diff --git a/qcom/opensource/wlan/qcacld-3.0/Android.mk b/qcom/opensource/wlan/qcacld-3.0/Android.mk new file mode 100644 index 0000000000..28346a3ab6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/Android.mk @@ -0,0 +1,390 @@ +# Android makefile for the WLAN Module + +# set WLAN_BUILD_DEBUG=y in your environment to enable debug logging +define wlog +$(if $(WLAN_BUILD_DEBUG),$(info $(1))) +endef + +define target_is_dual_wlan +$(strip \ + $(if $(TARGET_SUPPORT_DUAL_WLAN), \ + $(if $(findstring cnss2,$(1)),true,), \ + ) \ +) +endef + +LOCAL_MODULE_DDK_BUILD := false +LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := false + +ifeq ($(TARGET_BOARD_PLATFORM), sun) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true +endif +ifeq ($(TARGET_BOARD_PLATFORM), pineapple) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true +endif + +ifeq ($(TARGET_BOARD_PLATFORM), niobe) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true +endif + +ifeq ($(TARGET_BOARD_PLATFORM), volcano) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true +endif + +ifeq ($(TARGET_BOARD_PLATFORM),parrot) +ifeq ($(TARGET_BOARD_SUFFIX),66) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_DDK_ALLOW_UNSAFE_HEADERS := true +endif +endif + +LOCAL_PATH := $(call my-dir) +$(call wlog,LOCAL_PATH=$(LOCAL_PATH)) +BOARD_OPENSOURCE_DIR ?= vendor/qcom/opensource + +ENABLE_QCACLD := true +ifeq ($(TARGET_USES_QMAA), true) +ifneq ($(TARGET_USES_QMAA_OVERRIDE_WLAN), true) +ENABLE_QCACLD := false +else +ENABLE_QCACLD := true +endif +endif + +ifeq ($(BOARD_COMMON_DIR),) + BOARD_COMMON_DIR := device/qcom/common +endif + +ifeq ($(ENABLE_QCACLD), true) + +# Assume no targets will be supported +WLAN_CHIPSET := + +ifeq ($(BOARD_HAS_QCOM_WLAN), true) + +# Check if this driver needs be built for current target +ifneq ($(findstring qca_cld3,$(WIFI_DRIVER_BUILT)),) + WLAN_CHIPSET := qca_cld3 + WLAN_SELECT := CONFIG_QCA_CLD_WLAN=m +endif + +# Build/Package only in case of supported target +ifneq ($(WLAN_CHIPSET),) + +# This makefile is only for DLKM +ifneq ($(findstring vendor,$(LOCAL_PATH)),) + +ifneq ($(findstring opensource,$(LOCAL_PATH)),) + WLAN_BLD_DIR := $(BOARD_OPENSOURCE_DIR)/wlan +endif # opensource + +# Multi-ko check +LOCAL_DEV_NAME := $(patsubst .%,%,\ + $(lastword $(strip $(subst /, ,$(LOCAL_PATH))))) + +$(call wlog,LOCAL_DEV_NAME=$(LOCAL_DEV_NAME)) +$(call wlog,TARGET_WLAN_CHIP=$(TARGET_WLAN_CHIP)) + +TARGET_WLAN_CHIP ?= wlan +LOCAL_MULTI_KO := false +ifneq ($(TARGET_WLAN_CHIP), wlan) +ifeq ($(LOCAL_DEV_NAME), qcacld-3.0) +LOCAL_MULTI_KO := true +endif +endif + +ifeq ($(LOCAL_MULTI_KO), true) +LOCAL_ANDROID_ROOT := $(shell pwd) +LOCAL_WLAN_BLD_DIR := $(LOCAL_ANDROID_ROOT)/$(WLAN_BLD_DIR) +$(shell `find $(LOCAL_WLAN_BLD_DIR)/qcacld-3.0/ -maxdepth 1 -name '.*' ! -name '.git' -delete`) + +ifeq ($(LOCAL_MODULE_DDK_BUILD), true) +ifeq ($(CHIPSET),) +$(foreach chip, $(TARGET_WLAN_CHIP),\ + $(eval CHIPSET := $(chip))\ + $(eval include $(LOCAL_PATH)/Android.mk)) +else +# DLKM_DIR was moved for JELLY_BEAN (PLATFORM_SDK 16) +BAZEL_CHIPSET_NAME := $(subst _,-,$(CHIPSET)) +ifeq ($(call is-platform-sdk-version-at-least,16),true) + DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/dlkm +else + DLKM_DIR := build/dlkm +endif # platform-sdk-version + +include $(CLEAR_VARS) +LOCAL_MOD_NAME := wlan +LOCAL_MODULE := qca_cld3_$(CHIPSET).ko +LOCAL_MODULE_KBUILD_NAME := qca_cld3_$(CHIPSET).ko +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_DDK_SUBTARGET_REGEX := "all.*" +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) + ifeq ($(WIFI_DRIVER_INSTALL_TO_KERNEL_OUT),true) + LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) + else + LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/$(WLAN_CHIPSET) + endif +else + LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/modules/$(WLAN_CHIPSET) +endif + + +LOCAL_DEV_NAME := $(CHIPSET) +LOCAL_CHIP_NAME := $(LOCAL_DEV_NAME) +TARGET_MAC_BIN_PATH := /mnt/vendor/persist/$(LOCAL_CHIP_NAME) +TARGET_FW_DIR := firmware/wlan/qca_cld/$(LOCAL_CHIP_NAME) +TARGET_CFG_PATH := /vendor/etc/wifi/$(LOCAL_CHIP_NAME) +TARGET_MAC_BIN_PATH := /mnt/vendor/persist/$(LOCAL_CHIP_NAME) + +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) +TARGET_FW_PATH := $(TARGET_OUT_VENDOR)/$(TARGET_FW_DIR) +else +TARGET_FW_PATH := $(TARGET_OUT_ETC)/$(TARGET_FW_DIR) +endif + +# Create wlan_mac.bin symbolic link as part of the module +$(call symlink-file,,$(TARGET_MAC_BIN_PATH)/wlan_mac.bin,$(TARGET_FW_PATH)/wlan_mac.bin) +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_FW_PATH)/wlan_mac.bin + +# Conditionally create module symbolic link +ifneq ($(findstring $(WLAN_CHIPSET),$(WIFI_DRIVER_DEFAULT)),) +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) +ifneq ($(WIFI_DRIVER_INSTALL_TO_KERNEL_OUT),true) +$(call symlink-file,,$(TARGET_COPY_OUT_VENDOR)/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE),$(TARGET_OUT_VENDOR)/lib/modules/$(LOCAL_MODULE)) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_VENDOR)/lib/modules/$(LOCAL_MODULE) +endif +else +$(call symlink-file,,/system/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE),$(TARGET_OUT)/lib/modules/$(LOCAL_MODULE)) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT)/lib/modules/$(LOCAL_MODULE) +endif +endif + +# Conditionally create ini symbolic link +ifeq ($(TARGET_BOARD_AUTO),true) +$(call symlink-file,,$(TARGET_CFG_PATH)/WCNSS_qcom_cfg.ini,$(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini +$(call wlog,"generate soft link because TARGET_BOARD_AUTO true") +else +ifneq ($(GENERIC_ODM_IMAGE),true) +$(call symlink-file,,$(TARGET_CFG_PATH)/WCNSS_qcom_cfg.ini,$(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini +$(call wlog,"generate soft link because GENERIC_ODM_IMAGE not true") +endif +endif + +# Set dependencies so that CNSS family drivers can be compiled ahead. +ifneq ($(WLAN_PLATFORM_KBUILD_OPTIONS),) +LOCAL_REQUIRED_MODULES := wlan-platform-module-symvers +LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers +endif + +$(call wlog,TARGET_USES_KERNEL_PLATFORM=$(TARGET_USES_KERNEL_PLATFORM)) +ifeq ($(TARGET_USES_KERNEL_PLATFORM),true) + include $(DLKM_DIR)/Build_external_kernelmodule.mk +else + include $(DLKM_DIR)/AndroidKernelModule.mk +endif +endif +else +$(foreach chip, $(TARGET_WLAN_CHIP), \ + $(shell ln -sf . $(LOCAL_WLAN_BLD_DIR)/qcacld-3.0/.$(chip))) +include $(foreach chip, $(TARGET_WLAN_CHIP), $(LOCAL_PATH)/.$(chip)/Android.mk) +endif + +else # Multi-ok check + +# When dual wlan enabled, secondary dev name would be $(chip)_cnss2. +# Use LOCAL_CHIP_NAME instead of LOCAL_DEV_NAME for secondary one. +LOCAL_CHIP_NAME := $(LOCAL_DEV_NAME) +TARGET_SECONDARY_WLAN := $(call target_is_dual_wlan,$(LOCAL_DEV_NAME)) +ifeq ($(TARGET_SECONDARY_WLAN), true) +LOCAL_CHIP_NAME := $(patsubst %_cnss2,%,$(strip $(LOCAL_DEV_NAME))) +endif + +ifeq ($(WLAN_PROFILE),) +WLAN_PROFILE := default +endif + +ifeq ($(LOCAL_DEV_NAME), qcacld-3.0) + +LOCAL_DEV_NAME := wlan +LOCAL_MOD_NAME := wlan +LOCAL_SRC_DIR := +TARGET_FW_DIR := firmware/wlan/qca_cld +TARGET_CFG_PATH := /vendor/etc/wifi +TARGET_MAC_BIN_PATH := /mnt/vendor/persist + +else + +LOCAL_SRC_DIR := .$(LOCAL_DEV_NAME) +# Use default profile if WLAN_CFG_USE_DEFAULT defined. +ifeq ($(WLAN_CFG_USE_DEFAULT),) +WLAN_PROFILE := $(LOCAL_CHIP_NAME) +endif +TARGET_FW_DIR := firmware/wlan/qca_cld/$(LOCAL_CHIP_NAME) +TARGET_CFG_PATH := /vendor/etc/wifi/$(LOCAL_CHIP_NAME) +TARGET_MAC_BIN_PATH := /mnt/vendor/persist/$(LOCAL_CHIP_NAME) + +ifneq ($(TARGET_MULTI_WLAN), true) +LOCAL_MOD_NAME := wlan +DYNAMIC_SINGLE_CHIP := $(LOCAL_DEV_NAME) +else +LOCAL_MOD_NAME := $(LOCAL_DEV_NAME) +endif + +ifeq ($(TARGET_SECONDARY_WLAN), true) +TARGET_SECONDARY_WLAN_NUMBER := 2 +LOCAL_MOD_NAME := $(LOCAL_CHIP_NAME)_$(TARGET_SECONDARY_WLAN_NUMBER) +DYNAMIC_SINGLE_CHIP := $(LOCAL_CHIP_NAME) +endif + +endif + +# DLKM_DIR was moved for JELLY_BEAN (PLATFORM_SDK 16) +ifeq ($(call is-platform-sdk-version-at-least,16),true) + DLKM_DIR := $(TOP)/$(BOARD_COMMON_DIR)/dlkm +else + DLKM_DIR := build/dlkm +endif # platform-sdk-version + +# Build wlan.ko as $(WLAN_CHIPSET)_wlan.ko +########################################################### +# This is set once per LOCAL_PATH, not per (kernel) module +KBUILD_OPTIONS := WLAN_ROOT=$(WLAN_BLD_DIR)/qcacld-3.0/$(LOCAL_SRC_DIR) +KBUILD_OPTIONS += WLAN_COMMON_ROOT=cmn +KBUILD_OPTIONS += WLAN_COMMON_INC=$(WLAN_BLD_DIR)/qcacld-3.0/cmn +KBUILD_OPTIONS += WLAN_FW_API=$(WLAN_BLD_DIR)/fw-api +KBUILD_OPTIONS += WLAN_PROFILE=$(WLAN_PROFILE) +KBUILD_OPTIONS += DYNAMIC_SINGLE_CHIP=$(DYNAMIC_SINGLE_CHIP) + +# We are actually building wlan.ko here, as per the +# requirement we are specifying _wlan.ko as LOCAL_MODULE. +# This means we need to rename the module to _wlan.ko +# after wlan.ko is built. +KBUILD_OPTIONS += MODNAME=$(LOCAL_MOD_NAME) +KBUILD_OPTIONS += DEVNAME=$(LOCAL_DEV_NAME) +KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) +KBUILD_OPTIONS += $(WLAN_SELECT) + +KBUILD_REQUIRED_KOS := ipam.ko + +ifneq ($(WLAN_CFG_OVERRIDE_$(LOCAL_DEV_NAME)),) +KBUILD_OPTIONS += WLAN_CFG_OVERRIDE="$(WLAN_CFG_OVERRIDE_$(LOCAL_DEV_NAME))" +endif + +# driver expects "/dev/" for wifi driver state ctrl parameter. +# i.e. WIFI_DRIVER_STATE_CTRL_PARAM="/dev/wlan" is defined for single wlan. +# WIFI_DRIVER_STATE_CTRL_PARAM_SECONDARY="/dev/wlan2" is defined for 2nd wlan. +ifeq ($(TARGET_SECONDARY_WLAN), true) +$(call wlog,STATE_CTRL_PARAM_SECONDARY=$(WIFI_DRIVER_STATE_CTRL_PARAM_SECONDARY)) +PARAM_SECONDARY := $(patsubst "%",%,$(WIFI_DRIVER_STATE_CTRL_PARAM_SECONDARY)) +$(call wlog,PARAM_SECONDARY=$(PARAM_SECONDARY)) +ifeq ($(dir $(PARAM_SECONDARY)),/dev/) +KBUILD_OPTIONS += WLAN_CTRL_NAME=$(notdir $(PARAM_SECONDARY)) +endif +else +$(call wlog,WIFI_DRIVER_STATE_CTRL_PARAM=$(WIFI_DRIVER_STATE_CTRL_PARAM)) +PARAM := $(patsubst "%",%,$(WIFI_DRIVER_STATE_CTRL_PARAM)) +$(call wlog,PARAM=$(PARAM)) +ifeq ($(dir $(PARAM)),/dev/) +KBUILD_OPTIONS += WLAN_CTRL_NAME=$(notdir $(PARAM)) +endif +endif + +# Pass build options per chip to Kbuild. This will be injected from upper layer +# makefile. +# +# e.g. +# WLAN_KBUILD_OPTIONS_qca6390 := CONFIG_CNSS_QCA6390=y +ifneq ($(WLAN_KBUILD_OPTIONS_$(LOCAL_DEV_NAME)),) +KBUILD_OPTIONS += "$(WLAN_KBUILD_OPTIONS_$(LOCAL_DEV_NAME))" +endif + +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) +TARGET_FW_PATH := $(TARGET_OUT_VENDOR)/$(TARGET_FW_DIR) +else +TARGET_FW_PATH := $(TARGET_OUT_ETC)/$(TARGET_FW_DIR) +endif + +# WLAN_PLATFORM_KBUILD_OPTIONS should be passed from upper level Makefiles +# like wlan.mk. It indicates sources of CNSS family drivers (cnss2, cnss_nl, +# cnss_prealloc and cnss_utils etc.) are built out of kernel tree and it +# should also include all necessary config flags (e.g. CONFIG_CNSS2) which +# are originally defined from kernel Kconfig/defconfig. KBUILD_EXTRA_SYMBOLS +# is also needed to indicate all the symbols from these drivers. +ifneq ($(WLAN_PLATFORM_KBUILD_OPTIONS),) +KBUILD_OPTIONS += $(foreach wlan_platform_kbuild_option, \ + $(WLAN_PLATFORM_KBUILD_OPTIONS), \ + $(wlan_platform_kbuild_option)) + +KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(shell pwd)/$(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers +endif + +include $(CLEAR_VARS) + +# Create the module +LOCAL_MODULE := $(WLAN_CHIPSET)_$(LOCAL_DEV_NAME).ko +LOCAL_MODULE_KBUILD_NAME := $(LOCAL_MOD_NAME).ko +LOCAL_MODULE_DEBUG_ENABLE := true +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) + ifeq ($(WIFI_DRIVER_INSTALL_TO_KERNEL_OUT),true) + LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) + else + LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib/modules/$(WLAN_CHIPSET) + endif +else + LOCAL_MODULE_PATH := $(TARGET_OUT)/lib/modules/$(WLAN_CHIPSET) +endif + +# Create wlan_mac.bin symbolic link as part of the module +$(call symlink-file,,$(TARGET_MAC_BIN_PATH)/wlan_mac.bin,$(TARGET_FW_PATH)/wlan_mac.bin) +LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_FW_PATH)/wlan_mac.bin + +# Conditionally create module symbolic link +ifneq ($(findstring $(WLAN_CHIPSET),$(WIFI_DRIVER_DEFAULT)),) +ifeq ($(PRODUCT_VENDOR_MOVE_ENABLED),true) +ifneq ($(WIFI_DRIVER_INSTALL_TO_KERNEL_OUT),true) +$(call symlink-file,,$(TARGET_COPY_OUT_VENDOR)/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE),$(TARGET_OUT_VENDOR)/lib/modules/$(LOCAL_MODULE)) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_VENDOR)/lib/modules/$(LOCAL_MODULE) +endif +else +$(call symlink-file,,/system/lib/modules/$(WLAN_CHIPSET)/$(LOCAL_MODULE),$(TARGET_OUT)/lib/modules/$(LOCAL_MODULE)) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT)/lib/modules/$(LOCAL_MODULE) +endif +endif + +# Conditionally create ini symbolic link +ifeq ($(TARGET_BOARD_AUTO),true) +$(call symlink-file,,$(TARGET_CFG_PATH)/WCNSS_qcom_cfg.ini,$(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini +$(call wlog,"generate soft link because TARGET_BOARD_AUTO true") +else +ifneq ($(GENERIC_ODM_IMAGE),true) +$(call symlink-file,,$(TARGET_CFG_PATH)/WCNSS_qcom_cfg.ini,$(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini) +LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_FW_PATH)/WCNSS_qcom_cfg.ini +$(call wlog,"generate soft link because GENERIC_ODM_IMAGE not true") +endif +endif + +# Set dependencies so that CNSS family drivers can be compiled ahead. +ifneq ($(WLAN_PLATFORM_KBUILD_OPTIONS),) +LOCAL_REQUIRED_MODULES := wlan-platform-module-symvers +LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,wlan-platform-module-symvers)/Module.symvers +endif + +$(call wlog,TARGET_USES_KERNEL_PLATFORM=$(TARGET_USES_KERNEL_PLATFORM)) +ifeq ($(TARGET_USES_KERNEL_PLATFORM),true) + include $(DLKM_DIR)/Build_external_kernelmodule.mk +else + include $(DLKM_DIR)/AndroidKernelModule.mk +endif + +endif # Multi-ko check +endif # DLKM check +endif # supported target check +endif # WLAN enabled check +endif # ENABLE_QCACLD diff --git a/qcom/opensource/wlan/qcacld-3.0/BUILD.bazel b/qcom/opensource/wlan/qcacld-3.0/BUILD.bazel new file mode 100644 index 0000000000..c15db7b987 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/BUILD.bazel @@ -0,0 +1,10 @@ +load("//build/kernel/kleaf:kernel.bzl", "ddk_headers") +load(":wlan_qcacld3_modules.bzl", "define_modules") + +package( + default_visibility = [ + "//visibility:public", + ], +) + +define_modules() diff --git a/qcom/opensource/wlan/qcacld-3.0/Kbuild b/qcom/opensource/wlan/qcacld-3.0/Kbuild new file mode 100644 index 0000000000..105f2652f5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/Kbuild @@ -0,0 +1,5063 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := y +else + KERNEL_BUILD := n +endif + +ifeq ($(KERNEL_BUILD), y) + # These are provided in external module based builds + # Need to explicitly define for Kernel-based builds + MODNAME := wlan + WLAN_ROOT := drivers/staging/qcacld-3.0 + WLAN_COMMON_ROOT := cmn + WLAN_COMMON_INC := $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) + WLAN_FW_API := $(WLAN_ROOT)/../fw-api/ + WLAN_PROFILE := default +endif + +WLAN_COMMON_ROOT ?= cmn +WLAN_COMMON_INC ?= $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) +WLAN_FW_API ?= $(WLAN_ROOT)/../fw-api/ +WLAN_PROFILE ?= default +CONFIG_QCA_CLD_WLAN_PROFILE ?= $(WLAN_PROFILE) +DEVNAME ?= wlan +WLAN_PLATFORM_INC ?= $(WLAN_ROOT)/../platform/inc +DATA_IPA_INC ?= $(WLAN_ROOT)/../dataipa/drivers/platform/msm/include +DATA_IPA_UAPI_INC ?= $(DATA_IPA_INC)/uapi + +ifeq ($(KERNEL_BUILD), n) +ifneq ($(ANDROID_BUILD_TOP),) + ANDROID_BUILD_TOP_REL := $(shell python -c "import os.path; print(os.path.relpath('$(ANDROID_BUILD_TOP)'))") + override WLAN_ROOT := $(ANDROID_BUILD_TOP_REL)/$(WLAN_ROOT) + override WLAN_COMMON_INC := $(ANDROID_BUILD_TOP_REL)/$(WLAN_COMMON_INC) + override WLAN_FW_API := $(ANDROID_BUILD_TOP_REL)/$(WLAN_FW_API) +else ifneq ($(LINUX_BUILD_TOP),) + LINUX_BUILD_TOP_REL := $(shell python -c "import os.path; print(os.path.relpath('$(LINUX_BUILD_TOP)'))") + $(warning "LINUX_BUILD_TOP_REL=: $(LINUX_BUILD_TOP_REL)") + override WLAN_ROOT := $(LINUX_BUILD_TOP_REL)/qcacld-3.0 + override WLAN_COMMON_ROOT ?= cmn + override WLAN_COMMON_INC ?= $(WLAN_ROOT)/$(WLAN_COMMON_ROOT) + override WLAN_FW_API := $(WLAN_ROOT)/../fw-api +endif +endif + +include $(WLAN_ROOT)/configs/$(CONFIG_QCA_CLD_WLAN_PROFILE)_defconfig + +# add configurations in WLAN_CFG_OVERRIDE +$(foreach cfg, $(WLAN_CFG_OVERRIDE), \ + $(eval $(cfg)) \ + $(warning "Overriding WLAN config with: $(cfg)")) + +# KERNEL_SUPPORTS_NESTED_COMPOSITES := y is used to enable nested +# composite support. The nested composite support is available in some +# MSM kernels, and is available in 5.10 GKI kernels beginning with +# 5.10.20, but unfortunately is not available in any upstream kernel. +# +# When the feature is present in an MSM kernel, the flag is explicitly +# set in the kernel sources. When a GKI kernel is used, there isn't a +# flag set in the sources, so set the flag here if we are building +# with GKI kernel where the feature is present +KERNEL_VERSION = $(shell echo $$(( ( $1 << 16 ) + ( $2 << 8 ) + $3 ))) +LINUX_CODE := $(call KERNEL_VERSION,$(VERSION),$(PATCHLEVEL),$(SUBLEVEL)) + +# Comosite feature was added to GKI 5.10.20 +COMPOSITE_CODE_ADDED := 330260 # hardcoded $(call KERNEL_VERSION,5,10,20) + +# Comosite feature was not ported beyond 5.10.x +COMPOSITE_CODE_REMOVED := 330496 # hardcoded $(call KERNEL_VERSION,5,11,0) + +ifeq ($(KERNEL_SUPPORTS_NESTED_COMPOSITES),) + #flag is not explicitly present + ifneq ($(findstring gki,$(CONFIG_LOCALVERSION))$(findstring qki,$(CONFIG_LOCALVERSION)),) + # GKI kernel + ifeq ($(shell test $(LINUX_CODE) -ge $(COMPOSITE_CODE_ADDED); echo $$?),0) + # version >= 5.10.20 + ifeq ($(shell test $(LINUX_CODE) -lt $(COMPOSITE_CODE_REMOVED); echo $$?),0) + # version < 5.11.0 + KERNEL_SUPPORTS_NESTED_COMPOSITES := y + endif + endif + endif +endif + +OBJS := +OBJS_DIRS := + +define add-wlan-objs +$(eval $(_add-wlan-objs)) +endef + +define _add-wlan-objs + ifneq ($(2),) + ifeq ($(KERNEL_SUPPORTS_NESTED_COMPOSITES),y) + OBJS_DIRS += $(dir $(2)) + OBJS += $(1).o + $(1)-y := $(2) + else + OBJS += $(2) + endif + endif +endef + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(WLAN_ROOT)/$(UAPI_DIR)/linux + +############ COMMON ############ +COMMON_DIR := core/common +COMMON_INC := -I$(WLAN_ROOT)/$(COMMON_DIR) + +############ HDD ############ +HDD_DIR := core/hdd +HDD_INC_DIR := $(HDD_DIR)/inc +HDD_SRC_DIR := $(HDD_DIR)/src + +HDD_INC := -I$(WLAN_ROOT)/$(HDD_INC_DIR) \ + -I$(WLAN_ROOT)/$(HDD_SRC_DIR) + +HDD_OBJS := $(HDD_SRC_DIR)/wlan_hdd_assoc.o \ + $(HDD_SRC_DIR)/wlan_hdd_cfg.o \ + $(HDD_SRC_DIR)/wlan_hdd_cfg80211.o \ + $(HDD_SRC_DIR)/wlan_hdd_data_stall_detection.o \ + $(HDD_SRC_DIR)/wlan_hdd_driver_ops.o \ + $(HDD_SRC_DIR)/wlan_hdd_ftm.o \ + $(HDD_SRC_DIR)/wlan_hdd_hostapd.o \ + $(HDD_SRC_DIR)/wlan_hdd_ioctl.o \ + $(HDD_SRC_DIR)/wlan_hdd_main.o \ + $(HDD_SRC_DIR)/wlan_hdd_object_manager.o \ + $(HDD_SRC_DIR)/wlan_hdd_oemdata.o \ + $(HDD_SRC_DIR)/wlan_hdd_p2p.o \ + $(HDD_SRC_DIR)/wlan_hdd_power.o \ + $(HDD_SRC_DIR)/wlan_hdd_regulatory.o \ + $(HDD_SRC_DIR)/wlan_hdd_scan.o \ + $(HDD_SRC_DIR)/wlan_hdd_softap_tx_rx.o \ + $(HDD_SRC_DIR)/wlan_hdd_sta_info.o \ + $(HDD_SRC_DIR)/wlan_hdd_stats.o \ + $(HDD_SRC_DIR)/wlan_hdd_trace.o \ + $(HDD_SRC_DIR)/wlan_hdd_tx_rx.o \ + $(HDD_SRC_DIR)/wlan_hdd_wmm.o \ + $(HDD_SRC_DIR)/wlan_hdd_wowl.o\ + $(HDD_SRC_DIR)/wlan_hdd_ll_lt_sap.o\ + +ifeq ($(CONFIG_UNIT_TEST), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_unit_test.o +endif + +ifeq ($(CONFIG_WLAN_WEXT_SUPPORT_ENABLE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_wext.o \ + $(HDD_SRC_DIR)/wlan_hdd_hostapd_wext.o +endif + +ifeq ($(CONFIG_AFC_SUPPORT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_afc.o +endif + +ifeq ($(CONFIG_DCS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_dcs.o +endif + +ifeq ($(CONFIG_FEATURE_WLAN_EXTSCAN), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ext_scan.o +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs.o +ifeq ($(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_llstat.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_MIB_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_mibstat.o +endif +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_csr.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_offload.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_roam.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_config.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_unit_test.o +ifeq ($(CONFIG_WLAN_MWS_INFO_DEBUGFS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_coex.o +endif +endif + +ifeq ($(CONFIG_WLAN_CONV_SPECTRAL_ENABLE),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_spectralscan.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +HDD_OBJS+= $(HDD_SRC_DIR)/wlan_hdd_ocb.o +endif + +ifeq ($(CONFIG_FEATURE_MEMDUMP_ENABLE), y) +HDD_OBJS+= $(HDD_SRC_DIR)/wlan_hdd_memdump.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_FIPS), y) +HDD_OBJS+= $(HDD_SRC_DIR)/wlan_hdd_fips.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP), y) +HDD_OBJS+= $(HDD_SRC_DIR)/wlan_hdd_green_ap.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_APF), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_apf.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_LPSS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_lpass.o +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_napi.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ipa.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_son.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nan_datapath.o +endif + +ifeq ($(CONFIG_QCOM_TDLS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tdls.o +endif + +ifeq ($(CONFIG_WLAN_SYNC_TSF_PLUS), y) +CONFIG_WLAN_SYNC_TSF := y +endif + +ifeq ($(CONFIG_WLAN_SYNC_TSF), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tsf.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DISA), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_disa.o +endif + +ifeq ($(CONFIG_LFR_SUBNET_DETECTION), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_subnet_detect.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11AX), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_he.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11BE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_eht.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_TWT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_twt.o +endif + +ifeq ($(CONFIG_FEATURE_MONITOR_MODE_SUPPORT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_rx_monitor.o +endif + +ifeq ($(CONFIG_WLAN_NUD_TRACKING), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_nud_tracking.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_PACKET_FILTERING), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_packet_filter.o +endif + +ifeq ($(CONFIG_FEATURE_RSSI_MONITOR), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_rssi_monitor.o +endif + +ifeq ($(CONFIG_FEATURE_BSS_TRANSITION), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_bss_transition.o +endif + +ifeq ($(CONFIG_FEATURE_STATION_INFO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_station_info.o +endif + +ifeq ($(CONFIG_FEATURE_TX_POWER), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_tx_power.o +endif + +ifeq ($(CONFIG_FEATURE_OTA_TEST), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ota_test.o +endif + +ifeq ($(CONFIG_FEATURE_ACTIVE_TOS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_active_tos.o +endif + +ifeq ($(CONFIG_FEATURE_SAR_LIMITS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sar_limits.o +endif + +ifeq ($(CONFIG_FEATURE_CONCURRENCY_MATRIX), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_concurrency_matrix.o +endif + +ifeq ($(CONFIG_FEATURE_SAP_COND_CHAN_SWITCH), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sap_cond_chan_switch.o +endif + +ifeq ($(CONFIG_FEATURE_P2P_LISTEN_OFFLOAD), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_p2p_listen_offload.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs.o +ifeq ($(CONFIG_WLAN_SYSFS_CHANNEL), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_channel.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_FW_MODE_CFG), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_fw_mode_config.o +endif +ifeq ($(CONFIG_WLAN_REASSOC), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_reassoc.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_STA_INFO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_sta_info.o +endif +ifeq ($(CONFIG_WLAN_DEBUG_CRASH_INJECT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_crash_inject.o +endif +ifeq ($(CONFIG_FEATURE_UNIT_TEST_SUSPEND), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_suspend_resume.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_MEM_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_mem_stats.o +endif +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_unit_test.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_modify_acl.o +ifeq ($(CONFIG_WLAN_SYSFS_CONNECT_INFO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_connect_info.o +endif +ifeq ($(CONFIG_WLAN_SCAN_DISABLE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_scan_disable.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_DCM), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dcm.o +endif +ifeq ($(CONFIG_WLAN_WOW_ITO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wow_ito.o +endif +ifeq ($(CONFIG_WLAN_WOWL_ADD_PTRN), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wowl_add_ptrn.o +endif +ifeq ($(CONFIG_WLAN_WOWL_DEL_PTRN), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wowl_del_ptrn.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_TX_STBC), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_tx_stbc.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_SCAN_CFG), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_scan_config.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_monitor_mode_channel.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_RANGE_EXT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_range_ext.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_RADAR), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_radar.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_RTS_CTS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_rts_cts.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_HE_BSS_COLOR), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_he_bss_color.o +endif +ifeq ($(CONFIG_WLAN_TXRX_FW_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_txrx_fw_stats.o +endif +ifeq ($(CONFIG_WLAN_TXRX_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_txrx_stats.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_DP_TRACE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dp_trace.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_stats.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_TDLS_PEERS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_tdls_peers.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_TEMPERATURE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_temperature.o +endif +ifeq ($(CONFIG_WLAN_THERMAL_CFG), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_thermal_cfg.o +endif +ifeq ($(CONFIG_FEATURE_MOTION_DETECTION), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_motion_detection.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_WLAN_DBG), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wlan_dbg.o +endif +ifeq ($(CONFIG_WLAN_TXRX_FW_ST_RST), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_txrx_fw_st_rst.o +endif +ifeq ($(CONFIG_WLAN_GTX_BW_MASK), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_gtx_bw_mask.o +endif +ifeq ($(CONFIG_IPA_OFFLOAD), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_ipa.o +endif +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_pktlog.o +endif +ifeq ($(CONFIG_WLAN_DL_MODES), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dl_modes.o +endif +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_policy_mgr.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dp_aggregation.o +ifeq ($(CONFIG_DP_SWLM), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_swlm.o +endif +ifeq ($(CONFIG_WLAN_DUMP_IN_PROGRESS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dump_in_progress.o +endif +ifeq ($(CONFIG_FEATURE_SET), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wifi_features.o +endif +ifeq ($(CONFIG_WLAN_BMISS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_bmiss.o +endif +ifeq ($(CONFIG_WLAN_FREQ_LIST), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_get_freq_for_pwr.o +endif +ifeq ($(CONFIG_WLAN_SYSFS_DP_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_txrx_stats_console.o +endif + +ifeq ($(CONFIG_DP_PKT_ADD_TIMESTAMP), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_add_timestamp.o +endif + +ifeq ($(CONFIG_DP_TRAFFIC_END_INDICATION), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dp_traffic_end_indication.o +endif + +ifeq ($(CONFIG_DP_HW_TX_DELAY_STATS_ENABLE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dp_tx_delay_stats.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS_EHT_RATE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_eht_rate.o +endif + +ifeq ($(CONFIG_FEATURE_DIRECT_LINK), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_direct_link_ut_cmd.o +endif + +ifeq ($(CONFIG_BUS_AUTO_SUSPEND), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_runtime_pm.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS_LOG_BUFFER), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_log_buffer.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS_DFSNOL), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_dfsnol.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS_WDS_MODE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_wds_mode.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_roam_trigger_bitmap.o +endif + +ifeq ($(CONFIG_WLAN_SYSFS_RF_TEST_MODE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_sysfs_rf_test_mode.o +endif + +endif # CONFIG_WLAN_SYSFS + +ifeq ($(CONFIG_QCACLD_FEATURE_FW_STATE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_fw_state.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_COEX_CONFIG), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_coex_config.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_MPTA_HELPER), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mpta_helper.o +endif + +ifeq ($(CONFIG_WLAN_BCN_RECV_FEATURE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_bcn_recv.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_HW_CAPABILITY), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_hw_capability.o +endif + +ifeq ($(CONFIG_FW_THERMAL_THROTTLE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_thermal.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_BTC_CHAIN_MODE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_btc_chain_mode.o +endif + +ifeq ($(CONFIG_FEATURE_WLAN_TIME_SYNC_FTM), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_ftm_time_sync.o +endif + +ifeq ($(CONFIG_WLAN_HANG_EVENT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_hang_event.o +endif + +ifeq ($(CONFIG_WLAN_CFR_ENABLE), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_cfr.o +endif + +ifeq ($(CONFIG_FEATURE_GPIO_CFG),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_gpio.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_MEDIUM_ASSESS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_medium_assess.o +endif + +ifeq ($(CONFIG_WLAN_ENABLE_GPIO_WAKEUP),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_gpio_wakeup.o +endif + +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_cm_connect.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_cm_disconnect.o + + +ifeq ($(CONFIG_WLAN_BOOTUP_MARKER), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_bootup_marker.o +endif + +ifeq ($(CONFIG_FEATURE_WLAN_CH_AVOID_EXT),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_avoid_freq_ext.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11BE_MLO), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mlo.o +endif + + +ifeq ($(CONFIG_WLAN_FEATURE_MDNS_OFFLOAD),y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mdns_offload.o +endif + +ifeq ($(CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_connectivity_logging.o +else ifeq ($(CONFIG_QCACLD_WLAN_CONNECTIVITY_LOGGING), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_connectivity_logging.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mcc_quota.o +endif + +ifeq ($(CONFIG_FEATURE_WDS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_wds.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_peer_txq_flush.o +endif + +ifeq ($(CONFIG_WIFI_POS_CONVERGED), y) +ifeq ($(CONFIG_WIFI_POS_PASN), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_wifi_pos_pasn.o +endif +endif + +$(call add-wlan-objs,hdd,$(HDD_OBJS)) + +###### OSIF_SYNC ######## +SYNC_DIR := os_if/sync +SYNC_INC_DIR := $(SYNC_DIR)/inc +SYNC_SRC_DIR := $(SYNC_DIR)/src + +SYNC_INC := \ + -I$(WLAN_ROOT)/$(SYNC_INC_DIR) \ + -I$(WLAN_ROOT)/$(SYNC_SRC_DIR) \ + +SYNC_OBJS := \ + $(SYNC_SRC_DIR)/osif_sync.o \ + $(SYNC_SRC_DIR)/osif_driver_sync.o \ + $(SYNC_SRC_DIR)/osif_psoc_sync.o \ + $(SYNC_SRC_DIR)/osif_vdev_sync.o \ + +$(call add-wlan-objs,sync,$(SYNC_OBJS)) + +########### Driver Synchronization Core (DSC) ########### +DSC_DIR := components/dsc +DSC_INC_DIR := $(DSC_DIR)/inc +DSC_SRC_DIR := $(DSC_DIR)/src +DSC_TEST_DIR := $(DSC_DIR)/test + +DSC_INC := \ + -I$(WLAN_ROOT)/$(DSC_INC_DIR) \ + -I$(WLAN_ROOT)/$(DSC_SRC_DIR) \ + -I$(WLAN_ROOT)/$(DSC_TEST_DIR) + +DSC_OBJS := \ + $(DSC_SRC_DIR)/__wlan_dsc.o \ + $(DSC_SRC_DIR)/wlan_dsc_driver.o \ + $(DSC_SRC_DIR)/wlan_dsc_psoc.o \ + $(DSC_SRC_DIR)/wlan_dsc_vdev.o + +ifeq ($(CONFIG_DSC_TEST), y) + DSC_OBJS += $(DSC_TEST_DIR)/wlan_dsc_test.o +endif + +$(call add-wlan-objs,dsc,$(DSC_OBJS)) + +########### HOST DIAG LOG ########### +HOST_DIAG_LOG_DIR := $(WLAN_COMMON_ROOT)/utils/host_diag_log + +HOST_DIAG_LOG_INC_DIR := $(HOST_DIAG_LOG_DIR)/inc +HOST_DIAG_LOG_SRC_DIR := $(HOST_DIAG_LOG_DIR)/src + +HOST_DIAG_LOG_INC := -I$(WLAN_ROOT)/$(HOST_DIAG_LOG_INC_DIR) \ + -I$(WLAN_ROOT)/$(HOST_DIAG_LOG_SRC_DIR) + +ifeq ($(CONFIG_WLAN_DIAG_VERSION), y) +HOST_DIAG_LOG_OBJS += $(HOST_DIAG_LOG_SRC_DIR)/host_diag_log.o +endif + +$(call add-wlan-objs,host_diag_log,$(HOST_DIAG_LOG_OBJS)) + +############ EPPING ############ +EPPING_DIR := $(WLAN_COMMON_ROOT)/utils/epping +EPPING_INC_DIR := $(EPPING_DIR)/inc +EPPING_SRC_DIR := $(EPPING_DIR)/src + +EPPING_INC := -I$(WLAN_ROOT)/$(EPPING_INC_DIR) + +ifeq ($(CONFIG_FEATURE_EPPING), y) +EPPING_OBJS := $(EPPING_SRC_DIR)/epping_main.o \ + $(EPPING_SRC_DIR)/epping_txrx.o \ + $(EPPING_SRC_DIR)/epping_tx.o \ + $(EPPING_SRC_DIR)/epping_rx.o \ + $(EPPING_SRC_DIR)/epping_helper.o +endif + +$(call add-wlan-objs,epping,$(EPPING_OBJS)) + +############ SYS ############ +CMN_SYS_DIR := $(WLAN_COMMON_ROOT)/utils/sys +CMN_SYS_INC_DIR := $(CMN_SYS_DIR) +CMN_SYS_INC := -I$(WLAN_ROOT)/$(CMN_SYS_INC_DIR) + +############ MAC ############ +MAC_DIR := core/mac +MAC_INC_DIR := $(MAC_DIR)/inc +MAC_SRC_DIR := $(MAC_DIR)/src + +MAC_INC := -I$(WLAN_ROOT)/$(MAC_INC_DIR) \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/dph \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/include \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/include \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/lim \ + -I$(WLAN_ROOT)/$(MAC_SRC_DIR)/pe/nan + +MAC_DPH_OBJS := $(MAC_SRC_DIR)/dph/dph_hash_table.o + +ifeq ($(KERNEL_SUPPORTS_NESTED_COMPOSITES),y) +MAC_LIM_OBJS := $(MAC_SRC_DIR)/pe/lim/lim_aid_mgmt.o \ + $(MAC_SRC_DIR)/pe/lim/lim_admit_control.o \ + $(MAC_SRC_DIR)/pe/lim/lim_api.o \ + $(MAC_SRC_DIR)/pe/lim/lim_assoc_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ft.o \ + $(MAC_SRC_DIR)/pe/lim/lim_link_monitoring_algo.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_action_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_assoc_req_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_assoc_rsp_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_auth_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_beacon_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_cfg_updates.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_deauth_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_disassoc_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_message_queue.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_req_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_rsp_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_probe_req_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_probe_rsp_frame.o \ + $(MAC_SRC_DIR)/pe/lim/lim_process_sme_req_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_prop_exts_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_scan_result_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_security_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_management_frames.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_sme_rsp_messages.o \ + $(MAC_SRC_DIR)/pe/lim/lim_session.o \ + $(MAC_SRC_DIR)/pe/lim/lim_session_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_sme_req_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_timer_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_trace.o \ + $(MAC_SRC_DIR)/pe/lim/lim_utils.o +else +#composite of all of the above is in lim.c +MAC_LIM_OBJS := $(MAC_SRC_DIR)/pe/lim/lim.o +endif + +ifeq ($(CONFIG_QCOM_TDLS), y) +MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_tdls.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_FILS), y) +MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_fils.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y) +MAC_NDP_OBJS += $(MAC_SRC_DIR)/pe/nan/nan_datapath.o +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR2), y) + MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_process_mlm_host_roam.o \ + $(MAC_SRC_DIR)/pe/lim/lim_send_frames_host_roam.o \ + $(MAC_SRC_DIR)/pe/lim/lim_roam_timer_utils.o \ + $(MAC_SRC_DIR)/pe/lim/lim_ft_preauth.o \ + $(MAC_SRC_DIR)/pe/lim/lim_reassoc_utils.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11BE_MLO), y) + MAC_LIM_OBJS += $(MAC_SRC_DIR)/pe/lim/lim_mlo.o +endif + +MAC_SCH_OBJS := $(MAC_SRC_DIR)/pe/sch/sch_api.o \ + $(MAC_SRC_DIR)/pe/sch/sch_beacon_gen.o \ + $(MAC_SRC_DIR)/pe/sch/sch_beacon_process.o \ + $(MAC_SRC_DIR)/pe/sch/sch_message.o + +MAC_RRM_OBJS := $(MAC_SRC_DIR)/pe/rrm/rrm_api.o + +MAC_OBJS := $(MAC_CFG_OBJS) \ + $(MAC_DPH_OBJS) \ + $(MAC_LIM_OBJS) \ + $(MAC_SCH_OBJS) \ + $(MAC_RRM_OBJS) \ + $(MAC_NDP_OBJS) + +$(call add-wlan-objs,mac,$(MAC_OBJS)) + +############ SAP ############ +SAP_DIR := core/sap +SAP_INC_DIR := $(SAP_DIR)/inc +SAP_SRC_DIR := $(SAP_DIR)/src + +SAP_INC := -I$(WLAN_ROOT)/$(SAP_INC_DIR) \ + -I$(WLAN_ROOT)/$(SAP_SRC_DIR) + +SAP_OBJS := $(SAP_SRC_DIR)/sap_api_link_cntl.o \ + $(SAP_SRC_DIR)/sap_ch_select.o \ + $(SAP_SRC_DIR)/sap_fsm.o \ + $(SAP_SRC_DIR)/sap_module.o + +$(call add-wlan-objs,sap,$(SAP_OBJS)) + +############ CFG ############ +CFG_REL_DIR := $(WLAN_COMMON_ROOT)/cfg +CFG_DIR := $(WLAN_ROOT)/$(CFG_REL_DIR) +CFG_INC := \ + -I$(CFG_DIR)/inc \ + -I$(CFG_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/components/cfg +CFG_OBJS := \ + $(CFG_REL_DIR)/src/cfg.o + +$(call add-wlan-objs,cfg,$(CFG_OBJS)) + +############ DFS ############ +DFS_DIR := $(WLAN_COMMON_ROOT)/umac/dfs +DFS_CORE_INC_DIR := $(DFS_DIR)/core/inc +DFS_CORE_SRC_DIR := $(DFS_DIR)/core/src + +DFS_DISP_INC_DIR := $(DFS_DIR)/dispatcher/inc +DFS_DISP_SRC_DIR := $(DFS_DIR)/dispatcher/src +DFS_TARGET_INC_DIR := $(WLAN_COMMON_ROOT)/target_if/dfs/inc +DFS_CMN_SERVICES_INC_DIR := $(WLAN_COMMON_ROOT)/umac/cmn_services/dfs/inc + +DFS_INC := -I$(WLAN_ROOT)/$(DFS_DISP_INC_DIR) \ + -I$(WLAN_ROOT)/$(DFS_TARGET_INC_DIR) \ + -I$(WLAN_ROOT)/$(DFS_CMN_SERVICES_INC_DIR) + +ifeq ($(CONFIG_WLAN_DFS_MASTER_ENABLE), y) + +DFS_OBJS := $(DFS_CORE_SRC_DIR)/misc/dfs.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_nol.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_random_chan_sel.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_process_radar_found_ind.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_init_deinit_api.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_lmac_api.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_mlme_api.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_tgt_api.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_ucfg_api.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_tgt_api.o \ + $(DFS_DISP_SRC_DIR)/wlan_dfs_utils_api.o \ + $(WLAN_COMMON_ROOT)/target_if/dfs/src/target_if_dfs.o + +ifeq ($(CONFIG_WLAN_FEATURE_DFS_OFFLOAD), y) +DFS_OBJS += $(WLAN_COMMON_ROOT)/target_if/dfs/src/target_if_dfs_full_offload.o +else +DFS_OBJS += $(WLAN_COMMON_ROOT)/target_if/dfs/src/target_if_dfs_partial_offload.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_fcc_bin5.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_bindetects.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_debug.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_init.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_misc.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_phyerr_tlv.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_process_phyerr.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_process_radarevent.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_staggered.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_radar.o \ + $(DFS_CORE_SRC_DIR)/filtering/dfs_partial_offload_radar.o \ + $(DFS_CORE_SRC_DIR)/misc/dfs_filter_init.o +endif +endif + +$(call add-wlan-objs,dfs,$(DFS_OBJS)) + +############ SME ############ +SME_DIR := core/sme +SME_INC_DIR := $(SME_DIR)/inc +SME_SRC_DIR := $(SME_DIR)/src + +SME_INC := -I$(WLAN_ROOT)/$(SME_INC_DIR) \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/csr \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/qos \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/common \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/rrm \ + -I$(WLAN_ROOT)/$(SME_SRC_DIR)/nan + +ifeq ($(KERNEL_SUPPORTS_NESTED_COMPOSITES),y) +SME_CSR_OBJS := $(SME_SRC_DIR)/csr/csr_api_roam.o \ + $(SME_SRC_DIR)/csr/csr_api_scan.o \ + $(SME_SRC_DIR)/csr/csr_cmd_process.o \ + $(SME_SRC_DIR)/csr/csr_link_list.o \ + $(SME_SRC_DIR)/csr/csr_util.o \ + +SME_QOS_OBJS := $(SME_SRC_DIR)/qos/sme_qos.o + +SME_CMN_OBJS := $(SME_SRC_DIR)/common/sme_api.o \ + $(SME_SRC_DIR)/common/sme_power_save.o \ + $(SME_SRC_DIR)/common/sme_trace.o + +SME_RRM_OBJS := $(SME_SRC_DIR)/rrm/sme_rrm.o + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y) +SME_NDP_OBJS += $(SME_SRC_DIR)/nan/nan_datapath_api.o +endif + +SME_OBJS := $(SME_CMN_OBJS) \ + $(SME_CSR_OBJS) \ + $(SME_QOS_OBJS) \ + $(SME_RRM_OBJS) \ + $(SME_NAN_OBJS) \ + $(SME_NDP_OBJS) +else # KERNEL_SUPPORTS_NESTED_COMPOSITES +SME_OBJS := $(SME_SRC_DIR)/sme.o +endif +$(call add-wlan-objs,sme,$(SME_OBJS)) + +############ NLINK ############ +NLINK_DIR := $(WLAN_COMMON_ROOT)/utils/nlink +NLINK_INC_DIR := $(NLINK_DIR)/inc +NLINK_SRC_DIR := $(NLINK_DIR)/src + +NLINK_INC := -I$(WLAN_ROOT)/$(NLINK_INC_DIR) +NLINK_OBJS := $(NLINK_SRC_DIR)/wlan_nlink_srv.o + +$(call add-wlan-objs,nlink,$(NLINK_OBJS)) + +############ PTT ############ +PTT_DIR := $(WLAN_COMMON_ROOT)/utils/ptt +PTT_INC_DIR := $(PTT_DIR)/inc +PTT_SRC_DIR := $(PTT_DIR)/src + +PTT_INC := -I$(WLAN_ROOT)/$(PTT_INC_DIR) +PTT_OBJS := $(PTT_SRC_DIR)/wlan_ptt_sock_svc.o + +$(call add-wlan-objs,ptt,$(PTT_OBJS)) + +############ WLAN_LOGGING ############ +WLAN_LOGGING_DIR := $(WLAN_COMMON_ROOT)/utils/logging +WLAN_LOGGING_INC_DIR := $(WLAN_LOGGING_DIR)/inc +WLAN_LOGGING_SRC_DIR := $(WLAN_LOGGING_DIR)/src + +WLAN_LOGGING_INC := -I$(WLAN_ROOT)/$(WLAN_LOGGING_INC_DIR) +WLAN_LOGGING_OBJS := $(WLAN_LOGGING_SRC_DIR)/wlan_logging_sock_svc.o \ + $(WLAN_LOGGING_SRC_DIR)/wlan_roam_debug.o + +$(call add-wlan-objs,wlan_logging,$(WLAN_LOGGING_OBJS)) + +############ SYS ############ +SYS_DIR := core/mac/src/sys + +SYS_INC := -I$(WLAN_ROOT)/$(SYS_DIR)/common/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/platform/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/system/inc \ + -I$(WLAN_ROOT)/$(SYS_DIR)/legacy/src/utils/inc + +SYS_COMMON_SRC_DIR := $(SYS_DIR)/common/src +SYS_LEGACY_SRC_DIR := $(SYS_DIR)/legacy/src +SYS_OBJS := $(SYS_COMMON_SRC_DIR)/wlan_qct_sys.o \ + $(SYS_LEGACY_SRC_DIR)/platform/src/sys_wrapper.o \ + $(SYS_LEGACY_SRC_DIR)/system/src/mac_init_api.o \ + $(SYS_LEGACY_SRC_DIR)/system/src/sys_entry_func.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/dot11f.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/mac_trace.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/parser_api.o \ + $(SYS_LEGACY_SRC_DIR)/utils/src/utils_parser.o + +$(call add-wlan-objs,sys,$(SYS_OBJS)) + +############ Qcacld WMI ################### +WMI_DIR := components/wmi + +CLD_WMI_INC := -I$(WLAN_ROOT)/$(WMI_DIR)/inc + +ifeq ($(CONFIG_WMI_ROAM_SUPPORT), y) +CLD_WMI_ROAM_OBJS += $(WMI_DIR)/src/wmi_unified_roam_tlv.o \ + $(WMI_DIR)/src/wmi_unified_roam_api.o +endif + +ifeq ($(CONFIG_CP_STATS), y) +CLD_WMI_MC_CP_STATS_OBJS := $(WMI_DIR)/src/wmi_unified_mc_cp_stats_tlv.o \ + $(WMI_DIR)/src/wmi_unified_mc_cp_stats_api.o +endif + +ifeq ($(CONFIG_QCA_TARGET_IF_MLME), y) +CLD_WMI_MLME_OBJS += $(WMI_DIR)/src/wmi_unified_mlme_tlv.o \ + $(WMI_DIR)/src/wmi_unified_mlme_api.o +endif + +CLD_WMI_OBJS := $(CLD_WMI_ROAM_OBJS) \ + $(CLD_WMI_MC_CP_STATS_OBJS) \ + $(CLD_WMI_MLME_OBJS) + +$(call add-wlan-objs,cld_wmi,$(CLD_WMI_OBJS)) + +############ Qca-wifi-host-cmn ############ +QDF_OS_DIR := qdf +QDF_OS_INC_DIR := $(QDF_OS_DIR)/inc +QDF_OS_SRC_DIR := $(QDF_OS_DIR)/src +QDF_OS_LINUX_SRC_DIR := $(QDF_OS_DIR)/linux/src +QDF_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(QDF_OS_SRC_DIR) +QDF_LINUX_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(QDF_OS_LINUX_SRC_DIR) +QDF_TEST_DIR := $(QDF_OS_DIR)/test +QDF_TEST_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(QDF_TEST_DIR) + +QDF_INC := \ + -I$(WLAN_COMMON_INC)/$(QDF_OS_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(QDF_OS_LINUX_SRC_DIR) \ + -I$(WLAN_COMMON_INC)/$(QDF_TEST_DIR) + +QDF_OBJS := \ + $(QDF_LINUX_OBJ_DIR)/qdf_crypto.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_defer.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_delayed_work.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_event.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_file.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_func_tracker.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_idr.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_list.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_lock.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_mc_timer.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_mem.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_nbuf.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_periodic_work.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_status.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_threads.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_trace.o \ + $(QDF_LINUX_OBJ_DIR)/qdf_nbuf_frag.o \ + $(QDF_OBJ_DIR)/qdf_flex_mem.o \ + $(QDF_OBJ_DIR)/qdf_parse.o \ + $(QDF_OBJ_DIR)/qdf_platform.o \ + $(QDF_OBJ_DIR)/qdf_str.o \ + $(QDF_OBJ_DIR)/qdf_talloc.o \ + $(QDF_OBJ_DIR)/qdf_types.o \ + +ifeq ($(CONFIG_CNSS2_SSR_DRIVER_DUMP), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_ssr_driver_dump.o +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_debugfs.o +endif + +ifeq ($(CONFIG_WLAN_TRACEPOINTS), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_tracepoint.o +endif + +ifeq ($(CONFIG_WLAN_STREAMFS), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_streamfs.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_ipa.o +endif + +ifeq ($(CONFIG_DP_PKT_ADD_TIMESTAMP), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_pkt_add_timestamp.o +endif + +# enable CPU hotplug support if SMP is enabled +ifeq ($(CONFIG_SMP), y) + QDF_OBJS += $(QDF_OBJ_DIR)/qdf_cpuhp.o + QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_cpuhp.o +endif + +ifeq ($(CONFIG_LEAK_DETECTION), y) + QDF_OBJS += $(QDF_OBJ_DIR)/qdf_debug_domain.o + QDF_OBJS += $(QDF_OBJ_DIR)/qdf_tracker.o +endif + +ifeq ($(CONFIG_WLAN_HANG_EVENT), y) + QDF_OBJS += $(QDF_OBJ_DIR)/qdf_notifier.o +endif + +ifeq ($(CONFIG_QDF_TEST), y) + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_delayed_work_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_hashtable_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_periodic_work_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_ptr_hash_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_slist_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_talloc_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_tracker_test.o + QDF_OBJS += $(QDF_TEST_OBJ_DIR)/qdf_types_test.o +endif + +ifeq ($(CONFIG_WLAN_HANG_EVENT), y) + QDF_OBJS += $(QDF_OBJ_DIR)/qdf_hang_event_notifier.o +endif + +ifeq ($(CONFIG_WLAN_LRO), y) +QDF_OBJS += $(QDF_LINUX_OBJ_DIR)/qdf_lro.o +endif + +$(call add-wlan-objs,qdf,$(QDF_OBJS)) + +############ WBUFF ############ +WBUFF_OS_DIR := wbuff +WBUFF_OS_INC_DIR := $(WBUFF_OS_DIR)/inc +WBUFF_OS_SRC_DIR := $(WBUFF_OS_DIR)/src +WBUFF_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(WBUFF_OS_SRC_DIR) + +WBUFF_INC := -I$(WLAN_COMMON_INC)/$(WBUFF_OS_INC_DIR) \ + +ifeq ($(CONFIG_WLAN_WBUFF), y) +WBUFF_OBJS += $(WBUFF_OBJ_DIR)/wbuff.o +endif + +$(call add-wlan-objs,wbuff,$(WBUFF_OBJS)) + +##########QAL ####### +QAL_OS_DIR := qal +QAL_OS_INC_DIR := $(QAL_OS_DIR)/inc +QAL_OS_LINUX_SRC_DIR := $(QAL_OS_DIR)/linux/src + +QAL_INC := -I$(WLAN_COMMON_INC)/$(QAL_OS_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(QAL_OS_LINUX_SRC_DIR) + + +##########OS_IF ####### +OS_IF_DIR := $(WLAN_COMMON_ROOT)/os_if + +OS_IF_INC += -I$(WLAN_COMMON_INC)/os_if/linux \ + -I$(WLAN_COMMON_INC)/os_if/linux/scan/inc \ + -I$(WLAN_COMMON_INC)/os_if/linux/spectral/inc \ + -I$(WLAN_COMMON_INC)/os_if/linux/crypto/inc \ + -I$(WLAN_COMMON_INC)/os_if/linux/mlme/inc \ + -I$(WLAN_COMMON_INC)/os_if/linux/gpio/inc + +OS_IF_OBJ += $(OS_IF_DIR)/linux/wlan_osif_request_manager.o \ + $(OS_IF_DIR)/linux/crypto/src/wlan_nl_to_crypto_params.o \ + $(OS_IF_DIR)/linux/mlme/src/osif_cm_util.o \ + $(OS_IF_DIR)/linux/mlme/src/osif_cm_connect_rsp.o \ + $(OS_IF_DIR)/linux/mlme/src/osif_cm_disconnect_rsp.o \ + $(OS_IF_DIR)/linux/mlme/src/osif_cm_req.o \ + $(OS_IF_DIR)/linux/mlme/src/osif_cm_roam_rsp.o \ + $(OS_IF_DIR)/linux/mlme/src/osif_vdev_mgr_util.o + +OS_IF_OBJ += $(OS_IF_DIR)/linux/crypto/src/wlan_cfg80211_crypto.o + +$(call add-wlan-objs,os_if,$(OS_IF_OBJ)) + +############ UMAC_DISP ############ +UMAC_DISP_DIR := umac/global_umac_dispatcher/lmac_if +UMAC_DISP_INC_DIR := $(UMAC_DISP_DIR)/inc +UMAC_DISP_SRC_DIR := $(UMAC_DISP_DIR)/src +UMAC_DISP_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_DISP_SRC_DIR) + +UMAC_DISP_INC := -I$(WLAN_COMMON_INC)/$(UMAC_DISP_INC_DIR) + +UMAC_DISP_OBJS := $(UMAC_DISP_OBJ_DIR)/wlan_lmac_if.o + +$(call add-wlan-objs,umac_disp,$(UMAC_DISP_OBJS)) + +############# UMAC_SCAN ############ +UMAC_SCAN_DIR := umac/scan +UMAC_SCAN_DISP_INC_DIR := $(UMAC_SCAN_DIR)/dispatcher/inc +UMAC_SCAN_CORE_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_SCAN_DIR)/core/src +UMAC_SCAN_DISP_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_SCAN_DIR)/dispatcher/src +UMAC_TARGET_SCAN_INC := -I$(WLAN_COMMON_INC)/target_if/scan/inc + +UMAC_SCAN_INC := -I$(WLAN_COMMON_INC)/$(UMAC_SCAN_DISP_INC_DIR) +UMAC_SCAN_OBJS := $(UMAC_SCAN_CORE_DIR)/wlan_scan_cache_db.o \ + $(UMAC_SCAN_CORE_DIR)/wlan_scan_11d.o \ + $(UMAC_SCAN_CORE_DIR)/wlan_scan_filter.o \ + $(UMAC_SCAN_CORE_DIR)/wlan_scan_main.o \ + $(UMAC_SCAN_CORE_DIR)/wlan_scan_manager.o \ + $(UMAC_SCAN_DISP_DIR)/wlan_scan_tgt_api.o \ + $(UMAC_SCAN_DISP_DIR)/wlan_scan_ucfg_api.o \ + $(UMAC_SCAN_DISP_DIR)/wlan_scan_api.o \ + $(UMAC_SCAN_DISP_DIR)/wlan_scan_utils_api.o \ + $(WLAN_COMMON_ROOT)/os_if/linux/scan/src/wlan_cfg80211_scan.o \ + $(WLAN_COMMON_ROOT)/os_if/linux/wlan_cfg80211.o \ + $(WLAN_COMMON_ROOT)/target_if/scan/src/target_if_scan.o + +ifeq ($(CONFIG_FEATURE_WLAN_EXTSCAN), y) +UMAC_SCAN_OBJS += $(UMAC_SCAN_DISP_DIR)/wlan_extscan_api.o +endif + +ifeq ($(CONFIG_BAND_6GHZ), y) +UMAC_SCAN_OBJS += $(UMAC_SCAN_CORE_DIR)/wlan_scan_manager_6ghz.o +endif + +$(call add-wlan-objs,umac_scan,$(UMAC_SCAN_OBJS)) + +############# UMAC_SPECTRAL_SCAN ############ +UMAC_SPECTRAL_DIR := spectral +UMAC_SPECTRAL_DISP_INC_DIR := $(UMAC_SPECTRAL_DIR)/dispatcher/inc +UMAC_SPECTRAL_CORE_INC_DIR := $(UMAC_SPECTRAL_DIR)/core +UMAC_SPECTRAL_CORE_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_SPECTRAL_DIR)/core +UMAC_SPECTRAL_DISP_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_SPECTRAL_DIR)/dispatcher/src +UMAC_TARGET_SPECTRAL_INC := -I$(WLAN_COMMON_INC)/target_if/spectral + +UMAC_SPECTRAL_INC := -I$(WLAN_COMMON_INC)/$(UMAC_SPECTRAL_DISP_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(UMAC_SPECTRAL_CORE_INC_DIR) \ + -I$(WLAN_COMMON_INC)/target_if/direct_buf_rx/inc +ifeq ($(CONFIG_WLAN_CONV_SPECTRAL_ENABLE),y) +UMAC_SPECTRAL_OBJS := $(UMAC_SPECTRAL_CORE_DIR)/spectral_offload.o \ + $(UMAC_SPECTRAL_CORE_DIR)/spectral_common.o \ + $(UMAC_SPECTRAL_DISP_DIR)/wlan_spectral_ucfg_api.o \ + $(UMAC_SPECTRAL_DISP_DIR)/wlan_spectral_utils_api.o \ + $(UMAC_SPECTRAL_DISP_DIR)/wlan_spectral_tgt_api.o \ + $(WLAN_COMMON_ROOT)/os_if/linux/spectral/src/wlan_cfg80211_spectral.o \ + $(WLAN_COMMON_ROOT)/os_if/linux/spectral/src/os_if_spectral_netlink.o \ + $(WLAN_COMMON_ROOT)/target_if/spectral/target_if_spectral_netlink.o \ + $(WLAN_COMMON_ROOT)/target_if/spectral/target_if_spectral_phyerr.o \ + $(WLAN_COMMON_ROOT)/target_if/spectral/target_if_spectral.o \ + $(WLAN_COMMON_ROOT)/target_if/spectral/target_if_spectral_sim.o +endif + +$(call add-wlan-objs,umac_spectral,$(UMAC_SPECTRAL_OBJS)) + +############# WLAN_CFR ############ +WLAN_CFR_DIR := umac/cfr +WLAN_CFR_DISP_INC_DIR := $(WLAN_CFR_DIR)/dispatcher/inc +WLAN_CFR_CORE_INC_DIR := $(WLAN_CFR_DIR)/core/inc +WLAN_CFR_CORE_DIR := $(WLAN_COMMON_ROOT)/$(WLAN_CFR_DIR)/core/src +WLAN_CFR_DISP_DIR := $(WLAN_COMMON_ROOT)/$(WLAN_CFR_DIR)/dispatcher/src +WLAN_CFR_TARGET_INC_DIR := target_if/cfr/inc + +WLAN_CFR_INC := -I$(WLAN_COMMON_INC)/$(WLAN_CFR_DISP_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(WLAN_CFR_CORE_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(WLAN_CFR_TARGET_INC_DIR) +ifeq ($(CONFIG_WLAN_CFR_ENABLE),y) +WLAN_CFR_OBJS := $(WLAN_CFR_CORE_DIR)/cfr_common.o \ + $(WLAN_CFR_DISP_DIR)/wlan_cfr_tgt_api.o \ + $(WLAN_CFR_DISP_DIR)/wlan_cfr_ucfg_api.o \ + $(WLAN_CFR_DISP_DIR)/wlan_cfr_utils_api.o \ + $(WLAN_COMMON_ROOT)/target_if/cfr/src/target_if_cfr.o \ + $(WLAN_COMMON_ROOT)/target_if/cfr/src/target_if_cfr_6490.o +ifeq ($(CONFIG_WLAN_ENH_CFR_ENABLE),y) +WLAN_CFR_OBJS += $(WLAN_COMMON_ROOT)/target_if/cfr/src/target_if_cfr_enh.o +endif +ifeq ($(CONFIG_WLAN_CFR_ADRASTEA),y) +WLAN_CFR_OBJS += $(WLAN_COMMON_ROOT)/target_if/cfr/src/target_if_cfr_adrastea.o +endif +ifeq ($(CONFIG_WLAN_CFR_DBR),y) +WLAN_CFR_OBJS += $(WLAN_COMMON_ROOT)/target_if/cfr/src/target_if_cfr_dbr.o +endif +endif + +$(call add-wlan-objs,wlan_cfr,$(WLAN_CFR_OBJS)) + +############# GPIO_CFG ############ +UMAC_GPIO_DIR := gpio +UMAC_GPIO_DISP_INC_DIR := $(UMAC_GPIO_DIR)/dispatcher/inc +UMAC_GPIO_CORE_INC_DIR := $(UMAC_GPIO_DIR)/core/inc +UMAC_GPIO_CORE_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_GPIO_DIR)/core/src +UMAC_GPIO_DISP_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_GPIO_DIR)/dispatcher/src +UMAC_TARGET_GPIO_INC := -I$(WLAN_COMMON_INC)/target_if/gpio + +UMAC_GPIO_INC := -I$(WLAN_COMMON_INC)/$(UMAC_GPIO_DISP_INC_DIR) \ + -I$(WLAN_COMMON_INC)/$(UMAC_GPIO_CORE_INC_DIR) + +ifeq ($(CONFIG_FEATURE_GPIO_CFG),y) +UMAC_GPIO_OBJS := $(UMAC_GPIO_DISP_DIR)/wlan_gpio_tgt_api.o \ + $(UMAC_GPIO_DISP_DIR)/wlan_gpio_ucfg_api.o \ + $(UMAC_GPIO_CORE_DIR)/wlan_gpio_api.o \ + $(WLAN_COMMON_ROOT)/os_if/linux/gpio/src/wlan_cfg80211_gpio.o \ + $(WLAN_COMMON_ROOT)/target_if/gpio/target_if_gpio.o +endif + +$(call add-wlan-objs,umac_gpio,$(UMAC_GPIO_OBJS)) + +############# UMAC_GREEN_AP ############ +UMAC_GREEN_AP_DIR := umac/green_ap +UMAC_GREEN_AP_DISP_INC_DIR := $(UMAC_GREEN_AP_DIR)/dispatcher/inc +UMAC_GREEN_AP_CORE_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_GREEN_AP_DIR)/core/src +UMAC_GREEN_AP_DISP_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_GREEN_AP_DIR)/dispatcher/src +UMAC_TARGET_GREEN_AP_INC := -I$(WLAN_COMMON_INC)/target_if/green_ap/inc + +UMAC_GREEN_AP_INC := -I$(WLAN_COMMON_INC)/$(UMAC_GREEN_AP_DISP_INC_DIR) + +ifeq ($(CONFIG_QCACLD_FEATURE_GREEN_AP), y) +UMAC_GREEN_AP_OBJS := $(UMAC_GREEN_AP_CORE_DIR)/wlan_green_ap_main.o \ + $(UMAC_GREEN_AP_DISP_DIR)/wlan_green_ap_api.o \ + $(UMAC_GREEN_AP_DISP_DIR)/wlan_green_ap_ucfg_api.o \ + $(WLAN_COMMON_ROOT)/target_if/green_ap/src/target_if_green_ap.o +endif + +$(call add-wlan-objs,umac_green_ap,$(UMAC_GREEN_AP_OBJS)) + +############# WLAN_CONV_CRYPTO_SUPPORTED ############ +UMAC_CRYPTO_DIR := umac/cmn_services/crypto +UMAC_CRYPTO_CORE_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_CRYPTO_DIR)/src +UMAC_CRYPTO_INC := -I$(WLAN_COMMON_INC)/$(UMAC_CRYPTO_DIR)/inc \ + -I$(WLAN_COMMON_INC)/$(UMAC_CRYPTO_DIR)/src + +UMAC_CRYPTO_OBJS := $(UMAC_CRYPTO_CORE_DIR)/wlan_crypto_global_api.o \ + $(UMAC_CRYPTO_CORE_DIR)/wlan_crypto_ucfg_api.o \ + $(UMAC_CRYPTO_CORE_DIR)/wlan_crypto_main.o \ + $(UMAC_CRYPTO_CORE_DIR)/wlan_crypto_obj_mgr.o \ + $(UMAC_CRYPTO_CORE_DIR)/wlan_crypto_param_handling.o + +$(call add-wlan-objs,umac_crypto,$(UMAC_CRYPTO_OBJS)) + +############# FTM CORE ############ +FTM_CORE_DIR := ftm +TARGET_IF_FTM_DIR := target_if/ftm +OS_IF_LINUX_FTM_DIR := os_if/linux/ftm + +FTM_CORE_SRC := $(WLAN_COMMON_ROOT)/$(FTM_CORE_DIR)/core/src +FTM_DISP_SRC := $(WLAN_COMMON_ROOT)/$(FTM_CORE_DIR)/dispatcher/src +TARGET_IF_FTM_SRC := $(WLAN_COMMON_ROOT)/$(TARGET_IF_FTM_DIR)/src +OS_IF_FTM_SRC := $(WLAN_COMMON_ROOT)/$(OS_IF_LINUX_FTM_DIR)/src + +FTM_CORE_INC := $(WLAN_COMMON_INC)/$(FTM_CORE_DIR)/core/src +FTM_DISP_INC := $(WLAN_COMMON_INC)/$(FTM_CORE_DIR)/dispatcher/inc +TARGET_IF_FTM_INC := $(WLAN_COMMON_INC)/$(TARGET_IF_FTM_DIR)/inc +OS_IF_FTM_INC := $(WLAN_COMMON_INC)/$(OS_IF_LINUX_FTM_DIR)/inc + +FTM_INC := -I$(FTM_DISP_INC) \ + -I$(FTM_CORE_INC) \ + -I$(OS_IF_FTM_INC) \ + -I$(TARGET_IF_FTM_INC) + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) +FTM_OBJS := $(FTM_DISP_SRC)/wlan_ftm_init_deinit.o \ + $(FTM_DISP_SRC)/wlan_ftm_ucfg_api.o \ + $(FTM_CORE_SRC)/wlan_ftm_svc.o \ + $(TARGET_IF_FTM_SRC)/target_if_ftm.o + +ifeq ($(QCA_WIFI_FTM_NL80211), y) +FTM_OBJS += $(OS_IF_FTM_SRC)/wlan_cfg80211_ftm.o +endif + +ifeq ($(CONFIG_LINUX_QCMBR), y) +FTM_OBJS += $(OS_IF_FTM_SRC)/wlan_ioctl_ftm.o +endif + +endif + +$(call add-wlan-objs,ftm,$(FTM_OBJS)) + +############# UMAC_CMN_SERVICES ############ +UMAC_COMMON_INC := -I$(WLAN_COMMON_INC)/umac/cmn_services/cmn_defs/inc \ + -I$(WLAN_COMMON_INC)/umac/cmn_services/utils/inc +UMAC_COMMON_OBJS := $(WLAN_COMMON_ROOT)/umac/cmn_services/utils/src/wlan_utility.o + +$(call add-wlan-objs,umac_common,$(UMAC_COMMON_OBJS)) + +############ CDS (Connectivity driver services) ############ +CDS_DIR := core/cds +CDS_INC_DIR := $(CDS_DIR)/inc +CDS_SRC_DIR := $(CDS_DIR)/src + +CDS_INC := -I$(WLAN_ROOT)/$(CDS_INC_DIR) \ + -I$(WLAN_ROOT)/$(CDS_SRC_DIR) + +CDS_OBJS := $(CDS_SRC_DIR)/cds_api.o \ + $(CDS_SRC_DIR)/cds_reg_service.o \ + $(CDS_SRC_DIR)/cds_packet.o \ + $(CDS_SRC_DIR)/cds_regdomain.o \ + $(CDS_SRC_DIR)/cds_sched.o \ + $(CDS_SRC_DIR)/cds_utils.o + +$(call add-wlan-objs,cds,$(CDS_OBJS)) + +###### UMAC OBJMGR ######## +UMAC_OBJMGR_DIR := $(WLAN_COMMON_ROOT)/umac/cmn_services/obj_mgr + +UMAC_OBJMGR_INC := -I$(WLAN_COMMON_INC)/umac/cmn_services/obj_mgr/inc \ + -I$(WLAN_COMMON_INC)/umac/cmn_services/obj_mgr/src \ + -I$(WLAN_COMMON_INC)/umac/cmn_services/inc + +UMAC_OBJMGR_OBJS := $(UMAC_OBJMGR_DIR)/src/wlan_objmgr_global_obj.o \ + $(UMAC_OBJMGR_DIR)/src/wlan_objmgr_pdev_obj.o \ + $(UMAC_OBJMGR_DIR)/src/wlan_objmgr_peer_obj.o \ + $(UMAC_OBJMGR_DIR)/src/wlan_objmgr_psoc_obj.o \ + $(UMAC_OBJMGR_DIR)/src/wlan_objmgr_vdev_obj.o + +ifeq ($(CONFIG_WLAN_OBJMGR_DEBUG), y) +UMAC_OBJMGR_OBJS += $(UMAC_OBJMGR_DIR)/src/wlan_objmgr_debug.o +endif + +$(call add-wlan-objs,umac_objmgr,$(UMAC_OBJMGR_OBJS)) + +########### UMAC MGMT TXRX ########## +UMAC_MGMT_TXRX_DIR := $(WLAN_COMMON_ROOT)/umac/cmn_services/mgmt_txrx + +UMAC_MGMT_TXRX_INC := -I$(WLAN_COMMON_INC)/umac/cmn_services/mgmt_txrx/dispatcher/inc \ + +UMAC_MGMT_TXRX_OBJS := $(UMAC_MGMT_TXRX_DIR)/core/src/wlan_mgmt_txrx_main.o \ + $(UMAC_MGMT_TXRX_DIR)/dispatcher/src/wlan_mgmt_txrx_utils_api.o \ + $(UMAC_MGMT_TXRX_DIR)/dispatcher/src/wlan_mgmt_txrx_tgt_api.o + +$(call add-wlan-objs,umac_mgmt_txrx,$(UMAC_MGMT_TXRX_OBJS)) + +###### UMAC INTERFACE_MGR ######## +UMAC_INTERFACE_MGR_COMP_DIR := components/cmn_services/interface_mgr +UMAC_INTERFACE_MGR_CMN_DIR := $(WLAN_COMMON_ROOT)/umac/cmn_services/interface_mgr + +UMAC_INTERFACE_MGR_INC := -I$(WLAN_COMMON_INC)/umac/cmn_services/interface_mgr/inc \ + -I$(WLAN_ROOT)/components/cmn_services/interface_mgr/inc + +UMAC_INTERFACE_MGR_OBJS := $(UMAC_INTERFACE_MGR_CMN_DIR)/src/wlan_if_mgr_main.o \ + $(UMAC_INTERFACE_MGR_CMN_DIR)/src/wlan_if_mgr_core.o \ + $(UMAC_INTERFACE_MGR_COMP_DIR)/src/wlan_if_mgr_sta.o \ + $(UMAC_INTERFACE_MGR_COMP_DIR)/src/wlan_if_mgr_sap.o \ + $(UMAC_INTERFACE_MGR_COMP_DIR)/src/wlan_if_mgr_roam.o + +$(call add-wlan-objs,umac_ifmgr,$(UMAC_INTERFACE_MGR_OBJS)) + +###### UMAC MLO_MGR ######## +UMAC_MLO_MGR_CMN_DIR := $(WLAN_COMMON_ROOT)/umac/mlo_mgr +MLO_MGR_TARGET_IF_DIR := $(WLAN_COMMON_ROOT)/target_if/mlo_mgr + +UMAC_MLO_MGR_CLD_DIR := components/umac/mlme/mlo_mgr +UMAC_MLO_MGR_CLD_INC := -I$(WLAN_ROOT)/$(UMAC_MLO_MGR_CLD_DIR)/inc \ + -I$(WLAN_ROOT)/$(UMAC_MLO_MGR_CLD_DIR)/dispatcher/inc \ + +UMAC_MLO_MGR_INC := -I$(WLAN_COMMON_INC)/umac/mlo_mgr/inc \ + -I$(WLAN_COMMON_INC)/target_if/mlo_mgr/inc + +ifeq ($(CONFIG_WLAN_FEATURE_11BE_MLO), y) +UMAC_MLO_MGR_OBJS := $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_main.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_cmn.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_sta.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_op.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/utils_mlo.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_ap.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_peer_list.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_aid.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_peer.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_msgq.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_primary_umac.o \ + $(MLO_MGR_TARGET_IF_DIR)/src/target_if_mlo_mgr.o \ + $(UMAC_MLO_MGR_CLD_DIR)/src/wlan_mlo_link_force.o \ + $(UMAC_MLO_MGR_CLD_DIR)/src/wlan_mlo_mgr_roam.o \ + $(UMAC_MLO_MGR_CLD_DIR)/src/wlan_t2lm_api.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_t2lm.o \ + $(UMAC_MLO_MGR_CLD_DIR)/src/wlan_epcs_api.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_epcs.o \ + $(UMAC_MLO_MGR_CLD_DIR)/dispatcher/src/wlan_mlo_epcs_ucfg_api.o \ + $(UMAC_MLO_MGR_CMN_DIR)/src/wlan_mlo_mgr_link_switch.o \ + +$(call add-wlan-objs,umac_mlomgr,$(UMAC_MLO_MGR_OBJS)) +endif +########## POWER MANAGEMENT OFFLOADS (PMO) ########## +PMO_DIR := components/pmo +PMO_INC := -I$(WLAN_ROOT)/$(PMO_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(PMO_DIR)/dispatcher/inc \ + +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +PMO_OBJS := $(PMO_DIR)/core/src/wlan_pmo_main.o \ + $(PMO_DIR)/core/src/wlan_pmo_apf.o \ + $(PMO_DIR)/core/src/wlan_pmo_arp.o \ + $(PMO_DIR)/core/src/wlan_pmo_gtk.o \ + $(PMO_DIR)/core/src/wlan_pmo_mc_addr_filtering.o \ + $(PMO_DIR)/core/src/wlan_pmo_static_config.o \ + $(PMO_DIR)/core/src/wlan_pmo_wow.o \ + $(PMO_DIR)/core/src/wlan_pmo_lphb.o \ + $(PMO_DIR)/core/src/wlan_pmo_suspend_resume.o \ + $(PMO_DIR)/core/src/wlan_pmo_hw_filter.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_obj_mgmt_api.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_ucfg_api.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_arp.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_gtk.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_wow.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_static_config.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_lphb.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_suspend_resume.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_hw_filter.o \ + +ifeq ($(CONFIG_WLAN_FEATURE_PACKET_FILTERING), y) +PMO_OBJS += $(PMO_DIR)/core/src/wlan_pmo_pkt_filter.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_pkt_filter.o +endif +endif + +ifeq ($(CONFIG_WLAN_NS_OFFLOAD), y) +PMO_OBJS += $(PMO_DIR)/core/src/wlan_pmo_ns.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_ns.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_ICMP_OFFLOAD), y) +PMO_OBJS += $(PMO_DIR)/core/src/wlan_pmo_icmp.o \ + $(PMO_DIR)/dispatcher/src/wlan_pmo_tgt_icmp.o +endif + +$(call add-wlan-objs,pmo,$(PMO_OBJS)) + +########## DISA (ENCRYPTION TEST) ########## + +DISA_DIR := components/disa +DISA_INC := -I$(WLAN_ROOT)/$(DISA_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(DISA_DIR)/dispatcher/inc + +ifeq ($(CONFIG_WLAN_FEATURE_DISA), y) +DISA_OBJS := $(DISA_DIR)/core/src/wlan_disa_main.o \ + $(DISA_DIR)/dispatcher/src/wlan_disa_obj_mgmt_api.o \ + $(DISA_DIR)/dispatcher/src/wlan_disa_tgt_api.o \ + $(DISA_DIR)/dispatcher/src/wlan_disa_ucfg_api.o +endif + +$(call add-wlan-objs,disa,$(DISA_OBJS)) + +######## OCB ############## +OCB_DIR := components/ocb +OCB_INC := -I$(WLAN_ROOT)/$(OCB_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(OCB_DIR)/dispatcher/inc + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +OCB_OBJS := $(OCB_DIR)/dispatcher/src/wlan_ocb_ucfg_api.o \ + $(OCB_DIR)/dispatcher/src/wlan_ocb_tgt_api.o \ + $(OCB_DIR)/core/src/wlan_ocb_main.o +endif + +$(call add-wlan-objs,ocb,$(OCB_OBJS)) + +######## IPA ############## +IPA_DIR := $(WLAN_COMMON_ROOT)/ipa +IPA_INC := -I$(WLAN_ROOT)/$(IPA_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(IPA_DIR)/dispatcher/inc + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +IPA_OBJS := $(IPA_DIR)/dispatcher/src/wlan_ipa_ucfg_api.o \ + $(IPA_DIR)/dispatcher/src/wlan_ipa_obj_mgmt_api.o \ + $(IPA_DIR)/dispatcher/src/wlan_ipa_tgt_api.o \ + $(IPA_DIR)/core/src/wlan_ipa_main.o \ + $(IPA_DIR)/core/src/wlan_ipa_core.o \ + $(IPA_DIR)/core/src/wlan_ipa_stats.o \ + $(IPA_DIR)/core/src/wlan_ipa_rm.o +endif + +$(call add-wlan-objs,ipa,$(IPA_OBJS)) + +######## FWOL ########## +FWOL_CORE_INC := components/fw_offload/core/inc +FWOL_CORE_SRC := components/fw_offload/core/src +FWOL_DISPATCHER_INC := components/fw_offload/dispatcher/inc +FWOL_DISPATCHER_SRC := components/fw_offload/dispatcher/src +FWOL_TARGET_IF_INC := components/target_if/fw_offload/inc +FWOL_TARGET_IF_SRC := components/target_if/fw_offload/src +FWOL_OS_IF_INC := os_if/fw_offload/inc +FWOL_OS_IF_SRC := os_if/fw_offload/src + +FWOL_INC := -I$(WLAN_ROOT)/$(FWOL_CORE_INC) \ + -I$(WLAN_ROOT)/$(FWOL_DISPATCHER_INC) \ + -I$(WLAN_ROOT)/$(FWOL_TARGET_IF_INC) \ + -I$(WLAN_ROOT)/$(FWOL_OS_IF_INC) \ + -I$(WLAN_COMMON_INC)/umac/thermal/dispatcher/inc + +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +FWOL_OBJS := $(FWOL_CORE_SRC)/wlan_fw_offload_main.o \ + $(FWOL_DISPATCHER_SRC)/wlan_fwol_ucfg_api.o \ + $(FWOL_DISPATCHER_SRC)/wlan_fwol_tgt_api.o \ + $(FWOL_TARGET_IF_SRC)/target_if_fwol.o \ + $(FWOL_OS_IF_SRC)/os_if_fwol.o +endif + +$(call add-wlan-objs,fwol,$(FWOL_OBJS)) + +######## SM FRAMEWORK ############## +UMAC_SM_DIR := umac/cmn_services/sm_engine +UMAC_SM_INC := -I$(WLAN_COMMON_INC)/$(UMAC_SM_DIR)/inc + +UMAC_SM_OBJS := $(WLAN_COMMON_ROOT)/$(UMAC_SM_DIR)/src/wlan_sm_engine.o + +ifeq ($(CONFIG_SM_ENG_HIST), y) +UMAC_SM_OBJS += $(WLAN_COMMON_ROOT)/$(UMAC_SM_DIR)/src/wlan_sm_engine_dbg.o +endif + +$(call add-wlan-objs,umac_sm,$(UMAC_SM_OBJS)) + +######## COMMON MLME ############## +UMAC_MLME_INC := -I$(WLAN_COMMON_INC)/umac/mlme \ + -I$(WLAN_COMMON_INC)/umac/mlme/mlme_objmgr/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/umac/mlme/vdev_mgr/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/umac/mlme/pdev_mgr/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/umac/mlme/psoc_mgr/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/umac/mlme/connection_mgr/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/umac/mlme/connection_mgr/utf/inc \ + -I$(WLAN_COMMON_INC)/umac/mlme/include \ + -I$(WLAN_COMMON_INC)/umac/mlme/mlme_utils/ + +UMAC_MLME_OBJS := $(WLAN_COMMON_ROOT)/umac/mlme/mlme_objmgr/dispatcher/src/wlan_vdev_mlme_main.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/core/src/vdev_mlme_sm.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mlme_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_tgt_if_rx_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_tgt_if_tx_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_ucfg_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_utils_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/mlme_objmgr/dispatcher/src/wlan_cmn_mlme_main.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/mlme_objmgr/dispatcher/src/wlan_pdev_mlme_main.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/pdev_mgr/dispatcher/src/wlan_pdev_mlme_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/mlme_objmgr/dispatcher/src/wlan_psoc_mlme_main.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/psoc_mgr/dispatcher/src/wlan_psoc_mlme_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/psoc_mgr/dispatcher/src/wlan_psoc_mlme_ucfg_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_main.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_sm.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_connect.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_connect_scan.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_util.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_ucfg_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_api.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/mlme_utils/wlan_vdev_mlme_ser_if.o +ifeq ($(CONFIG_CM_UTF_ENABLE), y) +UMAC_MLME_OBJS += $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/utf/src/wlan_cm_utf_main.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/utf/src/wlan_cm_utf_scan.o +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR3), y) +# Add LFR3/FW roam specific connection manager files here +UMAC_MLME_OBJS += $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.o + +endif +ifeq ($(CONFIG_QCACLD_WLAN_LFR2), y) +# Add LFR2/host roam specific connection manager files here +UMAC_MLME_OBJS += $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.o \ + $(WLAN_COMMON_ROOT)/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam.o +endif + +$(call add-wlan-objs,umac_mlme,$(UMAC_MLME_OBJS)) + +######## MLME ############## +MLME_DIR := components/mlme +MLME_INC := -I$(WLAN_ROOT)/$(MLME_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(MLME_DIR)/dispatcher/inc \ + +MLME_OBJS := $(MLME_DIR)/core/src/wlan_mlme_main.o \ + $(MLME_DIR)/dispatcher/src/wlan_mlme_api.o \ + $(MLME_DIR)/dispatcher/src/wlan_mlme_ucfg_api.o + +MLME_OBJS += $(MLME_DIR)/core/src/wlan_mlme_vdev_mgr_interface.o + +ifeq ($(CONFIG_WLAN_FEATURE_TWT), y) +MLME_OBJS += $(MLME_DIR)/core/src/wlan_mlme_twt_api.o +MLME_OBJS += $(MLME_DIR)/dispatcher/src/wlan_mlme_twt_ucfg_api.o +endif + +CM_DIR := components/umac/mlme/connection_mgr +CM_TGT_IF_DIR := components/target_if/connection_mgr + +CM_INC := -I$(WLAN_ROOT)/$(CM_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(CM_DIR)/utf/inc \ + -I$(WLAN_ROOT)/$(CM_TGT_IF_DIR)/inc + +MLME_INC += $(CM_INC) + +MLME_OBJS += $(CM_DIR)/dispatcher/src/wlan_cm_tgt_if_tx_api.o \ + $(CM_DIR)/dispatcher/src/wlan_cm_roam_api.o \ + $(CM_DIR)/dispatcher/src/wlan_cm_roam_ucfg_api.o \ + $(CM_TGT_IF_DIR)/src/target_if_cm_roam_offload.o \ + $(CM_TGT_IF_DIR)/src/target_if_cm_roam_event.o \ + $(CM_DIR)/core/src/wlan_cm_roam_offload.o \ + $(CM_DIR)/core/src/wlan_cm_vdev_connect.o \ + $(CM_DIR)/core/src/wlan_cm_vdev_disconnect.o + +ifeq ($(CONFIG_CM_UTF_ENABLE), y) +MLME_OBJS += $(CM_DIR)/utf/src/cm_utf.o +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR3), y) +MLME_OBJS += $(CM_DIR)/core/src/wlan_cm_roam_fw_sync.o \ + $(CM_DIR)/core/src/wlan_cm_roam_offload_event.o +endif + +ifeq ($(CONFIG_QCACLD_WLAN_LFR2), y) +# Add LFR2/host roam specific connection manager files here +MLME_OBJS += $(CM_DIR)/core/src/wlan_cm_host_roam_preauth.o \ + $(CM_DIR)/core/src/wlan_cm_host_util.o +endif + +####### WFA_CONFIG ######## + +WFA_DIR := components/umac/mlme/wfa_config +WFA_TGT_IF_DIR := components/target_if/wfa_config + +WFA_INC := -I$(WLAN_ROOT)/$(WFA_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(WFA_TGT_IF_DIR)/inc + +MLME_INC += $(WFA_INC) + +MLME_OBJS += $(WFA_TGT_IF_DIR)/src/target_if_wfa_testcmd.o \ + $(WFA_DIR)/dispatcher/src/wlan_wfa_tgt_if_tx_api.o + +####### LL_SAP ####### +LL_SAP_DIR := components/umac/mlme/sap/ll_sap +LL_SAP_OS_IF_DIR := os_if/mlme/sap/ll_sap +LL_SAP_TARGET_IF_DIR := components/target_if/sap/ll_sap +LL_SAP_WMI_DIR := components/wmi/ + +LL_SAP_INC := -I$(WLAN_ROOT)/$(LL_SAP_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(LL_SAP_OS_IF_DIR)/inc \ + -I$(WLAN_ROOT)/$(LL_SAP_TARGET_IF_DIR)/inc \ + -I$(WLAN_ROOT)/$(LL_SAP_WMI_DIR)/inc + +MLME_INC += $(LL_SAP_INC) + +ifeq ($(CONFIG_WLAN_FEATURE_LL_LT_SAP), y) +MLME_OBJS += $(LL_SAP_DIR)/dispatcher/src/wlan_ll_sap_ucfg_api.o \ + $(LL_SAP_DIR)/dispatcher/src/wlan_ll_sap_api.o \ + $(LL_SAP_DIR)/core/src/wlan_ll_sap_main.o \ + $(LL_SAP_DIR)/core/src/wlan_ll_lt_sap_main.o \ + $(LL_SAP_DIR)/core/src/wlan_ll_lt_sap_bearer_switch.o \ + $(LL_SAP_OS_IF_DIR)/src/os_if_ll_sap.o \ + $(LL_SAP_TARGET_IF_DIR)/src/target_if_ll_sap.o \ + $(LL_SAP_WMI_DIR)/src/wmi_unified_ll_sap_api.o \ + $(LL_SAP_WMI_DIR)/src/wmi_unified_ll_sap_tlv.o +endif + +$(call add-wlan-objs,mlme,$(MLME_OBJS)) + +####### DENYLIST_MGR ######## + +DLM_DIR := components/denylist_mgr +DLM_INC := -I$(WLAN_ROOT)/$(DLM_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(DLM_DIR)/dispatcher/inc +ifeq ($(CONFIG_FEATURE_DENYLIST_MGR), y) +DLM_OBJS := $(DLM_DIR)/core/src/wlan_dlm_main.o \ + $(DLM_DIR)/core/src/wlan_dlm_core.o \ + $(DLM_DIR)/dispatcher/src/wlan_dlm_ucfg_api.o \ + $(DLM_DIR)/dispatcher/src/wlan_dlm_tgt_api.o +endif + +$(call add-wlan-objs,dlm,$(DLM_OBJS)) + +######### CONNECTIVITY_LOGGING ######### +CONN_LOGGING_DIR := components/cmn_services/logging +CONN_LOGGING_INC := -I$(WLAN_ROOT)/$(CONN_LOGGING_DIR)/inc + +ifeq ($(CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT), y) +CONN_LOGGING_OBJS := $(CONN_LOGGING_DIR)/src/wlan_connectivity_logging.o +else ifeq ($(CONFIG_QCACLD_WLAN_CONNECTIVITY_LOGGING), y) +CONN_LOGGING_OBJS := $(CONN_LOGGING_DIR)/src/wlan_connectivity_logging.o +endif + +$(call add-wlan-objs,conn_logging,$(CONN_LOGGING_OBJS)) + +########## ACTION OUI ########## + +ACTION_OUI_DIR := components/action_oui +ACTION_OUI_INC := -I$(WLAN_ROOT)/$(ACTION_OUI_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(ACTION_OUI_DIR)/dispatcher/inc + +ifeq ($(CONFIG_WLAN_FEATURE_ACTION_OUI), y) +ACTION_OUI_OBJS := $(ACTION_OUI_DIR)/core/src/wlan_action_oui_main.o \ + $(ACTION_OUI_DIR)/core/src/wlan_action_oui_parse.o \ + $(ACTION_OUI_DIR)/dispatcher/src/wlan_action_oui_tgt_api.o \ + $(ACTION_OUI_DIR)/dispatcher/src/wlan_action_oui_ucfg_api.o +endif + +$(call add-wlan-objs,action_oui,$(ACTION_OUI_OBJS)) + +######## PACKET CAPTURE ######## + +PKT_CAPTURE_DIR := components/pkt_capture +PKT_CAPTURE_OS_IF_DIR := os_if/pkt_capture +PKT_CAPTURE_TARGET_IF_DIR := components/target_if/pkt_capture/ +PKT_CAPTURE_INC := -I$(WLAN_ROOT)/$(PKT_CAPTURE_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(PKT_CAPTURE_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(PKT_CAPTURE_TARGET_IF_DIR)/inc \ + -I$(WLAN_ROOT)/$(PKT_CAPTURE_OS_IF_DIR)/inc + +ifeq ($(CONFIG_WLAN_FEATURE_PKT_CAPTURE), y) +PKT_CAPTURE_OBJS := $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_main.o \ + $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_mon_thread.o \ + $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_mgmt_txrx.o \ + $(PKT_CAPTURE_DIR)/core/src/wlan_pkt_capture_data_txrx.o \ + $(PKT_CAPTURE_DIR)/dispatcher/src/wlan_pkt_capture_ucfg_api.o \ + $(PKT_CAPTURE_DIR)/dispatcher/src/wlan_pkt_capture_tgt_api.o \ + $(PKT_CAPTURE_DIR)/dispatcher/src/wlan_pkt_capture_api.o \ + $(PKT_CAPTURE_TARGET_IF_DIR)/src/target_if_pkt_capture.o \ + $(PKT_CAPTURE_OS_IF_DIR)/src/os_if_pkt_capture.o +endif + +$(call add-wlan-objs,pkt_capture,$(PKT_CAPTURE_OBJS)) + +########## FTM TIME SYNC ########## + +FTM_TIME_SYNC_DIR := components/ftm_time_sync +FTM_TIME_SYNC_INC := -I$(WLAN_ROOT)/$(FTM_TIME_SYNC_DIR)/core/inc \ + -I$(WLAN_ROOT)/$(FTM_TIME_SYNC_DIR)/dispatcher/inc + +ifeq ($(CONFIG_FEATURE_WLAN_TIME_SYNC_FTM), y) +FTM_TIME_SYNC_OBJS := $(FTM_TIME_SYNC_DIR)/core/src/ftm_time_sync_main.o \ + $(FTM_TIME_SYNC_DIR)/dispatcher/src/ftm_time_sync_ucfg_api.o \ + $(FTM_TIME_SYNC_DIR)/dispatcher/src/wlan_ftm_time_sync_tgt_api.o +endif + +$(call add-wlan-objs,ftm_time_sync,$(FTM_TIME_SYNC_OBJS)) + +########## WLAN PRE_CAC ########## + +WLAN_PRE_CAC_DIR := components/pre_cac +PRE_CAC_OSIF_DIR := os_if/pre_cac +WLAN_PRE_CAC_INC := -I$(WLAN_ROOT)/$(WLAN_PRE_CAC_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(WLAN_PRE_CAC_DIR)/core/src \ + -I$(WLAN_ROOT)/$(PRE_CAC_OSIF_DIR)/inc + +ifeq ($(CONFIG_FEATURE_WLAN_PRE_CAC), y) +WLAN_PRE_CAC_OBJS := $(HDD_SRC_DIR)/wlan_hdd_pre_cac.o \ + $(WLAN_PRE_CAC_DIR)/core/src/wlan_pre_cac_main.o \ + $(WLAN_PRE_CAC_DIR)/dispatcher/src/wlan_pre_cac_ucfg_api.o \ + $(WLAN_PRE_CAC_DIR)/dispatcher/src/wlan_pre_cac_api.o \ + $(PRE_CAC_OSIF_DIR)/src/osif_pre_cac.o +endif + +$(call add-wlan-objs,wlan_pre_cac,$(WLAN_PRE_CAC_OBJS)) + +########## CLD TARGET_IF ####### +CLD_TARGET_IF_DIR := components/target_if + +CLD_TARGET_IF_INC := -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/pmo/inc \ + -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/mlme/inc \ + +ifeq ($(CONFIG_QCA_TARGET_IF_MLME), y) +CLD_TARGET_IF_OBJ := $(CLD_TARGET_IF_DIR)/mlme/src/target_if_mlme.o +endif + +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_arp.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_gtk.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_hw_filter.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_lphb.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_main.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_mc_addr_filtering.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_static_config.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_suspend_resume.o \ + $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_wow.o +ifeq ($(CONFIG_WLAN_NS_OFFLOAD), y) +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_ns.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_PACKET_FILTERING), y) +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_pkt_filter.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_ICMP_OFFLOAD), y) +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/pmo/src/target_if_pmo_icmp.o +endif +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +CLD_TARGET_IF_INC += -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/ocb/inc +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/ocb/src/target_if_ocb.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DISA), y) +CLD_TARGET_IF_INC += -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/disa/inc +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/disa/src/target_if_disa.o +endif + +ifeq ($(CONFIG_FEATURE_DENYLIST_MGR), y) +CLD_TARGET_IF_INC += -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/denylist_mgr/inc +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/denylist_mgr/src/target_if_dlm.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_ACTION_OUI), y) +CLD_TARGET_IF_INC += -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/action_oui/inc +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/action_oui/src/target_if_action_oui.o +endif + +ifeq ($(CONFIG_FEATURE_WLAN_TIME_SYNC_FTM), y) +CLD_TARGET_IF_INC += -I$(WLAN_ROOT)/$(CLD_TARGET_IF_DIR)/ftm_time_sync/inc +CLD_TARGET_IF_OBJ += $(CLD_TARGET_IF_DIR)/ftm_time_sync/src/target_if_ftm_time_sync.o +endif + +$(call add-wlan-objs,cld_target_if,$(CLD_TARGET_IF_OBJ)) + +############## UMAC P2P ########### +P2P_DIR := components/p2p +P2P_CORE_OBJ_DIR := $(P2P_DIR)/core/src +P2P_DISPATCHER_DIR := $(P2P_DIR)/dispatcher +P2P_DISPATCHER_INC_DIR := $(P2P_DISPATCHER_DIR)/inc +P2P_DISPATCHER_OBJ_DIR := $(P2P_DISPATCHER_DIR)/src +P2P_OS_IF_INC := os_if/p2p/inc +P2P_OS_IF_SRC := os_if/p2p/src +P2P_TARGET_IF_INC := components/target_if/p2p/inc +P2P_TARGET_IF_SRC := components/target_if/p2p/src +P2P_INC := -I$(WLAN_ROOT)/$(P2P_DISPATCHER_INC_DIR) \ + -I$(WLAN_ROOT)/$(P2P_OS_IF_INC) \ + -I$(WLAN_ROOT)/$(P2P_TARGET_IF_INC) +P2P_OBJS := $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_ucfg_api.o \ + $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_tgt_api.o \ + $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_cfg.o \ + $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_api.o \ + $(P2P_CORE_OBJ_DIR)/wlan_p2p_main.o \ + $(P2P_CORE_OBJ_DIR)/wlan_p2p_roc.o \ + $(P2P_CORE_OBJ_DIR)/wlan_p2p_off_chan_tx.o \ + $(P2P_OS_IF_SRC)/wlan_cfg80211_p2p.o \ + $(P2P_TARGET_IF_SRC)/target_if_p2p.o +ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y) +P2P_OBJS += $(P2P_DISPATCHER_OBJ_DIR)/wlan_p2p_mcc_quota_tgt_api.o \ + $(P2P_CORE_OBJ_DIR)/wlan_p2p_mcc_quota.o \ + $(P2P_TARGET_IF_SRC)/target_if_p2p_mcc_quota.o +endif +$(call add-wlan-objs,p2p,$(P2P_OBJS)) + +###### UMAC POLICY MGR ######## +POLICY_MGR_DIR := components/cmn_services/policy_mgr + +POLICY_MGR_INC := -I$(WLAN_ROOT)/$(POLICY_MGR_DIR)/inc \ + -I$(WLAN_ROOT)/$(POLICY_MGR_DIR)/src + +POLICY_MGR_OBJS := $(POLICY_MGR_DIR)/src/wlan_policy_mgr_action.o \ + $(POLICY_MGR_DIR)/src/wlan_policy_mgr_core.o \ + $(POLICY_MGR_DIR)/src/wlan_policy_mgr_get_set_utils.o \ + $(POLICY_MGR_DIR)/src/wlan_policy_mgr_init_deinit.o \ + $(POLICY_MGR_DIR)/src/wlan_policy_mgr_ucfg.o \ + $(POLICY_MGR_DIR)/src/wlan_policy_mgr_pcl.o +ifeq ($(CONFIG_WLAN_FEATURE_LL_LT_SAP), y) +POLICY_MGR_OBJS += $(POLICY_MGR_DIR)/src/wlan_policy_mgr_ll_sap.o +endif + +$(call add-wlan-objs,policy_mgr,$(POLICY_MGR_OBJS)) + +###### UMAC TDLS ######## +TDLS_DIR := components/tdls + +TDLS_OS_IF_INC := os_if/tdls/inc +TDLS_OS_IF_SRC := os_if/tdls/src +TDLS_TARGET_IF_INC := components/target_if/tdls/inc +TDLS_TARGET_IF_SRC := components/target_if/tdls/src +TDLS_INC := -I$(WLAN_ROOT)/$(TDLS_DIR)/dispatcher/inc \ + -I$(WLAN_ROOT)/$(TDLS_DIR)/core/src \ + -I$(WLAN_ROOT)/$(TDLS_OS_IF_INC) \ + -I$(WLAN_ROOT)/$(TDLS_TARGET_IF_INC) + +ifeq ($(CONFIG_QCOM_TDLS), y) +TDLS_OBJS := $(TDLS_DIR)/core/src/wlan_tdls_main.o \ + $(TDLS_DIR)/core/src/wlan_tdls_cmds_process.o \ + $(TDLS_DIR)/core/src/wlan_tdls_peer.o \ + $(TDLS_DIR)/core/src/wlan_tdls_mgmt.o \ + $(TDLS_DIR)/core/src/wlan_tdls_ct.o \ + $(TDLS_DIR)/dispatcher/src/wlan_tdls_tgt_api.o \ + $(TDLS_DIR)/dispatcher/src/wlan_tdls_ucfg_api.o \ + $(TDLS_DIR)/dispatcher/src/wlan_tdls_utils_api.o \ + $(TDLS_DIR)/dispatcher/src/wlan_tdls_cfg.o \ + $(TDLS_DIR)/dispatcher/src/wlan_tdls_api.o \ + $(TDLS_OS_IF_SRC)/wlan_cfg80211_tdls.o \ + $(TDLS_TARGET_IF_SRC)/target_if_tdls.o +endif + +$(call add-wlan-objs,tdls,$(TDLS_OBJS)) + +########### BMI ########### +BMI_DIR := core/bmi + +BMI_INC := -I$(WLAN_ROOT)/$(BMI_DIR)/inc + +ifeq ($(CONFIG_WLAN_FEATURE_BMI), y) +BMI_OBJS := $(BMI_DIR)/src/bmi.o \ + $(BMI_DIR)/src/bmi_1.o \ + $(BMI_DIR)/src/ol_fw.o \ + $(BMI_DIR)/src/ol_fw_common.o +endif + +$(call add-wlan-objs,bmi,$(BMI_OBJS)) + +########## TARGET_IF ####### +TARGET_IF_DIR := $(WLAN_COMMON_ROOT)/target_if + +TARGET_IF_INC := -I$(WLAN_COMMON_INC)/target_if/core/inc \ + -I$(WLAN_COMMON_INC)/target_if/init_deinit/inc \ + -I$(WLAN_COMMON_INC)/target_if/crypto/inc \ + -I$(WLAN_COMMON_INC)/target_if/regulatory/inc \ + -I$(WLAN_COMMON_INC)/target_if/mlme/vdev_mgr/inc \ + -I$(WLAN_COMMON_INC)/target_if/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/target_if/mlme/psoc/inc \ + -I$(WLAN_COMMON_INC)/target_if/ipa/inc + +TARGET_IF_OBJ := $(TARGET_IF_DIR)/core/src/target_if_main.o \ + $(TARGET_IF_DIR)/regulatory/src/target_if_reg.o \ + $(TARGET_IF_DIR)/regulatory/src/target_if_reg_lte.o \ + $(TARGET_IF_DIR)/regulatory/src/target_if_reg_11d.o \ + $(TARGET_IF_DIR)/init_deinit/src/init_cmd_api.o \ + $(TARGET_IF_DIR)/init_deinit/src/init_deinit_lmac.o \ + $(TARGET_IF_DIR)/init_deinit/src/init_event_handler.o \ + $(TARGET_IF_DIR)/init_deinit/src/service_ready_util.o \ + $(TARGET_IF_DIR)/mlme/vdev_mgr/src/target_if_vdev_mgr_tx_ops.o \ + $(TARGET_IF_DIR)/mlme/vdev_mgr/src/target_if_vdev_mgr_rx_ops.o \ + $(TARGET_IF_DIR)/mlme/psoc/src/target_if_psoc_timer_tx_ops.o + +ifeq ($(CONFIG_FEATURE_VDEV_OPS_WAKELOCK), y) +TARGET_IF_OBJ += $(TARGET_IF_DIR)/mlme/psoc/src/target_if_psoc_wake_lock.o +endif + +TARGET_IF_OBJ += $(TARGET_IF_DIR)/crypto/src/target_if_crypto.o + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +TARGET_IF_OBJ += $(TARGET_IF_DIR)/ipa/src/target_if_ipa.o +endif + +$(call add-wlan-objs,target_if,$(TARGET_IF_OBJ)) + +########### GLOBAL_LMAC_IF ########## +GLOBAL_LMAC_IF_DIR := $(WLAN_COMMON_ROOT)/global_lmac_if + +GLOBAL_LMAC_IF_INC := -I$(WLAN_COMMON_INC)/global_lmac_if/inc \ + +GLOBAL_LMAC_IF_OBJ := $(GLOBAL_LMAC_IF_DIR)/src/wlan_global_lmac_if.o + +$(call add-wlan-objs,global_lmac_if,$(GLOBAL_LMAC_IF_OBJ)) + +########### WMI ########### +WMI_ROOT_DIR := wmi + +WMI_SRC_DIR := $(WMI_ROOT_DIR)/src +WMI_INC_DIR := $(WMI_ROOT_DIR)/inc +WMI_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(WMI_SRC_DIR) + +WMI_INC := -I$(WLAN_COMMON_INC)/$(WMI_INC_DIR) + +WMI_OBJS := $(WMI_OBJ_DIR)/wmi_unified.o \ + $(WMI_OBJ_DIR)/wmi_tlv_helper.o \ + $(WMI_OBJ_DIR)/wmi_unified_tlv.o \ + $(WMI_OBJ_DIR)/wmi_unified_api.o \ + $(WMI_OBJ_DIR)/wmi_unified_reg_api.o \ + $(WMI_OBJ_DIR)/wmi_unified_vdev_api.o \ + $(WMI_OBJ_DIR)/wmi_unified_vdev_tlv.o \ + $(WMI_OBJ_DIR)/wmi_unified_crypto_api.o + +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_pmo_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_pmo_tlv.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_APF), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_apf_tlv.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_ACTION_OUI), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_action_oui_tlv.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +ifeq ($(CONFIG_OCB_UT_FRAMEWORK), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_ocb_ut.o +endif +endif + +ifeq ($(CONFIG_WLAN_DFS_MASTER_ENABLE), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_dfs_api.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_TWT), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_twt_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_twt_tlv.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_ocb_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_ocb_tlv.o +endif + +ifeq ($(CONFIG_FEATURE_WLAN_EXTSCAN), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_extscan_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_extscan_tlv.o +endif + +ifeq ($(CONFIG_FEATURE_INTEROP_ISSUES_AP), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_interop_issues_ap_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_interop_issues_ap_tlv.o +endif + +ifeq ($(CONFIG_DCS), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_dcs_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_dcs_tlv.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_nan_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_nan_tlv.o +endif + +ifeq ($(CONFIG_CONVERGED_P2P_ENABLE), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_p2p_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_p2p_tlv.o +endif + +ifeq ($(CONFIG_WMI_CONCURRENCY_SUPPORT), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_concurrency_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_concurrency_tlv.o +endif + +ifeq ($(CONFIG_WMI_STA_SUPPORT), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_sta_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_sta_tlv.o +endif + +ifeq ($(CONFIG_WMI_BCN_OFFLOAD), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_bcn_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_bcn_tlv.o +endif + +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_fwol_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_fwol_tlv.o +endif + +ifeq ($(CONFIG_WLAN_HANG_EVENT), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_hang_event.o +endif + +ifeq ($(CONFIG_WLAN_CFR_ENABLE), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_cfr_tlv.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_cfr_api.o +endif + +ifeq ($(CONFIG_CP_STATS), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_cp_stats_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_cp_stats_tlv.o +endif + +ifeq ($(CONFIG_FEATURE_GPIO_CFG), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_gpio_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_gpio_tlv.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_11BE_MLO), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_11be_tlv.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_11be_api.o +endif + +ifeq ($(CONFIG_FEATURE_WDS), y) +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_wds_api.o +WMI_OBJS += $(WMI_OBJ_DIR)/wmi_unified_wds_tlv.o +endif + +$(call add-wlan-objs,wmi,$(WMI_OBJS)) + +########### FWLOG ########### +FWLOG_DIR := $(WLAN_COMMON_ROOT)/utils/fwlog + +FWLOG_INC := -I$(WLAN_ROOT)/$(FWLOG_DIR) + +ifeq ($(CONFIG_FEATURE_FW_LOG_PARSING), y) +FWLOG_OBJS := $(FWLOG_DIR)/dbglog_host.o +endif + +$(call add-wlan-objs,fwlog,$(FWLOG_OBJS)) + +############ TXRX ############ +TXRX_DIR := core/dp/txrx +TXRX_INC := -I$(WLAN_ROOT)/$(TXRX_DIR) + +TXRX_OBJS := +ifeq ($(CONFIG_WDI_EVENT_ENABLE), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_event.o +endif + +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx.o \ + $(TXRX_DIR)/ol_cfg.o \ + $(TXRX_DIR)/ol_rx.o \ + $(TXRX_DIR)/ol_rx_fwd.o \ + $(TXRX_DIR)/ol_txrx.o \ + $(TXRX_DIR)/ol_rx_defrag.o \ + $(TXRX_DIR)/ol_tx_desc.o \ + $(TXRX_DIR)/ol_tx.o \ + $(TXRX_DIR)/ol_rx_reorder_timeout.o \ + $(TXRX_DIR)/ol_rx_reorder.o \ + $(TXRX_DIR)/ol_rx_pn.o \ + $(TXRX_DIR)/ol_txrx_peer_find.o \ + $(TXRX_DIR)/ol_txrx_encap.o \ + $(TXRX_DIR)/ol_tx_send.o + +ifeq ($(CONFIG_LL_DP_SUPPORT), y) + +TXRX_OBJS += $(TXRX_DIR)/ol_tx_ll.o + +ifeq ($(CONFIG_WLAN_FASTPATH), y) +TXRX_OBJS += $(TXRX_DIR)/ol_tx_ll_fastpath.o +else +TXRX_OBJS += $(TXRX_DIR)/ol_tx_ll_legacy.o +endif + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_flow_control.o +endif + +endif #CONFIG_LL_DP_SUPPORT + +ifeq ($(CONFIG_HL_DP_SUPPORT), y) +TXRX_OBJS += $(TXRX_DIR)/ol_tx_hl.o +TXRX_OBJS += $(TXRX_DIR)/ol_tx_classify.o +TXRX_OBJS += $(TXRX_DIR)/ol_tx_sched.o +TXRX_OBJS += $(TXRX_DIR)/ol_tx_queue.o +endif #CONFIG_HL_DP_SUPPORT + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_legacy_flow_control.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +TXRX_OBJS += $(TXRX_DIR)/ol_txrx_ipa.o +endif + +ifeq ($(CONFIG_QCA_SUPPORT_TX_THROTTLE), y) +TXRX_OBJS += $(TXRX_DIR)/ol_tx_throttle.o +endif +endif #LITHIUM/BERYLLIUM/RHINE + +$(call add-wlan-objs,txrx,$(TXRX_OBJS)) + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +############ DP 3.0 ############ +DP_INC := -I$(WLAN_COMMON_INC)/dp/inc \ + -I$(WLAN_COMMON_INC)/dp/wifi3.0 \ + -I$(WLAN_COMMON_INC)/target_if/dp/inc \ + -I$(WLAN_COMMON_INC)/dp/cmn_dp_api + +DP_SRC := $(WLAN_COMMON_ROOT)/dp/wifi3.0 +DP_OBJS := $(DP_SRC)/dp_main.o \ + $(DP_SRC)/dp_tx.o \ + $(DP_SRC)/dp_arch_ops.o \ + $(DP_SRC)/dp_tx_desc.o \ + $(DP_SRC)/dp_rx.o \ + $(DP_SRC)/dp_htt.o \ + $(DP_SRC)/dp_peer.o \ + $(DP_SRC)/dp_rx_desc.o \ + $(DP_SRC)/dp_rx_defrag.o \ + $(DP_SRC)/dp_stats.o \ + $(WLAN_COMMON_ROOT)/target_if/dp/src/target_if_dp.o + +ifneq ($(CONFIG_RHINE), y) +DP_OBJS += $(DP_SRC)/dp_rings_main.o +DP_OBJS += $(DP_SRC)/dp_reo.o +DP_OBJS += $(DP_SRC)/dp_rx_err.o +DP_OBJS += $(DP_SRC)/dp_rx_tid.o +endif + +ifeq ($(CONFIG_WIFI_MONITOR_SUPPORT), y) +DP_INC += -I$(WLAN_COMMON_INC)/dp/wifi3.0/monitor \ + -I$(WLAN_COMMON_INC)/dp/wifi3.0/monitor/1.0 \ + -I$(WLAN_COMMON_INC)/dp/wifi3.0/monitor/2.0 \ + +DP_OBJS += $(DP_SRC)/monitor/dp_mon.o \ + $(DP_SRC)/monitor/dp_mon_filter.o \ + $(DP_SRC)/monitor/dp_rx_mon.o \ + $(DP_SRC)/monitor/1.0/dp_rx_mon_dest_1.0.o \ + $(DP_SRC)/monitor/1.0/dp_rx_mon_status_1.0.o \ + $(DP_SRC)/monitor/1.0/dp_mon_filter_1.0.o \ + $(DP_SRC)/monitor/1.0/dp_mon_1.0.o +endif + +DP_OBJS += $(DP_SRC)/../cmn_dp_api/dp_ratetable.o + +ifeq ($(CONFIG_BERYLLIUM), y) +DP_INC += -I$(WLAN_COMMON_INC)/dp/wifi3.0/be + +DP_OBJS += $(DP_SRC)/be/dp_be.o +DP_OBJS += $(DP_SRC)/be/dp_be_tx.o +DP_OBJS += $(DP_SRC)/be/dp_be_rx.o + +ifeq ($(CONFIG_WIFI_MONITOR_SUPPORT), y) +ifeq ($(CONFIG_WLAN_TX_MON_2_0), y) +DP_OBJS += $(DP_SRC)/monitor/2.0/dp_mon_2.0.o \ + $(DP_SRC)/monitor/2.0/dp_mon_filter_2.0.o +DP_OBJS += $(DP_SRC)/monitor/2.0/dp_tx_mon_2.0.o \ + $(DP_SRC)/monitor/2.0/dp_tx_mon_status_2.0.o +ccflags-$(CONFIG_WLAN_TX_MON_2_0) += -DWLAN_PKT_CAPTURE_TX_2_0 +ccflags-y += -DWLAN_TX_PKT_CAPTURE_ENH_BE +ccflags-y += -DQDF_FRAG_CACHE_SUPPORT +endif +endif +endif + +ifeq ($(CONFIG_LITHIUM), y) +DP_OBJS += $(DP_SRC)/li/dp_li.o +DP_OBJS += $(DP_SRC)/li/dp_li_tx.o +DP_OBJS += $(DP_SRC)/li/dp_li_rx.o +endif + +ifeq ($(CONFIG_RHINE), y) +DP_OBJS += $(DP_SRC)/rh/dp_rh.o +DP_OBJS += $(DP_SRC)/rh/dp_rh_tx.o +DP_OBJS += $(DP_SRC)/rh/dp_rh_rx.o +DP_OBJS += $(DP_SRC)/rh/dp_rh_htt.o +endif + +ifeq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +DP_OBJS += $(DP_SRC)/dp_tx_flow_control.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_RX_BUFFER_POOL), y) +DP_OBJS += $(DP_SRC)/dp_rx_buffer_pool.o +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +DP_OBJS += $(DP_SRC)/dp_ipa.o +endif + +ifeq ($(CONFIG_WDI_EVENT_ENABLE), y) +DP_OBJS += $(DP_SRC)/dp_wdi_event.o +endif + +ifeq ($(CONFIG_FEATURE_MEC), y) +DP_OBJS += $(DP_SRC)/dp_txrx_wds.o +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +DP_OBJS += $(WLAN_COMMON_ROOT)/dp/cmn_dp_api/dp_ratetable.o +DP_INC += -I$(WLAN_COMMON_INC)/dp/cmn_dp_api +endif + +endif #LITHIUM + +$(call add-wlan-objs,dp,$(DP_OBJS)) + +############ CFG ############ +WCFG_DIR := wlan_cfg +WCFG_INC := -I$(WLAN_COMMON_INC)/$(WCFG_DIR) +WCFG_SRC := $(WLAN_COMMON_ROOT)/$(WCFG_DIR) + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +WCFG_OBJS := $(WCFG_SRC)/wlan_cfg.o +endif + +$(call add-wlan-objs,wcfg,$(WCFG_OBJS)) + +############ OL ############ +OL_DIR := core/dp/ol +OL_INC := -I$(WLAN_ROOT)/$(OL_DIR)/inc + +############ CDP ############ +CDP_ROOT_DIR := dp +CDP_INC_DIR := $(CDP_ROOT_DIR)/inc +CDP_INC := -I$(WLAN_COMMON_INC)/$(CDP_INC_DIR) + +############ PKTLOG ############ +PKTLOG_DIR := $(WLAN_COMMON_ROOT)/utils/pktlog +PKTLOG_INC := -I$(WLAN_ROOT)/$(PKTLOG_DIR)/include + +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +PKTLOG_OBJS := $(PKTLOG_DIR)/pktlog_ac.o \ + $(PKTLOG_DIR)/pktlog_internal.o \ + $(PKTLOG_DIR)/linux_ac.o + +ifeq ($(CONFIG_PKTLOG_LEGACY), y) + PKTLOG_OBJS += $(PKTLOG_DIR)/pktlog_wifi2.o +else + PKTLOG_OBJS += $(PKTLOG_DIR)/pktlog_wifi3.o +endif + +endif + + +$(call add-wlan-objs,pktlog,$(PKTLOG_OBJS)) + +############ HTT ############ +HTT_DIR := core/dp/htt +HTT_INC := -I$(WLAN_ROOT)/$(HTT_DIR) + +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +HTT_OBJS := $(HTT_DIR)/htt_tx.o \ + $(HTT_DIR)/htt.o \ + $(HTT_DIR)/htt_t2h.o \ + $(HTT_DIR)/htt_h2t.o \ + $(HTT_DIR)/htt_fw_stats.o \ + $(HTT_DIR)/htt_rx.o + +ifeq ($(CONFIG_FEATURE_MONITOR_MODE_SUPPORT), y) +HTT_OBJS += $(HTT_DIR)/htt_monitor_rx.o +endif + +ifeq ($(CONFIG_LL_DP_SUPPORT), y) +HTT_OBJS += $(HTT_DIR)/htt_rx_ll.o +endif + +ifeq ($(CONFIG_HL_DP_SUPPORT), y) +HTT_OBJS += $(HTT_DIR)/htt_rx_hl.o +endif +endif + +$(call add-wlan-objs,htt,$(HTT_OBJS)) + +############## INIT-DEINIT ########### +INIT_DEINIT_DIR := init_deinit/dispatcher +INIT_DEINIT_INC_DIR := $(INIT_DEINIT_DIR)/inc +INIT_DEINIT_SRC_DIR := $(INIT_DEINIT_DIR)/src +INIT_DEINIT_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(INIT_DEINIT_SRC_DIR) +INIT_DEINIT_INC := -I$(WLAN_COMMON_INC)/$(INIT_DEINIT_INC_DIR) +INIT_DEINIT_OBJS := $(INIT_DEINIT_OBJ_DIR)/dispatcher_init_deinit.o + +$(call add-wlan-objs,init_deinit,$(INIT_DEINIT_OBJS)) + +############## REGULATORY ########### +REGULATORY_DIR := umac/regulatory +REGULATORY_CORE_SRC_DIR := $(REGULATORY_DIR)/core/src +REG_DISPATCHER_INC_DIR := $(REGULATORY_DIR)/dispatcher/inc +REG_DISPATCHER_SRC_DIR := $(REGULATORY_DIR)/dispatcher/src +REG_CORE_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(REGULATORY_CORE_SRC_DIR) +REG_DISPATCHER_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(REG_DISPATCHER_SRC_DIR) +REGULATORY_INC := -I$(WLAN_COMMON_INC)/$(REGULATORY_CORE_SRC_DIR) +REGULATORY_INC += -I$(WLAN_COMMON_INC)/$(REG_DISPATCHER_INC_DIR) +REGULATORY_INC += -I$(WLAN_COMMON_INC)/umac/cmn_services/regulatory/inc +REGULATORY_OBJS := $(REG_CORE_OBJ_DIR)/reg_build_chan_list.o \ + $(REG_CORE_OBJ_DIR)/reg_callbacks.o \ + $(REG_CORE_OBJ_DIR)/reg_db.o \ + $(REG_CORE_OBJ_DIR)/reg_db_parser.o \ + $(REG_CORE_OBJ_DIR)/reg_utils.o \ + $(REG_CORE_OBJ_DIR)/reg_lte.o \ + $(REG_CORE_OBJ_DIR)/reg_offload_11d_scan.o \ + $(REG_CORE_OBJ_DIR)/reg_opclass.o \ + $(REG_CORE_OBJ_DIR)/reg_priv_objs.o \ + $(REG_DISPATCHER_OBJ_DIR)/wlan_reg_services_api.o \ + $(REG_CORE_OBJ_DIR)/reg_services_common.o \ + $(REG_DISPATCHER_OBJ_DIR)/wlan_reg_tgt_api.o \ + $(REG_DISPATCHER_OBJ_DIR)/wlan_reg_ucfg_api.o +ifeq ($(CONFIG_HOST_11D_SCAN), y) +REGULATORY_OBJS += $(REG_CORE_OBJ_DIR)/reg_host_11d.o +endif + +$(call add-wlan-objs,regulatory,$(REGULATORY_OBJS)) + +############## Control path common scheduler ########## +SCHEDULER_DIR := scheduler +SCHEDULER_INC_DIR := $(SCHEDULER_DIR)/inc +SCHEDULER_SRC_DIR := $(SCHEDULER_DIR)/src +SCHEDULER_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(SCHEDULER_SRC_DIR) +SCHEDULER_INC := -I$(WLAN_COMMON_INC)/$(SCHEDULER_INC_DIR) +SCHEDULER_OBJS := $(SCHEDULER_OBJ_DIR)/scheduler_api.o \ + $(SCHEDULER_OBJ_DIR)/scheduler_core.o + +$(call add-wlan-objs,scheduler,$(SCHEDULER_OBJS)) + +###### UMAC SERIALIZATION ######## +UMAC_SER_DIR := umac/cmn_services/serialization +UMAC_SER_INC_DIR := $(UMAC_SER_DIR)/inc +UMAC_SER_SRC_DIR := $(UMAC_SER_DIR)/src +UMAC_SER_OBJ_DIR := $(WLAN_COMMON_ROOT)/$(UMAC_SER_SRC_DIR) + +UMAC_SER_INC := -I$(WLAN_COMMON_INC)/$(UMAC_SER_INC_DIR) +UMAC_SER_OBJS := $(UMAC_SER_OBJ_DIR)/wlan_serialization_main.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_api.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_utils.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_legacy_api.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_rules.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_internal.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_non_scan.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_queue.o \ + $(UMAC_SER_OBJ_DIR)/wlan_serialization_scan.o + +$(call add-wlan-objs,umac_ser,$(UMAC_SER_OBJS)) + +###### WIFI POS ######## +WIFI_POS_OS_IF_DIR := $(WLAN_COMMON_ROOT)/os_if/linux/wifi_pos/src +WIFI_POS_OS_IF_INC := -I$(WLAN_COMMON_INC)/os_if/linux/wifi_pos/inc +WIFI_POS_TGT_DIR := $(WLAN_COMMON_ROOT)/target_if/wifi_pos/src +WIFI_POS_TGT_INC := -I$(WLAN_COMMON_INC)/target_if/wifi_pos/inc +WIFI_POS_CORE_DIR := $(WLAN_COMMON_ROOT)/umac/wifi_pos/src +WIFI_POS_API_INC := -I$(WLAN_COMMON_INC)/umac/wifi_pos/inc + + +ifeq ($(CONFIG_WIFI_POS_CONVERGED), y) + +WIFI_POS_CLD_DIR := components/wifi_pos +WIFI_POS_CLD_CORE_DIR := $(WIFI_POS_CLD_DIR)/core +WIFI_POS_CLD_CORE_SRC := $(WIFI_POS_CLD_CORE_DIR)/src +WIFI_POS_CLD_DISP_DIR := $(WIFI_POS_CLD_DIR)/dispatcher + +WIFI_POS_OBJS := $(WIFI_POS_CORE_DIR)/wifi_pos_api.o \ + $(WIFI_POS_CORE_DIR)/wifi_pos_main.o \ + $(WIFI_POS_CORE_DIR)/wifi_pos_ucfg.o \ + $(WIFI_POS_CORE_DIR)/wifi_pos_utils.o \ + $(WIFI_POS_CLD_DISP_DIR)/src/wifi_pos_ucfg_api.o \ + $(WIFI_POS_OS_IF_DIR)/os_if_wifi_pos.o \ + $(WIFI_POS_OS_IF_DIR)/os_if_wifi_pos_utils.o \ + $(WIFI_POS_OS_IF_DIR)/wlan_cfg80211_wifi_pos.o \ + $(WIFI_POS_TGT_DIR)/target_if_wifi_pos.o \ + $(WIFI_POS_TGT_DIR)/target_if_wifi_pos_rx_ops.o \ + $(WIFI_POS_TGT_DIR)/target_if_wifi_pos_tx_ops.o + +ifeq ($(CONFIG_WIFI_POS_PASN), y) +WIFI_POS_OBJS += $(WIFI_POS_CORE_DIR)/wifi_pos_pasn_api.o +WIFI_POS_OBJS += $(WIFI_POS_CLD_CORE_SRC)/wlan_wifi_pos_interface.o +endif + +WIFI_POS_CLD_INC := -I$(WLAN_ROOT)/$(WIFI_POS_CLD_CORE_DIR)/inc \ + -I$(WLAN_ROOT)/$(WIFI_POS_CLD_DISP_DIR)/inc +endif + +$(call add-wlan-objs,wifi_pos,$(WIFI_POS_OBJS)) + +###### TWT CONVERGED ######## +TWT_CONV_CMN_OSIF_SRC := $(WLAN_COMMON_ROOT)/os_if/linux/twt/src +TWT_CONV_CMN_DISPATCHER_SRC := $(WLAN_COMMON_ROOT)/umac/twt/dispatcher/src +TWT_CONV_CMN_CORE_SRC := $(WLAN_COMMON_ROOT)/umac/twt/core/src +TWT_CONV_CMN_TGT_SRC := $(WLAN_COMMON_ROOT)/target_if/twt/src +TWT_CONV_OSIF_SRC := os_if/twt/src +TWT_CONV_DISPATCHER_SRC := components/umac/twt/dispatcher/src +TWT_CONV_CORE_SRC := components/umac/twt/core/src +TWT_CONV_TGT_SRC := components/target_if/twt/src + +TWT_CONV_INCS := -I$(WLAN_COMMON_INC)/umac \ + -I$(WLAN_ROOT)/components/umac \ + -I$(WLAN_COMMON_INC)/os_if/linux/twt/inc \ + -I$(WLAN_COMMON_INC)/umac/twt/dispatcher/inc \ + -I$(WLAN_COMMON_INC)/target_if/twt/inc \ + -I$(WLAN_ROOT)/os_if/twt/inc \ + -I$(WLAN_ROOT)/components/umac/twt/dispatcher/inc \ + -I$(WLAN_ROOT)/components/target_if/twt/inc + + +ifeq ($(CONFIG_WLAN_TWT_CONVERGED), y) +TWT_CONV_OBJS := $(TWT_CONV_CMN_OSIF_SRC)/osif_twt_req.o \ + $(TWT_CONV_CMN_OSIF_SRC)/osif_twt_rsp.o \ + $(TWT_CONV_CMN_DISPATCHER_SRC)/wlan_twt_api.o \ + $(TWT_CONV_CMN_DISPATCHER_SRC)/wlan_twt_tgt_if_rx_api.o \ + $(TWT_CONV_CMN_DISPATCHER_SRC)/wlan_twt_tgt_if_tx_api.o \ + $(TWT_CONV_CMN_DISPATCHER_SRC)/wlan_twt_ucfg_api.o \ + $(TWT_CONV_CMN_CORE_SRC)/wlan_twt_common.o \ + $(TWT_CONV_CMN_CORE_SRC)/wlan_twt_objmgr.o \ + $(TWT_CONV_CMN_TGT_SRC)/target_if_twt_cmd.o \ + $(TWT_CONV_CMN_TGT_SRC)/target_if_twt_evt.o \ + $(TWT_CONV_CMN_TGT_SRC)/target_if_twt.o \ + $(TWT_CONV_OSIF_SRC)/osif_twt_ext_req.o \ + $(TWT_CONV_OSIF_SRC)/osif_twt_ext_rsp.o \ + $(TWT_CONV_OSIF_SRC)/osif_twt_ext_util.o \ + $(TWT_CONV_DISPATCHER_SRC)/wlan_twt_ucfg_ext_api.o \ + $(TWT_CONV_DISPATCHER_SRC)/wlan_twt_cfg_ext_api.o \ + $(TWT_CONV_DISPATCHER_SRC)/wlan_twt_tgt_if_ext_rx_api.o \ + $(TWT_CONV_DISPATCHER_SRC)/wlan_twt_tgt_if_ext_tx_api.o \ + $(TWT_CONV_CORE_SRC)/wlan_twt_cfg.o \ + $(TWT_CONV_CORE_SRC)/wlan_twt_main.o \ + $(TWT_CONV_TGT_SRC)/target_if_ext_twt_cmd.o \ + $(TWT_CONV_TGT_SRC)/target_if_ext_twt_evt.o +endif + +$(call add-wlan-objs,twt_conv,$(TWT_CONV_OBJS)) + +###### CP STATS ######## +CP_MC_STATS_OS_IF_SRC := os_if/cp_stats/src +CP_STATS_TGT_SRC := $(WLAN_COMMON_ROOT)/target_if/cp_stats/src +CP_STATS_CORE_SRC := $(WLAN_COMMON_ROOT)/umac/cp_stats/core/src +CP_STATS_DISPATCHER_SRC := $(WLAN_COMMON_ROOT)/umac/cp_stats/dispatcher/src +CP_MC_STATS_COMPONENT_SRC := components/cp_stats/dispatcher/src +CP_MC_STATS_COMPONENT_TGT_SRC := $(CLD_TARGET_IF_DIR)/cp_stats/src + +CP_STATS_OS_IF_INC := -I$(WLAN_COMMON_INC)/os_if/linux/cp_stats/inc +CP_STATS_TGT_INC := -I$(WLAN_COMMON_INC)/target_if/cp_stats/inc +CP_STATS_DISPATCHER_INC := -I$(WLAN_COMMON_INC)/umac/cp_stats/dispatcher/inc +CP_MC_STATS_COMPONENT_INC := -I$(WLAN_ROOT)/components/cp_stats/dispatcher/inc +CP_STATS_CFG80211_OS_IF_INC := -I$(WLAN_ROOT)/os_if/cp_stats/inc + +ifeq ($(CONFIG_CP_STATS), y) +CP_STATS_OBJS := $(CP_MC_STATS_COMPONENT_SRC)/wlan_cp_stats_mc_tgt_api.o \ + $(CP_MC_STATS_COMPONENT_SRC)/wlan_cp_stats_mc_ucfg_api.o \ + $(CP_MC_STATS_COMPONENT_TGT_SRC)/target_if_mc_cp_stats.o \ + $(CP_STATS_CORE_SRC)/wlan_cp_stats_comp_handler.o \ + $(CP_STATS_CORE_SRC)/wlan_cp_stats_obj_mgr_handler.o \ + $(CP_STATS_CORE_SRC)/wlan_cp_stats_ol_api.o \ + $(CP_MC_STATS_OS_IF_SRC)/wlan_cfg80211_mc_cp_stats.o \ + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_utils_api.o \ + $(WLAN_COMMON_ROOT)/target_if/cp_stats/src/target_if_cp_stats.o \ + $(CP_STATS_DISPATCHER_SRC)/wlan_cp_stats_ucfg_api.o + +endif + +$(call add-wlan-objs,cp_stats,$(CP_STATS_OBJS)) + +###### DCS ###### +DCS_TGT_IF_SRC := $(WLAN_COMMON_ROOT)/target_if/dcs/src +DCS_CORE_SRC := $(WLAN_COMMON_ROOT)/umac/dcs/core/src +DCS_DISP_SRC := $(WLAN_COMMON_ROOT)/umac/dcs/dispatcher/src + +DCS_TGT_IF_INC := -I$(WLAN_COMMON_INC)/target_if/dcs/inc +DCS_DISP_INC := -I$(WLAN_COMMON_INC)/umac/dcs/dispatcher/inc + +ifeq ($(CONFIG_DCS), y) +DCS_OBJS := $(DCS_TGT_IF_SRC)/target_if_dcs.o \ + $(DCS_CORE_SRC)/wlan_dcs.o \ + $(DCS_DISP_SRC)/wlan_dcs_init_deinit_api.o \ + $(DCS_DISP_SRC)/wlan_dcs_ucfg_api.o \ + $(DCS_DISP_SRC)/wlan_dcs_tgt_api.o +endif + +$(call add-wlan-objs,dcs,$(DCS_OBJS)) + +####### AFC ###### +AFC_CMN_OSIF_SRC := $(WLAN_COMMON_ROOT)/os_if/linux/afc/src +AFC_CMN_CORE_SRC := $(WLAN_COMMON_ROOT)/umac/afc/core/src +AFC_CMN_DISP_SRC := $(WLAN_COMMON_ROOT)/umac/afc/dispatcher/src + +AFC_CMN_OSIF_INC := -I$(WLAN_COMMON_INC)/os_if/linux/afc/inc +AFC_CMN_DISP_INC := -I$(WLAN_COMMON_INC)/umac/afc/dispatcher/inc +AFC_CMN_CORE_INC := -I$(WLAN_COMMON_INC)/umac/afc/core/inc + +ifeq ($(CONFIG_AFC_SUPPORT), y) +AFC_OBJS := $(AFC_CMN_OSIF_SRC)/wlan_cfg80211_afc.o \ + $(AFC_CMN_CORE_SRC)/wlan_afc_main.o \ + $(AFC_CMN_DISP_SRC)/wlan_afc_ucfg_api.o +endif + +$(call add-wlan-objs,afc,$(AFC_OBJS)) + +###### INTEROP ISSUES AP ######## +INTEROP_ISSUES_AP_OS_IF_SRC := os_if/interop_issues_ap/src +INTEROP_ISSUES_AP_TGT_SRC := components/target_if/interop_issues_ap/src +INTEROP_ISSUES_AP_CORE_SRC := components/interop_issues_ap/core/src +INTEROP_ISSUES_AP_DISPATCHER_SRC := components/interop_issues_ap/dispatcher/src + +INTEROP_ISSUES_AP_OS_IF_INC := -I$(WLAN_ROOT)/os_if/interop_issues_ap/inc +INTEROP_ISSUES_AP_TGT_INC := -I$(WLAN_ROOT)/components/target_if/interop_issues_ap/inc +INTEROP_ISSUES_AP_DISPATCHER_INC := -I$(WLAN_ROOT)/components/interop_issues_ap/dispatcher/inc +INTEROP_ISSUES_AP_CORE_INC := -I$(WLAN_ROOT)/components/interop_issues_ap/core/inc + +ifeq ($(CONFIG_FEATURE_INTEROP_ISSUES_AP), y) +INTEROP_ISSUES_AP_OBJS := $(INTEROP_ISSUES_AP_TGT_SRC)/target_if_interop_issues_ap.o \ + $(INTEROP_ISSUES_AP_CORE_SRC)/wlan_interop_issues_ap_api.o \ + $(INTEROP_ISSUES_AP_OS_IF_SRC)/wlan_cfg80211_interop_issues_ap.o \ + $(INTEROP_ISSUES_AP_DISPATCHER_SRC)/wlan_interop_issues_ap_tgt_api.o \ + $(INTEROP_ISSUES_AP_DISPATCHER_SRC)/wlan_interop_issues_ap_ucfg_api.o +endif + +$(call add-wlan-objs,interop_issues_ap,$(INTEROP_ISSUES_AP_OBJS)) + +######################### NAN ######################### +NAN_CORE_DIR := components/nan/core/src +NAN_CORE_INC := -I$(WLAN_ROOT)/components/nan/core/inc +NAN_UCFG_DIR := components/nan/dispatcher/src +NAN_UCFG_INC := -I$(WLAN_ROOT)/components/nan/dispatcher/inc +NAN_TGT_DIR := components/target_if/nan/src +NAN_TGT_INC := -I$(WLAN_ROOT)/components/target_if/nan/inc + +NAN_OS_IF_DIR := os_if/nan/src +NAN_OS_IF_INC := -I$(WLAN_ROOT)/os_if/nan/inc + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y) +WLAN_NAN_OBJS := $(NAN_CORE_DIR)/nan_main.o \ + $(NAN_CORE_DIR)/nan_api.o \ + $(NAN_UCFG_DIR)/nan_ucfg_api.o \ + $(NAN_UCFG_DIR)/wlan_nan_api.o \ + $(NAN_UCFG_DIR)/cfg_nan.o \ + $(NAN_TGT_DIR)/target_if_nan.o \ + $(NAN_OS_IF_DIR)/os_if_nan.o +endif + +$(call add-wlan-objs,nan,$(WLAN_NAN_OBJS)) + +####################################################### + +######################### DP_COMPONENT ######################### +DP_COMP_CORE_DIR := components/dp/core/src +DP_COMP_UCFG_DIR := components/dp/dispatcher/src +DP_COMP_TGT_DIR := components/target_if/dp/src +DP_COMP_OS_IF_DIR := os_if/dp/src + +DP_COMP_INC := -I$(WLAN_ROOT)/components/dp/core/inc \ + -I$(WLAN_ROOT)/components/dp/core/src \ + -I$(WLAN_ROOT)/components/dp/dispatcher/inc \ + -I$(WLAN_ROOT)/components/target_if/dp/inc \ + -I$(WLAN_ROOT)/os_if/dp/inc + +WLAN_DP_COMP_OBJS := $(DP_COMP_CORE_DIR)/wlan_dp_main.o \ + $(DP_COMP_UCFG_DIR)/wlan_dp_ucfg_api.o \ + $(DP_COMP_UCFG_DIR)/wlan_dp_api.o \ + $(DP_COMP_OS_IF_DIR)/os_if_dp.o \ + $(DP_COMP_OS_IF_DIR)/os_if_dp_txrx.o \ + $(DP_COMP_CORE_DIR)/wlan_dp_bus_bandwidth.o \ + $(DP_COMP_CORE_DIR)/wlan_dp_softap_txrx.o \ + $(DP_COMP_CORE_DIR)/wlan_dp_txrx.o \ + $(DP_COMP_TGT_DIR)/target_if_dp_comp.o + +ifeq ($(CONFIG_WLAN_LRO), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_OS_IF_DIR)/os_if_dp_lro.o +endif + +ifeq ($(CONFIG_WLAN_NUD_TRACKING), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_nud_tracking.o +endif + +ifeq ($(CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_periodic_sta_stats.o +endif + +ifeq ($(CONFIG_DP_SWLM), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_swlm.o +endif + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_prealloc.o + +ifeq ($(CONFIG_WLAN_TX_MON_2_0), y) +ifeq ($(CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_OS_IF_DIR)/os_if_dp_local_pkt_capture.o +endif #CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE +endif #CONFIG_WLAN_TX_MON_2_0 +endif + +ifeq ($(CONFIG_WLAN_FEATURE_DP_RX_THREADS), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_rx_thread.o +endif + +ifeq ($(CONFIG_RX_FISA), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_fisa_rx.o +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_rx_fst.o +endif + +ifeq ($(CONFIG_FEATURE_DIRECT_LINK), y) +WLAN_DP_COMP_OBJS += $(DP_COMP_CORE_DIR)/wlan_dp_wfds.o +endif + +$(call add-wlan-objs,dp_comp,$(WLAN_DP_COMP_OBJS)) + +####################################################### + +######################### QMI_COMPONENT ######################### +QMI_COMP_CORE_DIR := components/qmi/core/src +QMI_COMP_UCFG_DIR := components/qmi/dispatcher/src +QMI_COMP_OS_IF_DIR := os_if/qmi/src + +QMI_COMP_INC := -I$(WLAN_ROOT)/components/qmi/core/inc \ + -I$(WLAN_ROOT)/components/qmi/core/src \ + -I$(WLAN_ROOT)/components/qmi/dispatcher/inc \ + -I$(WLAN_ROOT)/os_if/qmi/inc + +ifeq ($(CONFIG_QMI_COMPONENT_ENABLE), y) +WLAN_QMI_COMP_OBJS := $(QMI_COMP_CORE_DIR)/wlan_qmi_main.o \ + $(QMI_COMP_UCFG_DIR)/wlan_qmi_ucfg_api.o \ + $(QMI_COMP_OS_IF_DIR)/os_if_qmi.o + +ifeq ($(CONFIG_QMI_WFDS), y) +WLAN_QMI_COMP_OBJS += $(QMI_COMP_OS_IF_DIR)/os_if_qmi_wifi_driver_service_v01.o +WLAN_QMI_COMP_OBJS += $(QMI_COMP_OS_IF_DIR)/os_if_qmi_wfds.o +WLAN_QMI_COMP_OBJS += $(QMI_COMP_UCFG_DIR)/wlan_qmi_wfds_api.o +endif +endif + +$(call add-wlan-objs,qmi_comp,$(WLAN_QMI_COMP_OBJS)) + +####################################################### + +######################### SON ######################### +#SON_CORE_DIR := components/son/core/src +#SON_CORE_INC := -I$(WLAN_ROOT)/components/son/core/inc +SON_UCFG_DIR := components/son/dispatcher/src +SON_UCFG_INC := -I$(WLAN_ROOT)/components/son/dispatcher/inc +SON_TGT_DIR := $(WLAN_COMMON_ROOT)/target_if/son/src +SON_TGT_INC := -I$(WLAN_COMMON_INC)/target_if/son/inc/ + +SON_OS_IF_DIR := os_if/son/src +SON_OS_IF_INC := -I$(WLAN_ROOT)/os_if/son/inc + +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +WLAN_SON_OBJS := $(SON_UCFG_DIR)/son_ucfg_api.o \ + $(SON_UCFG_DIR)/son_api.o \ + $(SON_OS_IF_DIR)/os_if_son.o \ + $(SON_TGT_DIR)/target_if_son.o +endif + +$(call add-wlan-objs,son,$(WLAN_SON_OBJS)) + +####################################################### + +######################### SPATIAL_REUSE ######################### +SR_UCFG_DIR := components/spatial_reuse/dispatcher/src +SR_UCFG_INC := -I$(WLAN_ROOT)/components/spatial_reuse/dispatcher/inc +SR_TGT_DIR := $(WLAN_COMMON_ROOT)/target_if/spatial_reuse/src +SR_TGT_INC := -I$(WLAN_COMMON_INC)/target_if/spatial_reuse/inc/ + +ifeq ($(CONFIG_WLAN_FEATURE_SR), y) +WLAN_SR_OBJS := $(SR_UCFG_DIR)/spatial_reuse_ucfg_api.o \ + $(SR_UCFG_DIR)/spatial_reuse_api.o \ + $(SR_TGT_DIR)/target_if_spatial_reuse.o +endif + +$(call add-wlan-objs,spatial_reuse,$(WLAN_SR_OBJS)) + +####################################################### + +###### COEX ######## +COEX_OS_IF_SRC := os_if/coex/src +COEX_TGT_SRC := components/target_if/coex/src +COEX_CORE_SRC := components/coex/core/src +COEX_DISPATCHER_SRC := components/coex/dispatcher/src + +COEX_OS_IF_INC := -I$(WLAN_ROOT)/os_if/coex/inc +COEX_TGT_INC := -I$(WLAN_ROOT)/components/target_if/coex/inc +COEX_DISPATCHER_INC := -I$(WLAN_ROOT)/components/coex/dispatcher/inc +COEX_CORE_INC := -I$(WLAN_ROOT)/components/coex/core/inc +COEX_STRUCT_INC := -I$(WLAN_COMMON_INC)/coex/dispatcher/inc + +ifeq ($(CONFIG_FEATURE_COEX), y) +COEX_OBJS := $(COEX_TGT_SRC)/target_if_coex.o \ + $(COEX_CORE_SRC)/wlan_coex_main.o \ + $(COEX_OS_IF_SRC)/wlan_cfg80211_coex.o \ + $(COEX_DISPATCHER_SRC)/wlan_coex_tgt_api.o \ + $(COEX_DISPATCHER_SRC)/wlan_coex_utils_api.o \ + $(COEX_DISPATCHER_SRC)/wlan_coex_ucfg_api.o +endif + +$(call add-wlan-objs,coex,$(COEX_OBJS)) + +###### COAP ######## +ifeq ($(CONFIG_WLAN_FEATURE_COAP), y) +COAP_HDD_SRC := core/hdd/src +COAP_OS_IF_SRC := os_if/coap/src +COAP_TGT_SRC := components/target_if/coap/src +COAP_CORE_SRC := components/coap/core/src +COAP_DISPATCHER_SRC := components/coap/dispatcher/src +COAP_WMI_SRC := components/wmi/src + +COAP_OS_IF_INC := -I$(WLAN_ROOT)/os_if/coap/inc +COAP_TGT_INC := -I$(WLAN_ROOT)/components/target_if/coap/inc +COAP_DISPATCHER_INC := -I$(WLAN_ROOT)/components/coap/dispatcher/inc +COAP_CORE_INC := -I$(WLAN_ROOT)/components/coap/core/inc +COAP_WMI_INC := -I$(WLAN_ROOT)/components/wmi/inc + +COAP_OBJS := \ + $(COAP_HDD_SRC)/wlan_hdd_coap.o \ + $(COAP_OS_IF_SRC)/wlan_cfg80211_coap.o \ + $(COAP_TGT_SRC)/target_if_coap.o \ + $(COAP_CORE_SRC)/wlan_coap_main.o \ + $(COAP_DISPATCHER_SRC)/wlan_coap_tgt_api.o \ + $(COAP_DISPATCHER_SRC)/wlan_coap_ucfg_api.o \ + $(COAP_WMI_SRC)/wmi_unified_coap_tlv.o +$(call add-wlan-objs,coap,$(COAP_OBJS)) +endif + +############## HTC ########## +HTC_DIR := htc +HTC_INC := -I$(WLAN_COMMON_INC)/$(HTC_DIR) + +HTC_OBJS := $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc.o \ + $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_send.o \ + $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_recv.o \ + $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_services.o + +ifeq ($(CONFIG_FEATURE_HTC_CREDIT_HISTORY), y) +HTC_OBJS += $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_credit_history.o +endif + +ifeq ($(CONFIG_WLAN_HANG_EVENT), y) +HTC_OBJS += $(WLAN_COMMON_ROOT)/$(HTC_DIR)/htc_hang_event.o +endif + +$(call add-wlan-objs,htc,$(HTC_OBJS)) + +########### HIF ########### +HIF_DIR := hif +HIF_CE_DIR := $(HIF_DIR)/src/ce + +HIF_DISPATCHER_DIR := $(HIF_DIR)/src/dispatcher + +HIF_PCIE_DIR := $(HIF_DIR)/src/pcie +HIF_IPCIE_DIR := $(HIF_DIR)/src/ipcie +HIF_SNOC_DIR := $(HIF_DIR)/src/snoc +HIF_USB_DIR := $(HIF_DIR)/src/usb +HIF_SDIO_DIR := $(HIF_DIR)/src/sdio + +HIF_SDIO_NATIVE_DIR := $(HIF_SDIO_DIR)/native_sdio +HIF_SDIO_NATIVE_INC_DIR := $(HIF_SDIO_NATIVE_DIR)/include +HIF_SDIO_NATIVE_SRC_DIR := $(HIF_SDIO_NATIVE_DIR)/src + +HIF_INC := -I$(WLAN_COMMON_INC)/$(HIF_DIR)/inc \ + -I$(WLAN_COMMON_INC)/$(HIF_DIR)/src + +ifeq ($(CONFIG_HIF_PCI), y) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_PCIE_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_CE_DIR) +endif + +ifeq ($(CONFIG_HIF_IPCI), y) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_IPCIE_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_CE_DIR) +endif + +ifeq ($(CONFIG_HIF_SNOC), y) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_SNOC_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_CE_DIR) +endif + +ifeq ($(CONFIG_HIF_USB), y) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_USB_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_CE_DIR) +endif + +ifeq ($(CONFIG_HIF_SDIO), y) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_DISPATCHER_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_SDIO_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_SDIO_NATIVE_INC_DIR) +HIF_INC += -I$(WLAN_COMMON_INC)/$(HIF_CE_DIR) +endif + +HIF_COMMON_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/ath_procfs.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_main.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_runtime_pm.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_exec.o + +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +HIF_COMMON_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_main_legacy.o +endif + +ifeq ($(CONFIG_WLAN_NAPI), y) +HIF_COMMON_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_irq_affinity.o +endif + +HIF_CE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_diag.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_main.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_service.o \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_tasklet.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/mp_dev.o \ + $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/regtable.o + +ifeq ($(CONFIG_WLAN_FEATURE_BMI), y) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_bmi.o +endif + +ifeq ($(CONFIG_LITHIUM), y) +ifeq ($(CONFIG_CNSS_QCA6290), y) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/qca6290def.o +endif + +ifeq ($(CONFIG_CNSS_QCA6390), y) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/qca6390def.o +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/qca6490def.o +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/qca6750def.o +endif + +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_service_srng.o +else ifeq ($(CONFIG_BERYLLIUM), y) +ifeq (y,$(findstring y,$(CONFIG_CNSS_KIWI) $(CONFIG_CNSS_KIWI_V2) $CONFIG_CNSS_PEACH)) +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/kiwidef.o +endif + +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_service_srng.o +else +HIF_CE_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ce_service_legacy.o +endif + +HIF_USB_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/usbdrv.o \ + $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/hif_usb.o \ + $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/if_usb.o \ + $(WLAN_COMMON_ROOT)/$(HIF_USB_DIR)/regtable_usb.o + +HIF_SDIO_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_diag_reg_access.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_sdio_dev.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_sdio.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/regtable_sdio.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/transfer/transfer.o + +ifeq ($(CONFIG_WLAN_FEATURE_BMI), y) +HIF_SDIO_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/hif_bmi_reg_access.o +endif + +ifeq ($(CONFIG_SDIO_TRANSFER), adma) +HIF_SDIO_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/transfer/adma.o +else +HIF_SDIO_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/transfer/mailbox.o +endif + +HIF_SDIO_NATIVE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_SDIO_NATIVE_SRC_DIR)/hif.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_NATIVE_SRC_DIR)/hif_scatter.o \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_NATIVE_SRC_DIR)/dev_quirks.o + +ifeq ($(CONFIG_WLAN_NAPI), y) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_napi.o +endif + +ifeq ($(CONFIG_FEATURE_UNIT_TEST_SUSPEND), y) + HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DIR)/src/hif_unit_test_suspend.o +endif + +HIF_PCIE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_PCIE_DIR)/if_pci.o +HIF_IPCIE_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_IPCIE_DIR)/if_ipci.o +HIF_SNOC_OBJS := $(WLAN_COMMON_ROOT)/$(HIF_SNOC_DIR)/if_snoc.o +HIF_SDIO_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/if_sdio.o + +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus.o +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/dummy.o +HIF_OBJS += $(HIF_COMMON_OBJS) + +ifeq ($(CONFIG_HIF_PCI), y) +HIF_OBJS += $(HIF_PCIE_OBJS) +HIF_OBJS += $(HIF_CE_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_pci.o +endif + +ifeq ($(CONFIG_HIF_IPCI), y) +HIF_OBJS += $(HIF_IPCIE_OBJS) +HIF_OBJS += $(HIF_CE_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_ipci.o +endif + +ifeq ($(CONFIG_HIF_SNOC), y) +HIF_OBJS += $(HIF_SNOC_OBJS) +HIF_OBJS += $(HIF_CE_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_snoc.o +endif + +ifeq ($(CONFIG_HIF_SDIO), y) +HIF_OBJS += $(HIF_SDIO_OBJS) +HIF_OBJS += $(HIF_SDIO_NATIVE_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_sdio.o +endif + +ifeq ($(CONFIG_HIF_USB), y) +HIF_OBJS += $(HIF_USB_OBJS) +HIF_OBJS += $(WLAN_COMMON_ROOT)/$(HIF_DISPATCHER_DIR)/multibus_usb.o +endif + +$(call add-wlan-objs,hif,$(HIF_OBJS)) + +############ HAL ############ +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +HAL_DIR := hal +HAL_INC := -I$(WLAN_COMMON_INC)/$(HAL_DIR)/inc \ + -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0 + +#TODO fix hal_reo for RHINE +HAL_OBJS := $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_srng.o \ + $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_reo.o + +ifeq ($(CONFIG_RX_FISA), y) +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/hal_rx_flow.o +endif +endif #### CONFIG LITHIUM/BERYLLIUM/RHINE #### + +ifeq ($(CONFIG_LITHIUM), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/li + +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/li/hal_li_generic_api.o + +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/li/hal_li_reo.o + +ifeq ($(CONFIG_CNSS_QCA6290), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/qca6290 +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/qca6290/hal_6290.o +else ifeq ($(CONFIG_CNSS_QCA6390), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/qca6390 +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/qca6390/hal_6390.o +else ifeq ($(CONFIG_CNSS_QCA6490), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/qca6490 +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/qca6490/hal_6490.o +else ifeq ($(CONFIG_CNSS_QCA6750), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/qca6750 +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/qca6750/hal_6750.o +else +#error "Not 11ax" +endif + +endif #####CONFIG_LITHIUM#### + +ifeq ($(CONFIG_BERYLLIUM), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/be + +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/be/hal_be_generic_api.o + +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/be/hal_be_reo.o \ + +ifeq (y,$(findstring y,$(CONFIG_INCLUDE_HAL_PEACH))) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/peach +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/peach/hal_peach.o +ccflags-y += -DINCLUDE_HAL_PEACH +else ifeq (y,$(findstring y,$(CONFIG_INCLUDE_HAL_KIWI))) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/kiwi +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/kiwi/hal_kiwi.o +ccflags-y += -DINCLUDE_HAL_KIWI +endif + +endif #### CONFIG_BERYLLIUM #### + +ifeq ($(CONFIG_RHINE), y) +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/rh + +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/rh/hal_rh_generic_api.o + +ifeq ($(CONFIG_CNSS_WCN6450), y) +#TODO fix this for RHINE +HAL_INC += -I$(WLAN_COMMON_INC)/$(HAL_DIR)/wifi3.0/wcn6450 +HAL_OBJS += $(WLAN_COMMON_ROOT)/$(HAL_DIR)/wifi3.0/wcn6450/hal_wcn6450.o +else +#error "Not RHINE" +endif + +endif #####CONFIG_RHINE#### + +$(call add-wlan-objs,hal,$(HAL_OBJS)) + +############ WMA ############ +WMA_DIR := core/wma + +WMA_INC_DIR := $(WMA_DIR)/inc +WMA_SRC_DIR := $(WMA_DIR)/src + +WMA_INC := -I$(WLAN_ROOT)/$(WMA_INC_DIR) \ + -I$(WLAN_ROOT)/$(WMA_SRC_DIR) + +ifeq ($(CONFIG_QCACLD_FEATURE_NAN), y) +WMA_NDP_OBJS += $(WMA_SRC_DIR)/wma_nan_datapath.o +endif + +WMA_OBJS := $(WMA_SRC_DIR)/wma_main.o \ + $(WMA_SRC_DIR)/wma_scan_roam.o \ + $(WMA_SRC_DIR)/wma_dev_if.o \ + $(WMA_SRC_DIR)/wma_mgmt.o \ + $(WMA_SRC_DIR)/wma_power.o \ + $(WMA_SRC_DIR)/wma_data.o \ + $(WMA_SRC_DIR)/wma_utils.o \ + $(WMA_SRC_DIR)/wma_features.o \ + $(WMA_SRC_DIR)/wlan_qct_wma_legacy.o\ + $(WMA_NDP_OBJS) + +ifeq ($(CONFIG_WLAN_FEATURE_11BE), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_eht.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +WMA_OBJS+= $(WMA_SRC_DIR)/wma_ocb.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_FIPS), y) +WMA_OBJS+= $(WMA_SRC_DIR)/wma_fips_api.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_11AX), y) +WMA_OBJS+= $(WMA_SRC_DIR)/wma_he.o +endif +ifeq ($(CONFIG_WLAN_FEATURE_TWT), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_twt.o +endif +ifeq ($(CONFIG_QCACLD_FEATURE_FW_STATE), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_fw_state.o +endif +ifeq ($(CONFIG_WLAN_MWS_INFO_DEBUGFS), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_coex.o +endif +ifeq ($(CONFIG_WIFI_POS_CONVERGED), y) +ifeq ($(CONFIG_WIFI_POS_PASN), y) +WMA_OBJS += $(WMA_SRC_DIR)/wma_pasn_peer_api.o +endif +endif + +$(call add-wlan-objs,wma,$(WMA_OBJS)) + +#######DIRECT_BUFFER_RX######### +ifeq ($(CONFIG_DIRECT_BUF_RX_ENABLE), y) +DBR_DIR = $(WLAN_COMMON_ROOT)/target_if/direct_buf_rx +UMAC_DBR_INC := -I$(WLAN_COMMON_INC)/target_if/direct_buf_tx/inc +UMAC_DBR_OBJS := $(DBR_DIR)/src/target_if_direct_buf_rx_api.o \ + $(DBR_DIR)/src/target_if_direct_buf_rx_main.o \ + $(WLAN_COMMON_ROOT)/wmi/src/wmi_unified_dbr_api.o \ + $(WLAN_COMMON_ROOT)/wmi/src/wmi_unified_dbr_tlv.o +endif + +$(call add-wlan-objs,umac_dbr,$(UMAC_DBR_OBJS)) + +############## PLD ########## +PLD_DIR := core/pld +PLD_INC_DIR := $(PLD_DIR)/inc +PLD_SRC_DIR := $(PLD_DIR)/src + +PLD_INC := -I$(WLAN_ROOT)/$(PLD_INC_DIR) \ + -I$(WLAN_ROOT)/$(PLD_SRC_DIR) + +PLD_OBJS := $(PLD_SRC_DIR)/pld_common.o + +ifeq ($(CONFIG_IPCIE_FW_SIM), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_pcie_fw_sim.o +endif +ifeq ($(CONFIG_PCIE_FW_SIM), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_pcie_fw_sim.o +else ifeq ($(CONFIG_HIF_PCI), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_pcie.o +endif +ifeq ($(CONFIG_SNOC_FW_SIM),y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_snoc_fw_sim.o +else ifeq (y,$(findstring y, $(CONFIG_ICNSS) $(CONFIG_PLD_SNOC_ICNSS_FLAG))) +PLD_OBJS += $(PLD_SRC_DIR)/pld_snoc.o +else ifeq (y,$(findstring y, $(CONFIG_PLD_IPCI_ICNSS_FLAG))) +PLD_OBJS += $(PLD_SRC_DIR)/pld_ipci.o +endif + +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_sdio.o +endif +ifeq ($(CONFIG_HIF_USB), y) +PLD_OBJS += $(PLD_SRC_DIR)/pld_usb.o +endif + +$(call add-wlan-objs,pld,$(PLD_OBJS)) + + +TARGET_INC := -I$(WLAN_FW_API)/fw + +ifeq ($(CONFIG_CNSS_QCA6290), y) +ifeq ($(CONFIG_QCA6290_11AX), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/qca6290/11ax/v2 +else +TARGET_INC += -I$(WLAN_FW_API)/hw/qca6290/v2 +endif +endif + +ifeq ($(CONFIG_CNSS_QCA6390), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/qca6390/v1 +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/qca6490/v1 +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/qca6750/v1 +endif + +ifeq ($(CONFIG_CNSS_WCN6450), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/wcn6450/v1 +endif + +ifeq ($(CONFIG_CNSS_PEACH), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/peach/v1/ +else +ifeq ($(CONFIG_CNSS_KIWI_V2), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/kiwi/v2/ +else +ifeq ($(CONFIG_CNSS_KIWI), y) +TARGET_INC += -I$(WLAN_FW_API)/hw/kiwi/v1/ +endif +endif +endif + +LINUX_INC := -Iinclude + +INCS := $(HDD_INC) \ + $(SYNC_INC) \ + $(DSC_INC) \ + $(EPPING_INC) \ + $(LINUX_INC) \ + $(MAC_INC) \ + $(SAP_INC) \ + $(SME_INC) \ + $(SYS_INC) \ + $(CLD_WMI_INC) \ + $(QAL_INC) \ + $(QDF_INC) \ + $(WBUFF_INC) \ + $(CDS_INC) \ + $(CFG_INC) \ + $(DFS_INC) \ + $(TARGET_IF_INC) \ + $(CLD_TARGET_IF_INC) \ + $(OS_IF_INC) \ + $(GLOBAL_LMAC_IF_INC) \ + $(FTM_INC) + +INCS += $(WMA_INC) \ + $(UAPI_INC) \ + $(COMMON_INC) \ + $(WMI_INC) \ + $(FWLOG_INC) \ + $(TXRX_INC) \ + $(OL_INC) \ + $(CDP_INC) \ + $(PKTLOG_INC) \ + $(HTT_INC) \ + $(INIT_DEINIT_INC) \ + $(SCHEDULER_INC) \ + $(REGULATORY_INC) \ + $(HTC_INC) \ + $(WCFG_INC) + +INCS += $(HIF_INC) \ + $(BMI_INC) \ + $(CMN_SYS_INC) + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +INCS += $(HAL_INC) \ + $(DP_INC) +endif + +################ WIFI POS ################ +INCS += $(WIFI_POS_CLD_INC) +INCS += $(WIFI_POS_API_INC) +INCS += $(WIFI_POS_TGT_INC) +INCS += $(WIFI_POS_OS_IF_INC) +################ CP STATS ################ +INCS += $(CP_STATS_OS_IF_INC) +INCS += $(CP_STATS_TGT_INC) +INCS += $(CP_STATS_DISPATCHER_INC) +INCS += $(CP_MC_STATS_COMPONENT_INC) +INCS += $(CP_STATS_CFG80211_OS_IF_INC) +################ TWT CONVERGED ################ +INCS += $(TWT_CONV_INCS) +################ Dynamic ACS #################### +INCS += $(DCS_TGT_IF_INC) +INCS += $(DCS_DISP_INC) +################ AFC ################# +INCS += $(AFC_CMN_OSIF_INC) +INCS += $(AFC_CMN_DISP_INC) +INCS += $(AFC_CMN_CORE_INC) +################ INTEROP ISSUES AP ################ +INCS += $(INTEROP_ISSUES_AP_OS_IF_INC) +INCS += $(INTEROP_ISSUES_AP_TGT_INC) +INCS += $(INTEROP_ISSUES_AP_DISPATCHER_INC) +INCS += $(INTEROP_ISSUES_AP_CORE_INC) +################ NAN POS ################ +INCS += $(NAN_CORE_INC) +INCS += $(NAN_UCFG_INC) +INCS += $(NAN_TGT_INC) +INCS += $(NAN_OS_IF_INC) +###########DP_COMPONENT #################### +INCS += $(DP_COMP_INC) +###########QMI_COMPONENT #################### +INCS += $(QMI_COMP_INC) +################ SON ################ +INCS += $(SON_CORE_INC) +INCS += $(SON_UCFG_INC) +INCS += $(SON_TGT_INC) +INCS += $(SON_OS_IF_INC) +################ SPATIAL_REUSE ################ +INCS += $(SR_UCFG_INC) +INCS += $(SR_TGT_INC) +########################################## + +INCS += $(UMAC_OBJMGR_INC) +INCS += $(UMAC_MGMT_TXRX_INC) +INCS += $(PMO_INC) +INCS += $(P2P_INC) +INCS += $(POLICY_MGR_INC) +INCS += $(TARGET_INC) +INCS += $(TDLS_INC) +INCS += $(UMAC_SER_INC) +INCS += $(NLINK_INC) \ + $(PTT_INC) \ + $(WLAN_LOGGING_INC) + +INCS += $(PLD_INC) +INCS += $(OCB_INC) + +INCS += $(IPA_INC) +INCS += $(UMAC_SM_INC) +INCS += $(UMAC_MLME_INC) +INCS += $(MLME_INC) +INCS += $(FWOL_INC) +INCS += $(DLM_INC) +INCS += $(CONN_LOGGING_INC) + +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +INCS += $(PKTLOG_INC) +endif + +INCS += $(HOST_DIAG_LOG_INC) + +INCS += $(DISA_INC) +INCS += $(ACTION_OUI_INC) +INCS += $(PKT_CAPTURE_INC) +INCS += $(FTM_TIME_SYNC_INC) +INCS += $(WLAN_PRE_CAC_INC) + +INCS += $(UMAC_DISP_INC) +INCS += $(UMAC_SCAN_INC) +INCS += $(UMAC_TARGET_SCAN_INC) +INCS += $(UMAC_GREEN_AP_INC) +INCS += $(UMAC_TARGET_GREEN_AP_INC) +INCS += $(UMAC_COMMON_INC) +INCS += $(UMAC_SPECTRAL_INC) +INCS += $(WLAN_CFR_INC) +INCS += $(UMAC_TARGET_SPECTRAL_INC) +INCS += $(UMAC_GPIO_INC) +INCS += $(UMAC_TARGET_GPIO_INC) +INCS += $(UMAC_DBR_INC) +INCS += $(UMAC_CRYPTO_INC) +INCS += $(UMAC_INTERFACE_MGR_INC) +INCS += $(UMAC_MLO_MGR_INC) +INCS += $(UMAC_MLO_MGR_CLD_INC) +INCS += $(COEX_OS_IF_INC) +INCS += $(COEX_TGT_INC) +INCS += $(COEX_DISPATCHER_INC) +INCS += $(COEX_CORE_INC) +INCS += $(COEX_STRUCT_INC) +################ COAP ################ +INCS += $(COAP_OS_IF_INC) +INCS += $(COAP_TGT_INC) +INCS += $(COAP_DISPATCHER_INC) +INCS += $(COAP_CORE_INC) +INCS += $(COAP_WMI_INC) + +ccflags-y += $(INCS) + +ccflags-y += -include $(WLAN_ROOT)/configs/default_config.h + +# CFG80211_MLO_KEY_OPERATION_SUPPORT +# Used to indicate the Linux Kernel contains support for ML key operation +# support. +# +# This feature was backported to Android Common Kernel 5.15 via: +# https://android-review.googlesource.com/c/kernel/common/+/2173923 +found = $(shell if grep -qF "nl80211_validate_key_link_id" $(srctree)/net/wireless/nl80211.c; then echo "yes" ;else echo "no" ;fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_MLO_KEY_OPERATION_SUPPORT +endif + +found = $(shell if grep -qF "struct link_station_parameters" $(srctree)/include/net/cfg80211.h; then echo "yes"; else echo "no"; fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_LINK_STA_PARAMS_PRESENT +endif + +found = $(shell if grep -qF "NL80211_EXT_FEATURE_PUNCT" $(srctree)/include/uapi/linux/nl80211.h; then echo "yes" ;else echo "no" ;fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DNL80211_EXT_FEATURE_PUNCT_SUPPORT +endif + +found = $(shell if grep -qF "unsigned int link_id, u16 punct_bitmap" $(srctree)/include/net/cfg80211.h; then echo "yes" ;else echo "no" ;fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_RU_PUNCT_NOTIFY +endif + +found = $(shell if grep -qF "NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA" $(srctree)/include/uapi/linux/nl80211.h; then echo "yes"; else echo "no"; fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA +endif + +# CFG80211_EXTERNAL_AUTH_MLO_SUPPORT +# Used to indicate Linux kernel contains support for ML external auth support. +# +# This feature was backported to Android Common Kernel 5.15 via: +# https://android-review.googlesource.com/c/kernel/common/+/2450264 +found = $(shell if grep -qF "MLD address of the peer. Used by the authentication request event" $(srctree)/include/net/cfg80211.h; then echo "yes" ;else echo "no" ;fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_EXTERNAL_AUTH_MLO_SUPPORT +endif + +found = $(shell if grep -qF "NL80211_EXT_FEATURE_SECURE_NAN" $(srctree)/include/uapi/linux/nl80211.h; then echo "yes"; else echo "no"; fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_EXT_FEATURE_SECURE_NAN +endif + +found = $(shell if grep -qF "bool mlo_params_valid;" $(srctree)/include/net/cfg80211.h; then echo "yes" ;else echo "no" ;fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DCFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT +endif + +ifeq (qca_cld3, $(WLAN_WEAR_CHIPSET)) + ccflags-y += -DWLAN_WEAR_CHIPSET +endif + +ccflags-$(CONFIG_ONE_MSI_VECTOR) += -DWLAN_ONE_MSI_VECTOR + +ccflags-$(CONFIG_DSC_DEBUG) += -DWLAN_DSC_DEBUG +ccflags-$(CONFIG_DSC_TEST) += -DWLAN_DSC_TEST + +ifeq ($(CONFIG_LITHIUM), y) +ccflags-y += -DCONFIG_LITHIUM +endif + +ifeq ($(CONFIG_BERYLLIUM), y) +ccflags-y += -DCONFIG_BERYLLIUM +ccflags-y += -DDP_OFFLOAD_FRAME_WITH_SW_EXCEPTION +endif + +ifeq ($(CONFIG_RHINE), y) +ccflags-y += -DCONFIG_RHINE +ccflags-y += -DDP_OFFLOAD_FRAME_WITH_SW_EXCEPTION +endif + +ccflags-$(CONFIG_TALLOC_DEBUG) += -DWLAN_TALLOC_DEBUG +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_DELAYED_WORK_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_HASHTABLE_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_PERIODIC_WORK_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_PTR_HASH_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_SLIST_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_TALLOC_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_TRACKER_TEST +ccflags-$(CONFIG_QDF_TEST) += -DWLAN_TYPES_TEST +ccflags-$(CONFIG_WLAN_HANG_EVENT) += -DWLAN_HANG_EVENT + +#Flag to enable pre_cac +ccflags-$(CONFIG_FEATURE_WLAN_PRE_CAC) += -DPRE_CAC_SUPPORT + +ccflags-$(CONFIG_WIFI_POS_PASN) += -DWLAN_FEATURE_RTT_11AZ_SUPPORT + +ifeq ($(CONFIG_DIRECT_BUF_RX_ENABLE), y) +ifeq ($(CONFIG_DBR_HOLD_LARGE_MEM), y) +ccflags-y += -DDBR_HOLD_LARGE_MEM +endif +endif + +ccflags-$(CONFIG_QCA_DMA_PADDR_CHECK) += -DQCA_DMA_PADDR_CHECK +ccflags-$(CONFIG_PADDR_CHECK_ON_3RD_PARTY_PLATFORM) += -DQCA_PADDR_CHECK_ON_3RD_PARTY_PLATFORM +ccflags-$(CONFIG_DP_TRAFFIC_END_INDICATION) += -DDP_TRAFFIC_END_INDICATION +ccflags-$(CONFIG_THERMAL_STATS_SUPPORT) += -DTHERMAL_STATS_SUPPORT +ccflags-$(CONFIG_PTT_SOCK_SVC_ENABLE) += -DPTT_SOCK_SVC_ENABLE +ccflags-$(CONFIG_FEATURE_WLAN_WAPI) += -DFEATURE_WLAN_WAPI +ccflags-$(CONFIG_FEATURE_WLAN_WAPI) += -DATH_SUPPORT_WAPI +ccflags-$(CONFIG_SOFTAP_CHANNEL_RANGE) += -DSOFTAP_CHANNEL_RANGE +ccflags-$(CONFIG_FEATURE_WLAN_SCAN_PNO) += -DFEATURE_WLAN_SCAN_PNO +ccflags-$(CONFIG_WLAN_FEATURE_PACKET_FILTERING) += -DWLAN_FEATURE_PACKET_FILTERING +ccflags-$(CONFIG_DHCP_SERVER_OFFLOAD) += -DDHCP_SERVER_OFFLOAD +ccflags-$(CONFIG_WLAN_NS_OFFLOAD) += -DWLAN_NS_OFFLOAD +ccflags-$(CONFIG_QCA_TARGET_IF_MLME) += -DQCA_TARGET_IF_MLME +ccflags-$(CONFIG_WLAN_DYNAMIC_ARP_NS_OFFLOAD) += -DFEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD +ccflags-$(CONFIG_WLAN_FEATURE_ICMP_OFFLOAD) += -DWLAN_FEATURE_ICMP_OFFLOAD +ccflags-$(CONFIG_FEATURE_WLAN_RA_FILTERING) += -DFEATURE_WLAN_RA_FILTERING +ccflags-$(CONFIG_FEATURE_WLAN_LPHB) += -DFEATURE_WLAN_LPHB +ccflags-$(CONFIG_QCA_SUPPORT_TX_THROTTLE) += -DQCA_SUPPORT_TX_THROTTLE +ccflags-$(CONFIG_WMI_INTERFACE_EVENT_LOGGING) += -DWMI_INTERFACE_EVENT_LOGGING +ccflags-$(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS) += -DWLAN_FEATURE_LINK_LAYER_STATS +ccflags-$(CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION) += -DFEATURE_CLUB_LL_STATS_AND_GET_STATION +ccflags-$(CONFIG_WLAN_FEATURE_MIB_STATS) += -DWLAN_FEATURE_MIB_STATS +ccflags-$(CONFIG_FEATURE_WLAN_EXTSCAN) += -DFEATURE_WLAN_EXTSCAN +ccflags-$(CONFIG_160MHZ_SUPPORT) += -DCONFIG_160MHZ_SUPPORT +ccflags-$(CONFIG_REG_CLIENT) += -DCONFIG_REG_CLIENT +ccflags-$(CONFIG_WLAN_PMO_ENABLE) += -DWLAN_PMO_ENABLE +ccflags-$(CONFIG_CONVERGED_P2P_ENABLE) += -DCONVERGED_P2P_ENABLE +ccflags-$(CONFIG_WLAN_POLICY_MGR_ENABLE) += -DWLAN_POLICY_MGR_ENABLE +ccflags-$(CONFIG_FEATURE_DENYLIST_MGR) += -DFEATURE_DENYLIST_MGR +ccflags-$(CONFIG_WAPI_BIG_ENDIAN) += -DFEATURE_WAPI_BIG_ENDIAN +ccflags-$(CONFIG_SUPPORT_11AX) += -DSUPPORT_11AX +ccflags-$(CONFIG_HDD_INIT_WITH_RTNL_LOCK) += -DCONFIG_HDD_INIT_WITH_RTNL_LOCK +ccflags-$(CONFIG_WLAN_CONV_SPECTRAL_ENABLE) += -DWLAN_CONV_SPECTRAL_ENABLE +ccflags-$(CONFIG_WLAN_CFR_ENABLE) += -DWLAN_CFR_ENABLE +ccflags-$(CONFIG_WLAN_ENH_CFR_ENABLE) += -DWLAN_ENH_CFR_ENABLE +ccflags-$(CONFIG_WLAN_ENH_CFR_ENABLE) += -DWLAN_CFR_PM +ccflags-$(CONFIG_WLAN_CFR_ADRASTEA) += -DWLAN_CFR_ADRASTEA +ccflags-$(CONFIG_WLAN_CFR_DBR) += -DWLAN_CFR_DBR +ccflags-$(CONFIG_WLAN_CFR_ENABLE) += -DCFR_USE_FIXED_FOLDER +ccflags-$(CONFIG_WLAN_FEATURE_MEDIUM_ASSESS) += -DWLAN_FEATURE_MEDIUM_ASSESS +ccflags-$(CONFIG_FEATURE_RADAR_HISTORY) += -DFEATURE_RADAR_HISTORY +ccflags-$(CONFIG_DIRECT_BUF_RX_ENABLE) += -DDIRECT_BUF_RX_ENABLE +ccflags-$(CONFIG_WMI_DBR_SUPPORT) += -DWMI_DBR_SUPPORT +ifneq ($(CONFIG_CNSS_QCA6750), y) +ccflags-$(CONFIG_DIRECT_BUF_RX_ENABLE) += -DDBR_MULTI_SRNG_ENABLE +endif +ifneq ($(CONFIG_CNSS_WCN6450), y) +ccflags-$(CONFIG_DIRECT_BUF_RX_ENABLE) += -DDBR_MULTI_SRNG_ENABLE +endif +ccflags-$(CONFIG_WMI_CMD_STRINGS) += -DWMI_CMD_STRINGS +ccflags-$(CONFIG_WLAN_FEATURE_TWT) += -DWLAN_SUPPORT_TWT +ifeq ($(CONFIG_WLAN_FEATURE_11BE_MLO), y) +ifeq ($(CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH), y) +ccflags-y += -DDP_USE_REDUCED_PEER_ID_FIELD_WIDTH +endif +endif +ccflags-$(CONFIG_DP_MULTIPASS_SUPPORT) += -DQCA_MULTIPASS_SUPPORT +ccflags-$(CONFIG_DP_MULTIPASS_SUPPORT) += -DWLAN_REPEATER_NOT_SUPPORTED +ccflags-$(CONFIG_DP_MULTIPASS_SUPPORT) += -DQCA_SUPPORT_PEER_ISOLATION +ccflags-$(CONFIG_WLAN_DP_PROFILE_SUPPORT) += -DWLAN_DP_PROFILE_SUPPORT + +ifdef CONFIG_WLAN_TWT_SAP_STA_COUNT +WLAN_TWT_SAP_STA_COUNT ?= 32 +ccflags-y += -DWLAN_TWT_SAP_STA_COUNT=$(WLAN_TWT_SAP_STA_COUNT) +endif + +ccflags-$(CONFIG_ENABLE_LOW_POWER_MODE) += -DCONFIG_ENABLE_LOW_POWER_MODE +ccflags-$(CONFIG_WLAN_TWT_SAP_PDEV_COUNT) += -DWLAN_TWT_AP_PDEV_COUNT_NUM_PHY +ccflags-$(CONFIG_WLAN_DISABLE_EXPORT_SYMBOL) += -DWLAN_DISABLE_EXPORT_SYMBOL +ccflags-$(CONFIG_WIFI_POS_CONVERGED) += -DWIFI_POS_CONVERGED +ccflags-$(CONFIG_WLAN_TWT_CONVERGED) += -DWLAN_TWT_CONV_SUPPORTED +ccflags-$(CONFIG_WIFI_POS_LEGACY) += -DFEATURE_OEM_DATA_SUPPORT +ccflags-$(CONFIG_FEATURE_HTC_CREDIT_HISTORY) += -DFEATURE_HTC_CREDIT_HISTORY +ccflags-$(CONFIG_WLAN_FEATURE_P2P_DEBUG) += -DWLAN_FEATURE_P2P_DEBUG +ccflags-$(CONFIG_WLAN_WEXT_SUPPORT_ENABLE) += -DWLAN_WEXT_SUPPORT_ENABLE +ccflags-$(CONFIG_WLAN_LOGGING_SOCK_SVC) += -DWLAN_LOGGING_SOCK_SVC_ENABLE +ccflags-$(CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY) += -DWLAN_LOGGING_BUFFERS_DYNAMICALLY +ccflags-$(CONFIG_WLAN_FEATURE_FILS) += -DWLAN_FEATURE_FILS_SK +ccflags-$(CONFIG_CP_STATS) += -DWLAN_SUPPORT_INFRA_CTRL_PATH_STATS +ccflags-$(CONFIG_CP_STATS) += -DQCA_SUPPORT_CP_STATS +ccflags-$(CONFIG_CP_STATS) += -DQCA_SUPPORT_MC_CP_STATS +ccflags-$(CONFIG_CP_STATS) += -DWLAN_SUPPORT_LEGACY_CP_STATS_HANDLERS +ccflags-$(CONFIG_DCS) += -DDCS_INTERFERENCE_DETECTION +ccflags-$(CONFIG_FEATURE_INTEROP_ISSUES_AP) += -DWLAN_FEATURE_INTEROP_ISSUES_AP +ccflags-$(CONFIG_FEATURE_MEMDUMP_ENABLE) += -DWLAN_FEATURE_MEMDUMP_ENABLE +ccflags-$(CONFIG_FEATURE_FW_LOG_PARSING) += -DFEATURE_FW_LOG_PARSING +ccflags-$(CONFIG_FEATURE_OEM_DATA) += -DFEATURE_OEM_DATA +ccflags-$(CONFIG_FEATURE_MOTION_DETECTION) += -DWLAN_FEATURE_MOTION_DETECTION +ccflags-$(CONFIG_WLAN_FW_OFFLOAD) += -DWLAN_FW_OFFLOAD +ccflags-$(CONFIG_WLAN_FEATURE_ELNA) += -DWLAN_FEATURE_ELNA +ccflags-$(CONFIG_FEATURE_COEX) += -DFEATURE_COEX +ccflags-$(CONFIG_HOST_WAKEUP_OVER_QMI) += -DHOST_WAKEUP_OVER_QMI +ccflags-$(CONFIG_DISABLE_STATUS_RING_TIMER_WAR) += -DWLAN_DISABLE_STATUS_RING_TIMER_WAR +ccflags-$(CONFIG_CE_DISABLE_SRNG_TIMER_IRQ) += -DWLAN_WAR_CE_DISABLE_SRNG_TIMER_IRQ + +ccflags-$(CONFIG_PLD_IPCI_ICNSS_FLAG) += -DCONFIG_PLD_IPCI_ICNSS +ccflags-$(CONFIG_PLD_SDIO_CNSS_FLAG) += -DCONFIG_PLD_SDIO_CNSS +ccflags-$(CONFIG_WLAN_RESIDENT_DRIVER) += -DFEATURE_WLAN_RESIDENT_DRIVER +ccflags-$(CONFIG_FEATURE_GPIO_CFG) += -DWLAN_FEATURE_GPIO_CFG +ccflags-$(CONFIG_FEATURE_BUS_BANDWIDTH_MGR) += -DFEATURE_BUS_BANDWIDTH_MGR +ccflags-$(CONFIG_DP_BE_WAR) += -DDP_BE_WAR + +ifeq ($(CONFIG_IPCIE_FW_SIM), y) +ccflags-y += -DCONFIG_PLD_IPCIE_FW_SIM +endif +ifeq ($(CONFIG_PLD_PCIE_CNSS_FLAG), y) +ifeq ($(CONFIG_PCIE_FW_SIM), y) +ccflags-y += -DCONFIG_PLD_PCIE_FW_SIM +else +ccflags-y += -DCONFIG_PLD_PCIE_CNSS +endif +endif + +ccflags-$(CONFIG_PLD_PCIE_INIT_FLAG) += -DCONFIG_PLD_PCIE_INIT +ccflags-$(CONFIG_WLAN_FEATURE_DP_RX_THREADS) += -DFEATURE_WLAN_DP_RX_THREADS +ccflags-$(CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE) += -DWLAN_FEATURE_LOCAL_PKT_CAPTURE +ccflags-$(CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT) += -DWLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT +ccflags-$(CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE) += -DHIF_LATENCY_PROFILE_ENABLE +ccflags-$(CONFIG_FEATURE_HAL_DELAYED_REG_WRITE) += -DFEATURE_HAL_DELAYED_REG_WRITE +ccflags-$(CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE) += -DFEATURE_HAL_RECORD_SUSPEND_WRITE +ccflags-$(CONFIG_QCA_OL_DP_SRNG_LOCK_LESS_ACCESS) += -DQCA_OL_DP_SRNG_LOCK_LESS_ACCESS +ccflags-$(CONFIG_SHADOW_WRITE_DELAY) += -DSHADOW_WRITE_DELAY + +ccflags-$(CONFIG_PLD_USB_CNSS) += -DCONFIG_PLD_USB_CNSS +ccflags-$(CONFIG_PLD_SDIO_CNSS2) += -DCONFIG_PLD_SDIO_CNSS2 +ccflags-$(CONFIG_WLAN_RECORD_RX_PADDR) += -DHIF_RECORD_RX_PADDR +ccflags-$(CONFIG_FEATURE_WLAN_TIME_SYNC_FTM) += -DFEATURE_WLAN_TIME_SYNC_FTM + +ccflags-$(CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB) += -DWLAN_FEATURE_LRO_CTX_IN_CB + +#For both legacy and lithium chip's monitor mode config +ifeq ($(CONFIG_FEATURE_MONITOR_MODE_SUPPORT), y) +ccflags-y += -DFEATURE_MONITOR_MODE_SUPPORT +ccflags-$(CONFIG_DP_CON_MON_MSI_ENABLED) += -DDP_CON_MON_MSI_ENABLED +ccflags-$(CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO) += -DWLAN_RX_MON_PARSE_CMN_USER_INFO +ccflags-$(CONFIG_DP_CON_MON_MSI_SKIP_SET) += -DDP_CON_MON_MSI_SKIP_SET +ccflags-$(CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT) += -DQCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT +else +ccflags-y += -DDISABLE_MON_CONFIG +endif + +ifeq ($(CONFIG_SMP), y) +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) +ccflags-y += -DWLAN_DP_LEGACY_OL_RX_THREAD +endif +endif + +#Enable NL80211 test mode +ccflags-$(CONFIG_NL80211_TESTMODE) += -DWLAN_NL80211_TESTMODE + +# Flag to enable bus auto suspend +ifeq ($(CONFIG_BUS_AUTO_SUSPEND), y) +ccflags-y += -DFEATURE_RUNTIME_PM +endif + +ifeq (y,$(findstring y, $(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE))) +ifeq ($(CONFIG_SNOC_FW_SIM), y) +ccflags-y += -DCONFIG_PLD_SNOC_FW_SIM +else +ccflags-y += -DCONFIG_PLD_SNOC_ICNSS +endif +endif + +ccflags-$(CONFIG_PLD_SNOC_ICNSS_FLAG) += -DCONFIG_PLD_SNOC_ICNSS +ccflags-$(CONFIG_ICNSS2_HELIUM) += -DCONFIG_PLD_SNOC_ICNSS2 + +ccflags-$(CONFIG_WIFI_3_0_ADRASTEA) += -DQCA_WIFI_3_0_ADRASTEA +ccflags-$(CONFIG_WIFI_3_0_ADRASTEA) += -DQCA_WIFI_3_0 +ccflags-$(CONFIG_ADRASTEA_SHADOW_REGISTERS) += -DADRASTEA_SHADOW_REGISTERS +ccflags-$(CONFIG_ADRASTEA_RRI_ON_DDR) += -DADRASTEA_RRI_ON_DDR + +ifeq ($(CONFIG_QMI_SUPPORT), n) +ccflags-y += -DCONFIG_BYPASS_QMI +endif + +ccflags-$(CONFIG_WLAN_FASTPATH) += -DWLAN_FEATURE_FASTPATH + +ccflags-$(CONFIG_FEATURE_PKTLOG) += -DFEATURE_PKTLOG + +ccflags-$(CONFIG_CONNECTIVITY_PKTLOG) += -DCONNECTIVITY_PKTLOG + +ifeq ($(CONFIG_WLAN_NAPI), y) +ccflags-y += -DFEATURE_NAPI +ccflags-y += -DHIF_IRQ_AFFINITY +ifeq ($(CONFIG_WLAN_NAPI_DEBUG), y) +ccflags-y += -DFEATURE_NAPI_DEBUG +endif +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM))) +ccflags-y += -DMSM_PLATFORM +endif + +ccflags-$(CONFIG_CNSS_OUT_OF_TREE) += -DCONFIG_CNSS_OUT_OF_TREE +ccflags-$(CONFIG_CNSS_OUT_OF_TREE) += -I$(WLAN_PLATFORM_INC) +ccflags-$(CONFIG_IPA_OUT_OF_TREE) += -I$(DATA_IPA_INC) +ccflags-$(CONFIG_IPA_OUT_OF_TREE) += -I$(DATA_IPA_UAPI_INC) + +ccflags-$(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH) += -DWLAN_FEATURE_DP_BUS_BANDWIDTH +ccflags-$(CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS) += -DWLAN_FEATURE_PERIODIC_STA_STATS + +ccflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_V2) += -DQCA_LL_TX_FLOW_CONTROL_V2 +ccflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_V2) += -DQCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +ccflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY) += -DQCA_LL_LEGACY_TX_FLOW_CONTROL +ccflags-$(CONFIG_WLAN_PDEV_TX_FLOW_CONTROL) += -DQCA_LL_PDEV_TX_FLOW_CONTROL + +ifeq ($(CONFIG_WLAN_DEBUG_VERSION), y) +ccflags-y += -DWLAN_DEBUG +ifeq ($(CONFIG_TRACE_RECORD_FEATURE), y) +ccflags-y += -DTRACE_RECORD \ + -DLIM_TRACE_RECORD \ + -DSME_TRACE_RECORD \ + -DHDD_TRACE_RECORD +endif +endif +ccflags-$(CONFIG_UNIT_TEST) += -DWLAN_UNIT_TEST +ccflags-$(CONFIG_WLAN_DEBUG_CRASH_INJECT) += -DCONFIG_WLAN_DEBUG_CRASH_INJECT +ccflags-$(CONFIG_WLAN_SYSFS_FW_MODE_CFG) += -DCONFIG_WLAN_SYSFS_FW_MODE_CFG +ccflags-$(CONFIG_WLAN_REASSOC) += -DCONFIG_WLAN_REASSOC +ccflags-$(CONFIG_WLAN_SCAN_DISABLE) += -DCONFIG_WLAN_SCAN_DISABLE +ccflags-$(CONFIG_WLAN_WOW_ITO) += -DCONFIG_WLAN_WOW_ITO +ccflags-$(CONFIG_WLAN_WOWL_ADD_PTRN) += -DCONFIG_WLAN_WOWL_ADD_PTRN +ccflags-$(CONFIG_WLAN_WOWL_DEL_PTRN) += -DCONFIG_WLAN_WOWL_DEL_PTRN +ccflags-$(CONFIG_WLAN_SYSFS_TX_STBC) += -DCONFIG_WLAN_SYSFS_TX_STBC +ccflags-$(CONFIG_WLAN_GET_STATS) += -DCONFIG_WLAN_GET_STATS +ccflags-$(CONFIG_WLAN_SYSFS_WLAN_DBG) += -DCONFIG_WLAN_SYSFS_WLAN_DBG +ccflags-$(CONFIG_WLAN_TXRX_FW_ST_RST) += -DCONFIG_WLAN_TXRX_FW_ST_RST +ccflags-$(CONFIG_WLAN_GTX_BW_MASK) += -DCONFIG_WLAN_GTX_BW_MASK +ccflags-$(CONFIG_WLAN_SYSFS_SCAN_CFG) += -DCONFIG_WLAN_SYSFS_SCAN_CFG +ccflags-$(CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL) += -DCONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL +ccflags-$(CONFIG_WLAN_SYSFS_RADAR) += -DCONFIG_WLAN_SYSFS_RADAR +ccflags-$(CONFIG_WLAN_SYSFS_RTS_CTS) += -DWLAN_SYSFS_RTS_CTS +ccflags-$(CONFIG_WLAN_TXRX_FW_STATS) += -DCONFIG_WLAN_TXRX_FW_STATS +ccflags-$(CONFIG_WLAN_TXRX_STATS) += -DCONFIG_WLAN_TXRX_STATS +ccflags-$(CONFIG_WLAN_SYSFS_DP_TRACE) += -DWLAN_SYSFS_DP_TRACE +ccflags-$(CONFIG_WLAN_SYSFS_STATS) += -DWLAN_SYSFS_STATS +ccflags-$(CONFIG_WLAN_SYSFS_TEMPERATURE) += -DCONFIG_WLAN_SYSFS_TEMPERATURE +ccflags-$(CONFIG_WLAN_THERMAL_CFG) += -DCONFIG_WLAN_THERMAL_CFG +ccflags-$(CONFIG_FEATURE_UNIT_TEST_SUSPEND) += -DWLAN_SUSPEND_RESUME_TEST +ccflags-$(CONFIG_FEATURE_WLM_STATS) += -DFEATURE_WLM_STATS +ccflags-$(CONFIG_WLAN_SYSFS_MEM_STATS) += -DCONFIG_WLAN_SYSFS_MEM_STATS +ccflags-$(CONFIG_WLAN_SYSFS_DCM) += -DWLAN_SYSFS_DCM +ccflags-$(CONFIG_WLAN_SYSFS_HE_BSS_COLOR) += -DWLAN_SYSFS_HE_BSS_COLOR +ccflags-$(CONFIG_WLAN_SYSFS_STA_INFO) += -DWLAN_SYSFS_STA_INFO +ccflags-$(CONFIG_WLAN_DL_MODES) += -DCONFIG_WLAN_DL_MODES +ccflags-$(CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT) += -DFEATURE_WPSS_THERMAL_MITIGATION +ccflags-$(CONFIG_WLAN_DUMP_IN_PROGRESS) += -DCONFIG_WLAN_DUMP_IN_PROGRESS +ccflags-$(CONFIG_WLAN_BMISS) += -DCONFIG_WLAN_BMISS +ccflags-$(CONFIG_WLAN_SYSFS_DP_STATS) += -DWLAN_SYSFS_DP_STATS +ccflags-$(CONFIG_WLAN_FREQ_LIST) += -DCONFIG_WLAN_FREQ_LIST + +ccflags-$(CONFIG_WIFI_MONITOR_SUPPORT) += -DWIFI_MONITOR_SUPPORT +ccflags-$(CONFIG_QCA_MONITOR_PKT_SUPPORT) += -DQCA_MONITOR_PKT_SUPPORT +ccflags-$(CONFIG_MONITOR_MODULARIZED_ENABLE) += -DMONITOR_MODULARIZED_ENABLE +ccflags-$(CONFIG_DP_PKT_ADD_TIMESTAMP) += -DCONFIG_DP_PKT_ADD_TIMESTAMP +ccflags-$(CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM) += -DWLAN_PDEV_VDEV_SEND_MULTI_PARAM +ccflags-$(CONFIG_WLAN_SYSFS_LOG_BUFFER) += -DFEATURE_SYSFS_LOG_BUFFER +ccflags-$(CONFIG_ENABLE_VALLOC_REPLACE_MALLOC) += -DENABLE_VALLOC_REPLACE_MALLOC +ccflags-$(CONFIG_WLAN_SYSFS_DFSNOL) += -DCONFIG_WLAN_SYSFS_DFSNOL +ccflags-$(CONFIG_WLAN_SYSFS_WDS_MODE) += -DFEATURE_SYSFS_WDS_MODE +ccflags-$(CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP) += -DFEATURE_SYSFS_ROAM_TRIGGER_BITMAP +cppflags-$(CONFIG_BCN_RATECODE_ENABLE) += -DWLAN_BCN_RATECODE_ENABLE +ccflags-$(CONFIG_WLAN_SYSFS_RF_TEST_MODE) += -DFEATURE_SYSFS_RF_TEST_MODE + +ifeq ($(CONFIG_LEAK_DETECTION), y) +ccflags-y += \ + -DCONFIG_HALT_KMEMLEAK \ + -DCONFIG_LEAK_DETECTION \ + -DMEMORY_DEBUG \ + -DNBUF_MEMORY_DEBUG \ + -DNBUF_MAP_UNMAP_DEBUG \ + -DTIMER_MANAGER \ + -DWLAN_DELAYED_WORK_DEBUG \ + -DWLAN_WAKE_LOCK_DEBUG \ + -DWLAN_PERIODIC_WORK_DEBUG +endif + +cppflags-$(CONFIG_ALLOC_CONTIGUOUS_MULTI_PAGE) += -DALLOC_CONTIGUOUS_MULTI_PAGE + +ifeq ($(CONFIG_QCOM_VOWIFI_11R), y) +ccflags-y += -DKERNEL_SUPPORT_11R_CFG80211 +ccflags-y += -DUSE_80211_WMMTSPEC_FOR_RIC +endif + +ifeq ($(CONFIG_QCOM_ESE), y) +ccflags-y += -DFEATURE_WLAN_ESE +endif + +#normally, TDLS negative behavior is not needed +ccflags-$(CONFIG_QCOM_TDLS) += -DFEATURE_WLAN_TDLS +ccflags-$(CONFIG_QCOM_TDLS) += -DWLAN_FEATURE_TDLS_CONCURRENCIES + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +ccflags-$(CONFIG_QCOM_TDLS) += -DTDLS_WOW_ENABLED +endif + +ccflags-$(CONFIG_WLAN_SYSFS_TDLS_PEERS) += -DWLAN_SYSFS_TDLS_PEERS +ccflags-$(CONFIG_WLAN_SYSFS_RANGE_EXT) += -DWLAN_SYSFS_RANGE_EXT + +ccflags-$(CONFIG_QCACLD_WLAN_LFR2) += -DWLAN_FEATURE_PREAUTH_ENABLE + +ifeq ($(CONFIG_CM_UTF_ENABLE), y) +ccflags-y += -DFEATURE_CM_UTF_ENABLE +endif + +ccflags-$(CONFIG_QCACLD_WLAN_LFR3) += -DWLAN_FEATURE_ROAM_OFFLOAD +ccflags-$(CONFIG_WLAN_FEATURE_ROAM_INFO_STATS) += -DWLAN_FEATURE_ROAM_INFO_STATS +ccflags-$(CONFIG_QCACLD_WLAN_CONNECTIVITY_LOGGING) += -DWLAN_FEATURE_CONNECTIVITY_LOGGING +ccflags-$(CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT) += -DCONNECTIVITY_DIAG_EVENT +ccflags-$(CONFIG_OFDM_SCRAMBLER_SEED) += -DWLAN_FEATURE_OFDM_SCRAMBLER_SEED + +ccflags-$(CONFIG_WLAN_FEATURE_MBSSID) += -DWLAN_FEATURE_MBSSID +ccflags-$(CONFIG_WLAN_FEATURE_P2P_P2P_STA) += -DWLAN_FEATURE_P2P_P2P_STA + +ifeq (y,$(findstring y, $(CONFIG_CNSS_GENL) $(CONFIG_CNSS_GENL_MODULE))) +ccflags-y += -DCNSS_GENL +endif + +ifeq (y,$(findstring y, $(CONFIG_CNSS_UTILS) $(CONFIG_CNSS_UTILS_MODULE))) +ccflags-y += -DCNSS_UTILS +endif + +ifeq (y,$(findstring y, $(CONFIG_WCNSS_MEM_PRE_ALLOC) $(CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE))) +ccflags-y += -DCNSS_MEM_PRE_ALLOC +endif + +ccflags-$(CONFIG_QCACLD_WLAN_LFR2) += -DWLAN_FEATURE_HOST_ROAM + +ccflags-$(CONFIG_FEATURE_ROAM_DEBUG) += -DFEATURE_ROAM_DEBUG + +ccflags-$(CONFIG_WLAN_POWER_DEBUG) += -DWLAN_POWER_DEBUG + +ccflags-$(CONFIG_WLAN_MWS_INFO_DEBUGFS) += -DWLAN_MWS_INFO_DEBUGFS + +ifeq ($(CONFIG_WLAN_DEBUG_LINK_VOTE), y) +ccflags-$(CONFIG_WLAN_DEBUG_LINK_VOTE) += -DWLAN_DEBUG_LINK_VOTE +endif +# Enable object manager reference count debug infrastructure +ccflags-$(CONFIG_WLAN_OBJMGR_DEBUG) += -DWLAN_OBJMGR_DEBUG +ccflags-$(CONFIG_WLAN_OBJMGR_DEBUG) += -DWLAN_OBJMGR_REF_ID_DEBUG +ccflags-$(CONFIG_WLAN_OBJMGR_REF_ID_TRACE) += -DWLAN_OBJMGR_REF_ID_TRACE +ccflags-$(CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY) += -DFEATURE_DELAYED_PEER_OBJ_DESTROY + +ccflags-$(CONFIG_WLAN_FEATURE_SAE) += -DWLAN_FEATURE_SAE + +ifeq ($(CONFIG_WLAN_DIAG_VERSION), y) +ccflags-y += -DFEATURE_WLAN_DIAG_SUPPORT +ccflags-y += -DFEATURE_WLAN_DIAG_SUPPORT_CSR +ccflags-y += -DFEATURE_WLAN_DIAG_SUPPORT_LIM +ifeq ($(CONFIG_HIF_PCI), y) +ccflags-y += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +endif +ifeq ($(CONFIG_HIF_IPCI), y) +ccflags-y += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +endif +endif + +ifeq ($(CONFIG_HIF_USB), y) +ccflags-y += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT +ccflags-y += -DQCA_SUPPORT_OL_RX_REORDER_TIMEOUT +ccflags-y += -DCONFIG_ATH_PCIE_MAX_PERF=0 -DCONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD=0 -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 +endif + +ccflags-$(CONFIG_QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK) += -DQCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + +ccflags-$(CONFIG_QCA_TXDESC_SANITY_CHECKS) += -DQCA_SUPPORT_TXDESC_SANITY_CHECKS + +ccflags-$(CONFIG_QCOM_LTE_COEX) += -DFEATURE_WLAN_CH_AVOID + +ccflags-$(CONFIG_WLAN_FEATURE_LPSS) += -DWLAN_FEATURE_LPSS + +ccflags-$(CONFIG_DESC_DUP_DETECT_DEBUG) += -DDESC_DUP_DETECT_DEBUG +ccflags-$(CONFIG_DEBUG_RX_RING_BUFFER) += -DDEBUG_RX_RING_BUFFER + +ccflags-$(CONFIG_DESC_TIMESTAMP_DEBUG_INFO) += -DDESC_TIMESTAMP_DEBUG_INFO + +ccflags-$(PANIC_ON_BUG) += -DPANIC_ON_BUG + +ccflags-$(WLAN_WARN_ON_ASSERT) += -DWLAN_WARN_ON_ASSERT + +ccflags-$(CONFIG_POWER_MANAGEMENT_OFFLOAD) += -DWLAN_POWER_MANAGEMENT_OFFLOAD + +ccflags-$(CONFIG_WLAN_LOG_FATAL) += -DWLAN_LOG_FATAL +ccflags-$(CONFIG_WLAN_LOG_ERROR) += -DWLAN_LOG_ERROR +ccflags-$(CONFIG_WLAN_LOG_WARN) += -DWLAN_LOG_WARN +ccflags-$(CONFIG_WLAN_LOG_INFO) += -DWLAN_LOG_INFO +ccflags-$(CONFIG_WLAN_LOG_DEBUG) += -DWLAN_LOG_DEBUG +ccflags-$(CONFIG_WLAN_LOG_ENTER) += -DWLAN_LOG_ENTER +ccflags-$(CONFIG_WLAN_LOG_EXIT) += -DWLAN_LOG_EXIT +ccflags-$(WLAN_OPEN_SOURCE) += -DWLAN_OPEN_SOURCE +ccflags-$(CONFIG_FEATURE_STATS_EXT) += -DWLAN_FEATURE_STATS_EXT +ccflags-$(CONFIG_QCACLD_FEATURE_NAN) += -DWLAN_FEATURE_NAN +ccflags-$(CONFIG_QCACLD_FEATURE_SON) += -DWLAN_FEATURE_SON +ccflags-$(CONFIG_NDP_SAP_CONCURRENCY_ENABLE) += -DNDP_SAP_CONCURRENCY_ENABLE +ccflags-$(CONFIG_ENFORCE_PLD_REMOVE) += -DENFORCE_PLD_REMOVE + +ifeq ($(CONFIG_DFS_FCC_TYPE4_DURATION_CHECK), y) +ccflags-$(CONFIG_DFS_FCC_TYPE4_DURATION_CHECK) += -DDFS_FCC_TYPE4_DURATION_CHECK +endif + +ccflags-$(CONFIG_WLAN_SYSFS) += -DWLAN_SYSFS +ccflags-$(CONFIG_WLAN_SYSFS_CHANNEL) += -DWLAN_SYSFS_CHANNEL +ccflags-$(CONFIG_FEATURE_BECN_STATS) += -DWLAN_FEATURE_BEACON_RECEPTION_STATS + +ccflags-$(CONFIG_WLAN_SYSFS_CONNECT_INFO) += -DWLAN_SYSFS_CONNECT_INFO +ccflags-$(CONFIG_WLAN_SYSFS_EHT_RATE) += -DWLAN_SYSFS_EHT_RATE + +#Set RX_PERFORMANCE +ccflags-$(CONFIG_RX_PERFORMANCE) += -DRX_PERFORMANCE + +#Set MULTI_IF_LOG +ccflags-$(CONFIG_MULTI_IF_LOG) += -DMULTI_IF_LOG + +#Set SLUB_MEM_OPTIMIZE +ccflags-$(CONFIG_SLUB_MEM_OPTIMIZE) += -DSLUB_MEM_OPTIMIZE + +ifeq ($(CONFIG_ARCH_SDXBAAGHA), y) +ccflags-$(CONFIG_WLAN_MEMORY_OPT) += -DWLAN_MEMORY_OPT +endif + +#Set DFS_PRI_MULTIPLIER +ccflags-$(CONFIG_DFS_PRI_MULTIPLIER) += -DDFS_PRI_MULTIPLIER + +#Set DFS_OVERRIDE_RF_THRESHOLD +ccflags-$(CONFIG_DFS_OVERRIDE_RF_THRESHOLD) += -DDFS_OVERRIDE_RF_THRESHOLD + +#Enable OL debug and wmi unified functions +ccflags-$(CONFIG_ATH_PERF_PWR_OFFLOAD) += -DATH_PERF_PWR_OFFLOAD + +#Disable packet log +ccflags-$(CONFIG_REMOVE_PKT_LOG) += -DREMOVE_PKT_LOG + +#Enable 11AC TX +ccflags-$(CONFIG_ATH_11AC_TXCOMPACT) += -DATH_11AC_TXCOMPACT + +#ENABLE HTT HTC tx completion +ccflags-$(ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST) += -DENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST + +#Enable PCI specific APIS (dma, etc) +ccflags-$(CONFIG_HIF_PCI) += -DHIF_PCI + +ccflags-$(CONFIG_HIF_IPCI) += -DHIF_IPCI + +ccflags-$(CONFIG_HIF_SNOC) += -DHIF_SNOC + +ccflags-$(CONFIG_HL_DP_SUPPORT) += -DCONFIG_HL_SUPPORT +ccflags-$(CONFIG_HL_DP_SUPPORT) += -DWLAN_PARTIAL_REORDER_OFFLOAD +ccflags-$(CONFIG_HL_DP_SUPPORT) += -DQCA_COMPUTE_TX_DELAY +ccflags-$(CONFIG_HL_DP_SUPPORT) += -DQCA_COMPUTE_TX_DELAY_PER_TID +ccflags-$(CONFIG_LL_DP_SUPPORT) += -DCONFIG_LL_DP_SUPPORT +ccflags-$(CONFIG_LL_DP_SUPPORT) += -DWLAN_FULL_REORDER_OFFLOAD +ccflags-$(CONFIG_WLAN_FEATURE_BIG_DATA_STATS) += -DWLAN_FEATURE_BIG_DATA_STATS +ifeq ($(CONFIG_WLAN_FEATURE_11AX), y) +ccflags-$(CONFIG_WLAN_FEATURE_SR) += -DWLAN_FEATURE_SR +ccflags-$(CONFIG_OBSS_PD) += -DOBSS_PD +endif +ccflags-$(CONFIG_WLAN_FEATURE_IGMP_OFFLOAD) += -DWLAN_FEATURE_IGMP_OFFLOAD +ccflags-$(CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST) += -DWLAN_FEATURE_GET_USABLE_CHAN_LIST + +# For PCIe GEN switch +ccflags-$(CONFIG_PCIE_GEN_SWITCH) += -DPCIE_GEN_SWITCH + +# For OOB testing +ccflags-$(CONFIG_WLAN_FEATURE_WOW_PULSE) += -DWLAN_FEATURE_WOW_PULSE + +#Enable High Latency related Flags +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +ccflags-y += -DCONFIG_AR6320_SUPPORT \ + -DSDIO_3_0 \ + -DHIF_SDIO \ + -DCONFIG_DISABLE_CDC_MAX_PERF_WAR=0 \ + -DCONFIG_ATH_PROCFS_DIAG_SUPPORT \ + -DHIF_MBOX_SLEEP_WAR \ + -DDEBUG_HL_LOGGING \ + -DQCA_BAD_PEER_TX_FLOW_CL \ + -DCONFIG_SDIO \ + -DFEATURE_WLAN_FORCE_SAP_SCC + +ifeq ($(CONFIG_SDIO_TRANSFER), adma) +ccflags-y += -DCONFIG_SDIO_TRANSFER_ADMA +else +ccflags-y += -DCONFIG_SDIO_TRANSFER_MAILBOX +endif +endif + +ccflags-$(CONFIG_AR6320_SUPPORT) += -DCONFIG_AR6320_SUPPORT + +ifeq ($(CONFIG_WLAN_FEATURE_DSRC), y) +ccflags-y += -DWLAN_FEATURE_DSRC +ifeq ($(CONFIG_OCB_UT_FRAMEWORK), y) +ccflags-y += -DWLAN_OCB_UT +endif + +else ifeq ($(CONFIG_WLAN_REG_AUTO), y) +ccflags-y += -DWLAN_REG_AUTO +endif + +ccflags-$(CONFIG_FEATURE_SKB_PRE_ALLOC) += -DFEATURE_SKB_PRE_ALLOC + +#Enable USB specific APIS +ifeq ($(CONFIG_HIF_USB), y) +ccflags-y += -DHIF_USB \ + -DDEBUG_HL_LOGGING +endif + +#Enable Genoa specific features. +ccflags-$(CONFIG_QCA_HL_NETDEV_FLOW_CONTROL) += -DQCA_HL_NETDEV_FLOW_CONTROL +ccflags-$(CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) += -DFEATURE_HL_GROUP_CREDIT_FLOW_CONTROL +ccflags-$(CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING) += -DFEATURE_HL_DBS_GROUP_CREDIT_SHARING +ccflags-$(CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE) += -DCONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE +ccflags-$(CONFIG_RX_PN_CHECK_OFFLOAD) += -DCONFIG_RX_PN_CHECK_OFFLOAD + +ccflags-$(CONFIG_WLAN_SYNC_TSF_TIMER) += -DWLAN_FEATURE_TSF_TIMER_SYNC +ccflags-$(CONFIG_WLAN_SYNC_TSF_PTP) += -DWLAN_FEATURE_TSF_PTP +ccflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ) += -DWLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +ccflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_SYNC) += -DWLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +ccflags-$(CONFIG_TX_DESC_HI_PRIO_RESERVE) += -DCONFIG_TX_DESC_HI_PRIO_RESERVE + +#Enable power management suspend/resume functionality +ccflags-$(CONFIG_ATH_BUS_PM) += -DATH_BUS_PM + +#Enable FLOWMAC module support +ccflags-$(CONFIG_ATH_SUPPORT_FLOWMAC_MODULE) += -DATH_SUPPORT_FLOWMAC_MODULE + +#Enable spectral support +ccflags-$(CONFIG_ATH_SUPPORT_SPECTRAL) += -DATH_SUPPORT_SPECTRAL + +#Enable legacy pktlog +ccflags-$(CONFIG_PKTLOG_LEGACY) += -DPKTLOG_LEGACY + +#Enable WDI Event support +ccflags-$(CONFIG_WDI_EVENT_ENABLE) += -DWDI_EVENT_ENABLE + +#Enable the type_specific_data in the struct ath_pktlog_arg +ccflags-$(CONFIG_PKTLOG_HAS_SPECIFIC_DATA) += -DPKTLOG_HAS_SPECIFIC_DATA + +#Endianness selection +ifeq ($(CONFIG_LITTLE_ENDIAN), y) +ccflags-y += -DANI_LITTLE_BYTE_ENDIAN +ccflags-y += -DANI_LITTLE_BIT_ENDIAN +ccflags-y += -DDOT11F_LITTLE_ENDIAN_HOST +else +ccflags-y += -DANI_BIG_BYTE_ENDIAN +ccflags-y += -DBIG_ENDIAN_HOST +endif + +#Enable TX reclaim support +ccflags-$(CONFIG_TX_CREDIT_RECLAIM_SUPPORT) += -DTX_CREDIT_RECLAIM_SUPPORT + +#Enable FTM support +ccflags-$(CONFIG_QCA_WIFI_FTM) += -DQCA_WIFI_FTM +ccflags-$(CONFIG_NL80211_TESTMODE) += -DQCA_WIFI_FTM_NL80211 +ccflags-$(CONFIG_LINUX_QCMBR) += -DLINUX_QCMBR -DQCA_WIFI_FTM_IOCTL + +#Enable Checksum Offload support +ccflags-$(CONFIG_CHECKSUM_OFFLOAD) += -DCHECKSUM_OFFLOAD + +#Enable IPA Offload support +ccflags-$(CONFIG_IPA_OFFLOAD) += -DIPA_OFFLOAD + +#Enable IPA optional Wifi datapath +ifeq ($(CONFIG_IPA_OPT_WIFI_DP), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ccflags-$(CONFIG_IPA_OPT_WIFI_DP) += -DIPA_OPT_WIFI_DP +endif +endif + +ccflags-$(CONFIG_WDI3_IPA_OVER_GSI) += -DIPA_WDI3_GSI +ccflags-$(CONFIG_WDI2_IPA_OVER_GSI) += -DIPA_WDI2_GSI + +#Enable WMI DIAG log over CE7 +ccflags-$(CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7) += -DWLAN_FEATURE_WMI_DIAG_OVER_CE7 + +ifdef CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY +ccflags-y += -DWLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +ccflags-y += -DSYNC_IPA_READY +endif + +ifeq ($(CONFIG_ARCH_SDXPOORWILLS), y) +CONFIG_FEATURE_SG := y +endif + +ifeq ($(CONFIG_ARCH_MSM8996), y) +ifneq ($(CONFIG_QCN7605_SUPPORT), y) +CONFIG_FEATURE_SG := y +CONFIG_RX_THREAD_PRIORITY := y +endif +endif + +ifeq ($(CONFIG_FEATURE_SG), y) +ccflags-y += -DFEATURE_SG +endif + +ifeq ($(CONFIG_RX_THREAD_PRIORITY), y) +ccflags-y += -DRX_THREAD_PRIORITY +endif + +ifeq ($(CONFIG_SUPPORT_P2P_BY_ONE_INTF_WLAN), y) +#sta support to tx P2P action frames +ccflags-y += -DSUPPORT_P2P_BY_ONE_INTF_WLAN +else +#Open P2P device interface only for non-Mobile router use cases +ccflags-$(CONFIG_WLAN_OPEN_P2P_INTERFACE) += -DWLAN_OPEN_P2P_INTERFACE +endif + +ccflags-$(CONFIG_WMI_BCN_OFFLOAD) += -DWLAN_WMI_BCN + +#Enable wbuff +ccflags-$(CONFIG_WLAN_WBUFF) += -DWLAN_FEATURE_WBUFF + +#Enable GTK Offload +ccflags-$(CONFIG_GTK_OFFLOAD) += -DWLAN_FEATURE_GTK_OFFLOAD + +#Enable External WoW +ccflags-$(CONFIG_EXT_WOW) += -DWLAN_FEATURE_EXTWOW_SUPPORT + +#Mark it as SMP Kernel +ccflags-$(CONFIG_SMP) += -DQCA_CONFIG_SMP + +#CONFIG_RPS default Y, but depend on CONFIG_SMP +ccflags-$(CONFIG_RPS) += -DQCA_CONFIG_RPS + +ccflags-$(CONFIG_CHNL_MATRIX_RESTRICTION) += -DWLAN_ENABLE_CHNL_MATRIX_RESTRICTION + +#Enable ICMP packet disable powersave feature +ccflags-$(CONFIG_ICMP_DISABLE_PS) += -DWLAN_ICMP_DISABLE_PS + +#enable MCC TO SCC switch +ccflags-$(CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH) += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH + +#enable wlan auto shutdown feature +ccflags-$(CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN) += -DFEATURE_WLAN_AUTO_SHUTDOWN + +#enable AP-AP ACS Optimization +ccflags-$(CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE) += -DFEATURE_WLAN_AP_AP_ACS_OPTIMIZE + +#Enable 4address scheme +ccflags-$(CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME) += -DFEATURE_WLAN_STA_4ADDR_SCHEME + +#Optimize GC connection speed by skipping JOIN +ccflags-$(CONFIG_FEATURE_WLAN_GC_SKIP_JOIN) += -DFEATURE_WLAN_GC_SKIP_JOIN + +#enable MDM/SDX special config +ccflags-$(CONFIG_MDM_PLATFORM) += -DMDM_PLATFORM + +#Disable STA-AP Mode DFS support +ccflags-$(CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) += -DFEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + +#Enable 2.4 GHz social channels in 5 GHz only mode for p2p usage +ccflags-$(CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY) += -DWLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + +#Green AP feature +ccflags-$(CONFIG_QCACLD_FEATURE_GREEN_AP) += -DWLAN_SUPPORT_GREEN_AP + +ccflags-$(CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE) += -DWLAN_SUPPORT_GAP_LL_PS_MODE + +ccflags-$(CONFIG_QCACLD_FEATURE_APF) += -DFEATURE_WLAN_APF + +ccflags-$(CONFIG_WLAN_FEATURE_SARV1_TO_SARV2) += -DWLAN_FEATURE_SARV1_TO_SARV2 + +ccflags-$(CONFIG_FEATURE_WLAN_FT_IEEE8021X) += -DFEATURE_WLAN_FT_IEEE8021X +ccflags-$(CONFIG_FEATURE_WLAN_FT_PSK) += -DFEATURE_WLAN_FT_PSK + +#Enable host 11d scan +ccflags-$(CONFIG_HOST_11D_SCAN) += -DHOST_11D_SCAN + +#Stats & Quota Metering feature +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ifeq ($(CONFIG_QCACLD_FEATURE_METERING), y) +ccflags-y += -DFEATURE_METERING +endif +endif + +#Define Max IPA interface +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ifdef CONFIG_NUM_IPA_IFACE +ccflags-y += -DMAX_IPA_IFACE=$(CONFIG_NUM_IPA_IFACE) +else +NUM_IPA_IFACE ?= 3 +ccflags-y += -DMAX_IPA_IFACE=$(NUM_IPA_IFACE) +endif +endif + + +ccflags-$(CONFIG_TUFELLO_DUAL_FW_SUPPORT) += -DCONFIG_TUFELLO_DUAL_FW_SUPPORT +ccflags-$(CONFIG_CHANNEL_HOPPING_ALL_BANDS) += -DCHANNEL_HOPPING_ALL_BANDS + +#Enable Signed firmware support for split binary format +ccflags-$(CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT) += -DQCA_SIGNED_SPLIT_BINARY_SUPPORT + +#Enable single firmware binary format +ccflags-$(CONFIG_QCA_SINGLE_BINARY_SUPPORT) += -DQCA_SINGLE_BINARY_SUPPORT + +#Enable collecting target RAM dump after kernel panic +ccflags-$(CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC) += -DTARGET_RAMDUMP_AFTER_KERNEL_PANIC + +#Enable/disable secure firmware feature +ccflags-$(CONFIG_FEATURE_SECURE_FIRMWARE) += -DFEATURE_SECURE_FIRMWARE + +ccflags-$(CONFIG_ATH_PCIE_ACCESS_DEBUG) += -DCONFIG_ATH_PCIE_ACCESS_DEBUG + +# Enable feature support for Linux version QCMBR +ccflags-$(CONFIG_LINUX_QCMBR) += -DLINUX_QCMBR + +# Enable feature sync tsf between multi devices +ccflags-$(CONFIG_WLAN_SYNC_TSF) += -DWLAN_FEATURE_TSF + +ifeq ($(CONFIG_WLAN_SYNC_TSF_PLUS), y) +ccflags-y += -DWLAN_FEATURE_TSF_PLUS + +ccflags-$(CONFIG_WLAN_SYNC_TSF_ACCURACY) += -DWLAN_FEATURE_TSF_ACCURACY + +ifneq ($(CONFIG_WLAN_SYNC_TSF_PLUS_DISABLE_SOCK_TS), y) +ccflags-y += -DWLAN_FEATURE_TSF_PLUS_SOCK_TS +endif + +endif + +# Enable feature sync tsf for chips based on Adrastea arch +ccflags-$(CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ) += -DWLAN_FEATURE_TSF_PLUS_NOIRQ + +ifeq ($(CONFIG_WLAN_TSF_UPLINK_DELAY), y) +# Enable uplink delay report feature +ccflags-y += -DWLAN_FEATURE_TSF_UPLINK_DELAY +CONFIG_WLAN_TSF_AUTO_REPORT := y +endif + +# Enable tx latency stats feature +ifeq ($(CONFIG_WLAN_TX_LATENCY_STATS), y) +ccflags-y += -DWLAN_FEATURE_TX_LATENCY_STATS +CONFIG_WLAN_TSF_AUTO_REPORT := y +endif + +# Enable TSF auto report feature +ccflags-$(CONFIG_WLAN_TSF_AUTO_REPORT) += -DWLAN_FEATURE_TSF_AUTO_REPORT + +ccflags-$(CONFIG_ATH_PROCFS_DIAG_SUPPORT) += -DCONFIG_ATH_PROCFS_DIAG_SUPPORT + +ccflags-$(CONFIG_HELIUMPLUS) += -DHELIUMPLUS +ccflags-$(CONFIG_RX_OL) += -DRECEIVE_OFFLOAD +ccflags-$(CONFIG_TX_TID_OVERRIDE) += -DATH_TX_PRI_OVERRIDE +ccflags-$(CONFIG_AR900B) += -DAR900B +ccflags-$(CONFIG_HTT_PADDR64) += -DHTT_PADDR64 +ccflags-$(CONFIG_OL_RX_INDICATION_RECORD) += -DOL_RX_INDICATION_RECORD +ccflags-$(CONFIG_TSOSEG_DEBUG) += -DTSOSEG_DEBUG +ccflags-$(CONFIG_ALLOW_PKT_DROPPING) += -DFEATURE_ALLOW_PKT_DROPPING + +# Enable feature for athdiag live debug mode +ccflags-$(CONFIG_ATH_DIAG_EXT_DIRECT) += -DATH_DIAG_EXT_DIRECT + +ccflags-$(CONFIG_ENABLE_DEBUG_ADDRESS_MARKING) += -DENABLE_DEBUG_ADDRESS_MARKING +ccflags-$(CONFIG_FEATURE_TSO) += -DFEATURE_TSO +ccflags-$(CONFIG_FEATURE_TSO_DEBUG) += -DFEATURE_TSO_DEBUG +ccflags-$(CONFIG_FEATURE_TSO_STATS) += -DFEATURE_TSO_STATS +ccflags-$(CONFIG_FEATURE_FORCE_WAKE) += -DFORCE_WAKE +ccflags-$(CONFIG_WLAN_LRO) += -DFEATURE_LRO + +ccflags-$(CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE) += -DFEATURE_AP_MCC_CH_AVOIDANCE + +ccflags-$(CONFIG_FEATURE_EPPING) += -DWLAN_FEATURE_EPPING + +ccflags-$(CONFIG_WLAN_OFFLOAD_PACKETS) += -DWLAN_FEATURE_OFFLOAD_PACKETS + +ccflags-$(CONFIG_WLAN_FEATURE_DISA) += -DWLAN_FEATURE_DISA + +ccflags-$(CONFIG_WLAN_FEATURE_ACTION_OUI) += -DWLAN_FEATURE_ACTION_OUI + +ccflags-$(CONFIG_WLAN_FEATURE_FIPS) += -DWLAN_FEATURE_FIPS + +ccflags-$(CONFIG_LFR_SUBNET_DETECTION) += -DFEATURE_LFR_SUBNET_DETECTION + +ccflags-$(CONFIG_MCC_TO_SCC_SWITCH) += -DFEATURE_WLAN_MCC_TO_SCC_SWITCH + +ccflags-$(CONFIG_FEATURE_WLAN_D0WOW) += -DFEATURE_WLAN_D0WOW + +ccflags-$(CONFIG_WLAN_FEATURE_PKT_CAPTURE) += -DWLAN_FEATURE_PKT_CAPTURE + +ccflags-$(CONFIG_WLAN_FEATURE_PKT_CAPTURE_V2) += -DWLAN_FEATURE_PKT_CAPTURE_V2 + +ccflags-$(CONFIG_DP_RX_UDP_OVER_PEER_ROAM) += -DDP_RX_UDP_OVER_PEER_ROAM + +cppflags-$(CONFIG_WLAN_BOOST_CPU_FREQ_IN_ROAM) += -DWLAN_BOOST_CPU_FREQ_IN_ROAM + +ccflags-$(CONFIG_QCA_WIFI_EMULATION) += -DQCA_WIFI_EMULATION +ccflags-$(CONFIG_SAP_MULTI_LINK_EMULATION) += -DSAP_MULTI_LINK_EMULATION +ccflags-$(CONFIG_SHADOW_V2) += -DCONFIG_SHADOW_V2 +ccflags-$(CONFIG_SHADOW_V3) += -DCONFIG_SHADOW_V3 +ccflags-$(CONFIG_QCA6290_HEADERS_DEF) += -DQCA6290_HEADERS_DEF +ccflags-$(CONFIG_QCA_WIFI_QCA6290) += -DQCA_WIFI_QCA6290 +ccflags-$(CONFIG_QCA6390_HEADERS_DEF) += -DQCA6390_HEADERS_DEF +ccflags-$(CONFIG_QCA6750_HEADERS_DEF) += -DQCA6750_HEADERS_DEF +ccflags-$(CONFIG_QCA_WIFI_QCA6390) += -DQCA_WIFI_QCA6390 +ccflags-$(CONFIG_QCA6490_HEADERS_DEF) += -DQCA6490_HEADERS_DEF +ccflags-$(CONFIG_KIWI_HEADERS_DEF) += -DKIWI_HEADERS_DEF +ccflags-$(CONFIG_WCN6450_HEADERS_DEF) += -DWCN6450_HEADERS_DEF +ccflags-$(CONFIG_QCA_WIFI_QCA6490) += -DQCA_WIFI_QCA6490 +ccflags-$(CONFIG_QCA_WIFI_QCA6750) += -DQCA_WIFI_QCA6750 +ccflags-$(CONFIG_QCA_WIFI_KIWI) += -DQCA_WIFI_KIWI +ccflags-$(CONFIG_QCA_WIFI_WCN6450) += -DQCA_WIFI_WCN6450 +ccflags-$(CONFIG_QCA_WIFI_WCN6450) += -DWLAN_40BIT_ADDRESSING_SUPPORT +ccflags-$(CONFIG_QCA_WIFI_WCN6450) += -DWLAN_64BIT_DATA_SUPPORT +ccflags-$(CONFIG_CE_LEGACY_MSI_SUPPORT) += -DCE_LEGACY_MSI_SUPPORT +ccflags-$(CONFIG_HIF_HAL_REG_ACCESS_SUPPORT) += -DHIF_HAL_REG_ACCESS_SUPPORT +ccflags-$(CONFIG_FEATURE_HIF_DELAYED_REG_WRITE) += -DFEATURE_HIF_DELAYED_REG_WRITE +ccflags-$(CONFIG_CNSS_KIWI_V2) += -DQCA_WIFI_KIWI_V2 +ccflags-$(CONFIG_CNSS_MANGO) += -DQCA_WIFI_MANGO +ccflags-$(CONFIG_CNSS_PEACH) += -DQCA_WIFI_PEACH +ccflags-$(CONFIG_QCA_WIFI_QCA8074) += -DQCA_WIFI_QCA8074 +ccflags-$(CONFIG_SCALE_INCLUDES) += -DSCALE_INCLUDES +ccflags-$(CONFIG_QCA_WIFI_QCA8074_VP) += -DQCA_WIFI_QCA8074_VP +ccflags-$(CONFIG_DP_INTR_POLL_BASED) += -DDP_INTR_POLL_BASED +ccflags-$(CONFIG_TX_PER_PDEV_DESC_POOL) += -DTX_PER_PDEV_DESC_POOL +ccflags-$(CONFIG_DP_TRACE) += -DCONFIG_DP_TRACE +ccflags-$(CONFIG_FEATURE_TSO) += -DFEATURE_TSO +ccflags-$(CONFIG_TSO_DEBUG_LOG_ENABLE) += -DTSO_DEBUG_LOG_ENABLE +ccflags-$(CONFIG_DP_LFR) += -DDP_LFR +ccflags-$(CONFIG_DUP_RX_DESC_WAR) += -DDUP_RX_DESC_WAR +ccflags-$(CONFIG_DP_MEM_PRE_ALLOC) += -DDP_MEM_PRE_ALLOC +ccflags-$(CONFIG_DP_TXRX_SOC_ATTACH) += -DDP_TXRX_SOC_ATTACH +ccflags-$(CONFIG_WLAN_FEATURE_BMI) += -DWLAN_FEATURE_BMI +ccflags-$(CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT) += -DQCA_TX_PADDING_CREDIT_SUPPORT +ccflags-$(CONFIG_QCN7605_SUPPORT) += -DQCN7605_SUPPORT -DPLATFORM_GENOA +ccflags-$(CONFIG_HIF_REG_WINDOW_SUPPORT) += -DHIF_REG_WINDOW_SUPPORT +ccflags-$(CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY) += -DWLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +ccflags-$(CONFIG_HIF_CE_DEBUG_DATA_BUF) += -DHIF_CE_DEBUG_DATA_BUF +ccflags-$(CONFIG_IPA_DISABLE_OVERRIDE) += -DIPA_DISABLE_OVERRIDE +ccflags-$(CONFIG_QCA_LL_TX_FLOW_CONTROL_RESIZE) += -DQCA_LL_TX_FLOW_CONTROL_RESIZE +ccflags-$(CONFIG_HIF_PCI) += -DCE_SVC_CMN_INIT +ccflags-$(CONFIG_HIF_IPCI) += -DCE_SVC_CMN_INIT +ccflags-$(CONFIG_HIF_SNOC) += -DCE_SVC_CMN_INIT +ccflags-$(CONFIG_RX_DESC_SANITY_WAR) += -DRX_DESC_SANITY_WAR +ccflags-$(CONFIG_WBM_IDLE_LSB_WR_CNF_WAR) += -DWBM_IDLE_LSB_WRITE_CONFIRM_WAR +ccflags-$(CONFIG_DYNAMIC_RX_AGGREGATION) += -DWLAN_FEATURE_DYNAMIC_RX_AGGREGATION +ccflags-$(CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION) += -DDP_FEATURE_HW_COOKIE_CONVERSION +ccflags-$(CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION) += -DDP_HW_COOKIE_CONVERT_EXCEPTION +ccflags-$(CONFIG_TX_ADDR_INDEX_SEARCH) += -DTX_ADDR_INDEX_SEARCH +ccflags-$(CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES) += -DQCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES +ccflags-$(CONFIG_QCA_GET_TSF_VIA_REG) += -DQCA_GET_TSF_VIA_REG +ccflags-$(CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK) += -DDP_TX_COMP_RING_DESC_SANITY_CHECK +ccflags-$(CONFIG_HAL_SRNG_REG_HIS_DEBUG) += -DHAL_SRNG_REG_HIS_DEBUG +ccflags-$(CONFIG_DP_MLO_LINK_STATS_SUPPORT) += -DDP_MLO_LINK_STATS_SUPPORT + +ccflags-$(CONFIG_RX_HASH_DEBUG) += -DRX_HASH_DEBUG +ccflags-$(CONFIG_DP_PKT_STATS_PER_LMAC) += -DDP_PKT_STATS_PER_LMAC +ccflags-$(CONFIG_NO_RX_PKT_HDR_TLV) += -DNO_RX_PKT_HDR_TLV +ccflags-$(CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP) += -DDP_TX_PACKET_INSPECT_FOR_ILP + +ifeq ($(CONFIG_QCA6290_11AX), y) +ccflags-y += -DQCA_WIFI_QCA6290_11AX -DQCA_WIFI_QCA6290_11AX_MU_UL +endif + +ccflags-$(CONFIG_WLAN_TX_FLOW_CONTROL_V2) += -DQCA_AC_BASED_FLOW_CONTROL + +# Enable Low latency optimisation mode +ccflags-$(CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT) += -DFEATURE_NO_DBS_INTRABAND_MCC_SUPPORT +ccflags-$(CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR) += -DHAL_DISABLE_NON_BA_2K_JUMP_ERROR +ccflags-$(CONFIG_ENABLE_HAL_SOC_STATS) += -DENABLE_HAL_SOC_STATS +ccflags-$(CONFIG_ENABLE_HAL_REG_WR_HISTORY) += -DENABLE_HAL_REG_WR_HISTORY +ccflags-$(CONFIG_DP_RX_DESC_COOKIE_INVALIDATE) += -DDP_RX_DESC_COOKIE_INVALIDATE +ccflags-$(CONFIG_MON_ENABLE_DROP_FOR_MAC) += -DMON_ENABLE_DROP_FOR_MAC +ccflags-$(CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC) += -DMON_ENABLE_DROP_FOR_NON_MON_PMAC +ccflags-$(CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG) += -DDP_WAR_INVALID_FIRST_MSDU_FLAG +ccflags-$(CONFIG_LITHIUM) += -DDISABLE_MON_RING_MSI_CFG +ccflags-$(CONFIG_LITHIUM) += -DFEATURE_IRQ_AFFINITY +ccflags-$(CONFIG_RHINE) += -DFEATURE_IRQ_AFFINITY +ccflags-$(CONFIG_RHINE) += -DWLAN_SOFTUMAC_SUPPORT +ccflags-$(CONFIG_BERYLLIUM) += -DFEATURE_IRQ_AFFINITY +ccflags-$(CONFIG_TX_MULTIQ_PER_AC) += -DTX_MULTIQ_PER_AC +ccflags-$(CONFIG_PCI_LINK_STATUS_SANITY) += -DPCI_LINK_STATUS_SANITY +ccflags-$(CONFIG_DDP_MON_RSSI_IN_DBM) += -DDP_MON_RSSI_IN_DBM +ccflags-$(CONFIG_SYSTEM_PM_CHECK) += -DSYSTEM_PM_CHECK +ccflags-$(CONFIG_DISABLE_EAPOL_INTRABSS_FWD) += -DDISABLE_EAPOL_INTRABSS_FWD +ccflags-$(CONFIG_TX_AGGREGATION_SIZE_ENABLE) += -DTX_AGGREGATION_SIZE_ENABLE +ccflags-$(CONFIG_TX_MULTI_TCL) += -DTX_MULTI_TCL +ccflags-$(CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG) += -DWLAN_DP_DISABLE_TCL_CMD_CRED_SRNG +ccflags-$(CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG) += -DWLAN_DP_DISABLE_TCL_STATUS_SRNG +ccflags-$(CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE) += -DDP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE +ccflags-$(CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING) += -DWLAN_DP_SRNG_USAGE_WM_TRACKING +ccflags-$(CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY) += -DWLAN_FEATURE_DP_CFG_EVENT_HISTORY +ccflags-$(CONFIG_WLAN_DP_VDEV_NO_SELF_PEER) += -DWLAN_DP_VDEV_NO_SELF_PEER +ccflags-$(CONFIG_DP_RX_MSDU_DONE_FAIL_HISTORY) += -DDP_RX_MSDU_DONE_FAIL_HISTORY +ccflags-$(CONFIG_DP_RX_PEEK_MSDU_DONE_WAR) += -DDP_RX_PEEK_MSDU_DONE_WAR + +# Enable Low latency +ccflags-$(CONFIG_WLAN_FEATURE_LL_MODE) += -DWLAN_FEATURE_LL_MODE + +# Enable PCI low power interrupt register configuration +ccflags-$(CONFIG_PCI_LOW_POWER_INT_REG) += -DCONFIG_PCI_LOW_POWER_INT_REG + +ccflags-$(CONFIG_WLAN_CLD_PM_QOS) += -DCLD_PM_QOS +ccflags-$(CONFIG_WLAN_CLD_DEV_PM_QOS) += -DCLD_DEV_PM_QOS +ccflags-$(CONFIG_REO_DESC_DEFER_FREE) += -DREO_DESC_DEFER_FREE +ccflags-$(CONFIG_WLAN_FEATURE_11AX) += -DWLAN_FEATURE_11AX +ccflags-$(CONFIG_WLAN_FEATURE_11AX) += -DWLAN_FEATURE_11AX_BSS_COLOR +ccflags-$(CONFIG_WLAN_FEATURE_11AX) += -DSUPPORT_11AX_D3 +ccflags-$(CONFIG_RXDMA_ERR_PKT_DROP) += -DRXDMA_ERR_PKT_DROP +ccflags-$(CONFIG_MAX_ALLOC_PAGE_SIZE) += -DMAX_ALLOC_PAGE_SIZE +ccflags-$(CONFIG_DELIVERY_TO_STACK_STATUS_CHECK) += -DDELIVERY_TO_STACK_STATUS_CHECK +ccflags-$(CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS) += -DWLAN_TRACE_HIDE_MAC_ADDRESS +ccflags-$(CONFIG_WLAN_TRACE_HIDE_SSID) += -DWLAN_TRACE_HIDE_SSID +ccflags-$(CONFIG_WLAN_FEATURE_11BE) += -DWLAN_FEATURE_11BE +ccflags-$(CONFIG_WLAN_FEATURE_11BE_MLO) += -DWLAN_FEATURE_11BE_MLO +ccflags-$(CONFIG_WLAN_FEATURE_11BE_MLO) += -DWLAN_FEATURE_11BE_MLO_ADV_FEATURE +ccflags-$(CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) += -DWLAN_HDD_MULTI_VDEV_SINGLE_NDEV +ccflags-$(CONFIG_WLAN_FEATURE_11BE_MLO) += -DWLAN_SUPPORT_11BE_D3_0 +ccflags-$(CONFIG_FIX_TXDMA_LIMITATION) += -DFIX_TXDMA_LIMITATION +ccflags-$(CONFIG_FEATURE_AST) += -DFEATURE_AST +ccflags-$(CONFIG_PEER_PROTECTED_ACCESS) += -DPEER_PROTECTED_ACCESS +ccflags-$(CONFIG_SERIALIZE_QUEUE_SETUP) += -DSERIALIZE_QUEUE_SETUP +ccflags-$(CONFIG_DP_RX_PKT_NO_PEER_DELIVER) += -DDP_RX_PKT_NO_PEER_DELIVER +ccflags-$(CONFIG_DP_RX_DROP_RAW_FRM) += -DDP_RX_DROP_RAW_FRM +ccflags-$(CONFIG_FEATURE_ALIGN_STATS_FROM_DP) += -DFEATURE_ALIGN_STATS_FROM_DP +ccflags-$(CONFIG_DP_RX_SPECIAL_FRAME_NEED) += -DDP_RX_SPECIAL_FRAME_NEED +ccflags-$(CONFIG_FEATURE_STATS_EXT_V2) += -DFEATURE_STATS_EXT_V2 +ccflags-$(CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER) += -DWLAN_FEATURE_CAL_FAILURE_TRIGGER +ccflags-$(CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE) += -DWLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +ccflags-$(CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE) += -DWLAN_FEATURE_SAP_ACS_OPTIMIZE +ccflags-$(CONFIG_WLAN_FEATURE_NO_STA_SAP_CONCURRENCY) += -DWLAN_FEATURE_NO_STA_SAP_CONCURRENCY +ccflags-$(CONFIG_WLAN_FEATURE_NO_STA_NAN_CONCURRENCY) += -DWLAN_FEATURE_NO_STA_NAN_CONCURRENCY +ccflags-$(CONFIG_WLAN_FEATURE_NO_P2P_CONCURRENCY) += -DWLAN_FEATURE_NO_P2P_CONCURRENCY +ccflags-$(CONFIG_WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY) += -DWLAN_FEATURE_NO_SAP_NAN_CONCURRENCY + +ccflags-$(CONFIG_VERBOSE_DEBUG) += -DENABLE_VERBOSE_DEBUG +ccflags-$(CONFIG_RX_DESC_DEBUG_CHECK) += -DRX_DESC_DEBUG_CHECK +ccflags-$(CONFIG_REGISTER_OP_DEBUG) += -DHAL_REGISTER_WRITE_DEBUG +ccflags-$(CONFIG_ENABLE_QDF_PTR_HASH_DEBUG) += -DENABLE_QDF_PTR_HASH_DEBUG +#Enable STATE MACHINE HISTORY +ccflags-$(CONFIG_SM_ENG_HIST) += -DSM_ENG_HIST_ENABLE +ccflags-$(CONFIG_FEATURE_VDEV_OPS_WAKELOCK) += -DFEATURE_VDEV_OPS_WAKELOCK + +# Vendor Commands +ccflags-$(CONFIG_FEATURE_RSSI_MONITOR) += -DFEATURE_RSSI_MONITOR +ccflags-$(CONFIG_FEATURE_BSS_TRANSITION) += -DFEATURE_BSS_TRANSITION +ccflags-$(CONFIG_FEATURE_STATION_INFO) += -DFEATURE_STATION_INFO +ccflags-$(CONFIG_FEATURE_TX_POWER) += -DFEATURE_TX_POWER +ccflags-$(CONFIG_FEATURE_OTA_TEST) += -DFEATURE_OTA_TEST +ccflags-$(CONFIG_FEATURE_ACTIVE_TOS) += -DFEATURE_ACTIVE_TOS +ccflags-$(CONFIG_FEATURE_SAR_LIMITS) += -DFEATURE_SAR_LIMITS +ccflags-$(CONFIG_FEATURE_CONCURRENCY_MATRIX) += -DFEATURE_CONCURRENCY_MATRIX +ccflags-$(CONFIG_FEATURE_SAP_COND_CHAN_SWITCH) += -DFEATURE_SAP_COND_CHAN_SWITCH +ccflags-$(CONFIG_FEATURE_WLAN_CH_AVOID_EXT) += -DFEATURE_WLAN_CH_AVOID_EXT +ccflags-$(CONFIG_WLAN_FEATURE_MDNS_OFFLOAD) += -DWLAN_FEATURE_MDNS_OFFLOAD + +#if converged p2p is enabled +ifeq ($(CONFIG_CONVERGED_P2P_ENABLE), y) +ccflags-$(CONFIG_FEATURE_P2P_LISTEN_OFFLOAD) += -DFEATURE_P2P_LISTEN_OFFLOAD +endif + +#Enable support to get ANI value +ifeq ($(CONFIG_ANI_LEVEL_REQUEST), y) +ccflags-y += -DFEATURE_ANI_LEVEL_REQUEST +endif + +#Flags to enable/disable WMI APIs +ccflags-$(CONFIG_WMI_ROAM_SUPPORT) += -DWMI_ROAM_SUPPORT +ccflags-$(CONFIG_WMI_CONCURRENCY_SUPPORT) += -DWMI_CONCURRENCY_SUPPORT +ccflags-$(CONFIG_WMI_STA_SUPPORT) += -DWMI_STA_SUPPORT + +ifdef CONFIG_HIF_LARGE_CE_RING_HISTORY +ccflags-y += -DHIF_CE_HISTORY_MAX=$(CONFIG_HIF_LARGE_CE_RING_HISTORY) +endif + +ccflags-$(CONFIG_WLAN_HANG_EVENT) += -DHIF_CE_LOG_INFO +ccflags-$(CONFIG_WLAN_HANG_EVENT) += -DHIF_BUS_LOG_INFO +ccflags-$(CONFIG_WLAN_HANG_EVENT) += -DDP_SUPPORT_RECOVERY_NOTIFY + +ccflags-$(CONFIG_ENABLE_SIZE_OPTIMIZE) += -Os + +# DFS component +ccflags-$(CONFIG_WLAN_DFS_STATIC_MEM_ALLOC) += -DWLAN_DFS_STATIC_MEM_ALLOC +ccflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DMOBILE_DFS_SUPPORT +ifeq ($(CONFIG_WLAN_FEATURE_DFS_OFFLOAD), y) +ccflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DWLAN_DFS_FULL_OFFLOAD +else +ccflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DWLAN_DFS_PARTIAL_OFFLOAD +endif +ccflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DDFS_COMPONENT_ENABLE +ccflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DQCA_DFS_USE_POLICY_MANAGER +ccflags-$(CONFIG_WLAN_DFS_MASTER_ENABLE) += -DQCA_DFS_NOL_PLATFORM_DRV_SUPPORT +ccflags-$(CONFIG_QCA_DFS_BW_PUNCTURE) += -DQCA_DFS_BW_PUNCTURE + +ccflags-$(CONFIG_WLAN_DEBUGFS) += -DWLAN_DEBUGFS +ccflags-$(CONFIG_WLAN_DEBUGFS) += -DWLAN_DBGLOG_DEBUGFS +ccflags-$(CONFIG_WLAN_STREAMFS) += -DWLAN_STREAMFS + +ccflags-$(CONFIG_DYNAMIC_DEBUG) += -DFEATURE_MULTICAST_HOST_FW_MSGS + +ccflags-$(CONFIG_ENABLE_SMMU_S1_TRANSLATION) += -DENABLE_SMMU_S1_TRANSLATION + +#Flag to enable/disable Line number logging +ccflags-$(CONFIG_LOG_LINE_NUMBER) += -DLOG_LINE_NUMBER + +#Flag to enable/disable MTRACE feature +ccflags-$(CONFIG_ENABLE_MTRACE_LOG) += -DENABLE_MTRACE_LOG + +ccflags-$(CONFIG_FUNC_CALL_MAP) += -DFUNC_CALL_MAP + +#Flag to enable/disable Adaptive 11r feature +ccflags-$(CONFIG_ADAPTIVE_11R) += -DWLAN_ADAPTIVE_11R + +#Flag to enable/disable sae single pmk feature feature +ccflags-$(CONFIG_SAE_SINGLE_PMK) += -DWLAN_SAE_SINGLE_PMK + +#Flag to enable/disable multi client low latency feature support +ccflags-$(CONFIG_MULTI_CLIENT_LL_SUPPORT) += -DMULTI_CLIENT_LL_SUPPORT + +#Flag to enable/disable vendor handoff control feature support +ccflags-$(CONFIG_WLAN_VENDOR_HANDOFF_CONTROL) += -DWLAN_VENDOR_HANDOFF_CONTROL + +#Flag to enable/disable mscs feature +ccflags-$(CONFIG_FEATURE_MSCS) += -DWLAN_FEATURE_MSCS + +#Flag to enable NUD tracking +ccflags-$(CONFIG_WLAN_NUD_TRACKING) += -DWLAN_NUD_TRACKING + +#Flag to enable set and get disable channel list feature +ccflags-$(CONFIG_DISABLE_CHANNEL_LIST) += -DDISABLE_CHANNEL_LIST + +#Flag to enable/disable WIPS feature +ccflags-$(CONFIG_WLAN_BCN_RECV_FEATURE) += -DWLAN_BCN_RECV_FEATURE + +#Flag to enable/disable thermal mitigation +ccflags-$(CONFIG_FW_THERMAL_THROTTLE) += -DFW_THERMAL_THROTTLE + +#Flag to enable/disable LTE COEX support +ccflags-$(CONFIG_LTE_COEX) += -DLTE_COEX + +#Flag to enable/disable HOST_OPCLASS +ccflags-$(CONFIG_HOST_OPCLASS) += -DHOST_OPCLASS +ccflags-$(CONFIG_HOST_OPCLASS) += -DHOST_OPCLASS_EXT + +#Flag to enable/disable TARGET_11D_SCAN +ccflags-$(CONFIG_TARGET_11D_SCAN) += -DTARGET_11D_SCAN + +#Flag to enable/disable avoid acs frequency list feature +ccflags-$(CONFIG_SAP_AVOID_ACS_FREQ_LIST) += -DSAP_AVOID_ACS_FREQ_LIST + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +ccflags-$(CONFIG_WLAN_DYNAMIC_CVM) += -DFEATURE_WLAN_DYNAMIC_CVM + +#Flag to enable get firmware state feature +ccflags-$(CONFIG_QCACLD_FEATURE_FW_STATE) += -DFEATURE_FW_STATE + +#Flag to enable set coex configuration feature +ccflags-$(CONFIG_QCACLD_FEATURE_COEX_CONFIG) += -DFEATURE_COEX_CONFIG + +#Flag to enable MPTA helper feature +ccflags-$(CONFIG_QCACLD_FEATURE_MPTA_HELPER) += -DFEATURE_MPTA_HELPER + +#Flag to enable get hw capability +ccflags-$(CONFIG_QCACLD_FEATURE_HW_CAPABILITY) += -DFEATURE_HW_CAPABILITY + +#Flag to enable set btc chain mode feature +ccflags-$(CONFIG_QCACLD_FEATURE_BTC_CHAIN_MODE) += -DFEATURE_BTC_CHAIN_MODE + +ccflags-$(CONFIG_DATA_CE_SW_INDEX_NO_INLINE_UPDATE) += -DDATA_CE_SW_INDEX_NO_INLINE_UPDATE + +#Flag to enable Multi page memory allocation for RX descriptor pool +ccflags-$(CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC) += -DRX_DESC_MULTI_PAGE_ALLOC + +#Flag to enable SAR Safety Feature +ccflags-$(CONFIG_SAR_SAFETY_FEATURE) += -DSAR_SAFETY_FEATURE + +ccflags-$(CONFIG_CONNECTION_ROAMING_CFG) += -DCONNECTION_ROAMING_CFG +ccflags-$(CONFIG_FEATURE_SET) += -DFEATURE_SET +ccflags-$(CONFIG_WLAN_FEATURE_LL_LT_SAP) += -DWLAN_FEATURE_LL_LT_SAP + +ccflags-$(CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ) += -DWLAN_FEATURE_NEAR_FULL_IRQ +ccflags-$(CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY) += -DWLAN_FEATURE_DP_EVENT_HISTORY +ccflags-$(CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY) += -DWLAN_FEATURE_DP_RX_RING_HISTORY +ccflags-$(CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY) += -DWLAN_FEATURE_DP_MON_STATUS_RING_HISTORY +ccflags-$(CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY) += -DWLAN_FEATURE_DP_TX_DESC_HISTORY +ccflags-$(CONFIG_REO_QDESC_HISTORY) += -DREO_QDESC_HISTORY +ccflags-$(CONFIG_DP_TX_HW_DESC_HISTORY) += -DDP_TX_HW_DESC_HISTORY +ifdef CONFIG_QDF_NBUF_HISTORY_SIZE +ccflags-y += -DQDF_NBUF_HISTORY_SIZE=$(CONFIG_QDF_NBUF_HISTORY_SIZE) +endif +ccflags-$(CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG) += -DWLAN_DP_PER_RING_TYPE_CONFIG +ccflags-$(CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG) += -DWLAN_CE_INTERRUPT_THRESHOLD_CONFIG +ccflags-$(CONFIG_SAP_DHCP_FW_IND) += -DSAP_DHCP_FW_IND +ccflags-$(CONFIG_WLAN_DP_PENDING_MEM_FLUSH) += -DWLAN_DP_PENDING_MEM_FLUSH +ccflags-$(CONFIG_WLAN_SUPPORT_DATA_STALL) += -DWLAN_SUPPORT_DATA_STALL +ccflags-$(CONFIG_WLAN_SUPPORT_TXRX_HL_BUNDLE) += -DWLAN_SUPPORT_TXRX_HL_BUNDLE +ccflags-$(CONFIG_QCN7605_PCIE_SHADOW_REG_SUPPORT) += -DQCN7605_PCIE_SHADOW_REG_SUPPORT +ccflags-$(CONFIG_QCN7605_PCIE_GOLBAL_RESET_SUPPORT) += -DQCN7605_PCIE_GOLBAL_RESET_SUPPORT +ccflags-$(CONFIG_MARK_ICMP_REQ_TO_FW) += -DWLAN_DP_FEATURE_MARK_ICMP_REQ_TO_FW +ccflags-$(CONFIG_EMULATION_2_0) += -DCONFIG_KIWI_EMULATION_2_0 +ccflags-$(CONFIG_WORD_BASED_TLV) += -DCONFIG_WORD_BASED_TLV +ccflags-$(CONFIG_4_BYTES_TLV_TAG) += -DCONFIG_4_BYTES_TLV_TAG +ccflags-$(CONFIG_WLAN_SKIP_BAR_UPDATE) += -DWLAN_SKIP_BAR_UPDATE +ccflags-$(CONFIG_WLAN_TRACEPOINTS) += -DWLAN_TRACEPOINTS + +ccflags-$(CONFIG_QCACLD_FEATURE_SON) += -DFEATURE_PERPKT_INFO +ccflags-$(CONFIG_QCACLD_FEATURE_SON) += -DQCA_ENHANCED_STATS_SUPPORT +ccflags-$(CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE) += -DWLAN_FEATURE_CE_RX_BUFFER_REUSE + +CONFIG_NUM_SOC_PERF_CLUSTER ?= 1 +ccflags-y += -DNUM_SOC_PERF_CLUSTER=$(CONFIG_NUM_SOC_PERF_CLUSTER) + +ifeq ($(CONFIG_QMI_COMPONENT_ENABLE), y) +ccflags-y += -DQMI_COMPONENT_ENABLE +ifeq ($(CONFIG_QMI_WFDS), y) +ccflags-y += -DQMI_WFDS +endif +endif + +ifdef CONFIG_MAX_LOGS_PER_SEC +ccflags-y += -DWLAN_MAX_LOGS_PER_SEC=$(CONFIG_MAX_LOGS_PER_SEC) +endif + +ifeq ($(CONFIG_NON_QC_PLATFORM), y) +ccflags-y += -DWLAN_DUMP_LOG_BUF_CNT=$(CONFIG_DUMP_LOG_BUF_CNT) +endif + +ifdef CONFIG_SCHED_HISTORY_SIZE +ccflags-y += -DWLAN_SCHED_HISTORY_SIZE=$(CONFIG_SCHED_HISTORY_SIZE) +endif + +ifdef CONFIG_QDF_TIMER_MULTIPLIER_FRAC +ccflags-y += -DQDF_TIMER_MULTIPLIER_FRAC=$(CONFIG_QDF_TIMER_MULTIPLIER_FRAC) +endif + +ifdef CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE +ccflags-y += -DDP_LEGACY_MODE_CSM_DEFAULT_DISABLE=$(CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE) +endif + +ifdef CONFIG_HANDLE_RX_REROUTE_ERR +ccflags-y += -DHANDLE_RX_REROUTE_ERR +endif + +# configure log buffer size +ifdef CONFIG_CFG_NUM_DP_TRACE_RECORD +ccflags-y += -DMAX_QDF_DP_TRACE_RECORDS=$(CONFIG_CFG_NUM_DP_TRACE_RECORD) +endif + +ifdef CONFIG_CFG_NUM_HTC_CREDIT_HISTORY +ccflags-y += -DHTC_CREDIT_HISTORY_MAX=$(CONFIG_CFG_NUM_HTC_CREDIT_HISTORY) +endif + +ifdef CONFIG_CFG_NUM_WMI_EVENT_HISTORY +ccflags-y += -DWMI_EVENT_DEBUG_MAX_ENTRY=$(CONFIG_CFG_NUM_WMI_EVENT_HISTORY) +endif + +ifdef CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY +ccflags-y += -DWMI_MGMT_EVENT_DEBUG_MAX_ENTRY=$(CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY) +endif + +ifdef CONFIG_CFG_NUM_TX_RX_HISTOGRAM +ccflags-y += -DNUM_TX_RX_HISTOGRAM=$(CONFIG_CFG_NUM_TX_RX_HISTOGRAM) +endif + +ifdef CONFIG_CFG_NUM_RX_IND_RECORD +ccflags-y += -DOL_RX_INDICATION_MAX_RECORDS=$(CONFIG_CFG_NUM_RX_IND_RECORD) +endif + +ifdef CONFIG_CFG_NUM_ROAM_DEBUG_RECORD +ccflags-y += -DWLAN_ROAM_DEBUG_MAX_REC=$(CONFIG_CFG_NUM_ROAM_DEBUG_RECORD) +endif + +ifdef CONFIG_CFG_PMO_WOW_FILTERS_MAX +ccflags-y += -DPMO_WOW_FILTERS_MAX=$(CONFIG_CFG_PMO_WOW_FILTERS_MAX) +endif + +ifdef CONFIG_CFG_GTK_OFFLOAD_MAX_VDEV +ccflags-y += -DCFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV=$(CONFIG_CFG_GTK_OFFLOAD_MAX_VDEV) +endif + +ifdef CONFIG_TGT_NUM_MSDU_DESC +ccflags-y += -DCFG_TGT_NUM_MSDU_DESC=$(CONFIG_TGT_NUM_MSDU_DESC) +endif + +ifdef CONFIG_HTC_MAX_MSG_PER_BUNDLE_TX +ccflags-y += -DCFG_HTC_MAX_MSG_PER_BUNDLE_TX=$(CONFIG_HTC_MAX_MSG_PER_BUNDLE_TX) +endif + +ifdef CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV +ccflags-y += -DCFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV=$(CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV) +endif + +ifdef CONFIG_WLAN_UMAC_MLO_MAX_DEV +ccflags-y += -DWLAN_UMAC_MLO_MAX_DEV=$(CONFIG_WLAN_UMAC_MLO_MAX_DEV) +endif + +ifdef CONFIG_CFG_ROAM_OFFLOAD_MAX_VDEV +ccflags-y += -DCFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV=$(CONFIG_CFG_ROAM_OFFLOAD_MAX_VDEV) +endif + +ifdef CONFIG_CFG_MAX_PERIODIC_TX_PTRNS +ccflags-y += -DMAXNUM_PERIODIC_TX_PTRNS=$(CONFIG_CFG_MAX_PERIODIC_TX_PTRNS) +endif + +ifdef CONFIG_CFG_MAX_STA_VDEVS +ccflags-y += -DCFG_TGT_DEFAULT_MAX_STA_VDEVS=$(CONFIG_CFG_MAX_STA_VDEVS) +endif + +ifdef CONFIG_CFG_NUM_OF_ADDITIONAL_FW_PEERS +ccflags-y += -DNUM_OF_ADDITIONAL_FW_PEERS=$(CONFIG_CFG_NUM_OF_ADDITIONAL_FW_PEERS) +endif + +ifdef CONFIG_CFG_NUM_OF_TDLS_CONN_TABLE_ENTRIES +ccflags-y += -DCFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES=$(CONFIG_CFG_NUM_OF_TDLS_CONN_TABLE_ENTRIES) +endif + +ifdef CONFIG_CFG_TGT_AST_SKID_LIMIT +ccflags-y += -DCFG_TGT_AST_SKID_LIMIT=$(CONFIG_CFG_TGT_AST_SKID_LIMIT) +endif + +ifdef CONFIG_TX_RESOURCE_HIGH_TH_IN_PER +ccflags-y += -DTX_RESOURCE_HIGH_TH_IN_PER=$(CONFIG_TX_RESOURCE_HIGH_TH_IN_PER) +endif + +ifdef CONFIG_TX_RESOURCE_LOW_TH_IN_PER +ccflags-y += -DTX_RESOURCE_LOW_TH_IN_PER=$(CONFIG_TX_RESOURCE_LOW_TH_IN_PER) +endif + +CONFIG_WLAN_MAX_PSOCS ?= 1 +ccflags-y += -DWLAN_MAX_PSOCS=$(CONFIG_WLAN_MAX_PSOCS) + +CONFIG_WLAN_MAX_PDEVS ?= 1 +ccflags-y += -DWLAN_MAX_PDEVS=$(CONFIG_WLAN_MAX_PDEVS) + +ifeq ($(CONFIG_WLAN_FEATURE_11BE_MLO), y) +CONFIG_WLAN_MAX_ML_VDEVS ?= 3 +else +CONFIG_WLAN_MAX_ML_VDEVS ?= 0 +endif +ccflags-y += -DWLAN_MAX_ML_VDEVS=$(CONFIG_WLAN_MAX_ML_VDEVS) + +CONFIG_WLAN_MAX_VDEVS ?= 6 +ccflags-y += -DWLAN_MAX_VDEVS=$(CONFIG_WLAN_MAX_VDEVS) + +ifdef CONFIG_WLAN_FEATURE_11BE_MLO +CONFIG_WLAN_MAX_MLD ?= 2 +else +CONFIG_WLAN_MAX_MLD ?= 1 +endif +ccflags-y += -DWLAN_MAX_MLD=$(CONFIG_WLAN_MAX_MLD) + +ifdef CONFIG_WLAN_FEATURE_11BE_MLO +CONFIG_WLAN_MAX_ML_DEFAULT_LINK ?= 2 +else +CONFIG_WLAN_MAX_ML_DEFAULT_LINK ?= 1 +endif +ccflags-y += -DWLAN_MAX_ML_DEFAULT_LINK=$(CONFIG_WLAN_MAX_ML_DEFAULT_LINK) + +ifdef CONFIG_WLAN_FEATURE_11BE_MLO +ifndef CONFIG_WLAN_DEFAULT_REC_LINK_VALUE +CONFIG_WLAN_DEFAULT_REC_LINK_VALUE ?= 2 +endif +else +ifndef CONFIG_WLAN_DEFAULT_REC_LINK_VALUE +CONFIG_WLAN_DEFAULT_REC_LINK_VALUE ?= 2 +endif +endif +ccflags-y += -DWLAN_DEFAULT_REC_LINK_VALUE=$(CONFIG_WLAN_DEFAULT_REC_LINK_VALUE) + +ifdef CONFIG_WLAN_FEATURE_11BE_MLO +CONFIG_WLAN_MAX_ML_BSS_LINKS ?= 3 +else +CONFIG_WLAN_MAX_ML_BSS_LINKS ?= 1 +endif +ccflags-y += -DWLAN_MAX_ML_BSS_LINKS=$(CONFIG_WLAN_MAX_ML_BSS_LINKS) + +ifdef CONFIG_WLAN_FEATURE_EMLSR +CONFIG_WLAN_EMLSR_ENABLE ?= 1 +else +CONFIG_WLAN_EMLSR_ENABLE ?= 0 +endif +ccflags-y += -DWLAN_EMLSR_ENABLE=$(CONFIG_WLAN_EMLSR_ENABLE) + +#Maximum pending commands for a vdev is calculated in vdev create handler +#by WLAN_SER_MAX_PENDING_CMDS/WLAN_SER_MAX_VDEVS. For SAP case, we will need +#to accommodate 32 Pending commands to handle multiple STA sending +#deauth/disassoc at the same time and for STA vdev,4 non scan pending commands +#are supported. So calculate WLAN_SER_MAX_PENDING_COMMANDS based on the SAP +#modes supported and no of STA vdev total non scan pending queue. Reserve +#additional 3 pending commands for WLAN_SER_MAX_PENDING_CMDS_AP to account for +#other commands like hardware mode change. + +ifdef CONFIG_SIR_SAP_MAX_NUM_PEERS +CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP ?=$(CONFIG_SIR_SAP_MAX_NUM_PEERS) +else +CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP ?=32 +endif +ccflags-y += -DWLAN_SER_MAX_PENDING_CMDS_AP=$(CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP)+3 + +CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA ?= 4 +ccflags-y += -DWLAN_SER_MAX_PENDING_CMDS_STA=$(CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA) + +CONFIG_WLAN_MAX_PENDING_CMDS ?= $(CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP)*3+$(CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA)*2 + +ccflags-y += -DWLAN_SER_MAX_PENDING_CMDS=$(CONFIG_WLAN_MAX_PENDING_CMDS) + +CONFIG_WLAN_PDEV_MAX_VDEVS ?= $(CONFIG_WLAN_MAX_VDEVS) +ccflags-y += -DWLAN_PDEV_MAX_VDEVS=$(CONFIG_WLAN_PDEV_MAX_VDEVS) + +CONFIG_WLAN_PSOC_MAX_VDEVS ?= $(CONFIG_WLAN_MAX_VDEVS) +ccflags-y += -DWLAN_PSOC_MAX_VDEVS=$(CONFIG_WLAN_PSOC_MAX_VDEVS) + +CONFIG_MAX_SCAN_CACHE_SIZE ?= 500 +ccflags-y += -DMAX_SCAN_CACHE_SIZE=$(CONFIG_MAX_SCAN_CACHE_SIZE) +CONFIG_SCAN_MAX_REST_TIME ?= 0 +ccflags-y += -DSCAN_MAX_REST_TIME=$(CONFIG_SCAN_MAX_REST_TIME) +CONFIG_SCAN_MIN_REST_TIME ?= 0 +ccflags-y += -DSCAN_MIN_REST_TIME=$(CONFIG_SCAN_MIN_REST_TIME) +CONFIG_SCAN_BURST_DURATION ?= 0 +ccflags-y += -DSCAN_BURST_DURATION=$(CONFIG_SCAN_BURST_DURATION) +CONFIG_SCAN_PROBE_SPACING_TIME ?= 0 +ccflags-y += -DSCAN_PROBE_SPACING_TIME=$(CONFIG_SCAN_PROBE_SPACING_TIME) +CONFIG_SCAN_PROBE_DELAY ?= 0 +ccflags-y += -DSCAN_PROBE_DELAY=$(CONFIG_SCAN_PROBE_DELAY) +CONFIG_SCAN_MAX_SCAN_TIME ?= 30000 +ccflags-y += -DSCAN_MAX_SCAN_TIME=$(CONFIG_SCAN_MAX_SCAN_TIME) +CONFIG_SCAN_NETWORK_IDLE_TIMEOUT ?= 0 +ccflags-y += -DSCAN_NETWORK_IDLE_TIMEOUT=$(CONFIG_SCAN_NETWORK_IDLE_TIMEOUT) +CONFIG_HIDDEN_SSID_TIME ?= 0xFFFFFFFF +ccflags-y += -DHIDDEN_SSID_TIME=$(CONFIG_HIDDEN_SSID_TIME) +CONFIG_SCAN_CHAN_STATS_EVENT_ENAB ?= false +ccflags-y += -DSCAN_CHAN_STATS_EVENT_ENAB=$(CONFIG_SCAN_CHAN_STATS_EVENT_ENAB) +CONFIG_MAX_BCN_PROBE_IN_SCAN_QUEUE ?= 150 +ccflags-y += -DMAX_BCN_PROBE_IN_SCAN_QUEUE=$(CONFIG_MAX_BCN_PROBE_IN_SCAN_QUEUE) + +#CONFIG_RX_DIAG_WQ_MAX_SIZE maximum number FW diag events that can be queued in +#FW diag events work queue. Host driver will discard the all diag events after +#this limit is reached. +# +# Value 0 represents no limit and any non zero value represents the maximum +# size of the work queue. +CONFIG_RX_DIAG_WQ_MAX_SIZE ?= 1000 +ccflags-y += -DRX_DIAG_WQ_MAX_SIZE=$(CONFIG_RX_DIAG_WQ_MAX_SIZE) + +CONFIG_MGMT_DESC_POOL_MAX ?= 64 +ccflags-y += -DMGMT_DESC_POOL_MAX=$(CONFIG_MGMT_DESC_POOL_MAX) + +ifdef CONFIG_SIR_SAP_MAX_NUM_PEERS +ccflags-y += -DSIR_SAP_MAX_NUM_PEERS=$(CONFIG_SIR_SAP_MAX_NUM_PEERS) +endif + +ifdef CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV +ccflags-y += -DCFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV=$(CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV) +endif + +ifdef CONFIG_LIMIT_IPA_TX_BUFFER +ccflags-y += -DLIMIT_IPA_TX_BUFFER=$(CONFIG_LIMIT_IPA_TX_BUFFER) +endif + +ifdef CONFIG_LOCK_STATS_ON +ccflags-y += -DQDF_LOCK_STATS=1 +ccflags-y += -DQDF_LOCK_STATS_DESTROY_PRINT=0 +ifneq ($(CONFIG_ARCH_SDXPRAIRIE), y) +ccflags-y += -DQDF_LOCK_STATS_BUG_ON=1 +endif +ccflags-$(CONFIG_VCPU_TIMESTOLEN) += -DVCPU_TIMESTOLEN +ccflags-y += -DQDF_LOCK_STATS_LIST=1 +ccflags-y += -DQDF_LOCK_STATS_LIST_SIZE=256 +endif + +ifdef CONFIG_FW_THERMAL_THROTTLE +ccflags-y += -DFW_THERMAL_THROTTLE_SUPPORT +endif + +ccflags-$(CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER) += -DFEATURE_RX_LINKSPEED_ROAM_TRIGGER +#DP_RATETABLE_SUPPORT is enabled when CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER is enabled +ccflags-$(CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER) += -DDP_RATETABLE_SUPPORT + +ccflags-$(CONFIG_BAND_6GHZ) += -DCONFIG_BAND_6GHZ +ccflags-$(CONFIG_6G_SCAN_CHAN_SORT_ALGO) += -DFEATURE_6G_SCAN_CHAN_SORT_ALGO +ccflags-$(CONFIG_AFC_SUPPORT) += -DCONFIG_AFC_SUPPORT +ccflags-$(CONFIG_WLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE) += -DWLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE + +ccflags-$(CONFIG_RX_FISA) += -DWLAN_SUPPORT_RX_FISA +ccflags-$(CONFIG_RX_FISA_HISTORY) += -DWLAN_SUPPORT_RX_FISA_HIST + +ccflags-$(CONFIG_DP_SWLM) += -DWLAN_DP_FEATURE_SW_LATENCY_MGR + +ccflags-$(CONFIG_RX_DEFRAG_DO_NOT_REINJECT) += -DRX_DEFRAG_DO_NOT_REINJECT + +ccflags-$(CONFIG_HANDLE_BC_EAP_TX_FRM) += -DHANDLE_BROADCAST_EAPOL_TX_FRAME + +ccflags-$(CONFIG_MORE_TX_DESC) += -DTX_TO_NPEERS_INC_TX_DESCS + +ccflags-$(CONFIG_HASTINGS_BT_WAR) += -DHASTINGS_BT_WAR + +ccflags-$(CONFIG_HIF_DEBUG) += -DHIF_CONFIG_SLUB_DEBUG_ON +ccflags-$(CONFIG_HAL_DEBUG) += -DHAL_CONFIG_SLUB_DEBUG_ON + +ccflags-$(CONFIG_FOURTH_CONNECTION) += -DFEATURE_FOURTH_CONNECTION +ccflags-$(CONFIG_FOURTH_CONNECTION_AUTO) += -DFOURTH_CONNECTION_AUTO +ccflags-$(CONFIG_WMI_SEND_RECV_QMI) += -DWLAN_FEATURE_WMI_SEND_RECV_QMI + +ccflags-$(CONFIG_WDI3_STATS_UPDATE) += -DWDI3_STATS_UPDATE +ccflags-$(CONFIG_WDI3_STATS_BW_MONITOR) += -DWDI3_STATS_BW_MONITOR + +ccflags-$(CONFIG_IPA_P2P_SUPPORT) += -DIPA_P2P_SUPPORT + +ccflags-$(CONFIG_WLAN_CUSTOM_DSCP_UP_MAP) += -DWLAN_CUSTOM_DSCP_UP_MAP +ccflags-$(CONFIG_WLAN_SEND_DSCP_UP_MAP_TO_FW) += -DWLAN_SEND_DSCP_UP_MAP_TO_FW + +ccflags-$(CONFIG_SMMU_S1_UNMAP) += -DCONFIG_SMMU_S1_UNMAP +ccflags-$(CONFIG_HIF_CPU_PERF_AFFINE_MASK) += -DHIF_CPU_PERF_AFFINE_MASK +ccflags-$(CONFIG_HIF_CPU_CLEAR_AFFINITY) += -DHIF_CPU_CLEAR_AFFINITY + +ccflags-$(CONFIG_GENERIC_SHADOW_REGISTER_ACCESS_ENABLE) += -DGENERIC_SHADOW_REGISTER_ACCESS_ENABLE +ccflags-$(CONFIG_IPA_SET_RESET_TX_DB_PA) += -DIPA_SET_RESET_TX_DB_PA +ccflags-$(CONFIG_DEVICE_FORCE_WAKE_ENABLE) += -DDEVICE_FORCE_WAKE_ENABLE +ccflags-$(CONFIG_WINDOW_REG_PLD_LOCK_ENABLE) += -DWINDOW_REG_PLD_LOCK_ENABLE +ccflags-$(CONFIG_DUMP_REO_QUEUE_INFO_IN_DDR) += -DDUMP_REO_QUEUE_INFO_IN_DDR +ccflags-$(CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK) += -DDP_RX_REFILL_CPU_PERF_AFFINE_MASK +ccflags-$(CONFIG_WLAN_FEATURE_AFFINITY_MGR) += -DWLAN_FEATURE_AFFINITY_MGR +ccflags-$(CONFIG_FEATURE_ENABLE_CE_DP_IRQ_AFFINE) += -DFEATURE_ENABLE_CE_DP_IRQ_AFFINE +found = $(shell if grep -qF "walt_get_cpus_taken" $(srctree)/kernel/sched/walt/walt.c; then echo "yes" ;else echo "no" ;fi;) +ifeq ($(findstring yes, $(found)), yes) +ccflags-y += -DWALT_GET_CPU_TAKEN_SUPPORT +endif + +ifdef CONFIG_MAX_CLIENTS_ALLOWED +ccflags-y += -DWLAN_MAX_CLIENTS_ALLOWED=$(CONFIG_MAX_CLIENTS_ALLOWED) +endif + +ifeq ($(CONFIG_WLAN_FEATURE_RX_BUFFER_POOL), y) +ccflags-y += -DWLAN_FEATURE_RX_PREALLOC_BUFFER_POOL +ifdef CONFIG_DP_RX_BUFFER_POOL_SIZE +ccflags-y += -DDP_RX_BUFFER_POOL_SIZE=$(CONFIG_DP_RX_BUFFER_POOL_SIZE) +endif +ifdef CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES +ccflags-y += -DDP_RX_BUFFER_POOL_ALLOC_THRES=$(CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES) +endif +ifdef CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE +ccflags-y += -DDP_RX_REFILL_BUFF_POOL_SIZE=$(CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE) +endif +ifdef CONFIG_DP_RX_REFILL_THRD_THRESHOLD +ccflags-y += -DDP_RX_REFILL_THRD_THRESHOLD=$(CONFIG_DP_RX_REFILL_THRD_THRESHOLD) +endif +endif + +ccflags-$(CONFIG_DP_FT_LOCK_HISTORY) += -DDP_FT_LOCK_HISTORY + +ccflags-$(CONFIG_INTRA_BSS_FWD_OFFLOAD) += -DINTRA_BSS_FWD_OFFLOAD +ccflags-$(CONFIG_GET_DRIVER_MODE) += -DFEATURE_GET_DRIVER_MODE + +ifeq ($(CONFIG_FEATURE_IPA_PIPE_CHANGE_WDI1), y) +ccflags-y += -DFEATURE_IPA_PIPE_CHANGE_WDI1 +endif + +ccflags-$(CONFIG_WLAN_BOOTUP_MARKER) += -DWLAN_BOOTUP_MARKER +ifdef CONFIG_WLAN_PLACEMARKER_PREFIX +ccflags-y += -DWLAN_PLACEMARKER_PREFIX=\"$(CONFIG_WLAN_PLACEMARKER_PREFIX)\" +endif + +ccflags-$(CONFIG_FEATURE_STA_MODE_VOTE_LINK) += -DFEATURE_STA_MODE_VOTE_LINK +ccflags-$(CONFIG_WLAN_ENABLE_GPIO_WAKEUP) += -DWLAN_ENABLE_GPIO_WAKEUP +ccflags-$(CONFIG_WLAN_MAC_ADDR_UPDATE_DISABLE) += -DWLAN_MAC_ADDR_UPDATE_DISABLE + +ifeq ($(CONFIG_SMP), y) +ifeq ($(CONFIG_HIF_DETECTION_LATENCY_ENABLE), y) +ccflags-y += -DHIF_DETECTION_LATENCY_ENABLE +ccflags-y += -DDETECTION_TIMER_TIMEOUT=4000 +ccflags-y += -DDETECTION_LATENCY_THRESHOLD=3900 +endif +endif + +#Flags to enable/disable WDS specific features +ccflags-$(CONFIG_FEATURE_WDS) += -DFEATURE_WDS +ccflags-$(CONFIG_FEATURE_MEC) += -DFEATURE_MEC +ccflags-$(CONFIG_FEATURE_MCL_REPEATER) += -DFEATURE_MCL_REPEATER +ccflags-$(CONFIG_WDS_CONV_TARGET_IF_OPS_ENABLE) += -DWDS_CONV_TARGET_IF_OPS_ENABLE +ccflags-$(CONFIG_BYPASS_WDS_OL_OPS) += -DBYPASS_OL_OPS + +ccflags-$(CONFIG_IPA_WDI3_TX_TWO_PIPES) += -DIPA_WDI3_TX_TWO_PIPES + +ccflags-$(CONFIG_DP_TX_TRACKING) += -DDP_TX_TRACKING + +ifdef CONFIG_CHIP_VERSION +ccflags-y += -DCHIP_VERSION=$(CONFIG_CHIP_VERSION) +endif + +ccflags-$(CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET) += -DWLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET + +ccflags-$(CONFIG_SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND) += -DSHUTDOWN_WLAN_IN_SYSTEM_SUSPEND + +ifeq ($(CONFIG_WLAN_FEATURE_MCC_QUOTA), y) +ccflags-y += -DWLAN_FEATURE_MCC_QUOTA +ifdef CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA +ccflags-y += -DWLAN_MCC_MIN_CHANNEL_QUOTA=$(CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA) +endif +endif + +ccflags-$(CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF) += -DWLAN_FEATURE_PEER_TXQ_FLUSH_CONF + +ifeq ($(CONFIG_DP_HW_TX_DELAY_STATS_ENABLE), y) +ccflags-y += -DHW_TX_DELAY_STATS_ENABLE +endif + +# Config MAX SAP interface number +ifdef CONFIG_QDF_MAX_NO_OF_SAP_MODE +ccflags-y += -DQDF_MAX_NO_OF_SAP_MODE=$(CONFIG_QDF_MAX_NO_OF_SAP_MODE) +endif + +#Flags to enable/disable Dynamic WLAN interface control feature +ifeq ($(CONFIG_CNSS_HW_SECURE_DISABLE), y) +ccflags-y += -DFEATURE_CNSS_HW_SECURE_DISABLE +endif + +#DBAM feature needs COEX feature to be enabled +ifeq ($(CONFIG_FEATURE_COEX), y) +ccflags-$(CONFIG_WLAN_FEATURE_COEX_DBAM) += -DWLAN_FEATURE_DBAM_CONFIG +endif + +# Flag to enable Constrained Application Protocol feature +ccflags-$(CONFIG_WLAN_FEATURE_COAP) += -DWLAN_FEATURE_COAP + +# SSR driver dump config +ccflags-$(CONFIG_CNSS2_SSR_DRIVER_DUMP) += -DWLAN_FEATURE_SSR_DRIVER_DUMP + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# WLAN driver. Note that we must use ccflags-y here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized), y) +ccflags-y += -Wmaybe-uninitialized +ifneq (y,$(CONFIG_ARCH_MSM)) +ccflags-y += -Wframe-larger-than=4096 +endif +endif +ccflags-y += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard), y) +ccflags-y += -Wheader-guard +endif +# If the module name is not "wlan", then the define MULTI_IF_NAME to be the +# same a the QCA CHIP name. The host driver will then append MULTI_IF_NAME to +# any string that must be unique for all instances of the driver on the system. +# This allows multiple instances of the driver with different module names. +# If the module name is wlan, leave MULTI_IF_NAME undefined and the code will +# treat the driver as the primary driver. +# +# If DYNAMIC_SINGLE_CHIP is defined and MULTI_IF_NAME is undefined, which means +# there are multiple possible drivers, but only 1 driver will be loaded at +# a time(WLAN dynamic detect), no matter what the module name is, then +# host driver will only append DYNAMIC_SINGLE_CHIP to the path of +# firmware/mac/ini file. +# +# If DYNAMIC_SINGLE_CHIP & MULTI_IF_NAME defined, which means there are +# multiple possible drivers, we also can load multiple drivers together. +# And we can use DYNAMIC_SINGLE_CHIP to distinguish the ko name, and use +# MULTI_IF_NAME to make cnss2 platform driver to figure out which wlanhost +# driver attached. Moreover, as the first priority, host driver will only +# append DYNAMIC_SINGLE_CHIP to the path of firmware/mac/ini file. + +ifneq ($(DYNAMIC_SINGLE_CHIP),) +ccflags-y += -DDYNAMIC_SINGLE_CHIP=\"$(DYNAMIC_SINGLE_CHIP)\" +ifneq ($(MULTI_IF_NAME),) +ccflags-y += -DMULTI_IF_NAME=\"$(MULTI_IF_NAME)\" +endif +# +else + +ifneq ($(MODNAME), wlan) +CHIP_NAME ?= $(MODNAME) +ccflags-y += -DMULTI_IF_NAME=\"$(CHIP_NAME)\" +endif + +endif #DYNAMIC_SINGLE_CHIP + +# WLAN_HDD_ADAPTER_MAGIC must be unique for all instances of the driver on the +# system. If it is not defined, then the host driver will use the first 4 +# characters (including NULL) of MULTI_IF_NAME to construct +# WLAN_HDD_ADAPTER_MAGIC. +ifdef WLAN_HDD_ADAPTER_MAGIC +ccflags-y += -DWLAN_HDD_ADAPTER_MAGIC=$(WLAN_HDD_ADAPTER_MAGIC) +endif + +# Determine if we are building against an arm architecture host +ifeq ($(findstring arm, $(ARCH)),) + ccflags-y += -DWLAN_HOST_ARCH_ARM=0 +else + ccflags-y += -DWLAN_HOST_ARCH_ARM=1 +endif + +# Android wifi state control interface +ifneq ($(WLAN_CTRL_NAME),) +ccflags-y += -DWLAN_CTRL_NAME=\"$(WLAN_CTRL_NAME)\" +endif + +# inject some build related information +ifeq ($(CONFIG_BUILD_TAG), y) +CLD_CHECKOUT = $(shell cd "$(WLAN_ROOT)" && \ + git reflog | grep -vm1 "}: cherry-pick: " | grep -oE ^[0-f]+) +CLD_IDS = $(shell cd "$(WLAN_ROOT)" && \ + git log -50 $(CLD_CHECKOUT)~..HEAD | \ + sed -nE 's/^\s*Change-Id: (I[0-f]{10})[0-f]{30}\s*$$/\1/p' | \ + paste -sd "," -) + +CMN_CHECKOUT = $(shell cd "$(WLAN_COMMON_INC)" && \ + git reflog | grep -vm1 "}: cherry-pick: " | grep -oE ^[0-f]+) +CMN_IDS = $(shell cd "$(WLAN_COMMON_INC)" && \ + git log -50 $(CMN_CHECKOUT)~..HEAD | \ + sed -nE 's/^\s*Change-Id: (I[0-f]{10})[0-f]{30}\s*$$/\1/p' | \ + paste -sd "," -) +BUILD_TAG = "cld:$(CLD_IDS); cmn:$(CMN_IDS); dev:$(DEVNAME)" +ccflags-y += -DBUILD_TAG=\"$(BUILD_TAG)\" +endif + +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +ccflags-y += -gdwarf-4 +endif + +# Module information used by KBuild framework +obj-$(CONFIG_QCA_CLD_WLAN) += $(MODNAME).o +ifeq ($(CONFIG_WLAN_RESIDENT_DRIVER), y) +$(MODNAME)-y := $(HDD_SRC_DIR)/wlan_hdd_main_module.o +obj-$(CONFIG_QCA_CLD_WLAN) += wlan_resident.o +wlan_resident-y := $(OBJS) +else +$(MODNAME)-y := $(OBJS) +endif +OBJS_DIRS += $(dir $(OBJS)) \ + $(WLAN_COMMON_ROOT)/$(HIF_CE_DIR)/ \ + $(QDF_OBJ_DIR)/ \ + $(WLAN_COMMON_ROOT)/$(HIF_PCIE_DIR)/ \ + $(WLAN_COMMON_ROOT)/$(HIF_SNOC_DIR)/ \ + $(WLAN_COMMON_ROOT)/$(HIF_SDIO_DIR)/ +CLEAN_DIRS := $(addsuffix *.o,$(sort $(OBJS_DIRS))) \ + $(addsuffix .*.o.cmd,$(sort $(OBJS_DIRS))) +clean-files := $(CLEAN_DIRS) diff --git a/qcom/opensource/wlan/qcacld-3.0/Kconfig b/qcom/opensource/wlan/qcacld-3.0/Kconfig new file mode 100644 index 0000000000..ced4984ef9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/Kconfig @@ -0,0 +1,2156 @@ +comment "Qualcomm Atheros CLD WLAN module" + +config QCA_CLD_WLAN + tristate "Qualcomm Atheros CLD WLAN module" + default n + help + Add support for the Qualcomm Atheros CLD WLAN module + +if QCA_CLD_WLAN != n + +config WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + bool "Enable WLAN_FEATURE_NO_STA_SAP_CONCURRENCY" + default n + +config WLAN_FEATURE_NO_STA_NAN_CONCURRENCY + bool "Enable WLAN_FEATURE_NO_STA_NAN_CONCURRENCY" + default n + +config WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY + bool "Enable WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY" + default n + +config WLAN_FEATURE_NO_P2P_CONCURRENCY + bool "Enable WLAN_FEATURE_NO_P2P_CONCURRENCY" + default n + +config 160MHZ_SUPPORT + bool "Enable 160MHZ_SUPPORT" + default n + +config 64BIT_PADDR + bool "Enable 37-bit physical/bus addresses" + depends on HELIUMPLUS + default n + +config 6G_SCAN_CHAN_SORT_ALGO + bool "Enable 6G_SCAN_CHAN_SORT_ALGO" + default n + +config ADAPTIVE_11R + bool "Enable ADAPTIVE_11R" + default n + +config AGEIE_ON_SCAN_RESULTS + bool "Enable AGEIE_ON_SCAN_RESULTS" + default n + +config ALLOW_PKT_DROPPING + bool "Enable ALLOW_PKT_DROPPING" + default n + +config ANI_LEVEL_REQUEST + bool "Enable ANI_LEVEL_REQUEST" + default n + +config AR900B + bool "Enable AR900B" + default n + +config ATH_11AC_TXCOMPACT + bool "Enable ATH_11AC_TXCOMPACT" + default n + +config ATH_BUS_PM + bool "Enable ATH_BUS_PM" + default n + +config ATH_DIAG_EXT_DIRECT + bool "Enable ATH_DIAG_EXT_DIRECT" + default n + +config ATH_PERF_PWR_OFFLOAD + bool "Enable ATH_PERF_PWR_OFFLOAD" + default n + +config BAND_6GHZ + bool "Enable BAND_6GHZ" + default n + +config BERYLLIUM + bool "Enable BERYLLIUM" + default n + +config BUILD_TAG + bool "Embed tags and timestamp in wlan version" + default n + +config BUILD_TIMESTAMP + bool "Embed timestamp in wlan version" + default n + +config BUS_AUTO_SUSPEND + bool "enable CONFIG_BUS_AUTO_SUSPEND" + default n + +config CE_DISABLE_SRNG_TIMER_IRQ + bool "Enable CE_DISABLE_SRNG_TIMER_IRQ" + default n + +config CHECKSUM_OFFLOAD + bool "Enable CHECKSUM_OFFLOAD" + default n + +config CHIP_VERSION + int "Enable CHIP_VERSION" + +config CNSS_GENL_MODULE + bool "Enable CNSS_GENL_MODULE" + default n + +config CNSS_KIWI + bool "Enable CNSS_KIWI" + default n + +config CNSS_KIWI_V2 + bool "Enable CNSS_KIWI_V2" + default n + +config CNSS_PEACH + bool "Enable CNSS_PEACH" + default n + +config CNSS_PEACH_V2 + bool "Enable CNSS_PEACH_V2" + default n + +config INCLUDE_HAL_KIWI + bool "Enable INCLUDE_HAL_KIWI" + default n + +config INCLUDE_HAL_PEACH + bool "Enable INCLUDE_HAL_PEACH" + default n + +config CNSS_UTILS_MODULE + bool "Enable CNSS_UTILS_MODULE" + default n + +config CNSS_UTILS + tristate "Enable CNSS_UTILS" + default n + +config CONNECTIVITY_PKTLOG + bool "Enable CONNECTIVITY_PKTLOG" + default n + +config CONVERGED_P2P_ENABLE + bool "Enable CONVERGED_P2P_ENABLE" + default n + +config CP_STATS + bool "Enable CP_STATS" + default n + +config QCA_TARGET_IF_MLME + bool "Enable TARGET_IF MLME" + default n + +config DCS + bool "Enable DCS" + default n + +config DDP_MON_RSSI_IN_DBM + bool "Enable DDP_MON_RSSI_IN_DBM" + default n + +config DEBUG_RX_RING_BUFFER + bool "Enable DEBUG_RX_RING_BUFFER" + default n + +config DELIVERY_TO_STACK_STATUS_CHECK + bool "Enable DELIVERY_TO_STACK_STATUS_CHECK" + default n + +config DESC_DUP_DETECT_DEBUG + bool "Enable DESC_DUP_DETECT_DEBUG" + default n + +config DESC_TIMESTAMP_DEBUG_INFO + bool "Enable DESC_TIMESTAMP_DEBUG_INFO" + default n + +config DEVICE_FORCE_WAKE_ENABLE + bool "Enable DEVICE_FORCE_WAKE_ENABLE" + default n + +config DIRECT_BUF_RX_ENABLE + bool "Enable DIRECT_BUF_RX_ENABLE" + default n + +config DISABLE_CHANNEL_LIST + bool "Enable DISABLE_CHANNEL_LIST" + default n + +config DISABLE_EAPOL_INTRABSS_FWD + bool "Enable DISABLE_EAPOL_INTRABSS_FWD" + default n + +config DISABLE_STATUS_RING_TIMER_WAR + bool "Enable DISABLE_STATUS_RING_TIMER_WAR" + default n + +config DP_BE_WAR + bool "Enable DP_BE_WAR" + default n + +config DP_CON_MON_MSI_ENABLED + bool "Enable DP_CON_MON_MSI_ENABLED" + default n + +config DP_CON_MON_MSI_SKIP_SET + bool "Enable DP_CON_MON_MSI_SKIP_SET" + default n + +config DP_FEATURE_HW_COOKIE_CONVERSION + bool "Enable DP_FEATURE_HW_COOKIE_CONVERSION" + default n + +config DP_HW_COOKIE_CONVERT_EXCEPTION + bool "Enable DP_HW_COOKIE_CONVERT_EXCEPTION" + default n + +config DP_HW_TX_DELAY_STATS_ENABLE + bool "Enable DP_HW_TX_DELAY_STATS_ENABLE" + default n + +config DP_INTR_POLL_BASED + bool "Enable DP_INTR_POLL_BASED" + default n + +config DP_LFR + bool "Enable DP_LFR" + default n + +config DP_MEM_PRE_ALLOC + bool "Enable DP_MEM_PRE_ALLOC" + default n + +config DP_PKT_ADD_TIMESTAMP + bool "Enable DP_PKT_ADD_TIMESTAMP" + default n + +config DP_PKT_STATS_PER_LMAC + bool "Enable DP_PKT_STATS_PER_LMAC" + default n + +config DP_RX_BUFFER_POOL_ALLOC_THRES + int "Enable DP_RX_BUFFER_POOL_ALLOC_THRES" + +config DP_RX_BUFFER_POOL_SIZE + int "Enable DP_RX_BUFFER_POOL_SIZE" + +config DP_RX_REFILL_BUFF_POOL_SIZE + int "Enable DP_RX_REFILL_BUFF_POOL_SIZE" + +config DP_RX_REFILL_THRD_THRESHOLD + int "Enable DP_RX_REFILL_THRD_THRESHOLD" + +config DP_RX_DROP_RAW_FRM + bool "Enable DP_RX_DROP_RAW_FRM" + default n + +config DP_RX_PKT_NO_PEER_DELIVER + bool "Enable DP_RX_PKT_NO_PEER_DELIVER" + default n + +config DP_RX_REFILL_CPU_PERF_AFFINE_MASK + bool "Enable DP_RX_REFILL_CPU_PERF_AFFINE_MASK" + default n + +config DP_RX_SPECIAL_FRAME_NEED + bool "Enable DP_RX_SPECIAL_FRAME_NEED" + default n + +config DP_TRACE + bool "Enable DP_TRACE" + default n + +config DP_TRAFFIC_END_INDICATION + bool "Enable DP_TRAFFIC_END_INDICATION" + default n + +config DP_TX_COMP_RING_DESC_SANITY_CHECK + bool "Enable DP_TX_COMP_RING_DESC_SANITY_CHECK" + default n + +config DP_TX_HW_DESC_HISTORY + bool "Enable DP_TX_HW_DESC_HISTORY" + default n + +config DP_TXRX_SOC_ATTACH + bool "Enable DP_TXRX_SOC_ATTACH" + default n + +config DP_USE_REDUCED_PEER_ID_FIELD_WIDTH + bool "Enable DP_USE_REDUCED_PEER_ID_FIELD_WIDTH" + default n + +config DP_WAR_INVALID_FIRST_MSDU_FLAG + bool "Enable DP_WAR_INVALID_FIRST_MSDU_FLAG" + default n + +config DSC_DEBUG + bool "Enable DSC_DEBUG" + default n + +config DSC_TEST + bool "Enable DSC_TEST" + default n + +config DUP_RX_DESC_WAR + bool "Enable DUP_RX_DESC_WAR" + default n + +config DYNAMIC_RX_AGGREGATION + bool "Enable DYNAMIC_RX_AGGREGATION" + default n + +config EMULATION_2_0 + bool "Enable EMULATION_2_0" + default n + +config ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST + bool "Enable ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST" + default n + +config ENABLE_HAL_REG_WR_HISTORY + bool "Enable ENABLE_HAL_REG_WR_HISTORY" + default n + +config ENABLE_HAL_SOC_STATS + bool "Enable ENABLE_HAL_SOC_STATS" + default n + +config ENABLE_MTRACE_LOG + bool "Enable ENABLE_MTRACE_LOG" + default n + +config ENABLE_QDF_PTR_HASH_DEBUG + bool "Enable ENABLE_QDF_PTR_HASH_DEBUG" + default n + +config ENABLE_SMMU_S1_TRANSLATION + bool "Enable ENABLE_SMMU_S1_TRANSLATION" + default n + +config FEATURE_ACTIVE_TOS + bool "Enable FEATURE_ACTIVE_TOS" + default n + +config FEATURE_ALIGN_STATS_FROM_DP + bool "Enable FEATURE_ALIGN_STATS_FROM_DP" + default n + +config FEATURE_BECN_STATS + bool "Enable FEATURE_BECN_STATS" + default n + +config FEATURE_BSS_TRANSITION + bool "Enable FEATURE_BSS_TRANSITION" + default n + +config FEATURE_BUS_BANDWIDTH_MGR + bool "Enable FEATURE_BUS_BANDWIDTH_MGR" + default n + +config FEATURE_CLUB_LL_STATS_AND_GET_STATION + bool "Enable FEATURE_CLUB_LL_STATS_AND_GET_STATION" + default n + +config FEATURE_COEX + bool "Enable FEATURE_COEX" + default n + +config FEATURE_CONCURRENCY_MATRIX + bool "Enable FEATURE_CONCURRENCY_MATRIX" + default n + +config FEATURE_DELAYED_PEER_OBJ_DESTROY + bool "Enable FEATURE_DELAYED_PEER_OBJ_DESTROY" + default n + +config FEATURE_DENYLIST_MGR + bool "Enable FEATURE_DENYLIST_MGR" + default n + +config FEATURE_EPPING + bool "Enable FEATURE_EPPING" + default n + +config FEATURE_FORCE_WAKE + bool "Enable FEATURE_FORCE_WAKE" + default n + +config FEATURE_FW_LOG_PARSING + bool "Enable FEATURE_FW_LOG_PARSING" + default n + +config FEATURE_GPIO_CFG + bool "Enable FEATURE_GPIO_CFG" + default n + +config FEATURE_HAL_DELAYED_REG_WRITE + bool "Enable FEATURE_HAL_DELAYED_REG_WRITE" + default n + +config FEATURE_HAL_RECORD_SUSPEND_WRITE + bool "Enable FEATURE_HAL_RECORD_SUSPEND_WRITE" + default n + +config FEATURE_HIF_LATENCY_PROFILE_ENABLE + bool "Enable FEATURE_HIF_LATENCY_PROFILE_ENABLE" + default n + +config FEATURE_HTC_CREDIT_HISTORY + bool "Enable FEATURE_HTC_CREDIT_HISTORY" + default n + +config FEATURE_INTEROP_ISSUES_AP + bool "Enable FEATURE_INTEROP_ISSUES_AP" + default n + +config FEATURE_MEMDUMP_ENABLE + bool "Enable FEATURE_MEMDUMP_ENABLE" + default n + +config FEATURE_MONITOR_MODE_SUPPORT + bool "Enable FEATURE_MONITOR_MODE_SUPPORT" + default n + +config FEATURE_MSCS + bool "Enable FEATURE_MSCS" + default n + +config FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT + bool "Enable FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT" + default n + +config FEATURE_OEM_DATA + bool "Enable FEATURE_OEM_DATA" + default n + +config FEATURE_OTA_TEST + bool "Enable FEATURE_OTA_TEST" + default n + +config FEATURE_P2P_LISTEN_OFFLOAD + bool "Enable FEATURE_P2P_LISTEN_OFFLOAD" + default n + +config FEATURE_RADAR_HISTORY + bool "Enable FEATURE_RADAR_HISTORY" + default n + +config FEATURE_ROAM_DEBUG + bool "Enable FEATURE_ROAM_DEBUG" + default n + +config FEATURE_RSSI_MONITOR + bool "Enable FEATURE_RSSI_MONITOR" + default n + +config FEATURE_RX_LINKSPEED_ROAM_TRIGGER + bool "Enable FEATURE_RX_LINKSPEED_ROAM_TRIGGER" + default n + +config FEATURE_SAP_COND_CHAN_SWITCH + bool "Enable FEATURE_SAP_COND_CHAN_SWITCH" + default n + +config FEATURE_SAR_LIMITS + bool "Enable FEATURE_SAR_LIMITS" + default n + +config FEATURE_SET + bool "Enable FEATURE_SET" + default n + +config FEATURE_STATION_INFO + bool "Enable FEATURE_STATION_INFO" + default n + +config FEATURE_STATS_EXT + bool "Enable FEATURE_STATS_EXT" + default n + +config FEATURE_STATS_EXT_V2 + bool "Enable FEATURE_STATS_EXT_V2" + default n + +config FEATURE_TSO + bool "Enable TCP Segmentation Offload" + default n + +config FEATURE_TSO_DEBUG + bool "Enable TCP Segmentation Offload with debug" + depends on FEATURE_TSO + default n + +config FEATURE_TSO_STATS + bool "Enable FEATURE_TSO_STATS" + default n + +config FEATURE_TX_POWER + bool "Enable FEATURE_TX_POWER" + default n + +config FEATURE_UNIT_TEST_SUSPEND + bool "Enable FEATURE_UNIT_TEST_SUSPEND" + default n + +config FEATURE_VDEV_OPS_WAKELOCK + bool "Enable FEATURE_VDEV_OPS_WAKELOCK" + default n + +config FEATURE_WLAN_D0WOW + bool "Enable FEATURE_WLAN_D0WOW" + default n + +config FEATURE_WLAN_LPHB + bool "Enable FEATURE_WLAN_LPHB" + default n + +config FEATURE_WLAN_PRE_CAC + bool "Enable FEATURE_WLAN_PRE_CAC" + default n + +config FEATURE_WLAN_RA_FILTERING + bool "Enable FEATURE_WLAN_RA_FILTERING" + default n + +config FEATURE_WLAN_SCAN_PNO + bool "Enable FEATURE_WLAN_SCAN_PNO" + default n + +config WALT_GET_CPU_TAKEN_SUPPORT + bool "enable WALT_GET_CPU_TAKEN_SUPPORT" + default n + +config FEATURE_WLAN_WAPI + bool "Enable FEATURE_WLAN_WAPI" + default n + +config FEATURE_WLM_STATS + bool "Enable FEATURE_WLM_STATS" + default n + +config FIX_TXDMA_LIMITATION + bool "Enable FIX_TXDMA_LIMITATION" + default n + +config FOURTH_CONNECTION + bool "Enable FOURTH_CONNECTION" + default n + +config FW_THERMAL_THROTTLE + bool "Enable FW_THERMAL_THROTTLE" + default n + +config GET_DRIVER_MODE + bool "Enable GET_DRIVER_MODE" + default n + +config GTK_OFFLOAD + bool "Enable GTK_OFFLOAD" + default n + +config HAL_DEBUG + bool "Enable HAL_DEBUG" + default n + +config HAL_DISABLE_NON_BA_2K_JUMP_ERROR + bool "Enable HAL_DISABLE_NON_BA_2K_JUMP_ERROR" + default n + +config HANDLE_BC_EAP_TX_FRM + bool "Enable HANDLE_BC_EAP_TX_FRM" + default n + +config HANDLE_RX_REROUTE_ERR + bool "Enable HANDLE_RX_REROUTE_ERR" + default n + +config HASTINGS_BT_WAR + bool "Enable HASTINGS_BT_WAR" + default n + +config HDD_INIT_WITH_RTNL_LOCK + bool "Enable HDD_INIT_WITH_RTNL_LOCK" + default n + +config HELIUMPLUS + bool "Enable Beeliner based descriptor structures for Helium" + default n + +config HIF_CE_DEBUG_DATA_BUF + bool "Enable HIF_CE_DEBUG_DATA_BUF" + default n + +config HIF_CPU_PERF_AFFINE_MASK + bool "Enable HIF_CPU_PERF_AFFINE_MASK" + default n + +config HIF_DEBUG + bool "Enable HIF_DEBUG" + default n + +config HIF_PCI + bool "Enable HIF_PCI" + default n + +config HIF_REG_WINDOW_SUPPORT + bool "Enable HIF_REG_WINDOW_SUPPORT" + default n + +config HOST_OPCLASS + bool "Enable HOST_OPCLASS" + default n + +config HTT_PADDR64 + bool "Enable HTT_PADDR64" + default n + +config ICMP_DISABLE_PS + bool "Enable ICMP packet disable powersave feature" + default n + +config IPA_OFFLOAD + bool "Enable IPA_OFFLOAD" + default n + +config IPA_OPT_WIFI_DP + bool "Enable IPA_OPT_WIFI_DP" + default n + +config IPA_SET_RESET_TX_DB_PA + bool "Enable IPA_SET_RESET_TX_DB_PA" + default n + +config KIWI_HEADERS_DEF + bool "Enable KIWI_HEADERS_DEF" + default n + +config LEAK_DETECTION + bool "Enable LEAK_DETECTION" + default n + +config LFR_SUBNET_DETECTION + bool "Enable LFR Subnet Change Detection" + default n + +config LINUX_QCMBR + bool "Enable LINUX_QCMBR" + default n + +config LITTLE_ENDIAN + bool "Enable LITTLE_ENDIAN" + default n + +config LL_DP_SUPPORT + bool "Enable LL_DP_SUPPORT" + default n + +config LOCK_STATS_ON + bool "Enable LOCK_STATS_ON" + default n + +config LTE_COEX + bool "Enable LTE_COEX" + default n + +config MARK_ICMP_REQ_TO_FW + bool "Enable MARK_ICMP_REQ_TO_FW" + default n + +config MAX_ALLOC_PAGE_SIZE + bool "Enable MAX_ALLOC_PAGE_SIZE" + default n + +config ENABLE_MAX_LOGS_PER_SEC + bool "Enable ENABLE_MAX_LOGS_PER_SEC" + default n + +config MAX_LOGS_PER_SEC + int "Enable MAX_LOGS_PER_SEC" + +config MCC_TO_SCC_SWITCH + bool "Enable MCC to SCC Switch Logic" + default n + +config MON_ENABLE_DROP_FOR_MAC + bool "Enable MON_ENABLE_DROP_FOR_MAC" + default n + +config MON_ENABLE_DROP_FOR_NON_MON_PMAC + bool "Enable MON_ENABLE_DROP_FOR_NON_MON_PMAC" + default n + +config MORE_TX_DESC + bool "Enable MORE_TX_DESC" + default n + +config MULTI_CLIENT_LL_SUPPORT + bool "Enable MULTI_CLIENT_LL_SUPPORT" + default n + +config NAN_CONVERGENCE + bool "Enable NAN_CONVERGENCE feature" + default n + +config NO_RX_PKT_HDR_TLV + bool "Enable NO_RX_PKT_HDR_TLV" + default n + +config OBSS_PD + bool "Enable OBSS_PD" + default n + +config OFDM_SCRAMBLER_SEED + bool "Enable OFDM_SCRAMBLER_SEED" + default n + +config PCI_LINK_STATUS_SANITY + bool "Enable PCI_LINK_STATUS_SANITY" + default n + +config PCIE_GEN_SWITCH + bool "Enable PCIE_GEN_SWITCH" + default n + +config PEER_PROTECTED_ACCESS + bool "Enable PEER_PROTECTED_ACCESS" + default n + +config PKTLOG_HAS_SPECIFIC_DATA + bool "Enable PKTLOG_HAS_SPECIFIC_DATA" + default n + +config PLD_PCIE_CNSS_FLAG + bool "Enable PLD_PCIE_CNSS_FLAG" + default n + +config PLD_PCIE_INIT_FLAG + bool "Enable PLD_PCIE_INIT_FLAG" + default n + +config POWER_MANAGEMENT_OFFLOAD + bool "Enable POWER_MANAGEMENT_OFFLOAD" + default n + +config PRIMA_WLAN_OKC + bool "Enable the Prima WLAN Opportunistic Key Caching feature" + default n + +config PTT_SOCK_SVC_ENABLE + bool "Enable PTT_SOCK_SVC_ENABLE" + default n + +config QCA_DFS_BW_PUNCTURE + bool "Enable QCA_DFS_BW_PUNCTURE" + default n + +config QCA_DMA_PADDR_CHECK + bool "Enable dma memory addr check" + +config QCA_GET_TSF_VIA_REG + bool "Enable QCA_GET_TSF_VIA_REG" + default n + +config QCA_MONITOR_PKT_SUPPORT + bool "Enable QCA_MONITOR_PKT_SUPPORT" + default n + +config QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES + bool "Enable QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES" + default n + +config QCA_SUPPORT_TX_THROTTLE + bool "Enable QCA_SUPPORT_TX_THROTTLE" + default n + +config QCA_WIFI_FTM + bool "Enable QCA_WIFI_FTM" + default n + +config QCA_WIFI_FTM_NL80211 + bool "Enable QCA_WIFI_FTM_NL80211" + depends on NL80211_TESTMODE + default n + +config QCA_WIFI_KIWI + bool "Enable QCA_WIFI_KIWI" + default n + +config QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT + bool "Enable QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT" + default n + +config QCA_WIFI_QCA8074 + bool "Enable QCA_WIFI_QCA8074" + default n + +config QCA_WIFI_QCA8074_VP + bool "Enable QCA_WIFI_QCA8074_VP" + default n + +config QCACLD_FEATURE_APF + bool "Enable QCACLD_FEATURE_APF" + default n + +config QCACLD_FEATURE_FW_STATE + bool "Enable QCACLD_FEATURE_FW_STATE" + default n + +config QCACLD_FEATURE_GAP_LL_PS_MODE + bool "Enable QCACLD_FEATURE_GAP_LL_PS_MODE" + default n + +config QCACLD_FEATURE_GREEN_AP + bool "Enable Green AP feature" + default n + +config QCACLD_FEATURE_NAN + bool "Enable NAN feature" + default n + +config QCACLD_RX_DESC_MULTI_PAGE_ALLOC + bool "Enable QCACLD_RX_DESC_MULTI_PAGE_ALLOC" + default n + +config QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT + bool "Enable QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT" + default n + +config QCACLD_WLAN_LFR2 + bool "Enable the WLAN Legacy Fast Roaming feature Version 2" + default n + +config QCACLD_WLAN_LFR3 + bool "Enable the WLAN Legacy Fast Roaming feature Version 3" + default n + +config QCOM_ESE + bool "Enable QCOM_ESE" + default n + +config QCOM_LTE_COEX + bool "Enable QCOM LTE Coex feature" + default n + +config QCOM_TDLS + bool "Enable TDLS feature" + default n + +config QCOM_VOWIFI_11R + bool "Enable Fast Transition (11r) feature" + default n + +config QDF_NBUF_HISTORY_SIZE + int "Enable QDF_NBUF_HISTORY_SIZE" + +config QDF_TEST + bool "Enable QDF_TEST" + default n + +config QMI_SUPPORT + bool "Enable QMI_SUPPORT" + default n + +config REG_CLIENT + bool "Enable REG_CLIENT" + default n + +config REGISTER_OP_DEBUG + bool "Enable REGISTER_OP_DEBUG" + default n + +config REMOVE_PKT_LOG + bool "Enable REMOVE_PKT_LOG" + default n + +config REO_DESC_DEFER_FREE + bool "Enable REO_DESC_DEFER_FREE" + default n + +config REO_QDESC_HISTORY + bool "Enable REO_QDESC_HISTORY" + default n + +config RPS + bool "enable CONFIG_QCA_CONFIG_RPS" + default n + +config RX_DEFRAG_DO_NOT_REINJECT + bool "Enable RX_DEFRAG_DO_NOT_REINJECT" + default n + +config RX_DESC_DEBUG_CHECK + bool "Enable RX_DESC_DEBUG_CHECK" + default n + +config RX_DESC_SANITY_WAR + bool "Enable RX_DESC_SANITY_WAR" + default n + +config RX_FISA + bool "Enable RX_FISA" + default n + +config RX_HASH_DEBUG + bool "Enable RX_HASH_DEBUG" + default n + +config RX_OL + bool "Enable RX_OL" + default n + +config RXDMA_ERR_PKT_DROP + bool "Enable RXDMA_ERR_PKT_DROP" + default n + +config SAE_SINGLE_PMK + bool "Enable SAE_SINGLE_PMK" + default n + +config SAP_AVOID_ACS_FREQ_LIST + bool "Enable SAP_AVOID_ACS_FREQ_LIST" + default n + +config SAP_DHCP_FW_IND + bool "Enable SAP_DHCP_FW_IND" + default n + +config SAR_SAFETY_FEATURE + bool "Enable SAR_SAFETY_FEATURE" + default n + +config SCALE_INCLUDES + bool "Enable SCALE_INCLUDES" + default n + +config ENABLE_SCHED_HISTORY_SIZE + bool "Enable ENABLE_SCHED_HISTORY_SIZE" + default n + +config SCHED_HISTORY_SIZE + int "Enable SCHED_HISTORY_SIZE" + +config SERIALIZE_QUEUE_SETUP + bool "Enable SERIALIZE_QUEUE_SETUP" + default n + +config SHADOW_V3 + bool "Enable SHADOW_V3" + default n + +config SMMU_S1_UNMAP + bool "Enable SMMU_S1_UNMAP" + default n + +config SMP + bool "enable CONFIG_SMP" + default n + +config SOFTAP_CHANNEL_RANGE + bool "Enable SOFTAP_CHANNEL_RANGE" + default n + +config SUPPORT_11AX + bool "Enable SUPPORT_11AX" + default n + +config SYSTEM_PM_CHECK + bool "Enable SYSTEM_PM_CHECK" + default n + +config TALLOC_DEBUG + bool "Enable TALLOC_DEBUG" + default n + +config TARGET_11D_SCAN + bool "Enable TARGET_11D_SCAN" + default n + +config TARGET_RAMDUMP_AFTER_KERNEL_PANIC + bool "Enable TARGET_RAMDUMP_AFTER_KERNEL_PANIC" + default n + +config THERMAL_STATS_SUPPORT + bool "Enable THERMAL_STATS_SUPPORT" + default n + +config TRACE_RECORD_FEATURE + bool "Enable TRACE_RECORD_FEATURE" + default n + +config TSO_DEBUG_LOG_ENABLE + bool "Enable TSO_DEBUG_LOG_ENABLE" + default n + +config TX_ADDR_INDEX_SEARCH + bool "Enable TX_ADDR_INDEX_SEARCH" + default n + +config TX_MULTI_TCL + bool "Enable TX_MULTI_TCL" + default n + +config TX_MULTIQ_PER_AC + bool "Enable TX_MULTIQ_PER_AC" + default n + +config TX_PER_PDEV_DESC_POOL + bool "Enable TX_PER_PDEV_DESC_POOL" + default n + +config TX_TID_OVERRIDE + bool "Enable TX_TID_OVERRIDE" + default n + +config UNIT_TEST + bool "Enable UNIT_TEST" + default n + +config VERBOSE_DEBUG + bool "Enable VERBOSE_DEBUG" + default n + +config WAPI_BIG_ENDIAN + bool "Enable WAPI_BIG_ENDIAN" + default n + +config WCNSS_MEM_PRE_ALLOC_MODULE + bool "Enable WCNSS_MEM_PRE_ALLOC_MODULE" + default n + +config WCNSS_MEM_PRE_ALLOC + tristate "Enable WCNSS_MEM_PRE_ALLOC" + default n + +config WDI_EVENT_ENABLE + bool "Enable WDI_EVENT_ENABLE" + default n + +config WDI3_IPA_OVER_GSI + bool "Enable WDI3_IPA_OVER_GSI" + default n + +config WIFI_MONITOR_SUPPORT + bool "Enable WIFI_MONITOR_SUPPORT" + default n + +config WIFI_POS_CONVERGED + bool "Enable WIFI_POS_CONVERGED" + default n + +config WIFI_POS_PASN + bool "Enable WIFI_POS_PASN" + default n + +config WINDOW_REG_PLD_LOCK_ENABLE + bool "Enable WINDOW_REG_PLD_LOCK_ENABLE" + default n + +config WLAN_BCN_RECV_FEATURE + bool "Enable WLAN_BCN_RECV_FEATURE" + default n + +config WLAN_BMISS + bool "Enable WLAN_BMISS" + default n + +config WLAN_CE_INTERRUPT_THRESHOLD_CONFIG + bool "Enable WLAN_CE_INTERRUPT_THRESHOLD_CONFIG" + default n + +config WLAN_CFR_ENABLE + bool "Enable WLAN_CFR_ENABLE" + default n + +config WLAN_CLD_DEV_PM_QOS + bool "Enable WLAN_CLD_DEV_PM_QOS" + default n + +config WLAN_CLD_PM_QOS + bool "Enable WLAN_CLD_PM_QOS" + default n + +config WLAN_CONV_SPECTRAL_ENABLE + bool "Enable WLAN_CONV_SPECTRAL_ENABLE" + default n + +config WLAN_CUSTOM_DSCP_UP_MAP + bool "Enable WLAN_CUSTOM_DSCP_UP_MAP" + default n + +config WLAN_DEBUG_CRASH_INJECT + bool "Enable WLAN_DEBUG_CRASH_INJECT" + default n + +config WLAN_DEBUG_LINK_VOTE + bool "Enable WLAN_DEBUG_LINK_VOTE" + default n + +config WLAN_DEBUG_VERSION + bool "Enable WLAN_DEBUG_VERSION" + default n + +config WLAN_DEBUGFS + bool "Enable WLAN_DEBUGFS" + depends on DEBUG_FS + default n + +config WLAN_DFS_MASTER_ENABLE + bool "Enable WLAN_DFS_MASTER_ENABLE" + default n + +config WLAN_DFS_STATIC_MEM_ALLOC + bool "Enable WLAN_DFS_STATIC_MEM_ALLOC" + default n + +config WLAN_DIAG_VERSION + bool "Enable WLAN_DIAG_VERSION" + default n + +config WLAN_DISABLE_EXPORT_SYMBOL + bool "Enable WLAN_DISABLE_EXPORT_SYMBOL" + default n + +config WLAN_MULTI_CHIP_SUPPORT + bool "Enable WLAN_MULTI_CHIP_SUPPORT" + select WLAN_DISABLE_EXPORT_SYMBOL + default n + +config WLAN_DL_MODES + bool "Enable WLAN_DL_MODES" + default n + +config WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG + bool "Enable WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG" + default n + +config WLAN_DP_DISABLE_TCL_STATUS_SRNG + bool "Enable WLAN_DP_DISABLE_TCL_STATUS_SRNG" + default n + +config WLAN_DP_PENDING_MEM_FLUSH + bool "Enable WLAN_DP_PENDING_MEM_FLUSH" + default n + +config WLAN_DP_PER_RING_TYPE_CONFIG + bool "Enable WLAN_DP_PER_RING_TYPE_CONFIG" + default n + +config WLAN_DP_SRNG_USAGE_WM_TRACKING + bool "Enable WLAN_DP_SRNG_USAGE_WM_TRACKING" + default n + +config WLAN_DYNAMIC_CVM + bool "Enable WLAN_DYNAMIC_CVM" + default n + +config WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + bool "Enable WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY" + default n + +config WLAN_ENH_CFR_ENABLE + bool "Enable WLAN_ENH_CFR_ENABLE" + default n + +config WLAN_FASTPATH + bool "Enable fastpath for datapackets" + default n + +config WLAN_FEATURE_11AX + bool "Enable 11AX(High Efficiency) feature" + default n + +config WLAN_FEATURE_11BE + bool "Enable WLAN_FEATURE_11BE" + default n + +config WLAN_FEATURE_11BE_MLO + bool "Enable WLAN_FEATURE_11BE_MLO" + default n + +config WLAN_HDD_MULTI_VDEV_SINGLE_NDEV + bool "Enable WLAN_HDD_MULTI_VDEV_SINGLE_NDEV" + default n + +config WLAN_FEATURE_11W + bool "Enable the WLAN 802.11w Protected Management Frames feature" + default n + +config WLAN_FEATURE_ACTION_OUI + bool "Enable WLAN_FEATURE_ACTION_OUI" + default n + +config WLAN_FEATURE_BIG_DATA_STATS + bool "Enable WLAN_FEATURE_BIG_DATA_STATS" + default n + +config WLAN_FEATURE_CAL_FAILURE_TRIGGER + bool "Enable WLAN_FEATURE_CAL_FAILURE_TRIGGER" + default n + +config WLAN_FEATURE_COAP + bool "Enable WLAN_FEATURE_COAP" + default n + +config WLAN_FEATURE_COEX_DBAM + bool "Enable WLAN_FEATURE_COEX_DBAM" + default n + +config WLAN_FEATURE_DFS_OFFLOAD + bool "Enable dfs offload feature" + default n + +config WLAN_FEATURE_DISA + bool "Enable DISA certification feature" + default n + +config WLAN_FEATURE_DP_BUS_BANDWIDTH + bool "Enable WLAN_FEATURE_DP_BUS_BANDWIDTH" + default n + +config WLAN_FEATURE_DP_CFG_EVENT_HISTORY + bool "Enable WLAN_FEATURE_DP_CFG_EVENT_HISTORY" + default n + +config WLAN_FEATURE_DP_EVENT_HISTORY + bool "Enable WLAN_FEATURE_DP_EVENT_HISTORY" + default n + +config WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY + bool "Enable WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY" + default n + +config WLAN_FEATURE_DP_RX_RING_HISTORY + bool "Enable WLAN_FEATURE_DP_RX_RING_HISTORY" + default n + +config WLAN_FEATURE_DP_RX_THREADS + bool "Enable WLAN_FEATURE_DP_RX_THREADS" + default n + +config WLAN_FEATURE_DP_TX_DESC_HISTORY + bool "Enable WLAN_FEATURE_DP_TX_DESC_HISTORY" + default n + +config WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE + bool "Enable WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE" + default n + +config WLAN_FEATURE_ELNA + bool "Enable WLAN_FEATURE_ELNA" + default n + +config WLAN_FEATURE_FILS + bool "Enable FILS feature" + default n + +config WLAN_FEATURE_FIPS + bool "Enable FIPS certification feature" + default n + +config WLAN_FEATURE_LL_LT_SAP + bool "Enable Low latency low throughput SAP feature" + default n + +config WLAN_FEATURE_GET_USABLE_CHAN_LIST + bool "Enable WLAN_FEATURE_GET_USABLE_CHAN_LIST" + default n + +config WLAN_FEATURE_ICMP_OFFLOAD + bool "Enable WLAN_FEATURE_ICMP_OFFLOAD" + default n + +config WLAN_FEATURE_IGMP_OFFLOAD + bool "Enable WLAN_FEATURE_IGMP_OFFLOAD" + default n + +config WLAN_FEATURE_LINK_LAYER_STATS + bool "Enable WLAN_FEATURE_LINK_LAYER_STATS" + default n + +config WLAN_FEATURE_LPSS + bool "Enable the WLAN LPSS feature" + default n + +config WLAN_FEATURE_LRO_CTX_IN_CB + bool "Enable WLAN_FEATURE_LRO_CTX_IN_CB" + default n + +config WLAN_FEATURE_MBSSID + bool "Enable WLAN_FEATURE_MBSSID" + default n + +config WLAN_FEATURE_MCC_QUOTA + bool "Enable WLAN_FEATURE_MCC_QUOTA" + default n + +config WLAN_FEATURE_MDNS_OFFLOAD + bool "Enable WLAN_FEATURE_MDNS_OFFLOAD" + default n + +config WLAN_FEATURE_MEDIUM_ASSESS + bool "Enable WLAN_FEATURE_MEDIUM_ASSESS" + default n + +config WLAN_FEATURE_MIB_STATS + bool "Enable WLAN_FEATURE_MIB_STATS" + depends on WLAN_DEBUGFS + default n + +config WLAN_FEATURE_NEAR_FULL_IRQ + bool "Enable WLAN_FEATURE_NEAR_FULL_IRQ" + default n + +config WLAN_FEATURE_P2P_DEBUG + bool "Enable WLAN_FEATURE_P2P_DEBUG" + default n + +config WLAN_FEATURE_P2P_P2P_STA + bool "Enable WLAN_FEATURE_P2P_P2P_STA" + default n + +config WLAN_FEATURE_PACKET_FILTERING + bool "Enable WLAN_FEATURE_PACKET_FILTERING" + default n + +config WLAN_FEATURE_PEER_TXQ_FLUSH_CONF + bool "Enable WLAN_FEATURE_PEER_TXQ_FLUSH_CONF" + default n + +config WLAN_FEATURE_ROAM_INFO_STATS + bool "Enable WLAN_FEATURE_ROAM_INFO_STATS" + default n + +config WLAN_FEATURE_RX_BUFFER_POOL + bool "Enable WLAN_FEATURE_RX_BUFFER_POOL" + default n + +config WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT + bool "Enable WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT" + default n + +config WLAN_FEATURE_SAE + bool "Enable WLAN_FEATURE_SAE" + default n + +config WLAN_FEATURE_SAP_ACS_OPTIMIZE + bool "Enable WLAN_FEATURE_SAP_ACS_OPTIMIZE" + default n + +config FEATURE_WLAN_GC_SKIP_JOIN + bool "enable CONFIG_FEATURE_WLAN_GC_SKIP_JOIN" + default n + +config WLAN_FEATURE_SARV1_TO_SARV2 + bool "Enable conversion of SAR v1 to v2 feature" + default n + +config WLAN_FEATURE_SR + bool "Enable WLAN_FEATURE_SR" + default n + +config WLAN_FEATURE_TWT + bool "Enable WLAN_FEATURE_TWT" + default n + +config WLAN_FEATURE_WMI_DIAG_OVER_CE7 + bool "Enable WLAN_FEATURE_WMI_DIAG_OVER_CE7" + default n + +config WLAN_FREQ_LIST + bool "Enable WLAN_FREQ_LIST" + default n + +config WLAN_FW_OFFLOAD + bool "Enable WLAN_FW_OFFLOAD" + default n + +config WLAN_GTX_BW_MASK + bool "Enable WLAN_GTX_BW_MASK" + default n + +config WLAN_HANG_EVENT + bool "Enable WLAN_HANG_EVENT" + default n + +config WLAN_LOG_DEBUG + bool "Enable WLAN_LOG_DEBUG" + default n + +config WLAN_LOG_ENTER + bool "Enable WLAN_LOG_ENTER" + default n + +config WLAN_LOG_ERROR + bool "Enable WLAN_LOG_ERROR" + default n + +config WLAN_LOG_EXIT + bool "Enable WLAN_LOG_EXIT" + default n + +config WLAN_LOG_FATAL + bool "Enable WLAN_LOG_FATAL" + default n + +config WLAN_LOG_INFO + bool "Enable WLAN_LOG_INFO" + default n + +config WLAN_LOG_WARN + bool "Enable WLAN_LOG_WARN" + default n + +config WLAN_LOGGING_SOCK_SVC + bool "Enable WLAN_LOGGING_SOCK_SVC" + default n + +config WLAN_LRO + bool "Enable Large Receive Offload" + depends on HELIUMPLUS + depends on INET_LRO + default n + +config WLAN_MWS_INFO_DEBUGFS + bool "Enable WLAN_MWS_INFO_DEBUGFS" + depends on WLAN_DEBUGFS + default n + +config WLAN_NAPI + bool "Enable NAPI - datapath rx" + default n + +config WLAN_NAPI_DEBUG + bool "Enable debug logging on NAPI" + depends on WLAN_NAPI + default n + +config WLAN_NS_OFFLOAD + bool "Enable WLAN_NS_OFFLOAD" + default n + +config WLAN_NUD_TRACKING + bool "Enable WLAN_NUD_TRACKING" + default n + +config WLAN_OBJMGR_DEBUG + bool "Enable WLAN Obj Mgr Debug services" + default n + +config WLAN_OBJMGR_REF_ID_TRACE + bool "Enable WLAN_OBJMGR_REF_ID_TRACE" + default n + +config WLAN_OFFLOAD_PACKETS + bool "Enable offload packets feature" + default n + +config WLAN_OPEN_P2P_INTERFACE + bool "Enable WLAN_OPEN_P2P_INTERFACE" + default n + +config WLAN_PDEV_VDEV_SEND_MULTI_PARAM + bool "Enable WLAN_PDEV_VDEV_SEND_MULTI_PARAM" + default n + +config WLAN_PMO_ENABLE + bool "Enable WLAN_PMO_ENABLE" + default n + +config WLAN_POLICY_MGR_ENABLE + bool "Enable WLAN_POLICY_MGR_ENABLE" + default n + +config WLAN_POWER_DEBUG + bool "Enable WLAN_POWER_DEBUG" + default n + +config WLAN_REASSOC + bool "Enable WLAN_REASSOC" + default n + +config WLAN_RECORD_RX_PADDR + bool "Enable WLAN_RECORD_RX_PADDR" + default n + +config WLAN_RX_MON_PARSE_CMN_USER_INFO + bool "Enable WLAN_RX_MON_PARSE_CMN_USER_INFO" + default n + +config WLAN_SCAN_DISABLE + bool "Enable WLAN_SCAN_DISABLE" + default n + +config WLAN_SKIP_BAR_UPDATE + bool "Enable WLAN_SKIP_BAR_UPDATE" + default n + +config WLAN_SPECTRAL_ENABLE + bool "Enable WLAN_SPECTRAL_ENABLE" + default n + +config WLAN_STREAMFS + bool "Enable WLAN_STREAMFS" + depends on RELAY + default n + +config WLAN_SUPPORT_DATA_STALL + bool "Enable WLAN_SUPPORT_DATA_STALL" + default n + +config WLAN_SYNC_TSF + bool "Enable QCOM sync multi devices tsf feature" + default n + +config WLAN_SYNC_TSF_PLUS + bool "Enable WLAN_SYNC_TSF_PLUS" + default n + +config WLAN_SYNC_TSF_TIMER + bool "Enable WLAN_SYNC_TSF_TIMER" + default n + +config WLAN_SYSFS + bool "Enable WLAN_SYSFS" + depends on SYSFS + default n + +config WLAN_SYSFS_CHANNEL + bool "Enable WLAN_SYSFS_CHANNEL" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_CONNECT_INFO + bool "Enable WLAN_SYSFS_CONNECT_INFO" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_DCM + bool "Enable WLAN_SYSFS_DCM" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_DFSNOL + bool "Enable WLAN_SYSFS_DFSNOL" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_DP_STATS + bool "Enable WLAN_SYSFS_DP_STATS" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_DP_TRACE + bool "Enable WLAN_SYSFS_DP_TRACE" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_EHT_RATE + bool "Enable WLAN_SYSFS_EHT_RATE" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_FW_MODE_CFG + bool "Enable WLAN_SYSFS_FW_MODE_CFG" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_HE_BSS_COLOR + bool "Enable WLAN_SYSFS_HE_BSS_COLOR" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_LOG_BUFFER + bool "Enable WLAN_SYSFS_LOG_BUFFER" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_MEM_STATS + bool "Enable WLAN_SYSFS_MEM_STATS" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_MONITOR_MODE_CHANNEL + bool "Enable WLAN_SYSFS_MONITOR_MODE_CHANNEL" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_RADAR + bool "Enable WLAN_SYSFS_RADAR" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_RANGE_EXT + bool "Enable WLAN_SYSFS_RANGE_EXT" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_RTS_CTS + bool "Enable WLAN_SYSFS_RTS_CTS" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_SCAN_CFG + bool "Enable WLAN_SYSFS_SCAN_CFG" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_STA_INFO + bool "Enable WLAN_SYSFS_STA_INFO" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_STATS + bool "Enable WLAN_SYSFS_STATS" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_TDLS_PEERS + bool "Enable WLAN_SYSFS_TDLS_PEERS" + depends on WLAN_SYSFS + depends on QCOM_TDLS + default n + +config WLAN_SYSFS_TEMPERATURE + bool "Enable WLAN_SYSFS_TEMPERATURE" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_TX_STBC + bool "Enable WLAN_SYSFS_TX_STBC" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_WLAN_DBG + bool "Enable WLAN_SYSFS_WLAN_DBG" + depends on WLAN_SYSFS + default n + +config WLAN_SYSFS_BITRATES + bool "enable WLAN_SYSFS_BITRATES" + depends on WLAN_SYSFS + default n + +config WLAN_THERMAL_CFG + bool "Enable WLAN_THERMAL_CFG" + default n + +config WLAN_THERMAL_MULTI_CLIENT_SUPPORT + bool "Enable WLAN_THERMAL_MULTI_CLIENT_SUPPORT" + default n + +config WLAN_TRACEPOINTS + bool "Enable WLAN_TRACEPOINTS" + default n + +config WLAN_TSF_AUTO_REPORT + bool "Enable WLAN_TSF_AUTO_REPORT" + default n + +config WLAN_TSF_UPLINK_DELAY + bool "Enable WLAN_TSF_UPLINK_DELAY" + depends on WLAN_TSF_AUTO_REPORT + default n + +config WLAN_TX_LATENCY_STATS + bool "Enable WLAN_TX_LATENCY_STATS" + depends on WLAN_TSF_AUTO_REPORT + default n + +config WLAN_TWT_CONVERGED + bool "Enable WLAN_TWT_CONVERGED" + default n + +config WLAN_TWT_SAP_PDEV_COUNT + bool "Enable WLAN_TWT_SAP_PDEV_COUNT" + default n + +config WLAN_TWT_SAP_STA_COUNT + bool "Enable WLAN_TWT_SAP_STA_COUNT" + default n + +config WLAN_TX_FLOW_CONTROL_V2 + bool "Enable tx flow control version:2" + default n + +config WLAN_TXRX_FW_ST_RST + bool "Enable WLAN_TXRX_FW_ST_RST" + default n + +config WLAN_TXRX_FW_STATS + bool "Enable WLAN_TXRX_FW_STATS" + default n + +config WLAN_TXRX_STATS + bool "Enable WLAN_TXRX_STATS" + default n + +config WLAN_UMAC_MLO_MAX_DEV + int "Enable WLAN_UMAC_MLO_MAX_DEV" + +config WLAN_VENDOR_HANDOFF_CONTROL + bool "Enable WLAN_VENDOR_HANDOFF_CONTROL" + default n + +config WLAN_WBUFF + bool "Enable WLAN_WBUFF" + default n + +config WLAN_WEXT_SUPPORT_ENABLE + bool "Enable WLAN_WEXT_SUPPORT_ENABLE" + default n + +config WLAN_WOW_ITO + bool "Enable WLAN_WOW_ITO" + default n + +config WLAN_WOWL_ADD_PTRN + bool "Enable WLAN_WOWL_ADD_PTRN" + default n + +config WLAN_WOWL_DEL_PTRN + bool "Enable WLAN_WOWL_DEL_PTRN" + default n + +config WMI_BCN_OFFLOAD + bool "Enable WMI_BCN_OFFLOAD" + default n + +config WMI_CMD_STRINGS + bool "Enable WMI_CMD_STRINGS" + default n + +config WMI_CONCURRENCY_SUPPORT + bool "Enable WMI_CONCURRENCY_SUPPORT" + default n + +config WMI_DBR_SUPPORT + bool "Enable WMI_DBR_SUPPORT" + default n + +config WMI_INTERFACE_EVENT_LOGGING + bool "Enable WMI_INTERFACE_EVENT_LOGGING" + default n + +config WMI_ROAM_SUPPORT + bool "Enable WMI_ROAM_SUPPORT" + default n + +config WMI_SEND_RECV_QMI + bool "Enable WMI_SEND_RECV_QMI" + default n + +config WMI_STA_SUPPORT + bool "Enable WMI_STA_SUPPORT" + default n + +config PADDR_CHECK_ON_3RD_PARTY_PLATFORM + bool "Enable data path memory addr check on third-party platforms" + default n + +config CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT + bool "Enable CONFIG_CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT" + default n + +config CFG80211_RU_PUNCT_NOTIFY + bool "Enable CFG80211_RU_PUNCT_NOTIFY" + default n + +config CFG80211_EXTERNAL_AUTH_MLO_SUPPORT + bool "Enable CFG80211_EXTERNAL_AUTH_MLO_SUPPORT" + default n + +config CFG80211_MLO_KEY_OPERATION_SUPPORT + bool "Enable CFG80211_MLO_KEY_OPERATION_SUPPORT" + default n + +config CFG80211_WEXT + bool "Enable CFG80211_WEXT" + default n + +config FEATURE_PKTLOG + bool "Enable CONFIG_FEATURE_PKTLOG" + default n + +config FEATURE_PKTLOG_EN_NON_LEGACY + bool "Enable FEATURE_PKTLOG_EN_NON_LEGACY" + default n + +config WLAN_CTRL_NAME + string "Enable CONFIG_WLAN_CTRL_NAME" + default \"wlan\" + +config LL_DP_SUPPORT_NON_LITH + bool "ENABLE CONFIG_LL_DP_SUPPORT_NON_LITH" + default n + +config QCA_SUPPORT_TX_THROTTLE_NON_LITH + bool "Enable CONFIG_QCA_SUPPORT_TX_THROTTLE_NON_LITH" + default n + +config PANIC_ON_BUG + bool "Enable PANIC_ON_BUG" + default n + +config CFG80211_LINK_STA_PARAMS_PRESENT + bool "Enable CONFIG_CFG80211_LINK_STA_PARAMS_PRESENT" + default n + +config ARCH_MSM + bool "Enable CONFIG_ARCH_MSM" + default n + +config WLAN_HOST_ARCH_ARM + bool "Enable if host arch is arm" + default n + +config WLAN_WARN_ON_ASSERT + bool "Enable WLAN_WARN_ON_ASSERT" + default n + +config WIFI_MONITOR_SUPPORT_2_0 + bool "Enable WIFI MONITOR SUPPORT 2_0" + default n + +config WLAN_TX_MON_2_0_Y_WLAN_DP_LOCAL_PKT_CAPTURE + bool "Enable WLAN_TX_MON_2_0_Y_DP_LOCAL_PKT_CAPTURE" + default n + +config WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0 + bool "Enable WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0" + default n + +config WLAN_DP_LOCAL_PKT_CAPTURE + bool "Enable CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE" + default n + +config DP_TX_PACKET_INSPECT_FOR_ILP + bool "enable DP_TX_PACKET_INSPECT_FOR_ILP" + default n + +config NUM_SOC_PERF_CLUSTER + int "enable NUM_SOC_PERF_CLUSTER" + default 0 + +config WLAN_OPEN_SOURCE + bool "enable WLAN_OPEN_SOURCE" + default n + +config CFG80211_EXT_FEATURE_SECURE_NAN + bool "enable CFG80211_EXT_FEATURE_SECURE_NAN" + default n + +config CNSS_OUT_OF_TREE + bool "enable CNSS_OUT_OF_TREE" + default n + +config CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT + bool "enable CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT" + default n + +config DP_MULTIPASS_SUPPORT + bool "enable CONFIG_DP_MULTIPASS_SUPPORT" + default n + +config WLAN_FEATURE_LL_LT_SAP + bool "enable CONFIG_WLAN_FEATURE_LL_LT_SAP" + default n + +config WLAN_DP_VDEV_NO_SELF_PEER + bool "enable CONFIG_WLAN_DP_VDEV_NO_SELF_PEER" + default n + +config WLAN_FEATURE_AFFINITY_MGR + bool "enable CONFIG_WLAN_FEATURE_AFFINITY_MGR" + default n + +config NL80211_EXT_FEATURE_PUNCT_SUPPORT + bool "enable CONFIG_NL80211_EXT_FEATURE_PUNCT_SUPPORT" + default n + +config NL80211_TESTMODE + bool "enable CONFIG_NL80211_TESTMODE" + default n + +config DYNAMIC_DEBUG + bool "enable CONFIG_DYNAMIC_DEBUG" + default n + +config WLAN_CHIPSET_STATS + bool "enable WLAN_CHIPSET_STATS" + default n + +config DP_MLO_LINK_STATS_SUPPORT + bool "enable CONFIG_DP_MLO_LINK_STATS_SUPPORT" + default n + +config MULTI_IF_NAME + string "set MULTI_IF_NAME" + default \"wlan\" + +config CFG80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA + bool "enable CFG80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA" + default n + +config WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY + bool "enable WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY" + default n + +config FEATURE_WLAN_CH_AVOID_EXT + bool "enable FEATURE_WLAN_CH_AVOID_EXT" + default n + +config WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE + bool "enable CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE" + default n + +config 4_BYTES_TLV_TAG + bool "enable 4_BYTES_TLV_TAG" + default n + +config QCA_WIFI_EMULATION + bool "enable CONFIG_QCA_WIFI_EMULATION" + default n + +config QDF_TIMER_MULTIPLIER_FRAC + int "set QDF_TIMER_MULTIPLIER_FRAC" + +config QDF_TIMER_MULTIPLIER_FRAC_ENABLE + bool "enable QDF_TIMER_MULTIPLIER_FRAC_ENABLE" + default n + +config QCA_WIFI_PEACH + bool "enable QCA_WIFI_PEACH" + default n + +config BCN_RATECODE_ENABLE + bool "enable CONFIG_BCN_RATECODE_ENABLE" + default n + +config WLAN_SYSFS_RF_TEST_MODE + bool "enable CONFIG_WLAN_SYSFS_RF_TEST_MODE" + default n + +config WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET + bool "enable WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET" + default n + +config CNSS2_MODULE + bool "Enable CONFIG_CNSS2_MODULE" + default n + +config DP_RX_DESC_COOKIE_INVALIDATE + bool "Enable CONFIG_DP_RX_DESC_COOKIE_INVALIDATE" + default n + +config DP_SWLM + bool "Enable DP_SWLM" + default n + +config DP_TX_TRACKING + bool "Enable DP_TX_TRACKING" + default n + +config DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE + bool "Enable DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE" + default n + +config FEATURE_AST + bool "Enable FEATURE_AST" + default n + +config HIF_IPCI + bool "Enable HIF_IPCI" + default n + +config HOST_WAKEUP_OVER_QMI + bool "Enable HOST_WAKEUP_OVER_QMI" + default n + +config LITHIUM + bool "Enable LITHIUM" + default n + +config QCA6750_HEADERS_DEF + bool "Enable QCA6750_HEADERS_DEF" + default n + +config QCA_TARGET_IF_MLME + bool "Enable QCA_TARGET_IF_MLME" + default n + +config QCA_WIFI_QCA6750 + bool "Enable QCA_WIFI_QCA6750" + default n + +config PLD_IPCI_ICNSS_FLAG + bool "Enable PLD_IPCI_ICNSS_FLAG" + default n + +config SHADOW_V2 + bool "Enable SHADOW_V2" + default n + +config WLAN_DP_PROFILE_SUPPORT + bool "Enable WLAN_DP_PROFILE_SUPPORT" + default n + +config WLAN_FEATURE_CE_RX_BUFFER_REUSE + bool "Enable WLAN_FEATURE_CE_RX_BUFFER_REUSE" + default n + +config WLAN_STREAMFS + bool "Enable WLAN_STREAMFS" + default n + +config WLAN_SYSFS_ROAM_TRIGGER_BITMAP + bool "Enable WLAN_SYSFS_ROAM_TRIGGER_BITMAP" + default n + +config WLAN_SYSFS_WDS_MODE + bool "Enable WLAN_SYSFS_WDS_MODE" + default n + +config WLAN_TRACE_HIDE_MAC_ADDRESS + bool "Enable WLAN_TRACE_HIDE_MAC_ADDRESS" + default n + +config CNSS_QCA6750 + bool "Enable CNSS_QCA6750" + default n + +config CNSS_ADRASTEA + bool "Enable CNSS_ADRASTEA" + default n + +config WLAN_FEATURE_EMLSR + bool "Enable EMLSR feature" + default n + +if CNSS_KIWI_V2 +config CFG_BMISS_OFFLOAD_MAX_VDEV + int "Enable CFG_BMISS_OFFLOAD_MAX_VDEV" + +config CFG_MAX_STA_VDEVS + int "Enable CFG_MAX_STA_VDEVS" + +config ROME_IF + string "Enable ROME_IF" + default pci +endif + +if CNSS_QCA6750 +config ROME_IF + string "Enable ROME_IF" + default ipci + +config DP_LEGACY_MODE_CSM_DEFAULT_DISABLE + int "Enable CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE" +endif + +if CNSS_ADRASTEA +config ROME_IF + string "Enable ROME_IF" + default snoc +endif + +config DP_RX_MSDU_DONE_FAIL_HISTORY + bool "Enable DP_RX_MSDU_DONE_FAIL_HISTORY" + default n + +config DP_RX_PEEK_MSDU_DONE_WAR + bool "Enable DP_RX_PEEK_MSDU_DONE_WAR" + default n + +config QCACLD_FEATURE_METERING + bool "Enable QCACLD_FEATURE_METERING" + default n + +config WIFI_3_0_ADRASTEA + bool "Enable WIFI_3_0_ADRASTEA" + default n + +config ADRASTEA_RRI_ON_DDR + bool "Enable ADRASTEA_RRI_ON_DDR" + default n + +config ATH_PROCFS_DIAG_SUPPORT + bool "Enable ATH_PROCFS_DIAG_SUPPORT" + default n + +config ADRASTEA_SHADOW_REGISTERS + bool "Enable ADRASTEA_SHADOW_REGISTERS" + default n + +config FEATURE_ENABLE_CE_DP_IRQ_AFFINE + bool "Enable FEATURE_ENABLE_CE_DP_IRQ_AFFINE" + default n + +config HIF_SNOC + bool "Enable HIF_SNOC" + default n + +config PKTLOG_LEGACY + bool "Enable PKTLOG_LEGACY" + default n + +config WLAN_SEND_DSCP_UP_MAP_TO_FW + bool "Enable WLAN_SEND_DSCP_UP_MAP_TO_FW" + default n + +config ENABLE_DEBUG_ADDRESS_MARKING + bool "Enable ENABLE_DEBUG_ADDRESS_MARKING" + default n + +config CHANNEL_HOPPING_ALL_BANDS + bool "Enable CHANNEL_HOPPING_ALL_BANDS" + default n + +config PKT_LOG + bool "Enable PKT_LOG" + default ni + +config WLAN_DUMP_IN_PROGRESS + bool "Enable WLAN_DUMP_IN_PROGRESS" + default n + +config WLAN_TX_FLOW_CONTROL_V2_HL + bool "Enable WLAN_TX_FLOW_CONTROL_V2_HL" + default n + +config LL_DP_SUPPORT_LEGACY + bool "Enable LL_DP_SUPPORT_LEGACY" + default n + +config WLAN_FASTPATH_LEGACY + bool "Enable WLAN_FASTPATH_LEGACY" + default n + +config QCA_SUPPORT_TX_THROTTLE_LEGACY + bool "Enable QCA_SUPPORT_TX_THROTTLE_LEGACY" + default n + +config PLD_SNOC_ICNSS_FLAG + bool "Enable PLD_SNOC_ICNSS_FLAG" + default n + +config ICNSS2_HELIUM + bool "Enable ICNSS2_HELIUM" + default n +endif # QCA_CLD_WLAN diff --git a/qcom/opensource/wlan/qcacld-3.0/Makefile b/qcom/opensource/wlan/qcacld-3.0/Makefile new file mode 100644 index 0000000000..32910a3acd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/Makefile @@ -0,0 +1,40 @@ +KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build + +# The Make variable $(M) must point to the directory that contains the module +# source code (which includes this Makefile). It can either be an absolute or a +# relative path. If it is a relative path, then it must be relative to the +# kernel source directory (KERNEL_SRC). An absolute path can be obtained very +# easily through $(shell pwd). Generating a path relative to KERNEL_SRC is +# difficult and we accept some outside help by letting the caller override the +# variable $(M). Allowing a relative path for $(M) enables us to have the build +# system put output/object files (.o, .ko.) into a directory different from the +# module source directory. +M ?= $(shell pwd) + +ifeq ($(WLAN_ROOT),) +# WLAN_ROOT must contain an absolute path (i.e. not a relative path) +KBUILD_OPTIONS := WLAN_ROOT=$(shell cd $(KERNEL_SRC); readlink -e $(M)) + +# MODNAME should be qca_cld3_wlan for helium based wear target +ifeq (qca_cld3, $(WLAN_WEAR_CHIPSET)) +KBUILD_OPTIONS += MODNAME?=$(WLAN_WEAR_CHIPSET)_wlan +else +KBUILD_OPTIONS += MODNAME?=wlan +endif + +#By default build for CLD +WLAN_SELECT := CONFIG_QCA_CLD_WLAN=m +KBUILD_OPTIONS += CONFIG_QCA_WIFI_ISOC=0 +KBUILD_OPTIONS += CONFIG_QCA_WIFI_2_0=1 +KBUILD_OPTIONS += $(WLAN_SELECT) +KBUILD_OPTIONS += $(KBUILD_EXTRA) # Extra config if any +endif + +all: + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 M=$(M) -C $(KERNEL_SRC) modules_install + +clean: + $(MAKE) -C $(KERNEL_SRC) M=$(M) clean $(KBUILD_OPTIONS) diff --git a/qcom/opensource/wlan/qcacld-3.0/README.txt b/qcom/opensource/wlan/qcacld-3.0/README.txt new file mode 100644 index 0000000000..bdf3e7a7ad --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/README.txt @@ -0,0 +1 @@ +This is CNSS WLAN Host Driver for products starting from iHelium diff --git a/qcom/opensource/wlan/qcacld-3.0/api b/qcom/opensource/wlan/qcacld-3.0/api new file mode 120000 index 0000000000..a064ee106e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/api @@ -0,0 +1 @@ +../fw-api \ No newline at end of file diff --git a/qcom/opensource/wlan/qcacld-3.0/cmn b/qcom/opensource/wlan/qcacld-3.0/cmn new file mode 120000 index 0000000000..c60dbf6d45 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/cmn @@ -0,0 +1 @@ +../qca-wifi-host-cmn \ No newline at end of file diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_main.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_main.h new file mode 100644 index 0000000000..7b9614ceed --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_main.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in action_oui component. This file shall include prototypes of + * various notification handlers and logging functions. + * + * Note: This API should be never accessed out of action_oui component. + */ + +#ifndef _WLAN_ACTION_OUI_MAIN_H_ +#define _WLAN_ACTION_OUI_MAIN_H_ + +#include +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_priv.h" +#include "wlan_action_oui_objmgr.h" + +#define action_oui_log(level, args...) \ + QDF_TRACE(QDF_MODULE_ID_ACTION_OUI, level, ## args) + +#define action_oui_logfl(level, format, args...) \ + action_oui_log(level, FL(format), ## args) + +#define action_oui_fatal(format, args...) \ + action_oui_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define action_oui_err(format, args...) \ + action_oui_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define action_oui_warn(format, args...) \ + action_oui_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define action_oui_info(format, args...) \ + action_oui_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define action_oui_debug(format, args...) \ + action_oui_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define ACTION_OUI_ENTER() action_oui_debug("enter") +#define ACTION_OUI_EXIT() action_oui_debug("exit") + +/** + * action_oui_psoc_create_notification(): Handler for psoc create notify. + * @psoc: psoc which is going to be created by objmgr + * @arg: argument for notification handler. + * + * Allocate and attach psoc private object. + * + * Return: QDF_STATUS status in case of success else return error. + */ +QDF_STATUS +action_oui_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * action_oui_psoc_destroy_notification(): Handler for psoc destroy notify. + * @psoc: psoc which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach psoc private object. + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS +action_oui_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * wlan_action_oui_search() - Check for OUIs and related info in IE data. + * @psoc: objmgr psoc object + * @attr: pointer to structure containing type of action, beacon IE data etc., + * @action_id: type of action to be checked + * + * This is a wrapper function which invokes internal function to search + * for OUIs and related info (specified from ini file) in vendor specific + * data of beacon IE for given action. + * + * Return: If search is successful return true else false. + */ +#ifdef WLAN_FEATURE_ACTION_OUI +bool wlan_action_oui_search(struct wlan_objmgr_psoc *psoc, + struct action_oui_search_attr *attr, + enum action_oui_id action_id); + +/** + * wlan_action_oui_is_empty() - Check action oui present or not + * @psoc: psoc object + * @action_id: action oui id + * + * This function will check action oui present or not for specific action type. + * + * Return: True if no action oui for the action type. + */ +bool wlan_action_oui_is_empty(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id); + +/** + * wlan_action_oui_cleanup() - Remove all of existing oui entry. + * @psoc_priv: action oui objmgr private context + * @action_id: type of action to be removed + * + * This is a wrapper function which invokes internal function to remove + * all of existing oui entry. + * + * Return: QDF_STATUS_SUCCESS If remove is successful. + */ +QDF_STATUS +wlan_action_oui_cleanup(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id); + +/** + * action_oui_psoc_enable() - Notify action OUI psoc enable + * @psoc: objmgr psoc object + * + * Return: void + */ +void action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * action_oui_psoc_disable() - Notify action OUI psoc disable + * @psoc: objmgr psoc object + * + * Return: void + */ +void action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc); + +#else +static inline +bool wlan_action_oui_search(struct wlan_objmgr_psoc *psoc, + struct action_oui_search_attr *attr, + enum action_oui_id action_id) +{ + return false; +} + +static inline +bool wlan_action_oui_is_empty(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id) +{ + return true; +} + +static inline QDF_STATUS +wlan_action_oui_cleanup(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ +} + +#endif +#endif /* end of _WLAN_ACTION_OUI_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_objmgr.h new file mode 100644 index 0000000000..17d0b09c89 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_objmgr.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains various object manager related wrappers and helpers + */ + +#ifndef _WLAN_ACTION_OUI_OBJMGR_H +#define _WLAN_ACTION_OUI_OBJMGR_H + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_psoc_obj.h" + +/** + * action_oui_psoc_get_ref() - Wrapper to increment action_oui ref count + * @psoc: psoc object + * + * Wrapper for action_oui to increment ref count after checking valid + * object state. + * + * Return: SUCCESS/FAILURE + */ +static inline +QDF_STATUS action_oui_psoc_get_ref(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_try_get_ref(psoc, WLAN_ACTION_OUI_ID); +} + +/** + * action_oui_psoc_put_ref() - Wrapper to decrement action_oui ref count + * @psoc: psoc object + * + * Wrapper for action_oui to decrement ref count of psoc. + * + * Return: SUCCESS/FAILURE + */ +static inline +void action_oui_psoc_put_ref(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_release_ref(psoc, WLAN_ACTION_OUI_ID); +} + +/** + * action_oui_psoc_get_priv(): Wrapper to retrieve psoc priv obj + * @psoc: psoc pointer + * + * Wrapper for action_oui to get psoc private object pointer. + * + * Return: Private object of psoc + */ +static inline struct action_oui_psoc_priv * +action_oui_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct action_oui_psoc_priv *psoc_priv; + + psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_ACTION_OUI); + QDF_BUG(psoc_priv); + + return psoc_priv; +} + +#endif /* _WLAN_ACTION_OUI_OBJMGR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_priv.h new file mode 100644 index 0000000000..5dd7913ec2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/inc/wlan_action_oui_priv.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in action_oui component. This file shall include prototypes of + * action_oui parsing and send logic. + * + * Note: This API should be never accessed out of action_oui component. + */ + +#ifndef _WLAN_ACTION_OUI_PRIV_STRUCT_H_ +#define _WLAN_ACTION_OUI_PRIV_STRUCT_H_ + +#include +#include +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_tgt_api.h" +#include "wlan_action_oui_objmgr.h" + +/** + * enum action_oui_token_type - String token types expected. + * @ACTION_OUI_TOKEN: oui string + * @ACTION_OUI_DATA_LENGTH_TOKEN: data length string + * @ACTION_OUI_DATA_TOKEN: OUI data string + * @ACTION_OUI_DATA_MASK_TOKEN: data mask string + * @ACTION_OUI_INFO_MASK_TOKEN: info mask string + * @ACTION_OUI_MAC_ADDR_TOKEN: mac addr string + * @ACTION_OUI_MAC_MASK_TOKEN: mac mask string + * @ACTION_OUI_CAPABILITY_TOKEN: capability string + * @ACTION_OUI_END_TOKEN: end of one oui extension + */ +enum action_oui_token_type { + ACTION_OUI_TOKEN = 1 << 0, + ACTION_OUI_DATA_LENGTH_TOKEN = 1 << 1, + ACTION_OUI_DATA_TOKEN = 1 << 2, + ACTION_OUI_DATA_MASK_TOKEN = 1 << 3, + ACTION_OUI_INFO_MASK_TOKEN = 1 << 4, + ACTION_OUI_MAC_ADDR_TOKEN = 1 << 5, + ACTION_OUI_MAC_MASK_TOKEN = 1 << 6, + ACTION_OUI_CAPABILITY_TOKEN = 1 << 7, + ACTION_OUI_END_TOKEN = 1 << 8, +}; + +/** + * struct action_oui_extension_priv - Private contents of extension. + * @item: list element + * @extension: Extension contents + * + * This structure encapsulates action_oui_extension and list item. + */ +struct action_oui_extension_priv { + qdf_list_node_t item; + struct action_oui_extension extension; +}; + +/** + * struct action_oui_priv - Each action info. + * @id: type of action + * @extension_list: list of extensions + * @extension_lock: lock to control access to @extension_list + * + * All extensions of action specified by action_id are stored + * at @extension_list as linked list. + */ +struct action_oui_priv { + enum action_oui_id id; + qdf_list_t extension_list; + qdf_mutex_t extension_lock; +}; + +/** + * struct action_oui_psoc_priv - Private object to be stored in psoc + * @psoc: pointer to psoc object + * @action_oui_enable: action oui enable + * @action_oui_str: oui configuration strings + * @total_extensions: total count of extensions from all actions + * @host_only_extensions: total host only only extensions from all actions + * @max_extensions: Max no. of extensions that can be configured to the firmware + * @oui_priv: array of pointers used to refer each action info + * @tx_ops: call-back functions to send OUIs to firmware + */ +struct action_oui_psoc_priv { + struct wlan_objmgr_psoc *psoc; + bool action_oui_enable; + uint8_t action_oui_str[ACTION_OUI_MAXIMUM_ID][ACTION_OUI_MAX_STR_LEN]; + uint32_t total_extensions; + uint32_t host_only_extensions; + uint32_t max_extensions; + struct action_oui_priv *oui_priv[ACTION_OUI_MAXIMUM_ID]; + struct action_oui_tx_ops tx_ops; +}; + +/** + * action_oui_parse() - Parse action oui string + * @psoc_priv: pointer to action_oui psoc priv obj + * @oui_string: string to be parsed + * @action_id: type of the action to be parsed + * + * This function parses the action oui string, extracts extensions and + * stores them @action_oui_priv using list data structure. + * + * Return: QDF_STATUS + * + */ +QDF_STATUS +action_oui_parse(struct action_oui_psoc_priv *psoc_priv, + uint8_t *oui_string, enum action_oui_id action_id); + +/** + * action_oui_parse_string() - Parse action oui string + * @psoc: psoc object + * @in_str: string to be parsed + * @action_id: type of the action to be parsed + * + * This function will validate the input string and call action_oui_parse + * to parse it. + * + * Return: QDF_STATUS + * + */ +QDF_STATUS +action_oui_parse_string(struct wlan_objmgr_psoc *psoc, + const uint8_t *in_str, + enum action_oui_id action_id); + +/** + * action_oui_send() - Send action oui extensions to target_if. + * @psoc_priv: pointer to action_oui psoc priv obj + * @action_id: type of the action to send + * + * This function sends action oui extensions to target_if. + * + * Return: QDF_STATUS + * + */ +QDF_STATUS +action_oui_send(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id); + +/** + * action_oui_search() - Check if Vendor OUIs are present in IE buffer + * @psoc_priv: pointer to action_oui psoc priv obj + * @attr: pointer to structure containing type of action, beacon IE data etc., + * @action_id: type of action to be checked + * + * This function parses the IE buffer and finds if any of the vendor OUI + * and related attributes are present in it. + * + * Return: If vendor OUI is present return true else false + */ +bool +action_oui_search(struct action_oui_psoc_priv *psoc_priv, + struct action_oui_search_attr *attr, + enum action_oui_id action_id); + +/** + * action_oui_is_empty() - Check action oui present or not + * @psoc_priv: action psoc private object + * @action_id: action oui id + * + * This function will check action oui present or not for specific action type. + * + * Return: True if no action oui for the action type. + */ +bool +action_oui_is_empty(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id); +#endif /* End of _WLAN_ACTION_OUI_PRIV_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_main.c b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_main.c new file mode 100644 index 0000000000..9b8595e7ec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_main.c @@ -0,0 +1,503 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement various notification handlers which are accessed + * internally in action_oui component only. + */ +#include "cfg_ucfg_api.h" +#include "wlan_action_oui_cfg.h" +#include "wlan_action_oui_main.h" +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_tgt_api.h" +#include "target_if_action_oui.h" + +/** + * action_oui_allocate() - Allocates memory for various actions. + * @psoc_priv: pointer to action_oui psoc priv obj + * + * This function allocates memory for all the action_oui types + * and initializes the respective lists to store extensions + * extracted from action_oui_extract(). + * + * Return: QDF_STATUS + */ +static QDF_STATUS +action_oui_allocate(struct action_oui_psoc_priv *psoc_priv) +{ + struct action_oui_priv *oui_priv; + uint32_t i; + uint32_t j; + + for (i = 0; i < ACTION_OUI_MAXIMUM_ID; i++) { + oui_priv = qdf_mem_malloc(sizeof(*oui_priv)); + if (!oui_priv) { + action_oui_err("Mem alloc failed for oui_priv id: %u", + i); + goto free_mem; + } + oui_priv->id = i; + qdf_list_create(&oui_priv->extension_list, + ACTION_OUI_MAX_EXTENSIONS); + qdf_mutex_create(&oui_priv->extension_lock); + psoc_priv->oui_priv[i] = oui_priv; + } + + return QDF_STATUS_SUCCESS; + +free_mem: + for (j = 0; j < i; j++) { + oui_priv = psoc_priv->oui_priv[j]; + if (!oui_priv) + continue; + + qdf_list_destroy(&oui_priv->extension_list); + qdf_mutex_destroy(&oui_priv->extension_lock); + psoc_priv->oui_priv[j] = NULL; + } + + return QDF_STATUS_E_NOMEM; +} + +/** + * action_oui_destroy() - Deallocates memory for various actions. + * @psoc_priv: pointer to action_oui psoc priv obj + * + * This function Deallocates memory for all the action_oui types. + * As a part of deallocate, all extensions are destroyed. + * + * Return: None + */ +static void +action_oui_destroy(struct action_oui_psoc_priv *psoc_priv) +{ + struct action_oui_priv *oui_priv; + struct action_oui_extension_priv *ext_priv; + qdf_list_t *ext_list; + QDF_STATUS status; + qdf_list_node_t *node = NULL; + uint32_t i; + + psoc_priv->total_extensions = 0; + psoc_priv->max_extensions = 0; + psoc_priv->host_only_extensions = 0; + + for (i = 0; i < ACTION_OUI_MAXIMUM_ID; i++) { + oui_priv = psoc_priv->oui_priv[i]; + psoc_priv->oui_priv[i] = NULL; + if (!oui_priv) + continue; + + ext_list = &oui_priv->extension_list; + qdf_mutex_acquire(&oui_priv->extension_lock); + while (!qdf_list_empty(ext_list)) { + status = qdf_list_remove_front(ext_list, &node); + if (!QDF_IS_STATUS_SUCCESS(status)) { + action_oui_err("Invalid delete in action: %u", + oui_priv->id); + break; + } + ext_priv = qdf_container_of(node, + struct action_oui_extension_priv, + item); + qdf_mem_free(ext_priv); + ext_priv = NULL; + } + + qdf_list_destroy(ext_list); + qdf_mutex_release(&oui_priv->extension_lock); + qdf_mutex_destroy(&oui_priv->extension_lock); + qdf_mem_free(oui_priv); + oui_priv = NULL; + } +} + +static void action_oui_load_config(struct action_oui_psoc_priv *psoc_priv) +{ + struct wlan_objmgr_psoc *psoc = psoc_priv->psoc; + + psoc_priv->action_oui_enable = + cfg_get(psoc, CFG_ENABLE_ACTION_OUI); + + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_CONNECT_1X1], + cfg_get(psoc, CFG_ACTION_OUI_CONNECT_1X1), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ITO_EXTENSION], + cfg_get(psoc, CFG_ACTION_OUI_ITO_EXTENSION), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_CCKM_1X1], + cfg_get(psoc, CFG_ACTION_OUI_CCKM_1X1), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ITO_ALTERNATE], + cfg_get(psoc, CFG_ACTION_OUI_ITO_ALTERNATE), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_SWITCH_TO_11N_MODE], + cfg_get(psoc, CFG_ACTION_OUI_SWITCH_TO_11N_MODE), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN], + cfg_get(psoc, + CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_AGGRESSIVE_TX], + cfg_get(psoc, + CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str + [ACTION_OUI_DISABLE_AGGRESSIVE_EDCA], + cfg_get(psoc, + CFG_ACTION_OUI_DISABLE_AGGRESSIVE_EDCA), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_EXTEND_WOW_ITO], + cfg_get(psoc, CFG_ACTION_OUI_EXTEND_WOW_ITO), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_TWT], + cfg_get(psoc, CFG_ACTION_OUI_DISABLE_TWT), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_HOST_RECONN], + cfg_get(psoc, CFG_ACTION_OUI_RECONN_ASSOCTIMEOUT), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_TAKE_ALL_BAND_INFO], + cfg_get(psoc, CFG_ACTION_OUI_TAKE_ALL_BAND_INFO), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_11BE_OUI_ALLOW], + cfg_get(psoc, CFG_ACTION_OUI_11BE_ALLOW_LIST), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str + [ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE], + cfg_get(psoc, + CFG_ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str + [ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL], + cfg_get(psoc, + CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL), + ACTION_OUI_MAX_STR_LEN); + + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_ENABLE_CTS2SELF], + cfg_get(psoc, CFG_ACTION_OUI_ENABLE_CTS2SELF), + ACTION_OUI_MAX_STR_LEN); + + qdf_str_lcopy(psoc_priv->action_oui_str + [ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN], + cfg_get(psoc, + CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str + [ACTION_OUI_RESTRICT_MAX_MLO_LINKS], + cfg_get(psoc, CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str + [ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ], + cfg_get(psoc, CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_DISABLE_BFORMEE], + cfg_get(psoc, CFG_ACTION_OUI_DISABLE_BFORMEE), + ACTION_OUI_MAX_STR_LEN); + qdf_str_lcopy(psoc_priv->action_oui_str[ACTION_OUI_LIMIT_BW], + cfg_get(psoc, CFG_ACTION_OUI_LIMIT_BW), + ACTION_OUI_MAX_STR_LEN); +} + +static void action_oui_parse_config(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + uint32_t id; + uint8_t *str; + struct action_oui_psoc_priv *psoc_priv; + + if (!psoc) { + action_oui_err("Invalid psoc"); + return; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + return; + } + if (!psoc_priv->action_oui_enable) { + action_oui_debug("action_oui is not enable"); + return; + } + for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) { + str = psoc_priv->action_oui_str[id]; + if (!qdf_str_len(str)) + continue; + + status = action_oui_parse_string(psoc, str, id); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("Failed to parse action_oui str: %u", + id); + } + + /* FW allocates memory for the extensions only during init time. + * Therefore, send additional legspace for configuring new + * extensions during runtime. + * The current max value is default extensions count + 10. + */ + psoc_priv->max_extensions = psoc_priv->total_extensions - + psoc_priv->host_only_extensions + + ACTION_OUI_MAX_ADDNL_EXTENSIONS; + action_oui_debug("Extensions - Max: %d Total: %d host_only %d", + psoc_priv->max_extensions, psoc_priv->total_extensions, + psoc_priv->host_only_extensions); +} + +static QDF_STATUS action_oui_send_config(struct wlan_objmgr_psoc *psoc) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t id; + + if (!psoc) { + action_oui_err("psoc is NULL"); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + if (!psoc_priv->action_oui_enable) { + action_oui_debug("action_oui is not enable"); + return QDF_STATUS_SUCCESS; + } + + for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) { + if (id >= ACTION_OUI_HOST_ONLY) + continue; + status = action_oui_send(psoc_priv, id); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("Failed to send: %u", id); + } + +exit: + return status; +} + +QDF_STATUS +action_oui_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status; + + ACTION_OUI_ENTER(); + + psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv)); + if (!psoc_priv) { + status = QDF_STATUS_E_NOMEM; + goto exit; + } + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_ACTION_OUI, + (void *)psoc_priv, QDF_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(status)) { + action_oui_err("Failed to attach priv with psoc"); + goto free_psoc_priv; + } + + target_if_action_oui_register_tx_ops(&psoc_priv->tx_ops); + psoc_priv->psoc = psoc; + action_oui_load_config(psoc_priv); + action_oui_debug("psoc priv attached"); + goto exit; +free_psoc_priv: + qdf_mem_free(psoc_priv); + status = QDF_STATUS_E_INVAL; +exit: + ACTION_OUI_EXIT(); + return status; +} + +QDF_STATUS +action_oui_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct action_oui_psoc_priv *psoc_priv = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + ACTION_OUI_ENTER(); + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_ACTION_OUI, + (void *)psoc_priv); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("Failed to detach priv with psoc"); + + qdf_mem_free(psoc_priv); + +exit: + ACTION_OUI_EXIT(); + return status; +} + +void action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + ACTION_OUI_ENTER(); + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + status = action_oui_allocate(psoc_priv); + if (!QDF_IS_STATUS_SUCCESS(status)) { + action_oui_err("Failed to alloc action_oui"); + goto exit; + } + action_oui_parse_config(psoc); + action_oui_send_config(psoc); +exit: + ACTION_OUI_EXIT(); +} + +void action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + struct action_oui_psoc_priv *psoc_priv; + + ACTION_OUI_ENTER(); + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + action_oui_destroy(psoc_priv); +exit: + ACTION_OUI_EXIT(); +} + +bool wlan_action_oui_search(struct wlan_objmgr_psoc *psoc, + struct action_oui_search_attr *attr, + enum action_oui_id action_id) +{ + struct action_oui_psoc_priv *psoc_priv; + bool found = false; + + if (!psoc || !attr) { + action_oui_err("Invalid psoc or search attrs"); + goto exit; + } + + if (action_id >= ACTION_OUI_MAXIMUM_ID) { + action_oui_err("Invalid action_oui id: %u", action_id); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + found = action_oui_search(psoc_priv, attr, action_id); + +exit: + return found; +} + +QDF_STATUS +wlan_action_oui_cleanup(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id) +{ + struct action_oui_priv *oui_priv; + struct action_oui_extension_priv *ext_priv; + qdf_list_t *ext_list; + QDF_STATUS status; + qdf_list_node_t *node = NULL; + + if (action_id >= ACTION_OUI_MAXIMUM_ID) + return QDF_STATUS_E_INVAL; + + oui_priv = psoc_priv->oui_priv[action_id]; + if (!oui_priv) + return QDF_STATUS_SUCCESS; + + ext_list = &oui_priv->extension_list; + qdf_mutex_acquire(&oui_priv->extension_lock); + while (!qdf_list_empty(ext_list)) { + status = qdf_list_remove_front(ext_list, &node); + if (!QDF_IS_STATUS_SUCCESS(status)) { + action_oui_err("Invalid delete in action: %u", + oui_priv->id); + break; + } + ext_priv = qdf_container_of( + node, + struct action_oui_extension_priv, + item); + qdf_mem_free(ext_priv); + ext_priv = NULL; + if (psoc_priv->total_extensions) + psoc_priv->total_extensions--; + else + action_oui_err("unexpected total_extensions 0"); + + if (action_id >= ACTION_OUI_HOST_ONLY) { + if (!psoc_priv->host_only_extensions) + action_oui_err("unexpected total host extensions"); + else + psoc_priv->host_only_extensions--; + } + } + qdf_mutex_release(&oui_priv->extension_lock); + + return QDF_STATUS_SUCCESS; +} + +bool wlan_action_oui_is_empty(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id) +{ + struct action_oui_psoc_priv *psoc_priv; + bool empty = true; + + if (!psoc) { + action_oui_err("Invalid psoc"); + goto exit; + } + + if (action_id >= ACTION_OUI_MAXIMUM_ID) { + action_oui_err("Invalid action_oui id: %u", action_id); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + empty = action_oui_is_empty(psoc_priv, action_id); + +exit: + return empty; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_parse.c b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_parse.c new file mode 100644 index 0000000000..eaba4bd2b5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/core/src/wlan_action_oui_parse.c @@ -0,0 +1,1091 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement parsing logic for action_oui strings, extract + * extensions and store them using linked list. Functions defined in + * this file can be accessed internally in action_oui component only. + */ + +#include "wlan_action_oui_main.h" +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_tgt_api.h" +#include "target_if_action_oui.h" +#include +#include + +/** + * action_oui_string_to_hex() - convert string to uint8_t hex array + * @token: string to be converted + * @hex: output string to hold converted string + * @no_of_lengths: count of possible lengths for input string + * @possible_lengths: array holding possible lengths + * + * This function converts the continuous input string of even length and + * containing hexa decimal characters into hexa decimal array of uint8_t type. + * Input string needs to be NULL terminated and the length should match with + * one of entries in @possible_lengths + * + * Return: If conversion is successful return true else false + */ +static bool action_oui_string_to_hex(uint8_t *token, uint8_t *hex, + uint32_t no_of_lengths, + uint32_t *possible_lengths) +{ + uint32_t token_len = qdf_str_len(token); + uint32_t hex_str_len; + uint32_t i; + int ret; + + if (!token_len || (token_len & 0x01)) { + action_oui_err("Token len is not multiple of 2"); + return false; + } + + for (i = 0; i < no_of_lengths; i++) + if (token_len == possible_lengths[i]) + break; + + if (i == no_of_lengths) { + action_oui_err("Token len doesn't match with expected len"); + return false; + } + + hex_str_len = token_len / 2; + + ret = qdf_hex_str_to_binary(hex, token, hex_str_len); + if (ret) { + action_oui_err("Token doesn't contain hex digits"); + return false; + } + + return true; +} + +/** + * action_oui_token_string() - converts enum value to string + * @token_id: enum value to be converted to string + * + * This function converts the enum value of type action_oui_token_type + * to string + * + * Return: converted string + */ +static +uint8_t *action_oui_token_string(enum action_oui_token_type token_id) +{ + switch (token_id) { + CASE_RETURN_STRING(ACTION_OUI_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_DATA_LENGTH_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_DATA_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_DATA_MASK_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_INFO_MASK_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_MAC_ADDR_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_MAC_MASK_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_CAPABILITY_TOKEN); + CASE_RETURN_STRING(ACTION_OUI_END_TOKEN); + } + + return (uint8_t *) "UNKNOWN"; +} + +/** + * validate_and_convert_oui() - validate and convert OUI str to hex array + * @token: OUI string + * @ext: pointer to container which holds converted hex array + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the OUI string for action OUI inis, convert them to hex array and store it + * in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static +bool validate_and_convert_oui(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + bool valid; + uint32_t expected_token_len[2] = {6, 10}; + + valid = action_oui_string_to_hex(token, ext->oui, 2, + expected_token_len); + if (!valid) + return false; + + ext->oui_length = qdf_str_len(token) / 2; + + *action_token = ACTION_OUI_DATA_LENGTH_TOKEN; + + return valid; +} + +/** + * validate_and_convert_data_length() - validate data len str + * @token: data length string + * @ext: pointer to container which holds hex value formed from input str + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the data length string for action OUI inis, convert it to hex value and + * store it in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_data_length(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + uint32_t token_len = qdf_str_len(token); + int ret; + uint8_t len = 0; + + if (token_len != 1 && token_len != 2) { + action_oui_err("Invalid str token len for action OUI data len"); + return false; + } + + ret = kstrtou8(token, 16, &len); + if (ret) { + action_oui_err("Invalid char in action OUI data len str token"); + return false; + } + + if ((uint32_t)len > ACTION_OUI_MAX_DATA_LENGTH) { + action_oui_err("action OUI data len %d is more than %u", + len, ACTION_OUI_MAX_DATA_LENGTH); + return false; + } + + ext->data_length = len; + + if (!ext->data_length) + *action_token = ACTION_OUI_INFO_MASK_TOKEN; + else + *action_token = ACTION_OUI_DATA_TOKEN; + + return true; +} + +/** + * validate_and_convert_data() - validate and convert data str to hex array + * @token: data string + * @ext: pointer to container which holds converted hex array + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the data string for action OUI inis, convert it to hex array and store in + * action_oui extension. After successful parsing update the @action_token + * to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_data(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + bool valid; + uint32_t expected_token_len[1] = {2 * ext->data_length}; + + valid = action_oui_string_to_hex(token, ext->data, 1, + expected_token_len); + if (!valid) + return false; + + *action_token = ACTION_OUI_DATA_MASK_TOKEN; + + return true; +} + +/** + * validate_and_convert_data_mask() - validate and convert data mask str + * @token: data mask string + * @ext: pointer to container which holds converted hex array + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the data mask string for action OUI inis, convert it to hex array and store + * in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_data_mask(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + bool valid; + uint32_t expected_token_len[1]; + uint32_t data_mask_length; + uint32_t data_length = ext->data_length; + + if (data_length % 8 == 0) + data_mask_length = data_length / 8; + else + data_mask_length = ((data_length / 8) + 1); + + if (data_mask_length > ACTION_OUI_MAX_DATA_MASK_LENGTH) + return false; + + expected_token_len[0] = 2 * data_mask_length; + + valid = action_oui_string_to_hex(token, ext->data_mask, 1, + expected_token_len); + if (!valid) + return false; + + ext->data_mask_length = data_mask_length; + + *action_token = ACTION_OUI_INFO_MASK_TOKEN; + + return valid; +} + +/** + * validate_and_convert_info_mask() - validate and convert info mask str + * @token: info mask string + * @ext: pointer to container which holds converted hex array + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the info mask string for action OUI inis, convert it to hex array and store + * in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_info_mask(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + uint32_t token_len = qdf_str_len(token); + uint8_t hex_value = 0; + uint32_t info_mask; + int ret; + + if (token_len != 2) { + action_oui_err("action OUI info mask str token len is not of 2 chars"); + return false; + } + + ret = kstrtou8(token, 16, &hex_value); + if (ret) { + action_oui_err("Invalid char in action OUI info mask str token"); + return false; + } + + info_mask = hex_value; + + ext->info_mask = info_mask; + + if (!info_mask || !(info_mask & ~ACTION_OUI_INFO_OUI)) { + *action_token = ACTION_OUI_END_TOKEN; + return true; + } + + if (info_mask & ~ACTION_OUI_INFO_MASK) { + action_oui_err("Invalid bits are set in action OUI info mask"); + return false; + } + + /* + * If OUI bit is not set in the info presence, we need to ignore the + * OUI and OUI Data. Set OUI and OUI data length to 0 here. + */ + if (!(info_mask & ACTION_OUI_INFO_OUI)) { + ext->oui_length = 0; + ext->data_length = 0; + ext->data_mask_length = 0; + } + + if (info_mask & ACTION_OUI_INFO_MAC_ADDRESS) { + *action_token = ACTION_OUI_MAC_ADDR_TOKEN; + return true; + } + + *action_token = ACTION_OUI_CAPABILITY_TOKEN; + return true; +} + +/** + * validate_and_convert_mac_addr() - validate and convert mac addr str + * @token: mac address string + * @ext: pointer to container which holds converted hex array + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the mac address string for action OUI inis, convert it to hex array and store + * in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_mac_addr(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + uint32_t expected_token_len[1] = {2 * QDF_MAC_ADDR_SIZE}; + bool valid; + + valid = action_oui_string_to_hex(token, ext->mac_addr, 1, + expected_token_len); + if (!valid) + return false; + + ext->mac_addr_length = QDF_MAC_ADDR_SIZE; + + *action_token = ACTION_OUI_MAC_MASK_TOKEN; + + return true; +} + +/** + * validate_and_convert_mac_mask() - validate and convert mac mask + * @token: mac mask string + * @ext: pointer to container which holds converted hex value + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the mac mask string for action OUI inis, convert it to hex value and store + * in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_mac_mask(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + uint32_t expected_token_len[1] = {2}; + uint32_t info_mask = ext->info_mask; + bool valid; + uint32_t mac_mask_length; + + valid = action_oui_string_to_hex(token, ext->mac_mask, 1, + expected_token_len); + if (!valid) + return false; + + mac_mask_length = qdf_str_len(token) / 2; + if (mac_mask_length > ACTION_OUI_MAC_MASK_LENGTH) { + action_oui_err("action OUI mac mask str token len is more than %u chars", + expected_token_len[0]); + return false; + } + + ext->mac_mask_length = mac_mask_length; + + if ((info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) || + (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_HT) || + (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_VHT) || + (info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND)) { + *action_token = ACTION_OUI_CAPABILITY_TOKEN; + return true; + } + + *action_token = ACTION_OUI_END_TOKEN; + return true; +} + +/** + * validate_and_convert_capability() - validate and convert capability str + * @token: capability string + * @ext: pointer to container which holds converted hex value + * @action_token: next action to be parsed + * + * This is an internal function invoked from action_oui_parse to validate + * the capability string for action OUI inis, convert it to hex value and store + * in action_oui extension. After successful parsing update the + * @action_token to hold the next expected string. + * + * Return: If conversion is successful return true else false + */ +static bool +validate_and_convert_capability(uint8_t *token, + struct action_oui_extension *ext, + enum action_oui_token_type *action_token) +{ + uint32_t expected_token_len[1] = {2}; + uint32_t info_mask = ext->info_mask; + uint32_t capability_length; + uint8_t caps_0; + bool valid; + + valid = action_oui_string_to_hex(token, ext->capability, 1, + expected_token_len); + if (!valid) + return false; + + capability_length = qdf_str_len(token) / 2; + if (capability_length > ACTION_OUI_MAX_CAPABILITY_LENGTH) { + action_oui_err("action OUI capability str token len is more than %u chars", + expected_token_len[0]); + return false; + } + + caps_0 = ext->capability[0]; + + if ((info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) && + (!(caps_0 & ACTION_OUI_CAPABILITY_NSS_MASK))) { + action_oui_err("Info presence for NSS is set but respective bits in capability are not set"); + return false; + } + + if ((info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND) && + (!(caps_0 & ACTION_OUI_CAPABILITY_BAND_MASK))) { + action_oui_err("Info presence for BAND is set but respective bits in capability are not set"); + return false; + } + + ext->capability_length = capability_length; + + *action_token = ACTION_OUI_END_TOKEN; + + return true; +} + +/** + * action_oui_extension_store() - store action oui extension + * @psoc_priv: pointer to action_oui priv obj + * @oui_priv: type of the action + * @ext: oui extension to store in sme + * + * This function stores the parsed oui extension + * + * Return: QDF_STATUS + * + */ +static QDF_STATUS +action_oui_extension_store(struct action_oui_psoc_priv *psoc_priv, + struct action_oui_priv *oui_priv, + struct action_oui_extension ext) +{ + struct action_oui_extension_priv *ext_priv; + + qdf_mutex_acquire(&oui_priv->extension_lock); + if (qdf_list_size(&oui_priv->extension_list) == + ACTION_OUI_MAX_EXTENSIONS) { + qdf_mutex_release(&oui_priv->extension_lock); + action_oui_err("Reached maximum OUI extensions"); + return QDF_STATUS_E_FAILURE; + } + + ext_priv = qdf_mem_malloc(sizeof(*ext_priv)); + if (!ext_priv) { + qdf_mutex_release(&oui_priv->extension_lock); + return QDF_STATUS_E_NOMEM; + } + + ext_priv->extension = ext; + qdf_list_insert_back(&oui_priv->extension_list, &ext_priv->item); + psoc_priv->total_extensions++; + qdf_mutex_release(&oui_priv->extension_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +action_oui_parse(struct action_oui_psoc_priv *psoc_priv, + uint8_t *oui_string, enum action_oui_id action_id) +{ + struct action_oui_extension ext = {0}; + enum action_oui_token_type action_token = ACTION_OUI_TOKEN; + char *str1; + char *str2; + char *token; + bool valid = true; + bool oui_count_exceed = false; + uint32_t oui_index = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct action_oui_priv *oui_priv; + + if (!oui_string) { + action_oui_err("Invalid string for action oui: %u", action_id); + return QDF_STATUS_E_INVAL; + } + + oui_priv = psoc_priv->oui_priv[action_id]; + if (!oui_priv) { + action_oui_err("action oui priv not allocated"); + return QDF_STATUS_E_INVAL; + } + + if (!psoc_priv->action_oui_enable) { + action_oui_debug("action_oui is not enable"); + return QDF_STATUS_SUCCESS; + } + + str1 = qdf_str_trim((char *)oui_string); + + while (str1) { + str2 = (char *)qdf_str_left_trim(str1); + if (str2[0] == '\0') { + action_oui_err("Invalid spaces in action oui: %u at extension: %u for token: %s", + action_id, + oui_index + 1, + action_oui_token_string(action_token)); + valid = false; + break; + } + + token = strsep(&str2, " "); + if (!token) { + action_oui_err("Invalid string for token: %s at extension: %u in action oui: %u", + action_oui_token_string(action_token), + oui_index + 1, action_id); + valid = false; + break; + } + + str1 = str2; + + switch (action_token) { + + case ACTION_OUI_TOKEN: + valid = validate_and_convert_oui(token, &ext, + &action_token); + break; + + case ACTION_OUI_DATA_LENGTH_TOKEN: + valid = validate_and_convert_data_length(token, &ext, + &action_token); + break; + + case ACTION_OUI_DATA_TOKEN: + valid = validate_and_convert_data(token, &ext, + &action_token); + break; + + case ACTION_OUI_DATA_MASK_TOKEN: + valid = validate_and_convert_data_mask(token, &ext, + &action_token); + break; + + case ACTION_OUI_INFO_MASK_TOKEN: + valid = validate_and_convert_info_mask(token, &ext, + &action_token); + break; + + case ACTION_OUI_MAC_ADDR_TOKEN: + valid = validate_and_convert_mac_addr(token, &ext, + &action_token); + break; + + case ACTION_OUI_MAC_MASK_TOKEN: + valid = validate_and_convert_mac_mask(token, &ext, + &action_token); + break; + + case ACTION_OUI_CAPABILITY_TOKEN: + valid = validate_and_convert_capability(token, &ext, + &action_token); + break; + + default: + valid = false; + break; + } + + if (!valid) { + action_oui_err("Invalid string for token: %s at extension: %u in action oui: %u", + action_oui_token_string(action_token), + oui_index + 1, + action_id); + break; + } + + if (action_token != ACTION_OUI_END_TOKEN) + continue; + + status = action_oui_extension_store(psoc_priv, oui_priv, ext); + if (!QDF_IS_STATUS_SUCCESS(status)) { + valid = false; + action_oui_err("sme set of extension: %u for action oui: %u failed", + oui_index + 1, action_id); + break; + } + + if (action_id >= ACTION_OUI_HOST_ONLY) { + qdf_mutex_acquire(&oui_priv->extension_lock); + psoc_priv->host_only_extensions++; + qdf_mutex_release(&oui_priv->extension_lock); + } + + oui_index++; + if (oui_index == ACTION_OUI_MAX_EXTENSIONS) { + if (str1) + oui_count_exceed = true; + break; + } + + /* reset the params for next action OUI parse */ + action_token = ACTION_OUI_TOKEN; + qdf_mem_zero(&ext, sizeof(ext)); + } + + if (oui_count_exceed) { + action_oui_err("Reached Maximum extensions: %u in action_oui: %u, ignoring the rest", + ACTION_OUI_MAX_EXTENSIONS, action_id); + return QDF_STATUS_SUCCESS; + } + + if (action_token != ACTION_OUI_TOKEN && + action_token != ACTION_OUI_END_TOKEN && + valid && !str1) { + action_oui_err("No string for token: %s at extension: %u in action oui: %u", + action_oui_token_string(action_token), + oui_index + 1, + action_id); + valid = false; + } + + if (!oui_index) { + action_oui_err("Not able to parse any extension in action oui: %u", + action_id); + return QDF_STATUS_E_INVAL; + } + + if (valid) + action_oui_debug("All extensions: %u parsed successfully in action oui: %u", + oui_index, action_id); + else + action_oui_err("First %u extensions parsed successfully in action oui: %u", + oui_index, action_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +action_oui_parse_string(struct wlan_objmgr_psoc *psoc, + const uint8_t *in_str, + enum action_oui_id action_id) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint8_t *oui_str; + int len; + + ACTION_OUI_ENTER(); + + if (!psoc) { + action_oui_err("psoc is NULL"); + goto exit; + } + + if (action_id >= ACTION_OUI_MAXIMUM_ID) { + action_oui_err("Invalid action_oui id: %u", action_id); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + len = qdf_str_len(in_str); + if (len <= 0 || len > ACTION_OUI_MAX_STR_LEN - 1) { + action_oui_err("Invalid string length: %u", action_id); + goto exit; + } + + oui_str = qdf_mem_malloc(len + 1); + if (!oui_str) { + status = QDF_STATUS_E_NOMEM; + goto exit; + } + + qdf_mem_copy(oui_str, in_str, len); + oui_str[len] = '\0'; + + status = action_oui_parse(psoc_priv, oui_str, action_id); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("Failed to parse: %u", action_id); + + qdf_mem_free(oui_str); + +exit: + ACTION_OUI_EXIT(); + return status; +} + +QDF_STATUS action_oui_send(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id) +{ + QDF_STATUS status; + struct action_oui_request *req; + struct action_oui_priv *oui_priv; + struct action_oui_extension *extension; + struct action_oui_extension_priv *ext_priv; + qdf_list_node_t *node = NULL; + qdf_list_node_t *next_node = NULL; + qdf_list_t *extension_list; + uint32_t len; + uint32_t no_oui_extensions; + + oui_priv = psoc_priv->oui_priv[action_id]; + if (!oui_priv) + return QDF_STATUS_SUCCESS; + + if (!psoc_priv->action_oui_enable) { + action_oui_debug("action_oui is not enable"); + return QDF_STATUS_SUCCESS; + } + + extension_list = &oui_priv->extension_list; + qdf_mutex_acquire(&oui_priv->extension_lock); + + if (psoc_priv->max_extensions - + (psoc_priv->total_extensions - psoc_priv->host_only_extensions) < 0) { + action_oui_err("total_extensions: %d exceeds max_extensions: %d, do not update", + psoc_priv->max_extensions, + (psoc_priv->total_extensions - + psoc_priv->host_only_extensions)); + qdf_mutex_release(&oui_priv->extension_lock); + return QDF_STATUS_E_FAILURE; + } + + no_oui_extensions = qdf_list_size(extension_list); + len = sizeof(*req) + no_oui_extensions * sizeof(*extension); + req = qdf_mem_malloc(len); + if (!req) { + qdf_mutex_release(&oui_priv->extension_lock); + return QDF_STATUS_E_NOMEM; + } + + req->action_id = oui_priv->id; + req->no_oui_extensions = no_oui_extensions; + req->total_no_oui_extensions = psoc_priv->max_extensions; + + extension = req->extension; + qdf_list_peek_front(extension_list, &node); + while (node) { + ext_priv = qdf_container_of(node, + struct action_oui_extension_priv, + item); + *extension = ext_priv->extension; + status = qdf_list_peek_next(extension_list, node, + &next_node); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + node = next_node; + next_node = NULL; + extension++; + } + + qdf_mutex_release(&oui_priv->extension_lock); + + status = tgt_action_oui_send(psoc_priv->psoc, req); + qdf_mem_free(req); + + return status; +} + +/** + * check_for_vendor_oui_data() - compares for vendor OUI data from IE + * and returns true if OUI data matches with the ini + * @extension: pointer to action oui extension data + * @oui_ptr: pointer to Vendor IE in the beacon + * + * Return: true or false + */ +static bool +check_for_vendor_oui_data(struct action_oui_extension *extension, + const uint8_t *oui_ptr) +{ + const uint8_t *data; + uint8_t i, j, elem_len, data_len; + uint8_t data_mask = 0x80; + + if (!oui_ptr) + return false; + + elem_len = oui_ptr[1]; + if (elem_len < extension->oui_length) + return false; + + data_len = elem_len - extension->oui_length; + if (data_len < extension->data_length) + return false; + + data = &oui_ptr[2 + extension->oui_length]; + for (i = 0, j = 0; + (i < data_len && j < extension->data_mask_length); + i++) { + if ((extension->data_mask[j] & data_mask) && + !(extension->data[i] == data[i])) + return false; + data_mask = data_mask >> 1; + if (!data_mask) { + data_mask = 0x80; + j++; + } + } + + return true; +} + +/** + * check_for_vendor_ap_mac() - compares for vendor AP MAC in the ini with + * bssid from the session and returns true if matches + * @extension: pointer to action oui extension data + * @attr: pointer to structure containing mac_addr (bssid) of AP + * + * Return: true or false + */ +static bool +check_for_vendor_ap_mac(struct action_oui_extension *extension, + struct action_oui_search_attr *attr) +{ + uint8_t i; + uint8_t mac_mask = 0x80; + uint8_t *mac_addr = attr->mac_addr; + + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + if ((*extension->mac_mask & mac_mask) && + !(extension->mac_addr[i] == mac_addr[i])) + return false; + mac_mask = mac_mask >> 1; + } + + return true; +} + +/** + * check_for_vendor_ap_capabilities() - Compares various Vendor AP + * capabilities like NSS, HT, VHT, Band from the ini with the AP's capability + * from the beacon and returns true if all the capability matches + * @extension: pointer to oui extension data + * @attr: pointer to structure containing type of action, ap capabilities + * + * Return: true or false + */ +static bool +check_for_vendor_ap_capabilities(struct action_oui_extension *extension, + struct action_oui_search_attr *attr) +{ + uint8_t nss_mask; + + if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_NSS) { + nss_mask = 1 << (attr->nss - 1); + if (!((*extension->capability & + ACTION_OUI_CAPABILITY_NSS_MASK) & + nss_mask)) + return false; + } + + if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_HT) { + if (*extension->capability & + ACTION_OUI_CAPABILITY_HT_ENABLE_MASK) { + if (!attr->ht_cap) + return false; + } else { + if (attr->ht_cap) + return false; + } + } + + if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_VHT) { + if (*extension->capability & + ACTION_OUI_CAPABILITY_VHT_ENABLE_MASK) { + if (!attr->vht_cap) + return false; + } else { + if (attr->vht_cap) + return false; + } + } + + if (extension->info_mask & ACTION_OUI_INFO_AP_CAPABILITY_BAND && + ((attr->enable_5g && + !(*extension->capability & ACTION_CAPABILITY_5G_BAND_MASK)) || + (attr->enable_2g && + !(*extension->capability & ACTION_OUI_CAPABILITY_2G_BAND_MASK)))) + return false; + + return true; +} + +static const uint8_t * +action_oui_get_oui_ptr(struct action_oui_extension *extension, + struct action_oui_search_attr *attr) +{ + if (!attr->ie_data || !attr->ie_length) + return NULL; + + return wlan_get_vendor_ie_ptr_from_oui(extension->oui, + extension->oui_length, + attr->ie_data, + attr->ie_length); +} + +bool +action_oui_is_empty(struct action_oui_psoc_priv *psoc_priv, + enum action_oui_id action_id) +{ + struct action_oui_priv *oui_priv; + qdf_list_t *extension_list; + + oui_priv = psoc_priv->oui_priv[action_id]; + if (!oui_priv) + return true; + + extension_list = &oui_priv->extension_list; + qdf_mutex_acquire(&oui_priv->extension_lock); + if (qdf_list_empty(extension_list)) { + qdf_mutex_release(&oui_priv->extension_lock); + return true; + } + qdf_mutex_release(&oui_priv->extension_lock); + + return false; +} + +static bool validate_vendor_oui_data(struct action_oui_extension *extension, + struct action_oui_search_attr *attr) +{ + uint8_t elem_id, elem_len; + int32_t left; + uint8_t eid = WLAN_MAC_EID_VENDOR; + const uint8_t *ptr = NULL; + const uint8_t *oui = extension->oui; + + if (!attr->ie_data || !attr->ie_length || !oui) + return false; + + ptr = attr->ie_data; + left = attr->ie_length; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + + if (elem_len > left) + return false; + + if (eid == elem_id) { + /* + * if oui is provided and oui_size is more than left + * bytes, then we cannot have match + */ + if (extension->oui_length > left) + return false; + + if (qdf_mem_cmp(&ptr[2], extension->oui, + extension->oui_length) == 0 && + check_for_vendor_oui_data(extension, ptr)) + return true; + } + + left -= elem_len; + ptr += (elem_len + 2); + } + + return false; +} + +bool +action_oui_search(struct action_oui_psoc_priv *psoc_priv, + struct action_oui_search_attr *attr, + enum action_oui_id action_id) +{ + struct action_oui_priv *oui_priv; + struct action_oui_extension_priv *priv_ext; + struct action_oui_extension *extension; + qdf_list_node_t *node = NULL; + qdf_list_node_t *next_node = NULL; + qdf_list_t *extension_list; + QDF_STATUS qdf_status; + const uint8_t *oui_ptr; + bool wildcard_oui = false; + + oui_priv = psoc_priv->oui_priv[action_id]; + if (!oui_priv) { + action_oui_debug("action oui for id %d is empty", + action_id); + return false; + } + + extension_list = &oui_priv->extension_list; + qdf_mutex_acquire(&oui_priv->extension_lock); + if (qdf_list_empty(extension_list)) { + qdf_mutex_release(&oui_priv->extension_lock); + return false; + } + + qdf_list_peek_front(extension_list, &node); + while (node) { + priv_ext = qdf_container_of(node, + struct action_oui_extension_priv, + item); + extension = &priv_ext->extension; + + /* + * If a wildcard OUI bit is not set in the info_mask, proceed + * to other checks skipping the OUI and vendor data checks + */ + + if (!(extension->info_mask & ACTION_OUI_INFO_OUI)) + wildcard_oui = true; + + oui_ptr = action_oui_get_oui_ptr(extension, attr); + + if (!oui_ptr && !wildcard_oui) + goto next; + + if (extension->data_length && !wildcard_oui && + !validate_vendor_oui_data(extension, attr)) + goto next; + + if ((extension->info_mask & ACTION_OUI_INFO_MAC_ADDRESS) && + !check_for_vendor_ap_mac(extension, attr)) + goto next; + + if (!check_for_vendor_ap_capabilities(extension, attr)) + goto next; + + action_oui_debug("Vendor AP/STA found for OUI"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + extension->oui, extension->oui_length); + qdf_mutex_release(&oui_priv->extension_lock); + return true; +next: + qdf_status = qdf_list_peek_next(extension_list, + node, &next_node); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + break; + + node = next_node; + next_node = NULL; + wildcard_oui = false; + } + + qdf_mutex_release(&oui_priv->extension_lock); + return false; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h new file mode 100644 index 0000000000..115c0d195d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_cfg.h @@ -0,0 +1,914 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of action oui configuration. + */ +#ifndef __WLAN_ACTION_OUI_CFG_H__ +#define __WLAN_ACTION_OUI_CFG_H__ +/* + * Start of action oui inis + * + * To enable action oui feature, set gEnableActionOUI + * + * Each action oui is expected in the following format: + * ..... (maximum 10) + * + * whereas, each Extension is separated by space and have the following format: + * + * where each Token is a string of hexa-decimal digits and + * following are the details about each token + * + * Token1 = OUI + * Token2 = Data_Length + * Token3 = Data + * Token4 = Data_Mask + * Token5 = Info_Presence_Bit + * Token6 = MAC_Address + * Token7 = Mac_Address Mask + * Token8 = Capability + * + * is mandatory and it can be either 3 or 5 bytes means 6 or 10 + * hexa-decimal characters + * If the OUI and Data checks needs to be ignored, the oui FFFFFF + * needs to be provided as OUI and bit 0 of Info_Presence_Bit should + * be set to 0. + * + * is mandatory field and should give length of + * the if present else zero + * + * Presence of is controlled by , if is 0, + * then is not expected else Data of the size Data Length bytes are + * expected which means the length of Data string is 2 * Data Length, + * since every byte constitutes two hexa-decimal characters. + * + * is mandatory if is present and length of the + * Data mask string depends on the + * If is 06, then length of Data Mask string is + * 2 characters (represents 1 byte) + * data_mask_length = ((Data_Length - (Data_Length % 8)) / 8) + + * ((Data_Length % 8) ? 1 : 0) + * and has to be constructed from left to right. + * + * Presence of and is + * controlled by which is mandatory + * will give the information for + * OUI – bit 0 Should be set to 1 + * Setting to 0 will ignore OUI and data check + * Mac Address present – bit 1 + * NSS – bit 2 + * HT check – bit 3 + * VHT check – bit 4 + * Band info – bit 5 + * reserved – bit 6 (should always be zero) + * reserved – bit 7 (should always be zero) + * and should be constructed from right to left (b7b6b5b4b3b2b1b0) + * + * for should be constructed from left to right + * + * is 1 byte long and it contains the below info + * NSS – 4 bits starting from LSB (b0 – b3) + * HT enabled – bit 4 + * VHT enabled – bit 5 + * 2G band – bit 6 + * 5G band – bit 7 + * and should be constructed from right to left (b7b6b5b4b3b2b1b0) + * is present if at least one of the bit is set + * from b2 - b6 in + * + * Example 1: + * + * OUI is 00-10-18, data length is 05 (hex form), data is 02-11-04-5C-DE and + * need to consider first 3 bytes and last byte of data for comparison + * mac-addr EE-1A-59-FE-FD-AF is present and first 3 bytes and last byte of + * mac address should be considered for comparison + * capability is not present + * then action OUI for gActionOUIITOExtension is as follows: + * + * gActionOUIITOExtension=001018 05 0211045CDE E8 03 EE1A59FEFDAF E4 + * + * data mask calculation in above example: + * Data[0] = 02 ---- d0 = 1 + * Data[1] = 11 ---- d1 = 1 + * Data[2] = 04 ---- d2 = 1 + * Data[3] = 5C ---- d3 = 0 + * Data[4] = DE ---- d4 = 1 + * data_mask = d0d1d2d3d4 + append with zeros to complete 8-bit = 11101000 = E8 + * + * mac mask calculation in above example: + * mac_addr[0] = EE ---- m0 = 1 + * mac_addr[1] = 1A ---- m1 = 1 + * mac_addr[2] = 59 ---- m2 = 1 + * mac_addr[3] = FE ---- m3 = 0 + * mac_addr[4] = FD ---- m4 = 0 + * mac_addr[5] = AF ---- m5 = 1 + * mac_mask = m0m1m2m3m4m5 + append with zeros to complete 8-bit = 11100100 = E4 + * + * Example 2: + * + * OUI is 00-10-18, data length is 00 and no Mac Address and capability + * + * gActionOUIITOExtension=001018 00 01 + * + */ + +/* + * + * gEnableActionOUI - Enable/Disable action oui feature + * @Min: 0 (disable) + * @Max: 1 (enable) + * @Default: 1 (enable) + * + * This ini is used to enable the action oui feature to control + * mode of connection, connected AP's in-activity time, Tx rate etc., + * + * Related: If gEnableActionOUI is set, then at least one of the following inis + * must be set with the proper action oui extensions: + * gActionOUIConnect1x1, gActionOUIITOExtension, gActionOUICCKM1X1 + * + * Supported Feature: action ouis + * + * Usage: External + * + * + */ +#define CFG_ENABLE_ACTION_OUI CFG_INI_BOOL( \ + "gEnableActionOUI", \ + 1, \ + "Enable/Disable action oui feature") + +/* + * + * gActionOUIConnect1x1 - Used to specify action OUIs for 1x1 connection + * @Default: 000C43 00 25 C2 001018 06 02FFF02C0000 BC 25 42 001018 06 02FF040C0000 BC 25 42 00037F 00 35 6C 001018 06 02FF009C0000 BC 25 48 + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * Default OUIs: (All values in Hex) + * OUI 1 : 000C43 + * OUI data Len : 00 + * Info Mask : 25 - Check for NSS and Band + * Capabilities: C2 - NSS == 2 && Band == 2G || Band == 5G + * OUI 2 : 001018 + * OUI data Len : 06 + * OUI Data : 02FFF02C0000 + * OUI data Mask: BC - 10111100 + * Info Mask : 25 - Check for NSS and Band + * Capabilities: 42 - NSS == 2 && Band == 2G + * OUI 3 : 001018 + * OUI data Len : 06 + * OUI Data : 02FF040C0000 + * OUI data Mask: BC - 10111100 + * Info Mask : 25 - Check for NSS and Band + * Capabilities: 42 - NSS == 2 && Band == 2G + * OUI 4 : 00037F + * OUI data Len : 00 + * Info Mask : 35 - Check for NSS, VHT Caps and Band + * Capabilities: 6C - (NSS == 3 or 4) && VHT Caps Preset && Band == 2G + * OUI 5 : 001018 + * OUI data Len : 06 + * OUI Data : 02FF009C0000 + * OUI data Mask: BC - 10111100 + * Info Mask : 25 - Check for NSS and Band + * Capabilities: 48 - NSS == 4 && Band == 2G + * + * This ini is used to specify the AP OUIs with which only 1x1 connection + * is allowed. + * + * Related: None + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_CONNECT_1X1 CFG_INI_STRING( \ + "gActionOUIConnect1x1", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "000C43 00 25 C2 001018 06 02FFF02C0000 BC 25 42 001018 06 02FF040C0000 BC 25 42 00037F 00 35 6C 001018 06 02FF009C0000 BC 25 48", \ + "Used to specify action OUIs for 1x1 connection") + +/* + * + * gActionOUIITOExtension - Used to extend in-activity time for specified APs + * @Default: 00037F 06 01010000FF7F FC 01 000AEB 02 0100 C0 01 000B86 03 010408 E0 01 + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * Default OUIs: (All values in Hex) + * OUI 1: 00037F + * OUI data Len: 06 + * OUI Data: 01010000FF7F + * OUI data Mask: FC - 11111100 + * Info Mask : 01 - only OUI present in Info mask + * + * OUI 2: 000AEB + * OUI data Len: 02 + * OUI Data: 0100 + * OUI data Mask: C0 - 11000000 + * Info Mask : 01 - only OUI present in Info mask + * + * OUI 3: 000B86 + * OUI data Len: 03 + * OUI Data: 010408 + * OUI data Mask: E0 - 11100000 + * Info Mask : 01 - only OUI present in Info mask + * + * This ini is used to specify AP OUIs using which station's in-activity time + * can be extended with the respective APs + * + * Related: None + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_ITO_EXTENSION CFG_INI_STRING( \ + "gActionOUIITOExtension", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "00037F 06 01010000FF7F FC 01 000AEB 02 0100 C0 01 000B86 03 010408 E0 01", \ + "Used to extend in-activity time for specified APs") + +/* + * + * gActionOUICCKM1X1 - Used to specify action OUIs to control station's TX rates + * + * This ini is used to specify AP OUIs for which station's CCKM TX rates + * should be 1x1 only. + * + * Related: None + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_CCKM_1X1 CFG_INI_STRING( \ + "gActionOUICCKM1X1", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Used to specify action OUIs to control station's TX rates") + +/* + * + * gActionOUIITOAlternate - Used to specify action OUIs to have alternate ITO in + * weak RSSI state + * + * This ini is used to specify AP OUIs for which the stations will have + * alternate ITOs for the case when the RSSI is weak. + * + * Related: None + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_ITO_ALTERNATE CFG_INI_STRING( \ + "gActionOUIITOAlternate", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "001018 06 0202001c0000 FC 01", \ + "Used to specify action OUIs to have alternate ITO") + +/* + * + * gActionOUISwitchTo11nMode - Used to specify action OUIs for switching to 11n + * + * This ini is used to specify which AP for which the connection has to be + * made in 2x2 mode with HT capabilities only and not VHT. + * + * Default OUIs: (All values in Hex) + * OUI 1 : 00904C + * OUI data Len : 03 + * OUI Data : 0418BF + * OUI data Mask: E0 - 11100000 + * Info Mask : 21 - Check for Band + * Capabilities: 40 - Band == 2G + * + * Related: None + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_SWITCH_TO_11N_MODE CFG_INI_STRING( \ + "gActionOUISwitchTo11nMode", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "00904C 05 0418BF0CB2 F8 21 40", \ + "Used to specify action OUIs for switching to 11n") + +/* + * + * gActionOUIConnect1x1with1TxRxChain - Used to specify action OUIs for + * 1x1 connection with one Tx/Rx Chain + * @Default: + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * Default OUIs: (All values in Hex) + * OUI 1 : 001018 + * OUI data Len : 06 + * OUI Data : 02FFF0040000 + * OUI data Mask: BC - 10111100 + * Info Mask : 21 - Check for Band + * Capabilities: 40 - Band == 2G + * + * OUI 2 : 001018 + * OUI data Len : 06 + * OUI Data : 02FFF0050000 + * OUI data Mask: BC - 10111100 + * Info Mask : 21 - Check for Band + * Capabilities: 40 - Band == 2G + * + * OUI 3 : 001018 + * OUI data Len : 06 + * OUI Data : 02FFF4050000 + * OUI data Mask: BC - 10111100 + * Info Mask : 21 - Check for Band + * Capabilities: 40 - Band == 2G + * + * This ini is used to specify the AP OUIs with which only 1x1 connection + * with one Tx/Rx Chain is allowed. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN CFG_INI_STRING( \ + "gActionOUIConnect1x1with1TxRxChain", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "001018 06 02FFF0040000 BC 21 40 001018 06 02FFF0050000 BC 21 40 001018 06 02FFF4050000 BC 21 40", \ + "Used to specify action OUIs for 1x1 connection with one Tx/Rx Chain") + +/* + * + * gActionOUIDisableAggressiveTX - Used to specify action OUIs to disable + * Aggressive TX feature when operating in softap. + * + * @Default: + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * Default OUIs: + * + * OUI 1 : FFFFFF + * OUI data Len : 00 + * OUI Data: No data + * OUI data Mask: No data mask + * Info Mask: 2A - Check for mac-addr, HT capability and Band + * Mac-addr: F8:59:71:00:00:00 - first 3 bytes + * Mac-mask: E0 - Match only first 3 bytes of peer mac-addr + * Capabilities: 50 – HT should be enabled, and band should be 2.4GHz + * + * OUI 2 : FFFFFF + * OUI data Len : 00 + * OUI Data: No data + * OUI data Mask: No data mask + * Info Mask: 2A - Check for mac-addr, HT capability and Band + * Mac-addr: 14:AB:C5:00:00:00 - first 3 bytes + * Mac-mask: E0 - Match only first 3 bytes of peer mac-addr + * Capabilities: 50 – HT should be enabled, and band should be 2.4GHz + * + * When operating in Softap mode, this ini is used to specify + * STA (peer) OUIs/mac-addr for which aggressive tx is disabled after + * association is successful. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX CFG_INI_STRING( \ + "gActionOUIDisableAggressiveTX", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "FFFFFF 00 2A F85971000000 E0 50 FFFFFF 00 2A 14ABC5000000 E0 50", \ + "Used to specify action OUIs to disable aggressive TX") + +/* + * + * gActionOUIDisableAggressiveEDCA - Used to specify action OUIs to control + * EDCA configuration when join the candidate AP + * + * @Default: NULL + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * This ini is used to specify AP OUIs. The station's EDCA should follow the + * APs' when connecting to those AP, even if the gEnableEdcaParams is set. + * For example, it follows the AP's EDCA whose OUI is 0050F2 with the + * following setting: + * gActionOUIDisableAggressiveEDCA=0050F2 00 01 + * Explain: 0050F2: OUI + * 00: data length is 0 + * 01: info mask, only OUI present in Info mask + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableEdcaParams, gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_DISABLE_AGGRESSIVE_EDCA CFG_INI_STRING( \ + "gActionOUIDisableAggressiveEDCA", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Used to specify action OUIs to control edca configuration") + +/* + * + * gActionOUIExtendWowITO - Used to extend ITO(Inactivity Time-Out) value under + * WoWLAN mode for specified APs. + * + * @Default: NULL + * + * Some APs sometimes don't honor Qos null frames under WoWLAN mode if + * station's ITO is too small. This ini is used to specify AP OUIs which + * exhibit this behavior. When connected to such an AP, the station's ITO + * value will be extended when in WoWLAN mode. + * For example, it extends the ITO value(under WoWLAN mode) when connected + * to AP whose OUI is 001018 and vendor specific data is 0201009C0000 with + * the following setting: + * gActionOUIExtendWowITO=001018 06 0201009C0000 FC 01 + * OUI: 001018 + * OUI data Len : 06 + * OUI Data : 0201009C0000 + * OUI data Mask: FC - 11111100 + * Info Mask : 01 - only OUI present in Info mask + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_EXTEND_WOW_ITO CFG_INI_STRING( \ + "gActionOUIExtendWowITO", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Used to extend inactivity time out under WoWLAN mode for specified APs") + +/* + * + * gActionOUIReconnAssocTimeout - Used to specify action OUIs to + * reconnect to same BSSID when wait for association response timeout + * + * This ini is used to specify AP OUIs. Some of AP doesn't response our + * first association request, but it would response our second association + * request. Add such OUI configuration INI to apply reconnect logic when + * association timeout happends with such AP. + * For default: + * gActionOUIReconnAssocTimeout=00E04C 00 01 + * Explain: 00E04C: OUI + * 00: data length is 0 + * 01: info mask, only OUI present in Info mask + * Note: User should strictly add new action OUIs at the end of this + * default value. + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_RECONN_ASSOCTIMEOUT CFG_INI_STRING( \ + "gActionOUIReconnAssocTimeout", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "00E04C 00 01", \ + "Used to specify action OUIs to reconnect when assoc timeout") + +/* + * + * gActionOUIDisableTWT - Used to specify action OUIs to control TWT param + * while joining the candidate AP + * + * This ini is used to specify AP OUIs. Some APs advertise TWT but do not + * follow through when the STA reaches out to them. Thus, TWT will be + * disabled when we receive OUIs of those APs. + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * Default OUIs: (All values in Hex) + * OUI 1: 001018 + * OUI data Len: 00 + * Info Mask : 01 - only OUI present in Info mask + * + * OUI 2: 000986 + * OUI data Len: 00 + * Info Mask : 01 - only OUI present in Info mask + * + * OUI 3: 000ce7 + * OUI data Len: 00 + * Info Mask : 01 - only OUI present in Info mask + * + * OUI 4: 00e0fc + * OUI data Len: 00 + * Info Mask : 01 - only OUI present in Info mask + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_DISABLE_TWT CFG_INI_STRING( \ + "gActionOUIDisableTWT", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "001018 00 01 000986 00 01 000ce7 00 01 00e0fc 00 01", \ + "Used to specify action OUIs to control TWT configuration") + +/* + * + * gActionOUITakeAllBandInfo - Used to specify action OUIs to check + * whether country ie need take all band channel information. + * + * This ini is used to specify STA association request OUIs. Some STA + * need AP country ie take all band channel information when do BSS + * transition across band. Thus, AP will take all band channel info + * when we receive association request with this OUIs. + * Note: User should strictly add new action OUIs at the end of this + * default value. + * + * Default OUIs: (All values in Hex) + * OUI 1: 0017f2 + * OUI data Len: 01 + * OUI Data : 0a + * OUI data Mask: 80 - 10000000 + * Info Mask : 01 - only OUI present in Info mask + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_TAKE_ALL_BAND_INFO CFG_INI_STRING( \ + "gActionOUITakeAllBandInfo", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "0017f2 01 0a 80 01", \ + "Used to specify action OUIs to control country ie") + +/* + * + * g11be_oui_allow_list - Used to specify 802.11be allowed ap oui list + * + * This ini is used to specify AP OUIs for which station can connect + * in 802.11be mode with the 802.11be AP. + * If no OUI set, then allow STA to connect to All 802.11be AP in 802.11be + * mode. + * If INI is set to "ffffff 00 01", then STA is not allowed to connect to + * any AP in 802.11be mode. + * + * Related: None + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_11BE_ALLOW_LIST CFG_INI_STRING( \ + "g11be_oui_allow_list", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Used to specify 11be allowed ap oui list") + +/* + * + * gActionOUIDisableDynamicQosNullTxRate - Used to turn off FW's dynamic qos + * null tx rate feature if specific vendor OUI received in beacon + * + * Some APs sometimes don't honor Qos null frames with some specific rate. + * This ini will disable dynamic qos null tx rate feature for specified APs. + * + * Default OUIs: (All values in Hex) + * OUI 1: 00e04c + * OUI data Len: 03 + * OUI Data : 020160 + * OUI data Mask: E0 - 11100000 + * Info Mask : 01 - only OUI present in Info mask + * + * OUI 2: 001018 + * OUI data Len : 06 + * OUI Data : 02FF009C0000 + * OUI data Mask: BC - 10111100 + * Info Mask : 01 - only OUI present in Info mask + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE CFG_INI_STRING( \ + "gActionOUIDisableDynamicQosNullTxRate", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "00e04c 03 020160 E0 01 001018 06 02FF009c0000 BC 01", \ + "Used to turn off FW's dynamic qos null tx rate for specified APs") + +/* + * + * gActionOUIAuthAssoc6Mbps2GHz - Used to send auth/assoc req with 6 Mbps rate + * on 2.4 GHz for specified AP + * + * Some AP sometimes doesn't honor auth/assoc with CCK rate. + * This ini will provide 6 Mbps rate for auth/assoc in 2.4 GHz. + * + * Example OUIs: (All values in Hex) + * OUI 1: 000c43 + * OUI data Len: 04 + * OUI Data : 03000000 + * OUI data Mask: F0 - 11110000 + * Info Mask : 01 - only OUI present in Info mask + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ CFG_INI_STRING( \ + "gActionOUIAuthAssoc6Mbps2GHz", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "send auth/assoc req with 6 Mbps rate on 2.4 GHz for specified APs") + +/* + * + * CFG_ACTION_OUI_DISABLE_BFORMEE - Used to disable SU/MU beamformee + * capability for specified AP with some conditions + * + * Example OUIs: (All values in Hex) + * OUI 1: 000c43 + * OUI data Len: 04 + * OUI Data : 03000000 + * OUI data Mask: F0 - 11110000 + * Info Mask : 01 - only OUI present in Info mask + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_DISABLE_BFORMEE CFG_INI_STRING( \ + "gActionOUIDisableBFORMEE", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "disable SU/MU beamformee capability for specified AP") + +/* + * + * gActionOUIEnableCTS2SelfWithQoSNull - Used to enable CTS2SELF with QoS null + * frame for specified APs + * + * Sample OUIs: (All values in Hex) + * OUI 1: 000c43 + * OUI data Len: 04 + * OUI Data : 03000000 + * OUI data Mask: F0 - 11110000 + * Info Mask : 01 - only OUI present in Info mask + * + * gActionOUIEnableCTS2SelfWithQoSNull=000c43 04 03000000 F0 01 + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL CFG_INI_STRING( \ + "gActionOUIEnableCTS2SelfWithQoSNull", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Used to enable CTS2SELF with QoS null frame for specified APs") + +/* + * + * g_action_oui_enable_cts_2_self - Used to enable CTS2SELF for specified APs + * + * Default OUIs: (All values in Hex) + * OUI 1: 000C43 + * OUI data Len: 04 + * OUI Data : 07000000 + * OUI data Mask: F0 - 11110000 + * Info Mask : 21 - 0010 0001 Check for OUI and Band + * Capabilities: C0 - 1100 0000 Band == 2 GHz || Band == 5 GHz + * + * OUI 2 : 000C43 + * OUI data Len : 04 + * OUI Data : 03000000 + * OUI data Mask: F0 - 11110000 + * Info Mask : 21 - 0010 0001 Check for OUI and Band + * Capabilities: C0 - 1100 0000 Band == 2 GHz || Band == 5 GHz + * + * g_action_oui_enable_cts_2_self=000C43 04 07000000 F0 21 C0 000C43 04 03000000 F0 21 C0 + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_ENABLE_CTS2SELF CFG_INI_STRING( \ + "g_action_oui_enable_cts_2_self", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "000C43 04 07000000 F0 21 C0 000C43 04 03000000 F0 21 C0", \ + "Used to enable CTS2SELF frame for specified APs") + +/* + * + * gActionOUISendSMPSFrameWithOMN - Used to send SMPS frame along with OMN + * for specified APs + * + * Sample OUIs: (All values in Hex) + * OUI 1: 000ce7 + * OUI data Len: 04 + * OUI Data : 88000000 + * OUI data Mask: F0 - 11110000 + * Info Mask : 01 - only OUI present in Info mask + * + * gActionOUISendSMPSFrameWithOMN=000ce7 04 88000000 F0 01 + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN CFG_INI_STRING( \ + "gActionOUISendSMPSFrameWithOMN", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Used to send SMPS frame along with OMN for specified APs") + +/* + * + * gActionOUIRestrictMaxMLOLinks - Used to downgrade 3 link to 2 link ML + * connection for specific AP build version. + * + * Sample OUIs: (All values in Hex) + * OUI 3 : 8CFDF0 + * OUI data Len : 13 + * OUI Data : 040000494c510302097201cb17000009110000 + * OUI data Mask: FFFFE0 - 1111 1111 1111 1111 1110 0000 + * Info Mask : 01 - only OUI present in Info mask + * + * gActionOUIRestrictMaxMLOLinks=8CFDF0 13 040000494c510c00203000cb17000009110000 FFFFE0 01 + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS CFG_INI_STRING( \ + "gActionOUIRestrictMaxMLOLinks", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "8CFDF0 13 040000494c510302097201cb17000009110000 FFFFE0 01", \ + "To restrict matching OUI APs to two link connection at max") + +/* + * + * CFG_ACTION_OUI_LIMIT_BW - Used to limit BW for specified AP + * + * Example OUIs: (All values in Hex) + * OUI 1: 00904c + * OUI data Len: 04 + * OUI Data : 0201009C + * OUI data Mask: F0 - 11110000 + * Info Mask : 01 - only OUI present in Info mask + * + * Refer to gEnableActionOUI for more detail about the format. + * + * Related: gEnableActionOUI + * + * Supported Feature: Action OUIs + * + * Usage: External + * + * + */ +#define CFG_ACTION_OUI_LIMIT_BW CFG_INI_STRING( \ + "gActionOUILimitBW", \ + 0, \ + ACTION_OUI_MAX_STR_LEN, \ + "", \ + "Limit BW for specified AP") + +#define CFG_ACTION_OUI \ + CFG(CFG_ACTION_OUI_CCKM_1X1) \ + CFG(CFG_ACTION_OUI_CONNECT_1X1) \ + CFG(CFG_ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN) \ + CFG(CFG_ACTION_OUI_ITO_ALTERNATE) \ + CFG(CFG_ACTION_OUI_ITO_EXTENSION) \ + CFG(CFG_ACTION_OUI_DISABLE_AGGRESSIVE_TX) \ + CFG(CFG_ACTION_OUI_DISABLE_AGGRESSIVE_EDCA) \ + CFG(CFG_ACTION_OUI_EXTEND_WOW_ITO) \ + CFG(CFG_ACTION_OUI_SWITCH_TO_11N_MODE) \ + CFG(CFG_ACTION_OUI_RECONN_ASSOCTIMEOUT) \ + CFG(CFG_ACTION_OUI_DISABLE_TWT) \ + CFG(CFG_ACTION_OUI_TAKE_ALL_BAND_INFO) \ + CFG(CFG_ACTION_OUI_11BE_ALLOW_LIST) \ + CFG(CFG_ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE) \ + CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF) \ + CFG(CFG_ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL) \ + CFG(CFG_ACTION_OUI_RESTRICT_MAX_MLO_LINKS) \ + CFG(CFG_ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN) \ + CFG(CFG_ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ) \ + CFG(CFG_ACTION_OUI_DISABLE_BFORMEE) \ + CFG(CFG_ACTION_OUI_LIMIT_BW) \ + CFG(CFG_ENABLE_ACTION_OUI) +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h new file mode 100644 index 0000000000..bda5443f7f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_public_struct.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare structs and macros which can be accessed by various + * components and modules. + */ + +#ifndef _WLAN_ACTION_OUI_PUBLIC_STRUCT_H_ +#define _WLAN_ACTION_OUI_PUBLIC_STRUCT_H_ + +#include +#include +#include + +/* + * Maximum ini string length of actions oui extensions, + * (n * 83) + (n - 1) spaces + 1 (terminating character), + * where n is the no of oui extensions + * currently, max no of oui extensions is 10 + */ +#define ACTION_OUI_MAX_STR_LEN 840 + +/* + * Maximum number of action oui extensions supported in + * each action oui category + */ +#define ACTION_OUI_MAX_EXTENSIONS 10 + +/* + * Firmware allocates memory for the extensions only during init time. + * Therefore, inaddition to the total extensions configured during + * init time, driver has to add extra space to allow runtime extensions. + * + * Example: ACTION_OUI_11BE_OUI_ALLOW + * + * Max. value should be increased with the addition of new runtime extensions. + */ +#define ACTION_OUI_MAX_ADDNL_EXTENSIONS 10 + +#define ACTION_OUI_MAX_OUI_LENGTH 5 +#define ACTION_OUI_MAX_DATA_LENGTH 20 +#define ACTION_OUI_MAX_DATA_MASK_LENGTH 3 +#define ACTION_OUI_MAC_MASK_LENGTH 1 +#define ACTION_OUI_MAX_CAPABILITY_LENGTH 1 + +/* + * NSS Mask and NSS Offset to extract NSS info from + * capability field of action oui extension + */ +#define ACTION_OUI_CAPABILITY_NSS_MASK 0x0f +#define ACTION_OUI_CAPABILITY_NSS_OFFSET 0 +#define ACTION_OUI_CAPABILITY_NSS_MASK_1X1 1 +#define ACTION_OUI_CAPABILITY_NSS_MASK_2X2 2 +#define ACTION_OUI_CAPABILITY_NSS_MASK_3X3 4 +#define ACTION_OUI_CAPABILITY_NSS_MASK_4X4 8 + +/* + * Mask and offset to extract HT and VHT info from + * capability field of action oui extension + */ +#define ACTION_OUI_CAPABILITY_HT_ENABLE_MASK 0x10 +#define ACTION_OUI_CAPABILITY_HT_ENABLE_OFFSET 4 +#define ACTION_OUI_CAPABILITY_VHT_ENABLE_MASK 0x20 +#define ACTION_OUI_CAPABILITY_VHT_ENABLE_OFFSET 5 + +/* + * Mask and offset to extract Band (2G and 5G) info from + * capability field of action oui extension + */ +#define ACTION_OUI_CAPABILITY_BAND_MASK 0xC0 +#define ACTION_OUI_CAPABILITY_BAND_OFFSET 6 +#define ACTION_OUI_CAPABILITY_2G_BAND_MASK 0x40 +#define ACTION_OUI_CAPABILITY_2G_BAND_OFFSET 6 +#define ACTION_CAPABILITY_5G_BAND_MASK 0x80 +#define ACTION_CAPABILITY_5G_BAND_OFFSET 7 + +/* Invalid OUI ID action */ +#define ACTION_OUI_INVALID "ffffff 00 01" + +/** + * enum action_oui_id - to identify type of action oui + * @ACTION_OUI_CONNECT_1X1: for 1x1 connection only + * @ACTION_OUI_ITO_EXTENSION: for extending inactivity time of station + * @ACTION_OUI_CCKM_1X1: for TX with CCKM 1x1 only + * @ACTION_OUI_ITO_ALTERNATE: alternate ITO extensions used by firmware + * @ACTION_OUI_SWITCH_TO_11N_MODE: connect in 11n + * @ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN: connect in 1x1 & disable diversity gain + * @ACTION_OUI_DISABLE_AGGRESSIVE_TX: disable aggressive TX in firmware + * @ACTION_OUI_DISABLE_AGGRESSIVE_EDCA: disable aggressive EDCA with the ap + * @ACTION_OUI_DISABLE_TWT: disable TWT with the ap + * @ACTION_OUI_EXTEND_WOW_ITO: extend ITO under WOW mode if vendor OUI is + * received in beacon. + * @ACTION_OUI_11BE_OUI_ALLOW: ap oui for which station can connect with + * 11be mode + * @ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE: Turn off FW's dynamic qos + * null tx rate feature if specific vendor OUI received in beacon + * @ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL: Enable CTS2SELF with QoS null + * frame for specified IoT APs. + * @ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN: Send SMPS frame along with OMN + * frame for specified IoT APs. + * @ACTION_OUI_HOST_ONLY: host only action id start - placeholder. + * New Firmware related "ACTION" needs to be added before this placeholder. + * @ACTION_OUI_HOST_RECONN: reconnect to the same BSSID when wait for + * association response timeout from AP + * @ACTION_OUI_TAKE_ALL_BAND_INFO: let AP country ie take all band info + * @ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ: send auth/assoc req with 6 Mbps rate + * on 2.4 GHz + * @ACTION_OUI_DISABLE_BFORMEE: disable SU/MU beam formee capability for + * specified AP + * @ACTION_OUI_ENABLE_CTS2SELF: enable cts to self for specified AP's + * @ACTION_OUI_RESTRICT_MAX_MLO_LINKS: Downgrade MLO if particular AP + * build present. + * @ACTION_OUI_LIMIT_BW: Limit BW if vendor OUI is received in beacon. + * @ACTION_OUI_MAXIMUM_ID: maximum number of action oui types + */ +enum action_oui_id { + ACTION_OUI_CONNECT_1X1 = 0, + ACTION_OUI_ITO_EXTENSION = 1, + ACTION_OUI_CCKM_1X1 = 2, + ACTION_OUI_ITO_ALTERNATE = 3, + ACTION_OUI_SWITCH_TO_11N_MODE = 4, + ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN = 5, + ACTION_OUI_DISABLE_AGGRESSIVE_TX = 6, + ACTION_OUI_DISABLE_TWT = 7, + ACTION_OUI_EXTEND_WOW_ITO = 8, + ACTION_OUI_11BE_OUI_ALLOW = 9, + ACTION_OUI_DISABLE_DYNAMIC_QOS_NULL_TX_RATE = 10, + ACTION_OUI_ENABLE_CTS2SELF_WITH_QOS_NULL = 11, + ACTION_OUI_SEND_SMPS_FRAME_WITH_OMN = 12, + /* host&fw interface add above here */ + + ACTION_OUI_HOST_ONLY, + ACTION_OUI_HOST_RECONN = ACTION_OUI_HOST_ONLY, + ACTION_OUI_TAKE_ALL_BAND_INFO, + ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ, + ACTION_OUI_DISABLE_BFORMEE, + ACTION_OUI_DISABLE_AGGRESSIVE_EDCA, + ACTION_OUI_ENABLE_CTS2SELF, + ACTION_OUI_RESTRICT_MAX_MLO_LINKS, + ACTION_OUI_LIMIT_BW, + ACTION_OUI_MAXIMUM_ID +}; + +/** + * enum action_oui_info - to indicate presence of various action OUI + * fields in action oui extension, following identifiers are to be set in + * the info mask field of action oui extension + * @ACTION_OUI_INFO_OUI: to indicate presence of OUI string + * @ACTION_OUI_INFO_MAC_ADDRESS: to indicate presence of mac address + * @ACTION_OUI_INFO_AP_CAPABILITY_NSS: to indicate presence of nss info + * @ACTION_OUI_INFO_AP_CAPABILITY_HT: to indicate presence of HT cap + * @ACTION_OUI_INFO_AP_CAPABILITY_VHT: to indicate presence of VHT cap + * @ACTION_OUI_INFO_AP_CAPABILITY_BAND: to indicate presence of band info + */ +enum action_oui_info { + /* + * OUI centric parsing, expect OUI in each action OUI extension, + * hence, ACTION_OUI_INFO_OUI is dummy + */ + ACTION_OUI_INFO_OUI = 1 << 0, + ACTION_OUI_INFO_MAC_ADDRESS = 1 << 1, + ACTION_OUI_INFO_AP_CAPABILITY_NSS = 1 << 2, + ACTION_OUI_INFO_AP_CAPABILITY_HT = 1 << 3, + ACTION_OUI_INFO_AP_CAPABILITY_VHT = 1 << 4, + ACTION_OUI_INFO_AP_CAPABILITY_BAND = 1 << 5, +}; + +/* Total mask of all enum action_oui_info IDs */ +#define ACTION_OUI_INFO_MASK 0x3F + +/** + * struct action_oui_extension - action oui extension contents + * @info_mask: info mask + * @oui_length: length of the oui, either 3 or 5 bytes + * @data_length: length of the oui data + * @data_mask_length: length of the data mask + * @mac_addr_length: length of the mac addr + * @mac_mask_length: length of the mac mask + * @capability_length: length of the capability + * @oui: oui value + * @data: data buffer + * @data_mask: data mask buffer + * @mac_addr: mac addr + * @mac_mask: mac mask + * @capability: capability buffer + */ +struct action_oui_extension { + uint32_t info_mask; + uint32_t oui_length; + uint32_t data_length; + uint32_t data_mask_length; + uint32_t mac_addr_length; + uint32_t mac_mask_length; + uint32_t capability_length; + uint8_t oui[ACTION_OUI_MAX_OUI_LENGTH]; + uint8_t data[ACTION_OUI_MAX_DATA_LENGTH]; + uint8_t data_mask[ACTION_OUI_MAX_DATA_MASK_LENGTH]; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t mac_mask[ACTION_OUI_MAC_MASK_LENGTH]; + uint8_t capability[ACTION_OUI_MAX_CAPABILITY_LENGTH]; +}; + +/** + * struct action_oui_request - Contains specific action oui information + * @action_id: type of action from enum action_oui_info + * @no_oui_extensions: number of action oui extensions of type @action_id + * @total_no_oui_extensions: total no of oui extensions from all + * action oui types, this is just a total count needed by firmware + * @extension: pointer to zero length array, to indicate this structure is + * followed by a array of @no_oui_extensions structures of + * type struct action_oui_extension + */ +struct action_oui_request { + enum action_oui_id action_id; + uint32_t no_oui_extensions; + uint32_t total_no_oui_extensions; + struct action_oui_extension extension[]; +}; + +/** + * struct action_oui_search_attr - Used to check against action_oui ini input + * + * @ie_data: beacon ie data + * @ie_length: length of ie data + * @mac_addr: bssid of access point + * @nss: AP spatial stream info + * @ht_cap: Whether AP is HT capable + * @vht_cap: Whether AP is VHT capable + * @enable_2g: Whether 2.4GHz band is enabled in AP + * @enable_5g: Whether 5GHz band is enabled in AP + */ +struct action_oui_search_attr { + uint8_t *ie_data; + uint32_t ie_length; + uint8_t *mac_addr; + uint32_t nss; + bool ht_cap; + bool vht_cap; + bool enable_2g; + bool enable_5g; +}; + +#endif /* _WLAN_ACTION_OUI_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_tgt_api.h new file mode 100644 index 0000000000..7a1d4f3080 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_tgt_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare public API for action_oui to interact with target/WMI + */ + +#ifndef _WLAN_ACTION_OUI_TGT_API_H_ +#define _WLAN_ACTION_OUI_TGT_API_H_ + +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_objmgr.h" + +#define GET_ACTION_OUI_TX_OPS_FROM_PSOC(psoc) \ + (&action_oui_psoc_get_priv(psoc)->tx_ops) + +/** + * tgt_action_oui_send() - Send request to target if + * @psoc: objmgr psoc object + * @req: action_oui request to be send + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_action_oui_send(struct wlan_objmgr_psoc *psoc, + struct action_oui_request *req); + +/** + * struct action_oui_tx_ops - structure of tx operations + * @send_req: Pointer to hold target_if send function + */ +struct action_oui_tx_ops { + QDF_STATUS (*send_req)(struct wlan_objmgr_psoc *psoc, + struct action_oui_request *req); +}; + +#endif /* _WLAN_ACTION_OUI_TGT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_ucfg_api.h new file mode 100644 index 0000000000..2097f8beab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/inc/wlan_action_oui_ucfg_api.h @@ -0,0 +1,331 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare public API related to the action_oui called by north bound + * HDD/OSIF/LIM + */ + +#ifndef _WLAN_ACTION_OUI_UCFG_API_H_ +#define _WLAN_ACTION_OUI_UCFG_API_H_ + +#include +#include +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_objmgr.h" + +#ifdef WLAN_FEATURE_ACTION_OUI + +/** + * ucfg_action_oui_init() - Register notification handlers. + * + * This function registers action_oui notification handlers which are + * invoked from psoc create/destroy handlers. + * + * Return: For successful registration - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +QDF_STATUS ucfg_action_oui_init(void); + +/** + * ucfg_action_oui_deinit() - Unregister notification handlers. + * + * This function Unregisters action_oui notification handlers which are + * invoked from psoc create/destroy handlers. + * + * Return: None + */ +void ucfg_action_oui_deinit(void); + +/** + * ucfg_action_oui_psoc_enable() - Notify action oui psoc enable + * @psoc: psoc object + * + * Return: None + */ +void ucfg_action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_action_oui_psoc_disable() - Notify action oui psoc disable + * @psoc: psoc object + * + * Return: None + */ +void ucfg_action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_action_oui_parse() - Parse input string and extract extensions. + * @psoc: objmgr psoc object + * @in_str: input string to be parsed + * @action_id: action to which given string corresponds + * + * This is a wrapper function which invokes internal function + * action_oui_extract() to extract OUIs and related attributes. + * + * Return: For successful parse - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +QDF_STATUS +ucfg_action_oui_parse(struct wlan_objmgr_psoc *psoc, + const uint8_t *in_str, + enum action_oui_id action_id); + +/** + * ucfg_action_oui_send() - Send action_oui and related attributes to Fw. + * @psoc: objmgr psoc object + * + * This is a wrapper function which invokes internal function + * action_oui_send() to send OUIs and related attributes to firmware. + * + * Return: For successful send - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +QDF_STATUS ucfg_action_oui_send(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_action_oui_enabled() - State of action_oui component + * @psoc: psoc object + * + * Return: True if action oui is enabled + */ +bool ucfg_action_oui_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_action_oui_search() - Check for OUIs and related info in IE data. + * @psoc: objmgr psoc object + * @attr: pointer to structure containing type of action, beacon IE data etc., + * @action_id: type of action to be checked + * + * This is a wrapper function which invokes internal function to search + * for OUIs and related info (specified from ini file) in vendor specific + * data of beacon IE for given action. + * + * Return: If search is successful return true else false. + */ +bool ucfg_action_oui_search(struct wlan_objmgr_psoc *psoc, + struct action_oui_search_attr *attr, + enum action_oui_id action_id); + +/** + * ucfg_action_oui_cleanup() - Remove all in existing oui entry. + * @psoc: objmgr psoc object + * @action_id: type of action to be removed + * + * This is a wrapper function which invokes internal function to remove + * all the existing oui entry. + * + * Return: QDF_STATUS_SUCCESS If remove is successful. + */ +QDF_STATUS +ucfg_action_oui_cleanup(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id); + +/** + * ucfg_action_oui_send_by_id() - Send action oui for action id + * @psoc: objmgr psoc object + * @id: type of action to be sent + * + * This is a wrapper function which invokes internal function to send + * action oui entry to firmware. + * + * Return: QDF_STATUS_SUCCESS If sending is successful. + */ +QDF_STATUS ucfg_action_oui_send_by_id(struct wlan_objmgr_psoc *psoc, + enum action_oui_id id); + +/** + * ucfg_action_oui_get_config() - Get current action INI config + * @psoc: objmgr psoc object + * @action_id: type of action to get + * + * Return: config string. + */ +uint8_t * +ucfg_action_oui_get_config(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id); +#else + +/** + * ucfg_action_oui_init() - Register notification handlers. + * + * This function registers action_oui notification handlers which are + * invoked from psoc create/destroy handlers. + * + * Return: For successful registration - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +static inline +QDF_STATUS ucfg_action_oui_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_action_oui_deinit() - Unregister notification handlers. + * + * This function Unregisters action_oui notification handlers which are + * invoked from psoc create/destroy handlers. + * + * Return: None + */ +static inline +void ucfg_action_oui_deinit(void) +{ +} + +/** + * ucfg_action_oui_psoc_enable() - Notify action oui psoc enable + * @psoc: psoc object + * + * Return: None + */ +static inline +void ucfg_action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ +} + +/** + * ucfg_action_oui_psoc_disable() - Notify action oui psoc disable + * @psoc: psoc object + * + * Return: None + */ +static inline +void ucfg_action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ +} + +/** + * ucfg_action_oui_parse() - Parse input string of action_id specified. + * @psoc: objmgr psoc object + * @in_str: input string to be parsed + * @action_id: action to which given string corresponds + * + * This is a wrapper function which invokes internal function + * action_oui_extract() to extract OUIs and related attributes. + * + * Return: For successful parse - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +static inline QDF_STATUS +ucfg_action_oui_parse(struct wlan_objmgr_psoc *psoc, + const uint8_t *in_str, + enum action_oui_id action_id) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_action_oui_send() - Send action_oui and related attributes to Fw. + * @psoc: objmgr psoc object + * + * This is a wrapper function which invokes internal function + * action_oui_send() to send OUIs and related attributes to firmware. + * + * Return: For successful send - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +static inline +QDF_STATUS ucfg_action_oui_send(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_action_oui_enabled() - State of action_oui component + * + * Return: When action_oui component is present return true + * else return false. + */ +static inline bool ucfg_action_oui_enabled(void) +{ + return false; +} + +/** + * ucfg_action_oui_search() - Check for OUIs and related info in IE data. + * @psoc: objmgr psoc object + * @attr: pointer to structure containing type of action, beacon IE data etc., + * @action_id: type of action to be checked + * + * This is a wrapper function which invokes internal function to search + * for OUIs and related info (specified from ini file) in vendor specific + * data of beacon IE for given action. + * + * Return: If search is successful return true else false. + */ +static inline +bool ucfg_action_oui_search(struct wlan_objmgr_psoc *psoc, + struct action_oui_search_attr *attr, + enum action_oui_id action_id) +{ + return false; +} + +/** + * ucfg_action_oui_cleanup() - Remove all of existing oui entry + * @psoc: objmgr psoc object + * @action_id: type of action to be removed + * + * This is a wrapper function which invokes internal function to remove + * all the existing oui entry. + * + * Return: QDF_STATUS_SUCCESS If remove is successful. + */ +static inline +QDF_STATUS +ucfg_action_oui_cleanup(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_action_oui_send_by_id() - Send action oui for action id + * @psoc: objmgr psoc object + * @id: type of action to be sent + * + * This is a wrapper function which invokes internal function to send + * action oui entry to firmware. + * + * Return: QDF_STATUS_SUCCESS If sending is successful. + */ +static inline +QDF_STATUS ucfg_action_oui_send_by_id(struct wlan_objmgr_psoc *psoc, + enum action_oui_id id) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_action_oui_get_config() - Get current action INI config + * @psoc: objmgr psoc object + * @action_id: type of action to get + * + * Return: config string. + */ +static inline uint8_t * +ucfg_action_oui_get_config(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id) +{ + return ""; +} +#endif /* WLAN_FEATURE_ACTION_OUI */ + +#endif /* _WLAN_ACTION_OUI_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_tgt_api.c new file mode 100644 index 0000000000..e3c2177d85 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_tgt_api.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for action_oui to interact with target/WMI + */ + +#include "wlan_action_oui_tgt_api.h" +#include "wlan_action_oui_main.h" +#include "wlan_action_oui_public_struct.h" + +QDF_STATUS tgt_action_oui_send(struct wlan_objmgr_psoc *psoc, + struct action_oui_request *req) +{ + struct action_oui_tx_ops *tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + ACTION_OUI_ENTER(); + + tx_ops = GET_ACTION_OUI_TX_OPS_FROM_PSOC(psoc); + QDF_ASSERT(tx_ops->send_req); + if (tx_ops->send_req) + status = tx_ops->send_req(psoc, req); + + ACTION_OUI_EXIT(); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c new file mode 100644 index 0000000000..a5eb1c55f7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2012-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Public API implementation of action_oui called by north bound HDD/OSIF. + */ + +#include "wlan_action_oui_ucfg_api.h" +#include "wlan_action_oui_main.h" +#include "target_if_action_oui.h" +#include "wlan_action_oui_tgt_api.h" +#include + +QDF_STATUS ucfg_action_oui_init(void) +{ + QDF_STATUS status; + + ACTION_OUI_ENTER(); + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_ACTION_OUI, + action_oui_psoc_create_notification, NULL); + if (!QDF_IS_STATUS_SUCCESS(status)) { + action_oui_err("Failed to register psoc create handler"); + goto exit; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_ACTION_OUI, + action_oui_psoc_destroy_notification, NULL); + if (QDF_IS_STATUS_SUCCESS(status)) { + action_oui_debug("psoc create/delete notifications registered"); + goto exit; + } + + action_oui_err("Failed to register psoc delete handler"); + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_ACTION_OUI, + action_oui_psoc_create_notification, NULL); + +exit: + ACTION_OUI_EXIT(); + return status; +} + +void ucfg_action_oui_deinit(void) +{ + QDF_STATUS status; + + ACTION_OUI_ENTER(); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_ACTION_OUI, + action_oui_psoc_create_notification, NULL); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("Failed to unregister psoc create handler"); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_ACTION_OUI, + action_oui_psoc_destroy_notification, + NULL); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_err("Failed to unregister psoc delete handler"); + + ACTION_OUI_EXIT(); +} + +void ucfg_action_oui_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + action_oui_psoc_enable(psoc); +} + +void ucfg_action_oui_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + action_oui_psoc_disable(psoc); +} + +bool ucfg_action_oui_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct action_oui_psoc_priv *psoc_priv; + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + return false; + } + + return psoc_priv->action_oui_enable; +} + +uint8_t * +ucfg_action_oui_get_config(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id) +{ + struct action_oui_psoc_priv *psoc_priv; + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + return ""; + } + if (action_id >= ACTION_OUI_MAXIMUM_ID) { + action_oui_err("Invalid action_oui id: %u", action_id); + return ""; + } + + return psoc_priv->action_oui_str[action_id]; +} + + +QDF_STATUS +ucfg_action_oui_parse(struct wlan_objmgr_psoc *psoc, + const uint8_t *in_str, + enum action_oui_id action_id) +{ + return action_oui_parse_string(psoc, in_str, action_id); +} + +QDF_STATUS +ucfg_action_oui_cleanup(struct wlan_objmgr_psoc *psoc, + enum action_oui_id action_id) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + ACTION_OUI_ENTER(); + + if (action_id >= ACTION_OUI_MAXIMUM_ID) { + action_oui_err("Invalid action_oui id: %u", action_id); + goto exit; + } + + if (!psoc) { + action_oui_err("psoc is NULL"); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + status = wlan_action_oui_cleanup(psoc_priv, action_id); +exit: + ACTION_OUI_EXIT(); + return status; +} + +QDF_STATUS ucfg_action_oui_send(struct wlan_objmgr_psoc *psoc) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint32_t id; + + if (!psoc) { + action_oui_err("psoc is NULL"); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + for (id = 0; id < ACTION_OUI_MAXIMUM_ID; id++) { + if (id >= ACTION_OUI_HOST_ONLY) + continue; + status = action_oui_send(psoc_priv, id); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_debug("Failed to send: %u", id); + } + +exit: + return status; +} + +QDF_STATUS ucfg_action_oui_send_by_id(struct wlan_objmgr_psoc *psoc, + enum action_oui_id id) +{ + struct action_oui_psoc_priv *psoc_priv; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + ACTION_OUI_ENTER(); + + if (!psoc) { + action_oui_err("psoc is NULL"); + goto exit; + } + + psoc_priv = action_oui_psoc_get_priv(psoc); + if (!psoc_priv) { + action_oui_err("psoc priv is NULL"); + goto exit; + } + + if (id >= ACTION_OUI_HOST_ONLY) { + action_oui_err("id %d not for firmware", id); + status = QDF_STATUS_SUCCESS; + goto exit; + } + + status = action_oui_send(psoc_priv, id); + if (!QDF_IS_STATUS_SUCCESS(status)) + action_oui_debug("Failed to send: %u", id); +exit: + ACTION_OUI_EXIT(); + + return status; +} + +bool ucfg_action_oui_search(struct wlan_objmgr_psoc *psoc, + struct action_oui_search_attr *attr, + enum action_oui_id action_id) +{ + return wlan_action_oui_search(psoc, attr, action_id); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cfg/cfg_all.h b/qcom/opensource/wlan/qcacld-3.0/components/cfg/cfg_all.h new file mode 100644 index 0000000000..fae179c2e5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cfg/cfg_all.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cfg_policy_mgr.h" +#include "cfg_define.h" +#include "cfg_converged.h" +#include "cfg_mlme.h" +#include "cfg_fwol.h" +#include "cfg_ipa.h" + +#ifdef CONVERGED_P2P_ENABLE +#include "cfg_p2p.h" +#else +#define CFG_P2P_ALL +#endif + +#ifdef FEATURE_WLAN_TDLS +#include "cfg_tdls.h" +#else +#define CFG_TDLS_ALL +#endif + +#ifdef WLAN_FEATURE_NAN +#include "cfg_nan.h" +#else +#define CFG_NAN_ALL +#endif + +#include "cfg_ftm_time_sync.h" + +#include "wlan_pmo_cfg.h" +#include "wlan_dp_cfg.h" +#include "hdd_config.h" +#include "hdd_dp_cfg.h" +#include "cfg_legacy_dp.h" +#include "cfg_dlm.h" +#include "cfg_pkt_capture.h" +#include "wlan_action_oui_cfg.h" + +/* Maintain Alphabetic order here while adding components */ +#define CFG_ALL \ + CFG_DENYLIST_MGR_ALL \ + CFG_CONVERGED_ALL \ + CFG_FWOL_ALL \ + CFG_POLICY_MGR_ALL \ + CFG_HDD_ALL \ + CFG_HDD_DP_ALL \ + CFG_DP_ALL \ + CFG_LEGACY_DP_ALL \ + CFG_MLME_ALL \ + CFG_NAN_ALL \ + CFG_P2P_ALL \ + CFG_PMO_ALL \ + CFG_TDLS_ALL \ + CFG_PKT_CAPTURE_MODE_ALL \ + CFG_TIME_SYNC_FTM_ALL \ + CFG_ACTION_OUI + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/inc/wlan_if_mgr_roam.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/inc/wlan_if_mgr_roam.h new file mode 100644 index 0000000000..67df12be5c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/inc/wlan_if_mgr_roam.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains interface manager public api + */ + +#ifndef _WLAN_IF_MGR_ROAM_H_ +#define _WLAN_IF_MGR_ROAM_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_if_mgr_roam.h" + +/** + * struct change_roam_state_arg - Contains roam state arguments + * @requestor: Driver disabled roaming requestor + * @curr_vdev_id: virtual device ID + * + * This structure is used to pass the roam state change information to the + * callback + */ +struct change_roam_state_arg { + enum wlan_cm_rso_control_requestor requestor; + uint8_t curr_vdev_id; +}; + +/** + * struct bssid_search_arg - Contains candidate validation arguments + * @peer_addr: MAC address of the BSS + * @vdev_id: virtual device ID + * + * This structure is used to pass the candidate validation information to the + * callback + */ +struct bssid_search_arg { + struct qdf_mac_addr peer_addr; + uint8_t vdev_id; +}; + +/** + * enum allow_mcc_go_diff_bi_definition - Defines the config values for allowing + * different beacon intervals between P2P-G0 and STA + * @ALLOW_MCC_GO_DIFF_BI_WFA_CERT: GO Beacon interval is not changed. + * MCC GO doesn't work well in optimized way. In worst scenario, it may + * invite STA disconnection. + * @ALLOW_MCC_GO_DIFF_BI_WORKAROUND: Workaround 1 disassoc all the clients and + * update beacon Interval. + * @ALLOW_MCC_GO_DIFF_BI_TEAR_DOWN: Tear down the P2P link in + * auto/Non-autonomous -GO case. + * @ALLOW_MCC_GO_DIFF_BI_NO_DISCONNECT: Don't disconnect the P2P client in + * autonomous/Non-autonomous -GO case update the BI dynamically + */ +enum allow_mcc_go_diff_bi_definition { + ALLOW_MCC_GO_DIFF_BI_WFA_CERT = 1, + ALLOW_MCC_GO_DIFF_BI_WORKAROUND, + ALLOW_MCC_GO_DIFF_BI_TEAR_DOWN, + ALLOW_MCC_GO_DIFF_BI_NO_DISCONNECT, +}; + +/** + * struct beacon_interval_arg - Contains beacon interval validation arguments + * @curr_vdev_id: current iterator vdev ID + * @curr_bss_opmode: current iterator BSS's opmode + * @ch_freq: current operating channel frequency + * @bss_beacon_interval: beacon interval that can be updated by callee + * @status: status to be filled by callee + * @is_done: boolean to stop iterating + * @update_beacon_interval: boolean to mark beacon interval as updated by callee + * + * This structure is used to pass the candidate validation information to the + * callback + */ +struct beacon_interval_arg { + uint8_t curr_vdev_id; + enum QDF_OPMODE curr_bss_opmode; + qdf_freq_t ch_freq; + uint16_t bss_beacon_interval; + QDF_STATUS status; + bool is_done; + bool update_beacon_interval; +}; + +/** + * if_mgr_enable_roaming() - interface manager enable roaming + * @pdev: pdev object + * @vdev: vdev object + * @requestor: RSO enable requestor + * + * Interface manager api to enable roaming for all other active vdev id's + * + * Context: It should run in thread context + * + * Return: QDF_STATUS + */ +QDF_STATUS if_mgr_enable_roaming(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_rso_control_requestor requestor); + +/** + * if_mgr_disable_roaming() - interface manager disable roaming + * @pdev: pdev object + * @vdev: vdev object + * @requestor: RSO disable requestor + * + * Interface manager api to disable roaming for all other active vdev id's + * + * Context: It should run in thread context + * + * Return: QDF_STATUS + */ +QDF_STATUS if_mgr_disable_roaming(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_rso_control_requestor requestor); + +/** + * if_mgr_enable_roaming_on_connected_sta() - interface manager disable roaming + * on connected STA + * @pdev: pdev object + * @vdev: vdev object + * + * Loops through connected vdevs and disables roaming if it is STA + * + * Context: It should run in thread context + * + * Return: QDF_STATUS + */ +QDF_STATUS +if_mgr_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev); + +/** + * if_mgr_enable_roaming_after_p2p_disconnect() - interface manager enable + * roaming after p2p disconnect + * @pdev: pdev object + * @vdev: vdev object + * @requestor: RSO enable requestor + * + * Disables roaming on p2p vdevs if the state is disconnected + * + * Context: It should run in thread context + * + * Return: QDF_STATUS + */ +QDF_STATUS if_mgr_enable_roaming_after_p2p_disconnect( + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_rso_control_requestor requestor); + +/** + * if_mgr_is_beacon_interval_valid() - checks if the concurrent session is + * valid + * @pdev: pdev object + * @vdev_id: vdev ID + * @candidate: concurrent candidate info + * + * This function validates the beacon interval with all other active vdevs. + * + * Context: It should run in thread context + * + * Return: true if session is valid, false if not + */ +bool if_mgr_is_beacon_interval_valid(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct validate_bss_data *candidate); + +/** + * if_mgr_validate_candidate() - validate candidate event handler + * @vdev: vdev object + * @event_data: Interface mgr event data + * + * This function will validate the candidate to see if it is a suitable option + * for roaming to. + * + * Context: It should run in thread context + * + * Return: QDF_STATUS + */ +QDF_STATUS if_mgr_validate_candidate(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c new file mode 100644 index 0000000000..59bdd3b490 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c @@ -0,0 +1,1007 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains interface manager roam public api + */ +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_if_mgr_roam.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_cm_roam_api.h" +#include "wlan_if_mgr_main.h" +#include "wlan_p2p_ucfg_api.h" +#include "cds_api.h" +#include "sme_api.h" +#include "wlan_vdev_mgr_utils_api.h" +#include "wni_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_cm_api.h" +#include "wlan_scan_api.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlo_mgr_link_switch.h" +#include + + +#ifdef WLAN_FEATURE_11BE_MLO +static inline bool +if_mgr_is_assoc_link_of_vdev(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + uint8_t cur_vdev_id) +{ + struct wlan_objmgr_vdev *cur_vdev, *assoc_vdev; + + cur_vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, cur_vdev_id, + WLAN_IF_MGR_ID); + if (!cur_vdev) + return false; + + assoc_vdev = wlan_mlo_get_assoc_link_vdev(cur_vdev); + + wlan_objmgr_vdev_release_ref(cur_vdev, WLAN_IF_MGR_ID); + if (vdev == assoc_vdev) + return true; + + return false; +} +#else +static inline bool +if_mgr_is_assoc_link_of_vdev(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + uint8_t cur_vdev_id) +{ + return false; +} +#endif + +static void if_mgr_enable_roaming_on_vdev(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct change_roam_state_arg *roam_arg = arg; + uint8_t vdev_id, curr_vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + curr_vdev_id = roam_arg->curr_vdev_id; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return; + + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) || + if_mgr_is_assoc_link_of_vdev(pdev, vdev, curr_vdev_id)) + return; + + if (curr_vdev_id != vdev_id && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + ifmgr_debug("Enable roaming for vdev_id %d", vdev_id); + wlan_cm_enable_rso(pdev, vdev_id, + roam_arg->requestor, + REASON_DRIVER_ENABLED); + } +} + +QDF_STATUS if_mgr_enable_roaming(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_rso_control_requestor requestor) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct change_roam_state_arg roam_arg; + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + + roam_arg.requestor = requestor; + roam_arg.curr_vdev_id = vdev_id; + + status = wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + if_mgr_enable_roaming_on_vdev, + &roam_arg, 0, + WLAN_IF_MGR_ID); + + return status; +} + +static void if_mgr_disable_roaming_on_vdev(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct change_roam_state_arg *roam_arg = arg; + uint8_t vdev_id, curr_vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + curr_vdev_id = roam_arg->curr_vdev_id; + + if (curr_vdev_id == vdev_id || + wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE || + wlan_cm_is_vdev_roam_sync_inprogress(vdev) || + vdev->vdev_mlme.mlme_state != WLAN_VDEV_S_UP) + return; + + /* + * Disable roaming only for the STA vdev which is not is roam sync state + * and VDEV is in UP state. + */ + ifmgr_debug("Roaming disabled on vdev_id %d", vdev_id); + wlan_cm_disable_rso(pdev, vdev_id, roam_arg->requestor, + REASON_DRIVER_DISABLED); +} + +QDF_STATUS if_mgr_disable_roaming(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_rso_control_requestor requestor) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct change_roam_state_arg roam_arg; + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + + roam_arg.requestor = requestor; + roam_arg.curr_vdev_id = vdev_id; + + status = wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + if_mgr_disable_roaming_on_vdev, + &roam_arg, 0, + WLAN_IF_MGR_ID); + + return status; +} + +QDF_STATUS +if_mgr_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return QDF_STATUS_E_FAILURE; + + /* + * When link switch is in progress, don't send RSO Enable before vdev + * is up. RSO Enable will be sent as part of install keys once + * link switch connect sequence is complete. + */ + if (mlo_mgr_is_link_switch_in_progress(vdev)) + return QDF_STATUS_SUCCESS; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + if (policy_mgr_is_sta_active_connection_exists(psoc) && + mlo_is_enable_roaming_on_connected_sta_allowed(vdev)) { + wlan_cm_enable_roaming_on_connected_sta(pdev, vdev_id); + policy_mgr_set_pcl_for_connected_vdev(psoc, vdev_id, true); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS if_mgr_enable_roaming_after_p2p_disconnect( + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_rso_control_requestor requestor) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_psoc *psoc; + struct change_roam_state_arg roam_arg; + uint8_t vdev_id; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + vdev_id = wlan_vdev_get_id(vdev); + + roam_arg.requestor = requestor; + roam_arg.curr_vdev_id = vdev_id; + + /* + * Due to audio share glitch with P2P clients due + * to roam scan on concurrent interface, disable + * roaming if "p2p_disable_roam" ini is enabled. + * Re-enable roaming again once the p2p client + * gets disconnected. + */ + if (ucfg_p2p_is_roam_config_disabled(psoc) && + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE) { + ifmgr_debug("P2P client disconnected, enable roam"); + status = wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + if_mgr_enable_roaming_on_vdev, + &roam_arg, 0, + WLAN_IF_MGR_ID); + } + + return status; +} + +/** + * if_mgr_calculate_mcc_beacon_interval() - Calculates the new beacon interval + * @sta_bi: station beacon interval + * @go_given_bi: P2P GO's given beacon interval + * + * This function has 3 stages. First it modifies the input go_given_bi to be + * within 100 to 199. Then it checks if the sta_bi and go_given_bi are multiples + * of each other. If they are, that means the 2 values are compatible, and just + * return as is, otherwise, find new compatible BI for P2P GO + * + * Return: valid beacon interval value + */ +static uint16_t if_mgr_calculate_mcc_beacon_interval(uint16_t sta_bi, + uint16_t go_given_bi) +{ + uint8_t num_beacons, is_multiple; + uint16_t go_calculated_bi, go_final_bi, sta_calculated_bi; + + /* ensure BI ranges between 100 and 200 */ + if (go_given_bi < 100) + go_calculated_bi = 100; + else + go_calculated_bi = 100 + (go_given_bi % 100); + + if (sta_bi == 0) { + /* There is possibility to receive zero as value. + * Which will cause divide by zero. Hence initialise with 100 + */ + sta_bi = 100; + ifmgr_warn("sta_bi 2nd parameter is zero, initialize to %d", + sta_bi); + } + /* check, if either one is multiple of another */ + if (sta_bi > go_calculated_bi) + is_multiple = !(sta_bi % go_calculated_bi); + else + is_multiple = !(go_calculated_bi % sta_bi); + + /* if it is multiple, then accept GO's beacon interval + * range [100,199] as it is + */ + if (is_multiple) + return go_calculated_bi; + + /* else , if it is not multiple, then then check for number of beacons + * to be inserted based on sta BI + */ + num_beacons = sta_bi / 100; + if (num_beacons) { + /* GO's final beacon interval will be aligned to sta beacon + * interval, but in the range of [100, 199]. + */ + sta_calculated_bi = sta_bi / num_beacons; + go_final_bi = sta_calculated_bi; + } else { + /* if STA beacon interval is less than 100, use GO's change + * beacon interval instead of updating to STA's beacon interval. + */ + go_final_bi = go_calculated_bi; + } + + return go_final_bi; +} + +static QDF_STATUS +if_mgr_send_chng_mcc_beacon_interval(struct wlan_objmgr_vdev *vdev, + struct beacon_interval_arg *bss_arg) +{ + struct scheduler_msg msg = {0}; + struct wlan_change_bi *p_msg; + uint16_t len = 0; + QDF_STATUS status; + uint8_t *mac_addr; + + if (!bss_arg->update_beacon_interval) + return QDF_STATUS_SUCCESS; + + bss_arg->update_beacon_interval = false; + + len = sizeof(*p_msg); + p_msg = qdf_mem_malloc(len); + if (!p_msg) + return QDF_STATUS_E_NOMEM; + + p_msg->message_type = eWNI_SME_CHNG_MCC_BEACON_INTERVAL; + p_msg->length = len; + + mac_addr = wlan_vdev_get_hw_macaddr(vdev); + qdf_mem_copy(&p_msg->bssid, mac_addr, QDF_MAC_ADDR_SIZE); + ifmgr_debug(QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac_addr)); + p_msg->session_id = wlan_vdev_get_id(vdev); + ifmgr_debug("session %d BeaconInterval %d", p_msg->session_id, + bss_arg->bss_beacon_interval); + p_msg->beacon_interval = bss_arg->bss_beacon_interval; + + msg.type = eWNI_SME_CHNG_MCC_BEACON_INTERVAL; + msg.bodyval = 0; + msg.bodyptr = p_msg; + + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(p_msg); + + return status; +} + +static void if_mgr_update_beacon_interval(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_psoc *psoc; + uint8_t allow_mcc_go_diff_bi; + struct wlan_objmgr_peer *peer; + enum wlan_peer_type bss_persona; + struct beacon_interval_arg *bss_arg = arg; + struct wlan_objmgr_vdev *vdev = object; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + policy_mgr_get_allow_mcc_go_diff_bi(psoc, &allow_mcc_go_diff_bi); + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID); + if (!peer) + return; + + bss_persona = wlan_peer_get_peer_type(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID); + + /* + * If GO in MCC support different beacon interval, + * change the BI of the P2P-GO + */ + if (bss_persona == WLAN_PEER_P2P_GO) + return; + /* + * Handle different BI scenario based on the + * configuration set. If Config is not set to 0x04 then + * Disconnect all the P2P clients associated. If config + * is set to 0x04 then update the BI without + * disconnecting all the clients + */ + if (allow_mcc_go_diff_bi == ALLOW_MCC_GO_DIFF_BI_NO_DISCONNECT && + bss_arg->update_beacon_interval) { + bss_arg->status = + if_mgr_send_chng_mcc_beacon_interval(vdev, bss_arg); + return; + } else if (bss_arg->update_beacon_interval) { + /* + * If the configuration of fAllowMCCGODiffBI is set to + * other than 0x04 + */ + bss_arg->status = wlan_sap_disconnect_all_p2p_client(vdev_id); + return; + } +} + +static QDF_STATUS +if_mgr_update_mcc_p2p_beacon_interval(struct wlan_objmgr_vdev *vdev, + struct beacon_interval_arg *bss_arg) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + uint8_t enable_mcc_mode; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + /* If MCC is not supported just break and return SUCCESS */ + wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode); + if (!enable_mcc_mode) + return QDF_STATUS_E_FAILURE; + + wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + if_mgr_update_beacon_interval, + bss_arg, 0, WLAN_IF_MGR_ID); + + return bss_arg->status; +} + +static bool if_mgr_validate_sta_bcn_intrvl(struct wlan_objmgr_vdev *vdev, + struct beacon_interval_arg *bss_arg) +{ + struct wlan_objmgr_psoc *psoc; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_objmgr_peer *peer; + uint16_t new_bcn_interval; + uint32_t beacon_interval; + struct wlan_channel *chan; + enum QDF_OPMODE curr_persona; + uint8_t allow_mcc_go_diff_bi; + uint8_t conc_rule1 = 0, conc_rule2 = 0; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return false; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID); + if (!peer) + return false; + + curr_persona = wlan_vdev_mlme_get_opmode(vdev); + + wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID); + + if (curr_persona == QDF_STA_MODE || + curr_persona == QDF_P2P_CLIENT_MODE) { + ifmgr_debug("Bcn Intrvl validation not require for STA/CLIENT"); + return false; + } + + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + ifmgr_err("failed to get active channel"); + return false; + } + + vdev_mlme = + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + QDF_ASSERT(0); + return false; + } + + wlan_util_vdev_mlme_get_param(vdev_mlme, WLAN_MLME_CFG_BEACON_INTERVAL, + &beacon_interval); + + if (curr_persona == QDF_SAP_MODE && + (chan->ch_cfreq1 != bss_arg->ch_freq || + chan->ch_cfreq2 != bss_arg->ch_freq)) { + ifmgr_debug("*** MCC with SAP+STA sessions ****"); + bss_arg->status = QDF_STATUS_SUCCESS; + return true; + } + + if (curr_persona == QDF_P2P_GO_MODE && + (chan->ch_cfreq1 != bss_arg->ch_freq || + chan->ch_cfreq2 != bss_arg->ch_freq) && + beacon_interval != bss_arg->bss_beacon_interval) { + policy_mgr_get_allow_mcc_go_diff_bi(psoc, + &allow_mcc_go_diff_bi); + + switch (allow_mcc_go_diff_bi) { + case ALLOW_MCC_GO_DIFF_BI_WFA_CERT: + bss_arg->status = QDF_STATUS_SUCCESS; + return true; + case ALLOW_MCC_GO_DIFF_BI_WORKAROUND: + fallthrough; + case ALLOW_MCC_GO_DIFF_BI_NO_DISCONNECT: + policy_mgr_get_conc_rule1(psoc, &conc_rule1); + policy_mgr_get_conc_rule2(psoc, &conc_rule2); + if (conc_rule1 || conc_rule2) + new_bcn_interval = CUSTOM_CONC_GO_BI; + else + new_bcn_interval = + if_mgr_calculate_mcc_beacon_interval( + bss_arg->bss_beacon_interval, + beacon_interval); + + ifmgr_debug("Peer AP BI : %d, new Beacon Interval: %d", + bss_arg->bss_beacon_interval, + new_bcn_interval); + + /* Update the beacon interval */ + if (new_bcn_interval != beacon_interval) { + ifmgr_err("Beacon Interval got changed config used: %d", + allow_mcc_go_diff_bi); + bss_arg->bss_beacon_interval = new_bcn_interval; + bss_arg->update_beacon_interval = true; + bss_arg->status = + if_mgr_update_mcc_p2p_beacon_interval( + vdev, + bss_arg); + return true; + } + bss_arg->status = QDF_STATUS_SUCCESS; + return true; + case ALLOW_MCC_GO_DIFF_BI_TEAR_DOWN: + bss_arg->update_beacon_interval = false; + bss_arg->status = wlan_sap_stop_bss(vdev_id); + return true; + default: + ifmgr_err("BcnIntrvl is diff can't connect to preferred AP"); + bss_arg->status = QDF_STATUS_E_FAILURE; + return true; + } + } + return false; +} + +static bool if_mgr_validate_p2pcli_bcn_intrvl(struct wlan_objmgr_vdev *vdev, + struct beacon_interval_arg *bss_arg) +{ + enum QDF_OPMODE curr_persona; + enum wlan_peer_type bss_persona; + uint32_t beacon_interval; + struct wlan_channel *chan; + struct wlan_objmgr_peer *peer; + struct vdev_mlme_obj *vdev_mlme; + + curr_persona = wlan_vdev_mlme_get_opmode(vdev); + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID); + if (!peer) + return false; + + bss_persona = wlan_peer_get_peer_type(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID); + + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + ifmgr_err("failed to get active channel"); + return false; + } + + vdev_mlme = + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + QDF_ASSERT(0); + return false; + } + + wlan_util_vdev_mlme_get_param(vdev_mlme, WLAN_MLME_CFG_BEACON_INTERVAL, + &beacon_interval); + + if (curr_persona == QDF_STA_MODE) { + ifmgr_debug("Ignore Beacon Interval Validation..."); + } else if (bss_persona == WLAN_PEER_P2P_GO) { + if ((chan->ch_cfreq1 != bss_arg->ch_freq || + chan->ch_cfreq2 != bss_arg->ch_freq) && + beacon_interval != bss_arg->bss_beacon_interval) { + ifmgr_err("BcnIntrvl is diff can't connect to P2P_GO network"); + bss_arg->status = QDF_STATUS_E_FAILURE; + return true; + } + } + + return false; +} + +static bool +if_mgr_validate_p2pgo_bcn_intrvl(struct wlan_objmgr_vdev *vdev, + struct beacon_interval_arg *bss_arg) +{ + struct wlan_objmgr_psoc *psoc; + struct vdev_mlme_obj *vdev_mlme; + enum QDF_OPMODE curr_persona; + uint32_t beacon_interval; + struct wlan_channel *chan; + uint8_t conc_rule1 = 0, conc_rule2 = 0; + uint16_t new_bcn_interval; + + curr_persona = wlan_vdev_mlme_get_opmode(vdev); + + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + ifmgr_err("failed to get active channel"); + return false; + } + + vdev_mlme = + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + QDF_ASSERT(0); + return false; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return false; + + wlan_util_vdev_mlme_get_param(vdev_mlme, WLAN_MLME_CFG_BEACON_INTERVAL, + &beacon_interval); + + if ((curr_persona == QDF_P2P_CLIENT_MODE) || + (curr_persona == QDF_STA_MODE)) { + /* check for P2P_client scenario */ + if ((chan->ch_cfreq1 == 0) && (chan->ch_cfreq2 == 0) && + (beacon_interval == 0)) + return false; + + if (wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP && + (chan->ch_cfreq1 != bss_arg->ch_freq || + chan->ch_cfreq2 != bss_arg->ch_freq) && + beacon_interval != bss_arg->bss_beacon_interval) { + /* + * Updated beaconInterval should be used only when + * we are starting a new BSS not incase of + * client or STA case + */ + policy_mgr_get_conc_rule1(psoc, &conc_rule1); + policy_mgr_get_conc_rule2(psoc, &conc_rule2); + + /* Calculate beacon Interval for P2P-GO incase of MCC */ + if (conc_rule1 || conc_rule2) { + new_bcn_interval = CUSTOM_CONC_GO_BI; + } else { + new_bcn_interval = + if_mgr_calculate_mcc_beacon_interval( + beacon_interval, + bss_arg->bss_beacon_interval); + } + if (new_bcn_interval != bss_arg->bss_beacon_interval) + bss_arg->bss_beacon_interval = new_bcn_interval; + bss_arg->status = QDF_STATUS_SUCCESS; + return true; + } + } + return false; +} + +static void if_mgr_validate_beacon_interval(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct beacon_interval_arg *bss_arg = arg; + struct wlan_objmgr_vdev *vdev = object; + uint8_t iter_vdev_id = wlan_vdev_get_id(vdev); + bool is_done = false; + + if (iter_vdev_id == bss_arg->curr_vdev_id) + return; + + if (wlan_vdev_mlme_get_state(vdev) != WLAN_VDEV_S_UP) + return; + + if (bss_arg->is_done) + return; + + switch (bss_arg->curr_bss_opmode) { + case QDF_STA_MODE: + is_done = if_mgr_validate_sta_bcn_intrvl(vdev, bss_arg); + break; + case QDF_P2P_CLIENT_MODE: + is_done = if_mgr_validate_p2pcli_bcn_intrvl(vdev, bss_arg); + break; + case QDF_SAP_MODE: + case QDF_IBSS_MODE: + break; + case QDF_P2P_GO_MODE: + is_done = if_mgr_validate_p2pgo_bcn_intrvl(vdev, bss_arg); + break; + default: + ifmgr_err("BSS opmode not supported: %d", + bss_arg->curr_bss_opmode); + } + + if (is_done) + bss_arg->is_done = is_done; +} + +bool if_mgr_is_beacon_interval_valid(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct validate_bss_data *candidate) +{ + struct wlan_objmgr_psoc *psoc; + struct beacon_interval_arg bss_arg; + uint8_t enable_mcc_mode; + struct wlan_objmgr_vdev *vdev; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return false; + + wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode); + if (!enable_mcc_mode) + return false; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_IF_MGR_ID); + if (!vdev) + return false; + + bss_arg.curr_vdev_id = vdev_id; + bss_arg.curr_bss_opmode = wlan_vdev_mlme_get_opmode(vdev); + bss_arg.ch_freq = candidate->chan_freq; + bss_arg.bss_beacon_interval = candidate->beacon_interval; + bss_arg.is_done = false; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_IF_MGR_ID); + + wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + if_mgr_validate_beacon_interval, + &bss_arg, 0, + WLAN_IF_MGR_ID); + + if (!bss_arg.is_done) + return true; + + if (bss_arg.is_done && QDF_IS_STATUS_SUCCESS(bss_arg.status)) + return true; + + return false; +} + +static void if_mgr_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct bssid_search_arg *bssid_arg = arg; + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct wlan_objmgr_peer *peer; + + if (!(wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE || + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE)) + return; + + /* Need to check the connection manager state when that becomes + * available + */ + if (wlan_vdev_mlme_get_state(vdev) != WLAN_VDEV_S_UP) + return; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_IF_MGR_ID); + if (!peer) + return; + + if (WLAN_ADDR_EQ(bssid_arg->peer_addr.bytes, + wlan_peer_get_macaddr(peer)) == QDF_STATUS_SUCCESS) + bssid_arg->vdev_id = wlan_vdev_get_id(vdev); + + wlan_objmgr_peer_release_ref(peer, WLAN_IF_MGR_ID); +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * if_mgr_get_conc_ext_flags() - get extended flags for concurrency check + * @vdev: pointer to vdev on which new connection is coming up + * @candidate_info: interface manager validate candidate data + * + * Return: extended flags for concurrency check + */ +static inline uint32_t +if_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev, + struct validate_bss_data *candidate_info) +{ + struct qdf_mac_addr *mld_addr; + + /* If connection is happening on non-ML VDEV + * force the ML AP candidate as non-MLO to + * downgrade connection to 11ax. + */ + mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + if (qdf_is_macaddr_zero(mld_addr)) + return policy_mgr_get_conc_ext_flags(vdev, false); + + return policy_mgr_get_conc_ext_flags(vdev, candidate_info->is_mlo); +} + +static void if_mgr_update_candidate(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct validate_bss_data *candidate_info) +{ + struct scan_cache_entry *scan_entry = candidate_info->scan_entry; + struct action_oui_search_attr attr = {0}; + int8_t i, allowed_partner_links = 0; + uint8_t mlo_support_link_num; + + if (!(scan_entry->ie_list.multi_link_bv || scan_entry->ie_list.ehtcap || + scan_entry->ie_list.ehtop)) + return; + + attr.ie_data = util_scan_entry_ie_data(scan_entry); + attr.ie_length = util_scan_entry_ie_len(scan_entry); + + if (!mlme_get_bss_11be_allowed(psoc, &candidate_info->peer_addr, + attr.ie_data, attr.ie_length) || + wlan_vdev_mlme_get_user_dis_eht_flag(vdev) || + !wlan_reg_phybitmap_support_11be(wlan_vdev_get_pdev(vdev))) { + scan_entry->ie_list.multi_link_bv = NULL; + scan_entry->ie_list.ehtcap = NULL; + scan_entry->ie_list.ehtop = NULL; + qdf_mem_zero(&scan_entry->ml_info, sizeof(scan_entry->ml_info)); + candidate_info->is_mlo = false; + return; + } + + mlo_support_link_num = wlan_mlme_get_sta_mlo_conn_max_num(psoc); + + if (mlo_support_link_num <= WLAN_MAX_ML_DEFAULT_LINK) + return; + + if (!wlan_action_oui_search(psoc, &attr, + ACTION_OUI_RESTRICT_MAX_MLO_LINKS)) + return; + + for (i = 0; i < scan_entry->ml_info.num_links; i++) { + if (i < WLAN_MAX_ML_DEFAULT_LINK - 1) { + allowed_partner_links++; + continue; + } + + scan_entry->ml_info.link_info[i].is_valid_link = false; + } + + if (allowed_partner_links != scan_entry->ml_info.num_links) + ifmgr_nofl_debug("Downgrade " QDF_MAC_ADDR_FMT " partner links from %d to %d", + QDF_MAC_ADDR_REF(scan_entry->ml_info.mld_mac_addr.bytes), + scan_entry->ml_info.num_links, + allowed_partner_links); +} +#else +static inline uint32_t +if_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev, + struct validate_bss_data *candidate_info) +{ + return 0; +} + +static void if_mgr_update_candidate(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct validate_bss_data *candidate_info) +{ +} +#endif + +QDF_STATUS if_mgr_validate_candidate(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + enum QDF_OPMODE op_mode; + enum policy_mgr_con_mode mode; + struct bssid_search_arg bssid_arg; + struct validate_bss_data *candidate_info = + &event_data->validate_bss_info; + uint32_t chan_freq = candidate_info->chan_freq; + uint32_t conc_freq = 0, conc_ext_flags; + + op_mode = wlan_vdev_mlme_get_opmode(vdev); + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + if_mgr_update_candidate(psoc, vdev, candidate_info); + /* + * Do not allow STA to connect on 6Ghz or indoor channel for non dbs + * hardware if SAP and skip_6g_and_indoor_freq_scan ini are present + */ + if (op_mode == QDF_STA_MODE && + !policy_mgr_is_sta_chan_valid_for_connect_and_roam(pdev, + chan_freq)) { + ifmgr_debug("STA connection not allowed on bssid: "QDF_MAC_ADDR_FMT" with freq: %d (6Ghz or indoor(%d)), as not valid for connection", + QDF_MAC_ADDR_REF(candidate_info->peer_addr.bytes), + chan_freq, + wlan_reg_is_freq_indoor(pdev, chan_freq)); + return QDF_STATUS_E_INVAL; + } + + /* + * This is a temporary check and will be removed once ll_lt_sap CSA + * support is added. + */ + if (policy_mgr_get_ll_lt_sap_freq(psoc) == chan_freq) { + ifmgr_debug("STA connection not allowed on LL_LT_SAP freq %d", + chan_freq); + return QDF_STATUS_E_INVAL; + } + /* + * Ignore the BSS if any other vdev is already connected to it. + */ + qdf_copy_macaddr(&bssid_arg.peer_addr, + &candidate_info->peer_addr); + bssid_arg.vdev_id = WLAN_INVALID_VDEV_ID; + wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + if_mgr_get_vdev_id_from_bssid, + &bssid_arg, 0, + WLAN_IF_MGR_ID); + + if (bssid_arg.vdev_id != WLAN_INVALID_VDEV_ID) { + ifmgr_info("vdev_id %d already connected to "QDF_MAC_ADDR_FMT". select next bss for vdev_id %d", + bssid_arg.vdev_id, + QDF_MAC_ADDR_REF(bssid_arg.peer_addr.bytes), + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + /* + * If concurrency enabled take the concurrent connected channel first. + * Valid multichannel concurrent sessions exempted + */ + mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, + wlan_vdev_get_id(vdev)); + + /* If concurrency is not allowed select next bss */ + conc_ext_flags = if_mgr_get_conc_ext_flags(vdev, candidate_info); + /* + * Apply concurrency check only for non ML and ML assoc links only + * For non-assoc ML link if concurrency check fails its will be forced + * disabled in peer assoc. + */ + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) && + !policy_mgr_is_concurrency_allowed(psoc, mode, chan_freq, + HW_MODE_20_MHZ, conc_ext_flags, + NULL)) { + ifmgr_info("Concurrency not allowed for this channel freq %d bssid "QDF_MAC_ADDR_FMT", selecting next", + chan_freq, + QDF_MAC_ADDR_REF(bssid_arg.peer_addr.bytes)); + return QDF_STATUS_E_INVAL; + } + + /* + * check if channel is allowed for current hw mode, if not fetch + * next BSS. + */ + if (!policy_mgr_is_hwmode_set_for_given_chnl(psoc, chan_freq)) { + ifmgr_info("HW mode isn't properly set, freq %d BSSID "QDF_MAC_ADDR_FMT, + chan_freq, + QDF_MAC_ADDR_REF(bssid_arg.peer_addr.bytes)); + return QDF_STATUS_E_INVAL; + } + + /* validate beacon interval */ + if (policy_mgr_concurrent_open_sessions_running(psoc) && + !if_mgr_is_beacon_interval_valid(pdev, wlan_vdev_get_id(vdev), + candidate_info)) { + conc_freq = wlan_get_conc_freq(); + ifmgr_debug("csr Conc Channel freq: %d", + conc_freq); + + if (conc_freq) { + if ((conc_freq == chan_freq) || + (policy_mgr_is_hw_sbs_capable(psoc) && + policy_mgr_are_sbs_chan(psoc, conc_freq, + chan_freq)) || + (policy_mgr_is_hw_dbs_capable(psoc) && + !wlan_reg_is_same_band_freqs(conc_freq, + chan_freq))) { + /* + * make this 0 because we do not want the below + * check to pass as we don't want to connect on + * other channel + */ + ifmgr_debug("Conc chnl freq match: %d", + conc_freq); + conc_freq = 0; + } + } + } + + if (conc_freq) + return QDF_STATUS_E_INVAL; + + /* Check low latency SAP and STA/GC concurrency are valid or not */ + if (!policy_mgr_is_ll_sap_concurrency_valid(psoc, chan_freq, mode)) { + ifmgr_debug("STA connection not allowed on bssid: "QDF_MAC_ADDR_FMT" with freq: %d due to LL SAP present", + QDF_MAC_ADDR_REF(candidate_info->peer_addr.bytes), + chan_freq); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c new file mode 100644 index 0000000000..951632a7ff --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains interface manager public api + */ +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_if_mgr_ap.h" +#include "wlan_if_mgr_roam.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_if_mgr_main.h" +#include "wlan_p2p_cfg_api.h" +#include "wlan_tdls_api.h" +#include "wlan_p2p_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_vdev_mgr_utils_api.h" +#include "wlan_tdls_tgt_api.h" +#include "wlan_policy_mgr_ll_sap.h" + +QDF_STATUS if_mgr_ap_start_bss(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + wlan_tdls_notify_start_bss(psoc, vdev); + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE || + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + wlan_handle_emlsr_sta_concurrency(psoc, true, false); + + if (policy_mgr_is_hw_mode_change_in_progress(psoc)) { + if (!QDF_IS_STATUS_SUCCESS( + policy_mgr_wait_for_connection_update(psoc))) { + ifmgr_err("qdf wait for event failed!!"); + return QDF_STATUS_E_FAILURE; + } + } + if (policy_mgr_is_chan_switch_in_progress(psoc)) { + status = policy_mgr_wait_chan_switch_complete_evt(psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ifmgr_err("qdf wait for csa event failed!!"); + return QDF_STATUS_E_FAILURE; + } + } + + if (policy_mgr_is_sta_active_connection_exists(psoc)) + /* Disable Roaming on all vdev's before starting bss */ + if_mgr_disable_roaming(pdev, vdev, RSO_START_BSS); + + /* abort p2p roc before starting the BSS for sync event */ + ucfg_p2p_cleanup_roc_by_psoc(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +if_mgr_ap_start_bss_complete(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + /* + * Due to audio share glitch with P2P GO caused by + * roam scan on concurrent interface, disable + * roaming if "p2p_disable_roam" ini is enabled. + * Donot re-enable roaming again on other STA interface + * if p2p GO is active on any vdev. + */ + if (cfg_p2p_is_roam_config_disabled(psoc) && + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) { + ifmgr_debug("p2p go mode, keep roam disabled"); + } else { + /* Enable Roaming after start bss in case of failure/success */ + if_mgr_enable_roaming(pdev, vdev, RSO_START_BSS); + } + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + policy_mgr_check_sap_go_force_scc(psoc, vdev, + CSA_REASON_GO_BSS_STARTED); + ifmgr_debug("check for SAP restart"); + + if (policy_mgr_is_vdev_ll_lt_sap(psoc, wlan_vdev_get_id(vdev))) + policy_mgr_ll_lt_sap_restart_concurrent_sap(psoc, true); + else + policy_mgr_check_concurrent_intf_and_restart_sap( + psoc, + wlan_util_vdev_mgr_get_acs_mode_for_vdev(vdev)); + /* + * Enable TDLS again on concurrent STA + */ + if (event_data && QDF_IS_STATUS_ERROR(event_data->status)) + wlan_tdls_notify_start_bss_failure(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS if_mgr_ap_stop_bss(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +if_mgr_ap_stop_bss_complete(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + uint8_t mcc_scc_switch; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE || + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + wlan_handle_emlsr_sta_concurrency(psoc, false, true); + /* + * Due to audio share glitch with P2P GO caused by + * roam scan on concurrent interface, disable + * roaming if "p2p_disable_roam" ini is enabled. + * Re-enable roaming on other STA interface if p2p GO + * is active on any vdev. + */ + if (cfg_p2p_is_roam_config_disabled(psoc) && + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) { + ifmgr_debug("p2p go disconnected enable roam"); + if_mgr_enable_roaming(pdev, vdev, RSO_START_BSS); + } + + ifmgr_debug("SAP/P2P-GO is stopped, re-enable roaming if it's stopped due to SAP/P2P-GO CSA"); + if_mgr_enable_roaming(pdev, vdev, RSO_SAP_CHANNEL_CHANGE); + + policy_mgr_get_mcc_scc_switch(psoc, &mcc_scc_switch); + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE && + mcc_scc_switch == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) + policy_mgr_check_concurrent_intf_and_restart_sap(psoc, false); + + if (policy_mgr_is_vdev_ll_lt_sap(psoc, wlan_vdev_get_id(vdev))) + policy_mgr_ll_lt_sap_restart_concurrent_sap(psoc, false); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +if_mgr_ap_csa_complete(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + status = wlan_p2p_check_and_force_scc_go_plus_go(psoc, vdev); + if (QDF_IS_STATUS_ERROR(status)) + ifmgr_err("force scc failure with status: %d", status); + + wlan_tdls_notify_channel_switch_complete(psoc, wlan_vdev_get_id(vdev)); + + return status; +} + +QDF_STATUS +if_mgr_ap_csa_start(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + enum QDF_OPMODE op_mode; + + op_mode = wlan_vdev_mlme_get_opmode(vdev); + if (op_mode != QDF_SAP_MODE && op_mode != QDF_P2P_GO_MODE) + return QDF_STATUS_SUCCESS; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + /* + * Disable TDLS off-channel before VDEV restart + */ + wlan_tdls_notify_channel_switch_start(psoc, vdev); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c new file mode 100644 index 0000000000..17fcb92cb5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains interface manager public api + */ +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_if_mgr_sta.h" +#include "wlan_if_mgr_roam.h" +#include "wlan_if_mgr_main.h" +#include "nan_ucfg_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_tdls_ucfg_api.h" +#include "wlan_tdls_api.h" +#include +#include +#include +#include +#include "wlan_nan_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include +#include "wlan_vdev_mgr_utils_api.h" +#include "wlan_tdls_api.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "wlan_ll_sap_api.h" + +QDF_STATUS if_mgr_connect_start(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + uint8_t sta_cnt, sap_cnt; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE op_mode; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS], i; + bool disable_nan = true; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + /* + * Disable NAN Discovery if incoming connection is P2P or if a STA + * connection already exists and if this is a case of STA+STA + * or SAP+STA concurrency + */ + sta_cnt = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, + PM_STA_MODE); + sap_cnt = policy_mgr_get_sap_mode_info(psoc, NULL, + &vdev_id_list[sta_cnt]); + + op_mode = wlan_vdev_mlme_get_opmode(vdev); + + if (op_mode == QDF_STA_MODE || op_mode == QDF_P2P_CLIENT_MODE) + wlan_handle_emlsr_sta_concurrency(psoc, true, false); + + if (op_mode == QDF_P2P_CLIENT_MODE || sap_cnt || sta_cnt) { + for (i = 0; i < sta_cnt + sap_cnt; i++) { + if (vdev_id_list[i] == wlan_vdev_get_id(vdev)) + disable_nan = false; + /* 1. Don't disable nan if firmware supports + * ML STA + NAN + NDP. + * 2. Disable nan if legacy sta + nan + + * ML STA(primary link) comes up. + */ + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) && + wlan_is_mlo_sta_nan_ndi_allowed(psoc)) + disable_nan = false; + } + if (disable_nan) + ucfg_nan_disable_concurrency(psoc); + } + + if (op_mode == QDF_P2P_CLIENT_MODE) + wlan_tdls_handle_p2p_client_connect(psoc, vdev); + + /* + * STA+NDI concurrency gets preference over NDI+NDI. Disable + * first NDI in case an NDI+NDI concurrency exists if FW does + * not support 4 port concurrency of two NDI + NAN with STA. + */ + if (!ucfg_nan_is_sta_nan_ndi_4_port_allowed(psoc)) + ucfg_nan_check_and_disable_unsupported_ndi(psoc, + false); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS if_mgr_connect_active(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { + /* + * In case of STA+STA concurrency, firmware might try to roam + * to same AP where host is trying to do association on the other + * STA iface. Roaming is disabled on all the ifaces to avoid + * this scenario. + */ + if_mgr_disable_roaming(pdev, vdev, RSO_CONNECT_START); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS if_mgr_connect_complete(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status = event_data->status; + uint8_t vdev_id; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + vdev_id = wlan_vdev_get_id(vdev); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* + * Due to audio share glitch with P2P clients caused by roam + * scan on concurrent interface, disable roaming if + * "p2p_disable_roam" ini is enabled. Donot re-enable roaming + * again on other STA interface if p2p client connection is + * active on any vdev. + */ + if (ucfg_p2p_is_roam_config_disabled(psoc) && + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE) { + ifmgr_debug("p2p client active, keep roam disabled"); + } else { + ifmgr_debug("set pcl when connection on vdev id:%d", + vdev_id); + policy_mgr_set_pcl_for_connected_vdev(psoc, vdev_id, + false); + /* + * Enable roaming on other STA iface except this one. + * Firmware doesn't support connection on one STA iface + * while roaming on other STA iface. + */ + if_mgr_enable_roaming(pdev, vdev, RSO_CONNECT_START); + } + } else { + /* notify connect failure on final failure */ + ucfg_tdls_notify_connect_failure(psoc); + + /* + * Enable roaming on other STA iface except this one. + * Firmware doesn't support connection on one STA iface + * while roaming on other STA iface. + */ + if_mgr_enable_roaming(pdev, vdev, RSO_CONNECT_START); + } + + policy_mgr_check_n_start_opportunistic_timer(psoc); + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE && + wlan_vdev_mlme_is_mlo_vdev(vdev)) + wlan_handle_emlsr_sta_concurrency(psoc, false, true); + + if (!wlan_cm_is_vdev_roaming(vdev)) + policy_mgr_check_concurrent_intf_and_restart_sap(psoc, + wlan_util_vdev_mgr_get_acs_mode_for_vdev(vdev)); + + wlan_ll_sap_switch_bearer_on_sta_connect_complete(psoc, vdev_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS if_mgr_disconnect_start(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct mlme_legacy_priv *mlme_priv; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + qdf_runtime_pm_prevent_suspend(&mlme_priv->disconnect_runtime_lock); + + if (mlo_mgr_is_link_switch_in_progress(vdev)) + wlan_tdls_delete_all_peers(vdev); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS if_mgr_disconnect_complete(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct mlme_legacy_priv *mlme_priv; + QDF_STATUS status; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + qdf_runtime_pm_allow_suspend(&mlme_priv->disconnect_runtime_lock); + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE || + wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE) + wlan_handle_emlsr_sta_concurrency(psoc, false, true); + + status = if_mgr_enable_roaming_after_p2p_disconnect(pdev, vdev, + RSO_CONNECT_START); + if (status) { + ifmgr_err("Failed to enable roaming after p2p disconnect"); + return status; + } + if (!mlo_is_mld_sta(vdev) || !mlo_mgr_is_link_switch_in_progress(vdev)) + policy_mgr_check_concurrent_intf_and_restart_sap( + psoc, wlan_util_vdev_mgr_get_acs_mode_for_vdev(vdev)); + + status = if_mgr_enable_roaming_on_connected_sta(pdev, vdev); + if (status) { + ifmgr_err("Failed to enable roaming on connected sta"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +if_mgr_sta_csa_complete(struct wlan_objmgr_vdev *vdev, + struct if_mgr_event_data *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + wlan_tdls_notify_channel_switch_complete(psoc, wlan_vdev_get_id(vdev)); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/logging/inc/wlan_connectivity_logging.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/logging/inc/wlan_connectivity_logging.h new file mode 100644 index 0000000000..76d74b65b7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/logging/inc/wlan_connectivity_logging.h @@ -0,0 +1,1713 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_logging.c + * + * Implementation for the Connect/roaming logging. + */ + +#ifndef _WLAN_CONNECTIVITY_LOGGING_H_ +#define _WLAN_CONNECTIVITY_LOGGING_H_ + +#include "wlan_logging_sock_svc.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_mlo_mgr_public_structs.h" + +#define WLAN_MAX_LOGGING_FREQ 120 + +/** + * enum wlan_main_tag - Main Tag used in logging + * @WLAN_CONNECTING: Connecting + * @WLAN_CONNECTING_FAIL: Connection failure + * @WLAN_AUTH_REQ: Authentication request frame + * @WLAN_AUTH_RESP: Authentication response frame + * @WLAN_ASSOC_REQ: Association request frame + * @WLAN_ASSOC_RSP: Association response frame + * @WLAN_REASSOC_REQ: Reassociation request frame + * @WLAN_REASSOC_RSP: Reassociation response frame + * @WLAN_DEAUTH_RX: Deauthentication frame received + * @WLAN_DEAUTH_TX: Deauthentication frame sent + * @WLAN_DISASSOC_RX: Disassociation frame received + * @WLAN_DISASSOC_TX: Disassociation frame sent + * @WLAN_DISCONN_BMISS: Disconnection due to beacon miss + * @WLAN_ROAM_SCAN_START: ROAM scan start + * @WLAN_ROAM_SCAN_DONE: Roam scan done + * @WLAN_ROAM_SCORE_CURR_AP: Roam score current AP + * @WLAN_ROAM_SCORE_CAND_AP: Roam Score Candidate AP + * @WLAN_ROAM_RESULT: Roam Result + * @WLAN_ROAM_CANCEL: Roam Cancel + * @WLAN_BTM_REQ: BTM request + * @WLAN_BTM_QUERY: BTM Query frame + * @WLAN_BTM_RESP: BTM response frame + * @WLAN_BTM_REQ_CANDI: BTM request candidate info + * @WLAN_ROAM_WTC: ROAM WTC trigger logs + * @WLAN_DHCP_DISCOVER: DHCP discover frame + * @WLAN_DHCP_OFFER: DHCP offer frame + * @WLAN_DHCP_REQUEST: DHCP Request frame + * @WLAN_DHCP_ACK: DHCP ACK + * @WLAN_DHCP_NACK: DHCP NACK + * @WLAN_EAPOL_M1: EAPOL M1 + * @WLAN_EAPOL_M2: EAPOL M2 + * @WLAN_EAPOL_M3: EAPOL M3 + * @WLAN_EAPOL_M4: EAPOL M4 + * @WLAN_GTK_M1: GTK rekey M1 frame + * @WLAN_GTK_M2: GTK Rekey M2 frame + * @WLAN_EAP_REQUEST: EAP request frame + * @WLAN_EAP_RESPONSE: EAP response frame + * @WLAN_EAP_SUCCESS: EAP success + * @WLAN_EAP_FAILURE: EAP failure + * @WLAN_CUSTOM_LOG: Additional WLAN logs + * @WLAN_TAG_MAX: MAX tag + */ +enum wlan_main_tag { + WLAN_CONNECTING, + WLAN_CONNECTING_FAIL, + WLAN_AUTH_REQ, + WLAN_AUTH_RESP, + WLAN_ASSOC_REQ, + WLAN_ASSOC_RSP, + WLAN_REASSOC_REQ, + WLAN_REASSOC_RSP, + WLAN_DEAUTH_RX, + WLAN_DEAUTH_TX, + WLAN_DISASSOC_RX, + WLAN_DISASSOC_TX, + WLAN_DISCONN_BMISS, + WLAN_ROAM_SCAN_START, + WLAN_ROAM_SCAN_DONE, + WLAN_ROAM_SCORE_CURR_AP, + WLAN_ROAM_SCORE_CAND_AP, + WLAN_ROAM_RESULT, + WLAN_ROAM_CANCEL, + WLAN_BTM_REQ, + WLAN_BTM_QUERY, + WLAN_BTM_RESP, + WLAN_BTM_REQ_CANDI, + WLAN_ROAM_WTC, + WLAN_DHCP_DISCOVER, + WLAN_DHCP_OFFER, + WLAN_DHCP_REQUEST, + WLAN_DHCP_ACK, + WLAN_DHCP_NACK, + WLAN_EAPOL_M1, + WLAN_EAPOL_M2, + WLAN_EAPOL_M3, + WLAN_EAPOL_M4, + WLAN_GTK_M1, + WLAN_GTK_M2, + WLAN_EAP_REQUEST, + WLAN_EAP_RESPONSE, + WLAN_EAP_SUCCESS, + WLAN_EAP_FAILURE, + WLAN_CUSTOM_LOG, + /* Keep at last */ + WLAN_TAG_MAX, +}; + +/** + * enum qca_conn_diag_log_event_type - Diag Event subtype used in logging + * @WLAN_CONN_DIAG_CONNECTING_EVENT: Connecting + * @WLAN_CONN_DIAG_CONNECT_FAIL_EVENT: Connection failure + * @WLAN_CONN_DIAG_AUTH_REQ_EVENT: Authentication request frame + * @WLAN_CONN_DIAG_AUTH_RESP_EVENT: Authentication response frame + * @WLAN_CONN_DIAG_ASSOC_REQ_EVENT: Association request frame + * @WLAN_CONN_DIAG_ASSOC_RESP_EVENT: Association response frame + * @WLAN_CONN_DIAG_REASSOC_REQ_EVENT: Reassociation request frame + * @WLAN_CONN_DIAG_REASSOC_RESP_EVENT: Reassociation response frame + * @WLAN_CONN_DIAG_DEAUTH_RX_EVENT: Deauthentication frame received + * @WLAN_CONN_DIAG_DEAUTH_TX_EVENT: Deauthentication frame sent + * @WLAN_CONN_DIAG_DISASSOC_RX_EVENT: Disassociation frame received + * @WLAN_CONN_DIAG_DISASSOC_TX_EVENT: Disassociation frame sent + * @WLAN_CONN_DIAG_BMISS_EVENT: Disconnection due to beacon miss + * @WLAN_CONN_DIAG_ROAM_SCAN_START_EVENT: ROAM scan start + * @WLAN_CONN_DIAG_ROAM_SCAN_DONE_EVENT: Roam scan done + * @WLAN_CONN_DIAG_ROAM_SCORE_CUR_AP_EVENT: Roam score current AP + * @WLAN_CONN_DIAG_ROAM_SCORE_CAND_AP_EVENT: Roam Score Candidate AP + * @WLAN_CONN_DIAG_ROAM_RESULT_EVENT: Roam Result + * @WLAN_CONN_DIAG_ROAM_CANCEL_EVENT: Roam Cancel + * @WLAN_CONN_DIAG_BTM_REQ_EVENT: BTM request + * @WLAN_CONN_DIAG_BTM_QUERY_EVENT: BTM Query frame + * @WLAN_CONN_DIAG_BTM_RESP_EVENT: BTM response frame + * @WLAN_CONN_DIAG_BTM_REQ_CAND_EVENT: BTM request candidate info + * @WLAN_CONN_DIAG_BTM_WTC_EVENT: ROAM WTC trigger logs + * @WLAN_CONN_DIAG_DHCP_DISC_EVENT: DHCP discover frame + * @WLAN_CONN_DIAG_DHCP_OFFER_EVENT: DHCP offer frame + * @WLAN_CONN_DIAG_DHCP_REQUEST_EVENT: DHCP Request frame + * @WLAN_CONN_DIAG_DHCP_ACK_EVENT: DHCP ACK + * @WLAN_CONN_DIAG_DHCP_NACK_EVENT: DHCP NACK + * @WLAN_CONN_DIAG_EAPOL_M1_EVENT: EAPOL M1 + * @WLAN_CONN_DIAG_EAPOL_M2_EVENT: EAPOL M2 + * @WLAN_CONN_DIAG_EAPOL_M3_EVENT: EAPOL M3 + * @WLAN_CONN_DIAG_EAPOL_M4_EVENT: EAPOL M4 + * @WLAN_CONN_DIAG_GTK_M1_EVENT: GTK rekey M1 frame + * @WLAN_CONN_DIAG_GTK_M2_EVENT: GTK Rekey M2 frame + * @WLAN_CONN_DIAG_EAP_REQ_EVENT: EAP request frame + * @WLAN_CONN_DIAG_EAP_RESP_EVENT: EAP response frame + * @WLAN_CONN_DIAG_EAP_SUCC_EVENT: EAP success + * @WLAN_CONN_DIAG_EAP_FAIL_EVENT: EAP failure + * @WLAN_CONN_DIAG_CUSTOM_EVENT: Additional WLAN logs + * @WLAN_CONN_DIAG_EAP_START_EVENT: EAPOL start frame + * @WLAN_CONN_DIAG_NBR_RPT_REQ_EVENT: Neighbor report request + * @WLAN_CONN_DIAG_NBR_RPT_RESP_EVENT: Neighbor report response + * @WLAN_CONN_DIAG_BCN_RPT_REQ_EVENT: Beacon report request + * @WLAN_CONN_DIAG_BCN_RPT_RESP_EVENT: Beacon report response + * @WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT: MLO T2LM request + * @WLAN_CONN_DIAG_MLO_T2LM_RESP_EVENT: MLO T2LM response + * @WLAN_CONN_DIAG_BTM_BLOCK_EVENT: BTM-drop indication + * @WLAN_CONN_DIAG_MAX: MAX tag + */ +enum qca_conn_diag_log_event_type { + WLAN_CONN_DIAG_CONNECTING_EVENT = 0, + WLAN_CONN_DIAG_CONNECT_FAIL_EVENT, + WLAN_CONN_DIAG_AUTH_REQ_EVENT, + WLAN_CONN_DIAG_AUTH_RESP_EVENT, + WLAN_CONN_DIAG_ASSOC_REQ_EVENT, + WLAN_CONN_DIAG_ASSOC_RESP_EVENT, + WLAN_CONN_DIAG_REASSOC_REQ_EVENT, + WLAN_CONN_DIAG_REASSOC_RESP_EVENT, + WLAN_CONN_DIAG_DEAUTH_RX_EVENT, + WLAN_CONN_DIAG_DEAUTH_TX_EVENT, + WLAN_CONN_DIAG_DISASSOC_RX_EVENT, + WLAN_CONN_DIAG_DISASSOC_TX_EVENT, + WLAN_CONN_DIAG_BMISS_EVENT, + WLAN_CONN_DIAG_ROAM_SCAN_START_EVENT, + WLAN_CONN_DIAG_ROAM_SCAN_DONE_EVENT, + WLAN_CONN_DIAG_ROAM_SCORE_CUR_AP_EVENT, + WLAN_CONN_DIAG_ROAM_SCORE_CAND_AP_EVENT, + WLAN_CONN_DIAG_ROAM_RESULT_EVENT, + WLAN_CONN_DIAG_ROAM_CANCEL_EVENT, + WLAN_CONN_DIAG_BTM_REQ_EVENT, + WLAN_CONN_DIAG_BTM_QUERY_EVENT, + WLAN_CONN_DIAG_BTM_RESP_EVENT, + WLAN_CONN_DIAG_BTM_REQ_CAND_EVENT, + WLAN_CONN_DIAG_BTM_WTC_EVENT, + WLAN_CONN_DIAG_DHCP_DISC_EVENT, + WLAN_CONN_DIAG_DHCP_OFFER_EVENT, + WLAN_CONN_DIAG_DHCP_REQUEST_EVENT, + WLAN_CONN_DIAG_DHCP_ACK_EVENT, + WLAN_CONN_DIAG_DHCP_NACK_EVENT, + WLAN_CONN_DIAG_EAPOL_M1_EVENT, + WLAN_CONN_DIAG_EAPOL_M2_EVENT, + WLAN_CONN_DIAG_EAPOL_M3_EVENT, + WLAN_CONN_DIAG_EAPOL_M4_EVENT, + WLAN_CONN_DIAG_GTK_M1_EVENT, + WLAN_CONN_DIAG_GTK_M2_EVENT, + WLAN_CONN_DIAG_EAP_REQ_EVENT, + WLAN_CONN_DIAG_EAP_RESP_EVENT, + WLAN_CONN_DIAG_EAP_SUCC_EVENT, + WLAN_CONN_DIAG_EAP_FAIL_EVENT, + WLAN_CONN_DIAG_CUSTOM_EVENT, + WLAN_CONN_DIAG_EAP_START_EVENT, + WLAN_CONN_DIAG_NBR_RPT_REQ_EVENT, + WLAN_CONN_DIAG_NBR_RPT_RESP_EVENT, + WLAN_CONN_DIAG_BCN_RPT_REQ_EVENT, + WLAN_CONN_DIAG_BCN_RPT_RESP_EVENT, + WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT, + WLAN_CONN_DIAG_MLO_T2LM_RESP_EVENT, + WLAN_CONN_DIAG_BTM_BLOCK_EVENT, + WLAN_CONN_DIAG_MAX +}; + +/* + * enum wlan_diag_wifi_band - Enum describing wifi band + * @WLAN_INVALID_BAND: invalid band + * @WLAN_24GHZ_BAND: 2.4 GHz band + * @WLAN_5GHZ_BAND: 5 GHz band + * @WLAN_6GHZ_BAND: 6 GHz band + */ +enum wlan_diag_wifi_band { + WLAN_INVALID_BAND = 0, + WLAN_24GHZ_BAND, + WLAN_5GHZ_BAND, + WLAN_6GHZ_BAND, +}; + +/** + * enum wlan_diag_mlo_link_switch_reason - MLO link switch reason enumeration + * @LINK_STATE_SWITCH_REASON_VDEV_READY: Link switch when vdev is ready + * @LINK_STATE_SWITCH_REASON_ULL_MODE: Link switch due to ULL mode configuration + * @LINK_STATE_SWITCH_REASON_T2LM_ENABLE: Link switch due to T2LM enable + * @LINK_STATE_SWITCH_REASON_T2LM_DISABLE: Link switch due T2LM disable + * @LINK_STATE_SWITCH_REASON_FORCE_ENABLED: Link switch when link is + * forcibly enable + * @LINK_STATE_SWITCH_REASON_FORCE_DISABLED: Link switch when link is + * forcibly disable + * @LINK_STATE_SWITCH_REASON_LINK_QUALITY: Link switch due to + * poor link quality + * @LINK_STATE_SWITCH_REASON_LINK_CAPACITY: Link switch due to link capacity + * @LINK_STATE_SWITCH_REASON_RSSI: Link switch due to changes in rssi + * @LINK_STATE_SWITCH_REASON_BMISS: Link switch due to BMISS + * @LINK_STATE_SWITCH_REASON_BT_STATUS: Link switch due to BT status + * @LINK_STATE_SWITCH_REASON_MAX: Max value + */ +enum wlan_diag_mlo_link_switch_reason { + LINK_STATE_SWITCH_REASON_VDEV_READY = 0, + LINK_STATE_SWITCH_REASON_ULL_MODE = 1, + LINK_STATE_SWITCH_REASON_T2LM_ENABLE = 2, + LINK_STATE_SWITCH_REASON_T2LM_DISABLE = 3, + LINK_STATE_SWITCH_REASON_FORCE_ENABLED = 4, + LINK_STATE_SWITCH_REASON_FORCE_DISABLED = 5, + LINK_STATE_SWITCH_REASON_LINK_QUALITY = 6, + LINK_STATE_SWITCH_REASON_LINK_CAPACITY = 7, + LINK_STATE_SWITCH_REASON_RSSI = 8, + LINK_STATE_SWITCH_REASON_BMISS = 9, + LINK_STATE_SWITCH_REASON_BT_STATUS = 10, + LINK_STATE_SWITCH_REASON_MAX, +}; + +/** + * enum wlan_bcn_rpt_measurement_mode - Measurement mode enum. + * Defined in IEEE Std 802.11‐2020 Table 9-103. + * @MEASURE_MODE_PASSIVE: Passive measurement mode + * @MEASURE_MODE_ACTIVE: Active measurement mode + * @MEASURE_MODE_BCN_TABLE: Beacon table measurement mode + * @MEASURE_MODE_RESERVED: Reserved + */ +enum wlan_bcn_rpt_measurement_mode { + MEASURE_MODE_PASSIVE = 0, + MEASURE_MODE_ACTIVE, + MEASURE_MODE_BCN_TABLE, + MEASURE_MODE_RESERVED = 0xFF +}; + +/** + * enum wlan_diag_connect_fail_reason - WLAN diag connect fail reason code + * @WLAN_DIAG_UNSPECIFIC_REASON: Unspecific reason + * @WLAN_DIAG_NO_CANDIDATE_FOUND: No candidate found + * @WLAN_DIAG_ABORT_DUE_TO_NEW_REQ_RECVD: Aborted as new command is + * received. + * @WLAN_DIAG_BSS_SELECT_IND_FAILED: Failed BSS select indication + * @WLAN_DIAG_PEER_CREATE_FAILED: peer create failed + * @WLAN_DIAG_JOIN_FAILED: Failed in joining state + * @WLAN_DIAG_JOIN_TIMEOUT: Did not receive beacon or probe response after + * unicast probe request + * @WLAN_DIAG_AUTH_FAILED: Auth rejected by AP + * @WLAN_DIAG_AUTH_TIMEOUT: No Auth resp from AP + * @WLAN_DIAG_ASSOC_FAILED: Assoc rejected by AP + * @WLAN_DIAG_ASSOC_TIMEOUT: No Assoc resp from AP + * @WLAN_DIAG_HW_MODE_FAILURE: failed to change HW mode + * @WLAN_DIAG_SER_FAILURE: Failed to serialize command + * @WLAN_DIAG_SER_TIMEOUT: Serialization cmd timeout + * @WLAN_DIAG_GENERIC_FAILURE: Generic failure apart from above + * @WLAN_DIAG_VALID_CANDIDATE_CHECK_FAIL: Valid Candidate Check fail + */ +enum wlan_diag_connect_fail_reason { + WLAN_DIAG_UNSPECIFIC_REASON = 0, + WLAN_DIAG_NO_CANDIDATE_FOUND = 1, + WLAN_DIAG_ABORT_DUE_TO_NEW_REQ_RECVD, + WLAN_DIAG_BSS_SELECT_IND_FAILED, + WLAN_DIAG_PEER_CREATE_FAILED, + WLAN_DIAG_JOIN_FAILED, + WLAN_DIAG_JOIN_TIMEOUT, + WLAN_DIAG_AUTH_FAILED, + WLAN_DIAG_AUTH_TIMEOUT, + WLAN_DIAG_ASSOC_FAILED, + WLAN_DIAG_ASSOC_TIMEOUT, + WLAN_DIAG_HW_MODE_FAILURE, + WLAN_DIAG_SER_FAILURE, + WLAN_DIAG_SER_TIMEOUT, + WLAN_DIAG_GENERIC_FAILURE, + WLAN_DIAG_VALID_CANDIDATE_CHECK_FAIL, +}; + +/** + * enum wlan_diag_btm_block_reason - BTM drop/ignore reason code + * @WLAN_DIAG_BTM_BLOCK_MBO_WO_PMF: Connected to MBO without PMF capable AP + * @WLAN_DIAG_BTM_BLOCK_UNSUPPORTED_P2P_CONC: p2p go/cli is present which + * restricts BTM roaming + */ +enum wlan_diag_btm_block_reason { + WLAN_DIAG_BTM_BLOCK_MBO_WO_PMF = 1, + WLAN_DIAG_BTM_BLOCK_UNSUPPORTED_P2P_CONC = 2, +}; + +/** + * struct wlan_connectivity_log_diag_cmn - Structure for diag event + * @bssid: bssid + * @vdev_id: Vdev id + * @timestamp_us: Timestamp(time of the day) in microseconds + * @fw_timestamp: FW timestamp in microseconds + * @ktime_us: Kernel Timestamp in microseconds + */ +struct wlan_connectivity_log_diag_cmn { + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint16_t vdev_id; + uint64_t timestamp_us; + uint64_t fw_timestamp; + uint64_t ktime_us; +} qdf_packed; + +#define DIAG_STA_INFO_VERSION 1 + +/** + * struct wlan_diag_sta_info - STA info structure + * @diag_cmn: Common diag info + * @version: structure version + * @is_mlo: MLO connection bit + * @mac_2g: 2.4 GHz link station mac address + * @mac_5g: 5 GHz link station mac address + * @mac_6g: 6 GHz link station mac address + */ +struct wlan_diag_sta_info { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t is_mlo; + uint8_t mac_2g[QDF_MAC_ADDR_SIZE]; + uint8_t mac_5g[QDF_MAC_ADDR_SIZE]; + uint8_t mac_6g[QDF_MAC_ADDR_SIZE]; +} qdf_packed; + +/* + * struct wlan_diag_mlo_cmn_info - MLO common info + * @band: Indicates link on which mlo setup is initiated. + * Refer enum enum wlan_diag_wifi_band. + * @link_id: Link id of the link when link is accepted + * @vdev_id: vdev id associated with the link + * @tid_ul: TID-to-link mapping information on the uplink + * @tid_dl: TID-to-link mapping information on the downlink + * @status: MLO setup status. 0 - Success, 1 - failure + * @link_addr: Link address of the link. + */ +struct wlan_diag_mlo_cmn_info { + uint8_t band; + uint8_t link_id; + uint8_t vdev_id; + uint8_t tid_ul; + uint8_t tid_dl; + uint8_t status; + uint8_t link_addr[QDF_MAC_ADDR_SIZE]; +} qdf_packed; + +#define DIAG_MLO_SETUP_VERSION 1 +#define DIAG_MLO_SETUP_VERSION_V2 2 + +#define MAX_NUM_LINKS_PER_EVENT 3 +/** + * struct wlan_diag_mlo_setup - MLO setup structure + * @diag_cmn: Common diag info + * @version: structure version + * @num_links: Number of links associated for MLO setup + * @reserved: Reserved field + * @status: status code of the link. Non-zero value when link is rejected + * @mlo_cmn_info: MLO common info + */ +struct wlan_diag_mlo_setup { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t num_links; + uint16_t reserved; + struct wlan_diag_mlo_cmn_info mlo_cmn_info[MAX_NUM_LINKS_PER_EVENT]; +} qdf_packed; + +#define DIAG_MLO_RECONFIG_VERSION 1 + +/** + * struct wlan_diag_mlo_reconfig - MLO reconfig diag event structure + * @diag_cmn: Common diag info + * @version: structure version + * @reserved: Reserved field + * @mlo_cmn_info: MLO common info + */ +struct wlan_diag_mlo_reconfig { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint32_t version:8; + uint32_t reserved:24; + struct wlan_diag_mlo_cmn_info mlo_cmn_info; +} qdf_packed; + +#define DIAG_MLO_T2LM_STATUS_VERSION 1 +#define DIAG_MLO_T2LM_STATUS_VERSION_V2 2 + +/** + * struct wlan_diag_mlo_t2lm_status - MLO T2LM status diag event structure + * @diag_cmn: Common diag info + * @version: structure version + * @num_links: Number of links associated for T2LM status + * @reserved: Reserved field + * @mlo_cmn_info: MLO common info + */ +struct wlan_diag_mlo_t2lm_status { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t num_links; + uint16_t reserved; + struct wlan_diag_mlo_cmn_info mlo_cmn_info[MAX_NUM_LINKS_PER_EVENT]; +} qdf_packed; + +#define DIAG_MLO_T2LM_REQ_RESP_VERSION 1 + +/** + * struct wlan_diag_mlo_t2lm_req_resp - MLO T2LM Req/Resp diag event structure + * @diag_cmn: Common diag info + * @version: Structure version + * @band: Indicates the band of the link + * @status: status code of TID-to-Link mapping response frame + * @token: Dialog Token field of TID-To-Link Mapping Request/Response frame + * @is_rx: Indicates the direction of packet. 0 - TX and 1 - RX + * @tx_status: tx status of transmitted packet. Refer enum qdf_dp_tx_rx_status + * @subtype: Subtype of the event + * @reserved: Reserved field + */ +struct wlan_diag_mlo_t2lm_req_resp { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t band; + uint8_t status; + uint8_t token; + uint8_t is_rx:1; + uint8_t tx_status:7; + uint8_t subtype; + uint16_t reserved; +} qdf_packed; + +#define DIAG_MLO_T2LM_TEARDOWN_VERSION 1 + +/** + * struct wlan_diag_mlo_t2lm_teardown - MLO T2LM Teardown diag event structure + * @diag_cmn: Common diag info + * @version: structure version + * @band: Indicates the band of the link. Refer enum wlan_diag_wifi_band + * @tx_status: tx status of transmitted packet. Refer enum qdf_dp_tx_rx_status + * @reserved: Reserved field + */ +struct wlan_diag_mlo_t2lm_teardown { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t band; + uint8_t tx_status; + uint8_t reserved; +} qdf_packed; + +#define DIAG_MLO_LINK_STATUS_VERSION 1 +#define DIAG_MLO_LINK_STATUS_VERSION_2 2 +/** + * struct wlan_diag_mlo_link_status - MLO Link status diag event structure + * @diag_cmn: Common diag info + * @version: structure version + * @active_link: List of current active links. BIT 0: 2.4 GHz BIT 1: 5 GHz + * BIT 2: 6 GHz + * @prev_active_link: List of previous active links. BIT 0: 2.4 G Hz + * BIT 1: 5 GHz BIT 2: 6 GHz + * @associated_links: Links associated in the current connection. + * BIT 0: 2.4 GHz BIT 1: 5 GHz BIT 2: 6 GHz + * @reserved: Reserved field + * @reason: Reason for changed link status. Refer + * enum wlan_diag_mlo_link_switch_reason + */ +struct wlan_diag_mlo_link_status { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t active_link:5; + uint8_t prev_active_link:5; + uint8_t associated_links:5; + uint8_t reserved:1; + uint8_t reason; +} qdf_packed; + +#define DIAG_NBR_RPT_VERSION 1 +#define DIAG_NBR_RPT_VERSION_2 2 + +/** + * struct wlan_diag_nbr_rpt - Neighbor report structure + * @diag_cmn: Common diag info + * @version: structure version + * @num_rpt: the number of neighbor report elements in response frame. + * @subtype: Event Subtype + * @token: dialog token. Dialog Token is a nonzero value chosen by the STA + * @num_freq: Number of frequency in response frame + * @ssid_len: SSID length + * @seq_num: Sequence number + * @ssid: SSID + * @freq: Frequency list in response frame + * @band: Band on which packet was received or transmitted. + * Refer enum enum wlan_diag_wifi_band + * @reserved: Reserved field + */ +struct wlan_diag_nbr_rpt { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t num_rpt; + uint8_t subtype; + uint8_t token; + uint16_t num_freq; + uint16_t ssid_len; + uint32_t seq_num; + char ssid[WLAN_SSID_MAX_LEN]; + uint32_t freq[WLAN_MAX_LOGGING_FREQ]; + uint32_t band:8; + uint32_t reserved:24; +} qdf_packed; + +#define DIAG_BCN_RPT_VERSION 1 +#define DIAG_BCN_RPT_VERSION_2 2 + +/** + * struct wlan_diag_bcn_rpt - Beacon report structure + * @diag_cmn: Common diag info + * @version: structure version + * @subtype: Event Subtype + * @diag_token: Dialog token + * @op_class: Operating classes that include primary channels + * @chan: The channel number field in the beacon report request. + * @req_mode: hex value defines Duration mandatory, parallel, enable, + * request, and report bits. + * @num_rpt: the number of neighbor report elements in response frame. + * @meas_token: A nonzero number that is unique among the Measurement Request + * elements + * @mode: Mode used for measurement.Values defined in IEEE + * Std 802.11‐2020 Table 9-103. + * @duration: The duration over which the Beacon report was measured.(in ms) + * @seq_num: Sequence number. + * @band: Band on which packet was received or transmitted. + * Refer enum enum wlan_diag_wifi_band + * @reserved: Reserved field + */ +struct wlan_diag_bcn_rpt { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t subtype; + uint8_t diag_token; + uint8_t op_class; + uint8_t chan; + uint8_t req_mode; + uint8_t num_rpt; + uint8_t meas_token; + uint16_t mode; + uint16_t duration; + uint32_t seq_num; + uint32_t band:8; + uint32_t reserved:24; +} qdf_packed; + +#define DIAG_ROAM_CAND_VERSION 1 +#define DIAG_ROAM_CAND_VERSION_V2 2 + +/** + * struct wlan_diag_roam_candidate_info - Roam candidate information for + * logging + * @diag_cmn: Common diag info + * @version: Structure Version + * @is_current_ap: Is the entry candidate AP or connected AP + * @is_mlo: MLO connection indicator + * @reserved: Reserved + * @idx: Entry index + * @cu_load: Channel utilization load of the AP in percentage + * @subtype: diag event subtype defined in enum qca_conn_diag_log_event_type + * @total_score: Total candidate AP score + * @freq: Candidate AP channel frequency in MHz + * @rssi: Candidate AP RSSI in dBm + * @etp: Estimated throughput value of the AP in Kbps + */ +struct wlan_diag_roam_candidate_info { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t is_current_ap:1; + uint8_t is_mlo:1; + uint8_t reserved:6; + uint16_t idx; + uint16_t cu_load; + uint16_t subtype; + uint32_t total_score; + uint32_t freq; + int32_t rssi; + uint32_t etp; +} qdf_packed; + +#define DIAG_SCAN_DONE_VERSION 1 + +/** + * struct wlan_diag_roam_scan_done - Roam scan related information + * @diag_cmn: Common diag info + * @version: Structure Version + * @btcoex_active: Is there active bluetooth connection + * @reserved: Reserved field + * @cand_ap_count: Roam candidate AP count + * @num_scanned_freq: Number of scanned frequencies + * @scan_freq: Array of scanned frequencies value in MHz + */ +struct wlan_diag_roam_scan_done { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t btcoex_active:1; + uint8_t reserved:7; + uint16_t cand_ap_count; + uint16_t num_scanned_freq; + uint32_t scan_freq[WLAN_MAX_LOGGING_FREQ]; +} qdf_packed; + +#define DIAG_ROAM_RESULT_VERSION 1 + +/** + * struct wlan_diag_roam_result - Roam result data + * @diag_cmn: Common diag info + * @version: Structure Version + * @is_roam_successful: True if roamed successfully or false if roaming failed + * @is_mlo: Indicates whether the current connection is a MLO connection + * @reserved: Reserved + * @roam_fail_reason: Roam failure reason code defined in enum + * wlan_roam_failure_reason_code + */ +struct wlan_diag_roam_result { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t is_roam_successful:1; + uint8_t is_mlo:1; + uint8_t reserved:6; + uint16_t roam_fail_reason; +} qdf_packed; + +#define DIAG_ROAM_SCAN_START_VERSION 1 +#define DIAG_ROAM_SCAN_START_VERSION_V2 2 + +/** + * struct wlan_diag_roam_scan_start - Structure to store roam scan trigger + * related data. + * @diag_cmn: Common diag info + * @version: Structure Version + * @is_full_scan: True if the scan is Full scan. False if the roam scan is + * partial channel map scan + * @band: Band involved in the roaming during a MLO connection. + * Refer enum enum wlan_diag_wifi_band + * @cu: Current connected channel load in percentage + * @trigger_reason: Roam trigger reason defined by enum roam_trigger_reason + * @trigger_sub_reason: Roam scan trigger sub reason indicating if + * periodic/inactivity scan timer initiated roam. Defined by enum + * roam_trigger_sub_reason + * @rssi: Connected AP RSSI in dBm + * @rssi_thresh: Roam scan trigger threshold in dBm + */ +struct wlan_diag_roam_scan_start { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t is_full_scan:1; + uint8_t band:7; + uint16_t cu; + uint32_t trigger_reason; + uint32_t trigger_sub_reason; + int32_t rssi; + int32_t rssi_thresh; +} qdf_packed; + +#define DIAG_BTM_CAND_VERSION 1 + +/** + * struct wlan_diag_btm_cand_info - BTM candidate information + * @diag_cmn: Common diag info + * @version: Structure Version + * @pad: Padded field + * @idx: Candidate index + * @preference: Candidate preference + */ +struct wlan_diag_btm_cand_info { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t pad; + uint16_t idx; + uint32_t preference; +} qdf_packed; + +#define DIAG_BTM_VERSION 1 +#define DIAG_BTM_VERSION_2 2 + +/** + * struct wlan_diag_btm_info - BTM frame related logging data + * @diag_cmn: Common diag info + * @version: Structure Version + * @reason: Query Reason field. Contains one of the values defined in IEEE + * Std 802.11‐2020 Table 9-198—Transition and Transition Query reasons + * @mode: BTM Request Mode field + * @sub_reason: WTC sub reason code field in the BTM WTC vendor specific IE + * @cand_lst_cnt: Candidates list in the BTM frame + * @status: BSS Transition management status codes defined in + * 802.11‐2020 Table 9-428—BTM status code definitions + * @delay: BSS Termination Delay field + * @is_disassoc_imminent: Disassociation imminent bit + * @band: indicates the link involved in MLO conenection. + * Refer enum enum wlan_diag_wifi_band + * @token: dialog token. Dialog Token is a nonzero value chosen by the STA + * @wtc_duration: WTC duration field in minutes + * while sending the BTM frame to identify the query/request/response + * transaction + * @subtype: Event Subtype + * @validity_timer: Validity interval in TBTT + * @disassoc_tim: Time after which the AP disassociates the STA, defined + * in TBTT. + */ +struct wlan_diag_btm_info { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t reason; + uint8_t mode; + uint8_t sub_reason; + uint8_t cand_lst_cnt; + uint8_t status; + uint8_t delay; + uint8_t is_disassoc_imminent:1; + uint8_t band:7; + uint8_t token; + uint8_t subtype; + uint16_t wtc_duration; + uint32_t validity_timer; + uint32_t disassoc_tim; +} qdf_packed; + +#define DIAG_MGMT_VERSION 1 +#define DIAG_MGMT_VERSION_V2 2 +#define MAX_VSIE_LEN 255 + +/** + * struct wlan_diag_packet_info - Data packets related info + * @diag_cmn: Common diag info + * @version: Structure Version + * @auth_algo: authentication algorithm number defined in IEEE Std 802.11‐2020 + * @auth_frame_type: Authentication frame sub-type for SAE authentication + * defined in Section 9.4.1.1 Authentication Algorithm Number field in + * IEEE Std 802.11‐2020. + * @auth_seq_num: Authentication frame transaction sequence number + * @status: Frame status code as defined in IEEE Std + * 802.11‐2020 Table 9-50—Status codes. + * @tx_status: Frame TX status defined by enum qdf_dp_tx_rx_status + * @reason: reason code defined in Table 9-49 Reason codes field’ from the + * IEEE 802.11 standard document. + * @is_retry_frame: Retry frame indicator + * @is_tx: Packet direction indicator. 0 - RX, 1 - TX + * @supported_links: link id bitmap indicates the links involved + * in MLO connection. + * @reserved: Reserved field + * @subtype: Diag event defined in enum qca_conn_diag_log_event_type + * @assoc_id: Association ID + * @eap_len: EAP data length + * @eap_type: EAP type. Values defined by IANA at: + * https://www.iana.org/assignments/eap-numbers + * @sn: Frame sequence number + * @rssi: Peer RSSI in dBm + * @tx_fail_reason: tx failure reason printed on TX_FAIL status. + * Refer enum qdf_dp_tx_rx_status + * @mld_addr: MLD mac address + * @vsie_len: VSIE length + * @vsie: VSIE + */ +struct wlan_diag_packet_info { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t auth_algo; + uint8_t auth_frame_type; + uint8_t auth_seq_num; + uint8_t status; + uint8_t tx_status; + uint8_t reason; + uint8_t is_retry_frame:1; + uint8_t is_tx:1; + uint8_t supported_links:6; + uint16_t subtype; + uint16_t assoc_id; + uint16_t eap_len; + uint16_t eap_type; + uint32_t sn; + int32_t rssi; + uint8_t tx_fail_reason; + uint8_t mld_addr[QDF_MAC_ADDR_SIZE]; + uint8_t vsie_len; + uint8_t vsie[MAX_VSIE_LEN]; +} qdf_packed; + +#define DIAG_CONN_VERSION 1 + +/** + * struct wlan_diag_connect - Connection related info + * @diag_cmn: Common diag info + * @version: Version number + * @auth_algo: Authentication algorithm number field as defined in + * IEEE 802.11 - 2020 standard section 9.4.1.1 + * @bt_coex: Is there active bluetooth connection + * @reserved: Reserved field + * @ssid_len: Length of SSID + * @ssid: SSID + * @bssid_hint: BSSID hint provided in the connect request + * @reason: failure reason. Refer enum wlan_cm_connect_fail_reason + * @akm: Auth key management suite defined in IEEE Std 802.11‐2020 + * Table 9-151—AKM suite selectors. + * @subtype: Event subtype defined in enum qca_conn_diag_log_event_type. + * @freq: Frequency in MHz + * @freq_hint: Frequency Hint in MHz + * @pairwise_cipher: Pairwise suite value as defined in IEEE 802.11 2020 + * Table 12-10—Integrity and key wrap algorithms. + * @grp_cipher: Group cipher suite value as defined in + * Table 12-10—Integrity and key wrap algorithm in IEEE 802.11 2020. + * @grp_mgmt: Group management cipher suite as defined in + * Table 12-10—Integrity and key wrap algorithms in IEEE 802.11 2020. + */ +struct wlan_diag_connect { + struct wlan_connectivity_log_diag_cmn diag_cmn; + uint8_t version; + uint8_t auth_algo; + uint8_t bt_coex:1; + uint8_t reserved:7; + uint8_t ssid_len; + char ssid[WLAN_SSID_MAX_LEN]; + uint8_t bssid_hint[6]; + uint16_t reason; + uint32_t akm; + uint32_t subtype; + uint32_t freq; + uint32_t freq_hint; + uint32_t pairwise_cipher; + uint32_t grp_cipher; + uint32_t grp_mgmt; +} qdf_packed; + +/** + * struct wlan_roam_candidate_info - Roam candidate information for logging + * @cand_bssid: BSSID of the candidate AP + * @is_current_ap: Is the entry candidate AP or connected AP + * @idx: Entry index + * @cu_load: Channel utilization load of the AP in percentage + * @freq: Candidate AP channel frequency in MHz + * @total_score: Total candidate AP score + * @rssi: Candidate AP RSSI in dBm + * @etp: Estimated throughput value of the AP in Kbps + */ +struct wlan_roam_candidate_info { + struct qdf_mac_addr cand_bssid; + bool is_current_ap; + uint8_t idx; + uint8_t cu_load; + qdf_freq_t freq; + uint16_t total_score; + int32_t rssi; + uint32_t etp; +}; + +/** + * struct wlan_roam_scan_info - Roam scan related information + * @cand_ap_count: Roam candidate AP count + * @num_scanned_freq: Number of scanned frequencies + * @is_btcoex_active: Is bluetooth coex active + * @scan_freq: Array of scanned frequencies value in MHz + */ +struct wlan_roam_scan_info { + uint8_t cand_ap_count; + uint16_t num_scanned_freq; + bool is_btcoex_active; + qdf_freq_t scan_freq[NUM_CHANNELS]; +}; + +/** + * struct wlan_roam_result_info - Roam result data + * @roam_fail_reason: Roam failure reason code defined in enum + * wlan_roam_failure_reason_code + * @is_roam_successful: True if roamed successfully or false if roaming failed + */ +struct wlan_roam_result_info { + enum wlan_roam_failure_reason_code roam_fail_reason; + bool is_roam_successful; +}; + +/** + * struct wlan_roam_trigger_info - Structure to store roam trigger related data. + * @is_full_scan: True if the scan is Full scan. False if the roam scan is + * partial channel map scan + * @trigger_reason: Roam trigger reason defined by enum roam_trigger_reason + * @trigger_sub_reason: Roam scan trigger sub reason indicating if + * periodic/inactivity scan timer initiated roam. Defined by enum + * roam_trigger_sub_reason + * @cu_load: Current connected channel load in percentage + * @current_rssi: Connected AP RSSI in dBm + * @rssi_threshold: Roam scan trigger threshold in dBm + */ +struct wlan_roam_trigger_info { + bool is_full_scan; + enum roam_trigger_reason trigger_reason; + enum roam_trigger_sub_reason trigger_sub_reason; + uint8_t cu_load; + int32_t current_rssi; + int32_t rssi_threshold; +}; + +/** + * struct wlan_btm_cand_info - BTM candidate information + * @idx: Candidate index + * @preference: Candidate preference + * @bssid: candidate bssid + */ +struct wlan_btm_cand_info { + uint8_t idx; + uint8_t preference; + struct qdf_mac_addr bssid; +}; + +/** + * struct wlan_roam_btm_info - BTM frame related logging data + * @reason: Query Reason field. Contains one of the values defined in IEEE + * Std 802.11‐2020 Table 9-198—Transition and Transition Query reasons + * @mode: BTM Request Mode field + * @sub_reason: WTC sub reason code field in the BTM WTC vendor specific IE + * @candidate_list_count: Candidates list in the BTM frame + * @btm_status_code: BSS Transition management status codes defined in + * 802.11‐2020 Table 9-428—BTM status code definitions + * @btm_delay: BSS Termination Delay field + * @is_disassoc_imminent: Disassociation imminent bit + * @token: dialog token. Dialog Token is a nonzero value chosen by the STA + * while sending the BTM frame to identify the query/request/response + * transaction + * @validity_timer: Validity interval in TBTT + * @disassoc_timer: Time after which the AP disassociates the STA, defined + * in TBTT. + * @wtc_duration: WTC duration field in minutes + * @target_bssid: BTM response target bssid field + */ +struct wlan_roam_btm_info { + uint8_t reason; + uint8_t mode; + uint8_t sub_reason; + uint8_t candidate_list_count; + uint8_t btm_status_code; + uint8_t btm_delay; + bool is_disassoc_imminent; + uint8_t token; + uint8_t validity_timer; + uint16_t disassoc_timer; + uint32_t wtc_duration; + struct qdf_mac_addr target_bssid; +}; + +/** + * struct wlan_packet_info - Data packets related info + * @tx_status: Frame TX status defined by enum qdf_dp_tx_rx_status + * @eap_type: EAP type. Values defined by IANA at: + * https://www.iana.org/assignments/eap-numbers + * @eap_len: EAP data length + * @auth_algo: authentication algorithm number defined in IEEE Std 802.11‐2020 + * Section 9.4.1.1 Authentication Algorithm Number field. + * @auth_seq_num: Authentication frame transaction sequence number + * @auth_type: Authentication frame sub-type for SAE authentication. Possible + * values: + * 1 - SAE commit frame + * 2 - SAE confirm frame + * @assoc_id: Association ID received in association response frame as + * defined in IEEE Std 802.11-2020 Figure 9-91-AID field format. + * @frame_status_code: Frame status code as defined in IEEE Std + * 802.11 2020 Table 9-50—Status codes. + * @seq_num: Frame sequence number + * @rssi: Peer RSSI in dBm + * @is_retry_frame: is frame retried + */ +struct wlan_packet_info { + uint8_t tx_status; + uint8_t eap_type; + uint16_t eap_len; + uint8_t auth_algo; + uint8_t auth_seq_num; + uint8_t auth_type; + uint16_t assoc_id; + uint16_t frame_status_code; + uint16_t seq_num; + int32_t rssi; + bool is_retry_frame; +}; + +/** + * struct wlan_connect_info - Connection related info + * @ssid: SSID + * @ssid_len: Length of the SSID + * @bssid_hint: BSSID hint provided in the connect request + * @freq: Frequency in MHz + * @freq_hint: Frequency Hint in MHz + * @akm: Auth key management suite defined in IEEE Std 802.11‐2020 + * Table 9-151—AKM suite selectors. + * @pairwise: Pairwise suite value as defined in IEEE 802.11 2020 + * Table 12-10—Integrity and key wrap algorithms. + * @group: Group cipher suite value as defined in + * Table 12-10—Integrity and key wrap algorithms. + * @group_mgmt: Group management cipher suite as defined in + * Table 12-10—Integrity and key wrap algorithms. + * @auth_type: Authentication algorithm number field as defined in + * IEEE 802.11 - 2020 standard section 9.4.1.1 + * @conn_status: Connection failure status defined by enum + * wlan_cm_connect_fail_reason + * @is_bt_coex_active: Is there active bluetooth connection + */ +struct wlan_connect_info { + char ssid[WLAN_SSID_MAX_LEN]; + uint8_t ssid_len; + struct qdf_mac_addr bssid_hint; + qdf_freq_t freq; + qdf_freq_t freq_hint; + uint32_t akm; + uint32_t pairwise; + uint32_t group; + uint32_t group_mgmt; + uint8_t auth_type; + enum wlan_cm_connect_fail_reason conn_status; + bool is_bt_coex_active; +}; + +#define WLAN_MAX_LOG_RECORDS 45 +#define WLAN_MAX_LOG_LEN 256 +#define WLAN_RECORDS_PER_SEC 20 +#define MAX_RECORD_IN_SINGLE_EVT 5 + +/** + * struct wlan_log_record - Structure for individual records in the ring + * buffer + * @timestamp_us: Timestamp(time of the day) in microseconds + * @fw_timestamp_us: timestamp at which roam scan was triggered + * @ktime_us: kernel timestamp (time of the day) in microseconds + * @vdev_id: VDEV id + * @log_subtype: Tag of the log + * @bssid: AP bssid + * @is_record_filled: indicates if the current record is empty or not + * @conn_info: Connection info + * @pkt_info: Packet info + * @roam_scan: Roam scan + * @ap: Roam candidate AP info + * @roam_result: Roam result + * @roam_trig: Roam trigger related info + * @btm_info: BTM info + * @btm_cand: BTM response candidate info + */ +struct wlan_log_record { + uint64_t timestamp_us; + uint64_t fw_timestamp_us; + uint64_t ktime_us; + uint8_t vdev_id; + uint32_t log_subtype; + struct qdf_mac_addr bssid; + bool is_record_filled; + union { + struct wlan_connect_info conn_info; + struct wlan_packet_info pkt_info; + struct wlan_roam_scan_info roam_scan; + struct wlan_roam_candidate_info ap; + struct wlan_roam_result_info roam_result; + struct wlan_roam_trigger_info roam_trig; + struct wlan_roam_btm_info btm_info; + struct wlan_btm_cand_info btm_cand; + }; +}; + +/** + * struct wlan_cl_osif_cbks - OSIF callbacks to be invoked for connectivity + * logging + * @wlan_connectivity_log_send_to_usr: Send the log buffer to user space + */ +struct wlan_cl_osif_cbks { + QDF_STATUS + (*wlan_connectivity_log_send_to_usr) (struct wlan_log_record *rec, + void *context, + uint8_t num_records); +}; + +/** + * struct wlan_connectivity_log_buf_data - Master structure to hold the + * pointers to the ring buffers. + * @psoc: Global psoc pointer + * @osif_cbks: OSIF callbacks + * @osif_cb_context: Pointer to the context to be passed to OSIF + * callback + * @first_record_timestamp_in_last_sec: First record timestamp + * @sent_msgs_count: Total sent messages counter in the last 1 sec + * @head: Pointer to the 1st record allocated in the ring buffer. + * @read_ptr: Pointer to the next record that can be read. + * @write_ptr: Pointer to the next empty record to be written. + * @write_ptr_lock: Spinlock to protect the write_ptr from multiple producers. + * @max_records: Maximum records in the ring buffer. + * @read_idx: Read index + * @write_idx: Write index + * @dropped_msgs: Dropped logs counter + * @is_active: If the global buffer is initialized or not + */ +struct wlan_connectivity_log_buf_data { + struct wlan_objmgr_psoc *psoc; + struct wlan_cl_osif_cbks osif_cbks; + void *osif_cb_context; + uint64_t first_record_timestamp_in_last_sec; + uint64_t sent_msgs_count; + struct wlan_log_record *head; + struct wlan_log_record *read_ptr; + struct wlan_log_record *write_ptr; + qdf_spinlock_t write_ptr_lock; + uint8_t max_records; + uint8_t read_idx; + uint8_t write_idx; + qdf_atomic_t dropped_msgs; + qdf_atomic_t is_active; +}; + +#define logging_err_rl(params...) \ + QDF_TRACE_ERROR_RL(QDF_MODULE_ID_MLME, ## params) +#define logging_warn_rl(params...) \ + QDF_TRACE_WARN_RL(QDF_MODULE_ID_MLME, ## params) +#define logging_info_rl(params...) \ + QDF_TRACE_INFO_RL(QDF_MODULE_ID_MLME, ## params) + +#define logging_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_QDF, ## params) +#define logging_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, ## params) +#define logging_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_QDF, ## params) + +#if (defined(CONNECTIVITY_DIAG_EVENT) && \ + defined(WLAN_FEATURE_ROAM_OFFLOAD)) +/** + * wlan_print_cached_sae_auth_logs() - Enqueue SAE authentication frame logs + * @psoc: Global psoc pointer + * @bssid: BSSID + * @vdev_id: Vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_print_cached_sae_auth_logs(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id); + +/** + * wlan_is_log_record_present_for_bssid() - Check if there is existing log + * record for the given bssid + * @psoc: Global psoc pointer + * @bssid: BSSID + * @vdev_id: vdev id + * + * Return: true if record is present else false + */ +bool wlan_is_log_record_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id); + +/** + * wlan_is_sae_auth_log_present_for_bssid() - Is cached SAE auth log record + * present for the given bssid. This API checks on all the link vdev if the + * given vdev_id is an MLO vdev and updates the vdev_id to caller in which + * the auth frame was cached. + * @psoc: Global psoc pointer + * @bssid: BSSID + * @vdev_id: vdev id + * + * Return: True if an entry is found + */ +bool +wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *vdev_id); + +/** + * wlan_clear_sae_auth_logs_cache() - Clear the cached auth related logs + * @psoc: Pointer to global psoc object + * @vdev_id: vdev id + * + * Return: None + */ +void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#else +static inline +QDF_STATUS wlan_print_cached_sae_auth_logs(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool wlan_is_log_record_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id) +{ + return false; +} + +static inline bool +wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *vdev_id) +{ + return false; +} + +static inline +void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{} +#endif + +#if defined(CONNECTIVITY_DIAG_EVENT) +/** + * wlan_connectivity_mgmt_event() - Fill and enqueue a new record + * for management frame information. + * @psoc: Pointer to global psoc object + * @mac_hdr: 802.11 management frame header + * @vdev_id: Vdev id + * @status_code: Frame status code as defined in IEEE 802.11 - 2020 standard + * section 9.4.1.9 + * @tx_status: Frame TX status defined by enum qdf_dp_tx_rx_status + * @peer_rssi: Peer RSSI in dBm + * @auth_algo: Authentication algorithm number field as defined in IEEE 802.11 - + * 2020 standard section 9.4.1.1 + * @auth_type: indicates SAE authentication frame type. Possible values are: + * 1 - SAE commit frame + * 2 - SAE confirm frame + * @auth_seq: Authentication frame transaction sequence number as defined in + * IEEE 802.11 - 2020 standard section 9.4.1.2 + * @aid: Association ID + * @tag: Record type main tag + * + * Return: QDF_STATUS + */ +void +wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc, + struct wlan_frame_hdr *mac_hdr, + uint8_t vdev_id, uint16_t status_code, + enum qdf_dp_tx_rx_status tx_status, + int8_t peer_rssi, + uint8_t auth_algo, uint8_t auth_type, + uint8_t auth_seq, uint16_t aid, + enum wlan_main_tag tag); + +/** + * wlan_populate_vsie() - Populate VSIE field for logging + * @vdev: vdev pointer + * @data: Diag packet info data + * @is_tx: flag to indicate whether packet transmitted or received + * + * Return: None + */ +void +wlan_populate_vsie(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, bool is_tx); + +/** + * wlan_cdp_set_peer_freq() - API to set frequency to dp peer + * @psoc: psoc pointer + * @peer_mac: Bssid of peer + * @freq: frequency(in MHz) + * @vdev_id: vdev id + * + * Return: None + */ +void +wlan_cdp_set_peer_freq(struct wlan_objmgr_psoc *psoc, uint8_t *peer_mac, + uint32_t freq, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_11BE_MLO + +/** + * wlan_connectivity_mlo_reconfig_event() -API to log MLO reconfig event + * @vdev: vdev pointer + * + * Return: None + */ +void +wlan_connectivity_mlo_reconfig_event(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_connectivity_mlo_setup_event() - Fill and send MLO setup data + * @vdev: vdev pointer + * @is_band_present: If Band is present(Associated link band is shared by FW) + * + * Return: None + */ +void wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev, + bool is_band_present); + +/** + * wlan_connectivity_t2lm_req_resp_event - API to send t2lm Req/resp + * event logs to userspace + * @vdev: vdev pointer + * @token: dialog Token + * @t2lm_status: T2LM response status code. Refer enum wlan_t2lm_resp_frm_type + * @tx_status: TX status + * @freq: frequency on which frame was transmitted/received + * @is_rx: Flag to inidcate packet being received + * @subtype: Determine whether the evnt sent is for t2lm request + * or t2lm response + * + * Return: None + */ +void +wlan_connectivity_t2lm_req_resp_event(struct wlan_objmgr_vdev *vdev, + uint8_t token, + enum wlan_t2lm_resp_frm_type t2lm_status, + enum qdf_dp_tx_rx_status tx_status, + qdf_freq_t freq, + bool is_rx, uint8_t subtype); +/** + * wlan_connectivity_t2lm_status_event() - Fill and send T2LM data + * @vdev: vdev pointer + * + * Return: None + */ +void wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_populate_mlo_mgmt_event_param() - API to populate MLO management frame + * parameter + * @vdev: vdev pointer + * @data: Buffer to be filled with MLO parameter + * @tag: WLAN event tag. Refer enum wlan_main_tag + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag); + +/** + * wlan_populate_roam_mld_log_param() - Populate roam MLO log parameters + * @vdev: Pointer to vdev object + * @data: Diag event packet info + * @tag: Main Tag + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_populate_roam_mld_log_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag); +#else +static inline void +wlan_connectivity_mlo_reconfig_event(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev, + bool is_band_present) +{ +} + +static inline void +wlan_connectivity_t2lm_req_resp_event(struct wlan_objmgr_vdev *vdev, + uint8_t token, + enum wlan_t2lm_resp_frm_type status, + enum qdf_dp_tx_rx_status tx_status, + qdf_freq_t freq, + bool is_rx, uint8_t subtype) +{} + +static inline void +wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline QDF_STATUS +wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_populate_roam_mld_log_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_populate_vsie() - Populate VSIE field for logging + * @vdev: vdev pointer + * @data: Diag packet info data + * @is_tx: flag to indicate whether packet transmitted or received + * + * Return: None + */ +void +wlan_populate_vsie(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, bool is_tx); +/** + * wlan_convert_freq_to_diag_band() - API to convert frequency to band value + * mentioned in enum wlan_diag_wifi_band + * @ch_freq: Frequency(in MHz) + * + * Return: Band specified in enum wlan_diag_wifi_band + */ +enum wlan_diag_wifi_band +wlan_convert_freq_to_diag_band(uint16_t ch_freq); + +static inline void wlan_connectivity_logging_stop(void) +{} + +/** + * wlan_connectivity_sta_info_event() - APi to send STA info event + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @is_roam: Is sta info event for roaming stats + * + * Return: None + */ +void +wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_roam); + +/** + * wlan_connectivity_connecting_event() - API to log connecting event + * @vdev: vdev pointer + * @con_req: Connection request parameter + * + * Return: None + */ +void +wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_req *con_req); + +#elif defined(WLAN_FEATURE_CONNECTIVITY_LOGGING) +/** + * wlan_connectivity_logging_start() - Initialize the connectivity/roaming + * logging buffer + * @psoc: Global psoc pointer + * @osif_cbks: OSIF callbacks + * @osif_cb_context: OSIF callback context argument + * + * Return: None + */ +void wlan_connectivity_logging_start(struct wlan_objmgr_psoc *psoc, + struct wlan_cl_osif_cbks *osif_cbks, + void *osif_cb_context); + +/** + * wlan_connectivity_logging_stop() - Deinitialize the connectivity logging + * buffers and spinlocks. + * + * Return: None + */ +void wlan_connectivity_logging_stop(void); + +/** + * wlan_connectivity_log_dequeue() - Send the connectivity logs to userspace + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_connectivity_log_dequeue(void); + +/** + * wlan_connectivity_log_enqueue() - Add new record to the logging buffer + * @new_record: Pointer to the new record to be added + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_connectivity_log_enqueue(struct wlan_log_record *new_record); + +/** + * wlan_connectivity_mgmt_event() - Fill and enqueue a new record + * for management frame information. + * @psoc: Pointer to global psoc object + * @mac_hdr: 802.11 management frame header + * @vdev_id: Vdev id + * @status_code: Frame status code as defined in IEEE 802.11 - 2020 standard + * section 9.4.1.9 + * @tx_status: Frame TX status defined by enum qdf_dp_tx_rx_status + * @peer_rssi: Peer RSSI in dBm + * @auth_algo: Authentication algorithm number field as defined in IEEE 802.11 - + * 2020 standard section 9.4.1.1 + * @auth_type: indicates SAE authentication frame type. Possible values are: + * 1 - SAE commit frame + * 2 - SAE confirm frame + * @auth_seq: Authentication frame transaction sequence number as defined in + * IEEE 802.11 - 2020 standard section 9.4.1.2 + * @aid: Association ID + * @tag: Record type main tag + * + * Return: QDF_STATUS + */ +void +wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc, + struct wlan_frame_hdr *mac_hdr, + uint8_t vdev_id, uint16_t status_code, + enum qdf_dp_tx_rx_status tx_status, + int8_t peer_rssi, + uint8_t auth_algo, uint8_t auth_type, + uint8_t auth_seq, uint16_t aid, + enum wlan_main_tag tag); + +/** + * wlan_connectivity_connecting_event() - API to log connecting event + * @vdev: vdev pointer + * @con_req: Connection request parameter + * + * Return: None + */ +void +wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_req *con_req); + +/** + * wlan_populate_vsie() - Populate VSIE field for logging + * @vdev: vdev pointer + * @data: Diag packet info data + * @is_tx: Flag to indicate whether the packet is transmitted or received + * + * Return: None + */ +void +wlan_populate_vsie(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, bool is_tx); + +/** + * wlan_connectivity_sta_info_event() - APi to send STA info event + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @is_roam: Is sta info event for roaming stats + */ +void +wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_roam); + +/** + * wlan_convert_freq_to_diag_band() - API to convert frequency to band value + * mentioned in enum wlan_diag_wifi_band + * @ch_freq: Frequency(in MHz) + * + * Return: Band specified in enum wlan_diag_wifi_band + */ +enum wlan_diag_wifi_band +wlan_convert_freq_to_diag_band(uint16_t ch_freq); + +/** + * wlan_populate_vsie() - Populate VSIE field for logging + * @vdev: vdev pointer + * @data: Diag packet info data + * @is_tx: flag to indicate whether packet transmitted or received + * + * Return: None + */ +void +wlan_populate_vsie(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, bool is_tx); + +/** + * wlan_cdp_set_peer_freq() - API to set frequency to dp peer + * @psoc: psoc pointer + * @peer_mac: Bssid of peer + * @freq: frequency(in MHz) + * @vdev_id: vdev id + * + * Return: None + */ +void +wlan_cdp_set_peer_freq(struct wlan_objmgr_psoc *psoc, uint8_t *peer_mac, + uint32_t freq, uint8_t vdev_id); + +#else +static inline +void wlan_connectivity_logging_start(struct wlan_objmgr_psoc *psoc, + struct wlan_cl_osif_cbks *osif_cbks, + void *osif_cb_context) +{} + +static inline void wlan_connectivity_logging_stop(void) +{} + +static inline QDF_STATUS wlan_connectivity_log_dequeue(void) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS wlan_connectivity_log_enqueue(struct wlan_log_record *new_record) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc, + struct wlan_frame_hdr *mac_hdr, + uint8_t vdev_id, uint16_t status_code, + enum qdf_dp_tx_rx_status tx_status, + int8_t peer_rssi, + uint8_t auth_algo, uint8_t auth_type, + uint8_t auth_seq, uint16_t aid, + enum wlan_main_tag tag) +{} + +static inline void +wlan_populate_vsie(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, bool is_tx) +{ +} + +static inline enum wlan_diag_wifi_band +wlan_convert_freq_to_diag_band(uint16_t ch_freq) +{ + return WLAN_INVALID_BAND; +} + +static inline QDF_STATUS +wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +wlan_cdp_set_peer_freq(struct wlan_objmgr_psoc *psoc, uint8_t *peer_mac, + uint32_t freq, uint8_t vdev_id) +{} + +static inline void +wlan_connectivity_mlo_reconfig_event(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_roam) +{} + +static inline void +wlan_connectivity_t2lm_req_resp_event(struct wlan_objmgr_vdev *vdev, + uint8_t token, + enum wlan_t2lm_resp_frm_type status, + enum qdf_dp_tx_rx_status tx_status, + qdf_freq_t freq, + bool is_rx, uint8_t subtype) +{} + +static inline void +wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_req *con_req) +{ +} +#endif + +#if defined(CONNECTIVITY_DIAG_EVENT) && defined(WLAN_FEATURE_11BE_MLO) +/** + * wlan_connectivity_mld_link_status_event() - Send connectivity logging + * ML Link Status event + * @psoc: Pointer to global PSOC object + * @src: Src parameters to be sent + * + * Return: None + */ +void +wlan_connectivity_mld_link_status_event(struct wlan_objmgr_psoc *psoc, + struct mlo_link_switch_params *src); +#else +static inline +void wlan_connectivity_mld_link_status_event(struct wlan_objmgr_psoc *psoc, + struct mlo_link_switch_params *src) +{} +#endif /* CONNECTIVITY_DIAG_EVENT && WLAN_FEATURE_11BE_MLO */ +#endif /* _WLAN_CONNECTIVITY_LOGGING_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/logging/src/wlan_connectivity_logging.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/logging/src/wlan_connectivity_logging.c new file mode 100644 index 0000000000..1fd30e71e5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/logging/src/wlan_connectivity_logging.c @@ -0,0 +1,1231 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_logging.c + * + * Implementation for the connectivity and roam logging api. + */ +#include "wlan_connectivity_logging.h" +#include "wlan_cm_api.h" +#include "wlan_mlme_main.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlme_api.h" +#include "cdp_txrx_ctrl.h" +#include "wlan_mlo_mgr_peer.h" +#include "wlan_scan_api.h" + +#ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING +static struct wlan_connectivity_log_buf_data global_cl; + +static void +wlan_connectivity_logging_register_callbacks( + struct wlan_cl_osif_cbks *osif_cbks, + void *osif_cb_context) +{ + global_cl.osif_cbks.wlan_connectivity_log_send_to_usr = + osif_cbks->wlan_connectivity_log_send_to_usr; + global_cl.osif_cb_context = osif_cb_context; +} + +void wlan_connectivity_logging_start(struct wlan_objmgr_psoc *psoc, + struct wlan_cl_osif_cbks *osif_cbks, + void *osif_cb_context) +{ + global_cl.head = qdf_mem_valloc(sizeof(*global_cl.head) * + WLAN_MAX_LOG_RECORDS); + if (!global_cl.head) { + QDF_BUG(0); + return; + } + + global_cl.psoc = psoc; + global_cl.write_idx = 0; + global_cl.read_idx = 0; + + qdf_atomic_init(&global_cl.dropped_msgs); + qdf_spinlock_create(&global_cl.write_ptr_lock); + + global_cl.read_ptr = global_cl.head; + global_cl.write_ptr = global_cl.head; + global_cl.max_records = WLAN_MAX_LOG_RECORDS; + + wlan_connectivity_logging_register_callbacks(osif_cbks, + osif_cb_context); + qdf_atomic_set(&global_cl.is_active, 1); +} + +void wlan_connectivity_logging_stop(void) +{ + if (!qdf_atomic_read(&global_cl.is_active)) + return; + + qdf_spin_lock_bh(&global_cl.write_ptr_lock); + + global_cl.psoc = NULL; + global_cl.osif_cb_context = NULL; + global_cl.osif_cbks.wlan_connectivity_log_send_to_usr = NULL; + + qdf_atomic_set(&global_cl.is_active, 0); + global_cl.read_ptr = NULL; + global_cl.write_ptr = NULL; + global_cl.read_idx = 0; + global_cl.write_idx = 0; + + qdf_mem_vfree(global_cl.head); + global_cl.head = NULL; + qdf_spin_unlock_bh(&global_cl.write_ptr_lock); + qdf_spinlock_destroy(&global_cl.write_ptr_lock); +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && \ + defined(WLAN_FEATURE_11BE_MLO) +static void +wlan_clear_ml_vdev_sae_auth_logs(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *link_vdev; + struct mlme_legacy_priv *mlme_priv; + uint8_t i, link_vdev_id; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + logging_err_rl("mlo_dev ctx is NULL for vdev:%d", + wlan_vdev_get_id(vdev)); + return; + } + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + link_vdev_id = + wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + link_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(link_vdev); + if (!mlme_priv) { + logging_err_rl("vdev:%d legacy private object is NULL", + link_vdev_id); + return; + } + + logging_debug("vdev:%d clear sae auth logs cache", + link_vdev_id); + qdf_mem_zero(mlme_priv->auth_log, sizeof(mlme_priv->auth_log)); + } +} +#else +static inline void +wlan_clear_ml_vdev_sae_auth_logs(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wlan_clear_sae_auth_logs_cache(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_err_rl("Invalid vdev:%d", vdev_id); + return; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + wlan_clear_ml_vdev_sae_auth_logs(psoc, vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + logging_err_rl("vdev legacy private object is NULL"); + return; + } + + logging_debug("vdev:%d clear sae auth logs cache", vdev_id); + qdf_mem_zero(mlme_priv->auth_log, sizeof(mlme_priv->auth_log)); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(CONNECTIVITY_DIAG_EVENT) +QDF_STATUS wlan_print_cached_sae_auth_logs(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id) +{ + uint8_t i, j; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_err_rl("Invalid vdev:%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + logging_err_rl("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_E_FAILURE; + } + + /* + * Get the index of matching bssid and queue all the records for + * that bssid + */ + for (i = 0; i < MAX_ROAM_CANDIDATE_AP; i++) { + if (!mlme_priv->auth_log[i][0].diag_cmn.ktime_us) + continue; + + if (qdf_is_macaddr_equal(bssid, + (struct qdf_mac_addr *)mlme_priv->auth_log[i][0].diag_cmn.bssid)) + break; + } + + /* + * No matching bssid found in cached log records. + * So return from here. + */ + if (i >= MAX_ROAM_CANDIDATE_AP) { + logging_debug("No cached SAE auth logs"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_E_FAILURE; + } + + for (j = 0; j < WLAN_ROAM_MAX_CACHED_AUTH_FRAMES; j++) { + if (!mlme_priv->auth_log[i][j].diag_cmn.ktime_us) + continue; + + WLAN_HOST_DIAG_EVENT_REPORT(&mlme_priv->auth_log[i][j], + EVENT_WLAN_MGMT); + qdf_mem_zero(&mlme_priv->auth_log[i][j], + sizeof(struct wlan_diag_packet_info)); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return QDF_STATUS_SUCCESS; +} + +bool wlan_is_log_record_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id) +{ + struct wlan_diag_packet_info *pkt_info; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + int i; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_err_rl("Invalid vdev:%d", vdev_id); + return false; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + logging_err_rl("vdev legacy private object is NULL"); + return false; + } + + for (i = 0; i < MAX_ROAM_CANDIDATE_AP; i++) { + pkt_info = &mlme_priv->auth_log[i][0]; + if (!pkt_info->diag_cmn.ktime_us) + continue; + + if (qdf_is_macaddr_equal(bssid, + (struct qdf_mac_addr *)pkt_info->diag_cmn.bssid)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return true; + } + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return false; +} + +#ifdef WLAN_FEATURE_11BE_MLO +bool +wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint8_t i, link_vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, *vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_err_rl("Invalid vdev:%d", *vdev_id); + return false; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return wlan_is_log_record_present_for_bssid(psoc, bssid, + *vdev_id); + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + if (!mlo_dev_ctx) { + logging_err_rl("mlo_dev ctx is NULL for vdev:%d", *vdev_id); + return wlan_is_log_record_present_for_bssid(psoc, bssid, + *vdev_id); + } + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + if (wlan_is_log_record_present_for_bssid(psoc, bssid, + link_vdev_id)) { + *vdev_id = link_vdev_id; + return true; + } + } + + return false; +} +#else +bool +wlan_is_sae_auth_log_present_for_bssid(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *vdev_id) +{ + return wlan_is_log_record_present_for_bssid(psoc, bssid, *vdev_id); +} +#endif + +/** + * wlan_add_sae_log_record_to_available_slot() - Add a new log record into the + * cache for the queue. + * @psoc: objmgr psoc object + * @vdev: objmgr vdev object + * @pkt_info: Log packet record pointer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_add_sae_log_record_to_available_slot(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *pkt_info) +{ + struct mlme_legacy_priv *mlme_priv; + uint8_t i, j; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + bool is_entry_exist = + wlan_is_log_record_present_for_bssid(psoc, + (struct qdf_mac_addr *)pkt_info->diag_cmn.bssid, + vdev_id); + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + logging_err_rl("vdev:%d legacy private object is NULL", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < MAX_ROAM_CANDIDATE_AP; i++) { + if (is_entry_exist && + mlme_priv->auth_log[i][0].diag_cmn.ktime_us && + qdf_is_macaddr_equal((struct qdf_mac_addr *)pkt_info->diag_cmn.bssid, + (struct qdf_mac_addr *)mlme_priv->auth_log[i][0].diag_cmn.bssid)) { + /* + * Frames for given bssid already exists store the new + * frame in corresponding array in empty slot + */ + for (j = 0; j < WLAN_ROAM_MAX_CACHED_AUTH_FRAMES; j++) { + if (mlme_priv->auth_log[i][j].diag_cmn.ktime_us) + continue; + + logging_debug("vdev:%d added at [i][j]:[%d][%d]", + vdev_id, i, j); + mlme_priv->auth_log[i][j] = *pkt_info; + break; + } + + } else if (!is_entry_exist && + !mlme_priv->auth_log[i][0].diag_cmn.ktime_us) { + /* + * For given record, there is no existing bssid + * so add the entry at first available slot + */ + logging_debug("vdev:%d added entry at [i][j]:[%d][%d]", + vdev_id, i, 0); + mlme_priv->auth_log[i][0] = *pkt_info; + break; + } + } + + return QDF_STATUS_SUCCESS; +} + +static void +wlan_cache_connectivity_log(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_diag_packet_info *pkt_info) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_err_rl("Invalid vdev:%d", vdev_id); + return; + } + + wlan_add_sae_log_record_to_available_slot(psoc, vdev, pkt_info); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} +#endif + +#define WLAN_SAE_AUTH_ALGO_NUMBER 3 +#ifdef CONNECTIVITY_DIAG_EVENT + +#ifdef WLAN_FEATURE_11BE_MLO +void +wlan_connectivity_t2lm_req_resp_event(struct wlan_objmgr_vdev *vdev, + uint8_t token, + enum wlan_t2lm_resp_frm_type t2lm_status, + enum qdf_dp_tx_rx_status tx_status, + qdf_freq_t freq, + bool is_rx, uint8_t subtype) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_mlo_t2lm_req_resp); + + wlan_diag_event.diag_cmn.vdev_id = wlan_vdev_get_id(vdev); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + + wlan_diag_event.version = DIAG_MLO_T2LM_REQ_RESP_VERSION; + + wlan_diag_event.token = token; + wlan_diag_event.subtype = subtype; + + wlan_diag_event.status = t2lm_status; + wlan_diag_event.tx_status = wlan_get_diag_tx_status(tx_status); + wlan_diag_event.is_rx = is_rx; + + wlan_diag_event.band = wlan_convert_freq_to_diag_band(freq); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_MLO_T2LM_REQ_RESP); +} + +void +wlan_connectivity_mlo_reconfig_event(struct wlan_objmgr_vdev *vdev) +{ + struct mlo_link_info *link_info = NULL; + struct wlan_channel *chan_info = NULL; + uint8_t link_id; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_mlo_reconfig); + + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.version = DIAG_MLO_RECONFIG_VERSION; + + link_id = wlan_vdev_get_link_id(vdev); + wlan_diag_event.mlo_cmn_info.link_id = link_id; + + if (!vdev->mlo_dev_ctx) + return; + + link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id); + if (!link_info) { + mlme_err("linl: %d Link info not found", link_id); + return; + } + chan_info = link_info->link_chan_info; + if (!chan_info) { + mlme_err("link: %d Chan info not found", link_id); + return; + } + + wlan_diag_event.mlo_cmn_info.band = + wlan_convert_freq_to_diag_band(chan_info->ch_freq); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MLO_RECONFIG); +} + +static QDF_STATUS +wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_sta_info *wlan_diag_event) +{ + uint i = 0; + struct mlo_link_switch_context *link_ctx = vdev->mlo_dev_ctx->link_ctx; + struct wlan_channel *link_chan_info; + + if (!link_ctx) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { + link_chan_info = link_ctx->links_info[i].link_chan_info; + + if (wlan_reg_is_24ghz_ch_freq( + (qdf_freq_t)link_chan_info->ch_freq)) { + qdf_mem_copy(wlan_diag_event->mac_2g, + link_ctx->links_info[i].link_addr.bytes, + QDF_MAC_ADDR_SIZE); + } else if (wlan_reg_is_5ghz_ch_freq( + (qdf_freq_t)link_chan_info->ch_freq)) { + qdf_mem_copy(wlan_diag_event->mac_5g, + link_ctx->links_info[i].link_addr.bytes, + QDF_MAC_ADDR_SIZE); + } else if (wlan_reg_is_6ghz_chan_freq( + link_chan_info->ch_freq)) { + qdf_mem_copy(wlan_diag_event->mac_6g, + link_ctx->links_info[i].link_addr.bytes, + QDF_MAC_ADDR_SIZE); + } + } + + return QDF_STATUS_SUCCESS; +} + +static uint8_t +wlan_populate_band_bitmap(struct mlo_link_switch_context *link_ctx) +{ + uint8_t i, band_bitmap = 0, band; + struct wlan_channel *link_chan_info; + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { + link_chan_info = link_ctx->links_info[i].link_chan_info; + + band = wlan_reg_freq_to_band((qdf_freq_t) + link_chan_info->ch_freq); + + band_bitmap |= BIT(band); + } + + return band_bitmap; +} + +QDF_STATUS +wlan_populate_mlo_mgmt_event_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag) +{ + struct mlo_link_switch_context *link_ctx; + struct qdf_mac_addr peer_mac, peer_mld_mac; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!mlo_is_mld_sta(vdev)) + return status; + + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return QDF_STATUS_E_INVAL; + + status = wlan_vdev_get_bss_peer_mac(vdev, &peer_mac); + if (QDF_IS_STATUS_ERROR(status)) { + logging_err("vdev: %d bss peer not found", + wlan_vdev_get_id(vdev)); + return status; + } + + qdf_mem_copy(data->diag_cmn.bssid, peer_mac.bytes, QDF_MAC_ADDR_SIZE); + + status = wlan_vdev_get_bss_peer_mld_mac(vdev, &peer_mld_mac); + if (QDF_IS_STATUS_ERROR(status)) { + logging_err("vdev: %d failed to get mld mac address of peer", + wlan_vdev_get_id(vdev)); + return status; + } + + qdf_mem_copy(data->mld_addr, peer_mld_mac.bytes, QDF_MAC_ADDR_SIZE); + + if (tag != WLAN_ASSOC_REQ && tag != WLAN_REASSOC_REQ) + return status; + + link_ctx = vdev->mlo_dev_ctx->link_ctx; + if (!link_ctx) { + logging_debug("vdev: %d link_ctx not found", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + data->supported_links = wlan_populate_band_bitmap(link_ctx); + + return status; +} + +QDF_STATUS +wlan_populate_roam_mld_log_param(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + enum wlan_main_tag tag) +{ + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_INVAL; + + status = wlan_scan_get_mld_addr_by_link_addr( + pdev, (struct qdf_mac_addr *)data->diag_cmn.bssid, + (struct qdf_mac_addr *)data->mld_addr); + if (QDF_IS_STATUS_ERROR(status)) + logging_err_rl("vdev:%d Not able to fetch MLD addr for link addr: " QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(vdev), + QDF_MAC_ADDR_REF(data->diag_cmn.bssid)); + + return status; +} + +enum wlan_diag_wifi_band +wlan_convert_freq_to_diag_band(uint16_t ch_freq) +{ + enum reg_wifi_band band; + + band = wlan_reg_freq_to_band((qdf_freq_t)ch_freq); + + switch (band) { + case REG_BAND_2G: + return WLAN_24GHZ_BAND; + case REG_BAND_5G: + return WLAN_5GHZ_BAND; + case REG_BAND_6G: + return WLAN_6GHZ_BAND; + default: + return WLAN_INVALID_BAND; + } +} + +#define REJECTED_LINK_STATUS 1 + +void +wlan_connectivity_mlo_setup_event(struct wlan_objmgr_vdev *vdev, + bool is_band_present) +{ + uint i = 0; + struct mlo_link_switch_context *link_ctx = NULL; + struct wlan_channel *chan_info; + uint8_t num_links = 0; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_mlo_setup); + + /* + * MLO setup event need to be logged in the following cases: + * + * 1. When connection request is initiated and the ML + * candidate is selected. + * 2. When roamed successfully to ML AP + * + */ + if ((wlan_cm_is_vdev_connecting(vdev) && !mlo_is_mld_sta(vdev)) || + (wlan_cm_is_vdev_active(vdev) && !is_band_present)) + return; + + qdf_mem_zero(&wlan_diag_event, sizeof(struct wlan_diag_mlo_setup)); + + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.version = DIAG_MLO_SETUP_VERSION_V2; + + if (!vdev->mlo_dev_ctx) { + logging_err("vdev: %d MLO dev ctx not found", + wlan_vdev_get_id(vdev)); + return; + } + + link_ctx = vdev->mlo_dev_ctx->link_ctx; + if (!link_ctx) { + logging_err("vdev: %d mlo link ctx not found", + wlan_vdev_get_id(vdev)); + return; + } + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { + if (link_ctx->links_info[i].link_id == WLAN_INVALID_LINK_ID) + continue; + + chan_info = link_ctx->links_info[i].link_chan_info; + if (!chan_info) { + logging_debug("link %d: chan_info not found", + link_ctx->links_info[i].link_id); + continue; + } + + wlan_diag_event.mlo_cmn_info[num_links].link_id = + link_ctx->links_info[i].link_id; + wlan_diag_event.mlo_cmn_info[num_links].vdev_id = + link_ctx->links_info[i].vdev_id; + + qdf_mem_copy(wlan_diag_event.mlo_cmn_info[num_links].link_addr, + link_ctx->links_info[i].ap_link_addr.bytes, + QDF_MAC_ADDR_SIZE); + + wlan_diag_event.mlo_cmn_info[num_links].band = + wlan_convert_freq_to_diag_band(chan_info->ch_freq); + + if (wlan_diag_event.mlo_cmn_info[num_links].band == + WLAN_INVALID_BAND) + wlan_diag_event.mlo_cmn_info[i].status = + REJECTED_LINK_STATUS; + + num_links++; + } + + wlan_diag_event.num_links = num_links; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MLO_SETUP); +} + +#define IS_LINK_SET(link_bitmap, link_id) ((link_bitmap) & (BIT(link_id))) +#define DEFAULT_TID_MAP 0xFF + +static void +wlan_populate_tid_link_id_bitmap(struct wlan_t2lm_info *t2lm, + struct mlo_link_info *link_info, + struct wlan_diag_mlo_t2lm_status *buf, + uint8_t bss_link) +{ + uint8_t link_id; + uint8_t dir, i; + uint16_t freq; + + link_id = link_info->link_id; + freq = link_info->link_chan_info->ch_freq; + buf->mlo_cmn_info[bss_link].band = + wlan_convert_freq_to_diag_band(freq); + buf->mlo_cmn_info[bss_link].vdev_id = link_info->vdev_id; + + for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { + if (t2lm[dir].default_link_mapping) { + buf->mlo_cmn_info[bss_link].tid_ul = DEFAULT_TID_MAP; + buf->mlo_cmn_info[bss_link].tid_dl = DEFAULT_TID_MAP; + continue; + } + + for (i = 0; i < T2LM_MAX_NUM_TIDS; i++) { + switch (t2lm[dir].direction) { + case WLAN_T2LM_DL_DIRECTION: + if ( + IS_LINK_SET( + t2lm[dir].ieee_link_map_tid[i], link_id)) + buf->mlo_cmn_info[bss_link].tid_dl |= + BIT(i); + break; + case WLAN_T2LM_UL_DIRECTION: + if ( + IS_LINK_SET( + t2lm[dir].ieee_link_map_tid[i], link_id)) + buf->mlo_cmn_info[bss_link].tid_ul |= + BIT(i); + break; + case WLAN_T2LM_BIDI_DIRECTION: + if ( + IS_LINK_SET( + t2lm[dir].ieee_link_map_tid[i], link_id)) { + buf->mlo_cmn_info[bss_link].tid_dl |= + BIT(i); + buf->mlo_cmn_info[bss_link].tid_ul |= + BIT(i); + } + break; + default: + logging_debug("Invalid direction %d", + t2lm[dir].direction); + break; + } + } + } +} + +void +wlan_connectivity_t2lm_status_event(struct wlan_objmgr_vdev *vdev) +{ + uint8_t i = 0, dir, num_links = 0; + QDF_STATUS status; + struct mlo_link_info *link_info; + struct wlan_t2lm_info t2lm[WLAN_T2LM_MAX_DIRECTION] = {0}; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_mlo_t2lm_status); + + if (!mlo_is_mld_sta(vdev)) + return; + + if (!vdev->mlo_dev_ctx) { + logging_err("MLO dev ctx not found"); + return; + } + link_info = mlo_mgr_get_ap_link(vdev); + if (!link_info) { + logging_err("link_info invalid"); + return; + } + + if (mlo_mgr_is_link_switch_in_progress(vdev)) + return; + + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.version = DIAG_MLO_T2LM_STATUS_VERSION_V2; + + for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) + t2lm[dir].direction = WLAN_T2LM_INVALID_DIRECTION; + + status = wlan_get_t2lm_mapping_status(vdev, t2lm); + if (QDF_IS_STATUS_ERROR(status)) { + logging_err("Unable to get t2lm_mapping"); + return; + } + + for (i = 0; + i < WLAN_MAX_ML_BSS_LINKS && i < MAX_NUM_LINKS_PER_EVENT; i++) { + if (qdf_is_macaddr_zero(&link_info->ap_link_addr) && + link_info->link_id == WLAN_INVALID_LINK_ID) + continue; + + wlan_populate_tid_link_id_bitmap(t2lm, link_info, + &wlan_diag_event, num_links); + link_info++; + num_links++; + } + + wlan_diag_event.num_links = num_links; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_MLO_T2LM_STATUS); +} + +#else +static QDF_STATUS +wlan_populate_link_addr(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_sta_info *wlan_diag_event) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void +wlan_cdp_set_peer_freq(struct wlan_objmgr_psoc *psoc, uint8_t *peer_mac, + uint32_t freq, uint8_t vdev_id) +{ + ol_txrx_soc_handle soc_txrx_handle; + cdp_config_param_type val = {0}; + + soc_txrx_handle = wlan_psoc_get_dp_handle(psoc); + + val.cdp_peer_param_freq = freq; + cdp_txrx_set_peer_param(soc_txrx_handle, vdev_id, peer_mac, + CDP_CONFIG_PEER_FREQ, val); +} + +void +wlan_connectivity_sta_info_event(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + bool is_roam) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev = NULL; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_sta_info); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_err_rl("Invalid vdev:%d", vdev_id); + return; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE || + (wlan_vdev_mlme_is_mlo_vdev(vdev) && + (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) || + wlan_vdev_mlme_is_mlo_link_vdev(vdev)))) + goto out; + + if (!is_roam && !wlan_cm_is_first_candidate_connect_attempt(vdev)) + goto out; + + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.diag_cmn.vdev_id = vdev_id; + wlan_diag_event.is_mlo = wlan_vdev_mlme_is_mlo_vdev(vdev); + + if (wlan_diag_event.is_mlo) { + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, + wlan_vdev_mlme_get_mldaddr(vdev), + QDF_MAC_ADDR_SIZE); + status = wlan_populate_link_addr(vdev, &wlan_diag_event); + if (QDF_IS_STATUS_ERROR(status)) { + logging_err_rl("wlan_populate_link_addr failed"); + goto out; + } + } else { + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE); + } + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_STA_INFO); +out: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +void +wlan_populate_vsie(struct wlan_objmgr_vdev *vdev, + struct wlan_diag_packet_info *data, + bool is_tx) +{ + struct element_info *vsie_info = NULL; + + if (is_tx) + vsie_info = mlme_get_self_disconnect_ies(vdev); + else + vsie_info = mlme_get_peer_disconnect_ies(vdev); + + if (!vsie_info) + return; + + data->vsie_len = vsie_info->len; + if (data->vsie_len > MAX_VSIE_LEN) + data->vsie_len = MAX_VSIE_LEN; + + qdf_mem_copy(data->vsie, vsie_info->ptr, data->vsie_len); +} + +void +wlan_connectivity_mgmt_event(struct wlan_objmgr_psoc *psoc, + struct wlan_frame_hdr *mac_hdr, + uint8_t vdev_id, uint16_t status_code, + enum qdf_dp_tx_rx_status tx_status, + int8_t peer_rssi, + uint8_t auth_algo, uint8_t auth_type, + uint8_t auth_seq, uint16_t aid, + enum wlan_main_tag tag) +{ + enum QDF_OPMODE opmode; + bool cache_sae_frame_cap, is_initial_connection; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_packet_info); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + logging_debug("Unable to find vdev:%d", vdev_id); + return; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE) + goto out; + + is_initial_connection = wlan_cm_is_vdev_connecting(vdev); + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) || + (is_initial_connection && + wlan_vdev_mlme_is_mlo_link_vdev(vdev)))) { + logging_debug("vdev:%d is_connection:%d | %s skip mgmt event", + vdev_id, is_initial_connection, + wlan_vdev_mlme_is_mlo_link_vdev(vdev) ? + "link_vdev" : wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) ? "link switch in prog" : ""); + goto out; + } + + qdf_mem_zero(&wlan_diag_event, sizeof(struct wlan_diag_packet_info)); + + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.diag_cmn.vdev_id = vdev_id; + wlan_diag_event.subtype = (uint8_t)tag; + + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, &mac_hdr->i_addr3[0], + QDF_MAC_ADDR_SIZE); + + if (is_initial_connection) { + status = wlan_populate_mlo_mgmt_event_param(vdev, + &wlan_diag_event, + tag); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + } + + wlan_diag_event.version = DIAG_MGMT_VERSION_V2; + wlan_diag_event.tx_fail_reason = tx_status; + wlan_diag_event.tx_status = wlan_get_diag_tx_status(tx_status); + wlan_diag_event.rssi = peer_rssi; + wlan_diag_event.sn = + (le16toh(*(uint16_t *)mac_hdr->i_seq) >> WLAN_SEQ_SEQ_SHIFT); + wlan_diag_event.status = status_code; + wlan_diag_event.auth_algo = auth_algo; + wlan_diag_event.auth_frame_type = auth_type; + wlan_diag_event.auth_seq_num = auth_seq; + wlan_diag_event.assoc_id = aid; + + if (tag == WLAN_DEAUTH_RX || tag == WLAN_DISASSOC_RX) + wlan_populate_vsie(vdev, &wlan_diag_event, false); + + if (wlan_diag_event.subtype > WLAN_CONN_DIAG_REASSOC_RESP_EVENT && + wlan_diag_event.subtype < WLAN_CONN_DIAG_BMISS_EVENT) + wlan_diag_event.reason = status_code; + + wlan_diag_event.is_retry_frame = + (mac_hdr->i_fc[1] & IEEE80211_FC1_RETRY); + + /* + * Cache the SAE auth frames info in vdev mlme private and return in + * case of roam preauth + */ + cache_sae_frame_cap = + wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_ROAM_STATS_FRAME_INFO_PER_CANDIDATE); + if (!is_initial_connection && + (tag == WLAN_AUTH_REQ || tag == WLAN_AUTH_RESP) && + auth_algo == WLAN_SAE_AUTH_ALGO_NUMBER && cache_sae_frame_cap) { + wlan_cache_connectivity_log(psoc, vdev_id, &wlan_diag_event); + goto out; + } + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MGMT); + + if (tag == WLAN_ASSOC_RSP || tag == WLAN_REASSOC_RSP) + wlan_connectivity_mlo_setup_event(vdev, false); + +out: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +void +wlan_connectivity_connecting_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_req *con_req) +{ + QDF_STATUS status; + struct wlan_cm_connect_req req; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_connect); + + if (!wlan_cm_is_first_candidate_connect_attempt(vdev)) + return; + + /* for candidate not found case*/ + if (con_req) { + req = *con_req; + qdf_mem_zero(&req.scan_ie, sizeof(struct element_info)); + qdf_mem_zero(&req.assoc_ie, sizeof(struct element_info)); + } else { + status = wlan_cm_get_active_connect_req_param(vdev, &req); + if (QDF_IS_STATUS_ERROR(status)) { + logging_err("vdev: %d failed to get active cmd request", + wlan_vdev_get_id(vdev)); + return; + } + } + + wlan_diag_event.version = DIAG_CONN_VERSION; + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.diag_cmn.vdev_id = wlan_vdev_get_id(vdev); + wlan_diag_event.subtype = WLAN_CONN_DIAG_CONNECTING_EVENT; + + wlan_diag_event.ssid_len = req.ssid.length; + + if (req.ssid.length > WLAN_SSID_MAX_LEN) + wlan_diag_event.ssid_len = WLAN_SSID_MAX_LEN; + + qdf_mem_copy(wlan_diag_event.ssid, req.ssid.ssid, + wlan_diag_event.ssid_len); + + if (!qdf_is_macaddr_zero(&req.bssid)) + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, req.bssid.bytes, + QDF_MAC_ADDR_SIZE); + else if (!qdf_is_macaddr_zero(&req.bssid_hint)) + qdf_mem_copy(wlan_diag_event.bssid_hint, req.bssid_hint.bytes, + QDF_MAC_ADDR_SIZE); + + if (req.chan_freq) + wlan_diag_event.freq = req.chan_freq; + else if (req.chan_freq_hint) + wlan_diag_event.freq_hint = req.chan_freq_hint; + + wlan_diag_event.pairwise_cipher = req.crypto.user_cipher_pairwise; + wlan_diag_event.grp_cipher = req.crypto.user_grp_cipher; + wlan_diag_event.akm = req.crypto.user_akm_suite; + wlan_diag_event.auth_algo = req.crypto.user_auth_type; + + if (req.scan_ie.len) { + qdf_mem_free(req.scan_ie.ptr); + qdf_mem_zero(&req.scan_ie, sizeof(struct element_info)); + } + + if (req.assoc_ie.len) { + qdf_mem_free(req.assoc_ie.ptr); + qdf_mem_zero(&req.assoc_ie, sizeof(struct element_info)); + } + + wlan_diag_event.bt_coex = + wlan_mlme_get_bt_profile_con(wlan_vdev_get_psoc(vdev)); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_CONN); +} + +#ifdef WLAN_FEATURE_11BE_MLO + +#define BAND_TO_BITMAP(band) (band - 1) + +static uint8_t +wlan_convert_link_id_to_diag_band(struct qdf_mac_addr *peer_mld, + uint16_t link_bitmap) +{ + uint8_t i, band_bitmap = 0, band; + struct wlan_mlo_dev_context *mldev = NULL; + struct wlan_mlo_peer_context *mlpeer = NULL; + struct mlo_link_info *link_info = NULL; + uint32_t freq; + + mlpeer = wlan_mlo_get_mlpeer_by_peer_mladdr(peer_mld, &mldev); + if (!mlpeer) { + logging_err("ml peer not found"); + return 0; + } + + for (i = 0; i < MAX_MLO_LINK_ID; i++) { + if (IS_LINK_SET(link_bitmap, i)) { + link_info = mlo_mgr_get_ap_link_by_link_id(mldev, i); + if (!link_info) { + logging_err("link: %d info does not exist", i); + return 0; + } + + freq = link_info->link_chan_info->ch_freq; + band = wlan_convert_freq_to_diag_band(freq); + if (band == WLAN_INVALID_BAND) + continue; + + band_bitmap |= BIT(BAND_TO_BITMAP(band)); + } + } + + return band_bitmap; +} + +static uint8_t +wlan_get_supported_link_band_bitmap(struct mlo_link_switch_context *link_ctx) +{ + uint8_t band_bitmap = 0, i = 0; + struct mlo_link_info link_info; + struct wlan_channel *chan_info; + enum wlan_diag_wifi_band band; + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { + link_info = link_ctx->links_info[i]; + + chan_info = link_info.link_chan_info; + if (!chan_info) + continue; + + band = wlan_convert_freq_to_diag_band(chan_info->ch_freq); + if (band == WLAN_INVALID_BAND) + continue; + + band_bitmap |= BIT(band - 1); + } + + return band_bitmap; +} + +void wlan_connectivity_mld_link_status_event(struct wlan_objmgr_psoc *psoc, + struct mlo_link_switch_params *src) +{ + struct wlan_mlo_peer_context *ml_peer = NULL; + struct wlan_mlo_dev_context *mld_ctx = NULL; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_mlo_link_status); + + qdf_mem_zero(&wlan_diag_event, + sizeof(struct wlan_diag_mlo_link_status)); + + ml_peer = wlan_mlo_get_mlpeer_by_peer_mladdr(&src->mld_addr, &mld_ctx); + + if (!mld_ctx) { + logging_err("mlo dev ctx for mld_mac: " + QDF_MAC_ADDR_FMT + " not found", + QDF_MAC_ADDR_REF(src->mld_addr.bytes)); + return; + } + + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.version = DIAG_MLO_LINK_STATUS_VERSION_2; + + wlan_diag_event.active_link = + wlan_convert_link_id_to_diag_band(&src->mld_addr, + src->active_link_bitmap); + if (!wlan_diag_event.active_link) + return; + wlan_diag_event.prev_active_link = + wlan_convert_link_id_to_diag_band(&src->mld_addr, + src->prev_link_bitmap); + if (!wlan_diag_event.prev_active_link) + return; + + if (!mld_ctx->link_ctx) { + logging_err("link ctx for mld_mac: " + QDF_MAC_ADDR_FMT + " not found", + QDF_MAC_ADDR_REF(src->mld_addr.bytes)); + return; + } + + wlan_diag_event.associated_links = + wlan_get_supported_link_band_bitmap(mld_ctx->link_ctx); + + if (!wlan_diag_event.associated_links) + return; + + wlan_diag_event.reason = src->reason_code; + /* + * FW timestamp received from FW in milliseconds and to be sent to + * userspace in microseconds + */ + wlan_diag_event.diag_cmn.fw_timestamp = src->fw_timestamp * 1000; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_MLO_LINK_STATUS); +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/cfg_policy_mgr.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/cfg_policy_mgr.h new file mode 100644 index 0000000000..4a46e749d8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/cfg_policy_mgr.h @@ -0,0 +1,781 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CFG_POLICY_MGR +#define __CFG_POLICY_MGR +#include "qdf_types.h" + +/* + * + * gWlanMccToSccSwitchMode - Control SAP channel. + * @Min: 0 + * @Max: 6 + * @Default: 0 + * + * This ini is used to override SAP channel. + * If gWlanMccToSccSwitchMode = 0: disabled. + * If gWlanMccToSccSwitchMode = 1: deprecated, overwritten to 3 in driver + * If gWlanMccToSccSwitchMode = 2: deprecated, overwritten to 3 in driver + * If gWlanMccToSccSwitchMode = 3: Force switch without SAP restart. + * If gWlanMccToSccSwitchMode = 4: Switch using + * fav channel(s)without SAP restart. + * If gWlanMccToSccSwitchMode = 5: Force switch without SAP restart.MCC allowed + * in exceptional cases. + * If gWlanMccToSccSwitchMode = 6: Force Switch without SAP restart only in + * user preferred band. + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_MCC_TO_SCC_SWITCH CFG_INI_UINT(\ + "gWlanMccToSccSwitchMode", \ + QDF_MCC_TO_SCC_SWITCH_DISABLE, \ + QDF_MCC_TO_SCC_SWITCH_MAX - 1, \ + QDF_MCC_TO_SCC_SWITCH_DISABLE, \ + CFG_VALUE_OR_DEFAULT, \ + "Provides MCC to SCC switch mode") +/* + * + * gSystemPref - Configure wlan system preference for PCL. + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to configure wlan system preference option to help + * policy manager decide on Preferred Channel List for a new connection. + * For possible values refer to enum hdd_conc_priority_mode + * + * Related: None. + * + * Supported Feature: DBS + * + * Usage: External + * + * + */ +#define CFG_CONC_SYS_PREF CFG_INI_UINT(\ + "gSystemPref", 0, 2, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "System preference to predict PCL") +/* + * + * gMaxConcurrentActiveSessions - Maximum number of concurrent connections. + * @Min: 1 + * @Max: 4 + * @Default: 3 + * + * This ini is used to configure the maximum number of concurrent connections. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_MAX_CONC_CXNS CFG_INI_UINT(\ + "gMaxConcurrentActiveSessions", \ + 1, 4, 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Config max num allowed connections") + +#define POLICY_MGR_CH_SELECT_POLICY_DEF 0x00000003 + +/* + * + * channel_select_logic_conc - Set channel selection logic + * for different concurrency combinations to DBS or inter band + * MCC. Default is DBS for STA+STA and STA+P2P. + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * 0 - inter-band MCC + * 1 - DBS + * + * BIT 0: STA+STA + * BIT 1: STA+P2P + * BIT 2-31: Reserved + * + * Supported Feature: STA+STA, STA+P2P + * + * Usage: External + * + * + */ +#define CFG_CHNL_SELECT_LOGIC_CONC CFG_INI_UINT(\ + "channel_select_logic_conc",\ + 0x00000000, \ + 0xFFFFFFFF, \ + POLICY_MGR_CH_SELECT_POLICY_DEF, \ + CFG_VALUE_OR_DEFAULT, \ + "Set channel selection policy for various concurrency") +/* + * + * dbs_selection_policy - Configure dbs selection policy. + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * set band preference or Vdev preference. + * bit[0] = 0: 5G 2x2 preferred to select 2x2 5G + 1x1 2G DBS mode. + * bit[0] = 1: 2G 2x2 preferred to select 2x2 2G + 1x1 5G DBS mode. + * bit[1] = 1: vdev priority enabled. The INI "vdev_priority_list" will + * specify the vdev priority. + * bit[1] = 0: vdev priority disabled. + * This INI only take effect for Genoa dual DBS hw. + * + * Supported Feature: DBS + * + * Usage: External + * + * + */ +#define CFG_DBS_SELECTION_PLCY CFG_INI_UINT(\ + "dbs_selection_policy", \ + 0, 3, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure dbs selection policy") +/* + * + * vdev_priority_list - Configure vdev priority list. + * @Min: 0 + * @Max: 0x4444 + * @Default: 0x4321 + * + * @vdev_priority_list: vdev priority list + * bit[0-3]: pri_id (policy_mgr_pri_id) of highest priority + * bit[4-7]: pri_id (policy_mgr_pri_id) of second priority + * bit[8-11]: pri_id (policy_mgr_pri_id) of third priority + * bit[12-15]: pri_id (policy_mgr_pri_id) of fourth priority + * example: 0x4321 - CLI < GO < SAP < STA + * vdev priority id mapping: + * PM_STA_PRI_ID = 1, + * PM_SAP_PRI_ID = 2, + * PM_P2P_GO_PRI_ID = 3, + * PM_P2P_CLI_PRI_ID = 4, + * When the previous INI "dbs_selection_policy" bit[1]=1, which means + * the vdev 2x2 prioritization enabled. Then this INI will be used to + * specify the vdev type priority list. For example : + * dbs_selection_policy=0x2 + * vdev_priority_list=0x4312 + * means: default preference 2x2 band is 5G, vdev 2x2 prioritization enabled. + * And the priority list is CLI < GO < STA < SAP + * + * This INI only take effect for Genoa dual DBS hw. + * + * Supported Feature: DBS + * + * Usage: External + * + * + */ +#define CFG_VDEV_CUSTOM_PRIORITY_LIST CFG_INI_UINT(\ + "vdev_priority_list", \ + 0, 0x4444, 0x4321, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure vdev priority list") +/* + * + * gEnableCustomConcRule1 - Enable custom concurrency rule1. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable custom concurrency rule1. + * If SAP comes up first and STA comes up later then SAP needs to follow STA's + * channel. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_ENABLE_CONC_RULE1 CFG_INI_UINT(\ + "gEnableCustomConcRule1", \ + 0, 1, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable custom concurrency rule 1") +/* + * + * gEnableCustomConcRule2 - Enable custom concurrency rule2. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable custom concurrency rule2. + * If P2PGO comes up first and STA comes up later then P2PGO need to follow + * STA's channel in 5Ghz. In following if condition we are just adding sanity + * check to make sure that by this time P2PGO's channel is same as STA's + * channel. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_ENABLE_CONC_RULE2 CFG_INI_UINT(\ + "gEnableCustomConcRule2", \ + 0, 1, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable custom concurrency rule 2") +/* + * + * gEnableMCCAdaptiveScheduler - MCC Adaptive Scheduler feature. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable MCC Adaptive Scheduler feature. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_ENABLE_MCC_ADAPTIVE_SCH_ENABLED_NAME CFG_INI_BOOL(\ + "gEnableMCCAdaptiveScheduler", \ + true, \ + "Enable/Disable MCC Adaptive Scheduler") + +/* + * + * gEnableStaConnectionIn5Ghz - To enable/disable STA connection in 5G + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable STA connection in 5G band + * + * Related: STA + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_ENABLE_STA_CONNECTION_IN_5GHZ CFG_INI_UINT(\ + "gEnableStaConnectionIn5Ghz", \ + 0, 1, 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable/Disable STA connection in 5G") + +/* + * + * gAllowMCCGODiffBI - Allow GO in MCC mode to accept different beacon interval + * than STA's. + * @Min: 0 + * @Max: 4 + * @Default: 4 + * + * This ini is used to allow GO in MCC mode to accept different beacon interval + * than STA's. + * Added for Wi-Fi Cert. 5.1.12 + * If gAllowMCCGODiffBI = 1 + * Set to 1 for WFA certification. GO Beacon interval is not changed. + * MCC GO doesn't work well in optimized way. In worst scenario, it may + * invite STA disconnection. + * If gAllowMCCGODiffBI = 2 + * If set to 2 workaround 1 disassoc all the clients and update beacon + * Interval. + * If gAllowMCCGODiffBI = 3 + * If set to 3 tear down the P2P link in auto/Non-autonomous -GO case. + * If gAllowMCCGODiffBI = 4 + * If set to 4 don't disconnect the P2P client in autonomous/Non-auto- + * nomous -GO case update the BI dynamically + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_ALLOW_MCC_GO_DIFF_BI \ +CFG_INI_UINT("gAllowMCCGODiffBI", 0, 4, 4, CFG_VALUE_OR_DEFAULT, \ + "Allow GO in MCC mode to accept different BI than STA's") + +/* + * + * + * gDualMacFeatureDisable - Disable Dual MAC feature. + * @Min: 0 + * @Max: 6 + * @Default: 6 + * + * This ini is used to enable/disable dual MAC feature. + * 0 - enable DBS + * 1 - disable DBS + * 2 - disable DBS for connection but keep DBS for scan + * 3 - disable DBS for connection but keep DBS scan with async + * scan policy disabled + * 4 - enable DBS for connection as well as for scan with async + * scan policy disabled + * 5 - enable DBS for connection but disable DBS for scan. + * 6 - enable DBS for connection but disable simultaneous scan + * from upper layer (DBS scan remains enabled in FW). + * + * Note: INI item value should match 'enum dbs_support' + * + * Related: None. + * + * Supported Feature: DBS + * + * Usage: External + * + * + */ +#define CFG_DUAL_MAC_FEATURE_DISABLE \ +CFG_INI_UINT("gDualMacFeatureDisable", 0, 6, 6, CFG_VALUE_OR_DEFAULT, \ + "This INI is used to enable/disable Dual MAC feature") + +/* + * + * + * enable_sbs - Enable/Disable SBS. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable SBS feature. + * 0 - disable SBS + * 1 - enable SBS + * + * + * Related: None. + * + * Supported Feature: SBS + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SBS CFG_INI_BOOL(\ + "enable_sbs", \ + true, \ + "Enable/Disable SBS") + +/* + * + * g_sta_sap_scc_on_dfs_chan - Allow STA+SAP SCC on DFS channel with master + * mode support disabled. + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * This ini is used to allow STA+SAP SCC on DFS channel with master mode + * support disabled, the value is defined by enum PM_AP_DFS_MASTER_MODE. + * 0 - Disallow STA+SAP SCC on DFS channel + * 1 - Allow STA+SAP SCC on DFS channel with master mode disabled + * This needs gEnableDFSMasterCap enabled to allow SAP SCC with + * STA on DFS but dfs master mode disabled. Single SAP is not allowed + * on DFS. + * 2 - enhance "1" with below requirement + * a. Allow single SAP (GO) start on DFS channel. + * b. Allow CAC process on DFS channel in single SAP (GO) mode + * c. Allow DFS radar event process in single SAP (GO) mode + * d. Disallow CAC and radar event process in SAP (GO) + STA mode. + * The value 2 of this ini requires master mode to be enabled so it is + * mandatory to enable the dfs master mode ini gEnableDFSMasterCap + * along with it. + * + * Related: None. + * + * Supported Feature: Non-DBS, DBS + * + * Usage: External + * + * + */ + +#define CFG_STA_SAP_SCC_ON_DFS_CHAN \ +CFG_INI_UINT("g_sta_sap_scc_on_dfs_chan", 0, 2, 2, CFG_VALUE_OR_DEFAULT, \ + "Allow STA+SAP SCC on DFS channel with master mode disable") + +/* + * + * sta_sap_scc_on_indoor_chan - Allow STA+SAP SCC on indoor channel + * when STA is connected on indoor channel. + * @Min: false + * @Max: true + * @Default: false + * + * This ini is used to allow STA+SAP SCC on indoor channel + * 0 - Disallow STA+SAP SCC on Indoor only channel + * 1 - Allow STA+SAP SCC on DFS channel. SAP will move to indoor channel + * once STA is connected on indoor only channel. + * When gindoor_channel_support=1, this ini will not be considered and + * SAP can come up on indoor channel. + * + * Related: gindoor_channel_support. + * + * Supported Feature: Non-DBS, DBS + * + * Usage: External + * + * + */ +#define CFG_STA_SAP_SCC_ON_INDOOR_CHAN CFG_INI_BOOL(\ + "sta_sap_scc_on_indoor_chan", \ + false, \ + "Allow STA+SAP SCC on indoor channel") + +/* + * + * gForce1x1Exception - force 1x1 when connecting to certain peer + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * This INI when enabled will force 1x1 connection with certain peer. + * The implementation for this ini would be as follows:- + * Value 0: Even if the AP is present in OUI, 1x1 will not be forced + * Value 1: If antenna sharing supported, then only do 1x1. + * Value 2: If AP present in OUI, force 1x1 connection. + + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ + +#define CFG_FORCE_1X1_FEATURE \ +CFG_INI_UINT("gForce1x1Exception", 0, 2, 1, CFG_VALUE_OR_DEFAULT, \ + "force 1x1 when connecting to certain peer") + +/* + * + * gEnableSAPManadatoryChanList - Enable SAP Mandatory channel list + * Options. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the SAP manadatory chan list + * 0 - Disable SAP mandatory chan list + * 1 - Enable SAP mandatory chan list + * + * Supported Feature: SAP + * + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_SAP_MANDATORY_CHAN_LIST \ +CFG_INI_UINT("gEnableSAPManadatoryChanList", 0, 1, 0, CFG_VALUE_OR_DEFAULT, \ + "Enable SAP Mandatory channel list") + +/* + * + * g_nan_sap_scc_on_lte_coex_chan - Allow NAN+SAP SCC on LTE coex channel + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to allow NAN+SAP SCC on LTE coex channel + * 0 - Disallow NAN+SAP SCC on LTE coex channel + * 1 - Allow NAN+SAP SCC on LTE coex channel + * + * Related: Depends on gWlanMccToSccSwitchMode config. + * + * Supported Feature: Non-DBS, DBS + * + * Usage: External + * + * + */ +#define CFG_NAN_SAP_SCC_ON_LTE_COEX_CHAN \ +CFG_INI_BOOL("g_nan_sap_scc_on_lte_coex_chan", 1, \ + "Allow NAN+SAP SCC on LTE coex channel") + +/* + * + * g_sta_sap_scc_on_lte_coex_chan - Allow STA+SAP SCC on LTE coex channel + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to allow STA+SAP SCC on LTE coex channel + * 0 - Disallow STA+SAP SCC on LTE coex channel + * 1 - Allow STA+SAP SCC on LTE coex channel + * + * Related: None. + * + * Supported Feature: Non-DBS, DBS + * + * Usage: External + * + * + */ +#define CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN \ +CFG_INI_UINT("g_sta_sap_scc_on_lte_coex_chan", 0, 1, 1, CFG_VALUE_OR_DEFAULT, \ + "Allow STA+SAP SCC on LTE coex channel") + +/* + * + * g_mark_sap_indoor_as_disable - Enable/Disable Indoor channel + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to mark the Indoor channel as + * disable when SAP start and revert it on SAP stop, + * so SAP will not turn on indoor channel and + * sta will not scan/associate and roam on indoor + * channels. + * + * Related: If g_mark_sap_indoor_as_disable set, turn the + * indoor channels to disable and update Wiphy & fw. + * + * Supported Feature: SAP/STA + * + * Usage: External + * + * + */ + +#define CFG_MARK_INDOOR_AS_DISABLE_FEATURE \ +CFG_INI_UINT("g_mark_sap_indoor_as_disable", 0, 1, 0, CFG_VALUE_OR_DEFAULT, \ + "Enable/Disable Indoor channel") + +/* + * + * g_enable_go_force_scc - Enable/Disable force SCC on P2P GO + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini and along with "gWlanMccToSccSwitchMode" is used to enable + * force SCC on P2P GO interface. + * + * GO_FORCE_SCC_DISABLED (value 0): GO force scc disabled and GO can come up + * in MCC mode + * GO_FORCE_SCC_STRICT (value 1): New GO will be forced to form on existing + * GO/STA/GC channel in start bss itself. + * GO_FORCE_SCC_LIBERAL (value 2): After SET KEY is done, do force SCC for the + * first GO to move to new GO channel. + * + * Supported Feature: P2P GO + * + * Usage: External + * + * + */ + +#define CFG_P2P_GO_ENABLE_FORCE_SCC \ +CFG_INI_UINT("g_enable_go_force_scc", 0, 2, 0, CFG_VALUE_OR_DEFAULT, \ + "Enable/Disable P2P GO force SCC") + +/* + * + * g_pcl_band_priority - Set 5G/6G Channel order + * Options. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set preference between 5G and 6G channels during + * PCL population. + * 0 - Prefer 5G channels, 5G channels will be placed before the 6G channels + * in PCL. + * 1 - Prefer 6G channels, 6G channels will be placed before the 5G channels + * in PCL. + * + * Supported Feature: STA, SAP + * + * + * Usage: External + * + * + */ + +#define CFG_PCL_BAND_PRIORITY \ +CFG_INI_UINT("g_pcl_band_priority", 0, 1, 0, CFG_VALUE_OR_DEFAULT, \ + "Set 5G and 6G Channel order") + +/* + * + * g_multi_sap_allowed_on_same_band - Allow multi sap started on same band + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to allow multi sap started on same band or not. + * 0 - Disallow multi sap started on same band + * 1 - Allow multi sap started on same band + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_MULTI_SAP_ALLOWED_ON_SAME_BAND \ +CFG_INI_BOOL("g_multi_sap_allowed_on_same_band", 1, \ + "Allow multi SAP started on same band") + +#ifdef WLAN_FEATURE_SR +/* + * + * g_enable_sr_in_same_mac_conc - Enable/Disable SR in same MAC concurrency + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable SR in same MAC concurrency scenarios. + * 0 - disable SR in same mac concurrency + * 1 - enable SR in same mac concurrency + * + * Ex- If 1st connection STA operating on MAC0 has enabled Spatial Reuse + * already. Then if user tries to bring-up 2nd connection SAP on MAC0 + * (STA + SAP (SCC)). + * Now if this INI is not set to 1, then Spatial Reuse gets disabled for + * all the interfaces running on MAC0. Once 2nd connection or concurrency + * interface is disabled, Spatial Reuse gets enabled again. + * + * Related: None. + * + * Supported Feature: Spatial Reuse + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SR_IN_SAME_MAC_CONC \ +CFG_INI_BOOL("g_enable_sr_in_same_mac_conc", 1, \ + "Enable/Disable SR in Same MAC concurrency") + +#define CFG_SPATIAL_REUSE CFG(CFG_ENABLE_SR_IN_SAME_MAC_CONC) +#else +#define CFG_SPATIAL_REUSE +#endif + +/* + * + * g_use_original_bw_for_sap_restart - Set sap default BW when do restart + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set sap default BW when do restart. + * 0 - Use maximum BW as default BW + * 1 - Use sap original BW as default BW + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_SAP_DEFAULT_BW_FOR_RESTART \ +CFG_INI_BOOL("g_use_original_bw_for_sap_restart", 0, \ + "Use SAP original bandwidth when do restart") + +/* + * + * g_move_sap_go_1st_on_dfs_sta_csa - Move SAP / GO first to enforce scc + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini moves SAP / GO first to enforce scc in STA+SAP (GO) DFS SCC + * 0 - Keep default MCC to SCC enforcement movement + * 1 - Move SAP / GO first before STA's movement to non-DFS channel + * + * In STA+SAP / GO concurrency, SCC is enforced by moving SAP / GO + * to STA's operating channel. STA side, if there is a CSA + * then SCC will be enforced only after STA moves to new channel. + * + * In usecase of STA + GO SCC on DFS channel, CSA is sent with no-TX + * and STA's movement will only happen once CSA count becomes 0. + * This will block data transmission till then, which will have bad + * user experience in case of XR where, it needs to have periodic data + * transmission in every 1 second with GO interface. + * + * To resolve this, it is better to move GO / SAP first to allow 1 + * second periodic transmissions. And once the STA moves to new channel, + * existing logic will be triggered to enforce SCC. + * + * This INI is added to change the behavior only in this specific case. + * If this INI is set, then move SAP / GO first upon receiving very first + * CSA from AP to a non-DFS channel. Current MCC to SCC rules will be applied + * once STA moves to new channel after CSA count becomes 0. + * + * Dependency: g_sta_sap_scc_on_dfs_chan, g_enable_go_force_scc + * + * Supported Feature: SAP / P2P-GO + * + * Usage: External + * + * + */ +#define CFG_MOVE_SAP_GO_1ST_ON_DFS_STA_CSA \ +CFG_INI_BOOL("g_move_sap_go_1st_on_dfs_sta_csa", 0, \ + "Move SAP / GO first to enforce scc on dfs sta csa") + +#define CFG_POLICY_MGR_ALL \ + CFG(CFG_MCC_TO_SCC_SWITCH) \ + CFG(CFG_CONC_SYS_PREF) \ + CFG(CFG_MAX_CONC_CXNS) \ + CFG(CFG_DBS_SELECTION_PLCY) \ + CFG(CFG_VDEV_CUSTOM_PRIORITY_LIST) \ + CFG(CFG_CHNL_SELECT_LOGIC_CONC) \ + CFG(CFG_ENABLE_CONC_RULE1) \ + CFG(CFG_ENABLE_CONC_RULE2) \ + CFG(CFG_ENABLE_MCC_ADAPTIVE_SCH_ENABLED_NAME)\ + CFG(CFG_ENABLE_STA_CONNECTION_IN_5GHZ)\ + CFG(CFG_DUAL_MAC_FEATURE_DISABLE)\ + CFG(CFG_ENABLE_SBS)\ + CFG(CFG_STA_SAP_SCC_ON_DFS_CHAN)\ + CFG(CFG_STA_SAP_SCC_ON_INDOOR_CHAN)\ + CFG(CFG_FORCE_1X1_FEATURE)\ + CFG(CFG_ENABLE_SAP_MANDATORY_CHAN_LIST)\ + CFG(CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN)\ + CFG(CFG_NAN_SAP_SCC_ON_LTE_COEX_CHAN) \ + CFG(CFG_MARK_INDOOR_AS_DISABLE_FEATURE)\ + CFG(CFG_ALLOW_MCC_GO_DIFF_BI) \ + CFG(CFG_P2P_GO_ENABLE_FORCE_SCC) \ + CFG(CFG_PCL_BAND_PRIORITY) \ + CFG(CFG_MULTI_SAP_ALLOWED_ON_SAME_BAND) \ + CFG_SPATIAL_REUSE \ + CFG(CFG_SAP_DEFAULT_BW_FOR_RESTART) \ + CFG(CFG_MOVE_SAP_GO_1ST_ON_DFS_STA_CSA) +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h new file mode 100644 index 0000000000..e1c08828f7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_api.h @@ -0,0 +1,5771 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_API_H +#define __WLAN_POLICY_MGR_API_H + +/** + * DOC: wlan_policy_mgr_api.h + * + * Concurrenct Connection Management entity + */ + +/* Include files */ +#include "qdf_types.h" +#include "qdf_status.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_mlo_mgr_public_structs.h" +#include "wlan_policy_mgr_public_struct.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_utility.h" +#include "sir_types.h" + +struct target_psoc_info; + +typedef const enum policy_mgr_pcl_type + pm_dbs_pcl_second_connection_table_type + [PM_MAX_ONE_CONNECTION_MODE][PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE]; + +typedef const enum policy_mgr_pcl_type + pm_dbs_pcl_third_connection_table_type + [PM_MAX_TWO_CONNECTION_MODE][PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE]; + +typedef const enum policy_mgr_conc_next_action + policy_mgr_next_action_two_connection_table_type + [PM_MAX_ONE_CONNECTION_MODE][POLICY_MGR_MAX_BAND]; + +typedef const enum policy_mgr_conc_next_action + policy_mgr_next_action_three_connection_table_type + [PM_MAX_TWO_CONNECTION_MODE][POLICY_MGR_MAX_BAND]; + +#define PM_FW_MODE_STA_STA_BIT_POS 0 +#define PM_FW_MODE_STA_P2P_BIT_POS 1 + +#define PM_FW_MODE_STA_STA_BIT_MASK (0x1 << PM_FW_MODE_STA_STA_BIT_POS) +#define PM_FW_MODE_STA_P2P_BIT_MASK (0x1 << PM_FW_MODE_STA_P2P_BIT_POS) + +#define PM_CHANNEL_SELECT_LOGIC_STA_STA_GET(channel_select_logic_conc) \ + ((channel_select_logic_conc & PM_FW_MODE_STA_STA_BIT_MASK) >> \ + PM_FW_MODE_STA_STA_BIT_POS) +#define PM_CHANNEL_SELECT_LOGIC_STA_P2P_GET(channel_select_logic_conc) \ + ((channel_select_logic_conc & PM_FW_MODE_STA_P2P_BIT_MASK) >> \ + PM_FW_MODE_STA_P2P_BIT_POS) + +/** + * enum PM_AP_DFS_MASTER_MODE - AP dfs master mode + * @PM_STA_SAP_ON_DFS_DEFAULT: Disallow STA+SAP SCC on DFS channel + * @PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED: Allow STA+SAP SCC + * on DFS channel with master mode disabled + * @PM_STA_SAP_ON_DFS_MASTER_MODE_FLEX: enhance + * "PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED" with below requirement: + * a. Allow single SAP (GO) start on DFS channel. + * b. Allow CAC process on DFS channel in single SAP (GO) mode + * c. Allow DFS radar event process in single SAP (GO) mode + * d. Disallow CAC and radar event process in SAP (GO) + STA mode. + * + * This enum value will be used to set to INI g_sta_sap_scc_on_dfs_chan to + * config the sta+sap on dfs channel behaviour expected by user. + */ +enum PM_AP_DFS_MASTER_MODE { + PM_STA_SAP_ON_DFS_DEFAULT, + PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED, + PM_STA_SAP_ON_DFS_MASTER_MODE_FLEX, +}; + +static inline const char *pcl_type_to_string(uint32_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(PM_NONE); + CASE_RETURN_STRING(PM_24G); + CASE_RETURN_STRING(PM_5G); + CASE_RETURN_STRING(PM_SCC_CH); + CASE_RETURN_STRING(PM_MCC_CH); + CASE_RETURN_STRING(PM_SCC_CH_24G); + CASE_RETURN_STRING(PM_SCC_CH_5G); + CASE_RETURN_STRING(PM_24G_SCC_CH); + CASE_RETURN_STRING(PM_5G_SCC_CH); + CASE_RETURN_STRING(PM_SCC_ON_5_CH_5G); + CASE_RETURN_STRING(PM_SCC_ON_5_SCC_ON_24_24G); + CASE_RETURN_STRING(PM_SCC_ON_5_SCC_ON_24_5G); + CASE_RETURN_STRING(PM_SCC_ON_5_5G_24G); + CASE_RETURN_STRING(PM_SCC_ON_5_5G_SCC_ON_24G); + CASE_RETURN_STRING(PM_SCC_ON_24_SCC_ON_5_24G); + CASE_RETURN_STRING(PM_SCC_ON_24_SCC_ON_5_5G); + CASE_RETURN_STRING(PM_SCC_ON_24_CH_24G); + CASE_RETURN_STRING(PM_SCC_ON_5_SCC_ON_24); + CASE_RETURN_STRING(PM_SCC_ON_24_SCC_ON_5); + CASE_RETURN_STRING(PM_MCC_CH_24G); + CASE_RETURN_STRING(PM_MCC_CH_5G); + CASE_RETURN_STRING(PM_24G_MCC_CH); + CASE_RETURN_STRING(PM_5G_MCC_CH); + CASE_RETURN_STRING(PM_SBS_CH); + CASE_RETURN_STRING(PM_SBS_CH_5G); + CASE_RETURN_STRING(PM_24G_SCC_CH_SBS_CH); + CASE_RETURN_STRING(PM_24G_SCC_CH_SBS_CH_5G); + CASE_RETURN_STRING(PM_24G_SBS_CH_MCC_CH); + /* New PCL type for DBS-SBS HW */ + CASE_RETURN_STRING(PM_SBS_CH_24G_SCC_CH); + CASE_RETURN_STRING(PM_SBS_CH_SCC_CH_24G); + CASE_RETURN_STRING(PM_SCC_CH_SBS_CH_24G); + CASE_RETURN_STRING(PM_SBS_CH_SCC_CH_5G_24G); + CASE_RETURN_STRING(PM_SCC_CH_MCC_CH_SBS_CH_24G); + CASE_RETURN_STRING(PM_SBS_CH_2G); + CASE_RETURN_STRING(PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G); + CASE_RETURN_STRING(PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G); + CASE_RETURN_STRING(PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G); + CASE_RETURN_STRING(PM_SBS_CH_MCC_CH); + CASE_RETURN_STRING(PM_SBS_5G_MCC_24G); + default: + return "Unknown"; + } +} + +static inline const char *device_mode_to_string(uint32_t idx) +{ + switch (idx) { + CASE_RETURN_STRING(PM_STA_MODE); + CASE_RETURN_STRING(PM_SAP_MODE); + CASE_RETURN_STRING(PM_P2P_CLIENT_MODE); + CASE_RETURN_STRING(PM_P2P_GO_MODE); + CASE_RETURN_STRING(PM_NDI_MODE); + CASE_RETURN_STRING(PM_NAN_DISC_MODE); + CASE_RETURN_STRING(PM_LL_LT_SAP_MODE); + default: + return "Unknown"; + } +}; + +/** + * struct trim_chan_info - trim channel info + * @band_capability: band capability + * @sap_count: sap count + * @trim: enum trim channel list + */ +struct trim_chan_info { + uint32_t band_capability; + uint32_t sap_count; + uint16_t trim; +}; + +/** + * policy_mgr_get_allow_mcc_go_diff_bi() - to get information on whether GO + * can have diff BI than STA in MCC + * @psoc: pointer to psoc + * @allow_mcc_go_diff_bi: value to be filled + * + * This API is used to find out whether GO's BI can different than STA in MCC + * scenario + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_allow_mcc_go_diff_bi(struct wlan_objmgr_psoc *psoc, + uint8_t *allow_mcc_go_diff_bi); +/** + * policy_mgr_get_dual_mac_feature() - to find out if DUAL MAC feature is + * enabled + * @psoc: pointer to psoc + * @dual_mac_feature: value to be filled + * + * This API is used to find out whether dual mac (dual radio) specific feature + * is enabled or not + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_dual_mac_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_mac_feature); + +/** + * policy_mgr_allow_multiple_sta_connections() - to find out if STA+STA feature + * is enabled. + * @psoc: pointer to psoc + * + * This API is used to find out whether STA+STA specific feature is enabled + * or not + * + * Return: true if supports else false. + */ +bool policy_mgr_allow_multiple_sta_connections(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_dual_mac_feature() - to set the dual mac feature value + * @psoc: pointer to psoc + * @dual_mac_feature: value to be updated + * + * This API is used to update the dual mac (dual radio) specific feature value + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_set_dual_mac_feature(struct wlan_objmgr_psoc *psoc, + uint8_t dual_mac_feature); + +/** + * policy_mgr_get_force_1x1() - to find out if 1x1 connection is enforced + * + * @psoc: pointer to psoc + * @force_1x1: value to be filled + * + * This API is used to find out if 1x1 connection is enforced. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_force_1x1(struct wlan_objmgr_psoc *psoc, + uint8_t *force_1x1); + +/** + * policy_mgr_get_max_conc_cxns() - to get configured max concurrent active + * connection count + * + * @psoc: pointer to psoc + * + * This API is used to query the configured max concurrent active connection + * count. + * + * Return: max active connection count + */ +uint32_t policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_max_conc_cxns() - to set supported max concurrent active + * connection count to policy mgr + * + * @psoc: pointer to psoc + * @max_conc_cxns: max active connection count + * + * This API is used to update the max concurrent active connection + * count to policy mgr + * + * Return: QDF_STATUS_SUCCESS if set successfully + */ +QDF_STATUS policy_mgr_set_max_conc_cxns(struct wlan_objmgr_psoc *psoc, + uint32_t max_conc_cxns); + +/** + * policy_mgr_set_sta_sap_scc_on_dfs_chnl() - to set sta_sap_scc_on_dfs_chnl + * @psoc: pointer to psoc + * @sta_sap_scc_on_dfs_chnl: value to be set + * + * This API is used to set sta_sap_scc_on_dfs_chnl + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_set_sta_sap_scc_on_dfs_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t sta_sap_scc_on_dfs_chnl); + +/** + * policy_mgr_get_sta_sap_scc_on_dfs_chnl() - to find out if STA and SAP + * SCC is allowed on DFS channel + * @psoc: pointer to psoc + * @sta_sap_scc_on_dfs_chnl: value to be filled + * + * This API is used to find out whether STA and SAP SCC is allowed on + * DFS channels + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_sta_sap_scc_on_dfs_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_on_dfs_chnl); + +/** + * policy_mgr_set_multi_sap_allowed_on_same_band() - to set + * multi_sap_allowed_on_same_band + * @psoc: pointer to psoc + * @multi_sap_allowed_on_same_band: value to be set + * + * This API is used to set multi_sap_allowed_on_same_band + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_set_multi_sap_allowed_on_same_band(struct wlan_objmgr_psoc *psoc, + bool multi_sap_allowed_on_same_band); + +/** + * policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl() - Get if STA-SAP scc is + * allowed on indoor channel + * @psoc: Global psoc pointer + * + * Return: true if STA-SAP SCC on indoor channel is allowed + */ +bool policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_multi_sap_allowed_on_same_band() - to find out if multi sap + * is allowed on same band + * @psoc: pointer to psoc + * @multi_sap_allowed_on_same_band: value to be filled + * + * This API is used to find out whether multi sap is allowed on same band + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_multi_sap_allowed_on_same_band(struct wlan_objmgr_psoc *psoc, + bool *multi_sap_allowed_on_same_band); + +/** + * policy_mgr_set_original_bw_for_sap_restart() - to set use_sap_original_bw + * @psoc: pointer to psoc + * @use_sap_original_bw: value to be set + * + * This API is used to set use_sap_original_bw + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_set_original_bw_for_sap_restart(struct wlan_objmgr_psoc *psoc, + bool use_sap_original_bw); + +/** + * policy_mgr_get_original_bw_for_sap_restart() - to find out if sap original + * bw is used as default BW when do sap restart + * @psoc: pointer to psoc + * @use_sap_original_bw: value to be filled + * + * This API is used to find out whether sap original BW is used as default BW + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_original_bw_for_sap_restart(struct wlan_objmgr_psoc *psoc, + bool *use_sap_original_bw); + +/** + * policy_mgr_get_dfs_sta_sap_go_scc_movement() - returns SAP / GO's movement + * in STA+SAP DFS SCC concurrency to whether SAP / GO should be moved first + * or not. + * @psoc: pointer to psoc + * @move_sap_go_first: value to be filled + * + * In STA+SAP DFS SCC concurrency, this API returns config on whether to move + * SAP / GO first on getting CSA STA side or not. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_dfs_sta_sap_go_scc_movement(struct wlan_objmgr_psoc *psoc, + bool *move_sap_go_first); + + /** + * policy_mgr_nss_update_cb() - callback from SME confirming nss + * update + * @psoc: psoc handle + * @tx_status: tx completion status for updated beacon with new + * nss value + * @vdev_id: vdev id for the specific connection + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for nss update + * @original_vdev_id: original request hwmode change vdev id + * @request_id: request ID + * + * This function is the callback registered with SME at nss + * update request time + * + * Return: None + */ + +void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc, + uint8_t tx_status, uint8_t vdev_id, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id); +/* + * policy_mgr_get_connected_vdev_band_mask() - to get the connected vdev band + * mask + * @vdev: pointer to vdev + * + * This API is used to get band of the frequency. + * + * Return: band mask of the frequency associated with the vdev + */ +uint32_t policy_mgr_get_connected_vdev_band_mask(struct wlan_objmgr_vdev *vdev); + +/** + * policy_mgr_get_dfs_master_dynamic_enabled() - support dfs master or not + * on AP interface when STA+SAP(GO) concurrency + * @psoc: pointer to psoc + * @vdev_id: sap vdev id + * + * This API is used to check AP dfs master functionality enabled or not when + * STA+SAP(GO) concurrency. + * If g_sta_sap_scc_on_dfs_chan is non-zero, the STA+SAP(GO) concurrency + * is allowed on DFS channel SCC and the SAP's DFS master functionality + * should be enable/disable according to: + * 1. g_sta_sap_scc_on_dfs_chan is 0: function return true - dfs master + * capability enabled. + * 2. g_sta_sap_scc_on_dfs_chan is 1: function return false - dfs master + * capability disabled. + * 3. g_sta_sap_scc_on_dfs_chan is 2: dfs master capability based on STA on + * 5G or not: + * a. 5G STA active - return false + * b. no 5G STA active -return true + * + * Return: true if dfs master functionality should be enabled. + */ +bool +policy_mgr_get_dfs_master_dynamic_enabled(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_get_can_skip_radar_event - Can skip DFS Radar event or not + * @psoc: soc obj + * @vdev_id: sap vdev id + * + * This API is used by dfs component to get decision whether to ignore + * the radar event or not. + * + * Return: true if Radar event should be ignored. + */ +bool +policy_mgr_get_can_skip_radar_event(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_get_sta_sap_scc_lte_coex_chnl() - to find out if STA & SAP + * SCC is allowed on LTE COEX + * @psoc: pointer to psoc + * @sta_sap_scc_lte_coex: value to be filled + * + * This API is used to find out whether STA and SAP scc is allowed on LTE COEX + * channel + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_sta_sap_scc_lte_coex_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_lte_coex); +/** + * policy_mgr_get_sap_mandt_chnl() - to find out if SAP mandatory channel + * support is enabled + * @psoc: pointer to psoc + * @sap_mandt_chnl: value to be filled + * + * This API is used to find out whether SAP's mandatory channel support + * is enabled + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_sap_mandt_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sap_mandt_chnl); +/** + * policy_mgr_get_indoor_chnl_marking() - to get if indoor channel can be + * marked as disabled + * @psoc: pointer to psoc + * @indoor_chnl_marking: value to be filled + * + * This API is used to find out whether indoor channel can be marked as disabled + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +policy_mgr_get_indoor_chnl_marking(struct wlan_objmgr_psoc *psoc, + uint8_t *indoor_chnl_marking); +/** + * policy_mgr_get_mcc_scc_switch() - To mcc to scc switch setting from INI + * @psoc: pointer to psoc + * @mcc_scc_switch: value to be filled + * + * This API pulls mcc to scc switch setting which is given as part of INI and + * stored in policy manager's CFGs. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc, + uint8_t *mcc_scc_switch); +/** + * policy_mgr_get_sys_pref() - to get system preference + * @psoc: pointer to psoc + * @sys_pref: value to be filled + * + * This API pulls the system preference for policy manager to provide + * PCL + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t *sys_pref); +/** + * policy_mgr_set_sys_pref() - to set system preference + * @psoc: pointer to psoc + * @sys_pref: value to be applied as new INI setting + * + * This API is meant to override original INI setting for system pref + * with new value which is used by policy manager to provide PCL + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t sys_pref); + +/** + * policy_mgr_get_conc_rule1() - to find out if conc rule1 is enabled + * @psoc: pointer to psoc + * @conc_rule1: value to be filled + * + * This API is used to find out if conc rule-1 is enabled by user + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule1); +/** + * policy_mgr_get_conc_rule2() - to find out if conc rule2 is enabled + * @psoc: pointer to psoc + * @conc_rule2: value to be filled + * + * This API is used to find out if conc rule-2 is enabled by user + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule2); + +/** + * policy_mgr_get_chnl_select_plcy() - to get channel selection policy + * @psoc: pointer to psoc + * @chnl_select_plcy: value to be filled + * + * This API is used to find out which channel selection policy has been + * configured + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc, + uint32_t *chnl_select_plcy); + +/** + * policy_mgr_set_ch_select_plcy() - to set channel selection policy + * @psoc: pointer to psoc + * @ch_select_policy: value to be set + * + * This API is used to set the ch selection policy. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_set_ch_select_plcy(struct wlan_objmgr_psoc *psoc, + uint32_t ch_select_policy); + +/** + * policy_mgr_get_dynamic_mcc_adaptive_sch() - to get dynamic mcc adaptive + * scheduler + * @psoc: pointer to psoc + * @dynamic_mcc_adaptive_sched: value to be filled + * + * This API is used to get dynamic mcc adaptive scheduler + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_dynamic_mcc_adaptive_sch( + struct wlan_objmgr_psoc *psoc, + bool *dynamic_mcc_adaptive_sched); + +/** + * policy_mgr_set_dynamic_mcc_adaptive_sch() - to set dynamic mcc adaptive + * scheduler + * @psoc: pointer to psoc + * @dynamic_mcc_adaptive_sched: value to be set + * + * This API is used to set dynamic mcc adaptive scheduler + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_set_dynamic_mcc_adaptive_sch( + struct wlan_objmgr_psoc *psoc, + bool dynamic_mcc_adaptive_sched); + +/** + * policy_mgr_get_mcc_adaptive_sch() - to get mcc adaptive scheduler + * @psoc: pointer to psoc + * @enable_mcc_adaptive_sch: value to be filled + * + * This API is used to find out if mcc adaptive scheduler enabled or disabled + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc, + bool *enable_mcc_adaptive_sch); + +/** + * policy_mgr_get_sta_cxn_5g_band() - to get STA's connection in 5G config + * + * @psoc: pointer to psoc + * @enable_sta_cxn_5g_band: value to be filled + * + * This API is used to find out if STA connection in 5G band is allowed or + * disallowed. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_sta_cxn_5g_band); +/** + * policy_mgr_set_concurrency_mode() - To set concurrency mode + * @psoc: PSOC object data + * @mode: device mode + * + * This routine is called to set the concurrency mode + * + * Return: NONE + */ +void policy_mgr_set_concurrency_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode); + +/** + * policy_mgr_clear_concurrency_mode() - To clear concurrency mode + * @psoc: PSOC object data + * @mode: device mode + * + * This routine is called to clear the concurrency mode + * + * Return: NONE + */ +void policy_mgr_clear_concurrency_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode); + +/** + * policy_mgr_get_connection_count() - provides the count of + * current connections + * @psoc: PSOC object information + * + * This function provides the count of current connections + * + * Return: connection count + */ +uint32_t policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_connection_count_with_mlo() - provides the count of + * current connections + * @psoc: PSOC object information + * + * This function provides the count of current connections, MLD dev count + * 1 connection no matter how many links connection. + * + * Return: connection count + */ +uint32_t +policy_mgr_get_connection_count_with_mlo(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_concurrency_mode() - return concurrency mode + * @psoc: PSOC object information + * + * This routine is used to retrieve concurrency mode + * + * Return: uint32_t value of concurrency mask + */ +uint32_t policy_mgr_get_concurrency_mode(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_chnl_in_diff_band() - to check that given channel + * is in diff band from existing channel or not + * @psoc: pointer to psoc + * @ch_freq: given channel frequency + * + * This API will check that if the passed channel is in diff band than the + * already existing connections or not. + * + * Return: true if channel is in diff band + */ +bool policy_mgr_is_chnl_in_diff_band(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq); + +/** + * policy_mgr_is_pcl_weightage_required() - to check that PCL weightage req or + * not + * @psoc: pointer to psoc + * + * This API will check that whether PCL weightage need to consider in best + * candidate selection or not. If some APs are in PCL list, those AP will get + * additional weightage. + * + * Return: true if pcl weightage is not required + */ +bool policy_mgr_is_pcl_weightage_required(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_check_for_session_conc() - Check if concurrency is + * allowed for a session + * @psoc: PSOC object information + * @vdev_id: Vdev ID + * @ch_freq: Channel frequency + * + * Checks if connection is allowed for a given session_id + * + * True if the concurrency is allowed, false otherwise + */ +bool policy_mgr_check_for_session_conc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq); + +/** + * policy_mgr_handle_conc_multiport() - to handle multiport concurrency + * @psoc: PSOC object information + * @vdev_id: Vdev ID + * @ch_freq: Channel frequency + * @reason: reason for connection update + * @request_id: Request id provided by the requester, can be used while + * calling callback to the requester + * + * This routine will handle STA side concurrency when policy manager + * is enabled. + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_handle_conc_multiport(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason, + uint32_t request_id); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * policy_mgr_check_concurrent_intf_and_restart_sap() - Check + * concurrent change intf + * @psoc: PSOC object information + * @is_acs_mode: Indicates whether SAP is started in ACS mode + * + * Checks the concurrent change interface and restarts SAP + * + * Return: None + */ +void policy_mgr_check_concurrent_intf_and_restart_sap( + struct wlan_objmgr_psoc *psoc, bool is_acs_mode); +#else +void policy_mgr_check_concurrent_intf_and_restart_sap( + struct wlan_objmgr_psoc *psoc, bool is_acs_mode) +{ + +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */ + +/** + * policy_mgr_is_chan_switch_in_progress() - Check if any SAP/GO + * CSA is in progress or not + * @psoc: PSOC object information + * + * Return: true if AP CSA is in progress + */ +bool policy_mgr_is_chan_switch_in_progress(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_wait_chan_switch_complete_evt() - Wait for SAP/GO CSA complete + * event + * @psoc: PSOC object information + * + * Return: QDF_STATUS_SUCCESS if CSA complete + */ +QDF_STATUS policy_mgr_wait_chan_switch_complete_evt( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_ap_start_in_progress() - Check if any SAP/GO + * start is in progress or not + * @psoc: PSOC object information + * + * Return: true if AP starting is in progress + */ +bool policy_mgr_is_ap_start_in_progress(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_conc_vdev_on_same_mac() - Function to get concurrent + * vdev on same mac + * @psoc: PSOC object information + * @vdev_id: vdev id + * @mac_id: mac id + * + * This function is used to get the concurrent vdev on same mac + * + * Return: vdev id of the concurrent interface running on same mac + * + */ +uint32_t policy_mgr_get_conc_vdev_on_same_mac(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint8_t mac_id); + +#ifdef WLAN_FEATURE_SR +/** + * policy_mgr_sr_same_mac_conc_enabled() - Function to check same MAC + * concurrency support in Spatial Reuse + * @psoc: PSOC object information + * + * This function is used to check whether concurrency is supported + * on same mac or not with Spatial Reuse enabled. + * + * Return: True if same MAC concurrency is supported with Spatial Reuse + * else False. + */ +bool policy_mgr_sr_same_mac_conc_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline +bool policy_mgr_sr_same_mac_conc_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +#endif + +/** + * policy_mgr_is_mcc_in_24G() - Function to check for MCC in 2.4GHz + * @psoc: PSOC object information + * + * This function is used to check for MCC operation in 2.4GHz band. + * STA, P2P and SAP adapters are only considered. + * + * Return: True if mcc is detected in 2.4 Ghz, false otherwise + * + */ +bool policy_mgr_is_mcc_in_24G(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_change_mcc_go_beacon_interval() - Change MCC beacon interval + * @psoc: PSOC object information + * @vdev_id: vdev id + * @dev_mode: device mode + * + * Updates the beacon parameters of the GO in MCC scenario + * + * Return: Success or Failure depending on the overall function behavior + */ +QDF_STATUS policy_mgr_change_mcc_go_beacon_interval( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, enum QDF_OPMODE dev_mode); + +#if defined(FEATURE_WLAN_MCC_TO_SCC_SWITCH) +/** + * policy_mgr_check_bw_with_unsafe_chan_freq() - valid SAP channel bw against + * unsafe channel list + * @psoc: PSOC object information + * @center_freq: SAP channel center frequency + * @ch_width: SAP channel width + * + * Return: true if no unsafe channel fall in SAP channel bandwidth range, + * false otherwise + */ +bool policy_mgr_check_bw_with_unsafe_chan_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t center_freq, + enum phy_ch_width ch_width); +/** + * policy_mgr_change_sap_channel_with_csa() - Move SAP channel using (E)CSA + * @psoc: PSOC object information + * @vdev_id: Vdev id + * @ch_freq: Channel frequency to change + * @ch_width: channel width to change + * @forced: Force to switch channel, ignore SCC/MCC check + * + * Invoke the callback function to change SAP channel using (E)CSA + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS +policy_mgr_change_sap_channel_with_csa(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t ch_width, bool forced); + +#else +static inline QDF_STATUS +policy_mgr_change_sap_channel_with_csa(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t ch_width, bool forced) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * policy_mgr_sta_sap_dfs_scc_conc_check() - validate and Move SAP channel + * using (E)CSA + * + * @psoc: PSOC object information + * @vdev_id: Vdev id + * @csa_event: Pointer to CSA IE Received event data + * + * Invoke the function to change SAP channel using (E)CSA for STA+GO / SAP + * SCC scenario only. This function will move P2P-GO / SAP first and then STA + * will follow. + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS +policy_mgr_sta_sap_dfs_scc_conc_check(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct csa_offload_params *csa_event); + +/** + * policy_mgr_sta_sap_dfs_enforce_scc() - validate and enforce SCC + * using (E)CSA upon receiving 1st beacon + * + * @psoc: PSOC object information + * @vdev_id: Vdev id + * + * Invoke the function to enforce SCC upon receiving 1st beacon. SAP / GO + * movement will be triggered using (E)CSA for STA+GO / SAP DFS scenario only. + * The pre-requisite for this function is SAP / GO shall already moved to new + * channel by policy_mgr_sta_sap_dfs_scc_conc_check() function. + * + * Return: void + */ +void policy_mgr_sta_sap_dfs_enforce_scc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * policy_mgr_is_p2p_p2p_conc_supported() - p2p concurrency support + * @psoc: pointer to psoc + * + * This API is used to check whether firmware supports p2p concurrency + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +bool +policy_mgr_is_p2p_p2p_conc_supported(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +policy_mgr_is_p2p_p2p_conc_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * policy_mgr_fetch_existing_con_info() - check if another vdev + * is present and find mode, freq , vdev id and chan width + * + * @psoc: psoc object + * @vdev_id: vdev id + * @curr_go_freq: frequency + * @mode: existing vdev mode + * @con_freq: existing connection freq + * @ch_width: ch_width of existing connection + * + * This function checks if another vdev is there and fetch connection + * info for that vdev.This is mainly for force SCC implementation of GO+GO , + * GO+SAP or GO+STA where we fetch other existing GO, STA, SAP on the same + * band with MCC. + * + * Return: vdev_id + */ +uint8_t +policy_mgr_fetch_existing_con_info(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t curr_go_freq, + enum policy_mgr_con_mode *mode, + uint32_t *con_freq, + enum phy_ch_width *ch_width); + +#define GO_FORCE_SCC_DISABLE 0 +#define GO_FORCE_SCC_STRICT 1 +#define GO_FORCE_SCC_LIBERAL 2 +/* + * Stay in MCC for 1 second, in case of first p2p go channel + * needs to be moved to curr go channel + */ +#define WAIT_BEFORE_GO_FORCESCC_RESTART (1000) + +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * policy_mgr_is_go_scc_strict() - Get GO force SCC enabled or not + * @psoc: psoc object + * + * This function checks if force SCC logic should be used on GO interface + * as a strict mode. + * + * Return: True if p2p needs o be start on provided channel only. + */ +bool policy_mgr_is_go_scc_strict(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_process_forcescc_for_go () - start work queue to move first p2p go + * to new p2p go's channel + * + * @psoc: PSOC object information + * @vdev_id: Vdev id + * @ch_freq: Channel frequency to change + * @ch_width: channel width to change + * @mode: existing vdev mode + * + * starts delayed work queue of 1 second to move first p2p go to new + * p2p go's channel. + * + * Return: None + */ +void policy_mgr_process_forcescc_for_go( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t ch_freq, uint32_t ch_width, + enum policy_mgr_con_mode mode); + +/** + * policy_mgr_do_go_plus_go_force_scc() - First p2p go + * to new p2p go's channel + * + * @psoc: PSOC object information + * @vdev_id: Vdev id + * @ch_freq: Channel frequency to change + * @ch_width: channel width to change + * + * Move first p2p go to new + * p2p go's channel. + * + * Return: None + */ +void policy_mgr_do_go_plus_go_force_scc( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t ch_freq, uint32_t ch_width); +#else +static inline +bool policy_mgr_is_go_scc_strict(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +void policy_mgr_process_forcescc_for_go( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t ch_freq, uint32_t ch_width, + enum policy_mgr_con_mode mode) +{} + +static inline +void policy_mgr_do_go_plus_go_force_scc( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t ch_freq, uint32_t ch_width) +{} +#endif + +/** + * policy_mgr_process_force_scc_for_nan () - force SAP scc on nan freq + * + * @psoc: PSOC object information + * + * Return: None + */ +void policy_mgr_process_force_scc_for_nan(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_check_sap_go_force_scc() - Check SAP GO MCC and save interface + * information + * @psoc: pointer to psoc + * @vdev: initiator vdev + * @reason_code: CSA reason code + * + * This API will check SAP and GO are coexistent on same band MCC or not. If + * it is, the interface ids will be saved and a delayed workqueue will be + * scheduled. The workqueue will handle the new channel selection and change + * the channel of second interface to avoid MCC. + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_check_sap_go_force_scc(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum sap_csa_reason_code reason_code); + +/** + * policy_mgr_set_pcl_for_existing_combo() - SET PCL for existing combo + * @psoc: PSOC object information + * @mode: Adapter mode + * @vdev_id: Vdev Id + * + * Return: None + */ +void policy_mgr_set_pcl_for_existing_combo(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t vdev_id); + +/** + * policy_mgr_set_pcl_for_connected_vdev() - Set the PCL for connected vdevs + * @psoc: PSOC object information + * @vdev_id: Vdev Id + * @clear_pcl: option to clear the PCL first before setting the new one + * + * This API will set the preferred channel list for other connected vdevs aside + * from the calling function's vdev + * + * Context: Any kernel thread + * Return: None + */ +void policy_mgr_set_pcl_for_connected_vdev(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool clear_pcl); + +/** + * policy_mgr_set_pcl() - Set preferred channel list in the FW + * @psoc: PSOC object information + * @msg: message containing preferred channel list information + * @vdev_id: Vdev Id + * @clear_vdev_pcl: clear PCL flag + * + * Sends the set pcl command and PCL info to FW + * + * Context: Any kernel thread + * Return: QDF_STATUS_SUCCESS on successful posting, fail status in any other + * case + */ +QDF_STATUS policy_mgr_set_pcl(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_list *msg, + uint8_t vdev_id, + bool clear_vdev_pcl); + +/** + * policy_mgr_incr_active_session() - increments the number of active sessions + * @psoc: PSOC object information + * @mode: Adapter mode + * @session_id: session ID for the connection session + * + * This function increments the number of active sessions maintained per device + * mode. In the case of STA/P2P CLI/IBSS upon connection indication it is + * incremented; In the case of SAP/P2P GO upon bss start it is incremented + * + * Return: None + */ +void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, uint8_t session_id); + +/** + * policy_mgr_decr_active_session() - decrements the number of active sessions + * @psoc: PSOC object information + * @mode: Adapter mode + * @session_id: session ID for the connection session + * + * This function decrements the number of active sessions maintained per device + * mode. In the case of STA/P2P CLI/IBSS upon disconnection it is decremented + * In the case of SAP/P2P GO upon bss stop it is decremented + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, uint8_t session_id); + +/** + * policy_mgr_decr_session_set_pcl() - Decrement session count and set PCL + * @psoc: PSOC object information + * @mode: Adapter mode + * @session_id: Session id + * + * Decrements the active session count and sets the PCL if a STA connection + * exists + * + * Return: None + */ +void policy_mgr_decr_session_set_pcl(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, uint8_t session_id); + +/** + * polic_mgr_send_pcl_to_fw() - Send PCL to fw + * @psoc: PSOC object information + * @mode: Adapter mode + * + * Loop through all existing connections, stop RSO, send PCL to firmware + * and start RSO. If Roaming is in progress on any of the interface, + * avoid PCL updation as PCL gets updated post roaming. + * + * Return: None + */ +void +polic_mgr_send_pcl_to_fw(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * policy_mgr_mlo_sta_set_nlink() - Set link mode for MLO STA + * by link id bitmap + * @psoc: psoc object + * @vdev_id: vdev id + * @reason: reason to set + * @mode: mode to set + * @link_num: number of link, valid for mode: + * MLO_LINK_FORCE_MODE_ACTIVE_NUM, MLO_LINK_FORCE_MODE_INACTIVE_NUM + * @link_bitmap: link bitmap, valid for mode: + * MLO_LINK_FORCE_MODE_ACTIVE, MLO_LINK_FORCE_MODE_INACTIVE, + * MLO_LINK_FORCE_MODE_ACTIVE_NUM, MLO_LINK_FORCE_MODE_INACTIVE_NUM + * MLO_LINK_FORCE_MODE_NO_FORCE. + * @link_bitmap2: inactive link bitmap, only valid for mode + * MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE + * @link_control_flags: bitmap of enum link_control_flags. + * + * Interface to set link mode for MLO STA + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_mlo_sta_set_nlink(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t link_num, + uint16_t link_bitmap, + uint16_t link_bitmap2, + uint32_t link_control_flags); + +/** + * policy_mgr_mlo_sta_set_link() - Set link mode for MLO STA + * @psoc: psoc object + * @reason: reason to set + * @mode: mode to set + * @num_mlo_vdev: number of vdevs + * @mlo_vdev_lst: vdev list + * + * Interface to set link mode for MLO STA + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_mlo_sta_set_link(struct wlan_objmgr_psoc *psoc, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t num_mlo_vdev, uint8_t *mlo_vdev_lst); + +/** + * policy_mgr_is_ml_vdev_id() - check if vdev id is part of ML + * @psoc: PSOC object information + * @vdev_id: vdev id to check + * + * Return: true if vdev is part of ml + */ +bool policy_mgr_is_ml_vdev_id(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * policy_mgr_get_disabled_ml_links_count() - provides the count of + * disabled ml links + * @psoc: PSOC object information + * + * This function provides the count of disabled ml links + * + * Return: disabled ml links count + */ +uint32_t policy_mgr_get_disabled_ml_links_count(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_move_vdev_from_disabled_to_connection_tbl() - re-enable a ml link + * and move it from disabled link table to pm_conc_connection_list + * @psoc: PSOC object information + * @vdev_id: vdev id + * + * Return: None + */ +void policy_mgr_move_vdev_from_disabled_to_connection_tbl( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_move_vdev_from_connection_to_disabled_tbl() - Add/move the link + * vdev to disable a ml link table + * @psoc: PSOC object information + * @vdev_id: vdev id + * + * Return: None + */ +void policy_mgr_move_vdev_from_connection_to_disabled_tbl( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_ml_link_vdev_need_to_be_disabled() - check if ml link need to be + * disabled during connection. + * @psoc: psoc + * @vdev: vdev + * @peer_assoc: check peer assoc command + * + * Check the vdev need to be moved to disabled policy mgr table. + * If peer_assoc = false, the API will check the forced inactive link bitmap + * as well. Vdev will be disabled if vdev's link id is forced inactive(includes + * dynamic inactive) + * + * Return: true if STA link is need to be disabled else false. + */ +bool +policy_mgr_ml_link_vdev_need_to_be_disabled(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + bool peer_assoc); + +/** + * policy_mgr_is_set_link_in_progress() - Check set link in progress or not + * @psoc: psoc pointer + * + * Return: true if set link in progress + */ +bool policy_mgr_is_set_link_in_progress(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_wait_for_set_link_update() - Wait for set/clear link response + * @psoc: psoc pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_wait_for_set_link_update(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_active_vdev_bitmap() - to get active ML STA vdev bitmap + * @psoc: PSOC object information + * + * This API will fetch the active ML STA vdev bitmap. + * + * Return: vdev bitmap value + */ +uint32_t +policy_mgr_get_active_vdev_bitmap(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_emlsr_sta_concurrency_present() - Check whether eMLSR + * concurrency is present or not. + * @psoc: PSOC object information + * + * This API is to check if any other concurrency is present when an eMLSR + * STA connection is about to complete(i.e. when first link is connected + * and second link is coming up). This helps to let the eMLSR connection + * happen but not let firmware enter into eMLSR hw mode by sending + * mlo_force_link_inactive=1 in peer_assoc of link when other concurrency is + * present. + * + * Host driver shall disable the one link post connection anyway if concurrency + * is present. Once the concurrency is gone, policy_mgr shall evaluate and + * re-enable links to let firmware go to eMLSR hw mode. + * + * Return: true is it's allow otherwise false + */ +bool policy_mgr_is_emlsr_sta_concurrency_present(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +policy_mgr_is_ml_vdev_id(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return false; +} + +static inline uint32_t +policy_mgr_get_disabled_ml_links_count(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline void +policy_mgr_move_vdev_from_disabled_to_connection_tbl( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) {} + +static inline bool +policy_mgr_ml_link_vdev_need_to_be_disabled(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + bool peer_assoc) +{ + return false; +} + +static inline void +policy_mgr_move_vdev_from_connection_to_disabled_tbl( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) {} + +static inline bool +policy_mgr_is_set_link_in_progress(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +policy_mgr_wait_for_set_link_update(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline uint32_t +policy_mgr_get_active_vdev_bitmap(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline bool +policy_mgr_is_emlsr_sta_concurrency_present(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * policy_mgr_skip_dfs_ch() - skip dfs channel or not + * @psoc: pointer to soc + * @skip_dfs_channel: pointer to result + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_skip_dfs_ch(struct wlan_objmgr_psoc *psoc, + bool *skip_dfs_channel); + +/** + * policy_mgr_get_channel() - provide channel number of given mode and vdevid + * @psoc: PSOC object information + * @mode: given mode + * @vdev_id: pointer to vdev_id + * + * This API will provide channel frequency value of matching mode and vdevid. + * If vdev_id is NULL then it will match only mode + * If vdev_id is not NULL the it will match both mode and vdev_id + * + * Return: channel frequency value + */ +uint32_t policy_mgr_get_channel(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *vdev_id); + +/** + * policy_mgr_get_pcl() - provides the preferred channel list for + * new connection + * @psoc: PSOC object information + * @mode: Device mode + * @pcl_channels: Preferred channel freq list + * @len: length of the PCL + * @pcl_weight: Weights of the PCL + * @weight_len: Max length of the weights list + * @vdev_id: Vdev id + * + * This function provides the preferred channel list on which + * policy manager wants the new connection to come up. Various + * connection decision making entities will using this function + * to query the PCL info + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_pcl(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_channels, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len, + uint8_t vdev_id); + +/** + * policy_mgr_init_chan_avoidance() - init channel avoidance in policy manager. + * @psoc: PSOC object information + * @chan_freq_list: channel frequency list + * @chan_cnt: channel count + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_init_chan_avoidance(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *chan_freq_list, + uint16_t chan_cnt); + +/** + * policy_mgr_update_with_safe_channel_list() - provides the safe + * channel list + * @psoc: PSOC object information + * @pcl_channels: channel freq list + * @len: length of the list + * @weight_list: Weights of the PCL + * @weight_len: Max length of the weights list + * + * This function provides the safe channel list from the list + * provided after consulting the channel avoidance list + * + * Return: None + */ +void policy_mgr_update_with_safe_channel_list(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, + uint32_t *len, + uint8_t *weight_list, + uint32_t weight_len); + +/** + * policy_mgr_get_nondfs_preferred_channel() - to get non-dfs preferred channel + * for given mode + * @psoc: PSOC object information + * @mode: mode for which preferred non-dfs channel is requested + * @for_existing_conn: flag to indicate if preferred channel is requested + * for existing connection + * @vdev_id: Vdev Id + * + * this routine will return non-dfs channel + * 1) for getting non-dfs preferred channel, first we check if there are any + * other connection exist whose channel is non-dfs. if yes then return that + * channel so that we can accommodate upto 3 mode concurrency. + * 2) if there no any other connection present then query concurrency module + * to give preferred channel list. once we get preferred channel list, loop + * through list to find first non-dfs channel from ascending order. + * + * Return: uint32_t non-dfs channel frequency + */ +uint32_t +policy_mgr_get_nondfs_preferred_channel(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + bool for_existing_conn, + uint8_t vdev_id); + +/** + * policy_mgr_is_any_nondfs_chnl_present() - Find any non-dfs + * channel from conc table + * @psoc: PSOC object information + * @ch_freq: pointer to channel frequency which needs to be filled + * + * In-case if any connection is already present whose channel is none dfs then + * return that channel + * + * Return: true up-on finding non-dfs channel else false + */ +bool policy_mgr_is_any_nondfs_chnl_present(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq); + +/** + * policy_mgr_get_dfs_beaconing_session_id() - to find the + * first DFS session id + * @psoc: PSOC object information + * + * Return: If any beaconing session such as SAP or GO present and it is on + * DFS channel then this function will return its session id + * + */ +uint32_t policy_mgr_get_dfs_beaconing_session_id( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_any_dfs_beaconing_session_present() - to find + * if any DFS session + * @psoc: PSOC object information + * @ch_freq: pointer to channel frequency that needs to filled + * @ch_width: pointer to channel width for the beaconing session + * + * If any beaconing session such as SAP or GO present and it is on DFS channel + * then this function will return true + * + * Return: true if session is on DFS or false if session is on non-dfs channel + */ +bool policy_mgr_is_any_dfs_beaconing_session_present( + struct wlan_objmgr_psoc *psoc, qdf_freq_t *ch_freq, + enum hw_mode_bandwidth *ch_width); + +/** + * policy_mgr_allow_concurrency() - Check for allowed concurrency + * combination consulting the PCL + * @psoc: PSOC object information + * @mode: new connection mode + * @ch_freq: channel frequency on which new connection is coming up + * @bw: Bandwidth requested by the connection (optional) + * @ext_flags: extended flags for concurrency check (union conc_ext_flag) + * @vdev_id: vdev id + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability + * + * Return: True/False based on concurrency support + */ +bool policy_mgr_allow_concurrency(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + enum hw_mode_bandwidth bw, + uint32_t ext_flags, uint8_t vdev_id); + +/** + * policy_mgr_check_scc_channel() - Check if SAP/GO freq need to be updated + * as per exiting concurrency + * @psoc: PSOC object information + * @intf_ch_freq: Channel frequency of existing concurrency + * @sap_ch_freq: Given SAP/GO channel frequency + * @vdev_id: Vdev id of the SAP/GO + * @cc_mode: concurrent switch mode + * + * When SAP/GO is starting or re-starting, check SAP/GO freq need to be + * aligned with the existing concurrencies. i.e. Forced to be on same freq as + * exiting concurrency. + * + * Return: True/False + */ +void policy_mgr_check_scc_channel(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *intf_ch_freq, + qdf_freq_t sap_ch_freq, + uint8_t vdev_id, uint8_t cc_mode); + +/** + * policy_mgr_handle_go_sap_fav_channel() - Get preferred force SCC + * channel frequency using favorite mandatory channel list for GO+SAP + * concurrency + * @psoc: Pointer to Psoc + * @vdev_id: vdev id + * @sap_ch_freq: sap/go channel starting channel frequency + * @intf_ch_freq: prefer force scc frequency + * + * SAP should move to 2.4 GHz if P2P GO is on 5G/6G. SAP should move to user + * configured channel after P2P GO is stopped + * + * Return: QDF_STATUS_SUCCESS if a valid favorite SAP channel is found + */ +QDF_STATUS +policy_mgr_handle_go_sap_fav_channel(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t sap_ch_freq, + qdf_freq_t *intf_ch_freq); + +/** + * policy_mgr_nan_sap_pre_enable_conc_check() - Check if NAN+SAP SCC is + * allowed in given ch + * @psoc: PSOC object information + * @mode: Connection mode + * @ch_freq: channel frequency to check + * + * Return: True if allowed else false + */ +bool +policy_mgr_nan_sap_pre_enable_conc_check(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq); + +/** + * policy_mgr_allow_concurrency_csa() - Check for allowed concurrency + * combination when channel switch + * @psoc: PSOC object information + * @mode: connection mode + * @ch_freq: target channel frequency to switch + * @bw: target channel bandwidth + * @vdev_id: vdev id of channel switch interface + * @forced: forced to chan switch. + * @reason: request reason of CSA + * + * There is already existing SAP+GO combination but due to upper layer + * notifying LTE-COEX event or sending command to move one of the connections + * to different channel. In such cases before moving existing connection to new + * channel, check if new channel can co-exist with the other existing + * connection. For example, one SAP1 is on channel-6 and second SAP2 is on + * channel-36 and lets say they are doing DBS, and lets say upper layer sends + * LTE-COEX to move SAP1 from channel-6 to channel-149. In this case, SAP1 and + * SAP2 will end up doing MCC which may not be desirable result. such cases + * will be prevented with this API. + * + * Return: True/False + */ +bool +policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, enum hw_mode_bandwidth bw, + uint32_t vdev_id, bool forced, + enum sap_csa_reason_code reason); + +/** + * policy_mgr_get_bw() - Convert phy_ch_width to hw_mode_bandwidth. + * @chan_width: phy_ch_width + * + * Return: hw_mode_bandwidth + */ +enum hw_mode_bandwidth policy_mgr_get_bw(enum phy_ch_width chan_width); + +/** + * policy_mgr_get_first_connection_pcl_table_index() - provides the + * row index to firstConnectionPclTable to get to the correct + * pcl + * @psoc: PSOC object information + * + * This function provides the row index to + * firstConnectionPclTable. The index is the preference config. + * + * Return: table index + */ +enum policy_mgr_conc_priority_mode + policy_mgr_get_first_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_second_connection_pcl_table_index() - provides the + * row index to secondConnectionPclTable to get to the correct + * pcl + * @psoc: PSOC object information + * + * This function provides the row index to + * secondConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from pm_conc_connection_list. + * + * Return: table index + */ +enum policy_mgr_one_connection_mode + policy_mgr_get_second_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_third_connection_pcl_table_index() - provides the + * row index to thirdConnectionPclTable to get to the correct + * pcl + * @psoc: PSOC object information + * + * This function provides the row index to + * thirdConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from pm_conc_connection_list. + * + * Return: table index + */ +enum policy_mgr_two_connection_mode + policy_mgr_get_third_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc); + +#ifdef FEATURE_FOURTH_CONNECTION +/** + * policy_mgr_get_fourth_connection_pcl_table_index() - provides the + * row index to fourthConnectionPclTable to get to the correct + * pcl + * @psoc: PSOC object information + * + * This function provides the row index to + * fourthConnectionPclTable. The index is derived based on + * current connection, band on which it is on & chain mask it is + * using, as obtained from pm_conc_connection_list. + * + * Return: table index + */ +enum policy_mgr_three_connection_mode + policy_mgr_get_fourth_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc); +#endif + +/** + * policy_mgr_incr_connection_count() - adds the new connection to + * the current connections list + * @psoc: PSOC object information + * @vdev_id: vdev id + * @mode: Operating mode + * + * This function adds the new connection to the current + * connections list + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_incr_connection_count(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + enum QDF_OPMODE mode); + +/** + * policy_mgr_update_connection_info() - updates the existing + * connection in the current connections list + * @psoc: PSOC object information + * @vdev_id: vdev id + * + * + * This function adds the new connection to the current + * connections list + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_update_connection_info(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +/** + * policy_mgr_decr_connection_count() - remove the old connection + * from the current connections list + * @psoc: PSOC object information + * @vdev_id: vdev id of the old connection + * + * + * This function removes the old connection from the current + * connections list + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_decr_connection_count(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +/** + * policy_mgr_current_connections_update() - initiates actions + * needed on current connections once channel has been decided + * for the new connection + * @psoc: PSOC object information + * @session_id: Session id + * @ch_freq: Channel frequency on which new connection will be + * @reason: Reason for which connection update is required + * @request_id: Request id provided by the requester, can be used while + * calling callback to the requester + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: QDF_STATUS enum + */ +QDF_STATUS +policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc, + uint32_t session_id, uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason, + uint32_t request_id); + +/** + * policy_mgr_change_hw_mode_sta_connect() - Change HW mode for STA connect + * @psoc: psoc object + * @scan_list: candidates for connection + * @vdev_id: vdev id for STA/CLI + * @connect_id: connect id of the connect request + * + * When a new connection is about to come up, change hw mode for STA/CLI + * based upon the scan results and hw type. + * + * Return: status if set HW mode is fail or already taken care of. + */ +QDF_STATUS +policy_mgr_change_hw_mode_sta_connect(struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, uint8_t vdev_id, + uint32_t connect_id); + +/** + * policy_mgr_is_dbs_allowed_for_concurrency() - If dbs is allowed for current + * concurreny + * @psoc: PSOC object information + * @new_conn_mode: new connection mode + * + * When a new connection is about to come up, check if dbs is allowed for + * STA+STA or STA+P2P + * + * Return: true if dbs is allowed for STA+STA or STA+P2P else false + */ +bool policy_mgr_is_dbs_allowed_for_concurrency( + struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE new_conn_mode); + +#ifndef WLAN_FEATURE_LL_LT_SAP +/** + * policy_mgr_get_pcl_chlist_for_ll_sap() - Get pcl channel list for LL SAP + * @psoc: PSOC object information + * @len: length of the PCL + * @pcl_channels: Preferred channel freq list + * @pcl_weight: Weights of the PCL + * + * This function provides the preferred channel list on which the ll sap + * can come. + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_get_pcl_chlist_for_ll_sap(struct wlan_objmgr_psoc *psoc, + uint32_t *len, uint32_t *pcl_channels, + uint8_t *pcl_weight); + +/** + * policy_mgr_get_pcl_ch_for_sap_go_with_ll_sap_present() - Get pcl channel + * list for SAP/GO when LL SAP is present + * @psoc: PSOC object information + * @len: length of the PCL + * @pcl_channels: Preferred channel freq list + * @pcl_weight: Weights of the PCL + * + * This function provides the preferred channel list for SAP/GO when LL SAP + * is present + * + * Return: QDF_STATUS + */ + +QDF_STATUS +policy_mgr_get_pcl_ch_for_sap_go_with_ll_sap_present( + struct wlan_objmgr_psoc *psoc, + uint32_t *len, uint32_t *pcl_channels, + uint8_t *pcl_weight); + +/** + * policy_mgr_get_pcl_channel_for_ll_sap_concurrency() - Get pcl channel list + * for LL SAP concurrency + * @psoc: PSOC object information + * @vdev_id: Vdev id + * @pcl_channels: Preferred channel freq list + * @pcl_weight: Weights of the PCL + * @len: length of the PCL + * + * Return: QDF_STATUS + */ + +QDF_STATUS +policy_mgr_get_pcl_channel_for_ll_sap_concurrency( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t *pcl_channels, + uint8_t *pcl_weight, uint32_t *len); +#else +static inline QDF_STATUS +policy_mgr_get_pcl_chlist_for_ll_sap(struct wlan_objmgr_psoc *psoc, + uint32_t *len, uint32_t *pcl_channels, + uint8_t *pcl_weight) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +policy_mgr_get_pcl_ch_for_sap_go_with_ll_sap_present( + struct wlan_objmgr_psoc *psoc, + uint32_t *len, uint32_t *pcl_channels, + uint8_t *pcl_weight) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +policy_mgr_get_pcl_channel_for_ll_sap_concurrency( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t *pcl_channels, + uint8_t *pcl_weight, uint32_t *len) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * policy_mgr_is_vdev_ll_sap() - Check whether given vdev is LL SAP or not + * @psoc: psoc object + * @vdev_id: vdev id + * + * Return: true if it's present otherwise false + */ +bool +policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +/** + * policy_mgr_is_vdev_ll_ht_sap() - Check whether given vdev is HT LL SAP or not + * @psoc: psoc object + * @vdev_id: vdev id + * + * Based on vdev id ap profile set via vendor command is get and compared with + * ll_ht_type AP type and is return true if profile set is throghput sensitive. + * + * Return: true if it's present otherwise false + */ +bool +policy_mgr_is_vdev_ll_ht_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +/** + * policy_mgr_is_vdev_ll_lt_sap() - Check whether given vdev is LL_LT_SAP or not + * @psoc: psoc object + * @vdev_id: vdev id + * + * Based on vdev id ap profile set via vendor command is get and compared with + * lt_ll_type AP and is return true if profile set is gaming or losless audio + * where latency matters. + * + * Return: true if it's present otherwise false + */ +bool +policy_mgr_is_vdev_ll_lt_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +/** + * policy_mgr_get_preferred_dbs_action_table() - get dbs action table type + * @psoc: Pointer to psoc + * @vdev_id: vdev Id + * @ch_freq: channel frequency of vdev. + * @reason: reason of request + * + * 1. Based on band preferred and vdev priority setting to choose the preferred + * dbs action. + * 2. This routine will be used to get DBS switching action tables. + * In Genoa, two action tables for DBS1 (2x2 5G + 1x1 2G), DBS2 + * (2x2 2G + 1x1 5G). + * 3. It can be used in mode change case in CSA channel switching or Roaming, + * opportunistic upgrade. If needs switch to DBS, we needs to query this + * function to get preferred DBS mode. + * 4. This is mainly used for dual dbs mode HW. For Legacy HW, there is + * only single DBS mode. This function will return PM_NOP. + * + * return : PM_NOP, PM_DBS1, PM_DBS2 + */ +enum policy_mgr_conc_next_action +policy_mgr_get_preferred_dbs_action_table( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason); + +/** + * policy_mgr_get_conn_info() - get the current connections list + * @len: length of the list + * + * This function returns a pointer to the current connections + * list + * + * Return: pointer to connection list + */ +struct policy_mgr_conc_connection_info *policy_mgr_get_conn_info( + uint32_t *len); + +/** + * policy_mgr_qdf_opmode_to_pm_con_mode() - provides the + * type translation from QDF to policy manager type + * @psoc: psoc + * @device_mode: Generic connection mode type + * @vdev_id: Vdev id + * + * + * This function provides the type translation + * + * Return: policy_mgr_con_mode enum + */ +enum policy_mgr_con_mode +policy_mgr_qdf_opmode_to_pm_con_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE device_mode, + uint8_t vdev_id); + +/** + * policy_mgr_get_qdf_mode_from_pm - provides the + * type translation from policy manager type + * to generic connection mode type + * @device_mode: policy manager mode type + * + * + * This function provides the type translation + * + * Return: QDF_OPMODE enum + */ +enum QDF_OPMODE policy_mgr_get_qdf_mode_from_pm( + enum policy_mgr_con_mode device_mode); + +/** + * policy_mgr_check_n_start_opportunistic_timer - check single mac upgrade + * needed or not, if needed start the oppurtunistic timer. + * @psoc: pointer to SOC + * + * This function starts the oppurtunistic timer if hw_mode change is needed + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_check_n_start_opportunistic_timer( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_pdev_set_hw_mode() - Set HW mode command to FW + * @psoc: PSOC object information + * @session_id: Session ID + * @mac0_ss: MAC0 spatial stream configuration + * @mac0_bw: MAC0 bandwidth configuration + * @mac1_ss: MAC1 spatial stream configuration + * @mac1_bw: MAC1 bandwidth configuration + * @mac0_band_cap: mac0 band capability requirement + * (0: Don't care, 1: 2.4G, 2: 5G) + * @dbs: HW DBS capability + * @dfs: HW Agile DFS capability + * @sbs: HW SBS capability + * @reason: Reason for connection update + * @next_action: next action to happen at policy mgr after + * HW mode change + * @action: action to be applied before hw mode change + * + * @request_id: Request id provided by the requester, can be used while + * calling callback to the requester + * + * Sends the set hw mode request to FW + * + * e.g.: To configure 2x2_80 + * mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_0x0, mac1_bw = HW_MODE_BW_NONE + * mac0_band_cap = HW_MODE_MAC_BAND_NONE, + * dbs = HW_MODE_DBS_NONE, dfs = HW_MODE_AGILE_DFS_NONE, + * sbs = HW_MODE_SBS_NONE + * e.g.: To configure 1x1_80_1x1_40 (DBS) + * mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * mac0_band_cap = HW_MODE_MAC_BAND_NONE, + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE, + * sbs = HW_MODE_SBS_NONE + * e.g.: To configure 1x1_80_1x1_40 (Agile DFS) + * mac0_ss = HW_MODE_SS_1x1, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * mac0_band_cap = HW_MODE_MAC_BAND_NONE, + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS, + * sbs = HW_MODE_SBS_NONE + * e.g.: To configure 2x2_5g_80+1x1_2g_40 + * mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_80_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * mac0_band_cap = HW_MODE_MAC_BAND_5G + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE, + * sbs = HW_MODE_SBS_NONE + * e.g.: To configure 2x2_2g_40+1x1_5g_40 + * mac0_ss = HW_MODE_SS_2x2, mac0_bw = HW_MODE_40_MHZ + * mac1_ss = HW_MODE_SS_1x1, mac1_bw = HW_MODE_40_MHZ + * mac0_band_cap = HW_MODE_MAC_BAND_2G + * dbs = HW_MODE_DBS, dfs = HW_MODE_AGILE_DFS_NONE, + * sbs = HW_MODE_SBS_NONE + * + * Return: Success if the message made it down to the next layer + */ +QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc, + uint32_t session_id, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_mac_band_cap mac0_band_cap, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs, + enum policy_mgr_conn_update_reason reason, + uint8_t next_action, enum policy_mgr_conc_next_action action, + uint32_t request_id); + +/** + * typedef policy_mgr_pdev_set_hw_mode_cback() - callback invoked by + * other component to provide set HW mode request status + * @status: status of the request + * @cfgd_hw_mode_index: new HW mode index + * @num_vdev_mac_entries: Number of mac entries + * @vdev_mac_map: The table of vdev to mac mapping + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for set HW mode + * @session_id: vdev id on which the request was made + * @context: PSOC object information + * @request_id: Request id provided by the requester, can be used while + * calling callback to the requester + * + * This function is the callback registered with SME at set HW + * mode request time + * + * Return: None + */ +typedef void (*policy_mgr_pdev_set_hw_mode_cback)(uint32_t status, + uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t session_id, void *context, + uint32_t request_id); + +/** + * typedef policy_mgr_nss_update_cback() - callback invoked by other + * component to provide nss update request status + * @psoc: PSOC object information + * @tx_status: tx completion status for updated beacon with new + * nss value + * @vdev_id: vdev id for the specific connection + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for nss update + * @original_vdev_id: original request hwmode change vdev id + * @request_id: cm req id + * + * This function is the callback registered with SME at nss + * update request time + * + * Return: None + */ +typedef void (*policy_mgr_nss_update_cback)(struct wlan_objmgr_psoc *psoc, + uint8_t tx_status, + uint8_t vdev_id, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id); + +/** + * struct policy_mgr_sme_cbacks - SME Callbacks to be invoked + * from policy manager + * @sme_get_nss_for_vdev: Get the allowed nss value for the vdev + * @sme_soc_set_dual_mac_config: Set the dual MAC scan & FW + * config + * @sme_pdev_set_hw_mode: Set the new HW mode to FW + * @sme_nss_update_request: Update NSS value to FW + * @sme_change_mcc_beacon_interval: Set MCC beacon interval to FW + * @sme_rso_start_cb: Enable roaming offload callback + * @sme_rso_stop_cb: Disable roaming offload callback + * @sme_change_sap_csa_count: Change CSA count for SAP/GO, only one + * time, needs to set again if used once. + * @sme_sap_update_ch_width: Update sap ch_width to fw to handle SAP 320MHz + * concurrencies + */ +struct policy_mgr_sme_cbacks { + void (*sme_get_nss_for_vdev)(enum QDF_OPMODE, + uint8_t *nss_2g, uint8_t *nss_5g); + QDF_STATUS (*sme_soc_set_dual_mac_config)( + struct policy_mgr_dual_mac_config msg); + QDF_STATUS (*sme_pdev_set_hw_mode)(struct policy_mgr_hw_mode msg); + QDF_STATUS (*sme_nss_update_request)(uint32_t vdev_id, + uint8_t new_nss, uint8_t ch_width, + policy_mgr_nss_update_cback cback, + uint8_t next_action, struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id); + QDF_STATUS (*sme_change_mcc_beacon_interval)(uint8_t session_id); + QDF_STATUS (*sme_rso_start_cb)( + mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t reason, enum wlan_cm_rso_control_requestor requestor); + QDF_STATUS (*sme_rso_stop_cb)( + mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t reason, enum wlan_cm_rso_control_requestor requestor); + QDF_STATUS (*sme_change_sap_csa_count)(uint8_t count); + QDF_STATUS (*sme_sap_update_ch_width)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width ch_width, + enum policy_mgr_conn_update_reason reason, + uint8_t conc_vdev_id, uint32_t request_id); +}; + +/** + * struct policy_mgr_hdd_cbacks - HDD Callbacks to be invoked + * from policy manager + * @sap_restart_chan_switch_cb: Restart SAP + * @wlan_hdd_get_channel_for_sap_restart: Get channel to restart + * SAP + * @get_mode_for_non_connected_vdev: Get the mode for a non + * connected vdev + * @hdd_get_device_mode: Get QDF_OPMODE type for session id (vdev id) + * @hdd_is_chan_switch_in_progress: Check if in any adapter channel switch is in + * progress + * @hdd_is_cac_in_progress: Check if in any adapter CAC is in progress + * @wlan_hdd_set_sap_csa_reason: Set the sap csa reason in cases like NAN. + * @hdd_get_ap_6ghz_capable: get ap vdev 6ghz capable info from hdd ap adapter. + * @wlan_hdd_indicate_active_ndp_cnt: indicate active ndp cnt to hdd + * @wlan_get_ap_prefer_conc_ch_params: get prefer ap channel bw parameters + * based on target channel frequency and concurrent connections. + * @wlan_get_sap_acs_band: get acs band from sap config + * @wlan_check_cc_intf_cb: get interference frequency of input SAP/GO interface + * @wlan_set_tx_rx_nss_cb: set NSS dynamically for STA + */ +struct policy_mgr_hdd_cbacks { + QDF_STATUS (*sap_restart_chan_switch_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t ch_freq, + uint32_t channel_bw, + bool forced); + QDF_STATUS (*wlan_hdd_get_channel_for_sap_restart)( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t *ch_freq); + enum policy_mgr_con_mode (*get_mode_for_non_connected_vdev)( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + enum QDF_OPMODE (*hdd_get_device_mode)(uint32_t session_id); + bool (*hdd_is_chan_switch_in_progress)(void); + bool (*hdd_is_cac_in_progress)(void); + void (*wlan_hdd_set_sap_csa_reason)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t reason); + uint32_t (*hdd_get_ap_6ghz_capable)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + void (*wlan_hdd_indicate_active_ndp_cnt)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t cnt); + QDF_STATUS (*wlan_get_ap_prefer_conc_ch_params)( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t chan_freq, + struct ch_params *ch_params); + uint32_t (*wlan_get_sap_acs_band)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t *acs_band); + QDF_STATUS (*wlan_check_cc_intf_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t *ch_freq); + QDF_STATUS (*wlan_set_tx_rx_nss_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t tx_nss, + uint8_t rx_nss); +}; + +/** + * struct policy_mgr_conc_cbacks - lim Callbacks to be invoked + * from policy manager + * @connection_info_update: check and update params based on STA/SAP + * concurrency.such as EDCA params and RTS threshold. + * If updated, it will also send the updated parameters + * to FW. + */ + +struct policy_mgr_conc_cbacks { + void (*connection_info_update)(void); +}; + +/** + * struct policy_mgr_tdls_cbacks - TDLS Callbacks to be invoked + * from policy manager + * @tdls_notify_increment_session: + * @tdls_notify_decrement_session: + */ +struct policy_mgr_tdls_cbacks { + void (*tdls_notify_increment_session)(struct wlan_objmgr_psoc *psoc); + void (*tdls_notify_decrement_session)(struct wlan_objmgr_psoc *psoc); +}; + +/** + * struct policy_mgr_cdp_cbacks - CDP Callbacks to be invoked + * from policy manager + * @cdp_update_mac_id: update mac_id for vdev + */ +struct policy_mgr_cdp_cbacks { + void (*cdp_update_mac_id)(struct wlan_objmgr_psoc *soc, + uint8_t vdev_id, uint8_t mac_id); +}; + +/** + * struct policy_mgr_dp_cbacks - CDP Callbacks to be invoked + * from policy manager + * @hdd_disable_rx_ol_in_concurrency: Callback to disable LRO/GRO offloads + * @hdd_set_rx_mode_rps_cb: Callback to set RPS + * @hdd_ipa_set_mcc_mode_cb: Callback to set mcc mode for ipa module + * @hdd_v2_flow_pool_map: Callback to create vdev flow pool + * @hdd_v2_flow_pool_unmap: Callback to delete vdev flow pool + * @hdd_ipa_set_perf_level_bw: Callback to set ipa perf level based on BW + */ +struct policy_mgr_dp_cbacks { + void (*hdd_disable_rx_ol_in_concurrency)(bool); + void (*hdd_set_rx_mode_rps_cb)(bool); + void (*hdd_ipa_set_mcc_mode_cb)(bool); + void (*hdd_v2_flow_pool_map)(int); + void (*hdd_v2_flow_pool_unmap)(int); + void (*hdd_ipa_set_perf_level_bw)(enum hw_mode_bandwidth bw); +}; + +/** + * struct policy_mgr_wma_cbacks - WMA Callbacks to be invoked + * from policy manager + * @wma_get_connection_info: Get the connection related info + * from wma table + */ +struct policy_mgr_wma_cbacks { + QDF_STATUS (*wma_get_connection_info)(uint8_t vdev_id, + struct policy_mgr_vdev_entry_info *conn_table_entry); +}; + +/** +* policy_mgr_need_opportunistic_upgrade - check whether needs to change current +* HW mode to single mac 2x2 or the other DBS mode(for Dual DBS HW only). +* @psoc: PSOC object information +* @reason: enum policy_mgr_conn_update_reason +* +* This function is to check whether needs to change to single Mac mode. +* when opportunistic timer fired. But a special case for Dual DBS HW, this +* function will check DBS to DBS change is required or not: +* 1. For Dual DBS HW, if user set vdev priority list, we may need to do +* DBS to DBS switching. +* eg. P2P GO (2g) < SAP (5G) < STA (2g) in DBS2. +* If STA down, we need to switch to DBS1: P2P GO (2g) < SAP (5g). +* So, for opportunistic checking, we need to add DBS ->DBS checking +* as well. +* 2. Reason code : +* DBS -> Single MAC : POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC +* DBS -> DBS : POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE +* +* return: PM_NOP, upgrade is not needed, otherwise new action type +* and reason code be returned. +*/ +enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conn_update_reason *reason); + +/** + * policy_mgr_next_actions() - initiates actions needed on current + * connections once channel has been decided for the new + * connection + * @psoc: PSOC object information + * @session_id: Session id + * @action: action to be executed + * @reason: Reason for connection update + * @request_id: Request id provided by the requester, can be used while + * calling callback to the requester + * + * This function initiates initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: QDF_STATUS enum + */ +QDF_STATUS policy_mgr_next_actions(struct wlan_objmgr_psoc *psoc, + uint32_t session_id, + enum policy_mgr_conc_next_action action, + enum policy_mgr_conn_update_reason reason, + uint32_t request_id); + +/** + * policy_mgr_validate_dbs_switch() - Check DBS action valid or not + * @psoc: Pointer to psoc + * @action: action requested + * + * This routine will check the current hw mode with requested action. + * If we are already in the mode, the caller will do nothing. + * This will be called by policy_mgr_next_actions to check the action needed + * or not. + * + * return : QDF_STATUS_SUCCESS, action is allowed. + * QDF_STATUS_E_ALREADY, action is not needed. + * QDF_STATUS_E_FAILURE, error happens. + * QDF_STATUS_E_NOSUPPORT, the requested mode not supported. + */ +QDF_STATUS +policy_mgr_validate_dbs_switch(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conc_next_action action); + +/** + * policy_mgr_set_dual_mac_scan_config() - Set the dual MAC scan config + * @psoc: PSOC object information + * @dbs_val: Value of DBS bit + * @dbs_plus_agile_scan_val: Value of DBS plus agile scan bit + * @single_mac_scan_with_dbs_val: Value of Single MAC scan with DBS + * + * Set the values of scan config. For FW mode config, the existing values + * will be retained + * + * Return: None + */ +void policy_mgr_set_dual_mac_scan_config(struct wlan_objmgr_psoc *psoc, + uint8_t dbs_val, + uint8_t dbs_plus_agile_scan_val, + uint8_t single_mac_scan_with_dbs_val); + +/** + * policy_mgr_set_dual_mac_fw_mode_config() - Set the dual mac FW mode config + * @psoc: PSOC object information + * @dbs: DBS bit + * @dfs: Agile DFS bit + * + * Set the values of fw mode config. For scan config, the existing values + * will be retain. + * + * Return: None + */ +void policy_mgr_set_dual_mac_fw_mode_config(struct wlan_objmgr_psoc *psoc, + uint8_t dbs, uint8_t dfs); + +/** + * policy_mgr_is_scc_with_this_vdev_id() - Check if this vdev_id has SCC with + * other vdev_id's + * @psoc: PSOC object information + * @vdev_id: vdev_id + * + * This function checks if the given vdev_id has SCC with any other vdev's + * or not. + * + * Return: true if SCC exists, false otherwise + */ +bool policy_mgr_is_scc_with_this_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_is_mcc_with_this_vdev_id() - Is current vdev having MCC + * with any other vdev. + * @psoc: Pointer to PSOC object + * @vdev_id: vdev id + * @mcc_vdev_id: Concurrent MCC vdev id + * + * Return: true if MCC exists, false otherwise + */ +bool policy_mgr_is_mcc_with_this_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *mcc_vdev_id); + +/** + * policy_mgr_is_mcc_on_any_sta_vdev() - Check if any sta vdev is in MCC + * @psoc: Pointer to PSOC object + * + * Return: true if STA vdev is in MCC false otherwise + */ +bool policy_mgr_is_mcc_on_any_sta_vdev(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_soc_set_dual_mac_cfg_cb() - Callback for set dual mac config + * @status: Status of set dual mac config + * @scan_config: Current scan config whose status is the first param + * @fw_mode_config: Current FW mode config whose status is the first param + * + * Callback on setting the dual mac configuration + * + * Return: None + */ +void policy_mgr_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status, + uint32_t scan_config, uint32_t fw_mode_config); + +/** + * policy_mgr_mode_specific_num_open_sessions() - to get number of open sessions + * for a specific mode + * @psoc: PSOC object information + * @mode: device mode + * @num_sessions: to store num open sessions + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_mode_specific_num_open_sessions( + struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode, + uint8_t *num_sessions); + +/** + * policy_mgr_mode_specific_num_active_sessions() - to get number of active + * sessions for a specific mode + * @psoc: PSOC object information + * @mode: device mode + * @num_sessions: to store num active sessions + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_mode_specific_num_active_sessions( + struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode, + uint8_t *num_sessions); + +/** + * policy_mgr_concurrent_open_sessions_running() - Checks for + * concurrent open session + * @psoc: PSOC object information + * + * Checks if more than one open session is running for all the allowed modes + * in the driver + * + * Return: True if more than one open session exists, False otherwise + */ +bool policy_mgr_concurrent_open_sessions_running( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_max_concurrent_connections_reached() - Check if + * max conccurrency is reached + * @psoc: PSOC object information + * Checks for presence of concurrency where more than one connection exists + * + * Return: True if the max concurrency is reached, False otherwise + * + * Example: + * STA + STA (wlan0 and wlan1 are connected) - returns true + * STA + STA (wlan0 connected and wlan1 disconnected) - returns false + * DUT with P2P-GO + P2P-CLIENT connection) - returns true + * + */ +bool policy_mgr_max_concurrent_connections_reached( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_clear_concurrent_session_count() - Clear active session count + * @psoc: PSOC object information + * Clears the active session count for all modes + * + * Return: None + */ +void policy_mgr_clear_concurrent_session_count(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_multiple_active_sta_sessions() - Check for + * multiple STA connections + * @psoc: PSOC object information + * + * Checks if multiple active STA connection are in the driver + * + * Return: True if multiple STA sessions are present, False otherwise + * + */ +bool policy_mgr_is_multiple_active_sta_sessions( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_sta_active_connection_exists() - Check if a STA + * connection is active + * @psoc: PSOC object information + * + * Checks if there is atleast one active STA connection in the driver + * + * Return: True if an active STA session is present, False otherwise + */ +bool policy_mgr_is_sta_active_connection_exists( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_concurrent_beaconing_sessions_running() - Checks + * for concurrent beaconing entities + * @psoc: PSOC object information + * + * Checks if multiple beaconing sessions are running i.e., if SAP or GO or IBSS + * are beaconing together + * + * Return: True if multiple entities are beaconing together, False otherwise + */ +bool policy_mgr_concurrent_beaconing_sessions_running( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_wait_for_connection_update() - Wait for hw mode + * command to get processed + * @psoc: PSOC object information + * Waits for CONNECTION_UPDATE_TIMEOUT duration until the set hw mode + * response sets the event connection_update_done_evt + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_wait_for_connection_update( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_reset_connection_update() - Reset connection + * update event + * @psoc: PSOC object information + * Resets the concurrent connection update event + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_reset_connection_update(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_reset_hw_mode_change() - Reset the hw mode change. + * @psoc: Pointer to PSOC object + * + * Return: none + */ +void policy_mgr_reset_hw_mode_change(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_connection_update() - Set connection update + * event + * @psoc: PSOC object information + * Sets the concurrent connection update event + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_set_connection_update(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_chan_switch_complete_evt() - set channel + * switch completion event + * @psoc: PSOC object information + * Sets the channel switch completion event. + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_set_chan_switch_complete_evt( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_reset_chan_switch_complete_evt() - reset channel + * switch completion event + * @psoc: PSOC object information + * Resets the channel switch completion event. + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_reset_chan_switch_complete_evt( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_opportunistic_update() - Set opportunistic + * update event + * @psoc: PSOC object information + * Sets the opportunistic update event + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_set_opportunistic_update(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_stop_opportunistic_timer() - Stops opportunistic timer + * @psoc: PSOC object information + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_stop_opportunistic_timer(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_restart_opportunistic_timer() - Restarts opportunistic timer + * @psoc: PSOC object information + * @check_state: check timer state if this flag is set, else restart + * irrespective of state + * + * Restarts opportunistic timer for DBS_OPPORTUNISTIC_TIME seconds. + * Check if current state is RUNNING if check_state is set, else + * restart the timer irrespective of state. + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_restart_opportunistic_timer( + struct wlan_objmgr_psoc *psoc, bool check_state); + +/** + * policy_mgr_modify_sap_pcl_based_on_mandatory_channel() - + * Modify SAPs PCL based on mandatory channel list + * @psoc: PSOC object information + * @pcl_list_org: Pointer to the preferred channel freq list to be trimmed + * @weight_list_org: Pointer to the weights of the preferred channel list + * @pcl_len_org: Pointer to the length of the preferred channel list + * + * Modifies the preferred channel list of SAP based on the mandatory channel + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel( + struct wlan_objmgr_psoc *psoc, uint32_t *pcl_list_org, + uint8_t *weight_list_org, uint32_t *pcl_len_org); + +/** + * policy_mgr_update_and_wait_for_connection_update() - Update and wait for + * connection update + * @psoc: PSOC object information + * @session_id: Session id + * @ch_freq: Channel frequency + * @reason: Reason for connection update + * + * Update the connection to either single MAC or dual MAC and wait for the + * update to complete + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_update_and_wait_for_connection_update( + struct wlan_objmgr_psoc *psoc, uint8_t session_id, + uint32_t ch_freq, enum policy_mgr_conn_update_reason reason); + +/** + * policy_mgr_is_sap_mandatory_channel_set() - Checks if SAP + * mandatory channel is set + * @psoc: PSOC object information + * Checks if any mandatory channel is set for SAP operation + * + * Return: True if mandatory channel is set, false otherwise + */ +bool policy_mgr_is_sap_mandatory_channel_set(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_list_has_24GHz_channel() - Check if list contains 2.4GHz channels + * @ch_freq_list: Channel frequency list + * @list_len: Length of the channel list + * + * Checks if the channel list contains atleast one 2.4GHz channel + * + * Return: True if 2.4GHz channel is present, false otherwise + */ +bool policy_mgr_list_has_24GHz_channel(uint32_t *ch_freq_list, + uint32_t list_len); + +/** + * policy_mgr_get_valid_chans_from_range() - get valid channel from given range + * @psoc: PSOC object information + * @ch_list: Pointer to the channel frequency list + * @ch_cnt: Pointer to the length of the channel list + * @mode: Device mode + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_valid_chans_from_range(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_list, + uint32_t *ch_cnt, + enum policy_mgr_con_mode mode); +/** + * policy_mgr_get_valid_chans() - Get the valid channel list + * @psoc: PSOC object information + * @ch_freq_list: Pointer to the valid channel frequency list + * @list_len: Pointer to the length of the valid channel list + * + * Gets the valid channel list filtered by band + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_valid_chans(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, + uint32_t *list_len); + +/** + * policy_mgr_get_nss_for_vdev() - Get the allowed nss value for the + * vdev + * @psoc: PSOC object information + * @mode: connection type. + * @nss_2g: Pointer to the 2G Nss parameter. + * @nss_5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on connection type. + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_nss_for_vdev(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *nss_2g, uint8_t *nss_5g); + +/** + * policy_mgr_get_sap_mandatory_channel() - Get the mandatory channel for SAP + * @psoc: PSOC object information + * @sap_ch_freq: sap current frequency in MHz + * @intf_ch_freq: input/out interference channel frequency to sap + * @sap_vdev_id: SAP vdev id + * + * Gets the mandatory channel for SAP operation + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_get_sap_mandatory_channel(struct wlan_objmgr_psoc *psoc, + uint32_t sap_ch_freq, + uint32_t *intf_ch_freq, + uint8_t sap_vdev_id); + +/** + * policy_mgr_set_sap_mandatory_channels() - Set the mandatory channel for SAP + * @psoc: PSOC object information + * @ch_freq_list: Channel frequency list to be set + * @len: Length of the channel list + * + * Sets the channels for the mandatory channel list along with the length of + * of the channel list. + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_set_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, + uint32_t len); + +/** + * policy_mgr_is_any_mode_active_on_band_along_with_session() - + * Check if any connection mode is active on a band along with + * the given session + * @psoc: PSOC object information + * @session_id: Session along which active sessions are looked for + * @band: Operating frequency band of the connection + * POLICY_MGR_BAND_24: Looks for active connection on 2.4 GHz only + * POLICY_MGR_BAND_5: Looks for active connection on 5 GHz only + * + * Checks if any of the connection mode is active on a given frequency band + * + * Return: True if any connection is active on a given band, false otherwise + */ +bool policy_mgr_is_any_mode_active_on_band_along_with_session( + struct wlan_objmgr_psoc *psoc, uint8_t session_id, + enum policy_mgr_band band); + +/** + * policy_mgr_get_bw_by_session_id() - Get channel width for a given session ID + * @psoc: PSOC object information + * @session_id: Session ID + * + * Return: channel width of the session + */ +enum phy_ch_width +policy_mgr_get_bw_by_session_id(struct wlan_objmgr_psoc *psoc, + uint8_t session_id); + +/** + * policy_mgr_get_chan_by_session_id() - Get channel for a given session ID + * @psoc: PSOC object information + * @session_id: Session ID + * @ch_freq: Pointer to the channel frequency + * + * Gets the channel for a given session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_chan_by_session_id(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + uint32_t *ch_freq); + +/** + * policy_mgr_get_sap_go_count_on_mac() - Provide the count of sap and go on + * given mac + * @psoc: PSOC object information + * @list: To provide the vdev_id of the satisfied sap and go (optional) + * @mac_id: MAC ID + * + * This function provides the count of the matched sap and go + * + * Return: count of the satisfied sap and go + */ +uint32_t policy_mgr_get_sap_go_count_on_mac(struct wlan_objmgr_psoc *psoc, + uint32_t *list, uint8_t mac_id); + +/** + * policy_mgr_is_sta_present_on_dfs_channel() - to find whether any DFS STA is + * present + * @psoc: PSOC object information + * @vdev_id: pointer to vdev_id. It will be filled with the vdev_id of DFS STA + * @ch_freq: pointer to channel frequency on which DFS STA is present + * @ch_width: pointer channel width on which DFS STA is connected + * If any STA is connected on DFS channel then this function will return true + * + * Return: true if session is on DFS or false if session is on non-dfs channel + */ +bool policy_mgr_is_sta_present_on_dfs_channel(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id, + qdf_freq_t *ch_freq, + enum hw_mode_bandwidth *ch_width); + +/** + * policy_mgr_is_sta_present_on_freq() - Checks whether sta is present on the + * given frequency + * @psoc: PSOC object information + * @vdev_id: pointer to vdev_id. It will be filled with the vdev_id of DFS STA + * @ch_freq: channel for which this checks is needed + * @ch_width: pointer channel width on which DFS STA is connected + * + * Return: true if STA is found in ch_freq + */ +bool policy_mgr_is_sta_present_on_freq(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id, qdf_freq_t ch_freq, + enum hw_mode_bandwidth *ch_width); + +/** + * policy_mgr_is_sta_gc_active_on_mac() - Is there active sta/gc for a + * given mac id + * @psoc: PSOC object information + * @mac_id: MAC ID + * + * Checks if there is active sta/gc for a given mac id + * + * Return: true if there is active sta/gc for a given mac id, false otherwise + */ +bool policy_mgr_is_sta_gc_active_on_mac(struct wlan_objmgr_psoc *psoc, + uint8_t mac_id); + +/** + * policy_mgr_get_mac_id_by_session_id() - Get MAC ID for a given session ID + * @psoc: PSOC object information + * @session_id: Session ID + * @mac_id: Pointer to the MAC ID + * + * Gets the MAC ID for a given session ID + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_mac_id_by_session_id(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, uint8_t *mac_id); + +/** + * policy_mgr_get_mcc_operating_channel() - Get the MCC channel + * @psoc: PSOC object information + * @session_id: Session ID with which MCC is being done + * + * Gets the MCC channel for a given session ID. + * + * Return: '0' (INVALID_CHANNEL_ID) or valid channel frequency + */ +uint32_t policy_mgr_get_mcc_operating_channel(struct wlan_objmgr_psoc *psoc, + uint8_t session_id); + +/** + * policy_mgr_get_pcl_for_existing_conn() - Get PCL for existing connection + * @psoc: PSOC object information + * @mode: Connection mode of type 'policy_mgr_con_mode' + * @pcl_ch: Pointer to the PCL + * @len: Pointer to the length of the PCL + * @pcl_weight: Pointer to the weights of the PCL + * @weight_len: Max length of the weights list + * @all_matching_cxn_to_del: Need remove all entries before getting pcl + * @vdev_id: Vdev Id + * + * Get the PCL for an existing connection + * + * Return: None + */ +QDF_STATUS policy_mgr_get_pcl_for_existing_conn( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len, + bool all_matching_cxn_to_del, + uint8_t vdev_id); + +/** + * policy_mgr_get_pcl_for_vdev_id() - Get PCL for 1 vdev + * @psoc: PSOC object information + * @mode: Connection mode of type 'policy_mgr_con_mode' + * @pcl_ch: Pointer to the PCL + * @len: Pointer to the length of the PCL + * @pcl_weight: Pointer to the weights of the PCL + * @weight_len: Max length of the weights list + * @vdev_id: vdev id to get PCL + * + * Get the PCL for a vdev, when vdev need move to another channel, need + * get PCL after remove the vdev from connection list. + * + * Return: None + */ +QDF_STATUS policy_mgr_get_pcl_for_vdev_id(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, + uint32_t weight_len, + uint8_t vdev_id); + +/** + * policy_mgr_get_pcl_for_scc_in_same_mode() - Get PCL for vdev and other + * connection in same mode and same frequency + * @psoc: PSOC object information + * @mode: Connection mode of type 'policy_mgr_con_mode' + * @pcl_ch: Pointer to the PCL + * @len: Pointer to the length of the PCL + * @pcl_weight: Pointer to the weights of the PCL + * @weight_len: Max length of the weights list + * @vdev_id: vdev id to get PCL + * + * If need move connections in same mode and same frequency, need get PCL + * after remove them from connection list. + * + * Return: QDF STATUS + */ +QDF_STATUS +policy_mgr_get_pcl_for_scc_in_same_mode(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, + uint32_t weight_len, + uint8_t vdev_id); + +/** + * policy_mgr_get_valid_chan_weights() - Get the weightage for + * all valid channels + * @psoc: PSOC object information + * @weight: Pointer to the structure containing pcl, saved channel list and + * weighed channel list + * @mode: Policy manager connection mode + * @vdev: pointer to vdev on which new connection is coming up + * + * Provides the weightage for all valid channels. This compares the PCL list + * with the valid channel list. The channels present in the PCL get their + * corresponding weightage and the non-PCL channels get the default weightage + * of WEIGHT_OF_NON_PCL_CHANNELS. + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_chan_weights *weight, + enum policy_mgr_con_mode mode, struct wlan_objmgr_vdev *vdev); + +/** + * policy_mgr_set_hw_mode_on_channel_switch() - Set hw mode + * after channel switch + * @psoc: PSOC object information + * @session_id: Session ID + * + * Sets hw mode after doing a channel switch + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_set_hw_mode_on_channel_switch( + struct wlan_objmgr_psoc *psoc, uint8_t session_id); + +/** + * policy_mgr_check_and_set_hw_mode_for_channel_switch() - check if hw mode + * change is required before channel switch for STA/SAP, + * this is required if DBS mode is 2x2 + * @psoc: PSOC object information + * @vdev_id: vdev id on which channel switch is required + * @ch_freq: New channel frequency to which channel switch is requested + * @reason: reason for hw mode change + * + * Return: QDF_STATUS, success if HW mode change is required else Failure + */ +QDF_STATUS policy_mgr_check_and_set_hw_mode_for_channel_switch( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t ch_freq, enum policy_mgr_conn_update_reason reason); + +/** + * policy_mgr_checkn_update_hw_mode_single_mac_mode() - Set hw_mode to SMM + * if required + * @psoc: PSOC object information + * @ch_freq: channel frequency for the new STA connection + * + * After the STA disconnection, if the hw_mode is in DBS and the new STA + * connection is coming in the band in which existing connections are + * present, then this function stops the dbs opportunistic timer and sets + * the hw_mode to Single MAC mode (SMM). + * + * Return: None + */ +void policy_mgr_checkn_update_hw_mode_single_mac_mode( + struct wlan_objmgr_psoc *psoc, uint32_t ch_freq); + +/** + * policy_mgr_dump_connection_status_info() - Dump the concurrency information + * @psoc: PSOC object information + * Prints the concurrency information such as tx/rx spatial stream, chainmask, + * etc. + * + * Return: None + */ +void policy_mgr_dump_connection_status_info(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_mode_get_macid_by_vdev_id() - get macid from vdev_id + * @psoc: PSOC object information + * @vdev_id: vdev id to get PCL + * + * Return: mac id + */ +uint32_t policy_mgr_mode_get_macid_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +/** + * policy_mgr_mode_specific_vdev_id() - provides the + * vdev id of the pecific mode + * @psoc: PSOC object information + * @mode: type of connection + * + * This function provides vdev id for the given mode + * + * Return: vdev id + */ +uint32_t policy_mgr_mode_specific_vdev_id(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode); + +/** + * policy_mgr_mode_specific_connection_count() - provides the + * count of connections of specific mode + * @psoc: PSOC object information + * @mode: type of connection + * @list: To provide the indices on pm_conc_connection_list + * (optional) + * + * This function provides the count of current connections + * + * Return: connection count of specific type + */ +uint32_t policy_mgr_mode_specific_connection_count( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, + uint32_t *list); + +/** + * policy_mgr_check_conn_with_mode_and_vdev_id() - checks if any active + * session with specific mode and vdev_id + * @psoc: PSOC object information + * @mode: type of connection + * @vdev_id: vdev_id of the connection + * + * This function checks if any active session with specific mode and vdev_id + * is present + * + * Return: QDF STATUS with success if active session is found, else failure + */ +QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, + uint32_t vdev_id); + +/** + * policy_mgr_dump_freq_range_n_vdev_map() - Dump freq range of mac and vdev to + * mac mapping + * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows + * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller. + * So, make local copy if needed. + * @num_mac_freq: Number of pdev freq mapping that follows + * @mac_freq_range: mac_freq_range mapping + * + * Return: None + */ +void +policy_mgr_dump_freq_range_n_vdev_map(uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *mac_freq_range); + +/** + * policy_mgr_hw_mode_transition_cb() - Callback for HW mode + * transition from FW + * @old_hw_mode_index: Old HW mode index + * @new_hw_mode_index: New HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id mapping that follows + * @vdev_mac_map: vdev-mac id map. This memory will be freed by the caller. + * So, make local copy if needed. + * @num_mac_freq: Number of pdev freq mapping that follows + * @mac_freq_range: mac_freq_range mapping + * @context: + * + * Provides the old and new HW mode index set by the FW + * + * Return: None + */ +void policy_mgr_hw_mode_transition_cb(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *mac_freq_range, + struct wlan_objmgr_psoc *context); + +/** + * policy_mgr_will_freq_lead_to_mcc() - Check if the given freq can lead to + * MCC scenario with existing connection + * @psoc: psoc pointer + * @freq: freq to check with existing connections + * + * Return: true or false + */ +bool policy_mgr_will_freq_lead_to_mcc(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq); + +/** + * policy_mgr_current_concurrency_is_scc() - To check the current + * concurrency combination if it is doing SCC + * @psoc: PSOC object information + * This routine is called to check if it is doing SCC + * + * Return: True - SCC, False - Otherwise + */ +bool policy_mgr_current_concurrency_is_scc(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_current_concurrency_is_mcc() - To check the current + * concurrency combination if it is doing MCC + * @psoc: PSOC object information + * This routine is called to check if it is doing MCC + * + * Return: True - MCC, False - Otherwise + */ +bool policy_mgr_current_concurrency_is_mcc(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_concurrent_sta_on_different_mac() - To check if + * sta concurrency on different mac + * @psoc: PSOC object information + * This routine is called to check if sta concurrency on different mac + * + * Return: True - sta concurrency on different mac, False - Otherwise + */ +bool policy_mgr_concurrent_sta_on_different_mac(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_sap_p2pgo_on_dfs() - check if there is a P2PGO or SAP + * operating in a DFS channel + * @psoc: PSOC object information + * This routine is called to check if there is a P2PGO/SAP on DFS channel + * + * Return: True - P2PGO/SAP present on DFS Channel + * False - Otherwise + */ + +bool policy_mgr_is_sap_p2pgo_on_dfs(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_register_sme_cb() - register SME callbacks + * @psoc: PSOC object information + * @sme_cbacks: function pointers from SME + * + * API, allows SME to register callbacks to be invoked by policy + * mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_sme_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_sme_cbacks *sme_cbacks); + +/** + * policy_mgr_register_hdd_cb() - register HDD callbacks + * @psoc: PSOC object information + * @hdd_cbacks: function pointers from HDD + * + * API, allows HDD to register callbacks to be invoked by policy + * mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_hdd_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_hdd_cbacks *hdd_cbacks); + +/** + * policy_mgr_register_conc_cb() - register Lim callbacks + * @psoc: PSOC object information + * @conc_cbacks: function pointers from lim + * + * API, allows Lim to register callbacks to be invoked by policy + * mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ + +QDF_STATUS policy_mgr_register_conc_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_conc_cbacks *conc_cbacks); + +/** + * policy_mgr_deregister_hdd_cb() - Deregister HDD callbacks + * @psoc: PSOC object information + * + * API, allows HDD to deregister callbacks + * + * Return: SUCCESS, + * Failure (if de-registration fails) + */ +QDF_STATUS policy_mgr_deregister_hdd_cb(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_register_tdls_cb() - register TDLS callbacks + * @psoc: PSOC object information + * @tdls_cbacks: function pointers from TDLS + * + * API, allows TDLS to register callbacks to be invoked by + * policy mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_tdls_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_tdls_cbacks *tdls_cbacks); + +/** + * policy_mgr_register_cdp_cb() - register CDP callbacks + * @psoc: PSOC object information + * @cdp_cbacks: function pointers from CDP + * + * API, allows CDP to register callbacks to be invoked by + * policy mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_cdp_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_cdp_cbacks *cdp_cbacks); + +/** + * policy_mgr_register_dp_cb() - register DP callbacks + * @psoc: PSOC object information + * @dp_cbacks: function pointers from DP + * + * API, allows DP to register callbacks to be invoked by + * policy mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_dp_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_dp_cbacks *dp_cbacks); + +/** + * policy_mgr_register_wma_cb() - register WMA callbacks + * @psoc: PSOC object information + * @wma_cbacks: function pointers from WMA + * + * API, allows WMA to register callbacks to be invoked by policy + * mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_wma_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_wma_cbacks *wma_cbacks); + +/** + * policy_mgr_find_if_fw_supports_dbs() - to find if FW/HW supports DBS + * @psoc: PSOC object information + * + * This API checks if legacy service ready event contains DBS or no. + * This API doesn't check service ready extension which contains actual + * hw mode list that tells if all supported HW modes' caps. + * + * Return: true (if service ready indication supports DBS or no) else false + * + */ +bool policy_mgr_find_if_fw_supports_dbs(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_dbs_enable() - Check if master DBS control is enabled + * @psoc: PSOC object information + * Checks if the master DBS control is enabled. This will be used + * to override any other DBS capability + * + * Return: True if master DBS control is enabled + */ +bool policy_mgr_is_dbs_enable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_hw_dbs_capable() - Check if HW is DBS capable + * @psoc: PSOC object information + * Checks if the HW is DBS capable + * + * Return: true if the HW is DBS capable + */ +bool policy_mgr_is_hw_dbs_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_interband_mcc_supported() - Checks for interband MCC support + * @psoc: PSOC object information + * Checks if target supports interband MCC or not + * + * Return: True if the target supports interband MCC else False + */ +bool policy_mgr_is_interband_mcc_supported(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_dbs_scan_allowed() - Check if DBS scan is allowed or not + * @psoc: PSOC object information + * Checks if the DBS scan can be performed or not + * + * Return: true if DBS scan is allowed. + */ +bool policy_mgr_is_dbs_scan_allowed(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_hw_sbs_capable() - Check if HW is SBS capable + * @psoc: PSOC object information + * Checks if the HW is SBS capable + * + * Return: true if the HW is SBS capable + */ +bool policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_hw_emlsr_capable() - Check if HW is EMLSR capable + * @psoc: PSOC object information + * Checks if the HW is EMLSR capable + * + * Return: true if the HW is EMLSR capable + */ +bool policy_mgr_is_hw_emlsr_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_2_freq_always_on_same_mac() - Function to check whether both the + * input frequencies are on same mac in all supported mode/freq range + * @psoc: Pointer to Psoc + * @freq_1: Frequency 1 to check + * @freq_2: Frequency 2 to check + * + * This Function check whether both the input frequency exist in the same mac + * in all supported mode/freq range + * + * Return:True if both the frequency exist on the same mac in all supported + * mode/freq range. + */ +bool policy_mgr_2_freq_always_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, qdf_freq_t freq_2); + +/** + * policy_mgr_are_2_freq_on_same_mac() - Function to check whether both the + * input frequencies are on same mac in current freq range + * @psoc: Pointer to Psoc + * @freq_1: Frequency 1 to check + * @freq_2: Frequency 2 to check + * + * This Function check whether both the input frequency exist in the same mac + * + * Return:True if both the frequency exist on the same mac. + */ +bool +policy_mgr_are_2_freq_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, + qdf_freq_t freq_2); + +/** + * policy_mgr_3_freq_always_on_same_mac() - Function to check whether all three + * input frequencies will always in same mac in all supported mode/freq range + * @psoc: Pointer to Psoc + * @freq_1: Frequency 1 to check + * @freq_2: Frequency 2 to check + * @freq_3: Frequency 3 to check + * + * This Function check whether all three input frequencies exist in the same + * mac in all supported mode/freq range. + * + * Return:True if all three frequency exist on the same mac in all supported + * mode/freq range + */ +bool +policy_mgr_3_freq_always_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, qdf_freq_t freq_2, + qdf_freq_t freq_3); + +/** + * policy_mgr_are_3_freq_on_same_mac() - Function to check whether all three + * input frequencies are in same mac in current freq range + * @psoc: Pointer to Psoc + * @freq_1: Frequency 1 to check + * @freq_2: Frequency 2 to check + * @freq_3: Frequency 3 to check + * + * This Function check whether all three input frequencies exist in the same + * mac. + * + * Return:True if all three frequency exist on the same mac + */ +bool +policy_mgr_are_3_freq_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, qdf_freq_t freq_2, + qdf_freq_t freq_3); + +/** + * policy_mgr_allow_4th_new_freq() - Function to check whether 4th freq can + * be allowed with existing 3 vifs + * @psoc: Pointer to Psoc + * @ch_freq: new channel frequency + * @mode: new device mode + * @ext_flags: extended flags for concurrency check + * + * Return:True if 4th freq can be allowed with existing 3 vifs + */ +#ifdef FEATURE_FOURTH_CONNECTION +bool +policy_mgr_allow_4th_new_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq, + enum policy_mgr_con_mode mode, + uint32_t ext_flags); +#else +static inline bool +policy_mgr_allow_4th_new_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq, + enum policy_mgr_con_mode mode, + uint32_t ext_flags) +{ + return false; +} +#endif + +/** + * policy_mgr_are_sbs_chan() - Function to check whether both the + * input frequency are in SBS frequency range + * + * @psoc: Pointer to Psoc + * @freq_1: Frequency 1 to check + * @freq_2: Frequency 2 to check + * + * This Function check whether both the input frequency exist in the SBS + * frequency range. + * + * Return:True if both the frequency exist on the SBS frequency range. + * + */ +bool +policy_mgr_are_sbs_chan(struct wlan_objmgr_psoc *psoc, qdf_freq_t freq_1, + qdf_freq_t freq_2); + +/** + * policy_mgr_is_current_hwmode_dbs() - Function to check if current HW mode is + * DBS + * + * @psoc: Pointer to Psoc + * + * This Function checks if current HW mode is DBS + * + * Return:True if current HW mode is DBS. + * + */ +bool policy_mgr_is_current_hwmode_dbs(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_current_hwmode_sbs() - Function to check if current HW mode is + * SBS + * + * @psoc: Pointer to Psoc + * + * This Function checks if current HW mode is SBS + * + * Return:True if current HW mode is SBS. + * + */ +bool policy_mgr_is_current_hwmode_sbs(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_curr_hwmode_emlsr() - Function to check if current HW mode is + * eMLSR + * + * @psoc: Pointer to psoc + * + * This Function checks if current HW mode is eMLSR + * + * Return:True if current HW mode is eMLSR. + * + */ +bool policy_mgr_is_curr_hwmode_emlsr(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_dp_hw_dbs_capable() - if hardware is capable of dbs 2x2 + * or 1X1 for Data Path (HW mode) + * @psoc: PSOC object information + * This API is for Data Path to get HW mode support dbs. + * + * Return: true - DBS capable, false - not + */ +bool policy_mgr_is_dp_hw_dbs_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_hw_dbs_2x2_capable() - if hardware is capable of dbs 2x2 + * @psoc: PSOC object information + * This function checks if hw_modes supported are always capable of + * DBS and there is no need for downgrading while entering DBS. + * true: DBS 2x2 can always be supported + * false: hw_modes support DBS 1x1 as well + * Genoa DBS 2x2 + 1x1 will not be included. + * + * Return: true - DBS2x2, false - DBS1x1 + */ +bool policy_mgr_is_hw_dbs_2x2_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_hw_dbs_required_for_band() - Check whether hardware needs DBS + * mode to support the given band + * @psoc: PSOC object information + * @band: band + * + * The function checks whether DBS mode switching required or not to support + * given band based on target capability. + * Any HW which doesn't support given band on PHY A will need DBS HW mode when a + * connection is coming up on that band. + * + * Return: true - DBS mode required for requested band + */ +bool policy_mgr_is_hw_dbs_required_for_band(struct wlan_objmgr_psoc *psoc, + enum hw_mode_mac_band_cap band); + +/* + * policy_mgr_is_2x2_1x1_dbs_capable() - check 2x2+1x1 DBS supported or not + * @psoc: PSOC object data + * + * This routine is called to check 2x2 5G + 1x1 2G (DBS1) or + * 2x2 2G + 1x1 5G (DBS2) support or not. + * Either DBS1 or DBS2 supported + * + * Return: true/false + */ +bool policy_mgr_is_2x2_1x1_dbs_capable(struct wlan_objmgr_psoc *psoc); + +/* + * policy_mgr_is_2x2_5G_1x1_2G_dbs_capable() - check Genoa DBS1 enabled or not + * @psoc: PSOC object data + * + * This routine is called to check support DBS1 or not. + * Notes: DBS1: 2x2 5G + 1x1 2G. + * This function will call policy_mgr_get_hw_mode_idx_from_dbs_hw_list to match + * the HW mode from hw mode list. The parameters will also be matched to + * 2x2 5G +2x2 2G HW mode. But firmware will not report 2x2 5G + 2x2 2G alone + * with 2x2 5G + 1x1 2G at same time. So, it is safe to find DBS1 with + * policy_mgr_get_hw_mode_idx_from_dbs_hw_list. + * + * Return: true/false + */ +bool policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(struct wlan_objmgr_psoc *psoc); + +/* + * policy_mgr_is_2x2_2G_1x1_5G_dbs_capable() - check Genoa DBS2 enabled or not + * @psoc: PSOC object data + * + * This routine is called to check support DBS2 or not. + * Notes: DBS2: 2x2 2G + 1x1 5G + * + * Return: true/false + */ +bool policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_init() - Policy Manager component initialization + * routine + * + * Return - QDF Status + */ +QDF_STATUS policy_mgr_init(void); + +/** + * policy_mgr_deinit() - Policy Manager component + * de-initialization routine + * + * Return - QDF Status + */ +QDF_STATUS policy_mgr_deinit(void); + +/** + * policy_mgr_psoc_enable() - Policy Manager component + * enable routine + * @psoc: PSOC object information + * + * Return - QDF Status + */ +QDF_STATUS policy_mgr_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_psoc_disable() - Policy Manager component + * disable routine + * @psoc: PSOC object information + * + * Return - QDF Status + */ +QDF_STATUS policy_mgr_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_psoc_open() - Policy Manager component + * open routine + * @psoc: PSOC object information + * + * Return - QDF Status + */ +QDF_STATUS policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_psoc_close() - Policy Manager component + * close routine + * @psoc: PSOC object information + * + * Return - QDF Status + */ +QDF_STATUS policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_num_dbs_hw_modes() - Get number of HW mode + * @psoc: PSOC object information + * Fetches the number of DBS HW modes returned by the FW + * + * Return: Negative value on error or returns the number of DBS HW modes + */ +int8_t policy_mgr_get_num_dbs_hw_modes(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_dbs_hw_modes() - Get the DBS HW modes for userspace + * @psoc: PSOC object information + * @one_by_one_dbs: 1x1 DBS capability of HW + * @two_by_two_dbs: 2x2 DBS capability of HW + * + * Provides the DBS HW mode capability such as whether + * 1x1 DBS, 2x2 DBS is supported by the HW or not. + * + * Return: Failure in case of error and 0 on success + * one_by_one_dbs/two_by_two_dbs will be false, + * if they are not supported. + * one_by_one_dbs/two_by_two_dbs will be true, + * if they are supported. + * false values of one_by_one_dbs/two_by_two_dbs, + * indicate DBS is disabled + */ +QDF_STATUS policy_mgr_get_dbs_hw_modes(struct wlan_objmgr_psoc *psoc, + bool *one_by_one_dbs, bool *two_by_two_dbs); + +/** + * policy_mgr_check_sap_restart() - Restart SAP when band/channel change + * @psoc: Pointer to soc + * @vdev_id: Vdev id + * + * Return: None + */ +void +policy_mgr_check_sap_restart(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * policy_mgr_check_sta_ap_concurrent_ch_intf() - Restart SAP in STA-AP case + * @data: Pointer to STA adapter + * + * Restarts the SAP interface in STA-AP concurrency scenario + * + * Return: None + */ +void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data); + +/** + * policy_mgr_get_current_hw_mode() - Get current HW mode params + * @psoc: PSOC object information + * @hw_mode: HW mode parameters + * + * Provides the current HW mode parameters if the HW mode is initialized + * in the driver + * + * Return: Success if the current HW mode params are successfully populated + */ +QDF_STATUS policy_mgr_get_current_hw_mode(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_hw_mode_params *hw_mode); + +/** + * policy_mgr_get_dbs_plus_agile_scan_config() - Get DBS plus agile scan bit + * @psoc: PSOC object information + * Gets the DBS plus agile scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS plus agile scan bit + */ +bool policy_mgr_get_dbs_plus_agile_scan_config(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_single_mac_scan_with_dfs_config() - Get Single + * MAC scan with DFS bit + * @psoc: PSOC object information + * Gets the Single MAC scan with DFS bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the Single MAC scan with DFS bit + */ +bool policy_mgr_get_single_mac_scan_with_dfs_config( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_hw_mode_change_in_progress() - Set value + * corresponding to policy_mgr_hw_mode_change that indicate if + * HW mode change is in progress + * @psoc: PSOC object information + * @value: Indicate if hw mode change is in progress + * + * Set the value corresponding to policy_mgr_hw_mode_change that + * indicated if hw mode change is in progress. + * + * Return: None + */ +void policy_mgr_set_hw_mode_change_in_progress( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_hw_mode_change value); + +/** + * policy_mgr_is_hw_mode_change_in_progress() - Check if HW mode + * change is in progress. + * @psoc: PSOC object information + * + * Returns the corresponding policy_mgr_hw_mode_change value. + * + * Return: policy_mgr_hw_mode_change value. + */ +enum policy_mgr_hw_mode_change policy_mgr_is_hw_mode_change_in_progress( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_hw_mode_change_from_hw_mode_index() - Get + * matching HW mode from index + * @psoc: PSOC object information + * @hw_mode_index: HW mode index + * Returns the corresponding policy_mgr_hw_mode_change HW mode. + * + * Return: policy_mgr_hw_mode_change value. + */ +enum policy_mgr_hw_mode_change policy_mgr_get_hw_mode_change_from_hw_mode_index( + struct wlan_objmgr_psoc *psoc, uint32_t hw_mode_index); + +/** + * policy_mgr_is_scan_simultaneous_capable() - Check if scan + * parallelization is supported or not + * @psoc: PSOC object information + * currently scan parallelization feature support is dependent on DBS but + * it can be independent in future. + * + * Return: True if master DBS control is enabled + */ +bool policy_mgr_is_scan_simultaneous_capable(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_set_user_cfg() - Function to set user cfg variables + * required by policy manager component + * @psoc: PSOC object information + * @user_cfg: User config valiables structure pointer + * + * This function sets the user cfg variables required by policy + * manager + * + * Return: SUCCESS or FAILURE + * + */ +QDF_STATUS policy_mgr_set_user_cfg(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_user_cfg *user_cfg); + +/** + * policy_mgr_init_dbs_config() - Function to initialize DBS + * config in policy manager component + * @psoc: PSOC object information + * @scan_config: DBS scan config + * @fw_config: DBS FW config + * + * This function sets the DBS configurations required by policy + * manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_init_dbs_config(struct wlan_objmgr_psoc *psoc, + uint32_t scan_config, uint32_t fw_config); + +/** + * policy_mgr_init_sbs_fw_config() - Function to initialize SBS + * fw mode config in policy manager component + * @psoc: PSOC object information + * @fw_config: FW config + * + * This function initialize SBS fw mode config in policy manager component + * + * Return: void + * + */ +void policy_mgr_init_sbs_fw_config(struct wlan_objmgr_psoc *psoc, + uint32_t fw_config); + +/** + * policy_mgr_update_dbs_scan_config() - Function to update + * DBS scan config in policy manager component + * @psoc: PSOC object information + * + * This function updates the DBS scan configurations required by + * policy manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_update_dbs_scan_config(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_update_dbs_fw_config() - Function to update DBS FW + * config in policy manager component + * @psoc: PSOC object information + * + * This function updates the DBS FW configurations required by + * policy manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_update_dbs_fw_config(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_update_dbs_req_config() - Function to update DBS + * request config in policy manager component + * @psoc: PSOC object information + * @scan_config: DBS scan config + * @fw_mode_config: DBS FW config + * + * This function updates DBS request configurations required by + * policy manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_update_dbs_req_config(struct wlan_objmgr_psoc *psoc, + uint32_t scan_config, uint32_t fw_mode_config); + +/** + * policy_mgr_dump_dbs_hw_mode() - Function to dump DBS config + * @psoc: PSOC object information + * + * This function dumps the DBS configurations + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_dump_dbs_hw_mode(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_init_dbs_hw_mode() - Function to initialize DBS HW + * modes in policy manager component + * @psoc: PSOC object information + * @num_dbs_hw_modes: Number of HW modes + * @ev_wlan_dbs_hw_mode_list: HW list + * + * This function to initialize the DBS HW modes in policy + * manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_init_dbs_hw_mode(struct wlan_objmgr_psoc *psoc, + uint32_t num_dbs_hw_modes, + uint32_t *ev_wlan_dbs_hw_mode_list); + +QDF_STATUS policy_mgr_update_sbs_freq(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl); + +/** + * policy_mgr_get_sbs_cut_off_freq() - Function to get SBS 5g cut off freq + * + * @psoc: PSOC object information + * + * This function to get sbs cut off freq + * + * Return: cut of freq + * + */ +qdf_freq_t policy_mgr_get_sbs_cut_off_freq(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_update_hw_mode_list() - Function to initialize DBS + * HW modes in policy manager component + * @psoc: PSOC object information + * @tgt_hdl: Target psoc information + * + * This function to initialize the DBS HW modes in policy + * manager + * + * Return: SUCCESS or FAILURE + * + */ +QDF_STATUS policy_mgr_update_hw_mode_list(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl); + +/** + * policy_mgr_update_hw_mode_index() - Function to update + * current HW mode in policy manager component + * @psoc: PSOC object information + * @new_hw_mode_index: index to new HW mode + * + * This function to update the current HW mode in policy manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_update_hw_mode_index(struct wlan_objmgr_psoc *psoc, + uint32_t new_hw_mode_index); + +/** + * policy_mgr_update_old_hw_mode_index() - Function to update + * old HW mode in policy manager component + * @psoc: PSOC object information + * @old_hw_mode_index: index to old HW mode + * + * This function to update the old HW mode in policy manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_update_old_hw_mode_index(struct wlan_objmgr_psoc *psoc, + uint32_t old_hw_mode_index); + +/** + * policy_mgr_update_new_hw_mode_index() - Function to update + * new HW mode in policy manager component + * @psoc: PSOC object information + * @new_hw_mode_index: index to new HW mode + * + * This function to update the new HW mode in policy manager + * + * Return: SUCCESS or FAILURE + * + */ +void policy_mgr_update_new_hw_mode_index(struct wlan_objmgr_psoc *psoc, + uint32_t new_hw_mode_index); + +/** + * policy_mgr_is_chan_ok_for_dnbs() - Function to check if a channel + * is OK for "Do Not Break Stream" + * @psoc: PSOC object information + * @ch_freq: Channel frequency to check. + * @ok: Pointer to flag in which status will be stored + * This function checks if a channel is OK for + * "Do Not Break Stream" + * Return: SUCCESS or FAILURE + */ +QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, bool *ok); + +/** + * policy_mgr_get_hw_dbs_nss() - Computes DBS NSS + * @psoc: PSOC object information + * @nss_dbs: NSS info of both MAC0 and MAC1 + * This function computes NSS info of both MAC0 and MAC1 + * + * Return: uint32_t value signifies supported RF chains + */ +uint32_t policy_mgr_get_hw_dbs_nss(struct wlan_objmgr_psoc *psoc, + struct dbs_nss *nss_dbs); + +/** + * policy_mgr_is_dnsc_set - Check if user has set + * "Do_Not_Switch_Channel" for the vdev passed + * @vdev: vdev pointer + * + * Get "Do_Not_Switch_Channel" setting for the vdev passed. + * + * Return: true for success, else false + */ +bool policy_mgr_is_dnsc_set(struct wlan_objmgr_vdev *vdev); + +/** + * policy_mgr_get_updated_scan_and_fw_mode_config() - Function + * to get latest scan & fw config for DBS + * @psoc: PSOC object information + * @scan_config: DBS related scan config + * @fw_mode_config: DBS related FW config + * @dual_mac_disable_ini: DBS related ini config + * @channel_select_logic_conc: + * + * This function returns the latest DBS configuration for + * connection & scan, sent to FW + * + * Return: SUCCESS or FAILURE + */ +QDF_STATUS policy_mgr_get_updated_scan_and_fw_mode_config( + struct wlan_objmgr_psoc *psoc, uint32_t *scan_config, + uint32_t *fw_mode_config, uint32_t dual_mac_disable_ini, + uint32_t channel_select_logic_conc); + +/** + * policy_mgr_is_safe_channel - Check if the channel is in LTE + * coex channel avoidance list + * @psoc: PSOC object information + * @ch_freq: channel frequency to be checked + * + * Check if the channel is in LTE coex channel avoidance list. + * + * Return: true for success, else false + */ +bool policy_mgr_is_safe_channel(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq); + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +/** + * policy_mgr_restrict_sap_on_unsafe_chan() - Check if need check unsafe + * channel if SAP start on fixed channel. + * @psoc: PSOC object information + * + * Return: true for success, else false + */ +bool policy_mgr_restrict_sap_on_unsafe_chan(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +policy_mgr_restrict_sap_on_unsafe_chan(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * policy_mgr_is_sap_freq_allowed - Check if the channel is allowed for sap + * @psoc: PSOC object information + * @opmode: Current op_mode, helps to check whether it's P2P_GO/SAP + * @sap_freq: channel frequency to be checked + * + * Check the factors as below to decide whether the channel is allowed or not: + * If the channel is in LTE coex channel avoidance list; + * If it's STA+SAP SCC; + * If STA+SAP SCC on LTE coex channel is allowed. + * + * Return: true for allowed, else false + */ +bool policy_mgr_is_sap_freq_allowed(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE opmode, + uint32_t sap_freq); + +/** + * policy_mgr_get_ch_width() - Convert hw_mode_bandwidth to phy_ch_width + * @bw: Hardware mode band width used by WMI + * + * Return: phy_ch_width + */ +enum phy_ch_width policy_mgr_get_ch_width(enum hw_mode_bandwidth bw); + +/** + * policy_mgr_is_force_scc() - checks if SCC needs to be + * mandated + * @psoc: PSOC object information + * + * This function checks if SCC needs to be mandated or not + * + * Return: True if SCC to be mandated, false otherwise + */ +bool policy_mgr_is_force_scc(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_go_scc_enforced() - Get GO force SCC enabled or not + * @psoc: psoc object + * + * This function checks if force SCC logic should be used on GO interface. + * + * Return: True if allow GO force SCC + */ +bool policy_mgr_go_scc_enforced(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_valid_sap_conc_channel_check() - Check and update + * the SAP channel in case of STA+SAP concurrency + * @psoc: PSOC object information + * @con_ch_freq: pointer to the chan freq on which sap will come up + * @sap_ch_freq: initial channel frequency for SAP + * @sap_vdev_id: sap vdev id. + * @ch_params: sap channel parameters + * + * This function checks & updates the channel SAP to come up on in + * case of STA+SAP concurrency + * + * Return: Success if SAP can come up on a channel + */ +QDF_STATUS policy_mgr_valid_sap_conc_channel_check( + struct wlan_objmgr_psoc *psoc, uint32_t *con_ch_freq, + uint32_t sap_ch_freq, uint8_t sap_vdev_id, + struct ch_params *ch_params); + +/** + * policy_mgr_get_alternate_channel_for_sap() - Get an alternate + * channel to move the SAP to + * @psoc: PSOC object information + * @sap_vdev_id: sap vdev id. + * @sap_ch_freq: sap channel frequency. + * @pref_band: Preferred band on channel is required + * + * This function returns an alternate channel for SAP to move to + * + * Return: The new channel for SAP + */ +uint32_t policy_mgr_get_alternate_channel_for_sap( + struct wlan_objmgr_psoc *psoc, uint8_t sap_vdev_id, + uint32_t sap_ch_freq, + enum reg_wifi_band pref_band); + +/** + * policy_mgr_con_mode_by_vdev_id() - Get policy mgr con mode from vdev id + * @psoc: psoc object + * @vdev_id: vdev id + * + * return: enum policy_mgr_con_mode for the vdev id + */ +enum policy_mgr_con_mode +policy_mgr_con_mode_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_disallow_mcc() - Check for mcc + * + * @psoc: PSOC object information + * @ch_freq: channel frequency on which new connection is coming up + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * causing MCC + * + * Return: True if it is causing MCC + */ +bool policy_mgr_disallow_mcc(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq); + +/** + * policy_mgr_mode_specific_get_channel() - Get channel for a + * connection type + * @psoc: PSOC object information + * @mode: Connection type + * + * Get channel frequency for a connection type + * + * Return: channel frequency + */ +uint32_t policy_mgr_mode_specific_get_channel(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode); + +/** + * policy_mgr_add_sap_mandatory_chan() - Add chan to SAP mandatory channel + * list + * @psoc: Pointer to soc + * @ch_freq: Channel frequency to be added + * + * Add chan to SAP mandatory channel list + * + * Return: None + */ +void policy_mgr_add_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq); + +/** + * policy_mgr_get_sap_mandatory_chan_list_len() - Return the SAP mandatory + * channel list len + * @psoc: Pointer to soc + * + * Get the SAP mandatory channel list len + * + * Return: Channel list length + */ +uint32_t policy_mgr_get_sap_mandatory_chan_list_len( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_init_sap_mandatory_chan() - Init 2.4G 5G 6G SAP mandatory channel + * list + * @psoc: Pointer to soc + * @org_ch_freq: sap initial channel frequency MHz + * + * Initialize the 2.4G 5G 6G SAP mandatory channels + * + * Return: None + */ +void policy_mgr_init_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc, + uint32_t org_ch_freq); + +/** + * policy_mgr_remove_sap_mandatory_chan() - Remove channel from SAP mandatory + * channel list + * @psoc: Pointer to soc + * @ch_freq: channel frequency to be removed from mandatory list + * + * Remove channel from SAP mandatory channel list + * + * Return: None + */ +void policy_mgr_remove_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq); + +/* + * policy_set_cur_conc_system_pref - set current conc_system_pref + * @psoc: soc pointer + * + * Set the current concurrency system preference. + * + * Return: None + */ +void policy_mgr_set_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc, + uint8_t conc_system_pref); +/** + * policy_mgr_get_cur_conc_system_pref - Get current conc_system_pref + * @psoc: soc pointer + * + * Get the current concurrent system preference. + * + * Return: conc_system_pref + */ +uint8_t policy_mgr_get_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc); +/** + * policy_mgr_check_and_stop_opportunistic_timer - Get current + * state of opportunistic timer, if running, stop it and take + * action + * @psoc: soc pointer + * @id: Session/vdev id + * + * Get the current state of opportunistic timer, if it is + * running, stop it and take action. + * + * Return: None + */ +void policy_mgr_check_and_stop_opportunistic_timer( + struct wlan_objmgr_psoc *psoc, uint8_t id); + +/** + * policy_mgr_set_weight_of_disabled_inactive_channels_to_zero() - set weight + * of disabled and inactive channels to 0 + * @psoc: pointer to soc + * @pcl: preferred channel freq list + * @len: length of preferred channel list + * @weight_list: preferred channel weight list + * @weight_len: length of weight list + * This function set the weight of disabled and inactive channels to 0 + * + * Return: None + */ +void policy_mgr_set_weight_of_disabled_inactive_channels_to_zero( + struct wlan_objmgr_psoc *psoc, uint32_t *pcl, + uint32_t *len, uint8_t *weight_list, uint32_t weight_len); +/** + * policy_mgr_is_sap_allowed_on_dfs_freq() - check if sap allowed on dfs freq + * @pdev: id of objmgr pdev + * @vdev_id: vdev id + * @ch_freq: channel freq + * This function is used to check if sta_sap_scc_on_dfs_chan ini is set, + * DFS master capability is assumed disabled in the driver. + * + * Return: true if sap is allowed on dfs freq, + * otherwise false + */ +bool policy_mgr_is_sap_allowed_on_dfs_freq(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, qdf_freq_t ch_freq); +/** + * policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan() - check if sta+sap scc + * allowed on dfs chan + * @psoc: pointer to soc + * This function is used to check if sta+sap scc allowed on dfs channel + * + * Return: true if sta+sap scc is allowed on dfs channel, otherwise false + */ +bool policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_multi_sap_allowed_on_same_band() - check if multi sap allowed + * on same band + * @pdev: id of objmgr pdev + * @mode: operating mode of interface to be checked + * @ch_freq: channel freq + * This function is used to check if multi sap can be started on the same band + * + * Return: true if multi sap is allowed on same band, otherwise false + */ +bool policy_mgr_is_multi_sap_allowed_on_same_band( + struct wlan_objmgr_pdev *pdev, + enum policy_mgr_con_mode mode, + qdf_freq_t ch_freq); + +/** + * policy_mgr_is_special_mode_active_5g() - check if given mode active in 5g + * @psoc: pointer to soc + * @mode: operating mode of interface to be checked + * + * Return: true if given mode is active in 5g + */ +bool policy_mgr_is_special_mode_active_5g(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode); + +/** + * policy_mgr_is_sta_connected_2g() - check if sta connected in 2g + * @psoc: pointer to soc + * + * Return: true if sta is connected in 2g else false + */ +bool policy_mgr_is_sta_connected_2g(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_connected_sta_5g() - check if sta connected in 5 GHz + * @psoc: pointer to soc + * @freq: Pointer to the frequency on which sta is connected + * + * Return: true if sta is connected in 5 GHz else false + */ +bool policy_mgr_is_connected_sta_5g(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *freq); + +/** + * policy_mgr_scan_trim_5g_chnls_for_dfs_ap() - check if sta scan should skip + * 5g channel when dfs ap is present. + * + * @psoc: pointer to soc + * @freq: DFS freq of concurrent SAP/GO + * + * Return: true if sta scan 5g chan should be skipped + */ +bool policy_mgr_scan_trim_5g_chnls_for_dfs_ap(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *freq); + +/** + * policy_mgr_scan_trim_chnls_for_connected_ap() - check if sta scan + * should skip 5g or 2.4g channel when AP/GO connected by clients. + * STA + AP 5G (connected) + AP 2.4G skip 5G scan + * STA + AP 5G (connected) skip 5G scan + * STA + AP 2.4G (connected && 2.4G only) skip 2.4G scan + * + * @pdev: pointer to pdev + * + * Return: trim_channel_list + */ +uint16_t +policy_mgr_scan_trim_chnls_for_connected_ap(struct wlan_objmgr_pdev *pdev); + +/** + * policy_mgr_is_hwmode_set_for_given_chnl() - to check for given channel + * if the hw mode is properly set. + * @psoc: pointer to psoc + * @ch_freq: given channel frequency + * + * If HW mode is properly set for given channel then it returns true else + * it returns false. + * For example, when 2x2 DBS is supported and if the first connection is + * coming up on 2G band then driver expects DBS HW mode to be set first + * before the connection can be established. Driver can call this API to + * find-out if HW mode is set properly. + * + * Return: true if HW mode is set properly else false + */ +bool policy_mgr_is_hwmode_set_for_given_chnl(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq); + +/** + * policy_mgr_get_connection_info() - Get info of all active connections + * @psoc: pointer to soc + * @info: Pointer to connection info + * + * Return: Connection count + */ +uint32_t policy_mgr_get_connection_info(struct wlan_objmgr_psoc *psoc, + struct connection_info *info); +/** + * policy_mgr_register_mode_change_cb() - Register mode change callback with + * policy manager + * @psoc: pointer to soc + * @mode_change_cb: HDD callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_register_mode_change_cb(struct wlan_objmgr_psoc *psoc, + send_mode_change_event_cb mode_change_cb); +/** + * policy_mgr_deregister_mode_change_cb() - Deregister mode change callback with + * policy manager + * @psoc: pointer to soc + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_deregister_mode_change_cb(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_allow_sap_go_concurrency() - check whether SAP/GO concurrency is + * allowed. + * @psoc: pointer to soc + * @mode: operating mode of interface to be checked + * @ch_freq: new operating channel of the interface to be checked + * @vdev_id: vdev id of the connection to be checked, 0xff for new connection + * + * Checks whether new channel SAP/GO can co-exist with the channel of existing + * SAP/GO connection. This API mainly used for two purposes: + * + * 1) When new GO/SAP session is coming up and needs to check if this session's + * channel can co-exist with existing existing GO/SAP sessions. For example, + * when single radio platform comes, MCC for SAP/GO+SAP/GO is not supported, in + * such case this API should prevent bringing the second connection. + * + * 2) There is already existing SAP+GO combination but due to upper layer + * notifying LTE-COEX event or sending command to move one of the connections + * to different channel. In such cases before moving existing connection to new + * channel, check if new channel can co-exist with the other existing + * connection. For example, one SAP1 is on channel-6 and second SAP2 is on + * channel-36 and lets say they are doing DBS, and lets say upper layer sends + * LTE-COEX to move SAP1 from channel-6 to channel-149. In this case, SAP1 and + * SAP2 will end up doing MCC which may not be desirable result. such cases + * will be prevented with this API. + * + * Return: true or false + */ +bool policy_mgr_allow_sap_go_concurrency(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + uint32_t vdev_id); + +/** + * policy_mgr_dual_beacon_on_single_mac_scc_capable() - get capability that + * whether support dual beacon on same channel on single MAC + * @psoc: pointer to soc + * + * Return: bool: capable + */ +bool policy_mgr_dual_beacon_on_single_mac_scc_capable( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_dual_beacon_on_single_mac_mcc_capable() - get capability that + * whether support dual beacon on different channel on single MAC + * @psoc: pointer to soc + * + * Return: bool: capable + */ +bool policy_mgr_dual_beacon_on_single_mac_mcc_capable( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_sta_sap_scc_on_lte_coex_chan() - get capability that + * whether support sta sap scc on lte coex chan + * @psoc: pointer to soc + * + * Return: bool: capable + */ +bool policy_mgr_sta_sap_scc_on_lte_coex_chan( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_user_config_sap_freq() - Get the user configured channel + * + * @psoc: pointer to psoc + * @vdev_id: vdev id + * + * Return: user configured frequency + */ +qdf_freq_t policy_mgr_get_user_config_sap_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_nan_sap_post_enable_conc_check() - Do concurrency operations + * post nan/sap enable + * @psoc: pointer to psoc + * + * Return: QDF_STATUS + **/ +QDF_STATUS +policy_mgr_nan_sap_post_enable_conc_check(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_nan_sap_post_disable_conc_check() - Do concurrency related + * operation post nan/sap disable + * @psoc: pointer to psoc + * + * Return: void + **/ +void policy_mgr_nan_sap_post_disable_conc_check(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_sap_restart_required_after_sta_disconnect() - is sap restart + * required + * after sta disconnection + * @psoc: psoc object data + * @sap_vdev_id: sap vdev id + * @intf_ch_freq: sap channel frequency + * @is_acs_mode: Indicates whether SAP is started in ACS mode or fixed channel + * + * Check if SAP should be moved to a non dfs channel after STA disconnection. + * This API applicable only for STA+SAP SCC and ini 'sta_sap_scc_on_dfs_chan' + * or 'sta_sap_scc_on_lte_coex_chan' is enabled. + * + * Return: true if sap restart is required, otherwise false + */ +bool policy_mgr_is_sap_restart_required_after_sta_disconnect( + struct wlan_objmgr_psoc *psoc, uint32_t sap_vdev_id, + uint32_t *intf_ch_freq, bool is_acs_mode); + +/** + * policy_mgr_is_sta_sap_scc() - check whether SAP is doing SCC with + * STA + * @psoc: pointer to psoc + * @sap_ch_freq: operating channel frequency of SAP interface + * This function checks whether SAP is doing SCC with STA + * + * Return: true or false + */ +bool policy_mgr_is_sta_sap_scc(struct wlan_objmgr_psoc *psoc, + uint32_t sap_ch_freq); + +/** + * policy_mgr_nan_sap_scc_on_unsafe_ch_chk() - check whether SAP is doing SCC + * with NAN + * @psoc: pointer to psoc + * @sap_freq: operating channel frequency of SAP interface + * + * Return: true or false + */ +bool policy_mgr_nan_sap_scc_on_unsafe_ch_chk(struct wlan_objmgr_psoc *psoc, + uint32_t sap_freq); + +/** + * policy_mgr_get_hw_mode_from_idx() - Get HW mode based on index + * @psoc: psoc object + * @idx: HW mode id + * @hw_mode: HW mode params + * + * Fetches the HW mode parameters + * + * Return: Success if hw mode is obtained and the hw mode params + */ +QDF_STATUS policy_mgr_get_hw_mode_from_idx( + struct wlan_objmgr_psoc *psoc, + uint32_t idx, + struct policy_mgr_hw_mode_params *hw_mode); + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +/** + * policy_mgr_is_6ghz_conc_mode_supported() - Check connection mode supported + * on 6ghz or not + * @psoc: Pointer to soc + * @mode: new connection mode + * + * Current PORed 6ghz connection modes are STA, SAP, P2P. + * + * Return: true if supports else false. + */ +bool policy_mgr_is_6ghz_conc_mode_supported( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode); + +/** + * policy_mgr_init_ap_6ghz_capable - Init 6Ghz capable flags + * @psoc: PSOC object information + * @vdev_id: vdev id + * @ap_6ghz_capable: vdev 6ghz capable flag + * + * Init 6Ghz capable flags for active connection in policy mgr conn table + * + * Return: void + */ +void policy_mgr_init_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum conn_6ghz_flag ap_6ghz_capable); + +/** + * policy_mgr_set_ap_6ghz_capable - Set 6Ghz capable flags to connection list + * @psoc: PSOC object information + * @vdev_id: vdev id + * @set: set or clear + * @ap_6ghz_capable: vdev 6ghz capable flag + * + * Set/Clear 6Ghz capable flags for active connection in policy mgr conn table + * + * Return: void + */ +void policy_mgr_set_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool set, + enum conn_6ghz_flag ap_6ghz_capable); + +/** + * policy_mgr_get_ap_6ghz_capable - Get 6Ghz capable info for a vdev + * @psoc: PSOC object information + * @vdev_id: vdev id + * @conn_flag: output conntion flags + * + * Get 6Ghz capable flag for ap vdev (SAP). When SAP on 5G, for same reason + * the AP needs to be moved to 6G and this API will be called to check whether + * AP is 6Ghz capable or not. + * AP is allowed on 6G band only when all of below statements are true: + * a. SAP config includes WPA3 security - SAE,OWE,SuiteB. + * b. SAP is configured by ACS range which includes any 6G channel or + * configured by 6G Fixed channel. + * c. SAP has no legacy clients (client doesn't support 6G band). + * legacy client (non 6ghz capable): association request frame has no + * 6G band global operating Class. + * + * Return: true if AP is 6ghz capable + */ +bool policy_mgr_get_ap_6ghz_capable( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, uint32_t *conn_flag); +#else +static inline bool policy_mgr_is_6ghz_conc_mode_supported( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode) +{ + return false; +} + +static inline void policy_mgr_init_ap_6ghz_capable( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum conn_6ghz_flag ap_6ghz_capable) +{} + +static inline +void policy_mgr_set_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool set, + enum conn_6ghz_flag ap_6ghz_capable) +{} + +static inline bool policy_mgr_get_ap_6ghz_capable( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, uint32_t *conn_flag) +{ + return false; +} + +#endif + +/** + * policy_mgr_update_nan_vdev_mac_info() - Update the NAN vdev id and MAC id in + * policy manager + * @psoc: psoc object + * @nan_vdev_id: NAN Discovery pseudo vdev id + * @mac_id: NAN Discovery MAC ID + * + * Stores NAN Discovery related vdev and MAC id in policy manager + * + * Return: QDF Success + */ +QDF_STATUS policy_mgr_update_nan_vdev_mac_info(struct wlan_objmgr_psoc *psoc, + uint8_t nan_vdev_id, + uint8_t mac_id); + +/** + * policy_mgr_get_mode_specific_conn_info() - Get active mode specific + * channel and vdev id + * @psoc: PSOC object information + * @ch_freq_list: Mode specific channel freq list + * @vdev_id: Mode specific vdev id (list) + * @mode: Connection Mode + * + * Get active mode specific channel and vdev id + * + * Return: number of connection found as per given mode + */ +uint32_t policy_mgr_get_mode_specific_conn_info(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, + uint8_t *vdev_id, + enum policy_mgr_con_mode mode); + +/* + * policy_mgr_get_ml_and_non_ml_sta_count() - get ML and non ML STA count + * also fills the freq and non ML/ML list + * @psoc: Objmgr psoc + * @num_ml: num ML as output + * @ml_idx: ML vdev index as output + * @num_non_ml: num non ML as output + * @non_ml_idx: non ML vdev index as output + * @freq_list: freq list of each sta vdev + * @vdev_id_list: vdev id list + * + * Return: void + */ +void policy_mgr_get_ml_and_non_ml_sta_count(struct wlan_objmgr_psoc *psoc, + uint8_t *num_ml, uint8_t *ml_idx, + uint8_t *num_non_ml, + uint8_t *non_ml_idx, + qdf_freq_t *freq_list, + uint8_t *vdev_id_list); + +/** + * policy_mgr_is_sap_go_on_2g() - check if sap/go is on 2g + * @psoc: PSOC object information + * + * Return: true or false + */ +bool policy_mgr_is_sap_go_on_2g(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_dump_channel_list() - Print channel list + * @len: Length of pcl list + * @pcl_channels: pcl channels list + * @pcl_weight: pcl weight list + * + * + * Return: True or false + */ +bool policy_mgr_dump_channel_list(uint32_t len, + uint32_t *pcl_channels, + uint8_t *pcl_weight); + +/** + * policy_mgr_filter_passive_ch() -filter out passive channels from the list + * @pdev: Pointer to pdev + * @ch_freq_list: pointer to channel frequency list + * @ch_cnt: number of channels in list + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_filter_passive_ch(struct wlan_objmgr_pdev *pdev, + uint32_t *ch_freq_list, + uint32_t *ch_cnt); + +/** + * policy_mgr_is_restart_sap_required() - check whether sap need restart + * @psoc: psoc pointer + * @vdev_id: vdev id + * @freq: sap current freq + * @scc_mode: mcc to scc switch mode + * + * If there is no STA/P2P CLI on same MAC of SAP/P2P GO, + * SAP/P2P Go needn't switch channel to force scc. + * + * Return: True or false + */ +bool policy_mgr_is_restart_sap_required(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + qdf_freq_t freq, + tQDF_MCC_TO_SCC_SWITCH_MODE scc_mode); + +/** + * policy_mgr_get_roam_enabled_sta_session_id() - get the session id of the sta + * on which roaming is enabled. + * @psoc: pointer to psoc object + * @vdev_id: vdev id of the requestor + * + * The function checks if any sta(other than the provided vdev_id) is present + * and has roaming enabled and return the session id of the sta with roaming + * enabled else if roaming is not enabled on any STA return + * WLAN_UMAC_VDEV_ID_MAX. + * + * Return: session id of STA on which roaming is enabled + */ +uint8_t policy_mgr_get_roam_enabled_sta_session_id( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_is_sta_mon_concurrency() - check if MONITOR and STA concurrency + * is UP. + * @psoc: pointer to psoc object + * + * Return: True - if STA and monitor concurrency is there, else False + * + */ +bool policy_mgr_is_sta_mon_concurrency(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_check_mon_concurrency() - Checks if monitor intf can be added. + * @psoc: pointer to psoc object + * + * Return: QDF_STATUS_SUCCESS if allowed, else send failure + * + */ +QDF_STATUS policy_mgr_check_mon_concurrency(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_hw_dbs_max_bw() - Computes DBS BW + * @psoc: PSOC object information + * @bw_dbs: BW info of both MAC0 and MAC1 + * This function computes BW info of both MAC0 and MAC1 + * + * Return: void + */ +void policy_mgr_get_hw_dbs_max_bw(struct wlan_objmgr_psoc *psoc, + struct dbs_bw *bw_dbs); + +/** + * policy_mgr_get_radio_combinations() - Query the supported radio combinations + * @psoc: soc object + * @comb: combination buffer + * @comb_max: max combination number can be saved to comb buffer + * @comb_num: returned combination number + * + * This function returns the radio combination information supported by target. + * + * Return: QDF_STATUS_SUCCESS if query successfully + */ +QDF_STATUS policy_mgr_get_radio_combinations(struct wlan_objmgr_psoc *psoc, + struct radio_combination *comb, + uint32_t comb_max, + uint32_t *comb_num); + +/** + * policy_mgr_is_mlo_sta_disconnected() - Check all STA in mlo are disconnected + * @psoc: PSOC object information + * @vdev_id: vdev id for sta + * + * if any link is associated the API will return false. + * + * Return: True if all sta links are disconnected + */ +bool policy_mgr_is_mlo_sta_disconnected(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * policy_mgr_is_ml_sta_links_in_mcc() - Check ML links are in MCC or not + * @psoc: psoc ctx + * @ml_freq_lst: ML STA freq list + * @ml_vdev_lst: ML STA vdev id list + * @ml_linkid_lst: ML STA link id list + * @num_ml_sta: Number of total ML STA links + * @affected_linkid_bitmap: link id bitmap which home channels are in MCC + * with each other + * + * Return: true if ML link in MCC else false + */ +bool +policy_mgr_is_ml_sta_links_in_mcc(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *ml_freq_lst, + uint8_t *ml_vdev_lst, + uint8_t *ml_linkid_lst, + uint8_t num_ml_sta, + uint32_t *affected_linkid_bitmap); + +/** + * policy_mgr_is_ml_links_in_mcc_allowed() - Check ML links are in MCC or not + * @psoc: psoc ctx + * @vdev: Pointer to vdev object + * @ml_sta_vdev_lst: ML STA vdev id list + * @num_ml_sta: Number of total ML STA links + * + * Return: QDF_STATUS_SUCCESS if ML link in MCC is allowed + */ +QDF_STATUS +policy_mgr_is_ml_links_in_mcc_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *ml_sta_vdev_lst, + uint8_t *num_ml_sta); + +/** + * policy_mgr_is_vdev_high_tput_or_low_latency() - Check vdev has + * high througput or low latency flag + * @psoc: PSOC object information + * @vdev_id: vdev id + * + * Return: true if vdev has high throughput or low latency flag + */ +bool +policy_mgr_is_vdev_high_tput_or_low_latency(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_check_2ghz_only_sap_affected_link() - Check force inactive + * link is needed for 2.4 GHz only sap + * @psoc: PSOC object information + * @sap_vdev_id: sap vdev id + * @sap_ch_freq: sap channel frequency + * @ml_ch_freq_num: ML STA link num + * @ml_freq_lst: ML STA link frequency list + * + * Return: true if 2.4 GHz only sap present and need to force inactive + * ML link + */ +bool +policy_mgr_check_2ghz_only_sap_affected_link( + struct wlan_objmgr_psoc *psoc, + uint8_t sap_vdev_id, + qdf_freq_t sap_ch_freq, + uint8_t ml_ch_freq_num, + qdf_freq_t *ml_freq_lst); + +/** + * policy_mgr_vdev_is_force_inactive() - Check force inactive or not + * for the vdev id + * @psoc: PSOC object information + * @vdev_id: vdev id + * + * Return: true if the vdev is in force inactive + */ +bool policy_mgr_vdev_is_force_inactive(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_get_legacy_conn_info() - Get legacy connection info + * @psoc: PSOC object information + * @vdev_lst: vdev id list + * @freq_lst: channel frequency list + * @mode_lst: vdev mode list + * @lst_sz: array size of above parameters + * + * This API will return the legacy STA/SAP/P2P connection info. + * If a connection want to avoid MCC with ML STA, that connection + * will be put in head of array list. And in 3 Port concurrency + * case (ML STA + 2 legacy Connections), usually we can only meet + * the high priority connection's MCC avoidance, so this API will + * return sorted lists based on the priority. Right now we don't + * clear requirement on which legacy interface has higher priority, + * here we follow this order: STA, SAP, P2P. + * + * Return: number of legacy connection count + */ +uint8_t +policy_mgr_get_legacy_conn_info(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_lst, + qdf_freq_t *freq_lst, + enum policy_mgr_con_mode *mode_lst, + uint8_t lst_sz); + +/* + * policy_mgr_get_ml_sta_info_psoc() - Get number of ML STA vdev ids and + * freq list + * @pm_ctx: pm_ctx ctx + * @num_ml_sta: Return number of ML STA present + * @num_disabled_ml_sta: Return number of disabled ML STA links + * @ml_vdev_lst: Return ML STA vdev id list + * @ml_freq_lst: Return ML STA freq list + * @num_non_ml: Return number of non-ML STA present + * @non_ml_vdev_lst: Return non-ML STA vdev id list + * @non_ml_freq_lst: Return non-ML STA freq list + * + * Return: void + */ +void +policy_mgr_get_ml_sta_info_psoc(struct wlan_objmgr_psoc *psoc, + uint8_t *num_ml_sta, + uint8_t *num_disabled_ml_sta, + uint8_t *ml_vdev_lst, + qdf_freq_t *ml_freq_lst, + uint8_t *num_non_ml, + uint8_t *non_ml_vdev_lst, + qdf_freq_t *non_ml_freq_lst); + +/** + * policy_mgr_handle_link_removal_on_vdev() - Handle AP link removal for + * MLO STA + * @vdev: objmgr vdev + * + * Handle link removal for STA vdev: + * Send force link command to target if MLO STA link number > 1. + * Select other inactive link to active if possible. + * + * Return: void + */ +void policy_mgr_handle_link_removal_on_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * policy_mgr_handle_link_removal_on_standby() - Handle AP link removal for + * MLO STA standby links + * @vdev: objmgr vdev + * @reconfig_info: link reconfig info + * + * Handle link removal for ML STA standby links: + * Send force link command to target with link removal reason code + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_handle_link_removal_on_standby(struct wlan_objmgr_vdev *vdev, + struct ml_rv_info *reconfig_info); + +/** + * policy_mgr_is_mlo_sap_concurrency_allowed() - Check for mlo sap allowed + * concurrency combination + * @psoc: PSOC object information + * @is_new_vdev_mlo: Is new vdev a mlo device or not + * @new_vdev_id: new vdev id which need concurrency check + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not. Currently no concurrency support for mlo sap + * + * Return: True if concurrency is supported, otherwise false. + */ +bool policy_mgr_is_mlo_sap_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + bool is_new_vdev_mlo, + uint8_t new_vdev_id); + +/** + * policy_mgr_get_conc_ext_flags() - get extended flags for concurrency check + * @vdev: pointer to vdev on which new connection is coming up + * @force_mlo: true means it's a MLO connection, false means uncertain + * + * In some scenario the flag WLAN_VDEV_FEXT2_MLO may not set for vdev when + * checking concurrency, then caller can set force_mlo accordingly to get + * proper extended flags. + * + * Return: extended flags for concurrency check + */ +uint32_t +policy_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev, bool force_mlo); + +/** + * policy_mgr_is_non_ml_sta_present() - Check whether Non-ML STA is present + * @psoc: PSOC object information + * + * Return: True if non-ML STA is present, otherwise false. + */ +bool policy_mgr_is_non_ml_sta_present(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_mlo_sta_present() - Check whether MLO STA is present + * @psoc: PSOC object information + * + * Return: True if MLO STA is present, otherwise false. + */ +bool policy_mgr_is_mlo_sta_present(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_is_mlo_in_mode_sbs() - Check whether MLO present is SBS (with both + * links on 5/6 ghz band) + * @psoc: PSOC object information + * @mode: mlo mode to check + * @mlo_vdev_lst: Pointer to mlo vdev list, this function will fill this with + * list of mlo vdev + * @num_mlo: Pointer to number of mlo link, this function will fill this with + * number of mlo links + * + * Return: True if MLO is present with both links on 5 and 6ghz band + */ +bool policy_mgr_is_mlo_in_mode_sbs(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo); + +/** + * policy_mgr_is_mlo_in_mode_dbs() - Check whether MLO present is DBS + * @psoc: PSOC object information + * @mode: mlo mode to check + * @mlo_vdev_lst: Pointer to mlo vdev list, this function will fill this with + * list of mlo vdev + * @num_mlo: Pointer to number of mlo link, this function will fill this with + * number of mlo links + * + * Return: True if MLO one link is on 2 GHz band and other links on + * 5/6 GHz band + */ +bool policy_mgr_is_mlo_in_mode_dbs(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo); + +/** + * policy_mgr_is_mlo_in_mode_emlsr() - Check whether current connection is eMLSR + * @psoc: PSOC object information + * @mlo_vdev_lst: Pointer to mlo vdev list, this function will fill this with + * list of mlo vdev + * @num_mlo: Pointer to number of mlo link, this function will fill this with + * number of mlo links + * + * Return: True if current connection is in eMLSR mode i.e. Both STA and AP + * support eMLSR connection along with vendor command selection + */ +bool policy_mgr_is_mlo_in_mode_emlsr(struct wlan_objmgr_psoc *psoc, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo); + +/** + * policy_mgr_handle_ml_sta_links_on_vdev_up_csa() - Handle enable/disable + * link on vdev UP and channel change + * @psoc: objmgr psoc + * @mode: mode of vdev that went UP or changed channel + * @vdev_id: vdev_id which went UP or changed channel + * + * Return: void + */ +void +policy_mgr_handle_ml_sta_links_on_vdev_up_csa(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t vdev_id); + +/** + * policy_mgr_handle_ml_sta_link_on_traffic_type_change() - Handle + * enable/disable link on vdev traffic type change on SAP/P2P vdev + * @psoc: objmgr psoc + * @vdev: vdev on which traffic type change + * + * Context: Should be called only from north bound context and never from + * schedular thread as it has wait for completed. + * + * Return: void + */ +void policy_mgr_handle_ml_sta_link_on_traffic_type_change( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * policy_mgr_handle_ml_sta_links_on_vdev_down() - Handle enable + * link on any vdev down + * @psoc: objmgr psoc + * @mode: mode of vdev that went down + * @vdev_id: vdev_id which went down + * + * Return: void + */ +void policy_mgr_handle_ml_sta_links_on_vdev_down(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t vdev_id); + +/** + * policy_mgr_handle_emlsr_sta_concurrency() - Handle concurrency scenarios with + * EMLSR STA. + * @psoc: objmgr psoc + * @conc_con_coming_up: Indicates if any concurrent connection is coming up + * @emlsr_sta_coming_up: Carries true when eMLSR STA is coming up. + * Carries true when an unsupported concurrency is + * gone, so that host can let firmware go to eMLSR mode. + * + * The API handles concurrency scenarios with existing EMLSR connection when a + * new connection request is received OR with an existing legacy connection when + * an EMLSR sta comes up. + * + * Return: none + */ +void policy_mgr_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc, + bool conc_con_coming_up, + bool emlsr_sta_coming_up); + +/** + * policy_mgr_clear_ml_links_settings_in_fw() - Process + * QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE in default mode + * @psoc: objmgr psoc + * @vdev_id: vdev_id + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_clear_ml_links_settings_in_fw(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_activate_mlo_links_nlink() - Force active ML links based on user + * requested link mac address with link bitmap + * @psoc: objmgr psoc + * @session_id: session id + * @num_links: number of links to be forced active + * @active_link_addr: link mac address of links to be forced active + * + * Return: void + */ +void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, uint8_t num_links, + struct qdf_mac_addr *active_link_addr); + +/** + * policy_mgr_activate_mlo_links() - Force active ML links based on user + * requested link mac address with vdev bitmap + * @psoc: objmgr psoc + * @session_id: session id + * @num_links: number of links to be forced active + * @active_link_addr: link mac address of links to be forced active + * + * Return: void + */ +void policy_mgr_activate_mlo_links(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, uint8_t num_links, + struct qdf_mac_addr *active_link_addr); + +/** + * policy_mgr_update_mlo_links_based_on_linkid() - Force active ML links based + * on user requested coming via QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @num_links: number of links to be forced active + * @link_id_list: link id(s) list coming from user space + * @config_state_list: config state list coming from user space + * + * Return: success if the command gets processed successfully + */ +QDF_STATUS +policy_mgr_update_mlo_links_based_on_linkid(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t num_links, + uint8_t *link_id_list, + uint32_t *config_state_list); + +/** + * policy_mgr_update_active_mlo_num_links() - Force active ML links based + * on user requested coming via LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @num_links: number of links to be forced active + * + * Return: success if the command gets processed successfully + */ +QDF_STATUS policy_mgr_update_active_mlo_num_links(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t num_links); +#else +static inline bool +policy_mgr_vdev_is_force_inactive(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline bool policy_mgr_is_mlo_sap_concurrency_allowed( + struct wlan_objmgr_psoc *psoc, + bool is_new_vdev_mlo, + uint8_t new_vdev_id) +{ + return true; +} + +static inline uint32_t +policy_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev, bool force_mlo) +{ + return 0; +} + +static inline bool +policy_mgr_is_non_ml_sta_present(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline bool policy_mgr_is_mlo_sta_present(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool policy_mgr_is_mlo_in_mode_sbs(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo) +{ + return false; +} + +static inline +bool policy_mgr_is_mlo_in_mode_dbs(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo) +{ + return false; +} + +static inline void +policy_mgr_handle_ml_sta_links_on_vdev_up_csa(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t vdev_id) +{ +} + +static inline void +policy_mgr_handle_ml_sta_link_on_traffic_type_change( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +bool policy_mgr_is_mlo_in_mode_emlsr(struct wlan_objmgr_psoc *psoc, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo) +{ + return false; +} + +static inline +void policy_mgr_handle_ml_sta_links_on_vdev_down(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t vdev_id) +{ +} +#endif + +/** + * policy_mgr_is_hwmode_offload_enabled() - Check for HW mode selection offload + * support + * @psoc: PSOC object information + * + * Check if target supports HW mode selection offload or not + * + * Return: True if the target supports HW mode selection offload, + * False otherwise. + */ +bool policy_mgr_is_hwmode_offload_enabled(struct wlan_objmgr_psoc *psoc); +/** + * policy_mgr_is_3rd_conn_on_same_band_allowed() - Check the third connection + * on same band allowed or not + * list for third connection + * @psoc: PSOC object information + * @mode: Device mode + * @ch_freq: 3rd channel frequency + * + * This function checks whether to allow third connection on same band or not + * based on pcl table + * + * Return: TRUE/FALSE + */ +bool policy_mgr_is_3rd_conn_on_same_band_allowed(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + qdf_freq_t ch_freq); + +/** + * policy_mgr_get_connected_roaming_vdev_band_mask() - get connected vdev + * band mask + * @psoc: PSOC object + * @vdev_id: Vdev id + * + * Return: reg wifi band mask + */ +uint32_t +policy_mgr_get_connected_roaming_vdev_band_mask(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * policy_mgr_is_sta_chan_valid_for_connect_and_roam - Check if given + * channel is valid for STA connection/roam pcl channels + * @pdev: pdev + * @freq: frequency + * + * Return: true if channel is valid else false + */ +bool policy_mgr_is_sta_chan_valid_for_connect_and_roam( + struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq); + +/** + * policy_mgr_is_ap_ap_mcc_allow() - Check AP AP MCC allow or not + * @psoc: psoc object + * @pdev: pdev object + * @vdev: vdev object of new SAP or P2P GO + * @ch_freq: channel frequency of up coming vdev + * @ch_width: channel width + * @con_vdev_id: concurrent SAP/GO vdev id + * @con_freq: concurrent SAP/GO home channel. + * + * Check if AP AP MCC allow or not when new SAP or P2P GO creating. + * If not allowed, the concurrency SAP/GO vdev and channel will + * be returned. + * + * Return: True if the target allow AP AP MCC, + * False otherwise. + */ +bool policy_mgr_is_ap_ap_mcc_allow(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + uint32_t ch_freq, + enum phy_ch_width ch_width, + uint8_t *con_vdev_id, + uint32_t *con_freq); + +/** + * policy_mgr_any_other_vdev_on_same_mac_as_freq() - Function to check + * whether more than one vdev are present on same mac or not + * @psoc: PSOC object + * @freq: Channel frequency + * @vdev_id: Vdev id + * + * Return: True if more than one vdev are present on same mac + * + */ +bool policy_mgr_any_other_vdev_on_same_mac_as_freq( + struct wlan_objmgr_psoc *psoc, + uint32_t freq, uint8_t vdev_id); + +/** + * policy_mgr_get_sbs_cfg() - Get SBS INI value + * @psoc: PSOC object + * @sbs: output sbs cfg value + * + */ +QDF_STATUS policy_mgr_get_sbs_cfg(struct wlan_objmgr_psoc *psoc, bool *sbs); + +/** + * policy_mgr_get_ll_sap_freq()- Function to get ll sap freq if it's present + * @psoc: PSOC object + * + * Based on vdev id ap profile set via vendor command is get and compared with + * ll_type_any AP type and return freq for that SAP if profile set is latency + * sensitive or throghput sensitive. + * + * Return: freq if it's LL SAP otherwise 0 + * + */ +qdf_freq_t policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_ll_lt_sap_freq()- Function to get LT LL sap freq if it's + * present + * @psoc: PSOC object + * + * Based on vdev id ap profile set via vendor command is get and compared with + * lt_ll_type AP type and return freq for that SAP if profile set is latency + * sensitive example gaming or losless audio. + * + * Return: freq if it's LT LL SAP otherwise 0 + * + */ +qdf_freq_t policy_mgr_get_ll_lt_sap_freq(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_ll_ht_sap_freq()- Function to get LL HT sap freq if it's + * present + * @psoc: PSOC object + * + * Based on vdev id ap profile set via vendor command is get and compared with + * ll_ht_type AP type and return freq for that SAP if profile set is throghput + * sensitive. + * + * Return: freq if it's HT LL SAP otherwise 0 + * + */ +qdf_freq_t policy_mgr_get_ll_ht_sap_freq(struct wlan_objmgr_psoc *psoc); + +#ifndef WLAN_FEATURE_LL_LT_SAP +/** + * policy_mgr_is_ll_sap_concurrency_valid() - Function to check whether + * low latency SAP + STA/SAP/GC/GO concurrency allowed or not + * @psoc: PSOC object + * @freq: Channel frequency + * @mode: Device mode + * + * Return: True if concurrency are allowed otherwise false + * + */ +bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, + enum policy_mgr_con_mode mode); +#else +static inline +bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, + enum policy_mgr_con_mode mode) +{ + return true; +} +#endif +/** + * policy_mgr_update_indoor_concurrency() - Function to update the indoor + * concurrency related regulatory changes + * + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @discon_freq: disconnect frequency + * @type: enum indoor_conc_update_type + * + * Return: True if need to compute pdev current channel list + */ +bool +policy_mgr_update_indoor_concurrency(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t discon_freq, + enum indoor_conc_update_type type); +/** + * policy_mgr_is_conc_sap_present_on_sta_freq() - Function to check if + * SAP or GO exists on the STA frequency + * + * @psoc: pointer to psoc + * @mode: interface mode + * @ch_freq: channel frequency + * + * Return: AP mode exists + */ +bool +policy_mgr_is_conc_sap_present_on_sta_freq(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq); + +/** + * policy_mgr_get_connection_count_with_ch_freq() - Get number of active + * connections on the channel frequecy + * @ch_freq: channel frequency + * + * Return: number of active connection on the specific frequency + */ +uint32_t policy_mgr_get_connection_count_with_ch_freq(uint32_t ch_freq); + +/** + * policy_mgr_is_sap_go_interface_allowed_on_indoor() - Check if SAP or GO + * interface is allowed on the indoor channel + * + * @pdev: pointer to pdev + * @vdev_id: vdev id + * @ch_freq: SAP frequency + * + * Return: is SAP allowed + */ +bool +policy_mgr_is_sap_go_interface_allowed_on_indoor(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t ch_freq); + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +/** + * policy_mgr_get_allowed_tdls_offchannel_freq() - Check if TDLS off-channel is + * allowed during concurrency. When off-channel is allowed, update the provided + * input channel frequency with concurrent vdev frequency in DBS case. + * Fill the provided channel frequency as 0 if all 5GHz/6GHz channels are + * allowed for off-channel operation in SCC case. + * Don't allow off channel operation in any MCC case. + * @psoc: psoc pointer + * @vdev: vdev pointer + * @ch_freq: Frequency pointer + * + * Return: true or false based on current concurrency combination + */ +bool +policy_mgr_get_allowed_tdls_offchannel_freq(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + qdf_freq_t *ch_freq); +#endif /* WLAN_FEATURE_TDLS_CONCURRENCIES */ + +/** + * policy_mgr_is_sap_mode() - Check if mode is SAP mode + * @mode: Policy manager concurrency mode + * + * Return: true if mode is SAP mode else false + */ +bool policy_mgr_is_sap_mode(enum policy_mgr_con_mode mode); + +/** + * policy_mgr_is_beaconing_mode() - Check if mode represents beaconing entity + * @mode: Policy manager concurrency mode + * + * Return: true if mode represents beaconing entity else false + */ +bool policy_mgr_is_beaconing_mode(enum policy_mgr_con_mode mode); + +/** + * policy_mgr_get_nan_sap_scc_on_lte_coex_chnl() -Get if NAN + SAP SCC on + * lte coex channel is allowed on lte coex channel or not + * @psoc: psoc pointer + * + * Return: cfg value of nan sap scc is allowed or not on lte coex channel + */ + +bool policy_mgr_get_nan_sap_scc_on_lte_coex_chnl(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_reset_sap_mandatory_channels() - Reset the SAP mandatory channels + * @psoc: psoc object + * + * Resets the SAP mandatory channel list and the length of the list + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_reset_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_sap_mode_count() - Get SAP interface counts + * @psoc: psoc object + * @list: To provide the indices on pm_conc_connection_list + * (optional) + * + * Return: No of SAP interface counts + */ +uint32_t policy_mgr_get_sap_mode_count(struct wlan_objmgr_psoc *psoc, + uint32_t *list); + +/** + * policy_mgr_get_beaconing_mode_count() - Get Beaconing interface counts + * @psoc: psoc object + * @list: To provide the indices on pm_conc_connection_list + * (optional) + * + * Return: No of Beaconing interface counts + */ +uint32_t policy_mgr_get_beaconing_mode_count(struct wlan_objmgr_psoc *psoc, + uint32_t *list); + +/** + * policy_mgr_get_sap_mode_info() - Get active SAP channels and vdev ids + * @psoc: PSOC object information + * @ch_freq_list: Mode specific channel freq list + * @vdev_id: Mode specific vdev id (list) + * + * Get active SAP channel and vdev id + * + * Return: number of SAP connections found + */ +uint32_t policy_mgr_get_sap_mode_info(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, uint8_t *vdev_id); + +/** + * policy_mgr_get_beaconing_mode_info() - Get active beaconing entity + * channels and vdev ids + * @psoc: PSOC object information + * @ch_freq_list: Mode specific channel freq list + * @vdev_id: Mode specific vdev id (list) + * + * Get active beaconing entity channels and vdev ids + * + * Return: number of beaconing entities found + */ +uint32_t policy_mgr_get_beaconing_mode_info(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, + uint8_t *vdev_id); + +/** + * policy_mgr_is_freq_on_mac_id() - Check if given freq belongs to given mac id + * @freq_range: Frequency range pointer + * @freq: Frequency which needs to be checked + * @mac_id: MAC id on which this frequency needs to be checked + * + * Return: True if given frequency belongs to the given MAC id + */ +bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range, + qdf_freq_t freq, uint8_t mac_id); + +/** + * policy_mgr_is_conn_lead_to_dbs_sbs() - New freq leads to DBS/SBS + * @psoc: PSOC object information + * @vdev_id: vdev id of the caller + * @freq: New connection frequency + * + * This API loops through existing connections from policy_mgr connection table + * + * Return: True if new frequency causes DBS/SBS with existing connections + */ +bool +policy_mgr_is_conn_lead_to_dbs_sbs(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t freq); + +/** + * policy_mgr_sap_ch_width_update() - Update SAP ch_width + * @psoc: PSOC object information + * @next_action: next action to happen in order to update bandwidth + * @reason: reason for ch_width update + * @conc_vdev_id: Concurrent connection vdev_id that is causing ch_width update + * @request_id: request id for connection manager + * + * Update ch_width as per next_action + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_sap_ch_width_update(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conc_next_action next_action, + enum policy_mgr_conn_update_reason reason, + uint8_t conc_vdev_id, uint32_t request_id); + +/* + * policy_mgr_get_vdev_same_freq_new_conn() - Get vdev_id of the first + * connection that has same + * channel frequency as new_freq + * @psoc: psoc object pointer + * @new_freq: channel frequency for the new connection + * @vdev_id: Output parameter to return vdev id of the first existing connection + * that has same channel frequency as @new_freq + * + * This function is to return the first connection that has same + * channel frequency as @new_freq. + * + * Return: true if connection that has same channel frequency as + * @new_freq exists. Otherwise false. + */ +bool policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id); + +/* + * policy_mgr_get_vdev_diff_freq_new_conn() - Get vdev id of the first + * connection that has different + * channel freq from new_freq + * @psoc: psoc object pointer + * @new_freq: channel frequency for the new connection + * @vdev_id: Output parameter to return vdev id of the first existing connection + * that has different channel frequency from @new_freq + * + * This function is to return the first connection that has different + * channel frequency from @new_freq. + * + * Return: true if connection that has different channel frequency from + * @new_freq exists. Otherwise false. + */ +bool policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id); + +/** + * policy_mgr_sap_on_non_psc_channel() - Check if STA operates in PSC or Non-PSC + * channel to restart SAP on Non-PSC + * channel + * @psoc: PSOC object information + * @intf_ch_freq: input/out interference channel frequency to sap + * @sap_vdev_id: SAP vdev id + * + * This function is to check if STA operates in PSC or Non-PSC channel + * to restart SAP on Non-PSC channel. + * + * Return: None + */ +void +policy_mgr_sap_on_non_psc_channel(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *intf_ch_freq, + uint8_t sap_vdev_id); + +#ifdef WLAN_FEATURE_LL_LT_SAP +/** + * policy_mgr_get_pcl_ch_list_for_ll_sap() - Get PCL channel list for LL_LT_SAP + * @psoc: psoc object + * @pcl: pcl list + * @vdev_id: vdev id + * @info: pointer to connection_info structure + * @connection_count: total number of existing connection present + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_pcl_ch_list_for_ll_sap( + struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_list *pcl, + uint8_t vdev_id, + struct connection_info *info, + uint8_t *connection_count); +#endif + +/** + * policy_mgr_is_given_freq_5g_low() - API to check whether given freq + * is 5GHz low or not + * @psoc: psoc object + * @given_freq: given freq + * + * Return: True if it 5GHz low otherwise false + */ +bool policy_mgr_is_given_freq_5g_low(struct wlan_objmgr_psoc *psoc, + qdf_freq_t given_freq); +#endif /* __WLAN_POLICY_MGR_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ll_sap.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ll_sap.h new file mode 100644 index 0000000000..ea01f46cf9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ll_sap.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains policy manager ll_sap definitions specific to the ll_sap module + */ +#ifndef WLAN_POLICY_MGR_LL_SAP_H +#define WLAN_POLICY_MGR_LL_SAP_H + +#include "wlan_objmgr_psoc_obj.h" + +#ifdef WLAN_FEATURE_LL_LT_SAP +/** + * policy_mgr_ll_lt_sap_get_valid_freq() - Check and get valid frequency for + * the current interface (SAP/P2PGO/LL_LT_SAP) + * @psoc: PSOC object + * @pdev: PDEV pointer + * @vdev_id: Vdev id of the current interface + * @sap_ch_freq: Frequency of the current interface + * @cc_switch_mode: Channel switch mode + * @new_sap_freq: Updated frequency + * @is_ll_lt_sap_present: Indicates if ll_lt_sap is present or not + * + * This API checks if ll_lt_sap is present or not and if ll_lt_sap is present + * then if current frequency of the ll_lt_sap or concurrent SAP or concurrent + * P2PGO is valid or not according to ll_lt_sap concurrency, if valid, does not + * fill anything in the new_sap_freq and if not valid, update the new_sap_freq + * with some new valid frequency. + * + * Return: true/false + */ +void policy_mgr_ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t sap_ch_freq, + uint8_t cc_switch_mode, + qdf_freq_t *new_sap_freq, + bool *is_ll_lt_sap_present); + +/** + * wlan_policy_mgr_get_ll_lt_sap_vdev_id() - Get ll_lt_sap vdev id + * @psoc: PSOC object + * + * API to find ll_lt_sap vdev id + * + * Return: vdev id + */ +uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev_id(struct wlan_objmgr_psoc *psoc); + +/** + * __policy_mgr_is_ll_lt_sap_restart_required() - Check in ll_lt_sap restart is + * required + * @psoc: PSOC object + * @func: Function pointer of the caller function. + * + * This API checks if ll_lt_sap restart is required or not + * + * Return: true/false + */ +bool __policy_mgr_is_ll_lt_sap_restart_required(struct wlan_objmgr_psoc *psoc, + const char *func); + +#define policy_mgr_is_ll_lt_sap_restart_required(psoc) \ + __policy_mgr_is_ll_lt_sap_restart_required(psoc, __func__) + +/** + * policy_mgr_ll_lt_sap_restart_concurrent_sap() - Check and restart + * concurrent SAP or ll_lt_sap + * @psoc: PSOC object + * @is_ll_lt_sap_enabled: Indicates if ll_lt_sap is getting enabled or + * getting disabled + * + * This API checks and restarts concurrent SAP or ll_lt_sap when ll_lt_sap comes + * up or goes down. + * Concurrent SAP and ll_lt_sap should always be on different MAC. + * restart the concurrent SAP in below scenario: + * If ll_lt_sap is coming up and HW is not sbs capable and concurrent SAP is + * operating on 5 GHz, then move concurrent SAP to 2.4 Ghz MAC to allow + * ll_lt_sap on 5 GHz + * If ll_lt_sap is going down and if concurrent SAP is on 2.4 GHz then try to + * restart concurrent SAP on its original user configured frequency + * If ll_lt_sap interface has come up and in parallel if some other interface + * comes up on the ll_lt_sap frequency, then ll_lt_sap needs to be restarted. + * + * Return: None + */ +void policy_mgr_ll_lt_sap_restart_concurrent_sap(struct wlan_objmgr_psoc *psoc, + bool is_ll_lt_sap_enabled); +#else + +static inline bool +policy_mgr_is_ll_lt_sap_restart_required(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +void policy_mgr_ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t sap_ch_freq, + uint8_t cc_switch_mode, + qdf_freq_t *new_sap_freq, + bool *is_ll_lt_sap_present) +{ +} + +static inline +uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev_id(struct wlan_objmgr_psoc *psoc) +{ + return WLAN_INVALID_VDEV_ID; +} + +static inline void +policy_mgr_ll_lt_sap_restart_concurrent_sap(struct wlan_objmgr_psoc *psoc, + bool is_ll_lt_sap_enabled) +{ +} +#endif +#endif /* WLAN_POLICY_MGR_LL_SAP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h new file mode 100644 index 0000000000..7a87d536c8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_public_struct.h @@ -0,0 +1,1911 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_PUBLIC_STRUCT_H +#define __WLAN_POLICY_MGR_PUBLIC_STRUCT_H + +/** + * DOC: wlan_policy_mgr_public_struct.h + * + * Concurrenct Connection Management entity + */ + +/* Include files */ +#include + +/* + * Some max value greater than the max length of the channel list + */ +#define MAX_WEIGHT_OF_PCL_CHANNELS 255 +/* + * Some fixed weight difference between the groups + */ +#define PCL_GROUPS_WEIGHT_DIFFERENCE 20 + +/* + * Currently max, only 3 groups are possible as per 'enum policy_mgr_pcl_type'. + * i.e., in a PCL only 3 groups of channels can be present + * e.g., SCC channel on 2.4 Ghz, SCC channel on 5 Ghz & 5 Ghz channels. + * Group 1 has highest priority, group 2 has the next higher priority + * and so on. + */ +#define WEIGHT_OF_GROUP1_PCL_CHANNELS MAX_WEIGHT_OF_PCL_CHANNELS +#define WEIGHT_OF_GROUP2_PCL_CHANNELS \ + (WEIGHT_OF_GROUP1_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE) +#define WEIGHT_OF_GROUP3_PCL_CHANNELS \ + (WEIGHT_OF_GROUP2_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE) +#define WEIGHT_OF_GROUP4_PCL_CHANNELS \ + (WEIGHT_OF_GROUP3_PCL_CHANNELS - PCL_GROUPS_WEIGHT_DIFFERENCE) + +#define WEIGHT_OF_NON_PCL_CHANNELS 1 +#define WEIGHT_OF_DISALLOWED_CHANNELS 0 + +#define MAX_MAC 2 + +#ifdef FEATURE_FOURTH_CONNECTION +#define MAX_NUMBER_OF_CONC_CONNECTIONS 4 +#else +#define MAX_NUMBER_OF_CONC_CONNECTIONS 3 +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/* Max MLO VDEVS for disabled link table */ +#define MAX_NUMBER_OF_DISABLE_LINK WLAN_UMAC_MLO_MAX_VDEVS +#endif + +/* BIT 0 for low latency and BIT 1 for HIGH TPUT */ +#define PM_VDEV_TRAFFIC_LOW_LATENCY 0x1 +#define PM_VDEV_TRAFFIC_HIGH_TPUT 0x2 + +/* Policy manager default request id */ +#define POLICY_MGR_DEF_REQ_ID 0 + +typedef int (*send_mode_change_event_cb)(void); + +/** + * enum sap_csa_reason_code - SAP channel switch reason code + * @CSA_REASON_UNKNOWN: Unknown reason + * @CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS: STA connection from DFS to NON DFS. + * @CSA_REASON_USER_INITIATED: User initiated form north bound. + * @CSA_REASON_PEER_ACTION_FRAME: Action frame received on sta iface. + * @CSA_REASON_PRE_CAC_SUCCESS: Pre CAC success. + * @CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL: concurrent sta changed channel. + * @CSA_REASON_UNSAFE_CHANNEL: Unsafe channel. + * @CSA_REASON_LTE_COEX: LTE coex. + * @CSA_REASON_CONCURRENT_NAN_EVENT: NAN concurrency. + * @CSA_REASON_BAND_RESTRICTED: band disabled or re-enabled + * @CSA_REASON_DCS: DCS + * @CSA_REASON_CHAN_DISABLED: channel is disabled + * @CSA_REASON_CHAN_PASSIVE: channel is passive + * @CSA_REASON_GO_BSS_STARTED: P2P go started + * @CSA_REASON_SAP_ACS: 2.4 GHz preferred SAP ACS starting + * @CSA_REASON_SAP_FIX_CH_CONC_WITH_GO: SAP fix channel start + * @CSA_REASON_CONCURRENT_LL_LT_SAP_EVENT: LL_LT_SAP concurrency + * and move GO to other band + */ +enum sap_csa_reason_code { + CSA_REASON_UNKNOWN, + CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS, + CSA_REASON_USER_INITIATED, + CSA_REASON_PEER_ACTION_FRAME, + CSA_REASON_PRE_CAC_SUCCESS, + CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL, + CSA_REASON_UNSAFE_CHANNEL, + CSA_REASON_LTE_COEX, + CSA_REASON_CONCURRENT_NAN_EVENT, + CSA_REASON_BAND_RESTRICTED, + CSA_REASON_DCS, + CSA_REASON_CHAN_DISABLED, + CSA_REASON_CHAN_PASSIVE, + CSA_REASON_GO_BSS_STARTED, + CSA_REASON_SAP_ACS, + CSA_REASON_SAP_FIX_CH_CONC_WITH_GO, + CSA_REASON_CONCURRENT_LL_LT_SAP_EVENT +}; + +/* + * enum link_control_flags: This enum is used for setting + * mlo_control_flags by api policy_mgr_mlo_sta_set_nlink. + * @link_ctrl_f_overwrite_active_bitmap: indicate overwrite all earlier + * force_active bitmaps. Used with MLO_LINK_FORCE_MODE_ACTIVE or + * MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE + * @link_ctrl_f_overwrite_inactive_bitmap: indicate overwrite all earlier + * force_inactive bitmaps. Used with MLO_LINK_FORCE_MODE_INACTIVE or + * MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE. + * @link_ctrl_f_dynamic_force_link_num: indicate fw to use force link number + * instead of force link bitmaps. Used with MLO_LINK_FORCE_MODE_ACTIVE_NUM. + * MLO_LINK_FORCE_MODE_INACTIVE_NUM, MLO_LINK_FORCE_MODE_NO_FORCE. + * @link_ctrl_f_post_re_evaluate: run link state check again after command + * response handled. + */ +enum link_control_flags { + link_ctrl_f_overwrite_active_bitmap = 1 << 0, + link_ctrl_f_overwrite_inactive_bitmap = 1 << 1, + link_ctrl_f_dynamic_force_link_num = 1 << 2, + link_ctrl_f_post_re_evaluate = 1 << 3, +}; + +/** + * enum hw_mode_ss_config - Possible spatial stream configuration + * @HW_MODE_SS_0x0: Unused Tx and Rx of MAC + * @HW_MODE_SS_1x1: 1 Tx SS and 1 Rx SS + * @HW_MODE_SS_2x2: 2 Tx SS and 2 Rx SS + * @HW_MODE_SS_3x3: 3 Tx SS and 3 Rx SS + * @HW_MODE_SS_4x4: 4 Tx SS and 4 Rx SS + * + * Note: Right now only 1x1 and 2x2 are being supported. Other modes should + * be added when supported. Asymmetric configuration like 1x2, 2x1 are also + * not supported now. But, they are still valid. Right now, Tx/Rx SS support is + * 4 bits long. So, we can go upto 15x15 + */ +enum hw_mode_ss_config { + HW_MODE_SS_0x0, + HW_MODE_SS_1x1, + HW_MODE_SS_2x2, + HW_MODE_SS_3x3, + HW_MODE_SS_4x4, +}; + +/** + * enum hw_mode_dbs_capab - DBS HW mode capability + * @HW_MODE_DBS_NONE: Non DBS capable + * @HW_MODE_DBS: DBS capable + */ +enum hw_mode_dbs_capab { + HW_MODE_DBS_NONE, + HW_MODE_DBS, +}; + +/** + * enum hw_mode_agile_dfs_capab - Agile DFS HW mode capability + * @HW_MODE_AGILE_DFS_NONE: Non Agile DFS capable + * @HW_MODE_AGILE_DFS: Agile DFS capable + */ +enum hw_mode_agile_dfs_capab { + HW_MODE_AGILE_DFS_NONE, + HW_MODE_AGILE_DFS, +}; + +/** + * enum hw_mode_sbs_capab - SBS HW mode capability + * @HW_MODE_SBS_NONE: Non SBS capable + * @HW_MODE_SBS: SBS capable + */ +enum hw_mode_sbs_capab { + HW_MODE_SBS_NONE, + HW_MODE_SBS, +}; + +/** + * enum hw_mode_emlsr_capab - EMLSR HW mode capability + * @HW_MODE_EMLSR_NONE: Non EMLSR capable + * @HW_MODE_EMLSR: EMLSR capable + */ +enum hw_mode_emlsr_capab { + HW_MODE_EMLSR_NONE, + HW_MODE_EMLSR, +}; + +/** + * enum hw_mode_mac_band_cap - mac band capability + * @HW_MODE_MAC_BAND_NONE: No band requirement. + * @HW_MODE_MAC_BAND_2G: 2G band supported. + * @HW_MODE_MAC_BAND_5G: 5G band supported. + * + * To add HW_MODE_MAC_BAND_NONE value to help to + * match the HW DBS mode in hw mode list. + * Other enum values should match with WMI header: + * typedef enum { + * WLAN_2G_CAPABILITY = 0x1, + * WLAN_5G_CAPABILITY = 0x2, + * } WLAN_BAND_CAPABILITY; + */ +enum hw_mode_mac_band_cap { + HW_MODE_MAC_BAND_NONE = 0, + HW_MODE_MAC_BAND_2G = WLAN_2G_CAPABILITY, + HW_MODE_MAC_BAND_5G = WLAN_5G_CAPABILITY, +}; + +/** + * enum force_1x1_type - enum to specify the type of forced 1x1 ini provided. + * @FORCE_1X1_DISABLED: even if the AP is present in OUI, 1x1 will not be forced + * @FORCE_1X1_ENABLED_FOR_AS: If antenna sharing supported, then only do 1x1. + * @FORCE_1X1_ENABLED_FORCED: If AP present in OUI, force 1x1 connection. + */ +enum force_1x1_type { + FORCE_1X1_DISABLED, + FORCE_1X1_ENABLED_FOR_AS, + FORCE_1X1_ENABLED_FORCED, +}; + +/** + * enum policy_mgr_pcl_group_id - Identifies the pcl groups to be used + * @POLICY_MGR_PCL_GROUP_ID1_ID2: Use weights of group1 and group2 + * @POLICY_MGR_PCL_GROUP_ID2_ID3: Use weights of group2 and group3 + * @POLICY_MGR_PCL_GROUP_ID3_ID4: Use weights of group3 and group4 + * + * Since maximum of three groups are possible, this will indicate which + * PCL group needs to be used. + */ +enum policy_mgr_pcl_group_id { + POLICY_MGR_PCL_GROUP_ID1_ID2, + POLICY_MGR_PCL_GROUP_ID2_ID3, + POLICY_MGR_PCL_GROUP_ID3_ID4, +}; + +/** + * enum policy_mgr_pcl_channel_order - Order in which the PCL is requested + * @POLICY_MGR_PCL_ORDER_NONE: no order + * @POLICY_MGR_PCL_ORDER_24G_THEN_5G: 2.4 Ghz channel followed by 5 Ghz channel + * @POLICY_MGR_PCL_ORDER_5G_THEN_2G: 5 Ghz channel followed by 2.4 Ghz channel + * @POLICY_MGR_PCL_ORDER_2G: 2G channels + * @POLICY_MGR_PCL_ORDER_5G: 5G channels + * @POLICY_MGR_PCL_ORDER_SCC_5G_LOW_5G_LOW: 5G Low SCC frequency followed by + * 5G low band i.e 5G freq < sbs cutoff freq + * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH: 5G High SCC frequency followed by + * 5G High band i.e 5G freq > sbs cutoff freq + * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW: 5 GHz High SCC + * frequency followed by 5G High band i.e 5G freq > sbs cutoff freq, add 5 GHz + * Low SCC frequency + * @POLICY_MGR_PCL_ORDER_SCC_5G_LOW: SCC channel on 5G low + * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH: SCC channel on 5G high + * @POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH: SCC channels on 5G low + * followed by MCC channels on 5G high + * @POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_MCC_5G_LOW: SCC channels on 5G high + * followed by MCC channels on 5G low + * + * Order in which the PCL is requested + */ +enum policy_mgr_pcl_channel_order { + POLICY_MGR_PCL_ORDER_NONE, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + POLICY_MGR_PCL_ORDER_2G, + POLICY_MGR_PCL_ORDER_5G, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW_5G_LOW, + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH, + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW, + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH, + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_MCC_5G_LOW, +}; + +/** + * enum policy_mgr_pcl_band_priority - Band priority between 5G and 6G channel + * @POLICY_MGR_PCL_BAND_5G_THEN_6G: 5 Ghz channel followed by 6 Ghz channel + * @POLICY_MGR_PCL_BAND_6G_THEN_5G: 6 Ghz channel followed by 5 Ghz channel + * + * Band priority between 5G and 6G + */ +enum policy_mgr_pcl_band_priority { + POLICY_MGR_PCL_BAND_5G_THEN_6G = 0, + POLICY_MGR_PCL_BAND_6G_THEN_5G, +}; + +/** + * enum policy_mgr_max_rx_ss - Maximum number of receive spatial streams + * @POLICY_MGR_RX_NSS_1: Receive Nss = 1 + * @POLICY_MGR_RX_NSS_2: Receive Nss = 2 + * @POLICY_MGR_RX_NSS_3: Receive Nss = 3 + * @POLICY_MGR_RX_NSS_4: Receive Nss = 4 + * @POLICY_MGR_RX_NSS_5: Receive Nss = 5 + * @POLICY_MGR_RX_NSS_6: Receive Nss = 6 + * @POLICY_MGR_RX_NSS_7: Receive Nss = 7 + * @POLICY_MGR_RX_NSS_8: Receive Nss = 8 + * @POLICY_MGR_RX_NSS_MAX: maximum enumeration + * + * Indicates the maximum number of spatial streams that the STA can receive + */ +enum policy_mgr_max_rx_ss { + POLICY_MGR_RX_NSS_1 = 0, + POLICY_MGR_RX_NSS_2 = 1, + POLICY_MGR_RX_NSS_3 = 2, + POLICY_MGR_RX_NSS_4 = 3, + POLICY_MGR_RX_NSS_5 = 4, + POLICY_MGR_RX_NSS_6 = 5, + POLICY_MGR_RX_NSS_7 = 6, + POLICY_MGR_RX_NSS_8 = 7, + POLICY_MGR_RX_NSS_MAX, +}; + +/** + * enum policy_mgr_chain_mode - Chain Mask tx & rx combination. + * + * @POLICY_MGR_ONE_ONE: One for Tx, One for Rx + * @POLICY_MGR_TWO_TWO: Two for Tx, Two for Rx + * @POLICY_MGR_MAX_NO_OF_CHAIN_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_chain_mode { + POLICY_MGR_ONE_ONE = 0, + POLICY_MGR_TWO_TWO, + POLICY_MGR_MAX_NO_OF_CHAIN_MODE +}; + +/** + * enum policy_mgr_conc_priority_mode - t/p, powersave, latency. + * + * @PM_THROUGHPUT: t/p is the priority + * @PM_POWERSAVE: powersave is the priority + * @PM_LATENCY: latency is the priority + * @PM_MAX_CONC_PRIORITY_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_conc_priority_mode { + PM_THROUGHPUT = 0, + PM_POWERSAVE, + PM_LATENCY, + PM_MAX_CONC_PRIORITY_MODE +}; + +/** + * enum policy_mgr_con_mode - concurrency mode for PCL table + * + * @PM_STA_MODE: station mode + * @PM_SAP_MODE: SAP mode + * @PM_P2P_CLIENT_MODE: P2P client mode + * @PM_P2P_GO_MODE: P2P Go mode + * @PM_NDI_MODE: NDI mode + * @PM_NAN_DISC_MODE: NAN Discovery mode + * @PM_LL_LT_SAP_MODE: Low latency low throughput SAP + * @PM_MAX_NUM_OF_MODE: max value place holder + */ +enum policy_mgr_con_mode { + PM_STA_MODE = 0, + PM_SAP_MODE, + PM_P2P_CLIENT_MODE, + PM_P2P_GO_MODE, + PM_NDI_MODE, + PM_NAN_DISC_MODE, + PM_LL_LT_SAP_MODE, + PM_MAX_NUM_OF_MODE +}; + +/** + * enum policy_mgr_mac_use - MACs that are used + * @POLICY_MGR_MAC0: Only MAC0 is used + * @POLICY_MGR_MAC1: Only MAC1 is used + * @POLICY_MGR_MAC0_AND_MAC1: Both MAC0 and MAC1 are used + */ +enum policy_mgr_mac_use { + POLICY_MGR_MAC0 = 1, + POLICY_MGR_MAC1 = 2, + POLICY_MGR_MAC0_AND_MAC1 = 3 +}; + +/** + * enum policy_mgr_pcl_type - Various types of Preferred channel list (PCL). + * + * @PM_NONE: No channel preference + * @PM_24G: 2.4 Ghz channels only + * @PM_5G: 5 Ghz channels only + * @PM_SCC_CH: SCC channel only + * @PM_MCC_CH: MCC channels only + * @PM_SBS_CH: SBS channels only + * @PM_SCC_CH_24G: SCC channel & 2.4 Ghz channels + * @PM_SCC_CH_5G: SCC channel & 5 Ghz channels + * @PM_24G_SCC_CH: 2.4 Ghz channels & SCC channel + * @PM_5G_SCC_CH: 5 Ghz channels & SCC channel + * @PM_SCC_ON_5_CH_5G: 5 Ghz SCC channel & 5 Ghz channels + * @PM_SCC_ON_5_SCC_ON_24_24G: SCC channel on 5 Ghz, SCC + * channel on 2.4 Ghz & 2.4 Ghz channels + * @PM_SCC_ON_5_SCC_ON_24_5G: SCC channel on 5 Ghz, SCC channel + * on 2.4 Ghz & 5 Ghz channels + * @PM_SCC_ON_5_5G_24G: SCC channel on 5 Ghz, 5 Ghz channels & 2.4 Ghz channels + * @PM_SCC_ON_5_5G_SCC_ON_24G: SCC channel on 5 Ghz, 5 Ghz channels & + * SCC channel on 2.4 Ghz + * @PM_SCC_ON_24_SCC_ON_5_24G: SCC channel on 2.4 Ghz, SCC + * channel on 5 Ghz & 2.4 Ghz channels + * @PM_SCC_ON_24_SCC_ON_5_5G: SCC channel on 2.4 Ghz, SCC + * channel on 5 Ghz & 5 Ghz channels + * @PM_SCC_ON_24_CH_24G: SCC channel on 2.4 GHz & 2.4 GHz channels + * @PM_SCC_ON_5_SCC_ON_24: SCC channel on 5 Ghz, SCC channel on + * 2.4 Ghz + * @PM_SCC_ON_24_SCC_ON_5: SCC channel on 2.4 Ghz, SCC channel + * on 5 Ghz + * @PM_MCC_CH_24G: MCC channels & 2.4 Ghz channels + * @PM_MCC_CH_5G: MCC channels & 5 Ghz channels + * @PM_24G_MCC_CH: 2.4 Ghz channels & MCC channels + * @PM_5G_MCC_CH: 5 Ghz channels & MCC channels + * @PM_SBS_CH_5G: SBS channels & rest of 5 Ghz channels + * @PM_24G_SCC_CH_SBS_CH: 2.4 Ghz channels, SCC channel & SBS channels + * @PM_24G_SCC_CH_SBS_CH_5G: 2.4 Ghz channels, SCC channel, + * SBS channels & rest of the 5G channels + * @PM_24G_SBS_CH_MCC_CH: 2.4 Ghz channels, SBS channels & MCC channels + * @PM_SBS_CH_24G_SCC_CH: + * @PM_SBS_CH_SCC_CH_24G: + * @PM_SCC_CH_SBS_CH_24G: + * @PM_SBS_CH_SCC_CH_5G_24G: + * @PM_SCC_CH_MCC_CH_SBS_CH_24G: + * @PM_SBS_CH_2G: SBS channels & 2.4 Ghz channels + * @PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G: 5 GHz low SCC channel followed by + * 5 GHz low frequencies, add 2.4 GHz if its shared with 5 GHz low + * @PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G: 5GHZ high SCC channel followed by + * 5 GHz high frequencies, add 2.4 GHZ if its shared with 5GHz high + * @PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G: 5GHZ high SCC + * channel followed by 5 GHz high frequencies and 5 GHz low SCC channel, + * add 2.4 GHZ if its shared with 5GHz high + * @PM_SBS_CH_MCC_CH: SBS channels followed by MCC channels + * @PM_SBS_5G_MCC_24G: SBS channels, 5G MCC channels and 2.4GHz channels + * @PM_SCC_ON_24G: SCC channels on 2.4 Ghz + * @PM_SCC_ON_5G_LOW: SCC channels on 5G low frequencies + * @PM_SCC_ON_5G_HIGH: SCC channels on 5G high frequencies + * @PM_SBS_CH_MCC_CH_SCC_ON_24_24G: SBS channels followed by MCC channels + * followed by SCC channels on 2.4 GHz followed by 2.4 GHz channels + * @PM_5G_24G: 5 GHz channels, followed by 2.4 GHz channels + * @PM_MCC_CH_SCC_ON_24G: MCC chanenls followed by SCC channels on 2.4 Ghz + * @PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH: SCC channels on 5G low frequencies + * followed by MCC channels on 5G high frequencies + * @PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW: SCC channels on 5G high frequencies + * followed by MCC channels on 5G low frequencies + * + * @PM_MAX_PCL_TYPE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_pcl_type { + PM_NONE = 0, + PM_24G, + PM_5G, + PM_SCC_CH, + PM_MCC_CH, + PM_SBS_CH, + PM_SCC_CH_24G, + PM_SCC_CH_5G, + PM_24G_SCC_CH, + PM_5G_SCC_CH, + PM_SCC_ON_5_CH_5G, + PM_SCC_ON_5_SCC_ON_24_24G, + PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_5G_24G, + PM_SCC_ON_5_5G_SCC_ON_24G, + PM_SCC_ON_24_SCC_ON_5_24G, + PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_CH_24G, + PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_24_SCC_ON_5, + PM_MCC_CH_24G, + PM_MCC_CH_5G, + PM_24G_MCC_CH, + PM_5G_MCC_CH, + PM_SBS_CH_5G, + PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH_5G, + PM_24G_SBS_CH_MCC_CH, + /* New PCL type for DBS-SBS HW */ + PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, + PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, + PM_SBS_CH_2G, + PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G, + PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G, + + PM_SBS_CH_MCC_CH, + PM_SBS_5G_MCC_24G, + PM_SCC_ON_24G, + PM_SCC_ON_5G_LOW, + PM_SCC_ON_5G_HIGH, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_5G_24G, + PM_MCC_CH_SCC_ON_24G, + PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW, + + PM_MAX_PCL_TYPE +}; + +/** + * enum policy_mgr_one_connection_mode - Combination of first connection + * type, band & spatial stream used. + * + * @PM_STA_24_1x1: STA connection using 1x1@2.4 Ghz + * @PM_STA_24_2x2: STA connection using 2x2@2.4 Ghz + * @PM_STA_5_1x1: STA connection using 1x1@5 Ghz + * @PM_STA_5_2x2: STA connection using 2x2@5 Ghz + * @PM_P2P_CLI_24_1x1: P2P Client connection using 1x1@2.4 Ghz + * @PM_P2P_CLI_24_2x2: P2P Client connection using 2x2@2.4 Ghz + * @PM_P2P_CLI_5_1x1: P2P Client connection using 1x1@5 Ghz + * @PM_P2P_CLI_5_2x2: P2P Client connection using 2x2@5 Ghz + * @PM_P2P_GO_24_1x1: P2P GO connection using 1x1@2.4 Ghz + * @PM_P2P_GO_24_2x2: P2P GO connection using 2x2@2.4 Ghz + * @PM_P2P_GO_5_1x1: P2P GO connection using 1x1@5 Ghz + * @PM_P2P_GO_5_2x2: P2P GO connection using 2x2@5 Ghz + * @PM_SAP_24_1x1: SAP connection using 1x1@2.4 Ghz + * @PM_SAP_24_2x2: SAP connection using 2x2@2.4 Ghz + * @PM_SAP_5_1x1: SAP connection using 1x1@5 Ghz + * @PM_SAP_5_2x2: SAP connection using 2x2@5 Ghz + * @PM_NAN_DISC_24_1x1: NAN Discovery using 1x1@2.4 Ghz + * @PM_NAN_DISC_24_2x2: NAN Discovery using 2x2@2.4 Ghz + * @PM_NDI_24_1x1: NAN Datapath using 1x1@2.4 Ghz + * @PM_NDI_24_2x2: NAN Datapath using 2x2@2.4 Ghz + * @PM_NDI_5_1x1: NAN Datapath using 1x1@5 Ghz + * @PM_NDI_5_2x2: NAN Datapath using 2x2@5 Ghz + * @PM_LL_LT_SAP_5_1x1: Low latency low throughput SAP using 1x1@5 Ghz + * @PM_LL_LT_SAP_5_2x2: Low latency low throughput SAP using 2x2@5 Ghz + * @PM_MAX_ONE_CONNECTION_MODE: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_one_connection_mode { + PM_STA_24_1x1 = 0, + PM_STA_24_2x2, + PM_STA_5_1x1, + PM_STA_5_2x2, + PM_P2P_CLI_24_1x1, + PM_P2P_CLI_24_2x2, + PM_P2P_CLI_5_1x1, + PM_P2P_CLI_5_2x2, + PM_P2P_GO_24_1x1, + PM_P2P_GO_24_2x2, + PM_P2P_GO_5_1x1, + PM_P2P_GO_5_2x2, + PM_SAP_24_1x1, + PM_SAP_24_2x2, + PM_SAP_5_1x1, + PM_SAP_5_2x2, + PM_NAN_DISC_24_1x1, + PM_NAN_DISC_24_2x2, + PM_NDI_24_1x1, + PM_NDI_24_2x2, + PM_NDI_5_1x1, + PM_NDI_5_2x2, + PM_LL_LT_SAP_5_1x1, + PM_LL_LT_SAP_5_2x2 = PM_LL_LT_SAP_5_1x1, + + PM_MAX_ONE_CONNECTION_MODE +}; + +/** + * enum policy_mgr_two_connection_mode - Combination of first two + * connections type, concurrency state, band & spatial stream + * used. + * + * @PM_STA_SAP_SCC_24_1x1: STA & SAP connection on SCC using + * 1x1@2.4 Ghz + * @PM_STA_SAP_SCC_24_2x2: STA & SAP connection on SCC using + * 2x2@2.4 Ghz + * @PM_STA_SAP_MCC_24_1x1: STA & SAP connection on MCC using + * 1x1@2.4 Ghz + * @PM_STA_SAP_MCC_24_2x2: STA & SAP connection on MCC using + * 2x2@2.4 Ghz + * @PM_STA_SAP_SCC_5_1x1: STA & SAP connection on SCC using + * 1x1@5 Ghz + * @PM_STA_SAP_SCC_5_2x2: STA & SAP connection on SCC using + * 2x2@5 Ghz + * @PM_STA_SAP_MCC_5_1x1: STA & SAP connection on MCC using + * 1x1@5 Ghz + * @PM_STA_SAP_MCC_5_2x2: STA & SAP connection on MCC using + * 2x2@5 Ghz + * @PM_STA_SAP_MCC_24_5_1x1: + * @PM_STA_SAP_MCC_24_5_2x2: + * @PM_STA_SAP_DBS_1x1: STA & SAP connection on DBS using 1x1 + * @PM_STA_SAP_DBS_2x2: STA & SAP connection on DBS using 2x2 + * @PM_STA_SAP_SBS_5_1x1: STA & SAP connection on 5G SBS using 1x1 + * @PM_STA_SAP_SBS_5_2x2: STA & SAP connection on 5G SBS using 2x2 + * @PM_STA_P2P_GO_SCC_24_1x1: STA & P2P GO connection on SCC + * using 1x1@2.4 Ghz + * @PM_STA_P2P_GO_SCC_24_2x2: STA & P2P GO connection on SCC + * using 2x2@2.4 Ghz + * @PM_STA_P2P_GO_MCC_24_1x1: STA & P2P GO connection on MCC + * using 1x1@2.4 Ghz + * @PM_STA_P2P_GO_MCC_24_2x2: STA & P2P GO connection on MCC + * using 2x2@2.4 Ghz + * @PM_STA_P2P_GO_SCC_5_1x1: STA & P2P GO connection on SCC + * using 1x1@5 Ghz + * @PM_STA_P2P_GO_SCC_5_2x2: STA & P2P GO connection on SCC + * using 2x2@5 Ghz + * @PM_STA_P2P_GO_MCC_5_1x1: STA & P2P GO connection on MCC + * using 1x1@5 Ghz + * @PM_STA_P2P_GO_MCC_5_2x2: STA & P2P GO connection on MCC + * using 2x2@5 Ghz + * @PM_STA_P2P_GO_MCC_24_5_1x1: + * @PM_STA_P2P_GO_MCC_24_5_2x2: + * @PM_STA_P2P_GO_DBS_1x1: STA & P2P GO connection on DBS using + * 1x1 + * @PM_STA_P2P_GO_DBS_2x2: STA & P2P GO connection on DBS using + * 2x2 + * @PM_STA_P2P_GO_SBS_5_1x1: STA & P2P GO connection on 5G SBS + * using 1x1 + * @PM_STA_P2P_GO_SBS_5_2x2: STA & P2P GO connection on 5G SBS + * using 2x2 + * @PM_STA_P2P_CLI_SCC_24_1x1: STA & P2P CLI connection on SCC + * using 1x1@2.4 Ghz + * @PM_STA_P2P_CLI_SCC_24_2x2: STA & P2P CLI connection on SCC + * using 2x2@2.4 Ghz + * @PM_STA_P2P_CLI_MCC_24_1x1: STA & P2P CLI connection on MCC + * using 1x1@2.4 Ghz + * @PM_STA_P2P_CLI_MCC_24_2x2: STA & P2P CLI connection on MCC + * using 2x2@2.4 Ghz + * @PM_STA_P2P_CLI_SCC_5_1x1: STA & P2P CLI connection on SCC + * using 1x1@5 Ghz + * @PM_STA_P2P_CLI_SCC_5_2x2: STA & P2P CLI connection on SCC + * using 2x2@5 Ghz + * @PM_STA_P2P_CLI_MCC_5_1x1: STA & P2P CLI connection on MCC + * using 1x1@5 Ghz + * @PM_STA_P2P_CLI_MCC_5_2x2: STA & P2P CLI connection on MCC + * using 2x2@5 Ghz + * @PM_STA_P2P_CLI_MCC_24_5_1x1: + * @PM_STA_P2P_CLI_MCC_24_5_2x2: + * @PM_STA_P2P_CLI_DBS_1x1: STA & P2P CLI connection on DBS + * using 1x1 + * @PM_STA_P2P_CLI_DBS_2x2: STA & P2P CLI connection on DBS + * using 2x2 + * @PM_STA_P2P_CLI_SBS_5_1x1: STA & P2P CLI connection on 5G + * SBS using 1x1 + * @PM_STA_P2P_CLI_SBS_5_2x2: STA & P2P CLI connection on 5G + * SBS using 2x2 + * @PM_P2P_GO_P2P_CLI_SCC_24_1x1: P2P GO & CLI connection on + * SCC using 1x1@2.4 Ghz + * @PM_P2P_GO_P2P_CLI_SCC_24_2x2: P2P GO & CLI connection on + * SCC using 2x2@2.4 Ghz + * @PM_P2P_GO_P2P_CLI_MCC_24_1x1: P2P GO & CLI connection on + * MCC using 1x1@2.4 Ghz + * @PM_P2P_GO_P2P_CLI_MCC_24_2x2: P2P GO & CLI connection on + * MCC using 2x2@2.4 Ghz + * @PM_P2P_GO_P2P_CLI_SCC_5_1x1: P2P GO & CLI connection on + * SCC using 1x1@5 Ghz + * @PM_P2P_GO_P2P_CLI_SCC_5_2x2: P2P GO & CLI connection on + * SCC using 2x2@5 Ghz + * @PM_P2P_GO_P2P_CLI_MCC_5_1x1: P2P GO & CLI connection on + * MCC using 1x1@5 Ghz + * @PM_P2P_GO_P2P_CLI_MCC_5_2x2: P2P GO & CLI connection on + * MCC using 2x2@5 Ghz + * @PM_P2P_GO_P2P_CLI_MCC_24_5_1x1: + * @PM_P2P_GO_P2P_CLI_MCC_24_5_2x2: + * @PM_P2P_GO_P2P_CLI_DBS_1x1: P2P GO & CLI connection on DBS + * using 1x1 + * @PM_P2P_GO_P2P_CLI_DBS_2x2: P2P GO & P2P CLI connection + * on DBS using 2x2 + * @PM_P2P_GO_P2P_CLI_SBS_5_1x1: P2P GO & P2P CLI connection + * on 5G SBS using 1x1 + * @PM_P2P_GO_P2P_CLI_SBS_5_2x2: P2P GO & P2P CLI connection + * on 5G SBS using 2x2 + * @PM_P2P_GO_SAP_SCC_24_1x1: P2P GO & SAP connection on + * SCC using 1x1@2.4 Ghz + * @PM_P2P_GO_SAP_SCC_24_2x2: P2P GO & SAP connection on + * SCC using 2x2@2.4 Ghz + * @PM_P2P_GO_SAP_MCC_24_1x1: P2P GO & SAP connection on + * MCC using 1x1@2.4 Ghz + * @PM_P2P_GO_SAP_MCC_24_2x2: P2P GO & SAP connection on + * MCC using 2x2@2.4 Ghz + * @PM_P2P_GO_SAP_SCC_5_1x1: P2P GO & SAP connection on + * SCC using 1x1@5 Ghz + * @PM_P2P_GO_SAP_SCC_5_2x2: P2P GO & SAP connection on + * SCC using 2x2@5 Ghz + * @PM_P2P_GO_SAP_MCC_5_1x1: P2P GO & SAP connection on + * MCC using 1x1@5 Ghz + * @PM_P2P_GO_SAP_MCC_5_2x2: P2P GO & SAP connection on + * MCC using 2x2@5 Ghz + * @PM_P2P_GO_SAP_MCC_24_5_1x1: + * @PM_P2P_GO_SAP_MCC_24_5_2x2: + * @PM_P2P_GO_SAP_DBS_1x1: P2P GO & SAP connection on DBS using + * 1x1 + * @PM_P2P_GO_SAP_DBS_2x2: P2P GO & SAP connection on DBS using + * 2x2 + * @PM_P2P_GO_SAP_SBS_5_1x1: P2P GO & SAP connection on 5G SBS + * using 1x1 + * @PM_P2P_GO_SAP_SBS_5_2x2: P2P GO & SAP connection on 5G SBS + * using 2x2 + * @PM_P2P_GO_P2P_GO_SCC_24_1x1: P2P GO & P2P GO SCC on 2.4G using 1x1 + * @PM_P2P_GO_P2P_GO_SCC_24_2x2: P2P GO & P2P GO SCC on 2.4G using 2x2 + * @PM_P2P_GO_P2P_GO_MCC_24_1x1: P2P GO & P2P GO MCC on 2.4G using 1x1 + * @PM_P2P_GO_P2P_GO_MCC_24_2x2: P2P GO & P2P GO MCC on 2.4G using 2x2 + * @PM_P2P_GO_P2P_GO_SCC_5_1x1: P2P GO & P2P GO SCC on 5G using 1x1 + * @PM_P2P_GO_P2P_GO_SCC_5_2x2: P2P GO & P2P GO SCC on 5G using 2x2 + * @PM_P2P_GO_P2P_GO_MCC_5_1x1: P2P GO & P2P GO MCC on 5G using 1x1 + * @PM_P2P_GO_P2P_GO_MCC_5_2x2: P2P GO & P2P GO MCC on 5G using 2x2 + * @PM_P2P_GO_P2P_GO_MCC_24_5_1x1: P2P GO 2.4G & P2P GO 5G dual band MCC + * using 1x1 + * @PM_P2P_GO_P2P_GO_MCC_24_5_2x2: P2P GO 2.4G & P2P GO 5G dual band MCC + * using 2x2 + * @PM_P2P_GO_P2P_GO_DBS_1x1: P2P GO & P2P GO on DBS using 1x1 + * @PM_P2P_GO_P2P_GO_DBS_2x2: P2P GO & P2P GO on DBS using 2x2 + * @PM_P2P_GO_P2P_GO_SBS_5_1x1: P2P GO & P2P GO on SBS using 1x1 + * @PM_P2P_GO_P2P_GO_SBS_5_2x2: P2P GO & P2P GO on SBS using 2x2 + * @PM_P2P_CLI_SAP_SCC_24_1x1: CLI & SAP connection on SCC using + * 1x1@2.4 Ghz + * @PM_P2P_CLI_SAP_SCC_24_2x2: CLI & SAP connection on SCC using + * 2x2@2.4 Ghz + * @PM_P2P_CLI_SAP_MCC_24_1x1: CLI & SAP connection on MCC using + * 1x1@2.4 Ghz + * @PM_P2P_CLI_SAP_MCC_24_2x2: CLI & SAP connection on MCC using + * 2x2@2.4 Ghz + * @PM_P2P_CLI_SAP_SCC_5_1x1: CLI & SAP connection on SCC using + * 1x1@5 Ghz + * @PM_P2P_CLI_SAP_SCC_5_2x2: CLI & SAP connection on SCC using + * 2x2@5 Ghz + * @PM_P2P_CLI_SAP_MCC_5_1x1: CLI & SAP connection on MCC using + * 1x1@5 Ghz + * @PM_P2P_CLI_SAP_MCC_5_2x2: CLI & SAP connection on MCC using + * 2x2@5 Ghz + * @PM_P2P_CLI_SAP_MCC_24_5_1x1: CLI and SAP connecting on MCC + * in 2.4 and 5GHz 1x1 + * @PM_P2P_CLI_SAP_MCC_24_5_2x2: CLI and SAP connecting on MCC + * in 2.4 and 5GHz 2x2 + * @PM_P2P_CLI_SAP_DBS_1x1: CLI & SAP connection on DBS using 1x1 + * @PM_P2P_CLI_SAP_DBS_2x2: P2P CLI & SAP connection on DBS using + * 2x2 + * @PM_P2P_CLI_SAP_SBS_5_1x1: P2P CLI & SAP connection on 5G SBS + * using 1x1 + * @PM_P2P_CLI_SAP_SBS_5_2x2: P2P CLI & SAP connection on 5G SBS + * using 2x2 + * @PM_P2P_CLI_P2P_CLI_SCC_24_1x1: P2P CLI & P2P CLI SCC on 2.4G using 1x1 + * @PM_P2P_CLI_P2P_CLI_SCC_24_2x2: P2P CLI & P2P CLI SCC on 2.4G using 2x2 + * @PM_P2P_CLI_P2P_CLI_MCC_24_1x1: P2P CLI & P2P CLI MCC on 2.4G using 1x1 + * @PM_P2P_CLI_P2P_CLI_MCC_24_2x2: P2P CLI & P2P CLI MCC on 2.4G using 2x2 + * @PM_P2P_CLI_P2P_CLI_SCC_5_1x1: P2P CLI & P2P CLI SCC on 5G using 1x1 + * @PM_P2P_CLI_P2P_CLI_SCC_5_2x2: P2P CLI & P2P CLI SCC on 5G using 2x2 + * @PM_P2P_CLI_P2P_CLI_MCC_5_1x1: P2P CLI & P2P CLI MCC on 5G using 1x1 + * @PM_P2P_CLI_P2P_CLI_MCC_5_2x2: P2P CLI & P2P CLI MCC on 5G using 2x2 + * @PM_P2P_CLI_P2P_CLI_MCC_24_5_1x1: P2P CLI 2.4G & P2P CLI 5G dual band MCC + * using 1x1 + * @PM_P2P_CLI_P2P_CLI_MCC_24_5_2x2: P2P CLI 2.4G & P2P CLI 5G dual band MCC + * using 2x2 + * @PM_P2P_CLI_P2P_CLI_DBS_1x1: P2P CLI & P2P CLI on DBS using 1x1 + * @PM_P2P_CLI_P2P_CLI_DBS_2x2: P2P CLI & P2P CLI on DBS using 2x2 + * @PM_P2P_CLI_P2P_CLI_SBS_5_1x1: P2P CLI & P2P CLI on SBS using 1x1 + * @PM_P2P_CLI_P2P_CLI_SBS_5_2x2: P2P CLI & P2P CLI on SBS using 2x2 + * @PM_SAP_SAP_SCC_24_1x1: SAP & SAP connection on + * SCC using 1x1@2.4 Ghz + * @PM_SAP_SAP_SCC_24_2x2: SAP & SAP connection on + * SCC using 2x2@2.4 Ghz + * @PM_SAP_SAP_MCC_24_1x1: SAP & SAP connection on + * MCC using 1x1@2.4 Ghz + * @PM_SAP_SAP_MCC_24_2x2: SAP & SAP connection on + * MCC using 2x2@2.4 Ghz + * @PM_SAP_SAP_SCC_5_1x1: SAP & SAP connection on + * SCC using 1x1@5 Ghz + * @PM_SAP_SAP_SCC_5_2x2: SAP & SAP connection on + * SCC using 2x2@5 Ghz + * @PM_SAP_SAP_MCC_5_1x1: SAP & SAP connection on + * MCC using 1x1@5 Ghz + * @PM_SAP_SAP_MCC_5_2x2: SAP & SAP connection on + * MCC using 2x2@5 Ghz + * @PM_SAP_SAP_MCC_24_5_1x1: SAP & SAP connection on + * MCC in 2.4 and 5GHz 1x1 + * @PM_SAP_SAP_MCC_24_5_2x2: SAP & SAP connection on + * MCC in 2.4 and 5GHz 2x2 + * @PM_SAP_SAP_DBS_1x1: SAP & SAP connection on DBS using + * 1x1 + * @PM_SAP_SAP_DBS_2x2: SAP & SAP connection on DBS using 2x2 + * @PM_SAP_SAP_SBS_5_1x1: SAP & SAP connection on 5G SBS using 1x1 + * @PM_SAP_SAP_SBS_5_2x2: SAP & SAP connection on 5G SBS using 2x2 + * @PM_SAP_NAN_DISC_SCC_24_1x1: SAP & NAN connection on + * SCC using 1x1@2.4 Ghz + * @PM_SAP_NAN_DISC_SCC_24_2x2: SAP & NAN connection on + * SCC using 2x2@2.4 Ghz + * @PM_SAP_NAN_DISC_MCC_24_1x1: SAP & NAN connection on + * MCC using 1x1@2.4 Ghz + * @PM_SAP_NAN_DISC_MCC_24_2x2: SAP & NAN connection on + * SCC using 2x2@2.4 Ghz + * @PM_SAP_NAN_DISC_DBS_1x1: SAP & NAN connection on DBS using 1x1 + * @PM_SAP_NAN_DISC_DBS_2x2: SAP & NAN connection on DBS using 2x2 + * @PM_STA_STA_SCC_24_1x1: STA & STA connection on + * SCC using 1x1@2.4 Ghz + * @PM_STA_STA_SCC_24_2x2: STA & STA connection on + * SCC using 2x2@2.4 Ghz + * @PM_STA_STA_MCC_24_1x1: STA & STA connection on + * MCC using 1x1@2.4 Ghz + * @PM_STA_STA_MCC_24_2x2: STA & STA connection on + * MCC using 2x2@2.4 Ghz + * @PM_STA_STA_SCC_5_1x1: STA & STA connection on + * SCC using 1x1@5 Ghz + * @PM_STA_STA_SCC_5_2x2: STA & STA connection on + * SCC using 2x2@5 Ghz + * @PM_STA_STA_MCC_5_1x1: STA & STA connection on + * MCC using 1x1@5 Ghz + * @PM_STA_STA_MCC_5_2x2: STA & STA connection on + * MCC using 2x2@5 Ghz + * @PM_STA_STA_MCC_24_5_1x1: STA & STA connection on + * MCC in 2.4 and 5GHz 1x1 + * @PM_STA_STA_MCC_24_5_2x2: STA & STA connection on + * MCC in 2.4 and 5GHz 2x2 + * @PM_STA_STA_DBS_1x1: STA & STA connection on DBS using + * 1x1 + * @PM_STA_STA_DBS_2x2: STA & STA connection on DBS using 2x2 + * @PM_STA_STA_SBS_5_1x1: STA & STA connection on 5G SBS using 1x1 + * @PM_STA_STA_SBS_5_2x2: STA & STA connection on 5G SBS using 2x2 + * @PM_STA_NAN_DISC_SCC_24_1x1: NAN & STA connection on SCC using 1x1 on 2.4 GHz + * @PM_STA_NAN_DISC_SCC_24_2x2: NAN & STA connection on SCC using 2x2 on 2.4 GHz + * @PM_STA_NAN_DISC_MCC_24_1x1: NAN & STA connection on MCC using 1x1 on 2.4 GHz + * @PM_STA_NAN_DISC_MCC_24_2x2: NAN & STA connection on MCC using 2x2 on 2.4 GHz + * @PM_STA_NAN_DISC_DBS_1x1: NAN & STA connection on DBS using 1x1 + * @PM_STA_NAN_DISC_DBS_2x2: NAN & STA connection on DBS using 2x2 + * @PM_NAN_DISC_NDI_SCC_24_1x1: NAN & NDI connection on SCC using 1x1 on 2.4 GHz + * @PM_NAN_DISC_NDI_SCC_24_2x2: NAN & NDI connection on SCC using 2x2 on 2.4 GHz + * @PM_NAN_DISC_NDI_MCC_24_1x1: NAN & NDI connection on MCC using 1x1 on 2.4 GHz + * @PM_NAN_DISC_NDI_MCC_24_2x2: NAN & NDI connection on MCC using 2x2 on 2.4 GHz + * @PM_NAN_DISC_NDI_DBS_1x1: NAN & NDI connection on DBS using 1x1 + * @PM_NAN_DISC_NDI_DBS_2x2: NAN & NDI connection on DBS using 2x2 + * @PM_STA_24_LL_LT_SAP_DBS_1x1: STA & LL_LT_SAP connection in DBS using 1x1 + * @PM_STA_24_LL_LT_SAP_DBS_2x2: STA & LL_LT_SAP connection in DBS using 2x2 + * @PM_STA_5_LL_LT_SAP_MCC_1x1: STA & LL_LT_SAP connection in MCC on 5 GHz + * using 1x1 + * @PM_STA_5_LL_LT_SAP_MCC_2x2: STA & LL_LT_SAP connection in MCC on 5 GHz + * using 2x2 + * @PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: STA on 5G low & LL_LT_SAP on 5G high + * connection in SBS using 1x1 + * @PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: STA on 5G low & LL_LT_SAP on 5G high + * connection in SBS using 2x2 + * @PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: STA on 5G high & LL_LT_SAP on 5G low + * connection in SBS using 1x1 + * @PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: STA on 5G high & LL_LT_SAP on 5G low + * connection in SBS using 1x1 + * @PM_SAP_24_LL_LT_SAP_DBS_1x1: SAP & LL_LT_SAP connection in DBS using 1x1 + * @PM_SAP_24_LL_LT_SAP_DBS_2x2: SAP & LL_LT_SAP connection in DBS using 2x2 + * @PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: SAP on 5G low & LL_LT_SAP on 5G high + * connection in SBS using 1x1 + * @PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: SAP on 5G low & LL_LT_SAP on 5G high + * connection in SBS using 2x2 + * @PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: SAP on 5G high & LL_LT_SAP on 5G low + * connection in SBS using 1x1 + * @PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: SAP on 5G high & LL_LT_SAP on 5G low + * connection in SBS using 1x1 + * @PM_P2P_GO_24_LL_LT_SAP_DBS_1x1: P2P GO & LL_LT_SAP connection in DBS + * using 1x1 + * @PM_P2P_GO_24_LL_LT_SAP_DBS_2x2: P2P GO & LL_LT_SAP connection in DBS + * using 2x2 + * @PM_P2P_GO_5_LL_LT_SAP_MCC_1x1: GO & LL_LT_SAP connection in MCC using 1x1 + * @PM_P2P_GO_5_LL_LT_SAP_MCC_2x2: GO & LL_LT_SAP connection in MCC using 2x2 + * @PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: GO on 5G low & LL_LT_SAP on 5G + * high connection in SBS using 1x1 + * @PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: GO on 5G low & LL_LT_SAP on 5G + * high connection in SBS using 2x2 + * @PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: GO on 5G high & LL_LT_SAP on 5G + * low connection in SBS using 1x1 + * @PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: GO on 5G high & LL_LT_SAP on 5G + * low connection in SBS using 2x2 + * @PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1: CLI & LL_LT_SAP connection in DBS using 1x1 + * @PM_P2P_CLI_24_LL_LT_SAP_DBS_2x2: CLI & LL_LT_SAP connection in DBS using 2x2 + * @PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1: CLI & LL_LT_SAP connection in MCC on 5 GHz + * using 1x1 + * @PM_P2P_CLI_5_LL_LT_SAP_MCC_2x2: CLI & LL_LT_SAP connection in MCC on 5 GHz + * using 2x2 + * @PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1: CLI on 5G low & LL_LT_SAP on 5G + * high connection in SBS using 1x1 + * @PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2: CLI on 5G low & LL_LT_SAP on 5G + * high connection in SBS using 2x2 + * @PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1: CLI on 5G high & LL_LT_SAP on 5G + * low connection in SBS using 1x1 + * @PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2: CLI on 5G high & LL_LT_SAP on 5G + * low connection in SBS using 2x2 + * @PM_MAX_TWO_CONNECTION_MODE: Max enumeration + * + * These are generic IDs that identify the various roles in the + * software system + */ +enum policy_mgr_two_connection_mode { + PM_STA_SAP_SCC_24_1x1 = 0, + PM_STA_SAP_SCC_24_2x2, + PM_STA_SAP_MCC_24_1x1, + PM_STA_SAP_MCC_24_2x2, + PM_STA_SAP_SCC_5_1x1, + PM_STA_SAP_SCC_5_2x2, + PM_STA_SAP_MCC_5_1x1, + PM_STA_SAP_MCC_5_2x2, + PM_STA_SAP_MCC_24_5_1x1, + PM_STA_SAP_MCC_24_5_2x2, + PM_STA_SAP_DBS_1x1, + PM_STA_SAP_DBS_2x2, + PM_STA_SAP_SBS_5_1x1, + PM_STA_SAP_SBS_5_2x2 = PM_STA_SAP_SBS_5_1x1, + PM_STA_P2P_GO_SCC_24_1x1, + PM_STA_P2P_GO_SCC_24_2x2, + PM_STA_P2P_GO_MCC_24_1x1, + PM_STA_P2P_GO_MCC_24_2x2, + PM_STA_P2P_GO_SCC_5_1x1, + PM_STA_P2P_GO_SCC_5_2x2, + PM_STA_P2P_GO_MCC_5_1x1, + PM_STA_P2P_GO_MCC_5_2x2, + PM_STA_P2P_GO_MCC_24_5_1x1, + PM_STA_P2P_GO_MCC_24_5_2x2, + PM_STA_P2P_GO_DBS_1x1, + PM_STA_P2P_GO_DBS_2x2, + PM_STA_P2P_GO_SBS_5_1x1, + PM_STA_P2P_GO_SBS_5_2x2 = PM_STA_P2P_GO_SBS_5_1x1, + PM_STA_P2P_CLI_SCC_24_1x1, + PM_STA_P2P_CLI_SCC_24_2x2, + PM_STA_P2P_CLI_MCC_24_1x1, + PM_STA_P2P_CLI_MCC_24_2x2, + PM_STA_P2P_CLI_SCC_5_1x1, + PM_STA_P2P_CLI_SCC_5_2x2, + PM_STA_P2P_CLI_MCC_5_1x1, + PM_STA_P2P_CLI_MCC_5_2x2, + PM_STA_P2P_CLI_MCC_24_5_1x1, + PM_STA_P2P_CLI_MCC_24_5_2x2, + PM_STA_P2P_CLI_DBS_1x1, + PM_STA_P2P_CLI_DBS_2x2, + PM_STA_P2P_CLI_SBS_5_1x1, + PM_STA_P2P_CLI_SBS_5_2x2 = PM_STA_P2P_CLI_SBS_5_1x1, + PM_P2P_GO_P2P_CLI_SCC_24_1x1, + PM_P2P_GO_P2P_CLI_SCC_24_2x2, + PM_P2P_GO_P2P_CLI_MCC_24_1x1, + PM_P2P_GO_P2P_CLI_MCC_24_2x2, + PM_P2P_GO_P2P_CLI_SCC_5_1x1, + PM_P2P_GO_P2P_CLI_SCC_5_2x2, + PM_P2P_GO_P2P_CLI_MCC_5_1x1, + PM_P2P_GO_P2P_CLI_MCC_5_2x2, + PM_P2P_GO_P2P_CLI_MCC_24_5_1x1, + PM_P2P_GO_P2P_CLI_MCC_24_5_2x2, + PM_P2P_GO_P2P_CLI_DBS_1x1, + PM_P2P_GO_P2P_CLI_DBS_2x2, + PM_P2P_GO_P2P_CLI_SBS_5_1x1, + PM_P2P_GO_P2P_CLI_SBS_5_2x2 = PM_P2P_GO_P2P_CLI_SBS_5_1x1, + PM_P2P_GO_SAP_SCC_24_1x1, + PM_P2P_GO_SAP_SCC_24_2x2, + PM_P2P_GO_SAP_MCC_24_1x1, + PM_P2P_GO_SAP_MCC_24_2x2, + PM_P2P_GO_SAP_SCC_5_1x1, + PM_P2P_GO_SAP_SCC_5_2x2, + PM_P2P_GO_SAP_MCC_5_1x1, + PM_P2P_GO_SAP_MCC_5_2x2, + PM_P2P_GO_SAP_MCC_24_5_1x1, + PM_P2P_GO_SAP_MCC_24_5_2x2, + PM_P2P_GO_SAP_DBS_1x1, + PM_P2P_GO_SAP_DBS_2x2, + PM_P2P_GO_SAP_SBS_5_1x1, + PM_P2P_GO_SAP_SBS_5_2x2 = PM_P2P_GO_SAP_SBS_5_1x1, + PM_P2P_GO_P2P_GO_SCC_24_1x1, + PM_P2P_GO_P2P_GO_SCC_24_2x2, + PM_P2P_GO_P2P_GO_MCC_24_1x1, + PM_P2P_GO_P2P_GO_MCC_24_2x2, + PM_P2P_GO_P2P_GO_SCC_5_1x1, + PM_P2P_GO_P2P_GO_SCC_5_2x2, + PM_P2P_GO_P2P_GO_MCC_5_1x1, + PM_P2P_GO_P2P_GO_MCC_5_2x2, + PM_P2P_GO_P2P_GO_MCC_24_5_1x1, + PM_P2P_GO_P2P_GO_MCC_24_5_2x2, + PM_P2P_GO_P2P_GO_DBS_1x1, + PM_P2P_GO_P2P_GO_DBS_2x2, + PM_P2P_GO_P2P_GO_SBS_5_1x1, + PM_P2P_GO_P2P_GO_SBS_5_2x2 = PM_P2P_GO_P2P_GO_SBS_5_1x1, + PM_P2P_CLI_SAP_SCC_24_1x1, + PM_P2P_CLI_SAP_SCC_24_2x2, + PM_P2P_CLI_SAP_MCC_24_1x1, + PM_P2P_CLI_SAP_MCC_24_2x2, + PM_P2P_CLI_SAP_SCC_5_1x1, + PM_P2P_CLI_SAP_SCC_5_2x2, + PM_P2P_CLI_SAP_MCC_5_1x1, + PM_P2P_CLI_SAP_MCC_5_2x2, + PM_P2P_CLI_SAP_MCC_24_5_1x1, + PM_P2P_CLI_SAP_MCC_24_5_2x2, + PM_P2P_CLI_SAP_DBS_1x1, + PM_P2P_CLI_SAP_DBS_2x2, + PM_P2P_CLI_SAP_SBS_5_1x1, + PM_P2P_CLI_SAP_SBS_5_2x2 = PM_P2P_CLI_SAP_SBS_5_1x1, + PM_P2P_CLI_P2P_CLI_SCC_24_1x1, + PM_P2P_CLI_P2P_CLI_SCC_24_2x2, + PM_P2P_CLI_P2P_CLI_MCC_24_1x1, + PM_P2P_CLI_P2P_CLI_MCC_24_2x2, + PM_P2P_CLI_P2P_CLI_SCC_5_1x1, + PM_P2P_CLI_P2P_CLI_SCC_5_2x2, + PM_P2P_CLI_P2P_CLI_MCC_5_1x1, + PM_P2P_CLI_P2P_CLI_MCC_5_2x2, + PM_P2P_CLI_P2P_CLI_MCC_24_5_1x1, + PM_P2P_CLI_P2P_CLI_MCC_24_5_2x2, + PM_P2P_CLI_P2P_CLI_DBS_1x1, + PM_P2P_CLI_P2P_CLI_DBS_2x2, + PM_P2P_CLI_P2P_CLI_SBS_5_1x1, + PM_P2P_CLI_P2P_CLI_SBS_5_2x2 = PM_P2P_CLI_P2P_CLI_SBS_5_1x1, + PM_SAP_SAP_SCC_24_1x1, + PM_SAP_SAP_SCC_24_2x2, + PM_SAP_SAP_MCC_24_1x1, + PM_SAP_SAP_MCC_24_2x2, + PM_SAP_SAP_SCC_5_1x1, + PM_SAP_SAP_SCC_5_2x2, + PM_SAP_SAP_MCC_5_1x1, + PM_SAP_SAP_MCC_5_2x2, + PM_SAP_SAP_MCC_24_5_1x1, + PM_SAP_SAP_MCC_24_5_2x2, + PM_SAP_SAP_DBS_1x1, + PM_SAP_SAP_DBS_2x2, + PM_SAP_SAP_SBS_5_1x1, + PM_SAP_SAP_SBS_5_2x2 = PM_SAP_SAP_SBS_5_1x1, + PM_SAP_NAN_DISC_SCC_24_1x1, + PM_SAP_NAN_DISC_SCC_24_2x2, + PM_SAP_NAN_DISC_MCC_24_1x1, + PM_SAP_NAN_DISC_MCC_24_2x2, + PM_SAP_NAN_DISC_DBS_1x1, + PM_SAP_NAN_DISC_DBS_2x2, + PM_STA_STA_SCC_24_1x1, + PM_STA_STA_SCC_24_2x2, + PM_STA_STA_MCC_24_1x1, + PM_STA_STA_MCC_24_2x2, + PM_STA_STA_SCC_5_1x1, + PM_STA_STA_SCC_5_2x2, + PM_STA_STA_MCC_5_1x1, + PM_STA_STA_MCC_5_2x2, + PM_STA_STA_MCC_24_5_1x1, + PM_STA_STA_MCC_24_5_2x2, + PM_STA_STA_DBS_1x1, + PM_STA_STA_DBS_2x2, + PM_STA_STA_SBS_5_1x1, + PM_STA_STA_SBS_5_2x2 = PM_STA_STA_SBS_5_1x1, + PM_STA_NAN_DISC_SCC_24_1x1, + PM_STA_NAN_DISC_SCC_24_2x2, + PM_STA_NAN_DISC_MCC_24_1x1, + PM_STA_NAN_DISC_MCC_24_2x2, + PM_STA_NAN_DISC_DBS_1x1, + PM_STA_NAN_DISC_DBS_2x2, + PM_NAN_DISC_NDI_SCC_24_1x1, + PM_NAN_DISC_NDI_SCC_24_2x2, + PM_NAN_DISC_NDI_MCC_24_1x1, + PM_NAN_DISC_NDI_MCC_24_2x2, + PM_NAN_DISC_NDI_DBS_1x1, + PM_NAN_DISC_NDI_DBS_2x2, + PM_STA_24_LL_LT_SAP_DBS_1x1, + PM_STA_24_LL_LT_SAP_DBS_2x2 = PM_STA_24_LL_LT_SAP_DBS_1x1, + PM_STA_5_LL_LT_SAP_MCC_1x1, + PM_STA_5_LL_LT_SAP_MCC_2x2 = PM_STA_5_LL_LT_SAP_MCC_1x1, + PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 = + PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 = + PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_SAP_24_LL_LT_SAP_DBS_1x1, + PM_SAP_24_LL_LT_SAP_DBS_2x2 = PM_SAP_24_LL_LT_SAP_DBS_1x1, + PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 = + PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 = + PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_P2P_GO_24_LL_LT_SAP_DBS_1x1, + PM_P2P_GO_24_LL_LT_SAP_DBS_2x2 = PM_P2P_GO_24_LL_LT_SAP_DBS_1x1, + PM_P2P_GO_5_LL_LT_SAP_MCC_1x1, + PM_P2P_GO_5_LL_LT_SAP_MCC_2x2 = PM_P2P_GO_5_LL_LT_SAP_MCC_1x1, + PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 = + PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 = + PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1, + PM_P2P_CLI_24_LL_LT_SAP_DBS_2x2 = PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1, + PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1, + PM_P2P_CLI_5_LL_LT_SAP_MCC_2x2 = PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1, + PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2 = + PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1, + PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2 = + PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1, + + PM_MAX_TWO_CONNECTION_MODE +}; + +#ifdef FEATURE_FOURTH_CONNECTION +/** + * enum policy_mgr_three_connection_mode - Combination of first three + * connections type, concurrency state, band used. + * + * @PM_STA_SAP_SCC_24_SAP_5_DBS: STA & SAP connection on 2.4 GHZ, another + * SAP on 5 GHZ + * @PM_STA_SAP_SCC_5_SAP_24_DBS: STA & SAP connection on 5 GHZ, + * another SAP on 2.4 GHZ + * @PM_24_SCC_MCC_PLUS_5_DBS: ANY 2 link on 2.4 GHZ SCC/MCC mac and one link on + * 5 GHZ doing DBS + * @PM_STA_SAP_24_STA_5_DBS: STA & SAP connection on 2.4 GHZ SCC/MCC, + * another STA on 5 GHZ + * @PM_5_SCC_MCC_PLUS_24_DBS: ANY 2 link on 5 GHZ SCC/MCC mac and one link on + * 2.4 GHZ doing DBS + * @PM_STA_SAP_5_STA_24_DBS: STA & SAP connection on 5 GHZ SCC/MCC, + * STA on 2.4 GHZ + * @PM_STA_STA_5_SAP_24_DBS: STA & STA connection on 5 GHZ SCC/MCC, + * SAP on 2.4 GHZ + * @PM_NAN_DISC_SAP_SCC_24_NDI_5_DBS: NAN_DISC & SAP connection on 2.4 Ghz SCC, + * NDI/NDP on 5 G + * @PM_NAN_DISC_NDI_SCC_24_SAP_5_DBS: NAN_DISC & NDI/NDP connection on 2.4 Ghz + * SCC, SAP on 5 G + * @PM_SAP_NDI_SCC_5_NAN_DISC_24_DBS: SAP & NDI/NDP connection on 5 Ghz, + * NAN_DISC on 24 Ghz + * @PM_NAN_DISC_STA_24_NDI_5_DBS: STA and NAN Disc on 2.4Ghz and NDI on 5ghz DBS + * @PM_NAN_DISC_NDI_24_STA_5_DBS: NDI and NAN Disc on 2.4Ghz and STA on 5ghz DBS + * @PM_STA_NDI_5_NAN_DISC_24_DBS: STA, NDI on 5ghz and NAN Disc on 2.4Ghz DBS + * @PM_STA_NDI_NAN_DISC_24_SMM: STA, NDI, NAN Disc all on 2.4ghz SMM + * @PM_NAN_DISC_NDI_24_NDI_5_DBS: NDI and NAN Disc on 2.4Ghz and second NDI in + * 5ghz DBS + * @PM_NDI_NDI_5_NAN_DISC_24_DBS: Both NDI on 5ghz and NAN Disc on 2.4Ghz DBS + * @PM_NDI_NDI_NAN_DISC_24_SMM: Both NDI, NAN Disc on 2.4ghz SMM + * @PM_SAP_SAP_SCC_24_SAP_5_DBS: Both SAP on 2.4Ghz and another SAP on 5Ghz DBS + * @PM_SAP_SAP_SCC_5_SAP_24_DBS: Both SAP on 5Ghz and another SAP on 2.4Ghz DBS + * @PM_STA_STA_5_NAN_DISC_24_DBS: Both STA on 5Ghz and NAN Disc on 2.4Ghz DBS + * @PM_NAN_DISC_24_STA_STA_5_DBS: NAN Disc on 2.4Ghz and both STA on 5Ghz DBS + * @PM_STA_STA_24_NAN_DISC_24_SMM: Both STA on 2.4Ghz and NAN Disc on 2.4Ghz SMM + * @PM_NAN_DISC_24_STA_STA_24_SMM: NAN Disc on 2.4Ghz and both STA on 2.4Ghz SMM + * @PM_STA_24_STA_5_NAN_DISC_24_SMM: First STA on 2.4Ghz and second STA on 5Ghz + * and NAN Disc on 2.4Ghz SMM + * @PM_STA_24_STA_5_NAN_DISC_24_DBS: First STA on 2.4Ghz and second STA on 5Ghz + * and NAN Disc on 2.4Ghz DBS + * @PM_STA_5_STA_24_NAN_DISC_24_SMM: First STA on 5Ghz and second STA on 2.4Ghz + * and NAN Disc on 2.4Ghz SMM + * @PM_STA_5_STA_24_NAN_DISC_24_DBS: First STA on 5Ghz and second STA on 2.4Ghz + * and NAN Disc on 2.4Ghz DBS + * @PM_NAN_DISC_24_STA_5_STA_24_SMM: NAN Disc on 2.4Ghz and first STA on 5Ghz + * and second STA on 2.4Ghz SMM + * @PM_NAN_DISC_24_STA_5_STA_24_DBS: NAN Disc on 2.4Ghz and first STA on 5Ghz + * and second STA on 2.4Ghz DBS + * @PM_NAN_DISC_24_STA_24_STA_5_SMM: NAN Disc on 2.4Ghz and first STA on 2.4Ghz + * and second STA on 5Ghz SMM + * @PM_NAN_DISC_24_STA_24_STA_5_DBS: NAN Disc on 2.4Ghz and first STA on 2.4Ghz + * and second STA on 5Ghz DBS + * @PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS: ANY 2 link on 5 GHZ high mac + * and one link on 5 GHZ low doing SBS + * @PM_STA_24_SAP_5_HIGH_MCC_STA_5_LOW_SBS : First STA on 2.4 GHZ & SAP on high + * 5 GHZ MCC on mac 0 and second STA on low 5 GHZ on mac1 doing SBS + * @PM_STA_24_STA_5_HIGH_MCC_SAP_5_LOW_SBS : First STA on 2.4 GHZ & second STA + * on high 5 GHZ MCC on mac 0 and SAP on high 5 GHZ on mac1 doing SBS + * @PM_STA_SAP_5_HIGH_STA_5_LOW_SBS : First STA on high 5 GHZ & SAP on high + * 5 GHZ SCC/MCC on mac0 and second STA on low 5 GHZ on mac1 doing SBS + * @PM_STA_5_HIGH_SAP_24_MCC_STA_5_LOW_SBS : First STA on high 5 GHZ & SAP on + * 2.4 GHZ MCC on mac0 and second STA on low 5 GHZ on mac1 doing SBS + * @PM_STA_STA_5_HIGH_MCC_SAP_5_LOW_SBS : First STA on high 5 GHZ & Second STA + * on high 5 GHZ MCC on mac0 and SAP on low 5 GHZ on mac1 doing SBS + * @PM_STA_24_STA_5_MCC_SAP_5_HIGH_SBS: MLO STA 2+5/6 GHz, SAP on 5/6 GHz + * high band, the current hw mode is SBS. + * @PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS: Any 2 link on low 5 GHZ mac + * and one link on high 5 GHZ freq doing SBS + * @PM_STA_24_SAP_5_LOW_MCC_STA_5_HIGH_SBS : First STA on 2.4 GHZ & SAP on low + * 5 GHZ MCC on mac 0 and second STA on high 5 GHZ on mac1 doing SBS + * @PM_STA_24_STA_5_LOW_MCC_SAP_5_HIGH_SBS : First STA on 2.4 & second STA on + * low 5G MCC on mac 0 and SAP on high 5g on mac1 doing SBS + * @PM_STA_SAP_5_LOW_STA_5_HIGH_SBS : First STA on low 5 GHZ & SAP on low 5 GHZ + * SCC/MCC on mac0 and second STA on high 5 GHZ on mac1 doing SBS + * @PM_STA_5_LOW_SAP_24_MCC_STA_5_HIGH_SBS : First STA on low 5 GHZ & SAP on + * 2.4 GHZ MCC on mac0 and second STA on high 5 GHZ on mac1 doing SBS + * @PM_STA_STA_5_LOW_MCC_SAP_5_HIGH_SBS : First STA on high 5 GHZ & Second STA + * on high 5 GHZ MCC on mac0 and SAP on low 5 GHZ on mac1 doing SBS + * @PM_STA_24_STA_5_MCC_SAP_5_LOW_SBS: MLO STA 2+5/6 GHz, SAP on 5/6 GHz + * low band, the current hw mode is SBS. + * @PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS: + * @PM_SAP_24_STA_5_STA_5_LOW_N_HIGH_SHARE_SBS: The 2.4 GHZ SAP creating MCC/SCC + * with STA of low 5 GHZ or high 5 GHZ (dynamic SBS) on mac 0 and one STA on + * high 5 GHZ or low 5 GHZ freq respectively on mac 1 doing SBS + * @PM_STA_24_SAP_5_STA_5_LOW_N_HIGH_SHARE_SBS: The 2.4 GHZ STA creating MCC/SCC + * with SAP of low 5 GHZ or high 5 GHZ (dynamic SBS) on mac 0 and one STA on + * high 5 GHZ or low 5 GHZ freq respectively on mac 1 doing SBS + * @PM_24_5_PLUS_5_LOW_OR_HIGH_SHARE_SBS: (not dynamic SBS) MLO STA 2+5/6 GHz, + * SAP on 5/6 GHz, and target only support 2.4 GHz shared with 5 GHz low band + * or 5 GHz high band but not both. + * @PM_MAX_THREE_CONNECTION_MODE: Maximum enumeration + */ +enum policy_mgr_three_connection_mode { + PM_STA_SAP_SCC_24_SAP_5_DBS, + PM_STA_SAP_SCC_5_SAP_24_DBS, + PM_24_SCC_MCC_PLUS_5_DBS, + PM_STA_SAP_24_STA_5_DBS = PM_24_SCC_MCC_PLUS_5_DBS, + PM_5_SCC_MCC_PLUS_24_DBS, + PM_STA_SAP_5_STA_24_DBS = PM_5_SCC_MCC_PLUS_24_DBS, + PM_STA_STA_5_SAP_24_DBS = PM_5_SCC_MCC_PLUS_24_DBS, + PM_NAN_DISC_SAP_SCC_24_NDI_5_DBS, + PM_NAN_DISC_NDI_SCC_24_SAP_5_DBS, + PM_SAP_NDI_SCC_5_NAN_DISC_24_DBS, + PM_NAN_DISC_STA_24_NDI_5_DBS, + PM_NAN_DISC_NDI_24_STA_5_DBS, + PM_STA_NDI_5_NAN_DISC_24_DBS, + PM_STA_NDI_NAN_DISC_24_SMM, + PM_NAN_DISC_NDI_24_NDI_5_DBS, + PM_NDI_NDI_5_NAN_DISC_24_DBS, + PM_NDI_NDI_NAN_DISC_24_SMM, + PM_SAP_SAP_SCC_24_SAP_5_DBS, + PM_SAP_SAP_SCC_5_SAP_24_DBS, + PM_STA_STA_5_NAN_DISC_24_DBS, + PM_NAN_DISC_24_STA_STA_5_DBS, + PM_STA_STA_24_NAN_DISC_24_SMM, + PM_NAN_DISC_24_STA_STA_24_SMM, + PM_STA_24_STA_5_NAN_DISC_24_SMM, + PM_STA_24_STA_5_NAN_DISC_24_DBS, + PM_STA_5_STA_24_NAN_DISC_24_SMM, + PM_STA_5_STA_24_NAN_DISC_24_DBS, + PM_NAN_DISC_24_STA_5_STA_24_SMM, + PM_NAN_DISC_24_STA_5_STA_24_DBS, + PM_NAN_DISC_24_STA_24_STA_5_SMM, + PM_NAN_DISC_24_STA_24_STA_5_DBS, + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_STA_24_SAP_5_HIGH_MCC_STA_5_LOW_SBS = + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_STA_24_STA_5_HIGH_MCC_SAP_5_LOW_SBS = + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_STA_SAP_5_HIGH_STA_5_LOW_SBS = + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_STA_5_HIGH_SAP_24_MCC_STA_5_LOW_SBS = + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_STA_STA_5_HIGH_MCC_SAP_5_LOW_SBS = + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_STA_24_STA_5_MCC_SAP_5_HIGH_SBS = + PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS, + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_STA_24_SAP_5_LOW_MCC_STA_5_HIGH_SBS = + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_STA_24_STA_5_LOW_MCC_SAP_5_HIGH_SBS = + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_STA_SAP_5_LOW_STA_5_HIGH_SBS = + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_STA_5_LOW_SAP_24_MCC_STA_5_HIGH_SBS = + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_STA_STA_5_LOW_MCC_SAP_5_HIGH_SBS = + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_STA_24_STA_5_MCC_SAP_5_LOW_SBS = + PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS, + PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS, + PM_SAP_24_STA_5_STA_5_LOW_N_HIGH_SHARE_SBS = + PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS, + PM_STA_24_SAP_5_STA_5_LOW_N_HIGH_SHARE_SBS = + PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS, + PM_24_5_PLUS_5_LOW_OR_HIGH_SHARE_SBS, + + PM_MAX_THREE_CONNECTION_MODE, +}; +#endif + +/** + * enum policy_mgr_conc_next_action - actions to be taken on old + * connections. + * + * @PM_NOP: No action + * @PM_DBS: switch to DBS mode + * @PM_DBS_DOWNGRADE: switch to DBS mode & downgrade to 1x1 + * @PM_DBS_UPGRADE: switch to DBS mode & upgrade to 2x2 + * @PM_SINGLE_MAC: switch to MCC/SCC mode + * @PM_SINGLE_MAC_UPGRADE: switch to MCC/SCC mode & upgrade to 2x2 + * @PM_SBS: switch to SBS mode + * @PM_SBS_DOWNGRADE: switch to SBS mode & downgrade to 1x1 + * @PM_DOWNGRADE: downgrade to 1x1 + * @PM_UPGRADE: upgrade to 2x2 + * @PM_DBS1: switch to DBS 1 + * @PM_DBS1_DOWNGRADE: downgrade 2G beaconing entity to 1x1 and switch to DBS1. + * @PM_DBS2: switch to DBS 2 + * @PM_DBS2_DOWNGRADE: downgrade 5G beaconing entity to 1x1 and switch to DBS2. + * @PM_UPGRADE_5G: upgrade 5g beaconing entity to 2x2. + * @PM_UPGRADE_2G: upgrade 2g beaconing entity to 2x2. + * @PM_DOWNGRADE_BW: Downgrade SAP bandwidth. + * @PM_UPGRADE_BW: Upgrade SAP bandwidth. + * @PM_MAX_CONC_NEXT_ACTION: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_conc_next_action { + PM_NOP = 0, + PM_DBS, + PM_DBS_DOWNGRADE, + PM_DBS_UPGRADE, + PM_SINGLE_MAC, + PM_SINGLE_MAC_UPGRADE, + PM_SBS, + PM_SBS_DOWNGRADE, + PM_DOWNGRADE, + PM_UPGRADE, + PM_DBS1, + PM_DBS1_DOWNGRADE, + PM_DBS2, + PM_DBS2_DOWNGRADE, + PM_UPGRADE_5G, + PM_UPGRADE_2G, + PM_DOWNGRADE_BW, + PM_UPGRADE_BW, + + PM_MAX_CONC_NEXT_ACTION +}; + +/** + * enum policy_mgr_band - wifi band. + * + * @POLICY_MGR_BAND_24: 2.4 Ghz band + * @POLICY_MGR_BAND_5: 5 Ghz band + * @POLICY_MGR_ANY: to specify all band + * @POLICY_MGR_MAX_BAND: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_band { + POLICY_MGR_BAND_24 = 0, + POLICY_MGR_BAND_5, + POLICY_MGR_ANY, + POLICY_MGR_MAX_BAND = POLICY_MGR_ANY, +}; + +/** + * enum policy_mgr_conn_update_reason: Reason for conc connection update + * @POLICY_MGR_UPDATE_REASON_TIMER_START: This is to decide whether to start the + * timer or not + * @POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN: Set probable operating channel + * @POLICY_MGR_UPDATE_REASON_START_AP: Start AP + * @POLICY_MGR_UPDATE_REASON_NORMAL_STA: Connection to Normal STA + * @POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC: Opportunistic HW mode update + * @POLICY_MGR_UPDATE_REASON_NSS_UPDATE: NSS update + * @POLICY_MGR_UPDATE_REASON_AFTER_CHANNEL_SWITCH: After Channel switch + * @POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA: Before Channel switch for STA + * @POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_SAP: Before Channel switch for SAP + * @POLICY_MGR_UPDATE_REASON_PRE_CAC: Pre-CAC + * @POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE: In Dual DBS HW, if the vdev based + * 2x2 preference enabled, the vdev down may cause prioritized active + * vdev change, then DBS hw mode may needs to change from one DBS mode + * to the other DBS mode. This reason code indicates such condition. + * @POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY: NAN Discovery related + * @POLICY_MGR_UPDATE_REASON_NDP_UPDATE: NAN Datapath related update + * @POLICY_MGR_UPDATE_REASON_LFR2_ROAM: LFR2 Roaming + * @POLICY_MGR_UPDATE_REASON_STA_CONNECT: STA/CLI connection to peer + * @POLICY_MGR_UPDATE_REASON_LFR3_ROAM: LFR3 Roaming + * @POLICY_MGR_UPDATE_REASON_MAX: Reason code to indicate that it's not a + * valid operation, should always be maintained at the end of enum. + */ +enum policy_mgr_conn_update_reason { + POLICY_MGR_UPDATE_REASON_TIMER_START, + POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN, + POLICY_MGR_UPDATE_REASON_START_AP, + POLICY_MGR_UPDATE_REASON_NORMAL_STA, + POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC, + POLICY_MGR_UPDATE_REASON_NSS_UPDATE, + POLICY_MGR_UPDATE_REASON_AFTER_CHANNEL_SWITCH, + POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA, + POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_SAP, + POLICY_MGR_UPDATE_REASON_PRE_CAC, + POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE, + POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY, + POLICY_MGR_UPDATE_REASON_NDP_UPDATE, + POLICY_MGR_UPDATE_REASON_LFR2_ROAM, + POLICY_MGR_UPDATE_REASON_STA_CONNECT, + POLICY_MGR_UPDATE_REASON_LFR3_ROAM, + POLICY_MGR_UPDATE_REASON_MAX, +}; + +/** + * enum hw_mode_bandwidth - bandwidth of wifi channel. + * @HW_MODE_BW_NONE: no bandwidth configured + * @HW_MODE_5_MHZ: 5 Mhz bandwidth + * @HW_MODE_10_MHZ: 10 Mhz bandwidth + * @HW_MODE_20_MHZ: 20 Mhz bandwidth + * @HW_MODE_40_MHZ: 40 Mhz bandwidth + * @HW_MODE_80_MHZ: 80 Mhz bandwidth + * @HW_MODE_80_PLUS_80_MHZ: 80 Mhz plus 80 Mhz bandwidth + * @HW_MODE_160_MHZ: 160 Mhz bandwidth + * @HW_MODE_320_MHZ: 320 Mhz bandwidth + * @HW_MODE_MAX_BANDWIDTH: Max place holder + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum hw_mode_bandwidth { + HW_MODE_BW_NONE, + HW_MODE_5_MHZ, + HW_MODE_10_MHZ, + HW_MODE_20_MHZ, + HW_MODE_40_MHZ, + HW_MODE_80_MHZ, + HW_MODE_80_PLUS_80_MHZ, + HW_MODE_160_MHZ, + HW_MODE_320_MHZ, + HW_MODE_MAX_BANDWIDTH +}; + +/** + * enum set_hw_mode_status - Status of set HW mode command + * @SET_HW_MODE_STATUS_OK: command successful + * @SET_HW_MODE_STATUS_EINVAL: Requested invalid hw_mode + * @SET_HW_MODE_STATUS_ECANCELED: HW mode change cancelled + * @SET_HW_MODE_STATUS_ENOTSUP: HW mode not supported + * @SET_HW_MODE_STATUS_EHARDWARE: HW mode change prevented by hardware + * @SET_HW_MODE_STATUS_EPENDING: HW mode change is pending + * @SET_HW_MODE_STATUS_ECOEX: HW mode change conflict with Coex + * @SET_HW_MODE_STATUS_ALREADY: Requested hw mode is already applied to FW. + */ +enum set_hw_mode_status { + SET_HW_MODE_STATUS_OK, + SET_HW_MODE_STATUS_EINVAL, + SET_HW_MODE_STATUS_ECANCELED, + SET_HW_MODE_STATUS_ENOTSUP, + SET_HW_MODE_STATUS_EHARDWARE, + SET_HW_MODE_STATUS_EPENDING, + SET_HW_MODE_STATUS_ECOEX, + SET_HW_MODE_STATUS_ALREADY, +}; + +typedef void (*dual_mac_cb)(enum set_hw_mode_status status, + uint32_t scan_config, + uint32_t fw_mode_config); +/** + * enum policy_mgr_hw_mode_change - identify the HW mode switching to. + * + * @POLICY_MGR_HW_MODE_NOT_IN_PROGRESS: HW mode change not in progress + * @POLICY_MGR_SMM_IN_PROGRESS: switching to SMM mode + * @POLICY_MGR_DBS_IN_PROGRESS: switching to DBS mode + * @POLICY_MGR_SBS_IN_PROGRESS: switching to SBS mode + * + * These are generic IDs that identify the various roles + * in the software system + */ +enum policy_mgr_hw_mode_change { + POLICY_MGR_HW_MODE_NOT_IN_PROGRESS = 0, + POLICY_MGR_SMM_IN_PROGRESS, + POLICY_MGR_DBS_IN_PROGRESS, + POLICY_MGR_SBS_IN_PROGRESS +}; + +/** + * enum dbs_support - structure to define INI values and their meaning + * + * @ENABLE_DBS_CXN_AND_SCAN: Enable DBS support for connection and scan + * @DISABLE_DBS_CXN_AND_SCAN: Disable DBS support for connection and scan + * @DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN: disable dbs support for + * connection but keep dbs support for scan + * @DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF: disable dbs support + * for connection but keep dbs for scan but switch off the async scan + * @ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF: enable dbs support for + * connection and scan but switch off the async scan + * @ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN: Enable DBS support for connection and + * disable DBS support for scan + * @ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN: Enable DBS + * support for connection and disable simultaneous scan from + * upper layer (DBS scan remains enabled in FW) + */ +enum dbs_support { + ENABLE_DBS_CXN_AND_SCAN, + DISABLE_DBS_CXN_AND_SCAN, + DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN, + DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF, + ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF, + ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN, + ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN, +}; + +/** + * enum conn_6ghz_flag - structure to define connection 6ghz capable info + * in policy mgr conn info struct + * + * @CONN_6GHZ_FLAG_VALID: The 6ghz flag is valid (has been initialized) + * @CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED: AP is configured in 6ghz band capable + * by user: + * a. ACS channel range includes 6ghz. + * b. SAP is started in 6ghz fix channel. + * @CONN_6GHZ_FLAG_SECURITY_ALLOWED: AP has security mode which is permitted in + * 6ghz band. + * @CONN_6GHZ_FLAG_NO_LEGACY_CLIENT: AP has no legacy client connected + */ +enum conn_6ghz_flag { + CONN_6GHZ_FLAG_VALID = 0x0001, + CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED = 0x0002, + CONN_6GHZ_FLAG_SECURITY_ALLOWED = 0x0004, + CONN_6GHZ_FLAG_NO_LEGACY_CLIENT = 0x0008, +}; + +#ifdef WLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE +/* To support DCS to 6 Ghz channel when AFC response receive */ +#define CONN_6GHZ_CAPABLE (CONN_6GHZ_FLAG_VALID | \ + CONN_6GHZ_FLAG_SECURITY_ALLOWED | \ + CONN_6GHZ_FLAG_NO_LEGACY_CLIENT) +#else +#define CONN_6GHZ_CAPABLE (CONN_6GHZ_FLAG_VALID | \ + CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED | \ + CONN_6GHZ_FLAG_SECURITY_ALLOWED | \ + CONN_6GHZ_FLAG_NO_LEGACY_CLIENT) +#endif + +/** + * struct policy_mgr_conc_connection_info - information of all existing + * connections in the wlan system + * + * @mode: connection type + * @freq: Channel frequency + * @bw: channel bandwidth used for the connection + * @mac: The HW mac it is running + * @chain_mask: The original capability advertised by HW + * @original_nss: nss negotiated at connection time + * @vdev_id: vdev id of the connection + * @in_use: if the table entry is active + * @ch_flagext: Channel extension flags. + * @conn_6ghz_flag: connection 6ghz capable flags + */ +struct policy_mgr_conc_connection_info { + enum policy_mgr_con_mode mode; + uint32_t freq; + enum hw_mode_bandwidth bw; + uint8_t mac; + enum policy_mgr_chain_mode chain_mask; + uint32_t original_nss; + uint32_t vdev_id; + bool in_use; + uint16_t ch_flagext; + enum conn_6ghz_flag conn_6ghz_flag; +}; + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * struct policy_mgr_disabled_ml_link_info - information of all existing + * disabled ml link + * @in_use: if the table entry is active + * @mode: connection type + * @freq: Channel frequency + * @vdev_id: vdev id of the connection + */ +struct policy_mgr_disabled_ml_link_info { + bool in_use; + enum policy_mgr_con_mode mode; + qdf_freq_t freq; + uint8_t vdev_id; +}; +#endif + +/** + * struct policy_mgr_hw_mode_params - HW mode params + * @mac0_tx_ss: MAC0 Tx spatial stream + * @mac0_rx_ss: MAC0 Rx spatial stream + * @mac1_tx_ss: MAC1 Tx spatial stream + * @mac1_rx_ss: MAC1 Rx spatial stream + * @mac0_bw: MAC0 bandwidth + * @mac1_bw: MAC1 bandwidth + * @mac0_band_cap: mac0 band (5g/2g) capability + * @dbs_cap: DBS capabality + * @agile_dfs_cap: Agile DFS capabality + * @sbs_cap: SBS capability + * @emlsr_cap: eMLSR capability + * @action_type: for dbs mode, the field indicates the "Action type" to be + * used to switch to the mode. To help the hw mode validation. + */ +struct policy_mgr_hw_mode_params { + uint8_t mac0_tx_ss; + uint8_t mac0_rx_ss; + uint8_t mac1_tx_ss; + uint8_t mac1_rx_ss; + uint8_t mac0_bw; + uint8_t mac1_bw; + uint8_t mac0_band_cap; + uint8_t dbs_cap; + uint8_t agile_dfs_cap; + uint8_t sbs_cap; + uint8_t emlsr_cap; + enum policy_mgr_conc_next_action action_type; +}; + +/** + * struct policy_mgr_dual_mac_config - Dual MAC configuration + * @scan_config: Scan configuration + * @fw_mode_config: FW mode configuration + * @set_dual_mac_cb: Callback function to be executed on response to the command + */ +struct policy_mgr_dual_mac_config { + uint32_t scan_config; + uint32_t fw_mode_config; + dual_mac_cb set_dual_mac_cb; +}; + +/** + * struct policy_mgr_hw_mode - Format of set HW mode + * @hw_mode_index: Index of HW mode to be set + * @set_hw_mode_cb: HDD set HW mode callback + * @reason: Reason for HW mode change + * @session_id: Session id + * @next_action: next action to happen at policy mgr + * @action: current hw change action to be done + * @context: psoc context + * @request_id: Request id provided by the requester, can be used while + * calling callback to the requester + */ +struct policy_mgr_hw_mode { + uint32_t hw_mode_index; + void *set_hw_mode_cb; + enum policy_mgr_conn_update_reason reason; + uint32_t session_id; + uint8_t next_action; + enum policy_mgr_conc_next_action action; + struct wlan_objmgr_psoc *context; + uint32_t request_id; +}; + +/** + * struct policy_mgr_pcl_list - Format of PCL + * @pcl_list: List of preferred channels + * @weight_list: Weights of the PCL + * @pcl_len: Number of channels in the PCL + */ +struct policy_mgr_pcl_list { + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + uint32_t pcl_len; +}; + +/** + * struct policy_mgr_pcl_chan_weights - Params to get the valid weighed list + * @pcl_list: Preferred channel list already sorted in the order of preference + * @pcl_len: Length of the PCL + * @saved_chan_list: Valid channel list updated as part of + * WMA_UPDATE_CHAN_LIST_REQ + * @saved_num_chan: Length of the valid channel list + * @weighed_valid_list: Weights of the valid channel list. This will have one + * to one mapping with valid_chan_list. FW expects channel order and size to be + * as per the list provided in WMI_SCAN_CHAN_LIST_CMDID. + * @weight_list: Weights assigned by policy manager + */ +struct policy_mgr_pcl_chan_weights { + uint32_t pcl_list[NUM_CHANNELS]; + uint32_t pcl_len; + uint32_t saved_chan_list[NUM_CHANNELS]; + uint32_t saved_num_chan; + uint8_t weighed_valid_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; +}; + +/** + * struct policy_mgr_vdev_entry_info - vdev related param to be + * used by policy manager + * @type: type + * @sub_type: sub type + * @mhz: channel frequency in MHz + * @chan_width: channel bandwidth + * @mac_id: the mac on which vdev is on + * @ch_flagext: Channel extension flags. + */ +struct policy_mgr_vdev_entry_info { + uint32_t type; + uint32_t sub_type; + uint32_t mhz; + uint32_t chan_width; + uint32_t mac_id; + uint16_t ch_flagext; +}; + +/** + * struct policy_mgr_freq_range - hw mode freq range for the pdev + * @low_2ghz_freq: lower 2.4GHz channels + * @high_2ghz_freq: higher 2.4 GHz channels + * @low_5ghz_freq: lower 5 GHz channels + * @high_5ghz_freq: higher 5 GHz channels + */ +struct policy_mgr_freq_range { + qdf_freq_t low_2ghz_freq; + qdf_freq_t high_2ghz_freq; + qdf_freq_t low_5ghz_freq; + qdf_freq_t high_5ghz_freq; +}; + +/** + * enum policy_mgr_mode - enum for host mode + * @MODE_SMM: Single mac mode + * @MODE_DBS: DBS mode + * @MODE_SBS: SBS mode with either high share or low share + * @MODE_SBS_UPPER_SHARE: Higher 5Ghz shared with 2.4Ghz + * @MODE_SBS_LOWER_SHARE: LOWER 5Ghz shared with 2.4Ghz + * @MODE_EMLSR: eMLSR mode + * @MODE_EMLSR_SINGLE: eMLSR single mode + * @MODE_EMLSR_SPLIT: eMLSR split mode + * @MODE_HW_MAX: MAX + */ +enum policy_mgr_mode { + MODE_SMM, + MODE_DBS, + MODE_SBS, + MODE_SBS_UPPER_SHARE, + MODE_SBS_LOWER_SHARE, + MODE_EMLSR, + MODE_EMLSR_SINGLE, + MODE_EMLSR_SPLIT, + MODE_HW_MAX, +}; + +/** + * struct dbs_hw_mode_info - WLAN_DBS_HW_MODES_TLV Format + * @hw_mode_list: WLAN_DBS_HW_MODE_LIST entries + * @sbs_lower_band_end_freq: value with which range will be divided + * @freq_range_caps: Initial capability and range for different modes for both + * pdev + * @cur_mac_freq_range: Current freq range for both pdev, this can be used to + * reject if 2 home channels on a MAC, depending on opmode + * and current HW mode. + */ +struct dbs_hw_mode_info { + uint64_t *hw_mode_list; + qdf_freq_t sbs_lower_band_end_freq; + struct policy_mgr_freq_range freq_range_caps[MODE_HW_MAX][MAX_MAC]; + struct policy_mgr_freq_range cur_mac_freq_range[MAX_MAC]; +}; + +/** + * struct dual_mac_config - Dual MAC configurations + * @prev_scan_config: Previous scan configuration + * @prev_fw_mode_config: Previous FW mode configuration + * @cur_scan_config: Current scan configuration + * @cur_fw_mode_config: Current FW mode configuration + * @req_scan_config: Requested scan configuration + * @req_fw_mode_config: Requested FW mode configuration + */ +struct dual_mac_config { + uint32_t prev_scan_config; + uint32_t prev_fw_mode_config; + uint32_t cur_scan_config; + uint32_t cur_fw_mode_config; + uint32_t req_scan_config; + uint32_t req_fw_mode_config; +}; + +/** + * enum policy_mgr_pri_id - vdev type priority id + * @PM_STA_PRI_ID: station vdev type priority id + * @PM_SAP_PRI_ID: sap vdev type priority id + * @PM_P2P_GO_PRI_ID: p2p go vdev type priority id + * @PM_P2P_CLI_PRI_ID: p2p cli vdev type priority id + * @PM_MAX_PRI_ID: vdev type priority id max value + */ +enum policy_mgr_pri_id { + PM_STA_PRI_ID = 1, + PM_SAP_PRI_ID, + PM_P2P_GO_PRI_ID, + PM_P2P_CLI_PRI_ID, + PM_MAX_PRI_ID = 0xF, +}; + +#define PM_GET_BAND_PREFERRED(_policy_) ((_policy_) & 0x1) +#define PM_GET_VDEV_PRIORITY_ENABLED(_policy_) (((_policy_) & 0x2) >> 1) + +/** + * struct policy_mgr_user_cfg - Policy manager user config variables + * @enable2x2: 2x2 chain mask user config + * @sub_20_mhz_enabled: Is 5 or 10 Mhz enabled + */ +struct policy_mgr_user_cfg { + bool enable2x2; + bool sub_20_mhz_enabled; +}; + +/** + * struct dbs_bw - Max BW supported in DBS mode + * @mac0_bw: BW of MAC0 + * @mac1_bw: BW of MAC1 + */ +struct dbs_bw { + enum hw_mode_bandwidth mac0_bw; + enum hw_mode_bandwidth mac1_bw; +}; + +/** + * struct dbs_nss - Number of spatial streams in DBS mode + * @mac0_ss: Number of spatial streams on MAC0 + * @mac1_ss: Number of spatial streams on MAC1 + * @single_mac0_band_cap: Mac0 band capability for single mac hw mode + */ +struct dbs_nss { + enum hw_mode_ss_config mac0_ss; + enum hw_mode_ss_config mac1_ss; + uint32_t single_mac0_band_cap; +}; + +/* + * Max radio combination numbers + */ +#define MAX_RADIO_COMBINATION 16 + +/** + * struct radio_combination - Radio combination + * @hw_mode: hw mode type + * @band_mask: band support type for each mac + * @antenna: antenna support for each mac + */ +struct radio_combination { + enum policy_mgr_mode hw_mode; + uint8_t band_mask[MAX_MAC]; + uint8_t antenna[MAX_MAC]; +}; + +/** + * struct connection_info - connection information + * @mac_id: The HW mac it is running + * @vdev_id: vdev id + * @channel: channel of the connection + * @ch_freq: channel freq in Mhz + */ +struct connection_info { + uint8_t mac_id; + uint8_t vdev_id; + uint8_t channel; + uint32_t ch_freq; +}; + +/** + * struct go_plus_go_force_scc - structure to hold p2p go + * params for forcescc restart + * + * @vdev_id: vdev id of first p2p go which needs to do csa + * @ch_freq: ch freq of curr p2p go + * @ch_width: ch width of curr p2p go + */ +struct go_plus_go_force_scc { + uint8_t vdev_id; + uint32_t ch_freq; + uint32_t ch_width; +}; + +/** + * struct sap_plus_go_force_scc - structure to hold + * params for forcescc restart in sap plus go + * + * @reason: channel change reason code + * @initiator_vdev_id: the first interface ID to trigger CSA + * @responder_vdev_id: the second interface ID to follow CSA + */ +struct sap_plus_go_force_scc { + enum sap_csa_reason_code reason; + uint8_t initiator_vdev_id; + uint8_t responder_vdev_id; +}; + +/** + * struct sta_ap_intf_check_work_ctx - sta_ap_intf_check_work + * related info + * @psoc: pointer to PSOC object information + * @go_plus_go_force_scc: structure to hold params of + * curr and first p2p go ctx + * @sap_plus_go_force_scc: sap p2p force SCC ctx + * @nan_force_scc_in_progress: NAN force scc in progress + */ +struct sta_ap_intf_check_work_ctx { + struct wlan_objmgr_psoc *psoc; + struct go_plus_go_force_scc go_plus_go_force_scc; + struct sap_plus_go_force_scc sap_plus_go_force_scc; + uint8_t nan_force_scc_in_progress; +}; + +/** + * union conc_ext_flag - extended flags for concurrency check + * + * @mlo: the new connection is MLO + * @mlo_link_assoc_connected: the new connection is secondary MLO link and + * the corresponding assoc link is connected + * @value: uint32 value for extended flags + */ +union conc_ext_flag { + struct { + uint32_t mlo: 1; + uint32_t mlo_link_assoc_connected: 1; + }; + + uint32_t value; +}; + +/** + * enum indoor_conc_update_type - Indoor concurrency update type + * @CONNECT: On a new STA connection + * @DISCONNECT_WITHOUT_CONCURRENCY: On a STA disconnection with no active + * sessions on the same frequency + * @DISCONNECT_WITH_CONCURRENCY: On a STA disconnection with an active + * session on the same frequency + * @SWITCH_WITH_CONCURRENCY: On a STA roam or CSA to a different channel + * with a concurrent SAP on previous frequency + * @SWITCH_WITHOUT_CONCURRENCY: On a STA roam or CSA to a different channel + * without any concurrent SAP on previous frequency + */ +enum indoor_conc_update_type { + CONNECT, + DISCONNECT_WITHOUT_CONCURRENCY, + DISCONNECT_WITH_CONCURRENCY, + SWITCH_WITHOUT_CONCURRENCY, + SWITCH_WITH_CONCURRENCY, +}; + +#endif /* __WLAN_POLICY_MGR_PUBLIC_STRUCT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h new file mode 100644 index 0000000000..bb0cd578c1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/inc/wlan_policy_mgr_ucfg.h @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __WLAN_POLICY_MGR_UCFG +#define __WLAN_POLICY_MGR_UCFG +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_global_obj.h" +#include "qdf_status.h" +#include "wlan_policy_mgr_public_struct.h" + +/** + * ucfg_policy_mgr_psoc_open() - This API sets CFGs to policy manager context + * @psoc: pointer to psoc + * + * This API pulls policy manager's context from PSOC and initialize the CFG + * structure of policy manager. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_policy_mgr_psoc_close() - This API resets CFGs for policy manager ctx + * @psoc: pointer to psoc + * + * This API pulls policy manager's context from PSOC and resets the CFG + * structure of policy manager. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +void ucfg_policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * ucfg_policy_mgr_get_mcc_scc_switch() - To mcc to scc switch setting from INI + * @psoc: pointer to psoc + * @mcc_scc_switch: value to be filled + * + * This API pulls mcc to scc switch setting which is given as part of INI and + * stored in policy manager's CFGs. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc, + uint8_t *mcc_scc_switch); +#else +static inline +QDF_STATUS ucfg_policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc, + uint8_t *mcc_scc_switch) +{ + return QDF_STATUS_SUCCESS; +} +#endif //FEATURE_WLAN_MCC_TO_SCC_SWITCH + +/** + * ucfg_policy_mgr_get_radio_combinations() - Query the supported radio + * combinations + * @psoc: soc object + * @comb: combination buffer + * @comb_max: max combination number can be saved to comb buffer + * @comb_num: returned combination number + * + * This function returns the radio combination information supported by target. + * + * Return: QDF_STATUS_SUCCESS if query successfully + */ +QDF_STATUS +ucfg_policy_mgr_get_radio_combinations(struct wlan_objmgr_psoc *psoc, + struct radio_combination *comb, + uint32_t comb_max, + uint32_t *comb_num); + +/** + * ucfg_policy_mgr_get_sys_pref() - to get system preference + * @psoc: pointer to psoc + * @sys_pref: value to be filled + * + * This API pulls the system preference for policy manager to provide + * PCL + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t *sys_pref); +/** + * ucfg_policy_mgr_set_sys_pref() - to set system preference + * @psoc: pointer to psoc + * @sys_pref: value to be applied as new INI setting + * + * This API is meant to override original INI setting for system pref + * with new value which is used by policy manager to provide PCL + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t sys_pref); + +/** + * ucfg_policy_mgr_get_conc_rule1() - to find out if conc rule1 is enabled + * @psoc: pointer to psoc + * @conc_rule1: value to be filled + * + * This API is used to find out if conc rule-1 is enabled by user + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule1); +/** + * ucfg_policy_mgr_get_conc_rule2() - to find out if conc rule2 is enabled + * @psoc: pointer to psoc + * @conc_rule2: value to be filled + * + * This API is used to find out if conc rule-2 is enabled by user + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule2); + +/** + * ucfg_policy_mgr_get_chnl_select_plcy() - to get channel selection policy + * @psoc: pointer to psoc + * @chnl_select_plcy: value to be filled + * + * This API is used to find out which channel selection policy has been + * configured + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc, + uint32_t *chnl_select_plcy); +/** + * ucfg_policy_mgr_get_mcc_adaptive_sch() - to get mcc adaptive scheduler + * @psoc: pointer to psoc + * @enable_mcc_adaptive_sch: value to be filled + * + * This API is used to find out if mcc adaptive scheduler enabled or disabled + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc, + bool *enable_mcc_adaptive_sch); + +/** + * ucfg_policy_mgr_get_dynamic_mcc_adaptive_sch() - to get dynamic mcc adaptive + * scheduler + * @psoc: pointer to psoc + * @dynamic_mcc_adaptive_sch: value to be filled + * + * This API is used to get dynamic mcc adaptive scheduler + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_get_dynamic_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc, + bool *dynamic_mcc_adaptive_sch); + +/** + * ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch() - to set dynamic mcc adaptive + * scheduler + * @psoc: pointer to psoc + * @dynamic_mcc_adaptive_sch: value to be set + * + * This API is used to set dynamic mcc adaptive scheduler + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc, + bool dynamic_mcc_adaptive_sch); + +/** + * ucfg_policy_mgr_get_sta_cxn_5g_band() - to get STA's connection in 5G config + * + * @psoc: pointer to psoc + * @enable_sta_cxn_5g_band: value to be filled + * + * This API is used to find out if STA connection in 5G band is allowed or + * disallowed. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_sta_cxn_5g_band); +/** + * ucfg_policy_mgr_get_allow_mcc_go_diff_bi() - to get information on whether GO + * can have diff BI than STA in MCC + * @psoc: pointer to psoc + * @allow_mcc_go_diff_bi: value to be filled + * + * This API is used to find out whether GO's BI can different than STA in MCC + * scenario + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_get_allow_mcc_go_diff_bi(struct wlan_objmgr_psoc *psoc, + uint8_t *allow_mcc_go_diff_bi); +/** + * ucfg_policy_mgr_get_dual_mac_feature() - to find out if DUAL MAC feature is + * enabled + * @psoc: pointer to psoc + * @dual_mac_feature: value to be filled + * + * This API is used to find out whether dual mac (dual radio) specific feature + * is enabled or not + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_dual_mac_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_mac_feature); + +/** + * ucfg_policy_mgr_get_dual_sta_feature() - to find out if DUAL STA feature is + * enabled + * @psoc: pointer to psoc + * + * This API is used to find out whether dual sta specific feature is enabled + * or not. + * + * Return: true if feature is enabled, otherwise false. + */ +bool ucfg_policy_mgr_get_dual_sta_feature(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_policy_mgr_get_force_1x1() - to find out if 1x1 connection is enforced + * + * @psoc: pointer to psoc + * @force_1x1: value to be filled + * + * This API is used to find out if 1x1 connection is enforced. + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_force_1x1(struct wlan_objmgr_psoc *psoc, + uint8_t *force_1x1); + +/** + * ucfg_policy_mgr_get_max_conc_cxns() - to get configured max concurrent active + * connection count + * + * @psoc: pointer to psoc + * + * This API is used to query the configured max concurrent active connection + * count. + * + * Return: max active connection count + */ +uint32_t ucfg_policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_policy_mgr_set_max_conc_cxns() - to set supported max concurrent active + * connection count to policy mgr + * + * @psoc: pointer to psoc + * @max_conc_cxns: max active connection count + * + * This API is used to update the max concurrent active connection + * count to policy mgr + * + * Return: QDF_STATUS_SUCCESS if set successfully + */ +QDF_STATUS ucfg_policy_mgr_set_max_conc_cxns(struct wlan_objmgr_psoc *psoc, + uint32_t max_conc_cxns); + +/** + * ucfg_policy_mgr_get_sta_sap_scc_on_dfs_chnl() - to find out if STA and SAP + * SCC is allowed on DFS channel + * @psoc: pointer to psoc + * @sta_sap_scc_on_dfs_chnl: value to be filled + * + * This API is used to find out whether STA and SAP SCC is allowed on + * DFS channels + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_get_sta_sap_scc_on_dfs_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_on_dfs_chnl); +/** + * ucfg_policy_mgr_get_sta_sap_scc_lte_coex_chnl() - to find out if STA & SAP + * SCC is allowed on LTE COEX + * @psoc: pointer to psoc + * @sta_sap_scc_lte_coex: value to be filled + * + * This API is used to find out whether STA and SAP scc is allowed on LTE COEX + * channel + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_get_sta_sap_scc_lte_coex_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_lte_coex); + +/** + * ucfg_policy_mgr_get_dfs_master_dynamic_enabled() - support dfs master or not + * AP interface when STA+SAP(GO) concurrency + * @psoc: pointer to psoc + * @vdev_id: sap vdev id + * + * This API is used to check SAP (GO) dfs master functionality enabled or not + * when STA+SAP(GO) concurrency. + * If g_sta_sap_scc_on_dfs_chan is non-zero, the STA+SAP(GO) is allowed on DFS + * channel SCC and the SAP's DFS master functionality should be enable/disable + * according to: + * 1. g_sta_sap_scc_on_dfs_chan is 0: function return true - dfs master + * capability enabled. + * 2. g_sta_sap_scc_on_dfs_chan is 1: function return false - dfs master + * capability disabled. + * 3. g_sta_sap_scc_on_dfs_chan is 2: dfs master capability based on STA on + * 5G or not: + * a. 5G STA active - return false + * b. no 5G STA active -return true + * + * Return: true if dfs master functionality should be enabled. + */ +bool +ucfg_policy_mgr_get_dfs_master_dynamic_enabled(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_policy_mgr_init_chan_avoidance() - init channel avoidance in policy + * manager + * @psoc: pointer to psoc + * @chan_freq_list: channel frequency list + * @chan_cnt: channel count + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_init_chan_avoidance(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *chan_freq_list, + uint16_t chan_cnt); + +/** + * ucfg_policy_mgr_get_sap_mandt_chnl() - to find out if SAP mandatory channel + * support is enabled + * @psoc: pointer to psoc + * @sap_mandt_chnl: value to be filled + * + * This API is used to find out whether SAP's mandatory channel support + * is enabled + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS ucfg_policy_mgr_get_sap_mandt_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sap_mandt_chnl); +/** + * ucfg_policy_mgr_get_indoor_chnl_marking() - to get if indoor channel can be + * marked as disabled + * @psoc: pointer to psoc + * @indoor_chnl_marking: value to be filled + * + * This API is used to find out whether indoor channel can be marked as disabled + * + * Return: QDF_STATUS_SUCCESS up on success and any other status for failure. + */ +QDF_STATUS +ucfg_policy_mgr_get_indoor_chnl_marking(struct wlan_objmgr_psoc *psoc, + uint8_t *indoor_chnl_marking); + +/** + * ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl() - to get if + * sta sap scc on indoor channel is allowed + * @psoc: pointer to psoc + * + * This API is used to get the value of sta+sap scc on indoor channel + * + * Return: TRUE or FALSE + */ + +bool +ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_policy_mgr_is_fw_supports_dbs() - to check whether FW supports DBS or + * not + * @psoc: pointer to psoc + * + * Return: true if DBS is supported else false + */ +bool ucfg_policy_mgr_is_fw_supports_dbs(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_policy_mgr_get_connection_count() - Get number of connections + * @psoc: pointer to psoc + * + * This API is used to get the count of current connections. + * + * Return: connection count + */ +uint32_t ucfg_policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_policy_mgr_is_hw_sbs_capable() - Check if HW is SBS capable + * @psoc: pointer to psoc + * + * This API is to check if the HW is SBS capable. + * + * Return: true if the HW is SBS capable + */ +bool ucfg_policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc); + +/* + * ucfg_policy_mgr_get_vdev_same_freq_new_conn() - Get vdev_id of the first + * connection that has same + * channel frequency as new_freq + * @psoc: psoc object pointer + * @new_freq: channel frequency for the new connection + * @vdev_id: Output parameter to return vdev id of the first existing connection + * that has same channel frequency as @new_freq + * + * This function is to return the first connection that has same + * channel frequency as @new_freq. + * + * Return: true if connection that has same channel frequency as + * @new_freq exists. Otherwise false. + */ +bool ucfg_policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id); +/* + * ucfg_policy_mgr_get_vdev_diff_freq_new_conn() - Get vdev id of the first + * connection that has different + * channel freq from new_freq + * @psoc: psoc object pointer + * @new_freq: channel frequency for the new connection + * @vdev_id: Output parameter to return vdev id of the first existing connection + * that has different channel frequency from @new_freq + * + * This function is to return the first connection that has different + * channel frequency from @new_freq. + * + * Return: true if connection that has different channel frequency from + * @new_freq exists. Otherwise false. + */ +bool ucfg_policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id); + +/** + * ucfg_policy_mgr_get_dbs_hw_modes() - to get the DBS HW modes + * + * @psoc: pointer to psoc + * @one_by_one_dbs: 1x1 DBS capability of HW + * @two_by_two_dbs: 2x2 DBS capability of HW + * + * Return: Failure in case of error otherwise success + */ +QDF_STATUS ucfg_policy_mgr_get_dbs_hw_modes(struct wlan_objmgr_psoc *psoc, + bool *one_by_one_dbs, + bool *two_by_two_dbs); + +#endif //__WLAN_POLICY_MGR_UCFG diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c new file mode 100644 index 0000000000..a4ac25b85b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c @@ -0,0 +1,4321 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_policy_mgr_action.c + * + * WLAN Concurrenct Connection Management APIs + * + */ + +/* Include files */ + +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_i.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "wlan_objmgr_global_obj.h" +#include "qdf_platform.h" +#include "wlan_nan_api.h" +#include "nan_ucfg_api.h" +#include "wlan_mlme_api.h" +#include "sap_api.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "target_if.h" +#include "wlan_cm_api.h" +#include "wlan_mlo_link_force.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_policy_mgr_ll_sap.h" + +enum policy_mgr_conc_next_action (*policy_mgr_get_current_pref_hw_mode_ptr) + (struct wlan_objmgr_psoc *psoc); + +#define HW_MODE_DUMP_MAX_LEN 100 +void +policy_mgr_dump_freq_range_n_vdev_map(uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *mac_freq_range) +{ + char log_str[HW_MODE_DUMP_MAX_LEN] = {0}; + uint32_t str_len = HW_MODE_DUMP_MAX_LEN; + uint32_t len = 0; + uint32_t i; + + if (mac_freq_range) { + for (i = 0, len = 0; i < num_mac_freq; i++) + len += qdf_scnprintf(log_str + len, str_len - len, + "mac %d: %d => %d ", + mac_freq_range[i].mac_id, + mac_freq_range[i].start_freq, + mac_freq_range[i].end_freq); + if (num_mac_freq) + policymgr_nofl_debug("Freq range:: %s", log_str); + } + + if (!vdev_mac_map || !num_vdev_mac_entries) + return; + + for (i = 0, len = 0; i < num_vdev_mac_entries; i++) + len += qdf_scnprintf(log_str + len, str_len - len, + "vdev %d -> mac %d ", + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + policymgr_nofl_debug("Vdev Map:: %s", log_str); +} + +void policy_mgr_hw_mode_transition_cb(uint32_t old_hw_mode_index, + uint32_t new_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *mac_freq_range, + struct wlan_objmgr_psoc *context) +{ + QDF_STATUS status; + struct policy_mgr_hw_mode_params hw_mode; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(context); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + + if (!vdev_mac_map) { + policy_mgr_err("vdev_mac_map is NULL"); + return; + } + + status = policy_mgr_get_hw_mode_from_idx(context, new_hw_mode_index, + &hw_mode); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Get HW mode for index %d reason: %d", + new_hw_mode_index, status); + return; + } + + policy_mgr_debug("HW mode: old %d new %d, DBS %d Agile %d SBS %d, MAC0:: SS:Tx %d Rx %d, BW %d band %d, MAC1:: SS:Tx %d Rx %d, BW %d", + old_hw_mode_index, new_hw_mode_index, hw_mode.dbs_cap, + hw_mode.agile_dfs_cap, hw_mode.sbs_cap, + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, + hw_mode.mac0_bw, hw_mode.mac0_band_cap, + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, + hw_mode.mac1_bw); + policy_mgr_dump_freq_range_n_vdev_map(num_vdev_mac_entries, + vdev_mac_map, num_mac_freq, + mac_freq_range); + + /* update pm_conc_connection_list */ + policy_mgr_update_hw_mode_conn_info(context, num_vdev_mac_entries, + vdev_mac_map, hw_mode, + num_mac_freq, mac_freq_range); + + if (pm_ctx->mode_change_cb) + pm_ctx->mode_change_cb(); + + return; +} + +QDF_STATUS policy_mgr_check_n_start_opportunistic_timer( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum policy_mgr_conn_update_reason reason = + POLICY_MGR_UPDATE_REASON_TIMER_START; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("PM ctx not valid. Oppurtunistic timer cannot start"); + return QDF_STATUS_E_FAILURE; + } + if (policy_mgr_need_opportunistic_upgrade(psoc, &reason)) { + /* let's start the timer */ + qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer); + status = qdf_mc_timer_start( + &pm_ctx->dbs_opportunistic_timer, + DBS_OPPORTUNISTIC_TIME * 1000); + if (!QDF_IS_STATUS_SUCCESS(status)) + policy_mgr_err("Failed to start dbs opportunistic timer"); + } + return status; +} + +QDF_STATUS policy_mgr_pdev_set_hw_mode(struct wlan_objmgr_psoc *psoc, + uint32_t session_id, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_mac_band_cap mac0_band_cap, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs, + enum policy_mgr_conn_update_reason reason, + uint8_t next_action, enum policy_mgr_conc_next_action action, + uint32_t request_id) +{ + int8_t hw_mode_index; + struct policy_mgr_hw_mode msg; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + if (!pm_ctx->sme_cbacks.sme_pdev_set_hw_mode) { + policy_mgr_debug("NOT supported"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* + * if HW is not capable of doing 2x2 or ini config disabled 2x2, don't + * allow to request FW for 2x2 + */ + if ((HW_MODE_SS_2x2 == mac0_ss) && (!pm_ctx->user_cfg.enable2x2)) { + policy_mgr_debug("2x2 is not allowed downgrading to 1x1 for mac0"); + mac0_ss = HW_MODE_SS_1x1; + } + if ((HW_MODE_SS_2x2 == mac1_ss) && (!pm_ctx->user_cfg.enable2x2)) { + policy_mgr_debug("2x2 is not allowed downgrading to 1x1 for mac1"); + mac1_ss = HW_MODE_SS_1x1; + } + + hw_mode_index = policy_mgr_get_hw_mode_idx_from_dbs_hw_list(psoc, + mac0_ss, mac0_bw, mac1_ss, mac1_bw, mac0_band_cap, + dbs, dfs, sbs); + if (hw_mode_index < 0) { + policy_mgr_err("Invalid HW mode index obtained"); + return QDF_STATUS_E_FAILURE; + } + + /* Don't send WMI_PDEV_SET_HW_MODE_CMDID to FW if existing SAP / GO is + * in CAC-in-progress state. Host is blocking this command as FW is + * having design limitation and FW don't expect this command when CAC + * is in progress state. + */ + if (pm_ctx->hdd_cbacks.hdd_is_cac_in_progress && + pm_ctx->hdd_cbacks.hdd_is_cac_in_progress() && + !policy_mgr_is_hw_dbs_2x2_capable(psoc)) { + policy_mgr_err("SAP CAC_IN_PROGRESS state, drop WMI_PDEV_SET_HW_MODE_CMDID"); + return QDF_STATUS_E_FAILURE; + } + + msg.hw_mode_index = hw_mode_index; + msg.set_hw_mode_cb = (void *)policy_mgr_pdev_set_hw_mode_cb; + msg.reason = reason; + msg.session_id = session_id; + msg.next_action = next_action; + msg.action = action; + msg.context = psoc; + msg.request_id = request_id; + + policy_mgr_debug("set hw mode to sme: hw_mode_index: %d session:%d reason:%d action %d request_id %d", + msg.hw_mode_index, msg.session_id, msg.reason, action, + msg.request_id); + + status = pm_ctx->sme_cbacks.sme_pdev_set_hw_mode(msg); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to set hw mode to SME"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_get_sap_bw() - get current SAP bandwidth + * @psoc: Pointer to psoc + * @bw: Buffer to update the bandwidth + * + * Get the current SAP bandwidth. This API supports only single SAP + * concurrencies and doesn't cover multi SAP(e.g. SAP+SAP). + * + * return : QDF_STATUS + */ +static QDF_STATUS +policy_mgr_get_sap_bw(struct wlan_objmgr_psoc *psoc, enum phy_ch_width *bw) +{ + uint32_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1]; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1]; + struct wlan_objmgr_vdev *vdev; + + if (policy_mgr_get_mode_specific_conn_info(psoc, &freq_list[0], + &vdev_id_list[0], + PM_SAP_MODE) != 1 || + !WLAN_REG_IS_6GHZ_CHAN_FREQ(freq_list[0])) + return QDF_STATUS_E_NOSUPPORT; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_list[0], + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d is NULL", vdev_id_list[0]); + return QDF_STATUS_E_INVAL; + } + + *bw = wlan_mlme_get_ap_oper_ch_width(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_get_sap_ch_width_update_action() - get SAP ch_width update action + * @psoc: Pointer to psoc + * @vdev_id: Vdev id of the caller + * @ch_freq: channel frequency of new connection + * @next_action: next action to happen in order to update bandwidth + * @reason: Bandwidth upgrade/downgrade reason + * + * Check if current operating SAP needs a downgrade to 160MHz or an upgrade + * to 320MHz based on the new connection. + * + * return : None + */ +static void +policy_mgr_get_sap_ch_width_update_action(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t ch_freq, + enum policy_mgr_conc_next_action *next_action, + enum policy_mgr_conn_update_reason *reason) +{ + enum phy_ch_width cur_bw; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1]; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1]; + bool eht_capab = false; + + /* + * Stop any running opportunistic timer as it will be started after + * decision if required. + */ + policy_mgr_stop_opportunistic_timer(psoc); + if (QDF_IS_STATUS_ERROR(wlan_psoc_mlme_get_11be_capab(psoc, + &eht_capab)) || + !eht_capab || + QDF_IS_STATUS_ERROR(policy_mgr_get_sap_bw(psoc, &cur_bw)) || + cur_bw < CH_WIDTH_160MHZ) + return; + + policy_mgr_get_mode_specific_conn_info(psoc, &freq_list[0], + &vdev_id_list[0], PM_SAP_MODE); + if (cur_bw == CH_WIDTH_320MHZ && ch_freq && + policy_mgr_is_conn_lead_to_dbs_sbs(psoc, vdev_id, ch_freq)) + *next_action = PM_DOWNGRADE_BW; + else if (cur_bw == CH_WIDTH_160MHZ && + !ch_freq && + !policy_mgr_is_conn_lead_to_dbs_sbs(psoc, + vdev_id_list[0], freq_list[0]) && + (reason && + (*reason == POLICY_MGR_UPDATE_REASON_TIMER_START || + *reason == POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC))) + *next_action = PM_UPGRADE_BW; +} + +enum policy_mgr_conc_next_action policy_mgr_need_opportunistic_upgrade( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conn_update_reason *reason) +{ + uint32_t conn_index; + enum policy_mgr_conc_next_action upgrade = PM_NOP; + enum policy_mgr_conc_next_action preferred_dbs_action; + uint8_t mac = 0; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (policy_mgr_is_hwmode_offload_enabled(psoc)) { + policy_mgr_get_sap_ch_width_update_action(psoc, + WLAN_INVALID_VDEV_ID, + 0, &upgrade, + reason); + return upgrade; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + goto exit; + } + + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + policy_mgr_rl_debug("driver isn't dbs capable, no further action needed"); + goto exit; + } + + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + goto exit; + } + if (!hw_mode.dbs_cap) { + policy_mgr_debug("current HW mode is non-DBS capable"); + goto exit; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* Are both mac's still in use */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + policy_mgr_debug("index:%d mac:%d in_use:%d chan:%d org_nss:%d", + conn_index, + pm_conc_connection_list[conn_index].mac, + pm_conc_connection_list[conn_index].in_use, + pm_conc_connection_list[conn_index].freq, + pm_conc_connection_list[conn_index].original_nss); + if ((pm_conc_connection_list[conn_index].mac == 0) && + pm_conc_connection_list[conn_index].in_use) { + mac |= POLICY_MGR_MAC0; + if (POLICY_MGR_MAC0_AND_MAC1 == mac) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + goto done; + } + } else if ((pm_conc_connection_list[conn_index].mac == 1) && + pm_conc_connection_list[conn_index].in_use) { + mac |= POLICY_MGR_MAC1; + if (policy_mgr_is_hw_dbs_required_for_band( + psoc, HW_MODE_MAC_BAND_2G) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[conn_index].freq)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("2X2 DBS capable with 2.4 GHZ connection"); + goto done; + } + if (POLICY_MGR_MAC0_AND_MAC1 == mac) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + goto done; + } + } + } + /* Let's request for single MAC mode */ + upgrade = PM_SINGLE_MAC; + if (reason) + *reason = POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC; + /* Is there any connection had an initial connection with 2x2 */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].original_nss == 2) && + pm_conc_connection_list[conn_index].in_use) { + upgrade = PM_SINGLE_MAC_UPGRADE; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + goto done; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + +done: + if (upgrade == PM_NOP && hw_mode.dbs_cap && + policy_mgr_is_2x2_1x1_dbs_capable(psoc)) { + preferred_dbs_action = + policy_mgr_get_preferred_dbs_action_table( + psoc, INVALID_VDEV_ID, 0, 0); + if (hw_mode.action_type == PM_DBS1 && + preferred_dbs_action == PM_DBS2) { + upgrade = PM_DBS2_DOWNGRADE; + if (reason) + *reason = + POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE; + } else if (hw_mode.action_type == PM_DBS2 && + preferred_dbs_action == PM_DBS1) { + upgrade = PM_DBS1_DOWNGRADE; + if (reason) + *reason = + POLICY_MGR_UPDATE_REASON_PRI_VDEV_CHANGE; + } + } +exit: + return upgrade; +} + +QDF_STATUS policy_mgr_update_connection_info(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0, ch_freq, cur_freq; + bool found = false; + struct policy_mgr_vdev_entry_info conn_table_entry; + enum policy_mgr_chain_mode chain_mask = POLICY_MGR_ONE_ONE; + uint8_t nss_2g, nss_5g; + enum policy_mgr_con_mode mode; + uint32_t nss = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = true; + break; + } + conn_index++; + } + + if (!found) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + /* err msg */ + policy_mgr_err("can't find vdev_id %d in pm_conc_connection_list", + vdev_id); + return QDF_STATUS_NOT_INITIALIZED; + } + if (pm_ctx->wma_cbacks.wma_get_connection_info) { + status = pm_ctx->wma_cbacks.wma_get_connection_info( + vdev_id, &conn_table_entry); + if (QDF_STATUS_SUCCESS != status) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_err("can't find vdev_id %d in connection table", + vdev_id); + return status; + } + } else { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_err("wma_get_connection_info is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cur_freq = pm_conc_connection_list[conn_index].freq; + + mode = policy_mgr_qdf_opmode_to_pm_con_mode( + psoc, + wlan_get_opmode_from_vdev_id( + pm_ctx->pdev, + vdev_id), + vdev_id); + + ch_freq = conn_table_entry.mhz; + status = policy_mgr_get_nss_for_vdev(psoc, mode, &nss_2g, &nss_5g); + if (QDF_IS_STATUS_SUCCESS(status)) { + if ((WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq) && nss_2g > 1) || + (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && nss_5g > 1)) + chain_mask = POLICY_MGR_TWO_TWO; + else + chain_mask = POLICY_MGR_ONE_ONE; + nss = (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) ? nss_2g : nss_5g; + } else { + policy_mgr_err("Error in getting nss"); + } + + policy_mgr_debug("update PM connection table for vdev:%d", vdev_id); + + /* add the entry */ + policy_mgr_update_conc_list( + psoc, conn_index, mode, ch_freq, + policy_mgr_get_bw(conn_table_entry.chan_width), + conn_table_entry.mac_id, chain_mask, + nss, vdev_id, true, true, conn_table_entry.ch_flagext); + policy_mgr_dump_current_concurrency(psoc); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* do we need to change the HW mode */ + policy_mgr_check_n_start_opportunistic_timer(psoc); + + if (policy_mgr_is_conc_sap_present_on_sta_freq(psoc, mode, cur_freq) && + policy_mgr_update_indoor_concurrency(psoc, vdev_id, 0, + SWITCH_WITH_CONCURRENCY)) + wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev); + else if (policy_mgr_update_indoor_concurrency(psoc, vdev_id, cur_freq, + SWITCH_WITHOUT_CONCURRENCY)) + wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev); + else if (wlan_reg_get_keep_6ghz_sta_cli_connection(pm_ctx->pdev) && + (mode == PM_STA_MODE || mode == PM_P2P_CLIENT_MODE)) + wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev); + + ml_nlink_conn_change_notify( + psoc, vdev_id, ml_nlink_connection_updated_evt, NULL); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_update_and_wait_for_connection_update( + struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason) +{ + QDF_STATUS status; + + policy_mgr_debug("session:%d ch_freq:%d reason:%d", + session_id, ch_freq, reason); + + status = policy_mgr_reset_connection_update(psoc); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("clearing event failed"); + + status = policy_mgr_current_connections_update( + psoc, session_id, ch_freq, reason, + POLICY_MGR_DEF_REQ_ID); + if (QDF_STATUS_E_FAILURE == status) { + policy_mgr_err("connections update failed"); + return QDF_STATUS_E_FAILURE; + } + + /* Wait only when status is success */ + if (QDF_IS_STATUS_SUCCESS(status)) { + status = policy_mgr_wait_for_connection_update(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("qdf wait for event failed"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_dbs_allowed_for_concurrency( + struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE new_conn_mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t count, dbs_for_sta_sta, dbs_for_sta_p2p; + bool ret = true; + uint32_t ch_sel_plcy; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return ret; + } + + count = policy_mgr_get_connection_count(psoc); + + if (count != 1 || new_conn_mode == QDF_MAX_NO_OF_MODE) + return ret; + + ch_sel_plcy = pm_ctx->cfg.chnl_select_plcy; + dbs_for_sta_sta = PM_CHANNEL_SELECT_LOGIC_STA_STA_GET(ch_sel_plcy); + dbs_for_sta_p2p = PM_CHANNEL_SELECT_LOGIC_STA_P2P_GET(ch_sel_plcy); + + switch (pm_conc_connection_list[0].mode) { + case PM_STA_MODE: + switch (new_conn_mode) { + case QDF_STA_MODE: + if (!dbs_for_sta_sta) + return false; + break; + case QDF_P2P_DEVICE_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + if (!dbs_for_sta_p2p) + return false; + break; + default: + break; + } + break; + case PM_P2P_CLIENT_MODE: + case PM_P2P_GO_MODE: + switch (new_conn_mode) { + case QDF_STA_MODE: + if (!dbs_for_sta_p2p) + return false; + break; + default: + break; + } + break; + case PM_NAN_DISC_MODE: + switch (new_conn_mode) { + case QDF_STA_MODE: + case QDF_SAP_MODE: + case QDF_NDI_MODE: + return true; + default: + return false; + } + break; + default: + break; + } + + return ret; +} + +bool policy_mgr_is_chnl_in_diff_band(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + uint8_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + /* + * check given channel freq against already existing connections' + * channel freqs. if they differ then channels are in different bands + */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use) + if (!WLAN_REG_IS_SAME_BAND_FREQS( + ch_freq, pm_conc_connection_list[i].freq)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("channel is in diff band"); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return false; +} + +bool policy_mgr_is_hwmode_set_for_given_chnl(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + enum policy_mgr_band band; + bool is_hwmode_dbs, dbs_required_for_2g; + + if (policy_mgr_is_hwmode_offload_enabled(psoc)) + return true; + + if (policy_mgr_is_hw_dbs_capable(psoc) == false) + return true; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) + band = POLICY_MGR_BAND_24; + else + band = POLICY_MGR_BAND_5; + + is_hwmode_dbs = policy_mgr_is_current_hwmode_dbs(psoc); + dbs_required_for_2g = policy_mgr_is_hw_dbs_required_for_band( + psoc, HW_MODE_MAC_BAND_2G); + /* + * If HW supports 2x2 chains in DBS HW mode and if DBS HW mode is not + * yet set then this is the right time to block the connection. + */ + if (band == POLICY_MGR_BAND_24 && dbs_required_for_2g && + !is_hwmode_dbs) { + policy_mgr_err("HW mode is not yet in DBS!!!!!"); + return false; + } + + return true; +} + +/** + * policy_mgr_pri_id_to_con_mode() - convert policy_mgr_pri_id to + * policy_mgr_con_mode + * @pri_id: policy_mgr_pri_id + * + * The help function converts policy_mgr_pri_id type to policy_mgr_con_mode + * type. + * + * Return: policy_mgr_con_mode type. + */ +static +enum policy_mgr_con_mode policy_mgr_pri_id_to_con_mode( + enum policy_mgr_pri_id pri_id) +{ + switch (pri_id) { + case PM_STA_PRI_ID: + return PM_STA_MODE; + case PM_SAP_PRI_ID: + return PM_SAP_MODE; + case PM_P2P_GO_PRI_ID: + return PM_P2P_GO_MODE; + case PM_P2P_CLI_PRI_ID: + return PM_P2P_CLIENT_MODE; + default: + return PM_MAX_NUM_OF_MODE; + } +} + +enum policy_mgr_conc_next_action +policy_mgr_get_preferred_dbs_action_table( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_con_mode pri_conn_mode = PM_MAX_NUM_OF_MODE; + enum policy_mgr_con_mode new_conn_mode = PM_MAX_NUM_OF_MODE; + enum QDF_OPMODE new_conn_op_mode = QDF_MAX_NO_OF_MODE; + bool band_pref_5g = true; + bool vdev_priority_enabled = false; + bool dbs_2x2_5g_1x1_2g_supported; + bool dbs_2x2_2g_1x1_5g_supported; + uint32_t vdev_pri_list, vdev_pri_id; + uint32_t ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1]; + uint8_t vdev_list[MAX_NUMBER_OF_CONC_CONNECTIONS + 1]; + uint32_t vdev_count = 0; + uint32_t i; + bool found; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return PM_NOP; + } + dbs_2x2_5g_1x1_2g_supported = + policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc); + dbs_2x2_2g_1x1_5g_supported = + policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc); + policy_mgr_debug("target support DBS1 %d DBS2 %d", + dbs_2x2_5g_1x1_2g_supported, + dbs_2x2_2g_1x1_5g_supported); + /* + * If both DBS1 and DBS2 not supported, this should be Legacy Single + * DBS mode HW. The policy_mgr_psoc_enable has setup the correct + * action tables. + */ + if (!dbs_2x2_5g_1x1_2g_supported && !dbs_2x2_2g_1x1_5g_supported) + return PM_NOP; + if (!dbs_2x2_5g_1x1_2g_supported) { + band_pref_5g = false; + policy_mgr_debug("target only supports DBS2!"); + goto DONE; + } + if (!dbs_2x2_2g_1x1_5g_supported) { + policy_mgr_debug("target only supports DBS1!"); + goto DONE; + } + if (PM_GET_BAND_PREFERRED(pm_ctx->cfg.dbs_selection_plcy) == 1) + band_pref_5g = false; + + if (PM_GET_VDEV_PRIORITY_ENABLED( + pm_ctx->cfg.dbs_selection_plcy) == 1 && + pm_ctx->cfg.vdev_priority_list) + vdev_priority_enabled = true; + + if (!vdev_priority_enabled) + goto DONE; + + if (vdev_id != INVALID_VDEV_ID && ch_freq) { + if (pm_ctx->hdd_cbacks.hdd_get_device_mode) + new_conn_op_mode = pm_ctx->hdd_cbacks. + hdd_get_device_mode(vdev_id); + + new_conn_mode = + policy_mgr_qdf_opmode_to_pm_con_mode(psoc, + new_conn_op_mode, + vdev_id); + if (new_conn_mode == PM_MAX_NUM_OF_MODE) + policy_mgr_debug("new vdev %d op_mode %d freq %d reason %d: not prioritized", + vdev_id, new_conn_op_mode, + ch_freq, reason); + else + policy_mgr_debug("new vdev %d op_mode %d freq %d : reason %d", + vdev_id, new_conn_op_mode, ch_freq, + reason); + } + vdev_pri_list = pm_ctx->cfg.vdev_priority_list; + while (vdev_pri_list) { + vdev_pri_id = vdev_pri_list & 0xF; + pri_conn_mode = policy_mgr_pri_id_to_con_mode(vdev_pri_id); + if (pri_conn_mode == PM_MAX_NUM_OF_MODE) { + policy_mgr_debug("vdev_pri_id %d prioritization not supported", + vdev_pri_id); + goto NEXT; + } + vdev_count = policy_mgr_get_mode_specific_conn_info( + psoc, ch_freq_list, vdev_list, pri_conn_mode); + /** + * Take care of duplication case, the vdev id may + * exist in the conn list already with old chan. + * Replace with new chan before make decision. + */ + found = false; + for (i = 0; i < vdev_count; i++) { + policy_mgr_debug("[%d] vdev %d chan %d conn_mode %d", + i, vdev_list[i], ch_freq_list[i], + pri_conn_mode); + + if (new_conn_mode == pri_conn_mode && + vdev_list[i] == vdev_id) { + ch_freq_list[i] = ch_freq; + found = true; + } + } + /** + * The new coming vdev should be added to the list to + * make decision if it is prioritized. + */ + if (!found && new_conn_mode == pri_conn_mode) { + ch_freq_list[vdev_count] = ch_freq; + vdev_list[vdev_count++] = vdev_id; + } + /** + * if more than one vdev has same priority, keep "band_pref_5g" + * value as default band preference setting. + */ + if (vdev_count > 1) + break; + /** + * select the only active vdev (or new coming vdev) chan as + * preferred band. + */ + if (vdev_count > 0) { + band_pref_5g = + WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq_list[0]); + break; + } +NEXT: + vdev_pri_list >>= 4; + } +DONE: + policy_mgr_debug("band_pref_5g %d", band_pref_5g); + if (band_pref_5g) + return PM_DBS1; + else + return PM_DBS2; +} + +/** + * policy_mgr_get_second_conn_action_table() - get second conn action table + * @psoc: Pointer to psoc + * @vdev_id: vdev Id + * @ch_freq: channel frequency of vdev. + * @reason: reason of request + * + * Get the action table based on current HW Caps and INI user preference. + * This function will be called by policy_mgr_current_connections_update during + * DBS action decision. + * + * return : action table address + */ +static policy_mgr_next_action_two_connection_table_type * +policy_mgr_get_second_conn_action_table( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason) +{ + enum policy_mgr_conc_next_action preferred_action; + + if (!policy_mgr_is_2x2_1x1_dbs_capable(psoc)) + return next_action_two_connection_table; + + preferred_action = policy_mgr_get_preferred_dbs_action_table( + psoc, vdev_id, ch_freq, reason); + switch (preferred_action) { + case PM_DBS2: + return next_action_two_connection_2x2_2g_1x1_5g_table; + default: + return next_action_two_connection_table; + } +} + +/** + * policy_mgr_get_third_conn_action_table() - get third connection action table + * @psoc: Pointer to psoc + * @vdev_id: vdev Id + * @ch_freq: channel frequency of vdev. + * @reason: reason of request + * + * Get the action table based on current HW Caps and INI user preference. + * This function will be called by policy_mgr_current_connections_update during + * DBS action decision. + * + * return : action table address + */ +static policy_mgr_next_action_three_connection_table_type * +policy_mgr_get_third_conn_action_table( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason) +{ + enum policy_mgr_conc_next_action preferred_action; + + if (!policy_mgr_is_2x2_1x1_dbs_capable(psoc)) + return next_action_three_connection_table; + + preferred_action = policy_mgr_get_preferred_dbs_action_table( + psoc, vdev_id, ch_freq, reason); + switch (preferred_action) { + case PM_DBS2: + return next_action_three_connection_2x2_2g_1x1_5g_table; + default: + return next_action_three_connection_table; + } +} + +bool +policy_mgr_is_conn_lead_to_dbs_sbs(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t freq) +{ + struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint32_t connection_count, i; + + connection_count = policy_mgr_get_connection_info(psoc, info); + for (i = 0; i < connection_count; i++) { + /* Ignore the vdev id for which freq is passed */ + if (vdev_id == info[i].vdev_id) + continue; + if (!policy_mgr_2_freq_always_on_same_mac(psoc, freq, + info[i].ch_freq)) + return true; + } + return false; +} + +static QDF_STATUS +policy_mgr_get_next_action(struct wlan_objmgr_psoc *psoc, + uint32_t session_id, + uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason, + enum policy_mgr_conc_next_action *next_action) +{ + uint32_t num_connections = 0; + enum policy_mgr_one_connection_mode second_index = 0; + enum policy_mgr_two_connection_mode third_index = 0; + policy_mgr_next_action_two_connection_table_type *second_conn_table; + policy_mgr_next_action_three_connection_table_type *third_conn_table; + enum policy_mgr_band band; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum QDF_OPMODE new_conn_mode = QDF_MAX_NO_OF_MODE; + + if (!next_action) { + policy_mgr_err("next_action is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (policy_mgr_is_hwmode_offload_enabled(psoc)) { + *next_action = PM_NOP; + policy_mgr_get_sap_ch_width_update_action(psoc, session_id, + ch_freq, + next_action, &reason); + return QDF_STATUS_SUCCESS; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) + band = POLICY_MGR_BAND_24; + else + band = POLICY_MGR_BAND_5; + + num_connections = policy_mgr_get_connection_count(psoc); + + policy_mgr_debug("num_connections=%d freq=%d", + num_connections, ch_freq); + + switch (num_connections) { + case 0: + if (band == POLICY_MGR_BAND_24) + if (policy_mgr_is_hw_dbs_required_for_band( + psoc, HW_MODE_MAC_BAND_2G)) + *next_action = PM_DBS; + else + *next_action = PM_NOP; + else + *next_action = PM_NOP; + break; + case 1: + second_index = + policy_mgr_get_second_connection_pcl_table_index(psoc); + if (PM_MAX_ONE_CONNECTION_MODE == second_index) { + policy_mgr_err( + "couldn't find index for 2nd connection next action table"); + return QDF_STATUS_E_FAILURE; + } + second_conn_table = policy_mgr_get_second_conn_action_table( + psoc, session_id, ch_freq, reason); + *next_action = (*second_conn_table)[second_index][band]; + break; + case 2: + third_index = + policy_mgr_get_third_connection_pcl_table_index(psoc); + if (PM_MAX_TWO_CONNECTION_MODE == third_index) { + policy_mgr_err( + "couldn't find index for 3rd connection next action table"); + return QDF_STATUS_E_FAILURE; + } + third_conn_table = policy_mgr_get_third_conn_action_table( + psoc, session_id, ch_freq, reason); + *next_action = (*third_conn_table)[third_index][band]; + break; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + break; + } + + /* + * There is no adapter associated with NAN Discovery, hence skip the + * HDD callback and fill separately. + */ + if (reason == POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY) + new_conn_mode = QDF_NAN_DISC_MODE; + else if (pm_ctx->hdd_cbacks.hdd_get_device_mode) + new_conn_mode = pm_ctx->hdd_cbacks. + hdd_get_device_mode(session_id); + + /* + * Based on channel_select_logic_conc ini, hw mode is set + * when second connection is about to come up that results + * in STA+STA and STA+P2P concurrency. + * 1) If MCC is set and if current hw mode is dbs, hw mode + * should be set to single mac for above concurrency. + * 2) If MCC is set and if current hw mode is not dbs, hw + * mode change is not required. + */ + if (policy_mgr_is_current_hwmode_dbs(psoc) && + !policy_mgr_is_dbs_allowed_for_concurrency(psoc, new_conn_mode)) + *next_action = PM_SINGLE_MAC; + else if (!policy_mgr_is_current_hwmode_dbs(psoc) && + !policy_mgr_is_dbs_allowed_for_concurrency(psoc, new_conn_mode)) + *next_action = PM_NOP; + + policy_mgr_debug("idx2=%d idx3=%d next_action=%d, band=%d reason=%d session_id=%d", + second_index, third_index, *next_action, band, + reason, session_id); + + return QDF_STATUS_SUCCESS; +} + +static bool +policy_mgr_is_hw_mode_change_required(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, uint8_t vdev_id) +{ + if (policy_mgr_is_hw_dbs_required_for_band(psoc, HW_MODE_MAC_BAND_2G)) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) + return true; + } else { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq) && + policy_mgr_is_any_mode_active_on_band_along_with_session + (psoc, vdev_id, POLICY_MGR_BAND_5)) + return true; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && + policy_mgr_is_any_mode_active_on_band_along_with_session + (psoc, vdev_id, POLICY_MGR_BAND_24)) + return true; + } + + return false; +} + +static bool +policy_mgr_is_ch_width_downgrade_required(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct scan_cache_entry *entry, + qdf_list_t *scan_list) + +{ + if (policy_mgr_is_conn_lead_to_dbs_sbs(psoc, vdev_id, + entry->channel.chan_freq) || + wlan_cm_bss_mlo_type(psoc, entry, scan_list)) + return true; + + return false; +} + +static uint32_t +policy_mgr_check_for_hw_mode_change(struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, uint8_t vdev_id) +{ + + struct scan_cache_node *scan_node = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + uint32_t ch_freq = 0; + struct scan_cache_entry *entry; + bool eht_capab = false, check_sap_bw_downgrade = false; + enum phy_ch_width cur_bw = CH_WIDTH_INVALID; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + goto end; + + if (policy_mgr_is_hwmode_offload_enabled(psoc)) { + /* + * Stop any running opportunistic timer as it will be started + * after decision if required. + */ + policy_mgr_stop_opportunistic_timer(psoc); + wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); + if (eht_capab && + QDF_IS_STATUS_SUCCESS(policy_mgr_get_sap_bw(psoc, + &cur_bw)) && + cur_bw == CH_WIDTH_320MHZ && + !mlo_mgr_is_link_switch_in_progress(vdev)) + check_sap_bw_downgrade = true; + else + goto end; + } + + if (!scan_list || !qdf_list_size(scan_list)) { + policy_mgr_debug("Scan list is NULL or No BSSIDs present"); + goto end; + } + + if (!policy_mgr_is_hw_dbs_capable(psoc)) { + policy_mgr_debug("Driver isn't DBS capable"); + goto end; + } + + if (check_sap_bw_downgrade) + goto ch_width_update; + + if (!policy_mgr_is_dbs_allowed_for_concurrency(psoc, QDF_STA_MODE)) { + policy_mgr_debug("DBS not allowed for concurrency combo"); + goto end; + } + + if (!policy_mgr_is_hw_dbs_2x2_capable(psoc) && + !policy_mgr_is_hw_dbs_required_for_band(psoc, + HW_MODE_MAC_BAND_2G) && + !policy_mgr_get_connection_count(psoc)) { + policy_mgr_debug("1x1 DBS with no existing connection, HW mode change not required"); + goto end; + } + +ch_width_update: + qdf_list_peek_front(scan_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(scan_list, cur_node, &next_node); + + scan_node = qdf_container_of(cur_node, struct scan_cache_node, + node); + entry = scan_node->entry; + ch_freq = entry->channel.chan_freq; + + if (policy_mgr_is_hw_mode_change_required(psoc, ch_freq, + vdev_id) || + policy_mgr_is_ch_width_downgrade_required(psoc, vdev_id, + entry, + scan_list)) { + policy_mgr_debug("Scan list has BSS of freq %d hw mode/SAP ch_width:%d update required", + ch_freq, cur_bw); + break; + } + + ch_freq = 0; + cur_node = next_node; + next_node = NULL; + } + +end: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return ch_freq; +} + +QDF_STATUS +policy_mgr_change_hw_mode_sta_connect(struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, uint8_t vdev_id, + uint32_t connect_id) +{ + QDF_STATUS status; + uint32_t ch_freq; + + ch_freq = policy_mgr_check_for_hw_mode_change(psoc, scan_list, vdev_id); + if (!ch_freq) + return QDF_STATUS_E_ALREADY; + + status = policy_mgr_current_connections_update(psoc, vdev_id, ch_freq, + POLICY_MGR_UPDATE_REASON_STA_CONNECT, connect_id); + + /* + * If status is success then the callback of policy mgr hw mode change + * would be called. + * If status is no support then the DUT is already in required HW mode. + */ + + if (status == QDF_STATUS_E_FAILURE) + policy_mgr_err("Hw mode change failed"); + else if (status == QDF_STATUS_E_NOSUPPORT) + status = QDF_STATUS_E_ALREADY; + + return status; +} + +QDF_STATUS +policy_mgr_current_connections_update(struct wlan_objmgr_psoc *psoc, + uint32_t session_id, uint32_t ch_freq, + enum policy_mgr_conn_update_reason + reason, uint32_t request_id) +{ + enum policy_mgr_conc_next_action next_action = PM_NOP; + QDF_STATUS status; + + if (!policy_mgr_is_hw_dbs_capable(psoc)) { + policy_mgr_rl_debug("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + + status = policy_mgr_get_next_action(psoc, session_id, ch_freq, reason, + &next_action); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + if (PM_NOP != next_action) + status = policy_mgr_next_actions(psoc, session_id, + next_action, reason, + request_id); + else + status = QDF_STATUS_E_NOSUPPORT; + + policy_mgr_debug("next_action %d reason=%d session_id=%d request_id %x", + next_action, reason, session_id, request_id); + + return status; +} + +/** + * policy_mgr_dbs1_dbs2_need_action() - whether more actions are needed + * in DBS1 and DBS2 hw mode + * @psoc: psoc object + * @action: action type + * @hw_mode: hardware mode + * + * The function checks further action are needed or not for DBS1 and DBS2. + * + * Return: true if more action are needed, otherwise + * return false + */ +static bool +policy_mgr_dbs1_dbs2_need_action(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conc_next_action action, + struct policy_mgr_hw_mode_params *hw_mode) +{ + if (policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc) || + policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc)) { + policy_mgr_debug("curr dbs action %d new action %d", + hw_mode->action_type, action); + if (hw_mode->action_type == PM_DBS1 && + ((action == PM_DBS1 || + action == PM_DBS1_DOWNGRADE))) { + policy_mgr_debug("driver is already in DBS_5G_2x2_24G_1x1 (%d), no further action %d needed", + hw_mode->action_type, action); + return false; + } else if (hw_mode->action_type == PM_DBS2 && + ((action == PM_DBS2 || + action == PM_DBS2_DOWNGRADE))) { + policy_mgr_debug("driver is already in DBS_24G_2x2_5G_1x1 (%d), no further action %d needed", + hw_mode->action_type, action); + return false; + } + } + + return true; +} + +QDF_STATUS +policy_mgr_validate_dbs_switch(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conc_next_action action) +{ + QDF_STATUS status; + struct policy_mgr_hw_mode_params hw_mode; + + /* check for the current HW index to see if really need any action */ + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return status; + } + + if ((action == PM_SBS) || (action == PM_SBS_DOWNGRADE)) { + if (!policy_mgr_is_hw_sbs_capable(psoc)) { + /* No action */ + policy_mgr_notice("firmware is not sbs capable"); + return QDF_STATUS_E_NOSUPPORT; + } + /* current mode is already SBS nothing to be + * done + */ + if (hw_mode.sbs_cap) { + policy_mgr_notice("current mode is already SBS"); + return QDF_STATUS_E_ALREADY; + } + return QDF_STATUS_SUCCESS; + } + + if (!hw_mode.dbs_cap) { + if (action == PM_SINGLE_MAC || + action == PM_SINGLE_MAC_UPGRADE) { + policy_mgr_notice("current mode is already single MAC"); + return QDF_STATUS_E_ALREADY; + } else { + return QDF_STATUS_SUCCESS; + } + } + /** + * If already in DBS, no need to request DBS again (HL, Napier). + * For dual DBS HW, in case DBS1 -> DBS2 or DBS2 -> DBS1 + * switching, we need to check the current DBS mode is same as + * requested or not. + */ + if (policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc) || + policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc)) { + if (!policy_mgr_dbs1_dbs2_need_action(psoc, action, &hw_mode)) + return QDF_STATUS_E_ALREADY; + } else if ((action == PM_DBS_DOWNGRADE) || (action == PM_DBS) || + (action == PM_DBS_UPGRADE)) { + policy_mgr_debug("driver is already in %s mode, no further action needed", + (hw_mode.dbs_cap) ? "dbs" : "non dbs"); + return QDF_STATUS_E_ALREADY; + } + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_validate_unsupported_action() - unsupported action validation + * @psoc: psoc object + * @action: action type + * + * The help function checks the Action supported by HW or not. + * + * Return: QDF_STATUS_SUCCESS if supported by HW, otherwise + * return QDF_STATUS_E_NOSUPPORT + */ +static QDF_STATUS policy_mgr_validate_unsupported_action + (struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conc_next_action action) +{ + if (action == PM_SBS || action == PM_SBS_DOWNGRADE) { + if (!policy_mgr_is_hw_sbs_capable(psoc)) { + /* No action */ + policy_mgr_notice("firmware is not sbs capable"); + return QDF_STATUS_E_NOSUPPORT; + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_next_actions( + struct wlan_objmgr_psoc *psoc, + uint32_t session_id, + enum policy_mgr_conc_next_action action, + enum policy_mgr_conn_update_reason reason, + uint32_t request_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct dbs_nss nss_dbs = {0}; + struct dbs_bw bw_dbs = {0}; + struct policy_mgr_hw_mode_params hw_mode; + enum policy_mgr_conc_next_action next_action; + bool is_sbs_supported; + enum hw_mode_sbs_capab sbs_capab; + + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + policy_mgr_rl_debug("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + status = policy_mgr_validate_unsupported_action(psoc, action); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + /* check for the current HW index to see if really need any action */ + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return status; + } + + switch (action) { + case PM_DBS_DOWNGRADE: + /* + * check if we have a beaconing entity that is using 2x2. If yes, + * update the beacon template & notify FW. Once FW confirms + * beacon updated, send down the HW mode change req + */ + status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1, + PM_DBS, reason, session_id, request_id); + break; + case PM_DBS: + (void)policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs); + policy_mgr_get_hw_dbs_max_bw(psoc, &bw_dbs); + is_sbs_supported = policy_mgr_is_hw_sbs_capable(psoc); + sbs_capab = is_sbs_supported ? HW_MODE_SBS : HW_MODE_SBS_NONE; + status = policy_mgr_pdev_set_hw_mode(psoc, session_id, + nss_dbs.mac0_ss, + bw_dbs.mac0_bw, + nss_dbs.mac1_ss, + bw_dbs.mac1_bw, + HW_MODE_MAC_BAND_NONE, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + sbs_capab, + reason, PM_NOP, PM_DBS, + request_id); + break; + case PM_SINGLE_MAC_UPGRADE: + /* + * change the HW mode first before the NSS upgrade + */ + status = policy_mgr_pdev_set_hw_mode(psoc, session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_MAC_BAND_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason, PM_UPGRADE, + PM_SINGLE_MAC_UPGRADE, + request_id); + break; + case PM_SINGLE_MAC: + status = policy_mgr_pdev_set_hw_mode(psoc, session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_0x0, HW_MODE_BW_NONE, + HW_MODE_MAC_BAND_NONE, + HW_MODE_DBS_NONE, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason, PM_NOP, PM_SINGLE_MAC, + request_id); + break; + case PM_DBS_UPGRADE: + status = policy_mgr_pdev_set_hw_mode(psoc, session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_2x2, HW_MODE_80_MHZ, + HW_MODE_MAC_BAND_NONE, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason, PM_UPGRADE, + PM_DBS_UPGRADE, request_id); + break; + case PM_SBS_DOWNGRADE: + status = policy_mgr_complete_action(psoc, POLICY_MGR_RX_NSS_1, + PM_SBS, reason, session_id, request_id); + break; + case PM_SBS: + status = policy_mgr_pdev_set_hw_mode(psoc, session_id, + HW_MODE_SS_1x1, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_80_MHZ, + HW_MODE_MAC_BAND_NONE, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS, + reason, PM_NOP, PM_SBS, + request_id); + break; + case PM_DOWNGRADE: + /* + * check if we have a beaconing entity that advertised 2x2 + * initially. If yes, update the beacon template & notify FW. + */ + status = policy_mgr_nss_update(psoc, POLICY_MGR_RX_NSS_1, + PM_NOP, POLICY_MGR_ANY, reason, + session_id, request_id); + break; + case PM_UPGRADE: + /* + * check if we have a beaconing entity that advertised 2x2 + * initially. If yes, update the beacon template & notify FW. + */ + status = policy_mgr_nss_update(psoc, POLICY_MGR_RX_NSS_2, + PM_NOP, POLICY_MGR_ANY, reason, + session_id, request_id); + break; + case PM_DBS1_DOWNGRADE: + if (policy_mgr_dbs1_dbs2_need_action(psoc, action, &hw_mode)) + status = policy_mgr_complete_action(psoc, + POLICY_MGR_RX_NSS_1, + PM_DBS1, reason, + session_id, + request_id); + else + status = QDF_STATUS_E_ALREADY; + break; + case PM_DBS2_DOWNGRADE: + if (policy_mgr_dbs1_dbs2_need_action(psoc, action, &hw_mode)) + status = policy_mgr_complete_action(psoc, + POLICY_MGR_RX_NSS_1, + PM_DBS2, reason, + session_id, + request_id); + else + status = QDF_STATUS_E_ALREADY; + break; + case PM_DBS1: + /* + * PM_DBS1 (2x2 5G + 1x1 2G) will support 5G 2x2. If previous + * mode is DBS, that should be 2x2 2G + 1x1 5G mode and + * the 5G band was downgraded to 1x1. So, we need to + * upgrade 5G vdevs after hw mode change. + */ + if (policy_mgr_dbs1_dbs2_need_action(psoc, action, &hw_mode)) { + if (hw_mode.dbs_cap) + next_action = PM_UPGRADE_5G; + else + next_action = PM_NOP; + status = policy_mgr_pdev_set_hw_mode( + psoc, session_id, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_MAC_BAND_5G, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason, next_action, PM_DBS1, + request_id); + } else { + status = QDF_STATUS_E_ALREADY; + } + break; + case PM_DBS2: + /* + * PM_DBS2 (2x2 2G + 1x1 5G) will support 2G 2x2. If previous + * mode is DBS, that should be 2x2 5G + 1x1 2G mode and + * the 2G band was downgraded to 1x1. So, we need to + * upgrade 5G vdevs after hw mode change. + */ + if (policy_mgr_dbs1_dbs2_need_action(psoc, action, &hw_mode)) { + if (hw_mode.dbs_cap) + next_action = PM_UPGRADE_2G; + else + next_action = PM_NOP; + status = policy_mgr_pdev_set_hw_mode( + psoc, session_id, + HW_MODE_SS_2x2, + HW_MODE_40_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_MAC_BAND_2G, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE, + reason, next_action, PM_DBS2, + request_id); + } else { + status = QDF_STATUS_E_ALREADY; + } + break; + case PM_UPGRADE_5G: + status = policy_mgr_nss_update( + psoc, POLICY_MGR_RX_NSS_2, + PM_NOP, POLICY_MGR_BAND_5, reason, + session_id, request_id); + break; + case PM_UPGRADE_2G: + status = policy_mgr_nss_update( + psoc, POLICY_MGR_RX_NSS_2, + PM_NOP, POLICY_MGR_BAND_24, reason, + session_id, request_id); + break; + case PM_DOWNGRADE_BW: + case PM_UPGRADE_BW: + policy_mgr_sap_ch_width_update(psoc, action, reason, + session_id, request_id); + break; + default: + policy_mgr_err("unexpected action value %d", action); + status = QDF_STATUS_E_FAILURE; + break; + } + + return status; +} + +QDF_STATUS +policy_mgr_handle_conc_multiport(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + enum policy_mgr_conn_update_reason reason, + uint32_t request_id) +{ + QDF_STATUS status; + uint8_t num_cxn_del = 0; + struct policy_mgr_conc_connection_info info = {0}; + + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id, + &info, &num_cxn_del); + + if (!policy_mgr_check_for_session_conc(psoc, vdev_id, ch_freq)) { + policy_mgr_err("Conc not allowed for the vdev %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + status = policy_mgr_reset_connection_update(psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) + policy_mgr_err("clearing event failed"); + + status = policy_mgr_current_connections_update(psoc, vdev_id, + ch_freq, reason, + request_id); + if (QDF_STATUS_E_FAILURE == status) + policy_mgr_err("connections update failed"); + + if (num_cxn_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, &info, + num_cxn_del); + + return status; +} + +enum policy_mgr_con_mode +policy_mgr_con_mode_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE; + enum QDF_OPMODE op_mode; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return mode; + } + + op_mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + return policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, vdev_id); +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +qdf_freq_t +policy_mgr_get_user_config_sap_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + qdf_freq_t freq; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return 0; + } + freq = wlan_get_sap_user_config_freq(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return freq; +} + +/** + * policy_mgr_is_sap_go_existed() - Check if restart SAP/Go exist + * @psoc: PSOC object data + * + * To simplify, if SAP/P2P Go exist, they may need switch channel for + * forcing scc with sta or band capability change. + * Restart: true or false + */ +static bool policy_mgr_is_sap_go_existed(struct wlan_objmgr_psoc *psoc) +{ + uint32_t ap_present, go_present; + + ap_present = policy_mgr_get_sap_mode_count(psoc, NULL); + if (ap_present) + return true; + + go_present = policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, NULL); + if (go_present) + return true; + + return false; +} + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +bool policy_mgr_is_safe_channel(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool is_safe = true; + uint8_t j; + unsigned long restriction_mask; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return is_safe; + } + + if (pm_ctx->unsafe_channel_count == 0) + return is_safe; + + restriction_mask = + (unsigned long)policy_mgr_get_freq_restriction_mask(pm_ctx); + for (j = 0; j < pm_ctx->unsafe_channel_count; j++) { + if ((ch_freq == pm_ctx->unsafe_channel_list[j]) && + (qdf_test_bit(QDF_SAP_MODE, &restriction_mask) || + !wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + psoc))) { + is_safe = false; + policy_mgr_warn("Freq %d is not safe, restriction mask %lu", ch_freq, restriction_mask); + break; + } + } + + return is_safe; +} + +bool policy_mgr_restrict_sap_on_unsafe_chan(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + unsigned long restriction_mask; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return false; + } + + restriction_mask = + (unsigned long)policy_mgr_get_freq_restriction_mask(pm_ctx); + return qdf_test_bit(QDF_SAP_MODE, &restriction_mask); +} +#else +bool policy_mgr_is_safe_channel(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool is_safe = true; + uint8_t j; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return is_safe; + } + + if (pm_ctx->unsafe_channel_count == 0) + return is_safe; + + for (j = 0; j < pm_ctx->unsafe_channel_count; j++) { + if (ch_freq == pm_ctx->unsafe_channel_list[j]) { + is_safe = false; + policy_mgr_warn("Freq %d is not safe", ch_freq); + break; + } + } + + return is_safe; +} +#endif + +bool policy_mgr_is_sap_freq_allowed(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE opmode, + uint32_t sap_freq) +{ + uint32_t nan_2g_freq, nan_5g_freq; + + /* + * Ignore safe channel validation when the mode is P2P_GO and user + * configures the corresponding bit in ini coex_unsafe_chan_nb_user_prefer. + */ + if ((opmode == QDF_P2P_GO_MODE && + wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_p2p_go(psoc)) || + policy_mgr_is_safe_channel(psoc, sap_freq)) + return true; + + /* + * Return true if it's STA+SAP SCC and + * STA+SAP SCC on LTE coex channel is allowed. + */ + if (policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc) && + policy_mgr_is_sta_sap_scc(psoc, sap_freq)) { + policy_mgr_debug("unsafe freq %d for sap is allowed", sap_freq); + return true; + } + + nan_2g_freq = + policy_mgr_mode_specific_get_channel(psoc, PM_NAN_DISC_MODE); + nan_5g_freq = wlan_nan_get_disc_5g_ch_freq(psoc); + + if ((WLAN_REG_IS_SAME_BAND_FREQS(nan_2g_freq, sap_freq) || + WLAN_REG_IS_SAME_BAND_FREQS(nan_5g_freq, sap_freq)) && + policy_mgr_is_force_scc(psoc) && + policy_mgr_get_nan_sap_scc_on_lte_coex_chnl(psoc)) { + policy_mgr_debug("NAN+SAP SCC on unsafe freq %d is allowed", + sap_freq); + return true; + } + + return false; +} + +bool policy_mgr_is_sap_restart_required_after_sta_disconnect( + struct wlan_objmgr_psoc *psoc, + uint32_t sap_vdev_id, uint32_t *intf_ch_freq, + bool is_acs_mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t curr_sap_freq = 0, new_sap_freq = 0; + bool sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + bool sta_sap_scc_on_lte_coex_chan = + policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc); + uint8_t sta_sap_scc_on_dfs_chnl_config_value = 0; + uint32_t cc_count, i, go_index_start, pcl_len = 0; + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS * 2]; + uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS * 2]; + enum policy_mgr_con_mode mode; + uint32_t pcl_channels[NUM_CHANNELS + 1]; + uint8_t pcl_weight[NUM_CHANNELS + 1]; + struct policy_mgr_conc_connection_info info = {0}; + uint8_t num_cxn_del = 0; + QDF_STATUS status; + uint32_t sta_gc_present = 0; + qdf_freq_t user_config_freq = 0; + enum reg_wifi_band user_band, op_band; + + if (intf_ch_freq) + *intf_ch_freq = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return false; + } + + policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, &sta_sap_scc_on_dfs_chnl_config_value); + + if (!policy_mgr_is_hw_dbs_capable(psoc)) + if (policy_mgr_get_connection_count(psoc) > 1) + return false; + + cc_count = policy_mgr_get_mode_specific_conn_info(psoc, + &op_ch_freq_list[0], + &vdev_id[0], + PM_SAP_MODE); + go_index_start = cc_count; + if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS) + cc_count += policy_mgr_get_mode_specific_conn_info( + psoc, &op_ch_freq_list[cc_count], + &vdev_id[cc_count], PM_P2P_GO_MODE); + + sta_gc_present = + policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, NULL) + + policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL); + + for (i = 0 ; i < cc_count; i++) { + if (sap_vdev_id != INVALID_VDEV_ID && + sap_vdev_id != vdev_id[i]) + continue; + + sap_vdev_id = vdev_id[i]; + user_config_freq = + policy_mgr_get_user_config_sap_freq(psoc, sap_vdev_id); + + if (policy_mgr_is_any_mode_active_on_band_along_with_session( + psoc, vdev_id[i], + WLAN_REG_IS_24GHZ_CH_FREQ(op_ch_freq_list[i]) ? + POLICY_MGR_BAND_24 : POLICY_MGR_BAND_5)) + continue; + + if (sta_sap_scc_on_dfs_chan && + (sta_sap_scc_on_dfs_chnl_config_value != 2) && + wlan_reg_is_dfs_for_freq(pm_ctx->pdev, + op_ch_freq_list[i]) && + pm_ctx->last_disconn_sta_freq == op_ch_freq_list[i]) { + curr_sap_freq = op_ch_freq_list[i]; + policy_mgr_debug("sta_sap_scc_on_dfs_chan %u, sta_sap_scc_on_dfs_chnl_config_value %u, dfs sap_ch_freq %u", + sta_sap_scc_on_dfs_chan, + sta_sap_scc_on_dfs_chnl_config_value, + curr_sap_freq); + break; + } + + if ((is_acs_mode || + policy_mgr_restrict_sap_on_unsafe_chan(psoc)) && + sta_sap_scc_on_lte_coex_chan && + !policy_mgr_is_safe_channel(psoc, op_ch_freq_list[i]) && + pm_ctx->last_disconn_sta_freq == op_ch_freq_list[i]) { + curr_sap_freq = op_ch_freq_list[i]; + policy_mgr_debug("sta_sap_scc_on_lte_coex_chan %u unsafe sap_ch_freq %u", + sta_sap_scc_on_lte_coex_chan, + curr_sap_freq); + break; + } + /* When STA+SAP SCC is allowed on indoor channel, + * Restart the SAP when : + * 1. The user configured SAP frequency is not + * the same as current freq. (or) + * 2. The frequency is not allowed in the indoor + * channel. + */ + if (pm_ctx->last_disconn_sta_freq == op_ch_freq_list[i] && + !policy_mgr_is_sap_go_interface_allowed_on_indoor( + pm_ctx->pdev, + sap_vdev_id, + op_ch_freq_list[i])) { + curr_sap_freq = op_ch_freq_list[i]; + policy_mgr_debug("indoor sap_ch_freq %u", + curr_sap_freq); + break; + } + + /* + * STA got disconnected & SAP has previously moved to 2.4 GHz + * due to concurrency, then move SAP back to user configured + * frequency if the user configured band is better than + * the current operating band. + */ + op_band = wlan_reg_freq_to_band(op_ch_freq_list[i]); + user_band = wlan_reg_freq_to_band(user_config_freq); + + if (!sta_gc_present && user_config_freq && + op_band < user_band) { + curr_sap_freq = op_ch_freq_list[i]; + policy_mgr_debug("Move sap to user configured freq: %d", + user_config_freq); + break; + } + } + + if (!curr_sap_freq) { + policy_mgr_debug("SAP restart is not required"); + return false; + } + + mode = i >= go_index_start ? PM_P2P_GO_MODE : PM_SAP_MODE; + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, sap_vdev_id, + &info, &num_cxn_del); + + /* Add the user config ch as first condidate */ + pcl_channels[0] = user_config_freq; + pcl_weight[0] = 0; + status = policy_mgr_get_pcl(psoc, mode, &pcl_channels[1], &pcl_len, + &pcl_weight[1], + QDF_ARRAY_SIZE(pcl_weight) - 1, + sap_vdev_id); + if (status == QDF_STATUS_SUCCESS) + pcl_len++; + else + pcl_len = 1; + + + for (i = 0; i < pcl_len; i++) { + if (pcl_channels[i] == curr_sap_freq) + continue; + + if (!policy_mgr_is_safe_channel(psoc, pcl_channels[i]) || + wlan_reg_is_dfs_for_freq(pm_ctx->pdev, pcl_channels[i])) + continue; + + /* SAP moved to 2.4 GHz, due to STA on DFS or Indoor where + * concurrency is not allowed, now that there is no + * STA/GC in 5 GHz band, move 2.4 GHz SAP to 5 GHz band if SAP + * was initially started on 5 GHz band. + * Checking again here as pcl_channels[0] could be + * on indoor which is not removed in policy_mgr_get_pcl + */ + if (!sta_gc_present && + !policy_mgr_is_sap_go_interface_allowed_on_indoor( + pm_ctx->pdev, + sap_vdev_id, + pcl_channels[i])) { + policy_mgr_debug("Do not allow SAP on indoor frequency, STA is absent"); + continue; + } + + new_sap_freq = pcl_channels[i]; + break; + } + + /* Restore the connection entry */ + if (num_cxn_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (new_sap_freq == 0 || curr_sap_freq == new_sap_freq) + return false; + if (!intf_ch_freq) + return true; + + *intf_ch_freq = new_sap_freq; + policy_mgr_debug("Standalone SAP(vdev_id %d) will be moved to channel %u", + sap_vdev_id, *intf_ch_freq); + + return true; +} + +/** + * policy_mgr_is_nan_sap_unsafe_ch_scc_allowed() - Check if NAN+SAP SCC is + * allowed in LTE COEX unsafe ch + * @pm_ctx: policy_mgr_psoc_priv_obj policy mgr context + * @ch_freq: Channel frequency to check + * + * Return: True if allowed else false + */ +static bool +policy_mgr_is_nan_sap_unsafe_ch_scc_allowed(struct policy_mgr_psoc_priv_obj + *pm_ctx, uint32_t ch_freq) +{ + if (policy_mgr_is_safe_channel(pm_ctx->psoc, ch_freq) || + pm_ctx->cfg.nan_sap_scc_on_lte_coex_chnl) + return true; + + return false; +} + +/** + * policy_mgr_nan_disable_work() - qdf defer function wrapper for NAN disable + * @data: qdf_work data + * + * Return: None + */ +static void policy_mgr_nan_disable_work(void *data) +{ + struct wlan_objmgr_psoc *psoc = data; + + ucfg_nan_disable_concurrency(psoc); +} + +bool policy_mgr_nan_sap_scc_on_unsafe_ch_chk(struct wlan_objmgr_psoc *psoc, + uint32_t sap_freq) +{ + uint32_t nan_2g_freq, nan_5g_freq; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + nan_2g_freq = policy_mgr_mode_specific_get_channel(psoc, + PM_NAN_DISC_MODE); + if (nan_2g_freq == 0) { + policy_mgr_debug("No NAN+SAP SCC"); + return false; + } + nan_5g_freq = wlan_nan_get_disc_5g_ch_freq(psoc); + + policy_mgr_debug("Freq SAP: %d NAN: %d %d", sap_freq, + nan_2g_freq, nan_5g_freq); + if (WLAN_REG_IS_SAME_BAND_FREQS(nan_2g_freq, sap_freq)) { + if (policy_mgr_is_force_scc(pm_ctx->psoc) && + policy_mgr_is_nan_sap_unsafe_ch_scc_allowed(pm_ctx, + nan_2g_freq)) + return true; + } else if (WLAN_REG_IS_SAME_BAND_FREQS(nan_5g_freq, sap_freq)) { + if (policy_mgr_is_force_scc(pm_ctx->psoc) && + policy_mgr_is_nan_sap_unsafe_ch_scc_allowed(pm_ctx, + nan_5g_freq)) + return true; + } else { + /* + * NAN + SAP in different bands. Continue to check for + * SAP in unsafe channel + */ + return false; + } + policy_mgr_info("NAN+SAP unsafe ch SCC not allowed. Disabling NAN"); + /* change context to worker since this is executed in sched thread ctx*/ + qdf_create_work(0, &pm_ctx->nan_sap_conc_work, + policy_mgr_nan_disable_work, psoc); + qdf_sched_work(0, &pm_ctx->nan_sap_conc_work); + + return false; +} + +bool +policy_mgr_nan_sap_pre_enable_conc_check(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t sap_freq, nan_2g_freq, nan_5g_freq; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (!policy_mgr_is_sap_mode(mode) || mode == PM_NAN_DISC_MODE) { + policy_mgr_debug("Not NAN or SAP mode"); + return true; + } + + if (!ch_freq) { + policy_mgr_err("Invalid channel"); + return false; + } + + if (!wlan_nan_get_sap_conc_support(pm_ctx->psoc)) { + policy_mgr_debug("NAN+SAP not supported in fw"); + /* Reject NAN as SAP is of high priority */ + if (mode == PM_NAN_DISC_MODE) + return false; + /* Before SAP start disable NAN */ + ucfg_nan_disable_concurrency(pm_ctx->psoc); + return true; + } + + if (mode == PM_NAN_DISC_MODE) { + sap_freq = policy_mgr_mode_specific_get_channel(pm_ctx->psoc, + PM_SAP_MODE); + policy_mgr_debug("FREQ SAP: %d NAN: %d", sap_freq, ch_freq); + if (!sap_freq) { + sap_freq = policy_mgr_mode_specific_get_channel( + pm_ctx->psoc, + PM_LL_LT_SAP_MODE); + policy_mgr_debug("FREQ LL_LT_SAP: %d NAN: %d", + sap_freq, ch_freq); + } + if (ucfg_is_nan_dbs_supported(pm_ctx->psoc) && + !WLAN_REG_IS_SAME_BAND_FREQS(sap_freq, ch_freq)) + return true; + + if (sap_freq == ch_freq) { + policy_mgr_debug("NAN+SAP SCC"); + return true; + } + + if (!policy_mgr_is_force_scc(pm_ctx->psoc)) { + policy_mgr_debug("SAP force SCC disabled"); + return false; + } + if (!policy_mgr_is_nan_sap_unsafe_ch_scc_allowed( + pm_ctx, ch_freq)) { + policy_mgr_debug("NAN+SAP unsafe ch SCC disabled"); + return false; + } + if (pm_ctx->hdd_cbacks.hdd_is_cac_in_progress && + pm_ctx->hdd_cbacks.hdd_is_cac_in_progress()) { + policy_mgr_debug("DFS CAC in progress, reject NAN enable"); + return false; + } + } else if (policy_mgr_is_sap_mode(mode)) { + nan_2g_freq = + policy_mgr_mode_specific_get_channel(pm_ctx->psoc, + PM_NAN_DISC_MODE); + nan_5g_freq = wlan_nan_get_disc_5g_ch_freq(pm_ctx->psoc); + policy_mgr_debug("SAP CH: %d NAN Ch: %d %d", ch_freq, + nan_2g_freq, nan_5g_freq); + if (ucfg_is_nan_conc_control_supported(pm_ctx->psoc) && + !ucfg_is_nan_dbs_supported(pm_ctx->psoc) && + !WLAN_REG_IS_SAME_BAND_FREQS(nan_2g_freq, ch_freq)) { + if (!policy_mgr_is_force_scc(pm_ctx->psoc)) { + policy_mgr_debug("NAN and SAP are in different bands but SAP force SCC disabled"); + ucfg_nan_disable_concurrency(pm_ctx->psoc); + return true; + } + } else if (WLAN_REG_IS_SAME_BAND_FREQS(nan_2g_freq, ch_freq) || + WLAN_REG_IS_SAME_BAND_FREQS(nan_5g_freq, ch_freq)) { + if (ch_freq == nan_2g_freq || ch_freq == nan_5g_freq) { + policy_mgr_debug("NAN+SAP SCC"); + return true; + } + if (!policy_mgr_is_force_scc(pm_ctx->psoc)) { + policy_mgr_debug("SAP force SCC disabled"); + ucfg_nan_disable_concurrency(pm_ctx->psoc); + return true; + } + if ((WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && + !policy_mgr_is_nan_sap_unsafe_ch_scc_allowed( + pm_ctx, nan_5g_freq)) || + (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq) && + !policy_mgr_is_nan_sap_unsafe_ch_scc_allowed( + pm_ctx, nan_2g_freq))) { + policy_mgr_debug("NAN+SAP unsafe ch SCC disabled"); + ucfg_nan_disable_concurrency(pm_ctx->psoc); + return true; + } + } + } + return true; +} + +QDF_STATUS +policy_mgr_nan_sap_post_enable_conc_check(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info *sap_info = NULL; + uint8_t i; + qdf_freq_t nan_freq_2g, nan_freq_5g; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return QDF_STATUS_E_INVAL; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (policy_mgr_is_sap_mode(pm_conc_connection_list[i].mode) && + pm_conc_connection_list[i].in_use) { + sap_info = &pm_conc_connection_list[i]; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (!sap_info) + goto end; + if (sap_info->freq == 0) + goto end; + nan_freq_2g = policy_mgr_mode_specific_get_channel(psoc, + PM_NAN_DISC_MODE); + nan_freq_5g = wlan_nan_get_disc_5g_ch_freq(psoc); + if (sap_info->freq == nan_freq_2g || sap_info->freq == nan_freq_5g) { + policy_mgr_debug("NAN and SAP already in SCC"); + goto end; + } + if (nan_freq_2g == 0) + goto end; + + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_debug("channel switch is already in progress"); + return status; + } + + if (pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason) + pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason(psoc, + sap_info->vdev_id, + CSA_REASON_CONCURRENT_NAN_EVENT); + + /* SAP should be moved to 2g NAN channel on non-DBS platforms */ + if (!ucfg_is_nan_dbs_supported(pm_ctx->psoc) || + WLAN_REG_IS_24GHZ_CH_FREQ(sap_info->freq)) { + policy_mgr_debug("Force SCC for NAN+SAP Ch freq: %d", + nan_freq_2g); + status = + policy_mgr_change_sap_channel_with_csa(psoc, sap_info->vdev_id, + nan_freq_2g, + policy_mgr_get_ch_width( + sap_info->bw), + true); + if (status == QDF_STATUS_SUCCESS) + status = QDF_STATUS_E_PENDING; + } else if (nan_freq_5g && WLAN_REG_IS_5GHZ_CH_FREQ(sap_info->freq)) { + policy_mgr_debug("Force SCC for NAN+SAP Ch freq: %d", + nan_freq_5g); + status = + policy_mgr_change_sap_channel_with_csa(psoc, sap_info->vdev_id, + nan_freq_5g, + policy_mgr_get_ch_width( + sap_info->bw), + true); + if (status == QDF_STATUS_SUCCESS) + status = QDF_STATUS_E_PENDING; + } + +end: + pm_ctx->sta_ap_intf_check_work_info->nan_force_scc_in_progress = false; + + return status; +} + +void policy_mgr_nan_sap_post_disable_conc_check(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info *sap_info = NULL; + uint32_t sap_freq = 0, i; + QDF_STATUS status; + uint32_t user_config_freq; + uint8_t band_mask = 0; + uint8_t chn_idx, num_chan; + struct regulatory_channel *channel_list; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return; + } + + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].mode == PM_SAP_MODE && + pm_conc_connection_list[i].in_use) { + sap_info = &pm_conc_connection_list[i]; + sap_freq = sap_info->freq; + break; + } + } + if (sap_freq == 0 || policy_mgr_is_safe_channel(psoc, sap_freq)) + return; + + user_config_freq = policy_mgr_get_user_config_sap_freq( + psoc, sap_info->vdev_id); + + sap_freq = policy_mgr_get_nondfs_preferred_channel(psoc, PM_SAP_MODE, + false, + sap_info->vdev_id); + policy_mgr_debug("User/ACS orig Freq: %d New SAP Freq: %d", + user_config_freq, sap_freq); + + if (wlan_reg_is_enable_in_secondary_list_for_freq(pm_ctx->pdev, + user_config_freq) && + policy_mgr_is_safe_channel(psoc, user_config_freq)) { + policy_mgr_debug("Give preference to user config freq"); + sap_freq = user_config_freq; + } else { + channel_list = qdf_mem_malloc( + sizeof(struct regulatory_channel) * + NUM_CHANNELS); + if (!channel_list) + return; + + band_mask |= BIT(wlan_reg_freq_to_band(user_config_freq)); + num_chan = wlan_reg_get_band_channel_list_for_pwrmode( + pm_ctx->pdev, + band_mask, + channel_list, + REG_CURRENT_PWR_MODE); + for (chn_idx = 0; chn_idx < num_chan; chn_idx++) { + if (wlan_reg_is_enable_in_secondary_list_for_freq( + pm_ctx->pdev, + channel_list[chn_idx].center_freq) && + policy_mgr_is_safe_channel( + psoc, + channel_list[chn_idx].center_freq)) { + policy_mgr_debug("Prefer user config band freq %d", + channel_list[chn_idx].center_freq); + sap_freq = channel_list[chn_idx].center_freq; + } + } + qdf_mem_free(channel_list); + } + + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_debug("wait as channel switch is already in progress"); + status = qdf_wait_single_event( + &pm_ctx->channel_switch_complete_evt, + CHANNEL_SWITCH_COMPLETE_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("wait for event failed, still continue with channel switch"); + } + + if (pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason) + pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason( + psoc, sap_info->vdev_id, + CSA_REASON_CONCURRENT_NAN_EVENT); + + policy_mgr_change_sap_channel_with_csa(psoc, sap_info->vdev_id, + sap_freq, + policy_mgr_get_ch_width( + sap_info->bw), true); +} + +void policy_mgr_check_sap_restart(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint32_t ch_freq; + struct policy_mgr_psoc_priv_obj *pm_ctx = NULL; + + if (!psoc) { + policy_mgr_err("Invalid psoc"); + return; + } + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_debug("channel switch is already in progress"); + return; + } + + /* + * Restart should be handled by sap_fsm_validate_and_change_channel(), + * after SAP starts. + */ + if (pm_ctx->hdd_cbacks.hdd_is_cac_in_progress && + pm_ctx->hdd_cbacks.hdd_is_cac_in_progress()) { + policy_mgr_debug("DFS CAC in progress, do not restart SAP"); + return; + } + + if (!pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart) { + policy_mgr_err("SAP restart get channel callback in NULL"); + goto end; + } + status = + pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart(psoc, + vdev_id, + &ch_freq); + if (status == QDF_STATUS_SUCCESS) + policy_mgr_debug("SAP vdev id %d switch to new ch freq: %d", + vdev_id, ch_freq); + +end: + pm_ctx->last_disconn_sta_freq = 0; +} + +/** + * policy_mgr_handle_sap_plus_go_force_scc() - Do SAP/GO force SCC + * @psoc: soc object + * + * This function will check SAP/GO channel state and select channel + * to avoid MCC, then do channel change on the second interface. + * + * Return: QDF_STATUS_SUCCESS if successfully handle the SAP/GO + * force SCC. + */ +static QDF_STATUS +policy_mgr_handle_sap_plus_go_force_scc(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + uint8_t existing_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + enum policy_mgr_con_mode vdev_con_mode; + uint32_t existing_ch_freq, chan_freq, intf_ch_freq; + enum phy_ch_width existing_ch_width; + uint8_t vdev_id; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct sta_ap_intf_check_work_ctx *work_info; + struct ch_params ch_params = {0}; + enum QDF_OPMODE opmode; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + work_info = pm_ctx->sta_ap_intf_check_work_info; + if (!work_info) { + policy_mgr_err("invalid work info"); + return status; + } + if (work_info->sap_plus_go_force_scc.reason == CSA_REASON_UNKNOWN) + return status; + + vdev_id = work_info->sap_plus_go_force_scc.initiator_vdev_id; + chan_freq = wlan_get_operation_chan_freq_vdev_id(pm_ctx->pdev, vdev_id); + opmode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + vdev_con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, opmode, + vdev_id); + + existing_vdev_id = + policy_mgr_fetch_existing_con_info( + psoc, + vdev_id, + chan_freq, + &existing_vdev_mode, + &existing_ch_freq, &existing_ch_width); + policy_mgr_debug("initiator vdev %d mode %d freq %d, existing vdev %d mode %d freq %d reason %d", + vdev_id, vdev_con_mode, chan_freq, existing_vdev_id, + existing_vdev_mode, existing_ch_freq, + work_info->sap_plus_go_force_scc.reason); + + if (existing_vdev_id == WLAN_UMAC_VDEV_ID_MAX) + goto force_scc_done; + + if (!((vdev_con_mode == PM_P2P_GO_MODE && + existing_vdev_mode == PM_SAP_MODE) || + (vdev_con_mode == PM_SAP_MODE && + existing_vdev_mode == PM_P2P_GO_MODE))) + goto force_scc_done; + + if (!pm_ctx->hdd_cbacks.wlan_check_cc_intf_cb) + goto force_scc_done; + + intf_ch_freq = 0; + status = pm_ctx->hdd_cbacks.wlan_check_cc_intf_cb(psoc, + existing_vdev_id, + &intf_ch_freq); + policy_mgr_debug("vdev %d freq %d intf %d status %d", + existing_vdev_id, existing_ch_freq, + intf_ch_freq, status); + if (QDF_IS_STATUS_ERROR(status)) + goto force_scc_done; + if (!intf_ch_freq || intf_ch_freq == existing_ch_freq) + goto force_scc_done; + + ch_params.ch_width = existing_ch_width; + if (pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params) { + status = pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params( + psoc, existing_vdev_id, intf_ch_freq, &ch_params); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_debug("no candidate valid bw for vdev %d intf %d", + existing_vdev_id, intf_ch_freq); + } + + status = policy_mgr_valid_sap_conc_channel_check( + psoc, &intf_ch_freq, existing_ch_freq, existing_vdev_id, + &ch_params); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("warning no candidate freq for vdev %d freq %d intf %d", + existing_vdev_id, existing_ch_freq, + intf_ch_freq); + goto force_scc_done; + } + + if (pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason) + pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason( + psoc, existing_vdev_id, + work_info->sap_plus_go_force_scc.reason); + + status = policy_mgr_change_sap_channel_with_csa( + psoc, existing_vdev_id, intf_ch_freq, + ch_params.ch_width, true); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("warning sap/go vdev %d freq %d intf %d csa failed", + existing_vdev_id, existing_ch_freq, + intf_ch_freq); + } + +force_scc_done: + work_info->sap_plus_go_force_scc.reason = CSA_REASON_UNKNOWN; + work_info->sap_plus_go_force_scc.initiator_vdev_id = + WLAN_UMAC_VDEV_ID_MAX; + work_info->sap_plus_go_force_scc.responder_vdev_id = + WLAN_UMAC_VDEV_ID_MAX; + + return status; +} + +QDF_STATUS +policy_mgr_check_sap_go_force_scc(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum sap_csa_reason_code reason_code) +{ + uint8_t existing_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + enum policy_mgr_con_mode vdev_con_mode; + uint32_t con_freq, chan_freq; + enum phy_ch_width ch_width; + uint8_t vdev_id; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct sta_ap_intf_check_work_ctx *work_info; + enum QDF_OPMODE opmode; + + if (reason_code != CSA_REASON_GO_BSS_STARTED && + reason_code != CSA_REASON_USER_INITIATED) + return QDF_STATUS_SUCCESS; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + if (pm_ctx->cfg.mcc_to_scc_switch == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) + return QDF_STATUS_SUCCESS; + + if (!vdev) { + policy_mgr_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + vdev_id = wlan_vdev_get_id(vdev); + opmode = wlan_vdev_mlme_get_opmode(vdev); + work_info = pm_ctx->sta_ap_intf_check_work_info; + if (!work_info) { + policy_mgr_err("invalid work info"); + return QDF_STATUS_E_INVAL; + } + + chan_freq = wlan_get_operation_chan_freq(vdev); + vdev_con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, opmode, + vdev_id); + + existing_vdev_id = + policy_mgr_fetch_existing_con_info(psoc, + vdev_id, + chan_freq, + &existing_vdev_mode, + &con_freq, &ch_width); + if (existing_vdev_id == WLAN_UMAC_VDEV_ID_MAX) + return QDF_STATUS_SUCCESS; + + if (!((vdev_con_mode == PM_P2P_GO_MODE && + existing_vdev_mode == PM_SAP_MODE) || + (vdev_con_mode == PM_SAP_MODE && + existing_vdev_mode == PM_P2P_GO_MODE))) + return QDF_STATUS_SUCCESS; + + work_info->sap_plus_go_force_scc.reason = reason_code; + work_info->sap_plus_go_force_scc.initiator_vdev_id = vdev_id; + work_info->sap_plus_go_force_scc.responder_vdev_id = existing_vdev_id; + + policy_mgr_debug("initiator vdev %d freq %d, existing vdev %d freq %d reason %d", + vdev_id, chan_freq, existing_vdev_id, + con_freq, reason_code); + + if (!qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + WAIT_BEFORE_GO_FORCESCC_RESTART)) + policy_mgr_debug("change interface request already queued"); + + return QDF_STATUS_E_PENDING; +} + +/** + * policy_mgr_is_any_conn_in_transition() - Check if any STA/CLI + * connection is disconnecting or roaming state + * @psoc: PSOC object information + * + * This function will check connection table and find any STA/CLI + * in transition state such as disconnecting, link switch or roaming. + * + * Return: true if there is one STA/CLI in transition state. + */ +static bool +policy_mgr_is_any_conn_in_transition(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i; + struct policy_mgr_conc_connection_info *conn_info; + struct wlan_objmgr_vdev *vdev; + bool non_connected = false; + bool in_link_switch = false; + uint8_t vdev_id; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + conn_info = &pm_conc_connection_list[i]; + if (!(conn_info->in_use && + (conn_info->mode == PM_STA_MODE || + conn_info->mode == PM_P2P_CLIENT_MODE))) + continue; + vdev_id = conn_info->vdev_id; + vdev = wlan_objmgr_get_vdev_by_id_from_pdev( + pm_ctx->pdev, vdev_id, WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d: not found", vdev_id); + continue; + } + + non_connected = !wlan_cm_is_vdev_connected(vdev); + + if (mlo_is_mld_sta(vdev) && + mlo_mgr_is_link_switch_in_progress(vdev)) + in_link_switch = true; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + if (non_connected) { + policy_mgr_debug("vdev %d: is in transition state", + vdev_id); + break; + } + if (in_link_switch) { + policy_mgr_debug("vdev %d: sta mld is in link switch state", + vdev_id); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return non_connected || in_link_switch; +} + +static void __policy_mgr_check_sta_ap_concurrent_ch_intf( + struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + uint32_t mcc_to_scc_switch, cc_count = 0, i; + QDF_STATUS status; + uint32_t ch_freq; + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct sta_ap_intf_check_work_ctx *work_info; + + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + work_info = pm_ctx->sta_ap_intf_check_work_info; + + if (work_info->nan_force_scc_in_progress) { + policy_mgr_nan_sap_post_enable_conc_check(pm_ctx->psoc); + return; + } + /* + * Check if force scc is required for GO + GO case. vdev id will be + * valid in case of GO+GO force scc only. So, for valid vdev id move + * first GO to newly formed GO channel. + */ + policy_mgr_debug("p2p go vdev id: %d csa reason: %d", + work_info->go_plus_go_force_scc.vdev_id, + work_info->sap_plus_go_force_scc.reason); + if (pm_ctx->sta_ap_intf_check_work_info->go_plus_go_force_scc.vdev_id < + WLAN_UMAC_VDEV_ID_MAX) { + policy_mgr_do_go_plus_go_force_scc( + pm_ctx->psoc, work_info->go_plus_go_force_scc.vdev_id, + work_info->go_plus_go_force_scc.ch_freq, + work_info->go_plus_go_force_scc.ch_width); + work_info->go_plus_go_force_scc.vdev_id = WLAN_UMAC_VDEV_ID_MAX; + goto end; + } + /* + * Check if force scc is required for GO + SAP case. + */ + if (pm_ctx->sta_ap_intf_check_work_info->sap_plus_go_force_scc.reason != + CSA_REASON_UNKNOWN) { + status = policy_mgr_handle_sap_plus_go_force_scc(pm_ctx->psoc); + goto end; + } + + mcc_to_scc_switch = + policy_mgr_get_mcc_to_scc_switch_mode(pm_ctx->psoc); + + policy_mgr_debug("Concurrent open sessions running: %d", + policy_mgr_concurrent_open_sessions_running(pm_ctx->psoc)); + + if (!policy_mgr_is_sap_go_existed(pm_ctx->psoc)) + goto end; + + cc_count = policy_mgr_get_sap_mode_info(pm_ctx->psoc, + &op_ch_freq_list[cc_count], + &vdev_id[cc_count]); + + policy_mgr_debug("Number of concurrent SAP: %d", cc_count); + if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS) + cc_count = cc_count + + policy_mgr_get_mode_specific_conn_info( + pm_ctx->psoc, &op_ch_freq_list[cc_count], + &vdev_id[cc_count], PM_P2P_GO_MODE); + policy_mgr_debug("Number of beaconing entities (SAP + GO):%d", + cc_count); + if (!cc_count) { + policy_mgr_err("Could not retrieve SAP/GO operating channel&vdevid"); + goto end; + } + + /* When any STA/CLI is transition state, such as roaming or + * disconnecting, skip force scc for this time. + */ + if (policy_mgr_is_any_conn_in_transition(pm_ctx->psoc)) { + policy_mgr_debug("defer sap conc check to a later time due to another sta/cli dicon/roam pending"); + qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + SAP_CONC_CHECK_DEFER_TIMEOUT_MS); + goto end; + } + + if (policy_mgr_is_ap_start_in_progress(pm_ctx->psoc)) { + policy_mgr_debug("defer sap conc check to a later time due to another sap/go start pending"); + qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + SAP_CONC_CHECK_DEFER_TIMEOUT_MS); + goto end; + } + if (policy_mgr_is_set_link_in_progress(pm_ctx->psoc)) { + policy_mgr_debug("defer sap conc check to a later time due to ml sta set link in progress"); + qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + SAP_CONC_CHECK_DEFER_TIMEOUT_MS); + goto end; + } + + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_debug("wait as channel switch is already in progress"); + status = qdf_wait_single_event( + &pm_ctx->channel_switch_complete_evt, + CHANNEL_SWITCH_COMPLETE_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("wait for event failed, still continue with channel switch"); + } + + if (!pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart) { + policy_mgr_err("SAP restart get channel callback in NULL"); + goto end; + } + if (cc_count <= MAX_NUMBER_OF_CONC_CONNECTIONS) + for (i = 0; i < cc_count; i++) { + status = pm_ctx->hdd_cbacks. + wlan_hdd_get_channel_for_sap_restart + (pm_ctx->psoc, vdev_id[i], &ch_freq); + if (status == QDF_STATUS_SUCCESS) { + policy_mgr_debug("SAP vdev id %d restarts, old ch freq :%d new ch freq: %d", + vdev_id[i], + op_ch_freq_list[i], ch_freq); + break; + } + } + +end: + pm_ctx->last_disconn_sta_freq = 0; +} + +void policy_mgr_check_sta_ap_concurrent_ch_intf(void *data) +{ + struct qdf_op_sync *op_sync; + struct policy_mgr_psoc_priv_obj *pm_ctx = data; + int ret; + + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + + ret = qdf_op_protect(&op_sync); + if (ret) { + if (ret == -EAGAIN) { + if (qdf_is_driver_unloading() || + qdf_is_recovering() || + qdf_is_driver_state_module_stop()) { + policy_mgr_debug("driver not ready"); + return; + } + + if (!pm_ctx->sta_ap_intf_check_work_info) + return; + + pm_ctx->work_fail_count++; + policy_mgr_debug("qdf_op start fail, ret %d, work_fail_count %d", + ret, pm_ctx->work_fail_count); + if (pm_ctx->work_fail_count > 1) { + pm_ctx->work_fail_count = 0; + return; + } + qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + SAP_CONC_CHECK_DEFER_TIMEOUT_MS); + } + return; + } + pm_ctx->work_fail_count = 0; + __policy_mgr_check_sta_ap_concurrent_ch_intf(data); + + qdf_op_unprotect(op_sync); +} + +static bool policy_mgr_valid_sta_channel_check(struct wlan_objmgr_psoc *psoc, + uint32_t sta_ch_freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool sta_sap_scc_on_dfs_chan, sta_sap_scc_on_indoor_channel; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return false; + } + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + if (wlan_reg_is_dfs_for_freq(pm_ctx->pdev, sta_ch_freq) && + sta_sap_scc_on_dfs_chan) { + policy_mgr_debug("STA, SAP SCC is allowed on DFS chan %u", + sta_ch_freq); + return true; + } + + sta_sap_scc_on_indoor_channel = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + if (wlan_reg_is_freq_indoor(pm_ctx->pdev, sta_ch_freq) && + sta_sap_scc_on_indoor_channel) { + policy_mgr_debug("STA, SAP SCC is allowed on indoor chan %u", + sta_ch_freq); + return true; + } + + if ((wlan_reg_is_dfs_for_freq(pm_ctx->pdev, sta_ch_freq) && + !sta_sap_scc_on_dfs_chan) || + wlan_reg_is_passive_or_disable_for_pwrmode( + pm_ctx->pdev, sta_ch_freq, REG_CURRENT_PWR_MODE) || + (wlan_reg_is_freq_indoor(pm_ctx->pdev, sta_ch_freq) && + !sta_sap_scc_on_indoor_channel) || + (!policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc) && + !policy_mgr_is_safe_channel(psoc, sta_ch_freq))) { + if (policy_mgr_is_hw_dbs_capable(psoc)) + return true; + else + return false; + } + else + return true; +} + +static bool policy_mgr_get_srd_enable_for_vdev( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE vdev_opmode; + bool enable_srd_channel = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return false; + } + + vdev_opmode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + wlan_mlme_get_srd_master_mode_for_vdev(psoc, vdev_opmode, + &enable_srd_channel); + return enable_srd_channel; +} + +QDF_STATUS +policy_mgr_valid_sap_conc_channel_check(struct wlan_objmgr_psoc *psoc, + uint32_t *con_ch_freq, + uint32_t sap_ch_freq, + uint8_t sap_vdev_id, + struct ch_params *ch_params) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t ch_freq = *con_ch_freq; + bool find_alternate = false; + enum phy_ch_width old_ch_width; + bool sta_sap_scc_on_dfs_chan, sta_sap_scc_on_indoor_channel; + bool is_dfs; + bool is_6ghz_cap; + bool is_sta_sap_scc; + enum policy_mgr_con_mode con_mode; + uint32_t nan_2g_freq, nan_5g_freq; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + /* + * If force SCC is set, Check if conc channel is DFS + * or passive or part of LTE avoided channel list. + * In that case move SAP to other band if DBS is supported, + * return otherwise + */ + if (!policy_mgr_is_force_scc(psoc)) + return QDF_STATUS_SUCCESS; + + /* + * If interference is 0, it could be STA/SAP SCC, + * check further if SAP can start on STA home channel or + * select other band channel if not. + */ + if (!ch_freq) { + if (!policy_mgr_any_other_vdev_on_same_mac_as_freq(psoc, + sap_ch_freq, + sap_vdev_id)) + return QDF_STATUS_SUCCESS; + + ch_freq = sap_ch_freq; + } + + if (!ch_freq) + return QDF_STATUS_SUCCESS; + + con_mode = policy_mgr_con_mode_by_vdev_id(psoc, sap_vdev_id); + + is_sta_sap_scc = policy_mgr_is_sta_sap_scc(psoc, ch_freq); + + nan_2g_freq = + policy_mgr_mode_specific_get_channel(psoc, PM_NAN_DISC_MODE); + nan_5g_freq = wlan_nan_get_disc_5g_ch_freq(psoc); + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + + sta_sap_scc_on_indoor_channel = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + old_ch_width = ch_params->ch_width; + if (pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params) + pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params( + psoc, sap_vdev_id, ch_freq, ch_params); + + is_dfs = wlan_mlme_check_chan_param_has_dfs( + pm_ctx->pdev, ch_params, ch_freq); + is_6ghz_cap = policy_mgr_get_ap_6ghz_capable(psoc, sap_vdev_id, NULL); + + if (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && is_dfs && + !sta_sap_scc_on_dfs_chan && is_sta_sap_scc) { + find_alternate = true; + policymgr_nofl_debug("sap not capable of DFS SCC on con ch_freq %d", + ch_freq); + } else if (wlan_reg_is_disable_for_pwrmode(pm_ctx->pdev, ch_freq, + REG_CURRENT_PWR_MODE)) { + find_alternate = true; + policymgr_nofl_debug("sap not capable on disabled con ch_freq %d", + ch_freq); + } else if (con_mode == PM_P2P_GO_MODE && + wlan_reg_is_passive_or_disable_for_pwrmode( + pm_ctx->pdev, + ch_freq, + REG_CURRENT_PWR_MODE) && + !(policy_mgr_is_go_scc_strict(psoc) && + (!is_sta_sap_scc || sta_sap_scc_on_dfs_chan))) { + find_alternate = true; + policymgr_nofl_debug("Go not capable on dfs/disabled con ch_freq %d", + ch_freq); + } else if (!policy_mgr_is_safe_channel(psoc, ch_freq) && + !(policy_mgr_sta_sap_scc_on_lte_coex_chan(psoc) && + is_sta_sap_scc) && + !(policy_mgr_get_nan_sap_scc_on_lte_coex_chnl(psoc) && + (WLAN_REG_IS_SAME_BAND_FREQS(nan_2g_freq, ch_freq) || + WLAN_REG_IS_SAME_BAND_FREQS(nan_5g_freq, ch_freq)))) { + find_alternate = true; + policymgr_nofl_debug("sap not capable unsafe con ch_freq %d", + ch_freq); + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq) && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ch_freq) && + !is_6ghz_cap) { + policymgr_nofl_debug("sap not capable on 6GHZ con ch_freq %d", + ch_freq); + find_alternate = true; + } else if (wlan_reg_is_etsi_srd_chan_for_freq(pm_ctx->pdev, + ch_freq) && + !policy_mgr_get_srd_enable_for_vdev(psoc, sap_vdev_id)) { + find_alternate = true; + policymgr_nofl_debug("sap not capable on SRD con ch_freq %d", + ch_freq); + } else if (!policy_mgr_is_sap_go_interface_allowed_on_indoor( + pm_ctx->pdev, + sap_vdev_id, ch_freq)) { + policymgr_nofl_debug("sap not capable on indoor con ch_freq %d is_sta_sap_scc:%d", + ch_freq, is_sta_sap_scc); + find_alternate = true; + } + + if (find_alternate) { + if (policy_mgr_is_hw_dbs_capable(psoc)) { + ch_freq = policy_mgr_get_alternate_channel_for_sap( + psoc, sap_vdev_id, sap_ch_freq, + REG_BAND_UNKNOWN); + policymgr_nofl_debug("selected alternate ch %d", + ch_freq); + if (!ch_freq) { + policymgr_nofl_debug("Sap can't have concurrency on %d in dbs hw", + *con_ch_freq); + return QDF_STATUS_E_FAILURE; + } + } else { + /* MCC not supported for non-DBS chip*/ + ch_freq = 0; + if (con_mode == PM_SAP_MODE) { + policymgr_nofl_debug("MCC situation in non-dbs hw STA freq %d SAP freq %d not supported", + *con_ch_freq, sap_ch_freq); + return QDF_STATUS_E_FAILURE; + } else { + policymgr_nofl_debug("MCC situation in non-dbs hw STA freq %d GO freq %d SCC not supported", + *con_ch_freq, sap_ch_freq); + } + } + } + + if (ch_freq != sap_ch_freq || old_ch_width != ch_params->ch_width) { + *con_ch_freq = ch_freq; + policymgr_nofl_debug("sap conc result con freq %d bw %d org freq %d bw %d", + ch_freq, ch_params->ch_width, sap_ch_freq, + old_ch_width); + } + + if (*con_ch_freq && + pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params) + pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params( + psoc, sap_vdev_id, ch_freq, ch_params); + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_check_concurrent_intf_and_restart_sap( + struct wlan_objmgr_psoc *psoc, bool is_acs_mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t mcc_to_scc_switch; + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint32_t cc_count = 0; + uint32_t timeout_ms = 0; + bool restart_sap = false; + uint32_t sap_freq; + /* + * if no sta, sap/p2p go may need switch channel for band + * capability change. + * If sta exist, sap/p2p go may need switch channel to force scc + */ + bool sta_check = false, gc_check = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + if (!pm_ctx->sta_ap_intf_check_work_info) { + policy_mgr_err("Invalid sta_ap_intf_check_work_info"); + return; + } + if (!policy_mgr_is_sap_go_existed(psoc)) { + policy_mgr_debug( + "No action taken at check_concurrent_intf_and_restart_sap"); + return; + } + + if (policy_mgr_is_ll_lt_sap_restart_required(psoc)) { + restart_sap = true; + goto sap_restart; + } + + /* + * If STA+SAP sessions are on DFS channel and STA+SAP SCC is + * enabled on DFS channel then move the SAP out of DFS channel + * as soon as STA gets disconnect. + * If STA+SAP sessions are on unsafe channel and STA+SAP SCC is + * enabled on unsafe channel then move the SAP to safe channel + * as soon as STA disconnected. + */ + if (policy_mgr_is_sap_restart_required_after_sta_disconnect( + psoc, INVALID_VDEV_ID, &sap_freq, is_acs_mode)) { + policy_mgr_debug("move the SAP to configured channel %u", + sap_freq); + restart_sap = true; + goto sap_restart; + } + + /* + * This is to check the cases where STA got disconnected or + * sta is present on some valid channel where SAP evaluation/restart + * might be needed. + * force SCC with STA+STA+SAP will need some additional logic + */ + cc_count = policy_mgr_get_mode_specific_conn_info( + psoc, &op_ch_freq_list[cc_count], + &vdev_id[cc_count], PM_STA_MODE); + + sta_check = !cc_count || + policy_mgr_valid_sta_channel_check(psoc, op_ch_freq_list[0]); + + cc_count = 0; + cc_count = policy_mgr_get_mode_specific_conn_info( + psoc, &op_ch_freq_list[cc_count], + &vdev_id[cc_count], PM_P2P_CLIENT_MODE); + + gc_check = !!cc_count; + + mcc_to_scc_switch = + policy_mgr_get_mcc_to_scc_switch_mode(psoc); + policy_mgr_debug("MCC to SCC switch: %d chan: %d sta_check: %d, gc_check: %d", + mcc_to_scc_switch, op_ch_freq_list[0], + sta_check, gc_check); + + cc_count = 0; + cc_count = policy_mgr_get_mode_specific_conn_info( + psoc, &op_ch_freq_list[cc_count], + &vdev_id[cc_count], PM_SAP_MODE); + + /* SAP + SAP case needs additional handling */ + if (cc_count == 1 && !is_acs_mode && + target_psoc_get_sap_coex_fixed_chan_cap( + wlan_psoc_get_tgt_if_handle(psoc)) && + !policy_mgr_is_safe_channel(psoc, op_ch_freq_list[0])) { + policy_mgr_debug("Avoid channel switch as it's allowed to operate on unsafe channel: %d", + op_ch_freq_list[0]); + return; + } + +sap_restart: + /* + * If sta_sap_scc_on_dfs_chan is true then standalone SAP is not + * allowed on DFS channel. SAP is allowed on DFS channel only when STA + * is already connected on that channel. + * In following condition restart_sap will be true if + * sta_sap_scc_on_dfs_chan is true and SAP is on DFS channel. + * This scenario can come if STA+SAP are operating on DFS channel and + * STA gets disconnected. + */ + if (restart_sap || + ((mcc_to_scc_switch != QDF_MCC_TO_SCC_SWITCH_DISABLE) && + (sta_check || gc_check))) { + if (!pm_ctx->sta_ap_intf_check_work_info) { + policy_mgr_err("invalid sta_ap_intf_check_work_info"); + return; + } + + policy_mgr_debug("Checking for Concurrent Change interference"); + + if (policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, NULL)) + timeout_ms = MAX_NOA_TIME; + + if (!qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + timeout_ms)) { + policy_mgr_debug("change interface request already queued"); + return; + } + } +} + +bool policy_mgr_check_bw_with_unsafe_chan_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t center_freq, + enum phy_ch_width ch_width) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t freq_start, freq_end, bw, i, unsafe_chan_freq; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return true; + } + + if (ch_width <= CH_WIDTH_20MHZ || !center_freq) + return true; + + if (!pm_ctx->unsafe_channel_count) + return true; + + bw = wlan_reg_get_bw_value(ch_width); + freq_start = center_freq - bw / 2; + freq_end = center_freq + bw / 2; + + for (i = 0; i < pm_ctx->unsafe_channel_count; i++) { + unsafe_chan_freq = pm_ctx->unsafe_channel_list[i]; + if (unsafe_chan_freq > freq_start && + unsafe_chan_freq < freq_end) { + policy_mgr_debug("unsafe ch freq %d is in range %d-%d", + unsafe_chan_freq, + freq_start, + freq_end); + return false; + } + } + return true; +} + +/** + * policy_mgr_change_sap_channel_with_csa() - Move SAP channel using (E)CSA + * @psoc: PSOC object information + * @vdev_id: Vdev id + * @ch_freq: Channel to change + * @ch_width: channel width to change + * @forced: Force to switch channel, ignore SCC/MCC check + * + * Invoke the callback function to change SAP channel using (E)CSA + * + * Return: QDF_STATUS_SUCCESS for success + */ +QDF_STATUS +policy_mgr_change_sap_channel_with_csa(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t ch_width, bool forced) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct ch_params ch_params = {0}; + qdf_freq_t center_freq; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_INVAL; + } + if (pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params) { + ch_params.ch_width = ch_width; + status = pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params( + psoc, vdev_id, ch_freq, &ch_params); + if (QDF_IS_STATUS_SUCCESS(status) && + ch_width > ch_params.ch_width) + ch_width = ch_params.ch_width; + } + + if (ch_params.mhz_freq_seg1) + center_freq = ch_params.mhz_freq_seg1; + else + center_freq = ch_params.mhz_freq_seg0; + + if (!policy_mgr_check_bw_with_unsafe_chan_freq(psoc, + center_freq, + ch_width)) { + policy_mgr_info("SAP bw shrink to 20M for unsafe"); + ch_width = CH_WIDTH_20MHZ; + } + + if (pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb) { + policy_mgr_info("SAP change change without restart"); + status = pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb(psoc, + vdev_id, + ch_freq, + ch_width, + forced); + } else { + status = QDF_STATUS_E_INVAL; + } + + return status; +} +#endif /* FEATURE_WLAN_MCC_TO_SCC_SWITCH */ + +QDF_STATUS +policy_mgr_sta_sap_dfs_scc_conc_check(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct csa_offload_params *csa_event) +{ + uint8_t concur_vdev_id, i; + bool move_sap_go_first; + enum hw_mode_bandwidth bw; + qdf_freq_t cur_freq, new_freq; + struct wlan_objmgr_vdev *vdev, *conc_vdev; + struct wlan_objmgr_pdev *pdev; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_con_mode cur_mode; + enum policy_mgr_con_mode concur_mode = PM_MAX_NUM_OF_MODE; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_INVAL; + } + if (!csa_event) { + policy_mgr_err("CSA IE Received event is NULL"); + return QDF_STATUS_E_INVAL; + } + + policy_mgr_get_dfs_sta_sap_go_scc_movement(psoc, &move_sap_go_first); + if (!move_sap_go_first) { + policy_mgr_err("g_move_sap_go_1st_on_dfs_sta_csa is disabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + cur_mode = policy_mgr_get_mode_by_vdev_id(psoc, vdev_id); + if (cur_mode != PM_STA_MODE) { + policy_mgr_err("CSA received on non-STA connection"); + return QDF_STATUS_E_INVAL; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + pdev = wlan_vdev_get_pdev(vdev); + cur_freq = wlan_get_operation_chan_freq_vdev_id(pdev, vdev_id); + + if (!wlan_reg_is_dfs_for_freq(pdev, cur_freq) && + !wlan_reg_is_freq_indoor(pdev, cur_freq)) { + policy_mgr_err("SAP / GO operating channel is non-DFS"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return QDF_STATUS_E_INVAL; + } + + /* Check if there is any SAP / GO operating on the same channel or not + * If yes, then get the current bandwidth and vdev_id of concurrent SAP + * or GO and trigger channel switch to new channel received in CSA on + * STA interface. If this new channel is DFS then trigger channel + * switch to non-DFS channel. Once STA moves to this new channel and + * when it receives very first beacon, it will then enforce SCC again + */ + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use && + pm_conc_connection_list[i].freq == cur_freq && + pm_conc_connection_list[i].vdev_id != vdev_id && + (pm_conc_connection_list[i].mode == PM_P2P_GO_MODE || + pm_conc_connection_list[i].mode == PM_SAP_MODE)) { + concur_mode = pm_conc_connection_list[i].mode; + bw = pm_conc_connection_list[i].bw; + concur_vdev_id = pm_conc_connection_list[i].vdev_id; + break; + } + } + + /* If there is no concurrent SAP / GO, then return */ + if (concur_mode == PM_MAX_NUM_OF_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return QDF_STATUS_E_INVAL; + } + + conc_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, concur_vdev_id, + WLAN_POLICY_MGR_ID); + if (!conc_vdev) { + policy_mgr_err("conc_vdev is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return QDF_STATUS_E_INVAL; + } + wlan_vdev_mlme_set_sap_go_move_before_sta(conc_vdev, true); + wlan_vdev_mlme_set_sap_go_move_before_sta(vdev, true); + wlan_objmgr_vdev_release_ref(conc_vdev, WLAN_POLICY_MGR_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + /*Change the CSA count*/ + if (pm_ctx->sme_cbacks.sme_change_sap_csa_count) + /* Total 4 CSA frames are allowed so that GO / SAP + * will move to new channel within 500ms + */ + pm_ctx->sme_cbacks.sme_change_sap_csa_count(4); + new_freq = csa_event->csa_chan_freq; + + /* If the new channel is DFS or indoor, then select another channel + * and switch the SAP / GO to avoid CAC. This will resume traffic on + * SAP / GO interface immediately. Once STA moves to this new channel + * and receives the very first beacon, then it will enforece SCC + */ + if (wlan_reg_is_dfs_for_freq(pdev, new_freq) || + wlan_reg_is_freq_indoor(pdev, new_freq)) { + if (wlan_reg_is_24ghz_ch_freq(new_freq)) { + new_freq = wlan_reg_min_24ghz_chan_freq(); + } else if (wlan_reg_is_5ghz_ch_freq(new_freq)) { + new_freq = wlan_reg_min_5ghz_chan_freq(); + /* if none of the 5G channel is non-DFS */ + if (wlan_reg_is_dfs_for_freq(pdev, new_freq) || + wlan_reg_is_freq_indoor(pdev, new_freq)) + new_freq = policy_mgr_get_nondfs_preferred_channel(psoc, + concur_mode, + true, + concur_vdev_id); + } else { + new_freq = wlan_reg_min_6ghz_chan_freq(); + } + } + policy_mgr_debug("Restart vdev: %u on freq: %u", + concur_vdev_id, new_freq); + + return policy_mgr_change_sap_channel_with_csa(psoc, concur_vdev_id, + new_freq, bw, true); +} + +void policy_mgr_sta_sap_dfs_enforce_scc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + bool is_sap_go_moved_before_sta, move_sap_go_first; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + enum policy_mgr_con_mode cur_mode; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return; + } + is_sap_go_moved_before_sta = + wlan_vdev_mlme_is_sap_go_move_before_sta(vdev); + pdev = wlan_vdev_get_pdev(vdev); + wlan_vdev_mlme_set_sap_go_move_before_sta(vdev, false); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + policy_mgr_get_dfs_sta_sap_go_scc_movement(psoc, &move_sap_go_first); + if (!is_sap_go_moved_before_sta || !move_sap_go_first) { + policy_mgr_debug("SAP / GO moved before STA: %u INI g_move_sap_go_1st_on_dfs_sta_csa: %u", + is_sap_go_moved_before_sta, move_sap_go_first); + return; + } + + cur_mode = policy_mgr_get_mode_by_vdev_id(psoc, vdev_id); + if (cur_mode != PM_STA_MODE) { + policy_mgr_err("CSA received on non-STA connection"); + return; + } + + policy_mgr_debug("Enforce SCC"); + policy_mgr_check_concurrent_intf_and_restart_sap(psoc, false); +} + +#ifdef WLAN_FEATURE_P2P_P2P_STA +void policy_mgr_do_go_plus_go_force_scc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t ch_width) +{ + uint8_t total_connection; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + total_connection = policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, NULL); + + policy_mgr_debug("Total p2p go connection %d", total_connection); + + /* If any p2p disconnected, don't do csa */ + if (total_connection > 1) { + if (pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason) + pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason( + psoc, vdev_id, + CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL); + + policy_mgr_change_sap_channel_with_csa(psoc, vdev_id, + ch_freq, ch_width, true); + } +} + +void policy_mgr_process_forcescc_for_go(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t ch_width, + enum policy_mgr_con_mode mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct sta_ap_intf_check_work_ctx *work_info; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + if (!pm_ctx->sta_ap_intf_check_work_info) { + policy_mgr_err("invalid work info"); + return; + } + work_info = pm_ctx->sta_ap_intf_check_work_info; + if (mode == PM_P2P_GO_MODE) { + work_info->go_plus_go_force_scc.vdev_id = vdev_id; + work_info->go_plus_go_force_scc.ch_freq = ch_freq; + work_info->go_plus_go_force_scc.ch_width = ch_width; + } + + if (!qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, + WAIT_BEFORE_GO_FORCESCC_RESTART)) + policy_mgr_debug("change interface request already queued"); +} +#endif + +bool policy_mgr_is_chan_switch_in_progress(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return false; + } + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_debug("channel switch is in progress"); + return true; + } + + return false; +} + +QDF_STATUS policy_mgr_wait_chan_switch_complete_evt( + struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_wait_single_event( + &pm_ctx->channel_switch_complete_evt, + CHANNEL_SWITCH_COMPLETE_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("wait for event failed, still continue with channel switch"); + + return status; +} + +static void __policy_mgr_is_ap_start_in_progress(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + uint32_t *ap_starting_vdev_id = (uint32_t *)arg; + enum wlan_serialization_cmd_type cmd_type; + enum QDF_OPMODE op_mode; + + if (!vdev || !ap_starting_vdev_id) + return; + if (*ap_starting_vdev_id != WLAN_INVALID_VDEV_ID) + return; + op_mode = wlan_vdev_mlme_get_opmode(vdev); + if (op_mode != QDF_SAP_MODE && op_mode != QDF_P2P_GO_MODE && + op_mode != QDF_NDI_MODE) + return; + /* Check AP start is present in active and pending queue or not */ + cmd_type = wlan_serialization_get_vdev_active_cmd_type(vdev); + if (cmd_type == WLAN_SER_CMD_VDEV_START_BSS || + wlan_ser_is_non_scan_cmd_type_in_vdev_queue( + vdev, WLAN_SER_CMD_VDEV_START_BSS)) { + *ap_starting_vdev_id = wlan_vdev_get_id(vdev); + policy_mgr_debug("vdev %d op mode %d start bss is pending", + *ap_starting_vdev_id, op_mode); + } +} + +bool policy_mgr_is_ap_start_in_progress(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t ap_starting_vdev_id = WLAN_INVALID_VDEV_ID; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return false; + } + + wlan_objmgr_pdev_iterate_obj_list(pm_ctx->pdev, WLAN_VDEV_OP, + __policy_mgr_is_ap_start_in_progress, + &ap_starting_vdev_id, 0, + WLAN_POLICY_MGR_ID); + + return ap_starting_vdev_id != WLAN_INVALID_VDEV_ID; +} + +void policy_mgr_process_force_scc_for_nan(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + if (!pm_ctx->sta_ap_intf_check_work_info) { + policy_mgr_err("invalid work info"); + return; + } + + pm_ctx->sta_ap_intf_check_work_info->nan_force_scc_in_progress = true; + + if (!qdf_delayed_work_start(&pm_ctx->sta_ap_intf_check_work, 0)) + policy_mgr_debug("change interface request already queued"); +} + +QDF_STATUS policy_mgr_wait_for_connection_update(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *policy_mgr_context; + + policy_mgr_context = policy_mgr_get_context(psoc); + if (!policy_mgr_context) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_wait_single_event( + &policy_mgr_context->connection_update_done_evt, + CONNECTION_UPDATE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("wait for event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_reset_connection_update(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *policy_mgr_context; + + policy_mgr_context = policy_mgr_get_context(psoc); + if (!policy_mgr_context) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_event_reset( + &policy_mgr_context->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("clear event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_reset_hw_mode_change(struct wlan_objmgr_psoc *psoc) +{ + policy_mgr_err("Clear hw mode change and connection update evt"); + policy_mgr_set_hw_mode_change_in_progress( + psoc, POLICY_MGR_HW_MODE_NOT_IN_PROGRESS); + policy_mgr_reset_connection_update(psoc); +} + +QDF_STATUS policy_mgr_set_connection_update(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *policy_mgr_context; + + policy_mgr_context = policy_mgr_get_context(psoc); + if (!policy_mgr_context) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_event_set(&policy_mgr_context->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("set event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_set_chan_switch_complete_evt( + struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + /* + * Set channel_switch_complete_evt only if no vdev has channel switch + * in progress. + */ + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_info("Not all channel switch completed"); + return QDF_STATUS_SUCCESS; + } + + status = qdf_event_set_all(&pm_ctx->channel_switch_complete_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("set event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_reset_chan_switch_complete_evt( + struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *policy_mgr_context; + + policy_mgr_context = policy_mgr_get_context(psoc); + + if (!policy_mgr_context) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + status = qdf_event_reset( + &policy_mgr_context->channel_switch_complete_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("reset event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_set_opportunistic_update(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *policy_mgr_context; + + policy_mgr_context = policy_mgr_get_context(psoc); + if (!policy_mgr_context) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_event_set( + &policy_mgr_context->opportunistic_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("set event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_stop_opportunistic_timer(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *policy_mgr_ctx; + + policy_mgr_ctx = policy_mgr_get_context(psoc); + if (!policy_mgr_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + if (policy_mgr_ctx->dbs_opportunistic_timer.state != + QDF_TIMER_STATE_RUNNING) + return QDF_STATUS_SUCCESS; + + qdf_mc_timer_stop(&policy_mgr_ctx->dbs_opportunistic_timer); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_restart_opportunistic_timer( + struct wlan_objmgr_psoc *psoc, bool check_state) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_psoc_priv_obj *policy_mgr_ctx; + + if (policy_mgr_is_hwmode_offload_enabled(psoc)) + return QDF_STATUS_E_NOSUPPORT; + + policy_mgr_ctx = policy_mgr_get_context(psoc); + if (!policy_mgr_ctx) { + policy_mgr_err("Invalid context"); + return status; + } + + if (check_state && + QDF_TIMER_STATE_RUNNING != + policy_mgr_ctx->dbs_opportunistic_timer.state) + return status; + + qdf_mc_timer_stop(&policy_mgr_ctx->dbs_opportunistic_timer); + + status = qdf_mc_timer_start( + &policy_mgr_ctx->dbs_opportunistic_timer, + DBS_OPPORTUNISTIC_TIME * 1000); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("failed to start opportunistic timer"); + return status; + } + + return status; +} + +QDF_STATUS policy_mgr_set_hw_mode_on_channel_switch( + struct wlan_objmgr_psoc *psoc, uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE, qdf_status; + enum policy_mgr_conc_next_action action; + + if (policy_mgr_is_hwmode_offload_enabled(psoc)) + return QDF_STATUS_E_NOSUPPORT; + + if (!policy_mgr_is_hw_dbs_capable(psoc)) { + policy_mgr_rl_debug("PM/DBS is disabled"); + return status; + } + + action = (*policy_mgr_get_current_pref_hw_mode_ptr)(psoc); + if ((action != PM_DBS_DOWNGRADE) && + (action != PM_SINGLE_MAC_UPGRADE) && + (action != PM_DBS1_DOWNGRADE) && + (action != PM_DBS2_DOWNGRADE)) { + policy_mgr_err("Invalid action: %d", action); + status = QDF_STATUS_SUCCESS; + goto done; + } + + policy_mgr_debug("action:%d session id:%d", action, session_id); + + /* Opportunistic timer is started, PM will check if MCC upgrade can be + * done on timer expiry. This avoids any possible ping pong effect + * as well. + */ + if (action == PM_SINGLE_MAC_UPGRADE) { + qdf_status = policy_mgr_restart_opportunistic_timer( + psoc, false); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + policy_mgr_debug("opportunistic timer for MCC upgrade"); + goto done; + } + + /* For DBS, we want to move right away to DBS mode */ + status = policy_mgr_next_actions(psoc, session_id, action, + POLICY_MGR_UPDATE_REASON_AFTER_CHANNEL_SWITCH, + POLICY_MGR_DEF_REQ_ID); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("no set hw mode command was issued"); + goto done; + } +done: + /* success must be returned only when a set hw mode was done */ + return status; +} + +QDF_STATUS policy_mgr_check_and_set_hw_mode_for_channel_switch( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t ch_freq, enum policy_mgr_conn_update_reason reason) +{ + QDF_STATUS status; + struct policy_mgr_conc_connection_info info; + uint8_t num_cxn_del = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_conc_next_action next_action = PM_NOP; + bool eht_capab = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); + if (eht_capab && + policy_mgr_mode_specific_connection_count(psoc, + PM_SAP_MODE, + NULL) == 1) { + policy_mgr_stop_opportunistic_timer(psoc); + goto ch_width_update; + } + + if (!policy_mgr_is_hw_dbs_capable(psoc) || + (!policy_mgr_is_hw_dbs_2x2_capable(psoc) && + !policy_mgr_is_hw_dbs_required_for_band( + psoc, HW_MODE_MAC_BAND_2G))) + return QDF_STATUS_E_NOSUPPORT; + + /* + * Stop opportunistic timer as current connection info will change once + * channel is switched and thus if required it will be started once + * channel switch is completed. With new connection info. + */ + policy_mgr_stop_opportunistic_timer(psoc); + + if (wlan_reg_freq_to_band(ch_freq) != REG_BAND_2G) + return QDF_STATUS_E_NOSUPPORT; + +ch_width_update: + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* + * Store the connection's parameter and temporarily delete it + * from the concurrency table. This way the allow concurrency + * check can be used as though a new connection is coming up, + * after check, restore the connection to concurrency table. + */ + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id, + &info, &num_cxn_del); + + status = policy_mgr_get_next_action(psoc, vdev_id, ch_freq, + reason, &next_action); + /* Restore the connection entry */ + if (num_cxn_del) + policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (QDF_IS_STATUS_ERROR(status)) + goto chk_opportunistic_timer; + + if (PM_NOP != next_action) + status = policy_mgr_next_actions(psoc, vdev_id, + next_action, reason, + POLICY_MGR_DEF_REQ_ID); + else + status = QDF_STATUS_E_NOSUPPORT; + +chk_opportunistic_timer: + /* + * If hw mode change failed restart the opportunistic timer to + * Switch to single mac if required. + */ + if (status == QDF_STATUS_E_FAILURE) { + policy_mgr_err("Failed to update HW modeStatus %d", status); + policy_mgr_check_n_start_opportunistic_timer(psoc); + } + + return status; +} + +void policy_mgr_checkn_update_hw_mode_single_mac_mode( + struct wlan_objmgr_psoc *psoc, uint32_t ch_freq) +{ + uint8_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool dbs_required_2g; + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return; + + if (QDF_TIMER_STATE_RUNNING == pm_ctx->dbs_opportunistic_timer.state) + qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer); + + dbs_required_2g = + policy_mgr_is_hw_dbs_required_for_band(psoc, HW_MODE_MAC_BAND_2G); + + if (dbs_required_2g && WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) { + policy_mgr_debug("DBS required for new connection"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use) { + if (!WLAN_REG_IS_SAME_BAND_FREQS( + ch_freq, pm_conc_connection_list[i].freq) && + (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[i].freq) || + WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq))) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("DBS required"); + return; + } + if (dbs_required_2g && WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[i].freq)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("DBS required"); + return; + } + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + pm_dbs_opportunistic_timer_handler((void *)psoc); +} + +void policy_mgr_check_and_stop_opportunistic_timer( + struct wlan_objmgr_psoc *psoc, uint8_t id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_conc_next_action action = PM_NOP; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum policy_mgr_conn_update_reason reason = + POLICY_MGR_UPDATE_REASON_MAX; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + if (QDF_TIMER_STATE_RUNNING == + pm_ctx->dbs_opportunistic_timer.state) { + qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer); + action = policy_mgr_need_opportunistic_upgrade(psoc, &reason); + if (action) { + qdf_event_reset(&pm_ctx->opportunistic_update_done_evt); + status = policy_mgr_next_actions(psoc, id, action, + reason, + POLICY_MGR_DEF_REQ_ID); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed in policy_mgr_next_actions"); + return; + } + status = qdf_wait_single_event( + &pm_ctx->opportunistic_update_done_evt, + CONNECTION_UPDATE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("wait for event failed"); + return; + } + } + } +} + +void policy_mgr_set_hw_mode_change_in_progress( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_hw_mode_change value) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + pm_ctx->hw_mode_change_in_progress = value; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + policy_mgr_debug("hw_mode_change_in_progress:%d", value); +} + +enum policy_mgr_hw_mode_change policy_mgr_is_hw_mode_change_in_progress( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_hw_mode_change value; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + value = POLICY_MGR_HW_MODE_NOT_IN_PROGRESS; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return value; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + value = pm_ctx->hw_mode_change_in_progress; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return value; +} + +enum policy_mgr_hw_mode_change policy_mgr_get_hw_mode_change_from_hw_mode_index( + struct wlan_objmgr_psoc *psoc, uint32_t hw_mode_index) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_hw_mode_params hw_mode; + enum policy_mgr_hw_mode_change value + = POLICY_MGR_HW_MODE_NOT_IN_PROGRESS; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return value; + } + + status = policy_mgr_get_hw_mode_from_idx(psoc, hw_mode_index, &hw_mode); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to get HW mode index"); + return value; + } + + if (hw_mode.dbs_cap) { + policy_mgr_debug("DBS is requested with HW (%d)", + hw_mode_index); + value = POLICY_MGR_DBS_IN_PROGRESS; + goto ret_value; + } + + if (hw_mode.sbs_cap) { + policy_mgr_debug("SBS is requested with HW (%d)", + hw_mode_index); + value = POLICY_MGR_SBS_IN_PROGRESS; + goto ret_value; + } + + value = POLICY_MGR_SMM_IN_PROGRESS; + policy_mgr_debug("SMM is requested with HW (%d)", hw_mode_index); + +ret_value: + return value; +} + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +bool +policy_mgr_get_allowed_tdls_offchannel_freq(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + qdf_freq_t *ch_freq) +{ + struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t connection_count, i, j, sta_vdev_id; + + *ch_freq = 0; + /* + * TDLS off channel is not allowed in any MCC scenario + */ + if (policy_mgr_current_concurrency_is_mcc(psoc)) { + policy_mgr_dump_current_concurrency(psoc); + policy_mgr_debug("TDLS off channel not allowed in MCC"); + return false; + } + + /* + * TDLS offchannel is done only when STA is connected on 2G channel and + * the current concurrency is not MCC + */ + if (!policy_mgr_is_sta_connected_2g(psoc)) { + policy_mgr_debug("STA not-connected on 2.4 Ghz"); + return false; + } + + /* + * 2 Port DBS scenario - Allow non-STA vdev channel for + * TDLS off-channel operation + * + * 3 Port Scenario - If STA Vdev is on SCC, allow TDLS off-channel on + * the channel of vdev on the other MAC + * If STA vdev is standalone on one mac, and scc on another mac, then + * allow TDLS off channel on other mac scc channel + */ + sta_vdev_id = wlan_vdev_get_id(vdev); + connection_count = policy_mgr_get_connection_info(psoc, info); + switch (connection_count) { + case 1: + return true; + case 2: + /* + * Allow all the 5GHz/6GHz channels when STA is in SCC + */ + if (policy_mgr_current_concurrency_is_scc(psoc)) { + *ch_freq = 0; + return true; + } else if (policy_mgr_is_current_hwmode_dbs(psoc)) { + /* + * In DBS case, allow off-channel operation on the + * other mac 5GHz/6GHz channel where the STA is not + * present + * Don't consider SBS case since STA should be + * connected in 2.4GHz channel for TDLS + * off-channel and MCC on SBS ex. 3 PORT + * 2.4GHz STA + 5GHz Lower MCC + 5GHz Upper will + * not be allowed + */ + if (sta_vdev_id == info[0].vdev_id) + *ch_freq = info[1].ch_freq; + else + *ch_freq = info[0].ch_freq; + + return true; + } + + break; + case 3: + + /* + * 3 Vdev SCC on 2.4GHz band. Allow TDLS off-channel operation + * on all the 5GHz & 6GHz channels + */ + if (info[0].ch_freq == info[1].ch_freq && + info[0].ch_freq == info[2].ch_freq) { + *ch_freq = 0; + return true; + } + + /* + * DBS with SCC on one vdev scenario. Allow TDLS off-channel + * on other mac frequency where STA is not present + * SBS case is not considered since STA should be connected + * on 2.4GHz and TDLS off-channel on SBS MCC is not allowed + */ + for (i = 0; i < connection_count; i++) { + for (j = i + 1; j < connection_count; j++) { + /* + * Find 2 vdevs such that STA is one of the vdev + * and STA + other vdev are not on same mac. + * Return the foreign vdev frequency which is + * not on same mac along with STA + */ + if (!policy_mgr_2_freq_always_on_same_mac( + psoc, info[i].ch_freq, + info[j].ch_freq)) { + if (sta_vdev_id == info[i].vdev_id) { + *ch_freq = info[j].ch_freq; + return true; + } else if (sta_vdev_id == + info[j].vdev_id) { + *ch_freq = info[i].ch_freq; + return true; + } + } + } + } + + return false; + default: + policy_mgr_debug("TDLS off channel not allowed on > 3 port conc"); + break; + } + + return false; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c new file mode 100644 index 0000000000..4f8a07a2cc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c @@ -0,0 +1,5327 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_policy_mgr_core.c + * + * WLAN Concurrenct Connection Management functions + * + */ + +/* Include files */ + +#include "wlan_policy_mgr_i.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_mlme_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_cm_api.h" +#include "wlan_reg_ucfg_api.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_cmn.h" +#include "wlan_mlo_mgr_public_structs.h" +#endif +#include "wlan_cm_ucfg_api.h" +#include "target_if.h" + +#define POLICY_MGR_MAX_CON_STRING_LEN 230 +#define LOWER_END_FREQ_5GHZ 4900 + +static const uint16_t sap_mand_5g_freq_list[] = {5745, 5765, 5785, 5805}; + +struct policy_mgr_conc_connection_info + pm_conc_connection_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + +#ifdef WLAN_FEATURE_11BE_MLO +struct policy_mgr_disabled_ml_link_info + pm_disabled_ml_links[MAX_NUMBER_OF_DISABLE_LINK]; +#endif + +struct policy_mgr_psoc_priv_obj *policy_mgr_get_context( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + pm_ctx = (struct policy_mgr_psoc_priv_obj *) + wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_POLICY_MGR); + return pm_ctx; +} + +QDF_STATUS policy_mgr_get_updated_scan_config( + struct wlan_objmgr_psoc *psoc, + uint32_t *scan_config, + bool dbs_scan, + bool dbs_plus_agile_scan, + bool single_mac_scan_with_dfs) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conc_scan_config_bits = 0; + struct target_psoc_info *tgt_hdl; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + *scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); + if (!tgt_hdl) { + policy_mgr_err("tgt_hdl NULL"); + return QDF_STATUS_E_FAILURE; + } + conc_scan_config_bits = target_if_get_conc_scan_config_bits(tgt_hdl); + + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, dbs_scan & + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(conc_scan_config_bits)); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET(*scan_config, + dbs_plus_agile_scan & + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(conc_scan_config_bits)); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET(*scan_config, + single_mac_scan_with_dfs & + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(conc_scan_config_bits)); + + policy_mgr_debug("scan_config:%x ", *scan_config); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_updated_fw_mode_config( + struct wlan_objmgr_psoc *psoc, + uint32_t *fw_mode_config, + bool dbs, + bool agile_dfs) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + *fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + WMI_DBS_FW_MODE_CFG_DBS_SET(*fw_mode_config, dbs); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET(*fw_mode_config, agile_dfs); + + policy_mgr_debug("fw_mode_config:%x ", *fw_mode_config); + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_dual_mac_disabled_in_ini( + struct wlan_objmgr_psoc *psoc) +{ + bool is_disabled = false; + uint8_t dbs_type = DISABLE_DBS_CXN_AND_SCAN; + + policy_mgr_get_dual_mac_feature(psoc, &dbs_type); + /* + * If DBS support for connection is disabled through INI then assume + * that DBS is not supported, so that policy manager takes + * the decision considering non-dbs cases only. + * + * For DBS scan check the INI value explicitly + */ + switch (dbs_type) { + case DISABLE_DBS_CXN_AND_SCAN: + case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN: + case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF: + is_disabled = true; + break; + default: + break; + } + + return is_disabled; +} + +uint32_t policy_mgr_get_mcc_to_scc_switch_mode( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + return pm_ctx->cfg.mcc_to_scc_switch; +} + +#ifdef WLAN_FEATURE_SR +bool policy_mgr_get_same_mac_conc_sr_status(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + return pm_ctx->cfg.sr_in_same_mac_conc; +} +#endif + +bool policy_mgr_get_dbs_config(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t fw_mode_config; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_DBS_GET(fw_mode_config); +} + +bool policy_mgr_get_agile_dfs_config(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t fw_mode_config; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + return WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_mode_config); +} + +bool policy_mgr_get_dbs_scan_config(struct wlan_objmgr_psoc *psoc) +{ + uint32_t scan_config; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config); +} + +void policy_mgr_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss, + uint32_t *tx_ss, uint32_t *rx_ss) +{ + switch (mac_ss) { + case HW_MODE_SS_0x0: + *tx_ss = 0; + *rx_ss = 0; + break; + case HW_MODE_SS_1x1: + *tx_ss = 1; + *rx_ss = 1; + break; + case HW_MODE_SS_2x2: + *tx_ss = 2; + *rx_ss = 2; + break; + case HW_MODE_SS_3x3: + *tx_ss = 3; + *rx_ss = 3; + break; + case HW_MODE_SS_4x4: + *tx_ss = 4; + *rx_ss = 4; + break; + default: + *tx_ss = 0; + *rx_ss = 0; + } +} + +int8_t policy_mgr_get_matching_hw_mode_index( + struct wlan_objmgr_psoc *psoc, + uint32_t mac0_tx_ss, uint32_t mac0_rx_ss, + enum hw_mode_bandwidth mac0_bw, + uint32_t mac1_tx_ss, uint32_t mac1_rx_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_mac_band_cap mac0_band_cap, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs) +{ + uint32_t i; + uint32_t t_mac0_tx_ss, t_mac0_rx_ss, t_mac0_bw; + uint32_t t_mac1_tx_ss, t_mac1_rx_ss, t_mac1_bw; + uint32_t dbs_mode, agile_dfs_mode, sbs_mode; + uint32_t t_mac0_band_cap; + int8_t found = -EINVAL; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return found; + } + + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + t_mac0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac0_tx_ss < mac0_tx_ss) + continue; + + t_mac0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac0_rx_ss < mac0_rx_ss) + continue; + + t_mac0_bw = POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + /* + * Firmware advertises max bw capability as CBW 80+80 + * for single MAC. Thus CBW 20/40/80 should also be + * supported, if CBW 80+80 is supported. + */ + if (t_mac0_bw < mac0_bw) + continue; + + t_mac1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac1_tx_ss < mac1_tx_ss) + continue; + + t_mac1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac1_rx_ss < mac1_rx_ss) + continue; + + t_mac1_bw = POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (t_mac1_bw < mac1_bw) + continue; + + dbs_mode = POLICY_MGR_HW_MODE_DBS_MODE_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (dbs_mode != dbs) + continue; + + agile_dfs_mode = POLICY_MGR_HW_MODE_AGILE_DFS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (agile_dfs_mode != dfs) + continue; + + sbs_mode = POLICY_MGR_HW_MODE_SBS_MODE_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (sbs_mode != sbs) + continue; + + t_mac0_band_cap = POLICY_MGR_HW_MODE_MAC0_BAND_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + if (mac0_band_cap && t_mac0_band_cap != mac0_band_cap) + continue; + + found = POLICY_MGR_HW_MODE_ID_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + + policy_mgr_debug("hw_mode id %d found at %d", found, i); + + break; + } + return found; +} + +int8_t policy_mgr_get_hw_mode_idx_from_dbs_hw_list( + struct wlan_objmgr_psoc *psoc, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_mac_band_cap mac0_band_cap, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs) +{ + uint32_t mac0_tx_ss, mac0_rx_ss; + uint32_t mac1_tx_ss, mac1_rx_ss; + + policy_mgr_get_tx_rx_ss_from_config(mac0_ss, &mac0_tx_ss, &mac0_rx_ss); + policy_mgr_get_tx_rx_ss_from_config(mac1_ss, &mac1_tx_ss, &mac1_rx_ss); + + policy_mgr_debug("MAC0: TxSS=%d, RxSS=%d, BW=%d band=%d", + mac0_tx_ss, mac0_rx_ss, mac0_bw, mac0_band_cap); + policy_mgr_debug("MAC1: TxSS=%d, RxSS=%d, BW=%d", + mac1_tx_ss, mac1_rx_ss, mac1_bw); + policy_mgr_debug("DBS=%d, Agile DFS=%d, SBS=%d", + dbs, dfs, sbs); + + return policy_mgr_get_matching_hw_mode_index(psoc, mac0_tx_ss, + mac0_rx_ss, + mac0_bw, + mac1_tx_ss, mac1_rx_ss, + mac1_bw, + mac0_band_cap, + dbs, dfs, sbs); +} + +QDF_STATUS policy_mgr_get_hw_mode_from_idx( + struct wlan_objmgr_psoc *psoc, + uint32_t idx, + struct policy_mgr_hw_mode_params *hw_mode) +{ + uint64_t param; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t mac0_min_ss; + uint8_t mac1_min_ss; + uint32_t i, hw_mode_id; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + if (!pm_ctx->num_dbs_hw_modes) { + policy_mgr_err("No dbs hw modes available"); + return QDF_STATUS_E_FAILURE; + } + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + hw_mode_id = POLICY_MGR_HW_MODE_ID_GET(param); + hw_mode->emlsr_cap = POLICY_MGR_HW_MODE_EMLSR_MODE_GET(param); + + if (hw_mode_id == idx || hw_mode->emlsr_cap) + break; + } + if (i >= pm_ctx->num_dbs_hw_modes) { + policy_mgr_err("hw mode id %d not found", idx); + return QDF_STATUS_E_FAILURE; + } + + param = pm_ctx->hw_mode.hw_mode_list[i]; + + hw_mode->mac0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param); + hw_mode->mac0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param); + hw_mode->mac0_bw = POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param); + hw_mode->mac1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param); + hw_mode->mac1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param); + hw_mode->mac1_bw = POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(param); + hw_mode->mac0_band_cap = POLICY_MGR_HW_MODE_MAC0_BAND_GET(param); + hw_mode->dbs_cap = POLICY_MGR_HW_MODE_DBS_MODE_GET(param); + hw_mode->agile_dfs_cap = POLICY_MGR_HW_MODE_AGILE_DFS_GET(param); + hw_mode->sbs_cap = POLICY_MGR_HW_MODE_SBS_MODE_GET(param); + if (hw_mode->dbs_cap) { + mac0_min_ss = QDF_MIN(hw_mode->mac0_tx_ss, hw_mode->mac0_rx_ss); + mac1_min_ss = QDF_MIN(hw_mode->mac1_tx_ss, hw_mode->mac1_rx_ss); + if (hw_mode->mac0_band_cap == WLAN_5G_CAPABILITY && + mac0_min_ss && mac1_min_ss && + mac0_min_ss > mac1_min_ss) + hw_mode->action_type = PM_DBS1; + else if (hw_mode->mac0_band_cap == WLAN_2G_CAPABILITY && + mac0_min_ss && mac1_min_ss && + mac0_min_ss > mac1_min_ss) + hw_mode->action_type = PM_DBS2; + else + hw_mode->action_type = PM_DBS; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_old_and_new_hw_index( + struct wlan_objmgr_psoc *psoc, + uint32_t *old_hw_mode_index, + uint32_t *new_hw_mode_index) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + *old_hw_mode_index = pm_ctx->old_hw_mode_index; + *new_hw_mode_index = pm_ctx->new_hw_mode_index; + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_update_conc_list(struct wlan_objmgr_psoc *psoc, + uint32_t conn_index, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + enum hw_mode_bandwidth bw, + uint8_t mac, + enum policy_mgr_chain_mode chain_mask, + uint32_t original_nss, + uint32_t vdev_id, + bool in_use, + bool update_conn, + uint16_t ch_flagext) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool mcc_mode; + enum hw_mode_bandwidth max_bw; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (conn_index >= MAX_NUMBER_OF_CONC_CONNECTIONS) { + policy_mgr_err("Number of connections exceeded conn_index: %d", + conn_index); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + pm_conc_connection_list[conn_index].mode = mode; + pm_conc_connection_list[conn_index].freq = ch_freq; + pm_conc_connection_list[conn_index].bw = bw; + pm_conc_connection_list[conn_index].mac = mac; + pm_conc_connection_list[conn_index].chain_mask = chain_mask; + pm_conc_connection_list[conn_index].original_nss = original_nss; + pm_conc_connection_list[conn_index].vdev_id = vdev_id; + pm_conc_connection_list[conn_index].in_use = in_use; + pm_conc_connection_list[conn_index].ch_flagext = ch_flagext; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* + * For STA and P2P client mode, the mode change event sent as part + * of the callback causes delay in processing M1 frame at supplicant + * resulting in cert test case failure. The mode change event is sent + * as part of add key for STA and P2P client mode. + */ + if (pm_ctx->mode_change_cb && update_conn) + pm_ctx->mode_change_cb(); + + if (pm_ctx->cdp_cbacks.cdp_update_mac_id) + pm_ctx->cdp_cbacks.cdp_update_mac_id(psoc, vdev_id, mac); + + /* IPA only cares about STA or SAP mode */ + if (mode == PM_STA_MODE || policy_mgr_is_sap_mode(mode)) { + mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc); + + if (pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb) + pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb(mcc_mode); + + if (pm_ctx->dp_cbacks.hdd_ipa_set_perf_level_bw) { + max_bw = policy_mgr_get_connection_max_channel_width( + psoc); + policy_mgr_debug("max channel width %d", max_bw); + pm_ctx->dp_cbacks.hdd_ipa_set_perf_level_bw(max_bw); + } + } + + if (pm_ctx->conc_cbacks.connection_info_update) + pm_ctx->conc_cbacks.connection_info_update(); +} + +/** + * policy_mgr_store_and_del_conn_info() - Store and del a connection info + * @psoc: psoc handle + * @mode: Mode whose entry has to be deleted + * @all_matching_cxn_to_del: All the specified mode entries should be deleted + * @info: Structure array pointer where the connection info will be saved + * @num_cxn_del: Number of connection which are going to be deleted + * + * Saves the connection info corresponding to the provided mode + * and deleted that corresponding entry based on vdev from the + * connection info structure + * + * Return: None + */ +void policy_mgr_store_and_del_conn_info(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, bool all_matching_cxn_to_del, + struct policy_mgr_conc_connection_info *info, uint8_t *num_cxn_del) +{ + int32_t conn_index = 0; + uint32_t found_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (!num_cxn_del) { + policy_mgr_err("num_cxn_del is NULL"); + return; + } + *num_cxn_del = 0; + if (!info) { + policy_mgr_err("Invalid connection info"); + return; + } + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (mode == pm_conc_connection_list[conn_index].mode) { + /* + * Storing the connection entry which will be + * temporarily deleted. + */ + info[found_index] = pm_conc_connection_list[conn_index]; + /* Deleting the connection entry */ + policy_mgr_decr_connection_count(psoc, + info[found_index].vdev_id); + policy_mgr_debug("Stored %d (%d), deleted STA entry with vdev id %d, index %d", + info[found_index].vdev_id, + info[found_index].mode, + info[found_index].vdev_id, conn_index); + pm_ctx->no_of_active_sessions[info->mode]--; + found_index++; + if (all_matching_cxn_to_del) + continue; + else + break; + } + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (!found_index) { + *num_cxn_del = 0; + policy_mgr_debug("Mode:%d not available in the conn info", + mode); + } else { + *num_cxn_del = found_index; + policy_mgr_debug("Mode:%d number of conn %d temp del", + mode, *num_cxn_del); + } + + /* + * Caller should set the PCL and restore the connection entry + * in conn info. + */ +} + +void policy_mgr_store_and_del_conn_info_by_vdev_id( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + struct policy_mgr_conc_connection_info *info, + uint8_t *num_cxn_del) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (!info || !num_cxn_del) { + policy_mgr_err("Invalid parameters"); + return; + } + + *num_cxn_del = 0; + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) && + pm_conc_connection_list[conn_index].in_use) { + *num_cxn_del = 1; + break; + } + } + /* + * Storing the connection entry which will be + * temporarily deleted. + */ + if (*num_cxn_del == 1) { + *info = pm_conc_connection_list[conn_index]; + pm_ctx->no_of_active_sessions[info->mode]--; + /* Deleting the connection entry */ + policy_mgr_decr_connection_count( + psoc, + pm_conc_connection_list[conn_index].vdev_id); + } + + policy_mgr_debug("vdev id %d, num_cxn_del %d", vdev_id, *num_cxn_del); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +void policy_mgr_store_and_del_conn_info_by_chan_and_mode( + struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, + enum policy_mgr_con_mode mode, + struct policy_mgr_conc_connection_info *info, + uint8_t *num_cxn_del) +{ + uint32_t conn_index = 0; + uint8_t found_index = 0; + + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (!info || !num_cxn_del) { + policy_mgr_err("Invalid parameters"); + return; + } + *num_cxn_del = 0; + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (ch_freq != pm_conc_connection_list[conn_index].freq || + mode != pm_conc_connection_list[conn_index].mode) { + conn_index++; + continue; + } + info[found_index] = pm_conc_connection_list[conn_index]; + policy_mgr_debug("Stored %d (%d), deleted STA entry with vdev id %d, index %d ch %d", + info[found_index].vdev_id, + info[found_index].mode, + info[found_index].vdev_id, conn_index, + ch_freq); + found_index++; + conn_index++; + } + conn_index = 0; + while (conn_index < found_index) { + policy_mgr_decr_connection_count( + psoc, info[conn_index].vdev_id); + + pm_ctx->no_of_active_sessions[info[conn_index].mode]--; + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + *num_cxn_del = found_index; +} + +/** + * policy_mgr_restore_deleted_conn_info() - Restore connection info + * @psoc: psoc handle + * @info: An array saving connection info that is to be restored + * @num_cxn_del: Number of connection temporary deleted + * + * Restores the connection info of STA that was saved before + * updating the PCL to the FW + * + * Return: None + */ +void policy_mgr_restore_deleted_conn_info(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_conc_connection_info *info, + uint8_t num_cxn_del) +{ + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + int i; + + if (MAX_NUMBER_OF_CONC_CONNECTIONS < num_cxn_del || 0 == num_cxn_del) { + policy_mgr_err("Failed to restore %d/%d deleted information", + num_cxn_del, MAX_NUMBER_OF_CONC_CONNECTIONS); + return; + } + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + conn_index = policy_mgr_get_connection_count(psoc); + if (conn_index + num_cxn_del > MAX_NUMBER_OF_CONC_CONNECTIONS) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_err("Failed to restore the deleted information %d/%d, as it exceed max %d", + conn_index, num_cxn_del, + MAX_NUMBER_OF_CONC_CONNECTIONS); + return; + } + + qdf_mem_copy(&pm_conc_connection_list[conn_index], info, + num_cxn_del * sizeof(*info)); + pm_ctx->no_of_active_sessions[info->mode] += num_cxn_del; + for (i = 0; i < num_cxn_del; i++) + policy_mgr_debug("Restored the deleleted conn info, vdev:%d, index:%d", + info[i].vdev_id, conn_index++); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +static bool +policy_mgr_is_freq_range_5_6ghz(qdf_freq_t start_freq, qdf_freq_t end_freq) +{ + /* + * As Fw is sending the whole hardware range which include 4.9Ghz as + * well. Use LOWER_END_FREQ_5GHZ to differentiate 2.4Ghz and 5Ghz + */ + if (start_freq >= LOWER_END_FREQ_5GHZ && + end_freq >= LOWER_END_FREQ_5GHZ) + return true; + + return false; +} + +static bool +policy_mgr_is_freq_range_2ghz(qdf_freq_t start_freq, qdf_freq_t end_freq) +{ + /* + * As Fw is sending the whole hardware range which include 4.9Ghz as + * well. Use LOWER_END_FREQ_5GHZ to differentiate 2.4Ghz and 5Ghz + */ + if (start_freq < LOWER_END_FREQ_5GHZ && end_freq < LOWER_END_FREQ_5GHZ) + return true; + + return false; +} + +static void +policy_mgr_fill_curr_mac_2ghz_freq(uint32_t mac_id, + struct policy_mgr_pdev_mac_freq_map *freq, + struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + pm_ctx->hw_mode.cur_mac_freq_range[mac_id].low_2ghz_freq = + QDF_MAX(freq->start_freq, + wlan_reg_min_24ghz_chan_freq()); + pm_ctx->hw_mode.cur_mac_freq_range[mac_id].high_2ghz_freq = + QDF_MIN(freq->end_freq, + wlan_reg_max_24ghz_chan_freq()); +} + +static void +policy_mgr_fill_curr_mac_5ghz_freq(uint32_t mac_id, + struct policy_mgr_pdev_mac_freq_map *freq, + struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + qdf_freq_t max_5g_freq; + + max_5g_freq = wlan_reg_max_6ghz_chan_freq() ? + wlan_reg_max_6ghz_chan_freq() : + wlan_reg_max_5ghz_chan_freq(); + + pm_ctx->hw_mode.cur_mac_freq_range[mac_id].low_5ghz_freq = + QDF_MAX(freq->start_freq, + wlan_reg_min_5ghz_chan_freq()); + pm_ctx->hw_mode.cur_mac_freq_range[mac_id].high_5ghz_freq = + QDF_MIN(freq->end_freq, max_5g_freq); +} + +void +policy_mgr_fill_curr_mac_freq_by_hwmode(struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_mode mode_hw) +{ + uint8_t i; + struct policy_mgr_freq_range *cur_mac_freq, *hwmode_freq; + + cur_mac_freq = pm_ctx->hw_mode.cur_mac_freq_range; + hwmode_freq = pm_ctx->hw_mode.freq_range_caps[mode_hw]; + + for (i = 0; i < MAX_MAC; i++) { + cur_mac_freq[i].low_2ghz_freq = hwmode_freq[i].low_2ghz_freq; + cur_mac_freq[i].high_2ghz_freq = hwmode_freq[i].high_2ghz_freq; + cur_mac_freq[i].low_5ghz_freq = hwmode_freq[i].low_5ghz_freq; + cur_mac_freq[i].high_5ghz_freq = hwmode_freq[i].high_5ghz_freq; + } +} + +static void +policy_mgr_fill_legacy_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct policy_mgr_hw_mode_params hw_mode) +{ + enum policy_mgr_mode mode; + + mode = hw_mode.dbs_cap ? MODE_DBS : MODE_SMM; + policy_mgr_fill_curr_mac_freq_by_hwmode(pm_ctx, mode); +} + +static QDF_STATUS +policy_mgr_fill_curr_freq_by_pdev_freq(int32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *freq, + struct policy_mgr_psoc_priv_obj *pm_ctx, + struct policy_mgr_hw_mode_params hw_mode) +{ + uint32_t mac_id, i; + + /* memzero before filling it */ + qdf_mem_zero(pm_ctx->hw_mode.cur_mac_freq_range, + sizeof(pm_ctx->hw_mode.cur_mac_freq_range)); + for (i = 0; i < num_mac_freq; i++) { + mac_id = freq[i].mac_id; + + if (mac_id >= MAX_MAC) { + policy_mgr_debug("Invalid pdev id %d", mac_id); + return QDF_STATUS_E_INVAL; + } + + if (policy_mgr_is_freq_range_2ghz(freq[i].start_freq, + freq[i].end_freq)) { + policy_mgr_fill_curr_mac_2ghz_freq(mac_id, + &freq[i], + pm_ctx); + } else if (policy_mgr_is_freq_range_5_6ghz(freq[i].start_freq, + freq[i].end_freq)) { + policy_mgr_fill_curr_mac_5ghz_freq(mac_id, &freq[i], + pm_ctx); + } else { + policy_mgr_err("Invalid different band freq range: mac_id %d start freq %d end_freq %d", + mac_id, freq[i].start_freq, + freq[i].end_freq); + return QDF_STATUS_E_INVAL; + } + } + + return QDF_STATUS_SUCCESS; +} + +static void +policy_mgr_update_curr_mac_freq(uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *freq, + struct policy_mgr_psoc_priv_obj *pm_ctx, + struct policy_mgr_hw_mode_params hw_mode) +{ + QDF_STATUS status; + + if (num_mac_freq && freq) { + status = policy_mgr_fill_curr_freq_by_pdev_freq(num_mac_freq, + freq, pm_ctx, + hw_mode); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + } + + policy_mgr_fill_legacy_freq_range(pm_ctx, hw_mode); +} + +/** + * policy_mgr_update_hw_mode_conn_info() - Update connection + * info based on HW mode + * @psoc: psoc handle + * @num_vdev_mac_entries: Number of vdev-mac id entries that follow + * @vdev_mac_map: Mapping of vdev-mac id + * @hw_mode: HW mode + * @num_mac_freq: number of Frequency Range + * @freq_info: Pointer to Frequency Range + * + * Updates the connection info parameters based on the new HW mode + * + * Return: None + */ +void policy_mgr_update_hw_mode_conn_info(struct wlan_objmgr_psoc *psoc, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + struct policy_mgr_hw_mode_params hw_mode, + uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *freq_info) +{ + uint32_t i, conn_index, found; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + policy_mgr_update_curr_mac_freq(num_mac_freq, freq_info, pm_ctx, + hw_mode); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < num_vdev_mac_entries; i++) { + conn_index = 0; + found = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_mac_map[i].vdev_id == + pm_conc_connection_list[conn_index].vdev_id) { + found = 1; + break; + } + conn_index++; + } + if (found) { + pm_conc_connection_list[conn_index].mac = + vdev_mac_map[i].mac_id; + policy_mgr_debug("vdev:%d, mac:%d", + pm_conc_connection_list[conn_index].vdev_id, + pm_conc_connection_list[conn_index].mac); + if (pm_ctx->cdp_cbacks.cdp_update_mac_id) + pm_ctx->cdp_cbacks.cdp_update_mac_id( + psoc, + vdev_mac_map[i].vdev_id, + vdev_mac_map[i].mac_id); + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + policy_mgr_dump_connection_status_info(psoc); +} + +void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, + uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t session_id, void *context, + uint32_t request_id) +{ + QDF_STATUS ret; + struct policy_mgr_hw_mode_params hw_mode; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(context); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + goto set_done_event; + } + + policy_mgr_set_hw_mode_change_in_progress(context, + POLICY_MGR_HW_MODE_NOT_IN_PROGRESS); + + if (status == SET_HW_MODE_STATUS_OK || + status == SET_HW_MODE_STATUS_ALREADY) { + policy_mgr_set_connection_update(context); + } + + if (status != SET_HW_MODE_STATUS_OK) { + policy_mgr_debug("Set HW mode failed with status %d", status); + goto next_action; + } + + /* vdev mac map for NAN Discovery is expected in NAN Enable resp */ + if (reason != POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY && + !vdev_mac_map) { + policy_mgr_err("vdev_mac_map is NULL"); + goto set_done_event; + } + + ret = policy_mgr_get_hw_mode_from_idx(context, cfgd_hw_mode_index, + &hw_mode); + if (QDF_IS_STATUS_ERROR(ret)) { + policy_mgr_err("Get HW mode for index %d reason: %d", + cfgd_hw_mode_index, ret); + goto set_done_event; + } + policy_mgr_debug("HW mode idx %d, DBS %d Agile %d SBS %d, MAC0:: SS:Tx %d Rx %d, BW %d band %d. MAC1:: SS:Tx %d Rx %d, BW %d", + cfgd_hw_mode_index, hw_mode.dbs_cap, + hw_mode.agile_dfs_cap, hw_mode.sbs_cap, + hw_mode.mac0_tx_ss, hw_mode.mac0_rx_ss, + hw_mode.mac0_bw, hw_mode.mac0_band_cap, + hw_mode.mac1_tx_ss, hw_mode.mac1_rx_ss, + hw_mode.mac1_bw); + policy_mgr_dump_freq_range_n_vdev_map(num_vdev_mac_entries, + vdev_mac_map, 0, NULL); + + /* update pm_conc_connection_list */ + policy_mgr_update_hw_mode_conn_info(context, + num_vdev_mac_entries, + vdev_mac_map, + hw_mode, 0, NULL); + if (pm_ctx->mode_change_cb) + pm_ctx->mode_change_cb(); + + /* Notify tdls */ + if (pm_ctx->tdls_cbacks.tdls_notify_decrement_session) + pm_ctx->tdls_cbacks.tdls_notify_decrement_session(pm_ctx->psoc); + +next_action: + if (PM_NOP != next_action && (status == SET_HW_MODE_STATUS_ALREADY || + status == SET_HW_MODE_STATUS_OK)) + policy_mgr_next_actions(context, session_id, + next_action, reason, request_id); + else + policy_mgr_debug("No action needed right now"); + +set_done_event: + ret = policy_mgr_set_opportunistic_update(context); + if (!QDF_IS_STATUS_SUCCESS(ret)) + policy_mgr_err("ERROR: set opportunistic_update event failed"); +} + +static char * +ml_sta_prefix(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", + vdev_id); + return "STA"; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return "ML STA"; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return "STA"; +} + +static void +policy_mgr_dump_ml_sta_conc(struct wlan_objmgr_psoc *psoc, + uint8_t *num_mlo_sta) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (!num_mlo_sta) + return; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + if (policy_mgr_is_mlo_in_mode_dbs(psoc, PM_STA_MODE, NULL, + num_mlo_sta)) + policy_mgr_debug("ML STA %d links in DBS band", *num_mlo_sta); + else if (policy_mgr_is_mlo_in_mode_sbs(psoc, PM_STA_MODE, NULL, + num_mlo_sta)) + policy_mgr_debug("ML STA %d links in SBS band", *num_mlo_sta); + else if (*num_mlo_sta > 1) + policy_mgr_debug("ML STA %d links in same mac MLSR", + *num_mlo_sta); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +/** + * policy_mgr_dump_current_concurrency_one_connection() - To dump the + * current concurrency info with one connection + * @psoc: psoc object + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_one_connection( + struct wlan_objmgr_psoc *psoc, + char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + char buf[9] = {0}; + + mode = pm_conc_connection_list[0].mode; + qdf_scnprintf(buf, sizeof(buf), "(vdev %d)", + pm_conc_connection_list[0].vdev_id); + + switch (mode) { + case PM_STA_MODE: + count = strlcat(cc_mode, + ml_sta_prefix( + psoc, pm_conc_connection_list[0].vdev_id), + length); + break; + case PM_SAP_MODE: + count = strlcat(cc_mode, "SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = strlcat(cc_mode, "P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = strlcat(cc_mode, "P2P GO", + length); + break; + case PM_NAN_DISC_MODE: + count = strlcat(cc_mode, "NAN DISC", length); + break; + case PM_NDI_MODE: + count = strlcat(cc_mode, "NDI", length); + break; + case PM_LL_LT_SAP_MODE: + count = strlcat(cc_mode, "LT_SAP", length); + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + count += strlcat(cc_mode, buf, length); + + return count; +} + +/** + * policy_mgr_dump_current_concurrency_two_connection() - To dump the + * current concurrency info with two connections + * @psoc: psoc object + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_two_connection( + struct wlan_objmgr_psoc *psoc, + char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + char buf[9] = {0}; + + mode = pm_conc_connection_list[1].mode; + qdf_scnprintf(buf, sizeof(buf), "(vdev %d)", + pm_conc_connection_list[1].vdev_id); + + switch (mode) { + case PM_STA_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+", length); + count += strlcat(cc_mode, + ml_sta_prefix( + psoc, pm_conc_connection_list[1].vdev_id), + length); + break; + case PM_SAP_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case PM_NDI_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+NDI", + length); + break; + case PM_NAN_DISC_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+NAN Disc", length); + break; + case PM_LL_LT_SAP_MODE: + count = policy_mgr_dump_current_concurrency_one_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+LT_SAP", + length); + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + count += strlcat(cc_mode, buf, length); + + return count; +} + +/** + * policy_mgr_dump_current_concurrency_three_connection() - To dump the + * current concurrency info with three connections + * @psoc: psoc object + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_three_connection( + struct wlan_objmgr_psoc *psoc, + char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + char buf[9] = {0}; + + mode = pm_conc_connection_list[2].mode; + qdf_scnprintf(buf, sizeof(buf), "(vdev %d)", + pm_conc_connection_list[2].vdev_id); + + switch (mode) { + case PM_STA_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+", length); + count += strlcat(cc_mode, + ml_sta_prefix( + psoc, pm_conc_connection_list[2].vdev_id), + length); + break; + case PM_SAP_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case PM_NAN_DISC_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+NAN Disc", + length); + break; + case PM_NDI_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+NDI", + length); + break; + case PM_LL_LT_SAP_MODE: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+LT_SAP", + length); + + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + count += strlcat(cc_mode, buf, length); + + return count; +} + +static void +policy_mgr_dump_dual_mac_concurrency(struct policy_mgr_psoc_priv_obj *pm_ctx, + char *cc_mode, uint32_t length) +{ + char buf[26] = {0}; + uint8_t i; + uint8_t j; + uint32_t vdev_bit_mask = 0; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (!pm_conc_connection_list[i].in_use) + continue; + for (j = i + 1; j < MAX_NUMBER_OF_CONC_CONNECTIONS; j++) { + if (!pm_conc_connection_list[j].in_use) + continue; + if (policy_mgr_are_2_freq_on_same_mac( + pm_ctx->psoc, + pm_conc_connection_list[i].freq, + pm_conc_connection_list[j].freq)) { + qdf_mem_zero(buf, sizeof(buf)); + qdf_scnprintf( + buf, sizeof(buf), + ": vdev %d & %d %s on mac %d", + pm_conc_connection_list[i].vdev_id, + pm_conc_connection_list[j].vdev_id, + pm_conc_connection_list[i].freq == + pm_conc_connection_list[j].freq ? "SCC" + : "MCC", + pm_conc_connection_list[i].mac); + QDF_SET_PARAM( + vdev_bit_mask, + pm_conc_connection_list[i].vdev_id); + QDF_SET_PARAM( + vdev_bit_mask, + pm_conc_connection_list[j].vdev_id); + strlcat(cc_mode, buf, length); + } + } + } + + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + /* in_use flag is required to be checked because vdev bit + * mask will be 0 for 4th bit if only 3 port concurrency is + * present on a hardware that can support 4 port concurrency + */ + if (!pm_conc_connection_list[i].in_use || + QDF_HAS_PARAM( + vdev_bit_mask, pm_conc_connection_list[i].vdev_id)) + continue; + + qdf_mem_zero(buf, sizeof(buf)); + qdf_scnprintf(buf, sizeof(buf), ": vdev %d alone on mac %d", + pm_conc_connection_list[i].vdev_id, + pm_conc_connection_list[i].mac); + strlcat(cc_mode, buf, length); + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +/** + * policy_mgr_dump_dbs_concurrency() - To dump the dbs concurrency + * combination + * @psoc: psoc handle + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void policy_mgr_dump_dbs_concurrency(struct wlan_objmgr_psoc *psoc, + char *cc_mode, uint32_t length) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + strlcat(cc_mode, " DBS", length); + policy_mgr_dump_dual_mac_concurrency(pm_ctx, cc_mode, length); +} + +/** + * policy_mgr_dump_sbs_concurrency() - To dump the sbs concurrency + * combination + * @psoc: psoc handle + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +static void policy_mgr_dump_sbs_concurrency(struct wlan_objmgr_psoc *psoc, + char *cc_mode, uint32_t length) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + strlcat(cc_mode, " SBS", length); + policy_mgr_dump_dual_mac_concurrency(pm_ctx, cc_mode, length); +} + +#ifdef WLAN_FEATURE_11BE_MLO +void +policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + uint8_t buf[POLICY_MGR_MAX_CON_STRING_LEN] = {0}; + uint32_t len = 0, count = 0, i; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_DISABLE_LINK; i++) { + if (pm_disabled_ml_links[i].in_use) { + len += qdf_scnprintf(buf + len, + POLICY_MGR_MAX_CON_STRING_LEN - len, + "vdev %d :Mode %d freq %d, ", + pm_disabled_ml_links[i].vdev_id, + pm_disabled_ml_links[i].mode, + pm_disabled_ml_links[i].freq); + count++; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (count) + policy_mgr_debug("Disabled links(%d): %s", count, buf); +} +#endif + +#ifdef FEATURE_FOURTH_CONNECTION +/** + * policy_mgr_dump_current_concurrency_4_connection() - To dump the + * current concurrency info with 4 connections + * @psoc: psoc object + * @cc_mode: connection string + * @length: Maximum size of the string + * + * This routine is called to dump the concurrency info + * + * Return: length of the string + */ +static uint32_t policy_mgr_dump_current_concurrency_4_connection( + struct wlan_objmgr_psoc *psoc, char *cc_mode, uint32_t length) +{ + uint32_t count = 0; + enum policy_mgr_con_mode mode; + char buf[9] = {0}; + + mode = pm_conc_connection_list[3].mode; + qdf_scnprintf(buf, sizeof(buf), "(vdev %d)", + pm_conc_connection_list[3].vdev_id); + + switch (mode) { + case PM_STA_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+", length); + count += strlcat(cc_mode, + ml_sta_prefix( + psoc, pm_conc_connection_list[3].vdev_id), + length); + break; + case PM_SAP_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+SAP", + length); + break; + case PM_P2P_CLIENT_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+P2P CLI", + length); + break; + case PM_P2P_GO_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+P2P GO", + length); + break; + case PM_NAN_DISC_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+NAN Disc", + length); + break; + case PM_NDI_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+NDI", + length); + break; + case PM_LL_LT_SAP_MODE: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, length); + count += strlcat(cc_mode, "+LT_SAP", + length); + break; + + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + count += strlcat(cc_mode, buf, length); + + return count; +} + +static bool +policy_mgr_handle_dump_4th_connection(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint32_t num_connections, + char *cc_mode, uint32_t len) +{ + uint32_t count = 0; + + if (num_connections != 4) + return false; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + count = policy_mgr_dump_current_concurrency_4_connection( + pm_ctx->psoc, cc_mode, len); + + if (policy_mgr_is_current_hwmode_dbs(pm_ctx->psoc)) + policy_mgr_dump_dbs_concurrency(pm_ctx->psoc, cc_mode, len); + else if (policy_mgr_is_current_hwmode_sbs(pm_ctx->psoc)) + policy_mgr_dump_sbs_concurrency(pm_ctx->psoc, cc_mode, len); + else + strlcat(cc_mode, " MCC", len); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return true; +} +#else +static inline bool +policy_mgr_handle_dump_4th_connection(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint32_t num_connections, + char *cc_mode, uint32_t len) +{ + return false; +} +#endif + +void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections = 0; + char *cc_mode; + uint32_t count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t len = POLICY_MGR_MAX_CON_STRING_LEN; + uint8_t num_mlo_sta = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + num_connections = policy_mgr_get_connection_count(psoc); + if (!num_connections) + return; + + cc_mode = qdf_mem_malloc(len); + if (!cc_mode) + return; + + policy_mgr_dump_connection_status_info(psoc); + policy_mgr_dump_ml_sta_conc(psoc, &num_mlo_sta); + switch (num_connections) { + case 1: + policy_mgr_dump_current_concurrency_one_connection(psoc, + cc_mode, + len); + policy_mgr_debug("%s Standalone", cc_mode); + break; + case 2: + count = policy_mgr_dump_current_concurrency_two_connection( + psoc, cc_mode, len); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq) { + strlcat(cc_mode, " SCC", len); + /* In some platform 2.4 Ghz can lead to DBS, + * so check for DBS for SCC/MCC case + */ + if (policy_mgr_is_current_hwmode_dbs(psoc)) + strlcat(cc_mode, " (DBS)", len); + } else if (policy_mgr_2_freq_always_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + strlcat(cc_mode, " MCC", len); + if (policy_mgr_is_current_hwmode_dbs(psoc)) + strlcat(cc_mode, " (DBS)", len); + } else if (policy_mgr_is_current_hwmode_dbs(psoc)) { + strlcat(cc_mode, " DBS", len); + } else if (policy_mgr_is_current_hwmode_sbs(psoc)) { + strlcat(cc_mode, " SBS", len); + } else { + if (num_mlo_sta < 2) + strlcat(cc_mode, " MCC", len); + else + strlcat(cc_mode, " SMM", len); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("%s", cc_mode); + break; + case 3: + count = policy_mgr_dump_current_concurrency_three_connection( + psoc, cc_mode, len); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq && + pm_conc_connection_list[0].freq == + pm_conc_connection_list[2].freq){ + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + strlcat(cc_mode, " SCC", len); + } else if (policy_mgr_are_3_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[2].freq)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (num_mlo_sta < 2) + strlcat(cc_mode, " MCC on single MAC", len); + else + strlcat(cc_mode, " on single MAC", len); + } else { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (policy_mgr_is_current_hwmode_dbs(psoc)) + policy_mgr_dump_dbs_concurrency(psoc, cc_mode, + len); + else if (policy_mgr_is_current_hwmode_sbs(psoc)) + policy_mgr_dump_sbs_concurrency(psoc, cc_mode, + len); + else if (num_mlo_sta < 2) + strlcat(cc_mode, " MCC", len); + else + strlcat(cc_mode, " SMM", len); + } + policy_mgr_debug("%s", cc_mode); + break; + case 4: + if (policy_mgr_handle_dump_4th_connection(pm_ctx, + num_connections, + cc_mode, len)) { + policy_mgr_debug("%s", cc_mode); + break; + } + fallthrough; + default: + policy_mgr_debug("unexpected num_connections value %d", + num_connections); + break; + } + qdf_mem_free(cc_mode); + + policy_mgr_dump_disabled_ml_links(pm_ctx); + + return; +} + +/** + * policy_mgr_set_pcl_for_existing_combo() - Set PCL for existing connection + * @psoc: psoc handle + * @mode: Connection mode of type 'policy_mgr_con_mode' + * @vdev_id: Vdev Id + * + * Set the PCL for an existing connection + * + * Return: None + */ +void policy_mgr_set_pcl_for_existing_combo(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_pcl_list pcl; + + status = policy_mgr_get_pcl_for_vdev_id(psoc, mode, pcl.pcl_list, + &pcl.pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), + vdev_id); + /* Send PCL only if policy_mgr_pdev_get_pcl returned success */ + if (QDF_IS_STATUS_SUCCESS(status)) { + status = policy_mgr_set_pcl(psoc, &pcl, vdev_id, false); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("Send set PCL to policy mgr failed"); + } +} + +void policy_mgr_set_pcl_for_connected_vdev(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool clear_pcl) +{ + struct policy_mgr_pcl_list msg = { {0} }; + struct wlan_objmgr_vdev *vdev; + uint8_t roam_enabled_vdev_id; + bool sta_concurrency_is_with_different_mac, dual_sta_roam_enabled; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + /* + * Get the vdev id of the STA on which roaming is already + * initialized and set the vdev PCL for that STA vdev if dual + * STA roaming feature is enabled and concurrency is STA + STA. + */ + roam_enabled_vdev_id = policy_mgr_get_roam_enabled_sta_session_id(psoc, + vdev_id); + if (roam_enabled_vdev_id == WLAN_UMAC_VDEV_ID_MAX) + return; + + sta_concurrency_is_with_different_mac = + policy_mgr_concurrent_sta_on_different_mac(psoc); + dual_sta_roam_enabled = wlan_mlme_get_dual_sta_roaming_enabled(psoc); + policy_mgr_debug("dual_sta_roam:%d, sta concurrency on different mac:%d, clear_pcl:%d", + dual_sta_roam_enabled, + sta_concurrency_is_with_different_mac, + clear_pcl); + + if (dual_sta_roam_enabled) { + if (clear_pcl) { + /* + * Here the PCL level should be at vdev level already + * as this is invoked from disconnect handler. Clear the + * vdev pcl for the existing connected STA vdev and this + * is followed by set PDEV pcl. + */ + policy_mgr_set_pcl(psoc, &msg, + roam_enabled_vdev_id, true); + wlan_cm_roam_activate_pcl_per_vdev(psoc, + roam_enabled_vdev_id, + false); + } else if (sta_concurrency_is_with_different_mac) { + wlan_cm_roam_activate_pcl_per_vdev(psoc, + roam_enabled_vdev_id, + true); + } + policy_mgr_set_pcl_for_existing_combo(psoc, PM_STA_MODE, + roam_enabled_vdev_id); + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +uint32_t +policy_mgr_get_connected_vdev_band_mask(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_channel *chan; + uint32_t band_mask = 0; + struct wlan_objmgr_vdev *ml_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + uint16_t ml_vdev_cnt = 0; + struct wlan_objmgr_vdev *t_vdev; + int i; + + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return band_mask; + } + + if (wlan_vdev_mlme_is_link_sta_vdev(vdev)) { + policy_mgr_debug("skip mlo link sta"); + return band_mask; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE || + !wlan_vdev_mlme_is_mlo_vdev(vdev)) { + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + policy_mgr_err("no active channel"); + return band_mask; + } + + band_mask |= BIT(wlan_reg_freq_to_band(chan->ch_freq)); + return band_mask; + } + + mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, ml_vdev_list); + for (i = 0; i < ml_vdev_cnt; i++) { + t_vdev = ml_vdev_list[i]; + if (!ucfg_cm_is_vdev_connected(t_vdev)) + goto next; + + chan = wlan_vdev_get_active_channel(t_vdev); + if (!chan) + goto next; + + band_mask |= BIT(wlan_reg_freq_to_band(chan->ch_freq)); +next: + mlo_release_vdev_ref(t_vdev); + } + + return band_mask; +} +#else +uint32_t +policy_mgr_get_connected_vdev_band_mask(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_channel *chan; + uint32_t band_mask = 0; + + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return band_mask; + } + + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + policy_mgr_err("no active channel"); + return band_mask; + } + + band_mask |= BIT(wlan_reg_freq_to_band(chan->ch_freq)); + return band_mask; +} +#endif + +/** + * policy_mgr_get_connected_roaming_vdev_band_mask() - get connected vdev + * band mask + * @psoc: PSOC object + * @vdev_id: Vdev id + * + * Return: reg wifi band mask + */ +uint32_t +policy_mgr_get_connected_roaming_vdev_band_mask(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + uint32_t band_mask = 0, roam_band_mask, band_mask_for_vdev; + struct wlan_objmgr_vdev *vdev; + bool dual_sta_roam_active, is_pcl_per_vdev; + bool is_sbs_capable = false; + + is_sbs_capable = + policy_mgr_is_hw_sbs_capable(psoc); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev is NULL"); + return 0; + } + + roam_band_mask = wlan_cm_get_roam_band_value(psoc, vdev); + + /* + * If sbs is enabled, just send PCL to F/W directly, allow SBS<->DBS + * roaming, not just limit intra band. + */ + if (is_sbs_capable) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return roam_band_mask; + } + band_mask_for_vdev = policy_mgr_get_connected_vdev_band_mask(vdev); + + is_pcl_per_vdev = wlan_cm_roam_is_pcl_per_vdev_active(psoc, vdev_id); + dual_sta_roam_active = wlan_mlme_get_dual_sta_roaming_enabled(psoc); + + policy_mgr_debug("connected STA vdev_id:%d, pcl_per_vdev:%d, dual_sta_roam_active:%d", + vdev_id, is_pcl_per_vdev, + dual_sta_roam_active); + + if (dual_sta_roam_active && is_pcl_per_vdev) { + policy_mgr_debug("connected vdev band mask:%d", + band_mask_for_vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return band_mask_for_vdev; + } + + /* + * if vendor command to configure roam band is set , we will + * take this as priority instead of drv cmd "SETROAMINTRABAND" or + * active connection band. + */ + ucfg_reg_get_band(wlan_vdev_get_pdev(vdev), &band_mask); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + if (roam_band_mask != band_mask) { + policy_mgr_debug("roam_band_mask:%d", roam_band_mask); + return roam_band_mask; + } + + /* + * If PCL command is PDEV level, only one sta is active. + * So fill the band mask if intra band roaming is enabled + */ + if ((!is_pcl_per_vdev) && ucfg_mlme_is_roam_intra_band(psoc)) { + policy_mgr_debug("connected STA band mask:%d", + band_mask_for_vdev); + return band_mask_for_vdev; + } + + policy_mgr_debug("band_mask:%d", band_mask); + return band_mask; +} + +QDF_STATUS policy_mgr_set_pcl(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_list *msg, + uint8_t vdev_id, + bool clear_vdev_pcl) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + struct set_pcl_req *req_msg; + uint32_t i; + + if (!msg) { + policy_mgr_err("msg is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!MLME_IS_ROAM_INITIALIZED(psoc, vdev_id)) { + policy_mgr_debug("Roam is not initialized on vdev:%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + req_msg->band_mask = + policy_mgr_get_connected_roaming_vdev_band_mask(psoc, vdev_id); + for (i = 0; i < msg->pcl_len; i++) { + req_msg->chan_weights.pcl_list[i] = msg->pcl_list[i]; + req_msg->chan_weights.weight_list[i] = msg->weight_list[i]; + } + + req_msg->chan_weights.pcl_len = msg->pcl_len; + req_msg->clear_vdev_pcl = clear_vdev_pcl; + + /* + * Set vdev value as WLAN_UMAC_VDEV_ID_MAX, if PDEV level + * PCL command needs to be sent. + */ + if (!wlan_cm_roam_is_pcl_per_vdev_active(psoc, vdev_id)) + vdev_id = WLAN_UMAC_VDEV_ID_MAX; + + req_msg->vdev_id = vdev_id; + + /* Serialize the req through MC thread */ + message.bodyptr = req_msg; + message.type = SIR_HAL_SET_PCL_TO_FW; + status = scheduler_post_message(QDF_MODULE_ID_POLICY_MGR, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("scheduler_post_msg failed!(err=%d)", status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +static uint32_t pm_get_vdev_id_of_first_conn_idx(struct wlan_objmgr_psoc *psoc) +{ + uint32_t conn_index = 0, vdev_id = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return conn_index; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use) { + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + policy_mgr_debug("Use vdev_id:%d for opportunistic upgrade", + vdev_id); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (conn_index == MAX_NUMBER_OF_CONC_CONNECTIONS) { + vdev = wlan_objmgr_pdev_get_first_vdev(pm_ctx->pdev, + WLAN_POLICY_MGR_ID); + if (vdev) { + vdev_id = wlan_vdev_get_id(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + policy_mgr_debug("Use default vdev_id:%d for opportunistic upgrade", + vdev_id); + } + + return vdev_id; +} + +/** + * pm_dbs_opportunistic_timer_handler() - handler of + * dbs_opportunistic_timer + * @data: context + * + * handler for dbs_opportunistic_timer + * + * Return: None + */ +void pm_dbs_opportunistic_timer_handler(void *data) +{ + enum policy_mgr_conc_next_action action = PM_NOP; + uint32_t session_id; + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data; + enum policy_mgr_conn_update_reason reason = + POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC; + struct policy_mgr_psoc_priv_obj *pm_ctx = policy_mgr_get_context(psoc); + + if (!psoc) { + policy_mgr_err("Invalid Context"); + return; + } + + /* if we still need it */ + action = policy_mgr_need_opportunistic_upgrade(psoc, &reason); + policy_mgr_debug("action:%d", action); + if (!action) { + return; + } else if (pm_ctx->hdd_cbacks.hdd_is_cac_in_progress && + pm_ctx->hdd_cbacks.hdd_is_cac_in_progress()) { + policy_mgr_debug("SAP is in CAC_IN_PROGRESS state, restarting"); + policy_mgr_restart_opportunistic_timer(psoc, false); + return; + } + session_id = pm_get_vdev_id_of_first_conn_idx(psoc); + policy_mgr_next_actions(psoc, session_id, action, + reason, POLICY_MGR_DEF_REQ_ID); +} + +uint32_t policy_mgr_get_connection_for_vdev_id(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return conn_index; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) && + pm_conc_connection_list[conn_index].in_use) { + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return conn_index; +} + +/** + * policy_mgr_get_bw() - Get channel bandwidth type used by WMI + * @chan_width: channel bandwidth type defined by host + * + * Get the channel bandwidth type used by WMI + * + * Return: hw_mode_bandwidth + */ +enum hw_mode_bandwidth policy_mgr_get_bw(enum phy_ch_width chan_width) +{ + enum hw_mode_bandwidth bw = HW_MODE_BW_NONE; + + switch (chan_width) { + case CH_WIDTH_20MHZ: + bw = HW_MODE_20_MHZ; + break; + case CH_WIDTH_40MHZ: + bw = HW_MODE_40_MHZ; + break; + case CH_WIDTH_80MHZ: + bw = HW_MODE_80_MHZ; + break; + case CH_WIDTH_160MHZ: + bw = HW_MODE_160_MHZ; + break; + case CH_WIDTH_80P80MHZ: + bw = HW_MODE_80_PLUS_80_MHZ; + break; + case CH_WIDTH_5MHZ: + bw = HW_MODE_5_MHZ; + break; + case CH_WIDTH_10MHZ: + bw = HW_MODE_10_MHZ; + break; + case CH_WIDTH_320MHZ: + bw = HW_MODE_320_MHZ; + break; + default: + policy_mgr_err("Unknown channel BW type %d", chan_width); + break; + } + + return bw; +} + +enum phy_ch_width policy_mgr_get_ch_width(enum hw_mode_bandwidth bw) +{ + enum phy_ch_width ch_width = CH_WIDTH_INVALID; + + switch (bw) { + case HW_MODE_20_MHZ: + ch_width = CH_WIDTH_20MHZ; + break; + case HW_MODE_40_MHZ: + ch_width = CH_WIDTH_40MHZ; + break; + case HW_MODE_80_MHZ: + ch_width = CH_WIDTH_80MHZ; + break; + case HW_MODE_160_MHZ: + ch_width = CH_WIDTH_160MHZ; + break; + case HW_MODE_80_PLUS_80_MHZ: + ch_width = CH_WIDTH_80P80MHZ; + break; + case HW_MODE_5_MHZ: + ch_width = CH_WIDTH_5MHZ; + break; + case HW_MODE_10_MHZ: + ch_width = CH_WIDTH_10MHZ; + break; + case HW_MODE_320_MHZ: + ch_width = CH_WIDTH_320MHZ; + break; + default: + policy_mgr_err("Invalid phy_ch_width type %d", ch_width); + break; + } + + return ch_width; +} + +static bool +is_preset_in_chlist(uint32_t chan_freq, const uint32_t *chlist, + uint32_t chlist_len) +{ + uint32_t i; + + for (i = 0; i < chlist_len; i++) + if (chlist[i] == chan_freq) + return true; + + return false; +} + +static void +get_sbs_chlist(struct wlan_objmgr_psoc *psoc, + uint32_t *sbs_freqs, uint32_t *sbs_num, uint32_t chan_freq, + const uint32_t *chlist1, uint32_t chlist1_len, + const uint32_t *chlist2, uint32_t chlist2_len) +{ + uint32_t size_of_sbs = *sbs_num; + uint32_t i; + + *sbs_num = 0; + for (i = 0; i < chlist1_len; i++) { + if (*sbs_num >= size_of_sbs) + return; + if (policy_mgr_are_sbs_chan(psoc, chan_freq, chlist1[i])) + sbs_freqs[(*sbs_num)++] = chlist1[i]; + } + for (i = 0; i < chlist2_len; i++) { + if (*sbs_num >= size_of_sbs) + return; + if (policy_mgr_are_sbs_chan(psoc, chan_freq, chlist2[i])) + sbs_freqs[(*sbs_num)++] = chlist2[i]; + } +} + +static void +get_rest_chlist(uint32_t *rest_freqs, uint32_t *rest_num, + uint32_t *scc_freqs, uint32_t scc_num, + uint32_t *sbs_freqs, uint32_t sbs_num, + const uint32_t *chlist1, uint32_t chlist1_len, + const uint32_t *chlist2, uint32_t chlist2_len) +{ + uint32_t size_of_rest = *rest_num; + uint32_t i; + + *rest_num = 0; + for (i = 0; i < chlist1_len; i++) { + if (*rest_num >= size_of_rest) + return; + if (is_preset_in_chlist(chlist1[i], scc_freqs, scc_num) || + is_preset_in_chlist(chlist1[i], sbs_freqs, sbs_num)) + continue; + rest_freqs[(*rest_num)++] = chlist1[i]; + } + for (i = 0; i < chlist2_len; i++) { + if (*rest_num >= size_of_rest) + return; + if (is_preset_in_chlist(chlist2[i], scc_freqs, scc_num) || + is_preset_in_chlist(chlist2[i], sbs_freqs, sbs_num)) + continue; + rest_freqs[(*rest_num)++] = chlist2[i]; + } +} + +static void +get_sub_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *sbs_freqs, uint32_t *sbs_num, + uint32_t *scc_freqs, uint32_t *scc_num, + uint32_t *rest_freqs, uint32_t *rest_num, + const uint32_t *chlist_5g, uint32_t chlist_5g_len, + const uint32_t *chlist_6g, uint32_t chlist_6g_len) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i = 0; + const uint32_t *chlist1; + uint8_t chlist1_len; + const uint32_t *chlist2; + uint8_t chlist2_len; + uint32_t size_of_scc = *scc_num; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + *scc_num = 0; + *sbs_num = 0; + *rest_num = 0; + return; + } + + if (pm_ctx->cfg.pcl_band_priority == POLICY_MGR_PCL_BAND_6G_THEN_5G) { + chlist1 = chlist_6g; + chlist1_len = chlist_6g_len; + chlist2 = chlist_5g; + chlist2_len = chlist_5g_len; + } else { + chlist1 = chlist_5g; + chlist1_len = chlist_5g_len; + chlist2 = chlist_6g; + chlist2_len = chlist_6g_len; + } + *scc_num = 0; + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* For SCC channels, 6G first then 5G */ + i = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(i)) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ( + pm_conc_connection_list[i].freq)) { + if (*scc_num < size_of_scc && + !is_preset_in_chlist( + pm_conc_connection_list[i].freq, + scc_freqs, *scc_num)) + scc_freqs[(*scc_num)++] = + pm_conc_connection_list[i].freq; + } + i++; + } + i = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(i)) { + if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[i].freq)) { + if (*scc_num < size_of_scc && + !is_preset_in_chlist( + pm_conc_connection_list[i].freq, + scc_freqs, *scc_num)) + scc_freqs[(*scc_num)++] = + pm_conc_connection_list[i].freq; + } + i++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* + * scc_num is number of existing 5Ghz or 6Ghz connection freqs. + * So check if they are all on same mac in SBS, to get SBS + * freq list. + * + * For scc_num > 2, it will always be with freq across + * both mac, as all 3 cannot be on same mac. + * + * For scc_num == 0, i.e no freq on 5/6Ghz there is no need to + * check for SBS freq. + * + * So check only if scc_num == 1 or 2, with both freq + * on same mac in SBS mode (non-SBS) in case of 2. + * + * sbs_num contains the max number of freq element can be saved in + * sbs_freqs array when this function is called. + * It will contain actual freq element number in the array on return. + * Clear it to 0 if no sbs freq is populated by get_sbs_chlist. + */ + if (policy_mgr_is_hw_sbs_capable(psoc) && + (*scc_num == 1 || + (*scc_num == 2 && + !policy_mgr_are_sbs_chan(psoc, scc_freqs[0], + scc_freqs[1])))) + get_sbs_chlist(psoc, sbs_freqs, sbs_num, scc_freqs[0], + chlist1, chlist1_len, chlist2, chlist2_len); + else + *sbs_num = 0; + + get_rest_chlist(rest_freqs, rest_num, scc_freqs, *scc_num, + sbs_freqs, *sbs_num, chlist1, chlist1_len, + chlist2, chlist2_len); +} + +/** + * add_sbs_chlist_to_pcl() - add sbs channel list in pcl + * + * @psoc: psoc object + * @pcl_freqs: pcl frequencies + * @pcl_weights: pcl weight + * @pcl_sz: pcl size + * @index: pcl index + * @skip_6gh_channel: to skip 6g channels or not + * @chlist_5: 5g channel list + * @chlist_len_5: 5g channel list length + * @chlist_6: 6g channel list + * @chlist_len_6: 6g channel list length + * @order: pcl order + * @high_5_band_scc_present: 5 GHz high band connection present + * @low_5_band_scc_present: 5 GHz low band connection present + * + * Get the pcl list based on current sbs concurrency + * + * Return: None + */ +static void +add_sbs_chlist_to_pcl(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_freqs, uint8_t *pcl_weights, + uint32_t pcl_sz, uint32_t *index, + bool skip_6gh_channel, + const uint32_t *chlist_5, uint8_t chlist_len_5, + const uint32_t *chlist_6, uint8_t chlist_len_6, + enum policy_mgr_pcl_channel_order order, + bool *high_5_band_scc_present, + bool *low_5_band_scc_present) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + qdf_freq_t sbs_cut_off_freq; + qdf_freq_t scc_freq = 0; + uint32_t i, conn_index = 0; + struct policy_mgr_conc_connection_info *cl; + + if (!policy_mgr_is_hw_sbs_capable(psoc)) + return; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + if (!sbs_cut_off_freq) { + policy_mgr_err("Invalid cut off freq"); + return; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (order == POLICY_MGR_PCL_ORDER_SCC_5G_LOW_5G_LOW) { + /* Add 5G low SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq < sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + scc_freq = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP1_PCL_CHANNELS; + (*index)++; + *low_5_band_scc_present = true; + break; + } + + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + /* Add rest 5G low channels*/ + for (i = 0; i < chlist_len_5 && *index < pcl_sz; i++) { + if (chlist_5[i] > sbs_cut_off_freq) + return; + + /* SCC channel is already added in pcl freq*/ + if (scc_freq == chlist_5[i]) + continue; + + pcl_freqs[*index] = chlist_5[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + for (i = 0; i < chlist_len_6 && *index < pcl_sz && + !skip_6gh_channel; i++) { + if (chlist_6[i] > sbs_cut_off_freq) + return; + + /* SCC channel is already added in pcl freq*/ + if (scc_freq == chlist_6[i]) + continue; + + pcl_freqs[*index] = chlist_6[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + } else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH || + order == + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW) { + /* Add 5G high SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq > sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + scc_freq = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP1_PCL_CHANNELS; + (*index)++; + *high_5_band_scc_present = true; + break; + } + + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + /* Add rest 5G high channels*/ + for (i = 0; i < chlist_len_5 && *index < pcl_sz; i++) { + if (chlist_5[i] < sbs_cut_off_freq) + continue; + /* SCC channel is already added in pcl freq*/ + if (scc_freq == chlist_5[i]) + continue; + + pcl_freqs[*index] = chlist_5[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + for (i = 0; i < chlist_len_6 && *index < pcl_sz && + !skip_6gh_channel; i++) { + if (chlist_6[i] < sbs_cut_off_freq) + return; + + /* SCC channel is already added in pcl freq*/ + if (scc_freq == chlist_6[i]) + continue; + + pcl_freqs[*index] = chlist_6[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + if (order == + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW) { + conn_index = 0; + /* Add 5G low SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq < sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP3_PCL_CHANNELS; + (*index)++; + break; + } + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } + } else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_LOW) { + /* Add 5 GHz low SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq < sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP1_PCL_CHANNELS; + (*index)++; + *low_5_band_scc_present = true; + break; + } + + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_HIGH) { + /* Add 5 GHz high SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq > sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP1_PCL_CHANNELS; + (*index)++; + *high_5_band_scc_present = true; + break; + } + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + } else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH) { + /* Add 5 GHz low SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq < sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP1_PCL_CHANNELS; + (*index)++; + *low_5_band_scc_present = true; + break; + } + + conn_index++; + } + + /* Add 5 GHz high MCC channels*/ + for (i = 0; i < chlist_len_5 && *index < pcl_sz; i++) { + /* Skip 5 GHz low frequencies */ + if (chlist_5[i] < sbs_cut_off_freq) + continue; + + conn_index = 0; + /* Skip SCC channels */ + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (cl[conn_index].freq == chlist_5[i]) + break; + conn_index++; + } + + if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) + continue; + pcl_freqs[*index] = chlist_5[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + for (i = 0; i < chlist_len_6 && *index < pcl_sz && + !skip_6gh_channel; i++) { + if (chlist_6[i] < sbs_cut_off_freq) + return; + + conn_index = 0; + /* Skip SCC channels */ + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (cl[conn_index].freq == chlist_6[i]) + break; + conn_index++; + } + + if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) + continue; + + pcl_freqs[*index] = chlist_6[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } else if (order == POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_MCC_5G_LOW) { + /* Add 5 GHz high SCC channel*/ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + cl[conn_index].freq > sbs_cut_off_freq) { + pcl_freqs[*index] = cl[conn_index].freq; + pcl_weights[*index] = + WEIGHT_OF_GROUP1_PCL_CHANNELS; + (*index)++; + *high_5_band_scc_present = true; + break; + } + + conn_index++; + } + + /* Add 5 GHz low MCC channels */ + for (i = 0; i < chlist_len_5 && *index < pcl_sz; i++) { + /* Skip 5 GHz high frequencies */ + if (chlist_5[i] > sbs_cut_off_freq) + continue; + + conn_index = 0; + /* Skip SCC channels */ + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (cl[conn_index].freq == chlist_5[i]) + break; + conn_index++; + } + + if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) + continue; + pcl_freqs[*index] = chlist_5[i]; + pcl_weights[*index] = WEIGHT_OF_GROUP2_PCL_CHANNELS; + (*index)++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } else { + policy_mgr_debug("invalid order %d", order); + return; + } + + policy_mgr_debug("new pcl index %d", *index); + +} + +static void +add_chlist_to_pcl(struct wlan_objmgr_pdev *pdev, + uint32_t *pcl_freqs, uint8_t *pcl_weights, + uint32_t pcl_sz, uint32_t *index, uint32_t weight, + const uint32_t *chlist, uint8_t chlist_len, + bool skip_6gh_channel) +{ + uint32_t i; + + for (i = 0; i < chlist_len && *index < pcl_sz; i++) { + if (skip_6gh_channel && + WLAN_REG_IS_6GHZ_CHAN_FREQ(chlist[i])) + continue; + pcl_freqs[*index] = chlist[i]; + pcl_weights[*index] = weight; + (*index)++; + } + policy_mgr_debug("Add chlist len %d index %d", + chlist_len, *index); +} + +/** + * policy_mgr_get_connection_channels() - provides the channel(s) + * on which current connection(s) is + * @psoc: psoc object + * @mode: conn mode + * @order: no order OR 2.4 Ghz channel followed by 5 Ghz channel OR + * 5 Ghz channel followed by 2.4 Ghz channel + * @skip_dfs_channel: if this flag is true then skip the dfs channel + * @group_id: Next available groups for weight assignment + * @pcl_freqs: Pointer to the frequencies of PCL + * @pcl_weights: Pointer to the weights of PCL + * @pcl_sz: Max length of the PCL list + * @index: Index from which the PCL list needs to be populated, + * will increase accordingly if any channel is obtained + * + * This function provides the channel(s) on which current + * connection(s) is/are + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_get_connection_channels(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + enum policy_mgr_pcl_channel_order order, + bool skip_dfs_channel, + enum policy_mgr_pcl_group_id group_id, + uint32_t *pcl_freqs, uint8_t *pcl_weights, + uint32_t pcl_sz, uint32_t *index) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t conn_index = 0; + uint32_t weight1, weight2; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info *cl; + bool add_6ghz = true; + uint32_t idx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + if (!pcl_freqs || !pcl_weights || !index || !pcl_sz) { + policy_mgr_err("list or index is NULL"); + status = QDF_STATUS_E_INVAL; + return status; + } + + idx = *index; + + /* POLICY_MGR_PCL_GROUP_ID1_ID2 indicates that all three weights are + * available for assignment. i.e., WEIGHT_OF_GROUP1_PCL_CHANNELS, + * WEIGHT_OF_GROUP2_PCL_CHANNELS and WEIGHT_OF_GROUP3_PCL_CHANNELS + * are all available. Since in this function only two weights are + * assigned at max, only group1 and group2 weights are considered. + * + * The other possible group id POLICY_MGR_PCL_GROUP_ID2_ID3 indicates + * group1 was assigned the weight WEIGHT_OF_GROUP1_PCL_CHANNELS and + * only weights WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS are available for further weight + * assignments. + * + * e.g., when order is POLICY_MGR_PCL_ORDER_24G_THEN_5G and group id is + * POLICY_MGR_PCL_GROUP_ID2_ID3, WEIGHT_OF_GROUP2_PCL_CHANNELS is + * assigned to 2.4GHz channels and the weight + * WEIGHT_OF_GROUP3_PCL_CHANNELS is assigned to the 5GHz channels. + */ + if (group_id == POLICY_MGR_PCL_GROUP_ID1_ID2) { + weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + } else if (group_id == POLICY_MGR_PCL_GROUP_ID2_ID3) { + weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + } else { + weight1 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP4_PCL_CHANNELS; + } + if (!policy_mgr_is_6ghz_conc_mode_supported(psoc, mode)) + add_6ghz = false; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + cl = pm_conc_connection_list; + if (POLICY_MGR_PCL_ORDER_NONE == order) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + bool is_6ghz_ch = WLAN_REG_IS_6GHZ_CHAN_FREQ( + cl[conn_index].freq); + if (skip_dfs_channel && wlan_reg_is_dfs_for_freq( + pm_ctx->pdev, cl[conn_index].freq)) { + conn_index++; + } else if ((idx < pcl_sz) && + (!is_6ghz_ch || add_6ghz)) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight1; + idx++; + } else { + conn_index++; + } + } + } else if (POLICY_MGR_PCL_ORDER_24G_THEN_5G == order) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + idx < pcl_sz) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight1; + idx++; + } else { + conn_index++; + } + } + + conn_index = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && + wlan_reg_is_dfs_for_freq(pm_ctx->pdev, + cl[conn_index].freq)) { + conn_index++; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + cl[conn_index].freq) && + (idx < pcl_sz)) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight2; + idx++; + } else { + conn_index++; + } + } + conn_index = 0; + while (add_6ghz && + PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + bool is_6ghz_ch = WLAN_REG_IS_6GHZ_CHAN_FREQ( + cl[conn_index].freq); + if (is_6ghz_ch && idx < pcl_sz) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight2; + idx++; + } else { + conn_index++; + } + } + } else if (POLICY_MGR_PCL_ORDER_5G_THEN_2G == order) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && + wlan_reg_is_dfs_for_freq( + pm_ctx->pdev, cl[conn_index].freq)) { + conn_index++; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + cl[conn_index].freq) && + (idx < pcl_sz)) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight1; + idx++; + } else { + conn_index++; + } + } + conn_index = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + idx < pcl_sz) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight2; + idx++; + + } else { + conn_index++; + } + } + conn_index = 0; + while (add_6ghz && + PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + bool is_6ghz_ch = WLAN_REG_IS_6GHZ_CHAN_FREQ( + cl[conn_index].freq); + if (is_6ghz_ch && idx < pcl_sz) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight2; + idx++; + } else { + conn_index++; + } + } + } else if (order == POLICY_MGR_PCL_ORDER_2G) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(cl[conn_index].freq) && + idx < pcl_sz) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight1; + idx++; + + } else { + conn_index++; + } + } + } else if (order == POLICY_MGR_PCL_ORDER_5G) { + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (skip_dfs_channel && + wlan_reg_is_dfs_for_freq(pm_ctx->pdev, + cl[conn_index].freq)) { + conn_index++; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + cl[conn_index].freq) && + (idx < pcl_sz)) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight1; + idx++; + } else { + conn_index++; + } + } + conn_index = 0; + while (add_6ghz && + PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + bool is_6ghz_ch = WLAN_REG_IS_6GHZ_CHAN_FREQ( + cl[conn_index].freq); + if (is_6ghz_ch && idx < pcl_sz) { + pcl_freqs[idx] = cl[conn_index++].freq; + pcl_weights[idx] = weight1; + idx++; + } else { + conn_index++; + } + } + } else { + policy_mgr_err("unknown order %d", order); + status = QDF_STATUS_E_FAILURE; + } + + *index = idx; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +/** + * policy_mgr_set_weight_of_disabled_inactive_channels_to_zero() - set weight + * of disabled and inactive channels to 0 + * @psoc: pointer to soc + * @pcl_channels: preferred channel freq list + * @len: length of preferred channel list + * @weight_list: preferred channel weight list + * @weight_len: length of weight list + * This function set the weight of disabled and inactive channels to 0 + * + * Return: None + */ +void policy_mgr_set_weight_of_disabled_inactive_channels_to_zero( + struct wlan_objmgr_psoc *psoc, uint32_t *pcl_channels, + uint32_t *len, uint8_t *weight_list, uint32_t weight_len) +{ + uint8_t i; + uint32_t orig_channel_count = 0; + enum channel_state channel_state; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (len) + orig_channel_count = QDF_MIN(*len, NUM_CHANNELS); + else { + policy_mgr_err("invalid number of channel length"); + return; + } + + policy_mgr_debug("Set weight of disabled, inactive channels to 0"); + + for (i = 0; i < orig_channel_count; i++) { + if (wlan_reg_is_6ghz_chan_freq(pcl_channels[i]) && + !wlan_reg_is_6ghz_band_set(pm_ctx->pdev)) { + weight_list[i] = 0; + } else { + channel_state = wlan_reg_get_channel_state_for_pwrmode( + pm_ctx->pdev, pcl_channels[i], + REG_CURRENT_PWR_MODE); + if (channel_state == CHANNEL_STATE_DISABLE || + channel_state == CHANNEL_STATE_INVALID) + weight_list[i] = 0; + } + } + + return; +} + +static bool is_freq_present_in_pcl(uint32_t idx, uint32_t *pcl_freqs, + uint32_t chanlist_freq) +{ + uint32_t i; + + for (i = 0; i < idx; i++) { + if (pcl_freqs[i] == chanlist_freq) + return true; + } + + return false; +} + +/** + * policy_mgr_add_5g_to_pcl() - add the 5G/6G channels into PCL + * @psoc: psoc object + * @pcl_freqs: Pointer to the frequencies of PCL + * @pcl_weights: Pointer to the weights of PCL + * @pcl_sz: Max length of the PCL list + * @index: Index from which the PCL list needs to be populated, + * will increase accordingly if any channel is obtained + * @group_id: Next available groups for weight assignment + * @chlist_5g: Pointer to the 5G channel list + * @chlist_5g_len: Length of the 5G channel list + * @chlist_6g: Pointer to the 6G channel list + * @chlist_6g_len: Length of the 6G channel list + * + * Return: None + */ +static void +policy_mgr_add_5g_to_pcl(struct wlan_objmgr_psoc *psoc, uint32_t *pcl_freqs, + uint8_t *pcl_weights, uint32_t pcl_sz, uint32_t *index, + enum policy_mgr_pcl_group_id group_id, + const uint32_t *chlist_5g, uint8_t chlist_5g_len, + const uint32_t *chlist_6g, uint8_t chlist_6g_len) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t weight1, weight2; + const uint32_t *chlist1; + uint8_t chlist1_len; + uint8_t list_len = 0; + const uint32_t *chlist2; + uint8_t chlist2_len; + uint32_t i; + uint32_t len = 0, idx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + idx = *index; + + if (group_id == POLICY_MGR_PCL_GROUP_ID1_ID2) { + weight1 = WEIGHT_OF_GROUP1_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + } else if (group_id == POLICY_MGR_PCL_GROUP_ID2_ID3) { + weight1 = WEIGHT_OF_GROUP2_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + } else { + weight1 = WEIGHT_OF_GROUP3_PCL_CHANNELS; + weight2 = WEIGHT_OF_GROUP4_PCL_CHANNELS; + } + if (pm_ctx->cfg.pcl_band_priority == POLICY_MGR_PCL_BAND_6G_THEN_5G) { + chlist1 = chlist_6g; + chlist1_len = chlist_6g_len; + chlist2 = chlist_5g; + chlist2_len = chlist_5g_len; + } else { + chlist1 = chlist_5g; + chlist1_len = chlist_5g_len; + chlist2 = chlist_6g; + chlist2_len = chlist_6g_len; + } + if ((chlist1_len + idx) > pcl_sz) { + policy_mgr_err("no enough weight len %d chlist1_len %d %d", + pcl_sz, chlist1_len, idx); + return; + } + for (i = 0; i < chlist1_len; i++) { + if (is_freq_present_in_pcl(idx, pcl_freqs, chlist1[i])) + continue; + pcl_freqs[idx] = chlist1[i]; + pcl_weights[idx] = weight1; + idx++; + list_len++; + } + + len += list_len; + + if ((chlist2_len + idx) > pcl_sz) { + policy_mgr_err("no enough weight len chlist2_len %d %d %d", + pcl_sz, chlist2_len, idx); + return; + } + list_len = 0; + for (i = 0; i < chlist2_len; i++) { + if (is_freq_present_in_pcl(idx, pcl_freqs, chlist2[i])) + continue; + pcl_freqs[idx] = chlist2[i]; + pcl_weights[idx] = weight2; + idx++; + list_len++; + } + len += list_len; + + *index = idx; + policy_mgr_debug("Add 5g chlist len %d 6g chlist len %d len %d index %d order %d", + chlist_5g_len, chlist_6g_len, len, idx, + pm_ctx->cfg.pcl_band_priority); +} + +/** + * policy_mgr_add_24g_to_pcl() - add the 2.4G channels into PCL + * @pcl_freqs: Pointer to the frequencies of PCL + * @pcl_weights: Pointer to the weights of PCL + * @pcl_sz: Max length of the PCL list + * @index: Index from which the PCL list needs to be populated, + * will increase accordingly if any channel is obtained + * @weight: group for weight assignment + * @chlist_24g: Pointer to the 2.4G channel list + * @chlist_24g_len: Length of the 2.4G channel list + * + * Return: None + */ +static void +policy_mgr_add_24g_to_pcl(uint32_t *pcl_freqs, uint8_t *pcl_weights, + uint32_t pcl_sz, uint32_t *index, uint32_t weight, + const uint32_t *chlist_24g, uint8_t chlist_24g_len) +{ + uint32_t num_to_add, i; + + if (*index >= NUM_CHANNELS || *index >= pcl_sz) + return; + num_to_add = QDF_MIN((*index + chlist_24g_len), pcl_sz) - *index; + for (i = 0; i < num_to_add; i++) { + if ((i + *index) >= NUM_CHANNELS || (i + *index) >= pcl_sz) + break; + pcl_weights[i + *index] = weight; + pcl_freqs[i + *index] = chlist_24g[i]; + } + + *index += i; + policy_mgr_debug("Add 24g chlist len %d len %d index %d", + chlist_24g_len, num_to_add, *index); +} + +static bool +policy_mgr_2ghz_connection_present(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + bool is_2ghz_present = false; + uint32_t conn_index; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use && + (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[conn_index].freq))) { + is_2ghz_present = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return is_2ghz_present; +} + +/** + * policy_mgr_get_channel_list() - provides the channel list + * suggestion for new connection + * @psoc: psoc handle + * @pcl: The preferred channel list enum + * @mode: concurrency mode for which channel list is requested + * @pcl_channels: PCL channels + * @pcl_weights: Weights of the PCL + * @pcl_sz: Max length of the PCL list + * @len: length of the PCL obtained + * + * This function provides the actual channel list based on the + * current regulatory domain derived using preferred channel + * list enum obtained from one of the pcl_table + * + * Return: Channel List + */ +QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_pcl_type pcl, + enum policy_mgr_con_mode mode, + uint32_t *pcl_channels, + uint8_t *pcl_weights, + uint32_t pcl_sz, uint32_t *len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t num_channels = 0; + uint32_t chan_index_24 = 0, chan_index_5 = 0, chan_index_6 = 0; + uint32_t i = 0; + bool skip_6ghz_channel = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t *channel_list, *channel_list_24, *channel_list_5, + *sbs_freqs, *channel_list_6, *scc_freqs, *rest_freqs; + uint32_t sbs_num, scc_num, rest_num; + bool high_5_band_scc_present = false; + bool low_5_band_scc_present = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + if ((!pcl_channels) || (!len)) { + policy_mgr_err("pcl_channels or len is NULL"); + return status; + } + + *len = 0; + if (PM_MAX_PCL_TYPE == pcl) { + /* msg */ + policy_mgr_err("pcl is invalid"); + return status; + } + + if (PM_NONE == pcl) { + /* msg */ + policy_mgr_debug("pcl is 0"); + return QDF_STATUS_SUCCESS; + } + + channel_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + channel_list_24 = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + channel_list_5 = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + sbs_freqs = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + channel_list_6 = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + rest_freqs = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + scc_freqs = qdf_mem_malloc( + MAX_NUMBER_OF_CONC_CONNECTIONS * sizeof(uint32_t)); + if (!channel_list || !channel_list_24 || !channel_list_5 || + !sbs_freqs || !channel_list_6 || !rest_freqs || !scc_freqs) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + /* get the channel list for current domain */ + status = policy_mgr_get_valid_chans(psoc, channel_list, + &num_channels); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Error in getting valid channels"); + goto end; + } + + num_channels = QDF_MIN(num_channels, NUM_CHANNELS); + + /* Let's divide the list in 2.4 & 5 Ghz lists */ + for (i = 0; i < num_channels; i++) { + if (wlan_reg_is_24ghz_ch_freq(channel_list[i])) { + channel_list_24[chan_index_24++] = channel_list[i]; + } else if (wlan_reg_is_5ghz_ch_freq(channel_list[i])) { + channel_list_5[chan_index_5++] = channel_list[i]; + } else if (wlan_reg_is_6ghz_chan_freq(channel_list[i])) { + /* Add to 5G list until 6G conc support is enabled */ + channel_list_6[chan_index_6++] = channel_list[i]; + } + } + if (!policy_mgr_is_6ghz_conc_mode_supported(psoc, mode)) { + chan_index_6 = 0; + skip_6ghz_channel = true; + } + sbs_num = NUM_CHANNELS; + scc_num = MAX_NUMBER_OF_CONC_CONNECTIONS; + rest_num = NUM_CHANNELS; + + /* In the below switch case, the channel list is populated based on the + * pcl. e.g., if the pcl is PM_SCC_CH_24G, the SCC channel group is + * populated first followed by the 2.4GHz channel group. Along with + * this, the weights are also populated in the same order for each of + * these groups. There are three weight groups: + * WEIGHT_OF_GROUP1_PCL_CHANNELS, WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS. + * + * e.g., if pcl is PM_SCC_ON_5_SCC_ON_24_24G: scc on 5GHz (group1) + * channels take the weight WEIGHT_OF_GROUP1_PCL_CHANNELS, scc on 2.4GHz + * (group2) channels take the weight WEIGHT_OF_GROUP2_PCL_CHANNELS and + * 2.4GHz (group3) channels take the weight + * WEIGHT_OF_GROUP3_PCL_CHANNELS. + * + * When the weight to be assigned to the group is known along with the + * number of channels, the weights are directly assigned to the + * pcl_weights list. But, the channel list is populated using + * policy_mgr_get_connection_channels(), the order of weights to be used + * is passed as an argument to the function + * policy_mgr_get_connection_channels() using + * 'enum policy_mgr_pcl_group_id' which indicates the next available + * weights to be used and policy_mgr_get_connection_channels() will take + * care of the weight assignments. + * + * e.g., 'enum policy_mgr_pcl_group_id' value of + * POLICY_MGR_PCL_GROUP_ID2_ID3 indicates that the next available groups + * for weight assignment are WEIGHT_OF_GROUP2_PCL_CHANNELS and + * WEIGHT_OF_GROUP3_PCL_CHANNELS and that the + * weight WEIGHT_OF_GROUP1_PCL_CHANNELS was already allocated. + * So, in the same example, when order is + * POLICY_MGR_PCL_ORDER_24G_THEN_5G, + * policy_mgr_get_connection_channels() will assign the weight + * WEIGHT_OF_GROUP2_PCL_CHANNELS to 2.4GHz channels and assign the + * weight WEIGHT_OF_GROUP3_PCL_CHANNELS to 5GHz channels. + */ + switch (pcl) { + case PM_24G: + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_5G: + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID1_ID2, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH: + case PM_MCC_CH: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_NONE, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH_24G: + case PM_MCC_CH_24G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_NONE, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH_5G: + case PM_MCC_CH_5G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_NONE, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID2_ID3, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SCC_CH: + case PM_24G_MCC_CH: + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24); + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_NONE, + false, + POLICY_MGR_PCL_GROUP_ID2_ID3, + pcl_channels, pcl_weights, + pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + case PM_5G_SCC_CH: + case PM_5G_MCC_CH: + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID1_ID2, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_NONE, + false, + POLICY_MGR_PCL_GROUP_ID3_ID4, + pcl_channels, pcl_weights, + pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_SCC_ON_5: + policy_mgr_get_connection_channels( + psoc, mode, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_SCC_ON_24: + policy_mgr_get_connection_channels( + psoc, mode, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_SCC_ON_5_24G: + policy_mgr_get_connection_channels( + psoc, mode, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, pcl_sz, len); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_SCC_ON_5_5G: + policy_mgr_get_connection_channels( + psoc, mode, + POLICY_MGR_PCL_ORDER_24G_THEN_5G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, pcl_sz, len); + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID3_ID4, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24_CH_24G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_2G, + true, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_CH_5G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_5G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID2_ID3, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_SCC_ON_24_24G: + policy_mgr_get_connection_channels( + psoc, mode, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, pcl_sz, len); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_SCC_ON_24_5G: + policy_mgr_get_connection_channels( + psoc, mode, + POLICY_MGR_PCL_ORDER_5G_THEN_2G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, pcl_sz, len); + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID3_ID4, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_5G_24G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_5G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID2_ID3, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5_5G_SCC_ON_24G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_5G, + false, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID2_ID3, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_2G, + false, + POLICY_MGR_PCL_GROUP_ID3_ID4, + pcl_channels, pcl_weights, + pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + + case PM_24G_SCC_CH_SBS_CH: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SCC_CH_SBS_CH_5G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP4_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + status = QDF_STATUS_SUCCESS; + break; + case PM_24G_SBS_CH_MCC_CH: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_5G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_24G_SCC_CH: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_SCC_CH_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH_SBS_CH_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_SCC_CH_5G_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP4_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_CH_MCC_CH_SBS_CH_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + scc_freqs, scc_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP4_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_2G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G: + add_sbs_chlist_to_pcl(psoc, pcl_channels, + pcl_weights, pcl_sz, + len, + skip_6ghz_channel, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW_5G_LOW, + &high_5_band_scc_present, + &low_5_band_scc_present); + + /* + * If no 2.4 GHZ connection is present and If 2.4 GHZ is shared + * with 5 GHz low freq then 2.4 GHz can be added as well. + * If no 5 GHz low band connection, 2.4 GHz can be added. + */ + if ((!policy_mgr_2ghz_connection_present(pm_ctx) || + !low_5_band_scc_present) && + policy_mgr_sbs_24_shared_with_low_5(pm_ctx)) + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G: + case PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G: + add_sbs_chlist_to_pcl(psoc, pcl_channels, + pcl_weights, pcl_sz, + len, + skip_6ghz_channel, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6, + (pcl == PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G) ? + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH : + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH_5G_HIGH_SCC_5G_LOW, + &high_5_band_scc_present, + &low_5_band_scc_present); + /* + * If no 2.4 GHZ connection is present and if 2.4 GHZ is shared + * with 5 GHz High freq then 2.4 GHz can be added as well + * If no 5 GHz high band connection, 2.4 GHz can be added. + */ + if ((!policy_mgr_2ghz_connection_present(pm_ctx) || + !high_5_band_scc_present) && + policy_mgr_sbs_24_shared_with_high_5(pm_ctx)) + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_MCC_CH: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + rest_freqs, rest_num, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_5G_MCC_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP3_PCL_CHANNELS, + channel_list_24, chan_index_24, + false); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_24G: + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_2G, + true, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5G_LOW: + add_sbs_chlist_to_pcl(psoc, pcl_channels, + pcl_weights, pcl_sz, + len, + skip_6ghz_channel, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW, + &high_5_band_scc_present, + &low_5_band_scc_present); + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5G_HIGH: + add_sbs_chlist_to_pcl(psoc, pcl_channels, + pcl_weights, pcl_sz, + len, + skip_6ghz_channel, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6, + POLICY_MGR_PCL_ORDER_SCC_5G_HIGH, + &high_5_band_scc_present, + &low_5_band_scc_present); + status = QDF_STATUS_SUCCESS; + break; + case PM_SBS_CH_MCC_CH_SCC_ON_24_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + sbs_freqs, sbs_num, + skip_6ghz_channel); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_2G, + true, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_5G_24G: + policy_mgr_add_5g_to_pcl(psoc, pcl_channels, pcl_weights, + pcl_sz, len, + POLICY_MGR_PCL_GROUP_ID1_ID2, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + policy_mgr_add_24g_to_pcl(pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP1_PCL_CHANNELS, + channel_list_24, chan_index_24); + status = QDF_STATUS_SUCCESS; + break; + case PM_MCC_CH_SCC_ON_24G: + get_sub_channels(psoc, + sbs_freqs, &sbs_num, + scc_freqs, &scc_num, + rest_freqs, &rest_num, + channel_list_5, chan_index_5, + channel_list_6, chan_index_6); + add_chlist_to_pcl(pm_ctx->pdev, + pcl_channels, pcl_weights, pcl_sz, + len, WEIGHT_OF_GROUP2_PCL_CHANNELS, + rest_freqs, rest_num, + skip_6ghz_channel); + policy_mgr_get_connection_channels(psoc, mode, + POLICY_MGR_PCL_ORDER_2G, + true, + POLICY_MGR_PCL_GROUP_ID1_ID2, + pcl_channels, pcl_weights, + pcl_sz, len); + status = QDF_STATUS_SUCCESS; + break; + + case PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH: + add_sbs_chlist_to_pcl( + psoc, pcl_channels, pcl_weights, pcl_sz, len, + skip_6ghz_channel, channel_list_5, chan_index_5, + channel_list_6, chan_index_6, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH, + &high_5_band_scc_present, + &low_5_band_scc_present); + status = QDF_STATUS_SUCCESS; + break; + status = QDF_STATUS_SUCCESS; + break; + case PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW: + add_sbs_chlist_to_pcl( + psoc, pcl_channels, pcl_weights, pcl_sz, len, + skip_6ghz_channel, channel_list_5, chan_index_5, + channel_list_6, chan_index_6, + POLICY_MGR_PCL_ORDER_SCC_5G_LOW_MCC_5G_HIGH, + &high_5_band_scc_present, + &low_5_band_scc_present); + + status = QDF_STATUS_SUCCESS; + break; + default: + policy_mgr_err("unknown pcl value %d", pcl); + break; + } + + policy_mgr_debug("pcl %s: mode %s", pcl_type_to_string(pcl), + device_mode_to_string(mode)); + policy_mgr_debug("pcl len %d and weight list sz %d", + *len, pcl_sz); + + policy_mgr_set_weight_of_disabled_inactive_channels_to_zero(psoc, + pcl_channels, len, pcl_weights, pcl_sz); + +end: + qdf_mem_free(channel_list); + qdf_mem_free(channel_list_24); + qdf_mem_free(channel_list_5); + qdf_mem_free(sbs_freqs); + qdf_mem_free(channel_list_6); + qdf_mem_free(scc_freqs); + qdf_mem_free(rest_freqs); + + return status; +} + +bool policy_mgr_disallow_mcc(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + uint32_t index = 0; + bool match = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return match; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(index)) { + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + if (pm_conc_connection_list[index].freq != ch_freq) { + match = true; + break; + } + } else if (!WLAN_REG_IS_24GHZ_CH_FREQ + (pm_conc_connection_list[index].freq)) { + if (pm_conc_connection_list[index].freq != ch_freq && + !policy_mgr_are_sbs_chan(psoc, ch_freq, + pm_conc_connection_list[index].freq)) { + match = true; + break; + } + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return match; +} + +/** + * policy_mgr_allow_same_mac_diff_freq() - Check whether diff freq are allowed + * on same mac + * + * @psoc: Pointer to Psoc + * @ch_freq: channel frequency + * + * Check whether diff freq are allowed on same mac + * + * Return: True/False + */ +static +bool policy_mgr_allow_same_mac_diff_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq) +{ + bool allow = true; + + if ((pm_conc_connection_list[0].mode == PM_NAN_DISC_MODE && + pm_conc_connection_list[1].mode == PM_NDI_MODE) || + (pm_conc_connection_list[0].mode == PM_NDI_MODE && + pm_conc_connection_list[1].mode == PM_NAN_DISC_MODE)) { + /* + * NAN + NDI are managed in Firmware by dividing + * up slots. Connection on NDI is re-negotiable + * and therefore a 3rd connection with the + * same MAC is possible. + */ + } else if (!policy_mgr_is_hw_dbs_capable(psoc) && + policy_mgr_is_interband_mcc_supported(psoc)) { + if (ch_freq != pm_conc_connection_list[0].freq && + ch_freq != pm_conc_connection_list[1].freq) { + policy_mgr_rl_debug("don't allow 3rd home channel on same MAC"); + allow = false; + } + } else if (policy_mgr_3_freq_always_on_same_mac(psoc, ch_freq, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + policy_mgr_rl_debug("don't allow 3rd home channel on same MAC"); + allow = false; + } + + return allow; +} + +/** + * policy_mgr_allow_same_mac_same_freq() - check whether given frequency is + * allowed for same mac + * + * @psoc: Pointer to Psoc + * @ch_freq: channel frequency + * @mode: Concurrency Mode + * + * check whether given frequency is allowed for same mac + * + * Return: True/False + */ +static +bool policy_mgr_allow_same_mac_same_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq, + enum policy_mgr_con_mode mode) +{ + bool allow = true; + + if (!policy_mgr_is_hw_dbs_capable(psoc) && + policy_mgr_is_interband_mcc_supported(psoc)) { + policy_mgr_rl_debug("allow 2 intf SCC + new intf ch %d for legacy hw", + ch_freq); + } else if ((pm_conc_connection_list[0].mode == PM_NAN_DISC_MODE && + pm_conc_connection_list[1].mode == PM_NDI_MODE) || + (pm_conc_connection_list[0].mode == PM_NDI_MODE && + pm_conc_connection_list[1].mode == PM_NAN_DISC_MODE)) { + /* + * NAN + NDI are managed in Firmware by dividing + * up slots. Connection on NDI is re-negotiable + * and therefore a 3rd connection with the + * same MAC is possible. + */ + } else if (policy_mgr_2_freq_always_on_same_mac( + psoc, ch_freq, pm_conc_connection_list[0].freq) && + !policy_mgr_is_3rd_conn_on_same_band_allowed( + psoc, mode, ch_freq)) { + policy_mgr_rl_debug("don't allow 3rd home channel on same MAC for sta+multi-AP"); + allow = false; + } + + return allow; +} + +bool policy_mgr_allow_new_home_channel( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, + qdf_freq_t ch_freq, uint32_t num_connections, bool is_dfs_ch, + uint32_t ext_flags) +{ + bool status = true; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool on_same_mac = false, force_switch_without_dis = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + force_switch_without_dis = + policy_mgr_get_mcc_to_scc_switch_mode(psoc) == + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (num_connections == 3) { + status = policy_mgr_allow_4th_new_freq(psoc, + ch_freq, mode, + ext_flags); + } else if (num_connections == 2) { + /* No SCC or MCC combination is allowed with / on DFS channel */ + on_same_mac = policy_mgr_2_freq_always_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq); + if (force_switch_without_dis && is_dfs_ch && + ((pm_conc_connection_list[0].ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)) || + (pm_conc_connection_list[1].ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)))) { + policy_mgr_rl_debug("Existing DFS connection, new 3-port DFS connection is not allowed"); + status = false; + } else if (((pm_conc_connection_list[0].freq != + pm_conc_connection_list[1].freq) || + force_switch_without_dis) && on_same_mac) { + status = policy_mgr_allow_same_mac_diff_freq(psoc, + ch_freq); + } else if (on_same_mac) { + status = policy_mgr_allow_same_mac_same_freq(psoc, + ch_freq, + mode); + } + } else if (num_connections == 1 && force_switch_without_dis && + is_dfs_ch && + (pm_conc_connection_list[0].ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2))) { + policy_mgr_rl_debug("Existing DFS connection, new 2-port DFS connection is not allowed"); + status = false; + } else if ((num_connections == 1) && + !policy_mgr_is_hw_dbs_capable(psoc) && + !policy_mgr_is_interband_mcc_supported(psoc)) { + /* For target which is single mac and doesn't support + * interband MCC + */ + if ((pm_conc_connection_list[0].mode != PM_NAN_DISC_MODE) && + (mode != PM_NAN_DISC_MODE)) + status = policy_mgr_2_freq_always_on_same_mac(psoc, + ch_freq, + pm_conc_connection_list[0].freq); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +bool policy_mgr_is_5g_channel_allowed(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, uint32_t *list, + enum policy_mgr_con_mode mode) +{ + uint32_t index = 0, count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + count = policy_mgr_mode_specific_connection_count(psoc, mode, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (index < count) { + if ((pm_conc_connection_list[list[index]].ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)) && + WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && + (ch_freq != pm_conc_connection_list[list[index]].freq && + !policy_mgr_are_sbs_chan(psoc, ch_freq, + pm_conc_connection_list[list[index]].freq))) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_rl_debug("don't allow MCC if SAP/GO on DFS channel"); + return false; + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return true; +} + +/** + * policy_mgr_get_pref_force_scc_freq() - Get preferred force SCC + * channel frequency + * @psoc: Pointer to Psoc + * @vdev_id: vdev id + * @intf_ch_freq: prefer force scc frequency + * @sap_ch_freq: sap/go channel starting channel frequency + * @acs_band: acs band + * @allow_6ghz: allow 6 Ghz channel or not + * + * This API will consider protocol 6ghz allow flag - allow_6ghz. + * Also for regdomain, it will consider PCL allow or not. + * For example, if STA is on 6ghz LPI mode, SAP is not allowed + * force scc to 6ghz, see API + * policy_mgr_modify_sap_pcl_for_6G_channels. + * + * Return: QDF_STATUS_SUCCESS if get preferred force scc channel. + */ +static QDF_STATUS +policy_mgr_get_pref_force_scc_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + qdf_freq_t *intf_ch_freq, + qdf_freq_t sap_ch_freq, + uint32_t acs_band, + bool allow_6ghz) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_con_mode mode; + QDF_STATUS status; + uint32_t i; + struct policy_mgr_pcl_list pcl; + bool allow_2ghz_only = false; + qdf_freq_t scc_ch_freq_on_same_mac = 0; + qdf_freq_t scc_ch_freq_on_diff_mac = 0; + qdf_freq_t scc_ch_freq_same_as_sap = 0; + qdf_freq_t non_scc_ch_freq_on_same_mac = 0; + qdf_freq_t non_scc_ch_freq_on_diff_mac = 0; + qdf_freq_t non_scc_ch_freq_same_as_sap = 0; + enum QDF_OPMODE op_mode; + qdf_freq_t pcl_freq; + bool same_mac, sbs_ml_sta_present = false, dbs_ml_sta_present = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + if (policy_mgr_is_mlo_in_mode_dbs(psoc, PM_STA_MODE, NULL, NULL)) + dbs_ml_sta_present = true; + else if (policy_mgr_is_mlo_in_mode_sbs(psoc, PM_STA_MODE, NULL, NULL)) + sbs_ml_sta_present = true; + + op_mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, vdev_id); + + qdf_mem_zero(&pcl, sizeof(pcl)); + status = policy_mgr_get_pcl(psoc, mode, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), + vdev_id); + if (QDF_IS_STATUS_ERROR(status) || !pcl.pcl_len) { + policy_mgr_err("get pcl failed for mode: %d, pcl len %d", mode, + pcl.pcl_len); + return QDF_STATUS_E_INVAL; + } + + if ((acs_band == QCA_ACS_MODE_IEEE80211B || + acs_band == QCA_ACS_MODE_IEEE80211G) && + WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq)) + allow_2ghz_only = true; + + /* + * The preferred force SCC channel is SAP original channel, + * and then the SCC channel on the same mac, and then the SCC + * channel on the different mac. + * Make sure the PCL only contains valid channels - not + * causing 3 vif on same mac. + * If none of channels are available, we have to keep SAP channel + * unchanged, and that may cause SAP MCC. + */ + for (i = 0; i < pcl.pcl_len; i++) { + pcl_freq = pcl.pcl_list[i]; + + if (!allow_6ghz && WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl_freq)) + continue; + if (allow_2ghz_only && !WLAN_REG_IS_24GHZ_CH_FREQ(pcl_freq)) + continue; + + /* + * If ML STA is present, as ML STA cannot be on same mac, + * check same band logic as per the ML hw mode, else + * use the API which is hw mode agnostic. + */ + if (dbs_ml_sta_present) + same_mac = policy_mgr_2_freq_same_mac_in_dbs(pm_ctx, + sap_ch_freq, + pcl_freq); + else if (sbs_ml_sta_present) + same_mac = policy_mgr_2_freq_same_mac_in_sbs(pm_ctx, + sap_ch_freq, + pcl_freq); + else + same_mac = policy_mgr_2_freq_always_on_same_mac(psoc, + sap_ch_freq, + pcl_freq); + if (!((pm_conc_connection_list[0].in_use && + (pcl_freq == pm_conc_connection_list[0].freq)) || + (pm_conc_connection_list[1].in_use && + (pcl_freq == pm_conc_connection_list[1].freq)) || + (pm_conc_connection_list[2].in_use && + (pcl_freq == pm_conc_connection_list[2].freq)))) { + if (sap_ch_freq == pcl_freq) + non_scc_ch_freq_same_as_sap = pcl_freq; + else if (!non_scc_ch_freq_on_same_mac && same_mac) + non_scc_ch_freq_on_same_mac = pcl_freq; + else if (!non_scc_ch_freq_on_diff_mac && !same_mac) + non_scc_ch_freq_on_diff_mac = pcl_freq; + continue; + } + + if (sap_ch_freq == pcl_freq) + scc_ch_freq_same_as_sap = pcl_freq; + else if (!scc_ch_freq_on_same_mac && same_mac) + scc_ch_freq_on_same_mac = pcl_freq; + else if (!scc_ch_freq_on_diff_mac && !same_mac) + scc_ch_freq_on_diff_mac = pcl_freq; + } + + if (scc_ch_freq_same_as_sap) + *intf_ch_freq = scc_ch_freq_same_as_sap; + else if (scc_ch_freq_on_same_mac) + *intf_ch_freq = scc_ch_freq_on_same_mac; + else if (non_scc_ch_freq_same_as_sap) + *intf_ch_freq = non_scc_ch_freq_same_as_sap; + else if (scc_ch_freq_on_diff_mac) + *intf_ch_freq = scc_ch_freq_on_diff_mac; + else if (non_scc_ch_freq_on_same_mac) + *intf_ch_freq = non_scc_ch_freq_on_same_mac; + else if (non_scc_ch_freq_on_diff_mac) + *intf_ch_freq = non_scc_ch_freq_on_diff_mac; + else + *intf_ch_freq = 0; + + policy_mgr_debug("2ghz_only %d allow_6ghz %d, ml sta SBS:%d DBS:%d, SCC: same_as_sap %d same_mac %d on_diff_mac %d, NON-SCC: same_as_sap %d same_mac %d on_diff_mac %d. intf_ch_freq %d", + allow_2ghz_only, allow_6ghz, sbs_ml_sta_present, + dbs_ml_sta_present, scc_ch_freq_same_as_sap, + scc_ch_freq_on_same_mac, scc_ch_freq_on_diff_mac, + non_scc_ch_freq_same_as_sap, + non_scc_ch_freq_on_same_mac, + non_scc_ch_freq_on_diff_mac, *intf_ch_freq); + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_handle_sta_sap_fav_channel() - Get preferred force SCC + * channel frequency using favorite mandatory channel list for STA+SAP + * concurrency + * @psoc: Pointer to Psoc + * @pm_ctx: pm ctx + * @vdev_id: vdev id + * @intf_ch_freq: prefer force scc frequency + * @sap_ch_freq: sap/go channel starting channel frequency + * @acs_band: acs band + * + * Return: QDF_STATUS_SUCCESS if a valid favorite mandatory force scc channel + * is found. + */ +static QDF_STATUS +policy_mgr_handle_sta_sap_fav_channel(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t vdev_id, qdf_freq_t sap_ch_freq, + qdf_freq_t *intf_ch_freq, + uint32_t acs_band) +{ + bool sta_sap_scc_on_indoor_channel_allowed; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + qdf_freq_t user_config_freq; + + /* intf_ch_freq and SAP freq in same band */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(*intf_ch_freq) == + WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq)) + return policy_mgr_get_sap_mandatory_channel(psoc, sap_ch_freq, + intf_ch_freq, vdev_id); + + /* intf_ch_freq and SAP freq in different band */ + /* + * STA + SAP where doing SCC on 5 GHz indoor channel. + * STA moved/roamed to 2.4 GHz. Move SAP to initially + * started channel. + * + * STA+SAP where STA is moved/roamed to 5GHz indoor + * and SAP is on 2.4 GHz due to previous concurrency. + * Move SAP to STA channel on SCC. + */ + sta_sap_scc_on_indoor_channel_allowed = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + + /* + * SAP and interface freq in different band and 5 GHz freq is + * indoor + */ + if (sta_sap_scc_on_indoor_channel_allowed && + ((wlan_reg_is_freq_indoor(pm_ctx->pdev, sap_ch_freq) && + WLAN_REG_IS_24GHZ_CH_FREQ(*intf_ch_freq)) || + (wlan_reg_is_freq_indoor(pm_ctx->pdev, *intf_ch_freq) && + WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq) && + !(acs_band == QCA_ACS_MODE_IEEE80211B || + acs_band == QCA_ACS_MODE_IEEE80211G)))) { + status = policy_mgr_get_sap_mandatory_channel(psoc, sap_ch_freq, + intf_ch_freq, + vdev_id); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + } + + user_config_freq = + policy_mgr_get_user_config_sap_freq(psoc, vdev_id); + + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq) && + user_config_freq && + !WLAN_REG_IS_24GHZ_CH_FREQ(user_config_freq) && + (wlan_reg_get_channel_state_for_pwrmode(pm_ctx->pdev, *intf_ch_freq, + REG_CURRENT_PWR_MODE) == CHANNEL_STATE_ENABLE)) { + status = policy_mgr_get_sap_mandatory_channel(psoc, sap_ch_freq, + intf_ch_freq, + vdev_id); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + } + + return status; +} + +QDF_STATUS +policy_mgr_handle_go_sap_fav_channel(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t sap_ch_freq, + qdf_freq_t *intf_ch_freq) +{ + QDF_STATUS status; + uint8_t go_count; + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct policy_mgr_pcl_list pcl; + uint32_t i; + + go_count = policy_mgr_get_mode_specific_conn_info(psoc, + op_ch_freq_list, + vdev_id_list, + PM_P2P_GO_MODE); + if (!go_count) + return QDF_STATUS_E_FAILURE; + + /* According to requirement, SAP should move to 2.4 GHz if P2P GO is + * on 5G/6G. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(op_ch_freq_list[0]) || + WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq)) + return QDF_STATUS_E_FAILURE; + + qdf_mem_zero(&pcl, sizeof(pcl)); + status = policy_mgr_get_pcl_for_existing_conn( + psoc, PM_SAP_MODE, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list), + false, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Unable to get PCL for SAP"); + return status; + } + + for (i = 0; i < pcl.pcl_len; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(pcl.pcl_list[i])) { + *intf_ch_freq = pcl.pcl_list[i]; + policy_mgr_debug("sap move to %d because GO on %d", + *intf_ch_freq, op_ch_freq_list[0]); + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} + +/** + * policy_mgr_handle_sap_fav_channel() - Get preferred force SCC + * channel frequency using favorite mandatory channel list + * @psoc: Pointer to Psoc + * @pm_ctx: pm ctx + * @vdev_id: vdev id + * @intf_ch_freq: prefer force scc frequency + * @sap_ch_freq: sap/go channel starting channel frequency + * @acs_band: acs band + * + * Return: QDF_STATUS_SUCCESS if a valid favorite mandatory force scc channel + * is found. + */ +static QDF_STATUS +policy_mgr_handle_sap_fav_channel(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t vdev_id, qdf_freq_t sap_ch_freq, + qdf_freq_t *intf_ch_freq, + uint32_t acs_band) +{ + QDF_STATUS status; + uint8_t sta_count, go_count; + + go_count = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, + NULL); + if (go_count) { + status = policy_mgr_handle_go_sap_fav_channel( + psoc, vdev_id, + sap_ch_freq, intf_ch_freq); + if (QDF_IS_STATUS_SUCCESS(status) && + *intf_ch_freq && *intf_ch_freq != sap_ch_freq) + return QDF_STATUS_SUCCESS; + } + + sta_count = policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL); + if (sta_count && sta_count < 2) + return policy_mgr_handle_sta_sap_fav_channel( + psoc, pm_ctx, vdev_id, + sap_ch_freq, intf_ch_freq, + acs_band); + + return QDF_STATUS_E_FAILURE; +} + +void policy_mgr_check_scc_channel(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *intf_ch_freq, + qdf_freq_t sap_ch_freq, + uint8_t vdev_id, uint8_t cc_mode) +{ + uint32_t num_connections, acs_band = QCA_ACS_MODE_IEEE80211ANY; + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status; + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + uint8_t num_cxn_del = 0; + bool allow_6ghz = true; + uint8_t sta_count; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + /* Always do force SCC on non-DBS platforms */ + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return; + + sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + if (pm_ctx->hdd_cbacks.wlan_get_sap_acs_band) { + status = pm_ctx->hdd_cbacks.wlan_get_sap_acs_band(psoc, + vdev_id, + &acs_band); + if (QDF_IS_STATUS_SUCCESS(status)) + policy_mgr_debug("acs_band: %d", acs_band); + } + + /* Handle STA/P2P + SAP mandaory freq cases */ + if (cc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) { + status = policy_mgr_handle_sap_fav_channel( + psoc, pm_ctx, vdev_id, sap_ch_freq, + intf_ch_freq, acs_band); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + policy_mgr_debug("no mandatory channels (%d, %d)", sap_ch_freq, + *intf_ch_freq); + } else if (sta_count && policy_mgr_is_hw_dbs_capable(psoc)) { + policy_mgr_sap_on_non_psc_channel(psoc, intf_ch_freq, vdev_id); + } + + /* Get allow 6Gz before interface entry is temporary deleted */ + if (sap_ch_freq && !WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ch_freq) && + !policy_mgr_get_ap_6ghz_capable(psoc, vdev_id, NULL)) + allow_6ghz = false; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* + * For SAP restart case SAP entry might be present in table, + * so delete it temporary + */ + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id, info, + &num_cxn_del); + + num_connections = policy_mgr_get_connection_count(psoc); + switch (num_connections) { + case 0: + /* use sap channel */ + *intf_ch_freq = 0; + break; + default: + if (num_connections > 3) { + policy_mgr_debug("invalid num_connections: %d", + num_connections); + break; + } + /* Use PCL and concurrency combo to get the best channel */ + policy_mgr_get_pref_force_scc_freq(psoc, vdev_id, intf_ch_freq, + sap_ch_freq, acs_band, + allow_6ghz); + break; + } + + /* Restore the connection entry */ + if (num_cxn_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +void policy_mgr_nss_update_cb(struct wlan_objmgr_psoc *psoc, + uint8_t tx_status, + uint8_t vdev_id, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id) +{ + uint32_t conn_index = 0; + QDF_STATUS ret; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (QDF_STATUS_SUCCESS != tx_status) + policy_mgr_err("nss update failed(%d) for vdev %d", + tx_status, vdev_id); + + /* + * Check if we are ok to request for HW mode change now + */ + conn_index = policy_mgr_get_connection_for_vdev_id(psoc, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + policy_mgr_err("connection not found for vdev %d", vdev_id); + return; + } + + policy_mgr_debug("nss update successful for vdev:%d ori %d reason %d", + vdev_id, original_vdev_id, reason); + if (PM_NOP != next_action) { + if (reason == POLICY_MGR_UPDATE_REASON_AFTER_CHANNEL_SWITCH) + policy_mgr_next_actions(psoc, vdev_id, next_action, + reason, request_id); + else + policy_mgr_next_actions(psoc, original_vdev_id, + next_action, reason, + request_id); + } else { + if (reason == POLICY_MGR_UPDATE_REASON_STA_CONNECT || + reason == POLICY_MGR_UPDATE_REASON_LFR2_ROAM) { + sme_debug("Continue connect/reassoc on vdev %d request_id %x reason %d", + vdev_id, request_id, reason); + wlan_connect_hw_mode_change_resp(pm_ctx->pdev, vdev_id, + request_id, + QDF_STATUS_SUCCESS); + } + policy_mgr_debug("No action needed right now"); + ret = policy_mgr_set_opportunistic_update(psoc); + if (!QDF_IS_STATUS_SUCCESS(ret)) + policy_mgr_err("ERROR: set opportunistic_update event failed"); + } + + return; +} + +QDF_STATUS +policy_mgr_sap_ch_width_update(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conc_next_action next_action, + enum policy_mgr_conn_update_reason reason, + uint8_t conc_vdev_id, uint32_t request_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t freq; + uint8_t sap_vdev_id; + enum phy_ch_width target_bw; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + policy_mgr_debug("action: %d reason: %d", next_action, reason); + + policy_mgr_get_mode_specific_conn_info(psoc, &freq, + &sap_vdev_id, + PM_SAP_MODE); + if (next_action == PM_DOWNGRADE_BW) + target_bw = CH_WIDTH_160MHZ; + else + target_bw = CH_WIDTH_320MHZ; + + status = pm_ctx->sme_cbacks.sme_sap_update_ch_width(psoc, + sap_vdev_id, + target_bw, reason, + conc_vdev_id, + request_id); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("vdev %d failed to set BW to %d", + sap_vdev_id, target_bw); + + return status; +} + +QDF_STATUS policy_mgr_nss_update(struct wlan_objmgr_psoc *psoc, + uint8_t new_nss, uint8_t next_action, + enum policy_mgr_band band, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t index, count; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_index = 0; + uint32_t vdev_id; + uint32_t original_nss, ch_freq; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum phy_ch_width ch_width = CH_WIDTH_MAX; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + if (next_action == PM_DBS2 && band == POLICY_MGR_BAND_5) + ch_width = CH_WIDTH_40MHZ; + + count = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, list); + for (index = 0; index < count; index++) { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + vdev_id = pm_conc_connection_list[list[index]].vdev_id; + original_nss = + pm_conc_connection_list[list[index]].original_nss; + ch_freq = pm_conc_connection_list[list[index]].freq; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + conn_index = policy_mgr_get_connection_for_vdev_id( + psoc, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + policy_mgr_err("connection not found for vdev %d", + vdev_id); + continue; + } + + if (original_nss == 2 && + (band == POLICY_MGR_ANY || + (band == POLICY_MGR_BAND_24 && + WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) || + (band == POLICY_MGR_BAND_5 && + WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq)))) { + status = pm_ctx->sme_cbacks.sme_nss_update_request( + vdev_id, new_nss, ch_width, + policy_mgr_nss_update_cb, + next_action, psoc, reason, + original_vdev_id, request_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("sme_nss_update_request() failed for vdev %d", + vdev_id); + } + } + } + + count = policy_mgr_get_sap_mode_count(psoc, list); + + for (index = 0; index < count; index++) { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + vdev_id = pm_conc_connection_list[list[index]].vdev_id; + original_nss = + pm_conc_connection_list[list[index]].original_nss; + ch_freq = pm_conc_connection_list[list[index]].freq; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + conn_index = policy_mgr_get_connection_for_vdev_id( + psoc, vdev_id); + if (MAX_NUMBER_OF_CONC_CONNECTIONS == conn_index) { + policy_mgr_err("connection not found for vdev %d", + vdev_id); + continue; + } + if (original_nss == 2 && + (band == POLICY_MGR_ANY || + (band == POLICY_MGR_BAND_24 && + WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) || + (band == POLICY_MGR_BAND_5 && + WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq)))) { + status = pm_ctx->sme_cbacks.sme_nss_update_request( + vdev_id, new_nss, ch_width, + policy_mgr_nss_update_cb, + next_action, psoc, reason, + original_vdev_id, request_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("sme_nss_update_request() failed for vdev %d", + vdev_id); + } + } + } + + return status; +} + +QDF_STATUS policy_mgr_complete_action(struct wlan_objmgr_psoc *psoc, + uint8_t new_nss, uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t session_id, uint32_t request_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum policy_mgr_band downgrade_band; + + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + policy_mgr_rl_debug("driver isn't dbs capable, no further action needed"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* policy_mgr_complete_action() is called by policy_mgr_next_actions(). + * All other callers of policy_mgr_next_actions() have taken mutex + * protection. So, not taking any lock inside + * policy_mgr_complete_action() during pm_conc_connection_list access. + */ + if (next_action == PM_DBS1) + downgrade_band = POLICY_MGR_BAND_24; + else if (next_action == PM_DBS2) + downgrade_band = POLICY_MGR_BAND_5; + else + downgrade_band = POLICY_MGR_ANY; + + status = policy_mgr_nss_update(psoc, new_nss, next_action, + downgrade_band, reason, + session_id, request_id); + if (!QDF_IS_STATUS_SUCCESS(status)) + status = policy_mgr_next_actions(psoc, session_id, + next_action, reason, + request_id); + + return status; +} + +enum policy_mgr_con_mode policy_mgr_get_mode_by_vdev_id( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return mode; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) + if ((pm_conc_connection_list[conn_index].vdev_id == vdev_id) && + pm_conc_connection_list[conn_index].in_use){ + mode = pm_conc_connection_list[conn_index].mode; + break; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return mode; +} + +/** + * policy_mgr_init_connection_update() - Initialize connection + * update event + * @pm_ctx: policy mgr context + * + * Initializes the concurrent connection update event + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_init_connection_update( + struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + QDF_STATUS qdf_status; + + qdf_status = qdf_event_create(&pm_ctx->connection_update_done_evt); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + policy_mgr_err("init event failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +enum policy_mgr_conc_next_action + policy_mgr_get_current_pref_hw_mode_dbs_2x2( + struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections; + uint8_t band1, band2, band3; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status; + + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return PM_NOP; + } + + num_connections = policy_mgr_get_connection_count(psoc); + + policy_mgr_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d", + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[2].freq, num_connections, + hw_mode.dbs_cap); + + /* If the band of operation of both the MACs is the same, + * single MAC is preferred, otherwise DBS is preferred. + */ + switch (num_connections) { + case 1: + band1 = wlan_reg_freq_to_band(pm_conc_connection_list[0].freq); + if (band1 == REG_BAND_2G) + return PM_DBS; + else + return PM_NOP; + case 2: + band1 = wlan_reg_freq_to_band(pm_conc_connection_list[0].freq); + band2 = wlan_reg_freq_to_band(pm_conc_connection_list[1].freq); + if (band1 == REG_BAND_2G || band2 == REG_BAND_2G) { + if (!hw_mode.dbs_cap) + return PM_DBS; + else + return PM_NOP; + } else if (band1 == REG_BAND_5G && band2 == REG_BAND_5G) { + if (policy_mgr_are_sbs_chan(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + if (!hw_mode.sbs_cap) + return PM_SBS; + else + return PM_NOP; + } else { + if (hw_mode.sbs_cap || hw_mode.dbs_cap) + return PM_SINGLE_MAC; + else + return PM_NOP; + } + } else + return PM_NOP; + case 3: + band1 = wlan_reg_freq_to_band(pm_conc_connection_list[0].freq); + band2 = wlan_reg_freq_to_band(pm_conc_connection_list[1].freq); + band3 = wlan_reg_freq_to_band(pm_conc_connection_list[2].freq); + if (band1 == REG_BAND_2G || band2 == REG_BAND_2G || + band3 == REG_BAND_2G) { + if (!hw_mode.dbs_cap) + return PM_DBS; + else + return PM_NOP; + } else if (band1 == REG_BAND_5G && band2 == REG_BAND_5G && + band3 == REG_BAND_5G) { + if (policy_mgr_are_sbs_chan(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[2].freq) && + policy_mgr_are_sbs_chan(psoc, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[2].freq) && + policy_mgr_are_sbs_chan(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + if (!hw_mode.sbs_cap) + return PM_SBS; + else + return PM_NOP; + } else { + if (hw_mode.sbs_cap || hw_mode.dbs_cap) + return PM_SINGLE_MAC; + else + return PM_NOP; + } + } else + return PM_NOP; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + return PM_NOP; + } +} + +enum policy_mgr_conc_next_action + policy_mgr_get_current_pref_hw_mode_dbs_1x1( + struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections; + uint8_t band1, band2, band3; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status; + enum policy_mgr_conc_next_action next_action; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return PM_NOP; + } + + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return PM_NOP; + } + + num_connections = policy_mgr_get_connection_count(psoc); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("chan[0]:%d chan[1]:%d chan[2]:%d num_connections:%d dbs:%d", + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[2].freq, num_connections, + hw_mode.dbs_cap); + + /* If the band of operation of both the MACs is the same, + * single MAC is preferred, otherwise DBS is preferred. + */ + switch (num_connections) { + case 1: + /* The driver would already be in the required hw mode */ + next_action = PM_NOP; + break; + case 2: + band1 = wlan_reg_freq_to_band(pm_conc_connection_list[0].freq); + band2 = wlan_reg_freq_to_band(pm_conc_connection_list[1].freq); + if ((band1 == band2) && (hw_mode.dbs_cap)) + next_action = PM_SINGLE_MAC_UPGRADE; + else if ((band1 != band2) && (!hw_mode.dbs_cap)) + next_action = PM_DBS_DOWNGRADE; + else + next_action = PM_NOP; + + break; + + case 3: + band1 = wlan_reg_freq_to_band(pm_conc_connection_list[0].freq); + band2 = wlan_reg_freq_to_band(pm_conc_connection_list[1].freq); + band3 = wlan_reg_freq_to_band(pm_conc_connection_list[2].freq); + if (((band1 == band2) && (band2 == band3)) && + (hw_mode.dbs_cap)) { + next_action = PM_SINGLE_MAC_UPGRADE; + } else if (((band1 != band2) || (band2 != band3) || + (band1 != band3)) && + (!hw_mode.dbs_cap)) { + next_action = PM_DBS_DOWNGRADE; + } else { + next_action = PM_NOP; + } + break; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + next_action = PM_NOP; + break; + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return next_action; +} + +enum policy_mgr_conc_next_action +policy_mgr_get_current_pref_hw_mode_dual_dbs( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_conc_next_action next_action; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_conc_next_action preferred_dbs; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return PM_NOP; + } + + next_action = policy_mgr_get_current_pref_hw_mode_dbs_1x1(psoc); + policy_mgr_info("next_action %d", next_action); + if (next_action != PM_DBS_DOWNGRADE) + return next_action; + + preferred_dbs = policy_mgr_get_preferred_dbs_action_table( + psoc, INVALID_VDEV_ID, 0, 0); + if (preferred_dbs == PM_DBS1) { + next_action = PM_DBS1_DOWNGRADE; + } else if (preferred_dbs == PM_DBS2) { + next_action = PM_DBS2_DOWNGRADE; + } else { + policy_mgr_err("DBS1 and DBS2 hw mode not supported"); + return PM_NOP; + } + policy_mgr_info("preferred_dbs %d", next_action); + return next_action; +} + +void policy_mgr_add_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + int i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + for (i = 0; i < pm_ctx->sap_mandatory_channels_len; i++) { + if (ch_freq == pm_ctx->sap_mandatory_channels[i]) + return; + } + if (pm_ctx->sap_mandatory_channels_len >= NUM_CHANNELS) { + policy_mgr_err("mand list overflow (%u)", ch_freq); + return; + } + + policy_mgr_debug("Ch freq: %u", ch_freq); + + pm_ctx->sap_mandatory_channels[pm_ctx->sap_mandatory_channels_len++] + = ch_freq; +} + +uint32_t policy_mgr_get_sap_mandatory_chan_list_len( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + return pm_ctx->sap_mandatory_channels_len; +} + +#if defined(CONFIG_BAND_6GHZ) +/** + * policy_mgr_add_sap_mandatory_6ghz_chan() - Add 6GHz SAP mandatory channel + * list + * @psoc: Pointer to soc + * + * Add the 6GHz PSC VLP channel to SAP mandatory channel list. + * + * Return: None + */ +static +void policy_mgr_add_sap_mandatory_6ghz_chan(struct wlan_objmgr_psoc *psoc) +{ + uint32_t ch_freq_list[NUM_CHANNELS] = {0}; + uint32_t len = 0; + int i; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool is_psd; + uint16_t tx_power; + uint16_t eirp_psd_power; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + status = policy_mgr_get_valid_chans(psoc, ch_freq_list, &len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Error in getting valid channels"); + return; + } + + for (i = 0; (i < len) && (i < NUM_CHANNELS) && + (pm_ctx->sap_mandatory_channels_len < NUM_CHANNELS); i++) { + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq_list[i])) + continue; + if (WLAN_REG_IS_6GHZ_PSC_CHAN_FREQ(ch_freq_list[i])) { + status = wlan_reg_get_6g_chan_ap_power( + pm_ctx->pdev, ch_freq_list[i], &is_psd, + &tx_power, &eirp_psd_power); + if (status != QDF_STATUS_SUCCESS || !tx_power) + continue; + + policy_mgr_debug("Add chan %u to mandatory list", + ch_freq_list[i]); + pm_ctx->sap_mandatory_channels[ + pm_ctx->sap_mandatory_channels_len++] = + ch_freq_list[i]; + } + } +} +#else +static inline +void policy_mgr_add_sap_mandatory_6ghz_chan(struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +/** + * policy_mgr_init_sap_mandatory_chan_by_band() - Init SAP mandatory channel + * list based on band + * @psoc: Pointer to soc + * @band_bitmap: band bitmap of type reg_wifi_band + * + * Initialize the 2.4G 5G 6G SAP mandatory channels based on band + * + * Return: None + */ +static void +policy_mgr_init_sap_mandatory_chan_by_band(struct wlan_objmgr_psoc *psoc, + uint32_t band_bitmap) +{ + uint32_t ch_freq_list[NUM_CHANNELS] = {0}; + uint32_t len = 0; + int i; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + status = policy_mgr_get_valid_chans(psoc, ch_freq_list, &len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Error in getting valid channels"); + return; + } + pm_ctx->sap_mandatory_channels_len = 0; + for (i = 0; (i < len) && (i < NUM_CHANNELS); i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq_list[i])) { + policy_mgr_debug("Add chan %u to mandatory list", + ch_freq_list[i]); + pm_ctx->sap_mandatory_channels[ + pm_ctx->sap_mandatory_channels_len++] = + ch_freq_list[i]; + } + } + if (band_bitmap & BIT(REG_BAND_5G)) + for (i = 0; i < ARRAY_SIZE(sap_mand_5g_freq_list); i++) + policy_mgr_add_sap_mandatory_chan( + psoc, sap_mand_5g_freq_list[i]); + if (band_bitmap & BIT(REG_BAND_6G)) + policy_mgr_add_sap_mandatory_6ghz_chan(psoc); +} + +void policy_mgr_init_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc, + uint32_t org_ch_freq) +{ + if (WLAN_REG_IS_5GHZ_CH_FREQ(org_ch_freq)) { + policy_mgr_debug("channel %u, sap mandatory chan list enabled", + org_ch_freq); + policy_mgr_init_sap_mandatory_chan_by_band( + psoc, BIT(REG_BAND_2G) | BIT(REG_BAND_5G)); + policy_mgr_add_sap_mandatory_chan( + psoc, org_ch_freq); + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(org_ch_freq)) { + policy_mgr_init_sap_mandatory_chan_by_band( + psoc, + BIT(REG_BAND_2G) | BIT(REG_BAND_5G) | + BIT(REG_BAND_6G)); + } else { + policy_mgr_init_sap_mandatory_chan_by_band( + psoc, BIT(REG_BAND_2G)); + } +} + +void policy_mgr_remove_sap_mandatory_chan(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq) +{ + uint32_t ch_freq_list[NUM_CHANNELS] = {0}; + uint32_t num_chan = 0; + int i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (pm_ctx->sap_mandatory_channels_len >= NUM_CHANNELS) { + policy_mgr_err("Invalid channel len %d ", + pm_ctx->sap_mandatory_channels_len); + return; + } + + for (i = 0; i < pm_ctx->sap_mandatory_channels_len; i++) { + if (ch_freq == pm_ctx->sap_mandatory_channels[i]) + continue; + ch_freq_list[num_chan++] = pm_ctx->sap_mandatory_channels[i]; + } + + qdf_mem_zero(pm_ctx->sap_mandatory_channels, + pm_ctx->sap_mandatory_channels_len * + sizeof(*pm_ctx->sap_mandatory_channels)); + qdf_mem_copy(pm_ctx->sap_mandatory_channels, ch_freq_list, + num_chan * sizeof(*pm_ctx->sap_mandatory_channels)); + pm_ctx->sap_mandatory_channels_len = num_chan; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c new file mode 100644 index 0000000000..2820f46bf5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c @@ -0,0 +1,13013 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_policy_mgr_get_set_utils.c + * + * WLAN Concurrenct Connection Management APIs + * + */ + +/* Include files */ +#include "target_if.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_i.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_nan_api.h" +#include "nan_public_structs.h" +#include "wlan_reg_services_api.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_main.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_cm_ucfg_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_mlo_link_force.h" +#include "wlan_connectivity_logging.h" +#include "wlan_policy_mgr_ll_sap.h" + +/* invalid channel id. */ +#define INVALID_CHANNEL_ID 0 + +#define IS_FREQ_ON_MAC_ID(freq_range, freq, mac_id) \ + ((freq >= freq_range[mac_id].low_2ghz_freq && \ + freq <= freq_range[mac_id].high_2ghz_freq) || \ + (freq >= freq_range[mac_id].low_5ghz_freq && \ + freq <= freq_range[mac_id].high_5ghz_freq)) + +/** + * policy_mgr_debug_alert() - fatal error alert + * + * This function will flush host drv log and + * disable all level logs. + * It can be called in fatal error detected in policy + * manager. + * This is to avoid host log overwritten in stress + * test to help issue debug. + * + * Return: none + */ +static void +policy_mgr_debug_alert(void) +{ + int module_id; + int qdf_print_idx; + + policy_mgr_err("fatal error detected to flush and pause host log"); + qdf_logging_flush_logs(); + qdf_print_idx = qdf_get_pidx(); + for (module_id = 0; module_id < QDF_MODULE_ID_MAX; module_id++) + qdf_print_set_category_verbose( + qdf_print_idx, + module_id, QDF_TRACE_LEVEL_NONE, + 0); +} + +QDF_STATUS +policy_mgr_get_allow_mcc_go_diff_bi(struct wlan_objmgr_psoc *psoc, + uint8_t *allow_mcc_go_diff_bi) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *allow_mcc_go_diff_bi = pm_ctx->cfg.allow_mcc_go_diff_bi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_set_dual_mac_feature(struct wlan_objmgr_psoc *psoc, + uint8_t dual_mac_feature) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->cfg.dual_mac_feature = dual_mac_feature; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_dual_mac_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_mac_feature) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *dual_mac_feature = pm_ctx->cfg.dual_mac_feature; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_force_1x1(struct wlan_objmgr_psoc *psoc, + uint8_t *force_1x1) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *force_1x1 = pm_ctx->cfg.is_force_1x1_enable; + + return QDF_STATUS_SUCCESS; +} + +uint32_t policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return 0; + } + + return pm_ctx->cfg.max_conc_cxns; +} + +QDF_STATUS policy_mgr_set_max_conc_cxns(struct wlan_objmgr_psoc *psoc, + uint32_t max_conc_cxns) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_debug("set max_conc_cxns %d old %d", max_conc_cxns, + pm_ctx->cfg.max_conc_cxns); + pm_ctx->cfg.max_conc_cxns = max_conc_cxns; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_set_sta_sap_scc_on_dfs_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t sta_sap_scc_on_dfs_chnl) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->cfg.sta_sap_scc_on_dfs_chnl = sta_sap_scc_on_dfs_chnl; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_sta_sap_scc_on_dfs_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_on_dfs_chnl) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *sta_sap_scc_on_dfs_chnl = pm_ctx->cfg.sta_sap_scc_on_dfs_chnl; + + return QDF_STATUS_SUCCESS; +} + +bool +policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return false; + } + + return pm_ctx->cfg.sta_sap_scc_on_indoor_channel; +} + +QDF_STATUS +policy_mgr_set_multi_sap_allowed_on_same_band(struct wlan_objmgr_psoc *psoc, + bool multi_sap_allowed_on_same_band) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->cfg.multi_sap_allowed_on_same_band = + multi_sap_allowed_on_same_band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_multi_sap_allowed_on_same_band(struct wlan_objmgr_psoc *psoc, + bool *multi_sap_allowed_on_same_band) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *multi_sap_allowed_on_same_band = + pm_ctx->cfg.multi_sap_allowed_on_same_band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_set_original_bw_for_sap_restart(struct wlan_objmgr_psoc *psoc, + bool use_sap_original_bw) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->cfg.use_sap_original_bw = use_sap_original_bw; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_original_bw_for_sap_restart(struct wlan_objmgr_psoc *psoc, + bool *use_sap_original_bw) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *use_sap_original_bw = pm_ctx->cfg.use_sap_original_bw; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_dfs_sta_sap_go_scc_movement(struct wlan_objmgr_psoc *psoc, + bool *move_sap_go_first) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *move_sap_go_first = pm_ctx->cfg.move_sap_go_1st_on_dfs_sta_csa; + + return QDF_STATUS_SUCCESS; +} + +static bool +policy_mgr_update_dfs_master_dynamic_enabled( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool sta_on_5g = false; + bool sta_on_2g = false; + uint32_t i; + bool enable = true; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return true; + } + + if (!pm_ctx->cfg.sta_sap_scc_on_dfs_chnl) { + enable = true; + goto end; + } + if (pm_ctx->cfg.sta_sap_scc_on_dfs_chnl == + PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED) { + enable = false; + goto end; + } + if (pm_ctx->cfg.sta_sap_scc_on_dfs_chnl != + PM_STA_SAP_ON_DFS_MASTER_MODE_FLEX) { + policy_mgr_debug("sta_sap_scc_on_dfs_chnl %d unknown", + pm_ctx->cfg.sta_sap_scc_on_dfs_chnl); + enable = true; + goto end; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (!((pm_conc_connection_list[i].vdev_id != vdev_id) && + pm_conc_connection_list[i].in_use && + (pm_conc_connection_list[i].mode == PM_STA_MODE || + pm_conc_connection_list[i].mode == PM_P2P_CLIENT_MODE))) + continue; + if (WLAN_REG_IS_5GHZ_CH_FREQ(pm_conc_connection_list[i].freq)) + sta_on_5g = true; + else + sta_on_2g = true; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (policy_mgr_is_hw_dbs_capable(psoc) && !sta_on_5g) + enable = true; + else if (!sta_on_5g && !sta_on_2g) + enable = true; + else + enable = false; +end: + pm_ctx->dynamic_dfs_master_disabled = !enable; + if (!enable) + policy_mgr_debug("sta_sap_scc_on_dfs_chnl %d sta_on_2g %d sta_on_5g %d enable %d", + pm_ctx->cfg.sta_sap_scc_on_dfs_chnl, sta_on_2g, + sta_on_5g, enable); + + return enable; +} + +bool +policy_mgr_get_dfs_master_dynamic_enabled( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return true; + } + + return policy_mgr_update_dfs_master_dynamic_enabled(psoc, vdev_id); +} + +bool +policy_mgr_get_can_skip_radar_event(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return false; + } + + return pm_ctx->dynamic_dfs_master_disabled; +} + +QDF_STATUS +policy_mgr_get_sta_sap_scc_lte_coex_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_lte_coex) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *sta_sap_scc_lte_coex = pm_ctx->cfg.sta_sap_scc_on_lte_coex_chnl; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_sap_mandt_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sap_mandt_chnl) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *sap_mandt_chnl = pm_ctx->cfg.sap_mandatory_chnl_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_indoor_chnl_marking(struct wlan_objmgr_psoc *psoc, + uint8_t *indoor_chnl_marking) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *indoor_chnl_marking = pm_ctx->cfg.mark_indoor_chnl_disable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc, + uint8_t *mcc_scc_switch) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *mcc_scc_switch = pm_ctx->cfg.mcc_to_scc_switch; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t *sys_pref) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *sys_pref = pm_ctx->cfg.sys_pref; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t sys_pref) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->cfg.sys_pref = sys_pref; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule1) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *conc_rule1 = pm_ctx->cfg.conc_rule1; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule2) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *conc_rule2 = pm_ctx->cfg.conc_rule2; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc, + uint32_t *chnl_select_plcy) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *chnl_select_plcy = pm_ctx->cfg.chnl_select_plcy; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_set_ch_select_plcy(struct wlan_objmgr_psoc *psoc, + uint32_t ch_select_policy) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->cfg.chnl_select_plcy = ch_select_policy; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_set_dynamic_mcc_adaptive_sch( + struct wlan_objmgr_psoc *psoc, + bool dynamic_mcc_adaptive_sched) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->dynamic_mcc_adaptive_sched = dynamic_mcc_adaptive_sched; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_dynamic_mcc_adaptive_sch( + struct wlan_objmgr_psoc *psoc, + bool *dynamic_mcc_adaptive_sched) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *dynamic_mcc_adaptive_sched = pm_ctx->dynamic_mcc_adaptive_sched; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc, + bool *enable_mcc_adaptive_sch) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *enable_mcc_adaptive_sch = pm_ctx->cfg.enable_mcc_adaptive_sch; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_sta_cxn_5g_band) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *enable_sta_cxn_5g_band = pm_ctx->cfg.enable_sta_cxn_5g_band; + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_update_new_hw_mode_index(struct wlan_objmgr_psoc *psoc, + uint32_t new_hw_mode_index) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + pm_ctx->new_hw_mode_index = new_hw_mode_index; +} + +void policy_mgr_update_old_hw_mode_index(struct wlan_objmgr_psoc *psoc, + uint32_t old_hw_mode_index) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + pm_ctx->old_hw_mode_index = old_hw_mode_index; +} + +void policy_mgr_update_hw_mode_index(struct wlan_objmgr_psoc *psoc, + uint32_t new_hw_mode_index) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + if (POLICY_MGR_DEFAULT_HW_MODE_INDEX == pm_ctx->new_hw_mode_index) { + pm_ctx->new_hw_mode_index = new_hw_mode_index; + } else { + pm_ctx->old_hw_mode_index = pm_ctx->new_hw_mode_index; + pm_ctx->new_hw_mode_index = new_hw_mode_index; + } + policy_mgr_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + pm_ctx->old_hw_mode_index, pm_ctx->new_hw_mode_index); +} + +/** + * policy_mgr_get_num_of_setbits_from_bitmask() - to get num of + * setbits from bitmask + * @mask: given bitmask + * + * This helper function should return number of setbits from bitmask + * + * Return: number of setbits from bitmask + */ +static uint32_t policy_mgr_get_num_of_setbits_from_bitmask(uint32_t mask) +{ + uint32_t num_of_setbits = 0; + + while (mask) { + mask &= (mask - 1); + num_of_setbits++; + } + return num_of_setbits; +} + +/** + * policy_mgr_map_wmi_channel_width_to_hw_mode_bw() - returns + * bandwidth in terms of hw_mode_bandwidth + * @width: bandwidth in terms of wmi_channel_width + * + * This function returns the bandwidth in terms of hw_mode_bandwidth. + * + * Return: BW in terms of hw_mode_bandwidth. + */ +static enum hw_mode_bandwidth policy_mgr_map_wmi_channel_width_to_hw_mode_bw( + wmi_channel_width width) +{ + switch (width) { + case WMI_CHAN_WIDTH_20: + return HW_MODE_20_MHZ; + case WMI_CHAN_WIDTH_40: + return HW_MODE_40_MHZ; + case WMI_CHAN_WIDTH_80: + return HW_MODE_80_MHZ; + case WMI_CHAN_WIDTH_160: + return HW_MODE_160_MHZ; + case WMI_CHAN_WIDTH_80P80: + return HW_MODE_80_PLUS_80_MHZ; + case WMI_CHAN_WIDTH_5: + return HW_MODE_5_MHZ; + case WMI_CHAN_WIDTH_10: + return HW_MODE_10_MHZ; +#ifdef WLAN_FEATURE_11BE + case WMI_CHAN_WIDTH_320: + return HW_MODE_320_MHZ; +#endif + default: + return HW_MODE_BW_NONE; + } + + return HW_MODE_BW_NONE; +} + +static void policy_mgr_get_hw_mode_params( + struct wlan_psoc_host_mac_phy_caps *caps, + struct policy_mgr_mac_ss_bw_info *info) +{ + qdf_freq_t max_5g_freq; + + if (!caps) { + policy_mgr_err("Invalid capabilities"); + return; + } + + info->mac_tx_stream = policy_mgr_get_num_of_setbits_from_bitmask( + QDF_MAX(caps->tx_chain_mask_2G, + caps->tx_chain_mask_5G)); + info->mac_rx_stream = policy_mgr_get_num_of_setbits_from_bitmask( + QDF_MAX(caps->rx_chain_mask_2G, + caps->rx_chain_mask_5G)); + info->mac_bw = policy_mgr_map_wmi_channel_width_to_hw_mode_bw( + QDF_MAX(caps->max_bw_supported_2G, + caps->max_bw_supported_5G)); + info->mac_band_cap = caps->supported_bands; + + if (caps->supported_bands & WMI_HOST_WLAN_5G_CAPABILITY) { + max_5g_freq = wlan_reg_max_6ghz_chan_freq() ? + wlan_reg_max_6ghz_chan_freq() : + wlan_reg_max_5ghz_chan_freq(); + max_5g_freq = caps->reg_cap_ext.high_5ghz_chan ? + QDF_MIN(caps->reg_cap_ext.high_5ghz_chan, + max_5g_freq) : max_5g_freq; + info->support_6ghz_band = + max_5g_freq > wlan_reg_min_6ghz_chan_freq(); + } +} + +QDF_STATUS policy_mgr_update_nss_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t tx_nss, + uint8_t rx_nss) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + return pm_ctx->hdd_cbacks.wlan_set_tx_rx_nss_cb(psoc, vdev_id, + tx_nss, rx_nss); +} + +/** + * policy_mgr_set_hw_mode_params() - sets TX-RX stream, + * bandwidth and DBS in hw_mode_list + * @psoc: PSOC object information + * @mac0_ss_bw_info: TX-RX streams, BW for MAC0 + * @mac1_ss_bw_info: TX-RX streams, BW for MAC1 + * @pos: refers to hw_mode_list array index + * @hw_mode_id: hw mode id value used by firmware + * @dbs_mode: dbs_mode for the dbs_hw_mode + * @sbs_mode: sbs_mode for the sbs_hw_mode + * @emlsr_mode: emlsr_mode for the emlsr_hw_mode + * + * This function sets TX-RX stream, bandwidth and DBS mode in + * hw_mode_list. + * + * Return: none + */ +static void policy_mgr_set_hw_mode_params(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_mac_ss_bw_info mac0_ss_bw_info, + struct policy_mgr_mac_ss_bw_info mac1_ss_bw_info, + uint32_t pos, uint32_t hw_mode_id, uint32_t dbs_mode, + uint32_t sbs_mode, uint64_t emlsr_mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint64_t legacy_hwmode_lst; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_tx_stream); + POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_rx_stream); + POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_bw); + POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_tx_stream); + POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_rx_stream); + POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac1_ss_bw_info.mac_bw); + POLICY_MGR_HW_MODE_DBS_MODE_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + dbs_mode); + POLICY_MGR_HW_MODE_AGILE_DFS_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + HW_MODE_AGILE_DFS_NONE); + POLICY_MGR_HW_MODE_SBS_MODE_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + sbs_mode); + POLICY_MGR_HW_MODE_MAC0_BAND_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + mac0_ss_bw_info.mac_band_cap); + POLICY_MGR_HW_MODE_ID_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + hw_mode_id); + + legacy_hwmode_lst = pm_ctx->hw_mode.hw_mode_list[pos]; + POLICY_MGR_HW_MODE_EMLSR_MODE_SET( + pm_ctx->hw_mode.hw_mode_list[pos], + legacy_hwmode_lst, emlsr_mode); +} + +QDF_STATUS policy_mgr_get_radio_combinations(struct wlan_objmgr_psoc *psoc, + struct radio_combination *comb, + uint32_t comb_max, + uint32_t *comb_num) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct radio_combination *radio_comb; + uint32_t i; + bool dbs_or_sbs_enabled = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + *comb_num = 0; + if (policy_mgr_is_hw_dbs_capable(psoc) || + policy_mgr_is_hw_sbs_capable(psoc)) + dbs_or_sbs_enabled = true; + + for (i = 0; i < pm_ctx->radio_comb_num; i++) { + radio_comb = &pm_ctx->radio_combinations[i]; + if (!dbs_or_sbs_enabled && radio_comb->hw_mode != MODE_SMM) + continue; + if (*comb_num >= comb_max) { + policy_mgr_err("out of buffer %d max %d", + pm_ctx->radio_comb_num, + comb_max); + return QDF_STATUS_E_FAILURE; + } + policy_mgr_debug("radio %d: mode %d mac0 (0x%x, 0x%x), mac1 (0x%x 0x%x)", + *comb_num, + radio_comb->hw_mode, + radio_comb->band_mask[0], + radio_comb->antenna[0], + radio_comb->band_mask[1], + radio_comb->antenna[1]); + qdf_mem_copy(&comb[*comb_num], radio_comb, + sizeof(*radio_comb)); + (*comb_num)++; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_add_radio_comb() - Add radio combination + * @pm_ctx: bandwidth in terms of wmi_channel_width + * @radio: radio combination + * + * This function adds one radio combination to list + * + * Return: void + */ +static void policy_mgr_add_radio_comb(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct radio_combination *radio) +{ + uint32_t i; + struct radio_combination *comb; + + /* don't add duplicated item */ + for (i = 0; i < pm_ctx->radio_comb_num; i++) { + comb = &pm_ctx->radio_combinations[i]; + if (radio->hw_mode == comb->hw_mode && + radio->band_mask[0] == comb->band_mask[0] && + radio->band_mask[1] == comb->band_mask[1] && + radio->antenna[0] == comb->antenna[0] && + radio->antenna[1] == comb->antenna[1]) + return; + } + if (pm_ctx->radio_comb_num == MAX_RADIO_COMBINATION) { + policy_mgr_err("radio combination overflow %d", + pm_ctx->radio_comb_num); + return; + } + policy_mgr_debug("radio %d: mode %d mac0 (0x%x, 0x%x), mac1 (0x%x 0x%x)", + pm_ctx->radio_comb_num, + radio->hw_mode, + radio->band_mask[0], + radio->antenna[0], + radio->band_mask[1], + radio->antenna[1]); + + qdf_mem_copy(&pm_ctx->radio_combinations[pm_ctx->radio_comb_num], + radio, sizeof(*radio)); + pm_ctx->radio_comb_num++; +} + +#define SET_RADIO(_radio, _mode, _mac0_band, _mac1_band,\ + _mac0_antenna, _mac1_antenna) \ +do { \ + (_radio)->hw_mode = _mode; \ + (_radio)->band_mask[0] = _mac0_band; \ + (_radio)->band_mask[1] = _mac1_band; \ + (_radio)->antenna[0] = _mac0_antenna; \ + (_radio)->antenna[1] = _mac1_antenna; \ +} while (0) + +/** + * policy_mgr_update_radio_combination_matrix() - Update radio combination + * list + * @psoc: psoc object + * @mac0_ss_bw_info: mac 0 band/bw info + * @mac1_ss_bw_info: mac 1 band/bw info + * @dbs_mode: dbs mode + * @sbs_mode: sbs mode + * + * This function updates radio combination list based on hw mode information. + * + * Return: void + */ +static void +policy_mgr_update_radio_combination_matrix( + struct wlan_objmgr_psoc *psoc, + struct policy_mgr_mac_ss_bw_info mac0_ss_bw_info, + struct policy_mgr_mac_ss_bw_info mac1_ss_bw_info, + uint32_t dbs_mode, uint32_t sbs_mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct radio_combination radio; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (!dbs_mode && !sbs_mode) { + if (mac0_ss_bw_info.mac_band_cap & + WMI_HOST_WLAN_2G_CAPABILITY) { + SET_RADIO(&radio, MODE_SMM, BIT(REG_BAND_2G), 0, + mac0_ss_bw_info.mac_tx_stream, 0); + policy_mgr_add_radio_comb(pm_ctx, &radio); + } + if (mac0_ss_bw_info.mac_band_cap & + WMI_HOST_WLAN_5G_CAPABILITY) { + SET_RADIO(&radio, MODE_SMM, BIT(REG_BAND_5G), 0, + mac0_ss_bw_info.mac_tx_stream, 0); + policy_mgr_add_radio_comb(pm_ctx, &radio); + if (mac0_ss_bw_info.support_6ghz_band) { + SET_RADIO(&radio, MODE_SMM, BIT(REG_BAND_6G), + 0, mac0_ss_bw_info.mac_tx_stream, 0); + policy_mgr_add_radio_comb(pm_ctx, &radio); + } + } + return; + } + if ((mac0_ss_bw_info.mac_band_cap & WMI_HOST_WLAN_2G_CAPABILITY) && + (mac1_ss_bw_info.mac_band_cap & WMI_HOST_WLAN_5G_CAPABILITY)) { + SET_RADIO(&radio, MODE_DBS, BIT(REG_BAND_2G), BIT(REG_BAND_5G), + mac0_ss_bw_info.mac_tx_stream, + mac1_ss_bw_info.mac_tx_stream); + policy_mgr_add_radio_comb(pm_ctx, &radio); + if (mac1_ss_bw_info.support_6ghz_band) { + SET_RADIO(&radio, MODE_DBS, BIT(REG_BAND_2G), + BIT(REG_BAND_6G), + mac0_ss_bw_info.mac_tx_stream, + mac1_ss_bw_info.mac_tx_stream); + policy_mgr_add_radio_comb(pm_ctx, &radio); + } + } + if ((mac0_ss_bw_info.mac_band_cap & WMI_HOST_WLAN_5G_CAPABILITY) && + (mac1_ss_bw_info.mac_band_cap & WMI_HOST_WLAN_2G_CAPABILITY)) { + SET_RADIO(&radio, MODE_DBS, BIT(REG_BAND_2G), BIT(REG_BAND_5G), + mac1_ss_bw_info.mac_tx_stream, + mac0_ss_bw_info.mac_tx_stream); + policy_mgr_add_radio_comb(pm_ctx, &radio); + if (mac0_ss_bw_info.support_6ghz_band) { + SET_RADIO(&radio, MODE_DBS, BIT(REG_BAND_2G), + BIT(REG_BAND_6G), + mac1_ss_bw_info.mac_tx_stream, + mac0_ss_bw_info.mac_tx_stream); + policy_mgr_add_radio_comb(pm_ctx, &radio); + } + } + if ((mac0_ss_bw_info.mac_band_cap & WMI_HOST_WLAN_5G_CAPABILITY) && + (mac1_ss_bw_info.mac_band_cap & WMI_HOST_WLAN_5G_CAPABILITY)) { + if (mac0_ss_bw_info.support_6ghz_band) { + SET_RADIO(&radio, MODE_SBS, BIT(REG_BAND_5G), + BIT(REG_BAND_6G), + mac1_ss_bw_info.mac_tx_stream, + mac0_ss_bw_info.mac_tx_stream); + policy_mgr_add_radio_comb(pm_ctx, &radio); + } else if (mac1_ss_bw_info.support_6ghz_band) { + SET_RADIO(&radio, MODE_SBS, BIT(REG_BAND_5G), + BIT(REG_BAND_6G), + mac0_ss_bw_info.mac_tx_stream, + mac1_ss_bw_info.mac_tx_stream); + policy_mgr_add_radio_comb(pm_ctx, &radio); + } + } +} + +static void +policy_mgr_update_24Ghz_freq_info(struct policy_mgr_freq_range *mac_range, + struct wlan_psoc_host_mac_phy_caps *mac_cap) +{ + mac_range->low_2ghz_freq = QDF_MAX(mac_cap->reg_cap_ext.low_2ghz_chan, + wlan_reg_min_24ghz_chan_freq()); + mac_range->high_2ghz_freq = mac_cap->reg_cap_ext.high_2ghz_chan ? + QDF_MIN(mac_cap->reg_cap_ext.high_2ghz_chan, + wlan_reg_max_24ghz_chan_freq()) : + wlan_reg_max_24ghz_chan_freq(); +} + +static void +policy_mgr_update_5Ghz_freq_info(struct policy_mgr_freq_range *mac_range, + struct wlan_psoc_host_mac_phy_caps *mac_cap) +{ + qdf_freq_t max_5g_freq; + + max_5g_freq = wlan_reg_max_6ghz_chan_freq() ? + wlan_reg_max_6ghz_chan_freq() : + wlan_reg_max_5ghz_chan_freq(); + + mac_range->low_5ghz_freq = QDF_MAX(mac_cap->reg_cap_ext.low_5ghz_chan, + wlan_reg_min_5ghz_chan_freq()); + mac_range->high_5ghz_freq = mac_cap->reg_cap_ext.high_5ghz_chan ? + QDF_MIN(mac_cap->reg_cap_ext.high_5ghz_chan, + max_5g_freq) : + max_5g_freq; +} + +static void +policy_mgr_update_freq_info(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct wlan_psoc_host_mac_phy_caps *mac_cap, + enum policy_mgr_mode mode, + uint32_t phy_id) +{ + struct policy_mgr_freq_range *mac_range; + + mac_range = &pm_ctx->hw_mode.freq_range_caps[mode][phy_id]; + if (mac_cap->supported_bands & WMI_HOST_WLAN_2G_CAPABILITY) + policy_mgr_update_24Ghz_freq_info(mac_range, mac_cap); + + if (mac_cap->supported_bands & WMI_HOST_WLAN_5G_CAPABILITY) + policy_mgr_update_5Ghz_freq_info(mac_range, mac_cap); +} + +static QDF_STATUS +policy_mgr_modify_sbs_freq(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t phy_id) +{ + uint8_t shared_phy_id; + struct policy_mgr_freq_range *sbs_mac_range, *shared_mac_range; + struct policy_mgr_freq_range *non_shared_range; + + sbs_mac_range = &pm_ctx->hw_mode.freq_range_caps[MODE_SBS][phy_id]; + + /* + * if SBS mac range has both 2.4 and 5 Ghz range, i e shared phy_id + * keep the range as it is in SBS + */ + if (sbs_mac_range->low_2ghz_freq && sbs_mac_range->low_5ghz_freq) + return QDF_STATUS_SUCCESS; + if (sbs_mac_range->low_2ghz_freq && !sbs_mac_range->low_5ghz_freq) { + policy_mgr_err("Invalid DBS/SBS mode with only 2.4Ghz"); + policy_mgr_dump_freq_range_per_mac(sbs_mac_range, MODE_SBS); + return QDF_STATUS_E_INVAL; + } + + non_shared_range = sbs_mac_range; + /* + * if SBS mac range has only 5Ghz then its the non shared phy, so + * modify the range as per the shared mac. + */ + shared_phy_id = phy_id ? 0 : 1; + shared_mac_range = + &pm_ctx->hw_mode.freq_range_caps[MODE_SBS][shared_phy_id]; + + if (shared_mac_range->low_5ghz_freq > non_shared_range->low_5ghz_freq) { + policy_mgr_debug("High 5Ghz shared"); + /* + * If the shared mac lower 5Ghz frequency is greater than + * non-shared mac lower 5Ghz frequency then the shared mac has + * HIGH 5Ghz shared with 2.4Ghz. So non-shared mac's 5Ghz high + * freq should be less than the shared mac's low 5Ghz freq. + */ + if (non_shared_range->high_5ghz_freq >= + shared_mac_range->low_5ghz_freq) + non_shared_range->high_5ghz_freq = + QDF_MAX(shared_mac_range->low_5ghz_freq - 10, + non_shared_range->low_5ghz_freq); + } else if (shared_mac_range->high_5ghz_freq < + non_shared_range->high_5ghz_freq) { + policy_mgr_debug("LOW 5Ghz shared"); + /* + * If the shared mac high 5Ghz frequency is less than + * non-shared mac high 5Ghz frequency then the shared mac has + * LOW 5Ghz shared with 2.4Ghz So non-shared mac's 5Ghz low + * freq should be greater than the shared mac's high 5Ghz freq. + */ + if (shared_mac_range->high_5ghz_freq >= + non_shared_range->low_5ghz_freq) + non_shared_range->low_5ghz_freq = + QDF_MIN(shared_mac_range->high_5ghz_freq + 10, + non_shared_range->high_5ghz_freq); + } else { + policy_mgr_info("Invalid SBS range with all 5Ghz shared"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +static qdf_freq_t +policy_mgr_get_highest_5ghz_freq_frm_range(struct policy_mgr_freq_range *range) +{ + uint8_t phy_id; + qdf_freq_t highest_freq = 0; + qdf_freq_t max_5g_freq = wlan_reg_max_6ghz_chan_freq() ? + wlan_reg_max_6ghz_chan_freq() : + wlan_reg_max_5ghz_chan_freq(); + + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + if (range[phy_id].high_5ghz_freq > highest_freq) + highest_freq = range[phy_id].high_5ghz_freq; + } + + return highest_freq ? highest_freq : max_5g_freq; +} + +static qdf_freq_t +policy_mgr_get_lowest_5ghz_freq_frm_range(struct policy_mgr_freq_range *range) +{ + uint8_t phy_id; + qdf_freq_t lowest_freq = 0; + + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + if ((!lowest_freq && range[phy_id].low_5ghz_freq) || + (range[phy_id].low_5ghz_freq < lowest_freq)) + lowest_freq = range[phy_id].low_5ghz_freq; + } + + return lowest_freq ? lowest_freq : wlan_reg_min_5ghz_chan_freq(); +} + +static void +policy_mgr_fill_lower_share_sbs_freq(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint16_t sbs_range_sep, + struct policy_mgr_freq_range *ref_freq) +{ + struct policy_mgr_freq_range *lower_sbs_freq_range; + uint8_t phy_id; + + lower_sbs_freq_range = + pm_ctx->hw_mode.freq_range_caps[MODE_SBS_LOWER_SHARE]; + + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + lower_sbs_freq_range[phy_id].low_2ghz_freq = + ref_freq[phy_id].low_2ghz_freq; + lower_sbs_freq_range[phy_id].high_2ghz_freq = + ref_freq[phy_id].high_2ghz_freq; + + /* update for shared mac */ + if (lower_sbs_freq_range[phy_id].low_2ghz_freq) { + lower_sbs_freq_range[phy_id].low_5ghz_freq = + policy_mgr_get_lowest_5ghz_freq_frm_range(ref_freq); + lower_sbs_freq_range[phy_id].high_5ghz_freq = + sbs_range_sep; + } else { + lower_sbs_freq_range[phy_id].low_5ghz_freq = + sbs_range_sep + 10; + lower_sbs_freq_range[phy_id].high_5ghz_freq = + policy_mgr_get_highest_5ghz_freq_frm_range(ref_freq); + } + } +} + +static void +policy_mgr_fill_upper_share_sbs_freq(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint16_t sbs_range_sep, + struct policy_mgr_freq_range *ref_freq) +{ + struct policy_mgr_freq_range *upper_sbs_freq_range; + uint8_t phy_id; + + upper_sbs_freq_range = + pm_ctx->hw_mode.freq_range_caps[MODE_SBS_UPPER_SHARE]; + + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + upper_sbs_freq_range[phy_id].low_2ghz_freq = + ref_freq[phy_id].low_2ghz_freq; + upper_sbs_freq_range[phy_id].high_2ghz_freq = + ref_freq[phy_id].high_2ghz_freq; + + /* update for shared mac */ + if (upper_sbs_freq_range[phy_id].low_2ghz_freq) { + upper_sbs_freq_range[phy_id].low_5ghz_freq = + sbs_range_sep + 10; + upper_sbs_freq_range[phy_id].high_5ghz_freq = + policy_mgr_get_highest_5ghz_freq_frm_range(ref_freq); + } else { + upper_sbs_freq_range[phy_id].low_5ghz_freq = + policy_mgr_get_lowest_5ghz_freq_frm_range(ref_freq); + upper_sbs_freq_range[phy_id].high_5ghz_freq = + sbs_range_sep; + } + } +} + +static bool +policy_mgr_both_phy_range_updated(struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_mode hwmode) +{ + struct policy_mgr_freq_range *mac_range; + uint8_t phy_id; + + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + mac_range = + &pm_ctx->hw_mode.freq_range_caps[hwmode][phy_id]; + /* modify SBS/DBS range only when both phy for DBS are filled */ + if (!mac_range->low_2ghz_freq && !mac_range->low_5ghz_freq) + return false; + } + + return true; +} + +static void +policy_mgr_update_sbs_freq_info(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + uint16_t sbs_range_sep; + struct policy_mgr_freq_range *mac_range; + uint8_t phy_id; + QDF_STATUS status; + + mac_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS]; + + /* + * If sbs_lower_band_end_freq has a value Z, then the frequency range + * will be split using that value. + */ + sbs_range_sep = pm_ctx->hw_mode.sbs_lower_band_end_freq; + if (sbs_range_sep) { + policy_mgr_fill_upper_share_sbs_freq(pm_ctx, sbs_range_sep, + mac_range); + policy_mgr_fill_lower_share_sbs_freq(pm_ctx, sbs_range_sep, + mac_range); + /* Reset the SBS range */ + qdf_mem_zero(mac_range, sizeof(*mac_range) * MAX_MAC); + return; + } + + /* + * If sbs_lower_band_end_freq is not set that means FW will send one + * shared mac range and one non-shared mac range. so update that freq. + */ + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + status = policy_mgr_modify_sbs_freq(pm_ctx, phy_id); + if (QDF_IS_STATUS_ERROR(status)) { + /* Reset the SBS range */ + qdf_mem_zero(mac_range, sizeof(*mac_range) * MAX_MAC); + break; + } + } +} + +static void +policy_mgr_update_dbs_freq_info(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + struct policy_mgr_freq_range *mac_range; + uint8_t phy_id; + + mac_range = pm_ctx->hw_mode.freq_range_caps[MODE_DBS]; + /* Reset 5Ghz range for shared mac for DBS */ + for (phy_id = 0; phy_id < MAX_MAC; phy_id++) { + if (mac_range[phy_id].low_2ghz_freq && + mac_range[phy_id].low_5ghz_freq) { + mac_range[phy_id].low_5ghz_freq = 0; + mac_range[phy_id].high_5ghz_freq = 0; + } + } +} + +static void +policy_mgr_update_mac_freq_info(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum wmi_hw_mode_config_type hw_config_type, + uint32_t phy_id, + struct wlan_psoc_host_mac_phy_caps *mac_cap) +{ + if (phy_id >= MAX_MAC) { + policy_mgr_err("mac more than two not supported: %d", + phy_id); + return; + } + + policy_mgr_debug("hw_mode_cfg: %d mac: %d band: 0x%x, SBS cutoff freq %d, 2Ghz: %d -> %d 5Ghz: %d -> %d", + hw_config_type, phy_id, mac_cap->supported_bands, + pm_ctx->hw_mode.sbs_lower_band_end_freq, + mac_cap->reg_cap_ext.low_2ghz_chan, + mac_cap->reg_cap_ext.high_2ghz_chan, + mac_cap->reg_cap_ext.low_5ghz_chan, + mac_cap->reg_cap_ext.high_5ghz_chan); + + switch (hw_config_type) { + case WMI_HW_MODE_SINGLE: + if (phy_id) { + policy_mgr_debug("MAC Phy 1 is not supported"); + break; + } + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_SMM, phy_id); + break; + + case WMI_HW_MODE_DBS: + case WMI_HW_MODE_DBS_2G_5G: + if (!policy_mgr_both_phy_range_updated(pm_ctx, MODE_DBS)) + policy_mgr_update_freq_info(pm_ctx, mac_cap, + MODE_DBS, phy_id); + break; + case WMI_HW_MODE_DBS_SBS: + case WMI_HW_MODE_DBS_OR_SBS: + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_DBS, phy_id); + /* + * fill SBS only if freq is provided by FW or + * pm_ctx->hw_mode.sbs_lower_band_end_freq is set + */ + if (pm_ctx->hw_mode.sbs_lower_band_end_freq || + mac_cap->reg_cap_ext.low_5ghz_chan || + mac_cap->reg_cap_ext.low_2ghz_chan) + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_SBS, + phy_id); + + /* Modify the DBS list once both phy info are filled */ + if (policy_mgr_both_phy_range_updated(pm_ctx, MODE_DBS)) + policy_mgr_update_dbs_freq_info(pm_ctx); + /* Modify the SBS list once both phy info are filled */ + if (policy_mgr_both_phy_range_updated(pm_ctx, MODE_SBS)) + policy_mgr_update_sbs_freq_info(pm_ctx); + break; + case WMI_HW_MODE_2G_PHYB: + if (phy_id) + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_SMM, + phy_id); + break; + case WMI_HW_MODE_SBS: + case WMI_HW_MODE_SBS_PASSIVE: + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_SBS, phy_id); + /* Modify the SBS Upper Lower list once both phy are filled */ + if (policy_mgr_both_phy_range_updated(pm_ctx, MODE_SBS)) + policy_mgr_update_sbs_freq_info(pm_ctx); + + break; + case WMI_HW_MODE_EMLSR: + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_EMLSR, + phy_id); + break; + case WMI_HW_MODE_AUX_EMLSR_SINGLE: + if (phy_id) { + policy_mgr_debug("MAC Phy 1 is not supported"); + break; + } + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_EMLSR_SINGLE, + phy_id); + break; + case WMI_HW_MODE_AUX_EMLSR_SPLIT: + policy_mgr_update_freq_info(pm_ctx, mac_cap, MODE_EMLSR_SPLIT, + phy_id); + break; + default: + policy_mgr_err("HW mode not defined %d", + hw_config_type); + break; + } +} + +void +policy_mgr_dump_curr_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + uint32_t i; + struct policy_mgr_freq_range *freq_range; + + freq_range = pm_ctx->hw_mode.cur_mac_freq_range; + for (i = 0; i < MAX_MAC; i++) + if (freq_range[i].low_2ghz_freq || freq_range[i].low_5ghz_freq) + policymgr_nofl_debug("PLCY_MGR_FREQ_RANGE_CUR: mac %d: 2Ghz: %d -> %d, 5Ghz: %d -> %d", + i, freq_range[i].low_2ghz_freq, + freq_range[i].high_2ghz_freq, + freq_range[i].low_5ghz_freq, + freq_range[i].high_5ghz_freq); +} + +static const char *policy_mgr_hw_mode_to_str(enum policy_mgr_mode hw_mode) +{ + if (hw_mode >= MODE_HW_MAX) + return "Unknown"; + + switch (hw_mode) { + CASE_RETURN_STRING(MODE_SMM); + CASE_RETURN_STRING(MODE_DBS); + CASE_RETURN_STRING(MODE_SBS); + CASE_RETURN_STRING(MODE_SBS_UPPER_SHARE); + CASE_RETURN_STRING(MODE_SBS_LOWER_SHARE); + CASE_RETURN_STRING(MODE_EMLSR); + CASE_RETURN_STRING(MODE_EMLSR_SINGLE); + CASE_RETURN_STRING(MODE_EMLSR_SPLIT); + default: + return "Unknown"; + } +} + +void +policy_mgr_dump_freq_range_per_mac(struct policy_mgr_freq_range *freq_range, + enum policy_mgr_mode hw_mode) +{ + uint32_t i; + + for (i = 0; i < MAX_MAC; i++) + if (freq_range[i].low_2ghz_freq || freq_range[i].low_5ghz_freq) + policymgr_nofl_debug("PLCY_MGR_FREQ_RANGE: %s(%d): mac %d: 2Ghz: %d -> %d, 5Ghz: %d -> %d", + policy_mgr_hw_mode_to_str(hw_mode), + hw_mode, i, + freq_range[i].low_2ghz_freq, + freq_range[i].high_2ghz_freq, + freq_range[i].low_5ghz_freq, + freq_range[i].high_5ghz_freq); +} + +static void +policy_mgr_dump_hw_modes_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + uint32_t i; + struct policy_mgr_freq_range *freq_range; + + for (i = MODE_SMM; i < MODE_HW_MAX; i++) { + freq_range = pm_ctx->hw_mode.freq_range_caps[i]; + policy_mgr_dump_freq_range_per_mac(freq_range, i); + } +} + +void policy_mgr_dump_sbs_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + uint32_t i; + struct policy_mgr_freq_range *freq_range; + + for (i = MODE_SMM; i < MODE_HW_MAX; i++) { + if ((i == MODE_SBS) || + (pm_ctx->hw_mode.sbs_lower_band_end_freq && + (i == MODE_SBS_LOWER_SHARE || i == MODE_SBS_UPPER_SHARE))) { + freq_range = pm_ctx->hw_mode.freq_range_caps[i]; + policy_mgr_dump_freq_range_per_mac(freq_range, i); + } + } +} + +static bool +policy_mgr_sbs_range_present(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + if (policy_mgr_both_phy_range_updated(pm_ctx, MODE_SBS) || + (pm_ctx->hw_mode.sbs_lower_band_end_freq && + policy_mgr_both_phy_range_updated(pm_ctx, MODE_SBS_LOWER_SHARE) && + policy_mgr_both_phy_range_updated(pm_ctx, MODE_SBS_UPPER_SHARE))) + return true; + + return false; +} + +void +policy_mgr_dump_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + policy_mgr_dump_hw_modes_freq_range(pm_ctx); + policy_mgr_dump_curr_freq_range(pm_ctx); +} + +static void +policy_mgr_update_sbs_lowr_band_end_frq(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct tgt_info *info) +{ + if (wlan_reg_is_5ghz_ch_freq(info->sbs_lower_band_end_freq) || + wlan_reg_is_6ghz_chan_freq(info->sbs_lower_band_end_freq)) + pm_ctx->hw_mode.sbs_lower_band_end_freq = + info->sbs_lower_band_end_freq; +} + +QDF_STATUS policy_mgr_update_hw_mode_list(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl) +{ + struct wlan_psoc_host_mac_phy_caps *tmp; + struct wlan_psoc_host_mac_phy_caps_ext2 *cap; + uint32_t i, j = 0; + enum wmi_hw_mode_config_type hw_config_type; + uint32_t dbs_mode, sbs_mode; + uint64_t emlsr_mode; + struct policy_mgr_mac_ss_bw_info mac0_ss_bw_info = {0}; + struct policy_mgr_mac_ss_bw_info mac1_ss_bw_info = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct tgt_info *info; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + info = &tgt_hdl->info; + if (!info->service_ext_param.num_hw_modes) { + policy_mgr_err("Number of HW modes: %d", + info->service_ext_param.num_hw_modes); + return QDF_STATUS_E_FAILURE; + } + + /* + * This list was updated as part of service ready event. Re-populate + * HW mode list from the device capabilities. + */ + if (pm_ctx->hw_mode.hw_mode_list) { + qdf_mem_free(pm_ctx->hw_mode.hw_mode_list); + pm_ctx->hw_mode.hw_mode_list = NULL; + policy_mgr_debug("DBS list is freed"); + } + + /* Reset old freq ranges */ + qdf_mem_zero(pm_ctx->hw_mode.freq_range_caps, + sizeof(pm_ctx->hw_mode.freq_range_caps)); + qdf_mem_zero(pm_ctx->hw_mode.cur_mac_freq_range, + sizeof(pm_ctx->hw_mode.cur_mac_freq_range)); + pm_ctx->num_dbs_hw_modes = info->service_ext_param.num_hw_modes; + pm_ctx->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*pm_ctx->hw_mode.hw_mode_list) * + pm_ctx->num_dbs_hw_modes); + if (!pm_ctx->hw_mode.hw_mode_list) { + pm_ctx->num_dbs_hw_modes = 0; + return QDF_STATUS_E_NOMEM; + } + pm_ctx->radio_comb_num = 0; + qdf_mem_zero(pm_ctx->radio_combinations, + sizeof(pm_ctx->radio_combinations)); + + policy_mgr_debug("Updated HW mode list: Num modes:%d", + pm_ctx->num_dbs_hw_modes); + + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + /* Update for MAC0 */ + tmp = &info->mac_phy_cap[j++]; + policy_mgr_get_hw_mode_params(tmp, &mac0_ss_bw_info); + dbs_mode = HW_MODE_DBS_NONE; + sbs_mode = HW_MODE_SBS_NONE; + emlsr_mode = HW_MODE_EMLSR_NONE; + mac1_ss_bw_info.mac_tx_stream = 0; + mac1_ss_bw_info.mac_rx_stream = 0; + mac1_ss_bw_info.mac_bw = 0; + + hw_config_type = tmp->hw_mode_config_type; + if (WMI_BECAP_PHY_GET_HW_MODE_CFG(hw_config_type) == + WMI_HW_MODE_EMLSR) + hw_config_type = WMI_HW_MODE_EMLSR; + else if (WMI_BECAP_PHY_GET_HW_MODE_CFG(hw_config_type) == + WMI_HW_MODE_AUX_EMLSR_SINGLE) + hw_config_type = WMI_HW_MODE_AUX_EMLSR_SINGLE; + else if (WMI_BECAP_PHY_GET_HW_MODE_CFG(hw_config_type) == + WMI_HW_MODE_AUX_EMLSR_SPLIT) + hw_config_type = WMI_HW_MODE_AUX_EMLSR_SPLIT; + + policy_mgr_update_mac_freq_info(psoc, pm_ctx, + hw_config_type, + tmp->phy_id, tmp); + + /* SBS and DBS have dual MAC. Upto 2 MACs are considered. */ + if ((hw_config_type == WMI_HW_MODE_DBS) || + (hw_config_type == WMI_HW_MODE_SBS_PASSIVE) || + (hw_config_type == WMI_HW_MODE_SBS) || + (hw_config_type == WMI_HW_MODE_DBS_OR_SBS)) { + /* Update for MAC1 */ + tmp = &info->mac_phy_cap[j++]; + policy_mgr_get_hw_mode_params(tmp, &mac1_ss_bw_info); + policy_mgr_update_mac_freq_info(psoc, pm_ctx, + hw_config_type, + tmp->phy_id, tmp); + if (hw_config_type == WMI_HW_MODE_DBS || + hw_config_type == WMI_HW_MODE_DBS_OR_SBS) + dbs_mode = HW_MODE_DBS; + if (policy_mgr_sbs_range_present(pm_ctx) && + ((hw_config_type == WMI_HW_MODE_SBS_PASSIVE) || + (hw_config_type == WMI_HW_MODE_SBS) || + (hw_config_type == WMI_HW_MODE_DBS_OR_SBS))) + sbs_mode = HW_MODE_SBS; + } else if (hw_config_type == WMI_HW_MODE_EMLSR || + hw_config_type == WMI_HW_MODE_AUX_EMLSR_SPLIT) { + /* eMLSR mode */ + tmp = &info->mac_phy_cap[j++]; + cap = &info->mac_phy_caps_ext2[i]; + wlan_mlme_set_eml_params(psoc, cap); + policy_mgr_get_hw_mode_params(tmp, &mac1_ss_bw_info); + policy_mgr_update_mac_freq_info(psoc, pm_ctx, + hw_config_type, + tmp->phy_id, tmp); + emlsr_mode = HW_MODE_EMLSR; + } else if (hw_config_type == WMI_HW_MODE_AUX_EMLSR_SINGLE) { + /* eMLSR mode */ + cap = &info->mac_phy_caps_ext2[i]; + wlan_mlme_set_eml_params(psoc, cap); + policy_mgr_get_hw_mode_params(tmp, &mac1_ss_bw_info); + emlsr_mode = HW_MODE_EMLSR; + } + + /* Updating HW mode list */ + policy_mgr_set_hw_mode_params(psoc, mac0_ss_bw_info, + mac1_ss_bw_info, i, tmp->hw_mode_id, dbs_mode, + sbs_mode, emlsr_mode); + /* Update radio combination info */ + policy_mgr_update_radio_combination_matrix( + psoc, mac0_ss_bw_info, mac1_ss_bw_info, + dbs_mode, sbs_mode); + } + + /* + * Initializing Current frequency with SMM frequency. + */ + policy_mgr_fill_curr_mac_freq_by_hwmode(pm_ctx, MODE_SMM); + policy_mgr_dump_freq_range(pm_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_update_sbs_freq(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct tgt_info *info; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + info = &tgt_hdl->info; + policy_mgr_debug("sbs_lower_band_end_freq %d", + info->sbs_lower_band_end_freq); + policy_mgr_update_sbs_lowr_band_end_frq(pm_ctx, info); + + policy_mgr_update_hw_mode_list(psoc, tgt_hdl); + + return QDF_STATUS_SUCCESS; +} + +qdf_freq_t policy_mgr_get_sbs_cut_off_freq(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_freq_range *first_mac_range, *second_mac_range; + qdf_freq_t sbs_cut_off_freq = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + if (!policy_mgr_is_hw_sbs_capable(psoc)) + return 0; + + if (pm_ctx->hw_mode.sbs_lower_band_end_freq) + return pm_ctx->hw_mode.sbs_lower_band_end_freq; + /* + * if cutoff freq is not available from FW (i.e SBS is not dynamic) + * get it from SBS freq range + */ + first_mac_range = &pm_ctx->hw_mode.freq_range_caps[MODE_SBS][0]; + + second_mac_range = + &pm_ctx->hw_mode.freq_range_caps[MODE_SBS][1]; + + /* + * SBS range is low 5Ghz shared with 2.4Ghz: The low_5Ghz of shared + * mac will be starting of 5Ghz and low_5Ghz of non-shared mac will be + * the cutoff freq + * + * SBS range is high 5Ghz shared with 2.4Ghz: The low_5Ghz of shared + * mac will be cutoff freq and low_5Ghz of non-shared mac will be + * the starting of 5Ghz + * + * so, maximum of low_5Ghz will be cutoff freq + */ + sbs_cut_off_freq = QDF_MAX(second_mac_range->low_5ghz_freq, + first_mac_range->low_5ghz_freq) - 1; + policy_mgr_debug("sbs cutoff freq %d", sbs_cut_off_freq); + + return sbs_cut_off_freq; +} + +static bool +policy_mgr_2_freq_same_mac_in_freq_range( + struct policy_mgr_psoc_priv_obj *pm_ctx, + struct policy_mgr_freq_range *freq_range, + qdf_freq_t freq_1, qdf_freq_t freq_2) +{ + uint8_t i; + + for (i = 0; i < MAX_MAC; i++) { + if (IS_FREQ_ON_MAC_ID(freq_range, freq_1, i) && + IS_FREQ_ON_MAC_ID(freq_range, freq_2, i)) + return true; + } + + return false; +} + +bool policy_mgr_can_2ghz_share_low_high_5ghz_sbs( + struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + if (pm_ctx->hw_mode.sbs_lower_band_end_freq) + return true; + + return false; +} + +bool +policy_mgr_sbs_24_shared_with_high_5(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + qdf_freq_t sbs_cut_off_freq; + struct policy_mgr_freq_range freq_range; + uint8_t i = 0; + + if (policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx)) + return true; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(pm_ctx->psoc); + if (!sbs_cut_off_freq) { + policy_mgr_err("Invalid cut off freq"); + return false; + } + + for (i = 0; i < MAX_MAC; i++) { + freq_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS][i]; + /* + * if 5 GHZ start freq of this mac is greater than cutoff + * return true + */ + if (freq_range.low_2ghz_freq && freq_range.low_5ghz_freq) { + if (sbs_cut_off_freq < freq_range.low_5ghz_freq) + return true; + } + } + + return false; +} + +bool +policy_mgr_sbs_24_shared_with_low_5(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + qdf_freq_t sbs_cut_off_freq; + struct policy_mgr_freq_range freq_range; + uint8_t i = 0; + + if (policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx)) + return true; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(pm_ctx->psoc); + if (!sbs_cut_off_freq) { + policy_mgr_err("Invalid cut off freq"); + return false; + } + + for (i = 0; i < MAX_MAC; i++) { + freq_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS][i]; + if (freq_range.low_2ghz_freq && freq_range.high_5ghz_freq) { + /* + * if 5 GHZ end freq of this mac is less than cutoff + * return true + */ + if (sbs_cut_off_freq > freq_range.high_5ghz_freq) + return true; + } + } + + return false; +} + +bool +policy_mgr_2_freq_same_mac_in_dbs(struct policy_mgr_psoc_priv_obj *pm_ctx, + qdf_freq_t freq_1, qdf_freq_t freq_2) +{ + struct policy_mgr_freq_range *freq_range; + + /* Return true if non DBS capable HW */ + if (!policy_mgr_is_hw_dbs_capable(pm_ctx->psoc)) + return true; + + freq_range = pm_ctx->hw_mode.freq_range_caps[MODE_DBS]; + return policy_mgr_2_freq_same_mac_in_freq_range(pm_ctx, freq_range, + freq_1, freq_2); +} + +bool +policy_mgr_2_freq_same_mac_in_sbs(struct policy_mgr_psoc_priv_obj *pm_ctx, + qdf_freq_t freq_1, qdf_freq_t freq_2) +{ + struct policy_mgr_freq_range *sbs_low_share; + struct policy_mgr_freq_range *sbs_uppr_share; + struct policy_mgr_freq_range *sbs_range; + + /* Return true if non SBS capable HW */ + if (!policy_mgr_is_hw_sbs_capable(pm_ctx->psoc)) + return true; + + if (policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx)) { + sbs_uppr_share = + pm_ctx->hw_mode.freq_range_caps[MODE_SBS_UPPER_SHARE]; + sbs_low_share = + pm_ctx->hw_mode.freq_range_caps[MODE_SBS_LOWER_SHARE]; + if (policy_mgr_2_freq_same_mac_in_freq_range(pm_ctx, + sbs_low_share, + freq_1, freq_2) || + policy_mgr_2_freq_same_mac_in_freq_range(pm_ctx, + sbs_uppr_share, + freq_1, freq_2)) + return true; + + return false; + } + + sbs_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS]; + + return policy_mgr_2_freq_same_mac_in_freq_range(pm_ctx, sbs_range, + freq_1, freq_2); +} + +static bool +policy_mgr_is_cur_freq_range_sbs(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_freq_range *freq_range; + uint8_t i; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + /* Check if any of the mac is shared */ + for (i = 0 ; i < MAX_MAC; i++) { + freq_range = &pm_ctx->hw_mode.cur_mac_freq_range[i]; + if (freq_range->low_2ghz_freq && freq_range->low_5ghz_freq) + return true; + } + + return false; +} + +bool policy_mgr_2_freq_always_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, qdf_freq_t freq_2) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool is_dbs_mode_same_mac = true; + bool is_sbs_mode_same_mac = true; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + is_dbs_mode_same_mac = + policy_mgr_2_freq_same_mac_in_dbs(pm_ctx, freq_1, freq_2); + + /* if DBS mode leading to same mac, check for SBS mode */ + if (is_dbs_mode_same_mac) + is_sbs_mode_same_mac = + policy_mgr_2_freq_same_mac_in_sbs(pm_ctx, freq_1, + freq_2); + + policy_mgr_rl_debug("freq1 %d freq2 %d: Same mac:: DBS:%d SBS:%d", + freq_1, freq_2, is_dbs_mode_same_mac, + is_sbs_mode_same_mac); + /* + * if in SBS and DBS mode, both is leading to freqs on same mac, + * return true else return false. + */ + if (is_dbs_mode_same_mac && is_sbs_mode_same_mac) + return true; + + return false; +} + +bool policy_mgr_are_2_freq_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, + qdf_freq_t freq_2) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_freq_range *freq_range; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status; + bool cur_range_sbs = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + /* if HW is not DBS return true*/ + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return true; + + /* HW is DBS/SBS capable */ + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return false; + } + + if (hw_mode.dbs_cap || hw_mode.sbs_cap) + cur_range_sbs = policy_mgr_is_cur_freq_range_sbs(psoc); + + freq_range = pm_ctx->hw_mode.cur_mac_freq_range; + /* current HW is DBS OR SBS check current DBS/SBS freq range */ + if (hw_mode.dbs_cap || hw_mode.sbs_cap) { + policy_mgr_rl_debug("freq1 %d freq2 %d dbs_cap %d sbs_cap %d, cur range is sbs %d", + freq_1, freq_2, hw_mode.dbs_cap, + hw_mode.sbs_cap, cur_range_sbs); + return policy_mgr_2_freq_same_mac_in_freq_range(pm_ctx, + freq_range, + freq_1, freq_2); + } + + /* + * If current HW mode is not DBS/SBS, check if in all supported mode + * it they will be on same mac + */ + return policy_mgr_2_freq_always_on_same_mac(psoc, freq_1, freq_2); +} + +static bool +policy_mgr_3_freq_same_mac_in_freq_range( + struct policy_mgr_psoc_priv_obj *pm_ctx, + struct policy_mgr_freq_range *freq_range, + qdf_freq_t freq_1, qdf_freq_t freq_2, + qdf_freq_t freq_3) +{ + uint8_t i; + + for (i = 0 ; i < MAX_MAC; i++) { + if (IS_FREQ_ON_MAC_ID(freq_range, freq_1, i) && + IS_FREQ_ON_MAC_ID(freq_range, freq_2, i) && + IS_FREQ_ON_MAC_ID(freq_range, freq_3, i)) + return true; + } + + return false; +} + +static bool +policy_mgr_3_freq_same_mac_in_sbs(struct policy_mgr_psoc_priv_obj *pm_ctx, + qdf_freq_t freq_1, qdf_freq_t freq_2, + qdf_freq_t freq_3) +{ + struct policy_mgr_freq_range *sbs_low_share; + struct policy_mgr_freq_range *sbs_uppr_share; + struct policy_mgr_freq_range *sbs_range; + + /* Return true if non SBS capable HW */ + if (!policy_mgr_is_hw_sbs_capable(pm_ctx->psoc)) + return true; + + if (pm_ctx->hw_mode.sbs_lower_band_end_freq) { + sbs_uppr_share = + pm_ctx->hw_mode.freq_range_caps[MODE_SBS_UPPER_SHARE]; + sbs_low_share = + pm_ctx->hw_mode.freq_range_caps[MODE_SBS_LOWER_SHARE]; + if (policy_mgr_3_freq_same_mac_in_freq_range(pm_ctx, + sbs_low_share, + freq_1, freq_2, + freq_3) || + policy_mgr_3_freq_same_mac_in_freq_range(pm_ctx, + sbs_uppr_share, + freq_1, freq_2, + freq_3)) + return true; + + return false; + } + + sbs_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS]; + return policy_mgr_3_freq_same_mac_in_freq_range(pm_ctx, sbs_range, + freq_1, freq_2, freq_3); +} + +bool +policy_mgr_3_freq_always_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, qdf_freq_t freq_2, + qdf_freq_t freq_3) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_freq_range *freq_range; + bool is_dbs_mode_same_mac = true; + bool is_sbs_mode_same_mac = true; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + /* if HW is not DBS return true*/ + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return true; + + /* Check for DBS mode first */ + freq_range = pm_ctx->hw_mode.freq_range_caps[MODE_DBS]; + is_dbs_mode_same_mac = + policy_mgr_3_freq_same_mac_in_freq_range(pm_ctx, freq_range, + freq_1, freq_2, + freq_3); + + /* if DBS mode leading to same mac, check for SBS mode */ + if (is_dbs_mode_same_mac) + is_sbs_mode_same_mac = + policy_mgr_3_freq_same_mac_in_sbs(pm_ctx, freq_1, + freq_2, freq_3); + + policy_mgr_rl_debug("freq1 %d freq2 %d freq3 %d: Same mac:: DBS:%d SBS:%d", + freq_1, freq_2, freq_3, is_dbs_mode_same_mac, + is_sbs_mode_same_mac); + /* + * if in SBS and DBS mode, both is leading to freqs on same mac, + * return true else return false. + */ + if (is_dbs_mode_same_mac && is_sbs_mode_same_mac) + return true; + + return false; +} + +bool +policy_mgr_are_3_freq_on_same_mac(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq_1, qdf_freq_t freq_2, + qdf_freq_t freq_3) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_freq_range *freq_range; + QDF_STATUS status; + struct policy_mgr_hw_mode_params hw_mode; + bool cur_range_sbs = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + /* if HW is not DBS return true*/ + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return true; + + /* HW is DBS/SBS capable, get current HW mode */ + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("policy_mgr_get_current_hw_mode failed"); + return false; + } + if (hw_mode.dbs_cap || hw_mode.sbs_cap) + cur_range_sbs = policy_mgr_is_cur_freq_range_sbs(psoc); + + freq_range = pm_ctx->hw_mode.cur_mac_freq_range; + + /* current HW is DBS OR SBS check current DBS/SBS freq range */ + if (hw_mode.dbs_cap || hw_mode.sbs_cap) { + policy_mgr_rl_debug("freq1 %d freq2 %d freq3 %d dbs_cap %d sbs_cap %d, cur range is sbs %d", + freq_1, freq_2, freq_3, hw_mode.dbs_cap, + hw_mode.sbs_cap, cur_range_sbs); + return policy_mgr_3_freq_same_mac_in_freq_range(pm_ctx, + freq_range, + freq_1, freq_2, freq_3); + } + /* + * If current HW mode is not DBS/SBS, check if in all supported mode + * it they will be on same mac + */ + return policy_mgr_3_freq_always_on_same_mac(psoc, freq_1, freq_2, + freq_3); +} + +#ifdef FEATURE_FOURTH_CONNECTION +static void +policy_mgr_get_mac_freq_list(struct policy_mgr_freq_range *freq_range, + uint8_t mac_id, + uint8_t mac_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS], + uint8_t mac_mode_list[MAX_NUMBER_OF_CONC_CONNECTIONS], + uint8_t *mac_freq_num, + qdf_freq_t freq_1, enum policy_mgr_con_mode mode_1, + qdf_freq_t freq_2, enum policy_mgr_con_mode mode_2, + qdf_freq_t freq_3, enum policy_mgr_con_mode mode_3, + qdf_freq_t freq_4, enum policy_mgr_con_mode mode_4) +{ + uint8_t j = 0; + + if (freq_1 && IS_FREQ_ON_MAC_ID(freq_range, freq_1, mac_id)) { + mac_freq_list[j] = freq_1; + mac_mode_list[j++] = mode_1; + } + if (freq_2 && IS_FREQ_ON_MAC_ID(freq_range, freq_2, mac_id)) { + mac_freq_list[j] = freq_2; + mac_mode_list[j++] = mode_2; + } + if (freq_3 && IS_FREQ_ON_MAC_ID(freq_range, freq_3, mac_id)) { + mac_freq_list[j] = freq_3; + mac_mode_list[j++] = mode_3; + } + if (freq_4 && IS_FREQ_ON_MAC_ID(freq_range, freq_4, mac_id)) { + mac_freq_list[j] = freq_4; + mac_mode_list[j++] = mode_4; + } + + *mac_freq_num = j; +} + +static bool +policy_mgr_is_supported_hw_mode(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_mode hw_mode) +{ + if (hw_mode == MODE_SMM) + return true; + + if (hw_mode == MODE_DBS) + return policy_mgr_is_hw_dbs_capable(psoc); + + if (hw_mode == MODE_SBS_UPPER_SHARE || + hw_mode == MODE_SBS_LOWER_SHARE) + return policy_mgr_is_hw_sbs_capable(psoc) && + pm_ctx->hw_mode.sbs_lower_band_end_freq; + + if (hw_mode == MODE_SBS) + return policy_mgr_is_hw_sbs_capable(psoc); + + return false; +} + +static bool +policy_mgr_mac_freq_list_allow(uint8_t mac_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS], + uint8_t mac_mode_list[MAX_NUMBER_OF_CONC_CONNECTIONS], + uint8_t mac_freq_num) +{ + uint8_t sta = 0, ap = 0, i; + + switch (mac_freq_num) { + case 1: + case 2: + return true; + case 3: + /* If 3 vifs are active in same mac, target only support: + * 3 vifs are in SCC and 3 vifs are : + * 1 STA + 2 APs, or 3 APs + */ + if (mac_freq_list[0] != mac_freq_list[1] || + mac_freq_list[0] != mac_freq_list[2]) + return false; + for (i = 0; i < mac_freq_num; i++) { + if (mac_mode_list[i] == PM_STA_MODE || + mac_mode_list[i] == PM_P2P_CLIENT_MODE) + sta++; + else + ap++; + } + + if (sta == 1 && ap == 2) + return true; + if (ap == 3) + return true; + return false; + default: + return false; + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +policy_mgr_ml_sta_active_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq, + enum policy_mgr_con_mode mode, + uint32_t ext_flags, + qdf_freq_t *ml_sta_link0_freq, + qdf_freq_t *ml_sta_link1_freq) +{ + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0; + uint8_t num_active_ml_sta; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + union conc_ext_flag conc_ext_flags; + + conc_ext_flags.value = ext_flags; + /* find the two active ml sta home channels */ + policy_mgr_get_ml_sta_info_psoc(psoc, &num_ml_sta, + &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, + NULL, NULL, NULL); + if (num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_disabled_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_ml_sta <= num_disabled_ml_sta) { + if (num_ml_sta || num_disabled_ml_sta) + policy_mgr_rl_debug("unexpected ml sta num %d %d", + num_ml_sta, num_disabled_ml_sta); + return; + } + num_active_ml_sta = num_ml_sta; + if (num_ml_sta >= num_disabled_ml_sta) + num_active_ml_sta = num_ml_sta - num_disabled_ml_sta; + if (num_active_ml_sta > 1) { + *ml_sta_link0_freq = ml_freq_lst[0]; + *ml_sta_link1_freq = ml_freq_lst[1]; + } else if (num_active_ml_sta > 0 && conc_ext_flags.mlo && + mode == PM_STA_MODE) { + *ml_sta_link0_freq = ml_freq_lst[0]; + *ml_sta_link1_freq = ch_freq; + } +} +#else +static void +policy_mgr_ml_sta_active_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq, + enum policy_mgr_con_mode mode, + uint32_t ext_flags, + qdf_freq_t *ml_sta_link0_freq, + qdf_freq_t *ml_sta_link1_freq) +{ +} +#endif + +bool +policy_mgr_allow_4th_new_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t ch_freq, + enum policy_mgr_con_mode mode, + uint32_t ext_flags) +{ + struct policy_mgr_conc_connection_info *conn = pm_conc_connection_list; + uint8_t mac_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t mac_mode_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t mac_freq_num; + struct policy_mgr_psoc_priv_obj *pm_ctx; + qdf_freq_t ml_sta_link0_freq = 0; + qdf_freq_t ml_sta_link1_freq = 0; + uint8_t i, j; + struct policy_mgr_freq_range *freq_range; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + /* if HW is not DBS return false */ + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return false; + + /* Find the two active ml sta home channels */ + policy_mgr_ml_sta_active_freq(psoc, ch_freq, mode, ext_flags, + &ml_sta_link0_freq, + &ml_sta_link1_freq); + + /* Check if any hw mode can support the 4th channel frequency + * and device mode. + */ + for (j = 0; j < MODE_HW_MAX; j++) { + if (!policy_mgr_is_supported_hw_mode(psoc, pm_ctx, j)) + continue; + freq_range = pm_ctx->hw_mode.freq_range_caps[j]; + + /* If ml sta present, the two links should be in + * different mac always. Skip the hw mode which + * causes they in same mac. + */ + if (ml_sta_link0_freq && ml_sta_link1_freq && + policy_mgr_2_freq_same_mac_in_freq_range(pm_ctx, + freq_range, + ml_sta_link0_freq, + ml_sta_link1_freq)) + continue; + for (i = 0; i < MAX_MAC; i++) { + /* Get the freq list which are in the MAC + * supported freq range. + */ + policy_mgr_get_mac_freq_list( + freq_range, + i, + mac_freq_list, mac_mode_list, &mac_freq_num, + conn[0].freq, conn[0].mode, + conn[1].freq, conn[1].mode, + conn[2].freq, conn[2].mode, + ch_freq, mode); + + /* Check the freq & mode list support or not in the + * MAC. + */ + if (!policy_mgr_mac_freq_list_allow( + mac_freq_list, mac_mode_list, mac_freq_num)) + break; + } + + /* If the frequency/mode combination meet requirement in the + * hw mode, then the 4th new ch_freq/mode are allowed to start + * in this hw mode. + */ + if (i == MAX_MAC) { + policy_mgr_rl_debug("new freq %d mode %s is allowed in hw mode %s", + ch_freq, + device_mode_to_string(mode), + policy_mgr_hw_mode_to_str(j)); + return true; + } + } + policy_mgr_debug("the 4th new freq %d mode %s is not allowed in any hw mode", + ch_freq, device_mode_to_string(mode)); + + return false; +} +#endif + +bool policy_mgr_are_sbs_chan(struct wlan_objmgr_psoc *psoc, qdf_freq_t freq_1, + qdf_freq_t freq_2) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + if (!policy_mgr_is_hw_sbs_capable(psoc)) + return false; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq_1) || + WLAN_REG_IS_24GHZ_CH_FREQ(freq_2)) + return false; + + return !policy_mgr_2_freq_same_mac_in_sbs(pm_ctx, freq_1, freq_2); +} + +bool policy_mgr_is_current_hwmode_sbs(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_hw_mode_params hw_mode; + + if (!policy_mgr_is_hw_sbs_capable(psoc)) + return false; + + if (QDF_STATUS_SUCCESS != + policy_mgr_get_current_hw_mode(psoc, &hw_mode)) + return false; + + if (hw_mode.sbs_cap && policy_mgr_is_cur_freq_range_sbs(psoc)) + return true; + + return false; +} + +void policy_mgr_init_dbs_hw_mode(struct wlan_objmgr_psoc *psoc, + uint32_t num_dbs_hw_modes, + uint32_t *ev_wlan_dbs_hw_mode_list) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + pm_ctx->num_dbs_hw_modes = num_dbs_hw_modes; + pm_ctx->hw_mode.hw_mode_list = + qdf_mem_malloc(sizeof(*pm_ctx->hw_mode.hw_mode_list) * + pm_ctx->num_dbs_hw_modes); + if (!pm_ctx->hw_mode.hw_mode_list) { + pm_ctx->num_dbs_hw_modes = 0; + return; + } + + qdf_mem_copy(pm_ctx->hw_mode.hw_mode_list, + ev_wlan_dbs_hw_mode_list, + (sizeof(*pm_ctx->hw_mode.hw_mode_list) * + pm_ctx->num_dbs_hw_modes)); + + policy_mgr_dump_dbs_hw_mode(psoc); +} + +void policy_mgr_dump_dbs_hw_mode(struct wlan_objmgr_psoc *psoc) +{ + uint32_t i; + uint32_t param; + uint32_t param1; + + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + policy_mgr_debug("old_hw_mode_index=%d, new_hw_mode_index=%d", + pm_ctx->old_hw_mode_index, pm_ctx->new_hw_mode_index); + + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + param1 = pm_ctx->hw_mode.hw_mode_list[i] >> 32; + policy_mgr_debug("[%d] 0x%x 0x%x", i, param, param1); + policy_mgr_debug("[%d]-MAC0: tx_ss:%d rx_ss:%d bw_idx:%d band_cap:%d", + i, + POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param), + POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param), + POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param), + POLICY_MGR_HW_MODE_MAC0_BAND_GET(param)); + policy_mgr_debug("[%d]-MAC1: tx_ss:%d rx_ss:%d bw_idx:%d", + i, + POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param), + POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param), + POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(param)); + policy_mgr_debug("[%d] DBS:%d SBS:%d hw_mode_id:%d", i, + POLICY_MGR_HW_MODE_DBS_MODE_GET(param), + POLICY_MGR_HW_MODE_SBS_MODE_GET(param), + POLICY_MGR_HW_MODE_ID_GET(param)); + } +} + +void policy_mgr_init_dbs_config(struct wlan_objmgr_psoc *psoc, + uint32_t scan_config, uint32_t fw_config) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t dual_mac_feature; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + pm_ctx->dual_mac_cfg.cur_scan_config = 0; + pm_ctx->dual_mac_cfg.cur_fw_mode_config = 0; + + dual_mac_feature = pm_ctx->cfg.dual_mac_feature; + /* If dual mac features are disabled in the INI, we + * need not proceed further + */ + if (dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) { + policy_mgr_err("Disabling dual mac capabilities"); + /* All capabilities are initialized to 0. We can return */ + goto done; + } + + /* Initialize concurrent_scan_config_bits with default FW value */ + WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET( + pm_ctx->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_GET(scan_config)); + WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_SET( + pm_ctx->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_SYNC_DBS_SCAN_GET(scan_config)); + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET( + pm_ctx->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_GET(scan_config)); + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_SET( + pm_ctx->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config)); + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_SET( + pm_ctx->dual_mac_cfg.cur_scan_config, + WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config)); + + /* Initialize fw_mode_config_bits with default FW value */ + WMI_DBS_FW_MODE_CFG_DBS_SET( + pm_ctx->dual_mac_cfg.cur_fw_mode_config, + WMI_DBS_FW_MODE_CFG_DBS_GET(fw_config)); + WMI_DBS_FW_MODE_CFG_AGILE_DFS_SET( + pm_ctx->dual_mac_cfg.cur_fw_mode_config, + WMI_DBS_FW_MODE_CFG_AGILE_DFS_GET(fw_config)); + WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET( + pm_ctx->dual_mac_cfg.cur_fw_mode_config, + WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_GET(fw_config)); +done: + /* Initialize the previous scan/fw mode config */ + pm_ctx->dual_mac_cfg.prev_scan_config = + pm_ctx->dual_mac_cfg.cur_scan_config; + pm_ctx->dual_mac_cfg.prev_fw_mode_config = + pm_ctx->dual_mac_cfg.cur_fw_mode_config; + + policy_mgr_debug("cur_scan_config:%x cur_fw_mode_config:%x", + pm_ctx->dual_mac_cfg.cur_scan_config, + pm_ctx->dual_mac_cfg.cur_fw_mode_config); +} + +void policy_mgr_init_sbs_fw_config(struct wlan_objmgr_psoc *psoc, + uint32_t fw_config) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool sbs_enabled; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + /* + * If SBS is not enabled from ini, no need to set SBS bits in fw config + */ + sbs_enabled = pm_ctx->cfg.sbs_enable; + if (!sbs_enabled) { + policy_mgr_debug("SBS not enabled from ini"); + return; + } + + /* Initialize fw_mode_config_bits with default FW value */ + WMI_DBS_FW_MODE_CFG_ASYNC_SBS_SET( + pm_ctx->dual_mac_cfg.cur_fw_mode_config, + WMI_DBS_FW_MODE_CFG_ASYNC_SBS_GET(fw_config)); + + policy_mgr_debug("fw_mode config updated from %x to %x", + pm_ctx->dual_mac_cfg.prev_fw_mode_config, + pm_ctx->dual_mac_cfg.cur_fw_mode_config); + /* Initialize the previous scan/fw mode config */ + pm_ctx->dual_mac_cfg.prev_fw_mode_config = + pm_ctx->dual_mac_cfg.cur_fw_mode_config; +} + +void policy_mgr_update_dbs_scan_config(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + pm_ctx->dual_mac_cfg.prev_scan_config = + pm_ctx->dual_mac_cfg.cur_scan_config; + pm_ctx->dual_mac_cfg.cur_scan_config = + pm_ctx->dual_mac_cfg.req_scan_config; +} + +void policy_mgr_update_dbs_fw_config(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + pm_ctx->dual_mac_cfg.prev_fw_mode_config = + pm_ctx->dual_mac_cfg.cur_fw_mode_config; + pm_ctx->dual_mac_cfg.cur_fw_mode_config = + pm_ctx->dual_mac_cfg.req_fw_mode_config; +} + +void policy_mgr_update_dbs_req_config(struct wlan_objmgr_psoc *psoc, + uint32_t scan_config, uint32_t fw_mode_config) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + pm_ctx->dual_mac_cfg.req_scan_config = scan_config; + pm_ctx->dual_mac_cfg.req_fw_mode_config = fw_mode_config; +} + +bool policy_mgr_get_dbs_plus_agile_scan_config(struct wlan_objmgr_psoc *psoc) +{ + uint32_t scan_config; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_SCAN_GET(scan_config); +} + +bool policy_mgr_get_single_mac_scan_with_dfs_config( + struct wlan_objmgr_psoc *psoc) +{ + uint32_t scan_config; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return false; + + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + /* We take that it is disabled and proceed */ + return false; + } + scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + + return WMI_DBS_CONC_SCAN_CFG_AGILE_DFS_SCAN_GET(scan_config); +} + +int8_t policy_mgr_get_num_dbs_hw_modes(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return -EINVAL; + } + return pm_ctx->num_dbs_hw_modes; +} + +bool policy_mgr_find_if_fw_supports_dbs(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wmi_unified *wmi_handle; + bool dbs_support; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return false; + } + dbs_support = + wmi_service_enabled(wmi_handle, + wmi_service_dual_band_simultaneous_support); + + /* The agreement with FW is that: To know if the target is DBS + * capable, DBS needs to be supported both in the HW mode list + * and in the service ready event + */ + if (!dbs_support) + return false; + + return true; +} + +bool policy_mgr_find_if_hwlist_has_dbs(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t param, i, found = 0; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + if (POLICY_MGR_HW_MODE_DBS_MODE_GET(param)) { + found = 1; + break; + } + } + if (found) + return true; + + return false; +} + +static bool policy_mgr_find_if_hwlist_has_sbs(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t param, i; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + if (POLICY_MGR_HW_MODE_SBS_MODE_GET(param)) { + return true; + } + } + + return false; +} + +bool policy_mgr_is_dbs_scan_allowed(struct wlan_objmgr_psoc *psoc) +{ + uint8_t dbs_type = DISABLE_DBS_CXN_AND_SCAN; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (!policy_mgr_find_if_fw_supports_dbs(psoc) || + !policy_mgr_find_if_hwlist_has_dbs(psoc)) + return false; + + policy_mgr_get_dual_mac_feature(psoc, &dbs_type); + /* + * If DBS support for scan is disabled through INI then DBS is not + * supported for scan. + * + * For DBS scan check the INI value explicitly + */ + switch (dbs_type) { + case DISABLE_DBS_CXN_AND_SCAN: + case ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN: + return false; + default: + return true; + } +} + +bool policy_mgr_is_hw_dbs_capable(struct wlan_objmgr_psoc *psoc) +{ + if (!policy_mgr_is_dbs_enable(psoc)) + return false; + + if (!policy_mgr_find_if_fw_supports_dbs(psoc)) + return false; + + if (!policy_mgr_find_if_hwlist_has_dbs(psoc)) { + policymgr_nofl_debug("HW mode list has no DBS"); + return false; + } + + return true; +} + +bool policy_mgr_is_hw_emlsr_capable(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint64_t param, i; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + if (POLICY_MGR_HW_MODE_EMLSR_MODE_GET(param)) + return true; + } + + return false; +} + +bool policy_mgr_is_current_hwmode_dbs(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_hw_mode_params hw_mode; + + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return false; + + if (QDF_STATUS_SUCCESS != policy_mgr_get_current_hw_mode(psoc, + &hw_mode)) + return false; + + if (!hw_mode.dbs_cap) + return false; + + /* sbs is not enabled and dbs_cap is set return true */ + if (!policy_mgr_is_hw_sbs_capable(psoc)) + return true; + + /* sbs is enabled and dbs_cap is set then check the freq range */ + if (!policy_mgr_is_cur_freq_range_sbs(psoc)) + return true; + + return false; +} + +bool policy_mgr_is_pcl_weightage_required(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct dual_sta_policy *dual_sta_policy; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return true; + + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + + if (dual_sta_policy->concurrent_sta_policy == + QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY && + dual_sta_policy->primary_vdev_id != WLAN_UMAC_VDEV_ID_MAX) { + return false; + } + + return true; +} + +bool policy_mgr_is_interband_mcc_supported(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wmi_unified *wmi_handle; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return false; + } + + return !wmi_service_enabled(wmi_handle, + wmi_service_no_interband_mcc_support); +} + +static bool policy_mgr_is_sbs_enable(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + /* + * if gEnableSBS is not set then policy_mgr_init_sbs_fw_config won't + * enable Async SBS fw config bit + */ + if (WMI_DBS_FW_MODE_CFG_ASYNC_SBS_GET( + pm_ctx->dual_mac_cfg.cur_fw_mode_config)) + return true; + + return false; +} + +bool policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc) +{ + if (!policy_mgr_is_sbs_enable(psoc)) { + policy_mgr_rl_debug("SBS INI is disabled"); + return false; + } + + if (!policy_mgr_find_if_fw_supports_dbs(psoc)) { + policy_mgr_rl_debug("fw doesn't support dual band"); + return false; + } + + if (!policy_mgr_find_if_hwlist_has_sbs(psoc)) { + policy_mgr_rl_debug("HW mode list has no SBS"); + return false; + } + + return true; +} + +QDF_STATUS policy_mgr_get_dbs_hw_modes(struct wlan_objmgr_psoc *psoc, + bool *one_by_one_dbs, bool *two_by_two_dbs) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i; + int8_t found_one_by_one = -EINVAL, found_two_by_two = -EINVAL; + uint32_t conf1_tx_ss, conf1_rx_ss; + uint32_t conf2_tx_ss, conf2_rx_ss; + + *one_by_one_dbs = false; + *two_by_two_dbs = false; + + if (policy_mgr_is_hw_dbs_capable(psoc) == false) { + policy_mgr_rl_debug("HW is not DBS capable"); + /* Caller will understand that DBS is disabled */ + return QDF_STATUS_SUCCESS; + + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + /* To check 1x1 capability */ + policy_mgr_get_tx_rx_ss_from_config(HW_MODE_SS_1x1, + &conf1_tx_ss, &conf1_rx_ss); + /* To check 2x2 capability */ + policy_mgr_get_tx_rx_ss_from_config(HW_MODE_SS_2x2, + &conf2_tx_ss, &conf2_rx_ss); + + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + uint32_t t_conf0_tx_ss, t_conf0_rx_ss; + uint32_t t_conf1_tx_ss, t_conf1_rx_ss; + uint32_t dbs_mode; + + t_conf0_tx_ss = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + t_conf0_rx_ss = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + t_conf1_tx_ss = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + t_conf1_rx_ss = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + dbs_mode = POLICY_MGR_HW_MODE_DBS_MODE_GET( + pm_ctx->hw_mode.hw_mode_list[i]); + + if (((((t_conf0_tx_ss == conf1_tx_ss) && + (t_conf0_rx_ss == conf1_rx_ss)) || + ((t_conf1_tx_ss == conf1_tx_ss) && + (t_conf1_rx_ss == conf1_rx_ss))) && + (dbs_mode == HW_MODE_DBS)) && + (found_one_by_one < 0)) { + found_one_by_one = i; + policy_mgr_debug("1x1 hw_mode index %d found", i); + /* Once an entry is found, need not check for 1x1 + * again + */ + continue; + } + + if (((((t_conf0_tx_ss == conf2_tx_ss) && + (t_conf0_rx_ss == conf2_rx_ss)) || + ((t_conf1_tx_ss == conf2_tx_ss) && + (t_conf1_rx_ss == conf2_rx_ss))) && + (dbs_mode == HW_MODE_DBS)) && + (found_two_by_two < 0)) { + found_two_by_two = i; + policy_mgr_debug("2x2 hw_mode index %d found", i); + /* Once an entry is found, need not check for 2x2 + * again + */ + continue; + } + } + + if (found_one_by_one >= 0) + *one_by_one_dbs = true; + if (found_two_by_two >= 0) + *two_by_two_dbs = true; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_current_hw_mode(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_hw_mode_params *hw_mode) +{ + QDF_STATUS status; + uint32_t old_hw_index = 0, new_hw_index = 0; + + status = policy_mgr_get_old_and_new_hw_index(psoc, &old_hw_index, + &new_hw_index); + if (QDF_STATUS_SUCCESS != status) { + policy_mgr_err("Failed to get HW mode index"); + return QDF_STATUS_E_FAILURE; + } + + if (new_hw_index == POLICY_MGR_DEFAULT_HW_MODE_INDEX) { + policy_mgr_err("HW mode is not yet initialized"); + return QDF_STATUS_E_FAILURE; + } + + status = policy_mgr_get_hw_mode_from_idx(psoc, new_hw_index, hw_mode); + if (QDF_STATUS_SUCCESS != status) { + policy_mgr_err("Failed to get HW mode index"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_dbs_enable(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) { + policy_mgr_rl_debug("DBS is disabled from ini"); + return false; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (WMI_DBS_FW_MODE_CFG_DBS_GET( + pm_ctx->dual_mac_cfg.cur_fw_mode_config)) + return true; + + return false; +} + +bool policy_mgr_is_hw_dbs_2x2_capable(struct wlan_objmgr_psoc *psoc) +{ + struct dbs_nss nss_dbs = {0}; + uint32_t nss; + + nss = policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs); + if (nss >= HW_MODE_SS_2x2 && (nss_dbs.mac0_ss == nss_dbs.mac1_ss)) + return true; + else + return false; +} + +bool policy_mgr_is_hw_dbs_required_for_band(struct wlan_objmgr_psoc *psoc, + enum hw_mode_mac_band_cap band) +{ + struct dbs_nss nss_dbs = {0}; + uint32_t nss; + + nss = policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs); + if (nss >= HW_MODE_SS_1x1 && nss_dbs.mac0_ss >= nss_dbs.mac1_ss && + !(nss_dbs.single_mac0_band_cap & band)) + return true; + else + return false; +} + +bool policy_mgr_is_dp_hw_dbs_capable(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_find_if_hwlist_has_dbs(psoc); +} + +/* + * policy_mgr_is_2x2_1x1_dbs_capable() - check 2x2+1x1 DBS supported or not + * @psoc: PSOC object data + * + * This routine is called to check 2x2 5G + 1x1 2G (DBS1) or + * 2x2 2G + 1x1 5G (DBS2) support or not. + * Either DBS1 or DBS2 supported + * + * Return: true/false + */ +bool policy_mgr_is_2x2_1x1_dbs_capable(struct wlan_objmgr_psoc *psoc) +{ + struct dbs_nss nss_dbs; + uint32_t nss; + + nss = policy_mgr_get_hw_dbs_nss(psoc, &nss_dbs); + if (nss >= HW_MODE_SS_2x2 && (nss_dbs.mac0_ss > nss_dbs.mac1_ss)) + return true; + else + return false; +} + +/* + * policy_mgr_is_2x2_5G_1x1_2G_dbs_capable() - check Genoa DBS1 enabled or not + * @psoc: PSOC object data + * + * This routine is called to check support DBS1 or not. + * Notes: DBS1: 2x2 5G + 1x1 2G. + * This function will call policy_mgr_get_hw_mode_idx_from_dbs_hw_list to match + * the HW mode from hw mode list. The parameters will also be matched to + * 2x2 5G +2x2 2G HW mode. But firmware will not report 2x2 5G + 2x2 2G alone + * with 2x2 5G + 1x1 2G at same time. So, it is safe to find DBS1 with + * policy_mgr_get_hw_mode_idx_from_dbs_hw_list. + * + * Return: true/false + */ +bool policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_is_2x2_1x1_dbs_capable(psoc) && + (policy_mgr_get_hw_mode_idx_from_dbs_hw_list( + psoc, + HW_MODE_SS_2x2, + HW_MODE_80_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_MAC_BAND_5G, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE) >= 0); +} + +/* + * policy_mgr_is_2x2_2G_1x1_5G_dbs_capable() - check Genoa DBS2 enabled or not + * @psoc: PSOC object data + * + * This routine is called to check support DBS2 or not. + * Notes: DBS2: 2x2 2G + 1x1 5G + * + * Return: true/false + */ +bool policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_is_2x2_1x1_dbs_capable(psoc) && + (policy_mgr_get_hw_mode_idx_from_dbs_hw_list( + psoc, + HW_MODE_SS_2x2, + HW_MODE_40_MHZ, + HW_MODE_SS_1x1, HW_MODE_40_MHZ, + HW_MODE_MAC_BAND_2G, + HW_MODE_DBS, + HW_MODE_AGILE_DFS_NONE, + HW_MODE_SBS_NONE) >= 0); +} + +uint32_t policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc) +{ + uint32_t conn_index, count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use) + count++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +uint32_t +policy_mgr_get_connection_count_with_mlo(struct wlan_objmgr_psoc *psoc) +{ + uint32_t conn_index, count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum policy_mgr_con_mode mode; + bool is_mlo = false, count_mlo = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use) { + is_mlo = policy_mgr_is_ml_vdev_id(psoc, + pm_conc_connection_list[conn_index].vdev_id); + mode = pm_conc_connection_list[conn_index].mode; + if (is_mlo && (mode == PM_STA_MODE)) { + if (!count_mlo) { + count_mlo = true; + count++; + } + } else { + count++; + } + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +uint32_t policy_mgr_mode_specific_vdev_id(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode) +{ + uint32_t conn_index = 0; + uint32_t vdev_id = WLAN_INVALID_VDEV_ID; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return vdev_id; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* + * Note: This gives you the first vdev id of the mode type in a + * sta+sta or sap+sap or p2p + p2p case + */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].mode == mode) && + pm_conc_connection_list[conn_index].in_use) { + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return vdev_id; +} + +uint32_t policy_mgr_mode_get_macid_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + uint32_t conn_index = 0; + uint32_t mac_id = 0xFF; + enum policy_mgr_con_mode mode; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return vdev_id; + } + mode = policy_mgr_con_mode_by_vdev_id(psoc, vdev_id); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].mode == mode) && + pm_conc_connection_list[conn_index].in_use && + vdev_id == pm_conc_connection_list[conn_index].vdev_id) { + mac_id = pm_conc_connection_list[conn_index].mac; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return mac_id; +} + +uint32_t policy_mgr_mode_specific_connection_count( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *list) +{ + uint32_t conn_index = 0, count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].mode == mode) && + pm_conc_connection_list[conn_index].in_use) { + if (list) + list[count] = conn_index; + count++; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +uint32_t policy_mgr_get_sap_mode_count(struct wlan_objmgr_psoc *psoc, + uint32_t *list) +{ + uint32_t count; + + count = policy_mgr_mode_specific_connection_count(psoc, PM_SAP_MODE, + list); + + count += policy_mgr_mode_specific_connection_count( + psoc, + PM_LL_LT_SAP_MODE, + list ? &list[count] : NULL); + return count; +} + +uint32_t policy_mgr_get_beaconing_mode_count(struct wlan_objmgr_psoc *psoc, + uint32_t *list) +{ + uint32_t count; + + count = policy_mgr_get_sap_mode_count(psoc, list); + + count += policy_mgr_mode_specific_connection_count( + psoc, + PM_P2P_GO_MODE, + list ? &list[count] : NULL); + return count; +} + +QDF_STATUS policy_mgr_check_conn_with_mode_and_vdev_id( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, + uint32_t vdev_id) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return qdf_status; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if ((pm_conc_connection_list[conn_index].mode == mode) && + (pm_conc_connection_list[conn_index].vdev_id == vdev_id)) { + qdf_status = QDF_STATUS_SUCCESS; + break; + } + conn_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return qdf_status; +} + +void policy_mgr_soc_set_dual_mac_cfg_cb(enum set_hw_mode_status status, + uint32_t scan_config, + uint32_t fw_mode_config) +{ + policy_mgr_debug("Status:%d for scan_config:%x fw_mode_config:%x", + status, scan_config, fw_mode_config); +} + +void policy_mgr_set_dual_mac_scan_config(struct wlan_objmgr_psoc *psoc, + uint8_t dbs_val, + uint8_t dbs_plus_agile_scan_val, + uint8_t single_mac_scan_with_dbs_val) +{ + struct policy_mgr_dual_mac_config cfg; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + /* Any non-zero positive value is treated as 1 */ + if (dbs_val != 0) + dbs_val = 1; + if (dbs_plus_agile_scan_val != 0) + dbs_plus_agile_scan_val = 1; + if (single_mac_scan_with_dbs_val != 0) + single_mac_scan_with_dbs_val = 1; + + status = policy_mgr_get_updated_scan_config(psoc, &cfg.scan_config, + dbs_val, + dbs_plus_agile_scan_val, + single_mac_scan_with_dbs_val); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("policy_mgr_get_updated_scan_config failed %d", + status); + return; + } + + status = policy_mgr_get_updated_fw_mode_config(psoc, + &cfg.fw_mode_config, + policy_mgr_get_dbs_config(psoc), + policy_mgr_get_agile_dfs_config(psoc)); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("policy_mgr_get_updated_fw_mode_config failed %d", + status); + return; + } + + cfg.set_dual_mac_cb = policy_mgr_soc_set_dual_mac_cfg_cb; + + policy_mgr_debug("scan_config:%x fw_mode_config:%x", + cfg.scan_config, cfg.fw_mode_config); + + status = pm_ctx->sme_cbacks.sme_soc_set_dual_mac_config(cfg); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("sme_soc_set_dual_mac_config failed %d", status); +} + +void policy_mgr_set_dual_mac_fw_mode_config(struct wlan_objmgr_psoc *psoc, + uint8_t dbs, uint8_t dfs) +{ + struct policy_mgr_dual_mac_config cfg; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + /* Any non-zero positive value is treated as 1 */ + if (dbs != 0) + dbs = 1; + if (dfs != 0) + dfs = 1; + + status = policy_mgr_get_updated_scan_config(psoc, &cfg.scan_config, + policy_mgr_get_dbs_scan_config(psoc), + policy_mgr_get_dbs_plus_agile_scan_config(psoc), + policy_mgr_get_single_mac_scan_with_dfs_config(psoc)); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("policy_mgr_get_updated_scan_config failed %d", + status); + return; + } + + status = policy_mgr_get_updated_fw_mode_config(psoc, + &cfg.fw_mode_config, dbs, dfs); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("policy_mgr_get_updated_fw_mode_config failed %d", + status); + return; + } + + cfg.set_dual_mac_cb = policy_mgr_soc_set_dual_mac_cfg_cb; + + policy_mgr_debug("scan_config:%x fw_mode_config:%x", + cfg.scan_config, cfg.fw_mode_config); + + status = pm_ctx->sme_cbacks.sme_soc_set_dual_mac_config(cfg); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("sme_soc_set_dual_mac_config failed %d", status); +} + +bool policy_mgr_is_scc_with_this_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i, ch_freq; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + /* Get the channel freq for a given vdev_id */ + status = policy_mgr_get_chan_by_session_id(psoc, vdev_id, + &ch_freq); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to get channel for vdev:%d", vdev_id); + return false; + } + + /* Compare given vdev_id freq against other vdev_id's */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if ((pm_conc_connection_list[i].vdev_id != vdev_id) && + (pm_conc_connection_list[i].in_use) && + (pm_conc_connection_list[i].freq == ch_freq)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return false; +} + +bool policy_mgr_is_mcc_with_this_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *mcc_vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i, ch_freq; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (mcc_vdev_id) + *mcc_vdev_id = WLAN_INVALID_VDEV_ID; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + /* Get the channel freq for a given vdev_id */ + status = policy_mgr_get_chan_by_session_id(psoc, vdev_id, &ch_freq); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to get channel for vdev:%d", vdev_id); + return false; + } + + /* Compare given vdev_id freq against other vdev_id's */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].vdev_id == vdev_id) + continue; + + if (!pm_conc_connection_list[i].in_use) + continue; + + if (pm_conc_connection_list[i].freq != ch_freq && + policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[i].freq, + ch_freq)) { + if (mcc_vdev_id) + *mcc_vdev_id = pm_conc_connection_list[i].vdev_id; + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return false; +} + +bool policy_mgr_is_mcc_on_any_sta_vdev(struct wlan_objmgr_psoc *psoc) +{ + uint8_t connection_count, i; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + + connection_count = + policy_mgr_get_mode_specific_conn_info(psoc, NULL, vdev_id_list, + PM_STA_MODE); + if (!connection_count) + return false; + + for (i = 0; i < connection_count; i++) + if (policy_mgr_is_mcc_with_this_vdev_id(psoc, vdev_id_list[i], + NULL)) + return true; + + return false; +} + +bool policy_mgr_current_concurrency_is_scc(struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections = 0; + bool is_scc = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return is_scc; + } + + num_connections = policy_mgr_get_connection_count(psoc); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + switch (num_connections) { + case 1: + break; + case 2: + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq && + policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) + is_scc = true; + break; + case 3: + /* + * In DBS/SBS mode 2 freq are different and on different mac. + * Thus if any of 2 freq are same that mean one of the MAC is + * in SCC. + * For non DBS/SBS, if all 3 freq are same then its SCC + */ + if ((policy_mgr_is_current_hwmode_dbs(psoc) || + policy_mgr_is_current_hwmode_sbs(psoc)) && + (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq || + pm_conc_connection_list[0].freq == + pm_conc_connection_list[2].freq || + pm_conc_connection_list[1].freq == + pm_conc_connection_list[2].freq)) + is_scc = true; + else if ((pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq) && + (pm_conc_connection_list[0].freq == + pm_conc_connection_list[2].freq)) + is_scc = true; + + break; + default: + policy_mgr_debug("unexpected num_connections value %d", + num_connections); + break; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return is_scc; +} + +bool policy_mgr_current_concurrency_is_mcc(struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections = 0; + bool is_mcc = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return is_mcc; + } + + num_connections = policy_mgr_get_connection_count(psoc); + if (!num_connections) + return is_mcc; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + switch (num_connections) { + case 1: + break; + case 2: + if (pm_conc_connection_list[0].freq != + pm_conc_connection_list[1].freq && + policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) + is_mcc = true; + break; + case 3: + /* + * Check if any 2 different freq is on same MAC. + * Return true if any of the different freq is on same MAC. + */ + if ((pm_conc_connection_list[0].freq != + pm_conc_connection_list[1].freq && + policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) || + (pm_conc_connection_list[0].freq != + pm_conc_connection_list[2].freq && + policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[2].freq)) || + (pm_conc_connection_list[1].freq != + pm_conc_connection_list[2].freq && + policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[2].freq))) + is_mcc = true; + break; + default: + policy_mgr_debug("unexpected num_connections value %d", + num_connections); + break; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return is_mcc; +} + +bool policy_mgr_is_sap_p2pgo_on_dfs(struct wlan_objmgr_psoc *psoc) +{ + int index, count; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct policy_mgr_psoc_priv_obj *pm_ctx = NULL; + + if (psoc) + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + index = 0; + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + count = policy_mgr_mode_specific_connection_count(psoc, + PM_SAP_MODE, + list); + while (index < count) { + if (pm_conc_connection_list[list[index]].ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + index++; + } + count = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, + list); + index = 0; + while (index < count) { + if (pm_conc_connection_list[list[index]].ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return false; +} + +/** + * policy_mgr_set_concurrency_mode() - To set concurrency mode + * @psoc: PSOC object data + * @mode: device mode + * + * This routine is called to set the concurrency mode + * + * Return: NONE + */ +void policy_mgr_set_concurrency_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_MONITOR_MODE: + pm_ctx->concurrency_mode |= (1 << mode); + pm_ctx->no_of_open_sessions[mode]++; + break; + default: + break; + } + + policy_mgr_debug("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", + pm_ctx->concurrency_mode, mode, + pm_ctx->no_of_open_sessions[mode]); +} + +/** + * policy_mgr_clear_concurrency_mode() - To clear concurrency mode + * @psoc: PSOC object data + * @mode: device mode + * + * This routine is called to clear the concurrency mode + * + * Return: NONE + */ +void policy_mgr_clear_concurrency_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return; + } + + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_MONITOR_MODE: + pm_ctx->no_of_open_sessions[mode]--; + if (!(pm_ctx->no_of_open_sessions[mode])) + pm_ctx->concurrency_mode &= (~(1 << mode)); + break; + default: + break; + } + + policy_mgr_debug("concurrency_mode = 0x%x Number of open sessions for mode %d = %d", + pm_ctx->concurrency_mode, mode, + pm_ctx->no_of_open_sessions[mode]); +} + +/** + * policy_mgr_validate_conn_info() - validate conn info list + * @psoc: PSOC object data + * + * This function will check connection list to see duplicated + * vdev entry existing or not. + * + * Return: true if conn list is in abnormal state. + */ +static bool +policy_mgr_validate_conn_info(struct wlan_objmgr_psoc *psoc) +{ + uint32_t i, j, conn_num = 0; + bool panic = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return true; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use) { + for (j = i + 1; j < MAX_NUMBER_OF_CONC_CONNECTIONS; + j++) { + if (pm_conc_connection_list[j].in_use && + pm_conc_connection_list[i].vdev_id == + pm_conc_connection_list[j].vdev_id) { + policy_mgr_debug( + "dup entry %d", + pm_conc_connection_list[i].vdev_id); + panic = true; + } + } + conn_num++; + } + } + if (panic) + policy_mgr_err("dup entry"); + + for (i = 0, j = 0; i < QDF_MAX_NO_OF_MODE; i++) + j += pm_ctx->no_of_active_sessions[i]; + + if (j != conn_num) { + policy_mgr_err("active session/conn count mismatch %d %d", + j, conn_num); + panic = true; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (panic) + policy_mgr_debug_alert(); + + return panic; +} + +#ifdef WLAN_FEATURE_11BE_MLO +bool policy_mgr_is_ml_vdev_id(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_mlo = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + return is_mlo; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + is_mlo = true; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return is_mlo; +} + +/* + * policy_mgr_get_ml_sta_info() - Get number of ML STA vdev ids and freq list + * @pm_ctx: pm_ctx ctx + * @num_ml_sta: Return number of ML STA present + * @num_disabled_ml_sta: Return number of disabled ML STA links + * @ml_vdev_lst: Return ML STA vdev id list + * @ml_freq_lst: Return ML STA freq list + * @num_non_ml: Return number of non-ML STA present + * @non_ml_vdev_lst: Return non-ML STA vdev id list + * @non_ml_freq_lst: Return non-ML STA freq list + * + * Return: void + */ +static void +policy_mgr_get_ml_sta_info(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t *num_ml_sta, + uint8_t *num_disabled_ml_sta, + uint8_t *ml_vdev_lst, + qdf_freq_t *ml_freq_lst, + uint8_t *num_non_ml, + uint8_t *non_ml_vdev_lst, + qdf_freq_t *non_ml_freq_lst) +{ + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id, conn_index; + qdf_freq_t freq; + + *num_ml_sta = 0; + *num_disabled_ml_sta = 0; + if (num_non_ml) + *num_non_ml = 0; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (!pm_conc_connection_list[conn_index].in_use) + continue; + if (pm_conc_connection_list[conn_index].mode != PM_STA_MODE) + continue; + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + freq = pm_conc_connection_list[conn_index].freq; + + /* add ml sta vdev and freq list */ + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(pm_ctx->psoc, + vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", vdev_id); + continue; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + ml_vdev_lst[*num_ml_sta] = vdev_id; + ml_freq_lst[(*num_ml_sta)++] = freq; + } else if (num_non_ml) { + if (non_ml_vdev_lst) + non_ml_vdev_lst[*num_non_ml] = vdev_id; + if (non_ml_freq_lst) + non_ml_freq_lst[*num_non_ml] = freq; + (*num_non_ml)++; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + /* Get disabled link info as well and keep it at last */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_DISABLE_LINK; + conn_index++) { + if (!pm_disabled_ml_links[conn_index].in_use) + continue; + if (pm_disabled_ml_links[conn_index].mode != PM_STA_MODE) + continue; + ml_vdev_lst[*num_ml_sta] = + pm_disabled_ml_links[conn_index].vdev_id; + ml_freq_lst[(*num_ml_sta)++] = + pm_disabled_ml_links[conn_index].freq; + (*num_disabled_ml_sta)++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +void +policy_mgr_get_ml_sta_info_psoc(struct wlan_objmgr_psoc *psoc, + uint8_t *num_ml_sta, + uint8_t *num_disabled_ml_sta, + uint8_t *ml_vdev_lst, + qdf_freq_t *ml_freq_lst, + uint8_t *num_non_ml, + uint8_t *non_ml_vdev_lst, + qdf_freq_t *non_ml_freq_lst) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm_ctx"); + return; + } + + return policy_mgr_get_ml_sta_info(pm_ctx, + num_ml_sta, + num_disabled_ml_sta, + ml_vdev_lst, + ml_freq_lst, + num_non_ml, + non_ml_vdev_lst, + non_ml_freq_lst); +} + +uint32_t policy_mgr_get_disabled_ml_links_count(struct wlan_objmgr_psoc *psoc) +{ + uint32_t i, count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm_ctx"); + return count; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_DISABLE_LINK; i++) { + if (pm_disabled_ml_links[i].in_use) + count++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +static QDF_STATUS +policy_mgr_delete_from_disabled_links(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t vdev_id) +{ + int i; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_DISABLE_LINK; i++) { + if (pm_disabled_ml_links[i].in_use && + pm_disabled_ml_links[i].vdev_id == vdev_id) { + pm_disabled_ml_links[i].in_use = false; + policy_mgr_debug("Disabled link removed for vdev %d", + vdev_id); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + /* Return failure if not found */ + if (i >= MAX_NUMBER_OF_DISABLE_LINK) + return QDF_STATUS_E_EXISTS; + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_move_vdev_from_disabled_to_connection_tbl( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status; + enum QDF_OPMODE mode; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm_ctx"); + return; + } + mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + if (mode != QDF_STA_MODE) { + policy_mgr_err("vdev %d opmode %d is not STA", vdev_id, mode); + return; + } + + if (!policy_mgr_is_ml_vdev_id(psoc, vdev_id)) { + policy_mgr_err("vdev %d is not ML", vdev_id); + return; + } + + status = policy_mgr_delete_from_disabled_links(pm_ctx, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_debug("Disabled link not found for vdev %d", + vdev_id); + return; + } + + /* + * Add entry to pm_conc_connection_list if remove from disabled links + * was success + */ + policy_mgr_incr_active_session(psoc, mode, vdev_id); +} + +static QDF_STATUS +policy_mgr_add_to_disabled_links(struct policy_mgr_psoc_priv_obj *pm_ctx, + qdf_freq_t freq, enum QDF_OPMODE mode, + uint8_t vdev_id) +{ + int i; + enum policy_mgr_con_mode pm_mode; + + pm_mode = policy_mgr_qdf_opmode_to_pm_con_mode(pm_ctx->psoc, mode, + vdev_id); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_DISABLE_LINK; i++) { + if (pm_disabled_ml_links[i].in_use && + pm_disabled_ml_links[i].vdev_id == vdev_id) + break; + } + + if (i < MAX_NUMBER_OF_DISABLE_LINK) { + pm_disabled_ml_links[i].freq = freq; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("Disabled link already present vdev %d, pm_mode %d, update freq %d", + vdev_id, pm_mode, freq); + + return QDF_STATUS_E_EXISTS; + } + + for (i = 0; i < MAX_NUMBER_OF_DISABLE_LINK; i++) { + if (!pm_disabled_ml_links[i].in_use) { + /* add in empty place */ + pm_disabled_ml_links[i].vdev_id = vdev_id; + pm_disabled_ml_links[i].mode = pm_mode; + pm_disabled_ml_links[i].in_use = true; + pm_disabled_ml_links[i].freq = freq; + policy_mgr_debug("Disabled link added vdev id: %d freq: %d pm_mode %d", + vdev_id, freq, pm_mode); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (i >= MAX_NUMBER_OF_DISABLE_LINK) { + policy_mgr_err("No empty entry found to disable link for vdev %d", + vdev_id); + return QDF_STATUS_E_RESOURCES; + } + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_move_vdev_from_connection_to_disabled_tbl( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + qdf_freq_t freq; + enum QDF_OPMODE mode; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm_ctx"); + return; + } + + mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + if (mode != QDF_STA_MODE) { + policy_mgr_err("vdev %d opmode %d is not STA", vdev_id, mode); + return; + } + + if (!policy_mgr_is_ml_vdev_id(psoc, vdev_id)) { + policy_mgr_err("vdev %d is not ML", vdev_id); + return; + } + freq = wlan_get_operation_chan_freq_vdev_id(pm_ctx->pdev, vdev_id); + status = policy_mgr_check_conn_with_mode_and_vdev_id(psoc, PM_STA_MODE, + vdev_id); + /* + * Remove entry if present in pm_conc_connection_list, if not just add + * it in disabled table. + */ + if (QDF_IS_STATUS_SUCCESS(status)) + policy_mgr_decr_session_set_pcl(psoc, mode, vdev_id); + else + policy_mgr_debug("Connection tbl dont have vdev %d in STA mode, Add it in disabled tbl", + vdev_id); + + policy_mgr_add_to_disabled_links(pm_ctx, freq, mode, vdev_id); + policy_mgr_dump_current_concurrency(psoc); +} + +static bool +policy_mgr_vdev_disabled_by_link_force(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + bool peer_assoc) +{ + uint16_t dynamic_inactive = 0, forced_inactive = 0; + uint16_t link_id; + + if (ml_is_nlink_service_supported(psoc) && + !peer_assoc) { + ml_nlink_get_dynamic_inactive_links(psoc, vdev, + &dynamic_inactive, + &forced_inactive); + link_id = wlan_vdev_get_link_id(vdev); + if ((forced_inactive | dynamic_inactive) & + (1 << link_id)) { + policy_mgr_debug("vdev %d linkid %d is forced inactived 0x%0x dyn 0x%x", + wlan_vdev_get_id(vdev), + link_id, forced_inactive, + dynamic_inactive); + return true; + } + } + + return false; +} + +bool +policy_mgr_ml_link_vdev_need_to_be_disabled(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + bool peer_assoc) +{ + union conc_ext_flag conc_ext_flags; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return false; + + /* Check only for link vdev */ + if (!wlan_vdev_mlme_is_mlo_vdev(vdev) || + !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return false; + + /* Check vdev is disabled by link force command */ + if (policy_mgr_vdev_disabled_by_link_force(psoc, vdev, + peer_assoc)) + return true; + + conc_ext_flags.value = policy_mgr_get_conc_ext_flags(vdev, false); + /* + * For non-assoc link vdev set link as disabled if concurrency is + * not allowed + */ + return !policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE, + wlan_get_operation_chan_freq(vdev), + HW_MODE_20_MHZ, + conc_ext_flags.value, NULL); +} + +static void +policy_mgr_enable_disable_link_from_vdev_bitmask(struct wlan_objmgr_psoc *psoc, + unsigned long enable_vdev_mask, + unsigned long disable_vdev_mask, + uint8_t start_vdev_id) +{ + uint8_t i; + + /* Enable required link if enable_vdev_mask preset */ + for (i = 0; enable_vdev_mask && i < WLAN_MAX_VDEVS; i++) { + if (qdf_test_and_clear_bit(i, &enable_vdev_mask)) + policy_mgr_move_vdev_from_disabled_to_connection_tbl( + psoc, + i + start_vdev_id); + } + + /* Disable required link if disable_mask preset */ + for (i = 0; disable_vdev_mask && i < WLAN_MAX_VDEVS; i++) { + if (qdf_test_and_clear_bit(i, &disable_vdev_mask)) + policy_mgr_move_vdev_from_connection_to_disabled_tbl( + psoc, + i + start_vdev_id); + } +} + +static void +policy_mgr_set_link_in_progress(struct policy_mgr_psoc_priv_obj *pm_ctx, + bool set_link_in_progress) +{ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (set_link_in_progress) + qdf_atomic_inc(&pm_ctx->link_in_progress); + else { + if (qdf_atomic_read(&pm_ctx->link_in_progress) > 0) + qdf_atomic_dec(&pm_ctx->link_in_progress); + } + + /* if set link has started reset the event, else complete the event */ + if (qdf_atomic_read(&pm_ctx->link_in_progress)) + qdf_event_reset(&pm_ctx->set_link_update_done_evt); + else + qdf_event_set(&pm_ctx->set_link_update_done_evt); + + policy_mgr_debug("link_in_progress %d", + qdf_atomic_read(&pm_ctx->link_in_progress)); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +static bool +policy_mgr_get_link_in_progress(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + bool value; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + value = qdf_atomic_read(&pm_ctx->link_in_progress); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (value) + policy_mgr_debug("set_link_in_progress %d", value); + + return value; +} + +bool policy_mgr_is_set_link_in_progress(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + return policy_mgr_get_link_in_progress(pm_ctx); +} + +/* + * policy_mgr_trigger_roam_on_link_removal() - Trigger roam on link removal + * @vdev: vdev object + * + * In multilink ML STA, if one link is removed by AP, and no other active + * link, trigger roam by roaming invoke command. + * + * Return: void + */ +static void +policy_mgr_trigger_roam_on_link_removal(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *ml_vdev; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0; + uint8_t num_active_ml_sta; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + uint8_t assoc_vdev_id = WLAN_INVALID_VDEV_ID; + uint8_t removed_vdev_id = WLAN_INVALID_VDEV_ID; + struct qdf_mac_addr bssid; + QDF_STATUS status; + bool ml_sta_is_not_connected = false; + uint32_t i; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + policy_mgr_err("Failed to get psoc"); + return; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + policy_mgr_err("Failed to get pdev"); + return; + } + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, + NULL, NULL, NULL); + if (!num_ml_sta) { + policy_mgr_debug("unexpected event, no ml sta"); + return; + } + if (num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_disabled_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_ml_sta <= num_disabled_ml_sta) { + policy_mgr_debug("unexpected ml sta num %d %d", + num_ml_sta, num_disabled_ml_sta); + return; + } + num_active_ml_sta = num_ml_sta; + if (num_ml_sta >= num_disabled_ml_sta) + num_active_ml_sta = num_ml_sta - num_disabled_ml_sta; + + for (i = 0; i < num_active_ml_sta; i++) { + if (!wlan_get_vdev_link_removed_flag_by_vdev_id( + psoc, ml_sta_vdev_lst[i])) + break; + } + + /* After link removal, one link is still active, no need invoke + * roaming. + * For Single link MLO, FW will do roaming automatically. + */ + if (i < num_active_ml_sta || num_ml_sta < 2) + return; + + /* For multi-link MLO STA, if one link is removed and no other active + * link, then trigger roaming. the other link may have concurrency + * limitation and can't be active. + */ + for (i = 0; i < num_ml_sta; i++) { + if (removed_vdev_id == WLAN_INVALID_VDEV_ID && + wlan_get_vdev_link_removed_flag_by_vdev_id( + psoc, ml_sta_vdev_lst[i])) { + policy_mgr_debug("removal link vdev %d is removed ", + vdev_id); + removed_vdev_id = ml_sta_vdev_lst[i]; + } + ml_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + pm_ctx->psoc, + ml_sta_vdev_lst[i], + WLAN_POLICY_MGR_ID); + if (!ml_vdev) { + policy_mgr_err("invalid vdev for id %d", + ml_sta_vdev_lst[i]); + continue; + } + if (!wlan_cm_is_vdev_connected(ml_vdev)) { + policy_mgr_debug("ml sta vdev %d is not connected state", + ml_sta_vdev_lst[i]); + ml_sta_is_not_connected = true; + } + + wlan_objmgr_vdev_release_ref(ml_vdev, WLAN_POLICY_MGR_ID); + + if (assoc_vdev_id == WLAN_INVALID_VDEV_ID && + !wlan_vdev_mlme_get_is_mlo_link(psoc, + ml_sta_vdev_lst[i])) + assoc_vdev_id = ml_sta_vdev_lst[i]; + } + if (removed_vdev_id == WLAN_INVALID_VDEV_ID) { + policy_mgr_debug("no link removed, unexpected"); + return; + } + if (assoc_vdev_id == WLAN_INVALID_VDEV_ID) { + policy_mgr_debug("no find assoc vdev, unexpected"); + return; + } + if (ml_sta_is_not_connected) { + policy_mgr_debug("ml sta is non-connected state, don't trigger roam"); + return; + } + /* trigger roaming */ + policy_mgr_debug("link removal detected, try roaming on vdev id: %d", + assoc_vdev_id); + qdf_zero_macaddr(&bssid); + status = wlan_cm_roam_invoke(pdev, assoc_vdev_id, &bssid, 0, + CM_ROAMING_LINK_REMOVAL); + if (QDF_IS_STATUS_ERROR(status)) + policy_mgr_err("roam invoke failed"); +} + +/* + * policy_mgr_update_dynamic_inactive_bitmap() - Update dynamic inactive links + * @psoc: psoc object + * @vdev: vdev object + * @req: req of set link command + * @resp: resp of set link command + * + * If MLO_LINK_FORCE_MODE_INACTIVE_NUM force mode with control flag - + * "dynamic_force_link_num" enabled was sent to firmware, + * host will need to select same num of links to be dyamic inactive + * links. And move corresponding vdevs to disabled policy mgr connection table. + * + * Return: void + */ +static void +policy_mgr_update_dynamic_inactive_bitmap( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint32_t candidate_inactive_links, inactive_links; + uint32_t standby_links; + uint32_t dyn_inactive_links = 0; + uint8_t dyn_num = 0, num = 0, i; + uint8_t link_ids[MAX_MLO_LINK_ID * 2]; + struct ml_link_force_state curr_state = {0}; + uint8_t force_inactive_num = 0; + uint32_t force_inactive_num_bitmap = 0; + uint32_t force_inactive_bitmap; + + ml_nlink_get_curr_force_state(psoc, vdev, &curr_state); + + switch (req->param.force_mode) { + case MLO_LINK_FORCE_MODE_ACTIVE: + case MLO_LINK_FORCE_MODE_INACTIVE: + case MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE: + case MLO_LINK_FORCE_MODE_ACTIVE_NUM: + case MLO_LINK_FORCE_MODE_NO_FORCE: + if (!curr_state.curr_dynamic_inactive_bitmap) + return; + + force_inactive_num = curr_state.force_inactive_num; + force_inactive_num_bitmap = + curr_state.force_inactive_num_bitmap; + force_inactive_bitmap = curr_state.force_inactive_bitmap; + break; + case MLO_LINK_FORCE_MODE_INACTIVE_NUM: + if (!req->param.control_flags.dynamic_force_link_num) { + if (!curr_state.curr_dynamic_inactive_bitmap) + return; + dyn_inactive_links = 0; + dyn_num = 0; + goto update; + } + + force_inactive_num = curr_state.force_inactive_num; + force_inactive_num_bitmap = + curr_state.force_inactive_num_bitmap; + force_inactive_bitmap = curr_state.force_inactive_bitmap; + break; + default: + return; + } + + /* force inactive num "clear" case, return 0 - no + * dynamic inactive links. + */ + if (!force_inactive_num) { + dyn_inactive_links = 0; + dyn_num = 0; + goto update; + } + + /* 1. If standby link is force inactive, + * select the standby link as dynamic inactive link firstly. + */ + standby_links = ml_nlink_get_standby_link_bitmap(psoc, vdev); + candidate_inactive_links = + force_inactive_num_bitmap & + force_inactive_bitmap & + standby_links; + inactive_links = candidate_inactive_links; + num = ml_nlink_convert_link_bitmap_to_ids(candidate_inactive_links, + QDF_ARRAY_SIZE(link_ids), + link_ids); + + /* 2. If non standby link is force inactive, + * select the non standby link as second option. + */ + if (num < force_inactive_num && + num < QDF_ARRAY_SIZE(link_ids)) { + candidate_inactive_links = + force_inactive_num_bitmap & + force_inactive_bitmap & + ~inactive_links; + num += ml_nlink_convert_link_bitmap_to_ids( + candidate_inactive_links, + QDF_ARRAY_SIZE(link_ids) - num, + &link_ids[num]); + inactive_links |= candidate_inactive_links; + } + + /* 3. If standby link is present (may not be force inactive), + * select the standby link as dynamic inactive link. + */ + if (num < force_inactive_num && + num < QDF_ARRAY_SIZE(link_ids)) { + candidate_inactive_links = + force_inactive_num_bitmap & + standby_links; + num += ml_nlink_convert_link_bitmap_to_ids( + candidate_inactive_links, + QDF_ARRAY_SIZE(link_ids) - num, + &link_ids[num]); + inactive_links |= candidate_inactive_links; + } + + /* 4. If there are links inactive from fw event's + * curr_inactive_linkid_bitmap, select the current inactive + * links as last option. note: those link may not be force + * inactive. + */ + if (num < force_inactive_num && + num < QDF_ARRAY_SIZE(link_ids)) { + candidate_inactive_links = + force_inactive_num_bitmap & + resp->curr_inactive_linkid_bitmap & + ~inactive_links; + num += ml_nlink_convert_link_bitmap_to_ids( + candidate_inactive_links, + QDF_ARRAY_SIZE(link_ids) - num, + &link_ids[num]); + inactive_links |= candidate_inactive_links; + } + + for (i = 0; i < num; i++) { + if (dyn_num >= force_inactive_num) + break; + dyn_inactive_links |= 1 << link_ids[i]; + dyn_num++; + } + +update: + policy_mgr_debug("inactive link num %d bitmap 0x%x force inactive 0x%x curr 0x%x dyn links 0x%x num %d", + force_inactive_num, + force_inactive_num_bitmap, + resp->inactive_linkid_bitmap, + resp->curr_inactive_linkid_bitmap, + dyn_inactive_links, dyn_num); + + ml_nlink_set_dynamic_inactive_links(psoc, vdev, dyn_inactive_links); +} + +static void +policy_mgr_handle_vdev_active_inactive_resp( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint8_t vdev_id_num = 0; + uint8_t vdev_ids[WLAN_MLO_MAX_VDEVS] = {0}; + uint32_t assoc_bitmap = 0; + uint16_t dynamic_inactive_bitmap = 0; + uint16_t forced_inactive_bitmap = 0; + + /* convert link id to vdev id and update vdev status based + * on both inactive and active bitmap. + * In link bitmap based WMI event (use_ieee_link_id = true), + * target will always indicate current force inactive and + * active bitmaps to host. For links in inactive_linkid_bitmap, + * they will be moved to policy mgr disable connection table. + * for other links, they will be in active tables. + */ + ml_nlink_get_dynamic_inactive_links(psoc, vdev, + &dynamic_inactive_bitmap, + &forced_inactive_bitmap); + resp->inactive_linkid_bitmap |= dynamic_inactive_bitmap; + ml_nlink_convert_linkid_bitmap_to_vdev_bitmap( + psoc, vdev, resp->inactive_linkid_bitmap, + &assoc_bitmap, + &resp->inactive_sz, resp->inactive, + &vdev_id_num, vdev_ids); + + ml_nlink_convert_linkid_bitmap_to_vdev_bitmap( + psoc, vdev, + (~resp->inactive_linkid_bitmap) & assoc_bitmap, + NULL, + &resp->active_sz, resp->active, + &vdev_id_num, vdev_ids); + for (i = 0; i < resp->inactive_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, 0, resp->inactive[i], i * 32); + for (i = 0; i < resp->active_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, resp->active[i], 0, i * 32); +} + +static void +policy_mgr_handle_force_active_resp(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint32_t assoc_bitmap = 0; + + if (resp->use_ieee_link_id) { + /* save link force active bitmap */ + ml_nlink_set_curr_force_active_state( + psoc, vdev, req->param.force_cmd.ieee_link_id_bitmap, + req->param.control_flags.overwrite_force_active_bitmap ? + LINK_OVERWRITE : LINK_ADD); + + policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req, + resp); + + /* update vdev active inactive status */ + policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req, + resp); + return; + } + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_vdev_bitmap, + req->param.vdev_bitmap, &resp->active_linkid_bitmap, + &assoc_bitmap); + ml_nlink_set_curr_force_active_state( + psoc, vdev, resp->active_linkid_bitmap, LINK_ADD); + + for (i = 0; i < resp->active_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, resp->active[i], 0, i * 32); +} + +static void +policy_mgr_handle_force_inactive_resp(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint32_t assoc_bitmap = 0; + + if (resp->use_ieee_link_id) { + /* save link force inactive bitmap */ + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, req->param.force_cmd.ieee_link_id_bitmap, + req->param.control_flags.overwrite_force_inactive_bitmap ? + LINK_OVERWRITE : LINK_ADD); + + policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req, + resp); + + /* update vdev active inactive status */ + policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req, + resp); + return; + } + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_vdev_bitmap, + req->param.vdev_bitmap, &resp->inactive_linkid_bitmap, + &assoc_bitmap); + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, resp->inactive_linkid_bitmap, LINK_ADD); + + for (i = 0; i < resp->inactive_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, 0, resp->inactive[i], i * 32); +} + +static void +policy_mgr_handle_force_active_num_resp(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint32_t assoc_bitmap = 0; + uint32_t link_bitmap = 0; + + if (resp->use_ieee_link_id) { + /* save force num and force num bitmap */ + ml_nlink_set_curr_force_active_num_state( + psoc, vdev, req->param.force_cmd.link_num, + req->param.force_cmd.ieee_link_id_bitmap); + + policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req, + resp); + + /* update vdev active inactive status */ + policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req, + resp); + return; + } + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_vdev_bitmap, + req->param.vdev_bitmap, + &link_bitmap, + &assoc_bitmap); + ml_nlink_set_curr_force_active_num_state( + psoc, vdev, req->param.link_num[0].num_of_link, + link_bitmap); + /* + * When the host sends a set link command with force link num + * and dynamic flag set, FW may not process it immediately. + * In this case FW buffer the request and sends a response as + * success to the host with VDEV bitmap as zero. + * FW ensures that the number of active links will be equal to + * the link num sent via WMI_MLO_LINK_SET_ACTIVE_CMDID command. + * So the host should also fill the mlo policy_mgr table as per + * request. + */ + if (req->param.control_flags.dynamic_force_link_num) { + policy_mgr_debug("Enable ML vdev(s) as sent in req"); + for (i = 0; i < req->param.num_vdev_bitmap; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, + req->param.vdev_bitmap[i], 0, i * 32); + return; + } + + /* + * MLO_LINK_FORCE_MODE_ACTIVE_NUM return which vdev is active + * So XOR of the requested ML vdev and active vdev bit will give + * the vdev bits to disable + */ + for (i = 0; i < resp->active_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, resp->active[i], + resp->active[i] ^ req->param.vdev_bitmap[i], + i * 32); +} + +static void +policy_mgr_handle_force_inactive_num_resp( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint32_t assoc_bitmap = 0; + uint32_t link_bitmap = 0; + + if (resp->use_ieee_link_id) { + /* save force num and force num bitmap */ + ml_nlink_set_curr_force_inactive_num_state( + psoc, vdev, req->param.force_cmd.link_num, + req->param.force_cmd.ieee_link_id_bitmap); + policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req, + resp); + + /* update vdev active inactive status */ + policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req, + resp); + return; + } + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_vdev_bitmap, + req->param.vdev_bitmap, + &link_bitmap, + &assoc_bitmap); + ml_nlink_set_curr_force_inactive_num_state( + psoc, vdev, req->param.link_num[0].num_of_link, + link_bitmap); + + /* + * MLO_LINK_FORCE_MODE_INACTIVE_NUM return which vdev is + * inactive So XOR of the requested ML vdev and inactive vdev + * bit will give the vdev bits to be enable. + */ + for (i = 0; i < resp->inactive_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, + resp->inactive[i] ^ req->param.vdev_bitmap[i], + resp->inactive[i], i * 32); +} + +static void +policy_mgr_handle_force_active_inactive_resp( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint32_t assoc_bitmap = 0; + + if (resp->use_ieee_link_id) { + /* save link active/inactive bitmap */ + ml_nlink_set_curr_force_active_state( + psoc, vdev, req->param.force_cmd.ieee_link_id_bitmap, + req->param.control_flags.overwrite_force_active_bitmap ? + LINK_OVERWRITE : LINK_ADD); + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, req->param.force_cmd.ieee_link_id_bitmap2, + req->param.control_flags.overwrite_force_inactive_bitmap ? + LINK_OVERWRITE : LINK_ADD); + + policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req, + resp); + + /* update vdev active inactive status */ + policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req, + resp); + return; + } + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_inactive_vdev_bitmap, + req->param.inactive_vdev_bitmap, + &resp->inactive_linkid_bitmap, + &assoc_bitmap); + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, resp->inactive_linkid_bitmap, LINK_ADD); + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_vdev_bitmap, + req->param.vdev_bitmap, + &resp->active_linkid_bitmap, + &assoc_bitmap); + ml_nlink_set_curr_force_active_state( + psoc, vdev, resp->active_linkid_bitmap, LINK_ADD); + + for (i = 0; i < resp->inactive_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, 0, resp->inactive[i], i * 32); + for (i = 0; i < resp->active_sz; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, resp->active[i], 0, i * 32); +} + +static void +policy_mgr_handle_no_force_resp(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mlo_link_set_active_req *req, + struct mlo_link_set_active_resp *resp) +{ + uint8_t i; + uint32_t assoc_bitmap = 0; + uint32_t link_bitmap = 0; + + if (resp->use_ieee_link_id) { + /* update link inactive/active bitmap */ + if (req->param.force_cmd.ieee_link_id_bitmap) { + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, + req->param.force_cmd.ieee_link_id_bitmap, + LINK_CLR); + ml_nlink_set_curr_force_active_state( + psoc, vdev, + req->param.force_cmd.ieee_link_id_bitmap, + LINK_CLR); + } else { + /* special handling for no force to clear all */ + ml_nlink_clr_force_state(psoc, vdev); + } + + policy_mgr_update_dynamic_inactive_bitmap(psoc, vdev, req, + resp); + /* update vdev active inactive status */ + policy_mgr_handle_vdev_active_inactive_resp(psoc, vdev, req, + resp); + return; + } + + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, req->param.num_vdev_bitmap, + req->param.vdev_bitmap, + &link_bitmap, &assoc_bitmap); + + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, link_bitmap, LINK_CLR); + ml_nlink_set_curr_force_active_state( + psoc, vdev, link_bitmap, LINK_CLR); + ml_nlink_set_curr_force_active_num_state( + psoc, vdev, 0, 0); + ml_nlink_set_curr_force_inactive_num_state( + psoc, vdev, 0, 0); + + /* Enable all the ML vdev id sent in request */ + for (i = 0; i < req->param.num_vdev_bitmap; i++) + policy_mgr_enable_disable_link_from_vdev_bitmask( + psoc, req->param.vdev_bitmap[i], 0, i * 32); +} + +static void +policy_mgr_handle_link_enable_disable_resp(struct wlan_objmgr_vdev *vdev, + void *arg, + struct mlo_link_set_active_resp *resp) +{ + struct mlo_link_set_active_req *req = arg; + struct wlan_objmgr_psoc *psoc; + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + policy_mgr_err("Psoc is Null"); + return; + } + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (!req || !resp) { + policy_mgr_err("arguments or event empty for vdev %d", + wlan_vdev_get_id(vdev)); + goto complete_evnt; + } + + if (resp->status) { + policy_mgr_err("Set link status %d, for mode %d reason %d vdev bitmask 0x%x", + resp->status, req->param.force_mode, + req->param.reason, req->param.vdev_bitmap[0]); + goto complete_evnt; + } + + policy_mgr_debug("Req mode %d reason %d, bitmask[0] = 0x%x, resp: active %d inactive %d, active[0] 0x%x inactive[0] 0x%x", + req->param.force_mode, req->param.reason, + req->param.vdev_bitmap[0], + resp->active_sz, resp->inactive_sz, + resp->active[0], resp->inactive[0]); + switch (req->param.force_mode) { + case MLO_LINK_FORCE_MODE_ACTIVE: + policy_mgr_handle_force_active_resp(psoc, vdev, req, resp); + break; + case MLO_LINK_FORCE_MODE_INACTIVE: + policy_mgr_handle_force_inactive_resp(psoc, vdev, req, resp); + break; + case MLO_LINK_FORCE_MODE_ACTIVE_NUM: + policy_mgr_handle_force_active_num_resp(psoc, vdev, req, resp); + break; + case MLO_LINK_FORCE_MODE_INACTIVE_NUM: + policy_mgr_handle_force_inactive_num_resp(psoc, vdev, req, + resp); + break; + case MLO_LINK_FORCE_MODE_NO_FORCE: + policy_mgr_handle_no_force_resp(psoc, vdev, req, resp); + break; + case MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE: + policy_mgr_handle_force_active_inactive_resp(psoc, vdev, req, + resp); + break; + default: + policy_mgr_err("Invalid request req mode %d", + req->param.force_mode); + break; + } + if (req->param.reason == MLO_LINK_FORCE_REASON_LINK_REMOVAL) + policy_mgr_trigger_roam_on_link_removal(vdev); + +complete_evnt: + policy_mgr_set_link_in_progress(pm_ctx, false); + if (ml_is_nlink_service_supported(psoc) && + req && resp && !resp->status && + req->param.control_flags.post_re_evaluate) + status = ml_nlink_conn_change_notify( + psoc, wlan_vdev_get_id(vdev), + ml_nlink_connection_updated_evt, NULL); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* reschedule force scc workqueue after link state changes */ + if (req && resp && !resp->status && + status == QDF_STATUS_SUCCESS) + policy_mgr_check_concurrent_intf_and_restart_sap(psoc, false); +} +#else +static inline QDF_STATUS +policy_mgr_delete_from_disabled_links(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +bool policy_mgr_is_mlo_sta_disconnected(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool disconnected; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + return true; + /* mlo mgr has no corresponding protocol api used in non-osif/hdd + * component. Todo: clean up to use internal API + */ + disconnected = ucfg_mlo_is_mld_disconnected(vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return disconnected; +} + +void policy_mgr_incr_active_session(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t session_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_6ghz_flag = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + /* + * Need to acquire mutex as entire functionality in this function + * is in critical section + */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_NAN_DISC_MODE: + case QDF_NDI_MODE: + pm_ctx->no_of_active_sessions[mode]++; + break; + default: + break; + } + + if (mode == QDF_NDI_MODE && + pm_ctx->hdd_cbacks.wlan_hdd_indicate_active_ndp_cnt) + pm_ctx->hdd_cbacks.wlan_hdd_indicate_active_ndp_cnt( + psoc, session_id, + pm_ctx->no_of_active_sessions[mode]); + + if (mode != QDF_NAN_DISC_MODE && pm_ctx->dp_cbacks.hdd_v2_flow_pool_map) + pm_ctx->dp_cbacks.hdd_v2_flow_pool_map(session_id); + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) + policy_mgr_get_ap_6ghz_capable(psoc, session_id, + &conn_6ghz_flag); + + policy_mgr_debug("No.# of active sessions for mode %d = %d", + mode, pm_ctx->no_of_active_sessions[mode]); + policy_mgr_incr_connection_count(psoc, session_id, mode); + + if ((policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, NULL) > 0) && (mode != QDF_STA_MODE)) { + /* Send set pcl for all the connected STA vdev */ + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + polic_mgr_send_pcl_to_fw(psoc, mode); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + } + + /* Notify tdls */ + if (pm_ctx->tdls_cbacks.tdls_notify_increment_session) + pm_ctx->tdls_cbacks.tdls_notify_increment_session(psoc); + + /* + * Disable LRO/GRO if P2P or SAP connection has come up or + * there are more than one STA connections + */ + if ((policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, NULL) > 1) || + (policy_mgr_get_beaconing_mode_count(psoc, NULL) > 0) || + (policy_mgr_mode_specific_connection_count(psoc, PM_P2P_CLIENT_MODE, NULL) > + 0) || + (policy_mgr_mode_specific_connection_count(psoc, + PM_NDI_MODE, + NULL) > 0)) { + if (pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency) + pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency(true); + }; + + /* Enable RPS if SAP interface has come up */ + if (policy_mgr_get_sap_mode_count(psoc, NULL) == 1) { + if (pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb) + pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb(true); + } + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) + policy_mgr_init_ap_6ghz_capable(psoc, session_id, + conn_6ghz_flag); + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE || + mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) + policy_mgr_update_dfs_master_dynamic_enabled(psoc, session_id); + + policy_mgr_dump_current_concurrency(psoc); + + if (policy_mgr_update_indoor_concurrency(psoc, session_id, 0, CONNECT)) + wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) + ml_nlink_conn_change_notify( + psoc, session_id, ml_nlink_ap_started_evt, NULL); +} + +/** + * policy_mgr_update_sta_scc_info_for_later_check() - function to update sta/sap + * scc channel frequency and later check flag. + * @pm_ctx: policy manager context pointer + * @mode: operation mode + * @vdev_id: vdev id + * + * Return: None + */ +static void policy_mgr_update_sta_scc_info_for_later_check( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum QDF_OPMODE mode, + uint8_t vdev_id) +{ + uint32_t conn_index = 0; + qdf_freq_t sta_freq = 0; + + if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE) + return; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) { + sta_freq = pm_conc_connection_list[conn_index].freq; + break; + } + conn_index++; + } + + if (!sta_freq) + goto release_mutex; + + /* + * When STA disconnected, we need to move DFS SAP + * to Non-DFS if g_sta_sap_scc_on_dfs_chan enabled. + * The same if g_sta_sap_scc_on_lte_coex_chan enabled, + * need to move SAP on unsafe channel to safe channel. + * The flag will be checked by + * policy_mgr_is_sap_restart_required_after_sta_disconnect. + */ + conn_index = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (pm_conc_connection_list[conn_index].freq == sta_freq && + (pm_conc_connection_list[conn_index].mode == PM_SAP_MODE || + pm_conc_connection_list[conn_index].mode == + PM_P2P_GO_MODE)) { + pm_ctx->last_disconn_sta_freq = sta_freq; + break; + } + conn_index++; + } + +release_mutex: + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +QDF_STATUS policy_mgr_decr_active_session(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t session_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS qdf_status; + bool mcc_mode; + uint32_t session_count, cur_freq; + enum hw_mode_bandwidth max_bw; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return QDF_STATUS_E_EMPTY; + } + + qdf_status = policy_mgr_check_conn_with_mode_and_vdev_id(psoc, + policy_mgr_qdf_opmode_to_pm_con_mode(psoc, mode, + session_id), + session_id); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + policy_mgr_debug("No connection with mode:%d vdev_id:%d", + policy_mgr_qdf_opmode_to_pm_con_mode(psoc, mode, + session_id), + session_id); + /* + * In case of disconnect try delete the link from disabled link + * as well, if its not present in pm_conc_connection_list, + * it can be present in pm_disabled_ml_links. + */ + policy_mgr_delete_from_disabled_links(pm_ctx, session_id); + policy_mgr_dump_current_concurrency(psoc); + return qdf_status; + } + policy_mgr_update_sta_scc_info_for_later_check(pm_ctx, + mode, + session_id); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + case QDF_NAN_DISC_MODE: + case QDF_NDI_MODE: + if (pm_ctx->no_of_active_sessions[mode]) + pm_ctx->no_of_active_sessions[mode]--; + break; + default: + break; + } + + policy_mgr_get_chan_by_session_id(psoc, session_id, &cur_freq); + + policy_mgr_decr_connection_count(psoc, session_id); + session_count = pm_ctx->no_of_active_sessions[mode]; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (mode != QDF_NAN_DISC_MODE && + pm_ctx->dp_cbacks.hdd_v2_flow_pool_unmap) + pm_ctx->dp_cbacks.hdd_v2_flow_pool_unmap(session_id); + + if (mode == QDF_NDI_MODE && + pm_ctx->hdd_cbacks.wlan_hdd_indicate_active_ndp_cnt) + pm_ctx->hdd_cbacks.wlan_hdd_indicate_active_ndp_cnt( + psoc, session_id, session_count); + + policy_mgr_debug("No.# of active sessions for mode %d = %d", + mode, session_count); + + /* Notify tdls */ + if (pm_ctx->tdls_cbacks.tdls_notify_decrement_session) + pm_ctx->tdls_cbacks.tdls_notify_decrement_session(psoc); + /* Enable LRO/GRO if there no concurrency */ + if ((policy_mgr_get_connection_count(psoc) == 0) || + ((policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL) == 1) && + (policy_mgr_get_beaconing_mode_count(psoc, NULL) == 0) && + (policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL) == 0) && + (policy_mgr_mode_specific_connection_count(psoc, + PM_NDI_MODE, + NULL) == 0))) { + if (pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency) + pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency(false); + }; + + /* Disable RPS if SAP interface has come up */ + if (policy_mgr_get_sap_mode_count(psoc, NULL) == 0) { + if (pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb) + pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb(false); + } + + policy_mgr_dump_current_concurrency(psoc); + + /* + * Check mode of entry being removed. Update mcc_mode only when STA + * or SAP since IPA only cares about these two + */ + if (mode == QDF_STA_MODE || mode == QDF_SAP_MODE) { + mcc_mode = policy_mgr_current_concurrency_is_mcc(psoc); + + if (pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb) + pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb(mcc_mode); + + if (pm_ctx->dp_cbacks.hdd_ipa_set_perf_level_bw) { + max_bw = policy_mgr_get_connection_max_channel_width( + psoc); + policy_mgr_debug("max channel width %d", max_bw); + pm_ctx->dp_cbacks.hdd_ipa_set_perf_level_bw(max_bw); + } + } + + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE || + mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) + policy_mgr_update_dfs_master_dynamic_enabled(psoc, session_id); + + if (!pm_ctx->last_disconn_sta_freq) { + if (policy_mgr_update_indoor_concurrency(psoc, session_id, + cur_freq, DISCONNECT_WITHOUT_CONCURRENCY)) + wlan_reg_recompute_current_chan_list(psoc, + pm_ctx->pdev); + } + + if (wlan_reg_get_keep_6ghz_sta_cli_connection(pm_ctx->pdev) && + (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE)) + wlan_reg_recompute_current_chan_list(psoc, pm_ctx->pdev); + + return qdf_status; +} + +QDF_STATUS policy_mgr_incr_connection_count(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + enum QDF_OPMODE op_mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index; + struct policy_mgr_vdev_entry_info conn_table_entry = {0}; + enum policy_mgr_chain_mode chain_mask = POLICY_MGR_ONE_ONE; + uint8_t nss_2g = 0, nss_5g = 0; + enum policy_mgr_con_mode mode; + uint32_t ch_freq; + uint32_t nss = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool update_conn = true; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return status; + } + + conn_index = policy_mgr_get_connection_count(psoc); + if (pm_ctx->cfg.max_conc_cxns < conn_index) { + policy_mgr_err("exceeded max connection limit %d", + pm_ctx->cfg.max_conc_cxns); + return status; + } + + if (op_mode == QDF_NAN_DISC_MODE) { + status = wlan_nan_get_connection_info(psoc, &conn_table_entry); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Can't get NAN Connection info"); + return status; + } + } else if (pm_ctx->wma_cbacks.wma_get_connection_info) { + status = pm_ctx->wma_cbacks.wma_get_connection_info( + vdev_id, &conn_table_entry); + if (QDF_STATUS_SUCCESS != status) { + policy_mgr_err("can't find vdev_id %d in connection table", + vdev_id); + return status; + } + } else { + policy_mgr_err("wma_get_connection_info is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, vdev_id); + + ch_freq = conn_table_entry.mhz; + status = policy_mgr_get_nss_for_vdev(psoc, mode, &nss_2g, &nss_5g); + if (QDF_IS_STATUS_SUCCESS(status)) { + if ((WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq) && nss_2g > 1) || + (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && nss_5g > 1)) + chain_mask = POLICY_MGR_TWO_TWO; + else + chain_mask = POLICY_MGR_ONE_ONE; + nss = (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) ? nss_2g : nss_5g; + } else { + policy_mgr_err("Error in getting nss"); + } + + if (mode == PM_STA_MODE || mode == PM_P2P_CLIENT_MODE) + update_conn = false; + + /* add the entry */ + policy_mgr_update_conc_list(psoc, conn_index, + mode, + ch_freq, + policy_mgr_get_bw(conn_table_entry.chan_width), + conn_table_entry.mac_id, + chain_mask, + nss, vdev_id, true, update_conn, + conn_table_entry.ch_flagext); + policy_mgr_debug("Add at idx:%d vdev %d mac=%d", + conn_index, vdev_id, + conn_table_entry.mac_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_decr_connection_count(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t conn_index = 0, next_conn_index = 0; + bool found = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool panic = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) { + /* debug msg */ + found = true; + break; + } + conn_index++; + } + if (!found) { + policy_mgr_err("can't find vdev_id %d in pm_conc_connection_list", + vdev_id); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return status; + } + next_conn_index = conn_index + 1; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(next_conn_index)) { + pm_conc_connection_list[conn_index].vdev_id = + pm_conc_connection_list[next_conn_index].vdev_id; + pm_conc_connection_list[conn_index].mode = + pm_conc_connection_list[next_conn_index].mode; + pm_conc_connection_list[conn_index].mac = + pm_conc_connection_list[next_conn_index].mac; + pm_conc_connection_list[conn_index].freq = + pm_conc_connection_list[next_conn_index].freq; + pm_conc_connection_list[conn_index].bw = + pm_conc_connection_list[next_conn_index].bw; + pm_conc_connection_list[conn_index].chain_mask = + pm_conc_connection_list[next_conn_index].chain_mask; + pm_conc_connection_list[conn_index].original_nss = + pm_conc_connection_list[next_conn_index].original_nss; + pm_conc_connection_list[conn_index].in_use = + pm_conc_connection_list[next_conn_index].in_use; + pm_conc_connection_list[conn_index].ch_flagext = + pm_conc_connection_list[next_conn_index].ch_flagext; + conn_index++; + next_conn_index++; + } + + /* clean up the entry */ + qdf_mem_zero(&pm_conc_connection_list[next_conn_index - 1], + sizeof(*pm_conc_connection_list)); + + conn_index = 0; + while (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + if (vdev_id == pm_conc_connection_list[conn_index].vdev_id) { + panic = true; + break; + } + conn_index++; + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (panic) { + policy_mgr_err("dup entry occur"); + policy_mgr_debug_alert(); + } + if (pm_ctx->conc_cbacks.connection_info_update) + pm_ctx->conc_cbacks.connection_info_update(); + + return QDF_STATUS_SUCCESS; +} + +uint32_t policy_mgr_get_mode_specific_conn_info( + struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, uint8_t *vdev_id, + enum policy_mgr_con_mode mode) +{ + + uint32_t count = 0, index = 0; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + if (!vdev_id) { + policy_mgr_err("Null pointer error"); + return count; + } + + count = policy_mgr_mode_specific_connection_count( + psoc, mode, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (count == 1) { + if (ch_freq_list) + *ch_freq_list = + pm_conc_connection_list[list[index]].freq; + *vdev_id = + pm_conc_connection_list[list[index]].vdev_id; + } else { + for (index = 0; index < count; index++) { + if (ch_freq_list) + ch_freq_list[index] = + pm_conc_connection_list[list[index]].freq; + + vdev_id[index] = + pm_conc_connection_list[list[index]].vdev_id; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +uint32_t policy_mgr_get_sap_mode_info(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, uint8_t *vdev_id) +{ + uint32_t count; + + count = policy_mgr_get_mode_specific_conn_info(psoc, ch_freq_list, + vdev_id, PM_SAP_MODE); + + count += policy_mgr_get_mode_specific_conn_info( + psoc, + ch_freq_list ? &ch_freq_list[count] : NULL, + vdev_id ? &vdev_id[count] : NULL, + PM_LL_LT_SAP_MODE); + return count; +} + +uint32_t policy_mgr_get_beaconing_mode_info(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, + uint8_t *vdev_id) +{ + uint32_t count; + + count = policy_mgr_get_sap_mode_info(psoc, ch_freq_list, vdev_id); + + count += policy_mgr_get_mode_specific_conn_info( + psoc, + ch_freq_list ? &ch_freq_list[count] : NULL, + vdev_id ? &vdev_id[count] : NULL, + PM_P2P_GO_MODE); + return count; +} + +void policy_mgr_get_ml_and_non_ml_sta_count(struct wlan_objmgr_psoc *psoc, + uint8_t *num_ml, uint8_t *ml_idx, + uint8_t *num_non_ml, + uint8_t *non_ml_idx, + qdf_freq_t *freq_list, + uint8_t *vdev_id_list) +{ + uint32_t sta_num = 0; + uint8_t i; + struct wlan_objmgr_vdev *temp_vdev; + + *num_ml = 0; + *num_non_ml = 0; + + sta_num = policy_mgr_get_mode_specific_conn_info(psoc, freq_list, + vdev_id_list, + PM_STA_MODE); + if (!sta_num) + return; + + for (i = 0; i < sta_num; i++) { + temp_vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id_list[i], + WLAN_POLICY_MGR_ID); + if (!temp_vdev) { + policy_mgr_err("invalid vdev for id %d", + vdev_id_list[i]); + *num_ml = 0; + *num_non_ml = 0; + return; + } + + if (wlan_vdev_mlme_is_mlo_vdev(temp_vdev)) { + if (ml_idx) + ml_idx[*num_ml] = i; + (*num_ml)++; + } else { + if (non_ml_idx) + non_ml_idx[*num_non_ml] = i; + (*num_non_ml)++; + } + + wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_POLICY_MGR_ID); + } +} + +bool policy_mgr_concurrent_sta_on_different_mac(struct wlan_objmgr_psoc *psoc) +{ + uint8_t num_ml = 0, num_non_ml = 0; + uint8_t ml_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t non_ml_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool is_different_mac = false; + int i; + + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_get_ml_and_non_ml_sta_count(psoc, &num_ml, ml_idx, + &num_non_ml, non_ml_idx, + freq_list, vdev_id_list); + if (num_ml + num_non_ml < 2 || !num_non_ml) + goto out; + + /* + * If more than 1 Non-ML STA is present, check whether they are + * within the same band. + */ + for (i = 1; i < num_non_ml; i++) { + if (!policy_mgr_2_freq_always_on_same_mac(psoc, + freq_list[non_ml_idx[i]], + freq_list[non_ml_idx[0]])) { + is_different_mac = true; + goto out; + } + } + + if (num_non_ml >= 2) + goto out; + + /* ML STA + Non-ML STA */ + for (i = 0; i < num_ml; i++) { + if (!policy_mgr_2_freq_always_on_same_mac(psoc, + freq_list[ml_idx[i]], + freq_list[non_ml_idx[0]])) { + is_different_mac = true; + goto out; + } + } + +out: + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("Non-ML STA count %d, ML STA count %d, sta concurrency on different mac %d", + num_non_ml, num_ml, is_different_mac); + + return is_different_mac; +} + +bool policy_mgr_max_concurrent_connections_reached( + struct wlan_objmgr_psoc *psoc) +{ + uint8_t i = 0, j = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (pm_ctx) { + for (i = 0; i < QDF_MAX_NO_OF_MODE; i++) + j += pm_ctx->no_of_active_sessions[i]; + return j > + (pm_ctx->cfg.max_conc_cxns - 1); + } + + return false; +} + +static bool policy_mgr_is_sub_20_mhz_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + return pm_ctx->user_cfg.sub_20_mhz_enabled; +} + +/** + * policy_mgr_allow_wapi_concurrency() - Check if WAPI concurrency is allowed + * @pm_ctx: policy_mgr_psoc_priv_obj policy mgr context + * + * This routine is called to check vdev security mode allowed in concurrency. + * At present, WAPI security mode is not allowed to run concurrency with any + * other vdev if the hardware doesn't support WAPI concurrency. + * + * Return: true - allow + */ +static bool +policy_mgr_allow_wapi_concurrency(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + struct wlan_objmgr_pdev *pdev = pm_ctx->pdev; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + + if (!pdev) { + policy_mgr_debug("pdev is Null"); + return false; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return false; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return false; + } + + if (!wmi_service_enabled(wmi_handle, + wmi_service_wapi_concurrency_supported) && + mlme_is_wapi_sta_active(pdev) && + policy_mgr_get_connection_count(pm_ctx->psoc) > 0) + return false; + + return true; +} + +#ifdef FEATURE_FOURTH_CONNECTION +static bool policy_mgr_is_concurrency_allowed_4_port( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + struct policy_mgr_pcl_list pcl) +{ + uint32_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx = NULL; + uint8_t sap_cnt, go_cnt, ll_lt_sap_vdev_id; + + ll_lt_sap_vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc); + + if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) { + policy_mgr_debug("LL_LT_SAP vdev %d present avoid 4th port concurrency", + ll_lt_sap_vdev_id); + return false; + } + /* new STA may just have ssid, no channel until bssid assigned */ + if (ch_freq == 0 && mode == PM_STA_MODE) + return true; + + sap_cnt = policy_mgr_mode_specific_connection_count(psoc, + PM_SAP_MODE, NULL); + + go_cnt = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, NULL); + if (sap_cnt || go_cnt) { + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return false; + } + + if (!policy_mgr_is_force_scc(psoc)) { + policy_mgr_err("couldn't start 4th port for bad force scc cfg"); + return false; + } + + if (!policy_mgr_is_dbs_enable(psoc)) { + policy_mgr_err( + "Couldn't start 4th port for bad cfg of dual mac"); + return false; + } + for (i = 0; i < pcl.pcl_len; i++) + if (ch_freq == pcl.pcl_list[i]) + return true; + + policy_mgr_err("4th port failed on ch freq %d with mode %d", + ch_freq, mode); + + return false; + } + + return true; +} +#else +static inline bool policy_mgr_is_concurrency_allowed_4_port( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + struct policy_mgr_pcl_list pcl) +{return false; } +#endif + +bool +policy_mgr_allow_multiple_sta_connections(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return false; + } + if (!wmi_service_enabled(wmi_handle, + wmi_service_sta_plus_sta_support)) { + policy_mgr_rl_debug("STA+STA is not supported"); + return false; + } + + return true; +} + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +bool policy_mgr_is_6ghz_conc_mode_supported( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode) +{ + if (mode == PM_STA_MODE || mode == PM_SAP_MODE || + mode == PM_P2P_CLIENT_MODE || mode == PM_P2P_GO_MODE) + return true; + else + return false; +} +#endif + +/** + * policy_mgr_is_6g_channel_allowed() - Check new 6Ghz connection + * allowed or not + * @psoc: Pointer to soc + * @mode: new connection mode + * @ch_freq: channel freq + * + * 1. Only STA/SAP are allowed on 6Ghz. + * 2. If there is DFS beacon entity existing on 5G band, 5G+6G MCC is not + * allowed. + * + * Return: true if supports else false. + */ +static bool policy_mgr_is_6g_channel_allowed( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, + uint32_t ch_freq) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info *conn; + bool is_dfs; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq)) { + policy_mgr_rl_debug("Not a 6Ghz channel Freq"); + return true; + } + /* Only STA/SAP is supported on 6Ghz currently */ + if (!policy_mgr_is_6ghz_conc_mode_supported(psoc, mode)) { + policy_mgr_rl_debug("mode %d for 6ghz not supported", mode); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn = &pm_conc_connection_list[conn_index]; + if (!conn->in_use) + continue; + is_dfs = (conn->ch_flagext & + (IEEE80211_CHAN_DFS | IEEE80211_CHAN_DFS_CFREQ2)) && + WLAN_REG_IS_5GHZ_CH_FREQ(conn->freq); + if (policy_mgr_is_beaconing_mode(conn->mode) && + is_dfs && (ch_freq != conn->freq && + !policy_mgr_are_sbs_chan(psoc, ch_freq, + conn->freq))) { + policy_mgr_rl_debug("don't allow MCC if SAP/GO on DFS channel"); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return false; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return true; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static bool policy_mgr_is_acs_2ghz_only_sap(struct wlan_objmgr_psoc *psoc, + uint8_t sap_vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t acs_band = QCA_ACS_MODE_IEEE80211ANY; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (pm_ctx->hdd_cbacks.wlan_get_sap_acs_band) + pm_ctx->hdd_cbacks.wlan_get_sap_acs_band(psoc, + sap_vdev_id, + &acs_band); + + if (acs_band == QCA_ACS_MODE_IEEE80211B || + acs_band == QCA_ACS_MODE_IEEE80211G) + return true; + + return false; +} + +bool policy_mgr_vdev_is_force_inactive(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + bool force_inactive = false; + uint8_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* Get disabled link info as well and keep it at last */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_DISABLE_LINK; + conn_index++) { + if (pm_disabled_ml_links[conn_index].in_use && + pm_disabled_ml_links[conn_index].mode == PM_STA_MODE && + pm_disabled_ml_links[conn_index].vdev_id == vdev_id) { + force_inactive = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return force_inactive; +} + +/* MCC avoidance priority value for different legacy connection type. + * Internal macro, not expected used other code. + * Bigger value have higher priority. + */ +#define PRIORITY_STA 3 +#define PRIORITY_SAP 2 +#define PRIORITY_P2P 1 +#define PRIORITY_OTHER 0 + +uint8_t +policy_mgr_get_legacy_conn_info(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_lst, + qdf_freq_t *freq_lst, + enum policy_mgr_con_mode *mode_lst, + uint8_t lst_sz) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t conn_index, j = 0, i, k, n; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + uint8_t has_priority[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (j >= lst_sz) + break; + if (!pm_conc_connection_list[conn_index].in_use) + continue; + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + pm_ctx->psoc, vdev_id, WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", vdev_id); + continue; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + pm_conc_connection_list[conn_index].mode == + PM_STA_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + continue; + } + if (pm_conc_connection_list[conn_index].mode != + PM_STA_MODE && + pm_conc_connection_list[conn_index].mode != + PM_SAP_MODE && + pm_conc_connection_list[conn_index].mode != + PM_P2P_CLIENT_MODE && + pm_conc_connection_list[conn_index].mode != + PM_P2P_GO_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + continue; + } + + /* Set mcc avoidance priority value. The bigger value + * have higher priority to avoid MCC. In 3 Port concurrency + * case, usually we can only meet the higher priority intf's + * MCC avoidance by force inactive link. + */ + if (pm_conc_connection_list[conn_index].mode == PM_STA_MODE) + has_priority[j] = PRIORITY_STA; + else if (pm_conc_connection_list[conn_index].mode == + PM_SAP_MODE && + policy_mgr_is_acs_2ghz_only_sap(psoc, vdev_id)) + has_priority[j] = PRIORITY_SAP; + else if ((pm_conc_connection_list[conn_index].mode == + PM_P2P_CLIENT_MODE || + pm_conc_connection_list[conn_index].mode == + PM_P2P_GO_MODE) && + policy_mgr_is_vdev_high_tput_or_low_latency( + psoc, vdev_id)) + has_priority[j] = PRIORITY_P2P; + else + has_priority[j] = PRIORITY_OTHER; + + vdev_lst[j] = vdev_id; + freq_lst[j] = pm_conc_connection_list[conn_index].freq; + mode_lst[j] = pm_conc_connection_list[conn_index].mode; + policy_mgr_debug("vdev %d freq %d mode %s pri %d", + vdev_id, freq_lst[j], + device_mode_to_string(mode_lst[j]), + has_priority[j]); + j++; + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + /* sort the list based on priority */ + for (i = 0; i < j; i++) { + uint8_t tmp_vdev_lst; + qdf_freq_t tmp_freq_lst; + enum policy_mgr_con_mode tmp_mode_lst; + + n = i; + for (k = i + 1; k < j; k++) { + if (has_priority[n] < has_priority[k]) + n = k; + else if ((has_priority[n] == has_priority[k]) && + (vdev_lst[n] > vdev_lst[k])) + n = k; + } + if (n == i) + continue; + tmp_vdev_lst = vdev_lst[i]; + tmp_freq_lst = freq_lst[i]; + tmp_mode_lst = mode_lst[i]; + + vdev_lst[i] = vdev_lst[n]; + freq_lst[i] = freq_lst[n]; + mode_lst[i] = mode_lst[n]; + + vdev_lst[n] = tmp_vdev_lst; + freq_lst[n] = tmp_freq_lst; + mode_lst[n] = tmp_mode_lst; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return j; +} + +static void +policy_mgr_fill_ml_active_link_vdev_bitmap(struct mlo_link_set_active_req *req, + uint8_t *mlo_vdev_lst, + uint32_t num_mlo_vdev) +{ + uint32_t entry_idx, entry_offset, vdev_idx; + uint8_t vdev_id; + + for (vdev_idx = 0; vdev_idx < num_mlo_vdev; vdev_idx++) { + vdev_id = mlo_vdev_lst[vdev_idx]; + entry_idx = vdev_id / 32; + entry_offset = vdev_id % 32; + if (entry_idx >= MLO_LINK_NUM_SZ) { + policy_mgr_err("Invalid entry_idx %d num_mlo_vdev %d vdev %d", + entry_idx, num_mlo_vdev, vdev_id); + continue; + } + req->param.vdev_bitmap[entry_idx] |= (1 << entry_offset); + /* update entry number if entry index changed */ + if (req->param.num_vdev_bitmap < entry_idx + 1) + req->param.num_vdev_bitmap = entry_idx + 1; + } + + policy_mgr_debug("num_vdev_bitmap %d vdev_bitmap[0] = 0x%x, vdev_bitmap[1] = 0x%x", + req->param.num_vdev_bitmap, req->param.vdev_bitmap[0], + req->param.vdev_bitmap[1]); +} + +static void +policy_mgr_fill_ml_inactive_link_vdev_bitmap( + struct mlo_link_set_active_req *req, + uint8_t *mlo_inactive_vdev_lst, + uint32_t num_mlo_inactive_vdev) +{ + uint32_t entry_idx, entry_offset, vdev_idx; + uint8_t vdev_id; + + for (vdev_idx = 0; vdev_idx < num_mlo_inactive_vdev; vdev_idx++) { + vdev_id = mlo_inactive_vdev_lst[vdev_idx]; + entry_idx = vdev_id / 32; + entry_offset = vdev_id % 32; + if (entry_idx >= MLO_LINK_NUM_SZ) { + policy_mgr_err("Invalid entry_idx %d num_mlo_vdev %d vdev %d", + entry_idx, num_mlo_inactive_vdev, + vdev_id); + continue; + } + req->param.inactive_vdev_bitmap[entry_idx] |= + (1 << entry_offset); + /* update entry number if entry index changed */ + if (req->param.num_inactive_vdev_bitmap < entry_idx + 1) + req->param.num_inactive_vdev_bitmap = entry_idx + 1; + } + + policy_mgr_debug("num_vdev_bitmap %d inactive_vdev_bitmap[0] = 0x%x, inactive_vdev_bitmap[1] = 0x%x", + req->param.num_inactive_vdev_bitmap, + req->param.inactive_vdev_bitmap[0], + req->param.inactive_vdev_bitmap[1]); +} + +/* + * policy_mgr_handle_ml_sta_link_state_allowed() - Check ml sta connection to + * allow link state change. + * @psoc: psoc object + * @reason: set link state reason + * + * If ml sta is not "connected" state, no need to do link state handling. + * After disconnected, target will clear the force active/inactive state + * and host will remove the connection entry finally. + * After roaming done, active/inactive will be re-calculated. + * + * Return: QDF_STATUS_SUCCESS if link state is allowed to change + */ +static QDF_STATUS +policy_mgr_handle_ml_sta_link_state_allowed(struct wlan_objmgr_psoc *psoc, + enum mlo_link_force_reason reason) +{ + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + bool ml_sta_is_not_connected = false; + bool ml_sta_is_link_removal = false; + uint8_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, &num_non_ml, + NULL, NULL); + if (!num_ml_sta || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) { + policy_mgr_debug("ml sta num is %d", num_ml_sta); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_ml_sta; i++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(pm_ctx->psoc, + ml_sta_vdev_lst[i], + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", + ml_sta_vdev_lst[i]); + continue; + } + if (!wlan_cm_is_vdev_connected(vdev)) { + policy_mgr_debug("ml sta vdev %d is not connected state", + ml_sta_vdev_lst[i]); + ml_sta_is_not_connected = true; + } + if (wlan_get_vdev_link_removed_flag_by_vdev_id( + psoc, ml_sta_vdev_lst[i])) { + policy_mgr_debug("ml sta vdev %d link removed", + ml_sta_vdev_lst[i]); + ml_sta_is_link_removal = true; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + + if (ml_sta_is_not_connected) { + status = QDF_STATUS_E_FAILURE; + } else if (reason != MLO_LINK_FORCE_REASON_LINK_REMOVAL) { + if (ml_sta_is_link_removal) + status = QDF_STATUS_E_FAILURE; + } + policy_mgr_debug("set link reason %d status %d rm %d", reason, status, + ml_sta_is_link_removal); + + return status; +} + +/* + * policy_mgr_validate_set_mlo_link_cb() - Callback to check whether + * it is allowed to set mlo sta link state. + * @psoc: psoc object + * @param: set mlo link parameter + * + * This api will be used as callback to be called by mlo_link_set_active + * in serialization context. + * + * Return: QDF_STATUS_SUCCESS if set mlo link is allowed + */ +static QDF_STATUS +policy_mgr_validate_set_mlo_link_cb(struct wlan_objmgr_psoc *psoc, + struct mlo_link_set_active_param *param) +{ + return policy_mgr_handle_ml_sta_link_state_allowed(psoc, + param->reason); +} + +uint32_t +policy_mgr_get_active_vdev_bitmap(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + policy_mgr_debug("active link bitmap value: %d", + pm_ctx->active_vdev_bitmap); + + return pm_ctx->active_vdev_bitmap; +} + +/** + * policy_mgr_mlo_sta_set_link_by_linkid() - wrapper API to call set link + * by link id bitmap API + * @psoc: psoc object + * @vdev: vdev object + * @reason: Reason for which link is forced + * @mode: Force reason + * @link_num: valid for MLO_LINK_FORCE_MODE_ACTIVE_NUM and + * MLO_LINK_FORCE_MODE_INACTIVE_NUM. + * @num_mlo_vdev: number of mlo vdev in array mlo_vdev_lst + * @mlo_vdev_lst: MLO STA vdev list + * @num_mlo_inactive_vdev: number of mlo vdev in array mlo_inactive_vdev_lst + * @mlo_inactive_vdev_lst: MLO STA vdev list + * + * This is internal wrapper of policy_mgr_mlo_sta_set_nlink to convert + * vdev based set link to link id based API for being compatible with old code. + * New code to use policy_mgr_mlo_sta_set_nlink directly as much as possible. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_mlo_sta_set_link_by_linkid(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t link_num, + uint8_t num_mlo_vdev, + uint8_t *mlo_vdev_lst, + uint8_t num_mlo_inactive_vdev, + uint8_t *mlo_inactive_vdev_lst) +{ + uint32_t link_bitmap = 0; + uint32_t link_bitmap2 = 0; + uint32_t assoc_bitmap = 0; + uint32_t vdev_bitmap[MLO_VDEV_BITMAP_SZ]; + uint32_t vdev_bitmap2[MLO_VDEV_BITMAP_SZ]; + uint8_t i, idx; + uint32_t link_control_flags = 0; + uint8_t vdev_per_bitmap = MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT; + + qdf_mem_zero(vdev_bitmap, sizeof(vdev_bitmap)); + qdf_mem_zero(vdev_bitmap2, sizeof(vdev_bitmap2)); + + for (i = 0; i < num_mlo_vdev; i++) { + idx = mlo_vdev_lst[i] / vdev_per_bitmap; + if (idx >= MLO_VDEV_BITMAP_SZ) + return QDF_STATUS_E_INVAL; + vdev_bitmap[idx] |= 1 << (mlo_vdev_lst[i] % vdev_per_bitmap); + } + + for (i = 0; i < num_mlo_inactive_vdev; i++) { + idx = mlo_inactive_vdev_lst[i] / vdev_per_bitmap; + if (idx >= MLO_VDEV_BITMAP_SZ) + return QDF_STATUS_E_INVAL; + vdev_bitmap2[idx] |= + 1 << (mlo_inactive_vdev_lst[i] % vdev_per_bitmap); + } + + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, MLO_VDEV_BITMAP_SZ, vdev_bitmap, + &link_bitmap, &assoc_bitmap); + + ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + psoc, vdev, MLO_VDEV_BITMAP_SZ, vdev_bitmap2, + &link_bitmap2, &assoc_bitmap); + + switch (mode) { + case MLO_LINK_FORCE_MODE_ACTIVE: + link_control_flags = link_ctrl_f_overwrite_active_bitmap; + break; + case MLO_LINK_FORCE_MODE_INACTIVE: + if (reason != MLO_LINK_FORCE_REASON_LINK_REMOVAL) + link_control_flags = + link_ctrl_f_overwrite_inactive_bitmap; + break; + case MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE: + if (reason != MLO_LINK_FORCE_REASON_LINK_REMOVAL) + link_control_flags = + link_ctrl_f_overwrite_active_bitmap | + link_ctrl_f_overwrite_inactive_bitmap; + break; + case MLO_LINK_FORCE_MODE_ACTIVE_NUM: + link_control_flags = link_ctrl_f_dynamic_force_link_num; + break; + case MLO_LINK_FORCE_MODE_INACTIVE_NUM: + link_control_flags = link_ctrl_f_dynamic_force_link_num; + break; + case MLO_LINK_FORCE_MODE_NO_FORCE: + link_control_flags = 0; + break; + default: + policy_mgr_err("Invalid force mode: %d", mode); + return QDF_STATUS_E_INVAL; + } + + return policy_mgr_mlo_sta_set_nlink(psoc, wlan_vdev_get_id(vdev), + reason, mode, + link_num, link_bitmap, + link_bitmap2, link_control_flags); +} + +/** + * policy_mgr_mlo_sta_set_link_ext() - Set links for MLO STA + * @psoc: psoc object + * @reason: Reason for which link is forced + * @mode: Force reason + * @num_mlo_vdev: number of mlo vdev + * @mlo_vdev_lst: MLO STA vdev list + * @num_mlo_inactive_vdev: number of mlo vdev + * @mlo_inactive_vdev_lst: MLO STA vdev list + * + * Interface manager Set links for MLO STA. And it supports to + * add inactive vdev list. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_mlo_sta_set_link_ext(struct wlan_objmgr_psoc *psoc, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t num_mlo_vdev, uint8_t *mlo_vdev_lst, + uint8_t num_mlo_inactive_vdev, + uint8_t *mlo_inactive_vdev_lst) +{ + struct mlo_link_set_active_req *req; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + + if (!num_mlo_vdev) { + policy_mgr_err("invalid 0 num_mlo_vdev"); + return QDF_STATUS_E_INVAL; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + /* + * Use one of the ML vdev as, if called from disconnect the caller vdev + * may get deleted, and thus flush serialization command. + */ + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, mlo_vdev_lst[0], + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d: invalid vdev", mlo_vdev_lst[0]); + qdf_mem_free(req); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_debug("vdev %d: mode %d num_mlo_vdev %d reason %d", + wlan_vdev_get_id(vdev), mode, num_mlo_vdev, reason); + + req->ctx.vdev = vdev; + req->param.reason = reason; + req->param.force_mode = mode; + req->ctx.set_mlo_link_cb = policy_mgr_handle_link_enable_disable_resp; + req->ctx.validate_set_mlo_link_cb = + policy_mgr_validate_set_mlo_link_cb; + req->ctx.cb_arg = req; + + /* set MLO vdev bit mask for all case */ + policy_mgr_fill_ml_active_link_vdev_bitmap(req, mlo_vdev_lst, + num_mlo_vdev); + + pm_ctx->active_vdev_bitmap = req->param.vdev_bitmap[0]; + pm_ctx->inactive_vdev_bitmap = req->param.vdev_bitmap[1]; + + if (mode == MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE) + policy_mgr_fill_ml_inactive_link_vdev_bitmap( + req, mlo_inactive_vdev_lst, num_mlo_inactive_vdev); + + /* + * Fill number of links for MLO_LINK_FORCE_MODE_ACTIVE_NUM or + * MLO_LINK_FORCE_MODE_INACTIVE_NUM mode. + */ + if (mode == MLO_LINK_FORCE_MODE_ACTIVE_NUM || + mode == MLO_LINK_FORCE_MODE_INACTIVE_NUM) { + req->param.num_link_entry = 1; + req->param.link_num[0].num_of_link = num_mlo_vdev - 1; + } + + if (ml_is_nlink_service_supported(psoc)) { + status = + policy_mgr_mlo_sta_set_link_by_linkid(psoc, vdev, reason, + mode, + req->param.link_num[0]. + num_of_link, + num_mlo_vdev, + mlo_vdev_lst, + num_mlo_inactive_vdev, + mlo_inactive_vdev_lst); + qdf_mem_free(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + if (status != QDF_STATUS_E_PENDING) { + policy_mgr_err("set_link_by_linkid status %d", status); + return status; + } + return QDF_STATUS_SUCCESS; + } + + policy_mgr_set_link_in_progress(pm_ctx, true); + + status = mlo_ser_set_link_req(req); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("vdev %d: Failed to set link mode %d num_mlo_vdev %d reason %d", + wlan_vdev_get_id(vdev), mode, num_mlo_vdev, + reason); + qdf_mem_free(req); + policy_mgr_set_link_in_progress(pm_ctx, false); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return status; +} + +QDF_STATUS +policy_mgr_mlo_sta_set_link(struct wlan_objmgr_psoc *psoc, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t num_mlo_vdev, uint8_t *mlo_vdev_lst) +{ + return policy_mgr_mlo_sta_set_link_ext(psoc, reason, mode, num_mlo_vdev, + mlo_vdev_lst, 0, NULL); +} + +QDF_STATUS +policy_mgr_mlo_sta_set_nlink(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t link_num, + uint16_t link_bitmap, + uint16_t link_bitmap2, + uint32_t link_control_flags) +{ + struct mlo_link_set_active_req *req; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", + vdev_id); + qdf_mem_free(req); + return QDF_STATUS_E_INVAL; + } + + policy_mgr_set_link_in_progress(pm_ctx, true); + + policy_mgr_debug("vdev %d: mode %d %s reason %d bitmap 0x%x 0x%x ctrl 0x%x", + wlan_vdev_get_id(vdev), mode, + force_mode_to_string(mode), reason, + link_bitmap, link_bitmap2, + link_control_flags); + + req->ctx.vdev = vdev; + req->param.reason = reason; + req->param.force_mode = mode; + req->param.use_ieee_link_id = true; + req->param.force_cmd.ieee_link_id_bitmap = link_bitmap; + req->param.force_cmd.ieee_link_id_bitmap2 = link_bitmap2; + req->param.force_cmd.link_num = link_num; + if (link_control_flags & link_ctrl_f_overwrite_active_bitmap) + req->param.control_flags.overwrite_force_active_bitmap = true; + if (link_control_flags & link_ctrl_f_overwrite_inactive_bitmap) + req->param.control_flags.overwrite_force_inactive_bitmap = + true; + if (link_control_flags & link_ctrl_f_dynamic_force_link_num) + req->param.control_flags.dynamic_force_link_num = true; + if (link_control_flags & link_ctrl_f_post_re_evaluate) + req->param.control_flags.post_re_evaluate = true; + + status = + wlan_vdev_get_bss_peer_mld_mac(vdev, + &req->param.force_cmd.ap_mld_mac_addr); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("fail to get ap mld addr for vdev %d", + wlan_vdev_get_id(vdev)); + goto end; + } + if (qdf_is_macaddr_zero(&req->param.force_cmd.ap_mld_mac_addr)) { + policy_mgr_err("get ap zero mld addr for vdev %d", + wlan_vdev_get_id(vdev)); + goto end; + } + + req->ctx.set_mlo_link_cb = policy_mgr_handle_link_enable_disable_resp; + req->ctx.validate_set_mlo_link_cb = + policy_mgr_validate_set_mlo_link_cb; + req->ctx.cb_arg = req; + status = mlo_ser_set_link_req(req); +end: + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("vdev %d: Failed to set link mode %d num_mlo_vdev %d reason %d", + wlan_vdev_get_id(vdev), mode, link_num, + reason); + qdf_mem_free(req); + policy_mgr_set_link_in_progress(pm_ctx, false); + } else { + status = QDF_STATUS_E_PENDING; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return status; +} + +uint32_t +policy_mgr_get_conc_ext_flags(struct wlan_objmgr_vdev *vdev, bool force_mlo) +{ + struct wlan_objmgr_vdev *assoc_vdev; + union conc_ext_flag conc_ext_flags; + + conc_ext_flags.value = 0; + if (!vdev || wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return conc_ext_flags.value; + + if (!force_mlo && !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return conc_ext_flags.value; + + conc_ext_flags.mlo = 1; + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { + assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); + if (assoc_vdev && ucfg_cm_is_vdev_active(assoc_vdev)) + conc_ext_flags.mlo_link_assoc_connected = 1; + } + + return conc_ext_flags.value; +} + +/** + * policy_mgr_allow_sta_concurrency() - check whether STA concurrency is allowed + * @psoc: Pointer to soc + * @freq: frequency to be checked + * @ext_flags: extended flags for concurrency check + * + * Return: true if supports else false. + */ +static bool +policy_mgr_allow_sta_concurrency(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, + uint32_t ext_flags) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + bool is_mlo, mlo_sta_present = false; + uint8_t vdev_id, sta_cnt = 0; + enum policy_mgr_con_mode mode; + union conc_ext_flag conc_ext_flags; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + conc_ext_flags.value = ext_flags; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + mode = pm_conc_connection_list[conn_index].mode; + if (mode != PM_STA_MODE || + !pm_conc_connection_list[conn_index].in_use) + continue; + + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + continue; + + is_mlo = wlan_vdev_mlme_is_mlo_vdev(vdev); + + /* Skip the link vdev for MLO STA */ + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + goto next; + + sta_cnt++; + if (!is_mlo) + goto next; + + mlo_sta_present = true; +next: + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* Reject if multiple STA connections are not allowed */ + if (sta_cnt && + !policy_mgr_allow_multiple_sta_connections(psoc)) { + policy_mgr_rl_debug("Disallow Multiple STA connections"); + return false; + } + + if (mlo_sta_present && conc_ext_flags.mlo_link_assoc_connected) { + policy_mgr_rl_debug("Allow secondary MLO link"); + return true; + } + + if (conc_ext_flags.mlo && mlo_sta_present) { + policy_mgr_rl_debug("Disallow ML STA when ML STA is present"); + return false; + } + + /* + * Reject a 3rd STA. + * Treat a MLO STA(including the primary and secondary link vdevs) + * as 1 STA here. + */ + if (sta_cnt >= 2) { + policy_mgr_rl_debug("Disallow 3rd STA"); + return false; + } + + return true; +} + +bool +policy_mgr_is_mlo_sap_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + bool is_new_vdev_mlo, + uint8_t new_vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + bool ret = false, mlo_sap_present = false; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return ret; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (!pm_conc_connection_list[conn_index].in_use || + (pm_conc_connection_list[conn_index].mode != PM_SAP_MODE)) + continue; + + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + if (vdev_id == new_vdev_id) + continue; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev for vdev_id:%d is NULL", vdev_id); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return ret; + } + + /* As only one ML SAP is allowed, break after one ML SAP + * instance found in the policy manager list. + */ + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + mlo_sap_present = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (is_new_vdev_mlo && mlo_sap_present) + ret = false; + else + ret = true; + + return ret; +} + +QDF_STATUS +policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *req, + enum wlan_mlo_link_switch_notify_reason notify_reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t vdev_id = req->vdev_id; + uint8_t curr_ieee_link_id = req->curr_ieee_link_id; + uint8_t new_ieee_link_id = req->new_ieee_link_id; + uint32_t new_primary_freq = req->new_primary_freq; + QDF_STATUS status; + union conc_ext_flag conc_ext_flags; + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + uint8_t num_del = 0; + struct ml_nlink_change_event data; + uint16_t dyn_inact_bmap = 0, force_inact_bmap = 0; + + if (notify_reason > MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER) + return QDF_STATUS_SUCCESS; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + policy_mgr_debug("target link %d freq %d curr link %d notify reason %d link switch reason %d vdev %d", + new_ieee_link_id, new_primary_freq, + curr_ieee_link_id, notify_reason, req->reason, + vdev_id); + qdf_mem_zero(&data, sizeof(data)); + data.evt.link_switch.curr_ieee_link_id = curr_ieee_link_id; + data.evt.link_switch.new_ieee_link_id = new_ieee_link_id; + data.evt.link_switch.new_primary_freq = new_primary_freq; + data.evt.link_switch.reason = req->reason; + status = ml_nlink_conn_change_notify(psoc, vdev_id, + ml_nlink_link_switch_start_evt, + &data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + policy_mgr_store_and_del_conn_info_by_vdev_id( + psoc, vdev_id, info, &num_del); + conc_ext_flags.value = + policy_mgr_get_conc_ext_flags(vdev, true); + ml_nlink_get_dynamic_inactive_links(psoc, vdev, &dyn_inact_bmap, + &force_inact_bmap); + + if (!(dyn_inact_bmap & BIT(new_ieee_link_id)) && + !policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE, + new_primary_freq, + HW_MODE_20_MHZ, + conc_ext_flags.value, + NULL)) { + status = QDF_STATUS_E_INVAL; + policy_mgr_debug("target link %d freq %d not allowed by conc rule", + new_ieee_link_id, new_primary_freq); + } + + if (num_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, info, num_del); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +bool policy_mgr_is_non_ml_sta_present(struct wlan_objmgr_psoc *psoc) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + bool non_ml_sta_present = false; + uint8_t vdev_id; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; + conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].mode != PM_STA_MODE || + !pm_conc_connection_list[conn_index].in_use) + continue; + + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + continue; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + non_ml_sta_present = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return non_ml_sta_present; +} + +bool policy_mgr_is_mlo_sta_present(struct wlan_objmgr_psoc *psoc) +{ + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + bool mlo_sta_present = false; + uint8_t vdev_id; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; + conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS && !mlo_sta_present; + conn_index++) { + if (pm_conc_connection_list[conn_index].mode != PM_STA_MODE || + !pm_conc_connection_list[conn_index].in_use) + continue; + + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + continue; + + mlo_sta_present = wlan_vdev_mlme_is_mlo_vdev(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return mlo_sta_present; +} + +bool policy_mgr_is_mlo_in_mode_sbs(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo) +{ + uint32_t mode_num = 0; + uint8_t i, mlo_idx = 0; + struct wlan_objmgr_vdev *temp_vdev; + qdf_freq_t mlo_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + bool is_sbs_link = true; + + mode_num = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, mode); + if (!mode_num || mode_num < 2) + return false; + + for (i = 0; i < mode_num; i++) { + temp_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id_list[i], + WLAN_POLICY_MGR_ID); + if (!temp_vdev) { + policy_mgr_err("invalid vdev for id %d", + vdev_id_list[i]); + return false; + } + + if (wlan_vdev_mlme_is_mlo_vdev(temp_vdev)) { + if (mlo_vdev_lst) + mlo_vdev_lst[mlo_idx] = vdev_id_list[i]; + mlo_freq_list[mlo_idx] = + wlan_get_operation_chan_freq(temp_vdev); + if (wlan_reg_is_24ghz_ch_freq(mlo_freq_list[mlo_idx])) + is_sbs_link = false; + mlo_idx++; + } + wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_POLICY_MGR_ID); + } + + if (num_mlo) + *num_mlo = mlo_idx; + if (mlo_idx < 2) + is_sbs_link = false; + if (is_sbs_link && + !policy_mgr_are_sbs_chan(psoc, mlo_freq_list[0], + mlo_freq_list[1])) { + policy_mgr_debug("Freq %d and %d are not SBS, set SBS false", + mlo_freq_list[0], + mlo_freq_list[1]); + is_sbs_link = false; + } + + return is_sbs_link; +} + +bool policy_mgr_is_mlo_in_mode_dbs(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo) +{ + uint32_t mode_num = 0; + uint8_t i, mlo_idx = 0; + struct wlan_objmgr_vdev *temp_vdev; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + bool has_2g_link = false; + bool has_5g_link = false; + qdf_freq_t mlo_freq; + + mode_num = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, mode); + if (!mode_num || mode_num < 2) + return false; + + for (i = 0; i < mode_num; i++) { + temp_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, + vdev_id_list[i], + WLAN_POLICY_MGR_ID); + if (!temp_vdev) { + policy_mgr_err("invalid vdev for id %d", + vdev_id_list[i]); + return false; + } + + if (wlan_vdev_mlme_is_mlo_vdev(temp_vdev)) { + if (mlo_vdev_lst) + mlo_vdev_lst[mlo_idx] = vdev_id_list[i]; + mlo_freq = + wlan_get_operation_chan_freq(temp_vdev); + if (wlan_reg_is_24ghz_ch_freq(mlo_freq)) + has_2g_link = true; + else + has_5g_link = true; + mlo_idx++; + } + wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_POLICY_MGR_ID); + } + + if (num_mlo) + *num_mlo = mlo_idx; + + return has_2g_link && has_5g_link; +} + +bool policy_mgr_is_curr_hwmode_emlsr(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_hw_mode_params hw_mode; + + if (!policy_mgr_is_hw_emlsr_capable(psoc)) + return false; + + if (QDF_STATUS_SUCCESS != policy_mgr_get_current_hw_mode(psoc, + &hw_mode)) + return false; + + if (!hw_mode.emlsr_cap) + return false; + + return true; +} + +bool policy_mgr_is_mlo_in_mode_emlsr(struct wlan_objmgr_psoc *psoc, + uint8_t *mlo_vdev_lst, uint8_t *num_mlo) +{ + bool emlsr_connection = false; + uint32_t mode_num = 0; + uint8_t i, mlo_idx = 0; + struct wlan_objmgr_vdev *temp_vdev; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + mode_num = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, + PM_STA_MODE); + + for (i = 0; i < mode_num; i++) { + temp_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id_list[i], + WLAN_POLICY_MGR_ID); + if (!temp_vdev) { + policy_mgr_err("invalid vdev for id %d", + vdev_id_list[i]); + goto end; + } + + if (wlan_vdev_mlme_is_mlo_vdev(temp_vdev)) { + if (mlo_vdev_lst) + mlo_vdev_lst[mlo_idx] = vdev_id_list[i]; + mlo_idx++; + } + /* Check if existing vdev is eMLSR STA */ + if (wlan_vdev_mlme_cap_get(temp_vdev, WLAN_VDEV_C_EMLSR_CAP)) + emlsr_connection = true; + + wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_POLICY_MGR_ID); + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_DISABLE_LINK; i++) { + if (!pm_disabled_ml_links[i].in_use) + continue; + if (pm_disabled_ml_links[i].mode != PM_STA_MODE) + continue; + temp_vdev = + wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, pm_disabled_ml_links[i].vdev_id, + WLAN_POLICY_MGR_ID); + if (!temp_vdev) { + policy_mgr_err("invalid inactive vdev for id %d", + pm_disabled_ml_links[i].vdev_id); + continue; + } + /* Check if existing vdev is eMLSR STA */ + if (wlan_vdev_mlme_cap_get(temp_vdev, WLAN_VDEV_C_EMLSR_CAP)) + emlsr_connection = true; + wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_POLICY_MGR_ID); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +end: + if (num_mlo) + *num_mlo = mlo_idx; + + return emlsr_connection; +} + +static void policy_mgr_restore_no_force(struct wlan_objmgr_psoc *psoc, + uint8_t num_mlo, + uint8_t mlo_vdev_lst[], + bool conc_con_coming_up) +{ + struct ml_link_force_state force_cmd = {0}; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + if (num_mlo < 1) { + policy_mgr_err("invalid num_mlo %d", + num_mlo); + return; + } + + vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + mlo_vdev_lst[0], + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", + mlo_vdev_lst[0]); + return; + } + + ml_nlink_get_curr_force_state(psoc, vdev, &force_cmd); + if (!conc_con_coming_up || force_cmd.force_active_bitmap) { + if (ml_is_nlink_service_supported(psoc)) + status = policy_mgr_mlo_sta_set_nlink( + psoc, mlo_vdev_lst[0], + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + 0, 0, 0, 0); + else + status = policy_mgr_mlo_sta_set_link( + psoc, + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + num_mlo, mlo_vdev_lst); + /* If concurrency vdev is coming up and force active bitmap + * is present, we need to wait for the respone of no force + * command. + */ + if (force_cmd.force_active_bitmap && conc_con_coming_up) { + if (status == QDF_STATUS_E_PENDING) + policy_mgr_wait_for_set_link_update(psoc); + else + policy_mgr_err("status %d", status); + + ml_nlink_get_curr_force_state(psoc, vdev, &force_cmd); + ml_nlink_dump_force_state(&force_cmd, ""); + } + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); +} + +void policy_mgr_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc, + bool conc_con_coming_up, + bool emlsr_sta_coming_up) +{ + uint8_t num_mlo = 0; + uint8_t mlo_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + bool is_mlo_emlsr = false; + uint8_t num_disabled_ml_sta = 0; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + is_mlo_emlsr = policy_mgr_is_mlo_in_mode_emlsr(psoc, mlo_vdev_lst, + &num_mlo); + policy_mgr_debug("num_mlo %d is_mlo_emlsr %d conc_con_coming_up: %d", + num_mlo, is_mlo_emlsr, conc_con_coming_up); + + if (!is_mlo_emlsr) + return; + + if (num_mlo < 2) { + policy_mgr_debug("conc_con_coming_up %d num mlo sta links %d", + conc_con_coming_up, num_mlo); + policy_mgr_get_ml_sta_info(pm_ctx, &num_mlo, + &num_disabled_ml_sta, + mlo_vdev_lst, ml_freq_lst, + NULL, NULL, NULL); + if (policy_mgr_get_connection_count(psoc) != 1 || + !num_disabled_ml_sta) + return; + } + + if (conc_con_coming_up || + (emlsr_sta_coming_up && + policy_mgr_get_connection_count(psoc) > 2)) { + /* + * If any force active link bitmap is present, we have to + * clear the force active bitmap from target. Otherwise that + * will be conflict with the force inactive num bitmap, then + * target can't handle force inactive num 1 command to exit + * EMLSR. + */ + if (conc_con_coming_up) + policy_mgr_restore_no_force(psoc, num_mlo, + mlo_vdev_lst, + conc_con_coming_up); + + /* + * Force disable one of the links (FW will decide which link) if + * 1) EMLSR STA is present and SAP/STA/NAN connection comes up. + * 2) There is a legacy connection (SAP/P2P/NAN) and a STA comes + * up in EMLSR mode. + */ + policy_mgr_mlo_sta_set_link(psoc, MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_INACTIVE_NUM, + num_mlo, mlo_vdev_lst); + return; + } + + if (!conc_con_coming_up && emlsr_sta_coming_up) + /* + * No force i.e. Re-enable the disabled link if- + * 1) EMLSR STA is present and new SAP/STA/NAN connection goes + * down. One of the links was disabled while a new connection + * came up. + * 2) Legacy connection (SAP/P2P/NAN) goes down and if STA is + * EMLSR capable. One of the links was disabled after EMLSR + * association. + */ + policy_mgr_restore_no_force(psoc, num_mlo, + mlo_vdev_lst, + conc_con_coming_up); +} + +bool +policy_mgr_is_emlsr_sta_concurrency_present(struct wlan_objmgr_psoc *psoc) +{ + uint8_t num_mlo = 0; + + if (policy_mgr_is_mlo_in_mode_emlsr(psoc, NULL, &num_mlo) && + num_mlo < policy_mgr_get_connection_count(psoc)) + return true; + + return false; +} + +static uint8_t +policy_mgr_get_affected_links_for_sta_sta(struct wlan_objmgr_psoc *psoc, + uint8_t num_ml, qdf_freq_t *freq_list, + uint8_t *vdev_id_list, + uint8_t *ml_vdev_lst, + uint8_t *ml_idx, qdf_freq_t freq) +{ + uint8_t i = 0; + bool same_band_sta_allowed; + + /* + * STA freq: ML STA combo: SBS Action + * --------------------------------------------------- + * 2Ghz 2Ghz+5/6Ghz Disable 2Ghz(Same MAC) + * 5Ghz 2Ghz+5/6Ghz Disable 2.4Ghz if 5Ghz lead to SBS + * (SBS, same MAC) and same band STA + * allowed, else disable 5/6Ghz + * (NON SBS, same MAC) + * 5Ghz(lower) 5Ghz+6Ghz Disable 5Ghz (NON SBS, same MAC) + * 5Ghz(higher) 5Ghz+6Ghz Disable 6Ghz (NON SBS, Same MAC) + * 2Ghz 5Ghz+6Ghz Disable Any + */ + + /* If non-ML STA is 2.4Ghz disable 2.4Ghz if present OR disable any */ + if (wlan_reg_is_24ghz_ch_freq(freq)) { + while (i < num_ml) { + if (wlan_reg_is_24ghz_ch_freq(freq_list[ml_idx[i]])) { + /* Affected ML STA link on 2.4Ghz */ + ml_vdev_lst[0] = vdev_id_list[ml_idx[i]]; + return 1; + } + /* Fill non effected vdev in list */ + ml_vdev_lst[i] = vdev_id_list[ml_idx[i]]; + i++; + } + /* No link affected return num_ml to disable any */ + return i; + } + + /* This mean non-ML STA is 5Ghz */ + + /* check if ML STA is DBS */ + i = 0; + while (i < num_ml && + !wlan_reg_is_24ghz_ch_freq(freq_list[ml_idx[i]])) + i++; + + same_band_sta_allowed = wlan_cm_same_band_sta_allowed(psoc); + + /* + * if ML STA is DBS ie 2.4Ghz link present and if same_band_sta_allowed + * is false, disable 5/6Ghz link to make sure we dont have all link + * on 5Ghz + */ + if (i < num_ml && !same_band_sta_allowed) + goto check_dbs_ml; + + /* check if any link lead to SBS, so that we can disable the other*/ + i = 0; + while (i < num_ml && + !policy_mgr_are_sbs_chan(psoc, freq, freq_list[ml_idx[i]])) + i++; + + /* + * if i < num_ml then i is the SBS link, in this case disable the other + * non SBS link, this mean ML STA is 5+6 or 2+5/6. + */ + if (i < num_ml) { + i = 0; + while (i < num_ml) { + if (!policy_mgr_are_sbs_chan(psoc, freq, + freq_list[ml_idx[i]])) { + /* Affected non SBS ML STA link */ + ml_vdev_lst[0] = vdev_id_list[ml_idx[i]]; + return 1; + } + /* Fill non effected vdev in list */ + ml_vdev_lst[i] = vdev_id_list[ml_idx[i]]; + i++; + } + /* All link lead to SBS, disable any, This should not happen */ + return i; + } + +check_dbs_ml: + /* + * None of the link can lead to SBS, i.e. its 2+ 5/6 ML STA in this case + * disable 5Ghz link. + */ + i = 0; + while (i < num_ml) { + if (!wlan_reg_is_24ghz_ch_freq(freq_list[ml_idx[i]])) { + /* Affected 5/6Ghz ML STA link */ + ml_vdev_lst[0] = vdev_id_list[ml_idx[i]]; + return 1; + } + /* Fill non effected vdev in list */ + ml_vdev_lst[i] = vdev_id_list[ml_idx[i]]; + i++; + } + + /* No link affected, This should not happen */ + return i; +} + +/* + * policy_mgr_get_concurrent_num_links() - get links which are affected + * if no affected then return num ml. Also fills the ml_vdev_lst to send. + * @num_ml: number of ML vdev + * @freq_list: freq list of all vdev + * @vdev_id_list: vdev id list + * @ml_vdev_lst: ML vdev list + * @ml_idx: ML index + * @freq: non ML STA freq + * + * Return: number of the affected links, else total link and ml_vdev_lst list. + */ +static uint8_t +policy_mgr_get_concurrent_num_links(struct wlan_objmgr_vdev *vdev, + uint8_t num_ml, qdf_freq_t *freq_list, + uint8_t *vdev_id_list, + uint8_t *ml_vdev_lst, + uint8_t *ml_idx, qdf_freq_t freq) +{ + uint8_t i = 0; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return 0; + + while (i < num_ml && (freq_list[ml_idx[i]] != freq)) + i++; + + if (i < num_ml) { + /* if one link is SCC then no need to disable any link */ + policy_mgr_debug("vdev %d: ML vdev %d lead to SCC, STA freq %d ML freq %d, no need to disable link", + wlan_vdev_get_id(vdev), + vdev_id_list[ml_idx[i]], + freq, freq_list[ml_idx[i]]); + return 0; + } + + + return policy_mgr_get_affected_links_for_sta_sta(psoc, num_ml, + freq_list, + vdev_id_list, + ml_vdev_lst, + ml_idx, freq); +} + +static void +policy_mgr_ml_sta_concurrency_on_connect(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t num_ml, uint8_t *ml_idx, + uint8_t num_non_ml, uint8_t *non_ml_idx, + qdf_freq_t *freq_list, + uint8_t *vdev_id_list) +{ + qdf_freq_t freq = 0; + struct wlan_channel *bss_chan; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t affected_links = 0; + enum mlo_link_force_mode mode = MLO_LINK_FORCE_MODE_ACTIVE_NUM; + + /* non ML STA doesn't exist, no need to change to link.*/ + if (!num_non_ml) + return; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + freq = freq_list[non_ml_idx[0]]; + } else { + bss_chan = wlan_vdev_mlme_get_bss_chan(vdev); + if (bss_chan) + freq = bss_chan->ch_freq; + } + policy_mgr_debug("vdev %d: Freq %d (non ML vdev id %d), is ML STA %d", + vdev_id, freq, vdev_id_list[non_ml_idx[0]], + wlan_vdev_mlme_is_mlo_vdev(vdev)); + if (!freq) + return; + + affected_links = + policy_mgr_get_concurrent_num_links(vdev, num_ml, freq_list, + vdev_id_list, ml_vdev_lst, + ml_idx, freq); + + if (!affected_links) { + policy_mgr_debug("vdev %d: no affected link found", vdev_id); + return; + } + policy_mgr_debug("affected link found: %u vdev_id: %u", + affected_links, ml_vdev_lst[0]); + + /* + * If affected link is less than num_ml, ie not all link are affected, + * send MLO_LINK_FORCE_MODE_INACTIVE. + */ + if (affected_links < num_ml && + affected_links <= MAX_NUMBER_OF_CONC_CONNECTIONS) { + if (mlo_is_sta_inactivity_allowed_with_quiet(psoc, vdev_id_list, + num_ml, ml_idx, + affected_links, + ml_vdev_lst)) { + mode = MLO_LINK_FORCE_MODE_INACTIVE; + } else { + policy_mgr_debug("vdev %d: force inactivity is not allowed", + ml_vdev_lst[0]); + return; + } + } + + policy_mgr_mlo_sta_set_link(psoc, MLO_LINK_FORCE_REASON_CONNECT, + mode, affected_links, ml_vdev_lst); +} + +static void +policy_mgr_get_disabled_ml_sta_idx(struct wlan_objmgr_psoc *psoc, + uint8_t *ml_sta, + uint8_t *ml_idx, + qdf_freq_t *freq_list, + uint8_t *vdev_id_list, uint8_t next_idx) +{ + uint8_t conn_index, fill_index = next_idx; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + /* Get disabled link info as well and keep it at last */ + for (conn_index = 0; conn_index < MAX_NUMBER_OF_DISABLE_LINK; + conn_index++) { + if (!pm_disabled_ml_links[conn_index].in_use) + continue; + if (pm_disabled_ml_links[conn_index].mode != PM_STA_MODE) + continue; + if ((fill_index >= MAX_NUMBER_OF_CONC_CONNECTIONS) || + (*ml_sta >= MAX_NUMBER_OF_CONC_CONNECTIONS)) { + policy_mgr_err("Invalid fill_index: %d or ml_sta: %d", + fill_index, *ml_sta); + break; + } + vdev_id_list[fill_index] = + pm_disabled_ml_links[conn_index].vdev_id; + freq_list[fill_index] = pm_disabled_ml_links[conn_index].freq; + ml_idx[(*ml_sta)++] = fill_index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +/** + * policy_mgr_handle_ml_sta_link_concurrency() - Handle STA+ML_STA concurrency + * @psoc: PSOC object information + * @vdev: vdev of the changed interface caller + * + * Return: void + */ +static QDF_STATUS +policy_mgr_handle_ml_sta_link_concurrency(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t num_ml = 0, num_non_ml = 0, next_idx, disabled_links; + uint8_t ml_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t non_ml_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + /* Skip non STA connection handling */ + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return QDF_STATUS_E_INVAL; + + /* + * Skip this in case of SAP/P2P Concurrencies, to avoid renable of + * the link, disabled by SAP/P2P logic, as this API only consider + * STA specific counts and ignore other counts. + */ + if (policy_mgr_get_beaconing_mode_count(psoc, NULL) || + policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL)) { + policy_mgr_debug("SAP/GO/CLI exist ignore this check"); + return QDF_STATUS_E_INVAL; + } + + policy_mgr_get_ml_and_non_ml_sta_count(psoc, &num_ml, ml_idx, + &num_non_ml, non_ml_idx, + freq_list, vdev_id_list); + /* Skip non STA+STA cases */ + if (!num_ml || !num_non_ml) + return QDF_STATUS_E_INVAL; + + next_idx = num_ml + num_non_ml; + policy_mgr_get_disabled_ml_sta_idx(psoc, &num_ml, ml_idx, + freq_list, vdev_id_list, next_idx); + + disabled_links = num_ml - (next_idx - num_non_ml); + policy_mgr_debug("vdev %d: num_ml %d num_non_ml %d disabled_links: %d", + wlan_vdev_get_id(vdev), num_ml, num_non_ml, + disabled_links); + + /* ML STA is not up or not sufficient links to disable */ + if (num_ml < 2 || num_ml > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_ml - disabled_links < 2) { + policy_mgr_debug("ML STA is not up or not sufficient links to disable"); + return QDF_STATUS_E_INVAL; + } + /* + * TODO: Check if both link enable/ link switch is possible when + * secondary STA switch happens to a new channel due to CSA + */ + + policy_mgr_ml_sta_concurrency_on_connect(psoc, vdev, num_ml, + ml_idx, num_non_ml, + non_ml_idx, freq_list, + vdev_id_list); + return QDF_STATUS_SUCCESS; +} + +static bool +policy_mgr_is_mode_p2p_sap(enum policy_mgr_con_mode mode) +{ + return (policy_mgr_is_beaconing_mode(mode) || + (mode == PM_P2P_CLIENT_MODE)); +} + +bool +policy_mgr_is_vdev_high_tput_or_low_latency(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_vdev_ll_ht; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", vdev_id); + return false; + } + is_vdev_ll_ht = wlan_is_vdev_traffic_ll_ht(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return is_vdev_ll_ht; +} + +bool +policy_mgr_check_2ghz_only_sap_affected_link( + struct wlan_objmgr_psoc *psoc, + uint8_t sap_vdev_id, + qdf_freq_t sap_ch_freq, + uint8_t ml_ch_freq_num, + qdf_freq_t *ml_freq_lst) +{ + uint8_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE op_mode; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq)) + return false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, sap_vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_debug("vdev is null %d", sap_vdev_id); + return false; + } + op_mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + if (op_mode != QDF_SAP_MODE) + return false; + + if (!policy_mgr_is_acs_2ghz_only_sap(psoc, sap_vdev_id)) + return false; + + /* If 2G ml STA exist, force scc will happen, no link + * to get affected. + */ + for (i = 0; i < ml_ch_freq_num; i++) + if (WLAN_REG_IS_24GHZ_CH_FREQ(ml_freq_lst[i])) + return false; + + /* If All ml STA are 5/6 band, force SCC will not happen + * for 2G only SAP, so return true to indicate one + * link get affected. + */ + return true; +} + +/* + * policy_mgr_get_affected_links_for_go_sap_cli() - Check if any of the P2P OR + * SAP is causing MCC with a ML link and also is configured high tput or low + * latency + * @psoc: psoc ctx + * @num_ml_sta: Number of ML STA present + * @ml_vdev_lst: ML STA vdev id list + * @ml_freq_lst: ML STA freq list + * @num_p2p_sap: Number of P2P and SAP present + * @p2p_sap_vdev_lst: P2P and SAP vdev id list + * @p2p_sap_freq_lst: P2P and SAP freq list + * + * Return: Number of links causing MCC with any of the P2P or SAP which is + * configured high tput or low latency + */ +static uint8_t +policy_mgr_get_affected_links_for_go_sap_cli(struct wlan_objmgr_psoc *psoc, + uint8_t num_ml_sta, + uint8_t *ml_vdev_lst, + qdf_freq_t *ml_freq_lst, + uint8_t num_p2p_sap, + uint8_t *p2p_sap_vdev_lst, + qdf_freq_t *p2p_sap_freq_lst) +{ + uint8_t i = 0, k = 0, num_affected_links = 0; + + if (!num_p2p_sap || num_ml_sta < 2) + return num_affected_links; + + while (i < num_ml_sta) { + /* if any link is causing MCC with GO/GC/AP, set mcc as true.*/ + for (k = 0; k < num_p2p_sap; k++) { + /* Continue if SCC */ + if (ml_freq_lst[i] == p2p_sap_freq_lst[k]) + continue; + + /* SAP MCC with MLO STA link is not preferred. + * If SAP is 2Ghz only by ACS and two ML link are + * 5/6 band, then force SCC may not happen. In such + * case inactive one link. + */ + if (policy_mgr_check_2ghz_only_sap_affected_link( + psoc, p2p_sap_vdev_lst[k], + p2p_sap_freq_lst[k], + num_ml_sta, ml_freq_lst)) { + policy_mgr_debug("2G only SAP vdev %d ch freq %d is not SCC with any MLO STA link", + p2p_sap_vdev_lst[k], + p2p_sap_freq_lst[k]); + num_affected_links++; + continue; + } + + /* Continue if high tput or low latency is not set */ + if (!policy_mgr_is_vdev_high_tput_or_low_latency( + psoc, p2p_sap_vdev_lst[k])) + continue; + + /* If both freq are on same mac then its MCC */ + if (policy_mgr_are_2_freq_on_same_mac(psoc, + ml_freq_lst[i], + p2p_sap_freq_lst[k])) { + policy_mgr_debug("ml sta vdev %d (freq %d) and p2p/sap vdev %d (freq %d) are MCC", + ml_vdev_lst[i], ml_freq_lst[i], + p2p_sap_vdev_lst[k], + p2p_sap_freq_lst[k]); + num_affected_links++; + } + } + i++; + } + + return num_affected_links; +} + +/* + * policy_mgr_get_ml_sta_and_p2p_cli_go_sap_info() - Get number of ML STA, + * P2P and SAP interfaces and their vdev ids and freq list + * @pm_ctx: pm_ctx ctx + * @num_ml_sta: Return number of ML STA present + * @num_disabled_ml_sta: Return number of disabled ML STA links + * @ml_vdev_lst: Return ML STA vdev id list + * @ml_freq_lst: Return ML STA freq list + * @num_p2p_sap: Return number of P2P and SAP present + * @p2p_sap_vdev_lst: Return P2P and SAP vdev id list + * @p2p_sap_freq_lst: Return P2P and SAP freq list + * + * Return: void + */ +static void +policy_mgr_get_ml_sta_and_p2p_cli_go_sap_info( + struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t *num_ml_sta, + uint8_t *num_disabled_ml_sta, + uint8_t *ml_vdev_lst, + qdf_freq_t *ml_freq_lst, + uint8_t *num_p2p_sap, + uint8_t *p2p_sap_vdev_lst, + qdf_freq_t *p2p_sap_freq_lst) +{ + enum policy_mgr_con_mode mode; + uint8_t vdev_id, conn_index; + qdf_freq_t freq; + + *num_p2p_sap = 0; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_get_ml_sta_info(pm_ctx, num_ml_sta, num_disabled_ml_sta, + ml_vdev_lst, ml_freq_lst, NULL, NULL, NULL); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (!pm_conc_connection_list[conn_index].in_use) + continue; + mode = pm_conc_connection_list[conn_index].mode; + if (!policy_mgr_is_mode_p2p_sap(mode)) + continue; + vdev_id = pm_conc_connection_list[conn_index].vdev_id; + freq = pm_conc_connection_list[conn_index].freq; + + /* add p2p and sap vdev and freq list */ + p2p_sap_vdev_lst[*num_p2p_sap] = vdev_id; + p2p_sap_freq_lst[(*num_p2p_sap)++] = freq; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +/* + * policy_mgr_is_ml_sta_links_in_mcc() - Check ML links are in MCC or not + * @psoc: psoc ctx + * @ml_freq_lst: ML STA freq list + * @ml_vdev_lst: ML STA vdev id list + * @ml_linkid_lst: ML STA link id list + * @num_ml_sta: Number of total ML STA links + * @affected_linkid_bitmap: link id bitmap which home channels are in MCC + * with each other + * + * Return: true if ML link in MCC else false + */ +bool +policy_mgr_is_ml_sta_links_in_mcc(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *ml_freq_lst, + uint8_t *ml_vdev_lst, + uint8_t *ml_linkid_lst, + uint8_t num_ml_sta, + uint32_t *affected_linkid_bitmap) +{ + uint8_t i, j; + uint32_t link_id_bitmap; + + for (i = 0; i < num_ml_sta; i++) { + link_id_bitmap = 0; + if (ml_linkid_lst) + link_id_bitmap = 1 << ml_linkid_lst[i]; + for (j = i + 1; j < num_ml_sta; j++) { + if (ml_freq_lst[i] != ml_freq_lst[j] && + policy_mgr_2_freq_always_on_same_mac( + psoc, ml_freq_lst[i], ml_freq_lst[j])) { + if (ml_vdev_lst) + policy_mgr_debug("vdev %d and %d are in MCC with freq %d and freq %d", + ml_vdev_lst[i], + ml_vdev_lst[j], + ml_freq_lst[i], + ml_freq_lst[j]); + if (ml_linkid_lst) { + link_id_bitmap |= 1 << ml_linkid_lst[j]; + policy_mgr_debug("link %d and %d are in MCC with freq %d and freq %d", + ml_linkid_lst[i], + ml_linkid_lst[j], + ml_freq_lst[i], + ml_freq_lst[j]); + if (affected_linkid_bitmap) + *affected_linkid_bitmap = + link_id_bitmap; + } + return true; + } + } + } + + return false; +} + +QDF_STATUS +policy_mgr_is_ml_links_in_mcc_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *ml_sta_vdev_lst, + uint8_t *num_ml_sta) +{ + uint8_t num_disabled_ml_sta = 0; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_get_ml_sta_info(pm_ctx, num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, + NULL, NULL, NULL); + if (*num_ml_sta < 2 || *num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_disabled_ml_sta) { + policy_mgr_debug("num_ml_sta invalid %d or link already disabled%d", + *num_ml_sta, num_disabled_ml_sta); + return QDF_STATUS_E_FAILURE; + } + + if (!policy_mgr_is_ml_sta_links_in_mcc(psoc, ml_freq_lst, + ml_sta_vdev_lst, NULL, + *num_ml_sta, + NULL)) + return QDF_STATUS_E_FAILURE; + + /* + * eMLSR is allowed in MCC mode also. So, don't disable any links + * if current connection happens in eMLSR mode. + */ + if (policy_mgr_is_mlo_in_mode_emlsr(psoc, NULL, NULL)) { + policy_mgr_debug("Don't disable eMLSR links"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_handle_mcc_ml_sta() - disables one ML STA link if causing MCC + * DBS - if ML STA links on 5 GHz + 6 GHz + * SBS - if both ML STA links on 5 GHz high/5 GHz low + * non-SBS - any combo (5/6 GHz + 5/6 GHz OR 2 GHz + 5/6 GHz) + * @psoc: psoc ctx + * @vdev: Pointer to vdev object + * + * Return: Success if MCC link is disabled else failure + */ +static QDF_STATUS +policy_mgr_handle_mcc_ml_sta(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t num_ml_sta = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + QDF_STATUS status; + + if ((wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE)) + return QDF_STATUS_E_FAILURE; + + status = policy_mgr_is_ml_links_in_mcc_allowed(psoc, vdev, + ml_sta_vdev_lst, + &num_ml_sta); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + policy_mgr_mlo_sta_set_link(psoc, MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_NUM, + num_ml_sta, ml_sta_vdev_lst); + + return QDF_STATUS_SUCCESS; +} + +/* + * policy_mgr_sta_ml_link_enable_allowed() - Check with given ML links and + * existing concurrencies, a disabled ml link can be enabled back. + * @psoc: psoc ctx + * @num_disabled_ml_sta: Number of existing disabled links + * @num_ml_sta: Number of total ML STA links + * @ml_freq_lst: ML STA freq list + * @ml_vdev_lst: ML STA vdev id list + * + * Return: if link can be enabled or not + */ +static bool +policy_mgr_sta_ml_link_enable_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t num_disabled_ml_sta, + uint8_t num_ml_sta, + qdf_freq_t *ml_freq_lst, + uint8_t *ml_vdev_lst) +{ + union conc_ext_flag conc_ext_flags; + uint8_t disabled_link_vdev_id; + qdf_freq_t disabled_link_freq; + struct wlan_objmgr_vdev *vdev; + + /* If no link is disabled nothing to do */ + if (!num_disabled_ml_sta || num_ml_sta < 2) + return false; + if (policy_mgr_is_ml_sta_links_in_mcc(psoc, ml_freq_lst, ml_vdev_lst, + NULL, num_ml_sta, + NULL)) + return false; + /* Disabled link is at the last index */ + disabled_link_vdev_id = ml_vdev_lst[num_ml_sta - 1]; + disabled_link_freq = ml_freq_lst[num_ml_sta - 1]; + policy_mgr_debug("disabled_link_vdev_id %d disabled_link_freq %d", + disabled_link_vdev_id, disabled_link_freq); + if (!disabled_link_freq) + return false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, disabled_link_vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("invalid vdev for id %d", disabled_link_vdev_id); + return false; + } + conc_ext_flags.value = policy_mgr_get_conc_ext_flags(vdev, false); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE, + disabled_link_freq, HW_MODE_20_MHZ, + conc_ext_flags.value, NULL); +} + +/* + * policy_mgr_re_enable_ml_sta_on_p2p_sap_down() - Handle enable + * link on P2P/SAP/ML_STA vdev UP or channel change + * @psoc: objmgr psoc + * @vdev: vdev which went UP or changed chan + * + * Return: void + */ +static void +policy_mgr_handle_sap_cli_go_ml_sta_up_csa(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t num_ml_sta = 0, num_p2p_sap = 0, num_disabled_ml_sta = 0; + uint8_t num_affected_link; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t p2p_sap_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t p2p_sap_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + status = policy_mgr_handle_ml_sta_link_state_allowed( + psoc, MLO_LINK_FORCE_REASON_CONNECT); + if (QDF_IS_STATUS_ERROR(status)) + return; + + /* + * eMLSR API policy_mgr_handle_emlsr_sta_concurrency() takes care of + * eMLSR concurrencies. Currently, eMLSR STA can't operate with any + * cocurrent mode, i.e. one link gets force-disabled when a new + * concurrecy is coming up. + */ + if (policy_mgr_is_mlo_in_mode_emlsr(psoc, NULL, NULL)) { + policy_mgr_debug("STA connected in eMLSR mode, don't enable/disable links"); + return; + } + + if (QDF_IS_STATUS_SUCCESS(policy_mgr_handle_mcc_ml_sta(psoc, vdev))) + return; + + status = policy_mgr_handle_ml_sta_link_concurrency(psoc, vdev); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + policy_mgr_get_ml_sta_and_p2p_cli_go_sap_info(pm_ctx, &num_ml_sta, + &num_disabled_ml_sta, + ml_sta_vdev_lst, + ml_freq_lst, &num_p2p_sap, + p2p_sap_vdev_lst, + p2p_sap_freq_lst); + + policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_p2p_sap %d", + vdev_id, num_ml_sta, num_disabled_ml_sta, num_p2p_sap); + if (num_ml_sta < 2 || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_p2p_sap > MAX_NUMBER_OF_CONC_CONNECTIONS) + return; + + num_affected_link = policy_mgr_get_affected_links_for_go_sap_cli(psoc, + num_ml_sta, ml_sta_vdev_lst, + ml_freq_lst, num_p2p_sap, + p2p_sap_vdev_lst, + p2p_sap_freq_lst); + + if (!num_affected_link) { + policy_mgr_debug("vdev %d: no affected link found", vdev_id); + goto enable_link; + } + + if (num_disabled_ml_sta) { + policy_mgr_debug("As a link is already disabled and affected link present (%d), No action required", + num_affected_link); + return; + } + + policy_mgr_mlo_sta_set_link(psoc, MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_NUM, + num_ml_sta, ml_sta_vdev_lst); + + return; +enable_link: + + /* + * if no affected link and link can be allowed to enable then renable + * the disabled link. + */ + if (policy_mgr_sta_ml_link_enable_allowed(psoc, num_disabled_ml_sta, + num_ml_sta, ml_freq_lst, + ml_sta_vdev_lst)) + policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + num_ml_sta, ml_sta_vdev_lst); +} + +void +policy_mgr_handle_ml_sta_links_on_vdev_up_csa(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d: invalid vdev", vdev_id); + return; + } + + if (mode == QDF_STA_MODE || mode == QDF_SAP_MODE || + mode == QDF_P2P_CLIENT_MODE || mode == QDF_P2P_GO_MODE) + policy_mgr_handle_sap_cli_go_ml_sta_up_csa(psoc, vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); +} + +#define SET_LINK_TIMEOUT 6000 +QDF_STATUS policy_mgr_wait_for_set_link_update(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + if (!policy_mgr_get_link_in_progress(pm_ctx)) { + policy_mgr_err("link is not in progress"); + return QDF_STATUS_E_FAILURE; + } + + status = + qdf_wait_for_event_completion(&pm_ctx->set_link_update_done_evt, + SET_LINK_TIMEOUT); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_set_link_in_progress(pm_ctx, false); + policy_mgr_err("wait for set_link_in_progress failed"); + } + + return status; +} + +void policy_mgr_handle_ml_sta_link_on_traffic_type_change( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + /* Check if any set link is already progress and thus wait */ + policy_mgr_wait_for_set_link_update(psoc); + + ml_nlink_conn_change_notify( + psoc, wlan_vdev_get_id(vdev), + ml_nlink_connection_updated_evt, NULL); + + /* + * Check if traffic type change lead to set link is progress and + * thus wait for it to complete. + */ + policy_mgr_wait_for_set_link_update(psoc); +} + +static QDF_STATUS +policy_mgr_handle_ml_sta_link_enable_on_sta_down(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return QDF_STATUS_E_INVAL; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + /* Handle only when non-ML STA is going down and ML STA is active */ + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, &num_non_ml, + NULL, NULL); + policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_non_ml: %d", + vdev_id, num_ml_sta, num_disabled_ml_sta, num_non_ml); + + /* + * No ML STA is present or sinle link ML is present or + * more no.of links are active than supported concurrent connections + */ + if (num_ml_sta < 2 || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) + return QDF_STATUS_E_INVAL; + + /* STA+STA cases */ + + /* One ML/non-ML STA is going down and another non ML STA is present */ + if (num_non_ml) { + policy_mgr_debug("non-ML STA is present"); + return QDF_STATUS_SUCCESS; + } + + /* + * If no links are disabled or + * link can not be allowed to enable then skip checking further. + */ + if (!num_disabled_ml_sta || + !policy_mgr_sta_ml_link_enable_allowed(psoc, num_disabled_ml_sta, + num_ml_sta, ml_freq_lst, + ml_sta_vdev_lst)) { + if (num_disabled_ml_sta) + policy_mgr_debug("Not re-enabled due to disallowed concurrency"); + goto done; + } + + policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + num_ml_sta, ml_sta_vdev_lst); + +done: + return QDF_STATUS_SUCCESS; +} + +/* + * policy_mgr_re_enable_ml_sta_on_p2p_sap_sta_down() - Handle enable + * link on P2P/SAP/ML_STA vdev down + * @psoc: objmgr psoc + * @vdev: vdev which went down + * + * Return: void + */ +static void +policy_mgr_re_enable_ml_sta_on_p2p_sap_sta_down(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t num_ml_sta = 0, num_p2p_sap = 0, num_disabled_ml_sta = 0; + uint8_t num_affected_link = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t p2p_sap_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t p2p_sap_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status; + + status = policy_mgr_handle_ml_sta_link_state_allowed( + psoc, MLO_LINK_FORCE_REASON_DISCONNECT); + if (QDF_IS_STATUS_ERROR(status)) + return; + + status = policy_mgr_handle_ml_sta_link_enable_on_sta_down(psoc, vdev); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + policy_mgr_get_ml_sta_and_p2p_cli_go_sap_info(pm_ctx, &num_ml_sta, + &num_disabled_ml_sta, + ml_sta_vdev_lst, + ml_freq_lst, &num_p2p_sap, + p2p_sap_vdev_lst, + p2p_sap_freq_lst); + + policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_p2p_sap %d", + vdev_id, num_ml_sta, num_disabled_ml_sta, num_p2p_sap); + + if (num_ml_sta < 2 || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_p2p_sap > MAX_NUMBER_OF_CONC_CONNECTIONS) + return; + + /* If link can not be allowed to enable then skip checking further. */ + if (!policy_mgr_sta_ml_link_enable_allowed(psoc, num_disabled_ml_sta, + num_ml_sta, ml_freq_lst, + ml_sta_vdev_lst)) + return; + + /* + * If num_p2p_sap is non zero, ie p2p or sap still present check if + * disable link is still required, if not enable the link. + * + * If num_p2p_sap is 0, ie only ml sta is present, enable the link. + */ + if (num_p2p_sap) + num_affected_link = + policy_mgr_get_affected_links_for_go_sap_cli(psoc, + num_ml_sta, ml_sta_vdev_lst, + ml_freq_lst, num_p2p_sap, + p2p_sap_vdev_lst, + p2p_sap_freq_lst); + + if (num_affected_link) + policy_mgr_debug("vdev %d: Affected link present, dont reanabe ML link", + vdev_id); + else + policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + num_ml_sta, ml_sta_vdev_lst); +} + +void policy_mgr_handle_ml_sta_links_on_vdev_down(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d: invalid vdev", vdev_id); + return; + } + + if (mode == QDF_STA_MODE || mode == QDF_SAP_MODE || + mode == QDF_P2P_CLIENT_MODE || mode == QDF_P2P_GO_MODE) + policy_mgr_re_enable_ml_sta_on_p2p_sap_sta_down(psoc, vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); +} + +/** + * policy_mgr_pick_link_vdev_from_inactive_list() - Get inactive vdev + * which can be activated + * @psoc: PSOC object information + * @vdev: vdev object + * @inactive_vdev_num: inactive vdev num in list + * @inactive_vdev_lst: inactive vdev list + * @inactive_freq_lst: inactive vdev frequency list + * @picked_vdev_id: Picked vdev id + * @non_removed_vdev_id: not removed inactive vdev id + * + * If one link is removed and inactivated, pick one of existing inactive + * vdev which can be activated by checking concurrency API. + * + * Return: void + */ +static void +policy_mgr_pick_link_vdev_from_inactive_list( + struct wlan_objmgr_psoc *psoc, struct wlan_objmgr_vdev *vdev, + uint8_t inactive_vdev_num, uint8_t *inactive_vdev_lst, + qdf_freq_t *inactive_freq_lst, uint8_t *picked_vdev_id, + uint8_t *non_removed_vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + uint8_t num_del = 0; + union conc_ext_flag conc_ext_flags = {0}; + uint8_t i; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_store_and_del_conn_info_by_vdev_id( + psoc, wlan_vdev_get_id(vdev), + info, &num_del); + /* pick one inactive parnter link and make it active */ + for (i = 0; i < inactive_vdev_num; i++) { + struct wlan_objmgr_vdev *partner_vdev; + + if (wlan_get_vdev_link_removed_flag_by_vdev_id( + psoc, inactive_vdev_lst[i])) { + policy_mgr_debug("skip removed link vdev %d", + inactive_vdev_lst[i]); + continue; + } + + partner_vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + inactive_vdev_lst[i], + WLAN_POLICY_MGR_ID); + if (!partner_vdev) { + policy_mgr_err("invalid partner_vdev %d ", + inactive_vdev_lst[i]); + continue; + } + *non_removed_vdev_id = inactive_vdev_lst[i]; + + conc_ext_flags.value = + policy_mgr_get_conc_ext_flags(partner_vdev, false); + + if (policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE, + inactive_freq_lst[i], + HW_MODE_20_MHZ, + conc_ext_flags.value, + NULL)) { + *picked_vdev_id = inactive_vdev_lst[i]; + wlan_objmgr_vdev_release_ref(partner_vdev, + WLAN_POLICY_MGR_ID); + break; + } + wlan_objmgr_vdev_release_ref(partner_vdev, WLAN_POLICY_MGR_ID); + } + /* Restore the connection info */ + policy_mgr_restore_deleted_conn_info(psoc, info, num_del); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +} + +QDF_STATUS +policy_mgr_handle_link_removal_on_standby(struct wlan_objmgr_vdev *vdev, + struct ml_rv_info *reconfig_info) +{ + struct mlo_link_info *link_info; + uint8_t i, link_id; + uint32_t removal_link_bitmap = 0; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + + if (!vdev || !vdev->mlo_dev_ctx) { + policy_mgr_err("invalid vdev or mlo_dev_ctx"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + policy_mgr_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < reconfig_info->num_links; i++) { + if (!(reconfig_info->link_info[i].is_ap_removal_timer_p && + reconfig_info->link_info[i].ap_removal_timer)) + continue; + + link_id = reconfig_info->link_info[i].link_id; + link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, + link_id); + if (!link_info) { + policy_mgr_err("link info null, id %d", link_id); + return QDF_STATUS_E_NULL_VALUE; + } + policy_mgr_debug("AP removal tbtt %d vdev %d link %d flag 0x%x STA MAC " QDF_MAC_ADDR_FMT " BSSID " QDF_MAC_ADDR_FMT, + reconfig_info->link_info[i].ap_removal_timer, + link_info->vdev_id, link_id, + (uint32_t)link_info->link_status_flags, + QDF_MAC_ADDR_REF(link_info->link_addr.bytes), + QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); + + if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) + continue; + + if (link_info->vdev_id != WLAN_INVALID_VDEV_ID) + continue; + + if (qdf_atomic_test_and_set_bit(LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags)) + continue; + + removal_link_bitmap |= 1 << link_id; + } + if (!removal_link_bitmap) + return QDF_STATUS_SUCCESS; + + status = policy_mgr_mlo_sta_set_nlink( + psoc, wlan_vdev_get_id(vdev), + MLO_LINK_FORCE_REASON_LINK_REMOVAL, + MLO_LINK_FORCE_MODE_INACTIVE, + 0, + removal_link_bitmap, + 0, + 0); + if (status == QDF_STATUS_E_PENDING) + status = QDF_STATUS_SUCCESS; + else + policy_mgr_err("status %d", status); + + return status; +} + +void policy_mgr_handle_link_removal_on_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i; + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0; + uint8_t num_active_ml_sta; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + uint8_t non_removal_link_vdev_id = WLAN_INVALID_VDEV_ID; + uint8_t picked_vdev_id = WLAN_INVALID_VDEV_ID; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + policy_mgr_err("Failed to get psoc"); + return; + } + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + if (wlan_get_vdev_link_removed_flag_by_vdev_id(psoc, vdev_id)) { + policy_mgr_debug("removal link vdev %d is removed already", + vdev_id); + return; + } + + wlan_connectivity_mlo_reconfig_event(vdev); + + /* mark link removed for vdev */ + wlan_set_vdev_link_removed_flag_by_vdev_id(psoc, vdev_id, + true); + status = policy_mgr_handle_ml_sta_link_state_allowed( + psoc, MLO_LINK_FORCE_REASON_LINK_REMOVAL); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_set_vdev_link_removed_flag_by_vdev_id(psoc, vdev_id, + false); + return; + } + + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, + NULL, NULL, NULL); + if (!num_ml_sta) { + policy_mgr_debug("unexpected event, no ml sta"); + return; + } + if (num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_disabled_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_ml_sta <= num_disabled_ml_sta) { + policy_mgr_debug("unexpected ml sta num %d %d", + num_ml_sta, num_disabled_ml_sta); + return; + } + /* Single link FW should handle BTM/disassoc and do roaming. + * Host will not send inactive command to FW. + */ + if (num_ml_sta < 2) { + policy_mgr_debug("no op for single link mlo, num_ml_sta %d", + num_ml_sta); + return; + } + + policy_mgr_debug("removal link vdev %d num_ml_sta %d num_disabled_ml_sta %d", + vdev_id, num_ml_sta, num_disabled_ml_sta); + + num_active_ml_sta = num_ml_sta; + if (num_ml_sta >= num_disabled_ml_sta) + num_active_ml_sta = num_ml_sta - num_disabled_ml_sta; + + for (i = 0; i < num_active_ml_sta; i++) + if (ml_sta_vdev_lst[i] == vdev_id) + break; + + if (i == num_active_ml_sta) { + /* no found in active ml list, it must be in inactive list */ + policy_mgr_debug("removal link vdev %d is inactive already", + vdev_id); + + /* send inactive command to fw again with "link removal + * reason" + */ + policy_mgr_mlo_sta_set_link( + psoc, MLO_LINK_FORCE_REASON_LINK_REMOVAL, + MLO_LINK_FORCE_MODE_INACTIVE, + 1, &vdev_id); + return; + } + + /* pick one inactive parnter link and make it active */ + if (num_active_ml_sta < num_ml_sta) + policy_mgr_pick_link_vdev_from_inactive_list( + psoc, vdev, num_disabled_ml_sta, + &ml_sta_vdev_lst[num_active_ml_sta], + &ml_freq_lst[num_active_ml_sta], + &picked_vdev_id, + &non_removal_link_vdev_id); + if (picked_vdev_id != WLAN_INVALID_VDEV_ID) { + /* find one inactive link can be active, send it to fw with + * the removed link together. + */ + policy_mgr_debug("active parnter vdev %d, inactive removal vdev %d", + picked_vdev_id, vdev_id); + policy_mgr_mlo_sta_set_link_ext( + psoc, MLO_LINK_FORCE_REASON_LINK_REMOVAL, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + 1, &picked_vdev_id, + 1, &vdev_id); + return; + } + if (num_active_ml_sta < 2) { + /* For multi-link MLO, one link is removed and + * no find one inactive link can be active: + * 1. If at least one left link is not link removed state, + * host will trigger roaming. + * 2. If all left links are link removed state, + * FW will trigger roaming based on BTM or disassoc frame + */ + if (non_removal_link_vdev_id != WLAN_INVALID_VDEV_ID) { + policy_mgr_debug("trigger roaming, non_removal_link_vdev_id %d", + non_removal_link_vdev_id); + policy_mgr_trigger_roam_on_link_removal(vdev); + } + return; + } + /* If active link number >= 2 and one link is removed, then at least + * one link is still active, just send inactived command to fw. + */ + policy_mgr_mlo_sta_set_link(psoc, MLO_LINK_FORCE_REASON_LINK_REMOVAL, + MLO_LINK_FORCE_MODE_INACTIVE, + 1, &vdev_id); +} + +/** + * policy_mgr_is_restart_sap_required_with_mlo_sta() - Check SAP required to + * restart for force SCC with MLO STA + * @psoc: PSOC object information + * @sap_vdev_id: sap vdev id + * @sap_ch_freq: sap channel frequency + * + * For MLO STA+SAP case, mlo link maybe in inactive state after connected + * and the hw mode maybe not updated, check MCC/SCC by + * policy_mgr_are_2_freq_on_same_mac may not match MCC/SCC state + * after the link is activated by target later. So to check frequency match + * or not to decide SAP do force SCC or not if MLO STA 2 links are present. + * + * Return: true if SAP is required to force SCC with MLO STA + */ +static bool +policy_mgr_is_restart_sap_required_with_mlo_sta(struct wlan_objmgr_psoc *psoc, + uint8_t sap_vdev_id, + qdf_freq_t sap_ch_freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i; + bool same_freq_with_mlo_sta = false; + bool restart_required = false; + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_ml_active_sta = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, + NULL, NULL, NULL); + if (num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) { + policy_mgr_debug("unexpected num_ml_sta %d ", num_ml_sta); + return false; + } + + num_ml_active_sta = num_ml_sta; + if (num_ml_sta >= num_disabled_ml_sta) + num_ml_active_sta = num_ml_sta - num_disabled_ml_sta; + for (i = 0; i < num_ml_active_sta; i++) { + if (ml_freq_lst[i] == sap_ch_freq) { + same_freq_with_mlo_sta = true; + break; + } + } + + if (num_ml_active_sta >= 2 && !same_freq_with_mlo_sta) { + policy_mgr_debug("SAP is not SCC with any of active MLO STA link, restart SAP"); + restart_required = true; + } + + return restart_required; +} + +/** + * policy_mgr_is_new_force_allowed() - Check if the new force command is allowed + * @psoc: PSOC object information + * @vdev: ml sta vdev object + * @active_link_bitmap: Active link bitmap from user request + * + * If ML STA associates in 3-link (2.4 GHz + 5 GHz + 6 GHz), Host sends force + * inactive num command between 5 GHz and 6 GHz links to firmware as it's a DBS + * RD. This force has to be in effect at all times but any new force active num + * command request from the userspace (except for 5 GHz + 6 GHz links) should be + * honored. This API checks if the new force command can be allowed. + * + * Return: True if the new force command is allowed, else False + */ +static bool +policy_mgr_is_new_force_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t active_link_bitmap) +{ + uint32_t link_bitmap = 0; + uint8_t link_num = 0; + struct set_link_req conc_link_req; + + qdf_mem_zero(&conc_link_req, sizeof(conc_link_req)); + ml_nlink_get_force_link_request(psoc, vdev, &conc_link_req, + SET_LINK_FROM_CONCURRENCY); + /* If force inactive num is present due to MCC link(DBS RD) or + * concurrency with legacy intf, don't allow force active if + * left inactive link number doesn't meet concurrency + * requirement. + */ + if (conc_link_req.force_inactive_num_bitmap || + conc_link_req.force_inactive_num) { + link_bitmap = ~active_link_bitmap & + conc_link_req.force_inactive_num_bitmap; + if (!link_bitmap) { + policy_mgr_err("New force bitmap 0x%x not allowed due to force_inactive_num_bitmap 0x%x", + active_link_bitmap, + conc_link_req. + force_inactive_num_bitmap); + return false; + } + link_num = convert_link_bitmap_to_link_ids(link_bitmap, + 0, NULL); + if (link_num < conc_link_req.force_inactive_num) { + policy_mgr_debug("force inact num exists with %d don't allow act bitmap 0x%x", + conc_link_req.force_active_num, + active_link_bitmap); + return false; + } + } + /* If force inactive bitmap is present due to link removal or + * concurrency with legacy intf, don't allow force active if + * it is conflict with existing concurrency requirement. + */ + if (conc_link_req.force_inactive_bitmap) { + link_bitmap = active_link_bitmap & + conc_link_req.force_inactive_bitmap; + if (link_bitmap) { + policy_mgr_err("New force act bitmap 0x%x not allowed due to conc force inact bitmap 0x%x", + active_link_bitmap, + conc_link_req.force_inactive_bitmap); + return false; + } + } + + return true; +} + +void policy_mgr_activate_mlo_links_nlink(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, uint8_t num_links, + struct qdf_mac_addr active_link_addr[2]) +{ + uint8_t *link_mac_addr; + uint32_t link_ctrl_flags; + enum mlo_link_force_reason reason; + enum mlo_link_force_mode mode; + struct wlan_objmgr_vdev *vdev; + struct mlo_link_info *link_info; + bool active_link_present = false; + uint8_t iter, link, active_link_cnt = 0, inactive_link_cnt = 0; + uint32_t active_link_bitmap = 0; + uint32_t inactive_link_bitmap = 0; + struct ml_link_force_state curr = {0}; + bool update_inactive_link = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev_id: %d vdev not found", session_id); + return; + } + + if (!wlan_cm_is_vdev_connected(vdev)) { + policy_mgr_err("vdev is not in connected state"); + goto done; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + policy_mgr_err("vdev is not mlo vdev"); + goto done; + } + + policy_mgr_debug("Num active links: %d", num_links); + link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; + for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) { + if (link_info->link_id == WLAN_INVALID_LINK_ID) { + link_info++; + continue; + } + + link_mac_addr = &link_info->link_addr.bytes[0]; + policy_mgr_debug("link addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(link_mac_addr)); + + for (link = 0; link < num_links; link++) { + policy_mgr_debug("active addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(&active_link_addr[link].bytes[0])); + if (!qdf_mem_cmp(link_mac_addr, + &active_link_addr[link].bytes[0], + QDF_MAC_ADDR_SIZE)) { + active_link_bitmap |= 1 << link_info->link_id; + active_link_cnt++; + active_link_present = true; + policy_mgr_debug("Link address match"); + } + } + if (!active_link_present) { + inactive_link_bitmap |= 1 << link_info->link_id; + inactive_link_cnt++; + policy_mgr_err("No link address match"); + } + active_link_present = false; + link_info++; + } + + policy_mgr_debug("active link cnt: %d, inactive link cnt: %d", + active_link_cnt, inactive_link_cnt); + + if (!active_link_cnt) { + goto done; + } else if (policy_mgr_is_emlsr_sta_concurrency_present(psoc)) { + policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode"); + goto done; + } else { + if (!policy_mgr_is_new_force_allowed( + psoc, vdev, active_link_bitmap)) + goto done; + + /* If current force inactive bitmap exists, we have to remove + * the new active bitmap from the existing inactive bitmap, + * e.g. a link id can't be present in active bitmap and + * inactive bitmap at same time, so update inactive bitmap + * as well. + */ + ml_nlink_get_curr_force_state(psoc, vdev, &curr); + if (curr.force_inactive_bitmap && !inactive_link_cnt) { + inactive_link_bitmap = curr.force_inactive_bitmap & + ~active_link_bitmap; + update_inactive_link = true; + } + } + + /* + * If there are both active and inactive vdev count, then issue a + * single WMI with force mode MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + * else if there is only active vdev count, send single WMI for + * all active vdevs with force mode MLO_LINK_FORCE_MODE_ACTIVE. + */ + if (inactive_link_cnt || update_inactive_link) { + reason = MLO_LINK_FORCE_REASON_CONNECT; + mode = MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE; + link_ctrl_flags = link_ctrl_f_overwrite_active_bitmap | + link_ctrl_f_overwrite_inactive_bitmap; + } else { + reason = MLO_LINK_FORCE_REASON_DISCONNECT; + mode = MLO_LINK_FORCE_MODE_ACTIVE; + link_ctrl_flags = link_ctrl_f_overwrite_active_bitmap; + } + + policy_mgr_mlo_sta_set_nlink(psoc, wlan_vdev_get_id(vdev), + reason, mode, 0, + active_link_bitmap, inactive_link_bitmap, + link_ctrl_flags); + if (active_link_bitmap) + ml_nlink_vendor_command_set_link( + psoc, session_id, + LINK_CONTROL_MODE_USER, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + 0, active_link_bitmap, + inactive_link_bitmap); + +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); +} + +void policy_mgr_activate_mlo_links(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, uint8_t num_links, + struct qdf_mac_addr *active_link_addr) +{ + uint8_t idx, link, active_vdev_cnt = 0, inactive_vdev_cnt = 0; + uint16_t ml_vdev_cnt = 0; + struct wlan_objmgr_vdev *tmp_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + uint8_t active_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + uint8_t inactive_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + struct wlan_objmgr_vdev *vdev; + uint8_t *link_mac_addr; + bool active_vdev_present = false; + uint16_t active_link_bitmap = 0; + uint16_t inactive_link_bitmap = 0; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev_id: %d vdev not found", session_id); + return; + } + + if (!wlan_cm_is_vdev_connected(vdev)) { + policy_mgr_err("vdev is not in connected state"); + goto done; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + policy_mgr_err("vdev is not mlo vdev"); + goto done; + } + + mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, tmp_vdev_lst); + policy_mgr_debug("Num active links: %d, ML vdev cnt: %d", num_links, + ml_vdev_cnt); + for (idx = 0; idx < ml_vdev_cnt; idx++) { + link_mac_addr = wlan_vdev_mlme_get_macaddr(tmp_vdev_lst[idx]); + policy_mgr_debug("link addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(link_mac_addr)); + for (link = 0; link < num_links; link++) { + policy_mgr_debug("active addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(&active_link_addr[link].bytes[0])); + if (!qdf_mem_cmp(link_mac_addr, + &active_link_addr[link].bytes[0], + QDF_MAC_ADDR_SIZE)) { + active_vdev_lst[active_vdev_cnt] = + wlan_vdev_get_id(tmp_vdev_lst[idx]); + active_link_bitmap |= + 1 << wlan_vdev_get_link_id(tmp_vdev_lst[idx]); + active_vdev_cnt++; + active_vdev_present = true; + policy_mgr_debug("Link address match"); + } + } + if (!active_vdev_present) { + inactive_vdev_lst[inactive_vdev_cnt] = + wlan_vdev_get_id(tmp_vdev_lst[idx]); + inactive_link_bitmap |= + 1 << wlan_vdev_get_link_id(tmp_vdev_lst[idx]); + + inactive_vdev_cnt++; + policy_mgr_err("No link address match"); + } + active_vdev_present = false; + } + + policy_mgr_debug("active vdev cnt: %d, inactive vdev cnt: %d", + active_vdev_cnt, inactive_vdev_cnt); + + if (active_vdev_cnt && + policy_mgr_is_emlsr_sta_concurrency_present(psoc)) { + policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode"); + goto ref_release; + } + + /* + * If there are both active and inactive vdev count, then issue a + * single WMI with force mode MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + * else if there is only active vdev count, send single WMI for + * all active vdevs with force mode MLO_LINK_FORCE_MODE_ACTIVE. + */ + if (active_vdev_cnt && inactive_vdev_cnt) + policy_mgr_mlo_sta_set_link_ext( + psoc, MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + active_vdev_cnt, active_vdev_lst, + inactive_vdev_cnt, inactive_vdev_lst); + else if (active_vdev_cnt && !inactive_vdev_cnt) + policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_ACTIVE, + active_vdev_cnt, active_vdev_lst); + if (active_link_bitmap) + ml_nlink_vendor_command_set_link( + psoc, session_id, + LINK_CONTROL_MODE_USER, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + 0, active_link_bitmap, + inactive_link_bitmap); + +ref_release: + for (idx = 0; idx < ml_vdev_cnt; idx++) + mlo_release_vdev_ref(tmp_vdev_lst[idx]); +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); +} + +QDF_STATUS +policy_mgr_update_mlo_links_based_on_linkid(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t num_links, + uint8_t *link_id_list, + uint32_t *config_state_list) +{ + uint8_t idx, link, active_vdev_cnt = 0, inactive_vdev_cnt = 0; + uint16_t ml_vdev_cnt = 0; + struct wlan_objmgr_vdev *vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + uint8_t active_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + uint8_t inactive_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + struct wlan_objmgr_vdev *vdev; + uint8_t link_id, num_links_to_disable = 0, num_matched_linkid = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t active_link_bitmap = 0; + uint32_t inactive_link_bitmap = 0; + bool update_vendor_cmd = false; + + for (idx = 0; idx < num_links; idx++) { + if (config_state_list[idx] == 0) + num_links_to_disable++; + } + + if (num_links_to_disable == num_links) { + policy_mgr_debug("vdev: %d num_links_to_disable: %d", vdev_id, + num_links_to_disable); + return QDF_STATUS_E_FAILURE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev: %d vdev not found", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (!wlan_cm_is_vdev_connected(vdev)) { + policy_mgr_err("vdev: %d is not in connected state", vdev_id); + goto release_vdev_ref; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + policy_mgr_err("vdev:%d is not mlo vdev", vdev_id); + goto release_vdev_ref; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + goto release_vdev_ref; + } + + mlo_get_ml_vdev_list(vdev, &ml_vdev_cnt, vdev_lst); + for (idx = 0; idx < ml_vdev_cnt; idx++) { + link_id = wlan_vdev_get_link_id(vdev_lst[idx]); + for (link = 0; link < num_links; link++) { + if (link_id_list[link] == link_id) { + num_matched_linkid++; + policy_mgr_debug("link id:%d match", link_id); + if (config_state_list[link]) { + active_vdev_lst[active_vdev_cnt] = + wlan_vdev_get_id(vdev_lst[idx]); + active_link_bitmap |= 1 << link_id; + active_vdev_cnt++; + } else { + inactive_vdev_lst[inactive_vdev_cnt] = + wlan_vdev_get_id(vdev_lst[idx]); + inactive_link_bitmap |= 1 << link_id; + inactive_vdev_cnt++; + } + } + } + } + + policy_mgr_debug("vdev: %d, active links: %d, ml count: %d, active count: %d, inactive count: %d", + vdev_id, num_links, ml_vdev_cnt, active_vdev_cnt, + inactive_vdev_cnt); + + if (num_links != num_matched_linkid) { + policy_mgr_debug("invalid link id(s), num_matched_linkid: %d", + num_matched_linkid); + goto release_ml_vdev_ref; + } + + if (active_vdev_cnt && + policy_mgr_is_emlsr_sta_concurrency_present(psoc)) { + policy_mgr_debug("vdev: %d emlsr sta conn present", vdev_id); + if (active_vdev_cnt == 1) + status = QDF_STATUS_SUCCESS; + goto release_ml_vdev_ref; + } + + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, &num_non_ml, + NULL, NULL); + policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_non_ml: %d", + vdev_id, num_ml_sta, num_disabled_ml_sta, num_non_ml); + + /* + * No ML STA is present or sinle link ML is present or + * more no.of links are active than supported concurrent connections + */ + if (!num_ml_sta || num_ml_sta < 2 || + num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) + goto release_ml_vdev_ref; + + if (!num_disabled_ml_sta) { + /* + * both link are already enabled and received set link req to + * enable both again + */ + if (active_vdev_cnt && !inactive_vdev_cnt) { + status = QDF_STATUS_SUCCESS; + goto release_ml_vdev_ref; + } + + /* + * both link are already enabled and received set link req + * disable one link, disable any + */ + if (active_vdev_cnt && inactive_vdev_cnt) { + status = policy_mgr_mlo_sta_set_link_ext(psoc, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + active_vdev_cnt, active_vdev_lst, + inactive_vdev_cnt, inactive_vdev_lst); + if (status == QDF_STATUS_E_PENDING || + status == QDF_STATUS_SUCCESS) + update_vendor_cmd = true; + + goto release_ml_vdev_ref; + } + } else { + /* + * one link is enable and one link is disabled, If disabled + * link can not be allowed to enable then send status failure + * to upper layer. + */ + if (active_vdev_cnt && + !policy_mgr_sta_ml_link_enable_allowed(psoc, + num_disabled_ml_sta, + num_ml_sta, + ml_freq_lst, + ml_sta_vdev_lst)) { + policy_mgr_debug("vdev %d: link enable not allowed", + vdev_id); + goto release_ml_vdev_ref; + } + + /* + * If there are both active and inactive vdev count, then + * issue a single WMI with force mode + * MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, else if there is only + * active vdev count, send single WMI for all active vdevs + * with force mode MLO_LINK_FORCE_MODE_ACTIVE. + */ + if (active_vdev_cnt && inactive_vdev_cnt) { + status = policy_mgr_mlo_sta_set_link_ext(psoc, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + active_vdev_cnt, active_vdev_lst, + inactive_vdev_cnt, inactive_vdev_lst); + if (status == QDF_STATUS_E_PENDING || + status == QDF_STATUS_SUCCESS) + update_vendor_cmd = true; + } else if (active_vdev_cnt && !inactive_vdev_cnt) { + status = policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_DISCONNECT, + MLO_LINK_FORCE_MODE_ACTIVE, + active_vdev_cnt, active_vdev_lst); + if (status == QDF_STATUS_E_PENDING || + status == QDF_STATUS_SUCCESS) + update_vendor_cmd = true; + } + } + if (update_vendor_cmd) + ml_nlink_vendor_command_set_link( + psoc, vdev_id, + LINK_CONTROL_MODE_USER, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE, + 0, active_link_bitmap, + inactive_link_bitmap); + +release_ml_vdev_ref: + for (idx = 0; idx < ml_vdev_cnt; idx++) + mlo_release_vdev_ref(vdev_lst[idx]); +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + return status; +} + +/** + * policy_mgr_process_mlo_sta_dynamic_force_num_link() - Set links for MLO STA + * @psoc: psoc object + * @reason: Reason for which link is forced + * @mode: Force reason + * @num_mlo_vdev: number of mlo vdev + * @mlo_vdev_lst: MLO STA vdev list + * @force_active_cnt: number of MLO links to operate in active state as per + * user req + * + * User space provides the desired number of MLO links to operate in active + * state at any given time. Host validate request as per current concurrency + * and send SET LINK requests to FW. FW will choose which MLO links should + * operate in the active state. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_process_mlo_sta_dynamic_force_num_link(struct wlan_objmgr_psoc *psoc, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t num_mlo_vdev, uint8_t *mlo_vdev_lst, + uint8_t force_active_cnt) +{ + struct mlo_link_set_active_req *req; + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + + if (!num_mlo_vdev) { + policy_mgr_err("invalid 0 num_mlo_vdev"); + return QDF_STATUS_E_INVAL; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_INVAL; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, mlo_vdev_lst[0], + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d: invalid vdev", mlo_vdev_lst[0]); + qdf_mem_free(req); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_debug("vdev %d: mode %d num_mlo_vdev %d reason %d", + wlan_vdev_get_id(vdev), mode, num_mlo_vdev, reason); + + /* + * TODO: this API has to be merged with policy_mgr_mlo_sta_set_link_ext + * as part of 3 link FR change as in caller only we have to decide how + * many links to disable/enable for MLO_LINK_FORCE_MODE_ACTIVE_NUM or + * MLO_LINK_FORCE_MODE_INACTIVE_NUM scenario + */ + req->ctx.vdev = vdev; + req->param.reason = reason; + req->param.force_mode = mode; + req->ctx.set_mlo_link_cb = policy_mgr_handle_link_enable_disable_resp; + req->ctx.validate_set_mlo_link_cb = + policy_mgr_validate_set_mlo_link_cb; + req->ctx.cb_arg = req; + + /* set MLO vdev bit mask */ + policy_mgr_fill_ml_active_link_vdev_bitmap(req, mlo_vdev_lst, + num_mlo_vdev); + + pm_ctx->active_vdev_bitmap = req->param.vdev_bitmap[0]; + pm_ctx->inactive_vdev_bitmap = req->param.vdev_bitmap[1]; + + req->param.num_link_entry = 1; + req->param.link_num[0].num_of_link = force_active_cnt; + req->param.control_flags.dynamic_force_link_num = 1; + + if (ml_is_nlink_service_supported(psoc)) { + status = + policy_mgr_mlo_sta_set_link_by_linkid(psoc, vdev, reason, + mode, + req->param.link_num[0]. + num_of_link, + num_mlo_vdev, + mlo_vdev_lst, + 0, + NULL); + qdf_mem_free(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + if (status != QDF_STATUS_E_PENDING) { + policy_mgr_err("set_link_by_linkid status %d", status); + return status; + } + return QDF_STATUS_SUCCESS; + } + + policy_mgr_set_link_in_progress(pm_ctx, true); + + status = mlo_ser_set_link_req(req); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("vdev %d: Failed to set link mode %d num_mlo_vdev %d force_active_cnt: %d, reason %d", + wlan_vdev_get_id(vdev), mode, num_mlo_vdev, + force_active_cnt, + reason); + qdf_mem_free(req); + policy_mgr_set_link_in_progress(pm_ctx, false); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return status; +} + +QDF_STATUS policy_mgr_update_active_mlo_num_links(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t force_active_cnt) +{ + struct wlan_objmgr_vdev *vdev, *tmp_vdev; + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0; + uint8_t num_enabled_ml_sta = 0, conn_count; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t link_bitmap = 0; + uint8_t i; + + if (policy_mgr_is_emlsr_sta_concurrency_present(psoc)) { + policy_mgr_debug("Concurrency exists, cannot enter EMLSR mode"); + return QDF_STATUS_E_FAILURE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev_id: %d vdev not found", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + goto release_vdev_ref; + + if (!wlan_cm_is_vdev_connected(vdev)) { + policy_mgr_err("vdev is not in connected state"); + goto release_vdev_ref; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + policy_mgr_err("vdev is not mlo vdev"); + goto release_vdev_ref; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + goto release_vdev_ref; + } + + conn_count = policy_mgr_get_connection_count(psoc); + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, &num_non_ml, + NULL, NULL); + policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_non_ml: %d conn cout %d", + vdev_id, num_ml_sta, num_disabled_ml_sta, num_non_ml, + conn_count); + + /* + * No ML STA is present or more no.of links are active than supported + * concurrent connections + */ + if (!num_ml_sta || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) + goto release_vdev_ref; + + /* + * DUT connected with MLO AP, one link is always active, So if + * request comes to make one link is active, host sends set link command + * with mode MLO_LINK_FORCE_MODE_ACTIVE_NUM, so that FW should restrict + * to only one link and avoid switch from MLSR to MLMR. + */ + if (force_active_cnt == 1) + goto set_link; + + /* + * num_disabled_ml_sta == 0, means 2 link is already active, + * In this case send set link command with num link 2 and mode + * MLO_LINK_FORCE_MODE_ACTIVE_NUM, so that FW should restrict to only + * in MLMR mode (2 link should be active). + * If current enabled links are < 2, and there are concurrent + * connection present, force active 2 links, which may be + * conflict with concurrent rules, reject it. + * If the two enabled links are MCC, don't not force active 2 links. + */ + num_enabled_ml_sta = num_ml_sta; + if (num_ml_sta >= num_disabled_ml_sta) + num_enabled_ml_sta = num_ml_sta - num_disabled_ml_sta; + + if (force_active_cnt >= 2) { + if (num_ml_sta < 2) { + policy_mgr_debug("num_ml_sta %d < 2, can't force active cnt %d", + num_ml_sta, + force_active_cnt); + goto release_vdev_ref; + } + if (num_enabled_ml_sta < 2 && + conn_count > num_enabled_ml_sta) { + policy_mgr_debug("enabled link num %d < 2, concurrent conn present %d", + num_enabled_ml_sta, + conn_count); + goto release_vdev_ref; + } + if (policy_mgr_is_ml_sta_links_in_mcc( + psoc, ml_freq_lst, + ml_sta_vdev_lst, + NULL, num_ml_sta, + NULL)) { + policy_mgr_debug("enabled links are mcc, concurrency disallow"); + goto release_vdev_ref; + } + } + if (force_active_cnt == 2 && num_disabled_ml_sta == 0) + goto set_link; + + /* Link can not be allowed to enable then skip checking further */ + if (!policy_mgr_sta_ml_link_enable_allowed(psoc, num_disabled_ml_sta, + num_ml_sta, ml_freq_lst, + ml_sta_vdev_lst)) { + policy_mgr_debug("vdev %d: link enable not allowed", vdev_id); + goto release_vdev_ref; + } + +set_link: + /* + * TODO: In all scenarios wherever host sends + * MLO_LINK_FORCE_MODE_ACTIVE_NUM/MLO_LINK_FORCE_MODE_INACTIVE_NUM to + * FW, Host need to send MLO_LINK_FORCE_MODE_NO_FORCE to FW. + * So instead of two commands for serialization, take care of this in + * single serialization active command. + */ + + /* + * send MLO_LINK_FORCE_MODE_NO_FORCE to FW to clear user mode setting + * configured via QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE in FW + */ + status = policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + num_ml_sta, ml_sta_vdev_lst); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_debug("fail to send no force cmd for num_links:%d", + num_ml_sta); + goto release_vdev_ref; + } else { + policy_mgr_debug("clear force mode setting for num_links:%d", + num_ml_sta); + } + + status = policy_mgr_process_mlo_sta_dynamic_force_num_link(psoc, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_NUM, + num_ml_sta, ml_sta_vdev_lst, + force_active_cnt); + if (QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_debug("vdev %d: link enable allowed", vdev_id); + for (i = 0; i < num_ml_sta; i++) { + if (i >= force_active_cnt) + break; + tmp_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, ml_sta_vdev_lst[i], + WLAN_POLICY_MGR_ID); + if (!tmp_vdev) { + policy_mgr_err("vdev not found for vdev_id %d ", + ml_sta_vdev_lst[i]); + continue; + } + + link_bitmap |= 1 << wlan_vdev_get_link_id(tmp_vdev); + wlan_objmgr_vdev_release_ref(tmp_vdev, + WLAN_POLICY_MGR_ID); + } + ml_nlink_vendor_command_set_link( + psoc, vdev_id, + LINK_CONTROL_MODE_MIXED, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_NUM, + force_active_cnt, + link_bitmap, + 0); + } + +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return status; +} + +QDF_STATUS +policy_mgr_clear_ml_links_settings_in_fw(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0, num_non_ml = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t num_link_to_no_force = 0, num_active_ml_sta = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev: %d vdev not found", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + goto release_vdev_ref; + + if (!wlan_cm_is_vdev_connected(vdev)) { + policy_mgr_err("vdev: %d is not in connected state", vdev_id); + goto release_vdev_ref; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + policy_mgr_err("vdev: %d is not mlo vdev", vdev_id); + goto release_vdev_ref; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("vdev: %d Invalid Context", vdev_id); + goto release_vdev_ref; + } + /* Clear all user vendor command setting for switching to "default" */ + ml_nlink_vendor_command_set_link(psoc, vdev_id, + LINK_CONTROL_MODE_DEFAULT, + 0, 0, 0, 0, 0); + + policy_mgr_get_ml_sta_info(pm_ctx, &num_ml_sta, &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, &num_non_ml, + NULL, NULL); + policy_mgr_debug("vdev %d: num_ml_sta %d disabled %d num_non_ml: %d", + vdev_id, num_ml_sta, num_disabled_ml_sta, num_non_ml); + + if (!num_ml_sta || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS || + num_disabled_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) + goto release_vdev_ref; + + num_active_ml_sta = num_ml_sta; + if (num_ml_sta >= num_disabled_ml_sta) + num_active_ml_sta = num_ml_sta - num_disabled_ml_sta; + + num_link_to_no_force += num_active_ml_sta; + + /* Link can not be allowed to enable then skip checking further */ + if (policy_mgr_sta_ml_link_enable_allowed(psoc, num_disabled_ml_sta, + num_ml_sta, ml_freq_lst, + ml_sta_vdev_lst)) { + num_link_to_no_force += num_disabled_ml_sta; + policy_mgr_debug("Link enable allowed, total num_links: %d", + num_link_to_no_force); + } + + if (num_link_to_no_force < 1 || + num_link_to_no_force > MAX_NUMBER_OF_CONC_CONNECTIONS) { + policy_mgr_debug("vdev %d: invalid num_link_to_no_force: %d", + vdev_id, num_link_to_no_force); + goto release_vdev_ref; + } + + /* + * send WMI_MLO_LINK_SET_ACTIVE_CMDID to clear user mode setting + * configured via QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE in FW + */ + status = policy_mgr_mlo_sta_set_link(psoc, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_NO_FORCE, + num_link_to_no_force, + ml_sta_vdev_lst); + if (QDF_IS_STATUS_ERROR(status)) + goto release_vdev_ref; + else + policy_mgr_debug("clear user mode setting for num_links:%d", + num_link_to_no_force); + + /* + * send WMI_MLO_LINK_SET_ACTIVE_CMDID with value of + * num_link as 0 to clear dynamic mode setting configured + * via vendor attr LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS in FW + */ + status = policy_mgr_process_mlo_sta_dynamic_force_num_link(psoc, + MLO_LINK_FORCE_REASON_CONNECT, + MLO_LINK_FORCE_MODE_ACTIVE_NUM, + num_link_to_no_force, ml_sta_vdev_lst, 0); + if (QDF_IS_STATUS_SUCCESS(status)) + policy_mgr_debug("clear mixed mode setting for num_links:%d", + num_link_to_no_force); +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return status; +} + +#else +static bool +policy_mgr_allow_sta_concurrency(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, + uint32_t ext_flags) +{ + uint32_t count; + + count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + if (!count) + return true; + + if (count >= 2) { + policy_mgr_rl_debug("Disallow 3rd STA"); + return false; + } + + if (!policy_mgr_allow_multiple_sta_connections(psoc)) { + policy_mgr_rl_debug("Multiple STA connections is not allowed"); + return false; + } + + return true; +} + +static bool +policy_mgr_is_restart_sap_required_with_mlo_sta(struct wlan_objmgr_psoc *psoc, + uint8_t sap_vdev_id, + qdf_freq_t sap_ch_freq) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_P2P_P2P_STA +bool policy_mgr_is_p2p_p2p_conc_supported(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_p2p_p2p_conc_support(psoc); +} +#endif + +/** + * policy_mgr_is_third_conn_sta_p2p_p2p_valid: This API checks the firmware + * capability and allows STA + P2P + P2P combination. It can be in SCC/MCC/DBS + * @psoc: psoc pointer + * @new_conn_mode: third connection mode + * + * Return: true if support else false + */ +static bool policy_mgr_is_third_conn_sta_p2p_p2p_valid( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode new_conn_mode) +{ + int num_sta, num_go, num_cli; + + num_sta = policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL); + + num_go = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, + NULL); + + num_cli = policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL); + + if (num_sta + num_go + num_cli != 2) + return true; + + /* If STA + P2P + another STA comes up then return true + * as this API is only for two port P2P + single STA combo + * checks + */ + if (num_sta == 1 && new_conn_mode == PM_STA_MODE) + return true; + + if ((((PM_STA_MODE == pm_conc_connection_list[0].mode && + PM_P2P_GO_MODE == pm_conc_connection_list[1].mode) || + (PM_P2P_GO_MODE == pm_conc_connection_list[0].mode && + PM_STA_MODE == pm_conc_connection_list[1].mode)) + || + (PM_P2P_GO_MODE == pm_conc_connection_list[0].mode && + PM_P2P_GO_MODE == pm_conc_connection_list[1].mode) + || + ((PM_STA_MODE == pm_conc_connection_list[0].mode && + PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode) || + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode && + PM_STA_MODE == pm_conc_connection_list[1].mode)) + || + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode && + PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode) + || + ((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode && + PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode) || + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode && + PM_P2P_GO_MODE == pm_conc_connection_list[1].mode))) && + num_sta <= 1) { + if ((new_conn_mode == PM_STA_MODE || + new_conn_mode == PM_P2P_CLIENT_MODE || + new_conn_mode == PM_P2P_GO_MODE) && + !policy_mgr_is_p2p_p2p_conc_supported(psoc)) + return false; + } + + return true; +} + +static bool policy_mgr_is_sap_go_allowed_with_ll_sap( + struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, + enum policy_mgr_con_mode mode) +{ + /** + * Scenario: When ll SAP(whose profile is set as gaming or + * lossless audio) is present on 5GHz channel and SAP/GO + * is trying to come up. + * Validate the ch_freq of SAP/GO for both DBS and SBS case + */ + if ((mode == PM_SAP_MODE || mode == PM_P2P_GO_MODE) && + !policy_mgr_is_ll_sap_concurrency_valid(psoc, freq, mode)) + return false; + + return true; +} + +bool policy_mgr_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + enum hw_mode_bandwidth bw, + uint32_t ext_flags, + struct policy_mgr_pcl_list *pcl) +{ + uint32_t num_connections = 0, count = 0, index = 0, i; + bool status = false, match = false; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool sta_sap_scc_on_dfs_chan; + bool go_force_scc; + enum channel_state chan_state; + bool is_dfs_ch = false; + struct ch_params ch_params; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + /* find the current connection state from pm_conc_connection_list*/ + num_connections = policy_mgr_get_connection_count(psoc); + + if (num_connections && policy_mgr_is_sub_20_mhz_enabled(psoc)) { + policy_mgr_rl_debug("dont allow concurrency if Sub 20 MHz is enabled"); + return status; + } + + if (policy_mgr_max_concurrent_connections_reached(psoc)) { + policy_mgr_rl_debug("Reached max concurrent connections: %d", + pm_ctx->cfg.max_conc_cxns); + policy_mgr_validate_conn_info(psoc); + return status; + } + + if (ch_freq) { + if (wlan_reg_is_5ghz_ch_freq(ch_freq)) { + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = policy_mgr_get_ch_width(bw); + chan_state = + wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pm_ctx->pdev, ch_freq, + &ch_params, REG_CURRENT_PWR_MODE); + if (chan_state == CHANNEL_STATE_DFS) + is_dfs_ch = true; + } + /* don't allow 3rd home channel on same MAC + * also check for single mac target which doesn't + * support interbad MCC as well + */ + if (!policy_mgr_allow_new_home_channel(psoc, mode, ch_freq, + num_connections, + is_dfs_ch, + ext_flags)) + return status; + + /* + * 1) DFS MCC is not yet supported + * 2) If you already have STA connection on 5G channel then + * don't allow any other persona to make connection on DFS + * channel because STA 5G + DFS MCC is not allowed. + * 3) If STA is on 2G channel and SAP is coming up on + * DFS channel then allow concurrency but make sure it is + * going to DBS and send PCL to firmware indicating that + * don't allow STA to roam to 5G channels. + * 4) On a single MAC device, if a SAP/P2PGO is already on a DFS + * channel, don't allow a 2 channel as it will result + * in MCC which is not allowed. + */ + if (!policy_mgr_is_5g_channel_allowed(psoc, + ch_freq, list, PM_P2P_GO_MODE)) + return status; + if (!policy_mgr_is_5g_channel_allowed(psoc, + ch_freq, list, PM_SAP_MODE)) + return status; + if (!policy_mgr_is_6g_channel_allowed(psoc, mode, + ch_freq)) + return status; + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + go_force_scc = policy_mgr_go_scc_enforced(psoc); + if ((mode == PM_SAP_MODE || mode == PM_P2P_GO_MODE) && + (!sta_sap_scc_on_dfs_chan || + !policy_mgr_is_sta_sap_scc(psoc, ch_freq) || + (!go_force_scc && mode == PM_P2P_GO_MODE))) { + if (is_dfs_ch) + match = policy_mgr_disallow_mcc(psoc, + ch_freq); + } + if (true == match) { + policy_mgr_rl_debug("No MCC, SAP/GO about to come up on DFS channel"); + return status; + } + if ((policy_mgr_is_hw_dbs_capable(psoc) != true) && + num_connections) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) { + if (policy_mgr_is_sap_p2pgo_on_dfs(psoc)) { + policy_mgr_rl_debug("MCC not allowed: SAP/P2PGO on DFS"); + return status; + } + } + } + } + + if (mode == PM_STA_MODE && + !policy_mgr_allow_sta_concurrency(psoc, ch_freq, ext_flags)) + return status; + + if (!policy_mgr_allow_sap_go_concurrency(psoc, mode, ch_freq, + WLAN_INVALID_VDEV_ID)) { + policy_mgr_rl_debug("This concurrency combination is not allowed"); + return status; + } + + /* + * don't allow two P2P GO on same band, if fw doesn't + * support p2p +p2p concurrency + */ + if (ch_freq && mode == PM_P2P_GO_MODE && num_connections && + !policy_mgr_is_p2p_p2p_conc_supported(psoc)) { + index = 0; + count = policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (index < count) { + if (WLAN_REG_IS_SAME_BAND_FREQS( + ch_freq, + pm_conc_connection_list[list[index]].freq)) { + policy_mgr_rl_debug("Don't allow P2P GO on same band"); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return status; + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } + + if (!policy_mgr_allow_wapi_concurrency(pm_ctx)) { + policy_mgr_rl_debug("Don't allow new conn when wapi security conn existing"); + return status; + } + + /* Allow sta+p2p+p2p only if firmware supports the capability */ + if (!policy_mgr_is_third_conn_sta_p2p_p2p_valid(psoc, mode)) { + policy_mgr_err("Don't allow third connection as GO or GC or STA with old fw"); + return status; + } + + /* Validate ll sap + sap/go concurrency */ + if (!policy_mgr_is_sap_go_allowed_with_ll_sap(psoc, ch_freq, mode)) { + policy_mgr_err("LL SAP concurrency is not valid"); + return status; + } + + /* + * Don't allow DFS SAP on non-SCC channels if an ML-STA is already + * present. PCL list returns the SCC channels and all channels from + * other MAC in case of non-ML/single link STA. + */ + if (mode == PM_SAP_MODE && pcl && + wlan_reg_is_dfs_for_freq(pm_ctx->pdev, ch_freq)) { + for (i = 0; i < pcl->pcl_len; i++) + if (pcl->pcl_list[i] == ch_freq) { + status = true; + break; + } + if (!status) { + policy_mgr_err("SAP channel %d Not present in PCL", + ch_freq); + return status; + } + } + status = true; + + return status; +} + +bool policy_mgr_allow_concurrency(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + enum hw_mode_bandwidth bw, + uint32_t ext_flags, uint8_t vdev_id) +{ + QDF_STATUS status; + struct policy_mgr_pcl_list pcl; + bool allowed; + + qdf_mem_zero(&pcl, sizeof(pcl)); + status = policy_mgr_get_pcl(psoc, mode, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("disallow connection:%d", status); + return false; + } + + allowed = policy_mgr_is_concurrency_allowed(psoc, mode, ch_freq, + bw, ext_flags, &pcl); + + /* Fourth connection concurrency check */ + if (allowed && policy_mgr_get_connection_count(psoc) == 3) + allowed = policy_mgr_is_concurrency_allowed_4_port( + psoc, + mode, + ch_freq, + pcl); + return allowed; +} + +bool +policy_mgr_allow_concurrency_csa(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, enum hw_mode_bandwidth bw, + uint32_t vdev_id, bool forced, + enum sap_csa_reason_code reason) +{ + bool allow = false; + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t num_cxn_del = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t old_ch_freq, conc_ext_flags; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return allow; + } + policy_mgr_debug("check concurrency_csa vdev:%d ch %d bw %d, forced %d, reason %d", + vdev_id, ch_freq, bw, forced, reason); + + status = policy_mgr_get_chan_by_session_id(psoc, vdev_id, + &old_ch_freq); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to get channel for vdev:%d", + vdev_id); + return allow; + } + qdf_mem_zero(info, sizeof(info)); + + /* + * Store the connection's parameter and temporarily delete it + * from the concurrency table. This way the allow concurrency + * check can be used as though a new connection is coming up, + * after check, restore the connection to concurrency table. + * + * In SAP+SAP SCC case, when LTE unsafe event processing, + * we should remove the all SAP conn entry on the same ch before + * do the concurrency check. Otherwise the left SAP on old channel + * will cause the concurrency check failure because of dual beacon + * MCC not supported. for the CSA request reason code, + * PM_CSA_REASON_UNSAFE_CHANNEL, we remove all the SAP + * entry on old channel before do concurrency check. + * + * The assumption is both SAP should move to the new channel later for + * the reason code. + */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + if (forced && (reason == CSA_REASON_UNSAFE_CHANNEL || + reason == CSA_REASON_DCS)) + policy_mgr_store_and_del_conn_info_by_chan_and_mode( + psoc, old_ch_freq, mode, info, &num_cxn_del); + else + policy_mgr_store_and_del_conn_info_by_vdev_id( + psoc, vdev_id, info, &num_cxn_del); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + conc_ext_flags = policy_mgr_get_conc_ext_flags(vdev, false); + allow = policy_mgr_allow_concurrency(psoc, mode, ch_freq, + bw, conc_ext_flags, vdev_id); + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + /* Restore the connection entry */ + if (num_cxn_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (!allow) + policy_mgr_err("CSA concurrency check failed"); + + return allow; +} + +/** + * policy_mgr_get_concurrency_mode() - return concurrency mode + * @psoc: PSOC object information + * + * This routine is used to retrieve concurrency mode + * + * Return: uint32_t value of concurrency mask + */ +uint32_t policy_mgr_get_concurrency_mode(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STA_MASK; + } + + policy_mgr_debug("concurrency_mode: 0x%x", + pm_ctx->concurrency_mode); + + return pm_ctx->concurrency_mode; +} + +QDF_STATUS policy_mgr_set_user_cfg(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_user_cfg *user_cfg) +{ + + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + if (!user_cfg) { + policy_mgr_err("Invalid User Config"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->user_cfg = *user_cfg; + policy_mgr_debug("dbs_selection_plcy 0x%x", + pm_ctx->cfg.dbs_selection_plcy); + policy_mgr_debug("vdev_priority_list 0x%x", + pm_ctx->cfg.vdev_priority_list); + pm_ctx->cur_conc_system_pref = pm_ctx->cfg.sys_pref; + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_will_freq_lead_to_mcc(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq) +{ + bool is_mcc = false; + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return is_mcc; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use && + policy_mgr_2_freq_always_on_same_mac(psoc, freq, + pm_conc_connection_list[conn_index].freq)) { + is_mcc = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return is_mcc; +} + +/** + * policy_mgr_is_two_connection_mcc() - Check if MCC scenario + * when there are two connections + * @psoc: PSOC object information + * + * If if MCC scenario when there are two connections + * + * Return: true or false + */ +static bool policy_mgr_is_two_connection_mcc(struct wlan_objmgr_psoc *psoc) +{ + return ((pm_conc_connection_list[0].freq != + pm_conc_connection_list[1].freq) && + (policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) && + (pm_conc_connection_list[0].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ) && + (pm_conc_connection_list[1].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ)) ? true : false; +} + +/** + * policy_mgr_is_three_connection_mcc() - Check if MCC scenario + * when there are three connections + * + * If if MCC scenario when there are three connections + * + * Return: true or false + */ +static bool policy_mgr_is_three_connection_mcc(void) +{ + return (((pm_conc_connection_list[0].freq != + pm_conc_connection_list[1].freq) || + (pm_conc_connection_list[0].freq != + pm_conc_connection_list[2].freq) || + (pm_conc_connection_list[1].freq != + pm_conc_connection_list[2].freq)) && + (pm_conc_connection_list[0].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ) && + (pm_conc_connection_list[1].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ) && + (pm_conc_connection_list[2].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ)) ? true : false; +} + +uint32_t policy_mgr_get_conc_vdev_on_same_mac(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint8_t mac_id) +{ + uint32_t id = WLAN_INVALID_VDEV_ID; + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return id; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].in_use) && + (pm_conc_connection_list[conn_index].vdev_id != vdev_id) && + (pm_conc_connection_list[conn_index].mac == mac_id)) { + id = pm_conc_connection_list[conn_index].vdev_id; + break; + } + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return id; +} + +bool policy_mgr_is_mcc_in_24G(struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections = 0; + bool is_24G_mcc = false; + + num_connections = policy_mgr_get_connection_count(psoc); + + switch (num_connections) { + case 1: + break; + case 2: + if (policy_mgr_is_two_connection_mcc(psoc)) + is_24G_mcc = true; + break; + case 3: + if (policy_mgr_is_three_connection_mcc()) + is_24G_mcc = true; + break; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + break; + } + + return is_24G_mcc; +} + +bool policy_mgr_check_for_session_conc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq) +{ + enum policy_mgr_con_mode mode; + bool ret; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev; + uint32_t conc_ext_flags; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev) { + mode = pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev( + psoc, vdev_id); + if (PM_MAX_NUM_OF_MODE == mode) { + policy_mgr_err("Invalid mode"); + return false; + } + } else + return false; + + if (ch_freq == 0) { + policy_mgr_err("Invalid channel number 0"); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + + /* Take care of 160MHz and 80+80Mhz later */ + conc_ext_flags = policy_mgr_get_conc_ext_flags(vdev, false); + ret = policy_mgr_allow_concurrency(psoc, mode, ch_freq, HW_MODE_20_MHZ, + conc_ext_flags, vdev_id); + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + if (false == ret) { + policy_mgr_err("Connection failed due to conc check fail"); + return 0; + } + + return true; +} + +/** + * policy_mgr_change_mcc_go_beacon_interval() - Change MCC beacon interval + * @psoc: PSOC object information + * @vdev_id: vdev id + * @dev_mode: device mode + * + * Updates the beacon parameters of the GO in MCC scenario + * + * Return: Success or Failure depending on the overall function behavior + */ +QDF_STATUS policy_mgr_change_mcc_go_beacon_interval( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, enum QDF_OPMODE dev_mode) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_debug("UPDATE Beacon Params"); + + if (QDF_SAP_MODE == dev_mode) { + if (pm_ctx->sme_cbacks.sme_change_mcc_beacon_interval + ) { + status = pm_ctx->sme_cbacks. + sme_change_mcc_beacon_interval(vdev_id); + if (status == QDF_STATUS_E_FAILURE) { + policy_mgr_err("Failed to update Beacon Params"); + return QDF_STATUS_E_FAILURE; + } + } else { + policy_mgr_err("sme_change_mcc_beacon_interval callback is NULL"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +struct policy_mgr_conc_connection_info *policy_mgr_get_conn_info(uint32_t *len) +{ + struct policy_mgr_conc_connection_info *conn_ptr = + &pm_conc_connection_list[0]; + *len = MAX_NUMBER_OF_CONC_CONNECTIONS; + + return conn_ptr; +} + +enum policy_mgr_con_mode +policy_mgr_qdf_opmode_to_pm_con_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + enum policy_mgr_con_mode mode = PM_MAX_NUM_OF_MODE; + + switch (device_mode) { + case QDF_STA_MODE: + mode = PM_STA_MODE; + break; + case QDF_P2P_CLIENT_MODE: + mode = PM_P2P_CLIENT_MODE; + break; + case QDF_P2P_GO_MODE: + mode = PM_P2P_GO_MODE; + break; + case QDF_SAP_MODE: +#ifdef WLAN_FEATURE_LL_LT_SAP + if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) + mode = PM_LL_LT_SAP_MODE; + else +#endif + mode = PM_SAP_MODE; + break; + case QDF_NAN_DISC_MODE: + mode = PM_NAN_DISC_MODE; + break; + case QDF_NDI_MODE: + mode = PM_NDI_MODE; + break; + default: + policy_mgr_debug("Unsupported mode (%d)", + device_mode); + } + + return mode; +} + +enum QDF_OPMODE policy_mgr_get_qdf_mode_from_pm( + enum policy_mgr_con_mode device_mode) +{ + enum QDF_OPMODE mode = QDF_MAX_NO_OF_MODE; + + switch (device_mode) { + case PM_STA_MODE: + mode = QDF_STA_MODE; + break; + case PM_SAP_MODE: + case PM_LL_LT_SAP_MODE: + mode = QDF_SAP_MODE; + break; + case PM_P2P_CLIENT_MODE: + mode = QDF_P2P_CLIENT_MODE; + break; + case PM_P2P_GO_MODE: + mode = QDF_P2P_GO_MODE; + break; + case PM_NAN_DISC_MODE: + mode = QDF_NAN_DISC_MODE; + break; + case PM_NDI_MODE: + mode = QDF_NDI_MODE; + break; + default: + policy_mgr_debug("Unsupported policy mgr mode (%d)", + device_mode); + } + return mode; +} + +QDF_STATUS policy_mgr_mode_specific_num_open_sessions( + struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode, + uint8_t *num_sessions) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + *num_sessions = pm_ctx->no_of_open_sessions[mode]; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_mode_specific_num_active_sessions( + struct wlan_objmgr_psoc *psoc, enum QDF_OPMODE mode, + uint8_t *num_sessions) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + *num_sessions = pm_ctx->no_of_active_sessions[mode]; + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_concurrent_open_sessions_running() - Checks for + * concurrent open session + * @psoc: PSOC object information + * + * Checks if more than one open session is running for all the allowed modes + * in the driver + * + * Return: True if more than one open session exists, False otherwise + */ +bool policy_mgr_concurrent_open_sessions_running( + struct wlan_objmgr_psoc *psoc) +{ + uint8_t i = 0; + uint8_t j = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return false; + } + + for (i = 0; i < QDF_MAX_NO_OF_MODE; i++) + j += pm_ctx->no_of_open_sessions[i]; + + return j > 1; +} + +/** + * policy_mgr_concurrent_beaconing_sessions_running() - Checks + * for concurrent beaconing entities + * @psoc: PSOC object information + * + * Checks if multiple beaconing sessions are running i.e., if SAP or GO + * are beaconing together + * + * Return: True if multiple entities are beaconing together, False otherwise + */ +bool policy_mgr_concurrent_beaconing_sessions_running( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return false; + } + + return (pm_ctx->no_of_open_sessions[QDF_SAP_MODE] + + pm_ctx->no_of_open_sessions[QDF_P2P_GO_MODE] + > 1) ? true : false; +} + + +void policy_mgr_clear_concurrent_session_count(struct wlan_objmgr_psoc *psoc) +{ + uint8_t i = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (pm_ctx) { + for (i = 0; i < QDF_MAX_NO_OF_MODE; i++) + pm_ctx->no_of_active_sessions[i] = 0; + } +} + +bool policy_mgr_is_multiple_active_sta_sessions(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, NULL) > 1; +} + +bool policy_mgr_is_sta_present_on_dfs_channel(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id, + qdf_freq_t *ch_freq, + enum hw_mode_bandwidth *ch_width) +{ + struct policy_mgr_conc_connection_info *conn_info; + bool status = false; + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + (conn_info->mode == PM_STA_MODE || + conn_info->mode == PM_P2P_CLIENT_MODE) && + (wlan_reg_is_dfs_for_freq(pm_ctx->pdev, conn_info->freq) || + (wlan_reg_is_5ghz_ch_freq(conn_info->freq) && + conn_info->bw == HW_MODE_160_MHZ))) { + *vdev_id = conn_info->vdev_id; + *ch_freq = pm_conc_connection_list[conn_index].freq; + *ch_width = conn_info->bw; + status = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +bool policy_mgr_is_sta_present_on_freq(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id, + qdf_freq_t ch_freq, + enum hw_mode_bandwidth *ch_width) +{ + struct policy_mgr_conc_connection_info *conn_info; + bool status = false; + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + (conn_info->mode == PM_STA_MODE || + conn_info->mode == PM_P2P_CLIENT_MODE) && + ch_freq == conn_info->freq) { + *vdev_id = conn_info->vdev_id; + *ch_width = conn_info->bw; + status = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +bool policy_mgr_is_sta_gc_active_on_mac(struct wlan_objmgr_psoc *psoc, + uint8_t mac_id) +{ + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t index, count; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + count = policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (index = 0; index < count; index++) { + if (mac_id == pm_conc_connection_list[list[index]].mac) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + count = policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_CLIENT_MODE, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (index = 0; index < count; index++) { + if (mac_id == pm_conc_connection_list[list[index]].mac) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return false; +} + +/** + * policy_mgr_is_sta_active_connection_exists() - Check if a STA + * connection is active + * @psoc: PSOC object information + * + * Checks if there is atleast one active STA connection in the driver + * + * Return: True if an active STA session is present, False otherwise + */ +bool policy_mgr_is_sta_active_connection_exists( + struct wlan_objmgr_psoc *psoc) +{ + return (!policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, NULL)) ? false : true; +} + +bool policy_mgr_is_any_nondfs_chnl_present(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq) +{ + bool status = false; + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use && + !wlan_reg_is_dfs_for_freq(pm_ctx->pdev, + pm_conc_connection_list[conn_index].freq)) { + *ch_freq = pm_conc_connection_list[conn_index].freq; + status = true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +uint32_t policy_mgr_get_dfs_beaconing_session_id( + struct wlan_objmgr_psoc *psoc) +{ + uint32_t session_id = WLAN_UMAC_VDEV_ID_MAX; + struct policy_mgr_conc_connection_info *conn_info; + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return session_id; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + WLAN_REG_IS_5GHZ_CH_FREQ(conn_info->freq) && + (conn_info->ch_flagext & (IEEE80211_CHAN_DFS | + IEEE80211_CHAN_DFS_CFREQ2)) && + (conn_info->mode == PM_SAP_MODE || + conn_info->mode == PM_P2P_GO_MODE)) { + session_id = + pm_conc_connection_list[conn_index].vdev_id; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return session_id; +} + +bool policy_mgr_is_any_dfs_beaconing_session_present( + struct wlan_objmgr_psoc *psoc, qdf_freq_t *ch_freq, + enum hw_mode_bandwidth *ch_width) +{ + struct policy_mgr_conc_connection_info *conn_info; + bool status = false; + uint32_t conn_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + (conn_info->mode == PM_SAP_MODE || + conn_info->mode == PM_P2P_GO_MODE) && + (wlan_reg_is_dfs_for_freq(pm_ctx->pdev, conn_info->freq) || + (wlan_reg_is_5ghz_ch_freq(conn_info->freq) && + conn_info->bw == HW_MODE_160_MHZ))) { + *ch_freq = pm_conc_connection_list[conn_index].freq; + *ch_width = conn_info->bw; + status = true; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +bool policy_mgr_scan_trim_5g_chnls_for_dfs_ap(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *freq) +{ + qdf_freq_t dfs_ch_frq = 0; + qdf_freq_t dfs_sta_frq = 0; + uint8_t vdev_id; + enum hw_mode_bandwidth ch_width; + enum hw_mode_bandwidth ch_sta_width; + QDF_STATUS status; + uint8_t sta_sap_scc_on_dfs_chnl; + + policy_mgr_is_any_dfs_beaconing_session_present(psoc, &dfs_ch_frq, + &ch_width); + if (!dfs_ch_frq) + return false; + + *freq = dfs_ch_frq; + + status = policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, + &sta_sap_scc_on_dfs_chnl); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + if (policy_mgr_is_sta_present_on_dfs_channel(psoc, &vdev_id, + &dfs_sta_frq, + &ch_sta_width) && + !policy_mgr_is_hw_dbs_capable(psoc) && + sta_sap_scc_on_dfs_chnl != PM_STA_SAP_ON_DFS_DEFAULT) { + policymgr_nofl_err("DFS STA present vdev_id %d ch_feq %d ch_width %d", + vdev_id, dfs_sta_frq, ch_sta_width); + return false; + } + + /* + * 1) if agile & DFS scans are supported + * 2) if hardware is DBS capable + * 3) if current hw mode is non-dbs + * if all above 3 conditions are true then don't skip any + * channel from scan list + */ + if (policy_mgr_is_hw_dbs_capable(psoc) && + !policy_mgr_is_current_hwmode_dbs(psoc) && + policy_mgr_get_dbs_plus_agile_scan_config(psoc) && + policy_mgr_get_single_mac_scan_with_dfs_config(psoc)) + return false; + + policy_mgr_debug("scan skip 5g chan due to dfs ap(ch %d / ch_width %d) present", + dfs_ch_frq, ch_width); + + return true; +} + +static void +policy_mgr_fill_trim_chan(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = object; + struct trim_chan_info *trim_info = arg; + uint16_t sap_peer_count = 0; + qdf_freq_t chan_freq; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE) + return; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return; + + sap_peer_count = wlan_vdev_get_peer_count(vdev); + policy_mgr_debug("vdev %d - peer count %d", + wlan_vdev_get_id(vdev), sap_peer_count); + if (sap_peer_count <= 1) + return; + + chan_freq = wlan_get_operation_chan_freq(vdev); + if (!chan_freq) + return; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) { + trim_info->trim |= TRIM_CHANNEL_LIST_5G; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) { + if (trim_info->sap_count != 1) + return; + + if ((trim_info->band_capability & BIT(REG_BAND_5G)) == + BIT(REG_BAND_5G)) + return; + + trim_info->trim |= TRIM_CHANNEL_LIST_24G; + } +} + +uint16_t +policy_mgr_scan_trim_chnls_for_connected_ap(struct wlan_objmgr_pdev *pdev) +{ + struct trim_chan_info trim_info; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return TRIM_CHANNEL_LIST_NONE; + + status = wlan_mlme_get_band_capability(psoc, + &trim_info.band_capability); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Could not get band capability"); + return TRIM_CHANNEL_LIST_NONE; + } + + trim_info.sap_count = policy_mgr_mode_specific_connection_count(psoc, + PM_SAP_MODE, NULL); + if (!trim_info.sap_count) + return TRIM_CHANNEL_LIST_NONE; + + trim_info.trim = TRIM_CHANNEL_LIST_NONE; + + wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + policy_mgr_fill_trim_chan, &trim_info, + 0, WLAN_POLICY_MGR_ID); + policy_mgr_debug("band_capability %d, sap_count %d, trim %d", + trim_info.band_capability, trim_info.sap_count, + trim_info.trim); + + return trim_info.trim; +} + +QDF_STATUS policy_mgr_get_nss_for_vdev(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + enum QDF_OPMODE dev_mode; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + dev_mode = policy_mgr_get_qdf_mode_from_pm(mode); + if (dev_mode == QDF_MAX_NO_OF_MODE) + return QDF_STATUS_E_FAILURE; + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (pm_ctx->sme_cbacks.sme_get_nss_for_vdev) { + pm_ctx->sme_cbacks.sme_get_nss_for_vdev( + dev_mode, nss_2g, nss_5g); + + } else { + policy_mgr_err("sme_get_nss_for_vdev callback is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_dump_connection_status_info(struct wlan_objmgr_psoc *psoc) +{ + uint32_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (!pm_conc_connection_list[i].in_use) + continue; + policy_mgr_debug("%d: use:%d vdev:%d mode:%d mac:%d freq:%d orig chainmask:%d orig nss:%d bw:%d, ch_flags %0X", + i, pm_conc_connection_list[i].in_use, + pm_conc_connection_list[i].vdev_id, + pm_conc_connection_list[i].mode, + pm_conc_connection_list[i].mac, + pm_conc_connection_list[i].freq, + pm_conc_connection_list[i].chain_mask, + pm_conc_connection_list[i].original_nss, + pm_conc_connection_list[i].bw, + pm_conc_connection_list[i].ch_flagext); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + policy_mgr_dump_curr_freq_range(pm_ctx); + policy_mgr_validate_conn_info(psoc); +} + +bool policy_mgr_is_any_mode_active_on_band_along_with_session( + struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + enum policy_mgr_band band) +{ + uint32_t i; + bool status = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + status = false; + goto send_status; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + switch (band) { + case POLICY_MGR_BAND_24: + if ((pm_conc_connection_list[i].vdev_id != session_id) + && (pm_conc_connection_list[i].in_use) && + (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[i].freq))) { + status = true; + goto release_mutex_and_send_status; + } + break; + case POLICY_MGR_BAND_5: + if ((pm_conc_connection_list[i].vdev_id != session_id) + && (pm_conc_connection_list[i].in_use) && + (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[i].freq))) { + status = true; + goto release_mutex_and_send_status; + } + break; + default: + policy_mgr_err("Invalidband option:%d", band); + status = false; + goto release_mutex_and_send_status; + } + } +release_mutex_and_send_status: + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); +send_status: + return status; +} + +enum phy_ch_width +policy_mgr_get_bw_by_session_id(struct wlan_objmgr_psoc *psoc, + uint8_t session_id) +{ + uint32_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum hw_mode_bandwidth bw = HW_MODE_BW_NONE; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return CH_WIDTH_INVALID; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].vdev_id == session_id && + pm_conc_connection_list[i].in_use) { + bw = pm_conc_connection_list[i].bw; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return policy_mgr_get_ch_width(bw); +} + +QDF_STATUS policy_mgr_get_chan_by_session_id(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + uint32_t *ch_freq) +{ + uint32_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if ((pm_conc_connection_list[i].vdev_id == session_id) && + (pm_conc_connection_list[i].in_use)) { + *ch_freq = pm_conc_connection_list[i].freq; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS policy_mgr_get_mac_id_by_session_id(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + uint8_t *mac_id) +{ + uint32_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if ((pm_conc_connection_list[i].vdev_id == session_id) && + (pm_conc_connection_list[i].in_use)) { + *mac_id = pm_conc_connection_list[i].mac; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return QDF_STATUS_E_FAILURE; +} + +uint32_t policy_mgr_get_sap_go_count_on_mac(struct wlan_objmgr_psoc *psoc, + uint32_t *list, uint8_t mac_id) +{ + uint32_t conn_index; + uint32_t count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].mac == mac_id && + pm_conc_connection_list[conn_index].in_use && + policy_mgr_is_beaconing_mode( + pm_conc_connection_list[conn_index].mode)) { + if (list) + list[count] = + pm_conc_connection_list[conn_index].vdev_id; + count++; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +uint32_t policy_mgr_get_mcc_operating_channel(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + uint8_t mcc_vdev_id; + QDF_STATUS status; + uint32_t ch_freq; + + if (!policy_mgr_is_mcc_with_this_vdev_id(psoc, vdev_id, &mcc_vdev_id)) { + policy_mgr_debug("No concurrent MCC vdev for id:%d", vdev_id); + return INVALID_CHANNEL_ID; + } + + status = policy_mgr_get_chan_by_session_id(psoc, mcc_vdev_id, &ch_freq); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to get channel for MCC vdev:%d", + mcc_vdev_id); + return INVALID_CHANNEL_ID; + } + + return ch_freq; +} + +bool policy_mgr_is_dnsc_set(struct wlan_objmgr_vdev *vdev) +{ + bool roffchan; + + if (!vdev) { + policy_mgr_err("Invalid parameter"); + return false; + } + + roffchan = wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_RESTRICT_OFFCHAN); + + if (roffchan) + policy_mgr_debug("Restrict offchannel is set"); + + return roffchan; +} + +QDF_STATUS policy_mgr_is_chan_ok_for_dnbs(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, bool *ok) +{ + uint32_t cc_count = 0, i; + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct wlan_objmgr_vdev *vdev; + + if (!ok) { + policy_mgr_err("Invalid parameter"); + return QDF_STATUS_E_INVAL; + } + + cc_count = policy_mgr_get_sap_mode_info(psoc, + &op_ch_freq_list[cc_count], + &vdev_id[cc_count]); + + if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS) + cc_count = cc_count + + policy_mgr_get_mode_specific_conn_info( + psoc, &op_ch_freq_list[cc_count], + &vdev_id[cc_count], PM_P2P_GO_MODE); + + if (!cc_count) { + *ok = true; + return QDF_STATUS_SUCCESS; + } + + if (!ch_freq) { + policy_mgr_err("channel is 0, cc count %d", cc_count); + return QDF_STATUS_E_INVAL; + } + + if (cc_count <= MAX_NUMBER_OF_CONC_CONNECTIONS) { + for (i = 0; i < cc_count; i++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id[i], WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev for vdev_id:%d is NULL", + vdev_id[i]); + return QDF_STATUS_E_INVAL; + } + + /** + * If channel passed is same as AP/GO operating + * channel, return true. + * + * If channel is different from operating channel but + * in same band, return false. + * + * If operating channel in different band + * (DBS capable), return true. + * + * If operating channel in different band + * (not DBS capable), return false. + */ + if (policy_mgr_is_dnsc_set(vdev)) { + if (op_ch_freq_list[i] == ch_freq) { + *ok = true; + wlan_objmgr_vdev_release_ref( + vdev, + WLAN_POLICY_MGR_ID); + break; + } else if (policy_mgr_2_freq_always_on_same_mac( + psoc, + op_ch_freq_list[i], ch_freq)) { + *ok = false; + wlan_objmgr_vdev_release_ref( + vdev, + WLAN_POLICY_MGR_ID); + break; + } else if (policy_mgr_is_hw_dbs_capable(psoc)) { + *ok = true; + wlan_objmgr_vdev_release_ref( + vdev, + WLAN_POLICY_MGR_ID); + break; + } else { + *ok = false; + wlan_objmgr_vdev_release_ref( + vdev, + WLAN_POLICY_MGR_ID); + break; + } + } else { + *ok = true; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + } + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_get_hw_dbs_max_bw(struct wlan_objmgr_psoc *psoc, + struct dbs_bw *bw_dbs) +{ + uint32_t dbs, sbs, i, param; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + dbs = POLICY_MGR_HW_MODE_DBS_MODE_GET(param); + sbs = POLICY_MGR_HW_MODE_SBS_MODE_GET(param); + + if (!dbs && !sbs) + bw_dbs->mac0_bw = + POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param); + + if (dbs) { + bw_dbs->mac0_bw = + POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(param); + bw_dbs->mac1_bw = + POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(param); + } else { + continue; + } + } +} + +uint32_t policy_mgr_get_hw_dbs_nss(struct wlan_objmgr_psoc *psoc, + struct dbs_nss *nss_dbs) +{ + int i, param; + uint32_t dbs, sbs, tx_chain0, rx_chain0, tx_chain1, rx_chain1; + uint32_t min_mac0_rf_chains, min_mac1_rf_chains; + uint32_t max_rf_chains, final_max_rf_chains = HW_MODE_SS_0x0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return final_max_rf_chains; + } + + nss_dbs->single_mac0_band_cap = 0; + for (i = 0; i < pm_ctx->num_dbs_hw_modes; i++) { + param = pm_ctx->hw_mode.hw_mode_list[i]; + dbs = POLICY_MGR_HW_MODE_DBS_MODE_GET(param); + sbs = POLICY_MGR_HW_MODE_SBS_MODE_GET(param); + + if (!dbs && !sbs && !nss_dbs->single_mac0_band_cap) + nss_dbs->single_mac0_band_cap = + POLICY_MGR_HW_MODE_MAC0_BAND_GET(param); + + if (dbs) { + tx_chain0 + = POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(param); + rx_chain0 + = POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(param); + + tx_chain1 + = POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(param); + rx_chain1 + = POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(param); + + min_mac0_rf_chains = QDF_MIN(tx_chain0, rx_chain0); + min_mac1_rf_chains = QDF_MIN(tx_chain1, rx_chain1); + + max_rf_chains + = QDF_MAX(min_mac0_rf_chains, min_mac1_rf_chains); + + if (final_max_rf_chains < max_rf_chains) { + final_max_rf_chains + = (max_rf_chains == 2) + ? HW_MODE_SS_2x2 : HW_MODE_SS_1x1; + + nss_dbs->mac0_ss + = (min_mac0_rf_chains == 2) + ? HW_MODE_SS_2x2 : HW_MODE_SS_1x1; + + nss_dbs->mac1_ss + = (min_mac1_rf_chains == 2) + ? HW_MODE_SS_2x2 : HW_MODE_SS_1x1; + } + } else { + continue; + } + } + + return final_max_rf_chains; +} + +bool policy_mgr_is_scan_simultaneous_capable(struct wlan_objmgr_psoc *psoc) +{ + uint8_t dual_mac_feature = DISABLE_DBS_CXN_AND_SCAN; + + policy_mgr_get_dual_mac_feature(psoc, &dual_mac_feature); + if ((dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) || + (dual_mac_feature == ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN) || + (dual_mac_feature == + ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN) || + !policy_mgr_is_hw_dbs_capable(psoc)) + return false; + + return true; +} + +void policy_mgr_set_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc, + uint8_t conc_system_pref) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + policy_mgr_debug("conc_system_pref %hu", conc_system_pref); + pm_ctx->cur_conc_system_pref = conc_system_pref; +} + +uint8_t policy_mgr_get_cur_conc_system_pref(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return PM_THROUGHPUT; + } + + policy_mgr_debug("conc_system_pref %hu", pm_ctx->cur_conc_system_pref); + return pm_ctx->cur_conc_system_pref; +} + +QDF_STATUS policy_mgr_get_updated_scan_and_fw_mode_config( + struct wlan_objmgr_psoc *psoc, uint32_t *scan_config, + uint32_t *fw_mode_config, uint32_t dual_mac_disable_ini, + uint32_t channel_select_logic_conc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + *scan_config = pm_ctx->dual_mac_cfg.cur_scan_config; + *fw_mode_config = pm_ctx->dual_mac_cfg.cur_fw_mode_config; + switch (dual_mac_disable_ini) { + case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN_WITH_ASYNC_SCAN_OFF: + policy_mgr_debug("dual_mac_disable_ini:%d async/dbs off", + dual_mac_disable_ini); + WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET(*scan_config, 0); + WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET(*fw_mode_config, 0); + break; + case DISABLE_DBS_CXN_AND_ENABLE_DBS_SCAN: + policy_mgr_debug("dual_mac_disable_ini:%d dbs_cxn off", + dual_mac_disable_ini); + WMI_DBS_FW_MODE_CFG_DBS_FOR_CXN_SET(*fw_mode_config, 0); + break; + case ENABLE_DBS_CXN_AND_ENABLE_SCAN_WITH_ASYNC_SCAN_OFF: + policy_mgr_debug("dual_mac_disable_ini:%d async off", + dual_mac_disable_ini); + WMI_DBS_CONC_SCAN_CFG_ASYNC_DBS_SCAN_SET(*scan_config, 0); + break; + case ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN: + policy_mgr_debug("dual_mac_disable_ini:%d ", + dual_mac_disable_ini); + WMI_DBS_CONC_SCAN_CFG_DBS_SCAN_SET(*scan_config, 0); + break; + default: + break; + } + + WMI_DBS_FW_MODE_CFG_DBS_FOR_STA_PLUS_STA_SET(*fw_mode_config, + PM_CHANNEL_SELECT_LOGIC_STA_STA_GET(channel_select_logic_conc)); + WMI_DBS_FW_MODE_CFG_DBS_FOR_STA_PLUS_P2P_SET(*fw_mode_config, + PM_CHANNEL_SELECT_LOGIC_STA_P2P_GET(channel_select_logic_conc)); + + policy_mgr_debug("*scan_config:%x ", *scan_config); + policy_mgr_debug("*fw_mode_config:%x ", *fw_mode_config); + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_force_scc(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + return ((pm_ctx->cfg.mcc_to_scc_switch == + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION) || + (pm_ctx->cfg.mcc_to_scc_switch == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) || + (pm_ctx->cfg.mcc_to_scc_switch == + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) || + (pm_ctx->cfg.mcc_to_scc_switch == + QDF_MCC_TO_SCC_WITH_PREFERRED_BAND)); +} + +bool policy_mgr_is_sap_allowed_on_dfs_freq(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, qdf_freq_t ch_freq) +{ + struct wlan_objmgr_psoc *psoc; + uint32_t sta_sap_scc_on_dfs_chan; + uint32_t sta_cnt, gc_cnt, idx; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct wlan_objmgr_vdev *vdev; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return false; + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + sta_cnt = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, + PM_STA_MODE); + + if (sta_cnt >= MAX_NUMBER_OF_CONC_CONNECTIONS) + return false; + + gc_cnt = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + &vdev_id_list[sta_cnt], + PM_P2P_CLIENT_MODE); + + policy_mgr_debug("sta_sap_scc_on_dfs_chan %u, sta_cnt %u, gc_cnt %u", + sta_sap_scc_on_dfs_chan, sta_cnt, gc_cnt); + + /* if sta_sap_scc_on_dfs_chan ini is set, DFS master capability is + * assumed disabled in the driver. + */ + if ((wlan_reg_get_channel_state_for_pwrmode( + pdev, ch_freq, REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS) && + !sta_cnt && !gc_cnt && sta_sap_scc_on_dfs_chan && + !policy_mgr_get_dfs_master_dynamic_enabled(psoc, vdev_id)) { + policy_mgr_err("SAP not allowed on DFS channel if no dfs master capability!!"); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("Invalid vdev"); + return false; + } + /* Allow the current CSA to continue if it's already started. This is + * possible when SAP CSA started to move to STA channel but STA got + * disconnected. + */ + if (!wlan_vdev_mlme_is_init_state(vdev) && + !wlan_vdev_is_up_active_state(vdev)) { + policy_mgr_debug("SAP is not yet UP: vdev %d", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return true; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + /* + * Check if any of the concurrent STA/ML-STA link/P2P client are in + * disconnecting state and disallow current SAP CSA. Concurrencies + * would be re-evaluated upon disconnect completion and SAP would be + * moved to right channel. + */ + for (idx = 0; idx < sta_cnt + gc_cnt; idx++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id_list[idx], + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("Invalid vdev"); + return false; + } + if (wlan_cm_is_vdev_disconnecting(vdev) || + mlo_is_any_link_disconnecting(vdev)) { + policy_mgr_err("SAP is not allowed to move to DFS channel at this time, vdev %d", + vdev_id_list[idx]); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return false; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + } + + return true; +} + +bool +policy_mgr_is_sap_go_interface_allowed_on_indoor(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t ch_freq) +{ + struct wlan_objmgr_psoc *psoc; + bool is_scc = false, indoor_support = false; + enum QDF_OPMODE mode; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return true; + + if (!wlan_reg_is_freq_indoor(pdev, ch_freq)) + return true; + + is_scc = policy_mgr_is_sta_sap_scc(psoc, ch_freq); + mode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + ucfg_mlme_get_indoor_channel_support(psoc, &indoor_support); + + /* + * Rules for indoor operation: + * If gindoor_channel_support is enabled - Allow SAP/GO + * If gindoor_channel_support is disabled + * a) Restrict 6 GHz SAP + * b) Restrict standalone 5 GHz SAP + * + * If p2p_go_on_5ghz_indoor_chan is enabled - Allow GO + * with or without concurrency + * + * If sta_sap_scc_on_indoor_chan is enabled - Allow + * SAP/GO with concurrent STA in indoor SCC + * + * Restrict all other operations on indoor + */ + + if (indoor_support) + return true; + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq)) { + policy_mgr_rl_debug("SAP operation is not allowed on 6 GHz indoor channel"); + return false; + } + + if (mode == QDF_SAP_MODE) { + if (is_scc && + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc)) + return true; + policy_mgr_rl_debug("SAP operation is not allowed on indoor channel"); + return false; + } + + if (mode == QDF_P2P_GO_MODE) { + if (ucfg_p2p_get_indoor_ch_support(psoc) || + (is_scc && + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc))) + return true; + policy_mgr_rl_debug("GO operation is not allowed on indoor channel"); + return false; + } + + policy_mgr_rl_debug("SAP operation is not allowed on indoor channel"); + return false; +} + +bool policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t sta_sap_scc_on_dfs_chnl = 0; + bool status = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return status; + } + + policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, + &sta_sap_scc_on_dfs_chnl); + if (policy_mgr_is_force_scc(psoc) && sta_sap_scc_on_dfs_chnl) + status = true; + + return status; +} + +bool policy_mgr_is_multi_sap_allowed_on_same_band( + struct wlan_objmgr_pdev *pdev, + enum policy_mgr_con_mode mode, + qdf_freq_t ch_freq) +{ + struct wlan_objmgr_psoc *psoc; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool multi_sap_allowed_on_same_band; + QDF_STATUS status; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (!ch_freq || !policy_mgr_is_sap_mode(mode)) + return true; + + status = policy_mgr_get_multi_sap_allowed_on_same_band(psoc, + &multi_sap_allowed_on_same_band); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("Failed to get multi_sap_allowed_on_same_band"); + /* Allow multi SAPs started on same band by default. */ + multi_sap_allowed_on_same_band = true; + } + if (!multi_sap_allowed_on_same_band) { + uint32_t ap_cnt, index = 0; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct policy_mgr_conc_connection_info *ap_info; + + ap_cnt = policy_mgr_get_sap_mode_count(psoc, list); + if (!ap_cnt) + return true; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + while (index < ap_cnt) { + ap_info = &pm_conc_connection_list[list[index]]; + if (WLAN_REG_IS_SAME_BAND_FREQS(ch_freq, + ap_info->freq)) { + policy_mgr_rl_debug("Don't allow SAP on same band"); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return false; + } + index++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } + + return true; +} + +bool policy_mgr_is_special_mode_active_5g(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + bool ret = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return ret; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].mode == mode && + pm_conc_connection_list[conn_index].freq >= + WLAN_REG_MIN_5GHZ_CHAN_FREQ && + pm_conc_connection_list[conn_index].in_use) + ret = true; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return ret; +} + +bool policy_mgr_is_sta_connected_2g(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + bool ret = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return ret; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].mode == PM_STA_MODE && + pm_conc_connection_list[conn_index].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ && + pm_conc_connection_list[conn_index].in_use) + ret = true; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return ret; +} + +bool +policy_mgr_is_connected_sta_5g(struct wlan_objmgr_psoc *psoc, qdf_freq_t *freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + bool ret = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return ret; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + *freq = pm_conc_connection_list[conn_index].freq; + if (pm_conc_connection_list[conn_index].mode == PM_STA_MODE && + WLAN_REG_IS_5GHZ_CH_FREQ(*freq) && + pm_conc_connection_list[conn_index].in_use) { + ret = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return ret; +} + +uint32_t policy_mgr_get_connection_info(struct wlan_objmgr_psoc *psoc, + struct connection_info *info) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index, count = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return count; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (PM_CONC_CONNECTION_LIST_VALID_INDEX(conn_index)) { + info[count].vdev_id = + pm_conc_connection_list[conn_index].vdev_id; + info[count].mac_id = + pm_conc_connection_list[conn_index].mac; + info[count].channel = wlan_reg_freq_to_chan( + pm_ctx->pdev, + pm_conc_connection_list[conn_index].freq); + info[count].ch_freq = + pm_conc_connection_list[conn_index].freq; + count++; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return count; +} + +bool policy_mgr_allow_sap_go_concurrency(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + uint32_t vdev_id) +{ + enum policy_mgr_con_mode con_mode; + int id; + uint32_t vdev, con_freq; + bool dbs; + + if (mode != PM_SAP_MODE && mode != PM_P2P_GO_MODE) + return true; + dbs = policy_mgr_is_hw_dbs_capable(psoc); + for (id = 0; id < MAX_NUMBER_OF_CONC_CONNECTIONS; id++) { + if (!pm_conc_connection_list[id].in_use) + continue; + vdev = pm_conc_connection_list[id].vdev_id; + if (vdev_id == vdev) + continue; + con_mode = pm_conc_connection_list[id].mode; + if (con_mode != PM_SAP_MODE && con_mode != PM_P2P_GO_MODE) + continue; + con_freq = pm_conc_connection_list[id].freq; + + if (policy_mgr_is_p2p_p2p_conc_supported(psoc) && + (mode == PM_P2P_GO_MODE) && (con_mode == PM_P2P_GO_MODE)) { + policy_mgr_debug("GO+GO scc is allowed freq = %d ", + ch_freq); + return true; + } + + if (policy_mgr_dual_beacon_on_single_mac_mcc_capable(psoc) && + (mode == PM_SAP_MODE || mode == PM_P2P_GO_MODE) && + (con_mode == PM_SAP_MODE || con_mode == PM_P2P_GO_MODE)) + return true; + + if (policy_mgr_dual_beacon_on_single_mac_scc_capable(psoc) && + (ch_freq == con_freq)) { + policy_mgr_debug("SCC enabled, 2 AP on same channel, allow 2nd AP"); + return true; + } + if (!dbs) { + policy_mgr_debug("DBS unsupported, mcc and scc unsupported too, don't allow 2nd AP"); + return false; + } + + if (policy_mgr_are_2_freq_on_same_mac(psoc, ch_freq, + con_freq)) { + policy_mgr_debug("DBS supported, 2 SAP on same band, reject 2nd AP"); + return false; + } + } + + /* Don't block the second interface */ + return true; +} + +bool policy_mgr_dual_beacon_on_single_mac_scc_capable( + struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return false; + } + + if (wmi_service_enabled( + wmi_handle, + wmi_service_dual_beacon_on_single_mac_scc_support)) { + policy_mgr_debug("Dual beaconing on same channel on single MAC supported"); + return true; + } + policy_mgr_debug("Dual beaconing on same channel on single MAC is not supported"); + return false; +} + +bool policy_mgr_dual_beacon_on_single_mac_mcc_capable( + struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return false; + } + + if (wmi_service_enabled( + wmi_handle, + wmi_service_dual_beacon_on_single_mac_mcc_support)) { + policy_mgr_debug("Dual beaconing on different channel on single MAC supported"); + return true; + } + policy_mgr_debug("Dual beaconing on different channel on single MAC is not supported"); + return false; +} + +bool policy_mgr_sta_sap_scc_on_lte_coex_chan( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t scc_lte_coex = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + policy_mgr_get_sta_sap_scc_lte_coex_chnl(psoc, &scc_lte_coex); + + return scc_lte_coex; +} + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +void policy_mgr_init_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum conn_6ghz_flag ap_6ghz_capable) +{ + struct policy_mgr_conc_connection_info *conn_info; + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum conn_6ghz_flag conn_6ghz_flag = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + policy_mgr_is_sap_mode(conn_info->mode) && + vdev_id == conn_info->vdev_id) { + conn_info->conn_6ghz_flag = ap_6ghz_capable; + conn_info->conn_6ghz_flag |= CONN_6GHZ_FLAG_VALID; + conn_6ghz_flag = conn_info->conn_6ghz_flag; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("vdev %d init conn_6ghz_flag %x new %x", + vdev_id, ap_6ghz_capable, conn_6ghz_flag); +} + +void policy_mgr_set_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool set, + enum conn_6ghz_flag ap_6ghz_capable) +{ + struct policy_mgr_conc_connection_info *conn_info; + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum conn_6ghz_flag conn_6ghz_flag = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + policy_mgr_is_beaconing_mode(conn_info->mode) && + policy_mgr_is_6ghz_conc_mode_supported( + psoc, conn_info->mode) && + vdev_id == conn_info->vdev_id) { + if (set) + conn_info->conn_6ghz_flag |= ap_6ghz_capable; + else + conn_info->conn_6ghz_flag &= ~ap_6ghz_capable; + conn_info->conn_6ghz_flag |= CONN_6GHZ_FLAG_VALID; + conn_6ghz_flag = conn_info->conn_6ghz_flag; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug("vdev %d %s conn_6ghz_flag %x new %x", + vdev_id, set ? "set" : "clr", + ap_6ghz_capable, conn_6ghz_flag); +} + +bool policy_mgr_get_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t *conn_flag) +{ + struct policy_mgr_conc_connection_info *conn_info; + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum conn_6ghz_flag conn_6ghz_flag = 0; + bool is_6g_allowed = false; + + if (conn_flag) + *conn_flag = 0; + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + conn_info = &pm_conc_connection_list[conn_index]; + if (conn_info->in_use && + policy_mgr_is_beaconing_mode(conn_info->mode) && + policy_mgr_is_6ghz_conc_mode_supported( + psoc, conn_info->mode) && + vdev_id == conn_info->vdev_id) { + conn_6ghz_flag = conn_info->conn_6ghz_flag; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* If the vdev connection is not active, policy mgr will query legacy + * hdd to get sap acs and security information. + * The assumption is no legacy client connected for non active + * connection. + */ + if (!(conn_6ghz_flag & CONN_6GHZ_FLAG_VALID) && + pm_ctx->hdd_cbacks.hdd_get_ap_6ghz_capable) + conn_6ghz_flag = pm_ctx->hdd_cbacks.hdd_get_ap_6ghz_capable( + psoc, vdev_id) | + CONN_6GHZ_FLAG_NO_LEGACY_CLIENT; + + if ((conn_6ghz_flag & CONN_6GHZ_CAPABLE) == CONN_6GHZ_CAPABLE) + is_6g_allowed = true; + policy_mgr_debug("vdev %d conn_6ghz_flag %x 6ghz %s", vdev_id, + conn_6ghz_flag, is_6g_allowed ? "allowed" : "deny"); + if (conn_flag) + *conn_flag = conn_6ghz_flag; + + return is_6g_allowed; +} +#endif + +bool policy_mgr_is_sta_sap_scc(struct wlan_objmgr_psoc *psoc, + uint32_t sap_freq) +{ + uint32_t conn_index; + bool is_scc = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return is_scc; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use && + (pm_conc_connection_list[conn_index].mode == + PM_STA_MODE || + pm_conc_connection_list[conn_index].mode == + PM_P2P_CLIENT_MODE) && (sap_freq == + pm_conc_connection_list[conn_index].freq)) { + is_scc = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return is_scc; +} + +bool policy_mgr_go_scc_enforced(struct wlan_objmgr_psoc *psoc) +{ + uint32_t mcc_to_scc_switch; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + mcc_to_scc_switch = policy_mgr_get_mcc_to_scc_switch_mode(psoc); + if (mcc_to_scc_switch == + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) + return true; + + if (pm_ctx->cfg.go_force_scc && policy_mgr_is_force_scc(psoc)) + return true; + + return false; +} + +uint8_t +policy_mgr_fetch_existing_con_info(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t freq, + enum policy_mgr_con_mode *mode, + uint32_t *existing_con_freq, + enum phy_ch_width *existing_ch_width) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return WLAN_UMAC_VDEV_ID_MAX; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((policy_mgr_is_beaconing_mode( + pm_conc_connection_list[conn_index].mode) || + pm_conc_connection_list[conn_index].mode == + PM_P2P_CLIENT_MODE || + pm_conc_connection_list[conn_index].mode == + PM_STA_MODE) && + pm_conc_connection_list[conn_index].in_use && + policy_mgr_are_2_freq_on_same_mac( + psoc, freq, pm_conc_connection_list[conn_index].freq) && + freq != pm_conc_connection_list[conn_index].freq && + vdev_id != pm_conc_connection_list[conn_index].vdev_id) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + policy_mgr_debug( + "Existing vdev_id for mode %d is %d", + pm_conc_connection_list[conn_index].mode, + pm_conc_connection_list[conn_index].vdev_id); + *mode = pm_conc_connection_list[conn_index].mode; + *existing_con_freq = + pm_conc_connection_list[conn_index].freq; + *existing_ch_width = policy_mgr_get_ch_width( + pm_conc_connection_list[conn_index].bw); + return pm_conc_connection_list[conn_index].vdev_id; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return WLAN_UMAC_VDEV_ID_MAX; +} + +#ifdef WLAN_FEATURE_P2P_P2P_STA +bool policy_mgr_is_go_scc_strict(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool ret = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + ret = false; + goto return_val; + } + if (pm_ctx->cfg.go_force_scc & GO_FORCE_SCC_STRICT) { + ret = true; + goto return_val; + } + ret = false; +return_val: + policy_mgr_debug("ret val is %d", ret); + return ret; +} +#endif + +QDF_STATUS policy_mgr_update_nan_vdev_mac_info(struct wlan_objmgr_psoc *psoc, + uint8_t nan_vdev_id, + uint8_t mac_id) +{ + struct policy_mgr_hw_mode_params hw_mode = {0}; + struct policy_mgr_vdev_mac_map vdev_mac_map = {0}; + QDF_STATUS status; + + vdev_mac_map.vdev_id = nan_vdev_id; + vdev_mac_map.mac_id = mac_id; + + status = policy_mgr_get_current_hw_mode(psoc, &hw_mode); + + if (QDF_IS_STATUS_SUCCESS(status)) + policy_mgr_update_hw_mode_conn_info(psoc, 1, &vdev_mac_map, + hw_mode, 0, NULL); + + return status; +} + +bool policy_mgr_is_sap_go_on_2g(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + bool ret = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return ret; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].mode == PM_SAP_MODE || + pm_conc_connection_list[conn_index].mode == PM_P2P_GO_MODE) && + pm_conc_connection_list[conn_index].freq <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ && + pm_conc_connection_list[conn_index].in_use) + ret = true; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return ret; +} + +static inline bool +policy_mgr_is_chan_eligible_for_sap(struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t vdev_id, qdf_freq_t freq) +{ + struct wlan_objmgr_vdev *vdev; + enum channel_state ch_state; + enum reg_6g_ap_type sta_connected_pwr_type; + uint32_t ap_power_type_6g = 0; + bool is_eligible = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(pm_ctx->psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) + return false; + + ch_state = wlan_reg_get_channel_state_for_pwrmode(pm_ctx->pdev, + freq, + REG_CURRENT_PWR_MODE); + sta_connected_pwr_type = mlme_get_best_6g_power_type(vdev); + wlan_reg_get_cur_6g_ap_pwr_type(pm_ctx->pdev, &ap_power_type_6g); + + /* + * If the SAP user configured frequency is 6 GHz, + * move the SAP to STA SCC in 6 GHz only if: + * a) The channel is PSC + * b) The channel supports AP in VLP power type + * c) The DUT is configured to operate SAP in VLP only + * d) The STA is connected to the 6 GHz AP in + * either VLP or LPI. + * - If the STA is in LPI, then lim_update_tx_power() + * would move the STA to VLP. + */ + if (WLAN_REG_IS_6GHZ_PSC_CHAN_FREQ(freq) && + ap_power_type_6g == REG_VERY_LOW_POWER_AP && + ch_state == CHANNEL_STATE_ENABLE && + (sta_connected_pwr_type == REG_VERY_LOW_POWER_AP || + sta_connected_pwr_type == REG_INDOOR_AP)) + is_eligible = true; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return is_eligible; +} + +bool policy_mgr_is_restart_sap_required(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + qdf_freq_t freq, + tQDF_MCC_TO_SCC_SWITCH_MODE scc_mode) +{ + uint8_t i; + bool restart_required = false; + bool is_sta_p2p_cli; + bool sap_on_dfs = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info *connection; + bool sta_sap_scc_on_dfs_chan, sta_sap_scc_allowed_on_indoor_ch; + qdf_freq_t user_config_freq; + bool sap_found = false; + uint8_t num_mcc_conn = 0; + uint8_t num_scc_conn = 0; + uint8_t num_5_or_6_conn = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid psoc"); + return false; + } + + if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) { + if (policy_mgr_is_ll_lt_sap_restart_required(psoc)) + return true; + return false; + } + + if (scc_mode == QDF_MCC_TO_SCC_SWITCH_DISABLE) { + policy_mgr_debug("No scc required"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + connection = pm_conc_connection_list; + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (!connection[i].in_use) + continue; + if (connection[i].vdev_id == vdev_id) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(connection[i].freq) && + (connection[i].ch_flagext & (IEEE80211_CHAN_DFS | + IEEE80211_CHAN_DFS_CFREQ2))) + sap_on_dfs = true; + sap_found = true; + } else { + if (connection[i].freq == freq) + num_scc_conn++; + else + num_mcc_conn++; + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(connection[i].freq)) + num_5_or_6_conn++; + } + } + if (!sap_found) { + policy_mgr_err("Invalid vdev id: %d", vdev_id); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return false; + } + /* Current hw mode is SBS low share. STA 5180, SAP 1 2412, + * SAP 2 5745, but SAP 1 is 2G only, can't move to STA 5180, + * SAP 2 is SBS with STA, policy_mgr_are_2_freq_on_same_mac + * return false for 5745 and 5180 and finally this function + * return false, no force SCC on SAP2. + * Add mcc conntion count check for SAP2, if SAP 2 channel + * is different from all of exsting 2 or more connections, then + * try to force SCC on SAP 2. + */ + if (num_mcc_conn > 1 && !num_scc_conn) { + policy_mgr_debug("sap vdev %d has chan %d diff with %d exsting conn", + vdev_id, freq, num_mcc_conn); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return true; + } + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + + sta_sap_scc_allowed_on_indoor_ch = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (!connection[i].in_use) + continue; + + if (scc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL && + connection[i].mode == PM_P2P_GO_MODE && + connection[i].vdev_id != vdev_id && + policy_mgr_2_freq_always_on_same_mac(psoc, freq, + connection[i].freq)) { + policy_mgr_debug("SAP:%d and GO:%d on same mac. Restart SAP ", + freq, connection[i].freq); + restart_required = true; + break; + } + + is_sta_p2p_cli = + (connection[i].mode == PM_STA_MODE || + connection[i].mode == PM_P2P_CLIENT_MODE); + if (!is_sta_p2p_cli) + continue; + + if (connection[i].freq != freq && + policy_mgr_are_2_freq_on_same_mac(psoc, freq, + connection[i].freq)) { + policy_mgr_debug("SAP:%d and STA:%d on same mac. Restart SAP ", + freq, connection[i].freq); + restart_required = true; + break; + } + if (connection[i].freq == freq && + !sta_sap_scc_on_dfs_chan && sap_on_dfs) { + policy_mgr_debug("Move SAP out of DFS ch:%d", freq); + restart_required = true; + break; + } + + if (connection[i].freq == freq && + !sta_sap_scc_allowed_on_indoor_ch && + wlan_reg_is_freq_indoor(pm_ctx->pdev, connection[i].freq)) { + policy_mgr_debug("Move SAP out of indoor ch:%d", freq); + restart_required = true; + break; + } + + /* + * Existing connection: + * 1. "STA in DFS ch and SoftAP in 2.4 GHz channel, and then + * STA moves to 5 GHz non-DFS channel + * + * 2. "STA in indoor channel and sta_sap_scc_on_indoor_ch + * ini is false & SAP has moved to 2.4 GHz channel" + * STA moves back to 5 GHZ non indoor/non DFS channel + * + * Now SAP has to move to STA 5 GHz channel if SAP + * was started on 5 GHz channel initially. + */ + user_config_freq = + policy_mgr_get_user_config_sap_freq(psoc, vdev_id); + + if (connection[i].freq != freq && + WLAN_REG_IS_24GHZ_CH_FREQ(freq) && + WLAN_REG_IS_5GHZ_CH_FREQ(connection[i].freq) && + !wlan_reg_is_dfs_for_freq(pm_ctx->pdev, + connection[i].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ(user_config_freq)) { + policy_mgr_debug("Move SAP from:%d to STA ch:%d (sap start freq:%d)", + freq, connection[i].freq, + user_config_freq); + restart_required = true; + + if (wlan_reg_is_freq_indoor(pm_ctx->pdev, + connection[i].freq) && + !sta_sap_scc_allowed_on_indoor_ch) + restart_required = false; + break; + } + + /* + * SAP has to move away from indoor only channel + * when STA moves out of indoor only channel and + * SAP standalone support on indoor only + * channel ini is disabled + **/ + if (connection[i].freq != freq && + WLAN_REG_IS_24GHZ_CH_FREQ(connection[i].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ(freq) && + !policy_mgr_is_sap_go_interface_allowed_on_indoor( + pm_ctx->pdev, + vdev_id, freq)) { + policy_mgr_debug("SAP in indoor freq: sta:%d sap:%d", + connection[i].freq, freq); + restart_required = true; + } + + if (scc_mode == QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL && + WLAN_REG_IS_24GHZ_CH_FREQ(freq) && user_config_freq) { + if (connection[i].freq == freq && !num_5_or_6_conn && + !WLAN_REG_IS_24GHZ_CH_FREQ(user_config_freq)) { + policy_mgr_debug("SAP move to user configure %d from %d", + user_config_freq, freq); + restart_required = true; + } else if (connection[i].freq != freq && + WLAN_REG_IS_6GHZ_CHAN_FREQ(user_config_freq) && + policy_mgr_is_chan_eligible_for_sap(pm_ctx, + connection[i].vdev_id, + connection[i].freq)) { + policy_mgr_debug("Move SAP to STA 6 GHz channel"); + restart_required = true; + } + } + } + + if (!restart_required && + policy_mgr_is_restart_sap_required_with_mlo_sta( + psoc, vdev_id, freq)) + restart_required = true; + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return restart_required; +} + +uint8_t policy_mgr_get_roam_enabled_sta_session_id( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t index, count; + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct wlan_objmgr_vdev *vdev, *assoc_vdev; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return WLAN_UMAC_VDEV_ID_MAX; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("Invalid vdev"); + return WLAN_UMAC_VDEV_ID_MAX; + } + + if (wlan_vdev_mlme_is_link_sta_vdev(vdev)) { + assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); + if (assoc_vdev && ucfg_cm_is_vdev_active(assoc_vdev)) { + policy_mgr_debug("replace link vdev %d with assoc vdev %d", + vdev_id, wlan_vdev_get_id(assoc_vdev)); + vdev_id = wlan_vdev_get_id(assoc_vdev); + } + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + count = policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, list); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + for (index = 0; index < count; index++) { + if (vdev_id == pm_conc_connection_list[list[index]].vdev_id) + continue; + if (MLME_IS_ROAM_INITIALIZED( + psoc, pm_conc_connection_list[list[index]].vdev_id)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return pm_conc_connection_list[list[index]].vdev_id; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return WLAN_UMAC_VDEV_ID_MAX; +} + +bool policy_mgr_is_sta_mon_concurrency(struct wlan_objmgr_psoc *psoc) +{ + uint32_t conc_mode; + + if (wlan_mlme_is_sta_mon_conc_supported(psoc)) { + conc_mode = policy_mgr_get_concurrency_mode(psoc); + if (conc_mode & QDF_STA_MASK && + conc_mode & QDF_MONITOR_MASK) { + policy_mgr_err("STA + MON mode is UP"); + return true; + } + } + return false; +} + +QDF_STATUS policy_mgr_check_mon_concurrency(struct wlan_objmgr_psoc *psoc) +{ + uint8_t num_open_session = 0; + + if (policy_mgr_mode_specific_num_open_sessions( + psoc, + QDF_MONITOR_MODE, + &num_open_session) != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + if (num_open_session) { + policy_mgr_err("monitor mode already exists, only one is possible"); + return QDF_STATUS_E_BUSY; + } + + num_open_session = policy_mgr_get_sap_mode_count(psoc, NULL); + + if (num_open_session) { + policy_mgr_err("cannot add monitor mode, due to SAP concurrency"); + return QDF_STATUS_E_INVAL; + } + + num_open_session = policy_mgr_mode_specific_connection_count( + psoc, + PM_P2P_CLIENT_MODE, + NULL); + + if (num_open_session) { + policy_mgr_err("cannot add monitor mode, due to P2P CLIENT concurrency"); + return QDF_STATUS_E_INVAL; + } + + num_open_session = policy_mgr_mode_specific_connection_count( + psoc, + PM_P2P_GO_MODE, + NULL); + + if (num_open_session) { + policy_mgr_err("cannot add monitor mode, due to P2P GO concurrency"); + return QDF_STATUS_E_INVAL; + } + + num_open_session = policy_mgr_mode_specific_connection_count( + psoc, + PM_NAN_DISC_MODE, + NULL); + + if (num_open_session) { + policy_mgr_err("cannot add monitor mode, due to NAN concurrency"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_hwmode_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + policy_mgr_err("Invalid WMI handle"); + return false; + } + + return wmi_service_enabled(wmi_handle, + wmi_service_hw_mode_policy_offload_support); +} + +bool policy_mgr_is_ap_ap_mcc_allow(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + uint32_t ch_freq, + enum phy_ch_width ch_width, + uint8_t *con_vdev_id, + uint32_t *con_freq) +{ + enum QDF_OPMODE mode; + enum policy_mgr_con_mode con_mode; + union conc_ext_flag conc_ext_flags; + uint32_t cc_count, i, j, ap_index; + uint32_t op_freq[MAX_NUMBER_OF_CONC_CONNECTIONS * 2]; + uint8_t vdev_id[MAX_NUMBER_OF_CONC_CONNECTIONS * 2]; + QDF_STATUS status; + struct policy_mgr_pcl_list pcl; + + if (!psoc || !vdev || !pdev) { + policy_mgr_debug("psoc or vdev or pdev is NULL"); + return false; + } + + cc_count = policy_mgr_get_mode_specific_conn_info(psoc, + &op_freq[0], + &vdev_id[0], + PM_SAP_MODE); + if (cc_count < MAX_NUMBER_OF_CONC_CONNECTIONS) + cc_count = cc_count + + policy_mgr_get_mode_specific_conn_info( + psoc, + &op_freq[cc_count], + &vdev_id[cc_count], + PM_P2P_GO_MODE); + if (!cc_count) + return true; + + mode = wlan_vdev_mlme_get_opmode(vdev); + con_mode = policy_mgr_qdf_opmode_to_pm_con_mode( + psoc, mode, wlan_vdev_get_id(vdev)); + qdf_mem_zero(&pcl, sizeof(pcl)); + status = policy_mgr_get_pcl(psoc, con_mode, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), + wlan_vdev_get_id(vdev)); + if (!pcl.pcl_len) + return true; + ap_index = cc_count; + for (i = 0 ; i < pcl.pcl_len; i++) { + for (j = 0; j < cc_count; j++) { + if (op_freq[j] == pcl.pcl_list[i]) + break; + } + if (j >= cc_count) + continue; + if (ch_freq == op_freq[j]) { + ap_index = j; + break; + } + if (!policy_mgr_is_hw_dbs_capable(psoc)) { + ap_index = j; + break; + } + if (wlan_reg_is_same_band_freqs(ch_freq, op_freq[j]) && + !policy_mgr_are_sbs_chan(psoc, ch_freq, op_freq[j])) { + ap_index = j; + break; + } + if (wlan_reg_is_same_band_freqs(ch_freq, op_freq[j]) && + policy_mgr_get_connection_count(psoc) > 2) { + ap_index = j; + break; + } + } + /* If same band MCC SAP/GO not present, return true, + * no AP to AP channel override + */ + if (ap_index >= cc_count) + return true; + + *con_freq = op_freq[ap_index]; + *con_vdev_id = vdev_id[ap_index]; + /* + * For 3Vif concurrency we only support SCC in same MAC + * in below combination: + * 2 beaconing entities with STA in SCC. + * 3 beaconing entities in SCC. + */ + conc_ext_flags.value = policy_mgr_get_conc_ext_flags(vdev, false); + if (!policy_mgr_allow_concurrency( + psoc, con_mode, ch_freq, + policy_mgr_get_bw(ch_width), + conc_ext_flags.value, + wlan_vdev_get_id(vdev))) { + policy_mgr_debug("AP AP mcc not allowed, try to override 2nd SAP/GO chan"); + return false; + } + /* For SCC case & bandwdith > 20, the center frequency have to be + * same to avoid target MCC on different center frequency even though + * primary channel are same. + */ + if (*con_freq == ch_freq && wlan_reg_get_bw_value(ch_width) > 20) + return false; + + return true; +} + +bool policy_mgr_any_other_vdev_on_same_mac_as_freq( + struct wlan_objmgr_psoc *psoc, + uint32_t freq, uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index = 0; + bool same_mac = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (!pm_conc_connection_list[conn_index].in_use) + continue; + + if (pm_conc_connection_list[conn_index].vdev_id == vdev_id) + continue; + + if (policy_mgr_are_2_freq_on_same_mac( + psoc, + pm_conc_connection_list[conn_index].freq, + freq)) { + same_mac = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return same_mac; +} + +QDF_STATUS policy_mgr_get_sbs_cfg(struct wlan_objmgr_psoc *psoc, bool *sbs) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + *sbs = pm_ctx->cfg.sbs_enable; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_SR +bool policy_mgr_sr_same_mac_conc_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + bool sr_conc_enabled; + + if (!psoc) { + mlme_err("PSOC is NULL"); + return false; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + mlme_err("wmi_handle is null"); + return false; + } + + sr_conc_enabled = policy_mgr_get_same_mac_conc_sr_status(psoc); + + return (sr_conc_enabled && + wmi_service_enabled(wmi_handle, + wmi_service_obss_per_packet_sr_support)); +} +#endif + +/** + * _policy_mgr_get_ll_sap_freq()- Function to get LL sap freq if it's present + * for provided type + * @psoc: PSOC object + * @ap_type: low latency ap type + * + * Return: freq if LL SAP otherwise return 0 + * + */ +static qdf_freq_t _policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc, + enum ll_ap_type ap_type) +{ + struct wlan_objmgr_vdev *sap_vdev; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_idx = 0, vdev_id; + bool is_ll_sap_present = false; + qdf_freq_t freq = 0; + enum host_concurrent_ap_policy profile = + HOST_CONCURRENT_AP_POLICY_UNSPECIFIED; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return 0; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_idx = 0; conn_idx < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_idx++) { + if (!(policy_mgr_is_sap_mode( + pm_conc_connection_list[conn_idx].mode) && + pm_conc_connection_list[conn_idx].in_use)) + continue; + + vdev_id = pm_conc_connection_list[conn_idx].vdev_id; + freq = pm_conc_connection_list[conn_idx].freq; + + sap_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, + vdev_id, + WLAN_POLICY_MGR_ID); + + if (!sap_vdev) { + policy_mgr_err("vdev %d: not a sap vdev", vdev_id); + continue; + } + + profile = wlan_mlme_get_ap_policy(sap_vdev); + wlan_objmgr_vdev_release_ref(sap_vdev, + WLAN_POLICY_MGR_ID); + switch (ap_type) { + case LL_AP_TYPE_HT: + if (profile == HOST_CONCURRENT_AP_POLICY_XR) + is_ll_sap_present = true; + break; + case LL_AP_TYPE_LT: + if (profile == HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO || + profile == + HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING) + is_ll_sap_present = true; + break; + case LL_AP_TYPE_ANY: + if (profile == HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO || + profile == HOST_CONCURRENT_AP_POLICY_XR || + profile == + HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING) + is_ll_sap_present = true; + break; + default: + break; + } + if (!is_ll_sap_present) + continue; + + policy_mgr_debug("LL SAP %d present with vdev_id %d and freq %d", + ap_type, vdev_id, freq); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return freq; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return 0; +} + +qdf_freq_t policy_mgr_get_ll_sap_freq(struct wlan_objmgr_psoc *psoc) +{ + return _policy_mgr_get_ll_sap_freq(psoc, LL_AP_TYPE_ANY); +} + +qdf_freq_t policy_mgr_get_ll_ht_sap_freq(struct wlan_objmgr_psoc *psoc) +{ + return _policy_mgr_get_ll_sap_freq(psoc, LL_AP_TYPE_HT); +} + +qdf_freq_t policy_mgr_get_ll_lt_sap_freq(struct wlan_objmgr_psoc *psoc) +{ + return _policy_mgr_get_ll_sap_freq(psoc, LL_AP_TYPE_LT); +} + +#ifndef WLAN_FEATURE_LL_LT_SAP +bool policy_mgr_is_ll_sap_concurrency_valid(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, + enum policy_mgr_con_mode mode) +{ + qdf_freq_t ll_sap_freq; + + ll_sap_freq = policy_mgr_get_ll_sap_freq(psoc); + if (!ll_sap_freq) + return true; + + /* + * Scenario: When low latency SAP with 5GHz channel(whose + * profile is set as gaming or lossless audio or XR) is present + * on SBS/DBS hardware and the other interface like + * STA/SAP/GC/GO trying to form connection. + * Allow connection on those freq which are mutually exclusive + * to LL SAP mac + */ + + if (policy_mgr_2_freq_always_on_same_mac(psoc, ll_sap_freq, + freq)) { + policy_mgr_debug("Invalid LL-SAP concurrency for SBS/DBS hw, ll-sap freq %d, conc_freq %d, conc_mode %d", + ll_sap_freq, freq, mode); + return false; + } + + return true; +} +#endif + +bool +policy_mgr_update_indoor_concurrency(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t discon_freq, + enum indoor_conc_update_type type) +{ + uint32_t ch_freq; + enum QDF_OPMODE mode; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum phy_ch_width ch_width = CH_WIDTH_INVALID; + bool indoor_support = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return false; + } + + ucfg_mlme_get_indoor_channel_support(psoc, &indoor_support); + if (indoor_support || + !policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc)) + return false; + + mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + + /** + * DISCONNECT_WITH_CONCURRENCY update comes after SAP/GO CSA. + * Whereas, all other updates come from STA/GC operation. + */ + if (type != DISCONNECT_WITH_CONCURRENCY && + (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE)) { + return false; + } else if (type == DISCONNECT_WITH_CONCURRENCY && + (mode != QDF_SAP_MODE && mode != QDF_P2P_GO_MODE)) { + return false; + } + + switch (type) { + case CONNECT: + case SWITCH_WITHOUT_CONCURRENCY: + case SWITCH_WITH_CONCURRENCY: + policy_mgr_get_chan_by_session_id(psoc, vdev_id, &ch_freq); + ch_width = policy_mgr_get_bw_by_session_id(psoc, vdev_id); + break; + case DISCONNECT_WITHOUT_CONCURRENCY: + case DISCONNECT_WITH_CONCURRENCY: + ch_freq = discon_freq; + break; + default: + return false; + } + + if (type != SWITCH_WITHOUT_CONCURRENCY && + !(WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && + wlan_reg_is_freq_indoor(pm_ctx->pdev, ch_freq))) { + return false; + } else if (type == SWITCH_WITHOUT_CONCURRENCY) { + /* Either the previous frequency or the current + * frequency can be indoor. Or both can be indoor. + * Therefore, atleast one of the frequency must be + * indoor in order to proceed for the update. + */ + if (!((WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && + wlan_reg_is_freq_indoor(pm_ctx->pdev, ch_freq)) || + (WLAN_REG_IS_5GHZ_CH_FREQ(discon_freq) && + wlan_reg_is_freq_indoor(pm_ctx->pdev, discon_freq)))) + return false; + } + + switch (type) { + case CONNECT: + wlan_reg_modify_indoor_concurrency(pm_ctx->pdev, vdev_id, + ch_freq, ch_width, true); + break; + case DISCONNECT_WITHOUT_CONCURRENCY: + wlan_reg_modify_indoor_concurrency(pm_ctx->pdev, vdev_id, + 0, CH_WIDTH_INVALID, false); + break; + case SWITCH_WITHOUT_CONCURRENCY: + wlan_reg_modify_indoor_concurrency(pm_ctx->pdev, vdev_id, 0, + CH_WIDTH_INVALID, false); + if (wlan_reg_is_freq_indoor(pm_ctx->pdev, ch_freq)) + wlan_reg_modify_indoor_concurrency(pm_ctx->pdev, + vdev_id, ch_freq, + ch_width, true); + break; + case DISCONNECT_WITH_CONCURRENCY: + /*If there are other sessions, do not change current chan list*/ + if (policy_mgr_get_connection_count_with_ch_freq(ch_freq) > 1) + return false; + wlan_reg_modify_indoor_concurrency(pm_ctx->pdev, + INVALID_VDEV_ID, ch_freq, + CH_WIDTH_INVALID, false); + break; + case SWITCH_WITH_CONCURRENCY: + wlan_reg_modify_indoor_concurrency(pm_ctx->pdev, vdev_id, + ch_freq, ch_width, true); + /* + * The previous frequency removal and current channel list + * recomputation will happen after SAP CSA + */ + return false; + } + return true; +} + +bool policy_mgr_is_conc_sap_present_on_sta_freq(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t i; + bool sap_go_exists = false; + enum policy_mgr_con_mode cmode; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return false; + } + + if (mode != PM_STA_MODE && mode != PM_P2P_CLIENT_MODE) + return false; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + cmode = pm_conc_connection_list[i].mode; + if (pm_conc_connection_list[i].in_use && + ch_freq == pm_conc_connection_list[i].freq && + (cmode == PM_SAP_MODE || cmode == PM_P2P_GO_MODE)) { + sap_go_exists = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return sap_go_exists; +} + +bool policy_mgr_is_sap_mode(enum policy_mgr_con_mode mode) +{ + if (mode == PM_SAP_MODE || mode == PM_LL_LT_SAP_MODE) + return true; + + return false; +} + +bool policy_mgr_is_beaconing_mode(enum policy_mgr_con_mode mode) +{ + if (mode == PM_SAP_MODE || mode == PM_LL_LT_SAP_MODE || + mode == PM_P2P_GO_MODE) + return true; + + return false; +} + +bool policy_mgr_get_nan_sap_scc_on_lte_coex_chnl(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return 0; + } + return pm_ctx->cfg.nan_sap_scc_on_lte_coex_chnl; +} + +QDF_STATUS +policy_mgr_reset_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->sap_mandatory_channels_len = 0; + qdf_mem_zero(pm_ctx->sap_mandatory_channels, + QDF_ARRAY_SIZE(pm_ctx->sap_mandatory_channels) * + sizeof(*pm_ctx->sap_mandatory_channels)); + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_freq_on_mac_id(struct policy_mgr_freq_range *freq_range, + qdf_freq_t freq, uint8_t mac_id) +{ + return IS_FREQ_ON_MAC_ID(freq_range, freq, mac_id); +} + +bool policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool match = false; + uint32_t i; + + pm_ctx = policy_mgr_get_context(psoc); + if (qdf_unlikely(!pm_ctx)) { + policy_mgr_err("Invalid pm_ctx"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use && + pm_conc_connection_list[i].freq == new_freq) { + match = true; + *vdev_id = pm_conc_connection_list[i].vdev_id; + policy_mgr_debug("new_freq %d matched with vdev_id %d", + new_freq, *vdev_id); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return match; +} + +bool policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool match = false; + uint32_t i; + + pm_ctx = policy_mgr_get_context(psoc); + if (qdf_unlikely(!pm_ctx)) { + policy_mgr_err("Invalid pm_ctx"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use && + pm_conc_connection_list[i].freq != new_freq) { + match = true; + *vdev_id = pm_conc_connection_list[i].vdev_id; + policy_mgr_debug("new_freq %d matched with vdev_id %d", + new_freq, *vdev_id); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return match; +} + +enum hw_mode_bandwidth +policy_mgr_get_connection_max_channel_width(struct wlan_objmgr_psoc *psoc) +{ + enum hw_mode_bandwidth bw = HW_MODE_20_MHZ; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return HW_MODE_20_MHZ; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].in_use && + pm_conc_connection_list[conn_index].bw > bw) + bw = pm_conc_connection_list[conn_index].bw; + } + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return bw; +} + +bool policy_mgr_is_given_freq_5g_low(struct wlan_objmgr_psoc *psoc, + qdf_freq_t given_freq) +{ + qdf_freq_t sbs_cut_off_freq; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + if (!sbs_cut_off_freq) + return false; + + if (given_freq < sbs_cut_off_freq && + WLAN_REG_IS_5GHZ_CH_FREQ(given_freq)) + return true; + + return false; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h new file mode 100644 index 0000000000..ad2fee9882 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_i.h @@ -0,0 +1,1214 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_POLICY_MGR_I_H +#define WLAN_POLICY_MGR_I_H + +#include "wlan_policy_mgr_api.h" +#include "qdf_event.h" +#include "qdf_mc_timer.h" +#include "qdf_lock.h" +#include "qdf_defer.h" +#include "wlan_reg_services_api.h" +#include "cds_ieee80211_common_i.h" +#include "qdf_delayed_work.h" +#define DBS_OPPORTUNISTIC_TIME 5 + +#define POLICY_MGR_SER_CMD_TIMEOUT 4000 + +#ifdef QCA_WIFI_3_0_EMU +#define CONNECTION_UPDATE_TIMEOUT (POLICY_MGR_SER_CMD_TIMEOUT + 3000) +#else +#define CONNECTION_UPDATE_TIMEOUT (POLICY_MGR_SER_CMD_TIMEOUT + 2000) +#endif + +#define PM_24_GHZ_CH_FREQ_6 (2437) +#define PM_5_GHZ_CH_FREQ_36 (5180) +#define CHANNEL_SWITCH_COMPLETE_TIMEOUT (2000) +#define MAX_NOA_TIME (3000) + +/* Defer SAP force SCC check by 2000ms due to another SAP/GO start AP in + * progress + */ +#define SAP_CONC_CHECK_DEFER_TIMEOUT_MS (2000) + +/* + * Policy Mgr hardware mode list bit-mask definitions. + * Bits 4:0, 31:29 are unused. + * + * The below definitions are added corresponding to WMI DBS HW mode + * list to make it independent of firmware changes for WMI definitions. + * Currently these definitions have dependency with BIT positions of + * the existing WMI macros. Thus, if the BIT positions are changed for + * WMI macros, then these macros' BIT definitions are also need to be + * changed. + */ +#define POLICY_MGR_HW_MODE_EMLSR_MODE_BITPOS (32) +#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS (28) +#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS (24) +#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS (20) +#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS (16) +#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS (12) +#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS (8) +#define POLICY_MGR_HW_MODE_DBS_MODE_BITPOS (7) +#define POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS (6) +#define POLICY_MGR_HW_MODE_SBS_MODE_BITPOS (5) +#define POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS (3) +#define POLICY_MGR_HW_MODE_ID_BITPOS (0) + +#define POLICY_MGR_HW_MODE_EMLSR_MODE_MASK \ + (0x1 << POLICY_MGR_HW_MODE_EMLSR_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_MASK \ + (0xf << POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_MASK \ + (0xf << POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_MASK \ + (0xf << POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_MASK \ + (0xf << POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_MASK \ + (0xf << POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_MASK \ + (0xf << POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define POLICY_MGR_HW_MODE_DBS_MODE_MASK \ + (0x1 << POLICY_MGR_HW_MODE_DBS_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_AGILE_DFS_MODE_MASK \ + (0x1 << POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_SBS_MODE_MASK \ + (0x1 << POLICY_MGR_HW_MODE_SBS_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_BAND_MASK \ + (0x3 << POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS) +#define POLICY_MGR_HW_MODE_ID_MASK \ + (0x7 << POLICY_MGR_HW_MODE_ID_BITPOS) + +#define POLICY_MGR_HW_MODE_EMLSR_MODE_SET(hw_mode, tmp, value) \ + QDF_SET_BITS64(hw_mode, tmp, POLICY_MGR_HW_MODE_EMLSR_MODE_BITPOS,\ + 1, value) +#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS,\ + 4, value) +#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS,\ + 4, value) +#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS,\ + 4, value) +#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS,\ + 4, value) +#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS,\ + 4, value) +#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS,\ + 4, value) +#define POLICY_MGR_HW_MODE_DBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_DBS_MODE_BITPOS,\ + 1, value) +#define POLICY_MGR_HW_MODE_AGILE_DFS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS,\ + 1, value) +#define POLICY_MGR_HW_MODE_SBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_SBS_MODE_BITPOS,\ + 1, value) +#define POLICY_MGR_HW_MODE_MAC0_BAND_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS,\ + 2, value) +#define POLICY_MGR_HW_MODE_ID_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, POLICY_MGR_HW_MODE_ID_BITPOS,\ + 3, value) + +#define POLICY_MGR_HW_MODE_EMLSR_MODE_GET(hw_mode) \ + QDF_GET_BITS64(hw_mode, POLICY_MGR_HW_MODE_EMLSR_MODE_BITPOS,\ + 1) +#define POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_MASK) >> \ + POLICY_MGR_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_MASK) >> \ + POLICY_MGR_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_MASK) >> \ + POLICY_MGR_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_MASK) >> \ + POLICY_MGR_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_MASK) >> \ + POLICY_MGR_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_MASK) >> \ + POLICY_MGR_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define POLICY_MGR_HW_MODE_DBS_MODE_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_DBS_MODE_MASK) >> \ + POLICY_MGR_HW_MODE_DBS_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_AGILE_DFS_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_AGILE_DFS_MODE_MASK) >> \ + POLICY_MGR_HW_MODE_AGILE_DFS_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_SBS_MODE_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_SBS_MODE_MASK) >> \ + POLICY_MGR_HW_MODE_SBS_MODE_BITPOS) +#define POLICY_MGR_HW_MODE_MAC0_BAND_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_MAC0_BAND_MASK) >> \ + POLICY_MGR_HW_MODE_MAC0_BAND_BITPOS) +#define POLICY_MGR_HW_MODE_ID_GET(hw_mode) \ + (((hw_mode) & POLICY_MGR_HW_MODE_ID_MASK) >> \ + POLICY_MGR_HW_MODE_ID_BITPOS) + +#define POLICY_MGR_DEFAULT_HW_MODE_INDEX 0xFFFF + +#define policy_mgr_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_POLICY_MGR, params) +#define policy_mgr_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_POLICY_MGR, params) +#define policy_mgr_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_POLICY_MGR, params) +#define policy_mgr_notice(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_POLICY_MGR, params) +#define policy_mgr_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_POLICY_MGR, params) +#define policy_mgr_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_POLICY_MGR, params) + +#define policymgr_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_POLICY_MGR, params) +#define policymgr_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_POLICY_MGR, params) +#define policymgr_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_POLICY_MGR, params) +#define policymgr_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_POLICY_MGR, params) +#define policymgr_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_POLICY_MGR, params) + +#define policy_mgr_rl_debug(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_POLICY_MGR, params) + +#define PM_CONC_CONNECTION_LIST_VALID_INDEX(index) \ + ((MAX_NUMBER_OF_CONC_CONNECTIONS > index) && \ + (pm_conc_connection_list[index].in_use)) + +extern struct policy_mgr_conc_connection_info + pm_conc_connection_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + +#ifdef WLAN_FEATURE_11BE_MLO +extern struct policy_mgr_disabled_ml_link_info + pm_disabled_ml_links[MAX_NUMBER_OF_DISABLE_LINK]; +#endif + +extern const enum policy_mgr_pcl_type + first_connection_pcl_table[PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE]; +extern pm_dbs_pcl_second_connection_table_type + *second_connection_pcl_dbs_table; + +extern enum policy_mgr_pcl_type const + (*second_connection_pcl_non_dbs_table)[PM_MAX_ONE_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE]; +extern pm_dbs_pcl_third_connection_table_type + *third_connection_pcl_dbs_table; +extern enum policy_mgr_pcl_type const + (*third_connection_pcl_non_dbs_table)[PM_MAX_TWO_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE]; + +extern policy_mgr_next_action_two_connection_table_type + *next_action_two_connection_table; +extern policy_mgr_next_action_three_connection_table_type + *next_action_three_connection_table; + +#ifdef FEATURE_FOURTH_CONNECTION +extern const enum policy_mgr_pcl_type + fourth_connection_pcl_dbs_sbs_table + [PM_MAX_THREE_CONNECTION_MODE][PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE]; +#endif + +extern policy_mgr_next_action_two_connection_table_type + *next_action_two_connection_2x2_2g_1x1_5g_table; +extern policy_mgr_next_action_three_connection_table_type + *next_action_three_connection_2x2_2g_1x1_5g_table; + +extern enum policy_mgr_conc_next_action + (*policy_mgr_get_current_pref_hw_mode_ptr) + (struct wlan_objmgr_psoc *psoc); + +/** + * struct policy_mgr_cfg - all the policy manager owned configs + * @mcc_to_scc_switch: switch to indicate MCC to SCC config + * @sys_pref: system's preference while selecting PCLs + * @max_conc_cxns: Max allowed concurrenct active connections + * @conc_rule1: concurrency rule1 + * @conc_rule2: concurrency rule2 + * @allow_mcc_go_diff_bi: Allow GO and STA diff beacon interval in MCC + * @dual_mac_feature: To enable/disable dual mac features + * @is_force_1x1_enable: Is 1x1 forced for connection + * @sta_sap_scc_on_dfs_chnl: STA-SAP SCC on DFS channel + * @sta_sap_scc_on_lte_coex_chnl: STA-SAP SCC on LTE Co-ex channel + * @sta_sap_scc_on_indoor_channel: Allow STA-SAP scc on indoor only + * channels + * @nan_sap_scc_on_lte_coex_chnl: NAN-SAP SCC on LTE Co-ex channel + * @sap_mandatory_chnl_enable: To enable/disable SAP mandatory channels + * @mark_indoor_chnl_disable: Mark indoor channel as disable or enable + * @dbs_selection_plcy: DBS selection policy for concurrency + * @vdev_priority_list: Priority list for various vdevs + * @chnl_select_plcy: Channel selection policy + * @enable_mcc_adaptive_sch: Enable/Disable MCC adaptive scheduler + * @enable_sta_cxn_5g_band: Enable/Disable STA connection in 5G band + * @go_force_scc: Enable/Disable P2P GO force SCC + * @pcl_band_priority: PCL channel order between 5G and 6G. + * @sbs_enable: To enable/disable SBS + * @multi_sap_allowed_on_same_band: Enable/Disable multi sap started + * on same band + * @sr_in_same_mac_conc: Enable/Disable SR in same MAC concurrency + * @use_sap_original_bw: Enable/Disable sap original BW as default + * BW when do restart + * @move_sap_go_1st_on_dfs_sta_csa: Enable/Disable SAP / GO's movement + * to non-DFS channel before STA + */ +struct policy_mgr_cfg { + uint8_t mcc_to_scc_switch; + uint8_t sys_pref; + uint8_t max_conc_cxns; + uint8_t conc_rule1; + uint8_t conc_rule2; + bool enable_mcc_adaptive_sch; + uint8_t allow_mcc_go_diff_bi; + uint8_t dual_mac_feature; + enum force_1x1_type is_force_1x1_enable; + uint8_t sta_sap_scc_on_dfs_chnl; + uint8_t sta_sap_scc_on_lte_coex_chnl; + bool sta_sap_scc_on_indoor_channel; + uint8_t nan_sap_scc_on_lte_coex_chnl; + uint8_t sap_mandatory_chnl_enable; + uint8_t mark_indoor_chnl_disable; + uint8_t enable_sta_cxn_5g_band; + uint32_t dbs_selection_plcy; + uint32_t vdev_priority_list; + uint32_t chnl_select_plcy; + uint8_t go_force_scc; + enum policy_mgr_pcl_band_priority pcl_band_priority; + bool sbs_enable; + bool multi_sap_allowed_on_same_band; +#ifdef WLAN_FEATURE_SR + bool sr_in_same_mac_conc; +#endif + bool use_sap_original_bw; + bool move_sap_go_1st_on_dfs_sta_csa; +}; + +/** + * struct policy_mgr_psoc_priv_obj - Policy manager private data + * @psoc: pointer to PSOC object information + * @pdev: pointer to PDEV object information + * @connection_update_done_evt: qdf event to synchronize + * connection activities + * @qdf_conc_list_lock: To protect connection table + * @dbs_opportunistic_timer: Timer to drop down to Single Mac + * Mode opportunistically + * @sap_restart_chan_switch_cb: Callback for channel switch + * notification for SAP + * @hdd_cbacks: callbacks to be registered by HDD for + * interaction with Policy Manager + * @sme_cbacks: callbacks to be registered by SME for + * interaction with Policy Manager + * @wma_cbacks: callbacks to be registered by SME for + * interaction with Policy Manager + * @tdls_cbacks: callbacks to be registered by SME for + * interaction with Policy Manager + * @cdp_cbacks: callbacks to be registered by SME for + * interaction with Policy Manager + * @dp_cbacks: callbacks to be registered by Datapath for + * interaction with Policy Manager + * @conc_cbacks: callbacks to be registered by lim for + * interaction with Policy Manager + * @sap_mandatory_channels: The user preferred master list on + * which SAP can be brought up. This + * mandatory channel freq list would be as per + * OEMs preference & conforming to the + * regulatory/other considerations + * @sap_mandatory_channels_len: Length of the SAP mandatory + * channel list + * @do_sap_unsafe_ch_check: whether need check sap unsafe channel + * @last_disconn_sta_freq: last disconnected sta channel freq + * @concurrency_mode: active concurrency combination + * @no_of_open_sessions: Number of active vdevs + * @no_of_active_sessions: Number of active connections + * @sta_ap_intf_check_work: delayed sap restart work + * @work_fail_count: sta_ap work schedule fail count + * @nan_sap_conc_work: Info related to nan sap conc work + * @num_dbs_hw_modes: Number of different HW modes supported + * @hw_mode: List of HW modes supported + * @old_hw_mode_index: Old HW mode from hw_mode table + * @new_hw_mode_index: New HW mode from hw_mode table + * @dual_mac_cfg: DBS configuration currently used by FW for + * scan & connections + * @radio_comb_num: radio combination number + * @radio_combinations: radio combination list + * @hw_mode_change_in_progress: This is to track if HW mode + * change is in progress + * @enable_mcc_adaptive_scheduler: Enable MCC adaptive scheduler + * value from INI + * @user_cfg: + * @unsafe_channel_list: LTE coex channel freq avoidance list + * @unsafe_channel_count: LTE coex channel avoidance list count + * @sta_ap_intf_check_work_info: Info related to sta_ap_intf_check_work + * @cur_conc_system_pref: + * @opportunistic_update_done_evt: qdf event to synchronize host + * & FW HW mode + * @channel_switch_complete_evt: qdf event for channel switch completion check + * @mode_change_cb: Mode change callback + * @cfg: Policy manager config data + * @valid_ch_freq_list: valid frequencies + * @valid_ch_freq_list_count: number of valid frequencies + * @dynamic_mcc_adaptive_sched: disable/enable mcc adaptive scheduler feature + * @dynamic_dfs_master_disabled: current state of dynamic dfs master + * @link_in_progress: To track if set link is in progress + * @set_link_update_done_evt: qdf event to synchronize set link + * @active_vdev_bitmap: Active vdev id bitmap + * @inactive_vdev_bitmap: Inactive vdev id bitmap + * @restriction_mask: + */ +struct policy_mgr_psoc_priv_obj { + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + qdf_event_t connection_update_done_evt; + qdf_mutex_t qdf_conc_list_lock; + qdf_mc_timer_t dbs_opportunistic_timer; + struct policy_mgr_hdd_cbacks hdd_cbacks; + struct policy_mgr_sme_cbacks sme_cbacks; + struct policy_mgr_wma_cbacks wma_cbacks; + struct policy_mgr_tdls_cbacks tdls_cbacks; + struct policy_mgr_cdp_cbacks cdp_cbacks; + struct policy_mgr_dp_cbacks dp_cbacks; + struct policy_mgr_conc_cbacks conc_cbacks; + uint32_t sap_mandatory_channels[NUM_CHANNELS]; + uint32_t sap_mandatory_channels_len; + qdf_freq_t last_disconn_sta_freq; + uint32_t concurrency_mode; + uint8_t no_of_open_sessions[QDF_MAX_NO_OF_MODE]; + uint8_t no_of_active_sessions[QDF_MAX_NO_OF_MODE]; + struct qdf_delayed_work sta_ap_intf_check_work; + uint8_t work_fail_count; + qdf_work_t nan_sap_conc_work; + uint32_t num_dbs_hw_modes; + struct dbs_hw_mode_info hw_mode; + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + struct dual_mac_config dual_mac_cfg; + uint32_t radio_comb_num; + struct radio_combination radio_combinations[MAX_RADIO_COMBINATION]; + uint32_t hw_mode_change_in_progress; + struct policy_mgr_user_cfg user_cfg; + uint32_t unsafe_channel_list[NUM_CHANNELS]; + uint16_t unsafe_channel_count; + struct sta_ap_intf_check_work_ctx *sta_ap_intf_check_work_info; + uint8_t cur_conc_system_pref; + qdf_event_t opportunistic_update_done_evt; + qdf_event_t channel_switch_complete_evt; + send_mode_change_event_cb mode_change_cb; + struct policy_mgr_cfg cfg; + uint32_t valid_ch_freq_list[NUM_CHANNELS]; + uint32_t valid_ch_freq_list_count; + bool dynamic_mcc_adaptive_sched; + bool dynamic_dfs_master_disabled; +#ifdef WLAN_FEATURE_11BE_MLO + qdf_atomic_t link_in_progress; + qdf_event_t set_link_update_done_evt; +#endif + uint32_t active_vdev_bitmap; + uint32_t inactive_vdev_bitmap; +#ifdef FEATURE_WLAN_CH_AVOID_EXT + uint32_t restriction_mask; +#endif +}; + +/** + * struct policy_mgr_mac_ss_bw_info - hw_mode_list PHY/MAC params for each MAC + * @mac_tx_stream: Max TX stream number supported on MAC + * @mac_rx_stream: Max RX stream number supported on MAC + * @mac_bw: Max bandwidth(wmi_channel_width enum type) + * @mac_band_cap: supported Band bit map(WLAN_2G_CAPABILITY = 0x1, + * WLAN_5G_CAPABILITY = 0x2) + * @support_6ghz_band: support 6 GHz band + */ +struct policy_mgr_mac_ss_bw_info { + uint32_t mac_tx_stream; + uint32_t mac_rx_stream; + uint32_t mac_bw; + uint32_t mac_band_cap; + bool support_6ghz_band; +}; + +#ifdef WLAN_FEATURE_SR +/** + * policy_mgr_get_same_mac_conc_sr_status() - Function returns value of INI + * g_enable_sr_in_same_mac_conc + * + * @psoc: Pointer to PSOC + * + * Return: Returns True / False + */ +bool policy_mgr_get_same_mac_conc_sr_status(struct wlan_objmgr_psoc *psoc); + +#else +static inline +bool policy_mgr_get_same_mac_conc_sr_status(struct wlan_objmgr_psoc *psoc) +{ + return true; +} +#endif + +struct policy_mgr_psoc_priv_obj *policy_mgr_get_context( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_updated_scan_config() - Get the updated scan configuration + * @psoc: psoc handle + * @scan_config: Pointer containing the updated scan config + * @dbs_scan: 0 or 1 indicating if DBS scan needs to be enabled/disabled + * @dbs_plus_agile_scan: 0 or 1 indicating if DBS plus agile scan needs to be + * enabled/disabled + * @single_mac_scan_with_dfs: 0 or 1 indicating if single MAC scan with DFS + * needs to be enabled/disabled + * + * Takes the current scan configuration and set the necessary scan config + * bits to either 0/1 and provides the updated value to the caller who + * can use this to pass it on to the FW + * + * Return: 0 on success + */ +QDF_STATUS policy_mgr_get_updated_scan_config( + struct wlan_objmgr_psoc *psoc, + uint32_t *scan_config, + bool dbs_scan, + bool dbs_plus_agile_scan, + bool single_mac_scan_with_dfs); + +/** + * policy_mgr_get_updated_fw_mode_config() - Get the updated fw + * mode configuration + * @psoc: psoc handle + * @fw_mode_config: Pointer containing the updated fw mode config + * @dbs: 0 or 1 indicating if DBS needs to be enabled/disabled + * @agile_dfs: 0 or 1 indicating if agile DFS needs to be enabled/disabled + * + * Takes the current fw mode configuration and set the necessary fw mode config + * bits to either 0/1 and provides the updated value to the caller who + * can use this to pass it on to the FW + * + * Return: 0 on success + */ +QDF_STATUS policy_mgr_get_updated_fw_mode_config( + struct wlan_objmgr_psoc *psoc, + uint32_t *fw_mode_config, + bool dbs, + bool agile_dfs); + +/** + * policy_mgr_is_dual_mac_disabled_in_ini() - Check if dual mac + * is disabled in INI + * @psoc: psoc handle + * + * Checks if the dual mac feature is disabled in INI + * + * Return: true if the dual mac connection is disabled from INI + */ +bool policy_mgr_is_dual_mac_disabled_in_ini( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_find_if_hwlist_has_dbs() - Find if hw list has DBS modes or not + * @psoc: PSOC object information + * + * Find if hw list has DBS modes or not + * + * Return: true or false + */ +bool policy_mgr_find_if_hwlist_has_dbs(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_mcc_to_scc_switch_mode() - MCC to SCC + * switch mode value in the user config + * @psoc: PSOC object information + * + * MCC to SCC switch mode value in user config + * + * Return: MCC to SCC switch mode value + */ +uint32_t policy_mgr_get_mcc_to_scc_switch_mode( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_dbs_config() - Get DBS bit + * @psoc: psoc handle + * + * Gets the DBS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the DBS bit + */ +bool policy_mgr_get_dbs_config(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_agile_dfs_config() - Get Agile DFS bit + * @psoc: psoc handle + * + * Gets the Agile DFS bit of fw_mode_config_bits + * + * Return: 0 or 1 to indicate the Agile DFS bit + */ +bool policy_mgr_get_agile_dfs_config(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_dbs_scan_config() - Get DBS scan bit + * @psoc: psoc handle + * + * Gets the DBS scan bit of concurrent_scan_config_bits + * + * Return: 0 or 1 to indicate the DBS scan bit + */ +bool policy_mgr_get_dbs_scan_config(struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_tx_rx_ss_from_config() - Get Tx/Rx spatial + * stream from HW mode config + * @mac_ss: Config which indicates the HW mode as per 'hw_mode_ss_config' + * @tx_ss: Contains the Tx spatial stream + * @rx_ss: Contains the Rx spatial stream + * + * Returns the number of spatial streams of Tx and Rx + * + * Return: None + */ +void policy_mgr_get_tx_rx_ss_from_config(enum hw_mode_ss_config mac_ss, + uint32_t *tx_ss, uint32_t *rx_ss); + +/** + * policy_mgr_get_matching_hw_mode_index() - Get matching HW mode index + * @psoc: psoc handle + * @mac0_tx_ss: Number of tx spatial streams of MAC0 + * @mac0_rx_ss: Number of rx spatial streams of MAC0 + * @mac0_bw: Bandwidth of MAC0 of type 'hw_mode_bandwidth' + * @mac1_tx_ss: Number of tx spatial streams of MAC1 + * @mac1_rx_ss: Number of rx spatial streams of MAC1 + * @mac1_bw: Bandwidth of MAC1 of type 'hw_mode_bandwidth' + * @mac0_band_cap: mac0 band capability requirement + * (0: Don't care, 1: 2.4G, 2: 5G) + * @dbs: DBS capability of type 'hw_mode_dbs_capab' + * @dfs: Agile DFS capability of type 'hw_mode_agile_dfs_capab' + * @sbs: SBS capability of type 'hw_mode_sbs_capab' + * + * Fetches the HW mode index corresponding to the HW mode provided. + * In Genoa two DBS HW modes (2x2 5G + 1x1 2G, 2x2 2G + 1x1 5G), + * the "ss" number and "bw" value are not enough to specify the expected + * HW mode. But in both HW mode, the mac0 can support either 5G or 2G. + * So, the Parameter "mac0_band_cap" will specify the expected band support + * requirement on mac 0 to find the expected HW mode. + * + * Return: Positive hw mode index in case a match is found or a negative + * value, otherwise + */ +int8_t policy_mgr_get_matching_hw_mode_index( + struct wlan_objmgr_psoc *psoc, + uint32_t mac0_tx_ss, uint32_t mac0_rx_ss, + enum hw_mode_bandwidth mac0_bw, + uint32_t mac1_tx_ss, uint32_t mac1_rx_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_mac_band_cap mac0_band_cap, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs); + +/** + * policy_mgr_get_hw_mode_idx_from_dbs_hw_list() - Get hw_mode index + * @psoc: psoc handle + * @mac0_ss: MAC0 spatial stream configuration + * @mac0_bw: MAC0 bandwidth configuration + * @mac1_ss: MAC1 spatial stream configuration + * @mac1_bw: MAC1 bandwidth configuration + * @mac0_band_cap: mac0 band capability requirement + * (0: Don't care, 1: 2.4G, 2: 5G) + * @dbs: HW DBS capability + * @dfs: HW Agile DFS capability + * @sbs: HW SBS capability + * + * Get the HW mode index corresponding to the HW modes spatial stream, + * bandwidth, DBS, Agile DFS and SBS capability + * + * In Genoa two DBS HW modes (2x2 5G + 1x1 2G, 2x2 2G + 1x1 5G), + * the "ss" number and "bw" value are not enough to specify the expected + * HW mode. But in both HW mode, the mac0 can support either 5G or 2G. + * So, the Parameter "mac0_band_cap" will specify the expected band support + * requirement on mac 0 to find the expected HW mode. + * + * Return: Index number if a match is found or -negative value if not found + */ +int8_t policy_mgr_get_hw_mode_idx_from_dbs_hw_list( + struct wlan_objmgr_psoc *psoc, + enum hw_mode_ss_config mac0_ss, + enum hw_mode_bandwidth mac0_bw, + enum hw_mode_ss_config mac1_ss, + enum hw_mode_bandwidth mac1_bw, + enum hw_mode_mac_band_cap mac0_band_cap, + enum hw_mode_dbs_capab dbs, + enum hw_mode_agile_dfs_capab dfs, + enum hw_mode_sbs_capab sbs); + +/** + * policy_mgr_get_old_and_new_hw_index() - Get the old and new HW index + * @psoc: psoc handle + * @old_hw_mode_index: Value at this pointer contains the old HW mode index + * Default value when not configured is POLICY_MGR_DEFAULT_HW_MODE_INDEX + * @new_hw_mode_index: Value at this pointer contains the new HW mode index + * Default value when not configured is POLICY_MGR_DEFAULT_HW_MODE_INDEX + * + * Get the old and new HW index configured in the driver + * + * Return: Failure in case the HW mode indices cannot be fetched and Success + * otherwise. When no HW mode transition has happened the values of + * old_hw_mode_index and new_hw_mode_index will be the same. + */ +QDF_STATUS policy_mgr_get_old_and_new_hw_index( + struct wlan_objmgr_psoc *psoc, + uint32_t *old_hw_mode_index, + uint32_t *new_hw_mode_index); + +/** + * policy_mgr_update_conc_list() - Update the concurrent connection list + * @psoc: PSOC object information + * @conn_index: Connection index + * @mode: Mode + * @freq: channel frequency + * @bw: Bandwidth + * @mac: Mac id + * @chain_mask: Chain mask + * @original_nss: Original number of spatial streams + * @vdev_id: vdev id + * @in_use: Flag to indicate if the index is in use or not + * @update_conn: Flag to indicate if mode change event should + * be sent or not + * @ch_flagext: channel state flags + * + * Updates the index value of the concurrent connection list + * + * Return: None + */ +void policy_mgr_update_conc_list(struct wlan_objmgr_psoc *psoc, + uint32_t conn_index, + enum policy_mgr_con_mode mode, + uint32_t freq, + enum hw_mode_bandwidth bw, + uint8_t mac, + enum policy_mgr_chain_mode chain_mask, + uint32_t original_nss, + uint32_t vdev_id, + bool in_use, + bool update_conn, + uint16_t ch_flagext); + +void policy_mgr_store_and_del_conn_info(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + bool all_matching_cxn_to_del, + struct policy_mgr_conc_connection_info *info, + uint8_t *num_cxn_del); + +/** + * policy_mgr_store_and_del_conn_info_by_vdev_id() - Store and del a + * connection info by vdev id + * @psoc: PSOC object information + * @vdev_id: vdev id whose entry has to be deleted + * @info: structure array pointer where the connection info will be saved + * @num_cxn_del: number of connection which are going to be deleted + * + * Saves the connection info corresponding to the provided mode + * and deleted that corresponding entry based on vdev from the + * connection info structure + * + * Return: None + */ +void policy_mgr_store_and_del_conn_info_by_vdev_id( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + struct policy_mgr_conc_connection_info *info, + uint8_t *num_cxn_del); + +/** + * policy_mgr_store_and_del_conn_info_by_chan_and_mode() - Store and del a + * connection info by chan number and conn mode + * @psoc: PSOC object information + * @ch_freq: channel frequency value + * @mode: conn mode + * @info: structure array pointer where the connection info will be saved + * @num_cxn_del: number of connection which are going to be deleted + * + * Saves and deletes the entries if the active connection entry chan and mode + * matches the provided chan & mode from the function parameters. + * + * Return: None + */ +void policy_mgr_store_and_del_conn_info_by_chan_and_mode( + struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, + enum policy_mgr_con_mode mode, + struct policy_mgr_conc_connection_info *info, + uint8_t *num_cxn_del); + +void policy_mgr_restore_deleted_conn_info(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_conc_connection_info *info, + uint8_t num_cxn_del); +void policy_mgr_update_hw_mode_conn_info(struct wlan_objmgr_psoc *psoc, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + struct policy_mgr_hw_mode_params hw_mode, + uint32_t num_mac_freq, + struct policy_mgr_pdev_mac_freq_map *freq_info); +void policy_mgr_pdev_set_hw_mode_cb(uint32_t status, + uint32_t cfgd_hw_mode_index, + uint32_t num_vdev_mac_entries, + struct policy_mgr_vdev_mac_map *vdev_mac_map, + uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t session_id, void *context, + uint32_t request_id); + +#ifdef WLAN_FEATURE_11BE_MLO +void +policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_link_switch_notifier_cb() - link switch notifier callback + * @vdev: vdev object + * @req: link switch request + * @notify_reason: Reason for notification + * + * This API will be registered to mlo link switch, to be invoked before + * do link switch process. + * + * Return: QDF_STATUS + */ +QDF_STATUS +policy_mgr_link_switch_notifier_cb(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *req, + enum wlan_mlo_link_switch_notify_reason notify_reason); +#else +static inline void +policy_mgr_dump_disabled_ml_links(struct policy_mgr_psoc_priv_obj *pm_ctx) {} +#endif + +/** + * policy_mgr_dump_current_concurrency() - To dump the current + * concurrency combination + * @psoc: psoc handle + * + * This routine is called to dump the concurrency info + * + * Return: None + */ +void policy_mgr_dump_current_concurrency(struct wlan_objmgr_psoc *psoc); + +void pm_dbs_opportunistic_timer_handler(void *data); + +/** + * policy_mgr_get_channel_list() - Get channel list based on PCL and mode + * @psoc: psoc object + * @pcl: pcl type + * @mode: interface mode + * @pcl_channels: pcl channel list buffer + * @pcl_weights: pcl weight buffer + * @pcl_sz: pcl channel list buffer size + * @len: pcl channel number returned from API + * + * Return: QDF_STATUS + */ +QDF_STATUS policy_mgr_get_channel_list(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_pcl_type pcl, + enum policy_mgr_con_mode mode, + uint32_t *pcl_channels, + uint8_t *pcl_weights, + uint32_t pcl_sz, uint32_t *len); + +/** + * policy_mgr_allow_new_home_channel() - Check for allowed number of + * home channels + * @psoc: PSOC Pointer + * @mode: Connection mode + * @ch_freq: channel frequency on which new connection is coming up + * @num_connections: number of current connections + * @is_dfs_ch: DFS channel or not + * @ext_flags: extended flags for concurrency check + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability + * + * Return: True/False + */ +bool policy_mgr_allow_new_home_channel( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode, + uint32_t ch_freq, uint32_t num_connections, bool is_dfs_ch, + uint32_t ext_flags); + +/** + * policy_mgr_is_5g_channel_allowed() - check if 5g channel is allowed + * @psoc: PSOC object information + * @ch_freq: channel frequency which needs to be validated + * @list: list of existing connections. + * @mode: mode against which channel needs to be validated + * + * This API takes the channel frequency as input and compares with existing + * connection channels. If existing connection's channel is DFS channel + * and provided channel is 5G channel then don't allow concurrency to + * happen as MCC with DFS channel is not yet supported + * + * Return: true if 5G channel is allowed, false if not allowed + * + */ +bool policy_mgr_is_5g_channel_allowed(struct wlan_objmgr_psoc *psoc, + uint32_t ch_freq, uint32_t *list, + enum policy_mgr_con_mode mode); + +/** + * policy_mgr_complete_action() - initiates actions needed on + * current connections once channel has been decided for the new + * connection + * @psoc: PSOC object information + * @new_nss: the new nss value + * @next_action: next action to happen at policy mgr after + * beacon update + * @reason: Reason for connection update + * @session_id: Session id + * @request_id: connection manager req id + * + * This function initiates actions + * needed on current connections once channel has been decided + * for the new connection. Notifies UMAC & FW as well + * + * Return: QDF_STATUS enum + */ +QDF_STATUS policy_mgr_complete_action(struct wlan_objmgr_psoc *psoc, + uint8_t new_nss, uint8_t next_action, + enum policy_mgr_conn_update_reason reason, + uint32_t session_id, uint32_t request_id); + +enum policy_mgr_con_mode policy_mgr_get_mode_by_vdev_id( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +QDF_STATUS policy_mgr_init_connection_update( + struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_get_current_pref_hw_mode_dbs_2x2() - Get the + * current preferred hw mode + * @psoc: psoc handle + * + * Get the preferred hw mode based on the current connection combinations + * + * Return: No change (PM_NOP), MCC (PM_SINGLE_MAC), + * DBS (PM_DBS), SBS (PM_SBS) + */ +enum policy_mgr_conc_next_action + policy_mgr_get_current_pref_hw_mode_dbs_2x2( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_current_pref_hw_mode_dbs_1x1() - Get the + * current preferred hw mode + * @psoc: psoc handle + * + * Get the preferred hw mode based on the current connection combinations + * + * Return: No change (PM_NOP), MCC (PM_SINGLE_MAC_UPGRADE), + * DBS (PM_DBS_DOWNGRADE) + */ +enum policy_mgr_conc_next_action + policy_mgr_get_current_pref_hw_mode_dbs_1x1( + struct wlan_objmgr_psoc *psoc); + +/** + * policy_mgr_get_current_pref_hw_mode_dual_dbs() - Get the + * current preferred hw mode + * @psoc: PSOC object information + * + * Get the preferred hw mode based on the current connection combinations + * + * Return: No change (PM_NOP), (PM_SINGLE_MAC_UPGRADE), + * DBS (PM_DBS1_DOWNGRADE or PM_DBS2_DOWNGRADE) + */ +enum policy_mgr_conc_next_action + policy_mgr_get_current_pref_hw_mode_dual_dbs( + struct wlan_objmgr_psoc *psoc); + +void +policy_mgr_dump_freq_range_per_mac(struct policy_mgr_freq_range *freq_range, + enum policy_mgr_mode hw_mode); + +/** + * policy_mgr_fill_curr_mac_freq_by_hwmode() - Fill Current Mac frequency with + * the frequency range of the given Hw Mode + * + * @pm_ctx: Policy Mgr context + * @mode_hw: Policy Mgr Hw mode + * + * Fill Current Mac frequency with the frequency range of the given Hw Mode + * + * Return: None + */ +void +policy_mgr_fill_curr_mac_freq_by_hwmode(struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_mode mode_hw); + +/** + * policy_mgr_dump_freq_range() - Function to print every frequency range + * for both MAC 0 and MAC1 for every Hw mode + * + * @pm_ctx: Policy Mgr context + * + * This function will print every frequency range + * for both MAC 0 and MAC1 for every Hw mode + * + * Return: void + * + */ +void +policy_mgr_dump_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_dump_sbs_freq_range() - Function to print SBS frequency range + * for both MAC 0 and MAC1 + * + * @pm_ctx: Policy Mgr context + * + * Return: void + */ +void +policy_mgr_dump_sbs_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_dump_curr_freq_range() - Function to print current frequency range + * for both MAC 0 and MAC1 + * + * @pm_ctx: Policy Mgr context + * + * This function will print current frequency range + * for both MAC 0 and MAC1 for every Hw mode + * + * Return: void + * + */ +void +policy_mgr_dump_curr_freq_range(struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_reg_chan_change_callback() - Callback to be + * invoked by regulatory module when valid channel list changes + * @psoc: PSOC object information + * @pdev: PDEV object information + * @chan_list: New channel list + * @avoid_freq_ind: LTE coex avoid channel list + * @arg: Information passed at registration + * + * Get updated channel list from regulatory module + * + * Return: None + */ +void policy_mgr_reg_chan_change_callback(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct regulatory_channel *chan_list, + struct avoid_freq_ind_data *avoid_freq_ind, + void *arg); + +/** + * policy_mgr_update_nss_req() - wrapper API to update nss + * @psoc: psoc object + * @vdev_id: vdev id + * @tx_nss: Tx nss to set + * @rx_nss: Rx nss to set + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS policy_mgr_update_nss_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t tx_nss, + uint8_t rx_nss); + +/** + * policy_mgr_nss_update() - update nss for AP vdev + * @psoc: PSOC object information + * @new_nss: new NSS value + * @next_action: Next action after nss update + * @band: update AP vdev on the Band. + * @reason: action reason + * @original_vdev_id: original request hwmode change vdev id + * @request_id: request id + * + * The function will update AP vdevs on specific band. + * eg. band = POLICY_MGR_ANY will request to update all band (2g and 5g) + * + * Return: QDF_STATUS_SUCCESS, update requested successfully. + */ +QDF_STATUS policy_mgr_nss_update(struct wlan_objmgr_psoc *psoc, + uint8_t new_nss, uint8_t next_action, + enum policy_mgr_band band, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id); + +/** + * policy_mgr_is_concurrency_allowed() - Check for allowed + * concurrency combination + * @psoc: PSOC object information + * @mode: new connection mode + * @ch_freq: channel frequency on which new connection is coming up + * @bw: Bandwidth requested by the connection (optional) + * @ext_flags: extended flags for concurrency check (union conc_ext_flag) + * @pcl: Optional PCL for new connection + * + * When a new connection is about to come up check if current + * concurrency combination including the new connection is + * allowed or not based on the HW capability, but no need to + * invoke get_pcl + * + * Return: True/False + */ +bool policy_mgr_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t ch_freq, + enum hw_mode_bandwidth bw, + uint32_t ext_flags, + struct policy_mgr_pcl_list *pcl); + +/** + * policy_mgr_can_2ghz_share_low_high_5ghz_sbs() - if SBS mode is dynamic where + * 2.4 GHZ can be shared by any of high 5 GHZ or low 5GHZ at a time. + * @pm_ctx: policy mgr psoc priv object + * + * Return: true is sbs is dynamic else false. + */ +bool policy_mgr_can_2ghz_share_low_high_5ghz_sbs( + struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_sbs_24_shared_with_high_5() - if 2.4 GHZ + * can be shared by high 5 GHZ + * + * @pm_ctx: policy mgr psoc priv object + * + * Return: true if 2.4 GHz is shared by high 5 GHZ + */ +bool +policy_mgr_sbs_24_shared_with_high_5(struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_sbs_24_shared_with_low_5() - if 2.4 GHZ + * can be shared by low 5 GHZ + * + * @pm_ctx: policy mgr psoc priv object + * + * Return: true if 2.4 GHz is shared by low 5 GHZ + */ +bool +policy_mgr_sbs_24_shared_with_low_5(struct policy_mgr_psoc_priv_obj *pm_ctx); + +/** + * policy_mgr_2_freq_same_mac_in_dbs() - to check provided frequencies are + * in dbs freq range or not + * + * @pm_ctx: policy mgr psoc priv object + * @freq_1: first frequency + * @freq_2: second frequency + * + * This API is used to check provided frequencies are in dbs freq range or not + * + * Return: true/false. + */ +bool +policy_mgr_2_freq_same_mac_in_dbs(struct policy_mgr_psoc_priv_obj *pm_ctx, + qdf_freq_t freq_1, qdf_freq_t freq_2); + +/** + * policy_mgr_2_freq_same_mac_in_sbs() - to check provided frequencies are + * in sbs freq range or not + * + * @pm_ctx: policy mgr psoc priv object + * @freq_1: first frequency + * @freq_2: second frequency + * + * This API is used to check provided frequencies are in sbs freq range or not + * + * Return: true/false. + */ +bool policy_mgr_2_freq_same_mac_in_sbs(struct policy_mgr_psoc_priv_obj *pm_ctx, + qdf_freq_t freq_1, qdf_freq_t freq_2); + +/** + * policy_mgr_get_connection_for_vdev_id() - provides the + * particular connection with the requested vdev id + * @psoc: PSOC object information + * @vdev_id: vdev id of the connection + * + * This function provides the specific connection with the + * requested vdev id + * + * Return: index in the connection table + */ +uint32_t policy_mgr_get_connection_for_vdev_id(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +/** + * policy_mgr_set_freq_restriction_mask() - fill the restriction_mask + * in pm_ctx + * + * @pm_ctx: policy mgr psoc priv object + * @freq_list: avoid freq indication carries freq/mask/freq count + * + * Return: None + */ +void +policy_mgr_set_freq_restriction_mask(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct ch_avoid_ind_type *freq_list); + +/** + * policy_mgr_get_freq_restriction_mask() - get restriction_mask from + * pm_ctx + * + * @pm_ctx: policy mgr psoc priv object + * + * Return: Restriction mask + */ +uint32_t +policy_mgr_get_freq_restriction_mask(struct policy_mgr_psoc_priv_obj *pm_ctx); +#else +static inline void +policy_mgr_set_freq_restriction_mask(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct ch_avoid_ind_type *freq_list) +{ +} +#endif + +/** + * policy_mgr_get_connection_max_channel_width() - Get max channel width + * among vdevs in use + * @psoc: PSOC object pointer + * + * This function returns max channel width among in-use vdevs + * + * Return: enum hw_mode_bandwidth + */ +enum hw_mode_bandwidth +policy_mgr_get_connection_max_channel_width(struct wlan_objmgr_psoc *psoc); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c new file mode 100644 index 0000000000..118eaeeb7e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c @@ -0,0 +1,989 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_policy_mgr_init_deinit.c + * + * WLAN Concurrenct Connection Management APIs + * + */ + +/* Include files */ + +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_tables_no_dbs_i.h" +#include "wlan_policy_mgr_tables_1x1_dbs_i.h" +#include "wlan_policy_mgr_tables_2x2_dbs_i.h" +#include "wlan_policy_mgr_tables_2x2_5g_1x1_2g.h" +#include "wlan_policy_mgr_tables_2x2_2g_1x1_5g.h" +#include "wlan_policy_mgr_tables_2x2_dbs_sbs_i.h" +#include "wlan_policy_mgr_i.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "wlan_objmgr_global_obj.h" +#include "target_if.h" + +static QDF_STATUS policy_mgr_psoc_obj_create_cb(struct wlan_objmgr_psoc *psoc, + void *data) +{ + struct policy_mgr_psoc_priv_obj *policy_mgr_ctx; + + policy_mgr_ctx = qdf_mem_malloc( + sizeof(struct policy_mgr_psoc_priv_obj)); + if (!policy_mgr_ctx) + return QDF_STATUS_E_FAILURE; + + policy_mgr_ctx->psoc = psoc; + policy_mgr_ctx->old_hw_mode_index = POLICY_MGR_DEFAULT_HW_MODE_INDEX; + policy_mgr_ctx->new_hw_mode_index = POLICY_MGR_DEFAULT_HW_MODE_INDEX; + + wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_ctx, + QDF_STATUS_SUCCESS); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_psoc_obj_destroy_cb(struct wlan_objmgr_psoc *psoc, + void *data) +{ + struct policy_mgr_psoc_priv_obj *policy_mgr_ctx; + + policy_mgr_ctx = policy_mgr_get_context(psoc); + wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_ctx); + qdf_mem_free(policy_mgr_ctx); + + return QDF_STATUS_SUCCESS; +} + +static void policy_mgr_psoc_obj_status_cb(struct wlan_objmgr_psoc *psoc, + void *data, QDF_STATUS status) +{ + return; +} + +static QDF_STATUS policy_mgr_pdev_obj_create_cb(struct wlan_objmgr_pdev *pdev, + void *data) +{ + struct policy_mgr_psoc_priv_obj *policy_mgr_ctx; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + policy_mgr_ctx = policy_mgr_get_context(psoc); + if (!policy_mgr_ctx) { + policy_mgr_err("invalid context"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_ctx->pdev = pdev; + + wlan_reg_register_chan_change_callback(psoc, + policy_mgr_reg_chan_change_callback, NULL); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_pdev_obj_destroy_cb(struct wlan_objmgr_pdev *pdev, + void *data) +{ + struct policy_mgr_psoc_priv_obj *policy_mgr_ctx; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + policy_mgr_ctx = policy_mgr_get_context(psoc); + if (!policy_mgr_ctx) { + policy_mgr_err("invalid context"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_ctx->pdev = NULL; + wlan_reg_unregister_chan_change_callback(psoc, + policy_mgr_reg_chan_change_callback); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_vdev_obj_create_cb(struct wlan_objmgr_vdev *vdev, + void *data) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_vdev_obj_destroy_cb(struct wlan_objmgr_vdev *vdev, + void *data) +{ + return QDF_STATUS_SUCCESS; +} + +static void policy_mgr_vdev_obj_status_cb(struct wlan_objmgr_vdev *vdev, + void *data, QDF_STATUS status) +{ + return; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS policy_mgr_register_link_switch_notifier(void) +{ + QDF_STATUS status; + + status = mlo_mgr_register_link_switch_notifier( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_link_switch_notifier_cb); + if (status == QDF_STATUS_E_NOSUPPORT) { + status = QDF_STATUS_SUCCESS; + policy_mgr_debug("Link switch not supported"); + } else if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register link switch notifier for policy mgr!"); + } + + return status; +} + +static QDF_STATUS policy_mgr_unregister_link_switch_notifier(void) +{ + QDF_STATUS status; + + status = mlo_mgr_unregister_link_switch_notifier( + WLAN_UMAC_COMP_POLICY_MGR); + if (status == QDF_STATUS_E_NOSUPPORT) + status = QDF_STATUS_SUCCESS; + else if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to unregister link switch notifier for policy mgr!"); + + return status; +} +#else +static QDF_STATUS policy_mgr_register_link_switch_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_unregister_link_switch_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS policy_mgr_init(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_create_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register psoc obj create cback"); + goto err_psoc_create; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_destroy_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register psoc obj delete cback"); + goto err_psoc_delete; + } + + status = wlan_objmgr_register_psoc_status_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_status_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register psoc obj status cback"); + goto err_psoc_status; + } + + status = wlan_objmgr_register_pdev_create_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_pdev_obj_create_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register pdev obj create cback"); + goto err_pdev_create; + } + + status = wlan_objmgr_register_pdev_destroy_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_pdev_obj_destroy_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register pdev obj delete cback"); + goto err_pdev_delete; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_create_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register vdev obj create cback"); + goto err_vdev_create; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_destroy_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register vdev obj delete cback"); + goto err_vdev_delete; + } + + status = wlan_objmgr_register_vdev_status_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_status_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register vdev obj status cback"); + goto err_vdev_status; + } + + status = policy_mgr_register_link_switch_notifier(); + if (status != QDF_STATUS_SUCCESS) { + policy_mgr_err("Failed to register link switch cback"); + goto err_link_switch; + } + + policy_mgr_notice("Callbacks registered with obj mgr"); + + return QDF_STATUS_SUCCESS; +err_link_switch: + wlan_objmgr_unregister_vdev_status_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_status_cb, + NULL); +err_vdev_status: + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_destroy_cb, + NULL); +err_vdev_delete: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_create_cb, + NULL); +err_vdev_create: + wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_pdev_obj_destroy_cb, + NULL); +err_pdev_delete: + wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_pdev_obj_create_cb, + NULL); +err_pdev_create: + wlan_objmgr_unregister_psoc_status_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_status_cb, + NULL); +err_psoc_status: + wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_destroy_cb, + NULL); +err_psoc_delete: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_create_cb, + NULL); +err_psoc_create: + return status; +} + +QDF_STATUS policy_mgr_deinit(void) +{ + QDF_STATUS status; + + status = policy_mgr_unregister_link_switch_notifier(); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister link switch cback"); + + status = wlan_objmgr_unregister_psoc_status_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_status_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister psoc obj status cback"); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_destroy_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister psoc obj delete cback"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_psoc_obj_create_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister psoc obj create cback"); + + status = wlan_objmgr_unregister_pdev_destroy_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_pdev_obj_destroy_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister pdev obj delete cback"); + + status = wlan_objmgr_unregister_pdev_create_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_pdev_obj_create_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister pdev obj create cback"); + + status = wlan_objmgr_unregister_vdev_status_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_status_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister vdev obj status cback"); + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_destroy_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister vdev obj delete cback"); + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_POLICY_MGR, + policy_mgr_vdev_obj_create_cb, + NULL); + if (status != QDF_STATUS_SUCCESS) + policy_mgr_err("Failed to deregister vdev obj create cback"); + + policy_mgr_info("deregistered callbacks with obj mgr successfully"); + + return status; +} + +QDF_STATUS policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create( + &pm_ctx->qdf_conc_list_lock))) { + policy_mgr_err("Failed to init qdf_conc_list_lock"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->sta_ap_intf_check_work_info = qdf_mem_malloc( + sizeof(struct sta_ap_intf_check_work_ctx)); + if (!pm_ctx->sta_ap_intf_check_work_info) { + qdf_mutex_destroy(&pm_ctx->qdf_conc_list_lock); + return QDF_STATUS_E_FAILURE; + } + pm_ctx->sta_ap_intf_check_work_info->psoc = psoc; + pm_ctx->sta_ap_intf_check_work_info->go_plus_go_force_scc.vdev_id = + WLAN_UMAC_VDEV_ID_MAX; + pm_ctx->sta_ap_intf_check_work_info->sap_plus_go_force_scc.reason = + CSA_REASON_UNKNOWN; + if (QDF_IS_STATUS_ERROR(qdf_delayed_work_create( + &pm_ctx->sta_ap_intf_check_work, + policy_mgr_check_sta_ap_concurrent_ch_intf, + pm_ctx))) { + policy_mgr_err("Failed to create dealyed work queue"); + qdf_mutex_destroy(&pm_ctx->qdf_conc_list_lock); + qdf_mem_free(pm_ctx->sta_ap_intf_check_work_info); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_destroy( + &pm_ctx->qdf_conc_list_lock))) { + policy_mgr_err("Failed to destroy qdf_conc_list_lock"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + if (pm_ctx->hw_mode.hw_mode_list) { + qdf_mem_free(pm_ctx->hw_mode.hw_mode_list); + pm_ctx->hw_mode.hw_mode_list = NULL; + policy_mgr_debug("HW list is freed"); + } + + if (pm_ctx->sta_ap_intf_check_work_info) { + qdf_delayed_work_destroy(&pm_ctx->sta_ap_intf_check_work); + qdf_mem_free(pm_ctx->sta_ap_intf_check_work_info); + pm_ctx->sta_ap_intf_check_work_info = NULL; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT +static void policy_mgr_init_non_dbs_pcl(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + policy_mgr_debug("Invalid WMI handle"); + return; + } + + if (wmi_service_enabled(wmi_handle, + wmi_service_no_interband_mcc_support) && + !wmi_service_enabled(wmi_handle, + wmi_service_dual_band_simultaneous_support)) { + second_connection_pcl_non_dbs_table = + &second_connection_pcl_nodbs_no_interband_mcc_table; + third_connection_pcl_non_dbs_table = + &third_connection_pcl_nodbs_no_interband_mcc_table; + } else { + second_connection_pcl_non_dbs_table = + &second_connection_pcl_nodbs_table; + third_connection_pcl_non_dbs_table = + &third_connection_pcl_nodbs_table; + } +} +#else +static void policy_mgr_init_non_dbs_pcl(struct wlan_objmgr_psoc *psoc) +{ + second_connection_pcl_non_dbs_table = + &second_connection_pcl_nodbs_table; + third_connection_pcl_non_dbs_table = + &third_connection_pcl_nodbs_table; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static inline void policy_mgr_memzero_disabled_ml_list(void) +{ + qdf_mem_zero(pm_disabled_ml_links, sizeof(pm_disabled_ml_links)); +} + +static QDF_STATUS +policy_mgr_init_ml_link_update(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + QDF_STATUS qdf_status; + + qdf_atomic_init(&pm_ctx->link_in_progress); + qdf_status = qdf_event_create(&pm_ctx->set_link_update_done_evt); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + policy_mgr_err("init event failed for for set_link_update_done_evt"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +policy_mgr_deinit_ml_link_update(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + QDF_STATUS qdf_status; + + qdf_atomic_set(&pm_ctx->link_in_progress, 0); + qdf_status = qdf_event_destroy(&pm_ctx->set_link_update_done_evt); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + policy_mgr_err("deinit event failed for set_link_update_done_evt"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#else +static inline void policy_mgr_memzero_disabled_ml_list(void) {} + +static inline QDF_STATUS +policy_mgr_init_ml_link_update(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +policy_mgr_deinit_ml_link_update(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS policy_mgr_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool enable_mcc_adaptive_sch = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_debug("Initializing the policy manager"); + + /* init pm_conc_connection_list */ + qdf_mem_zero(pm_conc_connection_list, sizeof(pm_conc_connection_list)); + policy_mgr_memzero_disabled_ml_list(); + policy_mgr_clear_concurrent_session_count(psoc); + /* init dbs_opportunistic_timer */ + status = qdf_mc_timer_init(&pm_ctx->dbs_opportunistic_timer, + QDF_TIMER_TYPE_SW, + pm_dbs_opportunistic_timer_handler, + (void *)psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("Failed to init DBS opportunistic timer"); + return status; + } + + status = policy_mgr_init_ml_link_update(pm_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* init connection_update_done_evt */ + status = policy_mgr_init_connection_update(pm_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("connection_update_done_evt init failed"); + return status; + } + + status = qdf_event_create(&pm_ctx->opportunistic_update_done_evt); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("opportunistic_update_done_evt init failed"); + return status; + } + + status = qdf_event_create(&pm_ctx->channel_switch_complete_evt); + if (!QDF_IS_STATUS_SUCCESS(status)) { + policy_mgr_err("channel_switch_complete_evt init failed"); + return status; + } + policy_mgr_get_mcc_adaptive_sch(psoc, &enable_mcc_adaptive_sch); + policy_mgr_set_dynamic_mcc_adaptive_sch(psoc, enable_mcc_adaptive_sch); + pm_ctx->hw_mode_change_in_progress = POLICY_MGR_HW_MODE_NOT_IN_PROGRESS; + /* reset sap mandatory channels */ + status = policy_mgr_reset_sap_mandatory_channels(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to reset mandatory channels"); + return status; + } + + /* init PCL table & function pointers based on HW capability */ + if (policy_mgr_is_hw_dbs_2x2_capable(psoc) || + policy_mgr_is_hw_dbs_required_for_band(psoc, HW_MODE_MAC_BAND_2G)) + policy_mgr_get_current_pref_hw_mode_ptr = + policy_mgr_get_current_pref_hw_mode_dbs_2x2; + else if (policy_mgr_is_2x2_1x1_dbs_capable(psoc)) + policy_mgr_get_current_pref_hw_mode_ptr = + policy_mgr_get_current_pref_hw_mode_dual_dbs; + else + policy_mgr_get_current_pref_hw_mode_ptr = + policy_mgr_get_current_pref_hw_mode_dbs_1x1; + + if (policy_mgr_is_hw_dbs_2x2_capable(psoc) && + policy_mgr_is_hw_sbs_capable(psoc)) + second_connection_pcl_dbs_table = + &pm_second_connection_pcl_dbs_sbs_2x2_table; + else if (policy_mgr_is_hw_dbs_2x2_capable(psoc) || + policy_mgr_is_hw_dbs_required_for_band(psoc, + HW_MODE_MAC_BAND_2G) || + policy_mgr_is_2x2_1x1_dbs_capable(psoc)) + second_connection_pcl_dbs_table = + &pm_second_connection_pcl_dbs_2x2_table; + else + second_connection_pcl_dbs_table = + &pm_second_connection_pcl_dbs_1x1_table; + + if (policy_mgr_is_hw_dbs_2x2_capable(psoc) && + policy_mgr_is_hw_sbs_capable(psoc)) + third_connection_pcl_dbs_table = + &pm_third_connection_pcl_dbs_sbs_2x2_table; + else if (policy_mgr_is_hw_dbs_2x2_capable(psoc) || + policy_mgr_is_hw_dbs_required_for_band(psoc, + HW_MODE_MAC_BAND_2G) || + policy_mgr_is_2x2_1x1_dbs_capable(psoc)) + third_connection_pcl_dbs_table = + &pm_third_connection_pcl_dbs_2x2_table; + else + third_connection_pcl_dbs_table = + &pm_third_connection_pcl_dbs_1x1_table; + + /* Initialize non-DBS pcl table pointer to particular table*/ + policy_mgr_init_non_dbs_pcl(psoc); + + if (policy_mgr_is_hw_dbs_2x2_capable(psoc)) { + if (policy_mgr_is_hw_dbs_required_for_band(psoc, + HW_MODE_MAC_BAND_2G)) { + next_action_two_connection_table = + &pm_next_action_two_connection_dbs_2x2_table; + policy_mgr_debug("using hst/hsp policy manager table"); + } else { + next_action_two_connection_table = + &pm_next_action_two_connection_dbs_2x2_table_v2; + policy_mgr_debug("using hmt policy manager table"); + } + } else if (policy_mgr_is_2x2_1x1_dbs_capable(psoc)) { + next_action_two_connection_table = + &pm_next_action_two_connection_dbs_2x2_5g_1x1_2g_table; + next_action_two_connection_2x2_2g_1x1_5g_table = + &pm_next_action_two_connection_dbs_2x2_2g_1x1_5g_table; + } else { + next_action_two_connection_table = + &pm_next_action_two_connection_dbs_1x1_table; + } + + if (policy_mgr_is_hw_dbs_2x2_capable(psoc) || + policy_mgr_is_hw_dbs_required_for_band(psoc, + HW_MODE_MAC_BAND_2G)) { + next_action_three_connection_table = + &pm_next_action_three_connection_dbs_2x2_table; + } else if (policy_mgr_is_2x2_1x1_dbs_capable(psoc)) { + next_action_three_connection_table = + &pm_next_action_three_connection_dbs_2x2_5g_1x1_2g_table; + next_action_three_connection_2x2_2g_1x1_5g_table = + &pm_next_action_three_connection_dbs_2x2_2g_1x1_5g_table; + } else { + next_action_three_connection_table = + &pm_next_action_three_connection_dbs_1x1_table; + } + policy_mgr_debug("is DBS Capable %d, is SBS Capable %d", + policy_mgr_is_hw_dbs_capable(psoc), + policy_mgr_is_hw_sbs_capable(psoc)); + policy_mgr_debug("is2x2 %d, 2g-on-dbs %d is2x2+1x1 %d, is2x2_5g+1x1_2g %d, is2x2_2g+1x1_5g %d", + policy_mgr_is_hw_dbs_2x2_capable(psoc), + policy_mgr_is_hw_dbs_required_for_band( + psoc, HW_MODE_MAC_BAND_2G), + policy_mgr_is_2x2_1x1_dbs_capable(psoc), + policy_mgr_is_2x2_5G_1x1_2G_dbs_capable(psoc), + policy_mgr_is_2x2_2G_1x1_5G_dbs_capable(psoc)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + /* destroy connection_update_done_evt */ + if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy + (&pm_ctx->connection_update_done_evt))) { + policy_mgr_err("Failed to destroy connection_update_done_evt"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + /* destroy opportunistic_update_done_evt */ + if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy + (&pm_ctx->opportunistic_update_done_evt))) { + policy_mgr_err("Failed to destroy opportunistic_update_done_evt"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + /* destroy channel_switch_complete_evt */ + if (!QDF_IS_STATUS_SUCCESS(qdf_event_destroy + (&pm_ctx->channel_switch_complete_evt))) { + policy_mgr_err("Failed to destroy channel_switch_complete evt"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + if (QDF_IS_STATUS_ERROR(policy_mgr_deinit_ml_link_update(pm_ctx))) { + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + /* deallocate dbs_opportunistic_timer */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &pm_ctx->dbs_opportunistic_timer)) { + qdf_mc_timer_stop(&pm_ctx->dbs_opportunistic_timer); + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_destroy( + &pm_ctx->dbs_opportunistic_timer))) { + policy_mgr_err("Cannot deallocate dbs opportunistic timer"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + /* reset sap mandatory channels */ + if (QDF_IS_STATUS_ERROR( + policy_mgr_reset_sap_mandatory_channels(psoc))) { + policy_mgr_err("failed to reset sap mandatory channels"); + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + } + + /* deinit pm_conc_connection_list */ + qdf_mem_zero(pm_conc_connection_list, sizeof(pm_conc_connection_list)); + policy_mgr_clear_concurrent_session_count(psoc); + + return status; +} + +QDF_STATUS policy_mgr_register_conc_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_conc_cbacks *conc_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->conc_cbacks.connection_info_update = + conc_cbacks->connection_info_update; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_register_sme_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_sme_cbacks *sme_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->sme_cbacks.sme_get_nss_for_vdev = + sme_cbacks->sme_get_nss_for_vdev; + pm_ctx->sme_cbacks.sme_nss_update_request = + sme_cbacks->sme_nss_update_request; + if (!policy_mgr_is_hwmode_offload_enabled(psoc)) + pm_ctx->sme_cbacks.sme_pdev_set_hw_mode = + sme_cbacks->sme_pdev_set_hw_mode; + pm_ctx->sme_cbacks.sme_soc_set_dual_mac_config = + sme_cbacks->sme_soc_set_dual_mac_config; + pm_ctx->sme_cbacks.sme_change_mcc_beacon_interval = + sme_cbacks->sme_change_mcc_beacon_interval; + pm_ctx->sme_cbacks.sme_rso_start_cb = + sme_cbacks->sme_rso_start_cb; + pm_ctx->sme_cbacks.sme_rso_stop_cb = + sme_cbacks->sme_rso_stop_cb; + pm_ctx->sme_cbacks.sme_change_sap_csa_count = + sme_cbacks->sme_change_sap_csa_count; + pm_ctx->sme_cbacks.sme_sap_update_ch_width = + sme_cbacks->sme_sap_update_ch_width; + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_register_hdd_cb() - register HDD callbacks + * @psoc: PSOC object information + * @hdd_cbacks: function pointers from HDD + * + * API, allows HDD to register callbacks to be invoked by policy + * mgr + * + * Return: SUCCESS, + * Failure (if registration fails) + */ +QDF_STATUS policy_mgr_register_hdd_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_hdd_cbacks *hdd_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb = + hdd_cbacks->sap_restart_chan_switch_cb; + pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart = + hdd_cbacks->wlan_hdd_get_channel_for_sap_restart; + pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev = + hdd_cbacks->get_mode_for_non_connected_vdev; + pm_ctx->hdd_cbacks.hdd_get_device_mode = + hdd_cbacks->hdd_get_device_mode; + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress = + hdd_cbacks->hdd_is_chan_switch_in_progress; + pm_ctx->hdd_cbacks.hdd_is_cac_in_progress = + hdd_cbacks->hdd_is_cac_in_progress; + pm_ctx->hdd_cbacks.hdd_get_ap_6ghz_capable = + hdd_cbacks->hdd_get_ap_6ghz_capable; + pm_ctx->hdd_cbacks.wlan_hdd_indicate_active_ndp_cnt = + hdd_cbacks->wlan_hdd_indicate_active_ndp_cnt; + pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params = + hdd_cbacks->wlan_get_ap_prefer_conc_ch_params; + pm_ctx->hdd_cbacks.wlan_get_sap_acs_band = + hdd_cbacks->wlan_get_sap_acs_band; + pm_ctx->hdd_cbacks.wlan_check_cc_intf_cb = + hdd_cbacks->wlan_check_cc_intf_cb; + pm_ctx->hdd_cbacks.wlan_set_tx_rx_nss_cb = + hdd_cbacks->wlan_set_tx_rx_nss_cb; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_deregister_hdd_cb(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->hdd_cbacks.sap_restart_chan_switch_cb = NULL; + pm_ctx->hdd_cbacks.wlan_hdd_get_channel_for_sap_restart = NULL; + pm_ctx->hdd_cbacks.get_mode_for_non_connected_vdev = NULL; + pm_ctx->hdd_cbacks.hdd_get_device_mode = NULL; + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress = NULL; + pm_ctx->hdd_cbacks.hdd_is_cac_in_progress = NULL; + pm_ctx->hdd_cbacks.hdd_get_ap_6ghz_capable = NULL; + pm_ctx->hdd_cbacks.wlan_get_ap_prefer_conc_ch_params = NULL; + pm_ctx->hdd_cbacks.wlan_get_sap_acs_band = NULL; + pm_ctx->hdd_cbacks.wlan_set_tx_rx_nss_cb = NULL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_register_wma_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_wma_cbacks *wma_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->wma_cbacks.wma_get_connection_info = + wma_cbacks->wma_get_connection_info; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_register_cdp_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_cdp_cbacks *cdp_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->cdp_cbacks.cdp_update_mac_id = + cdp_cbacks->cdp_update_mac_id; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_register_dp_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_dp_cbacks *dp_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->dp_cbacks.hdd_disable_rx_ol_in_concurrency = + dp_cbacks->hdd_disable_rx_ol_in_concurrency; + pm_ctx->dp_cbacks.hdd_set_rx_mode_rps_cb = + dp_cbacks->hdd_set_rx_mode_rps_cb; + pm_ctx->dp_cbacks.hdd_ipa_set_mcc_mode_cb = + dp_cbacks->hdd_ipa_set_mcc_mode_cb; + pm_ctx->dp_cbacks.hdd_v2_flow_pool_map = + dp_cbacks->hdd_v2_flow_pool_map; + pm_ctx->dp_cbacks.hdd_v2_flow_pool_unmap = + dp_cbacks->hdd_v2_flow_pool_unmap; + pm_ctx->dp_cbacks.hdd_ipa_set_perf_level_bw = + dp_cbacks->hdd_ipa_set_perf_level_bw; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_register_tdls_cb(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_tdls_cbacks *tdls_cbacks) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->tdls_cbacks.tdls_notify_increment_session = + tdls_cbacks->tdls_notify_increment_session; + pm_ctx->tdls_cbacks.tdls_notify_decrement_session = + tdls_cbacks->tdls_notify_decrement_session; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_register_mode_change_cb(struct wlan_objmgr_psoc *psoc, + send_mode_change_event_cb mode_change_cb) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->mode_change_cb = mode_change_cb; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_deregister_mode_change_cb(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->mode_change_cb = NULL; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c new file mode 100644 index 0000000000..9ddf906316 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains policy manager ll_sap definitions specific to the ll_sap module + */ + +#include "wlan_policy_mgr_ll_sap.h" +#include "wlan_policy_mgr_public_struct.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_cmn.h" +#include "wlan_ll_sap_api.h" + +void policy_mgr_ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t sap_ch_freq, + uint8_t cc_switch_mode, + qdf_freq_t *new_sap_freq, + bool *is_ll_lt_sap_present) +{ + enum sap_csa_reason_code csa_reason; + enum policy_mgr_con_mode conn_mode; + qdf_freq_t ll_lt_sap_freq = 0; + *is_ll_lt_sap_present = false; + + /* If Vdev is ll_lt_sap, check if the frequency on which it is + * coming up is correct, else, get new frequency + */ + if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) { + *new_sap_freq = wlan_get_ll_lt_sap_restart_freq(pdev, + sap_ch_freq, + vdev_id, + &csa_reason); + *is_ll_lt_sap_present = true; + } + + ll_lt_sap_freq = policy_mgr_get_ll_lt_sap_freq(psoc); + if (!ll_lt_sap_freq) + return; + + conn_mode = policy_mgr_get_mode_by_vdev_id(psoc, vdev_id); + + if (conn_mode == PM_SAP_MODE) { + /* If ll_lt_sap and concurrent SAP are on same MAC, + * update the frequency of concurrent SAP, else return. + */ + if (!policy_mgr_are_2_freq_on_same_mac(psoc, sap_ch_freq, + ll_lt_sap_freq)) + return; + goto policy_mgr_check_scc; + } else if (conn_mode == PM_P2P_GO_MODE) { + /* If ll_lt_sap and P2P_GO are in SCC, + * update the frequency of concurrent GO else, return. + */ + if (ll_lt_sap_freq != sap_ch_freq) + return; + goto policy_mgr_check_scc; + } else { + policy_mgr_debug("Invalid con mode %d vdev %d", conn_mode, + vdev_id); + return; + } + +policy_mgr_check_scc: + policy_mgr_check_scc_channel(psoc, new_sap_freq, sap_ch_freq, vdev_id, + cc_switch_mode); + policy_mgr_debug("vdev_id %d old_freq %d new_freq %d", vdev_id, + sap_ch_freq, *new_sap_freq); +} + +uint8_t wlan_policy_mgr_get_ll_lt_sap_vdev_id(struct wlan_objmgr_psoc *psoc) +{ + uint8_t ll_lt_sap_cnt; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + ll_lt_sap_cnt = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, + PM_LL_LT_SAP_MODE); + + /* Currently only 1 ll_lt_sap is supported */ + if (!ll_lt_sap_cnt) + return WLAN_INVALID_VDEV_ID; + + return vdev_id_list[0]; +} + +bool __policy_mgr_is_ll_lt_sap_restart_required(struct wlan_objmgr_psoc *psoc, + const char *func) +{ + qdf_freq_t ll_lt_sap_freq = 0; + uint8_t scc_vdev_id; + bool is_scc = false; + uint8_t conn_idx = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm ctx"); + return false; + } + + ll_lt_sap_freq = policy_mgr_get_ll_lt_sap_freq(psoc); + + if (!ll_lt_sap_freq) + return false; + + /* + * Restart ll_lt_sap if any other interface is present in SCC + * with LL_LT_SAP. + */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_idx = 0; conn_idx < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_idx++) { + if (pm_conc_connection_list[conn_idx].mode == + PM_LL_LT_SAP_MODE) + continue; + + if (ll_lt_sap_freq == pm_conc_connection_list[conn_idx].freq) { + scc_vdev_id = pm_conc_connection_list[conn_idx].vdev_id; + is_scc = true; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (is_scc) { + uint8_t ll_lt_sap_vdev_id = + wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc); + + policymgr_nofl_debug("%s ll_lt_sap vdev %d with freq %d is in scc with vdev %d", + func, ll_lt_sap_vdev_id, ll_lt_sap_freq, + scc_vdev_id); + return true; + } + + return false; +} + +/** + * policy_mgr_ll_lt_sap_get_restart_freq_for_concurent_sap() - Get restart frequency + * for concurrent SAP which is in concurrency with LL_LT_SAP + * @pm_ctx: Policy manager context + * @vdev_id: Vdev id of the SAP for which restart freq is required + * @curr_freq: Current frequency of the SAP for which restart freq is required + * @ll_lt_sap_enabled: Indicates if ll_lt_sap is getting enabled or disabled + * + * This API returns user configured frequency if ll_lt_sap is going down and + * if ll_lt_sap is coming up it returns frequency according to ll_lt_sap + * concurrency. + * + * Return: Restart frequency + */ +static qdf_freq_t +policy_mgr_ll_lt_sap_get_restart_freq_for_concurent_sap( + struct policy_mgr_psoc_priv_obj *pm_ctx, + uint8_t vdev_id, + qdf_freq_t curr_freq, + bool ll_lt_sap_enabled) +{ + qdf_freq_t user_config_freq; + uint8_t i; + QDF_STATUS status; + uint32_t channel_list[NUM_CHANNELS]; + uint32_t num_channels; + qdf_freq_t restart_freq = 0; + + /* + * If ll_lt_sap is getting disabled, return user configured frequency + * for concurrent SAP restart, if user configured frequency is not valid + * frequency, remain on the same frequency and do not restart the SAP + */ + if (!ll_lt_sap_enabled) { + user_config_freq = policy_mgr_get_user_config_sap_freq( + pm_ctx->psoc, + vdev_id); + if (wlan_reg_is_enable_in_secondary_list_for_freq( + pm_ctx->pdev, + user_config_freq) && + policy_mgr_is_safe_channel(pm_ctx->psoc, user_config_freq)) + return user_config_freq; + return curr_freq; + } + + status = policy_mgr_get_valid_chans(pm_ctx->psoc, channel_list, + &num_channels); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Error in getting valid channels"); + return curr_freq; + } + + /* return first valid 2.4 GHz frequency */ + for (i = 0; i < num_channels; i++) { + if (wlan_reg_is_24ghz_ch_freq(channel_list[i])) { + if (!restart_freq) + restart_freq = channel_list[i]; + /* Prefer SCC frequency */ + if (policy_mgr_get_connection_count_with_ch_freq( + channel_list[i])) { + restart_freq = channel_list[i]; + break; + } + } + } + return restart_freq; +} + +void policy_mgr_ll_lt_sap_restart_concurrent_sap(struct wlan_objmgr_psoc *psoc, + bool is_ll_lt_sap_enabled) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info sap_info = {0}; + qdf_freq_t restart_freq; + struct ch_params ch_params = {0}; + uint8_t i; + enum sap_csa_reason_code csa_reason; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm context"); + return; + } + + qdf_mem_zero(&sap_info, sizeof(sap_info)); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (!pm_conc_connection_list[i].in_use) + continue; + if (PM_SAP_MODE == pm_conc_connection_list[i].mode || + PM_LL_LT_SAP_MODE == pm_conc_connection_list[i].mode) { + qdf_mem_copy(&sap_info, &pm_conc_connection_list[i], + sizeof(sap_info)); + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* No concurrent SAP or ll_lt_sap present, return */ + if (!sap_info.in_use) + return; + + if (sap_info.mode == PM_SAP_MODE) { + /* + * For SBS case, no need to restart concurrent SAP as LL_LT_SAP + * and concurrent SAP can be on different MACs + */ + if (policy_mgr_is_hw_sbs_capable(psoc)) + return; + + /* + * If concurrent SAP is 2.4 GHz and ll_lt_sap is getting enabled + * then there is no need to restart the concurrent SAP + */ + if (is_ll_lt_sap_enabled && + wlan_reg_is_24ghz_ch_freq(sap_info.freq)) + return; + + /* + * If concurrent SAP is 5 GHz/6 GHz and ll_lt_sap is getting + * disabled then there is no need to restart the concurrent SAP + */ + else if (!is_ll_lt_sap_enabled && + (wlan_reg_is_5ghz_ch_freq(sap_info.freq) || + wlan_reg_is_6ghz_chan_freq(sap_info.freq))) + return; + + restart_freq = + policy_mgr_ll_lt_sap_get_restart_freq_for_concurent_sap( + pm_ctx, + sap_info.vdev_id, + sap_info.freq, + is_ll_lt_sap_enabled); + csa_reason = CSA_REASON_CONCURRENT_LL_LT_SAP_EVENT; + } else { + restart_freq = wlan_get_ll_lt_sap_restart_freq(pm_ctx->pdev, + sap_info.freq, + sap_info.vdev_id, + &csa_reason); + } + + if (pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress && + pm_ctx->hdd_cbacks.hdd_is_chan_switch_in_progress()) { + policy_mgr_debug("channel switch is already in progress"); + return; + } + + if (!restart_freq) { + policy_mgr_err("Restart freq not found for vdev %d", + sap_info.vdev_id); + return; + } + if (restart_freq == sap_info.freq) { + policy_mgr_debug("vdev %d restart freq %d same as current freq", + sap_info.vdev_id, restart_freq); + return; + } + ch_params.ch_width = policy_mgr_get_ch_width(sap_info.bw); + wlan_reg_set_channel_params_for_pwrmode(pm_ctx->pdev, restart_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + policy_mgr_debug("Restart SAP vdev %d with %d freq width %d", + sap_info.vdev_id, restart_freq, ch_params.ch_width); + + if (pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason) + pm_ctx->hdd_cbacks.wlan_hdd_set_sap_csa_reason(psoc, + sap_info.vdev_id, + csa_reason); + + policy_mgr_change_sap_channel_with_csa(psoc, sap_info.vdev_id, + restart_freq, + ch_params.ch_width, true); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c new file mode 100644 index 0000000000..15db62a06e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c @@ -0,0 +1,5135 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_policy_mgr_pcl.c + * + * WLAN Concurrenct Connection Management APIs + * + */ + +/* Include files */ + +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_i.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "qdf_str.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_utility.h" +#include "wlan_mlme_ucfg_api.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_cmn.h" +#endif +#include "wlan_policy_mgr_ll_sap.h" +#include "wlan_cm_ucfg_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_scan_api.h" +#include "wlan_nan_api.h" +#include "wlan_mlo_link_force.h" + +/* + * first_connection_pcl_table - table which provides PCL for the + * very first connection in the system + */ +const enum policy_mgr_pcl_type +first_connection_pcl_table[PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE] = { + [PM_STA_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G }, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G }, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G }, + [PM_NAN_DISC_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, +}; + +pm_dbs_pcl_second_connection_table_type + *second_connection_pcl_dbs_table; + +enum policy_mgr_pcl_type const + (*second_connection_pcl_non_dbs_table)[PM_MAX_ONE_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE]; +pm_dbs_pcl_third_connection_table_type + *third_connection_pcl_dbs_table; +enum policy_mgr_pcl_type const + (*third_connection_pcl_non_dbs_table)[PM_MAX_TWO_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE]; +policy_mgr_next_action_two_connection_table_type + *next_action_two_connection_table; +policy_mgr_next_action_three_connection_table_type + *next_action_three_connection_table; +policy_mgr_next_action_two_connection_table_type + *next_action_two_connection_2x2_2g_1x1_5g_table; +policy_mgr_next_action_three_connection_table_type + *next_action_three_connection_2x2_2g_1x1_5g_table; + +QDF_STATUS policy_mgr_get_pcl_for_existing_conn( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len, + bool all_matching_cxn_to_del, + uint8_t vdev_id) +{ + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + uint8_t num_cxn_del = 0; + + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + policy_mgr_debug("get pcl for existing conn:%d", mode); + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + *len = 0; + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (policy_mgr_mode_specific_connection_count(psoc, mode, NULL) > 0) { + /* Check, store and temp delete the mode's parameter */ + policy_mgr_store_and_del_conn_info(psoc, mode, + all_matching_cxn_to_del, info, &num_cxn_del); + /* Get the PCL */ + status = policy_mgr_get_pcl(psoc, mode, pcl_ch, len, + pcl_weight, weight_len, vdev_id); + policy_mgr_debug("Get PCL to FW for mode:%d", mode); + /* Restore the connection info */ + policy_mgr_restore_deleted_conn_info(psoc, info, num_cxn_del); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * policy_mgr_get_pcl_concurrent_connetions() - Get concurrent connections + * those will affect PCL fetching for the given vdev id + * @psoc: PSOC object information + * @mode: Connection Mode + * @vdev_id: vdev id + * @vdev_ids: vdev id list of the concurrent connections + * @vdev_ids_size: size of the vdev id list + * + * Return: number of the concurrent connections + */ +static uint32_t +policy_mgr_get_pcl_concurrent_connetions(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t vdev_id, uint8_t *vdev_ids, + uint32_t vdev_ids_size) +{ + struct wlan_objmgr_vdev *vdev; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t num_related = 0; + bool is_ml_sta, has_same_band = false; + uint8_t vdev_id_with_diff_band = WLAN_INVALID_VDEV_ID; + uint8_t num_ml = 0, num_non_ml = 0, ml_vdev_id; + uint8_t ml_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t non_ml_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t freq = 0, ml_freq; + int i; + + if (!vdev_ids || !vdev_ids_size) { + policy_mgr_err("Invalid parameters"); + return num_related; + } + + if (mode != PM_STA_MODE) { + vdev_ids[0] = vdev_id; + return 1; + } + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d is not present", vdev_id); + goto out; + } + + if (wlan_vdev_mlme_is_link_sta_vdev(vdev)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + policy_mgr_debug("ignore ML STA link vdev %d", vdev_id); + goto out; + } + + is_ml_sta = wlan_vdev_mlme_is_mlo_vdev(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + + policy_mgr_get_ml_and_non_ml_sta_count(psoc, &num_ml, ml_idx, + &num_non_ml, non_ml_idx, + freq_list, vdev_id_list); + for (i = 0; + i < num_non_ml + num_ml && num_related < vdev_ids_size; i++) { + if (vdev_id_list[i] == vdev_id) { + vdev_ids[num_related++] = vdev_id; + freq = freq_list[i]; + break; + } + } + + /* No existing connection for the vdev id */ + if (!freq) + goto out; + + for (i = 0; i < num_ml && num_related < vdev_ids_size; i++) { + ml_vdev_id = vdev_id_list[ml_idx[i]]; + if (ml_vdev_id == vdev_id) + continue; + + /* If it's ML STA, return vdev ids for all links */ + if (is_ml_sta) { + policy_mgr_debug("vdev_ids[%d]: %d", + num_related, ml_vdev_id); + vdev_ids[num_related++] = ml_vdev_id; + continue; + } + + ml_freq = freq_list[ml_idx[i]]; + if (wlan_reg_is_24ghz_ch_freq(ml_freq) == + wlan_reg_is_24ghz_ch_freq(freq)) { + if (policy_mgr_are_sbs_chan(psoc, freq, ml_freq) && + wlan_cm_same_band_sta_allowed(psoc)) + continue; + + /* + * If it's Non-ML STA, and its freq is within the same + * band with one of the existing ML link, but can NOT + * lead to SBS, return the original vdev id and vdev id + * of the ML link within same band. + */ + policy_mgr_debug("vdev_ids[%d]: %d", + num_related, ml_vdev_id); + vdev_ids[num_related++] = ml_vdev_id; + has_same_band = true; + break; + } + + vdev_id_with_diff_band = ml_vdev_id; + } + + /* + * If it's Non-ML STA, and ML STA is present but the links are + * within different band or (within same band but can lead to SBS and + * same band STA is allowed), return original vdev id and vdev id of + * any ML link within different band. + */ + if (!has_same_band && vdev_id_with_diff_band != WLAN_INVALID_VDEV_ID) { + policy_mgr_debug("vdev_ids[%d]: %d", + num_related, vdev_id_with_diff_band); + + if (num_related < vdev_ids_size) + vdev_ids[num_related++] = vdev_id_with_diff_band; + } + +out: + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return num_related; +} +#else +static inline uint32_t +policy_mgr_get_pcl_concurrent_connetions(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint8_t vdev_id, uint8_t *vdev_ids, + uint32_t vdev_ids_size) +{ + if (!vdev_ids || !vdev_ids_size) { + policy_mgr_err("Invalid parameters"); + return 0; + } + + vdev_ids[0] = vdev_id; + return 1; +} +#endif + +QDF_STATUS policy_mgr_get_pcl_for_vdev_id(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, + uint32_t weight_len, + uint8_t vdev_id) +{ + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t ids[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t num_del = 0, total_del = 0, id_num = 0; + int i; + + policy_mgr_debug("get pcl for existing conn:%d vdev id %d", + mode, vdev_id); + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + id_num = policy_mgr_get_pcl_concurrent_connetions(psoc, mode, + vdev_id, ids, + QDF_ARRAY_SIZE(ids)); + if (!id_num || id_num > MAX_NUMBER_OF_CONC_CONNECTIONS) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + *len = 0; + + /* Check, store and temp delete the mode's parameter */ + for (i = 0; i < id_num; i++) { + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, + ids[i], + &info[i], + &num_del); + total_del += num_del; + } + + /* Get the PCL */ + status = policy_mgr_get_pcl(psoc, mode, pcl_ch, len, + pcl_weight, weight_len, vdev_id); + policy_mgr_debug("Get PCL to FW for mode:%d", mode); + /* Restore the connection info */ + policy_mgr_restore_deleted_conn_info(psoc, info, total_del); + +out: + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +QDF_STATUS +policy_mgr_get_pcl_for_scc_in_same_mode(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_ch, uint32_t *len, + uint8_t *pcl_weight, + uint32_t weight_len, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + qdf_freq_t vdev_freq; + QDF_STATUS status; + uint8_t num_del = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + status = policy_mgr_get_chan_by_session_id(psoc, vdev_id, &vdev_freq); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Fail to get channel by vdev id %d", vdev_id); + return status; + } + + policy_mgr_debug("get pcl for existing conn:%d vdev id %d", + mode, vdev_id); + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_store_and_del_conn_info_by_chan_and_mode(psoc, + vdev_freq, + mode, + info, + &num_del); + status = policy_mgr_get_pcl(psoc, mode, pcl_ch, len, + pcl_weight, weight_len, vdev_id); + if (num_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, info, num_del); + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} + +void +polic_mgr_send_pcl_to_fw(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode) +{ + uint32_t conn_idx = 0; + mac_handle_t mac_handle = cds_get_context(QDF_MODULE_ID_SME); + uint8_t vdev_id = WLAN_INVALID_VDEV_ID; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + for (conn_idx = 0; conn_idx < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_idx++) { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (!(pm_conc_connection_list[conn_idx].mode == + PM_STA_MODE && + pm_conc_connection_list[conn_idx].in_use)) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + continue; + } + + vdev_id = pm_conc_connection_list[conn_idx].vdev_id; + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + /* + * Avoid sending PCL when roaming is in progress. PCL + * gets updated to firmware once roaming is done + */ + if (mode == QDF_SAP_MODE && + wlan_cm_roaming_in_progress(pm_ctx->pdev, + vdev_id)) { + policy_mgr_debug("Roaming is in progress, don't stop RSO for vdev_id: %d", + vdev_id); + continue; + } + + pm_ctx->sme_cbacks.sme_rso_stop_cb( + mac_handle, vdev_id, + REASON_DRIVER_DISABLED, + RSO_SET_PCL); + + policy_mgr_set_pcl_for_existing_combo(pm_ctx->psoc, PM_STA_MODE, + vdev_id); + pm_ctx->sme_cbacks.sme_rso_start_cb( + mac_handle, vdev_id, + REASON_DRIVER_ENABLED, + RSO_SET_PCL); + } +} + +void policy_mgr_decr_session_set_pcl(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE mode, + uint8_t session_id) +{ + QDF_STATUS qdf_status; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + qdf_status = policy_mgr_decr_active_session(psoc, mode, session_id); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + policy_mgr_debug("Invalid active session"); + return; + } + + /* + * After the removal of this connection, we need to check if + * a STA connection still exists. The reason for this is that + * if one or more STA exists, we need to provide the updated + * PCL to the FW for cases like LFR. + * + * Since policy_mgr_get_pcl provides PCL list based on the new + * connection that is going to come up, we will find the + * existing STA entry, save it and delete it temporarily. + * After this we will get PCL as though as new STA connection + * is coming up. This will give the exact PCL that needs to be + * given to the FW. After setting the PCL, we need to restore + * the entry that we have saved before. + */ + + if ((policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL) > 0) && + mode != QDF_STA_MODE) + polic_mgr_send_pcl_to_fw(psoc, mode); + + /* do we need to change the HW mode */ + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return; + + policy_mgr_check_n_start_opportunistic_timer(psoc); + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) + ml_nlink_conn_change_notify( + psoc, session_id, ml_nlink_ap_stopped_evt, NULL); +} + +/** + * policy_mgr_update_valid_ch_freq_list() - Update policy manager valid ch list + * @pm_ctx: policy manager context data + * @reg_ch_list: Regulatory channel list + * @is_client: true if caller is a client, false if it is a beaconing entity + * + * When regulatory component channel list is updated this internal function is + * called to update policy manager copy of valid channel list. + * + * Return: QDF_STATUS_SUCCESS on success other qdf error status code + */ +static void +policy_mgr_update_valid_ch_freq_list(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct regulatory_channel *reg_ch_list, + bool is_client) +{ + uint32_t i, j = 0, ch_freq; + enum channel_state state; + + for (i = 0; i < NUM_CHANNELS; i++) { + ch_freq = reg_ch_list[i].center_freq; + if (is_client) + state = wlan_reg_get_channel_state_for_pwrmode( + pm_ctx->pdev, ch_freq, + REG_CURRENT_PWR_MODE); + else + state = + wlan_reg_get_channel_state_from_secondary_list_for_freq( + pm_ctx->pdev, ch_freq); + + if (state != CHANNEL_STATE_DISABLE && + state != CHANNEL_STATE_INVALID) { + pm_ctx->valid_ch_freq_list[j] = + reg_ch_list[i].center_freq; + j++; + } + } + pm_ctx->valid_ch_freq_list_count = j; +} + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +void +policy_mgr_set_freq_restriction_mask(struct policy_mgr_psoc_priv_obj *pm_ctx, + struct ch_avoid_ind_type *freq_list) +{ + pm_ctx->restriction_mask = freq_list->restriction_mask; +} + +uint32_t +policy_mgr_get_freq_restriction_mask(struct policy_mgr_psoc_priv_obj *pm_ctx) +{ + return pm_ctx->restriction_mask; +} +#endif + +void +policy_mgr_reg_chan_change_callback(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct regulatory_channel *chan_list, + struct avoid_freq_ind_data *avoid_freq_ind, + void *arg) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i; + struct ch_avoid_ind_type *freq_list; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + policy_mgr_update_valid_ch_freq_list(pm_ctx, chan_list, false); + + if (!avoid_freq_ind) { + policy_mgr_debug("avoid_freq_ind NULL"); + return; + } + + /* + * The ch_list buffer can accommodate a maximum of + * NUM_CHANNELS and hence the ch_cnt should also not + * exceed NUM_CHANNELS. + */ + pm_ctx->unsafe_channel_count = avoid_freq_ind->chan_list.chan_cnt >= + NUM_CHANNELS ? + NUM_CHANNELS : avoid_freq_ind->chan_list.chan_cnt; + + freq_list = &avoid_freq_ind->freq_list; + policy_mgr_set_freq_restriction_mask(pm_ctx, freq_list); + + for (i = 0; i < pm_ctx->unsafe_channel_count; i++) + pm_ctx->unsafe_channel_list[i] = + avoid_freq_ind->chan_list.chan_freq_list[i]; + + policy_mgr_debug("Channel list update, received %d avoided channels", + pm_ctx->unsafe_channel_count); +} + +QDF_STATUS policy_mgr_init_chan_avoidance(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *chan_freq_list, + uint16_t chan_cnt) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t i; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + pm_ctx->unsafe_channel_count = chan_cnt >= NUM_CHANNELS ? + NUM_CHANNELS : chan_cnt; + + for (i = 0; i < pm_ctx->unsafe_channel_count; i++) + pm_ctx->unsafe_channel_list[i] = chan_freq_list[i]; + + policy_mgr_debug("Channel list init, received %d avoided channels", + pm_ctx->unsafe_channel_count); + + return QDF_STATUS_SUCCESS; +} + +void policy_mgr_update_with_safe_channel_list(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, + uint32_t *len, + uint8_t *weight_list, + uint32_t weight_len) +{ + uint32_t current_channel_list[NUM_CHANNELS]; + uint8_t org_weight_list[NUM_CHANNELS]; + uint8_t is_unsafe = 1; + uint8_t i, j; + uint32_t safe_channel_count = 0, current_channel_count = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t scc_on_lte_coex = 0; + uint32_t nan_2g_freq, nan_5g_freq; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + if (len) { + current_channel_count = QDF_MIN(*len, NUM_CHANNELS); + } else { + policy_mgr_err("invalid number of channel length"); + return; + } + + if (!pm_ctx->unsafe_channel_count) + return; + + qdf_mem_copy(current_channel_list, pcl_channels, + current_channel_count * sizeof(*current_channel_list)); + qdf_mem_zero(pcl_channels, + current_channel_count * sizeof(*pcl_channels)); + + qdf_mem_copy(org_weight_list, weight_list, NUM_CHANNELS); + qdf_mem_zero(weight_list, weight_len); + + policy_mgr_get_sta_sap_scc_lte_coex_chnl(psoc, &scc_on_lte_coex); + nan_2g_freq = + policy_mgr_mode_specific_get_channel(pm_ctx->psoc, + PM_NAN_DISC_MODE); + nan_5g_freq = wlan_nan_get_disc_5g_ch_freq(pm_ctx->psoc); + + for (i = 0; i < current_channel_count; i++) { + is_unsafe = 0; + for (j = 0; j < pm_ctx->unsafe_channel_count; j++) { + if (current_channel_list[i] == + pm_ctx->unsafe_channel_list[j]) { + /* Found unsafe channel, update it */ + is_unsafe = 1; + policy_mgr_debug("CH %d is not safe", + current_channel_list[i]); + break; + } + } + if (is_unsafe && scc_on_lte_coex && + policy_mgr_is_sta_sap_scc(psoc, current_channel_list[i])) { + policy_mgr_debug("CH %d unsafe ignored when STA present on it", + current_channel_list[i]); + is_unsafe = 0; + } else if (is_unsafe && + (nan_2g_freq == current_channel_list[i] || + nan_5g_freq == current_channel_list[i]) && + policy_mgr_is_force_scc(pm_ctx->psoc) && + policy_mgr_get_nan_sap_scc_on_lte_coex_chnl(pm_ctx->psoc)) { + is_unsafe = 0; + } + + if (!is_unsafe) { + pcl_channels[safe_channel_count] = + current_channel_list[i]; + if (safe_channel_count < weight_len) + weight_list[safe_channel_count] = + org_weight_list[i]; + safe_channel_count++; + } + } + *len = safe_channel_count; + + return; +} + +static QDF_STATUS policy_mgr_modify_pcl_based_on_enabled_channels( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + uint32_t i, pcl_len = 0; + bool allow_go_scc_on_dfs_chn = false; + bool dfs_master_capable = false; + uint8_t sta_sap_scc_on_dfs_chnl = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return status; + } + + status = ucfg_mlme_get_dfs_master_capability(psoc, &dfs_master_capable); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get dfs master capable"); + return status; + } + + status = policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, + &sta_sap_scc_on_dfs_chnl); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get sta_sap_scc_on_dfs_chnl"); + return status; + } + + if (dfs_master_capable && sta_sap_scc_on_dfs_chnl && + pm_ctx->cfg.go_force_scc == GO_FORCE_SCC_STRICT) { + allow_go_scc_on_dfs_chn = true; + } + + for (i = 0; i < *pcl_len_org; i++) { + if ((!wlan_reg_is_passive_or_disable_for_pwrmode( + pm_ctx->pdev, pcl_list_org[i], + REG_CURRENT_PWR_MODE)) || + (allow_go_scc_on_dfs_chn && + wlan_reg_is_dfs_for_freq(pm_ctx->pdev, pcl_list_org[i]))) { + pcl_list_org[pcl_len] = pcl_list_org[i]; + weight_list_org[pcl_len++] = weight_list_org[i]; + } + } + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_modify_pcl_based_on_dnbs( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + uint32_t i, pcl_len = 0; + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + bool ok; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return status; + } + for (i = 0; i < *pcl_len_org; i++) { + status = policy_mgr_is_chan_ok_for_dnbs(psoc, pcl_list_org[i], + &ok); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Not able to check DNBS eligibility"); + return status; + } + if (ok) { + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + } + + qdf_mem_zero(pcl_list_org, *pcl_len_org * sizeof(*pcl_list_org)); + qdf_mem_zero(weight_list_org, *pcl_len_org); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len * sizeof(*pcl_list_org)); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +uint32_t policy_mgr_get_channel(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *vdev_id) +{ + uint32_t idx = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + + if (mode >= PM_MAX_NUM_OF_MODE) { + policy_mgr_err("incorrect mode"); + return 0; + } + + for (idx = 0; idx < MAX_NUMBER_OF_CONC_CONNECTIONS; idx++) { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if ((pm_conc_connection_list[idx].mode == mode) && + (!vdev_id || (*vdev_id == + pm_conc_connection_list[idx].vdev_id)) + && pm_conc_connection_list[idx].in_use) { + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + return pm_conc_connection_list[idx].freq; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } + + return 0; +} + +QDF_STATUS policy_mgr_skip_dfs_ch(struct wlan_objmgr_psoc *psoc, + bool *skip_dfs_channel) +{ + bool sta_sap_scc_on_dfs_chan; + bool dfs_master_capable; + QDF_STATUS status; + + status = ucfg_mlme_get_dfs_master_capability(psoc, + &dfs_master_capable); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get dfs master capable"); + return status; + } + + *skip_dfs_channel = false; + if (!dfs_master_capable) { + policy_mgr_debug("skip DFS ch for SAP/Go dfs master cap %d", + dfs_master_capable); + *skip_dfs_channel = true; + return QDF_STATUS_SUCCESS; + } + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(psoc); + + if (policy_mgr_is_hw_dbs_capable(psoc)) { + if ((policy_mgr_is_special_mode_active_5g(psoc, + PM_P2P_CLIENT_MODE) || + policy_mgr_is_special_mode_active_5g(psoc, PM_STA_MODE)) && + !sta_sap_scc_on_dfs_chan) { + policy_mgr_debug("skip DFS ch from pcl for DBS SAP/Go"); + *skip_dfs_channel = true; + } + } else { + if ((policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL) > 0) && + !sta_sap_scc_on_dfs_chan) { + policy_mgr_debug("skip DFS ch from pcl for non-DBS SAP/Go"); + *skip_dfs_channel = true; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_modify_sap_pcl_based_on_dfs() - filter out DFS channel if needed + * @psoc: pointer to soc + * @pcl_list_org: channel list to filter out + * @weight_list_org: weight of channel list + * @pcl_len_org: length of channel list + * + * Return: QDF_STATUS + */ +static QDF_STATUS policy_mgr_modify_sap_pcl_based_on_dfs( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + size_t i, pcl_len = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool skip_dfs_channel = false; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + + status = policy_mgr_skip_dfs_ch(psoc, &skip_dfs_channel); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get dfs channel skip info"); + return status; + } + + if (!skip_dfs_channel) + return QDF_STATUS_SUCCESS; + + for (i = 0; i < *pcl_len_org; i++) { + if (!wlan_reg_is_dfs_in_secondary_list_for_freq( + pm_ctx->pdev, + pcl_list_org[i])) { + pcl_list_org[pcl_len] = pcl_list_org[i]; + weight_list_org[pcl_len++] = weight_list_org[i]; + } + } + + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_modify_sap_pcl_based_on_nol( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + uint32_t i, pcl_len = 0; + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < *pcl_len_org; i++) { + if (!wlan_reg_is_disable_in_secondary_list_for_freq( + pm_ctx->pdev, pcl_list_org[i])) { + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + } + + qdf_mem_zero(pcl_list_org, *pcl_len_org * sizeof(*pcl_list_org)); + qdf_mem_zero(weight_list_org, *pcl_len_org); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len * sizeof(*pcl_list_org)); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +policy_mgr_modify_pcl_based_on_srd(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + uint32_t i, pcl_len = 0; + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + for (i = 0; i < *pcl_len_org; i++) { + if (wlan_reg_is_etsi_srd_chan_for_freq( + pm_ctx->pdev, pcl_list_org[i])) + continue; + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + + qdf_mem_zero(pcl_list_org, *pcl_len_org * sizeof(*pcl_list_org)); + qdf_mem_zero(weight_list_org, *pcl_len_org); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len * sizeof(*pcl_list_org)); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_modify_pcl_based_on_indoor() - filter out indoor channel if needed + * @psoc: pointer to soc + * @pcl_list_org: channel list to filter out + * @weight_list_org: weight of channel list + * @pcl_len_org: length of channel list + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_modify_pcl_based_on_indoor(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + uint32_t i, pcl_len = 0; + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool include_indoor_channel, sta_sap_scc_on_indoor_channel_allowed; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + + status = ucfg_mlme_get_indoor_channel_support(psoc, + &include_indoor_channel); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get indoor channel skip info"); + return status; + } + + /* + * If STA SAP scc is allowed on indoor channels, and if STA/P2P + * client is present on 5 GHz channel, include indoor channels + */ + sta_sap_scc_on_indoor_channel_allowed = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + if (!include_indoor_channel && sta_sap_scc_on_indoor_channel_allowed && + (policy_mgr_is_special_mode_active_5g(psoc, PM_P2P_CLIENT_MODE) || + policy_mgr_is_special_mode_active_5g(psoc, PM_STA_MODE))) + include_indoor_channel = true; + + if (include_indoor_channel) { + policy_mgr_debug("Indoor channels allowed. PCL not modified for indoor channels"); + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < *pcl_len_org; i++) { + if (wlan_reg_is_freq_indoor_in_secondary_list(pm_ctx->pdev, + pcl_list_org[i])) { + policy_mgr_debug("Remove freq: %d from PCL as it's indoor", + pcl_list_org[i]); + continue; + } + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + + qdf_mem_zero(pcl_list_org, *pcl_len_org * sizeof(*pcl_list_org)); + qdf_mem_zero(weight_list_org, *pcl_len_org); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len * sizeof(*pcl_list_org)); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_modify_sap_pcl_for_6G_channels() - filter out the + * 6GHz channels where SCC is not supported. + * @psoc: pointer to soc + * @pcl_list_org: channel list to filter out + * @weight_list_org: weight of channel list + * @pcl_len_org: length of channel list + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_modify_sap_pcl_for_6G_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + uint32_t vdev_id = 0, pcl_len = 0, i; + struct wlan_objmgr_vdev *vdev; + qdf_freq_t sta_gc_6ghz_freq = 0; + uint32_t ap_pwr_type_6g = 0; + bool indoor_ch_support = false; + bool keep_6ghz_sta_cli_conn; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if ((pm_conc_connection_list[i].mode == PM_STA_MODE || + pm_conc_connection_list[i].mode == PM_P2P_CLIENT_MODE) && + pm_conc_connection_list[i].in_use) { + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(pm_conc_connection_list[i].freq)) + continue; + sta_gc_6ghz_freq = pm_conc_connection_list[i].freq; + vdev_id = pm_conc_connection_list[i].vdev_id; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (!sta_gc_6ghz_freq) + return QDF_STATUS_SUCCESS; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d is not present", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* If STA is present in 6GHz PSC, STA+SAP SCC is allowed + * only for the following combinations: + * + * VLP STA + SAP - Allowed with VLP Power + * LPI STA + SAP - Allowed with VLP power if channel supports VLP. + * LPI STA + SAP - Allowed with LPI power if gindoor_channel_support=1 + */ + ap_pwr_type_6g = wlan_mlme_get_6g_ap_power_type(vdev); + policy_mgr_debug("STA power type : %d", ap_pwr_type_6g); + + ucfg_mlme_get_indoor_channel_support(psoc, &indoor_ch_support); + keep_6ghz_sta_cli_conn = wlan_reg_get_keep_6ghz_sta_cli_connection( + pm_ctx->pdev); + for (i = 0; i < *pcl_len_org; i++) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl_list_org[i])) { + if (!WLAN_REG_IS_6GHZ_PSC_CHAN_FREQ(pcl_list_org[i]) || + keep_6ghz_sta_cli_conn) + continue; + if (ap_pwr_type_6g == REG_VERY_LOW_POWER_AP) + goto add_freq; + else if (ap_pwr_type_6g == REG_INDOOR_AP && + (!wlan_reg_is_freq_indoor(pm_ctx->pdev, + pcl_list_org[i]) || + indoor_ch_support)) + goto add_freq; + else + continue; + } +add_freq: + pcl_list[pcl_len] = pcl_list_org[i]; + weight_list[pcl_len++] = weight_list_org[i]; + } + + qdf_mem_zero(pcl_list_org, *pcl_len_org * sizeof(*pcl_list_org)); + qdf_mem_zero(weight_list_org, *pcl_len_org * sizeof(*weight_list_org)); + qdf_mem_copy(pcl_list_org, pcl_list, pcl_len * sizeof(*pcl_list_org)); + qdf_mem_copy(weight_list_org, weight_list, pcl_len); + *pcl_len_org = pcl_len; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_channel_mcc_with_non_sap() - Helper function to check if channel + * is MCC with exist non-movable connections. + * @psoc: pointer to SOC + * @chan_freq: channel frequency to check + * + * Return: true if is MCC with exist non-movable connections, otherwise false. + */ +static bool policy_mgr_channel_mcc_with_non_sap(struct wlan_objmgr_psoc *psoc, + qdf_freq_t chan_freq) +{ + uint32_t i, connection_of_2ghz = 0; + qdf_freq_t conc_freq; + bool is_mcc = false, check_only_dbs = false; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use && + WLAN_REG_IS_24GHZ_CH_FREQ(pm_conc_connection_list[i].freq)) + connection_of_2ghz++; + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (connection_of_2ghz >= 2) + check_only_dbs = true; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use && + (pm_conc_connection_list[i].mode == PM_STA_MODE || + pm_conc_connection_list[i].mode == PM_P2P_CLIENT_MODE || + pm_conc_connection_list[i].mode == PM_P2P_GO_MODE)) { + conc_freq = pm_conc_connection_list[i].freq; + if (conc_freq != chan_freq && + ((check_only_dbs && + policy_mgr_2_freq_same_mac_in_dbs(pm_ctx, + chan_freq, + conc_freq)) || + policy_mgr_2_freq_always_on_same_mac(psoc, + chan_freq, + conc_freq))) { + is_mcc = true; + break; + } + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return is_mcc; +} + +/** + * policy_mgr_modify_sap_pcl_filter_mcc() - API to filter out MCC channel with + * existing non-SAP connection frequency from SAP PCL list. + * @psoc: pointer to SOC + * @pcl_list_org: channel list to filter out + * @weight_list_org: weight of channel list + * @pcl_len_org: length of channel list + * @mode: Policy manager connection mode + * + * Return: QDF_STATUS + */ +static QDF_STATUS +policy_mgr_modify_sap_pcl_filter_mcc(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org, + enum policy_mgr_con_mode mode) +{ + uint32_t i, pcl_len = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + if (mode == PM_LL_LT_SAP_MODE) + return QDF_STATUS_SUCCESS; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + + if (!policy_mgr_is_force_scc(psoc)) { + policy_mgr_debug("force SCC is not prefer, skip!"); + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < *pcl_len_org; i++) { + if (policy_mgr_channel_mcc_with_non_sap(psoc, pcl_list_org[i])) + continue; + + pcl_list_org[pcl_len] = pcl_list_org[i]; + weight_list_org[pcl_len++] = weight_list_org[i]; + } + + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * policy_mgr_modify_sap_go_4th_conc_disallow() - filter out channel that + * is not allowed for 4th sap/go connection + * @psoc: pointer to soc + * @mode: interface mode + * @pcl_list_org: channel list to filter out + * @weight_list_org: weight of channel list + * @pcl_len_org: length of channel list + * + * Return: QDF_STATUS + */ +static QDF_STATUS policy_mgr_modify_sap_go_4th_conc_disallow( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_list_org, + uint8_t *weight_list_org, + uint32_t *pcl_len_org) +{ + size_t i, pcl_len = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t num_connections; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + if (*pcl_len_org > NUM_CHANNELS) { + policy_mgr_err("Invalid PCL List Length %d", *pcl_len_org); + return QDF_STATUS_E_FAILURE; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + num_connections = policy_mgr_get_connection_count(psoc); + if (num_connections < 3) + goto end; + + for (i = 0; i < *pcl_len_org; i++) { + if (policy_mgr_allow_4th_new_freq(psoc, pcl_list_org[i], + mode, 0)) { + pcl_list_org[pcl_len] = pcl_list_org[i]; + weight_list_org[pcl_len++] = weight_list_org[i]; + } + } + + *pcl_len_org = pcl_len; +end: + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_pcl_modification_for_sap( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, uint8_t *pcl_weight, + uint32_t *len, uint32_t weight_len, + enum policy_mgr_con_mode mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool mandatory_modified_pcl = false; + bool nol_modified_pcl = false; + bool dfs_modified_pcl = false; + bool indoor_modified_pcl = false; + bool passive_modified_pcl = false; + bool band_6ghz_modified_pcl = false; + bool fourth_conc_modified_pcl = false; + bool modified_final_pcl = false; + bool srd_chan_enabled; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid context"); + return QDF_STATUS_E_FAILURE; + } + + /* check the channel avoidance list for beaconing entities */ + policy_mgr_update_with_safe_channel_list(psoc, pcl_channels, + len, pcl_weight, weight_len); + + if (policy_mgr_is_sap_mandatory_channel_set(psoc)) { + status = policy_mgr_modify_sap_pcl_based_on_mandatory_channel( + psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err( + "failed to get mandatory modified pcl for SAP"); + return status; + } + mandatory_modified_pcl = true; + } + + status = policy_mgr_modify_sap_pcl_based_on_nol( + psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get nol modified pcl for SAP"); + return status; + } + nol_modified_pcl = true; + + status = policy_mgr_modify_sap_pcl_based_on_dfs( + psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get dfs modified pcl for SAP"); + return status; + } + dfs_modified_pcl = true; + + wlan_mlme_get_srd_master_mode_for_vdev(psoc, QDF_SAP_MODE, + &srd_chan_enabled); + + if (!srd_chan_enabled) { + status = policy_mgr_modify_pcl_based_on_srd + (psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to modify SRD in pcl for SAP"); + return status; + } + } + + status = policy_mgr_modify_pcl_based_on_indoor(psoc, pcl_channels, + pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get indoor modified pcl for SAP"); + return status; + } + indoor_modified_pcl = true; + + status = policy_mgr_filter_passive_ch(pm_ctx->pdev, + pcl_channels, len); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to filter passive channels"); + return INVALID_CHANNEL_ID; + } + passive_modified_pcl = true; + + status = policy_mgr_modify_sap_pcl_for_6G_channels(psoc, + pcl_channels, + pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to modify pcl for 6G channels"); + return status; + } + band_6ghz_modified_pcl = true; + + status = policy_mgr_modify_sap_go_4th_conc_disallow(psoc, + PM_SAP_MODE, + pcl_channels, + pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to modify pcl for 4th sap channels"); + return status; + } + fourth_conc_modified_pcl = true; + + status = policy_mgr_modify_sap_pcl_filter_mcc(psoc, + pcl_channels, + pcl_weight, len, + mode); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to modify pcl for filter mcc"); + return status; + } + + modified_final_pcl = true; + policy_mgr_debug("%d %d %d %d %d %d %d %d", + mandatory_modified_pcl, + nol_modified_pcl, + dfs_modified_pcl, + indoor_modified_pcl, + passive_modified_pcl, + band_6ghz_modified_pcl, + fourth_conc_modified_pcl, + modified_final_pcl); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS policy_mgr_pcl_modification_for_p2p_go( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, uint8_t *pcl_weight, + uint32_t *len, uint32_t weight_len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool srd_chan_enabled; + + /* check the channel avoidance list for beaconing entities */ + policy_mgr_update_with_safe_channel_list(psoc, pcl_channels, + len, pcl_weight, weight_len); + + status = policy_mgr_modify_pcl_based_on_enabled_channels( + psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get modified pcl for GO"); + return status; + } + + status = policy_mgr_modify_sap_pcl_based_on_dfs( + psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get dfs modified pcl for GO"); + return status; + } + + wlan_mlme_get_srd_master_mode_for_vdev(psoc, QDF_P2P_GO_MODE, + &srd_chan_enabled); + + if (!srd_chan_enabled) { + status = policy_mgr_modify_pcl_based_on_srd + (psoc, pcl_channels, pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Failed to modify SRD in pcl for GO"); + return status; + } + } + status = policy_mgr_modify_sap_go_4th_conc_disallow(psoc, + PM_P2P_GO_MODE, + pcl_channels, + pcl_weight, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to modify pcl for 4th go channels"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_LL_LT_SAP +#ifdef WLAN_FEATURE_LL_LT_SAP_6G_SUPPORT +static bool policy_mgr_is_6G_chan_valid_for_ll_sap(qdf_freq_t freq) +{ + if (!wlan_reg_is_6ghz_chan_freq(freq)) + return true; + + if (wlan_reg_is_6ghz_psc_chan_freq(freq) && + wlan_reg_is_6ghz_unii5_chan_freq(freq)) + return true; + + return false; +} +#else +static inline bool policy_mgr_is_6G_chan_valid_for_ll_sap(qdf_freq_t freq) +{ + if (!wlan_reg_is_6ghz_chan_freq(freq)) + return true; + + return false; +} +#endif + +static bool policy_mgr_is_dynamic_sbs_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + return (policy_mgr_is_hw_sbs_capable(psoc) && + policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx)); +} + +/** + * policy_mgr_is_sbs_mac0_freq() - Check if the given frequency is + * sbs frequency on mac0 for static sbs case. + * @psoc: psoc pointer + * @freq: Frequency which needs to be checked. + * + * Return: true/false. + */ +static bool policy_mgr_is_sbs_mac0_freq(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_freq_range *freq_range; + + if (policy_mgr_is_dynamic_sbs_enabled(psoc)) + return false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return false; + + freq_range = pm_ctx->hw_mode.freq_range_caps[MODE_SBS]; + + if (policy_mgr_is_freq_on_mac_id(freq_range, freq, 0)) + return true; + + return false; +} + +static QDF_STATUS policy_mgr_pcl_modification_for_ll_lt_sap( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, uint8_t *pcl_weight, + uint32_t *len, uint32_t weight_len) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t pcl_list[NUM_CHANNELS], orig_len = *len; + uint8_t weight_list[NUM_CHANNELS]; + uint32_t i, pcl_len = 0; + bool sbs_mac0_modified_pcl = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_pcl_modification_for_sap( + psoc, pcl_channels, pcl_weight, len, weight_len, + PM_LL_LT_SAP_MODE); + + for (i = 0; i < *len; i++) { + /* Remove passive/dfs/6G invalid channel for LL_LT_SAP */ + if (wlan_reg_is_24ghz_ch_freq(pcl_channels[i]) || + wlan_reg_is_passive_for_freq( + pm_ctx->pdev, + pcl_channels[i]) || + wlan_reg_is_dfs_for_freq( + pm_ctx->pdev, + pcl_channels[i]) || + !policy_mgr_is_6G_chan_valid_for_ll_sap(pcl_channels[i])) + continue; + + /* Remove mac0 frequencies for static SBS case */ + if (policy_mgr_is_sbs_mac0_freq(psoc, pcl_channels[i])) { + sbs_mac0_modified_pcl = true; + continue; + } + + pcl_list[pcl_len] = pcl_channels[i]; + weight_list[pcl_len++] = pcl_weight[i]; + } + + if (orig_len == pcl_len) + return QDF_STATUS_SUCCESS; + + qdf_mem_zero(pcl_channels, *len * sizeof(*pcl_channels)); + qdf_mem_zero(pcl_weight, *len); + qdf_mem_copy(pcl_channels, pcl_list, pcl_len * sizeof(*pcl_channels)); + qdf_mem_copy(pcl_weight, weight_list, pcl_len); + *len = pcl_len; + + policy_mgr_debug("sbs_mac0_modified_pcl %d, PCL after ll sap modification", + sbs_mac0_modified_pcl); + policy_mgr_dump_channel_list(*len, pcl_channels, pcl_weight); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +policy_mgr_pcl_modification_for_ll_lt_sap(struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, + uint8_t *pcl_weight, + uint32_t *len, uint32_t weight_len) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS policy_mgr_mode_specific_modification_on_pcl( + struct wlan_objmgr_psoc *psoc, + uint32_t *pcl_channels, uint8_t *pcl_weight, + uint32_t *len, uint32_t weight_len, + enum policy_mgr_con_mode mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + switch (mode) { + case PM_SAP_MODE: + status = policy_mgr_pcl_modification_for_sap( + psoc, pcl_channels, pcl_weight, len, weight_len, mode); + break; + case PM_P2P_GO_MODE: + status = policy_mgr_pcl_modification_for_p2p_go( + psoc, pcl_channels, pcl_weight, len, weight_len); + break; + case PM_STA_MODE: + case PM_P2P_CLIENT_MODE: + case PM_NAN_DISC_MODE: + status = QDF_STATUS_SUCCESS; + break; + case PM_LL_LT_SAP_MODE: + status = policy_mgr_pcl_modification_for_ll_lt_sap( + psoc, pcl_channels, pcl_weight, len, weight_len); + break; + default: + policy_mgr_err("unexpected mode %d", mode); + break; + } + + return status; +} + +#ifdef FEATURE_FOURTH_CONNECTION +static enum policy_mgr_pcl_type policy_mgr_get_pcl_4_port( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + enum policy_mgr_conc_priority_mode pref) +{ + enum policy_mgr_three_connection_mode fourth_index = 0; + enum policy_mgr_pcl_type pcl; + + /* Will be enhanced for other types of 4 port conc (NaN etc.) + * in future. + */ + if (!policy_mgr_is_hw_dbs_capable(psoc)) { + policy_mgr_err("Can't find index for 4th port pcl table for non dbs capable"); + return PM_MAX_PCL_TYPE; + } + + /* SAP and P2P Go have same result in 4th port pcl table */ + if (mode == PM_SAP_MODE || mode == PM_P2P_GO_MODE) + mode = PM_SAP_MODE; + else if (mode == PM_P2P_CLIENT_MODE) + mode = PM_STA_MODE; + + if (mode != PM_STA_MODE && mode != PM_SAP_MODE && + mode != PM_NDI_MODE) { + policy_mgr_err("Can't start 4th port if not STA, SAP, NDI"); + return PM_MAX_PCL_TYPE; + } + + fourth_index = + policy_mgr_get_fourth_connection_pcl_table_index(psoc); + if (PM_MAX_THREE_CONNECTION_MODE == fourth_index) { + policy_mgr_err("Can't find index for 4th port pcl table"); + return PM_MAX_PCL_TYPE; + } + policy_mgr_debug("Index for 4th port pcl table: %d", fourth_index); + + pcl = fourth_connection_pcl_dbs_sbs_table[fourth_index][mode][pref]; + + return pcl; +} +#else +static inline enum policy_mgr_pcl_type policy_mgr_get_pcl_4_port( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + enum policy_mgr_conc_priority_mode pref) +{return PM_MAX_PCL_TYPE; } +#endif + +QDF_STATUS policy_mgr_get_pcl(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + uint32_t *pcl_channels, uint32_t *len, + uint8_t *pcl_weight, uint32_t weight_len, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t num_connections = 0; + enum policy_mgr_conc_priority_mode first_index = 0; + enum policy_mgr_one_connection_mode second_index = 0; + enum policy_mgr_two_connection_mode third_index = 0; + enum policy_mgr_pcl_type pcl = PM_NONE; + enum policy_mgr_conc_priority_mode conc_system_pref = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum QDF_OPMODE qdf_mode; + uint32_t orig_pcl_len; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return status; + } + + if ((mode < 0) || (mode >= PM_MAX_NUM_OF_MODE)) { + policy_mgr_err("Invalid connection mode %d received", mode); + return status; + } + + /* find the current connection state from pm_conc_connection_list*/ + num_connections = policy_mgr_get_connection_count(psoc); + policy_mgr_debug("connections:%d pref:%d requested mode:%d vdev_id:%d", + num_connections, pm_ctx->cur_conc_system_pref, mode, + vdev_id); + + switch (pm_ctx->cur_conc_system_pref) { + case 0: + conc_system_pref = PM_THROUGHPUT; + break; + case 1: + conc_system_pref = PM_POWERSAVE; + break; + case 2: + conc_system_pref = PM_LATENCY; + break; + default: + policy_mgr_err("unknown cur_conc_system_pref value %d", + pm_ctx->cur_conc_system_pref); + break; + } + + switch (num_connections) { + case 0: + first_index = + policy_mgr_get_first_connection_pcl_table_index(psoc); + pcl = first_connection_pcl_table[mode][first_index]; + break; + case 1: + second_index = + policy_mgr_get_second_connection_pcl_table_index(psoc); + if (PM_MAX_ONE_CONNECTION_MODE == second_index) { + policy_mgr_err("couldn't find index for 2nd connection pcl table"); + return status; + } + qdf_mode = policy_mgr_get_qdf_mode_from_pm(mode); + if (qdf_mode == QDF_MAX_NO_OF_MODE) + return status; + + if (policy_mgr_is_hw_dbs_capable(psoc) == true && + policy_mgr_is_dbs_allowed_for_concurrency( + psoc, qdf_mode)) { + pcl = (*second_connection_pcl_dbs_table) + [second_index][mode][conc_system_pref]; + } else { + pcl = (*second_connection_pcl_non_dbs_table) + [second_index][mode][conc_system_pref]; + } + + break; + case 2: + third_index = + policy_mgr_get_third_connection_pcl_table_index(psoc); + if (PM_MAX_TWO_CONNECTION_MODE == third_index) { + policy_mgr_err( + "couldn't find index for 3rd connection pcl table"); + return status; + } + if (policy_mgr_is_hw_dbs_capable(psoc) == true) { + pcl = (*third_connection_pcl_dbs_table) + [third_index][mode][conc_system_pref]; + } else { + pcl = (*third_connection_pcl_non_dbs_table) + [third_index][mode][conc_system_pref]; + } + break; + case 3: + pcl = policy_mgr_get_pcl_4_port(psoc, mode, conc_system_pref); + break; + default: + policy_mgr_err("unexpected num_connections value %d", + num_connections); + break; + } + + /* once the PCL enum is obtained find out the exact channel list with + * help from sme_get_cfg_valid_channels + */ + status = policy_mgr_get_channel_list(psoc, pcl, mode, pcl_channels, + pcl_weight, weight_len, len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get channel list:%d", status); + return status; + } + + if (!*len) { + policymgr_nofl_debug("Total PCL Chan %d", *len); + return QDF_STATUS_SUCCESS; + } + orig_pcl_len = *len; + policy_mgr_dump_channel_list(*len, pcl_channels, pcl_weight); + policy_mgr_mode_specific_modification_on_pcl( + psoc, pcl_channels, pcl_weight, len, weight_len, mode); + + status = policy_mgr_modify_pcl_based_on_dnbs(psoc, pcl_channels, + pcl_weight, len); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get modified pcl based on DNBS"); + return status; + } + + if (orig_pcl_len != *len) { + policy_mgr_debug("PCL after modification"); + policy_mgr_dump_channel_list(*len, pcl_channels, pcl_weight); + } + + return QDF_STATUS_SUCCESS; +} + +enum policy_mgr_conc_priority_mode + policy_mgr_get_first_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return PM_THROUGHPUT; + } + + if (pm_ctx->cur_conc_system_pref >= PM_MAX_CONC_PRIORITY_MODE) + return PM_THROUGHPUT; + + return pm_ctx->cur_conc_system_pref; +} + +enum policy_mgr_one_connection_mode + policy_mgr_get_second_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_one_connection_mode index = PM_MAX_ONE_CONNECTION_MODE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return index; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (PM_STA_MODE == pm_conc_connection_list[0].mode) { + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_STA_24_1x1; + else + index = PM_STA_24_2x2; + } else { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_STA_5_1x1; + else + index = PM_STA_5_2x2; + } + } else if (PM_SAP_MODE == pm_conc_connection_list[0].mode) { + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_SAP_24_1x1; + else + index = PM_SAP_24_2x2; + } else { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_SAP_5_1x1; + else + index = PM_SAP_5_2x2; + } + } else if (PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) { + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_P2P_CLI_24_1x1; + else + index = PM_P2P_CLI_24_2x2; + } else { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_P2P_CLI_5_1x1; + else + index = PM_P2P_CLI_5_2x2; + } + } else if (PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) { + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_P2P_GO_24_1x1; + else + index = PM_P2P_GO_24_2x2; + } else { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_P2P_GO_5_1x1; + else + index = PM_P2P_GO_5_2x2; + } + } else if (PM_NAN_DISC_MODE == pm_conc_connection_list[0].mode) { + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_NAN_DISC_24_1x1; + else + index = PM_NAN_DISC_24_2x2; + } else if (PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) { + index = PM_LL_LT_SAP_5_2x2; + } + + policy_mgr_debug("mode:%d freq:%d chain:%d index:%d", + pm_conc_connection_list[0].mode, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[0].chain_mask, index); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return index; +} + +/* + * policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc() - + * This function checks connection mode is in scc or not and returns + * index value based on mode and prvided index inputs. + * + * @scc_2g_1x1: index of scc_2g_1x1 for provided concurrency + * @scc_2g_2x2: index of scc_2g_2x2 for provided concurrency + * @scc_5g_1x1: index of scc_5g_1x1 for provided concurrency + * @scc_5g_2x2: index of scc_5g_2x2 for provided concurrency + * + * Return: policy_mgr_two_connection_mode index + */ +static enum policy_mgr_two_connection_mode +policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + enum policy_mgr_two_connection_mode scc_2g_1x1, + enum policy_mgr_two_connection_mode scc_2g_2x2, + enum policy_mgr_two_connection_mode scc_5g_1x1, + enum policy_mgr_two_connection_mode scc_5g_2x2) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq) { + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = scc_2g_1x1; + else + index = scc_2g_2x2; + } else { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = scc_5g_1x1; + else + index = scc_5g_2x2; + } + } + return index; +} + +/* + * policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc() - + * This function checks connection mode is in mcc or not and returns + * index value based on mode and prvided index inputs. + * + * @mcc_2g_1x1: index of mcc_2g_1x1 for provided concurrency + * @mcc_2g_2x2: index of mcc_2g_2x2 for provided concurrency + * @mcc_5g_1x1: index of mcc_5g_1x1 for provided concurrency + * @mcc_5g_2x2: index of mcc_5g_2x2 for provided concurrency + * @mcc_24_5_1x1: index of mcc_24_5_1x1 for provided concurrency + * @mcc_24_5_2x2: index of mcc_24_5_2x2 for provided concurrency + * + * Return: policy_mgr_two_connection_mode index + */ +static enum policy_mgr_two_connection_mode +policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_two_connection_mode mcc_2g_1x1, + enum policy_mgr_two_connection_mode mcc_2g_2x2, + enum policy_mgr_two_connection_mode mcc_5g_1x1, + enum policy_mgr_two_connection_mode mcc_5g_2x2, + enum policy_mgr_two_connection_mode mcc_24_5_1x1, + enum policy_mgr_two_connection_mode mcc_24_5_2x2) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + if (policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq) + ) { + if ((WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = mcc_2g_1x1; + else + index = mcc_2g_2x2; + } else if (!(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + !(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = mcc_5g_1x1; + else + index = mcc_5g_2x2; + } else { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = mcc_24_5_1x1; + else + index = mcc_24_5_2x2; + } + } + return index; +} + +/* + * policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs() - + * This function checks connection mode is in dbs or sbs and returns index + * value based on mode and prvided index inputs. + * + * @sbs_5g_1x1: index of sbs_5g_1x1 for provided concurrency + * @sbs_5g_2x2: index of sbs_5g_2x2 for provided concurrency + * @dbs_1x1: index of dbs_1x1 for provided concurrency + * @dbs_2x2: index of dbs_2x2 for provided concurrency + * + * Return: policy_mgr_two_connection_mode index + */ +static enum policy_mgr_two_connection_mode +policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_two_connection_mode sbs_5g_1x1, + enum policy_mgr_two_connection_mode sbs_5g_2x2, + enum policy_mgr_two_connection_mode dbs_1x1, + enum policy_mgr_two_connection_mode dbs_2x2) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + if (!policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq) + ) { + /* SBS */ + if (!(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + !(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = sbs_5g_1x1; + else + index = sbs_5g_2x2; + } else { + /* DBS */ + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = dbs_1x1; + else + index = dbs_2x2; + } + } + + return index; +} + +/* + * policy_mgr_get_3rd_pcl_table_index_for_dbs_with_ml_sta() - + * Get third connection pcl table index when ML STA is present + * @sbs_5g_1x1: index of sbs_5g_1x1 for provided concurrency + * @sbs_5g_2x2: index of sbs_5g_2x2 for provided concurrency + * @dbs_1x1: index of dbs_1x1 for provided concurrency + * @dbs_2x2: index of dbs_2x2 for provided concurrency + * + * This function checks connection mode is in dbs or sbs when two ML STA links + * are active and returns index value based on mode and provided index inputs. + * + * Return: policy_mgr_two_connection_mode index + */ +static enum policy_mgr_two_connection_mode +policy_mgr_get_3rd_pcl_table_index_for_dbs_with_ml_sta( + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_two_connection_mode sbs_5g_1x1, + enum policy_mgr_two_connection_mode sbs_5g_2x2, + enum policy_mgr_two_connection_mode dbs_1x1, + enum policy_mgr_two_connection_mode dbs_2x2) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + if (!policy_mgr_2_freq_always_on_same_mac( + psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + /* SBS */ + if (!(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + !(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = sbs_5g_1x1; + else + index = sbs_5g_2x2; + } else { + /* DBS */ + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = dbs_1x1; + else + index = dbs_2x2; + } + } + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_cli_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_P2P_CLI_SAP_SCC_24_1x1, + PM_P2P_CLI_SAP_SCC_24_2x2, + PM_P2P_CLI_SAP_SCC_5_1x1, + PM_P2P_CLI_SAP_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_P2P_CLI_SAP_MCC_24_1x1, + PM_P2P_CLI_SAP_MCC_24_2x2, + PM_P2P_CLI_SAP_MCC_5_1x1, + PM_P2P_CLI_SAP_MCC_5_2x2, + PM_P2P_CLI_SAP_MCC_24_5_1x1, + PM_P2P_CLI_SAP_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_P2P_CLI_SAP_SBS_5_1x1, + PM_P2P_CLI_SAP_SBS_5_2x2, + PM_P2P_CLI_SAP_DBS_1x1, + PM_P2P_CLI_SAP_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sta_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_STA_SAP_SCC_24_1x1, + PM_STA_SAP_SCC_24_2x2, + PM_STA_SAP_SCC_5_1x1, + PM_STA_SAP_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_STA_SAP_MCC_24_1x1, + PM_STA_SAP_MCC_24_2x2, + PM_STA_SAP_MCC_5_1x1, + PM_STA_SAP_MCC_5_2x2, + PM_STA_SAP_MCC_24_5_1x1, + PM_STA_SAP_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_STA_SAP_SBS_5_1x1, + PM_STA_SAP_SBS_5_2x2, + PM_STA_SAP_DBS_1x1, + PM_STA_SAP_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sap_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_SAP_SAP_SCC_24_1x1, + PM_SAP_SAP_SCC_24_2x2, + PM_SAP_SAP_SCC_5_1x1, + PM_SAP_SAP_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_SAP_SAP_MCC_24_1x1, + PM_SAP_SAP_MCC_24_2x2, + PM_SAP_SAP_MCC_5_1x1, + PM_SAP_SAP_MCC_5_2x2, + PM_SAP_SAP_MCC_24_5_1x1, + PM_SAP_SAP_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_SAP_SAP_SBS_5_1x1, + PM_SAP_SAP_SBS_5_2x2, + PM_SAP_SAP_DBS_1x1, + PM_SAP_SAP_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sta_go( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_STA_P2P_GO_SCC_24_1x1, + PM_STA_P2P_GO_SCC_24_2x2, + PM_STA_P2P_GO_SCC_5_1x1, + PM_STA_P2P_GO_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_STA_P2P_GO_MCC_24_1x1, + PM_STA_P2P_GO_MCC_24_2x2, + PM_STA_P2P_GO_MCC_5_1x1, + PM_STA_P2P_GO_MCC_5_2x2, + PM_STA_P2P_GO_MCC_24_5_1x1, + PM_STA_P2P_GO_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_STA_P2P_GO_SBS_5_1x1, + PM_STA_P2P_GO_SBS_5_2x2, + PM_STA_P2P_GO_DBS_1x1, + PM_STA_P2P_GO_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sta_cli( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_STA_P2P_CLI_SCC_24_1x1, + PM_STA_P2P_CLI_SCC_24_2x2, + PM_STA_P2P_CLI_SCC_5_1x1, + PM_STA_P2P_CLI_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_STA_P2P_CLI_MCC_24_1x1, + PM_STA_P2P_CLI_MCC_24_2x2, + PM_STA_P2P_CLI_MCC_5_1x1, + PM_STA_P2P_CLI_MCC_5_2x2, + PM_STA_P2P_CLI_MCC_24_5_1x1, + PM_STA_P2P_CLI_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_STA_P2P_CLI_SBS_5_1x1, + PM_STA_P2P_CLI_SBS_5_2x2, + PM_STA_P2P_CLI_DBS_1x1, + PM_STA_P2P_CLI_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_go_cli( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_P2P_GO_P2P_CLI_SCC_24_1x1, + PM_P2P_GO_P2P_CLI_SCC_24_2x2, + PM_P2P_GO_P2P_CLI_SCC_5_1x1, + PM_P2P_GO_P2P_CLI_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_P2P_GO_P2P_CLI_MCC_24_1x1, + PM_P2P_GO_P2P_CLI_MCC_24_2x2, + PM_P2P_GO_P2P_CLI_MCC_5_1x1, + PM_P2P_GO_P2P_CLI_MCC_5_2x2, + PM_P2P_GO_P2P_CLI_MCC_24_5_1x1, + PM_P2P_GO_P2P_CLI_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_P2P_GO_P2P_CLI_SBS_5_1x1, + PM_P2P_GO_P2P_CLI_SBS_5_2x2, + PM_P2P_GO_P2P_CLI_DBS_1x1, + PM_P2P_GO_P2P_CLI_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_go_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_P2P_GO_SAP_SCC_24_1x1, + PM_P2P_GO_SAP_SCC_24_2x2, + PM_P2P_GO_SAP_SCC_5_1x1, + PM_P2P_GO_SAP_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_P2P_GO_SAP_MCC_24_1x1, + PM_P2P_GO_SAP_MCC_24_2x2, + PM_P2P_GO_SAP_MCC_5_1x1, + PM_P2P_GO_SAP_MCC_5_2x2, + PM_P2P_GO_SAP_MCC_24_5_1x1, + PM_P2P_GO_SAP_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_P2P_GO_SAP_SBS_5_1x1, + PM_P2P_GO_SAP_SBS_5_2x2, + PM_P2P_GO_SAP_DBS_1x1, + PM_P2P_GO_SAP_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sta_sta( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + + if (policy_mgr_is_ml_vdev_id(psoc, + pm_conc_connection_list[0].vdev_id) && + policy_mgr_is_ml_vdev_id(psoc, + pm_conc_connection_list[1].vdev_id)) { + index = + policy_mgr_get_3rd_pcl_table_index_for_dbs_with_ml_sta( + psoc, + PM_STA_STA_SBS_5_1x1, + PM_STA_STA_SBS_5_2x2, + PM_STA_STA_DBS_1x1, + PM_STA_STA_DBS_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + } + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_STA_STA_SCC_24_1x1, + PM_STA_STA_SCC_24_2x2, + PM_STA_STA_SCC_5_1x1, + PM_STA_STA_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_STA_STA_MCC_24_1x1, + PM_STA_STA_MCC_24_2x2, + PM_STA_STA_MCC_5_1x1, + PM_STA_STA_MCC_5_2x2, + PM_STA_STA_MCC_24_5_1x1, + PM_STA_STA_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_STA_STA_SBS_5_1x1, + PM_STA_STA_SBS_5_2x2, + PM_STA_STA_DBS_1x1, + PM_STA_STA_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_cli_cli( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_P2P_CLI_P2P_CLI_SCC_24_1x1, + PM_P2P_CLI_P2P_CLI_SCC_24_2x2, + PM_P2P_CLI_P2P_CLI_SCC_5_1x1, + PM_P2P_CLI_P2P_CLI_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_P2P_CLI_P2P_CLI_MCC_24_1x1, + PM_P2P_CLI_P2P_CLI_MCC_24_2x2, + PM_P2P_CLI_P2P_CLI_MCC_5_1x1, + PM_P2P_CLI_P2P_CLI_MCC_5_2x2, + PM_P2P_CLI_P2P_CLI_MCC_24_5_1x1, + PM_P2P_CLI_P2P_CLI_MCC_24_5_2x2); + + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_P2P_CLI_P2P_CLI_SBS_5_1x1, + PM_P2P_CLI_P2P_CLI_SBS_5_2x2, + PM_P2P_CLI_P2P_CLI_DBS_1x1, + PM_P2P_CLI_P2P_CLI_DBS_2x2); + + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_go_go( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_scc( + PM_P2P_GO_P2P_GO_SCC_24_1x1, + PM_P2P_GO_P2P_GO_SCC_24_2x2, + PM_P2P_GO_P2P_GO_SCC_5_1x1, + PM_P2P_GO_P2P_GO_SCC_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_mcc(psoc, + PM_P2P_GO_P2P_GO_MCC_24_1x1, + PM_P2P_GO_P2P_GO_MCC_24_2x2, + PM_P2P_GO_P2P_GO_MCC_5_1x1, + PM_P2P_GO_P2P_GO_MCC_5_2x2, + PM_P2P_GO_P2P_GO_MCC_24_5_1x1, + PM_P2P_GO_P2P_GO_MCC_24_5_2x2); + if (index != PM_MAX_TWO_CONNECTION_MODE) + return index; + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs(psoc, + PM_P2P_GO_P2P_GO_SBS_5_1x1, + PM_P2P_GO_P2P_GO_SBS_5_2x2, + PM_P2P_GO_P2P_GO_DBS_1x1, + PM_P2P_GO_P2P_GO_DBS_2x2); + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_nan_ndi( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + /* SCC */ + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_NAN_DISC_NDI_SCC_24_1x1; + else + index = PM_NAN_DISC_NDI_SCC_24_2x2; + /* MCC */ + } else if (policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_NAN_DISC_NDI_MCC_24_1x1; + else + index = PM_NAN_DISC_NDI_MCC_24_2x2; + /* DBS */ + } else { + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_NAN_DISC_NDI_DBS_1x1; + else + index = PM_NAN_DISC_NDI_DBS_2x2; + } + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sta_nan( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + /* SCC */ + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_STA_NAN_DISC_SCC_24_1x1; + else + index = PM_STA_NAN_DISC_SCC_24_2x2; + /* MCC */ + } else if (policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + /* Policy mgr only considers NAN Disc ch in 2.4 GHz */ + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_STA_NAN_DISC_MCC_24_1x1; + else + index = PM_STA_NAN_DISC_MCC_24_2x2; + /* DBS */ + } else { + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_STA_NAN_DISC_DBS_1x1; + else + index = PM_STA_NAN_DISC_DBS_2x2; + } + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sap_nan( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + /* SCC */ + if (pm_conc_connection_list[0].freq == + pm_conc_connection_list[1].freq) { + /* Policy mgr only considers NAN Disc ch in 2.4 GHz */ + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_SAP_NAN_DISC_SCC_24_1x1; + else + index = PM_SAP_NAN_DISC_SCC_24_2x2; + /* MCC */ + } else if (policy_mgr_are_2_freq_on_same_mac(psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_SAP_NAN_DISC_MCC_24_1x1; + else + index = PM_SAP_NAN_DISC_MCC_24_2x2; + /* DBS */ + } else { + if (POLICY_MGR_ONE_ONE == pm_conc_connection_list[0].chain_mask) + index = PM_SAP_NAN_DISC_DBS_1x1; + else + index = PM_SAP_NAN_DISC_DBS_2x2; + } + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sta_ll_lt_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + enum policy_mgr_two_connection_mode sbs_5g_1x1; + enum policy_mgr_two_connection_mode sbs_5g_2x2; + qdf_freq_t sta_freq, sbs_cut_off_freq; + + /* + * LL_LT_SAP can not be in SCC so there will not be any scc index. + * With LL_LT_SAP, MCC is possible only on 5 GHz + */ + if (policy_mgr_are_2_freq_on_same_mac( + psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + if (!(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + !(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_STA_5_LL_LT_SAP_MCC_1x1; + else + index = PM_STA_5_LL_LT_SAP_MCC_2x2; + + return index; + } + } + + if (pm_conc_connection_list[0].mode == PM_STA_MODE) + sta_freq = pm_conc_connection_list[0].freq; + else + sta_freq = pm_conc_connection_list[1].freq; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + + if (sta_freq < sbs_cut_off_freq) { + sbs_5g_1x1 = PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1; + sbs_5g_2x2 = PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2; + } else { + sbs_5g_1x1 = PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1; + sbs_5g_2x2 = PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2; + } + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs( + psoc, sbs_5g_1x1, sbs_5g_2x2, + PM_STA_24_LL_LT_SAP_DBS_1x1, + PM_STA_24_LL_LT_SAP_DBS_2x2); + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_sap_ll_lt_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + enum policy_mgr_two_connection_mode sbs_5g_1x1; + enum policy_mgr_two_connection_mode sbs_5g_2x2; + qdf_freq_t sap_freq, sbs_cut_off_freq; + + if (pm_conc_connection_list[0].mode == PM_SAP_MODE) + sap_freq = pm_conc_connection_list[0].freq; + else + sap_freq = pm_conc_connection_list[1].freq; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + + if (sap_freq < sbs_cut_off_freq) { + sbs_5g_1x1 = PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1; + sbs_5g_2x2 = PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2; + } else { + sbs_5g_1x1 = PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1; + sbs_5g_2x2 = PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2; + } + + /* + * LL_LT_SAP can not be in SCC so there will not be any scc index. + * For LL_LT_SAP + SAP, MCC is not possible, so there will be only + * sbs or dbs index + */ + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs( + psoc, sbs_5g_1x1, sbs_5g_2x2, + PM_SAP_24_LL_LT_SAP_DBS_1x1, + PM_SAP_24_LL_LT_SAP_DBS_2x2); + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_go_ll_lt_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + enum policy_mgr_two_connection_mode sbs_5g_1x1; + enum policy_mgr_two_connection_mode sbs_5g_2x2; + qdf_freq_t go_freq, sbs_cut_off_freq; + + /* + * LL_LT_SAP can not be in SCC so there will not be any scc index. + * With LL_LT_SAP, MCC is possible only on 5 GHz + */ + if (policy_mgr_are_2_freq_on_same_mac( + psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + if (!(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + !(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_P2P_GO_5_LL_LT_SAP_MCC_1x1; + else + index = PM_P2P_GO_5_LL_LT_SAP_MCC_2x2; + + return index; + } + } + + if (pm_conc_connection_list[0].mode == PM_P2P_GO_MODE) + go_freq = pm_conc_connection_list[0].freq; + else + go_freq = pm_conc_connection_list[1].freq; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + + if (go_freq < sbs_cut_off_freq) { + sbs_5g_1x1 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1; + sbs_5g_2x2 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2; + } else { + sbs_5g_1x1 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1; + sbs_5g_2x2 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2; + } + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs( + psoc, sbs_5g_1x1, sbs_5g_2x2, + PM_P2P_GO_24_LL_LT_SAP_DBS_1x1, + PM_P2P_GO_24_LL_LT_SAP_DBS_2x2); + return index; +} + +static enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index_cli_ll_lt_sap( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index; + enum policy_mgr_two_connection_mode sbs_5g_1x1; + enum policy_mgr_two_connection_mode sbs_5g_2x2; + qdf_freq_t cli_freq, sbs_cut_off_freq; + + /* + * LL_LT_SAP can not be in SCC so there will not be any scc index. + * With LL_LT_SAP, MCC is possible only on 5 GHz + */ + if (policy_mgr_are_2_freq_on_same_mac( + psoc, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq)) { + if (!(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[0].freq)) && + !(WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[1].freq))) { + if (POLICY_MGR_ONE_ONE == + pm_conc_connection_list[0].chain_mask) + index = PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1; + else + index = PM_P2P_CLI_5_LL_LT_SAP_MCC_2x2; + + return index; + } + } + + if (pm_conc_connection_list[0].mode == PM_P2P_GO_MODE) + cli_freq = pm_conc_connection_list[0].freq; + else + cli_freq = pm_conc_connection_list[1].freq; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + + if (cli_freq < sbs_cut_off_freq) { + sbs_5g_1x1 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1; + sbs_5g_2x2 = PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_2x2; + } else { + sbs_5g_1x1 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1; + sbs_5g_2x2 = PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_2x2; + } + + index = + policy_mgr_check_and_get_third_connection_pcl_table_index_for_dbs( + psoc, sbs_5g_1x1, sbs_5g_2x2, + PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1, + PM_P2P_CLI_24_LL_LT_SAP_DBS_2x2); + return index; +} + +enum policy_mgr_two_connection_mode +policy_mgr_get_third_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_two_connection_mode index = PM_MAX_TWO_CONNECTION_MODE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return index; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if (((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) && + (PM_SAP_MODE == pm_conc_connection_list[1].mode)) || + ((PM_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_cli_sap(psoc); + else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_SAP_MODE == pm_conc_connection_list[1].mode)) || + ((PM_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_sta_sap(psoc); + else if ((PM_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_SAP_MODE == pm_conc_connection_list[1].mode)) + index = + policy_mgr_get_third_connection_pcl_table_index_sap_sap(psoc); + else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_GO_MODE == pm_conc_connection_list[1].mode)) || + ((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_sta_go(psoc); + else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode)) || + ((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_sta_cli(psoc); + else if (((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode)) || + ((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_GO_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_go_cli(psoc); + else if (((PM_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_GO_MODE == pm_conc_connection_list[1].mode)) || + ((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) && + (PM_SAP_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_go_sap(psoc); + else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode)) || + ((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_sta_sta(psoc); + else if (((PM_NAN_DISC_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode)) || + ((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_NAN_DISC_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_sta_nan(psoc); + else if (((PM_NAN_DISC_MODE == pm_conc_connection_list[0].mode) && + (PM_NDI_MODE == pm_conc_connection_list[1].mode)) || + ((PM_NDI_MODE == pm_conc_connection_list[0].mode) && + (PM_NAN_DISC_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_nan_ndi(psoc); + else if (((PM_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_NAN_DISC_MODE == pm_conc_connection_list[1].mode)) || + ((PM_NAN_DISC_MODE == pm_conc_connection_list[0].mode) && + (PM_SAP_MODE == pm_conc_connection_list[1].mode))) + index = + policy_mgr_get_third_connection_pcl_table_index_sap_nan(psoc); + else if ((pm_conc_connection_list[0].mode == PM_P2P_GO_MODE) && + (pm_conc_connection_list[1].mode == PM_P2P_GO_MODE)) + index = + policy_mgr_get_third_connection_pcl_table_index_go_go(psoc); + + else if ((pm_conc_connection_list[0].mode == PM_P2P_CLIENT_MODE) && + (pm_conc_connection_list[1].mode == PM_P2P_CLIENT_MODE)) + index = + policy_mgr_get_third_connection_pcl_table_index_cli_cli(psoc); + + else if (((PM_STA_MODE == pm_conc_connection_list[0].mode) && + (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) || + ((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_STA_MODE == pm_conc_connection_list[1].mode))) + index = policy_mgr_get_third_connection_pcl_table_index_sta_ll_lt_sap(psoc); + + else if (((PM_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) || + ((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_SAP_MODE == pm_conc_connection_list[1].mode))) + index = policy_mgr_get_third_connection_pcl_table_index_sap_ll_lt_sap(psoc); + + else if (((PM_P2P_GO_MODE == pm_conc_connection_list[0].mode) && + (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) || + ((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_GO_MODE == pm_conc_connection_list[1].mode))) + index = policy_mgr_get_third_connection_pcl_table_index_go_ll_lt_sap(psoc); + + else if (((PM_P2P_CLIENT_MODE == pm_conc_connection_list[0].mode) && + (PM_LL_LT_SAP_MODE == pm_conc_connection_list[1].mode)) || + ((PM_LL_LT_SAP_MODE == pm_conc_connection_list[0].mode) && + (PM_P2P_CLIENT_MODE == pm_conc_connection_list[1].mode))) + index = policy_mgr_get_third_connection_pcl_table_index_cli_ll_lt_sap(psoc); + + policy_mgr_debug("mode0:%d mode1:%d freq0:%d freq1:%d chain:%d index:%d", + pm_conc_connection_list[0].mode, + pm_conc_connection_list[1].mode, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[0].chain_mask, index); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return index; +} + +#ifdef FEATURE_FOURTH_CONNECTION +/** + * policy_mgr_get_index_for_3_given_freq_dbs() - Find the index for next + * connection for given 3 freq in DBS mode + * @pm_ctx: policy manager context + * @index: Index to return for next connection + * @freq1: freq of interface 1 + * @freq2: freq of interface 2 + * @freq3: freq of interface 3 + * + * This function finds the index for next connection for 3 freq in DBS mode. + * + * Return: none + */ +static void +policy_mgr_get_index_for_3_given_freq_dbs( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, + qdf_freq_t freq1, qdf_freq_t freq2, qdf_freq_t freq3) +{ + /* If all freq are on same band */ + if ((WLAN_REG_IS_24GHZ_CH_FREQ(freq1) == + WLAN_REG_IS_24GHZ_CH_FREQ(freq2) && + (WLAN_REG_IS_24GHZ_CH_FREQ(freq2) == + WLAN_REG_IS_24GHZ_CH_FREQ(freq3)))) { + policy_mgr_err("Invalid mode for all freq %d, %d and %d on same band", + freq1, freq2, freq3); + return; + } + + /* + * If freq1 and freq2 are on same band and freq3 is on differet band and + * is not sharing mac with any SAP. STA on same band is handled above, + * so both SAP on same band mean STA cannot be on same band. This can + * happen if SBS is not enabled. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq1) == + WLAN_REG_IS_24GHZ_CH_FREQ(freq2)) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq3)) + /* + * As all 3 cannot be on same band, so if freq3 is + * 2.4 GHZ mean both freq1 and freq2 are on 5 / 6 GHZ + */ + *index = PM_5_SCC_MCC_PLUS_24_DBS; + else + /* + * As all 3 cannot be on same band, so if freq3 is + * 5 / 6 GHZ, mean both freq1 and freq2 are on 2.4 GHZ. + */ + *index = PM_24_SCC_MCC_PLUS_5_DBS; + return; + } + + /* + * if freq1 and freq 2 are on different band (2 GHZ + 5 GHZ/6 GHZ DBS), + * check with which freq the freq3 will share mac, and return index as + * per it. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq3)) + *index = PM_24_SCC_MCC_PLUS_5_DBS; + else + *index = PM_5_SCC_MCC_PLUS_24_DBS; +} + +/** + * policy_mgr_get_index_for_3_given_freq_sbs() - Find the index for next + * connection for 3 given freq, in case current HW mode is SBS + * @pm_ctx: policy manager context + * @index: Index to return for next connection + * @freq1: freq of interface 1 + * @freq2: freq of interface 2 + * @freq3: freq of interface 3 + * + * This function finds the index for next + * connection for 3 given freq, in case current HW mode is SBS + * + * Return: none + */ +static void policy_mgr_get_index_for_3_given_freq_sbs( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, + qdf_freq_t freq1, qdf_freq_t freq2, qdf_freq_t freq3) +{ + qdf_freq_t sbs_cut_off_freq; + qdf_freq_t shared_5_ghz_freq = 0; + + /* + * Sanity check: At least 2 of the given freq needs to be creating SBS + * separation for HW mode to be in SBS, if not it shouldn't have + * entered this API. + */ + if (!policy_mgr_are_sbs_chan(pm_ctx->psoc, freq1, freq2) && + !policy_mgr_are_sbs_chan(pm_ctx->psoc, freq2, freq3) && + !policy_mgr_are_sbs_chan(pm_ctx->psoc, freq3, freq1)) { + policy_mgr_err("freq1 %d, freq2 %d and freq3 %d, none of the 2 connections/3 vdevs are leading to SBS", + freq1, freq2, freq3); + return; + } + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(pm_ctx->psoc); + if (!sbs_cut_off_freq) { + policy_mgr_err("Invalid cutoff freq"); + return; + } + + /* + * If dynamic SBS is enabled (2.4 GHZ can share mac with HIGH + * 5GHZ as well as LOW 5 GHZ, but one at a time) and one of the + * freq is 2.4 GHZ, this mean that the new interface can come up on + * 5 GHZ LOW or HIGH and HW mode will move the 2.4 GHZ link to + * the other mac dynamically. + */ + if (policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx) && + (WLAN_REG_IS_24GHZ_CH_FREQ(freq1) || + WLAN_REG_IS_24GHZ_CH_FREQ(freq2) || + WLAN_REG_IS_24GHZ_CH_FREQ(freq3))) { + *index = PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS; + return; + } + /* + * if freq1 on freq2 same mac, get the 5 / 6 GHZ freq from it check + * and determine shared mac. + */ + if (policy_mgr_2_freq_same_mac_in_sbs(pm_ctx, freq1, freq2)) { + /* + * If freq1 is 2.4 GHZ that mean freq2 is 5 / 6 GHZ. + * so take decision using freq2. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq1)) + shared_5_ghz_freq = freq2; + else + /* freq1 5 / 6 GHZ, use freq1 */ + shared_5_ghz_freq = freq1; + } else if (policy_mgr_2_freq_same_mac_in_sbs(pm_ctx, freq2, freq3)) { + /* + * If freq2 is 2.4 GHZ that mean freq3 is 5 / 6 GHZ. + * so take decision using freq3. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq2)) + shared_5_ghz_freq = freq3; + else + /* freq2 5 / 6 GHZ, use freq1 */ + shared_5_ghz_freq = freq2; + } else if (policy_mgr_2_freq_same_mac_in_sbs(pm_ctx, freq3, freq1)) { + /* + * If freq1 is 2.4 GHZ that mean freq3 is 5 / 6 GHZ. + * so take decision using freq3. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq1)) + shared_5_ghz_freq = freq3; + else + /* freq1 5 / 6 GHZ, use freq1 */ + shared_5_ghz_freq = freq1; + } + + if (!shared_5_ghz_freq || + WLAN_REG_IS_24GHZ_CH_FREQ(shared_5_ghz_freq)) { + policy_mgr_err("shared_5_ghz_freq %d is not 5 / 6 GHZ", + shared_5_ghz_freq); + return; + } + + /* If shared 5 / 6 GHZ freq is low 5 GHZ, then return high 5 GHZ freq */ + if (shared_5_ghz_freq < sbs_cut_off_freq) + *index = PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS; + else + *index = PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * policy_mgr_get_index_for_ml_sta_sap_dbs() - Find the index for next + * connection for ML STA + SAP, in case current HW mode is DBS and ML STA is + * 2.4 GHZ + 5 GHZ/6 GHZ OR if SBS is not supported. + * @pm_ctx: policy manager context + * @index: Index to return for next connection + * @sap_freq: SAP freq + * @sta_freq_list: STA freq list + * @ml_sta_idx: ML STA index in freq_list + * + * This function finds the index for next + * connection for ML STA + SAP, in case current HW mode is DBS and ML STA is + * 2.4 GHZ + 5 GHZ/6 GHZ OR if SBS is not supported. + * + * Return: none + */ +static void +policy_mgr_get_index_for_ml_sta_sap_dbs( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, qdf_freq_t sap_freq, + qdf_freq_t *sta_freq_list, uint8_t *ml_sta_idx) +{ + /* If ML STA and SAP all are on same band */ + if ((WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[0]]) == + WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[1]])) && + (WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[0]]) == + WLAN_REG_IS_24GHZ_CH_FREQ(sap_freq))) { + policy_mgr_err("Invalid mode for ML STA %d and %d are on same band as SAP %d", + sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]], sap_freq); + return; + } + + /* + * If ML STA is MCC and SAP is on differet band and is not sharing mac + * with any link. SAP on same band is handled above, so ML STA on same + * band mean SAP cannot be on same band. This can happen if SBS is not + * enabled. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[0]]) == + WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[1]])) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_freq)) + /* + * As all 3 cannot be on same band, so if SAP is 2.4 GHZ + * mean both ML STA are on 5 / 6 GHZ + */ + *index = PM_STA_STA_5_SAP_24_DBS; + else + /* + * As all 3 cannot be on same band, so if SAP is + * 5 / 6 GHZ, mean both ML STA are on 2.4 GHZ. + */ + policy_mgr_err("Invalid mode for ML STA %d and %d are on 2.4 GHZ, sap freq %d", + sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]], sap_freq); + + return; + } + + /* + * if ML STA is 2 GHZ + 5 GHZ/6 GHZ DBS, check with which freq the SAP + * will share mac, and return index as per it. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_freq)) + *index = PM_STA_SAP_24_STA_5_DBS; + else + *index = PM_STA_SAP_5_STA_24_DBS; +} + +/** + * policy_mgr_get_index_for_ml_sta_sap_hwmode_sbs() - Find the index for next + * connection for ML STA + SAP, in case current HW mode is SBS but ML STA is + * with 2 GHz + 5/6 GHz. + * @pm_ctx: policy manager context + * @index: Index to return for next connection + * @sap_freq: SAP freq + * @sta_freq_list: STA freq list + * @ml_sta_idx: ML STA index in freq_list + * + * This function finds the index for next connection for ML STA + SAP, + * in case current HW mode is SBS but ML STA is with 2 GHz + 5/6 GHz. + * + * Return: none + */ +static void policy_mgr_get_index_for_ml_sta_sap_hwmode_sbs( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, qdf_freq_t sap_freq, + qdf_freq_t *sta_freq_list, uint8_t *ml_sta_idx) +{ + bool sbs_24_shared_high_support = + policy_mgr_sbs_24_shared_with_high_5(pm_ctx); + bool sbs_24_shared_low_support = + policy_mgr_sbs_24_shared_with_low_5(pm_ctx); + qdf_freq_t sbs_cut_off_freq, ml_sta_5g_freq; + bool ml_sta_5g_low; + + /* HW supports sbs but ml sta 2 home channels are not in sbs frequency + * separation by check policy_mgr_are_sbs_chan. + * It means one ml sta is 2.4 GHz, the other is 5/6 GHz. + * The combinations handled by this API: + * 2.4 GHz band | 5 GHz low band | 5/6 GHz high band | PCL list + * ---------------------------------------------------------------------- + * ML STA | ML STA+SAP | | 5 GHz High + 2.4 GHz + * ML STA | ML STA+SAP | | 2.4 GHz(nhss) + * ML STA | ML STA | SAP | 5 GHz Low + 2.4 GHz + * ML STA | ML STA | SAP | 2.4 GHz (nhss) + * ML STA | SAP | ML STA | 5 GHz High+ 2.4 GHz + * ML STA | SAP | ML STA | 2.4 GHz (nlss) + * ML STA | | ML STA+SAP | 5 GHz Low + 2.4 GHz + * ML STA | | ML STA+SAP | 2.4 GHz (nlss) + * ML STA+SAP | ML STA | | 5 GHz Low+5 GHz High + * ML STA+SAP | | ML STA | 5 GHz Low+5 GHz High + * + * nhss: no high share supported + * nlss: no low share supported + */ + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[0]]) && + !WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[1]])) { + policy_mgr_err("unexpected ml sta home freq to handle (%d %d)", + sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]]); + return; + } + if (!sbs_24_shared_low_support && !sbs_24_shared_high_support) { + policy_mgr_err("unexpected sbs mode: low share %d high share %d", + sbs_24_shared_low_support, + sbs_24_shared_high_support); + return; + } + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(pm_ctx->psoc); + if (!sbs_cut_off_freq) { + policy_mgr_err("Invalid cutoff freq"); + return; + } + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[0]])) + ml_sta_5g_freq = sta_freq_list[ml_sta_idx[0]]; + else + ml_sta_5g_freq = sta_freq_list[ml_sta_idx[1]]; + if (ml_sta_5g_freq < sbs_cut_off_freq) + ml_sta_5g_low = true; + else + ml_sta_5g_low = false; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_freq)) { + /* pcl 5 GHz Low+5 GHz High - PM_SCC_ON_5_CH_5G */ + *index = PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS; + } else if (sap_freq < sbs_cut_off_freq) { + if ((ml_sta_5g_low && sbs_24_shared_high_support) || + (!ml_sta_5g_low && sbs_24_shared_low_support)) + /* pcl 5 GHz High + 2.4 GHz - + * PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G + */ + *index = PM_STA_24_STA_5_MCC_SAP_5_LOW_SBS; + else + *index = PM_24_5_PLUS_5_LOW_OR_HIGH_SHARE_SBS; + } else { + if ((ml_sta_5g_low && sbs_24_shared_high_support) || + (!ml_sta_5g_low && sbs_24_shared_low_support)) + /* pcl 5 GHz Low + 2.4 GHz - + * PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G + */ + *index = PM_STA_24_STA_5_MCC_SAP_5_HIGH_SBS; + else + *index = PM_24_5_PLUS_5_LOW_OR_HIGH_SHARE_SBS; + } + policy_mgr_debug("4th index %d sap freq %d ml sta 5g %d sbs_cut_off_freq %d support high share %d low share %d", + *index, sap_freq, ml_sta_5g_freq, sbs_cut_off_freq, + sbs_24_shared_high_support, + sbs_24_shared_low_support); +} + +/** + * policy_mgr_get_index_for_ml_sta_sap_sbs() - Find the index for next + * connection for ML STA + SAP, in case current HW mode is SBS or ML STA is + * with 5 GHZ + 5 GHZ/6 GHZ SBS separation. + * @pm_ctx: policy manager context + * @index: Index to return for next connection + * @sap_freq: SAP freq + * @sta_freq_list: STA freq list + * @ml_sta_idx: ML STA index in freq_list + * + * This function finds the index for next + * connection for ML STA + SAP, in case current HW mode is SBS or ML STA is + * with 5 GHZ + 5 GHZ/6 GHZ SBS separation. + * + * Return: none + */ +static void policy_mgr_get_index_for_ml_sta_sap_sbs( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, qdf_freq_t sap_freq, + qdf_freq_t *sta_freq_list, uint8_t *ml_sta_idx) +{ + qdf_freq_t sbs_cut_off_freq; + bool can_2ghz_share_low_high_5ghz = + policy_mgr_can_2ghz_share_low_high_5ghz_sbs(pm_ctx); + + /* + * Sanity check: At least one of the 3 combo (ML STA OR SAP + one of + * ML STA link) needs to be creating SBS separation for + * HW mode to be in SBS, if not it shouldn't have entered this API. + */ + if (!policy_mgr_are_sbs_chan(pm_ctx->psoc, sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]]) && + !policy_mgr_are_sbs_chan(pm_ctx->psoc, sap_freq, + sta_freq_list[ml_sta_idx[0]]) && + !policy_mgr_are_sbs_chan(pm_ctx->psoc, sap_freq, + sta_freq_list[ml_sta_idx[1]])) { + if (policy_mgr_is_current_hwmode_sbs(pm_ctx->psoc)) { + policy_mgr_get_index_for_ml_sta_sap_hwmode_sbs( + pm_ctx, index, sap_freq, sta_freq_list, + ml_sta_idx); + return; + } + policy_mgr_err("SAP freq (%d) and ML STA freq %d and %d, none of the 2 connections/3 vdevs are leading to SBS", + sap_freq, + sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]]); + return; + } + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(pm_ctx->psoc); + if (!sbs_cut_off_freq) { + policy_mgr_err("Invalid cutoff freq"); + return; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_freq)) { + /* + * If dynamic SBS is enabled (2.4 GHZ can share mac with HIGH + * 5GHZ as well as LOW 5 GHZ, but one at a time) and SAP is + * 2.4 GHZ, this mean that the new SAP can come up on 5 GHZ LOW + * or HIGH and HW mode will move the 2.4 GHZ SAP to the other + * mac dynamically. + */ + if (can_2ghz_share_low_high_5ghz) { + *index = PM_SAP_24_STA_5_STA_5_LOW_N_HIGH_SHARE_SBS; + return; + } + /* + * if SAP is 2.4 GHZ that means both ML STA needs to + * be with 5 GHZ + 5 GHZ/6 GHZ SBS separation. If not, it would + * have failed the sanity check. So Get STA link with + * which SAP freq is sharing mac and select index accordingly + */ + if (policy_mgr_2_freq_same_mac_in_sbs( + pm_ctx, sap_freq, + sta_freq_list[ml_sta_idx[0]])) { + /* + * SAP is sharig mac with link ml_sta_idx[0], so check + * if ml_sta_idx[0] is lower 5 GHZ or high 5 GHZ and + * select index + */ + if (sta_freq_list[ml_sta_idx[0]] < sbs_cut_off_freq) + *index = PM_STA_5_LOW_SAP_24_MCC_STA_5_HIGH_SBS; + else + *index = PM_STA_5_HIGH_SAP_24_MCC_STA_5_LOW_SBS; + } else { + /* + * SAP is sharig mac with link ml_sta_idx[1], so check + * if ml_sta_idx[1] is lower 5 GHZ or high 5 GHZ and + * select index + */ + if (sta_freq_list[ml_sta_idx[1]] < sbs_cut_off_freq) + *index = PM_STA_5_LOW_SAP_24_MCC_STA_5_HIGH_SBS; + else + *index = PM_STA_5_HIGH_SAP_24_MCC_STA_5_LOW_SBS; + } + + return; + } + + /* SAP freq is 5 GHZ or 6 GHZ and one ML sta is on 2.4 GHZ */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[0]]) || + WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[ml_sta_idx[1]])) { + /* + * If dynamic SBS is enabled (2.4 GHZ can share mac with HIGH + * 5GHZ as well as LOW 5 GHZ, but one at a time) and one STA + * link is 2.4 GHZ, this mean that the new SAP can come up on + * 5 GHZ LOW or HIGH and HW mode will move the 2.4 GHZ link to + * the other mac dynamically. + */ + if (can_2ghz_share_low_high_5ghz) { + *index = PM_STA_24_SAP_5_STA_5_LOW_N_HIGH_SHARE_SBS; + return; + } + /* + * If (2 GHZ + 5 GHZ/6 GHZ) ML is MCC i.e Both sta links are on + * same mac and SAP is on separate mac. This can happen if SBS + * is not dynamic and is low 5 GHZ shared, with ML STA on 5 GHZ + * low along with SAP 5Ghz high and vice versa. As both links + * of ML STA and sap are on different mac, so set index based + * on sap frequency whether it is in 5 GHZ low band or 5 GHZ + * high Band. + */ + if (policy_mgr_2_freq_same_mac_in_sbs( + pm_ctx, sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]])) { + if (sap_freq < sbs_cut_off_freq) + *index = PM_STA_24_STA_5_HIGH_MCC_SAP_5_LOW_SBS; + else + *index = PM_STA_24_STA_5_LOW_MCC_SAP_5_HIGH_SBS; + } else { + /* + * STA ML is (2 GHZ + 5 GHZ/6 GHZ) select as per the SAP + * freq, as for current mode to be in SBS, SAP will + * share mac with STA 2.4 GHZ Link or will not share + * mac at all (2 GHZ + 5 GHZ/6 GHZ MCC). Other case i.e + * 2 links on 5 GHZ and one STA link on 2 GHZ is DBS and + * sanity check already taken care this at start of the + * func. + */ + if (sap_freq < sbs_cut_off_freq) + *index = PM_STA_24_SAP_5_LOW_MCC_STA_5_HIGH_SBS; + else + *index = PM_STA_24_SAP_5_HIGH_MCC_STA_5_LOW_SBS; + } + return; + } + /* + * If (5 GHZ + 5 GHZ/6 GHZ) ML is MCC i.e SAP is not sharing mac + * with any link. This can happen if SBS is not dynamic and is + * low 5 GHZ shared, with ML STA on 5 GHZ low along with SAP 5 GHZ + * high and vice versa. As both ML sta link are on same mac and + * sap is on different mac, so decide whether ML links are sharing + * low 5 GHZ frequency or high 5 GHZ frequency based on sap frequency + */ + if (policy_mgr_2_freq_same_mac_in_sbs( + pm_ctx, sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]])) { + if (sap_freq < sbs_cut_off_freq) + *index = PM_STA_STA_5_HIGH_MCC_SAP_5_LOW_SBS; + else + *index = PM_STA_STA_5_LOW_MCC_SAP_5_HIGH_SBS; + } else { + /* + * STA ML is (5 GHZ + 5 GHZ/6 GHZ SBS/MCC), select as per the + * SAP freq, as for current mode to be in SBS, SAP will share + * mac with the corresponding low/high 5 GHZ + * (5 GHZ + 5 GHZ/6 GHZ SBS) or will not share mac at all + * (5 GHZ +5 GHZ/6 GHZ MCC). Other case sanity already + * taken care at start of the func. + */ + if (sap_freq < sbs_cut_off_freq) + *index = PM_STA_SAP_5_LOW_STA_5_HIGH_SBS; + else + *index = PM_STA_SAP_5_HIGH_STA_5_LOW_SBS; + } +} + +static void +policy_mgr_get_index_for_ml_sta_sap( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, + qdf_freq_t sap_freq, qdf_freq_t *sta_freq_list, + uint8_t *ml_sta_idx) +{ + /* + * P2P GO/P2P CLI are treated as SAP to optimize as pcl + * table is same for all three. + */ + policy_mgr_debug("channel: sap0: %d, ML STA link0: %d, ML STA link1: %d", + sap_freq, sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]]); + if (policy_mgr_is_current_hwmode_sbs(pm_ctx->psoc) || + policy_mgr_are_sbs_chan(pm_ctx->psoc, sta_freq_list[ml_sta_idx[0]], + sta_freq_list[ml_sta_idx[1]])) { + /* if current mode is SBS or the ML STA is 5+5/6Ghz SBS */ + policy_mgr_get_index_for_ml_sta_sap_sbs(pm_ctx, index, + sap_freq, + sta_freq_list, + ml_sta_idx); + return; + } + /* + * current HW mode is DBS and ML STA is 2.4 GHZ + 5 GHZ or SBS + * is not enabled + */ + policy_mgr_get_index_for_ml_sta_sap_dbs(pm_ctx, index, sap_freq, + sta_freq_list, ml_sta_idx); +} + +static void +policy_mgr_get_index_for_ml_sta_sap_sap( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, + qdf_freq_t ml_sta_freq, qdf_freq_t sap_freq_1, + qdf_freq_t sap_freq_2) +{ + /* + * P2P GO/P2P CLI are treated as SAP to optimize as pcl + * table is same for all three. + */ + policy_mgr_debug("channel: ML sta0: %d, SAP0: %d, SAP1: %d", + ml_sta_freq, sap_freq_1, sap_freq_2); + if (policy_mgr_is_current_hwmode_sbs(pm_ctx->psoc)) + /* if current mode is SBS */ + return policy_mgr_get_index_for_3_given_freq_sbs(pm_ctx, index, + ml_sta_freq, sap_freq_1, + sap_freq_2); + + /* current HW mode is DBS */ + policy_mgr_get_index_for_3_given_freq_dbs(pm_ctx, index, ml_sta_freq, + sap_freq_1, sap_freq_2); +} + +#else /* WLAN_FEATURE_11BE_MLO */ + +static inline void +policy_mgr_get_index_for_ml_sta_sap( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, + qdf_freq_t sap_freq, qdf_freq_t *sta_freq_list, + uint8_t *ml_sta_idx) {} + +static inline void +policy_mgr_get_index_for_ml_sta_sap_sap( + struct policy_mgr_psoc_priv_obj *pm_ctx, + enum policy_mgr_three_connection_mode *index, + qdf_freq_t ml_sta_freq, qdf_freq_t sap_freq_1, + qdf_freq_t sap_freq_2) {} +#endif /* WLAN_FEATURE_11BE_MLO */ + +enum policy_mgr_three_connection_mode + policy_mgr_get_fourth_connection_pcl_table_index( + struct wlan_objmgr_psoc *psoc) +{ + enum policy_mgr_three_connection_mode index = + PM_MAX_THREE_CONNECTION_MODE; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t count_sap = 0; + uint32_t count_sta = 0; + uint32_t count_ndi = 0; + uint32_t count_nan_disc = 0; + uint8_t num_ml_sta = 0, num_non_ml_sta = 0; + uint32_t list_sap[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t list_sta[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t list_ndi[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t list_nan_disc[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_sta_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t non_ml_sta_idx[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t sap_freq = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return index; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + /* For 4 port concurrency case, + * 1st step: (SAP+STA)(2.4G MAC SCC) + (SAP+STA)(5G MAC SCC) + * 2nd step: (AGO+STA)(2.4G MAC SCC) + (AGO+STA)(5G MAC SCC) + */ + count_sap += policy_mgr_mode_specific_connection_count( + psoc, PM_SAP_MODE, &list_sap[count_sap]); + count_sap += policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, &list_sap[count_sap]); + count_sap += policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_CLIENT_MODE, &list_sap[count_sap]); + count_sta = policy_mgr_mode_specific_connection_count( + psoc, PM_STA_MODE, list_sta); + policy_mgr_get_ml_and_non_ml_sta_count(psoc, &num_ml_sta, ml_sta_idx, + &num_non_ml_sta, non_ml_sta_idx, + freq_list, vdev_id_list); + + count_ndi = policy_mgr_mode_specific_connection_count( + psoc, PM_NDI_MODE, list_ndi); + count_nan_disc = policy_mgr_mode_specific_connection_count( + psoc, PM_NAN_DISC_MODE, list_nan_disc); + policy_mgr_debug("sap/go/cli:%d sta:%d ndi:%d nan disc:%d ml_sta:%d", + count_sap, count_sta, count_ndi, count_nan_disc, + num_ml_sta); + + if (count_sap == 2 && num_ml_sta == 1) { + policy_mgr_get_index_for_ml_sta_sap_sap( + pm_ctx, &index, + freq_list[ml_sta_idx[0]], + pm_conc_connection_list[list_sap[0]].freq, + pm_conc_connection_list[list_sap[1]].freq); + } else if (count_sap == 2 && count_sta == 1 && !num_ml_sta) { + policy_mgr_debug( + "channel: sap0: %d, sap1: %d, sta0: %d", + pm_conc_connection_list[list_sap[0]].freq, + pm_conc_connection_list[list_sap[1]].freq, + pm_conc_connection_list[list_sta[0]].freq); + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[1]].freq)) { + index = PM_STA_SAP_SCC_24_SAP_5_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[1]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq)) { + index = PM_STA_SAP_SCC_24_SAP_5_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[1]].freq)) { + index = PM_STA_SAP_SCC_5_SAP_24_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[1]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq)) { + index = PM_STA_SAP_SCC_5_SAP_24_DBS; + } else { + index = PM_MAX_THREE_CONNECTION_MODE; + } + } else if (num_ml_sta == 2 && count_sap == 1) { + sap_freq = pm_conc_connection_list[list_sap[0]].freq; + policy_mgr_get_index_for_ml_sta_sap(pm_ctx, &index, sap_freq, + freq_list, ml_sta_idx); + } else if (count_sap == 1 && count_sta == 2 && !num_ml_sta) { + policy_mgr_debug( + "channel: sap0: %d, sta0: %d, sta1: %d", + pm_conc_connection_list[list_sap[0]].freq, + pm_conc_connection_list[list_sta[0]].freq, + pm_conc_connection_list[list_sta[1]].freq); + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[1]].freq)) { + index = PM_STA_SAP_24_STA_5_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[1]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq)) { + index = PM_STA_SAP_24_STA_5_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[1]].freq)) { + index = PM_STA_SAP_5_STA_24_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[1]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq)) { + index = PM_STA_SAP_5_STA_24_DBS; + } else { + index = PM_MAX_THREE_CONNECTION_MODE; + } + } else if (count_nan_disc == 1 && count_ndi == 1 && count_sap == 1) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NAN_DISC_SAP_SCC_24_NDI_5_DBS; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NAN_DISC_NDI_SCC_24_SAP_5_DBS; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sap[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_SAP_NDI_SCC_5_NAN_DISC_24_DBS; + } else { + index = PM_MAX_THREE_CONNECTION_MODE; + } + } else if (count_nan_disc == 1 && count_ndi == 1 && count_sta == 1) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NAN_DISC_STA_24_NDI_5_DBS; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NAN_DISC_NDI_24_STA_5_DBS; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_STA_NDI_5_NAN_DISC_24_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_sta[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_STA_NDI_NAN_DISC_24_SMM; + } + } else if (count_nan_disc == 1 && count_ndi == 2) { + /* Policy mgr only considers NAN Disc ch in 2.4GHz */ + if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[1]].freq)) { + index = PM_NAN_DISC_NDI_24_NDI_5_DBS; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NAN_DISC_NDI_24_NDI_5_DBS; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq) && + WLAN_REG_IS_5GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NDI_NDI_5_NAN_DISC_24_DBS; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq) && + WLAN_REG_IS_24GHZ_CH_FREQ( + pm_conc_connection_list[list_ndi[0]].freq)) { + index = PM_NDI_NDI_NAN_DISC_24_SMM; + } + } else if (count_sap == 3) { + if (policy_mgr_is_current_hwmode_sbs(psoc)) + policy_mgr_get_index_for_3_given_freq_sbs(pm_ctx, + &index, + pm_conc_connection_list[list_sap[0]].freq, + pm_conc_connection_list[list_sap[1]].freq, + pm_conc_connection_list[list_sap[2]].freq); + else if (policy_mgr_is_current_hwmode_dbs(psoc)) + policy_mgr_get_index_for_3_given_freq_dbs(pm_ctx, + &index, + pm_conc_connection_list[list_sap[0]].freq, + pm_conc_connection_list[list_sap[1]].freq, + pm_conc_connection_list[list_sap[2]].freq); + } + + policy_mgr_debug( + "mode0:%d mode1:%d mode2:%d chan0:%d chan1:%d chan2:%d chain:%d index:%d", + pm_conc_connection_list[0].mode, + pm_conc_connection_list[1].mode, + pm_conc_connection_list[2].mode, + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq, + pm_conc_connection_list[2].freq, + pm_conc_connection_list[0].chain_mask, index); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return index; +} +#endif + +uint32_t +policy_mgr_get_nondfs_preferred_channel(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + bool for_existing_conn, + uint8_t vdev_id) +{ + uint32_t pcl_channels[NUM_CHANNELS]; + uint8_t pcl_weight[NUM_CHANNELS]; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + /* + * in worst case if we can't find any channel at all + * then return 2.4G channel, so atleast we won't fall + * under 5G MCC scenario + */ + uint32_t i, pcl_len = 0, non_dfs_freq, freq; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return PM_24_GHZ_CH_FREQ_6; + } + + freq = PM_24_GHZ_CH_FREQ_6; + if (true == for_existing_conn) { + /* + * First try to see if there is any non-dfs channel already + * present in current connection table. If yes then return + * that channel + */ + if (true == policy_mgr_is_any_nondfs_chnl_present( + psoc, &non_dfs_freq)) + return non_dfs_freq; + + if (QDF_STATUS_SUCCESS != + policy_mgr_get_pcl_for_existing_conn( + psoc, mode, + pcl_channels, &pcl_len, + pcl_weight, QDF_ARRAY_SIZE(pcl_weight), + false, vdev_id)) + return freq; + } else { + if (QDF_STATUS_SUCCESS != policy_mgr_get_pcl( + psoc, mode, pcl_channels, &pcl_len, pcl_weight, + QDF_ARRAY_SIZE(pcl_weight), vdev_id)) + return freq; + } + + for (i = 0; i < pcl_len; i++) { + if (wlan_reg_is_dfs_for_freq(pm_ctx->pdev, pcl_channels[i]) || + !policy_mgr_is_safe_channel(psoc, pcl_channels[i])) { + continue; + } else { + freq = pcl_channels[i]; + break; + } + } + + return freq; +} + +static void policy_mgr_remove_dsrc_channels(uint32_t *ch_freq_list, + uint32_t *num_channels, + struct wlan_objmgr_pdev *pdev) +{ + uint32_t num_chan_temp = 0; + int i; + + for (i = 0; i < *num_channels; i++) { + if (!wlan_reg_is_dsrc_freq(ch_freq_list[i])) { + ch_freq_list[num_chan_temp] = ch_freq_list[i]; + num_chan_temp++; + } + } + + *num_channels = num_chan_temp; +} + +QDF_STATUS policy_mgr_get_valid_chans_from_range( + struct wlan_objmgr_psoc *psoc, uint32_t *ch_freq_list, + uint32_t *ch_cnt, enum policy_mgr_con_mode mode) +{ + uint8_t ch_weight_list[NUM_CHANNELS] = {0}; + uint32_t ch_weight_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + size_t chan_index = 0; + + if (!ch_freq_list || !ch_cnt) { + policy_mgr_err("NULL parameters"); + return QDF_STATUS_E_FAILURE; + } + + for (chan_index = 0; chan_index < *ch_cnt; chan_index++) + ch_weight_list[chan_index] = WEIGHT_OF_GROUP1_PCL_CHANNELS; + + ch_weight_len = *ch_cnt; + + /* check the channel avoidance list for beaconing entities */ + if (policy_mgr_is_beaconing_mode(mode)) + policy_mgr_update_with_safe_channel_list( + psoc, ch_freq_list, ch_cnt, ch_weight_list, + ch_weight_len); + + status = policy_mgr_mode_specific_modification_on_pcl( + psoc, ch_freq_list, ch_weight_list, ch_cnt, + ch_weight_len, mode); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get modified pcl for mode %d", mode); + return status; + } + + status = policy_mgr_modify_pcl_based_on_dnbs(psoc, ch_freq_list, + ch_weight_list, ch_cnt); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("failed to get modified pcl based on DNBS"); + return status; + } + policy_mgr_dump_channel_list(*ch_cnt, ch_freq_list, ch_weight_list); + + return status; +} + +QDF_STATUS policy_mgr_get_valid_chans(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, + uint32_t *list_len) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + *list_len = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + if (!pm_ctx->valid_ch_freq_list_count) { + policy_mgr_err("Invalid PM valid channel list"); + return QDF_STATUS_E_INVAL; + } + + *list_len = pm_ctx->valid_ch_freq_list_count; + qdf_mem_copy(ch_freq_list, pm_ctx->valid_ch_freq_list, + pm_ctx->valid_ch_freq_list_count * + sizeof(pm_ctx->valid_ch_freq_list[0])); + + policy_mgr_remove_dsrc_channels(ch_freq_list, list_len, pm_ctx->pdev); + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_list_has_24GHz_channel(uint32_t *ch_freq_list, + uint32_t list_len) +{ + uint32_t i; + + for (i = 0; i < list_len; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq_list[i])) + return true; + } + + return false; +} + +QDF_STATUS +policy_mgr_set_sap_mandatory_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, uint32_t len) +{ + uint32_t i; + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!len) { + policy_mgr_err("No mandatory freq/chan configured"); + return QDF_STATUS_E_FAILURE; + } + + if (!policy_mgr_list_has_24GHz_channel(ch_freq_list, len)) { + policy_mgr_err("2.4GHz channels missing, this is not expected"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_debug("mandatory chan length:%d", + pm_ctx->sap_mandatory_channels_len); + + for (i = 0; i < len; i++) { + pm_ctx->sap_mandatory_channels[i] = ch_freq_list[i]; + policy_mgr_debug("chan:%d", pm_ctx->sap_mandatory_channels[i]); + } + + pm_ctx->sap_mandatory_channels_len = len; + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_sap_mandatory_channel_set(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return false; + } + + if (pm_ctx->sap_mandatory_channels_len) + return true; + else + return false; +} + +static inline +uint32_t policy_mgr_is_sta_on_indoor_channel(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t conn_index; + uint32_t freq = INVALID_CHANNEL_ID; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return freq; + } + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if (pm_conc_connection_list[conn_index].mode == PM_STA_MODE && + wlan_reg_is_freq_indoor(pm_ctx->pdev, + pm_conc_connection_list[conn_index].freq) && + pm_conc_connection_list[conn_index].in_use) { + freq = pm_conc_connection_list[conn_index].freq; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return freq; +} + +QDF_STATUS policy_mgr_modify_sap_pcl_based_on_mandatory_channel( + struct wlan_objmgr_psoc *psoc, uint32_t *pcl_list_org, + uint8_t *weight_list_org, uint32_t *pcl_len_org) +{ + uint32_t i, j, pcl_len = 0; + bool found; + struct policy_mgr_psoc_priv_obj *pm_ctx; + qdf_freq_t dfs_sta_freq = INVALID_CHANNEL_ID; + qdf_freq_t indoor_sta_freq = INVALID_CHANNEL_ID; + qdf_freq_t sta_5GHz_freq = INVALID_CHANNEL_ID; + enum hw_mode_bandwidth sta_ch_width; + uint8_t sta_vdev_id = 0, scc_on_dfs_channel = 0; + bool sta_sap_scc_on_5ghz_channel; + bool scc_on_indoor = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + uint8_t go_count; + uint32_t go_op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t go_vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t go_op_ch_freq_5g = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + if (!pm_ctx->sap_mandatory_channels_len) + return QDF_STATUS_SUCCESS; + + if (!policy_mgr_list_has_24GHz_channel(pm_ctx->sap_mandatory_channels, + pm_ctx->sap_mandatory_channels_len)) { + policy_mgr_err("fav channel list is missing 2.4GHz channels"); + return QDF_STATUS_E_FAILURE; + } + + + for (i = 0; i < pm_ctx->sap_mandatory_channels_len; i++) + policy_mgr_debug("fav chan:%d", + pm_ctx->sap_mandatory_channels[i]); + + if (scc_on_indoor) + indoor_sta_freq = policy_mgr_is_sta_on_indoor_channel(psoc); + + policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, &scc_on_dfs_channel); + if (scc_on_dfs_channel) + policy_mgr_is_sta_present_on_dfs_channel(psoc, + &sta_vdev_id, + &dfs_sta_freq, + &sta_ch_width); + sta_sap_scc_on_5ghz_channel = + policy_mgr_is_connected_sta_5g(psoc, &sta_5GHz_freq); + + go_count = policy_mgr_get_mode_specific_conn_info( + psoc, go_op_ch_freq_list, + go_vdev_id_list, PM_P2P_GO_MODE); + if (go_count && !WLAN_REG_IS_24GHZ_CH_FREQ(go_op_ch_freq_list[0])) { + go_op_ch_freq_5g = go_op_ch_freq_list[0]; + policy_mgr_debug("go 5/6G present, SAP exclude 5/6G channels"); + } + + for (i = 0; i < *pcl_len_org; i++) { + found = false; + if (i >= NUM_CHANNELS) { + policy_mgr_debug("index is exceeding NUM_CHANNELS"); + break; + } + + if (go_op_ch_freq_5g && + !WLAN_REG_IS_24GHZ_CH_FREQ(pcl_list_org[i])) + continue; + + if (scc_on_indoor && policy_mgr_is_force_scc(psoc) && + pcl_list_org[i] == indoor_sta_freq) { + policy_mgr_debug("indoor chan:%d", pcl_list_org[i]); + found = true; + goto update_pcl; + } + + if (scc_on_dfs_channel && policy_mgr_is_force_scc(psoc) && + pcl_list_org[i] == dfs_sta_freq) { + policy_mgr_debug("dfs chan:%d", pcl_list_org[i]); + found = true; + goto update_pcl; + } + + if (sta_sap_scc_on_5ghz_channel && + policy_mgr_is_force_scc(psoc) && + pcl_list_org[i] == sta_5GHz_freq) { + policy_mgr_debug("scc chan:%d", pcl_list_org[i]); + found = true; + goto update_pcl; + } + + for (j = 0; j < pm_ctx->sap_mandatory_channels_len; j++) { + if (pcl_list_org[i] == + pm_ctx->sap_mandatory_channels[j]) { + found = true; + break; + } + } + +update_pcl: + if (found && (pcl_len < NUM_CHANNELS)) { + pcl_list_org[pcl_len] = pcl_list_org[i]; + weight_list_org[pcl_len++] = weight_list_org[i]; + } + } + *pcl_len_org = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +void +policy_mgr_sap_on_non_psc_channel(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *intf_ch_freq, uint8_t vdev_id) +{ + struct policy_mgr_pcl_list pcl; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + uint32_t i; + uint32_t ap_pwr_type_6g = 0; + + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(*intf_ch_freq)) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + + if (!vdev) { + policy_mgr_err("vdev %d is not present", vdev_id); + return; + } + + ap_pwr_type_6g = wlan_mlme_get_6g_ap_power_type(vdev); + qdf_mem_zero(&pcl, sizeof(pcl)); + + /* PCL list is filtered with Non-PSC channels during + * policy_mgr_pcl_modification_for_sap, Reuse same list to check + * if STA is in PSC channel for STA + SAP concurrency during SAP restart + */ + status = policy_mgr_get_pcl_for_existing_conn( + psoc, PM_SAP_MODE, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list), + false, vdev_id); + + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Unable to get PCL for SAP"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return; + } + + for (i = 0; i < pcl.pcl_len; i++) { + if ((WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl.pcl_list[i])) && + pcl.pcl_list[i] == *intf_ch_freq && + ap_pwr_type_6g == REG_VERY_LOW_POWER_AP) { + policy_mgr_debug("STA is in PSC channel %d in VLP mode, Hence SAP + STA allowed in PSC", + *intf_ch_freq); + *intf_ch_freq = 0; + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + return; + } + } + + /* if STA is in Non-PSC Channel + VLP or in non-VLP mode then move + * SAP to 2 GHz from PCL list channels + */ + *intf_ch_freq = pcl.pcl_list[0]; + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); +} + +QDF_STATUS +policy_mgr_get_sap_mandatory_channel(struct wlan_objmgr_psoc *psoc, + uint32_t sap_ch_freq, + uint32_t *intf_ch_freq, + uint8_t vdev_id) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + QDF_STATUS status; + struct policy_mgr_pcl_list pcl; + uint32_t i; + uint32_t sap_new_freq; + uint8_t mcc_to_scc_switch; + uint8_t sta_count; + qdf_freq_t user_config_freq = 0; + bool sta_sap_scc_on_indoor_channel = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc); + + mcc_to_scc_switch = + policy_mgr_get_mcc_to_scc_switch_mode(psoc); + + sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + + if (!sta_count || mcc_to_scc_switch != + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) + return QDF_STATUS_E_FAILURE; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&pcl, sizeof(pcl)); + + status = policy_mgr_get_pcl_for_existing_conn( + psoc, PM_SAP_MODE, pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, QDF_ARRAY_SIZE(pcl.weight_list), + false, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Unable to get PCL for SAP"); + return status; + } + + /* + * Get inside below loop if no existing SAP connection and hence a new + * SAP connection might be coming up. pcl.pcl_len can be 0 if no common + * channel between PCL & mandatory channel list as well + */ + if (!pcl.pcl_len && !policy_mgr_mode_specific_connection_count(psoc, + PM_SAP_MODE, NULL)) { + policy_mgr_debug("policy_mgr_get_pcl_for_existing_conn returned no pcl"); + status = policy_mgr_get_pcl( + psoc, PM_SAP_MODE, + pcl.pcl_list, &pcl.pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Unable to get PCL for SAP: policy_mgr_get_pcl"); + return status; + } + } + + status = policy_mgr_modify_sap_pcl_based_on_mandatory_channel( + psoc, pcl.pcl_list, + pcl.weight_list, + &pcl.pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("Unable to modify SAP PCL"); + return status; + } + + if (!pcl.pcl_len) { + policy_mgr_err("No common channel between mandatory list & PCL"); + return QDF_STATUS_E_FAILURE; + } + + /* + * If both freq leads to SBS, and sap_ch_freq is a mandatory freq, + * allow it as they are not interfering. + */ + if (policy_mgr_are_sbs_chan(psoc, sap_ch_freq, *intf_ch_freq)) { + for (i = 0; i < pcl.pcl_len; i++) { + if (pcl.pcl_list[i] == sap_ch_freq) { + policy_mgr_debug("As both freq, %d and %d are SBS, allow sap on mandatory freq %d", + sap_ch_freq, *intf_ch_freq, + sap_ch_freq); + *intf_ch_freq = 0; + return QDF_STATUS_SUCCESS; + } + } + } + + /* + * If intf_ch_freq is non-2.4Ghz, First try to get a mandatory freq + * which can cause SBS with intf_ch_freq. i.e if STA is in lower 5Ghz, + * allow higher 5Ghz mandatory freq. + */ + if (!WLAN_REG_IS_24GHZ_CH_FREQ(*intf_ch_freq)) { + for (i = 0; i < pcl.pcl_len; i++) { + if (policy_mgr_are_sbs_chan(psoc, pcl.pcl_list[i], + *intf_ch_freq)) { + sap_new_freq = pcl.pcl_list[i]; + goto update_freq; + } + } + } + + sap_new_freq = pcl.pcl_list[0]; + /* + * pcl_list carries multiple channel in ML-STA case depending on + * the no.of links connected. Check if intf_ch_freq is carrying + * any frequency from the list and pick it. If intf_ch_freq is not + * present in the list, the frequency present at pcl_list[0] can + * be picked as caller doesn't have any preferred/chosen channel + * as such. + */ + for (i = 0; i < pcl.pcl_len; i++) { + if (pcl.pcl_list[i] == *intf_ch_freq) { + sap_new_freq = pcl.pcl_list[i]; + break; + } + } + + user_config_freq = policy_mgr_get_user_config_sap_freq(psoc, vdev_id); + + for (i = 0; i < pcl.pcl_len; i++) { + /* When sta_sap_scc_on_indoor_channel is enabled, + * and if pcl contains SCC channel, then STA must + * exist on the concurrent session. Therefore, choose + * Indoor channel to restart SAP in SCC. + */ + if (wlan_reg_is_freq_indoor(pm_ctx->pdev, pcl.pcl_list[i]) && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl.pcl_list[i]) && + sta_sap_scc_on_indoor_channel) { + sap_new_freq = pcl.pcl_list[i]; + policy_mgr_debug("Choose Indoor channel from PCL list %d sap_new_freq %d", + *intf_ch_freq, sap_new_freq); + goto update_freq; + } + + if (user_config_freq && (pcl.pcl_list[i] == user_config_freq)) { + sap_new_freq = pcl.pcl_list[i]; + policy_mgr_debug("Prefer starting SAP on user configured channel:%d", + sap_new_freq); + goto update_freq; + } + } + + /* If no SBS Try get SCC freq */ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ch_freq) || + (WLAN_REG_IS_5GHZ_CH_FREQ(sap_ch_freq) && + WLAN_REG_IS_5GHZ_CH_FREQ(*intf_ch_freq))) { + for (i = 0; i < pcl.pcl_len; i++) { + if (pcl.pcl_list[i] == *intf_ch_freq) { + sap_new_freq = pcl.pcl_list[i]; + break; + } + } + } + +update_freq: + *intf_ch_freq = sap_new_freq; + policy_mgr_debug("Mandatory channel:%d org sap ch %d", *intf_ch_freq, + sap_ch_freq); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS policy_mgr_get_valid_chan_weights(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_chan_weights *weight, + enum policy_mgr_con_mode mode, struct wlan_objmgr_vdev *vdev) +{ + uint32_t i, j; + struct policy_mgr_conc_connection_info + info[MAX_NUMBER_OF_CONC_CONNECTIONS] = { {0} }; + uint8_t num_del = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool strict_follow_pcl = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_set(weight->weighed_valid_list, NUM_CHANNELS, + WEIGHT_OF_DISALLOWED_CHANNELS); + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + if ((mode == PM_P2P_GO_MODE || mode == PM_P2P_CLIENT_MODE) || + (mode == PM_STA_MODE && + policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL))) { + /* + * Store the STA mode's parameter and temporarily delete it + * from the concurrency table. This way the allow concurrency + * check can be used as though a new connection is coming up, + * allowing to detect the disallowed channels. + */ + if (mode == PM_STA_MODE) { + if (policy_mgr_concurrent_sta_on_different_mac(psoc) && + !wlan_cm_same_band_sta_allowed(psoc) && + weight->pcl_len) { + policy_mgr_debug("sta follow pcl strictly"); + strict_follow_pcl = true; + } + if (vdev) + policy_mgr_store_and_del_conn_info_by_vdev_id( + psoc, wlan_vdev_get_id(vdev), + info, &num_del); + else + policy_mgr_store_and_del_conn_info(psoc, + mode, true, + info, + &num_del); + } + /* + * For two port/three port connection strictly follow + * PCL weight if coming intf is p2p GO/GC and existing + * vdev is SAP/P2PGO/P2PGC. + */ + if ((mode == PM_P2P_GO_MODE || mode == PM_P2P_CLIENT_MODE) && + ((policy_mgr_get_beaconing_mode_count(psoc, NULL)) || + policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_CLIENT_MODE, NULL))) + strict_follow_pcl = true; + + /* + * This is a temporary check and will be removed once ll_lt_sap + * CSA support is added. + */ + if (wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc) != + WLAN_INVALID_VDEV_ID) { + policy_mgr_debug("LL_LT_SAP present, strict follow PCL"); + strict_follow_pcl = true; + } + + /* + * There is a small window between releasing the above lock + * and acquiring the same in policy_mgr_allow_concurrency, + * below! + */ + + for (i = 0; i < weight->saved_num_chan; i++) { + /* + * If channel is not allowed for concurrency, keep pcl + * weight as 0 (WEIGHT_OF_DISALLOWED_CHANNELS) + */ + if (!policy_mgr_is_concurrency_allowed + (psoc, mode, weight->saved_chan_list[i], + HW_MODE_20_MHZ, + policy_mgr_get_conc_ext_flags(vdev, false), NULL)) + continue; + /* + * Keep weight 0 (WEIGHT_OF_DISALLOWED_CHANNELS) not + * changed for scenarios which require to follow PCL. + */ + if (strict_follow_pcl) + continue; + weight->weighed_valid_list[i] = + WEIGHT_OF_NON_PCL_CHANNELS; + } + /* Restore the connection info */ + if (mode == PM_STA_MODE) + policy_mgr_restore_deleted_conn_info(psoc, info, + num_del); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + for (i = 0; i < weight->saved_num_chan; i++) { + for (j = 0; j < weight->pcl_len; j++) { + if (weight->saved_chan_list[i] == weight->pcl_list[j]) { + weight->weighed_valid_list[i] = + weight->weight_list[j]; + break; + } + } + } + + return QDF_STATUS_SUCCESS; +} + +uint32_t policy_mgr_mode_specific_get_channel( + struct wlan_objmgr_psoc *psoc, enum policy_mgr_con_mode mode) +{ + uint32_t conn_index; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t freq = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + /* provides the channel for the first matching mode type */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_index = 0; conn_index < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_index++) { + if ((pm_conc_connection_list[conn_index].mode == mode) && + pm_conc_connection_list[conn_index].in_use) { + freq = pm_conc_connection_list[conn_index].freq; + break; + } + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return freq; +} + +uint32_t policy_mgr_get_connection_count_with_ch_freq(uint32_t ch_freq) +{ + uint32_t i; + uint32_t count = 0; + + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (pm_conc_connection_list[i].in_use && + ch_freq == pm_conc_connection_list[i].freq) + count++; + } + + return count; +} + +uint32_t policy_mgr_get_alternate_channel_for_sap( + struct wlan_objmgr_psoc *psoc, uint8_t sap_vdev_id, + uint32_t sap_ch_freq, + enum reg_wifi_band pref_band) +{ + uint32_t pcl_channels[NUM_CHANNELS]; + uint8_t pcl_weight[NUM_CHANNELS]; + uint32_t ch_freq = 0; + uint32_t pcl_len = 0; + uint32_t first_valid_dfs_5g_freq = 0; + uint32_t first_valid_non_dfs_5g_freq = 0; + uint32_t first_valid_6g_freq = 0; + struct policy_mgr_conc_connection_info info; + uint8_t num_cxn_del = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t i; + enum policy_mgr_con_mode con_mode; + bool is_6ghz_cap; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return 0; + } + con_mode = policy_mgr_con_mode_by_vdev_id(psoc, sap_vdev_id); + is_6ghz_cap = policy_mgr_get_ap_6ghz_capable(psoc, sap_vdev_id, NULL); + /* + * Store the connection's parameter and temporarily delete it + * from the concurrency table. This way the get pcl can be used as a + * new connection is coming up, after check, restore the connection to + * concurrency table. + */ + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, sap_vdev_id, + &info, &num_cxn_del); + if (QDF_STATUS_SUCCESS == policy_mgr_get_pcl( + psoc, con_mode, pcl_channels, &pcl_len, + pcl_weight, QDF_ARRAY_SIZE(pcl_weight), sap_vdev_id)) { + for (i = 0; i < pcl_len; i++) { + /* + * The API is expected to select the channel on the + * other band which is not same as sap's home and + * concurrent interference channel (if present), + * so skip the sap home channel in PCL. + */ + if (pcl_channels[i] == sap_ch_freq) + continue; + if (!is_6ghz_cap && + WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl_channels[i])) + continue; + if (policy_mgr_get_connection_count(psoc) && + policy_mgr_are_2_freq_on_same_mac(psoc, + sap_ch_freq, + pcl_channels[i])) + continue; + if (policy_mgr_get_connection_count_with_ch_freq( + pcl_channels[i])) { + ch_freq = pcl_channels[i]; + break; + } else if (!ch_freq) { + ch_freq = pcl_channels[i]; + } + if (!first_valid_non_dfs_5g_freq && + wlan_reg_is_5ghz_ch_freq(pcl_channels[i])) { + if (!wlan_reg_is_dfs_in_secondary_list_for_freq( + pm_ctx->pdev, + pcl_channels[i])) { + first_valid_non_dfs_5g_freq = pcl_channels[i]; + if (pref_band == REG_BAND_5G) + break; + } else if (!first_valid_dfs_5g_freq) { + first_valid_dfs_5g_freq = pcl_channels[i]; + } + } + if (!first_valid_6g_freq && + wlan_reg_is_6ghz_chan_freq(pcl_channels[i])) { + first_valid_6g_freq = pcl_channels[i]; + if (pref_band == REG_BAND_6G) + break; + } + } + } + + /* Restore the connection entry */ + if (num_cxn_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, &info, num_cxn_del); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + if (pref_band == REG_BAND_6G) { + if (first_valid_6g_freq) + ch_freq = first_valid_6g_freq; + else if (first_valid_non_dfs_5g_freq) + ch_freq = first_valid_non_dfs_5g_freq; + else if (first_valid_dfs_5g_freq) + ch_freq = first_valid_dfs_5g_freq; + } else if (pref_band == REG_BAND_5G) { + if (first_valid_non_dfs_5g_freq) + ch_freq = first_valid_non_dfs_5g_freq; + else if (first_valid_dfs_5g_freq) + ch_freq = first_valid_dfs_5g_freq; + } + + return ch_freq; +} + +/* + * Buffer len size to consider the 4 char freq, 3 char weight, 2 char + * for open close brackets and space and a space, Total 10 + */ +#define CHAN_WEIGHT_CHAR_LEN 10 +#define MAX_CHAN_TO_PRINT 39 + +bool policy_mgr_dump_channel_list(uint32_t len, uint32_t *pcl_channels, + uint8_t *pcl_weight) +{ + uint32_t idx, buff_len, num = 0, count = 0; + char *chan_buff = NULL; + + buff_len = (QDF_MIN(len, MAX_CHAN_TO_PRINT) * CHAN_WEIGHT_CHAR_LEN) + 1; + chan_buff = qdf_mem_malloc(buff_len); + if (!chan_buff) + return false; + + policymgr_nofl_debug("Total PCL Chan Freq %d", len); + for (idx = 0; (idx < len) && (idx < NUM_CHANNELS); idx++) { + num += qdf_scnprintf(chan_buff + num, buff_len - num, + " %d[%d]", pcl_channels[idx], + pcl_weight[idx]); + count++; + if (count >= MAX_CHAN_TO_PRINT) { + /* Print the MAX_CHAN_TO_PRINT channels */ + policymgr_nofl_debug("Freq[weight]:%s", + chan_buff); + count = 0; + num = 0; + } + } + /* Print any pending channels */ + if (num) + policymgr_nofl_debug("Freq[weight]:%s", chan_buff); + + qdf_mem_free(chan_buff); + + return true; +} + +QDF_STATUS policy_mgr_filter_passive_ch(struct wlan_objmgr_pdev *pdev, + uint32_t *ch_freq_list, + uint32_t *ch_cnt) +{ + size_t ch_index; + size_t target_ch_cnt = 0; + + if (!pdev || !ch_freq_list || !ch_cnt) { + policy_mgr_err("NULL parameters"); + return QDF_STATUS_E_FAULT; + } + + for (ch_index = 0; ch_index < *ch_cnt; ch_index++) { + if (wlan_reg_is_passive_for_freq(pdev, + ch_freq_list[ch_index])) { + policy_mgr_debug("Remove freq: %d from list as it's passive", + ch_freq_list[ch_index]); + continue; + } + ch_freq_list[target_ch_cnt++] = ch_freq_list[ch_index]; + } + + *ch_cnt = target_ch_cnt; + + return QDF_STATUS_SUCCESS; +} + +bool policy_mgr_is_3rd_conn_on_same_band_allowed(struct wlan_objmgr_psoc *psoc, + enum policy_mgr_con_mode mode, + qdf_freq_t ch_freq) +{ + enum policy_mgr_pcl_type pcl = PM_NONE; + enum policy_mgr_conc_priority_mode conc_system_pref = 0; + enum policy_mgr_two_connection_mode third_index = 0; + struct policy_mgr_psoc_priv_obj *pm_ctx; + bool ret = false; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("context is NULL"); + return false; + } + + if (pm_conc_connection_list[0].freq != ch_freq || + pm_conc_connection_list[0].freq != + pm_conc_connection_list[1].freq) { + policy_mgr_debug("No MCC support in 3vif in same mac: %d %d %d", + pm_conc_connection_list[0].freq, + pm_conc_connection_list[1].freq, + ch_freq); + return false; + } + + policy_mgr_debug("pref:%d requested mode:%d", + pm_ctx->cur_conc_system_pref, mode); + + switch (pm_ctx->cur_conc_system_pref) { + case 0: + conc_system_pref = PM_THROUGHPUT; + break; + case 1: + conc_system_pref = PM_POWERSAVE; + break; + case 2: + conc_system_pref = PM_LATENCY; + break; + default: + policy_mgr_err("unknown cur_conc_system_pref value %d", + pm_ctx->cur_conc_system_pref); + break; + } + + third_index = policy_mgr_get_third_connection_pcl_table_index(psoc); + if (PM_MAX_TWO_CONNECTION_MODE == third_index) { + policy_mgr_err( + "couldn't find index for 3rd connection pcl table"); + return false; + } + if (policy_mgr_is_hw_dbs_capable(psoc) == true) { + pcl = (*third_connection_pcl_dbs_table) + [third_index][mode][conc_system_pref]; + } else { + pcl = (*third_connection_pcl_non_dbs_table) + [third_index][mode][conc_system_pref]; + } + + policy_mgr_debug("pcl for third connection mode %s is %d %s", + device_mode_to_string(mode), pcl, + pcl_type_to_string(pcl)); + switch (pcl) { + case PM_SCC_CH: + case PM_SCC_CH_24G: + case PM_SCC_CH_5G: + case PM_24G_SCC_CH: + case PM_5G_SCC_CH: + case PM_SCC_ON_5_CH_5G: + case PM_SCC_ON_5_SCC_ON_24_24G: + case PM_SCC_ON_5_SCC_ON_24_5G: + case PM_SCC_ON_5_5G_24G: + case PM_SCC_ON_5_5G_SCC_ON_24G: + case PM_SCC_ON_24_SCC_ON_5_24G: + case PM_SCC_ON_24_SCC_ON_5_5G: + case PM_SCC_ON_24_CH_24G: + case PM_SCC_ON_5_SCC_ON_24: + case PM_SCC_ON_24_SCC_ON_5: + case PM_24G_SCC_CH_SBS_CH: + case PM_24G_SCC_CH_SBS_CH_5G: + case PM_SBS_CH_24G_SCC_CH: + case PM_SBS_CH_SCC_CH_24G: + case PM_SCC_CH_SBS_CH_24G: + case PM_SBS_CH_SCC_CH_5G_24G: + case PM_SCC_CH_MCC_CH_SBS_CH_24G: + case PM_MCC_CH: + case PM_MCC_CH_24G: + case PM_MCC_CH_5G: + case PM_24G_MCC_CH: + case PM_5G_MCC_CH: + case PM_24G_SBS_CH_MCC_CH: + ret = true; + break; + default: + policy_mgr_debug("Not in SCC case"); + ret = false; + break; + } + return ret; +} + +bool policy_mgr_is_sta_chan_valid_for_connect_and_roam( + struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq) +{ + struct wlan_objmgr_psoc *psoc; + uint32_t sap_count; + bool skip_6g_and_indoor_freq; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return true; + + skip_6g_and_indoor_freq = + wlan_scan_cfg_skip_6g_and_indoor_freq(psoc); + sap_count = + policy_mgr_get_sap_mode_count(psoc, NULL); + /* + * Do not allow STA to connect/roam on 6Ghz or indoor channel for + * non-dbs hardware if SAP is present and skip_6g_and_indoor_freq_scan + * ini is enabled + */ + if (skip_6g_and_indoor_freq && sap_count && + !policy_mgr_is_hw_dbs_capable(psoc) && + (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq) || + wlan_reg_is_freq_indoor(pdev, freq))) + return false; + + return true; +} + +/** + * _policy_mgr_is_vdev_ll_sap() - Check whether any LL SAP is present or not + * for provided ap policy + * @psoc: psoc object + * @vdev_id: vdev id + * @ap_type: LL SAP type + * + * Return: true if it's present otherwise false + */ +static bool +_policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, enum ll_ap_type ap_type) +{ + struct wlan_objmgr_vdev *vdev; + bool is_ll_sap = false; + enum QDF_OPMODE mode; + struct policy_mgr_psoc_priv_obj *pm_ctx; + enum host_concurrent_ap_policy profile = + HOST_CONCURRENT_AP_POLICY_UNSPECIFIED; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid pm_ctx"); + return is_ll_sap; + } + + mode = wlan_get_opmode_from_vdev_id(pm_ctx->pdev, vdev_id); + + if (mode != QDF_SAP_MODE) + return is_ll_sap; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_POLICY_MGR_ID); + if (!vdev) { + policy_mgr_err("vdev %d: invalid vdev", vdev_id); + return is_ll_sap; + } + + profile = wlan_mlme_get_ap_policy(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_POLICY_MGR_ID); + switch (ap_type) { + case LL_AP_TYPE_HT: + if (profile == HOST_CONCURRENT_AP_POLICY_XR) + is_ll_sap = true; + break; + case LL_AP_TYPE_LT: + if (profile == HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO || + profile == + HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING) + is_ll_sap = true; + break; + case LL_AP_TYPE_ANY: + if (profile == HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO || + profile == + HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING || + profile == HOST_CONCURRENT_AP_POLICY_XR) + is_ll_sap = true; + break; + default: + policy_mgr_err("invalid ap type %d", ap_type); + } + return is_ll_sap; +} + +bool +policy_mgr_is_vdev_ll_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + return _policy_mgr_is_vdev_ll_sap(psoc, vdev_id, LL_AP_TYPE_ANY); +} + +bool +policy_mgr_is_vdev_ll_ht_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + return _policy_mgr_is_vdev_ll_sap(psoc, vdev_id, LL_AP_TYPE_HT); +} + +bool +policy_mgr_is_vdev_ll_lt_sap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + return _policy_mgr_is_vdev_ll_sap(psoc, vdev_id, LL_AP_TYPE_LT); +} + +#ifndef WLAN_FEATURE_LL_LT_SAP +QDF_STATUS +policy_mgr_get_pcl_chlist_for_ll_sap(struct wlan_objmgr_psoc *psoc, + uint32_t *len, uint32_t *pcl_channels, + uint8_t *pcl_weight) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t pcl_len = 0, i, conn_idx = 0; + uint32_t pcl_list[NUM_CHANNELS], total_connection = 0; + uint8_t weight_list[NUM_CHANNELS]; + qdf_freq_t freq; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is null"); + return QDF_STATUS_E_FAILURE; + } + + total_connection = policy_mgr_get_connection_count(psoc); + if (!total_connection) { + for (i = 0; i < *len; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(pcl_channels[i])) + continue; + + pcl_list[pcl_len] = pcl_channels[i]; + weight_list[pcl_len++] = pcl_weight[i]; + } + qdf_mem_zero(pcl_channels, *len * sizeof(*pcl_channels)); + qdf_mem_copy(pcl_channels, pcl_list, + pcl_len * sizeof(*pcl_channels)); + } else { + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_idx = 0; conn_idx < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_idx++) { + if (!pm_conc_connection_list[conn_idx].in_use) + continue; + + freq = pm_conc_connection_list[conn_idx].freq; + + for (i = 0; i < *len; i++) { + if (policy_mgr_2_freq_always_on_same_mac( + psoc, + pcl_channels[i], + freq) || + WLAN_REG_IS_24GHZ_CH_FREQ(pcl_channels[i])) + continue; + pcl_list[pcl_len] = pcl_channels[i]; + weight_list[pcl_len++] = pcl_weight[i]; + } + *len = pcl_len; + qdf_mem_zero(pcl_channels, + *len * sizeof(*pcl_channels)); + qdf_mem_copy(pcl_channels, pcl_list, + pcl_len * sizeof(*pcl_channels)); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + } + + qdf_mem_zero(pcl_weight, *len * sizeof(*pcl_weight)); + qdf_mem_copy(pcl_weight, weight_list, pcl_len); + *len = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_pcl_ch_for_sap_go_with_ll_sap_present( + struct wlan_objmgr_psoc *psoc, + uint32_t *len, uint32_t *pcl_channels, + uint8_t *pcl_weight) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint32_t pcl_len = 0, i, conn_idx = 0; + uint32_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; + qdf_freq_t freq; + uint32_t vdev_id; + bool is_ll_sap = 0; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is null"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + for (conn_idx = 0; conn_idx < MAX_NUMBER_OF_CONC_CONNECTIONS; + conn_idx++) { + if (!pm_conc_connection_list[conn_idx].in_use) + continue; + + freq = pm_conc_connection_list[conn_idx].freq; + vdev_id = pm_conc_connection_list[conn_idx].vdev_id; + if (!policy_mgr_is_vdev_ll_sap(psoc, vdev_id)) + continue; + + is_ll_sap = 1; + for (i = 0; i < *len; i++) { + if (policy_mgr_2_freq_always_on_same_mac( + psoc, + pcl_channels[i], + freq)) + continue; + pcl_list[pcl_len] = pcl_channels[i]; + weight_list[pcl_len++] = pcl_weight[i]; + } + *len = pcl_len; + qdf_mem_zero(pcl_channels, + *len * sizeof(*pcl_channels)); + qdf_mem_copy(pcl_channels, pcl_list, + pcl_len * sizeof(*pcl_channels)); + } + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + if (!is_ll_sap) + return QDF_STATUS_SUCCESS; + + qdf_mem_zero(pcl_weight, *len * sizeof(*pcl_weight)); + qdf_mem_copy(pcl_weight, weight_list, pcl_len); + *len = pcl_len; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +policy_mgr_get_pcl_channel_for_ll_sap_concurrency( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint32_t *pcl_channels, + uint8_t *pcl_weight, uint32_t *len) +{ + uint32_t orig_len = *len; + + if (policy_mgr_is_vdev_ll_sap(psoc, vdev_id)) { + /* Scenario: If there is some existing interface present and + * LL SAP is coming up. + * Filter pcl channel for LL SAP + */ + policy_mgr_get_pcl_chlist_for_ll_sap(psoc, len, pcl_channels, + pcl_weight); + } else { + /* Scenario: If there is LL SAP and GO/SAP is coming up. + * Filter pcl channel for GO/SAP + */ + policy_mgr_get_pcl_ch_for_sap_go_with_ll_sap_present( + psoc, + len, + pcl_channels, + pcl_weight); + } + + if (orig_len != *len) { + policy_mgr_debug("PCL after ll sap modification"); + policy_mgr_dump_channel_list(*len, pcl_channels, pcl_weight); + } + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_LL_LT_SAP +QDF_STATUS policy_mgr_get_pcl_ch_list_for_ll_sap( + struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_list *pcl, + uint8_t vdev_id, + struct connection_info *info, + uint8_t *connection_count) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + uint8_t num_cxn_del = 0; + struct policy_mgr_conc_connection_info pm_info = {0}; + QDF_STATUS status; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) + return QDF_STATUS_E_FAILURE; + + qdf_mutex_acquire(&pm_ctx->qdf_conc_list_lock); + + /* + * Scenario: Standalone XPAN is present and CSA happens on + * LL_LT_SAP interface. + * During CSA, it will check the PCL list to get the new freq. + * Since there is already LL_LT_SAP interface entry in PCL index. + * It will lead to LL_LT_SAP + LL_LT_SAP concurrencies. To avoid + * that, delete the existing connection entry from PCL index, + * get the PCL list and restore it back. + */ + policy_mgr_store_and_del_conn_info_by_vdev_id(psoc, vdev_id, + &pm_info, &num_cxn_del); + + status = policy_mgr_get_pcl(psoc, PM_LL_LT_SAP_MODE, pcl->pcl_list, + &pcl->pcl_len, pcl->weight_list, + QDF_ARRAY_SIZE(pcl->weight_list), + vdev_id); + + /* + * Get existing connection info before updating LL_LT_SAP freq list + * This will help to avoid updation of SCC channel in LL_LT_SAP + * freq list. + */ + *connection_count = policy_mgr_get_connection_info(psoc, info); + + /* Restore the connection entry */ + if (num_cxn_del > 0) + policy_mgr_restore_deleted_conn_info(psoc, &pm_info, + num_cxn_del); + + qdf_mutex_release(&pm_ctx->qdf_conc_list_lock); + + return status; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h new file mode 100644 index 0000000000..3da7e75b6b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_1x1_dbs_i.h @@ -0,0 +1,2283 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_TABLES_1X1_DBS_H +#define __WLAN_POLICY_MGR_TABLES_1X1_DBS_H + +#include "wlan_policy_mgr_api.h" + +/* + * second_connection_pcl_dbs_1x1_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS supported by HW) + */ +pm_dbs_pcl_second_connection_table_type +pm_second_connection_pcl_dbs_1x1_table = { + [PM_STA_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + + [PM_STA_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + + [PM_STA_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G} }, + + [PM_STA_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G} }, + + [PM_P2P_CLI_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + + [PM_P2P_CLI_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + + [PM_P2P_CLI_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G} }, + + [PM_P2P_CLI_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G} }, + + [PM_P2P_GO_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + + [PM_P2P_GO_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + + [PM_SAP_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + + [PM_SAP_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + + [PM_SAP_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G} }, + + [PM_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G} }, +}; + +/* + * third_connection_pcl_dbs_table - table which provides PCL for + * the 3rd connection, when we have two connections already in + * the system (with DBS supported by HW). For helium that is NON-DBS, + * DBS 1x1, three port concurrency would be disabled, so for every + * combination MAX_PCL_TYPE would be the return value, if in future + * the requirement for 3 port concurrency comes, refer to below table + * for details. + * static pm_dbs_pcl_third_connection_table_type + * pm_third_connection_pcl_dbs_1x1_table = { + * [PM_STA_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + + * + * [PM_STA_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + * + * [PM_STA_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + * + * [PM_STA_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + * + * [PM_STA_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + * + * [PM_STA_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + * + * [PM_STA_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + * + * [PM_STA_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + * + * [PM_STA_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_SCC_ON_5_SCC_ON_24_5G, PM_NONE, PM_SCC_ON_5_SCC_ON_24}, + * [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24} }, + * + * [PM_SAP_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + * + * [PM_SAP_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G} }, + * + * [PM_SAP_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_SAP_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_SAP_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + * PM_24G_SCC_CH_SBS_CH}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + * + * [PM_SAP_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + * PM_24G_SCC_CH_SBS_CH}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G} }, + * + * [PM_SAP_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + * [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_SAP_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + * [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_SAP_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_SAP_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_SAP_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24}, + * [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24} }, + * + * [PM_STA_P2P_GO_SCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + * + * [PM_STA_P2P_GO_SCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_5G, PM_5G_MCC_CH} }, + * + * [PM_STA_P2P_GO_SCC_5_1x1] = { + * [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G} }, + * + * [PM_STA_P2P_GO_SCC_5_2x2] = { + * [PM_STA_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_24G_SCC_CH, PM_SCC_CH_24G} }, + * + * [PM_STA_P2P_GO_MCC_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G} }, + * + * [PM_STA_P2P_GO_MCC_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G} }, + * + * [PM_STA_P2P_GO_MCC_24_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G} }, + * + * [PM_STA_P2P_GO_MCC_24_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH_5G, PM_5G, PM_5G}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH_24G, PM_24G, PM_24G} }, + * + * [PM_STA_P2P_GO_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_SCC_ON_5_SCC_ON_24_5G, PM_NONE, PM_SCC_ON_5_SCC_ON_24}, + * [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_SCC_ON_5_SCC_ON_24_5G, PM_NONE, PM_SCC_ON_5_SCC_ON_24} }, + * + * [PM_STA_P2P_CLI_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + * PM_SCC_ON_5_SCC_ON_24}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * }; + */ +static pm_dbs_pcl_third_connection_table_type +pm_third_connection_pcl_dbs_1x1_table = { + [PM_STA_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_DBS_2x2] = { + [PM_STA_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_DBS_1x1] = { + [PM_STA_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_DBS_2x2] = { + [PM_STA_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} + }, + + [PM_NAN_DISC_NDI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} + }, + + [PM_NAN_DISC_NDI_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} + }, + + [PM_NAN_DISC_NDI_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} + }, + + [PM_NAN_DISC_NDI_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} + }, + + [PM_NAN_DISC_NDI_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} + }, +}; + +/* + * next_action_two_connection_table - table which provides next + * action while a new connection is coming up, with one + * connection already in the system + */ +static policy_mgr_next_action_two_connection_table_type + pm_next_action_two_connection_dbs_1x1_table = { + [PM_STA_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_CLI_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_CLI_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_CLI_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_CLI_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_SAP_24_1x1] = {PM_NOP, PM_DBS}, + [PM_SAP_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_SAP_5_1x1] = {PM_DBS, PM_NOP}, + [PM_SAP_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, +}; + +/* + * next_action_three_connection_table - table which provides next + * action while a new connection is coming up, with two + * connections already in the system + */ +static policy_mgr_next_action_three_connection_table_type + pm_next_action_three_connection_dbs_1x1_table = { + [PM_STA_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_SAP_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_STA_SAP_MCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_SAP_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_STA_SAP_MCC_24_5_1x1] = {PM_DBS, PM_DBS}, + [PM_STA_SAP_MCC_24_5_2x2] = {PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE}, + [PM_STA_SAP_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_DBS, PM_DBS}, + [PM_STA_P2P_GO_MCC_24_5_2x2] = { + PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE}, + [PM_STA_P2P_GO_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_P2P_CLI_SCC_24_2x2] = { + PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_P2P_CLI_MCC_24_2x2] = { + PM_NOP, PM_DBS_DOWNGRADE}, + [PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_DBS, PM_DBS}, + [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE}, + [PM_STA_P2P_CLI_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_DBS, PM_DBS}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_SAP_MCC_24_5_1x1] = {PM_DBS, PM_DBS}, + [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE}, + [PM_P2P_GO_SAP_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS_DOWNGRADE}, + [PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS_DOWNGRADE, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_DBS, PM_DBS}, + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_DBS_DOWNGRADE, PM_DBS_DOWNGRADE}, + [PM_P2P_CLI_SAP_DBS_1x1] = {PM_NOP, PM_NOP}, + + [PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_SAP_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP}, + +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h new file mode 100644 index 0000000000..450bcc3db4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_2g_1x1_5g.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_TABLES_2X2_2G_1X1_5G_DBS_H +#define __WLAN_POLICY_MGR_TABLES_2X2_2G_1X1_5G_DBS_H + +#include "wlan_policy_mgr_api.h" + +/* + * next_action_two_connection_table - table which provides next + * action while a new connection is coming up, with one + * connection already in the system + */ +static policy_mgr_next_action_two_connection_table_type + pm_next_action_two_connection_dbs_2x2_2g_1x1_5g_table = { + [PM_STA_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_5_2x2] = {PM_DBS2, PM_NOP}, + [PM_P2P_CLI_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_CLI_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_CLI_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_CLI_5_2x2] = {PM_DBS2, PM_NOP}, + [PM_P2P_GO_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_GO_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_SAP_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_SAP_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_SAP_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_SAP_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, +}; + +/* + * next_action_three_connection_table - table which provides next + * action while a new connection is coming up, with two + * connections already in the system + */ +static policy_mgr_next_action_three_connection_table_type + pm_next_action_three_connection_dbs_2x2_2g_1x1_5g_table = { + [PM_STA_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_STA_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_STA_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_STA_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_STA_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_STA_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + + [PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_STA_P2P_GO_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_STA_P2P_GO_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_STA_P2P_GO_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + + [PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS2, PM_NOP}, + [PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS2, PM_NOP}, + [PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_MCC_24_5_2x2] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_DBS_1x1] = {PM_NOP, PM_DBS2}, + [PM_STA_P2P_CLI_DBS_2x2] = {PM_NOP, PM_DBS2}, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, + PM_DBS2_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, + PM_DBS2_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + + [PM_P2P_GO_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_P2P_GO_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_GO_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_GO_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_GO_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_CLI_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_P2P_CLI_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + + [PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_SAP_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_SAP_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS2}, + [PM_SAP_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS2}, + [PM_SAP_SAP_SCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_SAP_SAP_SCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_SAP_SAP_MCC_5_1x1] = {PM_DBS2, PM_NOP}, + [PM_SAP_SAP_MCC_5_2x2] = {PM_DBS2_DOWNGRADE, PM_NOP}, + [PM_SAP_SAP_MCC_24_5_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_SAP_SAP_MCC_24_5_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_SAP_SAP_DBS_1x1] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, + [PM_SAP_SAP_DBS_2x2] = {PM_DBS2_DOWNGRADE, PM_DBS2_DOWNGRADE}, +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h new file mode 100644 index 0000000000..74e853391a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_5g_1x1_2g.h @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_TABLES_2X2_5G_1X1_2G_DBS_H +#define __WLAN_POLICY_MGR_TABLES_2X2_5G_1X1_2G_DBS_H + +#include "wlan_policy_mgr_api.h" + +/* + * next_action_two_connection_table - table which provides next + * action while a new connection is coming up, with one + * connection already in the system + */ +static policy_mgr_next_action_two_connection_table_type + pm_next_action_two_connection_dbs_2x2_5g_1x1_2g_table = { + [PM_STA_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_24_2x2] = {PM_NOP, PM_DBS1}, + [PM_STA_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_CLI_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_CLI_24_2x2] = {PM_NOP, PM_DBS1}, + [PM_P2P_CLI_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_CLI_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_GO_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_SAP_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_SAP_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_SAP_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_SAP_5_2x2] = {PM_DBS1, PM_NOP}, +}; + +/* + * next_action_three_connection_table - table which provides next + * action while a new connection is coming up, with two + * connections already in the system + */ +static policy_mgr_next_action_three_connection_table_type + pm_next_action_three_connection_dbs_2x2_5g_1x1_2g_table = { + [PM_STA_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_STA_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_STA_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_STA_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_STA_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_STA_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_STA_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_STA_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + + [PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_STA_P2P_GO_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_STA_P2P_GO_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_STA_P2P_GO_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + + [PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS1}, + [PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_STA_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS1}, + [PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_DBS1, PM_DBS1}, + [PM_STA_P2P_CLI_MCC_24_5_2x2] = {PM_DBS1, PM_DBS1}, + [PM_STA_P2P_CLI_DBS_1x1] = {PM_DBS1, PM_DBS1}, + [PM_STA_P2P_CLI_DBS_2x2] = {PM_DBS1, PM_DBS1}, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, + PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, + PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + + [PM_P2P_GO_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_GO_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_GO_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_GO_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_GO_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_CLI_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_P2P_CLI_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + + [PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_SAP_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_SAP_SAP_MCC_24_1x1] = {PM_NOP, PM_DBS1}, + [PM_SAP_SAP_MCC_24_2x2] = {PM_NOP, PM_DBS1_DOWNGRADE}, + [PM_SAP_SAP_SCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_SAP_SAP_SCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_SAP_SAP_MCC_5_1x1] = {PM_DBS1, PM_NOP}, + [PM_SAP_SAP_MCC_5_2x2] = {PM_DBS1, PM_NOP}, + [PM_SAP_SAP_MCC_24_5_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_SAP_SAP_MCC_24_5_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_SAP_SAP_DBS_1x1] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, + [PM_SAP_SAP_DBS_2x2] = {PM_DBS1_DOWNGRADE, PM_DBS1_DOWNGRADE}, +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h new file mode 100644 index 0000000000..663f48b49b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_i.h @@ -0,0 +1,2580 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_TABLES_2X2_DBS_H +#define __WLAN_POLICY_MGR_TABLES_2X2_DBS_H + +#include "wlan_policy_mgr_api.h" + +/* + * second_connection_pcl_dbs_2x2_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS supported by HW) + * This table consolidates selection for P2PCLI, P2PGO, STA, SAP + * into the single set of STA entries for 2.4G and 5G. + */ +static pm_dbs_pcl_second_connection_table_type +pm_second_connection_pcl_dbs_2x2_table = { + [PM_STA_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, + PM_SCC_CH_24G, PM_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH_24G, + PM_SCC_CH_24G, PM_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, + PM_SCC_CH_24G, PM_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, + PM_SCC_CH_24G, PM_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH_24G, + PM_SCC_CH_24G, PM_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, + PM_SCC_CH_24G, PM_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_SAP_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH_5G} }, + + [PM_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_GO_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH_5G} }, + + [PM_NAN_DISC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24 }, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, + PM_5G_SCC_CH }, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_LL_LT_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, +}; + +/* + * third_connection_pcl_dbs_table - table which provides PCL for + * the 3rd connection, when we have two connections already in + * the system (with DBS supported by HW) + */ +static pm_dbs_pcl_third_connection_table_type +pm_third_connection_pcl_dbs_2x2_table = { + [PM_STA_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_DBS_1x1] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_GO_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_DBS_1x1] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_GO_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = { PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_1x1] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_DBS_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_GO_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_CLI_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_CLI_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_CLI_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_CLI_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, PM_24G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_STA_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_STA_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_LL_LT_SAP_MCC_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G}, + [PM_P2P_GO_MODE] = {PM_MCC_CH_SCC_ON_24G, PM_MCC_CH_SCC_ON_24G, + PM_MCC_CH_SCC_ON_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH, + PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH, + PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW, + PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW, + PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_LL_LT_SAP_MCC_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, +}; + +#ifdef FEATURE_FOURTH_CONNECTION +/* + * fourth_connection_pcl_dbs_sbs_table - table which provides PCL for + * the 4th connection, when we have 3 connections already in + * the system (with DBS & SBS supported by HW), this table is for auto products. + */ +#ifdef FOURTH_CONNECTION_AUTO +const enum policy_mgr_pcl_type +fourth_connection_pcl_dbs_sbs_table + [PM_MAX_THREE_CONNECTION_MODE][PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE] = { + [PM_STA_SAP_SCC_24_SAP_5_DBS] = { + [PM_STA_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_SAP_SCC_5_SAP_24_DBS] = { + [PM_STA_MODE] = { PM_24G, PM_24G, PM_24G } }, + [PM_STA_SAP_24_STA_5_DBS] = { + [PM_SAP_MODE] = { PM_SCC_ON_5_CH_5G, PM_SCC_ON_5_CH_5G, + PM_SCC_ON_5_CH_5G} }, + [PM_STA_SAP_5_STA_24_DBS] = { + [PM_SAP_MODE] = { PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G } }, + [PM_NAN_DISC_SAP_SCC_24_NDI_5_DBS] = { + [PM_SAP_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_NDI_SCC_24_SAP_5_DBS] = { + [PM_SAP_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_SAP_NDI_SCC_5_NAN_DISC_24_DBS] = { + [PM_SAP_MODE] = { PM_24G, PM_24G, PM_24G } } +}; +#else +/* + * fourth_connection_pcl_dbs_sbs_table - table which provides PCL for + * the 4th connection, when we have 3 connections already in + * the system (with DBS & SBS supported by HW), this table is for mobile + * products If you want to support any 4 port other than the below in MCL add + * below as other concurrencies supported by auto may not be PORed for mobile + * products and vice-versa. + */ +const enum policy_mgr_pcl_type +fourth_connection_pcl_dbs_sbs_table + [PM_MAX_THREE_CONNECTION_MODE][PM_MAX_NUM_OF_MODE] + [PM_MAX_CONC_PRIORITY_MODE] = { +#if !defined(MDM_PLATFORM) + [PM_NAN_DISC_STA_24_NDI_5_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_NDI_24_STA_5_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_NDI_5_NAN_DISC_24_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_NDI_NAN_DISC_24_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_NDI_24_NDI_5_DBS] = { + [PM_STA_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NDI_NDI_5_NAN_DISC_24_DBS] = { + [PM_STA_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NDI_NDI_NAN_DISC_24_SMM] = { + [PM_STA_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_STA_5_NAN_DISC_24_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_24_STA_STA_5_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_STA_24_NAN_DISC_24_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_24_STA_STA_24_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_24_STA_5_NAN_DISC_24_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_24_STA_5_NAN_DISC_24_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_5_STA_24_NAN_DISC_24_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_STA_5_STA_24_NAN_DISC_24_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_24_STA_5_STA_24_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_24_STA_5_STA_24_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_24_STA_24_STA_5_SMM] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, + [PM_NAN_DISC_24_STA_24_STA_5_DBS] = { + [PM_NDI_MODE] = { PM_5G, PM_5G, PM_5G } }, +#endif + [PM_24_SCC_MCC_PLUS_5_DBS] = { + [PM_STA_MODE] = { PM_SCC_ON_5_CH_5G, PM_SCC_ON_5_CH_5G, + PM_SCC_ON_5_CH_5G}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24} }, + [PM_5_SCC_MCC_PLUS_24_DBS] = { + [PM_STA_MODE] = { PM_SBS_CH_2G, PM_SBS_CH_2G, + PM_SBS_CH_2G }, + [PM_SAP_MODE] = { PM_SCC_ON_24_SCC_ON_5, PM_SCC_ON_24_SCC_ON_5, + PM_SCC_ON_24_SCC_ON_5 } }, + [PM_MCC_SCC_5G_HIGH_PLUS_5_LOW_SBS] = { + [PM_STA_MODE] = {PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_LOW_5G_LOW_PLUS_SHARED_2G} }, + [PM_MCC_SCC_5G_LOW_PLUS_5_HIGH_SBS] = { + [PM_STA_MODE] = {PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G, + PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G, + PM_SCC_ON_5G_HIGH_5G_HIGH_PLUS_SHARED_2G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G, + PM_SCC_ON_5G_HIGH_5G_HIGH_SCC_ON_5G_LOW_PLUS_SHARED_2G} }, + [PM_24_5_PLUS_5_LOW_N_HIGH_SHARE_SBS] = { + [PM_STA_MODE] = {PM_SCC_ON_5_CH_5G, PM_SCC_ON_5_CH_5G, + PM_SCC_ON_5_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_5G_SCC_ON_24G, + PM_SCC_ON_5_5G_SCC_ON_24G} }, + [PM_24_5_PLUS_5_LOW_OR_HIGH_SHARE_SBS] = { + [PM_STA_MODE] = {PM_SCC_ON_24_CH_24G, PM_SCC_ON_24_CH_24G, + PM_SCC_ON_24_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_24G, PM_SCC_ON_24_SCC_ON_5_24G, + PM_SCC_ON_24_SCC_ON_5_24G} }, +}; +#endif +#endif + +/* + * next_action_two_connection_table - table which provides next + * action while a new connection is coming up, with one + * connection already in the system + */ +static policy_mgr_next_action_two_connection_table_type + pm_next_action_two_connection_dbs_2x2_table = { + [PM_STA_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_CLI_24_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_24_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_CLI_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_24_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_24_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_SAP_24_1x1] = {PM_NOP, PM_NOP}, + [PM_SAP_24_2x2] = {PM_NOP, PM_NOP}, + [PM_SAP_5_1x1] = {PM_DBS, PM_SBS}, + [PM_SAP_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, +}; + +/* + * next_action_three_connection_table - table which provides next + * action while a new connection is coming up, with two + * connections already in the system + */ +static policy_mgr_next_action_three_connection_table_type + pm_next_action_three_connection_dbs_2x2_table = { + [PM_STA_SAP_SCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_SCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_MCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_MCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_SAP_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_SAP_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_SAP_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_SAP_MCC_24_5_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_MCC_24_5_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_DBS_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_SAP_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_STA_P2P_GO_SCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_SCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_MCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_MCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_P2P_GO_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_P2P_GO_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_P2P_GO_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_P2P_GO_MCC_24_5_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_MCC_24_5_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_DBS_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_GO_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_STA_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_P2P_CLI_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_P2P_CLI_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_P2P_CLI_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_P2P_CLI_MCC_24_5_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_MCC_24_5_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_DBS_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_P2P_CLI_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_DBS_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_GO_P2P_CLI_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_SCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_CLI_SAP_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_CLI_SAP_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_CLI_SAP_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_DBS_2x2] = {PM_NOP, PM_NOP}, + [PM_P2P_CLI_SAP_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_P2P_CLI_P2P_CLI_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_CLI_P2P_CLI_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_CLI_P2P_CLI_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_CLI_P2P_CLI_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_CLI_P2P_CLI_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_STA_STA_SCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_STA_SCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_STA_MCC_24_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_STA_MCC_24_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_STA_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_STA_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_STA_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_STA_STA_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_STA_STA_MCC_24_5_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_STA_MCC_24_5_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_STA_DBS_1x1] = {PM_NOP, PM_NOP}, + [PM_STA_STA_DBS_2x2] = {PM_NOP, PM_NOP}, + [PM_STA_STA_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_SAP_SAP_SCC_24_1x1] = {PM_NOP, PM_DBS}, + [PM_SAP_SAP_SCC_24_2x2] = {PM_NOP, PM_DBS}, + [PM_SAP_SAP_SCC_5_1x1] = {PM_DBS, PM_NOP}, + [PM_SAP_SAP_SCC_5_2x2] = {PM_DBS, PM_NOP}, + + [PM_P2P_GO_P2P_GO_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_P2P_GO_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_P2P_GO_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_P2P_GO_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_P2P_GO_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, + + [PM_P2P_GO_SAP_SCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_SAP_SCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_SAP_MCC_5_1x1] = {PM_DBS, PM_SBS}, + [PM_P2P_GO_SAP_MCC_5_2x2] = {PM_DBS, PM_SBS_DOWNGRADE}, + [PM_P2P_GO_SAP_SBS_5_1x1] = {PM_DBS_UPGRADE, PM_NOP}, +}; + +/* + * next_action_two_connection_table_v2 - table which provides next + * action while a new connection is coming up, with one + * connection already in the system. + */ +static policy_mgr_next_action_two_connection_table_type + pm_next_action_two_connection_dbs_2x2_table_v2 = { + [PM_STA_24_1x1] = {PM_NOP, PM_DBS}, + [PM_STA_24_2x2] = {PM_NOP, PM_DBS}, + [PM_STA_5_1x1] = {PM_DBS, PM_NOP}, + [PM_STA_5_2x2] = {PM_DBS, PM_NOP}, + [PM_P2P_CLI_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_CLI_24_2x2] = {PM_NOP, PM_DBS}, + [PM_P2P_CLI_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_CLI_5_2x2] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_24_1x1] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_24_2x2] = {PM_NOP, PM_DBS}, + [PM_P2P_GO_5_1x1] = {PM_DBS, PM_NOP}, + [PM_P2P_GO_5_2x2] = {PM_DBS, PM_NOP}, + [PM_SAP_24_1x1] = {PM_NOP, PM_DBS}, + [PM_SAP_24_2x2] = {PM_NOP, PM_DBS}, + [PM_SAP_5_1x1] = {PM_DBS, PM_NOP}, + [PM_SAP_5_2x2] = {PM_DBS, PM_NOP}, +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h new file mode 100644 index 0000000000..efc6a2fb79 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_2x2_dbs_sbs_i.h @@ -0,0 +1,2208 @@ +/* + * Copyright (c) 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_TABLES_2X2_DBS_SBS_H +#define __WLAN_POLICY_MGR_TABLES_2X2_DBS_SBS_H + +#include "wlan_policy_mgr_api.h" + +/* + * pm_second_connection_pcl_dbs_sbs_2x2_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS-SBS supported by HW) + * This table consolidates selection for P2PCLI, P2PGO, STA, SAP + * into the single set of STA entries for 2.4G and 5G. + */ +static pm_dbs_pcl_second_connection_table_type +pm_second_connection_pcl_dbs_sbs_2x2_table = { + [PM_STA_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SBS_CH_SCC_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SBS_CH_SCC_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_24G_SCC_CH_SBS_CH, PM_24G_SCC_CH_SBS_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, + PM_SCC_CH_MCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + + [PM_SAP_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH_5G, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH_5G} }, + + [PM_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_SCC_CH_24G, + PM_SCC_CH_SBS_CH_24G, PM_SBS_CH_24G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH_5G} }, + + [PM_NAN_DISC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24 }, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, + PM_5G_SCC_CH }, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_LL_LT_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, +}; + +/* + * third_connection_pcl_dbs_table - table which provides PCL for + * the 3rd connection, when we have two connections already in + * the system (with DBS supported by HW) + */ +static pm_dbs_pcl_third_connection_table_type +pm_third_connection_pcl_dbs_sbs_2x2_table = { + [PM_STA_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_24G_SCC_CH, PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_24G_SCC_CH, PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_24G_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_DBS_1x1] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_SAP_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_GO_MODE] = { + PM_SBS_CH_SCC_CH_5G_24G, PM_SBS_CH, PM_SBS_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_SBS_CH_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_SBS_CH_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_SAP_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_DBS_1x1] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_SAP_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_SAP_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SBS_CH_24G_SCC_CH, PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SBS_CH_24G_SCC_CH, PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_24G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_GO_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = { PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_24G_SCC_CH, PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_24G_SCC_CH, PM_SBS_CH_24G_SCC_CH, + PM_SBS_CH_24G_SCC_CH}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + + [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_1x1] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_DBS_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_SAP_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_SCC_CH_5G_24G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_P2P_CLI_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_CLI_SAP_SBS_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = {PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_GO_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_24G, PM_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = + {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = + {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_P2P_CLI_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SBS_CH_SCC_CH_5G_24G, PM_SBS_CH, PM_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_SCC_ON_24G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_P2P_GO_P2P_CLI_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_5G_24G, PM_SCC_CH, PM_SCC_CH_24G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_STA_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_SAP_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_24G_SCC_CH_SBS_CH_5G, PM_24G_SCC_CH, + PM_24G_SCC_CH_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_SAP_MODE] = { + PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_24G_SBS_CH_MCC_CH, PM_24G, PM_24G_MCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH, PM_SBS_CH, PM_SBS_CH} }, + + [PM_STA_STA_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_STA_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = {PM_SCC_ON_5_SCC_ON_24, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NAN_DISC_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_SBS_CH_MCC_CH, PM_SBS_CH_MCC_CH, + PM_SBS_CH_MCC_CH} }, + + [PM_STA_STA_SBS_5_2x2] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH}, + [PM_P2P_GO_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH}, + [PM_NAN_DISC_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH_5G, PM_SBS_CH}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G_SCC_CH, PM_5G_SCC_CH, PM_5G_SCC_CH}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_SAP_MODE] = {PM_5G, PM_5G, PM_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_SAP_MODE] = {PM_SCC_ON_24_SCC_ON_5_5G, PM_SCC_ON_24_SCC_ON_5_5G, + PM_SCC_ON_24_SCC_ON_5_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_LL_LT_SAP_MCC_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G, + PM_SBS_CH_MCC_CH_SCC_ON_24_24G}, + [PM_P2P_GO_MODE] = {PM_MCC_CH_SCC_ON_24G, PM_MCC_CH_SCC_ON_24G, + PM_MCC_CH_SCC_ON_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH, + PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH, + PM_SCC_ON_5G_LOW_MCC_ON_5G_HIGH}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW, + PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW, + PM_SCC_ON_5G_HIGH_MCC_ON_5G_LOW}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_LL_LT_SAP_MCC_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_24_LL_LT_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_24G, PM_SCC_ON_24G, PM_SCC_ON_24G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_P2P_GO_MODE] = {PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_LL_LT_SAP_MCC_1x1] = { + [PM_STA_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_SAP_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_CLIENT_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_P2P_GO_MODE] = {PM_SBS_CH_2G, PM_SBS_CH_2G, PM_SBS_CH_2G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_LOW_LL_LT_SAP_5_HIGH_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW, PM_SCC_ON_5G_LOW}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_HIGH_LL_LT_SAP_5_LOW_SBS_1x1] = { + [PM_STA_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_SAP_MODE] = {PM_SCC_ON_5G_HIGH, PM_SCC_ON_5G_HIGH, + PM_SCC_ON_5G_HIGH}, + [PM_P2P_CLIENT_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_P2P_GO_MODE] = {PM_5G_24G, PM_5G_24G, PM_5G_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h new file mode 100644 index 0000000000..20c41c896a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_tables_no_dbs_i.h @@ -0,0 +1,3692 @@ +/* + * Copyright (c) 2012-2017, 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_POLICY_MGR_TABLES_NO_DBS_H +#define __WLAN_POLICY_MGR_TABLES_NO_DBS_H + +#include "wlan_policy_mgr_api.h" + +/* + * second_connection_pcl_nodbs_table - table which provides PCL + * for the 2nd connection, when we have a connection already in + * the system (with DBS not supported by HW) + */ +static const enum policy_mgr_pcl_type +second_connection_pcl_nodbs_table[PM_MAX_ONE_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = { + [PM_STA_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_STA_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_5G, PM_5G, PM_5G} }, + + [PM_P2P_CLI_24_1x1] = { + [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_24_2x2] = { + [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_P2P_GO_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_NAN_DISC_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_LL_LT_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, +}; + +/* + * third_connection_pcl_nodbs_table - table which provides PCL + * for the 3rd connection, when we have two connections already + * in the system (with DBS not supported by HW). For helium that is NON-DBS, + * DBS 1x1, three port concurrency would be disabled, so for every + * combination MAX_PCL_TYPE would be the return value, if in future + * the requirement for 3 port concurrency comes, refer to below table + * for details. + * static const enum policy_mgr_pcl_type + * third_connection_pcl_nodbs_table[PM_MAX_TWO_CONNECTION_MODE] + * [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = { + * [PM_STA_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_GO_SCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_GO_SCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_GO_SCC_5_1x1] = { + * [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_GO_SCC_5_2x2] = { + * [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_24_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_GO_MCC_24_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_GO_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_STA_P2P_CLI_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_CLI_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_CLI_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_CLI_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_CLI_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_CLI_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_STA_P2P_CLI_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_CLI_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_STA_P2P_CLI_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_5G, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_5G_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + * [PM_STA_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = { + * PM_5G_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + * [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + * [PM_STA_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + * [PM_P2P_GO_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + * [PM_STA_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_SAP_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_CLIENT_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH}, + * [PM_P2P_GO_MODE] = {PM_MCC_CH, PM_MCC_CH, PM_MCC_CH} }, + * + * [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_GO_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * + * [PM_P2P_CLI_SAP_SCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_SCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_5_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_MCC_24_5_2x2] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE} }, + * + * [PM_P2P_CLI_SAP_DBS_1x1] = { + * [PM_STA_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_SAP_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_CLIENT_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * [PM_P2P_GO_MODE] = { + * PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + * }; + */ +static const enum policy_mgr_pcl_type +third_connection_pcl_nodbs_table[PM_MAX_TWO_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = { + [PM_STA_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_NONE, PM_NONE, PM_NONE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, +}; + +#ifdef FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT + +/* + * second_connection_pcl_nodbs_no_interband_mcc_table - table + * which provides PCL for the 2nd connection, when we have a + * connection already in the system (when DBS and interband mcc + * are not supported by HW). + * This table consolidates selection for P2PCLI, P2PGO, STA, SAP + * into the single set of STA entries for 2.4G and 5G. + */ +static const enum policy_mgr_pcl_type +second_connection_pcl_nodbs_no_interband_mcc_table[PM_MAX_ONE_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = { + [PM_STA_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_CH, PM_SCC_CH, PM_SCC_CH}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_P2P_GO_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_NAN_DISC_MODE] = {PM_24G, PM_24G, PM_24G}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + [PM_LL_LT_SAP_5_2x2] = { + [PM_STA_MODE] = {PM_SBS_5G_MCC_24G, + PM_SBS_5G_MCC_24G, PM_SBS_5G_MCC_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + +}; + +/* + * third_connection_pcl_nodbs_no_interband_mcc_table - table which provides + * PCL for the 3rd connection, when we have two connections already in + * the system (when DBS and interband mcc are not supported by HW) + */ +static const enum policy_mgr_pcl_type +third_connection_pcl_nodbs_no_interband_mcc_table[PM_MAX_TWO_CONNECTION_MODE] + [PM_MAX_NUM_OF_MODE][PM_MAX_CONC_PRIORITY_MODE] = { + [PM_STA_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_SAP_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_GO_SBS_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_SAP_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_CLI_SAP_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_MCC_24_5_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_DBS_1x1] = { + [PM_STA_MODE] = { + PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24_5G, + PM_SCC_ON_5_SCC_ON_24_5G}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_DBS_2x2] = { + [PM_STA_MODE] = { PM_SCC_ON_5_SCC_ON_24_5G, PM_SCC_ON_5_SCC_ON_24, + PM_SCC_ON_5_SCC_ON_24}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_GO_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_SBS_CH_5G, PM_SBS_CH, PM_SBS_CH}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_P2P_GO_P2P_CLI_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_MCC_24_5_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_DBS_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_DBS_2x2] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_STA_SBS_5_1x1] = { + [PM_STA_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NAN_DISC_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_1x1] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_STA_NAN_DISC_DBS_2x2] = { + [PM_STA_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_NDI_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_SCC_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_MCC_24_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_MCC_24_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_24G, PM_SCC_CH_24G, PM_SCC_CH_24G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_DBS_1x1] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, + + [PM_NAN_DISC_NDI_DBS_2x2] = { + [PM_STA_MODE] = {PM_SCC_CH_5G, PM_SCC_CH_5G, PM_SCC_CH_5G}, + [PM_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_CLIENT_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_P2P_GO_MODE] = { + PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE}, + [PM_LL_LT_SAP_MODE] = {PM_MAX_PCL_TYPE, PM_MAX_PCL_TYPE, + PM_MAX_PCL_TYPE} }, +}; +#endif /* FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c new file mode 100644 index 0000000000..2045aefea3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_policy_mgr_i.h" +#include "cfg_ucfg_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_nan_api.h" + +#ifdef WLAN_FEATURE_SR +/** + * policy_mgr_init_same_mac_conc_sr_status() - Function initializes default + * value to sr_in_same_mac_conc based on INI g_enable_sr_in_same_mac_conc + * + * @psoc: Pointer to PSOC + * + * Return: void + */ +static void +policy_mgr_init_same_mac_conc_sr_status(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("Invalid Context"); + return; + } + + pm_ctx->cfg.sr_in_same_mac_conc = + cfg_get(psoc, CFG_ENABLE_SR_IN_SAME_MAC_CONC); +} +#else +static void +policy_mgr_init_same_mac_conc_sr_status(struct wlan_objmgr_psoc *psoc) +{} +#endif + +static QDF_STATUS policy_mgr_init_cfg(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + struct policy_mgr_cfg *cfg; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + cfg = &pm_ctx->cfg; + + cfg->mcc_to_scc_switch = cfg_get(psoc, CFG_MCC_TO_SCC_SWITCH); + if (cfg->mcc_to_scc_switch != QDF_MCC_TO_SCC_SWITCH_DISABLE && + cfg->mcc_to_scc_switch < + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION) { + policy_mgr_info("User configured mcc_to_scc_switch: %d, overwrite it to: %d", + cfg->mcc_to_scc_switch, + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION); + cfg->mcc_to_scc_switch = + QDF_MCC_TO_SCC_SWITCH_FORCE_WITHOUT_DISCONNECTION; + } + + cfg->sys_pref = cfg_get(psoc, CFG_CONC_SYS_PREF); + + if (wlan_is_mlo_sta_nan_ndi_allowed(psoc)) { + cfg->max_conc_cxns = cfg_get(psoc, CFG_MAX_CONC_CXNS) + 1; + policy_mgr_err("max_conc_cxns %d nan", cfg->max_conc_cxns); + } else { + cfg->max_conc_cxns = cfg_get(psoc, CFG_MAX_CONC_CXNS); + policy_mgr_err("max_conc_cxns %d non-nan", cfg->max_conc_cxns); + } + cfg->max_conc_cxns = QDF_MIN(cfg->max_conc_cxns, + MAX_NUMBER_OF_CONC_CONNECTIONS); + cfg->conc_rule1 = cfg_get(psoc, CFG_ENABLE_CONC_RULE1); + cfg->conc_rule2 = cfg_get(psoc, CFG_ENABLE_CONC_RULE2); + cfg->pcl_band_priority = cfg_get(psoc, CFG_PCL_BAND_PRIORITY); + cfg->dbs_selection_plcy = cfg_get(psoc, CFG_DBS_SELECTION_PLCY); + cfg->vdev_priority_list = cfg_get(psoc, CFG_VDEV_CUSTOM_PRIORITY_LIST); + cfg->chnl_select_plcy = cfg_get(psoc, CFG_CHNL_SELECT_LOGIC_CONC); + cfg->enable_mcc_adaptive_sch = + cfg_get(psoc, CFG_ENABLE_MCC_ADAPTIVE_SCH_ENABLED_NAME); + cfg->enable_sta_cxn_5g_band = + cfg_get(psoc, CFG_ENABLE_STA_CONNECTION_IN_5GHZ); + cfg->allow_mcc_go_diff_bi = + cfg_get(psoc, CFG_ALLOW_MCC_GO_DIFF_BI); + cfg->dual_mac_feature = + cfg_get(psoc, CFG_DUAL_MAC_FEATURE_DISABLE); + cfg->sbs_enable = + cfg_get(psoc, CFG_ENABLE_SBS); + cfg->is_force_1x1_enable = + cfg_get(psoc, CFG_FORCE_1X1_FEATURE); + cfg->sta_sap_scc_on_dfs_chnl = + cfg_get(psoc, CFG_STA_SAP_SCC_ON_DFS_CHAN); + + /* + * Override concurrency sta+sap indoor flag to true if global indoor + * flag is true + */ + cfg->sta_sap_scc_on_indoor_channel = + cfg_get(psoc, CFG_STA_SAP_SCC_ON_INDOOR_CHAN); + if (cfg_get(psoc, CFG_INDOOR_CHANNEL_SUPPORT)) + cfg->sta_sap_scc_on_indoor_channel = true; + + /* + * Force set sta_sap_scc_on_dfs_chnl on Non-DBS HW so that standalone + * SAP is not allowed on DFS channel on non-DBS HW, Also, force SCC in + * case of STA+SAP + */ + if (cfg->sta_sap_scc_on_dfs_chnl == 2 && + !cfg_get(psoc, CFG_ENABLE_DFS_MASTER_CAPABILITY)) + cfg->sta_sap_scc_on_dfs_chnl = 0; + cfg->nan_sap_scc_on_lte_coex_chnl = + cfg_get(psoc, CFG_NAN_SAP_SCC_ON_LTE_COEX_CHAN); + cfg->sta_sap_scc_on_lte_coex_chnl = + cfg_get(psoc, CFG_STA_SAP_SCC_ON_LTE_COEX_CHAN); + cfg->sap_mandatory_chnl_enable = + cfg_get(psoc, CFG_ENABLE_SAP_MANDATORY_CHAN_LIST); + cfg->mark_indoor_chnl_disable = + cfg_get(psoc, CFG_MARK_INDOOR_AS_DISABLE_FEATURE); + cfg->go_force_scc = cfg_get(psoc, CFG_P2P_GO_ENABLE_FORCE_SCC); + cfg->multi_sap_allowed_on_same_band = + cfg_get(psoc, CFG_MULTI_SAP_ALLOWED_ON_SAME_BAND); + policy_mgr_init_same_mac_conc_sr_status(psoc); + cfg->use_sap_original_bw = + cfg_get(psoc, CFG_SAP_DEFAULT_BW_FOR_RESTART); + cfg->move_sap_go_1st_on_dfs_sta_csa = + cfg_get(psoc, CFG_MOVE_SAP_GO_1ST_ON_DFS_STA_CSA); + + return QDF_STATUS_SUCCESS; +} + +static void policy_mgr_deinit_cfg(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_psoc_priv_obj *pm_ctx; + + pm_ctx = policy_mgr_get_context(psoc); + if (!pm_ctx) { + policy_mgr_err("pm_ctx is NULL"); + return; + } + + qdf_mem_zero(&pm_ctx->cfg, sizeof(pm_ctx->cfg)); +} + +QDF_STATUS ucfg_policy_mgr_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = policy_mgr_init_cfg(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("pm_ctx is NULL"); + return status; + } + + status = policy_mgr_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_err("psoc open fail"); + policy_mgr_psoc_close(psoc); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +void ucfg_policy_mgr_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + policy_mgr_psoc_close(psoc); + policy_mgr_deinit_cfg(psoc); +} + +QDF_STATUS ucfg_policy_mgr_get_mcc_scc_switch(struct wlan_objmgr_psoc *psoc, + uint8_t *mcc_scc_switch) +{ + return policy_mgr_get_mcc_scc_switch(psoc, mcc_scc_switch); +} + +QDF_STATUS ucfg_policy_mgr_get_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t *sys_pref) +{ + return policy_mgr_get_sys_pref(psoc, sys_pref); +} + +QDF_STATUS ucfg_policy_mgr_set_sys_pref(struct wlan_objmgr_psoc *psoc, + uint8_t sys_pref) +{ + return policy_mgr_set_sys_pref(psoc, sys_pref); +} + +QDF_STATUS ucfg_policy_mgr_get_conc_rule1(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule1) +{ + return policy_mgr_get_conc_rule1(psoc, conc_rule1); +} + +QDF_STATUS ucfg_policy_mgr_get_conc_rule2(struct wlan_objmgr_psoc *psoc, + uint8_t *conc_rule2) +{ + return policy_mgr_get_conc_rule2(psoc, conc_rule2); +} + +QDF_STATUS ucfg_policy_mgr_get_chnl_select_plcy(struct wlan_objmgr_psoc *psoc, + uint32_t *chnl_select_plcy) +{ + return policy_mgr_get_chnl_select_plcy(psoc, chnl_select_plcy); +} + + +QDF_STATUS ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch( + struct wlan_objmgr_psoc *psoc, + bool dynamic_mcc_adaptive_sch) +{ + return policy_mgr_set_dynamic_mcc_adaptive_sch( + psoc, dynamic_mcc_adaptive_sch); +} + +QDF_STATUS ucfg_policy_mgr_get_dynamic_mcc_adaptive_sch( + struct wlan_objmgr_psoc *psoc, + bool *dynamic_mcc_adaptive_sch) +{ + return policy_mgr_get_dynamic_mcc_adaptive_sch( + psoc, dynamic_mcc_adaptive_sch); +} + +QDF_STATUS ucfg_policy_mgr_get_mcc_adaptive_sch(struct wlan_objmgr_psoc *psoc, + bool *mcc_adaptive_sch) +{ + return policy_mgr_get_mcc_adaptive_sch(psoc, mcc_adaptive_sch); +} + +QDF_STATUS ucfg_policy_mgr_get_sta_cxn_5g_band(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_sta_cxn_5g_band) +{ + return policy_mgr_get_sta_cxn_5g_band(psoc, enable_sta_cxn_5g_band); +} + +QDF_STATUS +ucfg_policy_mgr_get_allow_mcc_go_diff_bi(struct wlan_objmgr_psoc *psoc, + uint8_t *allow_mcc_go_diff_bi) +{ + return policy_mgr_get_allow_mcc_go_diff_bi(psoc, allow_mcc_go_diff_bi); +} + +QDF_STATUS ucfg_policy_mgr_get_dual_mac_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_mac_feature) +{ + return policy_mgr_get_dual_mac_feature(psoc, dual_mac_feature); +} + +bool ucfg_policy_mgr_get_dual_sta_feature(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_allow_multiple_sta_connections(psoc); +} + +QDF_STATUS ucfg_policy_mgr_get_force_1x1(struct wlan_objmgr_psoc *psoc, + uint8_t *force_1x1) +{ + return policy_mgr_get_force_1x1(psoc, force_1x1); +} + +uint32_t ucfg_policy_mgr_get_max_conc_cxns(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_get_max_conc_cxns(psoc); +} + +QDF_STATUS ucfg_policy_mgr_set_max_conc_cxns(struct wlan_objmgr_psoc *psoc, + uint32_t max_conc_cxns) +{ + return policy_mgr_set_max_conc_cxns(psoc, max_conc_cxns); +} + +QDF_STATUS +ucfg_policy_mgr_get_radio_combinations(struct wlan_objmgr_psoc *psoc, + struct radio_combination *comb, + uint32_t comb_max, + uint32_t *comb_num) +{ + return policy_mgr_get_radio_combinations(psoc, comb, + comb_max, comb_num); +} + +QDF_STATUS +ucfg_policy_mgr_get_sta_sap_scc_on_dfs_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_on_dfs_chnl) +{ + return policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, + sta_sap_scc_on_dfs_chnl); +} + +bool +ucfg_policy_mgr_get_dfs_master_dynamic_enabled(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return policy_mgr_get_dfs_master_dynamic_enabled(psoc, vdev_id); +} + +QDF_STATUS +ucfg_policy_mgr_get_sta_sap_scc_lte_coex_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sta_sap_scc_lte_coex) +{ + return policy_mgr_get_sta_sap_scc_lte_coex_chnl(psoc, + sta_sap_scc_lte_coex); +} + +QDF_STATUS +ucfg_policy_mgr_init_chan_avoidance(struct wlan_objmgr_psoc *psoc, + qdf_freq_t *chan_freq_list, + uint16_t chan_cnt) +{ + return policy_mgr_init_chan_avoidance(psoc, chan_freq_list, chan_cnt); +} + +QDF_STATUS ucfg_policy_mgr_get_sap_mandt_chnl(struct wlan_objmgr_psoc *psoc, + uint8_t *sap_mandt_chnl) +{ + return policy_mgr_get_sap_mandt_chnl(psoc, sap_mandt_chnl); +} + +QDF_STATUS +ucfg_policy_mgr_get_indoor_chnl_marking(struct wlan_objmgr_psoc *psoc, + uint8_t *indoor_chnl_marking) +{ + return policy_mgr_get_indoor_chnl_marking(psoc, indoor_chnl_marking); +} + +bool +ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(psoc) ? + true : false; +} + +bool ucfg_policy_mgr_is_fw_supports_dbs(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_find_if_fw_supports_dbs(psoc); +} + +uint32_t ucfg_policy_mgr_get_connection_count(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_get_connection_count(psoc); +} + +bool ucfg_policy_mgr_is_hw_sbs_capable(struct wlan_objmgr_psoc *psoc) +{ + return policy_mgr_is_hw_dbs_capable(psoc); +} + +bool ucfg_policy_mgr_get_vdev_same_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id) +{ + return policy_mgr_get_vdev_same_freq_new_conn(psoc, new_freq, vdev_id); +} + +bool ucfg_policy_mgr_get_vdev_diff_freq_new_conn(struct wlan_objmgr_psoc *psoc, + uint32_t new_freq, + uint8_t *vdev_id) +{ + return policy_mgr_get_vdev_diff_freq_new_conn(psoc, new_freq, vdev_id); +} + +QDF_STATUS ucfg_policy_mgr_get_dbs_hw_modes(struct wlan_objmgr_psoc *psoc, + bool *one_by_one_dbs, + bool *two_by_two_dbs) +{ + return policy_mgr_get_dbs_hw_modes(psoc, one_by_one_dbs, + two_by_two_dbs); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/core/inc/wlan_coap_main.h b/qcom/opensource/wlan/qcacld-3.0/components/coap/core/inc/wlan_coap_main.h new file mode 100644 index 0000000000..cc0a27c87c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/core/inc/wlan_coap_main.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains declarations for CoAP core functions + */ + +#ifndef _WLAN_COAP_MAIN_H_ +#define _WLAN_COAP_MAIN_H_ + +#ifdef WLAN_FEATURE_COAP +#include "wlan_objmgr_vdev_obj.h" + +#define coap_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_COAP, params) +#define coap_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_COAP, params) +#define coap_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_COAP, params) + +/** + * struct wlan_coap_comp_priv - CoAP component private structure + * @req_id: cache get request id + * @cache_get_cbk: Callback function to be called with the cache get result + * @cache_get_context: context to be used by the caller to associate the get + * cache request with the response + */ +struct wlan_coap_comp_priv { + uint32_t req_id; + coap_cache_get_callback cache_get_cbk; + void *cache_get_context; +}; + +static inline struct wlan_coap_comp_priv * +wlan_get_vdev_coap_obj(struct wlan_objmgr_vdev *vdev) +{ + return wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_COAP); +} + +/* + * wlan_coap_init() - CoAP module initialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_coap_init(void); + +/* + * wlan_coap_init() - CoAP module deinitialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_coap_deinit(void); + +/** + * wlan_coap_enable(): API to enable CoAP component + * @psoc: pointer to psoc + * + * This API is invoked from dispatcher psoc enable. + * This API will register CoAP related WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_coap_enable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_coap_disable(): API to disable CoAP component + * @psoc: pointer to psoc + * + * This API is invoked from dispatcher psoc disable. + * This API will unregister CoAP related WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_coap_disable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_coap_offload_reply_enable() - private API to enable CoAP offload reply + * @vdev: pointer to vdev object + * @param: parameters of CoAP offload reply + * + * Return: status of operation + */ +QDF_STATUS +wlan_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *param); + +/** + * wlan_coap_offload_reply_disable() - private API to disable CoAP offload reply + * @vdev: pointer to vdev object + * @req_id: request id + * @cbk: callback function to be called with the cache info + * @context: context to be used by the caller to associate the disable request + * + * Return: status of operation + */ +QDF_STATUS +wlan_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context); + +/** + * wlan_coap_offload_periodic_tx_enable() - private API to enable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @param: parameters of CoAP periodic transmit + * + * Return: status of operation + */ +QDF_STATUS +wlan_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *param); + +/** + * wlan_coap_offload_periodic_tx_disable() - private API to disable CoAP + * offload periodic transmitting + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +QDF_STATUS +wlan_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id); + +/** + * wlan_coap_offload_cache_get() - private API to get CoAP offload cache + * @vdev: pointer to vdev object + * @req_id: request id + * @cbk: callback function to be called with the cache get result + * @context: context to be used by the caller to associate the get + * cache request with the response + * + * Return: status of operation + */ +QDF_STATUS +wlan_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/core/src/wlan_coap_main.c b/qcom/opensource/wlan/qcacld-3.0/components/coap/core/src/wlan_coap_main.c new file mode 100644 index 0000000000..23ebbc331d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/core/src/wlan_coap_main.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains definitions for CoAP core functions + */ + +#include +#include +#include + +QDF_STATUS wlan_coap_enable(struct wlan_objmgr_psoc *psoc) +{ + return tgt_coap_attach(psoc); +} + +QDF_STATUS wlan_coap_disable(struct wlan_objmgr_psoc *psoc) +{ + return tgt_coap_detach(psoc); +} + +static QDF_STATUS +wlan_coap_vdev_obj_create_handler(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct wlan_coap_comp_priv *coap_priv; + QDF_STATUS status; + + if (!vdev) + return QDF_STATUS_E_INVAL; + + coap_priv = qdf_mem_malloc(sizeof(struct wlan_coap_comp_priv)); + if (!coap_priv) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_UMAC_COMP_COAP, + (void *)coap_priv, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(coap_priv); + + return status; +} + +static QDF_STATUS +wlan_coap_vdev_obj_destroy_handler(struct wlan_objmgr_vdev *vdev, void *arg) +{ + void *coap_priv; + + if (!vdev) { + coap_err("Vdev NULL"); + return QDF_STATUS_E_INVAL; + } + + coap_priv = wlan_get_vdev_coap_obj(vdev); + if (!coap_priv) { + coap_err("coap_priv NULL"); + return QDF_STATUS_E_INVAL; + } + + wlan_objmgr_vdev_component_obj_detach(vdev, WLAN_UMAC_COMP_COAP, + coap_priv); + qdf_mem_free(coap_priv); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_coap_init(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = wlan_objmgr_register_vdev_create_handler(WLAN_UMAC_COMP_COAP, + wlan_coap_vdev_obj_create_handler, NULL); + if (status != QDF_STATUS_SUCCESS) + return status; + + status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_COAP, + wlan_coap_vdev_obj_destroy_handler, NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_COAP, + wlan_coap_vdev_obj_create_handler, NULL); + return status; +} + +QDF_STATUS wlan_coap_deinit(void) +{ + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_COAP, + wlan_coap_vdev_obj_create_handler, NULL); + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_COAP, + wlan_coap_vdev_obj_destroy_handler, NULL); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *params) +{ + return tgt_send_coap_offload_reply_enable(vdev, params); +} + +QDF_STATUS +wlan_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context) +{ + struct wlan_coap_comp_priv *coap_priv; + + if (!vdev) { + coap_err("Vdev NULL"); + return QDF_STATUS_E_INVAL; + } + + coap_priv = wlan_get_vdev_coap_obj(vdev); + coap_priv->req_id = req_id; + coap_priv->cache_get_context = context; + coap_priv->cache_get_cbk = cbk; + return tgt_send_coap_offload_reply_disable(vdev, req_id); +} + +QDF_STATUS +wlan_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *params) +{ + return tgt_send_coap_offload_periodic_tx_enable(vdev, params); +} + +QDF_STATUS +wlan_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + return tgt_send_coap_offload_periodic_tx_disable(vdev, req_id); +} + +QDF_STATUS +wlan_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context) +{ + struct wlan_coap_comp_priv *coap_priv; + + if (!vdev) { + coap_err("Vdev NULL"); + return QDF_STATUS_E_INVAL; + } + + coap_priv = wlan_get_vdev_coap_obj(vdev); + coap_priv->req_id = req_id; + coap_priv->cache_get_context = context; + coap_priv->cache_get_cbk = cbk; + return tgt_send_coap_offload_cache_get(vdev, req_id); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_public_structs.h new file mode 100644 index 0000000000..deaefaa711 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_public_structs.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains CoAP structure definitions + */ + +#ifndef _WLAN_COAP_PUBLIC_STRUCTS_H_ +#define _WLAN_COAP_PUBLIC_STRUCTS_H_ +#include + +/** + * struct coap_offload_reply_param - parameters to enable CoAP offload reply + * @vdev_id: vdev id + * @pattern_id: pattern id + * @cache_timeout: the cached packet expire timeout in ms + * @src_ip_v4: source IPv4 address for sending reply message + * @src_udp_port: source udp port for sending reply message + * @dest_ip_v4: destination IPv4 address to match received CoAP message + * @dest_ip_v4_is_bc: indicate whether the destination address is broadcast + * address or not + * @dest_udp_port: destination UDP port to match received CoAP message + * @verify_offset: UDP payload offset to match received CoAP message + * @verify_len: UDP payload length to match received CoAP message + * @verify: pointer to binary data to match received CoAP message + * @coapmsg_len: CoAP reply message length + * @coapmsg: pointer to CoAP reply message + */ +struct coap_offload_reply_param { + uint32_t vdev_id; + uint32_t pattern_id; + uint32_t cache_timeout; + uint32_t src_ip_v4; + uint16_t src_udp_port; + uint32_t dest_ip_v4; + bool dest_ip_v4_is_bc; + uint16_t dest_udp_port; + uint32_t verify_offset; + uint32_t verify_len; + uint8_t *verify; + uint32_t coapmsg_len; + uint8_t *coapmsg; +}; + +/** + * struct coap_offload_periodic_tx_param - parameters to enable CoAP offload + * periodic transmitting + * @vdev_id: vdev id + * @pattern_id: pattern id + * @src_ip_v4: IPv4 address for sending CoAP message + * @src_udp_port: source udp port for sending CoAP message + * @dest_ip_v4: destination IPv4 address for sending CoAP message + * @dest_ip_v4_is_bc: indicate whether the destination address is broadcast + * address or not + * @dest_udp_port: destination UDP port for sending CoAP message + * @timeout: the periorid to send keepalive message in ms + * @coapmsg_len: keeplive CoAP message length + * @coapmsg: pointer to keeplive CoAP message + */ +struct coap_offload_periodic_tx_param { + uint32_t vdev_id; + uint32_t pattern_id; + uint32_t src_ip_v4; + uint16_t src_udp_port; + uint32_t dest_ip_v4; + bool dest_ip_v4_is_bc; + uint16_t dest_udp_port; + uint32_t timeout; + uint32_t coapmsg_len; + uint8_t *coapmsg; +}; + +/** + * struct coap_buf_node - CoAP message info entry + * @node: List entry element + * @tsf: TSF of the CoAP meesage + * @src_ip: source IPv4 address of the CoAP message + * @len: length of the payload + * @payload: pointer to buffer holding UDP payload of the CoAP message + */ +struct coap_buf_node { + qdf_list_node_t node; + uint64_t tsf; + uint32_t src_ip; + uint32_t len; + uint8_t *payload; +}; + +/** + * struct coap_buf_info - info of the cached CoAP messages + * @vdev_id: vdev id + * @req_id: request id + * @more_info: flag to indicate whether there are more cached messages + * @info_list: list to hold cached CoAP messages + */ +struct coap_buf_info { + uint8_t vdev_id; + uint32_t req_id; + bool more_info; + qdf_list_t info_list; +}; + +/** + * typedef coap_cache_get_callback() - callback for getting cached CoAP messages + * @context: context for getting cached CoAP messages + * @info: pointer to info of the cached CoAP messages + */ +typedef void (*coap_cache_get_callback)(void *context, + struct coap_buf_info *info); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_tgt_api.h new file mode 100644 index 0000000000..db9098ae19 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_tgt_api.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains CoAP south bound interface definitions + */ + +#ifndef _WLAN_COAP_TGT_API_H_ +#define _WLAN_COAP_TGT_API_H_ + +#ifdef WLAN_FEATURE_COAP +#include +#include +#include + +/** + * tgt_coap_attach(): attach CoAP component + * @psoc: pointer to psoc + * + * This API will register CoAP related WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS tgt_coap_attach(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_coap_detach(): detach CoAP component + * @psoc: pointer to psoc + * + * This API will unregister CoAP related WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS tgt_coap_detach(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_send_coap_offload_reply_enable() - enable CoAP offload reply + * @vdev: pointer to vdev object + * @param: parameters for CoAP offload reply + * + * Return: status of operation + */ +QDF_STATUS +tgt_send_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *param); + +/** + * tgt_send_coap_offload_reply_disable() - disable CoAP offload reply + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +QDF_STATUS +tgt_send_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id); + +/** + * tgt_send_coap_offload_periodic_tx_enable() - enable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @param: parameters for CoAP periodic transmitting + * + * Return: status of operation + */ +QDF_STATUS +tgt_send_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *param); + +/** + * tgt_send_coap_offload_periodic_tx_disable() - disable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +QDF_STATUS +tgt_send_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id); + +/** + * tgt_send_coap_offload_cache_get() - get cached CoAP messages + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +QDF_STATUS +tgt_send_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, + uint32_t req_id); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_ucfg_api.h new file mode 100644 index 0000000000..e6a07242f2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/inc/wlan_coap_ucfg_api.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains CoAP north bound interface declarations + */ + +#ifndef _WLAN_COAP_UCFG_API_H_ +#define _WLAN_COAP_UCFG_API_H_ + +#include "qdf_status.h" +#include +#include "wlan_coap_public_structs.h" + +#ifdef WLAN_FEATURE_COAP +/** + * ucfg_coap_offload_reply_enable() - API to enable CoAP offload reply + * @vdev: pointer to vdev object + * @param: parameters of CoAP offload reply + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *param); + +/** + * ucfg_coap_offload_reply_disable() - API to disable CoAP offload reply + * @vdev: pointer to vdev object + * @req_id: request id + * @cbk: callback function to invoke with cached data + * @context: caller-supplied context + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context); + +/** + * ucfg_coap_offload_periodic_tx_enable() - API to enable CoAP offload + * periodic transmit + * @vdev: pointer to vdev object + * @param: parameters of CoAP periodic transmit + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *param); + +/** + * ucfg_coap_offload_periodic_tx_disable() - API to disable CoAP offload + * periodic transmit + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id); + +/** + * ucfg_coap_offload_cache_get() - API to get CoAP offload cache + * @vdev: pointer to vdev object + * @req_id: request id + * @cbk: callback function to be called with the cache get result + * @context: context to be used by the caller to associate the get + * cache request with the response + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/src/wlan_coap_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/src/wlan_coap_tgt_api.c new file mode 100644 index 0000000000..3a415feacc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/src/wlan_coap_tgt_api.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains CoAP south bound interface definitions + */ + +#include +#include +#include +#include "wlan_objmgr_pdev_obj.h" + +static inline struct wlan_lmac_if_coap_tx_ops * +wlan_psoc_get_coap_txops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + coap_err("tx_ops is NULL"); + return NULL; + } + + return &tx_ops->coap_ops; +} + +static inline struct wlan_lmac_if_coap_tx_ops * +wlan_vdev_get_coap_txops(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coap_err("NULL psoc"); + return NULL; + } + + return wlan_psoc_get_coap_txops(psoc); +} + +QDF_STATUS tgt_coap_attach(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_coap_tx_ops *coap_tx_ops; + + if (!psoc) { + coap_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_tx_ops = wlan_psoc_get_coap_txops(psoc); + if (!coap_tx_ops) { + coap_err("tx_ops is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!coap_tx_ops->attach) { + coap_err("attach function is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + return coap_tx_ops->attach(psoc); +} + +QDF_STATUS tgt_coap_detach(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_coap_tx_ops *coap_tx_ops; + + if (!psoc) { + coap_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_tx_ops = wlan_psoc_get_coap_txops(psoc); + if (!coap_tx_ops) { + coap_err("tx_ops is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!coap_tx_ops->detach) { + coap_err("coap_detach function is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + return coap_tx_ops->detach(psoc); +} + +QDF_STATUS +tgt_send_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *param) +{ + struct wlan_lmac_if_coap_tx_ops *coap_ops; + + if (!vdev) { + coap_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_ops = wlan_vdev_get_coap_txops(vdev); + if (coap_ops && coap_ops->offload_reply_enable) + return coap_ops->offload_reply_enable(vdev, param); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_send_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + struct wlan_lmac_if_coap_tx_ops *coap_ops; + + if (!vdev) { + coap_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_ops = wlan_vdev_get_coap_txops(vdev); + if (coap_ops && coap_ops->offload_reply_disable) + return coap_ops->offload_reply_disable(vdev, req_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_send_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *param) +{ + struct wlan_lmac_if_coap_tx_ops *coap_ops; + + if (!vdev) { + coap_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_ops = wlan_vdev_get_coap_txops(vdev); + if (coap_ops && coap_ops->offload_periodic_tx_enable) + return coap_ops->offload_periodic_tx_enable(vdev, param); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_send_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + struct wlan_lmac_if_coap_tx_ops *coap_ops; + + if (!vdev) { + coap_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_ops = wlan_vdev_get_coap_txops(vdev); + if (coap_ops && coap_ops->offload_periodic_tx_disable) + return coap_ops->offload_periodic_tx_disable(vdev, req_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_send_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, uint32_t req_id) +{ + struct wlan_lmac_if_coap_tx_ops *coap_ops; + + if (!vdev) { + coap_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coap_ops = wlan_vdev_get_coap_txops(vdev); + if (coap_ops && coap_ops->offload_cache_get) + return coap_ops->offload_cache_get(vdev, req_id); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/src/wlan_coap_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/src/wlan_coap_ucfg_api.c new file mode 100644 index 0000000000..4d012adad0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coap/dispatcher/src/wlan_coap_ucfg_api.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains CoAP north bound interface definitions + */ + +#include +#include + +/** + * ucfg_coap_offload_reply_enable() - API to enable CoAP offload reply + * @vdev: pointer to vdev object + * @param: parameters of CoAP offload reply + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *param) +{ + return wlan_coap_offload_reply_enable(vdev, param); +} + +/** + * ucfg_coap_offload_reply_disable() - API to disable CoAP offload reply + * @vdev: pointer to vdev object + * @req_id: request id + * @cbk: callback function to be called with the cache info + * @context: context to be used by the caller to associate the disable request + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context) +{ + return wlan_coap_offload_reply_disable(vdev, req_id, cbk, context); +} + +/** + * ucfg_coap_offload_periodic_tx_enable() - API to enable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @param: parameters for CoAP periodic transmit + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *param) +{ + return wlan_coap_offload_periodic_tx_enable(vdev, param); +} + +/** + * ucfg_coap_offload_periodic_tx_disable() - private API to disable CoAP + * offload periodic transmitting + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + return wlan_coap_offload_periodic_tx_disable(vdev, req_id); +} + +/** + * ucfg_coap_offload_cache_get() - API to get CoAP offload cache + * @vdev: pointer to vdev object + * @req_id: request id + * @cbk: callback function to be called with the cache get result + * @context: context to be used by the caller to associate the get + * cache request with the response + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, uint32_t req_id, + coap_cache_get_callback cbk, void *context) +{ + return wlan_coap_offload_cache_get(vdev, req_id, cbk, context); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/core/inc/wlan_coex_main.h b/qcom/opensource/wlan/qcacld-3.0/components/coex/core/inc/wlan_coex_main.h new file mode 100644 index 0000000000..d6947cda09 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/core/inc/wlan_coex_main.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains declarations for coex core functions + */ + +#ifndef _WLAN_COEX_MAIN_API_H_ +#define _WLAN_COEX_MAIN_API_H_ + +#ifdef FEATURE_COEX +#include "wlan_coex_ucfg_api.h" +#include "wmi_unified_param.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_vdev_obj.h" + +#define coex_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_COEX, params) +#define coex_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_COEX, params) +#define coex_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_COEX, params) + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * struct wlan_coex_callback - coex dbam callback structure + * @set_dbam_config_cb: callback for set_dbam_config + * @set_dbam_config_ctx: context for set_dbam_config callback + */ +struct wlan_coex_callback { + void (*set_dbam_config_cb)(void *ctx, enum coex_dbam_comp_status *rsp); + void *set_dbam_config_ctx; +}; +#endif + +/** + * struct coex_psoc_obj - coex object definition + * @btc_chain_mode: BT Coex chain mode. + * @coex_config_updated: callback functions for each config type, which will + * be called when config is updated. + * @cb: structure to dbam callback + */ +struct coex_psoc_obj { + enum coex_btc_chain_mode btc_chain_mode; + update_coex_cb coex_config_updated[COEX_CONFIG_TYPE_MAX]; +#ifdef WLAN_FEATURE_DBAM_CONFIG + struct wlan_coex_callback cb; +#endif +}; + +/** + * wlan_psoc_get_coex_obj() - private API to get coex object from psoc + * @psoc: psoc object + * + * Return: coex object + */ +#define wlan_psoc_get_coex_obj(psoc) \ + wlan_psoc_get_coex_obj_fl(psoc, __func__, __LINE__) + +static inline struct coex_psoc_obj * +wlan_psoc_get_coex_obj_fl(struct wlan_objmgr_psoc *psoc, + const char *func, uint32_t line) +{ + struct coex_psoc_obj *psoc_obj; + + psoc_obj = (struct coex_psoc_obj *) + wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_COEX); + if (!psoc_obj) { + coex_err("%s:%u, Failed to get coex psoc object", func, line); + return NULL; + } + return psoc_obj; +} + +/** + * wlan_coex_psoc_init() - API to initialize coex component + * @psoc: soc context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_coex_psoc_init(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_coex_psoc_deinit() - API to deinitialize coex component + * @psoc: soc context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_coex_psoc_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_coex_config_send() - private API to send coex config + * @vdev: pointer to vdev object + * @param: parameters of coex config + * + * Return: status of operation + */ +QDF_STATUS wlan_coex_config_send(struct wlan_objmgr_vdev *vdev, + struct coex_config_params *param); + +/** + * wlan_coex_multi_config_send() - API to send coex multiple configure + * @vdev: pointer to vdev object + * @param: parameters of coex multiple config + * + * QDF_STATUS + */ +QDF_STATUS wlan_coex_multi_config_send(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param); + +/** + * wlan_coex_config_updated() - private API to notify that coex config + * is updated. + * @vdev: pointer to vdev object + * @type: type of coex config + * + * Return: status of operation + */ +QDF_STATUS +wlan_coex_config_updated(struct wlan_objmgr_vdev *vdev, uint8_t type); + +/** + * wlan_coex_psoc_created_notification() - PSOC obj create callback + * @psoc: PSOC object + * @arg_list: Variable argument list + * + * This callback is registered with object manager during initialization to + * get notified when the object is created. + * + * Return: Success or Failure + */ +QDF_STATUS wlan_coex_psoc_created_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list); + +/** + * wlan_coex_psoc_destroyed_notification() - PSOC obj delete callback + * @psoc: PSOC object + * @arg_list: Variable argument list + * + * This callback is registered with object manager during initialization to + * get notified when the object is deleted. + * + * Return: Success or Failure + */ +QDF_STATUS wlan_coex_psoc_destroyed_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list); + +/** + * wlan_coex_psoc_set_btc_chain_mode() - private API to set BT coex chain mode + * for psoc + * @psoc: pointer to psoc object + * @val: BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +wlan_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode val); + +/** + * wlan_coex_psoc_get_btc_chain_mode() - private API to get BT coex chain mode + * from psoc + * @psoc: pointer to psoc object + * @val: pointer to BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +wlan_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode *val); +#endif + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * wlan_dbam_config_send() - private API to send dbam config + * @vdev: pointer to vdev object + * @param: parameters of dbam config + * + * Return: QDF_STATUS of operation + */ +QDF_STATUS wlan_dbam_config_send(struct wlan_objmgr_vdev *vdev, + struct coex_dbam_config_params *param); + +static inline struct wlan_lmac_if_dbam_rx_ops * +wlan_psoc_get_dbam_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_rx_ops *rx_ops; + + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (!rx_ops) { + coex_err("rx_ops is NULL"); + return NULL; + } + + return &rx_ops->dbam_rx_ops; +} + +static inline struct wlan_lmac_if_dbam_tx_ops * +wlan_psoc_get_dbam_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + coex_err("tx_ops is NULL"); + return NULL; + } + + return &tx_ops->dbam_tx_ops; +} + +/** + * wlan_dbam_attach() - Attach dbam handler + * @psoc: psoc pointer + * + * This function gets called to register dbam FW events handler + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dbam_attach(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dbam_detach() - Detach dbam handler + * @psoc: psoc pointer + * + * This function gets called to unregister dbam FW events handler + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dbam_detach(struct wlan_objmgr_psoc *psoc); +#endif /* WLAN_FEATURE_DBAM_CONFIG */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/core/src/wlan_coex_main.c b/qcom/opensource/wlan/qcacld-3.0/components/coex/core/src/wlan_coex_main.c new file mode 100644 index 0000000000..ccb6e3cce5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/core/src/wlan_coex_main.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains definitions for coex core functions + */ + +#include +#include +#include + +QDF_STATUS wlan_coex_psoc_created_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + struct coex_psoc_obj *psoc_obj; + QDF_STATUS status; + + psoc_obj = qdf_mem_malloc(sizeof(*psoc_obj)); + if (!psoc_obj) + return QDF_STATUS_E_NOMEM; + + psoc_obj->btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + + /* Attach scan private date to psoc */ + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_COEX, + psoc_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("Failed to attach psoc coex component"); + qdf_mem_free(psoc_obj); + } else { + coex_debug("Coex object attach to psoc successful"); + } + + return status; +} + +QDF_STATUS wlan_coex_psoc_destroyed_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + void *psoc_obj; + QDF_STATUS status; + + psoc_obj = wlan_psoc_get_coex_obj(psoc); + if (!psoc_obj) + return QDF_STATUS_E_FAILURE; + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_COEX, + psoc_obj); + if (QDF_IS_STATUS_ERROR(status)) + coex_err("Failed to detach psoc coex component"); + + qdf_mem_free(psoc_obj); + + return status; +} + +QDF_STATUS +wlan_coex_psoc_init(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_coex_psoc_deinit(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_coex_config_send(struct wlan_objmgr_vdev *vdev, + struct coex_config_params *param) +{ + QDF_STATUS status; + + status = tgt_send_coex_config(vdev, param); + if (QDF_IS_STATUS_ERROR(status)) + coex_err("failed to send coex config"); + + return status; +} + +QDF_STATUS wlan_coex_multi_config_send(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param) +{ + struct wlan_objmgr_psoc *psoc; + struct coex_config_params one_param; + QDF_STATUS status, ret = QDF_STATUS_SUCCESS; + uint32_t i; + + if (!vdev) { + coex_err("Null vdev"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("failed to get coex_obj"); + return QDF_STATUS_E_INVAL; + } + + if (tgt_get_coex_multi_config_support(psoc)) + return tgt_send_coex_multi_config(vdev, param); + + for (i = 0; i < param->num_configs; i++) { + one_param.vdev_id = param->vdev_id; + one_param.config_type = param->cfg_items[i].config_type; + one_param.config_arg1 = param->cfg_items[i].config_arg1; + one_param.config_arg2 = param->cfg_items[i].config_arg2; + one_param.config_arg3 = param->cfg_items[i].config_arg3; + one_param.config_arg4 = param->cfg_items[i].config_arg4; + one_param.config_arg5 = param->cfg_items[i].config_arg5; + one_param.config_arg6 = param->cfg_items[i].config_arg6; + status = tgt_send_coex_config(vdev, &one_param); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("fail to send one coex config"); + ret = status; + } + } + + return ret; +} + +QDF_STATUS +wlan_coex_config_updated(struct wlan_objmgr_vdev *vdev, uint8_t type) +{ + struct wlan_objmgr_psoc *psoc; + struct coex_psoc_obj *coex_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!vdev) { + coex_err("NULL vdev"); + return QDF_STATUS_E_INVAL; + } + + if (type >= COEX_CONFIG_TYPE_MAX) { + coex_err("config type out of range: %d", type); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return QDF_STATUS_E_INVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + if (coex_obj->coex_config_updated[type]) + status = coex_obj->coex_config_updated[type](vdev); + + return status; +} + +QDF_STATUS +wlan_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode val) +{ + struct coex_psoc_obj *coex_obj; + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + coex_obj->btc_chain_mode = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode *val) +{ + struct coex_psoc_obj *coex_obj; + + if (!val) { + coex_err("invalid param for getting btc chain mode"); + return QDF_STATUS_E_INVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + *val = coex_obj->btc_chain_mode; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_DBAM_CONFIG +QDF_STATUS wlan_dbam_config_send(struct wlan_objmgr_vdev *vdev, + struct coex_dbam_config_params *param) +{ + QDF_STATUS status; + + status = tgt_send_dbam_config(vdev, param); + if (QDF_IS_STATUS_ERROR(status)) + coex_err("failed to send dbam config"); + + return status; +} + +QDF_STATUS wlan_dbam_attach(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_dbam_tx_ops *dbam_tx_ops; + + if (!psoc) { + coex_err("psoc is Null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dbam_tx_ops = wlan_psoc_get_dbam_tx_ops(psoc); + if (!dbam_tx_ops) { + coex_err("dbam_tx_ops is Null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!dbam_tx_ops->dbam_event_attach) { + coex_err("dbam_event_attach function is Null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return dbam_tx_ops->dbam_event_attach(psoc); +} + +QDF_STATUS wlan_dbam_detach(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_dbam_tx_ops *dbam_tx_ops; + + if (!psoc) { + coex_err("psoc is Null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dbam_tx_ops = wlan_psoc_get_dbam_tx_ops(psoc); + if (!dbam_tx_ops) { + coex_err("dbam_tx_ops is Null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!dbam_tx_ops->dbam_event_detach) { + coex_err("dbam_event_detach function is Null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return dbam_tx_ops->dbam_event_detach(psoc); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_tgt_api.h new file mode 100644 index 0000000000..49edabac48 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_tgt_api.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains coex south bound interface definitions + */ + +#ifndef _WLAN_COEX_TGT_API_H_ +#define _WLAN_COEX_TGT_API_H_ + +#ifdef WLAN_FEATURE_DBAM_CONFIG +#include "wlan_coex_public_structs.h" +#endif + +#ifdef FEATURE_COEX +struct coex_config_params; +struct coex_multi_config; + +/** + * tgt_send_coex_config() - invoke target_if send coex config + * @vdev: vdev object + * @param: coex config parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_send_coex_config(struct wlan_objmgr_vdev *vdev, + struct coex_config_params *param); + +/** + * tgt_send_coex_multi_config() - invoke target_if send coex multiple config + * @vdev: vdev object + * @param: coex multiple config parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_send_coex_multi_config(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param); + +/** + * tgt_get_coex_multi_config_support() - invoke target_if get coex multiple + * configure support + * @psoc: PSOC object + * + * Return: true if target support coex multiple config command + */ +bool +tgt_get_coex_multi_config_support(struct wlan_objmgr_psoc *psoc); +#endif + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * tgt_send_dbam_config() - invoke target_if send dbam config + * @vdev: vdev object + * @param: dbam config parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_send_dbam_config(struct wlan_objmgr_vdev *vdev, + struct coex_dbam_config_params *param); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_ucfg_api.h new file mode 100644 index 0000000000..2f1aa8f52c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_ucfg_api.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains coex north bound interface declarations + */ + +#ifndef _WLAN_COEX_UCFG_API_H_ +#define _WLAN_COEX_UCFG_API_H_ + +#include "qdf_status.h" +#include +#include +#include "wlan_coex_public_structs.h" + +/** + * enum coex_btc_chain_mode - btc chain mode definitions + * @WLAN_COEX_BTC_CHAIN_MODE_SHARED: chains of BT and WLAN 2.4 GHz are shared. + * @WLAN_COEX_BTC_CHAIN_MODE_FDD: chains of BT and WLAN 2.4 GHz are + * separated, FDD mode. + * @WLAN_COEX_BTC_CHAIN_MODE_HYBRID: chains of BT and WLAN 2.4 GHz are + * separated, hybrid mode. + * @WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED: chain mode is not set. + */ +enum coex_btc_chain_mode { + WLAN_COEX_BTC_CHAIN_MODE_SHARED = 0, + WLAN_COEX_BTC_CHAIN_MODE_FDD, + WLAN_COEX_BTC_CHAIN_MODE_HYBRID, + WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED = 0xFF, +}; + +/** + * enum coex_config_type - coex config type definitions + * @COEX_CONFIG_BTC_CHAIN_MODE: config BT coex chain mode + * @COEX_CONFIG_TYPE_MAX: max value + */ +enum coex_config_type { + COEX_CONFIG_BTC_CHAIN_MODE, + /* keep last */ + COEX_CONFIG_TYPE_MAX, +}; + +/** + * typedef update_coex_cb() - cb to inform coex config + * @vdev: vdev pointer + * + * Return: void + */ +typedef QDF_STATUS (*update_coex_cb)(struct wlan_objmgr_vdev *vdev); + +#ifdef FEATURE_COEX +/** + * ucfg_coex_register_cfg_updated_handler() - API to register coex config + * updated handler. + * @psoc: pointer to psoc object + * @type: type of coex config + * @handler: handler to be registered + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, + enum coex_config_type type, + update_coex_cb handler); + +/** + * ucfg_coex_psoc_set_btc_chain_mode() - API to set BT coex chain mode for psoc + * @psoc: pointer to psoc object + * @val: BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +ucfg_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode val); + +/** + * ucfg_coex_psoc_get_btc_chain_mode() - API to get BT coex chain mode from psoc + * @psoc: pointer to psoc object + * @val: pointer to BT coex chain mode + * + * Return : status of operation + */ +QDF_STATUS +ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode *val); + +/** + * ucfg_coex_send_btc_chain_mode() - API to send BT coex config to target if + * @vdev: pointer to vdev object + * @mode: BT coex chain mode + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + enum coex_btc_chain_mode mode); + +/** + * ucfg_coex_send_multi_config() - API to send coex multiple config to target + * @vdev: pointer to vdev object + * @param: pointer to coex multiple config parameters + * + * Return: status of operation + */ +QDF_STATUS +ucfg_coex_send_multi_config(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param); + +/** + * ucfg_coex_send_logging_config() - API to send BT coex logging config to + * target if + * @psoc: pointer to psoc object + * @apps_args: pointer to argument + * + * Return : status of operation + */ +QDF_STATUS +ucfg_coex_send_logging_config(struct wlan_objmgr_psoc *psoc, + uint32_t *apps_args); +#else +static inline QDF_STATUS +ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, + enum coex_config_type type, + update_coex_cb handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode *val) +{ + if (val) + *val = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + enum coex_btc_chain_mode mode) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_coex_send_multi_config(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_coex_send_logging_config(struct wlan_objmgr_psoc *psoc, + uint32_t *apps_args) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * ucfg_coex_send_dbam_config() - API to send dbam config to target if + * @vdev: pointer to vdev object + * @param: DBAM config mode params + * @clbk: dbam config response callback + * @context: request manager context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS +ucfg_coex_send_dbam_config(struct wlan_objmgr_vdev *vdev, + struct coex_dbam_config_params *param, + void (*clbk)(void *ctx, + enum coex_dbam_comp_status *rsp), + void *context); +#else +static inline QDF_STATUS +ucfg_coex_send_dbam_config(void) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_utils_api.h b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_utils_api.h new file mode 100644 index 0000000000..caaac7cf9f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/inc/wlan_coex_utils_api.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_coex_utils_api.h + * + * This header file provides declaration of public APIs exposed to other UMAC + * components. + */ + +#ifndef _WLAN_COEX_UTILS_API_H_ +#define _WLAN_COEX_UTILS_API_H_ +#include + +/* + * wlan_coex_init() - Coex module initialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_coex_init(void); + +/* + * wlan_coex_deinit() - Coex module deinitialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_coex_deinit(void); + +/** + * wlan_coex_psoc_open() - Open coex component + * @psoc: soc context + * + * This function gets called when dispatcher opening. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_coex_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_coex_psoc_close() - Close coex component + * @psoc: soc context + * + * This function gets called when dispatcher closing. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_coex_psoc_close(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * wlan_dbam_psoc_enable() - API to enable coex dbam psoc component + * @psoc: pointer to psoc + * + * This API is invoked from dispatcher psoc enable. + * This API will register dbam WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_dbam_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dbam_psoc_disable() - API to disable coex dbam psoc component + * @psoc: pointer to psoc + * + * This API is invoked from dispatcher psoc disable. + * This API will unregister dbam WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_dbam_psoc_disable(struct wlan_objmgr_psoc *psoc); +#endif /* WLAN_FEATURE_DBAM_CONFIG */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_tgt_api.c new file mode 100644 index 0000000000..c1452980d0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_tgt_api.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains coex south bound interface definitions + */ + +#include +#include +#include +#include "wlan_objmgr_pdev_obj.h" + +static inline struct wlan_lmac_if_coex_tx_ops * +wlan_psoc_get_coex_txops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + coex_err("tx_ops is NULL"); + return NULL; + } + + return &tx_ops->coex_ops; +} + +static inline struct wlan_lmac_if_coex_tx_ops * +wlan_vdev_get_coex_txops(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return NULL; + } + + return wlan_psoc_get_coex_txops(psoc); +} + +QDF_STATUS +tgt_send_coex_config(struct wlan_objmgr_vdev *vdev, + struct coex_config_params *param) +{ + struct wlan_lmac_if_coex_tx_ops *coex_ops; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + + if (!vdev) { + coex_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + coex_err("NULL pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coex_ops = wlan_psoc_get_coex_txops(psoc); + if (coex_ops && coex_ops->coex_config_send) + return coex_ops->coex_config_send(pdev, param); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_send_coex_multi_config(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param) +{ + struct wlan_lmac_if_coex_tx_ops *coex_ops; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + + if (!vdev) { + coex_err("NULL vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + coex_err("NULL pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + coex_ops = wlan_psoc_get_coex_txops(psoc); + if (coex_ops && coex_ops->coex_multi_config_send) + return coex_ops->coex_multi_config_send(pdev, param); + + return QDF_STATUS_SUCCESS; +} + +bool +tgt_get_coex_multi_config_support(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_coex_tx_ops *coex_ops; + + coex_ops = wlan_psoc_get_coex_txops(psoc); + if (coex_ops && coex_ops->coex_get_multi_config_support) + return coex_ops->coex_get_multi_config_support(psoc); + + return false; +} + +#ifdef WLAN_FEATURE_DBAM_CONFIG +QDF_STATUS +tgt_send_dbam_config(struct wlan_objmgr_vdev *vdev, + struct coex_dbam_config_params *param) +{ + struct wlan_lmac_if_dbam_tx_ops *dbam_tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + + dbam_tx_ops = wlan_psoc_get_dbam_tx_ops(psoc); + if (dbam_tx_ops && dbam_tx_ops->set_dbam_config) + return dbam_tx_ops->set_dbam_config(psoc, param); + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_ucfg_api.c new file mode 100644 index 0000000000..480e7fb819 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_ucfg_api.c @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains coex north bound interface definitions + */ + +#include +#include +#include "wmi_unified.h" +#include "wlan_coex_public_structs.h" +#include "wlan_coex_tgt_api.h" + +QDF_STATUS +ucfg_coex_register_cfg_updated_handler(struct wlan_objmgr_psoc *psoc, + enum coex_config_type type, + update_coex_cb handler) +{ + struct coex_psoc_obj *coex_obj; + + if (type >= COEX_CONFIG_TYPE_MAX) { + coex_err("invalid coex type: %d", type); + return QDF_STATUS_E_INVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return QDF_STATUS_E_INVAL; + + coex_obj->coex_config_updated[type] = handler; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_coex_psoc_set_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode val) +{ + return wlan_coex_psoc_set_btc_chain_mode(psoc, val); +} + +QDF_STATUS +ucfg_coex_psoc_get_btc_chain_mode(struct wlan_objmgr_psoc *psoc, + enum coex_btc_chain_mode *val) +{ + return wlan_coex_psoc_get_btc_chain_mode(psoc, val); +} + +QDF_STATUS +ucfg_coex_send_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + enum coex_btc_chain_mode mode) +{ + struct coex_config_params param = {0}; + + if (mode > WLAN_COEX_BTC_CHAIN_MODE_HYBRID) + return QDF_STATUS_E_INVAL; + + param.vdev_id = wlan_vdev_get_id(vdev); + param.config_type = WMI_COEX_CONFIG_BTCOEX_SEPARATE_CHAIN_MODE; + param.config_arg1 = mode; + + coex_debug("send btc chain mode %d for vdev %d", mode, param.vdev_id); + + return wlan_coex_config_send(vdev, ¶m); +} + +QDF_STATUS +ucfg_coex_send_multi_config(struct wlan_objmgr_vdev *vdev, + struct coex_multi_config *param) +{ + return wlan_coex_multi_config_send(vdev, param); +} + +#ifdef WLAN_FEATURE_DBAM_CONFIG +QDF_STATUS +ucfg_coex_send_dbam_config(struct wlan_objmgr_vdev *vdev, + struct coex_dbam_config_params *param, + void (*clbk)(void *ctx, + enum coex_dbam_comp_status *rsp), + void *context) +{ + struct wlan_objmgr_psoc *psoc; + struct coex_psoc_obj *coex_obj; + struct wlan_coex_callback *cbk; + + if (!vdev) { + coex_err("Null vdev"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) { + coex_err("failed to get coex_obj"); + return QDF_STATUS_E_INVAL; + } + + cbk = &coex_obj->cb; + cbk->set_dbam_config_cb = clbk; + cbk->set_dbam_config_ctx = context; + + coex_debug("send dbam config mode %d for vdev_id %d", + param->dbam_mode, param->vdev_id); + + return wlan_dbam_config_send(vdev, param); +} +#endif + +#define COEX_CONFIG_ENABLE_CONT_INFO 12 + +QDF_STATUS +ucfg_coex_send_logging_config(struct wlan_objmgr_psoc *psoc, + uint32_t *apps_args) +{ + struct coex_config_params param = {0}; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (apps_args[0] != COEX_CONFIG_ENABLE_CONT_INFO) { + coex_err("invalid cmd %d", apps_args[0]); + return QDF_STATUS_E_FAILURE; + } + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, QDF_STA_MODE, + WLAN_COEX_ID); + + if (!vdev) { + coex_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + param.vdev_id = wlan_vdev_get_id(vdev); + param.config_type = WMI_COEX_CONFIG_ENABLE_CONT_INFO; + param.config_arg1 = apps_args[1]; + param.config_arg2 = apps_args[2]; + param.config_arg3 = apps_args[3]; + param.config_arg4 = apps_args[4]; + param.config_arg5 = apps_args[5]; + param.config_arg6 = apps_args[6]; + + coex_debug("send logging_config arg: %u for vdev %d", *apps_args, + param.vdev_id); + + status = wlan_coex_config_send(vdev, ¶m); + wlan_objmgr_vdev_release_ref(vdev, WLAN_COEX_ID); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_utils_api.c b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_utils_api.c new file mode 100644 index 0000000000..2878cb2fdd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/coex/dispatcher/src/wlan_coex_utils_api.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_coex_utils_api.c + * + * This file provides definitions of public APIs exposed to other UMAC + * components. + */ + +#include +#include +#include +#include "cfg_ucfg_api.h" + +QDF_STATUS wlan_coex_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_COEX, + wlan_coex_psoc_created_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("Failed to register psoc create handler"); + goto fail_create_psoc; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_COEX, + wlan_coex_psoc_destroyed_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("Failed to create psoc delete handler"); + goto fail_psoc_destroy; + } + + coex_debug("coex psoc create and delete handler registered"); + return status; + +fail_psoc_destroy: + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_COEX, + wlan_coex_psoc_created_notification, NULL); +fail_create_psoc: + return status; +} + +QDF_STATUS wlan_coex_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_COEX, + wlan_coex_psoc_destroyed_notification, NULL); + if (status != QDF_STATUS_SUCCESS) + coex_err("Failed to unregister psoc delete handler"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_COEX, + wlan_coex_psoc_created_notification, NULL); + if (status != QDF_STATUS_SUCCESS) + coex_err("Failed to unregister psoc create handler"); + + return status; +} + +#ifdef FEATURE_BTC_CHAIN_MODE +/** + * wlan_coex_set_btc_chain_mode_with_ini() - set BTC init chain mode + * with ini + * @psoc: pointer to psoc object + * + * This function is used to set BTC init chain mode with ini + * + * Return: None + */ +static void +wlan_coex_set_btc_chain_mode_with_ini(struct wlan_objmgr_psoc *psoc) +{ + enum coex_btc_chain_mode btc_chain_mode; + QDF_STATUS status; + + status = wlan_coex_psoc_get_btc_chain_mode(psoc, &btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("error for getting btc chain mode"); + return; + } + + if (btc_chain_mode == WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED) { + btc_chain_mode = cfg_get(psoc, CFG_SET_INIT_CHAIN_MODE_FOR_BTC); + if (btc_chain_mode > WLAN_COEX_BTC_CHAIN_MODE_HYBRID && + btc_chain_mode != WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED) { + coex_err("invalid ini config %d for btc chain mode", + btc_chain_mode); + return; + } + + status = wlan_coex_psoc_set_btc_chain_mode(psoc, + btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) + coex_err("error for setting btc init chain mode from ini"); + } +} +#else +static void +wlan_coex_set_btc_chain_mode_with_ini(struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +QDF_STATUS +wlan_coex_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + wlan_coex_set_btc_chain_mode_with_ini(psoc); + return wlan_coex_psoc_init(psoc); +} + +QDF_STATUS +wlan_coex_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return wlan_coex_psoc_deinit(psoc); +} + +#ifdef WLAN_FEATURE_DBAM_CONFIG +QDF_STATUS wlan_dbam_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dbam_attach(psoc); +} + +QDF_STATUS wlan_dbam_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dbam_detach(psoc); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_ext_type.h b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_ext_type.h new file mode 100644 index 0000000000..a4f5ae1a19 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_ext_type.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_ext_cp_stats_types.h + * + * This header file is included by the converged control path statistics + * component to map legacy statistic structures to the external + * (ext)typedefs used by the converged code. This mechanism allows the + * legacy structs to be included as part of the global objmgr objects. + */ + +#ifndef __WLAN_EXT_CP_STATS_TYPE_H__ +#define __WLAN_EXT_CP_STATS_TYPE_H__ + +/** + * typedef psoc_ext_cp_stats_t - Definition of psoc cp stats pointer + * Define obj_stats from external umac/cp_stats component point to this type + */ +typedef struct psoc_mc_cp_stats psoc_ext_cp_stats_t; + +/** + * typedef pdev_ext_cp_stats_t - Definition of pdev cp stats pointer + * Define pdev_stats from external umac/cp_stats component point to this type + */ +typedef struct pdev_mc_cp_stats pdev_ext_cp_stats_t; + +/** + * typedef vdev_ext_cp_stats_t - Definition of vdev cp stats pointer + * Define vdev_stats from external umac/cp_stats component point to this type + */ +typedef struct vdev_mc_cp_stats vdev_ext_cp_stats_t; + +/** + * typedef peer_ext_cp_stats_t - Definition of peer cp stats pointer + * Define peer_stats from external umac/cp_stats component point to this type + */ +typedef struct peer_mc_cp_stats peer_ext_cp_stats_t; + +/** + * typedef peer_ext_adv_cp_stats_t - Definition of peer adv cp stats pointer + * Define peer_adv_stats from external umac/cp_stats component point to this + * type + */ +typedef struct peer_adv_mc_cp_stats peer_ext_adv_cp_stats_t; + +#endif /* __WLAN_EXT_CP_STATS_TYPE_H__ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h new file mode 100644 index 0000000000..823c66acac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_defs.h @@ -0,0 +1,875 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cp_stats_mc_defs.h + * + * This file provide definition for structure/enums/defines related to control + * path stats component + */ + +#ifndef __WLAN_CP_STATS_MC_DEFS_H__ +#define __WLAN_CP_STATS_MC_DEFS_H__ + +#include "wlan_cmn.h" +#include "qdf_event.h" +/* For WMI_MAX_CHAINS */ +#include "wmi_unified.h" +#include "wlan_mlo_mgr_cmn.h" + +#ifdef QCA_SUPPORT_MC_CP_STATS +#include "wlan_cp_stats_public_structs.h" +#endif + +#ifdef WLAN_SUPPORT_TWT + +#include +/* Max TWT sessions per peer (supported by fw) */ +#define TWT_PEER_MAX_SESSIONS 1 + +#endif /* WLAN_SUPPORT_TWT */ + +#define MAX_NUM_CHAINS 2 + +#define MAX_MIB_STATS 1 + +#define IS_MSB_SET(__num) ((__num) & BIT(31)) +#define IS_LSB_SET(__num) ((__num) & BIT(0)) + +#define VDEV_ALL 0xFF + +/** + * enum stats_req_type - enum indicating bit position of various stats type in + * request map + * @TYPE_CONNECTION_TX_POWER: tx power was requested + * @TYPE_STATION_STATS: station stats was requested + * @TYPE_PEER_STATS: peer stats was requested + * @TYPE_MIB_STATS: MIB stats was requested + * @TYPE_PEER_STATS_INFO_EXT: peer stats info ext was requested + * @TYPE_CONGESTION_STATS: congestion stats was requested + * @TYPE_BIG_DATA_STATS: big data stats was requested + * @TYPE_MAX: maximum value + */ +enum stats_req_type { + TYPE_CONNECTION_TX_POWER = 0, + TYPE_STATION_STATS, + TYPE_PEER_STATS, + TYPE_MIB_STATS, + TYPE_PEER_STATS_INFO_EXT, + TYPE_CONGESTION_STATS, + TYPE_BIG_DATA_STATS, + TYPE_MAX, +}; + +/** + * enum tx_rate_info - tx rate flags + * @TX_RATE_LEGACY: Legacy rates + * @TX_RATE_HT20: HT20 rates + * @TX_RATE_HT40: HT40 rates + * @TX_RATE_SGI: Rate with Short guard interval + * @TX_RATE_LGI: Rate with Long guard interval + * @TX_RATE_VHT20: VHT 20 rates + * @TX_RATE_VHT40: VHT 40 rates + * @TX_RATE_VHT80: VHT 80 rates + * @TX_RATE_HE20: HE 20 rates + * @TX_RATE_HE40: HE 40 rates + * @TX_RATE_HE80: HE 80 rates + * @TX_RATE_HE160: HE 160 rates + * @TX_RATE_VHT160: VHT 160 rates + * @TX_RATE_EHT20: EHT 20 rates + * @TX_RATE_EHT40: EHT 40 rates + * @TX_RATE_EHT80: EHT 80 rates + * @TX_RATE_EHT160: EHT 160 rates + * @TX_RATE_EHT320: EHT 320 rates + */ +enum tx_rate_info { + TX_RATE_LEGACY = 0x1, + TX_RATE_HT20 = 0x2, + TX_RATE_HT40 = 0x4, + TX_RATE_SGI = 0x8, + TX_RATE_LGI = 0x10, + TX_RATE_VHT20 = 0x20, + TX_RATE_VHT40 = 0x40, + TX_RATE_VHT80 = 0x80, + TX_RATE_HE20 = 0x100, + TX_RATE_HE40 = 0x200, + TX_RATE_HE80 = 0x400, + TX_RATE_HE160 = 0x800, + TX_RATE_VHT160 = 0x1000, + TX_RATE_EHT20 = 0x2000, + TX_RATE_EHT40 = 0x4000, + TX_RATE_EHT80 = 0x8000, + TX_RATE_EHT160 = 0x10000, + TX_RATE_EHT320 = 0x20000, +}; + +/** + * enum txrate_gi - Guard Intervals + * @TXRATE_GI_0_8_US: guard interval 0.8 us + * @TXRATE_GI_0_4_US: guard interval 0.4 us for legacy + * @TXRATE_GI_1_6_US: guard interval 1.6 us + * @TXRATE_GI_3_2_US: guard interval 3.2 us + */ +enum txrate_gi { + TXRATE_GI_0_8_US = 0, + TXRATE_GI_0_4_US, + TXRATE_GI_1_6_US, + TXRATE_GI_3_2_US, +}; + +/** + * struct wake_lock_stats - wake lock stats structure + * @ucast_wake_up_count: Unicast wakeup count + * @bcast_wake_up_count: Broadcast wakeup count + * @ipv4_mcast_wake_up_count: ipv4 multicast wakeup count + * @ipv6_mcast_wake_up_count: ipv6 multicast wakeup count + * @ipv6_mcast_ra_stats: ipv6 multicast ra stats + * @ipv6_mcast_ns_stats: ipv6 multicast ns stats + * @ipv6_mcast_na_stats: ipv6 multicast na stats + * @icmpv4_count: ipv4 icmp packet count + * @icmpv6_count: ipv6 icmp packet count + * @rssi_breach_wake_up_count: rssi breach wakeup count + * @low_rssi_wake_up_count: low rssi wakeup count + * @gscan_wake_up_count: gscan wakeup count + * @pno_complete_wake_up_count: pno complete wakeup count + * @pno_match_wake_up_count: pno match wakeup count + * @oem_response_wake_up_count: oem response wakeup count + * @uc_drop_wake_up_count: local data uc drop wakeup count + * @fatal_event_wake_up_count: fatal event wakeup count + * @pwr_save_fail_detected: pwr save fail detected wakeup count + * @scan_11d: 11d scan wakeup count + * @mgmt_assoc: association request management frame + * @mgmt_disassoc: disassociation management frame + * @mgmt_assoc_resp: association response management frame + * @mgmt_reassoc: reassociate request management frame + * @mgmt_reassoc_resp: reassociate response management frame + * @mgmt_auth: authentication management frame + * @mgmt_deauth: deauthentication management frame + * @mgmt_action: action management frame + */ +struct wake_lock_stats { + uint32_t ucast_wake_up_count; + uint32_t bcast_wake_up_count; + uint32_t ipv4_mcast_wake_up_count; + uint32_t ipv6_mcast_wake_up_count; + uint32_t ipv6_mcast_ra_stats; + uint32_t ipv6_mcast_ns_stats; + uint32_t ipv6_mcast_na_stats; + uint32_t icmpv4_count; + uint32_t icmpv6_count; + uint32_t rssi_breach_wake_up_count; + uint32_t low_rssi_wake_up_count; + uint32_t gscan_wake_up_count; + uint32_t pno_complete_wake_up_count; + uint32_t pno_match_wake_up_count; + uint32_t oem_response_wake_up_count; + uint32_t uc_drop_wake_up_count; + uint32_t fatal_event_wake_up_count; + uint32_t pwr_save_fail_detected; + uint32_t scan_11d; + uint32_t mgmt_assoc; + uint32_t mgmt_disassoc; + uint32_t mgmt_assoc_resp; + uint32_t mgmt_reassoc; + uint32_t mgmt_reassoc_resp; + uint32_t mgmt_auth; + uint32_t mgmt_deauth; + uint32_t mgmt_action; +}; + +struct stats_event; + +/** + * struct big_data_stats_event - big data stats event param + * @vdev_id: vdev id + * @tsf_out_of_sync: tsf out of sync + * @ani_level: ani level + * @last_data_tx_pwr: tx pwr last data frm + * @target_power_dsss: tx power dsss + * @target_power_ofdm: target power ofdm + * @last_tx_data_rix: rx lateset data frame + * @last_tx_data_rate_kbps: tx latest data frame + */ +struct big_data_stats_event { + uint32_t vdev_id; + uint32_t tsf_out_of_sync; + int32_t ani_level; + uint32_t last_data_tx_pwr; + uint32_t target_power_dsss; + uint32_t target_power_ofdm; + uint32_t last_tx_data_rix; + uint32_t last_tx_data_rate_kbps; +}; + +/** + * struct medium_assess_data - medium assess data from firmware + * @part1_valid: the flag for part1 data, include cycle_count, + * rx_clear_count and tx_frame_count + * @cycle_count: accumulative cycle count (total time) + * @rx_clear_count: accumulative rx clear count (busy time) + * @tx_frame_count: accumulative tx frame count (total time) + * @part2_valid: the flag for part2 data, include my_rx_count + * @my_rx_count: my RX count + */ +struct medium_assess_data { + bool part1_valid; + uint32_t cycle_count; + uint32_t rx_clear_count; + uint32_t tx_frame_count; + bool part2_valid; + uint32_t my_rx_count; +}; + +/** + * struct request_info: details of each request + * @cookie: identifier for os_if request + * @u: unified data type for callback to process tx power/peer rssi/ + * station stats/mib stats/peer stats request when response comes and + * congestion notification callback. + * @vdev_id: vdev_id of request + * @pdev_id: pdev_id of request + * @peer_mac_addr: peer mac address + * @ml_vdev_info: mlo_stats_vdev_params structure + * @ml_peer_mac_addr: Array of ml peer mac addresses + */ +struct request_info { + void *cookie; + union { + void (*get_tx_power_cb)(int tx_power, void *cookie); + void (*get_peer_rssi_cb)(struct stats_event *ev, void *cookie); + void (*get_station_stats_cb)(struct stats_event *ev, + void *cookie); + void (*get_mib_stats_cb)(struct stats_event *ev, + void *cookie); + void (*get_peer_stats_cb)(struct stats_event *ev, + void *cookie); + void (*congestion_notif_cb)(uint8_t vdev_id, + struct medium_assess_data *data, + bool last); +#ifdef WLAN_FEATURE_BIG_DATA_STATS + void (*get_big_data_stats_cb)(struct big_data_stats_event *ev, + void *cookie); +#endif + } u; + uint32_t vdev_id; + uint32_t pdev_id; + uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE]; +#ifdef WLAN_FEATURE_11BE_MLO + struct mlo_stats_vdev_params ml_vdev_info; + uint8_t ml_peer_mac_addr[WLAN_UMAC_MLO_MAX_VDEVS][QDF_MAC_ADDR_SIZE]; +#endif +}; + +/** + * struct pending_stats_requests: details of pending requests + * @type_map: map indicating type of outstanding requests + * @req: array of info for outstanding request of each type + */ +struct pending_stats_requests { + uint32_t type_map; + struct request_info req[TYPE_MAX]; +}; + +/** + * struct cca_stats - cca stats + * @congestion: the congestion percentage = (busy_time/total_time)*100 + * for the interval from when the vdev was started to the current time + * (or the time at which the vdev was stopped). + */ +struct cca_stats { + uint32_t congestion; +}; + +/** + * struct psoc_mc_cp_stats: psoc specific stats + * @is_cp_stats_suspended: is cp stats suspended or not + * @pending: details of pending requests + * @wow_unspecified_wake_up_count: number of non-wow related wake ups + * @wow_stats: wake_lock stats for vdev + * @big_data_fw_support_enable: big data feature supported by fw or not + */ +struct psoc_mc_cp_stats { + bool is_cp_stats_suspended; + struct pending_stats_requests pending; + uint32_t wow_unspecified_wake_up_count; + struct wake_lock_stats wow_stats; +#ifdef WLAN_FEATURE_BIG_DATA_STATS + bool big_data_fw_support_enable; +#endif +}; + +/** + * struct pdev_mc_cp_extd_stats - pdev extd stats + * @pdev_id: pdev id + * @my_rx_count: What portion of time, as measured by the MAC HW clock was + * occupied, by receiving PPDUs addressed to one of the vdevs + * within this pdev. + * @rx_matched_11ax_msdu_cnt: number of Rx 11ax MSDUs with matching BSS color + * counter updated at EOP (end of packet) + * @rx_other_11ax_msdu_cnt: number of Rx 11ax MSDUs with other BSS color counter + * updated at EOP (end of packet) + */ +struct pdev_mc_cp_extd_stats { + uint32_t pdev_id; + uint32_t my_rx_count; + uint32_t rx_matched_11ax_msdu_cnt; + uint32_t rx_other_11ax_msdu_cnt; +}; + +/* Max supported bandwidth is 320Mhz, so max 16 subbands for 20Mhz */ +#define MAX_WIDE_BAND_SCAN_CHAN 16 + +/** + * struct wide_band_scan_chan_info - wide band scan channel info + * @vdev_id: vdev id + * @num_chan: number of channels (for each subbands fo 20Mhz) + * @is_wide_band_scan: wide band scan or not + * @cca_busy_subband_info: CCA busy for each possible 20Mhz subbands + * of the wideband scan channel + */ +struct wide_band_scan_chan_info { + uint32_t vdev_id; + uint8_t num_chan; + bool is_wide_band_scan; + uint32_t cca_busy_subband_info[MAX_WIDE_BAND_SCAN_CHAN]; +}; + +/** + * struct channel_status + * @channel_freq: Channel freq + * @noise_floor: Noise Floor value + * @rx_clear_count: rx clear count + * @cycle_count: cycle count + * @chan_tx_pwr_range: channel tx power per range in 0.5dBm steps + * @chan_tx_pwr_throughput: channel tx power per throughput + * @rx_frame_count: rx frame count (cumulative) + * @bss_rx_cycle_count: BSS rx cycle count + * @rx_11b_mode_data_duration: b-mode data rx time (units are microseconds) + * @tx_frame_count: BSS tx cycle count + * @mac_clk_mhz: sample frequency + * @channel_id: channel index + * @cmd_flags: indicate which stat event is this status coming from + * @subband_info: wide band scan channel info + */ +struct channel_status { + uint32_t channel_freq; + uint32_t noise_floor; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint32_t chan_tx_pwr_range; + uint32_t chan_tx_pwr_throughput; + uint32_t rx_frame_count; + uint32_t bss_rx_cycle_count; + uint32_t rx_11b_mode_data_duration; + uint32_t tx_frame_count; + uint32_t mac_clk_mhz; + uint32_t channel_id; + uint32_t cmd_flags; + struct wide_band_scan_chan_info subband_info; +}; + +/** + * struct per_channel_stats + * @total_channel: total number of be scanned channel + * @channel_status_list: channel status info store in this array + */ +struct per_channel_stats { + uint8_t total_channel; + struct channel_status + channel_status_list[NUM_CHANNELS]; +}; + +/** + * struct pdev_mc_cp_stats: pdev specific stats + * @max_pwr: max tx power for pdev + * @pdev_id: pdev id + * @rx_clear_count: accumulative rx clear count (busy time) of pdev + * @cycle_count: accumulative cycle count (total time) of pdev + * @tx_frame_count: accumulative tx frame count (total time) of pdev + * @chan_stats: per channel info stats + */ +struct pdev_mc_cp_stats { + int32_t max_pwr; + uint32_t pdev_id; + uint32_t rx_clear_count; + uint32_t cycle_count; + uint32_t tx_frame_count; + struct per_channel_stats chan_stats; +}; + +/** + * struct summary_stats - summary stats + * @snr: snr of vdev + * @rssi: rssi of vdev + * @retry_cnt: retry count + * @multiple_retry_cnt: multiple_retry_cnt + * @tx_frm_cnt: num of tx frames + * @rx_frm_cnt: num of rx frames + * @frm_dup_cnt: duplicate frame count + * @fail_cnt: fail count + * @rts_fail_cnt: rts fail count + * @ack_fail_cnt: ack fail count + * @rts_succ_cnt: rts success count + * @rx_discard_cnt: rx frames discarded + * @rx_error_cnt: rx frames with error + */ +struct summary_stats { + uint32_t snr; + int8_t rssi; + uint32_t retry_cnt[4]; + uint32_t multiple_retry_cnt[4]; + uint32_t tx_frm_cnt[4]; + uint32_t rx_frm_cnt; + uint32_t frm_dup_cnt; + uint32_t fail_cnt[4]; + uint32_t rts_fail_cnt; + uint32_t ack_fail_cnt; + uint32_t rts_succ_cnt; + uint32_t rx_discard_cnt; + uint32_t rx_error_cnt; +}; + +/** + * struct pmf_bcn_protect_stats - pmf bcn protect stats param + * @pmf_bcn_stats_valid: bcn protect stats received from fw are valid or not + * @igtk_mic_fail_cnt: MIC failure count of management packets using IGTK + * @igtk_replay_cnt: Replay detection count of management packets using IGTK + * @bcn_mic_fail_cnt: MIC failure count of beacon packets using BIGTK + * @bcn_replay_cnt: Replay detection count of beacon packets using BIGTK + */ +struct pmf_bcn_protect_stats { + bool pmf_bcn_stats_valid; + uint32_t igtk_mic_fail_cnt; + uint32_t igtk_replay_cnt; + uint32_t bcn_mic_fail_cnt; + uint32_t bcn_replay_cnt; +}; + +/** + * struct vdev_summary_extd_stats - vdev summary extended stats + * @vdev_id: vdev_id of the event + * @is_mlo_vdev_active: is the mlo vdev currently active + * @vdev_tx_power: vdev tx power + */ +struct vdev_summary_extd_stats { + uint8_t vdev_id; + bool is_mlo_vdev_active; + uint32_t vdev_tx_power; +}; + +/** + * struct vdev_mc_cp_stats - vdev specific stats + * @cca: cca stats + * @tx_rate_flags: tx rate flags (enum tx_rate_info) + * @chain_rssi: chain rssi + * @vdev_summary_stats: vdev's summary stats + * @pmf_bcn_stats: pmf beacon protect stats + * @vdev_extd_stats: vdev summary extended stats + */ +struct vdev_mc_cp_stats { + struct cca_stats cca; + uint32_t tx_rate_flags; + int8_t chain_rssi[MAX_NUM_CHAINS]; + struct summary_stats vdev_summary_stats; + struct pmf_bcn_protect_stats pmf_bcn_stats; + struct vdev_summary_extd_stats vdev_extd_stats; +}; + +/** + * struct peer_extd_stats - Peer extension statistics + * @peer_macaddr: peer MAC address + * @rx_duration: lower 32 bits of rx duration in microseconds + * @peer_tx_bytes: Total TX bytes (including dot11 header) sent to peer + * @peer_rx_bytes: Total RX bytes (including dot11 header) received from peer + * @last_tx_rate_code: last TX ratecode + * @last_tx_power: TX power used by peer - units are 0.5 dBm + * @rx_mc_bc_cnt: Total number of received multicast & broadcast data frames + * corresponding to this peer, 1 in the MSB of rx_mc_bc_cnt represents a + * valid data + */ +struct peer_extd_stats { + uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE]; + uint32_t rx_duration; + uint32_t peer_tx_bytes; + uint32_t peer_rx_bytes; + uint32_t last_tx_rate_code; + int32_t last_tx_power; + uint32_t rx_mc_bc_cnt; +}; + +/** + * struct peer_mc_cp_stats - peer specific stats + * @tx_rate: tx rate + * @rx_rate: rx rate + * @peer_rssi: rssi + * @peer_macaddr: mac address + * @extd_stats: Pointer to peer extended stats + * @adv_stats: Pointer to peer adv (extd2) stats + * @twt_param: Pointer to peer twt session parameters + */ +struct peer_mc_cp_stats { + uint32_t tx_rate; + uint32_t rx_rate; + int8_t peer_rssi; + uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE]; + struct peer_extd_stats *extd_stats; + struct peer_adv_mc_cp_stats *adv_stats; +#ifdef WLAN_SUPPORT_TWT + struct wmi_host_twt_session_stats_info twt_param[TWT_PEER_MAX_SESSIONS]; +#endif +}; + +/** + * struct peer_adv_mc_cp_stats - peer specific adv stats + * @peer_macaddr: mac address + * @fcs_count: fcs count + * @rx_bytes: rx bytes + * @rx_count: rx count + */ +struct peer_adv_mc_cp_stats { + uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE]; + uint32_t fcs_count; + uint32_t rx_count; + uint64_t rx_bytes; +}; + +#ifdef WLAN_FEATURE_MIB_STATS +/** + * struct dot11_counters - mib group containing attributes that are MAC counters + * @tx_frags: successfully transmitted fragments + * @group_tx_frames: transmitted group addressed frames + * @failed_cnt: MSDUs not transmitted successfully + * @rx_frags: fragments successfully received + * @group_rx_frames: group addressed frames received + * @fcs_error_cnt: FCS errors detected + * @tx_frames: frames successfully transmitted + */ +struct dot11_counters { + uint32_t tx_frags; + uint32_t group_tx_frames; + uint32_t failed_cnt; + uint32_t rx_frags; + uint32_t group_rx_frames; + uint32_t fcs_error_cnt; + uint32_t tx_frames; +}; + +/** + * struct dot11_mac_statistics - mib stats information on the operation of MAC + * @retry_cnt: retries done by mac for successful transmission + * @multi_retry_cnt: multiple retries done before successful transmission + * @frame_dup_cnt: duplicate no of frames + * @rts_success_cnt: number of CTS received (in response to RTS) + * @rts_fail_cnt: number of CTS not received (in response to RTS) + * @tx_ack_fail_cnt: number of ACK not received + */ +struct dot11_mac_statistics { + uint32_t retry_cnt; + uint32_t multi_retry_cnt; + uint32_t frame_dup_cnt; + uint32_t rts_success_cnt; + uint32_t rts_fail_cnt; + uint32_t tx_ack_fail_cnt; +}; + +/** + * struct dot11_qos_counters - qos mac counters + * @qos_tx_frag_cnt: transmitted QoS fragments + * @qos_failed_cnt: failed Qos fragments + * @qos_retry_cnt: Qos frames transmitted after retransmissions + * @qos_multi_retry_cnt: Qos frames transmitted after more than + * one retransmissions + * @qos_frame_dup_cnt: duplicate frames + * @qos_rts_success_cnt: number of CTS received (in response to RTS) + * @qos_rts_fail_cnt: number of CTS not received (in response to RTS) + * @tx_qos_ack_fail_cnt_up: number of ACK not received + * (in response to Qos frame) + * @qos_rx_frag_cnt: number of received MPDU of type Data + * @qos_tx_frame_cnt: number of transmitted MPDU of type Data + * @qos_discarded_frame_cnt: total Discarded MSDUs + * @qos_mpdu_rx_cnt: total received MPDU + * @qos_retries_rx_cnt: received MPDU with retry bit equal to 1 + */ +struct dot11_qos_counters { + uint32_t qos_tx_frag_cnt; + uint32_t qos_failed_cnt; + uint32_t qos_retry_cnt; + uint32_t qos_multi_retry_cnt; + uint32_t qos_frame_dup_cnt; + uint32_t qos_rts_success_cnt; + uint32_t qos_rts_fail_cnt; + uint32_t tx_qos_ack_fail_cnt_up; + uint32_t qos_rx_frag_cnt; + uint32_t qos_tx_frame_cnt; + uint32_t qos_discarded_frame_cnt; + uint32_t qos_mpdu_rx_cnt; + uint32_t qos_retries_rx_cnt; +}; + +/** + * struct dot11_rsna_stats - mib rsn stats + * @rm_ccmp_replays: received robust management CCMP MPDUs discarded + * by the replay mechanism + * @tkip_icv_err: TKIP ICV errors encountered + * @tkip_replays: TKIP replay errors detected + * @ccmp_decrypt_err: MPDUs discarded by the CCMP decryption algorithm + * @ccmp_replays: received CCMP MPDUs discarded by the replay mechanism + * @cmac_icv_err: MPDUs discarded by the CMAC integrity check algorithm + * @cmac_replays: MPDUs discarded by the CMAC replay errors + */ +struct dot11_rsna_stats { + uint32_t rm_ccmp_replays; + uint32_t tkip_icv_err; + uint32_t tkip_replays; + uint32_t ccmp_decrypt_err; + uint32_t ccmp_replays; + uint32_t cmac_icv_err; + uint32_t cmac_replays; +}; + +/** + * struct dot11_counters_group3 - dot11 group3 stats + * @tx_ampdu_cnt: transmitted AMPDUs + * @tx_mpdus_in_ampdu_cnt: number of MPDUs in the A-MPDU in transmitted AMPDUs + * @tx_octets_in_ampdu_cnt: octets in the transmitted A-MPDUs + * @ampdu_rx_cnt: received A-MPDU + * @mpdu_in_rx_ampdu_cnt: MPDUs received in the A-MPDU + * @rx_octets_in_ampdu_cnt: octets in the received A-MPDU + * @rx_ampdu_deli_crc_err_cnt: number of MPDUs delimiter with CRC error + */ +struct dot11_counters_group3 { + uint32_t tx_ampdu_cnt; + uint32_t tx_mpdus_in_ampdu_cnt; + uint64_t tx_octets_in_ampdu_cnt; + uint32_t ampdu_rx_cnt; + uint32_t mpdu_in_rx_ampdu_cnt; + uint64_t rx_octets_in_ampdu_cnt; + uint32_t rx_ampdu_deli_crc_err_cnt; +}; + +/** + * struct mib_stats_metrics - mib stats counters + * @mib_counters: dot11Counters group + * @mib_mac_statistics: dot11MACStatistics group + * @mib_qos_counters: dot11QoSCounters group + * @mib_rsna_stats: dot11RSNAStats group + * @mib_counters_group3: dot11CountersGroup3 group + */ +struct mib_stats_metrics { + struct dot11_counters mib_counters; + struct dot11_mac_statistics mib_mac_statistics; + struct dot11_qos_counters mib_qos_counters; + struct dot11_rsna_stats mib_rsna_stats; + struct dot11_counters_group3 mib_counters_group3; +}; +#endif + +/** + * struct congestion_stats_event: congestion stats event param + * @vdev_id: vdev_id of the event + * @congestion: the congestion percentage + */ +struct congestion_stats_event { + uint8_t vdev_id; + uint32_t congestion; +}; + +/** + * struct summary_stats_event - summary_stats event param + * @vdev_id: vdev_id of the event + * @stats: summary stats + */ +struct summary_stats_event { + uint8_t vdev_id; + struct summary_stats stats; +}; + +/** + * struct chain_rssi_event - chain_rssi event param + * @vdev_id: vdev_id of the event + * @chain_rssi: chain_rssi + */ +struct chain_rssi_event { + uint8_t vdev_id; + int8_t chain_rssi[MAX_NUM_CHAINS]; +}; + +/** + * struct peer_stats_info_ext_event - peer extended stats info + * @peer_macaddr: MAC address + * @tx_packets: packets transmitted to this station + * @tx_bytes: bytes transmitted to this station + * @rx_packets: packets received from this station + * @rx_bytes: bytes received from this station + * @tx_retries: cumulative retry counts + * @tx_failed: the number of failed frames + * @tx_succeed: the number of succeed frames + * @rssi: the signal strength + * @tx_rate: last used tx bitrate (kbps) + * @tx_rate_code: last tx rate code (last_tx_rate_code of wmi_peer_stats_info) + * @rx_rate: last used rx bitrate (kbps) + * @rx_rate_code: last rx rate code (last_rx_rate_code of wmi_peer_stats_info) + * @peer_rssi_per_chain: the average value of RSSI (dbm) per chain + * @num_tx_rate_counts: Num tx rate count for current peer + * @num_rx_rate_counts: Num rx rate count for current peer + * @tx_pkt_per_mcs: Number of tx packets for each MCS + * @rx_pkt_per_mcs: Number of rx packets for each MCS + */ +struct peer_stats_info_ext_event { + struct qdf_mac_addr peer_macaddr; + uint32_t tx_packets; + uint64_t tx_bytes; + uint32_t rx_packets; + uint64_t rx_bytes; + uint32_t tx_retries; + uint32_t tx_failed; + uint32_t tx_succeed; + int32_t rssi; + uint32_t tx_rate; + uint32_t tx_rate_code; + uint32_t rx_rate; + uint32_t rx_rate_code; + int32_t peer_rssi_per_chain[WMI_MAX_CHAINS]; + uint32_t num_tx_rate_counts; + uint32_t num_rx_rate_counts; + uint32_t *tx_pkt_per_mcs; + uint32_t *rx_pkt_per_mcs; +}; + +/** + * struct stats_event - parameters populated by stats event + * @num_pdev_stats: num pdev stats + * @pdev_stats: if populated array indicating pdev stats (index = pdev_id) + * @num_pdev_extd_stats: num pdev extended stats + * @pdev_extd_stats: if populated array indicating pdev extended stats + * (index = pdev_id) + * @num_peer_stats: num peer stats + * @peer_stats: if populated array indicating peer stats + * @peer_adv_stats: if populated, indicates peer adv (extd2) stats + * @num_peer_adv_stats: number of peer adv (extd2) stats + * @num_peer_extd_stats: Num peer extended stats + * @peer_extended_stats: Peer extended stats + * @cca_stats: if populated indicates congestion stats + * @num_summary_stats: number of summary stats + * @vdev_summary_stats: if populated indicates array of summary stats per vdev + * @num_mib_stats: number of mib stats + * @mib_stats: if populated indicates array of mib stats per vdev + * @num_chain_rssi_stats: number of chain rssi stats + * @vdev_chain_rssi: if populated indicates array of chain rssi per vdev + * @tx_rate: tx rate (kbps) + * @rx_rate: rx rate (kbps) + * @tx_rate_flags: tx rate flags, (enum tx_rate_info) + * @last_event: The LSB indicates if the event is the last event or not and the + * MSB indicates if this feature is supported by FW or not. + * @mac_seq_num: sequence number of event when fw update to host + * @num_peer_stats_info_ext: number of peer extended stats info + * @peer_stats_info_ext: peer extended stats info + * @bcn_protect_stats: pmf bcn protect stats + * @num_vdev_extd_stats: number of vdev extended stats + * @vdev_extd_stats: if populated indicates array of ext summary stats per vdev + */ +struct stats_event { + uint32_t num_pdev_stats; + struct pdev_mc_cp_stats *pdev_stats; + uint32_t num_pdev_extd_stats; + struct pdev_mc_cp_extd_stats *pdev_extd_stats; + uint32_t num_peer_stats; + struct peer_mc_cp_stats *peer_stats; + uint32_t num_peer_adv_stats; + struct peer_adv_mc_cp_stats *peer_adv_stats; + uint32_t num_peer_extd_stats; + struct peer_extd_stats *peer_extended_stats; + struct congestion_stats_event *cca_stats; + uint32_t num_summary_stats; + struct summary_stats_event *vdev_summary_stats; +#ifdef WLAN_FEATURE_MIB_STATS + uint32_t num_mib_stats; + struct mib_stats_metrics *mib_stats; +#endif + uint32_t num_chain_rssi_stats; + struct chain_rssi_event *vdev_chain_rssi; + uint32_t tx_rate; + uint32_t rx_rate; + enum tx_rate_info tx_rate_flags; + uint32_t last_event; + uint8_t mac_seq_num; + uint32_t num_peer_stats_info_ext; + struct peer_stats_info_ext_event *peer_stats_info_ext; + struct pmf_bcn_protect_stats bcn_protect_stats; + uint32_t num_vdev_extd_stats; + struct vdev_summary_extd_stats *vdev_extd_stats; +}; + +/** + * struct peer_stats_request_params - peer stats request parameter + * @request_type: request type, one peer or all peers of the vdev + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address, omitted if request type is all peers + * @reset_after_request: whether reset stats after request + */ +struct peer_stats_request_params { + uint32_t request_type; + uint32_t vdev_id; + uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE]; + uint32_t reset_after_request; +}; + +/** + * struct wmi_host_peer_stats_info - WMI peer stats info + * @peer_macaddr: peer mac address + * @tx_bytes: tx_bytes + * @tx_packets: tx packets + * @rx_bytes: rx_bytes + * @rx_packets: rx packets + * @tx_retries: tx retries of MPDU + * @tx_failed: tx failed MPDU + * @last_tx_rate_code: rate code of the last tx + * @last_rx_rate_code: rate code of the last rx + * @last_tx_bitrate_kbps: bitrate in bps of the last tx + * @last_rx_bitrate_kbps: bitrate in bps of the last rx + * @peer_rssi: peer rssi + * @tx_succeed: tx succeed MPDU + * @peer_rssi_per_chain: peer rssi per chain + * @num_tx_rate_counts: Num tx rate count for current peer + * @num_rx_rate_counts: Num rx rate count for current peer + * @tx_pkt_per_mcs: Number of tx rate counts for each MCS + * @rx_pkt_per_mcs: Number of rx rate counts for each MCS + */ +typedef struct { + struct qdf_mac_addr peer_macaddr; + uint64_t tx_bytes; + uint32_t tx_packets; + uint64_t rx_bytes; + uint32_t rx_packets; + uint32_t tx_retries; + uint32_t tx_failed; + uint32_t last_tx_rate_code; + uint32_t last_rx_rate_code; + uint32_t last_tx_bitrate_kbps; + uint32_t last_rx_bitrate_kbps; + int32_t peer_rssi; + uint32_t tx_succeed; + int32_t peer_rssi_per_chain[WMI_MAX_CHAINS]; + uint32_t num_tx_rate_counts; + uint32_t num_rx_rate_counts; + uint32_t *tx_pkt_per_mcs; + uint32_t *rx_pkt_per_mcs; +} wmi_host_peer_stats_info; + +#endif /* __WLAN_CP_STATS_MC_DEFS_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h new file mode 100644 index 0000000000..a57267d373 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_tgt_api.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2018, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cp_stats_mc_tgt_api.h + * + * This header file provide with API declarations to interface with Southbound + */ +#ifndef __WLAN_CP_STATS_MC_TGT_API_H__ +#define __WLAN_CP_STATS_MC_TGT_API_H__ + +#ifdef QCA_SUPPORT_CP_STATS +#include "wlan_cp_stats_mc_defs.h" + +//TODO - Check if this is true for hamilton +#ifdef QCA_WIFI_QCA6490 +#define TGT_MAC_ID_24G 2 +#define TGT_MAC_ID_5G 1 +#else +#define TGT_MAC_ID_24G 0 +#define TGT_MAC_ID_5G 0 +#endif + +/** + * target_if_mc_cp_get_mac_id(): API to get mac id + * @vdev_mlme: vdev mlme pointer + * + * Return: mac id + */ +uint8_t target_if_mc_cp_get_mac_id(struct vdev_mlme_obj *vdev_mlme); + +/** + * tgt_mc_cp_stats_process_stats_event(): API to process stats event + * @psoc: pointer to psoc object + * @ev: event parameters + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes on + * failure + */ +QDF_STATUS +tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev); + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +/** + * tgt_mc_cp_stats_process_infra_stats_event(): API to process event from + * cp stats infrastructure + * @psoc: pointer to psoc object + * @infra_event: infra cp stats event parameters + * + * Return: status of operation + */ +QDF_STATUS tgt_mc_cp_stats_process_infra_stats_event( + struct wlan_objmgr_psoc *psoc, + struct infra_cp_stats_event *infra_event); + +#endif + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/** + * tgt_mc_cp_stats_process_big_data_stats_event(): API to process big data + * stats event + * @psoc: pointer to psoc object + * @event: big data stats event parameters + * + * Return: status of operation + */ +QDF_STATUS +tgt_mc_cp_stats_process_big_data_stats_event( + struct wlan_objmgr_psoc *psoc, + struct big_data_stats_event *event); +#endif + +/** + * tgt_send_mc_cp_stats_req(): API to send stats request to lmac + * @psoc: pointer to psoc object + * @type: specific type of stats requested + * @req: pointer to stats request + * + * Return: status of operation + */ +QDF_STATUS tgt_send_mc_cp_stats_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *req); + +/** + * tgt_set_pdev_stats_update_period(): API to set pdev stats update + * period to FW + * @psoc: pointer to psoc object + * @pdev_id: pdev id + * @val: pdev stats update period, 0: disabled periodical stats report. + * + * Return: status of operation + */ +QDF_STATUS tgt_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t val); + +/** + * tgt_mc_cp_stats_inc_wake_lock_stats() : API to increment wake lock stats + * given the wake reason code + * @psoc: pointer to psoc object + * @reason: wake reason + * @stats: vdev wow stats to update + * @unspecified_wake_count: unspecified wake count to update + * + * Return : status of operation + */ +QDF_STATUS tgt_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc, + uint32_t reason, struct wake_lock_stats *stats, + uint32_t *unspecified_wake_count); + +#endif /* QCA_SUPPORT_CP_STATS */ +#endif /* __WLAN_CP_STATS_MC_TGT_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h new file mode 100644 index 0000000000..f534774144 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/inc/wlan_cp_stats_mc_ucfg_api.h @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cp_stats_mc_ucfg_api.h + * + * This header file maintain API declaration required for northbound interaction + */ + +#ifndef __WLAN_CP_STATS_MC_UCFG_API_H__ +#define __WLAN_CP_STATS_MC_UCFG_API_H__ + +#ifdef QCA_SUPPORT_CP_STATS + +#include +#include +#include + +#ifdef WLAN_SUPPORT_TWT + +#include +#include "../../core/src/wlan_cp_stats_defs.h" +#include + +/* Max TWT sessions supported */ +#define TWT_PSOC_MAX_SESSIONS TWT_PEER_MAX_SESSIONS + +/** + * ucfg_twt_get_peer_session_params() - Retrieves peer twt session parameters + * corresponding to a peer by using mac_addr and dialog id + * If dialog_id is TWT_GET_ALL_PEER_PARAMS_DIALOG_ID retrieves twt session + * parameters of all peers with valid twt session + * @psoc_obj: psoc object + * @param: array pointer to store peer twt session parameters, should contain + * mac_addr and dialog id of a peer for which twt session stats to be retrieved + * + * Return: total number of valid twt session + */ +int +ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, + struct wmi_host_twt_session_stats_info *param); +#endif /* WLAN_SUPPORT_TWT */ + +struct psoc_cp_stats; +struct vdev_cp_stats; + +/** + * ucfg_mc_cp_stats_get_psoc_wake_lock_stats() : API to get wake lock stats from + * psoc + * @psoc: pointer to psoc object + * @stats: stats object to populate + * + * Return : status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_get_psoc_wake_lock_stats( + struct wlan_objmgr_psoc *psoc, + struct wake_lock_stats *stats); + +/** + * ucfg_mc_cp_stats_get_vdev_wake_lock_stats() : API to get wake lock stats from + * vdev + * @vdev: pointer to vdev object + * @stats: stats object to populate + * + * Return : status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_get_vdev_wake_lock_stats( + struct wlan_objmgr_vdev *vdev, + struct wake_lock_stats *stats); + +/** + * ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol() : API to increment wake + * lock stats given the protocol of the packet that was received. + * @psoc: pointer to psoc object + * @vdev_id: vdev_id for which the packet was received + * @protocol: protocol of the packet that was received + * + * Return : status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum qdf_proto_subtype protocol); + +/** + * ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr() : API to increment wake + * lock stats given destination of packet that was received. + * @psoc: pointer to psoc object + * @vdev_id: vdev_id for which the packet was received + * @dest_mac: destination mac address of packet that was received + * + * Return : status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *dest_mac); + +/** + * ucfg_mc_cp_stats_inc_wake_lock_stats() : API to increment wake lock stats + * given wake reason. + * @psoc: pointer to psoc object + * @vdev_id: vdev_id on with WOW was received + * @reason: reason of WOW + * + * Return : status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t reason); + +/** + * ucfg_mc_cp_stats_write_wow_stats() - Writes WOW stats to buffer + * @psoc: pointer to psoc object + * @buffer: The char buffer to write to + * @max_len: The maximum number of chars to write + * @ret: number of bytes written + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_write_wow_stats( + struct wlan_objmgr_psoc *psoc, + char *buffer, uint16_t max_len, int *ret); + +/** + * ucfg_mc_cp_stats_send_stats_request() - API to send stats request to lmac + * @vdev: pointer to vdev object + * @type: request type + * @info: specific request information + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info); + +/** + * wlan_cfg80211_mc_twt_clear_infra_cp_stats() - send request to reset + * control path statistics + * @vdev: pointer to vdev object + * @dialog_id: dialod id of the twt session + * @twt_peer_mac: mac address of the peer + * + * Return: 0 for success or error code for failure + */ +int +wlan_cfg80211_mc_twt_clear_infra_cp_stats( + struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + uint8_t twt_peer_mac[QDF_MAC_ADDR_SIZE]); + +/** + * wlan_cfg80211_mc_twt_get_infra_cp_stats() - send twt get statistic request + * @vdev: pointer to vdev object + * @dialog_id: TWT session dialog id + * @twt_peer_mac: mac address of the peer + * @errno: error code + * + * Return: pointer to infra cp stats event for success or NULL for failure + */ +struct infra_cp_stats_event * +wlan_cfg80211_mc_twt_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + uint8_t twt_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno); +/** + * ucfg_mc_cp_stats_get_tx_power() - API to fetch tx_power + * @vdev: pointer to vdev object + * @dbm: pointer to tx power in dbm + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, + int *dbm); + +/** + * ucfg_mc_cp_stats_is_req_pending() - API to tell if given request is pending + * @psoc: pointer to psoc object + * @type: request type to check + * + * Return: true of request is pending, false otherwise + */ +bool ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type); + +/** + * ucfg_mc_cp_stats_set_pending_req() - API to set pending request + * @psoc: pointer to psoc object + * @type: request to update + * @req: value to update + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *req); +/** + * ucfg_mc_cp_stats_reset_pending_req() - API to reset pending request + * @psoc: pointer to psoc object + * @type: request to update + * @last_req: last request + * @pending: pending request present + * + * The function is an atomic operation of "reset" and "get" last request. + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_reset_pending_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *last_req, + bool *pending); + +/** + * ucfg_mc_cp_stats_get_pending_req() - API to get pending request + * @psoc: pointer to psoc object + * @type: request to update + * @info: buffer to populate + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *info); + +/** + * ucfg_mc_infra_cp_stats_free_stats_resources() - API to free buffers within + * infra cp stats_event structure + * @ev: structure whose buffer are to freed + * + * Return: none + */ +void +ucfg_mc_infra_cp_stats_free_stats_resources(struct infra_cp_stats_event *ev); + +/** + * ucfg_mc_cp_stats_free_stats_resources() - API to free buffers within stats_event + * structure + * @ev: structure whose buffer are to freed + * + * Return: none + */ +void ucfg_mc_cp_stats_free_stats_resources(struct stats_event *ev); + +/** + * ucfg_mc_cp_stats_cca_stats_get() - API to fetch cca stats + * @vdev: pointer to vdev object + * @cca_stats: pointer to cca info + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev *vdev, + struct cca_stats *cca_stats); + +/** + * ucfg_mc_cp_stats_set_rate_flags() - API to set rate flags + * @vdev: pointer to vdev object + * @flags: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev, + uint32_t flags); + +/** + * ucfg_mc_cp_stats_register_lost_link_info_cb() - API to register lost link + * info callback + * @psoc: pointer to psoc object + * @lost_link_cp_stats_info_cb: Lost link info callback to be registered + * + */ +void ucfg_mc_cp_stats_register_lost_link_info_cb( + struct wlan_objmgr_psoc *psoc, + void (*lost_link_cp_stats_info_cb)(void *stats_ev)); + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD +/** + * ucfg_mc_cp_stats_register_pmo_handler() - API to register pmo handler + * + * Return: none + */ +void ucfg_mc_cp_stats_register_pmo_handler(void); +#else +void static inline ucfg_mc_cp_stats_register_pmo_handler(void) { }; +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/** + * ucfg_send_big_data_stats_request() - API to send big data stats + * request + * @vdev: pointer to vdev object + * @type: request type + * @info: request info + * + * Return: status of operation + */ +QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info); + +/** + * ucfg_mc_cp_set_big_data_fw_support() - set big data fw support + * @psoc: PSOC object + * @enable: Set true if firmware supports big data, otherwise false + * + * API to set fw supports big data feature or not + * + * Return: void + */ +void +ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool enable); + +/** + * ucfg_mc_cp_get_big_data_fw_support() - get big data fw support + * @psoc: PSOC object + * @enable: Set true if firmware supports big data, otherwise false + * + * API to get fw supports big data feature or not + * + * Return: void + */ +void +ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool *enable); +#else +static inline +QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool enable) +{} + +static inline void +ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool *enable) +{} +#endif + +#ifdef CONFIG_WLAN_BMISS +/** + * wlan_cfg80211_mc_bmiss_get_infra_cp_stats() - API to get bmiss stats + * @vdev: pointer to vdev object + * @bmiss_peer_mac: mac address of the peer + * @errno: error code + * + * Return: pointer to infra cp stats event for success or NULL for failure + */ +struct infra_cp_stats_event* +wlan_cfg80211_mc_bmiss_get_infra_cp_stats( + struct wlan_objmgr_vdev *vdev, + uint8_t bmiss_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno); +#else /* CONFIG_WLAN_BMISS */ +static inline struct infra_cp_stats_event* +wlan_cfg80211_mc_bmiss_get_infra_cp_stats( + struct wlan_objmgr_vdev *vdev, + uint8_t bmiss_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno) +{ + return NULL; +} +#endif /* CONFIG_WLAN_BMISS */ + +/** + * wlan_cp_stats_update_chan_info() - API to update chan stats + * @psoc: pointer to psoc + * @chan_stat: channel stats + * @vdev_id: vdev id + * + * Return: None + */ +void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc, + struct channel_status *chan_stat, + uint8_t vdev_id); + +/** + * wlan_cp_stats_get_rx_clear_count() - API to get rx clear count for a channel + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @req_freq: freq for which rx clear count require + * + * Return: channel load + */ +uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t req_freq); + +/** + * ucfg_mc_cp_stats_clear_channel_status() - API to clear chan stats + * @pdev: pointer to pdev object + * + * Return: None + */ +void ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_mc_cp_stats_get_channel_status() - API to get chan stats + * @pdev: pointer to pdev object + * @chan_freq: channel freq of which stats are needed + * + * Return: channel status + */ +struct channel_status * +ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq); +#else /* QCA_SUPPORT_CP_STATS */ + +void static inline ucfg_mc_cp_stats_register_pmo_handler(void) { }; +static inline QDF_STATUS ucfg_mc_cp_stats_send_stats_request( + struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_mc_cp_stats_set_rate_flags( + struct wlan_objmgr_vdev *vdev, + uint32_t flags) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_mc_cp_stats_get_psoc_wake_lock_stats( + struct wlan_objmgr_psoc *psoc, + struct wake_lock_stats *stats) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum qdf_proto_subtype protocol) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t reason) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *dest_mac) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_mc_cp_stats_get_vdev_wake_lock_stats( + struct wlan_objmgr_vdev *vdev, + struct wake_lock_stats *stats) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool enable) +{} + +static inline void +ucfg_mc_cp_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool *enable) +{} + +static inline struct infra_cp_stats_event* +wlan_cfg80211_mc_bmiss_get_infra_cp_stats( + struct wlan_objmgr_vdev *vdev, + uint8_t bmiss_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno) +{ + return NULL; +} + +static inline void +ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, + int *dbm) +{} + +static inline +void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc, + struct channel_status *chan_stat, + uint8_t vdev_id) +{ +} + +static inline +uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t req_freq) +{ +} + +static inline +void ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev *pdev) +{ +} + +static inline struct channel_status * +ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq) +{ + return NULL; +} +#endif /* QCA_SUPPORT_CP_STATS */ +#endif /* __WLAN_CP_STATS_MC_UCFG_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c new file mode 100644 index 0000000000..111724b641 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c @@ -0,0 +1,1564 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC:wlan_cp_stats_mc_tgt_api.c + * + * This file provide API definitions to update control plane statistics received + * from southbound interface + */ + +#include "wlan_cp_stats_mc_defs.h" +#include "target_if_cp_stats.h" +#include "wlan_cp_stats_tgt_api.h" +#include "wlan_cp_stats_ucfg_api.h" +#include "wlan_cp_stats_mc_tgt_api.h" +#include +#include +#include "../../core/src/wlan_cp_stats_defs.h" +#include "../../core/src/wlan_cp_stats_obj_mgr_handler.h" +#include "son_api.h" +#include "wlan_policy_mgr_api.h" + +static bool tgt_mc_cp_stats_is_last_event(struct stats_event *ev, + enum stats_req_type stats_type) +{ + bool is_last_event; + + if (IS_MSB_SET(ev->last_event)) { + is_last_event = IS_LSB_SET(ev->last_event); + } else { + if (stats_type == TYPE_CONNECTION_TX_POWER) + is_last_event = true; + else + is_last_event = !!ev->peer_stats; + } + + if (is_last_event) + cp_stats_debug("Last stats event"); + + return is_last_event; +} + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +static void +tgt_cp_stats_register_infra_cp_stats_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{ + rx_ops->cp_stats_rx_ops.process_infra_stats_event = + tgt_mc_cp_stats_process_infra_stats_event; +} +#else +static void +tgt_cp_stats_register_infra_cp_stats_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{ +} +#endif + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +static void +tgt_cp_stats_register_big_data_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{ + rx_ops->cp_stats_rx_ops.process_big_data_stats_event = + tgt_mc_cp_stats_process_big_data_stats_event; +} + +static QDF_STATUS +send_big_data_stats_req(struct wlan_lmac_if_cp_stats_tx_ops *tx_ops, + struct wlan_objmgr_psoc *psoc, + struct request_info *req) +{ + if (!tx_ops->send_req_big_data_stats) { + cp_stats_err("could not get send_req_big_data_stats"); + return QDF_STATUS_E_NULL_VALUE; + } + + return tx_ops->send_req_big_data_stats(psoc, req); +} +#else +static void +tgt_cp_stats_register_big_data_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{} + +static QDF_STATUS +send_big_data_stats_req(struct wlan_lmac_if_cp_stats_tx_ops *tx_ops, + struct wlan_objmgr_psoc *psoc, + struct request_info *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void tgt_cp_stats_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{ + rx_ops->cp_stats_rx_ops.process_stats_event = + tgt_mc_cp_stats_process_stats_event; + tgt_cp_stats_register_infra_cp_stats_rx_ops(rx_ops); + tgt_cp_stats_register_big_data_rx_ops(rx_ops); +} + +static void tgt_mc_cp_stats_extract_tx_power(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev, + bool is_station_stats) +{ + int32_t max_pwr = 0; + uint8_t pdev_id; + uint8_t mac_id = 0; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + struct request_info last_req = {0}; + struct wlan_objmgr_vdev *vdev = NULL; + struct pdev_mc_cp_stats *pdev_mc_stats; + struct pdev_cp_stats *pdev_cp_stats_priv; + + if (!ev->pdev_stats) + return; + + if (is_station_stats) + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_STATION_STATS, &last_req); + else + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_CONNECTION_TX_POWER, &last_req); + + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + goto end; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + goto end; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + cp_stats_err("pdev is null"); + goto end; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + if (pdev_id >= ev->num_pdev_stats) { + cp_stats_err("pdev_id: %d invalid", pdev_id); + goto end; + } + + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev_cp_stats_priv is null"); + goto end; + } + + mac_id = policy_mgr_mode_get_macid_by_vdev_id(psoc, last_req.vdev_id); + + wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); + pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; + if (!is_station_stats && + pdev_mc_stats->max_pwr != ev->pdev_stats[pdev_id].max_pwr) + wlan_son_deliver_tx_power(vdev, + ev->pdev_stats[pdev_id].max_pwr); + if (mac_id == ev->mac_seq_num) + max_pwr = pdev_mc_stats->max_pwr = + ev->pdev_stats[pdev_id].max_pwr; + + wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); + +end: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); +} + +static void peer_rssi_iterator(struct wlan_objmgr_pdev *pdev, + void *peer, void *arg) +{ + struct stats_event *ev; + struct peer_mc_cp_stats *peer_mc_stats; + struct peer_cp_stats *peer_cp_stats_priv; + struct peer_extd_stats *peer_extd_mc_stats; + + if (WLAN_PEER_SELF == wlan_peer_get_peer_type(peer)) { + cp_stats_debug("ignore self peer: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wlan_peer_get_macaddr(peer))); + return; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer cp stats object is null"); + return; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + ev = arg; + ev->peer_stats[ev->num_peer_stats] = *peer_mc_stats; + ev->num_peer_stats++; + + peer_extd_mc_stats = peer_mc_stats->extd_stats; + ev->peer_extended_stats[ev->num_peer_extd_stats] = *peer_extd_mc_stats; + ev->num_peer_extd_stats++; + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); +} + +static void +tgt_mc_cp_stats_prepare_raw_peer_rssi(struct wlan_objmgr_psoc *psoc, + struct request_info *last_req) +{ + uint8_t *mac_addr; + uint16_t peer_count; + struct stats_event ev = {0}; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer = NULL; + struct peer_mc_cp_stats *peer_mc_stats; + struct peer_extd_stats *peer_mc_extd_stats; + struct peer_cp_stats *peer_cp_stats_priv; + void (*get_peer_rssi_cb)(struct stats_event *ev, void *cookie); + + get_peer_rssi_cb = last_req->u.get_peer_rssi_cb; + if (!get_peer_rssi_cb) { + cp_stats_debug("get_peer_rssi_cb is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + goto end; + } + + mac_addr = last_req->peer_mac_addr; + if (QDF_IS_ADDR_BROADCAST(mac_addr)) { + pdev = wlan_vdev_get_pdev(vdev); + peer_count = wlan_pdev_get_peer_count(pdev); + ev.peer_stats = qdf_mem_malloc(sizeof(*ev.peer_stats) * + peer_count); + if (!ev.peer_stats) + goto end; + + ev.peer_extended_stats = + qdf_mem_malloc(sizeof(*ev.peer_extended_stats) * + peer_count); + if (!ev.peer_extended_stats) + goto end; + + wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_PEER_OP, + peer_rssi_iterator, &ev, + true, WLAN_CP_STATS_ID); + } else { + peer = wlan_objmgr_get_peer(psoc, last_req->pdev_id, + mac_addr, WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_debug("peer[" QDF_MAC_ADDR_FMT "] is null", + QDF_MAC_ADDR_REF(mac_addr)); + goto end; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer cp stats object is null"); + goto end; + } + + ev.peer_stats = qdf_mem_malloc(sizeof(*ev.peer_stats)); + if (!ev.peer_stats) + goto end; + + ev.num_peer_stats = 1; + + ev.peer_extended_stats = + qdf_mem_malloc(sizeof(*ev.peer_extended_stats)); + if (!ev.peer_extended_stats) + goto end; + + ev.num_peer_extd_stats = 1; + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + *ev.peer_stats = *peer_mc_stats; + + peer_mc_extd_stats = peer_mc_stats->extd_stats; + *ev.peer_extended_stats = *peer_mc_extd_stats; + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + } + +end: + get_peer_rssi_cb(&ev, last_req->cookie); + + ucfg_mc_cp_stats_free_stats_resources(&ev); + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); +} + +static QDF_STATUS +tgt_mc_cp_stats_update_peer_adv_stats(struct wlan_objmgr_psoc *psoc, + struct peer_adv_mc_cp_stats + *peer_adv_stats, uint32_t size) +{ + uint8_t *peer_mac_addr; + struct wlan_objmgr_peer *peer; + struct peer_mc_cp_stats *peer_mc_stats; + struct peer_adv_mc_cp_stats *peer_adv_mc_stats; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct peer_cp_stats *peer_cp_stats_priv; + + if (!peer_adv_stats) + return QDF_STATUS_E_INVAL; + + peer_mac_addr = peer_adv_stats->peer_macaddr; + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr, + WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_debug("peer is null"); + return QDF_STATUS_E_EXISTS; + } + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer_cp_stats_priv is null"); + status = QDF_STATUS_E_EXISTS; + goto end; + } + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + peer_adv_mc_stats = peer_mc_stats->adv_stats; + + qdf_mem_copy(peer_adv_mc_stats->peer_macaddr, + peer_adv_stats->peer_macaddr, + QDF_MAC_ADDR_SIZE); + if (peer_adv_stats->fcs_count) + peer_adv_mc_stats->fcs_count = peer_adv_stats->fcs_count; + if (peer_adv_stats->rx_bytes) + peer_adv_mc_stats->rx_bytes = peer_adv_stats->rx_bytes; + if (peer_adv_stats->rx_count) + peer_adv_mc_stats->rx_count = peer_adv_stats->rx_count; + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + +end: + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return status; +} + +static QDF_STATUS +tgt_mc_cp_stats_update_peer_stats(struct wlan_objmgr_psoc *psoc, + struct peer_mc_cp_stats *peer_stats) +{ + uint8_t *peer_mac_addr; + struct wlan_objmgr_peer *peer; + struct peer_mc_cp_stats *peer_mc_stats; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct peer_cp_stats *peer_cp_stats_priv; + + if (!peer_stats) + return QDF_STATUS_E_INVAL; + + peer_mac_addr = peer_stats->peer_macaddr; + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr, + WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_debug("peer is null"); + return QDF_STATUS_E_EXISTS; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer_cp_stats_priv is null"); + status = QDF_STATUS_E_EXISTS; + goto end; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + qdf_mem_copy(peer_mc_stats->peer_macaddr, + peer_stats->peer_macaddr, + QDF_MAC_ADDR_SIZE); + if (peer_stats->tx_rate) + peer_mc_stats->tx_rate = peer_stats->tx_rate; + if (peer_stats->rx_rate) + peer_mc_stats->rx_rate = peer_stats->rx_rate; + if (peer_stats->peer_rssi) + peer_mc_stats->peer_rssi = peer_stats->peer_rssi; + cp_stats_nofl_debug("PEER STATS: peer_mac="QDF_MAC_ADDR_FMT", tx_rate=%u, rx_rate=%u, peer_rssi=%d", + QDF_MAC_ADDR_REF(peer_mc_stats->peer_macaddr), + peer_mc_stats->tx_rate, + peer_mc_stats->rx_rate, peer_mc_stats->peer_rssi); + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + +end: + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return status; +} + +static QDF_STATUS +tgt_mc_cp_stats_update_peer_extd_stats( + struct wlan_objmgr_psoc *psoc, + struct peer_extd_stats *peer_extended_stats) +{ + uint8_t *peer_mac_addr; + struct wlan_objmgr_peer *peer; + struct peer_mc_cp_stats *peer_mc_stats; + struct peer_extd_stats *peer_extd_mc_stats; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct peer_cp_stats *peer_cp_stats_priv; + + if (!peer_extended_stats) + return QDF_STATUS_E_INVAL; + + peer_mac_addr = peer_extended_stats->peer_macaddr; + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_addr, + WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_debug("peer is null"); + return QDF_STATUS_E_EXISTS; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer_cp_stats_priv is null"); + status = QDF_STATUS_E_EXISTS; + goto end; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + peer_extd_mc_stats = peer_mc_stats->extd_stats; + if (!peer_extd_mc_stats) { + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + cp_stats_err("No peer_extd_mc_stats"); + status = QDF_STATUS_E_INVAL; + goto end; + } + qdf_mem_copy(peer_extd_mc_stats->peer_macaddr, + peer_extended_stats->peer_macaddr, + QDF_MAC_ADDR_SIZE); + if (peer_extended_stats->rx_mc_bc_cnt) + peer_extd_mc_stats->rx_mc_bc_cnt = + peer_extended_stats->rx_mc_bc_cnt; + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + + cp_stats_debug("peer_mac="QDF_MAC_ADDR_FMT", rx_mc_bc_cnt=%u", + QDF_MAC_ADDR_REF(peer_extended_stats->peer_macaddr), + peer_extended_stats->rx_mc_bc_cnt); + +end: + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return status; +} + +static void tgt_mc_cp_stats_extract_peer_extd_stats( + struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + uint32_t i, selected; + QDF_STATUS status; + struct request_info last_req = {0}; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_PEER_STATS, + &last_req); + + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + selected = ev->num_peer_extd_stats; + for (i = 0; i < ev->num_peer_extd_stats; i++) { + status = tgt_mc_cp_stats_update_peer_extd_stats( + psoc, + &ev->peer_extended_stats[i]); + + if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && + !qdf_mem_cmp(ev->peer_extended_stats[i].peer_macaddr, + last_req.peer_mac_addr, + QDF_MAC_ADDR_SIZE)) { + /* mac is specified, but failed to update the peer */ + if (QDF_IS_STATUS_ERROR(status)) + return; + + selected = i; + } + } + + /* no matched peer */ + if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && + selected == ev->num_peer_extd_stats) { + cp_stats_rl_err("peer not found stats"); + return; + } +} + +static void tgt_mc_cp_stats_extract_peer_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev, + bool is_station_stats) +{ + uint32_t i; + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + uint32_t selected; + + if (is_station_stats) + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_STATION_STATS, + &last_req); + else + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_PEER_STATS, + &last_req); + + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + if (!ev->peer_stats) + goto extd2_stats; + + selected = ev->num_peer_stats; + for (i = 0; i < ev->num_peer_stats; i++) { + status = tgt_mc_cp_stats_update_peer_stats(psoc, + &ev->peer_stats[i]); + if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && + !qdf_mem_cmp(ev->peer_stats[i].peer_macaddr, + last_req.peer_mac_addr, + QDF_MAC_ADDR_SIZE)) { + /* mac is specified, but failed to update the peer */ + if (QDF_IS_STATUS_ERROR(status)) + return; + + selected = i; + } + } + + /* no matched peer */ + if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && + selected == ev->num_peer_stats) + cp_stats_debug("peer not found for stats"); + +extd2_stats: + + if (!ev->peer_adv_stats) + goto complete; + + selected = ev->num_peer_adv_stats; + for (i = 0; i < ev->num_peer_adv_stats; i++) { + status = tgt_mc_cp_stats_update_peer_adv_stats( + psoc, &ev->peer_adv_stats[i], + ev->num_peer_adv_stats); + if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && + !qdf_mem_cmp(ev->peer_adv_stats[i].peer_macaddr, + last_req.peer_mac_addr, + QDF_MAC_ADDR_SIZE)) { + /* mac is specified, but failed to update the peer */ + if (QDF_IS_STATUS_ERROR(status)) + return; + + selected = i; + } + } + + /* no matched peer */ + if (!QDF_IS_ADDR_BROADCAST(last_req.peer_mac_addr) && + selected == ev->num_peer_adv_stats) + cp_stats_debug("peer not found for extd stats"); + +complete: + if (is_station_stats) + return; + + tgt_mc_cp_stats_extract_peer_extd_stats(psoc, ev); + if (tgt_mc_cp_stats_is_last_event(ev, TYPE_PEER_STATS)) { + ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_PEER_STATS, + &last_req, &pending); + if (pending && last_req.u.get_peer_rssi_cb) + tgt_mc_cp_stats_prepare_raw_peer_rssi(psoc, &last_req); + } +} + +#ifdef WLAN_FEATURE_MIB_STATS +static void tgt_mc_cp_stats_extract_mib_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + + if (!ev->mib_stats) { + cp_stats_debug("no mib stats"); + return; + } + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_MIB_STATS, &last_req); + + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + if (tgt_mc_cp_stats_is_last_event(ev, TYPE_MIB_STATS)) { + ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_MIB_STATS, + &last_req, &pending); + if (last_req.u.get_mib_stats_cb && pending) + last_req.u.get_mib_stats_cb(ev, last_req.cookie); + } +} +#else +static void tgt_mc_cp_stats_extract_mib_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ +} +#endif + +static void +tgt_mc_cp_stats_extract_peer_stats_info_ext(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + + if (!ev->peer_stats_info_ext || ev->num_peer_stats_info_ext == 0) { + cp_stats_debug("no peer_stats_info_ext"); + return; + } + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_PEER_STATS_INFO_EXT, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_PEER_STATS_INFO_EXT, + &last_req, &pending); + if (last_req.u.get_peer_stats_cb && pending) { + last_req.u.get_peer_stats_cb(ev, last_req.cookie); + last_req.u.get_peer_stats_cb = NULL; + } +} + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +#ifdef WLAN_SUPPORT_TWT +static void +tgt_mc_infra_cp_stats_extract_twt_stats(struct wlan_objmgr_psoc *psoc, + struct infra_cp_stats_event *ev) +{ + QDF_STATUS status; + get_infra_cp_stats_cb resp_cb = NULL; + void *context = NULL; + + status = wlan_cp_stats_infra_cp_get_context(psoc, &resp_cb, &context); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_get_infra_cp_stats_context failed"); + return; + } + + cp_stats_debug("num_twt_infra_cp_stats = %d action %d", + ev->num_twt_infra_cp_stats, ev->action); + + if (resp_cb) + resp_cb(ev, context); +} +#else +static void +tgt_mc_infra_cp_stats_extract_twt_stats(struct wlan_objmgr_psoc *psoc, + struct infra_cp_stats_event *ev) +{ +} +#endif +#endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ + +#ifdef WLAN_FEATURE_MEDIUM_ASSESS +static void +tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + QDF_STATUS status; + uint8_t i, index; + struct request_info last_req = {0}; + struct medium_assess_data data[WLAN_UMAC_MAX_RP_PID] = { {0} }; + bool is_last_event = tgt_mc_cp_stats_is_last_event(ev, + TYPE_CONGESTION_STATS); + + if (!(ev->num_pdev_stats || ev->num_pdev_extd_stats)) { + cp_stats_err("no congestion sta for pdev"); + return; + } + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_CONGESTION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + for (i = 0; (i < ev->num_pdev_stats) && (i < WLAN_UMAC_MAX_RP_PID); + i++){ + index = ev->pdev_stats[i].pdev_id; + if (index >= WLAN_UMAC_MAX_RP_PID) { + cp_stats_err("part1 pdev id error"); + continue; + } + data[index].part1_valid = true; + data[index].cycle_count = ev->pdev_stats[i].cycle_count; + data[index].rx_clear_count = ev->pdev_stats[i].rx_clear_count; + data[index].tx_frame_count = ev->pdev_stats[i].tx_frame_count; + } + + for (i = 0; (i < ev->num_pdev_extd_stats) && (i < WLAN_UMAC_MAX_RP_PID); + i++){ + index = ev->pdev_extd_stats[i].pdev_id; + if (index >= WLAN_UMAC_MAX_RP_PID) { + cp_stats_err("part2 pdev id error"); + continue; + } + data[index].part2_valid = true; + data[index].my_rx_count = ev->pdev_extd_stats[i].my_rx_count; + } + + if (last_req.u.congestion_notif_cb) + last_req.u.congestion_notif_cb(last_req.vdev_id, data, + is_last_event); + +} +#else +static void +tgt_mc_cp_stats_extract_congestion_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static void +update_ml_vdev_id_from_stats_event(struct request_info *req, + uint8_t *vdev_id) +{ + if (!req->ml_vdev_info.ml_vdev_count) { + *vdev_id = req->vdev_id; + return; + } + + if (*vdev_id == WLAN_UMAC_VDEV_ID_MAX || + *vdev_id >= WLAN_MAX_VDEVS) { + cp_stats_err("Invalid vdev[%u] sent by firmware", *vdev_id); + *vdev_id = WLAN_UMAC_VDEV_ID_MAX; + } +} +#else +static inline void +update_ml_vdev_id_from_stats_event(struct request_info *req, + uint8_t *vdev_id) +{ + *vdev_id = req->vdev_id; +} +#endif + +static void tgt_mc_cp_stats_extract_cca_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + if (!ev->cca_stats) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + ev->cca_stats->vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return; + } + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + goto end; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + vdev_mc_stats->cca.congestion = ev->cca_stats->congestion; + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); +} + +static void +tgt_mc_cp_stats_extract_pmf_bcn_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + struct wlan_objmgr_vdev *vdev; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_STATION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return; + } + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + + if (ev->bcn_protect_stats.pmf_bcn_stats_valid) + vdev_mc_stats->pmf_bcn_stats = ev->bcn_protect_stats; + + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); +} + +static void tgt_mc_cp_stats_extract_vdev_summary_stats( + struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + uint8_t i, vdev_id = WLAN_INVALID_VDEV_ID; + QDF_STATUS status; + struct wlan_objmgr_peer *peer = NULL; + struct request_info last_req = {0}; + struct wlan_objmgr_vdev *vdev; + struct peer_mc_cp_stats *peer_mc_stats; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct peer_cp_stats *peer_cp_stats_priv; + struct vdev_cp_stats *vdev_cp_stats_priv; + + if (!ev->vdev_summary_stats) + return; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_STATION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + for (i = 0; i < ev->num_summary_stats; i++) { + vdev_id = ev->vdev_summary_stats[i].vdev_id; + update_ml_vdev_id_from_stats_event(&last_req, &vdev_id); + if (ev->vdev_summary_stats[i].vdev_id == vdev_id) + break; + } + + if (i == ev->num_summary_stats) { + cp_stats_debug("vdev_id %d not found", vdev_id); + return; + } + + if (vdev_id == WLAN_INVALID_VDEV_ID) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return; + } + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + goto end; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + qdf_mem_copy(&vdev_mc_stats->vdev_summary_stats, + &ev->vdev_summary_stats[i].stats, + sizeof(vdev_mc_stats->vdev_summary_stats)); + + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + + peer = wlan_objmgr_get_peer(psoc, last_req.pdev_id, + last_req.peer_mac_addr, WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_debug("peer is null "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(last_req.peer_mac_addr)); + goto end; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer cp stats object is null"); + goto end; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + peer_mc_stats->peer_rssi = ev->vdev_summary_stats[i].stats.rssi; + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + +end: + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); +} + +static void tgt_mc_cp_stats_extract_vdev_chain_rssi_stats( + struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + uint8_t i, j, vdev_id; + QDF_STATUS status; + struct request_info last_req = {0}; + struct wlan_objmgr_vdev *vdev; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + if (!ev->vdev_chain_rssi) + return; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_STATION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + for (i = 0; i < ev->num_chain_rssi_stats; i++) { + vdev_id = ev->vdev_chain_rssi[i].vdev_id; + update_ml_vdev_id_from_stats_event(&last_req, &vdev_id); + if (ev->vdev_chain_rssi[i].vdev_id != vdev_id) + continue; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return; + } + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + for (j = 0; j < MAX_NUM_CHAINS; j++) { + vdev_mc_stats->chain_rssi[j] = + ev->vdev_chain_rssi[i].chain_rssi[j]; + } + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + } +} + +static void +tgt_mc_cp_stats_extract_vdev_extd_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + uint8_t i, vdev_id; + QDF_STATUS status; + struct request_info last_req = {0}; + struct wlan_objmgr_vdev *vdev; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + if (!ev->vdev_extd_stats) + return; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + for (i = 0; i < ev->num_vdev_extd_stats; i++) { + vdev_id = ev->vdev_extd_stats[i].vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return; + } + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + qdf_mem_copy(&vdev_mc_stats->vdev_extd_stats, + &ev->vdev_extd_stats[i], + sizeof(vdev_mc_stats->vdev_extd_stats)); + + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + } +} + +static QDF_STATUS +tgt_send_vdev_mc_cp_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev, + struct request_info *last_req) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + if (!ev || !last_req) + return QDF_STATUS_E_NULL_VALUE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + ev->vdev_summary_stats[0].vdev_id = last_req->vdev_id; + ev->vdev_summary_stats[0].stats = vdev_mc_stats->vdev_summary_stats; + ev->vdev_chain_rssi[0].vdev_id = last_req->vdev_id; + qdf_mem_copy(ev->vdev_chain_rssi[0].chain_rssi, + vdev_mc_stats->chain_rssi, + sizeof(vdev_mc_stats->chain_rssi)); + ev->tx_rate_flags = vdev_mc_stats->tx_rate_flags; + + ev->bcn_protect_stats = vdev_mc_stats->pmf_bcn_stats; + + qdf_mem_copy(&ev->vdev_extd_stats[0], + &vdev_mc_stats->vdev_extd_stats, + sizeof(vdev_mc_stats->vdev_extd_stats)); + + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +tgt_send_peer_mc_cp_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev, + struct request_info *last_req) +{ + struct wlan_objmgr_peer *peer; + struct peer_mc_cp_stats *peer_mc_stats; + struct peer_cp_stats *peer_cp_stats_priv; + + if (!ev || !last_req) + return QDF_STATUS_E_NULL_VALUE; + + peer = wlan_objmgr_get_peer(psoc, last_req->pdev_id, + last_req->peer_mac_addr, WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_debug("peer object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + cp_stats_err("peer cp stats object is null"); + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + /* + * The linkspeed returned by fw is in kbps so convert + * it in units of 100kbps which is expected by UMAC + */ + ev->tx_rate = peer_mc_stats->tx_rate / 100; + ev->rx_rate = peer_mc_stats->rx_rate / 100; + + if (peer_mc_stats->adv_stats) { + ev->num_peer_adv_stats = 1; + qdf_mem_copy(ev->peer_adv_stats, + peer_mc_stats->adv_stats, + sizeof(*peer_mc_stats->adv_stats)); + } + + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +tgt_send_pdev_mc_cp_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev, + struct request_info *last_req) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev = NULL; + struct pdev_mc_cp_stats *pdev_mc_stats; + struct pdev_cp_stats *pdev_cp_stats_priv; + int pdev_id; + + if (!ev || !last_req) + return QDF_STATUS_E_NULL_VALUE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req->vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + cp_stats_err("pdev is null"); + goto end; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + if (pdev_id != last_req->pdev_id) { + cp_stats_err("pdev_id: %d invalid", pdev_id); + goto end; + } + + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev_cp_stats_priv is null"); + goto end; + } + + wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); + pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; + qdf_mem_copy(ev->pdev_stats, + pdev_mc_stats, + sizeof(*pdev_mc_stats)); + wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + + return QDF_STATUS_SUCCESS; + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return QDF_STATUS_E_NULL_VALUE; +} + +static QDF_STATUS +tgt_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, int *dbm) +{ + struct wlan_objmgr_pdev *pdev; + struct pdev_mc_cp_stats *pdev_mc_stats; + struct pdev_cp_stats *pdev_cp_stats_priv; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stat; + uint32_t vdev_power = 0; + + vdev_cp_stat = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (vdev_cp_stat) { + wlan_cp_stats_vdev_obj_lock(vdev_cp_stat); + vdev_mc_stats = vdev_cp_stat->vdev_stats; + vdev_power = vdev_mc_stats->vdev_extd_stats.vdev_tx_power; + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stat); + if (vdev_power) { + *dbm = vdev_power; + return QDF_STATUS_SUCCESS; + } + } + + pdev = wlan_vdev_get_pdev(vdev); + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); + pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; + *dbm = pdev_mc_stats->max_pwr; + wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +static void +tgt_mc_cp_stats_extract_vdev_and_extd_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + int32_t max_pwr = 0; + struct wlan_objmgr_vdev *vdev = NULL; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_CONNECTION_TX_POWER, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + if (ev->pdev_stats) + tgt_mc_cp_stats_extract_tx_power(psoc, ev, false); + else if (ev->vdev_extd_stats) + tgt_mc_cp_stats_extract_vdev_extd_stats(psoc, ev); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, last_req.vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) { + cp_stats_err("vdev is null"); + return; + } + tgt_mc_cp_stats_get_tx_power(vdev, &max_pwr); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + + if (tgt_mc_cp_stats_is_last_event(ev, TYPE_CONNECTION_TX_POWER)) { + ucfg_mc_cp_stats_reset_pending_req(psoc, + TYPE_CONNECTION_TX_POWER, + &last_req, + &pending); + if (last_req.u.get_tx_power_cb && pending) + last_req.u.get_tx_power_cb(max_pwr, last_req.cookie); + } +} + +static void +tgt_mc_cp_stats_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, + struct request_info *last_req) +{ + /* station_stats to be given to userspace thread */ + struct stats_event info = {0}; + void (*get_station_stats_cb)(struct stats_event *info, void *cookie); + QDF_STATUS status; + + get_station_stats_cb = last_req->u.get_station_stats_cb; + if (!get_station_stats_cb) { + cp_stats_err("callback is null"); + return; + } + + info.num_summary_stats = 1; + info.num_chain_rssi_stats = 1; + info.num_vdev_extd_stats = 1; + info.vdev_summary_stats = qdf_mem_malloc( + sizeof(*info.vdev_summary_stats)); + info.vdev_chain_rssi = qdf_mem_malloc(sizeof(*info.vdev_chain_rssi)); + + info.vdev_extd_stats = qdf_mem_malloc(sizeof(*info.vdev_extd_stats)); + + if (!info.vdev_summary_stats || !info.vdev_chain_rssi || + !info.vdev_extd_stats) + goto end; + + status = tgt_send_vdev_mc_cp_stats(psoc, &info, last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("tgt_send_vdev_mc_cp_stats failed"); + goto end; + } + + info.peer_adv_stats = qdf_mem_malloc(sizeof(*info.peer_adv_stats)); + if (!info.peer_adv_stats) + goto end; + + status = tgt_send_peer_mc_cp_stats(psoc, &info, last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("tgt_send_peer_mc_cp_stats failed"); + goto end; + } + + info.num_pdev_stats = 1; + info.pdev_stats = qdf_mem_malloc(sizeof(*info.pdev_stats)); + if (!info.pdev_stats) + goto end; + + status = tgt_send_pdev_mc_cp_stats(psoc, &info, last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("tgt_send_pdev_mc_cp_stats failed"); + goto end; + } +end: + get_station_stats_cb(&info, last_req->cookie); + + ucfg_mc_cp_stats_free_stats_resources(&info); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +tgt_mc_cp_stats_prepare_n_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, + struct request_info *last_req) +{ + uint8_t i; + + if (!last_req->ml_vdev_info.ml_vdev_count) { + cp_stats_nofl_debug("Invoking get_station_cb for vdev_id[%d]", + last_req->vdev_id); + tgt_mc_cp_stats_send_raw_station_stats(psoc, last_req); + return; + } + + for (i = 0; i < last_req->ml_vdev_info.ml_vdev_count; i++) { + last_req->vdev_id = last_req->ml_vdev_info.ml_vdev_id[i]; + qdf_mem_copy(last_req->peer_mac_addr, + &(last_req->ml_peer_mac_addr[i][0]), + QDF_MAC_ADDR_SIZE); + cp_stats_nofl_debug("Invoking get_station_cb for ml vdev_id[%d]", + last_req->vdev_id); + tgt_mc_cp_stats_send_raw_station_stats(psoc, last_req); + } +} +#else +static void +tgt_mc_cp_stats_prepare_n_send_raw_station_stats(struct wlan_objmgr_psoc *psoc, + struct request_info *last_req) +{ + tgt_mc_cp_stats_send_raw_station_stats(psoc, last_req); +} +#endif + +static void tgt_mc_cp_stats_extract_station_stats( + struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_STATION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + tgt_mc_cp_stats_extract_tx_power(psoc, ev, true); + tgt_mc_cp_stats_extract_peer_stats(psoc, ev, true); + tgt_mc_cp_stats_extract_vdev_summary_stats(psoc, ev); + tgt_mc_cp_stats_extract_vdev_chain_rssi_stats(psoc, ev); + tgt_mc_cp_stats_extract_pmf_bcn_stats(psoc, ev); + tgt_mc_cp_stats_extract_vdev_extd_stats(psoc, ev); + + /* + * PEER stats are the last stats sent for get_station statistics. + * reset type_map bit for station stats . + */ + if (tgt_mc_cp_stats_is_last_event(ev, TYPE_STATION_STATS)) { + ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS, + &last_req, + &pending); + if (pending && last_req.u.get_station_stats_cb) + tgt_mc_cp_stats_prepare_n_send_raw_station_stats( + psoc, &last_req); + } +} + +static void tgt_mc_cp_send_lost_link_stats(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (psoc_cp_stats_priv && psoc_cp_stats_priv->legacy_stats_cb) + psoc_cp_stats_priv->legacy_stats_cb(ev); +} + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +QDF_STATUS tgt_mc_cp_stats_process_infra_stats_event( + struct wlan_objmgr_psoc *psoc, + struct infra_cp_stats_event *infra_event) +{ + if (!infra_event) + return QDF_STATUS_E_NULL_VALUE; + + tgt_mc_infra_cp_stats_extract_twt_stats(psoc, infra_event); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS tgt_mc_cp_stats_process_stats_event(struct wlan_objmgr_psoc *psoc, + struct stats_event *ev) +{ + if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_CONNECTION_TX_POWER)) + tgt_mc_cp_stats_extract_vdev_and_extd_stats(psoc, ev); + + if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_PEER_STATS)) + tgt_mc_cp_stats_extract_peer_stats(psoc, ev, false); + + if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_STATION_STATS)) + tgt_mc_cp_stats_extract_station_stats(psoc, ev); + + if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_MIB_STATS)) + tgt_mc_cp_stats_extract_mib_stats(psoc, ev); + + if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_PEER_STATS_INFO_EXT)) + tgt_mc_cp_stats_extract_peer_stats_info_ext(psoc, ev); + + if (ucfg_mc_cp_stats_is_req_pending(psoc, TYPE_CONGESTION_STATS)) + tgt_mc_cp_stats_extract_congestion_stats(psoc, ev); + + tgt_mc_cp_stats_extract_cca_stats(psoc, ev); + + tgt_mc_cp_send_lost_link_stats(psoc, ev); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +QDF_STATUS +tgt_mc_cp_stats_process_big_data_stats_event(struct wlan_objmgr_psoc *psoc, + struct big_data_stats_event *ev) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + + if (!ev) { + cp_stats_err("invalid data"); + return QDF_STATUS_E_INVAL; + } + + status = ucfg_mc_cp_stats_get_pending_req(psoc, + TYPE_BIG_DATA_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_get_pending_req failed"); + return QDF_STATUS_E_FAILURE; + } + + ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_BIG_DATA_STATS, + &last_req, &pending); + + if (last_req.u.get_big_data_stats_cb && pending) { + last_req.u.get_big_data_stats_cb(ev, last_req.cookie); + last_req.u.get_big_data_stats_cb = NULL; + } else { + cp_stats_err("callback to send big data stats not found"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS tgt_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc, + uint32_t reason, + struct wake_lock_stats *stats, + uint32_t *unspecified_wake_count) +{ + struct wlan_lmac_if_cp_stats_tx_ops *tx_ops; + + tx_ops = target_if_cp_stats_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->inc_wake_lock_stats) + return QDF_STATUS_E_NULL_VALUE; + + tx_ops->inc_wake_lock_stats(reason, stats, unspecified_wake_count); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_send_mc_cp_stats_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *req) +{ + struct wlan_lmac_if_cp_stats_tx_ops *tx_ops; + QDF_STATUS status; + + tx_ops = target_if_cp_stats_get_tx_ops(psoc); + if (!tx_ops) { + cp_stats_err("could not get tx_ops"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (type) { + case TYPE_PEER_STATS_INFO_EXT: + if (!tx_ops->send_req_peer_stats) { + cp_stats_err("could not get send_req_peer_stats"); + return QDF_STATUS_E_NULL_VALUE; + } + status = tx_ops->send_req_peer_stats(psoc, req); + break; + case TYPE_BIG_DATA_STATS: + status = send_big_data_stats_req(tx_ops, psoc, req); + break; + default: + if (!tx_ops->send_req_stats) { + cp_stats_err("could not get send_req_stats"); + return QDF_STATUS_E_NULL_VALUE; + } + status = tx_ops->send_req_stats(psoc, type, req); + } + + return status; +} + +QDF_STATUS tgt_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t val) +{ + struct wlan_lmac_if_cp_stats_tx_ops *tx_ops; + QDF_STATUS status; + + tx_ops = target_if_cp_stats_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->set_pdev_stats_update_period) { + cp_stats_err("could not get tx_ops"); + return QDF_STATUS_E_NULL_VALUE; + } + status = tx_ops->set_pdev_stats_update_period(psoc, pdev_id, val); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c new file mode 100644 index 0000000000..5381b99a95 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c @@ -0,0 +1,1460 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cp_stats_mc_ucfg_api.c + * + * This file provide API definitions required for northbound interaction + */ + +#include +#include "wlan_cp_stats_mc_defs.h" +#include +#include +#include +#include "../../core/src/wlan_cp_stats_defs.h" +#include "../../core/src/wlan_cp_stats_cmn_api_i.h" +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD +#include +#endif +#ifdef WLAN_SUPPORT_TWT +#include +#endif +#include + +#ifdef WLAN_SUPPORT_TWT + +/** + * ucfg_twt_get_peer_session_param_by_dlg_id() - Finds a Peer twt session with + * dialog id matching with input dialog id. If a match is found copies + * the twt session parameters + * @mc_stats: pointer to peer specific stats + * @input_dialog_id: input dialog id + * @dest_param: Pointer to copy twt session parameters when a peer with + * given dialog id is found + * @num_twt_session: Pointer holding total number of valid twt session + * + * Return: Success if stats are copied for a peer with given dialog, + * else failure + */ +static QDF_STATUS +ucfg_twt_get_peer_session_param_by_dlg_id(struct peer_mc_cp_stats *mc_stats, + uint32_t input_dialog_id, + struct wmi_host_twt_session_stats_info + *dest_param, int *num_twt_session) +{ + struct wmi_host_twt_session_stats_info *src_param; + uint32_t event_type; + int i = 0; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + + if (!mc_stats || !dest_param) + return qdf_status; + + for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { + event_type = mc_stats->twt_param[i].event_type; + + src_param = &mc_stats->twt_param[i]; + if (!event_type || + (src_param->dialog_id != input_dialog_id && + input_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID)) + continue; + + if ((event_type == HOST_TWT_SESSION_SETUP) || + (event_type == HOST_TWT_SESSION_UPDATE)) { + qdf_mem_copy(&dest_param[*num_twt_session], src_param, + sizeof(*src_param)); + qdf_status = QDF_STATUS_SUCCESS; + *num_twt_session += 1; + if (*num_twt_session >= TWT_PEER_MAX_SESSIONS) + break; + } + } + + return qdf_status; +} + +/** + * ucfg_twt_get_single_peer_session_params()- Extracts twt session parameters + * corresponding to a peer given by dialog_id + * @psoc_obj: psoc object + * @mac_addr: mac addr of peer + * @dialog_id: dialog id of peer for which twt session params to be retrieved + * @params: pointer to store peer twt session parameters + * + * Return: total number of valid twt session + */ +static int +ucfg_twt_get_single_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, + uint8_t *mac_addr, uint32_t dialog_id, + struct wmi_host_twt_session_stats_info + *params) +{ + struct wlan_objmgr_peer *peer; + struct peer_cp_stats *peer_cp_stats_priv; + struct peer_mc_cp_stats *peer_mc_stats; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + int num_twt_session = 0; + + if (!psoc_obj || !params) + return num_twt_session; + + peer = wlan_objmgr_get_peer_by_mac(psoc_obj, mac_addr, + WLAN_CP_STATS_ID); + if (!peer) + return num_twt_session; + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer); + if (!peer_cp_stats_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + return num_twt_session; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + peer_mc_stats = peer_cp_stats_priv->peer_stats; + + qdf_status = ucfg_twt_get_peer_session_param_by_dlg_id( + peer_mc_stats, + dialog_id, + params, + &num_twt_session); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + qdf_err("No TWT session for " QDF_MAC_ADDR_FMT " dialog_id %d", + QDF_MAC_ADDR_REF(mac_addr), dialog_id); + } + + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return num_twt_session; +} + +/** + * ucfg_twt_get_peer_session_param() - Obtains twt session parameters of + * a peer if twt session is valid + * @mc_cp_stats: pointer to peer specific stats + * @params: Pointer to copy twt session parameters + * @num_twt_session: Pointer holding total number of valid twt sessions + * + * Return: QDF_STATUS success if valid twt session parameters are obtained + * else other qdf error values + */ +static QDF_STATUS +ucfg_twt_get_peer_session_param(struct peer_mc_cp_stats *mc_cp_stats, + struct wmi_host_twt_session_stats_info *params, + int *num_twt_session) +{ + struct wmi_host_twt_session_stats_info *twt_params; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + uint32_t event_type; + int i; + + if (!mc_cp_stats || !params) + return qdf_status; + + for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { + twt_params = &mc_cp_stats->twt_param[i]; + event_type = mc_cp_stats->twt_param[i].event_type; + + /* Check twt session is established */ + if ((event_type == HOST_TWT_SESSION_SETUP) || + (event_type == HOST_TWT_SESSION_UPDATE)) { + qdf_mem_copy(¶ms[*num_twt_session], twt_params, + sizeof(*twt_params)); + qdf_status = QDF_STATUS_SUCCESS; + *num_twt_session += 1; + } + } + return qdf_status; +} + +/** + * ucfg_twt_get_all_peer_session_params()- Retrieves twt session parameters + * of all peers with valid twt session + * @psoc_obj: psoc object + * @vdev_id: vdev_id + * @params: array of pointer to store peer twt session parameters + * + * Return: total number of valid twt sessions + */ +static int +ucfg_twt_get_all_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, + uint8_t vdev_id, + struct wmi_host_twt_session_stats_info + *params) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct peer_cp_stats *cp_stats_peer_obj, *peer_cp_stat_prv; + struct peer_mc_cp_stats *mc_cp_stats; + int num_twt_session = 0; + enum QDF_OPMODE opmode; + int sap_max_peer = 0; + + if (!psoc_obj) { + cp_stats_err("psoc is NULL"); + return num_twt_session; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc_obj, vdev_id, + WLAN_CP_STATS_ID); + + if (!vdev) { + cp_stats_err("vdev is NULL, vdev_id: %d", vdev_id); + return num_twt_session; + } + + wlan_mlme_get_sap_max_peers(psoc_obj, &sap_max_peer); + opmode = wlan_vdev_mlme_get_opmode(vdev); + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + cp_stats_err("Peer list for vdev obj is NULL"); + return num_twt_session; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_CP_STATS_ID); + + while (peer) { + cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj( + peer, WLAN_UMAC_COMP_CP_STATS); + + mc_cp_stats = NULL; + if (cp_stats_peer_obj) + mc_cp_stats = cp_stats_peer_obj->peer_stats; + + peer_cp_stat_prv = + wlan_cp_stats_get_peer_stats_obj(peer); + + if (peer_cp_stat_prv && mc_cp_stats) { + wlan_cp_stats_peer_obj_lock(peer_cp_stat_prv); + ucfg_twt_get_peer_session_param(mc_cp_stats, + params, + &num_twt_session); + wlan_cp_stats_peer_obj_unlock(peer_cp_stat_prv); + } + + if (opmode == QDF_STA_MODE && + num_twt_session >= TWT_PEER_MAX_SESSIONS) { + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + goto done; + } + + if (opmode == QDF_SAP_MODE && + num_twt_session >= (sap_max_peer * TWT_PEER_MAX_SESSIONS)) { + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + goto done; + } + + peer_next = wlan_peer_get_next_active_peer_of_vdev( + vdev, peer_list, peer, + WLAN_CP_STATS_ID); + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + peer = peer_next; + } + +done: + if (!num_twt_session) + cp_stats_err("Unable to find a peer with twt session established"); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return num_twt_session; +} + +int +ucfg_twt_get_peer_session_params(struct wlan_objmgr_psoc *psoc_obj, + struct wmi_host_twt_session_stats_info *params) +{ + uint8_t *mac_addr; + uint32_t dialog_id; + uint8_t vdev_id; + int num_twt_session = 0; + + if (!psoc_obj || !params) + return num_twt_session; + + mac_addr = params[0].peer_mac; + dialog_id = params[0].dialog_id; + vdev_id = params[0].vdev_id; + + /* + * Currently for STA case, twt_get_params nl is sending only dialog_id + * and mac_addr is being filled by driver in STA peer case. + * For SAP case, twt_get_params nl is sending dialog_id and + * peer mac_addr. When twt_get_params add mac_addr and dialog_id of + * STA/SAP, we need handle unicast/multicast macaddr in + * ucfg_twt_get_peer_session_params. + */ + if (!QDF_IS_ADDR_BROADCAST(mac_addr)) + num_twt_session = ucfg_twt_get_single_peer_session_params( + psoc_obj, + mac_addr, + dialog_id, + params); + else + num_twt_session = ucfg_twt_get_all_peer_session_params( + psoc_obj, + vdev_id, + params); + + return num_twt_session; +} +#endif /* WLAN_SUPPORT_TWT */ + +QDF_STATUS wlan_cp_stats_psoc_cs_init(struct psoc_cp_stats *psoc_cs) +{ + psoc_cs->obj_stats = qdf_mem_malloc(sizeof(struct psoc_mc_cp_stats)); + if (!psoc_cs->obj_stats) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_psoc_cs_deinit(struct psoc_cp_stats *psoc_cs) +{ + qdf_mem_free(psoc_cs->obj_stats); + psoc_cs->obj_stats = NULL; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_vdev_cs_init(struct vdev_cp_stats *vdev_cs) +{ + vdev_cs->vdev_stats = qdf_mem_malloc(sizeof(struct vdev_mc_cp_stats)); + if (!vdev_cs->vdev_stats) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_vdev_cs_deinit(struct vdev_cp_stats *vdev_cs) +{ + qdf_mem_free(vdev_cs->vdev_stats); + vdev_cs->vdev_stats = NULL; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_pdev_cs_init(struct pdev_cp_stats *pdev_cs) +{ + pdev_cs->pdev_stats = qdf_mem_malloc(sizeof(struct pdev_mc_cp_stats)); + if (!pdev_cs->pdev_stats) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_pdev_cs_deinit(struct pdev_cp_stats *pdev_cs) +{ + qdf_mem_free(pdev_cs->pdev_stats); + pdev_cs->pdev_stats = NULL; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_peer_cs_init(struct peer_cp_stats *peer_cs) +{ + struct peer_mc_cp_stats *peer_mc_stats; + + peer_mc_stats = qdf_mem_malloc(sizeof(struct peer_mc_cp_stats)); + if (!peer_mc_stats) + return QDF_STATUS_E_NOMEM; + + peer_mc_stats->adv_stats = + qdf_mem_malloc(sizeof(struct peer_adv_mc_cp_stats)); + + if (!peer_mc_stats->adv_stats) { + qdf_mem_free(peer_mc_stats); + peer_mc_stats = NULL; + return QDF_STATUS_E_NOMEM; + } + + peer_mc_stats->extd_stats = + qdf_mem_malloc(sizeof(struct peer_extd_stats)); + + if (!peer_mc_stats->extd_stats) { + qdf_mem_free(peer_mc_stats->adv_stats); + peer_mc_stats->adv_stats = NULL; + qdf_mem_free(peer_mc_stats); + peer_mc_stats = NULL; + return QDF_STATUS_E_NOMEM; + } + peer_cs->peer_stats = peer_mc_stats; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cp_stats_peer_cs_deinit(struct peer_cp_stats *peer_cs) +{ + struct peer_mc_cp_stats *peer_mc_stats = peer_cs->peer_stats; + + qdf_mem_free(peer_mc_stats->adv_stats); + peer_mc_stats->adv_stats = NULL; + qdf_mem_free(peer_mc_stats->extd_stats); + peer_mc_stats->extd_stats = NULL; + qdf_mem_free(peer_cs->peer_stats); + peer_cs->peer_stats = NULL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum qdf_proto_subtype protocol) +{ + struct wake_lock_stats *stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + struct psoc_mc_cp_stats *psoc_mc_stats; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + + if (!psoc_mc_stats) { + cp_stats_err("psoc mc stats is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + stats = &psoc_mc_stats->wow_stats; + switch (protocol) { + case QDF_PROTO_ICMP_REQ: + case QDF_PROTO_ICMP_RES: + stats->icmpv4_count++; + break; + case QDF_PROTO_ICMPV6_REQ: + case QDF_PROTO_ICMPV6_RES: + case QDF_PROTO_ICMPV6_RS: + stats->icmpv6_count++; + break; + case QDF_PROTO_ICMPV6_RA: + stats->icmpv6_count++; + stats->ipv6_mcast_ra_stats++; + break; + case QDF_PROTO_ICMPV6_NS: + stats->icmpv6_count++; + stats->ipv6_mcast_ns_stats++; + break; + case QDF_PROTO_ICMPV6_NA: + stats->icmpv6_count++; + stats->ipv6_mcast_na_stats++; + break; + default: + break; + } + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *dest_mac) +{ + struct psoc_cp_stats *psoc_cp_stats_priv; + struct psoc_mc_cp_stats *psoc_mc_stats; + struct wake_lock_stats *stats; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + if (!psoc_mc_stats) { + cp_stats_err("psoc mc stats is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + stats = &psoc_mc_stats->wow_stats; + + switch (*dest_mac) { + case QDF_BCAST_MAC_ADDR: + stats->bcast_wake_up_count++; + break; + case QDF_MCAST_IPV4_MAC_ADDR: + stats->ipv4_mcast_wake_up_count++; + break; + case QDF_MCAST_IPV6_MAC_ADDR: + stats->ipv6_mcast_wake_up_count++; + break; + default: + stats->ucast_wake_up_count++; + break; + } + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_inc_wake_lock_stats(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t reason) +{ + struct wake_lock_stats *stats; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + + if (!psoc_mc_stats) { + cp_stats_err("psoc mc stats is null"); + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + return QDF_STATUS_E_NULL_VALUE; + } + + stats = &psoc_mc_stats->wow_stats; + + status = tgt_mc_cp_stats_inc_wake_lock_stats(psoc, reason, stats, + &psoc_mc_stats->wow_unspecified_wake_up_count); + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return status; +} + +/** + * vdev_iterator() - iterator function to collect wake_lock_stats from all vdev + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @arg: stats object pointer passed as arg + * + * Return - none + */ +static void vdev_iterator(struct wlan_objmgr_psoc *psoc, void *vdev, void *arg) +{ + struct wake_lock_stats *vdev_stats; + struct wake_lock_stats *stats = arg; + struct psoc_cp_stats *psoc_cp_stats_priv; + struct psoc_mc_cp_stats *psoc_mc_stats; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return; + } + + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + if (!psoc_mc_stats) { + cp_stats_err("psoc mc stats is null"); + return; + } + + vdev_stats = &psoc_mc_stats->wow_stats; + + stats->ucast_wake_up_count += vdev_stats->ucast_wake_up_count; + stats->bcast_wake_up_count += vdev_stats->bcast_wake_up_count; + stats->ipv4_mcast_wake_up_count += vdev_stats->ipv4_mcast_wake_up_count; + stats->ipv6_mcast_wake_up_count += vdev_stats->ipv6_mcast_wake_up_count; + stats->ipv6_mcast_ra_stats += vdev_stats->ipv6_mcast_ra_stats; + stats->ipv6_mcast_ns_stats += vdev_stats->ipv6_mcast_ns_stats; + stats->ipv6_mcast_na_stats += vdev_stats->ipv6_mcast_na_stats; + stats->icmpv4_count += vdev_stats->icmpv4_count; + stats->icmpv6_count += vdev_stats->icmpv6_count; + stats->rssi_breach_wake_up_count += + vdev_stats->rssi_breach_wake_up_count; + stats->low_rssi_wake_up_count += vdev_stats->low_rssi_wake_up_count; + stats->gscan_wake_up_count += vdev_stats->gscan_wake_up_count; + stats->pno_complete_wake_up_count += + vdev_stats->pno_complete_wake_up_count; + stats->pno_match_wake_up_count += vdev_stats->pno_match_wake_up_count; + stats->oem_response_wake_up_count += + vdev_stats->oem_response_wake_up_count; + stats->uc_drop_wake_up_count += vdev_stats->uc_drop_wake_up_count; + stats->fatal_event_wake_up_count += + vdev_stats->fatal_event_wake_up_count; + stats->pwr_save_fail_detected += vdev_stats->pwr_save_fail_detected; + stats->scan_11d += vdev_stats->scan_11d; +} + +QDF_STATUS ucfg_mc_cp_stats_get_psoc_wake_lock_stats( + struct wlan_objmgr_psoc *psoc, + struct wake_lock_stats *stats) +{ + struct psoc_cp_stats *psoc_cp_stats_priv; + struct psoc_mc_cp_stats *psoc_mc_stats; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + /* iterate through all vdevs, and get wow stats from vdev_cs object */ + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, vdev_iterator, + stats, true, WLAN_CP_STATS_ID); + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_get_vdev_wake_lock_stats( + struct wlan_objmgr_vdev *vdev, + struct wake_lock_stats *stats) +{ + struct wlan_objmgr_psoc *psoc; + struct psoc_cp_stats *psoc_cp_stats_priv; + struct psoc_mc_cp_stats *psoc_mc_stats; + + wlan_vdev_obj_lock(vdev); + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + wlan_vdev_obj_unlock(vdev); + cp_stats_err("psoc NULL"); + return QDF_STATUS_E_INVAL; + } + wlan_vdev_obj_unlock(vdev); + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + + if (!psoc_mc_stats) { + cp_stats_err("psoc mc stats is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_mem_copy(stats, &psoc_mc_stats->wow_stats, sizeof(*stats)); + + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_write_wow_stats( + struct wlan_objmgr_psoc *psoc, + char *buffer, uint16_t max_len, int *ret) +{ + QDF_STATUS status; + uint32_t unspecified_wake_count; + struct wake_lock_stats wow_stats = {0}; + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* get stats from psoc */ + status = ucfg_mc_cp_stats_get_psoc_wake_lock_stats(psoc, &wow_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("Failed to get WoW stats"); + return status; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + unspecified_wake_count = psoc_mc_stats->wow_unspecified_wake_up_count; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + *ret = qdf_scnprintf(buffer, max_len, + "WoW Wake Reasons\n" + "\tunspecified wake count: %u\n" + "\tunicast: %u\n" + "\tbroadcast: %u\n" + "\tIPv4 multicast: %u\n" + "\tIPv6 multicast: %u\n" + "\tIPv6 multicast RA: %u\n" + "\tIPv6 multicast NS: %u\n" + "\tIPv6 multicast NA: %u\n" + "\tICMPv4: %u\n" + "\tICMPv6: %u\n" + "\tRSSI Breach: %u\n" + "\tLow RSSI: %u\n" + "\tG-Scan: %u\n" + "\tPNO Complete: %u\n" + "\tPNO Match: %u\n" + "\tUC Drop wake_count: %u\n" + "\twake count due to fatal event: %u\n" + "\tOEM rsp wake_count: %u\n" + "\twake count due to pwr_save_fail_detected: %u\n" + "\twake count due to 11d scan: %u\n", + unspecified_wake_count, + wow_stats.ucast_wake_up_count, + wow_stats.bcast_wake_up_count, + wow_stats.ipv4_mcast_wake_up_count, + wow_stats.ipv6_mcast_wake_up_count, + wow_stats.ipv6_mcast_ra_stats, + wow_stats.ipv6_mcast_ns_stats, + wow_stats.ipv6_mcast_na_stats, + wow_stats.icmpv4_count, + wow_stats.icmpv6_count, + wow_stats.rssi_breach_wake_up_count, + wow_stats.low_rssi_wake_up_count, + wow_stats.gscan_wake_up_count, + wow_stats.pno_complete_wake_up_count, + wow_stats.pno_match_wake_up_count, + wow_stats.uc_drop_wake_up_count, + wow_stats.fatal_event_wake_up_count, + wow_stats.oem_response_wake_up_count, + wow_stats.pwr_save_fail_detected, + wow_stats.scan_11d); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_send_stats_request(struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info) +{ + QDF_STATUS status; + + status = ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev), + type, info); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_set_pending_req pdev failed: %d", + status); + return status; + } + + return tgt_send_mc_cp_stats_req(wlan_vdev_get_psoc(vdev), type, info); +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +QDF_STATUS ucfg_send_big_data_stats_request(struct wlan_objmgr_vdev *vdev, + enum stats_req_type type, + struct request_info *info) +{ + QDF_STATUS status; + + status = ucfg_mc_cp_stats_set_pending_req(wlan_vdev_get_psoc(vdev), + type, info); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("ucfg_mc_cp_stats_set_pending_req pdev failed: %d", + status); + return status; + } + return tgt_send_mc_cp_stats_req(wlan_vdev_get_psoc(vdev), type, info); +} + +void ucfg_mc_cp_set_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool enable) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + psoc_mc_stats->big_data_fw_support_enable = enable; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); +} + +void ucfg_mc_cp_get_big_data_fw_support(struct wlan_objmgr_psoc *psoc, + bool *enable) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + *enable = psoc_mc_stats->big_data_fw_support_enable; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); +} +#endif + +QDF_STATUS ucfg_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, + int *dbm) +{ + struct wlan_objmgr_pdev *pdev; + struct pdev_mc_cp_stats *pdev_mc_stats; + struct pdev_cp_stats *pdev_cp_stats_priv; + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stat; + uint32_t vdev_power = 0; + + vdev_cp_stat = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (vdev_cp_stat) { + wlan_cp_stats_vdev_obj_lock(vdev_cp_stat); + vdev_mc_stats = vdev_cp_stat->vdev_stats; + vdev_power = vdev_mc_stats->vdev_extd_stats.vdev_tx_power; + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stat); + if (vdev_power) { + *dbm = vdev_power; + return QDF_STATUS_SUCCESS; + } + } + + pdev = wlan_vdev_get_pdev(vdev); + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_pdev_obj_lock(pdev_cp_stats_priv); + pdev_mc_stats = pdev_cp_stats_priv->pdev_stats; + *dbm = pdev_mc_stats->max_pwr; + wlan_cp_stats_pdev_obj_unlock(pdev_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_mc_cp_stats_is_req_pending(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type) +{ + uint32_t pending_req_map; + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return false; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + pending_req_map = psoc_mc_stats->pending.type_map; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return (pending_req_map & (1 << type)); +} + +QDF_STATUS ucfg_mc_cp_stats_set_pending_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *req) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (type >= TYPE_MAX) { + cp_stats_err("Invalid type index: %d", type); + return QDF_STATUS_E_INVAL; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + if (psoc_mc_stats->is_cp_stats_suspended) { + cp_stats_debug("cp stats is suspended try again after resume"); + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + return QDF_STATUS_E_AGAIN; + } + psoc_mc_stats->pending.type_map |= (1 << type); + psoc_mc_stats->pending.req[type] = *req; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_reset_pending_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *last_req, + bool *pending) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (type >= TYPE_MAX) { + cp_stats_err("Invalid type index: %d", type); + return QDF_STATUS_E_INVAL; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + if (psoc_mc_stats->pending.type_map & (1 << type)) { + *last_req = psoc_mc_stats->pending.req[type]; + *pending = true; + } else { + *pending = false; + } + psoc_mc_stats->pending.type_map &= ~(1 << type); + qdf_mem_zero(&psoc_mc_stats->pending.req[type], + sizeof(psoc_mc_stats->pending.req[type])); + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_get_pending_req(struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *info) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (type >= TYPE_MAX) { + cp_stats_err("Invalid type index: %d", type); + return QDF_STATUS_E_INVAL; + } + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + *info = psoc_mc_stats->pending.req[type]; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_mc_cp_stats_free_peer_stats_info_ext() - API to free peer stats info ext + * structure + * @ev: structure from where peer stats info ext needs to be freed + * + * Return: none + */ +static void ucfg_mc_cp_stats_free_peer_stats_info_ext(struct stats_event *ev) +{ + struct peer_stats_info_ext_event *peer_stats_info = + ev->peer_stats_info_ext; + uint16_t i; + + for (i = 0; i < ev->num_peer_stats_info_ext; i++) { + qdf_mem_free(peer_stats_info->tx_pkt_per_mcs); + qdf_mem_free(peer_stats_info->rx_pkt_per_mcs); + peer_stats_info++; + } + + qdf_mem_free(ev->peer_stats_info_ext); +} + +void ucfg_mc_cp_stats_free_stats_resources(struct stats_event *ev) +{ + if (!ev) + return; + + qdf_mem_free(ev->pdev_stats); + qdf_mem_free(ev->pdev_extd_stats); + qdf_mem_free(ev->peer_adv_stats); + qdf_mem_free(ev->peer_stats); + qdf_mem_free(ev->cca_stats); + qdf_mem_free(ev->vdev_summary_stats); + qdf_mem_free(ev->vdev_chain_rssi); + qdf_mem_free(ev->peer_extended_stats); + ucfg_mc_cp_stats_free_peer_stats_info_ext(ev); + qdf_mem_free(ev->vdev_extd_stats); + qdf_mem_zero(ev, sizeof(*ev)); +} + +QDF_STATUS ucfg_mc_cp_stats_cca_stats_get(struct wlan_objmgr_vdev *vdev, + struct cca_stats *cca_stats) +{ + struct vdev_cp_stats *vdev_cp_stats_priv; + struct vdev_mc_cp_stats *vdev_mc_stats; + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + cca_stats->congestion = vdev_mc_stats->cca.congestion; + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mc_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev, + uint32_t flags) +{ + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + vdev_mc_stats->tx_rate_flags = flags; + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_mc_cp_stats_register_lost_link_info_cb( + struct wlan_objmgr_psoc *psoc, + void (*lost_link_cp_stats_info_cb)(void *stats_ev)) +{ + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return; + } + + psoc_cp_stats_priv->legacy_stats_cb = lost_link_cp_stats_info_cb; +} + +#ifdef QCA_SUPPORT_CP_STATS +uint8_t wlan_cp_stats_get_rx_clear_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, qdf_freq_t req_freq) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + struct pdev_cp_stats *pdev_cp_stats_priv; + struct per_channel_stats *channel_stats; + struct channel_status *channel_status_list; + uint8_t total_channel, chan_load = 0; + uint8_t i; + uint32_t rx_clear_count = 0, cycle_count = 0; + bool found = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) + return 0; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + cp_stats_err("pdev object is null"); + goto release_ref; + } + + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev cp stats object is null"); + goto release_ref; + } + + channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; + channel_status_list = channel_stats->channel_status_list; + total_channel = channel_stats->total_channel; + + for (i = 0; i < total_channel; i++) { + if (channel_status_list[i].channel_freq == req_freq) { + rx_clear_count = channel_status_list[i].rx_clear_count; + cycle_count = channel_status_list[i].cycle_count; + found = true; + break; + } + } + + if (!found) { + cp_stats_debug("no channel found for freq:%d", req_freq); + goto release_ref; + } + + if (cycle_count == 0) { + cp_stats_debug("cycle_count is zero"); + goto release_ref; + } + + chan_load = ((rx_clear_count * 255) / cycle_count); + + cp_stats_debug("t_chan:%d, freq:%d, rcc:%u, cc:%u, chan_load:%d", + total_channel, req_freq, rx_clear_count, cycle_count, + chan_load); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return chan_load; +} +#endif + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD +static QDF_STATUS +ucfg_mc_cp_stats_suspend_req_handler(struct wlan_objmgr_psoc *psoc) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + psoc_mc_stats->is_cp_stats_suspended = true; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ucfg_mc_cp_stats_resume_req_handler(struct wlan_objmgr_psoc *psoc) +{ + struct psoc_mc_cp_stats *psoc_mc_stats; + struct psoc_cp_stats *psoc_cp_stats_priv; + + psoc_cp_stats_priv = wlan_cp_stats_get_psoc_stats_obj(psoc); + if (!psoc_cp_stats_priv) { + cp_stats_err("psoc cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_psoc_obj_lock(psoc_cp_stats_priv); + psoc_mc_stats = psoc_cp_stats_priv->obj_stats; + psoc_mc_stats->is_cp_stats_suspended = false; + wlan_cp_stats_psoc_obj_unlock(psoc_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ucfg_mc_cp_stats_resume_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + return ucfg_mc_cp_stats_resume_req_handler(psoc); +} + +static QDF_STATUS +ucfg_mc_cp_stats_suspend_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + return ucfg_mc_cp_stats_suspend_req_handler(psoc); +} + +void ucfg_mc_cp_stats_register_pmo_handler(void) +{ + pmo_register_suspend_handler(WLAN_UMAC_COMP_CP_STATS, + ucfg_mc_cp_stats_suspend_handler, NULL); + pmo_register_resume_handler(WLAN_UMAC_COMP_CP_STATS, + ucfg_mc_cp_stats_resume_handler, NULL); +} + +/** + * wlan_cp_stats_get_ch_width_from_chan_info - get ch_width as per num channel + * present in scan event + * @channel_stat: struct scan_chan_info + * + * Return: phy_ch_width. + */ +static enum phy_ch_width +wlan_cp_stats_get_ch_width_from_chan_info(struct channel_status *channel_stat) +{ + enum phy_ch_width scanned_ch_width; + + switch (channel_stat->subband_info.num_chan) { + case 1: + scanned_ch_width = CH_WIDTH_20MHZ; + break; + case 2: + scanned_ch_width = CH_WIDTH_40MHZ; + break; + case 4: + scanned_ch_width = CH_WIDTH_80MHZ; + break; + case 8: + scanned_ch_width = CH_WIDTH_160MHZ; + break; + default: + scanned_ch_width = CH_WIDTH_INVALID; + break; + } + + return scanned_ch_width; +} + +/** + * wlan_cp_stats_update_per_channel_stats - update per channel stats as per + * data present in scan event + * @channel_stats: per channel stats + * @ev_channel_stat: channel stats per scan event + * @freq: freq to update channel stats + * @rx_clear_count: rx clear count for a freq + * + * Return: none. + */ +static void +wlan_cp_stats_update_per_channel_stats(struct per_channel_stats *channel_stats, + struct channel_status *ev_channel_stat, + uint32_t freq, uint32_t rx_clear_count) +{ + struct channel_status *channel_status_list; + uint8_t total_channel, i; + bool found = false; + + channel_status_list = channel_stats->channel_status_list; + total_channel = channel_stats->total_channel; + + for (i = 0; i < total_channel; i++) { + if (channel_status_list[i].channel_freq == freq) { + cp_stats_debug("update rcc: %d, cc:%d at index: %d, freq: %d", + ev_channel_stat->rx_clear_count, + ev_channel_stat->cycle_count, i, freq); + + channel_status_list[i].rx_clear_count = rx_clear_count; + channel_status_list[i].cycle_count = + ev_channel_stat->cycle_count; + found = true; + break; + } + } + + if (!found) { + if (total_channel < NUM_CHANNELS) { + ev_channel_stat->rx_clear_count = rx_clear_count; + ev_channel_stat->channel_freq = freq; + + cp_stats_debug("Add rcc: %d cc: %d, at index: %d, freq: %d", + ev_channel_stat->rx_clear_count, + ev_channel_stat->rx_clear_count, + total_channel, freq); + + qdf_mem_copy(&channel_status_list[total_channel++], + ev_channel_stat, + sizeof(*channel_status_list)); + channel_stats->total_channel = total_channel; + } else { + cp_stats_debug("Chan cnt exceed, channel_id: %d", + ev_channel_stat->channel_id); + } + } +} + +/** + * wlan_cp_stats_update_channel_stats - wrapper api to update per channel stats + * as per data present in scan event + * @channel_stats: per channel stats + * @ev_channel_stat: channel stats per scan event + * + * Return: none. + */ +static void +wlan_cp_stats_update_channel_stats(struct per_channel_stats *channel_stats, + struct channel_status *ev_channel_stat) +{ + uint8_t index, freq_info_num; + enum phy_ch_width scanned_ch_width; + const struct bonded_channel_freq *range = NULL; + uint16_t start_freq, end_freq; + uint32_t rx_clear_count; + + scanned_ch_width = + wlan_cp_stats_get_ch_width_from_chan_info(ev_channel_stat); + if (scanned_ch_width == CH_WIDTH_INVALID) { + cp_stats_debug("Invalid scanned_ch_width"); + return; + } + + if (scanned_ch_width == CH_WIDTH_20MHZ) { + start_freq = ev_channel_stat->channel_freq; + end_freq = ev_channel_stat->channel_freq; + } else { + range = + wlan_reg_get_bonded_chan_entry(ev_channel_stat->channel_freq, + scanned_ch_width, 0); + if (!range) { + cp_stats_debug("range is NULL for freq %d, ch_width %d", + ev_channel_stat->channel_freq, + scanned_ch_width); + return; + } + start_freq = range->start_freq; + end_freq = range->end_freq; + } + + freq_info_num = ev_channel_stat->subband_info.num_chan; + index = 0; + + cp_stats_debug("freq :%d bw %d, range [%d-%d], num_freq:%d", + ev_channel_stat->channel_freq, scanned_ch_width, + start_freq, end_freq, freq_info_num); + + for (; start_freq <= end_freq;) { + if (index >= freq_info_num || index >= MAX_WIDE_BAND_SCAN_CHAN) + break; + rx_clear_count = + ev_channel_stat->subband_info.cca_busy_subband_info[index]; + wlan_cp_stats_update_per_channel_stats(channel_stats, + ev_channel_stat, + start_freq, + rx_clear_count); + + start_freq += BW_20_MHZ; + index++; + } +} + +void wlan_cp_stats_update_chan_info(struct wlan_objmgr_psoc *psoc, + struct channel_status *ev_channel_stat, + uint8_t vdev_id) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + struct pdev_cp_stats *pdev_cp_stats_priv; + struct per_channel_stats *channel_stats; + struct channel_status *channel_status_list; + uint8_t total_channel; + uint8_t i; + bool found = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_CP_STATS_ID); + if (!vdev) + return; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + cp_stats_err("pdev object is null"); + return; + } + + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + cp_stats_err("pdev cp stats object is null"); + return; + } + + channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; + channel_status_list = channel_stats->channel_status_list; + total_channel = channel_stats->total_channel; + + if (ev_channel_stat->subband_info.is_wide_band_scan) { + wlan_cp_stats_update_channel_stats(channel_stats, + ev_channel_stat); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); + return; + } + + for (i = 0; i < total_channel; i++) { + if (channel_status_list[i].channel_id == + ev_channel_stat->channel_id) { + if (ev_channel_stat->cmd_flags == + WMI_CHAN_InFO_END_RESP && + channel_status_list[i].cmd_flags == + WMI_CHAN_InFO_START_RESP) { + /* adjust to delta value for counts */ + ev_channel_stat->rx_clear_count -= + channel_status_list[i].rx_clear_count; + ev_channel_stat->cycle_count -= + channel_status_list[i].cycle_count; + ev_channel_stat->rx_frame_count -= + channel_status_list[i].rx_frame_count; + ev_channel_stat->tx_frame_count -= + channel_status_list[i].tx_frame_count; + ev_channel_stat->bss_rx_cycle_count -= + channel_status_list[i].bss_rx_cycle_count; + } + qdf_mem_copy(&channel_status_list[i], ev_channel_stat, + sizeof(*channel_status_list)); + found = true; + break; + } + } + + if (!found) { + if (total_channel < NUM_CHANNELS) { + qdf_mem_copy(&channel_status_list[total_channel++], + ev_channel_stat, + sizeof(*channel_status_list)); + channel_stats->total_channel = total_channel; + } else { + cp_stats_err("Chan cnt exceed, channel_id=%d", + ev_channel_stat->channel_id); + } + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_CP_STATS_ID); +} + +struct channel_status * +ucfg_mc_cp_stats_get_channel_status(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq) +{ + struct pdev_cp_stats *pdev_cp_stats_priv; + struct per_channel_stats *channel_stats; + struct channel_status *entry; + uint8_t i; + + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev cp stats object is null"); + return NULL; + } + + channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; + + for (i = 0; i < channel_stats->total_channel; i++) { + entry = &channel_stats->channel_status_list[i]; + if (entry->channel_freq == chan_freq) + return entry; + } + cp_stats_err("Channel %d status info not exist", chan_freq); + + return NULL; +} + +void ucfg_mc_cp_stats_clear_channel_status(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cp_stats *pdev_cp_stats_priv; + struct per_channel_stats *channel_stats; + + pdev_cp_stats_priv = wlan_cp_stats_get_pdev_stats_obj(pdev); + if (!pdev_cp_stats_priv) { + cp_stats_err("pdev cp stats object is null"); + return; + } + + channel_stats = &pdev_cp_stats_priv->pdev_stats->chan_stats; + channel_stats->total_channel = 0; +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/inc/wlan_dlm_core.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/inc/wlan_dlm_core.h new file mode 100644 index 0000000000..c05250a6a5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/inc/wlan_dlm_core.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare internal APIs related to the denylist component + */ + +#ifndef _WLAN_DLM_CORE_H_ +#define _WLAN_DLM_CORE_H_ + +#include + +#define DLM_IS_AP_AVOIDED_BY_USERSPACE(cur_node) \ + (cur_node)->userspace_avoidlist + +#define DLM_IS_AP_AVOIDED_BY_DRIVER(cur_node) \ + (cur_node)->driver_avoidlist + +#define DLM_IS_AP_DENYLISTED_BY_USERSPACE(cur_node) \ + (cur_node)->userspace_denylist + +#define DLM_IS_AP_DENYLISTED_BY_DRIVER(cur_node) \ + (cur_node)->driver_denylist + +#define DLM_IS_AP_IN_MONITOR_LIST(cur_node) \ + (cur_node)->driver_monitorlist + +#define DLM_IS_AP_IN_RSSI_REJECT_LIST(cur_node) \ + (cur_node)->rssi_reject_list + +#define DLM_IS_AP_IN_DENYLIST(cur_node) \ + (DLM_IS_AP_DENYLISTED_BY_USERSPACE(cur_node) | \ + DLM_IS_AP_DENYLISTED_BY_DRIVER(cur_node) | \ + DLM_IS_AP_IN_RSSI_REJECT_LIST(cur_node)) + +#define DLM_IS_AP_IN_AVOIDLIST(cur_node) \ + (DLM_IS_AP_AVOIDED_BY_USERSPACE(cur_node) | \ + DLM_IS_AP_AVOIDED_BY_DRIVER(cur_node)) + +#define IS_AP_IN_USERSPACE_DENYLIST_ONLY(cur_node) \ + (DLM_IS_AP_DENYLISTED_BY_USERSPACE(cur_node) & \ + !(DLM_IS_AP_IN_AVOIDLIST(cur_node) | \ + DLM_IS_AP_IN_MONITOR_LIST(cur_node) | \ + DLM_IS_AP_IN_RSSI_REJECT_LIST(cur_node) | \ + DLM_IS_AP_DENYLISTED_BY_DRIVER(cur_node))) + +#define IS_AP_IN_MONITOR_LIST_ONLY(cur_node) \ + (DLM_IS_AP_IN_MONITOR_LIST(cur_node) & \ + !(DLM_IS_AP_IN_AVOIDLIST(cur_node) | \ + DLM_IS_AP_IN_DENYLIST(cur_node))) + +#define IS_AP_IN_AVOID_LIST_ONLY(cur_node) \ + (DLM_IS_AP_IN_AVOIDLIST(cur_node) & \ + !(DLM_IS_AP_IN_MONITOR_LIST(cur_node) | \ + DLM_IS_AP_IN_DENYLIST(cur_node))) + +#define IS_AP_IN_DRIVER_DENYLIST_ONLY(cur_node) \ + (DLM_IS_AP_DENYLISTED_BY_DRIVER(cur_node) & \ + !(DLM_IS_AP_IN_AVOIDLIST(cur_node) | \ + DLM_IS_AP_IN_MONITOR_LIST(cur_node) | \ + DLM_IS_AP_IN_RSSI_REJECT_LIST(cur_node) | \ + DLM_IS_AP_DENYLISTED_BY_USERSPACE(cur_node))) + +#define IS_AP_IN_RSSI_REJECT_LIST_ONLY(cur_node) \ + (DLM_IS_AP_IN_RSSI_REJECT_LIST(cur_node) & \ + !(DLM_IS_AP_IN_AVOIDLIST(cur_node) | \ + DLM_IS_AP_IN_MONITOR_LIST(cur_node) | \ + DLM_IS_AP_DENYLISTED_BY_DRIVER(cur_node) | \ + DLM_IS_AP_DENYLISTED_BY_USERSPACE(cur_node))) + +#define IS_AP_IN_USERSPACE_AVOID_LIST_ONLY(cur_node) \ + (DLM_IS_AP_AVOIDED_BY_USERSPACE(cur_node) & \ + !(DLM_IS_AP_AVOIDED_BY_DRIVER(cur_node) | \ + DLM_IS_AP_IN_MONITOR_LIST(cur_node) | \ + DLM_IS_AP_IN_DENYLIST(cur_node))) + +#define IS_AP_IN_DRIVER_AVOID_LIST_ONLY(cur_node) \ + (DLM_IS_AP_AVOIDED_BY_DRIVER(cur_node) & \ + !(DLM_IS_AP_AVOIDED_BY_USERSPACE(cur_node) | \ + DLM_IS_AP_IN_MONITOR_LIST(cur_node) | \ + DLM_IS_AP_IN_DENYLIST(cur_node))) + +/** + * struct dlm_reject_ap_timestamp - Structure to store the reject list BSSIDs + * entry time stamp. + * @userspace_avoid_timestamp: Time when userspace adds BSSID to avoid list. + * @driver_avoid_timestamp: Time when driver adds BSSID to avoid list. + * @userspace_denylist_timestamp: Time when userspace adds BSSID to deny list. + * @driver_denylist_timestamp: Time when driver adds BSSID to deny list. + * @rssi_reject_timestamp: Time when driver adds BSSID to rssi reject list. + * @driver_monitor_timestamp: Time when driver adds BSSID to monitor list. + */ +struct dlm_reject_ap_timestamp { + qdf_time_t userspace_avoid_timestamp; + qdf_time_t driver_avoid_timestamp; + qdf_time_t userspace_denylist_timestamp; + qdf_time_t driver_denylist_timestamp; + qdf_time_t rssi_reject_timestamp; + qdf_time_t driver_monitor_timestamp; +}; + +/** + * struct dlm_reject_ap - Structure of a node added to denylist manager + * @node: Node of the entry + * @bssid: Bssid of the AP entry. + * @rssi_reject_params: Rssi reject params of the AP entry. + * @bad_bssid_counter: It represent how many times data stall happened. + * @ap_timestamp: AP timestamp. + * @reject_ap_type: consolidated bitmap of rejection types for the AP + * @userspace_denylist: AP in userspace denylist + * @driver_denylist: AP in driver denylist + * @userspace_avoidlist: AP in userspace avoidlist + * @driver_avoidlist: AP in driver avoidlist + * @rssi_reject_list: AP has bad RSSI + * @driver_monitorlist: AP is monitored + * @reject_ap_reason: consolidated bitmap of rejection reasons for the AP + * @nud_fail: NUD fail reason + * @sta_kickout: STA kickout reason + * @ho_fail: Handoff failure reason + * @poor_rssi: Poor RSSI reason + * @oce_assoc_reject: OCE association rejected reason + * @denylist_userspace: Userspace denylist reason + * @avoid_userspace: Userspace avoidlist reason + * @btm_disassoc_imminent: BTM disassociation imminent reason + * @btm_bss_termination: BTM BSS termination reason + * @btm_mbo_retry: BTM MBO retry reason + * @reassoc_rssi_reject: Reassociation RSSI rejection reason + * @no_more_stas: AP reached STA capacity reason + * @source: source of the rejection + * @connect_timestamp: Timestamp when the STA got connected with this BSSID + */ +struct dlm_reject_ap { + qdf_list_node_t node; + struct qdf_mac_addr bssid; + struct dlm_rssi_disallow_params rssi_reject_params; + uint8_t bad_bssid_counter; + struct dlm_reject_ap_timestamp ap_timestamp; + union { + struct { + uint8_t userspace_denylist:1, + driver_denylist:1, + userspace_avoidlist:1, + driver_avoidlist:1, + rssi_reject_list:1, + driver_monitorlist:1; + }; + uint8_t reject_ap_type; + }; + union { + struct { + uint32_t nud_fail:1, + sta_kickout:1, + ho_fail:1, + poor_rssi:1, + oce_assoc_reject:1, + denylist_userspace:1, + avoid_userspace:1, + btm_disassoc_imminent:1, + btm_bss_termination:1, + btm_mbo_retry:1, + reassoc_rssi_reject:1, + no_more_stas:1; + }; + uint32_t reject_ap_reason; + }; + enum dlm_reject_ap_source source; + qdf_time_t connect_timestamp; +}; + +/** + * dlm_add_bssid_to_reject_list() - Add BSSID to the specific reject list. + * @pdev: Pdev object + * @ap_info: Ap info params such as BSSID, and the type of rejection to be done + * + * This API will add the BSSID to the reject AP list maintained by the denylist + * manager. + * + * Return: QDF status + */ +QDF_STATUS +dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info); + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * dlm_send_reject_ap_list_to_fw() - Send the denylist BSSIDs to FW + * @pdev: Pdev object + * @reject_db_list: List of denylist BSSIDs + * @cfg: Denylist manager cfg + * + * This API will send the denylist BSSIDs to FW for avoiding or denylisting + * in roaming scenarios. + * + * Return: None + */ +void +dlm_send_reject_ap_list_to_fw(struct wlan_objmgr_pdev *pdev, + qdf_list_t *reject_db_list, + struct dlm_config *cfg); + +/** + * dlm_update_reject_ap_list_to_fw() - Send the denylist BSSIDs to FW + * @psoc: psoc object + * + * This API will send the denylist BSSIDs to FW. + * + * Return: None + */ +void dlm_update_reject_ap_list_to_fw(struct wlan_objmgr_psoc *psoc); +#else +static inline void dlm_send_reject_ap_list_to_fw(struct wlan_objmgr_pdev *pdev, + qdf_list_t *reject_db_list, + struct dlm_config *cfg) +{ +} + +static inline void +dlm_update_reject_ap_list_to_fw(struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +/** + * dlm_add_userspace_deny_list() - Clear already existing userspace BSSID, and + * add the new ones to denylist manager. + * @pdev: pdev object + * @bssid_deny_list: BSSIDs to be denylisted by userspace. + * @num_of_bssid: num of bssids to be denylisted. + * + * This API will Clear already existing userspace BSSID, and add the new ones + * to denylist manager's reject list. + * + * Return: QDF status + */ +QDF_STATUS +dlm_add_userspace_deny_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid_deny_list, + uint8_t num_of_bssid); + +/** + * dlm_update_bssid_connect_params() - Inform the DLM about connect/disconnect + * with the current AP. + * @pdev: pdev object + * @bssid: BSSID of the AP + * @con_state: Connection state (connected/disconnected) + * + * This API will inform the DLM about the state with the AP so that if the AP + * is selected, and the connection went through, and the connection did not + * face any data stall till the bad bssid reset timer, DLM can remove the + * AP from the reject ap list maintained by it. + * + * Return: None + */ +void +dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state); + +/** + * dlm_flush_reject_ap_list() - Clear away BSSID and destroy the reject ap list + * @dlm_ctx: denylist manager pdev priv object + * + * This API will clear the BSSID info in the reject AP list maintained by the + * denylist manager, and will destroy the list as well. + * + * Return: None + */ +void +dlm_flush_reject_ap_list(struct dlm_pdev_priv_obj *dlm_ctx); + +/** + * dlm_get_bssid_reject_list() - Get the BSSIDs in reject list from DLM + * @pdev: pdev object + * @reject_list: reject list to be filled (passed by caller) + * @max_bssid_to_be_filled: num of bssids filled in reject list by DLM + * @reject_ap_type: reject ap type of the BSSIDs to be filled. + * + * This API will fill the reject ap list requested by caller of type given as + * argument reject_ap_type, and will return the number of BSSIDs filled. + * + * Return: Unsigned integer (number of BSSIDs filled by the denylist manager) + */ +uint8_t +dlm_get_bssid_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_config_params *reject_list, + uint8_t max_bssid_to_be_filled, + enum dlm_reject_ap_type reject_ap_type); + +/** + * dlm_dump_denylist_bssid - Dump denylisted bssids + * @pdev: pdev object + * + * Return: None + */ +void dlm_dump_denylist_bssid(struct wlan_objmgr_pdev *pdev); + +/** + * dlm_is_bssid_in_reject_list - Check whether a BSSID is present in + * reject list or not. + * @pdev: pdev object + * @bssid: bssid to check + * + * Return: true if BSSID is present in reject list + */ +bool dlm_is_bssid_in_reject_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid); + +/** + * dlm_get_rssi_denylist_threshold() - Get rssi denylist threshold value + * @pdev: pdev object + * + * This API will get the RSSI denylist threshold info. + * + * Return: rssi threshold value + */ +int32_t +dlm_get_rssi_denylist_threshold(struct wlan_objmgr_pdev *pdev); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/inc/wlan_dlm_main.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/inc/wlan_dlm_main.h new file mode 100644 index 0000000000..91eb398a1d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/inc/wlan_dlm_main.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare internal APIs related to the denylist manager component + */ + +#ifndef _WLAN_DLM_MAIN_H_ +#define _WLAN_DLM_MAIN_H_ + +#include +#include +#include +#include + +#define dlm_fatal(params...)\ + QDF_TRACE_FATAL(QDF_MODULE_ID_DENYLIST_MGR, params) +#define dlm_err(params...)\ + QDF_TRACE_ERROR(QDF_MODULE_ID_DENYLIST_MGR, params) +#define dlm_warn(params...)\ + QDF_TRACE_WARN(QDF_MODULE_ID_DENYLIST_MGR, params) +#define dlm_info(params...)\ + QDF_TRACE_INFO(QDF_MODULE_ID_DENYLIST_MGR, params) +#define dlm_debug(params...)\ + QDF_TRACE_DEBUG(QDF_MODULE_ID_DENYLIST_MGR, params) +#define dlm_nofl_debug(params...)\ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_DENYLIST_MGR, params) + +/** + * struct dlm_pdev_priv_obj - Pdev priv struct to store list of denylist mgr. + * @reject_ap_list_lock: Mutex needed to restrict two threads updating the list. + * @reject_ap_list: The reject Ap list which would contain the list of bad APs. + * @dlm_tx_ops: tx ops to send reject ap list to FW + */ +struct dlm_pdev_priv_obj { + qdf_mutex_t reject_ap_list_lock; + qdf_list_t reject_ap_list; + struct wlan_dlm_tx_ops dlm_tx_ops; +}; + +/** + * struct dlm_config - Structure to define the config params for denylist mgr. + * @avoid_list_exipry_time: Timer after which transition from avoid->monitor + * would happen for the BSSID which is in avoid list. + * @deny_list_exipry_time: Timer after which transition from deny->monitor + * would happen for the BSSID which is in deny list. + * @bad_bssid_counter_reset_time: Timer after which the bssid would be removed + * from the reject list when connected, and data stall is not seen with the AP. + * @bad_bssid_counter_thresh: This is the threshold count which is incremented + * after every NUD fail, and after this much count, the BSSID would be moved to + * denylist. + * @delta_rssi: This is the rssi threshold, only when rssi + * improves by this value the entry for BSSID should be removed from deny + * list manager list. + */ +struct dlm_config { + qdf_time_t avoid_list_exipry_time; + qdf_time_t deny_list_exipry_time; + qdf_time_t bad_bssid_counter_reset_time; + uint8_t bad_bssid_counter_thresh; + uint32_t delta_rssi; +}; + +/** + * struct dlm_psoc_priv_obj - Psoc priv structure of the denylist manager. + * @pdev_id: pdev id + * @is_suspended: is deny list manager state suspended + * @dlm_cfg: These are the config ini params that the user can configure. + */ +struct dlm_psoc_priv_obj { + uint8_t pdev_id; + bool is_suspended; + struct dlm_config dlm_cfg; +}; + +/** + * dlm_pdev_object_created_notification() - denylist mgr pdev create + * handler + * @pdev: pdev which is going to be created by objmgr + * @arg: argument for pdev create handler + * + * Register this api with objmgr to detect if pdev is created. + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dlm_pdev_object_created_notification(struct wlan_objmgr_pdev *pdev, + void *arg); + +/** + * dlm_pdev_object_destroyed_notification() - denylist mgr pdev delete handler + * @pdev: pdev which is going to be deleted by objmgr + * @arg: argument for pdev delete handler + * + * Register this api with objmgr to detect if pdev is deleted. + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dlm_pdev_object_destroyed_notification(struct wlan_objmgr_pdev *pdev, + void *arg); + +/** + * dlm_psoc_object_created_notification() - denylist mgr psoc create handler + * @psoc: psoc which is going to be created by objmgr + * @arg: argument for psoc create handler + * + * Register this api with objmgr to detect if psoc is created. + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dlm_psoc_object_created_notification(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * dlm_psoc_object_destroyed_notification() - denylist mgr psoc delete handler + * @psoc: psoc which is going to be deleted by objmgr + * @arg: argument for psoc delete handler. + * + * Register this api with objmgr to detect if psoc is deleted. + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dlm_psoc_object_destroyed_notification(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * dlm_cfg_psoc_open() - denylist mgr psoc open handler + * @psoc: psoc which is initialized by objmgr + * + * This API will initialize the config file, and store the config while in the + * psoc priv object of the denylist manager. + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dlm_cfg_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * dlm_get_pdev_obj() - Get the pdev priv object of the denylist manager + * @pdev: pdev object + * + * Get the pdev priv object of the denylist manager + * + * Return: Pdev priv object if present, else NULL. + */ +struct dlm_pdev_priv_obj * +dlm_get_pdev_obj(struct wlan_objmgr_pdev *pdev); + +/** + * dlm_get_psoc_obj() - Get the psoc priv object of the denylist manager + * @psoc: psoc object + * + * Get the psoc priv object of the denylist manager + * + * Return: Psoc priv object if present, else NULL. + */ +struct dlm_psoc_priv_obj * +dlm_get_psoc_obj(struct wlan_objmgr_psoc *psoc); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_core.c b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_core.c new file mode 100644 index 0000000000..a55b3d4424 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_core.c @@ -0,0 +1,1486 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare internal APIs related to the denylist component + */ + +#include +#include +#include +#include +#include +#include "wlan_dlm_tgt_api.h" +#include +#include + +#define SECONDS_TO_MS(params) ((params) * 1000) +#define MINUTES_TO_MS(params) (SECONDS_TO_MS(params) * 60) +#define RSSI_TIMEOUT_VALUE 60 + +static void +dlm_update_ap_info(struct dlm_reject_ap *dlm_entry, struct dlm_config *cfg, + struct scan_cache_entry *scan_entry) +{ + qdf_time_t cur_timestamp = qdf_mc_timer_get_system_time(); + qdf_time_t entry_add_time = 0; + bool update_done = false; + uint8_t old_reject_ap_type; + + old_reject_ap_type = dlm_entry->reject_ap_type; + + if (DLM_IS_AP_AVOIDED_BY_USERSPACE(dlm_entry)) { + entry_add_time = + dlm_entry->ap_timestamp.userspace_avoid_timestamp; + + if ((cur_timestamp - entry_add_time) >= + MINUTES_TO_MS(cfg->avoid_list_exipry_time)) { + /* Move AP to monitor list as avoid list time is over */ + dlm_entry->userspace_avoidlist = false; + dlm_entry->avoid_userspace = false; + dlm_entry->driver_monitorlist = true; + + dlm_entry->ap_timestamp.driver_monitor_timestamp = + cur_timestamp; + dlm_debug("Userspace avoid list timer expired, moved to monitor list"); + update_done = true; + } + } + + if (DLM_IS_AP_AVOIDED_BY_DRIVER(dlm_entry)) { + entry_add_time = dlm_entry->ap_timestamp.driver_avoid_timestamp; + + if ((cur_timestamp - entry_add_time) >= + MINUTES_TO_MS(cfg->avoid_list_exipry_time)) { + /* Move AP to monitor list as avoid list time is over */ + dlm_entry->driver_avoidlist = false; + dlm_entry->nud_fail = false; + dlm_entry->sta_kickout = false; + dlm_entry->ho_fail = false; + dlm_entry->driver_monitorlist = true; + + dlm_entry->ap_timestamp.driver_monitor_timestamp = + cur_timestamp; + dlm_debug("Driver avoid list timer expired, moved to monitor list"); + update_done = true; + } + } + + if (DLM_IS_AP_DENYLISTED_BY_DRIVER(dlm_entry)) { + entry_add_time = + dlm_entry->ap_timestamp.driver_denylist_timestamp; + + if ((cur_timestamp - entry_add_time) >= + MINUTES_TO_MS(cfg->deny_list_exipry_time)) { + /* Move AP to monitor list as deny list time is over */ + dlm_entry->driver_denylist = false; + dlm_entry->driver_monitorlist = true; + dlm_entry->nud_fail = false; + dlm_entry->sta_kickout = false; + dlm_entry->ho_fail = false; + dlm_entry->ap_timestamp.driver_monitor_timestamp = + cur_timestamp; + dlm_debug("Driver denylist timer expired, moved to monitor list"); + update_done = true; + } + } + + if (DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry)) { + qdf_time_t entry_age = cur_timestamp - + dlm_entry->ap_timestamp.rssi_reject_timestamp; + + if ((dlm_entry->rssi_reject_params.retry_delay && + entry_age >= dlm_entry->rssi_reject_params.retry_delay) || + (scan_entry && scan_entry->rssi_raw >= + dlm_entry->rssi_reject_params.expected_rssi)) { + /* + * Remove from the rssi reject list as:- + * 1. In case of OCE reject, both the time, and RSSI + * param are present, and one of them have improved + * now, so the STA can now connect to the AP. + * + * 2. In case of BTM message received from the FW, + * the STA just needs to wait for a certain time, + * hence RSSI is not a restriction (MIN RSSI needed + * in that case is filled as 0). + * Hence the above check will still pass, if BTM + * delay is over, and will fail is not. RSSI check + * for BTM message will fail (expected), as BTM does + * not care about the same. + */ + dlm_entry->poor_rssi = false; + dlm_entry->oce_assoc_reject = false; + dlm_entry->btm_bss_termination = false; + dlm_entry->btm_disassoc_imminent = false; + dlm_entry->btm_mbo_retry = false; + dlm_entry->no_more_stas = false; + dlm_entry->reassoc_rssi_reject = false; + dlm_entry->rssi_reject_list = false; + dlm_debug("Remove BSSID from rssi reject expected RSSI = %d, current RSSI = %d, retry delay required = %d ms, delay = %lu ms", + dlm_entry->rssi_reject_params.expected_rssi, + scan_entry ? scan_entry->rssi_raw : 0, + dlm_entry->rssi_reject_params.retry_delay, + entry_age); + update_done = true; + } + } + + if (!update_done) + return; + + dlm_debug(QDF_MAC_ADDR_FMT " Old %d Updated reject ap type = %x", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), + old_reject_ap_type, + dlm_entry->reject_ap_type); +} + +#define MAX_BL_TIME 255000 + +static enum cm_denylist_action +dlm_prune_old_entries_and_get_action(struct dlm_reject_ap *dlm_entry, + struct dlm_config *cfg, + struct scan_cache_entry *entry, + qdf_list_t *reject_ap_list) +{ + dlm_update_ap_info(dlm_entry, cfg, entry); + + /* + * If all entities have cleared the bits of reject ap type, then + * the AP is not needed in the database,(reject_ap_type should be 0), + * then remove the entry from the reject ap list. + */ + if (!dlm_entry->reject_ap_type) { + dlm_debug(QDF_MAC_ADDR_FMT " cleared from list", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + qdf_list_remove_node(reject_ap_list, &dlm_entry->node); + qdf_mem_free(dlm_entry); + return CM_DLM_NO_ACTION; + } + + if (DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry) && + !dlm_entry->userspace_denylist && !dlm_entry->driver_denylist && + dlm_entry->rssi_reject_params.original_timeout > MAX_BL_TIME) { + dlm_info("Allow BSSID " QDF_MAC_ADDR_FMT " as the retry delay is greater than %u ms, expected RSSI = %d, current RSSI = %d, retry delay = %u ms original timeout %u time added %lu source %d reason %d", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), MAX_BL_TIME, + dlm_entry->rssi_reject_params.expected_rssi, + entry ? entry->rssi_raw : 0, + dlm_entry->rssi_reject_params.retry_delay, + dlm_entry->rssi_reject_params.original_timeout, + dlm_entry->rssi_reject_params.received_time, + dlm_entry->source, dlm_entry->reject_ap_reason); + + if (DLM_IS_AP_IN_AVOIDLIST(dlm_entry)) { + dlm_debug(QDF_MAC_ADDR_FMT " in avoid list, deprioritize it", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + return CM_DLM_AVOID; + } + + return CM_DLM_NO_ACTION; + } + if (DLM_IS_AP_IN_DENYLIST(dlm_entry)) { + dlm_debug(QDF_MAC_ADDR_FMT " in denylist list, reject ap type %d removing from candidate list", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), + dlm_entry->reject_ap_type); + + if (DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry) || + DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry)) { + if (dlm_entry->reject_ap_reason == REASON_UNKNOWN || + dlm_entry->reject_ap_reason == REASON_NUD_FAILURE || + dlm_entry->reject_ap_reason == REASON_STA_KICKOUT || + dlm_entry->reject_ap_reason == REASON_ROAM_HO_FAILURE) + return CM_DLM_REMOVE; + else + return CM_DLM_FORCE_REMOVE; + } + + return CM_DLM_REMOVE; + } + + if (DLM_IS_AP_IN_AVOIDLIST(dlm_entry)) { + dlm_debug(QDF_MAC_ADDR_FMT " in avoid list, deprioritize it", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + return CM_DLM_AVOID; + } + + return CM_DLM_NO_ACTION; +} + +static enum cm_denylist_action +dlm_action_on_bssid(struct wlan_objmgr_pdev *pdev, + struct scan_cache_entry *entry) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + struct dlm_config *cfg; + struct dlm_reject_ap *dlm_entry = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + QDF_STATUS status; + enum cm_denylist_action action = CM_DLM_NO_ACTION; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return CM_DLM_NO_ACTION; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return CM_DLM_NO_ACTION; + } + + cfg = &dlm_psoc_obj->dlm_cfg; + + qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node, + &next_node); + + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + + if (qdf_is_macaddr_equal(&dlm_entry->bssid, &entry->bssid)) { + action = dlm_prune_old_entries_and_get_action(dlm_entry, + cfg, entry, &dlm_ctx->reject_ap_list); + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + return action; + } + cur_node = next_node; + next_node = NULL; + } + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + + return CM_DLM_NO_ACTION; +} + +enum cm_denylist_action +wlan_denylist_action_on_bssid(struct wlan_objmgr_pdev *pdev, + struct scan_cache_entry *entry) +{ + return dlm_action_on_bssid(pdev, entry); +} + +static void +dlm_update_avoidlist_reject_reason(struct dlm_reject_ap *entry, + enum dlm_reject_ap_reason reject_reason) +{ + entry->nud_fail = false; + entry->sta_kickout = false; + entry->ho_fail = false; + + switch (reject_reason) { + case REASON_NUD_FAILURE: + entry->nud_fail = true; + break; + case REASON_STA_KICKOUT: + entry->sta_kickout = true; + break; + case REASON_ROAM_HO_FAILURE: + entry->ho_fail = true; + break; + default: + dlm_err("Invalid reason passed %d", reject_reason); + } +} + +static void +dlm_handle_avoid_list(struct dlm_reject_ap *entry, + struct dlm_config *cfg, + struct reject_ap_info *ap_info) +{ + qdf_time_t cur_timestamp = qdf_mc_timer_get_system_time(); + + if (ap_info->reject_ap_type == USERSPACE_AVOID_TYPE) { + entry->userspace_avoidlist = true; + entry->avoid_userspace = true; + entry->ap_timestamp.userspace_avoid_timestamp = cur_timestamp; + } else if (ap_info->reject_ap_type == DRIVER_AVOID_TYPE) { + entry->driver_avoidlist = true; + dlm_update_avoidlist_reject_reason(entry, + ap_info->reject_reason); + entry->ap_timestamp.driver_avoid_timestamp = cur_timestamp; + } else { + return; + } + entry->source = ap_info->source; + /* Update bssid info for new entry */ + entry->bssid = ap_info->bssid; + + /* Clear the monitor list bit if the AP was present in monitor list */ + entry->driver_monitorlist = false; + + /* Increment bad bssid counter as NUD failure happenend with this ap */ + entry->bad_bssid_counter++; + + /* If bad bssid counter has reached threshold, move it to denylist */ + if (entry->bad_bssid_counter >= cfg->bad_bssid_counter_thresh) { + if (ap_info->reject_ap_type == USERSPACE_AVOID_TYPE) + entry->userspace_avoidlist = false; + else if (ap_info->reject_ap_type == DRIVER_AVOID_TYPE) + entry->driver_avoidlist = false; + + /* Move AP to denylist list */ + entry->driver_denylist = true; + entry->ap_timestamp.driver_denylist_timestamp = cur_timestamp; + + dlm_debug(QDF_MAC_ADDR_FMT " moved to deny list with counter %d", + QDF_MAC_ADDR_REF(entry->bssid.bytes), + entry->bad_bssid_counter); + return; + } + dlm_debug("Added " QDF_MAC_ADDR_FMT " to avoid list type %d, counter %d reason %d updated reject reason %d source %d", + QDF_MAC_ADDR_REF(entry->bssid.bytes), ap_info->reject_ap_type, + entry->bad_bssid_counter, ap_info->reject_reason, + entry->reject_ap_reason, entry->source); + + entry->connect_timestamp = qdf_mc_timer_get_system_time(); +} + +static void +dlm_handle_denylist(struct dlm_reject_ap *entry, + struct reject_ap_info *ap_info) +{ + /* + * No entity will denylist an AP internal to driver, so only + * userspace denylist is the case to be taken care. Driver denylist + * will only happen when the bad bssid counter has reached the max + * threshold. + */ + entry->bssid = ap_info->bssid; + entry->userspace_denylist = true; + entry->ap_timestamp.userspace_denylist_timestamp = + qdf_mc_timer_get_system_time(); + + entry->source = ADDED_BY_DRIVER; + entry->denylist_userspace = true; + dlm_debug(QDF_MAC_ADDR_FMT " added to userspace denylist", + QDF_MAC_ADDR_REF(entry->bssid.bytes)); +} + +static void +dlm_update_rssi_reject_reason(struct dlm_reject_ap *entry, + enum dlm_reject_ap_reason reject_reason) +{ + entry->poor_rssi = false; + entry->oce_assoc_reject = false; + entry->btm_bss_termination = false; + entry->btm_disassoc_imminent = false; + entry->btm_mbo_retry = false; + entry->no_more_stas = false; + entry->reassoc_rssi_reject = false; + + switch (reject_reason) { + case REASON_ASSOC_REJECT_POOR_RSSI: + entry->poor_rssi = true; + break; + case REASON_ASSOC_REJECT_OCE: + entry->oce_assoc_reject = true; + break; + case REASON_BTM_DISASSOC_IMMINENT: + entry->btm_disassoc_imminent = true; + break; + case REASON_BTM_BSS_TERMINATION: + entry->btm_bss_termination = true; + break; + case REASON_BTM_MBO_RETRY: + entry->btm_mbo_retry = true; + break; + case REASON_REASSOC_RSSI_REJECT: + entry->reassoc_rssi_reject = true; + break; + case REASON_REASSOC_NO_MORE_STAS: + entry->no_more_stas = true; + break; + default: + dlm_err("Invalid reason passed %d", reject_reason); + } +} + +static void +dlm_handle_rssi_reject_list(struct dlm_reject_ap *entry, + struct reject_ap_info *ap_info) +{ + bool bssid_newly_added; + + if (entry->rssi_reject_list) { + bssid_newly_added = false; + } else { + entry->rssi_reject_params.source = ap_info->source; + entry->bssid = ap_info->bssid; + entry->rssi_reject_list = true; + bssid_newly_added = true; + } + + entry->ap_timestamp.rssi_reject_timestamp = + qdf_mc_timer_get_system_time(); + entry->rssi_reject_params = ap_info->rssi_reject_params; + dlm_update_rssi_reject_reason(entry, ap_info->reject_reason); + dlm_info(QDF_MAC_ADDR_FMT " %s to rssi reject list, expected RSSI %d retry delay %u source %d original timeout %u received time %lu reject reason %d updated reason %d", + QDF_MAC_ADDR_REF(entry->bssid.bytes), + bssid_newly_added ? "ADDED" : "UPDATED", + entry->rssi_reject_params.expected_rssi, + entry->rssi_reject_params.retry_delay, + entry->rssi_reject_params.source, + entry->rssi_reject_params.original_timeout, + entry->rssi_reject_params.received_time, + ap_info->reject_reason, entry->reject_ap_reason); +} + +static void +dlm_modify_entry(struct dlm_reject_ap *entry, struct dlm_config *cfg, + struct reject_ap_info *ap_info) +{ + /* Modify the entry according to the ap_info */ + switch (ap_info->reject_ap_type) { + case USERSPACE_AVOID_TYPE: + case DRIVER_AVOID_TYPE: + dlm_handle_avoid_list(entry, cfg, ap_info); + break; + case USERSPACE_DENYLIST_TYPE: + dlm_handle_denylist(entry, ap_info); + break; + case DRIVER_RSSI_REJECT_TYPE: + dlm_handle_rssi_reject_list(entry, ap_info); + break; + default: + dlm_debug("Invalid input of ap type %d", + ap_info->reject_ap_type); + } +} + +static bool +dlm_is_bssid_present_only_in_list_type(enum dlm_reject_ap_type list_type, + struct dlm_reject_ap *dlm_entry) +{ + switch (list_type) { + case USERSPACE_AVOID_TYPE: + return IS_AP_IN_USERSPACE_AVOID_LIST_ONLY(dlm_entry); + case USERSPACE_DENYLIST_TYPE: + return IS_AP_IN_USERSPACE_DENYLIST_ONLY(dlm_entry); + case DRIVER_AVOID_TYPE: + return IS_AP_IN_DRIVER_AVOID_LIST_ONLY(dlm_entry); + case DRIVER_DENYLIST_TYPE: + return IS_AP_IN_DRIVER_DENYLIST_ONLY(dlm_entry); + case DRIVER_RSSI_REJECT_TYPE: + return IS_AP_IN_RSSI_REJECT_LIST_ONLY(dlm_entry); + case DRIVER_MONITOR_TYPE: + return IS_AP_IN_MONITOR_LIST_ONLY(dlm_entry); + default: + dlm_debug("Wrong list type %d passed", list_type); + return false; + } +} + +static bool +dlm_is_bssid_of_type(enum dlm_reject_ap_type reject_ap_type, + struct dlm_reject_ap *dlm_entry) +{ + switch (reject_ap_type) { + case USERSPACE_AVOID_TYPE: + return DLM_IS_AP_AVOIDED_BY_USERSPACE(dlm_entry); + case USERSPACE_DENYLIST_TYPE: + return DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry); + case DRIVER_AVOID_TYPE: + return DLM_IS_AP_AVOIDED_BY_DRIVER(dlm_entry); + case DRIVER_DENYLIST_TYPE: + return DLM_IS_AP_DENYLISTED_BY_DRIVER(dlm_entry); + case DRIVER_RSSI_REJECT_TYPE: + return DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry); + case DRIVER_MONITOR_TYPE: + return DLM_IS_AP_IN_MONITOR_LIST(dlm_entry); + default: + dlm_err("Wrong list type %d passed", reject_ap_type); + return false; + } +} + +static qdf_time_t +dlm_get_delta_of_bssid(enum dlm_reject_ap_type list_type, + struct dlm_reject_ap *dlm_entry, + struct dlm_config *cfg) +{ + qdf_time_t cur_timestamp = qdf_mc_timer_get_system_time(); + int32_t disallowed_time; + /* + * For all the list types, delta would be the entry age only. Hence the + * oldest entry would be removed first in case of list is full, and the + * driver needs to make space for newer entries. + */ + + switch (list_type) { + case USERSPACE_AVOID_TYPE: + return MINUTES_TO_MS(cfg->avoid_list_exipry_time) - + (cur_timestamp - + dlm_entry->ap_timestamp.userspace_avoid_timestamp); + case USERSPACE_DENYLIST_TYPE: + return cur_timestamp - + dlm_entry->ap_timestamp.userspace_denylist_timestamp; + case DRIVER_AVOID_TYPE: + return MINUTES_TO_MS(cfg->avoid_list_exipry_time) - + (cur_timestamp - + dlm_entry->ap_timestamp.driver_avoid_timestamp); + case DRIVER_DENYLIST_TYPE: + return MINUTES_TO_MS(cfg->deny_list_exipry_time) - + (cur_timestamp - + dlm_entry->ap_timestamp.driver_denylist_timestamp); + + /* + * For RSSI reject lowest delta would be the BSSID whose retry delay + * is about to expire, hence the delta would be remaining duration for + * de-denylisting the AP from rssi reject list. + */ + case DRIVER_RSSI_REJECT_TYPE: + if (dlm_entry->rssi_reject_params.retry_delay) + disallowed_time = + dlm_entry->rssi_reject_params.retry_delay - + (cur_timestamp - + dlm_entry->ap_timestamp.rssi_reject_timestamp); + else + disallowed_time = + (int32_t)(MINUTES_TO_MS(RSSI_TIMEOUT_VALUE) - + (cur_timestamp - + dlm_entry->ap_timestamp.rssi_reject_timestamp) + ); + return ((disallowed_time < 0) ? 0 : disallowed_time); + case DRIVER_MONITOR_TYPE: + return cur_timestamp - + dlm_entry->ap_timestamp.driver_monitor_timestamp; + default: + dlm_debug("Wrong list type %d passed", list_type); + return 0; + } +} + +static bool +dlm_is_oldest_entry(enum dlm_reject_ap_type list_type, + qdf_time_t cur_node_delta, + qdf_time_t oldest_node_delta) +{ + switch (list_type) { + /* + * For RSSI reject, userspace avoid, driver avoid/denylist type the + * lowest retry delay has to be found out hence if oldest_node_delta is + * 0, mean this is the first entry and thus return true, If + * oldest_node_delta is non zero, compare the delta and return true if + * the cur entry has lower retry delta. + */ + case DRIVER_RSSI_REJECT_TYPE: + case USERSPACE_AVOID_TYPE: + case DRIVER_AVOID_TYPE: + case DRIVER_DENYLIST_TYPE: + if (!oldest_node_delta || cur_node_delta < oldest_node_delta) + return true; + break; + case USERSPACE_DENYLIST_TYPE: + case DRIVER_MONITOR_TYPE: + if (cur_node_delta > oldest_node_delta) + return true; + break; + default: + dlm_debug("Wrong list type passed %d", list_type); + return false; + } + + return false; +} + +static QDF_STATUS +dlm_try_delete_bssid_in_list(qdf_list_t *reject_ap_list, + enum dlm_reject_ap_type list_type, + struct dlm_config *cfg) +{ + struct dlm_reject_ap *dlm_entry = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + struct dlm_reject_ap *oldest_dlm_entry = NULL; + qdf_time_t oldest_node_delta = 0; + qdf_time_t cur_node_delta = 0; + + qdf_list_peek_front(reject_ap_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(reject_ap_list, cur_node, &next_node); + + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + + if (dlm_is_bssid_present_only_in_list_type(list_type, + dlm_entry)) { + cur_node_delta = dlm_get_delta_of_bssid(list_type, + dlm_entry, cfg); + + if (dlm_is_oldest_entry(list_type, cur_node_delta, + oldest_node_delta)) { + /* now this is the oldest entry*/ + oldest_dlm_entry = dlm_entry; + oldest_node_delta = cur_node_delta; + } + } + cur_node = next_node; + next_node = NULL; + } + + if (oldest_dlm_entry) { + /* Remove this entry to make space for the next entry */ + dlm_debug("Removed " QDF_MAC_ADDR_FMT ", type = %d", + QDF_MAC_ADDR_REF(oldest_dlm_entry->bssid.bytes), + list_type); + qdf_list_remove_node(reject_ap_list, &oldest_dlm_entry->node); + qdf_mem_free(oldest_dlm_entry); + return QDF_STATUS_SUCCESS; + } + /* If the flow has reached here, that means no entry could be removed */ + + return QDF_STATUS_E_FAILURE; +} + +static QDF_STATUS +dlm_remove_lowest_delta_entry(qdf_list_t *reject_ap_list, + struct dlm_config *cfg) +{ + QDF_STATUS status; + + /* + * According to the Priority, the driver will try to remove the entries, + * as the least priority list, that is monitor list would not penalize + * the BSSIDs for connection. The priority order for the removal is:- + * 1. Monitor list + * 2. Driver avoid list + * 3. Userspace avoid list. + * 4. RSSI reject list. + * 5. Driver Denylist. + * 6. Userspace Denylist. + */ + + status = dlm_try_delete_bssid_in_list(reject_ap_list, + DRIVER_MONITOR_TYPE, cfg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + status = dlm_try_delete_bssid_in_list(reject_ap_list, + DRIVER_AVOID_TYPE, cfg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + status = dlm_try_delete_bssid_in_list(reject_ap_list, + USERSPACE_AVOID_TYPE, cfg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + status = dlm_try_delete_bssid_in_list(reject_ap_list, + DRIVER_RSSI_REJECT_TYPE, cfg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + status = dlm_try_delete_bssid_in_list(reject_ap_list, + DRIVER_DENYLIST_TYPE, cfg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + status = dlm_try_delete_bssid_in_list(reject_ap_list, + USERSPACE_DENYLIST_TYPE, cfg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + dlm_debug("Failed to remove AP from denylist manager"); + + return QDF_STATUS_E_FAILURE; +} + +static enum dlm_reject_ap_reason +dlm_get_rssi_reject_reason(struct dlm_reject_ap *dlm_entry) +{ + if (dlm_entry->poor_rssi) + return REASON_ASSOC_REJECT_POOR_RSSI; + else if (dlm_entry->oce_assoc_reject) + return REASON_ASSOC_REJECT_OCE; + else if (dlm_entry->btm_bss_termination) + return REASON_BTM_BSS_TERMINATION; + else if (dlm_entry->btm_disassoc_imminent) + return REASON_BTM_DISASSOC_IMMINENT; + else if (dlm_entry->btm_mbo_retry) + return REASON_BTM_MBO_RETRY; + else if (dlm_entry->no_more_stas) + return REASON_REASSOC_NO_MORE_STAS; + else if (dlm_entry->reassoc_rssi_reject) + return REASON_REASSOC_RSSI_REJECT; + + return REASON_UNKNOWN; +} + +static void +dlm_fill_rssi_reject_params(struct dlm_reject_ap *dlm_entry, + enum dlm_reject_ap_type reject_ap_type, + struct reject_ap_config_params *dlm_reject_list) +{ + if (reject_ap_type != DRIVER_RSSI_REJECT_TYPE) + return; + + dlm_reject_list->source = dlm_entry->rssi_reject_params.source; + dlm_reject_list->original_timeout = + dlm_entry->rssi_reject_params.original_timeout; + dlm_reject_list->received_time = + dlm_entry->rssi_reject_params.received_time; + dlm_reject_list->reject_reason = dlm_get_rssi_reject_reason(dlm_entry); + dlm_debug(QDF_MAC_ADDR_FMT " source %d original timeout %u received time %lu reject reason %d", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), + dlm_reject_list->source, + dlm_reject_list->original_timeout, + dlm_reject_list->received_time, + dlm_reject_list->reject_reason); +} + +/** + * dlm_find_reject_type_string() - Function to convert int to string + * @reject_ap_type: dlm_reject_ap_type + * + * This function is used to convert int value of enum dlm_reject_ap_type + * to string format. + * + * Return: String + * + */ +static const char * +dlm_find_reject_type_string(enum dlm_reject_ap_type reject_ap_type) +{ + switch (reject_ap_type) { + CASE_RETURN_STRING(USERSPACE_AVOID_TYPE); + CASE_RETURN_STRING(USERSPACE_DENYLIST_TYPE); + CASE_RETURN_STRING(DRIVER_AVOID_TYPE); + CASE_RETURN_STRING(DRIVER_DENYLIST_TYPE); + CASE_RETURN_STRING(DRIVER_RSSI_REJECT_TYPE); + CASE_RETURN_STRING(DRIVER_MONITOR_TYPE); + default: + return "REJECT_REASON_UNKNOWN"; + } +} + +/** + * dlm_get_reject_ap_type() - Function to find reject ap type + * @dlm_entry: dlm_reject_ap + * + * This function is used to get reject ap type. + * + * Return: dlm_reject_ap_type + * + */ +static enum dlm_reject_ap_type +dlm_get_reject_ap_type(struct dlm_reject_ap *dlm_entry) +{ + if (DLM_IS_AP_AVOIDED_BY_USERSPACE(dlm_entry)) + return USERSPACE_AVOID_TYPE; + if (DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry)) + return USERSPACE_DENYLIST_TYPE; + if (DLM_IS_AP_AVOIDED_BY_DRIVER(dlm_entry)) + return DRIVER_AVOID_TYPE; + if (DLM_IS_AP_DENYLISTED_BY_DRIVER(dlm_entry)) + return DRIVER_DENYLIST_TYPE; + if (DLM_IS_AP_IN_RSSI_REJECT_LIST(dlm_entry)) + return DRIVER_RSSI_REJECT_TYPE; + if (DLM_IS_AP_IN_MONITOR_LIST(dlm_entry)) + return DRIVER_MONITOR_TYPE; + + return REJECT_REASON_UNKNOWN; +} + +bool dlm_is_bssid_in_reject_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + struct dlm_reject_ap *dlm_entry = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + QDF_STATUS status; + + dlm_ctx = dlm_get_pdev_obj(pdev); + if (!dlm_ctx) { + dlm_err("dlm_ctx is NULL"); + return false; + } + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + if (!dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return false; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return false; + } + + qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node); + while (cur_node) { + qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node, + &next_node); + dlm_entry = + qdf_container_of(cur_node, struct dlm_reject_ap, node); + /* Update the AP info to the latest list first */ + dlm_update_ap_info(dlm_entry, &dlm_psoc_obj->dlm_cfg, NULL); + if (!dlm_entry->reject_ap_type) { + dlm_debug(QDF_MAC_ADDR_FMT " cleared from list", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + qdf_list_remove_node(&dlm_ctx->reject_ap_list, + &dlm_entry->node); + qdf_mem_free(dlm_entry); + cur_node = next_node; + next_node = NULL; + continue; + } + + if (qdf_is_macaddr_equal(&dlm_entry->bssid, bssid)) { + dlm_debug("BSSID reject_ap_type 0x%x", + dlm_entry->reject_ap_type); + if (DLM_IS_AP_IN_DENYLIST(dlm_entry)) { + dlm_debug("BSSID is present in deny list"); + qdf_mutex_release( + &dlm_ctx->reject_ap_list_lock); + return true; + } + qdf_mutex_release( + &dlm_ctx->reject_ap_list_lock); + return false; + } + cur_node = next_node; + next_node = NULL; + } + + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + + return false; +} + +/** + * dlm_dump_denylist_bssid() - Function to dump denylisted bssid + * @pdev: pdev object + * + * This function is used to dump denylisted bssid along with reject + * ap type, source, delay and required rssi + * + * Return: None + * + */ +void dlm_dump_denylist_bssid(struct wlan_objmgr_pdev *pdev) +{ + struct dlm_reject_ap *dlm_entry = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + uint32_t reject_duration; + enum dlm_reject_ap_type reject_ap_type; + qdf_list_t *reject_db_list; + QDF_STATUS status; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return; + } + + reject_db_list = &dlm_ctx->reject_ap_list; + qdf_list_peek_front(reject_db_list, &cur_node); + while (cur_node) { + qdf_list_peek_next(reject_db_list, cur_node, &next_node); + + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + + reject_ap_type = dlm_get_reject_ap_type(dlm_entry); + + reject_duration = dlm_get_delta_of_bssid(reject_ap_type, + dlm_entry, + &dlm_psoc_obj->dlm_cfg); + + dlm_nofl_debug("DENYLIST BSSID " QDF_MAC_ADDR_FMT " type %s retry delay %dms expected RSSI %d reject reason %d rejection source %d", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), + dlm_find_reject_type_string(reject_ap_type), + reject_duration, + dlm_entry->rssi_reject_params.expected_rssi, + dlm_entry->reject_ap_reason, + dlm_entry->rssi_reject_params.source); + cur_node = next_node; + next_node = NULL; + } + + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); +} + +static void dlm_fill_reject_list(qdf_list_t *reject_db_list, + struct reject_ap_config_params *reject_list, + uint8_t *num_of_reject_bssid, + enum dlm_reject_ap_type reject_ap_type, + uint8_t max_bssid_to_be_filled, + struct dlm_config *cfg) +{ + struct dlm_reject_ap *dlm_entry = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + + qdf_list_peek_front(reject_db_list, &cur_node); + while (cur_node) { + if (*num_of_reject_bssid == max_bssid_to_be_filled) { + dlm_debug("Max size reached in list, reject_ap_type %d", + reject_ap_type); + return; + } + qdf_list_peek_next(reject_db_list, cur_node, &next_node); + + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + + dlm_update_ap_info(dlm_entry, cfg, NULL); + if (!dlm_entry->reject_ap_type) { + dlm_debug(QDF_MAC_ADDR_FMT " cleared from list", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + qdf_list_remove_node(reject_db_list, &dlm_entry->node); + qdf_mem_free(dlm_entry); + cur_node = next_node; + next_node = NULL; + continue; + } + + if (dlm_is_bssid_of_type(reject_ap_type, dlm_entry)) { + struct reject_ap_config_params *dlm_reject_list; + + dlm_reject_list = &reject_list[*num_of_reject_bssid]; + dlm_reject_list->expected_rssi = + dlm_entry->rssi_reject_params.expected_rssi; + dlm_reject_list->reject_duration = + dlm_get_delta_of_bssid(reject_ap_type, dlm_entry, + cfg); + + dlm_fill_rssi_reject_params(dlm_entry, reject_ap_type, + dlm_reject_list); + dlm_reject_list->reject_ap_type = reject_ap_type; + dlm_reject_list->bssid = dlm_entry->bssid; + (*num_of_reject_bssid)++; + dlm_debug("Adding BSSID " QDF_MAC_ADDR_FMT " of type %d retry delay %d expected RSSI %d, entries added = %d reject reason %d", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), + reject_ap_type, + reject_list[*num_of_reject_bssid - 1].reject_duration, + dlm_entry->rssi_reject_params.expected_rssi, + *num_of_reject_bssid, + dlm_entry->reject_ap_reason); + } + cur_node = next_node; + next_node = NULL; + } +} + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) +void dlm_update_reject_ap_list_to_fw(struct wlan_objmgr_psoc *psoc) +{ + struct dlm_config *cfg; + struct wlan_objmgr_pdev *pdev; + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + QDF_STATUS status; + + dlm_psoc_obj = dlm_get_psoc_obj(psoc); + if (!dlm_psoc_obj) { + dlm_err("DLM psoc obj NULL"); + return; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, dlm_psoc_obj->pdev_id, + WLAN_MLME_CM_ID); + if (!pdev) { + dlm_err("pdev obj NULL"); + return; + } + + dlm_ctx = dlm_get_pdev_obj(pdev); + if (!dlm_ctx) { + dlm_err("DLM pdev obj NULL"); + goto end; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + goto end; + } + + cfg = &dlm_psoc_obj->dlm_cfg; + dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg); + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + +end: + wlan_objmgr_pdev_release_ref(pdev, WLAN_MLME_CM_ID); +} + +static void dlm_store_pdevid_in_dlm_psocpriv(struct wlan_objmgr_pdev *pdev) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_psoc_obj) { + dlm_err("DLM psoc obj NULL"); + return; + } + + dlm_psoc_obj->pdev_id = pdev->pdev_objmgr.wlan_pdev_id; +} + +void +dlm_send_reject_ap_list_to_fw(struct wlan_objmgr_pdev *pdev, + qdf_list_t *reject_db_list, + struct dlm_config *cfg) +{ + QDF_STATUS status; + bool is_dlm_suspended; + struct reject_ap_params reject_params = {0}; + + ucfg_dlm_psoc_get_suspended(wlan_pdev_get_psoc(pdev), + &is_dlm_suspended); + if (is_dlm_suspended) { + dlm_store_pdevid_in_dlm_psocpriv(pdev); + dlm_debug("Failed to send reject AP list to FW as DLM is suspended"); + return; + } + + reject_params.bssid_list = + qdf_mem_malloc(sizeof(*reject_params.bssid_list) * + PDEV_MAX_NUM_BSSID_DISALLOW_LIST); + if (!reject_params.bssid_list) + return; + + /* The priority for filling is as below */ + dlm_fill_reject_list(reject_db_list, reject_params.bssid_list, + &reject_params.num_of_reject_bssid, + USERSPACE_DENYLIST_TYPE, + PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg); + dlm_fill_reject_list(reject_db_list, reject_params.bssid_list, + &reject_params.num_of_reject_bssid, + DRIVER_DENYLIST_TYPE, + PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg); + dlm_fill_reject_list(reject_db_list, reject_params.bssid_list, + &reject_params.num_of_reject_bssid, + DRIVER_RSSI_REJECT_TYPE, + PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg); + dlm_fill_reject_list(reject_db_list, reject_params.bssid_list, + &reject_params.num_of_reject_bssid, + USERSPACE_AVOID_TYPE, + PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg); + dlm_fill_reject_list(reject_db_list, reject_params.bssid_list, + &reject_params.num_of_reject_bssid, + DRIVER_AVOID_TYPE, + PDEV_MAX_NUM_BSSID_DISALLOW_LIST, cfg); + + status = tgt_dlm_send_reject_list_to_fw(pdev, &reject_params); + + if (QDF_IS_STATUS_ERROR(status)) + dlm_err("failed to send the reject Ap list to FW"); + + qdf_mem_free(reject_params.bssid_list); +} +#endif + +QDF_STATUS +dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + struct dlm_config *cfg; + struct dlm_reject_ap *dlm_entry; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + QDF_STATUS status; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qdf_is_macaddr_zero(&ap_info->bssid) || + qdf_is_macaddr_group(&ap_info->bssid)) { + dlm_err("Zero/Broadcast BSSID received, entry not added"); + return QDF_STATUS_E_INVAL; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return status; + } + + cfg = &dlm_psoc_obj->dlm_cfg; + + qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(&dlm_ctx->reject_ap_list, + cur_node, &next_node); + + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + + /* Update the AP info to the latest list first */ + dlm_update_ap_info(dlm_entry, cfg, NULL); + if (!dlm_entry->reject_ap_type) { + dlm_debug(QDF_MAC_ADDR_FMT " cleared from list", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + qdf_list_remove_node(&dlm_ctx->reject_ap_list, + &dlm_entry->node); + qdf_mem_free(dlm_entry); + cur_node = next_node; + next_node = NULL; + continue; + } + + if (qdf_is_macaddr_equal(&dlm_entry->bssid, &ap_info->bssid)) { + dlm_modify_entry(dlm_entry, cfg, ap_info); + goto end; + } + + cur_node = next_node; + next_node = NULL; + } + + if (qdf_list_size(&dlm_ctx->reject_ap_list) == MAX_BAD_AP_LIST_SIZE) { + /* List is FULL, need to delete entries */ + status = + dlm_remove_lowest_delta_entry(&dlm_ctx->reject_ap_list, + cfg); + + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + return status; + } + } + + dlm_entry = qdf_mem_malloc(sizeof(*dlm_entry)); + if (!dlm_entry) { + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + return QDF_STATUS_E_FAILURE; + } + + qdf_list_insert_back(&dlm_ctx->reject_ap_list, &dlm_entry->node); + dlm_modify_entry(dlm_entry, cfg, ap_info); + +end: + dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg); + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +dlm_clear_userspace_denylist_info(struct wlan_objmgr_pdev *pdev) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_reject_ap *dlm_entry; + QDF_STATUS status; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + + dlm_ctx = dlm_get_pdev_obj(pdev); + if (!dlm_ctx) { + dlm_err("dlm_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return QDF_STATUS_E_RESOURCES; + } + + qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node, + &next_node); + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + + if (IS_AP_IN_USERSPACE_DENYLIST_ONLY(dlm_entry)) { + dlm_debug("removing bssid: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + qdf_list_remove_node(&dlm_ctx->reject_ap_list, + &dlm_entry->node); + qdf_mem_free(dlm_entry); + } else if (DLM_IS_AP_DENYLISTED_BY_USERSPACE(dlm_entry)) { + dlm_debug("Clearing userspace denylist bit for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + dlm_entry->userspace_denylist = false; + dlm_entry->denylist_userspace = false; + } + cur_node = next_node; + next_node = NULL; + } + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +dlm_add_userspace_deny_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid_deny_list, + uint8_t num_of_bssid) +{ + uint8_t i = 0; + struct reject_ap_info ap_info; + QDF_STATUS status; + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + struct dlm_config *cfg; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* Clear all the info of APs already existing in DLM first */ + dlm_clear_userspace_denylist_info(pdev); + cfg = &dlm_psoc_obj->dlm_cfg; + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return status; + } + + dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg); + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + + if (!bssid_deny_list || !num_of_bssid) { + dlm_debug("Userspace denylist/num of denylist NULL"); + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < num_of_bssid; i++) { + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + ap_info.bssid = bssid_deny_list[i]; + ap_info.reject_ap_type = USERSPACE_DENYLIST_TYPE; + ap_info.source = ADDED_BY_DRIVER; + ap_info.reject_reason = REASON_USERSPACE_BL; + status = dlm_add_bssid_to_reject_list(pdev, &ap_info); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("Failed to add bssid to userspace denylist"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +void +dlm_flush_reject_ap_list(struct dlm_pdev_priv_obj *dlm_ctx) +{ + struct dlm_reject_ap *dlm_entry = NULL; + QDF_STATUS status; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return; + } + + qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node, + &next_node); + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + qdf_list_remove_node(&dlm_ctx->reject_ap_list, + &dlm_entry->node); + qdf_mem_free(dlm_entry); + cur_node = next_node; + next_node = NULL; + } + + dlm_debug("DLM reject ap list flushed"); + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); +} + +uint8_t +dlm_get_bssid_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_config_params *reject_list, + uint8_t max_bssid_to_be_filled, + enum dlm_reject_ap_type reject_ap_type) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + uint8_t num_of_reject_bssid = 0; + QDF_STATUS status; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return 0; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return 0; + } + + dlm_fill_reject_list(&dlm_ctx->reject_ap_list, reject_list, + &num_of_reject_bssid, reject_ap_type, + max_bssid_to_be_filled, &dlm_psoc_obj->dlm_cfg); + + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + + return num_of_reject_bssid; +} + +void +dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + QDF_STATUS status; + struct dlm_reject_ap *dlm_entry = NULL; + qdf_time_t connection_age = 0; + bool entry_found = false; + qdf_time_t max_entry_time; + qdf_time_t bad_bssid_reset_time; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return; + } + + qdf_list_peek_front(&dlm_ctx->reject_ap_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(&dlm_ctx->reject_ap_list, cur_node, + &next_node); + dlm_entry = qdf_container_of(cur_node, struct dlm_reject_ap, + node); + if (!dlm_entry && next_node) { + cur_node = next_node; + next_node = NULL; + continue; + } + + if (!qdf_mem_cmp(dlm_entry->bssid.bytes, bssid.bytes, + QDF_MAC_ADDR_SIZE)) { + dlm_debug(QDF_MAC_ADDR_FMT " present in DLM reject list, updating connect info con_state = %d", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes), + con_state); + entry_found = true; + break; + } + cur_node = next_node; + next_node = NULL; + } + + /* This means that the BSSID was not added in the reject list of DLM */ + if (!entry_found || !dlm_entry) { + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); + return; + } + switch (con_state) { + case DLM_AP_CONNECTED: + dlm_entry->connect_timestamp = qdf_mc_timer_get_system_time(); + break; + case DLM_AP_DISCONNECTED: + /* Update the dlm info first */ + dlm_update_ap_info(dlm_entry, &dlm_psoc_obj->dlm_cfg, NULL); + + max_entry_time = dlm_entry->connect_timestamp; + if (dlm_entry->driver_denylist) { + max_entry_time = + dlm_entry->ap_timestamp.driver_denylist_timestamp; + } else if (dlm_entry->driver_avoidlist) { + max_entry_time = + QDF_MAX(dlm_entry->ap_timestamp.driver_avoid_timestamp, + dlm_entry->connect_timestamp); + } + connection_age = qdf_mc_timer_get_system_time() - + max_entry_time; + bad_bssid_reset_time = + dlm_psoc_obj->dlm_cfg.bad_bssid_counter_reset_time; + if (connection_age > SECONDS_TO_MS(bad_bssid_reset_time)) { + dlm_entry->driver_avoidlist = false; + dlm_entry->driver_denylist = false; + dlm_entry->driver_monitorlist = false; + dlm_entry->userspace_avoidlist = false; + dlm_debug("updated reject ap type %d ", + dlm_entry->reject_ap_type); + if (!dlm_entry->reject_ap_type) { + dlm_debug("Bad Bssid timer expired/AP cleared from all denylisting, removed " QDF_MAC_ADDR_FMT " from list", + QDF_MAC_ADDR_REF(dlm_entry->bssid.bytes)); + qdf_list_remove_node(&dlm_ctx->reject_ap_list, + &dlm_entry->node); + qdf_mem_free(dlm_entry); + dlm_send_reject_ap_list_to_fw(pdev, + &dlm_ctx->reject_ap_list, + &dlm_psoc_obj->dlm_cfg); + } + } + break; + default: + dlm_debug("Invalid AP connection state received %d", con_state); + }; + + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); +} + +int32_t dlm_get_rssi_denylist_threshold(struct wlan_objmgr_pdev *pdev) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + struct dlm_config *cfg; + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return 0; + } + + cfg = &dlm_psoc_obj->dlm_cfg; + return cfg->delta_rssi; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_main.c b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_main.c new file mode 100644 index 0000000000..75cf699c67 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/core/src/wlan_dlm_main.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_dlm_main.c + * + * WLAN Denylist Mgr related APIs + * + */ + +/* Include files */ + +#include "target_if_dlm.h" +#include +#include "cfg_ucfg_api.h" +#include + +struct dlm_pdev_priv_obj * +dlm_get_pdev_obj(struct wlan_objmgr_pdev *pdev) +{ + struct dlm_pdev_priv_obj *dlm_pdev_obj; + + dlm_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_DENYLIST_MGR); + + return dlm_pdev_obj; +} + +struct dlm_psoc_priv_obj * +dlm_get_psoc_obj(struct wlan_objmgr_psoc *psoc) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + + dlm_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_DENYLIST_MGR); + + return dlm_psoc_obj; +} + +QDF_STATUS +dlm_pdev_object_created_notification(struct wlan_objmgr_pdev *pdev, + void *arg) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + QDF_STATUS status; + + dlm_ctx = qdf_mem_malloc(sizeof(*dlm_ctx)); + + if (!dlm_ctx) + return QDF_STATUS_E_FAILURE; + + status = qdf_mutex_create(&dlm_ctx->reject_ap_list_lock); + + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("Failed to create mutex"); + qdf_mem_free(dlm_ctx); + return status; + } + qdf_list_create(&dlm_ctx->reject_ap_list, MAX_BAD_AP_LIST_SIZE); + + target_if_dlm_register_tx_ops(&dlm_ctx->dlm_tx_ops); + status = wlan_objmgr_pdev_component_obj_attach(pdev, + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_ctx, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("Failed to attach pdev_ctx with pdev"); + qdf_list_destroy(&dlm_ctx->reject_ap_list); + qdf_mutex_destroy(&dlm_ctx->reject_ap_list_lock); + qdf_mem_free(dlm_ctx); + } + + return status; +} + +QDF_STATUS +dlm_pdev_object_destroyed_notification(struct wlan_objmgr_pdev *pdev, + void *arg) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + + dlm_ctx = dlm_get_pdev_obj(pdev); + + if (!dlm_ctx) { + dlm_err("DLM Pdev obj is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* Clear away the memory allocated for the bad BSSIDs */ + dlm_flush_reject_ap_list(dlm_ctx); + qdf_list_destroy(&dlm_ctx->reject_ap_list); + qdf_mutex_destroy(&dlm_ctx->reject_ap_list_lock); + + wlan_objmgr_pdev_component_obj_detach(pdev, + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_ctx); + qdf_mem_free(dlm_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +dlm_psoc_object_created_notification(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + QDF_STATUS status; + + dlm_psoc_obj = qdf_mem_malloc(sizeof(*dlm_psoc_obj)); + + if (!dlm_psoc_obj) + return QDF_STATUS_E_FAILURE; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("Failed to attach psoc_ctx with psoc"); + qdf_mem_free(dlm_psoc_obj); + } + + return status; +} + +QDF_STATUS +dlm_psoc_object_destroyed_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + + dlm_psoc_obj = dlm_get_psoc_obj(psoc); + + if (!dlm_psoc_obj) { + dlm_err("DLM psoc obj NULL"); + return QDF_STATUS_E_FAILURE; + } + wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_obj); + qdf_mem_free(dlm_psoc_obj); + + return QDF_STATUS_SUCCESS; +} + +static void +dlm_init_cfg(struct wlan_objmgr_psoc *psoc, struct dlm_config *dlm_cfg) +{ + dlm_cfg->avoid_list_exipry_time = + cfg_get(psoc, CFG_AVOID_LIST_EXPIRY_TIME); + dlm_cfg->deny_list_exipry_time = + cfg_get(psoc, CFG_DENY_LIST_EXPIRY_TIME); + dlm_cfg->bad_bssid_counter_reset_time = + cfg_get(psoc, CFG_BAD_BSSID_RESET_TIME); + dlm_cfg->bad_bssid_counter_thresh = + cfg_get(psoc, CFG_BAD_BSSID_COUNTER_THRESHOLD); + dlm_cfg->delta_rssi = + cfg_get(psoc, CFG_DENYLIST_RSSI_THRESHOLD); +} + +QDF_STATUS +dlm_cfg_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + + dlm_psoc_obj = dlm_get_psoc_obj(psoc); + + if (!dlm_psoc_obj) { + dlm_err("DLM psoc obj NULL"); + return QDF_STATUS_E_FAILURE; + } + + dlm_init_cfg(psoc, &dlm_psoc_obj->dlm_cfg); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/cfg_dlm.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/cfg_dlm.h new file mode 100644 index 0000000000..24df175057 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/cfg_dlm.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains ini params for denylist mgr component + */ + +#ifndef __CFG_DLM_H_ +#define __CFG_DLM_H_ + +#ifdef FEATURE_DENYLIST_MGR + +/* + * + * avoid_list_expiry_time - Config Param to move AP from avoid to monitor list. + * @Min: 1 minutes + * @Max: 300 minutes + * @Default: 5 minutes + * + * This ini is used to specify the time after which the BSSID which is in the + * avoid list should be moved to monitor list, assuming that the AP or the + * gateway with which the data stall happenend might have recovered, and now + * the STA can give another chance to connect to the AP. + * + * Supported Feature: Data Stall Recovery + * + * Usage: External + * + * + */ +#define CFG_AVOID_LIST_EXPIRY_TIME CFG_INI_UINT( \ + "avoid_list_expiry_time", \ + 1, \ + 300, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "avoid list expiry") + +/* + * + * bad_bssid_counter_thresh - Threshold to move the Ap from avoid to denylist. + * @Min: 2 + * @Max: 100 + * @Default: 3 + * + * This ini is used to specify the threshld after which the BSSID which is in + * the avoid list should be moved to deny list, assuming that the AP or the + * gateway with which the data stall happenend has no recovered, and now + * the STA got the NUD failure again with the BSSID + * + * Supported Feature: Data Stall Recovery + * + * Usage: External + * + * + */ +#define CFG_BAD_BSSID_COUNTER_THRESHOLD CFG_INI_UINT( \ + "bad_bssid_counter_thresh", \ + 2, \ + 100, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "bad bssid counter thresh") + +/* + * + * deny_list_expiry_time - Config Param to move AP from denylist to monitor + * list. + * @Min: 1 minutes + * @Max: 600 minutes + * @Default: 10 minutes + * + * This ini is used to specify the time after which the BSSID which is in the + * deny list should be moved to monitor list, assuming that the AP or the + * gateway with which the data stall happenend might have recovered, and now + * the STA can give another chance to connect to the AP. + * + * Supported Feature: Data Stall Recovery + * + * Usage: External + * + * + */ +#define CFG_DENY_LIST_EXPIRY_TIME CFG_INI_UINT( \ + "black_list_expiry_time", \ + 1, \ + 600, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "deny list expiry") + +/* + * + * bad_bssid_reset_time - Config Param to specify time after which AP would be + * removed from monitor/avoid when connected. + * @Min: 30 seconds + * @Max: 1 minute + * @Default: 30 seconds + * + * This ini is used to specify the time after which the BSSID which is in the + * avoid or monitor list should be removed from the respective list, if the + * data stall has not happened till the mentioned time after connection to the + * AP. That means that the AP has recovered from the previous state where + * data stall was observed with it, and was moved to avoid list. + * + * Supported Feature: Data Stall Recovery + * + * Usage: External + * + * + */ +#define CFG_BAD_BSSID_RESET_TIME CFG_INI_UINT( \ + "bad_bssid_reset_time", \ + 30, \ + 60, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "bad bssid reset time") + +/* + * + * delta_rssi - RSSI threshold value, only when AP rssi improves + * by threshold value entry would be removed from denylist manager and assoc + * req would be sent by FW. + * @Min: 0 + * @Max: 10 + * @Default: 5 + * + * This ini is used to specify the rssi threshold value, after rssi improves + * by threshold the BSSID which is in the denylist manager list should be + * removed from the respective list. + * + * Supported Feature: Customer requirement + * + * Usage: Internal/External + * + * + */ +#define CFG_DENYLIST_RSSI_THRESHOLD CFG_INI_INT( \ + "delta_rssi", \ + 0, \ + 10, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure delta RSSI") + +#define CFG_DENYLIST_MGR_ALL \ + CFG(CFG_AVOID_LIST_EXPIRY_TIME) \ + CFG(CFG_BAD_BSSID_COUNTER_THRESHOLD) \ + CFG(CFG_DENY_LIST_EXPIRY_TIME) \ + CFG(CFG_BAD_BSSID_RESET_TIME) \ + CFG(CFG_DENYLIST_RSSI_THRESHOLD) + +#else + +#define CFG_DENYLIST_MGR_ALL + +#endif /* FEATURE_DENYLIST_MGR */ + +#endif /* __CFG_DENYLIST_MGR */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_api.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_api.h new file mode 100644 index 0000000000..0da5212aa5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_api.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare public APIs exposed by the denylist manager component + */ + +#ifndef _WLAN_DLM_API_H_ +#define _WLAN_DLM_API_H_ + +#include "qdf_types.h" +#include "wlan_objmgr_pdev_obj.h" +#include + +#ifdef FEATURE_DENYLIST_MGR +#include "wlan_dlm_core.h" + +/** + * wlan_dlm_add_bssid_to_reject_list() - Add BSSID to the specific reject list. + * @pdev: Pdev object + * @ap_info: Ap info params such as BSSID, and the type of rejection to be done + * + * This API will add the BSSID to the reject AP list maintained by the denylist + * manager. + */ +static inline QDF_STATUS +wlan_dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info) +{ + return dlm_add_bssid_to_reject_list(pdev, ap_info); +} + +/** + * wlan_dlm_update_bssid_connect_params() - Inform the DLM about connect or + * disconnect with the current AP. + * @pdev: pdev object + * @bssid: BSSID of the AP + * @con_state: Connection state (connected/disconnected) + * + * This API will inform the DLM about the state with the AP so that if the AP + * is selected, and the connection went through, and the connection did not + * face any data stall till the bad bssid reset timer, DLM can remove the + * AP from the reject ap list maintained by it. + * + * Return: None + */ +static inline void +wlan_dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state) +{ + return dlm_update_bssid_connect_params(pdev, bssid, con_state); +} + +/** + * wlan_dlm_get_bssid_reject_list() - Get the BSSIDs in reject list from DLM + * @pdev: pdev object + * @reject_list: reject list to be filled (passed by caller) + * @max_bssid_to_be_filled: num of bssids filled in reject list by DLM + * @reject_ap_type: reject ap type of the BSSIDs to be filled. + * + * This API is a wrapper to an API of denylist manager which will fill the + * reject ap list requested by caller of type given as argument reject_ap_type, + * and will return the number of BSSIDs filled. + * + * Return: Unsigned integer (number of BSSIDs filled by the denylist manager) + */ +static inline uint8_t +wlan_dlm_get_bssid_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_config_params *reject_list, + uint8_t max_bssid_to_be_filled, + enum dlm_reject_ap_type reject_ap_type) +{ + return dlm_get_bssid_reject_list(pdev, reject_list, + max_bssid_to_be_filled, + reject_ap_type); +} + +/** + * wlan_dlm_is_bssid_in_reject_list() - Check whether a BSSID is present in + * reject list or not + * @pdev: pdev object + * @bssid: bssid to check + * + * Return: true if BSSID is present in reject list + */ +static inline bool +wlan_dlm_is_bssid_in_reject_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid) +{ + return dlm_is_bssid_in_reject_list(pdev, bssid); +} + +/** + * wlan_dlm_dump_denylist_bssid() - dump the denylisted BSSIDs from DLM + * @pdev: pdev object + * + * Return: None + */ +static inline void +wlan_dlm_dump_denylist_bssid(struct wlan_objmgr_pdev *pdev) +{ + return dlm_dump_denylist_bssid(pdev); +} + +/** + * wlan_dlm_get_rssi_denylist_threshold() - Get the RSSI denylist threshold + * @pdev: pdev object + * + * This API will get the rssi denylist threshold value configured via + * CFG_DENYLIST_RSSI_THRESHOLD. + * + * Return: int32_t (threshold value) + */ +static inline int32_t +wlan_dlm_get_rssi_denylist_threshold(struct wlan_objmgr_pdev *pdev) +{ + return dlm_get_rssi_denylist_threshold(pdev); +} + +#else +static inline bool +wlan_dlm_is_bssid_in_reject_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid) +{ + return false; +} + +static inline QDF_STATUS +wlan_dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t +wlan_dlm_get_bssid_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_config_params *reject_list, + uint8_t max_bssid_to_be_filled, + enum dlm_reject_ap_type reject_ap_type) +{ + return 0; +} + +static inline void +wlan_dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state) +{ +} + +static inline int32_t +wlan_dlm_get_rssi_denylist_threshold(struct wlan_objmgr_pdev *pdev) +{ + return 0; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_public_struct.h new file mode 100644 index 0000000000..239fe2d105 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_public_struct.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define public structures of denylist mgr. + */ + +#ifndef _WLAN_DLM_PUBLIC_STRUCT_H +#define _WLAN_DLM_PUBLIC_STRUCT_H + +#include +#include "wlan_objmgr_pdev_obj.h" + +#define MAX_BAD_AP_LIST_SIZE 28 +#define MAX_RSSI_AVOID_BSSID_LIST 10 +#define PDEV_MAX_NUM_BSSID_DISALLOW_LIST 28 + +/** + * enum dlm_reject_ap_source - Source of adding BSSID to DLM + * @ADDED_BY_DRIVER: Source adding this BSSID is driver + * @ADDED_BY_TARGET: Source adding this BSSID is target + */ +enum dlm_reject_ap_source { + ADDED_BY_DRIVER = 1, + ADDED_BY_TARGET, +}; + +/** + * struct dlm_rssi_disallow_params - structure to specify params for RSSI + * reject + * @retry_delay: Time before which the AP doesn't expect a connection. + * @expected_rssi: RSSI less than which only the STA should try association + * @received_time: Time at which the AP was added to denylist. + * @original_timeout: Original timeout which the AP sent while denylisting. + * @source: Source of adding this BSSID to RSSI reject list + */ +struct dlm_rssi_disallow_params { + uint32_t retry_delay; + int8_t expected_rssi; + qdf_time_t received_time; + uint32_t original_timeout; + enum dlm_reject_ap_source source; +}; + +/** + * enum dlm_reject_ap_type - Rejection type of the AP + * @USERSPACE_AVOID_TYPE: userspace wants the AP to be avoided. + * @USERSPACE_DENYLIST_TYPE: userspace wants the AP to be denylisted. + * @DRIVER_AVOID_TYPE: driver wants the AP to be avoided. + * @DRIVER_DENYLIST_TYPE: driver wants the AP to be denylisted. + * @DRIVER_RSSI_REJECT_TYPE: driver wants the AP to be in driver rssi + * reject. + * @DRIVER_MONITOR_TYPE: driver wants the AP to be in monitor list. + * @REJECT_REASON_UNKNOWN: Rejection reason unknown + */ +enum dlm_reject_ap_type { + USERSPACE_AVOID_TYPE = 0, + USERSPACE_DENYLIST_TYPE = 1, + DRIVER_AVOID_TYPE = 2, + DRIVER_DENYLIST_TYPE = 3, + DRIVER_RSSI_REJECT_TYPE = 4, + DRIVER_MONITOR_TYPE = 5, + REJECT_REASON_UNKNOWN = 6, +}; + +/** + * enum dlm_reject_ap_reason - Rejection reason for adding BSSID to DLM + * @REASON_UNKNOWN: Unknown reason + * @REASON_NUD_FAILURE: NUD failure happened with this BSSID + * @REASON_STA_KICKOUT: STA kickout happened with this BSSID + * @REASON_ROAM_HO_FAILURE: HO failure happenend with this BSSID + * @REASON_ASSOC_REJECT_POOR_RSSI: assoc rsp with reason 71 received from + * AP. + * @REASON_ASSOC_REJECT_OCE: OCE assoc reject received from the AP. + * @REASON_USERSPACE_BL: Userspace wants to denylist this AP. + * @REASON_USERSPACE_AVOID_LIST: Userspace wants to avoid this AP. + * @REASON_BTM_DISASSOC_IMMINENT: BTM IE received with disassoc imminent + * set. + * @REASON_BTM_BSS_TERMINATION: BTM IE received with BSS termination set. + * @REASON_BTM_MBO_RETRY: BTM IE received from AP with MBO retry set. + * @REASON_REASSOC_RSSI_REJECT: Re-Assoc resp received with reason code 34 + * @REASON_REASSOC_NO_MORE_STAS: Re-assoc reject received with reason code + * 17 + */ +enum dlm_reject_ap_reason { + REASON_UNKNOWN = 0, + REASON_NUD_FAILURE, + REASON_STA_KICKOUT, + REASON_ROAM_HO_FAILURE, + REASON_ASSOC_REJECT_POOR_RSSI, + REASON_ASSOC_REJECT_OCE, + REASON_USERSPACE_BL, + REASON_USERSPACE_AVOID_LIST, + REASON_BTM_DISASSOC_IMMINENT, + REASON_BTM_BSS_TERMINATION, + REASON_BTM_MBO_RETRY, + REASON_REASSOC_RSSI_REJECT, + REASON_REASSOC_NO_MORE_STAS, +}; + +/** + * enum dlm_connection_state - State with AP (Connected, Disconnected) + * @DLM_AP_CONNECTED: Connected with the AP + * @DLM_AP_DISCONNECTED: Disconnected with the AP + */ +enum dlm_connection_state { + DLM_AP_CONNECTED, + DLM_AP_DISCONNECTED, +}; + +/** + * struct reject_ap_config_params - Structure to send reject ap list to FW + * @bssid: BSSID of the AP + * @reject_ap_type: Type of the rejection done with the BSSID + * @reject_duration: time left till the AP is in the reject list. + * @expected_rssi: expected RSSI when the AP expects the connection to be + * made. + * @reject_reason: reason to add the BSSID to DLM + * @source: Source of adding the BSSID to DLM + * @received_time: Time at which the AP was added to denylist. + * @original_timeout: Original timeout which the AP sent while denylisting. + */ +struct reject_ap_config_params { + struct qdf_mac_addr bssid; + enum dlm_reject_ap_type reject_ap_type; + uint32_t reject_duration; + int32_t expected_rssi; + enum dlm_reject_ap_reason reject_reason; + enum dlm_reject_ap_source source; + qdf_time_t received_time; + uint32_t original_timeout; +}; + +/** + * struct reject_ap_params - Struct to send bssid list and there num to FW + * @num_of_reject_bssid: num of bssid params there in bssid config. + * @bssid_list: Pointer to the bad bssid list + */ +struct reject_ap_params { + uint8_t num_of_reject_bssid; + struct reject_ap_config_params *bssid_list; +}; + +/** + * struct wlan_dlm_tx_ops - structure of tx operation function + * pointers for denylist manager component + * @dlm_send_reject_ap_list: send reject ap list to fw + */ +struct wlan_dlm_tx_ops { + QDF_STATUS (*dlm_send_reject_ap_list)(struct wlan_objmgr_pdev *pdev, + struct reject_ap_params *reject_params); +}; + +/** + * struct reject_ap_info - structure to specify the reject ap info. + * @bssid: BSSID of the AP. + * @rssi_reject_params: RSSI reject params of the AP is of type RSSI reject + * @reject_ap_type: Reject type of AP (eg. avoid, denylist, rssi reject + * etc.) + * @reject_reason: reason to add the BSSID to DLM + * @source: Source of adding the BSSID to DLM + */ +struct reject_ap_info { + struct qdf_mac_addr bssid; + struct dlm_rssi_disallow_params rssi_reject_params; + enum dlm_reject_ap_type reject_ap_type; + enum dlm_reject_ap_reason reject_reason; + enum dlm_reject_ap_source source; +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_tgt_api.h new file mode 100644 index 0000000000..234c7f79a9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_tgt_api.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare public API for denylist manager to interact with target/WMI + */ + +#ifndef _WLAN_DLM_TGT_API_H +#define _WLAN_DLM_TGT_API_H + +#include "wlan_dlm_main.h" + +/** + * tgt_dlm_send_reject_list_to_fw() - API to send the reject ap list to FW. + * @pdev: pdev object + * @reject_params: Reject params contains the bssid list, and num of bssids + * + * This API will send the reject AP list maintained by the denylist manager + * to the target. + * + * Return: QDF status + */ +QDF_STATUS +tgt_dlm_send_reject_list_to_fw(struct wlan_objmgr_pdev *pdev, + struct reject_ap_params *reject_params); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_ucfg_api.h new file mode 100644 index 0000000000..b16eda531d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/inc/wlan_dlm_ucfg_api.h @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare UCFG APIs exposed by the denylist manager component + */ + +#ifndef _WLAN_DLM_UCFG_H_ +#define _WLAN_DLM_UCFG_H_ + +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" +#include + +#ifdef FEATURE_DENYLIST_MGR + +/** + * ucfg_dlm_init() - initialize denylist mgr context + * + * This function initializes the denylist mgr context + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_dlm_init(void); + +/** + * ucfg_dlm_deinit() - De initialize denylist mgr context + * + * This function De initializes denylist mgr context + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_dlm_deinit(void); + +/** + * ucfg_dlm_psoc_set_suspended() - API to set denylist mgr state suspended + * @psoc: pointer to psoc object + * @state: state to be set + * + * This function sets denylist mgr state to suspended + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_dlm_psoc_set_suspended(struct wlan_objmgr_psoc *psoc, + bool state); + +/** + * ucfg_dlm_psoc_get_suspended() - API to get denylist mgr state suspended + * @psoc: pointer to psoc object + * @state: pointer to get suspend state of denylist manager + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_dlm_psoc_get_suspended(struct wlan_objmgr_psoc *psoc, + bool *state); + +/** + * ucfg_dlm_psoc_open() - API to initialize the cfg when psoc is initialized. + * @psoc: psoc object + * + * This function initializes the config of denylist mgr. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_dlm_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dlm_psoc_close() - API to deinit the dlm when psoc is deinitialized. + * @psoc: psoc object + * + * This function deinits the dlm psoc object. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_dlm_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dlm_add_userspace_deny_list() - Clear already existing userspace BSSID, + * and add the new ones to denylist manager. + * @pdev: pdev object + * @bssid_deny_list: BSSIDs to be denylisted by userspace. + * @num_of_bssid: num of bssids to be denylisted. + * + * This API clear already existing userspace BSSID, and add the new ones to + * denylist manager + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error. + */ +QDF_STATUS +ucfg_dlm_add_userspace_deny_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid_deny_list, + uint8_t num_of_bssid); + +/** + * ucfg_dlm_dump_deny_list_ap() - get denylisted bssid. + * @pdev: pdev object + * + * This API dumps denylist ap + * + * Return: None + */ +void ucfg_dlm_dump_deny_list_ap(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_dlm_update_bssid_connect_params() - Inform the DLM about connect or + * disconnect with the current AP. + * @pdev: pdev object + * @bssid: BSSID of the AP + * @con_state: Connection state (connected/disconnected) + * + * This API will inform the DLM about the state with the AP so that if the AP + * is selected, and the connection went through, and the connection did not + * face any data stall till the bad bssid reset timer, DLM can remove the + * AP from the reject ap list maintained by it. + * + * Return: None + */ +void +ucfg_dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state); + +/** + * ucfg_dlm_add_bssid_to_reject_list() - Add BSSID to the specific reject list. + * @pdev: Pdev object + * @ap_info: Ap info params such as BSSID, and the type of rejection to be done + * + * This API will add the BSSID to the reject AP list maintained by the denylist + * manager. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error. + */ +QDF_STATUS +ucfg_dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info); + +/** + * ucfg_dlm_wifi_off() - Inform the denylist manager about wifi off + * @pdev: Pdev object + * + * This API will inform the denylist manager that the user has turned wifi off + * from the UI, and the denylist manager can take action based upon this. + * + * Return: None + */ +void +ucfg_dlm_wifi_off(struct wlan_objmgr_pdev *pdev); + +#else +static inline +QDF_STATUS ucfg_dlm_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_dlm_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_dlm_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_dlm_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_dlm_dump_deny_list_ap(struct wlan_objmgr_pdev *pdev) +{} + +static inline +QDF_STATUS +ucfg_dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_dlm_add_userspace_deny_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid_deny_list, + uint8_t num_of_bssid) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state) +{ +} + +static inline +void ucfg_dlm_wifi_off(struct wlan_objmgr_pdev *pdev) +{ +} + +#endif +#endif /* _WLAN_DLM_UCFG_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/src/wlan_dlm_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/src/wlan_dlm_tgt_api.c new file mode 100644 index 0000000000..3e72423ef7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/src/wlan_dlm_tgt_api.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implements public API for denylist manager to interact with target/WMI + */ + +#include "wlan_dlm_tgt_api.h" + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS +tgt_dlm_send_reject_list_to_fw(struct wlan_objmgr_pdev *pdev, + struct reject_ap_params *reject_params) +{ + struct wlan_dlm_tx_ops *dlm_tx_ops; + struct dlm_pdev_priv_obj *dlm_priv; + + dlm_priv = dlm_get_pdev_obj(pdev); + + if (!dlm_priv) { + dlm_err("dlm_priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + dlm_tx_ops = &dlm_priv->dlm_tx_ops; + if (!dlm_tx_ops) { + dlm_err("dlm_tx_ops is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (dlm_tx_ops->dlm_send_reject_ap_list) + return dlm_tx_ops->dlm_send_reject_ap_list(pdev, reject_params); + dlm_err("Tx ops not registered, failed to send reject list to FW"); + + return QDF_STATUS_E_FAILURE; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/src/wlan_dlm_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/src/wlan_dlm_ucfg_api.c new file mode 100644 index 0000000000..41648a7f54 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/denylist_mgr/dispatcher/src/wlan_dlm_ucfg_api.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define UCFG APIs exposed by the denylist mgr component + */ + +#include +#include +#include +#include "wlan_pmo_obj_mgmt_api.h" + +QDF_STATUS ucfg_dlm_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_pdev_create_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_pdev_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("pdev create register notification failed"); + goto fail_create_pdev; + } + + status = wlan_objmgr_register_pdev_destroy_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_pdev_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("pdev destroy register notification failed"); + goto fail_destroy_pdev; + } + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("psoc create register notification failed"); + goto fail_create_psoc; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("psoc destroy register notification failed"); + goto fail_destroy_psoc; + } + + return QDF_STATUS_SUCCESS; + +fail_destroy_psoc: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_object_created_notification, NULL); +fail_create_psoc: + wlan_objmgr_unregister_pdev_destroy_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_pdev_object_destroyed_notification, NULL); +fail_destroy_pdev: + wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_pdev_object_created_notification, NULL); +fail_create_pdev: + return status; +} + +QDF_STATUS ucfg_dlm_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_object_destroyed_notification, + NULL); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_psoc_object_created_notification, + NULL); + + status = wlan_objmgr_unregister_pdev_destroy_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_pdev_object_destroyed_notification, + NULL); + + status = wlan_objmgr_unregister_pdev_create_handler( + WLAN_UMAC_COMP_DENYLIST_MGR, + dlm_pdev_object_created_notification, + NULL); + + return status; +} + +QDF_STATUS ucfg_dlm_psoc_set_suspended(struct wlan_objmgr_psoc *psoc, + bool state) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + + dlm_psoc_obj = dlm_get_psoc_obj(psoc); + + if (!dlm_psoc_obj) { + dlm_err("DLM psoc obj NULL"); + return QDF_STATUS_E_FAILURE; + } + + dlm_psoc_obj->is_suspended = state; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_dlm_psoc_get_suspended(struct wlan_objmgr_psoc *psoc, + bool *state) +{ + struct dlm_psoc_priv_obj *dlm_psoc_obj; + + dlm_psoc_obj = dlm_get_psoc_obj(psoc); + + if (!dlm_psoc_obj) { + dlm_err("DLM psoc obj NULL"); + *state = true; + return QDF_STATUS_E_FAILURE; + } + + *state = dlm_psoc_obj->is_suspended; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ucfg_dlm_suspend_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + ucfg_dlm_psoc_set_suspended(psoc, true); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ucfg_dlm_resume_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + ucfg_dlm_psoc_set_suspended(psoc, false); + dlm_update_reject_ap_list_to_fw(psoc); + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_dlm_register_pmo_handler(void) +{ + pmo_register_suspend_handler(WLAN_UMAC_COMP_DENYLIST_MGR, + ucfg_dlm_suspend_handler, NULL); + pmo_register_resume_handler(WLAN_UMAC_COMP_DENYLIST_MGR, + ucfg_dlm_resume_handler, NULL); +} + +static inline void +ucfg_dlm_unregister_pmo_handler(void) +{ + pmo_unregister_suspend_handler(WLAN_UMAC_COMP_DENYLIST_MGR, + ucfg_dlm_suspend_handler); + pmo_unregister_resume_handler(WLAN_UMAC_COMP_DENYLIST_MGR, + ucfg_dlm_resume_handler); +} + +QDF_STATUS ucfg_dlm_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + ucfg_dlm_register_pmo_handler(); + return dlm_cfg_psoc_open(psoc); +} + +QDF_STATUS ucfg_dlm_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + ucfg_dlm_unregister_pmo_handler(); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_dlm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_info *ap_info) +{ + return dlm_add_bssid_to_reject_list(pdev, ap_info); +} + +QDF_STATUS +ucfg_dlm_add_userspace_deny_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid_deny_list, + uint8_t num_of_bssid) +{ + return dlm_add_userspace_deny_list(pdev, bssid_deny_list, + num_of_bssid); +} + +void +ucfg_dlm_dump_deny_list_ap(struct wlan_objmgr_pdev *pdev) +{ + return wlan_dlm_dump_denylist_bssid(pdev); +} + +void +ucfg_dlm_update_bssid_connect_params(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr bssid, + enum dlm_connection_state con_state) +{ + wlan_dlm_update_bssid_connect_params(pdev, bssid, con_state); +} + +void +ucfg_dlm_wifi_off(struct wlan_objmgr_pdev *pdev) +{ + struct dlm_pdev_priv_obj *dlm_ctx; + struct dlm_psoc_priv_obj *dlm_psoc_obj; + struct dlm_config *cfg; + QDF_STATUS status; + + if (!pdev) { + dlm_err("pdev is NULL"); + return; + } + + dlm_ctx = dlm_get_pdev_obj(pdev); + dlm_psoc_obj = dlm_get_psoc_obj(wlan_pdev_get_psoc(pdev)); + + if (!dlm_ctx || !dlm_psoc_obj) { + dlm_err("dlm_ctx or dlm_psoc_obj is NULL"); + return; + } + + status = qdf_mutex_acquire(&dlm_ctx->reject_ap_list_lock); + if (QDF_IS_STATUS_ERROR(status)) { + dlm_err("failed to acquire reject_ap_list_lock"); + return; + } + + cfg = &dlm_psoc_obj->dlm_cfg; + + dlm_flush_reject_ap_list(dlm_ctx); + dlm_send_reject_ap_list_to_fw(pdev, &dlm_ctx->reject_ap_list, cfg); + qdf_mutex_release(&dlm_ctx->reject_ap_list_lock); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_main.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_main.h new file mode 100644 index 0000000000..fcb5df2a75 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_main.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare various api which shall be used by + * DISA user configuration and target interface + */ + +#ifndef _WLAN_DISA_MAIN_H_ +#define _WLAN_DISA_MAIN_H_ + +#include "wlan_disa_public_struct.h" +#include "wlan_disa_obj_mgmt_public_struct.h" +#include "wlan_disa_priv.h" +#include "wlan_disa_objmgr.h" + +#define disa_fatal(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_DISA, params) +#define disa_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_DISA, params) +#define disa_warn(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_DISA, params) +#define disa_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_DISA, params) +#define disa_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_DISA, params) + +#define disa_nofl_fatal(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_DISA, params) +#define disa_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_DISA, params) +#define disa_nofl_warn(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_DISA, params) +#define disa_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_DISA, params) +#define disa_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_DISA, params) + +#define DISA_ENTER() \ + QDF_TRACE_ENTER(QDF_MODULE_ID_DISA, "enter") +#define DISA_EXIT() \ + QDF_TRACE_EXIT(QDF_MODULE_ID_DISA, "exit") + +/** + * disa_allocate_ctx() - Api to allocate disa ctx + * + * Helper function to allocate disa ctx + * + * Return: Success or failure. + */ +QDF_STATUS disa_allocate_ctx(void); + +/** + * disa_free_ctx() - to free disa context + * + * Helper function to free disa context + * + * Return: None. + */ +void disa_free_ctx(void); + +/** + * disa_get_context() - to get disa context + * + * Helper function to get disa context + * + * Return: disa context. + */ +struct wlan_disa_ctx *disa_get_context(void); + +/** + * disa_core_encrypt_decrypt_req() - Form encrypt/decrypt request + * @psoc: objmgr psoc object + * @req: DISA encrypt/decrypt request parameters + * @cb: Response callback for the encrypt/decrypt request + * @cookie: Cookie to pass to the response callback + * + * Return: QDF status success or failure + */ +QDF_STATUS disa_core_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req, + encrypt_decrypt_resp_callback cb, + void *cookie); + +#endif /* end of _WLAN_DISA_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_objmgr.h new file mode 100644 index 0000000000..e719d695fb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_objmgr.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains various object manager related wrappers and helpers + */ + +#ifndef _WLAN_DISA_OBJMGR_H +#define _WLAN_DISA_OBJMGR_H + +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_disa_obj_mgmt_public_struct.h" + +/* Get/Put Ref */ + +/** + * disa_psoc_get_ref() - DISA wrapper to increment ref count, if allowed + * @psoc: PSOC object + * + * DISA wrapper to increment ref count after checking valid object state + * + * Return: SUCCESS/FAILURE + */ +static inline QDF_STATUS disa_psoc_get_ref(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_try_get_ref(psoc, WLAN_DISA_ID); +} + +/** + * disa_psoc_put_ref() - DISA wrapper to decrement ref count + * @psoc: PSOC object + * + * DISA wrapper to decrement ref count of psoc + * + * Return: SUCCESS/FAILURE + */ +static inline void disa_psoc_put_ref(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_release_ref(psoc, WLAN_DISA_ID); +} + +/* Private Data */ + +/** + * disa_psoc_get_priv_nolock(): DISA wrapper to retrieve component object + * @psoc: Psoc pointer + * + * DISA wrapper used to get the component private object pointer + * + * Return: Component private object + */ +static inline void *disa_psoc_get_priv_nolock(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DISA); +} + +/* Ids */ +static inline uint8_t +disa_vdev_get_id(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + QDF_BUG(vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS); + + return vdev_id; +} + +/* Tree Navigation */ + +/* + * !PLEASE READ! + * + * The following are objmgr navigation helpers for traversing objmgr object + * trees. + * + * Objmgr ensures parents of an objmgr object cannot be freed while a valid + * reference to one of its children is held. Based on this fact, all of these + * navigation helpers make the following assumptions to ensure safe usage: + * + * 1) The caller must hold a valid reference to the input objmgr object! + * E.g. Use disa_[peer|vdev|pdev|psoc]_get_ref() on the input objmgr + * object before using these APIs + * 2) Given assumption #1, the caller does not need to hold a reference to the + * parents of the input objmgr object + * 3) Given assumption #1, parents of the input objmgr object cannot be null + * 4) Given assumption #1, private contexts of any parent of the input objmgr + * object cannot be null + * + * These characteristics remove the need for most sanity checks when dealing + * with objmgr objects. However, please note that if you ever walk the tree + * from parent to child, references must be acquired all the way down! + * + * Example #1: + * + * psoc = disa_vdev_get_psoc(vdev); + * if (!psoc) + * // this is dead code + * + * Example #2: + * + * psoc_priv = disa_psoc_get_priv(psoc); + * if (!psoc_priv) + * // this is dead code + * + * Example #3: + * + * status = disa_psoc_get_ref(psoc); + * + * ... + * + * psoc = disa_vdev_get_psoc(vdev); + * + * // the next line is redundant, don't do it! + * status = disa_psoc_get_ref(psoc); + */ + +/* Tree Navigation: psoc */ +static inline struct disa_psoc_priv_obj * +disa_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct disa_psoc_priv_obj *psoc_priv; + + psoc_priv = disa_psoc_get_priv_nolock(psoc); + QDF_BUG(psoc_priv); + + return psoc_priv; +} + +static inline struct wlan_objmgr_vdev * +disa_psoc_get_vdev(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + QDF_BUG(vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS); + if (vdev_id >= WLAN_UMAC_PSOC_MAX_VDEVS) + return NULL; + + wlan_psoc_obj_lock(psoc); + vdev = psoc->soc_objmgr.wlan_vdev_list[vdev_id]; + wlan_psoc_obj_unlock(psoc); + + return vdev; +} + +/* Tree Navigation: pdev */ +static inline struct wlan_objmgr_psoc * +disa_pdev_get_psoc(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + QDF_BUG(psoc); + + return psoc; +} + +/* Tree Navigation: vdev */ +static inline struct wlan_objmgr_pdev * +disa_vdev_get_pdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + QDF_BUG(pdev); + + return pdev; +} + +static inline struct wlan_objmgr_psoc * +disa_vdev_get_psoc(struct wlan_objmgr_vdev *vdev) +{ + return disa_pdev_get_psoc(disa_vdev_get_pdev(vdev)); +} + +#endif /* _WLAN_DISA_OBJMGR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_priv.h new file mode 100644 index 0000000000..bb7adbe915 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/inc/wlan_disa_priv.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: Declare various struct, macros which are used privately in DISA + * component. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_DISA_PRIV_STRUCT_H_ +#define _WLAN_DISA_PRIV_STRUCT_H_ + +#include +#include "wlan_disa_public_struct.h" + +/** + * struct disa_psoc_priv_obj -psoc specific user configuration required for disa + * + * @disa_rx_ops: rx operations for disa + * @disa_tx_ops: tx operations for disa + * @lock: spin lock for disa psoc priv ctx + */ +struct disa_psoc_priv_obj { + struct wlan_disa_rx_ops disa_rx_ops; + struct wlan_disa_tx_ops disa_tx_ops; + qdf_spinlock_t lock; +}; + +/** + * struct wlan_disa_ctx - disa context for single command + * + * @callback: hdd callback for disa encrypt/decrypt resp + * @callback_context: context for the callback + * @request_active: true if a request is active + * @lock: spin lock for disa context + */ +struct wlan_disa_ctx { + encrypt_decrypt_resp_callback callback; + void *callback_context; + bool request_active; + qdf_spinlock_t lock; +}; + +#endif /* end of _WLAN_DISA_PRIV_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/core/src/wlan_disa_main.c b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/src/wlan_disa_main.c new file mode 100644 index 0000000000..7080e2293c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/core/src/wlan_disa_main.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implement various api / helper function which shall be used for + * DISA user and target interface. + */ + +#include "wlan_disa_main.h" +#include "wlan_disa_obj_mgmt_public_struct.h" +#include "wlan_disa_tgt_api.h" + +static struct wlan_disa_ctx *gp_disa_ctx; + +QDF_STATUS disa_allocate_ctx(void) +{ + /* If it is already created, ignore */ + if (gp_disa_ctx) { + disa_debug("already allocated disa_ctx"); + return QDF_STATUS_SUCCESS; + } + + /* allocate DISA ctx */ + gp_disa_ctx = qdf_mem_malloc(sizeof(*gp_disa_ctx)); + if (!gp_disa_ctx) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&gp_disa_ctx->lock); + + return QDF_STATUS_SUCCESS; +} + +void disa_free_ctx(void) +{ + if (!gp_disa_ctx) { + disa_err("disa ctx is already freed"); + QDF_ASSERT(0); + return; + } + qdf_spinlock_destroy(&gp_disa_ctx->lock); + qdf_mem_free(gp_disa_ctx); + gp_disa_ctx = NULL; +} + +struct wlan_disa_ctx *disa_get_context(void) +{ + return gp_disa_ctx; +} + +QDF_STATUS disa_core_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req, + encrypt_decrypt_resp_callback cb, + void *cookie) +{ + struct wlan_disa_ctx *disa_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + DISA_ENTER(); + disa_ctx = disa_get_context(); + if (!disa_ctx) { + disa_err("DISA context is NULL!"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&disa_ctx->lock); + if (!disa_ctx->request_active) { + disa_ctx->callback = cb; + disa_ctx->callback_context = cookie; + disa_ctx->request_active = true; + } else { + status = QDF_STATUS_E_INVAL; + } + qdf_spin_unlock_bh(&disa_ctx->lock); + + if (status != QDF_STATUS_SUCCESS) { + disa_err("A request is already active!"); + return status; + } + + status = disa_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + disa_err("DISA cannot get the reference out of psoc"); + return status; + } + + status = tgt_disa_encrypt_decrypt_req(psoc, req); + disa_psoc_put_ref(psoc); + + DISA_EXIT(); + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_api.h new file mode 100644 index 0000000000..12a689a699 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_api.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare utility API related to the disa component + * called by other components + */ + +#ifndef _WLAN_DISA_OBJ_MGMT_API_H_ +#define _WLAN_DISA_OBJ_MGMT_API_H_ + +#include + +struct wlan_objmgr_psoc; + +/** + * disa_init() - register disa notification handlers. + * + * This function registers disa related notification handlers. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +#ifdef WLAN_FEATURE_DISA +QDF_STATUS disa_init(void); +#else +static inline QDF_STATUS disa_init(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * disa_deinit() - unregister disa notification handlers. + * + * This function unregisters disa related notification handlers. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +#ifdef WLAN_FEATURE_DISA +QDF_STATUS disa_deinit(void); +#else +static inline QDF_STATUS disa_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * disa_psoc_enable() - Trigger psoc enable for DISA + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +#ifdef WLAN_FEATURE_DISA +QDF_STATUS disa_psoc_enable(struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS disa_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * disa_psoc_disable() - Trigger psoc disable for DISA + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +#ifdef WLAN_FEATURE_DISA +QDF_STATUS disa_psoc_disable(struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS disa_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * disa_psoc_object_created_notification(): disa psoc create handler + * @psoc: psoc which is going to created by objmgr + * @arg: argument for psoc create handler + * + * Attach psoc private object, register rx/tx ops and event handlers + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS disa_psoc_object_created_notification( + struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * disa_psoc_object_destroyed_notification(): disa psoc destroy handler + * @psoc: objmgr object corresponding to psoc which is going to be destroyed + * @arg: argument for psoc destroy handler + * + * Detach and free psoc private object, unregister event handlers + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS disa_psoc_object_destroyed_notification( + struct wlan_objmgr_psoc *psoc, void *arg); + +#endif /* end of _WLAN_DISA_OBJ_MGMT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_public_struct.h new file mode 100644 index 0000000000..76aae8163d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_obj_mgmt_public_struct.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which are used for object mgmt in disa. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_DISA_OBJ_MGMT_PUBLIC_STRUCT_H_ +#define _WLAN_DISA_OBJ_MGMT_PUBLIC_STRUCT_H_ + +struct wlan_objmgr_psoc; +struct disa_encrypt_decrypt_req_params; +struct disa_encrypt_decrypt_resp_params; + +/** + * struct wlan_disa_tx_ops - structure of tx operation function + * pointers for disa component + * @disa_encrypt_decrypt_req: send encrypt/decrypt request + * @disa_register_ev_handlers: register disa event handlers + * @disa_unregister_ev_handlers: unregister disa event handlers + */ +struct wlan_disa_tx_ops { + QDF_STATUS (*disa_encrypt_decrypt_req)(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req); + QDF_STATUS (*disa_register_ev_handlers)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*disa_unregister_ev_handlers) + (struct wlan_objmgr_psoc *psoc); +}; + +/** + * struct wlan_disa_rx_ops - structure of rx operation function + * pointers for disa component + * @encrypt_decrypt_msg_resp: send response of encrypt/decrypt request + */ +struct wlan_disa_rx_ops { + QDF_STATUS (*encrypt_decrypt_msg_resp)(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_resp_params *resp); +}; +#endif /* end of _WLAN_DISA_OBJ_MGMT_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_public_struct.h new file mode 100644 index 0000000000..6d42612bbc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_public_struct.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in the DISA + * component. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_DISA_PUBLIC_STRUCT_H_ +#define _WLAN_DISA_PUBLIC_STRUCT_H_ + +#include + +#define MAC_MAX_KEY_LENGTH 32 +#define MAC_PN_LENGTH 8 +#define MAX_MAC_HEADER_LEN 32 +#define MIN_MAC_HEADER_LEN 24 + +/** + * struct disa_encrypt_decrypt_req_params - disa encrypt request + * @vdev_id: virtual device id + * @key_flag: This indicates firmware to encrypt/decrypt payload + * see ENCRYPT_DECRYPT_FLAG + * @key_idx: Index used in storing key + * @key_cipher: cipher used for encryption/decryption + * Eg: see WMI_CIPHER_AES_CCM for CCMP + * @key_len: length of key data + * @key_txmic_len: length of Tx MIC + * @key_rxmic_len: length of Rx MIC + * @key_data: Key + * @pn: packet number + * @mac_header: MAC header + * @data_len: length of data + * @data: pointer to payload + */ +struct disa_encrypt_decrypt_req_params { + uint32_t vdev_id; + uint8_t key_flag; + uint32_t key_idx; + uint32_t key_cipher; + uint32_t key_len; + uint32_t key_txmic_len; + uint32_t key_rxmic_len; + uint8_t key_data[MAC_MAX_KEY_LENGTH]; + uint8_t pn[MAC_PN_LENGTH]; + uint8_t mac_header[MAX_MAC_HEADER_LEN]; + uint32_t data_len; + uint8_t *data; +}; + +/** + * struct disa_encrypt_decrypt_resp_params - disa encrypt response + * @vdev_id: vdev id + * @status: status + * @data_len: data length + * @data: data pointer + */ +struct disa_encrypt_decrypt_resp_params { + uint32_t vdev_id; + int32_t status; + uint32_t data_len; + uint8_t *data; +}; + +/** + * typedef encrypt_decrypt_resp_callback() - DISA callback function + * @cookie: cookie passed in the DISA request + * @resp: the DISA response + */ +typedef void (*encrypt_decrypt_resp_callback)(void *cookie, + struct disa_encrypt_decrypt_resp_params *resp); +#endif /* end of _WLAN_DISA_PUBLIC_STRUCT_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_tgt_api.h new file mode 100644 index 0000000000..ad900deb14 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_tgt_api.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare public API for disa to interact with target/WMI + */ + +#ifndef _WLAN_DISA_TGT_API_H_ +#define _WLAN_DISA_TGT_API_H_ + +#include + +struct wlan_objmgr_psoc; +struct disa_encrypt_decrypt_req_params; +struct disa_encrypt_decrypt_resp_params; + +#define GET_DISA_TX_OPS_FROM_PSOC(psoc) \ + (&disa_psoc_get_priv(psoc)->disa_tx_ops) + +/** + * tgt_disa_encrypt_decrypt_req() - send encrypt/decrypt request to target if + * @psoc: objmgr psoc object + * @req: encrypt/decrypt parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_disa_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req); + +/** + * tgt_disa_encrypt_decrypt_resp() - receive encrypt/decrypt response + * from target if + * @psoc: objmgr psoc object + * @resp: encrypt/decrypt response containing results + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_disa_encrypt_decrypt_resp(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_resp_params *resp); + +/** + * tgt_disa_register_ev_handlers() - API to register disa event handlers + * @psoc: objmgr psoc object + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS tgt_disa_register_ev_handlers(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_disa_unregister_ev_handlers() - API to unregister disa event handlers + * @psoc: objmgr psoc object + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS tgt_disa_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc); + +#endif /* end of _WLAN_DISA_TGT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_ucfg_api.h new file mode 100644 index 0000000000..b9c8206d35 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/inc/wlan_disa_ucfg_api.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare public API related to the disa called by north bound HDD/OSIF + */ + +#ifndef _WLAN_DISA_UCFG_API_H_ +#define _WLAN_DISA_UCFG_API_H_ + +#include "wlan_disa_public_struct.h" +struct wlan_objmgr_psoc; +struct disa_encrypt_decrypt_req_params; + + +/** + * ucfg_disa_encrypt_decrypt_req() - Send encrypt/decrypt request to the DISA + * core + * @psoc: objmgr psoc object + * @req: DISA encrypt/decrypt request parameters + * @cb: Response callback for the encrypt/decrypt request + * @cookie: Cookie to pass to the response callback + * + * Return: QDF status success or failure + */ +QDF_STATUS ucfg_disa_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req, + encrypt_decrypt_resp_callback cb, + void *cookie); + + +#endif /* end of _WLAN_DISA_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c new file mode 100644 index 0000000000..144dc5c95a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define utility API related to the DISA component + * called by other components + */ + +#include "wlan_disa_obj_mgmt_api.h" +#include "wlan_disa_main.h" +#include "target_if_disa.h" +#include "wlan_disa_tgt_api.h" +#include "wlan_objmgr_global_obj.h" + +/** + * disa_init() - register disa notification handlers. + * + * This function registers disa related notification handlers and + * allocates disa context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS disa_init(void) +{ + QDF_STATUS status; + + DISA_ENTER(); + + if (disa_allocate_ctx() != QDF_STATUS_SUCCESS) { + disa_err("unable to allocate disa ctx"); + status = QDF_STATUS_E_FAULT; + goto out; + } + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_DISA, + disa_psoc_object_created_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + disa_err("unable to register psoc create handler"); + goto err_free_ctx; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_DISA, + disa_psoc_object_destroyed_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + disa_err("unable to register psoc destroy handler"); + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_DISA, + disa_psoc_object_created_notification, + NULL); + } else { + goto out; + } + +err_free_ctx: + disa_free_ctx(); +out: + DISA_EXIT(); + + return status; +} + +/** + * disa_deinit() - unregister disa notification handlers. + * + * This function unregisters disa related notification handlers and + * frees disa context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS disa_deinit(void) +{ + QDF_STATUS status; + + DISA_ENTER(); + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_DISA, + disa_psoc_object_destroyed_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) + disa_err("unable to unregister psoc create handle"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_DISA, + disa_psoc_object_created_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) + disa_err("unable to unregister psoc create handle"); + + disa_free_ctx(); + DISA_EXIT(); + + return status; +} + +/** + * disa_psoc_object_created_notification(): disa psoc create handler + * @psoc: psoc which is going to created by objmgr + * @arg: argument for psoc create handler + * + * Attach psoc private object, register rx/tx ops and event handlers + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS disa_psoc_object_created_notification( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct disa_psoc_priv_obj *disa_priv; + QDF_STATUS status; + + DISA_ENTER(); + + disa_priv = qdf_mem_malloc(sizeof(*disa_priv)); + if (!disa_priv) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_DISA, + (void *)disa_priv, QDF_STATUS_SUCCESS); + if (status != QDF_STATUS_SUCCESS) { + disa_err("Failed to attach disa_priv with psoc"); + qdf_mem_free(disa_priv); + goto out; + } + + qdf_spinlock_create(&disa_priv->lock); + target_if_disa_register_tx_ops(&disa_priv->disa_tx_ops); + +out: + DISA_EXIT(); + + return status; +} + +/** + * disa_psoc_object_destroyed_notification(): disa psoc destroy handler + * @psoc: objmgr object corresponding to psoc which is going to be destroyed + * @arg: argument for psoc destroy handler + * + * Detach and free psoc private object, unregister event handlers + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS disa_psoc_object_destroyed_notification( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct disa_psoc_priv_obj *disa_priv = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + DISA_ENTER(); + + disa_priv = disa_psoc_get_priv(psoc); + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_DISA, + (void *)disa_priv); + + if (status != QDF_STATUS_SUCCESS) + disa_err("Failed to detach disa_priv with psoc"); + + qdf_spinlock_destroy(&disa_priv->lock); + qdf_mem_free(disa_priv); + DISA_EXIT(); + + return status; +} + +/** + * disa_psoc_enable() - Trigger psoc enable for DISA + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +QDF_STATUS disa_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return tgt_disa_register_ev_handlers(psoc); +} + +/** + * disa_psoc_disable() - Trigger psoc disable for DISA + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +QDF_STATUS disa_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return tgt_disa_unregister_ev_handlers(psoc); + +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_tgt_api.c new file mode 100644 index 0000000000..384916c0c4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_tgt_api.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implements public API for disa to interact with target/WMI + */ + +#include "wlan_disa_tgt_api.h" +#include "wlan_disa_main.h" +#include "wlan_disa_public_struct.h" + +/** + * tgt_disa_encrypt_decrypt_req() - send encrypt/decrypt request to target if + * @psoc: objmgr psoc object + * @req: encrypt/decrypt parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_disa_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req) +{ + struct wlan_disa_tx_ops *disa_tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + DISA_ENTER(); + + disa_tx_ops = GET_DISA_TX_OPS_FROM_PSOC(psoc); + QDF_ASSERT(disa_tx_ops->disa_encrypt_decrypt_req); + + if (disa_tx_ops->disa_encrypt_decrypt_req) + status = disa_tx_ops->disa_encrypt_decrypt_req(psoc, req); + + DISA_EXIT(); + return status; +} + +/** + * tgt_disa_encrypt_decrypt_resp() - receive encrypt/decrypt response + * from target if + * @psoc: objmgr psoc object + * @resp: encrypt/decrypt response containing results + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_disa_encrypt_decrypt_resp(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_resp_params *resp) +{ + struct wlan_disa_ctx *disa_ctx; + encrypt_decrypt_resp_callback cb; + void *cookie; + + DISA_ENTER(); + + if (!resp) { + disa_err("encrypt/decrypt resp is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + disa_ctx = disa_get_context(); + if (!disa_ctx) { + disa_err("DISA context is NULL!"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&disa_ctx->lock); + cb = disa_ctx->callback; + disa_ctx->callback = NULL; + cookie = disa_ctx->callback_context; + disa_ctx->callback_context = NULL; + disa_ctx->request_active = false; + qdf_spin_unlock_bh(&disa_ctx->lock); + + if (cb) + cb(cookie, resp); + + DISA_EXIT(); + return QDF_STATUS_SUCCESS; +} + +/** + * tgt_disa_register_ev_handlers() - API to register disa event handlers + * @psoc: objmgr psoc object + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS tgt_disa_register_ev_handlers(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_disa_tx_ops *disa_tx_ops; + + disa_tx_ops = GET_DISA_TX_OPS_FROM_PSOC(psoc); + + QDF_ASSERT(disa_tx_ops->disa_register_ev_handlers); + + if (disa_tx_ops->disa_register_ev_handlers) + return disa_tx_ops->disa_register_ev_handlers(psoc); + + return QDF_STATUS_SUCCESS; +} + +/** + * tgt_disa_unregister_ev_handlers() - API to unregister disa event handlers + * @psoc: objmgr psoc object + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS tgt_disa_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_disa_tx_ops *disa_tx_ops; + + disa_tx_ops = GET_DISA_TX_OPS_FROM_PSOC(psoc); + + QDF_ASSERT(disa_tx_ops->disa_unregister_ev_handlers); + + if (disa_tx_ops->disa_unregister_ev_handlers) + return disa_tx_ops->disa_unregister_ev_handlers(psoc); + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_ucfg_api.c new file mode 100644 index 0000000000..b24ea43307 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/disa/dispatcher/src/wlan_disa_ucfg_api.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: public API related to the disa called by north bound HDD/OSIF + */ + +#include "wlan_disa_ucfg_api.h" +#include "wlan_disa_main.h" + +QDF_STATUS ucfg_disa_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req, + encrypt_decrypt_resp_callback cb, + void *cookie) +{ + return disa_core_encrypt_decrypt_req(psoc, req, cb, cookie); +} + + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_main.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_main.h new file mode 100644 index 0000000000..1dfd32bc1c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_main.h @@ -0,0 +1,1030 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: wlan_dp_main.h + * + * + */ +#ifndef __WLAN_DP_MAIN_H__ +#define __WLAN_DP_MAIN_H__ + +#include "wlan_dp_public_struct.h" +#include "wlan_dp_priv.h" +#include "wlan_dp_objmgr.h" + +#define NUM_RX_QUEUES 5 + +#define dp_enter() QDF_TRACE_ENTER(QDF_MODULE_ID_DP, "enter") +#define dp_exit() QDF_TRACE_EXIT(QDF_MODULE_ID_DP, "exit") + +/** + * dp_allocate_ctx() - Allocate DP context + * + */ +QDF_STATUS dp_allocate_ctx(void); + +/** + * dp_free_ctx() - Free DP context + * + */ +void dp_free_ctx(void); + +/** + * dp_get_front_intf_no_lock() - Get the first interface from the intf list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * @dp_ctx: pointer to the DP context + * @out_intf: double pointer to pass the next interface + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_get_front_intf_no_lock(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_intf **out_intf); + +/** + * dp_get_next_intf_no_lock() - Get the next intf from the intf list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * @dp_ctx: pointer to the DP context + * @cur_intf: pointer to the current intf + * @out_intf: double pointer to pass the next intf + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_get_next_intf_no_lock(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_intf *cur_intf, + struct wlan_dp_intf **out_intf); + +/** + * __dp_take_ref_and_fetch_front_intf_safe - Helper macro to lock, fetch + * front and next intf, take ref and unlock. + * @dp_ctx: the global DP context + * @dp_intf: an dp_intf pointer to use as a cursor + * @dp_intf_next: dp_intf pointer to next intf + * + */ +#define __dp_take_ref_and_fetch_front_intf_safe(dp_ctx, dp_intf, \ + dp_intf_next) \ + qdf_spin_lock_bh(&dp_ctx->intf_list_lock), \ + dp_get_front_intf_no_lock(dp_ctx, &dp_intf), \ + dp_get_next_intf_no_lock(dp_ctx, dp_intf, &dp_intf_next), \ + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock) + +/** + * __dp_take_ref_and_fetch_next_intf_safe - Helper macro to lock, fetch next + * interface, take ref and unlock. + * @dp_ctx: the global DP context + * @dp_intf: dp_intf pointer to use as a cursor + * @dp_intf_next: dp_intf pointer to next interface + * + */ +#define __dp_take_ref_and_fetch_next_intf_safe(dp_ctx, dp_intf, \ + dp_intf_next) \ + qdf_spin_lock_bh(&dp_ctx->intf_list_lock), \ + dp_intf = dp_intf_next, \ + dp_get_next_intf_no_lock(dp_ctx, dp_intf, &dp_intf_next), \ + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock) + +/** + * __dp_is_intf_valid - Helper macro to return true/false for valid interface. + * @_dp_intf: an dp_intf pointer to use as a cursor + */ +#define __dp_is_intf_valid(_dp_intf) !!(_dp_intf) + +/** + * dp_for_each_intf_held_safe - Interface iterator called + * in a delete safe manner + * @dp_ctx: the global DP context + * @dp_intf: an dp_intf pointer to use as a cursor + * @dp_intf_next: dp_intf pointer to the next interface + * + */ +#define dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) \ + for (__dp_take_ref_and_fetch_front_intf_safe(dp_ctx, dp_intf, \ + dp_intf_next); \ + __dp_is_intf_valid(dp_intf); \ + __dp_take_ref_and_fetch_next_intf_safe(dp_ctx, dp_intf, \ + dp_intf_next)) + +/** + * dp_get_intf_by_macaddr() - Api to Get interface from MAC address + * @dp_ctx: DP context + * @addr: MAC address + * + * Return: Pointer to DP interface. + */ +struct wlan_dp_intf* +dp_get_intf_by_macaddr(struct wlan_dp_psoc_context *dp_ctx, + struct qdf_mac_addr *addr); + +/** + * dp_get_intf_by_netdev() - Api to Get interface from netdev + * @dp_ctx: DP context + * @dev: Pointer to network device + * + * Return: Pointer to DP interface. + */ +struct wlan_dp_intf* +dp_get_intf_by_netdev(struct wlan_dp_psoc_context *dp_ctx, qdf_netdev_t dev); + +/** + * dp_get_front_link_no_lock() - Get the first link from the dp links list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * @dp_intf: DP interface handle + * @out_link: double pointer to pass the next link + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_get_front_link_no_lock(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link **out_link); + +/** + * dp_get_next_link_no_lock() - Get the next link from the link list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * @dp_intf: DP interface handle + * @cur_link: pointer to the currentlink + * @out_link: double pointer to pass the nextlink + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_get_next_link_no_lock(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link *cur_link, + struct wlan_dp_link **out_link); + +/** + * __dp_take_ref_and_fetch_front_link_safe - Helper macro to lock, fetch + * front and next link, take ref and unlock. + * @dp_intf: DP interface handle + * @dp_link: an dp_link pointer to use as a cursor + * @dp_link_next: dp_link pointer to nextlink + */ +#define __dp_take_ref_and_fetch_front_link_safe(dp_intf, dp_link, \ + dp_link_next) \ + qdf_spin_lock_bh(&(dp_intf)->dp_link_list_lock), \ + dp_get_front_link_no_lock(dp_intf, &(dp_link)), \ + dp_get_next_link_no_lock(dp_intf, dp_link, &(dp_link_next)), \ + qdf_spin_unlock_bh(&(dp_intf)->dp_link_list_lock) + +/** + * __dp_take_ref_and_fetch_next_link_safe - Helper macro to lock, fetch next + * interface, take ref and unlock. + * @dp_intf: DP interface handle + * @dp_link: dp_link pointer to use as a cursor + * @dp_link_next: dp_link pointer to next link + */ +#define __dp_take_ref_and_fetch_next_link_safe(dp_intf, dp_link, \ + dp_link_next) \ + qdf_spin_lock_bh(&(dp_intf)->dp_link_list_lock), \ + dp_link = dp_link_next, \ + dp_get_next_link_no_lock(dp_intf, dp_link, &(dp_link_next)), \ + qdf_spin_unlock_bh(&(dp_intf)->dp_link_list_lock) + +/** + * __dp_is_link_valid - Helper macro to return true/false for valid interface. + * @_dp_link: an dp_link pointer to use as a cursor + */ +#define __dp_is_link_valid(_dp_link) !!(_dp_link) + +/** + * dp_for_each_link_held_safe - Interface iterator called + * in a delete safe manner + * @dp_intf: DP interface handle + * @dp_link: an dp_link pointer to use as a cursor + * @dp_link_next: dp_link pointer to the next interface + * + */ +#define dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) \ + for (__dp_take_ref_and_fetch_front_link_safe(dp_intf, dp_link, \ + dp_link_next); \ + __dp_is_link_valid(dp_link); \ + __dp_take_ref_and_fetch_next_link_safe(dp_intf, dp_link, \ + dp_link_next)) + +/* MAX iteration count to wait for dp packet process to complete */ +#define DP_TASK_MAX_WAIT_CNT 100 +/* Milli seconds to wait when packet is getting processed */ +#define DP_TASK_WAIT_TIME 200 + +#define DP_TX_FN_CLR (1 << 0) +#define DP_TX_SAP_STOP (1 << 1) +#define DP_TX_DFS_CAC_BLOCK (1 << 2) +#define WLAN_DP_SUSPEND (1 << 3) + +/** + * dp_wait_complete_tasks: Wait for DP tasks to complete + * @dp_ctx: DP context pointer + * + * This function waits for dp tasks like TX to be completed + * + * Return: None + */ +void dp_wait_complete_tasks(struct wlan_dp_psoc_context *dp_ctx); + +#define NUM_RX_QUEUES 5 + +#define dp_enter() QDF_TRACE_ENTER(QDF_MODULE_ID_DP, "enter") +#define dp_exit() QDF_TRACE_EXIT(QDF_MODULE_ID_DP, "exit") + +/** + * __wlan_dp_runtime_suspend() - Runtime suspend DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS __wlan_dp_runtime_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * __wlan_dp_runtime_resume() - Runtime suspend DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS __wlan_dp_runtime_resume(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * __wlan_dp_bus_suspend() - BUS suspend DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS __wlan_dp_bus_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * __wlan_dp_bus_resume() - BUS resume DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS __wlan_dp_bus_resume(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * wlan_dp_txrx_soc_attach() - Datapath soc attach + * @params: SoC attach params + * @is_wifi3_0_target: [OUT] Pointer to update if the target is wifi3.0 + * + * Return: SoC handle + */ +void *wlan_dp_txrx_soc_attach(struct dp_txrx_soc_attach_params *params, + bool *is_wifi3_0_target); + +/** + * wlan_dp_txrx_soc_detach() - Datapath SoC detach + * @soc: DP SoC handle + * + * Return: None + */ +void wlan_dp_txrx_soc_detach(ol_txrx_soc_handle soc); + +/** + * wlan_dp_txrx_attach_target() - DP target attach + * @soc: DP SoC handle + * @pdev_id: DP pdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dp_txrx_attach_target(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * wlan_dp_txrx_pdev_attach() - DP pdev attach + * @soc: DP SoC handle + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dp_txrx_pdev_attach(ol_txrx_soc_handle soc); + +/** + * wlan_dp_txrx_pdev_detach() - DP pdev detach + * @soc: DP SoC handle + * @pdev_id: DP pdev id + * @force: indicates if force detach is to be done or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dp_txrx_pdev_detach(ol_txrx_soc_handle soc, uint8_t pdev_id, + int force); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * dp_link_switch_notification() - DP notifier for MLO link switch + * @vdev: Objmgr vdev handle + * @lswitch_req: Link switch request params + * @notify_reason: Reason of notification + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_link_switch_notification(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *lswitch_req, + enum wlan_mlo_link_switch_notify_reason notify_reason); +#endif + +/** + * dp_peer_obj_create_notification(): dp peer create handler + * @peer: peer which is going to created by objmgr + * @arg: argument for vdev create handler + * + * Register this api with objmgr to detect peer is created + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dp_peer_obj_create_notification(struct wlan_objmgr_peer *peer, void *arg); + +/** + * dp_peer_obj_destroy_notification(): dp peer delete handler + * @peer: peer which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * Register this api with objmgr to detect peer is deleted + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +dp_peer_obj_destroy_notification(struct wlan_objmgr_peer *peer, void *arg); + +/** + * dp_vdev_obj_destroy_notification() - Free per DP vdev object + * @vdev: vdev context + * @arg: Pointer to arguments + * + * This function gets called from object manager when vdev is being + * deleted and delete DP vdev context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +dp_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg); + +/** + * dp_vdev_obj_create_notification() - Allocate per DP vdev object + * @vdev: vdev context + * @arg: Pointer to arguments + * + * This function gets called from object manager when vdev is being + * created and creates DP vdev context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg); + +/** + * dp_pdev_obj_create_notification() - Allocate per DP pdev object + * @pdev: pdev context + * @arg: Pointer to arguments + * + * This function gets called from object manager when pdev is being + * created and creates DP pdev context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +dp_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, void *arg); + +/** + * dp_pdev_obj_destroy_notification() - Free per DP pdev object + * @pdev: pdev context + * @arg: Pointer to arguments + * + * This function gets called from object manager when pdev is being + * deleted and delete DP pdev context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +dp_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, void *arg); + +/** + * dp_psoc_obj_create_notification() - Function to allocate per DP + * psoc private object + * @psoc: psoc context + * @arg: Pointer to arguments + * + * This function gets called from object manager when psoc is being + * created and creates DP soc context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +dp_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * dp_psoc_obj_destroy_notification() - Free psoc private object + * @psoc: psoc context + * @arg: Pointer to arguments + * + * This function gets called from object manager when psoc is being + * deleted and delete DP soc context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +dp_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * dp_attach_ctx() - Api to attach dp ctx + * @dp_ctx : DP Context + * + * Helper function to attach dp ctx + * + * Return: None. + */ +void dp_attach_ctx(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_detach_ctx() - to detach dp context + * + * Helper function to detach dp context + * + * Return: None. + */ +void dp_detach_ctx(void); + +/** + * dp_get_context() - to get dp context + * + * Helper function to get dp context + * + * Return: dp context. + */ +struct wlan_dp_psoc_context *dp_get_context(void); + +/** + * dp_add_latency_critical_client() - Add latency critical client + * @vdev: pointer to vdev object (Should not be NULL) + * @phymode: the phymode of the connected adapter + * + * This function checks if the present connection is latency critical + * and adds to the latency critical clients count and informs the + * datapath about this connection being latency critical. + * + * Returns: None + */ +static inline void +dp_add_latency_critical_client(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_802_11_mode phymode) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("No dp_link for objmgr vdev %pK", vdev); + return; + } + + dp_intf = dp_link->dp_intf; + if (!dp_intf) { + dp_err("Invalid dp_intf for dp_link %pK (" QDF_MAC_ADDR_FMT ")", + dp_link, QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + return; + } + + switch (phymode) { + case QCA_WLAN_802_11_MODE_11A: + case QCA_WLAN_802_11_MODE_11G: + qdf_atomic_inc(&dp_intf->dp_ctx->num_latency_critical_clients); + + dp_debug("Adding latency critical connection for vdev %d", + dp_link->link_id); + cdp_vdev_inform_ll_conn(cds_get_context(QDF_MODULE_ID_SOC), + dp_link->link_id, + CDP_VDEV_LL_CONN_ADD); + break; + default: + break; + } +} + +/** + * dp_del_latency_critical_client() - Add tlatency critical client + * @vdev: pointer to vdev object (Should not be NULL) + * @phymode: the phymode of the connected adapter + * + * This function checks if the present connection was latency critical + * and removes from the latency critical clients count and informs the + * datapath about the removed connection being latency critical. + * + * Returns: None + */ +static inline void +dp_del_latency_critical_client(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_802_11_mode phymode) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("No dp_link for objmgr vdev %pK", vdev); + return; + } + + dp_intf = dp_link->dp_intf; + if (!dp_intf) { + dp_err("Invalid dp_intf for dp_link %pK (" QDF_MAC_ADDR_FMT ")", + dp_link, QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + return; + } + + switch (phymode) { + case QCA_WLAN_802_11_MODE_11A: + case QCA_WLAN_802_11_MODE_11G: + qdf_atomic_dec(&dp_intf->dp_ctx->num_latency_critical_clients); + + dp_info("Removing latency critical connection for vdev %d", + dp_link->link_id); + cdp_vdev_inform_ll_conn(cds_get_context(QDF_MODULE_ID_SOC), + dp_link->link_id, + CDP_VDEV_LL_CONN_DEL); + break; + default: + break; + } +} + +/** + * is_dp_intf_valid() - to check DP interface valid + * @dp_intf: DP interface pointer + * + * API to check whether DP interface is valid + * + * Return: non zero value on interface valid + */ +int is_dp_intf_valid(struct wlan_dp_intf *dp_intf); + +/** + * is_dp_link_valid() - check if DP link is valid + * @dp_link: DP link handle + * + * API to check whether DP link is valid + * + * Return: true if dp_link is valid, else false. + */ +bool is_dp_link_valid(struct wlan_dp_link *dp_link); + +/** + * dp_send_rps_ind() - send rps indication to daemon + * @dp_intf: DP interface + * + * If RPS feature enabled by INI, send RPS enable indication to daemon + * Indication contents is the name of interface to find correct sysfs node + * Should send all available interfaces + * + * Return: none + */ +void dp_send_rps_ind(struct wlan_dp_intf *dp_intf); + +/** + * dp_try_send_rps_ind() - try to send rps indication to daemon. + * @vdev: vdev handle + * + * If RPS flag is set in DP context then send rsp indication. + * + * Return: none + */ +void dp_try_send_rps_ind(struct wlan_objmgr_vdev *vdev); + +/** + * dp_send_rps_disable_ind() - send rps disable indication to daemon + * @dp_intf: DP interface + * + * Return: none + */ +void dp_send_rps_disable_ind(struct wlan_dp_intf *dp_intf); + +#ifdef QCA_CONFIG_RPS +/** + * dp_set_rps() - Enable/disable RPS for mode specified + * @vdev_id: vdev id which RPS needs to be enabled + * @enable: Set true to enable RPS in SAP mode + * + * Callback function registered with ipa + * + * Return: none + */ +void dp_set_rps(uint8_t vdev_id, bool enable); +#else +static inline void dp_set_rps(uint8_t vdev_id, bool enable) +{ +} +#endif + +/** + * dp_set_rx_mode_rps() - Enable/disable RPS in SAP mode + * @enable: Set true to enable RPS in SAP mode + * + * Callback function registered with core datapath + * + * Return: none + */ +void dp_set_rx_mode_rps(bool enable); + +/** + * dp_set_rps_cpu_mask - set RPS CPU mask for interfaces + * @dp_ctx: pointer to struct dp_context + * + * Return: none + */ +void dp_set_rps_cpu_mask(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_try_set_rps_cpu_mask() - try to set RPS CPU mask + * @psoc: psoc handle + * + * If RPS flag is set in DP context then set RPS CPU mask. + * + * Return: none + */ +void dp_try_set_rps_cpu_mask(struct wlan_objmgr_psoc *psoc); + +/** + * dp_clear_rps_cpu_mask - clear RPS CPU mask for interfaces + * @dp_ctx: pointer to struct dp_context + * + * Return: none + */ +void dp_clear_rps_cpu_mask(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_mic_init_work() - init mic error work + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_mic_init_work(struct wlan_dp_intf *dp_intf); + +/** + * dp_mic_deinit_work() - deinitialize mic error work + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_mic_deinit_work(struct wlan_dp_intf *dp_intf); + +/** + * dp_rx_mic_error_ind() - MIC error indication handler + * @psoc: opaque handle for UMAC psoc object + * @pdev_id: physical device instance id + * @mic_failure_info: mic failure information + * + * This function indicates the Mic failure to the supplicant + * + * Return: None + */ +void +dp_rx_mic_error_ind(struct cdp_ctrl_objmgr_psoc *psoc, uint8_t pdev_id, + struct cdp_rx_mic_err_info *mic_failure_info); +/** + * dp_intf_get_tx_ops: get TX ops from the DP interface + * @psoc: pointer to psoc object + * + * Return: pointer to TX op callback + */ +static inline +struct wlan_dp_psoc_sb_ops *dp_intf_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + if (!psoc) { + dp_err("psoc is null"); + return NULL; + } + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("psoc private object is null"); + return NULL; + } + + return &dp_ctx->sb_ops; +} + +/** + * dp_intf_get_rx_ops: get RX ops from the DP interface + * @psoc: pointer to psoc object + * + * Return: pointer to RX op callback + */ +static inline +struct wlan_dp_psoc_nb_ops *dp_intf_get_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + if (!psoc) { + dp_err("psoc is null"); + return NULL; + } + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("psoc private object is null"); + return NULL; + } + + return &dp_ctx->nb_ops; +} + +/** + * dp_get_arp_request_ctx: get ARP req context from the DP context + * @psoc: pointer to psoc object + * + * Return: pointer to ARP request ctx. + */ +static inline +void *dp_get_arp_request_ctx(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("psoc private object is null"); + return NULL; + } + return dp_ctx->sb_ops.arp_request_ctx; +} + +/** + * dp_get_arp_stats_event_handler() - callback api to update the + * stats received from FW + * @psoc : psoc handle + * @rsp: pointer to data received from FW. + * + * This is called when wlan driver received response event for + * get arp stats to firmware. + * + * Return: None + */ +QDF_STATUS dp_get_arp_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct dp_rsp_stats *rsp); + +/** + * dp_trace_init() - Initialize DP trace + * @psoc: psoc handle + * + * Return: None + */ + +void dp_trace_init(struct wlan_objmgr_psoc *psoc); + +/** + * dp_set_dump_dp_trace() - set DP trace dump level + * @cmd_type : command type + * @count: count + * + * Return: None + */ +void dp_set_dump_dp_trace(uint16_t cmd_type, uint16_t count); + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +#define DP_BUS_BW_CFG(bus_bw_cfg) bus_bw_cfg +#define DP_BUS_BW_GET_RX_LVL(dp_ctx) (dp_ctx)->cur_rx_level +static inline bool +dp_is_low_tput_gro_enable(struct wlan_dp_psoc_context *dp_ctx) +{ + return (qdf_atomic_read(&dp_ctx->low_tput_gro_enable)) ? true : false; +} +#else +#define DP_BUS_BW_CFG(bus_bw_cfg) 0 +#define DP_BUS_BW_GET_RX_LVL(dp_ctx) 0 +static inline bool +dp_is_low_tput_gro_enable(struct wlan_dp_psoc_context *dp_ctx) +{ + return false; +} +#endif + +#define DP_DATA_STALL_ENABLE BIT(0) +#define DP_HOST_STA_TX_TIMEOUT BIT(16) +#define DP_HOST_SAP_TX_TIMEOUT BIT(17) +#define DP_HOST_NUD_FAILURE BIT(18) +#define DP_TIMEOUT_WLM_MODE BIT(31) +#define FW_DATA_STALL_EVT_MASK 0x8000FFFF + +/** + * dp_is_data_stall_event_enabled() - Check if data stall detection is enabled + * @evt: Data stall event to be checked + * + * Return: True if the data stall event is enabled + */ +bool dp_is_data_stall_event_enabled(uint32_t evt); + +/* + * dp_get_net_dev_stats(): Get netdev stats + * @dp_intf: DP interface handle + * @stats: To hold netdev stats + * + * Return: None + */ +static inline void +dp_get_net_dev_stats(struct wlan_dp_intf *dp_intf, qdf_net_dev_stats *stats) +{ + qdf_mem_copy(stats, &dp_intf->stats, sizeof(dp_intf->stats)); +} + +/* + * dp_clear_net_dev_stats(): Clear netdev stats + * @dp_intf: DP interface handle + * + * Return: None + */ +static inline +void dp_clear_net_dev_stats(struct wlan_dp_intf *dp_intf) +{ + qdf_mem_set(&dp_intf->stats, sizeof(dp_intf->stats), 0); +} + +#ifdef FEATURE_DIRECT_LINK +/** + * dp_direct_link_init() - Initializes Direct Link datapath + * @dp_ctx: DP private context + * + * Return: QDF status + */ +QDF_STATUS dp_direct_link_init(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_direct_link_deinit() - De-initializes Direct Link datapath + * @dp_ctx: DP private context + * @is_ssr: true if SSR is in progress else false + * + * Return: None + */ +void dp_direct_link_deinit(struct wlan_dp_psoc_context *dp_ctx, bool is_ssr); + +/** + * dp_config_direct_link: Set direct link config of vdev + * @dp_intf: DP interface handle + * @config_direct_link: Flag to enable direct link path + * @enable_low_latency: Flag to enable low link latency + * + * Return: QDF Status + */ +QDF_STATUS dp_config_direct_link(struct wlan_dp_intf *dp_intf, + bool config_direct_link, + bool enable_low_latency); +#else +static inline +QDF_STATUS dp_direct_link_init(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void dp_direct_link_deinit(struct wlan_dp_psoc_context *dp_ctx, bool is_ssr) +{ +} + +static inline +QDF_STATUS dp_config_direct_link(struct wlan_dp_intf *dp_intf, + bool config_direct_link, + bool enable_low_latency) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef WLAN_FEATURE_11BE +/** + * __wlan_dp_update_peer_map_unmap_version() - update peer map unmap version + * @version: Peer map unmap version pointer to be updated + * + * Return: None + */ +static inline void +__wlan_dp_update_peer_map_unmap_version(uint8_t *version) +{ + /* 0x32 -> host supports HTT peer map v3 format and peer unmap v2 format. */ + *version = 0x32; +} +#else +static inline void +__wlan_dp_update_peer_map_unmap_version(uint8_t *version) +{ +} +#endif + +#ifdef WLAN_DP_PROFILE_SUPPORT +/** + * wlan_dp_get_profile_info() - Get DP memory profile info + * + * Return: None + */ +struct wlan_dp_memory_profile_info *wlan_dp_get_profile_info(void); + +/** + * wlan_dp_select_profile_cfg() - Select DP profile configuration + * @psoc: psoc context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dp_select_profile_cfg(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dp_soc_cfg_sync_profile() - Sync DP soc cfg items with profile + * @cdp_soc: cdp soc context + * + * Return: None + */ +void wlan_dp_soc_cfg_sync_profile(struct cdp_soc_t *cdp_soc); + +/** + * wlan_dp_pdev_cfg_sync_profile() - Sync DP pdev cfg items with profile + * @cdp_soc: cdp soc context + * @pdev_id: pdev id + * + * Return: QDF_STATUS + */ +void wlan_dp_pdev_cfg_sync_profile(struct cdp_soc_t *cdp_soc, uint8_t pdev_id); +#else + +static inline +QDF_STATUS wlan_dp_select_profile_cfg(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * wlan_dp_link_cdp_vdev_delete_notification() - CDP vdev delete notification + * @context: osif_vdev handle + * + * Return: None + */ +void wlan_dp_link_cdp_vdev_delete_notification(void *context); + +/* DP CFG APIs - START */ + +#ifdef WLAN_SUPPORT_RX_FISA +/** + * wlan_dp_cfg_is_rx_fisa_enabled() - Get Rx FISA enabled flag + * @dp_cfg: soc configuration context + * + * Return: true if enabled, false otherwise. + */ +static inline +bool wlan_dp_cfg_is_rx_fisa_enabled(struct wlan_dp_psoc_cfg *dp_cfg) +{ + return dp_cfg->is_rx_fisa_enabled; +} + +/** + * wlan_dp_cfg_is_rx_fisa_lru_del_enabled() - Get Rx FISA LRU del enabled flag + * @dp_cfg: soc configuration context + * + * Return: true if enabled, false otherwise. + */ +static inline +bool wlan_dp_cfg_is_rx_fisa_lru_del_enabled(struct wlan_dp_psoc_cfg *dp_cfg) +{ + return dp_cfg->is_rx_fisa_lru_del_enabled; +} +#else +static inline +bool wlan_dp_cfg_is_rx_fisa_enabled(struct wlan_dp_psoc_cfg *dp_cfg) +{ + return false; +} + +static inline +bool wlan_dp_cfg_is_rx_fisa_lru_del_enabled(struct wlan_dp_psoc_cfg *dp_cfg) +{ + return false; +} +#endif + + +/* DP CFG APIs - END */ +/** + * __wlan_dp_update_def_link() - update DP interface default link + * @psoc: psoc handle + * @intf_mac: interface MAC address + * @vdev: objmgr vdev handle to set the def_link in dp_intf + * + */ +void __wlan_dp_update_def_link(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_mac, + struct wlan_objmgr_vdev *vdev); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_objmgr.h new file mode 100644 index 0000000000..f033537a8f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_objmgr.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains various object manager related wrappers and helpers + */ + +#ifndef __WLAN_DP_OBJMGR_H +#define __WLAN_DP_OBJMGR_H + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_peer_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_utility.h" + +struct wlan_dp_intf; +struct wlan_dp_link; + +/* Get/Put Ref */ + +#define dp_comp_peer_get_ref(peer) wlan_objmgr_peer_try_get_ref(peer, WLAN_DP_ID) +#define dp_comp_peer_put_ref(peer) wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID) + +#define dp_comp_vdev_get_ref(vdev) wlan_objmgr_vdev_try_get_ref(vdev, WLAN_DP_ID) +#define dp_comp_vdev_put_ref(vdev) wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID) + +#define dp_comp_pdev_get_ref(pdev) wlan_objmgr_pdev_try_get_ref(pdev, WLAN_DP_ID) +#define dp_comp_pdev_put_ref(pdev) wlan_objmgr_pdev_release_ref(pdev, WLAN_DP_ID) + +#define dp_comp_psoc_get_ref(psoc) wlan_objmgr_psoc_try_get_ref(psoc, WLAN_DP_ID) +#define dp_comp_psoc_put_ref(psoc) wlan_objmgr_psoc_release_ref(psoc, WLAN_DP_ID) + +/** + * dp_get_peer_priv_obj: get DP priv object from peer object + * @peer: pointer to peer object + * + * Return: pointer to DP peer private object + */ +static inline struct wlan_dp_sta_info * +dp_get_peer_priv_obj(struct wlan_objmgr_peer *peer) +{ + struct wlan_dp_sta_info *peer_info; + + peer_info = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_COMP_DP); + if (!peer_info) { + dp_err("peer is null"); + return NULL; + } + + return peer_info; +} + +/** + * dp_get_vdev_priv_obj() - Wrapper to retrieve vdev priv obj + * @vdev: vdev pointer + * + * Return: DP vdev private object + */ +static inline struct wlan_dp_link * +dp_get_vdev_priv_obj(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *obj; + + if (!vdev) { + dp_err("vdev is null"); + return NULL; + } + + obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_COMP_DP); + + return obj; +} + +/** + * dp_psoc_get_priv() - Wrapper to retrieve psoc priv obj + * @psoc: psoc pointer + * + * Return: DP psoc private object + */ +static inline struct wlan_dp_psoc_context * +dp_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_COMP_DP); + QDF_BUG(dp_ctx); + + return dp_ctx; +} + +/** + * dp_objmgr_get_vdev_by_user() - Get reference of vdev from dp_link + * with user id + * @dp_link: DP link handle + * @dbgid: reference count dbg id + * + * Return: pointer to vdev object for success, NULL for failure + */ +#ifdef WLAN_OBJMGR_REF_ID_TRACE +#define dp_objmgr_get_vdev_by_user(dp_link, dbgid) \ + __dp_objmgr_get_vdev_by_user(dp_link, dbgid, __func__, __LINE__) +struct wlan_objmgr_vdev * +__dp_objmgr_get_vdev_by_user(struct wlan_dp_link *dp_link, + wlan_objmgr_ref_dbgid id, + const char *func, + int line); +#else +#define dp_objmgr_get_vdev_by_user(dp_link, dbgid) \ + __dp_objmgr_get_vdev_by_user(dp_link, dbgid, __func__) +struct wlan_objmgr_vdev * +__dp_objmgr_get_vdev_by_user(struct wlan_dp_link *dp_link, + wlan_objmgr_ref_dbgid id, + const char *func); +#endif + +/** + * dp_objmgr_put_vdev_by_user() - Release reference of vdev object with + * user id + * @vdev: pointer to vdev object + * @dbgid: reference count dbg id + * + * This API releases vdev object reference which was acquired using + * dp_objmgr_get_vdev_by_user(). + * + * Return: void + */ +#ifdef WLAN_OBJMGR_REF_ID_TRACE +#define dp_objmgr_put_vdev_by_user(vdev, dbgid) \ + __dp_objmgr_put_vdev_by_user(vdev, dbgid, __func__, __LINE__) +void +__dp_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func, + int line); +#else +#define dp_objmgr_put_vdev_by_user(vdev, dbgid) \ + __dp_objmgr_put_vdev_by_user(vdev, dbgid, __func__) +void +__dp_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func); +#endif + +#endif /* __WLAN_DP_OBJMGR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_periodic_sta_stats.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_periodic_sta_stats.h new file mode 100644 index 0000000000..7e0144211e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_periodic_sta_stats.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: WLAN Host Device Driver periodic STA statistics related implementation + */ + +#if !defined(WLAN_DP_PERIODIC_STA_STATS_H) +#define WLAN_DP_PERIODIC_STA_STATS_H + +#include "wlan_dp_priv.h" +#include "wlan_objmgr_psoc_obj.h" + +#ifdef WLAN_FEATURE_PERIODIC_STA_STATS + +/** + * dp_periodic_sta_stats_config() - Initialize periodic stats configuration + * @config: Pointer to dp configuration + * @psoc: Pointer to psoc + * + * Return: none + */ +void dp_periodic_sta_stats_config(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc); + +/** + * dp_periodic_sta_stats_init() - Initialize periodic stats display flag + * @dp_intf: Pointer to the station interface + * + * Return: none + */ +void dp_periodic_sta_stats_init(struct wlan_dp_intf *dp_intf); + +/** + * dp_periodic_sta_stats_display() - Display periodic stats at STA + * @dp_ctx: dp context + * + * Return: none + */ +void dp_periodic_sta_stats_display(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_periodic_sta_stats_start() - Start displaying periodic stats for STA + * @vdev: vdev handle + * + * Return: none + */ +void dp_periodic_sta_stats_start(struct wlan_objmgr_vdev *vdev); + +/** + * dp_periodic_sta_stats_stop() - Stop displaying periodic stats for STA + * @vdev: vdev handle + * + * Return: none + */ +void dp_periodic_sta_stats_stop(struct wlan_objmgr_vdev *vdev); + +/** + * dp_periodic_sta_stats_mutex_create() - Create mutex for STA periodic stats + * @dp_intf: Pointer to the station interface + * + * Return: none + */ +void dp_periodic_sta_stats_mutex_create(struct wlan_dp_intf *dp_intf); + +/** + * dp_periodic_sta_stats_mutex_destroy() - Destroy STA periodic stats mutex + * @dp_intf: Pointer to the station interface + * + * Return: none + */ +void dp_periodic_sta_stats_mutex_destroy(struct wlan_dp_intf *dp_intf); + +#else +static inline void +dp_periodic_sta_stats_display(struct wlan_dp_psoc_context *dp_ctx) +{ +} + +static inline void +dp_periodic_sta_stats_config(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} + +static inline void dp_periodic_sta_stats_start(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void dp_periodic_sta_stats_stop(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +dp_periodic_sta_stats_init(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void +dp_periodic_sta_stats_mutex_create(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void +dp_periodic_sta_stats_mutex_destroy(struct wlan_dp_intf *dp_intf) +{ +} +#endif /* end #ifdef WLAN_FEATURE_PERIODIC_STA_STATS */ +#endif /* end #if !defined(WLAN_DP_PERIODIC_STA_STATS_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_prealloc.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_prealloc.h new file mode 100644 index 0000000000..9cbc3a38b3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_prealloc.h @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_DP_PREALLOC_H +#define _WLAN_DP_PREALLOC_H + +#include +#include +#include +#include +#include + +#ifdef DP_MEM_PRE_ALLOC +/** + * dp_prealloc_init() - Pre-allocate DP memory + * @ctrl_psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_prealloc_init(struct cdp_ctrl_objmgr_psoc *ctrl_psoc); + +/** + * dp_prealloc_deinit() - Free pre-alloced DP memory + * + * Return: None + */ +void dp_prealloc_deinit(void); + +/** + * dp_prealloc_get_context_memory() - gets pre-alloc DP context memory from + * global pool + * @ctxt_type: type of DP context + * @ctxt_size: size of memory needed + * + * This is done only as part of init happening in a single context. Hence + * no lock is used for protection + * + * Return: Address of context + */ +void *dp_prealloc_get_context_memory(uint32_t ctxt_type, qdf_size_t ctxt_size); + +/** + * dp_prealloc_put_context_memory() - puts back pre-alloc DP context memory to + * global pool + * @ctxt_type: type of DP context + * @vaddr: address of DP context + * + * This is done only as part of de-init happening in a single context. Hence + * no lock is used for protection + * + * Return: Failure if address not found + */ +QDF_STATUS dp_prealloc_put_context_memory(uint32_t ctxt_type, void *vaddr); + +/** + * dp_prealloc_get_coherent() - gets pre-alloc DP memory + * @size: size of memory needed + * @base_vaddr_unaligned: Unaligned virtual address. + * @paddr_unaligned: Unaligned physical address. + * @paddr_aligned: Aligned physical address. + * @align: Base address alignment. + * @align: alignment needed + * @ring_type: HAL ring type + * + * The function does not handle concurrent access to pre-alloc memory. + * All ring memory allocation from pre-alloc memory should happen from single + * context to avoid race conditions. + * + * Return: unaligned virtual address if success or null if memory alloc fails. + */ +void *dp_prealloc_get_coherent(uint32_t *size, void **base_vaddr_unaligned, + qdf_dma_addr_t *paddr_unaligned, + qdf_dma_addr_t *paddr_aligned, + uint32_t align, + uint32_t ring_type); + +/** + * dp_prealloc_put_coherent() - puts back pre-alloc DP memory + * @size: size of memory to be returned + * @vaddr_unligned: Unaligned virtual address. + * @paddr: Physical address + * + * Return: None + */ +void dp_prealloc_put_coherent(qdf_size_t size, void *vaddr_unligned, + qdf_dma_addr_t paddr); + +/** + * dp_prealloc_get_multi_pages() - gets pre-alloc DP multi-pages memory + * @src_type: the source that do memory allocation + * @element_size: single element size + * @element_num: total number of elements should be allocated + * @pages: multi page information storage + * @cacheable: coherent memory or cacheable memory + * + * Return: None. + */ +void dp_prealloc_get_multi_pages(uint32_t src_type, + qdf_size_t element_size, + uint16_t element_num, + struct qdf_mem_multi_page_t *pages, + bool cacheable); + +/** + * dp_prealloc_put_multi_pages() - puts back pre-alloc DP multi-pages memory + * @src_type: the source that do memory freement + * @pages: multi page information storage + * + * Return: None + */ +void dp_prealloc_put_multi_pages(uint32_t src_type, + struct qdf_mem_multi_page_t *pages); + +/** + * dp_prealloc_get_consistent_mem_unaligned() - gets pre-alloc unaligned + * consistent memory + * @size: total memory size + * @base_addr: pointer to dma address + * @ring_type: HAL ring type that requires memory + * + * Return: memory virtual address pointer on success, NULL on failure + */ +void *dp_prealloc_get_consistent_mem_unaligned(qdf_size_t size, + qdf_dma_addr_t *base_addr, + uint32_t ring_type); + +/** + * dp_prealloc_put_consistent_mem_unaligned() - puts back pre-alloc unaligned + * consistent memory + * @va_unaligned: memory virtual address pointer + * + * Return: None + */ +void dp_prealloc_put_consistent_mem_unaligned(void *va_unaligned); + +#else +static inline +QDF_STATUS dp_prealloc_init(struct cdp_ctrl_objmgr_psoc *ctrl_psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void dp_prealloc_deinit(void) { } + +#endif + +uint32_t dp_get_tx_inqueue(ol_txrx_soc_handle soc); + +#endif /* _WLAN_DP_PREALLOC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_priv.h new file mode 100644 index 0000000000..ff6d13f87d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_priv.h @@ -0,0 +1,979 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: Declare various struct, macros which are used for private to DP. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_DP_PRIV_STRUCT_H_ +#define _WLAN_DP_PRIV_STRUCT_H_ + +#include "wlan_dp_public_struct.h" +#include "cdp_txrx_cmn.h" +#include "wlan_dp_cfg.h" +#include "wlan_dp_objmgr.h" +#include +#include +#include "qdf_periodic_work.h" +#include +#include "pld_common.h" +#include "wlan_dp_nud_tracking.h" +#include +#include +#include "htc_api.h" +#include "wlan_dp_wfds.h" + +#ifndef NUM_TX_RX_HISTOGRAM +#define NUM_TX_RX_HISTOGRAM 128 +#endif + +#define NUM_TX_RX_HISTOGRAM_MASK (NUM_TX_RX_HISTOGRAM - 1) + +#if defined(WLAN_FEATURE_DP_BUS_BANDWIDTH) && defined(FEATURE_RUNTIME_PM) +/** + * enum dp_rtpm_tput_policy_state - states to track runtime_pm tput policy + * @DP_RTPM_TPUT_POLICY_STATE_INVALID: invalid state + * @DP_RTPM_TPUT_POLICY_STATE_REQUIRED: state indicating runtime_pm is required + * @DP_RTPM_TPUT_POLICY_STATE_NOT_REQUIRED: state indicating runtime_pm is NOT + * required + */ +enum dp_rtpm_tput_policy_state { + DP_RTPM_TPUT_POLICY_STATE_INVALID, + DP_RTPM_TPUT_POLICY_STATE_REQUIRED, + DP_RTPM_TPUT_POLICY_STATE_NOT_REQUIRED +}; + +/** + * struct dp_rtpm_tput_policy_context - RTPM throughput policy context + * @curr_state: current state of throughput policy (RTPM require or not) + * @wake_lock: wakelock for QDF wake_lock acquire/release APIs + * @rtpm_lock: lock use for QDF rutime PM prevent/allow APIs + * @high_tput_vote: atomic variable to keep track of voting + */ +struct dp_rtpm_tput_policy_context { + enum dp_rtpm_tput_policy_state curr_state; + qdf_wake_lock_t wake_lock; + qdf_runtime_lock_t rtpm_lock; + qdf_atomic_t high_tput_vote; +}; +#endif + +#define FISA_FLOW_MAX_AGGR_COUNT 16 /* max flow aggregate count */ + +/** + * struct wlan_dp_psoc_cfg - DP configuration parameters. + * @tx_orphan_enable: Enable/Disable tx orphan + * @rx_mode: rx mode for packet processing + * @tx_comp_loop_pkt_limit: max # of packets to be processed + * @rx_reap_loop_pkt_limit: max # of packets to be reaped + * @rx_hp_oos_update_limit: max # of HP OOS (out of sync) + * @rx_softirq_max_yield_duration_ns: max duration for RX softirq + * @periodic_stats_timer_interval: Print selective stats on this specified + * interval + * @periodic_stats_timer_duration: duration for which periodic timer should run + * @bus_bw_super_high_threshold: bus bandwidth super high threshold + * @bus_bw_ultra_high_threshold: bus bandwidth ultra high threshold + * @bus_bw_very_high_threshold: bus bandwidth very high threshold + * @bus_bw_mid_high_threshold: bus bandwidth mid high threshold + * @bus_bw_dbs_threshold: bus bandwidth for DBS mode threshold + * @bus_bw_high_threshold: bus bandwidth high threshold + * @bus_bw_medium_threshold: bandwidth threshold for medium bandwidth + * @bus_bw_low_threshold: bandwidth threshold for low bandwidth + * @bus_bw_compute_interval: bus bandwidth compute interval + * @enable_tcp_delack: enable Dynamic Configuration of Tcp Delayed Ack + * @enable_tcp_limit_output: enable TCP limit output + * @enable_tcp_adv_win_scale: enable TCP adv window scaling + * @tcp_delack_thres_high: High Threshold inorder to trigger TCP Del Ack + * indication + * @tcp_delack_thres_low: Low Threshold inorder to trigger TCP Del Ack + * indication + * @tcp_tx_high_tput_thres: High Threshold inorder to trigger High Tx + * Throughput requirement. + * @tcp_delack_timer_count: Del Ack Timer Count inorder to trigger TCP Del Ack + * indication + * @enable_tcp_param_update: enable tcp parameter update + * @bus_low_cnt_threshold: Threshold count to trigger low Tput GRO flush skip + * @enable_latency_crit_clients: Enable the handling of latency critical clients + * * @del_ack_enable: enable Dynamic Configuration of Tcp Delayed Ack + * @del_ack_threshold_high: High Threshold inorder to trigger TCP delay ack + * @del_ack_threshold_low: Low Threshold inorder to trigger TCP delay ack + * @del_ack_timer_value: Timeout value (ms) to send out all TCP del ack frames + * @del_ack_pkt_count: The maximum number of TCP delay ack frames + * @rx_thread_ul_affinity_mask: CPU mask to affine Rx_thread + * @rx_thread_affinity_mask: CPU mask to affine Rx_thread + * @cpu_map_list: RPS map for different RX queues + * @multicast_replay_filter: enable filtering of replayed multicast packets + * @rx_wakelock_timeout: Amount of time to hold wakelock for RX unicast packets + * @num_dp_rx_threads: number of dp rx threads + * @enable_dp_trace: Enable/Disable DP trace + * @dp_trace_config: DP trace configuration + * @enable_nud_tracking: Enable/Disable nud tracking + * @pkt_bundle_threshold_high: tx bundle high threshold + * @pkt_bundle_threshold_low: tx bundle low threshold + * @pkt_bundle_timer_value: tx bundle timer value in ms + * @pkt_bundle_size: tx bundle size + * @dp_proto_event_bitmap: Control for which protocol type diag log should be + * sent + * @fisa_enable: Enable/Disable FISA + * @icmp_req_to_fw_mark_interval: Interval to mark the ICMP Request packet to + * be sent to FW. + * @lro_enable: Enable/Disable lro + * @gro_enable: Enable/Disable gro + * @is_rx_fisa_enabled: flag to enable/disable FISA Rx + * @is_rx_fisa_lru_del_enabled: flag to enable/disable FST entry delete + */ +struct wlan_dp_psoc_cfg { + bool tx_orphan_enable; + + uint32_t rx_mode; + uint32_t tx_comp_loop_pkt_limit; + uint32_t rx_reap_loop_pkt_limit; + uint32_t rx_hp_oos_update_limit; + uint64_t rx_softirq_max_yield_duration_ns; +#ifdef WLAN_FEATURE_PERIODIC_STA_STATS + uint32_t periodic_stats_timer_interval; + uint32_t periodic_stats_timer_duration; +#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH + uint32_t bus_bw_super_high_threshold; + uint32_t bus_bw_ultra_high_threshold; + uint32_t bus_bw_very_high_threshold; + uint32_t bus_bw_dbs_threshold; + uint32_t bus_bw_mid_high_threshold; + uint32_t bus_bw_high_threshold; + uint32_t bus_bw_medium_threshold; + uint32_t bus_bw_low_threshold; + uint32_t bus_bw_compute_interval; + uint32_t enable_tcp_delack; + bool enable_tcp_limit_output; + uint32_t enable_tcp_adv_win_scale; + uint32_t tcp_delack_thres_high; + uint32_t tcp_delack_thres_low; + uint32_t tcp_tx_high_tput_thres; + uint32_t tcp_delack_timer_count; + bool enable_tcp_param_update; + uint32_t bus_low_cnt_threshold; + bool enable_latency_crit_clients; +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + bool del_ack_enable; + uint32_t del_ack_threshold_high; + uint32_t del_ack_threshold_low; + uint16_t del_ack_timer_value; + uint16_t del_ack_pkt_count; +#endif + uint32_t rx_thread_ul_affinity_mask; + uint32_t rx_thread_affinity_mask; + uint8_t cpu_map_list[CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST_LEN]; + bool multicast_replay_filter; + uint32_t rx_wakelock_timeout; + uint8_t num_dp_rx_threads; +#ifdef CONFIG_DP_TRACE + bool enable_dp_trace; + uint8_t dp_trace_config[DP_TRACE_CONFIG_STRING_LENGTH]; +#endif + uint8_t enable_nud_tracking; + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE + uint32_t pkt_bundle_threshold_high; + uint32_t pkt_bundle_threshold_low; + uint16_t pkt_bundle_timer_value; + uint16_t pkt_bundle_size; +#endif + uint32_t dp_proto_event_bitmap; + uint32_t fisa_enable; + + int icmp_req_to_fw_mark_interval; + + bool lro_enable; + bool gro_enable; +#ifdef WLAN_SUPPORT_RX_FISA + bool is_rx_fisa_enabled; + bool is_rx_fisa_lru_del_enabled; +#endif +}; + +/** + * struct tx_rx_histogram: structure to keep track of tx and rx packets + * received over 100ms intervals + * @interval_rx: # of rx packets received in the last 100ms interval + * @interval_tx: # of tx packets received in the last 100ms interval + * @next_vote_level: pld_bus_width_type voting level (high or low) + * determined on the basis of total tx and rx packets + * received in the last 100ms interval + * @next_rx_level: pld_bus_width_type voting level (high or low) + * determined on the basis of rx packets received in the + * last 100ms interval + * @next_tx_level: pld_bus_width_type voting level (high or low) + * determined on the basis of tx packets received in the + * last 100ms interval + * @is_rx_pm_qos_high: Capture rx_pm_qos voting + * @is_tx_pm_qos_high: Capture tx_pm_qos voting + * @qtime: timestamp when the record is added + * + * The structure keeps track of throughput requirements of wlan driver. + * An entry is added if either of next_vote_level, next_rx_level or + * next_tx_level changes. An entry is not added for every 100ms interval. + */ +struct tx_rx_histogram { + uint64_t interval_rx; + uint64_t interval_tx; + uint32_t next_vote_level; + uint32_t next_rx_level; + uint32_t next_tx_level; + bool is_rx_pm_qos_high; + bool is_tx_pm_qos_high; + uint64_t qtime; +}; + +/** + * struct dp_stats - DP stats + * @tx_rx_stats : Tx/Rx debug stats + * @arp_stats: arp debug stats + * @dns_stats: dns debug stats + * @tcp_stats: tcp debug stats + * @icmpv4_stats: icmpv4 debug stats + * @dhcp_stats: dhcp debug stats + * @eapol_stats: eapol debug stats + */ +struct dp_stats { + struct dp_tx_rx_stats tx_rx_stats; + struct dp_arp_stats arp_stats; + struct dp_dns_stats dns_stats; + struct dp_tcp_stats tcp_stats; + struct dp_icmpv4_stats icmpv4_stats; + struct dp_dhcp_stats dhcp_stats; + struct dp_eapol_stats eapol_stats; +}; + +/** + * enum dhcp_phase - Per Peer DHCP Phases + * @DHCP_PHASE_ACK: upon receiving DHCP_ACK/NAK message in REQUEST phase or + * DHCP_DELINE message in OFFER phase + * @DHCP_PHASE_DISCOVER: upon receiving DHCP_DISCOVER message in ACK phase + * @DHCP_PHASE_OFFER: upon receiving DHCP_OFFER message in DISCOVER phase + * @DHCP_PHASE_REQUEST: upon receiving DHCP_REQUEST message in OFFER phase or + * ACK phase (Renewal process) + */ +enum dhcp_phase { + DHCP_PHASE_ACK, + DHCP_PHASE_DISCOVER, + DHCP_PHASE_OFFER, + DHCP_PHASE_REQUEST +}; + +/** + * enum dhcp_nego_status - Per Peer DHCP Negotiation Status + * @DHCP_NEGO_STOP: when the peer is in ACK phase or client disassociated + * @DHCP_NEGO_IN_PROGRESS: when the peer is in DISCOVER or REQUEST + * (Renewal process) phase + */ +enum dhcp_nego_status { + DHCP_NEGO_STOP, + DHCP_NEGO_IN_PROGRESS +}; + +/* + * Pending frame type of EAP_FAILURE, bit number used in "pending_eap_frm_type" + * of sta_info. + */ +#define DP_PENDING_TYPE_EAP_FAILURE 0 + +enum bss_intf_state { + BSS_INTF_STOP, + BSS_INTF_START, +}; + +struct wlan_dp_sta_info { + struct qdf_mac_addr sta_mac; + unsigned long pending_eap_frm_type; + enum dhcp_phase dhcp_phase; + enum dhcp_nego_status dhcp_nego_status; +}; + +struct wlan_dp_conn_info { + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; + uint8_t proxy_arp_service; + uint8_t is_authenticated; +}; + +/** + * struct link_monitoring - link speed monitoring related info + * @enabled: Is link speed monitoring feature enabled + * @rx_linkspeed_threshold: link speed good/bad threshold + * @is_rx_linkspeed_good: true means rx link speed good, false means bad + */ +struct link_monitoring { + uint8_t enabled; + uint32_t rx_linkspeed_threshold; + uint8_t is_rx_linkspeed_good; +}; + +/** + * struct direct_link_info - direct link configuration items + * @config_set: is the direct link config active + * @low_latency: is low latency enabled + */ +struct direct_link_info { + bool config_set; + bool low_latency; +}; + +/** + * struct dp_fisa_reo_mismatch_stats - reo mismatch sub-case stats for FISA + * @allow_cce_match: packet allowed due to cce mismatch + * @allow_fse_metdata_mismatch: packet allowed since it belongs to same flow, + * only fse_metadata is not same. + * @allow_non_aggr: packet allowed due to any other reason. + */ +struct dp_fisa_reo_mismatch_stats { + uint32_t allow_cce_match; + uint32_t allow_fse_metdata_mismatch; + uint32_t allow_non_aggr; +}; + +/** + * struct dp_fisa_stats - FISA stats + * @invalid_flow_index: flow index invalid from RX HW TLV + * @update_deferred: workqueue deferred due to suspend + * @reo_mismatch: REO ID mismatch + * @incorrect_rdi: Incorrect REO dest indication in TLV + * (typically used for RDI = 0) + */ +struct dp_fisa_stats { + uint32_t invalid_flow_index; + uint32_t update_deferred; + struct dp_fisa_reo_mismatch_stats reo_mismatch; + uint32_t incorrect_rdi; +}; + +/** + * enum fisa_aggr_ret - FISA aggregation return code + * @FISA_AGGR_DONE: FISA aggregation done + * @FISA_AGGR_NOT_ELIGIBLE: Not eligible for FISA aggregation + * @FISA_FLUSH_FLOW: FISA flow flushed + */ +enum fisa_aggr_ret { + FISA_AGGR_DONE, + FISA_AGGR_NOT_ELIGIBLE, + FISA_FLUSH_FLOW +}; + +/** + * struct fisa_pkt_hist - FISA Packet history structure + * @tlv_hist: array of TLV history + * @ts_hist: array of timestamps of fisa packets + * @idx: index indicating the next location to be used in the array. + */ +struct fisa_pkt_hist { + uint8_t *tlv_hist; + qdf_time_t ts_hist[FISA_FLOW_MAX_AGGR_COUNT]; + uint32_t idx; +}; + +/** + * struct dp_fisa_rx_sw_ft - FISA Flow table entry + * @hw_fse: HAL Rx Flow Search Entry which matches HW definition + * @flow_hash: Flow hash value + * @flow_id_toeplitz: toeplitz hash value + * @flow_id: Flow index, equivalent to hash value truncated to FST size + * @stats: Stats tracking for this flow + * @is_ipv4_addr_entry: Flag indicating whether flow is IPv4 address tuple + * @is_valid: Flag indicating whether flow is valid + * @is_populated: Flag indicating whether flow is populated + * @is_flow_udp: Flag indicating whether flow is UDP stream + * @is_flow_tcp: Flag indicating whether flow is TCP stream + * @head_skb: HEAD skb where flow is aggregated + * @cumulative_l4_checksum: Cumulative L4 checksum + * @adjusted_cumulative_ip_length: Cumulative IP length + * @cur_aggr: Current aggregate length of flow + * @napi_flush_cumulative_l4_checksum: Cumulative L4 chekcsum for current + * NAPI flush + * @napi_flush_cumulative_ip_length: Cumulative IP length + * @last_skb: The last skb aggregated in the FISA flow + * @head_skb_ip_hdr_offset: IP header offset + * @head_skb_l4_hdr_offset: L4 header offset + * @rx_flow_tuple_info: RX tuple information + * @napi_id: NAPI ID (REO ID) on which the flow is being received + * @vdev: VDEV handle corresponding to the FLOW + * @vdev_id: DP vdev id + * @dp_intf: DP interface handle corresponding to the flow + * @bytes_aggregated: Number of bytes currently aggregated + * @flush_count: Number of Flow flushes done + * @aggr_count: Aggregation count + * @do_not_aggregate: Flag to indicate not to aggregate this flow + * @hal_cumultive_ip_len: HAL cumulative IP length + * @dp_ctx: DP component handle + * @soc_hdl: DP SoC handle + * @last_hal_aggr_count: last aggregate count fetched from RX PKT TLV + * @cur_aggr_gso_size: Current aggreagtesd GSO size + * @head_skb_udp_hdr: UDP header address for HEAD skb + * @frags_cumulative_len: + * @cmem_offset: CMEM offset + * @metadata: + * @reo_dest_indication: REO destination indication for the FLOW + * @flow_init_ts: FLOW init timestamp + * @last_accessed_ts: Timestamp when the flow was last accessed + * @pkt_hist: FISA aggreagtion packets history + * @same_mld_vdev_mismatch: Packets flushed after vdev_mismatch on same MLD + * @add_timestamp: FISA entry created timestamp + */ +struct dp_fisa_rx_sw_ft { + void *hw_fse; + uint32_t flow_hash; + uint32_t flow_id_toeplitz; + uint32_t flow_id; + struct cdp_flow_stats stats; + uint8_t is_ipv4_addr_entry; + uint8_t is_valid; + uint8_t is_populated; + uint8_t is_flow_udp; + uint8_t is_flow_tcp; + qdf_nbuf_t head_skb; + uint16_t cumulative_l4_checksum; + uint16_t adjusted_cumulative_ip_length; + uint16_t cur_aggr; + uint16_t napi_flush_cumulative_l4_checksum; + uint16_t napi_flush_cumulative_ip_length; + qdf_nbuf_t last_skb; + uint32_t head_skb_ip_hdr_offset; + uint32_t head_skb_l4_hdr_offset; + struct cdp_rx_flow_tuple_info rx_flow_tuple_info; + uint8_t napi_id; + struct dp_vdev *vdev; + uint8_t vdev_id; + struct wlan_dp_intf *dp_intf; + uint64_t bytes_aggregated; + uint32_t flush_count; + uint32_t aggr_count; + uint8_t do_not_aggregate; + uint16_t hal_cumultive_ip_len; + struct wlan_dp_psoc_context *dp_ctx; + /* TODO - Only reference needed to this is to get vdev. + * Once that ref is removed, this field can be deleted + */ + struct dp_soc *soc_hdl; + uint32_t last_hal_aggr_count; + uint32_t cur_aggr_gso_size; + qdf_net_udphdr_t *head_skb_udp_hdr; + uint16_t frags_cumulative_len; + uint32_t cmem_offset; + uint32_t metadata; + uint32_t reo_dest_indication; + qdf_time_t flow_init_ts; + qdf_time_t last_accessed_ts; +#ifdef WLAN_SUPPORT_RX_FISA_HIST + struct fisa_pkt_hist pkt_hist; +#endif + uint64_t same_mld_vdev_mismatch; + uint64_t add_timestamp; +}; + +#define DP_RX_GET_SW_FT_ENTRY_SIZE sizeof(struct dp_fisa_rx_sw_ft) +#define MAX_FSE_CACHE_FL_HST 10 +/** + * struct fse_cache_flush_history - Debug history cache flush + * @timestamp: Entry update timestamp + * @flows_added: Number of flows added for this flush + * @flows_deleted: Number of flows deleted for this flush + */ +struct fse_cache_flush_history { + uint64_t timestamp; + uint32_t flows_added; + uint32_t flows_deleted; +}; + +/** + * struct dp_rx_fst - FISA handle + * @base: Software (DP) FST + * @dp_ctx: DP component handle + * @hal_rx_fst: Pointer to HAL FST + * @hal_rx_fst_base_paddr: Base physical address of HAL RX HW FST + * @max_entries: Maximum number of flows FSE supports + * @num_entries: Num entries in flow table + * @max_skid_length: SKID Length + * @hash_mask: Hash mask to obtain legitimate hash entry + * @dp_rx_fst_lock: Lock for adding/deleting entries of FST + * @add_flow_count: Num of flows added + * @del_flow_count: Num of flows deleted + * @hash_collision_cnt: Num hash collisions + * @soc_hdl: DP SoC handle + * @fse_cache_flush_posted: Num FSE cache flush cmds posted + * @fse_cache_flush_timer: FSE cache flush timer + * @fse_cache_flush_allow: Flag to indicate if FSE cache flush is allowed + * @cache_fl_rec: FSE cache flush history + * @stats: FISA stats + * @fst_update_work: FST CMEM update work + * @fst_update_wq: FST CMEM update workqueue + * @fst_update_list: List to post event to CMEM update work + * @meta_counter: + * @cmem_ba: + * @dp_rx_sw_ft_lock: SW FST lock + * @cmem_resp_event: CMEM response event indicator + * @flow_deletion_supported: Flag to indicate if flow delete is supported + * @fst_in_cmem: Flag to indicate if FST is stored in CMEM + * @pm_suspended: Flag to indicate if driver is suspended + * @fst_wq_defer: + * @rx_hash_enabled: Flag to indicate if Hash based routing supported + * @rx_toeplitz_hash_key: hash key + * @rx_pkt_tlv_size: RX packet TLV size + */ +struct dp_rx_fst { + uint8_t *base; + struct wlan_dp_psoc_context *dp_ctx; + struct hal_rx_fst *hal_rx_fst; + uint64_t hal_rx_fst_base_paddr; + uint16_t max_entries; + uint16_t num_entries; + uint16_t max_skid_length; + uint32_t hash_mask; + qdf_spinlock_t dp_rx_fst_lock; + uint32_t add_flow_count; + uint32_t del_flow_count; + uint32_t hash_collision_cnt; + struct dp_soc *soc_hdl; + qdf_atomic_t fse_cache_flush_posted; + qdf_timer_t fse_cache_flush_timer; + bool fse_cache_flush_allow; + struct fse_cache_flush_history cache_fl_rec[MAX_FSE_CACHE_FL_HST]; + struct dp_fisa_stats stats; + + /* CMEM params */ + qdf_work_t fst_update_work; + qdf_workqueue_t *fst_update_wq; + qdf_list_t fst_update_list; + uint32_t meta_counter; + uint32_t cmem_ba; + qdf_spinlock_t dp_rx_sw_ft_lock[MAX_REO_DEST_RINGS]; + qdf_event_t cmem_resp_event; + bool flow_deletion_supported; + bool fst_in_cmem; + qdf_atomic_t pm_suspended; + bool fst_wq_defer; + bool rx_hash_enabled; + uint8_t *rx_toeplitz_hash_key; + uint16_t rx_pkt_tlv_size; +}; + +/** + * struct wlan_dp_intf - DP interface object related info + * @dp_ctx: DP context reference + * @link_monitoring: Link monitoring related info + * @mac_addr: Device MAC address + * @device_mode: Device Mode + * @intf_id: Interface ID + * @node: list node for membership in the interface list + * @dev: netdev reference + * @txrx_ops: Interface tx-rx ops + * @dp_stats: Device TX/RX statistics + * @is_sta_periodic_stats_enabled: Indicate whether to display sta periodic + * stats + * @periodic_stats_timer_count: count of periodic stats timer + * @periodic_stats_timer_counter: periodic stats timer counter + * @sta_periodic_stats_lock: sta periodic stats lock + * @stats: netdev stats + * @con_status: con_status value + * @dad: dad value + * @pkt_type_bitmap: packet type bitmap value + * @track_arp_ip: track ARP ip + * @dns_payload: dns payload + * @track_dns_domain_len: dns domain length + * @track_src_port: track source port value + * @track_dest_port: track destination port value + * @track_dest_ipv4: track destination ipv4 value + * @prev_rx_packets: Rx packets received N/W interface + * @prev_tx_packets: Tx packets transmitted on N/W interface + * @prev_tx_bytes: Tx bytes transmitted on N/W interface + * @prev_fwd_tx_packets: forwarded tx packets count + * @prev_fwd_rx_packets: forwarded rx packets count + * @nud_tracking: NUD tracking + * @mic_work: Work to handle MIC error + * @num_active_task: Active task count + * @sap_tx_block_mask: SAP TX block mask + * @gro_disallowed: GRO disallowed flag + * @gro_flushed: GRO flushed flag + * @fisa_disallowed: Flag to indicate fisa aggregation not to be done for a + * particular rx_context + * @fisa_force_flushed: Flag to indicate FISA flow has been flushed for a + * particular rx_context + * @runtime_disable_rx_thread: Runtime Rx thread flag + * @rx_stack: function pointer Rx packet handover + * @tx_fn: function pointer to send Tx packet + * @bss_state: AP BSS state + * @qdf_sta_eap_frm_done_event: EAP frame event management + * @traffic_end_ind: store traffic end indication info + * @direct_link_config: direct link configuration parameters + * @num_links: Number of links for this DP interface + * @def_link: Pointer to default link (usually used for TX operation) + * @dp_link_list_lock: Lock to protect dp_link_list operatiosn + * @dp_link_list: List of dp_links for this DP interface + */ +struct wlan_dp_intf { + struct wlan_dp_psoc_context *dp_ctx; + + struct link_monitoring link_monitoring; + + struct qdf_mac_addr mac_addr; + + enum QDF_OPMODE device_mode; + + qdf_list_node_t node; + + qdf_netdev_t dev; + struct ol_txrx_ops txrx_ops; + struct dp_stats dp_stats; +#ifdef WLAN_FEATURE_PERIODIC_STA_STATS + bool is_sta_periodic_stats_enabled; + uint16_t periodic_stats_timer_count; + uint32_t periodic_stats_timer_counter; + qdf_mutex_t sta_periodic_stats_lock; +#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ + qdf_net_dev_stats stats; + bool con_status; + bool dad; + uint32_t pkt_type_bitmap; + uint32_t track_arp_ip; + uint8_t dns_payload[256]; + uint32_t track_dns_domain_len; + uint32_t track_src_port; + uint32_t track_dest_port; + uint32_t track_dest_ipv4; +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH + unsigned long prev_rx_packets; + unsigned long prev_tx_packets; + unsigned long prev_tx_bytes; + uint64_t prev_fwd_tx_packets; + uint64_t prev_fwd_rx_packets; +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + struct dp_mic_work mic_work; +#ifdef WLAN_NUD_TRACKING + struct dp_nud_tracking_info nud_tracking; +#endif + qdf_atomic_t num_active_task; + uint32_t sap_tx_block_mask; + + qdf_atomic_t gro_disallowed; + uint8_t gro_flushed[DP_MAX_RX_THREADS]; + +#ifdef WLAN_SUPPORT_RX_FISA + /* + * Params used for controlling the fisa aggregation dynamically + */ + uint8_t fisa_disallowed[MAX_REO_DEST_RINGS]; + uint8_t fisa_force_flushed[MAX_REO_DEST_RINGS]; +#endif + + bool runtime_disable_rx_thread; + + enum bss_intf_state bss_state; + qdf_event_t qdf_sta_eap_frm_done_event; + struct dp_traffic_end_indication traffic_end_ind; +#ifdef FEATURE_DIRECT_LINK + struct direct_link_info direct_link_config; +#endif + uint8_t num_links; + struct wlan_dp_link *def_link; + qdf_spinlock_t dp_link_list_lock; + qdf_list_t dp_link_list; +}; + +#define WLAN_DP_LINK_MAGIC 0x5F44505F4C494E4B /* "_DP_LINK" in ASCII */ + +/** + * struct wlan_dp_link - DP link (corresponds to objmgr vdev) + * @node: list node for membership in the DP links list + * @magic: magic number to identify validity of dp_link + * @link_id: ID for this DP link (Same as vdev_id) + * @mac_addr: mac address of this link + * @dp_intf: Parent DP interface for this DP link + * @vdev: object manager vdev context + * @vdev_lock: vdev spin lock + * @conn_info: STA connection information + * @destroyed: flag to indicate dp_link destroyed (logical delete) + * @cdp_vdev_registered: flag to indicate if corresponding CDP vdev + * is registered + * @cdp_vdev_deleted: flag to indicate if corresponding CDP vdev is deleted + * @inactive_list_elem: list node for membership in dp link inactive list + */ +struct wlan_dp_link { + qdf_list_node_t node; + uint64_t magic; + uint8_t link_id; + struct qdf_mac_addr mac_addr; + struct wlan_dp_intf *dp_intf; + struct wlan_objmgr_vdev *vdev; + qdf_spinlock_t vdev_lock; + struct wlan_dp_conn_info conn_info; + uint8_t destroyed; + uint8_t cdp_vdev_registered; + uint8_t cdp_vdev_deleted; + TAILQ_ENTRY(wlan_dp_link) inactive_list_elem; +}; + +/** + * enum RX_OFFLOAD - Receive offload modes + * @CFG_LRO_ENABLED: Large Rx offload + * @CFG_GRO_ENABLED: Generic Rx Offload + */ +enum RX_OFFLOAD { + CFG_LRO_ENABLED = 1, + CFG_GRO_ENABLED, +}; + +#ifdef FEATURE_DIRECT_LINK +/** + * struct dp_direct_link_context - Datapath Direct Link context + * @dp_ctx: pointer to DP psoc priv context + * @lpass_ep_id: LPASS data msg service endpoint id + * @direct_link_refill_ring_hdl: Direct Link refill ring handle + * @dl_wfds: pointer to direct link WFDS context + */ +struct dp_direct_link_context { + struct wlan_dp_psoc_context *dp_ctx; + HTC_ENDPOINT_ID lpass_ep_id; + struct dp_srng *direct_link_refill_ring_hdl; + struct dp_direct_link_wfds_context *dl_wfds; +}; +#endif + +/** + * struct wlan_dp_psoc_context - psoc related data required for DP + * @psoc: object manager psoc context + * @pdev: object manager pdev context + * @qdf_dev: qdf device + * @dp_cfg: place holder for DP configuration + * @cdp_soc: CDP SoC handle + * @hif_handle: HIF handle + * @hal_soc: HAL SoC handle + * @intf_list_lock: DP interfaces list lock + * @intf_list: DP interfaces list + * @rps: rps + * @dynamic_rps: dynamic rps + * @enable_rxthread: Enable/Disable rx thread + * @enable_dp_rx_threads: Enable/Disable DP rx threads + * @napi_enable: Enable/Disable napi + * @dp_ops: DP callbacks registered from other modules + * @sb_ops: South bound direction call backs registered in DP + * @nb_ops: North bound direction call backs registered in DP + * @en_tcp_delack_no_lro: Enable/Disable tcp delack no lro + * @no_rx_offload_pkt_cnt: no of rx offload packet count + * @no_tx_offload_pkt_cnt: no of tx offload packet count + * @is_suspend: to check whether syetem suspend or not + * @is_wiphy_suspended: to check whether wiphy suspend or not + * @num_latency_critical_clients: num latency critical clients + * @high_bus_bw_request: high bus bandwidth request + * @bw_vote_time: bus bandwidth vote time + * @bus_bw_work: work for periodically computing DDR bus bandwidth requirements + * @cur_vote_level: Current vote level + * @prev_no_rx_offload_pkts: no of previous rx offload packets + * @prev_rx_offload_pkts: previous rx offload packets + * @prev_no_tx_offload_pkts: no of previous tx offload packets + * @prev_tx_offload_pkts: previous tx offload packets + * @cur_tx_level: Current Tx level + * @prev_tx: previous tx + * @low_tput_gro_enable: Enable/Disable low tput gro + * @bus_bw_lock: Bus bandwidth work lock + * @cur_rx_level: Current Rx level + * @bus_low_vote_cnt: bus low level count + * @disable_rx_ol_in_concurrency: disable RX offload in concurrency scenarios + * @disable_rx_ol_in_low_tput: disable RX offload in tput scenarios + * @txrx_hist_idx: txrx histogram index + * @rx_high_ind_cnt: rx high_ind count + * @receive_offload_cb: receive offload cb + * @dp_agg_param: DP aggregation parameter + * @dp_agg_param.rx_aggregation: + * @dp_agg_param.gro_force_flush: + * @dp_agg_param.tc_based_dyn_gro: + * @dp_agg_param.tc_ingress_prio: + * @rtpm_tput_policy_ctx: Runtime Tput policy context + * @txrx_hist: TxRx histogram + * @bbm_ctx: bus bandwidth manager context + * @dp_direct_link_lock: Direct link mutex lock + * @dp_direct_link_ctx: DP Direct Link context + * @arp_connectivity_map: ARP connectivity map + * @rx_wake_lock: rx wake lock + * @ol_enable: Enable/Disable offload + * @rx_fst: FST handle + * @fst_cmem_base: FST base in CMEM + * @fst_in_cmem: Flag indicating if FST is in CMEM or not + * @fisa_enable: Flag to indicate if FISA is enabled or not + * @fisa_lru_del_enable: Flag to indicate if LRU flow delete is enabled + * @fisa_dynamic_aggr_size_support: Indicate dynamic aggr size programming support + * @skip_fisa_param: FISA skip params structure + * @skip_fisa_param.skip_fisa: Flag to skip FISA aggr inside @skip_fisa_param + * @skip_fisa_param.fisa_force_flush: Force flush inside @skip_fisa_param + * @fst_cmem_size: CMEM size for FISA flow table + * @inactive_dp_link_list: inactive DP links list + * @dp_link_del_lock: DP link delete operation lock + */ +struct wlan_dp_psoc_context { + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + qdf_device_t qdf_dev; + struct wlan_dp_psoc_cfg dp_cfg; + ol_txrx_soc_handle cdp_soc; + struct hif_opaque_softc *hif_handle; + void *hal_soc; + + qdf_spinlock_t intf_list_lock; + qdf_list_t intf_list; + + bool rps; + bool dynamic_rps; + bool enable_rxthread; + bool enable_dp_rx_threads; + bool napi_enable; + + struct wlan_dp_psoc_callbacks dp_ops; + struct wlan_dp_psoc_sb_ops sb_ops; + struct wlan_dp_psoc_nb_ops nb_ops; + + bool en_tcp_delack_no_lro; + uint64_t no_rx_offload_pkt_cnt; + uint64_t no_tx_offload_pkt_cnt; + bool is_suspend; + bool is_wiphy_suspended; + qdf_atomic_t num_latency_critical_clients; + uint8_t high_bus_bw_request; + uint64_t bw_vote_time; +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH + struct qdf_periodic_work bus_bw_work; + int cur_vote_level; + qdf_spinlock_t bus_bw_lock; + int cur_rx_level; + uint64_t prev_no_rx_offload_pkts; + uint64_t prev_rx_offload_pkts; + uint64_t prev_no_tx_offload_pkts; + uint64_t prev_tx_offload_pkts; + int cur_tx_level; + uint64_t prev_tx; + qdf_atomic_t low_tput_gro_enable; + uint32_t bus_low_vote_cnt; +#ifdef FEATURE_RUNTIME_PM + struct dp_rtpm_tput_policy_context rtpm_tput_policy_ctx; +#endif +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + qdf_atomic_t disable_rx_ol_in_concurrency; + qdf_atomic_t disable_rx_ol_in_low_tput; + + uint16_t txrx_hist_idx; + struct tx_rx_histogram *txrx_hist; + + uint32_t rx_high_ind_cnt; +#ifdef FEATURE_BUS_BANDWIDTH_MGR + struct bbm_context *bbm_ctx; +#endif + + QDF_STATUS(*receive_offload_cb)(struct wlan_dp_intf *, qdf_nbuf_t nbuf); + + struct { + qdf_atomic_t rx_aggregation; + uint8_t gro_force_flush[DP_MAX_RX_THREADS]; + bool tc_based_dyn_gro; + uint32_t tc_ingress_prio; + } + dp_agg_param; + + uint32_t arp_connectivity_map; + + qdf_wake_lock_t rx_wake_lock; + + enum RX_OFFLOAD ol_enable; +#ifdef FEATURE_DIRECT_LINK + qdf_mutex_t dp_direct_link_lock; + struct dp_direct_link_context *dp_direct_link_ctx; +#endif +#ifdef WLAN_SUPPORT_RX_FISA + struct dp_rx_fst *rx_fst; + uint64_t fst_cmem_base; + bool fst_in_cmem; + uint8_t fisa_enable; + uint8_t fisa_lru_del_enable; + bool fisa_dynamic_aggr_size_support; + /* + * Params used for controlling the fisa aggregation dynamically + */ + struct { + qdf_atomic_t skip_fisa; + uint8_t fisa_force_flush[MAX_REO_DEST_RINGS]; + } skip_fisa_param; + + /* + * CMEM address and size for FST in CMEM, This is the address + * shared during init time. + */ + uint64_t fst_cmem_size; + +#endif + TAILQ_HEAD(, wlan_dp_link) inactive_dp_link_list; + qdf_spinlock_t dp_link_del_lock; +}; + +#ifdef WLAN_DP_PROFILE_SUPPORT +/** + * enum wlan_dp_cfg_param_type - param context type + * @DP_TX_DESC_NUM_CFG: Number of TX desc + * @DP_TX_EXT_DESC_NUM_CFG: Number of TX ext desc + * @DP_TX_RING_SIZE_CFG: TX ring size + * @DP_TX_COMPL_RING_SIZE_CFG: TX completion ring size + * @DP_RX_SW_DESC_NUM_CFG: Number of RX S.W descriptors + * @DP_REO_DST_RING_SIZE_CFG: RX ring size + * @DP_RXDMA_BUF_RING_SIZE_CFG: RXDMA BUF ring size + * @DP_RXDMA_REFILL_RING_SIZE_CFG: RXDMA refill ring size + * @DP_RX_REFILL_POOL_NUM_CFG: Refill buffer pool size + */ +enum wlan_dp_cfg_param_type { + DP_TX_DESC_NUM_CFG, + DP_TX_EXT_DESC_NUM_CFG, + DP_TX_RING_SIZE_CFG, + DP_TX_COMPL_RING_SIZE_CFG, + DP_RX_SW_DESC_NUM_CFG, + DP_REO_DST_RING_SIZE_CFG, + DP_RXDMA_BUF_RING_SIZE_CFG, + DP_RXDMA_REFILL_RING_SIZE_CFG, + DP_RX_REFILL_POOL_NUM_CFG, +}; + +/** + * struct wlan_dp_memory_profile_ctx - element representing DP config param info + * @param_type: DP config param type + * @size: size/length of the param to be selected + */ +struct wlan_dp_memory_profile_ctx { + enum wlan_dp_cfg_param_type param_type; + uint32_t size; +}; + +/** + * struct wlan_dp_memory_profile_info - Current memory profile info + * @is_selected: profile is selected or not + * @ctx: DP memory profile context + * @size: size of profile + */ +struct wlan_dp_memory_profile_info { + bool is_selected; + struct wlan_dp_memory_profile_ctx *ctx; + int size; +}; +#endif + +#endif /* end of _WLAN_DP_PRIV_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_rx_thread.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_rx_thread.h new file mode 100644 index 0000000000..80103c8629 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_rx_thread.h @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__WLAN_DP_RX_THREAD_H) +#define __WLAN_DP_RX_THREAD_H + +#include +#include +#include +#include +#include "cfg_dp.h" +#include +#include +#include "wlan_cfg.h" +#include "qdf_nbuf.h" +#include "qdf_threads.h" +#include "qdf_net_if.h" + +/* Maximum number of REO rings supported (for stats tracking) */ +#define DP_RX_TM_MAX_REO_RINGS WLAN_CFG_NUM_REO_DEST_RING +/* Number of DP RX threads supported */ +#define DP_MAX_RX_THREADS WLAN_CFG_NUM_REO_DEST_RING + +/* + * struct dp_rx_tm_handle_cmn - Opaque handle for rx_threads to store + * rx_tm_handle. This handle will be common for all the threads. + * Individual threads should not be accessing + * elements from dp_rx_tm_handle. It should be via an API. + */ +struct dp_rx_tm_handle_cmn; + +/** + * struct dp_rx_thread_stats - structure holding stats for DP RX thread + * @nbuf_queued: packets queued into the thread per reo ring + * @nbuf_queued_total: packets queued into the thread for all reo rings + * @nbuf_dequeued: packets de-queued from the thread + * @nbuf_sent_to_stack: packets sent to the stack. some dequeued packets may be + * dropped due to no peer or vdev, hence this stat. + * @gro_flushes: number of GRO flushes + * @gro_flushes_by_vdev_del: number of GRO flushes triggered by vdev del. + * @nbufq_max_len: maximum number of nbuf_lists queued for the thread + * @dropped_invalid_vdev: packets(nbuf_list) dropped due to no vdev + * @rx_flushed: packets flushed after vdev delete + * @dropped_invalid_peer: packets(nbuf_list) dropped due to no peer + * @dropped_invalid_os_rx_handles: packets(nbuf_list) dropped due to no os rx + * handles + * @dropped_others: packets dropped due to other reasons + * @dropped_enq_fail: packets dropped due to pending queue full + * @rx_nbufq_loop_yield: rx loop yield counter + */ +struct dp_rx_thread_stats { + unsigned int nbuf_queued[DP_RX_TM_MAX_REO_RINGS]; + unsigned int nbuf_queued_total; + unsigned int nbuf_dequeued; + unsigned int nbuf_sent_to_stack; + unsigned int gro_flushes; + unsigned int gro_flushes_by_vdev_del; + unsigned int nbufq_max_len; + unsigned int dropped_invalid_vdev; + unsigned int rx_flushed; + unsigned int dropped_invalid_peer; + unsigned int dropped_invalid_os_rx_handles; + unsigned int dropped_others; + unsigned int dropped_enq_fail; + unsigned int rx_nbufq_loop_yield; +}; + +/** + * enum dp_rx_refill_thread_state - enum to keep track of rx refill thread state + * @DP_RX_REFILL_THREAD_INVALID: initial invalid state + * @DP_RX_REFILL_THREAD_RUNNING: rx refill thread functional(NOT suspended, + * processing packets or waiting on a wait_queue) + * @DP_RX_REFILL_THREAD_SUSPENDING: rx refill thread is suspending + * @DP_RX_REFILL_THREAD_SUSPENDED: rx refill_thread suspended + */ +enum dp_rx_refill_thread_state { + DP_RX_REFILL_THREAD_INVALID, + DP_RX_REFILL_THREAD_RUNNING, + DP_RX_REFILL_THREAD_SUSPENDING, + DP_RX_REFILL_THREAD_SUSPENDED +}; + +/** + * struct dp_rx_thread - structure holding variables for a single DP RX thread + * @id: id of the dp_rx_thread (0 or 1 or 2..DP_MAX_RX_THREADS - 1) + * @task: task structure corresponding to the thread + * @start_event: handle of Event for DP Rx thread to signal startup + * @suspend_event: handle of Event for DP Rx thread to signal suspend + * @resume_event: handle of Event for DP Rx thread to signal resume + * @shutdown_event: handle of Event for DP Rx thread to signal shutdown + * @vdev_del_event: handle of Event for vdev del thread to signal completion + * for gro flush + * @gro_flush_ind: gro flush indication for DP Rx thread + * @event_flag: event flag to post events to DP Rx thread + * @nbuf_queue:nbuf queue used to store RX packets + * @nbufq_len: length of the nbuf queue + * @aff_mask: cuurent affinity mask of the DP Rx thread + * @stats: per thread stats + * @rtm_handle_cmn: abstract RX TM handle. This allows access to the dp_rx_tm + * structures via APIs. + * @napi: napi to deliver packet to stack via GRO + * @wait_q: wait queue to conditionally wait on events for DP Rx thread + * @netdev: dummy netdev to initialize the napi structure with + */ +struct dp_rx_thread { + uint8_t id; + qdf_thread_t *task; + qdf_event_t start_event; + qdf_event_t suspend_event; + qdf_event_t resume_event; + qdf_event_t shutdown_event; + qdf_event_t vdev_del_event; + qdf_atomic_t gro_flush_ind; + unsigned long event_flag; + qdf_nbuf_queue_head_t nbuf_queue; + unsigned long aff_mask; + struct dp_rx_thread_stats stats; + struct dp_rx_tm_handle_cmn *rtm_handle_cmn; + qdf_napi_struct napi; + qdf_wait_queue_head_t wait_q; + qdf_dummy_netdev_t netdev; +}; + +/** + * struct dp_rx_refill_thread - structure holding info of DP Rx refill thread + * @task: task structure corresponding to the thread + * @start_event: handle of Event for DP Rx refill thread to signal startup + * @suspend_event: handle of Event for DP Rx refill thread to signal suspend + * @resume_event: handle of Event for DP Rx refill thread to signal resume + * @shutdown_event: handle of Event for DP Rx refill thread to signal shutdown + * @event_flag: event flag to post events to DP Rx refill thread + * @wait_q: wait queue to conditionally wait on events for DP Rx refill thread + * @enabled: flag to check whether DP Rx refill thread is enabled + * @soc: abstract DP soc reference used in internal API's + * @state: state of DP Rx refill thread + */ +struct dp_rx_refill_thread { + qdf_thread_t *task; + qdf_event_t start_event; + qdf_event_t suspend_event; + qdf_event_t resume_event; + qdf_event_t shutdown_event; + unsigned long event_flag; + qdf_wait_queue_head_t wait_q; + bool enabled; + void *soc; + enum dp_rx_refill_thread_state state; +}; + +/** + * enum dp_rx_thread_state - enum to keep track of the state of the rx threads + * @DP_RX_THREADS_INVALID: initial invalid state + * @DP_RX_THREADS_RUNNING: rx threads functional(NOT suspended, processing + * packets or waiting on a wait_queue) + * @DP_RX_THREADS_SUSPENDING: rx thread is suspending + * @DP_RX_THREADS_SUSPENDED: rx_threads suspended from cfg8011 suspend + */ +enum dp_rx_thread_state { + DP_RX_THREADS_INVALID, + DP_RX_THREADS_RUNNING, + DP_RX_THREADS_SUSPENDING, + DP_RX_THREADS_SUSPENDED +}; + +/** + * struct dp_rx_tm_handle - DP RX thread infrastructure handle + * @num_dp_rx_threads: number of DP RX threads initialized + * @txrx_handle_cmn: opaque txrx handle to get to pdev and soc + * @state: state of the rx_threads. All of them should be in the same state. + * @rx_thread: array of pointers of type struct dp_rx_thread + * @allow_dropping: flag to indicate frame dropping is enabled + */ +struct dp_rx_tm_handle { + uint8_t num_dp_rx_threads; + struct dp_txrx_handle_cmn *txrx_handle_cmn; + enum dp_rx_thread_state state; + struct dp_rx_thread **rx_thread; + qdf_atomic_t allow_dropping; +}; + +/** + * enum dp_rx_gro_flush_code - enum differentiate different GRO flushes + * @DP_RX_GRO_NOT_FLUSH: not fush indication + * @DP_RX_GRO_NORMAL_FLUSH: Regular full flush + * @DP_RX_GRO_LOW_TPUT_FLUSH: Flush during low tput level + */ +enum dp_rx_gro_flush_code { + DP_RX_GRO_NOT_FLUSH = 0, + DP_RX_GRO_NORMAL_FLUSH, + DP_RX_GRO_LOW_TPUT_FLUSH +}; + +/** + * struct dp_txrx_config - dp txrx configuration passed to dp txrx modules + * @enable_rx_threads: DP rx threads or not + */ +struct dp_txrx_config { + bool enable_rx_threads; +}; + +struct dp_txrx_handle_cmn; + +/** + * struct dp_txrx_handle - main dp txrx container handle + * @pdev: cdp_pdev pdev handle + * @soc: ol_txrx_soc_handle soc handle + * @refill_thread: rx refill thread infra handle + * @rx_tm_hdl: rx thread infrastructure handle + * @config: configuration for DP TXRX modules + */ +struct dp_txrx_handle { + ol_txrx_soc_handle soc; + struct cdp_pdev *pdev; + struct dp_rx_tm_handle rx_tm_hdl; + struct dp_rx_refill_thread refill_thread; + struct dp_txrx_config config; +}; + +/** + * dp_rx_refill_thread_init() - Initialize DP Rx refill threads + * @refill_thread: Contains over all rx refill thread info + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_rx_refill_thread_init(struct dp_rx_refill_thread *refill_thread); + +/** + * dp_rx_refill_thread_deinit() - De-initialize DP Rx refill threads + * @refill_thread: Contains over all rx refill thread info + * + * Return: QDF_STATUS + */ +QDF_STATUS +dp_rx_refill_thread_deinit(struct dp_rx_refill_thread *refill_thread); + +/** + * dp_rx_tm_init() - initialize DP Rx thread infrastructure + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread infrastructure + * @num_dp_rx_threads: number of DP Rx threads to be initialized + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS dp_rx_tm_init(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t num_dp_rx_threads); + +/** + * dp_rx_tm_deinit() - de-initialize DP Rx thread infrastructure + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread infrastructure + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_rx_tm_deinit(struct dp_rx_tm_handle *rx_tm_hdl); + +/** + * dp_rx_tm_enqueue_pkt() - enqueue RX packet into RXTI + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread infrastructure + * @nbuf_list: single or a list of nbufs to be enqueued into RXTI + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS dp_rx_tm_enqueue_pkt(struct dp_rx_tm_handle *rx_tm_hdl, + qdf_nbuf_t nbuf_list); + +/** + * dp_rx_tm_gro_flush_ind() - flush GRO packets for a RX Context Id + * @rx_tm_handle: dp_rx_tm_handle containing the overall thread infrastructure + * @rx_ctx_id: RX Thread Context Id for which GRO flush needs to be done + * @flush_code: flush code to differentiate low TPUT flush + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS dp_rx_tm_gro_flush_ind(struct dp_rx_tm_handle *rx_tm_handle, + int rx_ctx_id, + enum dp_rx_gro_flush_code flush_code); +/** + * dp_rx_refill_thread_suspend() - Suspend RX refill thread + * @refill_thread: pointer to dp_rx_refill_thread object + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS +dp_rx_refill_thread_suspend(struct dp_rx_refill_thread *refill_thread); + +/** + * dp_rx_tm_suspend() - suspend all threads in RXTI + * @rx_tm_handle: pointer to dp_rx_tm_handle object + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_handle); + +/** + * dp_rx_tm_flush_by_vdev_id() - flush rx packets by vdev_id in all + * rx thread queues + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * @vdev_id: vdev id for which packets are to be flushed + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS dp_rx_tm_flush_by_vdev_id(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t vdev_id); + +/** + * dp_rx_refill_thread_resume() - Resume RX refill thread + * @refill_thread: pointer to dp_rx_refill_thread + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS +dp_rx_refill_thread_resume(struct dp_rx_refill_thread *refill_thread); + +/** + * dp_rx_tm_resume() - resume all threads in RXTI + * @rx_tm_handle: pointer to dp_rx_tm_handle object + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_rx_tm_resume(struct dp_rx_tm_handle *rx_tm_handle); + +/** + * dp_rx_tm_dump_stats() - dump stats for all threads in RXTI + * @rx_tm_handle: pointer to dp_rx_tm_handle object + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_rx_tm_dump_stats(struct dp_rx_tm_handle *rx_tm_handle); + +/** + * dp_rx_thread_get_txrx_handle() - get txrx handle from rx_tm_handle_cmn + * @rx_tm_handle_cmn: opaque pointer to dp_rx_tm_handle_cmn struct + * + * Return: pointer to dp_txrx_handle_cmn handle + */ +static inline struct dp_txrx_handle_cmn* +dp_rx_thread_get_txrx_handle(struct dp_rx_tm_handle_cmn *rx_tm_handle_cmn) +{ + return (((struct dp_rx_tm_handle *)rx_tm_handle_cmn)->txrx_handle_cmn); +} + +/** + * dp_rx_tm_get_napi_context() - get NAPI context for a RX CTX ID + * @rx_ctx_id: RX context ID (RX thread ID) corresponding to which NAPI is + * needed + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * + * Return: NULL on failure, else pointer to NAPI corresponding to rx_ctx_id + */ +qdf_napi_struct *dp_rx_tm_get_napi_context(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t rx_ctx_id); + +/** + * dp_rx_tm_set_cpu_mask() - set CPU mask for RX threads + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * @new_mask: New CPU mask pointer + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_rx_tm_set_cpu_mask(struct dp_rx_tm_handle *rx_tm_hdl, + qdf_cpu_mask *new_mask); + +#ifdef FEATURE_WLAN_DP_RX_THREADS +/** + * dp_txrx_get_cmn_hdl_frm_ext_hdl() - conversion func ext_hdl->txrx_handle_cmn + * @dp_ext_hdl: pointer to dp_txrx_handle structure + * + * Return: typecasted pointer of type - struct dp_txrx_handle_cmn + */ +static inline struct dp_txrx_handle_cmn * +dp_txrx_get_cmn_hdl_frm_ext_hdl(struct dp_txrx_handle *dp_ext_hdl) +{ + return (struct dp_txrx_handle_cmn *)dp_ext_hdl; +} + +/** + * dp_txrx_get_ext_hdl_frm_cmn_hdl() - conversion func txrx_handle_cmn->ext_hdl + * @txrx_cmn_hdl: pointer to dp_txrx_handle_cmn structure + * + * Return: typecasted pointer of type - struct dp_txrx_handle + */ +static inline struct dp_txrx_handle * +dp_txrx_get_ext_hdl_frm_cmn_hdl(struct dp_txrx_handle_cmn *txrx_cmn_hdl) +{ + return (struct dp_txrx_handle *)txrx_cmn_hdl; +} + +static inline ol_txrx_soc_handle +dp_txrx_get_soc_from_ext_handle(struct dp_txrx_handle_cmn *txrx_cmn_hdl) +{ + struct dp_txrx_handle *dp_ext_hdl; + + dp_ext_hdl = dp_txrx_get_ext_hdl_frm_cmn_hdl(txrx_cmn_hdl); + + return dp_ext_hdl->soc; +} + +/** + * dp_txrx_init() - initialize DP TXRX module + * @soc: ol_txrx_soc_handle + * @pdev_id: id of dp pdev handle + * @config: configuration for DP TXRX modules + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id, + struct dp_txrx_config *config); + +/** + * dp_txrx_deinit() - de-initialize DP TXRX module + * @soc: ol_txrx_soc_handle + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS dp_txrx_deinit(ol_txrx_soc_handle soc); + +/** + * dp_txrx_flush_pkts_by_vdev_id() - flush rx packets for a vdev_id + * @soc: ol_txrx_soc_handle object + * @vdev_id: vdev_id for which rx packets are to be flushed + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline QDF_STATUS dp_txrx_flush_pkts_by_vdev_id(ol_txrx_soc_handle soc, + uint8_t vdev_id) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (!soc) { + qdf_status = QDF_STATUS_E_INVAL; + goto ret; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + qdf_status = QDF_STATUS_E_FAULT; + goto ret; + } + + qdf_status = dp_rx_tm_flush_by_vdev_id(&dp_ext_hdl->rx_tm_hdl, vdev_id); +ret: + return qdf_status; +} + +/** + * dp_txrx_resume() - resume all threads + * @soc: ol_txrx_soc_handle object + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline QDF_STATUS dp_txrx_resume(ol_txrx_soc_handle soc) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct dp_rx_refill_thread *refill_thread; + + if (!soc) { + qdf_status = QDF_STATUS_E_INVAL; + goto ret; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + qdf_status = QDF_STATUS_E_FAULT; + goto ret; + } + + refill_thread = &dp_ext_hdl->refill_thread; + if (refill_thread->enabled) { + qdf_status = dp_rx_refill_thread_resume(refill_thread); + if (qdf_status != QDF_STATUS_SUCCESS) + return qdf_status; + } + + qdf_status = dp_rx_tm_resume(&dp_ext_hdl->rx_tm_hdl); +ret: + return qdf_status; +} + +/** + * dp_txrx_suspend() - suspend all threads + * @soc: ol_txrx_soc_handle object + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline QDF_STATUS dp_txrx_suspend(ol_txrx_soc_handle soc) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct dp_rx_refill_thread *refill_thread; + + if (!soc) { + qdf_status = QDF_STATUS_E_INVAL; + goto ret; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + qdf_status = QDF_STATUS_E_FAULT; + goto ret; + } + + refill_thread = &dp_ext_hdl->refill_thread; + if (refill_thread->enabled) { + qdf_status = dp_rx_refill_thread_suspend(refill_thread); + if (qdf_status != QDF_STATUS_SUCCESS) + return qdf_status; + } + + qdf_status = dp_rx_tm_suspend(&dp_ext_hdl->rx_tm_hdl); + if (QDF_IS_STATUS_ERROR(qdf_status) && refill_thread->enabled) + dp_rx_refill_thread_resume(refill_thread); + +ret: + return qdf_status; +} + +/** + * dp_rx_enqueue_pkt() - enqueue packet(s) into the thread + * @soc: ol_txrx_soc_handle object + * @nbuf_list: list of packets to be queued into the rx_thread + * + * The function accepts a list of skbs connected by the skb->next pointer and + * queues them into a RX thread to be sent to the stack. + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline +QDF_STATUS dp_rx_enqueue_pkt(ol_txrx_soc_handle soc, qdf_nbuf_t nbuf_list) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (!soc || !nbuf_list) { + qdf_status = QDF_STATUS_E_INVAL; + dp_err("invalid input params soc %pK nbuf %pK" + , soc, nbuf_list); + goto ret; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + qdf_status = QDF_STATUS_E_FAULT; + goto ret; + } + + qdf_status = dp_rx_tm_enqueue_pkt(&dp_ext_hdl->rx_tm_hdl, nbuf_list); +ret: + return qdf_status; +} + +/** + * dp_rx_gro_flush_ind() - Flush GRO packets for a given RX CTX Id + * @soc: ol_txrx_soc_handle object + * @rx_ctx_id: Context Id (Thread for which GRO packets need to be flushed) + * @flush_code: flush_code differentiating normal_flush from low_tput_flush + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline +QDF_STATUS dp_rx_gro_flush_ind(ol_txrx_soc_handle soc, int rx_ctx_id, + enum dp_rx_gro_flush_code flush_code) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (!soc) { + qdf_status = QDF_STATUS_E_INVAL; + dp_err("invalid input param soc %pK", soc); + goto ret; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + qdf_status = QDF_STATUS_E_FAULT; + goto ret; + } + + qdf_status = dp_rx_tm_gro_flush_ind(&dp_ext_hdl->rx_tm_hdl, rx_ctx_id, + flush_code); +ret: + return qdf_status; +} + +/** + * dp_txrx_ext_dump_stats() - dump txrx external module stats + * @soc: ol_txrx_soc_handle object + * @stats_id: id for the module whose stats are needed + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline QDF_STATUS dp_txrx_ext_dump_stats(ol_txrx_soc_handle soc, + uint8_t stats_id) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status; + + if (!soc) { + dp_err("invalid input params soc %pK", soc); + return QDF_STATUS_E_INVAL; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) + return QDF_STATUS_E_FAULT; + + if (stats_id == CDP_DP_RX_THREAD_STATS) + qdf_status = dp_rx_tm_dump_stats(&dp_ext_hdl->rx_tm_hdl); + else + qdf_status = QDF_STATUS_E_INVAL; + + return qdf_status; +} + +/** + * dp_rx_get_napi_context() - get NAPI context for a RX CTX ID + * @soc: ol_txrx_soc_handle object + * @rx_ctx_id: RX context ID (RX thread ID) corresponding to which NAPI is + * needed + * + * Return: NULL on failure, else pointer to NAPI corresponding to rx_ctx_id + */ +static inline +qdf_napi_struct *dp_rx_get_napi_context(ol_txrx_soc_handle soc, + uint8_t rx_ctx_id) +{ + struct dp_txrx_handle *dp_ext_hdl; + + if (!soc) { + dp_err("soc in NULL!"); + return NULL; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + dp_err("dp_ext_hdl in NULL!"); + return NULL; + } + + return dp_rx_tm_get_napi_context(&dp_ext_hdl->rx_tm_hdl, rx_ctx_id); +} + +/** + * dp_txrx_set_cpu_mask() - set CPU mask for RX threads + * @soc: ol_txrx_soc_handle object + * @new_mask: New CPU mask pointer + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +static inline +QDF_STATUS dp_txrx_set_cpu_mask(ol_txrx_soc_handle soc, qdf_cpu_mask *new_mask) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (!soc) { + qdf_status = QDF_STATUS_E_INVAL; + goto ret; + } + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) { + qdf_status = QDF_STATUS_E_FAULT; + goto ret; + } + + qdf_status = dp_rx_tm_set_cpu_mask(&dp_ext_hdl->rx_tm_hdl, new_mask); + +ret: + return qdf_status; +} + +#else + +static inline +QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id, + struct dp_txrx_config *config) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS dp_txrx_deinit(ol_txrx_soc_handle soc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS dp_txrx_flush_pkts_by_vdev_id(ol_txrx_soc_handle soc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS dp_txrx_resume(ol_txrx_soc_handle soc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS dp_txrx_suspend(ol_txrx_soc_handle soc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS dp_rx_enqueue_pkt(ol_txrx_soc_handle soc, qdf_nbuf_t nbuf_list) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS dp_rx_gro_flush_ind(ol_txrx_soc_handle soc, int rx_ctx_id, + enum dp_rx_gro_flush_code flush_code) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS dp_txrx_ext_dump_stats(ol_txrx_soc_handle soc, + uint8_t stats_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +qdf_napi_struct *dp_rx_get_napi_context(ol_txrx_soc_handle soc, + uint8_t rx_ctx_id) +{ + return NULL; +} + +static inline +QDF_STATUS dp_txrx_set_cpu_mask(ol_txrx_soc_handle soc, qdf_cpu_mask *new_mask) +{ + return QDF_STATUS_SUCCESS; +} + +#endif /* FEATURE_WLAN_DP_RX_THREADS */ + +/** + * dp_rx_tm_get_pending() - get number of frame in thread + * nbuf queue pending + * @soc: ol_txrx_soc_handle object + * + * Return: number of frames + */ +int dp_rx_tm_get_pending(ol_txrx_soc_handle soc); +#endif /* __WLAN_DP_RX_THREAD_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_swlm.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_swlm.h new file mode 100644 index 0000000000..e111d0bea2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_swlm.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_DP_SWLM_H_ +#define _WLAN_DP_SWLM_H_ + +#ifdef WLAN_DP_FEATURE_SW_LATENCY_MGR + +#define DP_SWLM_TCL_TPUT_PASS_THRESH 3 + +#define DP_SWLM_TCL_RX_TRAFFIC_THRESH 50 +#define DP_SWLM_TCL_TX_TRAFFIC_THRESH 50 +#define DP_SWLM_TCL_TX_PKT_THRESH 2 + +/* Traffic test time is in us */ +#define DP_SWLM_TCL_TRAFFIC_SAMPLING_TIME 250 +#define DP_SWLM_TCL_TIME_FLUSH_THRESH 1000 +#define DP_SWLM_TCL_TX_THRESH_MULTIPLIER 2 + +/* Inline Functions */ + +/** + * dp_tx_is_special_frame() - check if this TX frame is a special frame. + * @nbuf: TX skb pointer + * @frame_mask: the mask for required special frames + * + * Check if TX frame is a required special frame. + * + * Returns: true, if this frame is a needed special frame, + * false, otherwise + */ +static inline +bool dp_tx_is_special_frame(qdf_nbuf_t nbuf, uint32_t frame_mask) +{ + if (((frame_mask & FRAME_MASK_IPV4_ARP) && + qdf_nbuf_is_ipv4_arp_pkt(nbuf)) || + ((frame_mask & FRAME_MASK_IPV4_DHCP) && + qdf_nbuf_is_ipv4_dhcp_pkt(nbuf)) || + ((frame_mask & FRAME_MASK_IPV4_EAPOL) && + qdf_nbuf_is_ipv4_eapol_pkt(nbuf)) || + ((frame_mask & FRAME_MASK_IPV6_DHCP) && + qdf_nbuf_is_ipv6_dhcp_pkt(nbuf))) + return true; + + return false; +} + +/** + * dp_swlm_tcl_reset_session_data() - Reset the TCL coalescing session data + * @soc: DP soc handle + * @ring_id: TCL ring id + * + * Returns QDF_STATUS + */ +static inline QDF_STATUS +dp_swlm_tcl_reset_session_data(struct dp_soc *soc, uint8_t ring_id) +{ + struct dp_swlm_params *params = &soc->swlm.params; + + params->tcl[ring_id].coalesce_end_time = qdf_get_log_timestamp_usecs() + + params->time_flush_thresh; + params->tcl[ring_id].bytes_coalesced = 0; + params->tcl[ring_id].bytes_flush_thresh = + params->tcl[ring_id].sampling_session_tx_bytes * + params->tx_thresh_multiplier; + qdf_timer_sync_cancel(¶ms->tcl[ring_id].flush_timer); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_swlm_tcl_pre_check() - Pre checks for current packet to be transmitted + * @soc: Datapath soc handle + * @tcl_data: tcl swlm data + * + * Returns: QDF_STATUS_SUCCESS, if all pre-check conditions pass + * QDF_STATUS_E_FAILURE, otherwise + */ +static inline QDF_STATUS +dp_swlm_tcl_pre_check(struct dp_soc *soc, + struct dp_swlm_tcl_data *tcl_data) +{ + struct dp_swlm *swlm = &soc->swlm; + uint32_t frame_mask = FRAME_MASK_IPV4_ARP | FRAME_MASK_IPV4_DHCP | + FRAME_MASK_IPV4_EAPOL | FRAME_MASK_IPV6_DHCP; + + if (tcl_data->tid > DP_VO_TID) { + DP_STATS_INC(swlm, tcl[tcl_data->ring_id].tid_fail, 1); + goto fail; + } + + if (dp_tx_is_special_frame(tcl_data->nbuf, frame_mask)) { + DP_STATS_INC(swlm, tcl[tcl_data->ring_id].sp_frames, 1); + goto fail; + } + + if (tcl_data->num_ll_connections) { + DP_STATS_INC(swlm, tcl[tcl_data->ring_id].ll_connection, 1); + goto fail; + } + + return QDF_STATUS_SUCCESS; + +fail: + return QDF_STATUS_E_FAILURE; +} + +/** + * dp_swlm_query_policy() - apply software latency policy based on ring type. + * @soc: Datapath global soc handle + * @ring_type: SRNG type + * @query_data: private data for the query corresponding to the ring type + * + * Returns: 1, if policy is to be applied + * 0, if policy is not to be applied + */ +static inline int dp_swlm_query_policy(struct dp_soc *soc, int ring_type, + union swlm_data query_data) +{ + struct dp_swlm *swlm = &soc->swlm; + + switch (ring_type) { + case TCL_DATA: + return swlm->ops->tcl_wr_coalesce_check(soc, + query_data.tcl_data); + default: + dp_err("Ring type %d not supported by SW latency manager", + ring_type); + break; + } + + return 0; +} + +/* Function Declarations */ + +/** + * dp_soc_swlm_attach() - attach the software latency manager resources + * @soc: Datapath global soc handle + * + * Returns: QDF_STATUS + */ +QDF_STATUS dp_soc_swlm_attach(struct dp_soc *soc); + +/** + * dp_soc_swlm_detach() - detach the software latency manager resources + * @soc: Datapath global soc handle + * + * Returns: QDF_STATUS + */ +QDF_STATUS dp_soc_swlm_detach(struct dp_soc *soc); + +/** + * dp_print_swlm_stats() - Print the SWLM stats + * @soc: Datapath soc handle + * + * Returns: QDF_STATUS + */ +QDF_STATUS dp_print_swlm_stats(struct dp_soc *soc); + +#endif /* WLAN_DP_FEATURE_SW_LATENCY_MGR */ + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_txrx.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_txrx.h new file mode 100644 index 0000000000..9174b8b1f8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_txrx.h @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_DP_TXRX_H__ +#define __WLAN_DP_TXRX_H__ + +#include +#include +#include +#include +#include +#include "wlan_dp_priv.h" + +/** DP Tx Time out value */ +#define DP_TX_TIMEOUT qdf_system_msecs_to_ticks(5000) + +#define DP_TX_STALL_THRESHOLD 4 + +#ifdef FEATURE_WLAN_WAPI +#define IS_DP_ETHERTYPE_WAI(_nbuf) (qdf_ntohs(qdf_nbuf_get_protocol(_nbuf)) == \ + ETHERTYPE_WAI) +#else +#define IS_DP_ETHERTYPE_WAI(_nbuf) (false) +#endif + +#define DP_CONNECTIVITY_CHECK_SET_ARP 1 +#define DP_CONNECTIVITY_CHECK_SET_DNS 2 +#define DP_CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE 3 +#define DP_CONNECTIVITY_CHECK_SET_ICMPV4 4 +#define DP_CONNECTIVITY_CHECK_SET_ICMPV6 5 +#define DP_CONNECTIVITY_CHECK_SET_TCP_SYN 6 +#define DP_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK 7 +#define DP_CONNECTIVITY_CHECK_SET_TCP_ACK 8 + +/** + * wlan_dp_intf_get_pkt_type_bitmap_value() - Get packt type bitmap info + * @intf_ctx: DP interface context + * + * Return: bitmap information + */ +uint32_t wlan_dp_intf_get_pkt_type_bitmap_value(void *intf_ctx); + +#if defined(WLAN_SUPPORT_RX_FISA) +/** + * dp_rx_skip_fisa() - Set flags to skip fisa aggregation + * @dp_ctx: DP component handle + * @value: allow or skip fisa + * + * Return: None + */ +void dp_rx_skip_fisa(struct wlan_dp_psoc_context *dp_ctx, uint32_t value); +#endif + +/** + * dp_reset_all_intfs_connectivity_stats() - reset connectivity stats + * @dp_ctx: pointer to DP Context + * + * Return: None + */ +void dp_reset_all_intfs_connectivity_stats(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_softap_check_wait_for_tx_eap_pkt() - Check and wait for eap failure + * pkt completion event + * @dp_intf: pointer to DP interface + * @mac_addr: mac address of peer + * + * Check and wait for eap failure pkt tx completion. + * + * Return: void + */ +void dp_softap_check_wait_for_tx_eap_pkt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr); + +#ifdef SAP_DHCP_FW_IND +/** + * dp_post_dhcp_ind() - Send DHCP START/STOP indication to FW + * @dp_link: DP link handle + * @mac_addr: mac address + * @dhcp_start: true if DHCP start, otherwise DHCP stop + * + * Return: error number + */ +int dp_post_dhcp_ind(struct wlan_dp_link *dp_link, + uint8_t *mac_addr, bool dhcp_start); + +/** + * dp_softap_inspect_dhcp_packet() - Inspect DHCP packet + * @dp_link: DP link handle + * @nbuf: pointer to OS packet (sk_buff) + * @dir: direction + * + * Inspect the Tx/Rx frame, and send DHCP START/STOP notification to the FW + * through WMI message, during DHCP based IP address acquisition phase. + * + * - Send DHCP_START notification to FW when SAP gets DHCP Discovery + * - Send DHCP_STOP notification to FW when SAP sends DHCP ACK/NAK + * + * DHCP subtypes are determined by a status octet in the DHCP Message type + * option (option code 53 (0x35)). + * + * Each peer will be in one of 4 DHCP phases, starts from QDF_DHCP_PHASE_ACK, + * and transitioned per DHCP message type as it arrives. + * + * - QDF_DHCP_PHASE_DISCOVER: upon receiving DHCP_DISCOVER message in ACK phase + * - QDF_DHCP_PHASE_OFFER: upon receiving DHCP_OFFER message in DISCOVER phase + * - QDF_DHCP_PHASE_REQUEST: upon receiving DHCP_REQUEST message in OFFER phase + * or ACK phase (Renewal process) + * - QDF_DHCP_PHASE_ACK : upon receiving DHCP_ACK/NAK message in REQUEST phase + * or DHCP_DELINE message in OFFER phase + * + * Return: error number + */ +int dp_softap_inspect_dhcp_packet(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf, + enum qdf_proto_dir dir); +#else +static inline +int dp_post_dhcp_ind(struct wlan_dp_link *dp_link, + uint8_t *mac_addr, bool dhcp_start) +{ + return 0; +} + +static inline +int dp_softap_inspect_dhcp_packet(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf, + enum qdf_proto_dir dir) +{ + return 0; +} +#endif + +/** + * dp_rx_flush_packet_cbk() - flush rx packet handler + * @dp_link_context: pointer to DP link context + * @link_id: vdev_id of the packets to be flushed + * + * Flush rx packet callback registered with data path. DP will call this to + * notify when packets for a particular vdev is to be flushed out. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS dp_rx_flush_packet_cbk(void *dp_link_context, uint8_t link_id); + +/** + * dp_softap_start_xmit() - Transmit a frame for SAP interface + * @nbuf: pointer to Network buffer + * @dp_link: DP link handle + * + * Return: QDF_STATUS_SUCCESS on successful transmission + */ +QDF_STATUS dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_dp_link *dp_link); + +/** + * dp_softap_tx_timeout() - TX timeout handler + * @dp_intf: pointer to DP interface + * + * Timeout API called for mode interfaces (SoftAP/P2P GO) + * when TX transmission takes too long. + * called by the OS_IF layer legacy driver. + * + * Return: None + */ +void dp_softap_tx_timeout(struct wlan_dp_intf *dp_intf); + +/** + * dp_softap_rx_packet_cbk() - Receive packet handler for SAP + * @intf_ctx: pointer to DP interface context + * @rx_buf: pointer to rx qdf_nbuf + * + * Receive callback registered with data path. DP will call this to notify + * when one or more packets were received for a registered + * STA. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS +dp_softap_rx_packet_cbk(void *intf_ctx, qdf_nbuf_t rx_buf); + +/** + * dp_start_xmit() - Transmit a frame for STA interface + * @nbuf: pointer to Network buffer + * @dp_link: DP link handle + * + * Return: QDF_STATUS_SUCCESS on successful transmission + */ +QDF_STATUS +dp_start_xmit(struct wlan_dp_link *dp_link, qdf_nbuf_t nbuf); + +/** + * dp_tx_timeout() - DP Tx timeout API + * @dp_intf: Data path interface pointer + * + * Function called by OS_IF there is any timeout during transmission. + * + * Return: none + */ +void dp_tx_timeout(struct wlan_dp_intf *dp_intf); + +/** + * dp_rx_packet_cbk() - Receive packet handler + * @dp_link_context: pointer to DP link context + * @rx_buf: pointer to rx qdf_nbuf + * + * Receive callback registered with data path. DP will call this to notify + * when one or more packets were received for a registered + * STA. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS dp_rx_packet_cbk(void *dp_link_context, qdf_nbuf_t rx_buf); + +#if defined(WLAN_SUPPORT_RX_FISA) +/** + * wlan_dp_rx_fisa_cbk() - Entry function to FISA to handle aggregation + * @dp_soc: core txrx main context + * @dp_vdev: Handle DP vdev + * @nbuf_list: List nbufs to be aggregated + * + * Return: Success on aggregation + */ +QDF_STATUS wlan_dp_rx_fisa_cbk(void *dp_soc, void *dp_vdev, + qdf_nbuf_t nbuf_list); + +/** + * wlan_dp_rx_fisa_flush_by_ctx_id() - Flush function to end of context + * flushing of aggregates + * @dp_soc: core txrx main context + * @ring_num: REO number to flush the flow Rxed on the REO + * + * Return: Success on flushing the flows for the REO + */ +QDF_STATUS wlan_dp_rx_fisa_flush_by_ctx_id(void *dp_soc, int ring_num); + +/** + * wlan_dp_rx_fisa_flush_by_vdev_id() - Flush fisa aggregates per vdev id + * @dp_soc: core txrx main context + * @vdev_id: vdev ID + * + * Return: Success on flushing the flows for the vdev + */ +QDF_STATUS wlan_dp_rx_fisa_flush_by_vdev_id(void *dp_soc, uint8_t vdev_id); +#else +static inline QDF_STATUS wlan_dp_rx_fisa_flush_by_vdev_id(void *dp_soc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_dp_rx_deliver_to_stack() - DP helper function to deliver RX pkts to + * stack + * @dp_intf: pointer to DP interface context + * @nbuf: pointer to nbuf + * + * The function calls the appropriate stack function depending upon the packet + * type and whether GRO/LRO is enabled. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS wlan_dp_rx_deliver_to_stack(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf); + +/** + * dp_rx_thread_gro_flush_ind_cbk() - receive handler to flush GRO packets + * @link_ctx: pointer to DP interface context + * @rx_ctx_id: RX CTX Id for which flush should happen + * + * Receive callback registered with DP layer which flushes GRO packets + * for a given RX CTX ID (RX Thread) + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS dp_rx_thread_gro_flush_ind_cbk(void *link_ctx, int rx_ctx_id); + +/** + * dp_rx_pkt_thread_enqueue_cbk() - receive pkt handler to enqueue into thread + * @link_ctx: pointer to DP link context + * @nbuf_list: pointer to qdf_nbuf list + * + * Receive callback registered with DP layer which enqueues packets into dp rx + * thread + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS dp_rx_pkt_thread_enqueue_cbk(void *link_ctx, + qdf_nbuf_t nbuf_list); + +/** + * dp_disable_rx_ol_for_low_tput() - Disable Rx offload in low TPUT scenario + * @dp_ctx: dp context + * @disable: true/false to disable/enable the Rx offload + * + * Return: none + */ +void dp_disable_rx_ol_for_low_tput(struct wlan_dp_psoc_context *dp_ctx, + bool disable); + +/** + * dp_tx_rx_collect_connectivity_stats_info() - collect connectivity stats + * @nbuf: pointer to n/w buffer + * @context: pointer to DP interface + * @action: action done on pkt. + * @pkt_type: data pkt type + * + * Return: None + */ +void +dp_tx_rx_collect_connectivity_stats_info(qdf_nbuf_t nbuf, void *context, + enum connectivity_stats_pkt_status action, uint8_t *pkt_type); + +static inline void +dp_nbuf_fill_gso_size(qdf_netdev_t dev, qdf_nbuf_t nbuf) +{ + unsigned long val; + + if (qdf_nbuf_is_cloned(nbuf) && qdf_nbuf_is_nonlinear(nbuf) && + qdf_nbuf_get_gso_size(nbuf) == 0 && + qdf_nbuf_is_ipv4_tcp_pkt(nbuf)) { + val = dev->mtu - ((qdf_nbuf_transport_header(nbuf) - + qdf_nbuf_network_header(nbuf)) + + qdf_nbuf_get_tcp_hdr_len(nbuf)); + qdf_nbuf_set_gso_size(nbuf, val); + } +} + +#ifdef CONFIG_HL_SUPPORT +static inline QDF_STATUS +dp_nbuf_nontso_linearize(qdf_nbuf_t nbuf) +{ + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +dp_nbuf_nontso_linearize(qdf_nbuf_t nbuf) +{ + if (qdf_nbuf_is_nonlinear(nbuf) && qdf_nbuf_is_tso(nbuf) == false) { + if (qdf_unlikely(qdf_nbuf_linearize(nbuf))) + return QDF_STATUS_E_NOMEM; + } + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void dp_event_eapol_log(qdf_nbuf_t nbuf, enum qdf_proto_dir dir); +#else +static inline +void dp_event_eapol_log(qdf_nbuf_t nbuf, enum qdf_proto_dir dir) +{} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +static inline +qdf_nbuf_t dp_nbuf_orphan(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + unsigned int tx_flow_low_watermark; + int need_orphan = 0; + int cpu; + + tx_flow_low_watermark = + dp_ops->dp_get_tx_flow_low_watermark(dp_ops->callback_ctx, + dp_intf->dev); + if (tx_flow_low_watermark > 0) { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) + /* + * The TCP TX throttling logic is changed a little after + * 3.19-rc1 kernel, the TCP sending limit will be smaller, + * which will throttle the TCP packets to the host driver. + * The TCP UP LINK throughput will drop heavily. In order to + * fix this issue, need to orphan the socket buffer asap, which + * will call skb's destructor to notify the TCP stack that the + * SKB buffer is unowned. And then the TCP stack will pump more + * packets to host driver. + * + * The TX packets might be dropped for UDP case in the iperf + * testing. So need to be protected by follow control. + */ + need_orphan = 1; +#else + if (dp_ctx->dp_cfg.tx_orphan_enable) + need_orphan = 1; +#endif + } else if (dp_ctx->dp_cfg.tx_orphan_enable) { + if (qdf_nbuf_is_ipv4_tcp_pkt(nbuf) || + qdf_nbuf_is_ipv6_tcp_pkt(nbuf)) + need_orphan = 1; + } + + if (need_orphan) { + qdf_nbuf_orphan(nbuf); + cpu = qdf_get_smp_processor_id(); + ++dp_intf->dp_stats.tx_rx_stats.per_cpu[cpu].tx_orphaned; + } else { + nbuf = __qdf_nbuf_unshare(nbuf); + } + + return nbuf; +} + +/** + * dp_get_tx_resource() - check tx resources and take action + * @dp_link: DP link handle + * @mac_addr: mac address + * + * Return: none + */ +void dp_get_tx_resource(struct wlan_dp_link *dp_link, + struct qdf_mac_addr *mac_addr); + +#else +#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 19, 0)) +/** + * dp_nbuf_orphan() - skb_unshare a cloned packed else skb_orphan + * @dp_intf: pointer to DP interface + * @nbuf: pointer to nbuf data packet + * + * Return: pointer to nbuf structure + */ +static inline +qdf_nbuf_t dp_nbuf_orphan(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + int cpu; + + dp_nbuf_fill_gso_size(dp_intf->dev, nbuf); + + if (unlikely(dp_ctx->dp_cfg.tx_orphan_enable) || + qdf_nbuf_is_cloned(nbuf)) { + /* + * For UDP packets we want to orphan the packet to allow the app + * to send more packets. The flow would ultimately be controlled + * by the limited number of tx descriptors for the vdev. + */ + cpu = qdf_get_smp_processor_id(); + ++dp_intf->dp_stats.tx_rx_stats.per_cpu[cpu].tx_orphaned; + qdf_nbuf_orphan(nbuf); + } + return nbuf; +} +#else +static inline +qdf_nbuf_t dp_nbuf_orphan(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + qdf_nbuf_t nskb; + + dp_nbuf_fill_gso_size(dp_intf->dev, nbuf); + nskb = __qdf_nbuf_unshare(nbuf); + + return nskb; +} +#endif + +/** + * dp_get_tx_resource() - check tx resources and take action + * @dp_link: DP link handle + * @mac_addr: mac address + * + * Return: none + */ +static inline +void dp_get_tx_resource(struct wlan_dp_link *dp_link, + struct qdf_mac_addr *mac_addr) +{ +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * dp_start_xmit() - Transmit a frame + * @dp_link: DP link handle + * @nbuf: n/w buffer + * + * Function called to Transmit a n/w buffer in STA mode. + * + * Return: Status of the transmission + */ +QDF_STATUS +dp_start_xmit(struct wlan_dp_link *dp_link, qdf_nbuf_t nbuf); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * dp_mon_rx_packet_cbk() - Receive callback registered with OL layer. + * @context: pointer to qdf context + * @rxbuf: pointer to rx qdf_nbuf + * + * TL will call this to notify the HDD when one or more packets were + * received for a registered STA. + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf); + +/** + * dp_monitor_set_rx_monitor_cb(): Set rx monitor mode callback function + * @txrx: pointer to txrx ops + * @rx_monitor_cb: pointer to callback function + * + * Returns: None + */ +void dp_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx, + ol_txrx_rx_mon_fp rx_monitor_cb); +/** + * dp_rx_monitor_callback(): Callback function for receive monitor mode + * @vdev: Handle to vdev object + * @mpdu: pointer to mpdu to be delivered to os + * @rx_status: receive status + * + * Returns: None + */ +void dp_rx_monitor_callback(ol_osif_vdev_handle vdev, + qdf_nbuf_t mpdu, + void *rx_status); + +#else +static inline +QDF_STATUS dp_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void dp_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx, + ol_txrx_rx_mon_fp rx_monitor_cb) { } + +static inline +void dp_rx_monitor_callback(ol_osif_vdev_handle vdev, qdf_nbuf_t mpdu, + void *rx_status) { } +#endif + +/** + * dp_sta_notify_tx_comp_cb() - notify tx comp callback registered with dp + * @nbuf: pointer to nbuf + * @ctx: osif context + * @flag: tx status flag + * + * Return: None + */ +void dp_sta_notify_tx_comp_cb(qdf_nbuf_t nbuf, void *ctx, uint16_t flag); + +/** + * dp_softap_notify_tx_compl_cbk() - notify softap tx comp registered with dp + * @nbuf: pointer to nbuf + * @context: osif context + * @flag: tx status flag + * + * Return: None + */ +void dp_softap_notify_tx_compl_cbk(qdf_nbuf_t nbuf, + void *context, uint16_t flag); + +/** + * dp_rx_pkt_tracepoints_enabled() - Get the state of rx pkt tracepoint + * + * Return: True if any rx pkt tracepoint is enabled else false + */ +static inline bool dp_rx_pkt_tracepoints_enabled(void) +{ + return (qdf_trace_dp_rx_tcp_pkt_enabled() || + qdf_trace_dp_rx_udp_pkt_enabled() || + qdf_trace_dp_rx_pkt_enabled()); +} + +#ifdef CONFIG_DP_PKT_ADD_TIMESTAMP +/** + * wlan_dp_pkt_add_timestamp() - add timestamp in data payload + * @dp_intf: DP interface + * @index: timestamp index which decides offset in payload + * @nbuf: Network socket buffer + * + * Return: none + */ +void wlan_dp_pkt_add_timestamp(struct wlan_dp_intf *dp_intf, + enum qdf_pkt_timestamp_index index, + qdf_nbuf_t nbuf); +#else +static inline +void wlan_dp_pkt_add_timestamp(struct wlan_dp_intf *dp_intf, + enum qdf_pkt_timestamp_index index, + qdf_nbuf_t nbuf) +{ +} +#endif + +#if defined(FEATURE_LRO) +/** + * dp_lro_set_reset() - API for Disable/Enable LRO + * @dp_intf: DP interface pointer + * @enable_flag: enable or disable LRO. + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS dp_lro_set_reset(struct wlan_dp_intf *dp_intf, uint8_t enable_flag); +#else +static inline +QDF_STATUS dp_lro_set_reset(struct wlan_dp_intf *dp_intf, + uint8_t enable_flag) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* FEATURE_LRO */ + +#ifdef RECEIVE_OFFLOAD +/** + * dp_rx_ol_init() - Initialize Rx offload mode (LRO or GRO) + * @dp_ctx: pointer to DP Context + * @is_wifi3_0_target: true if it wifi3.0 target + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS dp_rx_ol_init(struct wlan_dp_psoc_context *dp_ctx, + bool is_wifi3_0_target); +#else /* RECEIVE_OFFLOAD */ + +static inline QDF_STATUS +dp_rx_ol_init(struct wlan_dp_psoc_context *dp_ctx, + bool is_wifi3_0_target) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static inline +void dp_rx_pkt_da_check(struct wlan_dp_intf *dp_intf, qdf_nbuf_t nbuf) +{ + /* only do DA check for RX frame from non-regular path */ + if (!qdf_nbuf_is_exc_frame(nbuf)) + return; + + if (qdf_mem_cmp(qdf_nbuf_data(nbuf), dp_intf->mac_addr.bytes, + ETH_ALEN)) { + dp_info("da mac:" QDF_MAC_ADDR_FMT "intf_mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(qdf_nbuf_data(nbuf)), + QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes)); + qdf_mem_copy(qdf_nbuf_data(nbuf), dp_intf->mac_addr.bytes, + ETH_ALEN); + } +} +#else +static inline +void dp_rx_pkt_da_check(struct wlan_dp_intf *dp_intf, qdf_nbuf_t nbuf) +{ +} +#endif + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_wfds.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_wfds.h new file mode 100644 index 0000000000..5ff061da03 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/inc/wlan_dp_wfds.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_DP_WFDS_H_ +#define _WLAN_DP_WFDS_H_ + +#ifdef FEATURE_DIRECT_LINK + +#include "qdf_atomic.h" +#include "wlan_dp_priv.h" +#include "wlan_qmi_public_struct.h" +#include "wlan_qmi_wfds_api.h" + +#define DP_WFDS_CE_MAX_SRNG QMI_WFDS_CE_MAX_SRNG + +/** + * enum dp_wfds_msg - WFDS message type + * @DP_WFDS_REQ_MEM_IND_MSG: Memory request indication message + * @DP_WFDS_IPCC_MAP_N_CFG_IND_MSG: IPCC map and configure indication message + * @DP_WFDS_MSG_MAX: not a real value just a placeholder for max + */ +enum dp_wfds_msg { + DP_WFDS_REQ_MEM_IND_MSG, + DP_WFDS_IPCC_MAP_N_CFG_IND_MSG, + DP_WFDS_MSG_MAX, +}; + +/** + * enum dp_wfds_state - Datapath WFDS state + * @DP_WFDS_SVC_DISCONNECTED: service disconnected + * @DP_WFDS_SVC_CONNECTED: service connected + * @DP_WFDS_SVC_CONFIG_DONE: configuration msg handshake done + * @DP_WFDS_SVC_MEM_CONFIG_DONE: memory handshake with server done + * @DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE: IPCC map and cfg handshake completed + */ +enum dp_wfds_state { + DP_WFDS_SVC_DISCONNECTED, + DP_WFDS_SVC_CONNECTED, + DP_WFDS_SVC_CONFIG_DONE, + DP_WFDS_SVC_MEM_CONFIG_DONE, + DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE, +}; + +/** + * enum dp_wfds_event_type - Datapath WFDS event type + * @DP_WFDS_NEW_SERVER: QMI new server event + * @DP_WFDS_MEM_REQ: QMI memory request event + * @DP_WFDS_IPCC_MAP_N_CFG: QMI IPCC map and configure event + */ +enum dp_wfds_event_type { + DP_WFDS_NEW_SERVER, + DP_WFDS_MEM_REQ, + DP_WFDS_IPCC_MAP_N_CFG, +}; + +/** + * struct dp_wfds_event - DP QMI event structure + * @list_node: node used for adding/deleting to a list + * @wfds_evt_type: QMI event type + * @data: Pointer to event data + */ +struct dp_wfds_event { + qdf_list_node_t list_node; + enum dp_wfds_event_type wfds_evt_type; + void *data; +}; + +/** + * struct dp_direct_link_iommu_config - Direct link related IOMMU configuration + * @shadow_rdptr_paddr: shadow read pointer dma address + * @shadow_rdptr_map_size: shadow read pointer memory size + * @shadow_wrptr_paddr: shadow write pointer dma address + * @shadow_wrptr_map_size: shadow write pointer memory size + * @direct_link_srng_ring_base_paddr: SRNG ring base dma address + * @direct_link_srng_ring_map_size: SRNG ring memory size + * @direct_link_refill_ring_base_paddr: refill SRNG ring base dma address + * @direct_link_refill_ring_map_size: refill SRNG ring memory size + */ +struct dp_direct_link_iommu_config { + qdf_dma_addr_t shadow_rdptr_paddr; + uint16_t shadow_rdptr_map_size; + qdf_dma_addr_t shadow_wrptr_paddr; + uint16_t shadow_wrptr_map_size; + qdf_dma_addr_t direct_link_srng_ring_base_paddr[QMI_WFDS_CE_MAX_SRNG]; + uint16_t direct_link_srng_ring_map_size[QMI_WFDS_CE_MAX_SRNG]; + qdf_dma_addr_t direct_link_refill_ring_base_paddr; + uint16_t direct_link_refill_ring_map_size; +}; + +/** + * struct dp_direct_link_wfds_context - DP Direct Link WFDS context structure + * @direct_link_ctx: direct link context + * @wfds_work: work to be scheduled on QMI event + * @wfds_wq: QMI workqueue + * @wfds_event_list_lock: spinlock for event list access + * @wfds_event_list: QMI event list + * @wfds_state: QMI state + * @num_mem_arenas: Number of memory arenas requested by QMI server + * @mem_arena_pages: Pointer to array of mem multi page structure for arenas + * @ipcc_dma_addr: ipcc dma address + * @ipcc_ce_id: ids of CEs that are configured with IPCC MSI info + * @ipcc_ce_id_len: number of valid entries in ipcc_ce_id array + * @iommu_cfg: direct link iommu configuration + */ +struct dp_direct_link_wfds_context { + struct dp_direct_link_context *direct_link_ctx; + qdf_work_t wfds_work; + qdf_workqueue_t *wfds_wq; + qdf_spinlock_t wfds_event_list_lock; + qdf_list_t wfds_event_list; + qdf_atomic_t wfds_state; + uint32_t num_mem_arenas; + struct qdf_mem_multi_page_t *mem_arena_pages; + uint32_t ipcc_dma_addr; + uint8_t ipcc_ce_id[DP_WFDS_CE_MAX_SRNG]; + uint8_t ipcc_ce_id_len; + struct dp_direct_link_iommu_config iommu_cfg; +}; + +/** + * dp_wfds_handle_request_mem_ind() - Process request memory indication received + * from QMI server + * @mem_msg: pointer to memory request indication message + * + * Return: None + */ +void +dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg); + +/** + * dp_wfds_handle_ipcc_map_n_cfg_ind() - Process IPCC map and configure + * indication received from QMI server + * @ipcc_msg: pointer to IPCC map and configure indication message + * + * Return: None + */ +void +dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg); + +/** + * dp_wfds_new_server() - New server callback triggered when service is up. + * Connect to the service as part of this call. + * + * Return: QDF status + */ +QDF_STATUS dp_wfds_new_server(void); + +/** + * dp_wfds_del_server() - Del server callback triggered when service is + * down. + * + * Return: None + */ +void dp_wfds_del_server(void); + +/** + * dp_wfds_init() - Initialize DP WFDS context + * @direct_link_ctx: DP Direct Link context + * + * Return: QDF status + */ +QDF_STATUS dp_wfds_init(struct dp_direct_link_context *direct_link_ctx); + +/** + * dp_wfds_deinit() - Deinitialize DP WFDS context + * @direct_link_ctx: DP Direct Link context + * @is_ssr: true if SSR is in progress else false + * + * Return: None + */ +void dp_wfds_deinit(struct dp_direct_link_context *direct_link_ctx, + bool is_ssr); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_bus_bandwidth.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_bus_bandwidth.c new file mode 100644 index 0000000000..d3bbb3d7a8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_bus_bandwidth.c @@ -0,0 +1,2347 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_dp_bus_bandwidth.c + * + * Bus Bandwidth Manager implementation + */ + +#include "wlan_dp_bus_bandwidth.h" +#include "wlan_dp_main.h" +#include +#include "pld_common.h" +#include "cds_api.h" +#include +#include "wlan_ipa_ucfg_api.h" +#include "wlan_dp_rx_thread.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "hif.h" +#include "qdf_trace.h" +#include +#include +#include +#include "wlan_dp_periodic_sta_stats.h" +#include "wlan_mlme_api.h" +#include "wlan_dp_txrx.h" +#include "cdp_txrx_host_stats.h" +#include "wlan_cm_roam_api.h" +#include "hif_main.h" + +#ifdef FEATURE_BUS_BANDWIDTH_MGR +/* + * bus_bw_table_default: default table which provides bus + * bandwidth level corresponding to a given connection mode and throughput + * level. + */ +static bus_bw_table_type bus_bw_table_default = { + [QCA_WLAN_802_11_MODE_11B] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_1, + BUS_BW_LEVEL_2, BUS_BW_LEVEL_3, + BUS_BW_LEVEL_4, BUS_BW_LEVEL_6, + BUS_BW_LEVEL_7, BUS_BW_LEVEL_8, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11G] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5}, + [QCA_WLAN_802_11_MODE_11A] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5, BUS_BW_LEVEL_5, + BUS_BW_LEVEL_5}, + [QCA_WLAN_802_11_MODE_11N] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_1, + BUS_BW_LEVEL_2, BUS_BW_LEVEL_3, + BUS_BW_LEVEL_4, BUS_BW_LEVEL_6, + BUS_BW_LEVEL_7, BUS_BW_LEVEL_8, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11AC] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_1, + BUS_BW_LEVEL_2, BUS_BW_LEVEL_3, + BUS_BW_LEVEL_4, BUS_BW_LEVEL_6, + BUS_BW_LEVEL_7, BUS_BW_LEVEL_8, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11AX] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_1, + BUS_BW_LEVEL_2, BUS_BW_LEVEL_3, + BUS_BW_LEVEL_4, BUS_BW_LEVEL_6, + BUS_BW_LEVEL_7, BUS_BW_LEVEL_8, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11BE] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_1, + BUS_BW_LEVEL_2, BUS_BW_LEVEL_3, + BUS_BW_LEVEL_4, BUS_BW_LEVEL_6, + BUS_BW_LEVEL_7, BUS_BW_LEVEL_8, + BUS_BW_LEVEL_9}, +}; + +/* + * bus_bw_table_low_latency: table which provides bus + * bandwidth level corresponding to a given connection mode and throughput + * level in low latency setting. + */ +static bus_bw_table_type bus_bw_table_low_latency = { + [QCA_WLAN_802_11_MODE_11B] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11G] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11A] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11N] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11AC] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11AX] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, + [QCA_WLAN_802_11_MODE_11BE] = {BUS_BW_LEVEL_NONE, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9, BUS_BW_LEVEL_9, + BUS_BW_LEVEL_9}, +}; + +/** + * bbm_convert_to_pld_bus_lvl() - Convert from internal bus vote level to + * PLD bus vote level + * @vote_lvl: internal bus bw vote level + * + * Returns: PLD bus vote level + */ +static enum pld_bus_width_type +bbm_convert_to_pld_bus_lvl(enum bus_bw_level vote_lvl) +{ + switch (vote_lvl) { + case BUS_BW_LEVEL_1: + return PLD_BUS_WIDTH_IDLE; + case BUS_BW_LEVEL_2: + return PLD_BUS_WIDTH_LOW; + case BUS_BW_LEVEL_3: + return PLD_BUS_WIDTH_MEDIUM; + case BUS_BW_LEVEL_4: + return PLD_BUS_WIDTH_HIGH; + case BUS_BW_LEVEL_5: + return PLD_BUS_WIDTH_LOW_LATENCY; + case BUS_BW_LEVEL_6: + return PLD_BUS_WIDTH_MID_HIGH; + case BUS_BW_LEVEL_7: + return PLD_BUS_WIDTH_VERY_HIGH; + case BUS_BW_LEVEL_8: + return PLD_BUS_WIDTH_ULTRA_HIGH; + case BUS_BW_LEVEL_9: + return PLD_BUS_WIDTH_MAX; + case BUS_BW_LEVEL_NONE: + default: + return PLD_BUS_WIDTH_NONE; + } +} + +/** + * bbm_get_bus_bw_level_vote() - Select bus bw vote level per interface based + * on connection mode and throughput level + * @dp_intf: DP Interface, caller assure that interface is valid. + * @tput_level: throughput level + * + * Returns: Bus bw level + */ +static enum bus_bw_level +bbm_get_bus_bw_level_vote(struct wlan_dp_intf *dp_intf, + enum tput_level tput_level) +{ + enum qca_wlan_802_11_mode i; + enum qca_wlan_802_11_mode dot11_mode; + enum bus_bw_level vote_lvl = BUS_BW_LEVEL_NONE; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct bbm_context *bbm_ctx = dp_ctx->bbm_ctx; + bus_bw_table_type *lkp_table = bbm_ctx->curr_bus_bw_lookup_table; + uint16_t client_count[QCA_WLAN_802_11_MODE_INVALID]; + struct wlan_dp_psoc_callbacks *cb_obj = &dp_ctx->dp_ops; + hdd_cb_handle ctx = cb_obj->callback_ctx; + + if (tput_level >= TPUT_LEVEL_MAX) { + dp_err("invalid tput level %d", tput_level); + return BUS_BW_LEVEL_NONE; + } + + switch (dp_intf->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (!cb_obj->wlan_dp_sta_get_dot11mode(ctx, + dp_intf->dev, + &dot11_mode)) + break; + + if (dot11_mode >= QCA_WLAN_802_11_MODE_INVALID) + break; + + return (*lkp_table)[dot11_mode][tput_level]; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (!cb_obj->wlan_dp_get_ap_client_count(ctx, + dp_intf->dev, + client_count)) + break; + + for (i = QCA_WLAN_802_11_MODE_11B; + i < QCA_WLAN_802_11_MODE_INVALID; i++) { + if (client_count[i] && + (*lkp_table)[i][tput_level] > vote_lvl) + vote_lvl = (*lkp_table)[i][tput_level]; + } + + return vote_lvl; + case QDF_NDI_MODE: + if (!cb_obj->wlan_dp_sta_ndi_connected(ctx, + dp_intf->dev)) + break; + + /* + * If the tput levels are between mid to high range, then + * apply next SNOC voting level BUS_BW_LEVEL_5 which maps + * to PLD_BUS_WIDTH_LOW_LATENCY. + * + * NDI dot11mode is currently hardcoded to 11AC in driver and + * since the bus bw levels in table do not differ between 11AC + * and 11AX, using max supported mode instead. Dot11mode of the + * peers are not saved in driver and legacy modes are not + * supported in NAN. + */ + if (tput_level <= TPUT_LEVEL_HIGH) + return BUS_BW_LEVEL_5; + else + return (*lkp_table)[QCA_WLAN_802_11_MODE_11AX][tput_level]; + default: + break; + } + + return vote_lvl; +} + +/** + * bbm_apply_tput_policy() - Apply tput BBM policy by considering + * throughput level and connection modes across adapters + * @dp_ctx: DP context + * @tput_level: throughput level + * + * Returns: None + */ +static void +bbm_apply_tput_policy(struct wlan_dp_psoc_context *dp_ctx, + enum tput_level tput_level) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_intf *dp_intf_next; + struct wlan_objmgr_psoc *psoc; + enum bus_bw_level next_vote = BUS_BW_LEVEL_NONE; + enum bus_bw_level tmp_vote; + struct bbm_context *bbm_ctx = dp_ctx->bbm_ctx; + hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx; + + if (tput_level == TPUT_LEVEL_NONE) { + /* + * This is to handle the scenario where bus bw periodic work + * is force cancelled + */ + if (dp_ctx->dp_ops.dp_any_adapter_connected(ctx)) + bbm_ctx->per_policy_vote[BBM_TPUT_POLICY] = next_vote; + return; + } + + psoc = dp_ctx->psoc; + if (!psoc) { + dp_err("psoc is NULL"); + return; + } + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + if (dp_intf->num_links == 0) + continue; + + tmp_vote = bbm_get_bus_bw_level_vote(dp_intf, tput_level); + if (tmp_vote > next_vote) + next_vote = tmp_vote; + } + + bbm_ctx->per_policy_vote[BBM_TPUT_POLICY] = next_vote; +} + +/** + * bbm_apply_driver_mode_policy() - Apply driver mode BBM policy + * @bbm_ctx: bus bw mgr context + * @driver_mode: global driver mode + * + * Returns: None + */ +static void +bbm_apply_driver_mode_policy(struct bbm_context *bbm_ctx, + enum QDF_GLOBAL_MODE driver_mode) +{ + switch (driver_mode) { + case QDF_GLOBAL_MONITOR_MODE: + case QDF_GLOBAL_FTM_MODE: + bbm_ctx->per_policy_vote[BBM_DRIVER_MODE_POLICY] = + BUS_BW_LEVEL_7; + return; + default: + bbm_ctx->per_policy_vote[BBM_DRIVER_MODE_POLICY] = + BUS_BW_LEVEL_NONE; + return; + } +} + +/** + * bbm_apply_non_persistent_policy() - Apply non persistent policy and set + * the bus bandwidth + * @dp_ctx: DP context + * @flag: flag + * + * Returns: None + */ +static void +bbm_apply_non_persistent_policy(struct wlan_dp_psoc_context *dp_ctx, + enum bbm_non_per_flag flag) +{ + hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx; + + switch (flag) { + case BBM_APPS_RESUME: + if (dp_ctx->dp_ops.dp_any_adapter_connected(ctx)) { + dp_ctx->bbm_ctx->curr_vote_level = BUS_BW_LEVEL_RESUME; + pld_request_bus_bandwidth(dp_ctx->qdf_dev->dev, + bbm_convert_to_pld_bus_lvl(BUS_BW_LEVEL_RESUME)); + } else { + dp_ctx->bbm_ctx->curr_vote_level = BUS_BW_LEVEL_NONE; + pld_request_bus_bandwidth(dp_ctx->qdf_dev->dev, + bbm_convert_to_pld_bus_lvl(BUS_BW_LEVEL_NONE)); + } + return; + case BBM_APPS_SUSPEND: + dp_ctx->bbm_ctx->curr_vote_level = BUS_BW_LEVEL_NONE; + pld_request_bus_bandwidth(dp_ctx->qdf_dev->dev, + bbm_convert_to_pld_bus_lvl(BUS_BW_LEVEL_NONE)); + return; + default: + dp_info("flag %d not handled in res/sus BBM policy", flag); + return; + } +} + +/** + * bbm_apply_wlm_policy() - Apply WLM based BBM policy by selecting + * lookup tables based on the latency level + * @bbm_ctx: Bus BW mgr context + * @wlm_level: WLM latency level + * + * Returns: None + */ +static void +bbm_apply_wlm_policy(struct bbm_context *bbm_ctx, enum wlm_ll_level wlm_level) +{ + switch (wlm_level) { + case WLM_LL_NORMAL: + bbm_ctx->curr_bus_bw_lookup_table = &bus_bw_table_default; + break; + case WLM_LL_LOW: + bbm_ctx->curr_bus_bw_lookup_table = &bus_bw_table_low_latency; + break; + default: + dp_info("wlm level %d not handled in BBM WLM policy", + wlm_level); + break; + } +} + +/** + * bbm_apply_user_policy() - Apply user specified bus voting + * level + * @bbm_ctx: Bus BW mgr context + * @set: set or reset flag + * @user_level: user bus vote level + * + * Returns: qdf status + */ +static QDF_STATUS +bbm_apply_user_policy(struct bbm_context *bbm_ctx, bool set, + enum bus_bw_level user_level) +{ + if (user_level >= BUS_BW_LEVEL_MAX) { + dp_err("Invalid user vote level %d", user_level); + return QDF_STATUS_E_FAILURE; + } + + if (set) + bbm_ctx->per_policy_vote[BBM_USER_POLICY] = user_level; + else + bbm_ctx->per_policy_vote[BBM_USER_POLICY] = BUS_BW_LEVEL_NONE; + + return QDF_STATUS_SUCCESS; +} + +/** + * bbm_request_bus_bandwidth() - Set bus bandwidth level + * @dp_ctx: DP context + * + * Returns: None + */ +static void +bbm_request_bus_bandwidth(struct wlan_dp_psoc_context *dp_ctx) +{ + enum bbm_policy i; + enum bus_bw_level next_vote = BUS_BW_LEVEL_NONE; + enum pld_bus_width_type pld_vote; + struct bbm_context *bbm_ctx = dp_ctx->bbm_ctx; + + for (i = BBM_DRIVER_MODE_POLICY; i < BBM_MAX_POLICY; i++) { + if (bbm_ctx->per_policy_vote[i] > next_vote) + next_vote = bbm_ctx->per_policy_vote[i]; + } + + if (next_vote != bbm_ctx->curr_vote_level) { + pld_vote = bbm_convert_to_pld_bus_lvl(next_vote); + dp_info("Bus bandwidth vote level change from %d to %d pld_vote: %d", + bbm_ctx->curr_vote_level, next_vote, pld_vote); + bbm_ctx->curr_vote_level = next_vote; + pld_request_bus_bandwidth(dp_ctx->qdf_dev->dev, pld_vote); + } +} + +void dp_bbm_apply_independent_policy(struct wlan_objmgr_psoc *psoc, + struct bbm_params *params) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct bbm_context *bbm_ctx; + QDF_STATUS status; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx || !params) + return; + + bbm_ctx = dp_ctx->bbm_ctx; + + qdf_mutex_acquire(&bbm_ctx->bbm_lock); + + switch (params->policy) { + case BBM_TPUT_POLICY: + bbm_apply_tput_policy(dp_ctx, params->policy_info.tput_level); + break; + case BBM_NON_PERSISTENT_POLICY: + bbm_apply_non_persistent_policy(dp_ctx, + params->policy_info.flag); + goto done; + case BBM_DRIVER_MODE_POLICY: + bbm_apply_driver_mode_policy(bbm_ctx, + params->policy_info.driver_mode); + break; + case BBM_SELECT_TABLE_POLICY: + bbm_apply_wlm_policy(bbm_ctx, params->policy_info.wlm_level); + goto done; + case BBM_USER_POLICY: + /* + * This policy is not used currently. + */ + status = bbm_apply_user_policy(bbm_ctx, + params->policy_info.usr.set, + params->policy_info.usr.user_level); + if (QDF_IS_STATUS_ERROR(status)) + goto done; + break; + default: + dp_info("BBM policy %d not handled", params->policy); + goto done; + } + + bbm_request_bus_bandwidth(dp_ctx); + +done: + qdf_mutex_release(&bbm_ctx->bbm_lock); +} + +int dp_bbm_context_init(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct bbm_context *bbm_ctx; + QDF_STATUS status; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) + return -EINVAL; + bbm_ctx = qdf_mem_malloc(sizeof(*bbm_ctx)); + if (!bbm_ctx) + return -ENOMEM; + + bbm_ctx->curr_bus_bw_lookup_table = &bus_bw_table_default; + + status = qdf_mutex_create(&bbm_ctx->bbm_lock); + if (QDF_IS_STATUS_ERROR(status)) + goto free_ctx; + + dp_ctx->bbm_ctx = bbm_ctx; + + return 0; + +free_ctx: + qdf_mem_free(bbm_ctx); + + return qdf_status_to_os_return(status); +} + +void dp_bbm_context_deinit(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct bbm_context *bbm_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) + return; + bbm_ctx = dp_ctx->bbm_ctx; + if (!bbm_ctx) + return; + + dp_ctx->bbm_ctx = NULL; + qdf_mutex_destroy(&bbm_ctx->bbm_lock); + + qdf_mem_free(bbm_ctx); +} +#endif /* FEATURE_BUS_BANDWIDTH_MGR */ +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +#ifdef FEATURE_RUNTIME_PM +void dp_rtpm_tput_policy_init(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct dp_rtpm_tput_policy_context *ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + ctx = &dp_ctx->rtpm_tput_policy_ctx; + qdf_runtime_lock_init(&ctx->rtpm_lock); + ctx->curr_state = DP_RTPM_TPUT_POLICY_STATE_REQUIRED; + qdf_atomic_init(&ctx->high_tput_vote); +} + +void dp_rtpm_tput_policy_deinit(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct dp_rtpm_tput_policy_context *ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + ctx = &dp_ctx->rtpm_tput_policy_ctx; + ctx->curr_state = DP_RTPM_TPUT_POLICY_STATE_INVALID; + qdf_runtime_lock_deinit(&ctx->rtpm_lock); +} + +/** + * dp_rtpm_tput_policy_prevent() - prevent a runtime bus suspend + * @dp_ctx: DP handle + * + * return: None + */ +static void dp_rtpm_tput_policy_prevent(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rtpm_tput_policy_context *ctx; + + ctx = &dp_ctx->rtpm_tput_policy_ctx; + qdf_runtime_pm_prevent_suspend(&ctx->rtpm_lock); +} + +/** + * dp_rtpm_tput_policy_allow() - allow a runtime bus suspend + * @dp_ctx: DP handle + * + * return: None + */ +static void dp_rtpm_tput_policy_allow(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rtpm_tput_policy_context *ctx; + + ctx = &dp_ctx->rtpm_tput_policy_ctx; + qdf_runtime_pm_allow_suspend(&ctx->rtpm_lock); +} + +#define DP_RTPM_POLICY_HIGH_TPUT_THRESH TPUT_LEVEL_MEDIUM + +void dp_rtpm_tput_policy_apply(struct wlan_dp_psoc_context *dp_ctx, + enum tput_level tput_level) +{ + int vote; + enum dp_rtpm_tput_policy_state temp_state; + struct dp_rtpm_tput_policy_context *ctx; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (qdf_unlikely(!soc)) + return; + + ctx = &dp_ctx->rtpm_tput_policy_ctx; + + if (tput_level >= DP_RTPM_POLICY_HIGH_TPUT_THRESH) + temp_state = DP_RTPM_TPUT_POLICY_STATE_NOT_REQUIRED; + else + temp_state = DP_RTPM_TPUT_POLICY_STATE_REQUIRED; + + if (ctx->curr_state == temp_state) + return; + + if (temp_state == DP_RTPM_TPUT_POLICY_STATE_REQUIRED) { + cdp_set_rtpm_tput_policy_requirement(soc, false); + qdf_atomic_dec(&ctx->high_tput_vote); + dp_rtpm_tput_policy_allow(dp_ctx); + } else { + cdp_set_rtpm_tput_policy_requirement(soc, true); + qdf_atomic_inc(&ctx->high_tput_vote); + dp_rtpm_tput_policy_prevent(dp_ctx); + } + + ctx->curr_state = temp_state; + vote = qdf_atomic_read(&ctx->high_tput_vote); + + if (vote < 0 || vote > 1) { + dp_alert_rl("Incorrect vote!"); + QDF_BUG(0); + } +} + +int dp_rtpm_tput_policy_get_vote(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rtpm_tput_policy_context *ctx; + + ctx = &dp_ctx->rtpm_tput_policy_ctx; + return qdf_atomic_read(&ctx->high_tput_vote); +} +#endif /* FEATURE_RUNTIME_PM */ + +void dp_reset_tcp_delack(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + enum wlan_tp_level next_level = WLAN_SVC_TP_LOW; + struct wlan_rx_tp_data rx_tp_data = {0}; + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + if (!dp_ctx->en_tcp_delack_no_lro) + return; + + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + rx_tp_data.level = next_level; + dp_ctx->rx_high_ind_cnt = 0; + wlan_dp_update_tcp_rx_param(dp_ctx, &rx_tp_data); +} + +/** + * dp_reset_tcp_adv_win_scale() - Reset TCP advance window scaling + * value to default + * @dp_ctx: pointer to DP context (Should not be NULL) + * + * Function used to reset TCP advance window scaling + * value to its default value + * + * Return: None + */ +static void dp_reset_tcp_adv_win_scale(struct wlan_dp_psoc_context *dp_ctx) +{ + enum wlan_tp_level next_level = WLAN_SVC_TP_NONE; + struct wlan_rx_tp_data rx_tp_data = {0}; + + if (!dp_ctx->dp_cfg.enable_tcp_adv_win_scale) + return; + + rx_tp_data.rx_tp_flags |= TCP_ADV_WIN_SCL; + rx_tp_data.level = next_level; + dp_ctx->cur_rx_level = WLAN_SVC_TP_NONE; + wlan_dp_update_tcp_rx_param(dp_ctx, &rx_tp_data); +} + +void wlan_dp_update_tcp_rx_param(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_rx_tp_data *data) +{ + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + + if (!dp_ctx) { + dp_err("psoc is null"); + return; + } + + if (!data) { + dp_err("Data is null"); + return; + } + + if (dp_ctx->dp_cfg.enable_tcp_param_update) + dp_ops->osif_dp_send_tcp_param_update_event(dp_ctx->psoc, + (union wlan_tp_data *)data, + 1); + else + dp_ops->dp_send_svc_nlink_msg(cds_get_radio_index(), + WLAN_SVC_WLAN_TP_IND, + (void *)data, + sizeof(struct wlan_rx_tp_data)); +} + +/** + * wlan_dp_update_tcp_tx_param() - update TCP param in Tx dir + * @dp_ctx: Pointer to DP context + * @data: Parameters to update + * + * Return: None + */ +static void wlan_dp_update_tcp_tx_param(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_tx_tp_data *data) +{ + enum wlan_tp_level next_tx_level; + struct wlan_tx_tp_data *tx_tp_data; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + + if (!dp_ctx) { + dp_err("psoc is null"); + return; + } + + if (!data) { + dp_err("Data is null"); + return; + } + + tx_tp_data = (struct wlan_tx_tp_data *)data; + next_tx_level = tx_tp_data->level; + + if (dp_ctx->dp_cfg.enable_tcp_param_update) + dp_ops->osif_dp_send_tcp_param_update_event(dp_ctx->psoc, + (union wlan_tp_data *)data, + 0); + else + dp_ops->dp_send_svc_nlink_msg(cds_get_radio_index(), + WLAN_SVC_WLAN_TP_TX_IND, + &next_tx_level, + sizeof(next_tx_level)); +} + +/** + * dp_low_tput_gro_flush_skip_handler() - adjust GRO flush for low tput + * @dp_ctx: dp_ctx object + * @next_vote_level: next bus bandwidth level + * @legacy_client: legacy connection mode active + * + * If bus bandwidth level is PLD_BUS_WIDTH_LOW consistently and hit + * the bus_low_cnt_threshold, set flag to skip GRO flush. + * If bus bandwidth keeps going to PLD_BUS_WIDTH_IDLE, perform a GRO + * flush to avoid TCP traffic stall + * + * Return: none + */ +static inline void dp_low_tput_gro_flush_skip_handler( + struct wlan_dp_psoc_context *dp_ctx, + enum pld_bus_width_type next_vote_level, + bool legacy_client) +{ + uint32_t threshold = dp_ctx->dp_cfg.bus_low_cnt_threshold; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + int i; + + if (next_vote_level == PLD_BUS_WIDTH_LOW && legacy_client) { + if (++dp_ctx->bus_low_vote_cnt >= threshold) + qdf_atomic_set(&dp_ctx->low_tput_gro_enable, 1); + } else { + if (qdf_atomic_read(&dp_ctx->low_tput_gro_enable) && + dp_ctx->enable_dp_rx_threads) { + /* flush pending rx pkts when LOW->IDLE */ + dp_info("flush queued GRO pkts"); + for (i = 0; i < cdp_get_num_rx_contexts(soc); i++) { + dp_rx_gro_flush_ind(soc, i, + DP_RX_GRO_NORMAL_FLUSH); + } + } + + dp_ctx->bus_low_vote_cnt = 0; + qdf_atomic_set(&dp_ctx->low_tput_gro_enable, 0); + } +} + +#ifdef WDI3_STATS_UPDATE +/** + * dp_ipa_set_perf_level() - set IPA perf level + * @dp_ctx: handle to dp context + * @tx_pkts: transmit packet count + * @rx_pkts: receive packet count + * @ipa_tx_pkts: IPA transmit packet count + * @ipa_rx_pkts: IPA receive packet count + * + * Return: none + */ +static inline +void dp_ipa_set_perf_level(struct wlan_dp_psoc_context *dp_ctx, + uint64_t *tx_pkts, uint64_t *rx_pkts, + uint32_t *ipa_tx_pkts, uint32_t *ipa_rx_pkts) +{ +} +#else +static void dp_ipa_set_perf_level(struct wlan_dp_psoc_context *dp_ctx, + uint64_t *tx_pkts, uint64_t *rx_pkts, + uint32_t *ipa_tx_pkts, uint32_t *ipa_rx_pkts) +{ + if (ucfg_ipa_is_fw_wdi_activated(dp_ctx->pdev)) { + ucfg_ipa_uc_stat_query(dp_ctx->pdev, ipa_tx_pkts, + ipa_rx_pkts); + *tx_pkts += *ipa_tx_pkts; + *rx_pkts += *ipa_rx_pkts; + + ucfg_ipa_set_perf_level(dp_ctx->pdev, *tx_pkts, *rx_pkts); + ucfg_ipa_uc_stat_request(dp_ctx->pdev, 2); + } +} +#endif /* WDI3_STATS_UPDATE */ + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +/** + * dp_set_vdev_bundle_require_flag() - set vdev bundle require flag + * @vdev_id: vdev id + * @dp_ctx: handle to dp context + * @tx_bytes: Tx bytes + * + * Return: none + */ +static inline +void dp_set_vdev_bundle_require_flag(uint16_t vdev_id, + struct wlan_dp_psoc_context *dp_ctx, + uint64_t tx_bytes) +{ + struct wlan_dp_psoc_cfg *cfg = dp_ctx->dp_cfg; + + cdp_vdev_set_bundle_require_flag(cds_get_context(QDF_MODULE_ID_SOC), + vdev_id, tx_bytes, + cfg->bus_bw_compute_interval, + cfg->pkt_bundle_threshold_high, + cfg->pkt_bundle_threshold_low); +} +#else +static inline +void dp_set_vdev_bundle_require_flag(uint16_t vdev_id, + struct wlan_dp_psoc_context *dp_ctx, + uint64_t tx_bytes) +{ +} +#endif /* WLAN_SUPPORT_TXRX_HL_BUNDLE */ + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +/** + * dp_set_driver_del_ack_enable() - set driver delayed ack enabled flag + * @vdev_id: vdev id + * @dp_ctx: handle to dp context + * @rx_packets: receive packet count + * + * Return: none + */ +static inline +void dp_set_driver_del_ack_enable(uint16_t vdev_id, + struct wlan_dp_psoc_context *dp_ctx, + uint64_t rx_packets) +{ + struct wlan_dp_psoc_cfg *cfg = dp_ctx->dp_cfg; + + cdp_vdev_set_driver_del_ack_enable(cds_get_context(QDF_MODULE_ID_SOC), + vdev_id, rx_packets, + cfg->bus_bw_compute_interval, + cfg->del_ack_threshold_high, + cfg->del_ack_threshold_low); +} +#else +static inline +void dp_set_driver_del_ack_enable(uint16_t vdev_id, + struct wlan_dp_psoc_context *dp_ctx, + uint64_t rx_packets) +{ +} +#endif /* QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK */ + +#define DP_BW_GET_DIFF(_x, _y) ((unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)) + +#ifdef RX_PERFORMANCE +bool dp_is_current_high_throughput(struct wlan_dp_psoc_context *dp_ctx) +{ + if (dp_ctx->cur_vote_level < PLD_BUS_WIDTH_MEDIUM) + return false; + else + return true; +} +#endif /* RX_PERFORMANCE */ + +/** + * wlan_dp_validate_context() - check the DP context + * @dp_ctx: Global DP context pointer + * + * Return: 0 if the context is valid. Error code otherwise + */ +static int wlan_dp_validate_context(struct wlan_dp_psoc_context *dp_ctx) +{ + if (!dp_ctx) { + dp_err("DP context is null"); + return -ENODEV; + } + + if (cds_is_driver_recovering()) { + dp_info("Recovery in progress; state:0x%x", + cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_load_or_unload_in_progress()) { + dp_info("Load/unload in progress; state:0x%x", + cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_driver_in_bad_state()) { + dp_info("Driver in bad state; state:0x%x", + cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_fw_down()) { + dp_info("FW is down; state:0x%x", cds_get_driver_state()); + return -EAGAIN; + } + + return 0; +} + +/** + * dp_tp_level_to_str() - Convert TPUT level to string + * @level: TPUT level + * + * Return: converted string + */ +static uint8_t *dp_tp_level_to_str(uint32_t level) +{ + switch (level) { + /* initialize the wlan sub system */ + case WLAN_SVC_TP_NONE: + return "NONE"; + case WLAN_SVC_TP_LOW: + return "LOW"; + case WLAN_SVC_TP_MEDIUM: + return "MED"; + case WLAN_SVC_TP_HIGH: + return "HIGH"; + default: + return "INVAL"; + } +} + +void wlan_dp_display_tx_rx_histogram(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + int i; + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + dp_nofl_info("BW compute Interval: %d ms", + dp_ctx->dp_cfg.bus_bw_compute_interval); + dp_nofl_info("BW TH - Very High: %d Mid High: %d High: %d Med: %d Low: %d DBS: %d", + dp_ctx->dp_cfg.bus_bw_very_high_threshold, + dp_ctx->dp_cfg.bus_bw_mid_high_threshold, + dp_ctx->dp_cfg.bus_bw_high_threshold, + dp_ctx->dp_cfg.bus_bw_medium_threshold, + dp_ctx->dp_cfg.bus_bw_low_threshold, + dp_ctx->dp_cfg.bus_bw_dbs_threshold); + dp_nofl_info("Enable TCP DEL ACK: %d", + dp_ctx->en_tcp_delack_no_lro); + dp_nofl_info("TCP DEL High TH: %d TCP DEL Low TH: %d", + dp_ctx->dp_cfg.tcp_delack_thres_high, + dp_ctx->dp_cfg.tcp_delack_thres_low); + dp_nofl_info("TCP TX HIGH TP TH: %d (Use to set tcp_output_bytes_lim)", + dp_ctx->dp_cfg.tcp_tx_high_tput_thres); + + dp_nofl_info("Total entries: %d Current index: %d", + NUM_TX_RX_HISTOGRAM, dp_ctx->txrx_hist_idx); + + if (dp_ctx->txrx_hist) { + dp_nofl_info("[index][timestamp]: interval_rx, interval_tx, bus_bw_level, RX TP Level, TX TP Level, Rx:Tx pm_qos"); + + for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) { + struct tx_rx_histogram *hist; + + /* using dp_log to avoid printing function name */ + if (dp_ctx->txrx_hist[i].qtime <= 0) + continue; + hist = &dp_ctx->txrx_hist[i]; + dp_nofl_info("[%3d][%15llu]: %6llu, %6llu, %s, %s, %s, %s:%s", + i, hist->qtime, hist->interval_rx, + hist->interval_tx, + pld_bus_width_type_to_str(hist->next_vote_level), + dp_tp_level_to_str(hist->next_rx_level), + dp_tp_level_to_str(hist->next_tx_level), + hist->is_rx_pm_qos_high ? "HIGH" : "LOW", + hist->is_tx_pm_qos_high ? "HIGH" : "LOW"); + } + } +} + +void wlan_dp_clear_tx_rx_histogram(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + dp_ctx->txrx_hist_idx = 0; + if (dp_ctx->txrx_hist) + qdf_mem_zero(dp_ctx->txrx_hist, + (sizeof(struct tx_rx_histogram) * + NUM_TX_RX_HISTOGRAM)); +} + +/** + * wlan_dp_init_tx_rx_histogram() - init tx/rx histogram stats + * @dp_ctx: dp context + * + * Return: 0 for success or error code + */ +static int wlan_dp_init_tx_rx_histogram(struct wlan_dp_psoc_context *dp_ctx) +{ + dp_ctx->txrx_hist = qdf_mem_malloc( + (sizeof(struct tx_rx_histogram) * NUM_TX_RX_HISTOGRAM)); + if (!dp_ctx->txrx_hist) + return -ENOMEM; + + return 0; +} + +/** + * wlan_dp_deinit_tx_rx_histogram() - deinit tx/rx histogram stats + * @dp_ctx: dp context + * + * Return: none + */ +static void wlan_dp_deinit_tx_rx_histogram(struct wlan_dp_psoc_context *dp_ctx) +{ + if (!dp_ctx || !dp_ctx->txrx_hist) + return; + + qdf_mem_free(dp_ctx->txrx_hist); + dp_ctx->txrx_hist = NULL; +} + +/** + * wlan_dp_display_txrx_stats() - Display tx/rx histogram stats + * @dp_ctx: dp context + * + * Return: none + */ +static void wlan_dp_display_txrx_stats(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_intf *dp_intf = NULL, *next_dp_intf = NULL; + struct dp_tx_rx_stats *stats; + hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx; + int i = 0; + uint32_t total_rx_pkt, total_rx_dropped, + total_rx_delv, total_rx_refused; + uint32_t total_tx_pkt; + uint32_t total_tx_dropped; + uint32_t total_tx_orphaned; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, next_dp_intf) { + total_rx_pkt = 0; + total_rx_dropped = 0; + total_rx_delv = 0; + total_rx_refused = 0; + total_tx_pkt = 0; + total_tx_dropped = 0; + total_tx_orphaned = 0; + stats = &dp_intf->dp_stats.tx_rx_stats; + + if (!dp_intf->num_links) + continue; + + dp_info("dp_intf: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes)); + for (i = 0; i < NUM_CPUS; i++) { + total_rx_pkt += stats->per_cpu[i].rx_packets; + total_rx_dropped += stats->per_cpu[i].rx_dropped; + total_rx_delv += stats->per_cpu[i].rx_delivered; + total_rx_refused += stats->per_cpu[i].rx_refused; + total_tx_pkt += stats->per_cpu[i].tx_called; + total_tx_dropped += stats->per_cpu[i].tx_dropped; + total_tx_orphaned += stats->per_cpu[i].tx_orphaned; + } + + for (i = 0; i < NUM_CPUS; i++) { + if (!stats->per_cpu[i].tx_called) + continue; + + dp_info("Tx CPU[%d]: called %u, dropped %u, orphaned %u", + i, stats->per_cpu[i].tx_called, + stats->per_cpu[i].tx_dropped, + stats->per_cpu[i].tx_orphaned); + } + + dp_info("TX - called %u, dropped %u orphan %u", + total_tx_pkt, total_tx_dropped, + total_tx_orphaned); + + dp_ctx->dp_ops.wlan_dp_display_tx_multiq_stats(ctx, + dp_intf->dev); + + for (i = 0; i < NUM_CPUS; i++) { + if (stats->per_cpu[i].rx_packets == 0) + continue; + dp_info("Rx CPU[%d]: packets %u, dropped %u, delivered %u, refused %u", + i, stats->per_cpu[i].rx_packets, + stats->per_cpu[i].rx_dropped, + stats->per_cpu[i].rx_delivered, + stats->per_cpu[i].rx_refused); + } + + dp_info("RX - packets %u, dropped %u, unsol_arp_mcast_drp %u, delivered %u, refused %u GRO - agg %u drop %u non-agg %u flush_skip %u low_tput_flush %u disabled(conc %u low-tput %u)", + total_rx_pkt, total_rx_dropped, + qdf_atomic_read(&stats->rx_usolict_arp_n_mcast_drp), + total_rx_delv, + total_rx_refused, stats->rx_aggregated, + stats->rx_gro_dropped, stats->rx_non_aggregated, + stats->rx_gro_flush_skip, + stats->rx_gro_low_tput_flush, + qdf_atomic_read(&dp_ctx->disable_rx_ol_in_concurrency), + qdf_atomic_read(&dp_ctx->disable_rx_ol_in_low_tput)); + } +} + +/** + * dp_display_periodic_stats() - Function to display periodic stats + * @dp_ctx: handle to dp context + * @data_in_interval: true, if data detected in bw time interval + * + * The periodicity is determined by dp_ctx->dp_cfg->periodic_stats_disp_time. + * Stats show up in wlan driver logs. + * + * Returns: None + */ +static void dp_display_periodic_stats(struct wlan_dp_psoc_context *dp_ctx, + bool data_in_interval) +{ + static uint32_t counter; + static bool data_in_time_period; + ol_txrx_soc_handle soc; + uint32_t periodic_stats_disp_time = 0; + hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx; + + wlan_mlme_stats_get_periodic_display_time(dp_ctx->psoc, + &periodic_stats_disp_time); + if (!periodic_stats_disp_time) + return; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) + return; + + counter++; + if (data_in_interval) + data_in_time_period = data_in_interval; + + if (counter * dp_ctx->dp_cfg.bus_bw_compute_interval >= + periodic_stats_disp_time * 1000) { + hif_rtpm_display_last_busy_hist(cds_get_context(QDF_MODULE_ID_HIF)); + if (data_in_time_period) { + wlan_dp_display_txrx_stats(dp_ctx); + dp_txrx_ext_dump_stats(soc, CDP_DP_RX_THREAD_STATS); + cdp_display_stats(soc, + CDP_RX_RING_STATS, + QDF_STATS_VERBOSITY_LEVEL_LOW); + cdp_display_stats(soc, + CDP_DP_NAPI_STATS, + QDF_STATS_VERBOSITY_LEVEL_LOW); + cdp_display_stats(soc, + CDP_TXRX_PATH_STATS, + QDF_STATS_VERBOSITY_LEVEL_LOW); + cdp_display_stats(soc, + CDP_DUMP_TX_FLOW_POOL_INFO, + QDF_STATS_VERBOSITY_LEVEL_LOW); + cdp_display_stats(soc, + CDP_DP_SWLM_STATS, + QDF_STATS_VERBOSITY_LEVEL_LOW); + dp_ctx->dp_ops.wlan_dp_display_netif_queue_history + (ctx, QDF_STATS_VERBOSITY_LEVEL_LOW); + cdp_display_txrx_hw_info(soc); + qdf_dp_trace_dump_stats(); + } + counter = 0; + data_in_time_period = false; + } +} + +/** + * dp_pm_qos_update_cpu_mask() - Prepare CPU mask for PM_qos voting + * @mask: return variable of cpumask for the TPUT + * @enable_perf_cluster: Enable PERF cluster or not + * + * By default, the function sets CPU mask for silver cluster unless + * enable_perf_cluster is set as true. + * + * Return: none + */ +static inline void dp_pm_qos_update_cpu_mask(qdf_cpu_mask *mask, + bool enable_perf_cluster) +{ + int package_id; + unsigned int cpus; + int perf_cpu_cluster = hif_get_perf_cluster_bitmap(); + int little_cpu_cluster = BIT(CPU_CLUSTER_TYPE_LITTLE); + + qdf_cpumask_clear(mask); + qdf_for_each_online_cpu(cpus) { + package_id = qdf_topology_physical_package_id(cpus); + if (package_id >= 0 && + (BIT(package_id) & little_cpu_cluster || + (enable_perf_cluster && + BIT(package_id) & perf_cpu_cluster))) { + qdf_cpumask_set_cpu(cpus, mask); + } + } +} + +/** + * dp_bus_bandwidth_work_tune_rx() - Function to tune for RX + * @dp_ctx: handle to dp context + * @rx_packets: receive packet count in last bus bandwidth interval + * @diff_us: delta time since last invocation. + * @next_rx_level: pointer to next_rx_level to be filled + * @cpu_mask: pm_qos cpu_mask needed for RX, to be filled + * @is_rx_pm_qos_high: pointer indicating if high qos is needed, to be filled + * + * The function tunes various aspects of driver based on a running average + * of RX packets received in last bus bandwidth interval. + * + * Returns: true if RX level has changed, else return false + */ +static +bool dp_bus_bandwidth_work_tune_rx(struct wlan_dp_psoc_context *dp_ctx, + const uint64_t rx_packets, + uint64_t diff_us, + enum wlan_tp_level *next_rx_level, + qdf_cpu_mask *cpu_mask, + bool *is_rx_pm_qos_high) +{ + bool rx_level_change = false; + bool rxthread_high_tput_req; + uint32_t bw_interval_us; + uint32_t delack_timer_cnt = dp_ctx->dp_cfg.tcp_delack_timer_count; + uint64_t avg_rx; + uint64_t no_rx_offload_pkts, avg_no_rx_offload_pkts; + uint64_t rx_offload_pkts, avg_rx_offload_pkts; + + bw_interval_us = dp_ctx->dp_cfg.bus_bw_compute_interval * 1000; + no_rx_offload_pkts = dp_ctx->no_rx_offload_pkt_cnt; + dp_ctx->no_rx_offload_pkt_cnt = 0; + + /* adjust for any sched delays */ + no_rx_offload_pkts = no_rx_offload_pkts * bw_interval_us; + no_rx_offload_pkts = qdf_do_div(no_rx_offload_pkts, (uint32_t)diff_us); + + /* average no-offload RX packets over last 2 BW intervals */ + avg_no_rx_offload_pkts = (no_rx_offload_pkts + + dp_ctx->prev_no_rx_offload_pkts) / 2; + dp_ctx->prev_no_rx_offload_pkts = no_rx_offload_pkts; + + if (rx_packets >= no_rx_offload_pkts) + rx_offload_pkts = rx_packets - no_rx_offload_pkts; + else + rx_offload_pkts = 0; + + /* average offloaded RX packets over last 2 BW intervals */ + avg_rx_offload_pkts = (rx_offload_pkts + + dp_ctx->prev_rx_offload_pkts) / 2; + dp_ctx->prev_rx_offload_pkts = rx_offload_pkts; + + avg_rx = avg_no_rx_offload_pkts + avg_rx_offload_pkts; + + qdf_cpumask_clear(cpu_mask); + + if (avg_no_rx_offload_pkts > dp_ctx->dp_cfg.bus_bw_high_threshold) { + rxthread_high_tput_req = true; + *is_rx_pm_qos_high = true; + /*Todo: move hdd implementation to qdf */ + dp_pm_qos_update_cpu_mask(cpu_mask, true); + } else if (avg_rx > dp_ctx->dp_cfg.bus_bw_high_threshold) { + rxthread_high_tput_req = false; + *is_rx_pm_qos_high = false; + dp_pm_qos_update_cpu_mask(cpu_mask, false); + } else { + *is_rx_pm_qos_high = false; + rxthread_high_tput_req = false; + } + + /* + * Takes care to set Rx_thread affinity for below case + * 1)LRO/GRO not supported ROME case + * 2)when rx_ol is disabled in cases like concurrency etc + * 3)For UDP cases + */ + if (cds_sched_handle_throughput_req(rxthread_high_tput_req)) + dp_warn("Rx thread high_tput(%d) affinity request failed", + rxthread_high_tput_req); + + /* fine-tuning parameters for RX Flows */ + if (avg_rx > dp_ctx->dp_cfg.tcp_delack_thres_high) { + if (dp_ctx->cur_rx_level != WLAN_SVC_TP_HIGH && + ++dp_ctx->rx_high_ind_cnt == delack_timer_cnt) { + *next_rx_level = WLAN_SVC_TP_HIGH; + } + } else { + dp_ctx->rx_high_ind_cnt = 0; + *next_rx_level = WLAN_SVC_TP_LOW; + } + + if (dp_ctx->cur_rx_level != *next_rx_level) { + struct wlan_rx_tp_data rx_tp_data = {0}; + + dp_ctx->cur_rx_level = *next_rx_level; + rx_level_change = true; + /* Send throughput indication only if it is enabled. + * Disabling tcp_del_ack will revert the tcp stack behavior + * to default delayed ack. Note that this will disable the + * dynamic delayed ack mechanism across the system + */ + if (dp_ctx->en_tcp_delack_no_lro) + rx_tp_data.rx_tp_flags |= TCP_DEL_ACK_IND; + + if (dp_ctx->dp_cfg.enable_tcp_adv_win_scale) + rx_tp_data.rx_tp_flags |= TCP_ADV_WIN_SCL; + + rx_tp_data.level = *next_rx_level; + wlan_dp_update_tcp_rx_param(dp_ctx, &rx_tp_data); + } + + return rx_level_change; +} + +/** + * dp_bus_bandwidth_work_tune_tx() - Function to tune for TX + * @dp_ctx: handle to dp context + * @tx_packets: transmit packet count in last bus bandwidth interval + * @diff_us: delta time since last invocation. + * @next_tx_level: pointer to next_tx_level to be filled + * @cpu_mask: pm_qos cpu_mask needed for TX, to be filled + * @is_tx_pm_qos_high: pointer indicating if high qos is needed, to be filled + * + * The function tunes various aspects of the driver based on a running average + * of TX packets received in last bus bandwidth interval. + * + * Returns: true if TX level has changed, else return false + */ +static +bool dp_bus_bandwidth_work_tune_tx(struct wlan_dp_psoc_context *dp_ctx, + const uint64_t tx_packets, + uint64_t diff_us, + enum wlan_tp_level *next_tx_level, + qdf_cpu_mask *cpu_mask, + bool *is_tx_pm_qos_high) +{ + bool tx_level_change = false; + uint32_t bw_interval_us; + uint64_t no_tx_offload_pkts, avg_no_tx_offload_pkts; + uint64_t tx_offload_pkts, avg_tx_offload_pkts; + uint64_t avg_tx; + + bw_interval_us = dp_ctx->dp_cfg.bus_bw_compute_interval * 1000; + no_tx_offload_pkts = dp_ctx->no_tx_offload_pkt_cnt; + + /* adjust for any sched delays */ + no_tx_offload_pkts = no_tx_offload_pkts * bw_interval_us; + no_tx_offload_pkts = qdf_do_div(no_tx_offload_pkts, (uint32_t)diff_us); + + /* average no-offload TX packets over last 2 BW intervals */ + avg_no_tx_offload_pkts = (no_tx_offload_pkts + + dp_ctx->prev_no_tx_offload_pkts) / 2; + dp_ctx->no_tx_offload_pkt_cnt = 0; + dp_ctx->prev_no_tx_offload_pkts = no_tx_offload_pkts; + + if (tx_packets >= no_tx_offload_pkts) + tx_offload_pkts = tx_packets - no_tx_offload_pkts; + else + tx_offload_pkts = 0; + + /* average offloaded TX packets over last 2 BW intervals */ + avg_tx_offload_pkts = (tx_offload_pkts + + dp_ctx->prev_tx_offload_pkts) / 2; + dp_ctx->prev_tx_offload_pkts = tx_offload_pkts; + + avg_tx = avg_no_tx_offload_pkts + avg_tx_offload_pkts; + + /* fine-tuning parameters for TX Flows */ + dp_ctx->prev_tx = tx_packets; + + qdf_cpumask_clear(cpu_mask); + + if (avg_no_tx_offload_pkts > + dp_ctx->dp_cfg.bus_bw_very_high_threshold) { + dp_pm_qos_update_cpu_mask(cpu_mask, true); + *is_tx_pm_qos_high = true; + } else if (avg_tx > dp_ctx->dp_cfg.bus_bw_high_threshold) { + dp_pm_qos_update_cpu_mask(cpu_mask, false); + *is_tx_pm_qos_high = false; + } else { + *is_tx_pm_qos_high = false; + } + + if (avg_tx > dp_ctx->dp_cfg.tcp_tx_high_tput_thres) + *next_tx_level = WLAN_SVC_TP_HIGH; + else + *next_tx_level = WLAN_SVC_TP_LOW; + + if (dp_ctx->dp_cfg.enable_tcp_limit_output && + dp_ctx->cur_tx_level != *next_tx_level) { + struct wlan_tx_tp_data tx_tp_data = {0}; + + dp_ctx->cur_tx_level = *next_tx_level; + tx_level_change = true; + tx_tp_data.level = *next_tx_level; + tx_tp_data.tcp_limit_output = true; + wlan_dp_update_tcp_tx_param(dp_ctx, &tx_tp_data); + } + + return tx_level_change; +} + +/** + * dp_sap_p2p_update_mid_high_tput() - Update mid high BW for SAP and P2P mode + * @dp_ctx: DP context + * @total_pkts: Total Tx and Rx packets + * + * Return: True if mid high threshold is set and opmode is SAP or P2P GO + */ +static inline +bool dp_sap_p2p_update_mid_high_tput(struct wlan_dp_psoc_context *dp_ctx, + uint64_t total_pkts) +{ + struct wlan_dp_intf *dp_intf = NULL; + struct wlan_dp_intf *dp_intf_next = NULL; + + if (dp_ctx->dp_cfg.bus_bw_mid_high_threshold && + total_pkts > dp_ctx->dp_cfg.bus_bw_mid_high_threshold) { + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + if (dp_intf->device_mode == QDF_SAP_MODE || + dp_intf->device_mode == QDF_P2P_GO_MODE) + return true; + } + } + + return false; +} + +/** + * dp_pld_request_bus_bandwidth() - Function to control bus bandwidth + * @dp_ctx: handle to DP context + * @tx_packets: transmit packet count received in BW interval + * @rx_packets: receive packet count received in BW interval + * @diff_us: delta time since last invocation. + * + * The function controls the bus bandwidth and dynamic control of + * tcp delayed ack configuration. + * + * Returns: None + */ +static void dp_pld_request_bus_bandwidth(struct wlan_dp_psoc_context *dp_ctx, + const uint64_t tx_packets, + const uint64_t rx_packets, + const uint64_t diff_us) +{ + uint16_t index; + bool vote_level_change = false; + bool rx_level_change; + bool tx_level_change; + bool dptrace_high_tput_req; + u64 total_pkts = tx_packets + rx_packets; + enum pld_bus_width_type next_vote_level = PLD_BUS_WIDTH_IDLE; + static enum wlan_tp_level next_rx_level = WLAN_SVC_TP_NONE; + enum wlan_tp_level next_tx_level = WLAN_SVC_TP_NONE; + qdf_cpu_mask pm_qos_cpu_mask_tx, pm_qos_cpu_mask_rx, pm_qos_cpu_mask; + bool is_rx_pm_qos_high; + bool is_tx_pm_qos_high; + bool pmqos_on_low_tput = false; + enum tput_level tput_level; + bool is_tput_level_high; + struct bbm_params param = {0}; + bool legacy_client = false; + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + static enum tput_level prev_tput_level = TPUT_LEVEL_NONE; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + hdd_cb_handle ctx = dp_ops->callback_ctx; + + if (!soc) + return; + + if (dp_ctx->high_bus_bw_request) { + next_vote_level = PLD_BUS_WIDTH_VERY_HIGH; + tput_level = TPUT_LEVEL_VERY_HIGH; + } else if (total_pkts > dp_ctx->dp_cfg.bus_bw_super_high_threshold) { + next_vote_level = PLD_BUS_WIDTH_MAX; + tput_level = TPUT_LEVEL_SUPER_HIGH; + } else if (total_pkts > dp_ctx->dp_cfg.bus_bw_ultra_high_threshold) { + next_vote_level = PLD_BUS_WIDTH_ULTRA_HIGH; + tput_level = TPUT_LEVEL_ULTRA_HIGH; + } else if (total_pkts > dp_ctx->dp_cfg.bus_bw_very_high_threshold) { + next_vote_level = PLD_BUS_WIDTH_VERY_HIGH; + tput_level = TPUT_LEVEL_VERY_HIGH; + } else if (total_pkts > dp_ctx->dp_cfg.bus_bw_high_threshold) { + next_vote_level = PLD_BUS_WIDTH_HIGH; + tput_level = TPUT_LEVEL_HIGH; + if (dp_sap_p2p_update_mid_high_tput(dp_ctx, total_pkts)) { + next_vote_level = PLD_BUS_WIDTH_MID_HIGH; + tput_level = TPUT_LEVEL_MID_HIGH; + } + } else if (total_pkts > dp_ctx->dp_cfg.bus_bw_medium_threshold) { + next_vote_level = PLD_BUS_WIDTH_MEDIUM; + tput_level = TPUT_LEVEL_MEDIUM; + } else if (total_pkts > dp_ctx->dp_cfg.bus_bw_low_threshold) { + next_vote_level = PLD_BUS_WIDTH_LOW; + tput_level = TPUT_LEVEL_LOW; + } else { + next_vote_level = PLD_BUS_WIDTH_IDLE; + tput_level = TPUT_LEVEL_IDLE; + } + + /* + * DBS mode requires more DDR/SNOC resources, vote to ultra high + * only when TPUT can reach VHT80 KPI and IPA is disabled, + * for other cases, follow general voting logic + */ + if (!ucfg_ipa_is_fw_wdi_activated(dp_ctx->pdev) && + policy_mgr_is_current_hwmode_dbs(dp_ctx->psoc) && + (total_pkts > dp_ctx->dp_cfg.bus_bw_dbs_threshold) && + (tput_level < TPUT_LEVEL_SUPER_HIGH)) { + next_vote_level = PLD_BUS_WIDTH_ULTRA_HIGH; + tput_level = TPUT_LEVEL_ULTRA_HIGH; + } + + param.policy = BBM_TPUT_POLICY; + param.policy_info.tput_level = tput_level; + dp_bbm_apply_independent_policy(dp_ctx->psoc, ¶m); + + dp_rtpm_tput_policy_apply(dp_ctx, tput_level); + + dptrace_high_tput_req = + next_vote_level > PLD_BUS_WIDTH_IDLE ? true : false; + + if (qdf_atomic_read(&dp_ctx->num_latency_critical_clients)) + legacy_client = true; + + dp_low_tput_gro_flush_skip_handler(dp_ctx, next_vote_level, + legacy_client); + + if (dp_ctx->cur_vote_level != next_vote_level) { + /* Set affinity for tx completion grp interrupts */ + if (tput_level >= TPUT_LEVEL_VERY_HIGH && + prev_tput_level < TPUT_LEVEL_VERY_HIGH) + hif_set_grp_intr_affinity(hif_ctx, + cdp_get_tx_rings_grp_bitmap(soc), true); + else if (tput_level < TPUT_LEVEL_VERY_HIGH && + prev_tput_level >= TPUT_LEVEL_VERY_HIGH) + hif_set_grp_intr_affinity(hif_ctx, + cdp_get_tx_rings_grp_bitmap(soc), + false); + + prev_tput_level = tput_level; + dp_ctx->cur_vote_level = next_vote_level; + vote_level_change = true; + + if ((next_vote_level == PLD_BUS_WIDTH_LOW) || + (next_vote_level == PLD_BUS_WIDTH_IDLE)) { + dp_ops->dp_pld_remove_pm_qos(ctx); + if (dp_ctx->dynamic_rps) + dp_clear_rps_cpu_mask(dp_ctx); + } else { + dp_ops->dp_pld_request_pm_qos(ctx); + if (dp_ctx->dynamic_rps) + /*Todo : check once hdd_set_rps_cpu_mask */ + dp_set_rps_cpu_mask(dp_ctx); + } + + if (dp_ctx->dp_cfg.rx_thread_ul_affinity_mask) { + if (next_vote_level == PLD_BUS_WIDTH_HIGH && + tx_packets > + dp_ctx->dp_cfg.bus_bw_high_threshold && + rx_packets > + dp_ctx->dp_cfg.bus_bw_low_threshold) + cds_sched_handle_rx_thread_affinity_req(true); + else if (next_vote_level != PLD_BUS_WIDTH_HIGH) + cds_sched_handle_rx_thread_affinity_req(false); + } + + dp_ops->dp_napi_apply_throughput_policy(ctx, + tx_packets, + rx_packets); + + if (rx_packets < dp_ctx->dp_cfg.bus_bw_low_threshold) + dp_disable_rx_ol_for_low_tput(dp_ctx, true); + else + dp_disable_rx_ol_for_low_tput(dp_ctx, false); + + /* + * force disable pktlog and only re-enable based + * on ini config + */ + if (next_vote_level >= PLD_BUS_WIDTH_HIGH) + dp_ops->dp_pktlog_enable_disable(ctx, + false, 0, 0); + else if (cds_is_packet_log_enabled()) + dp_ops->dp_pktlog_enable_disable(ctx, + true, 0, 0); + } + + qdf_dp_trace_apply_tput_policy(dptrace_high_tput_req); + + rx_level_change = dp_bus_bandwidth_work_tune_rx(dp_ctx, + rx_packets, + diff_us, + &next_rx_level, + &pm_qos_cpu_mask_rx, + &is_rx_pm_qos_high); + + tx_level_change = dp_bus_bandwidth_work_tune_tx(dp_ctx, + tx_packets, + diff_us, + &next_tx_level, + &pm_qos_cpu_mask_tx, + &is_tx_pm_qos_high); + + index = dp_ctx->txrx_hist_idx; + + if (vote_level_change) { + /* Clear mask if BW is not HIGH or more */ + if (next_vote_level < PLD_BUS_WIDTH_HIGH) { + is_rx_pm_qos_high = false; + is_tx_pm_qos_high = false; + qdf_cpumask_clear(&pm_qos_cpu_mask); + if (next_vote_level == PLD_BUS_WIDTH_LOW && + rx_packets > tx_packets && + !legacy_client) { + pmqos_on_low_tput = true; + dp_pm_qos_update_cpu_mask(&pm_qos_cpu_mask, + false); + } + } else { + qdf_cpumask_clear(&pm_qos_cpu_mask); + qdf_cpumask_or(&pm_qos_cpu_mask, + &pm_qos_cpu_mask_tx, + &pm_qos_cpu_mask_rx); + + /* Default mask in case throughput is high */ + if (qdf_cpumask_empty(&pm_qos_cpu_mask)) + dp_pm_qos_update_cpu_mask(&pm_qos_cpu_mask, + false); + } + dp_ops->dp_pm_qos_update_request(ctx, &pm_qos_cpu_mask); + is_tput_level_high = + tput_level >= TPUT_LEVEL_HIGH ? true : false; + cdp_set_bus_vote_lvl_high(soc, is_tput_level_high); + } + + if (vote_level_change || tx_level_change || rx_level_change) { + dp_info("tx:%llu[%llu(off)+%llu(no-off)] rx:%llu[%llu(off)+%llu(no-off)] next_level(vote %u rx %u tx %u rtpm %d) pm_qos(rx:%u,%*pb tx:%u,%*pb on_low_tput:%u)", + tx_packets, + dp_ctx->prev_tx_offload_pkts, + dp_ctx->prev_no_tx_offload_pkts, + rx_packets, + dp_ctx->prev_rx_offload_pkts, + dp_ctx->prev_no_rx_offload_pkts, + next_vote_level, next_rx_level, next_tx_level, + dp_rtpm_tput_policy_get_vote(dp_ctx), + is_rx_pm_qos_high, + qdf_cpumask_pr_args(&pm_qos_cpu_mask_rx), + is_tx_pm_qos_high, + qdf_cpumask_pr_args(&pm_qos_cpu_mask_tx), + pmqos_on_low_tput); + + if (dp_ctx->txrx_hist) { + dp_ctx->txrx_hist[index].next_tx_level = next_tx_level; + dp_ctx->txrx_hist[index].next_rx_level = next_rx_level; + dp_ctx->txrx_hist[index].is_rx_pm_qos_high = + is_rx_pm_qos_high; + dp_ctx->txrx_hist[index].is_tx_pm_qos_high = + is_tx_pm_qos_high; + dp_ctx->txrx_hist[index].next_vote_level = + next_vote_level; + dp_ctx->txrx_hist[index].interval_rx = rx_packets; + dp_ctx->txrx_hist[index].interval_tx = tx_packets; + dp_ctx->txrx_hist[index].qtime = + qdf_get_log_timestamp(); + dp_ctx->txrx_hist_idx++; + dp_ctx->txrx_hist_idx &= NUM_TX_RX_HISTOGRAM_MASK; + } + } + + /* Roaming is a high priority job but gets processed in scheduler + * thread, bypassing printing stats so that kworker exits quickly and + * scheduler thread can utilize CPU. + */ + if (!dp_ops->dp_is_roaming_in_progress(ctx)) { + dp_display_periodic_stats(dp_ctx, (total_pkts > 0) ? + true : false); + dp_periodic_sta_stats_display(dp_ctx); + } + + hif_affinity_mgr_set_affinity(hif_ctx); +} + +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +/** + * dp_rx_check_qdisc_for_intf() - Check if any ingress qdisc is configured + * for given adapter + * @dp_intf: pointer to DP interface context + * + * The function checks if ingress qdisc is registered for a given + * net device. + * + * Return: None + */ +static void +dp_rx_check_qdisc_for_intf(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_callbacks *dp_ops; + QDF_STATUS status; + + dp_ops = &dp_intf->dp_ctx->dp_ops; + status = dp_ops->dp_rx_check_qdisc_configured(dp_intf->dev, + dp_intf->dp_ctx->dp_agg_param.tc_ingress_prio); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (qdf_likely(qdf_atomic_read(&dp_intf->gro_disallowed))) + return; + + dp_debug("ingress qdisc/filter configured disable GRO"); + qdf_atomic_set(&dp_intf->gro_disallowed, 1); + + return; + } else if (status == QDF_STATUS_E_NOSUPPORT) { + if (qdf_unlikely(qdf_atomic_read(&dp_intf->gro_disallowed))) { + dp_debug("ingress qdisc/filter removed enable GRO"); + qdf_atomic_set(&dp_intf->gro_disallowed, 0); + } + } +} +#else +static void +dp_rx_check_qdisc_for_intf(struct wlan_dp_intf *dp_intf) +{ +} +#endif + +#define NO_RX_PKT_LINK_SPEED_AGEOUT_COUNT 50 +static void +dp_link_monitoring(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_intf *dp_intf) +{ + struct cdp_peer_stats *peer_stats; + QDF_STATUS status; + ol_txrx_soc_handle soc; + struct wlan_objmgr_peer *bss_peer; + static uint32_t no_rx_times; + uint64_t rx_packets; + uint32_t link_speed; + struct wlan_objmgr_psoc *psoc; + struct link_monitoring link_mon; + struct wlan_dp_link *def_link = dp_intf->def_link; + + /* + * If throughput is high, link speed should be good, don't check it + * to avoid performance penalty + */ + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (cdp_get_bus_lvl_high(soc) == true) + return; + + link_mon = dp_intf->link_monitoring; + if (!dp_ctx->dp_ops.link_monitoring_cb) + return; + + psoc = dp_ctx->psoc; + /* If no rx packets received for N sec, set link speed to poor */ + if (link_mon.is_rx_linkspeed_good) { + rx_packets = DP_BW_GET_DIFF( + qdf_net_stats_get_rx_pkts(&dp_intf->stats), + dp_intf->prev_rx_packets); + if (!rx_packets) + no_rx_times++; + else + no_rx_times = 0; + if (no_rx_times >= NO_RX_PKT_LINK_SPEED_AGEOUT_COUNT) { + no_rx_times = 0; + dp_ctx->dp_ops.link_monitoring_cb(psoc, + def_link->link_id, + false); + dp_intf->link_monitoring.is_rx_linkspeed_good = false; + + return; + } + } + /* Get rx link speed from dp peer */ + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) + return; + + /* TODO - Temp WAR, check what to do here */ + /* Peer stats for any link peer is going to return the + * stats from MLD peer, so its okay to query deflink + */ + bss_peer = wlan_vdev_get_bsspeer(def_link->vdev); + if (!bss_peer) { + dp_debug("Invalid bss peer"); + qdf_mem_free(peer_stats); + return; + } + + status = cdp_host_get_peer_stats(soc, def_link->link_id, + bss_peer->macaddr, + peer_stats); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(peer_stats); + return; + } + /* Convert rx linkspeed from kbps to mbps to compare with threshold */ + link_speed = peer_stats->rx.last_rx_rate / 1000; + + /* + * When found current rx link speed becomes good(above threshold) or + * poor, update to firmware. + * If the current RX link speed is above the threshold, low rssi + * roaming is not needed. If linkspeed_threshold is set to 0, the + * firmware will not consider RX link speed in the roaming decision, + * driver will send rx link speed poor state to firmware. + */ + if (!link_mon.rx_linkspeed_threshold) { + dp_ctx->dp_ops.link_monitoring_cb(psoc, def_link->link_id, + false); + dp_intf->link_monitoring.is_rx_linkspeed_good = false; + } else if (link_speed > link_mon.rx_linkspeed_threshold && + !link_mon.is_rx_linkspeed_good) { + dp_ctx->dp_ops.link_monitoring_cb(psoc, def_link->link_id, + true); + dp_intf->link_monitoring.is_rx_linkspeed_good = true; + } else if (link_speed < link_mon.rx_linkspeed_threshold && + link_mon.is_rx_linkspeed_good) { + dp_ctx->dp_ops.link_monitoring_cb(psoc, def_link->link_id, + false); + dp_intf->link_monitoring.is_rx_linkspeed_good = false; + } + + qdf_mem_free(peer_stats); +} + +/** + * __dp_bus_bw_work_handler() - Bus bandwidth work handler + * @dp_ctx: handle to DP context + * + * The function handles the bus bandwidth work schedule + * + * Returns: None + */ +static void __dp_bus_bw_work_handler(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_dp_intf *dp_intf = NULL, *con_sap_dp_intf = NULL; + struct wlan_dp_intf *dp_intf_next = NULL; + struct wlan_dp_link *dp_link = NULL; + struct wlan_dp_link *dp_link_next; + uint64_t tx_packets = 0, rx_packets = 0, tx_bytes = 0; + uint64_t fwd_tx_packets = 0, fwd_rx_packets = 0; + uint64_t fwd_tx_packets_temp = 0, fwd_rx_packets_temp = 0; + uint64_t fwd_tx_packets_diff = 0, fwd_rx_packets_diff = 0; + uint64_t total_tx = 0, total_rx = 0; + A_STATUS ret; + bool connected = false; + uint32_t ipa_tx_packets = 0, ipa_rx_packets = 0; + uint64_t sta_tx_bytes = 0, sap_tx_bytes = 0; + uint64_t diff_us; + uint64_t curr_time_us; + uint32_t bw_interval_us; + hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx; + + if (wlan_dp_validate_context(dp_ctx)) + goto stop_work; + + if (dp_ctx->is_suspend) + return; + + bw_interval_us = dp_ctx->dp_cfg.bus_bw_compute_interval * 1000; + + curr_time_us = qdf_get_log_timestamp(); + diff_us = qdf_log_timestamp_to_usecs( + curr_time_us - dp_ctx->bw_vote_time); + dp_ctx->bw_vote_time = curr_time_us; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + vdev = dp_objmgr_get_vdev_by_user(dp_intf->def_link, + WLAN_DP_ID); + if (!vdev) + continue; + + if ((dp_intf->device_mode == QDF_STA_MODE || + dp_intf->device_mode == QDF_P2P_CLIENT_MODE) && + !wlan_cm_is_vdev_active(vdev)) { + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + continue; + } + + if ((dp_intf->device_mode == QDF_SAP_MODE || + dp_intf->device_mode == QDF_P2P_GO_MODE) && + !dp_ctx->dp_ops.dp_is_ap_active(ctx, + dp_intf->dev)) { + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + continue; + } + + if (dp_ctx->dp_agg_param.tc_based_dyn_gro) + dp_rx_check_qdisc_for_intf(dp_intf); + + tx_packets += DP_BW_GET_DIFF( + qdf_net_stats_get_tx_pkts(&dp_intf->stats), + dp_intf->prev_tx_packets); + rx_packets += DP_BW_GET_DIFF( + qdf_net_stats_get_rx_pkts(&dp_intf->stats), + dp_intf->prev_rx_packets); + tx_bytes = DP_BW_GET_DIFF( + qdf_net_stats_get_tx_bytes(&dp_intf->stats), + dp_intf->prev_tx_bytes); + + if (dp_intf->device_mode == QDF_STA_MODE && + wlan_cm_is_vdev_active(vdev)) { + dp_ctx->dp_ops.dp_send_mscs_action_frame(ctx, + dp_intf->dev); + if (dp_intf->link_monitoring.enabled) + dp_link_monitoring(dp_ctx, dp_intf); + } + + ret = A_ERROR; + fwd_tx_packets = 0; + fwd_rx_packets = 0; + if (dp_intf->device_mode == QDF_SAP_MODE || + dp_intf->device_mode == QDF_P2P_GO_MODE || + dp_intf->device_mode == QDF_NDI_MODE) { + dp_for_each_link_held_safe(dp_intf, dp_link, + dp_link_next) { + ret = cdp_get_intra_bss_fwd_pkts_count( + cds_get_context(QDF_MODULE_ID_SOC), + dp_link->link_id, + &fwd_tx_packets_temp, + &fwd_rx_packets_temp); + if (ret == A_OK) { + fwd_tx_packets += fwd_tx_packets_temp; + fwd_rx_packets += fwd_rx_packets_temp; + } else { + break; + } + } + } + + if (ret == A_OK) { + fwd_tx_packets_diff += DP_BW_GET_DIFF( + fwd_tx_packets, + dp_intf->prev_fwd_tx_packets); + fwd_rx_packets_diff += DP_BW_GET_DIFF( + fwd_rx_packets, + dp_intf->prev_fwd_rx_packets); + } + + if (dp_intf->device_mode == QDF_SAP_MODE) { + con_sap_dp_intf = dp_intf; + sap_tx_bytes = + qdf_net_stats_get_tx_bytes(&dp_intf->stats); + } + + if (dp_intf->device_mode == QDF_STA_MODE) + sta_tx_bytes = + qdf_net_stats_get_tx_bytes(&dp_intf->stats); + + dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) { + dp_set_driver_del_ack_enable(dp_link->link_id, dp_ctx, + rx_packets); + + dp_set_vdev_bundle_require_flag(dp_link->link_id, + dp_ctx, tx_bytes); + } + + total_rx += qdf_net_stats_get_rx_pkts(&dp_intf->stats); + total_tx += qdf_net_stats_get_tx_pkts(&dp_intf->stats); + + qdf_spin_lock_bh(&dp_ctx->bus_bw_lock); + dp_intf->prev_tx_packets = + qdf_net_stats_get_tx_pkts(&dp_intf->stats); + dp_intf->prev_rx_packets = + qdf_net_stats_get_rx_pkts(&dp_intf->stats); + dp_intf->prev_fwd_tx_packets = fwd_tx_packets; + dp_intf->prev_fwd_rx_packets = fwd_rx_packets; + dp_intf->prev_tx_bytes = + qdf_net_stats_get_tx_bytes(&dp_intf->stats); + qdf_spin_unlock_bh(&dp_ctx->bus_bw_lock); + connected = true; + + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + if (!connected) { + dp_err("bus bandwidth timer running in disconnected state"); + goto stop_work; + } + + /* add intra bss forwarded tx and rx packets */ + tx_packets += fwd_tx_packets_diff; + rx_packets += fwd_rx_packets_diff; + + /* Send embedded Tx packet bytes on STA & SAP interface to IPA driver */ + ucfg_ipa_update_tx_stats(dp_ctx->pdev, sta_tx_bytes, sap_tx_bytes); + + dp_ipa_set_perf_level(dp_ctx, &tx_packets, &rx_packets, + &ipa_tx_packets, &ipa_rx_packets); + if (con_sap_dp_intf) { + qdf_net_stats_add_tx_pkts(&con_sap_dp_intf->stats, + ipa_tx_packets); + qdf_net_stats_add_rx_pkts(&con_sap_dp_intf->stats, + ipa_rx_packets); + } + + tx_packets = tx_packets * bw_interval_us; + tx_packets = qdf_do_div(tx_packets, (uint32_t)diff_us); + + rx_packets = rx_packets * bw_interval_us; + rx_packets = qdf_do_div(rx_packets, (uint32_t)diff_us); + + dp_pld_request_bus_bandwidth(dp_ctx, tx_packets, rx_packets, diff_us); + + return; + +stop_work: + qdf_periodic_work_stop_async(&dp_ctx->bus_bw_work); +} + +/** + * dp_bus_bw_work_handler() - Bus bandwidth work handler + * @context: handle to DP context + * + * The function handles the bus bandwidth work schedule + * + * Returns: None + */ +static void dp_bus_bw_work_handler(void *context) +{ + struct wlan_dp_psoc_context *dp_ctx = context; + struct qdf_op_sync *op_sync; + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + if (qdf_op_protect(&op_sync)) + return; + + __dp_bus_bw_work_handler(dp_ctx); + + qdf_op_unprotect(op_sync); +} + +int dp_bus_bandwidth_init(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + hdd_cb_handle ctx = dp_ctx->dp_ops.callback_ctx; + QDF_STATUS status; + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + return QDF_STATUS_SUCCESS; + + dp_enter(); + + qdf_spinlock_create(&dp_ctx->bus_bw_lock); + + dp_ctx->dp_ops.dp_pm_qos_add_request(ctx); + + wlan_dp_init_tx_rx_histogram(dp_ctx); + status = qdf_periodic_work_create(&dp_ctx->bus_bw_work, + dp_bus_bw_work_handler, + dp_ctx); + + dp_exit(); + + return qdf_status_to_os_return(status); +} + +void dp_bus_bandwidth_deinit(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + hdd_cb_handle ctx; + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + ctx = dp_ctx->dp_ops.callback_ctx; + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + return; + + dp_enter(); + + /* it is expecting the timer has been stopped or not started + * when coming deinit. + */ + QDF_BUG(!qdf_periodic_work_stop_sync(&dp_ctx->bus_bw_work)); + + qdf_periodic_work_destroy(&dp_ctx->bus_bw_work); + qdf_spinlock_destroy(&dp_ctx->bus_bw_lock); + wlan_dp_deinit_tx_rx_histogram(dp_ctx); + dp_ctx->dp_ops.dp_pm_qos_remove_request(ctx); + + dp_exit(); +} + +/** + * __dp_bus_bw_compute_timer_start() - start the bus bandwidth timer + * @psoc: psoc handle + * + * Return: None + */ +static void __dp_bus_bw_compute_timer_start(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + return; + + qdf_periodic_work_start(&dp_ctx->bus_bw_work, + dp_ctx->dp_cfg.bus_bw_compute_interval); + dp_ctx->bw_vote_time = qdf_get_log_timestamp(); +} + +void dp_bus_bw_compute_timer_start(struct wlan_objmgr_psoc *psoc) +{ + dp_enter(); + + __dp_bus_bw_compute_timer_start(psoc); + + dp_exit(); +} + +void dp_bus_bw_compute_timer_try_start(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + hdd_cb_handle ctx; + + dp_enter(); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + ctx = dp_ctx->dp_ops.callback_ctx; + + if (dp_ctx->dp_ops.dp_any_adapter_connected(ctx)) + __dp_bus_bw_compute_timer_start(psoc); + + dp_exit(); +} + +/** + * __dp_bus_bw_compute_timer_stop() - stop the bus bandwidth timer + * @psoc: psoc handle + * + * Return: None + */ +static void __dp_bus_bw_compute_timer_stop(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + hdd_cb_handle ctx; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + struct bbm_params param = {0}; + bool is_any_adapter_conn; + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + return; + + if (!dp_ctx || !soc) + return; + + ctx = dp_ctx->dp_ops.callback_ctx; + is_any_adapter_conn = dp_ctx->dp_ops.dp_any_adapter_connected(ctx); + + if (!qdf_periodic_work_stop_sync(&dp_ctx->bus_bw_work)) + goto exit; + + ucfg_ipa_set_perf_level(dp_ctx->pdev, 0, 0); + + dp_reset_tcp_delack(psoc); + + if (!is_any_adapter_conn) + dp_reset_tcp_adv_win_scale(dp_ctx); + + cdp_pdev_reset_driver_del_ack(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID); + cdp_pdev_reset_bundle_require_flag(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID); + + cdp_set_bus_vote_lvl_high(soc, false); + dp_ctx->bw_vote_time = 0; + +exit: + /** + * This check if for the case where the bus bw timer is forcibly + * stopped. We should remove the bus bw voting, if no adapter is + * connected + */ + if (!is_any_adapter_conn) { + uint64_t interval_us = + dp_ctx->dp_cfg.bus_bw_compute_interval * 1000; + qdf_atomic_set(&dp_ctx->num_latency_critical_clients, 0); + dp_pld_request_bus_bandwidth(dp_ctx, 0, 0, interval_us); + } + param.policy = BBM_TPUT_POLICY; + param.policy_info.tput_level = TPUT_LEVEL_NONE; + dp_bbm_apply_independent_policy(psoc, ¶m); +} + +void dp_bus_bw_compute_timer_stop(struct wlan_objmgr_psoc *psoc) +{ + dp_enter(); + + __dp_bus_bw_compute_timer_stop(psoc); + + dp_exit(); +} + +void dp_bus_bw_compute_timer_try_stop(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + hdd_cb_handle ctx; + + dp_enter(); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + ctx = dp_ctx->dp_ops.callback_ctx; + + if (!dp_ctx->dp_ops.dp_any_adapter_connected(ctx)) + __dp_bus_bw_compute_timer_stop(psoc); + + dp_exit(); +} + +void dp_bus_bw_compute_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_link) { + dp_err("No dp_link for objmgr vdev %pK", vdev); + return; + } + + dp_intf = dp_link->dp_intf; + if (!dp_intf) { + dp_err("Invalid dp_intf for dp_link %pK (" QDF_MAC_ADDR_FMT ")", + dp_link, QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + return; + } + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + return; + + qdf_spin_lock_bh(&dp_ctx->bus_bw_lock); + dp_intf->prev_tx_packets = qdf_net_stats_get_tx_pkts(&dp_intf->stats); + dp_intf->prev_rx_packets = qdf_net_stats_get_rx_pkts(&dp_intf->stats); + dp_intf->prev_tx_bytes = qdf_net_stats_get_tx_bytes(&dp_intf->stats); + + /* + * TODO - Should the prev_fwd_tx_packets and + * such stats be per link ?? + */ + cdp_get_intra_bss_fwd_pkts_count(cds_get_context(QDF_MODULE_ID_SOC), + dp_link->link_id, + &dp_intf->prev_fwd_tx_packets, + &dp_intf->prev_fwd_rx_packets); + qdf_spin_unlock_bh(&dp_ctx->bus_bw_lock); +} + +void dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_link) { + dp_err("No dp_link for objmgr vdev %pK", vdev); + return; + } + + dp_intf = dp_link->dp_intf; + if (!dp_intf) { + dp_err("Invalid dp_intf for dp_link %pK (" QDF_MAC_ADDR_FMT ")", + dp_link, QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + return; + } + + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + return; + + qdf_spin_lock_bh(&dp_ctx->bus_bw_lock); + dp_intf->prev_tx_packets = 0; + dp_intf->prev_rx_packets = 0; + dp_intf->prev_fwd_tx_packets = 0; + dp_intf->prev_fwd_rx_packets = 0; + dp_intf->prev_tx_bytes = 0; + qdf_spin_unlock_bh(&dp_ctx->bus_bw_lock); +} +#endif /* WLAN_FEATURE_DP_BUS_BANDWIDTH */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_bus_bandwidth.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_bus_bandwidth.h new file mode 100644 index 0000000000..64397fe8ba --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_bus_bandwidth.h @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_DP_BUS_BANDWIDTH_H) +#define WLAN_DP_BUS_BANDWIDTH_H +/** + * DOC: wlan_dp_bus_bandwidth.h + * + * Bus Bandwidth Manager implementation + */ + +#include "wlan_dp_priv.h" +#include +#include +#include +#include "wlan_dp_public_struct.h" +#include "wlan_dp_priv.h" +#include + +typedef const enum bus_bw_level + bus_bw_table_type[QCA_WLAN_802_11_MODE_INVALID][TPUT_LEVEL_MAX]; + +/** + * struct bbm_context: Bus Bandwidth Manager context + * + * @curr_bus_bw_lookup_table: current bus bw lookup table + * @curr_vote_level: current vote level + * @per_policy_vote: per BBM policy related vote + * @bbm_lock: BBM API lock + */ +struct bbm_context { + bus_bw_table_type *curr_bus_bw_lookup_table; + enum bus_bw_level curr_vote_level; + enum bus_bw_level per_policy_vote[BBM_MAX_POLICY]; + qdf_mutex_t bbm_lock; +}; + +#ifdef FEATURE_BUS_BANDWIDTH_MGR +/** + * dp_bbm_context_init() - Initialize BBM context + * @psoc: psoc Handle + * + * Returns: error code + */ +int dp_bbm_context_init(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bbm_context_deinit() - De-initialize BBM context + * @psoc: psoc Handle + * + * Returns: None + */ +void dp_bbm_context_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bbm_apply_independent_policy() - Function to apply independent policies + * to set the bus bw level + * @psoc: psoc Handle + * @params: BBM policy related params + * + * The function applies BBM related policies and appropriately sets the bus + * bandwidth level. + * + * Returns: None + */ +void dp_bbm_apply_independent_policy(struct wlan_objmgr_psoc *psoc, + struct bbm_params *params); +#else +static inline int dp_bbm_context_init(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline void dp_bbm_context_deinit(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bbm_apply_independent_policy(struct wlan_objmgr_psoc *psoc, + struct bbm_params *params) +{ +} +#endif /* FEATURE_BUS_BANDWIDTH_MGR */ + +#if defined(WLAN_FEATURE_DP_BUS_BANDWIDTH) && defined(FEATURE_RUNTIME_PM) +/** + * dp_rtpm_tput_policy_init() - Initialize RTPM tput policy + * @psoc: psoc handle + * + * Returns: None + */ +void dp_rtpm_tput_policy_init(struct wlan_objmgr_psoc *psoc); + +/** + * dp_rtpm_tput_policy_deinit() - Deinitialize RTPM tput policy + * @psoc: psoc handle + * + * Returns: None + */ +void dp_rtpm_tput_policy_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * dp_rtpm_tput_policy_apply() - Apply RTPM tput policy + * @dp_ctx: dp_ctx handle + * @tput_level : Tput level + * + * Returns: None + */ +void dp_rtpm_tput_policy_apply(struct wlan_dp_psoc_context *dp_ctx, + enum tput_level tput_level); + +/** + * dp_rtpm_tput_policy_get_vote() - Get RTPM tput policy vote + * @dp_ctx: dp_ctx handle + * + * Returns: Current vote + */ +int dp_rtpm_tput_policy_get_vote(struct wlan_dp_psoc_context *dp_ctx); +#else +static inline +void dp_rtpm_tput_policy_init(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_rtpm_tput_policy_deinit(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_rtpm_tput_policy_apply(struct wlan_dp_psoc_context *dp_ctx, + enum tput_level tput_level) +{ +} + +static inline int +dp_rtpm_tput_policy_get_vote(struct wlan_dp_psoc_context *dp_ctx) +{ + return -EINVAL; +} +#endif /* WLAN_FEATURE_DP_BUS_BANDWIDTH && FEATURE_RUNTIME_PM */ + +/** + * dp_set_high_bus_bw_request() - Set High Bandwidth request value + * @psoc: psoc handle + * @vdev_id: Vdev ID + * @high_bus_bw : Flag to set or clear high bandwidth request + * + * Return: None + */ +static inline void dp_set_high_bus_bw_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool high_bus_bw) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (high_bus_bw) + dp_ctx->high_bus_bw_request |= (1 << vdev_id); + else + dp_ctx->high_bus_bw_request &= ~(1 << vdev_id); +} + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +/** + * dp_reset_tcp_delack() - Reset tcp delack value to default + * @psoc: psoc handle + * + * Function used to reset TCP delack value to its default value + * + * Return: None + */ +void dp_reset_tcp_delack(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dp_update_tcp_rx_param() - update TCP param in RX dir + * @dp_ctx: Pointer to DP context + * @data: Parameters to update + * + * Return: None + */ +void wlan_dp_update_tcp_rx_param(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_rx_tp_data *data); + +#ifdef RX_PERFORMANCE +/** + * dp_is_current_high_throughput() - Check if vote level is high + * @dp_ctx: Pointer to DP context + * + * Function used to check if vote level is high + * + * Return: True if vote level is high + */ +bool dp_is_current_high_throughput(struct wlan_dp_psoc_context *dp_ctx); +#else +static inline +bool dp_is_current_high_throughput(struct wlan_dp_psoc_context *dp_ctx) +{ + return false; +} +#endif /* RX_PERFORMANCE */ + +/** + * dp_reset_tcp_delack() - Reset TCP delack + * @psoc: psoc handle + * + * Return: None + */ +void dp_reset_tcp_delack(struct wlan_objmgr_psoc *psoc); + +/** + * dp_get_current_throughput_level() - Get the current vote + * level + * @dp_ctx: DP Context handle + * + * Return: current vote level + */ +static inline enum pld_bus_width_type +dp_get_current_throughput_level(struct wlan_dp_psoc_context *dp_ctx) +{ + return dp_ctx->cur_vote_level; +} + +/** + * dp_set_current_throughput_level() - update the current vote + * level + * @psoc: psoc object + * @next_vote_level: pld_bus_width_type voting level + * + * This function updates the current vote level to the new level + * provided + * + * Return: None + */ +static inline void +dp_set_current_throughput_level(struct wlan_objmgr_psoc *psoc, + enum pld_bus_width_type next_vote_level) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + dp_ctx->cur_vote_level = next_vote_level; +} + +/** + * wlan_dp_display_tx_rx_histogram() - display tx rx histogram + * @psoc: psoc handle + * + * Return: none + */ +void wlan_dp_display_tx_rx_histogram(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dp_clear_tx_rx_histogram() - clear tx rx histogram + * @psoc: psoc handle + * + * Return: none + */ +void wlan_dp_clear_tx_rx_histogram(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bandwidth_init() - Initialize bus bandwidth data structures. + * @psoc: psoc handle + * + * Initialize bus bandwidth related data structures like spinlock and timer. + * + * Return: None. + */ +int dp_bus_bandwidth_init(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bandwidth_deinit() - De-initialize bus bandwidth data structures. + * @psoc: psoc handle + * + * De-initialize bus bandwidth related data structures like timer. + * + * Return: None. + */ +void dp_bus_bandwidth_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bw_compute_timer_start() - start the bandwidth timer + * @psoc: psoc handle + * + * Return: None + */ +void dp_bus_bw_compute_timer_start(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bw_compute_timer_try_start() - try to start the bandwidth timer + * @psoc: psoc handle + * + * This function ensures there is at least one interface in the assoc state + * before starting the bandwidth timer. + * + * Return: None + */ +void dp_bus_bw_compute_timer_try_start(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bw_compute_timer_stop() - stop the bandwidth timer + * @psoc: psoc handle + * + * Return: None + */ +void dp_bus_bw_compute_timer_stop(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bw_compute_timer_try_stop() - try to stop the bandwidth timer + * @psoc: psoc handle + * + * This function ensures there are no interface in the assoc state before + * stopping the bandwidth timer. + * + * Return: None + */ +void dp_bus_bw_compute_timer_try_stop(struct wlan_objmgr_psoc *psoc); + +/** + * dp_bus_bw_compute_prev_txrx_stats() - get tx and rx stats + * @vdev: vdev handle + * + * This function get the collected tx and rx stats before starting + * the bus bandwidth timer. + * + * Return: None + */ +void dp_bus_bw_compute_prev_txrx_stats(struct wlan_objmgr_vdev *vdev); + +/** + * dp_bus_bw_compute_reset_prev_txrx_stats() - reset previous tx and rx stats + * @vdev: vdev handle + * + * This function resets the previous tx rx stats. + * + * Return: None + */ +void dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev); + +/** + * dp_get_bus_bw_high_threshold() - Get the bus bw high threshold + * level + * @dp_ctx: DP Context handle + * + * Return: bus bw high threshold + */ +static inline uint32_t +dp_get_bus_bw_high_threshold(struct wlan_dp_psoc_context *dp_ctx) +{ + return dp_ctx->dp_cfg.bus_bw_high_threshold; +} + +#else +static inline +void dp_reset_tcp_delack(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void wlan_dp_update_tcp_rx_param(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_rx_tp_data *data) +{ +} + +static inline +bool dp_is_current_high_throughput(struct wlan_dp_psoc_context *dp_ctx) +{ + return false; +} + +static inline enum pld_bus_width_type +dp_get_current_throughput_level(struct wlan_dp_psoc_context *dp_ctx) +{ + return PLD_BUS_WIDTH_NONE; +} + +static inline +void dp_set_current_throughput_level(struct wlan_objmgr_psoc *psoc, + enum pld_bus_width_type next_vote_level) +{ +} + +static inline +void wlan_dp_display_tx_rx_histogram(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void wlan_dp_clear_tx_rx_histogram(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bandwidth_init(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bandwidth_deinit(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bw_compute_timer_start(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bw_compute_timer_try_start(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bw_compute_timer_stop(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bw_compute_timer_try_stop(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void dp_bus_bw_compute_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +void dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline uint32_t +dp_get_bus_bw_high_threshold(struct wlan_dp_psoc_context *dp_ctx) +{ + return 0; +} + +#endif /* WLAN_FEATURE_DP_BUS_BANDWIDTH */ +#endif /* WLAN_DP_BUS_BANDWIDTH_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_fisa_rx.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_fisa_rx.c new file mode 100644 index 0000000000..d1298f5cca --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_fisa_rx.c @@ -0,0 +1,2340 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "hal_rx_flow.h" +#include "dp_htt.h" +#include "dp_internal.h" +#include "hif.h" + +static void dp_rx_fisa_flush_flow_wrap(struct dp_fisa_rx_sw_ft *sw_ft); + +/* + * Used by FW to route RX packets to host REO2SW1 ring if IPA hit + * RX back pressure. + */ +#define REO_DEST_IND_IPA_REROUTE 2 + +#if defined(FISA_DEBUG_ENABLE) +/** + * hex_dump_skb_data() - Helper function to dump skb while debugging + * @nbuf: Nbuf to be dumped + * @dump: dump enable/disable dumping + * + * Return: NONE + */ +static void hex_dump_skb_data(qdf_nbuf_t nbuf, bool dump) +{ + qdf_nbuf_t next_nbuf; + int i = 0; + + if (!dump) + return; + + if (!nbuf) + return; + + dp_fisa_debug("%ps: skb: %pK skb->next:%pK frag_list %pK skb->data:%pK len %d data_len %d", + (void *)QDF_RET_IP, nbuf, qdf_nbuf_next(nbuf), + qdf_nbuf_get_ext_list(nbuf), qdf_nbuf_data(nbuf), + qdf_nbuf_len(nbuf), qdf_nbuf_get_only_data_len(nbuf)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH, + nbuf->data, 64); + + next_nbuf = qdf_nbuf_get_ext_list(nbuf); + while (next_nbuf) { + dp_fisa_debug("%d nbuf:%pK nbuf->next:%pK nbuf->data:%pK len %d", + i, next_nbuf, qdf_nbuf_next(next_nbuf), + qdf_nbuf_data(next_nbuf), + qdf_nbuf_len(next_nbuf)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH, + qdf_nbuf_data(next_nbuf), 64); + next_nbuf = qdf_nbuf_next(next_nbuf); + i++; + } +} + +/** + * dump_tlvs() - Helper function to dump TLVs of msdu + * @hal_soc_hdl: Handle to TLV functions + * @buf: Pointer to TLV header + * @dbg_level: level control output of TLV dump + * + * Return: NONE + */ +static void dump_tlvs(hal_soc_handle_t hal_soc_hdl, uint8_t *buf, + uint8_t dbg_level) +{ + uint32_t fisa_aggr_count, fisa_timeout, cumulat_l4_csum, cumulat_ip_len; + int flow_aggr_cont; + + hal_rx_dump_pkt_tlvs(hal_soc_hdl, buf, dbg_level); + + flow_aggr_cont = hal_rx_get_fisa_flow_agg_continuation(hal_soc_hdl, + buf); + fisa_aggr_count = hal_rx_get_fisa_flow_agg_count(hal_soc_hdl, buf); + fisa_timeout = hal_rx_get_fisa_timeout(hal_soc_hdl, buf); + cumulat_l4_csum = hal_rx_get_fisa_cumulative_l4_checksum(hal_soc_hdl, + buf); + cumulat_ip_len = hal_rx_get_fisa_cumulative_ip_length(hal_soc_hdl, buf); + + dp_fisa_debug("flow_aggr_cont %d, fisa_timeout %d, fisa_aggr_count %d, cumulat_l4_csum %d, cumulat_ip_len %d", + flow_aggr_cont, fisa_timeout, fisa_aggr_count, + cumulat_l4_csum, cumulat_ip_len); +} +#else +static void hex_dump_skb_data(qdf_nbuf_t nbuf, bool dump) +{ +} + +static void dump_tlvs(hal_soc_handle_t hal_soc_hdl, uint8_t *buf, + uint8_t dbg_level) +{ +} +#endif + +#ifdef WLAN_SUPPORT_RX_FISA_HIST +static +void dp_fisa_record_pkt(struct dp_fisa_rx_sw_ft *fisa_flow, qdf_nbuf_t nbuf, + uint8_t *rx_tlv_hdr, uint16_t tlv_size) +{ + uint32_t index; + uint8_t *tlv_hist_ptr; + + if (!rx_tlv_hdr || !fisa_flow || !fisa_flow->pkt_hist.tlv_hist) + return; + + index = fisa_flow->pkt_hist.idx++ % FISA_FLOW_MAX_AGGR_COUNT; + + fisa_flow->pkt_hist.ts_hist[index] = qdf_get_log_timestamp(); + tlv_hist_ptr = fisa_flow->pkt_hist.tlv_hist + (index * tlv_size); + qdf_mem_copy(tlv_hist_ptr, rx_tlv_hdr, tlv_size); +} +#else +static +void dp_fisa_record_pkt(struct dp_fisa_rx_sw_ft *fisa_flow, qdf_nbuf_t nbuf, + uint8_t *rx_tlv_hdr, uint16_t tlv_size) +{ +} + +#endif + +/** + * wlan_dp_nbuf_skip_rx_pkt_tlv() - Function to skip the TLVs and + * mac header from msdu + * @dp_ctx: DP component handle + * @rx_fst: FST handle + * @nbuf: msdu for which TLVs has to be skipped + * + * Return: None + */ +static inline void +wlan_dp_nbuf_skip_rx_pkt_tlv(struct wlan_dp_psoc_context *dp_ctx, + struct dp_rx_fst *rx_fst, qdf_nbuf_t nbuf) +{ + uint8_t *rx_tlv_hdr; + uint32_t l2_hdr_offset; + + rx_tlv_hdr = qdf_nbuf_data(nbuf); + l2_hdr_offset = hal_rx_msdu_end_l3_hdr_padding_get(dp_ctx->hal_soc, + rx_tlv_hdr); + qdf_nbuf_pull_head(nbuf, rx_fst->rx_pkt_tlv_size + l2_hdr_offset); +} + +static bool +dp_rx_fisa_should_bypass(struct cdp_rx_flow_tuple_info *flow_tuple_info) +{ + if (flow_tuple_info->dest_port == DNS_SERVER_PORT || + flow_tuple_info->src_port == DNS_SERVER_PORT) + return true; + + return false; +} + +static bool +dp_fisa_is_ipsec_connection(struct cdp_rx_flow_tuple_info *flow_tuple_info) +{ + if (flow_tuple_info->dest_port == IPSEC_PORT || + flow_tuple_info->dest_port == IPSEC_NAT_PORT || + flow_tuple_info->src_port == IPSEC_PORT || + flow_tuple_info->src_port == IPSEC_NAT_PORT) + return true; + + return false; +} + +/** + * wlan_dp_get_flow_tuple_from_nbuf() - Get the flow tuple from msdu + * @dp_ctx: DP component handle + * @flow_tuple_info: return argument where the flow is populated + * @nbuf: msdu from which flow tuple is extracted. + * @rx_tlv_hdr: Pointer to msdu TLVs + * + * Return: None + */ +static void +wlan_dp_get_flow_tuple_from_nbuf(struct wlan_dp_psoc_context *dp_ctx, + struct cdp_rx_flow_tuple_info *flow_tuple_info, + qdf_nbuf_t nbuf, uint8_t *rx_tlv_hdr) +{ + struct dp_rx_fst *rx_fst = dp_ctx->rx_fst; + qdf_net_iphdr_t *iph; + qdf_net_tcphdr_t *tcph; + uint32_t ip_hdr_offset; + uint32_t tcp_hdr_offset; + uint32_t l2_hdr_offset = + hal_rx_msdu_end_l3_hdr_padding_get(dp_ctx->hal_soc, + rx_tlv_hdr); + + hal_rx_get_l3_l4_offsets(dp_ctx->hal_soc, rx_tlv_hdr, + &ip_hdr_offset, &tcp_hdr_offset); + flow_tuple_info->tuple_populated = true; + + qdf_nbuf_pull_head(nbuf, rx_fst->rx_pkt_tlv_size + l2_hdr_offset); + + iph = (qdf_net_iphdr_t *)(qdf_nbuf_data(nbuf) + ip_hdr_offset); + tcph = (qdf_net_tcphdr_t *)(qdf_nbuf_data(nbuf) + ip_hdr_offset + + tcp_hdr_offset); + + flow_tuple_info->dest_ip_31_0 = qdf_ntohl(iph->ip_daddr); + flow_tuple_info->dest_ip_63_32 = 0; + flow_tuple_info->dest_ip_95_64 = 0; + flow_tuple_info->dest_ip_127_96 = + HAL_IP_DA_SA_PREFIX_IPV4_COMPATIBLE_IPV6; + + flow_tuple_info->src_ip_31_0 = qdf_ntohl(iph->ip_saddr); + flow_tuple_info->src_ip_63_32 = 0; + flow_tuple_info->src_ip_95_64 = 0; + flow_tuple_info->src_ip_127_96 = + HAL_IP_DA_SA_PREFIX_IPV4_COMPATIBLE_IPV6; + + flow_tuple_info->dest_port = qdf_ntohs(tcph->dest); + flow_tuple_info->src_port = qdf_ntohs(tcph->source); + if (dp_fisa_is_ipsec_connection(flow_tuple_info)) + flow_tuple_info->is_exception = 1; + else + flow_tuple_info->is_exception = 0; + + flow_tuple_info->bypass_fisa = + dp_rx_fisa_should_bypass(flow_tuple_info); + + flow_tuple_info->l4_protocol = iph->ip_proto; + dp_fisa_debug("l4_protocol %d", flow_tuple_info->l4_protocol); + + qdf_nbuf_push_head(nbuf, rx_fst->rx_pkt_tlv_size + l2_hdr_offset); + + dp_fisa_debug("head_skb: %pK head_skb->next:%pK head_skb->data:%pK len %d data_len %d", + nbuf, qdf_nbuf_next(nbuf), qdf_nbuf_data(nbuf), + qdf_nbuf_len(nbuf), qdf_nbuf_get_only_data_len(nbuf)); +} + +/** + * dp_rx_fisa_setup_hw_fse() - Populate flow so as to update DDR flow table + * @fisa_hdl: Handle fisa context + * @hashed_flow_idx: Index to flow table + * @rx_flow_info: tuple to be populated in flow table + * @flow_steer_info: REO index to which flow to be steered + * + * Return: Pointer to DDR flow table entry + */ +static void * +dp_rx_fisa_setup_hw_fse(struct dp_rx_fst *fisa_hdl, + uint32_t hashed_flow_idx, + struct cdp_rx_flow_tuple_info *rx_flow_info, + uint32_t flow_steer_info) +{ + struct hal_rx_flow flow; + void *hw_fse; + + flow.reo_destination_indication = flow_steer_info; + flow.fse_metadata = 0xDEADBEEF; + flow.tuple_info.dest_ip_127_96 = rx_flow_info->dest_ip_127_96; + flow.tuple_info.dest_ip_95_64 = rx_flow_info->dest_ip_95_64; + flow.tuple_info.dest_ip_63_32 = rx_flow_info->dest_ip_63_32; + flow.tuple_info.dest_ip_31_0 = rx_flow_info->dest_ip_31_0; + flow.tuple_info.src_ip_127_96 = rx_flow_info->src_ip_127_96; + flow.tuple_info.src_ip_95_64 = rx_flow_info->src_ip_95_64; + flow.tuple_info.src_ip_63_32 = rx_flow_info->src_ip_63_32; + flow.tuple_info.src_ip_31_0 = rx_flow_info->src_ip_31_0; + flow.tuple_info.dest_port = rx_flow_info->dest_port; + flow.tuple_info.src_port = rx_flow_info->src_port; + flow.tuple_info.l4_protocol = rx_flow_info->l4_protocol; + flow.reo_destination_handler = HAL_RX_FSE_REO_DEST_FT; + hw_fse = hal_rx_flow_setup_fse(fisa_hdl->dp_ctx->hal_soc, + fisa_hdl->hal_rx_fst, hashed_flow_idx, + &flow); + + return hw_fse; +} + +#ifdef DP_FT_LOCK_HISTORY +struct dp_ft_lock_history ft_lock_hist[MAX_REO_DEST_RINGS]; + +/** + * dp_rx_fisa_record_ft_lock_event() - Record FT lock/unlock events + * @reo_id: REO ID + * @func: caller function + * @type: lock/unlock event type + * + * Return: None + */ +static void dp_rx_fisa_record_ft_lock_event(uint8_t reo_id, const char *func, + enum dp_ft_lock_event_type type) +{ + struct dp_ft_lock_history *lock_hist; + struct dp_ft_lock_record *record; + uint32_t record_idx; + + if (reo_id >= MAX_REO_DEST_RINGS) + return; + + lock_hist = &ft_lock_hist[reo_id]; + record_idx = lock_hist->record_idx % DP_FT_LOCK_MAX_RECORDS; + ft_lock_hist->record_idx++; + + record = &lock_hist->ft_lock_rec[record_idx]; + + record->func = func; + record->cpu_id = qdf_get_cpu(); + record->timestamp = qdf_get_log_timestamp(); + record->type = type; +} + +/** + * __dp_rx_fisa_acquire_ft_lock() - Acquire lock which protects SW FT entries + * @fisa_hdl: Handle to fisa context + * @reo_id: REO ID + * @func: calling function name + * + * Return: None + */ +static inline void +__dp_rx_fisa_acquire_ft_lock(struct dp_rx_fst *fisa_hdl, + uint8_t reo_id, const char *func) +{ + if (!fisa_hdl->flow_deletion_supported) + return; + + qdf_spin_lock_bh(&fisa_hdl->dp_rx_sw_ft_lock[reo_id]); + dp_rx_fisa_record_ft_lock_event(reo_id, func, DP_FT_LOCK_EVENT); +} + +/** + * __dp_rx_fisa_release_ft_lock() - Release lock which protects SW FT entries + * @fisa_hdl: Handle to fisa context + * @reo_id: REO ID + * @func: calling function name + * + * Return: None + */ +static inline void +__dp_rx_fisa_release_ft_lock(struct dp_rx_fst *fisa_hdl, + uint8_t reo_id, const char *func) +{ + if (!fisa_hdl->flow_deletion_supported) + return; + + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_sw_ft_lock[reo_id]); + dp_rx_fisa_record_ft_lock_event(reo_id, func, DP_FT_UNLOCK_EVENT); +} + +#define dp_rx_fisa_acquire_ft_lock(fisa_hdl, reo_id) \ + __dp_rx_fisa_acquire_ft_lock(fisa_hdl, reo_id, __func__) + +#define dp_rx_fisa_release_ft_lock(fisa_hdl, reo_id) \ + __dp_rx_fisa_release_ft_lock(fisa_hdl, reo_id, __func__) + +#else +/** + * dp_rx_fisa_acquire_ft_lock() - Acquire lock which protects SW FT entries + * @fisa_hdl: Handle to fisa context + * @reo_id: REO ID + * + * Return: None + */ +static inline void +dp_rx_fisa_acquire_ft_lock(struct dp_rx_fst *fisa_hdl, uint8_t reo_id) +{ + if (fisa_hdl->flow_deletion_supported) + qdf_spin_lock_bh(&fisa_hdl->dp_rx_sw_ft_lock[reo_id]); +} + +/** + * dp_rx_fisa_release_ft_lock() - Release lock which protects SW FT entries + * @fisa_hdl: Handle to fisa context + * @reo_id: REO ID + * + * Return: None + */ +static inline void +dp_rx_fisa_release_ft_lock(struct dp_rx_fst *fisa_hdl, uint8_t reo_id) +{ + if (fisa_hdl->flow_deletion_supported) + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_sw_ft_lock[reo_id]); +} +#endif /* DP_FT_LOCK_HISTORY */ + +/** + * dp_rx_fisa_setup_cmem_fse() - Setup the flow search entry in HW CMEM + * @fisa_hdl: Handle to fisa context + * @hashed_flow_idx: Index to flow table + * @rx_flow_info: tuple to be populated in flow table + * @flow_steer_info: REO index to which flow to be steered + * + * Return: Offset to the FSE entry in CMEM + */ +static uint32_t +dp_rx_fisa_setup_cmem_fse(struct dp_rx_fst *fisa_hdl, uint32_t hashed_flow_idx, + struct cdp_rx_flow_tuple_info *rx_flow_info, + uint32_t flow_steer_info) +{ + struct dp_fisa_rx_sw_ft *sw_ft_entry; + struct hal_rx_flow flow; + + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[hashed_flow_idx]); + sw_ft_entry->metadata = ++fisa_hdl->meta_counter; + + flow.reo_destination_indication = flow_steer_info; + flow.fse_metadata = sw_ft_entry->metadata; + flow.tuple_info.dest_ip_127_96 = rx_flow_info->dest_ip_127_96; + flow.tuple_info.dest_ip_95_64 = rx_flow_info->dest_ip_95_64; + flow.tuple_info.dest_ip_63_32 = rx_flow_info->dest_ip_63_32; + flow.tuple_info.dest_ip_31_0 = rx_flow_info->dest_ip_31_0; + flow.tuple_info.src_ip_127_96 = rx_flow_info->src_ip_127_96; + flow.tuple_info.src_ip_95_64 = rx_flow_info->src_ip_95_64; + flow.tuple_info.src_ip_63_32 = rx_flow_info->src_ip_63_32; + flow.tuple_info.src_ip_31_0 = rx_flow_info->src_ip_31_0; + flow.tuple_info.dest_port = rx_flow_info->dest_port; + flow.tuple_info.src_port = rx_flow_info->src_port; + flow.tuple_info.l4_protocol = rx_flow_info->l4_protocol; + flow.reo_destination_handler = HAL_RX_FSE_REO_DEST_FT; + + return hal_rx_flow_setup_cmem_fse(fisa_hdl->dp_ctx->hal_soc, + fisa_hdl->cmem_ba, hashed_flow_idx, + &flow); +} + +static inline +struct wlan_dp_intf *dp_fisa_rx_get_dp_intf_for_vdev(struct dp_vdev *vdev) +{ + struct wlan_dp_link *dp_link = + (struct wlan_dp_link *)vdev->osif_vdev; + + /* dp_link cannot be invalid if vdev is present */ + return dp_link->dp_intf; +} + +/** + * dp_rx_fisa_update_sw_ft_entry() - Helper function to update few SW FT entry + * @sw_ft_entry: Pointer to softerware flow table entry + * @flow_hash: flow_hash for the flow + * @vdev: Saving dp_vdev in FT later used in the flushing the flow + * @dp_ctx: DP component handle + * @flow_id: Flow ID of the flow + * + * Return: NONE + */ +static void dp_rx_fisa_update_sw_ft_entry(struct dp_fisa_rx_sw_ft *sw_ft_entry, + uint32_t flow_hash, + struct dp_vdev *vdev, + struct wlan_dp_psoc_context *dp_ctx, + uint32_t flow_id) +{ + sw_ft_entry->flow_hash = flow_hash; + sw_ft_entry->flow_id = flow_id; + sw_ft_entry->vdev_id = vdev->vdev_id; + sw_ft_entry->vdev = vdev; + sw_ft_entry->dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev); + sw_ft_entry->dp_ctx = dp_ctx; +} + +/** + * is_same_flow() - Function to compare flow tuple to decide if they match + * @tuple1: flow tuple 1 + * @tuple2: flow tuple 2 + * + * Return: true if they match, false if they differ + */ +static bool is_same_flow(struct cdp_rx_flow_tuple_info *tuple1, + struct cdp_rx_flow_tuple_info *tuple2) +{ + if ((tuple1->src_port ^ tuple2->src_port) | + (tuple1->dest_port ^ tuple2->dest_port) | + (tuple1->src_ip_31_0 ^ tuple2->src_ip_31_0) | + (tuple1->src_ip_63_32 ^ tuple2->src_ip_63_32) | + (tuple1->src_ip_95_64 ^ tuple2->src_ip_95_64) | + (tuple1->src_ip_127_96 ^ tuple2->src_ip_127_96) | + (tuple1->dest_ip_31_0 ^ tuple2->dest_ip_31_0) | + /* DST IP check not required? */ + (tuple1->dest_ip_63_32 ^ tuple2->dest_ip_63_32) | + (tuple1->dest_ip_95_64 ^ tuple2->dest_ip_95_64) | + (tuple1->dest_ip_127_96 ^ tuple2->dest_ip_127_96) | + (tuple1->l4_protocol ^ tuple2->l4_protocol)) + return false; + else + return true; +} + +/** + * dp_rx_fisa_add_ft_entry() - Add new flow to HW and SW FT if it is not added + * @vdev: Handle DP vdev to save in SW flow table + * @fisa_hdl: handle to FISA context + * @nbuf: nbuf belonging to new flow + * @rx_tlv_hdr: Pointer to TLV header + * @flow_idx_hash: Hashed flow index + * @reo_dest_indication: Reo destination indication for nbuf + * + * Return: pointer to sw FT entry on success, NULL otherwise + */ +static struct dp_fisa_rx_sw_ft * +dp_rx_fisa_add_ft_entry(struct dp_vdev *vdev, + struct dp_rx_fst *fisa_hdl, + qdf_nbuf_t nbuf, + uint8_t *rx_tlv_hdr, + uint32_t flow_idx_hash, + uint32_t reo_dest_indication) +{ + struct dp_fisa_rx_sw_ft *sw_ft_entry; + uint32_t flow_hash; + uint32_t hashed_flow_idx; + uint32_t skid_count = 0, max_skid_length; + struct cdp_rx_flow_tuple_info rx_flow_tuple_info; + bool is_fst_updated = false; + uint32_t reo_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); + struct hal_proto_params proto_params; + + if (hal_rx_get_proto_params(fisa_hdl->dp_ctx->hal_soc, rx_tlv_hdr, + &proto_params)) + return NULL; + + if (proto_params.ipv6_proto || + !(proto_params.tcp_proto || proto_params.udp_proto)) { + dp_fisa_debug("Not UDP or TCP IPV4 flow"); + return NULL; + } + + rx_flow_tuple_info.tuple_populated = false; + flow_hash = flow_idx_hash; + hashed_flow_idx = flow_hash & fisa_hdl->hash_mask; + max_skid_length = fisa_hdl->max_skid_length; + + dp_fisa_debug("flow_hash 0x%x hashed_flow_idx 0x%x", flow_hash, + hashed_flow_idx); + dp_fisa_debug("max_skid_length 0x%x", max_skid_length); + + qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock); + + if (!rx_flow_tuple_info.tuple_populated) { + wlan_dp_get_flow_tuple_from_nbuf(fisa_hdl->dp_ctx, + &rx_flow_tuple_info, + nbuf, rx_tlv_hdr); + if (rx_flow_tuple_info.bypass_fisa) { + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock); + return NULL; + } + } + + do { + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[hashed_flow_idx]); + if (!sw_ft_entry->is_populated) { + /* Add SW FT entry */ + dp_rx_fisa_update_sw_ft_entry(sw_ft_entry, + flow_hash, vdev, + fisa_hdl->dp_ctx, + hashed_flow_idx); + + /* Add HW FT entry */ + sw_ft_entry->hw_fse = + dp_rx_fisa_setup_hw_fse(fisa_hdl, + hashed_flow_idx, + &rx_flow_tuple_info, + reo_dest_indication); + sw_ft_entry->is_populated = true; + sw_ft_entry->napi_id = reo_id; + sw_ft_entry->reo_dest_indication = reo_dest_indication; + sw_ft_entry->flow_id_toeplitz = + QDF_NBUF_CB_RX_FLOW_ID(nbuf); + sw_ft_entry->flow_init_ts = qdf_get_log_timestamp(); + + qdf_mem_copy(&sw_ft_entry->rx_flow_tuple_info, + &rx_flow_tuple_info, + sizeof(struct cdp_rx_flow_tuple_info)); + + sw_ft_entry->is_flow_tcp = proto_params.tcp_proto; + sw_ft_entry->is_flow_udp = proto_params.udp_proto; + sw_ft_entry->add_timestamp = qdf_get_log_timestamp(); + + is_fst_updated = true; + fisa_hdl->add_flow_count++; + break; + } + /* else */ + + if (is_same_flow(&sw_ft_entry->rx_flow_tuple_info, + &rx_flow_tuple_info)) { + sw_ft_entry->vdev = vdev; + sw_ft_entry->vdev_id = vdev->vdev_id; + sw_ft_entry->dp_intf = + dp_fisa_rx_get_dp_intf_for_vdev(vdev); + dp_fisa_debug("It is same flow fse entry idx %d", + hashed_flow_idx); + /* Incoming flow tuple matches with existing + * entry. This is subsequent skbs of the same + * flow. Earlier entry made is not reflected + * yet in FSE cache + */ + break; + } + /* else */ + /* hash collision move to the next FT entry */ + dp_fisa_debug("Hash collision %d", + fisa_hdl->hash_collision_cnt); + fisa_hdl->hash_collision_cnt++; +#ifdef NOT_YET /* assist Flow eviction algorithm */ + /* uint32_t lru_ft_entry_time = 0xffffffff, lru_ft_entry_idx = 0; */ + if (fisa_hdl->hw_ft_entry->timestamp < lru_ft_entry_time) { + lru_ft_entry_time = fisa_hdl->hw_ft_entry->timestamp; + lru_ft_entry_idx = hashed_flow_idx; + } +#endif + skid_count++; + hashed_flow_idx++; + hashed_flow_idx &= fisa_hdl->hash_mask; + } while (skid_count <= max_skid_length); + + /* + * fisa_hdl->flow_eviction_cnt++; + * if (skid_count > max_skid_length) + * Remove LRU flow from HW FT + * Remove LRU flow from SW FT + */ + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock); + + if (skid_count > max_skid_length) { + dp_fisa_debug("Max skid length reached flow cannot be added, evict exiting flow"); + return NULL; + } + + /** + * Send HTT cache invalidation command to firmware to + * reflect the flow update + */ + if (is_fst_updated && + fisa_hdl->fse_cache_flush_allow && + (qdf_atomic_inc_return(&fisa_hdl->fse_cache_flush_posted) == 1)) { + /* return 1 after increment implies FSE cache flush message + * already posted. so start restart the timer + */ + qdf_timer_start(&fisa_hdl->fse_cache_flush_timer, + FSE_CACHE_FLUSH_TIME_OUT); + } + dp_fisa_debug("sw_ft_entry %pK", sw_ft_entry); + return sw_ft_entry; +} + +/** + * is_flow_idx_valid() - Function to decide if flow_idx TLV is valid + * @flow_invalid: flow invalid TLV value + * @flow_timeout: flow timeout TLV value, set when FSE timedout flow search + * + * Return: True if flow_idx value is valid + */ +static bool is_flow_idx_valid(bool flow_invalid, bool flow_timeout) +{ + if (!flow_invalid && !flow_timeout) + return true; + else + return false; +} + +#ifdef WLAN_SUPPORT_RX_FISA_HIST +/** + * dp_rx_fisa_save_pkt_hist() - Save pkt history from rx sw ft entry + * @ft_entry: sw ft entry + * @pkt_hist: pkt history ptr + * + * Return: None + */ +static inline void +dp_rx_fisa_save_pkt_hist(struct dp_fisa_rx_sw_ft *ft_entry, + struct fisa_pkt_hist *pkt_hist) +{ + /* Structure copy by assignment */ + *pkt_hist = ft_entry->pkt_hist; +} + +/** + * dp_rx_fisa_restore_pkt_hist() - Restore rx sw ft entry pkt history + * @ft_entry: sw ft entry + * @pkt_hist: pkt history ptr + * + * Return: None + */ +static inline void +dp_rx_fisa_restore_pkt_hist(struct dp_fisa_rx_sw_ft *ft_entry, + struct fisa_pkt_hist *pkt_hist) +{ + /* Structure copy by assignment */ + ft_entry->pkt_hist = *pkt_hist; +} +#else +static inline void +dp_rx_fisa_save_pkt_hist(struct dp_fisa_rx_sw_ft *ft_entry, + struct fisa_pkt_hist *pkt_hist) +{ +} + +static inline void +dp_rx_fisa_restore_pkt_hist(struct dp_fisa_rx_sw_ft *ft_entry, + struct fisa_pkt_hist *pkt_hist) +{ +} +#endif + +/** + * dp_fisa_rx_delete_flow() - Delete a flow from SW and HW FST, currently + * only applicable when FST is in CMEM + * @fisa_hdl: handle to FISA context + * @elem: details of the flow which is being added + * @hashed_flow_idx: hashed flow idx of the deleting flow + * + * Return: None + */ +static void +dp_fisa_rx_delete_flow(struct dp_rx_fst *fisa_hdl, + struct dp_fisa_rx_fst_update_elem *elem, + uint32_t hashed_flow_idx) +{ + struct dp_fisa_rx_sw_ft *sw_ft_entry; + struct fisa_pkt_hist pkt_hist; + u8 reo_id; + + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[hashed_flow_idx]); + reo_id = sw_ft_entry->napi_id; + + dp_rx_fisa_acquire_ft_lock(fisa_hdl, reo_id); + + /* Flush the flow before deletion */ + dp_rx_fisa_flush_flow_wrap(sw_ft_entry); + + dp_rx_fisa_save_pkt_hist(sw_ft_entry, &pkt_hist); + /* Clear the sw_ft_entry */ + qdf_mem_zero(sw_ft_entry, sizeof(*sw_ft_entry)); + dp_rx_fisa_restore_pkt_hist(sw_ft_entry, &pkt_hist); + + dp_rx_fisa_update_sw_ft_entry(sw_ft_entry, elem->flow_idx, elem->vdev, + fisa_hdl->dp_ctx, hashed_flow_idx); + + /* Add HW FT entry */ + sw_ft_entry->cmem_offset = dp_rx_fisa_setup_cmem_fse( + fisa_hdl, hashed_flow_idx, + &elem->flow_tuple_info, + elem->reo_dest_indication); + + sw_ft_entry->is_populated = true; + sw_ft_entry->napi_id = elem->reo_id; + sw_ft_entry->reo_dest_indication = elem->reo_dest_indication; + qdf_mem_copy(&sw_ft_entry->rx_flow_tuple_info, &elem->flow_tuple_info, + sizeof(struct cdp_rx_flow_tuple_info)); + + sw_ft_entry->is_flow_tcp = elem->is_tcp_flow; + sw_ft_entry->is_flow_udp = elem->is_udp_flow; + sw_ft_entry->add_timestamp = qdf_get_log_timestamp(); + + fisa_hdl->add_flow_count++; + fisa_hdl->del_flow_count++; + + dp_rx_fisa_release_ft_lock(fisa_hdl, reo_id); +} + +/** + * dp_fisa_rx_get_hw_ft_timestamp() - Get timestamp maintained in the HW FSE + * @fisa_hdl: handle to FISA context + * @hashed_flow_idx: hashed idx of the flow + * + * Return: Timestamp + */ +static uint32_t +dp_fisa_rx_get_hw_ft_timestamp(struct dp_rx_fst *fisa_hdl, + uint32_t hashed_flow_idx) +{ + hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc; + struct dp_fisa_rx_sw_ft *sw_ft_entry; + + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[hashed_flow_idx]); + + if (fisa_hdl->fst_in_cmem) + return hal_rx_flow_get_cmem_fse_timestamp( + hal_soc_hdl, sw_ft_entry->cmem_offset); + + return ((struct rx_flow_search_entry *)sw_ft_entry->hw_fse)->timestamp; +} + +/** + * dp_fisa_rx_fst_update() - Core logic which helps in Addition/Deletion + * of flows + * into/from SW & HW FST + * @fisa_hdl: handle to FISA context + * @elem: details of the flow which is being added + * + * Return: None + */ +static void dp_fisa_rx_fst_update(struct dp_rx_fst *fisa_hdl, + struct dp_fisa_rx_fst_update_elem *elem) +{ + struct cdp_rx_flow_tuple_info *rx_flow_tuple_info; + uint32_t skid_count = 0, max_skid_length; + struct dp_fisa_rx_sw_ft *sw_ft_entry; + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg; + bool is_fst_updated = false; + uint32_t hashed_flow_idx; + uint32_t flow_hash; + uint32_t lru_ft_entry_time = 0xffffffff; + uint32_t lru_ft_entry_idx = 0; + uint32_t timestamp; + uint32_t reo_dest_indication; + uint64_t sw_timestamp; + + /* Get the hash from TLV + * FSE FT Toeplitz hash is same Common parser hash available in TLV + * common parser toeplitz hash is same as FSE toeplitz hash as + * toeplitz key is same. + */ + flow_hash = elem->flow_idx; + hashed_flow_idx = flow_hash & fisa_hdl->hash_mask; + max_skid_length = fisa_hdl->max_skid_length; + rx_flow_tuple_info = &elem->flow_tuple_info; + reo_dest_indication = elem->reo_dest_indication; + + dp_fisa_debug("flow_hash 0x%x hashed_flow_idx 0x%x", flow_hash, + hashed_flow_idx); + dp_fisa_debug("max_skid_length 0x%x", max_skid_length); + + do { + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[hashed_flow_idx]); + if (!sw_ft_entry->is_populated) { + /* Add SW FT entry */ + dp_rx_fisa_update_sw_ft_entry(sw_ft_entry, + flow_hash, elem->vdev, + fisa_hdl->dp_ctx, + hashed_flow_idx); + + /* Add HW FT entry */ + sw_ft_entry->cmem_offset = + dp_rx_fisa_setup_cmem_fse(fisa_hdl, + hashed_flow_idx, + rx_flow_tuple_info, + reo_dest_indication); + sw_ft_entry->is_populated = true; + sw_ft_entry->napi_id = elem->reo_id; + sw_ft_entry->reo_dest_indication = reo_dest_indication; + qdf_mem_copy(&sw_ft_entry->rx_flow_tuple_info, + rx_flow_tuple_info, + sizeof(struct cdp_rx_flow_tuple_info)); + + sw_ft_entry->flow_init_ts = qdf_get_log_timestamp(); + sw_ft_entry->is_flow_tcp = elem->is_tcp_flow; + sw_ft_entry->is_flow_udp = elem->is_udp_flow; + + sw_ft_entry->add_timestamp = qdf_get_log_timestamp(); + + is_fst_updated = true; + fisa_hdl->add_flow_count++; + break; + } + /* else */ + /* hash collision move to the next FT entry */ + dp_fisa_debug("Hash collision %d", + fisa_hdl->hash_collision_cnt); + fisa_hdl->hash_collision_cnt++; + + timestamp = dp_fisa_rx_get_hw_ft_timestamp(fisa_hdl, + hashed_flow_idx); + if (timestamp < lru_ft_entry_time) { + lru_ft_entry_time = timestamp; + lru_ft_entry_idx = hashed_flow_idx; + } + skid_count++; + hashed_flow_idx++; + hashed_flow_idx &= fisa_hdl->hash_mask; + } while (skid_count <= max_skid_length); + + /* + * if (skid_count > max_skid_length) + * Remove LRU flow from HW FT + * Remove LRU flow from SW FT + */ + if ((skid_count > max_skid_length) && + wlan_dp_cfg_is_rx_fisa_lru_del_enabled(dp_cfg)) { + dp_fisa_debug("Max skid length reached flow cannot be added, evict exiting flow"); + + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[lru_ft_entry_idx]); + sw_timestamp = qdf_get_log_timestamp(); + + if (qdf_log_timestamp_to_usecs(sw_timestamp - sw_ft_entry->add_timestamp) > + FISA_FT_ENTRY_AGING_US) { + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock); + dp_fisa_rx_delete_flow(fisa_hdl, elem, lru_ft_entry_idx); + qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock); + is_fst_updated = true; + } else + dp_fisa_debug("skip update due to aging not complete"); + } + + /** + * Send HTT cache invalidation command to firmware to + * reflect the flow update + */ + if (is_fst_updated && + fisa_hdl->fse_cache_flush_allow && + (qdf_atomic_inc_return(&fisa_hdl->fse_cache_flush_posted) == 1)) { + /* return 1 after increment implies FSE cache flush message + * already posted. so start restart the timer + */ + qdf_timer_start(&fisa_hdl->fse_cache_flush_timer, + FSE_CACHE_FLUSH_TIME_OUT); + } +} + +/** + * dp_fisa_rx_fst_update_work() - Work functions for FST updates + * @arg: argument passed to the work function + * + * Return: None + */ +void dp_fisa_rx_fst_update_work(void *arg) +{ + struct dp_fisa_rx_fst_update_elem *elem; + struct dp_rx_fst *fisa_hdl = arg; + qdf_list_node_t *node; + hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc; + struct dp_vdev *vdev; + + if (qdf_atomic_read(&fisa_hdl->pm_suspended)) { + dp_err_rl("WQ triggered during suspend stage, deferred update"); + DP_STATS_INC(fisa_hdl, update_deferred, 1); + return; + } + + if (hif_force_wake_request(((struct hal_soc *)hal_soc_hdl)->hif_handle)) { + dp_err("Wake up request failed"); + qdf_check_state_before_panic(__func__, __LINE__); + return; + } + + qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock); + while (qdf_list_peek_front(&fisa_hdl->fst_update_list, &node) == + QDF_STATUS_SUCCESS) { + elem = (struct dp_fisa_rx_fst_update_elem *)node; + vdev = dp_vdev_get_ref_by_id(fisa_hdl->soc_hdl, + elem->vdev_id, + DP_MOD_ID_RX); + /* + * Update fst only if current dp_vdev fetched by vdev_id is + * still valid and match with the original dp_vdev when fst + * node is queued. + */ + if (vdev) { + if (vdev == elem->vdev) + dp_fisa_rx_fst_update(fisa_hdl, elem); + + dp_vdev_unref_delete(fisa_hdl->soc_hdl, vdev, + DP_MOD_ID_RX); + } + qdf_list_remove_front(&fisa_hdl->fst_update_list, &node); + qdf_mem_free(elem); + } + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock); + + if (hif_force_wake_release(((struct hal_soc *)hal_soc_hdl)->hif_handle)) { + dp_err("Wake up release failed"); + qdf_check_state_before_panic(__func__, __LINE__); + return; + } +} + +/** + * dp_fisa_rx_is_fst_work_queued() - Check if work is already queued for + * the flow + * @fisa_hdl: handle to FISA context + * @flow_idx: Flow index + * + * Return: True/False + */ +static inline bool +dp_fisa_rx_is_fst_work_queued(struct dp_rx_fst *fisa_hdl, uint32_t flow_idx) +{ + struct dp_fisa_rx_fst_update_elem *elem; + qdf_list_node_t *cur_node, *next_node; + QDF_STATUS status; + + status = qdf_list_peek_front(&fisa_hdl->fst_update_list, &cur_node); + if (status == QDF_STATUS_E_EMPTY) + return false; + + do { + elem = (struct dp_fisa_rx_fst_update_elem *)cur_node; + if (elem->flow_idx == flow_idx) + return true; + + status = qdf_list_peek_next(&fisa_hdl->fst_update_list, + cur_node, &next_node); + cur_node = next_node; + } while (status == QDF_STATUS_SUCCESS); + + return false; +} + +/** + * dp_fisa_rx_queue_fst_update_work() - Queue FST update work + * @fisa_hdl: Handle to FISA context + * @flow_idx: Flow index + * @nbuf: Received RX packet + * @vdev: DP vdev handle + * + * Return: None + */ +static void * +dp_fisa_rx_queue_fst_update_work(struct dp_rx_fst *fisa_hdl, uint32_t flow_idx, + qdf_nbuf_t nbuf, struct dp_vdev *vdev) +{ + hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc; + struct cdp_rx_flow_tuple_info flow_tuple_info; + uint8_t *rx_tlv_hdr = qdf_nbuf_data(nbuf); + struct dp_fisa_rx_fst_update_elem *elem; + struct dp_fisa_rx_sw_ft *sw_ft_entry; + uint32_t hashed_flow_idx; + uint32_t reo_dest_indication; + bool found; + struct hal_proto_params proto_params; + + if (hal_rx_get_proto_params(fisa_hdl->dp_ctx->hal_soc, rx_tlv_hdr, + &proto_params)) + return NULL; + + if (proto_params.ipv6_proto || + !(proto_params.tcp_proto || proto_params.udp_proto)) { + dp_fisa_debug("Not UDP or TCP IPV4 flow"); + return NULL; + } + + hal_rx_msdu_get_reo_destination_indication(hal_soc_hdl, rx_tlv_hdr, + &reo_dest_indication); + qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock); + found = dp_fisa_rx_is_fst_work_queued(fisa_hdl, flow_idx); + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock); + if (found) + return NULL; + + hashed_flow_idx = flow_idx & fisa_hdl->hash_mask; + sw_ft_entry = &(((struct dp_fisa_rx_sw_ft *) + fisa_hdl->base)[hashed_flow_idx]); + + wlan_dp_get_flow_tuple_from_nbuf(fisa_hdl->dp_ctx, &flow_tuple_info, + nbuf, rx_tlv_hdr); + if (flow_tuple_info.bypass_fisa) + return NULL; + + if (sw_ft_entry->is_populated && is_same_flow( + &sw_ft_entry->rx_flow_tuple_info, &flow_tuple_info)) + return sw_ft_entry; + + elem = qdf_mem_malloc(sizeof(*elem)); + if (!elem) { + dp_fisa_debug("failed to allocate memory for FST update"); + return NULL; + } + + qdf_mem_copy(&elem->flow_tuple_info, &flow_tuple_info, + sizeof(struct cdp_rx_flow_tuple_info)); + elem->flow_idx = flow_idx; + elem->is_tcp_flow = proto_params.tcp_proto; + elem->is_udp_flow = proto_params.udp_proto; + elem->reo_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); + elem->reo_dest_indication = reo_dest_indication; + elem->vdev = vdev; + elem->vdev_id = vdev->vdev_id; + + qdf_spin_lock_bh(&fisa_hdl->dp_rx_fst_lock); + qdf_list_insert_back(&fisa_hdl->fst_update_list, &elem->node); + qdf_spin_unlock_bh(&fisa_hdl->dp_rx_fst_lock); + + if (qdf_atomic_read(&fisa_hdl->pm_suspended)) { + fisa_hdl->fst_wq_defer = true; + dp_info("defer fst update task in WoW"); + } else { + qdf_queue_work(fisa_hdl->dp_ctx->qdf_dev, + fisa_hdl->fst_update_wq, + &fisa_hdl->fst_update_work); + } + + return NULL; +} + +/** + * dp_fisa_rx_get_sw_ft_entry() - Get SW FT entry for the flow + * @fisa_hdl: Handle to FISA context + * @nbuf: Received RX packet + * @flow_idx: Flow index + * @vdev: handle to DP vdev + * + * Return: SW FT entry + */ +static inline struct dp_fisa_rx_sw_ft * +dp_fisa_rx_get_sw_ft_entry(struct dp_rx_fst *fisa_hdl, qdf_nbuf_t nbuf, + uint32_t flow_idx, struct dp_vdev *vdev) +{ + hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc; + struct dp_fisa_rx_sw_ft *sw_ft_entry = NULL; + struct dp_fisa_rx_sw_ft *sw_ft_base; + uint32_t fse_metadata; + uint8_t *rx_tlv_hdr; + + sw_ft_base = (struct dp_fisa_rx_sw_ft *)fisa_hdl->base; + rx_tlv_hdr = qdf_nbuf_data(nbuf); + + if (qdf_unlikely(flow_idx >= fisa_hdl->max_entries)) { + dp_info("flow_idx is invalid 0x%x", flow_idx); + hal_rx_dump_pkt_tlvs(hal_soc_hdl, rx_tlv_hdr, + QDF_TRACE_LEVEL_INFO_HIGH); + DP_STATS_INC(fisa_hdl, invalid_flow_index, 1); + return NULL; + } + + sw_ft_entry = &sw_ft_base[flow_idx]; + if (!sw_ft_entry->is_populated) { + dp_info("Pkt rx for non configured flow idx 0x%x", flow_idx); + DP_STATS_INC(fisa_hdl, invalid_flow_index, 1); + return NULL; + } + + if (!fisa_hdl->flow_deletion_supported) { + sw_ft_entry->vdev = vdev; + sw_ft_entry->vdev_id = vdev->vdev_id; + sw_ft_entry->dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev); + return sw_ft_entry; + } + + /* When a flow is deleted, there could be some packets of that flow + * with valid flow_idx in the REO queue and arrive at a later time, + * compare the metadata for such packets before returning the SW FT + * entry to avoid packets getting aggregated with the wrong flow. + */ + fse_metadata = hal_rx_msdu_fse_metadata_get(hal_soc_hdl, rx_tlv_hdr); + if (fisa_hdl->del_flow_count && fse_metadata != sw_ft_entry->metadata) + return NULL; + + sw_ft_entry->vdev = vdev; + sw_ft_entry->vdev_id = vdev->vdev_id; + sw_ft_entry->dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev); + return sw_ft_entry; +} + +#ifdef DP_OFFLOAD_FRAME_WITH_SW_EXCEPTION +/* + * dp_rx_reo_dest_honor_check() - check if packet reo destination is changed + by FW offload and is valid + * @fisa_hdl: handle to FISA context + *@nbuf: RX packet nbuf + *@tlv_reo_dest_ind: reo_dest_ind fetched from rx_packet_tlv + * + * Return: QDF_STATUS_SUCCESS - reo dest not change/ not valid, others - yes. + */ +static inline QDF_STATUS +dp_rx_reo_dest_honor_check(struct dp_rx_fst *fisa_hdl, qdf_nbuf_t nbuf, + uint32_t tlv_reo_dest_ind) +{ + uint8_t sw_exception = + qdf_nbuf_get_rx_reo_dest_ind_or_sw_excpt(nbuf); + + if (fisa_hdl->rx_hash_enabled && + (tlv_reo_dest_ind < HAL_REO_DEST_IND_START_OFFSET)) + return QDF_STATUS_E_FAILURE; + /* + * If sw_exception bit is marked, then this data packet is + * re-injected by FW offload, reo destination will not honor + * the original FSE/hash selection, skip FISA. + */ + return sw_exception ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +dp_rx_reo_dest_honor_check(struct dp_rx_fst *fisa_hdl, qdf_nbuf_t nbuf, + uint32_t tlv_reo_dest_ind) +{ + uint8_t ring_reo_dest_ind = + qdf_nbuf_get_rx_reo_dest_ind_or_sw_excpt(nbuf); + /* + * Compare reo_destination_indication between reo ring descriptor + * and rx_pkt_tlvs, if they are different, then likely these kind + * of frames re-injected by FW or touched by other module already, + * skip FISA to avoid REO2SW ring mismatch issue for same flow. + */ + if (tlv_reo_dest_ind != ring_reo_dest_ind || + REO_DEST_IND_IPA_REROUTE == ring_reo_dest_ind || + (fisa_hdl->rx_hash_enabled && + (tlv_reo_dest_ind < HAL_REO_DEST_IND_START_OFFSET))) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * dp_rx_get_fisa_flow() - Get FT entry corresponding to incoming nbuf + * @fisa_hdl: handle to FISA context + * @vdev: handle to DP vdev + * @nbuf: incoming msdu + * + * Return: handle SW FT entry for nbuf flow + */ +static struct dp_fisa_rx_sw_ft * +dp_rx_get_fisa_flow(struct dp_rx_fst *fisa_hdl, struct dp_vdev *vdev, + qdf_nbuf_t nbuf) +{ + uint8_t *rx_tlv_hdr; + uint32_t flow_idx_hash; + uint32_t tlv_reo_dest_ind; + bool flow_invalid, flow_timeout, flow_idx_valid; + struct dp_fisa_rx_sw_ft *sw_ft_entry = NULL; + hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc; + QDF_STATUS status; + + if (QDF_NBUF_CB_RX_TCP_PROTO(nbuf)) + return sw_ft_entry; + + rx_tlv_hdr = qdf_nbuf_data(nbuf); + hal_rx_msdu_get_reo_destination_indication(hal_soc_hdl, rx_tlv_hdr, + &tlv_reo_dest_ind); + status = dp_rx_reo_dest_honor_check(fisa_hdl, nbuf, tlv_reo_dest_ind); + if (QDF_IS_STATUS_ERROR(status)) + return sw_ft_entry; + + hal_rx_msdu_get_flow_params(hal_soc_hdl, rx_tlv_hdr, &flow_invalid, + &flow_timeout, &flow_idx_hash); + + flow_idx_valid = is_flow_idx_valid(flow_invalid, flow_timeout); + if (flow_idx_valid) { + sw_ft_entry = dp_fisa_rx_get_sw_ft_entry(fisa_hdl, nbuf, + flow_idx_hash, vdev); + goto print_and_return; + } + + /* else new flow, add entry to FT */ + + if (fisa_hdl->fst_in_cmem) + return dp_fisa_rx_queue_fst_update_work(fisa_hdl, flow_idx_hash, + nbuf, vdev); + + sw_ft_entry = dp_rx_fisa_add_ft_entry(vdev, fisa_hdl, + nbuf, + rx_tlv_hdr, + flow_idx_hash, + tlv_reo_dest_ind); + +print_and_return: + dp_fisa_debug("nbuf %pK fl_idx 0x%x fl_inv %d fl_timeout %d flow_id_toeplitz %x reo_dest_ind 0x%x", + nbuf, flow_idx_hash, flow_invalid, flow_timeout, + sw_ft_entry ? sw_ft_entry->flow_id_toeplitz : 0, + tlv_reo_dest_ind); + + return sw_ft_entry; +} + +#ifdef NOT_YET +/** + * dp_rx_fisa_aggr_tcp() - Aggregate incoming to TCP nbuf + * @fisa_flow: Handle to SW flow entry, which holds the aggregated nbuf + * @nbuf: Incoming nbuf + * + * Return: FISA_AGGR_DONE on successful aggregation + */ +static enum fisa_aggr_ret +dp_rx_fisa_aggr_tcp(struct dp_fisa_rx_sw_ft *fisa_flow, qdf_nbuf_t nbuf) +{ + qdf_nbuf_t head_skb = fisa_flow->head_skb; + qdf_net_iphdr_t *iph; + uint32_t tcp_data_len; + + fisa_flow->bytes_aggregated += qdf_nbuf_len(nbuf); + if (!head_skb) { + /* First nbuf for the flow */ + dp_fisa_debug("first head skb"); + fisa_flow->head_skb = nbuf; + return FISA_AGGR_DONE; + } + + tcp_data_len = (qdf_ntohs(iph->ip_len) - sizeof(qdf_net_iphdr_t) - + sizeof(qdf_net_tcphdr_t)); + qdf_nbuf_pull_head(nbuf, (qdf_nbuf_len(nbuf) - tcp_data_len)); + + if (qdf_nbuf_get_ext_list(head_skb)) { + /* this is 3rd skb after head skb, 2nd skb */ + fisa_flow->last_skb->next = nbuf; + } else { + /* 1st skb after head skb */ + qdf_nbuf_append_ext_list(head_skb, nbuf, + fisa_flow->cumulative_ip_length); + qdf_nbuf_set_is_frag(head, 1); + } + + fisa_flow->last_skb = nbuf; + fisa_flow->aggr_count++; + + /* move it to while flushing the flow, that is update before flushing */ + return FISA_AGGR_DONE; +} +#else +static enum fisa_aggr_ret +dp_rx_fisa_aggr_tcp(struct dp_rx_fst *fisa_hdl, + struct dp_fisa_rx_sw_ft *fisa_flow, qdf_nbuf_t nbuf) +{ + return FISA_AGGR_DONE; +} +#endif + +/** + * get_transport_payload_offset() - Get offset to payload + * @fisa_hdl: Handle to FISA context + * @l3_hdr_offset: layer 3 header offset + * @l4_hdr_offset: layer 4 header offset + * + * Return: Offset value to transport payload + */ +static inline int get_transport_payload_offset(struct dp_rx_fst *fisa_hdl, + uint32_t l3_hdr_offset, + uint32_t l4_hdr_offset) +{ + /* ETHERNET_HDR_LEN + ip_hdr_len + UDP/TCP; */ + return (l3_hdr_offset + l4_hdr_offset + sizeof(qdf_net_udphdr_t)); +} + +/** + * get_transport_header_offset() - Get transport header offset + * @fisa_flow: Handle to FISA sw flow entry + * @l3_hdr_offset: layer 3 header offset + * @l4_hdr_offset: layer 4 header offset + * + * Return: Offset value to transport header + */ +static inline +int get_transport_header_offset(struct dp_fisa_rx_sw_ft *fisa_flow, + uint32_t l3_hdr_offset, + uint32_t l4_hdr_offset) + +{ + /* ETHERNET_HDR_LEN + ip_hdr_len */ + return (l3_hdr_offset + l4_hdr_offset); +} + +/** + * dp_rx_fisa_aggr_udp() - Aggregate incoming to UDP nbuf + * @fisa_hdl: Handle fisa context + * @fisa_flow: Handle to SW flow entry, which holds the aggregated nbuf + * @nbuf: Incoming nbuf + * + * Return: FISA_AGGR_DONE on successful aggregation + */ +static enum fisa_aggr_ret +dp_rx_fisa_aggr_udp(struct dp_rx_fst *fisa_hdl, + struct dp_fisa_rx_sw_ft *fisa_flow, qdf_nbuf_t nbuf) +{ + qdf_nbuf_t head_skb = fisa_flow->head_skb; + uint8_t *rx_tlv_hdr = qdf_nbuf_data(nbuf); + uint32_t l2_hdr_offset = + hal_rx_msdu_end_l3_hdr_padding_get(fisa_hdl->dp_ctx->hal_soc, + rx_tlv_hdr); + qdf_net_udphdr_t *udp_hdr; + uint32_t udp_len; + uint32_t transport_payload_offset; + uint32_t l3_hdr_offset, l4_hdr_offset; + + qdf_nbuf_pull_head(nbuf, fisa_hdl->rx_pkt_tlv_size + l2_hdr_offset); + + hal_rx_get_l3_l4_offsets(fisa_hdl->dp_ctx->hal_soc, rx_tlv_hdr, + &l3_hdr_offset, &l4_hdr_offset); + udp_hdr = (qdf_net_udphdr_t *)(qdf_nbuf_data(nbuf) + + get_transport_header_offset(fisa_flow, l3_hdr_offset, + l4_hdr_offset)); + + udp_len = qdf_ntohs(udp_hdr->udp_len); + + /** + * Incoming nbuf is of size greater than ongoing aggregation + * then flush the aggregate and start new aggregation for nbuf + */ + if (head_skb && + (udp_len > qdf_ntohs(fisa_flow->head_skb_udp_hdr->udp_len))) { + /* current msdu should not take into account for flushing */ + fisa_flow->adjusted_cumulative_ip_length -= + (udp_len - sizeof(qdf_net_udphdr_t)); + fisa_flow->cur_aggr--; + dp_rx_fisa_flush_flow_wrap(fisa_flow); + /* napi_flush_cumulative_ip_length not include current msdu */ + fisa_flow->napi_flush_cumulative_ip_length -= udp_len; + head_skb = NULL; + } + + if (!head_skb) { + dp_fisa_debug("first head skb nbuf %pK", nbuf); + /* First nbuf for the flow */ + fisa_flow->head_skb = nbuf; + fisa_flow->head_skb_udp_hdr = udp_hdr; + fisa_flow->cur_aggr_gso_size = udp_len - + sizeof(qdf_net_udphdr_t); + fisa_flow->adjusted_cumulative_ip_length = udp_len; + fisa_flow->head_skb_ip_hdr_offset = l3_hdr_offset; + fisa_flow->head_skb_l4_hdr_offset = l4_hdr_offset; + + fisa_flow->frags_cumulative_len = 0; + + return FISA_AGGR_DONE; + } + + transport_payload_offset = + get_transport_payload_offset(fisa_hdl, l3_hdr_offset, + l4_hdr_offset); + + hex_dump_skb_data(nbuf, false); + qdf_nbuf_pull_head(nbuf, transport_payload_offset); + hex_dump_skb_data(nbuf, false); + + fisa_flow->bytes_aggregated += qdf_nbuf_len(nbuf); + + fisa_flow->frags_cumulative_len += (udp_len - + sizeof(qdf_net_udphdr_t)); + + if (qdf_nbuf_get_ext_list(head_skb)) { + /* + * This is 3rd skb for flow. + * After head skb, 2nd skb in fraglist + */ + if (qdf_likely(fisa_flow->last_skb)) { + qdf_nbuf_set_next(fisa_flow->last_skb, nbuf); + } else { + qdf_nbuf_free(nbuf); + return FISA_AGGR_DONE; + } + } else { + /* 1st skb after head skb + * implement qdf wrapper set_ext_list + */ + qdf_nbuf_append_ext_list(head_skb, nbuf, 0); + qdf_nbuf_set_is_frag(nbuf, 1); + } + + fisa_flow->last_skb = nbuf; + fisa_flow->aggr_count++; + + dp_fisa_debug("Stiched head skb fisa_flow %pK", fisa_flow); + hex_dump_skb_data(fisa_flow->head_skb, false); + + /** + * Incoming nbuf is of size less than ongoing aggregation + * then flush the aggregate + */ + if (udp_len < qdf_ntohs(fisa_flow->head_skb_udp_hdr->udp_len)) + dp_rx_fisa_flush_flow_wrap(fisa_flow); + + return FISA_AGGR_DONE; +} + +/** + * dp_fisa_rx_linear_skb() - Linearize fraglist skb to linear skb + * @vdev: handle to DP vdev + * @head_skb: non linear skb + * @size: Total length of non linear stiched skb + * + * Return: Linearized skb pointer + */ +static qdf_nbuf_t dp_fisa_rx_linear_skb(struct dp_vdev *vdev, + qdf_nbuf_t head_skb, uint32_t size) +{ + return NULL; +} + +#ifdef WLAN_FEATURE_11BE +static inline struct dp_vdev * +dp_fisa_rx_get_flow_flush_vdev_ref(ol_txrx_soc_handle cdp_soc, + struct dp_fisa_rx_sw_ft *fisa_flow) +{ + struct dp_vdev *fisa_flow_head_skb_vdev; + struct dp_vdev *fisa_flow_vdev; + uint8_t vdev_id; + + vdev_id = QDF_NBUF_CB_RX_VDEV_ID(fisa_flow->head_skb); + +get_new_vdev_ref: + fisa_flow_head_skb_vdev = dp_vdev_get_ref_by_id( + cdp_soc_t_to_dp_soc(cdp_soc), + vdev_id, DP_MOD_ID_RX); + if (qdf_unlikely(!fisa_flow_head_skb_vdev)) { + qdf_nbuf_free(fisa_flow->head_skb); + goto out; + } + + if (qdf_unlikely(fisa_flow_head_skb_vdev != fisa_flow->vdev)) { + if (qdf_unlikely(fisa_flow_head_skb_vdev->vdev_id == + fisa_flow->vdev_id)) + goto fisa_flow_vdev_fail; + + fisa_flow_vdev = dp_vdev_get_ref_by_id( + cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow->vdev_id, + DP_MOD_ID_RX); + if (qdf_unlikely(!fisa_flow_vdev)) + goto fisa_flow_vdev_fail; + + if (qdf_unlikely(fisa_flow_vdev != fisa_flow->vdev)) + goto fisa_flow_vdev_mismatch; + + /* + * vdev_id may mismatch in case of MLO link switch. + * Check if the vdevs belong to same MLD, + * if yes, then submit the flow else drop the packets. + */ + if (qdf_unlikely(qdf_mem_cmp( + fisa_flow_vdev->mld_mac_addr.raw, + fisa_flow_head_skb_vdev->mld_mac_addr.raw, + QDF_MAC_ADDR_SIZE) != 0)) { + goto fisa_flow_vdev_mismatch; + } else { + fisa_flow->same_mld_vdev_mismatch++; + /* Continue with aggregation */ + + /* Release ref to old vdev */ + dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow_head_skb_vdev, + DP_MOD_ID_RX); + + /* + * Update vdev_id and let it loop to find this + * vdev by ref. + */ + vdev_id = fisa_flow_vdev->vdev_id; + dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow_vdev, + DP_MOD_ID_RX); + goto get_new_vdev_ref; + } + } else { + goto out; + } + +fisa_flow_vdev_mismatch: + dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow_vdev, + DP_MOD_ID_RX); + +fisa_flow_vdev_fail: + qdf_nbuf_free(fisa_flow->head_skb); + dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow_head_skb_vdev, + DP_MOD_ID_RX); + fisa_flow_head_skb_vdev = NULL; +out: + return fisa_flow_head_skb_vdev; +} +#else +static inline struct dp_vdev * +dp_fisa_rx_get_flow_flush_vdev_ref(ol_txrx_soc_handle cdp_soc, + struct dp_fisa_rx_sw_ft *fisa_flow) +{ + struct dp_vdev *fisa_flow_head_skb_vdev; + + fisa_flow_head_skb_vdev = dp_vdev_get_ref_by_id( + cdp_soc_t_to_dp_soc(cdp_soc), + QDF_NBUF_CB_RX_VDEV_ID(fisa_flow->head_skb), + DP_MOD_ID_RX); + if (qdf_unlikely(!fisa_flow_head_skb_vdev || + (fisa_flow_head_skb_vdev != fisa_flow->vdev))) { + qdf_nbuf_free(fisa_flow->head_skb); + goto out; + } + + return fisa_flow_head_skb_vdev; + +out: + if (fisa_flow_head_skb_vdev) + dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow_head_skb_vdev, + DP_MOD_ID_RX); + return NULL; +} +#endif + +/** + * dp_rx_fisa_flush_udp_flow() - Flush all aggregated nbuf of the udp flow + * @vdev: handle to dp_vdev + * @fisa_flow: Flow for which aggregates to be flushed + * + * Return: None + */ +static void +dp_rx_fisa_flush_udp_flow(struct dp_vdev *vdev, + struct dp_fisa_rx_sw_ft *fisa_flow) +{ + qdf_nbuf_t head_skb = fisa_flow->head_skb; + qdf_net_iphdr_t *head_skb_iph; + qdf_net_udphdr_t *head_skb_udp_hdr; + qdf_nbuf_shared_info_t shinfo; + qdf_nbuf_t linear_skb; + struct dp_vdev *fisa_flow_vdev; + ol_txrx_soc_handle cdp_soc = fisa_flow->dp_ctx->cdp_soc; + + dp_fisa_debug("head_skb %pK", head_skb); + dp_fisa_debug("cumulative ip length %d", + fisa_flow->adjusted_cumulative_ip_length); + if (!head_skb) { + dp_fisa_debug("Already flushed"); + return; + } + + qdf_nbuf_set_hash(head_skb, QDF_NBUF_CB_RX_FLOW_ID(head_skb)); + head_skb->sw_hash = 1; + if (qdf_nbuf_get_ext_list(head_skb)) { + __sum16 pseudo; + + shinfo = qdf_nbuf_get_shinfo(head_skb); + /* Update the head_skb before flush */ + dp_fisa_debug("cumu ip length host order 0x%x", + fisa_flow->adjusted_cumulative_ip_length); + head_skb_iph = (qdf_net_iphdr_t *)(qdf_nbuf_data(head_skb) + + fisa_flow->head_skb_ip_hdr_offset); + dp_fisa_debug("iph ptr %pK", head_skb_iph); + + head_skb_udp_hdr = fisa_flow->head_skb_udp_hdr; + + dp_fisa_debug("udph ptr %pK", head_skb_udp_hdr); + + dp_fisa_debug("ip_len 0x%x", qdf_ntohs(head_skb_iph->ip_len)); + + /* data_len is total length of non head_skb, + * cumulative ip length is including head_skb ip length also + */ + qdf_nbuf_set_data_len(head_skb, + ((fisa_flow->adjusted_cumulative_ip_length) - + qdf_ntohs(head_skb_udp_hdr->udp_len))); + + qdf_nbuf_set_len(head_skb, (qdf_nbuf_len(head_skb) + + qdf_nbuf_get_only_data_len(head_skb))); + + head_skb_iph->ip_len = + qdf_htons((fisa_flow->adjusted_cumulative_ip_length) + + /* IP hdr len */ + fisa_flow->head_skb_l4_hdr_offset); + pseudo = ~qdf_csum_tcpudp_magic(head_skb_iph->ip_saddr, + head_skb_iph->ip_daddr, + fisa_flow->adjusted_cumulative_ip_length, + head_skb_iph->ip_proto, 0); + + head_skb_iph->ip_check = 0; + head_skb_iph->ip_check = qdf_ip_fast_csum(head_skb_iph, + head_skb_iph->ip_hl); + + head_skb_udp_hdr->udp_len = + qdf_htons(qdf_ntohs(head_skb_iph->ip_len) - + fisa_flow->head_skb_l4_hdr_offset); + head_skb_udp_hdr->udp_cksum = pseudo; + qdf_nbuf_set_csum_start(head_skb, ((u8 *)head_skb_udp_hdr - + qdf_nbuf_head(head_skb))); + qdf_nbuf_set_csum_offset(head_skb, + offsetof(qdf_net_udphdr_t, udp_cksum)); + + qdf_nbuf_set_gso_size(head_skb, fisa_flow->cur_aggr_gso_size); + dp_fisa_debug("gso_size %d, udp_len %d\n", + qdf_nbuf_get_gso_size(head_skb), + qdf_ntohs(head_skb_udp_hdr->udp_len)); + qdf_nbuf_set_gso_segs(head_skb, fisa_flow->cur_aggr); + qdf_nbuf_set_gso_type_udp_l4(head_skb); + qdf_nbuf_set_ip_summed_partial(head_skb); + } + + qdf_nbuf_set_next(fisa_flow->head_skb, NULL); + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(fisa_flow->head_skb) = 1; + if (fisa_flow->last_skb) + qdf_nbuf_set_next(fisa_flow->last_skb, NULL); + + hex_dump_skb_data(fisa_flow->head_skb, false); + + fisa_flow_vdev = dp_fisa_rx_get_flow_flush_vdev_ref(cdp_soc, fisa_flow); + if (!fisa_flow_vdev) + goto vdev_ref_get_fail; + + dp_fisa_debug("fisa_flow->curr_aggr %d", fisa_flow->cur_aggr); + linear_skb = dp_fisa_rx_linear_skb(vdev, fisa_flow->head_skb, 24000); + if (linear_skb) { + if (!vdev->osif_rx || QDF_STATUS_SUCCESS != + vdev->osif_rx(vdev->osif_vdev, linear_skb)) + qdf_nbuf_free(linear_skb); + /* Free non linear skb */ + qdf_nbuf_free(fisa_flow->head_skb); + } else { + /* + * Sanity check head data_len should be equal to sum of + * all fragments length + */ + if (qdf_unlikely(fisa_flow->frags_cumulative_len != + qdf_nbuf_get_only_data_len(fisa_flow->head_skb))) { + qdf_assert(0); + /* Drop the aggregate */ + qdf_nbuf_free(fisa_flow->head_skb); + goto out; + } + + if (!vdev->osif_rx || QDF_STATUS_SUCCESS != + vdev->osif_rx(vdev->osif_vdev, fisa_flow->head_skb)) + qdf_nbuf_free(fisa_flow->head_skb); + } + +out: + if (fisa_flow_vdev) + dp_vdev_unref_delete(cdp_soc_t_to_dp_soc(cdp_soc), + fisa_flow_vdev, + DP_MOD_ID_RX); + +vdev_ref_get_fail: + fisa_flow->head_skb = NULL; + fisa_flow->last_skb = NULL; + + fisa_flow->flush_count++; +} + +/** + * dp_rx_fisa_flush_tcp_flow() - Flush all aggregated nbuf of the TCP flow + * @vdev: handle to dp_vdev + * @fisa_flow: Flow for which aggregates to be flushed + * + * Return: None + */ +static void +dp_rx_fisa_flush_tcp_flow(struct dp_vdev *vdev, + struct dp_fisa_rx_sw_ft *fisa_flow) +{ + qdf_nbuf_t head_skb = fisa_flow->head_skb; + qdf_net_iphdr_t *head_skb_iph; + qdf_nbuf_shared_info_t shinfo; + + if (!head_skb) { + dp_fisa_debug("Already flushed"); + return; + } + + shinfo = qdf_nbuf_get_shinfo(head_skb); + + /* Update the head_skb before flush */ + head_skb->hash = fisa_flow->flow_hash; + head_skb->sw_hash = 1; + shinfo->gso_type = SKB_GSO_UDP_L4; + + head_skb_iph = (qdf_net_iphdr_t *)(qdf_nbuf_data(head_skb) + + fisa_flow->head_skb_ip_hdr_offset); + + head_skb_iph->ip_len = fisa_flow->adjusted_cumulative_ip_length; + head_skb_iph->ip_check = ip_fast_csum((u8 *)head_skb_iph, + head_skb_iph->ip_hl); + + qdf_nbuf_set_next(fisa_flow->head_skb, NULL); + if (fisa_flow->last_skb) + qdf_nbuf_set_next(fisa_flow->last_skb, NULL); + vdev->osif_rx(vdev->osif_vdev, fisa_flow->head_skb); + + fisa_flow->head_skb = NULL; + + fisa_flow->flush_count++; +} + +/** + * dp_rx_fisa_flush_flow() - Flush all aggregated nbuf of the flow + * @vdev: handle to dp_vdev + * @flow: Flow for which aggregates to be flushed + * + * Return: None + */ +static void dp_rx_fisa_flush_flow(struct dp_vdev *vdev, + struct dp_fisa_rx_sw_ft *flow) +{ + dp_fisa_debug("dp_rx_fisa_flush_flow"); + + if (flow->is_flow_udp) + dp_rx_fisa_flush_udp_flow(vdev, flow); + else + dp_rx_fisa_flush_tcp_flow(vdev, flow); +} + +/** + * dp_fisa_aggregation_should_stop - check if fisa aggregate should stop + * @fisa_flow: Handle SW flow entry + * @hal_aggr_count: current aggregate count from RX PKT TLV + * @hal_cumulative_ip_len: current cumulative ip length from RX PKT TLV + * @rx_tlv_hdr: current msdu RX PKT TLV + * + * Return: true - current flow aggregation should stop, + * false - continue to aggregate. + */ +static bool dp_fisa_aggregation_should_stop( + struct dp_fisa_rx_sw_ft *fisa_flow, + uint32_t hal_aggr_count, + uint16_t hal_cumulative_ip_len, + uint8_t *rx_tlv_hdr) +{ + uint32_t msdu_len = + hal_rx_msdu_start_msdu_len_get(fisa_flow->dp_ctx->hal_soc, + rx_tlv_hdr); + uint32_t l3_hdr_offset, l4_hdr_offset, l2_l3_hdr_len; + uint32_t cumulative_ip_len_delta = hal_cumulative_ip_len - + fisa_flow->hal_cumultive_ip_len; + uint32_t ip_csum_err = 0; + uint32_t tcp_udp_csum_err = 0; + + hal_rx_tlv_csum_err_get(fisa_flow->dp_ctx->hal_soc, rx_tlv_hdr, + &ip_csum_err, &tcp_udp_csum_err); + + hal_rx_get_l3_l4_offsets(fisa_flow->dp_ctx->hal_soc, rx_tlv_hdr, + &l3_hdr_offset, &l4_hdr_offset); + + l2_l3_hdr_len = l3_hdr_offset + l4_hdr_offset; + + /** + * If l3/l4 checksum validation failed for MSDU, then data + * is not trust worthy to build aggregated skb, so do not + * allow for aggregation. And also in aggregated case it + * is job of driver to make sure checksum is valid before + * computing partial checksum for final aggregated skb. + * + * kernel network panic if UDP data length < 12 bytes get aggregated, + * no solid conclusion currently, as a SW WAR, only allow UDP + * aggregation if UDP data length >= 16 bytes. + * + * current cumulative ip length should > last cumulative_ip_len + * and <= last cumulative_ip_len + 1478, also current aggregate + * count should be equal to last aggregate count + 1, + * cumulative_ip_len delta should be equal to current msdu length + * - l4 header offset, + * otherwise, current fisa flow aggregation should be stopped. + */ + if (fisa_flow->do_not_aggregate || + (ip_csum_err || tcp_udp_csum_err) || + msdu_len < (l2_l3_hdr_len + FISA_MIN_L4_AND_DATA_LEN) || + hal_cumulative_ip_len <= fisa_flow->hal_cumultive_ip_len || + cumulative_ip_len_delta > FISA_MAX_SINGLE_CUMULATIVE_IP_LEN || + (fisa_flow->last_hal_aggr_count + 1) != hal_aggr_count || + cumulative_ip_len_delta != (msdu_len - l2_l3_hdr_len)) + return true; + + return false; +} + +/** + * dp_add_nbuf_to_fisa_flow() - Aggregate incoming nbuf + * @fisa_hdl: handle to fisa context + * @vdev: handle DP vdev + * @nbuf: Incoming nbuf + * @fisa_flow: Handle SW flow entry + * + * Return: Success on aggregation + */ +static int dp_add_nbuf_to_fisa_flow(struct dp_rx_fst *fisa_hdl, + struct dp_vdev *vdev, qdf_nbuf_t nbuf, + struct dp_fisa_rx_sw_ft *fisa_flow) +{ + bool flow_aggr_cont; + uint8_t *rx_tlv_hdr = qdf_nbuf_data(nbuf); + uint16_t hal_cumulative_ip_len; + hal_soc_handle_t hal_soc_hdl = fisa_hdl->dp_ctx->hal_soc; + uint32_t hal_aggr_count; + uint8_t napi_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); + uint32_t fse_metadata; + bool cce_match; + + dump_tlvs(hal_soc_hdl, rx_tlv_hdr, QDF_TRACE_LEVEL_INFO_HIGH); + dp_fisa_debug("nbuf: %pK nbuf->next:%pK nbuf->data:%pK len %d data_len %d", + nbuf, qdf_nbuf_next(nbuf), qdf_nbuf_data(nbuf), + qdf_nbuf_len(nbuf), qdf_nbuf_get_only_data_len(nbuf)); + + /* Packets of the flow are arriving on a different REO than + * the one configured. + */ + if (qdf_unlikely(fisa_flow->napi_id != napi_id)) { + fse_metadata = + hal_rx_msdu_fse_metadata_get(hal_soc_hdl, rx_tlv_hdr); + cce_match = hal_rx_msdu_cce_match_get(hal_soc_hdl, rx_tlv_hdr); + /* + * For two cases the fse_metadata will not match the metadata + * from the fisa_flow_table entry + * 1) Flow has been evicted (lru deletion), and this packet is + * one of the few packets pending in the rx ring from the prev + * flow + * 2) HW flow table match fails for some packets in the + * currently active flow. + */ + if (cce_match) { + DP_STATS_INC(fisa_hdl, reo_mismatch.allow_cce_match, + 1); + return FISA_AGGR_NOT_ELIGIBLE; + } + + if (fse_metadata != fisa_flow->metadata) { + DP_STATS_INC(fisa_hdl, + reo_mismatch.allow_fse_metdata_mismatch, + 1); + return FISA_AGGR_NOT_ELIGIBLE; + } + + dp_err("REO id mismatch flow: %pK napi_id: %u nbuf: %pK reo_id: %u", + fisa_flow, fisa_flow->napi_id, nbuf, napi_id); + DP_STATS_INC(fisa_hdl, reo_mismatch.allow_non_aggr, 1); + QDF_BUG(0); + return FISA_AGGR_NOT_ELIGIBLE; + } + + hal_cumulative_ip_len = hal_rx_get_fisa_cumulative_ip_length( + hal_soc_hdl, + rx_tlv_hdr); + flow_aggr_cont = hal_rx_get_fisa_flow_agg_continuation(hal_soc_hdl, + rx_tlv_hdr); + hal_aggr_count = hal_rx_get_fisa_flow_agg_count(hal_soc_hdl, + rx_tlv_hdr); + + if (!flow_aggr_cont) { + /* Start of new aggregation for the flow + * Flush previous aggregates for this flow + */ + dp_fisa_debug("no fgc nbuf %pK, flush %pK napi %d", nbuf, + fisa_flow, QDF_NBUF_CB_RX_CTX_ID(nbuf)); + dp_rx_fisa_flush_flow(vdev, fisa_flow); + /* Clear of previoud context values */ + fisa_flow->napi_flush_cumulative_l4_checksum = 0; + fisa_flow->napi_flush_cumulative_ip_length = 0; + fisa_flow->cur_aggr = 0; + fisa_flow->do_not_aggregate = false; + fisa_flow->hal_cumultive_ip_len = 0; + fisa_flow->last_hal_aggr_count = 0; + /* Check fisa related HW TLV correct or not */ + if (qdf_unlikely(dp_fisa_aggregation_should_stop( + fisa_flow, + hal_aggr_count, + hal_cumulative_ip_len, + rx_tlv_hdr))) { + qdf_assert(0); + fisa_flow->do_not_aggregate = true; + /* + * do not aggregate until next new aggregation + * start. + */ + goto invalid_fisa_assist; + } + } else if (qdf_unlikely(dp_fisa_aggregation_should_stop( + fisa_flow, + hal_aggr_count, + hal_cumulative_ip_len, + rx_tlv_hdr))) { + qdf_assert(0); + /* Either HW cumulative ip length is wrong, or packet is missed + * Flush the flow and do not aggregate until next start new + * aggreagtion + */ + dp_rx_fisa_flush_flow(vdev, fisa_flow); + fisa_flow->do_not_aggregate = true; + fisa_flow->cur_aggr = 0; + fisa_flow->napi_flush_cumulative_ip_length = 0; + goto invalid_fisa_assist; + } else { + /* takecare to skip the udp hdr len for sub sequent cumulative + * length + */ + fisa_flow->cur_aggr++; + } + + dp_fisa_debug("nbuf %pK cumulat_ip_length %d flow %pK fl aggr cont %d", + nbuf, hal_cumulative_ip_len, fisa_flow, flow_aggr_cont); + + fisa_flow->aggr_count++; + fisa_flow->last_hal_aggr_count = hal_aggr_count; + fisa_flow->hal_cumultive_ip_len = hal_cumulative_ip_len; + + if (!fisa_flow->head_skb) { + /* This is start of aggregation for the flow, save the offsets*/ + fisa_flow->napi_flush_cumulative_l4_checksum = 0; + fisa_flow->cur_aggr = 0; + } + + fisa_flow->adjusted_cumulative_ip_length = + /* cumulative ip len has all the aggr msdu udp header len + * Aggr UDP msdu has one UDP header len + */ + (hal_cumulative_ip_len - + (fisa_flow->cur_aggr * sizeof(qdf_net_udphdr_t))) - + fisa_flow->napi_flush_cumulative_ip_length; + + /** + * cur_aggr does not include the head_skb, so compare with + * FISA_FLOW_MAX_AGGR_COUNT - 1. + */ + if (fisa_flow->cur_aggr > (FISA_FLOW_MAX_AGGR_COUNT - 1)) + dp_err("HAL cumulative_ip_length %d", hal_cumulative_ip_len); + + dp_fisa_debug("hal cum_len 0x%x - napI_cumu_len 0x%x = flow_cum_len 0x%x cur_aggr %d", + hal_cumulative_ip_len, + fisa_flow->napi_flush_cumulative_ip_length, + fisa_flow->adjusted_cumulative_ip_length, + fisa_flow->cur_aggr); + + if (fisa_flow->adjusted_cumulative_ip_length > + FISA_FLOW_MAX_CUMULATIVE_IP_LEN) { + dp_err("fisa_flow %pK nbuf %pK", fisa_flow, nbuf); + dp_err("fisa_flow->adjusted_cumulative_ip_length %d", + fisa_flow->adjusted_cumulative_ip_length); + dp_err("HAL cumulative_ip_length %d", hal_cumulative_ip_len); + dp_err("napi_flush_cumulative_ip_length %d", + fisa_flow->napi_flush_cumulative_ip_length); + qdf_assert(0); + } + + dp_fisa_record_pkt(fisa_flow, nbuf, rx_tlv_hdr, + fisa_hdl->rx_pkt_tlv_size); + + if (fisa_flow->is_flow_udp) { + dp_rx_fisa_aggr_udp(fisa_hdl, fisa_flow, nbuf); + } else if (fisa_flow->is_flow_tcp) { + qdf_assert(0); + dp_rx_fisa_aggr_tcp(fisa_hdl, fisa_flow, nbuf); + } + + fisa_flow->last_accessed_ts = qdf_get_log_timestamp(); + + return FISA_AGGR_DONE; + +invalid_fisa_assist: + /* Not eligible aggregation deliver frame without FISA */ + return FISA_AGGR_NOT_ELIGIBLE; +} + +/** + * dp_is_nbuf_bypass_fisa() - FISA bypass check for RX frame + * @nbuf: RX nbuf pointer + * + * Return: true if FISA should be bypassed else false + */ +static bool dp_is_nbuf_bypass_fisa(qdf_nbuf_t nbuf) +{ + /* RX frame from non-regular path or DHCP packet */ + if (QDF_NBUF_CB_RX_TCP_PROTO(nbuf) || + qdf_nbuf_is_exc_frame(nbuf) || + qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) || + qdf_nbuf_is_da_mcbc(nbuf)) + return true; + + return false; +} + +/** + * dp_rx_fisa_flush_by_intf_ctx_id() - Flush fisa aggregates per dp_interface + * and rx context id + * @dp_intf: DP interface handle + * @rx_ctx_id: Rx context id + * + * Return: Success on flushing the flows for the vdev and rx ctx id + */ +static +QDF_STATUS dp_rx_fisa_flush_by_intf_ctx_id(struct wlan_dp_intf *dp_intf, + uint8_t rx_ctx_id) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + struct dp_rx_fst *fisa_hdl = dp_ctx->rx_fst; + struct dp_fisa_rx_sw_ft *sw_ft_entry = + (struct dp_fisa_rx_sw_ft *)fisa_hdl->base; + int ft_size = fisa_hdl->max_entries; + int i; + + dp_rx_fisa_acquire_ft_lock(fisa_hdl, rx_ctx_id); + for (i = 0; i < ft_size; i++) { + if (sw_ft_entry[i].is_populated && + dp_intf == sw_ft_entry[i].dp_intf && + sw_ft_entry[i].napi_id == rx_ctx_id) { + dp_fisa_debug("flushing %d %pk dp_intf %pK napi id:%d", + i, &sw_ft_entry[i], dp_intf, rx_ctx_id); + dp_rx_fisa_flush_flow_wrap(&sw_ft_entry[i]); + } + } + dp_rx_fisa_release_ft_lock(fisa_hdl, rx_ctx_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_fisa_disallowed_for_vdev() - Check if fisa is allowed on vdev + * @soc: core txrx main context + * @vdev: Handle DP vdev + * @rx_ctx_id: Rx context id + * + * Return: true if fisa is disallowed for vdev else false + */ +static bool dp_fisa_disallowed_for_vdev(struct dp_soc *soc, + struct dp_vdev *vdev, + uint8_t rx_ctx_id) +{ + struct wlan_dp_intf *dp_intf; + + dp_intf = dp_fisa_rx_get_dp_intf_for_vdev(vdev); + if (!dp_intf->fisa_disallowed[rx_ctx_id]) { + if (dp_intf->fisa_force_flushed[rx_ctx_id]) + dp_intf->fisa_force_flushed[rx_ctx_id] = 0; + return false; + } + + if (!dp_intf->fisa_force_flushed[rx_ctx_id]) { + dp_rx_fisa_flush_by_intf_ctx_id(dp_intf, rx_ctx_id); + dp_intf->fisa_force_flushed[rx_ctx_id] = 1; + } + + return true; +} + +QDF_STATUS dp_fisa_rx(struct wlan_dp_psoc_context *dp_ctx, + struct dp_vdev *vdev, + qdf_nbuf_t nbuf_list) +{ + struct dp_soc *soc = cdp_soc_t_to_dp_soc(dp_ctx->cdp_soc); + struct dp_rx_fst *dp_fisa_rx_hdl = dp_ctx->rx_fst; + qdf_nbuf_t head_nbuf; + qdf_nbuf_t next_nbuf; + struct dp_fisa_rx_sw_ft *fisa_flow; + int fisa_ret; + uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(nbuf_list); + uint32_t tlv_reo_dest_ind; + uint8_t reo_id; + + head_nbuf = nbuf_list; + + while (head_nbuf) { + next_nbuf = head_nbuf->next; + qdf_nbuf_set_next(head_nbuf, NULL); + + /* bypass FISA check */ + if (dp_is_nbuf_bypass_fisa(head_nbuf)) + goto deliver_nbuf; + + if (dp_fisa_disallowed_for_vdev(soc, vdev, rx_ctx_id)) + goto deliver_nbuf; + + if (qdf_atomic_read(&dp_ctx->skip_fisa_param.skip_fisa)) { + if (!dp_ctx->skip_fisa_param.fisa_force_flush[rx_ctx_id]) { + dp_rx_fisa_flush_by_ctx_id(soc, rx_ctx_id); + dp_ctx->skip_fisa_param. + fisa_force_flush[rx_ctx_id] = 1; + } + goto deliver_nbuf; + } else if (dp_ctx->skip_fisa_param.fisa_force_flush[rx_ctx_id]) { + dp_ctx->skip_fisa_param.fisa_force_flush[rx_ctx_id] = 0; + } + + qdf_nbuf_push_head(head_nbuf, dp_fisa_rx_hdl->rx_pkt_tlv_size + + QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(head_nbuf)); + + hal_rx_msdu_get_reo_destination_indication(dp_ctx->hal_soc, + (uint8_t *)qdf_nbuf_data(head_nbuf), + &tlv_reo_dest_ind); + + /* Skip FISA aggregation and drop the frame if RDI is REO2TCL. */ + if (qdf_unlikely(tlv_reo_dest_ind == REO_REMAP_TCL)) { + qdf_nbuf_free(head_nbuf); + head_nbuf = next_nbuf; + DP_STATS_INC(dp_fisa_rx_hdl, incorrect_rdi, 1); + continue; + } + + reo_id = QDF_NBUF_CB_RX_CTX_ID(head_nbuf); + dp_rx_fisa_acquire_ft_lock(dp_fisa_rx_hdl, reo_id); + + /* Add new flow if the there is no ongoing flow */ + fisa_flow = dp_rx_get_fisa_flow(dp_fisa_rx_hdl, vdev, + head_nbuf); + + /* Do not FISA aggregate IPSec packets */ + if (fisa_flow && + fisa_flow->rx_flow_tuple_info.is_exception) { + dp_rx_fisa_release_ft_lock(dp_fisa_rx_hdl, reo_id); + goto pull_nbuf; + } + + /* Fragmented skb do not handle via fisa + * get that flow and deliver that flow to rx_thread + */ + if (qdf_unlikely(qdf_nbuf_get_ext_list(head_nbuf))) { + dp_fisa_debug("Fragmented skb, will not be FISAed"); + if (fisa_flow) + dp_rx_fisa_flush_flow(vdev, fisa_flow); + + dp_rx_fisa_release_ft_lock(dp_fisa_rx_hdl, reo_id); + goto pull_nbuf; + } + + if (!fisa_flow) { + dp_rx_fisa_release_ft_lock(dp_fisa_rx_hdl, reo_id); + goto pull_nbuf; + } + + fisa_ret = dp_add_nbuf_to_fisa_flow(dp_fisa_rx_hdl, vdev, + head_nbuf, fisa_flow); + + dp_rx_fisa_release_ft_lock(dp_fisa_rx_hdl, reo_id); + + if (fisa_ret == FISA_AGGR_DONE) + goto next_msdu; + +pull_nbuf: + wlan_dp_nbuf_skip_rx_pkt_tlv(dp_ctx, dp_fisa_rx_hdl, head_nbuf); + +deliver_nbuf: /* Deliver without FISA */ + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(head_nbuf) = 1; + qdf_nbuf_set_next(head_nbuf, NULL); + hex_dump_skb_data(head_nbuf, false); + if (!vdev->osif_rx || QDF_STATUS_SUCCESS != + vdev->osif_rx(vdev->osif_vdev, head_nbuf)) + qdf_nbuf_free(head_nbuf); +next_msdu: + head_nbuf = next_nbuf; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_fisa_flush_flow_wrap() - flush fisa flow by invoking + * dp_rx_fisa_flush_flow() + * @sw_ft: fisa flow for which aggregates to be flushed + * + * Return: None. + */ +static void dp_rx_fisa_flush_flow_wrap(struct dp_fisa_rx_sw_ft *sw_ft) +{ + /* Save the ip_len and checksum as hardware assist is + * always based on his start of aggregation + */ + sw_ft->napi_flush_cumulative_l4_checksum = + sw_ft->cumulative_l4_checksum; + sw_ft->napi_flush_cumulative_ip_length = + sw_ft->hal_cumultive_ip_len; + dp_fisa_debug("napi_flush_cumulative_ip_length 0x%x", + sw_ft->napi_flush_cumulative_ip_length); + + dp_rx_fisa_flush_flow(sw_ft->vdev, + sw_ft); + sw_ft->cur_aggr = 0; +} + +QDF_STATUS dp_rx_fisa_flush_by_ctx_id(struct dp_soc *soc, int napi_id) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + struct dp_rx_fst *fisa_hdl = dp_ctx->rx_fst; + struct dp_fisa_rx_sw_ft *sw_ft_entry = + (struct dp_fisa_rx_sw_ft *)fisa_hdl->base; + int ft_size = fisa_hdl->max_entries; + int i; + + dp_rx_fisa_acquire_ft_lock(fisa_hdl, napi_id); + for (i = 0; i < ft_size; i++) { + if (sw_ft_entry[i].napi_id == napi_id && + sw_ft_entry[i].is_populated) { + dp_fisa_debug("flushing %d %pK napi_id %d", i, + &sw_ft_entry[i], napi_id); + dp_rx_fisa_flush_flow_wrap(&sw_ft_entry[i]); + } + } + dp_rx_fisa_release_ft_lock(fisa_hdl, napi_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_rx_fisa_flush_by_vdev_id(struct dp_soc *soc, uint8_t vdev_id) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + struct dp_rx_fst *fisa_hdl = dp_ctx->rx_fst; + struct dp_fisa_rx_sw_ft *sw_ft_entry = + (struct dp_fisa_rx_sw_ft *)fisa_hdl->base; + int ft_size = fisa_hdl->max_entries; + int i; + struct dp_vdev *vdev; + uint8_t reo_id; + + vdev = dp_vdev_get_ref_by_id(soc, vdev_id, DP_MOD_ID_RX); + if (qdf_unlikely(!vdev)) { + dp_err("null vdev by vdev_id %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < ft_size; i++) { + reo_id = sw_ft_entry[i].napi_id; + if (reo_id >= MAX_REO_DEST_RINGS) + continue; + dp_rx_fisa_acquire_ft_lock(fisa_hdl, reo_id); + if (vdev == sw_ft_entry[i].vdev) { + dp_fisa_debug("flushing %d %pk vdev %pK", i, + &sw_ft_entry[i], vdev); + + dp_rx_fisa_flush_flow_wrap(&sw_ft_entry[i]); + } + dp_rx_fisa_release_ft_lock(fisa_hdl, reo_id); + } + dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_RX); + + return QDF_STATUS_SUCCESS; +} + +void dp_suspend_fse_cache_flush(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rx_fst *dp_fst; + + dp_fst = dp_ctx->rx_fst; + if (dp_fst) { + if (qdf_atomic_read(&dp_fst->fse_cache_flush_posted)) + qdf_timer_sync_cancel(&dp_fst->fse_cache_flush_timer); + dp_fst->fse_cache_flush_allow = false; + } + + dp_info("fse cache flush suspended"); +} + +void dp_resume_fse_cache_flush(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rx_fst *dp_fst; + + dp_fst = dp_ctx->rx_fst; + if (dp_fst) { + qdf_atomic_set(&dp_fst->fse_cache_flush_posted, 0); + dp_fst->fse_cache_flush_allow = true; + } + + dp_info("fse cache flush resumed"); +} + +void dp_set_fisa_dynamic_aggr_size_support(bool dynamic_aggr_size_support) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + + dp_ctx->fisa_dynamic_aggr_size_support = dynamic_aggr_size_support; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_fisa_rx.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_fisa_rx.h new file mode 100644 index 0000000000..71ebcb4163 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_fisa_rx.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_DP_FISA_RX_H__ +#define __WLAN_DP_FISA_RX_H__ + +#ifdef WLAN_SUPPORT_RX_FISA +#include +#endif +#include +#include + +//#define FISA_DEBUG_ENABLE + +#ifdef FISA_DEBUG_ENABLE +#define dp_fisa_debug dp_info +#else +#define dp_fisa_debug(params...) +#endif + +#if defined(WLAN_SUPPORT_RX_FISA) + +/* + * Below is different types of max MSDU aggregation supported in FISA. + * Host should send one value less so that F.W will increment one + * and program in RXOLE reg + */ +#define DP_RX_FISA_MAX_AGGR_COUNT_DEFAULT (16 - 1) +#define DP_RX_FISA_MAX_AGGR_COUNT_1 (32 - 1) + +#define FSE_CACHE_FLUSH_TIME_OUT 5 /* milliSeconds */ +#define FISA_UDP_MAX_DATA_LEN 1470 /* udp max data length */ +#define FISA_UDP_HDR_LEN 8 /* udp header length */ +/* single packet max cumulative ip length */ +#define FISA_MAX_SINGLE_CUMULATIVE_IP_LEN \ + (FISA_UDP_MAX_DATA_LEN + FISA_UDP_HDR_LEN) +/* max flow cumulative ip length */ +#define FISA_FLOW_MAX_CUMULATIVE_IP_LEN \ + (FISA_MAX_SINGLE_CUMULATIVE_IP_LEN * FISA_FLOW_MAX_AGGR_COUNT) + +/* minimal pure UDP data length required for FISA */ +#define FISA_MIN_UDP_DATA_LEN 64 +/* minimal length without L2/L3 header required for FISA */ +#define FISA_MIN_L4_AND_DATA_LEN \ + (FISA_UDP_HDR_LEN + FISA_MIN_UDP_DATA_LEN) + +/* CMEM size for FISA FST 16K */ +#define DP_CMEM_FST_SIZE 16384 + +#define IPSEC_PORT 500 +#define IPSEC_NAT_PORT 4500 +#define DNS_SERVER_PORT 53 + +#define DP_FT_LOCK_MAX_RECORDS 32 + +#define FISA_FT_ENTRY_AGING_US 1000000 + +struct dp_fisa_rx_fst_update_elem { + /* Do not add new entries here */ + qdf_list_node_t node; + struct cdp_rx_flow_tuple_info flow_tuple_info; + struct dp_vdev *vdev; + uint8_t vdev_id; + uint32_t flow_idx; + uint32_t reo_dest_indication; + bool is_tcp_flow; + bool is_udp_flow; + u8 reo_id; +}; + +enum dp_ft_lock_event_type { + DP_FT_LOCK_EVENT, + DP_FT_UNLOCK_EVENT, +}; + +struct dp_ft_lock_record { + const char *func; + int cpu_id; + uint64_t timestamp; + enum dp_ft_lock_event_type type; +}; + +struct dp_ft_lock_history { + uint32_t record_idx; + struct dp_ft_lock_record ft_lock_rec[DP_FT_LOCK_MAX_RECORDS]; +}; + +/** + * dp_fisa_rx() - FISA Rx packet delivery entry function + * @dp_ctx: DP component handle + * @vdev: core txrx vdev + * @nbuf_list: Delivery list of nbufs + * + * Return: Success on aggregation + */ +QDF_STATUS dp_fisa_rx(struct wlan_dp_psoc_context *dp_ctx, + struct dp_vdev *vdev, + qdf_nbuf_t nbuf_list); + +/** + * dp_rx_fisa_flush_by_ctx_id() - FISA Rx flush function to flush + * aggregation at end of NAPI + * @soc: core txrx main context + * @napi_id: Flows which are rxed on the NAPI ID to be flushed + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_rx_fisa_flush_by_ctx_id(struct dp_soc *soc, int napi_id); + +/** + * dp_rx_fisa_flush_by_vdev_id() - Flush fisa aggregates per vdev id + * @soc: core txrx main context + * @vdev_id: vdev ID + * + * Return: Success on flushing the flows for the vdev + */ +QDF_STATUS dp_rx_fisa_flush_by_vdev_id(struct dp_soc *soc, uint8_t vdev_id); + +/** + * dp_fisa_rx_fst_update_work() - Work functions for FST updates + * @arg: argument passed to the work function + * + * Return: None + */ +void dp_fisa_rx_fst_update_work(void *arg); + +/** + * dp_suspend_fse_cache_flush() - Suspend FSE cache flush + * @dp_ctx: DP component context + * + * Return: None + */ +void dp_suspend_fse_cache_flush(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_rx_fst_attach() - Initialize Rx FST and setup necessary parameters + * @dp_ctx: DP component context + * + * Return: Handle to flow search table entry + */ +QDF_STATUS dp_rx_fst_attach(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_rx_fst_target_config() - Configure RX OLE FSE engine in HW + * @dp_ctx: DP component context + * + * Return: Success + */ +QDF_STATUS dp_rx_fst_target_config(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_rx_fisa_config() - Configure FISA related settings + * @dp_ctx: DP component context + * + * Return: QDF_STATUS + */ +QDF_STATUS dp_rx_fisa_config(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_rx_fst_detach() - De-initialize Rx FST + * @dp_ctx: DP component context + * + * Return: None + */ +void dp_rx_fst_detach(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_resume_fse_cache_flush() - Resume FSE cache flush + * @dp_ctx: DP component context + * + * Return: None + */ +void dp_resume_fse_cache_flush(struct wlan_dp_psoc_context *dp_ctx); + +/** + * dp_rx_fst_update_pm_suspend_status() - Update Suspend status in FISA + * @dp_ctx: DP component context + * @suspended: Flag to indicate suspend or not + * + * Return: None + */ +void dp_rx_fst_update_pm_suspend_status(struct wlan_dp_psoc_context *dp_ctx, + bool suspended); + +/** + * dp_rx_fst_requeue_wq() - Re-queue pending work queue tasks + * @dp_ctx: DP component context + * + * Return: None + */ +void dp_rx_fst_requeue_wq(struct wlan_dp_psoc_context *dp_ctx); + +void dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id); + +/** + * dp_fisa_cfg_init() - FISA INI items init + * @config: SoC CFG config + * @psoc: Objmgr PSoC handle + * + * Return: None + */ +void dp_fisa_cfg_init(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc); + +/** + * dp_set_fst_in_cmem() - Set flag to indicate FST is in CMEM + * @fst_in_cmem: Flag to indicate FST is in CMEM + * + * Return: None + */ +void dp_set_fst_in_cmem(bool fst_in_cmem); + +/** + * dp_set_fisa_dynamic_aggr_size_support() - Set flag to indicate dynamic + * aggregation size support + * @dynamic_aggr_size_support: Flag to indicate dynamic aggregation support + * + * Return: None + */ +void dp_set_fisa_dynamic_aggr_size_support(bool dynamic_aggr_size_support); +#else +static inline void +dp_rx_fst_update_pm_suspend_status(struct wlan_dp_psoc_context *dp_ctx, + bool suspended) +{ +} + +static inline void dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id) +{ +} + +static inline void dp_fisa_cfg_init(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} + +static inline void dp_set_fst_in_cmem(bool fst_in_cmem) +{ +} + +static inline void +dp_set_fisa_dynamic_aggr_size_support(bool dynamic_aggr_size_support) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_main.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_main.c new file mode 100644 index 0000000000..2ada8b1d42 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_main.c @@ -0,0 +1,2852 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: wlan_dp_main.c + * + * + */ + +#include "wlan_dp_main.h" +#include "wlan_dp_public_struct.h" +#include "cfg_ucfg_api.h" +#include "wlan_dp_bus_bandwidth.h" +#include +#include +#include +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_cm_api.h" +#include "wlan_dp_nud_tracking.h" +#include "target_if_dp_comp.h" +#include "wlan_dp_txrx.h" +#include "init_deinit_lmac.h" +#include +#include +#include +#include +#if defined(WLAN_DP_PROFILE_SUPPORT) || defined(FEATURE_DIRECT_LINK) +#include "cdp_txrx_ctrl.h" +#endif +#ifdef FEATURE_DIRECT_LINK +#include "dp_internal.h" +#endif +#include + +#ifdef WLAN_DP_PROFILE_SUPPORT +/* Memory profile table based on supported caps */ +static struct wlan_dp_memory_profile_ctx wlan_dp_1x1_he80_1kqam[] = { + {DP_TX_DESC_NUM_CFG, 1024}, + {DP_TX_EXT_DESC_NUM_CFG, 1024}, + {DP_TX_RING_SIZE_CFG, 1024}, + {DP_TX_COMPL_RING_SIZE_CFG, 1024}, + {DP_RX_SW_DESC_NUM_CFG, 1024}, + {DP_REO_DST_RING_SIZE_CFG, 1024}, + {DP_RXDMA_BUF_RING_SIZE_CFG, 1024}, + {DP_RXDMA_REFILL_RING_SIZE_CFG, 1024}, + {DP_RX_REFILL_POOL_NUM_CFG, 1024}, +}; + +/* Global data structure to save profile info */ +static struct wlan_dp_memory_profile_info g_dp_profile_info; +#endif +#include + +/* Global DP context */ +static struct wlan_dp_psoc_context *gp_dp_ctx; + +QDF_STATUS dp_allocate_ctx(void) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = qdf_mem_malloc(sizeof(*dp_ctx)); + if (!dp_ctx) { + dp_err("Failed to create DP context"); + return QDF_STATUS_E_NOMEM; + } + + qdf_spinlock_create(&dp_ctx->intf_list_lock); + qdf_spinlock_create(&dp_ctx->dp_link_del_lock); + qdf_list_create(&dp_ctx->intf_list, 0); + TAILQ_INIT(&dp_ctx->inactive_dp_link_list); + + dp_attach_ctx(dp_ctx); + + return QDF_STATUS_SUCCESS; +} + +void dp_free_ctx(void) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + + qdf_spinlock_destroy(&dp_ctx->intf_list_lock); + qdf_list_destroy(&dp_ctx->intf_list); + dp_detach_ctx(); + qdf_mem_free(dp_ctx); +} + +QDF_STATUS dp_get_front_intf_no_lock(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_intf **out_intf) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_intf = NULL; + + status = qdf_list_peek_front(&dp_ctx->intf_list, &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_intf = qdf_container_of(node, struct wlan_dp_intf, node); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_get_next_intf_no_lock(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_intf *cur_intf, + struct wlan_dp_intf **out_intf) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + if (!cur_intf) + return QDF_STATUS_E_INVAL; + + *out_intf = NULL; + + status = qdf_list_peek_next(&dp_ctx->intf_list, + &cur_intf->node, + &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_intf = qdf_container_of(node, struct wlan_dp_intf, node); + + return status; +} + +struct wlan_dp_intf* +dp_get_intf_by_macaddr(struct wlan_dp_psoc_context *dp_ctx, + struct qdf_mac_addr *addr) +{ + struct wlan_dp_intf *dp_intf; + + qdf_spin_lock_bh(&dp_ctx->intf_list_lock); + for (dp_get_front_intf_no_lock(dp_ctx, &dp_intf); dp_intf; + dp_get_next_intf_no_lock(dp_ctx, dp_intf, &dp_intf)) { + if (qdf_is_macaddr_equal(&dp_intf->mac_addr, addr)) { + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); + return dp_intf; + } + } + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); + + return NULL; +} + +struct wlan_dp_intf* +dp_get_intf_by_netdev(struct wlan_dp_psoc_context *dp_ctx, qdf_netdev_t dev) +{ + struct wlan_dp_intf *dp_intf; + + qdf_spin_lock_bh(&dp_ctx->intf_list_lock); + for (dp_get_front_intf_no_lock(dp_ctx, &dp_intf); dp_intf; + dp_get_next_intf_no_lock(dp_ctx, dp_intf, &dp_intf)) { + if (dp_intf->dev == dev) { + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); + return dp_intf; + } + } + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); + + return NULL; +} + +/** + * validate_link_id() - Check if link ID is valid + * @link_id: DP link ID + * + * Return: true on success, false on failure + */ +static bool validate_link_id(uint8_t link_id) +{ + if (link_id == WLAN_UMAC_VDEV_ID_MAX) { + dp_err("Interface is not up: %ps", QDF_RET_IP); + return false; + } + + if (link_id >= WLAN_MAX_VDEVS) { + dp_err("Bad interface id:%u", link_id); + return false; + } + + return true; +} + +int is_dp_intf_valid(struct wlan_dp_intf *dp_intf) +{ + if (!dp_intf) { + dp_err("Interface is NULL"); + return -EINVAL; + } + + if (!dp_intf->dev) { + dp_err("DP interface net_device is null"); + return -EINVAL; + } + + if (!(dp_intf->dev->flags & IFF_UP)) { + dp_info_rl("DP interface '%s' is not up %ps", + dp_intf->dev->name, QDF_RET_IP); + return -EAGAIN; + } + + return 0; +} + +bool is_dp_link_valid(struct wlan_dp_link *dp_link) +{ + struct wlan_dp_intf *dp_intf; + int ret; + + if (!dp_link) { + dp_err("link is NULL"); + return false; + } + + if (dp_link->magic != WLAN_DP_LINK_MAGIC) { + dp_err("dp_link %pK bad magic %llx", dp_link, dp_link->magic); + return false; + } + + dp_intf = dp_link->dp_intf; + ret = is_dp_intf_valid(dp_intf); + if (ret) + return false; + + return validate_link_id(dp_link->link_id); +} + +QDF_STATUS dp_get_front_link_no_lock(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link **out_link) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_link = NULL; + + status = qdf_list_peek_front(&dp_intf->dp_link_list, &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_link = qdf_container_of(node, struct wlan_dp_link, node); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_get_next_link_no_lock(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link *cur_link, + struct wlan_dp_link **out_link) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + if (!cur_link) + return QDF_STATUS_E_INVAL; + + *out_link = NULL; + + status = qdf_list_peek_next(&dp_intf->dp_link_list, + &cur_link->node, + &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_link = qdf_container_of(node, struct wlan_dp_link, node); + + return status; +} + +static QDF_STATUS +dp_intf_wait_for_task_complete(struct wlan_dp_intf *dp_intf) +{ + int count = DP_TASK_MAX_WAIT_CNT; + int r; + + while (count) { + r = atomic_read(&dp_intf->num_active_task); + + if (!r) + return QDF_STATUS_SUCCESS; + + if (--count) { + dp_err_rl("Waiting for DP task to complete: %d", count); + qdf_sleep(DP_TASK_WAIT_TIME); + } + } + + dp_err("Timed-out waiting for DP task completion"); + return QDF_STATUS_E_TIMEOUT; +} + +void dp_wait_complete_tasks(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_intf *dp_intf, *dp_intf_next = NULL; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + /* + * If timeout happens for one interface better to bail out + * instead of waiting for other intefaces task completion + */ + if (qdf_atomic_read(&dp_intf->num_active_task)) + if (dp_intf_wait_for_task_complete(dp_intf)) + break; + } +} + +#ifdef CONFIG_DP_TRACE +/** + * dp_convert_string_to_array() - used to convert string into u8 array + * @str: String to be converted + * @array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * @to_hex: true, if conversion required for hex string + * + * This API is called to convert string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ +static QDF_STATUS dp_convert_string_to_array(char *str, uint8_t *array, + uint8_t *len, + uint16_t array_max_len, + bool to_hex) +{ + char *format, *s = str; + + if (!str || !array || !len) + return QDF_STATUS_E_INVAL; + + format = (to_hex) ? "%02x" : "%d"; + + *len = 0; + while ((s) && (*len < array_max_len)) { + int val; + /* Increment length only if sscanf successfully extracted + * one element. Any other return value means error. + * Ignore it. + */ + if (sscanf(s, format, &val) == 1) { + array[*len] = (uint8_t)val; + *len += 1; + } + + s = strpbrk(s, ","); + if (s) + s++; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_string_to_u8_array() - used to convert string into u8 array + * @str: String to be converted + * @array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * + * Return: QDF_STATUS + */ +static +QDF_STATUS dp_string_to_u8_array(char *str, uint8_t *array, + uint8_t *len, uint16_t array_max_len) +{ + return dp_convert_string_to_array(str, array, len, + array_max_len, false); +} + +void dp_trace_init(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_psoc_cfg *config; + bool live_mode = DP_TRACE_CONFIG_DEFAULT_LIVE_MODE; + uint8_t thresh = DP_TRACE_CONFIG_DEFAULT_THRESH; + uint16_t thresh_time_limit = DP_TRACE_CONFIG_DEFAULT_THRESH_TIME_LIMIT; + uint8_t verbosity = DP_TRACE_CONFIG_DEFAULT_VERBOSTY; + uint32_t proto_bitmap = DP_TRACE_CONFIG_DEFAULT_BITMAP; + uint8_t config_params[DP_TRACE_CONFIG_NUM_PARAMS]; + uint8_t num_entries = 0; + uint32_t bw_compute_interval; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + config = &dp_ctx->dp_cfg; + + qdf_dp_set_proto_event_bitmap(config->dp_proto_event_bitmap); + + if (!config->enable_dp_trace) { + dp_err("dp trace is disabled from ini"); + return; + } + + dp_string_to_u8_array(config->dp_trace_config, config_params, + &num_entries, sizeof(config_params)); + + /* calculating, num bw timer intervals in a second (1000ms) */ + bw_compute_interval = DP_BUS_BW_CFG(config->bus_bw_compute_interval); + + if (bw_compute_interval <= 1000 && bw_compute_interval > 0) { + thresh_time_limit = 1000 / bw_compute_interval; + } else if (bw_compute_interval > 1000) { + dp_err("busBandwidthComputeInterval > 1000, using 1000"); + thresh_time_limit = 1; + } else { + dp_err("busBandwidthComputeInterval is 0, using defaults"); + } + + switch (num_entries) { + case 4: + proto_bitmap = config_params[3]; + fallthrough; + case 3: + verbosity = config_params[2]; + fallthrough; + case 2: + thresh = config_params[1]; + fallthrough; + case 1: + live_mode = config_params[0]; + fallthrough; + default: + dp_debug("live_mode %u thresh %u time_limit %u verbosity %u bitmap 0x%x", + live_mode, thresh, thresh_time_limit, + verbosity, proto_bitmap); + }; + + qdf_dp_trace_init(live_mode, thresh, thresh_time_limit, + verbosity, proto_bitmap); +} + +void dp_set_dump_dp_trace(uint16_t cmd_type, uint16_t count) +{ + dp_debug("DUMP_DP_TRACE_LEVEL: %d %d", + cmd_type, count); + if (cmd_type == DUMP_DP_TRACE) + qdf_dp_trace_dump_all(count, QDF_TRACE_DEFAULT_PDEV_ID); + else if (cmd_type == ENABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_enable_live_mode(); + else if (cmd_type == CLEAR_DP_TRACE_BUFFER) + qdf_dp_trace_clear_buffer(); + else if (cmd_type == DISABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_disable_live_mode(); +} +#else +void dp_trace_init(struct wlan_objmgr_psoc *psoc) +{ +} + +void dp_set_dump_dp_trace(uint16_t cmd_type, uint16_t count) +{ +} +#endif +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +/** + * dp_ini_bus_bandwidth() - Initialize INIs concerned about bus bandwidth + * @config: pointer to dp config + * @psoc: pointer to psoc obj + * + * Return: none + */ +static void dp_ini_bus_bandwidth(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + config->bus_bw_super_high_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_SUPER_HIGH_THRESHOLD); + config->bus_bw_ultra_high_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_ULTRA_HIGH_THRESHOLD); + config->bus_bw_very_high_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_VERY_HIGH_THRESHOLD); + config->bus_bw_dbs_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_DBS_THRESHOLD); + config->bus_bw_mid_high_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_MID_HIGH_THRESHOLD); + config->bus_bw_high_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_HIGH_THRESHOLD); + config->bus_bw_medium_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_MEDIUM_THRESHOLD); + config->bus_bw_low_threshold = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_LOW_THRESHOLD); + config->bus_bw_compute_interval = + cfg_get(psoc, CFG_DP_BUS_BANDWIDTH_COMPUTE_INTERVAL); + config->bus_low_cnt_threshold = + cfg_get(psoc, CFG_DP_BUS_LOW_BW_CNT_THRESHOLD); + config->enable_latency_crit_clients = + cfg_get(psoc, CFG_DP_BUS_HANDLE_LATENCY_CRITICAL_CLIENTS); +} + +/** + * dp_ini_tcp_settings() - Initialize INIs concerned about tcp settings + * @config: pointer to dp config + * @psoc: pointer to psoc obj + * + * Return: none + */ +static void dp_ini_tcp_settings(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + config->enable_tcp_limit_output = + cfg_get(psoc, CFG_DP_ENABLE_TCP_LIMIT_OUTPUT); + config->enable_tcp_adv_win_scale = + cfg_get(psoc, CFG_DP_ENABLE_TCP_ADV_WIN_SCALE); + config->enable_tcp_delack = + cfg_get(psoc, CFG_DP_ENABLE_TCP_DELACK); + config->tcp_delack_thres_high = + cfg_get(psoc, CFG_DP_TCP_DELACK_THRESHOLD_HIGH); + config->tcp_delack_thres_low = + cfg_get(psoc, CFG_DP_TCP_DELACK_THRESHOLD_LOW); + config->tcp_delack_timer_count = + cfg_get(psoc, CFG_DP_TCP_DELACK_TIMER_COUNT); + config->tcp_tx_high_tput_thres = + cfg_get(psoc, CFG_DP_TCP_TX_HIGH_TPUT_THRESHOLD); + config->enable_tcp_param_update = + cfg_get(psoc, CFG_DP_ENABLE_TCP_PARAM_UPDATE); +} + +#else +static void dp_ini_bus_bandwidth(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} + +static void dp_ini_tcp_settings(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + +#ifdef CONFIG_DP_TRACE +/** + * dp_trace_cfg_update() - initialize DP Trace config + * @config : Configuration parameters + * @psoc: psoc handle + */ +static void +dp_trace_cfg_update(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + qdf_size_t array_out_size; + + config->enable_dp_trace = cfg_get(psoc, CFG_DP_ENABLE_DP_TRACE); + qdf_uint8_array_parse(cfg_get(psoc, CFG_DP_DP_TRACE_CONFIG), + config->dp_trace_config, + sizeof(config->dp_trace_config), &array_out_size); + config->dp_proto_event_bitmap = cfg_get(psoc, + CFG_DP_PROTO_EVENT_BITMAP); +} +#else +static void +dp_trace_cfg_update(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif +#ifdef WLAN_NUD_TRACKING +/** + * dp_nud_tracking_cfg_update() - initialize NUD Tracking config + * @config : Configuration parameters + * @psoc: psoc handle + */ +static void +dp_nud_tracking_cfg_update(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + config->enable_nud_tracking = cfg_get(psoc, CFG_DP_ENABLE_NUD_TRACKING); +} +#else +static void +dp_nud_tracking_cfg_update(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +/** + * dp_ini_tcp_del_ack_settings() - initialize TCP delack config + * @config : Configuration parameters + * @psoc: psoc handle + */ +static void dp_ini_tcp_del_ack_settings(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + config->del_ack_threshold_high = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_HIGH_THRESHOLD); + config->del_ack_threshold_low = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_LOW_THRESHOLD); + config->del_ack_enable = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_ENABLE); + config->del_ack_pkt_count = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_PKT_CNT); + config->del_ack_timer_value = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_TIMER_VALUE); +} +#else +static void dp_ini_tcp_del_ack_settings(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +/** + * dp_hl_bundle_cfg_update() - initialize TxRx HL bundle config + * @config : Configuration parameters + * @psoc: psoc handle + */ +static void dp_hl_bundle_cfg_update(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + config->pkt_bundle_threshold_high = + cfg_get(psoc, CFG_DP_HL_BUNDLE_HIGH_TH); + config->pkt_bundle_threshold_low = + cfg_get(psoc, CFG_DP_HL_BUNDLE_LOW_TH); + config->pkt_bundle_timer_value = + cfg_get(psoc, CFG_DP_HL_BUNDLE_TIMER_VALUE); + config->pkt_bundle_size = + cfg_get(psoc, CFG_DP_HL_BUNDLE_SIZE); +} +#else +static void dp_hl_bundle_cfg_update(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +/** + * dp_set_rx_mode_value() - set rx_mode values + * @dp_ctx: DP context + * + * Return: none + */ +static void dp_set_rx_mode_value(struct wlan_dp_psoc_context *dp_ctx) +{ + uint32_t rx_mode = dp_ctx->dp_cfg.rx_mode; + enum QDF_GLOBAL_MODE con_mode = 0; + + con_mode = cds_get_conparam(); + + /* RPS has higher priority than dynamic RPS when both bits are set */ + if (rx_mode & CFG_ENABLE_RPS && rx_mode & CFG_ENABLE_DYNAMIC_RPS) + rx_mode &= ~CFG_ENABLE_DYNAMIC_RPS; + + if (rx_mode & CFG_ENABLE_RX_THREAD && rx_mode & CFG_ENABLE_RPS) { + dp_warn("rx_mode wrong configuration. Make it default"); + rx_mode = CFG_RX_MODE_DEFAULT; + } + + if (rx_mode & CFG_ENABLE_RX_THREAD) { + dp_ctx->enable_rxthread = true; + } else if (rx_mode & CFG_ENABLE_DP_RX_THREADS) { + if (con_mode == QDF_GLOBAL_MONITOR_MODE) + dp_ctx->enable_dp_rx_threads = false; + else + dp_ctx->enable_dp_rx_threads = true; + } + + if (rx_mode & CFG_ENABLE_RPS) + dp_ctx->rps = true; + + if (rx_mode & CFG_ENABLE_NAPI) + dp_ctx->napi_enable = true; + + if (rx_mode & CFG_ENABLE_DYNAMIC_RPS) + dp_ctx->dynamic_rps = true; + + dp_info("rx_mode:%u dp_rx_threads:%u rx_thread:%u napi:%u rps:%u dynamic rps %u", + rx_mode, dp_ctx->enable_dp_rx_threads, + dp_ctx->enable_rxthread, dp_ctx->napi_enable, + dp_ctx->rps, dp_ctx->dynamic_rps); +} + +/** + * dp_cfg_init() - initialize target specific configuration + * @ctx: dp context handle + */ +static void dp_cfg_init(struct wlan_dp_psoc_context *ctx) +{ + struct wlan_dp_psoc_cfg *config = &ctx->dp_cfg; + struct wlan_objmgr_psoc *psoc = ctx->psoc; + uint16_t cfg_len; + + cfg_len = qdf_str_len(cfg_get(psoc, CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST)) + + 1; + dp_ini_bus_bandwidth(config, psoc); + dp_ini_tcp_settings(config, psoc); + + dp_ini_tcp_del_ack_settings(config, psoc); + + dp_hl_bundle_cfg_update(config, psoc); + + config->rx_thread_ul_affinity_mask = + cfg_get(psoc, CFG_DP_RX_THREAD_UL_CPU_MASK); + config->rx_thread_affinity_mask = + cfg_get(psoc, CFG_DP_RX_THREAD_CPU_MASK); + if (cfg_len < CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST_LEN) { + qdf_str_lcopy(config->cpu_map_list, + cfg_get(psoc, CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST), + cfg_len); + } else { + dp_err("ini string length greater than max size %d", + CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST_LEN); + cfg_len = qdf_str_len(cfg_default(CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST)); + qdf_str_lcopy(config->cpu_map_list, + cfg_default(CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST), + cfg_len); + } + config->tx_orphan_enable = cfg_get(psoc, CFG_DP_TX_ORPHAN_ENABLE); + config->rx_mode = cfg_get(psoc, CFG_DP_RX_MODE); + dp_set_rx_mode_value(ctx); + config->multicast_replay_filter = + cfg_get(psoc, CFG_DP_FILTER_MULTICAST_REPLAY); + config->rx_wakelock_timeout = + cfg_get(psoc, CFG_DP_RX_WAKELOCK_TIMEOUT); + config->num_dp_rx_threads = cfg_get(psoc, CFG_DP_NUM_DP_RX_THREADS); + config->icmp_req_to_fw_mark_interval = + cfg_get(psoc, CFG_DP_ICMP_REQ_TO_FW_MARK_INTERVAL); + + config->rx_softirq_max_yield_duration_ns = + cfg_get(psoc, + CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS); + + dp_trace_cfg_update(config, psoc); + dp_nud_tracking_cfg_update(config, psoc); + dp_trace_cfg_update(config, psoc); + dp_fisa_cfg_init(config, psoc); +} + +/** + * __dp_process_mic_error() - Indicate mic error to supplicant + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +static void +__dp_process_mic_error(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_callbacks *ops = &dp_intf->dp_ctx->dp_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = dp_objmgr_get_vdev_by_user(dp_intf->def_link, WLAN_DP_ID); + if (!vdev) { + return; + } + + if ((dp_intf->device_mode == QDF_STA_MODE || + dp_intf->device_mode == QDF_P2P_CLIENT_MODE) && + wlan_cm_is_vdev_active(vdev)) + ops->osif_dp_process_mic_error(dp_intf->mic_work.info, + vdev); + else if (dp_intf->device_mode == QDF_SAP_MODE || + dp_intf->device_mode == QDF_P2P_GO_MODE) + ops->osif_dp_process_mic_error(dp_intf->mic_work.info, + vdev); + else + dp_err("Invalid interface type:%d", dp_intf->device_mode); + + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); +} + +/** + * dp_process_mic_error() - process mic error work + * @data: void pointer to dp interface + * + * Return: None + */ +static void +dp_process_mic_error(void *data) +{ + struct wlan_dp_intf *dp_intf = data; + + if (is_dp_intf_valid(dp_intf)) + goto exit; + + __dp_process_mic_error(dp_intf); + +exit: + qdf_spin_lock_bh(&dp_intf->mic_work.lock); + if (dp_intf->mic_work.info) { + qdf_mem_free(dp_intf->mic_work.info); + dp_intf->mic_work.info = NULL; + } + if (dp_intf->mic_work.status == DP_MIC_SCHEDULED) + dp_intf->mic_work.status = DP_MIC_INITIALIZED; + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); +} + +void +dp_rx_mic_error_ind(struct cdp_ctrl_objmgr_psoc *psoc, uint8_t pdev_id, + struct cdp_rx_mic_err_info *mic_failure_info) +{ + struct dp_mic_error_info *dp_mic_info; + struct wlan_objmgr_vdev *vdev; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + if (!psoc) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc((struct wlan_objmgr_psoc *)psoc, + mic_failure_info->vdev_id, + WLAN_DP_ID); + if (!vdev) + return; + dp_link = dp_get_vdev_priv_obj(vdev); + if (!dp_link) { + dp_comp_vdev_put_ref(vdev); + return; + } + + dp_intf = dp_link->dp_intf; + dp_mic_info = qdf_mem_malloc(sizeof(*dp_mic_info)); + if (!dp_mic_info) { + dp_comp_vdev_put_ref(vdev); + return; + } + + qdf_copy_macaddr(&dp_mic_info->ta_mac_addr, + &mic_failure_info->ta_mac_addr); + dp_mic_info->multicast = mic_failure_info->multicast; + dp_mic_info->key_id = mic_failure_info->key_id; + qdf_mem_copy(&dp_mic_info->tsc, &mic_failure_info->tsc, + SIR_CIPHER_SEQ_CTR_SIZE); + dp_mic_info->vdev_id = mic_failure_info->vdev_id; + + qdf_spin_lock_bh(&dp_intf->mic_work.lock); + if (dp_intf->mic_work.status != DP_MIC_INITIALIZED) { + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); + qdf_mem_free(dp_mic_info); + dp_comp_vdev_put_ref(vdev); + return; + } + /* + * Store mic error info pointer in dp_intf + * for freeing up the allocated memory in case + * the work scheduled below is flushed or deinitialized. + */ + dp_intf->mic_work.status = DP_MIC_SCHEDULED; + dp_intf->mic_work.info = dp_mic_info; + qdf_sched_work(0, &dp_intf->mic_work.work); + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); + dp_comp_vdev_put_ref(vdev); +} + +/** + * dp_mic_flush_work() - disable and flush pending mic work + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +static void +dp_mic_flush_work(struct wlan_dp_intf *dp_intf) +{ + dp_info("Flush the MIC error work"); + + qdf_spin_lock_bh(&dp_intf->mic_work.lock); + if (dp_intf->mic_work.status != DP_MIC_SCHEDULED) { + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); + return; + } + dp_intf->mic_work.status = DP_MIC_DISABLED; + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); + + qdf_flush_work(&dp_intf->mic_work.work); +} + +/** + * dp_mic_enable_work() - enable mic error work + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +static void dp_mic_enable_work(struct wlan_dp_intf *dp_intf) +{ + dp_info("Enable the MIC error work"); + + qdf_spin_lock_bh(&dp_intf->mic_work.lock); + if (dp_intf->mic_work.status == DP_MIC_DISABLED) + dp_intf->mic_work.status = DP_MIC_INITIALIZED; + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); +} + +void dp_mic_deinit_work(struct wlan_dp_intf *dp_intf) +{ + dp_info("DeInitialize the MIC error work"); + + if (dp_intf->mic_work.status != DP_MIC_UNINITIALIZED) { + qdf_destroy_work(NULL, &dp_intf->mic_work.work); + + qdf_spin_lock_bh(&dp_intf->mic_work.lock); + dp_intf->mic_work.status = DP_MIC_UNINITIALIZED; + if (dp_intf->mic_work.info) { + qdf_mem_free(dp_intf->mic_work.info); + dp_intf->mic_work.info = NULL; + } + qdf_spin_unlock_bh(&dp_intf->mic_work.lock); + qdf_spinlock_destroy(&dp_intf->mic_work.lock); + } +} + +void dp_mic_init_work(struct wlan_dp_intf *dp_intf) +{ + qdf_spinlock_create(&dp_intf->mic_work.lock); + qdf_create_work(0, &dp_intf->mic_work.work, + dp_process_mic_error, dp_intf); + dp_intf->mic_work.status = DP_MIC_INITIALIZED; + dp_intf->mic_work.info = NULL; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * dp_intf_get_next_deflink_candidate() - Get a candidate link from the list of + * links available in the dp interface. + * @dp_intf: DP interface handle + * @cur_def_link: Handle to current def_link in the DP interface + * + * Return: Handle of the candidate for next def_link + * NULL, if there is no other suitable candidate found. + */ +static struct wlan_dp_link * +dp_intf_get_next_deflink_candidate(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link *cur_def_link) +{ + struct wlan_dp_link *dp_link, *dp_link_next; + + dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) { + /* + * dp_link is removed from the list when its deleted. + * But check if its valid or not. Additional check to make + * sure that the next deflink is valid. + */ + if (!is_dp_link_valid(dp_link)) + continue; + + if (dp_link != cur_def_link) + return dp_link; + } + + return NULL; +} + +/** + * dp_change_def_link() - Change default link for the dp_intf + * @dp_intf: DP interface for which default link is to be changed + * @dp_link: link on which link switch notification arrived. + * @lswitch_req: Link switch request params + * + * This API is called only when dp_intf->def_link == dp_link, + * and there is a need to change the def_link of the dp_intf, + * due to any reason. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +dp_change_def_link(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link *dp_link, + struct wlan_mlo_link_switch_req *lswitch_req) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_dp_link *next_def_link; + cdp_config_param_type peer_param = {0}; + QDF_STATUS status; + + next_def_link = dp_intf_get_next_deflink_candidate(dp_intf, dp_link); + if (!is_dp_link_valid(next_def_link)) { + /* Unable to get candidate for next def_link */ + dp_info("Unable to get next def link %pK", next_def_link); + return QDF_STATUS_E_FAILURE; + } + + /* + * Switch dp_vdev related params + * - Change vdev of MLD peer. + */ + dp_info("Peer " QDF_MAC_ADDR_FMT ", change vdev %d -> %d", + QDF_MAC_ADDR_REF(lswitch_req->peer_mld_addr.bytes), + dp_link->link_id, next_def_link->link_id); + peer_param.new_vdev_id = next_def_link->link_id; + status = cdp_txrx_set_peer_param(dp_ctx->cdp_soc, + /* Current vdev for remote MLD peer */ + dp_link->link_id, + lswitch_req->peer_mld_addr.bytes, + CDP_CONFIG_MLD_PEER_VDEV, + peer_param); + + /* + * DP link switch checks and process is completed successfully. + * Change the def_link to the partner link + */ + if (QDF_IS_STATUS_SUCCESS(status)) + dp_intf->def_link = next_def_link; + + return status; +} + +QDF_STATUS +dp_link_switch_notification(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *lswitch_req, + enum wlan_mlo_link_switch_notify_reason notify_reason) +{ + /* Add prints to string and print it at last, so we have only 1 print */ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* + * Currently DP handles link switch notification only if the command + * is in serialization's active queue. + * Return success for other notify reasons which are not handled in DP. + */ + if (notify_reason != MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_POST_SER) + return QDF_STATUS_SUCCESS; + + dp_ctx = dp_get_context(); + + dp_link = dp_get_vdev_priv_obj(vdev); + if (!is_dp_link_valid(dp_link)) { + dp_err("dp_link from vdev %pK is invalid", vdev); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + dp_info("Link switch req for dp_link %pK id %d (" QDF_MAC_ADDR_FMT + "), dp_intf %pK (" QDF_MAC_ADDR_FMT + ") cur_def_link %pK id %d device_mode %d num_links %d", + dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes), + dp_intf, QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes), + dp_intf->def_link, dp_intf->def_link->link_id, + dp_intf->device_mode, dp_intf->num_links); + + if (dp_intf->device_mode != QDF_STA_MODE) { + /* Link switch supported only for STA mode */ + status = QDF_STATUS_E_INVAL; + goto exit; + } + + if (dp_intf->num_links == 1) { + /* There is only one link, so we cannot switch */ + status = QDF_STATUS_E_CANCELED; + goto exit; + } + + if (dp_link != dp_intf->def_link) { + /* default link is not being switched, so DP is fine */ + goto exit; + } + + /* Recipe to be done before switching a default link */ + status = dp_change_def_link(dp_intf, dp_link, lswitch_req); + if (QDF_IS_STATUS_ERROR(status)) { + /* Failed to switch default link */ + dp_info("Failed to change def_link for dp_intf %pK", dp_intf); + goto exit; + } + +exit: + dp_info("Link switch req %s (ret %d) for dp_link %pK id %d (" + QDF_MAC_ADDR_FMT "), dp_intf %pK (" QDF_MAC_ADDR_FMT + ") cur_def_link %pK id %d device_mode %d num_links %d", + QDF_IS_STATUS_ERROR(status) ? "Failed" : "Successful", + status, dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes), + dp_intf, QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes), + dp_intf->def_link, dp_intf->def_link->link_id, + dp_intf->device_mode, dp_intf->num_links); + + return status; +} +#else +static struct wlan_dp_link * +dp_intf_get_next_deflink_candidate(struct wlan_dp_intf *dp_intf, + struct wlan_dp_link *cur_def_link) +{ + return NULL; +} +#endif + +QDF_STATUS +dp_peer_obj_create_notification(struct wlan_objmgr_peer *peer, void *arg) +{ + struct wlan_dp_sta_info *sta_info; + QDF_STATUS status; + + sta_info = qdf_mem_malloc(sizeof(*sta_info)); + if (!sta_info) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_peer_component_obj_attach(peer, WLAN_COMP_DP, + sta_info, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("DP peer ("QDF_MAC_ADDR_FMT") attach failed", + QDF_MAC_ADDR_REF(peer->macaddr)); + qdf_mem_free(sta_info); + return status; + } + + qdf_mem_copy(sta_info->sta_mac.bytes, peer->macaddr, + QDF_MAC_ADDR_SIZE); + sta_info->pending_eap_frm_type = 0; + sta_info->dhcp_phase = DHCP_PHASE_ACK; + sta_info->dhcp_nego_status = DHCP_NEGO_STOP; + + dp_info("sta info created mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_info->sta_mac.bytes)); + + return status; +} + +QDF_STATUS +dp_peer_obj_destroy_notification(struct wlan_objmgr_peer *peer, void *arg) +{ + struct wlan_dp_sta_info *sta_info; + QDF_STATUS status; + + sta_info = dp_get_peer_priv_obj(peer); + if (!sta_info) { + dp_err("DP_peer_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_peer_component_obj_detach(peer, WLAN_COMP_DP, + sta_info); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("DP peer ("QDF_MAC_ADDR_FMT") detach failed", + QDF_MAC_ADDR_REF(peer->macaddr)); + + qdf_mem_free(sta_info); + + return status; +} + +QDF_STATUS +dp_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr *mac_addr; + qdf_netdev_t dev; + + dp_info("DP VDEV OBJ create notification, vdev_id %d", + wlan_vdev_get_id(vdev)); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + dp_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + dp_ctx = dp_psoc_get_priv(psoc); + mac_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev); + + dev = dp_ctx->dp_ops.dp_get_netdev_by_vdev_mac(mac_addr); + if (!dev) { + dp_err("Failed to get intf mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_get_intf_by_netdev(dp_ctx, dev); + if (!dp_intf) { + dp_err("Failed to get dp intf dev: %s", + qdf_netdev_get_devname(dev)); + + return QDF_STATUS_E_INVAL; + } + + dp_link = qdf_mem_malloc(sizeof(*dp_link)); + if (!dp_link) { + dp_err("DP link(" QDF_MAC_ADDR_FMT ") memory alloc failed", + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return QDF_STATUS_E_NOMEM; + } + + /* Update Parent interface details */ + dp_link->magic = WLAN_DP_LINK_MAGIC; + dp_link->destroyed = 0; + dp_link->cdp_vdev_deleted = 0; + dp_link->dp_intf = dp_intf; + qdf_spin_lock_bh(&dp_intf->dp_link_list_lock); + qdf_list_insert_front(&dp_intf->dp_link_list, &dp_link->node); + dp_intf->num_links++; + qdf_spin_unlock_bh(&dp_intf->dp_link_list_lock); + + qdf_copy_macaddr(&dp_link->mac_addr, mac_addr); + qdf_spinlock_create(&dp_link->vdev_lock); + + qdf_spin_lock_bh(&dp_link->vdev_lock); + dp_link->link_id = vdev->vdev_objmgr.vdev_id; + dp_link->vdev = vdev; + qdf_spin_unlock_bh(&dp_link->vdev_lock); + + status = wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_COMP_DP, + (void *)dp_link, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to attach dp_link with vdev"); + return status; + } + + if (dp_intf->num_links == 1) { + /* + * Interface level operations to be done only + * when the first link is created + */ + dp_intf->def_link = dp_link; + dp_intf->device_mode = wlan_vdev_mlme_get_opmode(vdev); + qdf_atomic_init(&dp_intf->num_active_task); + dp_nud_ignore_tracking(dp_intf, false); + dp_mic_enable_work(dp_intf); + + if (dp_intf->device_mode == QDF_SAP_MODE || + dp_intf->device_mode == QDF_P2P_GO_MODE) { + dp_intf->sap_tx_block_mask = DP_TX_FN_CLR | + DP_TX_SAP_STOP; + + status = qdf_event_create(&dp_intf->qdf_sta_eap_frm_done_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + dp_err("eap frm done event init failed!!"); + return status; + } + qdf_mem_zero(&dp_intf->stats, + sizeof(qdf_net_dev_stats)); + } + } + + return status; +} + +static void dp_link_handle_cdp_vdev_delete(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_link *dp_link) +{ + qdf_spin_lock_bh(&dp_ctx->dp_link_del_lock); + + dp_info("CDP vdev registered %d, vdev deleted %d", + dp_link->cdp_vdev_registered, + dp_link->cdp_vdev_deleted); + + if (!dp_link->cdp_vdev_registered || dp_link->cdp_vdev_deleted) { + /* CDP vdev is not created/registered or already deleted */ + dp_info("Free dp_link %pK id %d (" QDF_MAC_ADDR_FMT ")", + dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + dp_link->magic = 0; + qdf_mem_free(dp_link); + } else { + /* + * Add it to inactive dp_link list, and it will be freed when + * the CDP vdev gets deleted + */ + dp_info("Add to inactive list dp_link %pK id %d (" + QDF_MAC_ADDR_FMT ")", + dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + TAILQ_INSERT_TAIL(&dp_ctx->inactive_dp_link_list, dp_link, + inactive_list_elem); + dp_link->destroyed = 1; + } + + qdf_spin_unlock_bh(&dp_ctx->dp_link_del_lock); +} + +QDF_STATUS +dp_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) + +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + dp_info("DP VDEV OBJ destroy notification, vdev_id %d", + wlan_vdev_get_id(vdev)); + + dp_link = dp_get_vdev_priv_obj(vdev); + if (!dp_link) { + dp_err("Failed to get DP link obj"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + dp_ctx = dp_intf->dp_ctx; + + qdf_spin_lock_bh(&dp_intf->dp_link_list_lock); + qdf_list_remove_node(&dp_intf->dp_link_list, &dp_link->node); + dp_intf->num_links--; + qdf_spin_unlock_bh(&dp_intf->dp_link_list_lock); + + if (dp_intf->num_links == 0) { + /* + * Interface level operations are stopped when last + * link is deleted + */ + dp_nud_ignore_tracking(dp_intf, true); + dp_nud_reset_tracking(dp_intf); + dp_nud_flush_work(dp_intf); + dp_mic_flush_work(dp_intf); + + if (dp_intf->device_mode == QDF_SAP_MODE || + dp_intf->device_mode == QDF_P2P_GO_MODE) { + status = qdf_event_destroy(&dp_intf->qdf_sta_eap_frm_done_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + dp_err("eap frm done event destroy failed!!"); + return status; + } + dp_intf->txrx_ops.tx.tx = NULL; + dp_intf->sap_tx_block_mask |= DP_TX_FN_CLR; + } + } + + qdf_mem_zero(&dp_link->conn_info, sizeof(struct wlan_dp_conn_info)); + + /* + * If the dp_link which is being destroyed is the default link, + * then find a new link to be made the default link + */ + if (dp_intf->def_link == dp_link) + dp_intf->def_link = + dp_intf_get_next_deflink_candidate(dp_intf, dp_link); + + /* + * Change this to link level, since during link switch, + * it might not go to 0 + */ + status = dp_intf_wait_for_task_complete(dp_intf); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + qdf_spin_lock_bh(&dp_link->vdev_lock); + dp_link->vdev = NULL; + qdf_spin_unlock_bh(&dp_link->vdev_lock); + + qdf_spinlock_destroy(&dp_link->vdev_lock); + + status = wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_COMP_DP, + (void *)dp_link); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to detach dp_link with vdev"); + return status; + } + + dp_link_handle_cdp_vdev_delete(dp_ctx, dp_link); + + return status; +} + +QDF_STATUS +dp_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, void *arg) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_info("DP PDEV OBJ create notification"); + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + obj_mgr_err("psoc is NULL in pdev"); + return QDF_STATUS_E_FAILURE; + } + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Failed to get dp_ctx from psoc"); + return QDF_STATUS_E_FAILURE; + } + status = wlan_objmgr_pdev_component_obj_attach(pdev, + WLAN_COMP_DP, + (void *)dp_ctx, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to attach dp_ctx to pdev"); + return status; + } + + dp_ctx->pdev = pdev; + return status; +} + +QDF_STATUS +dp_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, void *arg) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_info("DP PDEV OBJ destroy notification"); + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + obj_mgr_err("psoc is NULL in pdev"); + return QDF_STATUS_E_FAILURE; + } + + dp_ctx = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_COMP_DP); + if (!dp_ctx) { + dp_err("Failed to get dp_ctx from pdev"); + return QDF_STATUS_E_FAILURE; + } + status = wlan_objmgr_pdev_component_obj_detach(pdev, + WLAN_COMP_DP, + dp_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to detach dp_ctx from pdev"); + return status; + } + if (!dp_ctx->pdev) + dp_err("DP Pdev is NULL"); + + dp_ctx->pdev = NULL; + return status; +} + +QDF_STATUS +dp_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_dp_psoc_context *dp_ctx = gp_dp_ctx; + QDF_STATUS status; + + status = wlan_objmgr_psoc_component_obj_attach( + psoc, WLAN_COMP_DP, + dp_ctx, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to attach psoc component obj"); + return status; + } + + dp_ctx->psoc = psoc; + dp_cfg_init(dp_ctx); + target_if_dp_register_tx_ops(&dp_ctx->sb_ops); + target_if_dp_register_rx_ops(&dp_ctx->nb_ops); + + return status; +} + +QDF_STATUS +dp_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("psoc priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_psoc_component_obj_detach( + psoc, WLAN_COMP_DP, + dp_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to detach psoc component obj"); + return status; + } + + dp_reset_all_intfs_connectivity_stats(dp_ctx); + + return status; +} + +void dp_attach_ctx(struct wlan_dp_psoc_context *dp_ctx) +{ + if (gp_dp_ctx) + dp_debug("already attached global dp ctx"); + gp_dp_ctx = dp_ctx; +} + +void dp_detach_ctx(void) +{ + if (!gp_dp_ctx) { + dp_err("global dp ctx is already detached"); + return; + } + gp_dp_ctx = NULL; +} + +struct wlan_dp_psoc_context *dp_get_context(void) +{ + return gp_dp_ctx; +} + +/** + * dp_hex_string_to_u16_array() - convert a hex string to a uint16 array + * @str: input string + * @int_array: pointer to input array of type uint16 + * @len: pointer to number of elements which the function adds to the array + * @int_array_max_len: maximum number of elements in input uint16 array + * + * This function is used to convert a space separated hex string to an array of + * uint16_t. For example, an input string str = "a b c d" would be converted to + * a unint16 array, int_array = {0xa, 0xb, 0xc, 0xd}, *len = 4. + * This assumes that input value int_array_max_len >= 4. + * + * Return: QDF_STATUS_SUCCESS - if the conversion is successful + * non zero value - if the conversion is a failure + */ +static QDF_STATUS +dp_hex_string_to_u16_array(char *str, uint16_t *int_array, uint8_t *len, + uint8_t int_array_max_len) +{ + char *s = str; + uint32_t val = 0; + + if (!str || !int_array || !len) + return QDF_STATUS_E_INVAL; + + dp_debug("str %pK intArray %pK intArrayMaxLen %d", + s, int_array, int_array_max_len); + + *len = 0; + + while ((s) && (*len < int_array_max_len)) { + /* + * Increment length only if sscanf successfully extracted one + * element. Any other return value means error. Ignore it. + */ + if (sscanf(s, "%x", &val) == 1) { + int_array[*len] = (uint16_t)val; + dp_debug("s %pK val %x intArray[%d]=0x%x", + s, val, *len, int_array[*len]); + *len += 1; + } + s = strpbrk(s, " "); + if (s) + s++; + } + return QDF_STATUS_SUCCESS; +} + +/** + * dp_get_interface() - to get dp interface matching the mode + * @dp_ctx: dp context + * @mode: interface mode + * + * This routine will return the pointer to dp interface matching + * with the passed mode. + * + * Return: pointer to interface or null + */ +static struct +wlan_dp_intf *dp_get_interface(struct wlan_dp_psoc_context *dp_ctx, + enum QDF_OPMODE mode) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_intf *dp_intf_next; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + if (!dp_intf) + continue; + + if (dp_intf->device_mode == mode) + return dp_intf; + } + + return NULL; +} + +void dp_send_rps_ind(struct wlan_dp_intf *dp_intf) +{ + int i; + uint8_t cpu_map_list_len = 0; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_rps_data rps_data; + struct cds_config_info *cds_cfg; + + cds_cfg = cds_get_ini_config(); + if (!cds_cfg) { + dp_err("cds_cfg is NULL"); + return; + } + + rps_data.num_queues = NUM_RX_QUEUES; + + dp_info("cpu_map_list '%s'", dp_ctx->dp_cfg.cpu_map_list); + + /* in case no cpu map list is provided, simply return */ + if (!strlen(dp_ctx->dp_cfg.cpu_map_list)) { + dp_info("no cpu map list found"); + goto err; + } + + if (QDF_STATUS_SUCCESS != + dp_hex_string_to_u16_array(dp_ctx->dp_cfg.cpu_map_list, + rps_data.cpu_map_list, + &cpu_map_list_len, + WLAN_SVC_IFACE_NUM_QUEUES)) { + dp_err("invalid cpu map list"); + goto err; + } + + rps_data.num_queues = + (cpu_map_list_len < rps_data.num_queues) ? + cpu_map_list_len : rps_data.num_queues; + + for (i = 0; i < rps_data.num_queues; i++) { + dp_info("cpu_map_list[%d] = 0x%x", + i, rps_data.cpu_map_list[i]); + } + + strlcpy(rps_data.ifname, qdf_netdev_get_devname(dp_intf->dev), + sizeof(rps_data.ifname)); + dp_ctx->dp_ops.dp_send_svc_nlink_msg(cds_get_radio_index(), + WLAN_SVC_RPS_ENABLE_IND, + &rps_data, sizeof(rps_data)); + + cds_cfg->rps_enabled = true; + + return; + +err: + dp_info("Wrong RPS configuration. enabling rx_thread"); + cds_cfg->rps_enabled = false; +} + +void dp_try_send_rps_ind(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("dp link is NULL"); + return; + } + + dp_intf = dp_link->dp_intf; + if (dp_intf->dp_ctx->rps) + dp_send_rps_ind(dp_intf); +} + +void dp_send_rps_disable_ind(struct wlan_dp_intf *dp_intf) +{ + struct wlan_rps_data rps_data; + struct cds_config_info *cds_cfg; + + cds_cfg = cds_get_ini_config(); + + if (!cds_cfg) { + dp_err("cds_cfg is NULL"); + return; + } + + rps_data.num_queues = NUM_RX_QUEUES; + + dp_info("Set cpu_map_list 0"); + + qdf_mem_zero(&rps_data.cpu_map_list, sizeof(rps_data.cpu_map_list)); + + strlcpy(rps_data.ifname, qdf_netdev_get_devname(dp_intf->dev), + sizeof(rps_data.ifname)); + dp_intf->dp_ctx->dp_ops.dp_send_svc_nlink_msg(cds_get_radio_index(), + WLAN_SVC_RPS_ENABLE_IND, + &rps_data, sizeof(rps_data)); + + cds_cfg->rps_enabled = false; +} + +#ifdef QCA_CONFIG_RPS +void dp_set_rps(uint8_t vdev_id, bool enable) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_ctx = dp_get_context(); + if (!dp_ctx) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(dp_ctx->psoc, + vdev_id, WLAN_DP_ID); + if (!vdev) + return; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (!dp_link) { + dp_comp_vdev_put_ref(vdev); + dp_err_rl("DP link not found for vdev_id: %d", vdev_id); + return; + } + + dp_intf = dp_link->dp_intf; + + dp_info("Set RPS to %d for vdev_id %d", enable, vdev_id); + if (!dp_ctx->rps) { + if (enable) + dp_send_rps_ind(dp_intf); + else + dp_send_rps_disable_ind(dp_intf); + } + dp_comp_vdev_put_ref(vdev); +} +#endif + +void dp_set_rx_mode_rps(bool enable) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + struct cds_config_info *cds_cfg; + + dp_ctx = dp_get_context(); + cds_cfg = cds_get_ini_config(); + if (!dp_ctx || !cds_cfg) + return; + + dp_intf = dp_get_interface(dp_ctx, QDF_SAP_MODE); + if (!dp_intf) + return; + + if (!dp_intf->dp_ctx->rps && cds_cfg->uc_offload_enabled) { + if (enable && !cds_cfg->rps_enabled) + dp_send_rps_ind(dp_intf); + else if (!enable && cds_cfg->rps_enabled) + dp_send_rps_disable_ind(dp_intf); + } +} + +void dp_set_rps_cpu_mask(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_intf *dp_intf_next; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + if (!dp_intf) + continue; + + dp_send_rps_ind(dp_intf); + } +} + +void dp_try_set_rps_cpu_mask(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("dp context is NULL"); + return; + } + + if (dp_ctx->dynamic_rps) + dp_set_rps_cpu_mask(dp_ctx); +} + +void dp_clear_rps_cpu_mask(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_intf *dp_intf_next; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + if (!dp_intf) + continue; + + dp_send_rps_disable_ind(dp_intf); + } +} + +QDF_STATUS dp_get_arp_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct dp_rsp_stats *rsp) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + rsp->vdev_id, + WLAN_DP_ID); + if (!vdev) { + dp_err("Can't get vdev by vdev_id:%d", rsp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + dp_link = dp_get_vdev_priv_obj(vdev); + if (!dp_link) { + dp_err("Unable to get DP link for vdev_id %d", rsp->vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + + dp_info("rsp->arp_req_enqueue :%x", rsp->arp_req_enqueue); + dp_info("rsp->arp_req_tx_success :%x", rsp->arp_req_tx_success); + dp_info("rsp->arp_req_tx_failure :%x", rsp->arp_req_tx_failure); + dp_info("rsp->arp_rsp_recvd :%x", rsp->arp_rsp_recvd); + dp_info("rsp->out_of_order_arp_rsp_drop_cnt :%x", + rsp->out_of_order_arp_rsp_drop_cnt); + dp_info("rsp->dad_detected :%x", rsp->dad_detected); + dp_info("rsp->connect_status :%x", rsp->connect_status); + dp_info("rsp->ba_session_establishment_status :%x", + rsp->ba_session_establishment_status); + + dp_intf->dp_stats.arp_stats.rx_fw_cnt = rsp->arp_rsp_recvd; + dp_intf->dad |= rsp->dad_detected; + dp_intf->con_status = rsp->connect_status; + + /* Flag true indicates connectivity check stats present. */ + if (rsp->connect_stats_present) { + dp_info("rsp->tcp_ack_recvd :%x", rsp->tcp_ack_recvd); + dp_info("rsp->icmpv4_rsp_recvd :%x", rsp->icmpv4_rsp_recvd); + dp_intf->dp_stats.tcp_stats.rx_fw_cnt = rsp->tcp_ack_recvd; + dp_intf->dp_stats.icmpv4_stats.rx_fw_cnt = + rsp->icmpv4_rsp_recvd; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_OBJMGR_REF_ID_TRACE +struct wlan_objmgr_vdev * +__dp_objmgr_get_vdev_by_user(struct wlan_dp_link *dp_link, + wlan_objmgr_ref_dbgid id, + const char *func, int line) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!dp_link) + return NULL; + + qdf_spin_lock_bh(&dp_link->vdev_lock); + vdev = dp_link->vdev; + if (vdev) { + status = wlan_objmgr_vdev_try_get_ref_debug(vdev, id, func, + line); + if (QDF_IS_STATUS_ERROR(status)) + vdev = NULL; + } + qdf_spin_unlock_bh(&dp_link->vdev_lock); + + if (!vdev) + dp_debug("VDEV is NULL (via %s, id %d)", func, id); + + return vdev; +} + +void +__dp_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func, + int line) +{ + if (!vdev) { + dp_err("VDEV is NULL (via %s, id %d)", func, id); + return; + } + + wlan_objmgr_vdev_release_ref_debug(vdev, id, func, line); +} +#else +struct wlan_objmgr_vdev * +__dp_objmgr_get_vdev_by_user(struct wlan_dp_link *dp_link, + wlan_objmgr_ref_dbgid id, + const char *func) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!dp_link) + return NULL; + + qdf_spin_lock_bh(&dp_link->vdev_lock); + vdev = dp_link->vdev; + if (vdev) { + status = wlan_objmgr_vdev_try_get_ref(vdev, id); + if (QDF_IS_STATUS_ERROR(status)) + vdev = NULL; + } + qdf_spin_unlock_bh(&dp_link->vdev_lock); + + if (!vdev) + dp_debug("VDEV is NULL (via %s, id %d)", func, id); + + return vdev; +} + +void +__dp_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func) +{ + if (!vdev) { + dp_err("VDEV is NULL (via %s, id %d)", func, id); + return; + } + + wlan_objmgr_vdev_release_ref(vdev, id); +} +#endif /* WLAN_OBJMGR_REF_ID_TRACE */ + +bool dp_is_data_stall_event_enabled(uint32_t evt) +{ + uint32_t bitmap = cdp_cfg_get(cds_get_context(QDF_MODULE_ID_SOC), + cfg_dp_enable_data_stall); + + if (bitmap & DP_DATA_STALL_ENABLE || bitmap & evt) + return true; + + return false; +} + +#ifdef WLAN_SUPPORT_RX_FISA +static inline QDF_STATUS +wlan_dp_rx_fisa_attach_target(struct wlan_dp_psoc_context *dp_ctx) +{ + QDF_STATUS status; + + status = dp_rx_fst_target_config(dp_ctx); + if (status != QDF_STATUS_SUCCESS && + status != QDF_STATUS_E_NOSUPPORT) { + dp_err("Failed to send htt fst setup config message to target"); + return status; + } + + /* return success to let init process go */ + if (status == QDF_STATUS_E_NOSUPPORT) + return QDF_STATUS_SUCCESS; + + if (status == QDF_STATUS_SUCCESS) { + status = dp_rx_fisa_config(dp_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to send htt FISA config message to target"); + return status; + } + } + + return status; +} + +static inline QDF_STATUS +wlan_dp_rx_fisa_attach(struct wlan_dp_psoc_context *dp_ctx) +{ + return dp_rx_fst_attach(dp_ctx); +} + +static inline void wlan_dp_rx_fisa_detach(struct wlan_dp_psoc_context *dp_ctx) +{ + return dp_rx_fst_detach(dp_ctx); +} + +static inline void +wlan_dp_rx_fisa_cmem_attach(struct wlan_dp_psoc_context *dp_ctx) +{ + dp_ctx->fst_cmem_base = cdp_get_fst_cem_base(dp_ctx->cdp_soc, + DP_CMEM_FST_SIZE); +} + +static inline QDF_STATUS +wlan_dp_fisa_suspend(struct wlan_dp_psoc_context *dp_ctx) +{ + dp_suspend_fse_cache_flush(dp_ctx); + dp_rx_fst_update_pm_suspend_status(dp_ctx, true); + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_dp_fisa_resume(struct wlan_dp_psoc_context *dp_ctx) +{ + dp_resume_fse_cache_flush(dp_ctx); + dp_rx_fst_update_pm_suspend_status(dp_ctx, false); + dp_rx_fst_requeue_wq(dp_ctx); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +wlan_dp_rx_fisa_attach_target(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_dp_rx_fisa_attach(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_dp_rx_fisa_detach(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +wlan_dp_rx_fisa_cmem_attach(struct wlan_dp_psoc_context *dp_ctx) +{ +} + +static inline QDF_STATUS +wlan_dp_fisa_suspend(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_dp_fisa_resume(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void wlan_dp_link_cdp_vdev_delete_notification(void *context) +{ + struct wlan_dp_link *dp_link = (struct wlan_dp_link *)context; + struct wlan_dp_link *tmp_dp_link; + struct wlan_dp_psoc_context *dp_ctx = NULL; + uint8_t found = 0; + + /* dp_link will not be freed before this point. */ + if (!dp_link) { + dp_info("dp_link is null"); + return; + } + + dp_info("dp_link %pK id %d", dp_link, dp_link->link_id); + dp_ctx = dp_get_context(); + + qdf_spin_lock_bh(&dp_ctx->dp_link_del_lock); + + if (dp_link->destroyed) { + /* + * dp_link has been destroyed as a part of vdev_obj_destroy + * notification and will be present in inactive list + */ + TAILQ_FOREACH(tmp_dp_link, &dp_ctx->inactive_dp_link_list, + inactive_list_elem) { + if (tmp_dp_link == dp_link) { + found = 1; + break; + } + } + + if (found) + TAILQ_REMOVE(&dp_ctx->inactive_dp_link_list, dp_link, + inactive_list_elem); + else + qdf_assert_always(0); + + dp_info("Free dp_link %pK id %d (" QDF_MAC_ADDR_FMT ")", + dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + dp_link->magic = 0; + qdf_mem_free(dp_link); + } else { + /* dp_link not yet destroyed */ + dp_info("CDP vdev delete for dp_link %pK id %d (" + QDF_MAC_ADDR_FMT ")", + dp_link, dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + dp_link->cdp_vdev_deleted = 1; + } + + qdf_spin_unlock_bh(&dp_ctx->dp_link_del_lock); +} + +QDF_STATUS __wlan_dp_runtime_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_ctx = dp_get_context(); + status = cdp_runtime_suspend(soc, pdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wlan_dp_fisa_suspend(dp_ctx); + + return status; +} + +QDF_STATUS __wlan_dp_runtime_resume(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_ctx = dp_get_context(); + status = cdp_runtime_resume(soc, pdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wlan_dp_fisa_resume(dp_ctx); + + return status; +} + +QDF_STATUS __wlan_dp_bus_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_ctx = dp_get_context(); + + status = cdp_bus_suspend(soc, pdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wlan_dp_fisa_suspend(dp_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return status; +} + +QDF_STATUS __wlan_dp_bus_resume(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + + dp_ctx = dp_get_context(); + + status = cdp_bus_resume(soc, pdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wlan_dp_fisa_resume(dp_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return status; +} + +void *wlan_dp_txrx_soc_attach(struct dp_txrx_soc_attach_params *params, + bool *is_wifi3_0_target) +{ + struct wlan_dp_psoc_context *dp_ctx; + void *dp_soc = NULL; + struct hif_opaque_softc *hif_context; + HTC_HANDLE htc_ctx = cds_get_context(QDF_MODULE_ID_HTC); + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + dp_ctx = dp_get_context(); + hif_context = cds_get_context(QDF_MODULE_ID_HIF); + + if (TARGET_TYPE_QCA6290 == params->target_type || + TARGET_TYPE_QCA6390 == params->target_type || + TARGET_TYPE_QCA6490 == params->target_type || + TARGET_TYPE_QCA6750 == params->target_type) { + dp_soc = cdp_soc_attach(LITHIUM_DP, hif_context, + params->target_psoc, htc_ctx, + qdf_ctx, params->dp_ol_if_ops); + + if (dp_soc) + if (!cdp_soc_init(dp_soc, LITHIUM_DP, + hif_context, params->target_psoc, + htc_ctx, qdf_ctx, + params->dp_ol_if_ops)) + goto err_soc_detach; + *is_wifi3_0_target = true; + } else if (params->target_type == TARGET_TYPE_KIWI || + params->target_type == TARGET_TYPE_MANGO || + params->target_type == TARGET_TYPE_PEACH) { + dp_soc = cdp_soc_attach(BERYLLIUM_DP, hif_context, + params->target_psoc, + htc_ctx, qdf_ctx, + params->dp_ol_if_ops); + if (dp_soc) + if (!cdp_soc_init(dp_soc, BERYLLIUM_DP, hif_context, + params->target_psoc, htc_ctx, + qdf_ctx, params->dp_ol_if_ops)) + goto err_soc_detach; + *is_wifi3_0_target = true; + } else if (params->target_type == TARGET_TYPE_WCN6450) { + dp_soc = + cdp_soc_attach(RHINE_DP, hif_context, + params->target_psoc, htc_ctx, + qdf_ctx, params->dp_ol_if_ops); + if (dp_soc) + if (!cdp_soc_init(dp_soc, RHINE_DP, hif_context, + params->target_psoc, htc_ctx, + qdf_ctx, params->dp_ol_if_ops)) + goto err_soc_detach; + *is_wifi3_0_target = true; + } else { + dp_soc = cdp_soc_attach(MOB_DRV_LEGACY_DP, hif_context, + params->target_psoc, htc_ctx, qdf_ctx, + params->dp_ol_if_ops); + } + + if (!dp_soc) + return NULL; + + dp_ctx->cdp_soc = dp_soc; + wlan_dp_rx_fisa_cmem_attach(dp_ctx); + + return dp_soc; + +err_soc_detach: + cdp_soc_detach(dp_soc); + dp_soc = NULL; + + return dp_soc; +} + +void wlan_dp_txrx_soc_detach(ol_txrx_soc_handle soc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + + cdp_soc_deinit(soc); + cdp_soc_detach(soc); + + if (dp_ctx) + dp_ctx->cdp_soc = NULL; +} + +QDF_STATUS wlan_dp_txrx_attach_target(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS qdf_status; + int errno; + + dp_ctx = dp_get_context(); + + qdf_status = cdp_soc_attach_target(soc); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + dp_err("Failed to attach soc target; status:%d", qdf_status); + return qdf_status; + } + + qdf_status = wlan_dp_rx_fisa_attach_target(dp_ctx); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + errno = cdp_pdev_attach_target(soc, pdev_id); + if (errno) { + dp_err("Failed to attach pdev target; errno:%d", errno); + qdf_status = QDF_STATUS_E_FAILURE; + goto err_soc_detach_target; + } + + return qdf_status; + +err_soc_detach_target: + /* NOP */ + return qdf_status; +} + +QDF_STATUS wlan_dp_txrx_pdev_attach(ol_txrx_soc_handle soc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct cdp_pdev_attach_params pdev_params = { 0 }; + QDF_STATUS qdf_status; + + dp_ctx = dp_get_context(); + + pdev_params.htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + pdev_params.qdf_osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + pdev_params.pdev_id = 0; + + qdf_status = cdp_pdev_attach(cds_get_context(QDF_MODULE_ID_SOC), + &pdev_params); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + /* FISA Attach */ + qdf_status = wlan_dp_rx_fisa_attach(dp_ctx); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + /* return success to let init process go */ + if (qdf_status == QDF_STATUS_E_NOSUPPORT) + return QDF_STATUS_SUCCESS; + + wlan_dp_txrx_pdev_detach(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, false); + return qdf_status; + } + + return qdf_status; +} + +QDF_STATUS wlan_dp_txrx_pdev_detach(ol_txrx_soc_handle soc, uint8_t pdev_id, + int force) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + wlan_dp_rx_fisa_detach(dp_ctx); + return cdp_pdev_detach(soc, pdev_id, force); +} + +#ifdef FEATURE_DIRECT_LINK +/** + * dp_lpass_h2t_tx_complete() - Copy completion handler for LPASS data + * message service + * @ctx: DP Direct Link context + * @pkt: htc packet + * + * Return: None + */ +static void dp_lpass_h2t_tx_complete(void *ctx, HTC_PACKET *pkt) +{ + dp_info("Unexpected lpass tx complete trigger"); + qdf_assert(0); +} + +/** + * dp_lpass_t2h_msg_handler() - target to host message handler for LPASS data + * message service + * @ctx: DP Direct Link context + * @pkt: htc packet + * + * Return: None + */ +static void dp_lpass_t2h_msg_handler(void *ctx, HTC_PACKET *pkt) +{ + dp_info("Unexpected receive msg trigger for lpass service"); + qdf_assert(0); +} + +/** + * dp_lpass_connect_htc_service() - Connect lpass data message htc service + * @dp_direct_link_ctx: DP Direct Link context + * + * Return: QDF status + */ +static QDF_STATUS +dp_lpass_connect_htc_service(struct dp_direct_link_context *dp_direct_link_ctx) +{ + struct htc_service_connect_req connect = {0}; + struct htc_service_connect_resp response = {0}; + HTC_HANDLE htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + QDF_STATUS status; + + if (!htc_handle) + return QDF_STATUS_E_FAILURE; + + connect.EpCallbacks.pContext = dp_direct_link_ctx; + connect.EpCallbacks.EpTxComplete = dp_lpass_h2t_tx_complete; + connect.EpCallbacks.EpRecv = dp_lpass_t2h_msg_handler; + + /* disable flow control for LPASS data message service */ + connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + connect.service_id = LPASS_DATA_MSG_SVC; + + status = htc_connect_service(htc_handle, &connect, &response); + + if (status != QDF_STATUS_SUCCESS) { + dp_err("LPASS_DATA_MSG connect service failed"); + return status; + } + + dp_direct_link_ctx->lpass_ep_id = response.Endpoint; + + dp_err("LPASS_DATA_MSG connect service successful"); + + return status; +} + +/** + * dp_direct_link_refill_ring_init() - Initialize refill ring that would be used + * for Direct Link DP + * @direct_link_ctx: DP Direct Link context + * + * Return: QDF status + */ +static QDF_STATUS +dp_direct_link_refill_ring_init(struct dp_direct_link_context *direct_link_ctx) +{ + struct cdp_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t pdev_id; + + if (!soc) + return QDF_STATUS_E_FAILURE; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(direct_link_ctx->dp_ctx->pdev); + + direct_link_ctx->direct_link_refill_ring_hdl = + dp_setup_direct_link_refill_ring(soc, + pdev_id); + if (!direct_link_ctx->direct_link_refill_ring_hdl) { + dp_err("Refill ring init for Direct Link failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_direct_link_refill_ring_deinit() - De-initialize refill ring that would be + * used for Direct Link DP + * @dlink_ctx: DP Direct Link context + * + * Return: None + */ +static void +dp_direct_link_refill_ring_deinit(struct dp_direct_link_context *dlink_ctx) +{ + struct cdp_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t pdev_id; + + if (!soc) + return; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(dlink_ctx->dp_ctx->pdev); + dp_destroy_direct_link_refill_ring(soc, pdev_id); + dlink_ctx->direct_link_refill_ring_hdl = NULL; +} + +QDF_STATUS dp_direct_link_init(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_direct_link_context *dp_direct_link_ctx; + QDF_STATUS status; + + if (!pld_is_direct_link_supported(dp_ctx->qdf_dev->dev)) { + dp_info("FW does not support Direct Link"); + return QDF_STATUS_SUCCESS; + } + + dp_direct_link_ctx = qdf_mem_malloc(sizeof(*dp_direct_link_ctx)); + if (!dp_direct_link_ctx) { + dp_err("Failed to allocate memory for DP Direct Link context"); + return QDF_STATUS_E_NOMEM; + } + + dp_direct_link_ctx->dp_ctx = dp_ctx; + + status = dp_lpass_connect_htc_service(dp_direct_link_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to connect to LPASS data msg service"); + qdf_mem_free(dp_direct_link_ctx); + return status; + } + + status = dp_direct_link_refill_ring_init(dp_direct_link_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(dp_direct_link_ctx); + return status; + } + + status = dp_wfds_init(dp_direct_link_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to initialize QMI for Direct Link"); + dp_direct_link_refill_ring_deinit(dp_ctx->dp_direct_link_ctx); + qdf_mem_free(dp_direct_link_ctx); + return status; + } + qdf_mutex_create(&dp_ctx->dp_direct_link_lock); + + dp_ctx->dp_direct_link_ctx = dp_direct_link_ctx; + + return status; +} + +void dp_direct_link_deinit(struct wlan_dp_psoc_context *dp_ctx, bool is_ssr) +{ + struct wlan_dp_intf *dp_intf; + + if (!pld_is_direct_link_supported(dp_ctx->qdf_dev->dev)) + return; + + if (!dp_ctx->dp_direct_link_ctx) + return; + + for (dp_get_front_intf_no_lock(dp_ctx, &dp_intf); dp_intf; + dp_get_next_intf_no_lock(dp_ctx, dp_intf, &dp_intf)) { + if (dp_intf->device_mode == QDF_SAP_MODE) + dp_config_direct_link(dp_intf, false, false); + } + + dp_wfds_deinit(dp_ctx->dp_direct_link_ctx, is_ssr); + dp_direct_link_refill_ring_deinit(dp_ctx->dp_direct_link_ctx); + qdf_mutex_destroy(&dp_ctx->dp_direct_link_lock); + qdf_mem_free(dp_ctx->dp_direct_link_ctx); + dp_ctx->dp_direct_link_ctx = NULL; +} + +QDF_STATUS dp_config_direct_link(struct wlan_dp_intf *dp_intf, + bool config_direct_link, + bool enable_low_latency) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct direct_link_info *config = &dp_intf->direct_link_config; + struct wlan_dp_link *dp_link, *dp_link_next; + void *htc_handle; + bool prev_ll, update_ll, vote_link; + cdp_config_param_type vdev_param = {0}; + QDF_STATUS status; + + if (!dp_ctx || !dp_ctx->psoc) { + dp_err("DP Handle is NULL"); + return QDF_STATUS_E_CANCELED; + } + + if (!dp_ctx->dp_direct_link_ctx) { + dp_err("Direct link not enabled"); + return QDF_STATUS_SUCCESS; + } + + htc_handle = lmac_get_htc_hdl(dp_ctx->psoc); + if (!htc_handle) { + dp_err("HTC handle is NULL"); + return QDF_STATUS_E_EMPTY; + } + + qdf_mutex_acquire(&dp_ctx->dp_direct_link_lock); + prev_ll = config->low_latency; + update_ll = config_direct_link ? enable_low_latency : prev_ll; + vote_link = config->config_set ^ config_direct_link; + config->config_set = config_direct_link; + config->low_latency = enable_low_latency; + dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) { + vdev_param.cdp_vdev_tx_to_fw = config_direct_link; + status = cdp_txrx_set_vdev_param( + wlan_psoc_get_dp_handle(dp_ctx->psoc), + dp_link->link_id, CDP_VDEV_TX_TO_FW, + vdev_param); + if (QDF_IS_STATUS_ERROR(status)) + break; + } + + if (config_direct_link) { + if (vote_link) + htc_vote_link_up(htc_handle, + HTC_LINK_VOTE_DIRECT_LINK_USER_ID); + if (update_ll) + hif_prevent_link_low_power_states( + htc_get_hif_device(htc_handle)); + else if (prev_ll) + hif_allow_link_low_power_states( + htc_get_hif_device(htc_handle)); + dp_info("Direct link config set. Low link latency enabled: %d", + enable_low_latency); + } else { + if (vote_link) + htc_vote_link_down(htc_handle, + HTC_LINK_VOTE_DIRECT_LINK_USER_ID); + if (update_ll) + hif_allow_link_low_power_states( + htc_get_hif_device(htc_handle)); + dp_info("Direct link config cleared."); + } + qdf_mutex_release(&dp_ctx->dp_direct_link_lock); + + return status; +} +#endif + +#ifdef WLAN_DP_PROFILE_SUPPORT +struct wlan_dp_memory_profile_info * +wlan_dp_get_profile_info(void) +{ + return &g_dp_profile_info; +} + +QDF_STATUS wlan_dp_select_profile_cfg(struct wlan_objmgr_psoc *psoc) +{ + struct pld_soc_info info = {0}; + struct pld_wlan_hw_cap_info *hw_cap_info; + qdf_device_t qdf_dev; + bool apply_profile = false; + int ret; + + apply_profile = cfg_get(psoc, + CFG_DP_APPLY_MEM_PROFILE); + if (!apply_profile) + return QDF_STATUS_E_NOSUPPORT; + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + if (!qdf_dev) + return QDF_STATUS_E_FAILURE; + + ret = pld_get_soc_info(qdf_dev->dev, &info); + if (ret) { + dp_err("profile selection failed unable to H.W caps reason:%u", + qdf_status_from_os_return(ret)); + return qdf_status_from_os_return(ret); + } + + hw_cap_info = &info.hw_cap_info; + /* Based on supported H.W caps select required memory profile */ + if (hw_cap_info->nss == PLD_WLAN_HW_CAP_NSS_1x1 && + hw_cap_info->bw == PLD_WLAN_HW_CHANNEL_BW_80MHZ && + hw_cap_info->qam == PLD_WLAN_HW_QAM_1K) { + g_dp_profile_info.is_selected = true; + g_dp_profile_info.ctx = wlan_dp_1x1_he80_1kqam; + g_dp_profile_info.size = QDF_ARRAY_SIZE(wlan_dp_1x1_he80_1kqam); + dp_info("DP profile selected is 1x1_HE80_1KQAM based"); + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_RX_PREALLOC_BUFFER_POOL +static void +wlan_dp_rx_refill_pool_cfg_sync_profile(struct cdp_soc_t *cdp_soc, + struct wlan_dp_memory_profile_ctx *profile_ctx) +{ + cdp_config_param_type val; + QDF_STATUS status; + int cur_val; + + status = cdp_txrx_get_psoc_param(cdp_soc, CDP_CFG_RX_REFILL_POOL_NUM, + &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_rx_refill_buf_pool_size != profile_ctx->size) { + cur_val = val.cdp_rx_refill_buf_pool_size; + val.cdp_rx_refill_buf_pool_size = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_RX_REFILL_POOL_NUM, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + return; + } + dp_info("current Rx refill pool size:%u synced with profile:%u", + cur_val, profile_ctx->size); + } +} +#else +static inline void +wlan_dp_rx_refill_pool_cfg_sync_profile(struct cdp_soc_t *cdp_soc, + struct wlan_dp_memory_profile_ctx *profile_ctx) +{ +} +#endif + +void wlan_dp_soc_cfg_sync_profile(struct cdp_soc_t *cdp_soc) +{ + struct wlan_dp_memory_profile_info *profile_info; + struct wlan_dp_memory_profile_ctx *profile_ctx; + cdp_config_param_type val = {0}; + QDF_STATUS status; + int cur_val, i; + + profile_info = wlan_dp_get_profile_info(); + if (!profile_info->is_selected) + return; + + for (i = 0; i < profile_info->size; i++) { + profile_ctx = &profile_info->ctx[i]; + qdf_mem_zero(&val, sizeof(cdp_config_param_type)); + + switch (profile_ctx->param_type) { + case DP_TX_DESC_NUM_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_TX_DESC_NUM, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_tx_desc_num != profile_ctx->size) { + cur_val = val.cdp_tx_desc_num; + val.cdp_tx_desc_num = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_TX_DESC_NUM, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current Tx desc num:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_TX_EXT_DESC_NUM_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_TX_EXT_DESC_NUM, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_tx_ext_desc_num != profile_ctx->size) { + cur_val = val.cdp_tx_ext_desc_num; + val.cdp_tx_ext_desc_num = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_TX_EXT_DESC_NUM, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current Ext Tx desc num:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_TX_RING_SIZE_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_TX_RING_SIZE, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_tx_ring_size != profile_ctx->size) { + cur_val = val.cdp_tx_ring_size; + val.cdp_tx_ring_size = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_TX_RING_SIZE, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current Tx Ring size:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_TX_COMPL_RING_SIZE_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_TX_COMPL_RING_SIZE, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_tx_comp_ring_size != profile_ctx->size) { + cur_val = val.cdp_tx_comp_ring_size; + val.cdp_tx_comp_ring_size = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_TX_COMPL_RING_SIZE, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current Tx Comp Ring size:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_RX_SW_DESC_NUM_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_RX_SW_DESC_NUM, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_rx_sw_desc_num != profile_ctx->size) { + cur_val = val.cdp_rx_sw_desc_num; + val.cdp_rx_sw_desc_num = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_RX_SW_DESC_NUM, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current Rx desc num:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_REO_DST_RING_SIZE_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_REO_DST_RING_SIZE, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_reo_dst_ring_size != profile_ctx->size) { + cur_val = val.cdp_reo_dst_ring_size; + val.cdp_reo_dst_ring_size = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_REO_DST_RING_SIZE, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current Rx Ring size:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_RXDMA_REFILL_RING_SIZE_CFG: + status = cdp_txrx_get_psoc_param(cdp_soc, + CDP_CFG_RXDMA_REFILL_RING_SIZE, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_rxdma_refill_ring_size != profile_ctx->size) { + cur_val = val.cdp_rxdma_refill_ring_size; + val.cdp_rxdma_refill_ring_size = profile_ctx->size; + if (cdp_txrx_set_psoc_param(cdp_soc, + CDP_CFG_RXDMA_REFILL_RING_SIZE, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + break; + } + dp_info("current RXDMA refill ring size:%u synced with profile:%u", cur_val, profile_ctx->size); + } + break; + case DP_RX_REFILL_POOL_NUM_CFG: + wlan_dp_rx_refill_pool_cfg_sync_profile(cdp_soc, + profile_ctx); + break; + default: + dp_debug("Unknown profile param type:%u", profile_ctx->param_type); + break; + } + } +} + +void wlan_dp_pdev_cfg_sync_profile(struct cdp_soc_t *cdp_soc, uint8_t pdev_id) +{ + struct wlan_dp_memory_profile_info *profile_info; + struct wlan_dp_memory_profile_ctx *profile_ctx; + cdp_config_param_type val = {0}; + QDF_STATUS status; + int cur_val, i; + + profile_info = wlan_dp_get_profile_info(); + if (!profile_info->is_selected) + return; + + for (i = 0; i < profile_info->size; i++) { + profile_ctx = &profile_info->ctx[i]; + if (profile_ctx->param_type == DP_RXDMA_BUF_RING_SIZE_CFG) { + status = cdp_txrx_get_pdev_param(cdp_soc, pdev_id, + CDP_CONFIG_RXDMA_BUF_RING_SIZE, &val); + if (QDF_IS_STATUS_SUCCESS(status) && + val.cdp_rxdma_buf_ring_size != profile_ctx->size) { + cur_val = val.cdp_rxdma_buf_ring_size; + val.cdp_rxdma_buf_ring_size = profile_ctx->size; + if (cdp_txrx_set_pdev_param(cdp_soc, pdev_id, + CDP_CONFIG_RXDMA_BUF_RING_SIZE, val)) { + dp_err("unable to sync param type:%u", profile_ctx->param_type); + return; + } + dp_info("current RXDMA buf ring size:%u synced with profile:%u", cur_val, profile_ctx->size); + } + return; + } + } + + dp_err("pdev based config item not found in profile table"); +} +#endif + +void __wlan_dp_update_def_link(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_mac, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + struct wlan_dp_psoc_context *dp_ctx; + struct qdf_mac_addr zero_addr = QDF_MAC_ADDR_ZERO_INIT; + + dp_ctx = dp_psoc_get_priv(psoc); + + dp_intf = dp_get_intf_by_macaddr(dp_ctx, intf_mac); + if (!dp_intf) { + dp_err("DP interface not found addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(intf_mac->bytes)); + QDF_BUG(0); + return; + } + + dp_link = dp_get_vdev_priv_obj(vdev); + if (dp_link && dp_link->dp_intf == dp_intf) { + dp_info("change dp_intf %pK(" QDF_MAC_ADDR_FMT + ") def_link %d(" QDF_MAC_ADDR_FMT ") -> %d(" + QDF_MAC_ADDR_FMT ")", + dp_intf, QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes), + dp_intf->def_link->link_id, + QDF_MAC_ADDR_REF(dp_intf->def_link->mac_addr.bytes), + dp_link->link_id, + QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes)); + dp_intf->def_link = dp_link; + return; + } + + dp_info("Update failed dp_intf %pK(" QDF_MAC_ADDR_FMT ") from %pK(" + QDF_MAC_ADDR_FMT ") to %pK(" QDF_MAC_ADDR_FMT ") (intf %pK(" + QDF_MAC_ADDR_FMT ") id %d) ", + dp_intf, QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes), + dp_intf->def_link, + QDF_MAC_ADDR_REF(dp_intf->def_link->mac_addr.bytes), + dp_link, dp_link ? QDF_MAC_ADDR_REF(dp_link->mac_addr.bytes) : + QDF_MAC_ADDR_REF(zero_addr.bytes), + dp_link ? dp_link->dp_intf : NULL, + dp_link ? QDF_MAC_ADDR_REF(dp_link->dp_intf->mac_addr.bytes) : + QDF_MAC_ADDR_REF(zero_addr.bytes), + dp_link ? dp_link->link_id : WLAN_INVALID_LINK_ID); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_nud_tracking.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_nud_tracking.c new file mode 100644 index 0000000000..c2c8c0b286 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_nud_tracking.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nud event tracking main function definitions + */ + +#include "osif_sync.h" +#include "wlan_dp_main.h" +#include "wlan_dlm_ucfg_api.h" +#include "wlan_dp_cfg.h" +#include +#include "wlan_cm_roam_ucfg_api.h" +#include +#include "wlan_dp_nud_tracking.h" +#include "wlan_vdev_mgr_api.h" + +#ifdef WLAN_NUD_TRACKING +/** + * dp_txrx_get_tx_ack_count() - Get Tx Ack count + * @dp_intf: Pointer to dp_intf + * + * Return: number of Tx ack count + */ +static uint32_t dp_txrx_get_tx_ack_count(struct wlan_dp_intf *dp_intf) +{ + struct cdp_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_dp_link *dp_link; + struct wlan_dp_link *dp_link_next; + uint32_t ack_count = 0; + + dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) { + ack_count += cdp_get_tx_ack_stats(soc, dp_link->link_id); + } + + return ack_count; +} + +void dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_copy(dp_intf->nud_tracking.gw_mac_addr.bytes, + gw_mac_addr.bytes, + sizeof(struct qdf_mac_addr)); + dp_intf->nud_tracking.is_gw_updated = true; +} + +void dp_nud_incr_gw_rx_pkt_cnt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr) +{ + struct dp_nud_tracking_info *nud_tracking = &dp_intf->nud_tracking; + + if (!nud_tracking->is_gw_rx_pkt_track_enabled) + return; + + if (!nud_tracking->is_gw_updated) + return; + + if (qdf_is_macaddr_equal(&nud_tracking->gw_mac_addr, + mac_addr)) + qdf_atomic_inc(&nud_tracking->tx_rx_stats.gw_rx_packets); +} + +void dp_nud_flush_work(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("Flush the NUD work"); + qdf_disable_work(&dp_intf->nud_tracking.nud_event_work); + } +} + +void dp_nud_deinit_tracking(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("DeInitialize the NUD tracking"); + qdf_destroy_work(NULL, &dp_intf->nud_tracking.nud_event_work); + } +} + +void dp_nud_ignore_tracking(struct wlan_dp_intf *dp_intf, bool ignoring) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) + dp_intf->nud_tracking.ignore_nud_tracking = ignoring; +} + +void dp_nud_reset_tracking(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("Reset the NUD tracking"); + + qdf_zero_macaddr(&dp_intf->nud_tracking.gw_mac_addr); + dp_intf->nud_tracking.is_gw_updated = false; + qdf_mem_zero(&dp_intf->nud_tracking.tx_rx_stats, + sizeof(struct dp_nud_tx_rx_stats)); + + dp_intf->nud_tracking.curr_state = DP_NUD_NONE; + qdf_atomic_set(&dp_intf + ->nud_tracking.tx_rx_stats.gw_rx_packets, 0); + } +} + +/** + * dp_nud_stats_info() - display wlan NUD stats info + * @dp_intf: Pointer to dp_intf + * + * Return: None + */ +static void dp_nud_stats_info(struct wlan_dp_intf *dp_intf) +{ + struct wlan_objmgr_vdev *vdev; + struct dp_nud_tx_rx_stats *tx_rx_stats = + &dp_intf->nud_tracking.tx_rx_stats; + struct wlan_dp_psoc_callbacks *cb = &dp_intf->dp_ctx->dp_ops; + uint32_t pause_map; + + vdev = dp_objmgr_get_vdev_by_user(dp_intf->def_link, WLAN_DP_ID); + if (!vdev) { + return; + } + + dp_info("**** NUD STATS: ****"); + dp_info("NUD Probe Tx : %d", tx_rx_stats->pre_tx_packets); + dp_info("NUD Probe Ack : %d", tx_rx_stats->pre_tx_acked); + dp_info("NUD Probe Rx : %d", tx_rx_stats->pre_rx_packets); + dp_info("NUD Failure Tx : %d", tx_rx_stats->post_tx_packets); + dp_info("NUD Failure Ack : %d", tx_rx_stats->post_tx_acked); + dp_info("NUD Failure Rx : %d", tx_rx_stats->post_rx_packets); + dp_info("NUD Gateway Rx : %d", + qdf_atomic_read(&tx_rx_stats->gw_rx_packets)); + + cb->os_if_dp_nud_stats_info(vdev); + + pause_map = cb->dp_get_pause_map(cb->callback_ctx, + dp_intf->dev); + dp_info("Current pause_map value %x", pause_map); + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); +} + +/** + * dp_nud_capture_stats() - capture wlan NUD stats + * @dp_intf: Pointer to dp_intf + * @nud_state: NUD state for which stats to capture + * + * Return: None + */ +static void dp_nud_capture_stats(struct wlan_dp_intf *dp_intf, + uint8_t nud_state) +{ + switch (nud_state) { + case DP_NUD_INCOMPLETE: + case DP_NUD_PROBE: + dp_intf->nud_tracking.tx_rx_stats.pre_tx_packets = + dp_intf->stats.tx_packets; + dp_intf->nud_tracking.tx_rx_stats.pre_rx_packets = + dp_intf->stats.rx_packets; + dp_intf->nud_tracking.tx_rx_stats.pre_tx_acked = + dp_txrx_get_tx_ack_count(dp_intf); + break; + case DP_NUD_FAILED: + dp_intf->nud_tracking.tx_rx_stats.post_tx_packets = + dp_intf->stats.tx_packets; + dp_intf->nud_tracking.tx_rx_stats.post_rx_packets = + dp_intf->stats.rx_packets; + dp_intf->nud_tracking.tx_rx_stats.post_tx_acked = + dp_txrx_get_tx_ack_count(dp_intf); + break; + default: + break; + } +} + +/** + * dp_nud_honour_failure() - check if nud failure to be honored + * @dp_intf: Pointer to dp_intf + * + * Return: true if nud failure to be honored, else false. + */ +static bool dp_nud_honour_failure(struct wlan_dp_intf *dp_intf) +{ + uint32_t tx_transmitted, tx_acked, gw_rx_pkt, rx_received; + struct dp_nud_tracking_info *nud_tracking = &dp_intf->nud_tracking; + struct wlan_objmgr_vdev *vdev; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + bool ap_is_gateway; + + vdev = dp_objmgr_get_vdev_by_user(dp_intf->def_link, WLAN_DP_ID); + if (!vdev) + goto fail; + wlan_vdev_mgr_get_param_bssid(vdev, bssid); + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + tx_transmitted = nud_tracking->tx_rx_stats.post_tx_packets - + nud_tracking->tx_rx_stats.pre_tx_packets; + tx_acked = nud_tracking->tx_rx_stats.post_tx_acked - + nud_tracking->tx_rx_stats.pre_tx_acked; + gw_rx_pkt = qdf_atomic_read(&nud_tracking->tx_rx_stats.gw_rx_packets); + rx_received = nud_tracking->tx_rx_stats.post_rx_packets - + nud_tracking->tx_rx_stats.pre_rx_packets; + ap_is_gateway = qdf_is_macaddr_equal(&dp_intf->nud_tracking.gw_mac_addr, + (struct qdf_mac_addr *)bssid); + + if (!tx_transmitted || !tx_acked || + !(gw_rx_pkt || (ap_is_gateway && rx_received))) { + dp_info("NUD_FAILURE_HONORED [mac:" QDF_MAC_ADDR_FMT "]", + QDF_MAC_ADDR_REF(nud_tracking->gw_mac_addr.bytes)); + dp_nud_stats_info(dp_intf); + return true; + } +fail: + dp_info("NUD_FAILURE_NOT_HONORED [mac:" QDF_MAC_ADDR_FMT "]", + QDF_MAC_ADDR_REF(nud_tracking->gw_mac_addr.bytes)); + + dp_nud_stats_info(dp_intf); + + return false; +} + +/** + * dp_nud_set_tracking() - set the NUD tracking info + * @dp_intf: Pointer to dp_intf + * @nud_state: Current NUD state to set + * @capture_enabled: GW Rx packet to be capture or not + * + * Return: None + */ +static void dp_nud_set_tracking(struct wlan_dp_intf *dp_intf, + uint8_t nud_state, + bool capture_enabled) +{ + dp_intf->nud_tracking.curr_state = nud_state; + qdf_atomic_set(&dp_intf->nud_tracking.tx_rx_stats.gw_rx_packets, 0); + dp_intf->nud_tracking.is_gw_rx_pkt_track_enabled = capture_enabled; +} + +/** + * dp_nud_failure_work() - work for nud event + * @data: Pointer to dp_intf + * + * Return: None + */ +static void dp_nud_failure_work(void *data) +{ + struct wlan_dp_intf *dp_intf = data; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->nud_tracking.curr_state != DP_NUD_FAILED) { + dp_info("Not in NUD_FAILED state"); + return; + } + + dp_ctx->dp_ops.dp_nud_failure_work(dp_ctx->dp_ops.callback_ctx, + dp_intf->dev); +} + +void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if (dp_intf->device_mode == QDF_STA_MODE && + dp_ctx->dp_cfg.enable_nud_tracking) { + dp_info("Initialize the NUD tracking"); + + qdf_zero_macaddr(&dp_intf->nud_tracking.gw_mac_addr); + qdf_mem_zero(&dp_intf->nud_tracking.tx_rx_stats, + sizeof(struct dp_nud_tx_rx_stats)); + + dp_intf->nud_tracking.curr_state = DP_NUD_NONE; + dp_intf->nud_tracking.ignore_nud_tracking = false; + dp_intf->nud_tracking.is_gw_updated = false; + + qdf_atomic_init(&dp_intf + ->nud_tracking.tx_rx_stats.gw_rx_packets); + qdf_create_work(0, &dp_intf->nud_tracking.nud_event_work, + dp_nud_failure_work, dp_intf); + } +} + +/** + * dp_nud_process_failure_event() - processing NUD_FAILED event + * @dp_intf: Pointer to dp_intf + * + * Return: None + */ +static void dp_nud_process_failure_event(struct wlan_dp_intf *dp_intf) +{ + uint8_t curr_state; + + curr_state = dp_intf->nud_tracking.curr_state; + if (curr_state == DP_NUD_PROBE || curr_state == DP_NUD_INCOMPLETE) { + dp_nud_capture_stats(dp_intf, DP_NUD_FAILED); + if (dp_nud_honour_failure(dp_intf)) { + dp_intf->nud_tracking.curr_state = DP_NUD_FAILED; + qdf_sched_work(0, &dp_intf + ->nud_tracking.nud_event_work); + } else { + dp_info("NUD_START [0x%x]", DP_NUD_INCOMPLETE); + dp_nud_capture_stats(dp_intf, DP_NUD_INCOMPLETE); + dp_nud_set_tracking(dp_intf, DP_NUD_INCOMPLETE, true); + } + } else { + dp_info("NUD FAILED -> Current State [0x%x]", curr_state); + } +} + +/** + * dp_nud_filter_netevent() - filter netevents for STA interface + * @netdev_addr: Pointer to neighbour + * @gw_mac_addr: Gateway MAC address + * @nud_state: Current NUD state + * + * Return: None + */ +static void dp_nud_filter_netevent(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, + uint8_t nud_state) +{ + int status; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_objmgr_vdev *vdev; + + dp_enter(); + dp_ctx = dp_get_context(); + if (!dp_ctx) { + dp_err("unable to get DP context"); + return; + } + + dp_intf = dp_get_intf_by_macaddr(dp_ctx, netdev_addr); + + if (!dp_intf) { + dp_err("Unable to get DP intf for MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(netdev_addr->bytes)); + return; + } + + status = is_dp_intf_valid(dp_intf); + if (status) { + dp_err("invalid dp_intf"); + return; + } + + if (dp_intf->device_mode != QDF_STA_MODE) + return; + + if (dp_intf->nud_tracking.ignore_nud_tracking) { + dp_info("NUD Tracking is Disabled"); + return; + } + + if (!dp_intf->nud_tracking.is_gw_updated) { + dp_info("GW is not updated"); + return; + } + + /* + * NUD is used for STATION mode only, where all the MLO links + * are assumed to be connected. Hence use the deflink here to check + * if the interface is connected. + */ + dp_link = dp_intf->def_link; + vdev = dp_objmgr_get_vdev_by_user(dp_link, WLAN_DP_ID); + if (!vdev) + return; + + if (!wlan_cm_is_vdev_active(vdev)) { + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + dp_info("Not in Connected State"); + return; + } + dp_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + if (!dp_link->conn_info.is_authenticated) { + dp_info("client " QDF_MAC_ADDR_FMT + " is in the middle of WPS/EAPOL exchange.", + QDF_MAC_ADDR_REF(dp_intf->mac_addr.bytes)); + return; + } + + if (!qdf_is_macaddr_equal(&dp_intf->nud_tracking.gw_mac_addr, + gw_mac_addr)) { + dp_info("MAC mismatch NUD state %d GW MAC " + QDF_MAC_ADDR_FMT " Event MAC " QDF_MAC_ADDR_FMT, + nud_state, + QDF_MAC_ADDR_REF(dp_intf->nud_tracking.gw_mac_addr.bytes), + QDF_MAC_ADDR_REF(gw_mac_addr->bytes)); + return; + } + + if (dp_ctx->is_wiphy_suspended) { + dp_info("wlan is suspended, ignore NUD event"); + return; + } + + switch (nud_state) { + case DP_NUD_PROBE: + case DP_NUD_INCOMPLETE: + dp_info("DP_NUD_START [0x%x]", nud_state); + dp_nud_capture_stats(dp_intf, nud_state); + dp_nud_set_tracking(dp_intf, nud_state, true); + break; + + case DP_NUD_REACHABLE: + dp_info("DP_NUD_REACHABLE [0x%x]", nud_state); + dp_nud_set_tracking(dp_intf, DP_NUD_NONE, false); + break; + + case DP_NUD_FAILED: + dp_info("DP_NUD_FAILED [0x%x]", nud_state); + /* + * This condition is to handle the scenario where NUD_FAILED + * events are received without any NUD_PROBE/INCOMPLETE event + * post roaming. Nud state is set to NONE as part of roaming. + * NUD_FAILED is not honored when the curr state is any state + * other than NUD_PROBE/INCOMPLETE so post roaming, nud state + * is moved to DP_NUD_PROBE to honor future NUD_FAILED events. + */ + if (dp_intf->nud_tracking.curr_state == DP_NUD_NONE) { + dp_nud_capture_stats(dp_intf, DP_NUD_PROBE); + dp_nud_set_tracking(dp_intf, DP_NUD_PROBE, true); + } else { + dp_nud_process_failure_event(dp_intf); + } + break; + default: + dp_info("NUD Event For Other State [0x%x]", + nud_state); + break; + } + dp_exit(); +} + +void dp_nud_netevent_cb(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, uint8_t nud_state) +{ + dp_enter(); + dp_nud_filter_netevent(netdev_addr, gw_mac_addr, nud_state); + dp_exit(); +} + +void dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_nud_set_tracking(dp_intf, DP_NUD_NONE, false); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_nud_tracking.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_nud_tracking.h new file mode 100644 index 0000000000..47dface9a3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_nud_tracking.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nud event tracking function declarations + */ + +#ifndef _WLAN_DP_NUD_TRACKING_H_ +#define _WLAN_DP_NUD_TRACKING_H_ + +#ifdef WLAN_NUD_TRACKING + +/** + * struct dp_nud_tx_rx_stats - Capture tx and rx count during NUD tracking + * @pre_tx_packets: Number of tx packets at NUD_PROBE event + * @pre_tx_acked: Number of tx acked at NUD_PROBE event + * @pre_rx_packets: Number of rx packets at NUD_PROBE event + * @post_tx_packets: Number of tx packets at NUD_FAILED event + * @post_tx_acked: Number of tx acked at NUD_FAILED event + * @post_rx_packets: Number of rx packets at NUD_FAILED event + * @gw_rx_packets: Number of rx packets from the registered gateway + * during the period from NUD_PROBE to NUD_FAILED + */ +struct dp_nud_tx_rx_stats { + uint32_t pre_tx_packets; + uint32_t pre_tx_acked; + uint32_t pre_rx_packets; + uint32_t post_tx_packets; + uint32_t post_tx_acked; + uint32_t post_rx_packets; + qdf_atomic_t gw_rx_packets; +}; + + /** + * struct dp_nud_tracking_info - structure to keep track for NUD information + * @curr_state: current state of NUD machine + * @ignore_nud_tracking: true if nud tracking is not required else false + * @tx_rx_stats: Number of packets during NUD tracking + * @gw_mac_addr: gateway mac address for which NUD events are tracked + * @nud_event_work: work to be scheduled during NUD_FAILED + * @is_gw_rx_pkt_track_enabled: true if rx pkt capturing is enabled for GW, + * else false + * @is_gw_updated: true if GW is updated for NUD Tracking + */ +struct dp_nud_tracking_info { + uint8_t curr_state; + bool ignore_nud_tracking; + struct dp_nud_tx_rx_stats tx_rx_stats; + struct qdf_mac_addr gw_mac_addr; + qdf_work_t nud_event_work; + bool is_gw_rx_pkt_track_enabled; + bool is_gw_updated; +}; + +/** + * dp_nud_set_gateway_addr() - set gateway mac address + * @vdev: vdev handle + * @gw_mac_addr: mac address to be set + * + * Return: none + */ +void dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr); + +/** + * dp_nud_incr_gw_rx_pkt_cnt() - Increment rx count for gateway + * @dp_intf: Pointer to DP interface + * @mac_addr: Gateway mac address + * + * Return: None + */ +void dp_nud_incr_gw_rx_pkt_cnt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr); + +/** + * dp_nud_init_tracking() - initialize NUD tracking + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf); + +/** + * dp_nud_reset_tracking() - reset NUD tracking + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_nud_reset_tracking(struct wlan_dp_intf *dp_intf); + +/** + * dp_nud_deinit_tracking() - deinitialize NUD tracking + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_nud_deinit_tracking(struct wlan_dp_intf *dp_intf); + +/** + * dp_nud_ignore_tracking() - set/reset nud trackig status + * @dp_intf: Pointer to dp interface + * @ignoring: Ignore status to set + * + * Return: None + */ +void dp_nud_ignore_tracking(struct wlan_dp_intf *dp_intf, + bool ignoring); + +/** + * dp_nud_flush_work() - flush pending nud work + * @dp_intf: Pointer to dp interface + * + * Return: None + */ +void dp_nud_flush_work(struct wlan_dp_intf *dp_intf); + +/** + * dp_nud_indicate_roam() - reset NUD when roaming happens + * @vdev: vdev handle + * + * Return: None + */ +void dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev); + +/** + * dp_nud_netevent_cb() - netevent callback + * @netdev_addr: netdev_addr + * @gw_mac_addr: Gateway MAC address + * @nud_state : NUD State + * + * Return: None + */ +void dp_nud_netevent_cb(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, uint8_t nud_state); +#else +static inline void dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr) +{ +} + +static inline void dp_nud_incr_gw_rx_pkt_cnt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr) +{ +} + +static inline void dp_nud_init_tracking(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void dp_nud_reset_tracking(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void dp_nud_deinit_tracking(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void dp_nud_ignore_tracking(struct wlan_dp_intf *dp_intf, + bool status) +{ +} + +static inline void +dp_nud_flush_work(struct wlan_dp_intf *dp_intf) +{ +} + +static inline void +dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +void dp_nud_netevent_cb(struct qdf_mac_addr *netdev_addr, + struct qdf_mac_addr *gw_mac_addr, uint8_t nud_state) +{ +} +#endif /* WLAN_NUD_TRACKING */ +#endif /* end of _WLAN_NUD_TRACKING_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_periodic_sta_stats.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_periodic_sta_stats.c new file mode 100644 index 0000000000..36b59299e7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_periodic_sta_stats.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: WLAN Host Device Driver periodic STA statistics related implementation + */ + +#include "wlan_dp_periodic_sta_stats.h" + +void dp_periodic_sta_stats_display(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_intf *dp_intf, next_dp_intf = NULL; + struct dp_stats sta_stats; + struct wlan_dp_psoc_cfg *dp_cfg; + char *dev_name; + bool should_log; + + if (!dp_ctx) + return; + + dp_for_each_intf_held_safe(dp_ctx, dp_intf, next_dp_intf) { + should_log = false; + + if (dp_intf->device_mode != QDF_STA_MODE) + continue; + + dp_cfg = dp_ctx->dp_cfg; + qdf_mutex_acquire(&dp_intf->sta_periodic_stats_lock); + + if (!dp_intf->is_sta_periodic_stats_enabled) { + qdf_mutex_release(&dp_intf->sta_periodic_stats_lock); + continue; + } + + dp_intf->periodic_stats_timer_counter++; + if ((dp_intf->periodic_stats_timer_counter * + dp_cfg->bus_bw_compute_interval) >= + dp_cfg->periodic_stats_timer_interval) { + should_log = true; + + dp_intf->periodic_stats_timer_count--; + if (dp_intf->periodic_stats_timer_count == 0) + dp_intf->is_sta_periodic_stats_enabled = false; + dp_intf->periodic_stats_timer_counter = 0; + } + qdf_mutex_release(&dp_intf->sta_periodic_stats_lock); + + if (should_log) { + dev_name = qdf_netdev_get_devname(dp_intf->dev); + sta_stats = dp_intf->dp_stats; + dp_nofl_info("%s: Tx ARP requests: %d", dev_name, + sta_stats.dp_arp_stats.tx_arp_req_count); + dp_nofl_info("%s: Rx ARP responses: %d", dev_name, + sta_stats.dp_arp_stats.rx_arp_rsp_count); + dp_nofl_info("%s: Tx DNS requests: %d", dev_name, + sta_stats.dp_dns_stats.tx_dns_req_count); + dp_nofl_info("%s: Rx DNS responses: %d", dev_name, + sta_stats.dp_dns_stats.rx_dns_rsp_count); + } + } +} + +void dp_periodic_sta_stats_config(struct dp_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->periodic_stats_timer_interval = + cfg_get(psoc, CFG_PERIODIC_STATS_TIMER_INTERVAL); + config->periodic_stats_timer_duration = + cfg_get(psoc, CFG_PERIODIC_STATS_TIMER_DURATION); +} + +void dp_periodic_sta_stats_start(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + struct dp_config *dp_cfg; + + if (!dp_link) { + dp_nofl_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_cfg = dp_intf->dp_ctx->dp_cfg; + + if ((dp_intf->device_mode == QDF_STA_MODE) && + (dp_cfg->periodic_stats_timer_interval > 0)) { + qdf_mutex_acquire(&dp_intf->sta_periodic_stats_lock); + + /* Stop the periodic ARP and DNS stats timer */ + dp_intf->periodic_stats_timer_count = 0; + dp_intf->is_sta_periodic_stats_enabled = false; + + qdf_mutex_release(&dp_intf->sta_periodic_stats_lock); + } +} + +void dp_periodic_sta_stats_stop(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + struct dp_config *dp_cfg; + + if (!dp_link) { + dp_nofl_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_cfg = dp_intf->dp_ctx->dp_cfg; + + if ((dp_intf->device_mode == QDF_STA_MODE) && + (dp_cfg->periodic_stats_timer_interval > 0)) { + qdf_mutex_acquire(&dp_intf->sta_periodic_stats_lock); + + dp_intf->periodic_stats_timer_count = + dp_cfg->periodic_stats_timer_duration / + dp_cfg->periodic_stats_timer_interval; + dp_intf->periodic_stats_timer_counter = 0; + if (dp_intf->periodic_stats_timer_count > 0) + dp_intf->is_sta_periodic_stats_enabled = true; + + qdf_mutex_release(&dp_intf->sta_periodic_stats_lock); + } +} + +void dp_periodic_sta_stats_init(struct wlan_dp_intf *dp_intf) +{ + dp_intf->is_sta_periodic_stats_enabled = false; +} + +void dp_periodic_sta_stats_mutex_create(struct wlan_dp_intf *dp_intf) +{ + qdf_mutex_create(&dp_intf->sta_periodic_stats_lock); +} + +void dp_periodic_sta_stats_mutex_destroy(struct wlan_dp_intf *dp_intf) +{ +qdf_mutex_destroy(&dp_intf->sta_periodic_stats_lock); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_prealloc.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_prealloc.c new file mode 100644 index 0000000000..61daad3010 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_prealloc.c @@ -0,0 +1,1139 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_dp_prealloc.h" +#ifdef WIFI_MONITOR_SUPPORT +#include +#endif +#ifdef WLAN_PKT_CAPTURE_TX_2_0 +#include "mon_ingress_ring.h" +#include "mon_destination_ring.h" +#include "dp_mon_2.0.h" +#endif + +#ifdef DP_MEM_PRE_ALLOC + +/* Max entries in FISA Flow table */ +#define FISA_RX_FT_SIZE 256 + +/* Num elements in REO ring */ +#define REO_DST_RING_SIZE 1024 + +/* Num elements in TCL Data ring */ +#define TCL_DATA_RING_SIZE 5120 + +/* Num elements in WBM2SW ring */ +#define WBM2SW_RELEASE_RING_SIZE 8192 + +/* Num elements in WBM Idle Link */ +#define WBM_IDLE_LINK_RING_SIZE (32 * 1024) + +/* Num TX desc in TX desc pool */ +#define DP_TX_DESC_POOL_SIZE 6144 + +#define DP_TX_RX_DESC_MAX_NUM \ + (WLAN_CFG_NUM_TX_DESC_MAX * MAX_TXDESC_POOLS + \ + WLAN_CFG_RX_SW_DESC_NUM_SIZE_MAX * MAX_RXDESC_POOLS) + +/** + * struct dp_consistent_prealloc - element representing DP pre-alloc memory + * @ring_type: HAL ring type + * @size: size of pre-alloc memory + * @in_use: whether this element is in use (occupied) + * @va_unaligned: Unaligned virtual address + * @va_aligned: aligned virtual address. + * @pa_unaligned: Unaligned physical address. + * @pa_aligned: Aligned physical address. + */ + +struct dp_consistent_prealloc { + enum hal_ring_type ring_type; + uint32_t size; + uint8_t in_use; + void *va_unaligned; + void *va_aligned; + qdf_dma_addr_t pa_unaligned; + qdf_dma_addr_t pa_aligned; +}; + +/** + * struct dp_multi_page_prealloc - element representing DP pre-alloc multiple + * pages memory + * @desc_type: source descriptor type for memory allocation + * @element_size: single element size + * @element_num: total number of elements should be allocated + * @in_use: whether this element is in use (occupied) + * @cacheable: coherent memory or cacheable memory + * @pages: multi page information storage + */ +struct dp_multi_page_prealloc { + enum qdf_dp_desc_type desc_type; + qdf_size_t element_size; + uint16_t element_num; + bool in_use; + bool cacheable; + struct qdf_mem_multi_page_t pages; +}; + +/** + * struct dp_consistent_prealloc_unaligned - element representing DP pre-alloc + * unaligned memory + * @ring_type: HAL ring type + * @size: size of pre-alloc memory + * @in_use: whether this element is in use (occupied) + * @va_unaligned: unaligned virtual address + * @pa_unaligned: unaligned physical address + */ +struct dp_consistent_prealloc_unaligned { + enum hal_ring_type ring_type; + uint32_t size; + bool in_use; + void *va_unaligned; + qdf_dma_addr_t pa_unaligned; +}; + +/** + * struct dp_prealloc_context - element representing DP prealloc context memory + * @ctxt_type: DP context type + * @size: size of pre-alloc memory + * @in_use: check if element is being used + * @is_critical: critical prealloc failure would cause prealloc_init to fail + * @addr: address of memory allocated + */ +struct dp_prealloc_context { + enum dp_ctxt_type ctxt_type; + uint32_t size; + bool in_use; + bool is_critical; + void *addr; +}; + +static struct dp_prealloc_context g_dp_context_allocs[] = { + {DP_PDEV_TYPE, (sizeof(struct dp_pdev)), false, true, NULL}, +#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY + /* 4 Rx ring history */ + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, +#ifdef CONFIG_BERYLLIUM + /* 4 extra Rx ring history */ + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, + {DP_RX_RING_HIST_TYPE, sizeof(struct dp_rx_history), false, false, + NULL}, +#endif /* CONFIG_BERYLLIUM */ + /* 1 Rx error ring history */ + {DP_RX_ERR_RING_HIST_TYPE, sizeof(struct dp_rx_err_history), + false, false, NULL}, +#ifndef RX_DEFRAG_DO_NOT_REINJECT + /* 1 Rx reinject ring history */ + {DP_RX_REINJECT_RING_HIST_TYPE, sizeof(struct dp_rx_reinject_history), + false, false, NULL}, +#endif /* RX_DEFRAG_DO_NOT_REINJECT */ + /* 1 Rx refill ring history */ + {DP_RX_REFILL_RING_HIST_TYPE, sizeof(struct dp_rx_refill_history), + false, false, NULL}, +#endif /* WLAN_FEATURE_DP_RX_RING_HISTORY */ +#ifdef DP_TX_HW_DESC_HISTORY + {DP_TX_HW_DESC_HIST_TYPE, + DP_TX_HW_DESC_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_hw_desc_evt), + false, false, NULL}, + {DP_TX_HW_DESC_HIST_TYPE, + DP_TX_HW_DESC_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_hw_desc_evt), + false, false, NULL}, + {DP_TX_HW_DESC_HIST_TYPE, + DP_TX_HW_DESC_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_hw_desc_evt), + false, false, NULL}, +#endif +#ifdef WLAN_FEATURE_DP_TX_DESC_HISTORY + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_TCL_HIST_TYPE, + DP_TX_TCL_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + {DP_TX_COMP_HIST_TYPE, + DP_TX_COMP_HIST_PER_SLOT_MAX * sizeof(struct dp_tx_desc_event), + false, false, NULL}, + +#endif /* WLAN_FEATURE_DP_TX_DESC_HISTORY */ +#ifdef WLAN_SUPPORT_RX_FISA + {DP_FISA_RX_FT_TYPE, sizeof(struct dp_fisa_rx_sw_ft) * FISA_RX_FT_SIZE, + false, true, NULL}, +#endif +#ifdef WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY + {DP_MON_STATUS_BUF_HIST_TYPE, sizeof(struct dp_mon_status_ring_history), + false, false, NULL}, +#endif +#ifdef WIFI_MONITOR_SUPPORT + {DP_MON_PDEV_TYPE, sizeof(struct dp_mon_pdev), + false, false, NULL}, +#endif +#ifdef WLAN_FEATURE_DP_CFG_EVENT_HISTORY + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, + {DP_CFG_EVENT_HIST_TYPE, + DP_CFG_EVT_HIST_PER_SLOT_MAX * sizeof(struct dp_cfg_event), + false, false, NULL}, +#endif +#ifdef WLAN_PKT_CAPTURE_TX_2_0 + {DP_MON_TX_DESC_POOL_TYPE, 0, false, false, NULL}, +#endif +}; + +static struct dp_consistent_prealloc g_dp_consistent_allocs[] = { + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, +#ifdef CONFIG_BERYLLIUM + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, + {REO_DST, (sizeof(struct reo_destination_ring)) * REO_DST_RING_SIZE, 0, + NULL, NULL, 0, 0}, +#endif + /* 3 TCL data rings */ + {TCL_DATA, 0, 0, NULL, NULL, 0, 0}, + {TCL_DATA, 0, 0, NULL, NULL, 0, 0}, + {TCL_DATA, 0, 0, NULL, NULL, 0, 0}, + /* 4 WBM2SW rings */ + {WBM2SW_RELEASE, 0, 0, NULL, NULL, 0, 0}, + {WBM2SW_RELEASE, 0, 0, NULL, NULL, 0, 0}, + {WBM2SW_RELEASE, 0, 0, NULL, NULL, 0, 0}, + {WBM2SW_RELEASE, 0, 0, NULL, 0, 0}, + /* SW2WBM link descriptor return ring */ + {SW2WBM_RELEASE, 0, 0, NULL, 0, 0}, + /* 1 WBM idle link desc ring */ + {WBM_IDLE_LINK, (sizeof(struct wbm_link_descriptor_ring)) * + WBM_IDLE_LINK_RING_SIZE, 0, NULL, NULL, 0, 0}, + /* 2 RXDMA DST ERR rings */ + {RXDMA_DST, 0, 0, NULL, NULL, 0, 0}, + {RXDMA_DST, 0, 0, NULL, NULL, 0, 0}, + /* REFILL ring 0 */ + {RXDMA_BUF, 0, 0, NULL, NULL, 0, 0}, + /* 2 RXDMA buffer rings */ + {RXDMA_BUF, 0, 0, NULL, NULL, 0, 0}, + {RXDMA_BUF, 0, 0, NULL, NULL, 0, 0}, + /* REO Exception ring */ + {REO_EXCEPTION, 0, 0, NULL, NULL, 0, 0}, + /* 1 REO status ring */ + {REO_STATUS, 0, 0, NULL, NULL, 0, 0}, + /* 2 monitor status rings */ + {RXDMA_MONITOR_STATUS, 0, 0, NULL, NULL, 0, 0}, + {RXDMA_MONITOR_STATUS, 0, 0, NULL, NULL, 0, 0}, +#ifdef WLAN_PKT_CAPTURE_TX_2_0 + /* 2 MON2SW Tx monitor rings */ + {TX_MONITOR_DST, 0, 0, NULL, NULL, 0, 0}, + {TX_MONITOR_DST, 0, 0, NULL, NULL, 0, 0}, +#endif +}; + +/* Number of HW link descriptors needed (rounded to power of 2) */ +#define NUM_HW_LINK_DESCS (32 * 1024) + +/* Size in bytes of HW LINK DESC */ +#define HW_LINK_DESC_SIZE 128 + +/* Size in bytes of TX Desc (rounded to power of 2) */ +#define TX_DESC_SIZE 128 + +/* Size in bytes of TX TSO Desc (rounded to power of 2) */ +#define TX_TSO_DESC_SIZE 256 + +/* Size in bytes of TX TSO Num Seg Desc (rounded to power of 2) */ +#define TX_TSO_NUM_SEG_DESC_SIZE 16 + +#define NON_CACHEABLE 0 +#define CACHEABLE 1 + +#define DIRECT_LINK_CE_RX_BUF_SIZE 256 +#define DIRECT_LINK_DEFAULT_BUF_SZ 2048 +#define TX_DIRECT_LINK_BUF_NUM 380 +#define TX_DIRECT_LINK_CE_BUF_NUM 8 +#define RX_DIRECT_LINK_CE_BUF_NUM 30 + +static struct dp_multi_page_prealloc g_dp_multi_page_allocs[] = { + /* 4 TX DESC pools */ + {QDF_DP_TX_DESC_TYPE, TX_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_DESC_TYPE, TX_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_DESC_TYPE, TX_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_DESC_TYPE, TX_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + + /* 4 Tx EXT DESC NON Cacheable pools */ + {QDF_DP_TX_EXT_DESC_TYPE, HAL_TX_EXT_DESC_WITH_META_DATA, 0, 0, + NON_CACHEABLE, { 0 } }, + {QDF_DP_TX_EXT_DESC_TYPE, HAL_TX_EXT_DESC_WITH_META_DATA, 0, 0, + NON_CACHEABLE, { 0 } }, + {QDF_DP_TX_EXT_DESC_TYPE, HAL_TX_EXT_DESC_WITH_META_DATA, 0, 0, + NON_CACHEABLE, { 0 } }, + {QDF_DP_TX_EXT_DESC_TYPE, HAL_TX_EXT_DESC_WITH_META_DATA, 0, 0, + NON_CACHEABLE, { 0 } }, + + /* 4 Tx EXT DESC Link Cacheable pools */ + {QDF_DP_TX_EXT_DESC_LINK_TYPE, sizeof(struct dp_tx_ext_desc_elem_s), 0, + 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_EXT_DESC_LINK_TYPE, sizeof(struct dp_tx_ext_desc_elem_s), 0, + 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_EXT_DESC_LINK_TYPE, sizeof(struct dp_tx_ext_desc_elem_s), 0, + 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_EXT_DESC_LINK_TYPE, sizeof(struct dp_tx_ext_desc_elem_s), 0, + 0, CACHEABLE, { 0 } }, + + /* 4 TX TSO DESC pools */ + {QDF_DP_TX_TSO_DESC_TYPE, TX_TSO_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_TSO_DESC_TYPE, TX_TSO_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_TSO_DESC_TYPE, TX_TSO_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + {QDF_DP_TX_TSO_DESC_TYPE, TX_TSO_DESC_SIZE, 0, 0, CACHEABLE, { 0 } }, + + /* 4 TX TSO NUM SEG DESC pools */ + {QDF_DP_TX_TSO_NUM_SEG_TYPE, TX_TSO_NUM_SEG_DESC_SIZE, 0, 0, + CACHEABLE, { 0 } }, + {QDF_DP_TX_TSO_NUM_SEG_TYPE, TX_TSO_NUM_SEG_DESC_SIZE, 0, 0, + CACHEABLE, { 0 } }, + {QDF_DP_TX_TSO_NUM_SEG_TYPE, TX_TSO_NUM_SEG_DESC_SIZE, 0, 0, + CACHEABLE, { 0 } }, + {QDF_DP_TX_TSO_NUM_SEG_TYPE, TX_TSO_NUM_SEG_DESC_SIZE, 0, 0, + CACHEABLE, { 0 } }, + + /* DP RX DESCs BUF pools */ + {QDF_DP_RX_DESC_BUF_TYPE, sizeof(union dp_rx_desc_list_elem_t), + 0, 0, CACHEABLE, { 0 } }, + +#ifdef DISABLE_MON_CONFIG + /* no op */ +#else + /* 2 DP RX DESCs Status pools */ + {QDF_DP_RX_DESC_STATUS_TYPE, sizeof(union dp_rx_desc_list_elem_t), + WLAN_CFG_RXDMA_MONITOR_STATUS_RING_SIZE + 1, 0, CACHEABLE, { 0 } }, + {QDF_DP_RX_DESC_STATUS_TYPE, sizeof(union dp_rx_desc_list_elem_t), + WLAN_CFG_RXDMA_MONITOR_STATUS_RING_SIZE + 1, 0, CACHEABLE, { 0 } }, +#endif + /* DP HW Link DESCs pools */ + {QDF_DP_HW_LINK_DESC_TYPE, HW_LINK_DESC_SIZE, NUM_HW_LINK_DESCS, 0, + NON_CACHEABLE, { 0 } }, +#ifdef CONFIG_BERYLLIUM + {QDF_DP_HW_CC_SPT_PAGE_TYPE, qdf_page_size, + ((DP_TX_RX_DESC_MAX_NUM * sizeof(uint64_t)) / qdf_page_size), + 0, NON_CACHEABLE, { 0 } }, +#endif +#ifdef FEATURE_DIRECT_LINK + {QDF_DP_TX_DIRECT_LINK_CE_BUF_TYPE, DIRECT_LINK_DEFAULT_BUF_SZ, + TX_DIRECT_LINK_CE_BUF_NUM, 0, NON_CACHEABLE, { 0 } }, + {QDF_DP_TX_DIRECT_LINK_BUF_TYPE, DIRECT_LINK_DEFAULT_BUF_SZ, + TX_DIRECT_LINK_BUF_NUM, 0, NON_CACHEABLE, { 0 } }, + {QDF_DP_RX_DIRECT_LINK_CE_BUF_TYPE, DIRECT_LINK_CE_RX_BUF_SIZE, + RX_DIRECT_LINK_CE_BUF_NUM, 0, NON_CACHEABLE, { 0 } }, +#endif +}; + +static struct dp_consistent_prealloc_unaligned + g_dp_consistent_unaligned_allocs[] = { + /* CE-0 */ + {CE_SRC, (sizeof(struct ce_srng_src_desc) * 16 + CE_DESC_RING_ALIGN), + false, NULL, 0}, + /* CE-1 */ + {CE_DST, (sizeof(struct ce_srng_dest_desc) * 512 + CE_DESC_RING_ALIGN), + false, NULL, 0}, + {CE_DST_STATUS, (sizeof(struct ce_srng_dest_status_desc) * 512 + + CE_DESC_RING_ALIGN), false, NULL, 0}, + /* CE-2 */ + {CE_DST, (sizeof(struct ce_srng_dest_desc) * 32 + CE_DESC_RING_ALIGN), + false, NULL, 0}, + {CE_DST_STATUS, (sizeof(struct ce_srng_dest_status_desc) * 32 + + CE_DESC_RING_ALIGN), false, NULL, 0}, + /* CE-3 */ + {CE_SRC, (sizeof(struct ce_srng_src_desc) * 32 + CE_DESC_RING_ALIGN), + false, NULL, 0}, + /* CE-4 */ + {CE_SRC, (sizeof(struct ce_srng_src_desc) * 256 + CE_DESC_RING_ALIGN), + false, NULL, 0}, + /* CE-5 */ + {CE_DST, (sizeof(struct ce_srng_dest_desc) * 512 + CE_DESC_RING_ALIGN), + false, NULL, 0}, + {CE_DST_STATUS, (sizeof(struct ce_srng_dest_status_desc) * 512 + + CE_DESC_RING_ALIGN), false, NULL, 0}, +}; + +void dp_prealloc_deinit(void) +{ + int i; + struct dp_prealloc_context *cp; + struct dp_consistent_prealloc *p; + struct dp_multi_page_prealloc *mp; + struct dp_consistent_prealloc_unaligned *up; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) + return; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) { + p = &g_dp_consistent_allocs[i]; + + if (p->in_use) + dp_warn("i %d: consistent_mem in use while free", i); + + if (p->va_aligned) { + dp_debug("i %d: va aligned %pK pa aligned %pK size %d", + i, p->va_aligned, (void *)p->pa_aligned, + p->size); + qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, + p->size, + p->va_unaligned, + p->pa_unaligned, 0); + p->in_use = false; + p->va_unaligned = NULL; + p->va_aligned = NULL; + p->pa_unaligned = 0; + p->pa_aligned = 0; + } + } + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_multi_page_allocs); i++) { + mp = &g_dp_multi_page_allocs[i]; + + if (mp->in_use) + dp_warn("i %d: multi-page mem in use while free", i); + + if (mp->pages.num_pages) { + dp_info("i %d: type %d cacheable_pages %pK dma_pages %pK num_pages %d", + i, mp->desc_type, + mp->pages.cacheable_pages, + mp->pages.dma_pages, + mp->pages.num_pages); + qdf_mem_multi_pages_free(qdf_ctx, &mp->pages, + 0, mp->cacheable); + mp->in_use = false; + qdf_mem_zero(&mp->pages, sizeof(mp->pages)); + } + } + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_unaligned_allocs); i++) { + up = &g_dp_consistent_unaligned_allocs[i]; + + if (qdf_unlikely(up->in_use)) + dp_info("i %d: unaligned mem in use while free", i); + + if (up->va_unaligned) { + dp_info("i %d: va unalign %pK pa unalign %pK size %d", + i, up->va_unaligned, + (void *)up->pa_unaligned, up->size); + qdf_mem_free_consistent(qdf_ctx, qdf_ctx->dev, + up->size, + up->va_unaligned, + up->pa_unaligned, 0); + up->in_use = false; + up->va_unaligned = NULL; + up->pa_unaligned = 0; + } + } + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_context_allocs); i++) { + cp = &g_dp_context_allocs[i]; + if (qdf_unlikely(cp->in_use)) + dp_warn("i %d: context in use while free", i); + + if (cp->addr) { + qdf_mem_free(cp->addr); + cp->addr = NULL; + } + } +} + +#ifdef CONFIG_BERYLLIUM +/** + * dp_get_tcl_data_srng_entrysize() - Get the tcl data srng entry + * size + * + * Return: TCL data srng entry size + */ +static inline uint32_t dp_get_tcl_data_srng_entrysize(void) +{ + return sizeof(struct tcl_data_cmd); +} + +#ifdef WLAN_PKT_CAPTURE_TX_2_0 +/** + * dp_get_tx_mon_mem_size() - Get tx mon ring memory size + * @cfg: prealloc config + * @ring_type: ring type + * + * Return: Tx mon ring memory size + */ +static inline +uint32_t dp_get_tx_mon_mem_size(struct wlan_dp_prealloc_cfg *cfg, + enum hal_ring_type ring_type) +{ + uint32_t mem_size = 0; + + if (!cfg) + return mem_size; + + if (ring_type == TX_MONITOR_BUF) { + mem_size = (sizeof(struct mon_ingress_ring)) * + cfg->num_tx_mon_buf_ring_entries; + } else if (ring_type == TX_MONITOR_DST) { + mem_size = (sizeof(struct mon_destination_ring)) * + cfg->num_tx_mon_dst_ring_entries; + } + + return mem_size; +} + +/** + * dp_get_tx_mon_desc_pool_mem_size() - Get tx mon desc pool memory size + * @cfg: prealloc config + * + * Return : TX mon desc pool memory size + */ +static inline +uint32_t dp_get_tx_mon_desc_pool_mem_size(struct wlan_dp_prealloc_cfg *cfg) +{ + return (sizeof(union dp_mon_desc_list_elem_t)) * + cfg->num_tx_mon_buf_ring_entries; +} +#else +static inline +uint32_t dp_get_tx_mon_mem_size(struct wlan_dp_prealloc_cfg *cfg, + enum hal_ring_type ring_type) +{ + return 0; +} + +static inline +uint32_t dp_get_tx_mon_desc_pool_mem_size(struct wlan_dp_prealloc_cfg *cfg) +{ + return 0; +} +#endif /* WLAN_PKT_CAPTURE_TX_2_0 */ +#else +static inline uint32_t dp_get_tcl_data_srng_entrysize(void) +{ + return (sizeof(struct tlv_32_hdr) + sizeof(struct tcl_data_cmd)); +} + +static inline +uint32_t dp_get_tx_mon_mem_size(struct wlan_dp_prealloc_cfg *cfg, + enum hal_ring_type ring_type) +{ + return 0; +} + +static inline +uint32_t dp_get_tx_mon_desc_pool_mem_size(struct wlan_dp_prealloc_cfg *cfg) +{ + return 0; +} +#endif + +/** + * dp_update_mem_size_by_ctx_type() - Update dp context memory size + * based on context type + * @cfg: prealloc related cfg params + * @ctx_type: DP context type + * @mem_size: memory size to be updated + * + * Return: none + */ +static void +dp_update_mem_size_by_ctx_type(struct wlan_dp_prealloc_cfg *cfg, + enum dp_ctxt_type ctx_type, + uint32_t *mem_size) +{ + switch (ctx_type) { + case DP_MON_TX_DESC_POOL_TYPE: + *mem_size = dp_get_tx_mon_desc_pool_mem_size(cfg); + break; + default: + return; + } +} + +/** + * dp_update_mem_size_by_ring_type() - Update srng memory size based + * on ring type and the corresponding ini configuration + * @cfg: prealloc related cfg params + * @ring_type: srng type + * @mem_size: memory size to be updated + * + * Return: None + */ +static void +dp_update_mem_size_by_ring_type(struct wlan_dp_prealloc_cfg *cfg, + enum hal_ring_type ring_type, + uint32_t *mem_size) +{ + switch (ring_type) { + case TCL_DATA: + *mem_size = dp_get_tcl_data_srng_entrysize() * + cfg->num_tx_ring_entries; + return; + case WBM2SW_RELEASE: + *mem_size = (sizeof(struct wbm_release_ring)) * + cfg->num_tx_comp_ring_entries; + return; + case SW2WBM_RELEASE: + *mem_size = (sizeof(struct wbm_release_ring)) * + cfg->num_wbm_rel_ring_entries; + return; + case RXDMA_DST: + *mem_size = (sizeof(struct reo_entrance_ring)) * + cfg->num_rxdma_err_dst_ring_entries; + return; + case REO_EXCEPTION: + *mem_size = (sizeof(struct reo_destination_ring)) * + cfg->num_reo_exception_ring_entries; + return; + case REO_DST: + *mem_size = (sizeof(struct reo_destination_ring)) * + cfg->num_reo_dst_ring_entries; + return; + case RXDMA_BUF: + *mem_size = (sizeof(struct wbm_buffer_ring)) * + cfg->num_rxdma_refill_ring_entries; + return; + case REO_STATUS: + *mem_size = (sizeof(struct tlv_32_hdr) + + sizeof(struct reo_get_queue_stats_status)) * + cfg->num_reo_status_ring_entries; + return; + case RXDMA_MONITOR_STATUS: + *mem_size = (sizeof(struct wbm_buffer_ring)) * + cfg->num_mon_status_ring_entries; + return; + case TX_MONITOR_BUF: + case TX_MONITOR_DST: + *mem_size = dp_get_tx_mon_mem_size(cfg, ring_type); + return; + default: + return; + } +} + +/** + * dp_update_num_elements_by_desc_type() - Update num of descriptors based + * on type and the corresponding ini configuration + * @cfg: prealloc related cfg params + * @desc_type: descriptor type + * @num_elements: num of descriptor elements + * + * Return: None + */ +static void +dp_update_num_elements_by_desc_type(struct wlan_dp_prealloc_cfg *cfg, + enum qdf_dp_desc_type desc_type, + uint16_t *num_elements) +{ + switch (desc_type) { + case QDF_DP_TX_DESC_TYPE: + *num_elements = cfg->num_tx_desc; + return; + case QDF_DP_TX_EXT_DESC_TYPE: + case QDF_DP_TX_EXT_DESC_LINK_TYPE: + case QDF_DP_TX_TSO_DESC_TYPE: + case QDF_DP_TX_TSO_NUM_SEG_TYPE: + *num_elements = cfg->num_tx_ext_desc; + return; + case QDF_DP_RX_DESC_BUF_TYPE: + *num_elements = cfg->num_rx_sw_desc * WLAN_CFG_RX_SW_DESC_WEIGHT_SIZE; + return; + default: + return; + } +} + +#ifdef WLAN_DP_PROFILE_SUPPORT +static void +wlan_dp_sync_prealloc_with_profile_cfg(struct wlan_dp_prealloc_cfg *cfg) +{ + struct wlan_dp_memory_profile_info *profile_info; + struct wlan_dp_memory_profile_ctx *profile_ctx; + int i; + + profile_info = wlan_dp_get_profile_info(); + if (!profile_info->is_selected) + return; + + for (i = 0; i < profile_info->size; i++) { + profile_ctx = &profile_info->ctx[i]; + + switch (profile_ctx->param_type) { + case DP_TX_DESC_NUM_CFG: + cfg->num_tx_desc = profile_ctx->size; + break; + case DP_TX_EXT_DESC_NUM_CFG: + cfg->num_tx_ext_desc = profile_ctx->size; + break; + case DP_TX_RING_SIZE_CFG: + cfg->num_tx_ring_entries = profile_ctx->size; + break; + case DP_TX_COMPL_RING_SIZE_CFG: + cfg->num_tx_comp_ring_entries = profile_ctx->size; + break; + case DP_RX_SW_DESC_NUM_CFG: + cfg->num_rx_sw_desc = profile_ctx->size; + break; + case DP_REO_DST_RING_SIZE_CFG: + cfg->num_reo_dst_ring_entries = profile_ctx->size; + break; + case DP_RXDMA_BUF_RING_SIZE_CFG: + cfg->num_rxdma_buf_ring_entries = profile_ctx->size; + break; + case DP_RXDMA_REFILL_RING_SIZE_CFG: + cfg->num_rxdma_refill_ring_entries = profile_ctx->size; + break; + default: + break; + } + } +} +#else + +static inline void +wlan_dp_sync_prealloc_with_profile_cfg(struct wlan_dp_prealloc_cfg *cfg) {} +#endif + +QDF_STATUS dp_prealloc_init(struct cdp_ctrl_objmgr_psoc *ctrl_psoc) +{ + int i; + struct dp_prealloc_context *cp; + struct dp_consistent_prealloc *p; + struct dp_multi_page_prealloc *mp; + struct dp_consistent_prealloc_unaligned *up; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct wlan_dp_prealloc_cfg cfg; + + if (!qdf_ctx || !ctrl_psoc) { + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + wlan_cfg_get_prealloc_cfg(ctrl_psoc, &cfg); + wlan_dp_sync_prealloc_with_profile_cfg(&cfg); + + /*Context pre-alloc*/ + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_context_allocs); i++) { + cp = &g_dp_context_allocs[i]; + dp_update_mem_size_by_ctx_type(&cfg, cp->ctxt_type, + &cp->size); + cp->addr = qdf_mem_malloc(cp->size); + + if (qdf_unlikely(!cp->addr) && cp->is_critical) { + dp_warn("i %d: unable to preallocate %d bytes memory!", + i, cp->size); + break; + } + } + + if (i != QDF_ARRAY_SIZE(g_dp_context_allocs)) { + dp_err("unable to allocate context memory!"); + goto deinit; + } + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) { + p = &g_dp_consistent_allocs[i]; + p->in_use = 0; + dp_update_mem_size_by_ring_type(&cfg, p->ring_type, &p->size); + p->va_aligned = + qdf_aligned_mem_alloc_consistent(qdf_ctx, + &p->size, + &p->va_unaligned, + &p->pa_unaligned, + &p->pa_aligned, + DP_RING_BASE_ALIGN); + if (qdf_unlikely(!p->va_unaligned)) { + dp_warn("i %d: unable to preallocate %d bytes memory!", + i, p->size); + break; + } + dp_debug("i %d: va aligned %pK pa aligned %pK size %d", + i, p->va_aligned, (void *)p->pa_aligned, p->size); + } + + if (i != QDF_ARRAY_SIZE(g_dp_consistent_allocs)) { + dp_err("unable to allocate consistent memory!"); + goto deinit; + } + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_multi_page_allocs); i++) { + mp = &g_dp_multi_page_allocs[i]; + mp->in_use = false; + dp_update_num_elements_by_desc_type(&cfg, mp->desc_type, + &mp->element_num); + if (mp->cacheable) + mp->pages.page_size = DP_BLOCKMEM_SIZE; + + qdf_mem_multi_pages_alloc(qdf_ctx, &mp->pages, + mp->element_size, + mp->element_num, + 0, mp->cacheable); + if (qdf_unlikely(!mp->pages.num_pages)) { + dp_warn("i %d: preallocate %d bytes multi-pages failed!", + i, (int)(mp->element_size * mp->element_num)); + break; + } + + mp->pages.is_mem_prealloc = true; + dp_info("i %d: cacheable_pages %pK dma_pages %pK num_pages %d", + i, mp->pages.cacheable_pages, + mp->pages.dma_pages, + mp->pages.num_pages); + } + + if (i != QDF_ARRAY_SIZE(g_dp_multi_page_allocs)) { + dp_err("unable to allocate multi-pages memory!"); + goto deinit; + } + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_unaligned_allocs); i++) { + up = &g_dp_consistent_unaligned_allocs[i]; + up->in_use = 0; + up->va_unaligned = qdf_mem_alloc_consistent(qdf_ctx, + qdf_ctx->dev, + up->size, + &up->pa_unaligned); + if (qdf_unlikely(!up->va_unaligned)) { + dp_warn("i %d: fail to prealloc unaligned %d bytes!", + i, up->size); + break; + } + dp_info("i %d: va unalign %pK pa unalign %pK size %d", + i, up->va_unaligned, + (void *)up->pa_unaligned, up->size); + } + + if (i != QDF_ARRAY_SIZE(g_dp_consistent_unaligned_allocs)) { + dp_info("unable to allocate unaligned memory!"); + /* + * Only if unaligned memory prealloc fail, is deinit + * necessary for all other DP srng/multi-pages memory? + */ + goto deinit; + } + + return QDF_STATUS_SUCCESS; +deinit: + dp_prealloc_deinit(); + return QDF_STATUS_E_FAILURE; +} + +void *dp_prealloc_get_context_memory(uint32_t ctxt_type, qdf_size_t ctxt_size) +{ + int i; + struct dp_prealloc_context *cp; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_context_allocs); i++) { + cp = &g_dp_context_allocs[i]; + + if ((ctxt_type == cp->ctxt_type) && !cp->in_use && + cp->addr && ctxt_size <= cp->size) { + cp->in_use = true; + return cp->addr; + } + } + + return NULL; +} + +QDF_STATUS dp_prealloc_put_context_memory(uint32_t ctxt_type, void *vaddr) +{ + int i; + struct dp_prealloc_context *cp; + + if (!vaddr) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_context_allocs); i++) { + cp = &g_dp_context_allocs[i]; + + if ((ctxt_type == cp->ctxt_type) && vaddr == cp->addr) { + qdf_mem_zero(cp->addr, cp->size); + cp->in_use = false; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} + +void *dp_prealloc_get_coherent(uint32_t *size, void **base_vaddr_unaligned, + qdf_dma_addr_t *paddr_unaligned, + qdf_dma_addr_t *paddr_aligned, + uint32_t align, + uint32_t ring_type) +{ + int i; + struct dp_consistent_prealloc *p; + void *va_aligned = NULL; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) { + p = &g_dp_consistent_allocs[i]; + if (p->ring_type == ring_type && !p->in_use && + p->va_unaligned && *size <= p->size) { + p->in_use = 1; + *base_vaddr_unaligned = p->va_unaligned; + *paddr_unaligned = p->pa_unaligned; + *paddr_aligned = p->pa_aligned; + va_aligned = p->va_aligned; + *size = p->size; + dp_debug("index %i -> ring type %s va-aligned %pK", i, + dp_srng_get_str_from_hal_ring_type(ring_type), + va_aligned); + break; + } + } + + if (i == QDF_ARRAY_SIZE(g_dp_consistent_allocs)) + dp_info("unable to allocate memory for ring type %s (%d) size %d", + dp_srng_get_str_from_hal_ring_type(ring_type), + ring_type, *size); + return va_aligned; +} + +void dp_prealloc_put_coherent(qdf_size_t size, void *vaddr_unligned, + qdf_dma_addr_t paddr) +{ + int i; + struct dp_consistent_prealloc *p; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_allocs); i++) { + p = &g_dp_consistent_allocs[i]; + if (p->va_unaligned == vaddr_unligned) { + dp_debug("index %d, returned", i); + p->in_use = 0; + qdf_mem_zero(p->va_unaligned, p->size); + break; + } + } + + if (i == QDF_ARRAY_SIZE(g_dp_consistent_allocs)) + dp_err("unable to find vaddr %pK", vaddr_unligned); +} + +void dp_prealloc_get_multi_pages(uint32_t desc_type, + qdf_size_t element_size, + uint16_t element_num, + struct qdf_mem_multi_page_t *pages, + bool cacheable) +{ + int i; + struct dp_multi_page_prealloc *mp; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_multi_page_allocs); i++) { + mp = &g_dp_multi_page_allocs[i]; + + if (desc_type == mp->desc_type && !mp->in_use && + mp->pages.num_pages && element_size == mp->element_size && + element_num <= mp->element_num) { + mp->in_use = true; + *pages = mp->pages; + + dp_info("i %d: desc_type %d cacheable_pages %pK dma_pages %pK num_pages %d", + i, desc_type, + mp->pages.cacheable_pages, + mp->pages.dma_pages, + mp->pages.num_pages); + break; + } + } +} + +void dp_prealloc_put_multi_pages(uint32_t desc_type, + struct qdf_mem_multi_page_t *pages) +{ + int i; + struct dp_multi_page_prealloc *mp; + bool mp_found = false; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_multi_page_allocs); i++) { + mp = &g_dp_multi_page_allocs[i]; + + if (desc_type == mp->desc_type) { + /* compare different address by cacheable flag */ + mp_found = mp->cacheable ? + (mp->pages.cacheable_pages == + pages->cacheable_pages) : + (mp->pages.dma_pages == pages->dma_pages); + /* find it, put back to prealloc pool */ + if (mp_found) { + dp_info("i %d: desc_type %d returned", + i, desc_type); + mp->in_use = false; + qdf_mem_multi_pages_zero(&mp->pages, + mp->cacheable); + break; + } + } + } + + if (qdf_unlikely(!mp_found)) + dp_warn("Not prealloc pages %pK desc_type %d cacheable_pages %pK dma_pages %pK", + pages, + desc_type, + pages->cacheable_pages, + pages->dma_pages); +} + +void *dp_prealloc_get_consistent_mem_unaligned(qdf_size_t size, + qdf_dma_addr_t *base_addr, + uint32_t ring_type) +{ + int i; + struct dp_consistent_prealloc_unaligned *up; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_unaligned_allocs); i++) { + up = &g_dp_consistent_unaligned_allocs[i]; + + if (ring_type == up->ring_type && size == up->size && + up->va_unaligned && !up->in_use) { + up->in_use = true; + *base_addr = up->pa_unaligned; + dp_info("i %d: va unalign %pK pa unalign %pK size %d", + i, up->va_unaligned, + (void *)up->pa_unaligned, up->size); + return up->va_unaligned; + } + } + + return NULL; +} + +void dp_prealloc_put_consistent_mem_unaligned(void *va_unaligned) +{ + int i; + struct dp_consistent_prealloc_unaligned *up; + + for (i = 0; i < QDF_ARRAY_SIZE(g_dp_consistent_unaligned_allocs); i++) { + up = &g_dp_consistent_unaligned_allocs[i]; + + if (va_unaligned == up->va_unaligned) { + dp_info("index %d, returned", i); + up->in_use = false; + qdf_mem_zero(up->va_unaligned, up->size); + break; + } + } + + if (i == QDF_ARRAY_SIZE(g_dp_consistent_unaligned_allocs)) + dp_err("unable to find vaddr %pK", va_unaligned); +} +#endif + +#ifdef FEATURE_RUNTIME_PM +uint32_t dp_get_tx_inqueue(ol_txrx_soc_handle soc) +{ + struct dp_soc *dp_soc; + + dp_soc = cdp_soc_t_to_dp_soc(soc); + + return qdf_atomic_read(&dp_soc->tx_pending_rtpm); +} +#else +uint32_t dp_get_tx_inqueue(ol_txrx_soc_handle soc) +{ + return 0; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_rx_fst.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_rx_fst.c new file mode 100644 index 0000000000..a79b2269c9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_rx_fst.c @@ -0,0 +1,768 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "dp_types.h" +#include "qdf_mem.h" +#include "qdf_nbuf.h" +#include "cfg_dp.h" +#include "wlan_cfg.h" +#include "dp_types.h" +#include "hal_rx_flow.h" +#include "dp_htt.h" +#include "dp_internal.h" +#include "hif.h" +#include "wlan_dp_rx_thread.h" +#include +#include +#include +#include "qdf_ssr_driver_dump.h" + +/* Timeout in milliseconds to wait for CMEM FST HTT response */ +#define DP_RX_FST_CMEM_RESP_TIMEOUT 2000 + +#define INVALID_NAPI 0Xff + +#ifdef WLAN_SUPPORT_RX_FISA +void dp_fisa_rx_fst_update_work(void *arg); + +static void dp_rx_dump_fisa_table(struct wlan_dp_psoc_context *dp_ctx) +{ + hal_soc_handle_t hal_soc_hdl = dp_ctx->hal_soc; + struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg; + struct dp_rx_fst *fst = dp_ctx->rx_fst; + struct dp_fisa_rx_sw_ft *sw_ft_entry; + int i; + + /* Check if it is enabled in the INI */ + if (!wlan_dp_cfg_is_rx_fisa_enabled(dp_cfg)) { + dp_err("RX FISA feature is disabled"); + return; + } + + if (!fst->fst_in_cmem) + return hal_rx_dump_fse_table(fst->hal_rx_fst); + + sw_ft_entry = (struct dp_fisa_rx_sw_ft *)fst->base; + + if (hif_force_wake_request(((struct hal_soc *)hal_soc_hdl)->hif_handle)) { + dp_err("Wake up request failed"); + qdf_check_state_before_panic(__func__, __LINE__); + return; + } + + for (i = 0; i < fst->max_entries; i++) + hal_rx_dump_cmem_fse(hal_soc_hdl, + sw_ft_entry[i].cmem_offset, i); + + if (hif_force_wake_release(((struct hal_soc *)hal_soc_hdl)->hif_handle)) { + dp_err("Wake up release failed"); + qdf_check_state_before_panic(__func__, __LINE__); + return; + } +} + +static void dp_print_fisa_stats(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg; + struct dp_rx_fst *fst = dp_ctx->rx_fst; + + /* Check if it is enabled in the INI */ + if (!wlan_dp_cfg_is_rx_fisa_enabled(dp_cfg)) + return; + + dp_info("invalid flow index: %u", fst->stats.invalid_flow_index); + dp_info("workqueue update deferred: %u", fst->stats.update_deferred); + dp_info("reo_mismatch: cce_match: %u", + fst->stats.reo_mismatch.allow_cce_match); + dp_info("reo_mismatch: allow_fse_metdata_mismatch: %u", + fst->stats.reo_mismatch.allow_fse_metdata_mismatch); + dp_info("reo_mismatch: allow_non_aggr: %u", + fst->stats.reo_mismatch.allow_non_aggr); +} + +/* Length of string to store tuple information for printing */ +#define DP_TUPLE_STR_LEN 512 + +/** + * print_flow_tuple() - Debug function to dump flow tuple + * @flow_tuple: flow tuple containing tuple info + * @str: destination buffer + * @size: size of @str + * + * Return: NONE + */ +static +void print_flow_tuple(struct cdp_rx_flow_tuple_info *flow_tuple, char *str, + uint32_t size) +{ + qdf_scnprintf(str, size, + "dest 0x%x%x%x%x(0x%x) src 0x%x%x%x%x(0x%x) proto 0x%x", + flow_tuple->dest_ip_127_96, + flow_tuple->dest_ip_95_64, + flow_tuple->dest_ip_63_32, + flow_tuple->dest_ip_31_0, + flow_tuple->dest_port, + flow_tuple->src_ip_127_96, + flow_tuple->src_ip_95_64, + flow_tuple->src_ip_63_32, + flow_tuple->src_ip_31_0, + flow_tuple->src_port, + flow_tuple->l4_protocol); +} + +static QDF_STATUS dp_rx_dump_fisa_stats(struct wlan_dp_psoc_context *dp_ctx) +{ + char tuple_str[DP_TUPLE_STR_LEN] = {'\0'}; + struct dp_rx_fst *rx_fst = dp_ctx->rx_fst; + struct dp_fisa_rx_sw_ft *sw_ft_entry = + &((struct dp_fisa_rx_sw_ft *)rx_fst->base)[0]; + int ft_size = rx_fst->max_entries; + int i; + + dp_info("#flows added %d evicted %d hash collision %d", + rx_fst->add_flow_count, + rx_fst->del_flow_count, + rx_fst->hash_collision_cnt); + + for (i = 0; i < ft_size; i++, sw_ft_entry++) { + if (!sw_ft_entry->is_populated) + continue; + + print_flow_tuple(&sw_ft_entry->rx_flow_tuple_info, + tuple_str, + sizeof(tuple_str)); + + dp_info("Flow[%d][%s][%s] ring %d msdu-aggr %d flushes %d bytes-agg %llu avg-bytes-aggr %llu same_mld_vdev_mismatch %llu", + sw_ft_entry->flow_id, + sw_ft_entry->is_flow_udp ? "udp" : "tcp", + tuple_str, + sw_ft_entry->napi_id, + sw_ft_entry->aggr_count, + sw_ft_entry->flush_count, + sw_ft_entry->bytes_aggregated, + qdf_do_div(sw_ft_entry->bytes_aggregated, + sw_ft_entry->flush_count), + sw_ft_entry->same_mld_vdev_mismatch); + } + return QDF_STATUS_SUCCESS; +} + +void dp_set_fst_in_cmem(bool fst_in_cmem) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + + dp_ctx->fst_in_cmem = fst_in_cmem; +} + +void dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + + switch (stats_id) { + case CDP_FISA_STATS_ID_ERR_STATS: + dp_print_fisa_stats(dp_ctx); + break; + case CDP_FISA_STATS_ID_DUMP_HW_FST: + dp_rx_dump_fisa_table(dp_ctx); + break; + case CDP_FISA_STATS_ID_DUMP_SW_FST: + dp_rx_dump_fisa_stats(dp_ctx); + break; + default: + break; + } +} + +/** + * dp_rx_flow_send_htt_operation_cmd() - Invalidate FSE cache on FT change + * @dp_ctx: DP component handle + * @fse_op: Cache operation code + * @rx_flow_tuple: flow tuple whose entry has to be invalidated + * + * Return: Success if we successfully send FW HTT command + */ +static QDF_STATUS +dp_rx_flow_send_htt_operation_cmd(struct wlan_dp_psoc_context *dp_ctx, + enum dp_htt_flow_fst_operation fse_op, + struct cdp_rx_flow_tuple_info *rx_flow_tuple) +{ + struct dp_htt_rx_flow_fst_operation fse_op_cmd; + struct cdp_rx_flow_info rx_flow_info; + union cdp_fisa_config cfg; + + rx_flow_info.is_addr_ipv4 = true; + rx_flow_info.op_code = CDP_FLOW_FST_ENTRY_ADD; + qdf_mem_copy(&rx_flow_info.flow_tuple_info, rx_flow_tuple, + sizeof(struct cdp_rx_flow_tuple_info)); + rx_flow_info.fse_metadata = 0xDADA; + fse_op_cmd.pdev_id = OL_TXRX_PDEV_ID; + fse_op_cmd.op_code = fse_op; + fse_op_cmd.rx_flow = &rx_flow_info; + + cfg.fse_op_cmd = &fse_op_cmd; + + return cdp_txrx_fisa_config(dp_ctx->cdp_soc, OL_TXRX_PDEV_ID, + CDP_FISA_HTT_RX_FSE_OP_CFG, &cfg); +} + +/** + * dp_fisa_fse_cache_flush_timer() - FSE cache flush timeout handler + * @arg: SoC handle + * + * Return: None + */ +static void dp_fisa_fse_cache_flush_timer(void *arg) +{ + struct wlan_dp_psoc_context *dp_ctx = + (struct wlan_dp_psoc_context *)arg; + struct dp_rx_fst *fisa_hdl = dp_ctx->rx_fst; + struct cdp_rx_flow_tuple_info rx_flow_tuple_info = { 0 }; + static uint32_t fse_cache_flush_rec_idx; + struct fse_cache_flush_history *fse_cache_flush_rec; + QDF_STATUS status; + + if (!fisa_hdl) + return; + + if (qdf_atomic_read(&fisa_hdl->pm_suspended)) { + qdf_atomic_set(&fisa_hdl->fse_cache_flush_posted, 0); + return; + } + + fse_cache_flush_rec = &fisa_hdl->cache_fl_rec[fse_cache_flush_rec_idx % + MAX_FSE_CACHE_FL_HST]; + fse_cache_flush_rec->timestamp = qdf_get_log_timestamp(); + fse_cache_flush_rec->flows_added = + qdf_atomic_read(&fisa_hdl->fse_cache_flush_posted); + fse_cache_flush_rec_idx++; + dp_info("FSE cache flush for %d flows", + fse_cache_flush_rec->flows_added); + + status = + dp_rx_flow_send_htt_operation_cmd(dp_ctx, + DP_HTT_FST_CACHE_INVALIDATE_FULL, + &rx_flow_tuple_info); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to send the cache invalidation"); + /* + * Not big impact cache entry gets updated later + */ + } + + qdf_atomic_set(&fisa_hdl->fse_cache_flush_posted, 0); +} + +/** + * dp_rx_fst_cmem_deinit() - De-initialize CMEM parameters + * @fst: Pointer to DP FST + * + * Return: None + */ +static void dp_rx_fst_cmem_deinit(struct dp_rx_fst *fst) +{ + struct dp_fisa_rx_fst_update_elem *elem; + qdf_list_node_t *node; + int i; + + qdf_cancel_work(&fst->fst_update_work); + qdf_flush_work(&fst->fst_update_work); + qdf_flush_workqueue(0, fst->fst_update_wq); + qdf_destroy_workqueue(0, fst->fst_update_wq); + + qdf_spin_lock_bh(&fst->dp_rx_fst_lock); + while (qdf_list_peek_front(&fst->fst_update_list, &node) == + QDF_STATUS_SUCCESS) { + elem = (struct dp_fisa_rx_fst_update_elem *)node; + qdf_list_remove_front(&fst->fst_update_list, &node); + qdf_mem_free(elem); + } + qdf_spin_unlock_bh(&fst->dp_rx_fst_lock); + + qdf_list_destroy(&fst->fst_update_list); + qdf_event_destroy(&fst->cmem_resp_event); + + for (i = 0; i < MAX_REO_DEST_RINGS; i++) + qdf_spinlock_destroy(&fst->dp_rx_sw_ft_lock[i]); +} + +/** + * dp_rx_fst_cmem_init() - Initialize CMEM parameters + * @fst: Pointer to DP FST + * + * Return: Success/Failure + */ +static QDF_STATUS dp_rx_fst_cmem_init(struct dp_rx_fst *fst) +{ + int i; + + fst->fst_update_wq = + qdf_alloc_high_prior_ordered_workqueue("dp_rx_fst_update_wq"); + if (!fst->fst_update_wq) { + dp_err("failed to allocate fst update wq"); + return QDF_STATUS_E_FAILURE; + } + + qdf_create_work(0, &fst->fst_update_work, + dp_fisa_rx_fst_update_work, fst); + qdf_list_create(&fst->fst_update_list, 128); + qdf_event_create(&fst->cmem_resp_event); + + for (i = 0; i < MAX_REO_DEST_RINGS; i++) + qdf_spinlock_create(&fst->dp_rx_sw_ft_lock[i]); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_SUPPORT_RX_FISA_HIST +static +QDF_STATUS dp_rx_sw_ft_hist_init(struct dp_fisa_rx_sw_ft *sw_ft, + uint32_t max_entries, + uint32_t rx_pkt_tlv_size) +{ + int i; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + for (i = 0; i < max_entries; i++) { + sw_ft[i].pkt_hist.tlv_hist = + (uint8_t *)qdf_mem_malloc(rx_pkt_tlv_size * + FISA_FLOW_MAX_AGGR_COUNT); + if (!sw_ft[i].pkt_hist.tlv_hist) { + dp_err("unable to allocate tlv history"); + qdf_status = QDF_STATUS_E_NOMEM; + break; + } + } + return qdf_status; +} + +static void dp_rx_sw_ft_hist_deinit(struct dp_fisa_rx_sw_ft *sw_ft, + uint32_t max_entries) +{ + int i; + + for (i = 0; i < max_entries; i++) { + if (sw_ft[i].pkt_hist.tlv_hist) + qdf_mem_free(sw_ft[i].pkt_hist.tlv_hist); + } +} + +#else + +static +QDF_STATUS dp_rx_sw_ft_hist_init(struct dp_fisa_rx_sw_ft *sw_ft, + uint32_t max_entries, + uint32_t rx_pkt_tlv_size) +{ + return QDF_STATUS_SUCCESS; +} + +static void dp_rx_sw_ft_hist_deinit(struct dp_fisa_rx_sw_ft *sw_ft, + uint32_t max_entries) +{ +} +#endif + +QDF_STATUS dp_rx_fst_attach(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_soc *soc = (struct dp_soc *)dp_ctx->cdp_soc; + struct wlan_dp_psoc_cfg *dp_cfg = &dp_ctx->dp_cfg; + struct dp_rx_fst *fst; + struct dp_fisa_rx_sw_ft *ft_entry; + cdp_config_param_type soc_param; + int i = 0; + QDF_STATUS status; + + /* Check if it is enabled in the INI */ + if (!wlan_dp_cfg_is_rx_fisa_enabled(dp_cfg)) { + dp_err("RX FISA feature is disabled"); + return QDF_STATUS_E_NOSUPPORT; + } + +#ifdef NOT_YET /* Not required for now */ + /* Check if FW supports */ + if (!wlan_psoc_nif_fw_ext_cap_get((void *)pdev->ctrl_pdev, + WLAN_SOC_CEXT_RX_FSE_SUPPORT)) { + QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR, + "rx fse disabled in FW\n"); + wlan_cfg_set_rx_flow_tag_enabled(cfg, false); + return QDF_STATUS_E_NOSUPPORT; + } +#endif + if (dp_ctx->rx_fst) { + QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR, + "RX FST already allocated\n"); + return QDF_STATUS_SUCCESS; + } + + fst = qdf_mem_malloc(sizeof(struct dp_rx_fst)); + if (!fst) + return QDF_STATUS_E_NOMEM; + + fst->rx_pkt_tlv_size = 0; + status = cdp_txrx_get_psoc_param(dp_ctx->cdp_soc, CDP_RX_PKT_TLV_SIZE, + &soc_param); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Unable to fetch RX pkt tlv size"); + return status; + } + + fst->rx_pkt_tlv_size = soc_param.rx_pkt_tlv_size; + + /* This will clear entire FISA params */ + soc_param.fisa_params.rx_toeplitz_hash_key = NULL; + status = cdp_txrx_get_psoc_param(dp_ctx->cdp_soc, CDP_CFG_FISA_PARAMS, + &soc_param); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Unable to fetch fisa params"); + return status; + } + + fst->max_skid_length = soc_param.fisa_params.rx_flow_max_search; + fst->max_entries = soc_param.fisa_params.fisa_fst_size; + fst->rx_toeplitz_hash_key = soc_param.fisa_params.rx_toeplitz_hash_key; + + fst->hash_mask = fst->max_entries - 1; + fst->num_entries = 0; + dp_info("FST setup params FT size %d, hash_mask 0x%x, skid_length %d", + fst->max_entries, fst->hash_mask, fst->max_skid_length); + + /* Allocate the software flowtable */ + fst->base = (uint8_t *)dp_context_alloc_mem(soc, DP_FISA_RX_FT_TYPE, + DP_RX_GET_SW_FT_ENTRY_SIZE * fst->max_entries); + + if (!fst->base) + goto free_rx_fst; + + ft_entry = (struct dp_fisa_rx_sw_ft *)fst->base; + + for (i = 0; i < fst->max_entries; i++) + ft_entry[i].napi_id = INVALID_NAPI; + + status = dp_rx_sw_ft_hist_init(ft_entry, fst->max_entries, + fst->rx_pkt_tlv_size); + if (QDF_IS_STATUS_ERROR(status)) + goto free_hist; + + fst->hal_rx_fst = hal_rx_fst_attach(dp_ctx->hal_soc, + dp_ctx->qdf_dev, + &fst->hal_rx_fst_base_paddr, + fst->max_entries, + fst->max_skid_length, + fst->rx_toeplitz_hash_key, + dp_ctx->fst_cmem_base); + + if (qdf_unlikely(!fst->hal_rx_fst)) { + QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR, + "Rx Hal fst allocation failed, #entries:%d\n", + fst->max_entries); + goto free_hist; + } + + qdf_spinlock_create(&fst->dp_rx_fst_lock); + + status = qdf_timer_init(dp_ctx->qdf_dev, &fst->fse_cache_flush_timer, + dp_fisa_fse_cache_flush_timer, (void *)dp_ctx, + QDF_TIMER_TYPE_WAKE_APPS); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR, + "Failed to init cache_flush_timer\n"); + goto timer_init_fail; + } + + qdf_atomic_init(&fst->fse_cache_flush_posted); + + fst->fse_cache_flush_allow = true; + fst->rx_hash_enabled = wlan_cfg_is_rx_hash_enabled(soc->wlan_cfg_ctx); + fst->soc_hdl = soc; + fst->dp_ctx = dp_ctx; + dp_ctx->rx_fst = fst; + dp_ctx->fisa_enable = true; + dp_ctx->fisa_lru_del_enable = + wlan_dp_cfg_is_rx_fisa_lru_del_enabled(dp_cfg); + + qdf_atomic_init(&dp_ctx->skip_fisa_param.skip_fisa); + qdf_atomic_init(&fst->pm_suspended); + + QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR, + "Rx FST attach successful, #entries:%d\n", + fst->max_entries); + + qdf_ssr_driver_dump_register_region("dp_fisa", fst, sizeof(*fst)); + qdf_ssr_driver_dump_register_region("dp_fisa_sw_fse_table", fst->base, + DP_RX_GET_SW_FT_ENTRY_SIZE * + fst->max_entries); + + return QDF_STATUS_SUCCESS; + +timer_init_fail: + qdf_spinlock_destroy(&fst->dp_rx_fst_lock); + hal_rx_fst_detach(dp_ctx->hal_soc, fst->hal_rx_fst, dp_ctx->qdf_dev, + dp_ctx->fst_cmem_base); +free_hist: + dp_rx_sw_ft_hist_deinit((struct dp_fisa_rx_sw_ft *)fst->base, + fst->max_entries); + dp_context_free_mem(soc, DP_FISA_RX_FT_TYPE, fst->base); +free_rx_fst: + qdf_mem_free(fst); + return QDF_STATUS_E_NOMEM; +} + +/** + * dp_rx_fst_check_cmem_support() - Check if FW can allocate FSE in CMEM, + * allocate FSE in DDR if FW doesn't support CMEM allocation + * @dp_ctx: DP component context + * + * Return: None + */ +static void dp_rx_fst_check_cmem_support(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rx_fst *fst = dp_ctx->rx_fst; + QDF_STATUS status; + + /** + * FW doesn't support CMEM FSE, keep it in DDR + * dp_ctx->fst_cmem_base is non-NULL then CMEM support is + * already present + */ + if (!dp_ctx->fst_in_cmem && dp_ctx->fst_cmem_base == 0) + return; + + status = dp_rx_fst_cmem_init(fst); + if (status != QDF_STATUS_SUCCESS) + return; + + hal_rx_fst_detach(dp_ctx->hal_soc, fst->hal_rx_fst, dp_ctx->qdf_dev, + dp_ctx->fst_cmem_base); + fst->hal_rx_fst = NULL; + fst->hal_rx_fst_base_paddr = 0; + fst->flow_deletion_supported = true; + fst->fst_in_cmem = true; +} + +/** + * dp_rx_flow_send_fst_fw_setup() - Program FST parameters in FW/HW post-attach + * @dp_ctx: DP component context + * + * Return: Success when fst parameters are programmed in FW, error otherwise + */ +static QDF_STATUS +dp_rx_flow_send_fst_fw_setup(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_htt_rx_flow_fst_setup fisa_hw_fst_setup_cmd = {0}; + struct dp_rx_fst *fst = dp_ctx->rx_fst; + union cdp_fisa_config cfg; + QDF_STATUS status; + + /* check if FW has support to place FST in CMEM */ + dp_rx_fst_check_cmem_support(dp_ctx); + + /* mac_id = 0 is used to configure both macs with same FT */ + fisa_hw_fst_setup_cmd.pdev_id = 0; + fisa_hw_fst_setup_cmd.max_entries = fst->max_entries; + fisa_hw_fst_setup_cmd.max_search = fst->max_skid_length; + if (dp_ctx->fst_cmem_base) { + fisa_hw_fst_setup_cmd.base_addr_lo = + dp_ctx->fst_cmem_base & 0xffffffff; + /* Higher order bits are mostly 0, Always use 0x10 */ + fisa_hw_fst_setup_cmd.base_addr_hi = + (dp_ctx->fst_cmem_base >> 32) | 0x10; + dp_info("cmem base address 0x%llx", dp_ctx->fst_cmem_base); + } else { + fisa_hw_fst_setup_cmd.base_addr_lo = + fst->hal_rx_fst_base_paddr & 0xffffffff; + fisa_hw_fst_setup_cmd.base_addr_hi = + (fst->hal_rx_fst_base_paddr >> 32); + } + + fisa_hw_fst_setup_cmd.ip_da_sa_prefix = HTT_RX_IPV4_COMPATIBLE_IPV6; + fisa_hw_fst_setup_cmd.hash_key_len = HAL_FST_HASH_KEY_SIZE_BYTES; + fisa_hw_fst_setup_cmd.hash_key = fst->rx_toeplitz_hash_key; + + cfg.fse_setup_info = &fisa_hw_fst_setup_cmd; + + status = cdp_txrx_fisa_config(dp_ctx->cdp_soc, OL_TXRX_PDEV_ID, + CDP_FISA_HTT_RX_FSE_SETUP_CFG, &cfg); + if (!fst->fst_in_cmem || dp_ctx->fst_cmem_base) { + /** + * Return from here if fst_cmem is not enabled or cmem address + * is known at init time + */ + return status; + } + + status = qdf_wait_single_event(&fst->cmem_resp_event, + DP_RX_FST_CMEM_RESP_TIMEOUT); + + dp_err("FST params after CMEM update FT size %d, hash_mask 0x%x", + fst->max_entries, fst->hash_mask); + + return status; +} + +void dp_rx_fst_detach(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_soc *soc = (struct dp_soc *)dp_ctx->cdp_soc; + struct dp_rx_fst *dp_fst; + + dp_fst = dp_ctx->rx_fst; + if (qdf_likely(dp_fst)) { + qdf_ssr_driver_dump_unregister_region("dp_fisa_sw_fse_table"); + qdf_ssr_driver_dump_unregister_region("dp_fisa"); + qdf_timer_sync_cancel(&dp_fst->fse_cache_flush_timer); + if (dp_fst->fst_in_cmem) + dp_rx_fst_cmem_deinit(dp_fst); + else + hal_rx_fst_detach(soc->hal_soc, dp_fst->hal_rx_fst, + soc->osdev, dp_ctx->fst_cmem_base); + + dp_rx_sw_ft_hist_deinit((struct dp_fisa_rx_sw_ft *)dp_fst->base, + dp_fst->max_entries); + dp_context_free_mem(soc, DP_FISA_RX_FT_TYPE, dp_fst->base); + qdf_spinlock_destroy(&dp_fst->dp_rx_fst_lock); + qdf_mem_free(dp_fst); + } + + dp_ctx->rx_fst = NULL; + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, + "Rx FST detached\n"); +} + +/* + * dp_rx_fst_update_cmem_params() - Update CMEM FST params + * @soc: DP SoC context + * @num_entries: Number of flow search entries + * @cmem_ba_lo: CMEM base address low + * @cmem_ba_hi: CMEM base address high + * + * Return: None + */ +void dp_rx_fst_update_cmem_params(struct dp_soc *soc, uint16_t num_entries, + uint32_t cmem_ba_lo, uint32_t cmem_ba_hi) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + struct dp_rx_fst *fst = dp_ctx->rx_fst; + + fst->max_entries = num_entries; + fst->hash_mask = fst->max_entries - 1; + fst->cmem_ba = cmem_ba_lo; + + /* Address is not NULL then address is already known during init */ + if (dp_ctx->fst_cmem_base == 0) + qdf_event_set(&fst->cmem_resp_event); +} + +void dp_rx_fst_update_pm_suspend_status(struct wlan_dp_psoc_context *dp_ctx, + bool suspended) +{ + struct dp_rx_fst *fst = dp_ctx->rx_fst; + + if (!fst) + return; + + if (suspended) + qdf_atomic_set(&fst->pm_suspended, 1); + else + qdf_atomic_set(&fst->pm_suspended, 0); +} + +void dp_rx_fst_requeue_wq(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_rx_fst *fst = dp_ctx->rx_fst; + + if (!fst || !fst->fst_wq_defer) + return; + + fst->fst_wq_defer = false; + qdf_queue_work(fst->soc_hdl->osdev, + fst->fst_update_wq, + &fst->fst_update_work); + + dp_info("requeued defer fst update task"); +} + +QDF_STATUS dp_rx_fst_target_config(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_soc *soc = cdp_soc_t_to_dp_soc(dp_ctx->cdp_soc); + QDF_STATUS status; + struct dp_rx_fst *fst = dp_ctx->rx_fst; + + /* Check if it is enabled in the INI */ + if (!dp_ctx->fisa_enable) { + dp_err("RX FISA feature is disabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + status = dp_rx_flow_send_fst_fw_setup(dp_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("dp_rx_flow_send_fst_fw_setup failed %d", + status); + return status; + } + + if (dp_ctx->fst_cmem_base) { + dp_ctx->fst_in_cmem = true; + dp_rx_fst_update_cmem_params(soc, fst->max_entries, + dp_ctx->fst_cmem_base & 0xffffffff, + dp_ctx->fst_cmem_base >> 32); + } + return status; +} + +static uint8_t +dp_rx_fisa_get_max_aggr_supported(struct wlan_dp_psoc_context *dp_ctx) +{ + if (!dp_ctx->fisa_dynamic_aggr_size_support) + return DP_RX_FISA_MAX_AGGR_COUNT_DEFAULT; + + switch (hal_get_target_type(dp_ctx->hal_soc)) { + case TARGET_TYPE_WCN6450: + return DP_RX_FISA_MAX_AGGR_COUNT_1; + default: + return DP_RX_FISA_MAX_AGGR_COUNT_DEFAULT; + } +} + +#define FISA_MAX_TIMEOUT 0xffffffff +#define FISA_DISABLE_TIMEOUT 0 +QDF_STATUS dp_rx_fisa_config(struct wlan_dp_psoc_context *dp_ctx) +{ + struct dp_htt_rx_fisa_cfg fisa_config; + union cdp_fisa_config cfg; + + fisa_config.pdev_id = 0; + fisa_config.fisa_timeout = FISA_MAX_TIMEOUT; + fisa_config.max_aggr_supported = + dp_rx_fisa_get_max_aggr_supported(dp_ctx); + + cfg.fisa_config = &fisa_config; + + return cdp_txrx_fisa_config(dp_ctx->cdp_soc, OL_TXRX_PDEV_ID, + CDP_FISA_HTT_RX_FISA_CFG, &cfg); +} + +void dp_fisa_cfg_init(struct wlan_dp_psoc_cfg *config, + struct wlan_objmgr_psoc *psoc) +{ + config->fisa_enable = cfg_get(psoc, CFG_DP_RX_FISA_ENABLE); + config->is_rx_fisa_enabled = cfg_get(psoc, CFG_DP_RX_FISA_ENABLE); + config->is_rx_fisa_lru_del_enabled = + cfg_get(psoc, CFG_DP_RX_FISA_LRU_DEL_ENABLE); +} +#else /* WLAN_SUPPORT_RX_FISA */ + +#endif /* !WLAN_SUPPORT_RX_FISA */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_rx_thread.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_rx_thread.c new file mode 100644 index 0000000000..39a813a99b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_rx_thread.c @@ -0,0 +1,1637 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "dp_peer.h" +#include "dp_internal.h" +#include "dp_types.h" +#include +#include +#include +#include "dp_rx.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_dp_prealloc.h" +#include "wlan_dp_main.h" +#include "wlan_dp_public_struct.h" +#include "wlan_dp_ucfg_api.h" +#include "qdf_nbuf.h" +#include "qdf_threads.h" +#include "qdf_net_if.h" + +/* Timeout in ms to wait for a DP rx thread */ +#ifdef HAL_CONFIG_SLUB_DEBUG_ON +#define DP_RX_THREAD_WAIT_TIMEOUT 4000 +#else +#define DP_RX_THREAD_WAIT_TIMEOUT 2000 +#endif +#define DP_RX_THREAD_FLUSH_TIMEOUT 6000 +#define DP_RX_THREAD_MIN_FLUSH_TIMEOUT 10 + +#ifdef CONFIG_SLUB_DEBUG_ON +/* number of rx pkts that thread should yield */ +#define DP_RX_THREAD_YIELD_PKT_CNT 20000 +#endif + +#define DP_RX_TM_DEBUG 0 +#if DP_RX_TM_DEBUG +/** + * dp_rx_tm_walk_skb_list() - Walk skb list and print members + * @nbuf_list: nbuf list to print + * + * Returns: None + */ +static inline void dp_rx_tm_walk_skb_list(qdf_nbuf_t nbuf_list) +{ + qdf_nbuf_t nbuf; + int i = 0; + + nbuf = nbuf_list; + while (nbuf) { + dp_debug("%d nbuf:%pK nbuf->next:%pK nbuf->data:%pK", i, + nbuf, qdf_nbuf_next(nbuf), qdf_nbuf_data(nbuf)); + nbuf = qdf_nbuf_next(nbuf); + i++; + } +} +#else +static inline void dp_rx_tm_walk_skb_list(qdf_nbuf_t nbuf_list) +{ } +#endif /* DP_RX_TM_DEBUG */ + +#ifdef DP_RX_REFILL_CPU_PERF_AFFINE_MASK +/** + * dp_rx_refill_thread_set_affinity - Affine Rx refill threads + * @refill_thread: Contains over all rx refill thread info + * + * Return: None + */ +static void +dp_rx_refill_thread_set_affinity(struct dp_rx_refill_thread *refill_thread) +{ + unsigned int cpus; + char new_mask_str[10]; + qdf_cpu_mask new_mask; + int perf_cpu_cluster = hif_get_perf_cluster_bitmap(); + int package_id; + + qdf_cpumask_clear(&new_mask); + qdf_for_each_online_cpu(cpus) { + package_id = qdf_topology_physical_package_id(cpus); + if (package_id >= 0 && BIT(package_id) & perf_cpu_cluster) + qdf_cpumask_set_cpu(cpus, &new_mask); + } + + qdf_thread_set_cpus_allowed_mask(refill_thread->task, &new_mask); + + qdf_thread_cpumap_print_to_pagebuf(false, new_mask_str, &new_mask); + dp_debug("Refill Thread CPU mask %s", new_mask_str); +} +#else +static void +dp_rx_refill_thread_set_affinity(struct dp_rx_refill_thread *refill_thread) +{ +} +#endif +/** + * dp_rx_tm_get_soc_handle() - get soc handle from struct dp_rx_tm_handle_cmn + * @rx_tm_handle_cmn: rx thread manager cmn handle + * + * Returns: ol_txrx_soc_handle on success, NULL on failure. + */ +static inline ol_txrx_soc_handle +dp_rx_tm_get_soc_handle(struct dp_rx_tm_handle_cmn *rx_tm_handle_cmn) +{ + struct dp_txrx_handle_cmn *txrx_handle_cmn; + ol_txrx_soc_handle soc; + + txrx_handle_cmn = + dp_rx_thread_get_txrx_handle(rx_tm_handle_cmn); + + soc = dp_txrx_get_soc_from_ext_handle(txrx_handle_cmn); + return soc; +} + +/** + * dp_rx_tm_thread_dump_stats() - display stats for a rx_thread + * @rx_thread: rx_thread pointer for which the stats need to be + * displayed + * + * Returns: None + */ +static void dp_rx_tm_thread_dump_stats(struct dp_rx_thread *rx_thread) +{ + uint8_t reo_ring_num; + uint32_t off = 0; + char nbuf_queued_string[100]; + uint32_t total_queued = 0; + uint32_t temp = 0; + + qdf_mem_zero(nbuf_queued_string, sizeof(nbuf_queued_string)); + + for (reo_ring_num = 0; reo_ring_num < DP_RX_TM_MAX_REO_RINGS; + reo_ring_num++) { + temp = rx_thread->stats.nbuf_queued[reo_ring_num]; + if (!temp) + continue; + total_queued += temp; + if (off >= sizeof(nbuf_queued_string)) + continue; + off += qdf_scnprintf(&nbuf_queued_string[off], + sizeof(nbuf_queued_string) - off, + "reo[%u]:%u ", reo_ring_num, temp); + } + + if (!total_queued) + return; + + dp_info("thread:%u - qlen:%u queued:(total:%u %s) dequeued:%u stack:%u gro_flushes: %u gro_flushes_by_vdev_del: %u rx_flushes: %u max_len:%u invalid(peer:%u vdev:%u rx-handle:%u others:%u enq fail:%u)", + rx_thread->id, + qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue), + total_queued, + nbuf_queued_string, + rx_thread->stats.nbuf_dequeued, + rx_thread->stats.nbuf_sent_to_stack, + rx_thread->stats.gro_flushes, + rx_thread->stats.gro_flushes_by_vdev_del, + rx_thread->stats.rx_flushed, + rx_thread->stats.nbufq_max_len, + rx_thread->stats.dropped_invalid_peer, + rx_thread->stats.dropped_invalid_vdev, + rx_thread->stats.dropped_invalid_os_rx_handles, + rx_thread->stats.dropped_others, + rx_thread->stats.dropped_enq_fail); +} + +QDF_STATUS dp_rx_tm_dump_stats(struct dp_rx_tm_handle *rx_tm_hdl) +{ + int i; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i]) + continue; + dp_rx_tm_thread_dump_stats(rx_tm_hdl->rx_thread[i]); + } + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_ALLOW_PKT_DROPPING +/* + * dp_check_and_update_pending() - Check and Set RX Pending flag + * @tm_handle_cmn: DP thread pointer + * + * Returns: QDF_STATUS_SUCCESS on success or qdf error code on + * failure + */ +static inline +QDF_STATUS dp_check_and_update_pending(struct dp_rx_tm_handle_cmn + *tm_handle_cmn) +{ + struct dp_txrx_handle_cmn *txrx_handle_cmn; + struct dp_rx_tm_handle *rx_tm_hdl = + (struct dp_rx_tm_handle *)tm_handle_cmn; + struct dp_soc *dp_soc; + uint32_t rx_pending_hl_threshold; + uint32_t rx_pending_lo_threshold; + uint32_t nbuf_queued_total = 0; + uint32_t nbuf_dequeued_total = 0; + uint32_t rx_flushed_total = 0; + uint32_t pending = 0; + int i; + + txrx_handle_cmn = + dp_rx_thread_get_txrx_handle(tm_handle_cmn); + if (!txrx_handle_cmn) { + dp_err("invalid txrx_handle_cmn!"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + dp_soc = (struct dp_soc *)dp_txrx_get_soc_from_ext_handle( + txrx_handle_cmn); + if (!dp_soc) { + dp_err("invalid soc!"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + rx_pending_hl_threshold = wlan_cfg_rx_pending_hl_threshold( + dp_soc->wlan_cfg_ctx); + rx_pending_lo_threshold = wlan_cfg_rx_pending_lo_threshold( + dp_soc->wlan_cfg_ctx); + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (likely(rx_tm_hdl->rx_thread[i])) { + nbuf_queued_total += + rx_tm_hdl->rx_thread[i]->stats.nbuf_queued_total; + nbuf_dequeued_total += + rx_tm_hdl->rx_thread[i]->stats.nbuf_dequeued; + rx_flushed_total += + rx_tm_hdl->rx_thread[i]->stats.rx_flushed; + } + } + + if (nbuf_queued_total > (nbuf_dequeued_total + rx_flushed_total)) + pending = nbuf_queued_total - (nbuf_dequeued_total + + rx_flushed_total); + + if (unlikely(pending > rx_pending_hl_threshold)) + qdf_atomic_set(&rx_tm_hdl->allow_dropping, 1); + else if (pending < rx_pending_lo_threshold) + qdf_atomic_set(&rx_tm_hdl->allow_dropping, 0); + + return QDF_STATUS_SUCCESS; +} + +#else +static inline +QDF_STATUS dp_check_and_update_pending(struct dp_rx_tm_handle_cmn + *tm_handle_cmn) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * dp_rx_tm_thread_enqueue() - enqueue nbuf list into rx_thread + * @rx_thread: rx_thread in which the nbuf needs to be queued + * @nbuf_list: list of packets to be queued into the thread + * + * Enqueue packet into rx_thread and wake it up. The function + * moves the next pointer of the nbuf_list into the ext list of + * the first nbuf for storage into the thread. Only the first + * nbuf is queued into the thread nbuf queue. The reverse is + * done at the time of dequeue. + * + * Returns: QDF_STATUS_SUCCESS on success or qdf error code on + * failure + */ +static QDF_STATUS dp_rx_tm_thread_enqueue(struct dp_rx_thread *rx_thread, + qdf_nbuf_t nbuf_list) +{ + qdf_nbuf_t head_ptr, next_ptr_list; + uint32_t temp_qlen; + uint32_t num_elements_in_nbuf; + uint32_t nbuf_queued; + struct dp_rx_tm_handle_cmn *tm_handle_cmn; + uint8_t reo_ring_num = QDF_NBUF_CB_RX_CTX_ID(nbuf_list); + qdf_wait_queue_head_t *wait_q_ptr; + uint8_t allow_dropping; + + tm_handle_cmn = rx_thread->rtm_handle_cmn; + + if (!tm_handle_cmn) { + dp_alert("tm_handle_cmn is null!"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + wait_q_ptr = &rx_thread->wait_q; + + if (reo_ring_num >= DP_RX_TM_MAX_REO_RINGS) { + dp_alert("incorrect ring %u", reo_ring_num); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + num_elements_in_nbuf = QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf_list); + nbuf_queued = num_elements_in_nbuf; + + allow_dropping = qdf_atomic_read( + &((struct dp_rx_tm_handle *)tm_handle_cmn)->allow_dropping); + if (unlikely(allow_dropping)) { + qdf_nbuf_list_free(nbuf_list); + rx_thread->stats.dropped_enq_fail += num_elements_in_nbuf; + nbuf_queued = 0; + goto enq_done; + } + + dp_rx_tm_walk_skb_list(nbuf_list); + + head_ptr = nbuf_list; + + /* Ensure head doesn't have an ext list */ + while (qdf_unlikely(head_ptr && qdf_nbuf_get_ext_list(head_ptr))) { + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(head_ptr) = 1; + num_elements_in_nbuf--; + next_ptr_list = head_ptr->next; + qdf_nbuf_set_next(head_ptr, NULL); + /* count aggregated RX frame into enqueued stats */ + nbuf_queued += qdf_nbuf_get_gso_segs(head_ptr); + qdf_nbuf_queue_head_enqueue_tail(&rx_thread->nbuf_queue, + head_ptr); + head_ptr = next_ptr_list; + } + + if (!head_ptr) + goto enq_done; + + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(head_ptr) = num_elements_in_nbuf; + + next_ptr_list = head_ptr->next; + + if (next_ptr_list) { + /* move ->next pointer to ext list */ + qdf_nbuf_append_ext_list(head_ptr, next_ptr_list, 0); + dp_debug("appended next_ptr_list %pK to nbuf %pK ext list %pK", + qdf_nbuf_next(nbuf_list), nbuf_list, + qdf_nbuf_get_ext_list(nbuf_list)); + } + qdf_nbuf_set_next(head_ptr, NULL); + + qdf_nbuf_queue_head_enqueue_tail(&rx_thread->nbuf_queue, head_ptr); + +enq_done: + temp_qlen = qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue); + + rx_thread->stats.nbuf_queued[reo_ring_num] += nbuf_queued; + rx_thread->stats.nbuf_queued_total += nbuf_queued; + + dp_check_and_update_pending(tm_handle_cmn); + + if (temp_qlen > rx_thread->stats.nbufq_max_len) + rx_thread->stats.nbufq_max_len = temp_qlen; + + dp_debug("enqueue packet thread %pK wait queue %pK qlen %u", + rx_thread, wait_q_ptr, + qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue)); + + qdf_set_bit(RX_POST_EVENT, &rx_thread->event_flag); + qdf_wake_up_interruptible(wait_q_ptr); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_tm_thread_gro_flush_ind() - Rxthread flush ind post + * @rx_thread: rx_thread in which the flush needs to be handled + * @flush_code: flush code to differentiate low TPUT flush + * + * Return: QDF_STATUS_SUCCESS on success or qdf error code on + * failure + */ +static QDF_STATUS +dp_rx_tm_thread_gro_flush_ind(struct dp_rx_thread *rx_thread, + enum dp_rx_gro_flush_code flush_code) +{ + struct dp_rx_tm_handle_cmn *tm_handle_cmn; + qdf_wait_queue_head_t *wait_q_ptr; + + tm_handle_cmn = rx_thread->rtm_handle_cmn; + wait_q_ptr = &rx_thread->wait_q; + + qdf_atomic_set(&rx_thread->gro_flush_ind, flush_code); + + dp_debug("Flush indication received"); + + qdf_set_bit(RX_POST_EVENT, &rx_thread->event_flag); + qdf_wake_up_interruptible(wait_q_ptr); + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_thread_adjust_nbuf_list() - create an nbuf list from the frag list + * @head: nbuf list to be created + * + * Returns: void + */ +static void dp_rx_thread_adjust_nbuf_list(qdf_nbuf_t head) +{ + qdf_nbuf_t next_ptr_list, nbuf_list; + + nbuf_list = head; + if (head && QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(head) > 1) { + /* move ext list to ->next pointer */ + next_ptr_list = qdf_nbuf_get_ext_list(head); + qdf_nbuf_append_ext_list(head, NULL, 0); + qdf_nbuf_set_next(nbuf_list, next_ptr_list); + dp_rx_tm_walk_skb_list(nbuf_list); + } +} + +/** + * dp_rx_tm_thread_dequeue() - dequeue nbuf list from rx_thread + * @rx_thread: rx_thread from which the nbuf needs to be dequeued + * + * Returns: nbuf or nbuf_list dequeued from rx_thread + */ +static qdf_nbuf_t dp_rx_tm_thread_dequeue(struct dp_rx_thread *rx_thread) +{ + qdf_nbuf_t head; + + head = qdf_nbuf_queue_head_dequeue(&rx_thread->nbuf_queue); + dp_rx_thread_adjust_nbuf_list(head); + + dp_debug("Dequeued %pK nbuf_list", head); + return head; +} + +#ifdef CONFIG_SLUB_DEBUG_ON +/** + * dp_rx_thread_should_yield() - check whether rx loop should yield + * @iter: iteration of packets received + * @rx_thread: rx_thread which should yield + * + * Returns: should yield or not + */ +static inline bool dp_rx_thread_should_yield(struct dp_rx_thread *rx_thread, + uint32_t iter) +{ + if (iter >= DP_RX_THREAD_YIELD_PKT_CNT || + qdf_test_bit(RX_VDEV_DEL_EVENT, &rx_thread->event_flag)) + return true; + return false; +} +#else +static inline bool dp_rx_thread_should_yield(struct dp_rx_thread *rx_thread, + uint32_t iter) +{ + return false; +} +#endif + +/** + * dp_rx_thread_process_nbufq() - process nbuf queue of a thread + * @rx_thread: rx_thread whose nbuf queue needs to be processed + * + * Returns: 0 on success, error code on failure + */ +static int dp_rx_thread_process_nbufq(struct dp_rx_thread *rx_thread) +{ + qdf_nbuf_t nbuf_list; + uint8_t vdev_id; + ol_txrx_rx_fp stack_fn; + ol_osif_vdev_handle osif_vdev; + ol_txrx_soc_handle soc; + uint32_t num_list_elements = 0; + uint32_t iterates = 0; + + struct dp_txrx_handle_cmn *txrx_handle_cmn; + + txrx_handle_cmn = + dp_rx_thread_get_txrx_handle(rx_thread->rtm_handle_cmn); + + soc = dp_txrx_get_soc_from_ext_handle(txrx_handle_cmn); + if (!soc) { + dp_err("invalid soc!"); + QDF_BUG(0); + return -EFAULT; + } + + dp_debug("enter: qlen %u", + qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue)); + + nbuf_list = dp_rx_tm_thread_dequeue(rx_thread); + while (nbuf_list) { + num_list_elements = + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf_list); + /* count aggregated RX frame into stats */ + num_list_elements += qdf_nbuf_get_gso_segs(nbuf_list); + rx_thread->stats.nbuf_dequeued += num_list_elements; + iterates += num_list_elements; + + vdev_id = QDF_NBUF_CB_RX_VDEV_ID(nbuf_list); + cdp_get_os_rx_handles_from_vdev(soc, vdev_id, &stack_fn, + &osif_vdev); + dp_debug("rx_thread %pK sending packet %pK to stack", + rx_thread, nbuf_list); + if (!stack_fn || !osif_vdev || + QDF_STATUS_SUCCESS != stack_fn(osif_vdev, nbuf_list)) { + rx_thread->stats.dropped_invalid_os_rx_handles += + num_list_elements; + qdf_nbuf_list_free(nbuf_list); + } else { + rx_thread->stats.nbuf_sent_to_stack += + num_list_elements; + } + if (qdf_unlikely(dp_rx_thread_should_yield(rx_thread, + iterates))) { + rx_thread->stats.rx_nbufq_loop_yield++; + break; + } + nbuf_list = dp_rx_tm_thread_dequeue(rx_thread); + } + + dp_debug("exit: qlen %u", + qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue)); + + return 0; +} + +/** + * dp_rx_thread_gro_flush() - flush GRO packets for the RX thread + * @rx_thread: rx_thread to be processed + * @gro_flush_code: flush code to differentiating flushes + * + * Return: void + */ +static void dp_rx_thread_gro_flush(struct dp_rx_thread *rx_thread, + enum dp_rx_gro_flush_code gro_flush_code) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + if (!dp_ctx) { + dp_err("DP context is NULL"); + return; + } + dp_debug("flushing packets for thread %u", rx_thread->id); + qdf_local_bh_disable(); + dp_ctx->dp_ops.dp_rx_thread_napi_gro_flush(&rx_thread->napi, + gro_flush_code); + qdf_local_bh_enable(); + rx_thread->stats.gro_flushes++; +} + +/** + * dp_rx_should_flush() - Determines whether the RX thread should be flushed. + * @rx_thread: rx_thread to be processed + * + * Return: enum dp_rx_gro_flush_code + */ +static inline enum dp_rx_gro_flush_code +dp_rx_should_flush(struct dp_rx_thread *rx_thread) +{ + enum dp_rx_gro_flush_code gro_flush_code; + + gro_flush_code = qdf_atomic_read(&rx_thread->gro_flush_ind); + if (qdf_atomic_test_bit(RX_VDEV_DEL_EVENT, &rx_thread->event_flag)) + gro_flush_code = DP_RX_GRO_NORMAL_FLUSH; + + return gro_flush_code; +} + +/** + * dp_rx_thread_sub_loop() - rx thread subloop + * @rx_thread: rx_thread to be processed + * @shutdown: pointer to shutdown variable + * + * The function handles shutdown and suspend events from other + * threads and processes nbuf queue of a rx thread. In case a + * shutdown event is received from some other wlan thread, the + * function sets the shutdown pointer to true and returns + * + * Returns: 0 on success, error code on failure + */ +static int dp_rx_thread_sub_loop(struct dp_rx_thread *rx_thread, bool *shutdown) +{ + enum dp_rx_gro_flush_code gro_flush_code; + + while (true) { + if (qdf_atomic_test_and_clear_bit(RX_SHUTDOWN_EVENT, + &rx_thread->event_flag)) { + if (qdf_atomic_test_and_clear_bit(RX_SUSPEND_EVENT, + &rx_thread->event_flag)) { + qdf_event_set(&rx_thread->suspend_event); + } + dp_debug("shutting down (%s) id %d pid %d", + qdf_get_current_comm(), rx_thread->id, + qdf_get_current_pid()); + *shutdown = true; + break; + } + + dp_rx_thread_process_nbufq(rx_thread); + + gro_flush_code = dp_rx_should_flush(rx_thread); + /* Only flush when gro_flush_code is either + * DP_RX_GRO_NORMAL_FLUSH or DP_RX_GRO_LOW_TPUT_FLUSH + */ + if (gro_flush_code != DP_RX_GRO_NOT_FLUSH) { + dp_rx_thread_gro_flush(rx_thread, gro_flush_code); + qdf_atomic_set(&rx_thread->gro_flush_ind, 0); + } + + if (qdf_atomic_test_and_clear_bit(RX_VDEV_DEL_EVENT, + &rx_thread->event_flag)) { + rx_thread->stats.gro_flushes_by_vdev_del++; + qdf_event_set(&rx_thread->vdev_del_event); + if (qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue)) + continue; + } + + if (qdf_atomic_test_and_clear_bit(RX_SUSPEND_EVENT, + &rx_thread->event_flag)) { + dp_debug("received suspend ind (%s) id %d pid %d", + qdf_get_current_comm(), rx_thread->id, + qdf_get_current_pid()); + qdf_event_set(&rx_thread->suspend_event); + dp_debug("waiting for resume (%s) id %d pid %d", + qdf_get_current_comm(), rx_thread->id, + qdf_get_current_pid()); + qdf_wait_single_event(&rx_thread->resume_event, 0); + } + break; + } + return 0; +} + +/** + * dp_rx_thread_loop() - main dp rx thread loop + * @arg: pointer to dp_rx_thread structure for the rx thread + * + * Return: thread exit code + */ +static int dp_rx_thread_loop(void *arg) +{ + struct dp_rx_thread *rx_thread = arg; + bool shutdown = false; + int status; + QDF_STATUS status_intr; + struct dp_rx_tm_handle_cmn *tm_handle_cmn; + + if (!arg) { + dp_err("bad Args passed"); + return 0; + } + + tm_handle_cmn = rx_thread->rtm_handle_cmn; + + qdf_set_user_nice(qdf_get_current_task(), -1); + qdf_set_wake_up_idle(true); + + qdf_event_set(&rx_thread->start_event); + dp_info("starting rx_thread (%s) id %d pid %d", qdf_get_current_comm(), + rx_thread->id, qdf_get_current_pid()); + while (!shutdown) { + /* This implements the execution model algorithm */ + dp_debug("sleeping"); + status = + qdf_wait_queue_interruptible + (rx_thread->wait_q, + qdf_atomic_test_bit(RX_POST_EVENT, + &rx_thread->event_flag) || + qdf_atomic_test_bit(RX_SUSPEND_EVENT, + &rx_thread->event_flag) || + qdf_atomic_test_bit(RX_VDEV_DEL_EVENT, + &rx_thread->event_flag)); + dp_debug("woken up"); + status_intr = qdf_status_from_os_return(status); + if (status_intr == QDF_STATUS_E_RESTART) { + QDF_DEBUG_PANIC("wait_event_interruptible returned -ERESTARTSYS"); + break; + } + qdf_atomic_clear_bit(RX_POST_EVENT, &rx_thread->event_flag); + dp_rx_thread_sub_loop(rx_thread, &shutdown); + } + + /* If we get here the scheduler thread must exit */ + dp_info("exiting (%s) id %d pid %d", qdf_get_current_comm(), + rx_thread->id, qdf_get_current_pid()); + qdf_event_set(&rx_thread->shutdown_event); + + return 0; +} + +static int dp_rx_refill_thread_sub_loop(struct dp_rx_refill_thread *rx_thread, + bool *shutdown) +{ + while (true) { + if (qdf_atomic_test_and_clear_bit(RX_REFILL_SHUTDOWN_EVENT, + &rx_thread->event_flag)) { + if (qdf_atomic_test_and_clear_bit(RX_REFILL_SUSPEND_EVENT, + &rx_thread->event_flag)) { + qdf_event_set(&rx_thread->suspend_event); + } + dp_debug("shutting down (%s) pid %d", + qdf_get_current_comm(), qdf_get_current_pid()); + *shutdown = true; + break; + } + + dp_rx_refill_buff_pool_enqueue((struct dp_soc *)rx_thread->soc); + + if (qdf_atomic_test_and_clear_bit(RX_REFILL_SUSPEND_EVENT, + &rx_thread->event_flag)) { + dp_debug("refill thread received suspend ind (%s) pid %d", + qdf_get_current_comm(), + qdf_get_current_pid()); + qdf_event_set(&rx_thread->suspend_event); + dp_debug("refill thread waiting for resume (%s) pid %d", + qdf_get_current_comm(), + qdf_get_current_pid()); + qdf_wait_single_event(&rx_thread->resume_event, 0); + } + break; + } + return 0; +} + +static int dp_rx_refill_thread_loop(void *arg) +{ + struct dp_rx_refill_thread *rx_thread = arg; + bool shutdown = false; + int status; + QDF_STATUS status_intr; + + if (!arg) { + dp_err("bad Args passed"); + return 0; + } + + qdf_set_user_nice(qdf_get_current_task(), -1); + qdf_set_wake_up_idle(true); + + qdf_event_set(&rx_thread->start_event); + dp_info("starting rx_refill_thread (%s) pid %d", qdf_get_current_comm(), + qdf_get_current_pid()); + while (!shutdown) { + /* This implements the execution model algorithm */ + status = + qdf_wait_queue_interruptible + (rx_thread->wait_q, + qdf_atomic_test_bit(RX_REFILL_POST_EVENT, + &rx_thread->event_flag) || + qdf_atomic_test_bit(RX_REFILL_SUSPEND_EVENT, + &rx_thread->event_flag)); + + status_intr = qdf_status_from_os_return(status); + if (status_intr == QDF_STATUS_E_RESTART) { + QDF_DEBUG_PANIC("wait_event_interruptible returned -ERESTARTSYS"); + break; + } + qdf_atomic_clear_bit(RX_REFILL_POST_EVENT, + &rx_thread->event_flag); + dp_rx_refill_thread_sub_loop(rx_thread, &shutdown); + } + + /* If we get here the scheduler thread must exit */ + dp_info("exiting (%s) pid %d", qdf_get_current_comm(), + qdf_get_current_pid()); + qdf_event_set(&rx_thread->shutdown_event); + + return 0; +} + +/** + * dp_rx_tm_thread_napi_poll() - dummy napi poll for rx_thread NAPI + * @napi: pointer to DP rx_thread NAPI + * @budget: NAPI BUDGET + * + * Return: 0 as it is not supposed to be polled at all as it is not scheduled. + */ +static int dp_rx_tm_thread_napi_poll(qdf_napi_struct *napi, int budget) +{ + QDF_DEBUG_PANIC("this napi_poll should not be polled as we don't schedule it"); + + return 0; +} + +/** + * dp_rx_tm_thread_napi_init() - Initialize dummy rx_thread NAPI + * @rx_thread: dp_rx_thread structure containing dummy napi and netdev + * + * Return: None + */ +static void dp_rx_tm_thread_napi_init(struct dp_rx_thread *rx_thread) +{ + /* Todo - optimize to use only one dummy netdev for all thread napis */ + qdf_net_if_create_dummy_if((struct qdf_net_if *)&rx_thread->netdev); + qdf_netif_napi_add(&rx_thread->netdev, &rx_thread->napi, + dp_rx_tm_thread_napi_poll, 64); + qdf_napi_enable(&rx_thread->napi); +} + +/** + * dp_rx_tm_thread_napi_deinit() - De-initialize dummy rx_thread NAPI + * @rx_thread: dp_rx_thread handle containing dummy napi and netdev + * + * Return: None + */ +static void dp_rx_tm_thread_napi_deinit(struct dp_rx_thread *rx_thread) +{ + qdf_netif_napi_del(&rx_thread->napi); +} + +/* + * dp_rx_tm_thread_init() - Initialize dp_rx_thread structure and thread + * + * @rx_thread: dp_rx_thread structure to be initialized + * @id: id of the thread to be initialized + * + * Return: QDF_STATUS on success, QDF error code on failure + */ +static QDF_STATUS dp_rx_tm_thread_init(struct dp_rx_thread *rx_thread, + uint8_t id) +{ + char thread_name[15]; + QDF_STATUS qdf_status; + + qdf_mem_zero(thread_name, sizeof(thread_name)); + + if (!rx_thread) { + dp_err("rx_thread is null!"); + return QDF_STATUS_E_FAULT; + } + rx_thread->id = id; + rx_thread->event_flag = 0; + qdf_nbuf_queue_head_init(&rx_thread->nbuf_queue); + qdf_event_create(&rx_thread->start_event); + qdf_event_create(&rx_thread->suspend_event); + qdf_event_create(&rx_thread->resume_event); + qdf_event_create(&rx_thread->shutdown_event); + qdf_event_create(&rx_thread->vdev_del_event); + qdf_atomic_init(&rx_thread->gro_flush_ind); + qdf_init_waitqueue_head(&rx_thread->wait_q); + qdf_scnprintf(thread_name, sizeof(thread_name), "dp_rx_thread_%u", id); + dp_info("%s %u", thread_name, id); + + if (cdp_cfg_get(dp_rx_tm_get_soc_handle(rx_thread->rtm_handle_cmn), + cfg_dp_gro_enable)) + dp_rx_tm_thread_napi_init(rx_thread); + + rx_thread->task = qdf_create_thread(dp_rx_thread_loop, + rx_thread, thread_name); + if (!rx_thread->task) { + dp_err("could not create dp_rx_thread %d", id); + return QDF_STATUS_E_FAILURE; + } + + qdf_wake_up_process(rx_thread->task); + qdf_status = qdf_wait_single_event(&rx_thread->start_event, 0); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + dp_err("failed waiting for thread creation id %d", id); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/* + * dp_rx_tm_thread_deinit() - De-Initialize dp_rx_thread structure and thread + * @rx_thread: dp_rx_thread structure to be de-initialized + * @id: id of the thread to be initialized + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS dp_rx_tm_thread_deinit(struct dp_rx_thread *rx_thread) +{ + qdf_event_destroy(&rx_thread->start_event); + qdf_event_destroy(&rx_thread->suspend_event); + qdf_event_destroy(&rx_thread->resume_event); + qdf_event_destroy(&rx_thread->shutdown_event); + qdf_event_destroy(&rx_thread->vdev_del_event); + + if (cdp_cfg_get(dp_rx_tm_get_soc_handle(rx_thread->rtm_handle_cmn), + cfg_dp_gro_enable)) + dp_rx_tm_thread_napi_deinit(rx_thread); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_rx_refill_thread_init(struct dp_rx_refill_thread *refill_thread) +{ + char refill_thread_name[20] = {0}; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + qdf_scnprintf(refill_thread_name, sizeof(refill_thread_name), + "dp_refill_thread"); + dp_info("Initializing %s", refill_thread_name); + + refill_thread->state = DP_RX_REFILL_THREAD_INVALID; + refill_thread->event_flag = 0; + qdf_event_create(&refill_thread->start_event); + qdf_event_create(&refill_thread->suspend_event); + qdf_event_create(&refill_thread->resume_event); + qdf_event_create(&refill_thread->shutdown_event); + qdf_init_waitqueue_head(&refill_thread->wait_q); + refill_thread->task = qdf_create_thread(dp_rx_refill_thread_loop, + refill_thread, + refill_thread_name); + if (!refill_thread->task) { + dp_err("could not create dp_rx_refill_thread"); + return QDF_STATUS_E_FAILURE; + } + qdf_wake_up_process(refill_thread->task); + qdf_status = qdf_wait_single_event(&refill_thread->start_event, + 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + dp_err("failed waiting for refill thread creation status: %d", + qdf_status); + return QDF_STATUS_E_FAILURE; + } + + dp_rx_refill_thread_set_affinity(refill_thread); + + refill_thread->state = DP_RX_REFILL_THREAD_RUNNING; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_rx_refill_thread_deinit(struct dp_rx_refill_thread *refill_thread) +{ + qdf_set_bit(RX_REFILL_SHUTDOWN_EVENT, + &refill_thread->event_flag); + qdf_set_bit(RX_REFILL_POST_EVENT, + &refill_thread->event_flag); + qdf_wake_up_interruptible(&refill_thread->wait_q); + qdf_wait_single_event(&refill_thread->shutdown_event, 0); + + qdf_event_destroy(&refill_thread->start_event); + qdf_event_destroy(&refill_thread->suspend_event); + qdf_event_destroy(&refill_thread->resume_event); + qdf_event_destroy(&refill_thread->shutdown_event); + + refill_thread->state = DP_RX_REFILL_THREAD_INVALID; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_rx_tm_init(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t num_dp_rx_threads) +{ + int i; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (num_dp_rx_threads > DP_MAX_RX_THREADS) { + dp_err("unable to initialize %u number of threads. MAX %u", + num_dp_rx_threads, DP_MAX_RX_THREADS); + return QDF_STATUS_E_INVAL; + } + + rx_tm_hdl->num_dp_rx_threads = num_dp_rx_threads; + rx_tm_hdl->state = DP_RX_THREADS_INVALID; + + dp_info("initializing %u threads", num_dp_rx_threads); + + /* allocate an array to contain the DP RX thread pointers */ + rx_tm_hdl->rx_thread = qdf_mem_malloc(num_dp_rx_threads * + sizeof(struct dp_rx_thread *)); + + if (qdf_unlikely(!rx_tm_hdl->rx_thread)) { + qdf_status = QDF_STATUS_E_NOMEM; + goto ret; + } + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + rx_tm_hdl->rx_thread[i] = + (struct dp_rx_thread *) + qdf_mem_malloc(sizeof(struct dp_rx_thread)); + if (qdf_unlikely(!rx_tm_hdl->rx_thread[i])) { + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_NOMEM; + goto ret; + } + rx_tm_hdl->rx_thread[i]->rtm_handle_cmn = + (struct dp_rx_tm_handle_cmn *)rx_tm_hdl; + qdf_status = + dp_rx_tm_thread_init(rx_tm_hdl->rx_thread[i], i); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + break; + } +ret: + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + dp_rx_tm_deinit(rx_tm_hdl); + else + rx_tm_hdl->state = DP_RX_THREADS_RUNNING; + + return qdf_status; +} + +/** + * dp_rx_tm_suspend() - suspend DP RX threads + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * + * Return: Success/Failure + */ +QDF_STATUS dp_rx_tm_suspend(struct dp_rx_tm_handle *rx_tm_hdl) +{ + int i; + QDF_STATUS qdf_status; + struct dp_rx_thread *rx_thread; + + if (rx_tm_hdl->state == DP_RX_THREADS_SUSPENDED) { + dp_info("already in suspend state! Ignoring."); + return QDF_STATUS_E_INVAL; + } + + rx_tm_hdl->state = DP_RX_THREADS_SUSPENDING; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i]) + continue; + qdf_event_reset(&rx_tm_hdl->rx_thread[i]->resume_event); + qdf_event_reset(&rx_tm_hdl->rx_thread[i]->suspend_event); + qdf_set_bit(RX_SUSPEND_EVENT, + &rx_tm_hdl->rx_thread[i]->event_flag); + qdf_wake_up_interruptible(&rx_tm_hdl->rx_thread[i]->wait_q); + } + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + rx_thread = rx_tm_hdl->rx_thread[i]; + if (!rx_thread) + continue; + dp_debug("thread %d", i); + qdf_status = qdf_wait_single_event(&rx_thread->suspend_event, + DP_RX_THREAD_WAIT_TIMEOUT); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + dp_debug("thread:%d suspended", rx_thread->id); + else + goto suspend_fail; + } + rx_tm_hdl->state = DP_RX_THREADS_SUSPENDED; + + return QDF_STATUS_SUCCESS; + +suspend_fail: + dp_err("thread:%d %s(%d) while waiting for suspend", + rx_thread->id, + qdf_status == QDF_STATUS_E_TIMEOUT ? "timeout out" : "failed", + qdf_status); + + dp_rx_tm_resume(rx_tm_hdl); + + return qdf_status; +} + +/** + * dp_rx_refill_thread_suspend() - Suspend DP RX refill threads + * @refill_thread: containing the overall refill thread infrastructure + * + * Return: Success/Failure + */ +QDF_STATUS +dp_rx_refill_thread_suspend(struct dp_rx_refill_thread *refill_thread) +{ + QDF_STATUS qdf_status; + + if (refill_thread->state == DP_RX_REFILL_THREAD_SUSPENDED) { + dp_info("already in suspend state! Ignoring."); + return QDF_STATUS_E_INVAL; + } + + refill_thread->state = DP_RX_REFILL_THREAD_SUSPENDING; + + qdf_event_reset(&refill_thread->resume_event); + qdf_event_reset(&refill_thread->suspend_event); + qdf_set_bit(RX_REFILL_SUSPEND_EVENT, + &refill_thread->event_flag); + qdf_wake_up_interruptible(&refill_thread->wait_q); + + qdf_status = qdf_wait_single_event(&refill_thread->suspend_event, + DP_RX_THREAD_WAIT_TIMEOUT); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + dp_debug("Refill thread suspended"); + else + goto suspend_fail; + + refill_thread->state = DP_RX_REFILL_THREAD_SUSPENDED; + return QDF_STATUS_SUCCESS; + +suspend_fail: + dp_err("Refill thread %s(%d) while waiting for suspend", + qdf_status == QDF_STATUS_E_TIMEOUT ? "timeout out" : "failed", + qdf_status); + + dp_rx_refill_thread_resume(refill_thread); + + return qdf_status; +} + +/* + * dp_rx_tm_flush_nbuf_list() - Flush rx thread nbuf list + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * @vdev_id: vdev id for which packets are to be flushed + * + * Return: None + */ +static inline void +dp_rx_tm_flush_nbuf_list(struct dp_rx_tm_handle *rx_tm_hdl, uint8_t vdev_id) +{ + qdf_nbuf_t nbuf_list, tmp_nbuf_list; + uint32_t num_list_elements = 0; + uint64_t lock_time, unlock_time, flush_time; + qdf_nbuf_t nbuf_list_head = NULL, nbuf_list_next; + struct dp_rx_thread *rx_thread; + int i; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + rx_thread = rx_tm_hdl->rx_thread[i]; + if (!rx_thread) + continue; + + qdf_nbuf_queue_head_lock(&rx_thread->nbuf_queue); + lock_time = qdf_get_log_timestamp(); + QDF_NBUF_QUEUE_WALK_SAFE(&rx_thread->nbuf_queue, nbuf_list, + tmp_nbuf_list) { + if (QDF_NBUF_CB_RX_VDEV_ID(nbuf_list) == vdev_id) { + qdf_nbuf_unlink_no_lock(nbuf_list, + &rx_thread->nbuf_queue); + DP_RX_HEAD_APPEND(nbuf_list_head, nbuf_list); + } + } + qdf_nbuf_queue_head_unlock(&rx_thread->nbuf_queue); + unlock_time = qdf_get_log_timestamp(); + + while (nbuf_list_head) { + nbuf_list_next = qdf_nbuf_queue_next(nbuf_list_head); + qdf_nbuf_set_next(nbuf_list_head, NULL); + dp_rx_thread_adjust_nbuf_list(nbuf_list_head); + num_list_elements = + QDF_NBUF_CB_RX_NUM_ELEMENTS_IN_LIST(nbuf_list_head); + rx_thread->stats.rx_flushed += num_list_elements; + qdf_nbuf_list_free(nbuf_list_head); + nbuf_list_head = nbuf_list_next; + } + + flush_time = qdf_get_log_timestamp(); + dp_info("Thread: %u lock held time: %llu us flush time: %llu us", + rx_thread->id, + qdf_log_timestamp_to_usecs(unlock_time - lock_time), + qdf_log_timestamp_to_usecs(flush_time - unlock_time)); + + qdf_event_reset(&rx_thread->vdev_del_event); + qdf_set_bit(RX_VDEV_DEL_EVENT, &rx_thread->event_flag); + qdf_wake_up_interruptible(&rx_thread->wait_q); + } +} + +/** + * dp_rx_tm_wait_vdev_del_event() - wait on rx thread vdev delete event + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * + * Return: None + */ +static inline void +dp_rx_tm_wait_vdev_del_event(struct dp_rx_tm_handle *rx_tm_hdl) +{ + QDF_STATUS qdf_status; + int i; + struct dp_rx_thread *rx_thread; + int wait_timeout = DP_RX_THREAD_FLUSH_TIMEOUT; + uint64_t entry_time, exit_time, wait_time; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + rx_thread = rx_tm_hdl->rx_thread[i]; + if (!rx_thread) + continue; + + entry_time = qdf_get_log_timestamp(); + qdf_status = + qdf_wait_single_event(&rx_thread->vdev_del_event, + wait_timeout); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + dp_debug("thread:%d napi gro flush successfully", + rx_thread->id); + else if (qdf_status == QDF_STATUS_E_TIMEOUT) { + dp_err("thread:%d timed out waiting for napi gro flush", + rx_thread->id); + /* + * If timeout, then force flush in case any rx packets + * belong to this vdev is still pending on stack queue, + * while net_vdev will be freed soon. + */ + dp_rx_thread_gro_flush(rx_thread, + DP_RX_GRO_NORMAL_FLUSH); + } else { + dp_err("thread:%d event wait failed with status: %d", + rx_thread->id, qdf_status); + } + + exit_time = qdf_get_log_timestamp(); + wait_time = qdf_do_div(qdf_log_timestamp_to_usecs(exit_time - + entry_time), + QDF_USEC_PER_MSEC); + /** + * + * Maximum wait timeout to flush all thread is + * DP_RX_THREAD_MIN_FLUSH_TIMEOUT, This logic + * limit maximum wait time of all the thread to + * DP_RX_THREAD_FLUSH_TIMEOUT. In case if + * DP_RX_THREAD_FLUSH_TIMEOUT is exhausted + * give remaining thread DP_RX_THREAD_MIN_FLUSH_TIMEOUT. + * + * Since all the threads are already woken before calling + * wait API. So each thread will get + * DP_RX_THREAD_FLUSH_TIMEOUT to set the event. + */ + if (wait_timeout > DP_RX_THREAD_MIN_FLUSH_TIMEOUT) + wait_timeout = (wait_timeout > wait_time) ? + (wait_timeout - wait_time) : + DP_RX_THREAD_MIN_FLUSH_TIMEOUT; + } +} + +/** + * dp_rx_tm_flush_by_vdev_id() - flush rx packets by vdev_id in all + * rx thread queues + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * @vdev_id: vdev id for which packets are to be flushed + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS dp_rx_tm_flush_by_vdev_id(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t vdev_id) +{ + uint64_t entry_time, exit_time; + + entry_time = qdf_get_log_timestamp(); + dp_rx_tm_flush_nbuf_list(rx_tm_hdl, vdev_id); + dp_rx_tm_wait_vdev_del_event(rx_tm_hdl); + exit_time = qdf_get_log_timestamp(); + dp_info("Vdev: %u total flush time: %llu us", + vdev_id, + qdf_log_timestamp_to_usecs(exit_time - entry_time)); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_tm_resume() - resume DP RX threads + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * + * Return: QDF_STATUS_SUCCESS on resume success. QDF error otherwise. + */ +QDF_STATUS dp_rx_tm_resume(struct dp_rx_tm_handle *rx_tm_hdl) +{ + int i; + + if (rx_tm_hdl->state != DP_RX_THREADS_SUSPENDED && + rx_tm_hdl->state != DP_RX_THREADS_SUSPENDING) { + dp_info("resume callback received w/o suspend! Ignoring."); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i]) + continue; + dp_debug("calling thread %d to resume", i); + + /* postively reset event_flag for DP_RX_THREADS_SUSPENDING + * state + */ + qdf_clear_bit(RX_SUSPEND_EVENT, + &rx_tm_hdl->rx_thread[i]->event_flag); + qdf_event_set(&rx_tm_hdl->rx_thread[i]->resume_event); + } + + rx_tm_hdl->state = DP_RX_THREADS_RUNNING; + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_refill_thread_resume() - Resume DP RX refill threads + * @refill_thread: refill_thread containing the overall thread infrastructure + * + * Return: QDF_STATUS_SUCCESS on resume success. QDF error otherwise. + */ +QDF_STATUS dp_rx_refill_thread_resume(struct dp_rx_refill_thread *refill_thread) +{ + dp_debug("calling refill thread to resume"); + + if (refill_thread->state != DP_RX_REFILL_THREAD_SUSPENDED && + refill_thread->state != DP_RX_REFILL_THREAD_SUSPENDING) { + dp_info("resume callback received in %d state ! Ignoring.", + refill_thread->state); + return QDF_STATUS_E_INVAL; + } + + /* postively reset event_flag for DP_RX_REFILL_THREAD_SUSPENDING + * state + */ + qdf_clear_bit(RX_REFILL_SUSPEND_EVENT, + &refill_thread->event_flag); + qdf_event_set(&refill_thread->resume_event); + + refill_thread->state = DP_RX_REFILL_THREAD_RUNNING; + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_tm_shutdown() - shutdown all DP RX threads + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread infrastructure + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS dp_rx_tm_shutdown(struct dp_rx_tm_handle *rx_tm_hdl) +{ + int i; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i] || + rx_tm_hdl->state == DP_RX_THREADS_INVALID) + continue; + qdf_set_bit(RX_SHUTDOWN_EVENT, + &rx_tm_hdl->rx_thread[i]->event_flag); + qdf_set_bit(RX_POST_EVENT, + &rx_tm_hdl->rx_thread[i]->event_flag); + qdf_wake_up_interruptible(&rx_tm_hdl->rx_thread[i]->wait_q); + } + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i] || + rx_tm_hdl->state == DP_RX_THREADS_INVALID) + continue; + dp_debug("waiting for shutdown of thread %d", i); + qdf_wait_single_event(&rx_tm_hdl->rx_thread[i]->shutdown_event, + 0); + } + rx_tm_hdl->state = DP_RX_THREADS_INVALID; + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_tm_deinit() - de-initialize RX thread infrastructure + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS dp_rx_tm_deinit(struct dp_rx_tm_handle *rx_tm_hdl) +{ + int i = 0; + + if (!rx_tm_hdl->rx_thread) { + dp_err("rx_tm_hdl->rx_thread not initialized!"); + return QDF_STATUS_SUCCESS; + } + + dp_rx_tm_shutdown(rx_tm_hdl); + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i]) + continue; + dp_rx_tm_thread_deinit(rx_tm_hdl->rx_thread[i]); + qdf_mem_free(rx_tm_hdl->rx_thread[i]); + } + + /* free the array of RX thread pointers*/ + qdf_mem_free(rx_tm_hdl->rx_thread); + rx_tm_hdl->rx_thread = NULL; + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_tm_select_thread() - select a DP RX thread for a nbuf + * @rx_tm_hdl: dp_rx_tm_handle containing the overall thread + * infrastructure + * @reo_ring_num: REO ring number corresponding to the thread + * + * The function relies on the presence of QDF_NBUF_CB_RX_CTX_ID passed to it + * from the nbuf list. Depending on the RX_CTX (copy engine or reo + * ring) on which the packet was received, the function selects + * a corresponding rx_thread. + * + * Return: rx thread ID selected for the nbuf + */ +static uint8_t dp_rx_tm_select_thread(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t reo_ring_num) +{ + uint8_t selected_rx_thread; + + selected_rx_thread = reo_ring_num % rx_tm_hdl->num_dp_rx_threads; + dp_debug("ring_num %d, selected thread %u", reo_ring_num, + selected_rx_thread); + + return selected_rx_thread; +} + +QDF_STATUS dp_rx_tm_enqueue_pkt(struct dp_rx_tm_handle *rx_tm_hdl, + qdf_nbuf_t nbuf_list) +{ + uint8_t selected_thread_id; + + selected_thread_id = + dp_rx_tm_select_thread(rx_tm_hdl, + QDF_NBUF_CB_RX_CTX_ID(nbuf_list)); + dp_rx_tm_thread_enqueue(rx_tm_hdl->rx_thread[selected_thread_id], + nbuf_list); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +dp_rx_tm_gro_flush_ind(struct dp_rx_tm_handle *rx_tm_hdl, int rx_ctx_id, + enum dp_rx_gro_flush_code flush_code) +{ + uint8_t selected_thread_id; + + selected_thread_id = dp_rx_tm_select_thread(rx_tm_hdl, rx_ctx_id); + dp_rx_tm_thread_gro_flush_ind(rx_tm_hdl->rx_thread[selected_thread_id], + flush_code); + + return QDF_STATUS_SUCCESS; +} + +qdf_napi_struct *dp_rx_tm_get_napi_context(struct dp_rx_tm_handle *rx_tm_hdl, + uint8_t rx_ctx_id) +{ + uint8_t selected_thread_id; + + selected_thread_id = dp_rx_tm_select_thread(rx_tm_hdl, rx_ctx_id); + + return &rx_tm_hdl->rx_thread[selected_thread_id]->napi; +} + +QDF_STATUS dp_rx_tm_set_cpu_mask(struct dp_rx_tm_handle *rx_tm_hdl, + qdf_cpu_mask *new_mask) +{ + int i = 0; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + if (!rx_tm_hdl->rx_thread[i]) + continue; + qdf_thread_set_cpus_allowed_mask(rx_tm_hdl->rx_thread[i]->task, + new_mask); + } + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_refill_thread_schedule() - Schedule rx refill thread + * @soc: ol_txrx_soc_handle object + * + */ +#ifdef WLAN_FEATURE_RX_PREALLOC_BUFFER_POOL +static void dp_rx_refill_thread_schedule(ol_txrx_soc_handle soc) +{ + struct dp_rx_refill_thread *rx_thread; + struct dp_txrx_handle *dp_ext_hdl; + + if (!soc) + return; + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) + return; + + rx_thread = &dp_ext_hdl->refill_thread; + qdf_set_bit(RX_REFILL_POST_EVENT, &rx_thread->event_flag); + qdf_wake_up_interruptible(&rx_thread->wait_q); +} +#else +static void dp_rx_refill_thread_schedule(ol_txrx_soc_handle soc) +{ +} +#endif + +/** + * dp_get_rx_threads_num() - Get number of threads in use + * @soc: ol_txrx_soc_handle object + * + * Return: number of threads + */ +static uint8_t dp_get_rx_threads_num(ol_txrx_soc_handle soc) +{ + return cdp_get_num_rx_contexts(soc); +} + +QDF_STATUS dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id, + struct dp_txrx_config *config) +{ + struct dp_txrx_handle *dp_ext_hdl; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + uint8_t num_dp_rx_threads; + struct dp_pdev *pdev; + struct dp_soc *dp_soc; + + if (qdf_unlikely(!soc)) { + dp_err("soc is NULL"); + return 0; + } + + pdev = dp_get_pdev_from_soc_pdev_id_wifi3(cdp_soc_t_to_dp_soc(soc), + pdev_id); + if (!pdev) { + dp_err("pdev is NULL"); + return 0; + } + + dp_ext_hdl = qdf_mem_malloc(sizeof(*dp_ext_hdl)); + if (!dp_ext_hdl) { + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + + dp_info("dp_txrx_handle allocated"); + dp_ext_hdl->soc = soc; + dp_ext_hdl->pdev = dp_pdev_to_cdp_pdev(pdev); + cdp_soc_set_dp_txrx_handle(soc, dp_ext_hdl); + qdf_mem_copy(&dp_ext_hdl->config, config, sizeof(*config)); + dp_ext_hdl->rx_tm_hdl.txrx_handle_cmn = + dp_txrx_get_cmn_hdl_frm_ext_hdl(dp_ext_hdl); + + dp_soc = cdp_soc_t_to_dp_soc(soc); + if (wlan_cfg_is_rx_refill_buffer_pool_enabled(dp_soc->wlan_cfg_ctx)) { + dp_ext_hdl->refill_thread.soc = soc; + dp_ext_hdl->refill_thread.enabled = true; + qdf_status = + dp_rx_refill_thread_init(&dp_ext_hdl->refill_thread); + if (qdf_status != QDF_STATUS_SUCCESS) { + dp_err("Failed to initialize RX refill thread status:%d", + qdf_status); + qdf_mem_free(dp_ext_hdl); + return qdf_status; + } + cdp_register_rx_refill_thread_sched_handler(soc, + dp_rx_refill_thread_schedule); + } + + num_dp_rx_threads = dp_get_rx_threads_num(soc); + dp_info("%d RX threads in use", num_dp_rx_threads); + + if (dp_ext_hdl->config.enable_rx_threads) { + qdf_status = dp_rx_tm_init(&dp_ext_hdl->rx_tm_hdl, + num_dp_rx_threads); + } + + if (QDF_IS_STATUS_ERROR(qdf_status)) + dp_txrx_deinit(soc); + + return qdf_status; +} + +QDF_STATUS dp_txrx_deinit(ol_txrx_soc_handle soc) +{ + struct dp_txrx_handle *dp_ext_hdl; + struct dp_soc *dp_soc; + + if (!soc) + return QDF_STATUS_E_INVAL; + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) + return QDF_STATUS_E_FAULT; + + dp_soc = cdp_soc_t_to_dp_soc(soc); + if (wlan_cfg_is_rx_refill_buffer_pool_enabled(dp_soc->wlan_cfg_ctx)) { + dp_rx_refill_thread_deinit(&dp_ext_hdl->refill_thread); + dp_ext_hdl->refill_thread.soc = NULL; + dp_ext_hdl->refill_thread.enabled = false; + } + + if (dp_ext_hdl->config.enable_rx_threads) + dp_rx_tm_deinit(&dp_ext_hdl->rx_tm_hdl); + + qdf_mem_free(dp_ext_hdl); + dp_info("dp_txrx_handle_t de-allocated"); + + cdp_soc_set_dp_txrx_handle(soc, NULL); + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_tm_get_pending() - get number of frame in thread + * nbuf queue pending + * @soc: ol_txrx_soc_handle object + * + * Return: number of frames + */ +#ifdef FEATURE_WLAN_DP_RX_THREADS +int dp_rx_tm_get_pending(ol_txrx_soc_handle soc) +{ + int i; + int num_pending = 0; + struct dp_rx_thread *rx_thread; + struct dp_txrx_handle *dp_ext_hdl; + struct dp_rx_tm_handle *rx_tm_hdl; + + if (!soc) + return 0; + + dp_ext_hdl = cdp_soc_get_dp_txrx_handle(soc); + if (!dp_ext_hdl) + return 0; + + rx_tm_hdl = &dp_ext_hdl->rx_tm_hdl; + + for (i = 0; i < rx_tm_hdl->num_dp_rx_threads; i++) { + rx_thread = rx_tm_hdl->rx_thread[i]; + if (!rx_thread) + continue; + num_pending += qdf_nbuf_queue_head_qlen(&rx_thread->nbuf_queue); + } + + if (num_pending) + dp_debug("pending frames in thread queue %d", num_pending); + + return num_pending; +} +#else +int dp_rx_tm_get_pending(ol_txrx_soc_handle soc) +{ + return 0; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_softap_txrx.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_softap_txrx.c new file mode 100644 index 0000000000..f7a14e95c8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_softap_txrx.c @@ -0,0 +1,938 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: wlan_dp_softap_txrx.c + * DP Soft AP TX/RX path implementation + * + * + */ + +#include +#include +#include +#include "wlan_dp_public_struct.h" +#include +#include +#include +#include +#include +#include "wlan_dp_rx_thread.h" +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ +#undef QCA_DP_SAP_DUMP_SK_BUFF + +/* Type declarations */ + +/* Function definitions and documentation */ +#ifdef QCA_DP_SAP_DUMP_SK_BUFF +/** + * dp_softap_dump_nbuf() - Dump an nbuf + * @nbuf: nbuf to dump + * + * Return: None + */ +static void dp_softap_dump_nbuf(qdf_nbuf_t nbuf) +{ + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: head = %pK ", __func__, nbuf->head); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, + "%s: tail = %pK ", __func__, nbuf->tail); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: end = %pK ", __func__, nbuf->end); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: len = %d ", __func__, nbuf->len); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: data_len = %d ", __func__, nbuf->data_len); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "%s: mac_len = %d", __func__, nbuf->mac_len); + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x ", nbuf->data[0], + nbuf->data[1], nbuf->data[2], nbuf->data[3], nbuf->data[4], + nbuf->data[5], nbuf->data[6], nbuf->data[7]); + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", nbuf->data[8], + nbuf->data[9], nbuf->data[10], nbuf->data[11], nbuf->data[12], + nbuf->data[13], nbuf->data[14], nbuf->data[15]); +} +#else +static inline void dp_softap_dump_nbuf(qdf_nbuf_t nbuf) +{ +} +#endif + +#define IEEE8021X_AUTH_TYPE_EAP 0 +#define EAP_CODE_OFFSET 18 +#define EAP_CODE_FAILURE 4 + +/* Wait EAP Failure frame timeout in (MS) */ +#define EAP_FRM_TIME_OUT 80 + +/** + * dp_softap_inspect_tx_eap_pkt() - Inspect eap pkt tx/tx-completion + * @dp_intf: pointer to DP interface + * @nbuf: pointer to n/w buffer + * @tx_comp: tx sending or tx completion + * + * Inspect the EAP-Failure pkt tx sending and tx completion. + * + * Return: void + */ +static void dp_softap_inspect_tx_eap_pkt(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf, + bool tx_comp) +{ + struct qdf_mac_addr *mac_addr; + uint8_t *data; + uint8_t auth_type, eap_code; + struct wlan_objmgr_peer *peer; + struct wlan_dp_sta_info *sta_info; + + if (qdf_likely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) != + QDF_NBUF_CB_PACKET_TYPE_EAPOL) || + qdf_nbuf_len(nbuf) < (EAP_CODE_OFFSET + 1)) + return; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() || + cds_is_load_or_unload_in_progress()) { + dp_debug("Recovery/(Un)load in Progress. Ignore!!!"); + return; + } + + if (dp_intf->device_mode != QDF_P2P_GO_MODE) + return; + + if (dp_intf->bss_state != BSS_INTF_START) { + dp_debug("BSS intf state is not START"); + return; + } + data = qdf_nbuf_data(nbuf); + auth_type = *(uint8_t *)(data + EAPOL_PACKET_TYPE_OFFSET); + if (auth_type != IEEE8021X_AUTH_TYPE_EAP) + return; + eap_code = *(uint8_t *)(data + EAP_CODE_OFFSET); + if (eap_code != EAP_CODE_FAILURE) + return; + mac_addr = (struct qdf_mac_addr *)qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET; + + peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc, + mac_addr->bytes, + WLAN_DP_ID); + if (!peer) { + dp_err("Peer object not found"); + return; + } + sta_info = dp_get_peer_priv_obj(peer); + if (!sta_info) { + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + return; + } + + if (tx_comp) { + dp_info("eap_failure frm tx done" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + qdf_atomic_clear_bit(DP_PENDING_TYPE_EAP_FAILURE, + &sta_info->pending_eap_frm_type); + qdf_event_set(&dp_intf->qdf_sta_eap_frm_done_event); + } else { + dp_info("eap_failure frm tx pending" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + qdf_event_reset(&dp_intf->qdf_sta_eap_frm_done_event); + qdf_atomic_set_bit(DP_PENDING_TYPE_EAP_FAILURE, + &sta_info->pending_eap_frm_type); + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1; + } + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); +} + +void dp_softap_check_wait_for_tx_eap_pkt(struct wlan_dp_intf *dp_intf, + struct qdf_mac_addr *mac_addr) +{ + struct wlan_objmgr_peer *peer; + struct wlan_dp_sta_info *sta_info; + QDF_STATUS qdf_status; + + if (dp_intf->device_mode != QDF_P2P_GO_MODE) + return; + + peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc, + mac_addr->bytes, + WLAN_DP_ID); + if (!peer) { + dp_err("Peer object not found"); + return; + } + + sta_info = dp_get_peer_priv_obj(peer); + if (qdf_atomic_test_bit(DP_PENDING_TYPE_EAP_FAILURE, + &sta_info->pending_eap_frm_type)) { + dp_info("eap_failure frm pending" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + qdf_status = qdf_wait_for_event_completion( + &dp_intf->qdf_sta_eap_frm_done_event, + EAP_FRM_TIME_OUT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + dp_debug("eap_failure tx timeout"); + } + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); +} + +#ifdef SAP_DHCP_FW_IND +/** + * dp_post_dhcp_ind() - Send DHCP START/STOP indication to FW + * @dp_link: DP link handle + * @mac_addr: mac address + * @dhcp_start: dhcp start + * + * Return: error number + */ +int dp_post_dhcp_ind(struct wlan_dp_link *dp_link, uint8_t *mac_addr, + bool dhcp_start) +{ + struct wlan_dp_intf *dp_intf; + struct dp_dhcp_ind msg; + struct wlan_dp_psoc_sb_ops *sb_ops; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + dp_info("Post DHCP indication,sta_mac=" QDF_MAC_ADDR_FMT + " , start=%u", QDF_MAC_ADDR_REF(mac_addr), dhcp_start); + + if (!is_dp_link_valid(dp_link)) { + dp_err("NULL DP link"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + /* + * If DP RX thread is enabled, RX DHCP packets are enqueue into + * DP RX thread queue, defer DHCP inspection until host has + * resumed entirely, no issue to send DHCP indication MSG. + * If DP RX thread is disabled, DHCP inspection happens earlier, + * skip sending DHCP indication MSG if host has not resumed. + */ + if (qdf_unlikely(!dp_intf->dp_ctx->enable_dp_rx_threads && + dp_intf->dp_ctx->is_suspend)) { + dp_err_rl("Device is system suspended, skip DHCP Ind"); + return QDF_STATUS_E_INVAL; + } + + sb_ops = &dp_intf->dp_ctx->sb_ops; + msg.dhcp_start = dhcp_start; + msg.device_mode = dp_intf->device_mode; + qdf_mem_copy(msg.intf_mac_addr.bytes, + dp_intf->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(msg.peer_mac_addr.bytes, + mac_addr, + QDF_MAC_ADDR_SIZE); + + status = sb_ops->dp_send_dhcp_ind(dp_link->link_id, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + dp_err("Post DHCP Ind MSG fail"); + return QDF_STATUS_E_FAULT; + } + + return 0; +} + +#define DHCP_CLIENT_MAC_ADDR_OFFSET 0x46 + +/** + * dp_softap_notify_dhcp_ind() - Notify SAP for DHCP indication for tx desc + * @link_context: DP link context + * @nbuf: pointer to OS packet (sk_buff) + * + * Return: None + */ +static void dp_softap_notify_dhcp_ind(void *link_context, qdf_nbuf_t nbuf) +{ + uint8_t *dest_mac_addr; + struct wlan_dp_link *dp_link = link_context; + + if (!is_dp_link_valid(dp_link)) + return; + + dest_mac_addr = qdf_nbuf_data(nbuf) + DHCP_CLIENT_MAC_ADDR_OFFSET; + + /*stop dhcp indication*/ + dp_post_dhcp_ind(dp_link, dest_mac_addr, false); +} + +int dp_softap_inspect_dhcp_packet(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf, + enum qdf_proto_dir dir) +{ + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + struct wlan_objmgr_peer *peer; + struct wlan_dp_sta_info *sta_info; + int errno = 0; + struct qdf_mac_addr *src_mac; + + if (((dp_intf->device_mode == QDF_SAP_MODE) || + (dp_intf->device_mode == QDF_P2P_GO_MODE)) && + ((dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) || + (dir == QDF_RX && qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) == true))) { + src_mac = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) + + DHCP_CLIENT_MAC_ADDR_OFFSET); + + subtype = qdf_nbuf_get_dhcp_subtype(nbuf); + + peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc, + src_mac->bytes, + WLAN_DP_ID); + if (!peer) { + dp_err("Peer object not found"); + return QDF_STATUS_E_INVAL; + } + + sta_info = dp_get_peer_priv_obj(peer); + if (!sta_info) { + dp_err("Station not found"); + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + return QDF_STATUS_E_INVAL; + } + + dp_info("ENTER: type=%d, phase=%d, nego_status=%d", + subtype, + sta_info->dhcp_phase, + sta_info->dhcp_nego_status); + + switch (subtype) { + case QDF_PROTO_DHCP_DISCOVER: + if (dir != QDF_RX) + break; + if (sta_info->dhcp_nego_status == DHCP_NEGO_STOP) + errno = dp_post_dhcp_ind( + dp_link, + sta_info->sta_mac.bytes, + true); + sta_info->dhcp_phase = DHCP_PHASE_DISCOVER; + if (QDF_IS_STATUS_SUCCESS(errno)) + sta_info->dhcp_nego_status = + DHCP_NEGO_IN_PROGRESS; + break; + case QDF_PROTO_DHCP_OFFER: + sta_info->dhcp_phase = DHCP_PHASE_OFFER; + break; + case QDF_PROTO_DHCP_REQUEST: + if (dir != QDF_RX) + break; + if (sta_info->dhcp_nego_status == DHCP_NEGO_STOP) + errno = dp_post_dhcp_ind( + dp_link, + sta_info->sta_mac.bytes, + true); + if (QDF_IS_STATUS_SUCCESS(errno)) + sta_info->dhcp_nego_status = + DHCP_NEGO_IN_PROGRESS; + fallthrough; + case QDF_PROTO_DHCP_DECLINE: + if (dir == QDF_RX) + sta_info->dhcp_phase = DHCP_PHASE_REQUEST; + break; + case QDF_PROTO_DHCP_ACK: + case QDF_PROTO_DHCP_NACK: + sta_info->dhcp_phase = DHCP_PHASE_ACK; + if (sta_info->dhcp_nego_status == + DHCP_NEGO_IN_PROGRESS) { + dp_debug("Setting NOTIFY_COMP Flag"); + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1; + } + sta_info->dhcp_nego_status = DHCP_NEGO_STOP; + break; + default: + break; + } + + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + dp_info("EXIT: phase=%d, nego_status=%d", + sta_info->dhcp_phase, + sta_info->dhcp_nego_status); + } + + return errno; +} +#else +static void dp_softap_notify_dhcp_ind(void *context, qdf_nbuf_t nbuf) +{ +} +#endif /* SAP_DHCP_FW_IND */ + +#if defined(IPA_OFFLOAD) +static +qdf_nbuf_t dp_sap_nbuf_orphan(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + if (!qdf_nbuf_ipa_owned_get(nbuf)) { + nbuf = dp_nbuf_orphan(dp_intf, nbuf); + } else { + /* + * Clear the IPA ownership after check it to avoid ipa_free_skb + * is called when Tx completed for intra-BSS Tx packets + */ + qdf_nbuf_ipa_owned_clear(nbuf); + } + return nbuf; +} +#else +static inline +qdf_nbuf_t dp_sap_nbuf_orphan(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + return dp_nbuf_orphan(dp_intf, nbuf); +} +#endif /* IPA_OFFLOAD */ + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +static +void dp_softap_get_tx_resource(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + + if (QDF_NBUF_CB_GET_IS_BCAST(nbuf) || QDF_NBUF_CB_GET_IS_MCAST(nbuf)) + dp_get_tx_resource(dp_link, &dp_intf->mac_addr); + else + dp_get_tx_resource(dp_link, + (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET)); +} +#else +#define dp_softap_get_tx_resource(dp_intf, nbuf) +#endif + +#ifdef FEATURE_WDS +static void +dp_wds_replace_peer_mac(void *soc, struct wlan_dp_link *dp_link, + uint8_t *mac_addr) +{ + struct cdp_ast_entry_info ast_entry_info = {0}; + cdp_config_param_type val; + QDF_STATUS status; + + if (!cdp_find_peer_exist(soc, OL_TXRX_PDEV_ID, mac_addr)) { + status = cdp_txrx_get_vdev_param(soc, dp_link->link_id, + CDP_ENABLE_WDS, &val); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + + if (!val.cdp_vdev_param_wds) + return; + + if (!cdp_peer_get_ast_info_by_soc(soc, mac_addr, + &ast_entry_info)) + return; + + qdf_mem_copy(mac_addr, ast_entry_info.peer_mac_addr, + QDF_MAC_ADDR_SIZE); + } +} +#else +static inline +void dp_wds_replace_peer_mac(void *soc, struct wlan_dp_link *dp_link, + uint8_t *mac_addr) +{ +} +#endif /* FEATURE_WDS*/ + +static QDF_STATUS dp_softap_validate_peer_state(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf) +{ + struct qdf_mac_addr *dest_mac_addr; + struct qdf_mac_addr mac_addr; + enum ol_txrx_peer_state peer_state; + void *soc; + + dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET); + + if (QDF_NBUF_CB_GET_IS_BCAST(nbuf) || QDF_NBUF_CB_GET_IS_MCAST(nbuf)) + return QDF_STATUS_SUCCESS; + + /* for a unicast frame */ + qdf_copy_macaddr(&mac_addr, dest_mac_addr); + soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_BUG(soc); + dp_wds_replace_peer_mac(soc, dp_link, mac_addr.bytes); + peer_state = cdp_peer_state_get(soc, dp_link->link_id, + mac_addr.bytes, false); + + if (peer_state == OL_TXRX_PEER_STATE_INVALID) { + dp_debug_rl("Failed to find right station"); + return QDF_STATUS_E_FAILURE; + } + + if (peer_state != OL_TXRX_PEER_STATE_CONN && + peer_state != OL_TXRX_PEER_STATE_AUTH) { + dp_debug_rl("Station not connected yet"); + return QDF_STATUS_E_FAILURE; + } + + if (peer_state == OL_TXRX_PEER_STATE_CONN) { + if (qdf_ntohs(qdf_nbuf_get_protocol(nbuf)) != ETHERTYPE_PAE && + qdf_ntohs(qdf_nbuf_get_protocol(nbuf)) != ETHERTYPE_WAI) { + dp_debug_rl("NON-EAPOL/WAPI pkt in non-Auth state"); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS dp_softap_validate_driver_state(struct wlan_dp_intf *dp_intf) +{ + if (qdf_unlikely(cds_is_driver_transitioning())) { + dp_err_rl("driver is transitioning, drop pkt"); + return QDF_STATUS_E_ABORTED; + } + + /* + * below unified mask will take care of SAP TX block + * WLAN suspend state check + * BSS start check and + * DP TX function register check + */ + if (qdf_unlikely(dp_intf->sap_tx_block_mask)) { + dp_err_rl("Softap TX blocked mask: %u", + dp_intf->sap_tx_block_mask); + return QDF_STATUS_E_ABORTED; + } + + return QDF_STATUS_SUCCESS; +} + +static void dp_softap_config_tx_pkt_tracing(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + if (dp_is_current_high_throughput(dp_intf->dp_ctx)) + return; + + QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_UPDATE_TX_PKT_COUNT(nbuf, QDF_NBUF_TX_PKT_DP); + qdf_dp_trace_set_track(nbuf, QDF_TX); + DPTRACE(qdf_dp_trace(nbuf, QDF_DP_TRACE_TX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(nbuf), + sizeof(qdf_nbuf_data(nbuf)), + QDF_TX)); +} + +#ifdef DP_TRAFFIC_END_INDICATION +/** + * wlan_dp_traffic_end_indication_update_dscp() - Compare dscp derived from + * provided tos value with + * stored value and update if + * it's equal to special dscp + * @dp_intf: pointer to DP interface + * @tos: pointer to tos + * + * Return: True if tos is updated else False + */ +static inline bool +wlan_dp_traffic_end_indication_update_dscp(struct wlan_dp_intf *dp_intf, + uint8_t *tos) +{ + bool update; + uint8_t dscp, ecn; + + ecn = (*tos & ~QDF_NBUF_PKT_IPV4_DSCP_MASK); + dscp = (*tos & QDF_NBUF_PKT_IPV4_DSCP_MASK) >> + QDF_NBUF_PKT_IPV4_DSCP_SHIFT; + update = (dp_intf->traffic_end_ind.spl_dscp == dscp); + if (update) + *tos = ((dp_intf->traffic_end_ind.def_dscp << + QDF_NBUF_PKT_IPV4_DSCP_SHIFT) | ecn); + return update; +} + +/** + * dp_softap_inspect_traffic_end_indication_pkt() - Restore tos field for last + * packet in data stream + * @dp_intf: pointer to DP interface + * @nbuf: pointer to OS packet + * + * Return: None + */ +static inline void +dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + uint8_t tos, tc; + bool ret; + + if (qdf_nbuf_data_is_ipv4_pkt(qdf_nbuf_data(nbuf))) { + tos = qdf_nbuf_data_get_ipv4_tos(qdf_nbuf_data(nbuf)); + ret = wlan_dp_traffic_end_indication_update_dscp(dp_intf, &tos); + if (ret) { + qdf_nbuf_data_set_ipv4_tos(qdf_nbuf_data(nbuf), tos); + if (qdf_nbuf_is_ipv4_last_fragment(nbuf)) + QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) = + QDF_NBUF_CB_PACKET_TYPE_END_INDICATION; + } + } else if (qdf_nbuf_is_ipv6_pkt(nbuf)) { + tc = qdf_nbuf_data_get_ipv6_tc(qdf_nbuf_data(nbuf)); + ret = wlan_dp_traffic_end_indication_update_dscp(dp_intf, &tc); + if (ret) { + qdf_nbuf_data_set_ipv6_tc(qdf_nbuf_data(nbuf), tc); + QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) = + QDF_NBUF_CB_PACKET_TYPE_END_INDICATION; + } + } +} + +/** + * dp_softap_traffic_end_indication_enabled() - Check if traffic end indication + * is enabled or not + * @dp_intf: pointer to DP interface + * + * Return: True or False + */ +static inline bool +dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf *dp_intf) +{ + return qdf_unlikely(dp_intf->traffic_end_ind.enabled); +} +#else +static inline bool +dp_softap_traffic_end_indication_enabled(struct wlan_dp_intf *dp_intf) +{ + return false; +} + +static inline void +dp_softap_inspect_traffic_end_indication_pkt(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{} +#endif + +/** + * dp_softap_start_xmit() - Transmit a frame + * @nbuf: pointer to Network buffer + * @dp_link: DP link handle + * + * Return: QDF_STATUS_SUCCESS on successful transmission + */ +QDF_STATUS dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_dp_link *dp_link) +{ + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct qdf_mac_addr *dest_mac_addr; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t num_seg; + struct dp_tx_rx_stats *stats = &dp_intf->dp_stats.tx_rx_stats; + int cpu = qdf_get_smp_processor_id(); + + dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET); + ++stats->per_cpu[cpu].tx_called; + stats->cont_txtimeout_cnt = 0; + + if (QDF_IS_STATUS_ERROR(dp_softap_validate_driver_state(dp_intf))) + goto drop_pkt; + + wlan_dp_pkt_add_timestamp(dp_intf, QDF_PKT_TX_DRIVER_ENTRY, nbuf); + + if (QDF_IS_STATUS_ERROR(dp_softap_validate_peer_state(dp_link, nbuf))) + goto drop_pkt; + + dp_softap_get_tx_resource(dp_link, nbuf); + + nbuf = dp_sap_nbuf_orphan(dp_intf, nbuf); + if (!nbuf) + goto drop_pkt_accounting; + + qdf_net_buf_debug_acquire_skb(nbuf, __FILE__, __LINE__); + + qdf_net_stats_add_tx_bytes(&dp_intf->stats, qdf_nbuf_len(nbuf)); + + if (qdf_nbuf_is_tso(nbuf)) { + num_seg = qdf_nbuf_get_tso_num_seg(nbuf); + qdf_net_stats_add_tx_pkts(&dp_intf->stats, num_seg); + } else { + qdf_net_stats_add_tx_pkts(&dp_intf->stats, 1); + dp_ctx->no_tx_offload_pkt_cnt++; + } + + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 0; + + if (qdf_unlikely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) == + QDF_NBUF_CB_PACKET_TYPE_DHCP)) + dp_softap_inspect_dhcp_packet(dp_link, nbuf, QDF_TX); + + if (qdf_unlikely(QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL)) { + dp_softap_inspect_tx_eap_pkt(dp_intf, nbuf, false); + dp_event_eapol_log(nbuf, QDF_TX); + } + + if (dp_softap_traffic_end_indication_enabled(dp_intf)) + dp_softap_inspect_traffic_end_indication_pkt(dp_intf, nbuf); + + dp_softap_config_tx_pkt_tracing(dp_intf, nbuf); + + /* check whether need to linearize skb, like non-linear udp data */ + if (dp_nbuf_nontso_linearize(nbuf) != QDF_STATUS_SUCCESS) { + dp_debug_rl("nbuf %pK linearize failed. drop the pkt", nbuf); + goto drop_pkt_and_release_skb; + } + + if (dp_intf->txrx_ops.tx.tx(soc, dp_link->link_id, nbuf)) { + dp_debug("Failed to send packet to txrx for sta: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dest_mac_addr->bytes)); + goto drop_pkt_and_release_skb; + } + + return QDF_STATUS_SUCCESS; + +drop_pkt_and_release_skb: + qdf_net_buf_debug_release_skb(nbuf); +drop_pkt: + qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_DROP_PACKET_RECORD, 0, + QDF_TX); + qdf_nbuf_kfree(nbuf); +drop_pkt_accounting: + qdf_net_stats_inc_tx_dropped(&dp_intf->stats); + + return QDF_STATUS_E_FAILURE; +} + +void dp_softap_tx_timeout(struct wlan_dp_intf *dp_intf) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); + + ++dp_intf->dp_stats.tx_rx_stats.tx_timeout_cnt; + ++dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt; + + if (dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt > + DP_TX_STALL_THRESHOLD) { + dp_err("Detected data stall due to continuous TX timeouts"); + dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + + if (dp_is_data_stall_event_enabled(DP_HOST_SAP_TX_TIMEOUT)) + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_HOST_SOFTAP_TX_TIMEOUT, + OL_TXRX_PDEV_ID, 0xFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } +} + +/** + * dp_softap_notify_tx_compl_cbk() - callback to notify tx completion + * @nbuf: pointer to n/w buffer + * @context: pointer to DP interface + * @flag: tx status flag + * + * Return: None + */ +void dp_softap_notify_tx_compl_cbk(qdf_nbuf_t nbuf, + void *context, uint16_t flag) +{ + struct wlan_dp_link *dp_link = context; + struct wlan_dp_intf *dp_intf; + + if (!is_dp_link_valid(dp_link)) + return; + + dp_intf = dp_link->dp_intf; + if (QDF_NBUF_CB_PACKET_TYPE_DHCP == QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) { + dp_debug("sending DHCP indication"); + dp_softap_notify_dhcp_ind(context, nbuf); + } else if (QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL) { + dp_softap_inspect_tx_eap_pkt(dp_intf, nbuf, true); + } +} + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +static inline +void dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t netbuf) +{ + dp_ctx->dp_ops.dp_tsf_timestamp_rx(dp_ctx->dp_ops.callback_ctx, + netbuf); +} +#else +static inline +void dp_softap_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t netbuf) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static inline bool dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + struct qdf_mac_addr *mld_addr; + + mld_addr = (struct qdf_mac_addr *)&dp_intf->mac_addr; + + if (!qdf_is_macaddr_zero(mld_addr) && + !qdf_mem_cmp(mld_addr->bytes, + (qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET), + QDF_MAC_ADDR_SIZE)) + return true; + + return false; +} +#else +static inline bool dp_nbuf_dst_addr_is_mld_addr(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + return false; +} +#endif + +QDF_STATUS dp_softap_rx_packet_cbk(void *link_ctx, qdf_nbuf_t rx_buf) +{ + struct wlan_dp_intf *dp_intf = NULL; + struct wlan_dp_link *dp_link = NULL; + QDF_STATUS qdf_status; + unsigned int cpu_index; + qdf_nbuf_t nbuf = NULL; + qdf_nbuf_t next = NULL; + struct wlan_dp_psoc_context *dp_ctx = NULL; + bool is_eapol = false; + struct dp_tx_rx_stats *stats; + + /* Sanity check on inputs */ + if (unlikely(!link_ctx || !rx_buf)) { + dp_err("Null params being passed"); + return QDF_STATUS_E_FAILURE; + } + + dp_link = (struct wlan_dp_link *)link_ctx; + dp_intf = dp_link->dp_intf; + dp_ctx = dp_intf->dp_ctx; + + stats = &dp_intf->dp_stats.tx_rx_stats; + /* walk the chain until all are processed */ + next = rx_buf; + + while (next) { + nbuf = next; + next = qdf_nbuf_next(nbuf); + qdf_nbuf_set_next(nbuf, NULL); + + dp_softap_dump_nbuf(nbuf); + + qdf_nbuf_set_dev(nbuf, dp_intf->dev); + + cpu_index = qdf_get_cpu(); + ++stats->per_cpu[cpu_index].rx_packets; + qdf_net_stats_add_rx_pkts(&dp_intf->stats, 1); + /* count aggregated RX frame into stats */ + qdf_net_stats_add_rx_pkts(&dp_intf->stats, + qdf_nbuf_get_gso_segs(nbuf)); + qdf_net_stats_add_rx_bytes(&dp_intf->stats, + qdf_nbuf_len(nbuf)); + + dp_softap_inspect_dhcp_packet(dp_link, nbuf, QDF_RX); + + if (qdf_nbuf_is_ipv4_eapol_pkt(nbuf)) + is_eapol = true; + + if (qdf_unlikely(is_eapol && + !(!qdf_mem_cmp(dp_link->mac_addr.bytes, + qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET, + QDF_MAC_ADDR_SIZE) || + dp_nbuf_dst_addr_is_mld_addr(dp_intf, nbuf)))) { + qdf_nbuf_free(nbuf); + continue; + } + + wlan_dp_pkt_add_timestamp(dp_intf, + QDF_PKT_RX_DRIVER_EXIT, nbuf); + + dp_event_eapol_log(nbuf, QDF_RX); + qdf_dp_trace_log_pkt(dp_link->link_id, + nbuf, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID, + dp_intf->device_mode); + DPTRACE(qdf_dp_trace(nbuf, + QDF_DP_TRACE_RX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(nbuf), + sizeof(qdf_nbuf_data(nbuf)), QDF_RX)); + DPTRACE(qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_RX_PACKET_RECORD, + 0, QDF_RX)); + + if (dp_rx_pkt_tracepoints_enabled()) + qdf_trace_dp_packet(nbuf, QDF_RX, NULL, 0); + + qdf_nbuf_set_protocol_eth_tye_trans(nbuf); + + /* hold configurable wakelock for unicast traffic */ + if (!dp_is_current_high_throughput(dp_ctx) && + dp_ctx->dp_cfg.rx_wakelock_timeout && + !qdf_nbuf_pkt_type_is_mcast(nbuf) && + !qdf_nbuf_pkt_type_is_bcast(nbuf)) { + cds_host_diag_log_work(&dp_ctx->rx_wake_lock, + dp_ctx->dp_cfg.rx_wakelock_timeout, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); + qdf_wake_lock_timeout_acquire(&dp_ctx->rx_wake_lock, + dp_ctx->dp_cfg.rx_wakelock_timeout); + } + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(nbuf); + + dp_softap_tsf_timestamp_rx(dp_ctx, nbuf); + + if (is_eapol && dp_ctx->dp_ops.dp_send_rx_pkt_over_nl) { + if (dp_ctx->dp_ops.dp_send_rx_pkt_over_nl(dp_intf->dev, + (u8 *)&dp_link->conn_info.peer_macaddr, + nbuf, false)) + qdf_status = QDF_STATUS_SUCCESS; + else + qdf_status = QDF_STATUS_E_INVAL; + qdf_nbuf_dev_kfree(nbuf); + } else { + qdf_status = wlan_dp_rx_deliver_to_stack(dp_intf, nbuf); + } + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + ++stats->per_cpu[cpu_index].rx_delivered; + else + ++stats->per_cpu[cpu_index].rx_refused; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_swlm.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_swlm.c new file mode 100644 index 0000000000..b2fe3c9e0d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_swlm.c @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef WLAN_DP_FEATURE_SW_LATENCY_MGR + +#include +#include +#include +#include "wlan_dp_swlm.h" +#include "qdf_time.h" +#include "qdf_util.h" +#include "hal_internal.h" +#include "hal_api.h" +#include "hif.h" +#include +#include + +/** + * dp_swlm_is_tput_thresh_reached() - Calculate the current tx and rx TPUT + * and check if it passes the pre-set + * threshold. + * @soc: Datapath global soc handle + * @rid: TCL ring id + * + * This function calculates the current TX and RX throughput and checks + * if it is above the pre-set thresholds by SWLM. + * + * Returns: true, if the TX/RX throughput is passing the threshold + * false, otherwise + */ +static bool dp_swlm_is_tput_thresh_reached(struct dp_soc *soc, uint8_t rid) +{ + struct dp_swlm_params *params = &soc->swlm.params; + int rx_delta, tx_delta, tx_packet_delta; + bool result = false; + + tx_delta = soc->stats.tx.egress[rid].bytes - + params->tcl[rid].prev_tx_bytes; + params->tcl[rid].prev_tx_bytes = soc->stats.tx.egress[rid].bytes; + if (tx_delta > params->tx_traffic_thresh) { + params->tcl[rid].sampling_session_tx_bytes = tx_delta; + result = true; + } + + rx_delta = soc->stats.rx.ingress.bytes - params->tcl[rid].prev_rx_bytes; + params->tcl[rid].prev_rx_bytes = soc->stats.rx.ingress.bytes; + if (!result && rx_delta > params->rx_traffic_thresh) { + params->tcl[rid].sampling_session_tx_bytes = tx_delta; + result = true; + } + + tx_packet_delta = soc->stats.tx.egress[rid].num - + params->tcl[rid].prev_tx_packets; + params->tcl[rid].prev_tx_packets = soc->stats.tx.egress[rid].num; + if (tx_packet_delta < params->tx_pkt_thresh) + result = false; + + return result; +} + +/** + * dp_swlm_can_tcl_wr_coalesce() - To check if current TCL reg write can be + * coalesced or not. + * @soc: Datapath global soc handle + * @tcl_data: priv data for tcl coalescing + * + * This function takes into account the current tx and rx throughput and + * decides whether the TCL register write corresponding to the current packet, + * to be transmitted, is to be processed or coalesced. + * It maintains a session for which the TCL register writes are coalesced and + * then flushed if a certain time/bytes threshold is reached. + * + * Returns: 1 if the current TCL write is to be coalesced + * 0, if the current TCL write is to be processed. + */ +static int +dp_swlm_can_tcl_wr_coalesce(struct dp_soc *soc, + struct dp_swlm_tcl_data *tcl_data) +{ + u64 curr_time = qdf_get_log_timestamp_usecs(); + int tput_level_pass, coalesce = 0; + struct dp_swlm *swlm = &soc->swlm; + uint8_t rid = tcl_data->ring_id; + struct dp_swlm_params *params = &soc->swlm.params; + + if (curr_time >= params->tcl[rid].expire_time) { + params->tcl[rid].expire_time = qdf_get_log_timestamp_usecs() + + params->sampling_time; + tput_level_pass = dp_swlm_is_tput_thresh_reached(soc, rid); + if (tput_level_pass) { + params->tcl[rid].tput_pass_cnt++; + } else { + params->tcl[rid].tput_pass_cnt = 0; + DP_STATS_INC(swlm, tcl[rid].tput_criteria_fail, 1); + goto coalescing_fail; + } + } + + params->tcl[rid].bytes_coalesced += tcl_data->pkt_len; + + if (params->tcl[rid].tput_pass_cnt > DP_SWLM_TCL_TPUT_PASS_THRESH) { + coalesce = 1; + if (params->tcl[rid].bytes_coalesced > + params->tcl[rid].bytes_flush_thresh) { + coalesce = 0; + DP_STATS_INC(swlm, tcl[rid].bytes_thresh_reached, 1); + } else if (curr_time > params->tcl[rid].coalesce_end_time) { + coalesce = 0; + DP_STATS_INC(swlm, tcl[rid].time_thresh_reached, 1); + } + } + +coalescing_fail: + if (!coalesce) { + dp_swlm_tcl_reset_session_data(soc, rid); + return 0; + } + + qdf_timer_mod(¶ms->tcl[rid].flush_timer, 1); + + return 1; +} + +QDF_STATUS dp_print_swlm_stats(struct dp_soc *soc) +{ + struct dp_swlm *swlm = &soc->swlm; + int i; + + for (i = 0; i < soc->num_tcl_data_rings; i++) { + dp_info("TCL: %u Coalescing stats:", i); + dp_info("Num coalesce success: %d", + swlm->stats.tcl[i].coalesce_success); + dp_info("Num coalesce fail: %d", + swlm->stats.tcl[i].coalesce_fail); + dp_info("Timer flush success: %d", + swlm->stats.tcl[i].timer_flush_success); + dp_info("Timer flush fail: %d", + swlm->stats.tcl[i].timer_flush_fail); + dp_info("Coalesce fail (TID): %d", + swlm->stats.tcl[i].tid_fail); + dp_info("Coalesce fail (special frame): %d", + swlm->stats.tcl[i].sp_frames); + dp_info("Coalesce fail (Low latency connection): %d", + swlm->stats.tcl[i].ll_connection); + dp_info("Coalesce fail (bytes thresh crossed): %d", + swlm->stats.tcl[i].bytes_thresh_reached); + dp_info("Coalesce fail (time thresh crossed): %d", + swlm->stats.tcl[i].time_thresh_reached); + dp_info("Coalesce fail (TPUT sampling fail): %d", + swlm->stats.tcl[i].tput_criteria_fail); + } + + return QDF_STATUS_SUCCESS; +} + +static struct dp_swlm_ops dp_latency_mgr_ops = { + .tcl_wr_coalesce_check = dp_swlm_can_tcl_wr_coalesce, +}; + +/** + * dp_swlm_tcl_flush_timer() - Timer handler for tcl register write coalescing + * @arg: private data of the timer + * + * Returns: none + */ +static void dp_swlm_tcl_flush_timer(void *arg) +{ + struct dp_swlm_tcl_params *tcl = arg; + struct dp_soc *soc = tcl->soc; + struct dp_swlm *swlm = &soc->swlm; + int ret; + + ret = soc->arch_ops.dp_flush_tx_ring(soc->pdev_list[0], tcl->ring_id); + if (ret) { + DP_STATS_INC(swlm, tcl[tcl->ring_id].timer_flush_fail, 1); + return; + } + + DP_STATS_INC(swlm, tcl[tcl->ring_id].timer_flush_success, 1); +} + +/** + * dp_soc_swlm_tcl_attach() - attach the TCL resources for the software + * latency manager. + * @soc: Datapath global soc handle + * + * Returns: QDF_STATUS + */ +static inline QDF_STATUS dp_soc_swlm_tcl_attach(struct dp_soc *soc) +{ + struct dp_swlm *swlm = &soc->swlm; + int i; + + swlm->params.rx_traffic_thresh = DP_SWLM_TCL_RX_TRAFFIC_THRESH; + swlm->params.tx_traffic_thresh = DP_SWLM_TCL_TX_TRAFFIC_THRESH; + swlm->params.sampling_time = DP_SWLM_TCL_TRAFFIC_SAMPLING_TIME; + swlm->params.time_flush_thresh = DP_SWLM_TCL_TIME_FLUSH_THRESH; + swlm->params.tx_thresh_multiplier = DP_SWLM_TCL_TX_THRESH_MULTIPLIER; + swlm->params.tx_pkt_thresh = DP_SWLM_TCL_TX_PKT_THRESH; + + for (i = 0; i < soc->num_tcl_data_rings; i++) { + swlm->params.tcl[i].soc = soc; + swlm->params.tcl[i].ring_id = i; + swlm->params.tcl[i].bytes_flush_thresh = 0; + qdf_timer_init(soc->osdev, + &swlm->params.tcl[i].flush_timer, + dp_swlm_tcl_flush_timer, + (void *)&swlm->params.tcl[i], + QDF_TIMER_TYPE_WAKE_APPS); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_soc_swlm_tcl_detach() - detach the TCL resources for the software + * latency manager. + * @swlm: SWLM data pointer + * @ring_id: TCL ring id + * + * Returns: QDF_STATUS + */ +static inline QDF_STATUS dp_soc_swlm_tcl_detach(struct dp_swlm *swlm, + uint8_t ring_id) +{ + qdf_timer_stop(&swlm->params.tcl[ring_id].flush_timer); + qdf_timer_free(&swlm->params.tcl[ring_id].flush_timer); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dp_soc_swlm_attach(struct dp_soc *soc) +{ + struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx; + struct dp_swlm *swlm = &soc->swlm; + QDF_STATUS ret; + + /* Check if it is enabled in the INI */ + if (!wlan_cfg_is_swlm_enabled(cfg)) { + dp_err("SWLM feature is disabled"); + swlm->is_init = false; + swlm->is_enabled = false; + return QDF_STATUS_E_NOSUPPORT; + } + + swlm->ops = &dp_latency_mgr_ops; + + ret = dp_soc_swlm_tcl_attach(soc); + if (QDF_IS_STATUS_ERROR(ret)) + goto swlm_tcl_setup_fail; + + swlm->is_init = true; + swlm->is_enabled = true; + + return QDF_STATUS_SUCCESS; + +swlm_tcl_setup_fail: + swlm->is_enabled = false; + return ret; +} + +QDF_STATUS dp_soc_swlm_detach(struct dp_soc *soc) +{ + struct dp_swlm *swlm = &soc->swlm; + QDF_STATUS ret; + int i; + + if (!swlm->is_enabled) + return QDF_STATUS_SUCCESS; + + swlm->is_enabled = false; + + for (i = 0; i < soc->num_tcl_data_rings; i++) { + ret = dp_soc_swlm_tcl_detach(swlm, i); + if (QDF_IS_STATUS_ERROR(ret)) + return ret; + } + + swlm->ops = NULL; + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_DP_FEATURE_SW_LATENCY_MGR */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_txrx.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_txrx.c new file mode 100644 index 0000000000..9f0691a18e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_txrx.c @@ -0,0 +1,1889 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: wlan_dp_txrx.c + * DP TX/RX path implementation + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_dp_rx_thread.h" +#if defined(WLAN_SUPPORT_RX_FISA) +#include "wlan_dp_fisa_rx.h" +#endif +#include "nan_public_structs.h" +#include "wlan_nan_api_i.h" +#include +#include +#include +#include +#include "wlan_tdls_api.h" +#include +#include + +uint32_t wlan_dp_intf_get_pkt_type_bitmap_value(void *intf_ctx) +{ + struct wlan_dp_intf *dp_intf = (struct wlan_dp_intf *)intf_ctx; + + if (!dp_intf) { + dp_err_rl("DP Context is NULL"); + return 0; + } + + return dp_intf->pkt_type_bitmap; +} + +#if defined(WLAN_SUPPORT_RX_FISA) +void dp_rx_skip_fisa(struct wlan_dp_psoc_context *dp_ctx, uint32_t value) +{ + qdf_atomic_set(&dp_ctx->skip_fisa_param.skip_fisa, !value); +} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void dp_get_tx_resource(struct wlan_dp_link *dp_link, + struct qdf_mac_addr *mac_addr) +{ + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_intf->dp_ctx->dp_ops; + + dp_ops->dp_get_tx_resource(dp_link->link_id, + mac_addr); +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * dp_event_eapol_log() - send event to wlan diag + * @nbuf: Network buffer ptr + * @dir: direction + * + * Return: None + */ +void dp_event_eapol_log(qdf_nbuf_t nbuf, enum qdf_proto_dir dir) +{ + int16_t eapol_key_info; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct host_event_wlan_eapol); + + if (dir == QDF_TX && QDF_NBUF_CB_PACKET_TYPE_EAPOL != + QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) + return; + else if (!qdf_nbuf_is_ipv4_eapol_pkt(nbuf)) + return; + + eapol_key_info = (uint16_t)(*(uint16_t *) + (nbuf->data + EAPOL_KEY_INFO_OFFSET)); + + wlan_diag_event.event_sub_type = + (dir == QDF_TX ? + WIFI_EVENT_DRIVER_EAPOL_FRAME_TRANSMIT_REQUESTED : + WIFI_EVENT_DRIVER_EAPOL_FRAME_RECEIVED); + wlan_diag_event.eapol_packet_type = (uint8_t)(*(uint8_t *) + (nbuf->data + EAPOL_PACKET_TYPE_OFFSET)); + wlan_diag_event.eapol_key_info = eapol_key_info; + wlan_diag_event.eapol_rate = 0; + qdf_mem_copy(wlan_diag_event.dest_addr, + (nbuf->data + QDF_NBUF_DEST_MAC_OFFSET), + sizeof(wlan_diag_event.dest_addr)); + qdf_mem_copy(wlan_diag_event.src_addr, + (nbuf->data + QDF_NBUF_SRC_MAC_OFFSET), + sizeof(wlan_diag_event.src_addr)); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +static int dp_intf_is_tx_allowed(qdf_nbuf_t nbuf, + uint8_t intf_id, void *soc, + uint8_t *peer_mac) +{ + enum ol_txrx_peer_state peer_state; + + peer_state = cdp_peer_state_get(soc, intf_id, peer_mac, false); + if (qdf_likely(OL_TXRX_PEER_STATE_AUTH == peer_state)) + return true; + if (OL_TXRX_PEER_STATE_CONN == peer_state && + (qdf_ntohs(qdf_nbuf_get_protocol(nbuf)) == ETHERTYPE_PAE || + IS_DP_ETHERTYPE_WAI(nbuf))) + return true; + + dp_info("Invalid peer state for Tx: %d", peer_state); + return false; +} + +/** + * dp_tx_rx_is_dns_domain_name_match() - function to check whether dns + * domain name in the received nbuf matches with the tracking dns domain + * name or not + * + * @nbuf: Network buffer pointer + * @dp_intf: DP interface pointer + * + * Returns: true if matches else false + */ +static bool dp_tx_rx_is_dns_domain_name_match(qdf_nbuf_t nbuf, + struct wlan_dp_intf *dp_intf) +{ + uint8_t *domain_name; + + if (dp_intf->track_dns_domain_len == 0) + return false; + + /* check OOB , is strncmp accessing data more than skb->len */ + if ((dp_intf->track_dns_domain_len + + QDF_NBUF_PKT_DNS_NAME_OVER_UDP_OFFSET) > qdf_nbuf_len(nbuf)) + return false; + + domain_name = qdf_nbuf_get_dns_domain_name(nbuf, + dp_intf->track_dns_domain_len); + if (qdf_str_ncmp(domain_name, dp_intf->dns_payload, + dp_intf->track_dns_domain_len) == 0) + return true; + else + return false; +} + +/** + * dp_clear_tx_rx_connectivity_stats() - clear connectivity stats + * @dp_intf: pointer to DP interface + * + * Return: None + */ +static void dp_clear_tx_rx_connectivity_stats(struct wlan_dp_intf *dp_intf) +{ + dp_debug("Clear txrx connectivity stats"); + qdf_mem_zero(&dp_intf->dp_stats.arp_stats, + sizeof(dp_intf->dp_stats.arp_stats)); + qdf_mem_zero(&dp_intf->dp_stats.dns_stats, + sizeof(dp_intf->dp_stats.dns_stats)); + qdf_mem_zero(&dp_intf->dp_stats.tcp_stats, + sizeof(dp_intf->dp_stats.tcp_stats)); + qdf_mem_zero(&dp_intf->dp_stats.icmpv4_stats, + sizeof(dp_intf->dp_stats.icmpv4_stats)); + dp_intf->pkt_type_bitmap = 0; + dp_intf->track_arp_ip = 0; + qdf_mem_zero(dp_intf->dns_payload, dp_intf->track_dns_domain_len); + dp_intf->track_dns_domain_len = 0; + dp_intf->track_src_port = 0; + dp_intf->track_dest_port = 0; + dp_intf->track_dest_ipv4 = 0; +} + +void dp_reset_all_intfs_connectivity_stats(struct wlan_dp_psoc_context *dp_ctx) +{ + struct wlan_dp_intf *dp_intf = NULL; + + qdf_spin_lock_bh(&dp_ctx->intf_list_lock); + for (dp_get_front_intf_no_lock(dp_ctx, &dp_intf); dp_intf; + dp_get_next_intf_no_lock(dp_ctx, dp_intf, &dp_intf)) { + dp_clear_tx_rx_connectivity_stats(dp_intf); + } + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); +} + +void +dp_tx_rx_collect_connectivity_stats_info(qdf_nbuf_t nbuf, void *context, + enum connectivity_stats_pkt_status action, uint8_t *pkt_type) +{ + uint32_t pkt_type_bitmap; + struct wlan_dp_link *dp_link = (struct wlan_dp_link *)context; + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + + /* ARP tracking is done already. */ + pkt_type_bitmap = dp_intf->pkt_type_bitmap; + + pkt_type_bitmap &= ~dp_intf->dp_ctx->arp_connectivity_map; + + if (!pkt_type_bitmap) + return; + + switch (action) { + case PKT_TYPE_REQ: + case PKT_TYPE_TX_HOST_FW_SENT: + if (qdf_nbuf_is_icmp_pkt(nbuf)) { + if (qdf_nbuf_data_is_icmpv4_req(nbuf) && + dp_intf->track_dest_ipv4 == + qdf_nbuf_get_icmpv4_tgt_ip(nbuf)) { + *pkt_type = DP_CONNECTIVITY_CHECK_SET_ICMPV4; + if (action == PKT_TYPE_REQ) { + ++dp_intf->dp_stats.icmpv4_stats. + tx_icmpv4_req_count; + dp_info("ICMPv4 Req packet"); + } else + /* host receives tx completion */ + ++dp_intf->dp_stats.icmpv4_stats. + tx_host_fw_sent; + } + } else if (qdf_nbuf_is_ipv4_tcp_pkt(nbuf)) { + if (qdf_nbuf_data_is_tcp_syn(nbuf) && + dp_intf->track_dest_port == + qdf_nbuf_data_get_tcp_dst_port(nbuf)) { + *pkt_type = DP_CONNECTIVITY_CHECK_SET_TCP_SYN; + if (action == PKT_TYPE_REQ) { + ++dp_intf->dp_stats.tcp_stats. + tx_tcp_syn_count; + dp_info("TCP Syn packet"); + } else { + /* host receives tx completion */ + ++dp_intf->dp_stats.tcp_stats. + tx_tcp_syn_host_fw_sent; + } + } else if ((dp_intf->dp_stats.tcp_stats. + is_tcp_syn_ack_rcv || dp_intf->dp_stats. + tcp_stats.is_tcp_ack_sent) && + qdf_nbuf_data_is_tcp_ack(nbuf) && + (dp_intf->track_dest_port == + qdf_nbuf_data_get_tcp_dst_port(nbuf))) { + *pkt_type = DP_CONNECTIVITY_CHECK_SET_TCP_ACK; + if (action == PKT_TYPE_REQ && + dp_intf->dp_stats.tcp_stats. + is_tcp_syn_ack_rcv) { + ++dp_intf->dp_stats.tcp_stats. + tx_tcp_ack_count; + dp_intf->dp_stats.tcp_stats. + is_tcp_syn_ack_rcv = false; + dp_intf->dp_stats.tcp_stats. + is_tcp_ack_sent = true; + dp_info("TCP Ack packet"); + } else if (action == PKT_TYPE_TX_HOST_FW_SENT && + dp_intf->dp_stats.tcp_stats. + is_tcp_ack_sent) { + /* host receives tx completion */ + ++dp_intf->dp_stats.tcp_stats. + tx_tcp_ack_host_fw_sent; + dp_intf->dp_stats.tcp_stats. + is_tcp_ack_sent = false; + } + } + } else if (qdf_nbuf_is_ipv4_udp_pkt(nbuf)) { + if (qdf_nbuf_data_is_dns_query(nbuf) && + dp_tx_rx_is_dns_domain_name_match(nbuf, dp_intf)) { + *pkt_type = DP_CONNECTIVITY_CHECK_SET_DNS; + if (action == PKT_TYPE_REQ) { + ++dp_intf->dp_stats.dns_stats. + tx_dns_req_count; + dp_info("DNS query packet"); + } else + /* host receives tx completion */ + ++dp_intf->dp_stats.dns_stats. + tx_host_fw_sent; + } + } + break; + + case PKT_TYPE_RSP: + if (qdf_nbuf_is_icmp_pkt(nbuf)) { + if (qdf_nbuf_data_is_icmpv4_rsp(nbuf) && + (dp_intf->track_dest_ipv4 == + qdf_nbuf_get_icmpv4_src_ip(nbuf))) { + ++dp_intf->dp_stats.icmpv4_stats. + rx_icmpv4_rsp_count; + *pkt_type = + DP_CONNECTIVITY_CHECK_SET_ICMPV4; + dp_info("ICMPv4 resp packet"); + } + } else if (qdf_nbuf_is_ipv4_tcp_pkt(nbuf)) { + if (qdf_nbuf_data_is_tcp_syn_ack(nbuf) && + (dp_intf->track_dest_port == + qdf_nbuf_data_get_tcp_src_port(nbuf))) { + ++dp_intf->dp_stats.tcp_stats. + rx_tcp_syn_ack_count; + dp_intf->dp_stats.tcp_stats. + is_tcp_syn_ack_rcv = true; + *pkt_type = + DP_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK; + dp_info("TCP Syn ack packet"); + } + } else if (qdf_nbuf_is_ipv4_udp_pkt(nbuf)) { + if (qdf_nbuf_data_is_dns_response(nbuf) && + dp_tx_rx_is_dns_domain_name_match(nbuf, dp_intf)) { + ++dp_intf->dp_stats.dns_stats. + rx_dns_rsp_count; + *pkt_type = DP_CONNECTIVITY_CHECK_SET_DNS; + dp_info("DNS resp packet"); + } + } + break; + + case PKT_TYPE_TX_DROPPED: + switch (*pkt_type) { + case DP_CONNECTIVITY_CHECK_SET_ICMPV4: + ++dp_intf->dp_stats.icmpv4_stats.tx_dropped; + dp_info("ICMPv4 Req packet dropped"); + break; + case DP_CONNECTIVITY_CHECK_SET_TCP_SYN: + ++dp_intf->dp_stats.tcp_stats.tx_tcp_syn_dropped; + dp_info("TCP syn packet dropped"); + break; + case DP_CONNECTIVITY_CHECK_SET_TCP_ACK: + ++dp_intf->dp_stats.tcp_stats.tx_tcp_ack_dropped; + dp_info("TCP ack packet dropped"); + break; + case DP_CONNECTIVITY_CHECK_SET_DNS: + ++dp_intf->dp_stats.dns_stats.tx_dropped; + dp_info("DNS query packet dropped"); + break; + default: + break; + } + break; + case PKT_TYPE_RX_DELIVERED: + switch (*pkt_type) { + case DP_CONNECTIVITY_CHECK_SET_ICMPV4: + ++dp_intf->dp_stats.icmpv4_stats.rx_delivered; + break; + case DP_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + ++dp_intf->dp_stats.tcp_stats.rx_delivered; + break; + case DP_CONNECTIVITY_CHECK_SET_DNS: + ++dp_intf->dp_stats.dns_stats.rx_delivered; + break; + default: + break; + } + break; + case PKT_TYPE_RX_REFUSED: + switch (*pkt_type) { + case DP_CONNECTIVITY_CHECK_SET_ICMPV4: + ++dp_intf->dp_stats.icmpv4_stats.rx_refused; + break; + case DP_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + ++dp_intf->dp_stats.tcp_stats.rx_refused; + break; + case DP_CONNECTIVITY_CHECK_SET_DNS: + ++dp_intf->dp_stats.dns_stats.rx_refused; + break; + default: + break; + } + break; + case PKT_TYPE_TX_ACK_CNT: + switch (*pkt_type) { + case DP_CONNECTIVITY_CHECK_SET_ICMPV4: + ++dp_intf->dp_stats.icmpv4_stats.tx_ack_cnt; + break; + case DP_CONNECTIVITY_CHECK_SET_TCP_SYN: + ++dp_intf->dp_stats.tcp_stats.tx_tcp_syn_ack_cnt; + break; + case DP_CONNECTIVITY_CHECK_SET_TCP_ACK: + ++dp_intf->dp_stats.tcp_stats.tx_tcp_ack_ack_cnt; + break; + case DP_CONNECTIVITY_CHECK_SET_DNS: + ++dp_intf->dp_stats.dns_stats.tx_ack_cnt; + break; + default: + break; + } + break; + default: + break; + } +} + +/** + * dp_get_transmit_mac_addr() - Get the mac address to validate the xmit + * @dp_link: DP link handle + * @nbuf: The network buffer + * @mac_addr_tx_allowed: The mac address to be filled + * + * Return: None + */ +static +void dp_get_transmit_mac_addr(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf, + struct qdf_mac_addr *mac_addr_tx_allowed) +{ + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + bool is_mc_bc_addr = false; + enum nan_datapath_state state; + + /* Check for VDEV validity before accessing it. Since VDEV references + * are not taken in the per packet path, there is a change for VDEV + * getting deleted in a parallel context. Because DP VDEV object is + * protected by dp_intf::num_active_task, the chance of VDEV object + * getting deleted while executing dp_start_xmit() is sparse. So, a + * simple VDEV NULL check should be sufficient to handle the case of + * VDEV getting destroyed first followed by dp_start_xmit(). + */ + if (!dp_link->vdev) + return; + + switch (dp_intf->device_mode) { + case QDF_NDI_MODE: + state = wlan_nan_get_ndi_state(dp_link->vdev); + if (state == NAN_DATA_NDI_CREATED_STATE || + state == NAN_DATA_CONNECTED_STATE || + state == NAN_DATA_CONNECTING_STATE || + state == NAN_DATA_PEER_CREATE_STATE) { + if (QDF_NBUF_CB_GET_IS_BCAST(nbuf) || + QDF_NBUF_CB_GET_IS_MCAST(nbuf)) + is_mc_bc_addr = true; + if (is_mc_bc_addr) + qdf_copy_macaddr(mac_addr_tx_allowed, + &dp_intf->mac_addr); + else + qdf_copy_macaddr(mac_addr_tx_allowed, + (struct qdf_mac_addr *)qdf_nbuf_data(nbuf)); + } + break; + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (wlan_cm_is_vdev_active(dp_link->vdev)) + qdf_copy_macaddr(mac_addr_tx_allowed, + &dp_link->conn_info.bssid); + break; + default: + break; + } +} + +#ifdef HANDLE_BROADCAST_EAPOL_TX_FRAME +/** + * dp_fix_broadcast_eapol() - Fix broadcast eapol + * @dp_link: pointer to dp link + * @nbuf: pointer to nbuf + * + * Override DA of broadcast eapol with bssid addr. + * + * Return: None + */ +static void dp_fix_broadcast_eapol(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf) +{ + qdf_ether_header_t *eth_hdr = (qdf_ether_header_t *)qdf_nbuf_data(nbuf); + unsigned char *ap_mac_addr = + &dp_link->conn_info.bssid.bytes[0]; + + if (qdf_unlikely((QDF_NBUF_CB_GET_PACKET_TYPE(nbuf) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL) && + QDF_NBUF_CB_GET_IS_BCAST(nbuf))) { + dp_debug("SA: "QDF_MAC_ADDR_FMT " override DA: "QDF_MAC_ADDR_FMT " with AP mac address "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ð_hdr->ether_shost[0]), + QDF_MAC_ADDR_REF(ð_hdr->ether_dhost[0]), + QDF_MAC_ADDR_REF(ap_mac_addr)); + + qdf_mem_copy(ð_hdr->ether_dhost, ap_mac_addr, + QDF_MAC_ADDR_SIZE); + } +} +#else +static void dp_fix_broadcast_eapol(struct wlan_dp_link *dp_link, + qdf_nbuf_t nbuf) +{ +} +#endif /* HANDLE_BROADCAST_EAPOL_TX_FRAME */ + +#ifdef WLAN_DP_FEATURE_MARK_ICMP_REQ_TO_FW +/** + * dp_mark_icmp_req_to_fw() - Mark the ICMP request at a certain time interval + * to be sent to the FW. + * @dp_ctx: Global dp context + * @nbuf: packet to be transmitted + * + * This func sets the "to_fw" flag in the packet context block, if the + * current packet is an ICMP request packet. This marking is done at a + * specific time interval, unless the INI value indicates to disable/enable + * this for all frames. + * + * Return: none + */ +static void dp_mark_icmp_req_to_fw(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t nbuf) +{ + uint64_t curr_time, time_delta; + int time_interval_ms = dp_ctx->dp_cfg.icmp_req_to_fw_mark_interval; + static uint64_t prev_marked_icmp_time; + + if (!dp_ctx->dp_cfg.icmp_req_to_fw_mark_interval) + return; + + if ((qdf_nbuf_get_icmp_subtype(nbuf) != QDF_PROTO_ICMP_REQ) && + (qdf_nbuf_get_icmpv6_subtype(nbuf) != QDF_PROTO_ICMPV6_REQ)) + return; + + /* Mark all ICMP request to be sent to FW */ + if (time_interval_ms == WLAN_CFG_ICMP_REQ_TO_FW_MARK_ALL) + QDF_NBUF_CB_TX_PACKET_TO_FW(nbuf) = 1; + + /* For fragment IPV4 ICMP frames + * only mark last segment once to FW + */ + if (qdf_nbuf_is_ipv4_pkt(nbuf) && + qdf_nbuf_is_ipv4_fragment(nbuf)) + return; + + curr_time = qdf_get_log_timestamp(); + time_delta = curr_time - prev_marked_icmp_time; + if (time_delta >= (time_interval_ms * + QDF_LOG_TIMESTAMP_CYCLES_PER_10_US * 100)) { + QDF_NBUF_CB_TX_PACKET_TO_FW(nbuf) = 1; + prev_marked_icmp_time = curr_time; + } +} +#else +static void dp_mark_icmp_req_to_fw(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t nbuf) +{ +} +#endif + +#ifdef CONFIG_DP_PKT_ADD_TIMESTAMP +void wlan_dp_pkt_add_timestamp(struct wlan_dp_intf *dp_intf, + enum qdf_pkt_timestamp_index index, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_callbacks *dp_ops; + + if (qdf_unlikely(qdf_is_dp_pkt_timestamp_enabled())) { + uint64_t tsf_time; + + dp_ops = &dp_intf->dp_ctx->dp_ops; + dp_ops->dp_get_tsf_time(dp_intf->dev, + qdf_get_log_timestamp(), + &tsf_time); + qdf_add_dp_pkt_timestamp(nbuf, index, tsf_time); + } +} +#endif + +QDF_STATUS +dp_start_xmit(struct wlan_dp_link *dp_link, qdf_nbuf_t nbuf) +{ + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct dp_tx_rx_stats *stats; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + bool is_arp = false; + bool is_eapol = false; + bool is_dhcp = false; + uint8_t pkt_type; + struct qdf_mac_addr mac_addr_tx_allowed = QDF_MAC_ADDR_ZERO_INIT; + int cpu = qdf_get_smp_processor_id(); + + stats = &dp_intf->dp_stats.tx_rx_stats; + ++stats->per_cpu[cpu].tx_called; + stats->cont_txtimeout_cnt = 0; + + if (qdf_unlikely(cds_is_driver_transitioning())) { + dp_err_rl("driver is transitioning, drop pkt"); + goto drop_pkt; + } + + if (qdf_unlikely(dp_ctx->is_suspend)) { + dp_err_rl("Device is system suspended, drop pkt"); + goto drop_pkt; + } + + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(nbuf) = 1; + + pkt_type = QDF_NBUF_CB_GET_PACKET_TYPE(nbuf); + + if (pkt_type == QDF_NBUF_CB_PACKET_TYPE_ARP) { + if (qdf_nbuf_data_is_arp_req(nbuf) && + (dp_intf->track_arp_ip == qdf_nbuf_get_arp_tgt_ip(nbuf))) { + is_arp = true; + ++dp_intf->dp_stats.arp_stats.tx_arp_req_count; + dp_info("ARP packet"); + } + } else if (pkt_type == QDF_NBUF_CB_PACKET_TYPE_EAPOL) { + subtype = qdf_nbuf_get_eapol_subtype(nbuf); + if (subtype == QDF_PROTO_EAPOL_M2) { + ++dp_intf->dp_stats.eapol_stats.eapol_m2_count; + is_eapol = true; + } else if (subtype == QDF_PROTO_EAPOL_M4) { + ++dp_intf->dp_stats.eapol_stats.eapol_m4_count; + is_eapol = true; + } + } else if (pkt_type == QDF_NBUF_CB_PACKET_TYPE_DHCP) { + subtype = qdf_nbuf_get_dhcp_subtype(nbuf); + if (subtype == QDF_PROTO_DHCP_DISCOVER) { + ++dp_intf->dp_stats.dhcp_stats.dhcp_dis_count; + is_dhcp = true; + } else if (subtype == QDF_PROTO_DHCP_REQUEST) { + ++dp_intf->dp_stats.dhcp_stats.dhcp_req_count; + is_dhcp = true; + } + } else if ((pkt_type == QDF_NBUF_CB_PACKET_TYPE_ICMP) || + (pkt_type == QDF_NBUF_CB_PACKET_TYPE_ICMPv6)) { + dp_mark_icmp_req_to_fw(dp_ctx, nbuf); + } + + wlan_dp_pkt_add_timestamp(dp_intf, QDF_PKT_TX_DRIVER_ENTRY, nbuf); + + /* track connectivity stats */ + if (dp_intf->pkt_type_bitmap) + dp_tx_rx_collect_connectivity_stats_info(nbuf, dp_link, + PKT_TYPE_REQ, + &pkt_type); + + dp_get_transmit_mac_addr(dp_link, nbuf, &mac_addr_tx_allowed); + if (qdf_is_macaddr_zero(&mac_addr_tx_allowed)) { + dp_info_rl("tx not allowed, transmit operation suspended"); + goto drop_pkt; + } + + dp_get_tx_resource(dp_link, &mac_addr_tx_allowed); + + if (!qdf_nbuf_ipa_owned_get(nbuf)) { + nbuf = dp_nbuf_orphan(dp_intf, nbuf); + if (!nbuf) + goto drop_pkt_accounting; + } + + /* + * Add SKB to internal tracking table before further processing + * in WLAN driver. + */ + qdf_net_buf_debug_acquire_skb(nbuf, __FILE__, __LINE__); + + qdf_net_stats_add_tx_bytes(&dp_intf->stats, qdf_nbuf_len(nbuf)); + + if (qdf_nbuf_is_tso(nbuf)) { + qdf_net_stats_add_tx_pkts(&dp_intf->stats, + qdf_nbuf_get_tso_num_seg(nbuf)); + } else { + qdf_net_stats_add_tx_pkts(&dp_intf->stats, 1); + dp_ctx->no_tx_offload_pkt_cnt++; + } + + dp_event_eapol_log(nbuf, QDF_TX); + QDF_NBUF_CB_TX_PACKET_TRACK(nbuf) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_UPDATE_TX_PKT_COUNT(nbuf, QDF_NBUF_TX_PKT_DP); + + qdf_dp_trace_set_track(nbuf, QDF_TX); + + DPTRACE(qdf_dp_trace(nbuf, QDF_DP_TRACE_TX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(nbuf), + sizeof(qdf_nbuf_data(nbuf)), + QDF_TX)); + + if (!dp_intf_is_tx_allowed(nbuf, dp_link->link_id, soc, + mac_addr_tx_allowed.bytes)) { + dp_info("Tx not allowed for sta:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr_tx_allowed.bytes)); + goto drop_pkt_and_release_nbuf; + } + + /* check whether need to linearize nbuf, like non-linear udp data */ + if (dp_nbuf_nontso_linearize(nbuf) != QDF_STATUS_SUCCESS) { + dp_err_rl(" nbuf %pK linearize failed. drop the pkt", nbuf); + goto drop_pkt_and_release_nbuf; + } + + /* + * If a transmit function is not registered, drop packet + */ + if (!dp_intf->txrx_ops.tx.tx) { + dp_err_rl("TX function not registered by the data path"); + goto drop_pkt_and_release_nbuf; + } + + dp_fix_broadcast_eapol(dp_link, nbuf); + + if (dp_intf->txrx_ops.tx.tx(soc, dp_link->link_id, nbuf)) { + dp_debug_rl("Failed to send packet from adapter %u", + dp_link->link_id); + goto drop_pkt_and_release_nbuf; + } + + return QDF_STATUS_SUCCESS; + +drop_pkt_and_release_nbuf: + qdf_net_buf_debug_release_skb(nbuf); +drop_pkt: + + /* track connectivity stats */ + if (dp_intf->pkt_type_bitmap) + dp_tx_rx_collect_connectivity_stats_info(nbuf, dp_link, + PKT_TYPE_TX_DROPPED, + &pkt_type); + qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_DROP_PACKET_RECORD, 0, + QDF_TX); + qdf_nbuf_kfree(nbuf); + +drop_pkt_accounting: + + qdf_net_stats_inc_tx_dropped(&dp_intf->stats); + ++stats->per_cpu[cpu].tx_dropped; + if (is_arp) { + ++dp_intf->dp_stats.arp_stats.tx_dropped; + dp_info_rl("ARP packet dropped"); + } else if (is_eapol) { + ++dp_intf->dp_stats.eapol_stats. + tx_dropped[subtype - QDF_PROTO_EAPOL_M1]; + } else if (is_dhcp) { + ++dp_intf->dp_stats.dhcp_stats. + tx_dropped[subtype - QDF_PROTO_DHCP_DISCOVER]; + } + + return QDF_STATUS_E_FAILURE; +} + +void dp_tx_timeout(struct wlan_dp_intf *dp_intf) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + u64 diff_time; + + cdp_dump_flow_pool_info(soc); + + ++dp_intf->dp_stats.tx_rx_stats.tx_timeout_cnt; + ++dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt; + + diff_time = qdf_system_ticks() - + dp_intf->dp_stats.tx_rx_stats.last_txtimeout; + + if ((dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt > 1) && + (diff_time > (DP_TX_TIMEOUT * 2))) { + /* + * In case when there is no traffic is running, it may + * possible tx time-out may once happen and later system + * recovered then continuous tx timeout count has to be + * reset as it is gets modified only when traffic is running. + * If over a period of time if this count reaches to threshold + * then host triggers a false subsystem restart. In genuine + * time out case OS will call the tx time-out back to back + * at interval of DP_TX_TIMEOUT. Here now check if previous + * TX TIME out has occurred more than twice of DP_TX_TIMEOUT + * back then host may recovered here from data stall. + */ + dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + dp_info("Reset continuous tx timeout stat"); + } + + dp_intf->dp_stats.tx_rx_stats.last_txtimeout = qdf_system_ticks(); + + if (dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt > + DP_TX_STALL_THRESHOLD) { + dp_err("Data stall due to continuous TX timeouts"); + dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt = 0; + + if (dp_is_data_stall_event_enabled(DP_HOST_STA_TX_TIMEOUT)) + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_HOST_STA_TX_TIMEOUT, + OL_TXRX_PDEV_ID, 0xFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } +} + +void dp_sta_notify_tx_comp_cb(qdf_nbuf_t nbuf, void *ctx, uint16_t flag) +{ + struct wlan_dp_link *dp_link = ctx; + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + enum qdf_proto_subtype subtype; + struct qdf_mac_addr *dest_mac_addr; + QDF_STATUS status; + + if (is_dp_intf_valid(dp_intf)) + return; + + dest_mac_addr = (struct qdf_mac_addr *)qdf_nbuf_data(nbuf); + + switch (QDF_NBUF_CB_GET_PACKET_TYPE(nbuf)) { + case QDF_NBUF_CB_PACKET_TYPE_ARP: + if (flag & BIT(QDF_TX_RX_STATUS_DOWNLOAD_SUCC)) + ++dp_intf->dp_stats.arp_stats. + tx_host_fw_sent; + if (flag & BIT(QDF_TX_RX_STATUS_OK)) + ++dp_intf->dp_stats.arp_stats.tx_ack_cnt; + break; + case QDF_NBUF_CB_PACKET_TYPE_EAPOL: + subtype = qdf_nbuf_get_eapol_subtype(nbuf); + if (!(flag & BIT(QDF_TX_RX_STATUS_OK)) && + subtype != QDF_PROTO_INVALID && + subtype <= QDF_PROTO_EAPOL_M4) + ++dp_intf->dp_stats.eapol_stats. + tx_noack_cnt[subtype - QDF_PROTO_EAPOL_M1]; + break; + case QDF_NBUF_CB_PACKET_TYPE_DHCP: + subtype = qdf_nbuf_get_dhcp_subtype(nbuf); + if (!(flag & BIT(QDF_TX_RX_STATUS_OK)) && + subtype != QDF_PROTO_INVALID && + subtype <= QDF_PROTO_DHCP_ACK) + ++dp_intf->dp_stats.dhcp_stats. + tx_noack_cnt[subtype - QDF_PROTO_DHCP_DISCOVER]; + break; + default: + break; + } + + /* Since it is TDLS call took TDLS vdev ref*/ + status = wlan_objmgr_vdev_try_get_ref(dp_link->vdev, WLAN_TDLS_SB_ID); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_tdls_update_tx_pkt_cnt(dp_link->vdev, dest_mac_addr); + wlan_objmgr_vdev_release_ref(dp_link->vdev, WLAN_TDLS_SB_ID); + } +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +QDF_STATUS dp_mon_rx_packet_cbk(void *context, qdf_nbuf_t rxbuf) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + QDF_STATUS status; + qdf_nbuf_t nbuf; + qdf_nbuf_t nbuf_next; + unsigned int cpu_index; + struct dp_tx_rx_stats *stats; + enum dp_nbuf_push_type type; + + /* Sanity check on inputs */ + if ((!context) || (!rxbuf)) { + dp_err_rl("Null params being passed"); + return QDF_STATUS_E_FAILURE; + } + + dp_link = (struct wlan_dp_link *)context; + dp_intf = dp_link->dp_intf; + if (!dp_intf) { + dp_err_rl("dp_intf is NULL for dp_link %pK", dp_link); + return QDF_STATUS_E_FAILURE; + } + + cpu_index = qdf_get_cpu(); + stats = &dp_intf->dp_stats.tx_rx_stats; + + /* walk the chain until all are processed */ + nbuf = rxbuf; + while (nbuf) { + nbuf_next = qdf_nbuf_next(nbuf); + qdf_nbuf_set_dev(nbuf, dp_intf->dev); + + ++stats->per_cpu[cpu_index].rx_packets; + qdf_net_stats_add_rx_pkts(&dp_intf->stats, 1); + qdf_net_stats_add_rx_bytes(&dp_intf->stats, + qdf_nbuf_len(nbuf)); + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(nbuf); + + /* + * If this is not a last packet on the chain + * Just put packet into backlog queue, not scheduling RX sirq + */ + if (qdf_nbuf_next(nbuf)) { + status = dp_intf->dp_ctx->dp_ops.dp_nbuf_push_pkt(nbuf, + DP_NBUF_PUSH_SIMPLE); + } else { + /* + * This is the last packet on the chain + * Scheduling rx sirq + */ + type = qdf_in_atomic() ? DP_NBUF_PUSH_NAPI : + DP_NBUF_PUSH_BH_DISABLE; + status = dp_intf->dp_ctx->dp_ops.dp_nbuf_push_pkt(nbuf, + type); + } + + if (QDF_IS_STATUS_SUCCESS(status)) + ++stats->per_cpu[cpu_index].rx_delivered; + else + ++stats->per_cpu[cpu_index].rx_refused; + + nbuf = nbuf_next; + } + + return QDF_STATUS_SUCCESS; +} + +void dp_monitor_set_rx_monitor_cb(struct ol_txrx_ops *txrx, + ol_txrx_rx_mon_fp rx_monitor_cb) +{ + txrx->rx.mon = rx_monitor_cb; +} + +void dp_rx_monitor_callback(ol_osif_vdev_handle context, + qdf_nbuf_t rxbuf, + void *rx_status) +{ + dp_mon_rx_packet_cbk(context, rxbuf); +} +#endif + +/** + * dp_is_rx_wake_lock_needed() - check if wake lock is needed + * @nbuf: pointer to sk_buff + * @is_arp_req: ARP request packet + * + * RX wake lock is needed for: + * 1) Local ARP data packet + * 2) Unicast data packet + * + * Return: true if wake lock is needed or false otherwise. + */ +static bool dp_is_rx_wake_lock_needed(qdf_nbuf_t nbuf, bool is_arp_req) +{ + /* Take wake lock for local ARP request packet */ + if (qdf_unlikely(is_arp_req)) { + if (qdf_nbuf_is_arp_local(nbuf)) + return true; + } else if (qdf_likely(!qdf_nbuf_pkt_type_is_mcast(nbuf) && + !qdf_nbuf_pkt_type_is_bcast(nbuf))) { + return true; + } + + return false; +} + +#ifdef RECEIVE_OFFLOAD +/** + * dp_resolve_rx_ol_mode() - Resolve Rx offload method, LRO or GRO + * @dp_ctx: pointer to DP psoc Context + * + * Return: None + */ +static void dp_resolve_rx_ol_mode(struct wlan_dp_psoc_context *dp_ctx) +{ + void *soc; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!(cdp_cfg_get(soc, cfg_dp_lro_enable) ^ + cdp_cfg_get(soc, cfg_dp_gro_enable))) { + cdp_cfg_get(soc, cfg_dp_lro_enable) && + cdp_cfg_get(soc, cfg_dp_gro_enable) ? + dp_info("Can't enable both LRO and GRO, disabling Rx offload"): + dp_info("LRO and GRO both are disabled"); + dp_ctx->ol_enable = 0; + } else if (cdp_cfg_get(soc, cfg_dp_lro_enable)) { + dp_info("Rx offload LRO is enabled"); + dp_ctx->ol_enable = CFG_LRO_ENABLED; + } else { + dp_info("Rx offload: GRO is enabled"); + dp_ctx->ol_enable = CFG_GRO_ENABLED; + } +} + +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +/** + * dp_gro_rx_bh_disable() - GRO RX/flush function. + * @dp_intf: DP interface pointer + * @napi_to_use: napi to be used to give packets to the stack, gro flush + * @nbuf: pointer to n/w buff + * + * Function calls napi_gro_receive for the skb. If the skb indicates that a + * flush needs to be done (set by the lower DP layer), the function also calls + * napi_gro_flush. Local softirqs are disabled (and later enabled) while making + * napi_gro__ calls. + * + * Return: QDF_STATUS_SUCCESS if not dropped by napi_gro_receive or + * QDF error code. + */ +static QDF_STATUS dp_gro_rx_bh_disable(struct wlan_dp_intf *dp_intf, + qdf_napi_struct *napi_to_use, + qdf_nbuf_t nbuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + uint32_t rx_aggregation; + uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); + uint8_t low_tput_force_flush = 0; + int32_t gro_disallowed; + + rx_aggregation = qdf_atomic_read(&dp_ctx->dp_agg_param.rx_aggregation); + gro_disallowed = qdf_atomic_read(&dp_intf->gro_disallowed); + + if (dp_get_current_throughput_level(dp_ctx) == PLD_BUS_WIDTH_IDLE || + !rx_aggregation || gro_disallowed) { + status = dp_ctx->dp_ops.dp_rx_napi_gro_flush(napi_to_use, nbuf, + &low_tput_force_flush); + if (!low_tput_force_flush) + dp_intf->dp_stats.tx_rx_stats. + rx_gro_low_tput_flush++; + if (!rx_aggregation) + dp_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] = 1; + if (gro_disallowed) + dp_intf->gro_flushed[rx_ctx_id] = 1; + } else { + status = dp_ctx->dp_ops.dp_rx_napi_gro_receive(napi_to_use, + nbuf); + } + + return status; +} + +#else /* WLAN_FEATURE_DYNAMIC_RX_AGGREGATION */ + +/** + * dp_gro_rx_bh_disable() - GRO RX/flush function. + * @dp_intf: DP interface pointer + * @napi_to_use: napi to be used to give packets to the stack, gro flush + * @nbuf: pointer to nbuff + * + * Function calls napi_gro_receive for the skb. If the skb indicates that a + * flush needs to be done (set by the lower DP layer), the function also calls + * napi_gro_flush. Local softirqs are disabled (and later enabled) while making + * napi_gro__ calls. + * + * Return: QDF_STATUS_SUCCESS if not dropped by napi_gro_receive or + * QDF error code. + */ + +static QDF_STATUS dp_gro_rx_bh_disable(struct wlan_dp_intf *dp_intf, + qdf_napi_struct *napi_to_use, + qdf_nbuf_t nbuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + uint8_t low_tput_force_flush = 0; + + if (dp_get_current_throughput_level(dp_ctx) == PLD_BUS_WIDTH_IDLE) { + status = dp_ctx->dp_ops.dp_rx_napi_gro_flush(napi_to_use, nbuf, + &low_tput_force_flush); + if (!low_tput_force_flush) + dp_intf->dp_stats.tx_rx_stats. + rx_gro_low_tput_flush++; + } else { + status = dp_ctx->dp_ops.dp_rx_napi_gro_receive(napi_to_use, + nbuf); + } + + return status; +} +#endif /* WLAN_FEATURE_DYNAMIC_RX_AGGREGATION */ + +#if defined(FEATURE_LRO) +/** + * dp_lro_rx() - Handle Rx processing via LRO + * @dp_intf: pointer to DP interface + * @nbuf: pointer to n/w buff + * + * Return: QDF_STATUS_SUCCESS if processed via LRO or non zero return code + */ +static inline QDF_STATUS +dp_lro_rx(struct wlan_dp_intf *dp_intf, qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + return dp_ctx->dp_ops.dp_lro_rx_cb(dp_intf->dev, nbuf); +} + +/** + * dp_is_lro_enabled() - Is LRO enabled + * @dp_ctx: DP interface + * + * This function checks if LRO is enabled in DP context. + * + * Return: 0 - success, < 0 - failure + */ +static inline QDF_STATUS +dp_is_lro_enabled(struct wlan_dp_psoc_context *dp_ctx) +{ + if (dp_ctx->ol_enable != CFG_LRO_ENABLED) + return QDF_STATUS_E_NOSUPPORT; +} + +QDF_STATUS dp_lro_set_reset(struct wlan_dp_intf *dp_intf, uint8_t enable_flag) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + if ((dp_ctx->ol_enable != CFG_LRO_ENABLED) || + (dp_intf->device_mode != QDF_STA_MODE)) { + dp_info("LRO is already Disabled"); + return QDF_STATUS_E_INVAL; + } + + if (enable_flag) { + qdf_atomic_set(&dp_ctx->vendor_disable_lro_flag, 0); + } else { + /* Disable LRO, Enable tcpdelack*/ + qdf_atomic_set(&dp_ctx->vendor_disable_lro_flag, 1); + dp_info("LRO Disabled"); + + if (dp_ctx->dp_cfg.enable_tcp_delack) { + struct wlan_rx_tp_data rx_tp_data; + + dp_info("Enable TCP delack as LRO is disabled"); + rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND; + rx_tp_data.level = + DP_BUS_BW_CFG(dp_ctx->dp_cfg.cur_rx_level); + wlan_dp_update_tcp_rx_param(dp_ctx, &rx_tp_data); + dp_ctx->en_tcp_delack_no_lro = 1; + } + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline +QDF_STATUS dp_lro_rx(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +int dp_is_lro_enabled(struct wlan_dp_psoc_context *dp_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* FEATURE_LRO */ + +/** + * dp_gro_rx_thread() - Handle Rx processing via GRO for DP thread + * @dp_intf: pointer to DP interface + * @nbuf: pointer to n/w buff + * + * Return: QDF_STATUS_SUCCESS if processed via GRO or non zero return code + */ +static +QDF_STATUS dp_gro_rx_thread(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + qdf_napi_struct *napi_to_use = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!dp_intf->dp_ctx->enable_dp_rx_threads) { + dp_err_rl("gro not supported without DP RX thread!"); + return status; + } + + napi_to_use = + (qdf_napi_struct *)dp_rx_get_napi_context(cds_get_context(QDF_MODULE_ID_SOC), + QDF_NBUF_CB_RX_CTX_ID(nbuf)); + + if (!napi_to_use) { + dp_err_rl("no napi to use for GRO!"); + return status; + } + + return dp_gro_rx_bh_disable(dp_intf, napi_to_use, nbuf); +} + +/** + * dp_gro_rx_legacy() - Handle Rx processing via GRO for ihelium based targets + * @dp_intf: pointer to DP interface + * @nbuf: pointer to n/w buf + * + * Supports GRO for only station mode + * + * Return: QDF_STATUS_SUCCESS if processed via GRO or non zero return code + */ +static +QDF_STATUS dp_gro_rx_legacy(struct wlan_dp_intf *dp_intf, qdf_nbuf_t nbuf) +{ + qdf_napi_struct *napi_to_use; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + /* Only enabling it for STA mode like LRO today */ + if (QDF_STA_MODE != dp_intf->device_mode) + return QDF_STATUS_E_NOSUPPORT; + + if (qdf_atomic_read(&dp_ctx->disable_rx_ol_in_low_tput) || + qdf_atomic_read(&dp_ctx->disable_rx_ol_in_concurrency)) + return QDF_STATUS_E_NOSUPPORT; + + napi_to_use = dp_ctx->dp_ops.dp_gro_rx_legacy_get_napi(nbuf, + dp_ctx->enable_rxthread); + if (!napi_to_use) + goto out; + + status = dp_gro_rx_bh_disable(dp_intf, napi_to_use, nbuf); +out: + + return status; +} + +/** + * dp_register_rx_ol_cb() - Register LRO/GRO rx processing callbacks + * @dp_ctx: pointer to dp_ctx + * @wifi3_0_target: whether its a lithium/beryllium arch based target or not + * + * Return: none + */ +static void dp_register_rx_ol_cb(struct wlan_dp_psoc_context *dp_ctx, + bool wifi3_0_target) +{ + if (!dp_ctx) { + dp_err("DP context is NULL"); + return; + } + + dp_ctx->en_tcp_delack_no_lro = 0; + + if (!dp_is_lro_enabled(dp_ctx)) { + dp_ctx->dp_ops.dp_register_rx_offld_flush_cb(DP_RX_FLUSH_LRO); + dp_ctx->receive_offload_cb = dp_lro_rx; + dp_info("LRO is enabled"); + } else if (dp_ctx->ol_enable == CFG_GRO_ENABLED) { + qdf_atomic_set(&dp_ctx->dp_agg_param.rx_aggregation, 1); + if (wifi3_0_target) { + /* no flush registration needed, it happens in DP thread */ + dp_ctx->receive_offload_cb = dp_gro_rx_thread; + } else { + /*ihelium based targets */ + if (dp_ctx->enable_rxthread) + dp_ctx->dp_ops.dp_register_rx_offld_flush_cb( + DP_RX_FLUSH_THREAD); + else + dp_ctx->dp_ops.dp_register_rx_offld_flush_cb( + DP_RX_FLUSH_NAPI); + dp_ctx->receive_offload_cb = dp_gro_rx_legacy; + } + dp_info("GRO is enabled"); + } else if (DP_BUS_BW_CFG(dp_ctx->dp_cfg.enable_tcp_delack)) { + dp_ctx->en_tcp_delack_no_lro = 1; + dp_info("TCP Del ACK is enabled"); + } +} + +/** + * dp_rx_ol_send_config() - Send RX offload configuration to FW + * @dp_ctx: pointer to DP_ctx + * + * This function is only used for non lithium targets. Lithium based targets are + * sending LRO config to FW in vdev attach implemented in cmn DP layer. + * + * Return: 0 on success, non zero on failure + */ +static QDF_STATUS dp_rx_ol_send_config(struct wlan_dp_psoc_context *dp_ctx) +{ + struct cdp_lro_hash_config lro_config = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* + * This will enable flow steering and Toeplitz hash + * So enable it for LRO or GRO processing. + */ + if (dp_ctx->dp_cfg.gro_enable || + dp_ctx->dp_cfg.lro_enable) { + lro_config.lro_enable = 1; + lro_config.tcp_flag = QDF_TCPHDR_ACK; + lro_config.tcp_flag_mask = QDF_TCPHDR_FIN | QDF_TCPHDR_SYN | + QDF_TCPHDR_RST | QDF_TCPHDR_ACK | + QDF_TCPHDR_URG | QDF_TCPHDR_ECE | + QDF_TCPHDR_CWR; + } + + qdf_get_random_bytes(lro_config.toeplitz_hash_ipv4, + (sizeof(lro_config.toeplitz_hash_ipv4[0]) * + LRO_IPV4_SEED_ARR_SZ)); + + qdf_get_random_bytes(lro_config.toeplitz_hash_ipv6, + (sizeof(lro_config.toeplitz_hash_ipv6[0]) * + LRO_IPV6_SEED_ARR_SZ)); + + status = dp_ctx->sb_ops.dp_lro_config_cmd(dp_ctx->psoc, &lro_config); + dp_info("LRO Config: lro_enable: 0x%x tcp_flag 0x%x tcp_flag_mask 0x%x", + lro_config.lro_enable, lro_config.tcp_flag, + lro_config.tcp_flag_mask); + + return status; +} + +QDF_STATUS dp_rx_ol_init(struct wlan_dp_psoc_context *dp_ctx, + bool is_wifi3_0_target) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + dp_resolve_rx_ol_mode(dp_ctx); + dp_register_rx_ol_cb(dp_ctx, is_wifi3_0_target); + + dp_info("ol init"); + if (!is_wifi3_0_target) { + status = dp_rx_ol_send_config(dp_ctx); + if (status) { + dp_ctx->ol_enable = 0; + dp_err("Failed to send LRO/GRO configuration! %u", status); + return status; + } + } + + return 0; +} + +void dp_disable_rx_ol_for_low_tput(struct wlan_dp_psoc_context *dp_ctx, + bool disable) +{ + if (disable) + qdf_atomic_set(&dp_ctx->disable_rx_ol_in_low_tput, 1); + else + qdf_atomic_set(&dp_ctx->disable_rx_ol_in_low_tput, 0); +} + +#else /* RECEIVE_OFFLOAD */ +void dp_disable_rx_ol_for_low_tput(struct wlan_dp_psoc_context *dp_ctx, + bool disable) +{ +} +#endif /* RECEIVE_OFFLOAD */ + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +static inline void dp_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t netbuf) +{ + dp_ctx->dp_ops.dp_tsf_timestamp_rx(dp_ctx->dp_ops.callback_ctx, + netbuf); +} +#else +static inline void dp_tsf_timestamp_rx(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t netbuf) +{ +} +#endif + +QDF_STATUS +dp_rx_thread_gro_flush_ind_cbk(void *link_ctx, int rx_ctx_id) +{ + struct wlan_dp_link *dp_link = link_ctx; + struct wlan_dp_intf *dp_intf; + enum dp_rx_gro_flush_code gro_flush_code = DP_RX_GRO_NORMAL_FLUSH; + + if (qdf_unlikely((!dp_link) || (!dp_link->dp_intf) || + (!dp_link->dp_intf->dp_ctx))) { + dp_err("Null params being passed"); + return QDF_STATUS_E_FAILURE; + } + + dp_intf = dp_link->dp_intf; + if (dp_intf->runtime_disable_rx_thread) + return QDF_STATUS_SUCCESS; + + if (dp_is_low_tput_gro_enable(dp_intf->dp_ctx)) { + dp_intf->dp_stats.tx_rx_stats.rx_gro_flush_skip++; + gro_flush_code = DP_RX_GRO_LOW_TPUT_FLUSH; + } + + return dp_rx_gro_flush_ind(cds_get_context(QDF_MODULE_ID_SOC), + rx_ctx_id, gro_flush_code); +} + +QDF_STATUS dp_rx_pkt_thread_enqueue_cbk(void *link_ctx, + qdf_nbuf_t nbuf_list) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + uint8_t link_id; + qdf_nbuf_t head_ptr; + + if (qdf_unlikely(!link_ctx || !nbuf_list)) { + dp_err_rl("Null params being passed"); + return QDF_STATUS_E_FAILURE; + } + + dp_link = (struct wlan_dp_link *)link_ctx; + if (!is_dp_link_valid(dp_link)) + return QDF_STATUS_E_FAILURE; + + dp_intf = dp_link->dp_intf; + if (dp_intf->runtime_disable_rx_thread && + dp_intf->txrx_ops.rx.rx_stack) + return dp_intf->txrx_ops.rx.rx_stack(dp_link, nbuf_list); + + link_id = dp_link->link_id; + + head_ptr = nbuf_list; + while (head_ptr) { + qdf_nbuf_cb_update_vdev_id(head_ptr, + link_id); + head_ptr = qdf_nbuf_next(head_ptr); + } + + return dp_rx_enqueue_pkt(cds_get_context(QDF_MODULE_ID_SOC), nbuf_list); +} + +#ifdef CONFIG_HL_SUPPORT +QDF_STATUS wlan_dp_rx_deliver_to_stack(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + + dp_intf->dp_stats.tx_rx_stats.rx_non_aggregated++; + dp_ctx->no_rx_offload_pkt_cnt++; + + return dp_ctx->dp_ops.dp_nbuf_push_pkt(nbuf, DP_NBUF_PUSH_NI); +} +#else + +#if defined(WLAN_SUPPORT_RX_FISA) +/** + * wlan_dp_set_fisa_disallowed_for_intf() - Set fisa disallowed bit for an intf + * @soc: DP soc handle + * @dp_intf: DP interface handle + * @rx_ctx_id: rx context id + * @val: Enable or disable + * + * The function sets the fisa disallowed flag for a given vdev + * + * Return: None + */ +static inline +void wlan_dp_set_fisa_disallowed_for_intf(ol_txrx_soc_handle soc, + struct wlan_dp_intf *dp_intf, + uint8_t rx_ctx_id, uint8_t val) +{ + dp_intf->fisa_disallowed[rx_ctx_id] = val; +} +#else +static inline +void wlan_dp_set_fisa_disallowed_for_intf(ol_txrx_soc_handle soc, + struct wlan_dp_intf *dp_intf, + uint8_t rx_ctx_id, uint8_t val) +{ +} +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +QDF_STATUS wlan_dp_rx_deliver_to_stack(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + int status = QDF_STATUS_E_FAILURE; + bool nbuf_receive_offload_ok = false; + enum dp_nbuf_push_type push_type; + uint8_t rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(nbuf); + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + int32_t gro_disallowed; + + if (QDF_NBUF_CB_RX_TCP_PROTO(nbuf) && + !QDF_NBUF_CB_RX_PEER_CACHED_FRM(nbuf)) + nbuf_receive_offload_ok = true; + + gro_disallowed = qdf_atomic_read(&dp_intf->gro_disallowed); + if (gro_disallowed == 0 && + dp_intf->gro_flushed[rx_ctx_id] != 0) { + if (qdf_likely(soc)) + wlan_dp_set_fisa_disallowed_for_intf(soc, dp_intf, + rx_ctx_id, 0); + dp_intf->gro_flushed[rx_ctx_id] = 0; + } else if (gro_disallowed && + dp_intf->gro_flushed[rx_ctx_id] == 0) { + if (qdf_likely(soc)) + wlan_dp_set_fisa_disallowed_for_intf(soc, dp_intf, + rx_ctx_id, 1); + } + + if (nbuf_receive_offload_ok && dp_ctx->receive_offload_cb && + !dp_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] && + !dp_intf->gro_flushed[rx_ctx_id] && + !dp_intf->runtime_disable_rx_thread) { + status = dp_ctx->receive_offload_cb(dp_intf, nbuf); + + if (QDF_IS_STATUS_SUCCESS(status)) { + dp_intf->dp_stats.tx_rx_stats.rx_aggregated++; + return status; + } + + if (status == QDF_STATUS_E_GRO_DROP) { + dp_intf->dp_stats.tx_rx_stats.rx_gro_dropped++; + return status; + } + } + + /* + * The below case handles the scenario when rx_aggregation is + * re-enabled dynamically, in which case gro_force_flush needs + * to be reset to 0 to allow GRO. + */ + if (qdf_atomic_read(&dp_ctx->dp_agg_param.rx_aggregation) && + dp_ctx->dp_agg_param.gro_force_flush[rx_ctx_id]) + dp_ctx->dp_agg_param.gro_force_flush[rx_ctx_id] = 0; + + dp_intf->dp_stats.tx_rx_stats.rx_non_aggregated++; + + /* Account for GRO/LRO ineligible packets, mostly UDP */ + if (qdf_nbuf_get_gso_segs(nbuf) == 0) + dp_ctx->no_rx_offload_pkt_cnt++; + + if (qdf_likely((dp_ctx->enable_dp_rx_threads || + dp_ctx->enable_rxthread) && + (!dp_intf->runtime_disable_rx_thread || + !in_softirq()))) { + push_type = DP_NBUF_PUSH_BH_DISABLE; + } else if (qdf_unlikely(QDF_NBUF_CB_RX_PEER_CACHED_FRM(nbuf))) { + /* + * Frames before peer is registered to avoid contention with + * NAPI softirq. + * Refer fix: + * qcacld-3.0: Do netif_rx_ni() for frames received before + * peer assoc + */ + push_type = DP_NBUF_PUSH_NI; + } else { /* NAPI Context */ + push_type = DP_NBUF_PUSH_NAPI; + } + + return dp_ops->dp_nbuf_push_pkt(nbuf, push_type); +} + +#else /* WLAN_FEATURE_DYNAMIC_RX_AGGREGATION */ + +QDF_STATUS wlan_dp_rx_deliver_to_stack(struct wlan_dp_intf *dp_intf, + qdf_nbuf_t nbuf) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_intf->dp_ctx; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_ctx->dp_ops; + int status = QDF_STATUS_E_FAILURE; + bool nbuf_receive_offload_ok = false; + enum dp_nbuf_push_type push_type; + + if (QDF_NBUF_CB_RX_TCP_PROTO(nbuf) && + !QDF_NBUF_CB_RX_PEER_CACHED_FRM(nbuf)) + nbuf_receive_offload_ok = true; + + if (nbuf_receive_offload_ok && dp_ctx->receive_offload_cb) { + status = dp_ctx->receive_offload_cb(dp_intf, nbuf); + + if (QDF_IS_STATUS_SUCCESS(status)) { + dp_intf->dp_stats.tx_rx_stats.rx_aggregated++; + return status; + } + + if (status == QDF_STATUS_E_GRO_DROP) { + dp_intf->dp_stats.tx_rx_stats.rx_gro_dropped++; + return status; + } + } + + dp_intf->dp_stats.tx_rx_stats.rx_non_aggregated++; + + /* Account for GRO/LRO ineligible packets, mostly UDP */ + if (qdf_nbuf_get_gso_segs(nbuf) == 0) + dp_ctx->no_rx_offload_pkt_cnt++; + + if (qdf_likely((dp_ctx->enable_dp_rx_threads || + dp_ctx->enable_rxthread) && + (!dp_intf->runtime_disable_rx_thread || + !in_softirq()))) { + push_type = DP_NBUF_PUSH_BH_DISABLE; + } else if (qdf_unlikely(QDF_NBUF_CB_RX_PEER_CACHED_FRM(nbuf))) { + /* + * Frames before peer is registered to avoid contention with + * NAPI softirq. + * Refer fix: + * qcacld-3.0: Do netif_rx_ni() for frames received before + * peer assoc + */ + push_type = DP_NBUF_PUSH_NI; + } else { /* NAPI Context */ + push_type = DP_NBUF_PUSH_NAPI; + } + + return dp_ops->dp_nbuf_push_pkt(nbuf, push_type); +} +#endif /* WLAN_FEATURE_DYNAMIC_RX_AGGREGATION */ +#endif + +static inline bool +dp_is_gratuitous_arp_unsolicited_na(struct wlan_dp_psoc_context *dp_ctx, + qdf_nbuf_t nbuf) +{ + if (qdf_unlikely(dp_ctx->dp_ops.dp_is_gratuitous_arp_unsolicited_na)) + return dp_ctx->dp_ops.dp_is_gratuitous_arp_unsolicited_na(nbuf); + + return false; +} + +QDF_STATUS dp_rx_flush_packet_cbk(void *dp_link_context, uint8_t link_id) +{ + struct wlan_dp_link *dp_link = (struct wlan_dp_link *)dp_link_context; + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + struct wlan_dp_psoc_context *dp_ctx; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (qdf_unlikely(!soc)) + return QDF_STATUS_E_FAILURE; + + dp_ctx = dp_intf->dp_ctx; + if (qdf_unlikely(!dp_ctx)) + return QDF_STATUS_E_FAILURE; + + qdf_atomic_inc(&dp_intf->num_active_task); + + /* do fisa flush for this vdev */ + if (wlan_dp_cfg_is_rx_fisa_enabled(&dp_ctx->dp_cfg)) + wlan_dp_rx_fisa_flush_by_vdev_id((struct dp_soc *)soc, link_id); + + if (dp_ctx->enable_dp_rx_threads) + dp_txrx_flush_pkts_by_vdev_id(soc, link_id); + + qdf_atomic_dec(&dp_intf->num_active_task); + + return QDF_STATUS_SUCCESS; +} + +#if defined(WLAN_SUPPORT_RX_FISA) +QDF_STATUS wlan_dp_rx_fisa_cbk(void *dp_soc, + void *dp_vdev, qdf_nbuf_t nbuf_list) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + + return dp_fisa_rx(dp_ctx, dp_vdev, nbuf_list); +} + +QDF_STATUS wlan_dp_rx_fisa_flush_by_ctx_id(void *dp_soc, int ring_num) +{ + return dp_rx_fisa_flush_by_ctx_id((struct dp_soc *)dp_soc, ring_num); +} + +QDF_STATUS wlan_dp_rx_fisa_flush_by_vdev_id(void *dp_soc, uint8_t vdev_id) +{ + return dp_rx_fisa_flush_by_vdev_id((struct dp_soc *)dp_soc, vdev_id); +} +#endif + +QDF_STATUS dp_rx_packet_cbk(void *dp_link_context, + qdf_nbuf_t rxBuf) +{ + struct wlan_dp_intf *dp_intf = NULL; + struct wlan_dp_link *dp_link = NULL; + struct wlan_dp_psoc_context *dp_ctx = NULL; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + qdf_nbuf_t nbuf = NULL; + qdf_nbuf_t next = NULL; + unsigned int cpu_index; + struct qdf_mac_addr *mac_addr, *dest_mac_addr; + bool wake_lock = false; + bool track_arp = false; + bool is_arp_req; + enum qdf_proto_subtype subtype = QDF_PROTO_INVALID; + bool is_eapol, send_over_nl; + bool is_dhcp, is_ip_mcast; + struct dp_tx_rx_stats *stats; + QDF_STATUS status; + uint8_t pkt_type; + + /* Sanity check on inputs */ + if (qdf_unlikely((!dp_link_context) || (!rxBuf))) { + dp_err_rl("Null params being passed"); + return QDF_STATUS_E_FAILURE; + } + + dp_link = (struct wlan_dp_link *)dp_link_context; + dp_intf = dp_link->dp_intf; + dp_ctx = dp_intf->dp_ctx; + + cpu_index = qdf_get_cpu(); + stats = &dp_intf->dp_stats.tx_rx_stats; + + next = rxBuf; + + while (next) { + nbuf = next; + next = qdf_nbuf_next(nbuf); + qdf_nbuf_set_next(nbuf, NULL); + is_arp_req = false; + is_eapol = false; + is_dhcp = false; + is_ip_mcast = false; + send_over_nl = false; + + if (qdf_nbuf_is_ipv4_arp_pkt(nbuf)) { + if (qdf_nbuf_data_is_arp_rsp(nbuf) && + (dp_intf->track_arp_ip == + qdf_nbuf_get_arp_src_ip(nbuf))) { + ++dp_intf->dp_stats.arp_stats. + rx_arp_rsp_count; + dp_debug("ARP packet received"); + track_arp = true; + } else if (qdf_nbuf_data_is_arp_req(nbuf)) { + is_arp_req = true; + } + } else if (qdf_nbuf_is_ipv4_eapol_pkt(nbuf)) { + subtype = qdf_nbuf_get_eapol_subtype(nbuf); + send_over_nl = true; + + /* Mac address check between RX packet DA and dp_intf's */ + dp_rx_pkt_da_check(dp_intf, nbuf); + if (subtype == QDF_PROTO_EAPOL_M1) { + ++dp_intf->dp_stats.eapol_stats. + eapol_m1_count; + is_eapol = true; + } else if (subtype == QDF_PROTO_EAPOL_M3) { + ++dp_intf->dp_stats.eapol_stats. + eapol_m3_count; + is_eapol = true; + } + } else if (qdf_nbuf_is_ipv4_dhcp_pkt(nbuf)) { + subtype = qdf_nbuf_get_dhcp_subtype(nbuf); + if (subtype == QDF_PROTO_DHCP_OFFER) { + ++dp_intf->dp_stats.dhcp_stats. + dhcp_off_count; + is_dhcp = true; + } else if (subtype == QDF_PROTO_DHCP_ACK) { + ++dp_intf->dp_stats.dhcp_stats. + dhcp_ack_count; + is_dhcp = true; + } + } else if (qdf_nbuf_data_is_ipv4_mcast_pkt(nbuf->data) || + qdf_nbuf_data_is_ipv6_mcast_pkt(nbuf->data)) { + is_ip_mcast = true; + } + + wlan_dp_pkt_add_timestamp(dp_intf, QDF_PKT_RX_DRIVER_EXIT, + nbuf); + + /* track connectivity stats */ + if (dp_intf->pkt_type_bitmap) + dp_tx_rx_collect_connectivity_stats_info(nbuf, dp_link, + PKT_TYPE_RSP, + &pkt_type); + + if ((dp_link->conn_info.proxy_arp_service) && + dp_is_gratuitous_arp_unsolicited_na(dp_ctx, nbuf)) { + qdf_atomic_inc(&stats->rx_usolict_arp_n_mcast_drp); + /* Remove SKB from internal tracking table before + * submitting it to stack. + */ + qdf_nbuf_free(nbuf); + continue; + } + + dp_event_eapol_log(nbuf, QDF_RX); + qdf_dp_trace_log_pkt(dp_link->link_id, nbuf, QDF_RX, + QDF_TRACE_DEFAULT_PDEV_ID, + dp_intf->device_mode); + + DPTRACE(qdf_dp_trace(nbuf, + QDF_DP_TRACE_RX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(nbuf), + sizeof(qdf_nbuf_data(nbuf)), QDF_RX)); + + DPTRACE(qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_RX_PACKET_RECORD, + 0, QDF_RX)); + + dest_mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) + + QDF_NBUF_DEST_MAC_OFFSET); + mac_addr = (struct qdf_mac_addr *)(qdf_nbuf_data(nbuf) + + QDF_NBUF_SRC_MAC_OFFSET); + + status = wlan_objmgr_vdev_try_get_ref(dp_link->vdev, + WLAN_TDLS_SB_ID); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_tdls_update_rx_pkt_cnt(dp_link->vdev, mac_addr, + dest_mac_addr); + wlan_objmgr_vdev_release_ref(dp_link->vdev, + WLAN_TDLS_SB_ID); + } + + if (dp_rx_pkt_tracepoints_enabled()) + qdf_trace_dp_packet(nbuf, QDF_RX, NULL, 0); + + qdf_nbuf_set_dev(nbuf, dp_intf->dev); + qdf_nbuf_set_protocol_eth_tye_trans(nbuf); + ++stats->per_cpu[cpu_index].rx_packets; + qdf_net_stats_add_rx_pkts(&dp_intf->stats, 1); + /* count aggregated RX frame into stats */ + qdf_net_stats_add_rx_pkts(&dp_intf->stats, + qdf_nbuf_get_gso_segs(nbuf)); + qdf_net_stats_add_rx_bytes(&dp_intf->stats, + qdf_nbuf_len(nbuf)); + + /* Incr GW Rx count for NUD tracking based on GW mac addr */ + dp_nud_incr_gw_rx_pkt_cnt(dp_intf, mac_addr); + + /* Check & drop replayed mcast packets (for IPV6) */ + if (dp_ctx->dp_cfg.multicast_replay_filter && + qdf_nbuf_is_mcast_replay(nbuf)) { + qdf_atomic_inc(&stats->rx_usolict_arp_n_mcast_drp); + qdf_nbuf_free(nbuf); + continue; + } + + /* hold configurable wakelock for unicast traffic */ + if (!dp_is_current_high_throughput(dp_ctx) && + dp_ctx->dp_cfg.rx_wakelock_timeout && + dp_link->conn_info.is_authenticated && !is_ip_mcast) + wake_lock = dp_is_rx_wake_lock_needed(nbuf, is_arp_req); + + if (wake_lock) { + cds_host_diag_log_work(&dp_ctx->rx_wake_lock, + dp_ctx->dp_cfg.rx_wakelock_timeout, + WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); + qdf_wake_lock_timeout_acquire(&dp_ctx->rx_wake_lock, + dp_ctx->dp_cfg.rx_wakelock_timeout); + } + + /* Remove SKB from internal tracking table before submitting + * it to stack + */ + qdf_net_buf_debug_release_skb(nbuf); + + dp_tsf_timestamp_rx(dp_ctx, nbuf); + + if (send_over_nl && dp_ctx->dp_ops.dp_send_rx_pkt_over_nl) { + if (dp_ctx->dp_ops.dp_send_rx_pkt_over_nl(dp_intf->dev, + (u8 *)&dp_link->conn_info.peer_macaddr, + nbuf, false)) + qdf_status = QDF_STATUS_SUCCESS; + else + qdf_status = QDF_STATUS_E_INVAL; + qdf_nbuf_dev_kfree(nbuf); + } else { + qdf_status = wlan_dp_rx_deliver_to_stack(dp_intf, nbuf); + } + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + ++stats->per_cpu[cpu_index].rx_delivered; + if (track_arp) + ++dp_intf->dp_stats.arp_stats.rx_delivered; + if (is_eapol) + ++dp_intf->dp_stats.eapol_stats. + rx_delivered[subtype - QDF_PROTO_EAPOL_M1]; + else if (is_dhcp) + ++dp_intf->dp_stats.dhcp_stats. + rx_delivered[subtype - QDF_PROTO_DHCP_DISCOVER]; + + /* track connectivity stats */ + if (dp_intf->pkt_type_bitmap) + dp_tx_rx_collect_connectivity_stats_info( + nbuf, dp_link, + PKT_TYPE_RX_DELIVERED, + &pkt_type); + } else { + ++stats->per_cpu[cpu_index].rx_refused; + if (track_arp) + ++dp_intf->dp_stats.arp_stats.rx_refused; + + if (is_eapol) + ++dp_intf->dp_stats.eapol_stats. + rx_refused[subtype - QDF_PROTO_EAPOL_M1]; + else if (is_dhcp) + ++dp_intf->dp_stats.dhcp_stats. + rx_refused[subtype - QDF_PROTO_DHCP_DISCOVER]; + + /* track connectivity stats */ + if (dp_intf->pkt_type_bitmap) + dp_tx_rx_collect_connectivity_stats_info( + nbuf, dp_link, + PKT_TYPE_RX_REFUSED, + &pkt_type); + } + } + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_wfds.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_wfds.c new file mode 100644 index 0000000000..80b7013b6b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/core/src/wlan_dp_wfds.c @@ -0,0 +1,751 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "wlan_dp_wfds.h" +#include "hif.h" +#include "hal_api.h" +#include "dp_types.h" +#include "dp_rx.h" +#include "pld_common.h" +#include "wlan_objmgr_psoc_obj.h" +#include +#include "wlan_dp_prealloc.h" +#include + +static struct dp_direct_link_wfds_context *gp_dl_wfds_ctx; + +/** + * dp_wfds_send_config_msg() - Send config message to WFDS QMI server + * @dl_wfds: Direct Link WFDS context + * + * Return: QDF status + */ +static QDF_STATUS +dp_wfds_send_config_msg(struct dp_direct_link_wfds_context *dl_wfds) +{ + struct dp_direct_link_context *direct_link_ctx = + dl_wfds->direct_link_ctx; + struct wlan_qmi_wfds_config_req_msg *info; + struct dp_soc *dp_soc = + wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc); + struct hif_opaque_softc *hif_ctx; + qdf_device_t qdf_dev; + void *hal_soc; + struct hal_mem_info mem_info = {0}; + struct hif_direct_link_ce_info ce_info[QMI_WFDS_CE_MAX_SRNG] = {0}; + QDF_STATUS status; + struct hif_ce_ring_info *srng_info; + struct hal_srng_params srng_params = {0}; + hal_ring_handle_t refill_ring; + uint8_t i; + + qdf_dev = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + + if (!dp_soc || !dp_soc->hif_handle || !qdf_dev) + return QDF_STATUS_E_FAILURE; + + hif_ctx = dp_soc->hif_handle; + + hal_soc = hif_get_hal_handle(hif_ctx); + if (!hal_soc) + return QDF_STATUS_E_FAILURE; + + hal_get_meminfo(hal_soc, &mem_info); + + info = qdf_mem_malloc(sizeof(*info)); + if (!info) + return QDF_STATUS_E_NOMEM; + + info->shadow_rdptr_mem_paddr = + (uint64_t)mem_info.shadow_rdptr_mem_paddr; + info->shadow_rdptr_mem_size = sizeof(uint32_t) * HAL_SRNG_ID_MAX; + info->shadow_wrptr_mem_paddr = + (uint64_t)mem_info.shadow_wrptr_mem_paddr; + info->shadow_wrptr_mem_size = sizeof(uint32_t) * HAL_MAX_LMAC_RINGS; + info->pcie_bar_pa = (uint64_t)mem_info.dev_base_paddr; + + dl_wfds->iommu_cfg.shadow_rdptr_paddr = info->shadow_rdptr_mem_paddr; + dl_wfds->iommu_cfg.shadow_rdptr_map_size = info->shadow_rdptr_mem_size; + dl_wfds->iommu_cfg.shadow_wrptr_paddr = info->shadow_wrptr_mem_paddr; + dl_wfds->iommu_cfg.shadow_wrptr_map_size = info->shadow_wrptr_mem_size; + + pld_audio_smmu_map(qdf_dev->dev, + qdf_mem_paddr_from_dmaaddr(qdf_dev, + info->shadow_rdptr_mem_paddr), + info->shadow_rdptr_mem_paddr, + info->shadow_rdptr_mem_size); + pld_audio_smmu_map(qdf_dev->dev, + qdf_mem_paddr_from_dmaaddr(qdf_dev, + info->shadow_wrptr_mem_paddr), + info->shadow_wrptr_mem_paddr, + info->shadow_wrptr_mem_size); + + info->ce_info_len = QMI_WFDS_CE_MAX_SRNG; + status = hif_get_direct_link_ce_srng_info(hif_ctx, ce_info, + QMI_WFDS_CE_MAX_SRNG); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Direct Link CE srng info get failed"); + qdf_mem_free(info); + return status; + } + + for (i = 0; i < QMI_WFDS_CE_MAX_SRNG; i++) { + info->ce_info[i].ce_id = ce_info[i].ce_id; + info->ce_info[i].ce_dir = ce_info[i].pipe_dir; + + srng_info = &ce_info[i].ring_info; + info->ce_info[i].srng_info.ring_id = srng_info->ring_id; + info->ce_info[i].srng_info.dir = srng_info->ring_dir; + info->ce_info[i].srng_info.num_entries = srng_info->num_entries; + info->ce_info[i].srng_info.entry_size = srng_info->entry_size; + info->ce_info[i].srng_info.ring_base_paddr = + srng_info->ring_base_paddr; + info->ce_info[i].srng_info.hp_paddr = srng_info->hp_paddr; + info->ce_info[i].srng_info.tp_paddr = srng_info->tp_paddr; + + dl_wfds->iommu_cfg.direct_link_srng_ring_base_paddr[i] = + srng_info->ring_base_paddr; + dl_wfds->iommu_cfg.direct_link_srng_ring_map_size[i] = + srng_info->entry_size * srng_info->num_entries * 4; + + pld_audio_smmu_map(qdf_dev->dev, + qdf_mem_paddr_from_dmaaddr(qdf_dev, + srng_info->ring_base_paddr), + srng_info->ring_base_paddr, + dl_wfds->iommu_cfg.direct_link_srng_ring_map_size[i]); + } + + refill_ring = direct_link_ctx->direct_link_refill_ring_hdl->hal_srng; + hal_get_srng_params(hal_soc, refill_ring, &srng_params); + info->rx_refill_ring.ring_id = srng_params.ring_id; + info->rx_refill_ring.dir = + (srng_params.ring_dir == HAL_SRNG_SRC_RING) ? + QMI_WFDS_SRNG_SOURCE_RING : QMI_WFDS_SRNG_DESTINATION_RING; + info->rx_refill_ring.num_entries = srng_params.num_entries; + info->rx_refill_ring.entry_size = srng_params.entry_size; + info->rx_refill_ring.ring_base_paddr = srng_params.ring_base_paddr; + + dl_wfds->iommu_cfg.direct_link_refill_ring_base_paddr = srng_params.ring_base_paddr; + dl_wfds->iommu_cfg.direct_link_refill_ring_map_size = + srng_params.entry_size * srng_params.num_entries * 4; + + pld_audio_smmu_map(qdf_dev->dev, + qdf_mem_paddr_from_dmaaddr(qdf_dev, + srng_params.ring_base_paddr), + srng_params.ring_base_paddr, + dl_wfds->iommu_cfg.direct_link_refill_ring_map_size); + + info->rx_refill_ring.hp_paddr = + hal_srng_get_hp_addr(hal_soc, refill_ring); + info->rx_refill_ring.tp_paddr = + hal_srng_get_tp_addr(hal_soc, refill_ring); + + info->rx_pkt_tlv_len = dp_soc->rx_pkt_tlv_size; + info->rx_rbm = dp_rx_get_rx_bm_id(dp_soc); + info->pci_slot = pld_get_pci_slot(qdf_dev->dev); + qdf_assert(info.pci_slot >= 0); + info->lpass_ep_id = direct_link_ctx->lpass_ep_id; + + status = wlan_qmi_wfds_send_config_msg(direct_link_ctx->dp_ctx->psoc, + info); + qdf_mem_free(info); + + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Configuration message send failed %d", status); + return status; + } + + qdf_atomic_set(&dl_wfds->wfds_state, + DP_WFDS_SVC_CONFIG_DONE); + + return status; +} + +/** + * dp_wfds_req_mem_msg() - Send Request Memory message to QMI server + * @dl_wfds: Direct Link QMI context + * + * Return: QDF status + */ +static QDF_STATUS +dp_wfds_req_mem_msg(struct dp_direct_link_wfds_context *dl_wfds) +{ + struct wlan_qmi_wfds_mem_req_msg *info; + struct dp_soc *dp_soc = + wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc); + struct hif_opaque_softc *hif_ctx; + qdf_device_t qdf_dev; + QDF_STATUS status; + struct qdf_mem_multi_page_t *pages; + uint16_t num_pages; + uint8_t i; + + qdf_dev = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + + if (!dl_wfds || !dp_soc || !dp_soc->hif_handle || !qdf_dev) + return QDF_STATUS_E_NOSUPPORT; + + hif_ctx = dp_soc->hif_handle; + + info = qdf_mem_malloc(sizeof(*info)); + if (!info) + return QDF_STATUS_E_NOMEM; + + info->mem_arena_page_info_len = dl_wfds->num_mem_arenas; + for (i = 0; i < dl_wfds->num_mem_arenas; i++) { + if (i == QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS) { + uint64_t *dma_addr = NULL; + uint32_t buf_size; + + num_pages = + hif_get_direct_link_ce_dest_srng_buffers(hif_ctx, + &dma_addr, + &buf_size); + qdf_assert(dma_addr); + + info->mem_arena_page_info[i].num_entries_per_page = + qdf_page_size / buf_size; + info->mem_arena_page_info[i].page_dma_addr_len = + num_pages; + while (num_pages--) { + info->mem_arena_page_info[i].page_dma_addr[num_pages] = + dma_addr[num_pages]; + pld_audio_smmu_map(qdf_dev->dev, + qdf_mem_paddr_from_dmaaddr(qdf_dev, dma_addr[num_pages]), + dma_addr[num_pages], + buf_size); + } + + qdf_mem_free(dma_addr); + continue; + } + + num_pages = dl_wfds->mem_arena_pages[i].num_pages; + pages = &dl_wfds->mem_arena_pages[i]; + + info->mem_arena_page_info[i].num_entries_per_page = + dl_wfds->mem_arena_pages[i].num_element_per_page; + info->mem_arena_page_info[i].page_dma_addr_len = num_pages; + + while (num_pages--) { + info->mem_arena_page_info[i].page_dma_addr[num_pages] = + pages->dma_pages[num_pages].page_p_addr; + + pld_audio_smmu_map(qdf_dev->dev, + qdf_mem_paddr_from_dmaaddr(qdf_dev, pages->dma_pages[num_pages].page_p_addr), + pages->dma_pages[num_pages].page_p_addr, + pages->page_size); + } + } + + status = wlan_qmi_wfds_send_req_mem_msg( + dl_wfds->direct_link_ctx->dp_ctx->psoc, + info); + qdf_mem_free(info); + + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Memory request message send failed %d", status); + return status; + } + + qdf_atomic_set(&dl_wfds->wfds_state, + DP_WFDS_SVC_MEM_CONFIG_DONE); + + return status; +} + +/** + * dp_wfds_ipcc_map_n_cfg_msg() - Send the IPCC map and configure message + * to QMI server + * @dlink_wfds: Direct Link QMI context + * + * Return: QDF status + */ +static QDF_STATUS +dp_wfds_ipcc_map_n_cfg_msg(struct dp_direct_link_wfds_context *dlink_wfds) +{ + struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg info = {0}; + QDF_STATUS status; + + info.status = QMI_WFDS_STATUS_SUCCESS; + + status = wlan_qmi_wfds_ipcc_map_n_cfg_msg( + dlink_wfds->direct_link_ctx->dp_ctx->psoc, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("IPCC map n cfg message send failed %d", status); + return status; + } + + qdf_atomic_set(&dlink_wfds->wfds_state, + DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE); + + return status; +} + +/** + * dp_wfds_work() - DP WFDS work handler + * @arg: direct link QMI context + * + * Return: None + */ +static void dp_wfds_work(void *arg) +{ + struct dp_direct_link_wfds_context *dl_wfds = arg; + struct dp_wfds_event *wfds_evt; + + dp_debug("entry"); + + qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock); + while ((wfds_evt = + qdf_list_first_entry_or_null(&dl_wfds->wfds_event_list, + struct dp_wfds_event, + list_node))) { + qdf_list_remove_node(&dl_wfds->wfds_event_list, + &wfds_evt->list_node); + qdf_spinlock_release(&dl_wfds->wfds_event_list_lock); + + switch (wfds_evt->wfds_evt_type) { + case DP_WFDS_NEW_SERVER: + dp_wfds_send_config_msg(dl_wfds); + break; + case DP_WFDS_MEM_REQ: + dp_wfds_req_mem_msg(dl_wfds); + break; + case DP_WFDS_IPCC_MAP_N_CFG: + dp_wfds_ipcc_map_n_cfg_msg(dl_wfds); + break; + default: + break; + } + + qdf_mem_free(wfds_evt); + + qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock); + } + qdf_spinlock_release(&dl_wfds->wfds_event_list_lock); + + dp_debug("exit"); +} + +/** + * dp_wfds_event_post() - Post WFDS event to be processed in worker context + * @dl_wfds: Direct Link QMI context + * @wfds_evt_type: QMI event type + * @data: pointer to QMI data + * + * Return: QDF status + */ +static QDF_STATUS +dp_wfds_event_post(struct dp_direct_link_wfds_context *dl_wfds, + enum dp_wfds_event_type wfds_evt_type, void *data) +{ + struct dp_wfds_event *wfds_evt; + + wfds_evt = qdf_mem_malloc(sizeof(*wfds_evt)); + if (!wfds_evt) + return QDF_STATUS_E_NOMEM; + + wfds_evt->wfds_evt_type = wfds_evt_type; + wfds_evt->data = data; + + qdf_spinlock_acquire(&dl_wfds->wfds_event_list_lock); + qdf_list_insert_back(&dl_wfds->wfds_event_list, + &wfds_evt->list_node); + qdf_spinlock_release(&dl_wfds->wfds_event_list_lock); + + qdf_queue_work(0, dl_wfds->wfds_wq, &dl_wfds->wfds_work); + + return QDF_STATUS_SUCCESS; +} + +#ifdef DP_MEM_PRE_ALLOC +/** + * dp_wfds_get_desc_type_from_mem_arena() - Get descriptor type for the memory + * arena + * @mem_arena: memory arena + * + * Return: DP descriptor type + */ +static uint32_t +dp_wfds_get_desc_type_from_mem_arena(enum wlan_qmi_wfds_mem_arenas mem_arena) +{ + switch (mem_arena) { + case QMI_WFDS_MEM_ARENA_TX_BUFFERS: + return QDF_DP_TX_DIRECT_LINK_BUF_TYPE; + case QMI_WFDS_MEM_ARENA_CE_TX_MSG_BUFFERS: + return QDF_DP_TX_DIRECT_LINK_CE_BUF_TYPE; + default: + dp_debug("No desc type for mem arena %d", mem_arena); + qdf_assert(0); + return QDF_DP_DESC_TYPE_MAX; + } +} + +/** + * dp_wfds_alloc_mem_arena() - Allocate memory for the arena + * @dl_wfds: Direct Link QMI context + * @mem_arena: memory arena + * @entry_size: element size + * @num_entries: number of elements + * + * Return: None + */ +static void +dp_wfds_alloc_mem_arena(struct dp_direct_link_wfds_context *dl_wfds, + enum wlan_qmi_wfds_mem_arenas mem_arena, + uint16_t entry_size, uint16_t num_entries) +{ + qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + uint32_t desc_type; + + desc_type = dp_wfds_get_desc_type_from_mem_arena(mem_arena); + + if (desc_type != QDF_DP_DESC_TYPE_MAX) + dp_prealloc_get_multi_pages(desc_type, entry_size, + num_entries, + &dl_wfds->mem_arena_pages[mem_arena], + false); + + if (!dl_wfds->mem_arena_pages[mem_arena].num_pages) + qdf_mem_multi_pages_alloc(qdf_ctx, + &dl_wfds->mem_arena_pages[mem_arena], + entry_size, num_entries, 0, false); +} + +/** + * dp_wfds_free_mem_arena() - Free memory for the arena + * @dl_wfds: Direct Link QMI context + * @mem_arena: memory arena + * + * Return: None + */ +static void +dp_wfds_free_mem_arena(struct dp_direct_link_wfds_context *dl_wfds, + enum wlan_qmi_wfds_mem_arenas mem_arena) +{ + qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + uint32_t desc_type; + + if (dl_wfds->mem_arena_pages[mem_arena].is_mem_prealloc) { + desc_type = dp_wfds_get_desc_type_from_mem_arena(mem_arena); + dp_prealloc_put_multi_pages(desc_type, + &dl_wfds->mem_arena_pages[mem_arena]); + } else { + qdf_mem_multi_pages_free(qdf_ctx, + &dl_wfds->mem_arena_pages[mem_arena], + 0, false); + } +} +#else +static void +dp_wfds_alloc_mem_arena(struct dp_direct_link_wfds_context *dl_wfds, + enum wlan_qmi_wfds_mem_arenas mem_arena, + uint16_t entry_size, uint16_t num_entries) +{ + qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + + qdf_mem_multi_pages_alloc(qdf_ctx, + &dl_wfds->mem_arena_pages[mem_arena], + entry_size, num_entries, 0, false); +} + +static void +dp_wfds_free_mem_arena(struct dp_direct_link_wfds_context *dl_wfds, + enum wlan_qmi_wfds_mem_arenas mem_arena) +{ + qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + + qdf_mem_multi_pages_free(qdf_ctx, + &dl_wfds->mem_arena_pages[mem_arena], + 0, false); +} +#endif + +void +dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg) +{ + struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx; + uint8_t i; + + if (!dl_wfds) + return; + + dp_debug("Received request mem indication from QMI server"); + + dl_wfds->num_mem_arenas = mem_msg->mem_arena_info_len; + dl_wfds->mem_arena_pages = + qdf_mem_malloc(sizeof(*dl_wfds->mem_arena_pages) * + mem_msg->mem_arena_info_len); + if (!dl_wfds->mem_arena_pages) + return; + + for (i = 0; i < dl_wfds->num_mem_arenas; i++) { + if (i == QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS) + continue; + + dp_wfds_alloc_mem_arena(dl_wfds, i, + mem_msg->mem_arena_info[i].entry_size, + mem_msg->mem_arena_info[i].num_entries); + + if (!dl_wfds->mem_arena_pages[i].num_pages) { + while (--i >= 0 && + dl_wfds->mem_arena_pages[i].num_pages) + dp_wfds_free_mem_arena(dl_wfds, i); + + qdf_mem_free(dl_wfds->mem_arena_pages); + dl_wfds->mem_arena_pages = NULL; + dl_wfds->num_mem_arenas = 0; + + return; + } + } + + dp_wfds_event_post(dl_wfds, DP_WFDS_MEM_REQ, NULL); +} + +void +dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg) +{ + struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx; + qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + struct dp_soc *dp_soc = + wlan_psoc_get_dp_handle(dl_wfds->direct_link_ctx->dp_ctx->psoc); + struct hif_opaque_softc *hif_ctx; + uint8_t i; + + if (!dl_wfds || !qdf_ctx || !dp_soc || !dp_soc->hif_handle) + return; + + hif_ctx = dp_soc->hif_handle; + + dp_debug("Received IPCC map n cfg indication from QMI server"); + + /* + * IPCC Address for all the CE srngs will be the same and only the + * IPCC data will differ. + */ + pld_smmu_map(qdf_ctx->dev, ipcc_msg->ipcc_ce_info[0].ipcc_trig_addr, + &dl_wfds->ipcc_dma_addr, sizeof(uint32_t)); + + dl_wfds->ipcc_ce_id_len = ipcc_msg->ipcc_ce_info_len; + + for (i = 0; i < ipcc_msg->ipcc_ce_info_len; i++) { + dl_wfds->ipcc_ce_id[i] = ipcc_msg->ipcc_ce_info[i].ce_id; + hif_set_irq_config_by_ceid(hif_ctx, + ipcc_msg->ipcc_ce_info[i].ce_id, + dl_wfds->ipcc_dma_addr, + ipcc_msg->ipcc_ce_info[i].ipcc_trig_data); + } + + dp_wfds_event_post(dl_wfds, DP_WFDS_IPCC_MAP_N_CFG, NULL); +} + +QDF_STATUS dp_wfds_new_server(void) +{ + struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx; + void *htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + + if (!dl_wfds || !htc_handle) + return QDF_STATUS_E_INVAL; + + qdf_atomic_set(&dl_wfds->wfds_state, DP_WFDS_SVC_CONNECTED); + + htc_vote_link_up(htc_handle, HTC_LINK_VOTE_DIRECT_LINK_USER_ID); + dp_debug("Connected to WFDS QMI service, state: 0x%x", + qdf_atomic_read(&dl_wfds->wfds_state)); + + return dp_wfds_event_post(dl_wfds, DP_WFDS_NEW_SERVER, NULL); +} + +void dp_wfds_del_server(void) +{ + struct dp_direct_link_wfds_context *dl_wfds = gp_dl_wfds_ctx; + qdf_device_t qdf_ctx = dl_wfds->direct_link_ctx->dp_ctx->qdf_dev; + void *htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + enum dp_wfds_state dl_wfds_state; + uint8_t i; + uint16_t page_idx; + + if (!dl_wfds || !qdf_ctx || !hif_ctx || !htc_handle) + return; + + dp_debug("WFDS QMI server exiting"); + + dl_wfds_state = qdf_atomic_read(&dl_wfds->wfds_state); + qdf_atomic_set(&dl_wfds->wfds_state, + DP_WFDS_SVC_DISCONNECTED); + + if (dl_wfds_state >= DP_WFDS_SVC_IPCC_MAP_N_CFG_DONE && + dl_wfds->ipcc_dma_addr) { + for (i = 0; i < dl_wfds->ipcc_ce_id_len; i++) + hif_set_irq_config_by_ceid(hif_ctx, + dl_wfds->ipcc_ce_id[i], + 0, 0); + + pld_smmu_unmap(qdf_ctx->dev, dl_wfds->ipcc_dma_addr, + sizeof(uint32_t)); + } + + if (dl_wfds_state >= DP_WFDS_SVC_MEM_CONFIG_DONE) { + uint64_t *dma_addr = NULL; + uint16_t num_pages; + uint32_t buf_size; + + for (i = 0; i < dl_wfds->num_mem_arenas; i++) { + struct qdf_mem_multi_page_t *mp_info; + + if (!dl_wfds->mem_arena_pages[i].num_pages) + continue; + + mp_info = &dl_wfds->mem_arena_pages[i]; + for (page_idx = 0; page_idx < mp_info->num_pages; + page_idx++) + pld_audio_smmu_unmap(qdf_ctx->dev, + mp_info->dma_pages[page_idx].page_p_addr, + mp_info->page_size); + + dp_wfds_free_mem_arena(dl_wfds, i); + } + + qdf_mem_free(dl_wfds->mem_arena_pages); + dl_wfds->mem_arena_pages = NULL; + dl_wfds->num_mem_arenas = 0; + + num_pages = hif_get_direct_link_ce_dest_srng_buffers(hif_ctx, + &dma_addr, + &buf_size); + qdf_assert(dma_addr); + + while (num_pages--) + pld_audio_smmu_unmap(qdf_ctx->dev, dma_addr[num_pages], + buf_size); + + qdf_mem_free(dma_addr); + } + + if (dl_wfds_state >= DP_WFDS_SVC_CONFIG_DONE) { + pld_audio_smmu_unmap(qdf_ctx->dev, + dl_wfds->iommu_cfg.shadow_rdptr_paddr, + dl_wfds->iommu_cfg.shadow_rdptr_map_size); + pld_audio_smmu_unmap(qdf_ctx->dev, + dl_wfds->iommu_cfg.shadow_wrptr_paddr, + dl_wfds->iommu_cfg.shadow_wrptr_map_size); + + for (i = 0; i < QMI_WFDS_CE_MAX_SRNG; i++) + pld_audio_smmu_unmap(qdf_ctx->dev, + dl_wfds->iommu_cfg.direct_link_srng_ring_base_paddr[i], + dl_wfds->iommu_cfg.direct_link_srng_ring_map_size[i]); + + pld_audio_smmu_unmap(qdf_ctx->dev, + dl_wfds->iommu_cfg.direct_link_refill_ring_base_paddr, + dl_wfds->iommu_cfg.direct_link_refill_ring_map_size); + } + + htc_vote_link_down(htc_handle, HTC_LINK_VOTE_DIRECT_LINK_USER_ID); +} + +QDF_STATUS dp_wfds_init(struct dp_direct_link_context *dp_direct_link_ctx) +{ + struct dp_direct_link_wfds_context *dl_wfds; + QDF_STATUS status; + + dl_wfds = qdf_mem_malloc(sizeof(*dl_wfds)); + if (!dl_wfds) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + qdf_spinlock_create(&dl_wfds->wfds_event_list_lock); + qdf_list_create(&dl_wfds->wfds_event_list, 0); + + status = qdf_create_work(0, &dl_wfds->wfds_work, + dp_wfds_work, dl_wfds); + if (status != QDF_STATUS_SUCCESS) { + dp_err("DP QMI work create failed"); + goto wfds_work_create_fail; + } + + dl_wfds->wfds_wq = qdf_alloc_unbound_workqueue("dp_wfds_wq"); + if (!dl_wfds->wfds_wq) { + dp_err("DP QMI workqueue allocate failed"); + goto wfds_wq_alloc_fail; + } + + qdf_atomic_set(&dl_wfds->wfds_state, + DP_WFDS_SVC_DISCONNECTED); + + status = wlan_qmi_wfds_init(dp_direct_link_ctx->dp_ctx->psoc); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("WFDS QMI initialization failed %d", status); + goto qmi_wfds_init_fail; + } + + dp_direct_link_ctx->dl_wfds = dl_wfds; + dl_wfds->direct_link_ctx = dp_direct_link_ctx; + gp_dl_wfds_ctx = dl_wfds; + dp_debug("WFDS QMI init successful"); + + return status; + +qmi_wfds_init_fail: + qdf_flush_workqueue(0, dl_wfds->wfds_wq); + qdf_destroy_workqueue(0, dl_wfds->wfds_wq); + +wfds_wq_alloc_fail: + qdf_flush_work(&dl_wfds->wfds_work); + qdf_destroy_work(0, &dl_wfds->wfds_work); + +wfds_work_create_fail: + qdf_spinlock_destroy(&dl_wfds->wfds_event_list_lock); + qdf_list_destroy(&dl_wfds->wfds_event_list); + qdf_mem_free(dl_wfds); + +out: + return status; +} + +void dp_wfds_deinit(struct dp_direct_link_context *dp_direct_link_ctx, + bool is_ssr) +{ + struct dp_direct_link_wfds_context *dl_wfds; + + if (!dp_direct_link_ctx) + return; + + dl_wfds = dp_direct_link_ctx->dl_wfds; + + dp_debug("WFDS QMI deinit"); + + qdf_flush_workqueue(0, dl_wfds->wfds_wq); + qdf_destroy_workqueue(0, dl_wfds->wfds_wq); + + qdf_flush_work(&dl_wfds->wfds_work); + qdf_destroy_work(0, &dl_wfds->wfds_work); + + qdf_spinlock_destroy(&dl_wfds->wfds_event_list_lock); + qdf_list_destroy(&dl_wfds->wfds_event_list); + + if (qdf_atomic_read(&dl_wfds->wfds_state) != + DP_WFDS_SVC_DISCONNECTED) + wlan_qmi_wfds_send_misc_req_msg(dp_direct_link_ctx->dp_ctx->psoc, + is_ssr); + + wlan_qmi_wfds_deinit(dp_direct_link_ctx->dp_ctx->psoc); + gp_dl_wfds_ctx = NULL; + + qdf_mem_free(dl_wfds); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_api.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_api.h new file mode 100644 index 0000000000..55159ba428 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_api.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_dp_api.h + * + */ + +#if !defined(_WLAN_DP_API_H_) +#define _WLAN_DP_API_H_ + +#include + +/** + * wlan_dp_update_peer_map_unmap_version() - update peer map unmap version + * @version: Peer map unmap version pointer to be updated + * + * Return: None + */ +void wlan_dp_update_peer_map_unmap_version(uint8_t *version); + +/** + * wlan_dp_runtime_suspend() - Runtime suspend DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dp_runtime_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * wlan_dp_runtime_resume() - Runtime suspend DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dp_runtime_resume(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * wlan_dp_print_fisa_rx_stats() - Dump fisa stats + * @stats_id: ID for the stats to be dumped + * + * Return: None + */ +void wlan_dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id); + +/** + * wlan_dp_set_fst_in_cmem() - Set flag to indicate FST is in CMEM + * @fst_in_cmem: Flag to indicate FST is in CMEM + * + * Return: None + */ +void wlan_dp_set_fst_in_cmem(bool fst_in_cmem); + +/** + * wlan_dp_set_fisa_dynamic_aggr_size_support - Set flag to indicate dynamic + * MSDU aggregation size programming supported + * @dynamic_aggr_size_support: Flag to indicate dynamic aggregation size support + * + * Return: None + */ +void wlan_dp_set_fisa_dynamic_aggr_size_support(bool dynamic_aggr_size_support); + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +/** + * wlan_dp_is_local_pkt_capture_active() - Get local packet capture config + * @psoc: pointer to psoc object + * + * Return: true if local packet capture is active, false otherwise + */ +bool +wlan_dp_is_local_pkt_capture_active(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +wlan_dp_is_local_pkt_capture_active(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /* WLAN_FEATURE_LOCAL_PKT_CAPTURE */ + +/** + * wlan_dp_update_def_link() - update DP interface default link + * @psoc: psoc handle + * @intf_mac: interface MAC address + * @vdev: objmgr vdev handle to set the def_link in dp_intf + * + */ +void wlan_dp_update_def_link(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_mac, + struct wlan_objmgr_vdev *vdev); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_cfg.h new file mode 100644 index 0000000000..547ccdb4b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_cfg.h @@ -0,0 +1,1364 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_DP_CFG_H__ +#define WLAN_DP_CFG_H__ + +#define CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST_LEN 30 + +#ifdef CONFIG_DP_TRACE +/* Max length of gDptraceConfig string. e.g.- "1, 6, 1, 62" */ +#define DP_TRACE_CONFIG_STRING_LENGTH (20) + +/* At max 4 DP Trace config parameters are allowed. Refer - gDptraceConfig */ +#define DP_TRACE_CONFIG_NUM_PARAMS (4) + +/* + * Default value of live mode in case it cannot be determined from cfg string + * gDptraceConfig + */ +#define DP_TRACE_CONFIG_DEFAULT_LIVE_MODE (1) + +/* + * Default value of thresh (packets/second) beyond which DP Trace is disabled. + * Use this default in case the value cannot be determined from cfg string + * gDptraceConfig + */ +#define DP_TRACE_CONFIG_DEFAULT_THRESH (6) + +/* + * Number of intervals of BW timer to wait before enabling/disabling DP Trace. + * Since throughput threshold to disable live logging for DP Trace is very low, + * we calculate throughput based on # packets received in a second. + * For example assuming bandwidth timer interval is 100ms, and if more than 6 + * prints are received in 10 * 100 ms interval, we want to disable DP Trace + * live logging. DP_TRACE_CONFIG_DEFAULT_THRESH_TIME_LIMIT is the default + * value, to be used in case the real value cannot be derived from + * bw timer interval + */ +#define DP_TRACE_CONFIG_DEFAULT_THRESH_TIME_LIMIT (10) + +/* Default proto bitmap in case its missing in gDptraceConfig string */ +#define DP_TRACE_CONFIG_DEFAULT_BITMAP \ + (QDF_NBUF_PKT_TRAC_TYPE_EAPOL |\ + QDF_NBUF_PKT_TRAC_TYPE_DHCP |\ + QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION |\ + QDF_NBUF_PKT_TRAC_TYPE_ARP |\ + QDF_NBUF_PKT_TRAC_TYPE_ICMP |\ + QDF_NBUF_PKT_TRAC_TYPE_ICMPv6)\ + +/* Default verbosity, in case its missing in gDptraceConfig string*/ +#define DP_TRACE_CONFIG_DEFAULT_VERBOSTY QDF_DP_TRACE_VERBOSITY_LOW + +#endif + +#define CFG_ENABLE_RX_THREAD BIT(0) +#define CFG_ENABLE_RPS BIT(1) +#define CFG_ENABLE_NAPI BIT(2) +#define CFG_ENABLE_DYNAMIC_RPS BIT(3) +#define CFG_ENABLE_DP_RX_THREADS BIT(4) +#define CFG_RX_MODE_MAX (CFG_ENABLE_RX_THREAD | \ + CFG_ENABLE_RPS | \ + CFG_ENABLE_NAPI | \ + CFG_ENABLE_DYNAMIC_RPS | \ + CFG_ENABLE_DP_RX_THREADS) +#ifdef MDM_PLATFORM +#define CFG_RX_MODE_DEFAULT 0 +#elif defined(HELIUMPLUS) +#define CFG_RX_MODE_DEFAULT CFG_ENABLE_NAPI +#endif + +#ifndef CFG_RX_MODE_DEFAULT +#if defined(FEATURE_WLAN_DP_RX_THREADS) +#define CFG_RX_MODE_DEFAULT (CFG_ENABLE_DP_RX_THREADS | CFG_ENABLE_NAPI) +#else +#define CFG_RX_MODE_DEFAULT (CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI) +#endif +#endif + +/* Max # of packets to be processed in 1 tx comp loop */ +#define CFG_DP_TX_COMP_LOOP_PKT_LIMIT_DEFAULT 64 +#define CFG_DP_TX_COMP_LOOP_PKT_LIMIT_MAX (1024 * 1024) + +/*Max # of packets to be processed in 1 rx reap loop */ +#define CFG_DP_RX_REAP_LOOP_PKT_LIMIT_DEFAULT 64 +#define CFG_DP_RX_REAP_LOOP_PKT_LIMIT_MAX (1024 * 1024) + +/* Max # of HP OOS (out of sync) updates */ +#define CFG_DP_RX_HP_OOS_UPDATE_LIMIT_DEFAULT 0 +#define CFG_DP_RX_HP_OOS_UPDATE_LIMIT_MAX 1024 + +/* Max Yield time duration for RX Softirq */ +#define CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_DEFAULT (500 * 1000) +#define CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_MAX (10 * 1000 * 1000) + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +/* + * + * gBusBandwidthSuperHighThreshold - bus bandwidth super high threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 22000 + * + * This ini specifies the bus bandwidth super high threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_SUPER_HIGH_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthSuperHighThreshold", \ + 0, \ + 4294967295UL, \ + 22000, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth super high threshold") + +/* + * + * gBusBandwidthUltraHighThreshold - bus bandwidth ultra high threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 12000 + * + * This ini specifies the bus bandwidth very high threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_ULTRA_HIGH_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthUltraHighThreshold", \ + 0, \ + 4294967295UL, \ + 12000, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth ultra high threshold") + +/* + * + * gBusBandwidthVeryHighThreshold - bus bandwidth very high threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 10000 + * + * This ini specifies the bus bandwidth very high threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_VERY_HIGH_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthVeryHighThreshold", \ + 0, \ + 4294967295UL, \ + 10000, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth very high threshold") + +/* + * + * gBusBandwidthMidHighThreshold - bus bandwidth high HE cases threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini specifies the bus bandwidth high HE cases threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_MID_HIGH_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthMidHighThreshold", \ + 0, \ + 4294967295UL, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth high threshold") + +/* + * + * gBusBandwidthDBSThreshold - bus bandwidth for DBS mode threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 6000 + * + * This ini specifies the bus bandwidth high threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_DBS_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthDBSThreshold", \ + 0, \ + 4294967295UL, \ + 6000, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth DBS mode threshold") +/* + * + * gBusBandwidthHighThreshold - bus bandwidth high threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini specifies the bus bandwidth high threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_HIGH_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthHighThreshold", \ + 0, \ + 4294967295UL, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth high threshold") + +/* + * + * gBusBandwidthMediumThreshold - bus bandwidth medium threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 500 + * + * This ini specifies the bus bandwidth medium threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_MEDIUM_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthMediumThreshold", \ + 0, \ + 4294967295UL, \ + 500, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth medium threshold") + +/* + * + * gBusBandwidthLowThreshold - bus bandwidth low threshold + * + * @Min: 0 + * @Max: 4294967295UL + * @Default: 150 + * + * This ini specifies the bus bandwidth low threshold + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_LOW_THRESHOLD \ + CFG_INI_UINT( \ + "gBusBandwidthLowThreshold", \ + 0, \ + 4294967295UL, \ + 150, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth low threshold") + +/* + * + * gBusBandwidthComputeInterval - bus bandwidth compute interval + * + * @Min: 0 + * @Max: 10000 + * @Default: 100 + * + * This ini specifies thebus bandwidth compute interval + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_BANDWIDTH_COMPUTE_INTERVAL \ + CFG_INI_UINT( \ + "gBusBandwidthComputeInterval", \ + 0, \ + 10000, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "Bus bandwidth compute interval") + +/* + * + * gTcpLimitOutputEnable - Control to enable TCP limit output byte + * @Default: true + * + * This ini is used to enable dynamic configuration of TCP limit output bytes + * tcp_limit_output_bytes param. Enabling this will let driver post message to + * cnss-daemon, accordingly cnss-daemon will modify the tcp_limit_output_bytes. + * + * Supported Feature: Tcp limit output bytes + * + * Usage: Internal + * + * + */ +#define CFG_DP_ENABLE_TCP_LIMIT_OUTPUT \ + CFG_INI_BOOL( \ + "gTcpLimitOutputEnable", \ + true, \ + "Control to enable TCP limit output byte") + +/* + * + * gTcpAdvWinScaleEnable - Control to enable TCP adv window scaling + * @Default: true + * + * This ini is used to enable dynamic configuration of TCP adv window scaling + * system parameter. + * + * Supported Feature: Tcp Advance Window Scaling + * + * Usage: Internal + * + * + */ +#define CFG_DP_ENABLE_TCP_ADV_WIN_SCALE \ + CFG_INI_BOOL( \ + "gTcpAdvWinScaleEnable", \ + true, \ + "Control to enable TCP adv window scaling") + +/* + * + * gTcpDelAckEnable - Control to enable Dynamic Configuration of Tcp Delayed Ack + * @Default: true + * + * This ini is used to enable Dynamic Configuration of Tcp Delayed Ack + * + * Related: gTcpDelAckThresholdHigh, gTcpDelAckThresholdLow, + * gTcpDelAckTimerCount + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_DP_ENABLE_TCP_DELACK \ + CFG_INI_BOOL( \ + "gTcpDelAckEnable", \ + true, \ + "Control to enable Dynamic Config of Tcp Delayed Ack") + +/* + * + * gTcpDelAckThresholdHigh - High Threshold inorder to trigger TCP Del Ack + * indication + * @Min: 0 + * @Max: 16000 + * @Default: 500 + * + * This ini is used to mention the High Threshold inorder to trigger TCP Del Ack + * indication i.e the threshold of packets received over a period of 100 ms. + * i.e to have a low RX throughput requirement + * Related: gTcpDelAckEnable, gTcpDelAckThresholdLow, gTcpDelAckTimerCount + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_DP_TCP_DELACK_THRESHOLD_HIGH \ + CFG_INI_UINT( \ + "gTcpDelAckThresholdHigh", \ + 0, \ + 16000, \ + 500, \ + CFG_VALUE_OR_DEFAULT, \ + "High Threshold inorder to trigger TCP Del Ack") + +/* + * + * gTcpDelAckThresholdLow - Low Threshold inorder to trigger TCP Del Ack + * indication + * @Min: 0 + * @Max: 10000 + * @Default: 1000 + * + * This ini is used to mention the Low Threshold inorder to trigger TCP Del Ack + * indication i.e the threshold of packets received over a period of 100 ms. + * i.e to have a low RX throughput requirement + * + * Related: gTcpDelAckEnable, gTcpDelAckThresholdHigh, gTcpDelAckTimerCount + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_DP_TCP_DELACK_THRESHOLD_LOW \ + CFG_INI_UINT( \ + "gTcpDelAckThresholdLow", \ + 0, \ + 10000, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "Low Threshold inorder to trigger TCP Del Ack") + +/* + * + * gTcpDelAckTimerCount - Del Ack Timer Count inorder to trigger TCP Del Ack + * indication + * @Min: 1 + * @Max: 1000 + * @Default: 30 + * + * This ini is used to mention the Del Ack Timer Count inorder to + * trigger TCP Del Ack indication i.e number of 100 ms periods + * + * Related: gTcpDelAckEnable, gTcpDelAckThresholdHigh, gTcpDelAckThresholdLow + * + * Supported Feature: Tcp Delayed Ack + * + * Usage: Internal + * + * + */ +#define CFG_DP_TCP_DELACK_TIMER_COUNT \ + CFG_INI_UINT( \ + "gTcpDelAckTimerCount", \ + 1, \ + 1000, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "Del Ack Timer Count inorder to trigger TCP Del Ack") + +/* + * + * gTcpTxHighTputThreshold - High Threshold inorder to trigger High + * Tx Throughput requirement. + * @Min: 0 + * @Max: 16000 + * @Default: 500 + * + * This ini specifies the threshold of packets transmitted + * over a period of 100 ms beyond which TCP can be considered to have a high + * TX throughput requirement. The driver uses this condition to tweak TCP TX + * specific parameters (via cnss-daemon) + * + * Supported Feature: To tweak TCP TX n/w parameters + * + * Usage: Internal + * + * + */ +#define CFG_DP_TCP_TX_HIGH_TPUT_THRESHOLD \ + CFG_INI_UINT( \ + "gTcpTxHighTputThreshold", \ + 0, \ + 16000, \ + 500, \ + CFG_VALUE_OR_DEFAULT, \ + "High Threshold inorder to trigger High Tx Tp") + +/* + * + * gBusLowTputCntThreshold - Threshold count to trigger low Tput + * GRO flush skip + * @Min: 0 + * @Max: 200 + * @Default: 10 + * + * This ini is a threshold that if count of times for bus Tput level + * PLD_BUS_WIDTH_LOW in bus_bw_timer() >= this threshold, will enable skipping + * GRO flush, current default threshold is 10, then will delay GRO flush-skip + * 1 second for low Tput level. + * + * Supported Feature: GRO flush skip when low T-put + * + * Usage: Internal + * + * + */ +#define CFG_DP_BUS_LOW_BW_CNT_THRESHOLD \ + CFG_INI_UINT( \ + "gBusLowTputCntThreshold", \ + 0, \ + 200, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Threshold to trigger GRO flush skip for low T-put") + +/* + * + * gHandleLatencyCriticalClients - Enable the handling of latency critical + * clients in bus bandwidth timer. + * @Default: false + * + * This ini enables the handling of latency critical clients, eg: 11g/a + * clients, when they are running their corresponding peak throughput. + * + * Supported Feature: Latency critical clients in host + * + * Usage: External + * + * + */ +#define CFG_DP_BUS_HANDLE_LATENCY_CRITICAL_CLIENTS \ + CFG_INI_BOOL( \ + "gHandleLatencyCriticalClients", \ + false, \ + "Control to enable latency critical clients") + +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +/* + * + * gDriverDelAckHighThreshold - High Threshold inorder to trigger TCP + * delay ack feature in the host. + * @Min: 0 + * @Max: 70000 + * @Default: 300 + * + * This ini specifies the threshold of RX packets transmitted + * over a period of 100 ms beyond which TCP delay ack can be enabled + * to improve TCP RX throughput requirement. + * + * Supported Feature: Tcp Delayed Ack in the host + * + * Usage: Internal + * + * + */ +#define CFG_DP_DRIVER_TCP_DELACK_HIGH_THRESHOLD \ + CFG_INI_UINT( \ + "gDriverDelAckHighThreshold", \ + 0, \ + 70000, \ + 300, \ + CFG_VALUE_OR_DEFAULT, \ + "TCP delack high threshold") + +/* + * + * gDriverDelAckLowThreshold - Low Threshold inorder to disable TCP + * delay ack feature in the host. + * @Min: 0 + * @Max: 70000 + * @Default: 100 + * + * This ini is used to mention the Low Threshold inorder to disable TCP Del + * Ack feature in the host. + * + * Supported Feature: Tcp Delayed Ack in the host + * + * Usage: Internal + * + * + */ +#define CFG_DP_DRIVER_TCP_DELACK_LOW_THRESHOLD \ + CFG_INI_UINT( \ + "gDriverDelAckLowThreshold", \ + 0, \ + 70000, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "TCP delack low threshold") + +/* + * + * gDriverDelAckTimerValue - Timeout value (ms) to send out all TCP del + * ack frames + * @Min: 1 + * @Max: 15 + * @Default: 3 + * + * This ini specifies the time out value to send out all pending TCP delay + * ACK frames. + * + * Supported Feature: Tcp Delayed Ack in the host + * + * Usage: Internal + * + * + */ +#define CFG_DP_DRIVER_TCP_DELACK_TIMER_VALUE \ + CFG_INI_UINT( \ + "gDriverDelAckTimerValue", \ + 1, \ + 15, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Send out all TCP Del Acks if time out") + +/* + * + * gDriverDelAckPktCount - The maximum number of TCP delay ack frames + * @Min: 0 + * @Max: 50 + * @Default: 20 + * + * This ini specifies the maximum number of TCP delayed ack frames. + * + * Supported Feature: Tcp Delayed Ack in the host + * + * Usage: Internal + * + * + */ +#define CFG_DP_DRIVER_TCP_DELACK_PKT_CNT \ + CFG_INI_UINT( \ + "gDriverDelAckPktCount", \ + 0, \ + 50, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "No of TCP Del ACK count") + +/* + * + * gDriverDelAckEnable - Control to enable Dynamic Configuration of Tcp + * Delayed Ack in the host. + * @Default: true + * + * This ini is used to enable Dynamic Configuration of Tcp Delayed Ack + * in the host. + * + * Related: gDriverDelAckHighThreshold, gDriverDelAckLowThreshold, + * gDriverDelAckPktCount, gDriverDelAckTimerValue + * + * Supported Feature: Tcp Delayed Ack in the host + * + * Usage: Internal + * + * + */ +#define CFG_DP_DRIVER_TCP_DELACK_ENABLE \ + CFG_INI_BOOL( \ + "gDriverDelAckEnable", \ + true, \ + "Enable tcp del ack in the driver") +#endif + +/* + * + * RX_THREAD_CPU_AFFINITY_MASK - CPU mask to affine Rx_thread + * + * @Min: 0 + * @Max: 0xFF + * @Default: 0x02 + * + * This ini is used to set Rx_thread CPU affinity + * + * Supported Feature: Rx_thread + * + * Usage: Internal + * + * + */ +#ifdef RX_PERFORMANCE +#define CFG_DP_RX_THREAD_CPU_MASK \ + CFG_INI_UINT( \ + "RX_THREAD_CPU_AFFINITY_MASK", \ + 0, \ + 0xFF, \ + 0xFE, \ + CFG_VALUE_OR_DEFAULT, \ + "CPU mask to affine Rx_thread") +#else +#define CFG_DP_RX_THREAD_CPU_MASK \ + CFG_INI_UINT( \ + "RX_THREAD_CPU_AFFINITY_MASK", \ + 0, \ + 0xFF, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "CPU mask to affine Rx_thread") +#endif + +/* + * + * RX_THREAD_UL_CPU_AFFINITY_MASK - CPU mask to affine Rx_thread + * + * @Min: 0 + * @Max: 0xFF + * @Default: 0x0 + * + * This ini is used to set Rx_thread CPU affinity for uplink traffic + * + * Supported Feature: Rx_thread + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_THREAD_UL_CPU_MASK \ + CFG_INI_UINT( \ + "RX_THREAD_UL_CPU_AFFINITY_MASK", \ + 0, \ + 0xFF, \ + 0x0, \ + CFG_VALUE_OR_DEFAULT, \ + "CPU mask to affine Rx_thread for uplink traffic") + +/* + * + * rpsRxQueueCpuMapList - RPS map for different RX queues + * + * @Default: e + * + * This ini is used to set RPS map for different RX queues. + * + * List of RPS CPU maps for different rx queues registered by WLAN driver + * Ref - Kernel/Documentation/networking/scaling.txt + * RPS CPU map for a particular RX queue, selects CPU(s) for bottom half + * processing of RX packets. For example, for a system with 4 CPUs, + * 0xe: Use CPU1 - CPU3 and donot use CPU0. + * 0x0: RPS is disabled, packets are processed on the interrupting CPU. +.* + * WLAN driver registers NUM_TX_QUEUES queues for tx and rx each during + * alloc_netdev_mq. Hence, we need to have a cpu mask for each of the rx queues. + * + * For example, if the NUM_TX_QUEUES is 4, a sample WLAN ini entry may look like + * rpsRxQueueCpuMapList=a b c d + * For a 4 CPU system (CPU0 - CPU3), this implies: + * 0xa - (1010) use CPU1, CPU3 for rx queue 0 + * 0xb - (1011) use CPU0, CPU1 and CPU3 for rx queue 1 + * 0xc - (1100) use CPU2, CPU3 for rx queue 2 + * 0xd - (1101) use CPU0, CPU2 and CPU3 for rx queue 3 + + * In practice, we may want to avoid the cores which are heavily loaded. + * + * Default value of rpsRxQueueCpuMapList. Different platforms may have + * different configurations for NUM_TX_QUEUES and # of cpus, and will need to + * configure an appropriate value via ini file. Setting default value to 'e' to + * avoid use of CPU0 (since its heavily used by other system processes) by rx + * queue 0, which is currently being used for rx packet processing. + * + * Maximum length of string used to hold a list of cpu maps for various rx + * queues. Considering a 16 core system with 5 rx queues, a RPS CPU map + * list may look like - + * rpsRxQueueCpuMapList = ffff ffff ffff ffff ffff + * (all 5 rx queues can be processed on all 16 cores) + * max string len = 24 + 1(for '\0'). Considering 30 to be on safe side. + * + * Supported Feature: Rx_thread + * + * Usage: Internal + * + */ +#define CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST \ + CFG_INI_STRING( \ + "rpsRxQueueCpuMapList", \ + 1, \ + 30, \ + "e", \ + "specify RPS map for different RX queues") + +/* + * + * gEnableTxOrphan- Enable/Disable orphaning of Tx packets + * @Default: false + * + * This ini is used to enable/disable orphaning of Tx packets. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DP_TX_ORPHAN_ENABLE \ + CFG_INI_BOOL( \ + "gEnableTxOrphan", \ + false, \ + "orphaning of Tx packets") + +/* + * + * rx_mode - Control to decide rx mode for packet processing + * + * @Min: 0 + * @Max: (CFG_ENABLE_RX_THREAD | CFG_ENABLE_RPS | CFG_ENABLE_NAPI | \ + * CFG_ENABLE_DYNAMIC_RPS) + * + * Some possible configurations: + * rx_mode=0 - Uses tasklets for bottom half + * CFG_ENABLE_NAPI (rx_mode=4) - Uses NAPI for bottom half + * CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI (rx_mode=5) - NAPI for bottom half, + * rx_thread for stack. Single threaded. + * CFG_ENABLE_DP_RX_THREAD | CFG_ENABLE_NAPI (rx_mode=10) - NAPI for bottom + * half, dp_rx_thread for stack processing. Supports multiple rx threads. + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_MODE \ + CFG_INI_UINT("rx_mode", \ + 0, CFG_RX_MODE_MAX, CFG_RX_MODE_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Control to decide rx mode for packet processing") + +/* + * + * tx_comp_loop_pkt_limit - Control to decide max # of packets to be processed + * in 1 tx comp loop + * + * @Min: 8 + * @Max: CFG_DP_TX_COMP_LOOP_PKT_LIMIT_MAX + * + * Usage: Internal + * + * + */ +#define CFG_DP_TX_COMP_LOOP_PKT_LIMIT \ + CFG_INI_UINT("tx_comp_loop_pkt_limit", \ + 1, CFG_DP_TX_COMP_LOOP_PKT_LIMIT_MAX, \ + CFG_DP_TX_COMP_LOOP_PKT_LIMIT_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Control to decide tx comp loop pkt limit") +/* + * + * rx_reap_loop_pkt_limit - Control to decide max # of packets to be reaped + * in 1 dp_rx_process reap loop + * + * @Min: 8 + * @Max: CFG_DP_RX_REAP_LOOP_PKT_LIMIT_MAX + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_REAP_LOOP_PKT_LIMIT \ + CFG_INI_UINT("rx_reap_loop_pkt_limit", \ + 0, CFG_DP_RX_REAP_LOOP_PKT_LIMIT_MAX, \ + CFG_DP_RX_REAP_LOOP_PKT_LIMIT_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Control to decide rx reap loop packet limit") + +/* + * + * rx_hp_oos_update_limit - Control to decide max # of HP OOS (out of sync) + * updates + * + * @Min: 0 + * @Max: CFG_DP_RX_HP_OOS_UPDATE_LIMIT_MAX + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_HP_OOS_UPDATE_LIMIT \ + CFG_INI_UINT("rx_hp_oos_update_limit", \ + 0, CFG_DP_RX_HP_OOS_UPDATE_LIMIT_MAX, \ + CFG_DP_RX_HP_OOS_UPDATE_LIMIT_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Control to decide HP OOS update limit") + +/* + * + * rx_softirq_max_yield_duration_ns - Control to decide max duration for RX + * softirq + * + * @Min: 100 * 1000 , 100us + * @Max: CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_MAX + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS \ + CFG_INI_UINT("rx_softirq_max_yield_duration_ns", \ + 100 * 1000, CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_MAX, \ + CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "max yield time duration for RX Softirq") + +/* + * + * enable_multicast_replay_filter - Enable filtering of replayed multicast + * packets + * + * In a typical infrastructure setup, it is quite normal to receive + * replayed multicast packets. These packets may cause more harm than + * help if not handled properly. Providing a configuration option + * to enable filtering of such packets + * + * + */ +#define CFG_DP_FILTER_MULTICAST_REPLAY \ + CFG_INI_BOOL("enable_multicast_replay_filter", \ + true, "Enable filtering of replayed multicast packets") + +/* + * + * rx_wakelock_timeout - Amount of time to hold wakelock for RX unicast packets + * @Min: 0 + * @Max: 100 + * @Default: 50 + * + * This ini item configures the amount of time, in milliseconds, that the driver + * should prevent system power collapse after receiving an RX unicast packet. + * A conigured value of 0 disables the RX Wakelock feature completely. + * + * Related: None. + * + * Supported Feature: RX Wakelock + * + * Usage: Internal/External + * + * + */ +#define CFG_DP_RX_WAKELOCK_TIMEOUT \ + CFG_INI_UINT("rx_wakelock_timeout", \ + 0, 100, 50, CFG_VALUE_OR_DEFAULT, \ + "Amount of time to hold wakelock for RX unicast packets") + +/* + * + * num_dp_rx_threads - Control to set the number of dp rx threads + * + * @Min: 1 + * @Max: 4 + * @Default: 1 + * + * Usage: Internal + * + * + */ +#define CFG_DP_NUM_DP_RX_THREADS \ + CFG_INI_UINT("num_dp_rx_threads", \ + 1, 4, 1, CFG_VALUE_OR_DEFAULT, \ + "Control to set the number of dp rx threads") + +/* + * + * ce_service_max_rx_ind_flush - Maximum number of HTT messages + * to be processed per NAPI poll + * + * @Min: 1 + * @Max: 32 + * @Default: 1 + * + * Usage: Internal + * + * + */ +#define CFG_DP_CE_SERVICE_MAX_RX_IND_FLUSH \ + CFG_INI_UINT("ce_service_max_rx_ind_flush", \ + 1, 32, 1, \ + CFG_VALUE_OR_DEFAULT, "Ctrl to set ce service max rx ind flsh") + +/* + * + * ce_service_max_yield_time - Time in microseconds after which + * a NAPI poll must yield + * + * @Min: 500 + * @Max: 10000 + * @Default: 500 + * + * Usage: Internal + * + * + */ +#define CFG_DP_CE_SERVICE_MAX_YIELD_TIME \ + CFG_INI_UINT("ce_service_max_yield_time", \ + 500, 10000, 500, \ + CFG_VALUE_OR_DEFAULT, "Ctrl to set ce service max yield time") + +#ifdef WLAN_FEATURE_FASTPATH +#define CFG_DP_ENABLE_FASTPATH \ + CFG_INI_BOOL("gEnableFastPath", \ + false, "Ctrl to enable fastpath feature") + +#define CFG_DP_ENABLE_FASTPATH_ALL \ + CFG(CFG_DP_ENABLE_FASTPATH) +#else +#define CFG_DP_ENABLE_FASTPATH_ALL +#endif + +#define CFG_DP_ENABLE_TCP_PARAM_UPDATE \ + CFG_INI_BOOL("enable_tcp_param_update", \ + false, "configure TCP param through Wi-Fi HAL") +/* + * + * + * Enable/disable DPTRACE + * Enabling this might have performance impact. + * + * Config DPTRACE + * The sequence of params is important. If some param is missing, defaults are + * considered. + * Param 1: Enable/Disable DP Trace live mode (uint8_t) + * Param 2: DP Trace live mode high bandwidth thresh.(uint8_t) + * (packets/second) beyond which DP Trace is disabled. Decimal Val. + * MGMT, DHCP, EAPOL, ARP pkts are not counted. ICMP and Data are. + * Param 3: Default Verbosity (0-4) + * Param 4: Proto Bitmap (uint8_t). Decimal Value. + * (decimal 62 = 0x3e) + * e.g., to disable live mode, use the following param in the ini file. + * gDptraceConfig = 0 + * e.g., to enable dptrace live mode and set the thresh as 6, + * use the following param in the ini file. + * gDptraceConfig = 1, 6 + * + * + */ +#ifdef CONFIG_DP_TRACE +#define CFG_DP_ENABLE_DP_TRACE \ + CFG_INI_BOOL("enable_dp_trace", \ + true, "Ctrl to enable dp trace feature") + +#define CFG_DP_DP_TRACE_CONFIG \ + CFG_INI_STRING( \ + "gDptraceConfig", \ + 1, \ + 20, \ + "1, 6, 2, 126", \ + "dp trace configuration string") + +/* + * + * dp_proto_event_bitmap - Control for which protocol packet diag event should + * be sent to user space. + * @Min: 0 + * @Max: 0x17 + * @Default: 0x6 + * + * This ini is used to control for which protocol packet diag event should be + * sent to user space. + * + * QDF_NBUF_PKT_TRAC_TYPE_DNS 0x01 + * QDF_NBUF_PKT_TRAC_TYPE_EAPOL 0x02 + * QDF_NBUF_PKT_TRAC_TYPE_DHCP 0x04 + * QDF_NBUF_PKT_TRAC_TYPE_ARP 0x10 + * + * Related: None + * + * Supported Feature: STA, SAP + * + * Usage: Internal + * + * + */ +#define CFG_DP_PROTO_EVENT_BITMAP \ + CFG_INI_UINT("dp_proto_event_bitmap", \ + 0, 0x17, 0x17, \ + CFG_VALUE_OR_DEFAULT, \ + "Control for which protocol type diag log should be sent") + +#define CFG_DP_CONFIG_DP_TRACE_ALL \ + CFG(CFG_DP_ENABLE_DP_TRACE) \ + CFG(CFG_DP_DP_TRACE_CONFIG) \ + CFG(CFG_DP_PROTO_EVENT_BITMAP) +#else +#define CFG_DP_CONFIG_DP_TRACE_ALL +#endif + +#ifdef WLAN_NUD_TRACKING +/* + * + * gEnableNUDTracking - Will enable or disable NUD tracking within driver + * @Min: 0 + * @Max: 3 + * @Default: 2 + * + * This ini is used to specify the behaviour of the driver for NUD tracking. + * If the ini value is:- + * 0: Driver will not track the NUD failures, and ignore the same. + * 1: Driver will track the NUD failures and if honoured will disconnect from + * the connected BSSID. + * 2: Driver will track the NUD failures and if honoured will roam away from + * the connected BSSID to a new BSSID to retain the data connectivity. + * 3: Driver will try to roam to a new AP but if roam fails, disconnect. + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_DP_ENABLE_NUD_TRACKING \ + CFG_INI_UINT("gEnableNUDTracking", \ + 0, \ + 3, \ + 2, \ + CFG_VALUE_OR_DEFAULT, "Driver NUD tracking behaviour") + +#define CFG_DP_ENABLE_NUD_TRACKING_ALL \ + CFG(CFG_DP_ENABLE_NUD_TRACKING) +#else +#define CFG_DP_ENABLE_NUD_TRACKING_ALL +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE + +#define CFG_DP_HL_BUNDLE_HIGH_TH \ + CFG_INI_UINT( \ + "tx_bundle_high_threashold", \ + 0, \ + 70000, \ + 4330, \ + CFG_VALUE_OR_DEFAULT, \ + "tx bundle high threashold") + +#define CFG_DP_HL_BUNDLE_LOW_TH \ + CFG_INI_UINT( \ + "tx_bundle_low_threashold", \ + 0, \ + 70000, \ + 4000, \ + CFG_VALUE_OR_DEFAULT, \ + "tx bundle low threashold") + +#define CFG_DP_HL_BUNDLE_TIMER_VALUE \ + CFG_INI_UINT( \ + "tx_bundle_timer_in_ms", \ + 10, \ + 10000, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "tx bundle timer value in ms") + +#define CFG_DP_HL_BUNDLE_SIZE \ + CFG_INI_UINT( \ + "tx_bundle_size", \ + 0, \ + 64, \ + 16, \ + CFG_VALUE_OR_DEFAULT, \ + "tx bundle size") + +#endif + +#define WLAN_CFG_ICMP_REQ_TO_FW_MARK_ALL (-1) +#define WLAN_CFG_ICMP_REQ_TO_FW_MARK_INTERVAL 0 +#define WLAN_CFG_ICMP_REQ_TO_FW_MARK_INTERVAL_MIN (-1) +#define WLAN_CFG_ICMP_REQ_TO_FW_MARK_INTERVAL_MAX 100000 + +/* + * + * icmp_req_to_fw_mark_interval - Interval to mark the ICMP Request packet + * to be sent to FW. + * @Min: -1 + * @Max: 100000 + * @Default: 0 + * + * This ini is used to control DP Software to mark the ICMP request packets + * to be sent to FW at certain interval (in milliseconds). + * The value 0 is used to disable marking of ICMP requests to be sent to FW. + * The value -1 is used to mark all the ICMP requests to be sent to FW. + * Any value greater than zero indicates the time interval (in milliseconds) + * at which ICMP requests are marked to be sent to FW. + * + * Supported modes: All modes + * + * Usage: External + * + * + */ +#define CFG_DP_ICMP_REQ_TO_FW_MARK_INTERVAL \ + CFG_INI_INT("icmp_req_to_fw_mark_interval", \ + WLAN_CFG_ICMP_REQ_TO_FW_MARK_INTERVAL_MIN, \ + WLAN_CFG_ICMP_REQ_TO_FW_MARK_INTERVAL_MAX, \ + WLAN_CFG_ICMP_REQ_TO_FW_MARK_INTERVAL, \ + CFG_VALUE_OR_DEFAULT, \ + "Interval to mark ICMP Request packets to be sent to FW") + +/* + * + * enable_direct_link_ut_cmd - Enable direct link unit testing + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable direct link unit test + * + * Supported feature: Direct link + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_DIRECT_LINK_UT_CMD \ + CFG_INI_BOOL("enable_direct_link_ut_cmd", false, \ + "enable/disable direct link unit test") + +/* + * + * dp_apply_mem_profile - Apply mem profile config + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to apply DP mem profile config + * + * Supported feature: All modes + * + * Usage: Internal + * + * + */ +#define CFG_DP_APPLY_MEM_PROFILE \ + CFG_INI_BOOL("dp_apply_mem_profile", false, \ + "enable/disable dp mem profile") + +#ifdef WLAN_SUPPORT_RX_FISA +/* + * + * dp_rx_fisa_enable - Control Rx datapath FISA + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable DP Rx FISA feature + * + * Related: dp_rx_flow_search_table_size + * + * Supported Feature: STA,P2P and SAP IPA disabled terminating + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_FISA_ENABLE \ + CFG_INI_BOOL("dp_rx_fisa_enable", true, \ + "Enable/Disable DP Rx FISA") + +/* + * + * dp_rx_fisa_lru_del_enable - Control Rx datapath FISA + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable DP Rx FISA lru deletion feature + * + * Related: dp_rx_fisa_enable + * + * Supported Feature: STA,P2P and SAP IPA disabled terminating + * + * Usage: Internal + * + * + */ +#define CFG_DP_RX_FISA_LRU_DEL_ENABLE \ + CFG_INI_BOOL("dp_rx_fisa_lru_del_enable", true, \ + "Enable/Disable DP Rx FISA LRU deletion") + +#define CFG_DP_FISA \ + CFG(CFG_DP_RX_FISA_ENABLE) \ + CFG(CFG_DP_RX_FISA_LRU_DEL_ENABLE) +#else +#define CFG_DP_FISA +#endif + +/*TODO Flow control part to be moved to DP later*/ + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +#define CFG_DP_BUS_BANDWIDTH \ + CFG(CFG_DP_BUS_BANDWIDTH_SUPER_HIGH_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_ULTRA_HIGH_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_VERY_HIGH_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_MID_HIGH_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_DBS_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_HIGH_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_MEDIUM_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_LOW_THRESHOLD) \ + CFG(CFG_DP_BUS_BANDWIDTH_COMPUTE_INTERVAL) \ + CFG(CFG_DP_ENABLE_TCP_LIMIT_OUTPUT) \ + CFG(CFG_DP_ENABLE_TCP_ADV_WIN_SCALE) \ + CFG(CFG_DP_ENABLE_TCP_DELACK) \ + CFG(CFG_DP_TCP_DELACK_THRESHOLD_HIGH) \ + CFG(CFG_DP_TCP_DELACK_THRESHOLD_LOW) \ + CFG(CFG_DP_TCP_DELACK_TIMER_COUNT) \ + CFG(CFG_DP_TCP_TX_HIGH_TPUT_THRESHOLD) \ + CFG(CFG_DP_BUS_LOW_BW_CNT_THRESHOLD) \ + CFG(CFG_DP_BUS_HANDLE_LATENCY_CRITICAL_CLIENTS) + +#else +#define CFG_DP_BUS_BANDWIDTH +#endif + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +#define CFG_DP_DRIVER_TCP_DELACK \ + CFG(CFG_DP_DRIVER_TCP_DELACK_HIGH_THRESHOLD) \ + CFG(CFG_DP_DRIVER_TCP_DELACK_LOW_THRESHOLD) \ + CFG(CFG_DP_DRIVER_TCP_DELACK_TIMER_VALUE) \ + CFG(CFG_DP_DRIVER_TCP_DELACK_PKT_CNT) \ + CFG(CFG_DP_DRIVER_TCP_DELACK_ENABLE) +#else +#define CFG_DP_DRIVER_TCP_DELACK +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +#define CFG_DP_HL_BUNDLE \ + CFG(CFG_DP_HL_BUNDLE_HIGH_TH) \ + CFG(CFG_DP_HL_BUNDLE_LOW_TH) \ + CFG(CFG_DP_HL_BUNDLE_TIMER_VALUE) \ + CFG(CFG_DP_HL_BUNDLE_SIZE) +#else +#define CFG_DP_HL_BUNDLE +#endif + +#define CFG_DP_ALL \ + CFG(CFG_DP_RX_THREAD_CPU_MASK) \ + CFG(CFG_DP_RX_THREAD_UL_CPU_MASK) \ + CFG(CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST) \ + CFG(CFG_DP_TX_ORPHAN_ENABLE) \ + CFG(CFG_DP_RX_MODE) \ + CFG(CFG_DP_TX_COMP_LOOP_PKT_LIMIT)\ + CFG(CFG_DP_RX_REAP_LOOP_PKT_LIMIT)\ + CFG(CFG_DP_RX_HP_OOS_UPDATE_LIMIT)\ + CFG(CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS)\ + CFG(CFG_DP_CE_SERVICE_MAX_RX_IND_FLUSH) \ + CFG(CFG_DP_CE_SERVICE_MAX_YIELD_TIME) \ + CFG(CFG_DP_ENABLE_TCP_PARAM_UPDATE) \ + CFG(CFG_DP_FILTER_MULTICAST_REPLAY) \ + CFG(CFG_DP_RX_WAKELOCK_TIMEOUT) \ + CFG(CFG_DP_NUM_DP_RX_THREADS) \ + CFG(CFG_DP_ICMP_REQ_TO_FW_MARK_INTERVAL) \ + CFG(CFG_ENABLE_DIRECT_LINK_UT_CMD) \ + CFG(CFG_DP_APPLY_MEM_PROFILE) \ + CFG_DP_ENABLE_FASTPATH_ALL \ + CFG_DP_BUS_BANDWIDTH \ + CFG_DP_DRIVER_TCP_DELACK \ + CFG_DP_ENABLE_NUD_TRACKING_ALL \ + CFG_DP_CONFIG_DP_TRACE_ALL \ + CFG_DP_HL_BUNDLE \ + CFG_DP_FISA + +#endif /* WLAN_DP_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_public_struct.h new file mode 100644 index 0000000000..41002c887a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_public_struct.h @@ -0,0 +1,785 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Contains DP public data structure definitions. + * + */ + +#ifndef _WLAN_DP_PUBLIC_STRUCT_H_ +#define _WLAN_DP_PUBLIC_STRUCT_H_ + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_global_obj.h" +#include "qdf_status.h" +#include +#include +#include +#include "cdp_txrx_ops.h" +#include +#include +#include "wlan_dp_rx_thread.h" + +#define DP_MAX_SUBTYPES_TRACKED 4 + +enum dp_rx_offld_flush_cb { + DP_RX_FLUSH_LRO, + DP_RX_FLUSH_THREAD, + DP_RX_FLUSH_NAPI, +}; + +enum dp_nbuf_push_type { + DP_NBUF_PUSH_NI, + DP_NBUF_PUSH_NAPI, + DP_NBUF_PUSH_BH_DISABLE, + DP_NBUF_PUSH_SIMPLE, +}; + +/** + * struct dp_eapol_stats - eapol debug stats count + * @eapol_m1_count: eapol m1 count + * @eapol_m2_count: eapol m2 count + * @eapol_m3_count: eapol m3 count + * @eapol_m4_count: eapol m4 count + * @tx_dropped: no of tx frames dropped by host + * @tx_noack_cnt: no of frames for which there is no ack + * @rx_delivered: no. of frames delivered to network stack + * @rx_refused: no of frames not delivered to network stack + */ +struct dp_eapol_stats { + uint16_t eapol_m1_count; + uint16_t eapol_m2_count; + uint16_t eapol_m3_count; + uint16_t eapol_m4_count; + uint16_t tx_dropped[DP_MAX_SUBTYPES_TRACKED]; + uint16_t tx_noack_cnt[DP_MAX_SUBTYPES_TRACKED]; + uint16_t rx_delivered[DP_MAX_SUBTYPES_TRACKED]; + uint16_t rx_refused[DP_MAX_SUBTYPES_TRACKED]; +}; + +/** + * struct dp_dhcp_stats - dhcp debug stats count + * @dhcp_dis_count: dhcp discovery count + * @dhcp_off_count: dhcp offer count + * @dhcp_req_count: dhcp request count + * @dhcp_ack_count: dhcp ack count + * @tx_dropped: no of tx frames dropped by host + * @tx_noack_cnt: no of frames for which there is no ack + * @rx_delivered: no. of frames delivered to network stack + * @rx_refused: no of frames not delivered to network stack + */ +struct dp_dhcp_stats { + uint16_t dhcp_dis_count; + uint16_t dhcp_off_count; + uint16_t dhcp_req_count; + uint16_t dhcp_ack_count; + uint16_t tx_dropped[DP_MAX_SUBTYPES_TRACKED]; + uint16_t tx_noack_cnt[DP_MAX_SUBTYPES_TRACKED]; + uint16_t rx_delivered[DP_MAX_SUBTYPES_TRACKED]; + uint16_t rx_refused[DP_MAX_SUBTYPES_TRACKED]; +}; + +#ifdef TX_MULTIQ_PER_AC +#define TX_GET_QUEUE_IDX(ac, off) (((ac) * TX_QUEUES_PER_AC) + (off)) +#define TX_QUEUES_PER_AC 4 +#else +#define TX_GET_QUEUE_IDX(ac, off) (ac) +#define TX_QUEUES_PER_AC 1 +#endif + +/** Number of Tx Queues */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || \ + defined(QCA_HL_NETDEV_FLOW_CONTROL) || \ + defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/* Only one HI_PRIO queue */ +#define NUM_TX_QUEUES (4 * TX_QUEUES_PER_AC + 1) +#else +#define NUM_TX_QUEUES (4 * TX_QUEUES_PER_AC) +#endif + +#ifndef NUM_CPUS +#ifdef QCA_CONFIG_SMP +#define NUM_CPUS NR_CPUS +#else +#define NUM_CPUS 1 +#endif +#endif + +/** + * struct dp_arp_stats - arp debug stats count + * @tx_arp_req_count: no. of arp req received from network stack + * @rx_arp_rsp_count: no. of arp res received from FW + * @tx_dropped: no. of arp req dropped at hdd layer + * @rx_dropped: no. of arp res dropped + * @rx_delivered: no. of arp res delivered to network stack + * @rx_refused: no of arp rsp refused (not delivered) to network stack + * @tx_host_fw_sent: no of arp req sent by FW OTA + * @rx_host_drop_reorder: no of arp res dropped by host + * @rx_fw_cnt: no of arp res received by FW + * @tx_ack_cnt: no of arp req acked by FW + */ +struct dp_arp_stats { + uint16_t tx_arp_req_count; + uint16_t rx_arp_rsp_count; + uint16_t tx_dropped; + uint16_t rx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop_reorder; + uint16_t rx_fw_cnt; + uint16_t tx_ack_cnt; +}; + +/** + * struct dp_set_arp_stats_params - set/reset arp stats + * @vdev_id: session id + * @flag: enable/disable stats + * @pkt_type: type of packet(1 - arp) + * @ip_addr: subnet ipv4 address in case of encrypted packets + * @pkt_type_bitmap: pkt bitmap + * @tcp_src_port: tcp src port for pkt tracking + * @tcp_dst_port: tcp dst port for pkt tracking + * @icmp_ipv4: target ipv4 address to track ping packets + * @reserved: reserved + */ +struct dp_set_arp_stats_params { + uint32_t vdev_id; + uint8_t flag; + uint8_t pkt_type; + uint32_t ip_addr; + uint32_t pkt_type_bitmap; + uint32_t tcp_src_port; + uint32_t tcp_dst_port; + uint32_t icmp_ipv4; + uint32_t reserved; +}; + +/** + * struct dp_get_arp_stats_params - get arp stats from firmware + * @pkt_type: packet type(1 - ARP) + * @vdev_id: session id + */ +struct dp_get_arp_stats_params { + uint8_t pkt_type; + uint32_t vdev_id; +}; + +/** + * struct dp_dns_stats - dns debug stats count + * @tx_dns_req_count: no. of dns query received from network stack + * @rx_dns_rsp_count: no. of dns res received from FW + * @tx_dropped: no. of dns query dropped at hdd layer + * @rx_delivered: no. of dns res delivered to network stack + * @rx_refused: no of dns res refused (not delivered) to network stack + * @tx_host_fw_sent: no of dns query sent by FW OTA + * @rx_host_drop: no of dns res dropped by host + * @tx_ack_cnt: no of dns req acked by FW + */ +struct dp_dns_stats { + uint16_t tx_dns_req_count; + uint16_t rx_dns_rsp_count; + uint16_t tx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop; + uint16_t tx_ack_cnt; +}; + +/** + * struct dp_tcp_stats - tcp debug stats count + * @tx_tcp_syn_count: no. of tcp syn received from network stack + * @tx_tcp_ack_count: no. of tcp ack received from network stack + * @rx_tcp_syn_ack_count: no. of tcp syn ack received from FW + * @tx_tcp_syn_dropped: no. of tcp syn dropped at hdd layer + * @tx_tcp_ack_dropped: no. of tcp ack dropped at hdd layer + * @rx_delivered: no. of tcp syn ack delivered to network stack + * @rx_refused: no of tcp syn ack refused (not delivered) to network stack + * @tx_tcp_syn_host_fw_sent: no of tcp syn sent by FW OTA + * @tx_tcp_ack_host_fw_sent: no of tcp ack sent by FW OTA + * @rx_host_drop: no of tcp syn ack dropped by host + * @rx_fw_cnt: no of tcp res received by FW + * @tx_tcp_syn_ack_cnt: no of tcp syn acked by FW + * @tx_tcp_ack_ack_cnt: no of tcp ack acked by FW + * @is_tcp_syn_ack_rcv: flag to check tcp syn ack received or not + * @is_tcp_ack_sent: flag to check tcp ack sent or not + */ +struct dp_tcp_stats { + uint16_t tx_tcp_syn_count; + uint16_t tx_tcp_ack_count; + uint16_t rx_tcp_syn_ack_count; + uint16_t tx_tcp_syn_dropped; + uint16_t tx_tcp_ack_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_tcp_syn_host_fw_sent; + uint16_t tx_tcp_ack_host_fw_sent; + uint16_t rx_host_drop; + uint16_t rx_fw_cnt; + uint16_t tx_tcp_syn_ack_cnt; + uint16_t tx_tcp_ack_ack_cnt; + bool is_tcp_syn_ack_rcv; + bool is_tcp_ack_sent; + +}; + +/** + * struct dp_icmpv4_stats - icmpv4 debug stats count + * @tx_icmpv4_req_count: no. of icmpv4 req received from network stack + * @rx_icmpv4_rsp_count: no. of icmpv4 res received from FW + * @tx_dropped: no. of icmpv4 req dropped at hdd layer + * @rx_delivered: no. of icmpv4 res delivered to network stack + * @rx_refused: no of icmpv4 res refused (not delivered) to network stack + * @tx_host_fw_sent: no of icmpv4 req sent by FW OTA + * @rx_host_drop: no of icmpv4 res dropped by host + * @rx_fw_cnt: no of icmpv4 res received by FW + * @tx_ack_cnt: no of icmpv4 req acked by FW + */ +struct dp_icmpv4_stats { + uint16_t tx_icmpv4_req_count; + uint16_t rx_icmpv4_rsp_count; + uint16_t tx_dropped; + uint16_t rx_delivered; + uint16_t rx_refused; + uint16_t tx_host_fw_sent; + uint16_t rx_host_drop; + uint16_t rx_fw_cnt; + uint16_t tx_ack_cnt; +}; + +/** + * struct dp_rsp_stats - arp packet stats + * @vdev_id: session id + * @arp_req_enqueue: fw tx count + * @arp_req_tx_success: tx ack count + * @arp_req_tx_failure: tx ack fail count + * @arp_rsp_recvd: rx fw count + * @out_of_order_arp_rsp_drop_cnt: out of order count + * @dad_detected: dad detected + * @connect_status: connection status + * @ba_session_establishment_status: BA session status + * @connect_stats_present: connectivity stats present or not + * @tcp_ack_recvd: tcp syn ack's count + * @icmpv4_rsp_recvd: icmpv4 responses count + */ +struct dp_rsp_stats { + uint32_t vdev_id; + uint32_t arp_req_enqueue; + uint32_t arp_req_tx_success; + uint32_t arp_req_tx_failure; + uint32_t arp_rsp_recvd; + uint32_t out_of_order_arp_rsp_drop_cnt; + uint32_t dad_detected; + uint32_t connect_status; + uint32_t ba_session_establishment_status; + bool connect_stats_present; + uint32_t tcp_ack_recvd; + uint32_t icmpv4_rsp_recvd; +}; + +/** + * struct dp_txrx_soc_attach_params - SoC attach params + * @dp_ol_if_ops: DP ol_if ops + * @target_psoc: target psoc + * @target_type: Target type + */ +struct dp_txrx_soc_attach_params { + struct ol_if_ops *dp_ol_if_ops; + void *target_psoc; + uint32_t target_type; +}; + +struct dp_tx_rx_stats { + struct { + /* start_xmit stats */ + __u32 tx_called; + __u32 tx_dropped; + __u32 tx_orphaned; + __u32 tx_classified_ac[WLAN_MAX_AC]; + __u32 tx_dropped_ac[WLAN_MAX_AC]; +#ifdef TX_MULTIQ_PER_AC + /* Neither valid socket nor skb->hash */ + uint32_t inv_sk_and_skb_hash; + /* skb->hash already calculated */ + uint32_t qselect_existing_skb_hash; + /* valid tx queue id in socket */ + uint32_t qselect_sk_tx_map; + /* skb->hash calculated in select queue */ + uint32_t qselect_skb_hash_calc; +#endif + /* rx stats */ + __u32 rx_packets; + __u32 rx_dropped; + __u32 rx_delivered; + __u32 rx_refused; + } per_cpu[NUM_CPUS]; + + qdf_atomic_t rx_usolict_arp_n_mcast_drp; + + /* rx gro */ + __u32 rx_aggregated; + __u32 rx_gro_dropped; + __u32 rx_non_aggregated; + __u32 rx_gro_flush_skip; + __u32 rx_gro_low_tput_flush; + + /* txflow stats */ + bool is_txflow_paused; + __u32 txflow_pause_cnt; + __u32 txflow_unpause_cnt; + __u32 txflow_timer_cnt; + + /*tx timeout stats*/ + __u32 tx_timeout_cnt; + __u32 cont_txtimeout_cnt; + u64 last_txtimeout; +}; + +/** + * struct dp_dhcp_ind - DHCP Start/Stop indication message + * @dhcp_start: Is DHCP start idication + * @device_mode: Mode of the device(ex:STA, AP) + * @intf_mac_addr: MAC address of the interface + * @peer_mac_addr: MAC address of the connected peer + */ +struct dp_dhcp_ind { + bool dhcp_start; + uint8_t device_mode; + struct qdf_mac_addr intf_mac_addr; + struct qdf_mac_addr peer_mac_addr; +}; + +/** + * struct dp_mic_error_info - mic error info in dp + * @ta_mac_addr: transmitter mac address + * @multicast: Flag for multicast + * @key_id: Key ID + * @tsc: Sequence number + * @vdev_id: vdev id + * + */ +struct dp_mic_error_info { + struct qdf_mac_addr ta_mac_addr; + bool multicast; + uint8_t key_id; + uint8_t tsc[SIR_CIPHER_SEQ_CTR_SIZE]; + uint16_t vdev_id; +}; + +enum dp_mic_work_status { + DP_MIC_UNINITIALIZED, + DP_MIC_INITIALIZED, + DP_MIC_SCHEDULED, + DP_MIC_DISABLED +}; + +/** + * struct dp_mic_work - mic work info in dp + * @work: mic error work + * @status: sattus of mic error work + * @info: Pointer to mic error information + * @lock: lock to synchronixe mic error work + * + */ +struct dp_mic_work { + qdf_work_t work; + enum dp_mic_work_status status; + struct dp_mic_error_info *info; + qdf_spinlock_t lock; +}; + +enum dp_nud_state { + DP_NUD_NONE, + DP_NUD_INCOMPLETE, + DP_NUD_REACHABLE, + DP_NUD_STALE, + DP_NUD_DELAY, + DP_NUD_PROBE, + DP_NUD_FAILED, + DP_NUD_NOARP, + DP_NUD_PERMANENT, + DP_NUD_STATE_INVALID +}; + +struct opaque_hdd_callback_handle; +/* + * typedef hdd_cb_handle - HDD Handle + * + * Handle to the HDD. The HDD handle is given to the DP component from the + * HDD during start modules. The HDD handle is an input to all HDD function + * calls and represents an opaque handle to the HDD instance that is + * tied to the DP context + * + * The HDD must be able to derive it's internal instance structure + * pointer through this handle. + * + * NOTE WELL: struct opaque_hdd_callback_handle is not defined anywhere. This + * reference is used to help ensure that a hdd_cb_handle is never used + * where a different handle type is expected + */ +typedef struct opaque_hdd_callback_handle *hdd_cb_handle; + +/** + * enum bus_bw_level - bus bandwidth vote levels + * + * @BUS_BW_LEVEL_NONE: No vote for bus bandwidth + * @BUS_BW_LEVEL_1: vote for level-1 bus bandwidth + * @BUS_BW_LEVEL_2: vote for level-2 bus bandwidth + * @BUS_BW_LEVEL_3: vote for level-3 bus bandwidth + * @BUS_BW_LEVEL_4: vote for level-4 bus bandwidth + * @BUS_BW_LEVEL_5: vote for level-5 bus bandwidth + * @BUS_BW_LEVEL_6: vote for level-6 bus bandwidth + * @BUS_BW_LEVEL_7: vote for level-7 bus bandwidth + * @BUS_BW_LEVEL_8: vote for level-8 bus bandwidth + * @BUS_BW_LEVEL_9: vote for level-9 bus bandwidth + * @BUS_BW_LEVEL_MAX: vote for max level bus bandwidth + */ +enum bus_bw_level { + BUS_BW_LEVEL_NONE, + BUS_BW_LEVEL_1, + BUS_BW_LEVEL_2, + BUS_BW_LEVEL_3, + BUS_BW_LEVEL_4, + BUS_BW_LEVEL_5, + BUS_BW_LEVEL_6, + BUS_BW_LEVEL_7, + BUS_BW_LEVEL_8, + BUS_BW_LEVEL_9, + BUS_BW_LEVEL_MAX, +}; + +#define BUS_BW_LEVEL_RESUME BUS_BW_LEVEL_3 + +/** + * enum tput_level - throughput levels + * + * @TPUT_LEVEL_NONE: No throughput + * @TPUT_LEVEL_IDLE: idle throughtput level + * @TPUT_LEVEL_LOW: low throughput level + * @TPUT_LEVEL_MEDIUM: medium throughtput level + * @TPUT_LEVEL_HIGH: high throughput level + * @TPUT_LEVEL_MID_HIGH: mid high throughput level + * @TPUT_LEVEL_VERY_HIGH: very high throughput level + * @TPUT_LEVEL_ULTRA_HIGH: ultra high throughput level + * @TPUT_LEVEL_SUPER_HIGH: super high throughput level + * @TPUT_LEVEL_MAX: maximum throughput level + */ +enum tput_level { + TPUT_LEVEL_NONE, + TPUT_LEVEL_IDLE, + TPUT_LEVEL_LOW, + TPUT_LEVEL_MEDIUM, + TPUT_LEVEL_HIGH, + TPUT_LEVEL_MID_HIGH, + TPUT_LEVEL_VERY_HIGH, + TPUT_LEVEL_ULTRA_HIGH, + TPUT_LEVEL_SUPER_HIGH, + TPUT_LEVEL_MAX, +}; + +/** + * enum bbm_non_per_flag - Non persistent policy related flag + * + * @BBM_APPS_RESUME: system resume flag + * @BBM_APPS_SUSPEND: system suspend flag + * @BBM_FLAG_MAX: maximum flag + */ +enum bbm_non_per_flag { + BBM_APPS_RESUME, + BBM_APPS_SUSPEND, + BBM_FLAG_MAX, +}; + +/** + * enum bbm_policy - BBM policy + * + * @BBM_DRIVER_MODE_POLICY: driver mode policy + * @BBM_TPUT_POLICY: throughput policy + * @BBM_USER_POLICY: user policy + * @BBM_NON_PERSISTENT_POLICY: non persistent policy. For example, bus resume + * sets the bus bw level to LEVEL_3 if any adapter is connected but + * this is only a one time setting and is not persistent. This bus bw level + * is set without taking other policy vote levels into consideration. + * @BBM_SELECT_TABLE_POLICY: policy where bus bw table is selected based on + * the latency level. + * @BBM_MAX_POLICY: max policy + */ +enum bbm_policy { + BBM_DRIVER_MODE_POLICY, + BBM_TPUT_POLICY, + BBM_USER_POLICY, + BBM_NON_PERSISTENT_POLICY, + BBM_SELECT_TABLE_POLICY, + BBM_MAX_POLICY, +}; + +/** + * enum wlm_ll_level - WLM latency levels + * + * @WLM_LL_NORMAL: normal latency level + * @WLM_LL_LOW: low latency level + * @WLM_LL_MAX: max latency level + */ +enum wlm_ll_level { + WLM_LL_NORMAL, + WLM_LL_LOW, + WLM_LL_MAX, +}; + +/** + * union bbm_policy_info - BBM policy specific info. Only one of the value + * would be valid based on the BBM policy. + * + * @driver_mode: global driver mode. valid for BBM_DRIVER_MODE_POLICY. + * @flag: BBM non persistent flag. valid for BBM_NON_PERSISTENT_POLICY. + * @tput_level: throughput level. valid for BBM_TPUT_POLICY. + * @wlm_level: latency level. valid for BBM_WLM_POLICY. + * @user_level: user bus bandwidth vote. valid for BBM_USER_POLICY. + * @set: set or reset user level. valid for BBM_USER_POLICY. + * @usr: user specific info + */ +union bbm_policy_info { + enum QDF_GLOBAL_MODE driver_mode; + enum bbm_non_per_flag flag; + enum tput_level tput_level; + enum wlm_ll_level wlm_level; + struct { + enum bus_bw_level user_level; + bool set; + } usr; +}; + +/** + * struct bbm_params: BBM params + * + * @policy: BBM policy + * @policy_info: policy related info + */ +struct bbm_params { + enum bbm_policy policy; + union bbm_policy_info policy_info; +}; + +/** + * union wlan_tp_data: union of TCP msg for Tx and Rx Dir + * @tx_tp_data: msg to TCP for Tx Dir + * @rx_tp_data: msg to TCP for Rx Dir + */ +union wlan_tp_data { + struct wlan_tx_tp_data tx_tp_data; + struct wlan_rx_tp_data rx_tp_data; +}; + +/** + * struct wlan_dp_psoc_callbacks - struct containing callback + * to non-converged driver + * @callback_ctx : Opaque callback context + * @dp_get_netdev_by_vdev_mac: Callback to get netdev from vdev mac address + * @dp_get_tx_flow_low_watermark: Callback to get TX flow low watermark info + * @dp_get_tx_resource: Callback to check tx resources and take action + * @dp_get_tsf_time: Callback to get TSF time + * @dp_tsf_timestamp_rx: Callback to set rx packet timestamp + * @dp_nbuf_push_pkt: Callback to push rx pkt to network + * @dp_rx_napi_gro_flush: OS IF Callback to GRO RX/flush function. + * @dp_rx_thread_napi_gro_flush: OS IF Callback to do gro flush + * @dp_rx_napi_gro_receive: OS IF Callback for GRO RX receive function. + * @dp_lro_rx_cb: OS IF Callback for LRO receive function + * @dp_gro_rx_legacy_get_napi: Callback to get napi in legacy gro case + * @dp_register_rx_offld_flush_cb: OS IF Callback to get rx offld flush cb + * @dp_rx_check_qdisc_configured: OS IF Callback to check if any ingress qdisc + * configured + * @dp_is_gratuitous_arp_unsolicited_na: OS IF Callback to check gratuitous arp + * unsolicited na + * @dp_send_rx_pkt_over_nl: OS IF Callback to send rx pkt over nl + * @dp_disable_rx_ol_for_low_tput: Callback to disable Rx offload in low TPUT + * scenario + * @wlan_dp_sta_get_dot11mode: Callback to get dot11 mode + * @wlan_dp_get_ap_client_count: Callback to get client count connected to AP + * @wlan_dp_sta_ndi_connected: Callback to get NDI connected status + * @dp_any_adapter_connected: Callback to check if any adapter is connected + * @dp_send_svc_nlink_msg: Callback API to send svc nlink message + * @osif_dp_send_tcp_param_update_event: OS IF callback to send TCP param + * @dp_send_mscs_action_frame: Callback to send MSCS action frame + * @dp_pm_qos_add_request: Callback to send add pm qos request + * @dp_pm_qos_remove_request: Callback to send remove pm qos request + * @dp_pm_qos_update_request: Callback to send update pm qos request + * @dp_pld_remove_pm_qos: Callback to send remove pld pm qos request + * @dp_pld_request_pm_qos: Callback to send pld pm qos request + * @dp_pktlog_enable_disable:Callback to set packet log + * @dp_is_roaming_in_progress:Callback to check if roaming is in progress + * @dp_is_ap_active:Callback to check if AP is active + * @dp_napi_apply_throughput_policy:Callback to apply NAPI throughput policy + * @wlan_dp_display_tx_multiq_stats: Callback to display Tx Mulit queue stats + * @wlan_dp_display_netif_queue_history: Callback to display Netif queue + * history + * @osif_dp_process_mic_error: osif callback to process MIC error + * @dp_is_link_adapter: Callback API to check if adapter is link adapter + * @os_if_dp_nud_stats_info: osif callback to print nud stats info + * @dp_get_pause_map: Callback API to get pause map count + * @dp_nud_failure_work: Callback API to handle NUD failuire work + * @link_monitoring_cb: Callback API to handle link speed change + */ +struct wlan_dp_psoc_callbacks { + hdd_cb_handle callback_ctx; + + qdf_netdev_t (*dp_get_netdev_by_vdev_mac)(struct qdf_mac_addr *mac_addr); + unsigned int (*dp_get_tx_flow_low_watermark)(hdd_cb_handle cb_ctx, + qdf_netdev_t netdev); + void (*dp_get_tx_resource)(uint8_t link_id_id, + struct qdf_mac_addr *mac_addr); + void (*dp_get_tsf_time)(qdf_netdev_t netdev, uint64_t input_time, + uint64_t *tsf_time); + void (*dp_tsf_timestamp_rx)(hdd_cb_handle ctx, qdf_nbuf_t nbuf); + + QDF_STATUS (*dp_nbuf_push_pkt)(qdf_nbuf_t nbuf, + enum dp_nbuf_push_type type); + + QDF_STATUS (*dp_rx_napi_gro_flush)(qdf_napi_struct *napi_to_use, + qdf_nbuf_t nbuf, + uint8_t *force_flush); + void + (*dp_rx_thread_napi_gro_flush)(qdf_napi_struct *napi, + enum dp_rx_gro_flush_code flush_code); + QDF_STATUS (*dp_rx_napi_gro_receive)(qdf_napi_struct *napi_to_use, + qdf_nbuf_t nbuf); + + QDF_STATUS (*dp_lro_rx_cb)(qdf_netdev_t netdev, qdf_nbuf_t nbuf); + + qdf_napi_struct *(*dp_gro_rx_legacy_get_napi)(qdf_nbuf_t nbuf, + bool enable_rx_thread); + + void (*dp_register_rx_offld_flush_cb)(enum dp_rx_offld_flush_cb type); + + QDF_STATUS (*dp_rx_check_qdisc_configured)(qdf_netdev_t dev, + uint32_t prio); + + bool (*dp_is_gratuitous_arp_unsolicited_na)(qdf_nbuf_t nbuf); + + bool (*dp_send_rx_pkt_over_nl)(qdf_netdev_t dev, uint8_t *addr, + qdf_nbuf_t nbuf, bool unecrypted); + bool + (*wlan_dp_sta_get_dot11mode)(hdd_cb_handle context, qdf_netdev_t netdev, + enum qca_wlan_802_11_mode *dot11_mode); + bool (*wlan_dp_get_ap_client_count)(hdd_cb_handle context, + qdf_netdev_t netdev, + uint16_t *client_count); + bool (*wlan_dp_sta_ndi_connected)(hdd_cb_handle context, + qdf_netdev_t netdev); + bool (*dp_any_adapter_connected)(hdd_cb_handle context); + void (*dp_send_svc_nlink_msg)(int radio, int type, void *data, int len); + + void + (*osif_dp_send_tcp_param_update_event)(struct wlan_objmgr_psoc *psoc, + union wlan_tp_data *data, + uint8_t dir); + void (*dp_send_mscs_action_frame)(hdd_cb_handle context, + qdf_netdev_t netdev); + void (*dp_pm_qos_add_request)(hdd_cb_handle context); + void (*dp_pm_qos_remove_request)(hdd_cb_handle context); + void (*dp_pm_qos_update_request)(hdd_cb_handle context, + cpumask_t *mask); + void (*dp_pld_remove_pm_qos)(hdd_cb_handle context); + void (*dp_pld_request_pm_qos)(hdd_cb_handle context); + int (*dp_pktlog_enable_disable)(hdd_cb_handle context, + bool enable_disable_flag, + uint8_t user_triggered, int size); + bool (*dp_is_roaming_in_progress)(hdd_cb_handle context); + bool (*dp_is_ap_active)(hdd_cb_handle context, qdf_netdev_t netdev); + void (*dp_disable_rx_ol_for_low_tput)(hdd_cb_handle context, + bool disable); + int (*dp_napi_apply_throughput_policy)(hdd_cb_handle context, + uint64_t tx_packets, + uint64_t rx_packets); + void (*wlan_dp_display_tx_multiq_stats)(hdd_cb_handle context, + qdf_netdev_t netdev); + void (*wlan_dp_display_netif_queue_history)(hdd_cb_handle context, + enum qdf_stats_verbosity_level verb_lvl); + void (*osif_dp_process_mic_error)(struct dp_mic_error_info *info, + struct wlan_objmgr_vdev *vdev); + bool (*dp_is_link_adapter)(hdd_cb_handle context, uint8_t vdev_id); + void (*os_if_dp_nud_stats_info)(struct wlan_objmgr_vdev *vdev); + uint32_t (*dp_get_pause_map)(hdd_cb_handle context, qdf_netdev_t dev); + void (*dp_nud_failure_work)(hdd_cb_handle context, qdf_netdev_t dev); + void (*link_monitoring_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good); +}; + +/** + * struct wlan_dp_psoc_sb_ops - struct containing callback + * to south bound APIs. callbacks to call traget_if APIs + * @dp_arp_stats_register_event_handler: Callback to register + * arp stas WMI handle + * @dp_arp_stats_unregister_event_handler: Callback to unregister + * arp stas WMI handle + * @dp_get_arp_req_stats: Callback to get arp stats + * @dp_set_arp_req_stats: Callback to set arp stats + * @arp_request_ctx: ARP request context + * @dp_lro_config_cmd: Callback to send LRO config command + * @dp_send_dhcp_ind: Callback to send DHCP indication + */ +struct wlan_dp_psoc_sb_ops { + /*TODO to add target if TX ops*/ + QDF_STATUS (*dp_arp_stats_register_event_handler)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*dp_arp_stats_unregister_event_handler)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*dp_get_arp_req_stats)(struct wlan_objmgr_psoc *psoc, + struct dp_get_arp_stats_params *req_buf); + QDF_STATUS (*dp_set_arp_req_stats)(struct wlan_objmgr_psoc *psoc, + struct dp_set_arp_stats_params *req_buf); + void *arp_request_ctx; + QDF_STATUS (*dp_lro_config_cmd)(struct wlan_objmgr_psoc *psoc, + struct cdp_lro_hash_config *dp_lro_cmd); + QDF_STATUS (*dp_send_dhcp_ind)(uint16_t vdev_id, + struct dp_dhcp_ind *dhcp_ind); +}; + +/** + * struct wlan_dp_psoc_nb_ops - struct containing callback + * to north bound APIs. callbacks APIs to be called by target_if APIs + * @osif_dp_get_arp_stats_evt: Callback called on receiving arp stats event + */ +struct wlan_dp_psoc_nb_ops { + /*TODO to add target if RX ops*/ + void (*osif_dp_get_arp_stats_evt)(struct wlan_objmgr_psoc *psoc, + struct dp_rsp_stats *rsp); +}; + +/** + * struct wlan_dp_user_config - DP component user config + * @ipa_enable: IPA enabled/disabled config + * @arp_connectivity_map: ARP connectiviy map + */ +struct wlan_dp_user_config { + bool ipa_enable; + uint32_t arp_connectivity_map; +}; + +/** + * struct dp_traffic_end_indication - Traffic end indication + * @enabled: Feature enabled/disabled config + * @def_dscp: Default DSCP value in regular packets in traffic + * @spl_dscp: Special DSCP value to be used by packet to mark + * end of data stream + */ +struct dp_traffic_end_indication { + bool enabled; + uint8_t def_dscp; + uint8_t spl_dscp; +}; +#endif /* end of _WLAN_DP_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h new file mode 100644 index 0000000000..55d5840b77 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/inc/wlan_dp_ucfg_api.h @@ -0,0 +1,1655 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_dp_ucfg_api.h + * + * TDLS north bound interface declaration + */ + +#if !defined(_WLAN_DP_UCFG_API_H_) +#define _WLAN_DP_UCFG_API_H_ + +#include +#include +#include +#include +#include +#include "pld_common.h" +#include +#include +#include "wlan_dp_objmgr.h" +#include "wlan_qmi_public_struct.h" + +#define DP_IGNORE_NUD_FAIL 0 +#define DP_DISCONNECT_AFTER_NUD_FAIL 1 +#define DP_ROAM_AFTER_NUD_FAIL 2 +#define DP_DISCONNECT_AFTER_ROAM_FAIL 3 + +#ifdef WLAN_NUD_TRACKING +bool +ucfg_dp_is_roam_after_nud_enabled(struct wlan_objmgr_psoc *psoc); + +bool +ucfg_dp_is_disconect_after_roam_fail(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_dp_is_roam_after_nud_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool +ucfg_dp_is_disconect_after_roam_fail(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * ucfg_dp_update_link_mac_addr() - Update the dp_link mac address, during MLO + * link switch. + * @vdev: Objmgr vdev corresponding to the dp_link + * @new_mac_addr: New mac address of the dp_link + * @is_link_switch: Flag to indicate if the link mac addr update is as a part + * of MLO link switch. + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_update_link_mac_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *new_mac_addr, + bool is_link_switch); + +/** + * ucfg_dp_update_def_link() - update DP interface default link + * @psoc: psoc handle + * @intf_mac: interface MAC address + * @vdev: objmgr vdev handle to set the def_link in dp_intf + * + */ +void ucfg_dp_update_def_link(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_mac, + struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_update_intf_mac() - update DP interface MAC address + * @psoc: psoc handle + * @cur_mac: Current MAC address + * @new_mac: new MAC address + * @vdev: objmgr vdev handle to set the def_link in dp_intf + * + */ +void ucfg_dp_update_intf_mac(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *cur_mac, + struct qdf_mac_addr *new_mac, + struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_destroy_intf() - DP module interface deletion + * @psoc: psoc handle + * @intf_addr: Interface MAC address + * + */ +QDF_STATUS ucfg_dp_destroy_intf(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_addr); + +/** + * ucfg_dp_create_intf() - DP module interface creation + * @psoc: psoc handle + * @intf_addr: Interface MAC address + * @ndev : netdev object + * + */ +QDF_STATUS ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_addr, + qdf_netdev_t ndev); + +void ucfg_dp_set_hif_handle(struct wlan_objmgr_psoc *psoc, + struct hif_opaque_softc *hif_handle); +void ucfg_dp_set_cmn_dp_handle(struct wlan_objmgr_psoc *psoc, + ol_txrx_soc_handle soc); +/** + * ucfg_dp_init() - DP module initialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_init(void); + +/** + * ucfg_dp_deinit() - DP module deinitialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_deinit(void); + +/** + * ucfg_dp_psoc_open() - DP component Open + * @psoc: pointer to psoc object + * + * Return: QDF Status + */ +QDF_STATUS ucfg_dp_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_psoc_close() - DP component Close + * @psoc: pointer to psoc object + * + * Return: QDF Status + */ +QDF_STATUS ucfg_dp_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_suspend_wlan() - update suspend state in DP component + * @psoc: pointer to psoc object + * + * Return: None + */ +void ucfg_dp_suspend_wlan(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_resume_wlan() - update resume state in DP component + * @psoc: pointer to psoc object + * + * Return: None + */ +void ucfg_dp_resume_wlan(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_update_config() - DP module config update + * @psoc: pointer to psoc object + * @req : user config + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_dp_update_config(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_user_config *req); +/** + * ucfg_dp_wait_complete_tasks() - wait for DP tasks to complete + * Called from legacy layer to wait DP tasks completion + * + * Return: None + */ +void +ucfg_dp_wait_complete_tasks(void); + +/** + * ucfg_dp_remove_conn_info() - Remove DP STA intf connection info + * @vdev: vdev mapped to STA DP interface + * + * Return: QDF_STATUS + */ +void +ucfg_dp_remove_conn_info(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_conn_info_set_bssid() - set BSSID info in STA intf + * @vdev: vdev mapped to STA DP interface + * @bssid: BSSID mac + * + * Return: None + */ +void ucfg_dp_conn_info_set_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid); + +/** + * ucfg_dp_conn_info_set_arp_service() - set ARP service info + * @vdev: vdev mapped to STA DP interface + * @proxy_arp_service: ARP service info + * + * Return: None + */ +void ucfg_dp_conn_info_set_arp_service(struct wlan_objmgr_vdev *vdev, + uint8_t proxy_arp_service); + +/** + * ucfg_dp_conn_info_set_peer_authenticate() - set Peer authenticated state + * @vdev: vdev mapped to STA DP interface + * @is_authenticated: Peer authenticated info + * + * Return: None + */ +void ucfg_dp_conn_info_set_peer_authenticate(struct wlan_objmgr_vdev *vdev, + uint8_t is_authenticated); + +/** + * ucfg_dp_conn_info_set_peer_mac() - set peer mac info in DP intf + * @vdev: vdev mapped to STA DP interface + * @peer_mac: Peer MAC information + * + * Return: None + */ +void ucfg_dp_conn_info_set_peer_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac); + +/** + * ucfg_dp_softap_check_wait_for_tx_eap_pkt() - wait for TX EAP pkt in SAP + * @vdev: vdev mapped to SAP DP interface + * @mac_addr: Peer MAC address info + * + * Return: None + */ +void ucfg_dp_softap_check_wait_for_tx_eap_pkt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr); + +/** + * ucfg_dp_update_dhcp_state_on_disassoc() - update DHCP during disassoc + * @vdev: vdev mapped to SAP DP interface + * @mac_addr: Peer MAC address info + * + * Return: None + */ +void ucfg_dp_update_dhcp_state_on_disassoc(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr); + +/** + * ucfg_dp_set_dfs_cac_tx() - update DFS CAC TX block info + * @vdev: vdev mapped to SAP DP interface + * @tx_block: true if TX need to be blocked + * + * Return: None + */ +void ucfg_dp_set_dfs_cac_tx(struct wlan_objmgr_vdev *vdev, + bool tx_block); + +/** + * ucfg_dp_set_bss_state_start() - update BSS state for SAP intf + * @vdev: vdev mapped to SAP DP interface + * @start: true if BSS state is started + * + * Return: None + */ +void ucfg_dp_set_bss_state_start(struct wlan_objmgr_vdev *vdev, bool start); + +/** + * ucfg_dp_lro_set_reset() - LRO set/reset in DP + * @vdev: vdev mapped to DP interface + * @enable_flag: Enable/disable LRO feature + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_lro_set_reset(struct wlan_objmgr_vdev *vdev, + uint8_t enable_flag); +/** + * ucfg_dp_is_ol_enabled() - Get ol enable/disable info + * @psoc: PSOC mapped to DP context + * + * Return: true if OL enabled + */ +bool ucfg_dp_is_ol_enabled(struct wlan_objmgr_psoc *psoc); + +#ifdef RECEIVE_OFFLOAD +/** + * ucfg_dp_rx_handle_concurrency() - Handle concurrency setting in DP + * @psoc: PSOC mapped to DP context + * @disable: true/false to disable/enable the Rx offload + * + * Return: None + */ +void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, + bool disable); +#else +static inline +void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, + bool disable) { } +#endif + +/** + * ucfg_dp_is_rx_common_thread_enabled() - Get common thread enable/disable info + * @psoc: PSOC mapped to DP context + * + * Return: true if common thread enabled + */ +bool ucfg_dp_is_rx_common_thread_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_is_rx_threads_enabled() - Get RX DP threads info + * @psoc: PSOC mapped to DP context + * + * Return: true if DP RX threads enabled + */ +bool ucfg_dp_is_rx_threads_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_rx_ol_init() - Initialize Rx offload mode (LRO or GRO) + * @psoc: PSOC mapped to DP context + * @is_wifi3_0_target: true if it wifi3.0 target + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_rx_ol_init(struct wlan_objmgr_psoc *psoc, + bool is_wifi3_0_target); + +/** + * ucfg_dp_start_xmit() - Transmit packet on STA interface + * @nbuf: n/w buffer to transmitted + * @vdev: vdev mapped to STA DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS +ucfg_dp_start_xmit(qdf_nbuf_t nbuf, struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_rx_packet_cbk() - Receive packet on STA interface + * @nbuf: n/w buffer to be received + * @vdev: vdev mapped to STA DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_rx_packet_cbk(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t nbuf); + +/** + * ucfg_dp_tx_timeout() - called during transmission timeout on STA + * @vdev: vdev mapped to STA DP interface + * + * Return: None + */ +void ucfg_dp_tx_timeout(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_softap_tx_timeout() - called during transmission timeout on SAP + * @vdev: vdev mapped to SAP DP interface + * + * Return: None + */ +void ucfg_dp_softap_tx_timeout(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_softap_start_xmit() - Transmit packet on SAP interface + * @nbuf: n/w buffer to transmitted + * @vdev: vdev mapped to SAP DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS +ucfg_dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_dev_stats() - Get netdev stats info + * @dev: Pointer to network device + * + * Return: qdf_net_dev_stats info + */ +qdf_net_dev_stats *ucfg_dp_get_dev_stats(qdf_netdev_t dev); + +/** + * ucfg_dp_inc_rx_pkt_stats() - DP increment RX pkt stats + * @vdev: VDEV mapped to DP interface + * @pkt_len: packet length to be incremented in stats + * @delivered: pkts delivered or not + * + * Return: None + */ +void ucfg_dp_inc_rx_pkt_stats(struct wlan_objmgr_vdev *vdev, + uint32_t pkt_len, + bool delivered); + +/** + * ucfg_dp_get_rx_softirq_yield_duration() - Get rx soft IRQ yield duration + * @psoc: pointer to psoc object + * + * Return: soft IRQ yield duration + */ +uint64_t +ucfg_dp_get_rx_softirq_yield_duration(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_register_rx_mic_error_ind_handler : register mic error handler. + * @soc: soc handle + */ +void ucfg_dp_register_rx_mic_error_ind_handler(void *soc); + +/** + * ucfg_dp_sta_register_txrx_ops() - Register ops for TX/RX operations in STA + * @vdev: vdev mapped to STA DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_sta_register_txrx_ops(struct wlan_objmgr_vdev *vdev); + +#ifdef FEATURE_WLAN_TDLS +/** + * ucfg_dp_tdlsta_register_txrx_ops() - Register ops for TX/RX operations + * @vdev: vdev mapped to TDLS STA DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_tdlsta_register_txrx_ops(struct wlan_objmgr_vdev *vdev); +#else +static inline +QDF_STATUS ucfg_dp_tdlsta_register_txrx_ops(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * ucfg_dp_ocb_register_txrx_ops() - Register ops for TX/RX operations + * @vdev: vdev mapped to OCB DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_ocb_register_txrx_ops(struct wlan_objmgr_vdev *vdev); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * ucfg_dp_mon_register_txrx_ops() - Register ops for TX/RX operations + * @vdev: vdev mapped to Monitor mode DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_mon_register_txrx_ops(struct wlan_objmgr_vdev *vdev); +#else +static inline +QDF_STATUS ucfg_dp_mon_register_txrx_ops(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * ucfg_dp_softap_register_txrx_ops() - Register ops for TX/RX operations + * @vdev: vdev mapped to SAP mode DP interface + * @txrx_ops: Tx and Rx data transfer ops + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS ucfg_dp_softap_register_txrx_ops(struct wlan_objmgr_vdev *vdev, + struct ol_txrx_ops *txrx_ops); + +/** + * ucfg_dp_register_pkt_capture_callbacks() - Register ops for pkt capture operations + * @vdev: vdev mapped to DP interface + * + * Return: 0 on success and non zero on failure. + */ +QDF_STATUS +ucfg_dp_register_pkt_capture_callbacks(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_bbm_context_init() - Initialize BBM context + * @psoc: psoc handle + * + * Returns: error code + */ +int ucfg_dp_bbm_context_init(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_bbm_context_deinit() - De-initialize BBM context + * @psoc: psoc handle + * + * Returns: None + */ +void ucfg_dp_bbm_context_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_bbm_apply_independent_policy() - Apply independent policies + * to set the bus bw level + * @psoc: psoc handle + * @params: BBM policy related params + * + * The function applies BBM related policies and appropriately sets the bus + * bandwidth level. + * + * Returns: None + */ +void ucfg_dp_bbm_apply_independent_policy(struct wlan_objmgr_psoc *psoc, + struct bbm_params *params); + +/** + * ucfg_dp_periodic_sta_stats_start() - Start displaying periodic stats for STA + * @vdev: Pointer to the vdev + * + * Return: none + */ +void ucfg_dp_periodic_sta_stats_start(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_periodic_sta_stats_stop() - Stop displaying periodic stats for STA + * @vdev: Pointer to the vdev + * + * Return: none + */ +void ucfg_dp_periodic_sta_stats_stop(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_set_rx_mode_rps() - Enable/disable RPS in SAP mode + * @enable: Set true to enable RPS in SAP mode + * + * Callback function registered with datapath + * + * Return: none + */ +void ucfg_dp_set_rx_mode_rps(bool enable); + +/** + * ucfg_dp_try_send_rps_ind() - send rps indication to daemon + * @vdev: vdev handle + * + * If RPS feature enabled by INI, send RPS enable indication to daemon + * Indication contents is the name of interface to find correct sysfs node + * Should send all available interfaces + * + * Return: none + */ +void ucfg_dp_try_send_rps_ind(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_reg_ipa_rsp_ind() - Resiter RSP IND cb with IPA component + * @pdev: pdev handle + * + * Returns: None + */ +void ucfg_dp_reg_ipa_rsp_ind(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_dp_try_set_rps_cpu_mask - set RPS CPU mask for interfaces + * @psoc: psoc handle + * + * Return: none + */ +void ucfg_dp_try_set_rps_cpu_mask(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_add_latency_critical_client() - Add latency critical client + * @vdev: vdev handle (Should not be NULL) + * @phymode: the phymode of the connected adapter + * + * This function checks if the present connection is latency critical + * and adds to the latency critical clients count and informs the + * datapath about this connection being latency critical. + * + * Returns: None + */ +void ucfg_dp_add_latency_critical_client(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_802_11_mode phymode); + +/** + * ucfg_dp_del_latency_critical_client() - Remove latency critical client + * @vdev: vdev handle (Should not be NULL) + * @phymode: the phymode of the connected adapter + * + * This function checks if the present connection was latency critical + * and removes from the latency critical clients count and informs the + * datapath about the removed connection being latency critical. + * + * Returns: None + */ +void ucfg_dp_del_latency_critical_client(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_802_11_mode phymode); + +/** + * ucfg_dp_reset_tcp_delack() - Reset TCP delay ACK + * level + * @psoc: psoc handle + * + * Return: None + */ +void ucfg_dp_reset_tcp_delack(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_set_current_throughput_level() - update the current vote + * level + * @psoc: psoc handle + * @next_vote_level: pld_bus_width_type voting level + * + * This function updates the current vote level to the new level + * provided + * + * Return: None + */ +void +ucfg_dp_set_current_throughput_level(struct wlan_objmgr_psoc *psoc, + enum pld_bus_width_type next_vote_level); + +/** + * ucfg_wlan_dp_display_tx_rx_histogram() - display tx rx histogram + * @psoc: psoc handle + * + * Return: none + */ +void ucfg_wlan_dp_display_tx_rx_histogram(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_wlan_dp_clear_tx_rx_histogram() - clear tx rx histogram + * @psoc: psoc handle + * + * Return: none + */ +void ucfg_wlan_dp_clear_tx_rx_histogram(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_set_high_bus_bw_request() - Set high bandwidth request. + * @psoc: psoc handle + * @vdev_id: vdev_id + * @high_bus_bw : High bus bandwidth requested + * + * Return: None. + */ +void +ucfg_dp_set_high_bus_bw_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool high_bus_bw); + +/** + * ucfg_dp_bus_bw_compute_timer_start() - start the bandwidth timer + * @psoc: psoc handle + * + * Return: None + */ +void ucfg_dp_bus_bw_compute_timer_start(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_bus_bw_compute_timer_try_start() - try to start the bandwidth timer + * @psoc: psoc handle + * + * This function ensures there is at least one intf in the associated state + * before starting the bandwidth timer. + * + * Return: None + */ +void ucfg_dp_bus_bw_compute_timer_try_start(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_bus_bw_compute_timer_stop() - stop the bandwidth timer + * @psoc: psoc handle + * + * Return: None + */ +void ucfg_dp_bus_bw_compute_timer_stop(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_bus_bw_compute_timer_try_stop() - try to stop the bandwidth timer + * @psoc: psoc handle + * + * This function ensures there are no interface in the associated state before + * stopping the bandwidth timer. + * + * Return: None + */ +void ucfg_dp_bus_bw_compute_timer_try_stop(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_bus_bw_compute_prev_txrx_stats() - get tx and rx stats + * @vdev: vdev handle + * + * This function get the collected tx and rx stats before starting + * the bus bandwidth timer. + * + * Return: None + */ +void ucfg_dp_bus_bw_compute_prev_txrx_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_bus_bw_compute_reset_prev_txrx_stats() - reset previous txrx stats + * @vdev: vdev handle + * + * This function resets the adapter previous tx rx stats. + * + * Return: None + */ +void +ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_nud_set_gateway_addr() - set gateway mac address + * @vdev: vdev handle + * @gw_mac_addr: mac address to be set + * + * Return: none + */ +void ucfg_dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr); + +/** + * ucfg_dp_nud_event() - netevent callback + * @netdev_mac_addr: netdev MAC addr + * @gw_mac_addr: Gateway MAC address + * @nud_state : NUD State + * + * Return: None + */ +void ucfg_dp_nud_event(struct qdf_mac_addr *netdev_mac_addr, + struct qdf_mac_addr *gw_mac_addr, + uint8_t nud_state); + +/** + * ucfg_dp_get_arp_stats_event_handler - ARP get stats event handler + * + * @psoc: PSOC Handle + * @rsp : response message + * + * Return : 0 on success else error code. + */ + +QDF_STATUS ucfg_dp_get_arp_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct dp_rsp_stats *rsp); + +/** + * ucfg_dp_get_arp_request_ctx - Get ARP request context + * + * @psoc: PSOC Handle + * + * Return : ARP request context + */ +void *ucfg_dp_get_arp_request_ctx(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_nud_reset_tracking() - reset NUD tracking + * @vdev: vdev handle + * + * Return: None + */ +void ucfg_dp_nud_reset_tracking(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_nud_tracking_enabled - Check if NUD tracking is enabled + * + * @psoc: PSOC Handle + * + * Return : NUD tracking value. + */ +uint8_t ucfg_dp_nud_tracking_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_nud_indicate_roam() - reset NUD when roaming happens + * @vdev: vdev handle + * + * Return: None + */ +void ucfg_dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_clear_arp_stats() - Clear ARP Stats + * @vdev: vdev context + * + * Return: None + */ +void ucfg_dp_clear_arp_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_clear_dns_stats() - Clear DNS Stats + * @vdev: vdev context + * + * Return: None + */ +void ucfg_dp_clear_dns_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_clear_tcp_stats() - Clear TCP Stats + * @vdev: vdev context + * + * Return: None + */ +void ucfg_dp_clear_tcp_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_clear_icmpv4_stats() - Clear ICMPv4 Stats + * @vdev: vdev context + * + * Return: None + */ +void ucfg_dp_clear_icmpv4_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_clear_dns_payload_value() - Clear DNS payload value + * @vdev: vdev context + * + * Return: None + */ +void ucfg_dp_clear_dns_payload_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_set_pkt_type_bitmap_value() - Set Packet type bitmap value + * @vdev: vdev context + * @value: bitmap value + * + * Return: None + */ +void ucfg_dp_set_pkt_type_bitmap_value(struct wlan_objmgr_vdev *vdev, + uint32_t value); + +/** + * ucfg_dp_intf_get_pkt_type_bitmap_value() - Get packt type bitmap info + * @intf_ctx: DP interface context + * + * Return: bitmap information + */ +uint32_t ucfg_dp_intf_get_pkt_type_bitmap_value(void *intf_ctx); + +/** + * ucfg_dp_set_track_dest_ipv4_value() - Set track_dest_ipv4 value + * @vdev: vdev context + * @value: dest ipv4 value + * + * Return: None + */ +void ucfg_dp_set_track_dest_ipv4_value(struct wlan_objmgr_vdev *vdev, + uint32_t value); + +/** + * ucfg_dp_set_track_dest_port_value() - Set track_dest_port value + * @vdev: vdev context + * @value: dest port value + * + * Return: None + */ +void ucfg_dp_set_track_dest_port_value(struct wlan_objmgr_vdev *vdev, + uint32_t value); + +/** + * ucfg_dp_set_track_src_port_value() - Set track_dest_port value + * @vdev: vdev context + * @value: src port value + * + * Return: None + */ +void ucfg_dp_set_track_src_port_value(struct wlan_objmgr_vdev *vdev, + uint32_t value); + +/** + * ucfg_dp_set_track_dns_domain_len_value() - Set track_dns_domain_len value + * @vdev: vdev context + * @value: dns domain len value + * + * Return: None + */ +void ucfg_dp_set_track_dns_domain_len_value(struct wlan_objmgr_vdev *vdev, + uint32_t value); + +/** + * ucfg_dp_set_track_arp_ip_value() - Set track_arp_ip value + * @vdev: vdev context + * @value: ARP IP value + * + * Return: None + */ +void ucfg_dp_set_track_arp_ip_value(struct wlan_objmgr_vdev *vdev, + uint32_t value); + +/** + * ucfg_dp_get_pkt_type_bitmap_value() - Get pkt_type_bitmap value + * @vdev: vdev context + * + * Return: pkt_type_bitmap value + */ +uint32_t ucfg_dp_get_pkt_type_bitmap_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_dns_payload_value() - Get dns_payload value + * @vdev: vdev context + * @dns_query : DNS query pointer + * + * Return: None + */ +void ucfg_dp_get_dns_payload_value(struct wlan_objmgr_vdev *vdev, + uint8_t *dns_query); + +/** + * ucfg_dp_get_track_dns_domain_len_value() - Get track_dns_domain_len value + * @vdev: vdev context + * + * Return: track_dns_domain_len value + */ +uint32_t ucfg_dp_get_track_dns_domain_len_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_track_dest_port_value() - Get track_dest_port value + * @vdev: vdev context + * + * Return: track_dest_port value + */ +uint32_t ucfg_dp_get_track_dest_port_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_track_src_port_value() - Get track_src_port value + * @vdev: vdev context + * + * Return: track_src_port value + */ +uint32_t ucfg_dp_get_track_src_port_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_track_dest_ipv4_value() - Get track_dest_ipv4 value + * @vdev: vdev context + * + * Return: track_dest_ipv4 value + */ +uint32_t ucfg_dp_get_track_dest_ipv4_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_dad_value() - Get dad value + * @vdev: vdev context + * + * Return: dad value + */ +bool ucfg_dp_get_dad_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_con_status_value() - Get con_status value + * @vdev: vdev context + * + * Return: con_status value + */ +bool ucfg_dp_get_con_status_value(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_link_id() - Get link_id + * @vdev: vdev context + * + * Return: link_id + */ +uint8_t ucfg_dp_get_link_id(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_arp_stats() - Get ARP stats + * @vdev: vdev context + * + * Return: ARP Stats + */ +struct dp_arp_stats *ucfg_dp_get_arp_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_icmpv4_stats() - Get ICMPv4 stats + * @vdev: vdev context + * + * Return: ICMPv4 Stats + */ +struct dp_icmpv4_stats +*ucfg_dp_get_icmpv4_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_tcp_stats() - Get TCP stats + * @vdev: vdev context + * + * Return: TCP Stats + */ +struct dp_tcp_stats *ucfg_dp_get_tcp_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_get_dns_stats() - Get DNS stats + * @vdev: vdev context + * + * Return: DNS Stats + */ +struct dp_dns_stats *ucfg_dp_get_dns_stats(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_set_nud_stats_cb() - Register callback with WMI + * @psoc: psoc context + * @cookie: callback context + * + * Return: None + */ + +void ucfg_dp_set_nud_stats_cb(struct wlan_objmgr_psoc *psoc, void *cookie); + +/** + * ucfg_dp_clear_nud_stats_cb() - Unregister callback with WMI + * @psoc: psoc context + * + * Return: None + */ +void ucfg_dp_clear_nud_stats_cb(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_set_dump_dp_trace() - set DP Trace + * @cmd_type : command + * @count : Number of lines to dump + * + * Return: None + */ +void ucfg_dp_set_dump_dp_trace(uint16_t cmd_type, uint16_t count); + +/** + * ucfg_dp_req_get_arp_stats() - Send Get ARP set request to FW + * @psoc: psoc context + * @params : Get ARP stats param + * + * Return: Status + */ +QDF_STATUS +ucfg_dp_req_get_arp_stats(struct wlan_objmgr_psoc *psoc, + struct dp_get_arp_stats_params *params); + +/** + * ucfg_dp_req_set_arp_stats() - Send Set ARP set request to FW + * @psoc: psoc context + * @params : Set ARP stats param + * + * Return: Status + */ +QDF_STATUS +ucfg_dp_req_set_arp_stats(struct wlan_objmgr_psoc *psoc, + struct dp_set_arp_stats_params *params); + +/** + * ucfg_dp_register_hdd_callbacks() - Resiter HDD callbacks with DP component + * @psoc: psoc handle + * @cb_obj: Callback object + * + * Returns: None + */ +void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_psoc_callbacks *cb_obj); + +/** + * ucfg_dp_register_event_handler() - Resiter event handler with DP component + * @psoc: psoc handle + * @cb_obj: Callback object + * + * Returns: None + */ +void ucfg_dp_register_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_psoc_nb_ops *cb_obj); + +/** + * ucfg_dp_get_bus_bw_compute_interval() - Get bus bandwidth compute interval + * @psoc: psoc handle + * + * Returns: Bus bandwidth compute interval + */ +uint32_t ucfg_dp_get_bus_bw_compute_interval(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_get_current_throughput_level() - get current bandwidth level + * @psoc: psoc handle + * + * Return: current bandwidth level + */ +int ucfg_dp_get_current_throughput_level(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_get_txrx_stats() - get dp txrx stats + * @vdev: vdev handle + * @dp_stats : dp_stats pointer + * + * This function update dp_stats pointer with DP component + * txrx stats + * Return: 0 on success + */ +QDF_STATUS ucfg_dp_get_txrx_stats(struct wlan_objmgr_vdev *vdev, + struct dp_tx_rx_stats *dp_stats); + +/* + * ucfg_dp_get_net_dev_stats(): Get netdev stats + * @vdev: vdev handle + * @stats: To hold netdev stats + * + * Return: None + */ +void ucfg_dp_get_net_dev_stats(struct wlan_objmgr_vdev *vdev, + qdf_net_dev_stats *stats); + +/* + * ucfg_dp_clear_net_dev_stats(): Clear netdev stats + * @dev: Pointer to netdev + * + * Return: None + */ +void ucfg_dp_clear_net_dev_stats(qdf_netdev_t dev); + +/** + * ucfg_dp_reset_cont_txtimeout_cnt() - Reset Tx Timeout count + * @vdev: vdev handle + * + * Return: None + */ +void ucfg_dp_reset_cont_txtimeout_cnt(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_dp_set_rx_thread_affinity() - Set rx thread affinity mask + * @psoc: psoc handle + * + * Return: None + */ +void ucfg_dp_set_rx_thread_affinity(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_get_disable_rx_ol_val() - Get Rx OL concurrency value + * @psoc: psoc handle + * @disable_conc : disable rx OL concurrency value + * @disable_low_tput : disable rx OL low tput value + * + * this function reads and update value in pointer variable + * passed as arguments to function. + * + * Return: None + */ + +void ucfg_dp_get_disable_rx_ol_val(struct wlan_objmgr_psoc *psoc, + uint8_t *disable_conc, + uint8_t *disable_low_tput); + +/** + * ucfg_dp_get_rx_aggregation_val() - Get Rx aggregation values + * @psoc: psoc handle + * + * Return: Rx aggregation value + */ +uint32_t ucfg_dp_get_rx_aggregation_val(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_set_rx_aggregation_val() - Set rx aggregation value + * @psoc: psoc handle + * @value : value to be set + * + * Return: None + */ +void ucfg_dp_set_rx_aggregation_val(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * ucfg_dp_set_tc_based_dyn_gro() - Set tc based dynamic gro + * @psoc: psoc handle + * @value : value to be set + * + * Return: None + */ +void ucfg_dp_set_tc_based_dyn_gro(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * ucfg_dp_runtime_disable_rx_thread() - Disable rx thread + * @vdev: vdev handle + * @value : value to be set (true/false) + * + * Return: None + */ +void ucfg_dp_runtime_disable_rx_thread(struct wlan_objmgr_vdev *vdev, + bool value); + +/** + * ucfg_dp_get_napi_enabled() - Get NAPI enabled/disabled info + * @psoc: psoc handle mapped to DP context + * + * Return: true if NAPI enabled + */ +bool ucfg_dp_get_napi_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_set_tc_ingress_prio() - Set tc ingress priority + * @psoc: psoc handle mapped to DP context + * @value: value to be set + * + * Return: None + */ +void ucfg_dp_set_tc_ingress_prio(struct wlan_objmgr_psoc *psoc, uint32_t value); + +/** + * ucfg_dp_nud_fail_data_stall_evt_enabled() - Check if NUD failuire data stall + * detection is enabled + * + * Return: True if the data stall event is enabled + */ +bool ucfg_dp_nud_fail_data_stall_evt_enabled(void); + +/** + * ucfg_dp_fw_data_stall_evt_enabled() - Check if Fw data stall + * detection is enabled + * + * Return: data stall event mask + */ +uint32_t ucfg_dp_fw_data_stall_evt_enabled(void); + +/** + * ucfg_dp_get_bus_bw_high_threshold() - Get the bus bw high threshold + * @psoc: psoc handle + * + * Return: current bus bw high threshold + */ +uint32_t ucfg_dp_get_bus_bw_high_threshold(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_event_eapol_log() - send event to wlan diag + * @nbuf: Network buffer ptr + * @dir: direction + * + * Return: None + */ +void ucfg_dp_event_eapol_log(qdf_nbuf_t nbuf, enum qdf_proto_dir dir); + +/** + * ucfg_dp_softap_inspect_dhcp_packet() - Inspect DHCP packet + * @vdev: Vdev handle + * @nbuf: pointer to network buffer + * @dir: direction + * + * Inspect the Tx/Rx frame, and send DHCP START/STOP notification to the FW + * through WMI message, during DHCP based IP address acquisition phase. + * + * Return: error number + */ +QDF_STATUS +ucfg_dp_softap_inspect_dhcp_packet(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t nbuf, enum qdf_proto_dir dir); + +void +dp_ucfg_enable_link_monitoring(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t threshold); + +void +dp_ucfg_disable_link_monitoring(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +#if defined(WLAN_SUPPORT_RX_FISA) +/** + * ucfg_dp_rx_skip_fisa() - Set flags to skip fisa aggregation + * @value: allow or skip fisa + * + * Return: None + */ +void ucfg_dp_rx_skip_fisa(uint32_t value); + +#else +static inline +void ucfg_dp_rx_skip_fisa(uint32_t value) +{ +} +#endif + +#ifdef DP_TRAFFIC_END_INDICATION +/** + * ucfg_dp_traffic_end_indication_get() - Get data end indication info + * @vdev: vdev handle + * @info: variable to hold stored data end indication info + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_dp_traffic_end_indication_get(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication *info); +/** + * ucfg_dp_traffic_end_indication_set() - Store data end indication info + * @vdev: vdev handle + * @info: variable holding new data end indication info + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_dp_traffic_end_indication_set(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication info); +/** + * ucfg_dp_traffic_end_indication_update_dscp() - update dscp value to default + * @psoc: psoc handle + * @vdev_id: vdev id + * @dscp: dscp value to be updated + * + * Return: void + */ +void +ucfg_dp_traffic_end_indication_update_dscp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + unsigned char *dscp); +#else +static inline QDF_STATUS +ucfg_dp_traffic_end_indication_get(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication *info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_dp_traffic_end_indication_set(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_dp_traffic_end_indication_update_dscp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + unsigned char *dscp) +{} +#endif + +/* + * ucfg_dp_prealloc_init() - Pre-allocate DP memory + * @ctrl_psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS ucfg_dp_prealloc_init(struct cdp_ctrl_objmgr_psoc *ctrl_psoc); + +/* + * ucfg_dp_prealloc_deinit() - Free pre-alloced DP memory + * + * Return: None + */ +void ucfg_dp_prealloc_deinit(void); + +#ifdef DP_MEM_PRE_ALLOC +/** + * ucfg_dp_prealloc_get_consistent_mem_unaligned() - gets pre-alloc unaligned + * consistent memory + * @size: total memory size + * @base_addr: pointer to dma address + * @ring_type: HAL ring type that requires memory + * + * Return: memory virtual address pointer on success, NULL on failure + */ +void *ucfg_dp_prealloc_get_consistent_mem_unaligned(qdf_size_t size, + qdf_dma_addr_t *base_addr, + uint32_t ring_type); + +/** + * ucfg_dp_prealloc_put_consistent_mem_unaligned() - puts back pre-alloc + * unaligned consistent memory + * @va_unaligned: memory virtual address pointer + * + * Return: None + */ +void ucfg_dp_prealloc_put_consistent_mem_unaligned(void *va_unaligned); + +/** + * ucfg_dp_prealloc_get_multi_pages() - gets pre-alloc DP multi-pages memory + * @desc_type: descriptor type + * @elem_size: single element size + * @elem_num: total number of elements should be allocated + * @pages: multi page information storage + * @cacheable: coherent memory or cacheable memory + * + * Return: None + */ +void ucfg_dp_prealloc_get_multi_pages(uint32_t desc_type, qdf_size_t elem_size, + uint16_t elem_num, + struct qdf_mem_multi_page_t *pages, + bool cacheable); + +/** + * ucfg_dp_prealloc_put_multi_pages() - puts back pre-alloc DP multi-pages + * memory + * @desc_type: descriptor type + * @pages: multi page information storage + * + * Return: None + */ +void ucfg_dp_prealloc_put_multi_pages(uint32_t desc_type, + struct qdf_mem_multi_page_t *pages); +#endif + +#ifdef FEATURE_DIRECT_LINK +/** + * ucfg_dp_direct_link_init() - Initializes Direct Link datapath + * @psoc: psoc handle + * + * Return: QDF status + */ +QDF_STATUS ucfg_dp_direct_link_init(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_dp_direct_link_deinit() - De-initializes Direct Link datapath + * @psoc: psoc handle + * @is_ssr: true if SSR is in progress else false + * + * Return: None + */ +void ucfg_dp_direct_link_deinit(struct wlan_objmgr_psoc *psoc, bool is_ssr); + +/** + * ucfg_dp_wfds_handle_request_mem_ind() - Process request memory indication + * received from QMI server + * @mem_msg: pointer to memory request indication message + * + * Return: None + */ +void +ucfg_dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg); + +/** + * ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind() - Process IPCC map and configure + * indication received from QMI server + * @ipcc_msg: pointer to IPCC map and configure indication message + * + * Return: None + */ +void +ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg); + +/** + * ucfg_dp_wfds_new_server() - New server callback triggered when service is up. + * Connect to the service as part of this call. + * + * Return: QDF status + */ +QDF_STATUS ucfg_dp_wfds_new_server(void); + +/** + * ucfg_dp_wfds_del_server() - Del server callback triggered when service is + * down. + * + * Return: None + */ +void ucfg_dp_wfds_del_server(void); + +/** + * ucfg_dp_config_direct_link() - Set direct link config for vdev + * @dev: netdev + * @config_direct_link: Flag to enable direct link path + * @enable_low_latency: Flag to enable low link latency + * + * Return: QDF Status + */ +QDF_STATUS ucfg_dp_config_direct_link(qdf_netdev_t dev, + bool config_direct_link, + bool enable_low_latency); +#else +static inline +QDF_STATUS ucfg_dp_direct_link_init(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_dp_direct_link_deinit(struct wlan_objmgr_psoc *psoc, bool is_ssr) +{ +} + +#ifdef QMI_WFDS +static inline void +ucfg_dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg) +{ +} + +static inline void +ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg) +{ +} + +static inline QDF_STATUS ucfg_dp_wfds_new_server(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_dp_wfds_del_server(void) +{ +} +#endif + +static inline +QDF_STATUS ucfg_dp_config_direct_link(qdf_netdev_t dev, + bool config_direct_link, + bool enable_low_latency) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ucfg_dp_bus_suspend() - BUS suspend DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_bus_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * ucfg_dp_bus_resume() - BUS resume DP handler + * @soc: CDP SoC handle + * @pdev_id: DP PDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_bus_resume(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * ucfg_dp_txrx_soc_attach() - Datapath soc attach + * @params: SoC attach params + * @is_wifi3_0_target: [OUT] Pointer to update if the target is wifi3.0 + * + * Return: SoC handle + */ +void *ucfg_dp_txrx_soc_attach(struct dp_txrx_soc_attach_params *params, + bool *is_wifi3_0_target); + +/** + * ucfg_dp_txrx_soc_detach() - Datapath SoC detach + * @soc: DP SoC handle + * + * Return: None + */ +void ucfg_dp_txrx_soc_detach(ol_txrx_soc_handle soc); + +/** + * ucfg_dp_txrx_attach_target() - DP target attach + * @soc: DP SoC handle + * @pdev_id: DP pdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_txrx_attach_target(ol_txrx_soc_handle soc, uint8_t pdev_id); + +/** + * ucfg_dp_txrx_pdev_attach() - DP pdev attach + * @soc: DP SoC handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_txrx_pdev_attach(ol_txrx_soc_handle soc); + +/** + * ucfg_dp_txrx_pdev_detach() - DP pdev detach + * @soc: DP SoC handle + * @pdev_id: DP pdev id + * @force: indicates if force detach is to be done or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_dp_txrx_pdev_detach(ol_txrx_soc_handle soc, uint8_t pdev_id, + int force); + +/** + * ucfg_dp_txrx_init() - initialize DP TXRX module + * @soc: ol_txrx_soc_handle + * @pdev_id: id of dp pdev handle + * @config: configuration for DP TXRX modules + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS ucfg_dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id, + struct dp_txrx_config *config); + +/** + * ucfg_dp_txrx_deinit() - de-initialize DP TXRX module + * @soc: ol_txrx_soc_handle + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS ucfg_dp_txrx_deinit(ol_txrx_soc_handle soc); + +/** + * ucfg_dp_txrx_ext_dump_stats() - dump txrx external module stats + * @soc: ol_txrx_soc_handle object + * @stats_id: id for the module whose stats are needed + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS ucfg_dp_txrx_ext_dump_stats(ol_txrx_soc_handle soc, + uint8_t stats_id); +/** + * ucfg_dp_txrx_set_cpu_mask() - set CPU mask for RX threads + * @soc: ol_txrx_soc_handle object + * @new_mask: New CPU mask pointer + * + * Return: QDF_STATUS_SUCCESS on success, error qdf status on failure + */ +QDF_STATUS ucfg_dp_txrx_set_cpu_mask(ol_txrx_soc_handle soc, + qdf_cpu_mask *new_mask); + +/** + * ucfg_dp_get_per_link_peer_stats() - Call to get per link peer stats + * @soc: soc handle + * @vdev_id: vdev_id of vdev object + * @peer_mac: mac address of the peer + * @peer_stats: destination buffer + * @peer_type: Peer type + * @num_link: Number of ML links + * + * NOTE: For peer_type = CDP_MLD_PEER_TYPE peer_stats should point to + * buffer of size = (sizeof(*peer_stats) * num_link) + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_dp_get_per_link_peer_stats(ol_txrx_soc_handle soc, uint8_t vdev_id, + uint8_t *peer_mac, + struct cdp_peer_stats *peer_stats, + enum cdp_peer_type peer_type, + uint8_t num_link); + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +/** + * ucfg_dp_is_local_pkt_capture_enabled() - Get local packet capture config + * @psoc: pointer to psoc object + * + * Return: true if local packet capture is enabled from ini + * false otherwise + */ +bool +ucfg_dp_is_local_pkt_capture_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_dp_is_local_pkt_capture_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /* WLAN_FEATURE_LOCAL_PKT_CAPTURE */ + +/** + * ucfg_dp_get_vdev_stats () - API to get vdev stats + * @soc: dp soc object + * @vdev_id: Vdev ID of vdev for which stats is requested + * @buf: Pointer to buffer in which stats need to be updated + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS ucfg_dp_get_vdev_stats(ol_txrx_soc_handle soc, uint8_t vdev_id, + struct cdp_vdev_stats *buf); + +/* + * ucfg_dp_set_mon_conf_flags(): Set monitor configuration flags + * @psoc: psoc handle + * @flags: monitor configuration flags + * + * Return: None + */ +void ucfg_dp_set_mon_conf_flags(struct wlan_objmgr_psoc *psoc, uint32_t flags); +#endif /* _WLAN_DP_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/src/wlan_dp_api.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/src/wlan_dp_api.c new file mode 100644 index 0000000000..eab29a6d99 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/src/wlan_dp_api.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_dp_api.c + * + */ + +#include "wlan_dp_main.h" +#include "wlan_dp_api.h" +#include +#include + +void wlan_dp_update_peer_map_unmap_version(uint8_t *version) +{ + __wlan_dp_update_peer_map_unmap_version(version); +} + +QDF_STATUS wlan_dp_runtime_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + return __wlan_dp_runtime_suspend(soc, pdev_id); +} + +QDF_STATUS wlan_dp_runtime_resume(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + return __wlan_dp_runtime_resume(soc, pdev_id); +} + +void wlan_dp_print_fisa_rx_stats(enum cdp_fisa_stats_id stats_id) +{ + dp_print_fisa_rx_stats(stats_id); +} + +void wlan_dp_set_fst_in_cmem(bool fst_in_cmem) +{ + dp_set_fst_in_cmem(fst_in_cmem); +} + +void wlan_dp_set_fisa_dynamic_aggr_size_support(bool dynamic_aggr_size_support) +{ + dp_set_fisa_dynamic_aggr_size_support(dynamic_aggr_size_support); +} + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +bool wlan_dp_is_local_pkt_capture_active(struct wlan_objmgr_psoc *psoc) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + union cdp_config_param_t param; + QDF_STATUS status; + + status = cdp_txrx_get_psoc_param(soc, CDP_MONITOR_FLAG, ¶m); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Unable to fetch monitor flags."); + return false; + } + + if (cdp_cfg_get(soc, cfg_dp_local_pkt_capture) && + !(QDF_MONITOR_FLAG_OTHER_BSS & param.cdp_monitor_flag)) + return true; + + return false; +} +#endif + +void wlan_dp_update_def_link(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_mac, + struct wlan_objmgr_vdev *vdev) +{ + __wlan_dp_update_def_link(psoc, intf_mac, vdev); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/src/wlan_dp_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/src/wlan_dp_ucfg_api.c new file mode 100644 index 0000000000..69bb4ad78d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dp/dispatcher/src/wlan_dp_ucfg_api.c @@ -0,0 +1,2894 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: public API related to the DP called by north bound HDD/OSIF + */ + +#include "wlan_dp_ucfg_api.h" +#include "wlan_ipa_ucfg_api.h" +#include "wlan_dp_main.h" +#include "wlan_dp_objmgr.h" +#include "wlan_pmo_obj_mgmt_api.h" +#include "cdp_txrx_cmn.h" +#include "cfg_ucfg_api.h" +#include "wlan_pmo_obj_mgmt_api.h" +#include "wlan_dp_objmgr.h" +#include "wlan_dp_bus_bandwidth.h" +#include "wlan_dp_periodic_sta_stats.h" +#include "wlan_dp_nud_tracking.h" +#include "wlan_dp_txrx.h" +#include "wlan_nlink_common.h" +#include "wlan_pkt_capture_api.h" +#include +#include +#include "wlan_dp_prealloc.h" +#include "wlan_dp_rx_thread.h" +#include +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_public_api.h" +#endif +#include "cdp_txrx_ctrl.h" + +#ifdef FEATURE_DIRECT_LINK +/** + * wlan_dp_set_vdev_direct_link_cfg() - Set direct link config in DP vdev + * @psoc: objmgr psoc handle + * @dp_intf: pointer to DP component interface handle + * + * Return: direct link configuration + */ +static inline +QDF_STATUS wlan_dp_set_vdev_direct_link_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_intf *dp_intf) +{ + struct wlan_dp_link *dp_link, *dp_link_next; + cdp_config_param_type vdev_param = {0}; + QDF_STATUS status; + + if (dp_intf->device_mode != QDF_SAP_MODE || + !dp_intf->dp_ctx->dp_direct_link_ctx) + return QDF_STATUS_SUCCESS; + + dp_for_each_link_held_safe(dp_intf, dp_link, dp_link_next) { + vdev_param.cdp_vdev_tx_to_fw = + dp_intf->direct_link_config.config_set; + status = cdp_txrx_set_vdev_param(wlan_psoc_get_dp_handle(psoc), + dp_link->link_id, + CDP_VDEV_TX_TO_FW, vdev_param); + if (QDF_IS_STATUS_ERROR(status)) + break; + } + + return status; +} +#else +static inline +QDF_STATUS wlan_dp_set_vdev_direct_link_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_intf *dp_intf) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static inline +QDF_STATUS wlan_dp_update_vdev_mac_addr(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_link *dp_link, + struct qdf_mac_addr *new_mac_addr) +{ + cdp_config_param_type vdev_param = {0}; + + qdf_mem_copy(&vdev_param.mac_addr, new_mac_addr, QDF_MAC_ADDR_SIZE); + + /* CDP API to change the mac address */ + return cdp_txrx_set_vdev_param(dp_ctx->cdp_soc, dp_link->link_id, + CDP_VDEV_SET_MAC_ADDR, vdev_param); +} + +static QDF_STATUS wlan_dp_register_link_switch_notifier(void) +{ + return wlan_mlo_mgr_register_link_switch_notifier( + WLAN_COMP_DP, + dp_link_switch_notification); +} + +static QDF_STATUS wlan_dp_unregister_link_switch_notifier(void) +{ + return wlan_mlo_mgr_unregister_link_switch_notifier(WLAN_COMP_DP); +} +#else +static inline +QDF_STATUS wlan_dp_update_vdev_mac_addr(struct wlan_dp_psoc_context *dp_ctx, + struct wlan_dp_link *dp_link, + struct qdf_mac_addr *new_mac_addr) +{ + /* Link switch should be done only for 802.11BE */ + qdf_assert(0); + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS wlan_dp_register_link_switch_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlan_dp_unregister_link_switch_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** Add sanity for multiple link switches in parallel */ +QDF_STATUS ucfg_dp_update_link_mac_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *new_mac_addr, + bool is_link_switch) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_link *dp_link; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + dp_ctx = dp_get_context(); + + dp_link = dp_get_vdev_priv_obj(vdev); + if (!is_dp_link_valid(dp_link)) { + dp_err("dp_link from vdev %pK is invalid", vdev); + return QDF_STATUS_E_INVAL; + } + + qdf_copy_macaddr(&dp_link->mac_addr, new_mac_addr); + + if (is_link_switch) + status = wlan_dp_update_vdev_mac_addr(dp_ctx, dp_link, + new_mac_addr); + + return status; +} + +void ucfg_dp_update_def_link(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_mac, + struct wlan_objmgr_vdev *vdev) + +{ + __wlan_dp_update_def_link(psoc, intf_mac, vdev); +} + +void ucfg_dp_update_intf_mac(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *cur_mac, + struct qdf_mac_addr *new_mac, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + + dp_intf = dp_get_intf_by_macaddr(dp_ctx, cur_mac); + if (!dp_intf) { + dp_err("DP interface not found addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(cur_mac->bytes)); + QDF_BUG(0); + return; + } + + dp_info("MAC update from " QDF_MAC_ADDR_FMT " to " QDF_MAC_ADDR_FMT "", + QDF_MAC_ADDR_REF(cur_mac->bytes), + QDF_MAC_ADDR_REF(new_mac->bytes)); + + qdf_copy_macaddr(&dp_intf->mac_addr, new_mac); + + /* + * update of dp_intf mac address happens only during dynamic mac + * address update. This is a special case, where the connection + * can change without vdevs getting deleted. + * Hence its expected to reset the def_link in dp_intf to the + * def_link used by UMAC, for the next connection. + */ + dp_link = dp_get_vdev_priv_obj(vdev); + dp_info("Try def_link update for dp_intf %pK from %pK to %pK (intf %pK id %d)", + dp_intf, dp_intf->def_link, dp_link, + dp_link ? dp_link->dp_intf : NULL, + dp_link ? dp_link->link_id : 255); + if (dp_link && dp_link->dp_intf == dp_intf) + dp_intf->def_link = dp_link; + + wlan_dp_set_vdev_direct_link_cfg(psoc, dp_intf); +} + +QDF_STATUS +ucfg_dp_create_intf(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_addr, + qdf_netdev_t ndev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + + dp_info("DP interface create addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(intf_addr->bytes)); + + dp_intf = __qdf_mem_malloc(sizeof(*dp_intf), __func__, __LINE__); + if (!dp_intf) { + dp_err("DP intf memory alloc failed addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(intf_addr->bytes)); + return QDF_STATUS_E_FAILURE; + } + + dp_intf->def_link = NULL; + dp_intf->dp_ctx = dp_ctx; + dp_intf->dev = ndev; + qdf_copy_macaddr(&dp_intf->mac_addr, intf_addr); + + qdf_spin_lock_bh(&dp_ctx->intf_list_lock); + qdf_list_insert_front(&dp_ctx->intf_list, &dp_intf->node); + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); + + qdf_spinlock_create(&dp_intf->dp_link_list_lock); + qdf_list_create(&dp_intf->dp_link_list, 0); + + dp_periodic_sta_stats_init(dp_intf); + dp_periodic_sta_stats_mutex_create(dp_intf); + dp_nud_init_tracking(dp_intf); + dp_mic_init_work(dp_intf); + qdf_atomic_init(&dp_ctx->num_latency_critical_clients); + qdf_atomic_init(&dp_intf->gro_disallowed); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_dp_destroy_intf(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *intf_addr) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + + dp_info("DP interface destroy addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(intf_addr->bytes)); + + dp_intf = dp_get_intf_by_macaddr(dp_ctx, intf_addr); + if (!dp_intf) { + dp_err("DP interface not found addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(intf_addr->bytes)); + return QDF_STATUS_E_FAILURE; + } + + if (dp_intf->device_mode == QDF_SAP_MODE) + dp_config_direct_link(dp_intf, false, false); + + dp_periodic_sta_stats_mutex_destroy(dp_intf); + dp_nud_deinit_tracking(dp_intf); + dp_mic_deinit_work(dp_intf); + + qdf_spinlock_destroy(&dp_intf->dp_link_list_lock); + qdf_list_destroy(&dp_intf->dp_link_list); + + qdf_spin_lock_bh(&dp_ctx->intf_list_lock); + qdf_list_remove_node(&dp_ctx->intf_list, &dp_intf->node); + qdf_spin_unlock_bh(&dp_ctx->intf_list_lock); + + __qdf_mem_free(dp_intf); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_dp_set_cmn_dp_handle(struct wlan_objmgr_psoc *psoc, + ol_txrx_soc_handle soc) +{ + struct wlan_dp_psoc_context *dp_ctx; + cdp_config_param_type soc_param; + QDF_STATUS status; + + dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + dp_ctx->cdp_soc = soc; + + soc_param.hal_soc_hdl = NULL; + status = cdp_txrx_get_psoc_param(dp_ctx->cdp_soc, CDP_TXRX_HAL_SOC_HDL, + &soc_param); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Unable to fetch hal soc handle"); + return; + } + + dp_ctx->hal_soc = soc_param.hal_soc_hdl; +} + +void ucfg_dp_set_hif_handle(struct wlan_objmgr_psoc *psoc, + struct hif_opaque_softc *hif_handle) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + + dp_ctx->hif_handle = hif_handle; +} + +QDF_STATUS ucfg_dp_init(void) +{ + QDF_STATUS status; + + dp_info("DP module dispatcher init"); + + if (dp_allocate_ctx() != QDF_STATUS_SUCCESS) { + dp_err("DP ctx allocation failed"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_COMP_DP, + dp_psoc_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to register psoc create handler for DP"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_COMP_DP, + dp_psoc_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to register psoc destroy handler for DP"); + goto fail_destroy_psoc; + } + + status = wlan_objmgr_register_pdev_create_handler( + WLAN_COMP_DP, + dp_pdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to register pdev create handler for DP"); + goto fail_create_pdev; + } + + status = wlan_objmgr_register_pdev_destroy_handler( + WLAN_COMP_DP, + dp_pdev_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to register pdev destroy handler for DP"); + goto fail_destroy_pdev; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_COMP_DP, + dp_vdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to register vdev create handler"); + goto fail_create_vdev; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_COMP_DP, + dp_vdev_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("Failed to register vdev destroy handler"); + goto fail_destroy_vdev; + } + + status = wlan_objmgr_register_peer_create_handler( + WLAN_COMP_DP, + dp_peer_obj_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("wlan_objmgr_register_peer_create_handler failed"); + goto fail_create_peer; + } + + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_COMP_DP, + dp_peer_obj_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("wlan_objmgr_register_peer_destroy_handler failed"); + goto fail_destroy_peer; + } + + status = wlan_dp_register_link_switch_notifier(); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("wlan_mlomgr_register_link_switch_handler failed"); + goto fail_link_switch; + } + + return QDF_STATUS_SUCCESS; + +fail_link_switch: + wlan_objmgr_unregister_peer_destroy_handler( + WLAN_COMP_DP, dp_peer_obj_destroy_notification, + NULL); + +fail_destroy_peer: + wlan_objmgr_unregister_peer_create_handler(WLAN_COMP_DP, + dp_peer_obj_create_notification, + NULL); + +fail_create_peer: + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_COMP_DP, + dp_vdev_obj_destroy_notification, + NULL); + +fail_destroy_vdev: + wlan_objmgr_unregister_vdev_create_handler( + WLAN_COMP_DP, + dp_vdev_obj_create_notification, NULL); + +fail_create_vdev: + wlan_objmgr_unregister_pdev_destroy_handler( + WLAN_COMP_DP, + dp_pdev_obj_destroy_notification, NULL); + +fail_destroy_pdev: + wlan_objmgr_unregister_pdev_create_handler( + WLAN_COMP_DP, + dp_pdev_obj_create_notification, NULL); + +fail_create_pdev: + wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_COMP_DP, + dp_psoc_obj_destroy_notification, NULL); +fail_destroy_psoc: + wlan_objmgr_unregister_psoc_create_handler( + WLAN_COMP_DP, + dp_psoc_obj_create_notification, NULL); + + dp_free_ctx(); + return status; +} + +QDF_STATUS ucfg_dp_deinit(void) +{ + QDF_STATUS status; + + dp_info("DP module dispatcher deinit"); + + /* de-register link switch handler */ + wlan_dp_unregister_link_switch_notifier(); + + /* de-register peer delete handler functions. */ + status = wlan_objmgr_unregister_peer_destroy_handler( + WLAN_COMP_DP, + dp_peer_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister DP peer destroy handler: %d", status); + + /* de-register peer create handler functions. */ + status = wlan_objmgr_unregister_peer_create_handler( + WLAN_COMP_DP, + dp_peer_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister DP peer create handler: %d", status); + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_COMP_DP, + dp_vdev_obj_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister vdev delete handler:%d", status); + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_COMP_DP, + dp_vdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister vdev create handler:%d", status); + + status = wlan_objmgr_unregister_pdev_destroy_handler( + WLAN_COMP_DP, + dp_pdev_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister pdev destroy handler:%d", status); + + status = wlan_objmgr_unregister_pdev_create_handler( + WLAN_COMP_DP, + dp_pdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister pdev create handler:%d", status); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_COMP_DP, + dp_psoc_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister DP psoc delete handle:%d", status); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_COMP_DP, + dp_psoc_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to unregister DP psoc create handle:%d", status); + + dp_free_ctx(); + + return status; +} + +/** + * ucfg_dp_suspend_handler() - suspend handler registered with PMO component + * @psoc: psoc handle + * @arg: Arguments passed by the suspend handler. + * + * This handler is used to update the wiphy suspend state in DP context + * + * Return: QDF_STATUS status -in case of success else return error + */ +static QDF_STATUS +ucfg_dp_suspend_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf, *dp_intf_next = NULL; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_FAILURE; + } + if (dp_ctx->enable_dp_rx_threads) { + status = dp_txrx_suspend(cds_get_context(QDF_MODULE_ID_SOC)); + + if (status != QDF_STATUS_SUCCESS) { + dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC)); + return status; + } + } + dp_ctx->is_suspend = true; + cdp_set_tx_pause(soc, true); + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + dp_intf->sap_tx_block_mask |= WLAN_DP_SUSPEND; + } + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_dp_resume_handler() - resume handler registered with PMO component + * @psoc: psoc handle + * @arg: Arguments passed by the resume handler. + * + * This handler is used to update the wiphy resume state in DP context + * + * Return: QDF_STATUS status -in case of success else return error + */ +static QDF_STATUS +ucfg_dp_resume_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf, *dp_intf_next = NULL; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_FAILURE; + } + + dp_ctx->is_suspend = false; + cdp_set_tx_pause(soc, false); + dp_for_each_intf_held_safe(dp_ctx, dp_intf, dp_intf_next) { + dp_intf->sap_tx_block_mask &= ~WLAN_DP_SUSPEND; + } + if (dp_ctx->enable_dp_rx_threads) + dp_txrx_resume(cds_get_context(QDF_MODULE_ID_SOC)); + return QDF_STATUS_SUCCESS; +} + +/** + * dp_register_pmo_handler() - register suspend and resume handler + * with PMO component + * + * Return: None + */ +static inline void dp_register_pmo_handler(void) +{ + pmo_register_suspend_handler(WLAN_COMP_DP, + ucfg_dp_suspend_handler, NULL); + + pmo_register_resume_handler(WLAN_COMP_DP, + ucfg_dp_resume_handler, NULL); +} + +/** + * dp_unregister_pmo_handler() - unregister suspend and resume handler + * with PMO component + * + * Return: None + */ +static inline void dp_unregister_pmo_handler(void) +{ + pmo_unregister_suspend_handler(WLAN_COMP_DP, ucfg_dp_suspend_handler); + + pmo_unregister_resume_handler(WLAN_COMP_DP, ucfg_dp_resume_handler); +} + +/** + * ucfg_dp_store_qdf_dev() - Store qdf device instance in DP component + * @psoc: psoc handle + * + * Return: QDF_STATUS status -in case of success else return error + */ +static inline QDF_STATUS +ucfg_dp_store_qdf_dev(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_FAILURE; + } + + dp_ctx->qdf_dev = wlan_psoc_get_qdf_dev(psoc); + if (!dp_ctx->qdf_dev) { + dp_err("QDF_DEV is NULL"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_dp_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_FAILURE; + } + + ucfg_dp_store_qdf_dev(psoc); + dp_rtpm_tput_policy_init(psoc); + dp_register_pmo_handler(); + dp_trace_init(psoc); + dp_bus_bandwidth_init(psoc); + qdf_wake_lock_create(&dp_ctx->rx_wake_lock, "qcom_rx_wakelock"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_dp_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_FAILURE; + } + + dp_rtpm_tput_policy_deinit(psoc); + dp_unregister_pmo_handler(); + dp_bus_bandwidth_deinit(psoc); + qdf_wake_lock_destroy(&dp_ctx->rx_wake_lock); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_dp_suspend_wlan(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return; + } + + dp_ctx->is_wiphy_suspended = true; +} + +void ucfg_dp_resume_wlan(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return; + } + + dp_ctx->is_wiphy_suspended = false; +} + +void ucfg_dp_wait_complete_tasks(void) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + dp_wait_complete_tasks(dp_ctx); +} + +/* + * During connect/disconnect this needs to be updated + */ + +void ucfg_dp_remove_conn_info(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + qdf_mem_zero(&dp_link->conn_info, + sizeof(struct wlan_dp_conn_info)); +} + +void ucfg_dp_conn_info_set_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + qdf_copy_macaddr(&dp_link->conn_info.bssid, bssid); +} + +void ucfg_dp_conn_info_set_arp_service(struct wlan_objmgr_vdev *vdev, + uint8_t proxy_arp_service) +{ + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_link->conn_info.proxy_arp_service = proxy_arp_service; +} + +void ucfg_dp_conn_info_set_peer_authenticate(struct wlan_objmgr_vdev *vdev, + uint8_t is_authenticated) +{ + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_link->conn_info.is_authenticated = is_authenticated; +} + +void ucfg_dp_conn_info_set_peer_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac) +{ + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + qdf_copy_macaddr(&dp_link->conn_info.peer_macaddr, peer_mac); +} + +void ucfg_dp_softap_check_wait_for_tx_eap_pkt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_softap_check_wait_for_tx_eap_pkt(dp_intf, mac_addr); +} + +void ucfg_dp_update_dhcp_state_on_disassoc(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + struct wlan_objmgr_peer *peer; + struct wlan_dp_sta_info *stainfo; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + peer = wlan_objmgr_get_peer_by_mac(dp_intf->dp_ctx->psoc, + mac_addr->bytes, + WLAN_DP_ID); + if (!peer) { + dp_err("Peer object not found mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return; + } + + stainfo = dp_get_peer_priv_obj(peer); + if (!stainfo) { + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); + return; + } + + /* Send DHCP STOP indication to FW */ + stainfo->dhcp_phase = DHCP_PHASE_ACK; + if (stainfo->dhcp_nego_status == DHCP_NEGO_IN_PROGRESS) + dp_post_dhcp_ind(dp_link, + stainfo->sta_mac.bytes, + 0); + stainfo->dhcp_nego_status = DHCP_NEGO_STOP; + wlan_objmgr_peer_release_ref(peer, WLAN_DP_ID); +} + +void ucfg_dp_set_dfs_cac_tx(struct wlan_objmgr_vdev *vdev, bool tx_block) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + if (tx_block) + dp_intf->sap_tx_block_mask |= DP_TX_DFS_CAC_BLOCK; + else + dp_intf->sap_tx_block_mask &= ~DP_TX_DFS_CAC_BLOCK; +} + +void ucfg_dp_set_bss_state_start(struct wlan_objmgr_vdev *vdev, bool start) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + if (start) { + dp_intf->sap_tx_block_mask &= ~DP_TX_SAP_STOP; + dp_intf->bss_state = BSS_INTF_START; + } else { + dp_intf->sap_tx_block_mask |= DP_TX_SAP_STOP; + dp_intf->bss_state = BSS_INTF_STOP; + } +} + +QDF_STATUS ucfg_dp_lro_set_reset(struct wlan_objmgr_vdev *vdev, + uint8_t enable_flag) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + return dp_lro_set_reset(dp_intf, enable_flag); +} + +bool ucfg_dp_is_ol_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return 0; + } + + return dp_ctx->ol_enable; +} + +#ifdef RECEIVE_OFFLOAD +void ucfg_dp_rx_handle_concurrency(struct wlan_objmgr_psoc *psoc, + bool disable) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return; + } + + if (disable) { + if (DP_BUS_BW_CFG(dp_ctx->dp_cfg.enable_tcp_delack)) { + struct wlan_rx_tp_data rx_tp_data; + + dp_info("Enable TCP delack as LRO disabled in concurrency"); + rx_tp_data.rx_tp_flags = TCP_DEL_ACK_IND; + rx_tp_data.level = + DP_BUS_BW_GET_RX_LVL(dp_ctx); + wlan_dp_update_tcp_rx_param(dp_ctx, &rx_tp_data); + dp_ctx->en_tcp_delack_no_lro = 1; + } + qdf_atomic_set(&dp_ctx->disable_rx_ol_in_concurrency, 1); + } else { + if (DP_BUS_BW_CFG(dp_ctx->dp_cfg.enable_tcp_delack)) { + dp_info("Disable TCP delack as LRO is enabled"); + dp_ctx->en_tcp_delack_no_lro = 0; + dp_reset_tcp_delack(psoc); + } + qdf_atomic_set(&dp_ctx->disable_rx_ol_in_concurrency, 0); + } +} + +QDF_STATUS ucfg_dp_rx_ol_init(struct wlan_objmgr_psoc *psoc, + bool is_wifi3_0_target) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_INVAL; + } + + return dp_rx_ol_init(dp_ctx, is_wifi3_0_target); +} +#else /* RECEIVE_OFFLOAD */ + +QDF_STATUS ucfg_dp_rx_ol_init(struct wlan_objmgr_psoc *psoc, + bool is_wifi3_0_target) +{ + dp_err("Rx_OL, LRO/GRO not supported"); + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +bool ucfg_dp_is_rx_common_thread_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_INVAL; + } + + return dp_ctx->enable_rxthread; +} + +bool ucfg_dp_is_rx_threads_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_INVAL; + } + + return dp_ctx->enable_dp_rx_threads; +} + +#ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT +/** + * dp_get_config_rx_softirq_limits() - Update DP rx softirq limit config + * datapath + * @psoc: psoc handle + * @params: DP Configuration parameters + * + * Return: None + */ +static +void dp_get_config_rx_softirq_limits(struct wlan_objmgr_psoc *psoc, + struct cdp_config_params *params) +{ + params->tx_comp_loop_pkt_limit = cfg_get(psoc, + CFG_DP_TX_COMP_LOOP_PKT_LIMIT); + params->rx_reap_loop_pkt_limit = cfg_get(psoc, + CFG_DP_RX_REAP_LOOP_PKT_LIMIT); + params->rx_hp_oos_update_limit = cfg_get(psoc, + CFG_DP_RX_HP_OOS_UPDATE_LIMIT); +} +#else +static +void dp_get_config_rx_softirq_limits(struct wlan_objmgr_psoc *psoc, + struct cdp_config_params *params) +{ +} +#endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */ + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/** + * dp_get_config_queue_threshold() - Update DP tx flow limit config + * datapath + * @psoc: psoc handle + * @params: DP Configuration parameters + * + * Return: None + */ +static void +dp_get_config_queue_threshold(struct wlan_objmgr_psoc *psoc, + struct cdp_config_params *params) +{ + params->tx_flow_stop_queue_threshold = + cfg_get(psoc, CFG_DP_TX_FLOW_STOP_QUEUE_TH); + params->tx_flow_start_queue_offset = + cfg_get(psoc, CFG_DP_TX_FLOW_START_QUEUE_OFFSET); +} +#else +static inline void +dp_get_config_queue_threshold(struct wlan_objmgr_psoc *psoc, + struct cdp_config_params *params) +{ +} +#endif + +QDF_STATUS +ucfg_dp_update_config(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_user_config *req) +{ + struct cdp_config_params params = {0}; + struct wlan_dp_psoc_context *dp_ctx; + QDF_STATUS status; + void *soc; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return QDF_STATUS_E_INVAL; + } + + dp_ctx->arp_connectivity_map = req->arp_connectivity_map; + soc = cds_get_context(QDF_MODULE_ID_SOC); + params.tso_enable = cfg_get(psoc, CFG_DP_TSO); + dp_ctx->dp_cfg.lro_enable = cfg_get(psoc, CFG_DP_LRO); + params.lro_enable = dp_ctx->dp_cfg.lro_enable; + + dp_get_config_queue_threshold(psoc, ¶ms); + params.flow_steering_enable = + cfg_get(psoc, CFG_DP_FLOW_STEERING_ENABLED); + params.napi_enable = dp_ctx->napi_enable; + params.p2p_tcp_udp_checksumoffload = + cfg_get(psoc, CFG_DP_P2P_TCP_UDP_CKSUM_OFFLOAD); + params.nan_tcp_udp_checksumoffload = + cfg_get(psoc, CFG_DP_NAN_TCP_UDP_CKSUM_OFFLOAD); + params.tcp_udp_checksumoffload = + cfg_get(psoc, CFG_DP_TCP_UDP_CKSUM_OFFLOAD); + params.ipa_enable = req->ipa_enable; + dp_ctx->dp_cfg.gro_enable = cfg_get(psoc, CFG_DP_GRO); + params.gro_enable = dp_ctx->dp_cfg.gro_enable; + params.tx_comp_loop_pkt_limit = cfg_get(psoc, + CFG_DP_TX_COMP_LOOP_PKT_LIMIT); + params.rx_reap_loop_pkt_limit = cfg_get(psoc, + CFG_DP_RX_REAP_LOOP_PKT_LIMIT); + params.rx_hp_oos_update_limit = cfg_get(psoc, + CFG_DP_RX_HP_OOS_UPDATE_LIMIT); + dp_get_config_rx_softirq_limits(psoc, ¶ms); + + status = cdp_update_config_parameters(soc, ¶ms); + if (status) { + dp_err("Failed to attach config parameters"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +uint64_t +ucfg_dp_get_rx_softirq_yield_duration(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return 0; + } + + return dp_ctx->dp_cfg.rx_softirq_max_yield_duration_ns; +} + +#if defined(WLAN_SUPPORT_RX_FISA) +/** + * dp_rx_register_fisa_ops() - FISA callback functions + * @txrx_ops: operations handle holding callback functions + * + * Return: None + */ +static inline void +dp_rx_register_fisa_ops(struct ol_txrx_ops *txrx_ops) +{ + txrx_ops->rx.osif_fisa_rx = wlan_dp_rx_fisa_cbk; + txrx_ops->rx.osif_fisa_flush = wlan_dp_rx_fisa_flush_by_ctx_id; +} +#else +static inline void +dp_rx_register_fisa_ops(struct ol_txrx_ops *txrx_ops) +{ +} +#endif + +#ifdef CONFIG_DP_PKT_ADD_TIMESTAMP +static QDF_STATUS wlan_dp_get_tsf_time(void *dp_link_ctx, + uint64_t input_time, + uint64_t *tsf_time) +{ + struct wlan_dp_link *dp_link = (struct wlan_dp_link *)dp_link_ctx; + struct wlan_dp_intf *dp_intf = dp_link->dp_intf; + struct wlan_dp_psoc_callbacks *dp_ops = &dp_intf->dp_ctx->dp_ops; + + dp_ops->dp_get_tsf_time(dp_intf->dev, + input_time, + tsf_time); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS wlan_dp_get_tsf_time(void *dp_link_ctx, + uint64_t input_time, + uint64_t *tsf_time) +{ + *tsf_time = 0; + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +QDF_STATUS ucfg_dp_sta_register_txrx_ops(struct wlan_objmgr_vdev *vdev) +{ + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + + if (dp_intf->dp_ctx->enable_dp_rx_threads) { + txrx_ops.rx.rx = dp_rx_pkt_thread_enqueue_cbk; + txrx_ops.rx.rx_stack = dp_rx_packet_cbk; + txrx_ops.rx.rx_flush = dp_rx_flush_packet_cbk; + txrx_ops.rx.rx_gro_flush = dp_rx_thread_gro_flush_ind_cbk; + } else { + txrx_ops.rx.rx = dp_rx_packet_cbk; + txrx_ops.rx.rx_stack = NULL; + txrx_ops.rx.rx_flush = NULL; + } + + if (wlan_dp_cfg_is_rx_fisa_enabled(&dp_intf->dp_ctx->dp_cfg) && + dp_intf->device_mode != QDF_MONITOR_MODE) { + dp_debug("FISA feature enabled"); + dp_rx_register_fisa_ops(&txrx_ops); + } + + txrx_ops.rx.stats_rx = dp_tx_rx_collect_connectivity_stats_info; + + txrx_ops.tx.tx_comp = dp_sta_notify_tx_comp_cb; + txrx_ops.tx.tx = NULL; + txrx_ops.get_tsf_time = wlan_dp_get_tsf_time; + txrx_ops.vdev_del_notify = wlan_dp_link_cdp_vdev_delete_notification; + cdp_vdev_register(soc, dp_link->link_id, (ol_osif_vdev_handle)dp_link, + &txrx_ops); + if (!txrx_ops.tx.tx) { + dp_err("vdev register fail"); + return QDF_STATUS_E_FAILURE; + } + + dp_link->cdp_vdev_registered = 1; + dp_link->cdp_vdev_deleted = 0; + dp_link->destroyed = 0; + + dp_intf->txrx_ops = txrx_ops; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS ucfg_dp_tdlsta_register_txrx_ops(struct wlan_objmgr_vdev *vdev) +{ + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + if (dp_intf->dp_ctx->enable_dp_rx_threads) { + txrx_ops.rx.rx = dp_rx_pkt_thread_enqueue_cbk; + txrx_ops.rx.rx_stack = dp_rx_packet_cbk; + txrx_ops.rx.rx_flush = dp_rx_flush_packet_cbk; + txrx_ops.rx.rx_gro_flush = dp_rx_thread_gro_flush_ind_cbk; + } else { + txrx_ops.rx.rx = dp_rx_packet_cbk; + txrx_ops.rx.rx_stack = NULL; + txrx_ops.rx.rx_flush = NULL; + } + + if (wlan_dp_cfg_is_rx_fisa_enabled(&dp_intf->dp_ctx->dp_cfg) && + dp_intf->device_mode != QDF_MONITOR_MODE) { + dp_debug("FISA feature enabled"); + dp_rx_register_fisa_ops(&txrx_ops); + } + + txrx_ops.rx.stats_rx = dp_tx_rx_collect_connectivity_stats_info; + + txrx_ops.tx.tx_comp = dp_sta_notify_tx_comp_cb; + txrx_ops.tx.tx = NULL; + + txrx_ops.vdev_del_notify = wlan_dp_link_cdp_vdev_delete_notification; + cdp_vdev_register(soc, dp_link->link_id, (ol_osif_vdev_handle)dp_link, + &txrx_ops); + + if (!txrx_ops.tx.tx) { + dp_err("vdev register fail"); + return QDF_STATUS_E_FAILURE; + } + + dp_link->cdp_vdev_registered = 1; + dp_link->cdp_vdev_deleted = 0; + dp_link->destroyed = 0; + dp_intf->txrx_ops = txrx_ops; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS ucfg_dp_ocb_register_txrx_ops(struct wlan_objmgr_vdev *vdev) +{ + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + /* Register the vdev transmit and receive functions */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = dp_rx_packet_cbk; + txrx_ops.rx.stats_rx = dp_tx_rx_collect_connectivity_stats_info; + txrx_ops.vdev_del_notify = wlan_dp_link_cdp_vdev_delete_notification; + + cdp_vdev_register(soc, dp_link->link_id, (ol_osif_vdev_handle)dp_link, + &txrx_ops); + if (!txrx_ops.tx.tx) { + dp_err("vdev register fail"); + return QDF_STATUS_E_FAILURE; + } + + dp_link->cdp_vdev_registered = 1; + dp_link->cdp_vdev_deleted = 0; + dp_link->destroyed = 0; + dp_intf->txrx_ops = txrx_ops; + + qdf_copy_macaddr(&dp_link->conn_info.peer_macaddr, + &dp_link->mac_addr); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +QDF_STATUS ucfg_dp_mon_register_txrx_ops(struct wlan_objmgr_vdev *vdev) +{ + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.rx.rx = dp_mon_rx_packet_cbk; + dp_monitor_set_rx_monitor_cb(&txrx_ops, dp_rx_monitor_callback); + txrx_ops.vdev_del_notify = wlan_dp_link_cdp_vdev_delete_notification; + cdp_vdev_register(soc, dp_link->link_id, + (ol_osif_vdev_handle)dp_link, + &txrx_ops); + + dp_link->cdp_vdev_registered = 1; + dp_link->cdp_vdev_deleted = 0; + dp_link->destroyed = 0; + dp_intf->txrx_ops = txrx_ops; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS ucfg_dp_softap_register_txrx_ops(struct wlan_objmgr_vdev *vdev, + struct ol_txrx_ops *txrx_ops) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + + /* Register the vdev transmit and receive functions */ + txrx_ops->tx.tx_comp = dp_softap_notify_tx_compl_cbk; + + if (dp_intf->dp_ctx->enable_dp_rx_threads) { + txrx_ops->rx.rx = dp_rx_pkt_thread_enqueue_cbk; + txrx_ops->rx.rx_stack = dp_softap_rx_packet_cbk; + txrx_ops->rx.rx_flush = dp_rx_flush_packet_cbk; + txrx_ops->rx.rx_gro_flush = dp_rx_thread_gro_flush_ind_cbk; + } else { + txrx_ops->rx.rx = dp_softap_rx_packet_cbk; + txrx_ops->rx.rx_stack = NULL; + txrx_ops->rx.rx_flush = NULL; + } + + txrx_ops->get_tsf_time = wlan_dp_get_tsf_time; + txrx_ops->vdev_del_notify = wlan_dp_link_cdp_vdev_delete_notification; + cdp_vdev_register(soc, + dp_link->link_id, + (ol_osif_vdev_handle)dp_link, + txrx_ops); + if (!txrx_ops->tx.tx) { + dp_err("vdev register fail"); + return QDF_STATUS_E_FAILURE; + } + + dp_link->cdp_vdev_registered = 1; + dp_link->cdp_vdev_deleted = 0; + dp_link->destroyed = 0; + dp_intf->txrx_ops = *txrx_ops; + dp_intf->sap_tx_block_mask &= ~DP_TX_FN_CLR; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_dp_register_pkt_capture_callbacks(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + return wlan_pkt_capture_register_callbacks(vdev, + dp_mon_rx_packet_cbk, + dp_intf); +} + +QDF_STATUS ucfg_dp_start_xmit(qdf_nbuf_t nbuf, struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link, *tx_dp_link; + QDF_STATUS status; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + + /* + * UMAC may queue TX on any vdev of the interface, but it may not be + * in sync with the def_link for DP, hence ignore the vdev from + * UMAC and select the tx_dp_link in DP. + * + * Since one link is already present in the dp_intf and validated above, + * the def_link is not expected to be NULL. Hence there is no need + * to validate tx_dp_link again. + */ + tx_dp_link = dp_intf->def_link; + qdf_atomic_inc(&dp_intf->num_active_task); + status = dp_start_xmit(tx_dp_link, nbuf); + qdf_atomic_dec(&dp_intf->num_active_task); + + return status; +} + +QDF_STATUS ucfg_dp_rx_packet_cbk(struct wlan_objmgr_vdev *vdev, qdf_nbuf_t nbuf) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + return dp_rx_packet_cbk(dp_link, nbuf); +} + +void ucfg_dp_tx_timeout(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_tx_timeout(dp_intf); +} + +QDF_STATUS +ucfg_dp_softap_start_xmit(qdf_nbuf_t nbuf, struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + QDF_STATUS status; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + qdf_atomic_inc(&dp_intf->num_active_task); + status = dp_softap_start_xmit(nbuf, dp_link); + qdf_atomic_dec(&dp_intf->num_active_task); + + return status; +} + +void ucfg_dp_softap_tx_timeout(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_softap_tx_timeout(dp_intf); +} + +qdf_net_dev_stats *ucfg_dp_get_dev_stats(qdf_netdev_t dev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + + dp_intf = dp_get_intf_by_netdev(dp_ctx, dev); + if (!dp_intf) { + dp_err("DP interface not found dev: %s", + qdf_netdev_get_devname(dev)); + QDF_BUG(0); + return NULL; + } + + return &dp_intf->stats; +} + +void ucfg_dp_inc_rx_pkt_stats(struct wlan_objmgr_vdev *vdev, + uint32_t pkt_len, + bool delivered) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + struct dp_tx_rx_stats *stats; + unsigned int cpu_index; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + cpu_index = qdf_get_cpu(); + stats = &dp_intf->dp_stats.tx_rx_stats; + + ++stats->per_cpu[cpu_index].rx_packets; + qdf_net_stats_add_rx_pkts(&dp_intf->stats, 1); + qdf_net_stats_add_rx_bytes(&dp_intf->stats, pkt_len); + + if (delivered) + ++stats->per_cpu[cpu_index].rx_delivered; + else + ++stats->per_cpu[cpu_index].rx_refused; +} + +void ucfg_dp_register_rx_mic_error_ind_handler(void *soc) +{ + cdp_register_rx_mic_error_ind_handler(soc, dp_rx_mic_error_ind); +} + +#ifdef WLAN_NUD_TRACKING +bool +ucfg_dp_is_roam_after_nud_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_psoc_cfg *dp_cfg; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return false; + } + + dp_cfg = &dp_ctx->dp_cfg; + if (!dp_cfg) { + dp_err("Unable to get DP config"); + return false; + } + + if (dp_cfg->enable_nud_tracking == DP_ROAM_AFTER_NUD_FAIL || + dp_cfg->enable_nud_tracking == DP_DISCONNECT_AFTER_ROAM_FAIL) + return true; + + return false; +} + +bool +ucfg_dp_is_disconect_after_roam_fail(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_psoc_cfg *dp_cfg; + + dp_ctx = dp_psoc_get_priv(psoc); + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return false; + } + + dp_cfg = &dp_ctx->dp_cfg; + if (!dp_cfg) { + dp_err("Unable to get DP config"); + return false; + } + + if (dp_cfg->enable_nud_tracking == DP_DISCONNECT_AFTER_ROAM_FAIL) + return true; + + return false; +} +#endif + +int ucfg_dp_bbm_context_init(struct wlan_objmgr_psoc *psoc) +{ + return dp_bbm_context_init(psoc); +} + +void ucfg_dp_bbm_context_deinit(struct wlan_objmgr_psoc *psoc) +{ + dp_bbm_context_deinit(psoc); +} + +void ucfg_dp_bbm_apply_independent_policy(struct wlan_objmgr_psoc *psoc, + struct bbm_params *params) +{ + dp_bbm_apply_independent_policy(psoc, params); +} + +void ucfg_dp_set_rx_mode_rps(bool enable) +{ + dp_set_rx_mode_rps(enable); +} + +void ucfg_dp_periodic_sta_stats_start(struct wlan_objmgr_vdev *vdev) +{ + dp_periodic_sta_stats_start(vdev); +} + +void ucfg_dp_periodic_sta_stats_stop(struct wlan_objmgr_vdev *vdev) +{ + dp_periodic_sta_stats_stop(vdev); +} + +void ucfg_dp_try_send_rps_ind(struct wlan_objmgr_vdev *vdev) +{ + dp_try_send_rps_ind(vdev); +} + +void ucfg_dp_reg_ipa_rsp_ind(struct wlan_objmgr_pdev *pdev) +{ + ucfg_ipa_reg_rps_enable_cb(pdev, dp_set_rps); +} + +void ucfg_dp_try_set_rps_cpu_mask(struct wlan_objmgr_psoc *psoc) +{ + dp_try_set_rps_cpu_mask(psoc); +} + +void ucfg_dp_add_latency_critical_client(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_802_11_mode phymode) +{ + dp_add_latency_critical_client(vdev, phymode); +} + +void ucfg_dp_del_latency_critical_client(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_802_11_mode phymode) +{ + dp_del_latency_critical_client(vdev, phymode); +} + +void ucfg_dp_reset_tcp_delack(struct wlan_objmgr_psoc *psoc) +{ + dp_reset_tcp_delack(psoc); +} + +void +ucfg_dp_set_current_throughput_level(struct wlan_objmgr_psoc *psoc, + enum pld_bus_width_type next_vote_level) +{ + dp_set_current_throughput_level(psoc, next_vote_level); +} + +void +ucfg_dp_set_high_bus_bw_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool high_bus_bw) +{ + dp_set_high_bus_bw_request(psoc, vdev_id, high_bus_bw); +} + +void ucfg_wlan_dp_display_tx_rx_histogram(struct wlan_objmgr_psoc *psoc) +{ + wlan_dp_display_tx_rx_histogram(psoc); +} + +void ucfg_wlan_dp_clear_tx_rx_histogram(struct wlan_objmgr_psoc *psoc) +{ + wlan_dp_clear_tx_rx_histogram(psoc); +} + +void ucfg_dp_bus_bw_compute_timer_start(struct wlan_objmgr_psoc *psoc) +{ + dp_bus_bw_compute_timer_start(psoc); +} + +void ucfg_dp_bus_bw_compute_timer_try_start(struct wlan_objmgr_psoc *psoc) +{ + dp_bus_bw_compute_timer_try_start(psoc); +} + +void ucfg_dp_bus_bw_compute_timer_stop(struct wlan_objmgr_psoc *psoc) +{ + dp_bus_bw_compute_timer_stop(psoc); +} + +void ucfg_dp_bus_bw_compute_timer_try_stop(struct wlan_objmgr_psoc *psoc) +{ + dp_bus_bw_compute_timer_try_stop(psoc); +} + +void ucfg_dp_bus_bw_compute_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) +{ + dp_bus_bw_compute_prev_txrx_stats(vdev); +} + +void +ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(struct wlan_objmgr_vdev *vdev) +{ + dp_bus_bw_compute_reset_prev_txrx_stats(vdev); +} + +void ucfg_dp_nud_set_gateway_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr gw_mac_addr) +{ + dp_nud_set_gateway_addr(vdev, gw_mac_addr); +} + +void ucfg_dp_nud_event(struct qdf_mac_addr *netdev_mac_addr, + struct qdf_mac_addr *gw_mac_addr, + uint8_t nud_state) +{ + dp_nud_netevent_cb(netdev_mac_addr, gw_mac_addr, nud_state); +} + +QDF_STATUS ucfg_dp_get_arp_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct dp_rsp_stats *rsp) +{ + return dp_get_arp_stats_event_handler(psoc, rsp); +} + +void *ucfg_dp_get_arp_request_ctx(struct wlan_objmgr_psoc *psoc) +{ + return dp_get_arp_request_ctx(psoc); +} + +void ucfg_dp_nud_reset_tracking(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_nud_reset_tracking(dp_intf); +} + +uint8_t ucfg_dp_nud_tracking_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP Context is NULL"); + return 0; + } + return dp_ctx->dp_cfg.enable_nud_tracking; +} + +void ucfg_dp_nud_indicate_roam(struct wlan_objmgr_vdev *vdev) +{ + dp_nud_indicate_roam(vdev); +} + +void ucfg_dp_clear_arp_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_zero(&dp_intf->dp_stats.arp_stats, + sizeof(dp_intf->dp_stats.arp_stats)); +} + +void ucfg_dp_clear_dns_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_zero(&dp_intf->dp_stats.dns_stats, + sizeof(dp_intf->dp_stats.dns_stats)); +} + +void ucfg_dp_clear_tcp_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_zero(&dp_intf->dp_stats.tcp_stats, + sizeof(dp_intf->dp_stats.tcp_stats)); +} + +void ucfg_dp_clear_icmpv4_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_zero(&dp_intf->dp_stats.icmpv4_stats, + sizeof(dp_intf->dp_stats.icmpv4_stats)); +} + +void ucfg_dp_clear_dns_payload_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_zero(dp_intf->dns_payload, dp_intf->track_dns_domain_len); +} + +void ucfg_dp_set_pkt_type_bitmap_value(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->pkt_type_bitmap = value; +} + +uint32_t ucfg_dp_intf_get_pkt_type_bitmap_value(void *intf_ctx) +{ + struct wlan_dp_intf *dp_intf = (struct wlan_dp_intf *)intf_ctx; + + if (!dp_intf) { + dp_err("Unable to get DP link"); + return 0; + } + + return dp_intf->pkt_type_bitmap; +} + +void ucfg_dp_set_track_dest_ipv4_value(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->track_dest_ipv4 = value; +} + +void ucfg_dp_set_track_dest_port_value(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->track_dest_port = value; +} + +void ucfg_dp_set_track_src_port_value(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->track_src_port = value; +} + +void ucfg_dp_set_track_dns_domain_len_value(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->track_dns_domain_len = value; +} + +void ucfg_dp_set_track_arp_ip_value(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->track_arp_ip = value; +} + +uint32_t ucfg_dp_get_pkt_type_bitmap_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->pkt_type_bitmap; +} + +void ucfg_dp_get_dns_payload_value(struct wlan_objmgr_vdev *vdev, + uint8_t *dns_query) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + qdf_mem_copy(dns_query, dp_intf->dns_payload, + dp_intf->track_dns_domain_len); +} + +uint32_t ucfg_dp_get_track_dns_domain_len_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->track_dns_domain_len; +} + +uint32_t ucfg_dp_get_track_dest_port_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->track_dest_port; +} + +uint32_t ucfg_dp_get_track_src_port_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->track_src_port; +} + +uint32_t ucfg_dp_get_track_dest_ipv4_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->track_dest_ipv4; +} + +bool ucfg_dp_get_dad_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->dad; +} + +bool ucfg_dp_get_con_status_value(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + dp_intf = dp_link->dp_intf; + return dp_intf->con_status; +} + +uint8_t ucfg_dp_get_link_id(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + + if (!dp_link) { + dp_err("Unable to get DP link"); + return 0; + } + + return dp_link->link_id; +} + +struct dp_arp_stats *ucfg_dp_get_arp_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return NULL; + } + + dp_intf = dp_link->dp_intf; + return &dp_intf->dp_stats.arp_stats; +} + +struct dp_icmpv4_stats *ucfg_dp_get_icmpv4_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return NULL; + } + + dp_intf = dp_link->dp_intf; + return &dp_intf->dp_stats.icmpv4_stats; +} + +struct dp_tcp_stats *ucfg_dp_get_tcp_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return NULL; + } + + dp_intf = dp_link->dp_intf; + return &dp_intf->dp_stats.tcp_stats; +} + +struct dp_dns_stats *ucfg_dp_get_dns_stats(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return NULL; + } + + dp_intf = dp_link->dp_intf; + return &dp_intf->dp_stats.dns_stats; +} + +void ucfg_dp_set_nud_stats_cb(struct wlan_objmgr_psoc *psoc, void *cookie) +{ + struct wlan_dp_psoc_sb_ops *sb_ops = dp_intf_get_tx_ops(psoc); + + if (!sb_ops) { + dp_err("Unable to get ops"); + return; + } + + sb_ops->dp_arp_stats_register_event_handler(psoc); + sb_ops->arp_request_ctx = cookie; +} + +void ucfg_dp_clear_nud_stats_cb(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_sb_ops *sb_ops = dp_intf_get_tx_ops(psoc); + + if (!sb_ops) { + dp_err("Unable to get ops"); + return; + } + + sb_ops->dp_arp_stats_unregister_event_handler(psoc); +} + +void ucfg_dp_set_dump_dp_trace(uint16_t cmd_type, uint16_t count) +{ + dp_set_dump_dp_trace(cmd_type, count); +} + +int ucfg_dp_get_current_throughput_level(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) + return 0; + + return dp_get_current_throughput_level(dp_ctx); +} + +uint32_t ucfg_dp_get_bus_bw_high_threshold(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) + return 0; + + return dp_get_bus_bw_high_threshold(dp_ctx); +} + +QDF_STATUS +ucfg_dp_req_get_arp_stats(struct wlan_objmgr_psoc *psoc, + struct dp_get_arp_stats_params *params) +{ + struct wlan_dp_psoc_sb_ops *sb_ops = dp_intf_get_tx_ops(psoc); + + if (!sb_ops) { + dp_err("Unable to get ops"); + return QDF_STATUS_E_INVAL; + } + + return sb_ops->dp_get_arp_req_stats(psoc, params); +} + +QDF_STATUS +ucfg_dp_req_set_arp_stats(struct wlan_objmgr_psoc *psoc, + struct dp_set_arp_stats_params *params) +{ + struct wlan_dp_psoc_sb_ops *sb_ops = dp_intf_get_tx_ops(psoc); + + if (!sb_ops) { + dp_err("Unable to get ops"); + return QDF_STATUS_E_INVAL; + } + + return sb_ops->dp_set_arp_req_stats(psoc, params); +} + +void ucfg_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_psoc_callbacks *cb_obj) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return; + } + dp_ctx->dp_ops.callback_ctx = cb_obj->callback_ctx; + dp_ctx->dp_ops.wlan_dp_sta_get_dot11mode = + cb_obj->wlan_dp_sta_get_dot11mode; + dp_ctx->dp_ops.wlan_dp_get_ap_client_count = + cb_obj->wlan_dp_get_ap_client_count; + dp_ctx->dp_ops.wlan_dp_sta_ndi_connected = + cb_obj->wlan_dp_sta_ndi_connected; + dp_ctx->dp_ops.dp_any_adapter_connected = + cb_obj->dp_any_adapter_connected; + dp_ctx->dp_ops.dp_send_svc_nlink_msg = cb_obj->dp_send_svc_nlink_msg; + dp_ctx->dp_ops.dp_pm_qos_update_request = + cb_obj->dp_pm_qos_update_request; + dp_ctx->dp_ops.dp_pld_remove_pm_qos = cb_obj->dp_pld_remove_pm_qos; + dp_ctx->dp_ops.dp_pld_request_pm_qos = cb_obj->dp_pld_request_pm_qos; + dp_ctx->dp_ops.dp_pm_qos_add_request = cb_obj->dp_pm_qos_add_request; + dp_ctx->dp_ops.dp_pm_qos_remove_request = + cb_obj->dp_pm_qos_remove_request; + dp_ctx->dp_ops.wlan_dp_display_tx_multiq_stats = + cb_obj->wlan_dp_display_tx_multiq_stats; + dp_ctx->dp_ops.wlan_dp_display_netif_queue_history = + cb_obj->wlan_dp_display_netif_queue_history; + dp_ctx->dp_ops.dp_send_mscs_action_frame = + cb_obj->dp_send_mscs_action_frame; + dp_ctx->dp_ops.dp_pktlog_enable_disable = + cb_obj->dp_pktlog_enable_disable; + dp_ctx->dp_ops.dp_is_roaming_in_progress = + cb_obj->dp_is_roaming_in_progress; + dp_ctx->dp_ops.dp_is_ap_active = cb_obj->dp_is_ap_active; + dp_ctx->dp_ops.dp_disable_rx_ol_for_low_tput = + cb_obj->dp_disable_rx_ol_for_low_tput; + dp_ctx->dp_ops.dp_napi_apply_throughput_policy = + cb_obj->dp_napi_apply_throughput_policy; + dp_ctx->dp_ops.dp_is_link_adapter = cb_obj->dp_is_link_adapter; + dp_ctx->dp_ops.dp_get_pause_map = cb_obj->dp_get_pause_map; + dp_ctx->dp_ops.dp_nud_failure_work = cb_obj->dp_nud_failure_work; + + dp_ctx->dp_ops.dp_get_tx_resource = cb_obj->dp_get_tx_resource; + dp_ctx->dp_ops.dp_get_tx_flow_low_watermark = + cb_obj->dp_get_tx_flow_low_watermark; + dp_ctx->dp_ops.dp_get_tsf_time = cb_obj->dp_get_tsf_time; + dp_ctx->dp_ops.dp_tsf_timestamp_rx = cb_obj->dp_tsf_timestamp_rx; + dp_ctx->dp_ops.dp_gro_rx_legacy_get_napi = + cb_obj->dp_gro_rx_legacy_get_napi; + dp_ctx->dp_ops.dp_get_netdev_by_vdev_mac = + cb_obj->dp_get_netdev_by_vdev_mac; + + dp_ctx->dp_ops.dp_nbuf_push_pkt = cb_obj->dp_nbuf_push_pkt; + dp_ctx->dp_ops.dp_rx_napi_gro_flush = cb_obj->dp_rx_napi_gro_flush; + dp_ctx->dp_ops.dp_rx_thread_napi_gro_flush = + cb_obj->dp_rx_thread_napi_gro_flush; + dp_ctx->dp_ops.dp_rx_napi_gro_receive = cb_obj->dp_rx_napi_gro_receive; + dp_ctx->dp_ops.dp_lro_rx_cb = cb_obj->dp_lro_rx_cb; + dp_ctx->dp_ops.dp_register_rx_offld_flush_cb = + cb_obj->dp_register_rx_offld_flush_cb; + dp_ctx->dp_ops.dp_rx_check_qdisc_configured = + cb_obj->dp_rx_check_qdisc_configured; + dp_ctx->dp_ops.dp_is_gratuitous_arp_unsolicited_na = + cb_obj->dp_is_gratuitous_arp_unsolicited_na; + dp_ctx->dp_ops.dp_send_rx_pkt_over_nl = cb_obj->dp_send_rx_pkt_over_nl; + dp_ctx->dp_ops.osif_dp_send_tcp_param_update_event = + cb_obj->osif_dp_send_tcp_param_update_event; + dp_ctx->dp_ops.os_if_dp_nud_stats_info = + cb_obj->os_if_dp_nud_stats_info; + dp_ctx->dp_ops.osif_dp_process_mic_error = + cb_obj->osif_dp_process_mic_error; + dp_ctx->dp_ops.link_monitoring_cb = cb_obj->link_monitoring_cb; + } + +void ucfg_dp_register_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_psoc_nb_ops *cb_obj) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return; + } + + dp_ctx->nb_ops.osif_dp_get_arp_stats_evt = + cb_obj->osif_dp_get_arp_stats_evt; +} + +uint32_t ucfg_dp_get_bus_bw_compute_interval(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return 0; + } + return DP_BUS_BW_CFG(dp_ctx->dp_cfg.bus_bw_compute_interval); +} + +QDF_STATUS ucfg_dp_get_txrx_stats(struct wlan_objmgr_vdev *vdev, + struct dp_tx_rx_stats *dp_stats) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + struct dp_tx_rx_stats *txrx_stats; + int i = 0, rx_mcast_drp = 0; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + txrx_stats = &dp_intf->dp_stats.tx_rx_stats; + for (i = 0; i < NUM_CPUS; i++) { + dp_stats->per_cpu[i].rx_packets = txrx_stats->per_cpu[i].rx_packets; + dp_stats->per_cpu[i].rx_dropped = txrx_stats->per_cpu[i].rx_dropped; + dp_stats->per_cpu[i].rx_delivered = txrx_stats->per_cpu[i].rx_delivered; + dp_stats->per_cpu[i].rx_refused = txrx_stats->per_cpu[i].rx_refused; + dp_stats->per_cpu[i].tx_called = txrx_stats->per_cpu[i].tx_called; + dp_stats->per_cpu[i].tx_dropped = txrx_stats->per_cpu[i].tx_dropped; + dp_stats->per_cpu[i].tx_orphaned = txrx_stats->per_cpu[i].tx_orphaned; + } + rx_mcast_drp = qdf_atomic_read(&txrx_stats->rx_usolict_arp_n_mcast_drp); + qdf_atomic_set(&dp_stats->rx_usolict_arp_n_mcast_drp, rx_mcast_drp); + + dp_stats->rx_aggregated = txrx_stats->rx_aggregated; + dp_stats->rx_gro_dropped = txrx_stats->rx_gro_dropped; + dp_stats->rx_non_aggregated = txrx_stats->rx_non_aggregated; + dp_stats->rx_gro_flush_skip = txrx_stats->rx_gro_flush_skip; + dp_stats->rx_gro_low_tput_flush = txrx_stats->rx_gro_low_tput_flush; + dp_stats->tx_timeout_cnt = txrx_stats->tx_timeout_cnt; + dp_stats->cont_txtimeout_cnt = txrx_stats->cont_txtimeout_cnt; + dp_stats->last_txtimeout = txrx_stats->last_txtimeout; + + return QDF_STATUS_SUCCESS; +} + +void ucfg_dp_get_net_dev_stats(struct wlan_objmgr_vdev *vdev, + qdf_net_dev_stats *stats) +{ + struct wlan_dp_link *dp_link; + struct wlan_dp_intf *dp_intf; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err_rl("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_get_net_dev_stats(dp_intf, stats); +} + +void ucfg_dp_clear_net_dev_stats(qdf_netdev_t dev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + if (qdf_unlikely(!dp_ctx)) { + dp_err_rl("DP context not found"); + return; + } + + dp_intf = dp_get_intf_by_netdev(dp_ctx, dev); + if (qdf_unlikely(!dp_intf)) { + dp_err_rl("DP interface not found"); + return; + } + + dp_clear_net_dev_stats(dp_intf); +} + +void ucfg_dp_reset_cont_txtimeout_cnt(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->dp_stats.tx_rx_stats.cont_txtimeout_cnt = 0; +} + +void ucfg_dp_set_rx_thread_affinity(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + struct wlan_dp_psoc_cfg *cfg; + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return; + } + cfg = &dp_ctx->dp_cfg; + + if (cfg->rx_thread_affinity_mask) + cds_set_rx_thread_cpu_mask(cfg->rx_thread_affinity_mask); + + if (cfg->rx_thread_ul_affinity_mask) + cds_set_rx_thread_ul_cpu_mask(cfg->rx_thread_ul_affinity_mask); +} + +void ucfg_dp_get_disable_rx_ol_val(struct wlan_objmgr_psoc *psoc, + uint8_t *disable_conc, + uint8_t *disable_low_tput) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + *disable_conc = qdf_atomic_read(&dp_ctx->disable_rx_ol_in_concurrency); + *disable_low_tput = qdf_atomic_read(&dp_ctx->disable_rx_ol_in_low_tput); +} + +uint32_t ucfg_dp_get_rx_aggregation_val(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return 0; + } + return qdf_atomic_read(&dp_ctx->dp_agg_param.rx_aggregation); +} + +void ucfg_dp_set_rx_aggregation_val(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return; + } + qdf_atomic_set(&dp_ctx->dp_agg_param.rx_aggregation, !!value); +} + +void ucfg_dp_set_tc_based_dyn_gro(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return; + } + dp_ctx->dp_agg_param.tc_based_dyn_gro = value; +} + +void ucfg_dp_runtime_disable_rx_thread(struct wlan_objmgr_vdev *vdev, + bool value) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->runtime_disable_rx_thread = value; +} + +bool ucfg_dp_get_napi_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("Unable to get DP context"); + return 0; + } + return dp_ctx->napi_enable; +} + +void ucfg_dp_set_tc_ingress_prio(struct wlan_objmgr_psoc *psoc, uint32_t value) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP ctx is NULL"); + return; + } + dp_ctx->dp_agg_param.tc_ingress_prio = value; +} + +bool ucfg_dp_nud_fail_data_stall_evt_enabled(void) +{ + return dp_is_data_stall_event_enabled(DP_HOST_NUD_FAILURE); +} + +uint32_t ucfg_dp_fw_data_stall_evt_enabled(void) +{ + return cdp_cfg_get(cds_get_context(QDF_MODULE_ID_SOC), + cfg_dp_enable_data_stall) & FW_DATA_STALL_EVT_MASK; +} + +void ucfg_dp_event_eapol_log(qdf_nbuf_t nbuf, enum qdf_proto_dir dir) +{ + dp_event_eapol_log(nbuf, dir); +} + +QDF_STATUS +ucfg_dp_softap_inspect_dhcp_packet(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t nbuf, enum qdf_proto_dir dir) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + + if (!dp_link) { + dp_err("Unable to get DP link"); + return QDF_STATUS_E_INVAL; + } + + return dp_softap_inspect_dhcp_packet(dp_link, nbuf, dir); +} + +void +dp_ucfg_enable_link_monitoring(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t threshold) +{ + struct wlan_dp_link *dp_link; + struct wlan_dp_intf *dp_intf; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->link_monitoring.rx_linkspeed_threshold = threshold; + dp_intf->link_monitoring.enabled = true; +} + +void +dp_ucfg_disable_link_monitoring(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + dp_link = dp_get_vdev_priv_obj(vdev); + if (unlikely(!dp_link)) { + dp_err("DP link not found"); + return; + } + + dp_intf = dp_link->dp_intf; + dp_intf->link_monitoring.enabled = false; + dp_intf->link_monitoring.rx_linkspeed_threshold = 0; +} + +#ifdef DP_TRAFFIC_END_INDICATION +QDF_STATUS +ucfg_dp_traffic_end_indication_get(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication *info) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + + info->enabled = dp_intf->traffic_end_ind.enabled; + info->def_dscp = dp_intf->traffic_end_ind.def_dscp; + info->spl_dscp = dp_intf->traffic_end_ind.spl_dscp; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_dp_traffic_end_indication_set(struct wlan_objmgr_vdev *vdev, + struct dp_traffic_end_indication info) +{ + struct wlan_dp_link *dp_link = dp_get_vdev_priv_obj(vdev); + struct wlan_dp_intf *dp_intf; + cdp_config_param_type vdev_param; + + if (!dp_link) { + dp_err("Unable to get DP link"); + return QDF_STATUS_E_INVAL; + } + + dp_intf = dp_link->dp_intf; + dp_intf->traffic_end_ind = info; + + dp_debug("enabled:%u default dscp:%u special dscp:%u", + dp_intf->traffic_end_ind.enabled, + dp_intf->traffic_end_ind.def_dscp, + dp_intf->traffic_end_ind.spl_dscp); + + vdev_param.cdp_vdev_param_traffic_end_ind = info.enabled; + if (cdp_txrx_set_vdev_param(cds_get_context(QDF_MODULE_ID_SOC), + dp_link->link_id, + CDP_ENABLE_TRAFFIC_END_INDICATION, + vdev_param)) + dp_err("Failed to set traffic end indication param on DP vdev"); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_dp_traffic_end_indication_update_dscp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + unsigned char *dscp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_dp_intf *dp_intf; + struct wlan_dp_link *dp_link; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_DP_ID); + if (vdev) { + dp_link = dp_get_vdev_priv_obj(vdev); + + if (!dp_link) { + dp_err("Unable to get DP link"); + goto end; + } + + dp_intf = dp_link->dp_intf; + if (!dp_intf->traffic_end_ind.enabled) + goto end; + + if (*dscp == dp_intf->traffic_end_ind.spl_dscp) + *dscp = dp_intf->traffic_end_ind.def_dscp; +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + } +} +#endif + +QDF_STATUS ucfg_dp_prealloc_init(struct cdp_ctrl_objmgr_psoc *ctrl_psoc) +{ + wlan_dp_select_profile_cfg((struct wlan_objmgr_psoc *)ctrl_psoc); + return dp_prealloc_init(ctrl_psoc); +} + +void ucfg_dp_prealloc_deinit(void) +{ + dp_prealloc_deinit(); +} + +#ifdef DP_MEM_PRE_ALLOC +void *ucfg_dp_prealloc_get_consistent_mem_unaligned(qdf_size_t size, + qdf_dma_addr_t *base_addr, + uint32_t ring_type) +{ + return dp_prealloc_get_consistent_mem_unaligned(size, base_addr, + ring_type); +} + +void ucfg_dp_prealloc_put_consistent_mem_unaligned(void *va_unaligned) +{ + dp_prealloc_put_consistent_mem_unaligned(va_unaligned); +} + +void ucfg_dp_prealloc_get_multi_pages(uint32_t desc_type, qdf_size_t elem_size, + uint16_t elem_num, + struct qdf_mem_multi_page_t *pages, + bool cacheable) +{ + dp_prealloc_get_multi_pages(desc_type, elem_size, elem_num, pages, + cacheable); +} + +void ucfg_dp_prealloc_put_multi_pages(uint32_t desc_type, + struct qdf_mem_multi_page_t *pages) +{ + dp_prealloc_put_multi_pages(desc_type, pages); +} +#endif + +#if defined(WLAN_SUPPORT_RX_FISA) +void ucfg_dp_rx_skip_fisa(uint32_t value) +{ + struct wlan_dp_psoc_context *dp_ctx; + + dp_ctx = dp_get_context(); + + if (dp_ctx) + dp_rx_skip_fisa(dp_ctx, value); +} +#endif + +#ifdef FEATURE_DIRECT_LINK +QDF_STATUS ucfg_dp_direct_link_init(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP context not found"); + return QDF_STATUS_E_FAILURE; + } + + return dp_direct_link_init(dp_ctx); +} + +void ucfg_dp_direct_link_deinit(struct wlan_objmgr_psoc *psoc, bool is_ssr) +{ + struct wlan_dp_psoc_context *dp_ctx = dp_psoc_get_priv(psoc); + + if (!dp_ctx) { + dp_err("DP context not found"); + return; + } + + dp_direct_link_deinit(dp_ctx, is_ssr); +} + +void +ucfg_dp_wfds_handle_request_mem_ind(struct wlan_qmi_wfds_mem_ind_msg *mem_msg) +{ + dp_wfds_handle_request_mem_ind(mem_msg); +} + +void +ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg *ipcc_msg) +{ + dp_wfds_handle_ipcc_map_n_cfg_ind(ipcc_msg); +} + +QDF_STATUS ucfg_dp_wfds_new_server(void) +{ + return dp_wfds_new_server(); +} + +void ucfg_dp_wfds_del_server(void) +{ + dp_wfds_del_server(); +} + +QDF_STATUS ucfg_dp_config_direct_link(qdf_netdev_t dev, + bool config_direct_link, + bool enable_low_latency) +{ + struct wlan_dp_psoc_context *dp_ctx; + struct wlan_dp_intf *dp_intf; + + dp_ctx = dp_get_context(); + if (!dp_ctx) + return QDF_STATUS_E_FAILURE; + + dp_intf = dp_get_intf_by_netdev(dp_ctx, dev); + if (!dp_intf) { + dp_err("Unable to get DP interface"); + return QDF_STATUS_E_INVAL; + } + + return dp_config_direct_link(dp_intf, config_direct_link, + enable_low_latency); +} +#endif + +QDF_STATUS ucfg_dp_bus_suspend(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + return __wlan_dp_bus_suspend(soc, pdev_id); +} + +QDF_STATUS ucfg_dp_bus_resume(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + return __wlan_dp_bus_resume(soc, pdev_id); +} + +void *ucfg_dp_txrx_soc_attach(struct dp_txrx_soc_attach_params *params, + bool *is_wifi3_0_target) +{ + return wlan_dp_txrx_soc_attach(params, is_wifi3_0_target); +} + +void ucfg_dp_txrx_soc_detach(ol_txrx_soc_handle soc) +{ + return wlan_dp_txrx_soc_detach(soc); +} + +QDF_STATUS ucfg_dp_txrx_attach_target(ol_txrx_soc_handle soc, uint8_t pdev_id) +{ + return wlan_dp_txrx_attach_target(soc, pdev_id); +} + +QDF_STATUS ucfg_dp_txrx_pdev_attach(ol_txrx_soc_handle soc) +{ + return wlan_dp_txrx_pdev_attach(soc); +} + +QDF_STATUS ucfg_dp_txrx_pdev_detach(ol_txrx_soc_handle soc, uint8_t pdev_id, + int force) +{ + return wlan_dp_txrx_pdev_detach(soc, pdev_id, force); +} + +QDF_STATUS ucfg_dp_txrx_init(ol_txrx_soc_handle soc, uint8_t pdev_id, + struct dp_txrx_config *config) +{ + return dp_txrx_init(soc, pdev_id, config); +} + +QDF_STATUS ucfg_dp_txrx_deinit(ol_txrx_soc_handle soc) +{ + return dp_txrx_deinit(soc); +} + +QDF_STATUS ucfg_dp_txrx_ext_dump_stats(ol_txrx_soc_handle soc, + uint8_t stats_id) +{ + return dp_txrx_ext_dump_stats(soc, stats_id); +} + +QDF_STATUS ucfg_dp_txrx_set_cpu_mask(ol_txrx_soc_handle soc, + qdf_cpu_mask *new_mask) +{ + return dp_txrx_set_cpu_mask(soc, new_mask); +} + +QDF_STATUS +ucfg_dp_get_per_link_peer_stats(ol_txrx_soc_handle soc, uint8_t vdev_id, + uint8_t *peer_mac, + struct cdp_peer_stats *peer_stats, + enum cdp_peer_type peer_type, + uint8_t num_link) +{ + return cdp_host_get_per_link_peer_stats(soc, vdev_id, peer_mac, + peer_stats, peer_type, + num_link); +} + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +bool ucfg_dp_is_local_pkt_capture_enabled(struct wlan_objmgr_psoc *psoc) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + return cdp_cfg_get(soc, cfg_dp_local_pkt_capture); +} +#endif + +QDF_STATUS ucfg_dp_get_vdev_stats(ol_txrx_soc_handle soc, uint8_t vdev_id, + struct cdp_vdev_stats *buf) +{ + return cdp_host_get_vdev_stats(soc, vdev_id, buf, true); +} + +void ucfg_dp_set_mon_conf_flags(struct wlan_objmgr_psoc *psoc, uint32_t flags) +{ + cdp_config_param_type val; + QDF_STATUS status; + struct wlan_dp_psoc_context *dp_ctx = dp_get_context(); + + if (!dp_ctx) { + dp_err("Failed to set flag %d, dp_ctx NULL", flags); + return; + } + + val.cdp_monitor_flag = flags; + status = cdp_txrx_set_psoc_param(dp_ctx->cdp_soc, + CDP_MONITOR_FLAG, val); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("Failed to set flag %d status %d", flags, status); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc.h b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc.h new file mode 100644 index 0000000000..00b715ba44 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Driver Synchronization Core (DSC) APIs for use by the driver + * orchestration layer. + * + * This infrastructure accomplishes two high level goals: + * 1) Replace ad-hoc locking/flags (hdd_init_deinit_lock, + * iface_change_lock, con_mode_flag, etc., etc., etc.) + * 2) Make cds_ssr_protect() and driver state checking atomic + * + * These two goals are commplished in DSC via two corollary concepts: + * 1) Transitions (as in driver state machine transitions) + * These are mutually exclusive, and replace ad-hoc locking + * 2) Operations (as in operations the driver is currently servicing) + * These execute concurrently with other operations, and replace + * cds_ssr_protect(). Any active transition causes new operations to be + * rejected, in the same way as cds_ssr_protect/hdd_validate_context would. + * + * Transitions and operations are split into 3 distinct levels: driver, psoc, + * and vdev. These levels are arranged into a tree, with a single driver at + * the root, zero or more psocs per driver, and zero or more vdevs per psoc. + * + * High level transitions block transitions and operations at the same level, + * down-tree, and up-tree. So a driver transition effectively prevents any new + * activity in the system, while a vdev transition prevents transitions and + * operations on the same vdev, its parent psoc, and the driver. This also means + * that sibling nodes can transition at the same time, e.g. one vdev going up at + * the same time another is going down. + */ + +#ifndef __WLAN_DSC_H +#define __WLAN_DSC_H + +#include "wlan_dsc_driver.h" +#include "wlan_dsc_psoc.h" +#include "wlan_dsc_vdev.h" + +#endif /* __WLAN_DSC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_driver.h b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_driver.h new file mode 100644 index 0000000000..f3d357575c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_driver.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Driver Synchronization Core (DSC) driver-level APIs + */ + +#ifndef __WLAN_DSC_DRIVER_H +#define __WLAN_DSC_DRIVER_H + +#include "qdf_status.h" + +/* + * struct dsc_driver - opaque dsc driver context + */ +struct dsc_driver; + +/** + * dsc_driver_create() - create a dsc driver context + * @out_driver: opaque double pointer to assign the new context to + * + * Return: QDF_STATUS + */ +QDF_STATUS dsc_driver_create(struct dsc_driver **out_driver); + +/** + * dsc_driver_destroy() - destroy a dsc driver context + * @out_driver: opaque double pointer to context to destroy and NULL + * + * Note, this: + * - aborts all queued transitions on @driver + * - asserts @driver has no attached psoc's + * - asserts @driver has no operations in flight + * + * Return: None + */ +void dsc_driver_destroy(struct dsc_driver **out_driver); + +/** + * dsc_driver_trans_start() - start a transition on @driver + * @driver: the driver to start a transition on + * @desc: a unique description of the transition to start + * + * This API immediately aborts if a transition on @driver is already in flight + * + * Call dsc_driver_trans_stop() to complete the transition. + * + * Return: + * QDF_STATUS_SUCCESS - transition started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - transition cannot currently be started + * QDF_STATUS_E_ALREADY - transition with @desc already in flight + */ +QDF_STATUS dsc_driver_trans_start(struct dsc_driver *driver, const char *desc); + +/** + * dsc_driver_trans_start_wait() - start a transition on @driver, blocking if a + * transition is already in flight + * @driver: the driver to start a transition on + * @desc: a unique description of the transition to start + * + * Call dsc_driver_trans_stop() to complete the transition. + * + * Return: + * QDF_STATUS_SUCCESS - transition started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - transition cannot currently be started + * QDF_STATUS_E_ALREADY - transition with @desc already queued or in flight + */ +QDF_STATUS +dsc_driver_trans_start_wait(struct dsc_driver *driver, const char *desc); + +/** + * dsc_driver_trans_stop() - complete current transition in flight on @driver + * @driver: the driver to complete the transition on + * + * Note: this asserts a transition is currently in flight on @driver + * + * Return: None + */ +void dsc_driver_trans_stop(struct dsc_driver *driver); + +/** + * dsc_driver_assert_trans_protected() - assert @driver is protected by a + * transition + * @driver: the driver to check + * + * Return: None + */ +void dsc_driver_assert_trans_protected(struct dsc_driver *driver); + +/** + * dsc_driver_op_start() - start an operation on @driver + * @driver: the driver to start an operation on + * + * Return: + * QDF_STATUS_SUCCESS - operation started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - operation cannot currently be started + * QDF_STATUS_E_NOMEM - out of memory + */ +#define dsc_driver_op_start(driver) _dsc_driver_op_start(driver, __func__) +QDF_STATUS _dsc_driver_op_start(struct dsc_driver *driver, const char *func); + +/** + * dsc_driver_op_stop() - complete operation with matching @func on @driver + * @driver: the driver to stop an operation on + * + * Note: this asserts @func was previously started + * + * Return: None + */ +#define dsc_driver_op_stop(driver) _dsc_driver_op_stop(driver, __func__) +void _dsc_driver_op_stop(struct dsc_driver *driver, const char *func); + +/** + * dsc_driver_wait_for_ops() - blocks until all operations on @driver have + * stopped + * @driver: the driver to wait for operations on + * + * Note: this asserts that @driver cannot currently transition + * + * Return: None + */ +void dsc_driver_wait_for_ops(struct dsc_driver *driver); + +#endif /* __WLAN_DSC_DRIVER_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_psoc.h b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_psoc.h new file mode 100644 index 0000000000..9bd749c404 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_psoc.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Driver Synchronization Core (DSC) psoc-level APIs + */ + +#ifndef __WLAN_DSC_PSOC_H +#define __WLAN_DSC_PSOC_H + +#include "qdf_status.h" +#include "wlan_dsc_driver.h" + +/* + * struct dsc_psoc - opaque dsc psoc context + */ +struct dsc_psoc; + +/** + * dsc_psoc_create() - create a dsc psoc context + * @driver: parent dsc driver context + * @out_psoc: opaque double pointer to assign the new context to + * + * Note: this attaches @out_psoc to @driver + * + * Return: QDF_STATUS + */ +QDF_STATUS +dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc); + +/** + * dsc_psoc_destroy() - destroy a dsc psoc context + * @out_psoc: opaque double pointer to context to destroy and NULL + * + * Note, this: + * - detaches @out_psoc from its parent driver context + * - aborts all queued transitions on @psoc + * - asserts @psoc has no attached vdev's + * - asserts @psoc has no operations in flight + * + * Return: None + */ +void dsc_psoc_destroy(struct dsc_psoc **out_psoc); + +/** + * dsc_psoc_trans_start() - start a transition on @psoc + * @psoc: the psoc to start a transition on + * @desc: a unique description of the transition to start + * + * This API immediately aborts if a transition on @psoc is already in flight + * + * Call dsc_psoc_trans_stop() to complete the transition. + * + * Return: + * QDF_STATUS_SUCCESS - transition started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - transition cannot currently be started + * QDF_STATUS_E_ALREADY - transition with @desc already in flight + */ +QDF_STATUS dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc); + +/** + * dsc_psoc_trans_start_wait() - start a transition on @psoc, blocking if a + * transition is already in flight + * @psoc: the psoc to start a transition on + * @desc: a unique description of the transition to start + * + * Call dsc_psoc_trans_stop() to complete the transition. + * + * Return: + * QDF_STATUS_SUCCESS - transition started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - transition cannot currently be started + * QDF_STATUS_E_ALREADY - transition with @desc already queued or in flight + * QDF_STATUS_E_ABORTED - transition was aborted + */ +QDF_STATUS dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc); + +/** + * dsc_psoc_trans_stop() - complete current transition in flight on @psoc + * @psoc: the psoc to complete the transition on + * + * Note: this asserts a transition is currently in flight on @psoc + * + * Return: None + */ +void dsc_psoc_trans_stop(struct dsc_psoc *psoc); + +/** + * dsc_psoc_assert_trans_protected() - assert @psoc is protected by a transition + * @psoc: the psoc to check + * + * The protecting transition may be in flight on @psoc or its parent. + * + * Return: None + */ +void dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc); + +/** + * dsc_psoc_op_start() - start an operation on @psoc + * @psoc: the psoc to start an operation on + * + * Return: + * QDF_STATUS_SUCCESS - operation started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - operation cannot currently be started + * QDF_STATUS_E_NOMEM - out of memory + */ +#define dsc_psoc_op_start(psoc) _dsc_psoc_op_start(psoc, __func__) +QDF_STATUS _dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func); + +/** + * dsc_psoc_op_stop() - complete operation with matching @func on @psoc + * @psoc: the psoc to stop an operation on + * + * Note: this asserts @func was previously started + * + * Return: None + */ +#define dsc_psoc_op_stop(psoc) _dsc_psoc_op_stop(psoc, __func__) +void _dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func); + +/** + * dsc_psoc_wait_for_ops() - blocks until all operations on @psoc have stopped + * @psoc: the psoc to wait for operations on + * + * Note: this asserts that @psoc cannot currently transition + * + * Return: None + */ +void dsc_psoc_wait_for_ops(struct dsc_psoc *psoc); + +#endif /* __WLAN_DSC_PSOC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_vdev.h b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_vdev.h new file mode 100644 index 0000000000..12d9518fad --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/inc/wlan_dsc_vdev.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Driver Synchronization Core (DSC) vdev-level APIs + */ + +#ifndef __WLAN_DSC_VDEV_H +#define __WLAN_DSC_VDEV_H + +#include "qdf_status.h" +#include "wlan_dsc_psoc.h" + +/* + * struct dsc_vdev - opaque dsc vdev context + */ +struct dsc_vdev; + +/** + * dsc_vdev_create() - create a dsc vdev context + * @psoc: parent dsc psoc context + * @out_vdev: opaque double pointer to assign the new context to + * + * Note: this attaches @out_vdev to @psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS dsc_vdev_create(struct dsc_psoc *psoc, struct dsc_vdev **out_vdev); + +/** + * dsc_vdev_destroy() - destroy a dsc vdev context + * @out_vdev: opaque double pointer to context to destroy and NULL + * + * Note, this: + * - detaches @out_vdev from its parent psoc context + * - aborts all queued transitions on @vdev + * - asserts @vdev has no operations in flight + * + * Return: None + */ +void dsc_vdev_destroy(struct dsc_vdev **out_vdev); + +/** + * dsc_vdev_trans_start() - start a transition on @vdev + * @vdev: the vdev to start a transition on + * @desc: a unique description of the transition to start + * + * This API immediately aborts if a transition on @vdev is already in flight + * + * Call dsc_vdev_trans_stop() to complete the transition. + * + * Return: + * QDF_STATUS_SUCCESS - transition started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - transition cannot currently be started + * QDF_STATUS_E_ALREADY - transition with @desc already in flight + */ +QDF_STATUS dsc_vdev_trans_start(struct dsc_vdev *vdev, const char *desc); + +/** + * dsc_vdev_trans_start_wait() - start a transition on @vdev, blocking if a + * transition is already in flight + * @vdev: the vdev to start a transition on + * @desc: a unique description of the transition to start + * + * Call dsc_vdev_trans_stop() to complete the transition. + * + * Return: + * QDF_STATUS_SUCCESS - transition started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - transition cannot currently be started + * QDF_STATUS_E_ALREADY - transition with @desc already queued or in flight + * QDF_STATUS_E_ABORTED - transition was aborted + */ +QDF_STATUS dsc_vdev_trans_start_wait(struct dsc_vdev *vdev, const char *desc); + +/** + * dsc_vdev_trans_stop() - complete current transition in flight on @vdev + * @vdev: the vdev to complete the transition on + * + * Note: this asserts a transition is currently in flight on @vdev + * + * Return: None + */ +void dsc_vdev_trans_stop(struct dsc_vdev *vdev); + +/** + * dsc_vdev_assert_trans_protected() - assert @vdev is protected by a transition + * @vdev: the vdev to check + * + * The protecting transition may be in flight on @vdev or its ancestors. + * + * Return: None + */ +void dsc_vdev_assert_trans_protected(struct dsc_vdev *vdev); + +/** + * dsc_vdev_op_start() - start an operation on @vdev + * @vdev: the vdev to start an operation on + * + * Return: + * QDF_STATUS_SUCCESS - operation started successfully + * QDF_STATUS_E_INVAL - invalid request (causes debug panic) + * QDF_STATUS_E_AGAIN - operation cannot currently be started + * QDF_STATUS_E_NOMEM - out of memory + */ +#define dsc_vdev_op_start(vdev) _dsc_vdev_op_start(vdev, __func__) +QDF_STATUS _dsc_vdev_op_start(struct dsc_vdev *vdev, const char *func); + +/** + * dsc_vdev_op_stop() - complete operation with matching @func on @vdev + * @vdev: the vdev to stop an operation on + * + * Note: this asserts @func was previously started + * + * Return: None + */ +#define dsc_vdev_op_stop(vdev) _dsc_vdev_op_stop(vdev, __func__) +void _dsc_vdev_op_stop(struct dsc_vdev *vdev, const char *func); + +/** + * dsc_vdev_wait_for_ops() - blocks until all operations on @vdev have stopped + * @vdev: the vdev to wait for operations on + * + * Note: this asserts that @vdev cannot currently transition + * + * Return: None + */ +void dsc_vdev_wait_for_ops(struct dsc_vdev *vdev); + +/** + * dsc_vdev_get_cached_cmd() - Get north bound cmd cached during SSR + * @vdev: Pointer to the dsc vdev + * + * This api will be invoked after completion of SSR re-initialization to get + * the last north bound command received during SSR + * + * Return: North bound command ID + */ +uint8_t dsc_vdev_get_cached_cmd(struct dsc_vdev *vdev); + +/** + * dsc_vdev_cache_command() - Cache north bound command during SSR + * @vdev: Pointer to the dsc vdev corresponding to the network interface + * @cmd_id: North bound command ID + * + * This api will be invoked when a north bound command is received during SSR + * and it should be handled after SSR re-initialization. + * + * Return: None + */ +void dsc_vdev_cache_command(struct dsc_vdev *vdev, uint8_t cmd_id); + +/* + * dsc_vdev_wait_for_uptree_ops() - Wait for any uptree operations + * @vdev: The DSC vdev + * + * This function checks and waits for any uptree operations if there is any + * uptree operation is in progress. + * + * Return: None. + */ + +void dsc_vdev_wait_for_uptree_ops(struct dsc_vdev *vdev); + +#endif /* __WLAN_DSC_VDEV_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/__wlan_dsc.c b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/__wlan_dsc.c new file mode 100644 index 0000000000..0c3c053d2d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/__wlan_dsc.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_list.h" +#include "qdf_mem.h" +#include "qdf_status.h" +#include "qdf_str.h" +#include "qdf_threads.h" +#include "qdf_timer.h" +#include "__wlan_dsc.h" +#include "cds_api.h" + +#ifdef WLAN_DSC_DEBUG +static void __dsc_dbg_op_timeout(void *opaque_op) +{ + struct dsc_op *op = opaque_op; + + qdf_print_thread_trace(op->thread); + QDF_DEBUG_PANIC("Operation '%s' exceeded %ums", + op->func, DSC_OP_TIMEOUT_MS); +} + +/** + * __dsc_dbg_ops_init() - initialize debug ops data structures + * @ops: the ops container to initialize + * + * Return: None + */ +static inline void __dsc_dbg_ops_init(struct dsc_ops *ops) +{ + qdf_list_create(&ops->list, 0); +} + +/** + * __dsc_dbg_ops_deinit() - de-initialize debug ops data structures + * @ops: the ops container to de-initialize + * + * Return: None + */ +static inline void __dsc_dbg_ops_deinit(struct dsc_ops *ops) +{ + qdf_list_destroy(&ops->list); +} + +/** + * __dsc_dbg_ops_insert() - insert @func into the debug information in @ops + * @ops: the ops container to insert into + * @func: the debug information to insert + * + * Return: QDF_STATUS + */ +static QDF_STATUS __dsc_dbg_ops_insert(struct dsc_ops *ops, const char *func) +{ + QDF_STATUS status; + struct dsc_op *op; + + op = qdf_mem_malloc(sizeof(*op)); + if (!op) + return QDF_STATUS_E_NOMEM; + + op->thread = qdf_get_current_task(); + status = qdf_timer_init(NULL, &op->timeout_timer, __dsc_dbg_op_timeout, + op, QDF_TIMER_TYPE_SW); + if (QDF_IS_STATUS_ERROR(status)) + goto free_op; + + op->func = func; + + qdf_timer_start(&op->timeout_timer, DSC_OP_TIMEOUT_MS); + qdf_list_insert_back(&ops->list, &op->node); + + return QDF_STATUS_SUCCESS; + +free_op: + qdf_mem_free(op); + + return status; +} + +/** + * __dsc_dbg_ops_remove() - remove @func from the debug information in @ops + * @ops: the ops container to remove from + * @func: the debug information to remove + * + * Return: None + */ +static void __dsc_dbg_ops_remove(struct dsc_ops *ops, const char *func) +{ + struct dsc_op *op; + + /* Global pending op depth is usually <=3. Use linear search for now */ + qdf_list_for_each(&ops->list, op, node) { + if (!qdf_str_eq(op->func, func)) + continue; + + /* this is safe because we cease iteration */ + qdf_list_remove_node(&ops->list, &op->node); + + qdf_timer_stop(&op->timeout_timer); + qdf_timer_free(&op->timeout_timer); + qdf_mem_free(op); + + return; + } + + QDF_DEBUG_PANIC("Driver op '%s' is not pending", func); +} +#else +static inline void __dsc_dbg_ops_init(struct dsc_ops *ops) { } + +static inline void __dsc_dbg_ops_deinit(struct dsc_ops *ops) { } + +static inline QDF_STATUS +__dsc_dbg_ops_insert(struct dsc_ops *ops, const char *func) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +__dsc_dbg_ops_remove(struct dsc_ops *ops, const char *func) { } +#endif /* WLAN_DSC_DEBUG */ + +void __dsc_ops_init(struct dsc_ops *ops) +{ + ops->count = 0; + qdf_event_create(&ops->event); + __dsc_dbg_ops_init(ops); +} + +void __dsc_ops_deinit(struct dsc_ops *ops) +{ + /* assert no ops in flight */ + dsc_assert(!ops->count); + + __dsc_dbg_ops_deinit(ops); + qdf_event_destroy(&ops->event); +} + +QDF_STATUS __dsc_ops_insert(struct dsc_ops *ops, const char *func) +{ + QDF_STATUS status; + + status = __dsc_dbg_ops_insert(ops, func); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + ops->count++; + + return QDF_STATUS_SUCCESS; +} + +bool __dsc_ops_remove(struct dsc_ops *ops, const char *func) +{ + dsc_assert(ops->count); + ops->count--; + + __dsc_dbg_ops_remove(ops, func); + + return ops->count == 0; +} + +#ifdef WLAN_DSC_DEBUG +static void __dsc_dbg_trans_timeout(void *opaque_trans) +{ + struct dsc_trans *trans = opaque_trans; + + qdf_print_thread_trace(trans->thread); + + if (cds_is_fw_down() && + !qdf_str_eq(trans->active_desc, "hdd_soc_recovery_shutdown")) + dsc_err("fw is down avoid panic"); + else + QDF_DEBUG_PANIC("Transition '%s' exceeded %ums", + trans->active_desc, DSC_TRANS_TIMEOUT_MS); +} + +/** + * __dsc_dbg_trans_timeout_start() - start a timeout timer for @trans + * @trans: the active transition to start a timeout timer for + * + * Return: QDF_STATUS + */ +static QDF_STATUS __dsc_dbg_trans_timeout_start(struct dsc_trans *trans) +{ + QDF_STATUS status; + + trans->thread = qdf_get_current_task(); + status = qdf_timer_init(NULL, &trans->timeout_timer, + __dsc_dbg_trans_timeout, trans, + QDF_TIMER_TYPE_SW); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + qdf_timer_start(&trans->timeout_timer, DSC_TRANS_TIMEOUT_MS); + + return QDF_STATUS_SUCCESS; +} + +/** + * __dsc_dbg_trans_timeout_stop() - stop the timeout timer for @trans + * @trans: the active transition to stop the timeout timer for + * + * Return: None + */ +static void __dsc_dbg_trans_timeout_stop(struct dsc_trans *trans) +{ + qdf_timer_stop(&trans->timeout_timer); + qdf_timer_free(&trans->timeout_timer); +} + +static void __dsc_dbg_tran_wait_timeout(void *opaque_tran) +{ + struct dsc_tran *tran = opaque_tran; + + qdf_print_thread_trace(tran->thread); + QDF_DEBUG_PANIC("Transition '%s' waited more than %ums", + tran->desc, DSC_TRANS_WAIT_TIMEOUT_MS); +} + +/** + * __dsc_dbg_tran_wait_timeout_start() - start a timeout timer for @tran + * @tran: the pending transition to start a timeout timer for + * + * Return: QDF_STATUS + */ +static QDF_STATUS __dsc_dbg_tran_wait_timeout_start(struct dsc_tran *tran) +{ + QDF_STATUS status; + + tran->thread = qdf_get_current_task(); + status = qdf_timer_init(NULL, &tran->timeout_timer, + __dsc_dbg_tran_wait_timeout, tran, + QDF_TIMER_TYPE_SW); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + qdf_timer_start(&tran->timeout_timer, DSC_TRANS_WAIT_TIMEOUT_MS); + + return QDF_STATUS_SUCCESS; +} + +/** + * __dsc_dbg_tran_wait_timeout_stop() - stop the timeout timer for @tran + * @tran: the pending transition to stop the timeout timer for + * + * Return: None + */ +static void __dsc_dbg_tran_wait_timeout_stop(struct dsc_tran *tran) +{ + qdf_timer_stop(&tran->timeout_timer); + qdf_timer_free(&tran->timeout_timer); +} +#else +static inline QDF_STATUS __dsc_dbg_trans_timeout_start(struct dsc_trans *trans) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void __dsc_dbg_trans_timeout_stop(struct dsc_trans *trans) { } + +static inline QDF_STATUS +__dsc_dbg_tran_wait_timeout_start(struct dsc_tran *tran) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void __dsc_dbg_tran_wait_timeout_stop(struct dsc_tran *tran) { } +#endif /* WLAN_DSC_DEBUG */ + +void __dsc_trans_init(struct dsc_trans *trans) +{ + trans->active_desc = NULL; + qdf_list_create(&trans->queue, 0); +} + +void __dsc_trans_deinit(struct dsc_trans *trans) +{ + qdf_list_destroy(&trans->queue); + trans->active_desc = NULL; +} + +QDF_STATUS __dsc_trans_start(struct dsc_trans *trans, const char *desc) +{ + QDF_STATUS status; + + status = __dsc_dbg_trans_timeout_start(trans); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + dsc_assert(!trans->active_desc); + trans->active_desc = desc; + + return QDF_STATUS_SUCCESS; +} + +void __dsc_trans_stop(struct dsc_trans *trans) +{ + dsc_assert(trans->active_desc); + trans->active_desc = NULL; + __dsc_dbg_trans_timeout_stop(trans); +} + +QDF_STATUS __dsc_trans_queue(struct dsc_trans *trans, struct dsc_tran *tran, + const char *desc) +{ + QDF_STATUS status; + + tran->abort = false; + tran->desc = desc; + qdf_event_create(&tran->event); + + status = __dsc_dbg_tran_wait_timeout_start(tran); + if (QDF_IS_STATUS_ERROR(status)) + goto event_destroy; + + qdf_list_insert_back(&trans->queue, &tran->node); + + return QDF_STATUS_SUCCESS; + +event_destroy: + qdf_event_destroy(&tran->event); + + return status; +} + +/** + * __dsc_trans_dequeue() - dequeue the next queued transition from @trans + * @trans: the transactions container to dequeue from + * + * Return: the dequeued transition, or NULL if @trans is empty + */ +static struct dsc_tran *__dsc_trans_dequeue(struct dsc_trans *trans) +{ + QDF_STATUS status; + qdf_list_node_t *node; + struct dsc_tran *tran; + + status = qdf_list_remove_front(&trans->queue, &node); + if (QDF_IS_STATUS_ERROR(status)) + return NULL; + + tran = qdf_container_of(node, struct dsc_tran, node); + __dsc_dbg_tran_wait_timeout_stop(tran); + + return tran; +} + +bool __dsc_trans_abort(struct dsc_trans *trans) +{ + struct dsc_tran *tran; + + tran = __dsc_trans_dequeue(trans); + if (!tran) + return false; + + tran->abort = true; + qdf_event_set(&tran->event); + + return true; +} + +bool __dsc_trans_trigger(struct dsc_trans *trans) +{ + struct dsc_tran *tran; + + tran = __dsc_trans_dequeue(trans); + if (!tran) + return false; + + __dsc_trans_start(trans, tran->desc); + qdf_event_set(&tran->event); + + return true; +} + +bool __dsc_trans_active(struct dsc_trans *trans) +{ + return !!trans->active_desc; +} + +bool __dsc_trans_queued(struct dsc_trans *trans) +{ + return !qdf_list_empty(&trans->queue); +} + +bool __dsc_trans_active_or_queued(struct dsc_trans *trans) +{ + return __dsc_trans_active(trans) || __dsc_trans_queued(trans); +} + +QDF_STATUS __dsc_tran_wait(struct dsc_tran *tran) +{ + QDF_STATUS status; + + status = qdf_wait_single_event(&tran->event, 0); + qdf_event_destroy(&tran->event); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + if (tran->abort) + return QDF_STATUS_E_ABORTED; + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/__wlan_dsc.h b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/__wlan_dsc.h new file mode 100644 index 0000000000..1a2d347fc2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/__wlan_dsc.h @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Driver State Management (DSC) APIs for *internal* use + */ + +#ifndef ____WLAN_DSC_H +#define ____WLAN_DSC_H + +#include "qdf_event.h" +#include "qdf_list.h" +#include "qdf_threads.h" +#include "qdf_timer.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_dsc.h" + +#define dsc_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, params) +#define dsc_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_QDF, params) +#ifdef WLAN_DSC_DEBUG +#define dsc_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_QDF, params) +#else +#define dsc_debug(params...) /* no-op */ +#endif + +#define dsc_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_QDF, params) +#define dsc_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_QDF, params) +#define dsc_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_QDF, params) + +#define dsc_enter_exit dsc_debug +#define dsc_enter() dsc_enter_exit("enter") +#define dsc_enter_str(str) dsc_enter_exit("enter(\"%s\")", str) +#define dsc_exit() dsc_enter_exit("exit") +#define dsc_exit_status(status) dsc_enter_exit("exit(status:%u)", status) + +static inline bool __dsc_assert(const bool cond, const char *cond_str, + const char *func, const uint32_t line) +{ + if (cond) + return true; + + QDF_DEBUG_PANIC_FL(func, line, "Failed assertion '%s'!", cond_str); + + return false; +} + +#define dsc_assert(cond) __dsc_assert(cond, #cond, __func__, __LINE__) +#define dsc_assert_success(status) dsc_assert(QDF_IS_STATUS_SUCCESS(status)) + +#ifdef WLAN_DSC_DEBUG +#define DSC_OP_TIMEOUT_MS (1 * 60 * 1000) /* 1 minute */ +#define DSC_TRANS_TIMEOUT_MS (1 * 60 * 1000) /* 1 minute */ +#define DSC_TRANS_WAIT_TIMEOUT_MS (2 * 60 * 1000) /* 2 minutes */ + +/** + * struct dsc_op - list node for operation tracking information + * @node: list node + * @timeout_timer: a timer used to detect operation timeouts + * @thread: the thread which started the operation + * @func: name of the function the operation was started from + */ +struct dsc_op { + qdf_list_node_t node; + qdf_timer_t timeout_timer; + qdf_thread_t *thread; + const char *func; +}; +#endif /* WLAN_DSC_DEBUG */ + +/** + * struct dsc_ops - operations in flight tracking container + * @list: list for tracking debug information + * @count: count of current operations in flight + * @event: event used to wait in *_wait_for_ops() APIs + */ +struct dsc_ops { +#ifdef WLAN_DSC_DEBUG + qdf_list_t list; +#endif + uint32_t count; + qdf_event_t event; +}; + +/** + * struct dsc_tran - representation of a pending transition + * @abort: used to indicate if the transition stopped waiting due to an abort + * @desc: unique description of the transition + * @node: list node + * @event: event used to wait in *_start_trans_wait() APIs + * @timeout_timer: a timer used to detect transition wait timeouts + * @thread: the thread which started the transition wait + */ +struct dsc_tran { + bool abort; + const char *desc; + qdf_list_node_t node; + qdf_event_t event; +#ifdef WLAN_DSC_DEBUG + qdf_timer_t timeout_timer; + qdf_thread_t *thread; +#endif +}; + +/** + * struct dsc_trans - transition information container + * @active_desc: unique description of the current transition in progress + * @queue: queue of pending transitions + * @timeout_timer: a timer used to detect transition timeouts + * @thread: the thread which started the transition + */ +struct dsc_trans { + const char *active_desc; + qdf_list_t queue; +#ifdef WLAN_DSC_DEBUG + qdf_timer_t timeout_timer; + qdf_thread_t *thread; +#endif +}; + +/** + * struct dsc_driver - concrete dsc driver context + * @lock: lock under which all dsc APIs execute + * @psocs: list of children psoc contexts + * @trans: transition tracking container for this node + * @ops: operations in flight tracking container for this node + */ +struct dsc_driver { + struct qdf_spinlock lock; + qdf_list_t psocs; + struct dsc_trans trans; + struct dsc_ops ops; +}; + +/** + * struct dsc_psoc - concrete dsc psoc context + * @node: list node for membership in @driver->psocs + * @driver: parent driver context + * @vdevs: list of children vdevs contexts + * @trans: transition tracking container for this node + * @ops: operations in flight tracking container for this node + */ +struct dsc_psoc { + qdf_list_node_t node; + struct dsc_driver *driver; + qdf_list_t vdevs; + struct dsc_trans trans; + struct dsc_ops ops; +}; + +/** + * struct dsc_vdev - concrete dsc vdev context + * @node: list node for membership in @psoc->vdevs + * @psoc: parent psoc context + * @trans: transition tracking container for this node + * @ops: operations in flight tracking container for this node + * @nb_cmd_during_ssr: north bound command id + */ +struct dsc_vdev { + qdf_list_node_t node; + struct dsc_psoc *psoc; + struct dsc_trans trans; + struct dsc_ops ops; + uint8_t nb_cmd_during_ssr; +}; + +#define dsc_for_each_driver_psoc(driver_ptr, psoc_cursor) \ + qdf_list_for_each(&(driver_ptr)->psocs, psoc_cursor, node) + +#define dsc_for_each_psoc_vdev(psoc_ptr, vdev_cursor) \ + qdf_list_for_each(&(psoc_ptr)->vdevs, vdev_cursor, node) + +/** + * __dsc_lock() - grab the dsc driver lock + * @driver: the driver to lock + * + * Return: None + */ +void __dsc_lock(struct dsc_driver *driver); + +/** + * __dsc_unlock() - release the dsc driver lock + * @driver: the driver to unlock + * + * Return: None + */ +void __dsc_unlock(struct dsc_driver *driver); + +/** + * __dsc_ops_init() - initialize @ops + * @ops: the ops container to initialize + * + * Return: None + */ +void __dsc_ops_init(struct dsc_ops *ops); + +/** + * __dsc_ops_deinit() - de-initialize @ops + * @ops: the ops container to de-initialize + * + * Return: None + */ +void __dsc_ops_deinit(struct dsc_ops *ops); + +/** + * __dsc_ops_insert() - insert @func into the trakcing information in @ops + * @ops: the ops container to insert into + * @func: the debug information to insert + * + * Return: QDF_STATUS + */ +QDF_STATUS __dsc_ops_insert(struct dsc_ops *ops, const char *func); + +/** + * __dsc_ops_remove() - remove @func from the tracking information in @ops + * @ops: the ops container to remove from + * @func: the debug information to remove + * + * Return: None + */ +bool __dsc_ops_remove(struct dsc_ops *ops, const char *func); + +/** + * __dsc_trans_init() - initialize @trans + * @trans: the trans container to initialize + * + * Return: None + */ +void __dsc_trans_init(struct dsc_trans *trans); + +/** + * __dsc_trans_deinit() - de-initialize @trans + * @trans: the trans container to de-initialize + * + * Return: None + */ +void __dsc_trans_deinit(struct dsc_trans *trans); + +/** + * __dsc_trans_start() - set the active transition on @trans + * @trans: the transition container used to track the new active transition + * @desc: unique description of the transition being started + * + * Return: QDF_STATUS + */ +QDF_STATUS __dsc_trans_start(struct dsc_trans *trans, const char *desc); + +/** + * __dsc_trans_stop() - unset the active transition on @trans + * @trans: the transition container currently tracking the active transition + * + * Return: None + */ +void __dsc_trans_stop(struct dsc_trans *trans); + +/** + * __dsc_trans_queue() - queue @tran at the back of @trans + * @trans: the transitions container to enqueue to + * @tran: the transition to enqueue + * @desc: unique description of the transition being queued + * + * Return: QDF_STATUS + */ +QDF_STATUS __dsc_trans_queue(struct dsc_trans *trans, struct dsc_tran *tran, + const char *desc); + +/** + * __dsc_tran_wait() - block until @tran completes + * @tran: the transition to wait on + * + * Return: QDF_STATUS + */ +QDF_STATUS __dsc_tran_wait(struct dsc_tran *tran); + +/** + * __dsc_trans_abort() - abort the next queued transition from @trans + * @trans: the transitions container to abort from + * + * Return: true if a transition was aborted, false if @trans is empty + */ +bool __dsc_trans_abort(struct dsc_trans *trans); + +/** + * __dsc_trans_trigger() - trigger the next queued trans in @trans + * @trans: the transitions container to trigger from + * + * Return: true if a transition was triggered + */ +bool __dsc_trans_trigger(struct dsc_trans *trans); + +/** + * __dsc_trans_active() - check if a transition is active in @trans + * @trans: the transitions container to check + * + * Return: true if @trans has an active transition + */ +bool __dsc_trans_active(struct dsc_trans *trans); + +/** + * __dsc_trans_queued() - check if a transition is queued in @trans + * @trans: the transitions container to check + * + * Return: true if @trans has a queued transition + */ +bool __dsc_trans_queued(struct dsc_trans *trans); + +/** + * __dsc_trans_active_or_queued() - check if a transition is active or queued + * in @trans + * @trans: the transitions container to check + * + * Return: true if @trans has an active or queued transition + */ +bool __dsc_trans_active_or_queued(struct dsc_trans *trans); + +/** + * __dsc_driver_trans_trigger_checked() - trigger any next pending driver + * transition, only after passing the "can trans" check + * @driver: driver context + * + * Return: true if the trigger was "handled." This indicates down-tree nodes + * should _not_ attempt to trigger a new transition. + */ +bool __dsc_driver_trans_trigger_checked(struct dsc_driver *driver); + +/** + * __dsc_psoc_trans_trigger_checked() - trigger any next pending psoc + * transition, only after passing the "can trans" check + * @psoc: psoc context + * + * Return: true if the trigger was "handled." This indicates down-tree nodes + * should _not_ attempt to trigger a new transition. + */ +bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc); + +#endif /* ____WLAN_DSC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_driver.c b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_driver.c new file mode 100644 index 0000000000..fd17662c71 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_driver.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_list.h" +#include "qdf_mem.h" +#include "qdf_status.h" +#include "qdf_types.h" +#include "__wlan_dsc.h" +#include "wlan_dsc.h" + +void __dsc_lock(struct dsc_driver *driver) +{ + dsc_assert(driver); + qdf_spin_lock_bh(&driver->lock); +} + +void __dsc_unlock(struct dsc_driver *driver) +{ + dsc_assert(driver); + qdf_spin_unlock_bh(&driver->lock); +} + +static QDF_STATUS __dsc_driver_create(struct dsc_driver **out_driver) +{ + struct dsc_driver *driver; + + if (!dsc_assert(out_driver)) + return QDF_STATUS_E_INVAL; + + *out_driver = NULL; + + driver = qdf_mem_malloc(sizeof(*driver)); + if (!driver) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&driver->lock); + qdf_list_create(&driver->psocs, 0); + __dsc_trans_init(&driver->trans); + __dsc_ops_init(&driver->ops); + + *out_driver = driver; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dsc_driver_create(struct dsc_driver **out_driver) +{ + QDF_STATUS status; + + status = __dsc_driver_create(out_driver); + + return status; +} + +static void __dsc_driver_destroy(struct dsc_driver **out_driver) +{ + struct dsc_driver *driver; + + if (!dsc_assert(out_driver)) + return; + + driver = *out_driver; + if (!dsc_assert(driver)) + return; + + *out_driver = NULL; + + /* assert no children */ + dsc_assert(qdf_list_empty(&driver->psocs)); + + /* flush pending transitions */ + while (__dsc_trans_abort(&driver->trans)) + ; + + /* de-init */ + __dsc_ops_deinit(&driver->ops); + __dsc_trans_deinit(&driver->trans); + qdf_list_destroy(&driver->psocs); + qdf_spinlock_destroy(&driver->lock); + + qdf_mem_free(driver); +} + +void dsc_driver_destroy(struct dsc_driver **out_driver) +{ + __dsc_driver_destroy(out_driver); +} + +static bool __dsc_driver_trans_active_down_tree(struct dsc_driver *driver) +{ + struct dsc_psoc *psoc; + struct dsc_vdev *vdev; + + dsc_for_each_driver_psoc(driver, psoc) { + if (__dsc_trans_active(&psoc->trans)) + return true; + + dsc_for_each_psoc_vdev(psoc, vdev) { + if (__dsc_trans_active(&vdev->trans)) + return true; + } + } + + return false; +} + +#define __dsc_driver_can_op(driver) __dsc_driver_can_trans(driver) + +static bool __dsc_driver_can_trans(struct dsc_driver *driver) +{ + return !__dsc_trans_active_or_queued(&driver->trans) && + !__dsc_driver_trans_active_down_tree(driver); +} + +static bool __dsc_driver_can_trigger(struct dsc_driver *driver) +{ + return !__dsc_trans_active(&driver->trans) && + !__dsc_driver_trans_active_down_tree(driver); +} + +static QDF_STATUS +__dsc_driver_trans_start_nolock(struct dsc_driver *driver, const char *desc) +{ + if (!__dsc_driver_can_trans(driver)) + return QDF_STATUS_E_AGAIN; + + return __dsc_trans_start(&driver->trans, desc); +} + +static QDF_STATUS +__dsc_driver_trans_start(struct dsc_driver *driver, const char *desc) +{ + QDF_STATUS status; + + if (!dsc_assert(driver)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(desc)) + return QDF_STATUS_E_INVAL; + + __dsc_lock(driver); + status = __dsc_driver_trans_start_nolock(driver, desc); + __dsc_unlock(driver); + + return status; +} + +QDF_STATUS dsc_driver_trans_start(struct dsc_driver *driver, const char *desc) +{ + QDF_STATUS status; + + dsc_enter_str(desc); + status = __dsc_driver_trans_start(driver, desc); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +static QDF_STATUS +__dsc_driver_trans_start_wait(struct dsc_driver *driver, const char *desc) +{ + QDF_STATUS status; + struct dsc_tran tran = { 0 }; + + if (!dsc_assert(driver)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(desc)) + return QDF_STATUS_E_INVAL; + + __dsc_lock(driver); + + /* try to start without waiting */ + status = __dsc_driver_trans_start_nolock(driver, desc); + if (QDF_IS_STATUS_SUCCESS(status)) + goto unlock; + + status = __dsc_trans_queue(&driver->trans, &tran, desc); + if (QDF_IS_STATUS_ERROR(status)) + goto unlock; + + __dsc_unlock(driver); + + return __dsc_tran_wait(&tran); + +unlock: + __dsc_unlock(driver); + + return status; +} + +QDF_STATUS +dsc_driver_trans_start_wait(struct dsc_driver *driver, const char *desc) +{ + QDF_STATUS status; + + dsc_enter_str(desc); + status = __dsc_driver_trans_start_wait(driver, desc); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +bool __dsc_driver_trans_trigger_checked(struct dsc_driver *driver) +{ + if (!__dsc_trans_queued(&driver->trans)) + return false; + + /* handled, but don't trigger; we need to wait for more children */ + if (!__dsc_driver_can_trigger(driver)) + return true; + + return __dsc_trans_trigger(&driver->trans); +} + +static void __dsc_driver_trigger_trans(struct dsc_driver *driver) +{ + struct dsc_psoc *psoc; + struct dsc_vdev *vdev; + + if (__dsc_trans_trigger(&driver->trans)) + return; + + dsc_for_each_driver_psoc(driver, psoc) { + if (__dsc_trans_trigger(&psoc->trans)) + continue; + + dsc_for_each_psoc_vdev(psoc, vdev) + __dsc_trans_trigger(&vdev->trans); + } +} + +static void __dsc_driver_trans_stop(struct dsc_driver *driver) +{ + if (!dsc_assert(driver)) + return; + + __dsc_lock(driver); + + __dsc_trans_stop(&driver->trans); + __dsc_driver_trigger_trans(driver); + + __dsc_unlock(driver); +} + +void dsc_driver_trans_stop(struct dsc_driver *driver) +{ + __dsc_driver_trans_stop(driver); +} + +static void __dsc_driver_assert_trans_protected(struct dsc_driver *driver) +{ + if (!dsc_assert(driver)) + return; + + __dsc_lock(driver); + dsc_assert(__dsc_trans_active(&driver->trans)); + __dsc_unlock(driver); +} + +void dsc_driver_assert_trans_protected(struct dsc_driver *driver) +{ + __dsc_driver_assert_trans_protected(driver); +} + +static QDF_STATUS +__dsc_driver_op_start(struct dsc_driver *driver, const char *func) +{ + QDF_STATUS status; + + if (!dsc_assert(driver)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(func)) + return QDF_STATUS_E_INVAL; + + __dsc_lock(driver); + + if (!__dsc_driver_can_op(driver)) { + status = QDF_STATUS_E_AGAIN; + goto unlock; + } + + status = __dsc_ops_insert(&driver->ops, func); + +unlock: + __dsc_unlock(driver); + + return status; +} + +QDF_STATUS _dsc_driver_op_start(struct dsc_driver *driver, const char *func) +{ + QDF_STATUS status; + + dsc_enter_str(func); + status = __dsc_driver_op_start(driver, func); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +static void __dsc_driver_op_stop(struct dsc_driver *driver, const char *func) +{ + if (!dsc_assert(driver)) + return; + + if (!dsc_assert(func)) + return; + + __dsc_lock(driver); + if (__dsc_ops_remove(&driver->ops, func)) + qdf_event_set(&driver->ops.event); + __dsc_unlock(driver); +} + +void _dsc_driver_op_stop(struct dsc_driver *driver, const char *func) +{ + __dsc_driver_op_stop(driver, func); +} + +static void __dsc_driver_wait_for_ops(struct dsc_driver *driver) +{ + struct dsc_psoc *psoc; + bool wait; + + if (!dsc_assert(driver)) + return; + + __dsc_lock(driver); + + /* flushing without preventing new ops is almost certainly a bug */ + dsc_assert(!__dsc_driver_can_op(driver)); + + wait = driver->ops.count > 0; + if (wait) + qdf_event_reset(&driver->ops.event); + + __dsc_unlock(driver); + + if (wait) + qdf_wait_single_event(&driver->ops.event, 0); + + /* wait for down-tree ops to complete as well */ + dsc_for_each_driver_psoc(driver, psoc) + dsc_psoc_wait_for_ops(psoc); +} + +void dsc_driver_wait_for_ops(struct dsc_driver *driver) +{ + __dsc_driver_wait_for_ops(driver); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_psoc.c b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_psoc.c new file mode 100644 index 0000000000..e2cb178ad9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_psoc.c @@ -0,0 +1,390 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_list.h" +#include "qdf_status.h" +#include "qdf_talloc.h" +#include "qdf_types.h" +#include "__wlan_dsc.h" +#include "wlan_dsc.h" + +#define __dsc_driver_lock(psoc) __dsc_lock((psoc)->driver) +#define __dsc_driver_unlock(psoc) __dsc_unlock((psoc)->driver) + +static QDF_STATUS +__dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc) +{ + struct dsc_psoc *psoc; + + if (!dsc_assert(driver)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(out_psoc)) + return QDF_STATUS_E_INVAL; + + *out_psoc = NULL; + + psoc = qdf_talloc_type(driver, psoc); + if (!psoc) + return QDF_STATUS_E_NOMEM; + + /* init */ + psoc->driver = driver; + qdf_list_create(&psoc->vdevs, 0); + __dsc_trans_init(&psoc->trans); + __dsc_ops_init(&psoc->ops); + + /* attach */ + __dsc_driver_lock(psoc); + qdf_list_insert_back(&driver->psocs, &psoc->node); + __dsc_driver_unlock(psoc); + + *out_psoc = psoc; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +dsc_psoc_create(struct dsc_driver *driver, struct dsc_psoc **out_psoc) +{ + QDF_STATUS status; + + status = __dsc_psoc_create(driver, out_psoc); + + return status; +} + +static void __dsc_psoc_destroy(struct dsc_psoc **out_psoc) +{ + struct dsc_psoc *psoc; + + if (!dsc_assert(out_psoc)) + return; + + psoc = *out_psoc; + if (!dsc_assert(psoc)) + return; + + /* assert no children */ + dsc_assert(qdf_list_empty(&psoc->vdevs)); + + /* flush pending transitions */ + while (__dsc_trans_abort(&psoc->trans)) + ; + + /* detach */ + __dsc_driver_lock(psoc); + qdf_list_remove_node(&psoc->driver->psocs, &psoc->node); + __dsc_driver_unlock(psoc); + + /* de-init */ + __dsc_ops_deinit(&psoc->ops); + __dsc_trans_deinit(&psoc->trans); + qdf_list_destroy(&psoc->vdevs); + psoc->driver = NULL; + + *out_psoc = NULL; + + qdf_tfree(psoc); +} + +void dsc_psoc_destroy(struct dsc_psoc **out_psoc) +{ + __dsc_psoc_destroy(out_psoc); +} + +static bool __dsc_psoc_trans_active_down_tree(struct dsc_psoc *psoc) +{ + struct dsc_vdev *vdev; + + dsc_for_each_psoc_vdev(psoc, vdev) { + if (__dsc_trans_active(&vdev->trans)) + return true; + } + + return false; +} + +#define __dsc_psoc_can_op(psoc) __dsc_psoc_can_trans(psoc) + +/* + * __dsc_psoc_can_trans() - Returns if the psoc transition can occur or not + * @psoc: The DSC psoc + * + * This function checks if the psoc transition can occur or not by checking if + * any other down the tree/up the tree transition/operation is taking place. + * + * If there are any driver transition taking place, then the psoc trans/ops + * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL + * in this case. + * + * If there any psoc or vdev trans/ops is taking place, then the psoc trans/ops + * should be rejected and queued in the DSC queue so that it may be resumed + * after the current trans/ops is completed. Return QDF_STATUS_E_AGAIN in this + * case. + * + * Return: QDF_STATUS_SUCCESS if transition is allowed, error code if not. + */ +static QDF_STATUS __dsc_psoc_can_trans(struct dsc_psoc *psoc) +{ + if (__dsc_trans_active_or_queued(&psoc->driver->trans)) + return QDF_STATUS_E_INVAL; + + if (__dsc_trans_active_or_queued(&psoc->trans) || + __dsc_psoc_trans_active_down_tree(psoc)) + return QDF_STATUS_E_AGAIN; + + return QDF_STATUS_SUCCESS; +} + +static bool __dsc_psoc_can_trigger(struct dsc_psoc *psoc) +{ + return !__dsc_trans_active_or_queued(&psoc->driver->trans) && + !__dsc_trans_active(&psoc->trans) && + !__dsc_psoc_trans_active_down_tree(psoc); +} + +static QDF_STATUS +__dsc_psoc_trans_start_nolock(struct dsc_psoc *psoc, const char *desc) +{ + QDF_STATUS status; + + status = __dsc_psoc_can_trans(psoc); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return __dsc_trans_start(&psoc->trans, desc); +} + +static QDF_STATUS +__dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc) +{ + QDF_STATUS status; + + if (!dsc_assert(psoc)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(desc)) + return QDF_STATUS_E_INVAL; + + __dsc_driver_lock(psoc); + status = __dsc_psoc_trans_start_nolock(psoc, desc); + __dsc_driver_unlock(psoc); + + return status; +} + +QDF_STATUS dsc_psoc_trans_start(struct dsc_psoc *psoc, const char *desc) +{ + QDF_STATUS status; + + dsc_enter_str(desc); + status = __dsc_psoc_trans_start(psoc, desc); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +static QDF_STATUS +__dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc) +{ + QDF_STATUS status; + struct dsc_tran tran = { 0 }; + + if (!dsc_assert(psoc)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(desc)) + return QDF_STATUS_E_INVAL; + + __dsc_driver_lock(psoc); + + /* try to start without waiting */ + status = __dsc_psoc_trans_start_nolock(psoc, desc); + if (QDF_IS_STATUS_SUCCESS(status) || status == QDF_STATUS_E_INVAL) + goto unlock; + + status = __dsc_trans_queue(&psoc->trans, &tran, desc); + if (QDF_IS_STATUS_ERROR(status)) + goto unlock; + + __dsc_driver_unlock(psoc); + + return __dsc_tran_wait(&tran); + +unlock: + __dsc_driver_unlock(psoc); + + return status; +} + +QDF_STATUS dsc_psoc_trans_start_wait(struct dsc_psoc *psoc, const char *desc) +{ + QDF_STATUS status; + + dsc_enter_str(desc); + status = __dsc_psoc_trans_start_wait(psoc, desc); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +static void __dsc_psoc_trigger_trans(struct dsc_psoc *psoc) +{ + struct dsc_vdev *vdev; + + if (__dsc_driver_trans_trigger_checked(psoc->driver)) + return; + + if (__dsc_trans_trigger(&psoc->trans)) + return; + + dsc_for_each_psoc_vdev(psoc, vdev) + __dsc_trans_trigger(&vdev->trans); +} + +static void __dsc_psoc_trans_stop(struct dsc_psoc *psoc) +{ + if (!dsc_assert(psoc)) + return; + + __dsc_driver_lock(psoc); + + __dsc_trans_stop(&psoc->trans); + __dsc_psoc_trigger_trans(psoc); + + __dsc_driver_unlock(psoc); +} + +void dsc_psoc_trans_stop(struct dsc_psoc *psoc) +{ + __dsc_psoc_trans_stop(psoc); +} + +static void __dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc) +{ + if (!dsc_assert(psoc)) + return; + + __dsc_driver_lock(psoc); + dsc_assert(__dsc_trans_active(&psoc->trans) || + __dsc_trans_active(&psoc->driver->trans)); + __dsc_driver_unlock(psoc); +} + +void dsc_psoc_assert_trans_protected(struct dsc_psoc *psoc) +{ + __dsc_psoc_assert_trans_protected(psoc); +} + +bool __dsc_psoc_trans_trigger_checked(struct dsc_psoc *psoc) +{ + if (qdf_list_empty(&psoc->trans.queue)) + return false; + + /* handled, but don't trigger; we need to wait for more children */ + if (!__dsc_psoc_can_trigger(psoc)) + return true; + + return __dsc_trans_trigger(&psoc->trans); +} + +static QDF_STATUS __dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func) +{ + QDF_STATUS status; + + if (!dsc_assert(psoc)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(func)) + return QDF_STATUS_E_INVAL; + + __dsc_driver_lock(psoc); + + status = __dsc_psoc_can_op(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto unlock; + + status = __dsc_ops_insert(&psoc->ops, func); + +unlock: + __dsc_driver_unlock(psoc); + + return status; +} + +QDF_STATUS _dsc_psoc_op_start(struct dsc_psoc *psoc, const char *func) +{ + QDF_STATUS status; + + status = __dsc_psoc_op_start(psoc, func); + + return status; +} + +static void __dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func) +{ + if (!dsc_assert(psoc)) + return; + + if (!dsc_assert(func)) + return; + + __dsc_driver_lock(psoc); + if (__dsc_ops_remove(&psoc->ops, func)) + qdf_event_set(&psoc->ops.event); + __dsc_driver_unlock(psoc); +} + +void _dsc_psoc_op_stop(struct dsc_psoc *psoc, const char *func) +{ + __dsc_psoc_op_stop(psoc, func); +} + +static void __dsc_psoc_wait_for_ops(struct dsc_psoc *psoc) +{ + struct dsc_vdev *vdev; + bool wait; + + if (!dsc_assert(psoc)) + return; + + __dsc_driver_lock(psoc); + + wait = psoc->ops.count > 0; + if (wait) + qdf_event_reset(&psoc->ops.event); + + __dsc_driver_unlock(psoc); + + if (wait) + qdf_wait_single_event(&psoc->ops.event, 0); + + /* wait for down-tree ops to complete as well */ + dsc_for_each_psoc_vdev(psoc, vdev) + dsc_vdev_wait_for_ops(vdev); +} + +void dsc_psoc_wait_for_ops(struct dsc_psoc *psoc) +{ + __dsc_psoc_wait_for_ops(psoc); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_vdev.c b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_vdev.c new file mode 100644 index 0000000000..0bdf193ffc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/src/wlan_dsc_vdev.c @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_list.h" +#include "qdf_status.h" +#include "qdf_talloc.h" +#include "qdf_types.h" +#include "__wlan_dsc.h" +#include "wlan_dsc.h" +#include "qdf_platform.h" + +#define __dsc_driver_lock(vdev) __dsc_lock((vdev)->psoc->driver) +#define __dsc_driver_unlock(vdev) __dsc_unlock((vdev)->psoc->driver) + +static QDF_STATUS +__dsc_vdev_create(struct dsc_psoc *psoc, struct dsc_vdev **out_vdev) +{ + struct dsc_vdev *vdev; + + if (!dsc_assert(psoc)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(out_vdev)) + return QDF_STATUS_E_INVAL; + + *out_vdev = NULL; + + vdev = qdf_talloc_type(psoc, vdev); + if (!vdev) + return QDF_STATUS_E_NOMEM; + + /* init */ + vdev->psoc = psoc; + __dsc_trans_init(&vdev->trans); + __dsc_ops_init(&vdev->ops); + + /* attach */ + __dsc_driver_lock(vdev); + qdf_list_insert_back(&psoc->vdevs, &vdev->node); + __dsc_driver_unlock(vdev); + + *out_vdev = vdev; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS dsc_vdev_create(struct dsc_psoc *psoc, struct dsc_vdev **out_vdev) +{ + QDF_STATUS status; + + status = __dsc_vdev_create(psoc, out_vdev); + + return status; +} + +static void __dsc_vdev_destroy(struct dsc_vdev **out_vdev) +{ + struct dsc_vdev *vdev; + + if (!dsc_assert(out_vdev)) + return; + + vdev = *out_vdev; + if (!dsc_assert(vdev)) + return; + + *out_vdev = NULL; + + /* flush pending transitions */ + while (__dsc_trans_abort(&vdev->trans)) + ; + + /* detach */ + __dsc_driver_lock(vdev); + qdf_list_remove_node(&vdev->psoc->vdevs, &vdev->node); + __dsc_driver_unlock(vdev); + + /* de-init */ + __dsc_ops_deinit(&vdev->ops); + __dsc_trans_deinit(&vdev->trans); + vdev->psoc = NULL; + + qdf_tfree(vdev); +} + +void dsc_vdev_destroy(struct dsc_vdev **out_vdev) +{ + __dsc_vdev_destroy(out_vdev); +} + +static void __dsc_vdev_wait_for_uptree_ops(struct dsc_vdev *vdev) +{ + bool wait; + + if (!dsc_assert(vdev)) + return; + + __dsc_driver_lock(vdev); + wait = vdev->psoc->ops.count > 0; + if (wait) + qdf_event_reset(&vdev->psoc->ops.event); + __dsc_driver_unlock(vdev); + + if (wait) + qdf_wait_single_event(&vdev->psoc->ops.event, 0); + + __dsc_driver_lock(vdev); + wait = vdev->psoc->driver->ops.count > 0; + if (wait) + qdf_event_reset(&vdev->psoc->driver->ops.event); + __dsc_driver_unlock(vdev); + + if (wait) + qdf_wait_single_event(&vdev->psoc->driver->ops.event, 0); +} + +void dsc_vdev_wait_for_uptree_ops(struct dsc_vdev *vdev) +{ + __dsc_vdev_wait_for_uptree_ops(vdev); +} + +#define __dsc_vdev_can_op(vdev) __dsc_vdev_can_trans(vdev) + +/* + * __dsc_vdev_can_trans() - Returns if the vdev transition can occur or not + * @vdev: The DSC vdev + * + * This function checks if the vdev transition can occur or not by checking if + * any other down the tree/up the tree transition/operation is taking place. + * + * If there are any driver transition taking place, then the vdev trans/ops + * should be rejected and not queued in the DSC queue. Return QDF_STATUS_E_INVAL + * in this case. + * + * If there are any psoc transition taking place because of SSR, then vdev + * trans/op should be rejected and queued in the DSC queue so that it may be + * resumed after the current trans/op is completed. return QDF_STATUS_E_BUSY + * in this case. + * + * If there is a psoc transition taking place because of psoc idle shutdown, + * then the vdev trans/ops should be rejected and queued in the DSC queue so + * that it may be resumed after the current trans/ops is completed. Return + * QDF_STATUS_E_BUSY in this case. + * + * If there are any vdev trans/ops taking place, then the vdev trans/ops + * should be rejected and queued in the DSC queue so that it may be resumed + * after the current trans/ops is completed. Return QDF_STATUS_E_BUSY in this + * case. + * + * Return: QDF_STATUS_SUCCESS if transition is allowed, error code if not. + */ +static QDF_STATUS __dsc_vdev_can_trans(struct dsc_vdev *vdev) +{ + if (__dsc_trans_active_or_queued(&vdev->psoc->driver->trans)) + return QDF_STATUS_E_INVAL; + + if (qdf_is_recovering()) + return QDF_STATUS_E_INVAL; + + if (__dsc_trans_active_or_queued(&vdev->psoc->trans)) { + /* psoc idle shutdown(wifi off) needs to be added in DSC queue + * to avoid wifi on failure while previous psoc idle shutdown + * is in progress and wifi is turned on. And Wifi On also needs + * to be added to the queue so that it waits for SSR to + * complete. + */ + if (qdf_is_driver_unloading()) + return QDF_STATUS_E_INVAL; + else + return QDF_STATUS_E_BUSY; + } + + if (__dsc_trans_active_or_queued(&vdev->trans)) + return QDF_STATUS_E_BUSY; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +__dsc_vdev_trans_start_nolock(struct dsc_vdev *vdev, const char *desc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = __dsc_vdev_can_trans(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return __dsc_trans_start(&vdev->trans, desc); +} + +static QDF_STATUS +__dsc_vdev_trans_start(struct dsc_vdev *vdev, const char *desc) +{ + QDF_STATUS status; + + if (!dsc_assert(vdev)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(desc)) + return QDF_STATUS_E_INVAL; + + __dsc_driver_lock(vdev); + status = __dsc_vdev_trans_start_nolock(vdev, desc); + __dsc_driver_unlock(vdev); + + return status; +} + +QDF_STATUS dsc_vdev_trans_start(struct dsc_vdev *vdev, const char *desc) +{ + QDF_STATUS status; + + dsc_enter_str(desc); + status = __dsc_vdev_trans_start(vdev, desc); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +static QDF_STATUS +__dsc_vdev_trans_start_wait(struct dsc_vdev *vdev, const char *desc) +{ + QDF_STATUS status; + struct dsc_tran tran = { 0 }; + + if (!dsc_assert(vdev)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(desc)) + return QDF_STATUS_E_INVAL; + + __dsc_driver_lock(vdev); + + /* try to start without waiting */ + status = __dsc_vdev_trans_start_nolock(vdev, desc); + if (QDF_IS_STATUS_SUCCESS(status) || status == QDF_STATUS_E_INVAL) + goto unlock; + + status = __dsc_trans_queue(&vdev->trans, &tran, desc); + if (QDF_IS_STATUS_ERROR(status)) + goto unlock; + + __dsc_driver_unlock(vdev); + + return __dsc_tran_wait(&tran); + +unlock: + __dsc_driver_unlock(vdev); + + return status; +} + +QDF_STATUS dsc_vdev_trans_start_wait(struct dsc_vdev *vdev, const char *desc) +{ + QDF_STATUS status; + + dsc_enter_str(desc); + status = __dsc_vdev_trans_start_wait(vdev, desc); + if (QDF_IS_STATUS_ERROR(status)) + dsc_exit_status(status); + + return status; +} + +static void __dsc_vdev_trigger_trans(struct dsc_vdev *vdev) +{ + if (__dsc_driver_trans_trigger_checked(vdev->psoc->driver)) + return; + + if (__dsc_psoc_trans_trigger_checked(vdev->psoc)) + return; + + __dsc_trans_trigger(&vdev->trans); +} + +static void __dsc_vdev_trans_stop(struct dsc_vdev *vdev) +{ + if (!dsc_assert(vdev)) + return; + + __dsc_driver_lock(vdev); + + __dsc_trans_stop(&vdev->trans); + __dsc_vdev_trigger_trans(vdev); + + __dsc_driver_unlock(vdev); +} + +void dsc_vdev_trans_stop(struct dsc_vdev *vdev) +{ + __dsc_vdev_trans_stop(vdev); +} + +static void __dsc_vdev_assert_trans_protected(struct dsc_vdev *vdev) +{ + if (!dsc_assert(vdev)) + return; + + __dsc_driver_lock(vdev); + dsc_assert(__dsc_trans_active(&vdev->trans) || + __dsc_trans_active(&vdev->psoc->trans) || + __dsc_trans_active(&vdev->psoc->driver->trans)); + __dsc_driver_unlock(vdev); +} + +void dsc_vdev_assert_trans_protected(struct dsc_vdev *vdev) +{ + __dsc_vdev_assert_trans_protected(vdev); +} + +static QDF_STATUS __dsc_vdev_op_start(struct dsc_vdev *vdev, const char *func) +{ + QDF_STATUS status; + + if (!dsc_assert(vdev)) + return QDF_STATUS_E_INVAL; + + if (!dsc_assert(func)) + return QDF_STATUS_E_INVAL; + + __dsc_driver_lock(vdev); + + status = __dsc_vdev_can_op(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto unlock; + + status = __dsc_ops_insert(&vdev->ops, func); + +unlock: + __dsc_driver_unlock(vdev); + + return status; +} + +QDF_STATUS _dsc_vdev_op_start(struct dsc_vdev *vdev, const char *func) +{ + QDF_STATUS status; + + /* do not log from here because it can flood log message because vdev + * op protect is per vdev operation + */ + + status = __dsc_vdev_op_start(vdev, func); + + return status; +} + +static void __dsc_vdev_op_stop(struct dsc_vdev *vdev, const char *func) +{ + if (!dsc_assert(vdev)) + return; + + if (!dsc_assert(func)) + return; + + __dsc_driver_lock(vdev); + if (__dsc_ops_remove(&vdev->ops, func)) + qdf_event_set(&vdev->ops.event); + __dsc_driver_unlock(vdev); +} + +void _dsc_vdev_op_stop(struct dsc_vdev *vdev, const char *func) +{ + /* do not log from here because it can flood log message because vdev + * op protect is per vdev operation + */ + __dsc_vdev_op_stop(vdev, func); +} + +static void __dsc_vdev_wait_for_ops(struct dsc_vdev *vdev) +{ + bool wait; + + if (!dsc_assert(vdev)) + return; + + __dsc_driver_lock(vdev); + + wait = vdev->ops.count > 0; + if (wait) + qdf_event_reset(&vdev->ops.event); + + __dsc_driver_unlock(vdev); + + if (wait) + qdf_wait_single_event(&vdev->ops.event, 0); +} + +void dsc_vdev_wait_for_ops(struct dsc_vdev *vdev) +{ + __dsc_vdev_wait_for_ops(vdev); +} + +uint8_t dsc_vdev_get_cached_cmd(struct dsc_vdev *vdev) +{ + return vdev->nb_cmd_during_ssr; +} + +void dsc_vdev_cache_command(struct dsc_vdev *vdev, uint8_t cmd_id) +{ + vdev->nb_cmd_during_ssr = cmd_id; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/test/wlan_dsc_test.c b/qcom/opensource/wlan/qcacld-3.0/components/dsc/test/wlan_dsc_test.c new file mode 100644 index 0000000000..fe4f2774ea --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/test/wlan_dsc_test.c @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "__wlan_dsc.h" +#include "qdf_event.h" +#include "qdf_threads.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_dsc.h" +#include "wlan_dsc_test.h" +#include "cds_api.h" + +#define dsc_driver_trans_start(driver) dsc_driver_trans_start(driver, __func__) +#define dsc_psoc_trans_start(psoc) dsc_psoc_trans_start(psoc, __func__) +#define dsc_vdev_trans_start(vdev) dsc_vdev_trans_start(vdev, __func__) + +#define dsc_driver_trans_start_wait(driver) \ + dsc_driver_trans_start_wait(driver, "") +#define dsc_psoc_trans_start_wait(psoc) \ + dsc_psoc_trans_start_wait(psoc, __func__) +#define dsc_vdev_trans_start_wait(vdev) \ + dsc_vdev_trans_start_wait(vdev, __func__) + +static struct dsc_psoc *nth_psoc(struct dsc_driver *driver, int n) +{ + struct dsc_psoc *psoc; + + QDF_BUG(n > 0); + if (n <= 0) + return NULL; + + dsc_for_each_driver_psoc(driver, psoc) { + n--; + if (n) + continue; + + return psoc; + } + + QDF_DEBUG_PANIC("Failed to find nth psoc: %d", n); + + return NULL; +} + +static struct dsc_vdev *nth_vdev(struct dsc_psoc *psoc, int n) +{ + struct dsc_vdev *vdev; + + QDF_BUG(n > 0); + if (n <= 0) + return NULL; + + dsc_for_each_psoc_vdev(psoc, vdev) { + n--; + if (n) + continue; + + return vdev; + } + + QDF_DEBUG_PANIC("Failed to find nth vdev: %d", n); + + return NULL; +} + +static void __dsc_tree_destroy(struct dsc_driver *driver) +{ + struct dsc_psoc *psoc; + struct dsc_psoc *next_psoc; + + QDF_BUG(driver); + + qdf_list_for_each_del(&driver->psocs, psoc, next_psoc, node) { + struct dsc_vdev *vdev; + struct dsc_vdev *next_vdev; + + qdf_list_for_each_del(&psoc->vdevs, vdev, next_vdev, node) + dsc_vdev_destroy(&vdev); + + dsc_psoc_destroy(&psoc); + } + + dsc_driver_destroy(&driver); +} + +static QDF_STATUS __dsc_tree_create(struct dsc_driver **out_driver, + uint8_t psocs_per_driver, + uint8_t vdevs_per_psoc) +{ + QDF_STATUS status; + struct dsc_driver *driver; + int i, j; + + status = dsc_driver_create(&driver); + if (QDF_IS_STATUS_ERROR(status)) { + dsc_err("Failed to create driver; status:%u", status); + return status; + } + + for (i = 0; i < psocs_per_driver; i++) { + struct dsc_psoc *psoc; + + status = dsc_psoc_create(driver, &psoc); + if (QDF_IS_STATUS_ERROR(status)) { + dsc_err("Failed to create psoc; status:%u", status); + goto free_tree; + } + + for (j = 0; j < vdevs_per_psoc; j++) { + struct dsc_vdev *vdev; + + status = dsc_vdev_create(psoc, &vdev); + if (QDF_IS_STATUS_ERROR(status)) { + dsc_err("Failed to create vdev; status:%u", + status); + goto free_tree; + } + } + } + + *out_driver = driver; + + return QDF_STATUS_SUCCESS; + +free_tree: + __dsc_tree_destroy(driver); + + return status; +} + +static uint32_t dsc_test_create_destroy(void) +{ + uint32_t errors = 0; + QDF_STATUS status; + struct dsc_driver *driver; + + dsc_enter(); + + status = __dsc_tree_create(&driver, 2, 2); + if (QDF_IS_STATUS_ERROR(status)) { + errors++; + goto exit; + } + + __dsc_tree_destroy(driver); + +exit: + dsc_exit(); + + return errors; +} + +#define action_expect(obj, action, status, errors) \ +do { \ + void *__obj = obj; \ + QDF_STATUS __expected = status; \ + QDF_STATUS __result; \ +\ + __result = dsc_##obj##_##action##_start(__obj); \ + if (__result != __expected) { \ + dsc_err("FAIL: " #obj " " #action \ + "; expected " #status " (%u), found %u", \ + __expected, __result); \ + (errors)++; \ + } \ + if (QDF_IS_STATUS_SUCCESS(__result) && QDF_IS_STATUS_ERROR(__expected))\ + dsc_##obj##_##action##_stop(__obj); \ +} while (false) + +static uint32_t dsc_test_driver_trans_blocks(void) +{ + uint32_t errors = 0; + QDF_STATUS status; + struct dsc_driver *driver; + struct dsc_psoc *psoc; + struct dsc_vdev *vdev; + + dsc_enter(); + + /* setup */ + + status = __dsc_tree_create(&driver, 2, 2); + if (QDF_IS_STATUS_ERROR(status)) { + errors++; + goto exit; + } + + /* test */ + /* a driver in transition should cause ... */ + action_expect(driver, trans, QDF_STATUS_SUCCESS, errors); + + /* ... the same driver trans/ops to fail */ + action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + + /* ... children psoc trans/ops to fail */ + dsc_for_each_driver_psoc(driver, psoc) { + action_expect(psoc, trans, QDF_STATUS_E_INVAL, errors); + action_expect(psoc, op, QDF_STATUS_E_INVAL, errors); + + /* ... grandchildren vdev trans/ops to fail */ + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); + } + } + + /* teardown */ + + dsc_driver_trans_stop(driver); + + __dsc_tree_destroy(driver); + +exit: + dsc_exit(); + + return errors; +} + +static uint32_t dsc_test_psoc_trans_blocks(void) +{ + uint32_t errors = 0; + QDF_STATUS status; + struct dsc_driver *driver; + struct dsc_psoc *psoc; + struct dsc_vdev *vdev; + + dsc_enter(); + + /* setup */ + + status = __dsc_tree_create(&driver, 2, 2); + if (QDF_IS_STATUS_ERROR(status)) { + errors++; + goto exit; + } + + /* test */ + /* a psoc in transition should cause ... */ + psoc = nth_psoc(driver, 1); + action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors); + + /* ... driver trans/ops to fail */ + action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + + /* ... the same psoc trans/ops to fail */ + action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors); + + /* ... children vdev trans/ops to fail */ + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_BUSY, errors); + action_expect(vdev, op, QDF_STATUS_E_BUSY, errors); + } + + /* ... while driver unload in progress vdev op and trans should be + * rejected with EINVAL + */ + cds_set_unload_in_progress(true); + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); + } + cds_set_unload_in_progress(false); + + /* ... while SSR recovery in progress vdev op and trans should be + * rejected with EINVAL + */ + cds_set_recovery_in_progress(true); + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_INVAL, errors); + action_expect(vdev, op, QDF_STATUS_E_INVAL, errors); + } + cds_set_recovery_in_progress(false); + + /* a sibling psoc in transition should succeed and cause ... */ + psoc = nth_psoc(driver, 2); + action_expect(psoc, trans, QDF_STATUS_SUCCESS, errors); + + /* ... driver trans/ops to fail */ + action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + + /* ... the same psoc trans/ops to fail */ + action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors); + + /* ... children vdev trans/ops to fail */ + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_BUSY, errors); + action_expect(vdev, op, QDF_STATUS_E_BUSY, errors); + } + + /* teardown */ + + dsc_for_each_driver_psoc(driver, psoc) + dsc_psoc_trans_stop(psoc); + + __dsc_tree_destroy(driver); + +exit: + dsc_exit(); + + return errors; +} + +static uint32_t dsc_test_vdev_trans_blocks(void) +{ + uint32_t errors = 0; + QDF_STATUS status; + struct dsc_driver *driver; + struct dsc_psoc *psoc; + struct dsc_vdev *vdev; + + dsc_enter(); + + /* setup */ + + status = __dsc_tree_create(&driver, 2, 2); + if (QDF_IS_STATUS_ERROR(status)) { + errors++; + goto exit; + } + + /* test */ + + /* a vdev in transition should cause ... */ + dsc_for_each_driver_psoc(driver, psoc) { + dsc_for_each_psoc_vdev(psoc, vdev) + action_expect(vdev, trans, QDF_STATUS_SUCCESS, errors); + } + + /* ... driver trans/ops to fail */ + action_expect(driver, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(driver, op, QDF_STATUS_E_AGAIN, errors); + + /* ... psoc trans/ops to fail */ + dsc_for_each_driver_psoc(driver, psoc) { + action_expect(psoc, trans, QDF_STATUS_E_AGAIN, errors); + action_expect(psoc, op, QDF_STATUS_E_AGAIN, errors); + + /* ... the same vdev trans/ops to fail */ + dsc_for_each_psoc_vdev(psoc, vdev) { + action_expect(vdev, trans, QDF_STATUS_E_BUSY, errors); + action_expect(vdev, op, QDF_STATUS_E_BUSY, errors); + } + } + + /* teardown */ + + dsc_for_each_driver_psoc(driver, psoc) { + dsc_for_each_psoc_vdev(psoc, vdev) + dsc_vdev_trans_stop(vdev); + } + + __dsc_tree_destroy(driver); + +exit: + dsc_exit(); + + return errors; +} + +#define THREAD_TIMEOUT 1000 /* ms */ +#define dsc_event_wait(event) qdf_wait_single_event(event, THREAD_TIMEOUT) + +#define step_assert(field, expected) \ +do { \ + uint32_t _step = ++(field); \ + uint32_t _expected = (expected); \ +\ + if (_step != _expected) \ + QDF_DEBUG_PANIC("Step count is %u; Expected %u", \ + _step, _expected); \ +} while (false) + +#define trans_waiting(ctx) (!qdf_list_empty(&(ctx)->trans.queue)) + +struct thread_ctx { + struct dsc_driver *driver; + qdf_event_t start_vdev_trans; + qdf_event_t start_vdev_wait; + uint32_t step; +}; + +static QDF_STATUS dsc_thread_ops(void *context) +{ + struct thread_ctx *ctx = context; + struct dsc_driver *driver = ctx->driver; + struct dsc_psoc *psoc = nth_psoc(driver, 1); + struct dsc_vdev *vdev = nth_vdev(psoc, 1); + + dsc_enter(); + + /* thread 1 is doing some operations ... */ + step_assert(ctx->step, 1); + dsc_assert_success(dsc_driver_op_start(driver)); + dsc_assert_success(dsc_psoc_op_start(psoc)); + dsc_assert_success(dsc_vdev_op_start(vdev)); + step_assert(ctx->step, 2); + + /* ... at which point, thread 2 starts to transition the vdevs */ + qdf_event_set(&ctx->start_vdev_trans); + + /* meanwhile, thread 3,4,5 queue up to transition vdev/psoc/driver */ + while (!trans_waiting(driver)) + schedule(); + + /* at this point, each thread is: + * 1) doing operations + * 2) transitioning vdevs 1/2, waiting for ops to finish + * 3) waiting to transition vdev 1 + * 4) waiting to transition psoc + * 5) waitint to transition driver + */ + + step_assert(ctx->step, 8); + dsc_driver_op_stop(driver); + schedule(); + dsc_psoc_op_stop(psoc); + schedule(); + dsc_vdev_op_stop(vdev); + + /* all operations complete; thread2 is now unblocked */ + + dsc_exit(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dsc_thread_vdev_trans(void *context) +{ + struct thread_ctx *ctx = context; + struct dsc_driver *driver = ctx->driver; + struct dsc_psoc *psoc = nth_psoc(driver, 1); + struct dsc_vdev *vdev; + + dsc_enter(); + + /* wait for thread 1 to start operations */ + dsc_assert_success(dsc_event_wait(&ctx->start_vdev_trans)); + + /* start transitions on all vdevs */ + step_assert(ctx->step, 3); + dsc_for_each_psoc_vdev(psoc, vdev) + dsc_assert_success(dsc_vdev_trans_start(vdev)); + step_assert(ctx->step, 4); + + /* meanwhile, thread 3,4,5 queue up to transition vdev/psoc/driver */ + qdf_event_set(&ctx->start_vdev_wait); + + /* wait for thread 1 to complete pending vdev ops */ + dsc_for_each_psoc_vdev(psoc, vdev) + dsc_vdev_wait_for_ops(vdev); + + /* actual vdev transition work would happen here */ + + /* stop transition on vdev 1 */ + step_assert(ctx->step, 9); + dsc_vdev_trans_stop(nth_vdev(psoc, 1)); + + /* psoc trans should not start until both vdev trans are complete */ + schedule(); + step_assert(ctx->step, 10); + dsc_vdev_trans_stop(nth_vdev(psoc, 2)); + + dsc_exit(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dsc_thread_vdev_wait(void *context) +{ + struct thread_ctx *ctx = context; + struct dsc_vdev *vdev = nth_vdev(nth_psoc(ctx->driver, 1), 1); + + dsc_enter(); + + dsc_assert_success(dsc_event_wait(&ctx->start_vdev_wait)); + + step_assert(ctx->step, 5); + /* vdev trans queues first ... */ + dsc_assert_success(dsc_vdev_trans_start_wait(vdev)); + /* ... but de-queues third */ + step_assert(ctx->step, 15); + + dsc_vdev_wait_for_ops(vdev); + + step_assert(ctx->step, 16); + dsc_vdev_trans_stop(vdev); + + dsc_exit(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dsc_thread_psoc_wait(void *context) +{ + struct thread_ctx *ctx = context; + struct dsc_psoc *psoc = nth_psoc(ctx->driver, 1); + struct dsc_vdev *vdev = nth_vdev(psoc, 1); + + dsc_enter(); + + while (!trans_waiting(vdev)) + schedule(); + + step_assert(ctx->step, 6); + /* psoc trans queues second ... */ + dsc_assert_success(dsc_psoc_trans_start_wait(psoc)); + /* ... and de-queues second */ + step_assert(ctx->step, 13); + + dsc_psoc_wait_for_ops(psoc); + + step_assert(ctx->step, 14); + dsc_psoc_trans_stop(psoc); + + dsc_exit(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dsc_thread_driver_wait(void *context) +{ + struct thread_ctx *ctx = context; + struct dsc_driver *driver = ctx->driver; + struct dsc_psoc *psoc = nth_psoc(driver, 1); + + dsc_enter(); + + while (!trans_waiting(psoc)) + schedule(); + + step_assert(ctx->step, 7); + /* driver trans queues third ... */ + dsc_assert_success(dsc_driver_trans_start_wait(driver)); + /* ... but de-queues first */ + step_assert(ctx->step, 11); + + dsc_driver_wait_for_ops(driver); + + step_assert(ctx->step, 12); + dsc_driver_trans_stop(driver); + + dsc_exit(); + + return QDF_STATUS_SUCCESS; +} + +static uint32_t dsc_test_trans_wait(void) +{ + uint32_t errors = 0; + QDF_STATUS status; + qdf_thread_t *ops_thread; + qdf_thread_t *vdev_trans_thread; + qdf_thread_t *vdev_wait_thread; + qdf_thread_t *psoc_wait_thread; + qdf_thread_t *driver_wait_thread; + struct thread_ctx ctx = { 0 }; + + dsc_enter(); + + status = __dsc_tree_create(&ctx.driver, 1, 2); + if (QDF_IS_STATUS_ERROR(status)) { + errors++; + goto exit; + } + + dsc_assert_success(qdf_event_create(&ctx.start_vdev_trans)); + dsc_assert_success(qdf_event_create(&ctx.start_vdev_wait)); + + dsc_debug("starting threads"); + + ops_thread = qdf_thread_run(dsc_thread_ops, &ctx); + vdev_trans_thread = qdf_thread_run(dsc_thread_vdev_trans, &ctx); + vdev_wait_thread = qdf_thread_run(dsc_thread_vdev_wait, &ctx); + psoc_wait_thread = qdf_thread_run(dsc_thread_psoc_wait, &ctx); + driver_wait_thread = qdf_thread_run(dsc_thread_driver_wait, &ctx); + + qdf_thread_join(ops_thread); + qdf_thread_join(vdev_trans_thread); + qdf_thread_join(vdev_wait_thread); + qdf_thread_join(psoc_wait_thread); + qdf_thread_join(driver_wait_thread); + + dsc_debug("threads joined"); + + qdf_event_destroy(&ctx.start_vdev_wait); + qdf_event_destroy(&ctx.start_vdev_trans); + + __dsc_tree_destroy(ctx.driver); + +exit: + dsc_exit(); + + return errors; +} + +uint32_t dsc_unit_test(void) +{ + uint32_t errors = 0; + + errors += dsc_test_create_destroy(); + errors += dsc_test_driver_trans_blocks(); + errors += dsc_test_psoc_trans_blocks(); + errors += dsc_test_vdev_trans_blocks(); + errors += dsc_test_trans_wait(); + + return errors; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/dsc/test/wlan_dsc_test.h b/qcom/opensource/wlan/qcacld-3.0/components/dsc/test/wlan_dsc_test.h new file mode 100644 index 0000000000..b2c23d2ace --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/dsc/test/wlan_dsc_test.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_DSC_TEST +#define __WLAN_DSC_TEST + +#ifdef WLAN_DSC_TEST +/** + * dsc_unit_test() - run the dsc unit test suite + * + * Return: number of failed test cases + */ +uint32_t dsc_unit_test(void); +#else +static inline uint32_t dsc_unit_test(void) +{ + return 0; +} +#endif /* WLAN_DSC_TEST */ + +#endif /* __WLAN_DSC_TEST */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_main.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_main.h new file mode 100644 index 0000000000..e9e5e915d6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_main.h @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in ftm_time_sync component. This file shall include prototypes of + * various notification handlers and logging functions. + * + * Note: This API should be never accessed out of ftm_time_sync component. + */ + +#ifndef _FTM_TIME_SYNC_MAIN_H_ +#define _FTM_TIME_SYNC_MAIN_H_ + +#include +#include +#include "ftm_time_sync_priv.h" +#include "ftm_time_sync_objmgr.h" + +#define ftm_time_sync_log(level, args...) \ + QDF_TRACE(QDF_MODULE_ID_FTM_TIME_SYNC, level, ## args) + +#define ftm_time_sync_logfl(level, format, args...) \ + ftm_time_sync_log(level, FL(format), ## args) + +#define ftm_time_sync_fatal(format, args...) \ + ftm_time_sync_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define ftm_time_sync_err(format, args...) \ + ftm_time_sync_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define ftm_time_sync_warn(format, args...) \ + ftm_time_sync_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define ftm_time_sync_info(format, args...) \ + ftm_time_sync_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define ftm_time_sync_debug(format, args...) \ + ftm_time_sync_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define FTM_TIME_SYNC_ENTER() ftm_time_sync_debug("enter") +#define FTM_TIME_SYNC_EXIT() ftm_time_sync_debug("exit") + +/** + * ftm_time_sync_vdev_create_notification() - Handler for vdev create notify. + * @vdev: vdev which is going to be created by objmgr + * @arg: argument for notification handler + * + * Allocate and attach vdev private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS ftm_time_sync_vdev_create_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * ftm_time_sync_vdev_destroy_notification() - Handler for vdev destroy notify. + * @vdev: vdev which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach vdev private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ftm_time_sync_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * ftm_time_sync_psoc_create_notification() - Handler for psoc create notify. + * @psoc: psoc which is going to be created by objmgr + * @arg: argument for notification handler. + * + * Allocate and attach psoc private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ftm_time_sync_psoc_create_notification(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * ftm_time_sync_psoc_destroy_notification() - Handler for psoc destroy notify. + * @psoc: psoc which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach psoc private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ftm_time_sync_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * ftm_time_sync_is_enable() - Function to advertise feature is enabled or not + * @psoc: psoc context + * + * This function advertises whether the feature is enabled or not. + * + * Return: true if enable, false if disable + */ +bool ftm_time_sync_is_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ftm_time_sync_set_enable() - Handler to enable the feature + * @psoc: psoc context + * @value: value to be set + * + * This function is used to enable the ftm time sync feature. + * The feature is enabled iff both ini and wmi service is advertised by + * firmware. + * + * Return: None + */ +void ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * ftm_time_sync_get_mode() - API to get the ftm time sync mode + * @psoc: psoc context + * + * Return: enum ftm_time_sync_mode + */ +enum ftm_time_sync_mode ftm_time_sync_get_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ftm_time_sync_get_role() - API to get the ftm time sync role + * @psoc: psoc context + * + * Return: enum ftm_time_sync_role + */ +enum ftm_time_sync_role ftm_time_sync_get_role(struct wlan_objmgr_psoc *psoc); + +/** + * ftm_time_sync_send_trigger() - Handler for sending trigger cmd to FW + * @vdev: vdev for which FTM time_sync trigger cmd to be send + * + * This function sends the ftm trigger cmd to target. + * + * Return: QDF_STATUS + */ +QDF_STATUS ftm_time_sync_send_trigger(struct wlan_objmgr_vdev *vdev); + +/** + * ftm_time_sync_stop() - Handler for stopping the FTM time sync + * @vdev: vdev for which FTM time_sync feature to be stopped + * + * This function stops the ftm time sync functionality. + * + * Return: QDF_STATUS + */ +QDF_STATUS ftm_time_sync_stop(struct wlan_objmgr_vdev *vdev); + +/** + * ftm_time_sync_show() - Handler to print the offset derived + * @vdev: vdev for which offset is to be shown + * @buf: buffer in which the values to be printed + * + * Return: the number of bytes written in buf + */ +ssize_t ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf); + +/** + * ftm_time_sync_update_bssid() - Update the bssid info + * @vdev: vdev context + * @bssid: bssid of connected AP + * + * Return: None + */ +void ftm_time_sync_update_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr bssid); + +#endif /* end of _FTM_TIME_SYNC_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_objmgr.h new file mode 100644 index 0000000000..4b77c6e4f1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_objmgr.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains various object manager related wrappers and helpers + */ + +#ifndef _FTM_TIME_SYNC_OBJMGR_H +#define _FTM_TIME_SYNC_OBJMGR_H + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_global_obj.h" + +/** + * ftm_time_sync_vdev_get_ref() - Wrapper to increment ftm_time_sync ref count + * @vdev: vdev object + * + * Wrapper for ftm_time_sync to increment ref count after checking valid + * object state. + * + * Return: SUCCESS/FAILURE + */ +static inline +QDF_STATUS ftm_time_sync_vdev_get_ref(struct wlan_objmgr_vdev *vdev) +{ + return wlan_objmgr_vdev_try_get_ref(vdev, FTM_TIME_SYNC_ID); +} + +/** + * ftm_time_sync_vdev_put_ref() - Wrapper to decrement ftm_time_sync ref count + * @vdev: vdev object + * + * Wrapper for ftm_time_sync to decrement ref count of vdev. + * + * Return: SUCCESS/FAILURE + */ +static inline +void ftm_time_sync_vdev_put_ref(struct wlan_objmgr_vdev *vdev) +{ + return wlan_objmgr_vdev_release_ref(vdev, FTM_TIME_SYNC_ID); +} + +/** + * ftm_time_sync_vdev_get_priv() - Wrapper to retrieve vdev priv obj + * @vdev: vdev pointer + * + * Wrapper for ftm_time_sync to get vdev private object pointer. + * + * Return: Private object of vdev + */ +static inline struct ftm_time_sync_vdev_priv * +ftm_time_sync_vdev_get_priv(struct wlan_objmgr_vdev *vdev) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + + vdev_priv = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC); + QDF_BUG(vdev_priv); + + return vdev_priv; +} + +/** + * ftm_time_sync_psoc_get_ref() - Wrapper to increment ftm_time sync ref count + * @psoc: psoc object + * + * Wrapper for ftm time sync to increment ref count after checking valid + * object state. + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ftm_time_sync_psoc_get_ref(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_try_get_ref(psoc, FTM_TIME_SYNC_ID); +} + +/** + * ftm_time_sync_psoc_put_ref() - Wrapper to decrement ftm time sync ref count + * @psoc: psoc object + * + * Wrapper for ftm time sync to decrement ref count of psoc. + * + * Return: None + */ +static inline +void ftm_time_sync_psoc_put_ref(struct wlan_objmgr_psoc *psoc) +{ + wlan_objmgr_psoc_release_ref(psoc, FTM_TIME_SYNC_ID); +} + +/** + * ftm_time_sync_psoc_get_priv() - Wrapper to retrieve psoc priv obj + * @psoc: psoc pointer + * + * Wrapper for ftm time sync to get psoc private object pointer. + * + * Return: ftm time sync psoc private object + */ +static inline struct ftm_time_sync_psoc_priv * +ftm_time_sync_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + + psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( + psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC); + QDF_BUG(psoc_priv); + + return psoc_priv; +} +#endif /* _FTM_TIME_SYNC_OBJMGR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h new file mode 100644 index 0000000000..00a6ac276d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/inc/ftm_time_sync_priv.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in ftm_time_sync component. This file shall include prototypes of + * ftm_time_sync parsing and send logic. + * + * Note: This API should be never accessed out of ftm_time_sync component. + */ + +#ifndef _FTM_TIME_SYNC_PRIV_STRUCT_H_ +#define _FTM_TIME_SYNC_PRIV_STRUCT_H_ + +#include +#include +#include "ftm_time_sync_objmgr.h" +#include "wlan_ftm_time_sync_public_struct.h" + +#define WLAN_FTM_TIME_SYNC_PAIR_MAX 32 + +/** + * struct wlan_time_sync_pair - wlan time sync pair + * @qtime_initiator: initiator qtime + * @qtime_target: target qtime + */ +struct wlan_time_sync_pair { + uint64_t qtime_initiator; + uint64_t qtime_target; +}; + +/** + * struct ftm_time_sync_priv - Private object to be stored in vdev + * @qtime_ref: qtime ref + * @mac_ref: mac time ref + * @time_pair: array of initiator/target qtime pair + */ + +struct ftm_time_sync_priv { + uint64_t qtime_ref; + uint64_t mac_ref; + struct wlan_time_sync_pair time_pair[WLAN_FTM_TIME_SYNC_PAIR_MAX]; +}; + +/** + * struct ftm_time_sync_cfg - Cfg ini param for FTM time sync + * @enable: FTM time_sync feature enable/disable + * @mode: Aggregated/burst mode applicable iff enable = 1 + * @role: Target/Initiator Role applicable iff enable = 1 + */ +struct ftm_time_sync_cfg { + bool enable; + enum ftm_time_sync_mode mode; + enum ftm_time_sync_role role; +}; + +/** + * struct ftm_time_sync_psoc_priv - Private object to be stored in psoc + * @psoc: pointer to psoc object + * @cfg_param: INI config param for ftm time sync + */ +struct ftm_time_sync_psoc_priv { + struct wlan_objmgr_psoc *psoc; + struct ftm_time_sync_cfg cfg_param; +}; + +/** + * struct ftm_time_sync_vdev_priv - Private object to be stored in vdev + * @vdev: pointer to vdev object + * @ftm_ts_priv: time sync private struct + * @rx_ops: rx operations for ftm time sync + * @tx_ops: tx operations for ftm time sync + * @ftm_time_sync_mutex: mutex to access ftm time sync priv members + * @ftm_time_sync_work: work to capture audio qtime and send it to FW + * @time_sync_interval: interval between two qtime capture + * @num_qtime_pair: number of qinitiator and qtarget pair derived + * @num_reads: number of times the qtime to be captured + * @valid: send qtime to FW only if this is true + * @bssid: bssid of connected AP + */ +struct ftm_time_sync_vdev_priv { + struct wlan_objmgr_vdev *vdev; + struct ftm_time_sync_priv ftm_ts_priv; + struct wlan_ftm_time_sync_rx_ops rx_ops; + struct wlan_ftm_time_sync_tx_ops tx_ops; + qdf_mutex_t ftm_time_sync_mutex; + struct qdf_delayed_work ftm_time_sync_work; + uint32_t time_sync_interval; + int num_qtime_pair; + int num_reads; + bool valid; + struct qdf_mac_addr bssid; +}; + +#endif /* End of _FTM_TIME_SYNC_PRIV_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/src/ftm_time_sync_main.c b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/src/ftm_time_sync_main.c new file mode 100644 index 0000000000..120b52ac3c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/core/src/ftm_time_sync_main.c @@ -0,0 +1,428 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement various notification handlers which are accessed + * internally in ftm_time_sync component only. + */ + +#include "ftm_time_sync_main.h" +#include "target_if_ftm_time_sync.h" +#include "wlan_objmgr_vdev_obj.h" +#include "cfg_ftm_time_sync.h" +#include "cfg_ucfg_api.h" +#include + +void ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + + if (!psoc) { + ftm_time_sync_err("psoc is NULL"); + return; + } + + psoc_priv = ftm_time_sync_psoc_get_priv(psoc); + if (!psoc_priv) { + ftm_time_sync_err("psoc priv is NULL"); + return; + } + + psoc_priv->cfg_param.enable &= value; +} + +bool ftm_time_sync_is_enable(struct wlan_objmgr_psoc *psoc) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + + if (!psoc) { + ftm_time_sync_err("psoc is NULL"); + return false; + } + + psoc_priv = ftm_time_sync_psoc_get_priv(psoc); + if (!psoc_priv) { + ftm_time_sync_err("psoc priv is NULL"); + return false; + } + + return psoc_priv->cfg_param.enable; +} + +enum ftm_time_sync_mode ftm_time_sync_get_mode(struct wlan_objmgr_psoc *psoc) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + + if (!psoc) { + ftm_time_sync_err("psoc is NULL"); + return FTM_TIMESYNC_AGGREGATED_MODE; + } + + psoc_priv = ftm_time_sync_psoc_get_priv(psoc); + if (!psoc_priv) { + ftm_time_sync_err("psoc priv is NULL"); + return FTM_TIMESYNC_AGGREGATED_MODE; + } + + return psoc_priv->cfg_param.mode; +} + +enum ftm_time_sync_role ftm_time_sync_get_role(struct wlan_objmgr_psoc *psoc) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + + if (!psoc) { + ftm_time_sync_err("psoc is NULL"); + return FTM_TIMESYNC_TARGET_ROLE; + } + + psoc_priv = ftm_time_sync_psoc_get_priv(psoc); + if (!psoc_priv) { + ftm_time_sync_err("psoc priv is NULL"); + return FTM_TIMESYNC_TARGET_ROLE; + } + + return psoc_priv->cfg_param.role; +} + +static void ftm_time_sync_work_handler(void *arg) +{ + struct ftm_time_sync_vdev_priv *vdev_priv = arg; + struct wlan_objmgr_psoc *psoc; + qdf_device_t qdf_dev; + QDF_STATUS status; + uint8_t vdev_id; + uint64_t lpass_ts; + + if (!vdev_priv) { + ftm_time_sync_err("ftm vdev priv is Null"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev_priv->vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return; + } + + vdev_id = wlan_vdev_get_id(vdev_priv->vdev); + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + pld_get_audio_wlan_timestamp(qdf_dev->dev, PLD_TRIGGER_NEGATIVE_EDGE, + &lpass_ts); + + qdf_mutex_acquire(&vdev_priv->ftm_time_sync_mutex); + + if (vdev_priv->num_reads) { + vdev_priv->num_reads--; + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + qdf_delayed_work_start(&vdev_priv->ftm_time_sync_work, + vdev_priv->time_sync_interval); + } else { + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + } + + if (vdev_priv->valid) { + status = vdev_priv->tx_ops.ftm_time_sync_send_qtime( + psoc, vdev_id, lpass_ts); + if (status != QDF_STATUS_SUCCESS) + ftm_time_sync_err("send_ftm_time_sync_qtime failed %d", + status); + vdev_priv->valid = false; + } else { + vdev_priv->valid = true; + } +} + +QDF_STATUS +ftm_time_sync_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + if (!ftm_time_sync_is_enable(psoc)) + return QDF_STATUS_SUCCESS; + + vdev_priv = qdf_mem_malloc(sizeof(*vdev_priv)); + if (!vdev_priv) { + status = QDF_STATUS_E_NOMEM; + goto exit; + } + + status = wlan_objmgr_vdev_component_obj_attach( + vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC, + (void *)vdev_priv, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to attach priv with vdev"); + goto free_vdev_priv; + } + + vdev_priv->vdev = vdev; + status = qdf_delayed_work_create(&vdev_priv->ftm_time_sync_work, + ftm_time_sync_work_handler, vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to create ftm time sync work\n"); + goto free_vdev_priv; + } + + qdf_mutex_create(&vdev_priv->ftm_time_sync_mutex); + + target_if_ftm_time_sync_register_tx_ops(&vdev_priv->tx_ops); + target_if_ftm_time_sync_register_rx_ops(&vdev_priv->rx_ops); + + vdev_priv->rx_ops.ftm_time_sync_register_start_stop(psoc); + vdev_priv->rx_ops.ftm_time_sync_regiser_initiator_target_offset(psoc); + + vdev_priv->valid = true; + + goto exit; + +free_vdev_priv: + qdf_mem_free(vdev_priv); + status = QDF_STATUS_E_INVAL; +exit: + return status; +} + +static QDF_STATUS +ftm_time_sync_deregister_wmi_events(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + status = target_if_ftm_time_sync_unregister_ev_handlers(psoc); + return status; +} + +QDF_STATUS +ftm_time_sync_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, + void *arg) + +{ + struct ftm_time_sync_vdev_priv *vdev_priv = NULL; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + if (!ftm_time_sync_is_enable(psoc)) + return QDF_STATUS_SUCCESS; + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + if (!vdev_priv) { + ftm_time_sync_err("vdev priv is NULL"); + goto exit; + } + + qdf_mutex_destroy(&vdev_priv->ftm_time_sync_mutex); + qdf_delayed_work_destroy(&vdev_priv->ftm_time_sync_work); + + ftm_time_sync_deregister_wmi_events(vdev); + + status = wlan_objmgr_vdev_component_obj_detach( + vdev, WLAN_UMAC_COMP_FTM_TIME_SYNC, + (void *)vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) + ftm_time_sync_err("Failed to detach priv with vdev"); + + qdf_mem_free(vdev_priv); + vdev_priv = NULL; + +exit: + return status; +} + +static void +ftm_time_sync_cfg_init(struct ftm_time_sync_psoc_priv *psoc_priv) +{ + psoc_priv->cfg_param.enable = cfg_get(psoc_priv->psoc, + CFG_ENABLE_TIME_SYNC_FTM); + psoc_priv->cfg_param.role = cfg_get(psoc_priv->psoc, + CFG_TIME_SYNC_FTM_ROLE); + psoc_priv->cfg_param.mode = cfg_get(psoc_priv->psoc, + CFG_TIME_SYNC_FTM_MODE); +} + +QDF_STATUS +ftm_time_sync_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + QDF_STATUS status; + + psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv)); + if (!psoc_priv) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_attach( + psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC, + psoc_priv, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to attach psoc component obj"); + goto free_psoc_priv; + } + + psoc_priv->psoc = psoc; + ftm_time_sync_cfg_init(psoc_priv); + + return status; + +free_psoc_priv: + qdf_mem_free(psoc_priv); + return status; +} + +QDF_STATUS +ftm_time_sync_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + struct ftm_time_sync_psoc_priv *psoc_priv; + QDF_STATUS status; + + psoc_priv = ftm_time_sync_psoc_get_priv(psoc); + if (!psoc_priv) { + ftm_time_sync_err("psoc priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_psoc_component_obj_detach( + psoc, WLAN_UMAC_COMP_FTM_TIME_SYNC, + psoc_priv); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to detach psoc component obj"); + return status; + } + + qdf_mem_free(psoc_priv); + return status; +} + +QDF_STATUS ftm_time_sync_send_trigger(struct wlan_objmgr_vdev *vdev) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + struct wlan_objmgr_psoc *psoc; + enum ftm_time_sync_mode mode; + uint8_t vdev_id; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + if (!vdev_priv) { + ftm_time_sync_err("Failed to get ftm time sync vdev_priv"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = wlan_vdev_get_id(vdev_priv->vdev); + mode = ftm_time_sync_get_mode(psoc); + + status = vdev_priv->tx_ops.ftm_time_sync_send_trigger(psoc, + vdev_id, mode); + if (QDF_IS_STATUS_ERROR(status)) + ftm_time_sync_err("send_ftm_time_sync_trigger failed %d", + status); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ftm_time_sync_stop(struct wlan_objmgr_vdev *vdev) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + int iter; + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + if (!vdev_priv) { + ftm_time_sync_err("Failed to get ftm time sync vdev_priv"); + return QDF_STATUS_E_INVAL; + } + + qdf_delayed_work_stop_sync(&vdev_priv->ftm_time_sync_work); + + for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) { + vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator = 0; + vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target = 0; + } + + vdev_priv->num_qtime_pair = 0; + + return QDF_STATUS_SUCCESS; +} + +ssize_t ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + uint64_t q_initiator, q_target; + ssize_t size = 0; + int iter; + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + if (!vdev_priv) { + ftm_time_sync_debug("Failed to get ftm time sync vdev_priv"); + return 0; + } + + size = qdf_scnprintf(buf, PAGE_SIZE, + "%s " QDF_MAC_ADDR_FMT "\n", "BSSID", + QDF_MAC_ADDR_REF(vdev_priv->bssid.bytes)); + + for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) { + q_initiator = vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator; + q_target = vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target; + + size += qdf_scnprintf(buf + size, PAGE_SIZE - size, + "%s %llu %s %llu %s %lld\n", + + "Qtime_initiator", q_initiator, "Qtime_target", + q_target, "Offset", q_target > q_initiator ? + q_target - q_initiator : q_initiator - q_target); + } + return size; +} + +void ftm_time_sync_update_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr bssid) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + if (!vdev_priv) { + ftm_time_sync_debug("Failed to get ftm time sync vdev_priv"); + return; + } + + vdev_priv->bssid = bssid; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/cfg_ftm_time_sync.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/cfg_ftm_time_sync.h new file mode 100644 index 0000000000..876881eb0d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/cfg_ftm_time_sync.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__FTM_TIME_SYNC_CFG_H__) +#define __FTM_TIME_SYNC_CFG_H__ + +/** + * DOC: ftm_time_sync_cfg.h + * + * FTM TIME SYNC feature INI configuration parameter definitions + */ + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM + +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" + +/* + * + * enable_time_sync_ftm - Time Sync FTM feature support + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * When set to 1 Time Sync FTM feature will be enabled. + * + * Supported Feature: Time Sync FTM + * + * Usage: External + * + * + */ +#define CFG_ENABLE_TIME_SYNC_FTM CFG_INI_BOOL("enable_time_sync_ftm", \ + 0, \ + "Enable Time Sync FTM Support") +/* + * + * time_sync_ftm_mode- Time Sync FTM feature Mode configuration + * @Min: 0 - Aggregated Mode + * @Max: 1 - Burst Mode + * @Default: 0 + * + * This ini is applicable only if enable_time_sync_ftm is set to 1. + * + * Supported Feature: Time Sync FTM + * + * Usage: External + * + * + */ +#define CFG_TIME_SYNC_FTM_MODE CFG_INI_BOOL("time_sync_ftm_mode", \ + 0, \ + "Configure Time Sync FTM Mode") +/* + * + * time_sync_ftm_role- Time Sync FTM feature Role configuration + * @Min: 0 - Target Role + * @Max: 1 - Initiator Role + * @Default: 0 + * + * This ini is applicable only if enable_time_sync_ftm is set to 1. + * + * Supported Feature: Time Sync FTM + * + * Usage: External + * + * + */ +#define CFG_TIME_SYNC_FTM_ROLE CFG_INI_BOOL("time_sync_ftm_role", \ + 0, \ + "Configure Time Sync FTM Role") + +#define CFG_TIME_SYNC_FTM_ALL \ + CFG(CFG_ENABLE_TIME_SYNC_FTM) \ + CFG(CFG_TIME_SYNC_FTM_MODE) \ + CFG(CFG_TIME_SYNC_FTM_ROLE) + +#else +#define CFG_TIME_SYNC_FTM_ALL +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ +#endif /* __FTM_TIME_SYNC_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/ftm_time_sync_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/ftm_time_sync_ucfg_api.h new file mode 100644 index 0000000000..ea7b65e120 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/ftm_time_sync_ucfg_api.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare public API related to the ftm time_sync called by north bound + * HDD/OSIF/LIM + */ + +#ifndef _FTM_TIME_SYNC_UCFG_API_H_ +#define _FTM_TIME_SYNC_UCFG_API_H_ + +#include +#include +#include "ftm_time_sync_objmgr.h" +#include "wlan_ftm_time_sync_public_struct.h" + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM + +/** + * ucfg_ftm_time_sync_init() - FTM time sync component initialization. + * + * This function initializes the ftm time sync component and registers + * the handlers which are invoked on vdev creation. + * + * Return: For successful registration - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +QDF_STATUS ucfg_ftm_time_sync_init(void); + +/** + * ucfg_ftm_time_sync_deinit() - FTM time sync component deinit. + * + * This function deinits ftm time sync component. + * + * Return: None + */ +void ucfg_ftm_time_sync_deinit(void); + +/** + * ucfg_is_ftm_time_sync_enable() - FTM time sync feature enable/disable + * @psoc: psoc context + * + * This function advertises whether the ftm time sync feature is enabled or not + * + * Return: true if enable else false + */ +bool ucfg_is_ftm_time_sync_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_ftm_time_sync_set_enable() - FTM time sync feature set enable/disable + * @psoc: psoc context + * @value: value to be set + * + * This function enables/disables the feature. + * + * Return: None + */ +void ucfg_ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * ucfg_ftm_time_sync_update_sta_connect_state() - Handler for STA state change + * @vdev: STA vdev + * @state: connected/disconnected state + * @bssid: bssid of connected AP + * + * This function triggers the FTM time sync feature in case of connection and + * stops the ftm sync feature in case of disconnection. + * + * Return: None + */ +void +ucfg_ftm_time_sync_update_sta_connect_state(struct wlan_objmgr_vdev *vdev, + enum ftm_time_sync_sta_state state, + struct qdf_mac_addr bssid); + +/** + * ucfg_ftm_time_sync_update_bss_state() - Handler to notify bss start/stop + * @vdev: SAP vdev + * @ap_state: BSS start/stop state + * + * This function triggers the FTM time sync feature in case of bss start and + * stops the ftm sync feature in case of bss stop. + * + * Return: None. + */ +void ucfg_ftm_time_sync_update_bss_state(struct wlan_objmgr_vdev *vdev, + enum ftm_time_sync_bss_state ap_state); + +/** + * ucfg_ftm_time_sync_show() - Show the ftm time sync offset values derived + * @vdev: vdev context + * @buf: buffer in which the values to be written + * + * This function prints the offset values derived after ftm time sync + * between the qtime of STA(target) and connected SAP(initiator). + * + * Return: number of bytes written in buffer + */ +ssize_t ucfg_ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf); +#else + +static inline +QDF_STATUS ucfg_ftm_time_sync_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_ftm_time_sync_deinit(void) +{ +} + +static inline +bool ucfg_is_ftm_time_sync_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +void ucfg_ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool value) +{ +} + +static inline void +ucfg_ftm_time_sync_update_sta_connect_state(struct wlan_objmgr_vdev *vdev, + enum ftm_time_sync_sta_state state) +{ +} + +static inline void +ucfg_ftm_time_sync_update_bss_state(struct wlan_objmgr_vdev *vdev, + enum ftm_time_sync_bss_state ap_state) +{ +} + +static inline +ssize_t ucfg_ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf) +{ + return 0; +} +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ +#endif /* _FTM_TIME_SYNC_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_public_struct.h new file mode 100644 index 0000000000..8b3b7bf15b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_public_struct.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare various struct, macros which are used for obj mgmt in ftm time + * sync. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_TIME_SYNC_FTM_PUBLIC_STRUCT_H_ +#define _WLAN_TIME_SYNC_FTM_PUBLIC_STRUCT_H_ + +struct wlan_objmgr_psoc; + +/** + * enum ftm_time_sync_mode - ftm time sync modes + * @FTM_TIMESYNC_AGGREGATED_MODE: Ftm time sync aggregated mode + * Only one aggregated offset is provided + * @FTM_TIMESYNC_BURST_MODE: Ftm time sync burst mode, offset for each FTM + * frame is provided + */ +enum ftm_time_sync_mode { + FTM_TIMESYNC_AGGREGATED_MODE, + FTM_TIMESYNC_BURST_MODE, +}; + +/** + * enum ftm_time_sync_role - ftm time sync role + * @FTM_TIMESYNC_TARGET_ROLE: Target/STA role + * @FTM_TIMESYNC_INITIATOR_ROLE: Initiator/SAP role + */ +enum ftm_time_sync_role { + FTM_TIMESYNC_TARGET_ROLE, + FTM_TIMESYNC_INITIATOR_ROLE, +}; + +/** + * enum ftm_time_sync_sta_state - ftm time sync sta states + * @FTM_TIME_SYNC_STA_CONNECTED: STA connected to AP + * @FTM_TIME_SYNC_STA_DISCONNECTED: STA disconnected + */ +enum ftm_time_sync_sta_state { + FTM_TIME_SYNC_STA_CONNECTED, + FTM_TIME_SYNC_STA_DISCONNECTED, +}; + +/** + * enum ftm_time_sync_bss_state - ftm time sync bss states + * @FTM_TIME_SYNC_BSS_STARTED: BSS started + * @FTM_TIME_SYNC_BSS_STOPPED: BSS stopped + */ +enum ftm_time_sync_bss_state { + FTM_TIME_SYNC_BSS_STARTED, + FTM_TIME_SYNC_BSS_STOPPED, +}; +/** + * struct wlan_ftm_time_sync_tx_ops - structure of tx operation function + * pointers for ftm time_sync component + * @ftm_time_sync_send_qtime: send qtime wmi cmd to FW + * @ftm_time_sync_send_trigger: send ftm time sync trigger cmd + * + */ +struct wlan_ftm_time_sync_tx_ops { + QDF_STATUS (*ftm_time_sync_send_qtime)(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + uint64_t lpass_ts); + QDF_STATUS (*ftm_time_sync_send_trigger)(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool mode); +}; + +/** + * struct wlan_ftm_time_sync_rx_ops - structure of rx operation function + * pointers for ftm time_sync component + * @ftm_time_sync_register_start_stop: register ftm time_sync start stop event + * @ftm_time_sync_regiser_initiator_target_offset: register initiator target + * qtime offset event + */ +struct wlan_ftm_time_sync_rx_ops { + QDF_STATUS (*ftm_time_sync_register_start_stop) + (struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*ftm_time_sync_regiser_initiator_target_offset) + (struct wlan_objmgr_psoc *psoc); +}; +#endif /*_WLAN_TIME_SYNC_FTM_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_tgt_api.h new file mode 100644 index 0000000000..17f4c57074 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/inc/wlan_ftm_time_sync_tgt_api.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declares public API for ftm time sync to interact with target/WMI + */ + +#ifndef _WLAN_FTM_TIME_SYNC_TGT_API_H_ +#define _WLAN_FTM_TIME_SYNC_TGT_API_H_ + +#include + +struct wlan_objmgr_psoc; +struct ftm_time_sync_start_stop_params; +struct ftm_time_sync_offset; + +/** + * tgt_ftm_ts_start_stop_evt() - receive start/stop ftm event + * from target if + * @psoc: objmgr psoc object + * @param: start/stop parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_ftm_ts_start_stop_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_start_stop_params *param); + +/** + * tgt_ftm_ts_offset_evt() - receive offset ftm event from target if + * @psoc: objmgr psoc object + * @param: offset parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_ftm_ts_offset_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_offset *param); + +#endif /*_WLAN_FTM_TIME_SYNC_TGT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/src/ftm_time_sync_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/src/ftm_time_sync_ucfg_api.c new file mode 100644 index 0000000000..e0fe2c8b64 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/src/ftm_time_sync_ucfg_api.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Public API implementation of ftm time_sync called by north bound iface. + */ + +#include "ftm_time_sync_ucfg_api.h" +#include "ftm_time_sync_main.h" +#include + +QDF_STATUS ucfg_ftm_time_sync_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_psoc_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to register psoc create handler"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_psoc_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to register psoc delete handler"); + goto fail_destroy_psoc; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_vdev_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to register vdev create handler"); + goto fail_create_vdev; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_vdev_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ftm_time_sync_err("Failed to register vdev destroy handler"); + goto fail_destroy_vdev; + } + return status; + +fail_destroy_vdev: + wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_vdev_create_notification, NULL); + +fail_create_vdev: + wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_psoc_destroy_notification, NULL); + +fail_destroy_psoc: + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_psoc_create_notification, NULL); + + return status; +} + +void ucfg_ftm_time_sync_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_vdev_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + ftm_time_sync_err("Failed to unregister vdev delete handler"); + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_vdev_create_notification, NULL); + if (!QDF_IS_STATUS_ERROR(status)) + ftm_time_sync_err("Failed to unregister vdev create handler"); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_psoc_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + ftm_time_sync_err("Failed to unregister psoc destroy handler"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_FTM_TIME_SYNC, + ftm_time_sync_psoc_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + ftm_time_sync_err("Failed to unregister psoc create handler"); +} + +bool ucfg_is_ftm_time_sync_enable(struct wlan_objmgr_psoc *psoc) +{ + return ftm_time_sync_is_enable(psoc); +} + +void ucfg_ftm_time_sync_set_enable(struct wlan_objmgr_psoc *psoc, bool enable) +{ + return ftm_time_sync_set_enable(psoc, enable); +} + +void ucfg_ftm_time_sync_update_sta_connect_state( + struct wlan_objmgr_vdev *vdev, + enum ftm_time_sync_sta_state sta_state, + struct qdf_mac_addr bssid) +{ + struct wlan_objmgr_psoc *psoc; + enum ftm_time_sync_role role; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return; + } + + role = ftm_time_sync_get_role(psoc); + if (role == FTM_TIMESYNC_TARGET_ROLE) { + if (sta_state == FTM_TIME_SYNC_STA_CONNECTED) + ftm_time_sync_send_trigger(vdev); + else + ftm_time_sync_stop(vdev); + + ftm_time_sync_update_bssid(vdev, bssid); + } +} + +void ucfg_ftm_time_sync_update_bss_state(struct wlan_objmgr_vdev *vdev, + enum ftm_time_sync_bss_state ap_state) +{ + struct wlan_objmgr_psoc *psoc; + enum ftm_time_sync_role role; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ftm_time_sync_err("Failed to get psoc"); + return; + } + + if (!ftm_time_sync_is_enable(psoc)) + return; + + role = ftm_time_sync_get_role(psoc); + if (role == FTM_TIMESYNC_INITIATOR_ROLE) { + if (ap_state == FTM_TIME_SYNC_BSS_STARTED) + ftm_time_sync_send_trigger(vdev); + else + ftm_time_sync_stop(vdev); + } +} + +ssize_t ucfg_ftm_time_sync_show(struct wlan_objmgr_vdev *vdev, char *buf) +{ + return ftm_time_sync_show(vdev, buf); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c new file mode 100644 index 0000000000..c48eb54bf6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c @@ -0,0 +1,104 @@ +/* + *Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for ftm time sync to interact with target/WMI + */ + +#include "wlan_ftm_time_sync_tgt_api.h" +#include "ftm_time_sync_main.h" +#include "wlan_ftm_time_sync_public_struct.h" +#include + +QDF_STATUS +tgt_ftm_ts_start_stop_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_start_stop_params *param) +{ + struct wlan_objmgr_vdev *vdev; + struct ftm_time_sync_vdev_priv *vdev_priv; + uint8_t vdev_id; + + vdev_id = param->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + FTM_TIME_SYNC_ID); + if (!vdev) { + ftm_time_sync_err("failed to get vdev"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + + qdf_mutex_acquire(&vdev_priv->ftm_time_sync_mutex); + + vdev_priv->time_sync_interval = param->timer_interval; + vdev_priv->num_reads = param->num_reads * 2; + + if (vdev_priv->num_reads && vdev_priv->time_sync_interval) { + vdev_priv->num_reads--; + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + qdf_delayed_work_start(&vdev_priv->ftm_time_sync_work, + param->timer_interval); + } else if (vdev_priv->time_sync_interval == 0) { + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + vdev_priv->ftm_ts_priv.qtime_ref = param->qtime; + vdev_priv->ftm_ts_priv.mac_ref = param->mac_time; + qdf_delayed_work_stop_sync(&vdev_priv->ftm_time_sync_work); + } else { + qdf_mutex_release(&vdev_priv->ftm_time_sync_mutex); + } + + ftm_time_sync_vdev_put_ref(vdev); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_ftm_ts_offset_evt(struct wlan_objmgr_psoc *psoc, + struct ftm_time_sync_offset *param) +{ + struct ftm_time_sync_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + int iter; + + vdev_id = param->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + FTM_TIME_SYNC_ID); + if (!vdev) { + ftm_time_sync_err("failed to get vdev"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = ftm_time_sync_vdev_get_priv(vdev); + + vdev_priv->num_qtime_pair = param->num_qtime < + FTM_TIME_SYNC_QTIME_PAIR_MAX ? param->num_qtime : + FTM_TIME_SYNC_QTIME_PAIR_MAX; + + for (iter = 0; iter < vdev_priv->num_qtime_pair; iter++) { + vdev_priv->ftm_ts_priv.time_pair[iter].qtime_initiator = + param->pairs[iter].qtime_initiator; + vdev_priv->ftm_ts_priv.time_pair[iter].qtime_target = + param->pairs[iter].qtime_target; + } + + ftm_time_sync_vdev_put_ref(vdev); + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/core/inc/wlan_fw_offload_main.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/core/inc/wlan_fw_offload_main.h new file mode 100644 index 0000000000..658d0e5479 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/core/inc/wlan_fw_offload_main.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2012 - 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare utility API related to the fw_offload component + * called by other components + */ + +#ifndef _WLAN_FW_OFFLOAD_MAIN_H_ +#define _WLAN_FW_OFFLOAD_MAIN_H_ + +#include +#include +#include +#include + +#include "cfg_ucfg_api.h" +#include "wlan_fwol_public_structs.h" + +#define fwol_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_FWOL, params) +#define fwol_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_FWOL, params) +#define fwol_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_FWOL, params) +#define fwol_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_FWOL, params) +#define fwol_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_FWOL, params) + +#define fwol_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_FWOL, params) +#define fwol_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_FWOL, params) +#define fwol_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_FWOL, params) +#define fwol_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_FWOL, params) +#define fwol_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_FWOL, params) + +/** + * enum wlan_fwol_southbound_event - fw offload south bound event type + * @WLAN_FWOL_EVT_INVALID: invalid/unknown value + * @WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE: get eLNA bypass response + * @WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE: get Thermal Stats response + * @WLAN_FWOL_EVT_LAST: internal use + * @WLAN_FWOL_EVT_MAX: value of last valid enumerator + */ +enum wlan_fwol_southbound_event { + WLAN_FWOL_EVT_INVALID = 0, + WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE, + WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE, + WLAN_FWOL_EVT_LAST, + WLAN_FWOL_EVT_MAX = WLAN_FWOL_EVT_LAST - 1 +}; + +/** + * struct wlan_fwol_coex_config - BTC config items + * @btc_mode: Config BTC mode + * @antenna_isolation: Antenna isolation + * @max_tx_power_for_btc: Max wlan tx power in co-ex scenario + * @wlan_low_rssi_threshold: Wlan low rssi threshold for BTC mode switching + * @bt_low_rssi_threshold: BT low rssi threshold for BTC mode switching + * @bt_interference_low_ll: Lower limit of low level BT interference + * @bt_interference_low_ul: Upper limit of low level BT interference + * @bt_interference_medium_ll: Lower limit of medium level BT interference + * @bt_interference_medium_ul: Upper limit of medium level BT interference + * @bt_interference_high_ll: Lower limit of high level BT interference + * @bt_interference_high_ul: Upper limit of high level BT interference + * @btc_mpta_helper_enable: Enable/Disable tri-radio MPTA helper + * @bt_sco_allow_wlan_2g_scan: Enable/Disable wlan 2g scan when + * BT SCO connection is on + * @btc_three_way_coex_config_legacy_enable: Enable/Disable tri-radio coex + * config legacy feature + * @ble_scan_coex_policy: BLE Scan policy, true - better BLE scan result, false + * better wlan throughput + * @coex_tput_shaping_enable: wifi traffic shaping enable, true - enable, + * false - disable + */ +struct wlan_fwol_coex_config { + uint8_t btc_mode; + uint8_t antenna_isolation; + uint8_t max_tx_power_for_btc; + int16_t wlan_low_rssi_threshold; + int16_t bt_low_rssi_threshold; + int16_t bt_interference_low_ll; + int16_t bt_interference_low_ul; + int16_t bt_interference_medium_ll; + int16_t bt_interference_medium_ul; + int16_t bt_interference_high_ll; + int16_t bt_interference_high_ul; +#ifdef FEATURE_MPTA_HELPER + bool btc_mpta_helper_enable; +#endif + bool bt_sco_allow_wlan_2g_scan; +#ifdef FEATURE_COEX_CONFIG + bool btc_three_way_coex_config_legacy_enable; +#endif + bool ble_scan_coex_policy; +#ifdef FEATURE_COEX_TPUT_SHAPING_CONFIG + bool coex_tput_shaping_enable; +#endif +}; + +#define FWOL_THERMAL_LEVEL_MAX 6 +#define FWOL_THERMAL_THROTTLE_LEVEL_MAX 6 +/** + * struct wlan_fwol_thermal_temp - Thermal temperature config items + * @thermal_temp_min_level: Array of temperature minimum levels + * @thermal_temp_max_level: Array of temperature maximum levels + * @thermal_mitigation_enable: Control for Thermal mitigation feature + * @throttle_period: Thermal throttle period value + * @throttle_dutycycle_level: Array of throttle duty cycle levels + * @thermal_sampling_time: sampling time for thermal mitigation in ms + * @mon_id: Monitor client id either the wpps or apps + * @priority_apps: Priority of the apps mitigation to consider by fw + * @priority_wpps: Priority of the wpps mitigation to consider by fw + * @thermal_action: thermal action as defined enum thermal_mgmt_action_code + * @therm_stats_offset: thermal temp offset as set in gThermalStatsTempOffset + */ +struct wlan_fwol_thermal_temp { + bool thermal_mitigation_enable; + uint32_t throttle_period; + uint16_t thermal_temp_min_level[FWOL_THERMAL_LEVEL_MAX]; + uint16_t thermal_temp_max_level[FWOL_THERMAL_LEVEL_MAX]; + uint32_t throttle_dutycycle_level[FWOL_THERMAL_THROTTLE_LEVEL_MAX]; + uint16_t thermal_sampling_time; + uint8_t mon_id; + uint8_t priority_apps; + uint8_t priority_wpps; + enum thermal_mgmt_action_code thermal_action; +#ifdef THERMAL_STATS_SUPPORT + uint8_t therm_stats_offset; +#endif +}; + +/** + * struct wlan_fwol_ie_allowlist - Probe request IE allowlist config items + * @ie_allowlist: IE allowlist flag + * @ie_bitmap_0: IE bitmap 0 + * @ie_bitmap_1: IE bitmap 1 + * @ie_bitmap_2: IE bitmap 2 + * @ie_bitmap_3: IE bitmap 3 + * @ie_bitmap_4: IE bitmap 4 + * @ie_bitmap_5: IE bitmap 5 + * @ie_bitmap_6: IE bitmap 6 + * @ie_bitmap_7: IE bitmap 7 + * @no_of_probe_req_ouis: Total number of ouis present in probe req + * @probe_req_voui: Stores oui values after parsing probe req ouis + */ +struct wlan_fwol_ie_allowlist { + bool ie_allowlist; + uint32_t ie_bitmap_0; + uint32_t ie_bitmap_1; + uint32_t ie_bitmap_2; + uint32_t ie_bitmap_3; + uint32_t ie_bitmap_4; + uint32_t ie_bitmap_5; + uint32_t ie_bitmap_6; + uint32_t ie_bitmap_7; + uint32_t no_of_probe_req_ouis; + uint32_t probe_req_voui[MAX_PROBE_REQ_OUIS]; +}; + +/** + * struct wlan_fwol_neighbor_report_cfg - Neighbor report config params + * @enable_bitmask: Neighbor report offload bitmask control + * @params_bitmask: Param validity bitmask + * @time_offset: Neighbor report frame time offset + * @low_rssi_offset: Low RSSI offset + * @bmiss_count_trigger: Beacon miss trigger count + * @per_threshold_offset: PER Threshold offset + * @cache_timeout: Cache timeout + * @max_req_cap: Max request per peer + */ +struct wlan_fwol_neighbor_report_cfg { + uint32_t enable_bitmask; + uint32_t params_bitmask; + uint32_t time_offset; + uint32_t low_rssi_offset; + uint32_t bmiss_count_trigger; + uint32_t per_threshold_offset; + uint32_t cache_timeout; + uint32_t max_req_cap; +}; + +#ifdef WLAN_FEATURE_TSF_ACCURACY +/** + * struct wlan_fwol_tsf_accuracy_configs - TSF Accuracy feature config params + * @enable: Flag to Enable/Disable TSF Accuracy Feature + * @sync_gpio: GPIO to indicate TSF sync is done. The GPIO pin is toggled at + * every TSF sync done. + * @periodic_pulse_gpio: GPIO to indicate TSF time completes a cycle of given + * interval. The GPIO pin gets pulse of 1msec for every + * TSF cycle complete. + * @pulse_interval_ms: Periodicy of TSF pulse in milli seconds. + */ +struct wlan_fwol_tsf_accuracy_configs { + bool enable; + uint32_t sync_gpio; + uint32_t periodic_pulse_gpio; + uint32_t pulse_interval_ms; +}; +#endif + +/** + * struct wlan_fwol_cfg - fwol config items + * @coex_config: coex config items + * @thermal_temp_cfg: Thermal temperature related config items + * @ie_allowlist_cfg: IE Allowlist related config items + * @neighbor_report_cfg: 11K neighbor report config + * @ani_enabled: ANI enable/disable + * @pcie_config: to control pcie gen and lane params + * @enable_rts_sifsbursting: Enable RTS SIFS Bursting + * @enable_sifs_burst: Enable SIFS burst + * @max_mpdus_inampdu: Max number of MPDUS + * @enable_phy_reg_retention: Enable PHY reg retention + * @upper_brssi_thresh: Upper BRSSI threshold + * @lower_brssi_thresh: Lower BRSSI threshold + * @enable_dtim_1chrx: Enable/disable DTIM 1 CHRX + * @alternative_chainmask_enabled: Alternate chainmask + * @smart_chainmask_enabled: Enable/disable chainmask + * @get_rts_profile: Set the RTS profile + * @enable_fw_log_level: Set the FW log level + * @enable_fw_log_type: Set the FW log type + * @enable_fw_module_log_level: enable fw module log level + * @enable_fw_module_log_level_num: enable fw module log level num + * @enable_fw_mod_wow_log_level: enable fw wow module log level + * @enable_fw_mod_wow_log_level_num: enable fw wow module log level num + * @sap_xlna_bypass: bypass SAP xLNA + * @is_rate_limit_enabled: Enable/disable RA rate limited + * @tsf_gpio_pin: TSF GPIO Pin config + * @tsf_irq_host_gpio_pin: TSF GPIO Pin config + * @tsf_sync_host_gpio_pin: TSF Sync GPIO Pin config + * @tsf_ptp_options: TSF Plus feature options config + * @tsf_sync_enable: TSF sync feature enable/disable + * @tsf_accuracy_configs: TSF Accuracy feature config parameters + * @sae_enable: SAE feature enable config + * @gcmp_enable: GCMP feature enable config + * @enable_tx_sch_delay: Enable TX SCH delay value config + * @enable_secondary_rate: Enable secondary retry rate config + * @enable_dhcp_server_offload: DHCP Offload is enabled or not + * @dhcp_max_num_clients: Max number of DHCP client supported + * @dwelltime_params: adaptive dwell time parameters + * @enable_ilp: ILP HW block configuration + * @sap_sho: SAP SHO HW offload configuration + * @disable_hw_assist: Flag to configure HW assist feature in FW + * @enable_ofdm_scrambler_seed: Decide to enable/disable OFDM scrambler seed + */ +struct wlan_fwol_cfg { + /* Add CFG and INI items here */ + struct wlan_fwol_coex_config coex_config; + struct wlan_fwol_thermal_temp thermal_temp_cfg; + struct wlan_fwol_ie_allowlist ie_allowlist_cfg; + struct wlan_fwol_neighbor_report_cfg neighbor_report_cfg; + bool ani_enabled; + uint8_t pcie_config; + bool enable_rts_sifsbursting; + uint8_t enable_sifs_burst; + uint8_t max_mpdus_inampdu; + uint8_t enable_phy_reg_retention; + uint16_t upper_brssi_thresh; + uint16_t lower_brssi_thresh; + bool enable_dtim_1chrx; + bool alternative_chainmask_enabled; + bool smart_chainmask_enabled; + uint16_t get_rts_profile; + uint16_t enable_fw_log_level; + uint16_t enable_fw_log_type; + uint8_t enable_fw_module_log_level[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + uint8_t enable_fw_module_log_level_num; + uint8_t enable_fw_mod_wow_log_level[FW_MODULE_LOG_LEVEL_STRING_LENGTH]; + uint8_t enable_fw_mod_wow_log_level_num; + bool sap_xlna_bypass; +#ifdef FEATURE_WLAN_RA_FILTERING + bool is_rate_limit_enabled; +#endif +#ifdef WLAN_FEATURE_TSF + uint32_t tsf_gpio_pin; +#ifdef WLAN_FEATURE_TSF_PLUS + uint32_t tsf_ptp_options; + bool tsf_sync_enable; +#ifdef WLAN_FEATURE_TSF_ACCURACY + struct wlan_fwol_tsf_accuracy_configs tsf_accuracy_configs; +#endif +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ + uint32_t tsf_irq_host_gpio_pin; +#endif +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC + uint32_t tsf_sync_host_gpio_pin; +#endif +#endif +#endif +#ifdef WLAN_FEATURE_SAE + bool sae_enable; +#endif + bool gcmp_enable; + uint8_t enable_tx_sch_delay; + uint32_t enable_secondary_rate; +#ifdef DHCP_SERVER_OFFLOAD + bool enable_dhcp_server_offload; + uint32_t dhcp_max_num_clients; +#endif + struct adaptive_dwelltime_params dwelltime_params; + uint32_t enable_ilp; + uint32_t sap_sho; + bool disable_hw_assist; +#ifdef WLAN_FEATURE_OFDM_SCRAMBLER_SEED + bool enable_ofdm_scrambler_seed; +#endif +}; + +/** + * struct wlan_fwol_thermal_throttle_info - FW offload thermal throttle info + * @level: thermal throttle level + * @pdev_id: pdev id + */ +struct wlan_fwol_thermal_throttle_info { + enum thermal_throttle_level level; + uint32_t pdev_id; +}; + +/** + * struct wlan_fwol_capability_info - FW offload capability component + * @fw_thermal_stats_cap: Thermal Stats Fw capability + */ +struct wlan_fwol_capability_info { +#ifdef THERMAL_STATS_SUPPORT + bool fw_thermal_stats_cap; +#endif +}; + +/** + * struct wlan_fwol_psoc_obj - FW offload psoc priv object + * @cfg: cfg items + * @cbs: callback functions + * @tx_ops: tx operations for target interface + * @rx_ops: rx operations for target interface + * @thermal_throttle: cached target thermal stats information + * @thermal_cbs: thermal notification callbacks to hdd layer + * @capability_info: fwol capability info + */ +struct wlan_fwol_psoc_obj { + struct wlan_fwol_cfg cfg; + struct wlan_fwol_callbacks cbs; + struct wlan_fwol_tx_ops tx_ops; + struct wlan_fwol_rx_ops rx_ops; +#ifdef FW_THERMAL_THROTTLE_SUPPORT + struct wlan_fwol_thermal_throttle_info thermal_throttle; + struct fwol_thermal_callbacks thermal_cbs; +#endif + struct wlan_fwol_capability_info capability_info; +}; + +/** + * struct wlan_fwol_rx_event - event from south bound + * @psoc: psoc handle + * @event_id: event ID + * @get_elna_bypass_response: get eLNA bypass response + * @get_thermal_stats_response: get thermal stats response + */ +struct wlan_fwol_rx_event { + struct wlan_objmgr_psoc *psoc; + enum wlan_fwol_southbound_event event_id; + union { +#ifdef WLAN_FEATURE_ELNA + struct get_elna_bypass_response get_elna_bypass_response; +#endif +#ifdef THERMAL_STATS_SUPPORT + struct thermal_throttle_info get_thermal_stats_response; +#endif + }; +}; + +/** + * fwol_get_psoc_obj() - private API to get fwol object from psoc + * @psoc: psoc object + * + * Return: fwol object + */ +struct wlan_fwol_psoc_obj *fwol_get_psoc_obj(struct wlan_objmgr_psoc *psoc); + +/** + * fwol_cfg_on_psoc_enable() - Populate FWOL structure from CFG and INI + * @psoc: pointer to the psoc object + * + * Populate the FWOL CFG structure from CFG and INI values using CFG APIs + * + * Return: QDF_STATUS + */ +QDF_STATUS fwol_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * fwol_cfg_on_psoc_disable() - Clear the CFG structure on psoc disable + * @psoc: pointer to the psoc object + * + * Clear the FWOL CFG structure on psoc disable + * + * Return: QDF_STATUS + */ +QDF_STATUS fwol_cfg_on_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * fwol_process_event() - API to process event from south bound + * @msg: south bound message + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS fwol_process_event(struct scheduler_msg *msg); + +/** + * fwol_release_rx_event() - Release fw offload RX event + * @event: fw offload RX event + * + * Return: none + */ +void fwol_release_rx_event(struct wlan_fwol_rx_event *event); + +/** + * fwol_init_neighbor_report_cfg() - Populate default neighbor report CFG values + * @psoc: pointer to the psoc object + * @fwol_neighbor_report_cfg: Pointer to Neighbor report config data structure + * + * Return: QDF_STATUS + */ +QDF_STATUS fwol_init_neighbor_report_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_neighbor_report_cfg + *fwol_neighbor_report_cfg); + +/** + * fwol_init_adapt_dwelltime_in_cfg() - initialize adaptive dwell time params + * @psoc: Pointer to struct wlan_objmgr_psoc context + * @dwelltime_params: Pointer to dwell time params + * + * This function parses initialize the adaptive dwell params from ini. + * + * Return: QDF_STATUS + */ +QDF_STATUS +fwol_init_adapt_dwelltime_in_cfg( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params); + +/** + * fwol_set_adaptive_dwelltime_config() - API to set adaptive dwell params + * config + * @dwelltime_params: adaptive_dwelltime_params structure + * + * Return: QDF Status + */ +QDF_STATUS +fwol_set_adaptive_dwelltime_config( + struct adaptive_dwelltime_params *dwelltime_params); + +/** + * fwol_set_ilp_config() - API to set ILP HW block config + * @pdev: pointer to the pdev object + * @enable_ilp: ILP HW block configuration with various options + * + * Return: QDF_STATUS + */ +QDF_STATUS fwol_set_ilp_config(struct wlan_objmgr_pdev *pdev, + uint32_t enable_ilp); + +/** + * fwol_set_sap_sho() - API to set SAP SHO config + * @psoc: pointer to the psoc object + * @vdev_id: vdev id + * @sap_sho: enable/disable config for SAP SHO + * SHO- SoftAP hardware offload – When enabled the beacon/probe resp + * will be offloaded to HW. + * + * Return: QDF_STATUS + */ +QDF_STATUS fwol_set_sap_sho(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t sap_sho); + +/** + * fwol_configure_hw_assist() - API to configure HW assist feature in FW + * @pdev: pointer to the pdev object + * @disable_hw_assist: Flag to enable/disable HW assist feature + * + * Return: QDF_STATUS + */ +QDF_STATUS fwol_configure_hw_assist(struct wlan_objmgr_pdev *pdev, + bool disable_hw_assist); + +/** + * fwol_set_sap_wds_config() - API to configure WDS mode on SAP vdev + * @psoc: pointer to the psoc object + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +#ifdef FEATURE_WDS +QDF_STATUS +fwol_set_sap_wds_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); +#else +static inline QDF_STATUS +fwol_set_sap_wds_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/core/src/wlan_fw_offload_main.c b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/core/src/wlan_fw_offload_main.c new file mode 100644 index 0000000000..097b70808e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/core/src/wlan_fw_offload_main.c @@ -0,0 +1,933 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define internal APIs related to the fwol component + */ + +#include "wlan_fw_offload_main.h" +#include "cds_api.h" +#include "wma.h" +#include "wlan_fwol_tgt_api.h" + +struct wlan_fwol_psoc_obj *fwol_get_psoc_obj(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_FWOL); +} + +/** + * fwol_mpta_helper_config_get() - Populate btc_mpta_helper_enable from cfg + * @psoc: The global psoc handler + * @coex_config: The cfg structure + * + * Return: none + */ +#ifdef FEATURE_MPTA_HELPER +static void +fwol_mpta_helper_config_get(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ + coex_config->btc_mpta_helper_enable = + cfg_get(psoc, CFG_COEX_MPTA_HELPER); +} +#else +static void +fwol_mpta_helper_config_get(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ +} +#endif + +/** + * fwol_three_way_coex_config_legacy_config_get() - Populate + * btc_three_way_coex_config_legacy_enable from cfg + * @psoc: The global psoc handler + * @coex_config: The cfg structure + * + * Return: none + */ +#ifdef FEATURE_COEX_CONFIG +static void +fwol_three_way_coex_config_legacy_config_get( + struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ + coex_config->btc_three_way_coex_config_legacy_enable = + cfg_get(psoc, CFG_THREE_WAY_COEX_CONFIG_LEGACY); +} +#else +static void +fwol_three_way_coex_config_legacy_config_get( + struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ +} +#endif + +static void +fwol_init_coex_config_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ + coex_config->btc_mode = cfg_get(psoc, CFG_BTC_MODE); + coex_config->antenna_isolation = cfg_get(psoc, CFG_ANTENNA_ISOLATION); + coex_config->max_tx_power_for_btc = + cfg_get(psoc, CFG_MAX_TX_POWER_FOR_BTC); + coex_config->wlan_low_rssi_threshold = + cfg_get(psoc, CFG_WLAN_LOW_RSSI_THRESHOLD); + coex_config->bt_low_rssi_threshold = + cfg_get(psoc, CFG_BT_LOW_RSSI_THRESHOLD); + coex_config->bt_interference_low_ll = + cfg_get(psoc, CFG_BT_INTERFERENCE_LOW_LL); + coex_config->bt_interference_low_ul = + cfg_get(psoc, CFG_BT_INTERFERENCE_LOW_UL); + coex_config->bt_interference_medium_ll = + cfg_get(psoc, CFG_BT_INTERFERENCE_MEDIUM_LL); + coex_config->bt_interference_medium_ul = + cfg_get(psoc, CFG_BT_INTERFERENCE_MEDIUM_UL); + coex_config->bt_interference_high_ll = + cfg_get(psoc, CFG_BT_INTERFERENCE_HIGH_LL); + coex_config->bt_interference_high_ul = + cfg_get(psoc, CFG_BT_INTERFERENCE_HIGH_UL); + fwol_mpta_helper_config_get(psoc, coex_config); + coex_config->bt_sco_allow_wlan_2g_scan = + cfg_get(psoc, CFG_BT_SCO_ALLOW_WLAN_2G_SCAN); + fwol_three_way_coex_config_legacy_config_get(psoc, coex_config); + coex_config->ble_scan_coex_policy = cfg_get(psoc, + CFG_BLE_SCAN_COEX_POLICY); +#ifdef FEATURE_COEX_TPUT_SHAPING_CONFIG + coex_config->coex_tput_shaping_enable = + cfg_get(psoc, CFG_TPUT_SHAPING_ENABLE); +#endif +} + +#ifdef THERMAL_STATS_SUPPORT +static void +fwol_init_thermal_stats_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_temp) +{ + thermal_temp->therm_stats_offset = + cfg_get(psoc, CFG_THERMAL_STATS_TEMP_OFFSET); +} +#else +static void +fwol_init_thermal_stats_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_temp) +{ +} +#endif + +static void +fwol_init_thermal_temp_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_temp) +{ + thermal_temp->thermal_temp_min_level[0] = + cfg_get(psoc, CFG_THERMAL_TEMP_MIN_LEVEL0); + thermal_temp->thermal_temp_max_level[0] = + cfg_get(psoc, CFG_THERMAL_TEMP_MAX_LEVEL0); + thermal_temp->thermal_temp_min_level[1] = + cfg_get(psoc, CFG_THERMAL_TEMP_MIN_LEVEL1); + thermal_temp->thermal_temp_max_level[1] = + cfg_get(psoc, CFG_THERMAL_TEMP_MAX_LEVEL1); + thermal_temp->thermal_temp_min_level[2] = + cfg_get(psoc, CFG_THERMAL_TEMP_MIN_LEVEL2); + thermal_temp->thermal_temp_max_level[2] = + cfg_get(psoc, CFG_THERMAL_TEMP_MAX_LEVEL2); + thermal_temp->thermal_temp_min_level[3] = + cfg_get(psoc, CFG_THERMAL_TEMP_MIN_LEVEL3); + thermal_temp->thermal_temp_max_level[3] = + cfg_get(psoc, CFG_THERMAL_TEMP_MAX_LEVEL3); + thermal_temp->thermal_temp_min_level[4] = + cfg_get(psoc, CFG_THERMAL_TEMP_MIN_LEVEL4); + thermal_temp->thermal_temp_max_level[4] = + cfg_get(psoc, CFG_THERMAL_TEMP_MAX_LEVEL4); + thermal_temp->thermal_temp_min_level[5] = + cfg_get(psoc, CFG_THERMAL_TEMP_MIN_LEVEL5); + thermal_temp->thermal_temp_max_level[5] = + cfg_get(psoc, CFG_THERMAL_TEMP_MAX_LEVEL5); + + thermal_temp->thermal_mitigation_enable = + cfg_get(psoc, CFG_THERMAL_MITIGATION_ENABLE); + thermal_temp->throttle_period = cfg_get(psoc, CFG_THROTTLE_PERIOD); + thermal_temp->thermal_sampling_time = + cfg_get(psoc, CFG_THERMAL_SAMPLING_TIME); + thermal_temp->throttle_dutycycle_level[0] = + cfg_get(psoc, CFG_THROTTLE_DUTY_CYCLE_LEVEL0); + thermal_temp->throttle_dutycycle_level[1] = + cfg_get(psoc, CFG_THROTTLE_DUTY_CYCLE_LEVEL1); + thermal_temp->throttle_dutycycle_level[2] = + cfg_get(psoc, CFG_THROTTLE_DUTY_CYCLE_LEVEL2); + thermal_temp->throttle_dutycycle_level[3] = + cfg_get(psoc, CFG_THROTTLE_DUTY_CYCLE_LEVEL3); + thermal_temp->throttle_dutycycle_level[4] = + cfg_get(psoc, CFG_THROTTLE_DUTY_CYCLE_LEVEL4); + thermal_temp->throttle_dutycycle_level[5] = + cfg_get(psoc, CFG_THROTTLE_DUTY_CYCLE_LEVEL5); + thermal_temp->priority_apps = + cfg_get(psoc, CFG_THERMAL_APPS_PRIORITY); + thermal_temp->priority_wpps = + cfg_get(psoc, CFG_THERMAL_WPPS_PRIOITY); + thermal_temp->thermal_action = + cfg_get(psoc, CFG_THERMAL_MGMT_ACTION); + fwol_init_thermal_stats_in_cfg(psoc, thermal_temp); +} + +/** + * fwol_set_neighbor_report_offload_params() - set neighbor report parameters + * for rso user config + * @psoc: The global psoc handler + * @fwol_neighbor_report_cfg: neighbor report config params + * + * Return: none + */ +static void +fwol_set_neighbor_report_offload_params( + struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_neighbor_report_cfg *fwol_neighbor_report_cfg) +{ + struct cm_roam_neighbor_report_offload_params *neighbor_report_offload; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + fwol_err("Failed to get MLME Obj"); + return; + } + + neighbor_report_offload = &mlme_obj->cfg.lfr.rso_user_config + .neighbor_report_offload; + + neighbor_report_offload->offload_11k_enable_bitmask = + fwol_neighbor_report_cfg->enable_bitmask; + neighbor_report_offload->params_bitmask = + fwol_neighbor_report_cfg->params_bitmask; + neighbor_report_offload->time_offset = + fwol_neighbor_report_cfg->time_offset; + neighbor_report_offload->low_rssi_offset = + fwol_neighbor_report_cfg->low_rssi_offset; + neighbor_report_offload->bmiss_count_trigger = + fwol_neighbor_report_cfg->bmiss_count_trigger; + neighbor_report_offload->per_threshold_offset = + fwol_neighbor_report_cfg->per_threshold_offset; + neighbor_report_offload->neighbor_report_cache_timeout = + fwol_neighbor_report_cfg->cache_timeout; + neighbor_report_offload->max_neighbor_report_req_cap = + fwol_neighbor_report_cfg->max_req_cap; +} + +QDF_STATUS fwol_init_neighbor_report_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_neighbor_report_cfg + *fwol_neighbor_report_cfg) +{ + if (!fwol_neighbor_report_cfg) { + fwol_err("Neighbor report config pointer null"); + return QDF_STATUS_E_FAILURE; + } + + fwol_neighbor_report_cfg->enable_bitmask = + cfg_get(psoc, CFG_OFFLOAD_11K_ENABLE_BITMASK); + fwol_neighbor_report_cfg->params_bitmask = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK); + fwol_neighbor_report_cfg->time_offset = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET); + fwol_neighbor_report_cfg->low_rssi_offset = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET); + fwol_neighbor_report_cfg->bmiss_count_trigger = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER); + fwol_neighbor_report_cfg->per_threshold_offset = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET); + fwol_neighbor_report_cfg->cache_timeout = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT); + fwol_neighbor_report_cfg->max_req_cap = + cfg_get(psoc, CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP); + + fwol_set_neighbor_report_offload_params(psoc, fwol_neighbor_report_cfg); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +fwol_init_adapt_dwelltime_in_cfg( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + if (!dwelltime_params) { + fwol_err("dwelltime params config pointer null"); + return QDF_STATUS_E_FAILURE; + } + dwelltime_params->is_enabled = + cfg_get(psoc, CFG_ADAPTIVE_DWELL_MODE_ENABLED); + dwelltime_params->dwelltime_mode = + cfg_get(psoc, CFG_GLOBAL_ADAPTIVE_DWELL_MODE); + dwelltime_params->lpf_weight = + cfg_get(psoc, CFG_ADAPT_DWELL_LPF_WEIGHT); + dwelltime_params->passive_mon_intval = + cfg_get(psoc, CFG_ADAPT_DWELL_PASMON_INTVAL); + dwelltime_params->wifi_act_threshold = + cfg_get(psoc, CFG_ADAPT_DWELL_WIFI_THRESH); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +fwol_set_adaptive_dwelltime_config( + struct adaptive_dwelltime_params *dwelltime_params) +{ + tp_wma_handle wma_handle; + QDF_STATUS status; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + status = wma_send_adapt_dwelltime_params(wma_handle, + dwelltime_params); + return status; +} +/** + * fwol_parse_probe_req_ouis() - form ouis from ini gProbeReqOUIs + * @psoc: Pointer to struct wlan_objmgr_psoc context + * @allowlist: Pointer to struct wlan_fwol_ie_allowlist + * + * This function parses the ini string gProbeReqOUIs which needs be to in the + * following format: + * "<8 characters of [0-9] or [A-F]>space<8 characters from [0-9] etc.," + * example: "AABBCCDD 1122EEFF" + * and the logic counts the number of OUIS and allocates the memory + * for every valid OUI and is stored in struct hdd_context + * + * Return: None + */ +static void fwol_parse_probe_req_ouis(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_allowlist *allowlist) +{ + uint8_t probe_req_ouis[MAX_PRB_REQ_VENDOR_OUI_INI_LEN] = {0}; + uint32_t *voui = allowlist->probe_req_voui; + char *str; + uint8_t *token; + uint32_t oui_indx = 0; + int ret; + uint32_t hex_value; + + qdf_str_lcopy(probe_req_ouis, cfg_get(psoc, CFG_PROBE_REQ_OUI), + MAX_PRB_REQ_VENDOR_OUI_INI_LEN); + str = probe_req_ouis; + allowlist->no_of_probe_req_ouis = 0; + + if (!qdf_str_len(str)) { + fwol_debug("NO OUIs to parse"); + return; + } + + token = strsep(&str, " "); + while (token) { + if (qdf_str_len(token) != 8) + goto next_token; + + ret = qdf_kstrtouint(token, 16, &hex_value); + if (ret) + goto next_token; + + voui[oui_indx++] = cpu_to_be32(hex_value); + if (oui_indx >= MAX_PROBE_REQ_OUIS) + break; +next_token: + token = strsep(&str, " "); + } + + if (!oui_indx) { + allowlist->ie_allowlist = false; + return; + } + + allowlist->no_of_probe_req_ouis = oui_indx; +} + +/** + * fwol_validate_ie_bitmaps() - Validate all IE allowlist bitmap param values + * @psoc: Pointer to struct wlan_objmgr_psoc + * @allowlist: Pointer to struct wlan_fwol_ie_allowlist + * + * Return: True if all bitmap values are valid, else false + */ +static bool fwol_validate_ie_bitmaps(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_allowlist *allowlist) +{ + if (!(allowlist->ie_bitmap_0 || allowlist->ie_bitmap_1 || + allowlist->ie_bitmap_2 || allowlist->ie_bitmap_3 || + allowlist->ie_bitmap_4 || allowlist->ie_bitmap_5 || + allowlist->ie_bitmap_6 || allowlist->ie_bitmap_7)) + return false; + + /* + * check whether vendor oui IE is set and OUIs are present, each OUI + * is entered in the form of string of 8 characters from ini, therefore, + * for atleast one OUI, minimum length is 8 and hence this string length + * is checked for minimum of 8 + */ + if ((allowlist->ie_bitmap_6 & VENDOR_SPECIFIC_IE_BITMAP) && + (qdf_str_len(cfg_get(psoc, CFG_PROBE_REQ_OUI)) < 8)) + return false; + + /* check whether vendor oui IE is not set but OUIs are present */ + if (!(allowlist->ie_bitmap_6 & VENDOR_SPECIFIC_IE_BITMAP) && + (qdf_str_len(cfg_get(psoc, CFG_PROBE_REQ_OUI)) > 0)) + return false; + + return true; +} + +static void +fwol_init_ie_whiltelist_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_allowlist *allowlist) +{ + allowlist->ie_allowlist = cfg_get(psoc, CFG_PROBE_REQ_IE_ALLOWLIST); + allowlist->ie_bitmap_0 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP0); + allowlist->ie_bitmap_1 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP1); + allowlist->ie_bitmap_2 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP2); + allowlist->ie_bitmap_3 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP3); + allowlist->ie_bitmap_4 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP4); + allowlist->ie_bitmap_5 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP5); + allowlist->ie_bitmap_6 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP6); + allowlist->ie_bitmap_7 = cfg_get(psoc, CFG_PROBE_REQ_IE_BIT_MAP7); + if (!fwol_validate_ie_bitmaps(psoc, allowlist)) + allowlist->ie_allowlist = false; + fwol_parse_probe_req_ouis(psoc, allowlist); +} + +/** + * ucfg_fwol_fetch_dhcp_server_settings() - Populate the DHCP server settings + * from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * Return: none + */ +#ifdef DHCP_SERVER_OFFLOAD +static void ucfg_fwol_fetch_dhcp_server_settings(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->enable_dhcp_server_offload = + cfg_get(psoc, CFG_DHCP_SERVER_OFFLOAD_SUPPORT); + fwol_cfg->dhcp_max_num_clients = + cfg_get(psoc, CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT); +} +#else +static void ucfg_fwol_fetch_dhcp_server_settings(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +/** + * ucfg_fwol_fetch_tsf_gpio_pin() - Populate the tsf_gpio_pin from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * Return: none + */ +#ifdef WLAN_FEATURE_TSF +static void ucfg_fwol_fetch_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->tsf_gpio_pin = cfg_get(psoc, CFG_SET_TSF_GPIO_PIN); +} +#else +static void ucfg_fwol_fetch_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +#if defined(WLAN_FEATURE_TSF) && defined(WLAN_FEATURE_TSF_PLUS) +#ifdef WLAN_FEATURE_TSF_ACCURACY +/** + * fwol_init_tsf_accuracy_configs() - Populate the TSF Accuracy configs from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * Return: none + */ +static void fwol_init_tsf_accuracy_configs(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + int32_t configs[CFG_TSF_ACCURACY_CONFIG_LEN] = { 0 }; + int status; + qdf_size_t len; + + status = qdf_int32_array_parse(cfg_get(psoc, CFG_TSF_ACCURACY_CONFIGS), + configs, + CFG_TSF_ACCURACY_CONFIG_LEN, + &len); + + if (status != QDF_STATUS_SUCCESS || len != CFG_TSF_ACCURACY_CONFIG_LEN) { + fwol_cfg->tsf_accuracy_configs.enable = 0; + fwol_err("Invalid parameters from INI"); + return; + } + + fwol_cfg->tsf_accuracy_configs.enable = configs[0]; + fwol_cfg->tsf_accuracy_configs.sync_gpio = configs[1]; + fwol_cfg->tsf_accuracy_configs.periodic_pulse_gpio = configs[2]; + fwol_cfg->tsf_accuracy_configs.pulse_interval_ms = configs[3]; +} +#else +static void fwol_init_tsf_accuracy_configs(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +/** + * ucfg_fwol_init_tsf_ptp_options() - Populate the tsf_ptp_options from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * Return: none + */ +static void ucfg_fwol_init_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->tsf_ptp_options = cfg_get(psoc, CFG_SET_TSF_PTP_OPT); + fwol_cfg->tsf_sync_enable = cfg_get(psoc, CFG_TSF_SYNC_ENABLE); + fwol_init_tsf_accuracy_configs(psoc, fwol_cfg); +} +#else +static void ucfg_fwol_init_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +/** + * ucfg_fwol_fetch_tsf_irq_host_gpio_pin() - Populate the tsf_irq_host_gpio_pin + * from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * This function is used to populate the cfg value of host platform + * gpio pin configured to receive tsf interrupt from fw. + * + * Return: none + */ +static void +ucfg_fwol_fetch_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->tsf_irq_host_gpio_pin = + cfg_get(psoc, CFG_SET_TSF_IRQ_HOST_GPIO_PIN); +} +#else +static void +ucfg_fwol_fetch_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +/** + * ucfg_fwol_fetch_tsf_sync_host_gpio_pin() - Populate the + * tsf_sync_host_gpio_pin from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * This function is used to populate the cfg value of host platform + * gpio pin configured to drive tsf sync interrupt pin on wlan chip. + * + * Return: none + */ +static void +ucfg_fwol_fetch_tsf_sync_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->tsf_sync_host_gpio_pin = + cfg_get(psoc, CFG_SET_TSF_SYNC_HOST_GPIO_PIN); +} +#else +static void +ucfg_fwol_fetch_tsf_sync_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif +/** + * ucfg_fwol_init_sae_cfg() - Populate the sae control config from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * Return: none + */ +#ifdef WLAN_FEATURE_SAE +static void ucfg_fwol_init_sae_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->sae_enable = cfg_get(psoc, CFG_IS_SAE_ENABLED); +} +#else +static void ucfg_fwol_init_sae_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +/** + * ucfg_fwol_fetch_ra_filter() - Populate the RA filter enabled or not from cfg + * @psoc: The global psoc handler + * @fwol_cfg: The cfg structure + * + * Return: none + */ +#ifdef FEATURE_WLAN_RA_FILTERING +static void ucfg_fwol_fetch_ra_filter(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ + fwol_cfg->is_rate_limit_enabled = cfg_get(psoc, CFG_RA_FILTER_ENABLE); +} +#else +static void ucfg_fwol_fetch_ra_filter(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_cfg *fwol_cfg) +{ +} +#endif + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +static void fwol_thermal_init(struct wlan_fwol_psoc_obj *fwol_obj) +{ + fwol_obj->thermal_throttle.level = THERMAL_FULLPERF; + fwol_obj->thermal_throttle.pdev_id = WLAN_INVALID_PDEV_ID; +} +#else +static void fwol_thermal_init(struct wlan_fwol_psoc_obj *fwol_obj) +{ +} +#endif + +#ifdef WLAN_FEATURE_OFDM_SCRAMBLER_SEED +static inline void fwol_ofdm_scrambler_init(struct wlan_fwol_cfg *fwol_cfg, + struct wlan_objmgr_psoc *psoc) +{ + fwol_cfg->enable_ofdm_scrambler_seed = + cfg_get(psoc, CFG_ENABLE_OFDM_SCRAMBLER_SEED); +} +#else +static inline void fwol_ofdm_scrambler_init(struct wlan_fwol_cfg *fwol_cfg, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +QDF_STATUS fwol_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_cfg *fwol_cfg; + qdf_size_t enable_fw_module_log_level_num; + qdf_size_t enable_fw_wow_mod_log_level_num; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_FAILURE; + } + + fwol_cfg = &fwol_obj->cfg; + + fwol_init_coex_config_in_cfg(psoc, &fwol_cfg->coex_config); + fwol_init_thermal_temp_in_cfg(psoc, &fwol_cfg->thermal_temp_cfg); + fwol_init_ie_whiltelist_in_cfg(psoc, &fwol_cfg->ie_allowlist_cfg); + fwol_init_neighbor_report_cfg(psoc, &fwol_cfg->neighbor_report_cfg); + fwol_cfg->ani_enabled = cfg_get(psoc, CFG_ENABLE_ANI); + fwol_cfg->pcie_config = cfg_get(psoc, CFG_PCIE_CONFIG); + fwol_cfg->enable_rts_sifsbursting = + cfg_get(psoc, CFG_SET_RTS_FOR_SIFS_BURSTING); + fwol_cfg->enable_sifs_burst = cfg_get(psoc, CFG_SET_SIFS_BURST); + fwol_cfg->max_mpdus_inampdu = cfg_get(psoc, CFG_MAX_MPDUS_IN_AMPDU); + fwol_cfg->enable_phy_reg_retention = cfg_get(psoc, CFG_ENABLE_PHY_REG); + fwol_cfg->upper_brssi_thresh = cfg_get(psoc, CFG_UPPER_BRSSI_THRESH); + fwol_cfg->lower_brssi_thresh = cfg_get(psoc, CFG_LOWER_BRSSI_THRESH); + fwol_cfg->enable_dtim_1chrx = cfg_get(psoc, CFG_DTIM_1CHRX_ENABLE); + fwol_cfg->alternative_chainmask_enabled = + cfg_get(psoc, CFG_ENABLE_COEX_ALT_CHAINMASK); + fwol_cfg->smart_chainmask_enabled = + cfg_get(psoc, CFG_ENABLE_SMART_CHAINMASK); + fwol_cfg->get_rts_profile = cfg_get(psoc, CFG_ENABLE_FW_RTS_PROFILE); + fwol_cfg->enable_fw_log_level = + cfg_get(psoc, CFG_ENABLE_FW_DEBUG_LOG_LEVEL); + fwol_cfg->enable_fw_log_type = cfg_get(psoc, CFG_ENABLE_FW_LOG_TYPE); + qdf_uint8_array_parse(cfg_get(psoc, CFG_ENABLE_FW_MODULE_LOG_LEVEL), + fwol_cfg->enable_fw_module_log_level, + FW_MODULE_LOG_LEVEL_STRING_LENGTH, + &enable_fw_module_log_level_num); + fwol_cfg->enable_fw_module_log_level_num = + (uint8_t)enable_fw_module_log_level_num; + qdf_uint8_array_parse(cfg_get(psoc, CFG_ENABLE_FW_WOW_MODULE_LOG_LEVEL), + fwol_cfg->enable_fw_mod_wow_log_level, + FW_MODULE_LOG_LEVEL_STRING_LENGTH, + &enable_fw_wow_mod_log_level_num); + fwol_cfg->enable_fw_mod_wow_log_level_num = + (uint8_t)enable_fw_wow_mod_log_level_num; + ucfg_fwol_init_tsf_ptp_options(psoc, fwol_cfg); + ucfg_fwol_init_sae_cfg(psoc, fwol_cfg); + fwol_cfg->gcmp_enable = cfg_get(psoc, CFG_ENABLE_GCMP); + fwol_cfg->enable_tx_sch_delay = cfg_get(psoc, CFG_TX_SCH_DELAY); + fwol_cfg->enable_secondary_rate = cfg_get(psoc, + CFG_ENABLE_SECONDARY_RATE); + fwol_init_adapt_dwelltime_in_cfg(psoc, &fwol_cfg->dwelltime_params); + ucfg_fwol_fetch_ra_filter(psoc, fwol_cfg); + ucfg_fwol_fetch_tsf_gpio_pin(psoc, fwol_cfg); + ucfg_fwol_fetch_tsf_irq_host_gpio_pin(psoc, fwol_cfg); + ucfg_fwol_fetch_tsf_sync_host_gpio_pin(psoc, fwol_cfg); + ucfg_fwol_fetch_dhcp_server_settings(psoc, fwol_cfg); + fwol_cfg->sap_xlna_bypass = cfg_get(psoc, CFG_SET_SAP_XLNA_BYPASS); + fwol_cfg->enable_ilp = cfg_get(psoc, CFG_SET_ENABLE_ILP); + fwol_cfg->sap_sho = cfg_get(psoc, CFG_SAP_SHO_CONFIG); + fwol_cfg->disable_hw_assist = cfg_get(psoc, CFG_DISABLE_HW_ASSIST); + fwol_thermal_init(fwol_obj); + fwol_ofdm_scrambler_init(fwol_cfg, psoc); + + return status; +} + +QDF_STATUS fwol_cfg_on_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + /* Clear the CFG structure */ + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ELNA +/** + * fwol_process_get_elna_bypass_resp() - Process get eLNA bypass response + * @event: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +fwol_process_get_elna_bypass_resp(struct wlan_fwol_rx_event *event) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_callbacks *cbs; + struct get_elna_bypass_response *resp; + + if (!event) { + fwol_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + psoc = event->psoc; + if (!psoc) { + fwol_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + cbs = &fwol_obj->cbs; + if (cbs->get_elna_bypass_callback) { + resp = &event->get_elna_bypass_response; + cbs->get_elna_bypass_callback(cbs->get_elna_bypass_context, + resp); + } else { + fwol_err("NULL pointer for callback"); + status = QDF_STATUS_E_IO; + } + + return status; +} +#else +static QDF_STATUS +fwol_process_get_elna_bypass_resp(struct wlan_fwol_rx_event *event) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ELNA */ + +#ifdef THERMAL_STATS_SUPPORT +/** + * fwol_process_get_thermal_stats_resp() - Process get thermal stats response + * @event: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +fwol_process_get_thermal_stats_resp(struct wlan_fwol_rx_event *event) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_callbacks *cbs; + struct thermal_throttle_info *resp; + + if (!event) { + fwol_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + psoc = event->psoc; + if (!psoc) { + fwol_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + cbs = &fwol_obj->cbs; + if (cbs && cbs->get_thermal_stats_callback) { + resp = &event->get_thermal_stats_response; + cbs->get_thermal_stats_callback(cbs->get_thermal_stats_context, + resp); + } else { + fwol_err("NULL pointer for callback"); + status = QDF_STATUS_E_IO; + } + + return status; +} +#else +static QDF_STATUS +fwol_process_get_thermal_stats_resp(struct wlan_fwol_rx_event *event) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* THERMAL_STATS_SUPPORT */ + +QDF_STATUS fwol_process_event(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct wlan_fwol_rx_event *event; + + fwol_debug("msg type %d", msg->type); + + if (!(msg->bodyptr)) { + fwol_err("Invalid message body"); + return QDF_STATUS_E_INVAL; + } + + event = msg->bodyptr; + msg->bodyptr = NULL; + + switch (msg->type) { + case WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE: + status = fwol_process_get_elna_bypass_resp(event); + break; + case WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE: + status = fwol_process_get_thermal_stats_resp(event); + break; + default: + status = QDF_STATUS_E_INVAL; + break; + } + + fwol_release_rx_event(event); + + return status; +} + +void fwol_release_rx_event(struct wlan_fwol_rx_event *event) +{ + if (!event) { + fwol_err("event is NULL"); + return; + } + + if (event->psoc) + wlan_objmgr_psoc_release_ref(event->psoc, WLAN_FWOL_SB_ID); + qdf_mem_free(event); +} + +QDF_STATUS fwol_set_ilp_config(struct wlan_objmgr_pdev *pdev, + uint32_t enable_ilp) +{ + QDF_STATUS status; + struct pdev_params pdev_param = {}; + + pdev_param.param_id = wmi_pdev_param_pcie_hw_ilp; + pdev_param.param_value = enable_ilp; + + status = tgt_fwol_pdev_param_send(pdev, pdev_param); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("wmi_pdev_param_pcie_hw_ilp failed %d", status); + + return status; +} + +QDF_STATUS fwol_set_sap_sho(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t sap_sho) +{ + QDF_STATUS status; + struct vdev_set_params vdev_param; + + vdev_param.vdev_id = vdev_id; + vdev_param.param_id = wmi_vdev_param_sho_config; + vdev_param.param_value = sap_sho; + + status = tgt_fwol_vdev_param_send(psoc, vdev_param); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("wmi_vdev_param_sho_config failed %d", status); + + return status; +} + +QDF_STATUS fwol_configure_hw_assist(struct wlan_objmgr_pdev *pdev, + bool disable_hw_assist) +{ + QDF_STATUS status; + struct pdev_params pdev_param = {}; + + pdev_param.param_id = wmi_pdev_param_disable_hw_assist; + pdev_param.param_value = disable_hw_assist; + + status = tgt_fwol_pdev_param_send(pdev, pdev_param); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("wmi_pdev_param_disable_hw_assist failed %d", status); + + return status; +} + +#ifdef FEATURE_WDS +QDF_STATUS +fwol_set_sap_wds_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + QDF_STATUS status; + struct vdev_set_params vdev_param; + + if (!wlan_mlme_get_wds_mode(psoc)) + return QDF_STATUS_SUCCESS; + + vdev_param.vdev_id = vdev_id; + vdev_param.param_id = wmi_vdev_param_wds; + vdev_param.param_value = true; + + status = tgt_fwol_vdev_param_send(psoc, vdev_param); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("wmi_vdev_param_wds failed %d", status); + + return status; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_adaptive_dwelltime.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_adaptive_dwelltime.h new file mode 100644 index 0000000000..c2ff92b3a3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_adaptive_dwelltime.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains adaptive dwell components. + */ + +#ifndef __CFG_ADAPTIVE_DWELLTIME_H +#define __CFG_ADAPTIVE_DWELLTIME_H + +/* + * + * adaptive_dwell_mode_enabled - enable/disable the adaptive dwell config. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * + * This ini will globally disable/enable the adaptive dwell config. + * Following parameters will set different values of attributes for dwell + * time optimization thus reducing total scan time. + * Acceptable values for this: + * 0: Config is disabled + * 1: Config is enabled + * + * Related: None. + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_DWELL_MODE_ENABLED CFG_INI_BOOL(\ + "adaptive_dwell_mode_enabled",\ + 1, \ + "enable the adaptive dwell config") + +/* + * + * global_adapt_dwelltime_mode - set default adaptive mode. + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini will set default adaptive mode, will be used if any of the + * scan dwell mode is set to default. + * For uses : see enum scan_dwelltime_adaptive_mode + * + * Related: None. + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_GLOBAL_ADAPTIVE_DWELL_MODE CFG_INI_UINT(\ + "global_adapt_dwelltime_mode",\ + 0, 4, 0,\ + CFG_VALUE_OR_DEFAULT, \ + "set default adaptive mode") + +/* + * + * adapt_dwell_lpf_weight - weight to calculate avg low pass filter. + * @Min: 0 + * @Max: 100 + * @Default: 80 + * + * This ini is used to set the weight to calculate + * the average low pass filter for channel congestion. + * Acceptable values for this: 0-100 (In %) + * + * Related: None. + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPT_DWELL_LPF_WEIGHT CFG_INI_UINT(\ + "adapt_dwell_lpf_weight",\ + 0, 100, 80,\ + CFG_VALUE_OR_DEFAULT, \ + "weight to calc avg low pass filter") + +/* + * + * adapt_dwell_passive_mon_intval - Interval to monitor passive scan in msec. + * @Min: 0 + * @Max: 25 + * @Default: 10 + * + * This ini is used to set interval to monitor wifi + * activity in passive scan in milliseconds. + * + * Related: None. + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPT_DWELL_PASMON_INTVAL CFG_INI_UINT(\ + "adapt_dwell_passive_mon_intval",\ + 0, 25, 10,\ + CFG_VALUE_OR_DEFAULT, \ + "interval to monitor passive scan") + +/* + * + * adapt_dwell_wifi_act_threshold - % of wifi activity used in passive scan + * @Min: 0 + * @Max: 100 + * @Default: 10 + * + * This ini is used to set % of wifi activity used in passive scan + * Acceptable values for this: 0-100 (in %) + * + * Related: None. + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_ADAPT_DWELL_WIFI_THRESH CFG_INI_UINT(\ + "adapt_dwell_wifi_act_threshold",\ + 0, 100, 10,\ + CFG_VALUE_OR_DEFAULT, \ + "percent of wifi activity in pas scan") + +#define CFG_ADAPTIVE_DWELLTIME_ALL \ + CFG(CFG_ADAPTIVE_DWELL_MODE_ENABLED) \ + CFG(CFG_GLOBAL_ADAPTIVE_DWELL_MODE) \ + CFG(CFG_ADAPT_DWELL_LPF_WEIGHT) \ + CFG(CFG_ADAPT_DWELL_PASMON_INTVAL) \ + CFG(CFG_ADAPT_DWELL_WIFI_THRESH) + +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_coex.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_coex.h new file mode 100644 index 0000000000..5bf5a505d2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_coex.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_COEX_H +#define __CFG_COEX_H + +/* + * + * gSetBTCMode - Config BTC mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * 0 - TDD + * 1 - FDD + * 2 - Hybrid + * + * Usage: External + * + * + */ +#define CFG_BTC_MODE CFG_INI_UINT( \ + "gSetBTCMode", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "BTC mode") + +/* + * + * gSetAntennaIsolation - Set Antenna Isolation + * @Min: 0 + * @Max: 255 + * @Default: 25 + * + * Usage: External + * + * + */ +#define CFG_ANTENNA_ISOLATION CFG_INI_UINT( \ + "gSetAntennaIsolation", \ + 0, \ + 255, \ + 25, \ + CFG_VALUE_OR_DEFAULT, \ + "Antenna Isolation") + +/* + * + * gSetMaxTxPowerForBTC - Set Max WLAN Tx power in COEX scenario + * @Min: 0 + * @Max: 100 + * @Default: 100 + * + * Usage: External + * + * + */ +#define CFG_MAX_TX_POWER_FOR_BTC CFG_INI_UINT( \ + "gSetMaxTxPowerForBTC", \ + 0, \ + 100, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "Max Tx Power for BTC") + +/* + * + * gSetWlanLowRssiThreshold - Set WLAN low RSSI threshold for BTC mode switching + * @Min: -100 + * @Max: 0 + * @Default: -80 + * + * Usage: External + * + * + */ +#define CFG_WLAN_LOW_RSSI_THRESHOLD CFG_INI_INT( \ + "gSetWlanLowRssiThreshold", \ + -100, \ + 0, \ + -80, \ + CFG_VALUE_OR_DEFAULT, \ + "WLAN Low RSSI Threshold") + +/* + * + * gSetBtLowRssiThreshold - Set BT low RSSI threshold for BTC mode switching + * @Min: -100 + * @Max: 0 + * @Default: -65 + * + * Usage: External + * + * + */ +#define CFG_BT_LOW_RSSI_THRESHOLD CFG_INI_INT( \ + "gSetBtLowRssiThreshold", \ + -100, \ + 0, \ + -65, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Low RSSI Threshold") + +/* + * + * gSetBtInterferenceLowLL - Set lower limit of low level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -25 + * + * Usage: External + * + * + */ +#define CFG_BT_INTERFERENCE_LOW_LL CFG_INI_INT( \ + "gSetBtInterferenceLowLL", \ + -100, \ + 100, \ + -25, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Interference Low LL") + +/* + * + * gSetBtInterferenceLowUL - Set upper limit of low level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -21 + * + * Usage: External + * + * + */ +#define CFG_BT_INTERFERENCE_LOW_UL CFG_INI_INT( \ + "gSetBtInterferenceLowUL", \ + -100, \ + 100, \ + -21, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Interference Low UL") + +/* + * + * gSetBtInterferenceMediumLL - Set lower limit of medium level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -20 + * + * Usage: External + * + * + */ +#define CFG_BT_INTERFERENCE_MEDIUM_LL CFG_INI_INT( \ + "gSetBtInterferenceMediumLL", \ + -100, \ + 100, \ + -20, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Interference Medium LL") + +/* + * + * gSetBtInterferenceMediumUL - Set upper limit of medium level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -16 + * + * Usage: External + * + * + */ +#define CFG_BT_INTERFERENCE_MEDIUM_UL CFG_INI_INT( \ + "gSetBtInterferenceMediumUL", \ + -100, \ + 100, \ + -16, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Interference Medium UL") + +/* + * + * gSetBtInterferenceHighLL - Set lower limit of high level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -15 + * + * Usage: External + * + * + */ +#define CFG_BT_INTERFERENCE_HIGH_LL CFG_INI_INT( \ + "gSetBtInterferenceHighLL", \ + -100, \ + 100, \ + -15, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Interference High LL") + +/* + * + * gSetBtInterferenceHighUL - Set upper limit of high level BT interference + * @Min: -100 + * @Max: 100 + * @Default: -11 + * + * Usage: External + * + * + */ +#define CFG_BT_INTERFERENCE_HIGH_UL CFG_INI_INT( \ + "gSetBtInterferenceHighUL", \ + -100, \ + 100, \ + -11, \ + CFG_VALUE_OR_DEFAULT, \ + "BT Interference High UL") + +#ifdef FEATURE_MPTA_HELPER +/* + * + * gMPTAHelperEnable - Enable MPTA Helper + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable coex MPTA Helper. + * + * Usage: External + * + * + */ +#define CFG_COEX_MPTA_HELPER CFG_INI_BOOL( \ + "gMPTAHelperEnable", \ + 0, \ + "Enable/Disable MPTA Helper") + +#define COEX_MPTA_HELPER_CFG CFG(CFG_COEX_MPTA_HELPER) +#else +#define COEX_MPTA_HELPER_CFG +#endif + +/* + * + * gBtScoAllowWlan2GScan - Allow wlan 2g scan when BT SCO connection is on + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * 0 - Disable + * 1 - Enable + * + * This ini is used to enable or disable wlan 2g scan + * when BT SCO connection is on. + * + * Usage: External + * + * + */ +#define CFG_BT_SCO_ALLOW_WLAN_2G_SCAN CFG_INI_BOOL( \ + "gBtScoAllowWlan2GScan", \ + 1, \ + "Bt Sco Allow Wlan 2G Scan") + +/* + * + * ble_scan_coex_policy - Ini to configure coex policy + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 0 - Better BLE Advertiser reception performance + * 1 - Better WLAN performance + * + * This ini is used to control the performance of ble scan case,’0’ to place + * more emphasis on BLE Scan results , ‘1’ to place more emphasis on WLAN + * performance + * + * Usage: External + * + * + */ +#define CFG_BLE_SCAN_COEX_POLICY CFG_INI_BOOL( \ + "ble_scan_coex_policy", \ + 0, \ + "BLE scan Coex policy") + +#ifdef FEATURE_COEX_CONFIG +/* + * + * gThreeWayCoexConfigLegacyEnable - Enable coex config legacy feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable three way coex config legacy feature. + * This feature is designed only for non-mobile solution. + * When the feature is disabled, Firmware use the default configuration to + * set the coex priority of three antenna(WLAN, BT, ZIGBEE). + * when enable this feature, customer can use the vendor command to set antenna + * coex priority dynamically. + * + * Supported Feature: three way coex config + * + * Usage: External + * + * + */ +#define CFG_THREE_WAY_COEX_CONFIG_LEGACY CFG_INI_BOOL( \ + "gThreeWayCoexConfigLegacyEnable", \ + 0, \ + "Enable/Disable COEX Config Legacy") + +#define THREE_WAY_COEX_CONFIG_LEGACY_CFG CFG(CFG_THREE_WAY_COEX_CONFIG_LEGACY) +#else +#define THREE_WAY_COEX_CONFIG_LEGACY_CFG +#endif + +#ifdef FEATURE_BTC_CHAIN_MODE +/* + * + * gSetInitChainModeForBTC - Used to set init chain mode for BTC + * @Min: 0 + * @Max: 0xFF + * @Default: 0xFF + * + * This ini is used to set init chain mode for BTC, default value + * should be set to the same as macro WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED(0xFF), + * only below values can be set: + * 0 - init WLAN 2.4G to support 2x2. + * It means chains of BT and WLAN 2.4G are shared, or BT is OFF. + * 1 - init WLAN 2.4G as 1x1, chains of BT and WLAN 2.4G are separated, + * fixed FDD. + * 2 - init WLAN 2.4G as 1x1, chains of BT and WLAN 2.4G are separated, + * hybrid mode + * 0xFF - no need to send init chain mode for BTC to firmware. + * + * Supported Feature: init chain mode for BTC + * + * Usage: External + * + * + */ +#define CFG_SET_INIT_CHAIN_MODE_FOR_BTC CFG_INI_UINT( \ + "gSetInitChainModeForBTC", \ + 0, \ + 0xFF, \ + 0xFF, \ + CFG_VALUE_OR_DEFAULT, \ + "Init Chain Mode For BTC") + +#define SET_INIT_CHAIN_MODE_FOR_BTC_CFG CFG(CFG_SET_INIT_CHAIN_MODE_FOR_BTC) +#else +#define SET_INIT_CHAIN_MODE_FOR_BTC_CFG +#endif + +#ifdef FEATURE_COEX_TPUT_SHAPING_CONFIG +/* + * + * coex_tput_shaping_enable - Ini to enable wifi configure traffic shaping + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 0 - traffic shaping is disable + * 1 - traffic shaping is enable + * + * This ini is used to enable and disable wifi traffic shaping + * + * Usage: External + * + * + */ +#define CFG_TPUT_SHAPING_ENABLE CFG_INI_BOOL( \ + "coex_tput_shaping_enable", \ + 0, \ + "coex_tput_shaping_enable") +#define TPUT_SHAPING_ENABLE_CFG CFG(CFG_TPUT_SHAPING_ENABLE) +#else +#define TPUT_SHAPING_ENABLE_CFG +#endif + +#define CFG_COEX_ALL \ + CFG(CFG_BTC_MODE) \ + CFG(CFG_ANTENNA_ISOLATION) \ + CFG(CFG_MAX_TX_POWER_FOR_BTC) \ + CFG(CFG_WLAN_LOW_RSSI_THRESHOLD) \ + CFG(CFG_BT_LOW_RSSI_THRESHOLD) \ + CFG(CFG_BT_INTERFERENCE_LOW_LL) \ + CFG(CFG_BT_INTERFERENCE_LOW_UL) \ + CFG(CFG_BT_INTERFERENCE_MEDIUM_LL) \ + CFG(CFG_BT_INTERFERENCE_MEDIUM_UL) \ + CFG(CFG_BT_INTERFERENCE_HIGH_LL) \ + CFG(CFG_BT_INTERFERENCE_HIGH_UL) \ + COEX_MPTA_HELPER_CFG \ + CFG(CFG_BT_SCO_ALLOW_WLAN_2G_SCAN) \ + THREE_WAY_COEX_CONFIG_LEGACY_CFG \ + SET_INIT_CHAIN_MODE_FOR_BTC_CFG \ + CFG(CFG_BLE_SCAN_COEX_POLICY) \ + TPUT_SHAPING_ENABLE_CFG +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_fwol.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_fwol.h new file mode 100644 index 0000000000..001e700c7a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_fwol.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012 - 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CFG_FWOL_H +#define __CFG_FWOL_H + +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" +#include "cfg_coex.h" +#include "cfg_thermal_temp.h" +#include "cfg_ie_allowlist.h" +#include "cfg_fwol_generic.h" +#include "cfg_neighbor_roam.h" +#include "cfg_adaptive_dwelltime.h" + +#ifdef WLAN_FW_OFFLOAD +#define CFG_FWOL_ALL \ + CFG_ADAPTIVE_DWELLTIME_ALL \ + CFG_11K_ALL \ + CFG_COEX_ALL \ + CFG_FWOL_GENERIC_ALL \ + CFG_IE_ALLOWLIST \ + CFG_THERMAL_TEMP_ALL +#else +#define CFG_FWOL_ALL +#endif + +#endif /* __CFG_FWOL_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h new file mode 100644 index 0000000000..954edeefb4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_fwol_generic.h @@ -0,0 +1,1000 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_FWOL_GENERIC_H +#define __CFG_FWOL_GENERIC_H + + +/* + * + * + * gEnableANI - Enable Adaptive Noise Immunity + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable Adaptive Noise Immunity. + * + * Related: None + * + * Supported Feature: ANI + * + * Usage: External + * + * + */ +#define CFG_ENABLE_ANI CFG_INI_BOOL( \ + "gEnableANI", \ + 1, \ + "Enable/Disable Adaptive Noise Immunity") + +/* + * + * gSetRTSForSIFSBursting - set rts for sifs bursting + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini set rts for sifs bursting + * + * Usage: External + * + * + */ +#define CFG_SET_RTS_FOR_SIFS_BURSTING CFG_INI_BOOL( \ + "gSetRTSForSIFSBursting", \ + 0, \ + "Set rts for sifs bursting") + +#ifdef WLAN_FEATURE_OFDM_SCRAMBLER_SEED +/* + * + * gEnableUpdateScramSeed - Enable/Disable OFDM scambler seed + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_ENABLE_OFDM_SCRAMBLER_SEED CFG_INI_BOOL( \ + "gEnableUpdateScramSeed", \ + false, \ + "Enable OFDM Scrambler Seed") + +#define ENABLE_OFDM_SCRAMBLER_SEED CFG(CFG_ENABLE_OFDM_SCRAMBLER_SEED) +#else +#define ENABLE_OFDM_SCRAMBLER_SEED +#endif + +/* + * + * sifs_burst_mask - Set sifs burst mask + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This ini is used to set 11n and legacy(non 11n/wmm) + * sifs burst. Especially under running multi stream + * traffic test case, it can be useful to let the low + * priority AC, or legacy mode device, or the specified + * AC to aggressively contend air medium, then have a + * obvious improvement of throughput. Bit0 is the switch + * of sifs burst, it must be set if want to enable sifs + * burst, Bit1 is for legacy mode. + * Supported configuration: + * 0: disabled + * 1: enabled, but disabled for legacy mode + * 3: all enabled + * + * Usage: External + * + * + */ +#define CFG_SET_SIFS_BURST CFG_INI_UINT( \ + "sifs_burst_mask", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Set SIFS burst mask") + +/* + * + * gMaxMPDUsInAMPDU - max mpdus in ampdu + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * This ini configure max mpdus in ampdu + * + * Usage: External + * + * + */ +#define CFG_MAX_MPDUS_IN_AMPDU CFG_INI_INT( \ + "gMaxMPDUsInAMPDU", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "This ini configure max mpdus in ampdu") + +/* + * + * gEnableFastPwrTransition - Configuration for fast power transition + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini supported values: + * 0x0: Phy register retention disabled (Higher timeline, Good for power) + * 0x1: Phy register retention statically enabled + * 0x2: Phy register retention enabled/disabled dynamically + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_PHY_REG CFG_INI_UINT( \ + "gEnableFastPwrTransition", \ + 0x0, \ + 0x2, \ + 0x0, \ + CFG_VALUE_OR_DEFAULT, \ + "Configuration for fast power transition") + +/* + * + * gUpperBrssiThresh - Sets Upper threshold for beacon RSSI + * @Min: 36 + * @Max: 66 + * @Default: 46 + * + * This ini sets Upper beacon threshold for beacon RSSI in FW + * Used to reduced RX chainmask in FW, once this threshold is + * reached FW will switch to 1X1 (Single chain). + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_UPPER_BRSSI_THRESH CFG_INI_UINT( \ + "gUpperBrssiThresh", \ + 36, \ + 66, \ + 46, \ + CFG_VALUE_OR_DEFAULT, \ + "Sets Upper threshold for beacon RSSI") + +/* + * + * gLowerBrssiThresh - Sets Lower threshold for beacon RSSI + * @Min: 6 + * @Max: 36 + * @Default: 26 + * + * This ini sets Lower beacon threshold for beacon RSSI in FW + * Used to increase RX chainmask in FW, once this threshold is + * reached FW will switch to 2X2 chain. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_LOWER_BRSSI_THRESH CFG_INI_UINT( \ + "gLowerBrssiThresh", \ + 6, \ + 36, \ + 26, \ + CFG_VALUE_OR_DEFAULT, \ + "Sets Lower threshold for beacon RSSI") + +/* + * + * gDtim1ChRxEnable - Enable/Disable DTIM 1Chrx feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini Enables or Disables DTIM 1CHRX feature in FW + * If this flag is set FW enables shutting off one chain + * while going to power save. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_DTIM_1CHRX_ENABLE CFG_INI_BOOL( \ + "gDtim1ChRxEnable", \ + 1, \ + "Enable/Disable DTIM 1Chrx feature") + +/* + * + * gEnableAlternativeChainmask - Enable Co-Ex Alternative Chainmask + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the Co-ex Alternative Chainmask + * feature via the wmi_pdev_param_alternative_chainmask_scheme + * firmware parameter. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_COEX_ALT_CHAINMASK CFG_INI_BOOL( \ + "gEnableAlternativeChainmask", \ + 0, \ + "Enable Co-Ex Alternative Chainmask") + +/* + * + * gEnableSmartChainmask - Enable Smart Chainmask + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the Smart Chainmask feature via + * the wmi_pdev_param_smart_chainmask_scheme firmware parameter. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_SMART_CHAINMASK CFG_INI_BOOL( \ + "gEnableSmartChainmask", \ + 0, \ + "Enable/disable the Smart Chainmask feature") + +/* + * + * gEnableRTSProfiles - It will use configuring different RTS profiles + * @Min: 0 + * @Max: 66 + * @Default: 33 + * + * This ini used for configuring different RTS profiles + * to firmware. + * Following are the valid values for the rts profile: + * RTSCTS_DISABLED 0 + * NOT_ALLOWED 1 + * NOT_ALLOWED 2 + * RTSCTS_DISABLED 16 + * RTSCTS_ENABLED_4_SECOND_RATESERIES 17 + * CTS2SELF_ENABLED_4_SECOND_RATESERIES 18 + * RTSCTS_DISABLED 32 + * RTSCTS_ENABLED_4_SWRETRIES 33 + * CTS2SELF_ENABLED_4_SWRETRIES 34 + * NOT_ALLOWED 48 + * NOT_ALLOWED 49 + * NOT_ALLOWED 50 + * RTSCTS_DISABLED 64 + * RTSCTS_ENABLED_4_ALL_RATESERIES 65 + * CTS2SELF_ENABLED_4_ALL_RATESERIES 66 + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_FW_RTS_PROFILE CFG_INI_INT( \ + "gEnableRTSProfiles", \ + 0, \ + 66, \ + 33, \ + CFG_VALUE_OR_DEFAULT, \ + "It is used to configure different RTS profiles") + +/* + * gFwDebugLogLevel - Firmware debug log level + * @Min: 0 + * @Max: 255 + * @Default: 3 + * + * This option controls the level of firmware debug log. Default value is + * DBGLOG_WARN, which is to enable error and warning logs. + * + * Related: None + * + * Supported Features: Debugging + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_FW_DEBUG_LOG_LEVEL CFG_INI_INT( \ + "gFwDebugLogLevel", \ + 0, \ + 255, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "enable error and warning logs by default") + +/* + * gFwDebugLogType - Firmware debug log type + * @Min: 0 + * @Max: 255 + * @Default: 3 + * + * This option controls how driver is to give the firmware logs to net link + * when cnss_diag service is started. + * + * Related: None + * + * Supported Features: Debugging + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_FW_LOG_TYPE CFG_INI_INT( \ + "gFwDebugLogType", \ + 0, \ + 255, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Default value to be given to the net link cnss_diag service") + +/* + * + * gFwDebugModuleLoglevel - modulized firmware debug log level + * @Min: N/A + * @Max: N/A + * @Default: N/A + * + * This ini is used to set modulized firmware debug log level. + * FW module log level input string format looks like below: + * gFwDebugModuleLoglevel=",,..." + * For example: + * gFwDebugModuleLoglevel="1,0,2,1,3,2,4,3,5,4,6,5,7,6" + * The above input string means: + * For FW module ID 1 enable log level 0 + * For FW module ID 2 enable log level 1 + * For FW module ID 3 enable log level 2 + * For FW module ID 4 enable log level 3 + * For FW module ID 5 enable log level 4 + * For FW module ID 6 enable log level 5 + * For FW module ID 7 enable log level 6 + * For valid values of log levels check enum DBGLOG_LOG_LVL and + * for valid values of module ids check enum WLAN_MODULE_ID. + * + * Related: None + * + * Supported Feature: Debugging + * + * Usage: Internal/External + * + * + */ + +#define FW_MODULE_LOG_LEVEL_STRING_LENGTH (512) +#define CFG_ENABLE_FW_MODULE_LOG_LEVEL CFG_INI_STRING( \ + "gFwDebugModuleLoglevel", \ + 0, \ + FW_MODULE_LOG_LEVEL_STRING_LENGTH, \ + "1,1,2,1,3,1,4,1,5,1,11,1,9,1,13,1,14,1,17,1,18,1,19,1,22,1,26,1,28,1,"\ + "29,1,31,1,36,1,38,1,46,1,47,1,50,1,52,1,53,1,56,1,60,1,61,1,113,1", \ + "Set modulized firmware debug log level") + +/* + * + * gFwDebugWowModuleLoglevel - modulized firmware wow debug log level + * @Min: N/A + * @Max: N/A + * @Default: N/A + * + * This ini is used to set modulized firmware wow debug log level. + * FW module log level input string format looks like below: + * gFwDebugWowModuleLoglevel=",,..." + * For example: + * gFwDebugWowModuleLoglevel="1,0,2,1,3,2,4,3,5,4,6,5,7,6" + * The above input string means: + * For FW module ID 1 enable log level 0 + * For FW module ID 2 enable log level 1 + * For FW module ID 3 enable log level 2 + * For FW module ID 4 enable log level 3 + * For FW module ID 5 enable log level 4 + * For FW module ID 6 enable log level 5 + * For FW module ID 7 enable log level 6 + * For valid values of log levels check enum DBGLOG_LOG_LVL and + * for valid values of module ids check enum WLAN_MODULE_ID. + * + * Related: None + * + * Supported Feature: Debugging + * + * Usage: External + * + * + */ +#define CFG_ENABLE_FW_WOW_MODULE_LOG_LEVEL CFG_INI_STRING( \ + "gFwDebugWowModuleLoglevel", \ + 0, \ + FW_MODULE_LOG_LEVEL_STRING_LENGTH, \ + "1,3,5,3,18,1,19,3,31,1,36,1,57,3", \ + "Set modulized firmware wow debug log level") + +#ifdef FEATURE_WLAN_RA_FILTERING +/* + * gRAFilterEnable + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_RA_FILTER_ENABLE CFG_INI_BOOL( \ + "gRAFilterEnable", \ + 1, \ + "Enable RA Filter") +#else +#define CFG_RA_FILTER_ENABLE +#endif + +/* + * gtsf_gpio_pin + * @Min: 0 + * @Max: 254 + * @Default: 255 + * + * GPIO pin to toggle when capture tsf + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_SET_TSF_GPIO_PIN CFG_INI_INT( \ + "gtsf_gpio_pin", \ + 0, \ + 255, \ + 255, \ + CFG_VALUE_OR_DEFAULT, \ + "GPIO pin to toggle when capture tsf") + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +/* + * gtsf_irq_host_gpio_pin + * @Min: 0 + * @Max: 254 + * @Default: 255 + * + * TSF irq GPIO pin of host platform + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_SET_TSF_IRQ_HOST_GPIO_PIN CFG_INI_INT( \ + "gtsf_irq_host_gpio_pin", \ + 0, \ + 255, \ + 255, \ + CFG_VALUE_OR_DEFAULT, \ + "TSF irq GPIO pin of host platform") + +#define __CFG_SET_TSF_IRQ_HOST_GPIO_PIN CFG(CFG_SET_TSF_IRQ_HOST_GPIO_PIN) +#else +#define __CFG_SET_TSF_IRQ_HOST_GPIO_PIN +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +/* + * + * gtsf_sync_host_gpio_pin + * @Min: 0 + * @Max: 254 + * @Default: 255 + * + * TSF sync GPIO pin of host platform + * + * The driver will use this gpio on host platform + * to drive the TSF sync pin on wlan chip. + * Toggling this gpio will generate a strobe to fw + * for latching TSF. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_SET_TSF_SYNC_HOST_GPIO_PIN CFG_INI_UINT( \ + "gtsf_sync_host_gpio_pin", \ + 0, \ + 254, \ + 255, \ + CFG_VALUE_OR_DEFAULT, \ + "TSF sync GPIO pin of host platform") + +#define __CFG_SET_TSF_SYNC_HOST_GPIO_PIN CFG(CFG_SET_TSF_SYNC_HOST_GPIO_PIN) +#else +#define __CFG_SET_TSF_SYNC_HOST_GPIO_PIN +#endif + +#if defined(WLAN_FEATURE_TSF) && defined(WLAN_FEATURE_TSF_PLUS) +/* + * g_enable_tsf_sync: Enable TSF sync feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Enable/disable periodic sync of TSF with firmware. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_TSF_SYNC_ENABLE CFG_INI_BOOL( \ + "g_enable_tsf_sync", \ + 0, \ + "Enable TSF sync feature") + +/* + * gtsf_ptp_options: TSF Plus feature options + * @Min: 0 + * @Max: 0xff + * @Default: 0xf + * + * CFG_SET_TSF_PTP_OPT_RX (0x1) + * CFG_SET_TSF_PTP_OPT_TX (0x2) + * CFG_SET_TSF_PTP_OPT_RAW (0x4) + * CFG_SET_TSF_DBG_FS (0x8) + * CFG_SET_TSF_PTP_OPT_TSF64_TX (0x10) + * CFG_SET_TSF_PTP_SYNC_PERIOD (0x20) + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_SET_TSF_PTP_OPT_RX (0x1) +#define CFG_SET_TSF_PTP_OPT_TX (0x2) +#define CFG_SET_TSF_PTP_OPT_RAW (0x4) +#define CFG_SET_TSF_DBG_FS (0x8) +#define CFG_SET_TSF_PTP_OPT_TSF64_TX (0x10) +#define CFG_SET_TSF_PTP_SYNC_PERIOD (0x20) + +#define CFG_SET_TSF_PTP_OPT CFG_INI_UINT( \ + "gtsf_ptp_options", \ + 0, \ + 0xff, \ + 0x2f, \ + CFG_VALUE_OR_DEFAULT, \ + "TSF Plus feature options") + +#define __CFG_SET_TSF_PTP_OPT \ + CFG(CFG_SET_TSF_PTP_OPT) \ + CFG(CFG_TSF_SYNC_ENABLE) +#else +#define __CFG_SET_TSF_PTP_OPT +#endif + +#if defined(WLAN_FEATURE_TSF_ACCURACY) +/* + * g_tsf_accuracy_configs: Enable TSF Accuracy Feature config parameters + * @Min: N/A + * @Max: N/A + * @Default: N/A + * + * This ini is to configure TSF Accuracy parameters. + * The list of mandate CFG_TSF_ACCURACY_CONFIG_LEN elements of type integer are + * specified with (,) delimiter. + * Param1: Enable/Disable TSF Accuracy Feature. + * Param2: GPIO to toggle on TSF sync done + * Param3: GPIO to raise pulse on specified period(TSF time domain) + * Param4: Periodicity of TSF pulse in milli seconds + * For example: + * g_tsf_accuracy_configs=1,430,431,100 + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_TSF_ACCURACY_CONFIG_LEN 4 +#define CFG_TSF_ACCURACY_CONFIG_STR_LEN 128 +#define CFG_TSF_ACCURACY_CONFIGS_DEF "0, -1, -1, 0" +#define CFG_TSF_ACCURACY_CONFIGS CFG_INI_STRING( \ + "g_tsf_accuracy_configs", \ + 0, \ + CFG_TSF_ACCURACY_CONFIG_STR_LEN, \ + CFG_TSF_ACCURACY_CONFIGS_DEF, \ + "Configure TSF Accuracy parameters") + +#define __CFG_TSF_ACCURACY_CONFIGS \ + CFG(CFG_TSF_ACCURACY_CONFIGS) +#else +#define __CFG_TSF_ACCURACY_CONFIGS +#endif + +#ifdef DHCP_SERVER_OFFLOAD +/* + * gDHCPServerOffloadEnable + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * DHCP Server offload support + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_DHCP_SERVER_OFFLOAD_SUPPORT CFG_INI_BOOL( \ + "gDHCPServerOffloadEnable", \ + 0, \ + "DHCP Server offload support") + +/* + * gDHCPMaxNumClients + * @Min: 1 + * @Max: 8 + * @Default: 8 + * + * Number of DHCP server offload clients + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT CFG_INI_INT( \ + "gDHCPMaxNumClients", \ + 1, \ + 8, \ + 8, \ + CFG_VALUE_OR_DEFAULT, \ + "Number of DHCP server offload clients") + +#define CFG_FWOL_DHCP \ + CFG(CFG_DHCP_SERVER_OFFLOAD_SUPPORT) \ + CFG(CFG_DHCP_SERVER_OFFLOAD_NUM_CLIENT) + +#else +#define CFG_FWOL_DHCP +#endif + +#ifdef WLAN_FEATURE_SAE +/* + * + * sae_enabled - Enable/Disable SAE support in driver + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable SAE support in driver + * Driver will update config to supplicant based on this config. + * + * Related: None + * + * Supported Feature: SAE + * Usage: External + * + * + */ + +#define CFG_IS_SAE_ENABLED CFG_INI_BOOL( \ + "sae_enabled", \ + 1, \ + "SAE feature control") +#define __CFG_IS_SAE_ENABLED CFG(CFG_IS_SAE_ENABLED) +#else +#define __CFG_IS_SAE_ENABLED +#endif + +/* + * + * gcmp_enabled - ini to enable/disable GCMP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Currently Firmware update the sequence number for each TID with 2^3 + * because of security issues. But with this PN mechanism, throughput drop + * is observed. With this ini FW takes the decision to trade off between + * security and throughput + * + * Supported Feature: STA/SAP/P2P + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_GCMP CFG_INI_BOOL( \ + "gcmp_enabled", \ + 1, \ + "GCMP Feature control param") + +/* + * + * gTxSchDelay - Enable/Disable Tx sch delay + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * Usage: Internal/External + * + * + */ +#define CFG_TX_SCH_DELAY CFG_INI_UINT( \ + "gTxSchDelay", \ + 0, \ + 5, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable/Disable Tx sch delay") + +/* + * + * gEnableSecondaryRate - Enable/Disable Secondary Retry Rate feature subset + * + * @Min: 0x0 + * @Max: 0x3F + * @Default: 0x17 + * + * It is a 32 bit value such that the various bits represent as below - + * Bit-0 : is Enable/Disable Control for "PPDU Secondary Retry Support" + * Bit-1 : is Enable/Disable Control for "RTS Black/White-listing Support" + * Bit-2 : is Enable/Disable Control for "Higher MCS retry restriction + * on XRETRY failures" + * Bit 3-5 : is "Xretry threshold" to use + * Bit 3~31 : reserved for future use. + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SECONDARY_RATE CFG_INI_UINT( \ + "gEnableSecondaryRate", \ + 0, \ + 0x3f, \ + 0x17, \ + CFG_VALUE_OR_DEFAULT, \ + "Secondary Retry Rate feature subset control") + +/* + * + * sap_xlna_bypass - Enable/Disable xLNA bypass + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable SAP xLNA bypass in the FW + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: Internal + * + * + */ + +#define CFG_SET_SAP_XLNA_BYPASS CFG_INI_BOOL( \ + "xlna_bypass", \ + 0, \ + "SAP xLNA bypass control") + +/* + * + * g_enable_ilp - ILP HW Block Configuration + * @Min: 0 + * @Max: 3 + * @Default: 2 + * + * This ini is used to configure ILP HW block with various options + * 0: disable + * 1: perf settings + * 2: max power saving + * 3: balanced settings + * + * Related: none + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ + +#define CFG_SET_ENABLE_ILP CFG_INI_UINT( \ + "g_enable_ilp", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "ILP configuration") + +/* + * + * + * sap_sho_config - Bitmap to Enable/Disable SAP HW offload + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This INI is used to configure sap hw offload. + * + * bit-0: enable/disable SHO + * bit-1: enable for Sta connected state as well. + * bit-2 to bit-31: Reserved + * + * Related: None + * + * Supported Feature: SAP + * Usage: External + * + * + */ +#define CFG_SAP_SHO_CONFIG CFG_INI_UINT(\ + "sap_sho_config", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "enable SHO config") + +/* + * + * g_disable_hw_assist - Flag to disable HW assist feature + * @Default: 0 + * + * This ini is used to enable/disable the HW assist feature in FW + * + * Related: none + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ + +#define CFG_DISABLE_HW_ASSIST CFG_INI_BOOL( \ + "g_disable_hw_assist", \ + 0, \ + "Disable HW assist feature in FW") + +/* + * + * g_enable_pci_gen - To enable pci gen switch + * @Default: 1 + * + * Related: None + * + * Supported Feature: PCI + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_PCI_GEN CFG_INI_BOOL( \ + "g_enable_pci_gen", \ + 1, \ + "enable pci gen") + +/* + * + * pcie_config - Ini to control pcie gen and lane params + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini is used to control to pcie gen and lane params + * 0 - FW controlled + * 1 - Force PCIe Gen and lane to max supported value + * 2 - Configure PCIE Gen and Lane based on MCS and BW + * 3 - Configure PCIE Gen and Lane based on TXRX tput using traffic monitor + * 4 - Allow PCIE Gen Speed and Lane width to be configured by host via + * OEM data commands. + * + * Related: g_enable_pci_gen + * + * Supported Feature: PCI + * + * Usage: External + * + * + */ +#define CFG_PCIE_CONFIG CFG_INI_UINT( \ + "pcie_config", \ + 0, \ + 4, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "to control pcie gen and lane") + +#define CFG_FWOL_GENERIC_ALL \ + CFG_FWOL_DHCP \ + CFG(CFG_ENABLE_ANI) \ + CFG(CFG_SET_RTS_FOR_SIFS_BURSTING) \ + CFG(CFG_SET_SIFS_BURST) \ + CFG(CFG_MAX_MPDUS_IN_AMPDU) \ + CFG(CFG_ENABLE_PHY_REG) \ + CFG(CFG_UPPER_BRSSI_THRESH) \ + CFG(CFG_LOWER_BRSSI_THRESH) \ + CFG(CFG_DTIM_1CHRX_ENABLE) \ + CFG(CFG_ENABLE_COEX_ALT_CHAINMASK) \ + CFG(CFG_ENABLE_SMART_CHAINMASK) \ + CFG(CFG_ENABLE_FW_RTS_PROFILE) \ + CFG(CFG_ENABLE_FW_DEBUG_LOG_LEVEL) \ + CFG(CFG_ENABLE_FW_LOG_TYPE) \ + CFG(CFG_ENABLE_FW_MODULE_LOG_LEVEL) \ + CFG(CFG_RA_FILTER_ENABLE) \ + CFG(CFG_SET_TSF_GPIO_PIN) \ + __CFG_SET_TSF_IRQ_HOST_GPIO_PIN \ + __CFG_SET_TSF_SYNC_HOST_GPIO_PIN \ + __CFG_SET_TSF_PTP_OPT \ + __CFG_TSF_ACCURACY_CONFIGS \ + __CFG_IS_SAE_ENABLED \ + CFG(CFG_ENABLE_GCMP) \ + CFG(CFG_TX_SCH_DELAY) \ + CFG(CFG_ENABLE_SECONDARY_RATE) \ + CFG(CFG_SET_SAP_XLNA_BYPASS) \ + CFG(CFG_SET_ENABLE_ILP) \ + CFG(CFG_ENABLE_FW_WOW_MODULE_LOG_LEVEL) \ + CFG(CFG_SAP_SHO_CONFIG) \ + CFG(CFG_DISABLE_HW_ASSIST) \ + CFG(CFG_ENABLE_PCI_GEN) \ + CFG(CFG_PCIE_CONFIG) \ + ENABLE_OFDM_SCRAMBLER_SEED + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_ie_allowlist.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_ie_allowlist.h new file mode 100644 index 0000000000..40802231d8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_ie_allowlist.h @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_IE_ALLOWLIST_H +#define __CFG_IE_ALLOWLIST_H + +/* + * + * g_enable_probereq_whitelist_ies - Enable IE allow listing + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable probe request IE allow listing feature. + * Values 0 and 1 are used to disable and enable respectively, by default this + * feature is disabled. + * + * Related: None + * + * Supported Feature: Probe request IE allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_ALLOWLIST CFG_INI_BOOL( \ + "g_enable_probereq_whitelist_ies", \ + 0, \ + "Enable IE allowlisting") + +/* + * For IE allow listing in Probe Req, following ini parameters from + * g_probe_req_ie_bitmap_0 to g_probe_req_ie_bitmap_7 are used. User needs to + * input this values in hexa decimal format, when bit is set in bitmap, + * corresponding IE needs to be included in probe request. + * + * Example: + * ======== + * If IE 221 needs to be in the probe request, set the corresponding bit + * as follows: + * a= IE/32 = 221/32 = 6 = g_probe_req_ie_bitmap_6 + * b = IE modulo 32 = 29, + * means set the bth bit in g_probe_req_ie_bitmap_a, + * therefore set 29th bit in g_probe_req_ie_bitmap_6, + * as a result, g_probe_req_ie_bitmap_6=20000000 + * + * Note: For IE 221, its mandatory to set the gProbeReqOUIs. + */ + +/* + * + * g_probe_req_ie_bitmap_0 - Used to set the bitmap of IEs from 0 to 31 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 0 to 31 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP0 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_0", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 0") + +/* + * + * g_probe_req_ie_bitmap_1 - Used to set the bitmap of IEs from 32 to 63 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 32 to 63 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP1 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_1", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 1") + +/* + * + * g_probe_req_ie_bitmap_2 - Used to set the bitmap of IEs from 64 to 95 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 64 to 95 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP2 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_2", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 2") + +/* + * + * g_probe_req_ie_bitmap_3 - Used to set the bitmap of IEs from 96 to 127 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 96 to 127 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP3 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_3", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 3") + +/* + * + * g_probe_req_ie_bitmap_4 - Used to set the bitmap of IEs from 128 to 159 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 128 to 159 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP4 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_4", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 4") + +/* + * + * g_probe_req_ie_bitmap_5 - Used to set the bitmap of IEs from 160 to 191 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 160 to 191 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP5 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_5", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 5") + +/* + * + * g_probe_req_ie_bitmap_6 - Used to set the bitmap of IEs from 192 to 223 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 192 to 223 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP6 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_6", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 6") + +/* + * + * g_probe_req_ie_bitmap_7 - Used to set the bitmap of IEs from 224 to 255 + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * This ini is used to include the IEs from 224 to 255 in probe request, + * when corresponding bit is set. + * + * Related: Need to enable g_enable_probereq_whitelist_ies. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_IE_BIT_MAP7 CFG_INI_UINT( \ + "g_probe_req_ie_bitmap_7", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "IE Bitmap 7") + +#define MAX_PRB_REQ_VENDOR_OUI_INI_LEN 160 +#define VENDOR_SPECIFIC_IE_BITMAP 0x20000000 +/* + * For vendor specific IE, Probe Req OUI types and sub types which are + * to be allow listed are specified in gProbeReqOUIs in the following + * example format - gProbeReqOUIs=AABBCCDD EEFF1122 + */ + +/* + * + * gProbeReqOUIs - Used to specify vendor specific OUIs + * @Default: Empty string + * + * This ini is used to include the specified OUIs in vendor specific IE + * of probe request. + * + * Related: Need to enable g_enable_probereq_whitelist_ies and + * vendor specific IE should be set in g_probe_req_ie_bitmap_6. + * + * Supported Feature: Probe request ie allowlisting + * + * Usage: Internal/External + * + * + */ +#define CFG_PROBE_REQ_OUI CFG_INI_STRING( \ + "gProbeReqOUIs", \ + 0, \ + MAX_PRB_REQ_VENDOR_OUI_INI_LEN, \ + "", \ + "Probe Req OUIs") + +#define CFG_IE_ALLOWLIST \ + CFG(CFG_PROBE_REQ_IE_ALLOWLIST) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP0) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP1) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP2) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP3) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP4) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP5) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP6) \ + CFG(CFG_PROBE_REQ_IE_BIT_MAP7) \ + CFG(CFG_PROBE_REQ_OUI) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_neighbor_roam.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_neighbor_roam.h new file mode 100644 index 0000000000..d2b1c69bb6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_neighbor_roam.h @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2012 - 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_NR_H +#define __CFG_NR_H + +/* + * + * 11k_offload_enable_bitmask - 11K offload bitmask feature control + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Disabled when 0 and enabled when 1 + * Usage: External + * + * + */ +#define CFG_OFFLOAD_11K_ENABLE_BITMASK CFG_INI_BOOL( \ + "11k_offload_enable_bitmask", \ + 1, \ + "11K offload bitmask feature control") + +/* + * + * nr_offload_params_bitmask - bitmask to specify which of the + * neighbor report offload params are valid in the ini + * frame + * @Min: 0 + * @Max: 63 + * @Default: 63 + * + * This ini specifies which of the neighbor report offload params are valid + * and should be considered by the FW. The bitmask is as follows + * B0: nr_offload_time_offset + * B1: nr_offload_low_rssi_offset + * B2: nr_offload_bmiss_count_trigger + * B3: nr_offload_per_threshold_offset + * B4: nr_offload_cache_timeout + * B5: nr_offload_max_req_cap + * B6-B7: Reserved + * + * Related : 11k_offload_enable_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK CFG_INI_UINT( \ + "nr_offload_params_bitmask", \ + 0, \ + 63, \ + 63, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor report offload params validity bitmask") + +#define OFFLOAD_11K_BITMASK_NEIGHBOR_REPORT_REQUEST 0x1 + +/* + * + * nr_offload_time_offset - time interval in seconds after the + * neighbor report offload command to send the first neighbor report request + * frame + * @Min: 0 + * @Max: 3600 + * @Default: 30 + * + * Related : nr_offload_params_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET CFG_INI_UINT( \ + "nr_offload_time_offset", \ + 0, \ + 3600, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor report time offset") + +/* + * + * nr_offload_low_rssi_offset - offset from the roam RSSI threshold + * to trigger the neighbor report request frame (in dBm) + * @Min: 4 + * @Max: 10 + * @Default: 4 + * + * Related : nr_offload_params_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET CFG_INI_UINT( \ + "nr_offload_low_rssi_offset", \ + 4, \ + 10, \ + 4, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor report low RSSI offset") + +/* + * + * nr_offload_bmiss_count_trigger - Number of beacon miss events to + * trigger a neighbor report request frame + * @Min: 1 + * @Max: 5 + * @Default: 1 + * + * Related : nr_offload_params_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER CFG_INI_UINT( \ + "nr_offload_bmiss_count_trigger", \ + 1, \ + 5, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Beacon miss count trigger for neighbor report req frame") + +/* + * + * nr_offload_per_threshold_offset - offset from PER threshold to + * trigger a neighbor report request frame (in %) + * @Min: 5 + * @Max: 20 + * @Default: 5 + * + * This ini is used to set the neighbor report offload parameter: + * + * Related : nr_offload_params_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET CFG_INI_UINT( \ + "nr_offload_per_threshold_offset", \ + 5, \ + 20, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "PER threshold offset to trigger neighbor report req frame") + +/* + * + * nr_offload_cache_timeout - time in seconds after which the + * neighbor report cache is marked as timed out and any of the triggers would + * cause a neighbor report request frame to be sent. + * @Min: 5 + * @Max: 86400 + * @Default: 1200 + * + * Related : nr_offload_params_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT CFG_INI_UINT( \ + "nr_offload_cache_timeout", \ + 5, \ + 86400, \ + 1200, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor report cache timeout to trigger report req frame") + +/* + * + * nr_offload_max_req_cap - Max number of neighbor + * report requests that can be sent to a connected peer in the current session. + * This counter is reset once a successful roam happens or at cache timeout + * @Min: 3 + * @Max: 300 + * @Default: 3 + * + * Related : nr_offload_params_bitmask + * + * Usage: External + * + * + */ +#define CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP CFG_INI_UINT( \ + "nr_offload_max_req_cap", \ + 3, \ + 300, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Max neighbor report request to be sent to connected peer") + +#define CFG_11K_ALL \ + CFG(CFG_OFFLOAD_11K_ENABLE_BITMASK) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_PARAMS_BITMASK) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_TIME_OFFSET) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_LOW_RSSI_OFFSET) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_BMISS_COUNT_TRIGGER) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_PER_THRESHOLD_OFFSET) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_CACHE_TIMEOUT) \ + CFG(CFG_OFFLOAD_NEIGHBOR_REPORT_MAX_REQ_CAP) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h new file mode 100644 index 0000000000..2e223c6c92 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 2012-2018,2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_THERMAL_TEMP_H +#define __CFG_THERMAL_TEMP_H + +/* + * + * gThermalTempMinLevel0 - Set Thermal Temp Min Level0 + * @Min: 0 + * @Max: 1000 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MIN_LEVEL0 CFG_INI_UINT( \ + "gThermalTempMinLevel0", \ + 0, \ + 1000, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Min Level0") + +/* + * + * gThermalTempMaxLevel0 - Set Thermal Temp Max Level0 + * @Min: 0 + * @Max: 1000 + * @Default: 90 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MAX_LEVEL0 CFG_INI_UINT( \ + "gThermalTempMaxLevel0", \ + 0, \ + 1000, \ + 90, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Max Level0") + +/* + * + * gThermalTempMinLevel1 - Set Thermal Temp Min Level1 + * @Min: 0 + * @Max: 1000 + * @Default: 70 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MIN_LEVEL1 CFG_INI_UINT( \ + "gThermalTempMinLevel1", \ + 0, \ + 1000, \ + 70, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Min Level1") + +/* + * + * gThermalTempMaxLevel1 - Set Thermal Temp Max Level1 + * @Min: 0 + * @Max: 1000 + * @Default: 110 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MAX_LEVEL1 CFG_INI_UINT( \ + "gThermalTempMaxLevel1", \ + 0, \ + 1000, \ + 110, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Max Level1") + +/* + * + * gThermalTempMinLevel2 - Set Thermal Temp Min Level2 + * @Min: 0 + * @Max: 1000 + * @Default: 90 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MIN_LEVEL2 CFG_INI_UINT( \ + "gThermalTempMinLevel2", \ + 0, \ + 1000, \ + 90, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Min Level2") + +/* + * + * gThermalTempMaxLevel2 - Set Thermal Temp Max Level2 + * @Min: 0 + * @Max: 1000 + * @Default: 125 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MAX_LEVEL2 CFG_INI_UINT( \ + "gThermalTempMaxLevel2", \ + 0, \ + 1000, \ + 125, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Max Level2") + +/* + * + * gThermalTempMinLevel3 - Set Thermal Temp Min Level3 + * @Min: 0 + * @Max: 1000 + * @Default: 110 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MIN_LEVEL3 CFG_INI_UINT( \ + "gThermalTempMinLevel3", \ + 0, \ + 1000, \ + 110, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Min Level3") + +/* + * + * gThermalTempMaxLevel3 - Set Thermal Temp Max Level3 + * @Min: 0 + * @Max: 1000 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MAX_LEVEL3 CFG_INI_UINT( \ + "gThermalTempMaxLevel3", \ + 0, \ + 1000, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Max Level3") + +/* + * + * gThermalTempMinLevel4 - Set Thermal Temp Min Level + * for TX OFF + * @Min: 0 + * @Max: 1000 + * @Default: 116 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MIN_LEVEL4 CFG_INI_UINT( \ + "gThermalTempMinLevel4", \ + 0, \ + 1000, \ + 116, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Min Level4") + +/* + * + * gThermalTempMaxLevel4 - Set Thermal Temp Max Level + * for TX OFF + * @Min: 0 + * @Max: 1000 + * @Default: 117 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MAX_LEVEL4 CFG_INI_UINT( \ + "gThermalTempMaxLevel4", \ + 0, \ + 1000, \ + 117, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Max Level4") + +/* + * + * gThermalTempMinLevel5 - Set Thermal Temp Min Level + * for target shutdown + * @Min: 0 + * @Max: 1000 + * @Default: 118 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MIN_LEVEL5 CFG_INI_UINT( \ + "gThermalTempMinLevel5", \ + 0, \ + 1000, \ + 118, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Min Level5") + +/* + * + * gThermalTempMaxLevel5 - Set Thermal Temp Max Level + * for target shutdown + * @Min: 0 + * @Max: 1000 + * @Default: 120 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_TEMP_MAX_LEVEL5 CFG_INI_UINT( \ + "gThermalTempMaxLevel5", \ + 0, \ + 1000, \ + 120, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Temp Max Level5") + +/* + * + * gThermalMitigationEnable - Set Thermal mitigation feature control + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_THERMAL_MITIGATION_ENABLE CFG_INI_BOOL( \ + "gThermalMitigationEnable", \ + 0, \ + "Thermal mitigation feature control") + +/* + * + * gThrottlePeriod - Set Thermal mitigation throttle period + * @Min: 10 + * @Max: 10000 + * @Default: 4000 + * + * Usage: External + * + * + */ +#define CFG_THROTTLE_PERIOD CFG_INI_UINT( \ + "gThrottlePeriod", \ + 10, \ + 10000, \ + 4000, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle period") + +/* + * + * gThrottleDutyCycleLevel0 - Set Thermal mitigation throttle duty cycle level0 + * @Min: 0 + * @Max: 0 + * @Default: 0 + * + * Usage: External + * + * + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL0 CFG_INI_UINT( \ + "gThrottleDutyCycleLevel0", \ + 0, \ + 0, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle duty cycle level0") + +/* + * + * gThrottleDutyCycleLevel1 - Set Thermal mitigation throttle duty cycle level1 + * @Min: 0 + * @Max: 100 + * @Default: 10 + * + * Usage: External + * + * + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL1 CFG_INI_UINT( \ + "gThrottleDutyCycleLevel1", \ + 0, \ + 100, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle duty cycle level1") + +/* + * + * gThrottleDutyCycleLevel2 - Set Thermal mitigation throttle duty cycle level2 + * @Min: 0 + * @Max: 100 + * @Default: 30 + * + * Usage: External + * + * + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL2 CFG_INI_UINT( \ + "gThrottleDutyCycleLevel2", \ + 0, \ + 100, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle duty cycle level2") + +/* + * + * gThrottleDutyCycleLevel3 - Set Thermal mitigation throttle duty cycle level3 + * @Min: 0 + * @Max: 100 + * @Default: 50 + * + * Usage: External + * + * + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL3 CFG_INI_UINT( \ + "gThrottleDutyCycleLevel3", \ + 0, \ + 100, \ + 50, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle duty cycle level3") + +/* + * + * gThrottleDutyCycleLevel4 - Set Thermal mitigation throttle duty cycle level4 + * @Min: 0 + * @Max: 100 + * @Default: 70 + * + * This ini will apply the thermal throttle duty cycle value in FW + * Usage: External + * + * + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL4 CFG_INI_UINT( \ + "gThrottleDutyCycleLevel4", \ + 0, \ + 100, \ + 70, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle duty cycle level4") + +/* + * + * gThrottleDutyCycleLevel5 - Set Thermal mitigation throttle duty cycle level5 + * @Min: 0 + * @Max: 100 + * @Default: 90 + * + * This ini will apply the thermal throttle duty cycle value in FW + * Usage: External + * + * + */ +#define CFG_THROTTLE_DUTY_CYCLE_LEVEL5 CFG_INI_UINT( \ + "gThrottleDutyCycleLevel5", \ + 0, \ + 100, \ + 90, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation throttle duty cycle level5") + +/* + *gThermalSamplingTime - Configure the thermal mitigation sampling time in ms. + * + * @Min: 10 + * @Max: 100 + * @Default: 100 + * + * This ini will control the sampling time that the thermal mitigation in FW + * will consider while applying the duty cycle. + * + * Usage: External + * + * Supported features: Thermal Mitigation + * + * + */ +#define CFG_THERMAL_SAMPLING_TIME CFG_INI_UINT( \ + "gThermalSamplingTime", \ + 10, \ + 100, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation sampling time") + +/* + * gThermalAppsPriority - Configure the thermal mitigation APPS priority + * + * @Min: 1 + * @Max: 10 + * @Default: 1 + * + * This ini will control the priority of the thermal mitigation in FW. + * FW will consider this priority while applying the duty cycle from the + * multiple clients. 1 being the least priority and 10 being highest. + * + * Usage: External + * + * Supported features: Thermal Mitigation + * + * + */ +#define CFG_THERMAL_APPS_PRIORITY CFG_INI_UINT( \ + "gThermalAppsPriority", \ + 1, \ + 10, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation priority for APPS") + +/* + * gThermalWppsPriority - Configure the thermal mitigation WPPS priority + * + * @Min: 1 + * @Max: 10 + * @Default: 1 + * + * This ini will control the priority of the thermal mitigation in FW. + * FW will consider this priority while applying the duty cycle from the + * multiple clients. 1 being the least priority and 10 being highest. + * + * Usage: External + * + * Supported features: Thermal Mitigation + * + * + */ +#define CFG_THERMAL_WPPS_PRIOITY CFG_INI_UINT( \ + "gThermalWppsPriority", \ + 1, \ + 10, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal mitigation priority for WPPS") + +/* + * gThermalMgmtAction - Configure the thermal management action + * + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini will control the thermal throttle action to be performed by target + * when the thermal temperature increase/decrease to threshold. + * The valid thermal mgmt action INI value is defined as + * enum thermal_mgmt_action_code. + * 0 - THERMAL_MGMT_ACTION_DEFAULT: target default throttle behaviour + * 1 - THERMAL_MGMT_ACTION_HALT_TRAFFIC: Halt tx traffic + * 2 - THERMAL_MGMT_ACTION_NOTIFY_HOST: Notify host + * 3 - THERMAL_MGMT_ACTION_CHAINSCALING: Tx Chain scaling + * + * Usage: External + * + * Supported features: Thermal Mitigation + * + * + */ +#define CFG_THERMAL_MGMT_ACTION CFG_INI_UINT( \ + "gThermalMgmtAction", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal management action") + +/* + * gThermalStatsTempOffset - Configure the thermal stats offset + * + * @Min: 0 + * @Max: 10 + * @Default: 5 + * + * This ini will configure Thermal temperature offset value for capturing + * thermal stats in thermal range. + * Thermal STATS start capturing from temperature threshold to temperature + * threshold + offset. + * If the value 0 is given then then thermal STATS capture is disabled + * + * Usage: External + * + * + */ +#define CFG_THERMAL_STATS_TEMP_OFFSET CFG_INI_UINT( \ + "gThermalStatsTempOffset", \ + 0, \ + 10, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Thermal Stats Temperature Offset") + +#define CFG_THERMAL_TEMP_ALL \ + CFG(CFG_THERMAL_TEMP_MIN_LEVEL0) \ + CFG(CFG_THERMAL_TEMP_MAX_LEVEL0) \ + CFG(CFG_THERMAL_TEMP_MIN_LEVEL1) \ + CFG(CFG_THERMAL_TEMP_MAX_LEVEL1) \ + CFG(CFG_THERMAL_TEMP_MIN_LEVEL2) \ + CFG(CFG_THERMAL_TEMP_MAX_LEVEL2) \ + CFG(CFG_THERMAL_TEMP_MIN_LEVEL3) \ + CFG(CFG_THERMAL_TEMP_MAX_LEVEL3) \ + CFG(CFG_THERMAL_TEMP_MIN_LEVEL4) \ + CFG(CFG_THERMAL_TEMP_MAX_LEVEL4) \ + CFG(CFG_THERMAL_TEMP_MIN_LEVEL5) \ + CFG(CFG_THERMAL_TEMP_MAX_LEVEL5) \ + CFG(CFG_THERMAL_MITIGATION_ENABLE) \ + CFG(CFG_THROTTLE_PERIOD) \ + CFG(CFG_THROTTLE_DUTY_CYCLE_LEVEL0) \ + CFG(CFG_THROTTLE_DUTY_CYCLE_LEVEL1) \ + CFG(CFG_THROTTLE_DUTY_CYCLE_LEVEL2) \ + CFG(CFG_THROTTLE_DUTY_CYCLE_LEVEL3) \ + CFG(CFG_THROTTLE_DUTY_CYCLE_LEVEL4) \ + CFG(CFG_THROTTLE_DUTY_CYCLE_LEVEL5) \ + CFG(CFG_THERMAL_SAMPLING_TIME) \ + CFG(CFG_THERMAL_APPS_PRIORITY) \ + CFG(CFG_THERMAL_WPPS_PRIOITY) \ + CFG(CFG_THERMAL_MGMT_ACTION) \ + CFG(CFG_THERMAL_STATS_TEMP_OFFSET)\ + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h new file mode 100644 index 0000000000..b630e38042 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains fw offload structure definitions + */ + +#ifndef _WLAN_FWOL_PUBLIC_STRUCTS_H_ +#define _WLAN_FWOL_PUBLIC_STRUCTS_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_thermal_public_struct.h" +#include "wmi_unified.h" + +#ifdef WLAN_FEATURE_ELNA + +/** + * enum fwol_extlna_mode - provides elna modes + * @EXTLNA_MODE_DISABLE_ELNA_BYPASS: disables elna bypass + * @EXTLNA_MODE_ENABLE_ELNA_BYPASS: enables elna bypass + * @EXTLNA_MODE_FIRMWARE_DEFAULT: Reset eLNA bypass configuration, + * the driver should revert to the default + * configuration of eLNA bypass + */ +enum fwol_extlna_mode { + EXTLNA_MODE_DISABLE_ELNA_BYPASS = 0, + EXTLNA_MODE_ENABLE_ELNA_BYPASS, + EXTLNA_MODE_FIRMWARE_DEFAULT, +}; + +/** + * struct set_elna_bypass_request - set eLNA bypass request + * @vdev_id: vdev id + * @elna_mode:0 - disable eLNA bypass + * 1 - enable eLNA bypass + * 2 - firmware default + */ +struct set_elna_bypass_request { + uint8_t vdev_id; + enum fwol_extlna_mode elna_mode; +}; + +/** + * struct get_elna_bypass_request - get eLNA bypass request + * @vdev_id: vdev id + */ +struct get_elna_bypass_request { + uint8_t vdev_id; +}; + +/** + * struct get_elna_bypass_response - get eLNA bypass response + * @vdev_id: vdev id + * @elna_mode:0 - disable eLNA bypass + * 1 - enable eLNA bypass + * 2 - firmware default + */ +struct get_elna_bypass_response { + uint8_t vdev_id; + enum fwol_extlna_mode elna_mode; +}; +#endif + +/** + * struct thermal_throttle_info - thermal throttle info from Target + * @temperature: current temperature in c Degree + * @level: target thermal level info + * @pdev_id: pdev id + * @therm_throt_levels: Number of thermal throttle levels + * @level_info: Thermal Stats for each level + */ +struct thermal_throttle_info { + uint32_t temperature; + enum thermal_throttle_level level; + uint32_t pdev_id; + uint32_t therm_throt_levels; + struct thermal_throt_level_stats level_info[WMI_THERMAL_STATS_TEMP_THRESH_LEVEL_MAX]; +}; + +/** + * struct wlan_fwol_callbacks - fw offload callbacks + * @get_elna_bypass_callback: callback for get eLNA bypass + * @get_elna_bypass_context: context for get eLNA bypass + * @get_thermal_stats_callback: callback for get thermal stats + * @get_thermal_stats_context: context for get thermal stats + */ +struct wlan_fwol_callbacks { +#ifdef WLAN_FEATURE_ELNA + void (*get_elna_bypass_callback)(void *context, + struct get_elna_bypass_response *response); + void *get_elna_bypass_context; +#endif +#ifdef THERMAL_STATS_SUPPORT + void (*get_thermal_stats_callback)(void *context, + struct thermal_throttle_info *response); + void *get_thermal_stats_context; +#endif +}; + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD + +#define MDNS_FQDN_TYPE_GENERAL (0) +/* Maximum length of FQDN string including the NULL byte */ +#define MAX_FQDN_LEN (64) +/* This length depends on the WMI Message and TLV Header size. + * ((WMI_SVC_MSG_MAX_SIZE - WMI_TLV_HDR_SIZE) + */ +#define MAX_MDNS_RESP_LEN (512) + +/** + * struct mdns_config_info - Multicast DNS configuration information + * @vdev_id: vdev id + * @enable: false - disable mdns + * true - enable mdns + * @fqdn_type: FQDN type + * @fqdn_data: Fully Qualified Domain Name of the local network + * @fqdn_len: FQDN length + * @resource_record_count: Number Resource Records present in the answer payload + * @answer_payload_len: Length of the answer payload sent by mdnsResponder in userspace + * @answer_payload_data: Binary blob used to frame mdns response for mdns queries + */ +struct mdns_config_info { + uint32_t vdev_id; + bool enable; + uint32_t fqdn_type; + uint32_t fqdn_len; + uint8_t fqdn_data[MAX_FQDN_LEN]; + uint32_t resource_record_count; + uint32_t answer_payload_len; + uint8_t answer_payload_data[MAX_MDNS_RESP_LEN]; +}; +#endif + +/** + * struct wlan_fwol_tx_ops - structure of tx func pointers + * @set_elna_bypass: set eLNA bypass + * @get_elna_bypass: get eLNA bypass + * @reg_evt_handler: register event handler + * @unreg_evt_handler: unregister event handler + * @send_dscp_up_map_to_fw: send dscp-to-up map values to FW + * @set_mdns_config: set mdns config info + * @get_thermal_stats: send get_thermal_stats cmd to FW + */ +struct wlan_fwol_tx_ops { +#ifdef WLAN_FEATURE_ELNA + QDF_STATUS (*set_elna_bypass)(struct wlan_objmgr_psoc *psoc, + struct set_elna_bypass_request *req); + QDF_STATUS (*get_elna_bypass)(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_request *req); +#endif + QDF_STATUS (*reg_evt_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); + QDF_STATUS (*unreg_evt_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); +#ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW + QDF_STATUS (*send_dscp_up_map_to_fw)( + struct wlan_objmgr_psoc *psoc, + uint32_t *dscp_to_up_map); +#endif +#ifdef WLAN_FEATURE_MDNS_OFFLOAD + QDF_STATUS (*set_mdns_config)(struct wlan_objmgr_psoc *psoc, + struct mdns_config_info *mdns_info); +#endif +#ifdef THERMAL_STATS_SUPPORT + QDF_STATUS (*get_thermal_stats)(struct wlan_objmgr_psoc *psoc, + enum thermal_stats_request_type req_type, + uint8_t therm_stats_offset); +#endif +}; + +/** + * struct wlan_fwol_rx_ops - structure of rx func pointers + * @get_elna_bypass_resp: get eLNA bypass response + * @notify_thermal_throttle_handler: thermal stats indication callback to fwol + * core from target if layer + * @get_thermal_stats_resp: thermal stats cmd response callback to fwol + */ +struct wlan_fwol_rx_ops { +#ifdef WLAN_FEATURE_ELNA + QDF_STATUS (*get_elna_bypass_resp)(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_response *resp); +#endif +#ifdef FW_THERMAL_THROTTLE_SUPPORT + QDF_STATUS (*notify_thermal_throttle_handler)( + struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info); +#endif +#ifdef THERMAL_STATS_SUPPORT + QDF_STATUS (*get_thermal_stats_resp)(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *resp); +#endif +}; + +/** + * struct fwol_thermal_callbacks - structure of rx callback to hdd layer + * @notify_thermal_throttle_handler: thermal throttle event callback + */ +struct fwol_thermal_callbacks { + QDF_STATUS (*notify_thermal_throttle_handler)( + struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info); +}; +#endif /* _WLAN_FWOL_PUBLIC_STRUCTS_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_tgt_api.h new file mode 100644 index 0000000000..99e54f0420 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_tgt_api.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: fw offload south bound interface declaration + */ +#ifndef _WLAN_FWOL_TGT_API_H +#define _WLAN_FWOL_TGT_API_H + +#include "wlan_fwol_public_structs.h" + +#define FWOL_WILDCARD_PDEV_ID 0 + +/** + * tgt_fwol_register_ev_handler() - register south bound event handler + * @psoc: psoc handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_register_ev_handler(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_fwol_unregister_ev_handler() - unregister south bound event handler + * @psoc: psoc handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_unregister_ev_handler(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_fwol_register_rx_ops() - register fw offload rx operations + * @rx_ops: fps to rx operations + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops *rx_ops); + +/** + * tgt_fwol_pdev_param_send() - send pdev params to firmware + * @pdev: pdev handle + * @pdev_param: pdev params + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_pdev_param_send(struct wlan_objmgr_pdev *pdev, + struct pdev_params pdev_param); + +/** + * tgt_fwol_vdev_param_send() - send vdev params to firmware + * @psoc: psoc handle + * @vdev_param: vdev params + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_fwol_vdev_param_send(struct wlan_objmgr_psoc *psoc, + struct vdev_set_params vdev_param); + +#endif /* _WLAN_FWOL_TGT_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h new file mode 100644 index 0000000000..9c49f6e100 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h @@ -0,0 +1,1125 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare internal API related to the fwol component + */ + +#ifndef _WLAN_FWOL_UCFG_API_H_ +#define _WLAN_FWOL_UCFG_API_H_ + +#include +#include +#include +#include "wlan_fw_offload_main.h" +#include "wlan_fwol_public_structs.h" + +#ifdef WLAN_FW_OFFLOAD +/** + * ucfg_fwol_psoc_open() - FWOL component Open + * @psoc: pointer to psoc object + * + * Open the FWOL component and initialize the FWOL structure + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_psoc_close() - FWOL component close + * @psoc: pointer to psoc object + * + * Close the FWOL component and clear the FWOL structures + * + * Return: None + */ +void ucfg_fwol_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_psoc_enable() - FWOL component enable + * @psoc: pointer to psoc object + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_psoc_disable() - FWOL component disable + * @psoc: pointer to psoc object + * + * Return: None + */ +void ucfg_fwol_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_init() - initialize fwol_ctx context. + * + * This function initializes the fwol context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_fwol_init(void); + +/** + * ucfg_fwol_deinit() - De initialize fwol_ctx context. + * + * This function De initializes fwol context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +void ucfg_fwol_deinit(void); + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +/** + * ucfg_fwol_thermal_register_callbacks() - Register thermal callbacks + * to be called by fwol thermal + * @psoc: psoc object + * @cb: callback functions + * + * Currently only one callback notify_thermal_throttle_handler can be + * registered to fwol thermal core. The client will be notified by the callback + * when new thermal throttle level is changed in target. + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_fwol_thermal_register_callbacks( + struct wlan_objmgr_psoc *psoc, + struct fwol_thermal_callbacks *cb); + +/** + * ucfg_fwol_thermal_unregister_callbacks() - unregister thermal callbacks + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_fwol_thermal_unregister_callbacks( + struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_thermal_get_target_level() - get thermal level based on cached + * target thermal throttle level + * @psoc: psoc object + * @level: target thermal throttle level info + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_fwol_thermal_get_target_level(struct wlan_objmgr_psoc *psoc, + enum thermal_throttle_level *level); +#else +static inline QDF_STATUS ucfg_fwol_thermal_register_callbacks( + struct wlan_objmgr_psoc *psoc, + struct fwol_thermal_callbacks *cb) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_fwol_thermal_unregister_callbacks( + struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_fwol_thermal_get_target_level(struct wlan_objmgr_psoc *psoc, + enum thermal_throttle_level *level) + +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * ucfg_fwol_get_coex_config_params() - Get coex config params + * @psoc: Pointer to psoc object + * @coex_config: Pointer to struct wlan_fwol_coex_config + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_fwol_get_coex_config_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config); + +/** + * ucfg_fwol_get_thermal_temp() - Get thermal temperature config params + * @psoc: Pointer to psoc object + * @thermal_temp: Pointer to struct wlan_fwol_thermal_temp + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_thermal_temp(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_temp); + +/** + * ucfg_fwol_is_neighbor_report_req_supported() - Get neighbor report request + * supported bit + * @psoc: Pointer to psoc object + * @neighbor_report_req: Pointer to return value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_is_neighbor_report_req_supported(struct wlan_objmgr_psoc *psoc, + bool *neighbor_report_req); + +/** + * ucfg_fwol_get_ie_allowlist() - Get IE allowlist param value + * @psoc: Pointer to psoc object + * @ie_allowlist: Pointer to return the IE allowlist param value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_ie_allowlist(struct wlan_objmgr_psoc *psoc, bool *ie_allowlist); + +/** + * ucfg_fwol_set_ie_allowlist() - Set IE allowlist param value + * @psoc: Pointer to psoc object + * @ie_allowlist: Value to set IE allowlist param + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_set_ie_allowlist(struct wlan_objmgr_psoc *psoc, bool ie_allowlist); + +/** + * ucfg_fwol_get_all_allowlist_params() - Get all IE allowlist param values + * @psoc: Pointer to psoc object + * @allowlist: Pointer to struct wlan_fwol_ie_allowlist + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_all_allowlist_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_allowlist *allowlist); + +/** + * ucfg_fwol_get_ani_enabled() - Assigns the ani_enabled value + * @psoc: pointer to the psoc object + * @ani_enabled: pointer to return ani_enabled value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_ani_enabled(struct wlan_objmgr_psoc *psoc, + bool *ani_enabled); + +/** + * ucfg_fwol_get_pcie_config() - Assigns the pcie_config value + * @psoc: pointer to the psoc object + * @pcie_config: pointer to return pcie_config value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_pcie_config(struct wlan_objmgr_psoc *psoc, + uint8_t *pcie_config); + +/** + * ucfg_get_enable_rts_sifsbursting() - Assigns the enable_rts_sifsbursting + * value + * @psoc: pointer to the psoc object + * @enable_rts_sifsbursting: pointer to return enable_rts_sifsbursting value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_enable_rts_sifsbursting(struct wlan_objmgr_psoc *psoc, + bool *enable_rts_sifsbursting); + +/** + * ucfg_get_enable_sifs_burst() - Get the enable_sifs_burst value + * @psoc: pointer to the psoc object + * @enable_sifs_burst: pointer to return enable_sifs_burst value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_enable_sifs_burst(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_sifs_burst); + +/** + * ucfg_get_max_mpdus_inampdu() - Assigns the max_mpdus_inampdu value + * @psoc: pointer to the psoc object + * @max_mpdus_inampdu: pointer to return max_mpdus_inampdu value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_max_mpdus_inampdu(struct wlan_objmgr_psoc *psoc, + uint8_t *max_mpdus_inampdu); + +/** + * ucfg_get_enable_phy_reg_retention() - Assigns enable_phy_reg_retention value + * @psoc: pointer to the psoc object + * @enable_phy_reg_retention: pointer to return enable_phy_reg_retention value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_enable_phy_reg_retention(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_phy_reg_retention); + +/** + * ucfg_get_upper_brssi_thresh() - Assigns upper_brssi_thresh value + * @psoc: pointer to the psoc object + * @upper_brssi_thresh: pointer to return upper_brssi_thresh value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_upper_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *upper_brssi_thresh); + +/** + * ucfg_get_lower_brssi_thresh() - Assigns lower_brssi_thresh value + * @psoc: pointer to the psoc object + * @lower_brssi_thresh: pointer to return lower_brssi_thresh value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_lower_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *lower_brssi_thresh); + +/** + * ucfg_get_enable_dtim_1chrx() - Assigns enable_dtim_1chrx value + * @psoc: pointer to the psoc object + * @enable_dtim_1chrx: pointer to return enable_dtim_1chrx value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_enable_dtim_1chrx(struct wlan_objmgr_psoc *psoc, + bool *enable_dtim_1chrx); + +/** + * ucfg_get_alternative_chainmask_enabled() - Assigns alt chainmask_enabled + * value + * @psoc: pointer to the psoc object + * @alternative_chainmask_enabled: pointer to return + * alternative_chainmask_enabled value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_get_alternative_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *alternative_chainmask_enabled); + +/** + * ucfg_get_smart_chainmask_enabled() - Assigns smart_chainmask_enabled value + * @psoc: pointer to the psoc object + * @smart_chainmask_enabled: pointer to return smart_chainmask_enabled value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_get_smart_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *smart_chainmask_enabled); + +/** + * ucfg_fwol_get_rts_profile() - Assigns get_rts_profile value + * @psoc: pointer to the psoc object + * @get_rts_profile: pointer to return RTS profile value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_rts_profile(struct wlan_objmgr_psoc *psoc, + uint16_t *get_rts_profile); + +/** + * ucfg_fwol_get_enable_fw_log_level() - Assigns enable_fw_log_level value + * @psoc: pointer to the psoc object + * @enable_fw_log_level: pointer to return firmware log level enable bitmap + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_enable_fw_log_level(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_level); + +/** + * ucfg_fwol_get_enable_fw_log_type() - Assigns enable_fw_log_type value + * @psoc: pointer to the psoc object + * @enable_fw_log_type: pointer to return firmware log type bitmap + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_enable_fw_log_type(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_type); + +/** + * ucfg_fwol_get_enable_fw_module_log_level() - Assigns + * enable_fw_module_log_level string + * @psoc: pointer to the psoc object + * @enable_fw_module_log_level: + * pointer to enable_fw_module_log_level array + * @enable_fw_module_log_level_num: + * pointer to enable_fw_module_log_level array element num + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_enable_fw_module_log_level( + struct wlan_objmgr_psoc *psoc, + uint8_t **enable_fw_module_log_level, + uint8_t *enable_fw_module_log_level_num); + +/** + * ucfg_fwol_wow_get_enable_fw_module_log_level() - Assigns + * enable_fw_module_log_level string + * + * @psoc: pointer to the psoc object + * @enable_fw_wow_module_log_level: + * pointer to enable_fw_wow_module_log_level array + * @enable_fw_wow_module_log_level_num: + * pointer to enable_fw_wow_module_log_level array element num + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_wow_get_enable_fw_module_log_level( + struct wlan_objmgr_psoc *psoc, + uint8_t **enable_fw_wow_module_log_level, + uint8_t *enable_fw_wow_module_log_level_num); + +/** + * ucfg_fwol_get_sap_xlna_bypass() - Assigns sap_xlna_bypass value + * @psoc: pointer to the psoc object + * @sap_xlna_bypass: pointer to return sap_xlna_bypass bool + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_sap_xlna_bypass(struct wlan_objmgr_psoc *psoc, + bool *sap_xlna_bypass); + +#ifdef FEATURE_WLAN_RA_FILTERING +/** + * ucfg_fwol_set_is_rate_limit_enabled() - Sets the is_rate_limit_enabled value + * @psoc: pointer to the psoc object + * @is_rate_limit_enabled: value to set rate limit enabled bool + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_set_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool is_rate_limit_enabled); + +/** + * ucfg_fwol_get_is_rate_limit_enabled() - Assigns is_rate_limit_enabled value + * @psoc: pointer to the psoc object + * @is_rate_limit_enabled: pointer to return rate limit enabled bool + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool *is_rate_limit_enabled); + +#endif /* FEATURE_WLAN_RA_FILTERING */ + +/** + * ucfg_fwol_get_tsf_gpio_pin() - Assigns tsf_gpio_pin value + * @psoc: pointer to the psoc object + * @tsf_gpio_pin: pointer to return TSF GPIO pin value + * + * Return: QDF Status + */ + +QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_gpio_pin); + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +/** + * ucfg_fwol_get_tsf_irq_host_gpio_pin() - Assigns tsf_irq_host_gpio_pin value + * @psoc: pointer to the psoc object + * @tsf_irq_host_gpio_pin: pointer to return the TSF IRQ GPIO pin number + * + * Return: QDF Status + */ + +QDF_STATUS +ucfg_fwol_get_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_irq_host_gpio_pin); +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +/** + * ucfg_fwol_get_tsf_sync_host_gpio_pin() - Assigns tsf_sync_host_gpio_pin value + * @psoc: pointer to the psoc object + * @tsf_irq_host_gpio_pin: pointer to return the TSF sync GPIO pin number + * + * Return: QDF Status + */ + +QDF_STATUS +ucfg_fwol_get_tsf_sync_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_irq_host_gpio_pin); +#endif + +#ifdef DHCP_SERVER_OFFLOAD +/** + * ucfg_fwol_get_enable_dhcp_server_offload()-Assign enable_dhcp_server_offload + * @psoc: pointer to the psoc object + * @enable_dhcp_server_offload: pointer to return enable_dhcp_server_offload + * value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_enable_dhcp_server_offload(struct wlan_objmgr_psoc *psoc, + bool *enable_dhcp_server_offload); + +/** + * ucfg_fwol_get_dhcp_max_num_clients() - Assigns dhcp_max_num_clients value + * @psoc: pointer to the psoc object + * @dhcp_max_num_clients: pointer to return the max number of DHC clients value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_dhcp_max_num_clients(struct wlan_objmgr_psoc *psoc, + uint32_t *dhcp_max_num_clients); +#endif + +/** + * ucfg_fwol_get_tsf_sync_enable() - Get TSF sync enabled + * @psoc: pointer to the psoc object + * @tsf_sync_enable: Pointer to tsf sync enabled + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_tsf_sync_enable(struct wlan_objmgr_psoc *psoc, + bool *tsf_sync_enable); + +#ifdef WLAN_FEATURE_TSF_ACCURACY +/** + * ucfg_fwol_get_tsf_accuracy_configs() - Get TSF accuracy configs + * @psoc: pointer to the psoc object + * @config: Pointer to hold TSF Accuracy Feature configs + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_tsf_accuracy_configs(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_tsf_accuracy_configs **config); +#endif + +/** + * ucfg_fwol_get_tsf_ptp_options() - Get TSF Plus feature options + * @psoc: pointer to the psoc object + * @tsf_ptp_options: Pointer to return tsf ptp options + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_ptp_options); + +/** + * ucfg_fwol_get_sae_enable() - Get SAE feature enable status + * @psoc: pointer to the psoc object + * + * Return: True if enabled else false + */ +bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_get_gcmp_enable() - Get GCMP feature enable status + * @psoc: pointer to the psoc object + * + * Return: True if enabled else false + */ +bool ucfg_fwol_get_gcmp_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_fwol_get_enable_tx_sch_delay() - Get enable tx sch delay + * @psoc: pointer to the psoc object + * @enable_tx_sch_delay: Pointer to return enable_tx_sch_delay value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_enable_tx_sch_delay(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_tx_sch_delay); + +#ifdef WLAN_FEATURE_OFDM_SCRAMBLER_SEED +/** + * ucfg_fwol_get_ofdm_scrambler_seed() - Assigns enable_ofdm_scrambler_seed + * @psoc: pointer to psoc object + * @enable_ofdm_scrambler_seed: Pointer to return enable_ofdm_scrambler_seed + * value + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_fwol_get_ofdm_scrambler_seed(struct wlan_objmgr_psoc *psoc, + bool *enable_ofdm_scrambler_seed); +#else +static inline QDF_STATUS ucfg_fwol_get_ofdm_scrambler_seed( + struct wlan_objmgr_psoc *psoc, + bool *enable_ofdm_scrambler_seed) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * ucfg_fwol_get_enable_secondary_rate() - Get enable secondary rate + * @psoc: pointer to the psoc object + * @enable_secondary_rate: Pointer to return enable secondary rate value + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_enable_secondary_rate(struct wlan_objmgr_psoc *psoc, + uint32_t *enable_secondary_rate); +/** + * ucfg_fwol_get_all_adaptive_dwelltime_params() - Get all adaptive + * dwelltime_params + * @psoc: Pointer to psoc object + * @dwelltime_params: Pointer to struct adaptive_dwelltime_params + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_all_adaptive_dwelltime_params( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params); +/** + * ucfg_fwol_get_adaptive_dwell_mode_enabled() - API to globally disable/enable + * the adaptive dwell config. + * Acceptable values for this: + * 0: Config is disabled + * 1: Config is enabled + * + * @psoc: pointer to psoc object + * @adaptive_dwell_mode_enabled: adaptive dwell mode enable/disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_adaptive_dwell_mode_enabled(struct wlan_objmgr_psoc *psoc, + bool *adaptive_dwell_mode_enabled); + +/** + * ucfg_fwol_get_global_adapt_dwelltime_mode() - API to set default + * adaptive mode. + * It will be used if any of the scan dwell mode is set to default. + * For uses : see enum scan_dwelltime_adaptive_mode + * + * @psoc: pointer to psoc object + * @global_adapt_dwelltime_mode: global adaptive dwell mode value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_global_adapt_dwelltime_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *global_adapt_dwelltime_mode); +/** + * ucfg_fwol_get_adapt_dwell_lpf_weight() - API to get weight to calculate + * the average low pass filter for channel congestion + * @psoc: pointer to psoc object + * @adapt_dwell_lpf_weight: adaptive low pass filter weight + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_adapt_dwell_lpf_weight(struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_lpf_weight); + +/** + * ucfg_fwol_get_adapt_dwell_passive_mon_intval() - API to get interval value + * for montitoring wifi activity in passive scan in msec. + * @psoc: pointer to psoc object + * @adapt_dwell_passive_mon_intval: adaptive monitor interval in passive scan + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_fwol_get_adapt_dwell_passive_mon_intval( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_passive_mon_intval); + +/** + * ucfg_fwol_get_adapt_dwell_wifi_act_threshold - API to get % of wifi activity + * used in passive scan + * @psoc: pointer to psoc object + * @adapt_dwell_wifi_act_threshold: percent of wifi activity in passive scan + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_get_adapt_dwell_wifi_act_threshold( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_wifi_act_threshold); + +/** + * ucfg_fwol_init_adapt_dwelltime_in_cfg - API to initialize adaptive + * dwell params + * @psoc: pointer to psoc object + * @dwelltime_params: pointer to adaptive_dwelltime_params structure + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_fwol_init_adapt_dwelltime_in_cfg( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + return fwol_init_adapt_dwelltime_in_cfg(psoc, dwelltime_params); +} + +/** + * ucfg_fwol_set_adaptive_dwelltime_config - API to set adaptive + * dwell params config + * @dwelltime_params: adaptive_dwelltime_params structure + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_fwol_set_adaptive_dwelltime_config( + struct adaptive_dwelltime_params *dwelltime_params) +{ + return fwol_set_adaptive_dwelltime_config(dwelltime_params); +} + +#ifdef WLAN_FEATURE_ELNA +/** + * ucfg_fwol_set_elna_bypass() - send set eLNA bypass request + * @vdev: vdev handle + * @req: set eLNA bypass request + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct set_elna_bypass_request *req); + +/** + * ucfg_fwol_get_elna_bypass() - send get eLNA bypass request + * @vdev: vdev handle + * @req: get eLNA bypass request + * @callback: get eLNA bypass response callback + * @context: request manager context + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct get_elna_bypass_request *req, + void (*callback)(void *context, + struct get_elna_bypass_response *response), + void *context); +#endif /* WLAN_FEATURE_ELNA */ + +#ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW +/** + * ucfg_fwol_send_dscp_up_map_to_fw() - send dscp_up map to FW + * @vdev: vdev handle + * @dscp_to_up_map: DSCP to UP map array + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_fwol_send_dscp_up_map_to_fw( + struct wlan_objmgr_vdev *vdev, + uint32_t *dscp_to_up_map); +#else +static inline +QDF_STATUS ucfg_fwol_send_dscp_up_map_to_fw( + struct wlan_objmgr_vdev *vdev, + uint32_t *dscp_to_up_map) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD +/** + * ucfg_fwol_set_mdns_config() - set mdns config + * @psoc: pointer to psoc object + * @mdns_info: mdns config info pointer + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_fwol_set_mdns_config(struct wlan_objmgr_psoc *psoc, + struct mdns_config_info *mdns_info); +#endif /* WLAN_FEATURE_MDNS_OFFLOAD */ + +/** + * ucfg_fwol_update_fw_cap_info - API to update fwol capability info + * @psoc: pointer to psoc object + * @caps: pointer to wlan_fwol_capability_info struct + * + * Used to update fwol capability info. + * + * Return: void + */ +void ucfg_fwol_update_fw_cap_info(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_capability_info *caps); + +#ifdef THERMAL_STATS_SUPPORT +QDF_STATUS ucfg_fwol_send_get_thermal_stats_cmd(struct wlan_objmgr_psoc *psoc, + enum thermal_stats_request_type req_type, + void (*callback)(void *context, + struct thermal_throttle_info *response), + void *context); +#endif /* THERMAL_STATS_SUPPORT */ + +/** + * ucfg_fwol_configure_global_params - API to configure global params + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Used to configure global firmware params. This is invoked from hdd during + * bootup. + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_configure_global_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_fwol_set_ilp_config - API to configure Interface Low Power (ILP) + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * @enable: enable + * + * This API is used to enable/disable Interface Low Power (IPL) feature. + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_set_ilp_config(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint32_t enable); + +/** + * ucfg_fwol_configure_vdev_params - API to configure vdev specific params + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * + * Used to configure per vdev firmware params based on device mode. This is + * invoked from hdd during vdev creation. + * + * Return: QDF Status + */ +QDF_STATUS ucfg_fwol_configure_vdev_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS ucfg_fwol_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_fwol_psoc_close(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS ucfg_fwol_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_fwol_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS ucfg_fwol_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_fwol_deinit(void) +{ +} + +static inline QDF_STATUS ucfg_fwol_thermal_register_callbacks( + struct wlan_objmgr_psoc *psoc, + struct fwol_thermal_callbacks *cb) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_fwol_thermal_unregister_callbacks( + struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_fwol_thermal_get_target_level(struct wlan_objmgr_psoc *psoc, + enum thermal_throttle_level *level) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_coex_config_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_thermal_temp(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_temp) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_is_neighbor_report_req_supported(struct wlan_objmgr_psoc *psoc, + bool *neighbor_report_req) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_ie_allowlist(struct wlan_objmgr_psoc *psoc, bool *ie_allowlist) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_set_ie_allowlist(struct wlan_objmgr_psoc *psoc, bool ie_allowlist) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_all_allowlist_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_allowlist *allowlist) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_ani_enabled(struct wlan_objmgr_psoc *psoc, + bool *ani_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_pcie_config(struct wlan_objmgr_psoc *psoc, + uint8_t *pcie_config) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_enable_rts_sifsbursting(struct wlan_objmgr_psoc *psoc, + bool *enable_rts_sifsbursting) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_max_mpdus_inampdu(struct wlan_objmgr_psoc *psoc, + uint8_t *max_mpdus_inampdu) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_enable_phy_reg_retention(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_phy_reg_retention) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_upper_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *upper_brssi_thresh) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_lower_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *lower_brssi_thresh) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_enable_dtim_1chrx(struct wlan_objmgr_psoc *psoc, + bool *enable_dtim_1chrx) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_alternative_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *alternative_chainmask_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_get_smart_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *smart_chainmask_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_rts_profile(struct wlan_objmgr_psoc *psoc, + uint16_t *get_rts_profile) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_fw_log_level(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_level) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_fw_log_type(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_type) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_fw_module_log_level( + struct wlan_objmgr_psoc *psoc, + uint8_t **enable_fw_module_log_level, + uint8_t *enable_fw_module_log_level_num) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_sap_xlna_bypass(struct wlan_objmgr_psoc *psoc, + uint8_t *sap_xlna_bypass) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_gpio_pin) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_ptp_options) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool ucfg_fwol_get_gcmp_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_tx_sch_delay(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_tx_sch_delay) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_enable_secondary_rate(struct wlan_objmgr_psoc *psoc, + uint32_t *enable_secondary_rate) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_all_adaptive_dwelltime_params( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adaptive_dwell_mode_enabled(struct wlan_objmgr_psoc *psoc, + bool *adaptive_dwell_mode_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_global_adapt_dwelltime_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *global_adapt_dwelltime_mode) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adapt_dwell_lpf_weight(struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_lpf_weight) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adapt_dwell_passive_mon_intval( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_passive_mon_intval) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_adapt_dwell_wifi_act_threshold( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_wifi_act_threshold) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_init_adapt_dwelltime_in_cfg( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_set_adaptive_dwelltime_config( + struct adaptive_dwelltime_params *dwelltime_params) +{ + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_RA_FILTERING +static inline QDF_STATUS +ucfg_fwol_set_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool is_rate_limit_enabled) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_get_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool *is_rate_limit_enabled) +{ + return QDF_STATUS_E_FAILURE; +} +#endif /* FEATURE_WLAN_RA_FILTERING */ + +static inline QDF_STATUS +ucfg_fwol_configure_global_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_fwol_configure_vdev_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_FAILURE; +} + +#endif /* WLAN_FW_OFFLOAD */ + +#endif /* _WLAN_FWOL_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c new file mode 100644 index 0000000000..e5f64a6930 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains fw offload south bound interface definitions + */ + +#include "scheduler_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_fwol_public_structs.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_fwol_tgt_api.h" +#include "wlan_fw_offload_main.h" +#include "target_if.h" + +QDF_STATUS tgt_fwol_register_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!psoc) { + fwol_err("NULL psoc handle"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->reg_evt_handler) { + status = tx_ops->reg_evt_handler(psoc, NULL); + fwol_debug("reg_evt_handler, status:%d", status); + } else { + fwol_alert("No reg_evt_handler"); + } + + return status; +} + +QDF_STATUS tgt_fwol_unregister_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!psoc) { + fwol_err("NNULL psoc handle"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->unreg_evt_handler) { + status = tx_ops->unreg_evt_handler(psoc, NULL); + fwol_debug("unreg_evt_handler, status:%d", status); + } else { + fwol_alert("No unreg_evt_handler"); + } + + return status; +} + +/** + * fwol_flush_callback() - fw offload message flush callback + * @msg: fw offload message + * + * Return: QDF_STATUS_SUCCESS on success. + */ +__attribute__((unused)) +static QDF_STATUS fwol_flush_callback(struct scheduler_msg *msg) +{ + struct wlan_fwol_rx_event *event; + + if (!msg) { + fwol_err("NULL pointer for eLNA message"); + return QDF_STATUS_E_INVAL; + } + + event = msg->bodyptr; + msg->bodyptr = NULL; + fwol_release_rx_event(event); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ELNA +/** + * tgt_fwol_get_elna_bypass_resp() - handler for get eLNA bypass response + * @psoc: psoc handle + * @resp: status for last channel config + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +tgt_fwol_get_elna_bypass_resp(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_response *resp) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct wlan_fwol_rx_event *event; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FWOL_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("Failed to get psoc ref"); + fwol_release_rx_event(event); + return status; + } + + event->psoc = psoc; + event->event_id = WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE; + event->get_elna_bypass_response = *resp; + msg.type = WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE; + msg.bodyptr = event; + msg.callback = fwol_process_event; + msg.flush_callback = fwol_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_FWOL, + QDF_MODULE_ID_FWOL, + QDF_MODULE_ID_TARGET_IF, &msg); + + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + fwol_err("failed to send WLAN_FWOL_GET_ELNA_BYPASS_RESPONSE msg"); + fwol_flush_callback(&msg); + + return status; +} + +static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ + rx_ops->get_elna_bypass_resp = tgt_fwol_get_elna_bypass_resp; +} +#else +static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ +} +#endif /* WLAN_FEATURE_ELNA */ + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +/** + * notify_thermal_throttle_handler() - Thermal throttle stats event handler + * @psoc: psoc object + * @info: thermal throttle stats info from target if layer + * + * The handle will be registered to target if layer. Target if layer + * will notify the new level from firmware thermal stats event. + * + * Return: QDF_STATUS_SUCCESS for success + */ +static QDF_STATUS +notify_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct fwol_thermal_callbacks *thermal_cbs; + + if (!psoc) { + fwol_err("NULL psoc handle"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + thermal_cbs = &fwol_obj->thermal_cbs; + fwol_nofl_debug("thermal evt: pdev %d lvl %d", + info->pdev_id, info->level); + if (info->pdev_id <= fwol_obj->thermal_throttle.pdev_id || + fwol_obj->thermal_throttle.pdev_id == WLAN_INVALID_PDEV_ID) { + fwol_obj->thermal_throttle.level = info->level; + fwol_obj->thermal_throttle.pdev_id = info->pdev_id; + if (thermal_cbs->notify_thermal_throttle_handler) + status = + thermal_cbs->notify_thermal_throttle_handler(psoc, + info); + else + fwol_debug("no thermal throttle handler"); + } + + return status; +} +#endif + +#ifdef THERMAL_STATS_SUPPORT +static QDF_STATUS +tgt_fwol_get_thermal_stats_resp(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *resp) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct wlan_fwol_rx_event *event; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FWOL_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("Failed to get psoc ref"); + fwol_release_rx_event(event); + return status; + } + + event->psoc = psoc; + event->event_id = WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE; + event->get_thermal_stats_response = *resp; + msg.type = WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE; + msg.bodyptr = event; + msg.callback = fwol_process_event; + msg.flush_callback = fwol_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_FWOL, + QDF_MODULE_ID_FWOL, + QDF_MODULE_ID_TARGET_IF, &msg); + + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + fwol_err("failed to send WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE msg"); + fwol_flush_callback(&msg); + + return status; + +} +#endif + +#ifdef THERMAL_STATS_SUPPORT +static void +tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops *rx_ops) +{ + rx_ops->get_thermal_stats_resp = tgt_fwol_get_thermal_stats_resp; +} +#else +static void +tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops *rx_ops) +{ +} +#endif +#ifdef FW_THERMAL_THROTTLE_SUPPORT +static void +tgt_fwol_register_notify_thermal_throttle_evt(struct wlan_fwol_rx_ops *rx_ops) +{ + rx_ops->notify_thermal_throttle_handler = + notify_thermal_throttle_handler; +} +#else +static void +tgt_fwol_register_notify_thermal_throttle_evt(struct wlan_fwol_rx_ops *rx_ops) +{ +} +#endif + +static void tgt_fwol_register_thermal_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ + tgt_fwol_register_notify_thermal_throttle_evt(rx_ops); + tgt_fwol_register_thermal_stats_resp(rx_ops); +} + +QDF_STATUS tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops *rx_ops) +{ + tgt_fwol_register_elna_rx_ops(rx_ops); + tgt_fwol_register_thermal_rx_ops(rx_ops); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_fwol_pdev_param_send(struct wlan_objmgr_pdev *pdev, + struct pdev_params pdev_param) +{ + struct wmi_unified *wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); + + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_pdev_param_send(wmi_handle, &pdev_param, + FWOL_WILDCARD_PDEV_ID); +} + +QDF_STATUS tgt_fwol_vdev_param_send(struct wlan_objmgr_psoc *psoc, + struct vdev_set_params vdev_param) +{ + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_vdev_set_param_send(wmi_handle, &vdev_param); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c new file mode 100644 index 0000000000..ec63809d01 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c @@ -0,0 +1,1276 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define internal APIs related to the fwol component + */ + +#include "wlan_fw_offload_main.h" +#include "wlan_fwol_public_structs.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_fwol_tgt_api.h" +#include "target_if_fwol.h" +#include "wlan_objmgr_vdev_obj.h" + +QDF_STATUS ucfg_fwol_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = fwol_cfg_on_psoc_enable(psoc); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("Failed to initialize FWOL CFG"); + + return status; +} + +void ucfg_fwol_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + /* Clear the FWOL CFG Structure */ +} + +QDF_STATUS ucfg_fwol_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + tgt_fwol_register_ev_handler(psoc); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_fwol_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + tgt_fwol_unregister_ev_handler(psoc); +} + +/** + * fwol_psoc_object_created_notification(): fwol psoc create handler + * @psoc: psoc which is going to created by objmgr + * @arg: argument for vdev create handler + * + * Register this api with objmgr to detect psoc is created + * + * Return QDF_STATUS status in case of success else return error + */ +static QDF_STATUS +fwol_psoc_object_created_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + QDF_STATUS status; + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = qdf_mem_malloc(sizeof(*fwol_obj)); + if (!fwol_obj) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_FWOL, + fwol_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("Failed to attach psoc_ctx with psoc"); + qdf_mem_free(fwol_obj); + return status; + } + + tgt_fwol_register_rx_ops(&fwol_obj->rx_ops); + target_if_fwol_register_tx_ops(&fwol_obj->tx_ops); + + return status; +} + +/** + * fwol_psoc_object_destroyed_notification(): fwol psoc delete handler + * @psoc: psoc which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * Register this api with objmgr to detect psoc is deleted + * + * Return QDF_STATUS status in case of success else return error + */ +static QDF_STATUS fwol_psoc_object_destroyed_notification( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + QDF_STATUS status; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_FWOL, + fwol_obj); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("Failed to detach psoc_ctx from psoc"); + return status; + } + + qdf_mem_free(fwol_obj); + + return status; +} + +QDF_STATUS ucfg_fwol_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_FWOL, + fwol_psoc_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("unable to register psoc create handle"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_FWOL, + fwol_psoc_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + fwol_err("unable to register psoc create handle"); + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_FWOL, + fwol_psoc_object_created_notification, + NULL); + } + + return status; +} + +void ucfg_fwol_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_FWOL, + fwol_psoc_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("unable to unregister psoc destroy handle"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_FWOL, + fwol_psoc_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + fwol_err("unable to unregister psoc create handle"); +} + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +QDF_STATUS ucfg_fwol_thermal_register_callbacks( + struct wlan_objmgr_psoc *psoc, + struct fwol_thermal_callbacks *cb) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + fwol_obj->thermal_cbs = *cb; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_thermal_unregister_callbacks( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&fwol_obj->thermal_cbs, sizeof(fwol_obj->thermal_cbs)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_thermal_get_target_level(struct wlan_objmgr_psoc *psoc, + enum thermal_throttle_level *level) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + *level = fwol_obj->thermal_throttle.level; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +ucfg_fwol_get_coex_config_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_coex_config *coex_config) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + *coex_config = fwol_obj->cfg.coex_config; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_get_thermal_temp(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_thermal_temp *thermal_info) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + *thermal_info = fwol_obj->cfg.thermal_temp_cfg; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_is_neighbor_report_req_supported(struct wlan_objmgr_psoc *psoc, + bool *neighbor_report_req) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + *neighbor_report_req = + !!(cfg_get(psoc, + CFG_OFFLOAD_11K_ENABLE_BITMASK) & + OFFLOAD_11K_BITMASK_NEIGHBOR_REPORT_REQUEST); + return QDF_STATUS_E_FAILURE; + } + + *neighbor_report_req = + !!(fwol_obj->cfg.neighbor_report_cfg.enable_bitmask & + OFFLOAD_11K_BITMASK_NEIGHBOR_REPORT_REQUEST); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_get_ie_allowlist(struct wlan_objmgr_psoc *psoc, bool *ie_allowlist) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + *ie_allowlist = fwol_obj->cfg.ie_allowlist_cfg.ie_allowlist; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_set_ie_allowlist(struct wlan_objmgr_psoc *psoc, bool ie_allowlist) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + fwol_obj->cfg.ie_allowlist_cfg.ie_allowlist = ie_allowlist; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_ani_enabled(struct wlan_objmgr_psoc *psoc, + bool *ani_enabled) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *ani_enabled = fwol_obj->cfg.ani_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_pcie_config(struct wlan_objmgr_psoc *psoc, + uint8_t *pcie_config) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *pcie_config = fwol_obj->cfg.pcie_config; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ucfg_fwol_get_ilp_config(struct wlan_objmgr_psoc *psoc, + uint32_t *enable_ilp) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_ilp = fwol_obj->cfg.enable_ilp; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ucfg_fwol_get_sap_sho(struct wlan_objmgr_psoc *psoc, + uint32_t *sap_sho) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *sap_sho = fwol_obj->cfg.sap_sho; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ucfg_fwol_get_hw_assist_config(struct wlan_objmgr_psoc *psoc, + bool *disable_hw_assist) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *disable_hw_assist = fwol_obj->cfg.disable_hw_assist; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_enable_rts_sifsbursting(struct wlan_objmgr_psoc *psoc, + bool *enable_rts_sifsbursting) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_rts_sifsbursting = fwol_obj->cfg.enable_rts_sifsbursting; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_enable_sifs_burst(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_sifs_burst) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_sifs_burst = fwol_obj->cfg.enable_sifs_burst; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_max_mpdus_inampdu(struct wlan_objmgr_psoc *psoc, + uint8_t *max_mpdus_inampdu) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *max_mpdus_inampdu = fwol_obj->cfg.max_mpdus_inampdu; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_enable_phy_reg_retention(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_phy_reg_retention) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_phy_reg_retention = fwol_obj->cfg.enable_phy_reg_retention; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_get_all_allowlist_params(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_ie_allowlist *allowlist) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + *allowlist = fwol_obj->cfg.ie_allowlist_cfg; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_upper_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *upper_brssi_thresh) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *upper_brssi_thresh = fwol_obj->cfg.upper_brssi_thresh; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_lower_brssi_thresh(struct wlan_objmgr_psoc *psoc, + uint16_t *lower_brssi_thresh) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *lower_brssi_thresh = fwol_obj->cfg.lower_brssi_thresh; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_enable_dtim_1chrx(struct wlan_objmgr_psoc *psoc, + bool *enable_dtim_1chrx) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_dtim_1chrx = fwol_obj->cfg.enable_dtim_1chrx; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_get_alternative_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *alternative_chainmask_enabled) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + *alternative_chainmask_enabled = + fwol_obj->cfg.alternative_chainmask_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_get_smart_chainmask_enabled(struct wlan_objmgr_psoc *psoc, + bool *smart_chainmask_enabled) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *smart_chainmask_enabled = + fwol_obj->cfg.smart_chainmask_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_rts_profile(struct wlan_objmgr_psoc *psoc, + uint16_t *get_rts_profile) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *get_rts_profile = fwol_obj->cfg.get_rts_profile; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_enable_fw_log_level(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_level) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_fw_log_level = fwol_obj->cfg.enable_fw_log_level; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_enable_fw_log_type(struct wlan_objmgr_psoc *psoc, + uint16_t *enable_fw_log_type) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_fw_log_type = fwol_obj->cfg.enable_fw_log_type; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_enable_fw_module_log_level( + struct wlan_objmgr_psoc *psoc, + uint8_t **enable_fw_module_log_level, + uint8_t *enable_fw_module_log_level_num) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_fw_module_log_level = fwol_obj->cfg.enable_fw_module_log_level; + *enable_fw_module_log_level_num = + fwol_obj->cfg.enable_fw_module_log_level_num; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_wow_get_enable_fw_module_log_level( + struct wlan_objmgr_psoc *psoc, + uint8_t **enable_fw_wow_module_log_level, + uint8_t *enable_fw_wow_module_log_level_num) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_fw_wow_module_log_level = + fwol_obj->cfg.enable_fw_mod_wow_log_level; + *enable_fw_wow_module_log_level_num = + fwol_obj->cfg.enable_fw_mod_wow_log_level_num; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_sap_xlna_bypass(struct wlan_objmgr_psoc *psoc, + bool *sap_xlna_bypass) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *sap_xlna_bypass = fwol_obj->cfg.sap_xlna_bypass; + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_RA_FILTERING +QDF_STATUS ucfg_fwol_set_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool is_rate_limit_enabled) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + fwol_obj->cfg.is_rate_limit_enabled = is_rate_limit_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_is_rate_limit_enabled(struct wlan_objmgr_psoc *psoc, + bool *is_rate_limit_enabled) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *is_rate_limit_enabled = fwol_obj->cfg.is_rate_limit_enabled; + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_TSF +QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_gpio_pin) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *tsf_gpio_pin = cfg_default(CFG_SET_TSF_GPIO_PIN); + return QDF_STATUS_E_FAILURE; + } + + *tsf_gpio_pin = fwol_obj->cfg.tsf_gpio_pin; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_TSF_PLUS +QDF_STATUS ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_ptp_options) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *tsf_ptp_options = cfg_default(CFG_SET_TSF_PTP_OPT); + return QDF_STATUS_E_FAILURE; + } + + *tsf_ptp_options = fwol_obj->cfg.tsf_ptp_options; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_tsf_sync_enable(struct wlan_objmgr_psoc *psoc, + bool *tsf_sync_enable) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *tsf_sync_enable = cfg_default(CFG_TSF_SYNC_ENABLE); + return QDF_STATUS_E_FAILURE; + } + + *tsf_sync_enable = fwol_obj->cfg.tsf_sync_enable; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_TSF_ACCURACY +QDF_STATUS ucfg_fwol_get_tsf_accuracy_configs(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_tsf_accuracy_configs **config) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *config = &fwol_obj->cfg.tsf_accuracy_configs; + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ +QDF_STATUS +ucfg_fwol_get_tsf_irq_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_irq_host_gpio_pin) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *tsf_irq_host_gpio_pin = + cfg_default(CFG_SET_TSF_IRQ_HOST_GPIO_PIN); + return QDF_STATUS_E_FAILURE; + } + + *tsf_irq_host_gpio_pin = fwol_obj->cfg.tsf_irq_host_gpio_pin; + return QDF_STATUS_SUCCESS; +} + +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +QDF_STATUS +ucfg_fwol_get_tsf_sync_host_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_sync_host_gpio_pin) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *tsf_sync_host_gpio_pin = + cfg_default(CFG_SET_TSF_SYNC_HOST_GPIO_PIN); + return QDF_STATUS_E_FAILURE; + } + + *tsf_sync_host_gpio_pin = fwol_obj->cfg.tsf_sync_host_gpio_pin; + return QDF_STATUS_SUCCESS; +} + +#endif +#endif +#else +QDF_STATUS ucfg_fwol_get_tsf_gpio_pin(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_gpio_pin) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_tsf_ptp_options(struct wlan_objmgr_psoc *psoc, + uint32_t *tsf_ptp_options) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +#endif + +#ifdef WLAN_FEATURE_SAE +bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc) +{ + return cfg_get(psoc, CFG_IS_SAE_ENABLED); +} + +#else +bool ucfg_fwol_get_sae_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +bool ucfg_fwol_get_gcmp_enable(struct wlan_objmgr_psoc *psoc) +{ + return cfg_get(psoc, CFG_ENABLE_GCMP); +} + +QDF_STATUS ucfg_fwol_get_enable_tx_sch_delay(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_tx_sch_delay) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *enable_tx_sch_delay = cfg_default(CFG_TX_SCH_DELAY); + return QDF_STATUS_E_FAILURE; + } + + *enable_tx_sch_delay = fwol_obj->cfg.enable_tx_sch_delay; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_OFDM_SCRAMBLER_SEED +QDF_STATUS ucfg_fwol_get_ofdm_scrambler_seed(struct wlan_objmgr_psoc *psoc, + bool *enable_ofdm_scrambler_seed) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + *enable_ofdm_scrambler_seed = + cfg_default(CFG_ENABLE_OFDM_SCRAMBLER_SEED); + return QDF_STATUS_E_FAILURE; + } + + *enable_ofdm_scrambler_seed = + fwol_obj->cfg.enable_ofdm_scrambler_seed; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS ucfg_fwol_get_enable_secondary_rate(struct wlan_objmgr_psoc *psoc, + uint32_t *enable_secondary_rate) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + *enable_secondary_rate = cfg_default(CFG_ENABLE_SECONDARY_RATE); + return QDF_STATUS_E_FAILURE; + } + + *enable_secondary_rate = fwol_obj->cfg.enable_secondary_rate; + return QDF_STATUS_SUCCESS; +} + +#ifdef DHCP_SERVER_OFFLOAD +QDF_STATUS +ucfg_fwol_get_enable_dhcp_server_offload(struct wlan_objmgr_psoc *psoc, + bool *enable_dhcp_server_offload) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *enable_dhcp_server_offload = fwol_obj->cfg.enable_dhcp_server_offload; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_dhcp_max_num_clients(struct wlan_objmgr_psoc *psoc, + uint32_t *dhcp_max_num_clients) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *dhcp_max_num_clients = fwol_obj->cfg.dhcp_max_num_clients; + return QDF_STATUS_SUCCESS; +} + +#endif + +QDF_STATUS +ucfg_fwol_get_all_adaptive_dwelltime_params( + struct wlan_objmgr_psoc *psoc, + struct adaptive_dwelltime_params *dwelltime_params) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + *dwelltime_params = fwol_obj->cfg.dwelltime_params; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_get_adaptive_dwell_mode_enabled( + struct wlan_objmgr_psoc *psoc, + bool *adaptive_dwell_mode_enabled) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *adaptive_dwell_mode_enabled = + fwol_obj->cfg.dwelltime_params.is_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_get_global_adapt_dwelltime_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *global_adapt_dwelltime_mode) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *global_adapt_dwelltime_mode = + fwol_obj->cfg.dwelltime_params.dwelltime_mode; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_fwol_get_adapt_dwell_lpf_weight(struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_lpf_weight) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *adapt_dwell_lpf_weight = fwol_obj->cfg.dwelltime_params.lpf_weight; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_adapt_dwell_passive_mon_intval( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_passive_mon_intval) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *adapt_dwell_passive_mon_intval = + fwol_obj->cfg.dwelltime_params.passive_mon_intval; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_get_adapt_dwell_wifi_act_threshold( + struct wlan_objmgr_psoc *psoc, + uint8_t *adapt_dwell_wifi_act_threshold) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL obj"); + return QDF_STATUS_E_FAILURE; + } + + *adapt_dwell_wifi_act_threshold = + fwol_obj->cfg.dwelltime_params.wifi_act_threshold; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ELNA +QDF_STATUS ucfg_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct set_elna_bypass_request *req) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + fwol_err("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->set_elna_bypass) + status = tx_ops->set_elna_bypass(psoc, req); + else + status = QDF_STATUS_E_IO; + + return status; +} + +QDF_STATUS ucfg_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct get_elna_bypass_request *req, + void (*callback)(void *context, + struct get_elna_bypass_response *response), + void *context) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + struct wlan_fwol_callbacks *cbs; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + fwol_err("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + cbs = &fwol_obj->cbs; + cbs->get_elna_bypass_callback = callback; + cbs->get_elna_bypass_context = context; + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->get_elna_bypass) + status = tx_ops->get_elna_bypass(psoc, req); + else + status = QDF_STATUS_E_IO; + + return status; +} +#endif /* WLAN_FEATURE_ELNA */ + +#ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW +QDF_STATUS ucfg_fwol_send_dscp_up_map_to_fw(struct wlan_objmgr_vdev *vdev, + uint32_t *dscp_to_up_map) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + fwol_err("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops && tx_ops->send_dscp_up_map_to_fw) + status = tx_ops->send_dscp_up_map_to_fw(psoc, dscp_to_up_map); + else + status = QDF_STATUS_E_IO; + + return status; +} +#endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */ + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD +QDF_STATUS ucfg_fwol_set_mdns_config(struct wlan_objmgr_psoc *psoc, + struct mdns_config_info *mdns_info) +{ + QDF_STATUS status; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + + if (!psoc) { + fwol_err("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops->set_mdns_config) + status = tx_ops->set_mdns_config(psoc, mdns_info); + else + status = QDF_STATUS_E_IO; + + return status; +} +#endif /* WLAN_FEATURE_MDNS_OFFLOAD */ + +void ucfg_fwol_update_fw_cap_info(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_capability_info *caps) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return; + } + + qdf_mem_copy(&fwol_obj->capability_info, caps, + sizeof(fwol_obj->capability_info)); +} + +#ifdef THERMAL_STATS_SUPPORT +static QDF_STATUS +ucfg_fwol_get_cap(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_capability_info *cap_info) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + + if (!cap_info) { + fwol_err("Failed to get fwol obj"); + return QDF_STATUS_E_FAILURE; + } + *cap_info = fwol_obj->capability_info; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_fwol_send_get_thermal_stats_cmd(struct wlan_objmgr_psoc *psoc, + enum thermal_stats_request_type req_type, + void (*callback)(void *context, + struct thermal_throttle_info *response), + void *context) +{ + QDF_STATUS status; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_tx_ops *tx_ops; + struct wlan_fwol_thermal_temp thermal_temp = {0}; + struct wlan_fwol_capability_info cap_info; + struct wlan_fwol_callbacks *cbs; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + fwol_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + status = ucfg_fwol_get_thermal_temp(psoc, &thermal_temp); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + status = ucfg_fwol_get_cap(psoc, &cap_info); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (!thermal_temp.therm_stats_offset || + !cap_info.fw_thermal_stats_cap) { + fwol_err("Command Disabled in Ini gThermalStatsTempOffset %d or not enabled in FW %d", + thermal_temp.therm_stats_offset, + cap_info.fw_thermal_stats_cap); + return QDF_STATUS_E_INVAL; + } + + /* Registering Callback for the Request command */ + if (callback && context) { + cbs = &fwol_obj->cbs; + cbs->get_thermal_stats_callback = callback; + cbs->get_thermal_stats_context = context; + } + + tx_ops = &fwol_obj->tx_ops; + if (tx_ops && tx_ops->get_thermal_stats) + status = tx_ops->get_thermal_stats(psoc, req_type, + thermal_temp.therm_stats_offset); + else + status = QDF_STATUS_E_INVAL; + + return status; +} +#endif /* THERMAL_STATS_SUPPORT */ + +QDF_STATUS ucfg_fwol_configure_global_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + QDF_STATUS status; + uint32_t enable_ilp; + bool value; + + /* Configure ILP feature in FW */ + status = ucfg_fwol_get_ilp_config(psoc, &enable_ilp); + if (QDF_IS_STATUS_ERROR(status)) + return status; + status = fwol_set_ilp_config(pdev, enable_ilp); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* Configure HW assist feature in FW */ + status = ucfg_fwol_get_hw_assist_config(psoc, &value); + if (QDF_IS_STATUS_ERROR(status)) + return status; + status = fwol_configure_hw_assist(pdev, value); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return status; +} + +QDF_STATUS ucfg_fwol_set_ilp_config(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint32_t enable_ilp) +{ + return fwol_set_ilp_config(pdev, enable_ilp); +} + +QDF_STATUS ucfg_fwol_configure_vdev_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint32_t value; + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + switch (wlan_vdev_mlme_get_opmode(vdev)) { + case QDF_SAP_MODE: + status = ucfg_fwol_get_sap_sho(psoc, &value); + if (QDF_IS_STATUS_ERROR(status)) + break; + + status = fwol_set_sap_sho(psoc, vdev_id, value); + if (QDF_IS_STATUS_ERROR(status)) + break; + + status = fwol_set_sap_wds_config(psoc, vdev_id); + break; + default: + status = QDF_STATUS_SUCCESS; + break; + } + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/core/inc/wlan_interop_issues_ap_api.h b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/core/inc/wlan_interop_issues_ap_api.h new file mode 100644 index 0000000000..819b975759 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/core/inc/wlan_interop_issues_ap_api.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_interop_issues_ap_api.h + * + * This header file provide API declarations required for interop issues + * ap global context specific to offload + */ + +#ifndef __WLAN_INTEROP_ISSUES_AP_API_H__ +#define __WLAN_INTEROP_ISSUES_AP_API_H__ + +#ifdef WLAN_FEATURE_INTEROP_ISSUES_AP +#include +#include +#include +#include +#include + +#define interop_issues_ap_debug(args ...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_INTEROP_ISSUES_AP, ## args) +#define interop_issues_ap_err(args ...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_INTEROP_ISSUES_AP, ## args) + +/** + * struct interop_issues_ap_psoc_priv_obj - psoc private object + * @lock: qdf spin lock + * @soc: pointer to psoc object + * @cbs: interop issues ap ps event callbacks + * @tx_ops: interop issues ap ps tx ops + */ +struct interop_issues_ap_psoc_priv_obj { + qdf_spinlock_t lock; + struct wlan_objmgr_psoc *soc; + struct wlan_interop_issues_ap_callbacks cbs; + struct wlan_interop_issues_ap_tx_ops tx_ops; +}; + +/** + * wlan_interop_issues_ap_psoc_enable() - interop issues ap psoc enable + * @psoc: the pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_interop_issues_ap_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_interop_issues_ap_psoc_disable() - interop issues ap psoc disable + * @psoc: the pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_interop_issues_ap_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_interop_issues_ap_init() - API to init component + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_interop_issues_ap_init(void); + +/** + * wlan_interop_issues_ap_deinit() - API to deinit component + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_interop_issues_ap_deinit(void); + +/** + * interop_issues_ap_get_psoc_priv_obj() - get priv object from psoc object + * @psoc: pointer to psoc object + * + * Return: pointer to interop issues ap psoc private object + */ +static inline +struct interop_issues_ap_psoc_priv_obj *interop_issues_ap_get_psoc_priv_obj( + struct wlan_objmgr_psoc *psoc) +{ + struct interop_issues_ap_psoc_priv_obj *obj; + + if (!psoc) + return NULL; + + obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_INTEROP_ISSUES_AP); + + return obj; +} + +/** + * interop_issues_ap_psoc_get_tx_ops() - get TX ops from the private object + * @psoc: pointer to psoc object + * + * Return: pointer to TX op callback + */ +static inline +struct wlan_interop_issues_ap_tx_ops *interop_issues_ap_psoc_get_tx_ops( + struct wlan_objmgr_psoc *psoc) +{ + struct interop_issues_ap_psoc_priv_obj *interop_issues_ap_priv; + + if (!psoc) + return NULL; + + interop_issues_ap_priv = interop_issues_ap_get_psoc_priv_obj(psoc); + if (!interop_issues_ap_priv) { + interop_issues_ap_err("psoc private object is null"); + return NULL; + } + + return &interop_issues_ap_priv->tx_ops; +} + +/** + * interop_issues_ap_psoc_get_cbs() - get RX ops from private object + * @psoc: pointer to psoc object + * + * Return: pointer to RX op callback + */ +static inline +struct wlan_interop_issues_ap_callbacks *interop_issues_ap_psoc_get_cbs( + struct wlan_objmgr_psoc *psoc) +{ + struct interop_issues_ap_psoc_priv_obj *interop_issues_ap_priv; + + if (!psoc) + return NULL; + + interop_issues_ap_priv = interop_issues_ap_get_psoc_priv_obj(psoc); + if (!interop_issues_ap_priv) { + interop_issues_ap_err("psoc private object is null"); + return NULL; + } + + return &interop_issues_ap_priv->cbs; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/core/src/wlan_interop_issues_ap_api.c b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/core/src/wlan_interop_issues_ap_api.c new file mode 100644 index 0000000000..88d08fbeb1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/core/src/wlan_interop_issues_ap_api.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_interop_issues_ap_api.c + */ +#include +#include +#include + +/** + * interop_issues_ap_psoc_obj_created_notification() - PSOC obj create callback + * @psoc: PSOC object + * @arg_list: Variable argument list + * + * This callback is registered with object manager during initialization to + * get notified when the object is created. + * + * Return: Success or Failure + */ +static QDF_STATUS +interop_issues_ap_psoc_obj_created_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct interop_issues_ap_psoc_priv_obj *interop_issues_ap_obj; + + interop_issues_ap_obj = qdf_mem_malloc(sizeof(*interop_issues_ap_obj)); + if (!interop_issues_ap_obj) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&interop_issues_ap_obj->lock); + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + interop_issues_ap_err("obj attach with psoc failed"); + goto interop_issues_ap_psoc_attach_failed; + } + + target_if_interop_issues_ap_register_tx_ops(psoc, + &interop_issues_ap_obj->tx_ops); + + return QDF_STATUS_SUCCESS; + +interop_issues_ap_psoc_attach_failed: + qdf_spinlock_destroy(&interop_issues_ap_obj->lock); + qdf_mem_free(interop_issues_ap_obj); + return status; +} + +/** + * interop_issues_ap_psoc_obj_destroyed_notification() - obj delete callback + * @psoc: PSOC object + * @arg_list: Variable argument list + * + * This callback is registered with object manager during initialization to + * get notified when the object is deleted. + * + * Return: Success or Failure + */ +static QDF_STATUS +interop_issues_ap_psoc_obj_destroyed_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct interop_issues_ap_psoc_priv_obj *interop_issues_ap_obj; + + interop_issues_ap_obj = interop_issues_ap_get_psoc_priv_obj(psoc); + + if (!interop_issues_ap_obj) { + interop_issues_ap_err("interop_issues_ap_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + target_if_interop_issues_ap_unregister_tx_ops(psoc, + &interop_issues_ap_obj->tx_ops); + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_obj); + if (QDF_IS_STATUS_ERROR(status)) + interop_issues_ap_err("interop_issues_ap_obj detach failed"); + + qdf_spinlock_destroy(&interop_issues_ap_obj->lock); + qdf_mem_free(interop_issues_ap_obj); + + return status; +} + +QDF_STATUS wlan_interop_issues_ap_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return target_if_interop_issues_ap_register_event_handler(psoc); +} + +QDF_STATUS wlan_interop_issues_ap_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return target_if_interop_issues_ap_unregister_event_handler(psoc); +} + +QDF_STATUS wlan_interop_issues_ap_init(void) +{ + QDF_STATUS status; + + /* register psoc create handler functions. */ + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + interop_issues_ap_err("register create handler failed"); + return status; + } + + /* register psoc delete handler functions. */ + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + interop_issues_ap_err("register destroy handler failed"); + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_psoc_obj_created_notification, + NULL); + } + + return status; +} + +QDF_STATUS wlan_interop_issues_ap_deinit(void) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS, status; + + /* unregister psoc delete handler functions. */ + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + interop_issues_ap_err("unregister destroy handler failed"); + ret = status; + } + + /* unregister psoc create handler functions. */ + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_INTEROP_ISSUES_AP, + interop_issues_ap_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + interop_issues_ap_err("unregister create handler failed"); + ret = status; + } + + return ret; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_public_structs.h new file mode 100644 index 0000000000..df607b330b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_public_structs.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interop issues ap structure definitions + */ + +#ifndef _WLAN_INTEROP_ISSUES_AP_STRUCTS_H_ +#define _WLAN_INTEROP_ISSUES_AP_STRUCTS_H_ + +#ifdef WLAN_FEATURE_INTEROP_ISSUES_AP +#include +#include + +#define MAX_INTEROP_ISSUES_AP_NUM 20 + +/** + * struct wlan_interop_issues_ap_info - interop issues ap info + * @detect_enable: the flag to enable detect issue ap + * @count: the number of interop issues ap + * @rap_items: interop issues ap items + */ +struct wlan_interop_issues_ap_info { + bool detect_enable; + uint32_t count; + struct qdf_mac_addr rap_items[MAX_INTEROP_ISSUES_AP_NUM]; +}; + +/** + * struct wlan_interop_issues_ap_event - interop issues ap event + * @pdev: pdev object + * @psoc: psoc object + * @pdev_id: pdev id number + * @rap_addr: interop issues ap mac address + */ +struct wlan_interop_issues_ap_event { + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + uint32_t pdev_id; + struct qdf_mac_addr rap_addr; +}; + +/** + * struct wlan_interop_issues_ap_callbacks - interop issues ap callbacks + * @os_if_interop_issues_ap_event_handler: OS IF callback for handling events + */ +struct wlan_interop_issues_ap_callbacks { + void (*os_if_interop_issues_ap_event_handler) + (struct wlan_interop_issues_ap_event *event); +}; + +/** + * struct wlan_interop_issues_ap_tx_ops - structure of tx func pointers + * @set_rap_ps: handler for TX operations for the interop issues ap ps config + */ +struct wlan_interop_issues_ap_tx_ops { + QDF_STATUS (*set_rap_ps)(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_info *rap); +}; +#endif +#endif /* _WLAN_INTEROP_ISSUES_AP_STRUCTS_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_tgt_api.h new file mode 100644 index 0000000000..fe36e968db --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_tgt_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_interop_issues_ap_tgt_api.h + * + * This header file provide with API declarations to interface with Southbound + */ +#ifndef __WLAN_INTEROP_ISSUES_AP_TGT_API_H__ +#define __WLAN_INTEROP_ISSUES_AP_TGT_API_H__ + +#ifdef WLAN_FEATURE_INTEROP_ISSUES_AP +/** + * tgt_interop_issues_ap_info_callback() - interop issues ap info callback + * @psoc: the pointer to psoc object manager + * @rap: the interop issues ap mac address + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_interop_issues_ap_info_callback(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_event *rap); + +/** + * tgt_set_interop_issues_ap_req() - API to set interop issues ap to lmac + * @psoc: the pointer to psoc object manager + * @rap: the pointer to interop issues ap info + * + * Return: status of operation + */ +QDF_STATUS +tgt_set_interop_issues_ap_req(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_info *rap); +#endif +#endif /* __WLAN_INTEROP_ISSUES_AP_TGT_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_ucfg_api.h new file mode 100644 index 0000000000..913a98cf35 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/inc/wlan_interop_issues_ap_ucfg_api.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_interop_issues_ap_ucfg_api.h + * + * This header file maintain API declaration required for northbound interaction + */ + +#ifndef __WLAN_INTEROP_ISSUES_AP_UCFG_API_H__ +#define __WLAN_INTEROP_ISSUES_AP_UCFG_API_H__ + +#ifdef WLAN_FEATURE_INTEROP_ISSUES_AP +#include +#include +#include + +/** + * ucfg_interop_issues_ap_psoc_enable() - interop issues ap component enable + * @psoc: the point to psoc object + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_interop_issues_ap_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_interop_issues_ap_psoc_disable() - interop issues ap component disable + * @psoc: the point to psoc object + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_interop_issues_ap_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_interop_issues_ap_init() - interop issues ap component initialization + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_interop_issues_ap_init(void); + +/** + * ucfg_interop_issues_ap_deinit() - interop issues ap component de-init + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_interop_issues_ap_deinit(void); + +/** + * ucfg_register_interop_issues_ap_callback() - API to register callback + * @pdev: the pointer of pdev object + * @cbs: pointer to callback structure + * + * Return: none + */ +void ucfg_register_interop_issues_ap_callback(struct wlan_objmgr_pdev *pdev, + struct wlan_interop_issues_ap_callbacks *cbs); + +/** + * ucfg_set_interop_issues_ap_config() - API to set interop issues ap + * @psoc: the pointer of psoc object + * @rap: the pointer of interop issues ap info + * + * Return: none + */ +QDF_STATUS ucfg_set_interop_issues_ap_config(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_info *rap); +#else +static inline +QDF_STATUS ucfg_interop_issues_ap_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_interop_issues_ap_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_interop_issues_ap_init(void) { return QDF_STATUS_SUCCESS; } + +static inline +QDF_STATUS ucfg_interop_issues_ap_deinit(void) { return QDF_STATUS_SUCCESS; } +#endif /* WLAN_FEATURE_INTEROP_ISSUES_AP */ +#endif /* __WLAN_RAP_PS_UCFG_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_tgt_api.c new file mode 100644 index 0000000000..e58bd4a7f7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_tgt_api.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC:wlan_interop_issues_ap_tgt_api.c + * + * This file provide API definitions to update interop issues ap from interface + */ +#include +#include +#include +#include +#include + +static QDF_STATUS wlan_interop_issues_ap_flush_cbk(struct scheduler_msg *msg) +{ + if (msg->bodyptr) { + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlan_interop_issues_ap_info_cbk(struct scheduler_msg *msg) +{ + struct wlan_interop_issues_ap_event *data; + struct wlan_interop_issues_ap_callbacks *cbs; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + data = msg->bodyptr; + data->pdev = wlan_objmgr_get_pdev_by_id(data->psoc, + data->pdev_id, + WLAN_INTEROP_ISSUES_AP_ID); + if (!data->pdev) { + interop_issues_ap_err("pdev is null."); + status = QDF_STATUS_E_FAILURE; + goto err; + } + + cbs = interop_issues_ap_psoc_get_cbs(data->psoc); + if (cbs && cbs->os_if_interop_issues_ap_event_handler) + cbs->os_if_interop_issues_ap_event_handler(msg->bodyptr); + + wlan_objmgr_pdev_release_ref(data->pdev, WLAN_INTEROP_ISSUES_AP_ID); +err: + qdf_mem_free(data); + msg->bodyptr = NULL; + return status; +} + +QDF_STATUS tgt_interop_issues_ap_info_callback(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_event *rap) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + struct wlan_interop_issues_ap_event *data; + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(data, rap, sizeof(*data)); + + msg.bodyptr = data; + msg.callback = wlan_interop_issues_ap_info_cbk; + msg.flush_callback = wlan_interop_issues_ap_flush_cbk; + + status = scheduler_post_message(QDF_MODULE_ID_INTEROP_ISSUES_AP, + QDF_MODULE_ID_INTEROP_ISSUES_AP, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + interop_issues_ap_err("scheduler msg posting failed"); + qdf_mem_free(msg.bodyptr); + msg.bodyptr = NULL; + } + + return status; +} + +QDF_STATUS tgt_set_interop_issues_ap_req(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_info *rap) +{ + struct interop_issues_ap_psoc_priv_obj *obj; + + obj = interop_issues_ap_get_psoc_priv_obj(psoc); + if (!obj || !obj->tx_ops.set_rap_ps) + return QDF_STATUS_E_NULL_VALUE; + + return obj->tx_ops.set_rap_ps(psoc, rap); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_ucfg_api.c new file mode 100644 index 0000000000..d40611e493 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_ucfg_api.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains interop issues ap north bound interface definitions + */ +#include +#include +#include +#include +#include + +QDF_STATUS +ucfg_set_interop_issues_ap_config(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_info *rap) +{ + return tgt_set_interop_issues_ap_req(psoc, rap); +} + +void ucfg_register_interop_issues_ap_callback(struct wlan_objmgr_pdev *pdev, + struct wlan_interop_issues_ap_callbacks *cb) +{ + struct wlan_objmgr_psoc *psoc; + struct interop_issues_ap_psoc_priv_obj *obj; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + interop_issues_ap_err("psoc object is NULL"); + return; + } + + obj = interop_issues_ap_get_psoc_priv_obj(psoc); + if (!obj) { + interop_issues_ap_err("interop issues ap priv obj is NULL"); + return; + } + + obj->cbs.os_if_interop_issues_ap_event_handler = + cb->os_if_interop_issues_ap_event_handler; +} + +QDF_STATUS ucfg_interop_issues_ap_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_interop_issues_ap_psoc_enable(psoc); +} + +QDF_STATUS ucfg_interop_issues_ap_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_interop_issues_ap_psoc_disable(psoc); +} + +QDF_STATUS ucfg_interop_issues_ap_init(void) +{ + return wlan_interop_issues_ap_init(); +} + +QDF_STATUS ucfg_interop_issues_ap_deinit(void) +{ + return wlan_interop_issues_ap_deinit(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_main.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_main.h new file mode 100644 index 0000000000..e84457ea31 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_main.h @@ -0,0 +1,2036 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare internal API related to the mlme component + */ + +#ifndef _WLAN_MLME_MAIN_H_ +#define _WLAN_MLME_MAIN_H_ + +#include "qdf_periodic_work.h" +#include +#include +#include +#include +#include +#include +#include "wlan_wfa_config_public_struct.h" +#include "wlan_connectivity_logging.h" + +#define MAC_MAX_ADD_IE_LENGTH 2048 +/* Join probe request Retry timer default (200)ms */ +#define JOIN_PROBE_REQ_TIMER_MS 200 +#define MAX_JOIN_PROBE_REQ 5 + +#define MAX_WAKELOCK_FOR_BSS_COLOR_CHANGE 2000 + +/* If AP reported link delete timer less than such value, + * host will do link removel directly without wait for the + * timer timeout. + */ +#define LINK_REMOVAL_MIN_TIMEOUT_MS 1000 + +/* + * Following time is used to program WOW_TIMER_PATTERN to FW so that FW will + * wake host up to do graceful disconnect in case PEER remains un-authorized + * for this long. + */ +#define INSTALL_KEY_TIMEOUT_SEC 70 +#define INSTALL_KEY_TIMEOUT_MS \ + (INSTALL_KEY_TIMEOUT_SEC * SYSTEM_TIME_SEC_TO_MSEC) +/* 70 seconds, for WPA, WPA2, CCKM */ +#define WAIT_FOR_KEY_TIMEOUT_PERIOD \ + (INSTALL_KEY_TIMEOUT_SEC * QDF_MC_TIMER_TO_SEC_UNIT) +/* 120 seconds, for WPS */ +#define WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD (120 * QDF_MC_TIMER_TO_SEC_UNIT) + +#define MLME_PEER_SET_KEY_WAKELOCK_TIMEOUT WAKELOCK_DURATION_RECOMMENDED +/* QCN IE definitions */ +#define QCN_IE_HDR_LEN 6 + +#define QCN_IE_VERSION_SUBATTR_ID 1 +#define QCN_IE_VERSION_SUBATTR_DATA_LEN 2 +#define QCN_IE_VERSION_SUBATTR_LEN 4 +#define QCN_IE_VERSION_SUPPORTED 1 +#define QCN_IE_SUBVERSION_SUPPORTED 0 + +#define QCN_IE_ATTR_ID_VERSION 1 +#define QCN_IE_ATTR_ID_VHT_MCS11 2 +#define QCN_IE_ATTR_ID_ALL 0xFF + +#define mlme_legacy_fatal(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_MLME, params) +#define mlme_legacy_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_MLME, params) +#define mlme_legacy_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_MLME, params) +#define mlme_legacy_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_MLME, params) +#define mlme_legacy_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_MLME, params) +#define MAC_B_PR_SSID_OFFSET 12 + +enum size_of_len_field { + ONE_BYTE = 1, + TWO_BYTE = 2 +}; + +enum medium_access_type { + MEDIUM_ACCESS_AUTO = 0, + MEDIUM_ACCESS_DCF, + MEDIUM_ACCESS_11E_EDCF, + MEDIUM_ACCESS_WMM_EDCF_DSCP, +}; + +enum wmm_user_mode { + WMM_USER_MODE_AUTO = 0, + WMM_USER_MODE_QBSS_ONLY = 1, + WMM_USER_MODE_NO_QOS = 2, + +}; + +/** + * struct peer_mac_addresses -Peer MAC address info + * @mac: Provided peer MAC address + * @peer_mac: Peer MAC address + * @peer_mld: Peer MLD address + */ +struct peer_mac_addresses { + struct qdf_mac_addr mac; + struct qdf_mac_addr peer_mac; + struct qdf_mac_addr peer_mld; +}; + +struct pwr_channel_info { + uint32_t first_freq; + uint8_t num_chan; + int8_t max_tx_pwr; +}; + +/** + * struct peer_disconnect_stats_param -Peer disconnect stats params + * @vdev_id: vdev_id of the SAP vdev on which disconnect stats request is sent + * @is_disconn_stats_completed: Indicates if disconnect stats request is + * completed or not + * @disconn_stats_timer: Disconnect stats timer + */ +struct peer_disconnect_stats_param { + uint8_t vdev_id; + qdf_atomic_t is_disconn_stats_completed; + qdf_mc_timer_t disconn_stats_timer; +}; + +/** + * struct wlan_mlme_rx_ops - structure of tx function pointers for + * roaming related commands + * @peer_oper_mode_eventid : Rx ops function pointer for operating mode event + */ +struct wlan_mlme_rx_ops { + QDF_STATUS (*peer_oper_mode_eventid)(struct wlan_objmgr_psoc *psoc, + struct peer_oper_mode_event *data); +}; + +/** + * struct wlan_mlme_tx_ops - structure of mlme tx function pointers + * @send_csa_event_status_ind: Tx ops function to send csa event indication + * + */ +struct wlan_mlme_tx_ops { + QDF_STATUS + (*send_csa_event_status_ind)(struct wlan_objmgr_vdev *vdev, + uint8_t csa_status); +}; + +/** + * struct wlan_mlme_psoc_ext_obj -MLME ext psoc priv object + * @cfg: cfg items + * @rso_tx_ops: Roam Tx ops to send roam offload commands to firmware + * @rso_rx_ops: Roam Rx ops to receive roam offload events from firmware + * @mlme_rx_ops: mlme Rx ops to receive events from firmware + * @mlme_tx_ops: mlme tx ops + * @wfa_testcmd: WFA config tx ops to send to FW + * @disconnect_stats_param: Peer disconnect stats related params for SAP case + * @scan_requester_id: mlme scan requester id + */ +struct wlan_mlme_psoc_ext_obj { + struct wlan_mlme_cfg cfg; + struct wlan_cm_roam_tx_ops rso_tx_ops; + struct wlan_cm_roam_rx_ops rso_rx_ops; + struct wlan_mlme_rx_ops mlme_rx_ops; + struct wlan_mlme_tx_ops mlme_tx_ops; + struct wlan_mlme_wfa_cmd wfa_testcmd; + struct peer_disconnect_stats_param disconnect_stats_param; + wlan_scan_requester scan_requester_id; +}; + +/** + * struct wlan_disconnect_info - WLAN Disconnection Information + * @self_discon_ies: Disconnect IEs to be sent in deauth/disassoc frames + * originated from driver + * @peer_discon_ies: Disconnect IEs received in deauth/disassoc frames + * from peer + */ +struct wlan_disconnect_info { + struct element_info self_discon_ies; + struct element_info peer_discon_ies; +}; + +/** + * struct sae_auth_retry - SAE auth retry Information + * @sae_auth_max_retry: Max number of sae auth retries + * @sae_auth: SAE auth frame information + */ +struct sae_auth_retry { + uint8_t sae_auth_max_retry; + struct element_info sae_auth; +}; + +/** + * struct peer_mlme_priv_obj - peer MLME component object + * @last_pn_valid: if last PN is valid + * @last_pn: last pn received + * @rmf_pn_replays: rmf pn replay count + * @is_pmf_enabled: True if PMF is enabled + * @last_assoc_received_time: last assoc received time + * @last_disassoc_deauth_received_time: last disassoc/deauth received time + * @twt_ctx: TWT context + * @allow_kickout: True if the peer can be kicked out. Peer can't be kicked + * out if it is being steered + * @nss: Peer NSS + * @peer_set_key_wakelock: wakelock to protect peer set key op with firmware + * @peer_set_key_runtime_wakelock: runtime pm wakelock for set key + * @is_key_wakelock_set: flag to check if key wakelock is pending to release + * @assoc_rsp: assoc rsp IE received during connection + * @peer_ind_bw: peer indication channel bandwidth + */ +struct peer_mlme_priv_obj { + uint8_t last_pn_valid; + uint64_t last_pn; + uint32_t rmf_pn_replays; + bool is_pmf_enabled; + qdf_time_t last_assoc_received_time; + qdf_time_t last_disassoc_deauth_received_time; +#ifdef WLAN_SUPPORT_TWT + struct twt_context twt_ctx; +#endif +#ifdef WLAN_FEATURE_SON + bool allow_kickout; +#endif + uint8_t nss; + qdf_wake_lock_t peer_set_key_wakelock; + qdf_runtime_lock_t peer_set_key_runtime_wakelock; + bool is_key_wakelock_set; + struct element_info assoc_rsp; + enum phy_ch_width peer_ind_bw; +}; + +/** + * enum vdev_assoc_type - VDEV associate/reassociate type + * @VDEV_ASSOC: associate + * @VDEV_REASSOC: reassociate + * @VDEV_FT_REASSOC: fast reassociate + */ +enum vdev_assoc_type { + VDEV_ASSOC, + VDEV_REASSOC, + VDEV_FT_REASSOC +}; + +/** + * struct wlan_mlme_roam_state_info - Structure containing roaming + * state related details + * @state: Roaming module state. + * @mlme_operations_bitmap: Bitmap containing what mlme operations are in + * progress where roaming should not be allowed. + */ +struct wlan_mlme_roam_state_info { + enum roam_offload_state state; + uint8_t mlme_operations_bitmap; +}; + +/** + * struct wlan_mlme_roaming_config - Roaming configurations structure + * @roam_trigger_bitmap: Master bitmap of roaming triggers. If the bitmap is + * zero, roaming module will be deinitialized at firmware for this vdev. + * @supplicant_disabled_roaming: Enable/disable roam scan in firmware; will be + * used by supplicant to do roam invoke after disabling roam scan in firmware, + * it is only effective for current connection, it will be cleared during new + * connection. + */ +struct wlan_mlme_roaming_config { + uint32_t roam_trigger_bitmap; + bool supplicant_disabled_roaming; +}; + +/** + * struct wlan_mlme_roam - Roam structure containing roam state and + * roam config info + * @roam_sm: Structure containing roaming state related details + * @roam_cfg: Roaming configurations structure + * @sae_single_pmk: Details for sae roaming using single pmk + * @set_pmk_pending: RSO update status of PMK from set_key + * @sae_auth_ta: SAE pre-auth tx address + * @sae_auth_pending: Roaming SAE auth pending + */ +struct wlan_mlme_roam { + struct wlan_mlme_roam_state_info roam_sm; + struct wlan_mlme_roaming_config roam_cfg; +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) + struct wlan_mlme_sae_single_pmk sae_single_pmk; +#endif + bool set_pmk_pending; + struct qdf_mac_addr sae_auth_ta; + uint8_t sae_auth_pending; +}; + +#ifdef WLAN_FEATURE_MSCS +/** + * struct tclas_mask - TCLAS Mask Elements for mscs request + * @classifier_type: specifies the type of classifier parameters + * in TCLAS element. Currently driver supports classifier type = 4 only. + * @classifier_mask: Mask for tclas elements. For example, if + * classifier type = 4, value of classifier mask is 0x5F. + * @info: information of classifier type + */ +struct tclas_mask { + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t reserved[16]; + } ip_param; /* classifier_type = 4 */ + } info; +}; + +/** + * enum scs_request_type - scs request type to peer + * @SCS_REQ_ADD: To set mscs parameters + * @SCS_REQ_REMOVE: Remove mscs parameters + * @SCS_REQ_CHANGE: Update mscs parameters + */ +enum scs_request_type { + SCS_REQ_ADD = 0, + SCS_REQ_REMOVE = 1, + SCS_REQ_CHANGE = 2, +}; + +/** + * struct descriptor_element - mscs Descriptor element + * @request_type: mscs request type defined in enum scs_request_type + * @user_priority_control: To set user priority of tx packet + * @stream_timeout: minimum timeout value, in TUs, for maintaining + * variable user priority in the MSCS list. + * @tclas_mask: to specify how incoming MSDUs are classified into + * streams in MSCS + * @status_code: status of mscs request + */ +struct descriptor_element { + uint8_t request_type; + uint16_t user_priority_control; + uint64_t stream_timeout; + struct tclas_mask tclas_mask; + uint8_t status_code; +}; + +/** + * struct mscs_req_info - mscs request information + * @vdev_id: session id + * @bssid: peer bssid + * @dialog_token: Token number of mscs req action frame + * @dec: mscs Descriptor element defines information about + * the parameters used to classify streams + * @is_mscs_req_sent: To Save mscs req request if any (only + * one can be outstanding at any time) + */ +struct mscs_req_info { + uint8_t vdev_id; + struct qdf_mac_addr bssid; + uint8_t dialog_token; + struct descriptor_element dec; + bool is_mscs_req_sent; +}; +#endif + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * enum ft_ie_state - ft state + * @FT_START_READY: Start before and after 11r assoc + * @FT_AUTH_REQ_READY: When we have recvd the 1st or nth auth req + * @FT_REASSOC_REQ_WAIT: waiting for reassoc + * @FT_SET_KEY_WAIT: waiting for key + */ +enum ft_ie_state { + FT_START_READY, + FT_AUTH_REQ_READY, + FT_REASSOC_REQ_WAIT, + FT_SET_KEY_WAIT, +}; +#endif + +/** + * struct ft_context - ft related information + * @r0kh_id_len: r0kh id len + * @r0kh_id: r0kh id + * @auth_ft_ie: auth ft ies received during preauth phase + * @auth_ie_len: auth ie length + * @reassoc_ft_ie: reassoc ft ies received during reassoc phase + * @reassoc_ie_len: reassoc ie length + * @ric_ies: ric ie + * @ric_ies_length: ric ie len + * @set_ft_preauth_state: preauth state + * @ft_state: ft state + * @add_mdie: add mdie in assoc req + */ +struct ft_context { +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint32_t r0kh_id_len; + uint8_t r0kh_id[ROAM_R0KH_ID_MAX_LEN]; +#endif +#ifdef WLAN_FEATURE_HOST_ROAM + uint8_t auth_ft_ie[MAX_FTIE_SIZE]; + uint16_t auth_ie_len; + uint8_t reassoc_ft_ie[MAX_FTIE_SIZE]; + uint16_t reassoc_ie_len; + uint8_t ric_ies[MAX_FTIE_SIZE]; + uint16_t ric_ies_length; + bool set_ft_preauth_state; + enum ft_ie_state ft_state; + bool add_mdie; +#endif +}; + +/** + * struct assoc_channel_info - store channel info at the time of association + * @assoc_ch_width: channel width at the time of initial connection + * @omn_ie_ch_width: ch width present in operating mode notification IE of bcn + * @sec_2g_freq: secondary 2 GHz freq + * @cen320_freq: 320 MHz center freq + */ +struct assoc_channel_info { + enum phy_ch_width assoc_ch_width; + enum phy_ch_width omn_ie_ch_width; + qdf_freq_t sec_2g_freq; + qdf_freq_t cen320_freq; +}; + +/** + * struct mlme_connect_info - mlme connect information + * @timing_meas_cap: Timing meas cap + * @chan_info: oem channel info + * @tdls_chan_swit_prohibited: if tdls chan switch is prohobited by AP + * @tdls_prohibited: if tdls is prohobited by AP + * @uapsd_per_ac_bitmask: Used on STA, this is a static UAPSD mask setting + * derived from JOIN_REQ and REASSOC_REQ. If a particular AC bit is set, it + * means the AC is both trigger enabled and delivery enabled. + * @qos_enabled: is qos enabled + * @ft_info: ft related info + * @hlp_ie: hldp ie + * @hlp_ie_len: hlp ie length + * @fils_con_info: Pointer to fils connection info from connect req + * @cckm_ie: cck IE + * @cckm_ie_len: cckm_ie len + * @ese_tspec_info: ese tspec info + * @ext_cap_ie: Ext CAP IE + * @assoc_btm_cap: BSS transition management cap used in (re)assoc req + * @assoc_chan_info: store channel info at the time of association + * @force_20mhz_in_24ghz: Only 20 MHz BW allowed in 2.4 GHz + * + */ +struct mlme_connect_info { + uint8_t timing_meas_cap; + struct oem_channel_info chan_info; +#ifdef FEATURE_WLAN_TDLS + bool tdls_chan_swit_prohibited; + bool tdls_prohibited; +#endif + uint8_t uapsd_per_ac_bitmask; + bool qos_enabled; + struct ft_context ft_info; +#ifdef WLAN_FEATURE_FILS_SK + uint8_t *hlp_ie; + uint32_t hlp_ie_len; + struct wlan_fils_connection_info *fils_con_info; +#endif +#ifdef FEATURE_WLAN_ESE + uint8_t cckm_ie[DOT11F_IE_RSN_MAX_LEN]; + uint8_t cckm_ie_len; +#ifdef WLAN_FEATURE_HOST_ROAM + tESETspecInfo ese_tspec_info; +#endif +#endif + uint8_t ext_cap_ie[DOT11F_IE_EXTCAP_MAX_LEN + 2]; + bool assoc_btm_cap; + struct assoc_channel_info assoc_chan_info; + bool force_20mhz_in_24ghz; +}; + +/** struct wait_for_key_timer - wait for key timer object + * @vdev: Pointer to vdev + * @timer: timer for wati for key + */ +struct wait_for_key_timer { + struct wlan_objmgr_vdev *vdev; + qdf_mc_timer_t timer; +}; + +/** + * struct mlme_ap_config - VDEV MLME legacy private SAP + * related configurations + * @user_config_sap_ch_freq : Frequency from userspace to start SAP + * @update_required_scc_sta_power: Change the 6 GHz power type of the + * concurrent STA + * @ap_policy: Concurrent ap policy config + * @oper_ch_width: SAP current operating ch_width + * @psd_20mhz: PSD power(dBm/MHz) of SAP operating in 20 MHz + */ +struct mlme_ap_config { + qdf_freq_t user_config_sap_ch_freq; +#ifdef CONFIG_BAND_6GHZ + bool update_required_scc_sta_power; +#endif + enum host_concurrent_ap_policy ap_policy; + enum phy_ch_width oper_ch_width; + uint8_t psd_20mhz; +}; + +/** + * struct roam_trigger_per - per roam trigger related information + * @rx_rate_thresh_percent: percentage of lower than rx rate threshold + * @tx_rate_thresh_percent: percentage of lower than tx rate threshold + */ +struct roam_trigger_per { + uint8_t rx_rate_thresh_percent; + uint8_t tx_rate_thresh_percent; +}; + +/** + * struct roam_trigger_bmiss - bmiss roam trigger related information + * @final_bmiss_cnt: final beacon miss count + * @consecutive_bmiss_cnt: consecutive beacon miss count + * @qos_null_success: is Qos-Null tx Success: 0: success, 1:fail + */ +struct roam_trigger_bmiss { + uint32_t final_bmiss_cnt; + uint32_t consecutive_bmiss_cnt; + bool qos_null_success; +}; + +/** + * struct roam_trigger_poor_rssi - low rssi roam trigger + * related information + * @current_rssi: Connected AP rssi in dBm + * @roam_rssi_threshold: rssi threshold value in dBm + * @rx_linkspeed_status: rx linkspeed status, 0:good linkspeed, 1:bad + */ +struct roam_trigger_poor_rssi { + int8_t current_rssi; + int8_t roam_rssi_threshold; + bool rx_linkspeed_status; +}; + +/** + * struct roam_trigger_better_rssi - high rssi roam trigger + * related information + * @current_rssi: Connected AP rssi in dBm + * @hi_rssi_threshold: roam high RSSI threshold + */ +struct roam_trigger_better_rssi { + int8_t current_rssi; + int8_t hi_rssi_threshold; +}; + +/** + * struct roam_trigger_congestion - congestion roam trigger + * related information + * @rx_tput: RX Throughput in bytes per second in dense env + * @tx_tput: TX Throughput in bytes per second in dense env + * @roamable_count: roamable AP count info in dense env + */ +struct roam_trigger_congestion { + uint32_t rx_tput; + uint32_t tx_tput; + uint8_t roamable_count; +}; + +/** + * struct roam_trigger_user_trigger - user roam trigger related information + * @invoke_reason: defined in roam_invoke_reason + */ +struct roam_trigger_user_trigger { + enum roam_invoke_reason invoke_reason; +}; + +/** + * struct roam_trigger_background - roam trigger related information + * @current_rssi: Connected AP rssi in dBm + * @data_rssi: data frame rssi in dBm + * @data_rssi_threshold: data rssi threshold in dBm + */ +struct roam_trigger_background { + int8_t current_rssi; + int8_t data_rssi; + int8_t data_rssi_threshold; +}; + +/** + * struct roam_trigger_btm - BTM roam trigger related information + * @btm_request_mode: mode values are defined in IEEE Std + * 802.11-2020, 9.6.13.9 + * @disassoc_imminent_timer: disassoc time in milliseconds + * @validity_internal: Preferred candidate list validity interval in + * milliseconds + * @candidate_list_count: Number of preferred candidates from BTM request + * @btm_response_status_code: Response status values are enumerated in + * IEEE Std 802.11-2020, Table 9-428 (BTM status code definitions) + * @btm_bss_termination_timeout: BTM BSS termination timeout value in + * milliseconds + * @btm_mbo_assoc_retry_timeout: BTM MBO assoc retry timeout value in + * milliseconds + * @btm_req_dialog_token: btm_req_dialog_token: dialog token number in + * BTM request frame + */ + +struct roam_trigger_btm { + uint8_t btm_request_mode; + uint32_t disassoc_imminent_timer; + uint32_t validity_internal; + uint8_t candidate_list_count; + uint8_t btm_response_status_code; + uint32_t btm_bss_termination_timeout; + uint32_t btm_mbo_assoc_retry_timeout; + uint8_t btm_req_dialog_token; +}; + +/** + * struct roam_trigger_bss_load - BSS Load roam trigger parameters + * @cu_load: percentage of Connected AP channel congestion utilization + */ +struct roam_trigger_bss_load { + uint8_t cu_load; +}; + +/** + * struct roam_trigger_disconnection - Deauth roaming trigger related + * parameters + * @deauth_type: 1- Deauthentication 2- Disassociation + * @deauth_reason: Status code of the Deauth/Disassoc received, Values + * are enumerated in IEEE Std 802.11-2020, Table 9-49 (Reason codes). + */ +struct roam_trigger_disconnection { + uint8_t deauth_type; + uint16_t deauth_reason; +}; + +/** + * struct roam_trigger_periodic - periodic roam trigger + * related information + * @periodic_timer_ms: roam scan periodic, milliseconds + */ +struct roam_trigger_periodic { + uint32_t periodic_timer_ms; +}; + +/** + * struct roam_trigger_tx_failures - tx failures roam trigger + * related information + * @kickout_threshold: consecutive tx failure threshold + * @kickout_reason: defined in roam_tx_failures_reason + */ +struct roam_trigger_tx_failures { + uint32_t kickout_threshold; + enum roam_tx_failures_reason kickout_reason; +}; + +/** + * union roam_trigger_condition - union of all types roam trigger info + * structures + * @roam_per: per roam trigger related information + * @roam_bmiss: bmiss roam trigger related information + * @roam_poor_rssi: low rssi roam trigger related information + * @roam_better_rssi: high rssi roam trigger related information + * @roam_congestion: congestion roam trigger related information + * @roam_user_trigger: user trigger roam related information + * @roam_btm: btm roam trigger related information + * @roam_bss_load: bss load roam trigger related information + * @roam_disconnection: disconnect roam trigger related information + * @roam_periodic: periodic roam trigger related information + * @roam_background: background roam trigger related information + * @roam_tx_failures: tx failures roam trigger related information + */ +union roam_trigger_condition { + struct roam_trigger_per roam_per; + struct roam_trigger_bmiss roam_bmiss; + struct roam_trigger_poor_rssi roam_poor_rssi; + struct roam_trigger_better_rssi roam_better_rssi; + struct roam_trigger_congestion roam_congestion; + struct roam_trigger_user_trigger roam_user_trigger; + struct roam_trigger_btm roam_btm; + struct roam_trigger_bss_load roam_bss_load; + struct roam_trigger_disconnection roam_disconnection; + struct roam_trigger_periodic roam_periodic; + struct roam_trigger_background roam_background; + struct roam_trigger_tx_failures roam_tx_failures; +}; + +/** + * struct roam_trigger_abort_reason - roam abort related information + * @abort_reason_code: detail in roam_abort_reason + * @data_rssi: data rssi in dBm + * @data_rssi_threshold: data rssi threshold in dBm + * @rx_linkspeed_status: rx linkspeed status, 0:good linkspeed, 1:bad + */ +struct roam_trigger_abort_reason { + enum roam_abort_reason abort_reason_code; + int8_t data_rssi; + int8_t data_rssi_threshold; + bool rx_linkspeed_status; +}; + +/** + * struct eroam_trigger_info - roam trigger related information + * @timestamp: timestamp of roaming start + * @trigger_reason: roam trigger reason, enum in roam_trigger_reason + * @condition: roam trigger detail information + * @abort: roam abort related information + * @roam_scan_type: roam scan type, enum in roam_stats_scan_type + * @roam_status: roam result, 0 - Roaming is success, 1 - Roaming is failed + * @roam_fail_reason: roam fail reason, enum in wlan_roam_failure_reason_code + */ +struct eroam_trigger_info { + uint64_t timestamp; + uint32_t trigger_reason; + union roam_trigger_condition condition; + struct roam_trigger_abort_reason abort; + enum roam_stats_scan_type roam_scan_type; + uint8_t roam_status; + enum wlan_roam_failure_reason_code roam_fail_reason; +}; + +/** + * struct roam_scan_chn - each roam scan channel information + * @chan_freq: roam scan channel frequency(MHz) + * @dwell_type: indicate channel dwell type, enum in roam_scan_dwell_type + * @max_dwell_time: max dwell time of each channel + */ +struct roam_scan_chn { + uint16_t chan_freq; + enum roam_scan_dwell_type dwell_type; + uint32_t max_dwell_time; +}; + +/** + * struct eroam_scan_info - all roam scan channel related information + * @num_channels: total number of channels scanned during roam scan + * @roam_chn: each roam scan channel information + * @total_scan_time: total scan time of all roam channel + * @original_bssid: connected AP before roam happens, regardless of + * the roam resulting in success or failure. + * For non-MLO scenario, it indicates the original connected AP BSSID. + * For MLO scenario, it indicates the original BSSID of the link + * for which the reassociation occurred during the roam. + * @roamed_bssid: roamed AP BSSID when roam succeeds. + * For non-MLO case, it indicates new AP BSSID which has been + * successfully roamed. + * For MLO case, it indicates the new AP BSSID of the link on + * which the reassociation occurred during the roam. + */ +struct eroam_scan_info { + uint8_t num_channels; + struct roam_scan_chn roam_chn[MAX_ROAM_SCAN_CHAN]; + uint32_t total_scan_time; + struct qdf_mac_addr original_bssid; + struct qdf_mac_addr roamed_bssid; +}; + +/** + * struct eroam_frame_info - frame information during roaming + * @frame_type: frame subtype defined in eroam_frame_subtype + * @status: frame status defined in eroam_roam_status + * @timestamp: timestamp of the auth/assoc/eapol-M1/M2/M3/M4 frame, + * if status is successful, indicate received or send success, + * if status is failed, timestamp indicate roaming fail at that time + * @bssid: Source address for auth/assoc/eapol frame. + */ +struct eroam_frame_info { + enum eroam_frame_subtype frame_type; + enum eroam_frame_status status; + uint64_t timestamp; + struct qdf_mac_addr bssid; + +}; + +/** + * struct enhance_roam_info - enhance roam information + * @trigger: roam trigger information + * @scan: roam scan information + * @timestamp: types of frame information during roaming + */ +struct enhance_roam_info { + struct eroam_trigger_info trigger; + struct eroam_scan_info scan; + struct eroam_frame_info timestamp[WLAN_ROAM_MAX_FRAME_INFO]; +}; + +/** + * struct mlme_legacy_priv - VDEV MLME legacy priv object + * @chan_switch_in_progress: flag to indicate that channel switch is in progress + * @hidden_ssid_restart_in_progress: flag to indicate hidden ssid restart is + * in progress + * @vdev_start_failed: flag to indicate that vdev start failed. + * @connection_fail: flag to indicate connection failed + * @cac_required_for_new_channel: if CAC is required for new channel + * @follow_ap_edca: if true, it is forced to follow the AP's edca. + * @reconn_after_assoc_timeout: reconnect to the same AP if association timeout + * @assoc_type: vdev associate/reassociate type + * @dynamic_cfg: current configuration of nss, chains for vdev. + * @ini_cfg: Max configuration of nss, chains supported for vdev. + * @sta_dynamic_oce_value: Dynamic oce flags value for sta + * @disconnect_info: Disconnection information + * @vdev_stop_type: vdev stop type request + * @mlme_roam: Roam offload state + * @cm_roam: Roaming configuration + * @auth_log: Cached log records for SAE authentication frame + * related information. + * @roam_info: enhanced roam information include trigger, scan and + * frame information. + * @roam_cache_num: number of roam information cached in driver + * @roam_write_index: indicate current write position of ring buffer + * @roam_rd_wr_lock: protect roam buffer write and read + * @bigtk_vdev_support: BIGTK feature support for this vdev (SAP) + * @sae_retry: SAE auth retry information + * @roam_reason_better_ap: roam due to better AP found + * @hb_failure_rssi: heartbeat failure AP RSSI + * @opr_rate_set: operational rates set + * @ext_opr_rate_set: extended operational rates set + * @mcs_rate_set: MCS Based rates set + * @mscs_req_info: Information related to mscs request + * @he_config: he config + * @he_sta_obsspd: he_sta_obsspd + * @twt_wait_for_notify: TWT session teardown received, wait for + * notify event from firmware before next TWT setup is done. + * @rso_cfg: per vdev RSO config to be sent to FW + * @connect_info: mlme connect information + * @wait_key_timer: wait key timer + * @eht_config: Eht capability configuration + * @last_delba_sent_time: Last delba sent time to handle back to back delba + * requests from some IOT APs + * @ba_2k_jump_iot_ap: This is set to true if connected to the ba 2k jump IOT AP + * @is_usr_ps_enabled: Is Power save enabled + * @notify_co_located_ap_upt_rnr: Notify co located AP to update RNR or not + * @is_user_std_set: true if user set the @wifi_std + * @wifi_std: wifi standard version + * @max_mcs_index: Max supported mcs index of vdev + * @vdev_traffic_type: to set if vdev is LOW_LATENCY or HIGH_TPUT + * @country_ie_for_all_band: take all band channel info in country ie + * @mlme_ap: SAP related vdev private configurations + * @is_single_link_mlo_roam: Single link mlo roam flag + * @bss_color_change_wakelock: wakelock to complete bss color change + * operation on bss color collision detection + * @bss_color_change_runtime_lock: runtime lock to complete bss color change + * @disconnect_runtime_lock: runtime lock to complete disconnection + * @keep_alive_period: KEEPALIVE period in seconds + */ +struct mlme_legacy_priv { + bool chan_switch_in_progress; + bool hidden_ssid_restart_in_progress; + bool vdev_start_failed; + bool connection_fail; + bool cac_required_for_new_channel; + bool follow_ap_edca; + bool reconn_after_assoc_timeout; + enum vdev_assoc_type assoc_type; + struct wlan_mlme_nss_chains dynamic_cfg; + struct wlan_mlme_nss_chains ini_cfg; + uint8_t sta_dynamic_oce_value; + struct wlan_disconnect_info disconnect_info; + uint32_t vdev_stop_type; + struct wlan_mlme_roam mlme_roam; + struct wlan_cm_roam cm_roam; +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && \ + defined(WLAN_FEATURE_CONNECTIVITY_LOGGING) + struct wlan_log_record + auth_log[MAX_ROAM_CANDIDATE_AP][WLAN_ROAM_MAX_CACHED_AUTH_FRAMES]; +#elif defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(CONNECTIVITY_DIAG_EVENT) + struct wlan_diag_packet_info + auth_log[MAX_ROAM_CANDIDATE_AP][WLAN_ROAM_MAX_CACHED_AUTH_FRAMES]; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef WLAN_FEATURE_ROAM_INFO_STATS + struct enhance_roam_info *roam_info; + uint32_t roam_cache_num; + uint32_t roam_write_index; + qdf_mutex_t roam_rd_wr_lock; +#endif +#endif + bool bigtk_vdev_support; + struct sae_auth_retry sae_retry; + bool roam_reason_better_ap; + uint32_t hb_failure_rssi; + struct mlme_cfg_str opr_rate_set; + struct mlme_cfg_str ext_opr_rate_set; + struct mlme_cfg_str mcs_rate_set; + bool twt_wait_for_notify; +#ifdef WLAN_FEATURE_MSCS + struct mscs_req_info mscs_req_info; +#endif +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_config; + uint32_t he_sta_obsspd; +#endif + struct mlme_connect_info connect_info; + struct wait_for_key_timer wait_key_timer; +#ifdef WLAN_FEATURE_11BE + tDot11fIEeht_cap eht_config; +#endif + qdf_time_t last_delba_sent_time; + bool ba_2k_jump_iot_ap; + bool is_usr_ps_enabled; + bool notify_co_located_ap_upt_rnr; + bool is_user_std_set; + WMI_HOST_WIFI_STANDARD wifi_std; +#ifdef WLAN_FEATURE_SON + uint8_t max_mcs_index; +#endif + uint8_t vdev_traffic_type; + bool country_ie_for_all_band; + struct mlme_ap_config mlme_ap; +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) + bool is_single_link_mlo_roam; +#endif + qdf_wake_lock_t bss_color_change_wakelock; + qdf_runtime_lock_t bss_color_change_runtime_lock; + qdf_runtime_lock_t disconnect_runtime_lock; + enum reg_6g_ap_type best_6g_power_type; + uint16_t keep_alive_period; +}; + +/** + * struct del_bss_resp - params required for del bss response + * @status: QDF status + * @vdev_id: vdev_id + */ +struct del_bss_resp { + QDF_STATUS status; + uint8_t vdev_id; +}; + +/** + * mlme_init_rate_config() - initialize rate configuration of vdev + * @vdev_mlme: pointer to vdev mlme object + * + * Return: Success or Failure status + */ +QDF_STATUS mlme_init_rate_config(struct vdev_mlme_obj *vdev_mlme); + +/** + * mlme_init_connect_chan_info_config() - initialize channel info for a + * connection + * @vdev_mlme: pointer to vdev mlme object + * + * Return: Success or Failure status + */ +QDF_STATUS mlme_init_connect_chan_info_config(struct vdev_mlme_obj *vdev_mlme); + +/** + * mlme_get_peer_mic_len() - get mic hdr len and mic length for peer + * @psoc: psoc + * @pdev_id: pdev id for the peer + * @peer_mac: peer mac + * @mic_len: mic length for peer + * @mic_hdr_len: mic header length for peer + * + * Return: Success or Failure status + */ +QDF_STATUS mlme_get_peer_mic_len(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, + uint8_t *peer_mac, uint8_t *mic_len, + uint8_t *mic_hdr_len); + +/** + * mlme_peer_object_created_notification(): mlme peer create handler + * @peer: peer which is going to created by objmgr + * @arg: argument for vdev create handler + * + * Register this api with objmgr to detect peer is created + * + * Return: QDF_STATUS status in case of success else return error + */ + +QDF_STATUS +mlme_peer_object_created_notification(struct wlan_objmgr_peer *peer, + void *arg); + +/** + * mlme_peer_object_destroyed_notification(): mlme peer delete handler + * @peer: peer which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * Register this api with objmgr to detect peer is deleted + * + * Return: QDF_STATUS status in case of success else return error + */ +QDF_STATUS +mlme_peer_object_destroyed_notification(struct wlan_objmgr_peer *peer, + void *arg); + +/** + * mlme_get_dynamic_oce_flags(): mlme get dynamic oce flags + * @vdev: pointer to vdev object + * + * This api is used to get the dynamic oce flags pointer + * + * Return: QDF_STATUS status in case of success else return error + */ +uint8_t *mlme_get_dynamic_oce_flags(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_dynamic_vdev_config() - get the vdev dynamic config params + * @vdev: vdev pointer + * + * Return: pointer to the dynamic vdev config structure + */ +struct wlan_mlme_nss_chains *mlme_get_dynamic_vdev_config( + struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_vdev_he_ops() - Get vdev HE operations IE info + * @psoc: Pointer to PSOC object + * @vdev_id: vdev id + * + * Return: HE ops IE + */ +uint32_t mlme_get_vdev_he_ops(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * mlme_connected_chan_stats_request() - process connected channel stats + * request + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlme_get_ini_vdev_config() - get the vdev ini config params + * @vdev: vdev pointer + * + * Return: pointer to the ini vdev config structure + */ +struct wlan_mlme_nss_chains *mlme_get_ini_vdev_config( + struct wlan_objmgr_vdev *vdev); + +/** + * mlme_cfg_on_psoc_enable() - Populate MLME structure from CFG and INI + * @psoc: pointer to the psoc object + * + * Populate the MLME CFG structure from CFG and INI values using CFG APIs + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * mlme_get_psoc_ext_obj() - Get MLME object from psoc + * @psoc: pointer to the psoc object + * + * Get the MLME object pointer from the psoc + * + * Return: pointer to MLME object + */ +#define mlme_get_psoc_ext_obj(psoc) \ + mlme_get_psoc_ext_obj_fl(psoc, __func__, __LINE__) +struct wlan_mlme_psoc_ext_obj *mlme_get_psoc_ext_obj_fl(struct wlan_objmgr_psoc + *psoc, + const char *func, + uint32_t line); + +/** + * mlme_get_sae_auth_retry() - Get sae_auth_retry pointer + * @vdev: vdev pointer + * + * Return: Pointer to struct sae_auth_retry or NULL + */ +struct sae_auth_retry *mlme_get_sae_auth_retry(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_free_sae_auth_retry() - Free the SAE auth info + * @vdev: vdev pointer + * + * Return: None + */ +void mlme_free_sae_auth_retry(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_self_disconnect_ies() - Set diconnect IEs configured from userspace + * @vdev: vdev pointer + * @ie: pointer for disconnect IEs + * + * Return: None + */ +void mlme_set_self_disconnect_ies(struct wlan_objmgr_vdev *vdev, + struct element_info *ie); + +/** + * mlme_free_self_disconnect_ies() - Free the self diconnect IEs + * @vdev: vdev pointer + * + * Return: None + */ +void mlme_free_self_disconnect_ies(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_self_disconnect_ies() - Get diconnect IEs from vdev object + * @vdev: vdev pointer + * + * Return: Returns a pointer to the self disconnect IEs present in vdev object + */ +struct element_info *mlme_get_self_disconnect_ies(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_peer_disconnect_ies() - Cache disconnect IEs received from peer + * @vdev: vdev pointer + * @ie: pointer for disconnect IEs + * + * Return: None + */ +void mlme_set_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev, + struct element_info *ie); + +/** + * mlme_free_peer_disconnect_ies() - Free the peer diconnect IEs + * @vdev: vdev pointer + * + * Return: None + */ +void mlme_free_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_follow_ap_edca_flag() - Set follow ap's edca flag + * @vdev: vdev pointer + * @flag: carries if following ap's edca is true or not. + * + * Return: None + */ +void mlme_set_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev, bool flag); + +/** + * mlme_get_follow_ap_edca_flag() - Get follow ap's edca flag + * @vdev: vdev pointer + * + * Return: value of follow_ap_edca + */ +bool mlme_get_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_best_6g_power_type() - Set best 6g power type + * @vdev: vdev pointer + * @best_6g_power_type: best 6g power type + * + * Return: None + */ +void mlme_set_best_6g_power_type(struct wlan_objmgr_vdev *vdev, + enum reg_6g_ap_type best_6g_power_type); + +/** + * mlme_get_best_6g_power_type() - Get best 6g power type + * @vdev: vdev pointer + * + * Return: value of best 6g power type + */ +enum reg_6g_ap_type mlme_get_best_6g_power_type(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_reconn_after_assoc_timeout_flag() - Set reconn after assoc timeout + * flag + * @psoc: soc object + * @vdev_id: vdev id + * @flag: enable or disable reconnect + * + * Return: void + */ +void mlme_set_reconn_after_assoc_timeout_flag(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool flag); + +/** + * mlme_get_reconn_after_assoc_timeout_flag() - Get reconn after assoc timeout + * flag + * @psoc: soc object + * @vdev_id: vdev id + * + * Return: true for enabling reconnect, otherwise false + */ +bool mlme_get_reconn_after_assoc_timeout_flag(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlme_get_peer_disconnect_ies() - Get diconnect IEs from vdev object + * @vdev: vdev pointer + * + * Return: Returns a pointer to the peer disconnect IEs present in vdev object + */ +struct element_info *mlme_get_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_free_peer_assoc_rsp_ie() - Free the peer Assoc resp IE + * @peer_priv: Peer priv object + * + * Return: None + */ +void mlme_free_peer_assoc_rsp_ie(struct peer_mlme_priv_obj *peer_priv); + +/** + * mlme_set_peer_assoc_rsp_ie() - Cache Assoc resp IE send to peer + * @psoc: soc object + * @peer_addr: Mac address of requesting peer + * @ie: pointer for assoc resp IEs + * + * Return: None + */ +void mlme_set_peer_assoc_rsp_ie(struct wlan_objmgr_psoc *psoc, + uint8_t *peer_addr, struct element_info *ie); + +/** + * mlme_set_peer_pmf_status() - set pmf status of peer + * @peer: PEER object + * @is_pmf_enabled: Carries if PMF is enabled or not + * + * is_pmf_enabled will be set to true if PMF is enabled by peer + * + * Return: void + */ +void mlme_set_peer_pmf_status(struct wlan_objmgr_peer *peer, + bool is_pmf_enabled); +/** + * mlme_get_peer_pmf_status() - get if peer is of pmf capable + * @peer: PEER object + * + * Return: Value of is_pmf_enabled; True if PMF is enabled by peer + */ +bool mlme_get_peer_pmf_status(struct wlan_objmgr_peer *peer); + +/** + * wlan_get_opmode_from_vdev_id() - Get opmode from vdevid + * @pdev: pdev pointer + * @vdev_id: vdev id + * + * Return: opmode + */ +enum QDF_OPMODE wlan_get_opmode_from_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * wlan_mlme_get_bssid_vdev_id() - get bss peer mac address(BSSID) using vdev id + * @pdev: pdev + * @vdev_id: vdev_id + * @bss_peer_mac: pointer to bss_peer_mac_address + * + * This API is used to get mac address of bss peer/bssid. + * + * Context: Any context. + * + * Return: QDF_STATUS based on overall success + */ +QDF_STATUS wlan_mlme_get_bssid_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *bss_peer_mac); + +/** + * mlme_update_freq_in_scan_start_req() - Fill frequencies in wide + * band scan req for mlo connection + * @vdev: vdev common object + * @req: pointer to scan request + * @scan_ch_width: Channel width for which to trigger a wide band scan + * @scan_freq: frequency for which to trigger a wide band RRM scan + * @cen320_freq: 320 MHz center freq + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req, + enum phy_ch_width scan_ch_width, + qdf_freq_t scan_freq, + qdf_freq_t cen320_freq); + +/** + * wlan_get_operation_chan_freq() - get operating chan freq of + * given vdev + * @vdev: vdev + * + * Return: chan freq of given vdev id + */ +qdf_freq_t wlan_get_operation_chan_freq(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_get_operation_chan_freq_vdev_id() - get operating chan freq of + * given vdev id + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: chan freq of given vdev id + */ +qdf_freq_t wlan_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * wlan_vdev_set_dot11mode - Set the dot11mode of the vdev + * @mac_mlme_cfg: MAC's MLME config pointer + * @device_mode: OPMODE of the vdev + * @vdev_mlme: MLME component of the vdev + * + * Use this API to set the dot11mode of the vdev. + * For non-ML type vdev, this API restricts the connection + * of vdev to 11ax on 11be capable operation. + * + * Return: void + */ +void wlan_vdev_set_dot11mode(struct wlan_mlme_cfg *mac_mlme_cfg, + enum QDF_OPMODE device_mode, + struct vdev_mlme_obj *vdev_mlme); + +/** + * wlan_is_open_wep_cipher() - check if cipher is open or WEP + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: if cipher is open or WEP + */ +bool wlan_is_open_wep_cipher(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * wlan_vdev_id_is_open_cipher() - check if cipher is open + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: if cipher is open + */ +bool wlan_vdev_id_is_open_cipher(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * wlan_vdev_is_open_mode() - check if cipher is open + * @vdev: Pointer to vdev + * + * Return: if cipher is open + */ +bool wlan_vdev_is_open_mode(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_vdev_id_is_11n_allowed() - check if 11n allowed + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: false if cipher is TKIP or WEP + */ +bool wlan_vdev_id_is_11n_allowed(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * wlan_is_vdev_id_up() - check if vdev id is in UP state + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: if vdev is up + */ +bool wlan_is_vdev_id_up(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +QDF_STATUS +wlan_get_op_chan_freq_info_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, qdf_freq_t *op_freq, + qdf_freq_t *freq_seg_0, + enum phy_ch_width *ch_width); + +/** + * wlan_strip_ie() - strip requested IE from IE buffer + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @eid: EID of IE to strip + * @size_of_len_field: length of IE length field + * @oui: if present matches OUI also + * @oui_length: if previous present, this is length of oui + * @extracted_ie: if not NULL, copy the stripped IE to this buffer + * @eid_max_len: maximum length of IE @eid + * + * This utility function is used to strip of the requested IE if present + * in IE buffer. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_strip_ie(uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, enum size_of_len_field size_of_len_field, + uint8_t *oui, uint8_t oui_length, + uint8_t *extracted_ie, uint32_t eid_max_len); + +/** + * wlan_is_channel_present_in_list() - check if rfeq is present in the list + * given vdev id + * @freq_lst: given freq list + * @num_chan: num of chan freq + * @chan_freq: chan freq to check + * + * Return: chan freq of given vdev id + */ +bool wlan_is_channel_present_in_list(qdf_freq_t *freq_lst, + uint32_t num_chan, qdf_freq_t chan_freq); + +/** + * wlan_roam_is_channel_valid() - validate channel frequency + * @reg: regulatory context + * @chan_freq: channel frequency + * + * This function validates channel frequency present in valid channel + * list or not. + * + * Return: true or false + */ +bool wlan_roam_is_channel_valid(struct wlan_mlme_reg *reg, + qdf_freq_t chan_freq); + +int8_t wlan_get_cfg_max_tx_power(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint32_t ch_freq); + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * mlme_get_supplicant_disabled_roaming() - Get supplicant disabled roaming + * value for a given vdev. + * @psoc: PSOC pointer + * @vdev_id: Vdev for which the supplicant disabled roaming value is being + * requested + * + * Return: True if supplicant disabled roaming else false + */ +bool +mlme_get_supplicant_disabled_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlme_set_supplicant_disabled_roaming - Set the supplicant disabled + * roaming flag. + * @psoc: PSOC pointer + * @vdev_id: Vdev for which the supplicant disabled roaming needs to + * be set + * @val: value true is to disable RSO and false to enable RSO + * + * Return: None + */ +void mlme_set_supplicant_disabled_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool val); + +/** + * mlme_get_roam_trigger_bitmap() - Get roaming trigger bitmap value for a given + * vdev. + * @psoc: PSOC pointer + * @vdev_id: Vdev for which the roam trigger bitmap is being requested + * + * Return: roaming trigger bitmap + */ +uint32_t +mlme_get_roam_trigger_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * mlme_set_roam_trigger_bitmap() - Set the roaming trigger bitmap value for + * the given vdev. If the bitmap is zero then roaming is completely disabled + * on the vdev which means roam structure in firmware is not allocated and no + * RSO start/stop commands can be sent + * @psoc: PSOC pointer + * @vdev_id: Vdev for which the roam trigger bitmap is to be set + * @val: bitmap value to set + * + * Return: None + */ +void mlme_set_roam_trigger_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t val); + +/** + * mlme_get_roam_state() - Get roam state from vdev object + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * Return: Returns roam offload state + */ +enum roam_offload_state +mlme_get_roam_state(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * mlme_set_roam_state() - Set roam state in vdev object + * @psoc: psoc pointer + * @vdev_id: vdev id + * @val: roam offload state + * + * Return: None + */ +void mlme_set_roam_state(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_offload_state val); + +/** + * mlme_get_operations_bitmap() - Get the mlme operations bitmap which + * contains the bitmap of mlme operations which have disabled roaming + * temporarily + * @psoc: PSOC pointer + * @vdev_id: vdev for which the mlme operation bitmap is requested + * + * Return: bitmap value + */ +uint8_t +mlme_get_operations_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * mlme_set_operations_bitmap() - Set the mlme operations bitmap which + * indicates what mlme operations are in progress + * @psoc: PSOC pointer + * @vdev_id: vdev for which the mlme operation bitmap is requested + * @reqs: RSO stop requestor + * @clear: clear bit if true else set bit + * + * Return: None + */ +void +mlme_set_operations_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum wlan_cm_rso_control_requestor reqs, bool clear); +/** + * mlme_clear_operations_bitmap() - Clear mlme operations bitmap which + * indicates what mlme operations are in progress + * @psoc: PSOC pointer + * @vdev_id: vdev for which the mlme operation bitmap is requested + * + * Return: None + */ +void +mlme_clear_operations_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * mlme_get_cfg_wlm_level() - Get the WLM level value + * @psoc: pointer to psoc object + * @level: level that needs to be filled. + * + * Return: QDF Status + */ +QDF_STATUS mlme_get_cfg_wlm_level(struct wlan_objmgr_psoc *psoc, + uint8_t *level); + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * mlme_get_cfg_multi_client_ll_ini_support() - Get the ini value of wlm multi + * client latency level feature + * @psoc: pointer to psoc object + * @multi_client_ll_support: parameter that needs to be filled. + * + * Return: QDF Status + */ +QDF_STATUS +mlme_get_cfg_multi_client_ll_ini_support(struct wlan_objmgr_psoc *psoc, + bool *multi_client_ll_support); +#else +static inline QDF_STATUS +mlme_get_cfg_multi_client_ll_ini_support(struct wlan_objmgr_psoc *psoc, + bool *multi_client_ll_support) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * mlme_get_cfg_wlm_reset() - Get the WLM reset flag + * @psoc: pointer to psoc object + * @reset: reset that needs to be filled. + * + * Return: QDF Status + */ +QDF_STATUS mlme_get_cfg_wlm_reset(struct wlan_objmgr_psoc *psoc, + bool *reset); + +#define MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAM_RSO_ENABLED) + +#define MLME_IS_ROAM_STATE_DEINIT(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAM_DEINIT) + +#define MLME_IS_ROAM_STATE_INIT(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAM_INIT) + +#define MLME_IS_ROAM_STATE_STOPPED(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAM_RSO_STOPPED) + +#define MLME_IS_ROAM_INITIALIZED(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) >= WLAN_ROAM_INIT) +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define MLME_IS_ROAMING_IN_PROG(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAMING_IN_PROG) + +#define MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAM_SYNCH_IN_PROG) + +#else +#define MLME_IS_ROAMING_IN_PROG(psoc, vdev_id) (false) +#define MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) (false) +#endif + +#if defined (WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +#define MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) \ + (mlme_get_roam_state(psoc, vdev_id) == WLAN_MLO_ROAM_SYNCH_IN_PROG) +#else +#define MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) (false) +#endif + +/** + * mlme_reinit_control_config_lfr_params() - Reinitialize roam control config + * @psoc: PSOC pointer + * @lfr: Pointer of an lfr_cfg buffer to fill. + * + * Reinitialize/restore the param related control roam config lfr params with + * default values of corresponding ini params. + * + * Return: None + */ +void mlme_reinit_control_config_lfr_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr); + +/** + * wlan_mlme_get_mac_vdev_id() - get vdev self mac address using vdev id + * @pdev: pdev + * @vdev_id: vdev_id + * @self_mac: pointer to self_mac_address + * + * This API is used to get self mac address. + * + * Context: Any context. + * + * Return: QDF_STATUS based on overall success + */ +QDF_STATUS wlan_mlme_get_mac_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *self_mac); + +/** + * wlan_acquire_peer_key_wakelock -api to get key wakelock + * @pdev: pdev + * @mac_addr: peer mac addr + * + * This function acquires wakelock and prevent runtime pm during key + * installation + * + * Return: None + */ +void wlan_acquire_peer_key_wakelock(struct wlan_objmgr_pdev *pdev, + uint8_t *mac_addr); + +/** + * wlan_release_peer_key_wakelock -api to release key wakelock + * @pdev: pdev + * @mac_addr: peer mac addr + * + * This function releases wakelock and allow runtime pm after key + * installation + * + * Return: None + */ +void wlan_release_peer_key_wakelock(struct wlan_objmgr_pdev *pdev, + uint8_t *mac_addr); + +/** + * wlan_get_sap_user_config_freq() - Get the user configured frequency + * + * @vdev: pointer to vdev + * + * Return: User configured sap frequency. + */ +qdf_freq_t +wlan_get_sap_user_config_freq(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_set_sap_user_config_freq() - Set the user configured frequency + * + * @vdev: pointer to vdev + * @freq: user configured SAP frequency + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_set_sap_user_config_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + +#if defined(WLAN_FEATURE_11BE_MLO) +/** + * wlan_clear_mlo_sta_link_removed_flag() - Clear link removal flag on all + * vdev of same ml dev + * @vdev: pointer to vdev + * + * Return: void + */ +void wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_get_mlo_link_agnostic_flag() - Update mlo link agnostic flag + * + * @vdev: pointer to vdev + * @dest_addr: destination address + * + * Return: true/false + */ +bool wlan_get_mlo_link_agnostic_flag(struct wlan_objmgr_vdev *vdev, + uint8_t *dest_addr); +/** + * wlan_set_vdev_link_removed_flag_by_vdev_id() - Set link removal flag + * on vdev + * @psoc: psoc object + * @vdev_id: vdev id + * @removed: link removal flag + * + * Return: QDF_STATUS_SUCCESS if success, otherwise error code + */ +QDF_STATUS +wlan_set_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool removed); + +/** + * wlan_get_vdev_link_removed_flag_by_vdev_id() - Get link removal flag + * of vdev + * @psoc: psoc object + * @vdev_id: vdev id + * + * Return: true if link is removed on vdev, otherwise false. + */ +bool +wlan_get_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_drop_mgmt_frame_on_link_removal() - Check mgmt frame + * allow dropped due to link removal + * @vdev: pointer to vdev + * + * Return: true if frame can be dropped. + */ +bool wlan_drop_mgmt_frame_on_link_removal(struct wlan_objmgr_vdev *vdev); +#else +static inline void +wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +bool wlan_get_mlo_link_agnostic_flag(struct wlan_objmgr_vdev *vdev, + uint8_t *dest_addr) +{ + return false; +} + +static inline QDF_STATUS +wlan_set_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool removed) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_get_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline bool +wlan_drop_mgmt_frame_on_link_removal(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif + +#ifdef CONFIG_BAND_6GHZ +/** + * wlan_get_tpc_update_required_for_sta() - Get the tpc update required config + * to identify whether the tpc power has changed for concurrent STA interface + * + * @vdev: pointer to SAP vdev + * + * Return: Change scc power config + */ +bool +wlan_get_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_set_tpc_update_required_for_sta() - Set the tpc update required config + * for the concurrent STA interface + * + * @vdev: pointer to SAP vdev + * @value: change scc power config + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value); +#else +static inline bool +wlan_get_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline QDF_STATUS +wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_mlme_get_sta_num_tx_chains() - API to get station num tx chains + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @tx_chains : tx_chains out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *tx_chains); + +/** + * wlan_mlme_get_sta_tx_nss() - API to get station tx NSS + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @tx_nss : tx_nss out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *tx_nss); + +/** + * wlan_mlme_get_sta_num_rx_chains() - API to get station num rx chains + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @rx_chains : rx_chains out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *rx_chains); + +/** + * wlan_mlme_get_sta_rx_nss() - API to get station rx NSS + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @rx_nss : rx_nss out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *rx_nss); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_mlme_defer_pmk_set_in_roaming() - Set the set_key pending status + * + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @set_pmk_pending: set_key pending status + * + * Return: None + */ +void +wlan_mlme_defer_pmk_set_in_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set_pmk_pending); + +/** + * wlan_mlme_is_pmk_set_deferred() - Get the set_key pending status + * + * @psoc: pointer to psoc + * @vdev_id: vdev id + * + * Return : set_key pending status + */ +bool +wlan_mlme_is_pmk_set_deferred(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#else +static inline void +wlan_mlme_defer_pmk_set_in_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set_pmk_pending) +{ +} + +static inline bool +wlan_mlme_is_pmk_set_deferred(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_SAE +/** + * wlan_vdev_is_sae_auth_type() - is vdev SAE auth type + * @vdev: pointer to vdev + * + * Return: true if vdev is SAE auth type + */ +bool wlan_vdev_is_sae_auth_type(struct wlan_objmgr_vdev *vdev); +#endif /* WLAN_FEATURE_SAE */ + +/** + * wlan_get_rand_from_lst_for_freq()- Get random channel from a given channel + * list. + * @freq_lst: Frequency list + * @num_chan: number of channels + * + * Get random channel from given channel list. + * + * Return: channel frequency. + */ +uint16_t wlan_get_rand_from_lst_for_freq(uint16_t *freq_lst, + uint8_t num_chan); +#if defined WLAN_FEATURE_SR +/** + * mlme_sr_update() - MLME sr update callback + * @vdev: vdev object + * @enable: true or false + * + * This function is called to update the SR threshold + */ +void mlme_sr_update(struct wlan_objmgr_vdev *vdev, bool enable); + +/** + * mlme_sr_is_enable: Check whether SR is enabled or not + * @vdev: object manager vdev + * + * Return: True/False + */ +int mlme_sr_is_enable(struct wlan_objmgr_vdev *vdev); +#else +static inline void mlme_sr_update(struct wlan_objmgr_vdev *vdev, bool enable) +{ +} + +static inline int mlme_sr_is_enable(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} +#endif /* WLAN_FEATURE_SR */ + +/** + * mlme_peer_oper_mode_change_event_handler() - Handle peer oper mode event + * @scn: handle + * @event: Event data received from firmware + * @len: Event data length received from firmware + */ +int mlme_peer_oper_mode_change_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len); + +/** + * wmi_extract_peer_oper_mode_event() - Extract the peer operating + * mode change event and update the new bandwidth + * @wmi_handle: wmi handle + * @event: Event data received from firmware + * @len: Event data length received from firmware + * @data: Extract the event and fill in data + */ +QDF_STATUS +wmi_extract_peer_oper_mode_event(wmi_unified_t wmi_handle, + uint8_t *event, + uint32_t len, + struct peer_oper_mode_event *data); + +/** + * wlan_mlme_register_rx_ops - Target IF mlme API to register mlme + * related rx op. + * @rx_ops: Pointer to rx ops fp struct + * + * Return: none + */ +void wlan_mlme_register_rx_ops(struct wlan_mlme_rx_ops *rx_ops); + +/** + * mlme_get_rx_ops - Get mlme rx ops from psoc + * @psoc: psoc + * + * Return: Pointer to rx ops fp struct + */ +struct wlan_mlme_rx_ops * +mlme_get_rx_ops(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_mlme_register_common_events - Wrapper to register common events + * @psoc: psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS +wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_mlme_send_csa_event_status_ind_cmd() - send csa event status indication + * @vdev: vdev obj + * @csa_status: csa status + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_send_csa_event_status_ind_cmd(struct wlan_objmgr_vdev *vdev, + uint8_t csa_status); + +/** + * wlan_mlme_get_sap_psd_for_20mhz() - Get the PSD power for 20 MHz + * frequency + * @vdev: pointer to vdev object + * + * Return: psd power + */ +uint8_t wlan_mlme_get_sap_psd_for_20mhz(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_set_sap_psd_for_20mhz() - Set the PSD power for 20 MHz + * frequency + * @vdev: pointer to vdev object + * @psd_power : psd power + * + * Return: None + */ +QDF_STATUS wlan_mlme_set_sap_psd_for_20mhz(struct wlan_objmgr_vdev *vdev, + uint8_t psd_power); + +/** + * wlan_find_peer_and_get_mac_and_mld_addr() - This API find peer from the peer + * list and cache peer MAC and MLD address in the peer_mac_info. + * @psoc: PSOC object + * @peer_mac_info: Peer MAC address info + * + * Return: None + */ +QDF_STATUS +wlan_find_peer_and_get_mac_and_mld_addr( + struct wlan_objmgr_psoc *psoc, + struct peer_mac_addresses *peer_mac_info); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_twt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_twt_api.h new file mode 100644 index 0000000000..aa6308be9c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_twt_api.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declare internal API related to the mlme TWT functionality + */ + +#ifndef _WLAN_MLME_TWT_API_H_ +#define _WLAN_MLME_TWT_API_H_ + +#include +#include +#include +#include +#include +#include +#include +#include "wlan_cm_roam_public_struct.h" + +#ifdef WLAN_SUPPORT_TWT +/** + * mlme_is_twt_setup_in_progress() - Get if TWT setup command is in progress + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: True if Setup is in progress + */ +bool mlme_is_twt_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * mlme_add_twt_session() - Add TWT session entry in the TWT context + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: None + */ +void mlme_add_twt_session(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * mlme_set_twt_setup_done() - Set TWT setup complete for given dialog ID + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @is_set: Set or clear the setup done flag + * + * Return: None + */ +void mlme_set_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, bool is_set); + +/** + * mlme_is_twt_setup_done() - Get if TWT session is established for given + * dialog id. + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: Return true if TWT session exists for given dialog ID. + */ +bool mlme_is_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); + +/** + * mlme_set_twt_session_state() - Set the TWT session state for the given dialog + * id in TWT context + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @state: TWT session state + * + * Return: None + */ +void mlme_set_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_session_state state); + +/** + * mlme_get_twt_session_state() - Get TWT session state for given dialog id + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: TWT session state. + */ +enum wlan_twt_session_state +mlme_get_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); + +/** + * mlme_get_twt_peer_capabilities - Get TWT peer capabilities + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * + * Return: Peer TWT capabilities + */ +uint8_t mlme_get_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac); + +/** + * mlme_set_twt_peer_capabilities() - Set the TWT peer capabilities in TWT + * context + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @caps: Bitmap of enum wlan_twt_capabilities + */ +void mlme_set_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t caps); + +/** + * mlme_twt_any_peer_cmd_in_progress() - Iterate through the list of peers + * and check if the given command is in progress + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @dialog_id: Dialog id + * @cmd: command + * + * This API is used to check for the given @dialog_id if the + * @cmd command is in progress for any of the peers. + * + * Return: true if command is in progress, false otherwise + */ +bool +mlme_twt_any_peer_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id, + enum wlan_twt_commands cmd); + +/** + * mlme_sap_set_twt_all_peers_cmd_in_progress() - Iterate through the list + * of peers and set the command in the TWT session entry in the TWT context + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @dialog_id: Dialog ID + * @cmd: Command + * + * This API iterates through the list of peers and updates the active + * command to @cmd for the given dialog_id. + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_sap_set_twt_all_peers_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id, + enum wlan_twt_commands cmd); + +/** + * mlme_init_all_peers_twt_context() - Iterate through the list + * of peers and initialize the TWT context structure + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @dialog_id: Dialog ID + * + * This API iterates through the list of peers and initializes + * the TWT context structure + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_init_all_peers_twt_context(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id); +/** + * mlme_init_twt_context() - Initialize TWT context structure + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * This API will be called on disconnection from AP. + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_init_twt_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * mlme_twt_set_wait_for_notify() - Set wait for notify flag. + * @psoc: Pointer to psoc object + * @vdev_id: VDEV identifier + * @is_set: Set or clear notify flag + * + * Return: None + */ +void mlme_twt_set_wait_for_notify(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool is_set); + +/** + * mlme_is_twt_notify_in_progress() - Get TWT notify in progress. + * @psoc: Pointer to psoc object + * @vdev_id: VDEV identifier + * + * Return: True if twt_notify is in progress. + */ +bool mlme_is_twt_notify_in_progress(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); + +#ifdef WLAN_FEATURE_11AX +/** + * mlme_is_flexible_twt_enabled() - Check if flexible TWT is enabled. + * @psoc: Pointer to psoc object + * + * Return: True if flexible TWT is supported + */ +bool mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline +bool mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /* WLAN_FEATURE_11AX */ + +/** + * mlme_set_twt_command_in_progress() - Set TWT command is in progress. + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_twt_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd); + +/** + * mlme_sap_twt_peer_is_cmd_in_progress() - For a given peer_mac check if + * the given command is in progress + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * + * Return: True if given command is in progress. + */ +bool mlme_sap_twt_peer_is_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd); + + +/** + * mlme_twt_is_command_in_progress() - Check if given command is in progress + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * @active_cmd: Fill the active command in this output parameter + * + * Return: True if given command is in progress. + */ +bool mlme_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *active_cmd); + +/** + * mlme_is_max_twt_sessions_reached() - Check if the maximum number of + * TWT sessions reached or not excluding the given dialog_id + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: dialog id + * + * Check if the number of active TWT sessions is equal to the maximum number + * of TWT sessions supported. Only count the TWT session slot if it not + * TWT_ALL_SESSIONS_DIALOG_ID and dialog id is different from input dialog_id, + * because if same dialog_id already exists in the TWT sessions, we should + * return false since re-negotiation is supported on existing dialog_id. + * + * Return: True if slot is available for dialog_id, false otherwise + */ +bool mlme_is_max_twt_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * mlme_is_24ghz_twt_enabled() - Get if TWT is enabled on 2.4Ghz + * @psoc: Pointer to psoc object + * + * Return: True if TWT is allowed on 2.4Ghz connection. + */ +bool mlme_is_24ghz_twt_enabled(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_TWT_CONV_SUPPORTED +/** + * mlme_is_twt_disable_info_frame() - Get if TWT info frame enabled/disabled + * @psoc: Pointer to psoc object + * + * Return: True if TWT info frame is disabled. + */ +bool mlme_is_twt_disable_info_frame(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +mlme_is_twt_disable_info_frame(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +#endif +#else +static inline +void mlme_set_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t caps) +{} + +static inline +QDF_STATUS mlme_init_twt_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +bool mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool +mlme_is_24ghz_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool +mlme_is_twt_disable_info_frame(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +#endif /* WLAN_SUPPORT_TWT */ +#endif /* _WLAN_MLME_TWT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h new file mode 100644 index 0000000000..2b2765d759 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/inc/wlan_mlme_vdev_mgr_interface.h @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare VDEV Manager interface APIs exposed by the mlme component + */ + +#ifndef _WLAN_MLME_VDEV_MGR_INT_API_H_ +#define _WLAN_MLME_VDEV_MGR_INT_API_H_ + +#include +#include "include/wlan_vdev_mlme.h" +#include "wlan_mlme_main.h" +#include "wma_if.h" + +/** + * mlme_register_mlme_ext_ops() - Register mlme ext ops + * + * This function is called to register mlme ext operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_register_mlme_ext_ops(void); + +/** + * mlme_register_mlo_ext_ops() - Register mlme mlo ext ops + * + * This function is called to register mlme mlo ext operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_register_mlo_ext_ops(void); + +/** + * mlme_unregister_mlo_ext_ops() - Unregister mlme mlo ext ops + * + * This function is called to unregister mlme mlo ext operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_unregister_mlo_ext_ops(void); + +/** + * mlme_register_vdev_mgr_ops() - Register vdev mgr ops + * @vdev_mlme: vdev mlme object + * + * This function is called to register vdev manager operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_register_vdev_mgr_ops(struct vdev_mlme_obj *vdev_mlme); +/** + * mlme_unregister_vdev_mgr_ops() - Unregister vdev mgr ops + * @vdev_mlme: vdev mlme object + * + * This function is called to unregister vdev manager operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_unregister_vdev_mgr_ops(struct vdev_mlme_obj *vdev_mlme); + +/** + * mlme_set_chan_switch_in_progress() - set mlme priv restart in progress + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev, + bool val); + +#ifdef WLAN_FEATURE_MSCS +/** + * mlme_set_is_mscs_req_sent() - set mscs frame req flag + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_get_is_mscs_req_sent() - get mscs frame req flag + * @vdev: vdev pointer + * + * Return: value of mscs flag + */ +bool mlme_get_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev); +#else +static inline +QDF_STATUS mlme_set_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev, bool val) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +bool mlme_get_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif + +/** + * mlme_is_chan_switch_in_progress() - get mlme priv restart in progress + * @vdev: vdev pointer + * + * Return: value of mlme priv restart in progress + */ +bool mlme_is_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev); + +/** + * ap_mlme_set_hidden_ssid_restart_in_progress() - set mlme priv hidden ssid + * restart in progress + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ap_mlme_set_hidden_ssid_restart_in_progress(struct wlan_objmgr_vdev *vdev, + bool val); + +/** + * ap_mlme_is_hidden_ssid_restart_in_progress() - get mlme priv hidden ssid + * restart in progress + * @vdev: vdev pointer + * + * Return: value of mlme priv hidden ssid restart in progress + */ +bool ap_mlme_is_hidden_ssid_restart_in_progress(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_vdev_start_failed() - set mlme priv vdev restart fail flag + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_vdev_start_failed(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_is_connection_fail() - get connection fail flag + * @vdev: vdev pointer + * + * Return: value of vdev connection failure flag + */ +bool mlme_is_connection_fail(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_is_wapi_sta_active() - check sta with wapi security exists and is active + * @pdev: pdev pointer + * + * Return: true if sta with wapi security exists + */ +#ifdef FEATURE_WLAN_WAPI +bool mlme_is_wapi_sta_active(struct wlan_objmgr_pdev *pdev); +#else +static inline bool mlme_is_wapi_sta_active(struct wlan_objmgr_pdev *pdev) +{ + return false; +} +#endif + +QDF_STATUS mlme_set_bigtk_support(struct wlan_objmgr_vdev *vdev, bool val); + +bool mlme_get_bigtk_support(struct wlan_objmgr_vdev *vdev); + +#ifdef FEATURE_WLAN_TDLS +/** + * mlme_set_tdls_chan_switch_prohibited() - set tdls chan switch prohibited + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_get_tdls_chan_switch_prohibited() - get tdls chan switch prohibited + * @vdev: vdev pointer + * + * Return: bool + */ +bool mlme_get_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_tdls_prohibited() - set tdls prohibited + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_tdls_prohibited(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_get_tdls_prohibited() - get tdls prohibited + * @vdev: vdev pointer + * + * Return: bool + */ +bool mlme_get_tdls_prohibited(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +mlme_set_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev, bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool mlme_get_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline QDF_STATUS +mlme_set_tdls_prohibited(struct wlan_objmgr_vdev *vdev, bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool mlme_get_tdls_prohibited(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif +/** + * mlme_set_roam_reason_better_ap() - set roam reason better AP + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_roam_reason_better_ap(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_get_roam_reason_better_ap() - get roam reason better AP + * @vdev: vdev pointer + * + * Return: bool + */ +bool mlme_get_roam_reason_better_ap(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_hb_ap_rssi() - set hb ap RSSI + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_hb_ap_rssi(struct wlan_objmgr_vdev *vdev, uint32_t val); + +/** + * mlme_get_hb_ap_rssi() - get HB AP RSSIc + * @vdev: vdev pointer + * + * Return: rssi value + */ +uint32_t mlme_get_hb_ap_rssi(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_connection_fail() - set connection failure flag + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_connection_fail(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_get_vdev_start_failed() - get mlme priv vdev restart fail flag + * @vdev: vdev pointer + * + * Return: value of mlme priv vdev restart fail flag + */ +bool mlme_get_vdev_start_failed(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_cac_required() - get if cac is required for new channel + * @vdev: vdev pointer + * + * Return: if cac is required + */ +bool mlme_get_cac_required(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_cac_required() - set if cac is required for new channel + * @vdev: vdev pointer + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_cac_required(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_set_mbssid_info() - save mbssid info + * @vdev: vdev pointer + * @mbssid_info: mbssid info + * @freq: current operating frequency + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_mbssid_info(struct wlan_objmgr_vdev *vdev, + struct scan_mbssid_info *mbssid_info, qdf_freq_t freq); + +/** + * mlme_get_mbssid_info() - get mbssid info + * @vdev: vdev pointer + * @mbss_11ax: mbss 11ax info + * + * Return: None + */ +void mlme_get_mbssid_info(struct wlan_objmgr_vdev *vdev, + struct vdev_mlme_mbss_11ax *mbss_11ax); + +/** + * mlme_set_tx_power() - set tx power + * @vdev: vdev pointer + * @tx_power: tx power to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_tx_power(struct wlan_objmgr_vdev *vdev, + int8_t tx_power); + +/** + * mlme_get_tx_power() - get tx power + * @vdev: vdev pointer + * + * Return: current tx power + */ +int8_t mlme_get_tx_power(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_max_reg_power() - get max reg power + * @vdev: vdev pointer + * + * Return: max reg power + */ +int8_t mlme_get_max_reg_power(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_max_reg_power() - set max reg power + * @vdev: vdev pointer + * @max_reg_power: max regulatory power to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_max_reg_power(struct wlan_objmgr_vdev *vdev, + int8_t max_reg_power); + +/** + * mlme_is_vdev_in_beaconning_mode() - check if vdev is beaconing mode + * @vdev_opmode: vdev opmode + * + * To check if vdev is operating in beaconing mode or not. + * + * Return: true or false + */ +bool mlme_is_vdev_in_beaconning_mode(enum QDF_OPMODE vdev_opmode); + +/** + * mlme_set_assoc_type() - set associate type + * @vdev: vdev pointer + * @assoc_type: type to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_assoc_type(struct wlan_objmgr_vdev *vdev, + enum vdev_assoc_type assoc_type); + +/** + * mlme_get_vdev_stop_type() - to get vdev stop type + * @vdev: vdev pointer + * @vdev_stop_type: vdev stop type + * + * This API will get vdev stop type from mlme legacy priv. + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_get_vdev_stop_type(struct wlan_objmgr_vdev *vdev, + uint32_t *vdev_stop_type); + +/** + * mlme_set_vdev_stop_type() - to set vdev stop type + * @vdev: vdev pointer + * @vdev_stop_type: vdev stop type + * + * This API will set vdev stop type from mlme legacy priv. + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_vdev_stop_type(struct wlan_objmgr_vdev *vdev, + uint32_t vdev_stop_type); + +/** + * mlme_is_notify_co_located_ap_update_rnr() - Need co-located ap update rnr + * @vdev: vdev pointer + * + * Return: True if vdev need notify co-located ap to update rnr. + */ +bool mlme_is_notify_co_located_ap_update_rnr(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_notify_co_located_ap_update_rnr() - notify co-located ap to update + * rnr + * @vdev: vdev pointer + * @update_rnr: whether to notify co-located ap to update rnr + * + * Return: Void + */ +void mlme_set_notify_co_located_ap_update_rnr(struct wlan_objmgr_vdev *vdev, + bool update_rnr); + +/** + * wlan_is_vdev_traffic_ll_ht() - if vdev traffic type is low latency or high TP + * @vdev: vdev pointer + * + * Return: true is LL or HT is set. + */ +bool wlan_is_vdev_traffic_ll_ht(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_vdev_wifi_std() - get the wifi std version for the vdev + * @vdev: vdev pointer + * + * Return: WMI_HOST_WIFI_STANDARD + */ +WMI_HOST_WIFI_STANDARD mlme_get_vdev_wifi_std(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_assoc_type() - get associate type + * @vdev: vdev pointer + * + * Return: associate type + */ +enum vdev_assoc_type mlme_get_assoc_type(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_vdev_self_peer_create() - function to send the vdev create self peer + * @vdev: vdev pointer + * + * Return: QDF_STATUS_SUCCESS when the self peer is successfully created + * to firmware or QDF_STATUS_E_** when there is a failure. + */ +QDF_STATUS mlme_vdev_self_peer_create(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_vdev_self_peer_delete() - function to delete vdev self peer + * @self_peer_del_msg: scheduler message containing the del_vdev_params + * + * Return: QDF_STATUS_SUCCESS when the self peer is successfully deleted + * to firmware or QDF_STATUS_E_** when there is a failure. + */ +QDF_STATUS mlme_vdev_self_peer_delete(struct scheduler_msg *self_peer_del_msg); + +/** + * mlme_vdev_uses_self_peer() - does vdev use self peer? + * @vdev_type: vdev type + * @vdev_subtype: vdev subtype + * + * Return: true if the vdev type/subtype uses the self peer + */ +bool mlme_vdev_uses_self_peer(uint32_t vdev_type, uint32_t vdev_subtype); + +/** + * mlme_vdev_self_peer_delete_resp() - send vdev self peer delete resp to Upper + * layer + * @param: params of del vdev response + * + * Return: none + */ +void mlme_vdev_self_peer_delete_resp(struct del_vdev_params *param); + +/** + * mlme_vdev_del_resp() - send vdev delete resp to Upper layer + * @vdev_id: vdev id for which del vdev response is received + * + * Return: none + */ +void mlme_vdev_del_resp(uint8_t vdev_id); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * mlme_set_single_link_mlo_roaming() - to set single link mlo roaming + * @vdev: vdev pointer + * @val: single link mlo roaming value true/false + * + * This API will set single link mlo roaming value. + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_set_single_link_mlo_roaming(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * mlme_get_single_link_mlo_roaming() - get single link mlo roaming + * @vdev: vdev pointer + * + * Return: single link mlo roaming boolean value true/false + */ +bool mlme_get_single_link_mlo_roaming(struct wlan_objmgr_vdev *vdev); +#endif +/** + * wlan_sap_disconnect_all_p2p_client() - send SAP disconnect all P2P + * client event to the SAP event handler + * @vdev_id: vdev id of SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_disconnect_all_p2p_client(uint8_t vdev_id); + +/** + * wlan_sap_stop_bss() - send SAP stop bss event to the SAP event + * handler + * @vdev_id: vdev id of SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_stop_bss(uint8_t vdev_id); + +/** + * wlan_get_conc_freq() - get concurrent operation frequency + * + * Return: concurrent frequency + */ +qdf_freq_t wlan_get_conc_freq(void); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_handle_emlsr_sta_concurrency() - Handle concurrency scenarios with + * EMLSR STA. + * @psoc: pointer to psoc + * @conc_con_coming_up: Carries true if any concurrent connection(STA/SAP/NAN) + * is comng up + * @emlsr_sta_coming_up: Check if the new connection request is EMLSR STA + * + * The API handles concurrency scenarios with existing EMLSR connection when a + * new connection request is received OR with an existing legacy connection when + * an EMLSR sta comes up. + * + * Return: none + */ +void +wlan_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc, + bool conc_con_coming_up, + bool emlsr_sta_coming_up); +#else +static inline void +wlan_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc, + bool conc_con_coming_up, + bool emlsr_sta_coming_up) +{ +} +#endif + +#ifdef WLAN_FEATURE_LL_LT_SAP +/** + * wlan_ll_sap_sort_channel_list() - Sort channel list + * @vdev_id: Vdev Id + * @list: Pointer to list + * @ch_info: Pointer to ch_info + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_ll_sap_sort_channel_list(uint8_t vdev_id, qdf_list_t *list, + struct sap_sel_ch_info *ch_info); + +/** + * wlan_ll_sap_free_chan_info() - API to free allocated memory + * @ch_param: pointer to sap_sel_ch_info structure + * + * Return: None + */ +void wlan_ll_sap_free_chan_info(struct sap_sel_ch_info *ch_param); + +/** + * wlan_ll_sap_freq_present_in_pcl() - API to check whether given + * frequency is present in PCL or not + * @pcl: pcl list + * @freq: Frequency to check in PCL list + * + * Return: True/False + */ +bool wlan_ll_sap_freq_present_in_pcl(struct policy_mgr_pcl_list *pcl, + qdf_freq_t freq); +#endif + +/** + * wlan_sap_get_user_config_acs_ch_list: Get user configured channel list + * @vdev_id: Vdev Id + * @filter: Filter to apply to get scan result + * + * Return: None + * + */ +void +wlan_sap_get_user_config_acs_ch_list(uint8_t vdev_id, + struct scan_filter *filter); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c new file mode 100644 index 0000000000..5b1852d934 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_main.c @@ -0,0 +1,5825 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define internal APIs related to the mlme component + */ + +#include "wlan_mlme_main.h" +#include "include/wlan_vdev_mlme.h" +#include "cfg_ucfg_api.h" +#include "wmi_unified.h" +#include "wlan_scan_public_structs.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_vdev_mlme_api.h" +#include "wlan_mlme_api.h" +#include +#include +#include "wlan_mlme_ucfg_api.h" +#include "wifi_pos_ucfg_i.h" +#include "wlan_mlo_mgr_sta.h" +#include "twt/core/src/wlan_twt_cfg.h" +#include "wlan_scan_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_vdev_mgr_utils_api.h" +#include +#include + +#define NUM_OF_SOUNDING_DIMENSIONS 1 /*Nss - 1, (Nss = 2 for 2x2)*/ + +/* Time to passive scan dwell for scan to get channel stats, in milliseconds */ +#define MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME 40 +#define MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME 110 + +struct wlan_mlme_rx_ops * +mlme_get_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *psoc_ext_priv; + + if (!psoc) { + mlme_err("psoc object is NULL"); + return NULL; + } + psoc_ext_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!psoc_ext_priv) { + mlme_err("psoc legacy private object is NULL"); + return NULL; + } + + return &psoc_ext_priv->mlme_rx_ops; +} + +void wlan_mlme_register_rx_ops(struct wlan_mlme_rx_ops *rx_ops) +{ + rx_ops->peer_oper_mode_eventid = wlan_mlme_set_peer_indicated_ch_width; +} + +struct wlan_mlme_psoc_ext_obj *mlme_get_psoc_ext_obj_fl( + struct wlan_objmgr_psoc *psoc, + const char *func, uint32_t line) +{ + + return wlan_psoc_mlme_get_ext_hdl(psoc); +} + +struct wlan_mlme_nss_chains *mlme_get_dynamic_vdev_config( + struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + return &mlme_priv->dynamic_cfg; +} + +/* Buffer len size to consider the 4 char freq, and a space, Total 5 */ +#define MLME_CHAN_WEIGHT_CHAR_LEN 5 +#define MLME_MAX_CHAN_TO_PRINT 39 + +/** + * mlme_fill_freq_in_scan_start_request() - Fill frequencies in scan req + * @vdev: vdev common object + * @req: pointer to scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +mlme_fill_freq_in_scan_start_request(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + const struct bonded_channel_freq *range; + struct mlme_legacy_priv *mlme_priv; + enum phy_ch_width associated_ch_width; + uint8_t i; + struct chan_list *scan_chan_list; + qdf_freq_t first_freq, operation_chan_freq, sec_2g_freq; + char *chan_buff = NULL; + uint32_t buff_len, buff_num = 0, chan_count = 0; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + operation_chan_freq = wlan_get_operation_chan_freq(vdev); + associated_ch_width = + mlme_priv->connect_info.assoc_chan_info.assoc_ch_width; + if (associated_ch_width == CH_WIDTH_INVALID) { + mlme_debug("vdev %d : Invalid associated ch width for freq %d", + req->scan_req.vdev_id, operation_chan_freq); + return QDF_STATUS_E_FAILURE; + } + + req->scan_req.dwell_time_passive = + MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME; + req->scan_req.dwell_time_passive_6g = + MLME_GET_CHAN_STATS_PASSIVE_SCAN_TIME; + + if (associated_ch_width == CH_WIDTH_20MHZ) { + mlme_debug("vdev %d :Trigger scan for associated freq %d bw %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width); + req->scan_req.chan_list.num_chan = 1; + req->scan_req.chan_list.chan[0].freq = operation_chan_freq; + return QDF_STATUS_SUCCESS; + } + + if (wlan_reg_is_24ghz_ch_freq(operation_chan_freq) && + associated_ch_width == CH_WIDTH_40MHZ) { + sec_2g_freq = + mlme_priv->connect_info.assoc_chan_info.sec_2g_freq; + if (!sec_2g_freq) { + mlme_debug("vdev %d : Invalid sec 2g freq for freq: %d", + req->scan_req.vdev_id, operation_chan_freq); + return QDF_STATUS_E_FAILURE; + } + + if (operation_chan_freq > sec_2g_freq) { + req->scan_req.chan_list.chan[0].freq = sec_2g_freq; + req->scan_req.chan_list.chan[1].freq = + operation_chan_freq; + } else { + req->scan_req.chan_list.chan[0].freq = + operation_chan_freq; + req->scan_req.chan_list.chan[1].freq = sec_2g_freq; + } + + req->scan_req.chan_list.num_chan = 2; + return QDF_STATUS_SUCCESS; + } + + range = wlan_reg_get_bonded_chan_entry(operation_chan_freq, + associated_ch_width, 0); + if (!range) { + mlme_debug("vdev %d: Invalid freq range for freq: %d bw: %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width); + return QDF_STATUS_E_FAILURE; + } + + scan_chan_list = qdf_mem_malloc(sizeof(*scan_chan_list)); + if (!scan_chan_list) + return QDF_STATUS_E_NOMEM; + + scan_chan_list->num_chan = 0; + first_freq = range->start_freq; + for (; first_freq <= range->end_freq; first_freq += BW_20_MHZ) { + scan_chan_list->chan[scan_chan_list->num_chan].freq = + first_freq; + scan_chan_list->num_chan++; + } + + req->scan_req.chan_list.num_chan = scan_chan_list->num_chan; + + mlme_debug("vdev %d : freq %d bw %d, range [%d-%d], Total freq %d", + req->scan_req.vdev_id, operation_chan_freq, + associated_ch_width, range->start_freq, + range->end_freq, req->scan_req.chan_list.num_chan); + + buff_len = (QDF_MIN(req->scan_req.chan_list.num_chan, + MLME_MAX_CHAN_TO_PRINT) * MLME_CHAN_WEIGHT_CHAR_LEN) + 1; + + chan_buff = qdf_mem_malloc(buff_len); + if (!chan_buff) { + qdf_mem_free(scan_chan_list); + return QDF_STATUS_E_NOMEM; + } + for (i = 0; i < req->scan_req.chan_list.num_chan; i++) { + req->scan_req.chan_list.chan[i].freq = + scan_chan_list->chan[i].freq; + buff_num += qdf_scnprintf(chan_buff + buff_num, + buff_len - buff_num, " %d", + req->scan_req.chan_list.chan[i].freq); + chan_count++; + if (chan_count >= MLME_MAX_CHAN_TO_PRINT) { + mlme_debug("Freq list: %s", chan_buff); + buff_num = 0; + chan_count = 0; + } + } + + if (buff_num) + mlme_debug("Freq list: %s", chan_buff); + + qdf_mem_free(chan_buff); + qdf_mem_free(scan_chan_list); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +static enum scan_phy_mode mlme_get_scan_phy_mode(void) +{ + return SCAN_PHY_MODE_11BE_EHT160; +} + +static enum scan_phy_mode +wlan_scan_get_11be_scan_phy_mode(enum wlan_phymode ch_phymode) +{ + enum scan_phy_mode scan_phymode; + + switch (ch_phymode) { + case WLAN_PHYMODE_11BEA_EHT20: + scan_phymode = SCAN_PHY_MODE_11BE_EHT20; + break; + case WLAN_PHYMODE_11BEG_EHT20: + scan_phymode = SCAN_PHY_MODE_11BE_EHT20_2G; + break; + case WLAN_PHYMODE_11BEA_EHT40: + scan_phymode = SCAN_PHY_MODE_11BE_EHT40; + break; + case WLAN_PHYMODE_11BEG_EHT40: + scan_phymode = SCAN_PHY_MODE_11BE_EHT40_2G; + break; + case WLAN_PHYMODE_11BEA_EHT80: + scan_phymode = SCAN_PHY_MODE_11BE_EHT80; + break; + case WLAN_PHYMODE_11BEG_EHT80: + scan_phymode = SCAN_PHY_MODE_11BE_EHT80_2G; + break; + case WLAN_PHYMODE_11BEA_EHT160: + scan_phymode = SCAN_PHY_MODE_11BE_EHT160; + break; + case WLAN_PHYMODE_11BEA_EHT320: + scan_phymode = SCAN_PHY_MODE_11BE_EHT320; + break; + default: + scan_phymode = SCAN_PHY_MODE_UNKNOWN; + break; + } + + return scan_phymode; +} +#else +static inline enum scan_phy_mode mlme_get_scan_phy_mode(void) +{ + return SCAN_PHY_MODE_UNKNOWN; +} + +static inline enum scan_phy_mode +wlan_scan_get_11be_scan_phy_mode(enum wlan_phymode ch_phymode) +{ + return SCAN_PHY_MODE_UNKNOWN; +} +#endif + +/** + * wlan_scan_get_scan_phy_mode() - get scan phymode from channel phy mode + * @vdev: vdev common object + * @op_freq: operational frequency + * @vdev_id: vdev id + * + * Return: enum scan_phy_mode + */ +static enum scan_phy_mode +wlan_scan_get_scan_phy_mode(struct wlan_objmgr_vdev *vdev, qdf_freq_t op_freq, + uint32_t vdev_id) +{ + struct wlan_channel *des_chan; + enum scan_phy_mode scan_phymode = SCAN_PHY_MODE_UNKNOWN; + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) { + mlme_debug("vdev %d : des_chan is null", vdev_id); + return scan_phymode; + } + + switch (des_chan->ch_phymode) { + case WLAN_PHYMODE_11A: + scan_phymode = SCAN_PHY_MODE_11A; + break; + case WLAN_PHYMODE_11B: + scan_phymode = SCAN_PHY_MODE_11B; + break; + case WLAN_PHYMODE_11G: + scan_phymode = SCAN_PHY_MODE_11G; + break; + case WLAN_PHYMODE_11G_ONLY: + scan_phymode = SCAN_PHY_MODE_11GONLY; + break; + case WLAN_PHYMODE_11NA_HT20: + scan_phymode = SCAN_PHY_MODE_11NA_HT20; + break; + case WLAN_PHYMODE_11NG_HT20: + scan_phymode = SCAN_PHY_MODE_11NG_HT20; + break; + case WLAN_PHYMODE_11NA_HT40: + scan_phymode = SCAN_PHY_MODE_11NA_HT40; + break; + case WLAN_PHYMODE_11NG_HT40: + scan_phymode = SCAN_PHY_MODE_11NG_HT40; + break; + case WLAN_PHYMODE_11AC_VHT20: + scan_phymode = SCAN_PHY_MODE_11AC_VHT20; + break; + case WLAN_PHYMODE_11AC_VHT40: + scan_phymode = SCAN_PHY_MODE_11AC_VHT40; + break; + case WLAN_PHYMODE_11AC_VHT80: + scan_phymode = SCAN_PHY_MODE_11AC_VHT80; + break; + case WLAN_PHYMODE_11AC_VHT20_2G: + scan_phymode = SCAN_PHY_MODE_11AC_VHT20_2G; + break; + case WLAN_PHYMODE_11AC_VHT40_2G: + scan_phymode = SCAN_PHY_MODE_11AC_VHT40_2G; + break; + case WLAN_PHYMODE_11AC_VHT80_2G: + scan_phymode = SCAN_PHY_MODE_11AC_VHT80_2G; + break; + case WLAN_PHYMODE_11AC_VHT80_80: + scan_phymode = SCAN_PHY_MODE_11AC_VHT80_80; + break; + case WLAN_PHYMODE_11AC_VHT160: + scan_phymode = SCAN_PHY_MODE_11AC_VHT160; + break; + case WLAN_PHYMODE_11AXA_HE20: + scan_phymode = SCAN_PHY_MODE_11AX_HE20; + break; + case WLAN_PHYMODE_11AXG_HE20: + scan_phymode = SCAN_PHY_MODE_11AX_HE20_2G; + break; + case WLAN_PHYMODE_11AXA_HE40: + scan_phymode = SCAN_PHY_MODE_11AX_HE40; + break; + case WLAN_PHYMODE_11AXG_HE40: + scan_phymode = SCAN_PHY_MODE_11AX_HE40_2G; + break; + case WLAN_PHYMODE_11AXA_HE80: + scan_phymode = SCAN_PHY_MODE_11AX_HE80; + break; + case WLAN_PHYMODE_11AXG_HE80: + scan_phymode = SCAN_PHY_MODE_11AX_HE80_2G; + break; + case WLAN_PHYMODE_11AXA_HE80_80: + scan_phymode = SCAN_PHY_MODE_11AX_HE80_80; + break; + case WLAN_PHYMODE_11AXA_HE160: + scan_phymode = SCAN_PHY_MODE_11AX_HE160; + break; + default: + scan_phymode = SCAN_PHY_MODE_UNKNOWN; + break; + } + + if (scan_phymode != SCAN_PHY_MODE_UNKNOWN) + return scan_phymode; + + scan_phymode = wlan_scan_get_11be_scan_phy_mode(des_chan->ch_phymode); + + return scan_phymode; +} + +#ifdef WLAN_FEATURE_11BE +/** + * mlme_get_scan_phy_mode_for_chan_load() - get scan phymode from ch width + * @scan_ch_width: channel width + * + * Return: enum scan_phy_mode + */ +static enum scan_phy_mode +mlme_get_scan_phy_mode_for_chan_load(enum phy_ch_width scan_ch_width) +{ + enum scan_phy_mode scan_phymode = SCAN_PHY_MODE_UNKNOWN; + + switch (scan_ch_width) { + case CH_WIDTH_20MHZ: + scan_phymode = SCAN_PHY_MODE_11BE_EHT20; + break; + case CH_WIDTH_40MHZ: + scan_phymode = SCAN_PHY_MODE_11BE_EHT40; + break; + case CH_WIDTH_80MHZ: + scan_phymode = SCAN_PHY_MODE_11BE_EHT80; + break; + case CH_WIDTH_160MHZ: + scan_phymode = SCAN_PHY_MODE_11BE_EHT160; + break; + default: + mlme_debug("Invalid scan_ch_width:%d", scan_ch_width); + break; + } + + return scan_phymode; +} +#else +static inline enum scan_phy_mode +mlme_get_scan_phy_mode_for_chan_load(enum phy_ch_width scan_ch_width) +{ + return SCAN_PHY_MODE_UNKNOWN; +} +#endif + +QDF_STATUS +mlme_update_freq_in_scan_start_req(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req, + enum phy_ch_width scan_ch_width, + qdf_freq_t scan_freq, + qdf_freq_t cen320_freq) +{ + const struct bonded_channel_freq *range; + uint8_t num_chan; + qdf_freq_t op_freq, center_20_freq, start_freq, end_freq; + enum scan_phy_mode phymode = SCAN_PHY_MODE_UNKNOWN; + uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; + + if (scan_freq != INVALID_CHANNEL) + op_freq = scan_freq; + else + op_freq = wlan_get_operation_chan_freq(vdev); + + mlme_debug("vdev %d :op_freq:%d, cen320_freq:%d, scan_ch_width: %d", + vdev_id, op_freq, cen320_freq, scan_ch_width); + + if (scan_ch_width == CH_WIDTH_320MHZ) { + if (!cen320_freq) + return QDF_STATUS_E_FAILURE; + range = wlan_reg_get_bonded_chan_entry(op_freq, + scan_ch_width, + cen320_freq); + if (!range) { + mlme_debug("vdev %d : range is null for freq %d", + vdev_id, op_freq); + return QDF_STATUS_E_FAILURE; + } + + phymode = mlme_get_scan_phy_mode(); + if (phymode == SCAN_PHY_MODE_UNKNOWN) { + mlme_debug("vdev %d : invalid scan phymode for freq %d", + vdev_id, op_freq); + return QDF_STATUS_E_FAILURE; + } + + start_freq = range->start_freq; + end_freq = range->end_freq; + + /* fill connected 6 GHz ML link freq in wide band scan list */ + center_20_freq = start_freq + (7 * BW_20_MHZ); + if (op_freq > center_20_freq) + end_freq = op_freq; + else + start_freq = op_freq; + + num_chan = req->scan_req.chan_list.num_chan; + req->scan_req.chan_list.chan[num_chan].freq = start_freq; + req->scan_req.chan_list.chan[num_chan].phymode = phymode; + num_chan += 1; + req->scan_req.chan_list.chan[num_chan].freq = end_freq; + req->scan_req.chan_list.chan[num_chan].phymode = phymode; + num_chan += 1; + req->scan_req.chan_list.num_chan = num_chan; + } else { + if (scan_freq != INVALID_CHANNEL) + phymode = mlme_get_scan_phy_mode_for_chan_load(scan_ch_width); + else + phymode = wlan_scan_get_scan_phy_mode(vdev, op_freq, vdev_id); + + if (phymode == SCAN_PHY_MODE_UNKNOWN) { + mlme_debug("vdev %d : invalid scan phymode for freq %d", + vdev_id, op_freq); + return QDF_STATUS_E_FAILURE; + } + + num_chan = req->scan_req.chan_list.num_chan; + req->scan_req.chan_list.chan[num_chan].freq = op_freq; + req->scan_req.chan_list.chan[num_chan].phymode = phymode; + req->scan_req.chan_list.num_chan += 1; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * mlme_update_freq_from_link_ctx() - This API updates scan request from + * link context + * @links_info: pointer to MLO link info + * @req: pointer to scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +mlme_update_freq_from_link_ctx(struct mlo_link_info *links_info, + struct scan_start_request *req) +{ + const struct bonded_channel_freq *range; + uint8_t num_chan; + qdf_freq_t op_freq, center_20_freq, start_freq, end_freq; + enum scan_phy_mode phymode; + enum phy_ch_width scan_ch_width; + struct wlan_channel *link_chan_info = links_info->link_chan_info; + + if (!link_chan_info) { + mlme_err("link chan info is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + op_freq = link_chan_info->ch_freq; + phymode = wlan_scan_get_11be_scan_phy_mode(link_chan_info->ch_phymode); + if (phymode == SCAN_PHY_MODE_UNKNOWN) { + mlme_err("invalid scan phymode for freq %d", op_freq); + return QDF_STATUS_E_INVAL; + } + + scan_ch_width = wlan_mlme_get_ch_width_from_phymode( + link_chan_info->ch_phymode); + + if (scan_ch_width == CH_WIDTH_320MHZ) { + range = wlan_reg_get_bonded_chan_entry(op_freq, scan_ch_width, + link_chan_info->ch_cfreq2); + if (!range) { + mlme_err("range is null for freq %d center freq %d", + op_freq, link_chan_info->ch_cfreq2); + return QDF_STATUS_E_NULL_VALUE; + } + + start_freq = range->start_freq; + end_freq = range->end_freq; + + /* fill connected 6 GHz ML link freq in wide band scan list */ + center_20_freq = start_freq + (7 * BW_20_MHZ); + if (op_freq > center_20_freq) + end_freq = op_freq; + else + start_freq = op_freq; + + mlme_debug("op_freq:%d, c_freq:%d, start_freq:%d, end_freq:%d", + op_freq, center_20_freq, start_freq, end_freq); + + num_chan = req->scan_req.chan_list.num_chan; + req->scan_req.chan_list.chan[num_chan].freq = start_freq; + req->scan_req.chan_list.chan[num_chan].phymode = phymode; + num_chan += 1; + req->scan_req.chan_list.chan[num_chan].freq = end_freq; + req->scan_req.chan_list.chan[num_chan].phymode = phymode; + num_chan += 1; + req->scan_req.chan_list.num_chan = num_chan; + } else { + num_chan = req->scan_req.chan_list.num_chan; + req->scan_req.chan_list.chan[num_chan].freq = op_freq; + req->scan_req.chan_list.chan[num_chan].phymode = phymode; + req->scan_req.chan_list.num_chan += 1; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * mlme_fill_freq_in_mlo_wide_band_scan_start_req() - Fill frequencies in wide + * band scan req for mlo connection + * @vdev: vdev common object + * @req: pointer to scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +mlme_fill_freq_in_mlo_wide_band_scan_start_req(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint8_t i; + QDF_STATUS status; + struct mlo_link_switch_context *link_ctx; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + mlme_err("vdev %d :mlo_dev_ctx is NULL", req->scan_req.vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + link_ctx = mlo_dev_ctx->link_ctx; + if (!link_ctx) { + mlme_err("vdev %d :mlo_link_ctx is NULL", + req->scan_req.vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS && + link_ctx->links_info[i].link_id != WLAN_INVALID_LINK_ID; i++) { + status = mlme_update_freq_from_link_ctx( + &link_ctx->links_info[i], req); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("freq update fails for link id %d", + link_ctx->links_info[i].link_id); + return status; + } + } + + mlme_debug("vdev %d :trigger wide band scan for mlo conn, num freq %d", + req->scan_req.vdev_id, req->scan_req.chan_list.num_chan); + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +mlme_fill_freq_in_mlo_wide_band_scan_start_req(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * mlme_fill_freq_in_wide_scan_start_request() - Fill frequencies in wide band + * scan req + * @vdev: vdev common object + * @req: pointer to scan request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +mlme_fill_freq_in_wide_scan_start_request(struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + struct mlme_legacy_priv *mlme_priv; + enum phy_ch_width associated_ch_width; + QDF_STATUS status; + qdf_freq_t assoc_cen320_freq = 0; + + req->scan_req.chan_list.num_chan = 0; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + status = mlme_fill_freq_in_mlo_wide_band_scan_start_req(vdev, + req); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + goto update_param; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + associated_ch_width = + mlme_priv->connect_info.assoc_chan_info.assoc_ch_width; + if (associated_ch_width == CH_WIDTH_INVALID) { + mlme_debug("vdev %d :Invalid associated ch_width", + req->scan_req.vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* Set center frequency of complete 320MHz */ + assoc_cen320_freq = mlme_priv->connect_info.assoc_chan_info.cen320_freq; + + status = mlme_update_freq_in_scan_start_req(vdev, req, + associated_ch_width, + INVALID_CHANNEL, + assoc_cen320_freq); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + mlme_debug("vdev %d :trigger wide band scan, num freq %d", + req->scan_req.vdev_id, req->scan_req.chan_list.num_chan); + +update_param: + req->scan_req.dwell_time_passive = + MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME; + req->scan_req.dwell_time_passive_6g = + MLME_GET_CHAN_STATS_WIDE_BAND_PASSIVE_SCAN_TIME; + + req->scan_req.scan_f_wide_band = true; + /* + * FW report CCA busy for each possible 20Mhz subbands of the + * wideband scan channel if below flag is true + */ + req->scan_req.scan_f_report_cca_busy_for_each_20mhz = true; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct scan_start_request *req; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_debug("vdev %d : NULL mlme psoc object", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_debug("vdev %d : NULL vdev object", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_NOMEM; + } + + status = wlan_scan_init_default_params(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto release; + + req->scan_req.scan_id = wlan_scan_get_scan_id(psoc); + req->scan_req.scan_req_id = mlme_obj->scan_requester_id; + req->scan_req.vdev_id = vdev_id; + + req->scan_req.scan_type = SCAN_TYPE_DEFAULT; + + /* Fill channel list as per fw capability */ + if (wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_CCA_BUSY_INFO_FOREACH_20MHZ)) { + status = mlme_fill_freq_in_wide_scan_start_request(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto release; + } else { + status = mlme_fill_freq_in_scan_start_request(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto release; + } + + /* disable adatptive dwell time */ + req->scan_req.adaptive_dwell_time_mode = SCAN_DWELL_MODE_STATIC; + /* to disable early 6Ghz scan bail out */ + req->scan_req.min_dwell_time_6g = 0; + /* passive scan for CCA measurement */ + req->scan_req.scan_f_passive = true; + /* Fw pause home channel when scan channel is same as home channel */ + req->scan_req.scan_f_pause_home_channel = true; + + status = wlan_scan_start(req); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("vdev %d :Failed to send scan req, status %d", + vdev_id, status); + goto release; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return status; +release: + qdf_mem_free(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return status; +} + +uint32_t mlme_get_vdev_he_ops(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct vdev_mlme_obj *mlme_obj; + uint32_t he_ops = 0; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return he_ops; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_err("Failed to get vdev MLME Obj"); + return he_ops; + } + + he_ops = mlme_obj->proto.he_ops_info.he_ops; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return he_ops; +} + +struct wlan_mlme_nss_chains *mlme_get_ini_vdev_config( + struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + return &mlme_priv->ini_cfg; +} + +uint8_t *mlme_get_dynamic_oce_flags(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + return &mlme_priv->sta_dynamic_oce_value; +} + +QDF_STATUS mlme_init_rate_config(struct vdev_mlme_obj *vdev_mlme) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = vdev_mlme->ext_vdev_ptr; + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->opr_rate_set.max_len = + QDF_MIN(CFG_OPERATIONAL_RATE_SET_LEN, CFG_STR_DATA_LEN); + mlme_priv->opr_rate_set.len = 0; + mlme_priv->ext_opr_rate_set.max_len = + QDF_MIN(CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN, + CFG_STR_DATA_LEN); + mlme_priv->ext_opr_rate_set.len = 0; + mlme_priv->mcs_rate_set.max_len = + QDF_MIN(CFG_SUPPORTED_MCS_SET_LEN, CFG_STR_DATA_LEN); + mlme_priv->mcs_rate_set.len = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_init_connect_chan_info_config(struct vdev_mlme_obj *vdev_mlme) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = vdev_mlme->ext_vdev_ptr; + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->connect_info.assoc_chan_info.assoc_ch_width = + CH_WIDTH_INVALID; + mlme_priv->connect_info.assoc_chan_info.omn_ie_ch_width = + CH_WIDTH_INVALID; + mlme_priv->connect_info.assoc_chan_info.sec_2g_freq = 0; + mlme_priv->connect_info.assoc_chan_info.cen320_freq = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_get_peer_mic_len(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, + uint8_t *peer_mac, uint8_t *mic_len, + uint8_t *mic_hdr_len) +{ + struct wlan_objmgr_peer *peer; + int32_t key_cipher; + + if (!psoc || !mic_len || !mic_hdr_len || !peer_mac) { + mlme_legacy_debug("psoc/mic_len/mic_hdr_len/peer_mac null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_objmgr_get_peer(psoc, pdev_id, + peer_mac, WLAN_LEGACY_MAC_ID); + if (!peer) { + mlme_legacy_debug("Peer of peer_mac "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(peer_mac)); + return QDF_STATUS_E_INVAL; + } + + key_cipher = + wlan_crypto_get_peer_param(peer, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + if (key_cipher < 0) { + mlme_legacy_err("Invalid mgmt cipher"); + return QDF_STATUS_E_INVAL; + } + + if (key_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_GCM) || + key_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_GCM_256)) { + *mic_hdr_len = WLAN_IEEE80211_GCMP_HEADERLEN; + *mic_len = WLAN_IEEE80211_GCMP_MICLEN; + } else { + *mic_hdr_len = IEEE80211_CCMP_HEADERLEN; + *mic_len = IEEE80211_CCMP_MICLEN; + } + mlme_legacy_debug("peer "QDF_MAC_ADDR_FMT" hdr_len %d mic_len %d key_cipher 0x%x", + QDF_MAC_ADDR_REF(peer_mac), + *mic_hdr_len, *mic_len, key_cipher); + + return QDF_STATUS_SUCCESS; +} + +void +wlan_acquire_peer_key_wakelock(struct wlan_objmgr_pdev *pdev, uint8_t *mac_addr) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_LEGACY_MAC_ID); + if (!peer) + return; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return; + } + + if (peer_priv->is_key_wakelock_set) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return; + } + + mlme_debug(QDF_MAC_ADDR_FMT ": Acquire set key wake lock for %d ms", + QDF_MAC_ADDR_REF(mac_addr), + MLME_PEER_SET_KEY_WAKELOCK_TIMEOUT); + qdf_wake_lock_timeout_acquire(&peer_priv->peer_set_key_wakelock, + MLME_PEER_SET_KEY_WAKELOCK_TIMEOUT); + qdf_runtime_pm_prevent_suspend( + &peer_priv->peer_set_key_runtime_wakelock); + peer_priv->is_key_wakelock_set = true; + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +void +wlan_release_peer_key_wakelock(struct wlan_objmgr_pdev *pdev, uint8_t *mac_addr) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_LEGACY_MAC_ID); + if (!peer) + return; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return; + } + + if (!peer_priv->is_key_wakelock_set) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return; + } + + peer_priv->is_key_wakelock_set = false; + mlme_debug(QDF_MAC_ADDR_FMT ": Release set key wake lock", + QDF_MAC_ADDR_REF(mac_addr)); + qdf_wake_lock_release(&peer_priv->peer_set_key_wakelock, + WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_runtime_pm_allow_suspend( + &peer_priv->peer_set_key_runtime_wakelock); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +QDF_STATUS +mlme_peer_object_created_notification(struct wlan_objmgr_peer *peer, + void *arg) +{ + struct peer_mlme_priv_obj *peer_priv; + QDF_STATUS status; + + if (!peer) { + mlme_legacy_err(" peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = qdf_mem_malloc(sizeof(*peer_priv)); + if (!peer_priv) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_peer_component_obj_attach(peer, + WLAN_UMAC_COMP_MLME, + (void *)peer_priv, + QDF_STATUS_SUCCESS); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_legacy_err("unable to attach peer_priv obj to peer obj"); + qdf_mem_free(peer_priv); + return status; + } + + qdf_wake_lock_create(&peer_priv->peer_set_key_wakelock, "peer_set_key"); + qdf_runtime_lock_init(&peer_priv->peer_set_key_runtime_wakelock); + peer_priv->is_key_wakelock_set = false; + peer_priv->peer_ind_bw = CH_WIDTH_INVALID; + + return status; +} + +QDF_STATUS +mlme_peer_object_destroyed_notification(struct wlan_objmgr_peer *peer, + void *arg) +{ + struct peer_mlme_priv_obj *peer_priv; + QDF_STATUS status; + + if (!peer) { + mlme_legacy_err(" peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_legacy_err(" peer MLME component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv->is_key_wakelock_set = false; + qdf_runtime_lock_deinit(&peer_priv->peer_set_key_runtime_wakelock); + qdf_wake_lock_destroy(&peer_priv->peer_set_key_wakelock); + + status = wlan_objmgr_peer_component_obj_detach(peer, + WLAN_UMAC_COMP_MLME, + peer_priv); + + if (QDF_IS_STATUS_ERROR(status)) + mlme_legacy_err("unable to detach peer_priv obj to peer obj"); + + mlme_free_peer_assoc_rsp_ie(peer_priv); + qdf_mem_free(peer_priv); + + return status; +} + +static void mlme_init_chainmask_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_chainmask *chainmask_info) +{ + chainmask_info->txchainmask1x1 = + cfg_get(psoc, CFG_VHT_ENABLE_1x1_TX_CHAINMASK); + + chainmask_info->rxchainmask1x1 = + cfg_get(psoc, CFG_VHT_ENABLE_1x1_RX_CHAINMASK); + + chainmask_info->tx_chain_mask_cck = + cfg_get(psoc, CFG_TX_CHAIN_MASK_CCK); + + chainmask_info->tx_chain_mask_1ss = + cfg_get(psoc, CFG_TX_CHAIN_MASK_1SS); + + chainmask_info->num_11b_tx_chains = + cfg_get(psoc, CFG_11B_NUM_TX_CHAIN); + + chainmask_info->num_11ag_tx_chains = + cfg_get(psoc, CFG_11AG_NUM_TX_CHAIN); + + chainmask_info->tx_chain_mask_2g = + cfg_get(psoc, CFG_TX_CHAIN_MASK_2G); + + chainmask_info->rx_chain_mask_2g = + cfg_get(psoc, CFG_RX_CHAIN_MASK_2G); + + chainmask_info->tx_chain_mask_5g = + cfg_get(psoc, CFG_TX_CHAIN_MASK_5G); + + chainmask_info->rx_chain_mask_5g = + cfg_get(psoc, CFG_RX_CHAIN_MASK_5G); + + chainmask_info->enable_bt_chain_separation = + cfg_get(psoc, CFG_ENABLE_BT_CHAIN_SEPARATION); +} + +static void mlme_init_ratemask_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_ratemask *ratemask_cfg) +{ + uint32_t masks[CFG_MLME_RATE_MASK_LEN] = { 0 }; + qdf_size_t len = 0; + QDF_STATUS status; + + ratemask_cfg->type = cfg_get(psoc, CFG_RATEMASK_TYPE); + if ((ratemask_cfg->type <= WLAN_MLME_RATEMASK_TYPE_NO_MASK) || + (ratemask_cfg->type >= WLAN_MLME_RATEMASK_TYPE_MAX)) { + mlme_legacy_debug("Ratemask disabled"); + return; + } + + status = qdf_uint32_array_parse(cfg_get(psoc, CFG_RATEMASK_SET), + masks, + CFG_MLME_RATE_MASK_LEN, + &len); + + if (status != QDF_STATUS_SUCCESS || len != CFG_MLME_RATE_MASK_LEN) { + /* Do not enable ratemask if config is invalid */ + ratemask_cfg->type = WLAN_MLME_RATEMASK_TYPE_NO_MASK; + mlme_legacy_err("Failed to parse ratemask"); + return; + } + + ratemask_cfg->lower32 = masks[0]; + ratemask_cfg->higher32 = masks[1]; + ratemask_cfg->lower32_2 = masks[2]; + ratemask_cfg->higher32_2 = masks[3]; + mlme_legacy_debug("Ratemask type: %d, masks:0x%x, 0x%x, 0x%x, 0x%x", + ratemask_cfg->type, ratemask_cfg->lower32, + ratemask_cfg->higher32, ratemask_cfg->lower32_2, + ratemask_cfg->higher32_2); +} + +static void mlme_init_pmf_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->pmf_sa_query_max_retries = + cfg_get(psoc, CFG_PMF_SA_QUERY_MAX_RETRIES); + gen->pmf_sa_query_retry_interval = + cfg_get(psoc, CFG_PMF_SA_QUERY_RETRY_INTERVAL); +} + +#ifdef WLAN_FEATURE_11BE +static inline void mlme_init_oem_eht_mlo_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->oem_eht_mlo_crypto_bitmap = + cfg_get(psoc, CFG_OEM_EHT_MLO_CRYPTO_BITMAP); +} +#else +static inline void mlme_init_oem_eht_mlo_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +#ifdef WLAN_FEATURE_LPSS +static inline void +mlme_init_lpass_support_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->lpass_support = cfg_get(psoc, CFG_ENABLE_LPASS_SUPPORT); +} +#else +static inline void +mlme_init_lpass_support_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->lpass_support = cfg_default(CFG_ENABLE_LPASS_SUPPORT); +} +#endif + +#ifdef FEATURE_WDS +/** + * mlme_init_wds_config_cfg() - initialize wds_mode flag + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_wds_config_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->wds_mode = cfg_get(psoc, CFG_WDS_MODE); +} +#else +static void mlme_init_wds_config_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ +} +#endif + +#ifdef CONFIG_BAND_6GHZ +/** + * mlme_init_disable_vlp_sta_conn_to_sp_ap() - initialize disable vlp STA + * connection to sp AP flag + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_disable_vlp_sta_conn_to_sp_ap( + struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->disable_vlp_sta_conn_to_sp_ap = + cfg_default(CFG_DISABLE_VLP_STA_CONN_TO_SP_AP); +} +#else +static void mlme_init_disable_vlp_sta_conn_to_sp_ap( + struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ +} +#endif + +#ifdef CONFIG_BAND_6GHZ +/** + * mlme_init_standard_6ghz_conn_policy() - initialize standard 6GHz + * policy connection flag + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_standard_6ghz_conn_policy(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->std_6ghz_conn_policy = + cfg_get(psoc, CFG_6GHZ_STANDARD_CONNECTION_POLICY); +} +#else +static void mlme_init_standard_6ghz_conn_policy(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ +} +#endif + +/** + * mlme_init_mgmt_hw_tx_retry_count_cfg() - initialize mgmt hw tx retry count + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_mgmt_hw_tx_retry_count_cfg( + struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + uint32_t i; + qdf_size_t out_size = 0; + uint8_t count_array[MGMT_FRM_HW_TX_RETRY_COUNT_STR_LEN]; + + qdf_uint8_array_parse(cfg_get(psoc, CFG_MGMT_FRAME_HW_TX_RETRY_COUNT), + count_array, + MGMT_FRM_HW_TX_RETRY_COUNT_STR_LEN, + &out_size); + + for (i = 0; i + 1 < out_size; i += 2) { + if (count_array[i] >= CFG_FRAME_TYPE_MAX) { + mlme_legacy_debug("invalid frm type %d", + count_array[i]); + continue; + } + if (count_array[i + 1] >= MAX_MGMT_HW_TX_RETRY_COUNT) { + mlme_legacy_debug("mgmt hw tx retry count %d for frm %d, limit to %d", + count_array[i + 1], + count_array[i], + MAX_MGMT_HW_TX_RETRY_COUNT); + gen->mgmt_hw_tx_retry_count[count_array[i]] = + MAX_MGMT_HW_TX_RETRY_COUNT; + } else { + mlme_legacy_debug("mgmt hw tx retry count %d for frm %d", + count_array[i + 1], + count_array[i]); + gen->mgmt_hw_tx_retry_count[count_array[i]] = + count_array[i + 1]; + } + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * mlme_init_emlsr_mode() - initialize emlsr mode enable flag + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_emlsr_mode(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->enable_emlsr_mode = cfg_default(CFG_EMLSR_MODE_ENABLE); +} + +/** + * mlme_init_tl2m_negotiation_support() - initialize t2lm support + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_tl2m_negotiation_support(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->t2lm_negotiation_support = cfg_get(psoc, + CFG_T2LM_NEGOTIATION_SUPPORT); +} +#else +static void mlme_init_emlsr_mode(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ +} + +static void mlme_init_tl2m_negotiation_support(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ +} +#endif + +#if defined(WLAN_FEATURE_SR) +/** + * mlme_init_sr_ini_cfg() - initialize SR(Spatial Reuse) ini + * @psoc: Pointer to PSOC + * @gen: pointer to generic CFG items + * + * Return: None + */ +static void mlme_init_sr_ini_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->sr_enable_modes = cfg_get(psoc, CFG_SR_ENABLE_MODES); +} +#else +static void mlme_init_sr_ini_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{} +#endif + +static void mlme_init_generic_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_generic *gen) +{ + gen->rtt3_enabled = cfg_default(CFG_RTT3_ENABLE); + gen->rtt_mac_randomization = + cfg_get(psoc, CFG_ENABLE_RTT_MAC_RANDOMIZATION); + gen->band_capability = + cfg_get(psoc, CFG_BAND_CAPABILITY); + if (!gen->band_capability) + gen->band_capability = REG_BAND_MASK_ALL; + gen->band = gen->band_capability; + gen->select_5ghz_margin = + cfg_get(psoc, CFG_SELECT_5GHZ_MARGIN); + gen->sub_20_chan_width = + cfg_get(psoc, CFG_SUB_20_CHANNEL_WIDTH); + gen->ito_repeat_count = + cfg_get(psoc, CFG_ITO_REPEAT_COUNT); + gen->dropped_pkt_disconnect_thresh = + cfg_get(psoc, CFG_DROPPED_PKT_DISCONNECT_THRESHOLD); + gen->prevent_link_down = + cfg_get(psoc, CFG_PREVENT_LINK_DOWN); + gen->memory_deep_sleep = + cfg_get(psoc, CFG_ENABLE_MEM_DEEP_SLEEP); + gen->cck_tx_fir_override = + cfg_get(psoc, CFG_ENABLE_CCK_TX_FIR_OVERRIDE); + gen->crash_inject = + cfg_get(psoc, CFG_ENABLE_CRASH_INJECT); + gen->self_recovery = + cfg_get(psoc, CFG_ENABLE_SELF_RECOVERY); + gen->sap_dot11mc = + cfg_get(psoc, CFG_SAP_DOT11MC); + gen->fatal_event_trigger = + cfg_get(psoc, CFG_ENABLE_FATAL_EVENT_TRIGGER); + gen->optimize_ca_event = + cfg_get(psoc, CFG_OPTIMIZE_CA_EVENT); + gen->fw_timeout_crash = + cfg_get(psoc, CFG_CRASH_FW_TIMEOUT); + gen->debug_packet_log = cfg_get(psoc, CFG_ENABLE_DEBUG_PACKET_LOG); + gen->enable_deauth_to_disassoc_map = + cfg_get(psoc, CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP); + gen->wls_6ghz_capable = cfg_get(psoc, CFG_WLS_6GHZ_CAPABLE); + mlme_init_pmf_cfg(psoc, gen); + mlme_init_oem_eht_mlo_cfg(psoc, gen); + mlme_init_lpass_support_cfg(psoc, gen); + gen->enabled_rf_test_mode = cfg_default(CFG_RF_TEST_MODE_SUPP_ENABLED); + gen->enabled_11h = cfg_get(psoc, CFG_11H_SUPPORT_ENABLED); + gen->enabled_11d = cfg_get(psoc, CFG_11D_SUPPORT_ENABLED); + gen->enable_beacon_reception_stats = + cfg_get(psoc, CFG_ENABLE_BEACON_RECEPTION_STATS); + gen->disable_4way_hs_offload = + cfg_get(psoc, CFG_DISABLE_4WAY_HS_OFFLOAD); + gen->mgmt_retry_max = cfg_get(psoc, CFG_MGMT_RETRY_MAX); + gen->bmiss_skip_full_scan = cfg_get(psoc, CFG_BMISS_SKIP_FULL_SCAN); + gen->enable_ring_buffer = cfg_get(psoc, CFG_ENABLE_RING_BUFFER); + gen->enable_peer_unmap_conf_support = + cfg_get(psoc, CFG_DP_ENABLE_PEER_UMAP_CONF_SUPPORT); + gen->dfs_chan_ageout_time = + cfg_get(psoc, CFG_DFS_CHAN_AGEOUT_TIME); + gen->sae_connect_retries = + cfg_get(psoc, CFG_SAE_CONNECION_RETRIES); + gen->monitor_mode_concurrency = + cfg_get(psoc, CFG_MONITOR_MODE_CONCURRENCY); + gen->tx_retry_multiplier = cfg_get(psoc, CFG_TX_RETRY_MULTIPLIER); + gen->enable_he_mcs0_for_6ghz_mgmt = + cfg_get(psoc, CFG_ENABLE_HE_MCS0_MGMT_6GHZ); + mlme_init_sr_ini_cfg(psoc, gen); + mlme_init_wds_config_cfg(psoc, gen); + mlme_init_mgmt_hw_tx_retry_count_cfg(psoc, gen); + mlme_init_emlsr_mode(psoc, gen); + mlme_init_tl2m_negotiation_support(psoc, gen); + mlme_init_standard_6ghz_conn_policy(psoc, gen); + mlme_init_disable_vlp_sta_conn_to_sp_ap(psoc, gen); +} + +static void mlme_init_edca_ani_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_edca_params *edca_params) +{ + /* initialize the max allowed array length for read/write */ + edca_params->ani_acbe_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->ani_acbk_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->ani_acvi_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->ani_acvo_l.max_len = CFG_EDCA_DATA_LEN; + + edca_params->ani_acbe_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->ani_acbk_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->ani_acvi_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->ani_acvo_b.max_len = CFG_EDCA_DATA_LEN; + + /* parse the ETSI edca parameters from cfg string for BK,BE,VI,VO ac */ + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACBK_LOCAL), + edca_params->ani_acbk_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acbk_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACBE_LOCAL), + edca_params->ani_acbe_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acbe_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACVI_LOCAL), + edca_params->ani_acvi_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acvi_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACVO_LOCAL), + edca_params->ani_acvo_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acvo_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACBK), + edca_params->ani_acbk_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acbk_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACBE), + edca_params->ani_acbe_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acbe_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACVI), + edca_params->ani_acvi_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acvi_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ANI_ACVO), + edca_params->ani_acvo_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->ani_acvo_b.len); +} + +static void mlme_init_edca_wme_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_edca_params *edca_params) +{ + /* initialize the max allowed array length for read/write */ + edca_params->wme_acbk_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->wme_acbe_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->wme_acvi_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->wme_acvo_l.max_len = CFG_EDCA_DATA_LEN; + + edca_params->wme_acbk_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->wme_acbe_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->wme_acvi_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->wme_acvo_b.max_len = CFG_EDCA_DATA_LEN; + + /* parse the WME edca parameters from cfg string for BK,BE,VI,VO ac */ + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACBK_LOCAL), + edca_params->wme_acbk_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acbk_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACBE_LOCAL), + edca_params->wme_acbe_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acbe_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACVI_LOCAL), + edca_params->wme_acvi_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acvi_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACVO_LOCAL), + edca_params->wme_acvo_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acvo_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACBK), + edca_params->wme_acbk_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acbk_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACBE), + edca_params->wme_acbe_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acbe_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACVI), + edca_params->wme_acvi_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acvi_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_WME_ACVO), + edca_params->wme_acvo_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->wme_acvo_b.len); +} + +static void mlme_init_edca_etsi_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_edca_params *edca_params) +{ + /* initialize the max allowed array length for read/write */ + edca_params->etsi_acbe_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->etsi_acbk_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->etsi_acvi_l.max_len = CFG_EDCA_DATA_LEN; + edca_params->etsi_acvo_l.max_len = CFG_EDCA_DATA_LEN; + + edca_params->etsi_acbe_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->etsi_acbk_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->etsi_acvi_b.max_len = CFG_EDCA_DATA_LEN; + edca_params->etsi_acvo_b.max_len = CFG_EDCA_DATA_LEN; + + /* parse the ETSI edca parameters from cfg string for BK,BE,VI,VO ac */ + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACBK_LOCAL), + edca_params->etsi_acbk_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acbk_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACBE_LOCAL), + edca_params->etsi_acbe_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acbe_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACVI_LOCAL), + edca_params->etsi_acvi_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acvi_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACVO_LOCAL), + edca_params->etsi_acvo_l.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acvo_l.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACBK), + edca_params->etsi_acbk_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acbk_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACBE), + edca_params->etsi_acbe_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acbe_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACVI), + edca_params->etsi_acvi_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acvi_b.len); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_EDCA_ETSI_ACVO), + edca_params->etsi_acvo_b.data, + CFG_EDCA_DATA_LEN, + &edca_params->etsi_acvo_b.len); +} + +static void +mlme_init_qos_edca_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_edca_params *edca_params) +{ + edca_params->enable_edca_params = + cfg_get(psoc, CFG_EDCA_ENABLE_PARAM); + + edca_params->enable_wmm_txop = + cfg_get(psoc, CFG_ENABLE_WMM_TXOP); + edca_params->edca_ac_vo.vo_cwmin = + cfg_get(psoc, CFG_EDCA_VO_CWMIN); + edca_params->edca_ac_vo.vo_cwmax = + cfg_get(psoc, CFG_EDCA_VO_CWMAX); + edca_params->edca_ac_vo.vo_aifs = + cfg_get(psoc, CFG_EDCA_VO_AIFS); + + edca_params->edca_ac_vi.vi_cwmin = + cfg_get(psoc, CFG_EDCA_VI_CWMIN); + edca_params->edca_ac_vi.vi_cwmax = + cfg_get(psoc, CFG_EDCA_VI_CWMAX); + edca_params->edca_ac_vi.vi_aifs = + cfg_get(psoc, CFG_EDCA_VI_AIFS); + + edca_params->edca_ac_bk.bk_cwmin = + cfg_get(psoc, CFG_EDCA_BK_CWMIN); + edca_params->edca_ac_bk.bk_cwmax = + cfg_get(psoc, CFG_EDCA_BK_CWMAX); + edca_params->edca_ac_bk.bk_aifs = + cfg_get(psoc, CFG_EDCA_BK_AIFS); + + edca_params->edca_ac_be.be_cwmin = + cfg_get(psoc, CFG_EDCA_BE_CWMIN); + edca_params->edca_ac_be.be_cwmax = + cfg_get(psoc, CFG_EDCA_BE_CWMAX); + edca_params->edca_ac_be.be_aifs = + cfg_get(psoc, CFG_EDCA_BE_AIFS); + + edca_params->edca_param_type = + cfg_get(psoc, CFG_EDCA_PIFS_PARAM_TYPE); +} + +static void mlme_init_edca_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_edca_params *edca_params) +{ + mlme_init_edca_ani_cfg(psoc, edca_params); + mlme_init_edca_wme_cfg(psoc, edca_params); + mlme_init_edca_etsi_cfg(psoc, edca_params); + mlme_init_qos_edca_params(psoc, edca_params); +} + +static void mlme_init_timeout_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_timeout *timeouts) +{ + timeouts->join_failure_timeout = + cfg_get(psoc, CFG_JOIN_FAILURE_TIMEOUT); + timeouts->join_failure_timeout_ori = timeouts->join_failure_timeout; + timeouts->probe_req_retry_timeout = JOIN_PROBE_REQ_TIMER_MS; + timeouts->auth_failure_timeout = + cfg_get(psoc, CFG_AUTH_FAILURE_TIMEOUT); + timeouts->auth_rsp_timeout = + cfg_get(psoc, CFG_AUTH_RSP_TIMEOUT); + timeouts->assoc_failure_timeout = + cfg_get(psoc, CFG_ASSOC_FAILURE_TIMEOUT); + timeouts->reassoc_failure_timeout = + cfg_get(psoc, CFG_REASSOC_FAILURE_TIMEOUT); + timeouts->olbc_detect_timeout = + cfg_get(psoc, CFG_OLBC_DETECT_TIMEOUT); + timeouts->addts_rsp_timeout = + cfg_get(psoc, CFG_ADDTS_RSP_TIMEOUT); + timeouts->heart_beat_threshold = + cfg_get(psoc, CFG_HEART_BEAT_THRESHOLD); + timeouts->ap_keep_alive_timeout = + cfg_get(psoc, CFG_AP_KEEP_ALIVE_TIMEOUT); + timeouts->ap_link_monitor_timeout = + cfg_get(psoc, CFG_AP_LINK_MONITOR_TIMEOUT); + timeouts->wmi_wq_watchdog_timeout = + cfg_get(psoc, CFG_WMI_WQ_WATCHDOG); + timeouts->sae_auth_failure_timeout = + cfg_get(psoc, CFG_SAE_AUTH_FAILURE_TIMEOUT); +} + +static void mlme_init_ht_cap_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_ht_caps *ht_caps) +{ + union { + uint16_t val_16; + struct mlme_ht_capabilities_info ht_cap_info; + } u1; + + union { + uint16_t val_16; + struct mlme_ht_ext_cap_info ext_cap_info; + } u2; + + union { + uint8_t val_8; + struct mlme_ht_info_field_1 info_field_1; + } u3; + + union { + uint16_t val_16; + struct mlme_ht_info_field_2 info_field_2; + } u4; + + union { + uint16_t val_16; + struct mlme_ht_info_field_3 info_field_3; + } u5; + + /* HT Capabilities - HT Caps Info Field */ + u1.val_16 = (uint16_t)cfg_default(CFG_HT_CAP_INFO); + u1.ht_cap_info.adv_coding_cap = + cfg_get(psoc, CFG_RX_LDPC_ENABLE); + u1.ht_cap_info.rx_stbc = cfg_get(psoc, CFG_RX_STBC_ENABLE); + u1.ht_cap_info.tx_stbc = cfg_get(psoc, CFG_TX_STBC_ENABLE); + u1.ht_cap_info.short_gi_20_mhz = + cfg_get(psoc, CFG_SHORT_GI_20MHZ); + u1.ht_cap_info.short_gi_40_mhz = + cfg_get(psoc, CFG_SHORT_GI_40MHZ); + u1.ht_cap_info.mimo_power_save = cfg_get(psoc, CFG_HT_SMPS_MODE); + ht_caps->ht_cap_info = u1.ht_cap_info; + + /* HT Capapabilties - AMPDU Params */ + ht_caps->ampdu_params.max_rx_ampdu_factor = + cfg_get(psoc, CFG_MAX_RX_AMPDU_FACTOR); + ht_caps->ampdu_params.mpdu_density = + cfg_get(psoc, CFG_MPDU_DENSITY); + ht_caps->ampdu_params.reserved = 0; + + /* HT Capabilities - Extended Capabilities field */ + u2.val_16 = (uint16_t)cfg_default(CFG_EXT_HT_CAP_INFO); + ht_caps->ext_cap_info = u2.ext_cap_info; + + /* HT Operation - Information subset 1 of 3 */ + u3.val_8 = (uint8_t)cfg_default(CFG_HT_INFO_FIELD_1); + ht_caps->info_field_1 = u3.info_field_1; + + /* HT Operation - Information subset 2 of 3 */ + u4.val_16 = (uint16_t)cfg_default(CFG_HT_INFO_FIELD_2); + ht_caps->info_field_2 = u4.info_field_2; + + /* HT Operation - Information subset 3 of 3 */ + u5.val_16 = (uint16_t)cfg_default(CFG_HT_INFO_FIELD_3); + ht_caps->info_field_3 = u5.info_field_3; + + ht_caps->short_preamble = cfg_get(psoc, CFG_SHORT_PREAMBLE); + ht_caps->enable_ampdu_ps = cfg_get(psoc, CFG_ENABLE_AMPDUPS); + ht_caps->enable_smps = cfg_get(psoc, CFG_ENABLE_HT_SMPS); + ht_caps->smps = cfg_get(psoc, CFG_HT_SMPS_MODE); + ht_caps->max_num_amsdu = cfg_get(psoc, CFG_MAX_AMSDU_NUM); + ht_caps->tx_ldpc_enable = cfg_get(psoc, CFG_TX_LDPC_ENABLE); + ht_caps->short_slot_time_enabled = + cfg_get(psoc, CFG_SHORT_SLOT_TIME_ENABLED); +} + +static void mlme_init_qos_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_qos *qos_aggr_params) +{ + qos_aggr_params->tx_aggregation_size = + cfg_get(psoc, CFG_TX_AGGREGATION_SIZE); + qos_aggr_params->tx_aggregation_size_be = + cfg_get(psoc, CFG_TX_AGGREGATION_SIZEBE); + qos_aggr_params->tx_aggregation_size_bk = + cfg_get(psoc, CFG_TX_AGGREGATION_SIZEBK); + qos_aggr_params->tx_aggregation_size_vi = + cfg_get(psoc, CFG_TX_AGGREGATION_SIZEVI); + qos_aggr_params->tx_aggregation_size_vo = + cfg_get(psoc, CFG_TX_AGGREGATION_SIZEVO); + qos_aggr_params->rx_aggregation_size = + cfg_get(psoc, CFG_RX_AGGREGATION_SIZE); + qos_aggr_params->tx_aggr_sw_retry_threshold_be = + cfg_get(psoc, CFG_TX_AGGR_SW_RETRY_BE); + qos_aggr_params->tx_aggr_sw_retry_threshold_bk = + cfg_get(psoc, CFG_TX_AGGR_SW_RETRY_BK); + qos_aggr_params->tx_aggr_sw_retry_threshold_vi = + cfg_get(psoc, CFG_TX_AGGR_SW_RETRY_VI); + qos_aggr_params->tx_aggr_sw_retry_threshold_vo = + cfg_get(psoc, CFG_TX_AGGR_SW_RETRY_VO); + qos_aggr_params->tx_aggr_sw_retry_threshold = + cfg_get(psoc, CFG_TX_AGGR_SW_RETRY); + qos_aggr_params->tx_non_aggr_sw_retry_threshold_be = + cfg_get(psoc, CFG_TX_NON_AGGR_SW_RETRY_BE); + qos_aggr_params->tx_non_aggr_sw_retry_threshold_bk = + cfg_get(psoc, CFG_TX_NON_AGGR_SW_RETRY_BK); + qos_aggr_params->tx_non_aggr_sw_retry_threshold_vi = + cfg_get(psoc, CFG_TX_NON_AGGR_SW_RETRY_VI); + qos_aggr_params->tx_non_aggr_sw_retry_threshold_vo = + cfg_get(psoc, CFG_TX_NON_AGGR_SW_RETRY_VO); + qos_aggr_params->tx_non_aggr_sw_retry_threshold = + cfg_get(psoc, CFG_TX_NON_AGGR_SW_RETRY); + qos_aggr_params->sap_max_inactivity_override = + cfg_get(psoc, CFG_SAP_MAX_INACTIVITY_OVERRIDE); + qos_aggr_params->sap_uapsd_enabled = + cfg_get(psoc, CFG_SAP_QOS_UAPSD); +} + +static void mlme_init_mbo_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_mbo *mbo_params) +{ + mbo_params->mbo_candidate_rssi_thres = + cfg_get(psoc, CFG_MBO_CANDIDATE_RSSI_THRESHOLD); + mbo_params->mbo_current_rssi_thres = + cfg_get(psoc, CFG_MBO_CURRENT_RSSI_THRESHOLD); + mbo_params->mbo_current_rssi_mcc_thres = + cfg_get(psoc, CFG_MBO_CUR_RSSI_MCC_THRESHOLD); + mbo_params->mbo_candidate_rssi_btc_thres = + cfg_get(psoc, CFG_MBO_CAND_RSSI_BTC_THRESHOLD); +} + +static void mlme_init_vht_cap_cfg(struct wlan_objmgr_psoc *psoc, + struct mlme_vht_capabilities_info + *vht_cap_info) +{ + vht_cap_info->supp_chan_width = + cfg_default(CFG_VHT_SUPP_CHAN_WIDTH); + vht_cap_info->num_soundingdim = + cfg_default(CFG_VHT_NUM_SOUNDING_DIMENSIONS); + vht_cap_info->htc_vhtc = + cfg_default(CFG_VHT_HTC_VHTC); + vht_cap_info->link_adap_cap = + cfg_default(CFG_VHT_LINK_ADAPTATION_CAP); + vht_cap_info->rx_antpattern = + cfg_default(CFG_VHT_RX_ANT_PATTERN); + vht_cap_info->tx_antpattern = + cfg_default(CFG_VHT_TX_ANT_PATTERN); + vht_cap_info->rx_supp_data_rate = + cfg_default(CFG_VHT_RX_SUPP_DATA_RATE); + vht_cap_info->tx_supp_data_rate = + cfg_default(CFG_VHT_TX_SUPP_DATA_RATE); + vht_cap_info->txop_ps = + cfg_default(CFG_VHT_TXOP_PS); + vht_cap_info->rx_mcs_map = + CFG_VHT_RX_MCS_MAP_STADEF; + vht_cap_info->tx_mcs_map = + CFG_VHT_TX_MCS_MAP_STADEF; + vht_cap_info->basic_mcs_set = + CFG_VHT_BASIC_MCS_SET_STADEF; + + vht_cap_info->tx_bfee_ant_supp = + cfg_get(psoc, CFG_VHT_BEAMFORMEE_ANT_SUPP); + + vht_cap_info->enable_txbf_20mhz = + cfg_get(psoc, CFG_VHT_ENABLE_TXBF_IN_20MHZ); + vht_cap_info->ampdu_len = + cfg_get(psoc, CFG_VHT_MPDU_LEN); + + vht_cap_info->ldpc_coding_cap = + cfg_get(psoc, CFG_RX_LDPC_ENABLE); + vht_cap_info->short_gi_80mhz = + cfg_get(psoc, CFG_SHORT_GI_40MHZ); + vht_cap_info->short_gi_160mhz = + cfg_get(psoc, CFG_SHORT_GI_40MHZ); + vht_cap_info->tx_stbc = + cfg_get(psoc, CFG_TX_STBC_ENABLE); + vht_cap_info->rx_stbc = + cfg_get(psoc, CFG_RX_STBC_ENABLE); + + vht_cap_info->su_bformee = + cfg_get(psoc, CFG_VHT_SU_BEAMFORMEE_CAP); + + vht_cap_info->mu_bformer = + cfg_default(CFG_VHT_MU_BEAMFORMER_CAP); + + vht_cap_info->enable_mu_bformee = + cfg_get(psoc, CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE); + vht_cap_info->ampdu_len_exponent = + cfg_get(psoc, CFG_VHT_AMPDU_LEN_EXPONENT); + vht_cap_info->channel_width = + cfg_get(psoc, CFG_VHT_CHANNEL_WIDTH); + vht_cap_info->rx_mcs = + cfg_get(psoc, CFG_VHT_ENABLE_RX_MCS_8_9); + vht_cap_info->tx_mcs = + cfg_get(psoc, CFG_VHT_ENABLE_TX_MCS_8_9); + vht_cap_info->rx_mcs2x2 = + cfg_get(psoc, CFG_VHT_ENABLE_RX_MCS2x2_8_9); + vht_cap_info->tx_mcs2x2 = + cfg_get(psoc, CFG_VHT_ENABLE_TX_MCS2x2_8_9); + vht_cap_info->enable_vht20_mcs9 = + cfg_get(psoc, CFG_ENABLE_VHT20_MCS9); + vht_cap_info->enable2x2 = + cfg_get(psoc, CFG_VHT_ENABLE_2x2_CAP_FEATURE); + vht_cap_info->enable_paid = + cfg_get(psoc, CFG_VHT_ENABLE_PAID_FEATURE); + vht_cap_info->enable_gid = + cfg_get(psoc, CFG_VHT_ENABLE_GID_FEATURE); + vht_cap_info->b24ghz_band = + cfg_get(psoc, CFG_ENABLE_VHT_FOR_24GHZ); + vht_cap_info->vendor_24ghz_band = + cfg_get(psoc, CFG_ENABLE_VENDOR_VHT_FOR_24GHZ); + vht_cap_info->tx_bfee_sap = + cfg_get(psoc, CFG_VHT_ENABLE_TXBF_SAP_MODE); + vht_cap_info->vendor_vhtie = + cfg_get(psoc, CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE); + + if (vht_cap_info->enable2x2) + vht_cap_info->su_bformer = + cfg_get(psoc, CFG_VHT_ENABLE_TX_SU_BEAM_FORMER); + + if (vht_cap_info->enable2x2 && vht_cap_info->su_bformer) + vht_cap_info->num_soundingdim = NUM_OF_SOUNDING_DIMENSIONS; + + vht_cap_info->tx_bf_cap = cfg_default(CFG_TX_BF_CAP); + vht_cap_info->as_cap = cfg_default(CFG_AS_CAP); + vht_cap_info->disable_ldpc_with_txbf_ap = + cfg_get(psoc, CFG_DISABLE_LDPC_WITH_TXBF_AP); +} + +static void mlme_init_rates_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_rates *rates) +{ + rates->cfp_period = cfg_default(CFG_CFP_PERIOD); + rates->cfp_max_duration = cfg_default(CFG_CFP_MAX_DURATION); + rates->max_htmcs_txdata = cfg_get(psoc, CFG_MAX_HT_MCS_FOR_TX_DATA); + rates->disable_abg_rate_txdata = cfg_get(psoc, + CFG_DISABLE_ABG_RATE_FOR_TX_DATA); + rates->sap_max_mcs_txdata = cfg_get(psoc, + CFG_SAP_MAX_MCS_FOR_TX_DATA); + rates->disable_high_ht_mcs_2x2 = cfg_get(psoc, + CFG_DISABLE_HIGH_HT_RX_MCS_2x2); + + rates->supported_11b.max_len = CFG_SUPPORTED_RATES_11B_LEN; + qdf_uint8_array_parse(cfg_default(CFG_SUPPORTED_RATES_11B), + rates->supported_11b.data, + sizeof(rates->supported_11b.data), + &rates->supported_11b.len); + rates->supported_11a.max_len = CFG_SUPPORTED_RATES_11A_LEN; + qdf_uint8_array_parse(cfg_default(CFG_SUPPORTED_RATES_11A), + rates->supported_11a.data, + sizeof(rates->supported_11a.data), + &rates->supported_11a.len); + rates->supported_mcs_set.max_len = CFG_SUPPORTED_MCS_SET_LEN; + qdf_uint8_array_parse(cfg_default(CFG_SUPPORTED_MCS_SET), + rates->supported_mcs_set.data, + sizeof(rates->supported_mcs_set.data), + &rates->supported_mcs_set.len); + rates->basic_mcs_set.max_len = CFG_BASIC_MCS_SET_LEN; + qdf_uint8_array_parse(cfg_default(CFG_BASIC_MCS_SET), + rates->basic_mcs_set.data, + sizeof(rates->basic_mcs_set.data), + &rates->basic_mcs_set.len); + rates->current_mcs_set.max_len = CFG_CURRENT_MCS_SET_LEN; + qdf_uint8_array_parse(cfg_default(CFG_CURRENT_MCS_SET), + rates->current_mcs_set.data, + sizeof(rates->current_mcs_set.data), + &rates->current_mcs_set.len); +} + +static void mlme_init_dfs_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_dfs_cfg *dfs_cfg) +{ + dfs_cfg->dfs_ignore_cac = cfg_get(psoc, CFG_IGNORE_CAC); + dfs_cfg->dfs_master_capable = + cfg_get(psoc, CFG_ENABLE_DFS_MASTER_CAPABILITY); + dfs_cfg->dfs_disable_channel_switch = + cfg_get(psoc, CFG_DISABLE_DFS_CH_SWITCH); + dfs_cfg->dfs_filter_offload = + cfg_get(psoc, CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD); + dfs_cfg->dfs_prefer_non_dfs = + cfg_get(psoc, CFG_ENABLE_NON_DFS_CHAN_ON_RADAR); + dfs_cfg->dfs_beacon_tx_enhanced = + cfg_get(psoc, CFG_DFS_BEACON_TX_ENHANCED); + dfs_cfg->dfs_disable_japan_w53 = + cfg_get(psoc, CFG_DISABLE_DFS_JAPAN_W53); + dfs_cfg->sap_tx_leakage_threshold = + cfg_get(psoc, CFG_SAP_TX_LEAKAGE_THRESHOLD); + dfs_cfg->dfs_pri_multiplier = + cfg_get(psoc, CFG_DFS_RADAR_PRI_MULTIPLIER); +} + +static void mlme_init_feature_flag_in_cfg( + struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_feature_flag *feature_flags) +{ + feature_flags->accept_short_slot_assoc = + cfg_default(CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY); + feature_flags->enable_hcf = cfg_default(CFG_HCF_ENABLED); + feature_flags->enable_rsn = cfg_default(CFG_RSN_ENABLED); + feature_flags->enable_short_preamble_11g = + cfg_default(CFG_11G_SHORT_PREAMBLE_ENABLED); + feature_flags->enable_short_slot_time_11g = + cfg_default(CFG_11G_SHORT_SLOT_TIME_ENABLED); + feature_flags->channel_bonding_mode = + cfg_default(CFG_CHANNEL_BONDING_MODE); + feature_flags->enable_block_ack = cfg_default(CFG_BLOCK_ACK_ENABLED); + feature_flags->enable_ampdu = cfg_get(psoc, CFG_ENABLE_AMPDUPS); + feature_flags->mcc_rts_cts_prot = cfg_get(psoc, + CFG_FW_MCC_RTS_CTS_PROT); + feature_flags->mcc_bcast_prob_rsp = cfg_get(psoc, + CFG_FW_MCC_BCAST_PROB_RESP); + feature_flags->enable_mcc = cfg_get(psoc, CFG_MCC_FEATURE); + feature_flags->channel_bonding_mode_24ghz = + cfg_get(psoc, CFG_CHANNEL_BONDING_MODE_24GHZ); + feature_flags->channel_bonding_mode_5ghz = + cfg_get(psoc, CFG_CHANNEL_BONDING_MODE_5GHZ); + feature_flags->update_cw_allowed = + cfg_get(psoc, CFG_ALLOW_UPDATE_CHANNEL_WIDTH); +} + +static void mlme_init_sap_protection_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_sap_protection + *sap_protection_params) +{ + sap_protection_params->protection_enabled = + cfg_default(CFG_PROTECTION_ENABLED); + sap_protection_params->protection_force_policy = + cfg_default(CFG_FORCE_POLICY_PROTECTION); + sap_protection_params->ignore_peer_ht_opmode = + cfg_get(psoc, CFG_IGNORE_PEER_HT_MODE); + sap_protection_params->enable_ap_obss_protection = + cfg_get(psoc, CFG_AP_OBSS_PROTECTION_ENABLE); + sap_protection_params->is_ap_prot_enabled = + cfg_get(psoc, CFG_AP_ENABLE_PROTECTION_MODE); + sap_protection_params->ap_protection_mode = + cfg_get(psoc, CFG_AP_PROTECTION_MODE); +} + +#ifdef WLAN_FEATURE_11AX + +#define HE_MCS12_13_24G_INDEX 0 +#define HE_MCS12_13_5G_INDEX 1 +#define HE_MCS12_13_BITS 16 + +static void mlme_init_he_cap_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg *mlme_cfg) +{ + uint32_t chan_width, mcs_12_13; + uint16_t value = 0; + struct wlan_mlme_he_caps *he_caps = &mlme_cfg->he_caps; + bool is_twt_enabled = false; + + he_caps->dot11_he_cap.htc_he = cfg_default(CFG_HE_CONTROL); + he_caps->dot11_he_cap.twt_request = + cfg_get(psoc, CFG_TWT_REQUESTOR); + he_caps->dot11_he_cap.twt_responder = + cfg_get(psoc, CFG_TWT_RESPONDER); + /* + * Broadcast TWT capability will be filled in + * populate_dot11f_he_caps() based on STA/SAP + * role and "twt_bcast_req_resp_config" ini + */ + he_caps->dot11_he_cap.broadcast_twt = 0; + + is_twt_enabled = wlan_twt_cfg_is_twt_enabled(psoc); + + if (is_twt_enabled) + he_caps->dot11_he_cap.flex_twt_sched = + cfg_default(CFG_HE_FLEX_TWT_SCHED); + he_caps->dot11_he_cap.fragmentation = + cfg_default(CFG_HE_FRAGMENTATION); + he_caps->dot11_he_cap.max_num_frag_msdu_amsdu_exp = + cfg_default(CFG_HE_MAX_FRAG_MSDU); + he_caps->dot11_he_cap.min_frag_size = cfg_default(CFG_HE_MIN_FRAG_SIZE); + he_caps->dot11_he_cap.trigger_frm_mac_pad = + cfg_default(CFG_HE_TRIG_PAD); + he_caps->dot11_he_cap.multi_tid_aggr_rx_supp = + cfg_default(CFG_HE_MTID_AGGR_RX); + he_caps->dot11_he_cap.he_link_adaptation = + cfg_default(CFG_HE_LINK_ADAPTATION); + he_caps->dot11_he_cap.all_ack = cfg_default(CFG_HE_ALL_ACK); + he_caps->dot11_he_cap.trigd_rsp_sched = + cfg_default(CFG_HE_TRIGD_RSP_SCHEDULING); + he_caps->dot11_he_cap.a_bsr = cfg_default(CFG_HE_BUFFER_STATUS_RPT); + he_caps->dot11_he_cap.ba_32bit_bitmap = cfg_default(CFG_HE_BA_32BIT); + he_caps->dot11_he_cap.mu_cascade = cfg_default(CFG_HE_MU_CASCADING); + he_caps->dot11_he_cap.ack_enabled_multitid = + cfg_default(CFG_HE_MULTI_TID); + he_caps->dot11_he_cap.omi_a_ctrl = cfg_default(CFG_HE_OMI); + he_caps->dot11_he_cap.ofdma_ra = cfg_default(CFG_HE_OFDMA_RA); + he_caps->dot11_he_cap.max_ampdu_len_exp_ext = + cfg_default(CFG_HE_MAX_AMPDU_LEN); + he_caps->dot11_he_cap.amsdu_frag = cfg_default(CFG_HE_AMSDU_FRAG); + + he_caps->dot11_he_cap.rx_ctrl_frame = cfg_default(CFG_HE_RX_CTRL); + he_caps->dot11_he_cap.bsrp_ampdu_aggr = + cfg_default(CFG_HE_BSRP_AMPDU_AGGR); + he_caps->dot11_he_cap.qtp = cfg_default(CFG_HE_QTP); + he_caps->dot11_he_cap.a_bqr = cfg_default(CFG_HE_A_BQR); + he_caps->dot11_he_cap.spatial_reuse_param_rspder = + cfg_default(CFG_HE_SR_RESPONDER); + he_caps->dot11_he_cap.ndp_feedback_supp = + cfg_default(CFG_HE_NDP_FEEDBACK_SUPP); + he_caps->dot11_he_cap.ops_supp = cfg_default(CFG_HE_OPS_SUPP); + he_caps->dot11_he_cap.amsdu_in_ampdu = + cfg_default(CFG_HE_AMSDU_IN_AMPDU); + + chan_width = cfg_default(CFG_HE_CHAN_WIDTH); + he_caps->dot11_he_cap.chan_width_0 = HE_CH_WIDTH_GET_BIT(chan_width, 0); + he_caps->dot11_he_cap.chan_width_1 = HE_CH_WIDTH_GET_BIT(chan_width, 1); + he_caps->dot11_he_cap.chan_width_2 = HE_CH_WIDTH_GET_BIT(chan_width, 2); + he_caps->dot11_he_cap.chan_width_3 = HE_CH_WIDTH_GET_BIT(chan_width, 3); + he_caps->dot11_he_cap.chan_width_4 = HE_CH_WIDTH_GET_BIT(chan_width, 4); + he_caps->dot11_he_cap.chan_width_5 = HE_CH_WIDTH_GET_BIT(chan_width, 5); + he_caps->dot11_he_cap.chan_width_6 = HE_CH_WIDTH_GET_BIT(chan_width, 6); + + he_caps->dot11_he_cap.multi_tid_aggr_tx_supp = + cfg_default(CFG_HE_MTID_AGGR_TX); + he_caps->dot11_he_cap.he_sub_ch_sel_tx_supp = + cfg_default(CFG_HE_SUB_CH_SEL_TX); + he_caps->dot11_he_cap.ul_2x996_tone_ru_supp = + cfg_default(CFG_HE_UL_2X996_RU); + he_caps->dot11_he_cap.om_ctrl_ul_mu_data_dis_rx = + cfg_default(CFG_HE_OM_CTRL_UL_MU_DIS_RX); + he_caps->dot11_he_cap.he_dynamic_smps = + cfg_default(CFG_HE_DYNAMIC_SMPS); + he_caps->dot11_he_cap.punctured_sounding_supp = + cfg_default(CFG_HE_PUNCTURED_SOUNDING); + he_caps->dot11_he_cap.ht_vht_trg_frm_rx_supp = + cfg_default(CFG_HE_HT_VHT_TRG_FRM_RX); + he_caps->dot11_he_cap.rx_pream_puncturing = + cfg_get(psoc, CFG_HE_RX_PREAM_PUNC); + he_caps->dot11_he_cap.device_class = + cfg_default(CFG_HE_CLASS_OF_DEVICE); + he_caps->dot11_he_cap.ldpc_coding = cfg_default(CFG_HE_LDPC); + he_caps->dot11_he_cap.he_1x_ltf_800_gi_ppdu = + cfg_default(CFG_HE_LTF_PPDU); + he_caps->dot11_he_cap.midamble_tx_rx_max_nsts = + cfg_default(CFG_HE_MIDAMBLE_RX_MAX_NSTS); + he_caps->dot11_he_cap.he_4x_ltf_3200_gi_ndp = + cfg_default(CFG_HE_LTF_NDP); + he_caps->dot11_he_cap.tb_ppdu_tx_stbc_lt_80mhz = + cfg_default(CFG_HE_TX_STBC_LT80); + he_caps->dot11_he_cap.rx_stbc_lt_80mhz = + cfg_default(CFG_HE_RX_STBC_LT80); + he_caps->dot11_he_cap.doppler = cfg_default(CFG_HE_DOPPLER); + he_caps->dot11_he_cap.ul_mu = + cfg_get(psoc, CFG_HE_UL_MUMIMO); + he_caps->dot11_he_cap.dcm_enc_tx = cfg_default(CFG_HE_DCM_TX); + he_caps->dot11_he_cap.dcm_enc_rx = cfg_default(CFG_HE_DCM_RX); + he_caps->dot11_he_cap.ul_he_mu = cfg_default(CFG_HE_MU_PPDU); + he_caps->dot11_he_cap.su_beamformer = cfg_default(CFG_HE_SU_BEAMFORMER); + he_caps->dot11_he_cap.su_beamformee = cfg_default(CFG_HE_SU_BEAMFORMEE); + he_caps->dot11_he_cap.mu_beamformer = cfg_default(CFG_HE_MU_BEAMFORMER); + he_caps->dot11_he_cap.bfee_sts_lt_80 = + cfg_default(CFG_HE_BFEE_STS_LT80); + he_caps->dot11_he_cap.bfee_sts_gt_80 = + cfg_default(CFG_HE_BFEE_STS_GT80); + he_caps->dot11_he_cap.num_sounding_lt_80 = + cfg_default(CFG_HE_NUM_SOUND_LT80); + he_caps->dot11_he_cap.num_sounding_gt_80 = + cfg_default(CFG_HE_NUM_SOUND_GT80); + he_caps->dot11_he_cap.su_feedback_tone16 = + cfg_default(CFG_HE_SU_FEED_TONE16); + he_caps->dot11_he_cap.mu_feedback_tone16 = + cfg_default(CFG_HE_MU_FEED_TONE16); + he_caps->dot11_he_cap.codebook_su = cfg_default(CFG_HE_CODEBOOK_SU); + he_caps->dot11_he_cap.codebook_mu = cfg_default(CFG_HE_CODEBOOK_MU); + he_caps->dot11_he_cap.beamforming_feedback = + cfg_default(CFG_HE_BFRM_FEED); + he_caps->dot11_he_cap.he_er_su_ppdu = cfg_default(CFG_HE_ER_SU_PPDU); + he_caps->dot11_he_cap.dl_mu_mimo_part_bw = + cfg_default(CFG_HE_DL_PART_BW); + he_caps->dot11_he_cap.ppet_present = cfg_default(CFG_HE_PPET_PRESENT); + he_caps->dot11_he_cap.srp = cfg_default(CFG_HE_SRP); + he_caps->dot11_he_cap.power_boost = cfg_default(CFG_HE_POWER_BOOST); + he_caps->dot11_he_cap.he_ltf_800_gi_4x = cfg_default(CFG_HE_4x_LTF_GI); + he_caps->dot11_he_cap.max_nc = cfg_default(CFG_HE_MAX_NC); + he_caps->dot11_he_cap.tb_ppdu_tx_stbc_gt_80mhz = + cfg_default(CFG_HE_TX_STBC_GT80); + he_caps->dot11_he_cap.rx_stbc_gt_80mhz = + cfg_default(CFG_HE_RX_STBC_GT80); + he_caps->dot11_he_cap.er_he_ltf_800_gi_4x = + cfg_default(CFG_HE_ER_4x_LTF_GI); + he_caps->dot11_he_cap.he_ppdu_20_in_40Mhz_2G = + cfg_default(CFG_HE_PPDU_20_IN_40MHZ_2G); + he_caps->dot11_he_cap.he_ppdu_20_in_160_80p80Mhz = + cfg_default(CFG_HE_PPDU_20_IN_160_80P80MHZ); + he_caps->dot11_he_cap.he_ppdu_80_in_160_80p80Mhz = + cfg_default(CFG_HE_PPDU_80_IN_160_80P80MHZ); + he_caps->dot11_he_cap.er_1x_he_ltf_gi = + cfg_default(CFG_HE_ER_1X_HE_LTF_GI); + he_caps->dot11_he_cap.midamble_tx_rx_1x_he_ltf = + cfg_default(CFG_HE_MIDAMBLE_TXRX_1X_HE_LTF); + he_caps->dot11_he_cap.dcm_max_bw = cfg_default(CFG_HE_DCM_MAX_BW); + he_caps->dot11_he_cap.longer_than_16_he_sigb_ofdm_sym = + cfg_default(CFG_HE_LONGER_16_SIGB_OFDM_SYM); + he_caps->dot11_he_cap.non_trig_cqi_feedback = + cfg_default(CFG_HE_NON_TRIG_CQI_FEEDBACK); + he_caps->dot11_he_cap.tx_1024_qam_lt_242_tone_ru = + cfg_default(CFG_HE_TX_1024_QAM_LT_242_RU); + he_caps->dot11_he_cap.rx_1024_qam_lt_242_tone_ru = + cfg_default(CFG_HE_RX_1024_QAM_LT_242_RU); + he_caps->dot11_he_cap.rx_full_bw_su_he_mu_compress_sigb = + cfg_default(CFG_HE_RX_FULL_BW_MU_CMPR_SIGB); + he_caps->dot11_he_cap.rx_full_bw_su_he_mu_non_cmpr_sigb = + cfg_default(CFG_HE_RX_FULL_BW_MU_NON_CMPR_SIGB); + he_caps->dot11_he_cap.rx_he_mcs_map_lt_80 = + cfg_get(psoc, CFG_HE_RX_MCS_MAP_LT_80); + he_caps->dot11_he_cap.tx_he_mcs_map_lt_80 = + cfg_get(psoc, CFG_HE_TX_MCS_MAP_LT_80); + value = cfg_get(psoc, CFG_HE_RX_MCS_MAP_160); + qdf_mem_copy(he_caps->dot11_he_cap.rx_he_mcs_map_160, &value, + sizeof(uint16_t)); + value = cfg_get(psoc, CFG_HE_TX_MCS_MAP_160); + qdf_mem_copy(he_caps->dot11_he_cap.tx_he_mcs_map_160, &value, + sizeof(uint16_t)); + value = cfg_default(CFG_HE_RX_MCS_MAP_80_80); + qdf_mem_copy(he_caps->dot11_he_cap.rx_he_mcs_map_80_80, &value, + sizeof(uint16_t)); + value = cfg_default(CFG_HE_TX_MCS_MAP_80_80); + qdf_mem_copy(he_caps->dot11_he_cap.tx_he_mcs_map_80_80, &value, + sizeof(uint16_t)); + he_caps->he_ops_basic_mcs_nss = cfg_default(CFG_HE_OPS_BASIC_MCS_NSS); + he_caps->he_dynamic_fragmentation = + cfg_get(psoc, CFG_HE_DYNAMIC_FRAGMENTATION); + he_caps->enable_ul_mimo = + cfg_get(psoc, CFG_ENABLE_UL_MIMO); + he_caps->enable_ul_ofdm = + cfg_get(psoc, CFG_ENABLE_UL_OFDMA); + he_caps->he_sta_obsspd = + cfg_get(psoc, CFG_HE_STA_OBSSPD); + qdf_mem_zero(he_caps->he_ppet_2g, MLME_HE_PPET_LEN); + qdf_mem_zero(he_caps->he_ppet_5g, MLME_HE_PPET_LEN); + + mcs_12_13 = cfg_get(psoc, CFG_HE_MCS_12_13_SUPPORT); + /* Get 2.4Ghz and 5Ghz value */ + mlme_cfg->he_caps.he_mcs_12_13_supp_2g = + QDF_GET_BITS(mcs_12_13, + HE_MCS12_13_24G_INDEX * HE_MCS12_13_BITS, + HE_MCS12_13_BITS); + mlme_cfg->he_caps.he_mcs_12_13_supp_5g = + QDF_GET_BITS(mcs_12_13, + HE_MCS12_13_5G_INDEX * HE_MCS12_13_BITS, + HE_MCS12_13_BITS); + + mlme_cfg->he_caps.disable_sap_mcs_12_13 = cfg_get(psoc, + CFG_DISABLE_MCS_12_13_SAP); +} +#else +static void mlme_init_he_cap_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg *mlme_cfg) +{ +} +#endif + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/** + * mlme_init_disable_twt_info() - initialize disable twt info + * @psoc: Pointer to PSOC + * @twt_cfg: Pointer to twt_cfg + * + * Return: None + */ +static void mlme_init_disable_twt_info(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg_twt *twt_cfg) +{ + twt_cfg->disable_twt_info_frame = cfg_get(psoc, + CFG_DISABLE_TWT_INFO_FRAME); +} +#elif defined(WLAN_SUPPORT_TWT) +static void mlme_init_disable_twt_info(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg_twt *twt_cfg) +{ +} + +#endif + +#ifdef WLAN_SUPPORT_TWT +static void mlme_init_twt_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg_twt *twt_cfg) +{ + uint32_t bcast_conf = cfg_get(psoc, CFG_BCAST_TWT_REQ_RESP); + + twt_cfg->is_twt_enabled = cfg_get(psoc, CFG_ENABLE_TWT); + twt_cfg->twt_congestion_timeout = cfg_get(psoc, CFG_TWT_CONGESTION_TIMEOUT); + twt_cfg->enable_twt_24ghz = cfg_get(psoc, CFG_ENABLE_TWT_24GHZ); + twt_cfg->is_bcast_requestor_enabled = CFG_TWT_GET_BCAST_REQ(bcast_conf); + twt_cfg->is_bcast_responder_enabled = CFG_TWT_GET_BCAST_RES(bcast_conf); + mlme_init_disable_twt_info(psoc, twt_cfg); +} +#else +static void mlme_init_twt_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg_twt *twt_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +static void mlme_init_eht_cap_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg *mlme_cfg) +{ + struct wlan_mlme_eht_caps *eht_caps = &mlme_cfg->eht_caps; + + eht_caps->dot11_eht_cap.su_beamformer = + cfg_default(CFG_EHT_SU_BEAMFORMER); + eht_caps->dot11_eht_cap.su_beamformee = + cfg_default(CFG_EHT_SU_BEAMFORMEE); + eht_caps->dot11_eht_cap.mu_bformer_le_80mhz = + cfg_default(CFG_EHT_MU_BFORMER_LE_80MHZ); + eht_caps->dot11_eht_cap.mu_bformer_160mhz = + cfg_default(CFG_EHT_MU_BFORMER_160MHZ); + eht_caps->dot11_eht_cap.mu_bformer_320mhz = + cfg_default(CFG_EHT_MU_BFORMER_320MHZ); + eht_caps->dot11_eht_cap.bfee_ss_le_80mhz = + cfg_default(CFG_EHT_BFEE_SS_LE_80MHZ); + eht_caps->dot11_eht_cap.bfee_ss_160mhz = + cfg_default(CFG_EHT_BFEE_SS_160MHZ); + eht_caps->dot11_eht_cap.bfee_ss_320mhz = + cfg_default(CFG_EHT_BFEE_SS_320MHZ); + eht_caps->dot11_eht_cap.num_sounding_dim_le_80mhz = + cfg_default(CFG_EHT_NUM_SOUNDING_DIM_LE_80MHZ); + eht_caps->dot11_eht_cap.num_sounding_dim_160mhz = + cfg_default(CFG_EHT_NUM_SOUNDING_DIM_160MHZ); + eht_caps->dot11_eht_cap.num_sounding_dim_320mhz = + cfg_default(CFG_EHT_NUM_SOUNDING_DIM_320MHZ); +} +#else +static void mlme_init_eht_cap_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg *mlme_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_SAE +static bool is_sae_sap_enabled(struct wlan_objmgr_psoc *psoc) +{ + return cfg_get(psoc, CFG_IS_SAP_SAE_ENABLED); +} + +bool wlan_vdev_is_sae_auth_type(struct wlan_objmgr_vdev *vdev) +{ + int32_t auth_mode; + + auth_mode = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_AUTH_MODE); + + if (auth_mode == -1) + return false; + + if (QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_SAE)) + return true; + + return false; +} +#else +static bool is_sae_sap_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif +uint16_t wlan_get_rand_from_lst_for_freq(uint16_t *freq_lst, + uint8_t num_chan) +{ + uint8_t i; + uint32_t rand_byte = 0; + + if (!num_chan || !freq_lst) { + mlme_legacy_debug("invalid param freq_lst %pK, num_chan = %d", + freq_lst, num_chan); + return 0; + } + + get_random_bytes((uint8_t *)&rand_byte, 1); + i = (rand_byte + qdf_mc_timer_get_system_ticks()) % num_chan; + + return freq_lst[i]; +} + +static void mlme_init_sap_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg_sap *sap_cfg) +{ + sap_cfg->beacon_interval = cfg_get(psoc, CFG_BEACON_INTERVAL); + sap_cfg->dtim_interval = cfg_default(CFG_DTIM_PERIOD); + sap_cfg->listen_interval = cfg_default(CFG_LISTEN_INTERVAL); + sap_cfg->sap_11g_policy = cfg_default(CFG_11G_ONLY_POLICY); + sap_cfg->assoc_sta_limit = cfg_default(CFG_ASSOC_STA_LIMIT); + sap_cfg->enable_lte_coex = cfg_get(psoc, CFG_ENABLE_LTE_COEX); + sap_cfg->rate_tx_mgmt = cfg_get(psoc, CFG_RATE_FOR_TX_MGMT); + sap_cfg->rate_tx_mgmt_2g = cfg_get(psoc, CFG_RATE_FOR_TX_MGMT_2G); + sap_cfg->rate_tx_mgmt_5g = cfg_get(psoc, CFG_RATE_FOR_TX_MGMT_5G); + sap_cfg->tele_bcn_wakeup_en = cfg_get(psoc, CFG_TELE_BCN_WAKEUP_EN); + sap_cfg->tele_bcn_max_li = cfg_get(psoc, CFG_TELE_BCN_MAX_LI); + sap_cfg->sap_get_peer_info = cfg_get(psoc, CFG_SAP_GET_PEER_INFO); + sap_cfg->sap_allow_all_chan_param_name = + cfg_get(psoc, CFG_SAP_ALLOW_ALL_CHANNEL_PARAM); + sap_cfg->sap_max_no_peers = cfg_get(psoc, CFG_SAP_MAX_NO_PEERS); + sap_cfg->sap_max_offload_peers = + cfg_get(psoc, CFG_SAP_MAX_OFFLOAD_PEERS); + sap_cfg->sap_max_offload_reorder_buffs = + cfg_get(psoc, CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS); + sap_cfg->sap_ch_switch_beacon_cnt = + cfg_get(psoc, CFG_SAP_CH_SWITCH_BEACON_CNT); + sap_cfg->sap_ch_switch_mode = cfg_get(psoc, CFG_SAP_CH_SWITCH_MODE); + sap_cfg->sap_internal_restart = + cfg_get(psoc, CFG_SAP_INTERNAL_RESTART); + sap_cfg->chan_switch_hostapd_rate_enabled_name = + cfg_get(psoc, CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_NAME); + sap_cfg->reduced_beacon_interval = + cfg_get(psoc, CFG_REDUCED_BEACON_INTERVAL); + sap_cfg->max_li_modulated_dtim_time = + cfg_get(psoc, CFG_MAX_LI_MODULATED_DTIM); + sap_cfg->country_code_priority = + cfg_get(psoc, CFG_COUNTRY_CODE_PRIORITY); + sap_cfg->sap_pref_chan_location = + cfg_get(psoc, CFG_SAP_PREF_CHANNEL_LOCATION); + sap_cfg->sap_force_11n_for_11ac = + cfg_get(psoc, CFG_SAP_FORCE_11N_FOR_11AC); + sap_cfg->go_force_11n_for_11ac = + cfg_get(psoc, CFG_GO_FORCE_11N_FOR_11AC); + sap_cfg->ap_random_bssid_enable = + cfg_get(psoc, CFG_AP_ENABLE_RANDOM_BSSID); + sap_cfg->sap_mcc_chnl_avoid = + cfg_get(psoc, CFG_SAP_MCC_CHANNEL_AVOIDANCE); + sap_cfg->sap_11ac_override = + cfg_get(psoc, CFG_SAP_11AC_OVERRIDE); + sap_cfg->go_11ac_override = + cfg_get(psoc, CFG_GO_11AC_OVERRIDE); + sap_cfg->sap_sae_enabled = is_sae_sap_enabled(psoc); + sap_cfg->is_sap_bcast_deauth_enabled = + cfg_get(psoc, CFG_IS_SAP_BCAST_DEAUTH_ENABLED); + sap_cfg->is_6g_sap_fd_enabled = + cfg_get(psoc, CFG_6G_SAP_FILS_DISCOVERY_ENABLED); + sap_cfg->disable_bcn_prot = + cfg_get(psoc, CFG_DISABLE_SAP_BCN_PROT); + sap_cfg->sap_ps_with_twt_enable = + cfg_get(psoc, CFG_SAP_PS_WITH_TWT); +} + +static void mlme_init_obss_ht40_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_obss_ht40 *obss_ht40) +{ + obss_ht40->active_dwelltime = + cfg_get(psoc, CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME); + obss_ht40->passive_dwelltime = + cfg_get(psoc, CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME); + obss_ht40->width_trigger_interval = + cfg_get(psoc, CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL); + obss_ht40->passive_per_channel = (uint32_t) + cfg_default(CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL); + obss_ht40->active_per_channel = (uint32_t) + cfg_default(CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL); + obss_ht40->width_trans_delay = (uint32_t) + cfg_default(CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY); + obss_ht40->scan_activity_threshold = (uint32_t) + cfg_default(CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD); + obss_ht40->is_override_ht20_40_24g = + cfg_get(psoc, CFG_OBSS_HT40_OVERRIDE_HT40_20_24GHZ); + obss_ht40->obss_detection_offload_enabled = + (bool)cfg_default(CFG_OBSS_DETECTION_OFFLOAD); + obss_ht40->obss_color_collision_offload_enabled = + (bool)cfg_default(CFG_OBSS_COLOR_COLLISION_OFFLOAD); + obss_ht40->bss_color_collision_det_sta = + cfg_get(psoc, CFG_BSS_CLR_COLLISION_DETCN_STA); +} + +static void mlme_init_threshold_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_threshold *threshold) +{ + threshold->rts_threshold = cfg_get(psoc, CFG_RTS_THRESHOLD); + threshold->frag_threshold = cfg_get(psoc, CFG_FRAG_THRESHOLD); +} + +static bool +mlme_is_freq_present_in_list(struct acs_weight *normalize_weight_chan_list, + uint8_t num_freq, uint32_t freq, uint8_t *index) +{ + uint8_t i; + + for (i = 0; i < num_freq && i < NUM_CHANNELS; i++) { + if (normalize_weight_chan_list[i].chan_freq == freq) { + *index = i; + return true; + } + } + + return false; +} + +static void +mlme_acs_parse_weight_list(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_acs *acs) +{ + char *acs_weight, *str1, *str2 = NULL, *acs_weight_temp, is_range = '-'; + int freq1, freq2, normalize_factor; + uint8_t num_acs_weight = 0, num_acs_weight_range = 0, index = 0; + struct acs_weight *weight_list = acs->normalize_weight_chan; + struct acs_weight_range *range_list = acs->normalize_weight_range; + + if (!qdf_str_len(cfg_get(psoc, CFG_NORMALIZE_ACS_WEIGHT))) + return; + + acs_weight = qdf_mem_malloc(ACS_WEIGHT_MAX_STR_LEN); + if (!acs_weight) + return; + + qdf_mem_copy(acs_weight, cfg_get(psoc, CFG_NORMALIZE_ACS_WEIGHT), + ACS_WEIGHT_MAX_STR_LEN); + acs_weight_temp = acs_weight; + + while(acs_weight_temp) { + str1 = strsep(&acs_weight_temp, ","); + if (!str1) + goto end; + freq1 = 0; + freq2 = 0; + if (strchr(str1, is_range)) { + str2 = strsep(&str1, "-"); + sscanf(str2, "%d", &freq1); + sscanf(str1, "%d", &freq2); + strsep(&str1, "="); + if (!str1) + goto end; + sscanf(str1, "%d", &normalize_factor); + + if (num_acs_weight_range == MAX_ACS_WEIGHT_RANGE) + continue; + range_list[num_acs_weight_range].normalize_weight = + normalize_factor; + range_list[num_acs_weight_range].start_freq = freq1; + range_list[num_acs_weight_range++].end_freq = freq2; + } else { + sscanf(str1, "%d", &freq1); + strsep(&str1, "="); + if (!str1 || !weight_list) + goto end; + sscanf(str1, "%d", &normalize_factor); + if (mlme_is_freq_present_in_list(weight_list, + num_acs_weight, freq1, + &index)) { + weight_list[index].normalize_weight = + normalize_factor; + } else { + if (num_acs_weight == NUM_CHANNELS) + continue; + + weight_list[num_acs_weight].chan_freq = freq1; + weight_list[num_acs_weight++].normalize_weight = + normalize_factor; + } + } + } + + acs->normalize_weight_num_chan = num_acs_weight; + acs->num_weight_range = num_acs_weight_range; + +end: + qdf_mem_free(acs_weight); +} + +static void mlme_init_acs_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_acs *acs) +{ + acs->is_acs_with_more_param = + cfg_get(psoc, CFG_ACS_WITH_MORE_PARAM); + acs->auto_channel_select_weight = + cfg_get(psoc, CFG_AUTO_CHANNEL_SELECT_WEIGHT); + acs->is_vendor_acs_support = + cfg_get(psoc, CFG_USER_AUTO_CHANNEL_SELECTION); + acs->force_sap_start = + cfg_get(psoc, CFG_ACS_FORCE_START_SAP); + acs->is_acs_support_for_dfs_ltecoex = + cfg_get(psoc, CFG_USER_ACS_DFS_LTE); + acs->is_external_acs_policy = + cfg_get(psoc, CFG_EXTERNAL_ACS_POLICY); + acs->np_chan_weightage = cfg_get(psoc, CFG_ACS_NP_CHAN_WEIGHT); + acs->acs_prefer_6ghz_psc = cfg_default(CFG_ACS_PREFER_6GHZ_PSC); + mlme_acs_parse_weight_list(psoc, acs); +} + +static void +mlme_init_product_details_cfg(struct wlan_mlme_product_details_cfg + *product_details) +{ + qdf_str_lcopy(product_details->manufacturer_name, + cfg_default(CFG_MFR_NAME), + sizeof(product_details->manufacturer_name)); + qdf_str_lcopy(product_details->manufacture_product_name, + cfg_default(CFG_MFR_PRODUCT_NAME), + sizeof(product_details->manufacture_product_name)); + qdf_str_lcopy(product_details->manufacture_product_version, + cfg_default(CFG_MFR_PRODUCT_VERSION), + sizeof(product_details->manufacture_product_version)); + qdf_str_lcopy(product_details->model_name, + cfg_default(CFG_MODEL_NAME), + sizeof(product_details->model_name)); + qdf_str_lcopy(product_details->model_number, + cfg_default(CFG_MODEL_NUMBER), + sizeof(product_details->model_number)); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void mlme_init_sta_mlo_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_sta_cfg *sta) +{ + sta->mlo_support_link_num = + cfg_get(psoc, CFG_MLO_SUPPORT_LINK_NUM); + sta->mlo_support_link_band = + cfg_get(psoc, CFG_MLO_SUPPORT_LINK_BAND); + sta->mlo_max_simultaneous_links = + cfg_default(CFG_MLO_MAX_SIMULTANEOUS_LINKS); + sta->mlo_prefer_percentage = + cfg_get(psoc, CFG_MLO_PREFER_PERCENTAGE); + sta->mlo_same_link_mld_address = + cfg_default(CFG_MLO_SAME_LINK_MLD_ADDR); + sta->mlo_5gl_5gh_mlsr = + cfg_get(psoc, CFG_MLO_MLO_5GL_5GH_MLSR); + sta->epcs_capability = + cfg_get(psoc, CFG_MLO_EPCS_SUPPORT_ENABLE); + + mlme_debug("mlo_support_link_num: %d, mlo_support_link_band: 0x%x", + sta->mlo_support_link_num, sta->mlo_support_link_band); +} + +static bool +wlan_get_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev) +{ + bool is_mlo_link_removed = false; + uint8_t link_id; + struct mlo_link_info *link_info; + + if (!mlo_is_mld_sta(vdev)) + return false; + + link_id = wlan_vdev_get_link_id(vdev); + link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id); + if (link_info) + is_mlo_link_removed = + !!qdf_atomic_test_bit(LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags); + else + mlme_legacy_err("link info null, id %d", link_id); + + return is_mlo_link_removed; +} + +bool wlan_get_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_mlo_link_removed; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("get vdev failed for id %d", vdev_id); + return false; + } + + is_mlo_link_removed = wlan_get_vdev_link_removed_flag(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return is_mlo_link_removed; +} + +static QDF_STATUS +wlan_set_vdev_link_removed_flag(struct wlan_objmgr_vdev *vdev, bool removed) +{ + uint8_t link_id; + struct mlo_link_info *link_info; + bool is_mlo_link_removed; + + if (!vdev) { + mlme_legacy_err("vdev NULL"); + return QDF_STATUS_E_INVAL; + } + + if (!mlo_is_mld_sta(vdev)) { + mlme_legacy_debug("vdev not mld sta"); + return QDF_STATUS_E_INVAL; + } + + link_id = wlan_vdev_get_link_id(vdev); + link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, link_id); + if (!link_info) { + mlme_legacy_err("link info null, id %d", link_id); + return QDF_STATUS_E_INVAL; + } + is_mlo_link_removed = + !!qdf_atomic_test_bit(LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags); + if (removed == is_mlo_link_removed) + return QDF_STATUS_SUCCESS; + + mlme_legacy_debug("mlo sta vdev %d link %d link removed flag %d", + wlan_vdev_get_id(vdev), link_id, removed); + if (removed) + qdf_atomic_set_bit(LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags); + else + qdf_atomic_clear_bit(LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_set_vdev_link_removed_flag_by_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool removed) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev null for id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!mlo_is_mld_sta(vdev)) { + mlme_legacy_debug("vdev %d not mld sta", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_E_INVAL; + } + + status = wlan_set_vdev_link_removed_flag(vdev, removed); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return status; +} + +void wlan_clear_mlo_sta_link_removed_flag(struct wlan_objmgr_vdev *vdev) +{ + uint8_t i; + struct mlo_link_info *link_info; + + if (!vdev || !mlo_is_mld_sta(vdev)) + return; + + link_info = mlo_mgr_get_ap_link(vdev); + if (!link_info) + return; + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) + qdf_atomic_clear_bit(LS_F_AP_REMOVAL_BIT, + &link_info[i].link_status_flags); +} + +bool wlan_get_mlo_link_agnostic_flag(struct wlan_objmgr_vdev *vdev, + uint8_t *dest_addr) +{ + struct wlan_objmgr_peer *bss_peer = NULL; + bool mlo_link_agnostic = false; + uint8_t *peer_mld_addr = NULL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return mlo_link_agnostic; + + bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLME_OBJMGR_ID); + if (bss_peer) { + peer_mld_addr = wlan_peer_mlme_get_mldaddr(bss_peer); + if (!qdf_mem_cmp(bss_peer->macaddr, dest_addr, + QDF_MAC_ADDR_SIZE) || + (peer_mld_addr && !qdf_mem_cmp(peer_mld_addr, dest_addr, + QDF_MAC_ADDR_SIZE))) { + mlme_legacy_debug("dest address" QDF_MAC_ADDR_FMT "bss peer address" + QDF_MAC_ADDR_FMT "mld addr" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dest_addr), + QDF_MAC_ADDR_REF(bss_peer->macaddr), + QDF_MAC_ADDR_REF(peer_mld_addr)); + mlo_link_agnostic = true; + } + wlan_objmgr_peer_release_ref(bss_peer, WLAN_MLME_OBJMGR_ID); + } + return mlo_link_agnostic; +} + +bool wlan_drop_mgmt_frame_on_link_removal(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev || !mlo_is_mld_sta(vdev)) + return false; + + return wlan_get_vdev_link_removed_flag(vdev); +} +#else +static void mlme_init_sta_mlo_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_sta_cfg *sta) +{ +} +#endif + +static void mlme_init_sta_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_sta_cfg *sta) +{ + sta->sta_keep_alive_period = + cfg_get(psoc, CFG_INFRA_STA_KEEP_ALIVE_PERIOD); + sta->bss_max_idle_period = + cfg_get(psoc, CFG_STA_BSS_MAX_IDLE_PERIOD); + sta->tgt_gtx_usr_cfg = + cfg_get(psoc, CFG_TGT_GTX_USR_CFG); + sta->pmkid_modes = + cfg_get(psoc, CFG_PMKID_MODES); + sta->ignore_peer_erp_info = + cfg_get(psoc, CFG_IGNORE_PEER_ERP_INFO); + sta->sta_prefer_80mhz_over_160mhz = + cfg_get(psoc, CFG_STA_PREFER_80MHZ_OVER_160MHZ); + sta->enable_5g_ebt = + cfg_get(psoc, CFG_PPS_ENABLE_5G_EBT); + sta->deauth_before_connection = + cfg_get(psoc, CFG_ENABLE_DEAUTH_BEFORE_CONNECTION); + sta->dot11p_mode = + cfg_get(psoc, CFG_DOT11P_MODE); + sta->enable_go_cts2self_for_sta = + cfg_get(psoc, CFG_ENABLE_GO_CTS2SELF_FOR_STA); + sta->qcn_ie_support = + cfg_get(psoc, CFG_QCN_IE_SUPPORT); + sta->fils_max_chan_guard_time = + cfg_get(psoc, CFG_FILS_MAX_CHAN_GUARD_TIME); + sta->deauth_retry_cnt = cfg_get(psoc, CFG_DEAUTH_RETRY_CNT); + sta->single_tid = + cfg_get(psoc, CFG_SINGLE_TID_RC); + sta->sta_miracast_mcc_rest_time = + cfg_get(psoc, CFG_STA_MCAST_MCC_REST_TIME); + sta->wait_cnf_timeout = + (uint32_t)cfg_default(CFG_WT_CNF_TIMEOUT); + sta->current_rssi = + (uint32_t)cfg_default(CFG_CURRENT_RSSI); + sta->allow_tpc_from_ap = cfg_get(psoc, CFG_TX_POWER_CTRL); + sta->sta_keepalive_method = + cfg_get(psoc, CFG_STA_KEEPALIVE_METHOD); + sta->max_li_modulated_dtim_time_ms = + cfg_get(psoc, CFG_MAX_LI_MODULATED_DTIM_MS); + + mlme_init_sta_mlo_cfg(psoc, sta); + wlan_mlme_set_epcs_capability(psoc, + wlan_mlme_get_epcs_capability(psoc)); + wlan_mlme_set_usr_disable_sta_eht(psoc, false); + wlan_mlme_set_eht_disable_punct_in_us_lpi(psoc, + cfg_default(CFG_EHT_DISABLE_PUNCT_IN_US_LPI)); +} + +static void mlme_init_stats_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_stats_cfg *stats) +{ + stats->stats_periodic_display_time = + cfg_get(psoc, CFG_PERIODIC_STATS_DISPLAY_TIME); + stats->stats_link_speed_rssi_high = + cfg_get(psoc, CFG_LINK_SPEED_RSSI_HIGH); + stats->stats_link_speed_rssi_med = + cfg_get(psoc, CFG_LINK_SPEED_RSSI_MID); + stats->stats_link_speed_rssi_low = + cfg_get(psoc, CFG_LINK_SPEED_RSSI_LOW); + stats->stats_report_max_link_speed_rssi = + cfg_get(psoc, CFG_REPORT_MAX_LINK_SPEED); +} + +#ifdef WLAN_ADAPTIVE_11R +/** + * mlme_init_adaptive_11r_cfg() - initialize enable_adaptive_11r + * flag + * @psoc: Pointer to PSOC + * @lfr: pointer to mlme lfr config + * + * Return: None + */ +static void +mlme_init_adaptive_11r_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + lfr->enable_adaptive_11r = cfg_get(psoc, CFG_ADAPTIVE_11R); +} + +#else +static inline void +mlme_init_adaptive_11r_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ +} +#endif + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * mlme_init_sae_single_pmk_cfg() - initialize sae_same_pmk_config + * flag + * @psoc: Pointer to PSOC + * @lfr: pointer to mlme lfr config + * + * Return: None + */ +static void +mlme_init_sae_single_pmk_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + lfr->sae_single_pmk_feature_enabled = cfg_get(psoc, CFG_SAE_SINGLE_PMK); +} + +#else +static inline void +mlme_init_sae_single_pmk_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void mlme_init_roam_offload_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + bool val = false; + + lfr->lfr3_roaming_offload = + cfg_get(psoc, CFG_LFR3_ROAMING_OFFLOAD); + lfr->lfr3_dual_sta_roaming_enabled = + cfg_get(psoc, CFG_ENABLE_DUAL_STA_ROAM_OFFLOAD); + lfr->enable_self_bss_roam = cfg_get(psoc, CFG_LFR3_ENABLE_SELF_BSS_ROAM); + lfr->enable_roam_reason_vsie = + cfg_get(psoc, CFG_ENABLE_ROAM_REASON_VSIE); + lfr->enable_disconnect_roam_offload = + cfg_get(psoc, CFG_LFR_ENABLE_DISCONNECT_ROAM); + lfr->enable_idle_roam = + cfg_get(psoc, CFG_LFR_ENABLE_IDLE_ROAM); + lfr->idle_roam_rssi_delta = + cfg_get(psoc, CFG_LFR_IDLE_ROAM_RSSI_DELTA); + lfr->roam_info_stats_num = + cfg_get(psoc, CFG_LFR3_ROAM_INFO_STATS_NUM); + + ucfg_mlme_get_connection_roaming_ini_present(psoc, &val); + if (val) { + lfr->idle_roam_inactive_time = + cfg_get(psoc, CFG_ROAM_IDLE_INACTIVE_TIME) * 1000; + } else { + lfr->idle_roam_inactive_time = + cfg_get(psoc, CFG_LFR_IDLE_ROAM_INACTIVE_TIME); + } + + lfr->idle_data_packet_count = + cfg_get(psoc, CFG_LFR_IDLE_ROAM_PACKET_COUNT); + lfr->idle_roam_min_rssi = cfg_get(psoc, CFG_LFR_IDLE_ROAM_MIN_RSSI); + lfr->roam_trigger_bitmap = + cfg_get(psoc, CFG_ROAM_TRIGGER_BITMAP); + lfr->vendor_btm_param.user_roam_reason = DISABLE_VENDOR_BTM_CONFIG; + + lfr->idle_roam_band = cfg_get(psoc, CFG_LFR_IDLE_ROAM_BAND); + lfr->sta_roam_disable = cfg_get(psoc, CFG_STA_DISABLE_ROAM); + mlme_init_sae_single_pmk_cfg(psoc, lfr); + qdf_mem_zero(&lfr->roam_rt_stats, sizeof(lfr->roam_rt_stats)); +} + +void +wlan_mlme_defer_pmk_set_in_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set_pmk_pending) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + if (set_pmk_pending && !MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_err("get vdev failed"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->mlme_roam.set_pmk_pending = set_pmk_pending; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +bool +wlan_mlme_is_pmk_set_deferred(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + bool set_pmk_pending; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_err("get vdev failed"); + return false; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + set_pmk_pending = mlme_priv->mlme_roam.set_pmk_pending; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return set_pmk_pending; +} +#else +static void mlme_init_roam_offload_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ +} + +#endif + +#ifdef FEATURE_WLAN_ESE +static void mlme_init_ese_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + lfr->ese_enabled = cfg_get(psoc, CFG_LFR_ESE_FEATURE_ENABLED); +} +#else +static void mlme_init_ese_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ +} +#endif + +#ifdef FEATURE_LFR_SUBNET_DETECTION +static void mlme_init_subnet_detection(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + lfr->enable_lfr_subnet_detection = + cfg_get(psoc, CFG_LFR3_ENABLE_SUBNET_DETECTION); +} +#else +static void mlme_init_subnet_detection(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ +} +#endif + +static void +mlme_init_bss_load_trigger_params(struct wlan_objmgr_psoc *psoc, + struct bss_load_trigger *bss_load_trig) +{ + bool val = false; + + bss_load_trig->enabled = + cfg_get(psoc, CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM); + bss_load_trig->threshold = cfg_get(psoc, CFG_BSS_LOAD_THRESHOLD); + + ucfg_mlme_get_connection_roaming_ini_present(psoc, &val); + if (val) + bss_load_trig->sample_time = + cfg_get(psoc, CFG_ROAM_CU_MONITOR_TIME) * 1000; + else + bss_load_trig->sample_time = cfg_get(psoc, + CFG_BSS_LOAD_SAMPLE_TIME); + + bss_load_trig->rssi_threshold_6ghz = + cfg_get(psoc, CFG_BSS_LOAD_TRIG_6G_RSSI_THRES); + bss_load_trig->rssi_threshold_5ghz = + cfg_get(psoc, CFG_BSS_LOAD_TRIG_5G_RSSI_THRES); + bss_load_trig->rssi_threshold_24ghz = + cfg_get(psoc, CFG_BSS_LOAD_TRIG_2G_RSSI_THRES); +} + +void mlme_reinit_control_config_lfr_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + /* Restore the params set through SETDFSSCANMODE */ + lfr->roaming_dfs_channel = + cfg_get(psoc, CFG_LFR_ROAMING_DFS_CHANNEL); + + /* Restore the params set through SETWESMODE */ + lfr->wes_mode_enabled = cfg_get(psoc, CFG_LFR_ENABLE_WES_MODE); +} + +#ifdef CONNECTION_ROAMING_CFG +/** + * mlme_init_bmiss_timeout() - Init bmiss timeout + * @psoc: Pointer to psoc + * @lfr: Pointer to lfr config + * + * Return: None + */ +static void mlme_init_bmiss_timeout(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + lfr->beaconloss_timeout_onwakeup = + cfg_get(psoc, CFG_LFR_BEACONLOSS_TIMEOUT_ON_WAKEUP) / 2; + lfr->beaconloss_timeout_onsleep = + cfg_get(psoc, CFG_LFR_BEACONLOSS_TIMEOUT_ON_SLEEP) / 2; +} +#else +static void mlme_init_bmiss_timeout(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + lfr->beaconloss_timeout_onwakeup = + cfg_get(psoc, CFG_LFR_BEACONLOSS_TIMEOUT_ON_WAKEUP); + lfr->beaconloss_timeout_onsleep = + cfg_get(psoc, CFG_LFR_BEACONLOSS_TIMEOUT_ON_SLEEP); +} +#endif + +static void mlme_init_lfr_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_lfr_cfg *lfr) +{ + qdf_size_t neighbor_scan_chan_list_num = 0; + bool val = false; + + lfr->mawc_roam_enabled = + cfg_get(psoc, CFG_LFR_MAWC_ROAM_ENABLED); + lfr->enable_fast_roam_in_concurrency = + cfg_get(psoc, CFG_LFR_ENABLE_FAST_ROAM_IN_CONCURRENCY); + lfr->early_stop_scan_enable = + cfg_get(psoc, CFG_LFR_EARLY_STOP_SCAN_ENABLE); + lfr->enable_5g_band_pref = + cfg_get(psoc, CFG_LFR_ENABLE_5G_BAND_PREF); + lfr->lfr_enabled = cfg_get(psoc, CFG_LFR_FEATURE_ENABLED); + lfr->mawc_enabled = cfg_get(psoc, CFG_LFR_MAWC_FEATURE_ENABLED); + lfr->fast_transition_enabled = + cfg_get(psoc, CFG_LFR_FAST_TRANSITION_ENABLED); + lfr->wes_mode_enabled = cfg_get(psoc, CFG_LFR_ENABLE_WES_MODE); + lfr->mawc_roam_traffic_threshold = + cfg_get(psoc, CFG_LFR_MAWC_ROAM_TRAFFIC_THRESHOLD); + lfr->mawc_roam_ap_rssi_threshold = + cfg_get(psoc, CFG_LFR_MAWC_ROAM_AP_RSSI_THRESHOLD); + lfr->mawc_roam_rssi_high_adjust = + cfg_get(psoc, CFG_LFR_MAWC_ROAM_RSSI_HIGH_ADJUST); + lfr->mawc_roam_rssi_low_adjust = + cfg_get(psoc, CFG_LFR_MAWC_ROAM_RSSI_LOW_ADJUST); + lfr->roam_rssi_abs_threshold = + cfg_get(psoc, CFG_LFR_ROAM_RSSI_ABS_THRESHOLD); + lfr->rssi_threshold_offset_5g = + cfg_get(psoc, CFG_LFR_5G_RSSI_THRESHOLD_OFFSET); + lfr->early_stop_scan_min_threshold = + cfg_get(psoc, CFG_LFR_EARLY_STOP_SCAN_MIN_THRESHOLD); + lfr->early_stop_scan_max_threshold = + cfg_get(psoc, CFG_LFR_EARLY_STOP_SCAN_MAX_THRESHOLD); + lfr->roam_dense_traffic_threshold = + cfg_get(psoc, CFG_LFR_ROAM_DENSE_TRAFFIC_THRESHOLD); + lfr->roam_dense_rssi_thre_offset = + cfg_get(psoc, CFG_LFR_ROAM_DENSE_RSSI_THRE_OFFSET); + lfr->roam_dense_min_aps = + cfg_get(psoc, CFG_LFR_ROAM_DENSE_MIN_APS); + lfr->roam_bg_scan_bad_rssi_threshold = + cfg_get(psoc, CFG_LFR_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD); + lfr->roam_bg_scan_client_bitmap = + cfg_get(psoc, CFG_LFR_ROAM_BG_SCAN_CLIENT_BITMAP); + lfr->roam_bg_scan_bad_rssi_offset_2g = + cfg_get(psoc, CFG_LFR_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G); + lfr->roam_data_rssi_threshold_triggers = + cfg_get(psoc, CFG_ROAM_DATA_RSSI_THRESHOLD_TRIGGERS); + lfr->roam_data_rssi_threshold = + cfg_get(psoc, CFG_ROAM_DATA_RSSI_THRESHOLD); + lfr->rx_data_inactivity_time = + cfg_get(psoc, CFG_RX_DATA_INACTIVITY_TIME); + lfr->adaptive_roamscan_dwell_mode = + cfg_get(psoc, CFG_LFR_ADAPTIVE_ROAMSCAN_DWELL_MODE); + lfr->per_roam_enable = + cfg_get(psoc, CFG_LFR_PER_ROAM_ENABLE); + lfr->per_roam_config_high_rate_th = + cfg_get(psoc, CFG_LFR_PER_ROAM_CONFIG_HIGH_RATE_TH); + lfr->per_roam_config_low_rate_th = + cfg_get(psoc, CFG_LFR_PER_ROAM_CONFIG_LOW_RATE_TH); + lfr->per_roam_config_rate_th_percent = + cfg_get(psoc, CFG_LFR_PER_ROAM_CONFIG_RATE_TH_PERCENT); + lfr->per_roam_rest_time = + cfg_get(psoc, CFG_LFR_PER_ROAM_REST_TIME); + lfr->per_roam_monitor_time = + cfg_get(psoc, CFG_LFR_PER_ROAM_MONITOR_TIME); + lfr->per_roam_min_candidate_rssi = + cfg_get(psoc, CFG_LFR_PER_ROAM_MIN_CANDIDATE_RSSI); + lfr->lfr3_disallow_duration = + cfg_get(psoc, CFG_LFR3_ROAM_DISALLOW_DURATION); + lfr->lfr3_rssi_channel_penalization = + cfg_get(psoc, CFG_LFR3_ROAM_RSSI_CHANNEL_PENALIZATION); + lfr->lfr3_num_disallowed_aps = + cfg_get(psoc, CFG_LFR3_ROAM_NUM_DISALLOWED_APS); + + if (lfr->enable_5g_band_pref) { + lfr->rssi_boost_threshold_5g = + cfg_get(psoc, CFG_LFR_5G_RSSI_BOOST_THRESHOLD); + lfr->rssi_boost_factor_5g = + cfg_get(psoc, CFG_LFR_5G_RSSI_BOOST_FACTOR); + lfr->max_rssi_boost_5g = + cfg_get(psoc, CFG_LFR_5G_MAX_RSSI_BOOST); + lfr->rssi_penalize_threshold_5g = + cfg_get(psoc, CFG_LFR_5G_RSSI_PENALIZE_THRESHOLD); + lfr->rssi_penalize_factor_5g = + cfg_get(psoc, CFG_LFR_5G_RSSI_PENALIZE_FACTOR); + lfr->max_rssi_penalize_5g = + cfg_get(psoc, CFG_LFR_5G_MAX_RSSI_PENALIZE); + } + + lfr->max_num_pre_auth = (uint32_t) + cfg_default(CFG_LFR_MAX_NUM_PRE_AUTH); + lfr->roam_preauth_no_ack_timeout = + cfg_get(psoc, CFG_LFR3_ROAM_PREAUTH_NO_ACK_TIMEOUT); + lfr->roam_preauth_retry_count = + cfg_get(psoc, CFG_LFR3_ROAM_PREAUTH_RETRY_COUNT); + lfr->roam_rssi_diff = cfg_get(psoc, CFG_LFR_ROAM_RSSI_DIFF); + lfr->roam_rssi_diff_6ghz = cfg_get(psoc, CFG_LFR_ROAM_RSSI_DIFF_6GHZ); + lfr->bg_rssi_threshold = cfg_get(psoc, CFG_LFR_ROAM_BG_RSSI_TH); + lfr->roam_scan_offload_enabled = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED); + lfr->neighbor_scan_timer_period = + cfg_get(psoc, CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD); + lfr->neighbor_scan_min_timer_period = + cfg_get(psoc, CFG_LFR_NEIGHBOR_SCAN_MIN_TIMER_PERIOD); + lfr->neighbor_lookup_rssi_threshold = + abs(cfg_get(psoc, CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD)); + lfr->opportunistic_scan_threshold_diff = + cfg_get(psoc, CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF); + lfr->roam_rescan_rssi_diff = + cfg_get(psoc, CFG_LFR_ROAM_RESCAN_RSSI_DIFF); + lfr->neighbor_scan_min_chan_time = + cfg_get(psoc, CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME); + lfr->neighbor_scan_max_chan_time = + cfg_get(psoc, CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME); + lfr->passive_max_channel_time = + cfg_get(psoc, CFG_ROAM_PASSIVE_MAX_CHANNEL_TIME); + lfr->neighbor_scan_results_refresh_period = + cfg_get(psoc, CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD); + + ucfg_mlme_get_connection_roaming_ini_present(psoc, &val); + if (val) + lfr->empty_scan_refresh_period = + cfg_get(psoc, CFG_ROAM_SCAN_FIRST_TIMER) * 1000; + else + lfr->empty_scan_refresh_period = + cfg_get(psoc, CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD); + lfr->roam_bmiss_first_bcnt = + cfg_get(psoc, CFG_LFR_ROAM_BMISS_FIRST_BCNT); + lfr->roam_bmiss_final_bcnt = + cfg_get(psoc, CFG_LFR_ROAM_BMISS_FINAL_BCNT); + lfr->roaming_dfs_channel = + cfg_get(psoc, CFG_LFR_ROAMING_DFS_CHANNEL); + lfr->roam_scan_hi_rssi_maxcount = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_HI_RSSI_MAXCOUNT); + lfr->roam_scan_hi_rssi_delta = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_HI_RSSI_DELTA); + lfr->roam_scan_hi_rssi_delay = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_HI_RSSI_DELAY); + lfr->roam_scan_hi_rssi_ub = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_HI_RSSI_UB); + lfr->roam_prefer_5ghz = + cfg_get(psoc, CFG_LFR_ROAM_PREFER_5GHZ); + lfr->roam_intra_band = + cfg_get(psoc, CFG_LFR_ROAM_INTRA_BAND); + lfr->roam_scan_home_away_time = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME); + lfr->roam_scan_n_probes = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_N_PROBES); + lfr->delay_before_vdev_stop = + cfg_get(psoc, CFG_LFR_DELAY_BEFORE_VDEV_STOP); + qdf_uint8_array_parse(cfg_get(psoc, CFG_LFR_NEIGHBOR_SCAN_CHANNEL_LIST), + lfr->neighbor_scan_channel_list, + CFG_VALID_CHANNEL_LIST_LEN, + &neighbor_scan_chan_list_num); + lfr->neighbor_scan_channel_list_num = + (uint8_t)neighbor_scan_chan_list_num; + lfr->ho_delay_for_rx = + cfg_get(psoc, CFG_LFR3_ROAM_HO_DELAY_FOR_RX); + lfr->min_delay_btw_roam_scans = + cfg_get(psoc, CFG_LFR_MIN_DELAY_BTW_ROAM_SCAN); + lfr->roam_trigger_reason_bitmask = + cfg_get(psoc, CFG_LFR_ROAM_SCAN_TRIGGER_REASON_BITMASK); + lfr->enable_ftopen = + cfg_get(psoc, CFG_LFR_ROAM_FT_OPEN_ENABLE); + lfr->roam_force_rssi_trigger = + cfg_get(psoc, CFG_LFR_ROAM_FORCE_RSSI_TRIGGER); + lfr->roaming_scan_policy = + cfg_get(psoc, CFG_ROAM_SCAN_SCAN_POLICY); + + if (val) + lfr->roam_scan_inactivity_time = + cfg_get(psoc, CFG_ROAM_SCAN_INACTIVE_TIMER) * 1000; + else + lfr->roam_scan_inactivity_time = + cfg_get(psoc, CFG_ROAM_SCAN_INACTIVITY_TIME); + + lfr->roam_inactive_data_packet_count = + cfg_get(psoc, CFG_ROAM_INACTIVE_COUNT); + + lfr->fw_akm_bitmap = 0; + lfr->enable_ft_im_roaming = cfg_get(psoc, CFG_FT_IM_ROAMING); + lfr->enable_ft_over_ds = !ENABLE_FT_OVER_DS; + + mlme_init_roam_offload_cfg(psoc, lfr); + mlme_init_ese_cfg(psoc, lfr); + mlme_init_bss_load_trigger_params(psoc, &lfr->bss_load_trig); + mlme_init_adaptive_11r_cfg(psoc, lfr); + mlme_init_subnet_detection(psoc, lfr); + lfr->rso_user_config.cat_rssi_offset = DEFAULT_RSSI_DB_GAP; + mlme_init_bmiss_timeout(psoc, lfr); + lfr->hs20_btm_offload_disable = cfg_get(psoc, + CFG_HS_20_BTM_OFFLOAD_DISABLE); +} + +static void mlme_init_power_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_power *power) +{ + power->tx_power_2g = cfg_get(psoc, CFG_SET_TXPOWER_LIMIT2G); + power->tx_power_5g = cfg_get(psoc, CFG_SET_TXPOWER_LIMIT5G); + + power->max_tx_power_24_chan.max_len = CFG_MAX_TX_POWER_2_4_LEN; + qdf_uint8_array_parse(cfg_default(CFG_MAX_TX_POWER_2_4), + power->max_tx_power_24_chan.data, + sizeof(power->max_tx_power_24_chan.data), + &power->max_tx_power_24_chan.len); + + power->max_tx_power_5_chan.max_len = CFG_MAX_TX_POWER_5_LEN; + qdf_uint8_array_parse(cfg_default(CFG_MAX_TX_POWER_5), + power->max_tx_power_5_chan.data, + sizeof(power->max_tx_power_5_chan.data), + &power->max_tx_power_5_chan.len); + + power->power_usage.max_len = CFG_POWER_USAGE_MAX_LEN; + power->power_usage.len = CFG_POWER_USAGE_MAX_LEN; + qdf_mem_copy(power->power_usage.data, cfg_get(psoc, CFG_POWER_USAGE), + power->power_usage.len); + power->current_tx_power_level = + (uint8_t)cfg_default(CFG_CURRENT_TX_POWER_LEVEL); + power->local_power_constraint = + (uint8_t)cfg_default(CFG_LOCAL_POWER_CONSTRAINT); + power->skip_tpe = cfg_get(psoc, CFG_SKIP_TPE_CONSIDERATION); +} + +static void mlme_init_roam_scoring_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_roam_scoring_cfg *scoring_cfg) +{ + bool val = false; + + scoring_cfg->enable_scoring_for_roam = + cfg_get(psoc, CFG_ENABLE_SCORING_FOR_ROAM); + scoring_cfg->roam_trigger_bitmap = + cfg_get(psoc, CFG_ROAM_SCORE_DELTA_TRIGGER_BITMAP); + scoring_cfg->roam_score_delta = cfg_get(psoc, CFG_ROAM_SCORE_DELTA); + scoring_cfg->apsd_enabled = (bool)cfg_default(CFG_APSD_ENABLED); + + ucfg_mlme_get_connection_roaming_ini_present(psoc, &val); + if (val) { + scoring_cfg->min_roam_score_delta = + cfg_get(psoc, CFG_ROAM_COMMON_MIN_ROAM_DELTA) * 100; + } else { + scoring_cfg->min_roam_score_delta = + cfg_get(psoc, CFG_CAND_MIN_ROAM_SCORE_DELTA); + } +} + +static void mlme_init_oce_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_oce *oce) +{ + uint8_t val; + bool rssi_assoc_reject_enabled; + bool probe_req_rate_enabled; + bool probe_resp_rate_enabled; + bool beacon_rate_enabled; + bool probe_req_deferral_enabled; + bool fils_discovery_sap_enabled; + bool esp_for_roam_enabled; + + oce->enable_bcast_probe_rsp = + cfg_get(psoc, CFG_ENABLE_BCAST_PROBE_RESP); + oce->oce_sta_enabled = cfg_get(psoc, CFG_OCE_ENABLE_STA); + oce->oce_sap_enabled = cfg_get(psoc, CFG_OCE_ENABLE_SAP); + oce->fils_enabled = cfg_get(psoc, CFG_IS_FILS_ENABLED); + + rssi_assoc_reject_enabled = + cfg_get(psoc, CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT); + probe_req_rate_enabled = cfg_get(psoc, CFG_OCE_PROBE_REQ_RATE); + probe_resp_rate_enabled = cfg_get(psoc, CFG_OCE_PROBE_RSP_RATE); + beacon_rate_enabled = cfg_get(psoc, CFG_OCE_BEACON_RATE); + probe_req_deferral_enabled = + cfg_get(psoc, CFG_ENABLE_PROBE_REQ_DEFERRAL); + fils_discovery_sap_enabled = + cfg_get(psoc, CFG_ENABLE_FILS_DISCOVERY_SAP); + esp_for_roam_enabled = cfg_get(psoc, CFG_ENABLE_ESP_FEATURE); + + if (!rssi_assoc_reject_enabled || + !oce->enable_bcast_probe_rsp) { + oce->oce_sta_enabled = 0; + } + + val = (probe_req_rate_enabled * + WMI_VDEV_OCE_PROBE_REQUEST_RATE_FEATURE_BITMAP) + + (probe_resp_rate_enabled * + WMI_VDEV_OCE_PROBE_RESPONSE_RATE_FEATURE_BITMAP) + + (beacon_rate_enabled * + WMI_VDEV_OCE_BEACON_RATE_FEATURE_BITMAP) + + (probe_req_deferral_enabled * + WMI_VDEV_OCE_PROBE_REQUEST_DEFERRAL_FEATURE_BITMAP) + + (fils_discovery_sap_enabled * + WMI_VDEV_OCE_FILS_DISCOVERY_FRAME_FEATURE_BITMAP) + + (esp_for_roam_enabled * + WMI_VDEV_OCE_ESP_FEATURE_BITMAP) + + (rssi_assoc_reject_enabled * + WMI_VDEV_OCE_REASSOC_REJECT_FEATURE_BITMAP); + oce->feature_bitmap = val; +} + +static void mlme_init_nss_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_nss_chains *nss_chains) +{ + nss_chains->num_rx_chains[NSS_CHAINS_BAND_2GHZ] = + cfg_get(psoc, CFG_NUM_RX_CHAINS_2G); + nss_chains->num_rx_chains[NSS_CHAINS_BAND_5GHZ] = + cfg_get(psoc, CFG_NUM_RX_CHAINS_5G); + nss_chains->num_tx_chains[NSS_CHAINS_BAND_2GHZ] = + cfg_get(psoc, CFG_NUM_TX_CHAINS_2G); + nss_chains->num_tx_chains[NSS_CHAINS_BAND_5GHZ] = + cfg_get(psoc, CFG_NUM_TX_CHAINS_5G); + + nss_chains->tx_nss[NSS_CHAINS_BAND_2GHZ] = cfg_get(psoc, CFG_TX_NSS_2G); + nss_chains->tx_nss[NSS_CHAINS_BAND_5GHZ] = cfg_get(psoc, CFG_TX_NSS_5G); + nss_chains->rx_nss[NSS_CHAINS_BAND_2GHZ] = cfg_get(psoc, CFG_RX_NSS_2G); + nss_chains->rx_nss[NSS_CHAINS_BAND_5GHZ] = cfg_get(psoc, CFG_RX_NSS_5G); + + nss_chains->num_tx_chains_11b = cfg_get(psoc, CFG_NUM_TX_CHAINS_11b); + nss_chains->num_tx_chains_11g = cfg_get(psoc, CFG_NUM_TX_CHAINS_11g); + nss_chains->num_tx_chains_11a = cfg_get(psoc, CFG_NUM_TX_CHAINS_11a); + + nss_chains->disable_rx_mrc[NSS_CHAINS_BAND_2GHZ] = + cfg_get(psoc, CFG_DISABLE_RX_MRC_2G); + nss_chains->disable_rx_mrc[NSS_CHAINS_BAND_5GHZ] = + cfg_get(psoc, CFG_DISABLE_RX_MRC_5G); + nss_chains->disable_tx_mrc[NSS_CHAINS_BAND_2GHZ] = + cfg_get(psoc, CFG_DISABLE_TX_MRC_2G); + nss_chains->disable_tx_mrc[NSS_CHAINS_BAND_5GHZ] = + cfg_get(psoc, CFG_DISABLE_TX_MRC_5G); + nss_chains->enable_dynamic_nss_chains_cfg = + cfg_get(psoc, CFG_ENABLE_DYNAMIC_NSS_CHAIN_CONFIG); + nss_chains->restart_sap_on_dyn_nss_chains_cfg = + cfg_get(psoc, + CFG_RESTART_SAP_ON_DYNAMIC_NSS_CHAINS_CONFIG); +} + +static void mlme_init_wep_cfg(struct wlan_mlme_wep_cfg *wep_params) +{ + wep_params->is_privacy_enabled = cfg_default(CFG_PRIVACY_ENABLED); + wep_params->auth_type = cfg_default(CFG_AUTHENTICATION_TYPE); + wep_params->is_shared_key_auth = + cfg_default(CFG_SHARED_KEY_AUTH_ENABLE); + wep_params->is_auth_open_system = + cfg_default(CFG_OPEN_SYSTEM_AUTH_ENABLE); + + wep_params->wep_default_key_id = cfg_default(CFG_WEP_DEFAULT_KEYID); +} + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +static void +mlme_init_wifi_pos_11az_config(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wifi_pos_cfg *wifi_pos_cfg) +{ + bool rsta_sec_ltf_enabled = + cfg_get(psoc, CFG_RESPONDER_SECURE_LTF_SUPPORT); + uint32_t rsta_11az_ranging_enabled = + cfg_get(psoc, CFG_RESPONDER_11AZ_SUPPORT); + + wifi_pos_set_rsta_11az_ranging_cap(rsta_11az_ranging_enabled); + wifi_pos_set_rsta_sec_ltf_cap(rsta_sec_ltf_enabled); +} +#else +static inline void +mlme_init_wifi_pos_11az_config(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wifi_pos_cfg *wifi_pos_cfg) +{} +#endif + +static void mlme_init_wifi_pos_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wifi_pos_cfg *wifi_pos_cfg) +{ + wifi_pos_cfg->fine_time_meas_cap = + cfg_get(psoc, CFG_FINE_TIME_MEAS_CAPABILITY); + wifi_pos_cfg->oem_6g_support_disable = + cfg_get(psoc, CFG_OEM_SIXG_SUPPORT_DISABLE); + + mlme_init_wifi_pos_11az_config(psoc, wifi_pos_cfg); +} + +#ifdef FEATURE_WLAN_ESE +static void mlme_init_inactivity_intv(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wmm_params *wmm_params) +{ + wmm_params->wmm_tspec_element.inactivity_intv = + cfg_get(psoc, CFG_QOS_WMM_INACTIVITY_INTERVAL); +} +#else +static inline void +mlme_init_inactivity_intv(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wmm_params *wmm_params) +{ +} +#endif /* FEATURE_WLAN_ESE */ + +static void mlme_init_wmm_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wmm_params *wmm_params) +{ + wmm_params->qos_enabled = cfg_default(CFG_QOS_ENABLED); + wmm_params->wme_enabled = cfg_default(CFG_WME_ENABLED); + wmm_params->max_sp_length = cfg_default(CFG_MAX_SP_LENGTH); + wmm_params->wsm_enabled = cfg_default(CFG_WSM_ENABLED); + wmm_params->edca_profile = cfg_default(CFG_EDCA_PROFILE); + + wmm_params->ac_vo.dir_ac_vo = cfg_get(psoc, CFG_QOS_WMM_DIR_AC_VO); + wmm_params->ac_vo.nom_msdu_size_ac_vo = + cfg_get(psoc, CFG_QOS_WMM_NOM_MSDU_SIZE_AC_VO); + wmm_params->ac_vo.mean_data_rate_ac_vo = + cfg_get(psoc, CFG_QOS_WMM_MEAN_DATA_RATE_AC_VO); + wmm_params->ac_vo.min_phy_rate_ac_vo = + cfg_get(psoc, CFG_QOS_WMM_MIN_PHY_RATE_AC_VO); + wmm_params->ac_vo.sba_ac_vo = cfg_get(psoc, CFG_QOS_WMM_SBA_AC_VO); + wmm_params->ac_vo.uapsd_vo_srv_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_VO_SRV_INTV); + wmm_params->ac_vo.uapsd_vo_sus_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_VO_SUS_INTV); + + wmm_params->ac_vi.dir_ac_vi = + cfg_get(psoc, CFG_QOS_WMM_DIR_AC_VI); + wmm_params->ac_vi.nom_msdu_size_ac_vi = + cfg_get(psoc, CFG_QOS_WMM_NOM_MSDU_SIZE_AC_VI); + wmm_params->ac_vi.mean_data_rate_ac_vi = + cfg_get(psoc, CFG_QOS_WMM_MEAN_DATA_RATE_AC_VI); + wmm_params->ac_vi.min_phy_rate_ac_vi = + cfg_get(psoc, CFG_QOS_WMM_MIN_PHY_RATE_AC_VI); + wmm_params->ac_vi.sba_ac_vi = + cfg_get(psoc, CFG_QOS_WMM_SBA_AC_VI); + wmm_params->ac_vi.uapsd_vi_srv_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_VI_SRV_INTV); + wmm_params->ac_vi.uapsd_vi_sus_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_VI_SUS_INTV); + + wmm_params->ac_be.dir_ac_be = + cfg_get(psoc, CFG_QOS_WMM_DIR_AC_BE); + wmm_params->ac_be.nom_msdu_size_ac_be = + cfg_get(psoc, CFG_QOS_WMM_NOM_MSDU_SIZE_AC_BE); + wmm_params->ac_be.mean_data_rate_ac_be = + cfg_get(psoc, CFG_QOS_WMM_MEAN_DATA_RATE_AC_BE); + wmm_params->ac_be.min_phy_rate_ac_be = + cfg_get(psoc, CFG_QOS_WMM_MIN_PHY_RATE_AC_BE); + wmm_params->ac_be.sba_ac_be = + cfg_get(psoc, CFG_QOS_WMM_SBA_AC_BE); + wmm_params->ac_be.uapsd_be_srv_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_BE_SRV_INTV); + wmm_params->ac_be.uapsd_be_sus_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_BE_SUS_INTV); + + wmm_params->ac_bk.dir_ac_bk = + cfg_get(psoc, CFG_QOS_WMM_DIR_AC_BK); + wmm_params->ac_bk.nom_msdu_size_ac_bk = + cfg_get(psoc, CFG_QOS_WMM_NOM_MSDU_SIZE_AC_BK); + wmm_params->ac_bk.mean_data_rate_ac_bk = + cfg_get(psoc, CFG_QOS_WMM_MEAN_DATA_RATE_AC_BK); + wmm_params->ac_bk.min_phy_rate_ac_bk = + cfg_get(psoc, CFG_QOS_WMM_MIN_PHY_RATE_AC_BK); + wmm_params->ac_bk.sba_ac_bk = + cfg_get(psoc, CFG_QOS_WMM_SBA_AC_BK); + wmm_params->ac_bk.uapsd_bk_srv_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_BK_SRV_INTV); + wmm_params->ac_bk.uapsd_bk_sus_intv = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_BK_SUS_INTV); + + wmm_params->wmm_config.wmm_mode = + cfg_get(psoc, CFG_QOS_WMM_MODE); + wmm_params->wmm_config.b80211e_is_enabled = + cfg_get(psoc, CFG_QOS_WMM_80211E_ENABLED); + wmm_params->wmm_config.uapsd_mask = + cfg_get(psoc, CFG_QOS_WMM_UAPSD_MASK); + + mlme_init_inactivity_intv(psoc, wmm_params); + wmm_params->wmm_tspec_element.burst_size_def = + cfg_get(psoc, CFG_QOS_WMM_BURST_SIZE_DEFN); + wmm_params->wmm_tspec_element.ts_ack_policy = + cfg_get(psoc, CFG_QOS_WMM_TS_INFO_ACK_POLICY); + wmm_params->wmm_tspec_element.ts_acm_is_off = + cfg_get(psoc, CFG_QOS_ADDTS_WHEN_ACM_IS_OFF); + wmm_params->delayed_trigger_frm_int = + cfg_get(psoc, CFG_TL_DELAYED_TRGR_FRM_INTERVAL); + +} + +static void mlme_init_wps_params_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_wps_params *wps_params) +{ + wps_params->enable_wps = cfg_default(CFG_WPS_ENABLE); + wps_params->wps_cfg_method = cfg_default(CFG_WPS_CFG_METHOD); + wps_params->wps_device_password_id = + cfg_default(CFG_WPS_DEVICE_PASSWORD_ID); + wps_params->wps_device_sub_category = + cfg_default(CFG_WPS_DEVICE_SUB_CATEGORY); + wps_params->wps_primary_device_category = + cfg_default(CFG_WPS_PRIMARY_DEVICE_CATEGORY); + wps_params->wps_primary_device_oui = + cfg_default(CFG_WPS_PIMARY_DEVICE_OUI); + wps_params->wps_state = cfg_default(CFG_WPS_STATE); + wps_params->wps_version = cfg_default(CFG_WPS_VERSION); + wps_params->wps_uuid.max_len = MLME_CFG_WPS_UUID_MAX_LEN; + qdf_uint8_array_parse(cfg_default(CFG_WPS_UUID), + wps_params->wps_uuid.data, + MLME_CFG_WPS_UUID_MAX_LEN, + &wps_params->wps_uuid.len); +} + +static void mlme_init_btm_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_btm *btm) +{ + btm->btm_offload_config = cfg_get(psoc, CFG_BTM_ENABLE); + btm->prefer_btm_query = cfg_get(psoc, CFG_PREFER_BTM_QUERY); + if (btm->prefer_btm_query) + MLME_SET_BIT(btm->btm_offload_config, BTM_OFFLOAD_CONFIG_BIT_8); + + btm->abridge_flag = cfg_get(psoc, CFG_ENABLE_BTM_ABRIDGE); + if (btm->abridge_flag) + MLME_SET_BIT(btm->btm_offload_config, BTM_OFFLOAD_CONFIG_BIT_7); + wlan_mlme_set_btm_abridge_flag(psoc, btm->abridge_flag); + + btm->btm_solicited_timeout = cfg_get(psoc, CFG_BTM_SOLICITED_TIMEOUT); + btm->btm_max_attempt_cnt = cfg_get(psoc, CFG_BTM_MAX_ATTEMPT_CNT); + btm->btm_sticky_time = cfg_get(psoc, CFG_BTM_STICKY_TIME); + btm->rct_validity_timer = cfg_get(psoc, CFG_BTM_VALIDITY_TIMER); + btm->disassoc_timer_threshold = + cfg_get(psoc, CFG_BTM_DISASSOC_TIMER_THRESHOLD); + btm->btm_query_bitmask = cfg_get(psoc, CFG_BTM_QUERY_BITMASK); + btm->btm_trig_min_candidate_score = + cfg_get(psoc, CFG_MIN_BTM_CANDIDATE_SCORE); +} + +static void +mlme_init_roam_score_config(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_cfg *mlme_cfg) +{ + struct roam_trigger_score_delta *score_delta_param; + struct roam_trigger_min_rssi *min_rssi_param; + + score_delta_param = &mlme_cfg->trig_score_delta[IDLE_ROAM_TRIGGER]; + score_delta_param->roam_score_delta = + cfg_get(psoc, CFG_IDLE_ROAM_SCORE_DELTA); + score_delta_param->trigger_reason = ROAM_TRIGGER_REASON_IDLE; + + score_delta_param = &mlme_cfg->trig_score_delta[BTM_ROAM_TRIGGER]; + score_delta_param->roam_score_delta = + cfg_get(psoc, CFG_BTM_ROAM_SCORE_DELTA); + score_delta_param->trigger_reason = ROAM_TRIGGER_REASON_BTM; + + min_rssi_param = &mlme_cfg->trig_min_rssi[DEAUTH_MIN_RSSI]; + min_rssi_param->min_rssi = + cfg_get(psoc, CFG_DISCONNECT_ROAM_TRIGGER_MIN_RSSI); + min_rssi_param->trigger_reason = ROAM_TRIGGER_REASON_DEAUTH; + + min_rssi_param = &mlme_cfg->trig_min_rssi[BMISS_MIN_RSSI]; + min_rssi_param->min_rssi = + cfg_get(psoc, CFG_BMISS_ROAM_MIN_RSSI); + min_rssi_param->trigger_reason = ROAM_TRIGGER_REASON_BMISS; + + min_rssi_param = &mlme_cfg->trig_min_rssi[MIN_RSSI_2G_TO_5G_ROAM]; + min_rssi_param->min_rssi = + cfg_get(psoc, CFG_2G_TO_5G_ROAM_MIN_RSSI); + min_rssi_param->trigger_reason = ROAM_TRIGGER_REASON_HIGH_RSSI; + +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +static void +mlme_init_wlm_multi_client_ll_support(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_fe_wlm *wlm_config) +{ + wlm_config->multi_client_ll_support = + cfg_get(psoc, CFG_WLM_MULTI_CLIENT_LL_SUPPORT); +} + +QDF_STATUS +mlme_get_cfg_multi_client_ll_ini_support(struct wlan_objmgr_psoc *psoc, + bool *multi_client_ll_support) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *multi_client_ll_support = + mlme_obj->cfg.wlm_config.multi_client_ll_support; + + return QDF_STATUS_SUCCESS; +} +#else +static inline void +mlme_init_wlm_multi_client_ll_support(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_fe_wlm *wlm_config) +{ +} +#endif + +/** + * mlme_init_fe_wlm_in_cfg() - Populate WLM INI in MLME cfg + * @psoc: pointer to the psoc object + * @wlm_config: pointer to the MLME WLM cfg + * + * Return: None + */ +static void mlme_init_fe_wlm_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_fe_wlm *wlm_config) +{ + uint64_t flags = 0; + QDF_STATUS status; + + wlm_config->latency_enable = cfg_get(psoc, CFG_LATENCY_ENABLE); + wlm_config->latency_reset = cfg_get(psoc, CFG_LATENCY_RESET); + wlm_config->latency_level = cfg_get(psoc, CFG_LATENCY_LEVEL); + mlme_init_wlm_multi_client_ll_support(psoc, wlm_config); + + status = qdf_uint64_parse(cfg_get(psoc, CFG_LATENCY_FLAGS_NORMAL), + &flags); + if (status != QDF_STATUS_SUCCESS) { + flags = 0; + mlme_legacy_err("normal latency flags parsing failed"); + } + + wlm_config->latency_flags[0] = flags & 0xFFFFFFFF; + wlm_config->latency_host_flags[0] = flags >> 32; + mlme_legacy_debug("normal latency flags 0x%x host flags 0x%x", + wlm_config->latency_flags[0], + wlm_config->latency_host_flags[0]); + + status = qdf_uint64_parse(cfg_get(psoc, CFG_LATENCY_FLAGS_XR), + &flags); + if (status != QDF_STATUS_SUCCESS) { + flags = 0; + mlme_legacy_err("xr latency flags parsing failed"); + } + + wlm_config->latency_flags[1] = flags & 0xFFFFFFFF; + wlm_config->latency_host_flags[1] = flags >> 32; + mlme_legacy_debug("xr latency flags 0x%x host flags 0x%x", + wlm_config->latency_flags[1], + wlm_config->latency_host_flags[1]); + + status = qdf_uint64_parse(cfg_get(psoc, CFG_LATENCY_FLAGS_LOW), + &flags); + if (status != QDF_STATUS_SUCCESS) { + flags = 0; + mlme_legacy_err("low latency flags parsing failed"); + } + + wlm_config->latency_flags[2] = flags & 0xFFFFFFFF; + wlm_config->latency_host_flags[2] = flags >> 32; + mlme_legacy_debug("low latency flags 0x%x host flags 0x%x", + wlm_config->latency_flags[2], + wlm_config->latency_host_flags[2]); + + status = qdf_uint64_parse(cfg_get(psoc, CFG_LATENCY_FLAGS_ULTLOW), + &flags); + if (status != QDF_STATUS_SUCCESS) { + flags = 0; + mlme_legacy_err("ultra-low latency flags parsing failed"); + } + + wlm_config->latency_flags[3] = flags & 0xFFFFFFFF; + wlm_config->latency_host_flags[3] = flags >> 32; + mlme_legacy_debug("ultra-low latency flags 0x%x host flags 0x%x", + wlm_config->latency_flags[3], + wlm_config->latency_host_flags[3]); +} + +/** + * mlme_init_fe_rrm_in_cfg() - Populate RRM INI in MLME cfg + * @psoc: pointer to the psoc object + * @rrm_config: pointer to the MLME RRM cfg + * + * Return: None + */ +static void mlme_init_fe_rrm_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_fe_rrm *rrm_config) +{ + qdf_size_t len; + + rrm_config->rrm_enabled = cfg_get(psoc, CFG_RRM_ENABLE); + rrm_config->sap_rrm_enabled = cfg_get(psoc, CFG_SAP_RRM_ENABLE); + rrm_config->rrm_rand_interval = cfg_get(psoc, CFG_RRM_MEAS_RAND_INTVL); + + qdf_uint8_array_parse(cfg_get(psoc, CFG_RM_CAPABILITY), + rrm_config->rm_capability, + sizeof(rrm_config->rm_capability), &len); + + if (len < MLME_RMENABLEDCAP_MAX_LEN) { + mlme_legacy_debug("Incorrect RM capability, using default"); + qdf_uint8_array_parse(cfg_default(CFG_RM_CAPABILITY), + rrm_config->rm_capability, + sizeof(rrm_config->rm_capability), &len); + } +} + +static void mlme_init_powersave_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_powersave *ps_cfg) +{ + ps_cfg->is_imps_enabled = cfg_get(psoc, CFG_ENABLE_IMPS); + ps_cfg->is_bmps_enabled = cfg_get(psoc, CFG_ENABLE_PS); + ps_cfg->auto_bmps_timer_val = cfg_get(psoc, CFG_AUTO_BMPS_ENABLE_TIMER); + ps_cfg->bmps_min_listen_interval = cfg_get(psoc, CFG_BMPS_MINIMUM_LI); + ps_cfg->bmps_max_listen_interval = cfg_get(psoc, CFG_BMPS_MAXIMUM_LI); + ps_cfg->dtim_selection_diversity = + cfg_get(psoc, CFG_DTIM_SELECTION_DIVERSITY); +} + +#if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_BAND_6GHZ) +static void mlme_init_afc_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ + reg->enable_6ghz_sp_pwrmode_supp = + cfg_get(psoc, CFG_6GHZ_SP_POWER_MODE_SUPP); + reg->afc_disable_timer_check = + cfg_default(CFG_AFC_TIMER_CHECK_DIS); + reg->afc_disable_request_id_check = + cfg_default(CFG_AFC_REQ_ID_CHECK_DIS); + reg->is_afc_reg_noaction = + cfg_default(CFG_AFC_REG_NO_ACTION); +} +#else +static inline void mlme_init_afc_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ +} +#endif + +#ifdef MWS_COEX +static void mlme_init_mwc_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_mwc *mwc) +{ + mwc->mws_coex_4g_quick_tdm = + cfg_get(psoc, CFG_MWS_COEX_4G_QUICK_FTDM); + mwc->mws_coex_5g_nr_pwr_limit = + cfg_get(psoc, CFG_MWS_COEX_5G_NR_PWR_LIMIT); + mwc->mws_coex_pcc_channel_avoid_delay = + cfg_get(psoc, CFG_MWS_COEX_PCC_CHANNEL_AVOID_DELAY); + mwc->mws_coex_scc_channel_avoid_delay = + cfg_get(psoc, CFG_MWS_COEX_SCC_CHANNEL_AVOID_DELAY); +} +#else +static void mlme_init_mwc_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_mwc *mwc) +{ +} +#endif + +#ifdef SAP_AVOID_ACS_FREQ_LIST +static void mlme_init_acs_avoid_freq_list(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ + qdf_size_t avoid_acs_freq_list_num = 0; + uint8_t i; + + qdf_uint16_array_parse(cfg_get(psoc, CFG_SAP_AVOID_ACS_FREQ_LIST), + reg->avoid_acs_freq_list, + CFG_VALID_CHANNEL_LIST_LEN, + &avoid_acs_freq_list_num); + reg->avoid_acs_freq_list_num = avoid_acs_freq_list_num; + + for (i = 0; i < avoid_acs_freq_list_num; i++) + mlme_legacy_debug("avoid_acs_freq %d", + reg->avoid_acs_freq_list[i]); +} +#else +static void mlme_init_acs_avoid_freq_list(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +static void mlme_init_coex_unsafe_chan_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ + reg->coex_unsafe_chan_nb_user_prefer = + cfg_get(psoc, CFG_COEX_UNSAFE_CHAN_NB_USER_PREFER); +} + +static void mlme_init_coex_unsafe_chan_reg_disable_cfg( + struct wlan_objmgr_psoc *psoc, struct wlan_mlme_reg *reg) +{ + reg->coex_unsafe_chan_reg_disable = + cfg_get(psoc, CFG_COEX_UNSAFE_CHAN_REG_DISABLE); +} +#else +static void mlme_init_coex_unsafe_chan_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ +} + +static void mlme_init_coex_unsafe_chan_reg_disable_cfg( + struct wlan_objmgr_psoc *psoc, struct wlan_mlme_reg *reg) +{ +} +#endif + +static void mlme_init_reg_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_reg *reg) +{ + reg->self_gen_frm_pwr = cfg_get(psoc, CFG_SELF_GEN_FRM_PWR); + reg->etsi_srd_chan_in_master_mode = + cfg_get(psoc, CFG_ETSI_SRD_CHAN_IN_MASTER_MODE); + reg->fcc_5dot9_ghz_chan_in_master_mode = + cfg_get(psoc, CFG_FCC_5DOT9_GHZ_CHAN_IN_MASTER_MODE); + reg->restart_beaconing_on_ch_avoid = + cfg_get(psoc, CFG_RESTART_BEACONING_ON_CH_AVOID); + reg->indoor_channel_support = cfg_get(psoc, CFG_INDOOR_CHANNEL_SUPPORT); + reg->enable_11d_in_world_mode = cfg_get(psoc, + CFG_ENABLE_11D_IN_WORLD_MODE); + reg->scan_11d_interval = cfg_get(psoc, CFG_SCAN_11D_INTERVAL); + reg->enable_pending_chan_list_req = cfg_get(psoc, + CFG_ENABLE_PENDING_CHAN_LIST_REQ); + reg->ignore_fw_reg_offload_ind = cfg_get( + psoc, + CFG_IGNORE_FW_REG_OFFLOAD_IND); + reg->retain_nol_across_regdmn_update = + cfg_get(psoc, CFG_RETAIN_NOL_ACROSS_REG_DOMAIN); + + reg->enable_nan_on_indoor_channels = + cfg_get(psoc, CFG_INDOOR_CHANNEL_SUPPORT_FOR_NAN); + + mlme_init_afc_cfg(psoc, reg); + mlme_init_acs_avoid_freq_list(psoc, reg); + mlme_init_coex_unsafe_chan_cfg(psoc, reg); + mlme_init_coex_unsafe_chan_reg_disable_cfg(psoc, reg); +} + +static void +mlme_init_dot11_mode_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_dot11_mode *dot11_mode) +{ + dot11_mode->dot11_mode = cfg_default(CFG_DOT11_MODE); + dot11_mode->vdev_type_dot11_mode = cfg_get(psoc, CFG_VDEV_DOT11_MODE); +} + +/** + * mlme_iot_parse_aggr_info - parse aggr related items in ini + * @psoc: PSOC pointer + * @iot: IOT related CFG items + * + * Return: None + */ +static void +mlme_iot_parse_aggr_info(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_iot *iot) +{ + char *aggr_info, *oui, *msdu, *mpdu, *aggr_info_temp; + uint32_t ampdu_sz, amsdu_sz, index = 0, oui_len, cfg_str_len; + struct wlan_iot_aggr *aggr_info_list; + const char *cfg_str; + int ret; + + cfg_str = cfg_get(psoc, CFG_TX_IOT_AGGR); + if (!cfg_str) + return; + + cfg_str_len = qdf_str_len(cfg_str); + if (!cfg_str_len) + return; + + aggr_info = qdf_mem_malloc(cfg_str_len + 1); + if (!aggr_info) + return; + + aggr_info_list = iot->aggr; + qdf_mem_copy(aggr_info, cfg_str, cfg_str_len); + mlme_legacy_debug("aggr_info=[%s]", aggr_info); + + aggr_info_temp = aggr_info; + while (aggr_info_temp) { + /* skip possible spaces before oui string */ + while (*aggr_info_temp == ' ') + aggr_info_temp++; + + oui = strsep(&aggr_info_temp, ","); + if (!oui) { + mlme_legacy_err("oui error"); + goto end; + } + + oui_len = qdf_str_len(oui) / 2; + if (oui_len > sizeof(aggr_info_list[index].oui)) { + mlme_legacy_err("size error"); + goto end; + } + + amsdu_sz = 0; + msdu = strsep(&aggr_info_temp, ","); + if (!msdu) { + mlme_legacy_err("msdu error"); + goto end; + } + + ret = kstrtou32(msdu, 10, &amsdu_sz); + if (ret || amsdu_sz > IOT_AGGR_MSDU_MAX_NUM) { + mlme_legacy_err("invalid msdu no. %s [%u]", + msdu, amsdu_sz); + goto end; + } + + ampdu_sz = 0; + mpdu = strsep(&aggr_info_temp, ","); + if (!mpdu) { + mlme_legacy_err("mpdu error"); + goto end; + } + + ret = kstrtou32(mpdu, 10, &du_sz); + if (ret || ampdu_sz > IOT_AGGR_MPDU_MAX_NUM) { + mlme_legacy_err("invalid mpdu no. %s [%u]", + mpdu, ampdu_sz); + goto end; + } + + mlme_legacy_debug("id %u oui[%s] len %u msdu %u mpdu %u", + index, oui, oui_len, amsdu_sz, ampdu_sz); + + ret = qdf_hex_str_to_binary(aggr_info_list[index].oui, + oui, oui_len); + if (ret) { + mlme_legacy_err("oui error: %d", ret); + goto end; + } + + aggr_info_list[index].amsdu_sz = amsdu_sz; + aggr_info_list[index].ampdu_sz = ampdu_sz; + aggr_info_list[index].oui_len = oui_len; + index++; + if (index >= IOT_AGGR_INFO_MAX_NUM) { + mlme_legacy_err("exceed max num, index = %d", index); + break; + } + } + iot->aggr_num = index; + +end: + mlme_legacy_debug("configured aggr num %d", iot->aggr_num); + qdf_mem_free(aggr_info); +} + +/** + * mlme_init_iot_cfg() - parse IOT related items in ini + * @psoc: PSOC pointer + * @iot: IOT related CFG items + * + * Return: None + */ +static void +mlme_init_iot_cfg(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_iot *iot) +{ + mlme_iot_parse_aggr_info(psoc, iot); +} + +/** + * mlme_init_dual_sta_config - Initialize dual sta configurations + * @gen: Generic CFG config items + * + * Return: None + */ +static void +mlme_init_dual_sta_config(struct wlan_mlme_generic *gen) +{ + gen->dual_sta_policy.primary_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + gen->dual_sta_policy.concurrent_sta_policy = + QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED; +} + +#ifdef WLAN_FEATURE_MCC_QUOTA +/** + * mlme_init_user_mcc_quota_config - Initialize mcc quota + * @gen: Generic CFG config items + * + * Return: None + */ +static void +mlme_init_user_mcc_quota_config(struct wlan_mlme_generic *gen) +{ + gen->user_mcc_quota.quota = 0; + gen->user_mcc_quota.op_mode = QDF_MAX_NO_OF_MODE; + gen->user_mcc_quota.vdev_id = WLAN_UMAC_VDEV_ID_MAX; +} +#else +static void +mlme_init_user_mcc_quota_config(struct wlan_mlme_generic *gen) +{ +} +#endif +QDF_STATUS mlme_cfg_on_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_cfg *mlme_cfg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + mlme_cfg = &mlme_obj->cfg; + mlme_init_generic_cfg(psoc, &mlme_cfg->gen); + mlme_init_timeout_cfg(psoc, &mlme_cfg->timeouts); + mlme_init_edca_params(psoc, &mlme_cfg->edca_params); + mlme_init_ht_cap_in_cfg(psoc, &mlme_cfg->ht_caps); + mlme_init_wmm_in_cfg(psoc, &mlme_cfg->wmm_params); + mlme_init_mbo_cfg(psoc, &mlme_cfg->mbo_cfg); + mlme_init_qos_cfg(psoc, &mlme_cfg->qos_mlme_params); + mlme_init_rates_in_cfg(psoc, &mlme_cfg->rates); + mlme_init_dfs_cfg(psoc, &mlme_cfg->dfs_cfg); + mlme_init_sap_protection_cfg(psoc, &mlme_cfg->sap_protection_cfg); + mlme_init_vht_cap_cfg(psoc, &mlme_cfg->vht_caps.vht_cap_info); + mlme_init_chainmask_cfg(psoc, &mlme_cfg->chainmask_cfg); + mlme_init_sap_cfg(psoc, &mlme_cfg->sap_cfg); + mlme_init_nss_chains(psoc, &mlme_cfg->nss_chains_ini_cfg); + mlme_init_twt_cfg(psoc, &mlme_cfg->twt_cfg); + mlme_init_he_cap_in_cfg(psoc, mlme_cfg); + mlme_init_eht_cap_in_cfg(psoc, mlme_cfg); + mlme_init_obss_ht40_cfg(psoc, &mlme_cfg->obss_ht40); + mlme_init_product_details_cfg(&mlme_cfg->product_details); + mlme_init_powersave_params(psoc, &mlme_cfg->ps_params); + mlme_init_sta_cfg(psoc, &mlme_cfg->sta); + mlme_init_stats_cfg(psoc, &mlme_cfg->stats); + mlme_init_lfr_cfg(psoc, &mlme_cfg->lfr); + mlme_init_feature_flag_in_cfg(psoc, &mlme_cfg->feature_flags); + mlme_init_roam_scoring_cfg(psoc, &mlme_cfg->roam_scoring); + mlme_init_dot11_mode_cfg(psoc, &mlme_cfg->dot11_mode); + mlme_init_threshold_cfg(psoc, &mlme_cfg->threshold); + mlme_init_acs_cfg(psoc, &mlme_cfg->acs); + mlme_init_power_cfg(psoc, &mlme_cfg->power); + mlme_init_oce_cfg(psoc, &mlme_cfg->oce); + mlme_init_wep_cfg(&mlme_cfg->wep_params); + mlme_init_wifi_pos_cfg(psoc, &mlme_cfg->wifi_pos_cfg); + mlme_init_wps_params_cfg(psoc, &mlme_cfg->wps_params); + mlme_init_fe_wlm_in_cfg(psoc, &mlme_cfg->wlm_config); + mlme_init_fe_rrm_in_cfg(psoc, &mlme_cfg->rrm_config); + mlme_init_mwc_cfg(psoc, &mlme_cfg->mwc); + mlme_init_reg_cfg(psoc, &mlme_cfg->reg); + mlme_init_btm_cfg(psoc, &mlme_cfg->btm); + mlme_init_roam_score_config(psoc, mlme_cfg); + mlme_init_ratemask_cfg(psoc, &mlme_cfg->ratemask_cfg); + mlme_init_iot_cfg(psoc, &mlme_cfg->iot); + mlme_init_dual_sta_config(&mlme_cfg->gen); + mlme_init_user_mcc_quota_config(&mlme_cfg->gen); + + return status; +} + +struct sae_auth_retry *mlme_get_sae_auth_retry(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + return &mlme_priv->sae_retry; +} + +void mlme_free_sae_auth_retry(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->sae_retry.sae_auth_max_retry = 0; + if (mlme_priv->sae_retry.sae_auth.ptr) + qdf_mem_free(mlme_priv->sae_retry.sae_auth.ptr); + mlme_priv->sae_retry.sae_auth.ptr = NULL; + mlme_priv->sae_retry.sae_auth.len = 0; +} + +void mlme_set_self_disconnect_ies(struct wlan_objmgr_vdev *vdev, + struct element_info *ie) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!ie || !ie->len || !ie->ptr) { + mlme_legacy_debug("disocnnect IEs are NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + if (mlme_priv->disconnect_info.self_discon_ies.ptr) { + qdf_mem_free(mlme_priv->disconnect_info.self_discon_ies.ptr); + mlme_priv->disconnect_info.self_discon_ies.len = 0; + } + + mlme_priv->disconnect_info.self_discon_ies.ptr = + qdf_mem_malloc(ie->len); + if (!mlme_priv->disconnect_info.self_discon_ies.ptr) + return; + + qdf_mem_copy(mlme_priv->disconnect_info.self_discon_ies.ptr, + ie->ptr, ie->len); + mlme_priv->disconnect_info.self_discon_ies.len = ie->len; + + mlme_legacy_debug("Self disconnect IEs"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG, + mlme_priv->disconnect_info.self_discon_ies.ptr, + mlme_priv->disconnect_info.self_discon_ies.len); +} + +void mlme_free_self_disconnect_ies(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + if (mlme_priv->disconnect_info.self_discon_ies.ptr) { + qdf_mem_free(mlme_priv->disconnect_info.self_discon_ies.ptr); + mlme_priv->disconnect_info.self_discon_ies.ptr = NULL; + mlme_priv->disconnect_info.self_discon_ies.len = 0; + } +} + +struct element_info *mlme_get_self_disconnect_ies(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + return &mlme_priv->disconnect_info.self_discon_ies; +} + +void mlme_set_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev, + struct element_info *ie) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!ie || !ie->len || !ie->ptr) { + mlme_legacy_debug("disocnnect IEs are NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + if (mlme_priv->disconnect_info.peer_discon_ies.ptr) { + qdf_mem_free(mlme_priv->disconnect_info.peer_discon_ies.ptr); + mlme_priv->disconnect_info.peer_discon_ies.len = 0; + } + + mlme_priv->disconnect_info.peer_discon_ies.ptr = + qdf_mem_malloc(ie->len); + if (!mlme_priv->disconnect_info.peer_discon_ies.ptr) + return; + + qdf_mem_copy(mlme_priv->disconnect_info.peer_discon_ies.ptr, + ie->ptr, ie->len); + mlme_priv->disconnect_info.peer_discon_ies.len = ie->len; + + mlme_legacy_debug("peer disconnect IEs"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG, + mlme_priv->disconnect_info.peer_discon_ies.ptr, + mlme_priv->disconnect_info.peer_discon_ies.len); +} + +void mlme_free_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + if (mlme_priv->disconnect_info.peer_discon_ies.ptr) { + qdf_mem_free(mlme_priv->disconnect_info.peer_discon_ies.ptr); + mlme_priv->disconnect_info.peer_discon_ies.ptr = NULL; + mlme_priv->disconnect_info.peer_discon_ies.len = 0; + } +} + +struct element_info *mlme_get_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + return &mlme_priv->disconnect_info.peer_discon_ies; +} + +void mlme_free_peer_assoc_rsp_ie(struct peer_mlme_priv_obj *peer_priv) +{ + if (!peer_priv) { + mlme_legacy_debug("peer priv is NULL"); + return; + } + + if (peer_priv->assoc_rsp.ptr) { + qdf_mem_free(peer_priv->assoc_rsp.ptr); + peer_priv->assoc_rsp.ptr = NULL; + peer_priv->assoc_rsp.len = 0; + } +} + +void mlme_set_peer_assoc_rsp_ie(struct wlan_objmgr_psoc *psoc, + uint8_t *peer_addr, struct element_info *ie) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + + if (!ie || !ie->len || !ie->ptr || !peer_addr) { + mlme_legacy_debug("Assoc IE is NULL"); + return; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_addr, WLAN_LEGACY_MAC_ID); + if (!peer) + return; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + + if (!peer_priv) + goto end; + + /* Free existing assoc_rsp */ + mlme_free_peer_assoc_rsp_ie(peer_priv); + + peer_priv->assoc_rsp.ptr = qdf_mem_malloc(ie->len); + if (!peer_priv->assoc_rsp.ptr) + goto end; + + qdf_mem_copy(peer_priv->assoc_rsp.ptr, ie->ptr, ie->len); + peer_priv->assoc_rsp.len = ie->len; +end: + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +void mlme_set_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev, bool flag) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->follow_ap_edca = flag; +} + +bool mlme_get_follow_ap_edca_flag(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->follow_ap_edca; +} + +void mlme_set_best_6g_power_type(struct wlan_objmgr_vdev *vdev, + enum reg_6g_ap_type best_6g_power_type) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->best_6g_power_type = best_6g_power_type; +} + +enum reg_6g_ap_type mlme_get_best_6g_power_type(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return REG_VERY_LOW_POWER_AP; + } + + return mlme_priv->best_6g_power_type; +} + +void mlme_set_reconn_after_assoc_timeout_flag(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool flag) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + if (!psoc) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return; + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return; + } + + mlme_priv->reconn_after_assoc_timeout = flag; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +bool mlme_get_reconn_after_assoc_timeout_flag(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + bool reconn_after_assoc_timeout; + + if (!psoc) + return false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return false; + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return false; + } + + reconn_after_assoc_timeout = mlme_priv->reconn_after_assoc_timeout; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return reconn_after_assoc_timeout; +} + +void mlme_set_peer_pmf_status(struct wlan_objmgr_peer *peer, + bool is_pmf_enabled) +{ + struct peer_mlme_priv_obj *peer_priv; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_legacy_err(" peer mlme component object is NULL"); + return; + } + peer_priv->is_pmf_enabled = is_pmf_enabled; +} + +bool mlme_get_peer_pmf_status(struct wlan_objmgr_peer *peer) +{ + struct peer_mlme_priv_obj *peer_priv; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_legacy_err("peer mlme component object is NULL"); + return false; + } + + return peer_priv->is_pmf_enabled; +} + +enum QDF_OPMODE wlan_get_opmode_from_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode = QDF_MAX_NO_OF_MODE; + + if (!pdev) + return opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return opmode; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return opmode; +} + +QDF_STATUS wlan_mlme_get_bssid_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *bss_peer_mac) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!pdev) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = wlan_vdev_get_bss_peer_mac(vdev, bss_peer_mac); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return status; +} + +qdf_freq_t wlan_get_operation_chan_freq(struct wlan_objmgr_vdev *vdev) +{ + qdf_freq_t chan_freq = 0; + struct wlan_channel *chan; + + if (!vdev) + return chan_freq; + + chan = wlan_vdev_get_active_channel(vdev); + if (chan) + chan_freq = chan->ch_freq; + + return chan_freq; +} + +qdf_freq_t wlan_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + qdf_freq_t chan_freq = 0; + struct wlan_objmgr_vdev *vdev; + + if (!pdev) + return chan_freq; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return chan_freq; + chan_freq = wlan_get_operation_chan_freq(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return chan_freq; +} + +void wlan_vdev_set_dot11mode(struct wlan_mlme_cfg *mac_mlme_cfg, + enum QDF_OPMODE device_mode, + struct vdev_mlme_obj *vdev_mlme) +{ + uint8_t dot11_mode_indx; + uint8_t *mld_addr; + enum mlme_vdev_dot11_mode vdev_dot11_mode; + uint32_t mac_dot11_mode = + mac_mlme_cfg->dot11_mode.vdev_type_dot11_mode; + + switch (device_mode) { + default: + case QDF_STA_MODE: + dot11_mode_indx = STA_DOT11_MODE_INDX; + break; + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + dot11_mode_indx = P2P_DEV_DOT11_MODE_INDX; + break; + case QDF_TDLS_MODE: + dot11_mode_indx = TDLS_DOT11_MODE_INDX; + break; + case QDF_NAN_DISC_MODE: + dot11_mode_indx = NAN_DISC_DOT11_MODE_INDX; + break; + case QDF_NDI_MODE: + dot11_mode_indx = NDI_DOT11_MODE_INDX; + break; + case QDF_OCB_MODE: + dot11_mode_indx = OCB_DOT11_MODE_INDX; + break; + } + + vdev_dot11_mode = QDF_GET_BITS(mac_dot11_mode, dot11_mode_indx, 4); + if ((device_mode != QDF_NAN_DISC_MODE && device_mode != QDF_NDI_MODE) && + (vdev_dot11_mode == MLME_VDEV_DOT11_MODE_AUTO || + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11BE)) { + mld_addr = wlan_vdev_mlme_get_mldaddr(vdev_mlme->vdev); + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)mld_addr)) { + vdev_dot11_mode = MLME_VDEV_DOT11_MODE_11AX; + vdev_mlme->proto.vdev_dot11_mode = vdev_dot11_mode; + } + } + mlme_debug("vdev%d: dot11_mode %d", wlan_vdev_get_id(vdev_mlme->vdev), + vdev_dot11_mode); +} + +bool wlan_is_open_wep_cipher(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + int32_t ucast_cipher; + bool is_open_wep = false; + + if (!pdev) + return is_open_wep; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return is_open_wep; + ucast_cipher = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + if (!ucast_cipher || + ((QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_NONE) == + ucast_cipher)) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104)) + is_open_wep = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return is_open_wep; +} + +bool wlan_vdev_is_open_mode(struct wlan_objmgr_vdev *vdev) +{ + int32_t ucast_cipher; + + ucast_cipher = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + if (!ucast_cipher || + ((QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_NONE) == + ucast_cipher))) + return true; + + return false; +} + +bool wlan_vdev_id_is_open_cipher(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_open = false; + + if (!pdev) + return is_open; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return is_open; + is_open = wlan_vdev_is_open_mode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return is_open; +} + +bool wlan_vdev_id_is_11n_allowed(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_11n_allowed = true; + int32_t ucast_cipher; + + if (!pdev) + return is_11n_allowed; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return is_11n_allowed; + ucast_cipher = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + if (ucast_cipher == -1) + goto err; + if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_TKIP) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104)) { + QDF_CLEAR_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_TKIP); + QDF_CLEAR_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP); + QDF_CLEAR_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40); + QDF_CLEAR_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104); + if (!ucast_cipher) + is_11n_allowed = false; + } +err: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return is_11n_allowed; +} + + +bool wlan_is_vdev_id_up(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_up = false; + + if (!pdev) + return is_up; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (vdev) { + is_up = QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(vdev)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + } + + return is_up; +} + + +QDF_STATUS +wlan_get_op_chan_freq_info_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, qdf_freq_t *op_freq, + qdf_freq_t *freq_seg_0, + enum phy_ch_width *ch_width) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_channel *chan; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + *op_freq = 0; + *freq_seg_0 = 0; + *ch_width = 0; + + if (!pdev) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + goto rel_ref; + if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS) + goto rel_ref; + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) + goto rel_ref; + + /* If operating mode is STA / P2P-CLI then get the channel width + * from phymode. This is due the reason where actual operating + * channel width is configured as part of WMI_PEER_ASSOC_CMDID + * which could be downgraded while the peer associated. + * If there is a failure or operating mode is not STA / P2P-CLI + * then get channel width from wlan_channel. + */ + status = wlan_mlme_get_sta_ch_width(vdev, ch_width); + if (QDF_IS_STATUS_ERROR(status)) + *ch_width = chan->ch_width; + + *op_freq = chan->ch_freq; + *freq_seg_0 = chan->ch_cfreq1; + status = QDF_STATUS_SUCCESS; + +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return status; +} + +QDF_STATUS wlan_strip_ie(uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, enum size_of_len_field size_of_len_field, + uint8_t *oui, uint8_t oui_length, + uint8_t *extracted_ie, uint32_t eid_max_len) +{ + uint8_t *tmp_buf = NULL; + uint16_t tmp_len = 0; + int left = *addn_ielen; + uint8_t *ptr = addn_ie; + uint8_t elem_id; + uint16_t elem_len, ie_len, extracted_ie_len = 0; + + if (!addn_ie) { + mlme_debug("NULL addn_ie pointer"); + return QDF_STATUS_E_INVAL; + } + if (!left) + return QDF_STATUS_E_INVAL; + + tmp_buf = qdf_mem_malloc(left); + if (!tmp_buf) + return QDF_STATUS_E_NOMEM; + + if (extracted_ie) + qdf_mem_zero(extracted_ie, eid_max_len + size_of_len_field + 1); + + while (left >= 2) { + elem_id = ptr[0]; + left -= 1; + if (size_of_len_field == TWO_BYTE) { + elem_len = *((uint16_t *)&ptr[1]); + left -= 2; + } else { + elem_len = ptr[1]; + left -= 1; + } + if (elem_len > left) { + mlme_err("Invalid IEs eid: %d elem_len: %d left: %d", + elem_id, elem_len, left); + qdf_mem_free(tmp_buf); + return QDF_STATUS_E_FAILURE; + } + + if (eid != elem_id || + (oui && qdf_mem_cmp(oui, + &ptr[size_of_len_field + 1], + oui_length))) { + qdf_mem_copy(tmp_buf + tmp_len, &ptr[0], + elem_len + size_of_len_field + 1); + tmp_len += (elem_len + size_of_len_field + 1); + } else { + /* + * eid matched and if provided OUI also matched + * take oui IE and store in provided buffer. + */ + if (extracted_ie) { + ie_len = elem_len + size_of_len_field + 1; + if (ie_len <= eid_max_len - extracted_ie_len) { + qdf_mem_copy( + extracted_ie + extracted_ie_len, + &ptr[0], ie_len); + extracted_ie_len += ie_len; + } + } + } + left -= elem_len; + ptr += (elem_len + size_of_len_field + 1); + } + qdf_mem_copy(addn_ie, tmp_buf, tmp_len); + + *addn_ielen = tmp_len; + qdf_mem_free(tmp_buf); + + return QDF_STATUS_SUCCESS; +} + +bool wlan_is_channel_present_in_list(qdf_freq_t *freq_lst, + uint32_t num_chan, qdf_freq_t chan_freq) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!freq_lst || (num_chan == 0)) + return false; + + /* Look for the channel in the list */ + for (i = 0; (i < num_chan) && (i < CFG_VALID_CHANNEL_LIST_LEN); i++) { + if (freq_lst[i] == chan_freq) + return true; + } + + return false; +} + +bool wlan_roam_is_channel_valid(struct wlan_mlme_reg *reg, qdf_freq_t chan_freq) +{ + bool valid = false; + uint32_t i; + uint32_t len = reg->valid_channel_list_num; + + for (i = 0; (i < len); i++) { + if (wlan_reg_is_dsrc_freq( + reg->valid_channel_freq_list[i])) + continue; + + if (chan_freq == reg->valid_channel_freq_list[i]) { + valid = true; + break; + } + } + + return valid; +} + +int8_t wlan_get_cfg_max_tx_power(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint32_t ch_freq) +{ + uint32_t cfg_length = 0; + int8_t max_tx_pwr = 0; + struct pwr_channel_info *country_info = NULL; + uint8_t count = 0; + uint8_t maxChannels; + int32_t rem_length = 0; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return max_tx_pwr; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq)) { + cfg_length = mlme_obj->cfg.power.max_tx_power_5.len; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) { + cfg_length = mlme_obj->cfg.power.max_tx_power_24.len; + + } else if (wlan_reg_is_6ghz_chan_freq(ch_freq)) { + return wlan_reg_get_channel_reg_power_for_freq(pdev, + ch_freq); + } else { + return max_tx_pwr; + } + + if (!cfg_length) + goto error; + + country_info = qdf_mem_malloc(cfg_length); + if (!country_info) + goto error; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq)) { + if (cfg_length > CFG_MAX_TX_POWER_5_LEN) + goto error; + qdf_mem_copy(country_info, + mlme_obj->cfg.power.max_tx_power_5.data, + cfg_length); + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) { + if (cfg_length > CFG_MAX_TX_POWER_2_4_LEN) + goto error; + qdf_mem_copy(country_info, + mlme_obj->cfg.power.max_tx_power_24.data, + cfg_length); + } + + /* Identify the channel and maxtxpower */ + rem_length = cfg_length; + while (rem_length >= (sizeof(struct pwr_channel_info))) { + maxChannels = country_info[count].num_chan; + max_tx_pwr = country_info[count].max_tx_pwr; + count++; + rem_length -= (sizeof(struct pwr_channel_info)); + + if (ch_freq >= country_info[count].first_freq && + ch_freq < (country_info[count].first_freq + maxChannels)) { + break; + } + } + +error: + if (country_info) + qdf_mem_free(country_info); + + return max_tx_pwr; +} + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +static +const char *mlme_roam_state_to_string(enum roam_offload_state state) +{ + switch (state) { + case WLAN_ROAM_INIT: + return "ROAM_INIT"; + case WLAN_ROAM_DEINIT: + return "ROAM_DEINIT"; + case WLAN_ROAM_RSO_ENABLED: + return "ROAM_RSO_ENABLED"; + case WLAN_ROAM_RSO_STOPPED: + return "ROAM_RSO_STOPPED"; + case WLAN_ROAMING_IN_PROG: + return "ROAMING_IN_PROG"; + case WLAN_ROAM_SYNCH_IN_PROG: + return "ROAM_SYNCH_IN_PROG"; + case WLAN_MLO_ROAM_SYNCH_IN_PROG: + return "MLO_ROAM_SYNCH_IN_PROG"; + default: + return ""; + } +} + +static void +mlme_print_roaming_state(uint8_t vdev_id, enum roam_offload_state cur_state, + enum roam_offload_state new_state) +{ + mlme_nofl_debug("CM_RSO: vdev%d: [%s(%d)] --> [%s(%d)]", + vdev_id, mlme_roam_state_to_string(cur_state), + cur_state, + mlme_roam_state_to_string(new_state), new_state); + + /* TODO: Try to print the state change requestor also */ +} + +bool +mlme_get_supplicant_disabled_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + bool value; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return 0; + } + + value = mlme_priv->mlme_roam.roam_cfg.supplicant_disabled_roaming; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return value; +} + +void mlme_set_supplicant_disabled_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool val) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return; + } + + mlme_priv->mlme_roam.roam_cfg.supplicant_disabled_roaming = val; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +uint32_t +mlme_get_roam_trigger_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + uint32_t roam_bitmap; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return 0; + } + + roam_bitmap = mlme_priv->mlme_roam.roam_cfg.roam_trigger_bitmap; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return roam_bitmap; +} + +void mlme_set_roam_trigger_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t val) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return; + } + + mlme_priv->mlme_roam.roam_cfg.roam_trigger_bitmap = val; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +uint8_t +mlme_get_operations_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + uint8_t bitmap; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return 0xFF; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return 0xFF; + } + + bitmap = mlme_priv->mlme_roam.roam_sm.mlme_operations_bitmap; + mlme_legacy_debug("vdev[%d] bitmap[0x%x]", vdev_id, + mlme_priv->mlme_roam.roam_sm.mlme_operations_bitmap); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return bitmap; +} + +void +mlme_set_operations_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum wlan_cm_rso_control_requestor reqs, bool clear) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return; + } + + if (clear) + mlme_priv->mlme_roam.roam_sm.mlme_operations_bitmap &= ~reqs; + else + mlme_priv->mlme_roam.roam_sm.mlme_operations_bitmap |= reqs; + + mlme_legacy_debug("vdev[%d] bitmap[0x%x], reqs: %d, clear: %d", vdev_id, + mlme_priv->mlme_roam.roam_sm.mlme_operations_bitmap, + reqs, clear); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +void +mlme_clear_operations_bitmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev object is NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return; + } + + mlme_priv->mlme_roam.roam_sm.mlme_operations_bitmap = 0; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +QDF_STATUS mlme_get_cfg_wlm_level(struct wlan_objmgr_psoc *psoc, + uint8_t *level) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *level = mlme_obj->cfg.wlm_config.latency_level; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_get_cfg_wlm_reset(struct wlan_objmgr_psoc *psoc, + bool *reset) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *reset = mlme_obj->cfg.wlm_config.latency_reset; + + return QDF_STATUS_SUCCESS; +} + +enum roam_offload_state +mlme_get_roam_state(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + enum roam_offload_state roam_state; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) + return WLAN_ROAM_DEINIT; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return WLAN_ROAM_DEINIT; + } + + roam_state = mlme_priv->mlme_roam.roam_sm.state; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return roam_state; +} + +void mlme_set_roam_state(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_offload_state new_state) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", vdev_id); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev%d: vdev legacy private object is NULL", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return; + } + + mlme_print_roaming_state(vdev_id, mlme_priv->mlme_roam.roam_sm.state, + new_state); + mlme_priv->mlme_roam.roam_sm.state = new_state; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +QDF_STATUS +mlme_store_fw_scan_channels(struct wlan_objmgr_psoc *psoc, + tSirUpdateChanList *chan_list) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_lfr_cfg *lfr; + uint16_t i; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + lfr = &mlme_obj->cfg.lfr; + qdf_mem_zero(&lfr->saved_freq_list, sizeof(lfr->saved_freq_list)); + lfr->saved_freq_list.num_channels = chan_list->numChan; + for (i = 0; i < chan_list->numChan; i++) + lfr->saved_freq_list.freq[i] = chan_list->chanParam[i].freq; + + mlme_legacy_debug("ROAM: save %d channels", + chan_list->numChan); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_get_fw_scan_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *freq_list, + uint8_t *saved_num_chan) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_lfr_cfg *lfr; + uint16_t i; + + if (!freq_list) { + mlme_legacy_err("ROAM: Freq list is NULL"); + *saved_num_chan = 0; + return QDF_STATUS_E_FAILURE; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + *saved_num_chan = 0; + return QDF_STATUS_E_FAILURE; + } + + lfr = &mlme_obj->cfg.lfr; + *saved_num_chan = lfr->saved_freq_list.num_channels; + + for (i = 0; i < lfr->saved_freq_list.num_channels; i++) + freq_list[i] = lfr->saved_freq_list.freq[i]; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wlan_mlme_get_mac_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *self_mac) +{ + struct wlan_objmgr_vdev *vdev; + + if (!pdev) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + qdf_mem_copy(self_mac->bytes, + wlan_vdev_mlme_get_macaddr(vdev), QDF_MAC_ADDR_SIZE); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return QDF_STATUS_SUCCESS; +} + +qdf_freq_t +wlan_get_sap_user_config_freq(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + enum QDF_OPMODE opmode = QDF_MAX_NO_OF_MODE; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_SAP_MODE && opmode != QDF_P2P_GO_MODE) { + mlme_debug("Cannot get user config freq for mode %d", opmode); + return 0; + } + + return mlme_priv->mlme_ap.user_config_sap_ch_freq; +} + +QDF_STATUS +wlan_set_sap_user_config_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + struct mlme_legacy_priv *mlme_priv; + enum QDF_OPMODE opmode = QDF_MAX_NO_OF_MODE; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_SAP_MODE && opmode != QDF_P2P_GO_MODE) { + mlme_debug("Cannot set user config freq for mode %d", opmode); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->mlme_ap.user_config_sap_ch_freq = freq; + return QDF_STATUS_SUCCESS; +} + +#ifdef CONFIG_BAND_6GHZ +bool +wlan_get_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + enum QDF_OPMODE opmode; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_SAP_MODE && opmode != QDF_P2P_GO_MODE) { + mlme_debug("Invalid opmode %d", opmode); + return false; + } + + return mlme_priv->mlme_ap.update_required_scc_sta_power; +} + +QDF_STATUS +wlan_set_tpc_update_required_for_sta(struct wlan_objmgr_vdev *vdev, bool value) +{ + struct mlme_legacy_priv *mlme_priv; + enum QDF_OPMODE opmode; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_SAP_MODE && opmode != QDF_P2P_GO_MODE) { + mlme_debug("Invalid mode %d", opmode); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->mlme_ap.update_required_scc_sta_power = value; + mlme_debug("Set change scc power as %d", value); + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wlan_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *tx_chains) +{ + bool dynamic_nss_chains_support; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + QDF_STATUS status; + struct vdev_mlme_obj *vdev_mlme; + + status = wlan_mlme_cfg_get_dynamic_nss_chains_support + (psoc, &dynamic_nss_chains_support); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to get dynamic_nss_chains_support"); + return QDF_STATUS_E_INVAL; + } + + vdev_mlme = + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + QDF_ASSERT(0); + return false; + } + + if (dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + mlme_err("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + + operating_band = ucfg_cm_get_connected_band(vdev); + switch (operating_band) { + case BAND_2G: + *tx_chains = + dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *tx_chains = + dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]; + break; + default: + mlme_err("Band %d Not 2G or 5G", operating_band); + return QDF_STATUS_E_INVAL; + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *tx_nss) +{ + uint8_t proto_generic_nss; + bool dynamic_nss_chains_support; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + QDF_STATUS status; + + status = wlan_mlme_cfg_get_dynamic_nss_chains_support + (psoc, &dynamic_nss_chains_support); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to get dynamic_nss_chains_support"); + return QDF_STATUS_E_INVAL; + } + + proto_generic_nss = wlan_vdev_mlme_get_nss(vdev); + if (dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + mlme_err("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + + operating_band = ucfg_cm_get_connected_band(vdev); + switch (operating_band) { + case BAND_2G: + *tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ]; + break; + default: + mlme_err("Band %d Not 2G or 5G", operating_band); + return QDF_STATUS_E_INVAL; + } + + if (*tx_nss > proto_generic_nss) + *tx_nss = proto_generic_nss; + } else { + *tx_nss = proto_generic_nss; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *rx_chains) +{ + bool dynamic_nss_chains_support; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + QDF_STATUS status; + struct vdev_mlme_obj *vdev_mlme; + + status = wlan_mlme_cfg_get_dynamic_nss_chains_support + (psoc, &dynamic_nss_chains_support); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to get dynamic_nss_chains_support"); + return QDF_STATUS_E_INVAL; + } + vdev_mlme = + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (!vdev_mlme) { + QDF_ASSERT(0); + return false; + } + + if (dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + mlme_err("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + + operating_band = ucfg_cm_get_connected_band(vdev); + switch (operating_band) { + case BAND_2G: + *rx_chains = + dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *rx_chains = + dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ]; + break; + default: + mlme_err("Band %d Not 2G or 5G", operating_band); + return QDF_STATUS_E_INVAL; + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *rx_nss) +{ + uint8_t proto_generic_nss; + bool dynamic_nss_chains_support; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + QDF_STATUS status; + + status = wlan_mlme_cfg_get_dynamic_nss_chains_support + (psoc, &dynamic_nss_chains_support); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to get dynamic_nss_chains_support"); + return QDF_STATUS_E_INVAL; + } + + proto_generic_nss = wlan_vdev_mlme_get_nss(vdev); + if (dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + mlme_err("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + + operating_band = ucfg_cm_get_connected_band(vdev); + switch (operating_band) { + case BAND_2G: + *rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ]; + break; + default: + mlme_err("Band %d Not 2G or 5G", operating_band); + return QDF_STATUS_E_INVAL; + } + + if (*rx_nss > proto_generic_nss) + *rx_nss = proto_generic_nss; + } else { + *rx_nss = proto_generic_nss; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +wmi_extract_peer_oper_mode_event(wmi_unified_t wmi_handle, + uint8_t *event, + uint32_t len, + struct peer_oper_mode_event *data) +{ + if (wmi_handle->ops->extract_peer_oper_mode_event) + return wmi_handle->ops->extract_peer_oper_mode_event(wmi_handle, + event, + len, data); + return QDF_STATUS_E_FAILURE; +} + +int mlme_peer_oper_mode_change_event_handler(ol_scn_t scn, + uint8_t *event, + uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct peer_oper_mode_event data = {0}; + struct wlan_mlme_rx_ops *mlme_rx_ops; + QDF_STATUS qdf_status; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + mlme_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_peer_oper_mode_event(wmi_handle, event, + len, &data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + mlme_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + + mlme_rx_ops = mlme_get_rx_ops(psoc); + if (!mlme_rx_ops || !mlme_rx_ops->peer_oper_mode_eventid) { + mlme_err("No valid roam rx ops"); + return -EINVAL; + } + + qdf_status = mlme_rx_ops->peer_oper_mode_eventid(psoc, &data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + mlme_err("peer_oper_mode_change_event Failed"); + return -EINVAL; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_register_common_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + mlme_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Register for peer operating mode change devent */ + ret = wmi_unified_register_event_handler(handle, + wmi_peer_oper_mode_change_event_id, + mlme_peer_oper_mode_change_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + mlme_err("wmi event(%u) registration failed, ret: %d", + wmi_peer_oper_mode_change_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +wlan_mlme_send_csa_event_status_ind_cmd(struct wlan_objmgr_vdev *vdev, + uint8_t csa_status) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_tx_ops *tx_ops; + mlme_psoc_ext_t *mlme_priv; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("vdev_id %d psoc object is NULL", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + tx_ops = &mlme_priv->mlme_tx_ops; + + if (!tx_ops || !tx_ops->send_csa_event_status_ind) { + mlme_err("CSA no op defined"); + return QDF_STATUS_E_FAILURE; + } + + return tx_ops->send_csa_event_status_ind(vdev, csa_status); +} + +uint8_t +wlan_mlme_get_sap_psd_for_20mhz(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + enum QDF_OPMODE opmode = QDF_MAX_NO_OF_MODE; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_SAP_MODE) { + mlme_debug("Invalid opmode %d", opmode); + return 0; + } + + return mlme_priv->mlme_ap.psd_20mhz; +} + +QDF_STATUS +wlan_mlme_set_sap_psd_for_20mhz(struct wlan_objmgr_vdev *vdev, + uint8_t psd_power) +{ + struct mlme_legacy_priv *mlme_priv; + enum QDF_OPMODE opmode = QDF_MAX_NO_OF_MODE; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_SAP_MODE) { + mlme_debug("Invalid opmode %d", opmode); + return QDF_STATUS_E_INVAL; + } + + mlme_priv->mlme_ap.psd_20mhz = psd_power; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_peer_find_mld_peer_n_get_mac_info() - This API will find MLD peer from + * peer list. + * @psoc: Pointer to psoc object + * @obj: Pointer to peer object + * @args: Pointer to void * argument + * + * Return: void + */ +static void +wlan_peer_find_mld_peer_n_get_mac_info(struct wlan_objmgr_psoc *psoc, + void *obj, void *args) +{ + struct wlan_objmgr_peer *peer = (struct wlan_objmgr_peer *)obj; + struct peer_mac_addresses *peer_mac_info = + (struct peer_mac_addresses *)args; + uint8_t *mld_mac, *peer_mac, *given_mac; + + mld_mac = wlan_peer_mlme_get_mldaddr(peer); + peer_mac = wlan_peer_get_macaddr(peer); + given_mac = peer_mac_info->mac.bytes; + + if (!mld_mac || WLAN_ADDR_EQ(mld_mac, given_mac) != QDF_STATUS_SUCCESS) + return; + qdf_copy_macaddr(&peer_mac_info->peer_mac, + (struct qdf_mac_addr *)peer_mac); + qdf_copy_macaddr(&peer_mac_info->peer_mld, + (struct qdf_mac_addr *)mld_mac); +} + +QDF_STATUS wlan_find_peer_and_get_mac_and_mld_addr( + struct wlan_objmgr_psoc *psoc, + struct peer_mac_addresses *peer_mac_info) +{ + struct wlan_objmgr_peer *peer; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac_info->mac.bytes, + WLAN_LEGACY_MAC_ID); + if (peer) { + qdf_copy_macaddr( + &peer_mac_info->peer_mac, + (struct qdf_mac_addr *)wlan_peer_get_macaddr(peer)); + if (wlan_peer_mlme_get_mldaddr(peer)) + qdf_copy_macaddr( + &peer_mac_info->peer_mld, + (struct qdf_mac_addr *) + wlan_peer_mlme_get_mldaddr(peer)); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return status; + } + + /* if not found with mac address try finding using MLD address */ + wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP, + wlan_peer_find_mld_peer_n_get_mac_info, + peer_mac_info, 0, WLAN_LEGACY_MAC_ID); + if (qdf_is_macaddr_zero(&peer_mac_info->peer_mac)) { + mlme_err("peer is null for mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac_info->mac.bytes)); + return QDF_STATUS_E_EXISTS; + } + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_twt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_twt_api.c new file mode 100644 index 0000000000..b18486cc6e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_twt_api.c @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: define internal APIs related to the mlme TWT functionality + */ + +#include "cfg_mlme_twt.h" +#include "cfg_ucfg_api.h" +#include "wlan_mlme_main.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_vdev_mlme_api.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_twt_api.h" + +bool mlme_is_max_twt_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + uint8_t num_twt_sessions = 0, max_twt_sessions; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return true; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err("peer mlme component object is NULL"); + return true; + } + + max_twt_sessions = peer_priv->twt_ctx.num_twt_sessions; + for (i = 0; i < max_twt_sessions; i++) { + uint8_t existing_session_dialog_id = + peer_priv->twt_ctx.session_info[i].dialog_id; + + if (existing_session_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + existing_session_dialog_id != dialog_id) + num_twt_sessions++; + } + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + mlme_legacy_debug("num_twt_sessions:%d max_twt_sessions:%d", + num_twt_sessions, max_twt_sessions); + return num_twt_sessions == max_twt_sessions; +} + +bool mlme_is_twt_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t existing_session_dialog_id; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err("peer mlme component object is NULL"); + return false; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + bool setup_done = peer_priv->twt_ctx.session_info[i].setup_done; + existing_session_dialog_id = + peer_priv->twt_ctx.session_info[i].dialog_id; + if (existing_session_dialog_id == dialog_id && + existing_session_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + !setup_done) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + return true; + } + } + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return false; +} + +void mlme_add_twt_session(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err("peer mlme component object is NULL"); + return; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == + TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->twt_ctx.session_info[i].dialog_id = + dialog_id; + break; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); +} + +void mlme_set_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, bool is_set) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err(" peer mlme component object is NULL"); + return; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id) { + peer_priv->twt_ctx.session_info[i].setup_done = is_set; + mlme_legacy_debug("setup done:%d dialog:%d", is_set, + dialog_id); + break; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); +} + +QDF_STATUS mlme_init_twt_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_debug("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_debug("peer mlme component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer_priv->twt_ctx.num_twt_sessions = WLAN_MAX_TWT_SESSIONS_PER_PEER; + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->twt_ctx.session_info[i].setup_done = false; + peer_priv->twt_ctx.session_info[i].dialog_id = + TWT_ALL_SESSIONS_DIALOG_ID; + mlme_set_twt_command_in_progress( + psoc, peer_mac, + peer_priv->twt_ctx.session_info[i].dialog_id, + WLAN_TWT_NONE); + } + } + + mlme_legacy_debug("init done"); + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +mlme_init_all_peers_twt_context(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct peer_mlme_priv_obj *peer_priv; + + if (!psoc) { + mlme_legacy_err("psoc is NULL, dialog_id: %d", dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_legacy_err("vdev is NULL, vdev_id: %d dialog_id: %d", + vdev_id, dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_err("Peer list for vdev obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_MLME_NB_ID); + while (peer) { + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (peer_priv) { + uint8_t i = 0; + uint8_t num_twt_sessions = + WLAN_MAX_TWT_SESSIONS_PER_PEER; + + peer_priv->twt_ctx.num_twt_sessions = + num_twt_sessions; + for (i = 0; i < num_twt_sessions; i++) { + uint8_t existing_dialog_id = + peer_priv->twt_ctx.session_info[i].dialog_id; + + if (existing_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->twt_ctx.session_info[i].setup_done = false; + peer_priv->twt_ctx.session_info[i].dialog_id = + TWT_ALL_SESSIONS_DIALOG_ID; + } + } + } + + peer_next = + wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_MLME_NB_ID); + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + peer = peer_next; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_debug("init done"); + return QDF_STATUS_SUCCESS; +} + + +bool mlme_is_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + bool is_setup_done = false; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err("peer mlme component object is NULL"); + return false; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + is_setup_done = + peer_priv->twt_ctx.session_info[i].setup_done; + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + is_setup_done) + break; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return is_setup_done; +} + +void mlme_twt_set_wait_for_notify(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool is_set) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_legacy_err("vdev object not found"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->twt_wait_for_notify = is_set; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +} + +void mlme_set_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_session_state state) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_err(" peer mlme component object is NULL"); + return; + } + + mlme_debug("set_state:%d for dialog_id:%d", state, dialog_id); + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->twt_ctx.session_info[i].state = state; + break; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); +} + +enum wlan_twt_session_state +mlme_get_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err(" peer mlme object is NULL"); + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id && + dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + return peer_priv->twt_ctx.session_info[i].state; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + +uint8_t mlme_get_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + if (!peer_priv) { + mlme_legacy_err("peer mlme object is NULL"); + return 0; + } + + return peer_priv->twt_ctx.peer_capability; +} + +void mlme_set_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t caps) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_debug("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_debug("peer mlme object is NULL"); + return; + } + + peer_priv->twt_ctx.peer_capability = caps; + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); +} + +bool mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_ENABLE_TWT); + + return mlme_obj->cfg.twt_cfg.is_twt_enabled; +} + +#if defined(WLAN_FEATURE_11AX) && defined(WLAN_SUPPORT_TWT) +bool mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.he_caps.dot11_he_cap.flex_twt_sched; +} +#endif + +QDF_STATUS +mlme_sap_set_twt_all_peers_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct peer_mlme_priv_obj *peer_priv; + + if (!psoc) { + mlme_legacy_err("psoc is NULL, dialog_id: %d", dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_legacy_err("vdev is NULL, vdev_id: %d dialog_id: %d", + vdev_id, dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_err("Peer list for vdev obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_MLME_NB_ID); + while (peer) { + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (peer_priv) { + uint8_t i = 0; + uint8_t num_twt_sessions = + peer_priv->twt_ctx.num_twt_sessions; + + for (i = 0; i < num_twt_sessions; i++) { + uint8_t existing_dialog_id = + peer_priv->twt_ctx.session_info[i].dialog_id; + + if (existing_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->twt_ctx.session_info[i].active_cmd = cmd; + + if (dialog_id != + TWT_ALL_SESSIONS_DIALOG_ID) { + break; + } + } + } + } + + peer_next = + wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_MLME_NB_ID); + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + peer = peer_next; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_SUCCESS; +} + +bool +mlme_twt_any_peer_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct peer_mlme_priv_obj *peer_priv; + bool cmd_in_progress = false; + + if (!psoc) { + mlme_legacy_err("psoc is NULL, dialog_id: %d", dialog_id); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_legacy_err("vdev is NULL, vdev_id: %d dialog_id: %d", + vdev_id, dialog_id); + return false; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_err("Peer list for vdev obj is NULL"); + return false; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_MLME_NB_ID); + while (peer) { + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (peer_priv) { + uint8_t i = 0; + uint8_t num_twt_sessions = + peer_priv->twt_ctx.num_twt_sessions; + + for (i = 0; i < num_twt_sessions; i++) { + enum wlan_twt_commands active_cmd; + uint8_t existing_dialog_id; + + active_cmd = + peer_priv->twt_ctx.session_info[i].active_cmd; + existing_dialog_id = + peer_priv->twt_ctx.session_info[i].dialog_id; + + if (existing_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + cmd_in_progress = (active_cmd == cmd); + + if (dialog_id != + TWT_ALL_SESSIONS_DIALOG_ID || + cmd_in_progress) { + wlan_objmgr_peer_release_ref( + peer, + WLAN_MLME_NB_ID); + wlan_objmgr_vdev_release_ref( + vdev, + WLAN_MLME_NB_ID); + return cmd_in_progress; + } + } + } + } + + peer_next = + wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_MLME_NB_ID); + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + peer = peer_next; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return cmd_in_progress; +} + +bool mlme_sap_twt_peer_is_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + uint8_t i = 0; + bool cmd_in_progress = false; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err(" peer mlme component object is NULL"); + return false; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + enum wlan_twt_commands active_cmd; + uint8_t existing_dialog_id; + + active_cmd = + peer_priv->twt_ctx.session_info[i].active_cmd; + existing_dialog_id = + peer_priv->twt_ctx.session_info[i].dialog_id; + + if (existing_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID || + existing_dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + cmd_in_progress = (active_cmd == cmd); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + cmd_in_progress) { + break; + } + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + return cmd_in_progress; +} + +QDF_STATUS mlme_set_twt_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + uint8_t i = 0; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err(" peer mlme component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->twt_ctx.session_info[i].active_cmd = cmd; + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) + break; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +bool mlme_is_twt_notify_in_progress(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + bool is_twt_notify_in_progress; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + + if (!vdev) { + mlme_legacy_err("vdev object not found"); + return false; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + is_twt_notify_in_progress = mlme_priv->twt_wait_for_notify; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return is_twt_notify_in_progress; +} + +bool mlme_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + enum wlan_twt_commands active_cmd; + uint8_t i = 0; + bool is_command_in_progress = false; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + mlme_legacy_err(" peer mlme component object is NULL"); + return false; + } + + for (i = 0; i < peer_priv->twt_ctx.num_twt_sessions; i++) { + active_cmd = peer_priv->twt_ctx.session_info[i].active_cmd; + + if (pactive_cmd) + *pactive_cmd = active_cmd; + + if (peer_priv->twt_ctx.session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + if (cmd == WLAN_TWT_ANY) { + is_command_in_progress = + (active_cmd != WLAN_TWT_NONE); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + is_command_in_progress) + break; + } else { + is_command_in_progress = (active_cmd == cmd); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + is_command_in_progress) + break; + } + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return is_command_in_progress; +} + +bool mlme_is_24ghz_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_ENABLE_TWT_24GHZ); + + return mlme_obj->cfg.twt_cfg.enable_twt_24ghz; +} + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +bool mlme_is_twt_disable_info_frame(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_DISABLE_TWT_INFO_FRAME); + + return mlme_obj->cfg.twt_cfg.disable_twt_info_frame; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c new file mode 100644 index 0000000000..79c57ff12c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c @@ -0,0 +1,2492 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define internal APIs related to the mlme component, legacy APIs are + * called for the time being, but will be cleaned up after convergence + */ +#include "wlan_mlme_main.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "lim_utils.h" +#include "wma_api.h" +#include "wma.h" +#include "lim_types.h" +#include +#include <../../core/src/vdev_mgr_ops.h> +#include "wlan_psoc_mlme_api.h" +#include "target_if_cm_roam_offload.h" +#include "wlan_crypto_global_api.h" +#include "target_if_wfa_testcmd.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include "csr_api.h" +#include +#include "target_if_cm_roam_event.h" +#include "wlan_cm_roam_api.h" +#include "wifi_pos_api.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include +#include +#include +#include "wlan_mlo_mgr_sta.h" +#endif +#include +#include "target_if_mlme.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_cp_stats_mc_tgt_api.h" +#include "wlan_objmgr_pdev_obj.h" + +static struct vdev_mlme_ops sta_mlme_ops; +static struct vdev_mlme_ops ap_mlme_ops; +static struct vdev_mlme_ops mon_mlme_ops; +static struct mlme_ext_ops ext_ops; +#ifdef WLAN_FEATURE_11BE_MLO +static struct mlo_mlme_ext_ops mlo_ext_ops; +#endif + +bool mlme_is_vdev_in_beaconning_mode(enum QDF_OPMODE vdev_opmode) +{ + switch (vdev_opmode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + case QDF_IBSS_MODE: + case QDF_NDI_MODE: + return true; + default: + return false; + } +} + +/** + * mlme_get_global_ops() - Register ext global ops + * + * Return: ext_ops global ops + */ +static struct mlme_ext_ops *mlme_get_global_ops(void) +{ + return &ext_ops; +} + +QDF_STATUS mlme_register_mlme_ext_ops(void) +{ + mlme_set_ops_register_cb(mlme_get_global_ops); + + /* Overwrite with UTF cb if UTF enabled */ + cm_utf_set_mlme_ops(mlme_get_global_ops()); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS mlme_register_mlo_ext_ops(void) +{ + QDF_STATUS status; + struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); + + if (!mlo_ctx) + return QDF_STATUS_E_FAILURE; + + mlo_reg_mlme_ext_cb(mlo_ctx, &mlo_ext_ops); + + status = mlo_mgr_register_link_switch_notifier(WLAN_UMAC_COMP_MLME, + wlan_cm_link_switch_notif_cb); + if (status == QDF_STATUS_E_NOSUPPORT) { + status = QDF_STATUS_SUCCESS; + mlme_debug("Link switch not supported"); + } else if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to register link switch notifier for mlme!"); + } + + return status; +} + +QDF_STATUS mlme_unregister_mlo_ext_ops(void) +{ + struct mlo_mgr_context *mlo_ctx = wlan_objmgr_get_mlo_ctx(); + + if (mlo_ctx) + mlo_unreg_mlme_ext_cb(mlo_ctx); + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS mlme_register_mlo_ext_ops(void) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_unregister_mlo_ext_ops(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif +/** + * mlme_register_vdev_mgr_ops() - Register vdev mgr ops + * @vdev_mlme: vdev mlme object + * + * This function is called to register vdev manager operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_register_vdev_mgr_ops(struct vdev_mlme_obj *vdev_mlme) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = vdev_mlme->vdev; + + if (mlme_is_vdev_in_beaconning_mode(vdev->vdev_mlme.vdev_opmode)) + vdev_mlme->ops = &ap_mlme_ops; + else if (vdev->vdev_mlme.vdev_opmode == QDF_MONITOR_MODE) + vdev_mlme->ops = &mon_mlme_ops; + else + vdev_mlme->ops = &sta_mlme_ops; + + return QDF_STATUS_SUCCESS; +} + +/** + * mlme_unregister_vdev_mgr_ops() - Unregister vdev mgr ops + * @vdev_mlme: vdev mlme object + * + * This function is called to unregister vdev manager operations + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_unregister_vdev_mgr_ops(struct vdev_mlme_obj *vdev_mlme) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * sta_mlme_vdev_start_send() - MLME vdev start callback + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to initiate actions of VDEV.start + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_sta_mlme_vdev_start_send(vdev_mlme, event_data_len, + event_data); +} + +/** + * sta_mlme_start_continue() - vdev start rsp callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to handle the VDEV START/RESTART callback + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_sta_mlme_vdev_start_continue(vdev_mlme, data_len, data); +} + +/** + * sta_mlme_vdev_restart_send() - MLME vdev restart send + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to initiate actions of VDEV.start + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_sta_mlme_vdev_restart_send(vdev_mlme, event_data_len, + event_data); +} + +/** + * sta_mlme_vdev_start_req_failed() - MLME start fail callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send the vdev stop to firmware + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_start_req_failed(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, + void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_sta_mlme_vdev_req_fail(vdev_mlme, data_len, data); +} + +/** + * sta_mlme_vdev_start_connection() - MLME vdev start callback + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to initiate actions of STA connection + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_start_connection(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return QDF_STATUS_SUCCESS; +} + +#if defined WLAN_FEATURE_SR +int mlme_sr_is_enable(struct wlan_objmgr_vdev *vdev) +{ + uint8_t sr_ctrl; + + sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev); + return (!sr_ctrl || !(sr_ctrl & NON_SRG_PD_SR_DISALLOWED) || + (sr_ctrl & SRG_INFO_PRESENT)); +} + +/** + * mlme_sr_handle_conc(): Handle concurrency scenario i.e Single MAC + * concurrency is not supoprted for SR, Disable SR if it is enable on other + * VDEV and enable it back once the once the concurrent vdev is down. + * + * @vdev: object manager vdev + * @conc_vdev: cuncurrent vdev object + * @en_sr_curr_vdev: indicates spatial reuse enable/disable + * + */ +static void +mlme_sr_handle_conc(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_vdev *conc_vdev, bool en_sr_curr_vdev) +{ + uint32_t val = 0; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_tx_ops *tx_ops; + struct wlan_lmac_if_spatial_reuse_tx_ops *sr_tx_ops; + uint8_t conc_vdev_id = wlan_vdev_get_id(conc_vdev); + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev is NULL"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev); + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + mlme_err("tx_ops is NULL"); + return; + } + + sr_tx_ops = &tx_ops->spatial_reuse_tx_ops; + if (en_sr_curr_vdev) { + wlan_vdev_mlme_set_sr_disable_due_conc(vdev, true); + wlan_vdev_mlme_set_sr_disable_due_conc(conc_vdev, true); + + if (!wlan_vdev_mlme_get_he_spr_enabled(conc_vdev)) + return; + + if (mlme_sr_is_enable(conc_vdev)) { + if (sr_tx_ops->target_if_sr_update) + sr_tx_ops->target_if_sr_update + (pdev, conc_vdev_id, val); + + wlan_spatial_reuse_osif_event(conc_vdev, + SR_OPERATION_SUSPEND, + SR_REASON_CODE_CONCURRENCY); + } + } else if (wlan_vdev_mlme_is_sr_disable_due_conc(conc_vdev)) { + wlan_vdev_mlme_set_sr_disable_due_conc(conc_vdev, false); + + if (!wlan_vdev_mlme_get_he_spr_enabled(conc_vdev)) + return; + + if (mlme_sr_is_enable(conc_vdev)) { + wlan_mlme_update_sr_data(conc_vdev, &val, 0, 0, true); + + if (sr_tx_ops->target_if_sr_update) + sr_tx_ops->target_if_sr_update + (pdev, conc_vdev_id, val); + + wlan_spatial_reuse_osif_event(conc_vdev, + SR_OPERATION_RESUME, + SR_REASON_CODE_CONCURRENCY); + } else { + mlme_debug("SR Disabled in SR Control"); + } + } +} + +void mlme_sr_update(struct wlan_objmgr_vdev *vdev, bool enable) +{ + struct wlan_objmgr_vdev *conc_vdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_lmac_if_tx_ops *tx_ops; + uint32_t conc_vdev_id; + uint32_t val = 0; + uint8_t vdev_id; + uint8_t mac_id; + + if (!vdev) { + mlme_err("vdev is NULL"); + return; + } + vdev_id = wlan_vdev_get_id(vdev); + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev is NULL"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("psoc is NULL"); + return; + } + + policy_mgr_get_mac_id_by_session_id(psoc, vdev_id, &mac_id); + conc_vdev_id = policy_mgr_get_conc_vdev_on_same_mac(psoc, vdev_id, + mac_id); + if (conc_vdev_id != WLAN_INVALID_VDEV_ID && + !policy_mgr_sr_same_mac_conc_enabled(psoc)) { + /* + * Single MAC concurrency is not supoprted for SR, + * Disable SR if it is enable on other VDEV and enable + * it back once the once the concurrent vdev is down. + */ + mlme_debug("SR with concurrency is not allowed"); + conc_vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, conc_vdev_id, + WLAN_MLME_SB_ID); + if (!conc_vdev) { + mlme_err("Can't get vdev by vdev_id:%d", conc_vdev_id); + } else { + mlme_sr_handle_conc(vdev, conc_vdev, enable); + wlan_objmgr_vdev_release_ref(conc_vdev, + WLAN_MLME_SB_ID); + goto err; + } + } + + if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) { + mlme_err("Spatial Reuse disabled for vdev_id: %d", vdev_id); + goto err; + } + + if (mlme_sr_is_enable(vdev)) { + if (enable) { + wlan_mlme_update_sr_data(vdev, &val, 0, 0, true); + } else { + /* VDEV down, disable SR */ + wlan_vdev_mlme_set_he_spr_enabled(vdev, false); + wlan_vdev_mlme_set_sr_ctrl(vdev, 0); + wlan_vdev_mlme_set_non_srg_pd_offset(vdev, 0); + } + + mlme_debug("SR param val: %x, Enable: %x", val, enable); + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (tx_ops && tx_ops->spatial_reuse_tx_ops.target_if_sr_update) + tx_ops->spatial_reuse_tx_ops.target_if_sr_update + (pdev, vdev_id, val); + } else { + mlme_debug("Spatial reuse is disabled in SR control"); + } +err: + return; +} +#endif + +/** + * sta_mlme_vdev_up_send() - MLME vdev UP callback + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to send the vdev up command + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + QDF_STATUS status; + + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + status = wma_sta_vdev_up_send(vdev_mlme, event_data_len, event_data); + + if (QDF_IS_STATUS_SUCCESS(status)) + mlme_sr_update(vdev_mlme->vdev, true); + + return status; +} + +/** + * sta_mlme_vdev_notify_up_complete() - MLME vdev UP complete callback + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to VDEV MLME on moving + * to UP state + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_notify_up_complete(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return QDF_STATUS_SUCCESS; +} + +/** + * sta_mlme_vdev_notify_roam_start() - MLME vdev Roam start callback + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to VDEV MLME on roaming + * to UP state + * + * Return: QDF_STATUS + */ +static +QDF_STATUS sta_mlme_vdev_notify_roam_start(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wlan_cm_sta_mlme_vdev_roam_notify(vdev_mlme, event_data_len, + event_data); +} + +/** + * sta_mlme_vdev_disconnect_bss() - MLME vdev disconnect bss callback + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * @is_disconnect_legacy_only: flag to indicate legacy disconnect + * + * This function is called to disconnect BSS/send deauth to AP + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_disconnect_bss(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data, + bool is_disconnect_legacy_only) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_sta_mlme_vdev_disconnect_bss(vdev_mlme, event_data_len, + event_data); +} + +/** + * sta_mlme_vdev_stop_send() - MLME vdev stop send callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send the vdev stop to firmware + * + * Return: QDF_STATUS + */ +static QDF_STATUS sta_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, + void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_sta_mlme_vdev_stop_send(vdev_mlme, data_len, data); +} + +/** + * sta_mlme_vdev_sta_disconnect_start() - MLME vdev disconnect send callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to trigger the vdev stop to firmware when + * reassoc failure + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sta_mlme_vdev_sta_disconnect_start(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_sta_mlme_vdev_sta_disconnect_start(vdev_mlme, data_len, + data); +} + +/** + * vdevmgr_mlme_stop_continue() - MLME vdev stop send callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to initiate operations on + * LMAC/FW stop response such as remove peer. + * + * Return: QDF_STATUS + */ +static QDF_STATUS vdevmgr_mlme_stop_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, + void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_mlme_vdev_stop_continue(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_start_send () - send vdev start req + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to initiate actions of VDEV start ie start bss + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_start_send(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_start_continue () - vdev start rsp callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to handle the VDEV START/RESTART callback + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + mlme_set_notify_co_located_ap_update_rnr(vdev_mlme->vdev, true); + + return wma_ap_mlme_vdev_start_continue(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_update_beacon() - callback to initiate beacon update + * @vdev_mlme: vdev mlme object + * @op: beacon operation + * @data_len: event data length + * @data: event data + * + * This function is called to update beacon + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_update_beacon(struct vdev_mlme_obj *vdev_mlme, + enum beacon_update_op op, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_update_beacon(vdev_mlme, op, data_len, data); +} + +/** + * ap_mlme_vdev_up_send() - callback to send vdev up + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send vdev up req + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_up_send(vdev_mlme, data_len, data); +} + +#ifdef WLAN_FEATURE_11BE_MLO +void wlan_handle_emlsr_sta_concurrency(struct wlan_objmgr_psoc *psoc, + bool conc_con_coming_up, + bool emlsr_sta_coming_up) +{ + policy_mgr_handle_emlsr_sta_concurrency(psoc, conc_con_coming_up, + emlsr_sta_coming_up); +} +#endif + +/** + * ap_mlme_vdev_notify_up_complete() - callback to notify up completion + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to indicate up is completed + * + * Return: QDF_STATUS + */ +static QDF_STATUS +ap_mlme_vdev_notify_up_complete(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + if (!vdev_mlme) { + mlme_legacy_err("data is NULL"); + return QDF_STATUS_E_INVAL; + } + + pe_debug("Vdev %d is up", wlan_vdev_get_id(vdev_mlme->vdev)); + + return QDF_STATUS_SUCCESS; +} + +/** + * ap_mlme_vdev_disconnect_peers() - callback to disconnect all connected peers + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * @is_disconnect_legacy_only: flag to indicate is disconnect legacy + * + * This function is called to disconnect all connected peers + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_disconnect_peers(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data, + bool is_disconnect_legacy_only) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_disconnect_peers(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_stop_send() - callback to send stop vdev request + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send stop vdev request + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_stop_send(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_is_newchan_no_cac - VDEV SM CSA complete notification + * @vdev_mlme: VDEV MLME comp object + * + * On CSA complete, checks whether Channel does not needs CAC period, if + * it doesn't need cac return SUCCESS else FAILURE + * + * Return: SUCCESS if new channel doesn't need cac + * else FAILURE + */ +static QDF_STATUS +ap_mlme_vdev_is_newchan_no_cac(struct vdev_mlme_obj *vdev_mlme) +{ + bool cac_required; + + cac_required = mlme_get_cac_required(vdev_mlme->vdev); + mlme_legacy_debug("vdev id = %d cac_required %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id, cac_required); + + if (!cac_required) + return QDF_STATUS_SUCCESS; + + mlme_set_cac_required(vdev_mlme->vdev, false); + + return QDF_STATUS_E_FAILURE; +} + +/** + * vdevmgr_mlme_vdev_down_send() - callback to send vdev down req + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send vdev down req + * + * Return: QDF_STATUS + */ +static QDF_STATUS vdevmgr_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + QDF_STATUS status; + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + + mlme_legacy_debug("vdev id = %d ", vdev_id); + status = wma_ap_mlme_vdev_down_send(vdev_mlme, data_len, data); + if (QDF_IS_STATUS_SUCCESS(status)) + mlme_sr_update(vdev_mlme->vdev, false); + + return status; +} + +/** + * vdevmgr_notify_down_complete() - callback to indicate vdev down is completed + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to indicate vdev down is completed + * + * Return: QDF_STATUS + */ +static QDF_STATUS vdevmgr_notify_down_complete(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + + return wma_mlme_vdev_notify_down_complete(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_start_req_failed () - vdev start req fail callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to handle vdev start req/rsp failure + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_start_req_failed(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_start_req_failed(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_restart_send() - a callback to send vdev restart + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to initiate and send vdev restart req + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_ap_mlme_vdev_restart_send(vdev_mlme, data_len, data); +} + +/** + * ap_mlme_vdev_stop_start_send() - handle vdev stop during start req + * @vdev_mlme: vdev mlme object + * @type: restart req or start req + * @data_len: event data length + * @data: event data + * + * This function is called to handle vdev stop during start req + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_stop_start_send(struct vdev_mlme_obj *vdev_mlme, + enum vdev_cmd_type type, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_ap_mlme_vdev_stop_start_send(vdev_mlme, type, + data_len, data); +} + +QDF_STATUS mlme_set_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev, + bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->chan_switch_in_progress = val; + mlo_set_chan_switch_in_progress(vdev, val); + + mlme_legacy_info("Set chan_switch_in_progress: %d vdev %d", + val, wlan_vdev_get_id(vdev)); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_MSCS +QDF_STATUS mlme_set_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->mscs_req_info.is_mscs_req_sent = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_is_mscs_req_sent(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->mscs_req_info.is_mscs_req_sent; +} +#endif + +bool mlme_is_chan_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->chan_switch_in_progress; +} + +QDF_STATUS +ap_mlme_set_hidden_ssid_restart_in_progress(struct wlan_objmgr_vdev *vdev, + bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->hidden_ssid_restart_in_progress = val; + + return QDF_STATUS_SUCCESS; +} + +bool ap_mlme_is_hidden_ssid_restart_in_progress(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->hidden_ssid_restart_in_progress; +} + +QDF_STATUS mlme_set_bigtk_support(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->bigtk_vdev_support = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_bigtk_support(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->bigtk_vdev_support; +} + +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS +mlme_set_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->connect_info.tdls_chan_swit_prohibited = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->connect_info.tdls_chan_swit_prohibited; +} + +QDF_STATUS +mlme_set_tdls_prohibited(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->connect_info.tdls_prohibited = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_tdls_prohibited(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->connect_info.tdls_prohibited; +} +#endif + +QDF_STATUS +mlme_set_roam_reason_better_ap(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->roam_reason_better_ap = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_roam_reason_better_ap(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->roam_reason_better_ap; +} + +QDF_STATUS +mlme_set_hb_ap_rssi(struct wlan_objmgr_vdev *vdev, uint32_t val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->hb_failure_rssi = val; + + return QDF_STATUS_SUCCESS; +} + +uint32_t mlme_get_hb_ap_rssi(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + return mlme_priv->hb_failure_rssi; +} + + +QDF_STATUS mlme_set_connection_fail(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->connection_fail = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_is_connection_fail(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->connection_fail; +} + +#ifdef FEATURE_WLAN_WAPI +static void mlme_is_sta_vdev_wapi(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + int32_t keymgmt; + bool *is_wapi_sta_exist = (bool *)arg; + QDF_STATUS status; + + if (*is_wapi_sta_exist) + return; + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return; + + status = wlan_vdev_is_up(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return; + + keymgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (keymgmt < 0) + return; + + if (keymgmt & ((1 << WLAN_CRYPTO_KEY_MGMT_WAPI_PSK) | + (1 << WLAN_CRYPTO_KEY_MGMT_WAPI_CERT))) { + *is_wapi_sta_exist = true; + mlme_debug("wapi exist for Vdev: %d", + wlan_vdev_get_id(vdev)); + } +} + +bool mlme_is_wapi_sta_active(struct wlan_objmgr_pdev *pdev) +{ + bool is_wapi_sta_exist = false; + + wlan_objmgr_pdev_iterate_obj_list(pdev, + WLAN_VDEV_OP, + mlme_is_sta_vdev_wapi, + &is_wapi_sta_exist, 0, + WLAN_MLME_OBJMGR_ID); + + return is_wapi_sta_exist; +} +#endif + +QDF_STATUS mlme_set_assoc_type(struct wlan_objmgr_vdev *vdev, + enum vdev_assoc_type assoc_type) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->assoc_type = assoc_type; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_get_vdev_stop_type(struct wlan_objmgr_vdev *vdev, + uint32_t *vdev_stop_type) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + *vdev_stop_type = mlme_priv->vdev_stop_type; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_set_vdev_stop_type(struct wlan_objmgr_vdev *vdev, + uint32_t vdev_stop_type) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->vdev_stop_type = vdev_stop_type; + + return QDF_STATUS_SUCCESS; +} + +void mlme_set_notify_co_located_ap_update_rnr(struct wlan_objmgr_vdev *vdev, + bool upt_rnr) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->notify_co_located_ap_upt_rnr = upt_rnr; +} + +bool mlme_is_notify_co_located_ap_update_rnr(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->notify_co_located_ap_upt_rnr; +} + +bool wlan_is_vdev_traffic_ll_ht(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + if (mlme_priv->vdev_traffic_type & PM_VDEV_TRAFFIC_LOW_LATENCY || + mlme_priv->vdev_traffic_type & PM_VDEV_TRAFFIC_HIGH_TPUT) + return true; + + return false; +} + +WMI_HOST_WIFI_STANDARD mlme_get_vdev_wifi_std(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return WMI_HOST_WIFI_STANDARD_7; + } + + if (!mlme_priv->is_user_std_set) + return WMI_HOST_WIFI_STANDARD_7; + + return mlme_priv->wifi_std; +} + +enum vdev_assoc_type mlme_get_assoc_type(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->assoc_type; +} + +QDF_STATUS +mlme_set_vdev_start_failed(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->vdev_start_failed = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_vdev_start_failed(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->vdev_start_failed; +} + +QDF_STATUS mlme_set_cac_required(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->cac_required_for_new_channel = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_cac_required(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->cac_required_for_new_channel; +} + +QDF_STATUS mlme_set_mbssid_info(struct wlan_objmgr_vdev *vdev, + struct scan_mbssid_info *mbssid_info, + qdf_freq_t freq) +{ + struct vdev_mlme_obj *vdev_mlme; + struct vdev_mlme_mbss_11ax *mbss_11ax; + struct qdf_mac_addr bssid; + struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_legacy_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mbss_11ax = &vdev_mlme->mgmt.mbss_11ax; + mbss_11ax->profile_idx = mbssid_info->profile_num; + mbss_11ax->profile_num = mbssid_info->profile_count; + qdf_mem_copy(mbss_11ax->trans_bssid, + mbssid_info->trans_bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(mbss_11ax->non_trans_bssid, + mbssid_info->non_trans_bssid, QDF_MAC_ADDR_SIZE); + + qdf_mem_copy(&bssid.bytes, vdev_mlme->mgmt.generic.bssid, + QDF_MAC_ADDR_SIZE); + + /* + * Consider the case of 5 GHz + non-tx 6 GHz MLO candidate. + * The scan entry might be generated from a ML-probe, which doesn't have + * the MBSSID info for the non-tx partner link. In this case, host has + * to identify if this link is MBSS or not. This is essential to receive + * traffic over this link. + * + * The below logic looks into the rnr db for the 6 GHz bssid and + * determines if the bssid is non-tx profile from the bss parameter + * saved by its neighbor. If this is a non-tx bssid, but trans_bssid + * info is not available from the scan entry, then set transmitted bssid + * to bcast address. Upon sending this bcast tx bssid to firmware, the + * firmware would auto-detect the tx bssid from the upcoming beacons + * and tunes the interface to proper bssid. + * + * Note: Always send bcast mac in trans_bssid if the host is unable + * to determine if a given BSS is part of an MBSS. + */ + if (freq != INVALID_CHANNEL_NUM && !mbss_11ax->profile_idx && + qdf_is_macaddr_zero((struct qdf_mac_addr *)&mbss_11ax->trans_bssid) && + util_is_bssid_non_tx(wlan_vdev_get_psoc(vdev), &bssid, freq)) + qdf_mem_copy(mbss_11ax->trans_bssid, + bcast_addr.bytes, QDF_MAC_ADDR_SIZE); + + return QDF_STATUS_SUCCESS; +} + +void mlme_get_mbssid_info(struct wlan_objmgr_vdev *vdev, + struct vdev_mlme_mbss_11ax *mbss_11ax) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_legacy_err("vdev component object is NULL"); + return; + } + + mbss_11ax = &vdev_mlme->mgmt.mbss_11ax; +} + +QDF_STATUS mlme_set_tx_power(struct wlan_objmgr_vdev *vdev, + int8_t tx_power) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + + if (!vdev_mlme) { + mlme_legacy_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_mlme->mgmt.generic.tx_power = tx_power; + + return QDF_STATUS_SUCCESS; +} + +int8_t mlme_get_tx_power(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_legacy_err("vdev component object is NULL"); + return QDF_STATUS_E_INVAL; + } + + return vdev_mlme->mgmt.generic.tx_power; +} + +QDF_STATUS mlme_set_max_reg_power(struct wlan_objmgr_vdev *vdev, + int8_t max_reg_power) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + + if (!vdev_mlme) { + mlme_legacy_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_mlme->mgmt.generic.maxregpower = max_reg_power; + + return QDF_STATUS_SUCCESS; +} + +int8_t mlme_get_max_reg_power(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_legacy_err("vdev component object is NULL"); + return QDF_STATUS_E_INVAL; + } + + return vdev_mlme->mgmt.generic.maxregpower; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS +mlme_set_single_link_mlo_roaming(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->is_single_link_mlo_roam = val; + + return QDF_STATUS_SUCCESS; +} + +bool mlme_get_single_link_mlo_roaming(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->is_single_link_mlo_roam; +} +#endif + +/** + * mlme_get_vdev_types() - get vdev type and subtype from its operation mode + * @mode: operation mode of vdev + * @type: type of vdev + * @sub_type: sub_type of vdev + * + * This API is called to get vdev type and subtype from its operation mode. + * Vdev operation modes are defined in enum QDF_OPMODE. + * + * Type of vdev are WLAN_VDEV_MLME_TYPE_AP, WLAN_VDEV_MLME_TYPE_STA, + * WLAN_VDEV_MLME_TYPE_IBSS, ,WLAN_VDEV_MLME_TYPE_MONITOR, + * WLAN_VDEV_MLME_TYPE_NAN, WLAN_VDEV_MLME_TYPE_OCB, WLAN_VDEV_MLME_TYPE_NDI + * + * Sub_types of vdev are WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE, + * WLAN_VDEV_MLME_SUBTYPE_P2P_CLIENT, WLAN_VDEV_MLME_SUBTYPE_P2P_GO, + * WLAN_VDEV_MLME_SUBTYPE_PROXY_STA, WLAN_VDEV_MLME_SUBTYPE_MESH + * Return: QDF_STATUS + */ + +static QDF_STATUS mlme_get_vdev_types(enum QDF_OPMODE mode, uint8_t *type, + uint8_t *sub_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + *type = 0; + *sub_type = 0; + + switch (mode) { + case QDF_STA_MODE: + *type = WLAN_VDEV_MLME_TYPE_STA; + break; + case QDF_SAP_MODE: + *type = WLAN_VDEV_MLME_TYPE_AP; + break; + case QDF_P2P_DEVICE_MODE: + *type = WLAN_VDEV_MLME_TYPE_AP; + *sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE; + break; + case QDF_P2P_CLIENT_MODE: + *type = WLAN_VDEV_MLME_TYPE_STA; + *sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_CLIENT; + break; + case QDF_P2P_GO_MODE: + *type = WLAN_VDEV_MLME_TYPE_AP; + *sub_type = WLAN_VDEV_MLME_SUBTYPE_P2P_GO; + break; + case QDF_OCB_MODE: + *type = WLAN_VDEV_MLME_TYPE_OCB; + break; + case QDF_IBSS_MODE: + *type = WLAN_VDEV_MLME_TYPE_IBSS; + break; + case QDF_MONITOR_MODE: + *type = WMI_HOST_VDEV_TYPE_MONITOR; + break; + case QDF_NDI_MODE: + *type = WLAN_VDEV_MLME_TYPE_NDI; + break; + case QDF_NAN_DISC_MODE: + *type = WLAN_VDEV_MLME_TYPE_NAN; + break; + default: + mlme_err("Invalid device mode %d", mode); + status = QDF_STATUS_E_INVAL; + break; + } + return status; +} + +#ifdef WLAN_FEATURE_FILS_SK +static inline void mlme_free_fils_info(struct mlme_connect_info *connect_info) +{ + qdf_mem_free(connect_info->fils_con_info); + qdf_mem_free(connect_info->hlp_ie); + connect_info->hlp_ie = NULL; + connect_info->hlp_ie_len = 0; + connect_info->fils_con_info = NULL; +} +#else +static inline void mlme_free_fils_info(struct mlme_connect_info *connect_info) +{} +#endif + +static +void mlme_init_wait_for_key_timer(struct wlan_objmgr_vdev *vdev, + struct wait_for_key_timer *wait_key_timer) +{ + QDF_STATUS status; + + if (!vdev || !wait_key_timer) { + mlme_err("vdev or wait for key is NULL"); + return; + } + + wait_key_timer->vdev = vdev; + status = qdf_mc_timer_init(&wait_key_timer->timer, QDF_TIMER_TYPE_SW, + cm_wait_for_key_time_out_handler, + wait_key_timer); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("cannot allocate memory for WaitForKey time out timer"); +} + +static +void mlme_deinit_wait_for_key_timer(struct wait_for_key_timer *wait_key_timer) +{ + qdf_mc_timer_stop(&wait_key_timer->timer); + qdf_mc_timer_destroy(&wait_key_timer->timer); +} + +static void mlme_ext_handler_destroy(struct vdev_mlme_obj *vdev_mlme) +{ + if (!vdev_mlme || !vdev_mlme->ext_vdev_ptr) + return; + qdf_runtime_lock_deinit( + &vdev_mlme->ext_vdev_ptr->bss_color_change_runtime_lock); + qdf_wake_lock_destroy( + &vdev_mlme->ext_vdev_ptr->bss_color_change_wakelock); + qdf_runtime_lock_deinit( + &vdev_mlme->ext_vdev_ptr->disconnect_runtime_lock); + mlme_free_self_disconnect_ies(vdev_mlme->vdev); + mlme_free_peer_disconnect_ies(vdev_mlme->vdev); + mlme_free_sae_auth_retry(vdev_mlme->vdev); + mlme_deinit_wait_for_key_timer(&vdev_mlme->ext_vdev_ptr->wait_key_timer); + mlme_free_fils_info(&vdev_mlme->ext_vdev_ptr->connect_info); + mlme_cm_free_roam_stats_info(vdev_mlme->ext_vdev_ptr); + qdf_mem_free(vdev_mlme->ext_vdev_ptr); + vdev_mlme->ext_vdev_ptr = NULL; +} + +static QDF_STATUS +mlme_wma_vdev_detach_post_cb(struct scheduler_msg *msg) +{ + struct vdev_delete_response rsp = {0}; + + if (!msg) { + mlme_err("Msg is NULL"); + return QDF_STATUS_E_INVAL; + } + + rsp.vdev_id = msg->bodyval; + wma_vdev_detach_callback(&rsp); + + return QDF_STATUS_SUCCESS; +} + +static void mlme_wma_vdev_detach_handler(uint8_t vdev_id) +{ + struct scheduler_msg msg = {0}; + + msg.bodyptr = NULL; + msg.bodyval = vdev_id; + msg.callback = mlme_wma_vdev_detach_post_cb; + + if (scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg) == + QDF_STATUS_SUCCESS) + return; + + mlme_err("Failed to post wma vdev detach"); +} + +/** + * vdevmgr_mlme_ext_hdl_destroy () - Destroy mlme legacy priv object + * @vdev_mlme: vdev mlme object + * + * Return: QDF_STATUS + */ +static +QDF_STATUS vdevmgr_mlme_ext_hdl_destroy(struct vdev_mlme_obj *vdev_mlme) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t vdev_id; + + vdev_id = vdev_mlme->vdev->vdev_objmgr.vdev_id; + mlme_legacy_debug("Sending vdev delete to firmware for vdev id = %d ", + vdev_id); + + if (!vdev_mlme->ext_vdev_ptr) + return status; + + status = vdev_mgr_delete_send(vdev_mlme); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to send vdev delete to firmware"); + mlme_wma_vdev_detach_handler(vdev_id); + } + + mlme_ext_handler_destroy(vdev_mlme); + + return QDF_STATUS_SUCCESS; +} + +/** + * vdevmgr_mlme_ext_hdl_create () - Create mlme legacy priv object + * @vdev_mlme: vdev mlme object + * + * Return: QDF_STATUS + */ +static +QDF_STATUS vdevmgr_mlme_ext_hdl_create(struct vdev_mlme_obj *vdev_mlme) +{ + QDF_STATUS status; + + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + vdev_mlme->ext_vdev_ptr = + qdf_mem_malloc(sizeof(struct mlme_legacy_priv)); + if (!vdev_mlme->ext_vdev_ptr) + return QDF_STATUS_E_NOMEM; + + mlme_init_rate_config(vdev_mlme); + mlme_init_connect_chan_info_config(vdev_mlme); + mlme_cm_alloc_roam_stats_info(vdev_mlme); + vdev_mlme->ext_vdev_ptr->connect_info.fils_con_info = NULL; + mlme_init_wait_for_key_timer(vdev_mlme->vdev, + &vdev_mlme->ext_vdev_ptr->wait_key_timer); + + qdf_wake_lock_create( + &vdev_mlme->ext_vdev_ptr->bss_color_change_wakelock, + "bss_color_change_wakelock"); + qdf_runtime_lock_init( + &vdev_mlme->ext_vdev_ptr->bss_color_change_runtime_lock); + qdf_runtime_lock_init( + &vdev_mlme->ext_vdev_ptr->disconnect_runtime_lock); + + sme_get_vdev_type_nss(wlan_vdev_mlme_get_opmode(vdev_mlme->vdev), + &vdev_mlme->proto.generic.nss_2g, + &vdev_mlme->proto.generic.nss_5g); + + status = mlme_get_vdev_types(wlan_vdev_mlme_get_opmode(vdev_mlme->vdev), + &vdev_mlme->mgmt.generic.type, + &vdev_mlme->mgmt.generic.subtype); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Get vdev type failed; status:%d", status); + mlme_ext_handler_destroy(vdev_mlme); + return status; + } + + status = vdev_mgr_create_send(vdev_mlme); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to create vdev for vdev id %d", + wlan_vdev_get_id(vdev_mlme->vdev)); + vdevmgr_mlme_ext_hdl_destroy(vdev_mlme); + return status; + } + + return status; +} + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +static +QDF_STATUS vdevmgr_mlme_vdev_send_set_mac_addr(struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + struct wlan_objmgr_vdev *vdev) +{ + return vdev_mgr_send_set_mac_addr(mac_addr, mld_addr, vdev); +} +#endif + +/** + * ap_vdev_dfs_cac_timer_stop() - callback to stop cac timer + * @vdev_mlme: vdev mlme object + * @event_data_len: event data length + * @event_data: event data + * + * This function is called to stop cac timer + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_vdev_dfs_cac_timer_stop(struct vdev_mlme_obj *vdev_mlme, + uint16_t event_data_len, + void *event_data) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return QDF_STATUS_SUCCESS; +} + +/** + * mon_mlme_vdev_start_restart_send () - send vdev start/restart req + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to initiate actions of VDEV start/restart + * + * Return: QDF_STATUS + */ +static QDF_STATUS mon_mlme_vdev_start_restart_send( + struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return lim_mon_mlme_vdev_start_send(vdev_mlme, data_len, data); +} + +/** + * mon_mlme_start_continue () - vdev start rsp callback + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to handle the VDEV START/RESTART callback + * + * Return: QDF_STATUS + */ +static QDF_STATUS mon_mlme_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_mon_mlme_vdev_start_continue(vdev_mlme, data_len, data); +} + +/** + * mon_mlme_vdev_up_send() - callback to send vdev up + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send vdev up req + * + * Return: QDF_STATUS + */ +static QDF_STATUS mon_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_mon_mlme_vdev_up_send(vdev_mlme, data_len, data); +} + +/** + * mon_mlme_vdev_disconnect_peers() - callback to disconnect all connected peers + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * @is_disconnect_legacy_only: flag to indicate legacy disconnect + * + * montior mode no connected peers, only do VDEV state transition. + * + * Return: QDF_STATUS + */ +static QDF_STATUS mon_mlme_vdev_disconnect_peers( + struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data, + bool is_disconnect_legacy_only) +{ + struct wlan_objmgr_psoc *psoc = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + uint32_t pdev_id; + + psoc = wlan_vdev_get_psoc(vdev_mlme->vdev); + if (!psoc) { + mlme_legacy_debug("Invalid psoc"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_vdev_get_pdev(vdev_mlme->vdev); + if (!pdev) { + mlme_legacy_debug("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + mlme_legacy_debug("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + /* Cancel periodic pdev stats update */ + tgt_set_pdev_stats_update_period(psoc, pdev_id, 0); + + mlme_legacy_debug("vdev id = %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wlan_vdev_mlme_sm_deliver_evt( + vdev_mlme->vdev, + WLAN_VDEV_SM_EV_DISCONNECT_COMPLETE, + 0, NULL); +} + +/** + * mon_mlme_vdev_stop_send() - callback to send stop vdev request + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send stop vdev request + * + * Return: QDF_STATUS + */ +static QDF_STATUS mon_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_mon_mlme_vdev_stop_send(vdev_mlme, data_len, data); +} + +/** + * mon_mlme_vdev_down_send() - callback to send vdev down req + * @vdev_mlme: vdev mlme object + * @data_len: event data length + * @data: event data + * + * This function is called to send vdev down req + * + * Return: QDF_STATUS + */ +static QDF_STATUS mon_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + mlme_legacy_debug("vdev id = %d", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_mon_mlme_vdev_down_send(vdev_mlme, data_len, data); +} + +/** + * vdevmgr_vdev_delete_rsp_handle() - callback to handle vdev delete response + * @psoc: psoc object + * @rsp: pointer to vdev delete response + * + * This function is called to handle vdev delete response and send result to + * upper layer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +vdevmgr_vdev_delete_rsp_handle(struct wlan_objmgr_psoc *psoc, + struct vdev_delete_response *rsp) +{ + mlme_legacy_debug("vdev id = %d ", rsp->vdev_id); + return wma_vdev_detach_callback(rsp); +} + +/** + * vdevmgr_vdev_stop_rsp_handle() - callback to handle vdev stop response + * @vdev_mlme: vdev mlme object + * @rsp: pointer to vdev stop response + * + * This function is called to handle vdev stop response and send result to + * upper layer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +vdevmgr_vdev_stop_rsp_handle(struct vdev_mlme_obj *vdev_mlme, + struct vdev_stop_response *rsp) +{ + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + return wma_vdev_stop_resp_handler(vdev_mlme, rsp); +} + +/** + * psoc_mlme_ext_hdl_enable() - to enable mlme ext param handler + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS psoc_mlme_ext_hdl_enable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->scan_requester_id = + wlan_scan_register_requester(psoc, "MLME_EXT", + wlan_mlme_chan_stats_scan_event_cb, + NULL); + + return QDF_STATUS_SUCCESS; +} + +/** + * psoc_mlme_ext_hdl_disable() - to disable mlme ext param handler + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS psoc_mlme_ext_hdl_disable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + wlan_scan_unregister_requester(psoc, mlme_obj->scan_requester_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * psoc_mlme_ext_hdl_create() - Create mlme legacy priv object + * @psoc_mlme: psoc mlme object + * + * Return: QDF_STATUS + */ +static +QDF_STATUS psoc_mlme_ext_hdl_create(struct psoc_mlme_obj *psoc_mlme) +{ + psoc_mlme->ext_psoc_ptr = + qdf_mem_malloc(sizeof(struct wlan_mlme_psoc_ext_obj)); + if (!psoc_mlme->ext_psoc_ptr) + return QDF_STATUS_E_NOMEM; + + target_if_cm_roam_register_tx_ops( + &psoc_mlme->ext_psoc_ptr->rso_tx_ops); + + target_if_wfatestcmd_register_tx_ops( + &psoc_mlme->ext_psoc_ptr->wfa_testcmd.tx_ops); + target_if_cm_roam_register_rx_ops( + &psoc_mlme->ext_psoc_ptr->rso_rx_ops); + wlan_mlme_register_rx_ops(&psoc_mlme->ext_psoc_ptr->mlme_rx_ops); + + target_if_mlme_register_tx_ops( + &psoc_mlme->ext_psoc_ptr->mlme_tx_ops); + + return QDF_STATUS_SUCCESS; +} + +/** + * psoc_mlme_ext_hdl_destroy() - Destroy mlme legacy priv object + * @psoc_mlme: psoc mlme object + * + * Return: QDF_STATUS + */ +static +QDF_STATUS psoc_mlme_ext_hdl_destroy(struct psoc_mlme_obj *psoc_mlme) +{ + if (!psoc_mlme) { + mlme_err("PSOC MLME is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (psoc_mlme->ext_psoc_ptr) { + qdf_mem_free(psoc_mlme->ext_psoc_ptr); + psoc_mlme->ext_psoc_ptr = NULL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * vdevmgr_vdev_start_rsp_handle() - callback to handle vdev start response + * @vdev_mlme: vdev mlme object + * @rsp: pointer to vdev start response + * + * This function is called to handle vdev start response + * + * Return: QDF_STATUS + */ +static QDF_STATUS +vdevmgr_vdev_start_rsp_handle(struct vdev_mlme_obj *vdev_mlme, + struct vdev_start_response *rsp) +{ + QDF_STATUS status; + + mlme_legacy_debug("vdev id = %d ", + vdev_mlme->vdev->vdev_objmgr.vdev_id); + status = wma_vdev_start_resp_handler(vdev_mlme, rsp); + + return status; +} + +/** + * vdevmgr_vdev_peer_delete_all_rsp_handle() - callback to handle vdev delete + * all response + * @vdev_mlme: vdev mlme object + * @rsp: pointer to vdev delete response + * + * This function is called to handle vdev delete response and send result to + * upper layer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +vdevmgr_vdev_peer_delete_all_rsp_handle(struct vdev_mlme_obj *vdev_mlme, + struct peer_delete_all_response *rsp) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_wifi_pos_rx_ops *rx_ops; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev_mlme->vdev); + if (!psoc) + return -QDF_STATUS_E_INVAL; + + if (QDF_HAS_PARAM(rsp->peer_type_bitmap, WLAN_PEER_RTT_PASN)) { + rx_ops = wifi_pos_get_rx_ops(psoc); + if (!rx_ops || + !rx_ops->wifi_pos_vdev_delete_all_ranging_peers_rsp_cb) { + mlme_err("rx_ops is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = rx_ops->wifi_pos_vdev_delete_all_ranging_peers_rsp_cb( + psoc, rsp->vdev_id); + return status; + } + + status = lim_process_mlm_del_all_sta_rsp(vdev_mlme, rsp); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("Failed to call lim_process_mlm_del_all_sta_rsp"); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS vdevmgr_reconfig_req_cb(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev = msg->bodyptr; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + + if (!vdev) { + mlme_err("vdev null"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("Failed to get psoc"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + if (!wlan_get_vdev_link_removed_flag_by_vdev_id(psoc, vdev_id)) + mlme_cm_osif_link_reconfig_notify(vdev); + + policy_mgr_handle_link_removal_on_vdev(vdev); + mlo_sta_stop_reconfig_timer_by_vdev(vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS vdevmgr_reconfig_req_flush_cb(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev = msg->bodyptr; + + if (!vdev) { + mlme_err("vdev null"); + return QDF_STATUS_E_INVAL; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +vdevmgr_vdev_reconfig_notify(struct vdev_mlme_obj *vdev_mlme, + uint16_t *tbtt_count, uint16_t bcn_int) +{ + struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev; + + if (!vdev) { + mlme_err("invalid vdev"); + return QDF_STATUS_E_INVAL; + } + mlme_debug("vdev %d link removal notify tbtt %d bcn_int %d", + wlan_vdev_get_id(vdev), *tbtt_count, bcn_int); + if (*tbtt_count * bcn_int <= LINK_REMOVAL_MIN_TIMEOUT_MS) + *tbtt_count = 0; + else if (bcn_int) + *tbtt_count -= LINK_REMOVAL_MIN_TIMEOUT_MS / bcn_int; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +vdevmgr_vdev_reconfig_notify_standby(struct vdev_mlme_obj *vdev_mlme, + struct ml_rv_info *reconfig_info) +{ + struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev; + + if (!vdev) { + mlme_err("invalid vdev"); + return QDF_STATUS_E_INVAL; + } + + return policy_mgr_handle_link_removal_on_standby(vdev, reconfig_info); +} + +static void +vdevmgr_vdev_reconfig_timer_complete(struct vdev_mlme_obj *vdev_mlme) +{ + struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev; + struct scheduler_msg msg = {0}; + QDF_STATUS ret; + + if (!vdev) { + mlme_err("invalid vdev"); + return; + } + mlme_debug("vdev %d link removal timed out", wlan_vdev_get_id(vdev)); + + msg.bodyptr = vdev; + msg.callback = vdevmgr_reconfig_req_cb; + msg.flush_callback = vdevmgr_reconfig_req_flush_cb; + + ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_MLME_CM_ID); + if (QDF_IS_STATUS_ERROR(ret)) + return; + + ret = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + + if (QDF_IS_STATUS_ERROR(ret)) { + mlme_err("vdev %d failed to post scheduler_msg", + wlan_vdev_get_id(vdev)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } +} +#endif + +QDF_STATUS mlme_vdev_self_peer_create(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_err("Failed to get vdev mlme obj for vdev id %d", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + return wma_vdev_self_peer_create(vdev_mlme); +} + +static +QDF_STATUS vdevmgr_mlme_ext_post_hdl_create(struct vdev_mlme_obj *vdev_mlme) +{ + return QDF_STATUS_SUCCESS; +} + +bool mlme_vdev_uses_self_peer(uint32_t vdev_type, uint32_t vdev_subtype) +{ + switch (vdev_type) { + case WMI_VDEV_TYPE_AP: + return vdev_subtype == WMI_UNIFIED_VDEV_SUBTYPE_P2P_DEVICE; + + case WMI_VDEV_TYPE_MONITOR: + case WMI_VDEV_TYPE_OCB: + return true; + + default: + return false; + } +} + +void mlme_vdev_del_resp(uint8_t vdev_id) +{ + sme_vdev_del_resp(vdev_id); +} + +static +QDF_STATUS mlme_vdev_self_peer_delete_resp_flush_cb(struct scheduler_msg *msg) +{ + /* + * sme should be the last component to hold the reference invoke the + * same to release the reference gracefully + */ + sme_vdev_self_peer_delete_resp(msg->bodyptr); + return QDF_STATUS_SUCCESS; +} + +void mlme_vdev_self_peer_delete_resp(struct del_vdev_params *param) +{ + struct scheduler_msg peer_del_rsp = {0}; + QDF_STATUS status; + + peer_del_rsp.type = eWNI_SME_VDEV_DELETE_RSP; + peer_del_rsp.bodyptr = param; + peer_del_rsp.flush_callback = mlme_vdev_self_peer_delete_resp_flush_cb; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &peer_del_rsp); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* In the error cases release the final sme reference */ + wlan_objmgr_vdev_release_ref(param->vdev, WLAN_LEGACY_SME_ID); + qdf_mem_free(param); + } +} + +QDF_STATUS mlme_vdev_self_peer_delete(struct scheduler_msg *self_peer_del_msg) +{ + QDF_STATUS status; + struct del_vdev_params *del_vdev = self_peer_del_msg->bodyptr; + + if (!del_vdev) { + mlme_err("Invalid del self peer params"); + return QDF_STATUS_E_INVAL; + } + + status = wma_vdev_detach(del_vdev); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("Failed to detach vdev"); + + return status; +} + +QDF_STATUS wlan_sap_disconnect_all_p2p_client(uint8_t vdev_id) +{ + return csr_mlme_vdev_disconnect_all_p2p_client_event(vdev_id); +} + +QDF_STATUS wlan_sap_stop_bss(uint8_t vdev_id) +{ + return csr_mlme_vdev_stop_bss(vdev_id); +} + +qdf_freq_t wlan_get_conc_freq(void) +{ + return csr_mlme_get_concurrent_operation_freq(); +} + +/** + * ap_mlme_vdev_csa_complete() - callback to initiate csa complete + * + * @vdev_mlme: vdev mlme object + * + * This function is called for csa complete indication + * + * Return: QDF_STATUS + */ +static QDF_STATUS ap_mlme_vdev_csa_complete(struct vdev_mlme_obj *vdev_mlme) + +{ + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + mlme_legacy_debug("vdev id = %d ", vdev_id); + + if (lim_is_csa_tx_pending(vdev_id)) + lim_send_csa_tx_complete(vdev_id); + else + mlme_legacy_debug("CSAIE_TX_COMPLETE_IND already sent"); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_LL_LT_SAP +QDF_STATUS +wlan_ll_sap_sort_channel_list(uint8_t vdev_id, qdf_list_t *list, + struct sap_sel_ch_info *ch_info) +{ + return wlansap_sort_channel_list(vdev_id, list, ch_info); +} + +void wlan_ll_sap_free_chan_info(struct sap_sel_ch_info *ch_param) +{ + return wlansap_free_chan_info(ch_param); +} + +bool wlan_ll_sap_freq_present_in_pcl(struct policy_mgr_pcl_list *pcl, + qdf_freq_t freq) +{ + uint8_t i; + + for (i = 0; i < pcl->pcl_len; i++) { + if (pcl->pcl_list[i] == freq) + return true; + } + + return false; +} +#endif + +void +wlan_sap_get_user_config_acs_ch_list(uint8_t vdev_id, + struct scan_filter *filter) +{ + wlansap_get_user_config_acs_ch_list(vdev_id, filter); +} + +static struct vdev_mlme_ops sta_mlme_ops = { + .mlme_vdev_start_send = sta_mlme_vdev_start_send, + .mlme_vdev_restart_send = sta_mlme_vdev_restart_send, + .mlme_vdev_start_continue = sta_mlme_start_continue, + .mlme_vdev_start_req_failed = sta_mlme_vdev_start_req_failed, + .mlme_vdev_sta_conn_start = sta_mlme_vdev_start_connection, + .mlme_vdev_up_send = sta_mlme_vdev_up_send, + .mlme_vdev_notify_up_complete = sta_mlme_vdev_notify_up_complete, + .mlme_vdev_notify_roam_start = sta_mlme_vdev_notify_roam_start, + .mlme_vdev_disconnect_peers = sta_mlme_vdev_disconnect_bss, + .mlme_vdev_stop_send = sta_mlme_vdev_stop_send, + .mlme_vdev_stop_continue = vdevmgr_mlme_stop_continue, + .mlme_vdev_down_send = vdevmgr_mlme_vdev_down_send, + .mlme_vdev_notify_down_complete = vdevmgr_notify_down_complete, + .mlme_vdev_ext_stop_rsp = vdevmgr_vdev_stop_rsp_handle, + .mlme_vdev_ext_start_rsp = vdevmgr_vdev_start_rsp_handle, + .mlme_vdev_sta_disconn_start = sta_mlme_vdev_sta_disconnect_start, + .mlme_vdev_ext_peer_delete_all_rsp = + vdevmgr_vdev_peer_delete_all_rsp_handle, +#ifdef WLAN_FEATURE_11BE_MLO + .mlme_vdev_reconfig_notify = + vdevmgr_vdev_reconfig_notify, + .mlme_vdev_reconfig_timer_complete = + vdevmgr_vdev_reconfig_timer_complete, + .mlme_vdev_reconfig_notify_standby = + vdevmgr_vdev_reconfig_notify_standby, + +#endif +}; + +static struct vdev_mlme_ops ap_mlme_ops = { + .mlme_vdev_start_send = ap_mlme_vdev_start_send, + .mlme_vdev_restart_send = ap_mlme_vdev_restart_send, + .mlme_vdev_stop_start_send = ap_mlme_vdev_stop_start_send, + .mlme_vdev_start_continue = ap_mlme_start_continue, + .mlme_vdev_start_req_failed = ap_mlme_vdev_start_req_failed, + .mlme_vdev_up_send = ap_mlme_vdev_up_send, + .mlme_vdev_notify_up_complete = ap_mlme_vdev_notify_up_complete, + .mlme_vdev_update_beacon = ap_mlme_vdev_update_beacon, + .mlme_vdev_disconnect_peers = ap_mlme_vdev_disconnect_peers, + .mlme_vdev_dfs_cac_timer_stop = ap_vdev_dfs_cac_timer_stop, + .mlme_vdev_stop_send = ap_mlme_vdev_stop_send, + .mlme_vdev_stop_continue = vdevmgr_mlme_stop_continue, + .mlme_vdev_down_send = vdevmgr_mlme_vdev_down_send, + .mlme_vdev_notify_down_complete = vdevmgr_notify_down_complete, + .mlme_vdev_is_newchan_no_cac = ap_mlme_vdev_is_newchan_no_cac, + .mlme_vdev_ext_stop_rsp = vdevmgr_vdev_stop_rsp_handle, + .mlme_vdev_ext_start_rsp = vdevmgr_vdev_start_rsp_handle, + .mlme_vdev_ext_peer_delete_all_rsp = + vdevmgr_vdev_peer_delete_all_rsp_handle, + .mlme_vdev_csa_complete = ap_mlme_vdev_csa_complete, +}; + +static struct vdev_mlme_ops mon_mlme_ops = { + .mlme_vdev_start_send = mon_mlme_vdev_start_restart_send, + .mlme_vdev_restart_send = mon_mlme_vdev_start_restart_send, + .mlme_vdev_start_continue = mon_mlme_start_continue, + .mlme_vdev_up_send = mon_mlme_vdev_up_send, + .mlme_vdev_disconnect_peers = mon_mlme_vdev_disconnect_peers, + .mlme_vdev_stop_send = mon_mlme_vdev_stop_send, + .mlme_vdev_down_send = mon_mlme_vdev_down_send, + .mlme_vdev_ext_start_rsp = vdevmgr_vdev_start_rsp_handle, +}; + +static struct mlme_ext_ops ext_ops = { + .mlme_psoc_ext_hdl_create = psoc_mlme_ext_hdl_create, + .mlme_psoc_ext_hdl_destroy = psoc_mlme_ext_hdl_destroy, + .mlme_vdev_ext_hdl_create = vdevmgr_mlme_ext_hdl_create, + .mlme_vdev_ext_hdl_destroy = vdevmgr_mlme_ext_hdl_destroy, + .mlme_vdev_ext_hdl_post_create = vdevmgr_mlme_ext_post_hdl_create, + .mlme_vdev_ext_delete_rsp = vdevmgr_vdev_delete_rsp_handle, + .mlme_cm_ext_hdl_create_cb = cm_ext_hdl_create, + .mlme_cm_ext_hdl_destroy_cb = cm_ext_hdl_destroy, + .mlme_cm_ext_connect_start_ind_cb = cm_connect_start_ind, + .mlme_cm_ext_connect_req_cb = cm_handle_connect_req, + .mlme_cm_ext_bss_peer_create_req_cb = cm_send_bss_peer_create_req, + .mlme_cm_ext_connect_complete_ind_cb = cm_connect_complete_ind, + .mlme_cm_ext_disconnect_start_ind_cb = cm_disconnect_start_ind, + .mlme_cm_ext_disconnect_req_cb = cm_handle_disconnect_req, + .mlme_cm_ext_bss_peer_delete_req_cb = cm_send_bss_peer_delete_req, + .mlme_cm_ext_disconnect_complete_ind_cb = cm_disconnect_complete_ind, + .mlme_cm_ext_vdev_down_req_cb = cm_send_vdev_down_req, + .mlme_cm_ext_reassoc_req_cb = cm_handle_reassoc_req, + .mlme_cm_ext_roam_start_ind_cb = cm_handle_roam_start, + .mlme_psoc_ext_hdl_enable = psoc_mlme_ext_hdl_enable, + .mlme_psoc_ext_hdl_disable = psoc_mlme_ext_hdl_disable, +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE + .mlme_vdev_send_set_mac_addr = vdevmgr_mlme_vdev_send_set_mac_addr, +#endif + .mlme_cm_ext_rso_stop_cb = cm_send_rso_stop, +}; + +#ifdef WLAN_FEATURE_11BE_MLO +static struct mlo_mlme_ext_ops mlo_ext_ops = { + .mlo_mlme_ext_peer_create = lim_mlo_proc_assoc_req_frm, + .mlo_mlme_ext_peer_delete = lim_mlo_cleanup_partner_peer, + .mlo_mlme_ext_peer_assoc_fail = lim_mlo_ap_sta_assoc_fail, + .mlo_mlme_ext_assoc_resp = lim_mlo_ap_sta_assoc_suc, + .mlo_mlme_ext_handle_sta_csa_param = lim_handle_mlo_sta_csa_param, +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme.h new file mode 100644 index 0000000000..2ff42f663e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CFG_MLME_H +#define __CFG_MLME_H + +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" +#include "cfg_mlme_wps_params.h" +#include "cfg_mlme_chainmask.h" +#include "cfg_mlme_edca_params.h" +#include "cfg_mlme_generic.h" +#include "cfg_mlme_acs.h" +#include "cfg_mlme_power.h" +#include "cfg_mlme_ht_caps.h" +#include "cfg_mlme_he_caps.h" +#include "cfg_mlme_lfr.h" +#include "cfg_mlme_obss_ht40.h" +#include "cfg_mlme_dfs.h" +#include "cfg_mlme_mbo.h" +#include "cfg_mlme_dot11mode.h" +#include "cfg_mlme_nss_chains.h" +#include "cfg_mlme_vht_caps.h" +#include "cfg_qos.h" +#include "cfg_mlme_timeout.h" +#include "cfg_mlme_rates.h" +#include "wlan_mlme_product_details_cfg.h" +#include "cfg_mlme_sta.h" +#include "cfg_sap_protection.h" +#include "cfg_mlme_fe_wmm.h" +#include "cfg_mlme_powersave.h" +#include "cfg_mlme_sap.h" +#include "cfg_mlme_stats.h" +#include "cfg_mlme_twt.h" +#include "cfg_mlme_roam_scoring.h" +#include "cfg_mlme_oce.h" +#include "cfg_mlme_threshold.h" +#include "cfg_mlme_feature_flag.h" +#include "cfg_mlme_wep_params.h" +#include "cfg_mlme_wifi_pos.h" +#include "cfg_mlme_btm.h" +#include "cfg_mlme_fe_wlm.h" +#include "cfg_mlme_fe_rrm.h" +#include "cfg_mlme_mwc.h" +#include "cfg_mlme_reg.h" +#include "cfg_mlme_eht_caps.h" +#include "cfg_twt.h" + +/* Please Maintain Alphabetic Order here */ +#define CFG_MLME_ALL \ + CFG_ACS_ALL \ + CFG_BTM_ALL \ + CFG_CHAINMASK_ALL \ + CFG_DFS_ALL \ + CFG_DOT11_MODE_ALL \ + CFG_EDCA_PARAMS_ALL \ + CFG_FE_RRM_ALL \ + CFG_FE_WLM_ALL \ + CFG_FEATURE_FLAG_ALL \ + CFG_GENERIC_ALL \ + CFG_HT_CAPS_ALL \ + CFG_HE_CAPS_ALL \ + CFG_LFR_ALL \ + CFG_MBO_ALL \ + CFG_MLME_POWER_ALL \ + CFG_MLME_PRODUCT_DETAILS_ALL \ + CFG_MWC_ALL \ + CFG_NSS_CHAINS_ALL \ + CFG_OBSS_HT40_ALL \ + CFG_OCE_ALL \ + CFG_POWERSAVE_ALL \ + CFG_QOS_ALL \ + CFG_RATES_ALL \ + CFG_REG_ALL \ + CFG_SAP_ALL \ + CFG_SAP_PROTECTION_ALL \ + CFG_ROAM_SCORING_ALL \ + CFG_STA_ALL \ + CFG_STATS_ALL \ + CFG_THRESHOLD_ALL \ + CFG_TIMEOUT_ALL \ + CFG_TWT_ALL \ + CFG_VHT_CAPS_ALL \ + CFG_WEP_PARAMS_ALL \ + CFG_WIFI_POS_ALL \ + CFG_WMM_PARAMS_ALL\ + CFG_WPS_ALL \ + CFG_EHT_CAPS_ALL + +#endif /* __CFG_MLME_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_acs.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_acs.h new file mode 100644 index 0000000000..fc583c88f6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_acs.h @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_ACS_H +#define __CFG_MLME_ACS_H + +/* + * + * acs_with_more_param- Enable acs calculation with more param. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable acs calculation with more param. + * + * Related: NA + * + * Supported Feature: ACS + * + * Usage: External + * + * + */ + +#define CFG_ACS_WITH_MORE_PARAM CFG_INI_BOOL( \ + "acs_with_more_param", \ + 1, \ + "Enable ACS with more param") + +/* + * + * AutoChannelSelectWeight - ACS channel weight + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 0x00fafafa + * + * This ini is used to adjust weight of factors in + * acs algorithm. + * + * Supported Feature: ACS + * + * Usage: External + * + * bits 0-3: rssi weight + * bits 4-7: bss count weight + * bits 8-11: noise floor weight + * bits 12-15: channel free weight + * bits 16-19: tx power range weight + * bits 20-23: tx power throughput weight + * bits 24-31: reserved + * + * + */ + +#define CFG_AUTO_CHANNEL_SELECT_WEIGHT CFG_INI_UINT( \ + "AutoChannelSelectWeight", \ + 0, \ + 0xFFFFFFFF, \ + 0x00fafafa, \ + CFG_VALUE_OR_DEFAULT, \ + "Adjust weight factor in ACS") + +/* + * + * gvendor_acs_support - vendor based channel selection manager + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Enabling this parameter will force driver to use user application based + * channel selection algo instead of driver based auto channel selection + * logic. + * + * Supported Feature: ACS + * + * Usage: External + * + * + */ + +#define CFG_USER_AUTO_CHANNEL_SELECTION CFG_INI_BOOL( \ + "gvendor_acs_support", \ + 0, \ + "Vendor channel selection manager") + +/* + * + * gacs_support_for_dfs_lte_coex - acs support for lte coex and dfs event + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Enabling this parameter will force driver to use user application based + * channel selection algo for channel selection in case of dfs and lte + * coex event. + * + * Supported Feature: ACS + * + * Usage: Internal + * + * + */ + +#define CFG_USER_ACS_DFS_LTE CFG_INI_BOOL( \ + "gacs_support_for_dfs_lte_coex", \ + 0, \ + "Acs support for lte coex and dfs") + +/* + * + * acs_policy - External ACS policy control + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Values are per enum hdd_external_acs_policy. + * + * This ini is used to control the external ACS policy. + * + * 0 -Preferable for ACS to select a + * channel with non-zero pcl weight. + * 1 -Mandatory for ACS to select a + * channel with non-zero pcl weight. + * + * Related: None + * + * Supported Feature: ACS + * + * Usage: External + * + * + */ + +#define CFG_EXTERNAL_ACS_POLICY CFG_INI_BOOL( \ + "acs_policy", \ + 1, \ + "External ACS Policy Control") + +#define ACS_WEIGHT_MAX_STR_LEN 500 + +/* + * + * normalize_acs_weight - Used to control the ACS channel weightage. + * + * This ini is used to specify the weight percentage of the channel. Channel + * weights can be controlled by user to prioritize or de-prioritize channels. + * + * Related: ACS + * + * Supported Feature: ACS + * + * Usage: External + * + * + */ +#define CFG_NORMALIZE_ACS_WEIGHT CFG_INI_STRING( \ + "normalize_acs_weight", \ + 0, \ + ACS_WEIGHT_MAX_STR_LEN, \ + "2407-5875=40, 5945-7125=90, 5975=100, 6055=100, 6135=100, 6215=100, 6295=100, 6375=100, 6615=100, 6695=100, 6775=100, 6855=100", \ + "Used to specify the channel weights") + +/* + * + * force_start_sap- Enable the SAP even if no channel is suitable for SAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable the SAP even if no channel is found suitable + * for SAP by ACS. + * + * Related: NA + * + * Supported Feature: ACS + * + * Usage: Internal + * + * + */ +#define CFG_ACS_FORCE_START_SAP CFG_INI_BOOL( \ + "force_start_sap", \ + 0, \ + "Force start SAP") + +/* + * + * acs_prefer_6ghz_psc - Select 6 GHz PSC channel as priority + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This config is used to configure ACS logic to select PSC channel as + * perefered result. "normalize_acs_weight" INI can make the PSC + * channel priority higher than NON PSC, but it is for a single channel's + * weight, for bw 160 or bw 80 combined channel weight, it has less + * help. + * + * Related: None + * + * Supported Feature: ACS + * + * Usage: Internal + * + * + */ +#define CFG_ACS_PREFER_6GHZ_PSC CFG_BOOL( \ + "acs_prefer_6ghz_psc", \ + 1, \ + "Select 6 GHz PSC channel as priority") + +/* + * + * np_chan_weight - chan weightage for non preferred channels + * @Min: 0x00000000 + * @Max: 0x64646464 + * @Default: 0x00000000 + * + * This INI give percentage value of weights to be considered in the ACS algo + * for the non preferred channels. the distribution of the channel type is:- + * Example:- If the percentage of lets say DFS channels is set to 50%, and + * the weight comes out to be x, then we would increase the weight of DFS + * channels by 50% ( 100 - y% set in INI), so that it gets de-prioritized in + * the ACS sorted channel list, the lesser the weight, the better the channel. + * So the channel with more weight is less likely to be selected. So by default + * the np chan weightage for DFS is set to 0, that is it will be assigned max + * weightage, so no probality of getting selected, as for standlaone, DFS is not + * recommended (it takes 60 sec/10min to start depending upon channel type). + * + * Indexes are defined in this way. + * 0 Index (BITS 0-7): DFS - Def 1% + * 1 Index (BITS 8-15): Reserved + * 2 Index (BITS 16-23): Reserved + * 3 Index (BITS 24-31): Reserved + * These percentage values are stored in HEX. Max can be 0x64 + * Supported Feature: ACS + * + * Usage: External + * + * + */ +#define CFG_ACS_NP_CHAN_WEIGHT CFG_INI_UINT( \ + "np_chan_weight", \ + 0x00000000, \ + 0x64646464, \ + 0x00000001, \ + CFG_VALUE_OR_DEFAULT, \ + "np chan weight") + +#define CFG_ACS_ALL \ + CFG(CFG_ACS_WITH_MORE_PARAM) \ + CFG(CFG_AUTO_CHANNEL_SELECT_WEIGHT) \ + CFG(CFG_USER_AUTO_CHANNEL_SELECTION) \ + CFG(CFG_USER_ACS_DFS_LTE) \ + CFG(CFG_EXTERNAL_ACS_POLICY) \ + CFG(CFG_NORMALIZE_ACS_WEIGHT) \ + CFG(CFG_ACS_PREFER_6GHZ_PSC) \ + CFG(CFG_ACS_FORCE_START_SAP) \ + CFG(CFG_ACS_NP_CHAN_WEIGHT) + +#endif /* __CFG_MLME_ACS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_btm.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_btm.h new file mode 100644 index 0000000000..310132178a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_btm.h @@ -0,0 +1,327 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains MLME BTM related CFG/INI Items. + */ + +#ifndef CFG_MLME_BTM_H_ +#define CFG_MLME_BTM_H_ + +/* + * + * prefer_btm_query - Prefer btm query over 11k neighbor report + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable the STA to send BTM query instead of + * 11k neighbor report. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_PREFER_BTM_QUERY CFG_INI_BOOL( \ + "prefer_btm_query", \ + 1, \ + "prefer btm query over 11k neighbor report") + +/* + * + * prefer_roam_score_for_candidate_selection - choose to sort the candidates on + * roam score or preferred AP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable the the firmware to sort the candidates + * based on the roam score rather than selecting APs as per the order + * of the APs sent by the connected AP. + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ENABLE_BTM_ABRIDGE CFG_INI_BOOL( \ + "prefer_roam_score_for_candidate_selection", \ + 1, \ + "sort candidate based on roam score") + +/* + * + * btm_offload_config - Configure BTM + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x000001c1 + * + * This ini is used to configure BTM + * + * Bit 0: Enable/Disable the BTM offload. Set this to 1 will + * enable and 0 will disable BTM offload. + * + * BIT 2, 1: Action on non matching candidate with cache. If a BTM request + * is received from AP then the candidate AP's may/may-not be present in + * the firmware scan cache . Based on below config firmware will decide + * whether to forward BTM frame to host or consume with firmware and proceed + * with Roaming to candidate AP. + * 00 scan and consume + * 01 no scan and forward to host + * 10, 11 reserved + * + * BIT 5, 4, 3: Roaming handoff decisions on multiple candidates match + * for unsolicited BTM request. + * 000 match if exact BSSIDs are found + * 001 match if at least one top priority BSSID only + * 010, 011, 100, 101, 110, 111 reserved + * In case of solicited request intersection of Roam cache/candidates + * with candidates in BTM request is taken into consideration. + * + * BIT 6: Set this to 1 will send BTM query frame and 0 not sent. + * + * BIT 7: Roam BTM candidates based on the roam score instead of BTM preferred + * value + * + * BIT 8: BTM query preference over 11k neighbor report request + * + * BIT 9: BTM query with candidate list + * + * BIT 10: When this bit is set, Firmware will forward BTM Request Frame to + * driver when the frame contains MBO assoc retry attribute. Driver will send + * this frame to supplicant and supplicant will use the frame info for + * denylisting the AP so for the next connection framework will avoid this AP. + * + * BIT 11-31: Reserved + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_ENABLE CFG_INI_UINT( \ + "btm_offload_config", \ + 0x00000000, \ + 0xffffffff, \ + 0x000001c1, \ + CFG_VALUE_OR_DEFAULT, \ + "configure btm offload") + +/* + * + * btm_solicited_timeout - timeout value for waiting BTM request + * @Min: 1 + * @Max: 10000 + * @Default: 100 + * + * This ini is used to configure timeout value for waiting BTM request. + * Unit: millionsecond + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_SOLICITED_TIMEOUT CFG_INI_UINT( \ + "btm_solicited_timeout", \ + 1, \ + 10000, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "configure timeout value for waiting BTM request") + +/* + * + * btm_max_attempt_cnt - Maximum attempt for sending BTM query to ESS + * @Min: 1 + * @Max: 0xFFFFFFFF + * @Default: 3 + * + * This ini is used to configure maximum attempt for sending BTM query to ESS. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_MAX_ATTEMPT_CNT CFG_INI_UINT( \ + "btm_max_attempt_cnt", \ + 1, \ + 0xFFFFFFFF, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "configure maximum attempt for sending BTM query to ESS") + +/* + * + * btm_sticky_time - Stick time after roaming to new AP by BTM + * @Min: 0 + * @Max: 0x0000FFFF + * @Default: 0 + * + * This ini is used to configure Stick time after roaming to new AP by BTM. + * Unit: seconds + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_BTM_STICKY_TIME CFG_INI_UINT( \ + "btm_sticky_time", \ + 0, \ + 0x0000FFFF, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "configure Stick time after roaming to new AP by BTM") + +/* + * + * roam_candidate_validity_timer - roam cache entries validity timer + * @Min: 0 + * @Max: 0xffffffff + * @Default: 0xffffffff + * + * This value is the timeout values for the cached roam candidate + * entries in firmware. If this value is 0, then that entry is not + * valid + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_BTM_VALIDITY_TIMER CFG_INI_UINT( \ + "roam_candidate_validity_timer", \ + 0, \ + 0xffffffff, \ + 0xffffffff, \ + CFG_VALUE_OR_DEFAULT, \ + "BTM validity timer") + +/* + * + * btm_disassoc_timer_threshold - Disassociation timer threshold to wait + * after which the full scan for roaming can be started after the AP has sent + * the disassoc imminent + * @Min: 0 + * @Max: 0xffffffff + * @Default: 10000 + * + * When AP sends, BTM request with disassoc imminent bit set, the STA should + * roam to a new AP within the disassc timeout provided by the ap. If the Roam + * scan period is less than the disassoc timeout value, then instead of + * triggering the roam scan immediately, STA can wait for this + * btm_disassoc_timer_threshold and then start roaming. + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_BTM_DISASSOC_TIMER_THRESHOLD CFG_INI_UINT( \ + "btm_disassoc_timer_threshold", \ + 0, \ + 0xffffffff, \ + 10000, \ + CFG_VALUE_OR_DEFAULT, \ + "BTM disassociation timer threshold") + +/* + * + * btm_query_bitmask - To send BTM query with candidate list on various roam + * scans reasons + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 0x8 + * + * This new ini is introduced to configure the bitmask for various roam scan + * reasons. Fw sends "BTM query with preferred candidate list" only for those + * roam scans which are enable through this bitmask. + + * For Example: + * Bitmask : 0x8 (LOW_RSSI) refer enum WMI_ROAM_TRIGGER_REASON_ID + * Bitmask : 0xDA (PER, LOW_RSSI, HIGH_RSSI, MAWC, DENSE) + * refer enum WMI_ROAM_TRIGGER_REASON_ID + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_BTM_QUERY_BITMASK CFG_INI_UINT( \ + "btm_query_bitmask", \ + 0, \ + 0xFFFFFFFF, \ + 0x8, \ + CFG_VALUE_OR_DEFAULT, \ + "btm query with candidate list bitmask") + +/* + * + * minimum_btm_candidate_score - Consider the AP as roam candidate only if + * its score is greater than minimum_btm_candidate_score. + * @Min: 0 + * @Max: 10000 + * @Default: 2600 + * + * This ini is applicable only for candidate selection during BTM roam trigger. + * For this roam_score_delta_bitmap bit 10 should be set to 1. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_MIN_BTM_CANDIDATE_SCORE CFG_INI_UINT( \ + "minimum_btm_candidate_score", \ + 0, \ + 10000, \ + 2600, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum BTM candidate score") + +#define CFG_BTM_ALL \ + CFG(CFG_PREFER_BTM_QUERY) \ + CFG(CFG_ENABLE_BTM_ABRIDGE) \ + CFG(CFG_BTM_ENABLE) \ + CFG(CFG_BTM_SOLICITED_TIMEOUT) \ + CFG(CFG_BTM_MAX_ATTEMPT_CNT) \ + CFG(CFG_BTM_STICKY_TIME) \ + CFG(CFG_BTM_VALIDITY_TIMER) \ + CFG(CFG_BTM_DISASSOC_TIMER_THRESHOLD) \ + CFG(CFG_BTM_QUERY_BITMASK) \ + CFG(CFG_MIN_BTM_CANDIDATE_SCORE) + +#endif /* CFG_MLME_BTM_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_chainmask.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_chainmask.h new file mode 100644 index 0000000000..1778f42e54 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_chainmask.h @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2012-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_CHAINMASK_H +#define __CFG_CHAINMASK_H + +/* + * + * gSetTxChainmask1x1 - Sets Transmit chain mask. + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This ini Sets Transmit chain mask. + * + * If gEnable2x2 is disabled, gSetTxChainmask1x1 and gSetRxChainmask1x1 values + * are taken into account. If chainmask value exceeds the maximum number of + * chains supported by target, the max number of chains is used. By default, + * chain0 is selected for both Tx and Rx. + * gSetTxChainmask1x1=1 or gSetRxChainmask1x1=1 to select chain0. + * gSetTxChainmask1x1=2 or gSetRxChainmask1x1=2 to select chain1. + * gSetTxChainmask1x1=3 or gSetRxChainmask1x1=3 to select both chains. + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_1x1_TX_CHAINMASK CFG_INI_UINT( \ + "gSetTxChainmask1x1", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "1x1 VHT Tx Chainmask") + +/* + * + * gSetRxChainmask1x1 - Sets Receive chain mask. + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This ini is used to set Receive chain mask. + * + * If gEnable2x2 is disabled, gSetTxChainmask1x1 and gSetRxChainmask1x1 values + * are taken into account. If chainmask value exceeds the maximum number of + * chains supported by target, the max number of chains is used. By default, + * chain0 is selected for both Tx and Rx. + * gSetTxChainmask1x1=1 or gSetRxChainmask1x1=1 to select chain0. + * gSetTxChainmask1x1=2 or gSetRxChainmask1x1=2 to select chain1. + * gSetTxChainmask1x1=3 or gSetRxChainmask1x1=3 to select both chains. + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_1x1_RX_CHAINMASK CFG_INI_UINT( \ + "gSetRxChainmask1x1", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "1x1 VHT Rx Chainmask") + +/* + * + * gCckChainMaskEnable - Used to enable/disable Cck ChainMask + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default Cck ChainMask + * 0: disable the cck tx chain mask (default) + * 1: enable the cck tx chain mask + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_TX_CHAIN_MASK_CCK CFG_INI_BOOL( \ + "gCckChainMaskEnable", \ + 0, \ + "Set default CCK Tx Chainmask") + +/* + * + * gTxChainMask1ss - Enables/disables tx chain mask1ss, used by Rome + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to set default tx chain mask for 1ss + * + * gTxChainMask1ss=0 : 1ss data tx chain mask set to 3 and self gen chain mask + * set to 3. This is default setting of fw side. For 1x1 case, WIFI will + * using chain0 to sent 1ss data and selfgen packets. 2x2 case, WIFI will + * using chain0 and chain1 to sent 1ss data and selfgen packets. + * + * gTxChainMask1ss=1 : 1ss data tx chain mask set to 2 and self gen chain mask + * set to 2. This setting can work only when 2x2 case, WIFI will use chain1 + * to sent 1ss data packets and selfgen packets, this can improve BTC + * performance a little, but have side affect when chain0 and chain1 RSSI + * is unbalance or green AP is enabled. So we recommend not using it. + * + * gTxChainMask1ss=2 : 1ss data tx chain mask set to 3 and self gen chain mask + * set to 2. This setting never used before. + * + * gTxChainMask1ss=3 : 1ss data tx chain mask set to 2 and self gen chain mask + * set to 3. This setting never used before. + * + * Related: None + * + * Supported Feature: STA/SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_TX_CHAIN_MASK_1SS CFG_INI_UINT( \ + "gTxChainMask1ss", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "1SS Tx Chainmask") + +/* + * + * g11bNumTxChains - Number of Tx Chanins in 11b mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * Number of Tx Chanins in 11b mode + * + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_11B_NUM_TX_CHAIN CFG_INI_UINT( \ + "g11bNumTxChains", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "11b Num Tx chains") + +/* + * + * g11agNumTxChains - Number of Tx Chanins in 11ag mode + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * Number of Tx Chanins in 11ag mode + * + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_11AG_NUM_TX_CHAIN CFG_INI_UINT( \ + "g11agNumTxChains", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "11ag Num Tx chains") + +/* + * + * tx_chain_mask_2g - tx chain mask for 2g + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini will set tx chain mask for 2g. To use the ini, make sure: + * gSetTxChainmask1x1/gSetRxChainmask1x1 = 0, + * gDualMacFeatureDisable = 1 + * gEnable2x2 = 0 + * + * tx_chain_mask_2g=0 : don't care + * tx_chain_mask_2g=1 : for 2g tx use chain 0 + * tx_chain_mask_2g=2 : for 2g tx use chain 1 + * tx_chain_mask_2g=3 : for 2g tx can use either chain + * + * QCN7605 DBS chip has 3 RF chains. + * Chain0 for 2G, Chain1 for 2G/5G, Chain2 for 5G. + * DBS mode need 3 bits to map chainmask and halphy. + * In HW design, PHYA0 always Connects to shared RF chain1. + * tx_chain_mask_2g=4 : for 2g tx chain use PHYB and chain 0 + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_TX_CHAIN_MASK_2G CFG_INI_UINT( \ + "tx_chain_mask_2g", \ + 0, \ + 4, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "2.4G Tx Chainmask") + +/* + * + * rx_chain_mask_2g - rx chain mask for 2g + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * This ini will set rx chain mask for 2g. To use the ini, make sure: + * gSetTxChainmask1x1/gSetRxChainmask1x1 = 0, + * gDualMacFeatureDisable = 1 + * gEnable2x2 = 0 + * + * rx_chain_mask_2g=0 : don't care + * rx_chain_mask_2g=1 : for 2g rx use chain 0 + * rx_chain_mask_2g=2 : for 2g rx use chain 1 + * rx_chain_mask_2g=3 : for 2g rx can use either chain + * + * QCN7605 DBS chip has 3 RF chains. + * Chain0 for 2G, Chain1 for 2G/5G, Chain2 for 5G. + * DBS mode need 3 bits to map chainmask and halphy. + * In HW design, PHYA0 always Connects to shared RF chain1. + * rx_chain_mask_2g=4 : for 2g rx chain use PHYB and chain 0 + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_RX_CHAIN_MASK_2G CFG_INI_UINT( \ + "rx_chain_mask_2g", \ + 0, \ + 4, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "2.4G Rx Chainmask") + +/* + * + * tx_chain_mask_5g - tx chain mask for 5g + * @Min: 0 + * @Max: 6 + * @Default: 0 + * + * This ini will set tx chain mask for 5g. To use the ini, make sure: + * gSetTxChainmask1x1/gSetRxChainmask1x1 = 0, + * gDualMacFeatureDisable = 1 + * gEnable2x2 = 0 + * + * tx_chain_mask_5g=0 : don't care + * tx_chain_mask_5g=1 : for 5g tx use chain 0, Genoa use chain 1 + * tx_chain_mask_5g=2 : for 5g tx use chain 1, Genoa use chain 2 + * tx_chain_mask_5g=3 : for 5g tx can use either chain + * + * QCN7605 DBS chip has 3 RF chains. + * Chain0 for 2G, Chain1 for 2G/5G, Chain2 for 5G. + * DBS mode need 3 bits to map chainmask and halphy. + * In HW design, PHYA0 always Connects to shared RF chain1. + * tx_chain_mask_5g=4 : for 5g tx chain use PHYB and chain 2 + * tx_chain_mask_5g=5 : for 5g tx chain use PHYA and chain 1 + * tx_chain_mask_5g=6 : for 5g tx chain use PHYA and chain 2 + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_TX_CHAIN_MASK_5G CFG_INI_UINT( \ + "tx_chain_mask_5g", \ + 0, \ + 6, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "5Ghz Tx Chainmask") + +/* + * + * rx_chain_mask_5g - rx chain mask for 5g + * @Min: 0 + * @Max: 6 + * @Default: 0 + * + * This ini will set rx chain mask for 5g. To use the ini, make sure: + * gSetTxChainmask1x1/gSetRxChainmask1x1 = 0, + * gDualMacFeatureDisable = 1 + * gEnable2x2 = 0 + * + * rx_chain_mask_5g=0 : don't care + * rx_chain_mask_5g=1 : for 5g rx use chain 0, Genoa use chain 1 + * rx_chain_mask_5g=2 : for 5g rx use chain 1, Genoa use chain 2 + * rx_chain_mask_5g=3 : for 5g rx can use either chain + * + * QCN7605 DBS chip has 3 RF chains. + * Chain0 for 2G, Chain1 for 2G/5G, Chain2 for 5G. + * DBS mode need 3 bits to map halphy and chain. + * HW design, PHYA0 always Connects to shared RF chain1. + * rx_chain_mask_5g=4 : for 5g rx chain use PHYB and chain 2 + * rx_chain_mask_5g=5 : for 5g rx chain use PHYA and chain 1 + * rx_chain_mask_5g=6 : for 5g rx chain use PHYB and chain 2 + * + * Related: None + * + * Supported Feature: All profiles + * + * Usage: External + * + * + */ +#define CFG_RX_CHAIN_MASK_5G CFG_INI_UINT( \ + "rx_chain_mask_5g", \ + 0, \ + 6, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "5Ghz Rx Chainmask") + +/* + * + * enable_bt_chain_separation - Enables/disables bt /wlan chainmask assignment + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini disables/enables chainmask setting on 2x2, mainly used for ROME + * BT/WLAN chainmask assignment. + * + * 0, Disable + * 1, Enable + * + * Related: NA + * + * Supported Feature: 11n/11ac + * + * Usage: External + * + * + */ +#define CFG_ENABLE_BT_CHAIN_SEPARATION CFG_INI_BOOL( \ + "enableBTChainSeparation", \ + 0, \ + "Enable/disable BT chainmask assignment") + +#define CFG_CHAINMASK_ALL \ + CFG(CFG_VHT_ENABLE_1x1_TX_CHAINMASK) \ + CFG(CFG_VHT_ENABLE_1x1_RX_CHAINMASK) \ + CFG(CFG_TX_CHAIN_MASK_CCK) \ + CFG(CFG_TX_CHAIN_MASK_1SS) \ + CFG(CFG_11B_NUM_TX_CHAIN) \ + CFG(CFG_11AG_NUM_TX_CHAIN) \ + CFG(CFG_TX_CHAIN_MASK_2G) \ + CFG(CFG_RX_CHAIN_MASK_2G) \ + CFG(CFG_TX_CHAIN_MASK_5G) \ + CFG(CFG_RX_CHAIN_MASK_5G) \ + CFG(CFG_ENABLE_BT_CHAIN_SEPARATION) + +#endif /* __CFG_CHAINMASK_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_dfs.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_dfs.h new file mode 100644 index 0000000000..0699cd2faa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_dfs.h @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_DFS_H +#define __CFG_MLME_DFS_H + +/* + * + * gsap_tx_leakage_threshold - sap tx leakage threshold + * @Min: 100 + * @Max: 1000 + * @Default: 310 + * + * customer can set this value from 100 to 1000 which means + * sap tx leakage threshold is -10db to -100db + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_SAP_TX_LEAKAGE_THRESHOLD CFG_INI_UINT( \ + "gsap_tx_leakage_threshold", \ + 100, \ + 1000, \ + 310, \ + CFG_VALUE_OR_DEFAULT, \ + "sap tx leakage threshold") + +/* + * + * gDFSradarMappingPriMultiplier - dfs pri multiplier + * @Min: 1 + * @Max: 10 + * @Default: 2 + * + * customer can set this value from 1 to 10 which means + * host could handle missing pulses while there is high + * channel loading, for example: 30% ETSI and 50% Japan W53 + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_DFS_RADAR_PRI_MULTIPLIER CFG_INI_UINT( \ + "gDFSradarMappingPriMultiplier", \ + 1, \ + 10, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "dfs pri multiplier") + +/* + * + * gDfsBeaconTxEnhanced - beacon tx enhanced + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enhance dfs beacon tx + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_DFS_BEACON_TX_ENHANCED CFG_INI_BOOL( \ + "gDfsBeaconTxEnhanced", \ + 0, \ + "beacon tx enhanced") + +/* + * + * gPreferNonDfsChanOnRadar - During random channel selection prefer non dfs + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * During random channel selection prefer non dfs. + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_ENABLE_NON_DFS_CHAN_ON_RADAR CFG_INI_BOOL( \ + "gPreferNonDfsChanOnRadar", \ + 0, \ + "channel selection prefer non dfs") + +/* + * + * dfsPhyerrFilterOffload - Enable dfs phyerror filtering offload in FW + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to to enable dfs phyerror filtering offload to firmware + * Enabling it will cause basic phy error to be discarding in firmware. + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD CFG_INI_BOOL( \ + "dfsPhyerrFilterOffload", \ + 0, \ + "dfs phyerror filtering offload") + +/* + * + * gIgnoreCAC - Used to ignore CAC + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default CAC + * + * Related: None + * + * Supported Feature: DFS + * + * Usage: External + * + * + */ +#define CFG_IGNORE_CAC CFG_INI_BOOL( \ + "gIgnoreCAC", \ + 0, \ + "ignore CAC on DFS channel") + +/* + * + * gDisableDFSChSwitch - Disable channel switch if radar is found + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disable channel switch if radar is found + * on that channel. + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal + * + * + */ +#define CFG_DISABLE_DFS_CH_SWITCH CFG_INI_BOOL( \ + "gDisableDFSChSwitch", \ + 0, \ + "Disable channel switch on radar") + +/* + * + * gEnableDFSMasterCap - Enable DFS master capability + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the DFS master capability. + * Disabling it will cause driver to not advertise the spectrum + * management capability + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DFS_MASTER_CAPABILITY CFG_INI_BOOL( \ + "gEnableDFSMasterCap", \ + 0, \ + "DFS master mode capability") + +/* + * + * gDisableDfsJapanW53 - Block W53 channels in random channel selection + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to block W53 Japan channel in random channel selection + * + * Related: none + * + * Supported Feature: DFS + * + * Usage: External + * + * + */ +#define CFG_DISABLE_DFS_JAPAN_W53 CFG_INI_BOOL( \ + "gDisableDfsJapanW53", \ + 0, \ + "Block W53 channels in random selection") + +#define CFG_DFS_ALL \ + CFG(CFG_IGNORE_CAC) \ + CFG(CFG_DISABLE_DFS_CH_SWITCH) \ + CFG(CFG_DFS_BEACON_TX_ENHANCED) \ + CFG(CFG_SAP_TX_LEAKAGE_THRESHOLD) \ + CFG(CFG_DFS_RADAR_PRI_MULTIPLIER) \ + CFG(CFG_ENABLE_NON_DFS_CHAN_ON_RADAR) \ + CFG(CFG_ENABLE_DFS_MASTER_CAPABILITY) \ + CFG(CFG_DISABLE_DFS_JAPAN_W53) \ + CFG(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD) + +#endif /* __CFG_MLME_DFS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_dot11mode.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_dot11mode.h new file mode 100644 index 0000000000..fad8e6357a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_dot11mode.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_DOT11MODE_H +#define __CFG_MLME_DOT11MODE_H + +#define CFG_DOT11_MODE CFG_UINT( \ + "dot11_mode", \ + 0, \ + 10, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "dot 11 mode") + +/* + * + * vdev_dot11_mode- Bit mask to set the dot11 mode for different vdev types + * @Min: 0x0 + * @Max: 0x333333 + * @Default: 0 + * + * This ini is used to set the dot11mode different vdev types. + * dot11_mode ini value (CFG_DOT11_MODE) is the master configuration + * Min configuration of INI dot11_mode and vdev_dot11_mode is used for that + * vdev type. + * dot11_mode vdev_dot11_mode dot11_mode_used + * 11AX 11AC 11AC + * 11AC 11AX 11AC + * + * Dot11 mode value is 4 bit length for each vdev. Below is the bit definition + * for different vdev types dot11 mode value bit index. + * + * Bits used for dot11mode Vdev Type + * BIT[3:0] STA mode + * BIT[7:4] P2P_CLI/P2P_DEVICE mode + * BIT[11:8] NAN DISCOVERY + * BIT[15:12] OCB + * BIT[19:16] TDLS + * BIT[23:20] NDI mode + * + * Dot11 mode value to be set in the above bit definition: + * 0 - Auto, Uses CFG_DOT11_MODE setting + * 1 - HT mode(11N) + * 2 - VHT mode(11AC) + * 3 - HE mode(11AX) + * + * E.g: vdev_dot11_mode=0x013220 + * + * 0 1 3 2 2 0 + * NDI(auto) TDLS HT OCB_HE VHT NAN_DISC VHT P2P STA_AUTO + * + * Usage: Internal/External + * + * + */ +#define CFG_VDEV_DOT11_MODE CFG_INI_UINT( \ + "vdev_dot11_mode", \ + 0, \ + 0x333333, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "vdev dot 11 mode") + +#define CFG_DOT11_MODE_ALL \ + CFG(CFG_DOT11_MODE) \ + CFG(CFG_VDEV_DOT11_MODE) \ + +#endif /* __CFG_MLME_DOT11MODE_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_edca_params.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_edca_params.h new file mode 100644 index 0000000000..2b2b26e540 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_edca_params.h @@ -0,0 +1,897 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_EDCA__PARAM_H +#define __CFG_MLME_EDCA__PARAM_H + +#define STR_EDCA_ANI_ACBK_LOCAL "0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_ANI_ACBK_LOCAL_LEN (sizeof(STR_EDCA_ANI_ACBK_LOCAL) - 1) + +#define CFG_EDCA_ANI_ACBK_LOCAL CFG_INI_STRING( \ + "edca_ani_acbk_local", \ + 0, \ + STR_EDCA_ANI_ACBK_LOCAL_LEN, \ + STR_EDCA_ANI_ACBK_LOCAL, \ + "EDCA ANI ACBK LOCAL") + +#define STR_EDCA_ANI_ACBE_LOCAL "0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, 0xf, 0x3, 0xff, 0x64" +#define STR_EDCA_ANI_ACBE_LOCAL_LEN (sizeof(STR_EDCA_ANI_ACBE_LOCAL) - 1) + +#define CFG_EDCA_ANI_ACBE_LOCAL CFG_INI_STRING( \ + "edca_ani_acbe_local", \ + 0, \ + STR_EDCA_ANI_ACBE_LOCAL_LEN, \ + STR_EDCA_ANI_ACBE_LOCAL, \ + "EDCA ANI ACBE LOCAL") + +#define STR_EDCA_ANI_ACVI_LOCAL "0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, 0xbc, 0x0, 0x7, 0x0, 0xf, 0xc8" +#define STR_EDCA_ANI_ACVI_LOCAL_LEN (sizeof(STR_EDCA_ANI_ACVI_LOCAL) - 1) + +#define CFG_EDCA_ANI_ACVI_LOCAL CFG_INI_STRING( \ + "edca_ani_acvi_local",\ + 0, \ + STR_EDCA_ANI_ACVI_LOCAL_LEN, \ + STR_EDCA_ANI_ACVI_LOCAL, \ + "EDCA ANI ACVI LOCAL") + +#define STR_EDCA_ANI_ACVO_LOCAL "0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, 0x3, 0x0, 0x7, 0x64" +#define STR_EDCA_ANI_ACVO_LOCAL_LEN (sizeof(STR_EDCA_ANI_ACVO_LOCAL) - 1) + +#define CFG_EDCA_ANI_ACVO_LOCAL CFG_INI_STRING( \ + "edca_ani_acvo_local", \ + 0, \ + STR_EDCA_ANI_ACVO_LOCAL_LEN, \ + STR_EDCA_ANI_ACVO_LOCAL, \ + "EDCA ANI ACVO LOCAL") + +#define STR_EDCA_ANI_ACBK "0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_ANI_ACBK_LEN (sizeof(STR_EDCA_ANI_ACBK) - 1) + +#define CFG_EDCA_ANI_ACBK CFG_INI_STRING( \ + "edca_ani_acbk", \ + 0, \ + STR_EDCA_ANI_ACBK_LEN, \ + STR_EDCA_ANI_ACBK, \ + "EDCA ANI ACBK BROADCAST") + +#define STR_EDCA_ANI_ACBE "0x0, 0x2, 0x0, 0xf, 0x3, 0xff, 0x64, 0x0, 0x1f, 0x3, 0xff, 0x64, 0x0, 0xf, 0x3, 0xff, 0x64" +#define STR_EDCA_ANI_ACBE_LEN (sizeof(STR_EDCA_ANI_ACBE) - 1) + +#define CFG_EDCA_ANI_ACBE CFG_INI_STRING( \ + "edca_ani_acbe", \ + 0, \ + STR_EDCA_ANI_ACBE_LEN, \ + STR_EDCA_ANI_ACBE, \ + "EDCA ANI ACBE BROADCAST") + +#define STR_EDCA_ANI_ACVI "0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0xc8, 0x0, 0xf, 0x0, 0x1f, 0xbc, 0x0, 0x7, 0x0, 0xf, 0xc8" +#define STR_EDCA_ANI_ACVI_LEN (sizeof(STR_EDCA_ANI_ACVI) - 1) + +#define CFG_EDCA_ANI_ACVI CFG_INI_STRING( \ + "edca_ani_acvi", \ + 0, \ + STR_EDCA_ANI_ACVI_LEN, \ + STR_EDCA_ANI_ACVI, \ + "EDCA ANI ACVI BROADCAST") + +#define STR_EDCA_ANI_ACVO "0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x64, 0x0, 0x7, 0x0, 0xf, 0x66, 0x0, 0x3, 0x0, 0x7, 0x64" +#define STR_EDCA_ANI_ACVO_LEN (sizeof(STR_EDCA_ANI_ACVO) - 1) + +#define CFG_EDCA_ANI_ACVO CFG_INI_STRING( \ + "edca_ani_acvo", \ + 0, \ + STR_EDCA_ANI_ACVO_LEN, \ + STR_EDCA_ANI_ACVO, \ + "EDCA ANI ACVO BROADCAST") + +#define STR_EDCA_WME_ACBK_LOCAL "0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_WME_ACBK_LOCAL_LEN (sizeof(STR_EDCA_WME_ACBK_LOCAL) - 1) + +/* + * + * edca_wme_acbk_local - Set EDCA parameters for WME local AC BK + * @Default: 0x0,0x7,0x0,0xf,0x3,0xff,0x0,0x0,0x1f,0x3,0xff,0x0,0x0,0xf,0x3, + * 0xff,0x0 + * + * This ini is used to set EDCA parameters for WME AC BK that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_WME_ACBK_LOCAL CFG_INI_STRING( \ + "edca_wme_acbk_local", \ + 0, \ + STR_EDCA_WME_ACBK_LOCAL_LEN, \ + STR_EDCA_WME_ACBK_LOCAL, \ + "EDCA WME ACBK LOCAL") + +#define STR_EDCA_WME_ACBE_LOCAL "0x0, 0x3, 0x0, 0xf, 0x0, 0x3f, 0x0, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, 0xf, 0x0, 0x3f, 0x0" +#define STR_EDCA_WME_ACBE_LOCAL_LEN (sizeof(STR_EDCA_WME_ACBE_LOCAL) - 1) + +/* + * + * edca_wme_acbe_local - Set EDCA parameters for WME local AC BE + * @Default: 0x0,0x3,0x0,0xf,0x0,0x3f,0x0,0x0,0x1f,0x3,0xff,0x0,0x0,0xf,0x0, + * 0x3f,0x0 + * + * This ini is used to set EDCA parameters for WME AC BE that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_WME_ACBE_LOCAL CFG_INI_STRING( \ + "edca_wme_acbe_local", \ + 0, \ + STR_EDCA_WME_ACBE_LOCAL_LEN, \ + STR_EDCA_WME_ACBE_LOCAL, \ + "EDCA WME ACBE LOCAL") + +#define STR_EDCA_WME_ACVI_LOCAL "0x0, 0x1, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, 0x0, 0xf, 0x5e" +#define STR_EDCA_WME_ACVI_LOCAL_LEN (sizeof(STR_EDCA_WME_ACVI_LOCAL) - 1) + +/* + * + * edca_wme_acvi_local - Set EDCA parameters for WME AC VI + * @Default: 0x0,0x1,0x0,0x7,0x0,0xf,0x5e,0x0,0x7,0x0,0xf,0xbc,0x0,0x7,0x0,0xf, + * 0x5e + * + * This ini is used to set EDCA parameters for WME AC VI that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_WME_ACVI_LOCAL CFG_INI_STRING( \ + "edca_wme_acvi_local", \ + 0, \ + STR_EDCA_WME_ACVI_LOCAL_LEN, \ + STR_EDCA_WME_ACVI_LOCAL, \ + "EDCA WME ACVI LOCAL") + +#define STR_EDCA_WME_ACVO_LOCAL "0x0, 0x1, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, 0x0, 0x7, 0x2f" +#define STR_EDCA_WME_ACVO_LOCAL_LEN (sizeof(STR_EDCA_WME_ACVO_LOCAL) - 1) + +/* + * + * edca_wme_acvo_local - Set EDCA parameters for WME AC VO + * @Default: 0x0,0x1,0x0,0x3,0x0,0x7,0x2f,0x0,0x3,0x0,0x7,0x66,0x0,0x3,0x0,0x7, + * 0x2f + * + * This ini is used to set EDCA parameters for WME AC VO that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_WME_ACVO_LOCAL CFG_INI_STRING( \ + "edca_wme_acvo_local", \ + 0, \ + STR_EDCA_WME_ACVO_LOCAL_LEN, \ + STR_EDCA_WME_ACVO_LOCAL, \ + "EDCA WME ACVO LOCAL") + +#define STR_EDCA_WME_ACBK "0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_WME_ACBK_LEN (sizeof(STR_EDCA_WME_ACBK) - 1) + +#define CFG_EDCA_WME_ACBK CFG_INI_STRING( \ + "edca_wme_acbk", \ + 0, \ + STR_EDCA_WME_ACBK_LEN, \ + STR_EDCA_WME_ACBK, \ + "EDCA WME ACBK BROADCAST") + +#define STR_EDCA_WME_ACBE "0x0, 0x3, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_WME_ACBE_LEN (sizeof(STR_EDCA_WME_ACBE) - 1) + +#define CFG_EDCA_WME_ACBE CFG_INI_STRING( \ + "edca_wme_acbe", \ + 0, \ + STR_EDCA_WME_ACBE_LEN, \ + STR_EDCA_WME_ACBE, \ + "EDCA WME ACBE BROADCAST") + +#define STR_EDCA_WME_ACVI "0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0x5e, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, 0x0, 0xf, 0x5e" +#define STR_EDCA_WME_ACVI_LEN (sizeof(STR_EDCA_WME_ACVI) - 1) + +#define CFG_EDCA_WME_ACVI CFG_INI_STRING( \ + "edca_wme_acvi", \ + 0, \ + STR_EDCA_WME_ACVI_LEN, \ + STR_EDCA_WME_ACVI, \ + "EDCA WME ACVI BROADCAST") + +#define STR_EDCA_WME_ACVO "0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x2f, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, 0x0, 0x7, 0x2f" +#define STR_EDCA_WME_ACVO_LEN (sizeof(STR_EDCA_WME_ACVO) - 1) + +#define CFG_EDCA_WME_ACVO CFG_INI_STRING( \ + "edca_wme_acvo", \ + 0, \ + STR_EDCA_WME_ACVO_LEN, \ + STR_EDCA_WME_ACVO, \ + "EDCA WME ACVO BROADCAST") + +#define STR_EDCA_ETSI_ACBK_LOCAL "0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0xbb, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_ETSI_ACBK_LOCAL_LEN (sizeof(STR_EDCA_ETSI_ACBK_LOCAL) - 1) + +/* + * + * edca_etsi_acbk_local - Set EDCA parameters for ETSI local AC BK + * @Default: 0x0,0x7,0x0,0xf,0x3,0xff,0xbb,0x0,0x1f,0x3,0xff,0x0,0x0,0xf,0x3, + * 0xff,0x0 + * + * This ini is used to set EDCA parameters for ETSI AC BK that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_ETSI_ACBK_LOCAL CFG_INI_STRING( \ + "edca_etsi_acbk_local", \ + 0, \ + STR_EDCA_ETSI_ACBK_LOCAL_LEN, \ + STR_EDCA_ETSI_ACBK_LOCAL, \ + "EDCA ETSI ACBK LOCAL") + +#define STR_EDCA_ETSI_ACBE_LOCAL "0x0, 0x3, 0x0, 0xf, 0x0, 0x3f, 0xbb, 0x0, 0x1f, 0x3, 0xff, 0x0, 0x0, 0xf, 0x0, 0x3f, 0x0" +#define STR_EDCA_ETSI_ACBE_LOCAL_LEN (sizeof(STR_EDCA_ETSI_ACBE_LOCAL) - 1) + +/* + * + * edca_etsi_acbe_local - Set EDCA parameters for ETSI local AC BE + * @Default: 0x0,0x3,0x0,0xf,0x0,0x3f,0xbb,0x0,0x1f,0x3,0xff,0x0,0x0,0xf,0x0, + * 0x3f,0x0 + * + * This ini is used to set EDCA parameters for ETSI AC BE that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_ETSI_ACBE_LOCAL CFG_INI_STRING( \ + "edca_etsi_acbe_local", \ + 0, \ + STR_EDCA_ETSI_ACBE_LOCAL_LEN, \ + STR_EDCA_ETSI_ACBE_LOCAL, \ + "EDCA ETSI ACBE LOCAL") + +#define STR_EDCA_ETSI_ACVI_LOCAL "0x0, 0x1, 0x0, 0x7, 0x0, 0xf, 0x7d, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, 0x0, 0xf, 0x5e" +#define STR_EDCA_ETSI_ACVI_LOCAL_LEN (sizeof(STR_EDCA_ETSI_ACVI_LOCAL) - 1) + +/* + * + * edca_etsi_acvi_local - Set EDCA parameters for ETSI local AC VI + * @Default: 0x0,0x1,0x0,0x7,0x0,0xf,0x7d,0x0,0x7,0x0,0xf,0xbc,0x0,0x7,0x0, + * 0xf,0x5e + * + * This ini is used to set EDCA parameters for ETSI AC VI that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_ETSI_ACVI_LOCAL CFG_INI_STRING( \ + "edca_etsi_acvi_local", \ + 0, \ + STR_EDCA_ETSI_ACVI_LOCAL_LEN, \ + STR_EDCA_ETSI_ACVI_LOCAL, \ + "EDCA ETSI ACVI LOCAL") + +#define STR_EDCA_ETSI_ACVO_LOCAL "0x0, 0x1, 0x0, 0x3, 0x0, 0x7, 0x3e, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, 0x0, 0x7, 0x2f" +#define STR_EDCA_ETSI_ACVO_LOCAL_LEN (sizeof(STR_EDCA_ETSI_ACVO_LOCAL) - 1) + +/* + * + * edca_etsi_acvo_local - Set EDCA parameters for ETSI local AC VO + * @Default: 0x0,0x1,0x0,0x3,0x0,0x7,0x3e,0x0,0x3,0x0,0x7,0x66,0x0,0x3,0x0, + * 0x7,0x2f + * + * This ini is used to set EDCA parameters for ETSI AC VO that are used locally + * on AP. The ini is with 17 bytes and comma is used as a separator for each + * byte. Index of each byte is defined in wlan_mlme_public_struct.h, such as + * CFG_EDCA_PROFILE_ACM_IDX. + * + * For cwmin and cwmax, they each occupy two bytes with the index defined + * above. The actual value are counted as number of bits with 1, e.g. + * "0x0,0x3f" means a value of 6. And final cwmin and cwmax will be converted + * to 2^value - 1. + * + * Related: None + * + * Supported Feature: AP + * + * Usage: External + * + * + */ +#define CFG_EDCA_ETSI_ACVO_LOCAL CFG_INI_STRING( \ + "edca_etsi_acvo_local", \ + 0, \ + STR_EDCA_ETSI_ACVO_LOCAL_LEN, \ + STR_EDCA_ETSI_ACVO_LOCAL, \ + "EDCA ETSI ACVO LOCAL") + +#define STR_EDCA_ETSI_ACBK "0x0, 0x7, 0x0, 0xf, 0x3, 0xff, 0xbb, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_ETSI_ACBK_LEN (sizeof(STR_EDCA_ETSI_ACBK) - 1) + +#define CFG_EDCA_ETSI_ACBK CFG_INI_STRING( \ + "edca_etsi_acbk", \ + 0, \ + STR_EDCA_ETSI_ACBK_LEN, \ + STR_EDCA_ETSI_ACBK, \ + "EDCA ETSI ACBK BROADCAST") + +#define STR_EDCA_ETSI_ACBE "0x0, 0x3, 0x0, 0xf, 0x3, 0xff, 0xbb, 0x0, 0xf, 0x3, 0xff, 0x0, 0x0, 0xf, 0x3, 0xff, 0x0" +#define STR_EDCA_ETSI_ACBE_LEN (sizeof(STR_EDCA_ETSI_ACBE) - 1) + +#define CFG_EDCA_ETSI_ACBE CFG_INI_STRING( \ + "edca_etsi_acbe", \ + 0, \ + STR_EDCA_ETSI_ACBE_LEN, \ + STR_EDCA_ETSI_ACBE, \ + "EDCA ETSI ACBE BROADCAST") + +#define STR_EDCA_ETSI_ACVI "0x0, 0x2, 0x0, 0x7, 0x0, 0xf, 0x7d, 0x0, 0x7, 0x0, 0xf, 0xbc, 0x0, 0x7, 0x0, 0xf, 0x5e" +#define STR_EDCA_ETSI_ACVI_LEN (sizeof(STR_EDCA_ETSI_ACVI) - 1) + +#define CFG_EDCA_ETSI_ACVI CFG_INI_STRING( \ + "edca_etsi_acvi", \ + 0, \ + STR_EDCA_ETSI_ACVI_LEN, \ + STR_EDCA_ETSI_ACVI, \ + "EDCA ETSI ACVI BROADCAST") + +#define STR_EDCA_ETSI_ACVO "0x0, 0x2, 0x0, 0x3, 0x0, 0x7, 0x3e, 0x0, 0x3, 0x0, 0x7, 0x66, 0x0, 0x3, 0x0, 0x7, 0x2f" +#define STR_EDCA_ETSI_ACVO_LEN (sizeof(STR_EDCA_ETSI_ACVO) - 1) + +#define CFG_EDCA_ETSI_ACVO CFG_INI_STRING( \ + "edca_etsi_acvo", \ + 0, \ + STR_EDCA_ETSI_ACVO_LEN, \ + STR_EDCA_ETSI_ACVO, \ + "EDCA ETSI ACVO BROADCAST") + +/* + * + * gEnableEdcaParams - Enable edca parameter + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used if gEnableEdcaParams is set to 1, params gEdcaVoCwmin, + * gEdcaViCwmin, gEdcaBkCwmin, gEdcaBeCwmin, gEdcaVoCwmax, + * gEdcaViCwmax, gEdcaBkCwmax, gEdcaBeCwmax, gEdcaVoAifs, + * gEdcaViAifs, gEdcaBkAifs and gEdcaBeAifs values are used + * to overwrite the values received from AP + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_ENABLE_PARAM CFG_INI_BOOL( \ + "gEnableEdcaParams", \ + 0, \ + "Enable edca parameter") + +/* + * + * enable_wmm_txop - Enable WMM based txop feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable the WMM based txop feature in FW + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_WMM_TXOP CFG_INI_BOOL( \ + "enable_wmm_txop", \ + 1, \ + "Enable WMM TXOP") + +/* + * + * gEdcaVoCwmin - Set Cwmin value for QCA_WLAN_AC_VO + * @Min: 0 + * @Max: 0x15 + * @Default: 2 + * + * This ini is used to set default Cwmin value for QCA_WLAN_AC_VO + * Cwmin value for QCA_WLAN_AC_VO. CWVomin = 2^gEdcaVoCwmin -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin etc + * are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VO_CWMIN CFG_INI_UINT( \ + "gEdcaVoCwmin", \ + 0x0, \ + 15, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "Cwmin value for QCA_WLAN_AC_VO") + +/* + * + * gEdcaVoCwmax - Set Cwmax value for QCA_WLAN_AC_VO + * @Min: 0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default Cwmax value for QCA_WLAN_AC_VO + * Cwmax value for QCA_WLAN_AC_VO. CWVomax = 2^gEdcaVoCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VO_CWMAX CFG_INI_UINT( \ + "gEdcaVoCwmax", \ + 0x0, \ + 15, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Cwmax value for QCA_WLAN_AC_VO") + +/* + * + * gEdcaVoAifs - Set Aifs value for QCA_WLAN_AC_VO + * @Min: 0 + * @Max: 15 + * @Default: 2 + * + * This ini is used to set default Aifs value for QCA_WLAN_AC_VO + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VO_AIFS CFG_INI_UINT( \ + "gEdcaVoAifs", \ + 0x0, \ + 15, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "default Aifs value for QCA_WLAN_AC_VO") + +/* + * + * gEdcaViCwmin - Set Cwmin value for QCA_WLAN_AC_VI + * @Min: 0x0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default value for QCA_WLAN_AC_VI + * Cwmin value for QCA_WLAN_AC_VI. CWVimin = 2^gEdcaViCwmin -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VI_CWMIN CFG_INI_UINT( \ + "gEdcaViCwmin", \ + 0x0, \ + 15, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Cwmin value for QCA_WLAN_AC_VI") + +/* + * + * gEdcaViCwmax - Set Cwmax value for QCA_WLAN_AC_VI + * @Min: 0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmax value for QCA_WLAN_AC_VI + * Cwmax value for QCA_WLAN_AC_VI. CWVimax = 2^gEdcaViCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VI_CWMAX CFG_INI_UINT( \ + "gEdcaViCwmax", \ + 0x0, \ + 15, \ + 4, \ + CFG_VALUE_OR_DEFAULT, \ + "cwmax value for QCA_WLAN_AC_VI") + +/* + * + * gEdcaViAifs - Set Aifs value for QCA_WLAN_AC_VI + * @Min: 0 + * @Max: 15 + * @Default: 2 + * + * This ini is used to set default Aifs value for QCA_WLAN_AC_VI + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_VI_AIFS CFG_INI_UINT( \ + "gEdcaViAifs", \ + 0x0, \ + 15, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "default Aifs value for QCA_WLAN_AC_VI") + +/* + * + * gEdcaBkCwmin - Set Cwmin value for QCA_WLAN_AC_BK + * @Min: 0x0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmin value for QCA_WLAN_AC_BK + * Cwmin value for QCA_WLAN_AC_BK. CWBkmin = 2^gEdcaBkCwmin -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + */ +#define CFG_EDCA_BK_CWMIN CFG_INI_UINT( \ + "gEdcaBkCwmin", \ + 0x0, \ + 15, \ + 4, \ + CFG_VALUE_OR_DEFAULT, \ + "Cwmin value for QCA_WLAN_AC_BK") + +/* + * + * gEdcaBkCwmax - Set Cwmax value for QCA_WLAN_AC_BK + * @Min: 0 + * @Max: 15 + * @Default: 10 + * + * This ini is used to set default Cwmax value for QCA_WLAN_AC_BK + * Cwmax value for QCA_WLAN_AC_BK. CWBkmax = 2^gEdcaBkCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_BK_CWMAX CFG_INI_UINT( \ + "gEdcaBkCwmax", \ + 0, \ + 15, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "cwmax value for QCA_WLAN_AC_BK") + +/* + * + * gEdcaBkAifs - Set Aifs value for QCA_WLAN_AC_BK + * @Min: 0 + * @Max: 15 + * @Default: 7 + * + * This ini is used to set default Aifs value for QCA_WLAN_AC_BK + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_BK_AIFS CFG_INI_UINT( \ + "gEdcaBkAifs", \ + 0, \ + 15, \ + 7, \ + CFG_VALUE_OR_DEFAULT, \ + "default Aifs value for QCA_WLAN_AC_BK") + +/* + * + * gEdcaBeCwmin - Set Cwmin value for QCA_WLAN_AC_BE + * @Min: 0x0 + * @Max: 15 + * @Default: 4 + * + * This ini is used to set default Cwmin value for QCA_WLAN_AC_BE + * Cwmin value for QCA_WLAN_AC_BE. CWBemin = 2^gEdcaBeCwmin + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_BE_CWMIN CFG_INI_UINT( \ + "gEdcaBeCwmin", \ + 0x0, \ + 15, \ + 4, \ + CFG_VALUE_OR_DEFAULT, \ + "Cwmin value for QCA_WLAN_AC_BE") + +/* + * + * gEdcaBeCwmax - Set Cwmax value for QCA_WLAN_AC_BE + * @Min: 0 + * @Max: 15 + * @Default: 10 + * + * This ini is used to set default Cwmax value for QCA_WLAN_AC_BE + * Cwmax value for QCA_WLAN_AC_BE. CWBemax = 2^gEdcaBeCwmax -1 + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_EDCA_BE_CWMAX CFG_INI_UINT( \ + "gEdcaBeCwmax", \ + 0, \ + 15, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "cwmax value for QCA_WLAN_AC_BE") + +/* + * + * gEdcaBeAifs - Set Aifs value for QCA_WLAN_AC_BE + * @Min: 0 + * @Max: 15 + * @Default: 3 + * + * This ini is used to set default Aifs value for QCA_WLAN_AC_BE + * + * Related: If gEnableEdcaParams is set to 1, params gEdcaVoCwmin + * etc are aplicable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_BE_AIFS CFG_INI_UINT( \ + "gEdcaBeAifs", \ + 0, \ + 15, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "default Aifs value for QCA_WLAN_AC_BE") + +/* + * + * edca_param_type - Edca param type + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to configure edca or pifs param for low latency SAP. + * If edca_param_type is set to 0 then host configures edca param and + * send it to firmware via WMI cmd and earbud via OTA frame. If it set to + * to 1 then host configures pifs param and send it to firmware via WMI + * cmd and earbud via OTA frame. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_EDCA_PIFS_PARAM_TYPE CFG_INI_UINT( \ + "edca_param_type", \ + 0, \ + 1, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Edca param type") + +#define CFG_EDCA_PARAMS_ALL \ + CFG(CFG_EDCA_ANI_ACBK_LOCAL) \ + CFG(CFG_EDCA_ANI_ACBE_LOCAL) \ + CFG(CFG_EDCA_ANI_ACVI_LOCAL) \ + CFG(CFG_EDCA_ANI_ACVO_LOCAL) \ + CFG(CFG_EDCA_ANI_ACBK) \ + CFG(CFG_EDCA_ANI_ACBE) \ + CFG(CFG_EDCA_ANI_ACVI) \ + CFG(CFG_EDCA_ANI_ACVO) \ + CFG(CFG_EDCA_WME_ACBK_LOCAL) \ + CFG(CFG_EDCA_WME_ACBE_LOCAL) \ + CFG(CFG_EDCA_WME_ACVI_LOCAL) \ + CFG(CFG_EDCA_WME_ACVO_LOCAL) \ + CFG(CFG_EDCA_WME_ACBK) \ + CFG(CFG_EDCA_WME_ACBE) \ + CFG(CFG_EDCA_WME_ACVI) \ + CFG(CFG_EDCA_WME_ACVO) \ + CFG(CFG_EDCA_ETSI_ACBK_LOCAL) \ + CFG(CFG_EDCA_ETSI_ACBE_LOCAL) \ + CFG(CFG_EDCA_ETSI_ACVI_LOCAL) \ + CFG(CFG_EDCA_ETSI_ACVO_LOCAL) \ + CFG(CFG_EDCA_ETSI_ACBK) \ + CFG(CFG_EDCA_ETSI_ACBE) \ + CFG(CFG_EDCA_ETSI_ACVI) \ + CFG(CFG_EDCA_ETSI_ACVO) \ + CFG(CFG_EDCA_ENABLE_PARAM) \ + CFG(CFG_EDCA_VO_CWMIN) \ + CFG(CFG_EDCA_VO_CWMAX) \ + CFG(CFG_EDCA_VO_AIFS) \ + CFG(CFG_EDCA_VI_CWMIN) \ + CFG(CFG_EDCA_VI_CWMAX) \ + CFG(CFG_EDCA_VI_AIFS) \ + CFG(CFG_EDCA_BK_CWMIN) \ + CFG(CFG_EDCA_BK_CWMAX) \ + CFG(CFG_EDCA_BK_AIFS) \ + CFG(CFG_EDCA_BE_CWMIN) \ + CFG(CFG_EDCA_BE_CWMAX) \ + CFG(CFG_ENABLE_WMM_TXOP) \ + CFG(CFG_EDCA_BE_AIFS) \ + CFG(CFG_EDCA_PIFS_PARAM_TYPE) + +#endif /* __CFG_MLME_EDCA__PARAM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_eht_caps.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_eht_caps.h new file mode 100644 index 0000000000..e2f423a91b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_eht_caps.h @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_EHT_CAPS_H +#define __CFG_MLME_EHT_CAPS_H + +/* + * + * eht_su_beamformer - Enable SU beamformer + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable SU beamformer + * + * Related: None + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_SU_BEAMFORMER CFG_BOOL( \ + "eht_su_beamformer", \ + 0, \ + "EHT Su Beamformer") + +/* + * + * eht_su_beamformee - Enable SU beamformee + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable SU beamformee + * + * Related: None + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_SU_BEAMFORMEE CFG_BOOL( \ + "eht_su_beamformee", \ + 0, \ + "EHT Su Beamformee") + +/* + * + * mu_bformer_le_80mhz - Enable MU beamformer for BW <= 80 + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable MU beamformer for BW <= 80 + * + * Related: None + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_MU_BFORMER_LE_80MHZ CFG_BOOL( \ + "mu_bformer_le_80mhz", \ + 0, \ + "EHT MU Beamformer BW <= 80 MHz") + +/* + * + * mu_bformer_160mhz - Enable MU beamformer for BW == 160 + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable MU beamformer for BW == 160 + * + * Related: None + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_MU_BFORMER_160MHZ CFG_BOOL( \ + "mu_bformer_160mhz", \ + 0, \ + "EHT MU Beamformer BW = 160 MHz") + +/* + * + * mu_bformer_320mhz - Enable MU beamformer for BW == 320 + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable or disable MU beamformer for BW == 320 + * + * Related: None + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_MU_BFORMER_320MHZ CFG_BOOL( \ + "mu_bformer_320mhz", \ + 0, \ + "EHT MU Beamformer BW = 320 MHz") + +/* + * + * eht_bfee_ss_le_80mhz - For a PPDU bandwidth less than or equal to 80 MHz, + * indicates the maximum number of spatial streams that + * the STA can receive in an EHT sounding NDP. + * @Min: 0 + * @Max: 7 + * @Default: 0 + * + * If the SU Beamformee subfield is 1, set to the maximum number of spatial + * streams that the STA is capable of receiving in an EHT sounding NDP minus 1. + * The minimum value of this field is 3. + * Reserved if the SU Beamformee field is 0. + * + * Related: NA + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_BFEE_SS_LE_80MHZ CFG_UINT( \ + "eht_bfee_ss_le_80mhz", \ + 3, \ + 7, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "EHT Beamformee SS <= 80 MHz") + +/* + * + * eht_bfee_ss_160mhz - For a PPDU bandwidth of 160 MHz, indicates the + * maximum number of spatial streams that the STA + * can receive in an EHT sounding NDP. + * @Min: 0 + * @Max: 7 + * @Default: 0 + * + * If the SU Beamformee subfield is 1, set to the maximum number of spatial + * streams that the STA is capable of receiving in an EHT sounding NDP minus 1. + * The minimum value of this field is 3. + * Reserved if the SU Beamformee field is 0. + * + * Related: NA + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_BFEE_SS_160MHZ CFG_UINT( \ + "eht_bfee_ss_160mhz", \ + 3, \ + 7, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "EHT Beamformee SS = 160 MHz") + +/* + * + * eht_bfee_ss_320mhz - For a PPDU bandwidth of 320 MHz, indicates the + * maximum number of spatial streams that the STA + * can receive in an EHT sounding NDP. + * @Min: 0 + * @Max: 7 + * @Default: 0 + * + * If the SU Beamformee subfield is 1, set to the maximum number of spatial + * streams that the STA is capable of receiving in an EHT sounding NDP minus 1. + * The minimum value of this field is 3. + * Reserved if the SU Beamformee field is 0. + * + * Related: NA + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_BFEE_SS_320MHZ CFG_UINT( \ + "eht_bfee_ss_320mhz", \ + 3, \ + 7, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "EHT Beamformee SS = 320 MHz") + +/* + * + * eht_num_sounding_dim_le_80mhz - For bandwidth less than or equal to 80 MHz, + * indicates the beamformer's capability + * indicating the maximum value of the TXVECTOR + * parameter NUM_STS for an EHT sounding NDP + * @Min: 0 + * @Max: 7 + * @Default: 0 + * + * If the SU Beamformer subfield is 1, set to the supported maximum + * TXVECTOR parameter NUM_STS value minus 1. + * Reserved if the SU Beamformer subfield is 0. + * + * Related: NA + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_NUM_SOUNDING_DIM_LE_80MHZ CFG_UINT( \ + "eht_num_sounding_dim_le_80mhz", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "EHT Number Of Sounding Dimensions <= 80 MHz") + +/* + * + * eht_num_sounding_dim_160mhz - For bandwidth of 160 MHz, indicates the + * beamformer's capability indicating the + * maximum value of the TXVECTOR parameter + * NUM_STS for an EHT sounding NDP + * @Min: 0 + * @Max: 7 + * @Default: 0 + * + * If the SU Beamformer subfield is 1, set to the supported maximum + * TXVECTOR parameter NUM_STS value minus 1. + * Reserved if the SU Beamformer subfield is 0 or the Supported Channel + * Width Set field does not indicate support for bandwidth of 160 MHz. + * + * Related: NA + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_NUM_SOUNDING_DIM_160MHZ CFG_UINT( \ + "eht_num_sounding_dim_160mhz", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "EHT Number Of Sounding Dimensions = 160 MHz") + +/* + * + * eht_num_sounding_dim_320mhz - For bandwidth of 320 MHz, indicates the + * beamformer's capability indicating the + * maximum value of the TXVECTOR parameter + * NUM_STS for an EHT sounding NDP + * @Min: 0 + * @Max: 7 + * @Default: 0 + * + * If the SU Beamformer subfield is 1, set to the supported maximum + * TXVECTOR parameter NUM_STS value minus 1. + * Reserved if the SU Beamformer subfield is 0 or the Supported Channel + * Width Set field does not indicate support for bandwidth of 320 MHz. + * + * Related: NA + * + * Supported Feature: 11be + * + * Usage: Internal + * + * + */ +#define CFG_EHT_NUM_SOUNDING_DIM_320MHZ CFG_UINT( \ + "eht_num_sounding_dim_320mhz", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "EHT Number Of Sounding Dimensions = 320 MHz") + +#define CFG_EHT_CAPS_ALL \ + CFG(CFG_EHT_SU_BEAMFORMER) \ + CFG(CFG_EHT_SU_BEAMFORMEE) \ + CFG(CFG_EHT_MU_BFORMER_LE_80MHZ) \ + CFG(CFG_EHT_MU_BFORMER_160MHZ) \ + CFG(CFG_EHT_MU_BFORMER_320MHZ) \ + CFG(CFG_EHT_BFEE_SS_LE_80MHZ) \ + CFG(CFG_EHT_BFEE_SS_160MHZ) \ + CFG(CFG_EHT_BFEE_SS_320MHZ) \ + CFG(CFG_EHT_NUM_SOUNDING_DIM_LE_80MHZ) \ + CFG(CFG_EHT_NUM_SOUNDING_DIM_160MHZ) \ + CFG(CFG_EHT_NUM_SOUNDING_DIM_320MHZ) + +#endif /* __CFG_MLME_EHT_CAPS_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_rrm.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_rrm.h new file mode 100644 index 0000000000..7468a99831 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_rrm.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_FE_RRM_H +#define __CFG_MLME_FE_RRM_H + +/* + * + * gRrmEnable - Enable/Disable RRM on STA + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to controls the capabilities (11 k) included + * in the capabilities field for STA. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal + * + * + */ +#define CFG_RRM_ENABLE CFG_INI_BOOL("gRrmEnable", \ + 1, \ + "Enable/Disable RRM") + +/* + * + * sap_rrm_enable - Enable/Disable RRM on SAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to control the capabilities (11 k) included + * in the capabilities field for SAP. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal + * + * + */ +#define CFG_SAP_RRM_ENABLE CFG_INI_BOOL("sap_rrm_enable", \ + 0, \ + "Enable/Disable RRM on SAP") + +/* + * + * gRrmRandnIntvl - Randomization interval + * @Min: 10 + * @Max: 100 + * @Default: 100 + * + * This ini is used to set randomization interval which is used to start a timer + * of a random value within randomization interval. Next RRM Scan request + * will be issued after the expiry of this random interval. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define CFG_RRM_MEAS_RAND_INTVL CFG_INI_UINT("gRrmRandnIntvl", \ + 10, \ + 100, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "RRM Randomization interval") + +/* + * + * rm_capability - Configure RM enabled capabilities IE + * @Default: 0x73,0x1A,0x91,0x00,0x04 + * + * This ini is used to configure RM enabled capabilities IE. + * Using this INI, we can set/unset any of the bits in 5 bytes + * (last 4bytes are reserved). Bit details are updated as per + * Draft version of 11mc spec. (Draft P802.11REVmc_D4.2) + * + * Bitwise details are defined as bit mask in rrm_global.h + * Comma is used as a separator for each byte. + * + * Related: None. + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define CFG_RM_CAPABILITY CFG_INI_STRING("rm_capability", \ + 24, \ + 40, \ + "0x73,0x1A,0x91,0x00,0x04", \ + "RM enabled capabilities IE") + +#define CFG_FE_RRM_ALL \ + CFG(CFG_RRM_ENABLE) \ + CFG(CFG_SAP_RRM_ENABLE) \ + CFG(CFG_RRM_MEAS_RAND_INTVL) \ + CFG(CFG_RM_CAPABILITY) + +#endif /* __CFG_MLME_FE_RRM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_wlm.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_wlm.h new file mode 100644 index 0000000000..ac82e1f0eb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_wlm.h @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_FE_WLM_H +#define __CFG_MLME_FE_WLM_H + +/* + * Flag definition of 32-bit host latency flags + * + * |31 18| 17 | 16 |15 8|7 1| 0 | + * +------+------+--------+-----------+------+-----------+ + * | RSVD | HBB | PM-QOS | RSVD | RSVD | RX Thread | + * +------+------+--------+-----------+------+-----------+ + * | common | TX Path | RX Path | + * + * bit 0-7: Rx path related optimization + * bit 0: disable rx_thread for vdev + * bit 1-7: Reserved + * bit 8-15: Tx path related optimization + * bit 8-15: Reserved + * bit 16-31: common changes + * bit 16: Request for pm_qos vote + * bit 17: Request for high ddr bus bandwidth + */ + +#define WLM_HOST_RX_THREAD_FLAG (1 << 0) +#define WLM_HOST_PM_QOS_FLAG (1 << 16) +#define WLM_HOST_HBB_FLAG (1 << 17) + +#define CFG_MAX_LATENCY_FLAGS "0xFFFFFFFFFFFFFFFF" + +/* + * + * wlm_latency_enable - WLM latency Enable + * + * @min: 0 + * @max: 1 + * @default: 1 + * + * 0 - disable + * 1 - enable + * + * + */ +#define CFG_LATENCY_ENABLE CFG_INI_BOOL("wlm_latency_enable", \ + 1, \ + "WLM latency Enable") + +/* + * + * wlm_latency_reset_on_disconnect - WLM latency level reset on disconnect + * + * @min: 0 + * @max: 1 + * @default: 0 + * + * 0 - disable + * 1 - enable + * + * + */ +#define CFG_LATENCY_RESET CFG_INI_BOOL("wlm_latency_reset_on_disconnect", \ + 0, \ + "WLM latency reset on disconnect") + +/* + * + * wlm_latency_level - WLM latency level + * Define 4 latency level to gain latency + * + * @min: 0 + * @max: 3 + * @default: 0 + * + * 0 - normal + * 1 - xr + * 2 - low + * 3 - ultralow + * + * + */ +#define CFG_LATENCY_LEVEL CFG_INI_UINT("wlm_latency_level", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "WLM latency level") + +#ifdef MULTI_CLIENT_LL_SUPPORT +/* + * + * wlm_multi_client_ll - Ini to configure multi client latency feature + * + * @min: 0 + * @max: 1 + * @default: 0 + * + * 0 - disable + * 1 - enable + * + * + */ +#define CFG_WLM_MULTI_CLIENT_LL_SUPPORT CFG_INI_BOOL("wlm_multi_client_ll", \ + 0, \ + "wlm multi client ll feature") + +#define WLM_MULTI_CLIENT_LL_CFG CFG(CFG_WLM_MULTI_CLIENT_LL_SUPPORT) +#else +#define WLM_MULTI_CLIENT_LL_CFG +#endif + +/* + * + * wlm_latency_flags_normal - WLM flags setting for normal level + * + * @min: 0x0 + * @max: 0xffffffffffffffff + * @default: 0x0 + * + * |31 12| 11 | 10 |9 8|7 6|5 4|3 2| 1 | 0 | + * +------+------+------+------+------+------+------+-----+-----+ + * | RSVD | SSLP | CSLP | RSVD | Roam | RSVD | DWLT | DFS | SUP | + * +------+-------------+-------------+-------------------------+ + * | WAL | PS | Roam | Scan | + * + * bit 0: Avoid scan request from HLOS if setting + * bit 1: Skip DFS channel SCAN if setting + * bit 2-3: Define policy of dwell time/duration for each foreign channel + * (b2 b3) + * (0 0 ): Default scan dwell time + * (0 1 ): Reserve + * (1 0 ): Shrink off channel dwell time + * (1 1 ): Reserve + * bit 4-5: Reserve for scan + * bit 6-7: Define roaming policy + * (b6 b7) + * (0 0 ): Default roaming behavior, allow roaming in all scenarios + * (0 1 ): Disallow all roaming + * (1 0 ): Allow roaming when final bmissed + * (1 1 ): Reserve + * bit 8-9: Reserve for roaming + * bit 10: Disable css power collapse if setting + * bit 11: Disable sys sleep if setting + * bit 12-31: Reserve for future usage + * + * |63 50| 49 | 48 |47 40|39 33| 32 | + * +------+------+--------+------------+-------+-----------+ + * | RSVD | HBB | PM-QOS | RSVD | RSVD | RX Thread | + * +------+------+--------+------------+-------+-----------+ + * | common | TX Path | RX Path | + * + * bit 39-32: Rx path related optimization + * bit 32: disable rx_thread for vdev + * bit 33-39: Reserved + * bit 40-47: Tx path related optimization + * bit 40-47: Reserved + * bit 48-63: common changes + * bit 48: Request for pm_qos vote + * bit 49: Request for high ddr bus bandwidth + * + * + */ +#define CFG_DEFAULT_NORMAL_FLAGS "0x0" +#define CFG_LATENCY_FLAGS_NORMAL \ + CFG_INI_STRING("wlm_latency_flags_normal",\ + 0, \ + sizeof(CFG_MAX_LATENCY_FLAGS) - 1,\ + CFG_DEFAULT_NORMAL_FLAGS, \ + "WLM flags for normal level") + + +/* + * + * wlm_latency_flags_xr - WLM flags setting for XR level + * + * @min: 0x0 + * @max: 0xffffffffffffffff + * @default: 0x3000100000083 + * + * |31 12| 11 | 10 |9 8|7 6|5 4|3 2| 1 | 0 | + * +------+------+------+------+------+------+------+-----+-----+ + * | RSVD | SSLP | CSLP | RSVD | Roam | RSVD | DWLT | DFS | SUP | + * +------+-------------+-------------+-------------------------+ + * | WAL | PS | Roam | Scan | + * + * bit 0: Avoid scan request from HLOS if setting + * bit 1: Skip DFS channel SCAN if setting + * bit 2-3: Define policy of dwell time/duration for each foreign channel + * (b2 b3) + * (0 0 ): Default scan dwell time + * (0 1 ): Reserve + * (1 0 ): Shrink off channel dwell time + * (1 1 ): Reserve + * bit 4-5: Reserve for scan + * bit 6-7: Define roaming policy + * (b6 b7) + * (0 0 ): Default roaming behavior, allow roaming in all scenarios + * (0 1 ): Disallow all roaming + * (1 0 ): Allow roaming when final bmissed + * (1 1 ): Reserve + * bit 8-9: Reserve for roaming + * bit 10: Disable css power collapse if setting + * bit 11: Disable sys sleep if setting + * bit 12-31: Reserve for future usage + * + * |63 50| 49 | 48 |47 40|39 33| 32 | + * +------+------+--------+------------+-------+-----------+ + * | RSVD | HBB | PM-QOS | RSVD | RSVD | RX Thread | + * +------+------+--------+------------+-------+-----------+ + * | common | TX Path | RX Path | + * + * bit 39-32: Rx path related optimization + * bit 32: disable rx_thread for vdev + * bit 33-39: Reserved + * bit 40-47: Tx path related optimization + * bit 40-47: Reserved + * bit 48-63: common changes + * bit 48: Request for pm_qos vote + * bit 49: Request for high ddr bus bandwidth + * + * + */ +#define CFG_DEFAULT_XR_FLAGS "0x3000100000083" +#define CFG_LATENCY_FLAGS_XR \ + CFG_INI_STRING("wlm_latency_flags_xr",\ + 0, \ + sizeof(CFG_MAX_LATENCY_FLAGS) - 1,\ + CFG_DEFAULT_XR_FLAGS, \ + "WLM flags for XR level") + + +/* + * + * wlm_latency_flags_low - WLM flags setting for low level + * + * @min: 0x0 + * @max: 0xffffffffffffffff + * @default: 0xa + * + * |31 12| 11 | 10 |9 8|7 6|5 4|3 2| 1 | 0 | + * +------+------+------+------+------+------+------+-----+-----+ + * | RSVD | SSLP | CSLP | RSVD | Roam | RSVD | DWLT | DFS | SUP | + * +------+-------------+-------------+-------------------------+ + * | WAL | PS | Roam | Scan | + * + * bit 0: Avoid scan request from HLOS if setting + * bit 1: Skip DFS channel SCAN if setting + * bit 2-3: Define policy of dwell time/duration for each foreign channel + * (b2 b3) + * (0 0 ): Default scan dwell time + * (0 1 ): Reserve + * (1 0 ): Shrink off channel dwell time + * (1 1 ): Reserve + * bit 4-5: Reserve for scan + * bit 6-7: Define roaming policy + * (b6 b7) + * (0 0 ): Default roaming behavior, allow roaming in all scenarios + * (0 1 ): Disallow all roaming + * (1 0 ): Allow roaming when final bmissed + * (1 1 ): Reserve + * bit 8-9: Reserve for roaming + * bit 10: Disable css power collapse if setting + * bit 11: Disable sys sleep if setting + * bit 12-31: Reserve for future usage + * + * |63 50| 49 | 48 |47 40|39 33| 32 | + * +------+------+--------+------------+-------+-----------+ + * | RSVD | HBB | PM-QOS | RSVD | RSVD | RX Thread | + * +------+------+--------+------------+-------+-----------+ + * | common | TX Path | RX Path | + * + * bit 39-32: Rx path related optimization + * bit 32: disable rx_thread for vdev + * bit 33-39: Reserved + * bit 40-47: Tx path related optimization + * bit 40-47: Reserved + * bit 48-63: common changes + * bit 48: Request for pm_qos vote + * bit 49: Request for high ddr bus bandwidth + * + * + */ +#define CFG_DEFAULT_LOW_FLAGS "0xa" +#define CFG_LATENCY_FLAGS_LOW \ + CFG_INI_STRING("wlm_latency_flags_low",\ + 0, \ + sizeof(CFG_MAX_LATENCY_FLAGS) - 1,\ + CFG_DEFAULT_LOW_FLAGS, \ + "WLM flags for low level") + +/* + * + * wlm_latency_flags_ultralow - WLM flags setting for ultralow level + * + * @min: 0x0 + * @max: 0xffffffffffffffff + * @default: 0xc83 + * + * |31 25| 24 |23 12| 11 | 10 |9 8|7 6|5 4|3 2| 1 | 0 | + * +------+------+------+------+------+------+------+------+------+-----+-----+ + * | RSVD | MLMR | RSVD | SSLP | CSLP | RSVD | Roam | RSVD | DWLT | DFS | SUP | + * +------+------+------+-------------+-------------+-------------------------+ + * | WAL | PS | WAL | PS | Roam | Scan | + * + * bit 0: Avoid scan request from HLOS if setting + * bit 1: Skip DFS channel SCAN if setting + * bit 2-3: Define policy of dwell time/duration for each foreign channel + * (b2 b3) + * (0 0 ): Default scan dwell time + * (0 1 ): Reserve + * (1 0 ): Shrink off channel dwell time + * (1 1 ): Reserve + * bit 4-5: Reserve for scan + * bit 6-7: Define roaming policy + * (b6 b7) + * (0 0 ): Default roaming behavior, allow roaming in all scenarios + * (0 1 ): Disallow all roaming + * (1 0 ): Allow roaming when final bmissed + * (1 1 ): Reserve + * bit 8-9: Reserve for roaming + * bit 10: Disable css power collapse if setting + * bit 11: Disable sys sleep if setting + * bit 12-23: Reserve for future usage + * bit 24: Disable MLMR mode + * bit 25-31: Reserved for future use + * + * |63 50| 49 | 48 |47 40|39 33| 32 | + * +------+------+--------+------------+-------+-----------+ + * | RSVD | HBB | PM-QOS | RSVD | RSVD | RX Thread | + * +------+------+--------+------------+-------+-----------+ + * | common | TX Path | RX Path | + * + * bit 39-32: Rx path related optimization + * bit 32: disable rx_thread for vdev + * bit 33-39: Reserved + * bit 40-47: Tx path related optimization + * bit 40-47: Reserved + * bit 48-63: common changes + * bit 48: Request for pm_qos vote + * bit 49: Request for high ddr bus bandwidth + * + * + */ +#define CFG_DEFAULT_ULTLOW_FLAGS "0xc83" +#define CFG_LATENCY_FLAGS_ULTLOW \ + CFG_INI_STRING("wlm_latency_flags_ultralow",\ + 0, \ + sizeof(CFG_MAX_LATENCY_FLAGS) - 1,\ + CFG_DEFAULT_ULTLOW_FLAGS, \ + "WLM flags for ultralow level") + +#define CFG_FE_WLM_ALL \ + CFG(CFG_LATENCY_ENABLE) \ + CFG(CFG_LATENCY_RESET) \ + CFG(CFG_LATENCY_LEVEL) \ + WLM_MULTI_CLIENT_LL_CFG \ + CFG(CFG_LATENCY_FLAGS_NORMAL) \ + CFG(CFG_LATENCY_FLAGS_XR) \ + CFG(CFG_LATENCY_FLAGS_LOW) \ + CFG(CFG_LATENCY_FLAGS_ULTLOW) + +#endif /* __CFG_MLME_FE_WLM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_wmm.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_wmm.h new file mode 100644 index 0000000000..fac5aa5e35 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_fe_wmm.h @@ -0,0 +1,1035 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_FE_WMM_H +#define __CFG_MLME_FE_WMM_H + +#define CFG_QOS_ENABLED CFG_BOOL( \ + "qos_enabled", \ + 0, \ + "QOS Enabled") + +#define CFG_WME_ENABLED CFG_BOOL( \ + "wme_enabled", \ + 1, \ + "WME Enabled") + +#define CFG_MAX_SP_LENGTH CFG_UINT( \ + "max_sp_length", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "MAX sp length") + +#define CFG_WSM_ENABLED CFG_BOOL( \ + "wsm_enabled", \ + 0, \ + "WSM Enabled") + +#define CFG_EDCA_PROFILE CFG_UINT( \ + "edca_profile", \ + 0, \ + 4, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Edca Profile") + +/* default TSPEC parameters for AC_VO */ +/* + * + * InfraDirAcVo - Set TSPEC direction for VO + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for VO + * + * 0 - uplink + * 1 - direct link + * 2 - down link + * 3 - bidirectional link + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_DIR_AC_VO CFG_INI_UINT( \ + "InfraDirAcVo", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "direction for vo") + +/* + * + * InfraNomMsduSizeAcVo - Set normal MSDU size for VO + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x80D0 + * + * This ini is used to set normal MSDU size for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_NOM_MSDU_SIZE_AC_VO CFG_INI_UINT( \ + "InfraNomMsduSizeAcVo", \ + 0x0, \ + 0xFFFF, \ + 0x80D0, \ + CFG_VALUE_OR_DEFAULT, \ + "MSDU size for VO") + +/* + * + * InfraMeanDataRateAcVo - Set mean data rate for VO + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x14500 + * + * This ini is used to set mean data rate for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MEAN_DATA_RATE_AC_VO CFG_INI_UINT( \ + "InfraMeanDataRateAcVo", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x14500, \ + CFG_VALUE_OR_DEFAULT, \ + "mean data rate for VO") + +/* + * + * InfraMinPhyRateAcVo - Set min PHY rate for VO + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for VO + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MIN_PHY_RATE_AC_VO CFG_INI_UINT( \ + "InfraMinPhyRateAcVo", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x5B8D80, \ + CFG_VALUE_OR_DEFAULT, \ + "min PHY rate for VO") + +/* + * + * InfraSbaAcVo - Set surplus bandwidth allowance for VO + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for VO + * + * Related: None. + * + * Supported Feature: WMM +* + * Usage: External + * + * + */ +#define CFG_QOS_WMM_SBA_AC_VO CFG_INI_UINT( \ + "InfraSbaAcVo", \ + 0x2001, \ + 0xFFFF, \ + 0x2001, \ + CFG_VALUE_OR_DEFAULT, \ + "surplus bandwidth allowance for VO") +/* + * + * InfraDirAcVi - Set TSPEC direction for VI + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_DIR_AC_VI CFG_INI_UINT( \ + "InfraDirAcVi", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "TSPEC direction for VI") + +/* + * + * InfraNomMsduSizeAcVi - Set normal MSDU size for VI + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x85DC + * + * This ini is used to set normal MSDU size for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_NOM_MSDU_SIZE_AC_VI CFG_INI_UINT( \ + "InfraNomMsduSizeAcVi", \ + 0x0, \ + 0xFFFF, \ + 0x85DC, \ + CFG_VALUE_OR_DEFAULT, \ + "MSDU size for VI") + +/* + * + * InfraMeanDataRateAcVi - Set mean data rate for VI + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x57E40 + * + * This ini is used to set mean data rate for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MEAN_DATA_RATE_AC_VI CFG_INI_UINT( \ + "InfraMeanDataRateAcVi", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x57E40, \ + CFG_VALUE_OR_DEFAULT, \ + "data rate for VI") + +/* + * + * InfraMinPhyRateAcVi - Set min PHY rate for VI + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MIN_PHY_RATE_AC_VI CFG_INI_UINT( \ + "InfraMinPhyRateAcVi", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x5B8D80, \ + CFG_VALUE_OR_DEFAULT, \ + "min PHY rate for VI") + +/* + * + * InfraSbaAcVi - Set surplus bandwidth allowance for VI + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for VI + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ + +#define CFG_QOS_WMM_SBA_AC_VI CFG_INI_UINT( \ + "InfraSbaAcVi", \ + 0x2001, \ + 0xFFFF, \ + 0x2001, \ + CFG_VALUE_OR_DEFAULT, \ + "surplus bandwidth allowance for VI") + +/* + * + * InfraUapsdVoSrvIntv - Set Uapsd service interval for voice + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini is used to set Uapsd service interval(in ms) for voice. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_VO_SRV_INTV CFG_INI_UINT( \ + "InfraUapsdVoSrvIntv", \ + 0, \ + 4294967295UL, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd vo srv intv") + +/* + * + * InfraUapsdVoSuspIntv - Set Uapsd suspension interval for voice + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval(in ms) for voice. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_VO_SUS_INTV CFG_INI_UINT( \ + "InfraUapsdVoSuspIntv", \ + 0, \ + 4294967295UL, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd vo sus intv") + +/* + * + * InfraUapsdViSrvIntv - Set Uapsd service interval for video + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini is used to set Uapsd service interval(in ms) for video. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ + +#define CFG_QOS_WMM_UAPSD_VI_SRV_INTV CFG_INI_UINT( \ + "InfraUapsdViSrvIntv", \ + 0, \ + 4294967295UL, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd vi srv intv") + +/* + * + * InfraUapsdViSuspIntv - Set Uapsd suspension interval for video + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval(in ms) for video + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_VI_SUS_INTV CFG_INI_UINT( \ + "InfraUapsdViSuspIntv", \ + 0, \ + 4294967295UL, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd vi sus intv") + +/* + * + * InfraDirAcBe - Set TSPEC direction for BE + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for BE + * + * 0 - uplink + * 1 - direct link + * 2 - down link + * 3 - bidirectional link + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_DIR_AC_BE CFG_INI_UINT( \ + "InfraDirAcBe", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "TSPEC direction for BE") + +/* + * + * InfraNomMsduSizeAcBe - Set normal MSDU size for BE + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x85DC + * + * This ini is used to set normal MSDU size for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_NOM_MSDU_SIZE_AC_BE CFG_INI_UINT( \ + "InfraNomMsduSizeAcBe", \ + 0x0, \ + 0xFFFF, \ + 0x85DC, \ + CFG_VALUE_OR_DEFAULT, \ + "MSDU size for BE") + +/* + * + * InfraMeanDataRateAcBe - Set mean data rate for BE + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x493E0 + * + * This ini is used to set mean data rate for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MEAN_DATA_RATE_AC_BE CFG_INI_UINT( \ + "InfraMeanDataRateAcBe", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x493E0, \ + CFG_VALUE_OR_DEFAULT, \ + "data rate for BE") + +/* + * + * InfraMinPhyRateAcBe - Set min PHY rate for BE + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MIN_PHY_RATE_AC_BE CFG_INI_UINT( \ + "InfraMinPhyRateAcBe", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x5B8D80, \ + CFG_VALUE_OR_DEFAULT, \ + "min PHY rate for BE") + +/* + * + * InfraSbaAcBe - Set surplus bandwidth allowance for BE + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_SBA_AC_BE CFG_INI_UINT( \ + "InfraSbaAcBe", \ + 0x2001, \ + 0xFFFF, \ + 0x2001, \ + CFG_VALUE_OR_DEFAULT, \ + "surplus bandwidth allowance for BE") + +/* + * + * InfraUapsdBeSrvIntv - Set Uapsd service interval for BE + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini is used to set Uapsd service interval(in ms) for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_BE_SRV_INTV CFG_INI_UINT( \ + "InfraUapsdBeSrvIntv", \ + 0, \ + 4294967295UL, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd be srv intv") + +/* + * + * InfraUapsdBeSuspIntv - Set Uapsd suspension interval for BE + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval(in ms) for BE + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_BE_SUS_INTV CFG_INI_UINT( \ + "InfraUapsdBeSuspIntv", \ + 0, \ + 4294967295UL, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd vi sus intv") + +/* + * + * InfraDirAcBk - Set TSPEC direction for BK + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set TSPEC direction for BK + * + * 0 - uplink + * 1 - direct link + * 2 - down link + * 3 - bidirectional link + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_DIR_AC_BK CFG_INI_UINT( \ + "InfraDirAcBk", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "TSPEC direction for BK") + +/* + * + * InfraNomMsduSizeAcBk - Set normal MSDU size for BK + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0x85DC + * + * This ini is used to set normal MSDU size for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_NOM_MSDU_SIZE_AC_BK CFG_INI_UINT( \ + "InfraNomMsduSizeAcBk", \ + 0x0, \ + 0xFFFF, \ + 0x85DC, \ + CFG_VALUE_OR_DEFAULT, \ + "MSDU size for BK") + +/* + * + * InfraMeanDataRateAcBk - Set mean data rate for BK + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x493E0 + * + * This ini is used to set mean data rate for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MEAN_DATA_RATE_AC_BK CFG_INI_UINT( \ + "InfraMeanDataRateAcBk", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x493E0, \ + CFG_VALUE_OR_DEFAULT, \ + "data rate for BK") + +/* + * + * InfraMinPhyRateAcBk - Set min PHY rate for BK + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x5B8D80 + * + * This ini is used to set min PHY rate for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MIN_PHY_RATE_AC_BK CFG_INI_UINT( \ + "InfraMinPhyRateAcBk", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x5B8D80, \ + CFG_VALUE_OR_DEFAULT, \ + "min PHY rate for BK") + +/* + * + * InfraSbaAcBk - Set surplus bandwidth allowance for BK + * @Min: 0x2001 + * @Max: 0xFFFF + * @Default: 0x2001 + * + * This ini is used to set surplus bandwidth allowance for BK + * + * The 13 least significant bits (LSBs) indicate the decimal part while the + * three MSBs indicate the integer part of the number. + * + * A value of 1 indicates that no additional allocation of time is requested. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_SBA_AC_BK CFG_INI_UINT( \ + "InfraSbaAcBk", \ + 0x2001, \ + 0xFFFF, \ + 0x2001, \ + CFG_VALUE_OR_DEFAULT, \ + "surplus bandwidth allowance for BK") + +/* + * + * InfraUapsdBkSrvIntv - Set Uapsd service interval for BK + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini is used to set Uapsd service interval(in ms) for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_BK_SRV_INTV CFG_INI_UINT( \ + "InfraUapsdBkSrvIntv", \ + 0, \ + 4294967295UL, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd bk srv intv") + +/* + * + * InfraUapsdBkSuspIntv - Set Uapsd suspension interval for BK + * @Min: 0 + * @Max: 4294967295UL + * @Default: 2000 + * + * This ini is used to set Uapsd suspension interval(in ms) for BK + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_BK_SUS_INTV CFG_INI_UINT( \ + "InfraUapsdBkSuspIntv", \ + 0, \ + 4294967295UL, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra uapsd bk sus intv") + +/* WMM configuration */ +/* + * + * WmmIsEnabled - Enable WMM feature + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to enable/disable WMM. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_MODE CFG_INI_UINT( \ + "WmmIsEnabled", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable WMM feature") + +/* + * + * 80211eIsEnabled - Enable 802.11e feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable 802.11e. + * + * Related: None. + * + * Supported Feature: 802.11e + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_80211E_ENABLED CFG_INI_BOOL( \ + "80211eIsEnabled", \ + 0, \ + "Enable 802.11e feature") + +/* + * + * UapsdMask - To setup U-APSD mask for ACs + * @Min: 0x00 + * @Max: 0xFF + * @Default: 0x00 + * + * This ini is used to setup U-APSD mask for ACs. + * + * Bit 0 set, Voice both deliver/trigger enabled + * Bit 1 set, Video both deliver/trigger enabled + * Bit 2 set, Background both deliver/trigger enabled + * Bit 3 set, Best Effort both deliver/trigger enabled + * others, reserved + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_UAPSD_MASK CFG_INI_UINT( \ + "UapsdMask", \ + 0x00, \ + 0xFF, \ + 0x00, \ + CFG_VALUE_OR_DEFAULT, \ + "setup U-APSD mask for ACs") + +#ifdef FEATURE_WLAN_ESE +/* + * + * InfraInactivityInterval - To setup Infra Inactivity Interval for ACs + * @Min: 0 + * @Max: 4294967295UL + * @Default: 0 + * + * This ini is used to setup Infra Inactivity Interval for + * ACs. + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_INACTIVITY_INTERVAL CFG_INI_UINT( \ + "InfraInactivityInterval", \ + 0, \ + 4294967295UL, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Infra Inactivity Interval") + +#define QOS_CFG CFG(CFG_QOS_WMM_INACTIVITY_INTERVAL) +#else + +#define QOS_CFG + +#endif /* FEATURE_WLAN_ESE */ + +/* + * + * burstSizeDefinition - Set TS burst size + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set TS burst size + * + * 0 - burst is disabled + * 1 - burst is enabled + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_BURST_SIZE_DEFN CFG_INI_BOOL( \ + "burstSizeDefinition", \ + 0, \ + "burst size definition") + +/* + * + * tsInfoAckPolicy - Set TS ack policy + * @Min: 0x00 + * @Max: 0x01 + * @Default: 0x00 + * + * This ini is used to set TS ack policy + * + * TS Info Ack Policy can be either of the following values: + * + * 0 - normal ack + * 1 - HT immediate block ack + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_WMM_TS_INFO_ACK_POLICY CFG_INI_UINT( \ + "tsInfoAckPolicy", \ + 0, \ + 1, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "ts info ack policy") + +/* + * + * gAddTSWhenACMIsOff - Set ACM value for AC + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set ACM value for AC + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_QOS_ADDTS_WHEN_ACM_IS_OFF CFG_INI_BOOL( \ + "gAddTSWhenACMIsOff", \ + 1, \ + "ACM value for AC") + +/* + * + * DelayedTriggerFrmInt - UAPSD delay interval + * @Min: 1 + * @Max: 4294967295 + * @Default: 3000 + * + * This parameter controls the delay interval(in ms) of UAPSD auto trigger. + * + * Supported Feature: WMM + * + * Usage: External + * + * + */ +#define CFG_TL_DELAYED_TRGR_FRM_INTERVAL CFG_INI_UINT( \ + "DelayedTriggerFrmInt", \ + 1, \ + 4294967295UL, \ + 3000, \ + CFG_VALUE_OR_DEFAULT, \ + "UAPSD auto trigger Interval") + +#define CFG_WMM_PARAMS_ALL \ + CFG(CFG_QOS_ENABLED) \ + CFG(CFG_WME_ENABLED) \ + CFG(CFG_MAX_SP_LENGTH) \ + CFG(CFG_WSM_ENABLED) \ + CFG(CFG_EDCA_PROFILE) \ + CFG(CFG_QOS_WMM_DIR_AC_VO) \ + CFG(CFG_QOS_WMM_NOM_MSDU_SIZE_AC_VO) \ + CFG(CFG_QOS_WMM_MEAN_DATA_RATE_AC_VO) \ + CFG(CFG_QOS_WMM_MIN_PHY_RATE_AC_VO) \ + CFG(CFG_QOS_WMM_SBA_AC_VO) \ + CFG(CFG_QOS_WMM_UAPSD_VO_SRV_INTV) \ + CFG(CFG_QOS_WMM_UAPSD_VO_SUS_INTV) \ + CFG(CFG_QOS_WMM_DIR_AC_VI) \ + CFG(CFG_QOS_WMM_NOM_MSDU_SIZE_AC_VI) \ + CFG(CFG_QOS_WMM_MEAN_DATA_RATE_AC_VI) \ + CFG(CFG_QOS_WMM_MIN_PHY_RATE_AC_VI) \ + CFG(CFG_QOS_WMM_SBA_AC_VI) \ + CFG(CFG_QOS_WMM_UAPSD_VI_SRV_INTV) \ + CFG(CFG_QOS_WMM_UAPSD_VI_SUS_INTV) \ + CFG(CFG_QOS_WMM_DIR_AC_BE) \ + CFG(CFG_QOS_WMM_NOM_MSDU_SIZE_AC_BE) \ + CFG(CFG_QOS_WMM_MEAN_DATA_RATE_AC_BE) \ + CFG(CFG_QOS_WMM_MIN_PHY_RATE_AC_BE) \ + CFG(CFG_QOS_WMM_SBA_AC_BE) \ + CFG(CFG_QOS_WMM_UAPSD_BE_SRV_INTV) \ + CFG(CFG_QOS_WMM_UAPSD_BE_SUS_INTV) \ + CFG(CFG_QOS_WMM_DIR_AC_BK) \ + CFG(CFG_QOS_WMM_NOM_MSDU_SIZE_AC_BK) \ + CFG(CFG_QOS_WMM_MEAN_DATA_RATE_AC_BK) \ + CFG(CFG_QOS_WMM_MIN_PHY_RATE_AC_BK) \ + CFG(CFG_QOS_WMM_SBA_AC_BK) \ + CFG(CFG_QOS_WMM_UAPSD_BK_SRV_INTV) \ + CFG(CFG_QOS_WMM_UAPSD_BK_SUS_INTV) \ + CFG(CFG_QOS_WMM_MODE) \ + CFG(CFG_QOS_WMM_80211E_ENABLED) \ + CFG(CFG_QOS_WMM_UAPSD_MASK) \ + QOS_CFG \ + CFG(CFG_QOS_WMM_BURST_SIZE_DEFN) \ + CFG(CFG_QOS_WMM_TS_INFO_ACK_POLICY) \ + CFG(CFG_QOS_ADDTS_WHEN_ACM_IS_OFF) \ + CFG(CFG_TL_DELAYED_TRGR_FRM_INTERVAL) + +#endif /* __CFG_MLME_FE_WMM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_feature_flag.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_feature_flag.h new file mode 100644 index 0000000000..c25e70ac8d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_feature_flag.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_FEATURE_FLAG_H +#define __CFG_MLME_FEATURE_FLAG_H + +#define CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY CFG_BOOL( \ + "accept_short_slot_assoc", \ + 0, \ + "Accept short slot assoc only") + +#define CFG_HCF_ENABLED CFG_BOOL( \ + "enable_hcf", \ + 0, \ + "HCF enabled") + +#define CFG_RSN_ENABLED CFG_BOOL( \ + "enable_rsn", \ + 0, \ + "RSN enabled") + +#define CFG_11G_SHORT_PREAMBLE_ENABLED CFG_BOOL( \ + "enable_short_preamble_11g", \ + 0, \ + "Short Preamble Enable") + +#define CFG_11G_SHORT_SLOT_TIME_ENABLED CFG_BOOL( \ + "enable_short_slot_time_11g", \ + 1, \ + "Short Slot time enable") + +#define CFG_CHANNEL_BONDING_MODE CFG_UINT( \ + "channel_bonding_mode", \ + 0, \ + 10, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "channel bonding mode") + +#define CFG_BLOCK_ACK_ENABLED CFG_UINT( \ + "enable_block_ack", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "enable block Ack") +/* + * + * gEnableAMPDUPS - Enable the AMPDUPS + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default AMPDUPS + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_AMPDUPS CFG_INI_BOOL( \ + "gEnableAMPDUPS", \ + 0, \ + "Enable AMPDU") + +/* + * + * gFWMccRtsCtsProtection - RTS-CTS protection in MCC. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable use of long duration RTS-CTS protection + * when SAP goes off channel in MCC mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_FW_MCC_RTS_CTS_PROT CFG_INI_UINT( \ + "gFWMccRtsCtsProtection", \ + 0, 1, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "RTS-CTS protection in MCC") + +/* + * + * gFWMccBCastProbeResponse - Broadcast Probe Response in MCC. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable use of broadcast probe response to + * increase the detectability of SAP in MCC mode. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ + +#define CFG_FW_MCC_BCAST_PROB_RESP CFG_INI_UINT( \ + "gFWMccBCastProbeResponse", \ + 0, 1, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Broadcast Probe Response in MCC") + +/* + * + * gEnableMCCMode - Enable/Disable MCC feature. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable MCC feature. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: External + * + * + */ +#define CFG_MCC_FEATURE CFG_INI_UINT( \ + "gEnableMCCMode", \ + 0, 1, 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable/Disable MCC feature.") + +/* + * + * gChannelBondingMode24GHz - Configures Channel Bonding in 24 GHz + * @Min: 0 + * @Max: 10 + * @Default: 1 + * + * This ini is used to set default channel bonding mode 24GHZ + * + * 0 - 20MHz IF bandwidth centered on IF carrier + * 1 - 40MHz IF bandwidth with lower 20MHz supporting the primary channel + * 2 - reserved + * 3 - 40MHz IF bandwidth with higher 20MHz supporting the primary channel + * 4 - 20/40MHZ offset LOW 40/80MHZ offset CENTERED + * 5 - 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED + * 6 - 20/40MHZ offset HIGH 40/80MHZ offset CENTERED + * 7 - 20/40MHZ offset LOW 40/80MHZ offset LOW + * 8 - 20/40MHZ offset HIGH 40/80MHZ offset LOW + * 9 - 20/40MHZ offset LOW 40/80MHZ offset HIGH + * 10 - 20/40MHZ offset-HIGH 40/80MHZ offset HIGH + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_CHANNEL_BONDING_MODE_24GHZ CFG_INI_UINT( \ + "gChannelBondingMode24GHz", \ + 0, \ + 10, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Configures Channel Bonding in 24 GHz") + +/* + * + * gChannelBondingMode5GHz - Configures Channel Bonding in 5 GHz + * @Min: 0 + * @Max: 10 + * @Default: 1 + * + * This ini is used to set default channel bonding mode 5GHZ + * + * Values of 0 - 10 have the same meanings as for gChannelBondingMode24GHz. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_CHANNEL_BONDING_MODE_5GHZ CFG_INI_UINT( \ + "gChannelBondingMode5GHz", \ + 0, \ + 10, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Configures Channel Bonding in 5 GHz") + +/* + * + * update_cw_allowed - process set channel width or not + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to check whether driver allowed to process set channel + * width request from upper layer or not. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ALLOW_UPDATE_CHANNEL_WIDTH CFG_INI_BOOL( \ + "update_cw_allowed", \ + 1, \ + "is update chan width allowed") + +#define CFG_FEATURE_FLAG_ALL \ + CFG(CFG_ACCEPT_SHORT_SLOT_ASSOC_ONLY) \ + CFG(CFG_HCF_ENABLED) \ + CFG(CFG_RSN_ENABLED) \ + CFG(CFG_FW_MCC_RTS_CTS_PROT) \ + CFG(CFG_FW_MCC_BCAST_PROB_RESP) \ + CFG(CFG_MCC_FEATURE) \ + CFG(CFG_11G_SHORT_PREAMBLE_ENABLED) \ + CFG(CFG_11G_SHORT_SLOT_TIME_ENABLED) \ + CFG(CFG_CHANNEL_BONDING_MODE) \ + CFG(CFG_BLOCK_ACK_ENABLED) \ + CFG(CFG_ENABLE_AMPDUPS) \ + CFG(CFG_CHANNEL_BONDING_MODE_24GHZ) \ + CFG(CFG_CHANNEL_BONDING_MODE_5GHZ) \ + CFG(CFG_ALLOW_UPDATE_CHANNEL_WIDTH) + +#endif /* __CFG_MLME_FEATURE_FLAG_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_generic.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_generic.h new file mode 100644 index 0000000000..c2993e10e4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_generic.h @@ -0,0 +1,1304 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_GENERIC_H +#define __CFG_MLME_GENERIC_H + +#define CFG_PMF_SA_QUERY_MAX_RETRIES_TYPE CFG_INI_UINT +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL_TYPE CFG_INI_UINT + +/** + * enum monitor_mode_concurrency - Monitor mode concurrency + * @MONITOR_MODE_CONC_NO_SUPPORT: No concurrency supported with monitor mode + * @MONITOR_MODE_CONC_STA_SCAN_MON: STA + monitor mode concurrency is supported + * @MONITOR_MODE_CONC_AFTER_LAST: last value in enum + * @MONITOR_MODE_CONC_MAX: max value supported + */ +enum monitor_mode_concurrency { + MONITOR_MODE_CONC_NO_SUPPORT, + MONITOR_MODE_CONC_STA_SCAN_MON, + MONITOR_MODE_CONC_AFTER_LAST, + MONITOR_MODE_CONC_MAX = MONITOR_MODE_CONC_AFTER_LAST - 1, +}; + +/** + * enum wlan_wds_mode - wds mode + * @WLAN_WDS_MODE_DISABLED: WDS is disabled + * @WLAN_WDS_MODE_REPEATER: WDS repeater mode + * @WLAN_WDS_MODE_LAST: last value in enum + * @WLAN_WDS_MODE_MAX: max value supported + * This is used for 'type' values in wds_mode + */ +enum wlan_wds_mode { + WLAN_WDS_MODE_DISABLED = 0, + WLAN_WDS_MODE_REPEATER = 1, + /* keep this last */ + WLAN_WDS_MODE_LAST, + WLAN_WDS_MODE_MAX = WLAN_WDS_MODE_LAST - 1, +}; + +/** + * enum wlan_eht_mode - EHT mode of operation + * @WLAN_EHT_MODE_DISABLED: EHT is disabled + * @WLAN_EHT_MODE_SLO: Single-link operation mode + * @WLAN_EHT_MODE_MLSR: Multi-link Single-Radio mode + * @WLAN_EHT_MODE_MLMR: Multi-link Multi-Radio mode + * @WLAN_EHT_MODE_EMLSR: Enhanced Multi-link Single-Radio mode + * @WLAN_EHT_MODE_LAST: last value in enum + * @WLAN_EHT_MODE_MAX: max value supported + * + * This is used for 'type' values in eht_mode + */ +enum wlan_eht_mode { + WLAN_EHT_MODE_DISABLED = 0, + WLAN_EHT_MODE_SLO = 1, + WLAN_EHT_MODE_MLSR = 2, + WLAN_EHT_MODE_MLMR = 3, + WLAN_EHT_MODE_EMLSR = 4, + /* keep this last */ + WLAN_EHT_MODE_LAST, + WLAN_EHT_MODE_MAX = WLAN_EHT_MODE_LAST - 1, +}; + +/** + * enum wlan_emlsr_action_mode - EMLSR action mode + * @WLAN_EMLSR_MODE_DISABLED: EMLSR is disabled + * @WLAN_EMLSR_MODE_ENTER: Enter EMLSR operation mode + * @WLAN_EMLSR_MODE_EXIT: Exit EMLSR operation mode + * @WLAN_EMLSR_MODE_LAST: last value in enum + * @WLAN_EMLSR_MODE_MAX: max value supported + * + * This is used for 'type' values in emlsr_mode + */ +enum wlan_emlsr_action_mode { + WLAN_EMLSR_MODE_DISABLED = 0, + WLAN_EMLSR_MODE_ENTER = 1, + WLAN_EMLSR_MODE_EXIT = 2, + /* keep this last */ + WLAN_EMLSR_MODE_LAST, + WLAN_EMLSR_MODE_MAX = WLAN_EMLSR_MODE_LAST - 1, +}; + +/** + * enum wlan_t2lm_negotiation_support - TID-to-link mapping negotiation support + * @WLAN_T2LM_DISABLE: T2LM support is disabled + * @WLAN_T2LM_SAME_LINK_SET: Mapping of all TIDs to the same link set, both DL + * and UL + * @WLAN_T2LM_RESERVED: This value is Reserved + * @WLAN_T2LM_SAME_DIFF_LINK_SET: Mapping of each TID to the same or different + * link set + * @WLAN_T2LM_SUPPORT_LAST: last value in enum + * @WLAN_T2LM_SUPPORT_MAX: max value supported + * + * This is used for 'type' values in T2LM support + */ +enum wlan_t2lm_negotiation_support { + WLAN_T2LM_DISABLE = 0, + WLAN_T2LM_SAME_LINK_SET = 1, + WLAN_T2LM_RESERVED = 2, + WLAN_T2LM_SAME_DIFF_LINK_SET = 3, + /* keep this last */ + WLAN_T2LM_SUPPORT_LAST, + WLAN_T2LM_SUPPORT_MAX = WLAN_T2LM_SUPPORT_LAST - 1, +}; + +/** + * enum debug_packet_log_type - Debug packet log type + * @DEBUG_PKTLOG_TYPE_NONE: Debug packet log is disabled + * @DEBUG_PKTLOG_TYPE_MGMT: Management frames logging is enabled. + * @DEBUG_PKTLOG_TYPE_EAPOL: EAPOL packets logging is enabled. + * @DEBUG_PKTLOG_TYPE_DHCP: DHCP packets logging is enabled. + * @DEBUG_PKTLOG_TYPE_ACTION: Action frames logging is enabled. + * @DEBUG_PKTLOG_TYPE_ARP: ARP packets logging is enabled. + */ +enum debug_packet_log_type { + DEBUG_PKTLOG_TYPE_NONE = 0x0, + DEBUG_PKTLOG_TYPE_MGMT = 0x1, + DEBUG_PKTLOG_TYPE_EAPOL = 0x2, + DEBUG_PKTLOG_TYPE_DHCP = 0x4, + DEBUG_PKTLOG_TYPE_ACTION = 0x8, + DEBUG_PKTLOG_TYPE_ARP = 0x10, +}; + +/** + * enum t2lm_negotiation_support: t2lm negotiation supported + * @T2LM_NEGOTIATION_DISABLED: T2LM is disabled + * @T2LM_NEGOTIATION_ALL_TIDS_TO_SUBSET_OF_LINKS: supports the mapping + * of all TIDs to the same link set both DL and UL. + * @T2LM_NEGOTIATION_RESERVED: + * this mapping value is reserved. + * @T2LM_NEGOTIATION_DISJOINT_MAPPING: supports the mapping of + * each TID to the same or different link set. + * @T2LM_NEGOTIATION_LAST: last value in enum + * @T2LM_NEGOTIATION_MAX: max value supported + */ +enum t2lm_negotiation_support { + T2LM_NEGOTIATION_DISABLED = 0, + T2LM_NEGOTIATION_ALL_TIDS_TO_SUBSET_OF_LINKS = 1, + T2LM_NEGOTIATION_RESERVED = 2, + T2LM_NEGOTIATION_DISJOINT_MAPPING = 3, + T2LM_NEGOTIATION_LAST, + /* keep this last */ + T2LM_NEGOTIATION_MAX = T2LM_NEGOTIATION_LAST - 1, +}; + +/** + * enum wlan_epcs_capability - EPCS capability + * @WLAN_EPCS_CAP_DISABLED: EPCS capability disable + * @WLAN_EPCS_CAP_ENABLE: EPCS capability enable + * @WLAN_EPCS_CAP_LAST: last value in enum + * @WLAN_EPCS_CAP_MAX: max value supported + */ +enum wlan_epcs_capability { + WLAN_EPCS_CAP_DISABLED = 0, + WLAN_EPCS_CAP_ENABLE = 1, + /* keep this last */ + WLAN_EPCS_CAP_LAST, + WLAN_EPCS_CAP_MAX = WLAN_EPCS_CAP_LAST - 1, +}; + +/** + * enum wlan_epcs_frame - EPCS frame type + * @WLAN_EPCS_FRAME_TEARDOWN: EPCS teardown frame + * @WLAN_EPCS_FRAME_REQUEST: EPCS request frame + * @WLAN_EPCS_FRAME_LAST: last value in enum + * @WLAN_EPCS_FRAME_MAX: max value supported + */ +enum wlan_epcs_frame { + WLAN_EPCS_FRAME_TEARDOWN = 0, + WLAN_EPCS_FRAME_REQUEST = 1, + /* keep this last */ + WLAN_EPCS_FRAME_LAST, + WLAN_EPCS_FRAME_MAX = WLAN_EPCS_FRAME_LAST - 1, +}; + +/* + * pmfSaQueryMaxRetries - Control PMF SA query retries for SAP + * @Min: 0 + * @Max: 20 + * @Default: 5 + * + * This ini to set the number of PMF SA query retries for SAP + * + * Related: None. + * + * Supported Feature: PMF(11W) + * + */ +#define CFG_PMF_SA_QUERY_MAX_RETRIES CFG_PMF_SA_QUERY_MAX_RETRIES_TYPE( \ + "pmfSaQueryMaxRetries", \ + 0, \ + 20, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "PMF SA query retries for SAP") +/* + * pmfSaQueryRetryInterval - Control PMF SA query retry interval + * for SAP in ms + * @Min: 10 + * @Max: 2000 + * @Default: 200 + * + * This ini to set the PMF SA query retry interval for SAP in ms + * + * Related: None. + * + * Supported Feature: PMF(11W) + * + */ +#define CFG_PMF_SA_QUERY_RETRY_INTERVAL CFG_PMF_SA_QUERY_RETRY_INTERVAL_TYPE( \ + "pmfSaQueryRetryInterval", \ + 10, \ + 2000, \ + 200, \ + CFG_VALUE_OR_DEFAULT, \ + "PMF SA query retry interval for SAP") + +#ifdef WLAN_FEATURE_11BE +/* + * oem_eht_mlo_crypto_bitmap - OEM control to allow various EHT connection + * options using bitmap based on following ENUM (Name of ENUM to be added) + * @Min: 0x0 + * @Max: 0xFFFFFFFF + * @Default: 0x20008 - To allow MLO WPA2-PMF cap APs and WPA3-SAE w/o H2E cap + * + * This INI is used to control the driver candidate selection and EHT + * connection choice based on OEM configuration. The bitmap follows the + * implementation from wlan_crypto_oem_eht_mlo_config enum + */ +#define CFG_OEM_EHT_MLO_CRYPTO_BITMAP CFG_INI_UINT( \ + "oem_eht_mlo_crypto_bitmap", \ + 0x0, \ + 0xFFFFFFFF, \ + 0x20008, \ + CFG_VALUE_OR_DEFAULT, \ + "OEM control to allow/disallow crypto to EHT configuration") + +#define CFG_OEM_EHT_MLO_CRYPTO_BITMAP_SUPPORTED \ + CFG(CFG_OEM_EHT_MLO_CRYPTO_BITMAP) +#else +#define CFG_OEM_EHT_MLO_CRYPTO_BITMAP_SUPPORTED +#endif + +/* + * + * enable_rtt_mac_randomization - Enable/Disable rtt mac randomization + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Usage: External + * + * + */ +#define CFG_ENABLE_RTT_MAC_RANDOMIZATION CFG_INI_BOOL( \ + "enable_rtt_mac_randomization", \ + 1, \ + "Enable RTT MAC randomization") + +#define CFG_RTT3_ENABLE CFG_BOOL( \ + "rtt3_enabled", \ + 1, \ + "RTT3 enable/disable info") + +/* + * + * g11hSupportEnabled - Enable 11h support + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set 11h support flag + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_11H_SUPPORT_ENABLED CFG_INI_BOOL( \ + "g11hSupportEnabled", \ + 1, \ + "11h Enable Flag") + +/* + * + * g11dSupportEnabled - Enable 11d support + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set 11d support flag + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_11D_SUPPORT_ENABLED CFG_INI_BOOL( \ + "g11dSupportEnabled", \ + 1, \ + "11d Enable Flag") + +/* + * rf_test_mode_enabled - Enable rf test mode support + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to set rf test mode support flag + * by default 6 G Hz security check will be enabled + * with rf test mode as disabled. + * + * Related: None + * + * Supported Feature: STA + */ +#define CFG_RF_TEST_MODE_SUPP_ENABLED CFG_BOOL( \ + "rf_test_mode_enabled", \ + 0, \ + "rf test mode Enable Flag") + +#ifdef CONFIG_BAND_6GHZ +/* + * disable_vlp_sta_conn_to_sp_ap - Disable VLP STA connection to SP AP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to disable connection when AP is operating in 6 GHz + * SP mode but STA doesn't support SP mode and supports VLP mode. + * + * Related: None + * + * Supported Feature: STA + */ +#define CFG_DISABLE_VLP_STA_CONN_TO_SP_AP CFG_BOOL( \ + "disable_vlp_sta_conn_to_sp_ap", \ + 0, \ + "disable vlp sta conn to sp ap") +#define CFG_DIS_VLP_STA_CONN_TO_SP_AP CFG(CFG_DISABLE_VLP_STA_CONN_TO_SP_AP) +#else +#define CFG_DIS_VLP_STA_CONN_TO_SP_AP +#endif + +#ifdef CONFIG_BAND_6GHZ +/* + * standard_6ghz_connection_policy - Enable 6 GHz standard connection policy + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set standard 6 GHz policies where STA will be + * allowed to scan and connect to any 6 GHz AP. + * + * Related: None + * + * Supported Feature: STA + */ +#define CFG_6GHZ_STANDARD_CONNECTION_POLICY CFG_INI_BOOL( \ + "standard_6ghz_connection_policy", \ + 1, \ + "6ghz standard 6 GHZ connection policy") +#define CFG_6GHZ_STD_CONN_POLICY CFG(CFG_6GHZ_STANDARD_CONNECTION_POLICY) +#else +#define CFG_6GHZ_STD_CONN_POLICY +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * emlsr_mode_enable - Enable eMLSR mode support + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to enable eMLSR mode + * If 0 - MLMR mode (Default mode) + * If 1 - eMLSR mode + * + * Related: None + * + * Supported Feature: STA + */ +#define CFG_EMLSR_MODE_ENABLE CFG_BOOL( \ + "emlsr_mode_enable", \ + 0, \ + "eMLSR mode enable flag") +#define CFG_EMLSR_MODE_ENABLED CFG(CFG_EMLSR_MODE_ENABLE) +#else +#define CFG_EMLSR_MODE_ENABLED +#endif + +/* + * + * BandCapability - Preferred band (0: 2.4G, 5G, and 6G, + * 1: 2.4G only, + * 2: 5G only, + * 3: Both 2.4G and 5G, + * 4: 6G only, + * 5: Both 2.4G and 6G, + * 6: Both 5G and 6G, + * 7: 2.4G, 5G, and 6G) + * @Min: 0 + * @Max: 7 + * @Default: 7 + * + * This ini is used to set default band capability + * (0: Both 2.4G and 5G, 1: 2.4G only, 2: 5G only, 3: Both 2.4G and 5G, + * 4: 6G only, 5: Both 2.4G and 6G, 6: Both 5G and 6G, 7: 2.4G, 5G, and 6G) + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_BAND_CAPABILITY CFG_INI_UINT( \ + "BandCapability", \ + 0, \ + 7, \ + 7, \ + CFG_VALUE_OR_DEFAULT, \ + "Band Capability") + +/* + * + * gPreventLinkDown - Enable to prevent bus link from going down + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Enable to prevent bus link from going down. Useful for platforms that do not + * (yet) support link down suspend cases. + * + * Related: N/A + * + * Supported Feature: Suspend/Resume + * + * Usage: Internal + * + * + */ +#if defined(QCA_WIFI_EMULATION) || defined(QCA_WIFI_QCA6290) +#define CFG_PREVENT_LINK_DOWN CFG_INI_BOOL( \ + "gPreventLinkDown", \ + 1, \ + "Prevent Bus Link Down") +#else +#define CFG_PREVENT_LINK_DOWN CFG_INI_BOOL( \ + "gPreventLinkDown", \ + 0, \ + "Prevent Bus Link Down") +#endif /* QCA_WIFI_EMULATION */ + +/* + * + * gSelect5GHzMargin - Sets RSSI preference for 5GHz over 2.4GHz AP. + * @Min: 0 + * @Max: 60 + * @Default: 0 + * + * Prefer connecting to 5G AP even if its RSSI is lower by gSelect5GHzMargin + * dBm than 2.4G AP. This feature requires the dependent cfg.ini + * "gRoamPrefer5GHz" set to 1 + * + * Related: gRoamPrefer5GHz + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_SELECT_5GHZ_MARGIN CFG_INI_UINT( \ + "gSelect5GHzMargin", \ + 0, \ + 60, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Select 5Ghz Margin") + +/* + * + * gEnableMemDeepSleep - Sets Memory Deep Sleep on/off. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This option enables/disables memory deep sleep. + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_ENABLE_MEM_DEEP_SLEEP CFG_INI_BOOL( \ + "gEnableMemDeepSleep", \ + 1, \ + "Enable Memory Deep Sleep") + +/* + * + * + * gEnableCckTxFirOverride - Enable/disable CCK TxFIR Override + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 0 (disabled) + * + * When operating in an 802.11b mode, this configuration item forces a 2x2 radio + * configuration into 1x for Tx and 2x for Rx (ie 1x2) for regulatory compliance + * reasons. + * + * Related: enable2x2 + * + * Supported Feature: 802.11b, 2x2 + * + * Usage: External + * + * + */ +#define CFG_ENABLE_CCK_TX_FIR_OVERRIDE CFG_INI_BOOL( \ + "gEnableCckTxFirOverride", \ + 0, \ + "Enable CCK TX FIR Override") + +/* + * + * + * gEnableForceTargetAssert - Enable/disable SSR + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 0 (disabled) + * + * This INI item is used to control subsystem restart(SSR) test framework + * Set it's value to 1 to enable APPS triggered SSR testing + * + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_ENABLE_CRASH_INJECT CFG_INI_BOOL( \ + "gEnableForceTargetAssert", \ + 0, \ + "Enable Crash Inject") + +/* + * + * + * gEnableLpassSupport - Enable/disable LPASS Support + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 1 (disabled) if WLAN_FEATURE_LPSS is defined, 0 otherwise + * + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#ifdef WLAN_FEATURE_LPSS +#define CFG_ENABLE_LPASS_SUPPORT CFG_INI_BOOL( \ + "gEnableLpassSupport", \ + 1, \ + "Enable LPASS Support") +#else +#define CFG_ENABLE_LPASS_SUPPORT CFG_BOOL( \ + "gEnableLpassSupport", \ + 0, \ + "Enable LPASS Support") +#endif + +/* + * + * + * gEnableSelfRecovery - Enable/disable Self Recovery + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 0 (disabled) + * + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SELF_RECOVERY CFG_INI_BOOL( \ + "gEnableSelfRecovery", \ + 0, \ + "Enable Self Recovery") + +/* + * + * + * gSapDot11mc - Enable/disable SAP 802.11mc support + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 0 (disabled) + * + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_SAP_DOT11MC CFG_INI_BOOL( \ + "gSapDot11mc", \ + 0, \ + "SAP 802.11mc support") + +/* + * + * + * gEnableFatalEvent - Enable/Disable BUG report in case of fatal event + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 1 (enabled) + * + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_ENABLE_FATAL_EVENT_TRIGGER CFG_INI_BOOL( \ + "gEnableFatalEvent", \ + 1, \ + "Enable Fatal Event Trigger") + +/* + * + * gSub20ChannelWidth - Control sub 20 channel width (5/10 Mhz) + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set the sub 20 channel width. + * gSub20ChannelWidth=0: indicates do not use Sub 20 MHz bandwidth + * gSub20ChannelWidth=1: Bring up SAP/STA in 5 MHz bandwidth + * gSub20ChannelWidth=2: Bring up SAP/STA in 10 MHz bandwidth + * + * Related: None + * + * Supported Feature: 5/10 Mhz channel width support + * + * Usage: External + * + * + */ +#define CFG_SUB_20_CHANNEL_WIDTH CFG_INI_UINT( \ + "gSub20ChannelWidth", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Sub 20 Channel Width") + +/* + * + * goptimize_chan_avoid_event - Optimize channel avoidance indication + * coming from firmware + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: None + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_OPTIMIZE_CA_EVENT CFG_INI_BOOL( \ + "goptimize_chan_avoid_event", \ + 0, \ + "Optimize FW CA Event") + +/* + * + * fw_timeout_crash - Enable/Disable BUG ON + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to Trigger host crash when firmware fails to send the + * response to host + * fw_timeout_crash = 0 Disabled + * fw_timeout_crash = 1 Trigger host crash + * + * Related: None + * + * Supported Feature: SSR + * + * Usage: External + * + * + */ +#define CFG_CRASH_FW_TIMEOUT CFG_INI_BOOL( \ + "fw_timeout_crash", \ + 1, \ + "Enable FW Timeout Crash") + +/* + * + * gDroppedPktDisconnectTh - Sets dropped packet threshold in firmware + * @Min: 0 + * @Max: 65535 + * @Default: 512 + * + * This INI is the packet drop threshold will trigger disconnect from remote + * peer. + * + * Related: None + * + * Supported Feature: connection + * + * Usage: External + * + * + */ +#define CFG_DROPPED_PKT_DISCONNECT_THRESHOLD CFG_INI_UINT( \ + "gDroppedPktDisconnectTh", \ + 0, \ + 65535, \ + 512, \ + CFG_VALUE_OR_DEFAULT, \ + "Dropped Pkt Disconnect threshold") + +/* + * + * gItoRepeatCount - sets ito repeated count + * @Min: 0 + * @Max: 5 + * @Default: 0 + * + * This ini sets the ito count in FW + * + * Usage: External + * + * + */ +#define CFG_ITO_REPEAT_COUNT CFG_INI_UINT( \ + "gItoRepeatCount", \ + 0, \ + 5, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "ITO Repeat Count") + +/* + * + * gEnableDeauthToDisassocMap - Enables deauth to disassoc map + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default disassoc map + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP CFG_INI_BOOL( \ + "gEnableDeauthToDisassocMap", \ + 0, \ + "Enables deauth to disassoc map") + +/* + * + * gEnableDebugLog - Enable/Disable the Connection related logs + * @Min: 0 + * @Max: 0xFF + * @Default: 0x01 + * + * This ini is used to enable/disable the connection related logs + * 0x1 - Enable mgmt pkt logs (except probe req/rsp, beacons). + * 0x2 - Enable EAPOL pkt logs. + * 0x4 - Enable DHCP pkt logs. + * 0x8 - Enable mgmt action frames logs. + * 0x10 - Enable ARP pkt logs. + * 0x0 - Disable all the above connection related logs. + * The default value of 0x01 will enable all the mgmt logs + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DEBUG_PACKET_LOG CFG_INI_UINT( \ + "gEnableDebugLog", \ + 0, 0xFF, 0x01, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable debug log") + +/* + * + * enable_beacon_reception_stats - Enable disable beacon reception stats + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable the beacon reception stats collected per + * vdev and then sent to the driver to be displayed in sysfs + * + * Related: None + * + * Supported Feature: Stats + * + * Usage: External + * + * + */ + #define CFG_ENABLE_BEACON_RECEPTION_STATS CFG_INI_BOOL( \ + "enable_beacon_reception_stats", \ + 0, \ + "Enable disable beacon reception stats") + +/* + * + * disable_4way_hs_offload - Enable/Disable 4 way handshake offload to firmware + * @Min: 0 + * @Max: 0x2 + * @Default: 0x2 + * + * 0x0 - 4-way HS to be handled in firmware for the AKMs except for SAE and + * OWE roaming the 4way HS is handled in supplicant by default + * 0x1 - 4-way HS to be handled in supplicant + * 0x2 - 4-way HS to be handled in firmware for the AKMs including the SAE + * Roam except for OWE roaming the 4way HS is handled in supplicant + * + * Based on the requirement the Max value can be increased per AKM. + * + * Related: None + * + * Supported Feature: STA Roaming + * + * Usage: External + * + * + */ +#define CFG_DISABLE_4WAY_HS_OFFLOAD CFG_INI_UINT( \ + "disable_4way_hs_offload", \ + 0, \ + 0x2, \ + 0x2, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable/disable 4 way handshake offload to firmware") + +/* + * + * mgmt_retry_max - Maximum Retries for mgmt frames + * @Min: 0 + * @Max: 31 + * @Default: 15 + * + * This ini is used to set maximum retries for mgmt frames + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ +#define CFG_MGMT_RETRY_MAX CFG_INI_UINT( \ + "mgmt_retry_max", \ + 0, \ + 31, \ + 15, \ + CFG_VALUE_OR_DEFAULT, \ + "Max retries for mgmt frames") + +/* + * + * enable_he_mcs0_for_mgmt_6ghz- if disabled FW will use 6Mbps 11A rate + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * If this ini is disabled firmware will use 6Mbps 11A rate + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ +#define CFG_ENABLE_HE_MCS0_MGMT_6GHZ CFG_INI_BOOL( \ + "enable_he_mcs0_for_mgmt_6ghz", \ + 0, \ + "MCS0 rate for 6ghz mgmt frames") + +/* + * + * bmiss_skip_full_scan - To decide whether firmware does channel map based + * partial scan or partial scan followed by full scan in case no candidate is + * found in partial scan. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * 0 : Based on the channel map , firmware does scan to find new AP. if AP is + * not found then it does a full scan on all valid channels. + * 1 : Firmware does channel map based partial scan only. + * + * Related: None + * + * Supported Feature: STA Roaming + * + * Usage: External + * + * + */ +#define CFG_BMISS_SKIP_FULL_SCAN CFG_INI_BOOL("bmiss_skip_full_scan", \ + 0, \ + "To decide partial/partial scan followed by full scan") + +/* + * + * gEnableRingBuffer - Enable Ring Buffer for Bug Report + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable Ring Buffer + * + * Related: None + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ +#define CFG_ENABLE_RING_BUFFER CFG_INI_BOOL( \ + "gEnableRingBuffer", \ + 1, \ + "To Enable Ring Buffer") + +/* + * + * dfs_chan_ageout_time - Set DFS Channel ageout time(in seconds) + * @Min: 0 + * @Max: 8 + * Default: 0 + * + * Ageout time is the time upto which DFS channel information such as beacon + * found is remembered. So that Firmware performs Active scan instead of the + * Passive to reduce the Dwell time. + * This ini Parameter used to set ageout timer value from host to FW. + * If not set, Firmware will disable ageout time. + * + * Supported Feature: STA scan in DFS channels + * + * Usage: External + * + * + */ +#define CFG_DFS_CHAN_AGEOUT_TIME CFG_INI_UINT("dfs_chan_ageout_time", \ + 0, 8, 0, CFG_VALUE_OR_DEFAULT, \ + "Set DFS Channel ageout time from host to firmware") + +/* + * + * sae_connect_retries - Bit mask to retry Auth and full connection on assoc + * timeout to same AP and auth retries during roaming + * @Min: 0x0 + * @Max: 0x53 + * @Default: 0x52 + * + * This ini is used to set max auth retry in auth phase of roaming and initial + * connection and max connection retry in case of assoc timeout. MAX Auth + * retries are capped to 3, connection retries are capped to 2 and roam Auth + * retry is capped to 1. + * Default is 0x52 i.e. 1 roam auth retry, 2 auth retry and 2 full connection + * retry. + * + * Bits Retry Type + * BIT[0:2] AUTH retries + * BIT[3:5] Connection reties + * BIT[6:8] ROAM AUTH retries + * + * Some Possible values are as below + * 0 - NO auth/roam Auth retry and NO full connection retry after + * assoc timeout + * 0x49 - 1 auth/roam auth retry and 1 full connection retry + * 0x52 - 1 roam auth retry, 2 auth retry and 2 full connection retry + * 0x1 /0x2 - 0 roam auth retry, 1 or 2 auth retry respectively and NO full + * connection retry + * 0x8 /0x10 - 0 roam auth retry,NO auth retry and 1 or 2 full connection retry + * respectively. + * 0x4A - 1 roam auth retry,2 auth retry and 1 full connection retry + * 0x51 - 1 auth/roam auth retry and 2 full connection retry + * + * Related: None + * + * Supported Feature: STA SAE + * + * Usage: External + * + * + */ +#define CFG_SAE_CONNECION_RETRIES CFG_INI_UINT("sae_connect_retries", \ + 0, 0x53, 0x52, CFG_VALUE_OR_DEFAULT, \ + "Bit mask to retry Auth and full connection on assoc timeout to same AP for SAE connection") + +/* + * + * + * wls_6ghz_capable - WiFi Location Service(WLS) is 6Ghz capable + * @Min: 0 (WLS 6Ghz non-capable) + * @Max: 1 (WLS 6Ghz capable) + * @Default: 0 (WLS 6Ghz non-capable) + * + * Related: None + * + * Supported Feature: General + * + * Usage: Internal + * + * + */ +#define CFG_WLS_6GHZ_CAPABLE CFG_INI_BOOL( \ + "wls_6ghz_capable", \ + 0, \ + "WiFi Location Service(WLS) is 6Ghz capable or not") + +/* + * + * + * monitor_mode_conc - Monitor mode concurrency supported + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: None + * + * Monitor mode concurrency supported + * 0 - No concurrency supported + * 1 - Allow STA scan + Monitor mode concurrency + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_MONITOR_MODE_CONCURRENCY CFG_INI_UINT( \ + "monitor_mode_concurrency", \ + MONITOR_MODE_CONC_NO_SUPPORT, \ + MONITOR_MODE_CONC_MAX, \ + MONITOR_MODE_CONC_NO_SUPPORT, \ + CFG_VALUE_OR_DEFAULT, \ + "Monitor mode concurrency supported") + +#ifdef FEATURE_WDS +/* + * + * + * wds_mode - wds mode supported + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: None + * + * wds mode supported + * 0 - wds mode disabled + * 1 - wds repeater mode + * + * Supported Feature: General + * + * Usage: External + * + * + */ +#define CFG_WDS_MODE CFG_INI_UINT( \ + "wds_mode", \ + WLAN_WDS_MODE_DISABLED, \ + WLAN_WDS_MODE_MAX, \ + WLAN_WDS_MODE_DISABLED, \ + CFG_VALUE_OR_DEFAULT, \ + "wds mode supported") + +#define CFG_WDS_MODE_ALL CFG(CFG_WDS_MODE) +#else +#define CFG_WDS_MODE_ALL +#endif + +/* + * + * tx_retry_multiplier - TX retry multiplier + * @Min: 0 + * @Max: 500 + * @Default: 0 + * + * This ini is used to indicate percentage to max retry limit to fw + * which can further be used by fw to multiply counter by + * tx_retry_multiplier percent. + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ +#define CFG_TX_RETRY_MULTIPLIER CFG_INI_UINT( \ + "tx_retry_multiplier", \ + 0, \ + 500, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "percentage of max retry limit") + +/* + * + * mgmt_frame_hw_tx_retry_count - Set hw tx retry count for mgmt action + * frame + * @Min: N/A + * @Max: N/A + * @Default: N/A + * + * Set mgmt action frame hw tx retry count, string format looks like below: + * frame_hw_tx_retry_count=",,..." + * frame type is enum value of mlme_cfg_frame_type. + * Retry count max value is 127. + * For example: + * frame_hw_tx_retry_count="0,64,2,32" + * The above input string means: + * For p2p go negotiation request fame, hw retry count 64 + * For p2p provision discovery request, hw retry count 32 + * + * Related: None. + * + * Supported Feature: STA/P2P + * + * Usage: External + * + * + */ +#define MGMT_FRM_HW_TX_RETRY_COUNT_STR_LEN (64) +#define CFG_MGMT_FRAME_HW_TX_RETRY_COUNT CFG_INI_STRING( \ + "mgmt_frame_hw_tx_retry_count", \ + 0, \ + MGMT_FRM_HW_TX_RETRY_COUNT_STR_LEN, \ + "", \ + "Set mgmt action frame hw tx retry count") + +#if defined(WLAN_FEATURE_SR) +/* + * + * sr_enable_modes - Modes for which SR(Spatial Reuse) feature can be enabled + * @Min: 0x00 + * @Max: 0xf + * @Default: 0x1 + * + * This ini is used to check for which mode SR feature is enabled + * + * Bit 0: Enable/Disable SR feature for STA + * Bit 1: Enable/Disable SR feature for SAP + * Bit 2: Enable/Disable SR feature for P2P CLI + * Bit 3: Enable/Disable SR feature for P2P GO + * + * Related: None + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ +#define CFG_SR_ENABLE_MODES CFG_INI_UINT( \ + "sr_enable_modes",\ + 0x0,\ + 0xf,\ + 0x1,\ + CFG_VALUE_OR_DEFAULT, \ + "To decide for which mode SR feature is enabled") +#define CFG_SR_ENABLE_MODES_ALL CFG(CFG_SR_ENABLE_MODES) +#else +#define CFG_SR_ENABLE_MODES_ALL +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * t2lm_negotiation_support - T2LM negotiation support by STA + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * This cfg is used to define t2lm negotiation supported value by STA + * If 0 - t2lm negotiation is not supported + * If 1 - supports the mapping of all TIDs to the same link set both DL and UL. + * If 2 - reserved + * If 3 - supports the mapping of each TID to the same or different link set. + * + * Related: None + * + * Supported Feature: STA + */ +#define CFG_T2LM_NEGOTIATION_SUPPORT CFG_INI_UINT( \ + "t2lm_negotiation_supported", \ + T2LM_NEGOTIATION_DISABLED, \ + T2LM_NEGOTIATION_DISJOINT_MAPPING, \ + T2LM_NEGOTIATION_ALL_TIDS_TO_SUBSET_OF_LINKS, \ + CFG_VALUE_OR_DEFAULT, \ + "T2LM negotiation supported value") + +#define CFG_T2LM_NEGOTIATION_SUPPORTED CFG(CFG_T2LM_NEGOTIATION_SUPPORT) +#else +#define CFG_T2LM_NEGOTIATION_SUPPORTED +#endif + +#define CFG_GENERIC_ALL \ + CFG(CFG_ENABLE_DEBUG_PACKET_LOG) \ + CFG(CFG_PMF_SA_QUERY_MAX_RETRIES) \ + CFG(CFG_PMF_SA_QUERY_RETRY_INTERVAL) \ + CFG_OEM_EHT_MLO_CRYPTO_BITMAP_SUPPORTED \ + CFG(CFG_ENABLE_RTT_MAC_RANDOMIZATION) \ + CFG(CFG_RTT3_ENABLE) \ + CFG(CFG_11H_SUPPORT_ENABLED) \ + CFG(CFG_11D_SUPPORT_ENABLED) \ + CFG(CFG_BAND_CAPABILITY) \ + CFG(CFG_PREVENT_LINK_DOWN) \ + CFG(CFG_SELECT_5GHZ_MARGIN) \ + CFG(CFG_ENABLE_MEM_DEEP_SLEEP) \ + CFG(CFG_ENABLE_CCK_TX_FIR_OVERRIDE) \ + CFG(CFG_ENABLE_CRASH_INJECT) \ + CFG(CFG_ENABLE_LPASS_SUPPORT) \ + CFG(CFG_ENABLE_SELF_RECOVERY) \ + CFG(CFG_ENABLE_DEAUTH_TO_DISASSOC_MAP) \ + CFG(CFG_DISABLE_4WAY_HS_OFFLOAD) \ + CFG(CFG_SAP_DOT11MC) \ + CFG(CFG_ENABLE_FATAL_EVENT_TRIGGER) \ + CFG(CFG_SUB_20_CHANNEL_WIDTH) \ + CFG(CFG_OPTIMIZE_CA_EVENT) \ + CFG(CFG_CRASH_FW_TIMEOUT) \ + CFG(CFG_DROPPED_PKT_DISCONNECT_THRESHOLD) \ + CFG(CFG_ITO_REPEAT_COUNT) \ + CFG(CFG_ENABLE_BEACON_RECEPTION_STATS) \ + CFG(CFG_MGMT_RETRY_MAX) \ + CFG(CFG_ENABLE_HE_MCS0_MGMT_6GHZ) \ + CFG(CFG_BMISS_SKIP_FULL_SCAN) \ + CFG(CFG_ENABLE_RING_BUFFER) \ + CFG(CFG_DFS_CHAN_AGEOUT_TIME) \ + CFG(CFG_SAE_CONNECION_RETRIES) \ + CFG(CFG_WLS_6GHZ_CAPABLE) \ + CFG(CFG_MONITOR_MODE_CONCURRENCY) \ + CFG(CFG_RF_TEST_MODE_SUPP_ENABLED) \ + CFG_WDS_MODE_ALL \ + CFG(CFG_TX_RETRY_MULTIPLIER) \ + CFG(CFG_MGMT_FRAME_HW_TX_RETRY_COUNT) \ + CFG_6GHZ_STD_CONN_POLICY \ + CFG_EMLSR_MODE_ENABLED \ + CFG_SR_ENABLE_MODES_ALL \ + CFG_T2LM_NEGOTIATION_SUPPORTED\ + CFG_DIS_VLP_STA_CONN_TO_SP_AP +#endif /* __CFG_MLME_GENERIC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_he_caps.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_he_caps.h new file mode 100644 index 0000000000..fe28374ea0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_he_caps.h @@ -0,0 +1,975 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_HE_CAPS_H +#define __CFG_MLME_HE_CAPS_H + +#define CFG_HE_CONTROL CFG_BOOL( \ + "he_control", \ + 0, \ + "HE Control") + +#define CFG_HE_FRAGMENTATION CFG_UINT( \ + "he_fragmentation", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Fragmentation") + +#define CFG_HE_MAX_FRAG_MSDU CFG_UINT( \ + "he_max_frag_msdu", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Max Frag Msdu") + +#define CFG_HE_MIN_FRAG_SIZE CFG_UINT( \ + "he_min_frag_size", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Min Frag Size") + +#define CFG_HE_TRIG_PAD CFG_UINT( \ + "he_trig_pad", \ + 0, \ + 2, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Trig Pad") + +#define CFG_HE_MTID_AGGR_RX CFG_UINT( \ + "he_mtid_aggr_rx", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Mtid Aggr") + +#define CFG_HE_LINK_ADAPTATION CFG_UINT( \ + "he_link_adaptation", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Link Adaptation") + +#define CFG_HE_ALL_ACK CFG_BOOL( \ + "he_all_ack", \ + 0, \ + "HE All Ack") + +#define CFG_HE_TRIGD_RSP_SCHEDULING CFG_BOOL( \ + "he_trigd_rsp_scheduling", \ + 0, \ + "HE Trigd Rsp Scheduling") + +#define CFG_HE_BUFFER_STATUS_RPT CFG_BOOL( \ + "he_buffer_status_rpt", \ + 0, \ + "HE Buffer Status Rpt") + +#define CFG_HE_BA_32BIT CFG_BOOL( \ + "he_ba_32bit", \ + 0, \ + "HE BA 32Bit") + +#define CFG_HE_MU_CASCADING CFG_BOOL( \ + "he_mu_cascading", \ + 0, \ + "HE Mu Cascading") + +#define CFG_HE_MULTI_TID CFG_BOOL( \ + "he_multi_tid", \ + 0, \ + "HE Multi Tid") + +#define CFG_HE_OMI CFG_BOOL( \ + "he_omi", \ + 0, \ + "HE Omi") + +#define CFG_HE_OFDMA_RA CFG_BOOL( \ + "he_ofdma_ra", \ + 0, \ + "HE Ofdma Ra") + +#define CFG_HE_MAX_AMPDU_LEN CFG_INI_UINT( \ + "he_max_ampdu_len", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Max Ampdu Len") + +#define CFG_HE_AMSDU_FRAG CFG_BOOL( \ + "he_amspdu_frag", \ + 0, \ + "HE Amsdu Frag") + +#define CFG_HE_FLEX_TWT_SCHED CFG_BOOL( \ + "he_flex_twt_sched", \ + 0, \ + "HE Flex Twt Sched") + +#define CFG_HE_RX_CTRL CFG_BOOL( \ + "he_rx_ctrl", \ + 0, \ + "HE Rx Ctrl") + +#define CFG_HE_BSRP_AMPDU_AGGR CFG_BOOL( \ + "he_bsrp_ampdu_aggr", \ + 0, \ + "He Bspr Ampdu Aggr") + +#define CFG_HE_QTP CFG_BOOL( \ + "he_qtp", \ + 0, \ + "He Qtp") + +#define CFG_HE_A_BQR CFG_BOOL( \ + "he_a_bqr", \ + 0, \ + "He A Bqr") + +#define CFG_HE_SR_RESPONDER CFG_BOOL( \ + "he_sr_responder", \ + 0, \ + "He Sr Responder") + +#define CFG_HE_NDP_FEEDBACK_SUPP CFG_BOOL( \ + "he_ndp_feedback_supp", \ + 0, \ + "He Ndp Feedback Supp") + +#define CFG_HE_OPS_SUPP CFG_BOOL( \ + "he_ops_supp", \ + 0, \ + "He Ops Supp") + +#define CFG_HE_AMSDU_IN_AMPDU CFG_BOOL( \ + "he_amsdu_in_ampdu", \ + 0, \ + "He Amsdu In Ampdu") + +#define CFG_HE_MTID_AGGR_TX CFG_UINT( \ + "he_mtid_aggr_tx", \ + 0, \ + 0x7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He MTid Aggr Tx") + +#define CFG_HE_SUB_CH_SEL_TX CFG_BOOL( \ + "he_sub_ch_sel_tx", \ + 0, \ + "He Sub cg sel tx") + +#define CFG_HE_UL_2X996_RU CFG_BOOL( \ + "he_ul_2x996_ru", \ + 0, \ + "He Ul 2x996 Ru") + +#define CFG_HE_OM_CTRL_UL_MU_DIS_RX CFG_BOOL( \ + "he_om_ctrl_ul_mu_dis_rx", \ + 0, \ + "He Om Ctrl Ul My Dis Rx") + +#define CFG_HE_DYNAMIC_SMPS CFG_BOOL( \ + "he_dynamic_smps", \ + 0, \ + "He Dynamic SMPS") + +#define CFG_HE_PUNCTURED_SOUNDING CFG_BOOL( \ + "he_punctured_sounding", \ + 0, \ + "He Punctured Sounding") + +#define CFG_HE_HT_VHT_TRG_FRM_RX CFG_BOOL( \ + "ht_vht_trg_frm_rx", \ + 0, \ + "HT VHT Trigger frame Rx") + +#define CFG_HE_CHAN_WIDTH CFG_UINT( \ + "he_chan_width", \ + 0, \ + 0x3F, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Chan Width") + +#define CFG_HE_RX_PREAM_PUNC CFG_INI_UINT( \ + "he_rx_pream_punc", \ + 0, \ + 0xF, \ + 0x3, \ + CFG_VALUE_OR_DEFAULT, \ + "He Rx Pream Punc") + +#define CFG_HE_CLASS_OF_DEVICE CFG_BOOL( \ + "he_class_of_device", \ + 0, \ + "He Class Of Device") + +#define CFG_HE_LDPC CFG_BOOL( \ + "he_ldpc", \ + 0, \ + "He Ldpc") + +#define CFG_HE_LTF_PPDU CFG_UINT( \ + "he_ltf_ppdu", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Ltf Ppdu") + +#define CFG_HE_MIDAMBLE_RX_MAX_NSTS CFG_UINT( \ + "he_midamble_rx_max_nsts", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Midamble Rx Max Nsts") + +#define CFG_HE_LTF_NDP CFG_UINT( \ + "he_ltf_ndp", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Ltf Ndp") + +#define CFG_HE_TX_STBC_LT80 CFG_BOOL( \ + "he_tx_stbc_lt80_sta", \ + 0, \ + "He Tx Stbc Lt80") + +#define CFG_HE_RX_STBC_LT80 CFG_BOOL( \ + "he_rx_stbc_lt80", \ + 0, \ + "He Rx Stbc Lt80") + +#define CFG_HE_DOPPLER CFG_UINT( \ + "he_doppler", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Doppler") + +#define CFG_HE_DCM_TX CFG_UINT( \ + "he_dcm_tx", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Dcm Tx") + +#define CFG_HE_DCM_RX CFG_UINT( \ + "he_dcm_rx", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Dcm Rx") + +#define CFG_HE_MU_PPDU CFG_BOOL( \ + "he_mu_ppdu", \ + 0, \ + "He Mu Ppdu") + +#define CFG_HE_SU_BEAMFORMER CFG_BOOL( \ + "he_su_beamformer", \ + 0, \ + "He Su Beamformer") + +#define CFG_HE_SU_BEAMFORMEE CFG_BOOL( \ + "he_su_beamformee", \ + 0, \ + "He Su Beamformee") + +#define CFG_HE_MU_BEAMFORMER CFG_BOOL( \ + "he_mu_beamformer", \ + 0, \ + "He Mu Beamformer") + +#define CFG_HE_BFEE_STS_LT80 CFG_UINT( \ + "he_bfee_sts_lt80", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Mu Bfee Sts Lt80") + +#define CFG_HE_BFEE_STS_GT80 CFG_UINT( \ + "he_bfee_sts_lt80", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Mu Bfee Sts Gt80") + +#define CFG_HE_NUM_SOUND_LT80 CFG_UINT( \ + "he_num_sound_lt80", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Num Sound Lt80") + +#define CFG_HE_NUM_SOUND_GT80 CFG_UINT( \ + "he_num_sound_gt80", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Num Sound Gt80") + +#define CFG_HE_SU_FEED_TONE16 CFG_BOOL( \ + "he_su_feed_tone16", \ + 0, \ + "He Su Feed Tone16") + +#define CFG_HE_MU_FEED_TONE16 CFG_BOOL( \ + "he_mu_feed_tone16", \ + 0, \ + "He Mu Feed Tone16") + +#define CFG_HE_CODEBOOK_SU CFG_BOOL( \ + "he_codebook_su", \ + 0, \ + "He Codebook Su") + +#define CFG_HE_CODEBOOK_MU CFG_BOOL( \ + "he_codebook_mu", \ + 0, \ + "He Codebook Mu") + +#define CFG_HE_BFRM_FEED CFG_UINT( \ + "he_bfrm_feed", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Bfrm Feed") + +#define CFG_HE_ER_SU_PPDU CFG_BOOL( \ + "he_bfrm_feed", \ + 0, \ + "He Er Su Ppdu") + +#define CFG_HE_DL_PART_BW CFG_BOOL( \ + "he_dl_part_bw", \ + 0, \ + "He Dl Part Bw") + +#define CFG_HE_PPET_PRESENT CFG_BOOL( \ + "he_ppet_present", \ + 0, \ + "He Pper Present") + +#define CFG_HE_SRP CFG_BOOL( \ + "he_srp", \ + 0, \ + "He Srp") + +#define CFG_HE_POWER_BOOST CFG_BOOL( \ + "he_power_boost", \ + 0, \ + "He Power Boost") + +#define CFG_HE_4x_LTF_GI CFG_BOOL( \ + "he_4x_ltf_gi", \ + 0, \ + "He 4x Ltf Gi") + +#define CFG_HE_MAX_NC CFG_UINT( \ + "he_max_nc", \ + 0, \ + 7, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Max Nc") + +#define CFG_HE_RX_STBC_GT80 CFG_BOOL( \ + "he_rx_stbc_gt80", \ + 0, \ + "He Rx Stbc Gt80") + +#define CFG_HE_TX_STBC_GT80 CFG_BOOL( \ + "he_Tx_stbc_gt80", \ + 0, \ + "He Tx Stbc Gt80") + +#define CFG_HE_ER_4x_LTF_GI CFG_BOOL( \ + "he_er_4x_ltf_gi", \ + 0, \ + "He Er 4x Ltf Gi") + +#define CFG_HE_PPDU_20_IN_40MHZ_2G CFG_BOOL( \ + "he_ppdu_20_in_40mhz_2g", \ + 0, \ + "He Ppdu 20 In 40Mhz 2g") + +#define CFG_HE_PPDU_20_IN_160_80P80MHZ CFG_BOOL( \ + "he_ppdu_20_in_160_80p80mhz", \ + 0, \ + "He Ppdu 20 In 160 80p80mhz") + +#define CFG_HE_PPDU_80_IN_160_80P80MHZ CFG_BOOL( \ + "he_ppdu_80_in_160_80p80mhz", \ + 0, \ + "He Ppdu 80 In 160 80p80mhz") + +#define CFG_HE_ER_1X_HE_LTF_GI CFG_BOOL( \ + "he_er_1x_he_ltf_gi", \ + 0, \ + "He Er 1x He Ltf Gi") + +#define CFG_HE_MIDAMBLE_TXRX_1X_HE_LTF CFG_BOOL( \ + "he_midamble_txrx_1x_he_ltf", \ + 0, \ + "He Midamble Tx Rx 1x He Ltf") + +#define CFG_HE_DCM_MAX_BW CFG_UINT( \ + "he_dcm_max_bw", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Dcm Max Bw") + +#define CFG_HE_LONGER_16_SIGB_OFDM_SYM CFG_BOOL( \ + "he_longer_16_sigb_ofdm_sys", \ + 0, \ + "He Longer 16 Sigb Ofdm Sys") + +#define CFG_HE_NON_TRIG_CQI_FEEDBACK CFG_BOOL( \ + "he_rx_mcs_map_lt_80", \ + 0, \ + "He Non Trig Cqi Feedback") + +#define CFG_HE_TX_1024_QAM_LT_242_RU CFG_BOOL( \ + "he_tx_1024_qam_lt_242_ru", \ + 0, \ + "He Tx 1024 Qam Lt 242 Ru") + +#define CFG_HE_RX_1024_QAM_LT_242_RU CFG_BOOL( \ + "he_rx_1024_qam_lt_242_ru", \ + 0, \ + "He Rx 1024 Qam Lt 242 Ru") + +#define CFG_HE_RX_FULL_BW_MU_CMPR_SIGB CFG_BOOL( \ + "he_rx_full_bw_cmpr_sigb", \ + 0, \ + "He Rx Full Bw Mu Cmpr Sigb") + +#define CFG_HE_RX_FULL_BW_MU_NON_CMPR_SIGB CFG_BOOL( \ + "he_rx_full_bw_mu_non_cmpr_sigb", \ + 0, \ + "He Rx Full Bw Mu Non Cmpr Sigb") + +/* 11AX related INI configuration */ +/* + * + * he_rx_mcs_map_lt_80 - configure Rx HE-MCS Map for ≤ 80 MHz + * @Min: 0 + * @Max: 0xFFFF + * @Default: 0xFFFA + * + * This ini is used to configure Rx HE-MCS Map for ≤ 80 MHz + * 0:1 Max HE-MCS For 1 SS + * 2:3 Max HE-MCS For 2 SS + * 4:5 Max HE-MCS For 3 SS + * 6:7 Max HE-MCS For 4 SS + * 8:9 Max HE-MCS For 5 SS + * 10:11 Max HE-MCS For 6 SS + * 12:13 Max HE-MCS For 7 SS + * 14:15 Max HE-MCS For 8 SS + * + * 0 indicates support for HE-MCS 0-7 for n spatial streams + * 1 indicates support for HE-MCS 0-9 for n spatial streams + * 2 indicates support for HE-MCS 0-11 for n spatial streams + * 3 indicates that n spatial streams is not supported for HE PPDUs + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_HE_RX_MCS_MAP_LT_80 CFG_INI_UINT( \ + "he_rx_mcs_map_lt_80", \ + 0, \ + 0xFFFF, \ + 0xFFFA, \ + CFG_VALUE_OR_DEFAULT, \ + "He Rx Mcs Map Lt 80") + +/* 11AX related INI configuration */ +/* + * + * he_tx_mcs_map_lt_80 - configure Tx HE-MCS Map for ≤ 80 MHz + * @Min: 0 + * @Max: 0xFFFF + * @Default: 0xFFFA + * + * This ini is used to configure Tx HE-MCS Map for ≤ 80 MHz + * 0:1 Max HE-MCS For 1 SS + * 2:3 Max HE-MCS For 2 SS + * 4:5 Max HE-MCS For 3 SS + * 6:7 Max HE-MCS For 4 SS + * 8:9 Max HE-MCS For 5 SS + * 10:11 Max HE-MCS For 6 SS + * 12:13 Max HE-MCS For 7 SS + * 14:15 Max HE-MCS For 8 SS + * + * 0 indicates support for HE-MCS 0-7 for n spatial streams + * 1 indicates support for HE-MCS 0-9 for n spatial streams + * 2 indicates support for HE-MCS 0-11 for n spatial streams + * 3 indicates that n spatial streams is not supported for HE PPDUs + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_HE_TX_MCS_MAP_LT_80 CFG_INI_UINT( \ + "he_tx_mcs_map_lt_80", \ + 0, \ + 0xFFFF, \ + 0xFFFA, \ + CFG_VALUE_OR_DEFAULT, \ + "He Tx Mcs Map Lt 80") +/* 11AX related INI configuration */ +/* + * + * he_rx_mcs_map_160 - configure Rx HE-MCS Map for 160 MHz + * @Min: 0 + * @Max: 0xFFFF + * @Default: 0xFFFA + * + * This ini is used to configure Rx HE-MCS Map for 160 MHz + * 0:1 Max HE-MCS For 1 SS + * 2:3 Max HE-MCS For 2 SS + * 4:5 Max HE-MCS For 3 SS + * 6:7 Max HE-MCS For 4 SS + * 8:9 Max HE-MCS For 5 SS + * 10:11 Max HE-MCS For 6 SS + * 12:13 Max HE-MCS For 7 SS + * 14:15 Max HE-MCS For 8 SS + * + * 0 indicates support for HE-MCS 0-7 for n spatial streams + * 1 indicates support for HE-MCS 0-9 for n spatial streams + * 2 indicates support for HE-MCS 0-11 for n spatial streams + * 3 indicates that n spatial streams is not supported for HE PPDUs + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_HE_RX_MCS_MAP_160 CFG_INI_UINT( \ + "he_rx_mcs_map_160", \ + 0, \ + 0xFFFF, \ + 0xFFFA, \ + CFG_VALUE_OR_DEFAULT, \ + "He Rx Mcs Map 160") + +/* 11AX related INI configuration */ +/* + * + * he_tx_mcs_map_160 - configure Tx HE-MCS Map for 160 MHz + * @Min: 0 + * @Max: 0xFFFF + * @Default: 0xFFFA + * + * This ini is used to configure Tx HE-MCS Map for 160 MHz + * 0:1 Max HE-MCS For 1 SS + * 2:3 Max HE-MCS For 2 SS + * 4:5 Max HE-MCS For 3 SS + * 6:7 Max HE-MCS For 4 SS + * 8:9 Max HE-MCS For 5 SS + * 10:11 Max HE-MCS For 6 SS + * 12:13 Max HE-MCS For 7 SS + * 14:15 Max HE-MCS For 8 SS + * + * 0 indicates support for HE-MCS 0-7 for n spatial streams + * 1 indicates support for HE-MCS 0-9 for n spatial streams + * 2 indicates support for HE-MCS 0-11 for n spatial streams + * 3 indicates that n spatial streams is not supported for HE PPDUs + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_HE_TX_MCS_MAP_160 CFG_INI_UINT( \ + "he_tx_mcs_map_160", \ + 0, \ + 0xFFFF, \ + 0xFFFA, \ + CFG_VALUE_OR_DEFAULT, \ + "He Tx Mcs Map 160") + +#define CFG_HE_RX_MCS_MAP_80_80 CFG_UINT( \ + "he_rx_mcs_map_80_80", \ + 0, \ + 0xFFFF, \ + 0xFFF0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Rx Mcs Map 80 80") + +#define CFG_HE_TX_MCS_MAP_80_80 CFG_UINT( \ + "he_tx_mcs_map_80_80", \ + 0, \ + 0xFFFF, \ + 0xFFF0, \ + CFG_VALUE_OR_DEFAULT, \ + "He tx Mcs Map 80 80") + +#define CFG_HE_OPS_BASIC_MCS_NSS CFG_UINT( \ + "cfg_he_ops_basic_mcs_nss", \ + 0x0000, \ + 0xFFFF, \ + 0xFFFC, \ + CFG_VALUE_OR_DEFAULT, \ + "He Ops Basic Mcs NSS") + +/* 11AX related INI configuration */ +/* + * + * he_ul_mumimo - configure ul mu capabilities + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to configure capabilities of ul mu-mimo + * 0-> no support + * 1-> full bandwidth support + * 2-> partial bandwidth support + * 3-> full and partial bandwidth support + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal/External + * + * + */ +#define CFG_HE_UL_MUMIMO CFG_INI_UINT( \ + "he_ul_mumimo", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "He Ul Mumimo") + +/* 11AX related INI configuration */ +/* + * + * he_dynamic_frag_support - configure dynamic fragmentation + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to configure dynamic fragmentation. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal/External + * + * + */ +#define CFG_HE_DYNAMIC_FRAGMENTATION CFG_INI_UINT( \ + "he_dynamic_frag_support", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HE Dynamic Fragmentation") + + +/* + * + * enable_ul_mimo- Enable UL MIMO. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable UL MIMO. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_ENABLE_UL_MIMO CFG_INI_BOOL( \ + "enable_ul_mimo", \ + 1, \ + "He Enable Ul Mimo Name") + +/* + * + * enable_ul_ofdma- Enable UL OFDMA. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable UL OFDMA. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_UL_OFDMA CFG_INI_BOOL( \ + "enable_ul_ofdma", \ + 1, \ + "He Enable Ul Ofdma Name") + +/* + * + * he_sta_obsspd- 11AX HE OBSS PD bit field + * @Min: 0 + * @Max: uin32_t max + * @Default: 0x15b8c2ae + * + * 4 Byte value with each byte representing a signed value for following params: + * Param Bit position Default + * OBSS_PD min (primary) 7:0 -82 (0xae) + * OBSS_PD max (primary) 15:8 -62 (0xc2) + * Secondary channel Ed 23:16 -72 (0xb8) + * TX_PWR(ref) 31:24 21 (0x15) + * This bit field value is directly applied to FW + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_HE_STA_OBSSPD CFG_INI_UINT( \ + "he_sta_obsspd", \ + 0, \ + 0xFFFFFFFF, \ + 0x15b8c2ae, \ + CFG_VALUE_OR_DEFAULT, \ + "He Mu Bfee Sts Gt80") + +/* + * + * he_mcs_12_13_support - Bit mask to enable MCS 12 and 13 support + * @Min: 0x0 + * @Max: 0xffffffff + * @Default: 0xffffffff + * + * This ini is used to set MCS 12 and 13 for 2.4Ghz and 5Ghz. first 16 + * bits(0-15) is for 2.4ghz and next 16 bits is for 5Ghz. Of 16 bits the lower + * 8 bits represent BW less than or equal 80Mhz (<= 80Mhz) and higher 8 bits + * represent BW greater than 80Mhz (> 80Mhz). nth bit in octet represent support + * for nth NSS [n=1:8]. Def value is 0xFFFFFFFF which enable MCS 12 and 13 for + * all NSS and BW. + * + * Bits Band + * BIT[0:15] 2.4Ghz support for MCS 12 and 13, for NSS n[1:8] and BW <= 80Mhz + * first 8 bits should be used (0-7) and for NSS n[1:8] and BW > + * 80 Mhz, next 8 bits (8-15) should be used. + * + * BIT[16:31] 5Ghz support for MCS 12 and 13, for NSS n[1:8] and BW < 80Mhz, + * bits 16-23 should be used and for BW > 80Mhz, next 8 bits + * (24-31) + * + * Some Possible values are as below + * 0 - MCS 12 and 13 disabled for 2.4Ghz and 5Ghz for all nss and + * BW > 80Mz and <= 80Mhz + * 0x3030303 - MCS 12 and 13 enabled for 2.4Ghz and 5Ghz for NSS 1 and 2 for + * BW > 80Mhz and <= 80Mhz + * 0x0303 - MCS 12 and 13 enabled for 2.4Ghz NSS 1 and 2 for BW > 80Mhz and + * <= 80Mhz but disabled for 5Ghz + * 0x3030000 - MCS 12 and 13 enabled for 5Ghz NSS 1 and 2 for BW > 80Mhz and + * <= 80Mhz but disabled for 2.4Ghz + * 0x30000 - MCS 12 and 13 enabled for 5Ghz NSS 1 and 2 for BW <= 80Mhz and + * disabled for BW > 80Mhz. And disabled for 2.4Ghz + * 0x3 MCS 12 and 13 enabled for 2.4Ghz NSS 1 and 2 for BW <= 80Mhz and + * disabled for all + * + * Related: None + * + * Supported Feature: HE MCS 12 and 13 + * + * Usage: Internal + * + * + */ +#define CFG_HE_MCS_12_13_SUPPORT CFG_INI_UINT("he_mcs_12_13_support", \ + 0, 0xffffffff, 0xffffffff, \ + CFG_VALUE_OR_DEFAULT, \ + "He Configure MCS_12_13 bits") + +/* + * + * disable_mcs_12_13_sap - Bitmask to disable HE MCS 12 13 support for SAP + * @Min: 0 + * @Max: 4095 + * @Default: 0 + * + * This ini is used to disable HE MCS_12_13 for SAP. + * Currently only support is present to disable 2.4 GHz 40 MHz SAP for value + * 2 i.e. 2nd bit set. + * + * Related: NA + * + * Usage: External + * + * + */ +#define CFG_DISABLE_MCS_12_13_SAP CFG_INI_UINT( \ + "disable_mcs_12_13_sap", \ + 0, 4095, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Disable HE MCS_12_13 for SAP") + +#define CFG_HE_CAPS_ALL \ + CFG(CFG_HE_CONTROL) \ + CFG(CFG_HE_FRAGMENTATION) \ + CFG(CFG_HE_MAX_FRAG_MSDU) \ + CFG(CFG_HE_MIN_FRAG_SIZE) \ + CFG(CFG_HE_TRIG_PAD) \ + CFG(CFG_HE_MTID_AGGR_RX) \ + CFG(CFG_HE_LINK_ADAPTATION) \ + CFG(CFG_HE_ALL_ACK) \ + CFG(CFG_HE_TRIGD_RSP_SCHEDULING) \ + CFG(CFG_HE_BUFFER_STATUS_RPT) \ + CFG(CFG_HE_BA_32BIT) \ + CFG(CFG_HE_MU_CASCADING) \ + CFG(CFG_HE_MULTI_TID) \ + CFG(CFG_HE_OMI) \ + CFG(CFG_HE_OFDMA_RA) \ + CFG(CFG_HE_MAX_AMPDU_LEN) \ + CFG(CFG_HE_AMSDU_FRAG) \ + CFG(CFG_HE_FLEX_TWT_SCHED) \ + CFG(CFG_HE_RX_CTRL) \ + CFG(CFG_HE_BSRP_AMPDU_AGGR) \ + CFG(CFG_HE_QTP) \ + CFG(CFG_HE_A_BQR) \ + CFG(CFG_HE_SR_RESPONDER) \ + CFG(CFG_HE_NDP_FEEDBACK_SUPP) \ + CFG(CFG_HE_OPS_SUPP) \ + CFG(CFG_HE_AMSDU_IN_AMPDU) \ + CFG(CFG_HE_CHAN_WIDTH) \ + CFG(CFG_HE_MTID_AGGR_TX) \ + CFG(CFG_HE_SUB_CH_SEL_TX) \ + CFG(CFG_HE_UL_2X996_RU) \ + CFG(CFG_HE_OM_CTRL_UL_MU_DIS_RX) \ + CFG(CFG_HE_RX_PREAM_PUNC) \ + CFG(CFG_HE_CLASS_OF_DEVICE) \ + CFG(CFG_HE_LDPC) \ + CFG(CFG_HE_LTF_PPDU) \ + CFG(CFG_HE_MIDAMBLE_RX_MAX_NSTS) \ + CFG(CFG_HE_LTF_NDP) \ + CFG(CFG_HE_TX_STBC_LT80) \ + CFG(CFG_HE_RX_STBC_LT80) \ + CFG(CFG_HE_DOPPLER) \ + CFG(CFG_HE_UL_MUMIMO) \ + CFG(CFG_HE_DCM_TX) \ + CFG(CFG_HE_DCM_RX) \ + CFG(CFG_HE_MU_PPDU) \ + CFG(CFG_HE_SU_BEAMFORMER) \ + CFG(CFG_HE_SU_BEAMFORMEE) \ + CFG(CFG_HE_MU_BEAMFORMER) \ + CFG(CFG_HE_BFEE_STS_LT80) \ + CFG(CFG_HE_BFEE_STS_GT80) \ + CFG(CFG_HE_NUM_SOUND_LT80) \ + CFG(CFG_HE_NUM_SOUND_GT80) \ + CFG(CFG_HE_SU_FEED_TONE16) \ + CFG(CFG_HE_MU_FEED_TONE16) \ + CFG(CFG_HE_CODEBOOK_SU) \ + CFG(CFG_HE_CODEBOOK_MU) \ + CFG(CFG_HE_BFRM_FEED) \ + CFG(CFG_HE_ER_SU_PPDU) \ + CFG(CFG_HE_DL_PART_BW) \ + CFG(CFG_HE_PPET_PRESENT) \ + CFG(CFG_HE_SRP) \ + CFG(CFG_HE_POWER_BOOST) \ + CFG(CFG_HE_4x_LTF_GI) \ + CFG(CFG_HE_MAX_NC) \ + CFG(CFG_HE_RX_STBC_GT80) \ + CFG(CFG_HE_TX_STBC_GT80) \ + CFG(CFG_HE_ER_4x_LTF_GI) \ + CFG(CFG_HE_PPDU_20_IN_40MHZ_2G) \ + CFG(CFG_HE_PPDU_20_IN_160_80P80MHZ) \ + CFG(CFG_HE_PPDU_80_IN_160_80P80MHZ) \ + CFG(CFG_HE_ER_1X_HE_LTF_GI) \ + CFG(CFG_HE_MIDAMBLE_TXRX_1X_HE_LTF) \ + CFG(CFG_HE_DCM_MAX_BW) \ + CFG(CFG_HE_LONGER_16_SIGB_OFDM_SYM) \ + CFG(CFG_HE_NON_TRIG_CQI_FEEDBACK) \ + CFG(CFG_HE_TX_1024_QAM_LT_242_RU) \ + CFG(CFG_HE_RX_1024_QAM_LT_242_RU) \ + CFG(CFG_HE_RX_FULL_BW_MU_CMPR_SIGB) \ + CFG(CFG_HE_RX_FULL_BW_MU_NON_CMPR_SIGB) \ + CFG(CFG_HE_RX_MCS_MAP_LT_80) \ + CFG(CFG_HE_TX_MCS_MAP_LT_80) \ + CFG(CFG_HE_RX_MCS_MAP_160) \ + CFG(CFG_HE_TX_MCS_MAP_160) \ + CFG(CFG_HE_RX_MCS_MAP_80_80) \ + CFG(CFG_HE_TX_MCS_MAP_80_80) \ + CFG(CFG_HE_OPS_BASIC_MCS_NSS) \ + CFG(CFG_HE_DYNAMIC_FRAGMENTATION) \ + CFG(CFG_ENABLE_UL_MIMO) \ + CFG(CFG_ENABLE_UL_OFDMA) \ + CFG(CFG_HE_STA_OBSSPD) \ + CFG(CFG_HE_MCS_12_13_SUPPORT) \ + CFG(CFG_DISABLE_MCS_12_13_SAP) + +#endif /* __CFG_MLME_HE_CAPS_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_ht_caps.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_ht_caps.h new file mode 100644 index 0000000000..bef0ca2d98 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_ht_caps.h @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_HT_CAPS_H +#define __CFG_MLME_HT_CAPS_H + +/* + * + * gTxLdpcEnable - Config Param to enable Tx LDPC capability + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to enable/disable Tx LDPC capability + * 0 - disable + * 1 - HT LDPC enable + * 2 - VHT LDPC enable + * 3 - HT & VHT LDPC enable + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Concurrency/Standalone + * + * Usage: External + * + * + */ +#define CFG_TX_LDPC_ENABLE CFG_INI_UINT( \ + "gTxLdpcEnable", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx LDPC capability") + +/* + * + * gEnableRXLDPC - Config Param to enable Rx LDPC capability + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable Rx LDPC capability + * 0 - disable Rx LDPC + * 1 - enable Rx LDPC + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Concurrency/Standalone + * + * Usage: External + * + * + */ +#define CFG_RX_LDPC_ENABLE CFG_INI_BOOL( \ + "gEnableRXLDPC", \ + 1, \ + "Rx LDPC capability") + +/* + * + * gEnableTXSTBC - Enables/disables Tx STBC capability in STA mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default Tx STBC capability + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_TX_STBC_ENABLE CFG_INI_BOOL( \ + "gEnableTXSTBC", \ + 1, \ + "Tx STBC capability") + +/* + * + * gEnableRXSTBC - Enables/disables Rx STBC capability in STA mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default Rx STBC capability + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_RX_STBC_ENABLE CFG_INI_BOOL( \ + "gEnableRXSTBC", \ + 1, \ + "Rx STBC capability") + +/* + * + * gShortGI20Mhz - Short Guard Interval for HT20 + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default short interval for HT20 + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_SHORT_GI_20MHZ CFG_INI_BOOL( \ + "gShortGI20Mhz", \ + 1, \ + "Short Guard Interval for HT20") + +/* + * + * gShortGI40Mhz - It will check gShortGI20Mhz and + * gShortGI40Mhz from session entry + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default gShortGI40Mhz + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_SHORT_GI_40MHZ CFG_INI_BOOL( \ + "gShortGI40Mhz", \ + 1, \ + "Short Guard Interval for HT40") + +#define CFG_HT_CAP_INFO CFG_UINT( \ + "ht_cap_info", \ + 0, \ + 65535, \ + 364, \ + CFG_VALUE_OR_DEFAULT, \ + "HT cap info") + +/* + * + * gShortPreamble - Set Short Preamble + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default short Preamble + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_SHORT_PREAMBLE CFG_INI_BOOL( \ + "gShortPreamble", \ + 1, \ + "Short Preamble") + +#define CFG_HT_AMPDU_PARAMS CFG_UINT( \ + "ht_ampdu_params", \ + 0, \ + 255, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HT AMPDU Params") + +#define CFG_EXT_HT_CAP_INFO CFG_UINT( \ + "ext_ht_cap_info", \ + 0, \ + 65535, \ + 1024, \ + CFG_VALUE_OR_DEFAULT, \ + "HT Ext Cap Info") + +#define CFG_HT_INFO_FIELD_1 CFG_UINT( \ + "ht_info_field_1", \ + 0, \ + 255, \ + 15, \ + CFG_VALUE_OR_DEFAULT, \ + "HT Info Field 1") + +#define CFG_HT_INFO_FIELD_2 CFG_UINT( \ + "ht_info_field_2", \ + 0, \ + 65535, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HT Info Field 2") + +#define CFG_HT_INFO_FIELD_3 CFG_UINT( \ + "ht_info_field_3", \ + 0, \ + 65535, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "HT Info Field 3") + +/* + * + * gEnableHtSMPS - Enable the SM Power Save + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable SM Power Save + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_HT_SMPS CFG_INI_BOOL( \ + "gEnableHtSMPS", \ + 0, \ + "Enable HT SM PowerSave") + +/* + * + * gHtSMPS - SMPS Mode + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set default SM Power Save Antenna mode + * 0 - Static + * 1 - Dynamic + * 2 - Reserved/Invalid + * 3 - Disabled + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_HT_SMPS_MODE CFG_INI_UINT( \ + "gHtSMPS", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "HT SM Power Save Config") + +/* + * + * gMaxAmsduNum - Max number of MSDU's in aggregate + * @Min: 0 + * @Max: 15 + * @Default: 0 + * + * gMaxAmsduNum is the number of MSDU's transmitted in the aggregated + * frame. Setting it to a value larger than 1 enables transmit aggregation. + * Set the value to 0 to enable FW automode selection where it decides + * the maximum number of MSDUs in AMSDU based on connection mode. + * + * It is a PHY parameter that applies to all vdev's in firmware. + * + * Supported Feature: 11n aggregation + * + * Usage: Internal + * + * + */ +#define CFG_MAX_AMSDU_NUM CFG_INI_UINT( \ + "gMaxAmsduNum", \ + 0, \ + 15, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Max AMSDU Number") + +/* + * + * gMaxRxAmpduFactor - Provide the maximum ampdu factor. + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to set default maxampdu factor + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_MAX_RX_AMPDU_FACTOR CFG_INI_UINT( \ + "gMaxRxAmpduFactor", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Max Rx AMPDU Factor") + +/* + * + * ght_mpdu_density - Configuration option for HT MPDU density + * @Min: 0 + * @Max: 7 + * @Default: 4 + * + * This ini is used to set default MPDU Density + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * As per (Table 8-125 802.11-2012) + * 0 for no restriction + * 1 for 1/4 micro sec + * 2 for 1/2 micro sec + * 3 for 1 micro sec + * 4 for 2 micro sec + * 5 for 4 micro sec + * 6 for 8 micro sec + * 7 for 16 micro sec + * + * + */ +#define CFG_MPDU_DENSITY CFG_INI_UINT( \ + "ght_mpdu_density", \ + 0, \ + 7, \ + 4, \ + CFG_VALUE_OR_DEFAULT, \ + "MPDU Density") + +/* + * + * gShortSlotTimeEnabled - It will set slot timing slot. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default timing slot. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_SHORT_SLOT_TIME_ENABLED CFG_INI_BOOL( \ + "gShortSlotTimeEnabled", \ + 1, \ + "Short Slot Time Enabled") + +#define CFG_HT_CAPS_ALL \ + CFG(CFG_HT_CAP_INFO) \ + CFG(CFG_TX_LDPC_ENABLE) \ + CFG(CFG_RX_LDPC_ENABLE) \ + CFG(CFG_TX_STBC_ENABLE) \ + CFG(CFG_RX_STBC_ENABLE) \ + CFG(CFG_SHORT_GI_20MHZ) \ + CFG(CFG_SHORT_GI_40MHZ) \ + CFG(CFG_SHORT_PREAMBLE) \ + CFG(CFG_HT_AMPDU_PARAMS) \ + CFG(CFG_EXT_HT_CAP_INFO) \ + CFG(CFG_HT_INFO_FIELD_1) \ + CFG(CFG_HT_INFO_FIELD_2) \ + CFG(CFG_HT_INFO_FIELD_3) \ + CFG(CFG_ENABLE_HT_SMPS) \ + CFG(CFG_HT_SMPS_MODE) \ + CFG(CFG_MAX_AMSDU_NUM) \ + CFG(CFG_MAX_RX_AMPDU_FACTOR) \ + CFG(CFG_MPDU_DENSITY) \ + CFG(CFG_SHORT_SLOT_TIME_ENABLED) + +#endif /* __CFG_MLME_HT_CAPS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_lfr.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_lfr.h new file mode 100644 index 0000000000..6229f6396b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_lfr.h @@ -0,0 +1,3429 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains configuration definitions for MLME LFR. + */ + +#ifndef CFG_MLME_LFR_H__ +#define CFG_MLME_LFR_H__ + +#ifdef CONNECTION_ROAMING_CFG +# define RoamScan_ActiveCH_DwellTime_min 0 +# define RoamScan_ActiveCH_DwellTime_max 200 +# define RoamScan_ActiveCH_DwellTime_default 40 +# define RoamScan_InactiveCount_min 0 +# define RoamScan_InactiveCount_max 20 +# define RoamScan_InactiveCount_default 5 +# define RoamScan_StepRSSI_min 0 +# define RoamScan_StepRSSI_max 20 +# define RoamScan_StepRSSI_default 5 +# define RoamScan_HomeTime_min 0 +# define RoamScan_HomeTime_max 200 +# define RoamScan_HomeTime_default 45 +# define RoamScan_AwayTime_min 0 +# define RoamScan_AwayTime_max 200 +# define RoamScan_AwayTime_default 100 +# define RoamRSSI_Trigger_min -100 +# define RoamRSSI_Trigger_max -50 +# define RoamRSSI_Trigger_default -75 +# define RoamCU_Trigger_min 60 +# define RoamCU_Trigger_max 90 +# define RoamCU_Trigger_default 70 +# define RoamCU_24GRSSIRange_min -70 +# define RoamCU_24GRSSIRange_max -50 +# define RoamCU_24GRSSIRange_default -60 +# define RoamCU_5GRSSIRange_min -70 +# define RoamCU_5GRSSIRange_max -50 +# define RoamCU_5GRSSIRange_default -70 +# define RoamIdle_TriggerBand_min 0 +# define RoamIdle_TriggerBand_max 4 +# define RoamIdle_TriggerBand_default 3 +# define RoamIdle_MinRSSI_min -70 +# define RoamIdle_MinRSSI_max -50 +# define RoamIdle_MinRSSI_default -65 +# define RoamIdle_RSSIVariation_min 0 +# define RoamIdle_RSSIVariation_max 10 +# define RoamIdle_RSSIVariation_default 8 +# define RoamIdle_InactivePacketCount_min 0 +# define RoamIdle_InactivePacketCount_max 20 +# define RoamIdle_InactivePacketCount_default 5 +# define CONBEACONLOSS_TIMEOUTONWAKEUP_MIN 0 +# define CONBEACONLOSS_TIMEOUTONWAKEUP_MAX 20 +# define CONBEACONLOSS_TIMEOUTONWAKEUP_DEFAULT 6 +# define CONBEACONLOSS_TIMEOUTONSLEEP_MIN 0 +# define CONBEACONLOSS_TIMEOUTONSLEEP_MAX 20 +# define CONBEACONLOSS_TIMEOUTONSLEEP_DEFAULT 10 +# define ROAMCU_6GRSSIRANGE_MIN -70 +# define ROAMCU_6GRSSIRANGE_MAX -50 +# define ROAMCU_6GRSSIRANGE_DEFAULT -70 +# define RoamIdle_InactiveTime_default 5 +#else +# define RoamScan_ActiveCH_DwellTime_min 3 +# define RoamScan_ActiveCH_DwellTime_max 300 +# define RoamScan_ActiveCH_DwellTime_default 40 +# define RoamScan_InactiveCount_min 0 +# define RoamScan_InactiveCount_max 0xFFFFFFFF +# define RoamScan_InactiveCount_default 10 +# define RoamScan_StepRSSI_min 0 +# define RoamScan_StepRSSI_max 100 +# define RoamScan_StepRSSI_default 5 +# define RoamScan_HomeTime_min 3 +# define RoamScan_HomeTime_max 300 +# define RoamScan_HomeTime_default 50 +# define RoamScan_AwayTime_min 0 +# define RoamScan_AwayTime_max 300 +# define RoamScan_AwayTime_default 0 +# define RoamRSSI_Trigger_min -100 +# define RoamRSSI_Trigger_max -50 +# define RoamRSSI_Trigger_default -76 +# define RoamCU_Trigger_min 0 +# define RoamCU_Trigger_max 100 +# define RoamCU_Trigger_default 70 +# define RoamCU_24GRSSIRange_min -120 +# define RoamCU_24GRSSIRange_max 0 +# define RoamCU_24GRSSIRange_default -60 +# define RoamCU_5GRSSIRange_min -120 +# define RoamCU_5GRSSIRange_max 0 +# define RoamCU_5GRSSIRange_default -70 +# define RoamIdle_TriggerBand_min 0 +# define RoamIdle_TriggerBand_max 2 +# define RoamIdle_TriggerBand_default 0 +# define RoamIdle_MinRSSI_min -96 +# define RoamIdle_MinRSSI_max 0 +# define RoamIdle_MinRSSI_default -65 +# define RoamIdle_RSSIVariation_min 0 +# define RoamIdle_RSSIVariation_max 50 +# define RoamIdle_RSSIVariation_default 3 +# define RoamIdle_InactivePacketCount_min 0 +# define RoamIdle_InactivePacketCount_max 0xFFFFFFFF +# define RoamIdle_InactivePacketCount_default 10 +# define CONBEACONLOSS_TIMEOUTONWAKEUP_MIN 0 +# define CONBEACONLOSS_TIMEOUTONWAKEUP_MAX 20 +# define CONBEACONLOSS_TIMEOUTONWAKEUP_DEFAULT 3 +# define CONBEACONLOSS_TIMEOUTONSLEEP_MIN 0 +# define CONBEACONLOSS_TIMEOUTONSLEEP_MAX 20 +# define CONBEACONLOSS_TIMEOUTONSLEEP_DEFAULT 5 +# define ROAMCU_6GRSSIRANGE_MIN -120 +# define ROAMCU_6GRSSIRANGE_MAX 0 +# define ROAMCU_6GRSSIRANGE_DEFAULT -70 +# define RoamIdle_InactiveTime_default 10 +#endif + +/* + * + * RoamScan_PassiveCH_DwellTime - Set max channel time for roam passive scan + * @Min: 0 + * @Max: 200 + * @Default: 130 + * + * This ini is used to set maximum channel time in msecs spent in + * passive scan for roaming + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_ROAM_PASSIVE_MAX_CHANNEL_TIME CFG_INI_UINT(\ + "RoamScan_PassiveCH_DwellTime",\ + 0, \ + 200, \ + 130, \ + CFG_VALUE_OR_DEFAULT, "roam scan passive dwell time") + +/* + * + * mawc_roam_enabled - Enable/Disable MAWC during roaming + * @Min: 0 - Disabled + * @Max: 1 - Enabled + * @Default: 0 + * + * This ini is used to control MAWC during roaming. + * + * Related: MAWCEnabled. + * + * Supported Feature: MAWC Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_MAWC_ROAM_ENABLED CFG_INI_BOOL( \ + "mawc_roam_enabled", \ + 0, \ + "Enable/Disable MAWC during roaming") + +/* + * + * mawc_roam_traffic_threshold - Configure traffic threshold + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 300 + * + * This ini is used to configure the data traffic load in kbps to + * register CMC. + * + * Related: mawc_roam_enabled. + * + * Supported Feature: MAWC Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_MAWC_ROAM_TRAFFIC_THRESHOLD CFG_INI_UINT( \ + "mawc_roam_traffic_threshold", \ + 0, \ + 0xFFFFFFFF, \ + 300, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure traffic threshold") + +/* + * + * mawc_roam_ap_rssi_threshold - Best AP RSSI threshold + * @Min: -120 + * @Max: 0 + * @Default: -66 + * + * This ini is used to specify the RSSI threshold to scan for the AP. + * + * Related: mawc_roam_enabled. + * + * Supported Feature: MAWC Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_MAWC_ROAM_AP_RSSI_THRESHOLD CFG_INI_INT( \ + "mawc_roam_ap_rssi_threshold", \ + -120, \ + 0, \ + -66, \ + CFG_VALUE_OR_DEFAULT, \ + "Best AP RSSI threshold") + +/* + * + * mawc_roam_rssi_high_adjust - Adjust MAWC roam high RSSI + * @Min: 3 + * @Max: 5 + * @Default: 5 + * + * This ini is used for high RSSI threshold adjustment in stationary state + * to suppress the scan. + * + * Related: mawc_roam_enabled. + * + * Supported Feature: MAWC Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_MAWC_ROAM_RSSI_HIGH_ADJUST CFG_INI_UINT( \ + "mawc_roam_rssi_high_adjust", \ + 3, \ + 5, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Adjust MAWC roam high RSSI") + +/* + * + * mawc_roam_rssi_low_adjust - Adjust MAWC roam low RSSI + * @Min: 3 + * @Max: 5 + * @Default: 5 + * + * This ini is used for low RSSI threshold adjustment in stationary state + * to suppress the scan. + * + * Related: mawc_roam_enabled. + * + * Supported Feature: MAWC Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_MAWC_ROAM_RSSI_LOW_ADJUST CFG_INI_UINT( \ + "mawc_roam_rssi_low_adjust", \ + 3, \ + 5, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Adjust MAWC roam low RSSI") + +/* + * + * rssi_abs_thresh - The min RSSI of the candidate AP to consider roam + * @Min: -96 + * @Max: 0 + * @Default: 0 + * + * The RSSI value of the candidate AP should be higher than rssi_abs_thresh + * to roam to the AP. 0 means no absolute minimum RSSI is required. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_RSSI_ABS_THRESHOLD CFG_INI_INT( \ + "rssi_abs_thresh", \ + -96, \ + 0, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "The min RSSI of the candidate AP to consider roam") + +/* + * + * lookup_threshold_5g_offset - Lookup threshold offset for 5G band + * @Min: -120 + * @Max: 120 + * @Default: 0 + * + * This ini is used to set the 5G band lookup threshold for roaming. + * It depends on another INI which is gNeighborLookupThreshold. + * gNeighborLookupThreshold is a legacy INI item which will be used to + * set the RSSI lookup threshold for both 2G and 5G bands. If the + * user wants to setup a different threshold for a 5G band, then user + * can use this offset value which will be summed up to the value of + * gNeighborLookupThreshold and used for 5G + * e.g: gNeighborLookupThreshold = -76dBm + * lookup_threshold_5g_offset = 6dBm + * Then the 5G band will be configured to -76+6 = -70dBm + * A default value of Zero to lookup_threshold_5g_offset will keep the + * thresholds same for both 2G and 5G bands + * + * Related: gNeighborLookupThreshold + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_5G_RSSI_THRESHOLD_OFFSET CFG_INI_INT( \ + "lookup_threshold_5g_offset", \ + -120, \ + 120, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Lookup threshold offset for 5G band") + +/* + * + * gEnableFastRoamInConcurrency - Enable LFR roaming on STA during concurrency + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable Legacy fast roaming(LFR) on STA link during + * concurrent sessions. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ENABLE_FAST_ROAM_IN_CONCURRENCY CFG_INI_BOOL( \ + "gEnableFastRoamInConcurrency", \ + 1, \ + "Enable LFR roaming on STA during concurrency") + +/* + * + * gEnableEarlyStopScan - Set early stop scan + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set early stop scan. Early stop + * scan is a feature for roaming to stop the scans at + * an early stage as soon as we find a better AP to roam. + * This would make the roaming happen quickly. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_EARLY_STOP_SCAN_ENABLE CFG_INI_BOOL( \ + "gEnableEarlyStopScan", \ + 0, \ + "Set early stop scan") + +/* + * + * gEarlyStopScanMinThreshold - Set early stop scan min + * threshold + * @Min: -80 + * @Max: -70 + * @Default: -73 + * + * This ini is used to set the early stop scan minimum + * threshold. Early stop scan minimum threshold is the + * minimum threshold to be considered for stopping the + * scan. The algorithm starts with a scan on the greedy + * channel list with the maximum threshold and steps down + * the threshold by 20% for each further channel. It can + * step down on each channel but cannot go lower than the + * minimum threshold. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_EARLY_STOP_SCAN_MIN_THRESHOLD CFG_INI_INT( \ + "gEarlyStopScanMinThreshold", \ + -80, \ + -70, \ + -73, \ + CFG_VALUE_OR_DEFAULT, \ + "Set early stop scan min") + +/* + * + * gEarlyStopScanMaxThreshold - Set early stop scan max + * threshold + * @Min: -60 + * @Max: -40 + * @Default: -43 + * + * This ini is used to set the the early stop scan maximum + * threshold at which the candidate AP should be to be + * qualified as a potential roam candidate and good enough + * to stop the roaming scan. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_EARLY_STOP_SCAN_MAX_THRESHOLD CFG_INI_INT( \ + "gEarlyStopScanMaxThreshold", \ + -60, \ + -40, \ + -43, \ + CFG_VALUE_OR_DEFAULT, \ + "Set early stop scan max") + +/* + * + * gtraffic_threshold - Dense traffic threshold + * @Min: 0 + * @Max: 0xffffffff + * @Default: 400 + * + * Dense traffic threshold + * traffic threshold required for dense roam scan + * Measured in kbps + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_DENSE_TRAFFIC_THRESHOLD CFG_INI_UINT( \ + "gtraffic_threshold", \ + 0, \ + 0xffffffff, \ + 400, \ + CFG_VALUE_OR_DEFAULT, \ + "Dense traffic threshold") + +/* + * + * groam_dense_rssi_thresh_offset - Sets dense roam RSSI threshold diff + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * This INI is used to set offset value from normal RSSI threshold to dense + * RSSI threshold FW will optimize roaming based on new RSSI threshold once + * it detects dense environment. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_DENSE_RSSI_THRE_OFFSET CFG_INI_UINT( \ + "groam_dense_rssi_thresh_offset", \ + 0, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Dense traffic threshold") + +/* + * + * groam_dense_min_aps - Sets minimum number of AP for dense roam + * @Min: 1 + * @Max: 5 + * @Default: 3 + * + * Minimum number of APs required for dense roam. FW will consider + * environment as dense once it detects #APs operating is more than + * groam_dense_min_aps. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_DENSE_MIN_APS CFG_INI_UINT( \ + "groam_dense_min_aps", \ + 1, \ + 5, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Sets minimum number of AP for dense roam") + +/* + * + * roam_bg_scan_bad_rssi_thresh - RSSI threshold for background roam + * @Min: -96 + * @Max: 0 + * @Default: -76 + * + * If the DUT is connected to an AP with weak signal, then the bad RSSI + * threshold will be used as an opportunity to use the scan results + * from other scan clients and try to roam if there is a better AP + * available in the environment. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD CFG_INI_INT( \ + "roam_bg_scan_bad_rssi_thresh", \ + -96, \ + 0, \ + -76, \ + CFG_VALUE_OR_DEFAULT, \ + "RSSI threshold for background roam") + +/* + * + * roam_bg_scan_client_bitmap - Bitmap used to identify the scan clients + * @Min: 0 + * @Max: 0x7FF + * @Default: 0x424 + * + * This bitmap is used to define the client scans that need to be used + * by the roaming module to perform a background roaming. + * Currently supported bit positions are as follows: + * Bit 0 is reserved in the firmware. + * WMI_SCAN_CLIENT_NLO - 1 + * WMI_SCAN_CLIENT_EXTSCAN - 2 + * WMI_SCAN_CLIENT_ROAM - 3 + * WMI_SCAN_CLIENT_P2P - 4 + * WMI_SCAN_CLIENT_LPI - 5 + * WMI_SCAN_CLIENT_NAN - 6 + * WMI_SCAN_CLIENT_ANQP - 7 + * WMI_SCAN_CLIENT_OBSS - 8 + * WMI_SCAN_CLIENT_PLM - 9 + * WMI_SCAN_CLIENT_HOST - 10 + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_BG_SCAN_CLIENT_BITMAP CFG_INI_UINT( \ + "roam_bg_scan_client_bitmap", \ + 0, \ + 0x7FF, \ + 0x424, \ + CFG_VALUE_OR_DEFAULT, \ + "Bitmap used to identify the scan clients") + +/* + * + * roam_bad_rssi_thresh_offset_2g - RSSI threshold offset for 2G to 5G roam + * @Min: 0 + * @Max: 86 + * @Default: 40 + * + * If the DUT is connected to an AP with weak signal in 2G band, then the + * bad RSSI offset for 2g would be used as offset from the bad RSSI + * threshold configured and then use the resulting rssi for an opportunity + * to use the scan results from other scan clients and try to roam to + * 5G Band ONLY if there is a better AP available in the environment. + * + * For example if the roam_bg_scan_bad_rssi_thresh is -76 and + * roam_bad_rssi_thresh_offset_2g is 40 then the difference of -36 would be + * used as a trigger to roam to a 5G AP if DUT initially connected to a 2G AP + * + * Related: roam_bg_scan_bad_rssi_thresh + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G CFG_INI_UINT( \ + "roam_bad_rssi_thresh_offset_2g", \ + 0, \ + 86, \ + 40, \ + CFG_VALUE_OR_DEFAULT, \ + "RSSI threshold offset for 2G to 5G roam") + +/* + * + * roam_data_rssi_threshold_triggers - triggers of data rssi threshold for roam + * @Min: 0 + * @Max: 0xffff + * @Default: 0x3 + * + * If the DUT is connected to an AP with weak signal, during latest + * rx_data_inactivity_time, if there is no activity or avg of data_rssi is + * better than roam_data_rssi_threshold(-70dbM), then suppress roaming + * triggered by roam_data_rssi_threshold_triggers: low RSSI or bg scan. + * Triggers bitmap definition: + * ROAM_DATA_RSSI_FLAG_LOW_RSSI 1<<0 + * ROAM_DATA_RSSI_FLAG_BACKGROUND 1<<1 + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_DATA_RSSI_THRESHOLD_TRIGGERS CFG_INI_UINT( \ + "roam_data_rssi_threshold_triggers", \ + 0, \ + 0xffff, \ + 0x3, \ + CFG_VALUE_OR_DEFAULT, \ + "Triggers of DATA RSSI threshold for roam") + +/* + * + * roam_data_rssi_threshold - Data RSSI threshold for background roam + * @Min: -96 + * @Max: 0 + * @Default: -70 + * + * If the DUT is connected to an AP with weak signal, during latest + * rx_data_inactivity_time, if there is no activity or avg of data_rssi is + * better than roam_data_rssi_threshold(-70dbM), then suppress roaming + * triggered by roam_data_rssi_threshold_triggers: low RSSI or bg scan. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_DATA_RSSI_THRESHOLD CFG_INI_INT( \ + "roam_data_rssi_threshold", \ + -96, \ + 0, \ + -70, \ + CFG_VALUE_OR_DEFAULT, \ + "DATA RSSI threshold for roam") + +/* + * + * rx_data_inactivity_time - Duration to check data rssi + * @Min: 0 + * @Max: 100000 ms + * @Default: 2000 + * + * If the DUT is connected to an AP with weak signal, during latest + * rx_data_inactivity_time, if there is no activity or avg of data_rssi is + * better than roam_data_rssi_threshold(-70dbM), then suppress roaming + * triggered by roam_data_rssi_threshold_triggers: low RSSI or bg scan. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_RX_DATA_INACTIVITY_TIME CFG_INI_UINT( \ + "rx_data_inactivity_time", \ + 0, \ + 100000, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Rx inactivity time to check data rssi") + +/* + * + * roamscan_adaptive_dwell_mode - Sets dwell time adaptive mode + * @Min: 0 + * @Max: 4 + * @Default: 4 + * + * This parameter will set the algo used in dwell time optimization during + * roam scan. see enum scan_dwelltime_adaptive_mode. + * Acceptable values for this: + * 0: Default (Use firmware default mode) + * 1: Conservative optimization + * 2: Moderate optimization + * 3: Aggressive optimization + * 4: Static + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ADAPTIVE_ROAMSCAN_DWELL_MODE CFG_INI_UINT( \ + "roamscan_adaptive_dwell_mode", \ + 0, \ + 4, \ + 4, \ + CFG_VALUE_OR_DEFAULT, \ + "Sets dwell time adaptive mode") + +/* + * + * gper_roam_enabled - To enabled/disable PER based roaming in FW + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to enable/disable Packet error based roaming, enabling this + * will cause DUT to monitor Tx and Rx traffic and roam to a better candidate + * if current is not good enough. + * + * Values supported: + * 0: disabled + * 1: enabled for Rx traffic + * 2: enabled for Tx traffic + * 3: enabled for Tx and Rx traffic + * + * Related: gper_roam_high_rate_th, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_ENABLE CFG_INI_UINT( \ + "gper_roam_enabled", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "To enabled/disable PER based roaming in FW") + +/* + * + * gper_roam_high_rate_th - Rate at which PER based roam will stop + * @Min: 1 Mbps + * @Max: 0xffffffff + * @Default: 40 Mbps + * + * This ini is used to define the data rate in mbps*10 at which FW will stop + * monitoring the traffic for PER based roam. + * + * Related: gper_roam_enabled, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_CONFIG_HIGH_RATE_TH CFG_INI_UINT( \ + "gper_roam_high_rate_th", \ + 10, \ + 0xffffffff, \ + 400, \ + CFG_VALUE_OR_DEFAULT, \ + "Rate at which PER based roam will stop") + +/* + * + * gper_roam_low_rate_th - Rate at which FW starts considering traffic for PER + * based roam. + * + * @Min: 1 Mbps + * @Max: 0xffffffff + * @Default: 20 Mbps + * + * This ini is used to define the rate in mbps*10 at which FW starts considering + * traffic for PER based roam, if gper_roam_th_percent of data is below this + * rate, FW will issue a roam scan. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_CONFIG_LOW_RATE_TH CFG_INI_UINT( \ + "gper_roam_low_rate_th", \ + 10, \ + 0xffffffff, \ + 200, \ + CFG_VALUE_OR_DEFAULT, \ + "Rate at which FW starts considering traffic for PER") + +/* + * + * gper_roam_th_percent - Percentage at which FW will issue a roam scan if + * traffic is below gper_roam_low_rate_th rate. + * + * @Min: 10% + * @Max: 100% + * @Default: 60% + * + * This ini is used to define the percentage at which FW will issue a roam scan + * if traffic is below gper_roam_low_rate_th rate. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, + * gper_roam_high_rate_th, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_CONFIG_RATE_TH_PERCENT CFG_INI_UINT( \ + "gper_roam_th_percent", \ + 10, \ + 100, \ + 60, \ + CFG_VALUE_OR_DEFAULT, \ + "Percentage at which FW will issue a roam scan") + +/* + * + * gper_roam_rest_time - Time for which FW will wait once it issues a + * roam scan. + * + * @Min: 10 seconds + * @Max: 3600 seconds + * @Default: 300 seconds + * + * This ini is used to define the time for which FW will wait once it issues a + * PER based roam scan. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, + * gper_roam_high_rate_th, gper_roam_th_percent + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_REST_TIME CFG_INI_UINT( \ + "gper_roam_rest_time", \ + 10, \ + 3600, \ + 300, \ + CFG_VALUE_OR_DEFAULT, \ + "Time for which FW will wait once it issues a roam scan") + +/* + * + * gper_roam_mon_time - Minimum time required in seconds to + * be considered as valid scenario for PER based roam + * @Min: 5 + * @Max: 25 + * @Default: 25 + * + * This ini is used to define minimum time in seconds for which DUT has + * collected the PER stats before it can consider the stats hysteresis to be + * valid for PER based scan. + * DUT collects following information during this period: + * 1. % of packets below gper_roam_low_rate_th + * 2. # packets above gper_roam_high_rate_th + * if DUT gets (1) greater than gper_roam_th_percent and (2) is zero during + * this period, it triggers PER based roam scan. + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_MONITOR_TIME CFG_INI_UINT( \ + "gper_roam_mon_time", \ + 5, \ + 25, \ + 25, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum time to be considered as valid scenario for PER based roam") + +/* + * + * gper_min_rssi_threshold_for_roam - Minimum roamable AP RSSI for + * candidate selection for PER based roam + * @Min: 0 + * @Max: 96 + * @Default: 83 + * + * Minimum roamable AP RSSI for candidate selection for PER based roam + * + * Related: gper_roam_enabled, gper_roam_high_rate_th, gper_roam_low_rate_th, + * gper_roam_th_percent, gper_roam_rest_time + * + * Supported Feature: LFR-3.0 + * + * Usage: Internal + * + * + */ +#define CFG_LFR_PER_ROAM_MIN_CANDIDATE_RSSI CFG_INI_UINT( \ + "gper_min_rssi_threshold_for_roam", \ + 10, \ + 96, \ + 83, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum roamable AP RSSI for candidate selection for PER based roam") + +/* + * + * groam_disallow_duration - disallow duration before roaming + * @Min: 0 + * @Max: 3600 + * @Default: 30 + * + * This ini is used to configure how long LCA[Last Connected AP] AP will + * be disallowed before it can be a roaming candidate again, in units of + * seconds. + * + * Related: LFR + * + * Usage: Internal + * + * + */ +#define CFG_LFR3_ROAM_DISALLOW_DURATION CFG_INI_UINT( \ + "groam_disallow_duration", \ + 0, \ + 3600, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "disallow duration before roaming") + +/* + * + * grssi_channel_penalization - RSSI penalization + * @Min: 0 + * @Max: 15 + * @Default: 5 + * + * This ini is used to configure RSSI that will be penalized if candidate(s) + * are found to be in the same channel as disallowed AP's, in units of db. + * + * Related: LFR + * + * Usage: Internal + * + * + */ +#define CFG_LFR3_ROAM_RSSI_CHANNEL_PENALIZATION CFG_INI_UINT( \ + "grssi_channel_penalization", \ + 0, \ + 15, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "RSSI penalization") + +/* + * + * groam_num_disallowed_aps - Max number of AP's to maintain in LCA list + * @Min: 0 + * @Max: 8 + * @Default: 3 + * + * This ini is used to set the maximum number of AP's to be maintained + * in LCA [Last Connected AP] list. + * + * Related: LFR + * + * Usage: Internal + * + * + */ +#define CFG_LFR3_ROAM_NUM_DISALLOWED_APS CFG_INI_UINT( \ + "groam_num_disallowed_aps", \ + 0, \ + 8, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Max number of AP's to maintain in LCA list") + +/* + * + * enable_5g_band_pref - Enable preference for 5G from INI. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * This ini is used to enable 5G preference parameters. + * + * Related: 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_ENABLE_5G_BAND_PREF CFG_INI_BOOL( \ + "enable_5g_band_pref", \ + 0, \ + "Enable preference for 5G from INI") + +/* + * + * 5g_rssi_boost_threshold - A_band_boost_threshold above which 5G is favored. + * @Min: -70 + * @Max: -55 + * @Default: -60 + * This ini is used to set threshold for 5GHz band preference. + * + * Related: 5g_rssi_boost_factor, 5g_max_rssi_boost + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_5G_RSSI_BOOST_THRESHOLD CFG_INI_INT( \ + "5g_rssi_boost_threshold", \ + -70, \ + -55, \ + -60, \ + CFG_VALUE_OR_DEFAULT, \ + "A_band_boost_threshold above which 5 GHz is favored") + +/* + * + * 5g_rssi_boost_factor - Factor by which 5GHz RSSI is boosted. + * @Min: 0 + * @Max: 2 + * @Default: 1 + * This ini is used to set the 5Ghz boost factor. + * + * Related: 5g_rssi_boost_threshold, 5g_max_rssi_boost + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_5G_RSSI_BOOST_FACTOR CFG_INI_UINT( \ + "5g_rssi_boost_factor", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Factor by which 5GHz RSSI is boosted") + +/* + * + * 5g_max_rssi_boost - Maximum boost that can be applied to 5GHz RSSI. + * @Min: 0 + * @Max: 20 + * @Default: 10 + * This ini is used to set maximum boost which can be given to a 5Ghz network. + * + * Related: 5g_rssi_boost_threshold, 5g_rssi_boost_factor + * 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_5G_MAX_RSSI_BOOST CFG_INI_UINT( \ + "5g_max_rssi_boost", \ + 0, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Maximum boost that can be applied to 5GHz RSSI") + +/* + * + * 5g_rssi_penalize_threshold - A_band_penalize_threshold above which + * 5 GHz is not favored. + * @Min: -80 + * @Max: -65 + * @Default: -70 + * This ini is used to set threshold for 5GHz band preference. + * + * Related: 5g_rssi_penalize_factor, 5g_max_rssi_penalize + * 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_5G_RSSI_PENALIZE_THRESHOLD CFG_INI_INT( \ + "5g_rssi_penalize_threshold", \ + -80, \ + -65, \ + -70, \ + CFG_VALUE_OR_DEFAULT, \ + "A_band_penalize_threshold above which 5 GHz is not favored") + +/* + * + * 5g_rssi_penalize_factor - Factor by which 5GHz RSSI is penalizeed. + * @Min: 0 + * @Max: 2 + * @Default: 1 + * This ini is used to set the 5Ghz penalize factor. + * + * Related: 5g_rssi_penalize_threshold, 5g_max_rssi_penalize + * 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_5G_RSSI_PENALIZE_FACTOR CFG_INI_UINT( \ + "5g_rssi_penalize_factor", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Factor by which 5GHz RSSI is penalizeed") + +/* + * + * 5g_max_rssi_penalize - Maximum penalty that can be applied to 5GHz RSSI. + * @Min: 0 + * @Max: 20 + * @Default: 10 + * This ini is used to set maximum penalty which can be given to a 5Ghz network. + * + * Related: 5g_rssi_penalize_threshold, 5g_rssi_penalize_factor + * 5g_rssi_boost_threshold, 5g_rssi_boost_factor, 5g_max_rssi_boost + * + * Supported Feature: 5G band preference + * + * Usage: External + * + * + */ +#define CFG_LFR_5G_MAX_RSSI_PENALIZE CFG_INI_UINT( \ + "5g_max_rssi_penalize", \ + 0, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Maximum penalty that can be applied to 5GHz RSSI") + +/* + * + * max_num_pre_auth - Configure max number of pre-auth + * @Min: 0 + * @Max: 256 + * @Default: 64 + * + * This ini is used to configure the data max number of pre-auth + * + * Usage: Internal + * + * + */ +#define CFG_LFR_MAX_NUM_PRE_AUTH CFG_UINT( \ + "max_num_pre_auth", \ + 0, \ + 256, \ + 64, \ + CFG_VALUE_OR_DEFAULT, \ + "") + +/* + * + * roam_preauth_retry_count + * + * @Min: 1 + * @Max: 10 + * @Default: 5 + * + * The maximum number of software retries for preauth or + * reassoc made before picking up the next candidate for + * connection during roaming. + * + * Related: N/A + * + * Supported Features: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR3_ROAM_PREAUTH_RETRY_COUNT CFG_INI_INT( \ + "roam_preauth_retry_count", \ + 1, \ + 10, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "The maximum number of software retries for preauth") + +/* + * + * roam_preauth_no_ack_timeout + * + * @Min: 5 + * @Max: 50 + * @Default: 5 + * + * Time to wait (in ms) after sending an preauth or reassoc + * request which didn't have an ack, before considering + * it as a failure and making another software retry. + * + * Related: N/A + * + * Supported Features: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR3_ROAM_PREAUTH_NO_ACK_TIMEOUT CFG_INI_INT( \ + "roam_preauth_no_ack_timeout", \ + 5, \ + 50, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Time to wait after sending an preauth or reassoc") + +/* + * + * FastRoamEnabled - Enable fast roaming + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to inform FW to enable fast roaming + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_FEATURE_ENABLED CFG_INI_BOOL( \ + "FastRoamEnabled", \ + 1, \ + "Enable fast roaming") + +/* + * + * MAWCEnabled - Enable/Disable Motion Aided Wireless Connectivity Global + * @Min: 0 - Disabled + * @Max: 1 - Enabled + * @Default: 0 + * + * This ini is used to controls the MAWC feature globally. + * MAWC is Motion Aided Wireless Connectivity. + * + * Related: mawc_roam_enabled. + * + * Supported Feature: Roaming and PNO/NLO + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_MAWC_FEATURE_ENABLED CFG_INI_BOOL( \ + "MAWCEnabled", \ + 0, \ + "Enable MAWC") + +/* + * + * FastTransitionEnabled - Enable fast transition in case of 11r and ese. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to turn ON/OFF the whole neighbor roam, pre-auth, reassoc. + * With this turned OFF 11r will completely not work. For 11r this flag has to + * be ON. For ESE fastroam will not work. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_FAST_TRANSITION_ENABLED CFG_INI_BOOL( \ + "FastTransitionEnabled", \ + 1, \ + "Enable fast transition") + +/* + * + * RoamRssiDiff - Enable roam based on rssi + * @Min: 0 + * @Max: 100 + * @Default: 5 + * + * This INI is used to decide whether to Roam or not based on RSSI. AP1 is the + * currently associated AP and AP2 is chosen for roaming. The Roaming will + * happen only if AP2 has better Signal Quality and it has a RSSI better than + * AP2. RoamRssiDiff is the number of units (typically measured in dB) AP2 + * is better than AP1. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_RSSI_DIFF CFG_INI_UINT( \ + "RoamRssiDiff", \ + 0, \ + 100, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable roam based on rssi") + +/* + * + * RoamRssiDiff6GHz - Enable roam to 6 GHz AP based on rssi + * @Min: 0 + * @Max: 100 + * @Default: 5 + * + * This INI is used to decide whether to roam to 6 GHz AP or not based on RSSI. + * AP1 is the currently associated AP(2.4 GHz / 5 GHz) and AP2(6 GHz) is chosen + * for roaming. The Roaming will happen only if AP2 has better Signal Quality + * and it has a RSSI better than AP1. RoamRssiDiff6GHz is the number of units + * (typically measured in dB) AP2 is better than AP1. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_RSSI_DIFF_6GHZ CFG_INI_UINT( \ + "RoamRssiDiff6GHz", \ + 0, \ + 100, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable 6 GHz roam based on rssi") + +/* + * + * bg_rssi_threshold - To set RSSI Threshold for BG scan roaming + * @Min: 0 + * @Max: 100 + * @Default: 5 + * + * This INI is used to set the value of rssi threshold to trigger roaming + * after background scan. To trigger roam after bg scan, value of rssi of + * candidate AP should be higher by this threshold than the rssi of the + * currently associated AP. + * + * Related: RoamRssiDiff + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_BG_RSSI_TH CFG_INI_UINT( \ + "bg_rssi_threshold", \ + 0, \ + 100, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable roam based on rssi after BG scan") + +/* + * + * gWESModeEnabled - Enable WES mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable Wireless Extended Security mode. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ENABLE_WES_MODE CFG_INI_BOOL( \ + "gWESModeEnabled", \ + 0, \ + "Enable WES mode") + +/* + * + * gRoamScanOffloadEnabled - Enable Roam Scan Offload + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable Roam Scan Offload in firmware + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED CFG_INI_BOOL( \ + "gRoamScanOffloadEnabled", \ + 1, \ + "Enable Roam Scan Offload") + +/* + * + * gNeighborScanChannelList - Set channels to be scanned + * by firmware for LFR scan + * @Default: "" + * + * This ini is used to set the channels to be scanned + * by firmware for LFR scan. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ + +#define CFG_LFR_NEIGHBOR_SCAN_CHANNEL_LIST CFG_INI_STRING( \ + "gNeighborScanChanList", \ + 0, \ + CFG_VALID_CHANNEL_LIST_STRING_LEN, \ + "", \ + "Set channels to be scanned") + +/* + * + * gNeighborScanTimerPeriod - Set neighbor scan timer period + * @Min: 3 + * @Max: 300 + * @Default: 100 + * + * This ini is used to set the timer period in secs after + * which neighbor scan is triggered. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD CFG_INI_UINT( \ + "gNeighborScanTimerPeriod", \ + 3, \ + 300, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor scan timer period") + +/* + * + * gRoamRestTimeMin/RoamScan_HomeTime - Set min neighbor scan timer period + * @Min: 3 + * @Max: 300 + * @Default: 50 + * + * This is the min rest time after which firmware will check for traffic + * and if there no traffic it will move to a new channel to scan + * else it will stay on the home channel till gNeighborScanTimerPeriod time + * and then will move to a new channel to scan. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_NEIGHBOR_SCAN_MIN_TIMER_PERIOD CFG_INI_UINT( \ + "gRoamRestTimeMin RoamScan_HomeTime", \ + RoamScan_HomeTime_min, \ + RoamScan_HomeTime_max, \ + RoamScan_HomeTime_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Min neighbor scan timer period") + +/* + * + * gNeighborLookupThreshold/RoamRSSI_Trigger - Set neighbor lookup rssi + * threshold + * @Min: -100 + * @Max: -50 + * @Default: -76 + * + * This is used to control the RSSI threshold for neighbor lookup. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD CFG_INI_INT( \ + "gNeighborLookupThreshold RoamRSSI_Trigger", \ + RoamRSSI_Trigger_min, \ + RoamRSSI_Trigger_max, \ + RoamRSSI_Trigger_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor lookup rssi threshold") + +/* + * + * gOpportunisticThresholdDiff - Set oppurtunistic threshold diff + * @Min: 0 + * @Max: 127 + * @Default: 0 + * + * This ini is used to set opportunistic threshold diff. + * This parameter is the RSSI diff above neighbor lookup + * threshold, when opportunistic scan should be triggered. + * MAX value is chosen so that this type of scan can be + * always enabled by user. + * MIN value will cause opportunistic scan to be triggered + * in neighbor lookup RSSI range. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF CFG_INI_UINT( \ + "gOpportunisticThresholdDiff", \ + 0, \ + 127, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Set oppurtunistic threshold diff") + +/* + * + * gRoamRescanRssiDiff/RoamScan_StepRSSI - Sets RSSI for Scan trigger in + * firmware + * @Min: 0 + * @Max: 100 + * @Default: 5 + * + * This INI is the drop in RSSI value that will trigger a precautionary + * scan by firmware. Max value is chosen in such a way that this type + * of scan can be disabled by user. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_RESCAN_RSSI_DIFF CFG_INI_UINT( \ + "gRoamRescanRssiDiff RoamScan_StepRSSI", \ + RoamScan_StepRSSI_min, \ + RoamScan_StepRSSI_max, \ + RoamScan_StepRSSI_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Sets RSSI for Scan trigger in firmware") + +/* + * + * gNeighborScanChannelMinTime - Set neighbor scan channel min time + * @Min: 10 + * @Max: 40 + * @Default: 20 + * + * This ini is used to set the minimum time in secs spent on each + * channel in LFR scan inside firmware. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME CFG_INI_UINT( \ + "gNeighborScanChannelMinTime", \ + 10, \ + 40, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor scan channel min time") + +/* + * + * gNeighborScanChannelMaxTime/RoamScan_ActiveCH_DwellTime - Set neighbor scan + * channel max time + * @Min: 3 + * @Max: 300 + * @Default: 40 + * + * This ini is used to set the maximum time in secs spent on each + * channel in LFR scan inside firmware. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME CFG_INI_UINT( \ + "gNeighborScanChannelMaxTime RoamScan_ActiveCH_DwellTime", \ + RoamScan_ActiveCH_DwellTime_min, \ + RoamScan_ActiveCH_DwellTime_max, \ + RoamScan_ActiveCH_DwellTime_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor scan channel max time") + +/* + * + * gNeighborScanRefreshPeriod - Set neighbor scan refresh period + * @Min: 1000 + * @Max: 60000 + * @Default: 20000 + * + * This ini is used by firmware to set scan refresh period + * in msecs for lfr scan. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD CFG_INI_UINT( \ + "gNeighborScanRefreshPeriod", \ + 1000, \ + 60000, \ + 20000, \ + CFG_VALUE_OR_DEFAULT, \ + "Neighbor scan refresh period") + +/* + * + * gFullRoamScanPeriod - Set full roam scan refresh period + * @Min: 0 + * @Max: 600 + * @Default: 0 + * + * This ini is used by firmware to set full roam scan period in secs. + * Full roam scan period is the minimum idle period in seconds between two + * successive full channel roam scans. If this is configured as a non-zero, + * full roam scan will be triggered for every configured interval. + * If this configured as 0, full roam scan will not be triggered at all. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_FULL_ROAM_SCAN_REFRESH_PERIOD CFG_INI_UINT( \ + "gFullRoamScanPeriod", \ + 0, \ + 600, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Full roam scan refresh period") + +/* + * + * gEmptyScanRefreshPeriod - Set empty scan refresh period + * @Min: 0 + * @Max: 60000 + * @Default: 0 + * + * This ini is used by firmware to set scan period in msecs + * following empty scan results. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD CFG_INI_UINT( \ + "gEmptyScanRefreshPeriod", \ + 0, \ + 60000, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Empty scan refresh period") + + /* + * + * RoamScan_FirstTimer - Set empty scan refresh period + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * This ini is used by firmware to set scan period in secs + * following empty scan results. + * + * Related: None + * + * Supported Feature: LFR Scan + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_FIRST_TIMER CFG_INI_UINT( \ + "RoamScan_FirstTimer", \ + 0, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Empty scan refresh period") + +/* + * + * gRoamBmissFirstBcnt - Beacon miss count to trigger 1st bmiss event + * @Min: 5 + * @Max: 100 + * @Default: 10 + * + * This ini used to control how many beacon miss will trigger first bmiss + * event. First bmiss event will result in roaming scan. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_BMISS_FIRST_BCNT CFG_INI_UINT( \ + "gRoamBmissFirstBcnt", \ + 5, \ + 100, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "First beacon miss count") + +/* + * + * gRoamBmissFinalBcnt - Beacon miss count to trigger final bmiss event + * @Min: 5 + * @Max: 100 + * @Default: 20 + * + * This ini used to control how many beacon miss will trigger final bmiss + * event. Final bmiss event will make roaming take place or cause the + * indication of final bmiss event. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_BMISS_FINAL_BCNT CFG_INI_UINT( \ + "gRoamBmissFinalBcnt", \ + 5, \ + 100, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "Final beacon miss count") + +/* + * + * BeaconLoss_TimeoutOnWakeUp - Consecutive Beaconloss timeout on wakeup to + * trigger timeout + * @Min: 0 + * @Max: 20 + * @Default: 3 + * + * This ini is used to control the beacon miss timeout when the system is awake. + * On the timeout, BMISS event will be triggered by FW. + * The units of this timeout is in seconds. + * + * Related: None + * + * Usage: External + * + * + */ + +/* + * + * BeaconLoss_TimeoutOnWakeUp - Consecutive Beaconloss timeout on wakeup to + * trigger timeout + * @Min: 0 + * @Max: 20 + * @Default: 6 + * + * This ini is used to control the beacon miss timeout when the system is awake. + * On the timeout, BMISS event will be triggered by FW. + * The units of this timeout is in seconds. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_LFR_BEACONLOSS_TIMEOUT_ON_WAKEUP CFG_INI_UINT( \ + "ConBeaconLoss_TimeoutOnWakeUp", \ + CONBEACONLOSS_TIMEOUTONWAKEUP_MIN, \ + CONBEACONLOSS_TIMEOUTONWAKEUP_MAX, \ + CONBEACONLOSS_TIMEOUTONWAKEUP_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "ConBeaconloss timeout on wakeup") + +/* + * + * BeaconLoss_TimeoutOnSleep - Consecutive Beaconloss timeout on sleep to + * trigger timeout + * @Min: 0 + * @Max: 20 + * @Default: 5 + * + * This ini is used to control the beacon miss timeout + * when the system is in sleep. + * On the timeout, BMISS event will be triggered by FW. + * The units of this timeout is in seconds. + * + * Related: None + * + * Usage: External + * + * + */ + +/* + * + * BeaconLoss_TimeoutOnSleep - Consecutive Beaconloss timeout on sleep to + * trigger timeout + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * This ini is used to control the beacon miss timeout + * when the system is in sleep. + * On the timeout, BMISS event will be triggered by FW. + * The units of this timeout is in seconds. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_LFR_BEACONLOSS_TIMEOUT_ON_SLEEP CFG_INI_UINT( \ + "ConBeaconLoss_TimeoutOnSleep", \ + CONBEACONLOSS_TIMEOUTONSLEEP_MIN, \ + CONBEACONLOSS_TIMEOUTONSLEEP_MAX, \ + CONBEACONLOSS_TIMEOUTONSLEEP_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "ConBeaconloss timeout on sleep") + +/* + * + * gAllowDFSChannelRoam - Allow dfs channel in roam + * @Min: 0 + * @Max: 2 + * @Default: 1 + * + * This ini is used to set default dfs channel + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_ROAMING_DFS_CHANNEL CFG_INI_UINT( \ + "gAllowDFSChannelRoam", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Allow dfs channel in roam") + +/* + * + * gRoamScanHiRssiMaxCount - Sets 5GHz maximum scan count + * @Min: 0 + * @Max: 10 + * @Default: 3 + * + * This INI is used to set maximum scan count in 5GHz + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_HI_RSSI_MAXCOUNT CFG_INI_UINT( \ + "gRoamScanHiRssiMaxCount", \ + 0, \ + 10, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "5GHz maximum scan count") + +/* + * + * gRoamScanHiRssiDelta - Sets RSSI Delta for scan trigger + * @Min: 0 + * @Max: 40 + * @Default: 23 + * + * This INI is used to set change in RSSI at which scan is triggered + * in 5GHz. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_HI_RSSI_DELTA CFG_INI_UINT( \ + "gRoamScanHiRssiDelta", \ + 0, \ + 40, \ + 23, \ + CFG_VALUE_OR_DEFAULT, \ + "RSSI Delta for scan trigger") + +/* + * + * gRoamScanHiRssiDelay - Sets minimum delay between 5GHz scans + * @Min: 5000 + * @Max: 0x7fffffff + * @Default: 15000 + * + * This INI is used to set the minimum delay between 5GHz scans. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_HI_RSSI_DELAY CFG_INI_UINT( \ + "gRoamScanHiRssiDelay", \ + 5000, \ + 0x7fffffff, \ + 15000, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum delay between 5GHz scans") + +/* + * + * gRoamScanHiRssiUpperBound - Sets upper bound after which 5GHz scan + * @Min: -66 + * @Max: 0 + * @Default: -30 + * + * This INI is used to set the RSSI upper bound above which the 5GHz scan + * will not be performed. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_HI_RSSI_UB CFG_INI_INT( \ + "gRoamScanHiRssiUpperBound", \ + -66, \ + 0, \ + -30, \ + CFG_VALUE_OR_DEFAULT, \ + "Upper bound after which 5GHz scan") + +/* + * + * gRoamPrefer5GHz - Prefer roaming to 5GHz Bss + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to inform FW to prefer roaming to 5GHz BSS + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_PREFER_5GHZ CFG_INI_BOOL( \ + "gRoamPrefer5GHz", \ + 1, \ + "Prefer roaming to 5GHz Bss") + +/* + * + * gRoamIntraBand - Prefer roaming within Band + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to inform FW to prefer roaming within band + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_INTRA_BAND CFG_INI_BOOL( \ + "gRoamIntraBand", \ + 0, \ + "Prefer roaming within Band") + +/* + * + * gRoamScanNProbes - Sets the number of probes to be sent for firmware roaming + * @Min: 1 + * @Max: 10 + * @Default: 2 + * + * This INI is used to set the maximum number of probes the firmware can send + * for firmware internal roaming cases. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_N_PROBES CFG_INI_UINT( \ + "gRoamScanNProbes", \ + 1, \ + 10, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "The number of probes to be sent for firmware roaming") + +/* + * + * gRoamScanHomeAwayTime/RoamScan_AwayTime - Sets the Home Away Time to firmware + * @Min: 0 + * @Max: 300 + * @Default: 0 + * + * Home Away Time should be at least equal to (gNeighborScanChannelMaxTime + * + (2*RFS)), where RFS is the RF Switching time(3). It is twice RFS + * to consider the time to go off channel and return to the home channel. + * + * Related: gNeighborScanChannelMaxTime + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME CFG_INI_UINT( \ + "gRoamScanHomeAwayTime RoamScan_AwayTime", \ + RoamScan_AwayTime_min, \ + RoamScan_AwayTime_max, \ + RoamScan_AwayTime_default, \ + CFG_VALUE_OR_DEFAULT, \ + "the home away time to firmware") + +/* + * + * gDelayBeforeVdevStop - wait time for tx complete before vdev stop + * @Min: 2 + * @Max: 200 + * @Default: 20 + * + * This INI is used to set wait time for tx complete before vdev stop. + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_LFR_DELAY_BEFORE_VDEV_STOP CFG_INI_UINT( \ + "gDelayBeforeVdevStop", \ + 2, \ + 200, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "wait time for tx complete before vdev stop") +/* + * + * enable_bss_load_roam_trigger - enable/disable bss load based roam trigger + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini when enabled, allows the firmware to roam when bss load outpaces + * the configured bss load threshold. When this ini is disabled, firmware + * doesn't consider bss load values to trigger roam. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM CFG_INI_BOOL( \ + "enable_bss_load_roam_trigger", \ + 0, \ + "enable bss load triggered roaming") + +/* + * + * bss_load_threshold/RoamCU_Trigger - bss load above which the STA should + * trigger roaming + * @Min: 0 + * @Max: 100 + * @Default: 70 + * + * When the bss load value that is sampled exceeds this threshold, firmware + * will trigger roaming if bss load trigger is enabled. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_BSS_LOAD_THRESHOLD CFG_INI_UINT( \ + "bss_load_threshold RoamCU_Trigger", \ + RoamCU_Trigger_min, \ + RoamCU_Trigger_max, \ + RoamCU_Trigger_default, \ + CFG_VALUE_OR_DEFAULT, \ + "bss load threshold") + +/* + * + * bss_load_sample_time - Time in milliseconds for which the bss load values + * obtained from the beacons is sampled. + * @Min: 0 + * @Max: 0xffffffff + * @Default: 10000 + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_BSS_LOAD_SAMPLE_TIME CFG_INI_UINT( \ + "bss_load_sample_time", \ + 0, \ + 0xffffffff, \ + 10000, \ + CFG_VALUE_OR_DEFAULT, \ + "bss load sampling time") + +/* + * + * RoamCU_MonitorTime - Time in seconds for which the bss load values + * obtained from the beacons is sampled. + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_CU_MONITOR_TIME CFG_INI_UINT( \ + "RoamCU_MonitorTime", \ + 0, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "bss load sampling time") + +/* + * + * bss_load_trigger_6g_rssi_threshold/RoamCU_6GRSSIRange - + * Current AP minimum RSSI in dBm below + * which roaming can be triggered if BSS load exceeds bss_load_threshold. + * @Min: -120 + * @Max: 0 + * @Default: -70 + * + * If connected AP is in 6Ghz, then consider bss load roam triggered only if + * load % > bss_load_threshold && connected AP rssi is worse than + * bss_load_trigger_6g_rssi_threshold + * + * Related: "bss_load_threshold" + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ + +/* + * + * bss_load_trigger_6g_rssi_threshold/RoamCU_6GRSSIRange - + * Current AP minimum RSSI in dBm below + * which roaming can be triggered if BSS load exceeds bss_load_threshold. + * @Min: -70 + * @Max: -50 + * @Default: -70 + * + * If connected AP is in 6Ghz, then consider bss load roam triggered only if + * load % > bss_load_threshold && connected AP rssi is worse than + * bss_load_trigger_6g_rssi_threshold + * + * Related: "bss_load_threshold" + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_BSS_LOAD_TRIG_6G_RSSI_THRES CFG_INI_INT( \ + "bss_load_trigger_6g_rssi_threshold RoamCU_6GRSSIRange", \ + ROAMCU_6GRSSIRANGE_MIN, \ + ROAMCU_6GRSSIRANGE_MAX, \ + ROAMCU_6GRSSIRANGE_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum RSSI of current AP in 6GHz band for BSS load roam trigger") + +/* + * + * bss_load_trigger_5g_rssi_threshold/RoamCU_5GRSSIRange - + * Current AP minimum RSSI in dBm below + * which roaming can be triggered if BSS load exceeds bss_load_threshold. + * @Min: -120 + * @Max: 0 + * @Default: -70 + * + * If connected AP is in 5Ghz, then consider bss load roam triggered only if + * load % > bss_load_threshold && connected AP rssi is worse than + * bss_load_trigger_5g_rssi_threshold + * + * Related: "bss_load_threshold" + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_BSS_LOAD_TRIG_5G_RSSI_THRES CFG_INI_INT( \ + "bss_load_trigger_5g_rssi_threshold RoamCU_5GRSSIRange", \ + RoamCU_5GRSSIRange_min, \ + RoamCU_5GRSSIRange_max, \ + RoamCU_5GRSSIRange_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum RSSI of current AP in 5GHz band for BSS load roam trigger") + +/* + * + * bss_load_trigger_2g_rssi_threshold/RoamCU_24GRSSIRange - + * Current AP minimum RSSI in dBm below + * which roaming can be triggered if BSS load exceeds bss_load_threshold. + * @Min: -120 + * @Max: 0 + * @Default: -60 + * + * If connected AP is in 2Ghz, then consider bss load roam triggered only if + * load % > bss_load_threshold && connected AP rssi is worse than + * bss_load_trigger_2g_rssi_threshold. + * + * Related: "bss_load_threshold" + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_BSS_LOAD_TRIG_2G_RSSI_THRES CFG_INI_INT( \ + "bss_load_trigger_2g_rssi_threshold RoamCU_24GRSSIRange", \ + RoamCU_24GRSSIRange_min, \ + RoamCU_24GRSSIRange_max, \ + RoamCU_24GRSSIRange_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum RSSI of current AP in 2.4GHz band for BSS load roam trigger") + +/* + * + * ho_delay_for_rx - Delay hand-off (in msec) by this duration to receive + * pending rx frames from current BSS + * @Min: 0 + * @Max: 200 + * @Default: 0 + * + * For LFR 3.0 roaming scenario, once roam candidate is found, firmware + * waits for minimum this much duration to receive pending rx frames from + * current BSS before switching to new channel for handoff to new AP. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR3_ROAM_HO_DELAY_FOR_RX CFG_INI_UINT( \ + "ho_delay_for_rx", \ + 0, \ + 200, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Delay Hand-off by this duration to receive") + +/* + * + * min_delay_btw_roam_scans - Min duration (in sec) allowed btw two + * consecutive roam scans + * @Min: 0 + * @Max: 60 + * @Default: 10 + * + * Roam scan is not allowed if duration between two consecutive + * roam scans is less than this time. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_MIN_DELAY_BTW_ROAM_SCAN CFG_INI_UINT( \ + "min_delay_btw_roam_scans", \ + 0, \ + 60, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Min duration") + +/* + * + * roam_trigger_reason_bitmask - Contains roam_trigger_reasons + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 0x10DA + * + * Bitmask containing roam_trigger_reasons for which + * min_delay_btw_roam_scans constraint should be applied. + * Currently supported bit positions are as follows: + * Bit 0 is reserved in the firmware. + * WMI_ROAM_TRIGGER_REASON_PER - 1 + * WMI_ROAM_TRIGGER_REASON_BMISS - 2 + * WMI_ROAM_TRIGGER_REASON_LOW_RSSI - 3 + * WMI_ROAM_TRIGGER_REASON_HIGH_RSSI - 4 + * WMI_ROAM_TRIGGER_REASON_PERIODIC - 5 + * WMI_ROAM_TRIGGER_REASON_MAWC - 6 + * WMI_ROAM_TRIGGER_REASON_DENSE - 7 + * WMI_ROAM_TRIGGER_REASON_BACKGROUND - 8 + * WMI_ROAM_TRIGGER_REASON_FORCED - 9 + * WMI_ROAM_TRIGGER_REASON_BTM - 10 + * WMI_ROAM_TRIGGER_REASON_UNIT_TEST - 11 + * WMI_ROAM_TRIGGER_REASON_BSS_LOAD - 12 + * WMI_ROAM_TRIGGER_REASON_DEAUTH - 13 + * WMI_ROAM_TRIGGER_REASON_IDLE - 14 + * WMI_ROAM_TRIGGER_REASON_MAX - 15 + * + * For Ex: 0xDA (PER, LOW_RSSI, HIGH_RSSI, MAWC, DENSE) + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_SCAN_TRIGGER_REASON_BITMASK CFG_INI_UINT( \ + "roam_trigger_reason_bitmask", \ + 0, \ + 0xFFFFFFFF, \ + 0x10DA, \ + CFG_VALUE_OR_DEFAULT, \ + "Contains roam_trigger_reasons") + +/* + * + * enable_ftopen - enable/disable FT open feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable/disable FT open feature + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_FT_OPEN_ENABLE CFG_INI_BOOL( \ + "enable_ftopen", \ + 1, \ + "enable/disable FT open feature") + +/* + * + * roam_force_rssi_trigger - To force RSSI trigger + * irrespective of channel list type + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set roam scan mode + * WMI_ROAM_SCAN_MODE_RSSI_CHANGE, irrespective of whether + * channel list type is CHANNEL_LIST_STATIC or not + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ROAM_FORCE_RSSI_TRIGGER CFG_INI_BOOL( \ + "roam_force_rssi_trigger", \ + 1, \ + "To force RSSI trigger") + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * + * gRoamOffloadEnabled - enable/disable roam offload feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable/disable roam offload feature + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR3_ROAMING_OFFLOAD CFG_INI_BOOL( \ + "gRoamOffloadEnabled", \ + 1, \ + "enable roam offload") + +/* + * + * enable_self_bss_roam - enable/disable roaming to self bss + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is used to enable/disable roaming to already connected BSSID + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define CFG_LFR3_ENABLE_SELF_BSS_ROAM CFG_INI_BOOL( \ + "enable_self_bss_roam", \ + 1, \ + "enable self bss roam") + +/* + * + * enable_disconnect_roam_offload - Enable/Disable emergency roaming during + * deauth/disassoc + * @Min: 0 - Disabled + * @Max: 1 - Enabled + * @Default: 1 + * + * When this ini is enabled firmware will trigger roam scan and roam to a new ap + * if candidate is found and it will not send the deauth/disassoc frame to + * the host driver. + * If roaming fails after this deauth, then firmware will send + * WMI_ROAM_REASON_DEAUTH event to the host. If roaming is successful, driver + * follows the normal roam synch event path. + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_ENABLE_DISCONNECT_ROAM CFG_INI_BOOL( \ + "enable_disconnect_roam_offload", \ + true, \ + "Enable/Disable roaming on deauth/disassoc from AP") + +/* + * + * enable_idle_roam - Enable/Disable idle roaming + * @Min: 0 - Disabled + * @Max: 1 - Enabled + * @Default: 0 + * + * When this ini is enabled firmware will trigger roam scan and roam to a new + * ap if current connected AP rssi falls below the threshold. To consider the + * connection as idle, the following conditions should be met if this ini + * "enable_idle_roam" is enabled: + * 1. User space sends "SET SUSPENDMODE" command with value 0. + * 2. No TX/RX data for idle time configured via ini "idle_roam_inactive_time". + * 3. Connected AP rssi change doesn't exceed a specific delta value. + * (configured via ini idle_roam_rssi_delta) + * 4. Connected AP rssi falls below minimum rssi (configured via ini + * "idle_roam_min_rssi"). + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_ENABLE_IDLE_ROAM CFG_INI_BOOL( \ + "enable_idle_roam", \ + false, \ + "Enable/Disable idle roam") + +/* + * + * idle_roam_rssi_delta/RoamIdle_RSSIVariation - This threshold is the criteria + * to decide whether DUT is idle or moving. If rssi delta is more than + * configured threshold then its considered as not idle. RSSI delta is entered + *in dBm. Idle roaming can be triggered if the connected AP rssi change exceeds + * or falls below the rssi delta and if other criteria of ini "enable_idle_roam" + * is met + * @Min: 0 + * @Max: 50 + * @Default: 3 + * + * Related: enable_idle_roam + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_IDLE_ROAM_RSSI_DELTA CFG_INI_UINT( \ + "idle_roam_rssi_delta RoamIdle_RSSIVariation", \ + RoamIdle_RSSIVariation_min, \ + RoamIdle_RSSIVariation_max, \ + RoamIdle_RSSIVariation_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure RSSI delta to start idle roam") + +/* + * + * idle_roam_inactive_time - Time duration in milliseconds for which the + * connection is idle. + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 10000 + * + * This ini is used to configure the time in seconds for which the connection + * candidate is idle and after which idle roam scan can be triggered if + * other criteria of ini "enable_idle_roam" is met. + * + * Related: enable_idle_roam + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_IDLE_ROAM_INACTIVE_TIME CFG_INI_UINT( \ + "idle_roam_inactive_time", \ + 0, \ + 0xFFFFFFFF, \ + 10000, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure RSSI delta to start idle roam") + +/* + * + * RoamIdle_InactiveTime - Time duration in seconds for which the + * connection is idle. + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * This ini is used to configure the time in seconds for which the connection + * candidate is idle and after which idle roam scan can be triggered if + * other criteria of ini "enable_idle_roam" is met. + * + * Related: enable_idle_roam + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_ROAM_IDLE_INACTIVE_TIME CFG_INI_UINT( \ + "RoamIdle_InactiveTime", \ + 0, \ + 20, \ + RoamIdle_InactiveTime_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure RSSI delta to start idle roam") + +/* + * + * idle_data_packet_count/RoamIdle_InactivePacketCount - No of tx/rx packets + * above which the connection is not idle. + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 10 + * + * This ini is used to configure the acceptable number of tx/rx packets below + * which the connection is idle. Ex: If idle_data_packet_count is 10 + * and if the tx/rx packet count is less than 10, the connection is + * idle. If there are more than 10 packets, the connection is active one. + * + * Related: enable_idle_roam + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_IDLE_ROAM_PACKET_COUNT CFG_INI_UINT( \ + "idle_data_packet_count RoamIdle_InactivePacketCount", \ + RoamIdle_InactivePacketCount_min, \ + RoamIdle_InactivePacketCount_max, \ + RoamIdle_InactivePacketCount_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure idle packet count") + +/* + * + * idle_roam_min_rssi/RoamIdle_MinRSSI - Minimum RSSI of connected AP, below + * which idle roam scan can be triggered if other criteria of ini + * "enable_idle_roam" is met. + * @Min: -96 + * @Max: 0 + * @Default: -65 + * + * Related: enable_idle_roam + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_IDLE_ROAM_MIN_RSSI CFG_INI_INT( \ + "idle_roam_min_rssi RoamIdle_MinRSSI", \ + RoamIdle_MinRSSI_min, \ + RoamIdle_MinRSSI_max, \ + RoamIdle_MinRSSI_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Configure idle roam minimum RSSI") + +/* + * + * idle_roam_band/RoamIdle_TriggerBand - Band on which idle roam scan will be + * enabled + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * Value 0 - Allow idle roam on both bands + * Value 1 - Allow idle roam only on 2G band + * Value 2 - Allow idle roam only on 5G band + * + * Related: enable_idle_roam + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_LFR_IDLE_ROAM_BAND CFG_INI_UINT( \ + "idle_roam_band RoamIdle_TriggerBand", \ + RoamIdle_TriggerBand_min, \ + RoamIdle_TriggerBand_max, \ + RoamIdle_TriggerBand_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Band on which idle roam needs to be enabled") + +/* + * + * roam_triggers - Bitmap of roaming triggers. Setting this to + * zero will disable roaming altogether for the STA interface. + * ESS report element of beacon explores BSS information, for roaming station + * uses it to consider next AP to roam. ROAM_TRIGGER_REASON_ESS_RSSI bit is + * to enable/disable roam trigger for ESS RSSI reason. This bit of ini is also + * used for WFA certification. + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 0x3FFFF + * + * ROAM_TRIGGER_REASON_PER BIT 1 + * ROAM_TRIGGER_REASON_BMISS BIT 2 + * ROAM_TRIGGER_REASON_LOW_RSSI BIT 3 + * ROAM_TRIGGER_REASON_HIGH_RSSI BIT 4 + * ROAM_TRIGGER_REASON_PERIODIC BIT 5 + * ROAM_TRIGGER_REASON_MAWC BIT 6 + * ROAM_TRIGGER_REASON_DENSE BIT 7 + * ROAM_TRIGGER_REASON_BACKGROUND BIT 8 + * ROAM_TRIGGER_REASON_FORCED BIT 9 + * ROAM_TRIGGER_REASON_BTM BIT 10 + * ROAM_TRIGGER_REASON_UNIT_TEST BIT 11 + * ROAM_TRIGGER_REASON_BSS_LOAD BIT 12 + * ROAM_TRIGGER_REASON_DEAUTH BIT 13 + * ROAM_TRIGGER_REASON_IDLE BIT 14 + * ROAM_TRIGGER_REASON_STA_KICKOUT BIT 15 + * ROAM_TRIGGER_REASON_ESS_RSSI BIT 16 + * ROAM_TRIGGER_REASON_WTC_BTM BIT 17 + * ROAM_TRIGGER_REASON_PMK_TIMEOUT BIT 18 + * ROAM_TRIGGER_REASON_BTC BIT 19 + * ROAM_TRIGGER_REASON_MAX BIT 20 + * + * Related: none + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_TRIGGER_BITMAP CFG_INI_UINT( \ + "roam_triggers", \ + 0, \ + 0xFFFFFFFF, \ + 0x7FFFF, \ + CFG_VALUE_OR_DEFAULT, \ + "Bitmap of roaming triggers") + +/* + * + * sta_disable_roam - Disable Roam on sta interface + * @Min: 0 - Roam Enabled on sta interface + * @Max: 0xffffffff - Roam Disabled on sta interface irrespective + * of other interface connections + * @Default: 0x00 + * + * Disable roaming on STA iface to avoid audio glitches on p2p and ndp if + * those are in connected state. Each bit for "sta_disable_roam" INI represents + * an interface for which sta roaming can be disabled. + * + * LFR3_STA_ROAM_DISABLE_BY_P2P BIT(0) + * LFR3_STA_ROAM_DISABLE_BY_NAN BIT(1) + * + * Related: None. + * + * Supported Feature: ROAM + * + * Usage: Internal + * + * + */ +#define CFG_STA_DISABLE_ROAM CFG_INI_UINT( \ + "sta_disable_roam", \ + 0, \ + 0xffffffff, \ + 0x00, \ + CFG_VALUE_OR_DEFAULT, \ + "disable roam on STA iface if one of the iface mentioned in default is in connected state") + +/* + * + * enable_dual_sta_roam_offload - Enable roaming offload on both interfaces + * for STA + STA + * @Min: 0 - Dual STA Roam offload Disabled + * @Max: 1 - Dual STA Roam offload Enabled + * @Default: 1 + * + * Enabling this ini will: + * a) Enforce the STA + STA connection be DBS if the hw is capable. + * b) Enable Roam Scan Offload on both the STA vdev. + * c) Enable firmware to support sequential roaming on both STA vdev + * if the firmware is capable of dual sta roaming. + * + * Related: None. + * + * Supported Feature: ROAM + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DUAL_STA_ROAM_OFFLOAD CFG_INI_UINT( \ + "enable_dual_sta_roam_offload", \ + false, \ + true, \ + true, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable roam on both STA vdev") + +#define ROAM_OFFLOAD_ALL \ + CFG(CFG_LFR3_ROAMING_OFFLOAD) \ + CFG(CFG_LFR3_ENABLE_SELF_BSS_ROAM) \ + CFG(CFG_LFR_ENABLE_DISCONNECT_ROAM) \ + CFG(CFG_LFR_ENABLE_IDLE_ROAM) \ + CFG(CFG_LFR_IDLE_ROAM_RSSI_DELTA) \ + CFG(CFG_LFR_IDLE_ROAM_INACTIVE_TIME) \ + CFG(CFG_ROAM_IDLE_INACTIVE_TIME) \ + CFG(CFG_LFR_IDLE_ROAM_PACKET_COUNT) \ + CFG(CFG_LFR_IDLE_ROAM_MIN_RSSI) \ + CFG(CFG_LFR_IDLE_ROAM_BAND) \ + CFG(CFG_ROAM_TRIGGER_BITMAP) \ + CFG(CFG_STA_DISABLE_ROAM) \ + CFG(CFG_ENABLE_DUAL_STA_ROAM_OFFLOAD) \ + +#else +#define ROAM_OFFLOAD_ALL +#endif + +#ifdef FEATURE_WLAN_ESE +/* + * + * EseEnabled - Enable ESE feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable ESE feature + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR_ESE_FEATURE_ENABLED CFG_INI_BOOL( \ + "EseEnabled", \ + 0, \ + "Enable ESE") +#define LFR_ESE_ALL CFG(CFG_LFR_ESE_FEATURE_ENABLED) +#else +#define LFR_ESE_ALL +#endif + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/* + * + * gLFRSubnetDetectionEnable - Enable LFR3 subnet detection + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Enable IP subnet detection during legacy fast roming version 3. Legacy fast + * roaming could roam across IP subnets without host processors' knowledge. + * This feature enables firmware to wake up the host processor if it + * successfully determines change in the IP subnet. Change in IP subnet could + * potentially cause disruption in IP connnectivity if IP address is not + * refreshed. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_LFR3_ENABLE_SUBNET_DETECTION CFG_INI_BOOL( \ + "gLFRSubnetDetectionEnable", \ + 1, \ + "Enable LFR3 subnet detection") + +#define LFR_SUBNET_DETECTION_ALL CFG(CFG_LFR3_ENABLE_SUBNET_DETECTION) +#else +#define LFR_SUBNET_DETECTION_ALL +#endif + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/* + * + * sae_single_pmk_feature_enabled - Enable/disable sae single pmk feature. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This INI is to enable/disable SAE Roaming with same PMK/PMKID feature support + * + * Related: None. + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define CFG_SAE_SINGLE_PMK CFG_INI_BOOL( \ + "sae_single_pmk_feature_enabled", \ + true, \ + "Enable/disable SAE Roaming with single PMK/PMKID") + +#define SAE_SINGLE_PMK_ALL CFG(CFG_SAE_SINGLE_PMK) +#else +#define SAE_SINGLE_PMK_ALL +#endif + +#ifdef WLAN_ADAPTIVE_11R +/* + * + * adaptive_11r - Enable/disable adaptive 11r feature. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Adaptive 11r feature enables the AP to support FT-AKM without + * configuring the FT-AKM in the network. The AP will advertise non-FT akm + * with a vendor specific IE having Adaptive 11r bit set to 1 in the IE data. + * The AP also advertises the MDE in beacon/probe response. + * + * STA should check the adaptive 11r capability if the AP advertises MDE in + * beacon/probe and adaptive 11r capability in vendor specific IE. If adaptive + * 11r capability is found, STA can advertise the FT equivalent of the non-FT + * AKM and connect with 11r protocol. + * + * Related: None. + * + * Supported Feature: Fast BSS Transition + * + * Usage: External + * + * + */ +#define CFG_ADAPTIVE_11R CFG_INI_BOOL( \ + "enable_adaptive_11r", \ + false, \ + "Enable/disable adaptive 11r support") + +#define ADAPTIVE_11R_ALL CFG(CFG_ADAPTIVE_11R) +#else +#define ADAPTIVE_11R_ALL +#endif + +/* + * + * roaming_scan_policy - To config roaming scan policy + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to configure roaming scan behavior from HOST + * 0 : DBS scan + * 1 : Non-DBS scan + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_SCAN_POLICY CFG_INI_BOOL( \ + "roaming_scan_policy", \ + 0, \ + "Config roam scan policy") + +/* + * + * enable_ft_im_roaming - FW needs to perform FT initial moiblity association + * instead of FT roaming for deauth roam trigger + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to FT roaming for deauth roam trigger behavior from HOST + * 0 - To disable FT-IM + * 1 - To enable FT-IM + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define CFG_FT_IM_ROAMING CFG_INI_BOOL( \ + "enable_ft_im_roaming", \ + 1, \ + "FT roaming for deauth roam trigger") + +/* + * + * roam_scan_inactivity_time - Device inactivity monitoring time in + * milliseconds for which the device is considered to be inactive with data + * packets count is less than configured roam_inactive_data_count. + * + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 0 + * + * The below three ini values are used to control the roam scan after the + * firmware gets empty roam scan results during periodic roam scans. + * 1. roam_scan_inactivity_time + * 2. roam_inactive_data_count + * The first two ini "roam_scan_inactivity_time" and "roam_inactive_data_count" + * is frames the criteria to detect if the DUT is inactive. + * + * Related: roam_inactive_data_count + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_INACTIVITY_TIME CFG_INI_UINT( \ + "roam_scan_inactivity_time", \ + 0, \ + 0xFFFFFFFF, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Device inactivity monitoring time") + + /* + * + * RoamScan_SecondTimer - Device inactivity monitoring time in + * seconds for which the device is considered to be inactive with data + * packets count is less than configured RoamScan_InactiveCount. + * + * @Min: 60 + * @Max: 300 + * @Default: 120 + * + * The below three ini values are used to control the roam scan after the + * firmware gets empty roam scan results during periodic roam scans. + * 1. RoamScan_SecondTimer + * 2. RoamScan_InactiveCount + * 3. RoamScan_InactiveTimer + * The first two ini "RoamScan_SecondTimer" and "RoamScan_InactiveCount" + * is frames the criteria to detect if the DUT is inactive. If the device is + * identified to be inactive based on the above two ini, then the value, + * "RoamScan_InactiveTimer" will be used as periodic roam scan + * duration. + * + * Related: RoamScan_InactiveCount + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_SECOND_TIMER CFG_INI_UINT( \ + "RoamScan_SecondTimer", \ + 60, \ + 300, \ + 120, \ + CFG_VALUE_OR_DEFAULT, \ + "Device inactivity monitoring time") + +/* + * + * roam_inactive_data_count/RoamScan_InactiveCount - Maximum allowed data + * packets count during roam_scan_inactivity_time. + * + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 10 + * + * The DUT is said to be inactive only if the data packets count + * during this roam_scan_inactivity_time is less than the configured + * roam_inactive_data_count. + * + * Related: roam_scan_inactivity_time + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_INACTIVE_COUNT CFG_INI_UINT( \ + "roam_inactive_data_count RoamScan_InactiveCount", \ + RoamScan_InactiveCount_min, \ + RoamScan_InactiveCount_max, \ + RoamScan_InactiveCount_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Roam scan inactivity period data pkt count") + +/* + * + * RoamScan_InactiveTimer - Roam scan duration in sec after device is + * out of inactivity state. + * + * @Min: 0 + * @Max: 20 + * @Default: 10 + * + * If there is empty scan results during roam scan, firmware will move to + * roam scan inactive state if roam_scan_inactivity and + * roam_inactive_data_count criteria are met. + * This ini is used to configure the roam scan duration in sec once the + * inactivity is finished and roam scan can be started. + * + * Related: roam_scan_inactivity_time, roam_inactive_data_count + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCAN_INACTIVE_TIMER CFG_INI_UINT( \ + "RoamScan_InactiveTimer", \ + 0, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Roam scan period post inactivity") + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * + * enable_roam_reason_vsie - Enable/Disable inclusion of Roam Reason + * in Re(association) frame + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable fw to include/exclude roam reason vsie in + * Re(association) + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: internal + * + * + */ +#define CFG_ENABLE_ROAM_REASON_VSIE CFG_INI_BOOL( \ + "enable_roam_reason_vsie", \ + 0, \ + "To Enable enable_roam_reason_vsie") +#define ROAM_REASON_VSIE_ALL CFG(CFG_ENABLE_ROAM_REASON_VSIE) +#else +#define ROAM_REASON_VSIE_ALL +#endif + +/* + * + * groam_info_stats_num - number of wlan driver cache roam information + * @Min: 0 + * @Max: 32 + * @Default: 5 + * + * This ini is used to set the cache number of enhanced roam + * information, including roam trigger, scan information and + * roam frame information. + * If ini set to 0, enhanced roam feature not support + * + * Related: LFR + * + * Usage: External + * + * + */ +#define CFG_LFR3_ROAM_INFO_STATS_NUM CFG_INI_UINT( \ + "groam_info_stats_num", \ + 0, \ + 32, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Roam information cache number in wlan driver") + +/* + * + * hs20_btm_offload_disable - To enable/disable BTM offload + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable BTM offload for Hotspot 2.0. + * Some solutions may not have Hotspot 2.0 certification + * and there is no need to forward the BTM frame to wpa_supplicant, + * in such solutions Let firmware handle the frame, in such cases by + * enabling btm_offload so that it doesn't wakeup the host. + * Firmware may roam to another AP upon BTM reception. + * + * Related: LFR + * + * Usage: External + * + * + */ +#define CFG_HS_20_BTM_OFFLOAD_DISABLE CFG_INI_BOOL( \ + "hs20_btm_offload_disable", \ + true, \ + "To Enable/disable BTM offload for hotspot 2.0") + +#define CFG_LFR_ALL \ + CFG(CFG_LFR_MAWC_ROAM_ENABLED) \ + CFG(CFG_LFR_MAWC_ROAM_TRAFFIC_THRESHOLD) \ + CFG(CFG_LFR_MAWC_ROAM_AP_RSSI_THRESHOLD) \ + CFG(CFG_LFR_MAWC_ROAM_RSSI_HIGH_ADJUST) \ + CFG(CFG_LFR_MAWC_ROAM_RSSI_LOW_ADJUST) \ + CFG(CFG_LFR_ROAM_RSSI_ABS_THRESHOLD) \ + CFG(CFG_LFR_5G_RSSI_THRESHOLD_OFFSET) \ + CFG(CFG_LFR_ENABLE_FAST_ROAM_IN_CONCURRENCY) \ + CFG(CFG_LFR_EARLY_STOP_SCAN_ENABLE) \ + CFG(CFG_LFR_EARLY_STOP_SCAN_MIN_THRESHOLD) \ + CFG(CFG_LFR_EARLY_STOP_SCAN_MAX_THRESHOLD) \ + CFG(CFG_LFR_ROAM_DENSE_TRAFFIC_THRESHOLD) \ + CFG(CFG_LFR_ROAM_DENSE_RSSI_THRE_OFFSET) \ + CFG(CFG_LFR_ROAM_DENSE_MIN_APS) \ + CFG(CFG_LFR_ROAM_BG_SCAN_BAD_RSSI_THRESHOLD) \ + CFG(CFG_LFR_ROAM_BG_SCAN_CLIENT_BITMAP) \ + CFG(CFG_LFR_ROAM_BG_SCAN_BAD_RSSI_OFFSET_2G) \ + CFG(CFG_ROAM_DATA_RSSI_THRESHOLD_TRIGGERS) \ + CFG(CFG_ROAM_DATA_RSSI_THRESHOLD) \ + CFG(CFG_RX_DATA_INACTIVITY_TIME) \ + CFG(CFG_LFR_ADAPTIVE_ROAMSCAN_DWELL_MODE) \ + CFG(CFG_LFR_PER_ROAM_ENABLE) \ + CFG(CFG_LFR_PER_ROAM_CONFIG_HIGH_RATE_TH) \ + CFG(CFG_LFR_PER_ROAM_CONFIG_LOW_RATE_TH) \ + CFG(CFG_LFR_PER_ROAM_CONFIG_RATE_TH_PERCENT) \ + CFG(CFG_LFR_PER_ROAM_REST_TIME) \ + CFG(CFG_LFR_PER_ROAM_MONITOR_TIME) \ + CFG(CFG_LFR_PER_ROAM_MIN_CANDIDATE_RSSI) \ + CFG(CFG_LFR3_ROAM_DISALLOW_DURATION) \ + CFG(CFG_LFR3_ROAM_RSSI_CHANNEL_PENALIZATION) \ + CFG(CFG_LFR3_ROAM_NUM_DISALLOWED_APS) \ + CFG(CFG_LFR_ENABLE_5G_BAND_PREF) \ + CFG(CFG_LFR_5G_RSSI_BOOST_THRESHOLD) \ + CFG(CFG_LFR_5G_RSSI_BOOST_FACTOR) \ + CFG(CFG_LFR_5G_MAX_RSSI_BOOST) \ + CFG(CFG_LFR_5G_RSSI_PENALIZE_THRESHOLD) \ + CFG(CFG_LFR_5G_RSSI_PENALIZE_FACTOR) \ + CFG(CFG_LFR_5G_MAX_RSSI_PENALIZE) \ + CFG(CFG_LFR_MAX_NUM_PRE_AUTH) \ + CFG(CFG_LFR3_ROAM_PREAUTH_RETRY_COUNT) \ + CFG(CFG_LFR3_ROAM_PREAUTH_NO_ACK_TIMEOUT) \ + CFG(CFG_LFR_FEATURE_ENABLED) \ + CFG(CFG_LFR_MAWC_FEATURE_ENABLED) \ + CFG(CFG_LFR_FAST_TRANSITION_ENABLED) \ + CFG(CFG_LFR_ROAM_RSSI_DIFF) \ + CFG(CFG_LFR_ROAM_RSSI_DIFF_6GHZ) \ + CFG(CFG_LFR_ROAM_BG_RSSI_TH) \ + CFG(CFG_LFR_ENABLE_WES_MODE) \ + CFG(CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED) \ + CFG(CFG_LFR_NEIGHBOR_SCAN_CHANNEL_LIST) \ + CFG(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD) \ + CFG(CFG_LFR_NEIGHBOR_SCAN_MIN_TIMER_PERIOD) \ + CFG(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD) \ + CFG(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF) \ + CFG(CFG_LFR_ROAM_RESCAN_RSSI_DIFF) \ + CFG(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME) \ + CFG(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME) \ + CFG(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD) \ + CFG(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) \ + CFG(CFG_ROAM_SCAN_FIRST_TIMER) \ + CFG(CFG_LFR_ROAM_BMISS_FIRST_BCNT) \ + CFG(CFG_LFR_ROAM_BMISS_FINAL_BCNT) \ + CFG(CFG_LFR_ROAMING_DFS_CHANNEL) \ + CFG(CFG_LFR_ROAM_SCAN_HI_RSSI_MAXCOUNT) \ + CFG(CFG_LFR_ROAM_SCAN_HI_RSSI_DELTA) \ + CFG(CFG_LFR_ROAM_SCAN_HI_RSSI_DELAY) \ + CFG(CFG_LFR_ROAM_SCAN_HI_RSSI_UB) \ + CFG(CFG_LFR_ROAM_PREFER_5GHZ) \ + CFG(CFG_LFR_ROAM_INTRA_BAND) \ + CFG(CFG_LFR_ROAM_SCAN_N_PROBES) \ + CFG(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME) \ + CFG(CFG_LFR_DELAY_BEFORE_VDEV_STOP) \ + CFG(CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM) \ + CFG(CFG_BSS_LOAD_THRESHOLD) \ + CFG(CFG_BSS_LOAD_SAMPLE_TIME) \ + CFG(CFG_ROAM_CU_MONITOR_TIME) \ + CFG(CFG_LFR3_ROAM_HO_DELAY_FOR_RX) \ + CFG(CFG_LFR_MIN_DELAY_BTW_ROAM_SCAN) \ + CFG(CFG_LFR_ROAM_SCAN_TRIGGER_REASON_BITMASK) \ + CFG(CFG_LFR_ROAM_FT_OPEN_ENABLE) \ + CFG(CFG_LFR_ROAM_FORCE_RSSI_TRIGGER) \ + CFG(CFG_ROAM_SCAN_SCAN_POLICY) \ + CFG(CFG_ROAM_SCAN_INACTIVITY_TIME) \ + CFG(CFG_ROAM_SCAN_SECOND_TIMER) \ + CFG(CFG_FT_IM_ROAMING) \ + CFG(CFG_ROAM_INACTIVE_COUNT) \ + CFG(CFG_ROAM_PASSIVE_MAX_CHANNEL_TIME) \ + CFG(CFG_ROAM_SCAN_INACTIVE_TIMER) \ + CFG(CFG_BSS_LOAD_TRIG_6G_RSSI_THRES) \ + CFG(CFG_BSS_LOAD_TRIG_5G_RSSI_THRES) \ + CFG(CFG_BSS_LOAD_TRIG_2G_RSSI_THRES) \ + CFG(CFG_LFR_FULL_ROAM_SCAN_REFRESH_PERIOD) \ + ADAPTIVE_11R_ALL \ + ROAM_OFFLOAD_ALL \ + LFR_ESE_ALL \ + LFR_SUBNET_DETECTION_ALL \ + SAE_SINGLE_PMK_ALL \ + ROAM_REASON_VSIE_ALL \ + CFG(CFG_LFR_BEACONLOSS_TIMEOUT_ON_WAKEUP) \ + CFG(CFG_LFR_BEACONLOSS_TIMEOUT_ON_SLEEP) \ + CFG(CFG_LFR3_ROAM_INFO_STATS_NUM) \ + CFG(CFG_HS_20_BTM_OFFLOAD_DISABLE) + +#endif /* CFG_MLME_LFR_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_mbo.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_mbo.h new file mode 100644 index 0000000000..02dce2278e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_mbo.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of QOS related + * converged configurations. + */ + +#ifndef __CFG_MLME_MBO_H +#define __CFG_MLME_MBO_H + +/* + * + * g_mbo_candidate_rssi_thres - Candidate AP's minimum RSSI to accept + * @Min: -120 + * @Max: 0 + * @Default: -72 + * + * This ini specifies the minimum RSSI value a candidate should have to accept + * it as a target for transition. + * + * Related: N/A + * + * Supported Feature: MBO + * + * Usage: Internal + * + * + */ +#define CFG_MBO_CANDIDATE_RSSI_THRESHOLD CFG_INI_INT( \ + "g_mbo_candidate_rssi_thres", \ + -120, \ + 0, \ + -72, \ + CFG_VALUE_OR_DEFAULT, \ + "candidate AP rssi threshold") +/* + * + * g_mbo_current_rssi_thres - Connected AP's RSSI threshold to consider a + * transition + * @Min: -120 + * @Max: 0 + * @Default: -65 + * + * This ini is used to configure connected AP's RSSI threshold value to consider + * a transition. + * + * Related: N/A + * + * Supported Feature: MBO + * + * Usage: Internal + * + * + */ +#define CFG_MBO_CURRENT_RSSI_THRESHOLD CFG_INI_INT( \ + "g_mbo_current_rssi_thres", \ + -120, \ + 0, \ + -65, \ + CFG_VALUE_OR_DEFAULT, \ + "current AP rssi threshold") + +/* + * + * g_mbo_current_rssi_mcc_thres - connected AP's RSSI threshold value to prefer + * against a MCC + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * This ini is used to configure connected AP's minimum RSSI threshold that is + * preferred against a MCC case, if the candidate can cause MCC. + * + * Related: N/A + * + * Supported Feature: MBO + * + * Usage: Internal + * + * + */ +#define CFG_MBO_CUR_RSSI_MCC_THRESHOLD CFG_INI_INT( \ + "g_mbo_current_rssi_mcc_thres", \ + -120, \ + 0, \ + -75, \ + CFG_VALUE_OR_DEFAULT, \ + "current AP mcc rssi threshold") + +/* + * + * g_mbo_candidate_rssi_btc_thres - Candidate AP's minimum RSSI threshold to + * prefer it even in case of BT coex + * @Min: -120 + * @Max: 0 + * @Default: -70 + * + * This ini is used to configure candidate AP's minimum RSSI threshold to prefer + * it for transition even in case of BT coex. + * + * Related: N/A + * + * Supported Feature: MBO + * + * Usage: Internal + * + * + */ +#define CFG_MBO_CAND_RSSI_BTC_THRESHOLD CFG_INI_INT( \ + "g_mbo_candidate_rssi_btc_thres", \ + -120, \ + 0, \ + -70, \ + CFG_VALUE_OR_DEFAULT, \ + "candidate AP rssi threshold") + +#define CFG_MBO_ALL \ + CFG(CFG_MBO_CANDIDATE_RSSI_THRESHOLD) \ + CFG(CFG_MBO_CURRENT_RSSI_THRESHOLD) \ + CFG(CFG_MBO_CUR_RSSI_MCC_THRESHOLD) \ + CFG(CFG_MBO_CAND_RSSI_BTC_THRESHOLD) + +#endif /* __CFG_MLME_MBO_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_mwc.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_mwc.h new file mode 100644 index 0000000000..677cafe44b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_mwc.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains configuration definitions for MLME WMC. + */ +#ifndef CFG_MLME_MWC_H_ +#define CFG_MLME_MWC_H_ + +#ifdef MWS_COEX +/* + * + * gMwsCoex4gQuickTdm - Bitmap to control MWS-COEX 4G quick FTDM policy + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * It is a 32 bit value such that the various bits represent as below: + * Bit-0 : 0 - Don't allow quick FTDM policy (Default) + * 1 - Allow quick FTDM policy + * Bit 1-31 : reserved for future use + * + * It is used to enable or disable MWS-COEX 4G (LTE) Quick FTDM + * + * Usage: Internal + * + * + */ + +#define CFG_MWS_COEX_4G_QUICK_FTDM CFG_INI_UINT( \ + "gMwsCoex4gQuickTdm", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "set mws-coex 4g quick ftdm policy") + +/* + * + * gMwsCoex5gnrPwrLimit - Bitmap to set MWS-COEX 5G-NR power limit + * @Min: 0x00000000 + * @Max: 0xFFFFFFFF + * @Default: 0x00000000 + * + * It is a 32 bit value such that the various bits represent as below: + * Bit-0 : Don't apply user specific power limit, + * use internal power limit (Default) + * Bit 1-2 : Invalid value (Ignored) + * Bit 3-21 : Apply the specified value as the external power limit, in dBm + * Bit 22-31 : Invalid value (Ignored) + * + * It is used to set MWS-COEX 5G-NR power limit + * + * Usage: Internal + * + * + */ + +#define CFG_MWS_COEX_5G_NR_PWR_LIMIT CFG_INI_UINT( \ + "gMwsCoex5gnrPwrLimit", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x00000000, \ + CFG_VALUE_OR_DEFAULT, \ + "set mws-coex 5g-nr power limit") + +/* + * + * mws_coex_pcc_channel_avoid_delay - configures the duration, when WWAN PCC + * (Primary Component Carrier) conflicts with WLAN channel. + * @Min: 0x00 + * @Max: 0xFF + * @Default: 0x3C + * + * It is used to set MWS-COEX WWAN PCC channel avoidance delay + * + * Usage: External + * + * + */ +#define CFG_MWS_COEX_PCC_CHANNEL_AVOID_DELAY CFG_INI_UINT(\ + "mws_coex_pcc_channel_avoid_delay", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x3C, \ + CFG_VALUE_OR_DEFAULT, \ + "set mws-coex PCC channel avoidance delay") + +/* + * + * mws_coex_scc_channel_avoid_delay - configures the duration, when WWAN SCC + * (Secondary Component Carrier) conflicts with WLAN channel. + * @Min: 0x00 + * @Max: 0xFF + * @Default: 0x78 + * + * It is used to set MWS-COEX WWAN SCC channel avoidance delay + * + * Usage: External + * + * + */ +#define CFG_MWS_COEX_SCC_CHANNEL_AVOID_DELAY CFG_INI_UINT(\ + "mws_coex_scc_channel_avoid_delay", \ + 0x00000000, \ + 0xFFFFFFFF, \ + 0x78, \ + CFG_VALUE_OR_DEFAULT, \ + "set mws-coex SCC channel avoidance delay") + +#define CFG_MWC_ALL \ + CFG(CFG_MWS_COEX_4G_QUICK_FTDM) \ + CFG(CFG_MWS_COEX_5G_NR_PWR_LIMIT) \ + CFG(CFG_MWS_COEX_PCC_CHANNEL_AVOID_DELAY) \ + CFG(CFG_MWS_COEX_SCC_CHANNEL_AVOID_DELAY) + +#else +#define CFG_MWC_ALL +#endif /* MWS_COEX */ + +#endif /* CFG_MLME_MWC_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_nss_chains.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_nss_chains.h new file mode 100644 index 0000000000..2a91ed45a9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_nss_chains.h @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_NSS_CHAINS +#define __CFG_MLME_NSS_CHAINS + +/* + * + * num_tx_chains_2g - Config Param to change number of tx + * chains per vdev for 2.4ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249 - change all vdev's num tx chains for 2.4ghz connection to 1 each + * 0x02492492 - change all vdev's num tx chains for 2.4ghz connection to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_TX_CHAINS_2G CFG_INI_UINT( \ + "num_tx_chains_2g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num tx chains 2g") + +/* + * + * num_tx_chains_5g - Config Param to change number of tx + * chains per vdev for 5 ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249- change all vdev's tx num chains for 5ghz connection to 1 each + * 0x02492492 - change all vdev's tx num chains for 5ghz connection to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_TX_CHAINS_5G CFG_INI_UINT( \ + "num_tx_chains_5g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num tx chains 5g") + +/* + * + * num_rx_chains_2g - Config Param to change number of rx + * chains per vdev for 2.4 ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249 - change all vdev's rx num chains for 2.4ghz connections to 1 each + * 0x02492492 - change all vdev's rx num chains for 2.4ghz connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_RX_CHAINS_2G CFG_INI_UINT( \ + "num_rx_chains_2g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num rx chains 2g") + +/* + * + * num_rx_chains_5g - Config Param to change number of rx + * chains per vdev for 5 ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249 - change all vdev's rx num chains for 5ghz connections to 1 each + * 0x02492492 - change all vdev's rx num chains for 5ghz connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_RX_CHAINS_5G CFG_INI_UINT( \ + "num_rx_chains_5g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num rx chains 5g") + +/* + * + * tx_nss_2g - Config Param to change tx nss + * per vdev for 2.4ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of tx spatial streams for eg:- + * 0x01249249 - change all vdev's tx nss for 2.4ghz connections to 1 each + * 0x02492492 - change all vdev's tx nss for 2.4ghz connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_TX_NSS_2G CFG_INI_UINT( \ + "tx_nss_2g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "tx nss 2.4ghz") + +/* + * + * tx_nss_5g - Config Param to change tx nss + * per vdev for 5ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of tx spatial streams for eg:- + * 0x01249249 - change all vdev's tx nss for 5ghz connections to 1 each + * 0x02492492 - change all vdev's tx nss for 5ghz connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_TX_NSS_5G CFG_INI_UINT( \ + "tx_nss_5g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "tx nss 5ghz") + +/* + * + * rx_nss_2g - Config Param to change rx nss + * per vdev for 2.4ghz frequency connections + * + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of rx spatial streams for eg:- + * 0x01249249 - change all vdev's rx nss for 2.4ghz connections to 1 each + * 0x02492492 - change all vdev's rx nss for 2.4ghz connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_RX_NSS_2G CFG_INI_UINT( \ + "rx_nss_2g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "rx nss 2.4ghz") + +/* + * + * rx_nss_5g - Config Param to change rx nss + * per vdev for 5ghz frequency connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of rx spatial streams for eg:- + * 0x01249249 - change all vdev's rx nss for 5ghz connections to 1 each + * 0x02492492 - change all vdev's rx nss for 5ghz connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_RX_NSS_5G CFG_INI_UINT( \ + "rx_nss_5g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "rx nss 5ghz") + +/* + * + * num_tx_chains_11b - Config Param to change number of tx + * chains per vdev for 2.4ghz 11b mode connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249 - change all vdev's num chains for 11b connections to 1 each + * 0x02492492 - change all vdev's num chains for 11b connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_TX_CHAINS_11b CFG_INI_UINT( \ + "num_tx_chains_11b", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num tx chains 11b") + +/* + * + * num_tx_chains_11g - Config Param to change number of tx + * chains per vdev for 2.4ghz 11g mode connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249 - change all vdev's num chains for 11g connections to 1 each + * 0x02492492 - change all vdev's num chains for 11g connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_TX_CHAINS_11g CFG_INI_UINT( \ + "num_tx_chains_11g", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num tx chains 11g") + +/* + * + * num_tx_chains_11a - Config Param to change number of tx + * chains per vdev for 5ghz 11a mode connections + * @Min: 0x01249249 + * @Max: 0x02492492 + * @Default: 0x02492492 + * + * This ini is used to change the num of chains for eg:- + * 0x01249249 - change all vdev's num chains for 11a connections to 1 each + * 0x02492492 - change all vdev's num chains for 11a connections to 2 each + * Bits VDEV Type + * BIT[0:2] STA + * BIT[3:5] SAP + * BIT[6:8] P2P GO + * BIT[9:11] P2P Client + * BIT[12:14] TDLS + * BIT[15:17] IBSS + * BIT[18:20] P2P device + * BIT[21:23] OCB + * BIT[24:26] NAN + * BIT[27:31] Reserved + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_NUM_TX_CHAINS_11a CFG_INI_UINT( \ + "num_tx_chains_11a", \ + 0x01249249, \ + 0x02492492, \ + 0x02492492, \ + CFG_VALUE_OR_DEFAULT, \ + "num tx chains 11a") + +/* + * + * disable_tx_mrc_2g - Config Param to disable 2 chains in 1x1 nss mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_DISABLE_TX_MRC_2G CFG_INI_BOOL( \ + "disable_tx_mrc_2g", \ + 0, \ + "disable diversity gain tx 2g") + +/* + * + * disable_rx_mrc_2g - Config Param to disable 2 chains in 1x1 nss mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_DISABLE_RX_MRC_2G CFG_INI_BOOL( \ + "disable_rx_mrc_2g", \ + 0, \ + "disable diversity gain rx 2g") + +/* + * + * disable_tx_mrc_5g - Config Param to disable 2 chains in 1x1 nss mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_DISABLE_TX_MRC_5G CFG_INI_BOOL( \ + "disable_tx_mrc_5g", \ + 0, \ + "disable diversity gain tx 5g") + +/* + * + * disable_rx_mrc_5g - Config Param to disable 2 chains in 1x1 nss mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: STA/SAP/P2P/IBSS/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_DISABLE_RX_MRC_5G CFG_INI_BOOL( \ + "disable_rx_mrc_5g", \ + 0, \ + "disable diversity gain rx 5g") + +/* + * + * enable_dynamic_nss_chain_config - Enable/Disable dynamic nss and chain config + * to FW. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: STA/SAP/P2P/NAN. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_ENABLE_DYNAMIC_NSS_CHAIN_CONFIG CFG_INI_BOOL( \ + "enable_dynamic_nss_chain_config", \ + 1, \ + "enable dynamic nss chain config") + +/* + * + * restart_sap_on_dynamic_nss_chains_config - Decide whether SAP needs to be + * restarted on dynamic nss chains update + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: SAP/P2P. + * + * Supported Feature: Dynamic chainmask + * + * Usage: External + * + * + */ +#define CFG_RESTART_SAP_ON_DYNAMIC_NSS_CHAINS_CONFIG CFG_INI_BOOL( \ + "restart_sap_on_dynamic_nss_chains_config", \ + 0, \ + "Restart SAP on dynamic nss chain config") + +#define CFG_NSS_CHAINS_ALL \ + CFG(CFG_NUM_TX_CHAINS_2G) \ + CFG(CFG_NUM_TX_CHAINS_5G) \ + CFG(CFG_NUM_RX_CHAINS_2G) \ + CFG(CFG_NUM_RX_CHAINS_5G) \ + CFG(CFG_TX_NSS_5G) \ + CFG(CFG_TX_NSS_2G) \ + CFG(CFG_RX_NSS_5G) \ + CFG(CFG_RX_NSS_2G) \ + CFG(CFG_NUM_TX_CHAINS_11b) \ + CFG(CFG_NUM_TX_CHAINS_11g) \ + CFG(CFG_NUM_TX_CHAINS_11a) \ + CFG(CFG_DISABLE_TX_MRC_2G) \ + CFG(CFG_DISABLE_RX_MRC_2G) \ + CFG(CFG_DISABLE_TX_MRC_5G) \ + CFG(CFG_DISABLE_RX_MRC_5G) \ + CFG(CFG_ENABLE_DYNAMIC_NSS_CHAIN_CONFIG) \ + CFG(CFG_RESTART_SAP_ON_DYNAMIC_NSS_CHAINS_CONFIG) + +#endif /* __CFG_MLME_NSS_CHAINS */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_obss_ht40.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_obss_ht40.h new file mode 100644 index 0000000000..4f1bff0d01 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_obss_ht40.h @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains configuration definitions for MLME OBSS HT40. + */ +#ifndef CFG_MLME_OBSS_HT40_H__ +#define CFG_MLME_OBSS_HT40_H__ + +/* + * + * obss_active_dwelltime - Set obss active dwelltime + * @Min: 10 + * @Max: 1000 + * @Default: 10 + * + * This ini is used to set dwell time in secs for active + * obss scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME CFG_INI_UINT( \ + "obss_active_dwelltime", \ + 10, \ + 1000, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Set obss active dwelltime") + +/* + * + * obss_passive_dwelltime - Set obss passive dwelltime + * @Min: 5 + * @Max: 1000 + * @Default: 20 + * + * This ini is used to set dwell time in secs for passive + * obss scan + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME CFG_INI_UINT( \ + "obss_passive_dwelltime", \ + 5, \ + 1000, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "Set obss passive dwelltime") + +/* + * + * obss_width_trigger_interval - Set obss trigger interval + * @Min: 10 + * @Max: 900 + * @Default: 200 + * + * This ini is used during an OBSS scan operation, + * where each channel in the set is scanned at least + * once per configured trigger interval time. Unit is TUs. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL CFG_INI_UINT( \ + "obss_width_trigger_interval", \ + 10, \ + 900, \ + 200, \ + CFG_VALUE_OR_DEFAULT, \ + "Set obss trigger interval") + +/* + * obss_passive_total_per_channel - Set obss scan passive total per channel + * @Min: 200 + * @Max: 10000 + * @Default: 200 + * + * FW can perform multiple scans with in a OBSS scan interval. This cfg is for + * the total per channel dwell time of passive scans. Unit is TUs. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + */ +#define CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL CFG_UINT( \ + "obss_passive_total_per_channel", \ + 200, \ + 10000, \ + 200, \ + CFG_VALUE_OR_DEFAULT, \ + "obss passive total per channel") + +/* + * obss_active_total_per_channel - Set obss scan active total per channel + * @Min: 20 + * @Max: 10000 + * @Default: 20 + * + * FW can perform multiple scans with in a OBSS scan interval. This cfg is for + * the total per channel dwell time of active scans. Unit is TUs. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + */ +#define CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL CFG_UINT( \ + "obss_active_total_per_channel", \ + 20, \ + 10000, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "obss active total per channel") + +/* + * obss_scan_activity_thre - Set obss scan activity threshold + * @Min: 0 + * @Max: 100 + * @Default: 25 + * + * This cfg sets obss scan activity threshold. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + */ +#define CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD CFG_UINT( \ + "obss_scan_activity_thre", \ + 0, \ + 100, \ + 25, \ + CFG_VALUE_OR_DEFAULT, \ + "obss ht40 scan activity threshold") + +/* + * obss_width_transition_delay - Set obss width transition delay + * @Min: 5 + * @Max: 100 + * @Default: 5 + * + * This cfg sets obss width transition delay, it is used to check exemption + * from scan. The unit is TUs. + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: Internal + * + */ +#define CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY CFG_UINT( \ + "obss_width_transition_delay", \ + 5, \ + 100, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "obss ht40 width transition delay") + +/* + * + * override_ht20_40_24g - Use channel bonding in 2.4GHz from supplicant + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini used to set whether use channel Bonding in 2.4GHz from supplicant + * if gChannelBondingMode24GHz is set + * + * Related: gChannelBondingMode24GHz + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_OBSS_HT40_OVERRIDE_HT40_20_24GHZ CFG_INI_BOOL( \ + "override_ht20_40_24g", \ + 0, \ + "Use channel bonding in 24 GHz") + +/* + * + * obss_detection_offload - Enable OBSS detection offload + * @Min: 0 + * @Max: 1 + * @Default: 0 + */ +#define CFG_OBSS_DETECTION_OFFLOAD CFG_BOOL( \ + "obss_detection_offload", \ + 0, \ + "Enable OBSS detection offload") + +/* + * + * obss_color_collision_offload - Enable obss color collision offload + * @Min: 0 + * @Max: 1 + * @Default: 0 + */ +#define CFG_OBSS_COLOR_COLLISION_OFFLOAD CFG_BOOL( \ + "obss_color_collision_offload", \ + 0, \ + "Enable obss color collision offload") + +/* + * + * bss_color_collision_det_sta - Enables BSS color collision detection in STA + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini used to enable or disable the BSS color collision detection in + * STA mode if obss_color_collision_offload is enabled. + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_BSS_CLR_COLLISION_DETCN_STA CFG_INI_BOOL( \ + "bss_color_collision_det_sta", \ + 1, \ + "BSS color collision detection in STA") + +#define CFG_OBSS_HT40_ALL \ + CFG(CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME) \ + CFG(CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME) \ + CFG(CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL) \ + CFG(CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL) \ + CFG(CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL) \ + CFG(CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD) \ + CFG(CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY) \ + CFG(CFG_OBSS_HT40_OVERRIDE_HT40_20_24GHZ) \ + CFG(CFG_OBSS_DETECTION_OFFLOAD) \ + CFG(CFG_BSS_CLR_COLLISION_DETCN_STA) \ + CFG(CFG_OBSS_COLOR_COLLISION_OFFLOAD) + +#endif /* CFG_MLME_OBSS_HT40_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_oce.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_oce.h new file mode 100644 index 0000000000..90142a21f1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_oce.h @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_OCE_H +#define __CFG_MLME_OCE_H + +/* + * + * g_enable_bcast_probe_rsp - Enable Broadcast probe response. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable broadcast probe response. + * If this is disabled then OCE ini oce_sta_enable will also be + * disabled and OCE IE will not be sent in frames. + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_ENABLE_BCAST_PROBE_RESP CFG_INI_BOOL( \ + "g_enable_bcast_probe_rsp", \ + 1, \ + "Enable Broadcast probe response") + +/* + * + * oce_sta_enable - Enable/disable oce feature for STA + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable oce feature for STA + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_OCE_ENABLE_STA CFG_INI_BOOL( \ + "oce_sta_enable", \ + 1, \ + "Enable/disable oce feature for STA") + +/* + * + * oce_sap_enable - Enable/disable oce feature for SAP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable oce feature for SAP + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_OCE_ENABLE_SAP CFG_INI_BOOL( \ + "oce_sap_enable", \ + 1, \ + "Enable/disable oce feature for SAP") + +/* + * + * oce_enable_rssi_assoc_reject - Enable/disable rssi based assoc rejection + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable rssi based assoc rejection. If this is + * disabled then OCE ini oce_sta_enable will also be disabled and OCE IE will + * not be sent in frames. + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT CFG_INI_BOOL( \ + "oce_enable_rssi_assoc_reject", \ + 1, \ + "Enable/disable rssi based assoc rejection") + +/* + * + * oce_enable_probe_req_rate - Set probe request rate + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set probe request rate to 5.5Mbps as per OCE requirement + * in 2.4G band + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_OCE_PROBE_REQ_RATE CFG_INI_BOOL( \ + "oce_enable_probe_req_rate", \ + 1, \ + "Set probe request rate for OCE") + +/* + * + * oce_enable_probe_resp_rate - Set probe response rate + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set probe response rate to 5.5Mbps as per OCE requirement + * in 2.4G band + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_OCE_PROBE_RSP_RATE CFG_INI_BOOL( \ + "oce_enable_probe_resp_rate", \ + 0, \ + "Set probe response rate for OCE") + +/* + * + * oce_enable_beacon_rate - Set beacon rate + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set beacon rate to 5.5Mbps as per OCE requirement in + * 2.4G band + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_OCE_BEACON_RATE CFG_INI_BOOL( \ + "oce_enable_beacon_rate", \ + 0, \ + "Set Beacon rate for OCE") +/* + * + * oce_enable_probe_req_deferral - Enable/disable probe request deferral + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable probe request deferral as per OCE spec + * + * Related: None + * + * Supported Feature: OCE + * + * Usage: External + * + * + */ +#define CFG_ENABLE_PROBE_REQ_DEFERRAL CFG_INI_BOOL( \ + "oce_enable_probe_req_deferral", \ + 1, \ + "Enable/disable probe request deferral for OCE") + +/* + * + * oce_enable_fils_discovery_sap - Enable/disable fils discovery in sap mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable fils discovery in sap mode + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_ENABLE_FILS_DISCOVERY_SAP CFG_INI_BOOL( \ + "oce_enable_fils_discovery_sap", \ + 1, \ + "Enable/disable fils discovery in sap mode") + +/* + * + * enable_esp_for_roam - Enable/disable esp feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable ESP(Estimated service parameters) IE + * parsing and decides whether firmware will include this in its scoring algo. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_ESP_FEATURE CFG_INI_BOOL( \ + "enable_esp_for_roam", \ + 1, \ + "Enable/disable esp feature") + +/* + * + * g_is_fils_enabled - Enable/Disable FILS support in driver + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable FILS support in driver + * Driver will update config to supplicant based on this config. + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_IS_FILS_ENABLED CFG_INI_BOOL( \ + "g_is_fils_enabled", \ + 1, \ + "Enable/disable support") + +#define CFG_OCE_ALL \ + CFG(CFG_ENABLE_BCAST_PROBE_RESP) \ + CFG(CFG_OCE_ENABLE_STA) \ + CFG(CFG_OCE_ENABLE_SAP) \ + CFG(CFG_OCE_ENABLE_RSSI_BASED_ASSOC_REJECT) \ + CFG(CFG_OCE_PROBE_REQ_RATE) \ + CFG(CFG_OCE_PROBE_RSP_RATE) \ + CFG(CFG_OCE_BEACON_RATE) \ + CFG(CFG_ENABLE_PROBE_REQ_DEFERRAL) \ + CFG(CFG_ENABLE_FILS_DISCOVERY_SAP) \ + CFG(CFG_ENABLE_ESP_FEATURE) \ + CFG(CFG_IS_FILS_ENABLED) +#endif /* __CFG_MLME_OCE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_power.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_power.h new file mode 100644 index 0000000000..14f06d4a91 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_power.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_POWER_H +#define __CFG_MLME_POWER_H + +/* + * + * max_tx_power_24 - max tx power allowed for 2.4 ghz + * @Min: 0 minimum length of tx power + * @Max: default data length of tx power in string format + * @Default: 1, 14, 20 + * + * This ini contains the string in the form of first_channel number, + * number of channels and max tx power triplets + */ +#define CFG_MAX_TX_POWER_2_4_DATA "1, 14, 20" +#define CFG_MAX_TX_POWER_2_4 CFG_STRING( \ + "max_tx_power_24", \ + 0, \ + sizeof(CFG_MAX_TX_POWER_2_4_DATA) - 1, \ + CFG_MAX_TX_POWER_2_4_DATA, \ + "max tx power 24") + +/* + * + * max_tx_power_5 - max tx power allowed for 5 ghz + * @Min: 0 minimum length of tx power + * @Max: default data length of tx power in string format + * @Default: 36, 126, 20 + * + * This ini contains the string in the form of first_channel number, + * number of channels and max tx power triplets + */ +#define CFG_MAX_TX_POWER_5_DATA "36, 126, 20" +#define CFG_MAX_TX_POWER_5 CFG_STRING( \ + "max_tx_power_5", \ + 0, \ + sizeof(CFG_MAX_TX_POWER_5_DATA) - 1, \ + CFG_MAX_TX_POWER_5_DATA, \ + "max tx power 5") + +/* + * + * gPowerUsage - power usage name + * @Min: "Min" - minimum power usage + * @Max: "Max" - maximum power usage + * @Default: "Mod" + * + * Usage: Internal/External + * + * + */ + +#define CFG_POWER_USAGE CFG_INI_STRING( \ + "gPowerUsage", \ + 0, \ + 3, \ + "Mod", \ + "power usage") +/* + * + * TxPower2g - Limit power in case of 2.4ghz + * @Min: 0 + * @Max: 30 + * @Default: 30 + * + * Usage: Internal/External + * + * + */ + +#define CFG_SET_TXPOWER_LIMIT2G CFG_INI_UINT( \ + "TxPower2g", \ + 0, \ + 30, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "power limit 2g") +/* + * + * TxPower5g - Limit power in case of 5ghz + * @Min: 0 + * @Max: 30 + * @Default: 30 + * + * Usage: Internal/External + * + * + */ + +#define CFG_SET_TXPOWER_LIMIT5G CFG_INI_UINT( \ + "TxPower5g", \ + 0, \ + 30, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "power limit 5g") + +/* + * + * current_tx_power_level - current tx power level + * @Min: 0 + * @Max: 128 + * @Default: 27 + */ +#define CFG_CURRENT_TX_POWER_LEVEL CFG_UINT( \ + "current_tx_power_level", \ + 0, \ + 128, \ + 27, \ + CFG_VALUE_OR_DEFAULT, \ + "current tx power level") + +/* + * + * local_power_constraint - local power constraint + * @Min: 0 + * @Max: 255 + * @Default: 0 + */ +#define CFG_LOCAL_POWER_CONSTRAINT CFG_UINT( \ + "local_power_constraint", \ + 0, \ + 255, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "local power constraint") + +/* + * + * skip_tpe_consideration - Skip TPE IE value in tx power calculation for + * 2G/5G bands + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is to determine if the TPE IE should be considered in the Tx power + * calculation. If the ini is set, host will consider TPE IE in case of 6GHz + * only (skip over in 2GHz or 5GHz case). If the ini is not set, honor the TPE + * IE values in all bands. + * + * Related: None + * + * Supported Feature: Transmit power calculation (TPC) + * + * Usage: External + * + * + */ +#define CFG_SKIP_TPE_CONSIDERATION CFG_INI_BOOL("skip_tpe_consideration", \ + true, \ + "consider TPE IE in tx power") + +#define CFG_MLME_POWER_ALL \ + CFG(CFG_MAX_TX_POWER_2_4) \ + CFG(CFG_MAX_TX_POWER_5) \ + CFG(CFG_POWER_USAGE) \ + CFG(CFG_SET_TXPOWER_LIMIT2G) \ + CFG(CFG_SET_TXPOWER_LIMIT5G) \ + CFG(CFG_CURRENT_TX_POWER_LEVEL) \ + CFG(CFG_LOCAL_POWER_CONSTRAINT) \ + CFG(CFG_SKIP_TPE_CONSIDERATION) + +#endif /* __CFG_MLME_POWER_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_powersave.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_powersave.h new file mode 100644 index 0000000000..2780ae9403 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_powersave.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of power save related + * converged configurations. + */ + +#ifndef __CFG_MLME_POWERSAVE_H +#define __CFG_MLME_POWERSAVE_H + +/* + * + * gEnableImps - Enable/Disable IMPS + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/Disable IMPS(IdleModePowerSave) Mode + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_IMPS CFG_INI_BOOL( \ + "gEnableImps", \ + 1,\ + "Enable/disable IMPS") + +/* + * + * gEnableBmps - Enable/Disable BMPS + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/Disable BMPS(BeaconModePowerSave) Mode + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_PS CFG_INI_BOOL( \ + "gEnableBmps", \ + 1,\ + "Enable/disable BMPS") + +/* + * + * gAutoBmpsTimerValue - Set Auto BMPS Timer value + * @Min: 0 + * @Max: 1000 + * @Default: 600 + * + * This ini is used to set Auto BMPS Timer value in seconds + * + * Related: gEnableBmps + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_AUTO_BMPS_ENABLE_TIMER CFG_INI_UINT( \ + "gAutoBmpsTimerValue", \ + 0, \ + 1000, \ + 600, \ + CFG_VALUE_OR_DEFAULT, \ + "Auto BMPS Timer value") + +/* + * + * gBmpsMinListenInterval - Set BMPS Minimum Listen Interval + * @Min: 1 + * @Max: 65535 + * @Default: 1 + * + * This ini is used to set BMPS Minimum Listen Interval. If gPowerUsage + * is set "Min", this INI need to be set. + * + * Related: gEnableBmps, gPowerUsage + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_BMPS_MINIMUM_LI CFG_INI_UINT( \ + "gBmpsMinListenInterval", \ + 1, \ + 65535, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "BMPS Minimum Listen Interval") + +/* + * + * gBmpsMaxListenInterval - Set BMPS Maximum Listen Interval + * @Min: 1 + * @Max: 65535 + * @Default: 1 + * + * This ini is used to set BMPS Maximum Listen Interval. If gPowerUsage + * is set "Max", this INI need to be set. + * + * Related: gEnableBmps, gPowerUsage + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_BMPS_MAXIMUM_LI CFG_INI_UINT( \ + "gBmpsMaxListenInterval", \ + 1, \ + 65535, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "BMPS Maximum Listen Interval") + +/* + * + * gEnableDTIMSelectionDiversity - Enable/Disable chain + * selection optimization for one chain dtim + * @Min: 0 + * @Max: 30 + * @Default: 5 + * + * Usage: External + * + * + */ +#define CFG_DTIM_SELECTION_DIVERSITY CFG_INI_UINT( \ + "gEnableDTIMSelectionDiversity", \ + 0, \ + 30, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Chain selection diversity value") + +#define CFG_POWERSAVE_ALL \ + CFG(CFG_ENABLE_IMPS) \ + CFG(CFG_ENABLE_PS) \ + CFG(CFG_AUTO_BMPS_ENABLE_TIMER) \ + CFG(CFG_BMPS_MINIMUM_LI) \ + CFG(CFG_BMPS_MAXIMUM_LI) \ + CFG(CFG_DTIM_SELECTION_DIVERSITY) + +#endif /* __CFG_MLME_POWERSAVE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_rates.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_rates.h new file mode 100644 index 0000000000..35ea03dd9d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_rates.h @@ -0,0 +1,313 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_RATES_H +#define __CFG_MLME_RATES_H + +#define CFG_SUPPORTED_RATES_11B_LEN 4 +#define CFG_SUPPORTED_RATES_11A_LEN 8 +#define CFG_OPERATIONAL_RATE_SET_LEN 12 +#define CFG_EXTENDED_OPERATIONAL_RATE_SET_LEN 8 +#define CFG_SUPPORTED_MCS_SET_LEN 16 +#define CFG_BASIC_MCS_SET_LEN 16 +#define CFG_CURRENT_MCS_SET_LEN 16 +#define CFG_MLME_RATE_MASK_LEN 4 + +/* + * + * gMaxHTMCSForTxData - max HT mcs for TX + * @Min: 0 + * @Max: 383 + * @Default: 0 + * + * This ini is used to configure the max HT mcs + * for tx data. + * + * Usage: External + * + * bits 0-15: max HT mcs + * bits 16-31: zero to disable, otherwise enable. + * + * + */ +#define CFG_MAX_HT_MCS_FOR_TX_DATA CFG_INI_UINT( \ + "gMaxHTMCSForTxData", \ + 0, \ + 0x17f, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Max HT Mcs for Tx Data") + +/* + * + * gDisableABGRateForTxData - disable abg rate for tx data + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disable abg rate for tx data. + * + * Usage: External + * + * + */ +#define CFG_DISABLE_ABG_RATE_FOR_TX_DATA CFG_INI_BOOL( \ + "gDisableABGRateForTxData", \ + 0, \ + "Disable ABG RATE for TX Data") + +/* + * + * gSapMaxMCSForTxData - sap 11n max mcs + * @Min: 0 + * @Max: 383 + * @Default: 0 + * + * This ini configure SAP 11n max mcs + * + * Usage: External + * + * + */ +#define CFG_SAP_MAX_MCS_FOR_TX_DATA CFG_INI_UINT( \ + "gSapMaxMCSForTxData", \ + 0, \ + 383, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "SAP Max MCS for TX Data") + +/* + * + * disable_high_ht_mcs_2x2 - disable high mcs index for 2nd stream in 2.4G + * @Min: 0 + * @Max: 8 + * @Default: 0 + * + * This ini is used to disable high HT MCS index for 2.4G STA connection. + * It has been introduced to resolve IOT issue with one of the vendor. + * + * Note: This INI is not useful with 1x1 setting. If some platform supports + * only 1x1 then this INI is not useful. + * + * 0 - It won't disable any HT MCS index (just like normal HT MCS) + * 1 - It will disable 15th bit from HT RX MCS set (from 8-15 bits slot) + * 2 - It will disable 14th & 15th bits from HT RX MCS set + * 3 - It will disable 13th, 14th, & 15th bits from HT RX MCS set + * and so on. + * + * Related: STA + * + * Supported Feature: 11n + * + * Usage: External + */ +#define CFG_DISABLE_HIGH_HT_RX_MCS_2x2 CFG_INI_UINT( \ + "disable_high_ht_mcs_2x2", \ + 0, \ + 8, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Disable high MCS index for 2x2") + +#define CFG_CFP_PERIOD CFG_UINT( \ + "cfpPeriod", \ + 0, \ + 255, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "CFP Period") + +#define CFG_CFP_MAX_DURATION CFG_UINT( \ + "cfpMaxDuration", \ + 0, \ + 65535, \ + 30000, \ + CFG_VALUE_OR_DEFAULT, \ + "CFP Max Duration") +/* + * + * supported_rates_11b - supported rates for 11b + * @Min: 0 minimum length of supported rates + * @Max: default data length of supported rates in string format + * @Default: 2, 4, 11, 22 + */ +#define CFG_SUPPORTED_RATES_11B_DATA "2, 4, 11, 22" +#define CFG_SUPPORTED_RATES_11B CFG_STRING( \ + "supported_rates_11b", \ + 0, \ + sizeof(CFG_SUPPORTED_RATES_11B_DATA) - 1, \ + CFG_SUPPORTED_RATES_11B_DATA, \ + "Supported rates for 11B") + +/* + * + * supported_rates_11a - supported rates for 11a + * @Min: 0 minimum length of supported rates + * @Max: default data length of supported rates in string format + * @Default: 12, 18, 24, 36, 48, 72, 96, 108 + */ +#define CFG_SUPPORTED_RATES_11A_DATA "12, 18, 24, 36, 48, 72, 96, 108" +#define CFG_SUPPORTED_RATES_11A CFG_STRING( \ + "supported_rates_11a", \ + 0, \ + sizeof(CFG_SUPPORTED_RATES_11A_DATA) - 1, \ + CFG_SUPPORTED_RATES_11A_DATA, \ + "Supported rates for 11A") + +/* + * + * supported_mcs_set - supported MCS set data + * @Min: 0 minimum length of supported MCS set + * @Max: default data length of supported mcs set in string format + * @Default: 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + * 0x0, 0x0, 0x0 + */ +#define CFG_SUPPORTED_MCS_SET_DATA "0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0" +#define CFG_SUPPORTED_MCS_SET CFG_STRING( \ + "supported_mcs_set", \ + 0, \ + sizeof(CFG_SUPPORTED_MCS_SET_DATA) - 1, \ + CFG_SUPPORTED_MCS_SET_DATA, \ + "supported MCS set") + +/* + * + * basic_mcs_set - basic MCS set data + * @Min: 0 minimum length of basic MCS set + * @Max: default data length of basic mcs set in string format + * @Default: 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + * 0x0, 0x0, 0x0 + */ +#define CFG_BASIC_MCS_SET_DATA "0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0" +#define CFG_BASIC_MCS_SET CFG_STRING( \ + "basic_mcs_set", \ + 0, \ + sizeof(CFG_BASIC_MCS_SET_DATA) - 1, \ + CFG_BASIC_MCS_SET_DATA, \ + "basic MCS set") + +/* + * + * current_mcs_set - current MCS set data + * @Min: 0 minimum length of current MCS set + * @Max: default data length of current mcs set in string format + * @Default: 0x00, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + * 0x0, 0x0, 0x0 + */ +#define CFG_CURRENT_MCS_SET_DATA "0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0" +#define CFG_CURRENT_MCS_SET CFG_STRING( \ + "current_mcs_set", \ + 0, \ + sizeof(CFG_CURRENT_MCS_SET_DATA) - 1, \ + CFG_CURRENT_MCS_SET_DATA, \ + "current MCS set") + +/* + * + * ratemask_type - PHY type for the ratemask. + * @Min: 0 No rate mask set defined - disabled the configuration + * @Max: 4 + * @Default: 0 + * + * This ini is used to set the PHY type for ratemask in rate selection. + * + * 0 = Disables the configuration + * 1 = The rate mask specified is for CCK/OFDM configuration + * 2 = The rate mask specified is for HT configuration + * 3 = The rate mask specified is for VHT configuration + * 4 = The rate mask specified is for HE/11ax configuration + * + * Related: CFG_RATEMASK_SET + * + * Usage: External + */ +#define CFG_RATEMASK_TYPE CFG_INI_UINT( \ + "ratemask_type", \ + 0, \ + 4, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Ratemask type") + +/* + * + * ratemask_set - ratemasks for a PHY type used in rate selection + * @Min: default data length of ratemask in string format + * @Max: default data length of ratemask in string format + * @Default: 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0xFFFFFFFF + * + * This is used to set the rate mask value to be used in rate selection. + * Each of the four words must be configured. + * A bit value of 1 represents rate is enabled + * A bit value of 0 represents rate is disabled + * + * [b31-b0],[b63-b32],[b95-b64],[b127-b96] + * For HE targets, 12 bits correpond to one NSS setting. Ex: + * b0-13 => NSS1, MCS 0-13 + * b14-27 => NSS2, MCS 0-13 and so on for other NSS. + * Note that the bit representation is continuous. + * + * For VHT targets, 12 bits correspond to one NSS setting. + * b0-11 => NSS1, MCS 0-11 + * b12-23 => NSS2, MCS 0-11 and so on for other NSS. + * + * For HT targets, 8 bits correspond to one NSS setting. + * b0-7 => NSS1, MCS 0-7 + * b8-15 => NSS2, MCS 0-7 and so on for other NSS. + * + * For OFDM/CCK targets, 8 bits correspond to one NSS setting. + * Bit position |-b3-|-b2-|-b1-|-b0-| + * Rates in Mbps |-1 -|-2 -|-5.5|-11-| CCK Rates + * + * Bit position |-b11-|-b10-|-b09-|-b08-|-b07-|-b06-|-b05-|-b04-| + * Rates in Mbps |- 9 -|- 18-|-36 -|-54 -|- 6 -|-12 -| -24-|-48- | OFDM Rates + * + * Related: CFG_RATEMASK_TYPE + * + * Usage: External + */ +#define CFG_RATEMASK_DATA "0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF" +#define CFG_RATEMASK_SET CFG_INI_STRING( \ + "ratemask_set", \ + 0, \ + sizeof(CFG_RATEMASK_DATA) - 1, \ + CFG_RATEMASK_DATA, \ + "Ratemasks for rate selection") + +#define CFG_RATES_ALL \ + CFG(CFG_MAX_HT_MCS_FOR_TX_DATA) \ + CFG(CFG_DISABLE_ABG_RATE_FOR_TX_DATA) \ + CFG(CFG_SAP_MAX_MCS_FOR_TX_DATA) \ + CFG(CFG_DISABLE_HIGH_HT_RX_MCS_2x2) \ + CFG(CFG_CFP_PERIOD) \ + CFG(CFG_CFP_MAX_DURATION) \ + CFG(CFG_SUPPORTED_RATES_11B) \ + CFG(CFG_SUPPORTED_RATES_11A) \ + CFG(CFG_SUPPORTED_MCS_SET) \ + CFG(CFG_BASIC_MCS_SET) \ + CFG(CFG_CURRENT_MCS_SET) \ + CFG(CFG_RATEMASK_TYPE) \ + CFG(CFG_RATEMASK_SET) + +#endif /* __CFG_MLME_RATES_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h new file mode 100644 index 0000000000..dc13a8a5b6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_reg.h @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains configuration definitions for MLME REG. + */ + +#ifndef CFG_MLME_REG_H__ +#define CFG_MLME_REG_H__ + +/* + * + * gSelfGenFrmPwr - self-generated frame power in tx chain mask + * for CCK rates + * @Min: 0 + * @Max: 0xffff + * @Default: 0 + * + * gSelfGenFrmPwr is to set self-generated frame power in tx chain mask + * for CCK rates + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_SELF_GEN_FRM_PWR CFG_INI_UINT( \ + "gSelfGenFrmPwr", \ + 0, \ + 0xffff, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "set the self gen power value") + +/* + * + * enable_11d_in_world_mode - enable 11d in world mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini enables 11d in world mode, irrespective of value of + * g11dSupportEnabled + * + * Usage: External + * + * + */ +#define CFG_ENABLE_11D_IN_WORLD_MODE CFG_INI_BOOL( \ + "enable_11d_in_world_mode", \ + 0, \ + "enable 11d in world mode") + +/* + * + * etsi_srd_chan_in_master_mode - Enable/disable ETSI SRD channels in + * master mode PCL and ACS functionality + * @Min: 0 + * @Max: 0xFF + * @Default: 6 + * + * etsi_srd_chan_in_master_mode is to enable/disable ETSI SRD channels in + * master mode PCL and ACS functionality + * Bit map for enabling the SRD mode in various modes are as follows:- + * BIT 0:- Enable/Disable SRD channels for SAP. + * BIT 1:- Enable/Disable SRD channels for P2P-GO. + * BIT 2:- Enable/Disable SRD channels for NAN. + * Rest of the bits are currently reserved for future SRD channel support for + * other vdevs. + * + * Related: None + * + * Supported Feature: SAP/P2P-GO + * + * Usage: Internal/External + * + * + */ +#define CFG_ETSI_SRD_CHAN_IN_MASTER_MODE CFG_INI_UINT( \ + "etsi13_srd_chan_in_master_mode", \ + 0, \ + 0xff, \ + 6, \ + CFG_VALUE_OR_DEFAULT, \ + "enable/disable ETSI SRD channels in master mode") + +/* + * + * enable_nan_indoor_channel - Enable Indoor channels for NAN + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to support to indoor channels for NAN interface + * Customer can config this item to enable/disable NAN in indoor channel + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_INDOOR_CHANNEL_SUPPORT_FOR_NAN CFG_INI_BOOL( \ + "enable_nan_indoor_channel", \ + 0, \ + "enable/disable indoor channels for NAN") + +/* + * + * fcc_5dot9_ghz_chan_in_master_mode - Enable/disable 5.9 GHz channels in + * master mode for US + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * fcc_5dot9_ghz_chan_in_master_mode is to enable/disable 5.9 GHz channels + * in master mode for FCC reg domain + * + * Related: None + * + * Supported Feature: SAP/P2P-GO + * + * Usage: Internal/External + * + * + */ +#define CFG_FCC_5DOT9_GHZ_CHAN_IN_MASTER_MODE CFG_INI_BOOL( \ + "fcc_5dot9_ghz_chan_in_master_mode", \ + 0, \ + "enable/disable FCC 5.9 GHz channels in master mode") + +#ifdef SAP_AVOID_ACS_FREQ_LIST +#define SAP_AVOID_ACS_FREQ_LIST_DEFAULT "" + +/* + * + * sap_avoid_acs_freq_list - Avoid configured frequencies from acs + * @Default: No frequencies are configured, it means consider all + * the frequencies for acs + * + * This ini is to configure the frequencies which needs to be + * avoided during acs and sap will not come up on these channels + * Ex: sap_avoid_acs_freq_list=2412,2417,2422,2427,2467,2472 + * + * Related: Feature flag SAP_AVOID_ACS_FREQ_LIST + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ + +#define CFG_SAP_AVOID_ACS_FREQ_LIST CFG_INI_STRING( \ + "sap_avoid_acs_freq_list", \ + 0, \ + CFG_VALID_CHANNEL_LIST_STRING_LEN, \ + SAP_AVOID_ACS_FREQ_LIST_DEFAULT, \ + "Avoid configured frequencies during acs") +#define CFG_SAP_AVOID_ACS_FREQ_LIST_ALL CFG(CFG_SAP_AVOID_ACS_FREQ_LIST) +#else +#define CFG_SAP_AVOID_ACS_FREQ_LIST_ALL +#endif + +/* + * + * restart_beaconing_on_chan_avoid_event - control the beaconing entity to move + * away from active LTE channels + * @Min: 0 + * @Max: 2 + * @Default: 1 + * + * This ini is used to control the beaconing entity (SAP/GO) to move away from + * active LTE channels when channel avoidance event is received + * restart_beaconing_on_chan_avoid_event=0: Don't allow beaconing entity move + * from active LTE channels + * restart_beaconing_on_chan_avoid_event=1: Allow beaconing entity move from + * active LTE channels + * restart_beaconing_on_chan_avoid_event=2: Allow beaconing entity move from + * 2.4G active LTE channels only + * + * Related: None + * + * Supported Feature: channel avoidance + * + * Usage: Internal/External + * + * + */ +#define CFG_RESTART_BEACONING_ON_CH_AVOID CFG_INI_UINT( \ + "restart_beaconing_on_chan_avoid_event", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "control the beaconing entity to move away from active LTE channels") + +/* + * + * gindoor_channel_support - support to start sap in indoor channel + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is to support to start sap in indoor channel. + * Customer can config this item to enable/disable sap in indoor channel + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_INDOOR_CHANNEL_SUPPORT CFG_INI_BOOL( \ + "gindoor_channel_support", \ + 0, \ + "enable/disable sap in indoor channel") + +/* + * + * scan_11d_interval - 11d scan interval in ms + * @Min: 1 sec + * @Max: 10 hr + * @Default: 1 hr + * + * This ini sets the 11d scan interval in FW + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ + +#define CFG_SCAN_11D_INTERVAL CFG_INI_UINT( \ + "scan_11d_interval", \ + 1000, \ + 36000000, \ + 3600000, \ + CFG_VALUE_OR_DEFAULT, \ + "set the 11d scan interval in FW") + +/* + * + * ignore_fw_reg_offload_ind - If set, Ignore the FW offload indication + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to ignore regdb offload indication from FW and + * regulatory will be treated as non offload. + * + * Related: None + * + * Supported Feature: STA/AP + * + * Usage: External + * + * + */ +#define CFG_IGNORE_FW_REG_OFFLOAD_IND CFG_INI_BOOL( \ + "ignore_fw_reg_offload_ind", \ + 0, \ + "Ignore Regulatory offloads Indication from FW") + +/* + * + * enable_pending_list_req - Sets Pending channel List Req. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This option enables/disables SCAN_CHAN_LIST_CMDID channel list command to FW + * till the current scan is complete. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_PENDING_CHAN_LIST_REQ CFG_INI_BOOL( \ + "enable_pending_list_req", \ + 1, \ + "Enable Pending list req") + +#if defined(CONFIG_BAND_6GHZ) && defined(CONFIG_AFC_SUPPORT) +/* + * afc_reg_no_action - Whether action to AFC response + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to control whether action to AFC response. + * + * Related: None + * + * Supported Feature: SAP + * + */ +#define CFG_AFC_REG_NO_ACTION CFG_BOOL( \ + "afc_reg_no_action", false, \ + "driver/user space action needed for afc resp") + +/* + * enable_6ghz_sp_pwrmode_supp - Enable 6Ghz SP power mode + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to control support of 6Ghz SP power mode. + * + * Related: None + * + * Supported Feature: SAP + * + */ +#define CFG_6GHZ_SP_POWER_MODE_SUPP CFG_INI_BOOL( \ + "enable_6ghz_sp_pwrmode_supp", false, \ + "Enable support for SP Power mode in 6GHz") + +/* + * afc_disable_timer_check - Disable AFC timer check + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to control whether disable AFC timer check. + * + * Related: None + * + * Supported Feature: SAP + * + */ +#define CFG_AFC_TIMER_CHECK_DIS CFG_BOOL( \ + "afc_disable_timer_check", false, \ + "Disable the AFC request timer in FW") + +/* + * afc_disable_request_id_check - Disable AFC request id check + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to control whether disable AFC request id check. + * + * Related: None + * + * Supported Feature: SAP + * + */ +#define CFG_AFC_REQ_ID_CHECK_DIS CFG_BOOL( \ + "afc_disable_request_id_check", false, \ + "Disable the AFC request ID check in FW") + +#define CFG_AFC_REG_ALL \ + CFG(CFG_AFC_REG_NO_ACTION) \ + CFG(CFG_6GHZ_SP_POWER_MODE_SUPP) \ + CFG(CFG_AFC_TIMER_CHECK_DIS) \ + CFG(CFG_AFC_REQ_ID_CHECK_DIS) +#else +#define CFG_AFC_REG_ALL +#endif + +/* + * + * retain_nol_across_regdmn - Retain NOL across reg domain + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set if NOL needs to be retained + * on the reg domain change. + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_RETAIN_NOL_ACROSS_REG_DOMAIN CFG_INI_BOOL( \ + "retain_nol_across_regdmn", \ + 1, \ + "Retain NOL even if the regdomain changes") + +#ifdef FEATURE_WLAN_CH_AVOID_EXT + +/** + * enum ignore_fw_coex_info_modes - Represents modes + * @IGNORE_FW_COEX_INFO_ON_SAP_MODE: Set this bit to ignore fw coex info on + * SAP mode + * @IGNORE_FW_COEX_INFO_ON_P2P_GO_MODE: Set this bit to ignore fw coex info + * on P2P-GO mode + */ +enum ignore_fw_coex_info_modes { + IGNORE_FW_COEX_INFO_ON_SAP_MODE = 1 << 0, + IGNORE_FW_COEX_INFO_ON_P2P_GO_MODE = 1 << 1 +}; + +/* + * + * coex_unsafe_chan_nb_user_prefer- Used to handle coex unsafe freq + * event + * + * @Min: 0 + * @Max: 0xFF + * @Default: 0 + * + * Bit map of the modes to consider/ignore firmware provided coex/unsafe + * channels. + * Firmware provided coex/unsafe channel info is ignored if the corresponding + * bit is set to 1. + * Firmware provided coex/unsafe channel info is honored if the corresponding + * bit is set to 0. + * + * BIT 0: Don't honor firmware coex info for SAP mode + * BIT 1: Don't honor firmware coex info for P2P-GO mode + * Rest of the bits are currently reserved + * + * This ini is used to handle coex unsafe freq event + * Usage: External + * + * + */ +#define CFG_COEX_UNSAFE_CHAN_NB_USER_PREFER CFG_INI_UINT( \ + "coex_unsafe_chan_nb_user_prefer", \ + 0, \ + 0xff, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Honor coex unsafe freq event from firmware") +/* + * + * coex_unsafe_chan_reg_disable - Used to disable reg channels + * for coex unsafe freq event + * + * @Min: 0 (Don't disable reg channels for coex unsafe chan event) + * @Max: 1 (Disable reg channels for coex unsafe chan event) + * Default: 0 + * + * This ini is used to disable reg channels for coex unsafe chan + * event + * Usage: External + * + * + */ +#define CFG_COEX_UNSAFE_CHAN_REG_DISABLE CFG_INI_BOOL( \ + "coex_unsafe_chan_reg_disable", \ + 0, \ + "Disable reg channels for coex unsafe chan event") + +#define CFG_COEX_UNSAFE_CHAN_ALL \ + CFG(CFG_COEX_UNSAFE_CHAN_NB_USER_PREFER) \ + CFG(CFG_COEX_UNSAFE_CHAN_REG_DISABLE) +#else +#define CFG_COEX_UNSAFE_CHAN_ALL +#endif + +#define CFG_REG_ALL \ + CFG_COEX_UNSAFE_CHAN_ALL \ + CFG(CFG_SELF_GEN_FRM_PWR) \ + CFG(CFG_ENABLE_PENDING_CHAN_LIST_REQ) \ + CFG(CFG_ENABLE_11D_IN_WORLD_MODE) \ + CFG(CFG_ETSI_SRD_CHAN_IN_MASTER_MODE) \ + CFG(CFG_INDOOR_CHANNEL_SUPPORT_FOR_NAN) \ + CFG(CFG_FCC_5DOT9_GHZ_CHAN_IN_MASTER_MODE) \ + CFG(CFG_RESTART_BEACONING_ON_CH_AVOID) \ + CFG(CFG_INDOOR_CHANNEL_SUPPORT) \ + CFG(CFG_SCAN_11D_INTERVAL) \ + CFG(CFG_IGNORE_FW_REG_OFFLOAD_IND) \ + CFG_AFC_REG_ALL \ + CFG(CFG_RETAIN_NOL_ACROSS_REG_DOMAIN) \ + CFG_SAP_AVOID_ACS_FREQ_LIST_ALL + +#endif /* CFG_MLME_REG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_roam_scoring.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_roam_scoring.h new file mode 100644 index 0000000000..4f98ddf4e6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_roam_scoring.h @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains roam specific SCORING related CFG/INI Items. + */ + +#ifndef __CFG_MLME_ROAM_SCORING_H +#define __CFG_MLME_ROAM_SCORING_H + +#ifdef CONNECTION_ROAMING_CFG +#define RoamCommon_Delta_min 0 +#define RoamCommon_Delta_max 30 +#define RoamCommon_Delta_default 20 +#define RoamIdle_Delta_min 0 +#define RoamIdle_Delta_max 20 +#define RoamIdle_Delta_default 0 +#define RoamBeaconLoss_TargetMinRSSI_min -127 +#define RoamBeaconLoss_TargetMinRSSI_max -70 +#define RoamBeaconLoss_TargetMinRSSI_default -75 +#define RoamBTM_Delta_min 0 +#define RoamBTM_Delta_max 20 +#define RoamBTM_Delta_default 0 +#define RoamEmergency_TargetMinRSSI_min -127 +#define RoamEmergency_TargetMinRSSI_max 0 +#define RoamEmergency_TargetMinRSSI_default -70 +#else +#define RoamCommon_Delta_min 0 +#define RoamCommon_Delta_max 100 +#define RoamCommon_Delta_default 0 +#define RoamIdle_Delta_min 0 +#define RoamIdle_Delta_max 100 +#define RoamIdle_Delta_default 0 +#define RoamBeaconLoss_TargetMinRSSI_min -120 +#define RoamBeaconLoss_TargetMinRSSI_max 0 +#define RoamBeaconLoss_TargetMinRSSI_default -75 +#define RoamBTM_Delta_min 0 +#define RoamBTM_Delta_max 100 +#define RoamBTM_Delta_default 0 +#define RoamEmergency_TargetMinRSSI_min -120 +#define RoamEmergency_TargetMinRSSI_max 0 +#define RoamEmergency_TargetMinRSSI_default -75 +#endif +/* + * + * roam_score_delta_bitmap - bitmap to enable roam triggers on + * which roam score delta is to be applied during roam candidate + * selection + * @Min: 0 + * @Max: 0xffffffff + * @Default: 0xffffffff + * + * Bitmap value of the following roam triggers: + * ROAM_TRIGGER_REASON_NONE - B0, + * ROAM_TRIGGER_REASON_PER - B1, + * ROAM_TRIGGER_REASON_BMISS - B2, + * ROAM_TRIGGER_REASON_LOW_RSSI - B3, + * ROAM_TRIGGER_REASON_HIGH_RSSI - B4, + * ROAM_TRIGGER_REASON_PERIODIC - B5, + * ROAM_TRIGGER_REASON_MAWC - B6, + * ROAM_TRIGGER_REASON_DENSE - B7, + * ROAM_TRIGGER_REASON_BACKGROUND - B8, + * ROAM_TRIGGER_REASON_FORCED - B9, + * ROAM_TRIGGER_REASON_BTM - B10, + * ROAM_TRIGGER_REASON_UNIT_TEST - B11, + * ROAM_TRIGGER_REASON_BSS_LOAD - B12 + * ROAM_TRIGGER_REASON_DISASSOC - B13 + * ROAM_TRIGGER_REASON_IDLE_ROAM - B14 + * + * When the bit corresponding to a particular roam trigger reason + * is set, the value of "roam_score_delta" is expected over the + * roam score of the current connected AP, for that triggered roam + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCORE_DELTA_TRIGGER_BITMAP CFG_INI_UINT( \ + "roam_score_delta_bitmap", \ + 0, \ + 0xFFFFFFFF, \ + 0xFFFFFFFF, \ + CFG_VALUE_OR_DEFAULT, \ + "Bitmap for various roam triggers") + +/* + * + * roam_score_delta/RoamCommon_Delta - Percentage increment in roam score value + * that is expected from a roaming candidate AP. + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * This ini is used to provide the percentage increment value over roam + * score for the candidate APs so that they can be preferred over current + * AP for roaming. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_ROAM_SCORE_DELTA CFG_INI_UINT( \ + "roam_score_delta RoamCommon_Delta", \ + RoamCommon_Delta_min,\ + RoamCommon_Delta_max, \ + RoamCommon_Delta_default, \ + CFG_VALUE_OR_DEFAULT, \ + "candidate AP's percentage roam score delta") + +/* + * + * min_roam_score_delta - Difference of roam score values between connected + * AP and roam candidate AP. + * @Min: 0 + * @Max: 10000 + * @Default: 0 + * + * This ini is used during CU and low rssi based roam triggers, consider + * AP as roam candidate only if its roam score is better than connected + * AP score by at least min_roam_score_delta. + * If user configured "roam_score_delta" and "min_roam_score_delta" both, + * then firmware selects roam candidate AP by considering values of both + * INIs. + * Example: If DUT is connected with AP1 and roam candidate AP2 has roam + * score greater than roam_score_delta and min_roam_score_delta then only + * firmware will trigger roaming to AP2. + * + * Related: roam_score_delta + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define CFG_CAND_MIN_ROAM_SCORE_DELTA CFG_INI_UINT( \ + "min_roam_score_delta", \ + 0, \ + 10000, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Diff between connected AP's and candidate AP's roam score") + +/* + * + * RoamCommon_MinRoamDelta - Difference of roam score values between connected + * AP and roam candidate AP. + * @Min: 0 + * @Max: 100 + * @Default: 15 + * + * This ini is used during CU and low rssi based roam triggers, consider + * AP as roam candidate only if its roam score is better than connected + * AP score by at least RoamCommon_MinRoamDelta. + * If user configured "RoamCommon_Delta" and "RoamCommon_MinRoamDelta" both, + * then firmware selects roam candidate AP by considering values of both + * INIs. + * Example: If DUT is connected with AP1 and roam candidate AP2 has roam + * score greater than RoamCommon_Delta and RoamCommon_MinRoamDelta then only + * firmware will trigger roaming to AP2. + * This value needs to be given in percentage + * + * Related: RoamCommon_Delta + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define CFG_ROAM_COMMON_MIN_ROAM_DELTA CFG_INI_UINT( \ + "RoamCommon_MinRoamDelta", \ + 0, \ + 100, \ + 15, \ + CFG_VALUE_OR_DEFAULT, \ + "Diff bet connected AP's and candidate AP's roam score") + +/* + * + * enable_scoring_for_roam - enable/disable scoring logic in FW for candidate + * selection during roaming + * + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable scoring logic in FW for candidate + * selection during roaming. + * + * Supported Feature: STA Candidate selection by FW during roaming based on + * scoring logic. + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SCORING_FOR_ROAM CFG_INI_BOOL( \ + "enable_scoring_for_roam", \ + 1, \ + "Enable Scoring for Roam") + +/* + * + * apsd_enabled - Enable automatic power save delivery + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Supported Feature: Power save + * + * Usage: Internal + * + * + */ +#define CFG_APSD_ENABLED CFG_BOOL( \ + "apsd_enabled", \ + 0, \ + "Enable APSD") + +/* + * + * candidate_min_rssi_for_disconnect/RoamEmergency_TargetMinRSSI - + * Candidate AP minimum RSSI in idle roam trigger(in dBm). + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * Minimum RSSI value of the candidate AP to consider it as candidate for + * roaming when roam trigger is Deauthentication/Disconnection from current + * AP. This value will be sent to firmware over the WMI_ROAM_AP_PROFILE + * wmi command in the roam_min_rssi_param_list tlv. + * + * Related: enable_idle_roam. + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_DISCONNECT_ROAM_TRIGGER_MIN_RSSI CFG_INI_INT( \ + "candidate_min_rssi_for_disconnect RoamEmergency_TargetMinRSSI", \ + RoamEmergency_TargetMinRSSI_min, \ + RoamEmergency_TargetMinRSSI_max, \ + RoamEmergency_TargetMinRSSI_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum RSSI of candidate AP for Disconnect roam trigger") + +/* + * + * candidate_min_rssi_for_beacon_miss/RoamBeaconLoss_TargetMinRSSI - + * Candidate AP minimum RSSI for beacon miss roam trigger (in dBm) + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * Minimum RSSI value of the candidate AP to consider it as candidate for + * roaming when roam trigger is disconnection from current AP due to beacon + * miss. This value will be sent to firmware over the WMI_ROAM_AP_PROFILE + * wmi command in the roam_min_rssi_param_list tlv. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_BMISS_ROAM_MIN_RSSI CFG_INI_INT( \ + "candidate_min_rssi_for_beacon_miss RoamBeaconLoss_TargetMinRSSI", \ + RoamBeaconLoss_TargetMinRSSI_min, \ + RoamBeaconLoss_TargetMinRSSI_max, \ + RoamBeaconLoss_TargetMinRSSI_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum RSSI of candidate AP for Bmiss roam trigger") + +/* + * + * min_rssi_for_2g_to_5g_roam - Candidate AP minimum RSSI for + * 2G to 5G roam trigger (in dBm) + * @Min: -120 + * @Max: 0 + * @Default: -70 + * + * Minimum RSSI value of the candidate AP to consider it as candidate + * for 2G to 5G roam. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: Internal/External + * + * + */ +#define CFG_2G_TO_5G_ROAM_MIN_RSSI CFG_INI_INT( \ + "min_rssi_for_2g_to_5g_roam", \ + -120, \ + 0, \ + -70, \ + CFG_VALUE_OR_DEFAULT, \ + "Minimum RSSI of candidate AP for 2G to 5G roam trigger") + +/* + * + * idle_roam_score_delta/RoamIdle_Delta - Roam score delta value in + * percentage for idle roam. + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * This ini is used to configure the minimum change in roam score + * value of the AP to consider it as candidate for + * roaming when roam trigger is due to idle state of sta. + * This value will be sent to firmware over the WMI_ROAM_AP_PROFILE wmi + * command in the roam_score_delta_param_list tlv. + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_IDLE_ROAM_SCORE_DELTA CFG_INI_UINT( \ + "idle_roam_score_delta RoamIdle_Delta", \ + RoamIdle_Delta_min, \ + RoamIdle_Delta_max, \ + RoamIdle_Delta_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Roam score delta for Idle roam trigger") + +/* + * + * btm_roam_score_delta/RoamBTM_Delta - Roam score delta value in percentage for + * BTM triggered roaming. + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * This ini is used to configure the minimum change in roam score + * value of the AP to consider it as candidate when the sta is disconnected + * from the current AP due to BTM kickout. + * This value will be sent to firmware over the WMI_ROAM_AP_PROFILE wmi + * command in the roam_score_delta_param_list tlv. + * + * Related: None + * + * Supported Feature: Roaming + * + * Usage: External + * + * + */ +#define CFG_BTM_ROAM_SCORE_DELTA CFG_INI_UINT( \ + "btm_roam_score_delta RoamBTM_Delta", \ + RoamBTM_Delta_min, \ + RoamBTM_Delta_max, \ + RoamBTM_Delta_default, \ + CFG_VALUE_OR_DEFAULT, \ + "Roam score delta for BTM roam trigger") + +#define CFG_ROAM_SCORING_ALL \ + CFG(CFG_ROAM_SCORE_DELTA_TRIGGER_BITMAP) \ + CFG(CFG_ROAM_SCORE_DELTA) \ + CFG(CFG_CAND_MIN_ROAM_SCORE_DELTA) \ + CFG(CFG_ROAM_COMMON_MIN_ROAM_DELTA) \ + CFG(CFG_ENABLE_SCORING_FOR_ROAM) \ + CFG(CFG_APSD_ENABLED) \ + CFG(CFG_DISCONNECT_ROAM_TRIGGER_MIN_RSSI) \ + CFG(CFG_BMISS_ROAM_MIN_RSSI) \ + CFG(CFG_2G_TO_5G_ROAM_MIN_RSSI) \ + CFG(CFG_IDLE_ROAM_SCORE_DELTA) \ + CFG(CFG_BTM_ROAM_SCORE_DELTA) + +#endif /* __CFG_MLME_ROAM_SCORING_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_sap.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_sap.h new file mode 100644 index 0000000000..1576a0679e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_sap.h @@ -0,0 +1,834 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_SAP_H +#define __CFG_MLME_SAP_H + +#define CFG_BEACON_INTERVAL CFG_INI_UINT( \ + "gBeaconInterval", \ + 0, \ + 65535, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "CFG_BEACON_INTERVAL") + +#define CFG_DTIM_PERIOD CFG_UINT( \ + "cfg_dtim_period", \ + 0, \ + 65535, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "CFG_DTIM_PERIOD") + +#define CFG_LISTEN_INTERVAL CFG_UINT( \ + "cfg_listen_interval", \ + 0, \ + 65535, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "CFG_LISTEN_INTERVAL") + +#define CFG_11G_ONLY_POLICY CFG_UINT( \ + "cfg_11g_only_policy", \ + 0, \ + 1, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "CFG_11G_ONLY_POLICY") + +#define CFG_ASSOC_STA_LIMIT CFG_UINT( \ + "cfg_assoc_sta_limit", \ + 1, \ + 64, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "CFG_ASSOC_STA_LIMIT") + +/* + * + * cfg_enable_lte_coex - enable LTE COEX + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable LTE COEX + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_ENABLE_LTE_COEX CFG_INI_BOOL( \ + "gEnableLTECoex", \ + 0, \ + "enabled lte coex") + +/* + * + * cfg_rate_for_tx_mgmt - Set rate for tx mgmt + * @Min: 0 + * @Max: 0xFF + * @Default: 0xFF + * + * This ini is used to set rate for tx mgmt + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_RATE_FOR_TX_MGMT CFG_INI_UINT( \ + "gRateForTxMgmt", \ + 0, \ + 0xFF, \ + 0xFF, \ + CFG_VALUE_OR_DEFAULT, \ + "set rate for mgmt tx") + +/* + * + * cfg_rate_for_tx_mgmt_2g - Set rate for tx mgmt 2g + * @Min: 0 + * @Max: 255 + * @Default: 255 + * + * This ini is used to set rate for tx mgmt 2g + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_RATE_FOR_TX_MGMT_2G CFG_INI_UINT( \ + "gRateForTxMgmt2G", \ + 0, \ + 255, \ + 255, \ + CFG_VALUE_OR_DEFAULT, \ + "set rate for mgmt tx 2g") + +/* + * + * cfg_rate_for_tx_mgmt_5g - Set rate for tx mgmt 5g + * @Min: 0 + * @Max: 255 + * @Default: 255 + * + * This ini is used to set rate for tx mgmt 5g + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_RATE_FOR_TX_MGMT_5G CFG_INI_UINT( \ + "gRateForTxMgmt5G", \ + 0, \ + 255, \ + 255, \ + CFG_VALUE_OR_DEFAULT, \ + "set rate for mgmt tx 5g") + +/* + * + * gTelescopicBeaconWakeupEn - Set teles copic beacon wakeup + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set default teles copic beacon wakeup + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_TELE_BCN_WAKEUP_EN CFG_INI_BOOL( \ + "gTelescopicBeaconWakeupEn", \ + 0, \ + "set tescopic beacon wakeup") + +/* + * + * telescopicBeaconMaxListenInterval - Set teles scopic beacon max listen value + * @Min: 0 + * @Max: 7 + * @Default: 5 + * + * This ini is used to set teles scopic beacon max listen interval value + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_TELE_BCN_MAX_LI CFG_INI_UINT( \ + "telescopicBeaconMaxListenInterval", \ + 0, \ + 7, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "set telescopic beacon max listen") + +/* + * + * gSapGetPeerInfo - Enable/Disable remote peer info query support + * @Min: 0 - Disable remote peer info query support + * @Max: 1 - Enable remote peer info query support + * @Default: 1 + * + * This ini is used to enable/disable remote peer info query support + * + * Usage: External + * + * + */ + #define CFG_SAP_GET_PEER_INFO CFG_INI_BOOL( \ + "gSapGetPeerInfo", \ + 1, \ + "sap get peer info") + +/* + * + * gSapAllowAllChannel - Sap allow all channels + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to allow all channels for SAP + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + #define CFG_SAP_ALLOW_ALL_CHANNEL_PARAM CFG_INI_BOOL( \ + "gSapAllowAllChannel", \ + 0, \ + "sap allow all channel params") + +/* + * + * gSoftApMaxPeers - Set Max peers connected for SAP + * @Min: 1 + * @Max: 64 + * @Default: 10 + * + * This ini is used to set Max peers connected for SAP + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + #define CFG_SAP_MAX_NO_PEERS CFG_INI_UINT( \ + "gSoftApMaxPeers", \ + 1, \ + 64, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "max no of peers") + +/* + * + * gMaxOffloadPeers - Set max offload peers + * @Min: 2 + * @Max: 5 + * @Default: 2 + * + * This ini is used to set default teles copic beacon wakeup + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_SAP_MAX_OFFLOAD_PEERS CFG_INI_UINT( \ + "gMaxOffloadPeers", \ + 2, \ + 5, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "max offload peers") + +/* + * + * gMaxOffloadReorderBuffs - Set max offload reorder buffs + * @Min: 0 + * @Max: 3 + * @Default: 2 + * + * This ini is used to set max offload reorder buffs + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS CFG_INI_UINT( \ + "gMaxOffloadReorderBuffs", \ + 0, \ + 3, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "sap max offload reorder buffs") + +/* + * + * g_sap_chanswitch_beacon_cnt - Set channel switch beacon count + * @Min: 1 + * @Max: 10 + * @Default: 10 + * + * This ini is used to set channel switch beacon count + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + #define CFG_SAP_CH_SWITCH_BEACON_CNT CFG_INI_UINT( \ + "g_sap_chanswitch_beacon_cnt", \ + 1, \ + 10, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "set channel switch beacon count") + +/* + * + * g_sap_chanswitch_mode - channel switch mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to configure the value of channel switch mode, which is + * contained in the Channel Switch Announcement(CSA) information element sent + * by an SAP. + * + * 0 - CSA receiving STA doesn't need to do anything + * 1 - CSA receiving STA shall not transmit any more frames on the channel + * until the scheduled channel switch occurs + * + * Related: none + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_SAP_CH_SWITCH_MODE CFG_INI_BOOL( \ + "g_sap_chanswitch_mode", \ + 1, \ + "sap channel switch mode") + +/* + * + * gEnableSapInternalRestart - Sap internal restart name + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used for sap internal restart name + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + #define CFG_SAP_INTERNAL_RESTART CFG_INI_BOOL( \ + "gEnableSapInternalRestart", \ + 1, \ + "sap internal restart") + +/* + * + * gChanSwitchHostapdRateEnabled - Enable channale switch hostapd rate + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable channale switch hostapd rate + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + #define CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_NAME CFG_INI_BOOL( \ + "gChanSwitchHostapdRateEnabled", \ + 0, \ + "chan switch hostapd rate enabled") + +/* + * + * gReducedBeaconInterval - beacon interval reduced + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * This ini is used to reduce beacon interval before channel + * switch (when val great than 0, or the feature is disabled). + * It would reduce the downtime on the STA side which is + * waiting for beacons from the AP to resume back transmission. + * Switch back the beacon_interval to its original value after + * channel switch based on the timeout. + * + * Related: none + * + * Usage: External + * + * + */ +#define CFG_REDUCED_BEACON_INTERVAL CFG_INI_UINT( \ + "gReducedBeaconInterval", \ + 0, \ + 100, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "reduced beacon interval") + +/* + * + * gCountryCodePriority - Priority to set country code + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default gCountryCodePriority + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: Internal + * + * + */ +#define CFG_COUNTRY_CODE_PRIORITY CFG_INI_BOOL( \ + "gCountryCodePriority", \ + 1, \ + "Country code priority") + +/* + * + * gSapPreferredChanLocation - Restrict channel switches between ondoor and + * outdoor. + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used for restricting channel switches between Indoor and outdoor + * channels after radar detection. + * 0- No preferred channel location + * 1- Use indoor channels only + * 2- Use outdoor channels only + * Related: NA. + * + * Supported Feature: DFS + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_PREF_CHANNEL_LOCATION CFG_INI_UINT( \ + "gSapPreferredChanLocation", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Sap preferred channel location") +/* + * + * gSapForce11NFor11AC - Restrict SAP to 11n if set 1 even though + * hostapd.conf request for 11ac. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Restrict SAP to 11n if set 1 even though hostapd.conf request for 11ac. + * + * 0- Do not force 11n for 11ac. + * 1- Force 11n for 11ac. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_FORCE_11N_FOR_11AC CFG_INI_BOOL( \ + "gSapForce11NFor11AC", \ + 0, \ + "Sap force 11n for 11ac") + +/* + * + * gGoForce11NFor11AC - Restrict GO to 11n if set 1 even though + * hostapd.conf request for 11ac. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Restrict GO to 11n if set 1 even though hostapd.conf request for 11ac. + * + * 0- Do not force 11n for 11ac. + * 1- Force 11n for 11ac. + * + * Supported Feature: GO + * + * Usage: Internal/External + * + * + */ +#define CFG_GO_FORCE_11N_FOR_11AC CFG_INI_BOOL( \ + "gGoForce11NFor11AC", \ + 0, \ + "GO force 11n for 11ac") + + +/* + * + * gEnableApRandomBssid - Create ramdom BSSID + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to create a random BSSID in SoftAP mode to meet + * the Android requirement. + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_ENABLE_RANDOM_BSSID CFG_INI_BOOL( \ + "gEnableApRandomBssid", \ + 0, \ + "Create ramdom BSSID") + +/* + * + * gSapChannelAvoidance - SAP MCC channel avoidance. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to sets sap mcc channel avoidance. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_MCC_CHANNEL_AVOIDANCE CFG_INI_UINT( \ + "gSapChannelAvoidance", \ + 0, \ + 1, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "SAP MCC channel avoidance") + +/* + * + * gSAP11ACOverride - Override bw to 11ac for SAP in driver even if supplicant + * or hostapd configures HT. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable 11AC override for SAP. + * Android UI does not provide advanced configuration options + * for SoftAP for Android O and below. + * Default override disabled for android. Can be enabled from + * ini for Android O and below. + * + * + * Supported Feature: SAP + * + * + * Usage: Internal/External + * + * + */ +#define CFG_SAP_11AC_OVERRIDE CFG_INI_BOOL( \ + "gSAP11ACOverride", \ + 0, \ + "Override bw to 11ac for SAP") + +/* + * + * gGO11ACOverride - Override bw to 11ac for P2P GO + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable 11AC override for GO. + * P2P GO also follows start_bss and since P2P GO could not be + * configured to setup VHT channel width in wpa_supplicant, driver + * can override 11AC. + * + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ +#define CFG_GO_11AC_OVERRIDE CFG_INI_BOOL( \ + "gGO11ACOverride", \ + 1, \ + "Override bw to 11ac for P2P GO") + +/* + * + * + * enable_bcast_deauth_for_sap - Enable/Disable broadcast deauth support + * in driver for SAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable broadcast deauth support in driver + * for sap mode. + * + * Related: None + * + * Supported Feature: SAP + * Usage: External + * + * + */ +#define CFG_IS_SAP_BCAST_DEAUTH_ENABLED CFG_INI_BOOL( \ + "enable_bcast_deauth_for_sap", \ + 0, \ + "Enable/Disable bcast deauth for SAP") + +#ifdef WLAN_FEATURE_SAE +/* + * + * + * enable_sae_for_sap - Enable/Disable SAE support in driver for SAP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable SAE support in driver for SAP mode + * Driver will process/drop the SAE authentication frames based on this config. + * + * Related: None + * + * Supported Feature: SAE + * Usage: External + * + * + */ +#define CFG_IS_SAP_SAE_ENABLED CFG_INI_BOOL( \ + "enable_sae_for_sap", \ + 1, \ + "Enable/Disable SAE support for SAP") + +#define CFG_SAP_SAE CFG(CFG_IS_SAP_SAE_ENABLED) + +#else +#define CFG_SAP_SAE +#endif /* WLAN_FEATURE_SAE */ + +/* + * + * + * enable_sap_fils_discovery - Enable/Disable fils discovery for 6Ghz SAP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Enable: 6Ghz SAP transmits fils discovery frame at every 20ms + * Disable: 6Ghz SAP transmits probe response frame at every 20ms + * + * Related: None + * + * Supported Feature: SAP + * Usage: External + * + * + */ +#define CFG_6G_SAP_FILS_DISCOVERY_ENABLED CFG_INI_BOOL( \ + "enable_6g_sap_fils_discovery", \ + 1, \ + "Enable/Disable fils discovery for SAP") + +/* + * + * disable_mcs13_support - Disable mcs13 support. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disable mcs13 if SAP works on 80p80MHZ/160MHZ/320MHZ + * and he_mcs_12_13_support enabled. + * + * Related: he_mcs_12_13_support + * + * Supported Feature: Concurrency + * + * Usage: Internal + * + * + */ +#define CFG_DISABLE_MCS13_SUPPORT CFG_INI_BOOL( \ + "disable_mcs13_support", \ + 0, \ + "disable mcs13 support") + +/* + * + * disable_sap_bcn_prot - Disable beacon protection for SAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to disable beacon protection in SAP only + * for non-6 GHz or non-11be cases where BP is not mandatory. + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_DISABLE_SAP_BCN_PROT CFG_INI_BOOL(\ + "disable_sap_bcn_prot", \ + false, \ + "Disable beacon protection for SAP") + +/* + * + * g_sap_ps_with_twt_enable - enable/disable power save between successive TWT + * SPs for SAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable power save between successive + * TWT SPs for SAP + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_SAP_PS_WITH_TWT CFG_INI_BOOL(\ + "g_sap_ps_with_twt_enable", \ + false, \ + "Enable/Disable SAP power save with twt") + +#define CFG_SAP_ALL \ + CFG_SAP_SAE \ + CFG(CFG_AP_ENABLE_RANDOM_BSSID) \ + CFG(CFG_BEACON_INTERVAL) \ + CFG(CFG_DTIM_PERIOD) \ + CFG(CFG_LISTEN_INTERVAL) \ + CFG(CFG_11G_ONLY_POLICY) \ + CFG(CFG_ASSOC_STA_LIMIT) \ + CFG(CFG_ENABLE_LTE_COEX) \ + CFG(CFG_RATE_FOR_TX_MGMT) \ + CFG(CFG_RATE_FOR_TX_MGMT_2G) \ + CFG(CFG_RATE_FOR_TX_MGMT_5G) \ + CFG(CFG_TELE_BCN_WAKEUP_EN) \ + CFG(CFG_TELE_BCN_MAX_LI) \ + CFG(CFG_SAP_MCC_CHANNEL_AVOIDANCE) \ + CFG(CFG_SAP_GET_PEER_INFO) \ + CFG(CFG_SAP_ALLOW_ALL_CHANNEL_PARAM) \ + CFG(CFG_SAP_MAX_NO_PEERS) \ + CFG(CFG_SAP_MAX_OFFLOAD_PEERS) \ + CFG(CFG_SAP_MAX_OFFLOAD_REORDER_BUFFS) \ + CFG(CFG_SAP_CH_SWITCH_BEACON_CNT) \ + CFG(CFG_SAP_CH_SWITCH_MODE) \ + CFG(CFG_SAP_INTERNAL_RESTART) \ + CFG(CFG_CHAN_SWITCH_HOSTAPD_RATE_ENABLED_NAME) \ + CFG(CFG_REDUCED_BEACON_INTERVAL) \ + CFG(CFG_MAX_LI_MODULATED_DTIM) \ + CFG(CFG_COUNTRY_CODE_PRIORITY) \ + CFG(CFG_SAP_PREF_CHANNEL_LOCATION) \ + CFG(CFG_SAP_FORCE_11N_FOR_11AC) \ + CFG(CFG_SAP_11AC_OVERRIDE) \ + CFG(CFG_GO_FORCE_11N_FOR_11AC) \ + CFG(CFG_GO_11AC_OVERRIDE) \ + CFG(CFG_IS_SAP_BCAST_DEAUTH_ENABLED) \ + CFG(CFG_6G_SAP_FILS_DISCOVERY_ENABLED) \ + CFG(CFG_DISABLE_MCS13_SUPPORT) \ + CFG(CFG_DISABLE_SAP_BCN_PROT) \ + CFG(CFG_SAP_PS_WITH_TWT) + +#endif /* __CFG_MLME_SAP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_sta.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_sta.h new file mode 100644 index 0000000000..41296bb292 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_sta.h @@ -0,0 +1,828 @@ +/* + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains configuration definitions for MLME STA. + */ + +#ifndef CFG_MLME_STA_H__ +#define CFG_MLME_STA_H__ + +#include "wlan_mlme_public_struct.h" + +#ifdef CONNECTION_ROAMING_CFG +# define CONKEEPALIVE_INTERVAL_MIN 0 +# define CONKEEPALIVE_INTERVAL_MAX 120 +# define CONKEEPALIVE_INTERVAL_DEFAULT 30 +#else +# define CONKEEPALIVE_INTERVAL_MIN 0 +# define CONKEEPALIVE_INTERVAL_MAX 1000 +# define CONKEEPALIVE_INTERVAL_DEFAULT 30 +#endif +/* + * + * gStaKeepAlivePeriod/ConKeepAlive_Interval - STA keep alive period + * + * + * @Min: 0 + * @Max: 1000 + * @Default: 30 + * + * This ini is used to control how frequently STA should send NULL frames to AP + * (period in seconds) to notify AP of its existence. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +/* + * + * gStaKeepAlivePeriod/ConKeepAlive_Interval - STA keep alive period + * + * + * @Min: 0 + * @Max: 120 + * @Default: 30 + * + * This ini is used to control how frequently STA should send NULL frames to AP + * (period in seconds) to notify AP of its existence. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_INFRA_STA_KEEP_ALIVE_PERIOD CFG_INI_UINT( \ + "gStaKeepAlivePeriod ConKeepAlive_Interval", \ + CONKEEPALIVE_INTERVAL_MIN, \ + CONKEEPALIVE_INTERVAL_MAX, \ + CONKEEPALIVE_INTERVAL_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "send default NULL frame to AP") + + +/* + * bss_max_idle_period - STA bss max period + * + * @Min: 0 + * @Max: 100 + * @Default: 0 + * + * This ini is used to advertise the bss max idle period in assoc req. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + */ +#define CFG_STA_BSS_MAX_IDLE_PERIOD CFG_INI_UINT( \ + "bss_max_idle_period", \ + 0, \ + 100, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "advertise bss max idle period") + +/* + * + * tgt_gtx_usr_cfg - target gtx user config + * @Min: 0 + * @Max: 32 + * @Default: 32 + * + * This ini is used to set target gtx user config. + * + * Related: None + * + * Usage: Internal/External + * + * + */ +#define CFG_TGT_GTX_USR_CFG CFG_INI_UINT( \ + "tgt_gtx_usr_cfg", \ + 0, \ + 32, \ + 32, \ + CFG_VALUE_OR_DEFAULT, \ + "target gtx user config") + +/* + * + * pmkidModes - Enable PMKID modes + * This INI is used to enable PMKID feature options + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * Related: None + * + * Supported Feature: Scan + * + * Usage: External + * + * + */ +#define CFG_PMKID_MODES CFG_INI_UINT( \ + "pmkidModes", \ + 0, \ + 3, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "PMKID feature options") + +/* + * + * gIgnorePeerErpInfo - Ignore peer information + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to ignore default peer info + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_IGNORE_PEER_ERP_INFO CFG_INI_BOOL( \ + "gIgnorePeerErpInfo", \ + 0, \ + "ignore default peer info") + +/* + * + * gStaPrefer80MHzOver160MHz - set sta preference to connect in 80HZ/160HZ + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to set sta preference to connect in 80HZ/160HZ + * + * 0 - Connects in 160MHz 1x1 when AP is 160MHz 2x2 + * 1 - Connects in 80MHz 2x2 when AP is 160MHz 2x2 + * 2 - Always Connects in 80MHz when AP is 160MHz + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_STA_PREFER_80MHZ_OVER_160MHZ CFG_INI_UINT( \ + "gStaPrefer80MHzOver160MHz", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Sta preference to connect in 80HZ/160HZ") + +/* + * + * gEnable5gEBT - Enables/disables 5G early beacon termination. When enabled + * terminate the reception of beacon if the TIM element is + * clear for the power saving + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set default 5G early beacon termination + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_PPS_ENABLE_5G_EBT CFG_INI_BOOL( \ + "gEnable5gEBT", \ + 1, \ + "5G early beacon termination") + +/* + * + * gSendDeauthBeforeCon - Send deauth before connection or not + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set whether send deauth before connection or + * not. If last disconnection was due to HB failure and we reconnect + * to same AP next time, send deauth before starting connection. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_DEAUTH_BEFORE_CONNECTION CFG_INI_BOOL( \ + "gSendDeauthBeforeCon", \ + 0, \ + "send deauth before connection") + +/* + * + * deauth_retry_cnt- No. of deauth retries if the Tx is failed + * @Min: 0 + * @Max: 4 + * @Default: 2 + * + * This ini is used to set retry deauth if Tx is not success. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_DEAUTH_RETRY_CNT CFG_INI_UINT( \ + "deauth_retry_cnt", \ + 0, \ + 4, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "Set Deauth retry count") + +/* + * + * gDot11PMode - 802.11p mode + * @Min: CFG_11P_DISABLED + * @Max: CFG_11P_CONCURRENT + * @Default: CFG_11P_DISABLED + * + * This ini used to set 802.11p mode. + * + * + * Usage: Internal/External + * + * + */ +#define CFG_DOT11P_MODE CFG_INI_UINT( \ + "gDot11PMode", \ + CFG_11P_DISABLED, \ + CFG_11P_CONCURRENT, \ + CFG_11P_DISABLED, \ + CFG_VALUE_OR_DEFAULT, \ + "802.11p mode") + +/* + * + * gEnable_go_cts2self_for_sta - Indicate firmware to stop NOA and + * start using cts2self + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * When gEnable_go_cts2self_for_sta is enabled then if a legacy + * client connects to P2P GO, Host will send a WMI VDEV command + * to FW to stop using NOA for P2P GO + * and start using CTS2SELF. + * + * + * Supported Feature: P2P + * + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_GO_CTS2SELF_FOR_STA CFG_INI_BOOL( \ + "gEnable_go_cts2self_for_sta", \ + 0, \ + "firmware to stop NOA and start using cts2self") + +/* + * + * g_qcn_ie_support - QCN IE support + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 1 (enabled) + * + * This config item is used to support QCN IE in probe/assoc/reassoc request + * for STA mode. QCN IE support is not added for SAP mode. + * + * Related: N/A + * + * Supported Feature: N/A + * + * Usage: Internal/External + * + * + */ +#define CFG_QCN_IE_SUPPORT CFG_INI_BOOL( \ + "g_qcn_ie_support", \ + 1, \ + "QCN IE support") + +/* + * + * g_fils_max_chan_guard_time - Set maximum channel guard time(ms) + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to set maximum channel guard time in milliseconds. + * + * Related: None + * + * Supported Feature: FILS + * + * Usage: External + * + * + */ +#define CFG_FILS_MAX_CHAN_GUARD_TIME CFG_INI_UINT( \ + "g_fils_max_chan_guard_time", \ + 0, \ + 10, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Set maximum channel guard time") + +/* + * + * SingleTIDRC - Set replay counter for all TID's + * @Min: 0 Separate replay counter for all TID + * @Max: 1 Single replay counter for all TID + * @Default: 1 + * + * This ini is used to set replay counter for all TID's + * + * 0 - Separate replay counter for all TID + * 1 - Single replay counter for all TID + * + * Related: None. + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define CFG_SINGLE_TID_RC CFG_INI_BOOL( \ + "SingleTIDRC", \ + 1, \ + "replay counter for all TID") + +/* + * wait_cnf_timeout - Wait assoc cnf timeout + * @Min: 10 + * @Max: 3000 + * @Default: 1000 + * + * This is internal configure for waiting assoc cnf timeout + * + * Related: None + * + * Usage: Internal + * + */ +#define CFG_WT_CNF_TIMEOUT CFG_UINT( \ + "wait_cnf_timeout", \ + 10, \ + 3000, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "Wait confirm timeout") + +/* + * + * gStaMiracastMccRestTimeVal - Rest time when Miracast is running. + * @Min: 100 + * @Max: 500 + * @Default: 400 + * + * This ini is used to set rest time for home channel for Miracast before + * going for scan. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ + +#define CFG_STA_MCAST_MCC_REST_TIME CFG_INI_UINT( \ + "gStaMiracastMccRestTimeVal", \ + 100, \ + 500, \ + 400, \ + CFG_VALUE_OR_DEFAULT, \ + "Rest time when Miracast is running") + +/* + * current_rssi - current rssi + * @Min: 0 + * @Max: 127 + * @Default: 0 + * + * This is internal configure for current rssi + * + * Related: None + * + * Usage: Internal + * + */ +#define CFG_CURRENT_RSSI CFG_UINT( \ + "current_rssi", \ + 0, \ + 127, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Current RSSI") + +/* + * + * gAllowTPCfromAP - Support for AP power constraint + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini controls driver to honor/dishonor power constraint from AP. + * + * Related: None. + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define CFG_TX_POWER_CTRL CFG_INI_BOOL( \ + "gAllowTPCfromAP", \ + 1, \ + "Support for AP power constraint") + +/* + * + * gStaKeepAliveMethod - Which keepalive method to use + * @Min: 1 + * @Max: 3 + * @Default: 1 + * + * This ini determines which keepalive method to use for station interfaces + * 1) Use null data packets + * 2) Use gratuitous ARP packets + * 3) Use unsolicited ARP response packets + * + * Related: gStaKeepAlivePeriod, gApKeepAlivePeriod, gGoKeepAlivePeriod + * + * Supported Feature: STA, Keepalive + * + * Usage: External + * + * + */ +#define CFG_STA_KEEPALIVE_METHOD CFG_INI_INT( \ + "gStaKeepAliveMethod", \ + MLME_STA_KEEPALIVE_NULL_DATA, \ + MLME_STA_KEEPALIVE_UNSOLICIT_ARP_RSP, \ + MLME_STA_KEEPALIVE_NULL_DATA, \ + CFG_VALUE_OR_DEFAULT, \ + "Which keepalive method to use") + +/* + * + * gMaxLIModulatedDTIM - Set MaxLIModulate Dtim + * @Min: 1 + * @Max: 10 + * @Default: 5 + * + * This ini is used to set default MaxLIModulatedDTIM + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_MAX_LI_MODULATED_DTIM CFG_INI_UINT( \ + "gMaxLIModulatedDTIM", \ + 1, \ + 10, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Max modulated dtim") + +/* + * + * @Min: 0 + * @Max: 2000 + * @Default: 500 + * + * This ini is used to set default ConDTIMSkipping_MaxTime in ms + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_MAX_LI_MODULATED_DTIM_MS CFG_INI_UINT( \ + "ConDTIMSkipping_MaxTime", \ + 0, \ + 2000, \ + 500, \ + CFG_VALUE_OR_DEFAULT, \ + "DTIM skipping max time") + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * + * mlo_support_link_num - Set number of link mlo connection supports for sta + * @Min: 1 + * @Max: 3 + * @Default: 2 + * + * This ini is used to configure the number of link mlo connection supports + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_MLO_SUPPORT_LINK_NUM CFG_INI_UINT( \ + "mlo_support_link_num", \ + 1, \ + 3, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "supported mlo link number") + +#define CFG_MLO_SUPPORT_LINK_NUM_CFG CFG(CFG_MLO_SUPPORT_LINK_NUM) + +/* + * + * mlo_max_simultaneous_links- Set number of mlo simultaneous links for sta + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This cfg is used to configure the mlo max simultaneous links + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_MLO_MAX_SIMULTANEOUS_LINKS CFG_UINT( \ + "mlo_max_simultaneous_links", \ + 0, \ + 1, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "mlo max simultaneous links") + +#define CFG_MLO_MAX_SIMULTANEOUS_LINKS_CFG CFG(CFG_MLO_MAX_SIMULTANEOUS_LINKS) +/* + * + * mlo_support_link_band - Set band bitmap of mlo connection supports for sta + * @Min: 1 + * @Max: 0x77 + * @Default: 0x77 + * + * This cfg is used to configure the band bitmap of mlo connection supports + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * Supported band of all mlo links + * bits 0: REG_BAND_2G + * bits 1: REG_BAND_5G + * bits 2: REG_BAND_6G + * + * Supported band of assoc link + * bits 4: REG_BAND_2G + * bits 5: REG_BAND_5G + * bits 6: REG_BAND_6G + * + * + */ +#define CFG_MLO_SUPPORT_LINK_BAND CFG_INI_UINT( \ + "mlo_support_link_band", \ + 0x1, \ + 0x77, \ + 0x77, \ + CFG_VALUE_OR_DEFAULT, \ + "supported mlo link band") + +#define CFG_MLO_SUPPORT_LINK_BAND_CFG CFG(CFG_MLO_SUPPORT_LINK_BAND) +/* + * + * RoamCommon_Mlo_TpPrefer - percentage to boost mlo scoring + * + * @Min: -20 + * @Max: +20 + * @Default: 10 + * + * This cfg is used to boost/reduce the mlo weightage with configured + * value. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_MLO_PREFER_PERCENTAGE CFG_INI_INT(\ + "RoamCommon_Mlo_TpPrefer", \ + -20, \ + 20, \ + 10,\ + CFG_VALUE_OR_DEFAULT, \ + "mlo prefer percentage") + +#define CFG_MLO_PREFER_PERCENTAGE_CFG CFG(CFG_MLO_PREFER_PERCENTAGE) + +#else +#define CFG_MLO_SUPPORT_LINK_NUM_CFG +#define CFG_MLO_SUPPORT_LINK_BAND_CFG +#define CFG_MLO_MAX_SIMULTANEOUS_LINKS_CFG +#define CFG_MLO_PREFER_PERCENTAGE_CFG +#endif + +/* + * + * mlo_same_link_mld_addr - Use one of the links address as same mld address + * @Default: false + * + * This cfg is used to configure the one of link address as same mld address + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + * + */ +#define CFG_MLO_SAME_LINK_MLD_ADDR CFG_BOOL( \ + "mlo_same_link_mld_addr",\ + 0, \ + "same address for mlo link/mld") + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +#define CFG_MLO_SAME_LINK_MLD_ADDR_CFG CFG(CFG_MLO_SAME_LINK_MLD_ADDR) +#else +#define CFG_MLO_SAME_LINK_MLD_ADDR_CFG +#endif + +/* + * + * eht_disable_punct_in_us_lpi - Flag to Disable eht puncture in US LPI mode + * @Min: false + * @Max: true + * @Default: false + * + * Related: None + * + * Supported Feature: 802.11be protocol + * + * Usage: Internal + * + * + */ +#define CFG_EHT_DISABLE_PUNCT_IN_US_LPI \ + CFG_BOOL("eht_disable_punct_in_us_lpi", \ + false, \ + "Disable eht puncture in US LPI mode") + +#ifdef WLAN_FEATURE_11BE +#define CFG_EHT_DISABLE_PUNCT_IN_US_LPI_CFG CFG(CFG_EHT_DISABLE_PUNCT_IN_US_LPI) +#else +#define CFG_EHT_DISABLE_PUNCT_IN_US_LPI_CFG +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * + * mlo_5gl_5gh_mlsr - enable/disable 5GL+5GH MLSR + * @Min: false + * @Max: true + * @Default: true + * + * Related: None + * + * Supported Feature: 5GL+5GH MLSR + * + * Usage: Internal + * + * + */ + +#define CFG_MLO_MLO_5GL_5GH_MLSR CFG_INI_BOOL( \ + "mlo_5gl_5gh_mlsr",\ + 1, \ + "enable 5GL+5GH MLSR") + +#define CFG_MLO_MLO_5GL_5GH_MLSR_CFG CFG(CFG_MLO_MLO_5GL_5GH_MLSR) + +/* + * + * epcs_support_enable - enable/disable epcs + * @Min: false + * @Max: true + * @Default: false + * + * Related: None + * + * Supported Feature: emergency preparedness communications service (EPCS) + * priority access + * + * Usage: External + * + * + */ + +#define CFG_MLO_EPCS_SUPPORT_ENABLE CFG_INI_BOOL( \ + "epcs_support_enable",\ + 0, \ + "enable epcs support") + +#define CFG_MLO_EPCS_SUPPORT_ENABLE_CFG CFG(CFG_MLO_EPCS_SUPPORT_ENABLE) +#else +#define CFG_MLO_MLO_5GL_5GH_MLSR_CFG +#define CFG_MLO_EPCS_SUPPORT_ENABLE_CFG +#endif + +#define CFG_STA_ALL \ + CFG(CFG_INFRA_STA_KEEP_ALIVE_PERIOD) \ + CFG(CFG_STA_BSS_MAX_IDLE_PERIOD) \ + CFG(CFG_TGT_GTX_USR_CFG) \ + CFG(CFG_PMKID_MODES) \ + CFG(CFG_IGNORE_PEER_ERP_INFO) \ + CFG(CFG_STA_PREFER_80MHZ_OVER_160MHZ) \ + CFG(CFG_PPS_ENABLE_5G_EBT) \ + CFG(CFG_ENABLE_DEAUTH_BEFORE_CONNECTION) \ + CFG(CFG_DOT11P_MODE) \ + CFG(CFG_DEAUTH_RETRY_CNT) \ + CFG(CFG_ENABLE_GO_CTS2SELF_FOR_STA) \ + CFG(CFG_QCN_IE_SUPPORT) \ + CFG(CFG_STA_MCAST_MCC_REST_TIME) \ + CFG(CFG_FILS_MAX_CHAN_GUARD_TIME) \ + CFG(CFG_SINGLE_TID_RC) \ + CFG(CFG_STA_KEEPALIVE_METHOD) \ + CFG(CFG_WT_CNF_TIMEOUT) \ + CFG(CFG_CURRENT_RSSI) \ + CFG(CFG_TX_POWER_CTRL) \ + CFG(CFG_MAX_LI_MODULATED_DTIM_MS) \ + CFG_MLO_SUPPORT_LINK_NUM_CFG \ + CFG_MLO_MAX_SIMULTANEOUS_LINKS_CFG \ + CFG_MLO_SUPPORT_LINK_BAND_CFG \ + CFG_MLO_PREFER_PERCENTAGE_CFG \ + CFG_MLO_SAME_LINK_MLD_ADDR_CFG \ + CFG_EHT_DISABLE_PUNCT_IN_US_LPI_CFG \ + CFG_MLO_MLO_5GL_5GH_MLSR_CFG \ + CFG_MLO_EPCS_SUPPORT_ENABLE_CFG +#endif /* CFG_MLME_STA_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_stats.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_stats.h new file mode 100644 index 0000000000..827e06ec37 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_stats.h @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_STATS_H +#define __CFG_MLME_STATS_H + +enum mlme_stats_link_speed_rpt_type { + CFG_STATS_LINK_SPEED_REPORT_ACTUAL = 0, + CFG_STATS_LINK_SPEED_REPORT_MAX = 1, + CFG_STATS_LINK_SPEED_REPORT_MAX_SCALED = 2, +}; + +/* + * + * periodic_stats_display_time - time(seconds) after which stats will be printed + * @Min: 0 + * @Max: 256 + * @Default: 10 + * + * This values specifies the recurring time period after which stats will be + * printed in wlan driver logs. + * + * Usage: Internal / External + * + * + */ +#define CFG_PERIODIC_STATS_DISPLAY_TIME CFG_INI_UINT( \ + "periodic_stats_display_time", \ + 0, \ + 256, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "time after which stats will be printed") + +/* + * + * gLinkSpeedRssiMed - Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + * @Min: -127 + * @Max: 0 + * @Default: -65 + * + * This ini is used to set medium rssi link speed + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal / External + * + * + */ +#define CFG_LINK_SPEED_RSSI_MID CFG_INI_INT( \ + "gLinkSpeedRssiMed", \ + -127, \ + 0, \ + -65, \ + CFG_VALUE_OR_DEFAULT, \ + "medium rssi link speed") + +/* + * + * gReportMaxLinkSpeed - Max link speed + * @Min: CFG_STATS_LINK_SPEED_REPORT_ACTUAL + * @Max: CFG_STATS_LINK_SPEED_REPORT_MAX_SCALED + * @Default: CFG_STATS_LINK_SPEED_REPORT_ACTUAL + * + * This ini is used to set Max link speed + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal / External + * + * + */ +#define CFG_REPORT_MAX_LINK_SPEED CFG_INI_UINT( \ + "gReportMaxLinkSpeed", \ + CFG_STATS_LINK_SPEED_REPORT_ACTUAL, \ + CFG_STATS_LINK_SPEED_REPORT_MAX_SCALED, \ + CFG_STATS_LINK_SPEED_REPORT_ACTUAL, \ + CFG_VALUE_OR_DEFAULT, \ + "Max link speed") + +/* + * + * gLinkSpeedRssiLow - Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + * @Min: -127 + * @Max: 0 + * @Default: -80 + * + * This ini is used to set low rssi link speed + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal / External + * + * + */ +#define CFG_LINK_SPEED_RSSI_LOW CFG_INI_INT( \ + "gLinkSpeedRssiLow", \ + -127, \ + 0, \ + -80, \ + CFG_VALUE_OR_DEFAULT, \ + "low rssi link speed") + +/* + * + * gLinkSpeedRssiHigh - Report the max possible speed with RSSI scaling + * @Min: -127 + * @Max: 0 + * @Default: -55 + * + * This ini is used to set default eHDD_LINK_SPEED_REPORT + * Used when eHDD_LINK_SPEED_REPORT_SCALED is selected + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal / External + * + * + */ +#define CFG_LINK_SPEED_RSSI_HIGH CFG_INI_INT( \ + "gLinkSpeedRssiHigh", \ + -127, \ + 0, \ + -55, \ + CFG_VALUE_OR_DEFAULT, \ + "max possible rssi link speed") + +#define CFG_STATS_ALL \ + CFG(CFG_PERIODIC_STATS_DISPLAY_TIME) \ + CFG(CFG_LINK_SPEED_RSSI_HIGH) \ + CFG(CFG_LINK_SPEED_RSSI_MID) \ + CFG(CFG_LINK_SPEED_RSSI_LOW) \ + CFG(CFG_REPORT_MAX_LINK_SPEED) + +#endif /* __CFG_MLME_STATS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_threshold.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_threshold.h new file mode 100644 index 0000000000..f0d1ed71ca --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_threshold.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_THRESHOLD_H +#define __CFG_MLME_THRESHOLD_H + +#include "wni_cfg.h" + +/* + * + * RTSThreshold - Will provide RTSThreshold + * @Min: 0 + * @Max: 1048576 + * @Default: 2347 + * + * This ini is used to set default RTSThreshold + * If minimum value 0 is selected then it will use always RTS + * max is the max frame size + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_RTS_THRESHOLD CFG_INI_UINT( \ + "RTSThreshold", \ + 0, \ + 1048576, \ + 2347, \ + CFG_VALUE_OR_DEFAULT, \ + "Default RTS Threshold") + +/* + * + * gFragmentationThreshold - It will set fragmentation threshold + * @Min: 256 + * @Max: 8000 + * @Default: 8000 + * + * This ini is used to indicate default fragmentation threshold + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define CFG_FRAG_THRESHOLD CFG_INI_UINT( \ + "gFragmentationThreshold", \ + 256, \ + 8000, \ + 8000, \ + CFG_VALUE_OR_DEFAULT, \ + "Default Fragmentation Threshold") + +#define CFG_THRESHOLD_ALL \ + CFG(CFG_RTS_THRESHOLD) \ + CFG(CFG_FRAG_THRESHOLD) + +#endif /* __CFG_MLME_MAIN_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_timeout.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_timeout.h new file mode 100644 index 0000000000..a63cd9a86b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_timeout.h @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2011-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_TIMEOUT_H +#define __CFG_MLME_TIMEOUT_H + +/* + * + * join_failure_timeout - Join failure timeout value + * @Min: 500 + * @Max: 3000 + * @Default: 3000 + * + * This cfg is used to configure the join failure timeout. + * + * Usage: Internal + * + * + */ +#define CFG_JOIN_FAILURE_TIMEOUT CFG_INI_UINT( \ + "join_failure_timeout", \ + 500, \ + 3000, \ + 3000, \ + CFG_VALUE_OR_DEFAULT, \ + "Join failure timeout") + +/* + * + * auth_failure_timeout - Auth failure timeout value + * @Min: 500 + * @Max: 5000 + * @Default: 1000 + * + * This cfg is used to configure the auth failure timeout. + * + * Usage: Internal + * + * + */ +#define CFG_AUTH_FAILURE_TIMEOUT CFG_INI_UINT( \ + "auth_failure_timeout", \ + 500, \ + 5000, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "auth failure timeout") + +/* + * + * auth_rsp_timeout - Auth response timeout value + * @Min: 0 + * @Max: 65535 + * @Default: 1000 + * + * This cfg is used to configure the auth response timeout. + * + * Usage: Internal + * + * + */ +#define CFG_AUTH_RSP_TIMEOUT CFG_INI_UINT( \ + "auth_rsp_timeout", \ + 0, \ + 65535, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "auth rsp timeout") + +/* + * + * assoc_failure_timeout - Assoc failure timeout value + * @Min: 500 + * @Max: 3000 + * @Default: 2000 + * + * This cfg is used to configure the assoc failure timeout. + * + * Usage: Internal + * + * + */ +#define CFG_ASSOC_FAILURE_TIMEOUT CFG_INI_UINT( \ + "assoc_failure_timeout", \ + 500, \ + 3000, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "assoc failure timeout") + +/* + * + * reassoc_failure_timeout - Re-Assoc failure timeout value + * @Min: 0 + * @Max: 65535 + * @Default: 1000 + * + * This cfg is used to configure the re-assoc failure timeout. + * + * Usage: Internal + * + * + */ +#define CFG_REASSOC_FAILURE_TIMEOUT CFG_INI_UINT( \ + "reassoc_failure_timeout", \ + 0, \ + 65535, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "reassoc failure timeout") + +/* + * + * olbc_detect_timeout - olbc detect timeout value + * @Min: 1000 + * @Max: 30000 + * @Default: 10000 + * + * This cfg is used to configure the olbc detect timeout. + * + * Usage: Internal + * + * + */ +#define CFG_OLBC_DETECT_TIMEOUT CFG_INI_UINT( \ + "olbc_detect_timeout", \ + 1000, \ + 30000, \ + 10000, \ + CFG_VALUE_OR_DEFAULT, \ + "OLBC detect timeout") + +/* + * + * addts_rsp_timeout - addts response timeout value + * @Min: 0 + * @Max: 65535 + * @Default: 1000 + * + * This cfg is used to configure the addts response timeout. + * + * Usage: Internal + * + * + */ +#define CFG_ADDTS_RSP_TIMEOUT CFG_INI_UINT( \ + "addts_rsp_timeout", \ + 0, \ + 65535, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "ADDTS RSP timeout") + +/* + * + * gHeartbeat24 - Heart beat threshold value + * @Min: 0 + * @Max: 65535 + * @Default: 40 + * + * This cfg is used to configure the Heart beat threshold. + * + * Usage: Internal/External + * + * + */ +#define CFG_HEART_BEAT_THRESHOLD CFG_INI_UINT( \ + "gHeartbeat24", \ + 0, \ + 65535, \ + 40, \ + CFG_VALUE_OR_DEFAULT, \ + "Heart beat threshold") + +/* + * + * gApKeepAlivePeriod - AP keep alive period + * @Min: 1 + * @Max: 65535 + * @Default: 20 + * + * This ini is used to set keep alive period(in seconds) of AP + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_KEEP_ALIVE_TIMEOUT CFG_INI_UINT( \ + "gApKeepAlivePeriod", \ + 1, \ + 65535, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "AP keep alive timeout") + +/* + * + * gApLinkMonitorPeriod - AP keep alive period + * @Min: 3 + * @Max: 50 + * @Default: 10 + * + * This ini is used to configure AP link monitor timeout value + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_LINK_MONITOR_TIMEOUT CFG_INI_UINT( \ + "gApLinkMonitorPeriod", \ + 3, \ + 50, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "AP link monitor timeout") + +/* + * + * wmi_wq_watchdog - Sets timeout period for wmi watchdog bite. + * @Min: 0 + * @Max: 30 + * @Default: 20 + * + * This ini is used to set timeout period for wmi watchdog bite. If it is + * 0 then wmi watchdog bite is disabled. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_WMI_WQ_WATCHDOG CFG_INI_UINT( \ + "wmi_wq_watchdog", \ + 0, \ + 30, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "timeout period for wmi watchdog bite") + +/* + * + * sae_auth_failure_timeout - SAE Auth failure timeout value in msec + * @Min: 100 + * @Max: 1000 + * @Default: 1000 + * + * This cfg is used to configure the SAE auth failure timeout. + * + * Usage: External + * + * + */ +#define CFG_SAE_AUTH_FAILURE_TIMEOUT CFG_INI_UINT( \ + "sae_auth_failure_timeout", \ + 100, \ + 1000, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "SAE auth failure timeout") + +#define CFG_TIMEOUT_ALL \ + CFG(CFG_JOIN_FAILURE_TIMEOUT) \ + CFG(CFG_AUTH_FAILURE_TIMEOUT) \ + CFG(CFG_AUTH_RSP_TIMEOUT) \ + CFG(CFG_ASSOC_FAILURE_TIMEOUT) \ + CFG(CFG_REASSOC_FAILURE_TIMEOUT) \ + CFG(CFG_OLBC_DETECT_TIMEOUT) \ + CFG(CFG_ADDTS_RSP_TIMEOUT) \ + CFG(CFG_HEART_BEAT_THRESHOLD) \ + CFG(CFG_AP_KEEP_ALIVE_TIMEOUT) \ + CFG(CFG_AP_LINK_MONITOR_TIMEOUT) \ + CFG(CFG_WMI_WQ_WATCHDOG) \ + CFG(CFG_SAE_AUTH_FAILURE_TIMEOUT) + +#endif /* __CFG_MLME_TIMEOUT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_twt.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_twt.h new file mode 100644 index 0000000000..776068a84d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_twt.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2011-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_TWT_H +#define __CFG_MLME_TWT_H +#if defined(WLAN_SUPPORT_TWT) && !defined(WLAN_TWT_CONV_SUPPORTED) +/* + * + * twt_requestor - twt requestor. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This cfg is used to store twt requestor config. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal + * + * + */ +#define CFG_TWT_REQUESTOR CFG_INI_BOOL( \ + "twt_requestor", \ + 1, \ + "TWT requestor") +/* + * + * twt_responder - twt responder. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This cfg is used to store twt responder config. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal + * + * + */ +#define CFG_TWT_RESPONDER CFG_INI_BOOL( \ + "twt_responder", \ + false, \ + "TWT responder") + +/* + * + * enable_twt - Enable Target Wake Time support. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable TWT support. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_ENABLE_TWT CFG_INI_BOOL( \ + "enable_twt", \ + 1, \ + "TWT support") + +/* + * + * twt_congestion_timeout - Target wake time congestion timeout. + * @Min: 0 + * @Max: 10000 + * @Default: 100 + * + * STA uses this timer to continuously monitor channel congestion levels to + * decide whether to start or stop TWT. This ini is used to configure the + * target wake time congestion timeout value in the units of milliseconds. + * A value of Zero indicates that this is a host triggered TWT and all the + * necessary configuration for TWT will be directed from the host. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_TWT_CONGESTION_TIMEOUT CFG_INI_UINT( \ + "twt_congestion_timeout", \ + 0, \ + 10000, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "twt congestion timeout") +/* + * + * twt_bcast_req_resp_config - To enable broadcast twt requestor and responder. + * @Min: 0 Disable the extended twt capability + * @Max: 3 + * @Default: 1 + * + * This cfg is used to configure the broadcast TWT requestor and responder. + * Bitmap for enabling the broadcast twt requestor and responder. + * BIT 0: Enable/Disable broadcast twt requestor. + * BIT 1: Enable/Disable broadcast twt responder. + * BIT 2-31: Reserved + * + * Related: CFG_ENABLE_TWT + * Related: CFG_TWT_RESPONDER + * Related: CFG_TWT_REQUESTOR + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +/* defines to extract the requestor/responder capabilities from cfg */ +#define TWT_BCAST_REQ_INDEX 0 +#define TWT_BCAST_REQ_BITS 1 +#define TWT_BCAST_RES_INDEX 1 +#define TWT_BCAST_RES_BITS 1 + +#define CFG_BCAST_TWT_REQ_RESP CFG_INI_UINT( \ + "twt_bcast_req_resp_config", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "BROADCAST TWT CAPABILITY") + +#define CFG_TWT_GET_BCAST_REQ(_bcast_conf) \ + QDF_GET_BITS(_bcast_conf, \ + TWT_BCAST_REQ_INDEX, \ + TWT_BCAST_REQ_BITS) + +#define CFG_TWT_GET_BCAST_RES(_bcast_conf) \ + QDF_GET_BITS(_bcast_conf, \ + TWT_BCAST_RES_INDEX, \ + TWT_BCAST_RES_BITS) + +/* + * + * enable_twt_24ghz - Enable Target wake time when STA is connected on 2.4Ghz + * band. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable the host TWT when STA is connected to AP + * in 2.4Ghz band. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_ENABLE_TWT_24GHZ CFG_INI_BOOL( \ + "enable_twt_24ghz", \ + true, \ + "enable twt in 2.4Ghz band") + +#define CFG_TWT_ALL \ + CFG(CFG_ENABLE_TWT) \ + CFG(CFG_TWT_REQUESTOR) \ + CFG(CFG_TWT_RESPONDER) \ + CFG(CFG_TWT_CONGESTION_TIMEOUT) \ + CFG(CFG_BCAST_TWT_REQ_RESP) \ + CFG(CFG_ENABLE_TWT_24GHZ) +#endif +#endif /* __CFG_MLME_TWT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_vht_caps.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_vht_caps.h new file mode 100644 index 0000000000..7a433beee6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_vht_caps.h @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_VHT_CAPS_H +#define __CFG_MLME_VHT_CAPS_H + +#define CFG_VHT_SUPP_CHAN_WIDTH CFG_UINT( \ + "supp_chan_width", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT SUPPORTED CHAN WIDTH SET") + +/* + * + * gTxBFCsnValue - ini to set VHT/HE STS Caps field + * @Min: 0 + * @Max: 7 + * @Default: 7 + * + * This ini is used to configure the STS capability shown in AC/AX mode + * MGMT frame IE, the final STS field shown in VHT/HE IE will be calculated + * by MIN of (INI set, target report value). Only if gTxBFEnable is enabled + * and SU/MU BEAMFORMEE Caps is shown, then STS Caps make sense. + * + * Related: gTxBFEnable. + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ +#define CFG_VHT_BEAMFORMEE_ANT_SUPP CFG_INI_UINT( \ + "txBFCsnValue", \ + 0, \ + 7, \ + 7, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT BEAMFORMEE ANTENNA SUPPORTED CAP") + +/* + * + * gEnableTxSUBeamformer - Enables TX Su beam former + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_TX_SU_BEAM_FORMER CFG_INI_BOOL( \ + "gEnableTxSUBeamformer", \ + 0, \ + "vht tx su beam former") + +#define CFG_VHT_NUM_SOUNDING_DIMENSIONS CFG_UINT( \ + "num_soundingdim", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT NUMBER OF SOUNDING DIMENSIONS") + +#define CFG_VHT_HTC_VHTC CFG_BOOL( \ + "htc_vhtc", \ + 0, \ + "VHT HTC VHTC") + +#define CFG_VHT_LINK_ADAPTATION_CAP CFG_UINT( \ + "link_adap_cap", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT LINK ADAPTATION CAP") + +#define CFG_VHT_RX_ANT_PATTERN CFG_BOOL( \ + "rx_antpattern", \ + 1, \ + "VHT RX ANTENNA PATTERN CAP") + +#define CFG_VHT_TX_ANT_PATTERN CFG_BOOL( \ + "tx_antpattern", \ + 1, \ + "VHT TX ANTENNA PATTERN CAP") + +#define CFG_VHT_RX_SUPP_DATA_RATE CFG_UINT( \ + "rx_supp_data_rate", \ + 0, \ + 780, \ + 780, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT RX SUPP DATA RATE") + +#define CFG_VHT_TX_SUPP_DATA_RATE CFG_UINT( \ + "tx_supp_data_rate", \ + 0, \ + 780, \ + 780, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT TX SUPP DATA RATE") + +#define CFG_TX_BF_CAP CFG_UINT( \ + "tx_bf_cap", \ + 0, \ + 4294967295, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "TX BF CAP") + +#define CFG_AS_CAP CFG_UINT( \ + "as_cap", \ + 0, \ + 255, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "AS CAP") + +/* + * + * gDisableLDPCWithTxbfAP - Disable LDPC with tx bf AP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_DISABLE_LDPC_WITH_TXBF_AP CFG_INI_BOOL( \ + "gDisableLDPCWithTxbfAP", \ + 0, \ + "Disable LDPC with tx bf AP") + +/* + * + * gTxBFEnable - Enables SU beamformee caps + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_SU_BEAMFORMEE_CAP CFG_INI_BOOL( \ + "gTxBFEnable", \ + 1, \ + "VHT SU BEAMFORMEE CAPABILITY") + +/* + * + * gEnableTxBFin20MHz - Enables TXBF in 20mhz + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_TXBF_IN_20MHZ CFG_INI_BOOL( \ + "gEnableTxBFin20MHz", \ + 1, \ + "VHT ENABLE TXBF 20MHZ") + +#define CFG_VHT_MU_BEAMFORMER_CAP CFG_BOOL( \ + "mu_bformer", \ + 0, \ + "VHT MU BEAMFORMER CAP") + +#define CFG_VHT_TXOP_PS CFG_BOOL( \ + "txop_ps", \ + 0, \ + "VHT TXOP PS") + +/* + * + * gVhtChannelWidth - Channel width capability for 11ac + * @Min: 0 + * @Max: 4 + * @Default: 2 + * + * This ini is used to set channel width capability for 11AC. + * eHT_CHANNEL_WIDTH_20MHZ = 0, + * eHT_CHANNEL_WIDTH_40MHZ = 1, + * eHT_CHANNEL_WIDTH_80MHZ = 2, + * eHT_CHANNEL_WIDTH_160MHZ = 3, + * eHT_CHANNEL_WIDTH_80P80MHZ = 4, + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_CHANNEL_WIDTH CFG_INI_UINT( \ + "gVhtChannelWidth", \ + 0, \ + 4, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "Channel width capability for 11ac") + +/* + * + * gVhtRxMCS - VHT Rx MCS capability for 1x1 mode + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * This ini is used to set VHT Rx MCS capability for 1x1 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_RX_MCS_8_9 CFG_INI_UINT( \ + "gVhtRxMCS", \ + 0, \ + 2, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT Rx MCS") + +/* + * + * gVhtTxMCS - VHT Tx MCS capability for 1x1 mode + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * This ini is used to set VHT Tx MCS capability for 1x1 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_TX_MCS_8_9 CFG_INI_UINT( \ + "gVhtTxMCS", \ + 0, \ + 2, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT Tx MCS") + +/* + * + * gVhtRxMCS2x2 - VHT Rx MCS capability for 2x2 mode + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * This ini is used to set VHT Rx MCS capability for 2x2 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_RX_MCS2x2_8_9 CFG_INI_UINT( \ + "gVhtRxMCS2x2", \ + 0, \ + 2, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT Rx MCS 2x2") + +/* + * + * gVhtTxMCS2x2 - VHT Tx MCS capability for 2x2 mode + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * This ini is used to set VHT Tx MCS capability for 2x2 mode. + * 0, MCS0-7 + * 1, MCS0-8 + * 2, MCS0-9 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_TX_MCS2x2_8_9 CFG_INI_UINT( \ + "gVhtTxMCS2x2", \ + 0, \ + 2, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT Tx MCS 2x2") + +/* + * + * enable_vht20_mcs9 - Enables VHT MCS9 in 20M BW operation + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_ENABLE_VHT20_MCS9 CFG_INI_BOOL( \ + "enable_vht20_mcs9", \ + 1, \ + "Enables VHT MCS9 in 20M BW") + +/* + * + * gEnable2x2 - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini disables/enables 2x2 mode. If this is zero then DUT operates as 1x1 + * + * 0, Disable + * 1, Enable + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_2x2_CAP_FEATURE CFG_INI_BOOL( \ + "gEnable2x2", \ + 1, \ + "VHT Enable 2x2") + +/* + * + * gEnableMuBformee - Enables/disables multi-user (MU) beam formee capability + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini enables/disables multi-user (MU) beam formee + * capability + * + * Change MU Bformee only when gTxBFEnable is enabled. + * When gTxBFEnable and gEnableMuBformee are set, MU beam formee capability is + * enabled. + * Related: gTxBFEnable + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE CFG_INI_BOOL( \ + "gEnableMuBformee", \ + 1, \ + "VHT Enable MU Beamformee") + +/* + * + * gEnablePAID - VHT partial AID feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This option enables/disables VHT partial AID feature. + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_PAID_FEATURE CFG_INI_BOOL( \ + "gEnablePAID", \ + 0, \ + "VHT Enable PAID") + +/* + * + * gEnableGID - VHT Group ID feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This option enables/disables VHT Group ID feature. + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_GID_FEATURE CFG_INI_BOOL( \ + "gEnableGID", \ + 0, \ + "VHT Enable GID") + +/* + * + * gEnableVhtFor24GHzBand - Enable VHT for 2.4GHZ in SAP mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_ENABLE_VHT_FOR_24GHZ CFG_INI_BOOL( \ + "gEnableVhtFor24GHzBand", \ + 1, \ + "VHT Enable for 24GHz") + +/* + * gEnableVendorVhtFor24GHzBand - Parameter to control VHT support + * based on vendor ie in 2.4 GHz band + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This parameter will enable SAP to read VHT capability in vendor ie in Assoc + * Req and send VHT caps in Resp to establish connection in VHT Mode. + * Supported Feature: SAP + * + * + * Usage: External + * + * + */ +#define CFG_ENABLE_VENDOR_VHT_FOR_24GHZ CFG_INI_BOOL( \ + "gEnableVendorVhtFor24GHzBand", \ + 1, \ + "VHT Enable Vendor for 24GHz") + +/* + * + * gVhtAmpduLenExponent - maximum receive AMPDU size configuration + * @Min: 0 + * @Max: 7 + * @Default: 7 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_AMPDU_LEN_EXPONENT CFG_INI_UINT( \ + "gVhtAmpduLenExponent", \ + 0, \ + 7, \ + 7, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT AMPDU Len in Exponent") + +/* + * + * gVhtMpduLen - VHT MPDU length + * @Min: 0 + * @Max: 2 + * @Default: 2 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_MPDU_LEN CFG_INI_UINT( \ + "gVhtMpduLen", \ + 0, \ + 2, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "VHT MPDU Length") + +/* + * + * gEnableTxBFeeSAP - Enable / Disable Tx beamformee in SAP mode + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Related: NA + * + * Supported Feature: 11AC + * + * Usage: External + * + * + */ +#define CFG_VHT_ENABLE_TXBF_SAP_MODE CFG_INI_BOOL( \ + "gEnableTxBFeeSAP", \ + 1, \ + "Enable tx bf sap mode") + +/* + * + * enable_subfee_vendor_vhtie - ini to enable/disable SU Bformee in vendor VHTIE + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable SU Bformee in vendor vht ie if gTxBFEnable + * is enabled. if gTxBFEnable is 0 this will not have any effect. + * + * Related: gTxBFEnable. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE CFG_INI_BOOL( \ + "enable_subfee_vendor_vhtie", \ + 1, \ + "Enable subfee in vendor vht ie") + +/* + * + * enable_vhtmcs_10_11_support - Enable/Disable vht mcs 10, 11 support + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable mcs 10, 11 support. + * + * Related: NA + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_VHT_MCS_10_11 CFG_INI_BOOL( \ + "enable_vhtmcs_10_11_support", \ + 1, \ + "Enable/Disable vht mcs 10, 11 support") + +#define CFG_VHT_CAPS_ALL \ + CFG(CFG_VHT_SUPP_CHAN_WIDTH) \ + CFG(CFG_VHT_SU_BEAMFORMEE_CAP) \ + CFG(CFG_VHT_BEAMFORMEE_ANT_SUPP) \ + CFG(CFG_VHT_ENABLE_TX_SU_BEAM_FORMER) \ + CFG(CFG_VHT_NUM_SOUNDING_DIMENSIONS) \ + CFG(CFG_VHT_MU_BEAMFORMER_CAP) \ + CFG(CFG_VHT_TXOP_PS) \ + CFG(CFG_VHT_HTC_VHTC) \ + CFG(CFG_VHT_LINK_ADAPTATION_CAP) \ + CFG(CFG_VHT_RX_ANT_PATTERN) \ + CFG(CFG_VHT_TX_ANT_PATTERN) \ + CFG(CFG_VHT_RX_SUPP_DATA_RATE) \ + CFG(CFG_VHT_TX_SUPP_DATA_RATE) \ + CFG(CFG_VHT_ENABLE_TXBF_IN_20MHZ) \ + CFG(CFG_VHT_CHANNEL_WIDTH) \ + CFG(CFG_VHT_ENABLE_RX_MCS_8_9) \ + CFG(CFG_VHT_ENABLE_TX_MCS_8_9) \ + CFG(CFG_VHT_ENABLE_RX_MCS2x2_8_9) \ + CFG(CFG_VHT_ENABLE_TX_MCS2x2_8_9) \ + CFG(CFG_ENABLE_VHT20_MCS9) \ + CFG(CFG_VHT_ENABLE_2x2_CAP_FEATURE) \ + CFG(CFG_VHT_ENABLE_MU_BFORMEE_CAP_FEATURE) \ + CFG(CFG_VHT_ENABLE_PAID_FEATURE) \ + CFG(CFG_VHT_ENABLE_GID_FEATURE) \ + CFG(CFG_ENABLE_VHT_FOR_24GHZ) \ + CFG(CFG_ENABLE_VENDOR_VHT_FOR_24GHZ) \ + CFG(CFG_VHT_AMPDU_LEN_EXPONENT) \ + CFG(CFG_VHT_MPDU_LEN) \ + CFG(CFG_VHT_ENABLE_TXBF_SAP_MODE) \ + CFG(CFG_ENABLE_SUBFEE_IN_VENDOR_VHTIE) \ + CFG(CFG_TX_BF_CAP) \ + CFG(CFG_AS_CAP) \ + CFG(CFG_DISABLE_LDPC_WITH_TXBF_AP) \ + CFG(CFG_ENABLE_VHT_MCS_10_11) + +#endif /* __CFG_MLME_VHT_CAPS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wep_params.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wep_params.h new file mode 100644 index 0000000000..ddd5f93c54 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wep_params.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of WEP parameters related + * converged configuration. + */ + +#ifndef __CFG_MLME_WEP_PARAMS_H +#define __CFG_MLME_WEP_PARAMS_H + +#define CFG_WEP_DEFAULT_KEYID CFG_UINT( \ + "wep_default_key_id", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "wep default key id") + +#define CFG_SHARED_KEY_AUTH_ENABLE CFG_BOOL( \ + "shared_key_auth", \ + 1, \ + "shared key authentication") + +#define CFG_OPEN_SYSTEM_AUTH_ENABLE CFG_BOOL( \ + "open_system_auth", \ + 1, \ + "Open system authentication") + +#define CFG_AUTHENTICATION_TYPE CFG_UINT( \ + "auth_type", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "authentication type") + +#define CFG_PRIVACY_ENABLED CFG_BOOL( \ + "privacy_enabled", \ + 0, \ + "wep privacy") + +#define CFG_WEP_PARAMS_ALL \ + CFG(CFG_WEP_DEFAULT_KEYID) \ + CFG(CFG_SHARED_KEY_AUTH_ENABLE) \ + CFG(CFG_OPEN_SYSTEM_AUTH_ENABLE) \ + CFG(CFG_AUTHENTICATION_TYPE) \ + CFG(CFG_PRIVACY_ENABLED) + +#endif /* __CFG_MLME_WEP_PARAMS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wifi_pos.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wifi_pos.h new file mode 100644 index 0000000000..a749ade71d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wifi_pos.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_WIFI_POS_H +#define __CFG_MLME_WIFI_POS_H + +/* + * + * gfine_time_meas_cap - fine timing measurement capability information + * @Min: 0x0000 + * @Max: 0x00BD + * @Default: 0x000D + * + * fine timing measurement capability information + * + * <----- fine_time_meas_cap (in bits) -----> + * +---------+-----+-----+-----+-----+------+------+-------+-------+-----+-----+ + * | 10-31 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +---------+-----+-----+-----+-----+------+------+-------+-------+-----+-----+ + * | reserved| NAN | NAN | SAP | SAP |P2P-GO|P2P-GO|P2P-CLI|P2P-CLI| STA | STA | + * | | resp|init |resp |init |resp |init |resp |init |resp |init | + * +---------+-----+-----+-----+-----+------+------+-------+-------+-----+-----+ + * + * resp - responder role; init- initiator role + * + * CFG_FINE_TIME_MEAS_CAPABILITY_MAX computed based on the table + * +-----------------+-----------------+-----------+ + * | Device Role | Initiator | Responder | + * +-----------------+-----------------+-----------+ + * | Station | Y | N | + * | P2P-CLI | Y | Y | + * | P2P-GO | Y | Y | + * | SAP | N | Y | + * +-----------------+-----------------+-----------+ + * + * Related: None + * + * Supported Feature: WIFI POS + * + * Usage: Internal/External + * + * + */ +#define CFG_FINE_TIME_MEAS_CAPABILITY CFG_INI_UINT( \ + "gfine_time_meas_cap", \ + 0x0000, \ + 0x003BD, \ + 0x0030D, \ + CFG_VALUE_OR_DEFAULT, \ + "fine timing measurement capability") + +/* + * + * oem_6g_support_disable - oem 6g support is disabled + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to show OEM is 6Ghz disabled. For legacy OEM apps + * having no support for 6Ghz, the default value is 1 and thus driver will + * not serve 6Ghz info to legacy oem application. + * OEM apps supporting 6Ghz sets the ini value to 0 to get 6Ghz + * information from driver. + * + * Related: None + * + * Supported Feature: WIFI POS + * + * Usage: Internal/External + * + * + */ +#define CFG_OEM_SIXG_SUPPORT_DISABLE CFG_INI_BOOL( \ + "oem_6g_support_disable", \ + 1, \ + "oem 6Ghz support Enabled/disabled") +/* + * + * enable_responder_secure_ltf_support - R-STA secure LTF keyseed support + * @Min: false + * @Max: true + * @Default: false + * + * This ini is used to enable R-STA advertising secure LTF support. + * + * Related: None + * + * Supported Feature: WIFI POS + * + * Usage: Internal/External + * + * + */ +#define CFG_RESPONDER_SECURE_LTF_SUPPORT CFG_INI_BOOL( \ + "enable_responder_secure_ltf_support", \ + false, \ + "enable Responder secure LTF support") + +/* + * + * enable_responder_11az_support - R-STA 11az ranging support + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to enable TB and NTB of R-STA advertising 11az ranging + * capabilities. + * + * +-----------+----------+-------+ + * | Value | TB | NTB | + * +-----------+----------+-------+ + * | 0x0 | 0 | 0 | + * | 0x1 | 0 | 1 | + * | 0x2 | 1 | 0 | + * | 0x3 | 1 | 1 | + * +-----------+----------+-------+ + * + * Related: None + * + * Supported Feature: WIFI POS + * + * Usage: Internal/External + * + * + */ +#define CFG_RESPONDER_11AZ_SUPPORT CFG_INI_UINT( \ + "enable_responder_11az_support", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "enable Responder 11az support") + +#define CFG_WIFI_POS_ALL \ + CFG(CFG_FINE_TIME_MEAS_CAPABILITY) \ + CFG(CFG_OEM_SIXG_SUPPORT_DISABLE) \ + CFG(CFG_RESPONDER_SECURE_LTF_SUPPORT) \ + CFG(CFG_RESPONDER_11AZ_SUPPORT) + +#endif /* __CFG_MLME_WIFI_POS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wps_params.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wps_params.h new file mode 100644 index 0000000000..43a093503a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_mlme_wps_params.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __CFG_MLME_WPS_PARAMS_H +#define __CFG_MLME_WPS_PARAMS_H + +#define CFG_WPS_ENABLE CFG_UINT( \ + "enable_wps", \ + 0, \ + 255, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "enable wps") + +#define CFG_WPS_STATE CFG_UINT( \ + "wps_state", \ + 0, \ + 255, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "wps_state") + +#define CFG_WPS_VERSION CFG_UINT( \ + "wps_version", \ + 0, \ + 255, \ + 16, \ + CFG_VALUE_OR_DEFAULT, \ + "wps version") + +#define CFG_WPS_CFG_METHOD CFG_UINT( \ + "wps_cfg_method", \ + 0, \ + 4294967295, \ + 8, \ + CFG_VALUE_OR_DEFAULT, \ + "wps cfg method") + +#define CFG_WPS_PRIMARY_DEVICE_CATEGORY CFG_UINT( \ + "wps_primary_device_category", \ + 0, \ + 65535, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "wps primary device category") + +#define CFG_WPS_PIMARY_DEVICE_OUI CFG_UINT( \ + "wps_primary_device_oui", \ + 0, \ + 4294967295, \ + 5304836, \ + CFG_VALUE_OR_DEFAULT, \ + "wps primary device oui") + +#define CFG_WPS_DEVICE_SUB_CATEGORY CFG_UINT( \ + "wps_device_sub_category", \ + 0, \ + 65535, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "wps device sub category") + +#define CFG_WPS_DEVICE_PASSWORD_ID CFG_UINT( \ + "wps_device_password_id", \ + 0, \ + 4294967295, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "wps device password id") + +#define WPS_UUID_DEF_STR "0xa, 0xb, 0xc, 0xd, 0xe, 0xf" +#define WPS_UUID_DEF_LEN (sizeof(WPS_UUID_DEF_STR) - 1) + +#define CFG_WPS_UUID CFG_STRING( \ + "wps_uuid", \ + 0, \ + WPS_UUID_DEF_LEN, \ + WPS_UUID_DEF_STR, \ + "wps uuid") + +#define CFG_WPS_ALL \ + CFG(CFG_WPS_ENABLE) \ + CFG(CFG_WPS_STATE) \ + CFG(CFG_WPS_VERSION) \ + CFG(CFG_WPS_CFG_METHOD) \ + CFG(CFG_WPS_PRIMARY_DEVICE_CATEGORY) \ + CFG(CFG_WPS_PIMARY_DEVICE_OUI) \ + CFG(CFG_WPS_DEVICE_SUB_CATEGORY) \ + CFG(CFG_WPS_DEVICE_PASSWORD_ID) \ + CFG(CFG_WPS_UUID) + +#endif /* __CFG_MLME_WPS_PARAMS_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_qos.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_qos.h new file mode 100644 index 0000000000..d55a012c4e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_qos.h @@ -0,0 +1,568 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of QOS related + * converged configurations. + */ + +#ifndef __CFG_MLME_QOS_H +#define __CFG_MLME_QOS_H + +#define ADDBA_TXAGGR_SIZE 256 + +/* + * + * gTxAggregationSize - Gives an option to configure Tx aggregation size + * in no of MPDUs + * @Min: 0 + * @Max: ADDBA_TXAGGR_SIZE + * @Default: ADDBA_TXAGGR_SIZE + * + * gTxAggregationSize gives an option to configure Tx aggregation size + * in no of MPDUs.This can be useful in debugging throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_TX_AGGREGATION_SIZE CFG_INI_UINT( \ + "gTxAggregationSize", \ + 0, \ + ADDBA_TXAGGR_SIZE, \ + ADDBA_TXAGGR_SIZE, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx Aggregation size value") + +/* + * + * gTxAggregationSizeBE - To configure Tx aggregation size for BE queue + * in no of MPDUs + * @Min: 0 + * @Max: ADDBA_TXAGGR_SIZE + * @Default: 0 + * + * gTxAggregationSizeBE gives an option to configure Tx aggregation size + * for BE queue in no of MPDUs.This can be useful in debugging + * throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGREGATION_SIZEBE CFG_INI_UINT( \ + "gTxAggregationSizeBE", \ + 0, \ + ADDBA_TXAGGR_SIZE, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx Aggregation size value BE") + +/* + * + * gTxAggregationSizeBK - To configure Tx aggregation size for BK queue + * in no of MPDUs + * @Min: 0 + * @Max: ADDBA_TXAGGR_SIZE + * @Default: 0 + * + * gTxAggregationSizeBK gives an option to configure Tx aggregation size + * for BK queue in no of MPDUs.This can be useful in debugging + * throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGREGATION_SIZEBK CFG_INI_UINT( \ + "gTxAggregationSizeBK", \ + 0, \ + ADDBA_TXAGGR_SIZE, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx Aggregation size value BK") + +/* + * + * gTxAggregationSizeVI - To configure Tx aggregation size for VI queue + * in no of MPDUs + * @Min: 0 + * @Max: ADDBA_TXAGGR_SIZE + * @Default: 0 + * + * gTxAggregationSizeVI gives an option to configure Tx aggregation size + * for VI queue in no of MPDUs.This can be useful in debugging + * throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGREGATION_SIZEVI CFG_INI_UINT( \ + "gTxAggregationSizeVI", \ + 0, \ + ADDBA_TXAGGR_SIZE, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx Aggregation size value for VI") + +/* + * + * gTxAggregationSizeVO - To configure Tx aggregation size for VO queue + * in no of MPDUs + * @Min: 0 + * @Max: ADDBA_TXAGGR_SIZE + * @Default: 0 + * + * gTxAggregationSizeVO gives an option to configure Tx aggregation size + * for BE queue in no of MPDUs.This can be useful in debugging + * throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGREGATION_SIZEVO CFG_INI_UINT( \ + "gTxAggregationSizeVO", \ + 0, \ + ADDBA_TXAGGR_SIZE, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx Aggregation size value for VO") + +/* + * + * gRxAggregationSize - Gives an option to configure Rx aggregation size + * in no of MPDUs + * @Min: 1 + * @Max: 1024 + * @Default: 256 + * + * gRxAggregationSize gives an option to configure Rx aggregation size + * in no of MPDUs. This can be useful in debugging throughput issues + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_RX_AGGREGATION_SIZE CFG_INI_UINT( \ + "gRxAggregationSize", \ + 1, \ + 1024, \ + 256, \ + CFG_VALUE_OR_DEFAULT, \ + "Rx Aggregation size value") + +/* + * + * gTxAggSwRetryBE - Configure Tx aggregation sw retry for BE + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxAggSwRetryBE gives an option to configure Tx aggregation sw + * retry for BE. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGR_SW_RETRY_BE CFG_INI_UINT( \ + "gTxAggSwRetryBE", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx aggregation retry value for BE") + +/* + * + * gTxAggSwRetryBK - Configure Tx aggregation sw retry for BK + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxAggSwRetryBK gives an option to configure Tx aggregation sw + * retry for BK. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGR_SW_RETRY_BK CFG_INI_UINT( \ + "gTxAggSwRetryBK", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx aggregation retry value for BK") + +/* + * + * gTxAggSwRetryVI - Configure Tx aggregation sw retry for VI + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxAggSwRetryVI gives an option to configure Tx aggregation sw + * retry for VI. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGR_SW_RETRY_VI CFG_INI_UINT( \ + "gTxAggSwRetryVI", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx aggregation retry value for VI") + +/* + * + * gTxAggSwRetryVO - Configure Tx aggregation sw retry for VO + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxAggSwRetryVO gives an option to configure Tx aggregation sw + * retry for VO. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_AGGR_SW_RETRY_VO CFG_INI_UINT( \ + "gTxAggSwRetryVO", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx aggregation retry value for VO") + +/* + * + * gTxNonAggSwRetryBE - Configure Tx non aggregation sw retry for BE + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxNonAggSwRetryBE gives an option to configure Tx non aggregation sw + * retry for BE. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_NON_AGGR_SW_RETRY_BE CFG_INI_UINT( \ + "gTxNonAggSwRetryBE", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx non aggregation retry value for BE") + +/* + * + * gTxNonAggSwRetryBK - Configure Tx non aggregation sw retry for BK + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxNonAggSwRetryBK gives an option to configure Tx non aggregation sw + * retry for BK. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_NON_AGGR_SW_RETRY_BK CFG_INI_UINT( \ + "gTxNonAggSwRetryBK", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx non aggregation retry value for BK") + +/* + * + * gTxNonAggSwRetryVI - Configure Tx non aggregation sw retry for VI + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxNonAggSwRetryVI gives an option to configure Tx non aggregation sw + * retry for VI. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_NON_AGGR_SW_RETRY_VI CFG_INI_UINT( \ + "gTxNonAggSwRetryVI", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx non aggregation retry value for VI") + +/* + * + * gTxNonAggSwRetryVO - Configure Tx non aggregation sw retry for VO + * @Min: 0 + * @Max: 64 + * @Default: 0 + * + * gTxNonAggSwRetryVO gives an option to configure Tx non aggregation sw + * retry for VO. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_TX_NON_AGGR_SW_RETRY_VO CFG_INI_UINT( \ + "gTxNonAggSwRetryVO", \ + 0, \ + 64, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx non aggregation retry value for VO") +/* + * + * gTxAggSwRetry - Configure Tx aggregation sw retry + * @Min: 0 + * @Max: 64 + * @Default: 16 + * + * gTxAggSwRetry gives an option to configure Tx aggregation sw + * retry. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_TX_AGGR_SW_RETRY CFG_INI_UINT( \ + "gTxAggSwRetry", \ + 0, \ + 64, \ + 16, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx aggregation retry value") +/* + * + * gTxNonAggSwRetry - Configure Tx non aggregation sw retry + * @Min: 0 + * @Max: 64 + * @Default: 16 + * + * gTxNonAggSwRetry gives an option to configure Tx non aggregation sw + * retry. This can be useful in debugging throughput issues. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_TX_NON_AGGR_SW_RETRY CFG_INI_UINT( \ + "gTxNonAggSwRetry", \ + 0, \ + 64, \ + 16, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx non aggregation retry value") +/* + * + * gSapMaxInactivityOverride - Configure + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This parameter will avoid updating ap_sta_inactivity from hostapd.conf + * file. If a station does not send anything in ap_max_inactivity seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. This feature is used to + * clear station table of old entries when the STAs move out of the + * range. + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + */ +#define CFG_SAP_MAX_INACTIVITY_OVERRIDE CFG_INI_BOOL( \ + "gSapMaxInactivityOverride", \ + 0, \ + "SAP maximum inactivity override flag") + +/* + * + * gEnableApUapsd - Enable/disable UAPSD for SoftAP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to setup setup U-APSD for Acs at association + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_SAP_QOS_UAPSD CFG_INI_BOOL( \ + "gEnableApUapsd", \ + 1, \ + "Enable UAPSD for SAP") + +#define IOT_AGGR_INFO_MAX_LEN 500 +#define IOT_AGGR_INFO_MAX_NUM 32 +#define IOT_AGGR_MSDU_MAX_NUM 6 +#define IOT_AGGR_MPDU_MAX_NUM 512 +/* + * + * cfg_tx_iot_aggr - OUI based tx aggr size for msdu/mpdu + * + * This ini gives an option to configure Tx aggregation size + * in no. of MPDUs/MSDUs for specified OUI. + * This can be useful for IOT issues. + * + * Format of the configuration: + * cfg_tx_iot_aggr=,,,,,... + * MSDU: 0..IOT_AGGR_MSDU_MAX_NUM, the max tx aggregation size in no. of MSDUs, + * 0 means not specified. + * MPDU: 0..IOT_AGGR_MPDU_MAX_NUM, the max tx aggregation size in no. of MPDUs, + * 0 means not specified. + * Note: MSDU-x/MPDU-x are the max values, FW will take decision for actual + * AMSDU/AMPDU size on different platforms. + * + * For example: + * cfg_tx_iot_aggr=112233,2,0,445566,3,32,778899,0,64 + * If vendor OUI-1("\x11\x22\x33") is found in assoc resp, + * set tx amsdu size to 2; + * If vendor OUI-2("\x44\x55\x66") is found in assoc resp, + * set tx amsdu size to 3, set tx ampdu size to 32; + * If vendor OUI-3("\x77\x88\x99") is found in assoc resp, + * set tx ampdu size to 64. + * + * Related: IOT + * + * Supported Feature: IOT + * + * Usage: External + * + * + */ +#define CFG_TX_IOT_AGGR CFG_INI_STRING( \ + "cfg_tx_iot_aggr", \ + 0, \ + IOT_AGGR_INFO_MAX_LEN, \ + "", \ + "Used to configure OUI based tx aggr size for msdu/mpdu") + +#define CFG_QOS_ALL \ + CFG(CFG_SAP_MAX_INACTIVITY_OVERRIDE) \ + CFG(CFG_TX_AGGREGATION_SIZE) \ + CFG(CFG_TX_AGGREGATION_SIZEBE) \ + CFG(CFG_TX_AGGREGATION_SIZEBK) \ + CFG(CFG_TX_AGGREGATION_SIZEVI) \ + CFG(CFG_TX_AGGREGATION_SIZEVO) \ + CFG(CFG_RX_AGGREGATION_SIZE) \ + CFG(CFG_TX_AGGR_SW_RETRY_BE) \ + CFG(CFG_TX_AGGR_SW_RETRY_BK) \ + CFG(CFG_TX_AGGR_SW_RETRY_VI) \ + CFG(CFG_TX_AGGR_SW_RETRY_VO) \ + CFG(CFG_TX_AGGR_SW_RETRY) \ + CFG(CFG_TX_NON_AGGR_SW_RETRY_BE) \ + CFG(CFG_TX_NON_AGGR_SW_RETRY_BK) \ + CFG(CFG_TX_NON_AGGR_SW_RETRY_VI) \ + CFG(CFG_TX_NON_AGGR_SW_RETRY_VO) \ + CFG(CFG_TX_NON_AGGR_SW_RETRY) \ + CFG(CFG_SAP_QOS_UAPSD) \ + CFG(CFG_TX_IOT_AGGR) + +#endif /* __CFG_MLME_QOS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_sap_protection.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_sap_protection.h new file mode 100644 index 0000000000..4454392303 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/cfg_sap_protection.h @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of sap erp protection related + * converged configurations. + */ + +#ifndef __CFG_MLME_SAP_PROTECTION_H +#define __CFG_MLME_SAP_PROTECTION_H + +#define CFG_PROTECTION_ENABLED CFG_UINT( \ + "protection_enabled", \ + 0, \ + 65535, \ + 65535, \ + CFG_VALUE_OR_DEFAULT, \ + "sap protection enabled") + +#define CFG_FORCE_POLICY_PROTECTION CFG_UINT( \ + "protection_force_policy", \ + 0, \ + 5, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "force policy protection") + +/* + * + * gignore_peer_ht_opmode + * + * @min 0 + * @max 1 + * @default 1 + * + * Enabling gignore_peer_ht_opmode will enable 11g + * protection only when there is a 11g AP in vicinity. + * + * Related: None + * + * Supported Feature: SAP Protection + * + */ +#define CFG_IGNORE_PEER_HT_MODE CFG_INI_BOOL( \ + "gignore_peer_ht_opmode", \ + false, \ + "ignore the peer ht mode") + +/* + * + * gEnableApProt - Enable/Disable AP protection + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable AP protection + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_ENABLE_PROTECTION_MODE CFG_INI_BOOL( \ + "gEnableApProt", \ + true, \ + "enable protection on sap") + +/* + * + * gApProtection - Set AP protection parameter + * @Min: 0x0 + * @Max: 0xFFFF + * @Default: 0xBFFF + * + * This ini is used to set AP protection parameter + * Bit map for CFG_AP_PROTECTION_MODE_DEFAULT + * LOWER byte for associated stations + * UPPER byte for overlapping stations + * each byte will have the following info + * bit15 bit14 bit13 bit12 bit11 bit10 bit9 bit8 + * OBSS RIFS LSIG_TXOP NON_GF HT20 FROM_11G FROM_11B FROM_11A + * bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 + * OBSS RIFS LSIG_TXOP NON_GF HT_20 FROM_11G FROM_11B FROM_11A + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_PROTECTION_MODE CFG_INI_UINT( \ + "gApProtection", \ + 0x0, \ + 0xFFFF, \ + 0xBFFF, \ + CFG_VALUE_OR_DEFAULT, \ + "AP protection mode bitmap") + +/* + * + * gEnableApOBSSProt - Enable/Disable AP OBSS protection + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable AP OBSS protection + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ +#define CFG_AP_OBSS_PROTECTION_ENABLE CFG_INI_BOOL( \ + "gEnableApOBSSProt", \ + false, \ + "Enable/Disable AP OBSS protection") + +#define CFG_SAP_PROTECTION_ALL \ + CFG(CFG_PROTECTION_ENABLED) \ + CFG(CFG_FORCE_POLICY_PROTECTION) \ + CFG(CFG_IGNORE_PEER_HT_MODE) \ + CFG(CFG_AP_ENABLE_PROTECTION_MODE) \ + CFG(CFG_AP_PROTECTION_MODE) \ + CFG(CFG_AP_OBSS_PROTECTION_ENABLE) + +#endif /* __CFG_MLME_SAP_PROTECTION_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_ext_mlme_obj_types.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_ext_mlme_obj_types.h new file mode 100644 index 0000000000..bca632106e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_ext_mlme_obj_types.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_ext_mlme_obj_types.h + * + * This header file is included by the converged control path mlme + * component to map legacy private structures to the external + * (ext)typedefs used by the converged code. This mechanism allows the + * legacy structs to be included as part of the global objmgr objects. + */ + +#ifndef __WLAN_EXT_MLME_OBJ_TYPE_H__ +#define __WLAN_EXT_MLME_OBJ_TYPE_H__ + +struct opaque_mlme_pdev_ext; + +/** + * typedef mlme_pdev_ext_t - Opaque definition of pdev mlme pointer + * Define ext_pdev_ptr from external umac/mlme component point to this type + */ +typedef struct opaque_mlme_pdev_ext mlme_pdev_ext_t; + +/** + * typedef mlme_vdev_ext_t - Definition of vdev mlme pointer + * Define ext_vdev_ptr from external umac/mlme component point to this type + */ +typedef struct mlme_legacy_priv mlme_vdev_ext_t; + +/** + * typedef mlme_psoc_ext_t - Definition of psoc mlme pointer + * Define ext_psoc_ptr from external umac/mlme component point to this type + */ +typedef struct wlan_mlme_psoc_ext_obj mlme_psoc_ext_t; + +/** + * typedef cm_ext_t - Definition of connection manager ext pointer + * Define ext_cm_ptr from legacy umac/mlme component to use + */ +typedef struct cm_ext_obj cm_ext_t; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h new file mode 100644 index 0000000000..8e0b3c9f8a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_api.h @@ -0,0 +1,5028 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare public APIs exposed by the mlme component + */ + +#ifndef _WLAN_MLME_API_H_ +#define _WLAN_MLME_API_H_ + +#include +#include +#include +#include "sme_api.h" + +#define DISABLE_MCS_12_13_2G_40M 1 + +#define ASSEMBLE_RATECODE_V1(_pream, _nss, _rate) \ + (((1) << 28) | ((_pream) << 8) | ((_nss) << 5) | (_rate)) + +/* This macro is used to extract the rate from the rate_code as first four bits + * in rate_code represents the rate, next 3 bits represents the nss and + * next 2 bits represents preamble. + */ +#define RATECODE_V1_RIX_MASK 0xf + +/* This macro is used to extract preamble from the rate_code as first 4 bits + * in rate_code represents the rate, next 3 bits represents the nss and + * next 2 bits represents preamble. + */ +#define RATECODE_V1_PREAMBLE_OFFSET (4 + 3) + +/* This macro is used to extract NSS from the rate_code as first 4 bits + * in rate_code represents the rate, next 3 bits represents the NSS and + * next 2 bits represents preamble. + */ +#define RATECODE_V1_NSS_OFFSET 0x4 +#define RATECODE_V1_NSS_MASK 0x7 + +#ifdef FEATURE_SET +/** + * wlan_mlme_get_feature_info() - Get mlme features + * @psoc: psoc context + * @mlme_feature_set: MLME feature set info structure + * + * Return: None + */ +void wlan_mlme_get_feature_info( + struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_features *mlme_feature_set); +#endif + +/** + * wlan_mlme_get_cfg_str() - Copy the uint8_t array for a particular CFG + * @dst: pointer to the destination buffer. + * @cfg_str: pointer to the cfg string structure + * @len: length to be copied + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + */ +QDF_STATUS wlan_mlme_get_cfg_str(uint8_t *dst, struct mlme_cfg_str *cfg_str, + qdf_size_t *len); + +/** + * wlan_mlme_set_cfg_str() - Set values for a particular CFG + * @src: pointer to the source buffer. + * @dst_cfg_str: pointer to the cfg string structure to be modified + * @len: length to be written + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + */ +QDF_STATUS wlan_mlme_set_cfg_str(uint8_t *src, struct mlme_cfg_str *dst_cfg_str, + qdf_size_t len); + +/** + * wlan_mlme_get_edca_params() - get the EDCA parameters corresponding to the + * edca profile access category + * @edca_params: pointer to mlme edca parameters structure + * @data: data to which the parameter is to be copied + * @edca_ac: edca ac type enum passed to get the cfg value + * + * Return QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + * + */ +QDF_STATUS wlan_mlme_get_edca_params(struct wlan_mlme_edca_params *edca_params, + uint8_t *data, enum e_edca_type edca_ac); + +/** + * wlan_mlme_update_cfg_with_tgt_caps() - Update mlme cfg with tgt caps + * @psoc: pointer to psoc object + * @tgt_caps: Pointer to the mlme related capability structure + * + * Return: None + */ +void +wlan_mlme_update_cfg_with_tgt_caps(struct wlan_objmgr_psoc *psoc, + struct mlme_tgt_caps *tgt_caps); + +/** + * wlan_mlme_update_aux_dev_caps() - Update mlme aux capability + * @psoc: pointer to psoc object + * @wlan_mlme_aux_dev_caps: array for aux dev capability + * + * Return: None + */ + +void +wlan_mlme_update_aux_dev_caps(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_aux_dev_caps + wlan_mlme_aux_dev_caps[]); + +/* + * mlme_get_wep_key() - get the wep key to process during auth frame + * @vdev: VDEV object for which the wep key is being requested + * @wep_params: cfg wep parameters structure + * @wep_key_id: default key number + * @default_key: default key to be copied + * @key_len: length of the key to copy + * + * Return QDF_STATUS + */ +QDF_STATUS mlme_get_wep_key(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_wep_cfg *wep_params, + enum wep_key_id wep_keyid, uint8_t *default_key, + qdf_size_t *key_len); + +/** + * wlan_mlme_get_tx_power() - Get the max tx power in particular band + * @psoc: pointer to psoc object + * @band: 2ghz/5ghz band + * + * Return: value of tx power in the respective band + */ +uint8_t wlan_mlme_get_tx_power(struct wlan_objmgr_psoc *psoc, + enum band_info band); + +/** + * wlan_mlme_get_power_usage() - Get the power usage info + * @psoc: pointer to psoc object + * + * Return: pointer to character array of power usage + */ +char *wlan_mlme_get_power_usage(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_enable_deauth_to_disassoc_map() - Get the deauth to disassoc + * map + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_enable_deauth_to_disassoc_map(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_ht_cap_info() - Get the HT cap info config + * @psoc: pointer to psoc object + * @ht_cap_info: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_ht_cap_info(struct wlan_objmgr_psoc *psoc, + struct mlme_ht_capabilities_info + *ht_cap_info); + +/** + * wlan_mlme_get_manufacturer_name() - get manufacturer name + * @psoc: pointer to psoc object + * @pbuf: pointer of the buff which will be filled for the caller + * @plen: pointer of max buffer length + * actual length will be returned at this address + * This function gets manufacturer name + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_mlme_get_manufacturer_name(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen); + +/** + * wlan_mlme_get_model_number() - get model number + * @psoc: pointer to psoc object + * @pbuf: pointer of the buff which will be filled for the caller + * @plen: pointer of max buffer length + * actual length will be returned at this address + * This function gets model number + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_mlme_get_model_number(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen); + +/** + * wlan_mlme_get_model_name() - get model name + * @psoc: pointer to psoc object + * @pbuf: pointer of the buff which will be filled for the caller + * @plen: pointer of max buffer length + * actual length will be returned at this address + * This function gets model name + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_mlme_get_model_name(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen); + +/** + * wlan_mlme_get_manufacture_product_name() - get manufacture product name + * @psoc: pointer to psoc object + * @pbuf: pointer of the buff which will be filled for the caller + * @plen: pointer of max buffer length + * actual length will be returned at this address + * This function gets manufacture product name + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_mlme_get_manufacture_product_name(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen); + +/** + * wlan_mlme_get_manufacture_product_version() - get manufacture product version + * @psoc: pointer to psoc object + * @pbuf: pointer of the buff which will be filled for the caller + * @plen: pointer of max buffer length + * actual length will be returned at this address + * This function gets manufacture product version + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +wlan_mlme_get_manufacture_product_version(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen); + +/** + * wlan_mlme_set_ht_cap_info() - Set the HT cap info config + * @psoc: pointer to psoc object + * @ht_cap_info: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_ht_cap_info(struct wlan_objmgr_psoc *psoc, + struct mlme_ht_capabilities_info + ht_cap_info); + +/** + * wlan_mlme_get_max_amsdu_num() - get the max amsdu num + * @psoc: pointer to psoc object + * @value: pointer to the value where the max_amsdu num is to be filled + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_get_max_amsdu_num(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_set_max_amsdu_num() - set the max amsdu num + * @psoc: pointer to psoc object + * @value: value to be set for max_amsdu_num + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_set_max_amsdu_num(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_get_ht_mpdu_density() - get the ht mpdu density + * @psoc: pointer to psoc object + * @value: pointer to the value where the ht mpdu density is to be filled + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_get_ht_mpdu_density(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_set_ht_mpdu_density() - set the ht mpdu density + * @psoc: pointer to psoc object + * @value: value to be set for ht mpdu density + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_set_ht_mpdu_density(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_get_band_capability() - Get the Band capability config + * @psoc: pointer to psoc object + * @band_capability: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_band_capability(struct wlan_objmgr_psoc *psoc, + uint32_t *band_capability); + +#ifdef QCA_MULTIPASS_SUPPORT +/** + * wlan_mlme_peer_config_vlan() - send vlan id to FW for RX path + * @vdev: vdev pointer + * @mac_addr: mac address of the peer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_peer_config_vlan(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr); +#else +static inline QDF_STATUS +wlan_mlme_peer_config_vlan(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * wlan_mlme_get_wlm_multi_client_ll_caps() - Get the wlm multi client latency + * level capability flag + * @psoc: pointer to psoc object + * + * Return: True is multi client ll cap present + */ +bool wlan_mlme_get_wlm_multi_client_ll_caps(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +wlan_mlme_get_wlm_multi_client_ll_caps(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +/** + * wlan_mlme_get_coex_unsafe_chan_nb_user_prefer() - get coex unsafe nb + * support + * @psoc: pointer to psoc object + * + * Return: coex_unsafe_chan_nb_user_prefer + */ +uint32_t wlan_mlme_get_coex_unsafe_chan_nb_user_prefer( + struct wlan_objmgr_psoc *psoc); +bool wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_p2p_go( + struct wlan_objmgr_psoc *psoc); +bool wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + struct wlan_objmgr_psoc *psoc); +#else +static inline +uint32_t wlan_mlme_get_coex_unsafe_chan_nb_user_prefer( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_p2p_go( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * wlan_mlme_set_band_capability() - Set the Band capability config + * @psoc: pointer to psoc object + * @band_capability: Value to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_band_capability(struct wlan_objmgr_psoc *psoc, + uint32_t band_capability); + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * wlan_mlme_get_vendor_handoff_control_caps() - Get the vendor handoff control + * capability flag + * @psoc: pointer to psoc object + * + * Return: True if vendor handoff control caps present + */ +bool wlan_mlme_get_vendor_handoff_control_caps(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +wlan_mlme_get_vendor_handoff_control_caps(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * wlan_mlme_set_dual_sta_policy() - Set the dual sta config + * @psoc: pointer to psoc object + * @dual_sta_config: Value to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_dual_sta_policy(struct wlan_objmgr_psoc *psoc, + uint8_t dual_sta_config); + +/** + * wlan_mlme_get_dual_sta_policy() - Get the dual sta policy + * @psoc: pointer to psoc object + * @dual_sta_config: Value to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_dual_sta_policy(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_sta_config); + +/** + * wlan_mlme_convert_ap_policy_config() - Convert vendor attr ap policy + * config to host enum + * @ap_config: Value to convert + * + * Return: enum host_concurrent_ap_policy + */ +enum host_concurrent_ap_policy +wlan_mlme_convert_ap_policy_config( + enum qca_wlan_concurrent_ap_policy_config ap_config); + +/** + * wlan_mlme_set_ap_policy() - Set ap config policy value + * @vdev: pointer to vdev object + * @ap_cfg_policy: Value to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_ap_policy(struct wlan_objmgr_vdev *vdev, + enum host_concurrent_ap_policy ap_cfg_policy); + +/** + * wlan_mlme_get_ap_policy() - Get ap config policy value + * @vdev: pointer to vdev object + * + * Return: enum host_concurrent_ap_policy + */ +enum host_concurrent_ap_policy +wlan_mlme_get_ap_policy(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_ll_lt_sap_send_oce_flags_fw() - Send the oce flags to FW for + * ll_lt_sap + * @vdev: pointer to vdev object + * + * Return: void + */ +void wlan_mlme_ll_lt_sap_send_oce_flags_fw(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_get_prevent_link_down() - Get the prevent link down config + * @psoc: pointer to psoc object + * @prevent_link_down: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_prevent_link_down(struct wlan_objmgr_psoc *psoc, + bool *prevent_link_down); + +/** + * wlan_mlme_get_select_5ghz_margin() - Get the select 5Ghz margin config + * @psoc: pointer to psoc object + * @select_5ghz_margin: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_select_5ghz_margin(struct wlan_objmgr_psoc *psoc, + uint8_t *select_5ghz_margin); + +/** + * wlan_mlme_get_rtt_mac_randomization() - Get the RTT MAC randomization config + * @psoc: pointer to psoc object + * @rtt_mac_randomization: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_rtt_mac_randomization(struct wlan_objmgr_psoc *psoc, + bool *rtt_mac_randomization); + +/** + * wlan_mlme_get_crash_inject() - Get the crash inject config + * @psoc: pointer to psoc object + * @crash_inject: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_crash_inject(struct wlan_objmgr_psoc *psoc, + bool *crash_inject); + +/** + * wlan_mlme_get_lpass_support() - Get the LPASS Support config + * @psoc: pointer to psoc object + * @lpass_support: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_lpass_support(struct wlan_objmgr_psoc *psoc, + bool *lpass_support); + +/** + * wlan_mlme_get_wls_6ghz_cap() - Get the wifi location service(WLS) + * 6ghz capability + * @psoc: pointer to psoc object + * @wls_6ghz_capable: Pointer to the variable from caller + * + * Return: void + */ +void wlan_mlme_get_wls_6ghz_cap(struct wlan_objmgr_psoc *psoc, + bool *wls_6ghz_capable); + +/** + * wlan_mlme_get_self_recovery() - Get the self recovery config + * @psoc: pointer to psoc object + * @self_recovery: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_self_recovery(struct wlan_objmgr_psoc *psoc, + bool *self_recovery); + +/** + * wlan_mlme_get_sub_20_chan_width() - Get the sub 20 chan width config + * @psoc: pointer to psoc object + * @sub_20_chan_width: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sub_20_chan_width(struct wlan_objmgr_psoc *psoc, + uint8_t *sub_20_chan_width); + +/** + * wlan_mlme_get_fw_timeout_crash() - Get the fw timeout crash config + * @psoc: pointer to psoc object + * @fw_timeout_crash: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_fw_timeout_crash(struct wlan_objmgr_psoc *psoc, + bool *fw_timeout_crash); + +/** + * wlan_mlme_get_ito_repeat_count() - Get the fw timeout crash config + * @psoc: pointer to psoc object + * @ito_repeat_count: Pointer to the variable from caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_ito_repeat_count(struct wlan_objmgr_psoc *psoc, + uint8_t *ito_repeat_count); + +/** + * wlan_mlme_get_acs_with_more_param() - Get the acs_with_more_param flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_acs_with_more_param(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_auto_channel_weight() - Get the auto channel weight + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_auto_channel_weight(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_vendor_acs_support() - Get the vendor based channel selece + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ + +QDF_STATUS wlan_mlme_get_vendor_acs_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_acs_support_for_dfs_ltecoex() - Get the flag for + * acs support for dfs ltecoex + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_acs_support_for_dfs_ltecoex(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_external_acs_policy() - Get the flag for external acs policy + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_external_acs_policy(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_sap_inactivity_override() - Check if sap max inactivity + * override flag is set. + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +void wlan_mlme_get_sap_inactivity_override(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_ignore_peer_ht_mode() - Get the ignore peer ht opmode flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_ignore_peer_ht_mode(struct wlan_objmgr_psoc *psoc, + bool *value); +/** + * wlan_mlme_get_tx_chainmask_cck() - Get the tx_chainmask_cfg value + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +QDF_STATUS wlan_mlme_get_tx_chainmask_cck(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_tx_chainmask_1ss() - Get the tx_chainmask_1ss value + * @psoc: pointer to psoc object + * @value: Value that caller needs to get + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +QDF_STATUS wlan_mlme_get_tx_chainmask_1ss(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_num_11b_tx_chains() - Get the number of 11b only tx chains + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +QDF_STATUS wlan_mlme_get_num_11b_tx_chains(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_num_11ag_tx_chains() - get the total number of 11a/g tx chains + * @psoc: pointer to psoc object + * @value: Value that caller needs to get + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +QDF_STATUS wlan_mlme_get_num_11ag_tx_chains(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_bt_chain_separation_flag() - get the enable_bt_chain_separation + * flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +QDF_STATUS wlan_mlme_get_bt_chain_separation_flag(struct wlan_objmgr_psoc *psoc, + bool *value); +/** + * wlan_mlme_configure_chain_mask() - configure chainmask parameters + * @psoc: pointer to psoc object + * @session_id: vdev_id + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc, + uint8_t session_id); + +/** + * wlan_mlme_is_chain_mask_supported() - check if configure chainmask can + * be supported + * @psoc: pointer to psoc object + * + * Return: true if supported else false + */ +bool wlan_mlme_is_chain_mask_supported(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_listen_interval() - Get listen interval + * @psoc: pointer to psoc object + * @value: Pointer to value that needs to be filled by MLME + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_listen_interval(struct wlan_objmgr_psoc *psoc, + int *value); + +/** + * wlan_mlme_set_sap_listen_interval() - Set the sap listen interval + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_sap_listen_interval(struct wlan_objmgr_psoc *psoc, + int value); + +/** + * wlan_mlme_set_assoc_sta_limit() - Set the assoc sta limit + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_assoc_sta_limit(struct wlan_objmgr_psoc *psoc, + int value); + +/** + * wlan_mlme_get_assoc_sta_limit() - Get the assoc sta limit + * @psoc: pointer to psoc object + * @value: Pointer to value that needs to be filled by MLME + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_assoc_sta_limit(struct wlan_objmgr_psoc *psoc, + int *value); + +/** + * wlan_mlme_get_sap_get_peer_info() - get the sap get peer info + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_get_peer_info(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_set_sap_get_peer_info() - set the sap get peer info + * @psoc: pointer to psoc object + * @value: value to overwrite the sap get peer info + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_sap_get_peer_info(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_get_sap_bcast_deauth_enabled() - get the enable/disable value + * for broadcast deauth in sap + * @psoc: pointer to psoc object + * @value: Value that needs to get from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_sap_bcast_deauth_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_sap_allow_all_channels() - get the value of sap allow all + * channels + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_allow_all_channels(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_is_6g_sap_fd_enabled() - get the enable/disable value + * for 6g sap fils discovery + * @psoc: pointer to psoc object + * @value: Value that needs to get from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_is_6g_sap_fd_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_sap_max_peers() - get the value sap max peers + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_max_peers(struct wlan_objmgr_psoc *psoc, + int *value); + +/** + * wlan_mlme_set_sap_max_peers() - set the value sap max peers + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_sap_max_peers(struct wlan_objmgr_psoc *psoc, + int value); + +/** + * wlan_mlme_get_sap_max_offload_peers() - get the value sap max offload peers + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_max_offload_peers(struct wlan_objmgr_psoc *psoc, + int *value); + +/** + * wlan_mlme_get_sap_max_offload_reorder_buffs() - get the value sap max offload + * reorder buffs. + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_max_offload_reorder_buffs(struct wlan_objmgr_psoc + *psoc, int *value); + +/** + * wlan_mlme_get_sap_chn_switch_bcn_count() - get the value sap max channel + * switch beacon count + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_chn_switch_bcn_count(struct wlan_objmgr_psoc *psoc, + int *value); + +/** + * wlan_mlme_get_sap_chn_switch_mode() - get the sap channel + * switch mode + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_chn_switch_mode(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_sap_internal_restart() - get the sap internal + * restart + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_internal_restart(struct wlan_objmgr_psoc *psoc, + bool *value); +/** + * wlan_mlme_get_sap_max_modulated_dtim() - get the max modulated dtim + * restart + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_max_modulated_dtim(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_sap_chan_pref_location() - get the sap chan pref location + * restart + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_chan_pref_location(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_sap_country_priority() - get the sap country code priority + * restart + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_country_priority(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_sap_reduced_beacon_interval() - get the sap reduced + * beacon interval + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_reduced_beacon_interval(struct wlan_objmgr_psoc + *psoc, int *value); + +/** + * wlan_mlme_get_sap_chan_switch_rate_enabled() - get the sap rate hostapd + * enabled beacon interval + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_chan_switch_rate_enabled(struct wlan_objmgr_psoc + *psoc, bool *value); + +/** + * wlan_mlme_get_sap_force_11n_for_11ac() - get the sap 11n for 11ac + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_sap_force_11n_for_11ac(struct wlan_objmgr_psoc + *psoc, bool *value); + +/** + * wlan_mlme_get_go_force_11n_for_11ac() - get the go 11n for 11ac + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_go_force_11n_for_11ac(struct wlan_objmgr_psoc + *psoc, bool *value); + +/** + * wlan_mlme_is_go_11ac_override() - Override 11ac bandwdith for P2P GO + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_is_go_11ac_override(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_is_sap_11ac_override() - Override 11ac bandwdith for SAP + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_is_sap_11ac_override(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_set_go_11ac_override() - set override 11ac bandwdith for P2P GO + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_go_11ac_override(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_set_sap_11ac_override() - set override 11ac bandwdith for SAP + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_sap_11ac_override(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_get_oce_sta_enabled_info() - Get the OCE feature enable + * info for STA + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_oce_sta_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_bigtk_support() - Get the BIGTK support + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_bigtk_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_ocv_support() - Get the OCV support + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_ocv_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_host_scan_abort_support() - Get support for stop all host + * scans service capability. + * @psoc: PSOC object pointer + * + * Return: True if capability is supported, else False + */ +bool wlan_mlme_get_host_scan_abort_support(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_dual_sta_roam_support - Get support for dual sta roaming + * feature + * @psoc: PSOC object pointer + * + * Return: True if capability is supported, else False + */ +bool wlan_mlme_get_dual_sta_roam_support(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_oce_sap_enabled_info() - Get the OCE feature enable + * info for SAP + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_oce_sap_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_update_oce_flags() - Update the oce flags to FW + * @pdev: pointer to pdev object + * + * Return: void + */ +void wlan_mlme_update_oce_flags(struct wlan_objmgr_pdev *pdev); + +/** + * wlan_mlme_cfg_get_aux_supported_modes() - get supported mode of aux. + * definition of bitmap refer WMI_AUX_DEV_CAPS_SUPPORTED_MODE. + * + * @psoc: pointer to psoc object + * @aux_index: aux index, current only support aux0. + * @hw_mode_id: hw mode id + * @supported_modes_bitmap: output for value + * + * Return: true for getting value. false for failure check. + */ +bool wlan_mlme_cfg_get_aux_supported_modes( + struct wlan_objmgr_psoc *psoc, + uint32_t aux_index, + enum wlan_mlme_hw_mode_config_type hw_mode_id, + uint32_t *supported_modes_bitmap); + +/** + * wlan_mlme_is_aux_scan_support() - check whether aux scan is supported. + * @psoc: pointer to psoc object + * @hw_mode_id: hw mode id + * + * Return: true if supporting, else false + */ +bool +wlan_mlme_is_aux_scan_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_hw_mode_config_type hw_mode_id); + +/** + * wlan_mlme_is_aux_listen_support() - check whether aux listen is supported. + * @psoc: pointer to psoc object + * @hw_mode_id: hw mode id + * + * Return: true if supporting, else false + */ +bool +wlan_mlme_is_aux_listen_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_hw_mode_config_type hw_mode_id); + +/** + * wlan_mlme_is_aux_emlsr_support() - check whether aux emlsr is supported. + * @psoc: pointer to psoc object + * @hw_mode_id: hw mode id + * + * Return: true if supporting, else false + */ +bool +wlan_mlme_is_aux_emlsr_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_hw_mode_config_type hw_mode_id); + +#ifdef WLAN_FEATURE_11AX +/** + * wlan_mlme_cfg_get_he_ul_mumimo() - Get the HE Ul Mumio + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_cfg_get_he_ul_mumimo(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_cfg_set_he_ul_mumimo() - Set the HE Ul Mumio + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_cfg_set_he_ul_mumimo(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * mlme_cfg_get_he_caps() - Get the HE capability info + * @psoc: pointer to psoc object + * @he_cap: Caps that needs to be filled. + * + * Return: QDF Status + */ +QDF_STATUS mlme_cfg_get_he_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEhe_cap *he_cap); + +/** + * wlan_mlme_cfg_get_enable_ul_mimo() - Get the HE Ul mimo + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_cfg_get_enable_ul_mimo(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_get_enable_ul_ofdm() - Get enable ul ofdm + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_cfg_get_enable_ul_ofdm(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * mlme_update_tgt_he_caps_in_cfg() - Update tgt he cap in mlme component + * @psoc: pointer to psoc object + * @cfg: pointer to config params from target + * + * This api to be used by callers to update + * he caps in mlme. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_cfg *cfg); +#endif + +/** + * wlan_mlme_convert_vht_op_bw_to_phy_ch_width() - convert channel width in VHT + * operation IE to phy_ch_width + * @channel_width: channel width in VHT operation IE. + * @chan_id: channel id + * @ccfs0: channel center frequency segment 0 + * @ccfs1: channel center frequency segment 1 + * + * Return: phy_ch_width + */ +enum phy_ch_width +wlan_mlme_convert_vht_op_bw_to_phy_ch_width(uint8_t channel_width, + uint8_t chan_id, + uint8_t ccfs0, + uint8_t ccfs1); + +/** + * wlan_mlme_convert_he_6ghz_op_bw_to_phy_ch_width() - convert channel width in + * he 6ghz peration IE to phy_ch_width + * @channel_width: channel width in HE operation IE. + * @chan_id: channel id + * @ccfs0: channel center frequency segment 0 + * @ccfs1: channel center frequency segment 1 + * + * Return: phy_ch_width + */ +enum phy_ch_width +wlan_mlme_convert_he_6ghz_op_bw_to_phy_ch_width(uint8_t channel_width, + uint8_t chan_id, + uint8_t ccfs0, + uint8_t ccfs1); + +/** + * wlan_mlme_chan_stats_scan_event_cb() - process connected channel stats + * scan event + * @vdev: pointer to vdev object + * @event: scan event definition + * @arg: scan argument + * + * Return: none + */ +void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); + +/** + * wlan_mlme_send_ch_width_update_with_notify() - update connected VDEV + * channel bandwidth + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @link_id: mlo link id + * @ch_width: channel width to update + * + * Return: none + */ +QDF_STATUS +wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t link_id, + enum phy_ch_width ch_width); + +/** + * wlan_mlme_update_bss_rate_flags() - update bss rate flag as per new channel + * width + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @cw: channel width to update + * @eht_present: connected bss is eht capable or not + * @he_present: connected bss is he capable or not + * @vht_present: connected bss is vht capable or not + * @ht_present: connected bss is ht capable or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width cw, + uint8_t eht_present, + uint8_t he_present, + uint8_t vht_present, + uint8_t ht_present); + +#ifdef WLAN_FEATURE_11BE +/** + * mlme_update_tgt_eht_caps_in_cfg() - Update tgt eht cap in mlme component + * @psoc: pointer to psoc object + * @cfg: pointer to config params from target + * + * This api to be used by callers to update EHT caps in mlme. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS mlme_update_tgt_eht_caps_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_cfg *cfg); + +/** + * mlme_update_tgt_mlo_caps_in_cfg() - Update tgt MLO cap in mlme component + * @psoc: pointer to psoc object + * + * This api to be used by callers to update MLO caps in mlme. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS mlme_update_tgt_mlo_caps_in_cfg(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_convert_eht_op_bw_to_phy_ch_width() - convert channel width in eht + * operation IE to phy_ch_width + * @channel_width: channel width in eht operation IE + * + * Return: phy_ch_width + */ +enum phy_ch_width wlan_mlme_convert_eht_op_bw_to_phy_ch_width( + uint8_t channel_width); + +/** + * wlan_mlme_convert_phy_ch_width_to_eht_op_bw() - convert channel width to eht + * operation IE format + * @ch_width: phy_ch_width + * + * Return: channel width in eht operation IE + */ +uint8_t wlan_mlme_convert_phy_ch_width_to_eht_op_bw(enum phy_ch_width ch_width); + +/** + * wlan_mlme_get_epcs_capability() - Get mlme epcs capability flag + * @psoc: psoc object + * + * Return: true if epcs capability enabled + */ +bool wlan_mlme_get_epcs_capability(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_epcs_capability() - Set mlme epcs capability flag + * @psoc: psoc object + * @flag: epcs capability flag + * + * Return: void + */ +void wlan_mlme_set_epcs_capability(struct wlan_objmgr_psoc *psoc, bool flag); + +/** + * wlan_mlme_get_usr_disable_sta_eht() - Get user disable sta eht flag + * @psoc: psoc object + * + * Return: true if user has disabled eht in connect request + */ +bool wlan_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_usr_disable_sta_eht() - Set user disable sta eht flag + * @psoc: psoc object + * @disable: eht disable flag + * + * Return: void + */ +void wlan_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc, + bool disable); + +/** + * wlan_mlme_get_eht_disable_punct_in_us_lpi() - Get disable eht punct in us + * lpi mode flag. + * @psoc: psoc object + * + * Return: true if eht punct disabled in us lpi mode + */ +bool wlan_mlme_get_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_eht_disable_punct_in_us_lpi() - Set disable eht punct in us + * lpi mode flag. + * @psoc: psoc object + * @flag: true if eht punct disabled in us lpi mode + * + * Return: void + */ +void wlan_mlme_set_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc, + bool flag); +/** + * wlan_mlme_update_bw_no_punct() - update connected VDEV + * channel bandwidth without puncture bitmap for FCC requirement + * @psoc: pointer to SOC object + * @vdev_id: vdev id + * + * Return: none + */ +QDF_STATUS +wlan_mlme_update_bw_no_punct(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_mlme_get_bw_no_punct() - Get connected VDEV + * channel bandwidth without puncture bitmap for FCC requirement + * @psoc: pointer to SOC object + * @vdev: pointer to vdev + * @bss_chan: bss chan with puncture + * @new_ch_width: pointer to new channel bandwidth without puncture + * Return: none + */ +QDF_STATUS +wlan_mlme_get_bw_no_punct(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_channel *bss_chan, + enum phy_ch_width *new_ch_width); +#else +static inline +bool wlan_mlme_get_epcs_capability(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +void wlan_mlme_set_epcs_capability(struct wlan_objmgr_psoc *psoc, bool flag) +{ +} + +static inline +bool wlan_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline +void wlan_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc, + bool disable) +{ +} + +static inline +bool wlan_mlme_get_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +void wlan_mlme_set_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc, + bool flag) +{ +} + +static inline QDF_STATUS +wlan_mlme_update_bw_no_punct(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_E_INVAL; +} + +static inline QDF_STATUS +wlan_mlme_get_bw_no_punct(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_channel *bss_chan, + enum phy_ch_width *new_ch_width) +{ + return QDF_STATUS_E_INVAL; +} +#endif + +/** + * wlan_mlme_is_ap_prot_enabled() - check if sap protection is enabled + * @psoc: pointer to psoc object + * + * Return: is_ap_prot_enabled flag + */ +bool wlan_mlme_is_ap_prot_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_ap_protection_mode() - Get ap_protection_mode value + * @psoc: pointer to psoc object + * @value: pointer to the value which needs to be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_ap_protection_mode(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_is_ap_obss_prot_enabled() - Get ap_obss_protection is + * enabled/disabled + * @psoc: pointer to psoc object + * @value: pointer to the value which needs to be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_is_ap_obss_prot_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_rts_threshold() - Get the RTS threshold config + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_rts_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_set_rts_threshold() - Set the RTS threshold config + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_rts_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * wlan_mlme_get_frag_threshold() - Get the Fragmentation threshold + * config + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_frag_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_set_frag_threshold() - Set the Fragmentation threshold + * config + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_frag_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * wlan_mlme_get_fils_enabled_info() - Get the fils enable info for driver + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_fils_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value); +/** + * wlan_mlme_set_fils_enabled_info() - Set the fils enable info for driver + * @psoc: pointer to psoc object + * @value: value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_fils_enabled_info(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_set_primary_interface() - Set the primary iface id for driver + * @psoc: pointer to psoc object + * @value: value that needs to be set from the caller + * + * When a vdev is set as primary then based on the dual sta policy + * "qca_wlan_concurrent_sta_policy_config" mcc preference and roaming has + * to be enabled on the primary vdev + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_primary_interface(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_set_default_primary_iface() - Set the default primary iface id + * for driver + * @psoc: pointer to psoc object + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_default_primary_iface(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_is_primary_interface_configured() - Check if primary iface is set + * @psoc: pointer to psoc object + * + * Check if primary iface is configured from userspace through vendor command. + * Return true if it's configured. If it's not configured, default value would + * be 0xFF and return false then. + * + * Return: True or False + */ +bool wlan_mlme_is_primary_interface_configured(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_peer_get_assoc_rsp_ies() - Get the assoc response IEs of peer + * @peer: WLAN peer objmgr + * @ie_buf: Pointer to IE buffer + * @ie_len: Length of the IE buffer + * + * Get the pointer to assoc response IEs of the peer from MLME + * and length of the IE buffer. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_peer_get_assoc_rsp_ies(struct wlan_objmgr_peer *peer, + const uint8_t **ie_buf, + size_t *ie_len); + +/** + * wlan_mlme_get_mcc_duty_cycle_percentage() - Get primary STA iface duty + * cycle percentage + * @pdev: pointer to pdev object + * + * API to get the MCC duty cycle for primary and secondary STA's + * + * Return: primary iface quota on success + */ +int wlan_mlme_get_mcc_duty_cycle_percentage(struct wlan_objmgr_pdev *pdev); + +/** + * wlan_mlme_get_tl_delayed_trgr_frm_int() - Get delay interval(in ms) + * of UAPSD auto trigger + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: None + */ +void wlan_mlme_get_tl_delayed_trgr_frm_int(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_dir_ac_vi() - Get TSPEC direction + * for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_vi(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +/** + * wlan_mlme_get_wmm_nom_msdu_size_ac_vi() - Get normal + * MSDU size for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_vi(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_wmm_mean_data_rate_ac_vi() - mean data + * rate for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_mean_data_rate_ac_vi(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_min_phy_rate_ac_vi() - min PHY + * rate for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_vi(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_sba_ac_vi() - surplus bandwidth + * allowance for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_vi(struct wlan_objmgr_psoc *psoc, uint16_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_vi_srv_intv() - Get Uapsd service + * interval for video + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_vi_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_vi_sus_intv() - Get Uapsd suspension + * interval for video + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_vi_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_dir_ac_be() - Get TSPEC direction + * for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_be(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_wmm_nom_msdu_size_ac_be() - Get normal + * MSDU size for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_be(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_wmm_mean_data_rate_ac_be() - mean data + * rate for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_mean_data_rate_ac_be(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_min_phy_rate_ac_be() - min PHY + * rate for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_be(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_sba_ac_be() - surplus bandwidth + * allowance for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_be(struct wlan_objmgr_psoc *psoc, uint16_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_be_srv_intv() - Get Uapsd service + * interval for BE + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_be_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_be_sus_intv() - Get Uapsd suspension + * interval for BE + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_be_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_dir_ac_bk() - Get TSPEC direction + * for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_bk(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +/** + * wlan_mlme_get_wmm_nom_msdu_size_ac_bk() - Get normal + * MSDU size for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_bk(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_wmm_mean_data_rate_ac_bk() - mean data + * rate for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_mean_data_rate_ac_bk(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_min_phy_rate_ac_bk() - min PHY + * rate for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_bk(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_sba_ac_bk() - surplus bandwidth + * allowance for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_bk(struct wlan_objmgr_psoc *psoc, uint16_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_bk_srv_intv() - Get Uapsd service + * interval for BK + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_bk_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_bk_sus_intv() - Get Uapsd suspension + * interval for BK + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_bk_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_mode() - Enable WMM feature + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_mode(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +/** + * wlan_mlme_get_80211e_is_enabled() - Enable 802.11e feature + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_80211e_is_enabled(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_wmm_uapsd_mask() - setup U-APSD mask for ACs + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_mask(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +#ifdef FEATURE_WLAN_ESE +/** + * wlan_mlme_get_inactivity_interval() - Infra Inactivity Interval + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: None + */ +void +wlan_mlme_get_inactivity_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value); +#endif + +/** + * wlan_mlme_get_is_ts_burst_size_enable() - Get TS burst size flag + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: None + */ +void wlan_mlme_get_is_ts_burst_size_enable(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_ts_info_ack_policy() - Get TS ack policy + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: None + */ +void wlan_mlme_get_ts_info_ack_policy(struct wlan_objmgr_psoc *psoc, + enum mlme_ts_info_ack_policy *value); + +/** + * wlan_mlme_get_ts_acm_value_for_ac() - Get ACM value for AC + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_ts_acm_value_for_ac(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_wmm_dir_ac_vo() - Get TSPEC direction + * for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_vo(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +/** + * wlan_mlme_get_wmm_nom_msdu_size_ac_vo() - Get normal + * MSDU size for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_vo(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_wmm_mean_data_rate_ac_vo() - mean data rate for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_mean_data_rate_ac_vo(struct wlan_objmgr_psoc *psoc, + uint32_t *value); +/** + * wlan_mlme_get_wmm_min_phy_rate_ac_vo() - min PHY + * rate for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_vo(struct wlan_objmgr_psoc *psoc, + uint32_t *value); +/** + * wlan_mlme_get_wmm_sba_ac_vo() - surplus bandwidth allowance for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_vo(struct wlan_objmgr_psoc *psoc, uint16_t *value); + +/** + * wlan_mlme_set_enable_bcast_probe_rsp() - Set enable bcast probe resp info + * @psoc: pointer to psoc object + * @value: value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_enable_bcast_probe_rsp(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_get_wmm_uapsd_vo_srv_intv() - Get Uapsd service + * interval for voice + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_vo_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_wmm_uapsd_vo_sus_intv() - Get Uapsd suspension + * interval for voice + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_wmm_uapsd_vo_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_cfg_get_vht_max_mpdu_len() - gets vht max mpdu length from cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_max_mpdu_len(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_set_vht_max_mpdu_len() - sets vht max mpdu length into cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_max_mpdu_len(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_cfg_get_ht_smps() - gets HT SM Power Save mode from cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_ht_smps(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_get_vht_chan_width() - gets vht supported channel width from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_chan_width(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_set_vht_chan_width() - sets vht supported channel width into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_set_vht_chan_width(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_cfg_get_vht_chan_width() - sets vht supported channel width into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_chan_width(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_get_vht_ldpc_coding_cap() - gets vht ldpc coding cap from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_ldpc_coding_cap(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_cfg_set_vht_ldpc_coding_cap() - sets vht ldpc coding cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_set_vht_ldpc_coding_cap(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_cfg_get_vht_short_gi_80mhz() - gets vht short gi 80MHz from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_short_gi_80mhz(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_cfg_set_vht_short_gi_80mhz() - sets vht short gi 80MHz into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_set_vht_short_gi_80mhz(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_cfg_get_short_gi_160_mhz() - gets vht short gi 160MHz from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_short_gi_160_mhz(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_short_gi_160_mhz() - sets vht short gi 160MHz into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_short_gi_160_mhz(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_get_vht_tx_stbc() - gets vht tx stbc from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_tx_stbc(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_get_vht_rx_stbc() - gets vht rx stbc from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_rx_stbc(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_vht_tx_stbc() - sets vht tx stbc into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_tx_stbc(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_get_vht_rx_stbc() - gets vht rx stbc from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_rx_stbc(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_vht_rx_stbc() - sets vht rx stbc into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_rx_stbc(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_get_vht_su_bformer() - gets vht su beam former cap from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_su_bformer(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_vht_su_bformer() - sets vht su beam former cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_su_bformer(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_set_vht_su_bformee() - sets vht su beam formee cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_su_bformee(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_set_vht_tx_bfee_ant_supp() - sets vht Beamformee antenna + * support cap + * into cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_set_vht_tx_bfee_ant_supp(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_cfg_get_vht_tx_bfee_ant_supp() - Gets vht Beamformee antenna + * support cap into cfg item + * + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_tx_bfee_ant_supp(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_set_vht_num_sounding_dim() - sets vht no of sounding dimensions + * into cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_set_vht_num_sounding_dim(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_cfg_get_vht_mu_bformer() - gets vht mu beam former cap from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_mu_bformer(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_vht_mu_bformer() - sets vht mu beam former cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_mu_bformer(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_get_vht_mu_bformee() - gets vht mu beam formee cap from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_mu_bformee(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_vht_mu_bformee() - sets vht mu beam formee cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_mu_bformee(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_get_vht_txop_ps() - gets vht tx ops ps cap from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_txop_ps(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_cfg_set_vht_txop_ps() - sets vht tx ops ps cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_txop_ps(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_cfg_get_vht_ampdu_len_exp() - gets vht max AMPDU length exponent from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_ampdu_len_exp(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_cfg_set_vht_ampdu_len_exp() - sets vht max AMPDU length exponent into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_ampdu_len_exp(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_cfg_get_vht_rx_mcs_map() - gets vht rx mcs map from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_rx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_cfg_set_vht_rx_mcs_map() - sets rx mcs map into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_rx_mcs_map(struct wlan_objmgr_psoc *psoc, uint32_t value); + +/** + * wlan_mlme_cfg_get_vht_tx_mcs_map() - gets vht tx mcs map from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_get_vht_tx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_cfg_set_vht_tx_mcs_map() - sets tx mcs map into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_cfg_set_vht_tx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * wlan_mlme_cfg_set_vht_rx_supp_data_rate() - sets rx supported data rate into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_rx_supp_data_rate(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * wlan_mlme_cfg_set_vht_tx_supp_data_rate() - sets tx supported data rate into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_tx_supp_data_rate(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * wlan_mlme_cfg_get_vht_basic_mcs_set() - gets basic mcs set from + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_get_vht_basic_mcs_set(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_cfg_set_vht_basic_mcs_set() - sets basic mcs set into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_cfg_set_vht_basic_mcs_set(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * wlan_mlme_get_vht_enable_tx_bf() - Get vht enable tx bf + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_enable_tx_bf(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_vht_tx_su_beamformer() - VHT enable tx su beamformer + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_tx_su_beamformer(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_vht_channel_width() - gets Channel width capability + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_get_vht_channel_width(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_vht_rx_mcs_8_9() - VHT Rx MCS capability for 1x1 mode + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_get_vht_rx_mcs_8_9(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_vht_tx_mcs_8_9() - VHT Tx MCS capability for 1x1 mode + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_tx_mcs_8_9(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +/** + * wlan_mlme_get_vht_rx_mcs_2x2() - VHT Rx MCS capability for 2x2 mode + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_get_vht_rx_mcs_2x2(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_vht_tx_mcs_2x2() - VHT Tx MCS capability for 2x2 mode + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_get_vht_tx_mcs_2x2(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_vht20_mcs9() - Enables VHT MCS9 in 20M BW operation + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht20_mcs9(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_srd_master_mode_for_vdev - Get SRD master mode for vdev + * @psoc: pointer to psoc object + * @vdev_opmode: vdev operating mode + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value); + +/** + * wlan_mlme_get_indoor_support_for_nan - Get indoor channel support for NAN + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_indoor_support_for_nan(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_force_sap_enabled() - Get the value of force SAP enabled + * @psoc: psoc context + * @value: data to get + * + * Get the value of force SAP enabled + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_force_sap_enabled(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_enable_dynamic_nss_chains_cfg() - API to get whether dynamic + * nss and chain config is enabled or not + * @psoc: psoc context + * @value: data to be set + * + * API to get whether dynamic nss and chain config is enabled or not + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_enable_dynamic_nss_chains_cfg(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_restart_sap_on_dynamic_nss_chains_cfg() - API to get whether + * SAP needs to be restarted or not on dynamic nss chain config + * @psoc: psoc context + * @value: data to be set + * + * API to get whether SAP needs to be restarted or not on dynamic nss chain + * config + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_get_restart_sap_on_dynamic_nss_chains_cfg( + struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_cfg_set_dynamic_nss_chains_support() - API to update + * dynamic_nss_chains_support + * + * @psoc: psoc context + * @value: data to be set + * + * API to update dynamic_nss_chains_support in wlan_mlme_cfg object to + * maintain this value in mlme context + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_cfg_set_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_cfg_get_dynamic_nss_chains_support() - API to get current value of + * dynamic_nss_chains_support + * + * @psoc: psoc context + * @value: data to be set + * + * API to get current value of dynamic_nss_chains_support + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +QDF_STATUS +wlan_mlme_cfg_get_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_vht_enable2x2() - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_set_vht_enable2x2() - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_get_vht_enable_paid() - Enables/disables paid feature + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_enable_paid(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_vht_enable_gid() - Enables/disables VHT GID feature + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_enable_gid(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_get_vht_for_24ghz() - Enables/disables VHT for 24 ghz + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_set_vht_for_24ghz() - Enables/disables VHT for 24 ghz + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_get_vendor_vht_for_24ghz() - nables/disables vendor VHT for 24 ghz + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_vendor_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * mlme_update_vht_cap() - update vht capabilities + * @psoc: psoc context + * @cfg: data to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_update_vht_cap(struct wlan_objmgr_psoc *psoc, struct wma_tgt_vht_cap *cfg); + +/** + * mlme_update_nss_vht_cap() - Update the number of spatial + * streams supported for vht + * @psoc: psoc context + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_update_nss_vht_cap(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_11BE +/** + * mlme_get_bss_11be_allowed() - Check BSS allowed in 11be mode + * @psoc: psoc context + * @bssid: bssid + * @ie_data: ie data + * @ie_length: ie data length + * + * Return: true if AP in 11be oui allow list + */ +bool mlme_get_bss_11be_allowed(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *ie_data, + uint32_t ie_length); + +/** + * wlan_mlme_get_oem_eht_mlo_config() - Get the OEM EHT configuration. + * @psoc: PSOC object manager. + * @oem_eht_cfg: Pointer to fill OEM cfg + * + * Returns success of retrieving OEM cfg else failure. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wlan_mlme_get_oem_eht_mlo_config(struct wlan_objmgr_psoc *psoc, + uint32_t *oem_eht_cfg); +#else +static inline +bool mlme_get_bss_11be_allowed(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *ie_data, + uint32_t ie_length) +{ + return false; +} + +static inline QDF_STATUS +wlan_mlme_get_oem_eht_mlo_config(struct wlan_objmgr_psoc *psoc, + uint32_t *oem_eht_cfg) +{ + *oem_eht_cfg = 0x0; + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_mlme_is_sap_uapsd_enabled() - Get if SAP UAPSD is enabled/disabled + * @psoc: psoc context + * @value: value to be filled for caller + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_is_sap_uapsd_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_set_sap_uapsd_flag() - Enable/Disable SAP UAPSD + * @psoc: psoc context + * @value: Enable/Disable control value for sap_uapsd_enabled field + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_set_sap_uapsd_flag(struct wlan_objmgr_psoc *psoc, + bool value); +/** + * wlan_mlme_is_11h_enabled() - Get the 11h flag + * @psoc: psoc context + * @value: Enable/Disable value ptr. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_is_11h_enabled(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_set_11h_enabled() - Set the 11h flag + * @psoc: psoc context + * @value: Enable/Disable value + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_11h_enabled(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_is_11d_enabled() - Get the 11d flag + * @psoc: psoc context + * @value: Enable/Disable value ptr. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_is_11d_enabled(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_set_11d_enabled() - Set the 11h flag + * @psoc: psoc context + * @value: Enable/Disable value + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_11d_enabled(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_is_rf_test_mode_enabled() - Get the rf test mode flag + * @psoc: psoc context + * @value: Enable/Disable value ptr. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_is_rf_test_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_set_rf_test_mode_enabled() - Set the rf test mode flag + * @psoc: psoc context + * @value: Enable/Disable value. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_rf_test_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value); + +#ifdef CONFIG_BAND_6GHZ +/** + * wlan_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled() - Get the disable vlp + * STA conn to SP AP flag + * @psoc: psoc context + * @value: Enable/Disable value ptr. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled( + struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_is_standard_6ghz_conn_policy_enabled() - Get the 6 GHz standard + * connection policy flag + * @psoc: psoc context + * @value: Enable/Disable value ptr. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_is_standard_6ghz_conn_policy_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +#else +static inline QDF_STATUS +wlan_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled( + struct wlan_objmgr_psoc *psoc, + bool *value) +{ + *value = false; + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_is_standard_6ghz_conn_policy_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + *value = false; + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_mlme_get_eht_mode() - Get the EHT mode of operations + * @psoc: psoc context + * @value: EHT mode value ptr + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_eht_mode(struct wlan_objmgr_psoc *psoc, + enum wlan_eht_mode *value); + +/** + * wlan_mlme_set_eht_mode() - Set the EHT mode of operation + * @psoc: psoc context + * @value: EHT mode value + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode value); + +/** + * wlan_mlme_get_emlsr_mode_enabled() - Get the eMLSR mode flag + * @psoc: psoc context + * @value: Enable/Disable value ptr. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * wlan_mlme_set_emlsr_mode_enabled() - Set the eMLSR mode flag + * @psoc: psoc context + * @value: Enable/Disable value. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_set_eml_params() - Set EML subfields in psoc mlme obj that + * are received from FW + * @psoc: psoc context + * @cap: psoc mac/phy capability ptr + * + * Return: none + */ +void +wlan_mlme_set_eml_params(struct wlan_objmgr_psoc *psoc, + struct wlan_psoc_host_mac_phy_caps_ext2 *cap); + +/** + * wlan_mlme_get_eml_params() - Get EML subfields from psoc mlme obj + * @psoc: psoc context + * @cap: EML capability subfield ptr + * + * Return: none + */ +void +wlan_mlme_get_eml_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlo_eml_cap *cap); + +/** + * wlan_mlme_cfg_set_emlsr_pad_delay() - Configure EMLSR padding delay subfield + * @psoc: psoc context + * @val: EMLSR padding delay subfield value + * + * API to configure EMLSR padding delay subfield in psoc mlme obj with user + * requested value if it greater than the value configured by FW during boot-up. + * + * Return: none + */ +void +wlan_mlme_cfg_set_emlsr_pad_delay(struct wlan_objmgr_psoc *psoc, uint8_t val); + +/** + * wlan_mlme_get_t2lm_negotiation_supported() - Get the T2LM + * negotiation supported value + * @psoc: psoc context + * + * Return: t2lm negotiation supported value + */ +enum t2lm_negotiation_support +wlan_mlme_get_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_t2lm_negotiation_supported() - Set the T2LM + * negotiation supported value + * @psoc: psoc context + * @value: t2lm negotiation supported value + * + * Return: qdf status + */ +QDF_STATUS +wlan_mlme_set_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_get_eht_mld_id() - Get the MLD ID of the requested BSS + * @psoc: psoc context + * + * Return: MLD ID of the requested BSS + */ +uint8_t +wlan_mlme_get_eht_mld_id(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_eht_mld_id() - Set MLD ID of the requested BSS information + * within the ML probe request. + * @psoc: psoc context + * @value: MLD ID + * + * Return: qdf status + */ +QDF_STATUS +wlan_mlme_set_eht_mld_id(struct wlan_objmgr_psoc *psoc, uint8_t value); + +/* + * wlan_mlme_get_mlo_prefer_percentage() - get MLO preference percentage + * @psoc: pointer to psoc object + * + * Return: void + */ +void +wlan_mlme_get_mlo_prefer_percentage( + struct wlan_objmgr_psoc *psoc, + int8_t *mlo_prefer_percentage); +#else +static inline QDF_STATUS +wlan_mlme_get_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode *value) +{ + *value = WLAN_EHT_MODE_DISABLED; + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_set_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_get_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + *value = false; + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_set_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +wlan_mlme_set_eml_params(struct wlan_objmgr_psoc *psoc, + struct wlan_psoc_host_mac_phy_caps_ext2 *cap) +{ +} + +static inline void +wlan_mlme_get_eml_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlo_eml_cap *cap) +{ +} + +static inline void +wlan_mlme_cfg_set_emlsr_pad_delay(struct wlan_objmgr_psoc *psoc, uint8_t val) +{ +} + +static inline enum t2lm_negotiation_support +wlan_mlme_get_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc) +{ + return T2LM_NEGOTIATION_DISABLED; +} + +static inline QDF_STATUS +wlan_mlme_set_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +wlan_mlme_get_mlo_prefer_percentage( + struct wlan_objmgr_psoc *psoc, + int8_t *mlo_prefer_percentage) +{} +#endif + +/** + * wlan_mlme_set_btm_abridge_flag() - Set BTM abridge flag + * @psoc: psoc context + * @value: abridge flag + * + * Return: qdf status + * + * BTM abridge flag indicates whether to select candidates + * for BTM roam based on score. + */ +QDF_STATUS +wlan_mlme_set_btm_abridge_flag(struct wlan_objmgr_psoc *psoc, bool value); + +/** + * wlan_mlme_get_btm_abridge_flag() - Get BTM abridge flag + * @psoc: psoc context + * + * Return: abridge flag + * + * BTM abridge flag indicates whether to select candidates + * for BTM roam based on score. + */ +bool +wlan_mlme_get_btm_abridge_flag(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_sta_miracast_mcc_rest_time() - Get STA/MIRACAST MCC rest time + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * This API gives rest time to be used when STA and MIRACAST MCC conc happens + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_sta_miracast_mcc_rest_time(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_max_modulated_dtim_ms() - get the max modulated dtim in ms + * restart + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_max_modulated_dtim_ms(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * wlan_mlme_get_scan_probe_unicast_ra() - Get scan probe unicast RA cfg + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * This API gives scan probe request with unicast RA user config + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_set_scan_probe_unicast_ra() - Set scan probe unicast RA cfg + * @psoc: pointer to psoc object + * @value: set value + * + * This API sets scan probe request with unicast RA user config + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * wlan_mlme_get_sap_mcc_chnl_avoid() - Check if SAP MCC needs to be avoided + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * This API fetches the user setting to determine if SAP MCC with other persona + * to be avoided. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_sap_mcc_chnl_avoid(struct wlan_objmgr_psoc *psoc, + uint8_t *value); +/** + * wlan_mlme_get_mcc_bcast_prob_resp() - Get broadcast probe rsp in MCC + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * To get INI value which helps to determe whether to enable/disable use of + * broadcast probe response to increase the detectability of SAP in MCC mode. + * + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_mcc_bcast_prob_resp(struct wlan_objmgr_psoc *psoc, + uint8_t *value); +/** + * wlan_mlme_get_mcc_rts_cts_prot() - To get RTS-CTS protection in MCC. + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * To get INI value which helps to determine whether to enable/disable + * use of long duration RTS-CTS protection when SAP goes off + * channel in MCC mode. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_mcc_rts_cts_prot(struct wlan_objmgr_psoc *psoc, + uint8_t *value); +/** + * wlan_mlme_get_mcc_feature() - To find out to enable/disable MCC feature + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * To get INI value which helps to determine whether to enable MCC feature + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_mcc_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * wlan_mlme_get_rrm_enabled() - Get the RRM enabled ini + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_rrm_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_dtim_selection_diversity() - get dtim selection diversity + * bitmap + * @psoc: pointer to psoc object + * @dtim_selection_div: value that is requested by the caller + * This function gets the dtim selection diversity bitmap to be + * sent to the firmware + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_get_dtim_selection_diversity(struct wlan_objmgr_psoc *psoc, + uint32_t *dtim_selection_div); + +/** + * wlan_mlme_get_bmps_min_listen_interval() - get beacon mode powersave + * minimum listen interval value + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_get_bmps_min_listen_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_bmps_max_listen_interval() - get beacon mode powersave + * maximum listen interval value + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_get_bmps_max_listen_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_auto_bmps_timer_value() - get bmps timer value + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_get_auto_bmps_timer_value(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_is_bmps_enabled() - check if beacon mode powersave is + * enabled/disabled + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_is_bmps_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_override_bmps_imps() - disable imps/bmps + * @psoc: pointer to psoc object + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_override_bmps_imps(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_is_imps_enabled() - check if idle mode powersave is + * enabled/disabled + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_mlme_is_imps_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_wps_uuid() - get the wps uuid string + * @wps_params: pointer to mlme wps parameters structure + * @data: data to which the parameter is to be copied + * + * Return None + * + */ +void +wlan_mlme_get_wps_uuid(struct wlan_mlme_wps_params *wps_params, uint8_t *data); + +/** + * wlan_mlme_get_self_gen_frm_pwr() - get self gen frm pwr + * @psoc: pointer to psoc object + * @value: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_self_gen_frm_pwr(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_get_4way_hs_offload() - get 4-way hs offload to fw cfg + * @psoc: pointer to psoc object + * @value: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_4way_hs_offload(struct wlan_objmgr_psoc *psoc, uint32_t *value); + +/** + * wlan_mlme_get_bmiss_skip_full_scan_value() - To get value of + * bmiss_skip_full_scan ini + * @psoc: pointer to psoc object + * @value: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bmiss_skip_full_scan_value(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * mlme_get_peer_phymode() - get phymode of peer + * @psoc: pointer to psoc object + * @mac: Pointer to the mac addr of the peer + * @peer_phymode: phymode + * + * Return: QDF Status + */ +QDF_STATUS +mlme_get_peer_phymode(struct wlan_objmgr_psoc *psoc, uint8_t *mac, + enum wlan_phymode *peer_phymode); + +/** + * mlme_set_tgt_wpa3_roam_cap() - Set the target WPA3 roam support + * to mlme + * @psoc: pointer to PSOC object + * @akm_bitmap: Bitmap of akm suites supported for roaming by the firmware + * + * Return: QDF Status + */ +QDF_STATUS mlme_set_tgt_wpa3_roam_cap(struct wlan_objmgr_psoc *psoc, + uint32_t akm_bitmap); +/** + * wlan_mlme_get_ignore_fw_reg_offload_ind() - Get the + * ignore_fw_reg_offload_ind ini + * @psoc: pointer to psoc object + * @disabled: output pointer to hold user config + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_ignore_fw_reg_offload_ind(struct wlan_objmgr_psoc *psoc, + bool *disabled); + +/** + * mlme_get_roam_trigger_str() - Get the string for enum + * WMI_ROAM_TRIGGER_REASON_ID reason. + * @roam_scan_trigger: roam scan trigger ID + * + * Return: Meaningful string from enum WMI_ROAM_TRIGGER_REASON_ID + */ +char *mlme_get_roam_trigger_str(uint32_t roam_scan_trigger); + +/** + * mlme_get_roam_status_str() - Get the string for roam status + * @roam_status: roam status coming from fw via + * wmi_roam_scan_info tlv + * + * Return: Meaningful string for roam status + */ +char *mlme_get_roam_status_str(uint32_t roam_status); + +/** + * mlme_get_converted_timestamp() - Return time of the day + * from timestamp + * @timestamp: Timestamp value in milliseconds + * @time: Output buffer to fill time into + * + * Return: Time of the day in [HH:MM:SS.uS] + */ +void mlme_get_converted_timestamp(uint32_t timestamp, char *time); + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * wlan_mlme_set_sae_single_pmk_bss_cap - API to set WPA3 single pmk AP IE + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * @val: value to be set + * + * Return : None + */ +void wlan_mlme_set_sae_single_pmk_bss_cap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool val); + +/** + * wlan_mlme_update_sae_single_pmk - API to update mlme_pmkid_info + * @vdev: vdev object + * @sae_single_pmk: pointer to sae_single_pmk_info struct + * + * Return : None + */ +void +wlan_mlme_update_sae_single_pmk(struct wlan_objmgr_vdev *vdev, + struct mlme_pmk_info *sae_single_pmk); + +/** + * wlan_mlme_get_sae_single_pmk_info - API to get mlme_pmkid_info + * @vdev: vdev object + * @pmksa: pointer to PMKSA struct + * + * Return : None + */ +void +wlan_mlme_get_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_sae_single_pmk *pmksa); + +/** + * wlan_mlme_is_sae_single_pmk_enabled() - Get is SAE single pmk feature enabled + * @psoc: Pointer to Global psoc + * + * Return: True if SAE single PMK is enabled + */ +bool wlan_mlme_is_sae_single_pmk_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_clear_sae_single_pmk_info - API to clear mlme_pmkid_info ap caps + * @vdev: vdev object + * @pmk : pmk info to clear + * + * Return : None + */ +void wlan_mlme_clear_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct mlme_pmk_info *pmk); +#else +static inline void +wlan_mlme_set_sae_single_pmk_bss_cap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool val) +{ +} + +static inline +bool wlan_mlme_is_sae_single_pmk_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline void +wlan_mlme_update_sae_single_pmk(struct wlan_objmgr_vdev *vdev, + struct mlme_pmk_info *sae_single_pmk) +{ +} + +static inline void +wlan_mlme_get_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_sae_single_pmk *pmksa) +{ +} + +static inline +void wlan_mlme_clear_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct mlme_pmk_info *pmk) +{ +} +#endif + +/** + * mlme_get_roam_fail_reason_str() - Get fail string from enum + * WMI_ROAM_FAIL_REASON_ID + * @result: Roam fail reason + * + * Return: Meaningful string from enum + */ +char *mlme_get_roam_fail_reason_str(uint32_t result); + +/** + * mlme_get_sub_reason_str() - Get roam trigger sub reason from enum + * WMI_ROAM_TRIGGER_SUB_REASON_ID + * @sub_reason: Sub reason value + * + * Return: Meaningful string from enum WMI_ROAM_TRIGGER_SUB_REASON_ID + */ +char *mlme_get_sub_reason_str(uint32_t sub_reason); + +/** + * wlan_mlme_get_mgmt_max_retry() - Get the + * max mgmt retry + * @psoc: pointer to psoc object + * @max_retry: output pointer to hold user config + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mgmt_max_retry(struct wlan_objmgr_psoc *psoc, + uint8_t *max_retry); + +/** + * wlan_mlme_get_mgmt_6ghz_rate_support() - Get status of HE rates for + * 6GHz mgmt frames + * @psoc: pointer to psoc object + * @enable_he_mcs0_for_6ghz_mgmt: pointer to check for HE rates support + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mgmt_6ghz_rate_support(struct wlan_objmgr_psoc *psoc, + bool *enable_he_mcs0_for_6ghz_mgmt); + +/** + * wlan_mlme_get_status_ring_buffer() - Get the + * status of ring buffer + * @psoc: pointer to psoc object + * @enable_ring_buffer: output pointer to point the configured value of + * ring buffer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_status_ring_buffer(struct wlan_objmgr_psoc *psoc, + bool *enable_ring_buffer); + +/** + * wlan_mlme_get_peer_unmap_conf() - Indicate if peer unmap confirmation + * support is enabled or disabled + * @psoc: pointer to psoc object + * + * Return: true if peer unmap confirmation support is enabled, else false + */ +bool wlan_mlme_get_peer_unmap_conf(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_mlme_get_roam_reason_vsie_status() - Indicate if roam reason + * vsie is enabled or disabled + * @psoc: pointer to psoc object + * @roam_reason_vsie_enabled: pointer to hold value of roam reason + * vsie + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t *roam_reason_vsie_enabled); + +/** + * wlan_mlme_set_roam_reason_vsie_status() - Update roam reason vsie status + * @psoc: pointer to psoc object + * @roam_reason_vsie_enabled: value of roam reason vsie + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t roam_reason_vsie_enabled); + +/** + * wlan_mlme_get_roaming_triggers - Get the roaming triggers bitmap + * @psoc: Pointer to PSOC object + * + * Return: Roaming triggers value + */ +uint32_t wlan_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_roaming_triggers() - Set the roaming triggers bitmap + * @psoc: Pointer to PSOC object + * @trigger_bitmap: Roaming triggers bitmap to set + * + * Return: void + */ +void wlan_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc, + uint32_t trigger_bitmap); + +/** + * wlan_mlme_get_roaming_offload() - Get roaming offload setting + * @psoc: pointer to psoc object + * @val: Pointer to enable/disable roaming offload + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * wlan_mlme_get_enable_disconnect_roam_offload() - Get emergency roaming + * Enable/Disable status during deauth/disassoc + * @psoc: pointer to psoc object + * @val: Pointer to emergency roaming Enable/Disable status + * during deauth/disassoc + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_enable_disconnect_roam_offload(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * wlan_mlme_get_enable_idle_roam() - Get Enable/Disable idle roaming status + * @psoc: pointer to psoc object + * @val: Pointer to Enable/Disable idle roaming status + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_enable_idle_roam(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_mlme_get_idle_roam_rssi_delta() - Get idle roam rssi delta + * @psoc: pointer to psoc object + * @val: Pointer to idle roam rssi delta + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_idle_roam_rssi_delta(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * wlan_mlme_get_roam_info_stats_num() - Get roam information statistics number + * @psoc: pointer to psoc object + * @val: Pointer to roam_info_stats_num + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_roam_info_stats_num(struct wlan_objmgr_psoc *psoc, uint32_t *val); + +/** + * wlan_mlme_get_idle_roam_inactive_time() - Get idle roam inactive time + * @psoc: pointer to psoc object + * @val: Pointer to idle roam inactive time + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_idle_roam_inactive_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val); +/** + * wlan_mlme_get_idle_data_packet_count() - Get idle data packet count + * @psoc: pointer to psoc object + * @val: Pointer to idle data packet count + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_idle_data_packet_count(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * wlan_mlme_get_idle_roam_min_rssi() - Get idle roam min rssi + * @psoc: pointer to psoc object + * @val: Pointer to idle roam min rssi + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_idle_roam_min_rssi(struct wlan_objmgr_psoc *psoc, uint32_t *val); + +/** + * wlan_mlme_get_idle_roam_band() - Get idle roam band + * @psoc: pointer to psoc object + * @val: Pointer to idle roam band + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_idle_roam_band(struct wlan_objmgr_psoc *psoc, uint32_t *val); + +/** + * wlan_mlme_get_self_bss_roam() - Get self bss roam enable status + * @psoc: pointer to psoc object + * @enable_self_bss_roam: Pointer to self bss roam enable status + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_self_bss_roam(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_self_bss_roam); +#else +static inline QDF_STATUS +wlan_mlme_get_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t *roam_reason_vsie_enable) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +wlan_mlme_set_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t roam_reason_vsie_enable) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +uint32_t wlan_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc) +{ + return 0xFFFF; +} + +static inline +void wlan_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc, + uint32_t trigger_bitmap) +{ +} + +static inline QDF_STATUS +wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_mlme_set_peer_indicated_ch_width() - Set peer indicated channel width + * @psoc: pointer to psoc object + * @data: Pointer to peer operating mode change event status + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc, + struct peer_oper_mode_event *data); + +/** + * wlan_mlme_get_peer_indicated_ch_width() - Get peer indicated channel width + * @psoc: pointer to psoc object + * @data: Pointer to peer operating mode change event status + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc, + struct peer_oper_mode_event *data); + +/** + * wlan_mlme_set_ft_over_ds() - Update ft_over_ds + * @psoc: pointer to psoc object + * @ft_over_ds_enable: value of ft_over_ds + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_mlme_set_ft_over_ds(struct wlan_objmgr_psoc *psoc, + uint8_t ft_over_ds_enable); +/** + * wlan_mlme_get_dfs_chan_ageout_time() - Get the DFS Channel ageout time + * @psoc: pointer to psoc object + * @dfs_chan_ageout_time: output pointer to hold configured value of DFS + * Channel ageout time + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_dfs_chan_ageout_time(struct wlan_objmgr_psoc *psoc, + uint8_t *dfs_chan_ageout_time); + +#ifdef WLAN_FEATURE_SAE +/** + * wlan_mlme_get_sae_assoc_retry_count() - Get the sae assoc retry count + * @psoc: pointer to psoc object + * @retry_count: assoc retry count + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_sae_assoc_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count); +/** + * wlan_mlme_get_sae_auth_retry_count() - Get the sae auth retry count + * @psoc: pointer to psoc object + * @retry_count: auth retry count + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_sae_auth_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count); + +/** + * wlan_mlme_get_sae_roam_auth_retry_count() - Get the sae roam auth retry count + * @psoc: pointer to psoc object + * @retry_count: auth retry count + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_sae_roam_auth_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count); + +#else +static inline QDF_STATUS +wlan_mlme_get_sae_assoc_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count) +{ + *retry_count = 0; + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_get_sae_auth_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count) +{ + *retry_count = 0; + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_get_sae_roam_auth_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count) +{ + *retry_count = 0; + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_mlme_get_dual_sta_roaming_enabled - API to get if the dual sta + * roaming support is enabled. + * @psoc: Pointer to global psoc object + * + * Return: True if dual sta roaming feature is enabled else return false + */ +bool +wlan_mlme_get_dual_sta_roaming_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +wlan_mlme_get_dual_sta_roaming_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * mlme_store_fw_scan_channels - Update the valid channel list to mlme. + * @psoc: Pointer to global psoc object + * @chan_list: Source channel list pointer + * + * Currently the channel list is saved to wma_handle to be updated in the + * PCL command. This cannot be accessed at target_if while sending vdev + * set pcl command. So save the channel list to mlme. + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlme_store_fw_scan_channels(struct wlan_objmgr_psoc *psoc, + tSirUpdateChanList *chan_list); + +/** + * mlme_get_fw_scan_channels - Copy the saved valid channel + * list to the provided buffer + * @psoc: Pointer to global psoc object + * @freq_list: Pointer to the frequency list buffer to be filled + * @saved_num_chan: Number of channels filled + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_get_fw_scan_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *freq_list, + uint8_t *saved_num_chan); +/** + * wlan_mlme_get_roam_scan_offload_enabled() - Roam scan offload enable or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_roam_scan_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * wlan_mlme_get_roam_bmiss_final_bcnt() - Get roam bmiss final count + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_roam_bmiss_final_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * wlan_mlme_get_roam_bmiss_first_bcnt() - Get roam bmiss first count + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_roam_bmiss_first_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * wlan_mlme_get_bmiss_timeout_on_wakeup() - Get bmiss timeout + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bmiss_timeout_on_wakeup(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * wlan_mlme_get_bmiss_timeout_on_sleep() - Get roam conbmiss timeout + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bmiss_timeout_on_sleep(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * wlan_mlme_adaptive_11r_enabled() - check if adaptive 11r feature is enaled + * or not + * @psoc: pointer to psoc object + * + * Return: bool + */ +#ifdef WLAN_ADAPTIVE_11R +bool wlan_mlme_adaptive_11r_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool wlan_mlme_adaptive_11r_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * wlan_mlme_get_mawc_enabled() - Get mawc enabled status + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mawc_enabled(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_mlme_get_mawc_roam_enabled() - Get mawc roam enabled status + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mawc_roam_enabled(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_mlme_get_mawc_roam_traffic_threshold() - Get mawc traffic threshold + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mawc_roam_traffic_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * wlan_mlme_get_mawc_roam_ap_rssi_threshold() - Get AP RSSI threshold for + * MAWC roaming + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mawc_roam_ap_rssi_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * wlan_mlme_get_mawc_roam_rssi_high_adjust() - Get high adjustment value + * for suppressing scan + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mawc_roam_rssi_high_adjust(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * wlan_mlme_get_mawc_roam_rssi_low_adjust() - Get low adjustment value + * for suppressing scan + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_mawc_roam_rssi_low_adjust(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * wlan_mlme_get_bss_load_enabled() - Get bss load based roam trigger + * enabled status + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bss_load_enabled(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_mlme_get_bss_load_threshold() - Get bss load threshold + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bss_load_threshold(struct wlan_objmgr_psoc *psoc, uint32_t *val); + +/** + * wlan_mlme_get_bss_load_sample_time() - Get bss load sample time + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bss_load_sample_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * wlan_mlme_get_bss_load_rssi_threshold_6ghz() - Get bss load RSSI + * threshold on 6G + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bss_load_rssi_threshold_6ghz(struct wlan_objmgr_psoc *psoc, + int32_t *val); + +/** + * wlan_mlme_get_bss_load_rssi_threshold_5ghz() - Get bss load RSSI + * threshold on 5G + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bss_load_rssi_threshold_5ghz(struct wlan_objmgr_psoc *psoc, + int32_t *val); + +/** + * wlan_mlme_get_bss_load_rssi_threshold_24ghz() - Get bss load RSSI + * threshold on 2.4G + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_bss_load_rssi_threshold_24ghz(struct wlan_objmgr_psoc *psoc, + int32_t *val); +/** + * wlan_mlme_check_chan_param_has_dfs() - Get dfs flag based on + * channel & channel parameters + * @pdev: pdev object + * @ch_params: channel parameters + * @chan_freq: channel frequency in MHz + * + * Return: True for dfs + */ +bool +wlan_mlme_check_chan_param_has_dfs(struct wlan_objmgr_pdev *pdev, + struct ch_params *ch_params, + uint32_t chan_freq); + +/** + * wlan_mlme_set_usr_disabled_roaming() - Set user config for roaming disable + * @psoc: pointer to psoc object + * @val: user config for roaming disable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_set_usr_disabled_roaming(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * wlan_mlme_get_usr_disabled_roaming() - Get user config for roaming disable + * @psoc: pointer to psoc object + * @val: user config for roaming disable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_get_usr_disabled_roaming(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * mlme_get_opr_rate() - get operational rate + * @vdev: vdev pointer + * @dst: buffer to get rates set + * @len: length of the buffer + * + * Return: length of the rates set + */ +qdf_size_t mlme_get_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *dst, + qdf_size_t len); + +/** + * mlme_set_opr_rate() - set operational rate + * @vdev: vdev pointer + * @src: pointer to set operational rate + * @len: length of operational rate + * + * Return: QDF_SUCCESS if success + */ +QDF_STATUS mlme_set_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *src, + qdf_size_t len); + +/** + * mlme_get_ext_opr_rate() - get extended operational rate + * @vdev: vdev pointer + * @dst: buffer to get rates set + * @len: length of the buffer + * + * Return: length of the rates set + */ +qdf_size_t mlme_get_ext_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *dst, + qdf_size_t len); + +/** + * mlme_set_ext_opr_rate() - set extended operational rate + * @vdev: vdev pointer + * @src: pointer to set extended operational rate + * @len: length of extended operational rate + * + * Return: QDF_SUCCESS if success + */ +QDF_STATUS mlme_set_ext_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *src, + qdf_size_t len); + +/** + * mlme_clear_ext_opr_rate() - clear extended operational rate + * @vdev: vdev pointer + * + * Return: QDF_SUCCESS if success + */ +QDF_STATUS mlme_clear_ext_opr_rate(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_get_mcs_rate() - get MCS based rate + * @vdev: vdev pointer + * @dst: buffer to get rates set + * @len: length of the buffer + * + * Return: length of the rates set + */ +qdf_size_t mlme_get_mcs_rate(struct wlan_objmgr_vdev *vdev, uint8_t *dst, + qdf_size_t len); + +/** + * mlme_set_mcs_rate() - set MCS based rate + * @vdev: vdev pointer + * @src: pointer to set MCS based rate + * @len: length of MCS based rate + * + * Return: QDF_SUCCESS if success + */ +QDF_STATUS mlme_set_mcs_rate(struct wlan_objmgr_vdev *vdev, uint8_t *src, + qdf_size_t len); + +/** + * mlme_clear_mcs_rate() - clear MCS based rate + * @vdev: vdev pointer + * + * Return: QDF_SUCCESS if success + */ +QDF_STATUS mlme_clear_mcs_rate(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_is_sta_mon_conc_supported() - Check if STA + Monitor mode + * concurrency is supported + * @psoc: pointer to psoc object + * + * Return: True if supported + */ +bool wlan_mlme_is_sta_mon_conc_supported(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_phy_max_freq_range() - Get phy supported max channel + * frequency range + * @psoc: psoc for country information + * @low_2ghz_chan: 2.4 GHz low channel frequency + * @high_2ghz_chan: 2.4 GHz high channel frequency + * @low_5ghz_chan: 5 GHz low channel frequency + * @high_5ghz_chan: 5 GHz high channel frequency + * + * Return: QDF status + */ +QDF_STATUS wlan_mlme_get_phy_max_freq_range(struct wlan_objmgr_psoc *psoc, + uint32_t *low_2ghz_chan, + uint32_t *high_2ghz_chan, + uint32_t *low_5ghz_chan, + uint32_t *high_5ghz_chan); + +/** + * wlan_mlme_is_multipass_sap() -Get multipass sap support + * @psoc: psoc pointer + * + * Return: True, if FW support multipass support. + */ +bool wlan_mlme_is_multipass_sap(struct wlan_objmgr_psoc *psoc); + +#ifdef FEATURE_WDS +/** + * wlan_mlme_get_wds_mode() - Check wds mode supported + * @psoc: pointer to psoc object + * + * Return: supported wds mode + */ +enum wlan_wds_mode +wlan_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_wds_mode() - Set wds mode + * @psoc: pointer to psoc object + * @mode: wds mode to set + * + * Return: void + */ +void wlan_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc, + enum wlan_wds_mode mode); +#else +static inline enum wlan_wds_mode +wlan_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc) +{ + return WLAN_WDS_MODE_DISABLED; +} + +static inline void wlan_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc, + enum wlan_wds_mode mode) +{ +} +#endif + +#ifdef WLAN_SUPPORT_TWT +/** + * mlme_is_twt_enabled() - Get if TWT is enabled via ini. + * @psoc: pointer to psoc object + * + * Return: True if TWT is enabled else false. + */ +bool +mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /* WLAN_SUPPORT_TWT */ + +/** + * wlan_mlme_skip_tpe() - Get preference to not consider TPE in 2G/5G case + * + * @psoc: pointer to psoc object + * + * Return: True if host should not consider TPE IE in TX power calculation when + * operating in 2G/5G bands, false if host should always consider TPE IE values + */ +bool wlan_mlme_skip_tpe(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_is_data_stall_recovery_fw_supported() - Check if data stall + * recovery is supported by fw + * @psoc: pointer to psoc object + * + * Return: True if supported + */ +bool +wlan_mlme_is_data_stall_recovery_fw_supported(struct wlan_objmgr_psoc *psoc); + +/** + * mlme_cfg_get_orig_eht_caps() - Get the original EHT capability info + * @psoc: pointer to psoc object + * @eht_cap: Caps that needs to be filled. + * + * Return: QDF Status + */ +QDF_STATUS mlme_cfg_get_orig_eht_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEeht_cap *eht_cap); + +/** + * mlme_cfg_get_eht_caps() - Get the EHT capability info + * @psoc: pointer to psoc object + * @eht_cap: Caps that needs to be filled. + * + * Return: QDF Status + */ +QDF_STATUS mlme_cfg_get_eht_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEeht_cap *eht_cap); + +/** + * wlan_mlme_set_bt_profile_con() - Set bluetooth connection profile + * @psoc: pointer to psoc object + * @bt_profile_con: Bluetooth connection profile bit + * + * Return: None + */ +void +wlan_mlme_set_bt_profile_con(struct wlan_objmgr_psoc *psoc, + bool bt_profile_con); + +/** + * wlan_mlme_get_bt_profile_con() - Get Bluetooth connection profile + * @psoc: pointer to psoc object + * + * Return: Bluetooth connection profile + */ +bool +wlan_mlme_get_bt_profile_con(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_mlme_get_sta_mlo_conn_max_num() - get max number of links that sta mlo + * connection can support + * @psoc: pointer to psoc object + * + * Return: max number of links that sta mlo connection can support + */ +uint8_t wlan_mlme_get_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_is_5gl_5gh_mlsr_supported() - check 5GH_5GL MLSR supported + * @psoc: pointer to psoc object + * + * Return: true if 5GH_5GL MLSR supported otherwise false + */ +bool wlan_mlme_is_5gl_5gh_mlsr_supported(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_sta_mlo_conn_max_num() - set max number of links that sta mlo + * connection can support + * @psoc: pointer to psoc object + * @value: value to set + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_set_user_set_link_num() - set number of links that config by user + * @psoc: pointer to psoc object + * @value: value to set + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_set_ml_link_control_mode() - set ml_link_control_mode + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @value: value to set + * + * API get call when host receives vendor command + * QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE to configure link control mode. + * + * Return: none + */ +void wlan_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t value); + +/** + * wlan_mlme_get_ml_link_control_mode() - get ml_link_control_mode + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * + * Return: value of ml_link_control_mode in success + */ +uint8_t wlan_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_mlme_restore_user_set_link_num() - restore link num when SSR happens + * @psoc: pointer to psoc object + * + * Return: void + */ +void wlan_mlme_restore_user_set_link_num(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_clear_user_set_link_num() - clear user set link num + * @psoc: pointer to psoc object + * + * Return: void + */ +void wlan_mlme_clear_user_set_link_num(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_sta_mlo_conn_band_bmp() - get band bitmap that sta mlo + * connection can support + * @psoc: pointer to psoc object + * + * Return: band bitmap that sta mlo connection can support + */ +uint8_t wlan_mlme_get_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_sta_mlo_simultaneous_links() - set mlo simultaneous links + * @psoc: pointer to psoc object + * @value: value to set + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_get_sta_mlo_simultaneous_links() - get mlo simultaneous links + * @psoc: pointer to psoc object + * + * Return: number of links + */ +uint8_t wlan_mlme_get_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_set_sta_mlo_conn_band_bmp() - set band bitmap that sta mlo + * connection can support + * @psoc: pointer to psoc object + * @value: value to set + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * wlan_mlme_get_sta_same_link_mld_addr() - check if mld/link use same address + * @psoc: pointer to psoc object + * + * Return: bool to check if the mld/link use same mac address + */ +bool wlan_mlme_get_sta_same_link_mld_addr(struct wlan_objmgr_psoc *psoc); +#else +static inline +void wlan_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t value) +{ +} + +static inline +uint8_t wlan_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return 0; +} + +static inline QDF_STATUS +wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void wlan_mlme_restore_user_set_link_num(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +void wlan_mlme_clear_user_set_link_num(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS +wlan_mlme_set_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t +wlan_mlme_get_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline bool +wlan_mlme_is_5gl_5gh_mlsr_supported(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +wlan_mlme_set_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_set_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_mlme_set_ba_2k_jump_iot_ap() - Set a flag if ba 2k jump IOT AP is found + * @vdev: vdev pointer + * @found: Carries the value true if ba 2k jump IOT AP is found + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev, bool found); + +/** + * wlan_mlme_is_ba_2k_jump_iot_ap() - Check if ba 2k jump IOT AP is found + * @vdev: vdev pointer + * + * Return: true if ba 2k jump IOT AP is found + */ +bool +wlan_mlme_is_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_set_last_delba_sent_time() - Cache the last delba sent ts + * @vdev: vdev pointer + * @delba_sent_time: Last delba sent timestamp + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_last_delba_sent_time(struct wlan_objmgr_vdev *vdev, + qdf_time_t delba_sent_time); + +/** + * wlan_mlme_get_last_delba_sent_time() - Get the last delba sent ts + * @vdev: vdev pointer + * + * Return: Last delba timestamp if cached, 0 otherwise + */ +qdf_time_t +wlan_mlme_get_last_delba_sent_time(struct wlan_objmgr_vdev *vdev); + +/** + * mlme_set_user_ps() - Set the PS user config + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * @ps_enable: User PS enable + * + * Return: QDF_STATUS + */ +QDF_STATUS mlme_set_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + bool ps_enable); + +/** + * mlme_get_user_ps() - Set the user ps flag + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * + * Return: True if user_ps flag is set + */ +bool mlme_get_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * wlan_mlme_get_p2p_p2p_conc_support() - Get p2p+p2p conc support + * @psoc: pointer to psoc object + * + * Return: Success/failure + */ +bool +wlan_mlme_get_p2p_p2p_conc_support(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +wlan_mlme_get_p2p_p2p_conc_support(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * mlme_get_vht_ch_width() - get vht channel width of fw capability + * + * Return: vht channel width + */ +enum phy_ch_width mlme_get_vht_ch_width(void); + +/** + * wlan_mlme_get_mgmt_hw_tx_retry_count() - Get mgmt frame hw tx retry count + * @psoc: pointer to psoc object + * @frm_type: frame type of the query + * + * Return: hw tx retry count + */ +uint8_t +wlan_mlme_get_mgmt_hw_tx_retry_count(struct wlan_objmgr_psoc *psoc, + enum mlme_cfg_frame_type frm_type); + +/** + * wlan_mlme_get_tx_retry_multiplier() - Get the tx retry multiplier percentage + * @psoc: pointer to psoc object + * @tx_retry_multiplier: pointer to hold user config value of + * tx_retry_multiplier + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_tx_retry_multiplier(struct wlan_objmgr_psoc *psoc, + uint32_t *tx_retry_multiplier); + +/** + * wlan_mlme_get_update_chan_width_allowed - Get value of INI + * is_update_chan_width_allowed + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_update_chan_width_allowed(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * wlan_mlme_get_channel_bonding_5ghz - Get the channel bonding + * val for 5ghz freq + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_get_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * wlan_mlme_update_ratemask_params() - Update ratemask params + * + * @vdev: pointer to vdev object + * @num_ratemask: number of rate masks + * @rate_params: pointer to ratemask structure + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_update_ratemask_params(struct wlan_objmgr_vdev *vdev, + uint8_t num_ratemask, + struct config_ratemask_params *rate_params); + +/** + * wlan_mlme_is_channel_valid() - validate channel frequency + * @psoc: psoc object manager + * @chan_freq: channel frequency + * + * This function validates channel frequency present in valid channel + * list or not. + * + * Return: true or false + */ +bool wlan_mlme_is_channel_valid(struct wlan_objmgr_psoc *psoc, + uint32_t chan_freq); +#ifdef WLAN_FEATURE_MCC_QUOTA +/** + * wlan_mlme_set_user_mcc_quota() - set the user mcc quota in mlme + * @psoc: pointer to psoc object + * @quota: pointer to user set mcc quota object + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota); + +/** + * wlan_mlme_get_user_mcc_quota() - Get the user mcc quota from mlme + * @psoc: pointer to psoc object + * @quota: pointer to user set mcc quota object + * + * Return: QDF Status + */ +QDF_STATUS wlan_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota); + +/** + * wlan_mlme_get_user_mcc_duty_cycle_percentage() - Get user mcc duty cycle + * @psoc: pointer to psoc object + * + * Return: MCC duty cycle if MCC exists for the user MCC quota, else 0 + */ +uint32_t +wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS +wlan_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline uint32_t +wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} +#endif /* WLAN_FEATURE_MCC_QUOTA */ + +/** + * mlme_get_max_he_mcs_idx() - get max mcs index from he cap information + * @mcs_ch_width: channel width + * @hecap_rxmcsnssmap: rx mcs map from he cap + * @hecap_txmcsnssmap: tx mcs map from he cap + * + * Return: the maximum MCS supported + */ +uint8_t mlme_get_max_he_mcs_idx(enum phy_ch_width mcs_ch_width, + u_int16_t *hecap_rxmcsnssmap, + u_int16_t *hecap_txmcsnssmap); + +/** + * mlme_get_max_vht_mcs_idx() - get max mcs index from vht cap information + * @rx_vht_mcs_map: rx mcs map from vht cap + * @tx_vht_mcs_map: tx mcs map from vht cap + * + * Return: the maximum MCS supported + */ +uint8_t mlme_get_max_vht_mcs_idx(u_int16_t rx_vht_mcs_map, + u_int16_t tx_vht_mcs_map); + +#ifdef WLAN_FEATURE_SON +/** + * mlme_save_vdev_max_mcs_idx() - Save max mcs index of vdev + * @vdev: pointer to vdev object + * @max_mcs_idx: max_mcs_idx to save + * + * Return: QDF Status + */ +QDF_STATUS mlme_save_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + uint8_t max_mcs_idx); + +/** + * mlme_get_vdev_max_mcs_idx() - Get max mcs index of vdev + * @vdev: pointer to vdev object + * + * Return max mcs index of vdev + */ +uint8_t mlme_get_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev); +#endif /* WLAN_FEATURE_SON */ +/** + * wlan_mlme_set_safe_mode_enable() - set safe_mode_enable flag + * based on value set by user space. + * + * @psoc: psoc context + * @safe_mode_enable: safe mode enabled or not + * + * Return: none + */ +void wlan_mlme_set_safe_mode_enable(struct wlan_objmgr_psoc *psoc, + bool safe_mode_enable); + +/** + * wlan_mlme_get_safe_mode_enable() - get safe_mode_enable set by user + * space + * + * @psoc: psoc context + * @safe_mode_enable: safe mode enabled or not + * + * Return: none + */ +void wlan_mlme_get_safe_mode_enable(struct wlan_objmgr_psoc *psoc, + bool *safe_mode_enable); + +/** + * wlan_mlme_get_6g_ap_power_type() - get the power type of the + * vdev operating on 6GHz. + * + * @vdev: vdev context + * + * Return: 6g_power_type + */ +uint32_t wlan_mlme_get_6g_ap_power_type(struct wlan_objmgr_vdev *vdev); + +QDF_STATUS wlan_connect_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + wlan_cm_id cm_id, + QDF_STATUS status); + +/** + * wlan_mlme_get_ch_width_from_phymode() - Convert phymode to ch_width + * @phy_mode: Phy mode + * + * Return: enum phy_ch_width + */ +enum phy_ch_width +wlan_mlme_get_ch_width_from_phymode(enum wlan_phymode phy_mode); + +/** + * wlan_mlme_get_peer_ch_width() - get ch_width of the given peer + * @psoc: psoc context + * @mac: peer mac + * + * Return: enum phy_ch_width + */ +enum phy_ch_width +wlan_mlme_get_peer_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t *mac); + +#if defined(WLAN_FEATURE_SR) +/** + * wlan_mlme_get_sr_enable_modes() - get mode for which SR is enabled + * + * @psoc: psoc context + * @val: pointer to hold the value of SR(Spatial Reuse) enable modes + * + * Return: void + */ +void +wlan_mlme_get_sr_enable_modes(struct wlan_objmgr_psoc *psoc, uint8_t *val); +#endif + +/** + * wlan_mlme_set_edca_pifs_param() - set edca/pifs param for ll sap + * @ep: pointer to wlan_edca_pifs_param_ie + * @type: edca_param_type + * + * Return: None + */ +void +wlan_mlme_set_edca_pifs_param(struct wlan_edca_pifs_param_ie *ep, + enum host_edca_param_type type); +/** + * wlan_mlme_stats_get_periodic_display_time() - get display time + * @psoc: pointer to psoc object + * @periodic_display_time: buffer to hold value + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_stats_get_periodic_display_time(struct wlan_objmgr_psoc *psoc, + uint32_t *periodic_display_time); + +/** + * wlan_mlme_is_bcn_prot_disabled_for_sap() - Is beacon protection config + * disabled for SAP interface + * + * @psoc: pointer to psoc object + * + * Return: is beacon protection disabled + */ +bool +wlan_mlme_is_bcn_prot_disabled_for_sap(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_src_addr_from_frame() - Get source address of the frame + * @frame: frame ptr + * + * Extract source mac address of the frame + * + * Return: Ptr for extracted src mac address + * + */ +uint8_t * +wlan_mlme_get_src_addr_from_frame(struct element_info *frame); + +/* + * wlan_mlme_get_sap_ps_with_twt() - power save with twt config enabled/disabled + * for SAP interface + * + * @psoc: pointer to psoc object + * + * Return: power save enabled/disabled + */ +bool +wlan_mlme_get_sap_ps_with_twt(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_mlme_get_max_bw() - Get max supported bandwidth + * + * Extract max supported bandwidth + * + * Return: enum phy_ch_width + * + */ +enum phy_ch_width wlan_mlme_get_max_bw(void); + +/** + * wlan_mlme_get_sta_ch_width() - Get current operating + * channel width for STA / P2P-CLI mode + * + * @vdev: STA / P2P-CLI vdev + * @ch_width: Returned channel width + * + * Return: QDF_STATUS_SUCCESS for success otherwise QDF_STATUS_E_INVAL + * + */ +QDF_STATUS wlan_mlme_get_sta_ch_width(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width *ch_width); + +/** + * wlan_mlme_set_ul_mu_config() - set ul mu config + * + * @psoc: pointer to psoc object + * @vdev_id : vdev_id + * @ulmu_disable : ulmu_disable value + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_ul_mu_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t ulmu_disable); + +/** + * wlan_mlme_assemble_rate_code() - assemble rate code to be sent to FW + * + * @preamble: rate preamble + * @nss: number of spatial streams + * @rate: rate index + * + * Rate code assembling is different for targets which are 11ax capable. + * Check for the target support and assemble the rate code accordingly. + * + * Return: assembled rate code + */ +uint32_t +wlan_mlme_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate); + +/** + * wlan_mlme_set_ap_oper_ch_width() - set SAP current operating ch_width + * + * @vdev: SAP VDEV object + * @ch_width: ch_width to be cached + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_set_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width ch_width); + +/** + * wlan_mlme_get_ap_oper_ch_width() - get SAP current operating ch_width + * + * @vdev: SAP VDEV object + * + * Return: Current SAP operating ch_width + */ +enum phy_ch_width +wlan_mlme_get_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_send_csa_event_status_ind() - send csa event status ind + * @vdev: vdev obj + * @csa_status: csa status + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlme_send_csa_event_status_ind(struct wlan_objmgr_vdev *vdev, + uint8_t csa_status); + +/** + * wlan_mlme_is_hs_20_btm_offload_disabled() - Get BTM offload is enable/disable + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +wlan_mlme_is_hs_20_btm_offload_disabled(struct wlan_objmgr_psoc *psoc, + bool *val); +/** + * wlan_mlme_set_keepalive_period() - Save keep alive period + * @vdev: VDEV object + * @keep_alive_period: Keep alive period + * + * Return: None + */ +void wlan_mlme_set_keepalive_period(struct wlan_objmgr_vdev *vdev, + uint16_t keep_alive_period); + +/** + * wlan_mlme_get_keepalive_period() - Get keep alive period + * @vdev: VDEV object + * + * Return: Keep alive period. + */ +uint16_t wlan_mlme_get_keepalive_period(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_reset_sta_keepalive_period() - Reset keep alive period to default + * cfg whether it is set by userspace or via assoc rsp + * @psoc: pointer to psoc object + * @vdev: VDEV object + * + * Return: None + */ +void wlan_mlme_reset_sta_keepalive_period(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_mlme_get_sta_keep_alive_period() - get keep alive period + * @psoc: pointer to psoc object + * @keep_alive_period: keep alive period + * + * Return: QDF STATUS + */ +QDF_STATUS +wlan_mlme_get_sta_keep_alive_period(struct wlan_objmgr_psoc *psoc, + uint32_t *keep_alive_period); + +#endif /* _WLAN_MLME_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_product_details_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_product_details_cfg.h new file mode 100644 index 0000000000..fb2b01e2ee --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_product_details_cfg.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2011-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_MLME_PRODUCT_DETAILS_H__ +#define WLAN_MLME_PRODUCT_DETAILS_H__ + +/* + * manufacturer_name - Set manufacture Name + * @Min_len: 0 + * @Max_len: 63 + * @Default: Qualcomm Atheros + * + * This internal CFG is used to set manufacture name + * + * Related: None + * + * Supported Feature: product details + * + * Usage: Internal + * + */ +#define CFG_MFR_NAME CFG_STRING( \ + "manufacturer_name", \ + 0, \ + WLAN_CFG_MFR_NAME_LEN, \ + "Qualcomm Atheros", \ + "Manufacture name") + +/* + * model_number - Set model number + * @Min_len: 0 + * @Max_len: 31 + * @Default: MN1234 + * + * This internal CFG is used to set model number + * + * Related: None + * + * Supported Feature: product details + * + * Usage: Internal + * + */ +#define CFG_MODEL_NUMBER CFG_STRING( \ + "model_number", \ + 0, \ + WLAN_CFG_MODEL_NUMBER_LEN, \ + "MN1234", \ + "model number") + +/* + * model_name - Set model name + * @Min_len: 0 + * @Max_len: 31 + * @Default: WFR4031 + * + * This internal CFG is used to set model name + * + * Related: None + * + * Supported Feature: product details + * + * Usage: Internal + * + */ +#define CFG_MODEL_NAME CFG_STRING( \ + "model_name", \ + 0, \ + WLAN_CFG_MODEL_NAME_LEN, \ + "WFR4031", \ + "model name") + +/* + * manufacture_product_name - Set manufacture product name + * @Min_len: 0 + * @Max_len: 31 + * @Default: 11n-AP + * + * This internal CFG is used to set manufacture product name + * + * Related: None + * + * Supported Feature: product details + * + * Usage: Internal + * + */ +#define CFG_MFR_PRODUCT_NAME CFG_STRING( \ + "manufacture_product_name", \ + 0, \ + WLAN_CFG_MFR_PRODUCT_NAME_LEN, \ + "11n-AP", \ + "manufacture product name") + +/* + * model_number - Set manufacture product version + * @Min_len: 0 + * @Max_len: 31 + * @Default: SN1234 + * + * This internal CFG is used to set manufacture product version + * + * Related: None + * + * Supported Feature: product details + * + * Usage: Internal + * + */ +#define CFG_MFR_PRODUCT_VERSION CFG_STRING( \ + "manufacture_product_version", \ + 0, \ + WLAN_CFG_MFR_PRODUCT_VERSION_LEN, \ + "SN1234", \ + "manufacture product version") + +#define CFG_MLME_PRODUCT_DETAILS_ALL \ + CFG(CFG_MFR_NAME) \ + CFG(CFG_MODEL_NUMBER) \ + CFG(CFG_MODEL_NAME) \ + CFG(CFG_MFR_PRODUCT_NAME) \ + CFG(CFG_MFR_PRODUCT_VERSION) + +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h new file mode 100644 index 0000000000..59d122c749 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_public_struct.h @@ -0,0 +1,3142 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains mlme structure definitions + */ + +#ifndef _WLAN_MLME_STRUCT_H_ +#define _WLAN_MLME_STRUCT_H_ + +#include +#include +#include +#include +#include "wlan_cm_roam_public_struct.h" +#include "wlan_mlme_twt_public_struct.h" +#include "cfg_mlme_generic.h" +#include "host_diag_core_event.h" + +#define OWE_TRANSITION_OUI_TYPE "\x50\x6f\x9a\x1c" +#define OWE_TRANSITION_OUI_SIZE 4 + +/* + * EID_VENDOR| IE_LEN | OUI |OUI_TYPE| OWE transition BSSID|SSID_LEN| SSID | + * (1) | (1) | (3) | (1) | (6) | (1) |(SSID_LEN)| + */ +#define OWE_SSID_LEN_OFFSET 12 +#define OWE_SSID_OFFSET 13 + +#define CFG_PMKID_MODES_OKC (0x1) +#define CFG_PMKID_MODES_PMKSA_CACHING (0x2) + +#define CFG_VHT_BASIC_MCS_SET_STADEF 0xFFFE + +#define CFG_VHT_RX_MCS_MAP_STAMIN 0 +#define CFG_VHT_RX_MCS_MAP_STAMAX 0xFFFF +#define CFG_VHT_RX_MCS_MAP_STADEF 0xFFFE + +#define CFG_VHT_TX_MCS_MAP_STAMIN 0 +#define CFG_VHT_TX_MCS_MAP_STAMAX 0xFFFF +#define CFG_VHT_TX_MCS_MAP_STADEF 0xFFFE + +#define STA_DOT11_MODE_INDX 0 +#define P2P_DEV_DOT11_MODE_INDX 4 +#define NAN_DISC_DOT11_MODE_INDX 8 +#define OCB_DOT11_MODE_INDX 12 +#define TDLS_DOT11_MODE_INDX 16 +#define NDI_DOT11_MODE_INDX 20 + +/* Roam debugging related macro defines */ +#define MAX_ROAM_DEBUG_BUF_SIZE 250 +#define MAX_ROAM_EVENTS_SUPPORTED 5 +#define ROAM_FAILURE_BUF_SIZE 60 +#define TIME_STRING_LEN 24 + +#define ROAM_CHANNEL_BUF_SIZE 300 +#define LINE_STR "==============================================================" +/* + * MLME_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF + 1 is + * assumed to be the default fw supported BF antennas, if fw + * says it supports 8 antennas in rx ready event and if + * gTxBFCsnValue INI value is configured above 3, set + * the same to MLME_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED. + * Otherwise, fall back and set fw default value[3]. + */ +#define MLME_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF 3 + +#define CFG_STR_DATA_LEN 17 +#define CFG_EDCA_DATA_LEN 17 +#define CFG_MAX_TX_POWER_2_4_LEN 128 +#define CFG_MAX_TX_POWER_5_LEN 256 +#define CFG_POWER_USAGE_MAX_LEN 4 +#define CFG_MAX_STR_LEN 256 +#define MAX_VENDOR_IES_LEN 1532 + +#define CFG_MAX_PMK_LEN 64 + +#define CFG_VALID_CHANNEL_LIST_STRING_LEN (CFG_VALID_CHANNEL_LIST_LEN * 4) + +#define DEFAULT_ROAM_TRIGGER_BITMAP 0xFFFFFFFF + +/* + * detect AP off based FW reported last RSSI > roaming Low rssi + * and not less than 20db of host cached RSSI + */ +#define AP_OFF_RSSI_OFFSET 20 + +/* Default beacon interval of 100 ms */ +#define CUSTOM_CONC_GO_BI 100 + +#define HECAP_TXRX_MCS_NSS_IDX_80 (0) +#define HECAP_TXRX_MCS_NSS_IDX_160 (1) +#define HECAP_TXRX_MCS_NSS_IDX_80_80 (2) +#define INVALID_MCS_NSS_INDEX 0xff + +enum diagwlan_status_eventsubtype { + DIAG_WLAN_STATUS_CONNECT = 0, + DIAG_WLAN_STATUS_DISCONNECT +}; + +enum diagwlan_status_eventreason { + DIAG_REASON_UNSPECIFIED = 0, + DIAG_REASON_USER_REQUESTED, + DIAG_REASON_MIC_ERROR, + DIAG_REASON_DISASSOC, + DIAG_REASON_DEAUTH, + DIAG_REASON_HANDOFF, + DIAG_REASON_ROAM_SYNCH_IND, + DIAG_REASON_ROAM_SYNCH_CNF, + DIAG_REASON_ROAM_HO_FAIL, +}; + +/** + * struct mlme_cfg_str - generic structure for all mlme CFG string items + * + * @max_len: maximum data length allowed + * @len: valid no. of elements of the data + * @data: uint8_t array to store values + */ +struct mlme_cfg_str { + qdf_size_t max_len; + qdf_size_t len; + uint8_t data[CFG_STR_DATA_LEN]; +}; + +/** + * enum e_edca_type - to index edca params for edca profile + * EDCA profile AC unicast/bcast + * @edca_ani_acbe_local: ani BE unicast + * @edca_ani_acbk_local: ani BK unicast + * @edca_ani_acvi_local: ani VI unicast + * @edca_ani_acvo_local: ani VO unicast + * @edca_ani_acbe_bcast: ani BE bcast + * @edca_ani_acbk_bcast: ani BK bcast + * @edca_ani_acvi_bcast: ani VI bcast + * @edca_ani_acvo_bcast: ani VO bcast + * @edca_wme_acbe_local: wme BE unicast + * @edca_wme_acbk_local: wme BK unicast + * @edca_wme_acvi_local: wme VI unicast + * @edca_wme_acvo_local: wme VO unicast + * @edca_wme_acbe_bcast: wme BE bcast + * @edca_wme_acbk_bcast: wme BK bcast + * @edca_wme_acvi_bcast: wme VI bcast + * @edca_wme_acvo_bcast: wme VO bcast + * @edca_etsi_acbe_local: etsi BE unicast + * @edca_etsi_acbk_local: etsi BK unicast + * @edca_etsi_acvi_local: etsi VI unicast + * @edca_etsi_acvo_local: etsi VO unicast + * @edca_etsi_acbe_bcast: etsi BE bcast + * @edca_etsi_acbk_bcast: etsi BK bcast + * @edca_etsi_acvi_bcast: etsi VI bcast + * @edca_etsi_acvo_bcast: etsi VO bcast + */ +enum e_edca_type { + edca_ani_acbe_local, + edca_ani_acbk_local, + edca_ani_acvi_local, + edca_ani_acvo_local, + edca_ani_acbe_bcast, + edca_ani_acbk_bcast, + edca_ani_acvi_bcast, + edca_ani_acvo_bcast, + edca_wme_acbe_local, + edca_wme_acbk_local, + edca_wme_acvi_local, + edca_wme_acvo_local, + edca_wme_acbe_bcast, + edca_wme_acbk_bcast, + edca_wme_acvi_bcast, + edca_wme_acvo_bcast, + edca_etsi_acbe_local, + edca_etsi_acbk_local, + edca_etsi_acvi_local, + edca_etsi_acvo_local, + edca_etsi_acbe_bcast, + edca_etsi_acbk_bcast, + edca_etsi_acvi_bcast, + edca_etsi_acvo_bcast +}; + +#define CFG_EDCA_PROFILE_ACM_IDX 0 +#define CFG_EDCA_PROFILE_AIFSN_IDX 1 +#define CFG_EDCA_PROFILE_CWMINA_IDX 2 +#define CFG_EDCA_PROFILE_CWMAXA_IDX 4 +#define CFG_EDCA_PROFILE_TXOPA_IDX 6 +#define CFG_EDCA_PROFILE_CWMINB_IDX 7 +#define CFG_EDCA_PROFILE_CWMAXB_IDX 9 +#define CFG_EDCA_PROFILE_TXOPB_IDX 11 +#define CFG_EDCA_PROFILE_CWMING_IDX 12 +#define CFG_EDCA_PROFILE_CWMAXG_IDX 14 +#define CFG_EDCA_PROFILE_TXOPG_IDX 16 + +/** + * struct mlme_edca_ac_vo - cwmin, cwmax and aifs value for edca_ac_vo + * + * @vo_cwmin: cwmin value for voice + * @vo_cwmax: cwmax value for voice + * @vo_aifs: aifs value for voice + */ +struct mlme_edca_ac_vo { + uint32_t vo_cwmin; + uint32_t vo_cwmax; + uint32_t vo_aifs; +}; + +/** + * enum mlme_dot11_mode - Dot11 mode of the vdev + * @MLME_DOT11_MODE_ALL: vdev supports all dot11 modes + * @MLME_DOT11_MODE_ABG: vdev supports just 11A, 11B and 11G modes + * @MLME_DOT11_MODE_11A: vdev just supports 11A mode + * @MLME_DOT11_MODE_11B: vdev supports 11B mode, and modes above it + * @MLME_DOT11_MODE_11G: vdev supports 11G mode, and modes above it + * @MLME_DOT11_MODE_11N: vdev supports 11N mode, and modes above it + * @MLME_DOT11_MODE_11G_ONLY: vdev just supports 11G mode + * @MLME_DOT11_MODE_11N_ONLY: vdev just supports 11N mode + * @MLME_DOT11_MODE_11AC: vdev supports 11AC mode, and modes above it + * @MLME_DOT11_MODE_11AC_ONLY: vdev just supports 11AC mode + * @MLME_DOT11_MODE_11AX: vdev supports 11AX mode, and modes above it + * @MLME_DOT11_MODE_11AX_ONLY: vdev just supports 11AX mode + * @MLME_DOT11_MODE_11BE: vdev supports 11BE mode, and modes above it + * @MLME_DOT11_MODE_11BE_ONLY: vdev just supports 11BE mode + */ +enum mlme_dot11_mode { + MLME_DOT11_MODE_ALL, + /* Initial dot11 modes should come first */ + MLME_DOT11_MODE_ABG, + MLME_DOT11_MODE_11A, + MLME_DOT11_MODE_11B, + MLME_DOT11_MODE_11G, + MLME_DOT11_MODE_11N, + MLME_DOT11_MODE_11G_ONLY, + MLME_DOT11_MODE_11N_ONLY, + MLME_DOT11_MODE_11AC, + MLME_DOT11_MODE_11AC_ONLY, + MLME_DOT11_MODE_11AX, + MLME_DOT11_MODE_11AX_ONLY, + MLME_DOT11_MODE_11BE, + MLME_DOT11_MODE_11BE_ONLY, +}; + +/** + * struct wlan_mlme_dot11_mode - dot11 mode + * + * @dot11_mode: dot11 mode supported + * @vdev_type_dot11_mode: dot11 mode supported by different vdev types + */ +struct wlan_mlme_dot11_mode { + enum mlme_dot11_mode dot11_mode; + uint32_t vdev_type_dot11_mode; +}; + +/** + * struct mlme_edca_ac_vi - cwmin, cwmax and aifs value for edca_ac_vi + * + * @vi_cwmin: cwmin value for video + * @vi_cwmax: cwmax value for video + * @vi_aifs: aifs value for video + */ +struct mlme_edca_ac_vi { + uint32_t vi_cwmin; + uint32_t vi_cwmax; + uint32_t vi_aifs; +}; + +/** + * struct mlme_edca_ac_bk - cwmin, cwmax and aifs value for edca_ac_bk + * + * @bk_cwmin: cwmin value for background + * @bk_cwmax: cwmax value for background + * @bk_aifs: aifs value for background + */ +struct mlme_edca_ac_bk { + uint32_t bk_cwmin; + uint32_t bk_cwmax; + uint32_t bk_aifs; +}; + +/** + * struct mlme_edca_ac_be - cwmin, cwmax and aifs value for edca_ac_be + * + * @be_cwmin: cwmin value for best effort + * @be_cwmax: cwmax value for best effort + * @be_aifs: aifs value for best effort + */ +struct mlme_edca_ac_be { + uint32_t be_cwmin; + uint32_t be_cwmax; + uint32_t be_aifs; +}; + +/** + * enum mlme_ts_info_ack_policy - TS Info Ack Policy + * @TS_INFO_ACK_POLICY_NORMAL_ACK:normal ack + * @TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: HT immediate block ack + */ +enum mlme_ts_info_ack_policy { + TS_INFO_ACK_POLICY_NORMAL_ACK = 0, + TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 1, +}; + +/** + * struct wlan_mlme_edca_params - EDCA pramaters related config items + * + * @ani_acbk_l: EDCA parameters for ANI local access category background + * @ani_acbe_l: EDCA parameters for ANI local access category best effort + * @ani_acvi_l: EDCA parameters for ANI local access category video + * @ani_acvo_l: EDCA parameters for ANI local access category voice + * @ani_acbk_b: EDCA parameters for ANI bcast access category background + * @ani_acbe_b: EDCA parameters for ANI bcast access category best effort + * @ani_acvi_b: EDCA parameters for ANI bcast access category video + * @ani_acvo_b: EDCA parameters for ANI bcast access category voice + * @wme_acbk_l: EDCA parameters for WME local access category background + * @wme_acbe_l: EDCA parameters for WME local access category best effort + * @wme_acvi_l: EDCA parameters for WME local access category video + * @wme_acvo_l: EDCA parameters for WME local access category voice + * @wme_acbk_b: EDCA parameters for WME bcast access category background + * @wme_acbe_b: EDCA parameters for WME bcast access category best effort + * @wme_acvi_b: EDCA parameters for WME bcast access category video + * @wme_acvo_b: EDCA parameters for WME bcast access category voice + * @etsi_acbk_l: EDCA parameters for ETSI local access category background + * @etsi_acbe_l: EDCA parameters for ETSI local access category best effort + * @etsi_acvi_l: EDCA parameters for ETSI local access category video + * @etsi_acvo_l: EDCA parameters for ETSI local access category voice + * @etsi_acbk_b: EDCA parameters for ETSI bcast access category background + * @etsi_acbe_b: EDCA parameters for ETSI bcast access category best effort + * @etsi_acvi_b: EDCA parameters for ETSI bcast access category video + * @etsi_acvo_b: EDCA parameters for ETSI bcast access category voice + * @enable_edca_params: Enable edca parameter + * @enable_wmm_txop: Enable WMM TxOp + * @edca_ac_vo: value for edca_ac_vo + * @edca_ac_vi: value for edca_ac_vi + * @edca_ac_bk: value for edca_ac_bk + * @edca_ac_be: value for edca_ac_be + * @edca_param_type: Edca param type + */ +struct wlan_mlme_edca_params { + struct mlme_cfg_str ani_acbk_l; + struct mlme_cfg_str ani_acbe_l; + struct mlme_cfg_str ani_acvi_l; + struct mlme_cfg_str ani_acvo_l; + struct mlme_cfg_str ani_acbk_b; + struct mlme_cfg_str ani_acbe_b; + struct mlme_cfg_str ani_acvi_b; + struct mlme_cfg_str ani_acvo_b; + + struct mlme_cfg_str wme_acbk_l; + struct mlme_cfg_str wme_acbe_l; + struct mlme_cfg_str wme_acvi_l; + struct mlme_cfg_str wme_acvo_l; + struct mlme_cfg_str wme_acbk_b; + struct mlme_cfg_str wme_acbe_b; + struct mlme_cfg_str wme_acvi_b; + struct mlme_cfg_str wme_acvo_b; + + struct mlme_cfg_str etsi_acbk_l; + struct mlme_cfg_str etsi_acbe_l; + struct mlme_cfg_str etsi_acvi_l; + struct mlme_cfg_str etsi_acvo_l; + struct mlme_cfg_str etsi_acbk_b; + struct mlme_cfg_str etsi_acbe_b; + struct mlme_cfg_str etsi_acvi_b; + struct mlme_cfg_str etsi_acvo_b; + + bool enable_edca_params; + bool enable_wmm_txop; + struct mlme_edca_ac_vo edca_ac_vo; + struct mlme_edca_ac_vi edca_ac_vi; + struct mlme_edca_ac_bk edca_ac_bk; + struct mlme_edca_ac_be edca_ac_be; + + enum host_edca_param_type edca_param_type; +}; + +/* To configure EDCA/PIFS param for LL SAP */ +#define CFG_EDCA_PARAM_ACM 0 +#define CFG_EDCA_PARAM_AIFSN 2 +#define CFG_EDCA_PARAM_ACI 3 +#define CFG_EDCA_PARAM_CWMIN 2 +#define CFG_EDCA_PARAM_CWMAX 3 +#define CFG_EDCA_PARAM_TXOP 47 +#define CFG_PIFS_PARAM_SAP_OFFSET 0 +#define CFG_PIFS_PARAM_LEB_OFFSET 1 +#define CFG_PIFS_PARAM_REB_OFFSET 2 + +#define WLAN_CFG_MFR_NAME_LEN (63) +#define WLAN_CFG_MODEL_NUMBER_LEN (31) +#define WLAN_CFG_MODEL_NAME_LEN (31) +#define WLAN_CFG_MFR_PRODUCT_NAME_LEN (31) +#define WLAN_CFG_MFR_PRODUCT_VERSION_LEN (31) + +#define MLME_NUM_WLM_LATENCY_LEVEL 4 +#define MLME_RMENABLEDCAP_MAX_LEN 5 + +#ifndef ANI_LITTLE_BIT_ENDIAN +/** + * struct mlme_ht_capabilities_info - HT Capabilities Info + * @l_sig_tx_op_protection: L-SIG TXOP Protection Mechanism support + * @stbc_control_frame: STBC Control frame support + * @psmp: PSMP Support + * @dsss_cck_mode_40_mhz: To indicate use of DSSS/CCK in 40Mhz + * @maximal_amsdu_size: Maximum AMSDU Size - 0:3839 octes, 1:7935 octets + * @delayed_ba: Support of Delayed Block Ack + * @rx_stbc: Rx STBC Support - 0:Not Supported, 1: 1SS, 2: 1,2SS, 3: 1,2,3SS + * @tx_stbc: Tx STBC Support + * @short_gi_40_mhz: Short GI Support for HT40 + * @short_gi_20_mhz: Short GI support for HT20 + * @green_field: Support for HT Greenfield PPDUs + * @mimo_power_save: SM Power Save Mode - 0:Static, 1:Dynamic, 3:Disabled, 2:Res + * @supported_channel_width_set: Supported Chan Width - 0:20Mhz, 1:20Mhz & 40Mhz + * @adv_coding_cap: Rx LDPC support + */ +struct mlme_ht_capabilities_info { + uint16_t l_sig_tx_op_protection:1; + uint16_t stbc_control_frame:1; + uint16_t psmp:1; + uint16_t dsss_cck_mode_40_mhz:1; + uint16_t maximal_amsdu_size:1; + uint16_t delayed_ba:1; + uint16_t rx_stbc:2; + uint16_t tx_stbc:1; + uint16_t short_gi_40_mhz:1; + uint16_t short_gi_20_mhz:1; + uint16_t green_field:1; + uint16_t mimo_power_save:2; + uint16_t supported_channel_width_set:1; + uint16_t adv_coding_cap:1; +} qdf_packed; +#else +struct mlme_ht_capabilities_info { + uint16_t adv_coding_cap:1; + uint16_t supported_channel_width_set:1; + uint16_t mimo_power_save:2; + uint16_t green_field:1; + uint16_t short_gi_20_mhz:1; + uint16_t short_gi_40_mhz:1; + uint16_t tx_stbc:1; + uint16_t rx_stbc:2; + uint16_t delayed_ba:1; + uint16_t maximal_amsdu_size:1; + uint16_t dsss_cck_mode_40_mhz:1; + uint16_t psmp:1; + uint16_t stbc_control_frame:1; + uint16_t l_sig_tx_op_protection:1; +} qdf_packed; +#endif + +/** + * struct wlan_ht_config - HT capabilities + * @ht_caps: ht caps in bitwise + * @caps: uint32 caps + */ +struct wlan_ht_config { + union { + struct mlme_ht_capabilities_info ht_caps; + uint32_t caps; + }; +}; + +#ifndef ANI_LITTLE_BIT_ENDIAN +/** + * struct mlme_ht_param_info - HT AMPDU Parameters Info + * @reserved: reserved bits + * @mpdu_density: MPDU Density + * @max_rx_ampdu_factor: Max Rx AMPDU Factor + */ +struct mlme_ht_param_info { + uint8_t reserved:3; + uint8_t mpdu_density:3; + uint8_t max_rx_ampdu_factor:2; +} qdf_packed; +#else +struct mlme_ht_param_info { + uint8_t max_rx_ampdu_factor:2; + uint8_t mpdu_density:3; + uint8_t reserved:3; +} qdf_packed; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN +/** + * struct mlme_ht_ext_cap_info - Extended HT Capabilities Info + * @reserved_2: Reserved Bits + * @mcs_feedback: MCS Feedback Capability + * @reserved_1: Reserved Bits + * @transition_time: Time needed for transition between 20Mhz and 40 Mhz + * @pco: PCO (Phased Coexistence Operation) Support + */ +struct mlme_ht_ext_cap_info { + uint16_t reserved_2:6; + uint16_t mcs_feedback:2; + uint16_t reserved_1:5; + uint16_t transition_time:2; + uint16_t pco:1; +} qdf_packed; +#else +struct mlme_ht_ext_cap_info { + uint16_t pco:1; + uint16_t transition_time:2; + uint16_t reserved1:5; + uint16_t mcs_feedback:2; + uint16_t reserved2:6; +} qdf_packed; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN +/** + * struct mlme_ht_info_field_1 - Additional HT IE Field1 + * @service_interval_granularity: Shortest Service Interval + * @controlled_access_only: Access Control for assoc requests + * @rifs_mode: Reduced Interframe Spacing mode + * @recommended_tx_width_set: Recommended Tx Channel Width + * @secondary_channel_offset: Secondary Channel Offset + */ +struct mlme_ht_info_field_1 { + uint8_t service_interval_granularity:3; + uint8_t controlled_access_only:1; + uint8_t rifs_mode:1; + uint8_t recommended_tx_width_set:1; + uint8_t secondary_channel_offset:2; +} qdf_packed; +#else +struct mlme_ht_info_field_1 { + uint8_t secondary_channel_offset:2; + uint8_t recommended_tx_width_set:1; + uint8_t rifs_mode:1; + uint8_t controlled_access_only:1; + uint8_t service_interval_granularity:3; +} qdf_packed; +#endif + +/* struct mlme_ht_info_field_2 - Additional HT IE Field2 + * @reserved: reserved bits + * @obss_non_ht_sta_present: Protection for non-HT STAs by Overlapping BSS + * @transmit_burst_limit: Transmit Burst Limit + * @non_gf_devices_present: Non Greenfield devices present + * @op_mode: Operation Mode + */ +#ifndef ANI_LITTLE_BIT_ENDIAN +struct mlme_ht_info_field_2 { + uint16_t reserved:11; + uint16_t obss_non_ht_sta_present:1; + uint16_t transmit_burst_limit:1; + uint16_t non_gf_devices_present:1; + uint16_t op_mode:2; +} qdf_packed; +#else +struct mlme_ht_info_field_2 { + uint16_t op_mode:2; + uint16_t non_gf_devices_present:1; + uint16_t transmit_burst_limit:1; + uint16_t obss_non_ht_sta_present:1; + uint16_t reserved:11; +} qdf_packed; +#endif + +#ifdef WLAN_FEATURE_FILS_SK + +/** + * struct wlan_fils_connection_info - Fils connection parameters + * @is_fils_connection: flag to indicate if the connection is done using + * authentication algorithm as 4 + * @keyname_nai: key name network access identifier + * @key_nai_length: key name network access identifier length + * @erp_sequence_number: FILS ERP sequence number + * @r_rk: re-authentication Root Key length + * @r_rk_length: reauthentication root keys length + * @rik: Re-authentication integrity key + * @rik_length: Re-Authentication integrity key length + * @realm: Realm name + * @realm_len: Realm length + * @akm_type: FILS connection akm + * @auth_type: FILS Authentication Algorithm + * @pmk: Pairwise master key + * @pmk_len: Pairwise master key length + * @pmkid: Pairwise master key ID + * @fils_ft: FILS FT key + * @fils_ft_len: Length of FILS FT + */ +struct wlan_fils_connection_info { + bool is_fils_connection; + uint8_t keyname_nai[FILS_MAX_KEYNAME_NAI_LENGTH]; + uint32_t key_nai_length; + uint32_t erp_sequence_number; + uint8_t r_rk[WLAN_FILS_MAX_RRK_LENGTH]; + uint32_t r_rk_length; + uint8_t rik[WLAN_FILS_MAX_RIK_LENGTH]; + uint32_t rik_length; + uint8_t realm[WLAN_FILS_MAX_REALM_LEN]; + uint32_t realm_len; + uint8_t akm_type; + uint8_t auth_type; + uint8_t pmk[MAX_PMK_LEN]; + uint8_t pmk_len; + uint8_t pmkid[PMKID_LEN]; + uint8_t fils_ft[WLAN_FILS_FT_MAX_LEN]; + uint8_t fils_ft_len; +}; +#endif + +#ifndef ANI_LITTLE_BIT_ENDIAN +/** + * struct mlme_ht_info_field_3 - Additional HT IE Field3 + * @reserved: reserved bits + * @pco_phase: PCO Phase + * @pco_active: PCO state + * @lsig_txop_protection_full_support: L-Sig TXOP Protection Full Support + * @secondary_beacon: Beacon ID + * @dual_cts_protection: Dual CTS protection Required + * @basic_stbc_mcs: Basic STBC MCS + */ +struct mlme_ht_info_field_3 { + uint16_t reserved:4; + uint16_t pco_phase:1; + uint16_t pco_active:1; + uint16_t lsig_txop_protection_full_support:1; + uint16_t secondary_beacon:1; + uint16_t dual_cts_protection:1; + uint16_t basic_stbc_mcs:7; +} qdf_packed; +#else +struct mlme_ht_info_field_3 { + uint16_t basic_stbc_mcs:7; + uint16_t dual_cts_protection:1; + uint16_t secondary_beacon:1; + uint16_t lsig_txop_protection_full_support:1; + uint16_t pco_active:1; + uint16_t pco_phase:1; + uint16_t reserved:4; +} qdf_packed; +#endif + +/** + * struct wlan_mlme_ht_caps - HT Capabilities related config items + * @ht_cap_info: HT capabilities Info Structure + * @ampdu_params: AMPDU parameters + * @ext_cap_info: HT EXT capabilities info + * @info_field_1: HT Information Subset 1 + * @info_field_2: HT Information Subset 2 + * @info_field_3: HT Information Subset 3 + * @short_preamble: Short Preamble support + * @enable_ampdu_ps: Enable AMPDU Power Save + * @enable_smps: Enabled SM Power Save + * @smps : SM Power Save mode + * @max_num_amsdu: Max number of AMSDU + * @tx_ldpc_enable: Enable Tx LDPC + * @short_slot_time_enabled: Enabled/disable short slot time + */ +struct wlan_mlme_ht_caps { + struct mlme_ht_capabilities_info ht_cap_info; + struct mlme_ht_param_info ampdu_params; + struct mlme_ht_ext_cap_info ext_cap_info; + struct mlme_ht_info_field_1 info_field_1; + struct mlme_ht_info_field_2 info_field_2; + struct mlme_ht_info_field_3 info_field_3; + bool short_preamble; + bool enable_ampdu_ps; + bool enable_smps; + uint8_t smps; + uint8_t max_num_amsdu; + uint8_t tx_ldpc_enable; + bool short_slot_time_enabled; +}; + +#define MLME_CFG_WPS_UUID_MAX_LEN 16 +/** + * struct wlan_mlme_wps_params - All wps based related cfg items + * + * @enable_wps: to enable wps + * @wps_state: current wps state + * @wps_version: wps version + * @wps_cfg_method: wps config method + * @wps_primary_device_category: wps primary device category + * @wps_primary_device_oui: primary device OUI + * @wps_device_sub_category: device sub category + * @wps_device_password_id: password id of device + * @wps_uuid: wps uuid to be sent in probe + */ +struct wlan_mlme_wps_params { + uint8_t enable_wps; + uint8_t wps_state; + uint8_t wps_version; + uint32_t wps_cfg_method; + uint32_t wps_primary_device_category; + uint32_t wps_primary_device_oui; + uint16_t wps_device_sub_category; + uint32_t wps_device_password_id; + struct mlme_cfg_str wps_uuid; +}; + +#define MLME_CFG_LISTEN_INTERVAL 1 +#define MLME_CFG_BEACON_INTERVAL_DEF 100 +#define MLME_CFG_TX_MGMT_RATE_DEF 0xFF +#define MLME_CFG_TX_MGMT_2G_RATE_DEF 0xFF +#define MLME_CFG_TX_MGMT_5G_RATE_DEF 0xFF + +/** + * struct wlan_mlme_cfg_sap - SAP related config items + * @cfg_ssid: SSID to be configured + * @beacon_interval: beacon interval + * @dtim_interval: dtim interval + * @listen_interval: listen interval + * @sap_11g_policy: Check if 11g support is enabled + * @assoc_sta_limit: Limit on number of STA associated to SAP + * @enable_lte_coex: Flag for LTE coexistence + * @rate_tx_mgmt: mgmt frame tx rate + * @rate_tx_mgmt_2g: mgmt frame tx rate for 2G band + * @rate_tx_mgmt_5g: mgmt frame tx rate for 5G band + * @tele_bcn_wakeup_en: beacon wakeup enable/disable + * @tele_bcn_max_li: max listen interval + * @sap_get_peer_info: get peer info + * @sap_allow_all_chan_param_name: allow all channels + * @sap_max_no_peers: Maximum number of peers + * @sap_max_offload_peers: Maximum number of peer offloads + * @sap_max_offload_reorder_buffs: Maximum offload reorder buffs + * @sap_ch_switch_beacon_cnt: Number of beacons to be sent out during CSA + * @sap_internal_restart: flag to check if sap restart is in progress + * @sap_ch_switch_mode: Channel switch test mode enable/disable + * @chan_switch_hostapd_rate_enabled_name: enable/disable skip hostapd rate + * @reduced_beacon_interval: reduced beacon interval value + * @max_li_modulated_dtim_time: Max modulated DTIM time. + * @country_code_priority: Country code priority. + * @sap_pref_chan_location: SAP Preferred channel location. + * @sap_force_11n_for_11ac: + * @go_force_11n_for_11ac: + * @ap_random_bssid_enable: + * @sap_mcc_chnl_avoid: SAP MCC channel avoidance flag + * @sap_11ac_override: Overrirde SAP bandwidth to 11ac + * @go_11ac_override: Override GO bandwidth to 11ac + * @sap_sae_enabled: enable sae in sap mode + * @is_sap_bcast_deauth_enabled: enable bcast deauth for sap + * @is_6g_sap_fd_enabled: enable fils discovery on sap + * @disable_bcn_prot: disable beacon protection for sap + * @sap_ps_with_twt_enable: SAP power save with TWT + */ +struct wlan_mlme_cfg_sap { + uint16_t beacon_interval; + uint16_t dtim_interval; + uint16_t listen_interval; + bool sap_11g_policy; + uint8_t assoc_sta_limit; + bool enable_lte_coex; + uint8_t rate_tx_mgmt; + uint8_t rate_tx_mgmt_2g; + uint8_t rate_tx_mgmt_5g; + bool tele_bcn_wakeup_en; + uint8_t tele_bcn_max_li; + bool sap_get_peer_info; + bool sap_allow_all_chan_param_name; + uint8_t sap_max_no_peers; + uint8_t sap_max_offload_peers; + uint8_t sap_max_offload_reorder_buffs; + uint8_t sap_ch_switch_beacon_cnt; + bool sap_internal_restart; + bool sap_ch_switch_mode; + bool chan_switch_hostapd_rate_enabled_name; + uint8_t reduced_beacon_interval; + uint8_t max_li_modulated_dtim_time; + bool country_code_priority; + uint8_t sap_pref_chan_location; + bool sap_force_11n_for_11ac; + bool go_force_11n_for_11ac; + bool ap_random_bssid_enable; + uint8_t sap_mcc_chnl_avoid; + bool sap_11ac_override; + bool go_11ac_override; + bool sap_sae_enabled; + bool is_sap_bcast_deauth_enabled; + bool is_6g_sap_fd_enabled; + bool disable_bcn_prot; + bool sap_ps_with_twt_enable; +}; + +/** + * struct wlan_mlme_dfs_cfg - DFS Capabilities related config items + * @dfs_master_capable: Is DFS master mode support enabled + * @dfs_disable_channel_switch: disable channel switch on radar detection + * @dfs_ignore_cac: Disable cac + * @dfs_filter_offload: dfs filter offloaad + * @dfs_beacon_tx_enhanced: enhance dfs beacon tx + * @dfs_prefer_non_dfs: perefer non dfs channel after radar + * @dfs_disable_japan_w53: Disable W53 channels + * @sap_tx_leakage_threshold: sap tx leakage threshold + * @dfs_pri_multiplier: dfs_pri_multiplier for handle missing pulses + */ +struct wlan_mlme_dfs_cfg { + bool dfs_master_capable; + bool dfs_disable_channel_switch; + bool dfs_ignore_cac; + bool dfs_filter_offload; + bool dfs_beacon_tx_enhanced; + bool dfs_prefer_non_dfs; + bool dfs_disable_japan_w53; + uint32_t sap_tx_leakage_threshold; + uint32_t dfs_pri_multiplier; +}; + +/** + * struct wlan_mlme_mbo - Multiband Operation related ini configs + * @mbo_candidate_rssi_thres: candidate AP's min rssi to accept it + * @mbo_current_rssi_thres: Connected AP's rssi threshold below which + * transition is considered + * @mbo_current_rssi_mcc_thres: connected AP's RSSI threshold value to prefer + * against MCC + * @mbo_candidate_rssi_btc_thres: Candidate AP's minimum RSSI threshold to + * prefer it even in BT coex. + */ +struct wlan_mlme_mbo { + int8_t mbo_candidate_rssi_thres; + int8_t mbo_current_rssi_thres; + int8_t mbo_current_rssi_mcc_thres; + int8_t mbo_candidate_rssi_btc_thres; +}; + +/** + * struct wlan_mlme_powersave - Powersave related ini configs + * @is_imps_enabled: flag to enable/disable IMPS + * @is_bmps_enabled: flag to enable/disable BMPS + * @auto_bmps_timer_val: auto BMPS timer value + * @bmps_min_listen_interval: BMPS listen interval minimum value + * @bmps_max_listen_interval: BMPS listen interval maximum value + * @dtim_selection_diversity: dtim selection diversity value to be sent to fw + */ +struct wlan_mlme_powersave { + bool is_imps_enabled; + bool is_bmps_enabled; + uint32_t auto_bmps_timer_val; + uint32_t bmps_min_listen_interval; + uint32_t bmps_max_listen_interval; + uint32_t dtim_selection_diversity; +}; + +/** + * struct mlme_vht_capabilities_info - MLME VHT config items + * @supp_chan_width: Supported Channel Width + * @ldpc_coding_cap: LDPC Coding Capability + * @short_gi_80mhz: 80MHz Short Guard Interval + * @short_gi_160mhz: 160MHz Short Guard Interval + * @tx_stbc: Tx STBC cap + * @rx_stbc: Rx STBC cap + * @su_bformer: SU Beamformer cap + * @su_bformee: SU Beamformee cap + * @tx_bfee_ant_supp: Tx beamformee anti supp + * @num_soundingdim: Number of sounding dimensions + * @mu_bformer: MU Beamformer cap + * @txop_ps: Tx OPs in power save + * @htc_vhtc: htc_vht capability + * @link_adap_cap: Link adaptation capability + * @rx_antpattern: Rx Antenna Pattern cap + * @tx_antpattern: Tx Antenna Pattern cap + * @rx_mcs_map: Rx MCS Map + * @tx_mcs_map: Tx MCS Map + * @rx_supp_data_rate: Rx highest supported data rate + * @tx_supp_data_rate: Tx highest supported data rate + * @basic_mcs_set: Basic MCS set + * @enable_txbf_20mhz: enable tx bf for 20mhz + * @channel_width: Channel width capability for 11ac + * @rx_mcs: VHT Rx MCS capability for 1x1 mode + * @tx_mcs: VHT Tx MCS capability for 1x1 mode + * @rx_mcs2x2: VHT Rx MCS capability for 2x2 mode + * @tx_mcs2x2: VHT Tx MCS capability for 2x2 mode + * @enable_vht20_mcs9: Enables VHT MCS9 in 20M BW operation + * @enable2x2: Enables/disables VHT Tx/Rx MCS values for 2x2 + * @enable_mu_bformee: Enables/disables multi-user (MU) + * beam formee capability + * @enable_paid: Enables/disables paid + * @enable_gid: Enables/disables gid + * @b24ghz_band: To control VHT support in 2.4 GHz band + * @vendor_24ghz_band: to control VHT support based on vendor + * ie in 2.4 GHz band + * @ampdu_len_exponent: To handle maximum receive AMPDU ampdu len exponent + * @ampdu_len: To handle maximum receive AMPDU ampdu len + * @tx_bfee_sap: enable tx bfee SAp + * @vendor_vhtie: enable subfee vendor vht ie + * @tx_bf_cap: Transmit bf capability + * @as_cap: Antenna sharing capability info + * @disable_ldpc_with_txbf_ap: Disable ldpc capability + * @vht_mcs_10_11_supp: VHT MCS 10 & 11 support + * @extended_nss_bw_supp: + * @vht_extended_nss_bw_cap: + * @max_nsts_total: + * @restricted_80p80_bw_supp: + */ +struct mlme_vht_capabilities_info { + uint8_t supp_chan_width; + bool ldpc_coding_cap; + bool short_gi_80mhz; + bool short_gi_160mhz; + bool tx_stbc; + bool rx_stbc; + bool su_bformer; + bool su_bformee; + uint8_t tx_bfee_ant_supp; + uint8_t num_soundingdim; + bool mu_bformer; + bool txop_ps; + bool htc_vhtc; + uint8_t link_adap_cap; + bool rx_antpattern; + bool tx_antpattern; + uint32_t rx_mcs_map; + uint32_t tx_mcs_map; + uint32_t rx_supp_data_rate; + uint32_t tx_supp_data_rate; + uint32_t basic_mcs_set; + bool enable_txbf_20mhz; + uint8_t channel_width; + uint32_t rx_mcs; + uint32_t tx_mcs; + uint8_t rx_mcs2x2; + uint8_t tx_mcs2x2; + bool enable_vht20_mcs9; + bool enable2x2; + bool enable_mu_bformee; + bool enable_paid; + bool enable_gid; + bool b24ghz_band; + bool vendor_24ghz_band; + uint8_t ampdu_len_exponent; + uint8_t ampdu_len; + bool tx_bfee_sap; + bool vendor_vhtie; + uint8_t tx_bf_cap; + uint8_t as_cap; + bool disable_ldpc_with_txbf_ap; + bool vht_mcs_10_11_supp; + uint8_t extended_nss_bw_supp; + uint8_t vht_extended_nss_bw_cap; + uint8_t max_nsts_total; + bool restricted_80p80_bw_supp; +}; + +/** + * struct wlan_mlme_vht_caps - VHT Capabilities related config items + * @vht_cap_info: VHT capabilities Info Structure + */ +struct wlan_mlme_vht_caps { + struct mlme_vht_capabilities_info vht_cap_info; +}; + +/** + * struct wlan_vht_config - VHT capabilities + * @max_mpdu_len: MPDU length + * @supported_channel_widthset: channel width set + * @ldpc_coding: LDPC coding capability + * @shortgi80: short GI 80 support + * @shortgi160and80plus80: short Gi 160 & 80+80 support + * @tx_stbc: Tx STBC cap + * @rx_stbc: Rx STBC cap + * @su_beam_former: SU beam former cap + * @su_beam_formee: SU beam formee cap + * @csnof_beamformer_antSup: Antenna support for beamforming + * @num_soundingdim: Sound dimensions + * @mu_beam_former: MU beam former cap + * @mu_beam_formee: MU beam formee cap + * @vht_txops: TXOP power save + * @htc_vhtcap: HTC VHT capability + * @max_ampdu_lenexp: AMPDU length + * @vht_link_adapt: VHT link adapatation capable + * @rx_antpattern: RX antenna pattern + * @tx_antpattern: TX antenna pattern + * @extended_nss_bw_supp: + * @caps: entire capability bitmap + */ +struct wlan_vht_config { + union { + struct { + uint32_t max_mpdu_len:2; + uint32_t supported_channel_widthset:2; + uint32_t ldpc_coding:1; + uint32_t shortgi80:1; + uint32_t shortgi160and80plus80:1; + uint32_t tx_stbc:1; + uint32_t rx_stbc:3; + uint32_t su_beam_former:1; + uint32_t su_beam_formee:1; + uint32_t csnof_beamformer_antSup:3; + uint32_t num_soundingdim:3; + uint32_t mu_beam_former:1; + uint32_t mu_beam_formee:1; + uint32_t vht_txops:1; + uint32_t htc_vhtcap:1; + uint32_t max_ampdu_lenexp:3; + uint32_t vht_link_adapt:2; + uint32_t rx_antpattern:1; + uint32_t tx_antpattern:1; + uint32_t extended_nss_bw_supp:2; + }; + uint32_t caps; + }; +}; + +/** + * struct wlan_mlme_qos - QOS TX/RX aggregation related CFG items + * @tx_aggregation_size: TX aggr size in number of MPDUs + * @tx_aggregation_size_be: No. of MPDUs for BE queue for TX aggr + * @tx_aggregation_size_bk: No. of MPDUs for BK queue for TX aggr + * @tx_aggregation_size_vi: No. of MPDUs for VI queue for TX aggr + * @tx_aggregation_size_vo: No. of MPDUs for VO queue for TX aggr + * @rx_aggregation_size: No. of MPDUs for RX aggr + * @tx_aggr_sw_retry_threshold_be: aggr sw retry threshold for BE + * @tx_aggr_sw_retry_threshold_bk: aggr sw retry threshold for BK + * @tx_aggr_sw_retry_threshold_vi: aggr sw retry threshold for VI + * @tx_aggr_sw_retry_threshold_vo: aggr sw retry threshold for VO + * @tx_aggr_sw_retry_threshold: aggr sw retry threshold + * @tx_non_aggr_sw_retry_threshold_be: non aggr sw retry threshold for BE + * @tx_non_aggr_sw_retry_threshold_bk: non aggr sw retry threshold for BK + * @tx_non_aggr_sw_retry_threshold_vi: non aggr sw retry threshold for VI + * @tx_non_aggr_sw_retry_threshold_vo: non aggr sw retry threshold for VO + * @tx_non_aggr_sw_retry_threshold: non aggr sw retry threshold + * @sap_max_inactivity_override: Override updating ap_sta_inactivity from + * hostapd.conf + * @sap_uapsd_enabled: Flag to enable/disable UAPSD for SAP + */ +struct wlan_mlme_qos { + uint32_t tx_aggregation_size; + uint32_t tx_aggregation_size_be; + uint32_t tx_aggregation_size_bk; + uint32_t tx_aggregation_size_vi; + uint32_t tx_aggregation_size_vo; + uint32_t rx_aggregation_size; + uint32_t tx_aggr_sw_retry_threshold_be; + uint32_t tx_aggr_sw_retry_threshold_bk; + uint32_t tx_aggr_sw_retry_threshold_vi; + uint32_t tx_aggr_sw_retry_threshold_vo; + uint32_t tx_aggr_sw_retry_threshold; + uint32_t tx_non_aggr_sw_retry_threshold_be; + uint32_t tx_non_aggr_sw_retry_threshold_bk; + uint32_t tx_non_aggr_sw_retry_threshold_vi; + uint32_t tx_non_aggr_sw_retry_threshold_vo; + uint32_t tx_non_aggr_sw_retry_threshold; + bool sap_max_inactivity_override; + bool sap_uapsd_enabled; +}; + +#ifdef WLAN_FEATURE_11AX +#define MLME_HE_PPET_LEN 25 +#define WNI_CFG_HE_OPS_BSS_COLOR_MAX 0x3F + +/** + * struct wlan_mlme_he_caps - HE Capabilities related config items + * @dot11_he_cap: + * @he_cap_orig: + * @he_ppet_2g: + * @he_ppet_5g: + * @he_ops_basic_mcs_nss: + * @he_dynamic_fragmentation: + * @enable_ul_mimo: + * @enable_ul_ofdm: + * @he_sta_obsspd: + * @he_mcs_12_13_supp_2g: + * @he_mcs_12_13_supp_5g: + * @disable_sap_mcs_12_13: Bitmap to disable he mcs 12 13 for SAP + */ +struct wlan_mlme_he_caps { + tDot11fIEhe_cap dot11_he_cap; + tDot11fIEhe_cap he_cap_orig; + uint8_t he_ppet_2g[MLME_HE_PPET_LEN]; + uint8_t he_ppet_5g[MLME_HE_PPET_LEN]; + uint32_t he_ops_basic_mcs_nss; + uint8_t he_dynamic_fragmentation; + uint8_t enable_ul_mimo; + uint8_t enable_ul_ofdm; + uint32_t he_sta_obsspd; + uint16_t he_mcs_12_13_supp_2g; + uint16_t he_mcs_12_13_supp_5g; + uint32_t disable_sap_mcs_12_13; +}; +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * struct wlan_mlme_eht_caps - EHT Capabilities related config items + * @dot11_eht_cap: current EHT capabilities + * @eht_cap_orig: original EHT capabilities + */ +struct wlan_mlme_eht_caps { + tDot11fIEeht_cap dot11_eht_cap; + tDot11fIEeht_cap eht_cap_orig; + /* Add members to store INI configuration corresponding to 11be */ +}; +#endif + +/** + * struct wlan_mlme_chain_cfg - Chain info related structure + * @max_tx_chains_2g: max tx chains supported in 2.4ghz band + * @max_rx_chains_2g: max rx chains supported in 2.4ghz band + * @max_tx_chains_5g: max tx chains supported in 5ghz band + * @max_rx_chains_5g: max rx chains supported in 5ghz band + */ +struct wlan_mlme_chain_cfg { + uint8_t max_tx_chains_2g; + uint8_t max_rx_chains_2g; + uint8_t max_tx_chains_5g; + uint8_t max_rx_chains_5g; +}; + +/** + * struct mlme_tgt_caps - mlme related capability coming from target (FW) + * @data_stall_recovery_fw_support: does target supports data stall recovery. + * @bigtk_support: does the target support bigtk capability or not. + * @stop_all_host_scan_support: Target capability that indicates if the target + * supports stop all host scan request type. + * @peer_create_conf_support: Peer create confirmation command support + * @dual_sta_roam_fw_support: Firmware support for dual sta roaming feature + * @ocv_support: FW supports OCV + * + * Add all the mlme-tgt related capabilities here, and the public API would fill + * the related capability in the required mlme cfg structure. + */ +struct mlme_tgt_caps { + bool data_stall_recovery_fw_support; + bool bigtk_support; + bool stop_all_host_scan_support; + bool peer_create_conf_support; + bool dual_sta_roam_fw_support; + bool ocv_support; +}; + +/** + * struct wlan_mlme_rates - RATES related config items + * @cfp_period: cfp period info + * @cfp_max_duration: cfp Max duration info + * @max_htmcs_txdata: max HT mcs info for Tx + * @disable_abg_rate_txdata: disable abg rate info for tx data + * @sap_max_mcs_txdata: sap max mcs info + * @disable_high_ht_mcs_2x2: disable high mcs for 2x2 info + * @supported_11b: supported 11B rates + * @supported_11a: supported 11A rates + * @supported_mcs_set: supported MCS set + * @basic_mcs_set: basic MCS set + * @current_mcs_set: current MCS set + */ +struct wlan_mlme_rates { + uint8_t cfp_period; + uint16_t cfp_max_duration; + uint16_t max_htmcs_txdata; + bool disable_abg_rate_txdata; + uint16_t sap_max_mcs_txdata; + uint8_t disable_high_ht_mcs_2x2; + struct mlme_cfg_str supported_11b; + struct mlme_cfg_str supported_11a; + struct mlme_cfg_str supported_mcs_set; + struct mlme_cfg_str basic_mcs_set; + struct mlme_cfg_str current_mcs_set; +}; + + +/* Flags for gLimProtectionControl that is updated in pe session*/ +#define MLME_FORCE_POLICY_PROTECTION_DISABLE 0 +#define MLME_FORCE_POLICY_PROTECTION_CTS 1 +#define MLME_FORCE_POLICY_PROTECTION_RTS 2 +#define MLME_FORCE_POLICY_PROTECTION_DUAL_CTS 3 +#define MLME_FORCE_POLICY_PROTECTION_RTS_ALWAYS 4 +#define MLME_FORCE_POLICY_PROTECTION_AUTO 5 + +/* protection_enabled bits*/ +#define MLME_PROTECTION_ENABLED_FROM_llA 0 +#define MLME_PROTECTION_ENABLED_FROM_llB 1 +#define MLME_PROTECTION_ENABLED_FROM_llG 2 +#define MLME_PROTECTION_ENABLED_HT_20 3 +#define MLME_PROTECTION_ENABLED_NON_GF 4 +#define MLME_PROTECTION_ENABLED_LSIG_TXOP 5 +#define MLME_PROTECTION_ENABLED_RIFS 6 +#define MLME_PROTECTION_ENABLED_OBSS 7 +#define MLME_PROTECTION_ENABLED_OLBC_FROM_llA 8 +#define MLME_PROTECTION_ENABLED_OLBC_FROM_llB 9 +#define MLME_PROTECTION_ENABLED_OLBC_FROM_llG 10 +#define MLME_PROTECTION_ENABLED_OLBC_HT20 11 +#define MLME_PROTECTION_ENABLED_OLBC_NON_GF 12 +#define MLME_PROTECTION_ENABLED_OLBC_LSIG_TXOP 13 +#define MLME_PROTECTION_ENABLED_OLBC_RIFS 14 +#define MLME_PROTECTION_ENABLED_OLBC_OBSS 15 + +/** + * struct wlan_mlme_feature_flag - feature related information + * @accept_short_slot_assoc: enable short slot feature + * @enable_hcf: enable HCF feature + * @enable_rsn: enable RSN for connection + * @enable_short_preamble_11g: enable short preamble for 11g + * @enable_short_slot_time_11g: enable shot slot time for 11g + * @enable_ampdu: enable AMPDU feature + * @enable_mcc: enable MCC feature + * @mcc_rts_cts_prot: RTS-CTS protection in MCC + * @mcc_bcast_prob_rsp: broadcast Probe Response in MCC + * @channel_bonding_mode: channel bonding mode + * @enable_block_ack: enable block ack feature + * @channel_bonding_mode_24ghz: configures Channel Bonding in 24 GHz + * @channel_bonding_mode_5ghz: configures Channel Bonding in 5 GHz + * @update_cw_allowed: to check update chan width allowed or not + */ +struct wlan_mlme_feature_flag { + bool accept_short_slot_assoc; + bool enable_hcf; + bool enable_rsn; + bool enable_short_preamble_11g; + bool enable_short_slot_time_11g; + bool enable_ampdu; + bool enable_mcc; + uint8_t mcc_rts_cts_prot; + uint8_t mcc_bcast_prob_rsp; + uint32_t channel_bonding_mode; + uint32_t enable_block_ack; + uint32_t channel_bonding_mode_24ghz; + uint32_t channel_bonding_mode_5ghz; + bool update_cw_allowed; +}; + +/** + * struct wlan_mlme_sap_protection - SAP erp protection config items + * @ignore_peer_ht_opmode: Ignore the ht opmode of the peer. Dynamic via INI + * @enable_ap_obss_protection: enable/disable AP OBSS protection + * @protection_force_policy: Protection force policy. Static via cfg + * @is_ap_prot_enabled: Enable/disable SAP protection + * @ap_protection_mode: AP protection bitmap + * @protection_enabled: Force enable protection. static via cfg + */ +struct wlan_mlme_sap_protection { + bool ignore_peer_ht_opmode; + bool enable_ap_obss_protection; + uint8_t protection_force_policy; + bool is_ap_prot_enabled; + uint16_t ap_protection_mode; + uint32_t protection_enabled; +}; + +/** + * struct wlan_mlme_chainmask - All chainmask related cfg items + * @txchainmask1x1: To set transmit chainmask + * @rxchainmask1x1: To set rx chainmask + * @tx_chain_mask_cck: Used to enable/disable Cck ChainMask + * @tx_chain_mask_1ss: Enables/disables tx chain Mask1ss + * @num_11b_tx_chains: Number of Tx Chains in 11b mode + * @num_11ag_tx_chains: Number of Tx Chains in 11ag mode + * @tx_chain_mask_2g: Tx chain mask for 2g + * @rx_chain_mask_2g: Tx chain mask for 2g + * @tx_chain_mask_5g: Tx chain mask for 5g + * @rx_chain_mask_5g: Rx chain mask for 5g + * @enable_bt_chain_separation: Enable/Disable BT/WLAN Host chain separation + */ +struct wlan_mlme_chainmask { + uint8_t txchainmask1x1; + uint8_t rxchainmask1x1; + bool tx_chain_mask_cck; + uint8_t tx_chain_mask_1ss; + uint16_t num_11b_tx_chains; + uint16_t num_11ag_tx_chains; + uint8_t tx_chain_mask_2g; + uint8_t rx_chain_mask_2g; + uint8_t tx_chain_mask_5g; + uint8_t rx_chain_mask_5g; + bool enable_bt_chain_separation; +}; + +/** + * enum wlan_mlme_ratemask_type: Type of PHY for ratemask + * @WLAN_MLME_RATEMASK_TYPE_NO_MASK: no ratemask set + * @WLAN_MLME_RATEMASK_TYPE_CCK: CCK/OFDM rate + * @WLAN_MLME_RATEMASK_TYPE_HT: HT rate + * @WLAN_MLME_RATEMASK_TYPE_VHT: VHT rate + * @WLAN_MLME_RATEMASK_TYPE_HE: HE rate + * @WLAN_MLME_RATEMASK_TYPE_MAX: max enumeration + * + * This is used for 'type' values in wlan_mlme_ratemask + */ +enum wlan_mlme_ratemask_type { + WLAN_MLME_RATEMASK_TYPE_NO_MASK = 0, + WLAN_MLME_RATEMASK_TYPE_CCK = 1, + WLAN_MLME_RATEMASK_TYPE_HT = 2, + WLAN_MLME_RATEMASK_TYPE_VHT = 3, + WLAN_MLME_RATEMASK_TYPE_HE = 4, + /* keep this last */ + WLAN_MLME_RATEMASK_TYPE_MAX, +}; + +/** + * struct wlan_mlme_ratemask - ratemask config parameters + * @type: Type of PHY the mask to be applied + * @lower32: Lower 32 bits in the 1st 64-bit value + * @higher32: Higher 32 bits in the 1st 64-bit value + * @lower32_2: Lower 32 bits in the 2nd 64-bit value + * @higher32_2: Higher 32 bits in the 2nd 64-bit value + */ +struct wlan_mlme_ratemask { + enum wlan_mlme_ratemask_type type; + uint32_t lower32; + uint32_t higher32; + uint32_t lower32_2; + uint32_t higher32_2; +}; + +/** + * struct dual_sta_policy - Concurrent STA policy configuration + * @concurrent_sta_policy: Possible values are defined in enum + * qca_wlan_concurrent_sta_policy_config + * @primary_vdev_id: specified iface is the primary STA iface, say 0 means + * vdev 0 is acting as primary interface + */ +struct dual_sta_policy { + uint8_t concurrent_sta_policy; + uint8_t primary_vdev_id; +}; + +/** + * enum mlme_cfg_frame_type - frame type to configure mgmt hw tx retry count + * @CFG_GO_NEGOTIATION_REQ_FRAME_TYPE: p2p go negotiation request fame + * @CFG_P2P_INVITATION_REQ_FRAME_TYPE: p2p invitation request frame + * @CFG_PROVISION_DISCOVERY_REQ_FRAME_TYPE: p2p provision discovery request + * @CFG_FRAME_TYPE_MAX: max enumeration + */ +enum mlme_cfg_frame_type { + CFG_GO_NEGOTIATION_REQ_FRAME_TYPE = 0, + CFG_P2P_INVITATION_REQ_FRAME_TYPE = 1, + CFG_PROVISION_DISCOVERY_REQ_FRAME_TYPE = 2, + CFG_FRAME_TYPE_MAX, +}; + +#define MAX_MGMT_HW_TX_RETRY_COUNT 127 + +/** + * struct wlan_user_mcc_quota - User MCC quota configuration + * @op_mode: Mode for which MCC quota needs to be applied + * @quota: User MCC quota value + * @vdev_id: Intended VDEV id for the quota + */ +struct wlan_user_mcc_quota { + enum QDF_OPMODE op_mode; + uint8_t quota; + uint8_t vdev_id; +}; + +/** + * enum wlan_mlme_hw_mode_config_type - HW mode config type replicated from + * wmi_hw_mode_config_type in FW header. + * similar as wmi_host_hw_mode_config_type. + * @WLAN_MLME_HW_MODE_SINGLE: Only one PHY is active. + * @WLAN_MLME_HW_MODE_DBS: Both PHYs are active in different bands, + * one in 2G and another in 5G. + * @WLAN_MLME_HW_MODE_SBS_PASSIVE: Both PHYs are in passive mode (only rx) in + * same band; no tx allowed. + * @WLAN_MLME_HW_MODE_SBS: Both PHYs are active in the same band. + * Support for both PHYs within one band is planned + * for 5G only(as indicated in WMI_MAC_PHY_CAPABILITIES), + * but could be extended to other bands in the future. + * The separation of the band between the two PHYs needs + * to be communicated separately. + * @WLAN_MLME_HW_MODE_DBS_SBS: 3 PHYs, with 2 on the same band doing SBS + * as in WMI_HW_MODE_SBS, and 3rd on the other band + * @WLAN_MLME_HW_MODE_DBS_OR_SBS: Two PHY with one PHY capabale of both 2G and + * 5G. It can support SBS (5G + 5G) OR DBS (5G + 2G). + * @WLAN_MLME_HW_MODE_DBS_2G_5G: Both PHYs are active in different bands. + * PhyA 2G and PhyB 5G + * @WLAN_MLME_HW_MODE_2G_PHYB: Only one phy is active. 2G mode on PhyB. + * @WLAN_MLME_HW_MODE_EMLSR: Both PHYs are active in listen mode in 1x1 + * and Tx/Rx trigger on any PHY will switch + * from 1x1 to 2x2 on that Phy + * @WLAN_MLME_HW_MODE_AUX_EMLSR_SINGLE: PHYA0 and AUX are active in listen mode + * in 1x1 and Tx/Rx trigger on any. + * PHY will switch from 1x1 to 2x2 + * on that Phy. + * @WLAN_MLME_HW_MODE_AUX_EMLSR_SPLIT: PHYA1 and AUX are active in listen mode + * in 1x1 and Tx/Rx trigger on any. + * PHY will switch from 1x1 to 2x2 + * on that Phy. + * @WLAN_MLME_HW_MODE_MAX: Max hw_mode_id. + */ +enum wlan_mlme_hw_mode_config_type { + WLAN_MLME_HW_MODE_SINGLE = 0, + WLAN_MLME_HW_MODE_DBS = 1, + WLAN_MLME_HW_MODE_SBS_PASSIVE = 2, + WLAN_MLME_HW_MODE_SBS = 3, + WLAN_MLME_HW_MODE_DBS_SBS = 4, + WLAN_MLME_HW_MODE_DBS_OR_SBS = 5, + WLAN_MLME_HW_MODE_DBS_2G_5G = 6, + WLAN_MLME_HW_MODE_2G_PHYB = 7, + WLAN_MLME_HW_MODE_EMLSR = 8, + WLAN_MLME_HW_MODE_AUX_EMLSR_SINGLE = 9, + WLAN_MLME_HW_MODE_AUX_EMLSR_SPLIT = 10, + WLAN_MLME_HW_MODE_MAX, +}; + +/** + * enum wlan_mlme_aux_caps_bit - Bit mapping for aux capability + * + * @WLAN_MLME_AUX_MODE_SCAN_BIT: if set, aux scan is supported + * @WLAN_MLME_AUX_MODE_LISTEN_BIT: if set, aux listen is supported + * @WLAN_MLME_AUX_MODE_EMLSR_BIT: if set, aux emlsr is supported + */ +enum wlan_mlme_aux_caps_bit { + WLAN_MLME_AUX_MODE_SCAN_BIT = 0, + WLAN_MLME_AUX_MODE_LISTEN_BIT = 1, + WLAN_MLME_AUX_MODE_EMLSR_BIT = 2, +}; + +/* struct wlan_mlme_aux_dev_caps - wlan mlme aux dev capability + * + * @supported_modes_bitmap: indicate which mode this AUX supports for the + * HW mode defined in hw_mode_id + * @listen_pdev_id_map: indicate which AUX MAC can listen/scan for the HW mode + * described in hw_mode_id + * @emlsr_pdev_id_map: indicate which AUX MAC can perform eMLSR for the HW mode + * described in hw_mode_id. + */ +struct wlan_mlme_aux_dev_caps { + uint32_t supported_modes_bitmap; + uint32_t listen_pdev_id_map; + uint32_t emlsr_pdev_id_map; +}; + +/* struct wlan_mlme_generic - Generic CFG config items + * + * @band_capability: HW Band Capability - Both or 2.4G only or 5G only + * @band: Current Band - Internal variable, initialized to INI and updated later + * @select_5ghz_margin: RSSI margin to select 5Ghz over 2.4 Ghz + * @sub_20_chan_width: Sub 20Mhz Channel Width + * @ito_repeat_count: ITO Repeat Count + * @pmf_sa_query_max_retries: PMF query max retries for SAP + * @pmf_sa_query_retry_interval: PMF query retry interval for SAP + * @dropped_pkt_disconnect_thresh: Threshold for dropped pkts before disconnect + * @rtt_mac_randomization: Enable/Disable RTT MAC randomization + * @rtt3_enabled: RTT3 enable or disable info + * @prevent_link_down: Enable/Disable prevention of link down + * @memory_deep_sleep: Enable/Disable memory deep sleep + * @cck_tx_fir_override: Enable/Disable CCK Tx FIR Override + * @crash_inject: Enable/Disable Crash Inject + * @lpass_support: Enable/Disable LPASS Support + * @self_recovery: Enable/Disable Self Recovery + * @sap_dot11mc: Enable/Disable SAP 802.11mc support + * @fatal_event_trigger: Enable/Disable Fatal Events Trigger + * @optimize_ca_event: Enable/Disable Optimization of CA events + * @fw_timeout_crash: Enable/Disable FW Timeout Crash * + * @debug_packet_log: Debug packet log flags + * @enabled_11h: enable 11h flag + * @enabled_11d: enable 11d flag + * @enable_beacon_reception_stats: enable beacon reception stats + * @data_stall_recovery_fw_support: whether FW supports Data stall recovery. + * @enable_change_channel_bandwidth: enable/disable change channel bw in mission + * mode + * @disable_4way_hs_offload: enable/disable 4 way handshake offload to firmware + * @as_enabled: antenna sharing enabled or not (FW capability) + * @mgmt_retry_max: maximum retries for management frame + * @enable_he_mcs0_for_6ghz_mgmt: HE MCS0 rate for mgmt frames in 6GHz band + * @bmiss_skip_full_scan: Decide if full scan can be skipped in firmware if no + * candidate is found in partial scan based on channel map + * @enable_ring_buffer: Decide to enable/disable ring buffer for bug report + * @enable_peer_unmap_conf_support: Indicate whether to send conf for peer unmap + * @dfs_chan_ageout_time: Set DFS Channel ageout time + * @bigtk_support: Whether BIGTK is supported or not + * @stop_all_host_scan_support: Target capability that indicates if the target + * supports stop all host scan request type. + * @dual_sta_roam_fw_support: Firmware support for dual sta roaming feature + * @sae_connect_retries: sae connect retry bitmask + * @wls_6ghz_capable: wifi location service(WLS) is 6ghz capable + * @enabled_rf_test_mode: Enable/disable the RF test mode config + * @monitor_mode_concurrency: Monitor mode concurrency supported + * @ocv_support: FW supports OCV or not + * @wds_mode: wds mode supported + * @dual_sta_policy_cfg: Dual STA policies configuration + * @tx_retry_multiplier: TX xretry extension parameter + * @mgmt_hw_tx_retry_count: MGMT HW tx retry count for frames + * @std_6ghz_conn_policy: 6GHz standard connection policy + * @disable_vlp_sta_conn_to_sp_ap: Disable VLP STA connection to SP AP + * @eht_mode: EHT mode of operation + * @t2lm_negotiation_support: T2LM negotiation supported enum value + * @enable_emlsr_mode: 11BE eMLSR mode support + * @mld_id: MLD ID of requested BSS within ML probe request frame + * @oem_eht_mlo_crypto_bitmap: Bitmap of APs allowed by OEMs to connect + * in EHT/MLO. + * @safe_mode_enable: safe mode to bypass some strict 6 GHz checks for + * connection, bypass strict power levels + * @sr_enable_modes: modes for which SR(Spatial Reuse) is enabled + * @wlan_mlme_aux0_dev_caps: capability for aux0 + * @bt_profile_con: Bluetooth connection profile + */ +struct wlan_mlme_generic { + uint32_t band_capability; + uint32_t band; + uint8_t select_5ghz_margin; + uint8_t sub_20_chan_width; + uint8_t ito_repeat_count; + uint8_t pmf_sa_query_max_retries; + uint16_t pmf_sa_query_retry_interval; + uint16_t dropped_pkt_disconnect_thresh; + bool rtt_mac_randomization; + bool rtt3_enabled; + bool prevent_link_down; + bool memory_deep_sleep; + bool cck_tx_fir_override; + bool crash_inject; + bool lpass_support; + bool self_recovery; + bool sap_dot11mc; + bool fatal_event_trigger; + bool optimize_ca_event; + bool fw_timeout_crash; + uint8_t debug_packet_log; + bool enabled_11h; + bool enabled_11d; + bool enable_deauth_to_disassoc_map; + bool enable_beacon_reception_stats; + bool data_stall_recovery_fw_support; + uint32_t disable_4way_hs_offload; + bool as_enabled; + uint8_t mgmt_retry_max; + bool enable_he_mcs0_for_6ghz_mgmt; + bool bmiss_skip_full_scan; + bool enable_ring_buffer; + bool enable_peer_unmap_conf_support; + uint8_t dfs_chan_ageout_time; + bool bigtk_support; + bool stop_all_host_scan_support; + bool dual_sta_roam_fw_support; + uint32_t sae_connect_retries; + bool wls_6ghz_capable; + bool enabled_rf_test_mode; + enum monitor_mode_concurrency monitor_mode_concurrency; + bool ocv_support; + enum wlan_wds_mode wds_mode; + struct dual_sta_policy dual_sta_policy; + uint32_t tx_retry_multiplier; + uint8_t mgmt_hw_tx_retry_count[CFG_FRAME_TYPE_MAX]; +#ifdef CONFIG_BAND_6GHZ + bool std_6ghz_conn_policy; + bool disable_vlp_sta_conn_to_sp_ap; +#endif +#ifdef WLAN_FEATURE_11BE_MLO + enum wlan_eht_mode eht_mode; + bool enable_emlsr_mode; + enum t2lm_negotiation_support t2lm_negotiation_support; + uint8_t mld_id; +#endif +#ifdef WLAN_FEATURE_11BE + uint32_t oem_eht_mlo_crypto_bitmap; +#endif +#ifdef WLAN_FEATURE_MCC_QUOTA + struct wlan_user_mcc_quota user_mcc_quota; +#endif + bool safe_mode_enable; +#if defined(WLAN_FEATURE_SR) + uint32_t sr_enable_modes; +#endif + struct wlan_mlme_aux_dev_caps + wlan_mlme_aux0_dev_caps[WLAN_MLME_HW_MODE_MAX]; + bool bt_profile_con; +}; + +/** + * struct wlan_mlme_product_details_cfg - product details config items + * @manufacturer_name: manufacture name + * @model_number: model number + * @model_name: model name + * @manufacture_product_name: manufacture product name + * @manufacture_product_version: manufacture product version + */ +struct wlan_mlme_product_details_cfg { + char manufacturer_name[WLAN_CFG_MFR_NAME_LEN + 1]; + char model_number[WLAN_CFG_MODEL_NUMBER_LEN + 1]; + char model_name[WLAN_CFG_MODEL_NAME_LEN + 1]; + char manufacture_product_name[WLAN_CFG_MFR_PRODUCT_NAME_LEN + 1]; + char manufacture_product_version[WLAN_CFG_MFR_PRODUCT_VERSION_LEN + 1]; +}; + +/** + * struct acs_weight - Normalize ACS weight for mentioned channels + * @chan_freq: frequency of the channel + * @normalize_weight: Normalization factor of the frequency + */ +struct acs_weight { + uint32_t chan_freq; + uint8_t normalize_weight; +}; + +/** + * struct acs_weight_range - Normalize ACS weight for mentioned channel range + * @start_freq: frequency of the start channel + * @end_freq: frequency of the end channel + * @normalize_weight: Normalization factor for freq range + */ +struct acs_weight_range { + uint32_t start_freq; + uint32_t end_freq; + uint8_t normalize_weight; +}; + +#define MAX_ACS_WEIGHT_RANGE 10 +#define MLME_GET_DFS_CHAN_WEIGHT(np_chan_weight) (np_chan_weight & 0x000000FF) + +/** + * struct wlan_mlme_acs - All acs related cfg items + * @is_acs_with_more_param: to enable acs with more param + * @auto_channel_select_weight: to set acs channel weight + * @is_vendor_acs_support: enable application based channel selection + * @is_acs_support_for_dfs_ltecoex: enable channel for dfs and lte coex + * @is_external_acs_policy: control external policy + * @normalize_weight_chan: Weight factor to be considered in ACS + * @normalize_weight_num_chan: Number of freq items for normalization. + * @normalize_weight_range: Frequency range for weight normalization + * @num_weight_range: num of ranges provided by user + * @force_sap_start: Force SAP start when no channel is found suitable + * by ACS + * @acs_prefer_6ghz_psc: Select 6 GHz PSC channel as priority + * @np_chan_weightage: Weightage to be given to non preferred channels. + */ +struct wlan_mlme_acs { + bool is_acs_with_more_param; + uint32_t auto_channel_select_weight; + bool is_vendor_acs_support; + bool is_acs_support_for_dfs_ltecoex; + bool is_external_acs_policy; + struct acs_weight normalize_weight_chan[NUM_CHANNELS]; + uint16_t normalize_weight_num_chan; + struct acs_weight_range normalize_weight_range[MAX_ACS_WEIGHT_RANGE]; + uint16_t num_weight_range; + bool force_sap_start; + bool acs_prefer_6ghz_psc; + uint32_t np_chan_weightage; +}; + +/** + * struct wlan_mlme_cfg_twt - All twt related cfg items + * @is_twt_enabled: global twt configuration + * @is_bcast_responder_enabled: bcast responder enable/disable + * @is_bcast_requestor_enabled: bcast requestor enable/disable + * @bcast_requestor_tgt_cap: Broadcast requestor target capability + * @bcast_responder_tgt_cap: Broadcast responder target capability + * @bcast_legacy_tgt_cap: Broadcast Target capability. This is the legacy + * capability. + * @is_twt_nudge_tgt_cap_enabled: support for nudge request enable/disable + * @is_all_twt_tgt_cap_enabled: support for all twt enable/disable + * @is_twt_statistics_tgt_cap_enabled: support for twt statistics + * @twt_congestion_timeout: congestion timeout value + * @disable_btwt_usr_cfg: User config param to enable/disable the BTWT support + * @enable_twt_24ghz: Enable/disable host TWT when STA is connected in + * 2.4Ghz + * @disable_twt_info_frame: Enable/disable TWT info frame + * @req_flag: requestor flag enable/disable + * @res_flag: responder flag enable/disable + * @twt_res_svc_cap: responder service capability + */ +struct wlan_mlme_cfg_twt { + bool is_twt_enabled; + bool is_bcast_responder_enabled; + bool is_bcast_requestor_enabled; + bool bcast_requestor_tgt_cap; + bool bcast_responder_tgt_cap; + bool bcast_legacy_tgt_cap; + bool is_twt_nudge_tgt_cap_enabled; + bool is_all_twt_tgt_cap_enabled; + bool is_twt_statistics_tgt_cap_enabled; + uint32_t twt_congestion_timeout; + bool disable_btwt_usr_cfg; + bool enable_twt_24ghz; + bool disable_twt_info_frame; + bool req_flag; + bool res_flag; + bool twt_res_svc_cap; +}; + +/** + * struct wlan_mlme_obss_ht40 - OBSS HT40 config items + * @active_dwelltime: obss active dwelltime + * @passive_dwelltime: obss passive dwelltime + * @width_trigger_interval: obss trigger interval + * @passive_per_channel: obss scan passive total duration per channel + * @active_per_channel: obss scan active total duration per channel + * @width_trans_delay: obss width transition delay + * @scan_activity_threshold: obss scan activity threshold + * @is_override_ht20_40_24g: use channel bonding in 2.4 GHz + * @obss_detection_offload_enabled: Enable OBSS detection offload + * @obss_color_collision_offload_enabled: Enable obss color collision + * @bss_color_collision_det_sta: STA BSS color collision detection offload + * @bss_color_collision_det_tgt_support: STA BSS color collision detection + * target support + */ +struct wlan_mlme_obss_ht40 { + uint32_t active_dwelltime; + uint32_t passive_dwelltime; + uint32_t width_trigger_interval; + uint32_t passive_per_channel; + uint32_t active_per_channel; + uint32_t width_trans_delay; + uint32_t scan_activity_threshold; + bool is_override_ht20_40_24g; + bool obss_detection_offload_enabled; + bool obss_color_collision_offload_enabled; + bool bss_color_collision_det_sta; + bool bss_color_collision_det_tgt_support; +}; + +/** + * struct wlan_mlme_eml_cap - EML capabilities of MLD + * @emlsr_supp: eMLSR Support + * @emlsr_pad_delay: eMLSR Padding Delay + * @emlsr_trans_delay: eMLSR transition delay + * @emlmr_supp: eMLMR Support + * @emlmr_delay: eMLMR Delay + * @trans_timeout: Transition Timeout + * @reserved: Reserved + */ +struct wlan_mlme_eml_cap { + uint16_t emlsr_supp:1, + emlsr_pad_delay:3, + emlsr_trans_delay:3, + emlmr_supp:1, + emlmr_delay:3, + trans_timeout:4, + reserved:1; +}; + +/** + * enum dot11p_mode - The 802.11p mode of operation + * @CFG_11P_DISABLED: 802.11p mode is disabled + * @CFG_11P_STANDALONE: 802.11p-only operation + * @CFG_11P_CONCURRENT: 802.11p and WLAN operate concurrently + */ +enum dot11p_mode { + CFG_11P_DISABLED = 0, + CFG_11P_STANDALONE, + CFG_11P_CONCURRENT, +}; + +#define MAX_VDEV_NSS 2 +#define MAX_VDEV_CHAINS 2 + +/** + * struct wlan_mlme_nss_chains - MLME vdev config of nss, and chains + * @num_tx_chains: tx chains of vdev config + * @num_rx_chains: rx chains of vdev config + * @tx_nss: tx nss of vdev config + * @rx_nss: rx nss of vdev config + * @num_tx_chains_11b: number of tx chains in 11b mode + * @num_tx_chains_11g: number of tx chains in 11g mode + * @num_tx_chains_11a: number of tx chains in 11a mode + * @disable_rx_mrc: disable 2 rx chains, in rx nss 1 mode + * @disable_tx_mrc: disable 2 tx chains, in tx nss 1 mode + * @enable_dynamic_nss_chains_cfg: enable the dynamic nss chain config to FW + * @restart_sap_on_dyn_nss_chains_cfg: restart SAP on dynamic NSS chains + * update + */ +struct wlan_mlme_nss_chains { + uint32_t num_tx_chains[NSS_CHAINS_BAND_MAX]; + uint32_t num_rx_chains[NSS_CHAINS_BAND_MAX]; + uint32_t tx_nss[NSS_CHAINS_BAND_MAX]; + uint32_t rx_nss[NSS_CHAINS_BAND_MAX]; + uint32_t num_tx_chains_11b; + uint32_t num_tx_chains_11g; + uint32_t num_tx_chains_11a; + bool disable_rx_mrc[NSS_CHAINS_BAND_MAX]; + bool disable_tx_mrc[NSS_CHAINS_BAND_MAX]; + bool enable_dynamic_nss_chains_cfg; + bool restart_sap_on_dyn_nss_chains_cfg; +}; + +/** + * enum station_keepalive_method - available keepalive methods for stations + * @MLME_STA_KEEPALIVE_MIN: ensure KEEPALIVE_NULL or ARP are not values of 0 + * @MLME_STA_KEEPALIVE_NULL_DATA: null data packet + * @MLME_STA_KEEPALIVE_GRAT_ARP: gratuitous ARP packet + * @MLME_STA_KEEPALIVE_UNSOLICIT_ARP_RSP: unsolicited ARP response packet + * @MLME_STA_KEEPALIVE_COUNT: number of method options available + */ +enum station_keepalive_method { + MLME_STA_KEEPALIVE_MIN, + MLME_STA_KEEPALIVE_NULL_DATA = 1, + MLME_STA_KEEPALIVE_GRAT_ARP = 2, + MLME_STA_KEEPALIVE_UNSOLICIT_ARP_RSP = 3, + /* keep at the end */ + MLME_STA_KEEPALIVE_COUNT +}; + +/** + * enum station_prefer_bw - Station preferred bandwidth to connect AP + * @STA_PREFER_BW_DEFAULT: Station connects AP with its max bw capability. + * @STA_PREFER_BW_VHT80MHZ: Station connects in VHT 80MHz 2x2 when AP is in + * 160MHz 2x2 + * @STA_PREFER_BW_80MHZ: Station connects in 80MHz when AP is in 160MHz + */ +enum station_prefer_bw { + STA_PREFER_BW_DEFAULT, + STA_PREFER_BW_VHT80MHZ, + STA_PREFER_BW_80MHZ +}; + +/** + * struct wlan_mlme_sta_cfg - MLME STA configuration items + * @sta_keep_alive_period: Sends NULL frame to AP period + * @bss_max_idle_period: BSS max idle period + * @tgt_gtx_usr_cfg: Target gtx user config + * @pmkid_modes: Enable PMKID modes + * @wait_cnf_timeout: Wait assoc cnf timeout + * @sta_miracast_mcc_rest_time: STA+MIRACAST(P2P) MCC rest time + * @dot11p_mode: Set 802.11p mode + * @fils_max_chan_guard_time: Set maximum channel guard time + * @current_rssi: Current rssi + * @deauth_retry_cnt: Deauth retry count + * @sta_prefer_80mhz_over_160mhz: Set Sta preference to connect in 80HZ/160HZ + * @ignore_peer_erp_info: Ignore peer information + * @enable_5g_ebt: Set default 5G early beacon termination + * @deauth_before_connection: Send deauth before connection or not + * @enable_go_cts2self_for_sta: Stop NOA and start using cts2self + * @qcn_ie_support: QCN IE support + * @force_rsne_override: Force rsnie override from user + * @single_tid: Set replay counter for all TID + * @allow_tpc_from_ap: Support for AP power constraint + * @sta_keepalive_method: STA keepalive method + * @usr_disabled_roaming: User disable roaming for current connection + * @usr_scan_probe_unicast_ra: User config unicast probe req in scan + * @event_payload: Diagnostic event payload + * @max_li_modulated_dtim_time_ms: Max modulated DTIM time in ms. + * @mlo_same_link_mld_address: Use one of the links same as mld address + * @user_set_link_num: save link num set by vendor command + * @mlo_support_link_num: max number of links that sta mlo supports + * @mlo_support_link_band: band bitmap that sta mlo supports + * @mlo_max_simultaneous_links: number of simultaneous links + * @mlo_prefer_percentage: percentage to boost/reduce mlo scoring + * @mlo_5gl_5gh_mlsr: enable/disable 5GL+5GH MLSR + * @epcs_capability: epcs capability enable or disable flag + * @usr_disable_eht: user disable the eht for STA + * @eht_disable_punct_in_us_lpi: Disable eht puncture in us lpi mode + */ +struct wlan_mlme_sta_cfg { + uint32_t sta_keep_alive_period; + uint32_t bss_max_idle_period; + uint32_t tgt_gtx_usr_cfg; + uint32_t pmkid_modes; + uint32_t wait_cnf_timeout; + uint32_t sta_miracast_mcc_rest_time; + enum dot11p_mode dot11p_mode; + uint8_t fils_max_chan_guard_time; + uint8_t current_rssi; + uint8_t deauth_retry_cnt; + uint8_t sta_prefer_80mhz_over_160mhz; + bool ignore_peer_erp_info; + bool enable_5g_ebt; + bool deauth_before_connection; + bool enable_go_cts2self_for_sta; + bool qcn_ie_support; + bool single_tid; + bool allow_tpc_from_ap; + enum station_keepalive_method sta_keepalive_method; + bool usr_disabled_roaming; + bool usr_scan_probe_unicast_ra; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + host_event_wlan_status_payload_type event_payload; +#endif + uint16_t max_li_modulated_dtim_time_ms; +#ifdef WLAN_FEATURE_11BE_MLO + bool mlo_same_link_mld_address; + uint8_t user_set_link_num; + uint8_t mlo_support_link_num; + uint8_t mlo_support_link_band; + uint8_t mlo_max_simultaneous_links; + int8_t mlo_prefer_percentage; + bool mlo_5gl_5gh_mlsr; +#endif +#ifdef WLAN_FEATURE_11BE + bool epcs_capability; + bool usr_disable_eht; + bool eht_disable_punct_in_us_lpi; +#endif +}; + +/** + * struct wlan_mlme_stats_cfg - MLME stats configuration items + * @stats_periodic_display_time: time after which stats will be printed + * @stats_link_speed_rssi_high: rssi link speed, high + * @stats_link_speed_rssi_med: medium rssi link speed + * @stats_link_speed_rssi_low: rssi link speed, low + * @stats_report_max_link_speed_rssi: report speed limit + */ +struct wlan_mlme_stats_cfg { + uint32_t stats_periodic_display_time; + int stats_link_speed_rssi_high; + int stats_link_speed_rssi_med; + int stats_link_speed_rssi_low; + uint32_t stats_report_max_link_speed_rssi; +}; + +/** + * enum roaming_dfs_channel_type - Allow dfs channel in roam + * @ROAMING_DFS_CHANNEL_DISABLED: Disallow dfs channel in roam + * @ROAMING_DFS_CHANNEL_ENABLED_NORMAL: Allow dfs channel + * @ROAMING_DFS_CHANNEL_ENABLED_ACTIVE: Allow dfs channel with active scan + */ +enum roaming_dfs_channel_type { + ROAMING_DFS_CHANNEL_DISABLED, + ROAMING_DFS_CHANNEL_ENABLED_NORMAL, + ROAMING_DFS_CHANNEL_ENABLED_ACTIVE, +}; + +/** + * struct bss_load_trigger - parameters related to bss load triggered roam + * @enabled: flag to check if this trigger is enabled/disabled + * @threshold: Bss load threshold value above which roaming should start + * @sample_time: Time duration in milliseconds for which the bss load value + * should be monitored + * @rssi_threshold_6ghz: RSSI threshold of the current connected AP below which + * roam should be triggered if bss load threshold exceeds the configured value. + * This value is applicable only when we are connected in 6GHz band. + * @rssi_threshold_5ghz: RSSI threshold of the current connected AP below which + * roam should be triggered if bss load threshold exceeds the configured value. + * This value is applicable only when we are connected in 5GHz band. + * @rssi_threshold_24ghz: RSSI threshold of the current connected AP below which + * roam should be triggered if bss load threshold exceeds the configured value. + * This value is applicable only when we are connected in 2.4 GHz band. + */ +struct bss_load_trigger { + bool enabled; + uint32_t threshold; + uint32_t sample_time; + uint32_t rssi_threshold_6ghz; + int32_t rssi_threshold_5ghz; + int32_t rssi_threshold_24ghz; +}; + +/* + * AKM suites supported by firmware for roaming + */ +#define AKM_FT_SAE 0 +#define AKM_FT_SUITEB_SHA384 1 +#define AKM_FT_FILS 2 +#define AKM_SAE 3 +#define AKM_OWE 4 +#define AKM_SUITEB 5 +#define AKM_SAE_EXT 6 + +#define LFR3_STA_ROAM_DISABLE_BY_P2P BIT(0) +#define LFR3_STA_ROAM_DISABLE_BY_NAN BIT(1) + +/** + * struct fw_scan_channels - Channel details part of VDEV set PCL command + * @num_channels: Number of channels + * @freq: Channel Frequency list + */ +struct fw_scan_channels { + uint8_t num_channels; + uint32_t freq[NUM_CHANNELS]; +}; + +/** + * struct wlan_mlme_lfr_cfg - MLME LMAC fast roaming config + * @mawc_roam_enabled: Enable/Disable MAWC during roaming + * @enable_fast_roam_in_concurrency: Enable LFR roaming on STA during + * concurrency + * @vendor_btm_param: Vendor WTC roam trigger parameters + * @roam_rt_stats: Roam event stats vendor command parameters + * @lfr3_roaming_offload: Enable/disable roam offload feature + * @lfr3_dual_sta_roaming_enabled: Enable/Disable dual sta roaming offload + * feature + * @enable_self_bss_roam: enable roaming to connected BSSID + * @enable_disconnect_roam_offload: enable disassoc/deauth roam scan. + * @enable_idle_roam: flag to enable/disable idle roam in fw + * @idle_roam_rssi_delta: rssi delta of connected ap which is used to + * identify if the AP is idle or in motion + * @idle_roam_inactive_time: Timeout value in seconds, above which the + * connection is idle + * @idle_data_packet_count: data packet count measured during inactive time, + * below which the connection is idle. + * @idle_roam_band: Bands on which idle roam scan is allowed + * @idle_roam_min_rssi: Minimum rssi of connected AP to be considered for + * idle roam trigger. + * @enable_roam_reason_vsie: Enable/disable incluison of roam reason + * vsie in Re(assoc) frame + * @roam_trigger_bitmap: Bitmap of roaming triggers. + * @sta_roam_disable: STA roaming disabled by interfaces + * @roam_info_stats_num: STA roaming information cache number + * @roam_high_rssi_delta: Delta change in high RSSI at which roam scan is + * triggered in 2.4/5 GHz. + * @early_stop_scan_enable: Set early stop scan + * @enable_5g_band_pref: Enable preference for 5G from INI + * @ese_enabled: Enable ESE feature + * @lfr_enabled: Enable fast roaming + * @mawc_enabled: Enable MAWC + * @fast_transition_enabled: Enable fast transition + * @wes_mode_enabled: Enable WES mode + * @mawc_roam_traffic_threshold: Configure traffic threshold + * @mawc_roam_ap_rssi_threshold: Best AP RSSI threshold + * @mawc_roam_rssi_high_adjust: Adjust MAWC roam high RSSI + * @mawc_roam_rssi_low_adjust: Adjust MAWC roam low RSSI + * @roam_rssi_abs_threshold: The min RSSI of the candidate AP + * @rssi_threshold_offset_5g: Lookup threshold offset for 5G band + * @early_stop_scan_min_threshold: Set early stop scan min + * @early_stop_scan_max_threshold: Set early stop scan max + * @roam_dense_traffic_threshold: Dense traffic threshold + * @roam_dense_rssi_thre_offset: Sets dense roam RSSI threshold diff + * @roam_dense_min_aps: Sets minimum number of AP for dense roam + * @roam_bg_scan_bad_rssi_threshold:RSSI threshold for background roam + * @roam_bg_scan_client_bitmap: Bitmap used to identify the scan clients + * @roam_bg_scan_bad_rssi_offset_2g:RSSI threshold offset for 2G to 5G roam + * @roam_data_rssi_threshold_triggers: triggers of bad data RSSI threshold to + * roam + * @roam_data_rssi_threshold: Bad data RSSI threshold to roam + * @rx_data_inactivity_time: Rx duration to check data RSSI + * @adaptive_roamscan_dwell_mode: Sets dwell time adaptive mode + * @per_roam_enable: To enabled/disable PER based roaming in FW + * @per_roam_config_high_rate_th: Rate at which PER based roam will stop + * @per_roam_config_low_rate_th: Rate at which PER based roam will start + * @per_roam_config_rate_th_percent:Percentage at which FW will issue roam scan + * @per_roam_rest_time: FW will wait once it issues a roam scan. + * @per_roam_monitor_time: Min time to be considered as valid scenario + * @per_roam_min_candidate_rssi: Min roamable AP RSSI for candidate selection + * @lfr3_disallow_duration: Disallow duration before roaming + * @lfr3_rssi_channel_penalization: RSSI penalization + * @lfr3_num_disallowed_aps: Max number of AP's to maintain in LCA list + * @rssi_boost_threshold_5g: Boost threshold above which 5 GHz is favored + * @rssi_boost_factor_5g: Factor by which 5GHz RSSI is boosted + * @max_rssi_boost_5g: Maximum boost that can be applied to 5G RSSI + * @rssi_penalize_threshold_5g: Penalize thres above which 5G isn't favored + * @rssi_penalize_factor_5g: Factor by which 5GHz RSSI is penalizeed + * @max_rssi_penalize_5g: Max penalty that can be applied to 5G RSSI + * @max_num_pre_auth: Configure max number of pre-auth + * @roam_preauth_retry_count: Configure the max number of preauth retry + * @roam_preauth_no_ack_timeout: Configure the no ack timeout period + * @roam_rssi_diff: Enable roam based on rssi + * @roam_rssi_diff_6ghz: RSSI diff value to be used for roaming to 6 GHz AP. + * @bg_rssi_threshold: Background RSSI threshold + * @roam_scan_offload_enabled: Enable Roam Scan Offload + * @neighbor_scan_timer_period: Neighbor scan timer period + * @neighbor_scan_min_timer_period: Min neighbor scan timer period + * @neighbor_lookup_rssi_threshold: Neighbor lookup rssi threshold + * @opportunistic_scan_threshold_diff: Set oppurtunistic threshold diff + * @roam_rescan_rssi_diff: Sets RSSI for Scan trigger in firmware + * @neighbor_scan_min_chan_time: Neighbor scan channel min time + * @neighbor_scan_max_chan_time: Neighbor scan channel max time + * @passive_max_channel_time: Passive scan channel max time + * @neighbor_scan_results_refresh_period: Neighbor scan refresh period + * @empty_scan_refresh_period: Empty scan refresh period + * @roam_bmiss_first_bcnt: First beacon miss count + * @roam_bmiss_final_bcnt: Final beacon miss count + * @roam_beacon_rssi_weight: Beacon miss weight + * @roaming_dfs_channel: Allow dfs channel in roam + * @roam_scan_hi_rssi_maxcount: 5GHz maximum scan count + * @roam_scan_hi_rssi_delta: RSSI Delta for scan trigger + * @roam_scan_hi_rssi_delay: Minimum delay between 5GHz scans + * @roam_scan_hi_rssi_ub: Upper bound after which 5GHz scan + * @roam_prefer_5ghz: Prefer roaming to 5GHz Bss + * @roam_intra_band: Prefer roaming within Band + * @enable_adaptive_11r: Flag to check if adaptive 11r ini is enabled + * @tgt_adaptive_11r_cap: Flag to check if target supports adaptive 11r + * @enable_ft_im_roaming: Flag to enable/disable FT-IM roaming + * @roam_scan_home_away_time: The home away time to firmware + * @roam_scan_n_probes: The number of probes to be sent for firmware roaming + * @delay_before_vdev_stop: Wait time for tx complete before vdev stop + * @neighbor_scan_channel_list: Neighbor scan channel list + * @neighbor_scan_channel_list_num: Neighbor scan channel list number + * @enable_lfr_subnet_detection: Enable LFR3 subnet detection + * @ho_delay_for_rx: Delay hand-off by this duration to receive + * @min_delay_btw_roam_scans: Min duration + * @roam_trigger_reason_bitmask: Contains roam_trigger_reasons + * @enable_ftopen: Enable/disable FT open feature + * @roam_force_rssi_trigger: Force RSSI trigger or not + * @bss_load_trig: configuration of BSS load roam trigger + * @roaming_scan_policy: Config roaming scan policy in fw + * @roam_scan_inactivity_time: Device inactivity monitoring time in + * milliseconds for which the device is considered to be inactive. + * @roam_inactive_data_packet_count: Maximum allowed data packets count + * during roam_scan_inactivity_time. + * @fw_akm_bitmap: Supported Akm suites of firmware + * @roam_full_scan_period: Idle period in seconds between two successive + * full channel roam scans + * @saved_freq_list: Valid channel list + * @sae_single_pmk_feature_enabled: Contains value of ini + * sae_single_pmk_feature_enabled + * @rso_user_config: RSO user config + * @enable_ft_over_ds: Enable FT over DS + * @beaconloss_timeout_onwakeup: time in sec to configure FW BMISS event + * during wakeup. + * @beaconloss_timeout_onsleep: time in sec to configure FW BMISS event + * during sleep. + * @roam_ho_delay_config: Roam HO delay value + * @exclude_rm_partial_scan_freq: Exclude the channels in roam full scan that + * are already scanned as part of partial scan. + * @roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full scan + * only on prior discovery of any 6 GHz support in the environment. + * @disconnect_on_nud_roam_invoke_fail: indicate whether disconnect ap when + * roam invoke fail on nud. + * @hs20_btm_offload_disable: indicate whether btm offload is enable/disable + * for Hotspot 2.0 + */ +struct wlan_mlme_lfr_cfg { + bool mawc_roam_enabled; + bool enable_fast_roam_in_concurrency; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + struct wlan_cm_roam_vendor_btm_params vendor_btm_param; + struct wlan_cm_roam_rt_stats roam_rt_stats; + bool lfr3_roaming_offload; + bool lfr3_dual_sta_roaming_enabled; + bool enable_self_bss_roam; + bool enable_disconnect_roam_offload; + bool enable_idle_roam; + uint32_t idle_roam_rssi_delta; + uint32_t idle_roam_inactive_time; + uint32_t idle_data_packet_count; + uint32_t idle_roam_band; + int32_t idle_roam_min_rssi; + bool enable_roam_reason_vsie; + uint32_t roam_trigger_bitmap; + uint32_t sta_roam_disable; + uint32_t roam_info_stats_num; + uint8_t roam_high_rssi_delta; +#endif + bool early_stop_scan_enable; + bool enable_5g_band_pref; +#ifdef FEATURE_WLAN_ESE + bool ese_enabled; +#endif + bool lfr_enabled; + bool mawc_enabled; + bool fast_transition_enabled; + bool wes_mode_enabled; + uint32_t mawc_roam_traffic_threshold; + uint32_t mawc_roam_ap_rssi_threshold; + uint8_t mawc_roam_rssi_high_adjust; + uint8_t mawc_roam_rssi_low_adjust; + uint32_t roam_rssi_abs_threshold; + uint8_t rssi_threshold_offset_5g; + int8_t early_stop_scan_min_threshold; + int8_t early_stop_scan_max_threshold; + uint32_t roam_dense_traffic_threshold; + uint32_t roam_dense_rssi_thre_offset; + uint32_t roam_dense_min_aps; + uint32_t roam_bg_scan_bad_rssi_threshold; + uint32_t roam_bg_scan_client_bitmap; + uint32_t roam_bg_scan_bad_rssi_offset_2g; + uint32_t roam_data_rssi_threshold_triggers; + int32_t roam_data_rssi_threshold; + uint32_t rx_data_inactivity_time; + uint32_t adaptive_roamscan_dwell_mode; + uint32_t per_roam_enable; + uint32_t per_roam_config_high_rate_th; + uint32_t per_roam_config_low_rate_th; + uint32_t per_roam_config_rate_th_percent; + uint32_t per_roam_rest_time; + uint32_t per_roam_monitor_time; + uint32_t per_roam_min_candidate_rssi; + uint32_t lfr3_disallow_duration; + uint32_t lfr3_rssi_channel_penalization; + uint32_t lfr3_num_disallowed_aps; + uint32_t rssi_boost_threshold_5g; + uint32_t rssi_boost_factor_5g; + uint32_t max_rssi_boost_5g; + uint32_t rssi_penalize_threshold_5g; + uint32_t rssi_penalize_factor_5g; + uint32_t max_rssi_penalize_5g; + uint32_t max_num_pre_auth; + uint32_t roam_preauth_retry_count; + uint32_t roam_preauth_no_ack_timeout; + uint8_t roam_rssi_diff; + uint8_t roam_rssi_diff_6ghz; + uint8_t bg_rssi_threshold; + bool roam_scan_offload_enabled; + uint32_t neighbor_scan_timer_period; + uint32_t neighbor_scan_min_timer_period; + uint32_t neighbor_lookup_rssi_threshold; + uint32_t opportunistic_scan_threshold_diff; + uint32_t roam_rescan_rssi_diff; + uint16_t neighbor_scan_min_chan_time; + uint16_t neighbor_scan_max_chan_time; + uint32_t passive_max_channel_time; + uint32_t neighbor_scan_results_refresh_period; + uint32_t empty_scan_refresh_period; + uint8_t roam_bmiss_first_bcnt; + uint8_t roam_bmiss_final_bcnt; + enum roaming_dfs_channel_type roaming_dfs_channel; + uint32_t roam_scan_hi_rssi_maxcount; + uint32_t roam_scan_hi_rssi_delta; + uint32_t roam_scan_hi_rssi_delay; + uint32_t roam_scan_hi_rssi_ub; + bool roam_prefer_5ghz; + bool roam_intra_band; +#ifdef WLAN_ADAPTIVE_11R + bool enable_adaptive_11r; + bool tgt_adaptive_11r_cap; +#endif + bool enable_ft_im_roaming; + uint16_t roam_scan_home_away_time; + uint32_t roam_scan_n_probes; + uint8_t delay_before_vdev_stop; + uint8_t neighbor_scan_channel_list[CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t neighbor_scan_channel_list_num; +#ifdef FEATURE_LFR_SUBNET_DETECTION + bool enable_lfr_subnet_detection; +#endif + uint8_t ho_delay_for_rx; + uint8_t min_delay_btw_roam_scans; + uint32_t roam_trigger_reason_bitmask; + bool enable_ftopen; + bool roam_force_rssi_trigger; + struct bss_load_trigger bss_load_trig; + bool roaming_scan_policy; + uint32_t roam_scan_inactivity_time; + uint32_t roam_inactive_data_packet_count; + uint32_t fw_akm_bitmap; + uint32_t roam_full_scan_period; + struct fw_scan_channels saved_freq_list; +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) + bool sae_single_pmk_feature_enabled; +#endif + struct rso_config_params rso_user_config; + bool enable_ft_over_ds; + uint8_t beaconloss_timeout_onwakeup; + uint8_t beaconloss_timeout_onsleep; + uint16_t roam_ho_delay_config; + uint8_t exclude_rm_partial_scan_freq; + uint8_t roam_full_scan_6ghz_on_disc; + bool disconnect_on_nud_roam_invoke_fail; + bool hs20_btm_offload_disable; +}; + +/** + * struct wlan_mlme_wmm_config - WMM configuration + * @wmm_mode: Enable WMM feature + * @b80211e_is_enabled: Enable 802.11e feature + * @uapsd_mask: what ACs to setup U-APSD for at assoc + */ +struct wlan_mlme_wmm_config { + uint8_t wmm_mode; + bool b80211e_is_enabled; + uint8_t uapsd_mask; +}; + +/** + * struct wlan_mlme_wmm_tspec_element - Default TSPEC parameters + * from the wmm spec + * @inactivity_intv: inactivity_interval as per wmm spec + * @burst_size_def: TS burst size + * @ts_ack_policy: TS Info ACK policy + * @ts_acm_is_off: ACM is off for AC + */ +struct wlan_mlme_wmm_tspec_element { +#ifdef FEATURE_WLAN_ESE + uint32_t inactivity_intv; +#endif + bool burst_size_def; + enum mlme_ts_info_ack_policy ts_ack_policy; + bool ts_acm_is_off; +}; + +/** + * struct wlan_mlme_wmm_ac_vo - Default TSPEC parameters + * for AC_VO + * @dir_ac_vo: TSPEC direction for VO + * @nom_msdu_size_ac_vo: normal MSDU size for VO + * @mean_data_rate_ac_vo: mean data rate for VO + * @min_phy_rate_ac_vo: min PHY rate for VO + * @sba_ac_vo: surplus bandwidth allowance for VO + * @uapsd_vo_srv_intv: Uapsd service interval for voice + * @uapsd_vo_sus_intv: Uapsd suspension interval for voice + */ +struct wlan_mlme_wmm_ac_vo { + uint8_t dir_ac_vo; + uint16_t nom_msdu_size_ac_vo; + uint32_t mean_data_rate_ac_vo; + uint32_t min_phy_rate_ac_vo; + uint16_t sba_ac_vo; + uint32_t uapsd_vo_srv_intv; + uint32_t uapsd_vo_sus_intv; +}; + +/** + * struct wlan_mlme_wmm_ac_vi - Default TSPEC parameters + * for AC_VI + * @dir_ac_vi: TSPEC direction for VI + * @nom_msdu_size_ac_vi: normal MSDU size for VI + * @mean_data_rate_ac_vi: mean data rate for VI + * @min_phy_rate_ac_vi: min PHY rate for VI + * @sba_ac_vi: surplus bandwidth allowance for VI + * @uapsd_vi_srv_intv: Uapsd service interval for VI + * @uapsd_vi_sus_intv: Uapsd suspension interval for VI + */ +struct wlan_mlme_wmm_ac_vi { + uint8_t dir_ac_vi; + uint16_t nom_msdu_size_ac_vi; + uint32_t mean_data_rate_ac_vi; + uint32_t min_phy_rate_ac_vi; + uint16_t sba_ac_vi; + uint32_t uapsd_vi_srv_intv; + uint32_t uapsd_vi_sus_intv; +}; + +/** + * struct wlan_mlme_wmm_ac_be - Default TSPEC parameters + * for AC_BE + * @dir_ac_be: TSPEC direction for BE + * @nom_msdu_size_ac_be: normal MSDU size for BE + * @mean_data_rate_ac_be: mean data rate for BE + * @min_phy_rate_ac_be: min PHY rate for BE + * @sba_ac_be: surplus bandwidth allowance for BE + * @uapsd_be_srv_intv: Uapsd service interval for BE + * @uapsd_be_sus_intv: Uapsd suspension interval for BE + */ +struct wlan_mlme_wmm_ac_be { + uint8_t dir_ac_be; + uint16_t nom_msdu_size_ac_be; + uint32_t mean_data_rate_ac_be; + uint32_t min_phy_rate_ac_be; + uint16_t sba_ac_be; + uint32_t uapsd_be_srv_intv; + uint32_t uapsd_be_sus_intv; + +}; + +/** + * struct wlan_mlme_wmm_ac_bk - Default TSPEC parameters + * for AC_BK + * @dir_ac_bk: TSPEC direction for BK + * @nom_msdu_size_ac_bk: normal MSDU size for BK + * @mean_data_rate_ac_bk: mean data rate for BK + * @min_phy_rate_ac_bk: min PHY rate for BK + * @sba_ac_bk: surplus bandwidth allowance for BK + * @uapsd_bk_srv_intv: Uapsd service interval for BK + * @uapsd_bk_sus_intv: Uapsd suspension interval for BK + */ +struct wlan_mlme_wmm_ac_bk { + uint8_t dir_ac_bk; + uint16_t nom_msdu_size_ac_bk; + uint32_t mean_data_rate_ac_bk; + uint32_t min_phy_rate_ac_bk; + uint16_t sba_ac_bk; + uint32_t uapsd_bk_srv_intv; + uint32_t uapsd_bk_sus_intv; +}; + +/** + * struct wlan_mlme_wmm_params - WMM CFG Items + * @qos_enabled: AP is enabled with 11E + * @wme_enabled: AP is enabled with WMM + * @max_sp_length: Maximum SP Length + * @wsm_enabled: AP is enabled with WSM + * @edca_profile: WMM Edca profile + * @wmm_config: WMM configuration + * @wmm_tspec_element: Default TSPEC parameters + * @ac_vo: Default TSPEC parameters for AC_VO + * @ac_vi: Default TSPEC parameters for AC_VI + * @ac_be: Default TSPEC parameters for AC_BE + * @ac_bk: Default TSPEC parameters for AC_BK + * @delayed_trigger_frm_int: delay int(in ms) of UAPSD auto trigger + */ +struct wlan_mlme_wmm_params { + bool qos_enabled; + bool wme_enabled; + uint8_t max_sp_length; + bool wsm_enabled; + uint32_t edca_profile; + struct wlan_mlme_wmm_config wmm_config; + struct wlan_mlme_wmm_tspec_element wmm_tspec_element; + struct wlan_mlme_wmm_ac_vo ac_vo; + struct wlan_mlme_wmm_ac_vi ac_vi; + struct wlan_mlme_wmm_ac_be ac_be; + struct wlan_mlme_wmm_ac_bk ac_bk; + uint32_t delayed_trigger_frm_int; +}; + +/** + * struct wlan_mlme_weight_config - weight params to + * calculate best candidate + * @rssi_weightage: RSSI weightage + * @ht_caps_weightage: HT caps weightage + * @vht_caps_weightage: VHT caps weightage + * @he_caps_weightage: HE caps weightage + * @chan_width_weightage: Channel width weightage + * @chan_band_weightage: Channel band weightage + * @nss_weightage: NSS weightage + * @beamforming_cap_weightage: Beamforming caps weightage + * @pcl_weightage: PCL weightage + * @channel_congestion_weightage: channel congestion weightage + * @oce_wan_weightage: OCE WAN metrics weightage + * @oce_ap_tx_pwr_weightage: weightage based on ap tx power + * @oce_subnet_id_weightage: weightage based on subnet id + * @sae_pk_ap_weightage:SAE-PK AP weightage + */ +struct wlan_mlme_weight_config { + uint8_t rssi_weightage; + uint8_t ht_caps_weightage; + uint8_t vht_caps_weightage; + uint8_t he_caps_weightage; + uint8_t chan_width_weightage; + uint8_t chan_band_weightage; + uint8_t nss_weightage; + uint8_t beamforming_cap_weightage; + uint8_t pcl_weightage; + uint8_t channel_congestion_weightage; + uint8_t oce_wan_weightage; + uint8_t oce_ap_tx_pwr_weightage; + uint8_t oce_subnet_id_weightage; + uint8_t sae_pk_ap_weightage; +}; + +/** + * struct wlan_mlme_rssi_cfg_score - RSSI params to + * calculate best candidate + * @best_rssi_threshold: Best RSSI threshold + * @good_rssi_threshold: Good RSSI threshold + * @bad_rssi_threshold: Bad RSSI threshold + * @good_rssi_pcnt: Good RSSI Percentage + * @bad_rssi_pcnt: Bad RSSI Percentage + * @good_rssi_bucket_size: Good RSSI Bucket Size + * @bad_rssi_bucket_size: Bad RSSI Bucket Size + * @rssi_pref_5g_rssi_thresh: Preferred 5G RSSI threshold + */ +struct wlan_mlme_rssi_cfg_score { + uint32_t best_rssi_threshold; + uint32_t good_rssi_threshold; + uint32_t bad_rssi_threshold; + uint32_t good_rssi_pcnt; + uint32_t bad_rssi_pcnt; + uint32_t good_rssi_bucket_size; + uint32_t bad_rssi_bucket_size; + uint32_t rssi_pref_5g_rssi_thresh; +}; + +/** + * struct wlan_mlme_roam_scoring_cfg - MLME roam related scoring config + * @enable_scoring_for_roam: Enable/disable BSS Scoring for Roaming + * @roam_trigger_bitmap: bitmap for various roam triggers + * @roam_score_delta: percentage delta in roam score + * @apsd_enabled: Enable automatic power save delivery + * @min_roam_score_delta: Minimum difference between connected AP's and + * candidate AP's roam score to start roaming. + */ +struct wlan_mlme_roam_scoring_cfg { + bool enable_scoring_for_roam; + uint32_t roam_trigger_bitmap; + uint32_t roam_score_delta; + bool apsd_enabled; + uint32_t min_roam_score_delta; +}; + +/* struct wlan_mlme_threshold - Threshold related config items + * @rts_threshold: set rts threshold + * @frag_threshold: set fragmentation threshold + */ +struct wlan_mlme_threshold { + uint32_t rts_threshold; + uint32_t frag_threshold; +}; + +/* struct mlme_max_tx_power_24 - power related items + * @max_len: max length of string + * @len: actual len of string + * @data: Data in string format + */ +struct mlme_max_tx_power_24 { + qdf_size_t max_len; + qdf_size_t len; + uint8_t data[CFG_MAX_TX_POWER_2_4_LEN]; +}; + +/* struct mlme_max_tx_power_5 - power related items + * @max_len: max length of string + * @len: actual len of string + * @data: Data in string format + */ +struct mlme_max_tx_power_5 { + qdf_size_t max_len; + qdf_size_t len; + uint8_t data[CFG_MAX_TX_POWER_5_LEN]; +}; + +/* struct mlme_power_usage - power related items + * @max_len: max length of string + * @len: actual len of string + * @data: Data in string format + */ +struct mlme_power_usage { + qdf_size_t max_len; + qdf_size_t len; + char data[CFG_POWER_USAGE_MAX_LEN]; +}; + +/** + * struct wlan_mlme_power - power related config items + * @max_tx_power_24: max power Tx for 2.4 ghz, this is based on frequencies + * @max_tx_power_5: max power Tx for 5 ghz, this is based on frequencies + * @max_tx_power_24_chan: max power Tx for 2.4 ghz, this is based on channel + * numbers, this is added to parse the ini values to maintain the backward + * compatibility, these channel numbers are converted to frequencies and copied + * to max_tx_power_24 structure, once this conversion is done this structure + * should not be used. + * @max_tx_power_5_chan: max power Tx for 5 ghz, this is based on channel + * numbers, this is added to parse the ini values to maintain the backward + * compatibility, these channel numbers are converted to frequencies and copied + * to max_tx_power_24 structure, once this conversion is done this structure + * should not be used. + * @power_usage: power usage mode, min, max, mod + * @tx_power_2g: limit tx power in 2.4 ghz + * @tx_power_5g: limit tx power in 5 ghz + * @current_tx_power_level: current tx power level + * @local_power_constraint: local power constraint + * @skip_tpe: option to not consider TPE values in 2.4G/5G bands + */ +struct wlan_mlme_power { + struct mlme_max_tx_power_24 max_tx_power_24; + struct mlme_max_tx_power_5 max_tx_power_5; + struct mlme_max_tx_power_24 max_tx_power_24_chan; + struct mlme_max_tx_power_5 max_tx_power_5_chan; + struct mlme_power_usage power_usage; + uint8_t tx_power_2g; + uint8_t tx_power_5g; + uint8_t current_tx_power_level; + uint8_t local_power_constraint; + bool skip_tpe; +}; + +/** + * struct wlan_mlme_timeout - mlme timeout related config items + * @join_failure_timeout: join failure timeout (can be changed in connect req) + * @probe_req_retry_timeout: Probe req retry timeout during join time + * @join_failure_timeout_ori: original value of above join timeout + * @auth_failure_timeout: authenticate failure timeout + * @auth_rsp_timeout: authenticate response timeout + * @assoc_failure_timeout: assoc failure timeout + * @reassoc_failure_timeout: re-assoc failure timeout + * @olbc_detect_timeout: OLBC detect timeout + * @addts_rsp_timeout: ADDTS rsp timeout value + * @heart_beat_threshold: Heart beat threshold + * @ap_keep_alive_timeout: AP keep alive timeout value + * @ap_link_monitor_timeout: AP link monitor timeout value + * @wmi_wq_watchdog_timeout: timeout period for wmi watchdog bite + * @sae_auth_failure_timeout: SAE authentication failure timeout + */ +struct wlan_mlme_timeout { + uint32_t join_failure_timeout; + uint32_t probe_req_retry_timeout; + uint32_t join_failure_timeout_ori; + uint32_t auth_failure_timeout; + uint32_t auth_rsp_timeout; + uint32_t assoc_failure_timeout; + uint32_t reassoc_failure_timeout; + uint32_t olbc_detect_timeout; + uint32_t addts_rsp_timeout; + uint32_t heart_beat_threshold; + uint32_t ap_keep_alive_timeout; + uint32_t ap_link_monitor_timeout; + uint32_t wmi_wq_watchdog_timeout; + uint32_t sae_auth_failure_timeout; +}; + +/** + * struct wlan_mlme_oce - OCE related config items + * @enable_bcast_probe_rsp: enable broadcast probe response + * @oce_sta_enabled: enable/disable oce feature for sta + * @oce_sap_enabled: enable/disable oce feature for sap + * @fils_enabled: enable/disable fils support + * @feature_bitmap: oce feature bitmap + * + */ +struct wlan_mlme_oce { + bool enable_bcast_probe_rsp; + bool oce_sta_enabled; + bool oce_sap_enabled; + bool fils_enabled; + uint8_t feature_bitmap; +}; + +/** + * enum wep_key_id - values passed to get/set wep default keys + * @MLME_WEP_DEFAULT_KEY_1: wep default key 1 + * @MLME_WEP_DEFAULT_KEY_2: wep default key 2 + * @MLME_WEP_DEFAULT_KEY_3: wep default key 3 + * @MLME_WEP_DEFAULT_KEY_4: wep default key 4 + */ +enum wep_key_id { + MLME_WEP_DEFAULT_KEY_1 = 0, + MLME_WEP_DEFAULT_KEY_2, + MLME_WEP_DEFAULT_KEY_3, + MLME_WEP_DEFAULT_KEY_4 +}; + +/** + * struct wlan_mlme_wep_cfg - WEP related configs + * @is_privacy_enabled: Flag to check if encryption is enabled + * @is_shared_key_auth: Flag to check if the auth type is shared key + * @is_auth_open_system: Flag to check if the auth type is open + * @auth_type: Authentication type value + * @wep_default_key_id: Default WEP key id + */ +struct wlan_mlme_wep_cfg { + bool is_privacy_enabled; + bool is_shared_key_auth; + bool is_auth_open_system; + uint8_t auth_type; + uint8_t wep_default_key_id; +}; + +/** + * struct wlan_mlme_wifi_pos_cfg - WIFI POS configs + * @fine_time_meas_cap: fine timing measurement capability information + * @oem_6g_support_disable: oem is 6Ghz disabled if set + */ +struct wlan_mlme_wifi_pos_cfg { + uint32_t fine_time_meas_cap; + bool oem_6g_support_disable; +}; + +#define MLME_SET_BIT(value, bit_offset) ((value) |= (1 << (bit_offset))) +#define MLME_CLEAR_BIT(value, bit_offset) ((value) &= ~(1 << (bit_offset))) + +/* Mask to check if BTM offload is enabled/disabled*/ +#define BTM_OFFLOAD_ENABLED_MASK 0x01 + +#define BTM_OFFLOAD_CONFIG_BIT_0 0 +#define BTM_OFFLOAD_CONFIG_BIT_8 8 +#define BTM_OFFLOAD_CONFIG_BIT_7 7 + +/** + * struct wlan_mlme_btm - BTM related configs + * @prefer_btm_query: flag to prefer btm query over 11k + * @abridge_flag: set this flag to enable firmware to sort candidates based on + * roam score rather than selecting preferred APs. + * @btm_offload_config: configure btm offload + * @btm_solicited_timeout: configure timeout value for waiting BTM request + * @btm_max_attempt_cnt: configure maximum attempt for sending BTM query to ESS + * @btm_sticky_time: configure Stick time after roaming to new AP by BTM + * @rct_validity_timer: Timeout values for roam cache table entries + * @disassoc_timer_threshold: Disassociation timeout till which roam scan need + * not be triggered + * @btm_query_bitmask: Bitmask to send BTM query with candidate list on + * various roam + * @btm_trig_min_candidate_score: Minimum score to consider the AP as candidate + * when the roam trigger is BTM. + */ +struct wlan_mlme_btm { + bool prefer_btm_query; + bool abridge_flag; + uint32_t btm_offload_config; + uint32_t btm_solicited_timeout; + uint32_t btm_max_attempt_cnt; + uint32_t btm_sticky_time; + uint32_t rct_validity_timer; + uint32_t disassoc_timer_threshold; + uint32_t btm_query_bitmask; + uint32_t btm_trig_min_candidate_score; +}; + +/** + * struct wlan_mlme_fe_wlm - WLM related configs + * @latency_enable: Flag to check if latency is enabled + * @latency_reset: Flag to check if latency reset is enabled + * @latency_level: WLM latency level + * @latency_flags: WLM latency flags setting + * @latency_host_flags: WLM latency host flags setting + * @multi_client_ll_support: To check whether host support multi client feature + */ +struct wlan_mlme_fe_wlm { + bool latency_enable; + bool latency_reset; + uint8_t latency_level; + uint32_t latency_flags[MLME_NUM_WLM_LATENCY_LEVEL]; + uint32_t latency_host_flags[MLME_NUM_WLM_LATENCY_LEVEL]; +#ifdef MULTI_CLIENT_LL_SUPPORT + bool multi_client_ll_support; +#endif +}; + +/** + * struct wlan_mlme_fe_rrm - RRM related configs + * @rrm_enabled: Flag to check if RRM is enabled for STA + * @sap_rrm_enabled: Flag to check if RRM is enabled for SAP + * @rrm_rand_interval: RRM randomization interval + * @rm_capability: RM enabled capabilities IE + */ +struct wlan_mlme_fe_rrm { + bool rrm_enabled; + bool sap_rrm_enabled; + uint8_t rrm_rand_interval; + uint8_t rm_capability[MLME_RMENABLEDCAP_MAX_LEN]; +}; + +#ifdef MWS_COEX +/** + * struct wlan_mlme_mwc - MWC related configs + * @mws_coex_4g_quick_tdm: bitmap to set mws-coex 5g-nr power limit + * @mws_coex_5g_nr_pwr_limit: bitmap to set mws-coex 5g-nr power limit + * @mws_coex_pcc_channel_avoid_delay: PCC avoidance delay in seconds + * @mws_coex_scc_channel_avoid_delay: SCC avoidance delay in seconds + **/ +struct wlan_mlme_mwc { + uint32_t mws_coex_4g_quick_tdm; + uint32_t mws_coex_5g_nr_pwr_limit; + uint32_t mws_coex_pcc_channel_avoid_delay; + uint32_t mws_coex_scc_channel_avoid_delay; +}; +#else +struct wlan_mlme_mwc { +}; +#endif + +/** + * enum mlme_reg_srd_master_modes - Bitmap of SRD master modes supported + * @MLME_SRD_MASTER_MODE_SAP: SRD master mode for SAP + * @MLME_SRD_MASTER_MODE_P2P_GO: SRD master mode for P2P-GO + * @MLME_SRD_MASTER_MODE_NAN: SRD master mode for NAN + */ +enum mlme_reg_srd_master_modes { + MLME_SRD_MASTER_MODE_SAP = 1, + MLME_SRD_MASTER_MODE_P2P_GO = 2, + MLME_SRD_MASTER_MODE_NAN = 4, +}; + +/** + * struct wlan_mlme_reg - REG related configs + * @self_gen_frm_pwr: self-generated frame power in tx chain mask + * for CCK rates + * @etsi_srd_chan_in_master_mode: etsi srd chan in master mode + * @fcc_5dot9_ghz_chan_in_master_mode: fcc 5.9 GHz chan in master mode + * @restart_beaconing_on_ch_avoid: restart beaconing on ch avoid + * @indoor_channel_support: indoor channel support + * @scan_11d_interval: scan 11d interval + * @valid_channel_freq_list: array for valid channel list + * @valid_channel_list_num: valid channel list number + * @enable_11d_in_world_mode: Whether to enable 11d scan in world mode or not + * @avoid_acs_freq_list: List of the frequencies which need to be avoided + * during acs + * @avoid_acs_freq_list_num: Number of the frequencies to be avoided during acs + * @ignore_fw_reg_offload_ind: Ignore fw regulatory offload indication + * @enable_pending_chan_list_req: enables/disables scan channel + * list command to FW till the current scan is complete. + * @retain_nol_across_regdmn_update: Retain the NOL list across the regdomain. + * @enable_nan_on_indoor_channels: Enable nan on Indoor channels + * @enable_6ghz_sp_pwrmode_supp: Enable 6 GHz SP mode support + * @afc_disable_timer_check: Disable AFC timer check + * @afc_disable_request_id_check: Disable AFC request id check + * @is_afc_reg_noaction: Whether no action to AFC power event + * @coex_unsafe_chan_nb_user_prefer: Honor coex unsafe freq event from firmware + * or not + * @coex_unsafe_chan_reg_disable: To disable reg channels for received coex + * unsafe channels list + */ +struct wlan_mlme_reg { + uint32_t self_gen_frm_pwr; + uint8_t etsi_srd_chan_in_master_mode; + bool fcc_5dot9_ghz_chan_in_master_mode; + enum restart_beaconing_on_ch_avoid_rule + restart_beaconing_on_ch_avoid; + bool indoor_channel_support; + uint32_t scan_11d_interval; + uint32_t valid_channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; + uint32_t valid_channel_list_num; + bool enable_11d_in_world_mode; +#ifdef SAP_AVOID_ACS_FREQ_LIST + uint16_t avoid_acs_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t avoid_acs_freq_list_num; +#endif + bool ignore_fw_reg_offload_ind; + bool enable_pending_chan_list_req; + bool retain_nol_across_regdmn_update; + bool enable_nan_on_indoor_channels; +#if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_BAND_6GHZ) + bool enable_6ghz_sp_pwrmode_supp; + bool afc_disable_timer_check; + bool afc_disable_request_id_check; + bool is_afc_reg_noaction; +#endif +#ifdef FEATURE_WLAN_CH_AVOID_EXT + uint32_t coex_unsafe_chan_nb_user_prefer; + bool coex_unsafe_chan_reg_disable; +#endif +}; + +#define IOT_AGGR_INFO_MAX_NUM 32 + +/** + * struct wlan_iot_aggr - IOT related AGGR rule + * + * @oui: OUI for the rule + * @oui_len: length of the OUI + * @ampdu_sz: max aggregation size in no. of MPDUs + * @amsdu_sz: max aggregation size in no. of MSDUs + */ +struct wlan_iot_aggr { + uint8_t oui[OUI_LENGTH]; + uint32_t oui_len; + uint32_t ampdu_sz; + uint32_t amsdu_sz; +}; + +/** + * struct wlan_mlme_iot - IOT related CFG Items + * + * @aggr: aggr rules + * @aggr_num: number of the configured aggr rules + */ +struct wlan_mlme_iot { + struct wlan_iot_aggr aggr[IOT_AGGR_INFO_MAX_NUM]; + uint32_t aggr_num; +}; + +/** + * struct wlan_mlme_cfg - MLME config items + * @chainmask_cfg: VHT chainmask related cfg items + * @edca_params: edca related CFG items + * @gen: Generic CFG items + * @ht_caps: HT related CFG Items + * @he_caps: HE related cfg items + * @eht_caps: EHT related cfg items + * @lfr: LFR related CFG Items + * @ibss: IBSS related CFG items + * @obss_ht40:obss ht40 CFG Items + * @mbo_cfg: Multiband Operation related CFG items + * @vht_caps: VHT related CFG Items + * @qos_mlme_params: QOS CFG Items + * @rates: Rates related cfg items + * @product_details: product details related CFG Items + * @dfs_cfg: DFS related CFG Items + * @sap_protection_cfg: SAP erp protection related CFG items + * @sap_cfg: sap CFG items + * @nss_chains_ini_cfg: Per vdev nss, chains related CFG items + * @sta: sta CFG Items + * @stats: stats CFG Items + * @roam_scoring: BSS Scoring related CFG Items + * @oce: OCE related CFG items + * @threshold: threshold related cfg items + * @timeouts: mlme timeout related CFG items + * @twt_cfg: TWT CFG Items + * @power: power related items + * @acs: ACS related CFG items + * @feature_flags: Feature flag config items + * @ps_params: Powersave related ini configs + * @wep_params: WEP related config items + * @wifi_pos_cfg: WIFI POS config + * @wmm_params: WMM related CFG & INI Items + * @wps_params: WPS related CFG itmes + * @btm: BTM related CFG itmes + * @wlm_config: WLM related CFG items + * @rrm_config: RRM related CFG items + * @mwc: MWC related CFG items + * @dot11_mode: dot11 mode supported + * @reg: REG related CFG itmes + * @trig_score_delta: Roam score delta value for various roam triggers + * @trig_min_rssi: Expected minimum RSSI value of candidate AP for + * various roam triggers + * @ratemask_cfg: ratemask configuration + * @iot: IOT related CFG items + * @connection_roaming_ini_flag: To indicate whether connection_roaming related + * ini file is present or not. + * @eml_cap: EML capability subfield present in ML IE common info + * @dynamic_nss_chains_support : intersection of host and fw capability of + * dynamic NSS chain support + */ +struct wlan_mlme_cfg { + struct wlan_mlme_chainmask chainmask_cfg; + struct wlan_mlme_edca_params edca_params; + struct wlan_mlme_generic gen; + struct wlan_mlme_ht_caps ht_caps; +#ifdef WLAN_FEATURE_11AX + struct wlan_mlme_he_caps he_caps; +#endif +#ifdef WLAN_FEATURE_11BE + struct wlan_mlme_eht_caps eht_caps; +#endif + struct wlan_mlme_lfr_cfg lfr; + struct wlan_mlme_obss_ht40 obss_ht40; + struct wlan_mlme_mbo mbo_cfg; + struct wlan_mlme_vht_caps vht_caps; + struct wlan_mlme_qos qos_mlme_params; + struct wlan_mlme_rates rates; + struct wlan_mlme_product_details_cfg product_details; + struct wlan_mlme_dfs_cfg dfs_cfg; + struct wlan_mlme_sap_protection sap_protection_cfg; + struct wlan_mlme_cfg_sap sap_cfg; + struct wlan_mlme_nss_chains nss_chains_ini_cfg; + struct wlan_mlme_sta_cfg sta; + struct wlan_mlme_stats_cfg stats; + struct wlan_mlme_roam_scoring_cfg roam_scoring; + struct wlan_mlme_oce oce; + struct wlan_mlme_threshold threshold; + struct wlan_mlme_timeout timeouts; + struct wlan_mlme_cfg_twt twt_cfg; + struct wlan_mlme_power power; + struct wlan_mlme_acs acs; + struct wlan_mlme_feature_flag feature_flags; + struct wlan_mlme_powersave ps_params; + struct wlan_mlme_wep_cfg wep_params; + struct wlan_mlme_wifi_pos_cfg wifi_pos_cfg; + struct wlan_mlme_wmm_params wmm_params; + struct wlan_mlme_wps_params wps_params; + struct wlan_mlme_btm btm; + struct wlan_mlme_fe_wlm wlm_config; + struct wlan_mlme_fe_rrm rrm_config; + struct wlan_mlme_mwc mwc; + struct wlan_mlme_dot11_mode dot11_mode; + struct wlan_mlme_reg reg; + struct roam_trigger_score_delta trig_score_delta[NUM_OF_ROAM_TRIGGERS]; + struct roam_trigger_min_rssi trig_min_rssi[NUM_OF_ROAM_MIN_RSSI]; + struct wlan_mlme_ratemask ratemask_cfg; + struct wlan_mlme_iot iot; + bool connection_roaming_ini_flag; + struct wlan_mlme_eml_cap eml_cap; + bool dynamic_nss_chains_support; +}; + +/** + * struct mlme_pmk_info - SAE Roaming using single pmk info + * @pmk: pmk + * @pmk_len: pmk length + * @spmk_timeout_period: Time to generate new SPMK in seconds. + * @spmk_timestamp: System timestamp at which the Single PMK entry was added. + */ +struct mlme_pmk_info { + uint8_t pmk[CFG_MAX_PMK_LEN]; + uint8_t pmk_len; + uint16_t spmk_timeout_period; + qdf_time_t spmk_timestamp; +}; + +/** + * struct wlan_mlme_sae_single_pmk - SAE Roaming using single pmk configuration + * structure + * @sae_single_pmk_ap: Current connected AP has VSIE or not + * @pmk_info: pmk information + */ +struct wlan_mlme_sae_single_pmk { + bool sae_single_pmk_ap; + struct mlme_pmk_info pmk_info; +}; + +#define ROAM_FRAME_INFO_FRAME_TYPE_EXT 3 +/** + * struct mlme_roam_debug_info - Roam debug information storage structure. + * @trigger: Roam trigger related data + * @scan: Roam scan related data structure. + * @result: Roam result parameters. + * @data_11kv: Neighbor report/BTM parameters. + * @btm_rsp: BTM response information + * @roam_init_info: Roam initial info + * @roam_msg_info: roam related message information + * @frame_info: Information related to mgmt/eapol frames exchanged + * during roaming. + */ +struct mlme_roam_debug_info { + struct wmi_roam_trigger_info trigger; + struct wmi_roam_scan_data scan; + struct wmi_roam_result result; + struct wmi_neighbor_report_data data_11kv; + struct roam_btm_response_data btm_rsp; + struct roam_initial_data roam_init_info; + struct roam_msg_info roam_msg_info; + struct roam_frame_info frame_info[WLAN_ROAM_MAX_FRAME_INFO]; +}; + +/** + * struct wlan_change_bi - Message struct to update beacon interval + * @message_type: type of message + * @length: length of message + * @beacon_interval: beacon interval to update to (seconds) + * @bssid: BSSID of vdev + * @session_id: session ID of vdev + */ +struct wlan_change_bi { + uint16_t message_type; + uint16_t length; + uint16_t beacon_interval; + struct qdf_mac_addr bssid; + uint8_t session_id; +}; + +#ifdef FEATURE_SET +/** + * enum wlan_mlme_iface_combinations - Iface combinations + * @MLME_IFACE_STA_P2P_SUPPORT: STA + P2P concurrency bit + * @MLME_IFACE_STA_SAP_SUPPORT: STA + SAP concurrency bit + * @MLME_IFACE_STA_NAN_SUPPORT: STA + NAN concurrency bit + * @MLME_IFACE_STA_TDLS_SUPPORT: STA + TDLS concurrency bit + * @MLME_IFACE_STA_DUAL_P2P_SUPPORT: STA + P2P + P2P concurrency bit + * @MLME_IFACE_STA_SAP_P2P_SUPPORT: STA + SAP + P2P concurrency bit + * @MLME_IFACE_STA_SAP_NAN_SUPPORT: STA + SAP + NAN concurrency bit + * @MLME_IFACE_STA_P2P_NAN_SUPPORT: STA + P2P + NAN concurrency bit + * @MLME_IFACE_STA_P2P_TDLS_SUPPORT: STA + P2P + TDLS concurrency bit + * @MLME_IFACE_STA_SAP_TDLS_SUPPORT: STA + SAP + TDLS concurrency bit + * @MLME_IFACE_STA_NAN_TDLS_SUPPORT: STA + NAN + TDLS concurrency bit + * @MLME_IFACE_STA_SAP_P2P_TDLS_SUPPORT: STA + SAP + P2P + TDLS concurrency bit + * @MLME_IFACE_STA_SAP_NAN_TDLS_SUPPORT: STA + SAP + NAN + TDLS concurrency bit + * @MLME_IFACE_STA_P2P_P2P_TDLS_SUPPORT: STA + P2P + P2P + TDLS concurrency bit + * @MLME_IFACE_STA_P2P_NAN_TDLS_SUPPORT: STA + P2P + NAN + TDLS concurrency bit + */ +enum wlan_mlme_iface_combinations { + MLME_IFACE_STA_P2P_SUPPORT = 0x1, + MLME_IFACE_STA_SAP_SUPPORT = 0x2, + MLME_IFACE_STA_NAN_SUPPORT = 0x4, + MLME_IFACE_STA_TDLS_SUPPORT = 0x8, + MLME_IFACE_STA_DUAL_P2P_SUPPORT = 0x10, + MLME_IFACE_STA_SAP_P2P_SUPPORT = 0x20, + MLME_IFACE_STA_SAP_NAN_SUPPORT = 0x40, + MLME_IFACE_STA_P2P_NAN_SUPPORT = 0x80, + MLME_IFACE_STA_P2P_TDLS_SUPPORT = 0x100, + MLME_IFACE_STA_SAP_TDLS_SUPPORT = 0x200, + MLME_IFACE_STA_NAN_TDLS_SUPPORT = 0x400, + MLME_IFACE_STA_SAP_P2P_TDLS_SUPPORT = 0x800, + MLME_IFACE_STA_SAP_NAN_TDLS_SUPPORT = 0x1000, + MLME_IFACE_STA_P2P_P2P_TDLS_SUPPORT = 0x2000, + MLME_IFACE_STA_P2P_NAN_TDLS_SUPPORT = 0x4000, +}; + +/** + * struct wlan_mlme_features - Mlme feature set structure + * @enable_wifi_optimizer: indicates wifi optimizer is enabled or disabled + * @sap_max_num_clients: maximum number of SoftAP clients + * @roaming_high_cu_roam_trigger: Roaming high CPU trigger enabled or disabled + * @roaming_emergency_trigger: Roaming emergency trigger enabled or disabled + * @roaming_btm_trihgger: Roaming btm trigger enabled or disabled + * @roaming_idle_trigger: Roaming idle trigger enabled or disabled + * @roaming_wtc_trigger: Roaming wtc trigger enabled or disabled + * @roaming_btcoex_trigger: Roaming btcoex trigger enabled or disabled + * @roaming_btw_wpa_wpa2: Roaming btw wpa wpa2 enabled or disabled + * @roaming_manage_chan_list_api: Roaming manage chan list api enabled or + * disabled + * @roaming_adaptive_11r: Roaming adaptive 11r enabled or disabled + * @roaming_ctrl_api_get_set: Roaming ctrl api get set enabled or disabled + * @roaming_ctrl_api_reassoc: Roaming ctrl api reassoc enabled or disabled + * @roaming_ctrl_get_cu: Roaming ctrl get cu enabled or disabled + * @vendor_req_1_version: Vendor requirement version 1 + * @vendor_req_2_version: Vendor requirement version 2 + * @enable2x2: Enable 2x2 + * @iface_combinations: iface combination bitmask + */ +struct wlan_mlme_features { + bool enable_wifi_optimizer; + uint8_t sap_max_num_clients; + bool roaming_high_cu_roam_trigger; + bool roaming_emergency_trigger; + bool roaming_btm_trihgger; + bool roaming_idle_trigger; + bool roaming_wtc_trigger; + bool roaming_btcoex_trigger; + bool roaming_btw_wpa_wpa2; + bool roaming_manage_chan_list_api; + bool roaming_adaptive_11r; + bool roaming_ctrl_api_get_set; + bool roaming_ctrl_api_reassoc; + bool roaming_ctrl_get_cu; + WMI_HOST_VENDOR1_REQ1_VERSION vendor_req_1_version; + WMI_HOST_VENDOR1_REQ2_VERSION vendor_req_2_version; + bool enable2x2; + uint32_t iface_combinations; +}; +#endif + +/** + * enum host_concurrent_ap_policy - Host concurrent AP policy value + * @HOST_CONCURRENT_AP_POLICY_UNSPECIFIED: Unspecified concurrent policy value + * @HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO: Gaming audio concurrent policy value + * @HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: Lossless audio + * concurrent streaming policy value + * @HOST_CONCURRENT_AP_POLICY_XR: Concurrent policy to meet AR/VR requirements. + */ +enum host_concurrent_ap_policy { + HOST_CONCURRENT_AP_POLICY_UNSPECIFIED = 0, + HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO = 1, + HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING = 2, + HOST_CONCURRENT_AP_POLICY_XR = 3 +}; + +/** + * enum ll_ap_type - low latency AP type + * @LL_AP_TYPE_HT: low latency AP type high throughput + * @LL_AP_TYPE_LT: low latency AP type low latency + * @LL_AP_TYPE_ANY: low latency AP type any + */ +enum ll_ap_type { + LL_AP_TYPE_HT = 0, + LL_AP_TYPE_LT = 1, + LL_AP_TYPE_ANY = 2, +}; + +/** + * struct sap_ch_info - Structure holding all the information required to make + * a decision for the best operating channel based on dfs formula. + * @chan_freq: Channel frequency found in scanresult + * @bss_count: Bss found in scanresult for this channel + * @rssi_agr: Max value of rssi among all BSS(es) from scan result + * for this channel. + * @weight: Weightage of this channel + * @weight_copy: copy of the original weight + * @valid: Is this a valid center frequency for regulatory domain + * @weight_calc_done: Weight calculation done for this channel + */ +struct sap_ch_info { + uint32_t chan_freq; + uint16_t bss_count; + int32_t rssi_agr; + uint32_t weight; + uint32_t weight_copy; + bool valid; + bool weight_calc_done; +}; + +/** + * struct sap_sel_ch_info - Wrapper of sap_ch_info structure. + * @ch_info: Ptr to the channel information. + * @num_ch: Total num of channels. + */ +struct sap_sel_ch_info { + struct sap_ch_info *ch_info; + uint8_t num_ch; +}; + +/** + * enum mlme_peer_oper_mode_ind - Peer mode indication type + * @mlme_peer_ind_smps: spatial multiplexing power save + * @mlme_peer_ind_omn: Operating mode notification + * @mlme_peer_ind_omi: Operating mode indication + */ +enum mlme_peer_oper_mode_ind { + mlme_peer_ind_smps, + mlme_peer_ind_omn, + mlme_peer_ind_omi, +}; + +/** + * struct peer_oper_mode_event - structure for peer oper mode indication data + * @peer_mac_address: mac address of peer + * @ind_type: indication type of type @enum mlme_peer_oper_mode_ind + * @new_rxnss: New Rx NSS + * @new_bw: New bandwidth + * @new_txnss: New Tx NSS, valid only for mlme_peer_ind_omi + * @new_disablemu: Disabled MU mode, valid only for mlme_peer_ind_omi + */ +struct peer_oper_mode_event { + struct qdf_mac_addr peer_mac_address; + uint32_t ind_type; + uint32_t new_rxnss; + uint32_t new_bw; + uint32_t new_txnss; + uint32_t new_disablemu; +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_twt_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_twt_public_struct.h new file mode 100644 index 0000000000..db41386822 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_twt_public_struct.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for MLME TWT functionality. + */ + +#ifndef _WLAN_MLME_TWT_PUBLIC_STRUCT_H_ +#define _WLAN_MLME_TWT_PUBLIC_STRUCT_H_ + +#include + +#ifdef WLAN_SUPPORT_TWT +/** + * struct twt_session_info - TWT session related parameters + * @dialog_id: TWT session dialog id + * @state: TWT session state + * @setup_done: TWT session setup is complete + * @active_cmd: bitmap to indicate which command is + * in progress. Bits are provided by enum wlan_twt_commands. + */ +struct twt_session_info { + uint8_t dialog_id; + uint8_t state; + bool setup_done; + enum wlan_twt_commands active_cmd; +}; + +/** + * struct twt_context - TWT context + * @peer_capability: TWT peer capability bitmap. Refer enum + * wlan_twt_capabilities for representation. + * @num_twt_sessions: Maximum supported TWT sessions. + * @session_info: TWT session related parameters for each session + */ +struct twt_context { + uint8_t peer_capability; + uint8_t num_twt_sessions; + struct twt_session_info session_info[WLAN_MAX_TWT_SESSIONS_PER_PEER]; +}; + +#ifdef FEATURE_SET +/** + * struct wlan_twt_features - TWT features info + * @enable_twt: Enable TWT + * @enable_twt_requester: Enable TWT requester + * @enable_twt_broadcast: Enable TWT broadcast + * @enable_twt_flexible: Enable flexible TWT + */ +struct wlan_twt_features { + bool enable_twt; + bool enable_twt_requester; + bool enable_twt_broadcast; + bool enable_twt_flexible; +}; +#endif /* FEATURE_SET */ +#endif /* WLAN_SUPPORT_TWT */ +#endif /* _WLAN_MLME_TWT_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_twt_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_twt_ucfg_api.h new file mode 100644 index 0000000000..21b34cb201 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_twt_ucfg_api.h @@ -0,0 +1,905 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declare UCFG APIs for TWT exposed by the mlme component + */ + +#ifndef _WLAN_MLME_TWT_UCFG_API_H_ +#define _WLAN_MLME_TWT_UCFG_API_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_FEATURE_11AX) && \ + defined(WLAN_TWT_CONV_SUPPORTED) +static inline +QDF_STATUS ucfg_mlme_init_twt_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +ucfg_mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_responder(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_responder(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +ucfg_mlme_is_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return 0; +} + +static inline void +ucfg_mlme_set_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, bool is_set) +{} + +static inline +void ucfg_mlme_set_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_session_state state) +{} + +static inline enum wlan_twt_session_state +ucfg_mlme_get_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_reset_twt_active_cmd(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + return QDF_STATUS_E_FAILURE; +} + +#elif defined(WLAN_SUPPORT_TWT) && defined(WLAN_FEATURE_11AX) +/** + * ucfg_mlme_get_twt_requestor() - Get twt requestor + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_set_twt_requestor() - Set twt requestor + * @psoc: pointer to psoc object + * @val: value that needs to set to this config + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_get_twt_responder() - Get twt responder + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_twt_responder(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_set_twt_responder() - Set twt responder + * @psoc: pointer to psoc object + * @val: value that needs to set to this config + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_twt_responder(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_get_twt_congestion_timeout() - Get twt congestion timeout + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_set_twt_congestion_timeout() - Set twt congestion timeout + * @psoc: pointer to psoc object + * @val: value that needs to set to this config + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t val); + +/** + * ucfg_mlme_is_twt_enabled() - Get global twt config support + * @psoc: pointer to psoc object + * + * Return: True if TWT is enabled else false. + */ +static inline bool +ucfg_mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return mlme_is_twt_enabled(psoc); +} + +/** + * ucfg_mlme_set_enable_twt() - Set global twt config support + * @psoc: pointer to psoc object + * @val: value that needs to set to this config + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_enable_twt(struct wlan_objmgr_psoc *psoc, + bool val); + +/* + * ucfg_mlme_get_twt_bcast_requestor() - Get twt requestor enabled + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_twt_bcast_requestor(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_get_twt_bcast_responder() - Get twt responder enabled + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_twt_bcast_responder(struct wlan_objmgr_psoc *psoc, + bool *val); +/* + * 1. If both of the new service caps + * WMI_SERVICE_BROADCAST_TWT_REQUESTER And + * WMI_SERVICE_BROADCAST_TWT_RESPONDER are enabled then the old + * WMI_SERVICE_BROADCAST_TWT will be set to 1. + * + * 2.a. If any of the new service caps in case of new firmware: + * WMI_SERVICE_BROADCAST_TWT_REQUESTER And + * WMI_SERVICE_BROADCAST_TWT_RESPONDER is DISABLED then the old + * WMI_SERVICE_BROADCAST_TWT will be set to 0. + * + * 2.b In case of new firmware wants to disable broadcast TWT: + * all 3 WMI_SERVICE_BROADCAST_TWT_REQUESTER, + * WMI_SERVICE_BROADCAST_TWT_RESPONDER & + * WMI_SERVICE_BROADCAST_TWT will be disabled. + * + * 2.c IN case of old firmware: + * WMI_SERVICE_BROADCAST_TWT will be 1 and + * WMI_SERVICE_BROADCAST_TWT_REQUESTER, + * WMI_SERVICE_BROADCAST_TWT_RESPONDER will be 0. + * + * bcast_requestor_cfg/bcast_responder_cfg is intersection of + * "enable_twt", "twt_bcast_req_resp_config" ini and above target + * service cap combination. + */ + +/** + * ucfg_mlme_set_twt_bcast_requestor() - Set Global twt bcast requestor support + * @psoc: pointer to psoc object + * @val: Value to be set to config + * + * The caller of ucfg_mlme_set_twt_bcast_requestor() updates with the + * intersection of "enable_twt", "twt_bcast_req_resp_config" ini and the + * WMI_SERVICE_BROADCAST_TWT_REQUESTOR, WMI_SERVICE_BROADCAST_TWT + * combination. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_twt_bcast_requestor(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_set_twt_bcast_responder() - Set Global twt bcast responder support + * @psoc: pointer to psoc object + * @val: Value to be set to config + * + * The caller of ucfg_mlme_set_twt_bcast_requestor() updates with the + * intersection of "enable_twt", "twt_bcast_req_resp_config" ini and the + * WMI_SERVICE_BROADCAST_TWT_RESPONDER, WMI_SERVICE_BROADCAST_TWT + * combination. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_twt_bcast_responder(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_set_twt_requestor_flag() - Set twt requestor flag + * @psoc: pointer to psoc object + * @val: Value to be set to config + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_set_twt_requestor_flag(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_set_twt_responder_flag() - Set twt responder flag + * @psoc: pointer to psoc object + * @val: Value to be set to config + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_set_twt_responder_flag(struct wlan_objmgr_psoc *psoc, + bool val); +/** + * ucfg_mlme_set_twt_res_service_cap() - Set twt responder service capability + * @psoc: pointer to psoc object + * @val: Value to be set to config + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_get_twt_res_service_cap() - Get twt responder service capability + * @psoc: pointer to psoc object + * @val: Value to be set to config + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_reset_twt_active_cmd() - Reset twt active cmd if ack fail + * This is to handle back to back command. If ack failed for active + * command then reset this command to allow new twt command. + * @psoc: pointer to psoc object + * @peer_mac: peer mac address + * @dialog_id: dialog id + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_reset_twt_active_cmd(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_mlme_is_twt_setup_in_progress() - Get TWT setup in progress for + * given dialog id + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog id + * + * Return: True if already the TWT setup is in progress + */ +static inline bool +ucfg_mlme_is_twt_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return mlme_is_twt_setup_in_progress(psoc, peer_mac, dialog_id); +} + +/** + * ucfg_mlme_is_max_twt_sessions_reached() - Check if the maximum number of + * TWT sessions reached or not excluding the given dialog_id + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: dialog id + * + * Check if the number of active TWT sessions is equal to the maximum number + * of TWT sessions supported. Only count the TWT session slot if it not + * TWT_ALL_SESSIONS_DIALOG_ID and dialog id is different from input dialog_id, + * because if same dialog_id already exists in the TWT sessions, we should + * return false since re-negotiation is supported on existing dialog_id. + * + * Return: True if slot is available for dialog_id, false otherwise + */ +static inline bool +ucfg_mlme_is_max_twt_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return mlme_is_max_twt_sessions_reached(psoc, peer_mac, dialog_id); +} + +/** + * ucfg_mlme_twt_is_command_in_progress() - Check if given command is in + * progress + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: TWT session dialog id + * @cmd: TWT command + * @active_cmd: Fill active command in this output parameter + * + * Return: True if given command is in progress + */ +static inline bool +ucfg_mlme_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *active_cmd) +{ + return mlme_twt_is_command_in_progress(psoc, peer_mac, dialog_id, + cmd, active_cmd); +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + return mlme_set_twt_command_in_progress(psoc, peer_mac, dialog_id, cmd); +} + +/** + * ucfg_mlme_set_twt_setup_done() - Set TWT setup done flag + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: TWT session dialog id + * @is_set: true if setup done flag needs to be set + * + * Return: None + */ +static inline void +ucfg_mlme_set_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, bool is_set) +{ + mlme_set_twt_setup_done(psoc, peer_mac, dialog_id, is_set); +} + +/** + * ucfg_mlme_is_twt_setup_done() - Get if the TWT setup for given dialog id + * is complete. + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: TWT session dialog id + * + * Return: True if TWT setup is successful for the dialog id + */ +static inline bool +ucfg_mlme_is_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return mlme_is_twt_setup_done(psoc, peer_mac, dialog_id); +} + +/** + * ucfg_mlme_is_flexible_twt_enabled() - Get if flexible TWT is enabled + * @psoc: Pointer to global psoc object + * + * Return: True if flexible TWT is supported + */ +static inline +bool ucfg_mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return mlme_is_flexible_twt_enabled(psoc); +} + +/** + * ucfg_mlme_get_twt_peer_capabilities() - Get peer capabilities + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * + * Return: Peer capabilities bitmap + */ +static inline +uint8_t ucfg_mlme_get_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + return mlme_get_twt_peer_capabilities(psoc, peer_mac); +} + +/** + * ucfg_mlme_get_twt_peer_bcast_capabilities() - Get peer broadcast capabilities + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * + * Return: Return True if peer responder capabilities support else False + */ +bool ucfg_mlme_get_twt_peer_bcast_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac); + +/** + * ucfg_mlme_get_twt_peer_responder_capabilities() - Get peer responder + * capabilities + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * + * Return: Return True if peer responder capabilities support else False + */ +bool ucfg_mlme_get_twt_peer_responder_capabilities( + struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac); + +/** + * ucfg_mlme_init_twt_context() - Initialize TWT context + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_mlme_init_twt_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return mlme_init_twt_context(psoc, peer_mac, dialog_id); +} + +/** + * ucfg_mlme_is_24ghz_twt_enabled() - Get if host triggered TWT is enabled on + * 2.4Ghz band. + * @psoc: Pointer to global psoc object + * + * Return: True if host TWT is enabled on 2.4 Ghz band. + */ +static inline bool +ucfg_mlme_is_24ghz_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return mlme_is_24ghz_twt_enabled(psoc); +} + +/** + * ucfg_mlme_set_twt_nudge_tgt_cap() - Set TWT nudge target capability. + * @psoc: Pointer to global psoc object + * @val: Value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_set_twt_nudge_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_get_twt_nudge_tgt_cap() - Get TWT Nudge target capability + * @psoc: Pointer to global psoc object + * @val: Value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_get_twt_nudge_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_set_twt_all_twt_tgt_cap() - Set TWT all dialog support target + * @psoc: Pointer to global psoc object + * @val: Value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_set_twt_all_twt_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_get_twt_all_twt_tgt_cap() - Get TWT all dialog support target + * capability + * @psoc: Pointer to global psoc object + * @val: Value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_get_twt_all_twt_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_set_twt_statistics_tgt_cap() - Set TWT statistics target + * capability + * @psoc: Pointer to global psoc object + * @val: Value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_set_twt_statistics_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_get_twt_statistics_tgt_cap() - Get TWT statistics target capability + * @psoc: Pointer to global psoc object + * @val: Value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_get_twt_statistics_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_set_twt_session_state() - Set TWT session state + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: TWT session dialog id + * @state: TWT state + * + * Return: None + */ +static inline +void ucfg_mlme_set_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_session_state state) +{ + mlme_set_twt_session_state(psoc, peer_mac, dialog_id, state); +} + +/** + * ucfg_mlme_get_twt_session_state() - Get TWT session state + * @psoc: Pointer to global psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: TWT session dialog id + * + * Return: enum wlan_twt_session_state + */ +static inline enum wlan_twt_session_state +ucfg_mlme_get_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return mlme_get_twt_session_state(psoc, peer_mac, dialog_id); +} +#else +static inline QDF_STATUS +ucfg_mlme_get_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_responder(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_responder(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + *val = 0; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +ucfg_mlme_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_enable_twt(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +ucfg_mlme_is_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return 0; +} + +static inline void +ucfg_mlme_set_twt_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, bool is_set) +{} + +static inline bool +ucfg_mlme_is_twt_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return false; +} + +static inline bool +ucfg_mlme_is_max_twt_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return false; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline bool +ucfg_mlme_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *active_cmd) +{ + return false; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_bcast_requestor(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_bcast_requestor(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_bcast_responder(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_bcast_responder(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_requestor_flag(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_responder_flag(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +bool ucfg_mlme_is_flexible_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +uint8_t ucfg_mlme_get_twt_peer_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + return 0; +} + +static inline +bool ucfg_mlme_get_twt_peer_bcast_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + return false; +} + +static inline +bool ucfg_mlme_get_twt_peer_responder_capabilities( + struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + return false; +} + +static inline +QDF_STATUS ucfg_mlme_init_twt_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +ucfg_mlme_is_24ghz_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_nudge_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_all_twt_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_statistics_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_nudge_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_all_twt_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_statistics_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +void ucfg_mlme_set_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_session_state state) +{} + +static inline enum wlan_twt_session_state +ucfg_mlme_get_twt_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + +static inline QDF_STATUS +ucfg_mlme_set_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_reset_twt_active_cmd(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +#endif /* defined(WLAN_SUPPORT_TWT) && defined(WLAN_FEATURE_11AX) */ +#endif /* _WLAN_MLME_TWT_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h new file mode 100644 index 0000000000..cf0e789707 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/inc/wlan_mlme_ucfg_api.h @@ -0,0 +1,5451 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare UCFG APIs exposed by the mlme component + */ + +#ifndef _WLAN_MLME_UCFG_API_H_ +#define _WLAN_MLME_UCFG_API_H_ + +#include +#include +#include +#include +#include +#include +#include "wma_tgt_cfg.h" +#include "wlan_mlme_vdev_mgr_interface.h" + +/** + * ucfg_mlme_init() - initialize mlme_ctx context. + * + * This function initializes the mlme context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_mlme_init(void); + +/** + * ucfg_mlme_deinit() - De initialize mlme_ctx context. + * + * This function De initializes mlme context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS ucfg_mlme_deinit(void); + +/** + * ucfg_mlme_psoc_open() - MLME component Open + * @psoc: pointer to psoc object + * + * Open the MLME component and initialize the MLME structure + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_psoc_close() - MLME component close + * @psoc: pointer to psoc object + * + * Close the MLME component and clear the MLME structures + * + * Return: None + */ +void ucfg_mlme_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_pdev_open() - MLME component pdev Open + * @pdev: pointer to pdev object + * + * Open the MLME component and initialize the MLME pdev structure + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_pdev_open(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_mlme_set_ml_link_control_mode() - set ml_link_control_mode + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @value: value to set + * + * API get call when host receives vendor command + * QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE to configure link control mode. + * + * Return: none + */ +void ucfg_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t value); + +/** + * ucfg_mlme_set_bt_profile_con() - set Bluetooth connection profile + * @psoc: Pointer to psoc object + * @bt_profile_con: Bluetooth connection profile indicator + * + * Return: None + */ +void ucfg_mlme_set_bt_profile_con(struct wlan_objmgr_psoc *psoc, + bool bt_profile_con); +/** + * ucfg_mlme_get_ml_link_control_mode() - get ml_link_control_mode + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * + * Return: value of ml_link_control_mode in success + */ +uint8_t ucfg_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_mlme_pdev_close() - MLME component pdev close + * @pdev: pointer to pdev object + * + * close the MLME pdev information + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_pdev_close(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_mlme_global_init() - initialize global mlme ops and structure + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_global_init(void); +/** + * ucfg_mlme_global_deinit() - deinitialize global mlme ops and structure + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_global_deinit(void); + +/** + * ucfg_mlme_cfg_chan_to_freq() - convert channel numbers to frequencies + * @pdev: pointer to pdev object + * + * convert the channels numbers received as part of cfg items to + * frequencies. + * + * Return: None + */ +void ucfg_mlme_cfg_chan_to_freq(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_mlme_get_power_usage() - Get the power usage info + * @psoc: pointer to psoc object + * + * Return: pointer to character array of power usage + */ +static inline +char *ucfg_mlme_get_power_usage(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_power_usage(psoc); +} + +/** + * ucfg_get_tx_power() - Get the max tx power in particular band + * @psoc: pointer to psoc object + * @band: 2ghz/5ghz band + * + * Return: value of tx power in the respective band + */ +static inline +uint8_t ucfg_get_tx_power(struct wlan_objmgr_psoc *psoc, uint8_t band) +{ + return wlan_mlme_get_tx_power(psoc, band); +} + +/** + * ucfg_mlme_get_phy_max_freq_range() - Get phy supported max channel + * frequency range + * @psoc: psoc for country information + * @low_2ghz_chan: 2.4 GHz low channel frequency + * @high_2ghz_chan: 2.4 GHz high channel frequency + * @low_5ghz_chan: 5 GHz low channel frequency + * @high_5ghz_chan: 5 GHz high channel frequency + * + * Return: QDF status + */ +static inline +QDF_STATUS ucfg_mlme_get_phy_max_freq_range(struct wlan_objmgr_psoc *psoc, + uint32_t *low_2ghz_chan, + uint32_t *high_2ghz_chan, + uint32_t *low_5ghz_chan, + uint32_t *high_5ghz_chan) +{ + return wlan_mlme_get_phy_max_freq_range(psoc, + low_2ghz_chan, + high_2ghz_chan, + low_5ghz_chan, + high_5ghz_chan); +} + +/** + * ucfg_mlme_get_ht_cap_info() - Get the HT cap info config + * @psoc: pointer to psoc object + * @ht_cap_info: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_ht_cap_info(struct wlan_objmgr_psoc *psoc, + struct mlme_ht_capabilities_info + *ht_cap_info) +{ + return wlan_mlme_get_ht_cap_info(psoc, ht_cap_info); +} + +/** + * ucfg_mlme_set_ht_cap_info() - Set the HT cap info config + * @psoc: pointer to psoc object + * @ht_cap_info: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_ht_cap_info(struct wlan_objmgr_psoc *psoc, + struct mlme_ht_capabilities_info + ht_cap_info) +{ + return wlan_mlme_set_ht_cap_info(psoc, ht_cap_info); +} + +/** + * ucfg_mlme_get_max_amsdu_num() - get the max amsdu num + * @psoc: pointer to psoc object + * @value: pointer to the value where the max_amsdu num is to be filled + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_mlme_get_max_amsdu_num(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_max_amsdu_num(psoc, value); +} + +/** + * ucfg_mlme_set_max_amsdu_num() - set the max amsdu num + * @psoc: pointer to psoc object + * @value: value to be set for max_amsdu_num + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_mlme_set_max_amsdu_num(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return wlan_mlme_set_max_amsdu_num(psoc, value); +} + +/** + * ucfg_mlme_get_ht_mpdu_density() - get the ht mpdu density + * @psoc: pointer to psoc object + * @value: pointer to the value where the ht mpdu density is to be filled + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_mlme_get_ht_mpdu_density(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_ht_mpdu_density(psoc, value); +} + +/** + * ucfg_mlme_set_ht_mpdu_density() - set the ht mpdu density + * @psoc: pointer to psoc object + * @value: value to be set for ht mpdu density + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_mlme_set_ht_mpdu_density(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return wlan_mlme_set_ht_mpdu_density(psoc, value); +} + +/** + * ucfg_mlme_get_band_capability() - Get the Band capability config + * @psoc: pointer to psoc object + * @band_capability: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_band_capability(struct wlan_objmgr_psoc *psoc, + uint32_t *band_capability) +{ + return wlan_mlme_get_band_capability(psoc, band_capability); +} + +/** + * ucfg_mlme_peer_config_vlan() - Send VLAN id to FW for + * RX packet + * @vdev: vdev pointer + * @macaddr: Peer mac address + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_peer_config_vlan(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr) +{ + return wlan_mlme_peer_config_vlan(vdev, macaddr); +} + +/** + * ucfg_mlme_get_tdls_prohibited() - get if TDLS prohibited is advertised by + * the connected AP. + * @vdev: vdev pointer + * + * Return: bool + */ +static inline +bool ucfg_mlme_get_tdls_prohibited(struct wlan_objmgr_vdev *vdev) +{ + return mlme_get_tdls_prohibited(vdev); +} + +/** + * ucfg_mlme_get_tdls_chan_switch_prohibited() - get tdls chan switch prohibited + * @vdev: vdev pointer + * + * Return: bool + */ +static inline +bool ucfg_mlme_get_tdls_chan_switch_prohibited(struct wlan_objmgr_vdev *vdev) +{ + return mlme_get_tdls_chan_switch_prohibited(vdev); +} +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * ucfg_mlme_get_wlm_multi_client_ll_caps() - Get multi client latency level + * capability of FW + * @psoc: pointer to psoc object + * + * Return: true if multi client feature supported + */ +bool ucfg_mlme_get_wlm_multi_client_ll_caps(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_cfg_get_multi_client_ll_ini_support() - Get multi client latency + * level ini support value + * @psoc: pointer to psoc object + * @multi_client_ll_support: parameter that needs to be filled + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_cfg_get_multi_client_ll_ini_support(struct wlan_objmgr_psoc *psoc, + bool *multi_client_ll_support); +#else +static inline +bool ucfg_mlme_get_wlm_multi_client_ll_caps(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +ucfg_mlme_cfg_get_multi_client_ll_ini_support(struct wlan_objmgr_psoc *psoc, + bool *multi_client_ll_support) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * ucfg_mlme_set_band_capability() - Set the Band capability config + * @psoc: pointer to psoc object + * @band_capability: Value to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_band_capability(struct wlan_objmgr_psoc *psoc, + uint32_t band_capability) +{ + return wlan_mlme_set_band_capability(psoc, band_capability); +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * ucfg_mlme_get_vendor_handoff_control_caps() - Get vendor handoff control + * capability of FW + * @psoc: pointer to psoc object + * + * Return: true if vendor handoff feature supported + */ +bool ucfg_mlme_get_vendor_handoff_control_caps(struct wlan_objmgr_psoc *psoc); +#else +static inline +bool ucfg_mlme_get_vendor_handoff_control_caps(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * ucfg_mlme_set_dual_sta_policy() - Configures the Concurrent STA policy + * value + * @psoc: pointer to psoc object + * @dual_sta_config: Concurrent STA policy configuration value + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_dual_sta_policy(struct wlan_objmgr_psoc *psoc, + uint8_t dual_sta_config) +{ + return wlan_mlme_set_dual_sta_policy(psoc, dual_sta_config); +} + +/** + * ucfg_mlme_get_dual_sta_policy() - Get the Concurrent STA policy value + * @psoc: pointer to psoc object + * @dual_sta_config: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_dual_sta_policy(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_sta_config) +{ + return wlan_mlme_get_dual_sta_policy(psoc, dual_sta_config); +} + +/** + * ucfg_mlme_set_ap_policy() - Configures the AP policy value + * @vdev: pointer to vdev object + * @ap_cfg_policy: AP policy configuration value + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_ap_policy(struct wlan_objmgr_vdev *vdev, + enum host_concurrent_ap_policy ap_cfg_policy) +{ + return wlan_mlme_set_ap_policy(vdev, ap_cfg_policy); +} + +/** + * ucfg_mlme_get_ap_policy() - Get the AP policy value + * @vdev: pointer to vdev object + * + * Return: enum host_concurrent_ap_policy + */ +static inline enum host_concurrent_ap_policy +ucfg_mlme_get_ap_policy(struct wlan_objmgr_vdev *vdev) +{ + return wlan_mlme_get_ap_policy(vdev); +} + +/** + * ucfg_mlme_get_prevent_link_down() - Get the prevent link down config + * @psoc: pointer to psoc object + * @prevent_link_down: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_prevent_link_down(struct wlan_objmgr_psoc *psoc, + bool *prevent_link_down) +{ + return wlan_mlme_get_prevent_link_down(psoc, prevent_link_down); +} + +/** + * ucfg_mlme_get_select_5ghz_margin() - Get the select 5Ghz margin config + * @psoc: pointer to psoc object + * @select_5ghz_margin: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_select_5ghz_margin(struct wlan_objmgr_psoc *psoc, + uint8_t *select_5ghz_margin) +{ + return wlan_mlme_get_select_5ghz_margin(psoc, select_5ghz_margin); +} + +/** + * ucfg_mlme_get_rtt_mac_randomization() - Get the RTT MAC randomization config + * @psoc: pointer to psoc object + * @rtt_mac_randomization: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_rtt_mac_randomization(struct wlan_objmgr_psoc *psoc, + bool *rtt_mac_randomization) +{ + return wlan_mlme_get_rtt_mac_randomization(psoc, rtt_mac_randomization); +} + +/** + * ucfg_mlme_get_crash_inject() - Get the crash inject config + * @psoc: pointer to psoc object + * @crash_inject: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_crash_inject(struct wlan_objmgr_psoc *psoc, + bool *crash_inject) +{ + return wlan_mlme_get_crash_inject(psoc, crash_inject); +} + +/** + * ucfg_mlme_get_lpass_support() - Get the LPASS Support config + * @psoc: pointer to psoc object + * @lpass_support: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_lpass_support(struct wlan_objmgr_psoc *psoc, + bool *lpass_support) +{ + return wlan_mlme_get_lpass_support(psoc, lpass_support); +} + +/** + * ucfg_mlme_get_wls_6ghz_cap() - Get the WiFi Location Service(WLS) + * 6ghz capability + * @psoc: pointer to psoc object + * @wls_6ghz_capable: Pointer to the variable from caller + * + * Return: void + */ +static inline +void ucfg_mlme_get_wls_6ghz_cap(struct wlan_objmgr_psoc *psoc, + bool *wls_6ghz_capable) +{ + wlan_mlme_get_wls_6ghz_cap(psoc, wls_6ghz_capable); +} + +/** + * ucfg_mlme_get_self_recovery() - Get the self recovery config + * @psoc: pointer to psoc object + * @self_recovery: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_self_recovery(struct wlan_objmgr_psoc *psoc, + bool *self_recovery) +{ + return wlan_mlme_get_self_recovery(psoc, self_recovery); +} + +/** + * ucfg_mlme_get_sub_20_chan_width() - Get the sub 20 chan width config + * @psoc: pointer to psoc object + * @sub_20_chan_width: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sub_20_chan_width(struct wlan_objmgr_psoc *psoc, + uint8_t *sub_20_chan_width) +{ + return wlan_mlme_get_sub_20_chan_width(psoc, sub_20_chan_width); +} + +/** + * ucfg_mlme_get_fw_timeout_crash() - Get the fw timeout crash config + * @psoc: pointer to psoc object + * @fw_timeout_crash: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_fw_timeout_crash(struct wlan_objmgr_psoc *psoc, + bool *fw_timeout_crash) +{ + return wlan_mlme_get_fw_timeout_crash(psoc, fw_timeout_crash); +} + +/** + * ucfg_mlme_get_ito_repeat_count() - Get the fw timeout crash config + * @psoc: pointer to psoc object + * @ito_repeat_count: Pointer to the variable from caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_ito_repeat_count(struct wlan_objmgr_psoc *psoc, + uint8_t *ito_repeat_count) +{ + return wlan_mlme_get_ito_repeat_count(psoc, ito_repeat_count); +} + +/** + * ucfg_mlme_get_acs_with_more_param() - Get the flag for acs with + * more param + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_acs_with_more_param(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_acs_with_more_param(psoc, value); +} + +/** + * ucfg_mlme_get_auto_channel_weight() - Get the auto channel select weight + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_auto_channel_weight(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_auto_channel_weight(psoc, value); +} + +/** + * ucfg_mlme_get_vendor_acs_support() - Get the flag for + * vendor acs support + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_vendor_acs_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_vendor_acs_support(psoc, value); +} + +/** + * ucfg_mlme_get_external_acs_policy() - Get flag for external control + * acs policy + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_external_acs_policy(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_external_acs_policy(psoc, value); +} + +/** + * ucfg_mlme_get_acs_support_for_dfs_ltecoex() - Is DFS LTE CoEx ACS supported + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS +ucfg_mlme_get_acs_support_for_dfs_ltecoex(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_acs_support_for_dfs_ltecoex(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_dir_ac_vo() - Get TSPEC direction for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_dir_ac_vo(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_wmm_dir_ac_vo(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_nom_msdu_size_ac_vo() - Get normal + * MSDU size for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_nom_msdu_size_ac_vo(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_wmm_nom_msdu_size_ac_vo(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_mean_data_rate_ac_vo() - mean data rate for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_mean_data_rate_ac_vo(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_mean_data_rate_ac_vo(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_min_phy_rate_ac_vo() - min PHY + * rate for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_min_phy_rate_ac_vo(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_min_phy_rate_ac_vo(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_sba_ac_vo() - surplus bandwidth + * allowance for VO + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_sba_ac_vo(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_wmm_sba_ac_vo(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_vo_srv_intv() - Get Uapsd service + * interval for voice + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_vo_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_vo_srv_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_vo_sus_intv() - Get Uapsd suspension + * interval for voice + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_vo_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_vo_sus_intv(psoc, value); +} + +/** + * ucfg_mlme_get_sap_inactivity_override() - Check if sap max inactivity + * override flag is set. + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to call + * the mlme function wlan_mlme_get_sap_inactivity_override + * + * Return: QDF Status + */ +static inline +void ucfg_mlme_get_sap_inactivity_override(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + wlan_mlme_get_sap_inactivity_override(psoc, value); +} + +/** + * ucfg_mlme_get_tx_chainmask_1ss() - Get the tx_chainmask_1ss value + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +static inline +QDF_STATUS ucfg_mlme_get_tx_chainmask_1ss(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_tx_chainmask_1ss(psoc, value); +} + +/** + * ucfg_mlme_get_num_11b_tx_chains() - Get the number of 11b only tx chains + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +static inline +QDF_STATUS ucfg_mlme_get_num_11b_tx_chains(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_num_11b_tx_chains(psoc, value); +} + +/** + * ucfg_mlme_get_num_11ag_tx_chains() - get the total number of 11a/g tx chains + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +static inline +QDF_STATUS ucfg_mlme_get_num_11ag_tx_chains(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_num_11ag_tx_chains(psoc, value); +} + +/** + * ucfg_mlme_get_bt_chain_separation_flag() - bt chain separation enable/disable + * @psoc: pointer to psoc object + * @value: Value that needs to be got for the caller + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +static inline +QDF_STATUS ucfg_mlme_get_bt_chain_separation_flag(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_bt_chain_separation_flag(psoc, value); +} + +/** + * ucfg_mlme_configure_chain_mask() - configure chainmask parameters + * + * @psoc: pointer to psoc object + * @session_id: vdev_id + * + * Return: QDF_STATUS_FAILURE or QDF_STATUS_SUCCESS + */ +static inline +QDF_STATUS ucfg_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc, + uint8_t session_id) +{ + return wlan_mlme_configure_chain_mask(psoc, session_id); +} + +/** + * ucfg_mlme_is_chain_mask_supported() - check if configure chainmask can + * be supported + * @psoc: pointer to psoc object + * + * Return: true if supported else false + */ +static inline +bool ucfg_mlme_is_chain_mask_supported(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_is_chain_mask_supported(psoc); +} + +/* + * ucfg_mlme_get_sta_keep_alive_period() - Get the sta keep alive period + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_sta_keep_alive_period(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/* + * ucfg_mlme_get_dfs_master_capability() - Get the dfs master capability + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_dfs_master_capability(struct wlan_objmgr_psoc *psoc, + bool *val); + +/* + * ucfg_mlme_get_dfs_disable_channel_switch() - Get the dfs channel switch + * @psoc: pointer to psoc object + * @dfs_disable_channel_switch: Pointer to the value which will be filled + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc, + bool *dfs_disable_channel_switch); + +/* + * ucfg_mlme_set_dfs_disable_channel_switch() - Set the dfs channel switch + * @psoc: pointer to psoc object + * @dfs_disable_channel_switch: Value that needs to be set. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc, + bool dfs_disable_channel_switch); +/* + * ucfg_mlme_get_dfs_ignore_cac() - GSet the dfs ignore cac + * @psoc: pointer to psoc object + * @dfs_ignore_cac: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc, + bool *dfs_ignore_cac); + +/* + * ucfg_mlme_set_dfs_ignore_cac() - Set the dfs ignore cac + * @psoc: pointer to psoc object + * @dfs_ignore_cac: Value that needs to be set. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc, + bool dfs_ignore_cac); + +/* + * ucfg_mlme_get_sap_tx_leakage_threshold() - Get sap tx leakage threshold + * @psoc: pointer to psoc object + * @sap_tx_leakage_threshold: Pointer to the value which will be filled + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *sap_tx_leakage_threshold); + +/* + * ucfg_mlme_set_sap_tx_leakage_threshold() - Set sap tx leakage threshold + * @psoc: pointer to psoc object + * @sap_tx_leakage_threshold: Value that needs to be set. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t sap_tx_leakage_threshold); + +/* + * ucfg_mlme_get_dfs_pri_multiplier() - Get dfs pri multiplier + * @psoc: pointer to psoc object + * @dfs_pri_multiplier: Pointer to the value which will be filled + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_dfs_pri_multiplier(struct wlan_objmgr_psoc *psoc, + uint32_t *dfs_pri_multiplier); + +/* + * ucfg_mlme_set_dfs_pri_multiplier() - Set dfs pri multiplier + * @psoc: pointer to psoc object + * @dfs_pri_multiplier: Value that needs to be set. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_dfs_pri_multiplier(struct wlan_objmgr_psoc *psoc, + uint32_t dfs_pri_multiplier); + +/* + * ucfg_mlme_get_dfs_filter_offload() - Get the dfs filter offload + * @psoc: pointer to psoc object + * @dfs_filter_offload: Pointer to the value which will be filled + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_dfs_filter_offload(struct wlan_objmgr_psoc *psoc, + bool *dfs_filter_offload); + +/* + * ucfg_mlme_set_dfs_filter_offload() - Set the dfs filter offload + * @psoc: pointer to psoc object + * @dfs_filter_offload: Value that needs to be set. + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_dfs_filter_offload(struct wlan_objmgr_psoc *psoc, + bool dfs_filter_offload); + +/** + * ucfg_mlme_get_oem_6g_supported() - Get oem 6Ghz supported + * @psoc: pointer to psoc object + * @oem_6g_supported: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_oem_6g_supported(struct wlan_objmgr_psoc *psoc, + bool *oem_6g_supported); + +/** + * ucfg_mlme_get_fine_time_meas_cap() - Get fine timing measurement capability + * @psoc: pointer to psoc object + * @fine_time_meas_cap: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc, + uint32_t *fine_time_meas_cap); + +/** + * ucfg_mlme_set_fine_time_meas_cap() - Set fine timing measurement capability + * @psoc: pointer to psoc object + * @fine_time_meas_cap: Value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc, + uint32_t fine_time_meas_cap); + +/** + * ucfg_mlme_get_pmkid_modes() - Get PMKID modes + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_pmkid_modes(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_set_pmkid_modes() - Set PMKID modes + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_pmkid_modes(struct wlan_objmgr_psoc *psoc, + uint32_t val); + +/** + * ucfg_mlme_get_dot11p_mode() - Get the setting about 802.11p mode + * @psoc: pointer to psoc object + * @out_mode: Pointer to the mode which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_dot11p_mode(struct wlan_objmgr_psoc *psoc, + enum dot11p_mode *out_mode); + +/** + * ucfg_mlme_get_go_cts2self_for_sta() - Stop NOA and start using cts2self + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_go_cts2self_for_sta(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_get_qcn_ie_support() - QCN IE support or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_qcn_ie_support(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_get_tgt_gtx_usr_cfg() - Get the target gtx user config + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_tgt_gtx_usr_cfg(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_is_override_ht20_40_24g() - use channel bonding in 2.4 GHz or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_override_ht20_40_24g(struct wlan_objmgr_psoc *psoc, bool *val); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * ucfg_mlme_get_roam_disable_config() - Get sta roam disable value + * @psoc: pointer to psoc object + * @val: Pointer to bitmap of interfaces for those sta roaming is disabled + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_roam_disable_config(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_get_roaming_offload() - Get roaming offload setting + * @psoc: pointer to psoc object + * @val: Pointer to enable/disable roaming offload + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_set_roaming_offload() - Enable/disable roaming offload + * @psoc: pointer to psoc object + * @val: enable/disable roaming offload + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_get_roaming_triggers() - Get roaming triggers bitmap + * value + * @psoc: pointer to psoc object + * + * Return: Roaming triggers value + */ +static inline uint32_t +ucfg_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_roaming_triggers(psoc); +} + +/** + * ucfg_mlme_set_roaming_triggers() - Set roaming triggers bitmap + * value + * @psoc: pointer to psoc object + * @trigger_bitmap: Roaming triggers bitmap to set + * + * Return: void + */ +static inline void +ucfg_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc, + uint32_t trigger_bitmap) +{ + wlan_mlme_set_roaming_triggers(psoc, trigger_bitmap); +} +#else +static inline QDF_STATUS +ucfg_mlme_get_roam_disable_config(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +ucfg_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_mlme_set_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint32_t +ucfg_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc) +{ + return 0xffff; +} + +static inline void +ucfg_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc, + uint32_t trigger_bitmap) +{ +} +#endif + +/** + * ucfg_mlme_is_mawc_enabled() - MAWC enabled or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_mawc_enabled(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_set_mawc_enabled() - Set MAWC enable or disable + * @psoc: pointer to psoc object + * @val: enable or disable MAWC + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_mawc_enabled(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_is_fast_transition_enabled() - Fast transition enable or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_fast_transition_enabled(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * ucfg_mlme_set_fast_transition_enabled() - Set fast transition enable + * @psoc: pointer to psoc object + * @val: Fast transition enable or disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_fast_transition_enabled(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_is_roam_scan_offload_enabled() - Roam scan offload enable or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_roam_scan_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool *val); + +#ifdef WLAN_ADAPTIVE_11R +/** + * ucfg_mlme_set_tgt_adaptive_11r_cap() - Set adaptive 11r target service + * capability + * @psoc: pointer to psoc object + * @val: Target capability of adaptive 11r + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_tgt_adaptive_11r_cap(struct wlan_objmgr_psoc *psoc, + bool val); +/** + * ucfg_mlme_get_adaptive11r_enabled() - get adaptive 11R enabled status + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_adaptive11r_enabled(struct wlan_objmgr_psoc *psoc, + bool *value); +#else +static inline QDF_STATUS +ucfg_mlme_set_tgt_adaptive_11r_cap(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_mlme_get_adaptive11r_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + *value = false; + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ucfg_mlme_set_roam_scan_offload_enabled() - Set roam scan offload enable + * @psoc: pointer to psoc object + * @val: Roam scan offload enable or disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_roam_scan_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_get_neighbor_scan_max_chan_time() - Get neighbor scan max + * channel time + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_neighbor_scan_max_chan_time(struct wlan_objmgr_psoc *psoc, + uint16_t *val); + +/** + * ucfg_mlme_get_neighbor_scan_min_chan_time() - Get neighbor scan min + * channel time + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_neighbor_scan_min_chan_time(struct wlan_objmgr_psoc *psoc, + uint16_t *val); + +/** + * ucfg_mlme_get_delay_before_vdev_stop() - Get the delay before vdev stop + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_delay_before_vdev_stop(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * ucfg_mlme_get_roam_bmiss_final_bcnt() - Get roam bmiss first count + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_roam_bmiss_final_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * ucfg_mlme_validate_roam_bmiss_final_bcnt() - Validate roam bmiss final bcnt + * @bmiss_final_bcnt: Roam bmiss final bcnt + * + * Return: True if bmiss_final_bcnt is in expected range, false otherwise. + */ +bool +ucfg_mlme_validate_roam_bmiss_final_bcnt(uint32_t bmiss_final_bcnt); + +/** + * ucfg_mlme_get_dual_sta_roaming_enabled() - Get dual sta roaming enable flag + * @psoc: pointer to psoc object + * + * Return: true if dual sta roaming allowed in fw + */ +bool +ucfg_mlme_get_dual_sta_roaming_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_get_roam_bmiss_first_bcnt() - Get roam bmiss final count + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_roam_bmiss_first_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val); + +/** + * ucfg_mlme_is_lfr_enabled() - LFR enable or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_lfr_enabled(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_set_lfr_enabled() - Enable or disable LFR + * @psoc: pointer to psoc object + * @val: Enable or disable LFR + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_lfr_enabled(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_is_roam_prefer_5ghz() - prefer 5ghz or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_roam_prefer_5ghz(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * ucfg_mlme_is_roam_intra_band() - Get the preference to roam within band + * @psoc: pointer to psoc object + * + * Return: True if vdev should roam within band, false otherwise + */ +bool ucfg_mlme_is_roam_intra_band(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_set_roam_intra_band() - Set roam intra modes + * @psoc: pointer to psoc object + * @val: roam intra modes or not + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_roam_intra_band(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * ucfg_mlme_get_home_away_time() - Get home away time + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_home_away_time(struct wlan_objmgr_psoc *psoc, uint16_t *val); + +/** + * ucfg_mlme_set_fast_roam_in_concurrency_enabled() - Enable fast roam in + * concurrency + * @psoc: pointer to psoc object + * @val: Enable or disable fast roam in concurrency + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_fast_roam_in_concurrency_enabled(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_mlme_get_wmi_wq_watchdog_timeout() - Get timeout for wmi watchdog bite + * @psoc: pointer to psoc object + * @wmi_wq_watchdog_timeout: buffer to hold value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *wmi_wq_watchdog_timeout); + +/** + * ucfg_mlme_set_wmi_wq_watchdog_timeout() - Set timeout for wmi watchdog bite + * @psoc: pointer to psoc object + * @wmi_wq_watchdog_timeout: value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t wmi_wq_watchdog_timeout); + +/** + * ucfg_mlme_set_sap_listen_interval() - Set the Sap listen interval + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_sap_listen_interval(struct wlan_objmgr_psoc *psoc, + int value) +{ + return wlan_mlme_set_sap_listen_interval(psoc, value); +} + +/** + * ucfg_mlme_set_assoc_sta_limit() - Set the assoc sta limit + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_assoc_sta_limit(struct wlan_objmgr_psoc *psoc, + int value) +{ + return wlan_mlme_set_assoc_sta_limit(psoc, value); +} + +/** + * ucfg_mlme_get_assoc_sta_limit() - Get the assoc sta limit + * @psoc: pointer to psoc object + * @value: Pointer to variable that needs to be filled by MLME + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_assoc_sta_limit(struct wlan_objmgr_psoc *psoc, + int *value) +{ + return wlan_mlme_get_assoc_sta_limit(psoc, value); +} + +/** + * ucfg_mlme_get_listen_interval() - Get listen interval + * @psoc: pointer to psoc object + * @value: Pointer to variable that needs to be filled by MLME + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_listen_interval(struct wlan_objmgr_psoc *psoc, + int *value) +{ + return wlan_mlme_get_listen_interval(psoc, value); +} + + +/** + * ucfg_mlme_get_sap_get_peer_info() - get the sap get peer info + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_get_peer_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_sap_get_peer_info(psoc, value); +} + +/** + * ucfg_mlme_set_sap_get_peer_info() - set the sap get peer info + * @psoc: pointer to psoc object + * @value: value to overwrite the sap get peer info + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_sap_get_peer_info(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_sap_get_peer_info(psoc, value); +} + +/** + * ucfg_mlme_get_sap_bcast_deauth_enabled() - get the sap bcast deauth + * enabled value + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_sap_bcast_deauth_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_sap_bcast_deauth_enabled(psoc, value); +} + +/** + * ucfg_mlme_is_6g_sap_fd_enabled() - get the sap fils discovery + * enabled value + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_6g_sap_fd_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_is_6g_sap_fd_enabled(psoc, value); +} + +/** + * ucfg_mlme_get_sap_allow_all_channels() - get the sap allow all channels + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_allow_all_channels(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_sap_allow_all_channels(psoc, value); +} + +/** + * ucfg_mlme_get_sap_max_peers() - get the sap max peers + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_max_peers(struct wlan_objmgr_psoc *psoc, + int *value) +{ + return wlan_mlme_get_sap_max_peers(psoc, value); +} + +/** + * ucfg_mlme_set_sap_max_peers() - Set the sap max peers + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_sap_max_peers(struct wlan_objmgr_psoc *psoc, int value) +{ + return wlan_mlme_set_sap_max_peers(psoc, value); +} + +/** + * ucfg_mlme_get_sap_max_offload_peers() - get the sap max offload peers + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_max_offload_peers(struct wlan_objmgr_psoc *psoc, + int *value) +{ + return wlan_mlme_get_sap_max_offload_peers(psoc, value); +} + +/** + * ucfg_mlme_get_sap_max_offload_reorder_buffs() - get the sap max offload + * reorder buffs + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_max_offload_reorder_buffs(struct wlan_objmgr_psoc + *psoc, int *value) +{ + return wlan_mlme_get_sap_max_offload_reorder_buffs(psoc, value); +} + +/** + * ucfg_mlme_get_sap_chn_switch_bcn_count() - get the sap channel + * switch beacon count + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_chn_switch_bcn_count(struct wlan_objmgr_psoc *psoc, + int *value) +{ + return wlan_mlme_get_sap_chn_switch_bcn_count(psoc, value); +} + +/** + * ucfg_mlme_get_sap_channel_switch_mode() - get the sap channel switch mode + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_channel_switch_mode(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_sap_chn_switch_mode(psoc, value); +} + +/** + * ucfg_mlme_get_sap_internal_restart() - get sap internal restart value + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_internal_restart(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_sap_internal_restart(psoc, value); +} + +/** + * ucfg_mlme_get_sap_max_modulated_dtim() - get sap max modulated dtim + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_max_modulated_dtim(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_sap_max_modulated_dtim(psoc, value); +} + +/** + * ucfg_mlme_get_pref_chan_location() - get sap pref chan location + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_pref_chan_location(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_sap_chan_pref_location(psoc, value); +} + +/** + * ucfg_mlme_get_sap_country_priority() - get sap country code priority + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_country_priority(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_sap_country_priority(psoc, value); +} + +/** + * ucfg_mlme_get_sap_reduces_beacon_interval() - get the sap reduces beacon + * interval + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_reduces_beacon_interval(struct wlan_objmgr_psoc + *psoc, int *value) +{ + return wlan_mlme_get_sap_reduced_beacon_interval(psoc, value); +} + +/** + * ucfg_mlme_get_sap_chan_switch_rate_enabled() - get the sap channel + * switch rate enabled. + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_chan_switch_rate_enabled(struct wlan_objmgr_psoc + *psoc, bool *value) +{ + return wlan_mlme_get_sap_chan_switch_rate_enabled(psoc, value); +} + +/** + * ucfg_mlme_get_sap_force_11n_for_11ac() - get the sap 11n for 11ac + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_sap_force_11n_for_11ac(struct wlan_objmgr_psoc + *psoc, bool *value) +{ + return wlan_mlme_get_sap_force_11n_for_11ac(psoc, value); +} + +/** + * ucfg_mlme_get_go_force_11n_for_11ac() - get the GO 11n for 11ac + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_go_force_11n_for_11ac(struct wlan_objmgr_psoc + *psoc, bool *value) +{ + return wlan_mlme_get_go_force_11n_for_11ac(psoc, value); +} + +/** + * ucfg_mlme_is_sap_11ac_override() - Override 11ac bandwdith for SAP + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_is_sap_11ac_override(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_is_sap_11ac_override(psoc, value); +} + +/** + * ucfg_mlme_is_go_11ac_override() - Override 11ac bandwdith for P2P GO + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_is_go_11ac_override(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_is_go_11ac_override(psoc, value); +} + +/** + * ucfg_mlme_set_sap_11ac_override() - Set override 11ac bandwdith for SAP + * + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_sap_11ac_override(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_sap_11ac_override(psoc, value); +} + +/** + * ucfg_mlme_set_go_11ac_override() - Set override 11ac bandwdith for P2P GO + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_go_11ac_override(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_go_11ac_override(psoc, value); +} + +/** + * ucfg_mlme_get_oce_sta_enabled_info() - Get OCE feature enable/disable + * info for STA + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * OCE STA feature enable value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_get_oce_sta_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_oce_sta_enabled_info(psoc, value); +} + +/** + * ucfg_mlme_get_bigtk_support() - Get whether bigtk is supported or not. + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the BIGTK support + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_get_bigtk_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_bigtk_support(psoc, value); +} + +/** + * ucfg_mlme_get_ocv_support() - Get whether ocv is supported or not. + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the OCV support + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_get_ocv_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_ocv_support(psoc, value); +} + +/** + * ucfg_mlme_get_oce_sap_enabled_info() - Get OCE feature enable/disable + * info for SAP + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * OCE SAP feature enable value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_get_oce_sap_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_oce_sap_enabled_info(psoc, value); +} + +/** + * ucfg_mlme_update_oce_flags: Update the OCE flags + * + * @pdev: pointer to pdev object + * + * Inline UCFG API to be used by HDD/OSIF callers to update the + * OCE feature flags + * + * Return: void + */ +static inline +void ucfg_mlme_update_oce_flags(struct wlan_objmgr_pdev *pdev) +{ + wlan_mlme_update_oce_flags(pdev); +} + +/** + * ucfg_mlme_is_ap_prot_enabled() - Check if sap is enabled + * @psoc: pointer to psoc object + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * sap protection enabled/disabled + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +bool ucfg_mlme_is_ap_prot_enabled(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_is_ap_prot_enabled(psoc); +} + +/** + * ucfg_mlme_get_ap_protection_mode() - Get ap protection mode info + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ap protection mode value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_get_ap_protection_mode(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_ap_protection_mode(psoc, value); +} + +/** + * ucfg_mlme_is_ap_obss_prot_enabled() - Get ap obss protection enable/disable + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * obss protection enable value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_is_ap_obss_prot_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_is_ap_obss_prot_enabled(psoc, value); +} + +/** + * ucfg_mlme_get_rts_threshold() - Get the rts threshold config + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_rts_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_rts_threshold(psoc, value); +} + +/** + * ucfg_mlme_set_rts_threshold() - Set the rts threshold config + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_rts_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + return wlan_mlme_set_rts_threshold(psoc, value); +} + +/** + * ucfg_mlme_get_frag_threshold() - Get the fragmentation threshold + * config + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_frag_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_frag_threshold(psoc, value); +} + +/** + * ucfg_mlme_set_frag_threshold() - set the frag threshold config + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_frag_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + return wlan_mlme_set_frag_threshold(psoc, value); +} + +/** + * ucfg_mlme_get_fils_enabled_info() - Get fils enable/disable info + * + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * fils enable value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_get_fils_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_fils_enabled_info(psoc, value); +} + +/** + * ucfg_mlme_set_fils_enabled_info() - Set fils enable info + * + * @psoc: pointer to psoc object + * @value: value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to set the + * fils enable value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_set_fils_enabled_info(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_fils_enabled_info(psoc, value); +} + +/** + * ucfg_mlme_set_primary_interface() - Set primary STA iface id + * + * @psoc: pointer to psoc object + * @value: value that needs to be set from the caller + * + * When a vdev is set as primary then based on the dual sta policy + * "qca_wlan_concurrent_sta_policy_config" mcc preference and roaming has + * to be enabled on the primary vdev + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_set_primary_interface(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return wlan_mlme_set_primary_interface(psoc, value); +} + +/** + * ucfg_mlme_get_mcc_duty_cycle_percentage() - Get primary STA iface MCC + * duty-cycle + * @pdev: pointer to pdev object + * + * primary and secondary STA iface MCC duty-cycle value in below format + * ****************************************************** + * |bit 31-24 | bit 23-16 | bits 15-8 |bits 7-0 | + * | Unused | Quota for | chan. # for |chan. # for| + * | | 1st chan | 1st chan. |2nd chan. | + * ***************************************************** + * + * Return: primary iface MCC duty-cycle value + */ +static inline +int ucfg_mlme_get_mcc_duty_cycle_percentage(struct wlan_objmgr_pdev *pdev) +{ + return wlan_mlme_get_mcc_duty_cycle_percentage(pdev); +} + +/** + * ucfg_mlme_set_enable_bcast_probe_rsp() - Set enable bcast probe resp info + * @psoc: pointer to psoc object + * @value: value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers to set the + * enable bcast probe resp info + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_set_enable_bcast_probe_rsp(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_enable_bcast_probe_rsp(psoc, value); +} + +/** + * ucfg_mlme_set_vht_ch_width() - set the vht supported channel width cfg + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_set_vht_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t value) +{ + return wlan_mlme_cfg_set_vht_chan_width(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_chan_width() - gets vht supported channel width into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_chan_width(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_cfg_get_vht_chan_width(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_ldpc_coding_cap() - sets vht ldpc coding cap into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_vht_ldpc_coding_cap(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_cfg_set_vht_ldpc_coding_cap(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_short_gi_160_mhz() - Get SHORT GI 160MHZ from cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_short_gi_160_mhz(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_cfg_get_short_gi_160_mhz(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_short_gi_160_mhz() - sets basic set SHORT GI 160MHZ into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_short_gi_160_mhz(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_cfg_set_short_gi_160_mhz(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_tx_stbc() - gets vht tx stbc from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_tx_stbc(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_cfg_get_vht_tx_stbc(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_rx_stbc() - gets vht rx stbc from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_rx_stbc(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_cfg_get_vht_rx_stbc(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_tx_bfee_ant_supp() - sets vht Beamformee antenna + * support cap into cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_cfg_set_vht_tx_bfee_ant_supp(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return wlan_mlme_cfg_set_vht_tx_bfee_ant_supp(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp() - gets vht Beamformee antenna + * support cap into cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_cfg_get_vht_tx_bfee_ant_supp(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_rx_mcs_map() - gets vht rx mcs map from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_rx_mcs_map(struct wlan_objmgr_psoc *psoc, uint32_t *value) +{ + return wlan_mlme_cfg_get_vht_rx_mcs_map(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_rx_mcs_map() - sets rx mcs map into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_vht_rx_mcs_map(struct wlan_objmgr_psoc *psoc, uint32_t value) +{ + return wlan_mlme_cfg_set_vht_rx_mcs_map(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_tx_mcs_map() - gets vht tx mcs map from + * cfg item + * @psoc: psoc context + * @value: pointer to get required data + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_tx_mcs_map(struct wlan_objmgr_psoc *psoc, uint32_t *value) +{ + return wlan_mlme_cfg_get_vht_tx_mcs_map(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_tx_mcs_map() - sets tx mcs map into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_vht_tx_mcs_map(struct wlan_objmgr_psoc *psoc, uint32_t value) +{ + return wlan_mlme_cfg_set_vht_tx_mcs_map(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_rx_supp_data_rate() - sets rx supported data + * rate into cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_vht_rx_supp_data_rate(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + return wlan_mlme_cfg_set_vht_rx_supp_data_rate(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_tx_supp_data_rate() - sets tx supported data rate into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_vht_tx_supp_data_rate(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + return wlan_mlme_cfg_set_vht_tx_supp_data_rate(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_vht_basic_mcs_set() - gets basic mcs set from + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_basic_mcs_set(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_cfg_get_vht_basic_mcs_set(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_vht_basic_mcs_set() - sets basic mcs set into + * cfg item + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_cfg_set_vht_basic_mcs_set(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + return wlan_mlme_cfg_set_vht_basic_mcs_set(psoc, value); +} + +/** + * ucfg_mlme_get_vht_enable_tx_bf() - gets enable TXBF for 20MHZ + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_enable_tx_bf(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht_enable_tx_bf(psoc, value); +} + +/** + * ucfg_mlme_get_vht_tx_su_beamformer() - gets enable tx_su_beamformer + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_tx_su_beamformer(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht_tx_su_beamformer(psoc, value); +} + +/** + * ucfg_mlme_get_vht_channel_width() - gets Channel width capability + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_channel_width(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_vht_channel_width(psoc, value); +} + +/** + * ucfg_mlme_get_vht_rx_mcs_8_9() - VHT Rx MCS capability for 1x1 mode + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_rx_mcs_8_9(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_vht_rx_mcs_8_9(psoc, value); +} + +/** + * ucfg_mlme_get_vht_tx_mcs_8_9() - VHT Tx MCS capability for 1x1 mode + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_tx_mcs_8_9(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_vht_tx_mcs_8_9(psoc, value); +} + +/** + * ucfg_mlme_get_vht_rx_mcs_2x2() - VHT Rx MCS capability for 2x2 mode + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_rx_mcs_2x2(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_vht_rx_mcs_2x2(psoc, value); +} + +/** + * ucfg_mlme_get_vht_tx_mcs_2x2() - VHT Tx MCS capability for 2x2 mode + * for 11ac + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_tx_mcs_2x2(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_vht_tx_mcs_2x2(psoc, value); +} + +/** + * ucfg_mlme_peer_get_assoc_rsp_ies() - Get assoc response sent to peer + * @peer: WLAN peer objmgr + * @ie_buf: Pointer to IE buffer + * @ie_len: Length of the IE buffer + * + * This API is used to get the assoc response sent to peer + * as part of association. + * Caller to hold reference for peer. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_peer_get_assoc_rsp_ies(struct wlan_objmgr_peer *peer, + const uint8_t **ie_buf, + size_t *ie_len) +{ + return wlan_mlme_peer_get_assoc_rsp_ies(peer, ie_buf, ie_len); +} + +/** + * ucfg_mlme_get_ini_vdev_config() - get the ini capability of vdev + * @vdev: pointer to the vdev obj + * + * This API will get the ini config of the vdev related to + * the nss, chains params + * + * Return: pointer to the nss, chain param ini cfg structure + */ +static inline struct wlan_mlme_nss_chains * +ucfg_mlme_get_ini_vdev_config(struct wlan_objmgr_vdev *vdev) +{ + return mlme_get_ini_vdev_config(vdev); +} + +/** + * ucfg_mlme_get_dynamic_vdev_config() - get the dynamic capability of vdev + * @vdev: pointer to the vdev obj + * + * This API will get the dynamic config of the vdev related to nss, + * chains params + * + * Return: pointer to the nss, chain param dynamic cfg structure + */ +static inline struct wlan_mlme_nss_chains * +ucfg_mlme_get_dynamic_vdev_config(struct wlan_objmgr_vdev *vdev) +{ + return mlme_get_dynamic_vdev_config(vdev); +} + +/** + * ucfg_mlme_get_vht20_mcs9() - Enables VHT MCS9 in 20M BW operation + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht20_mcs9(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht20_mcs9(psoc, value); +} + +/** + * ucfg_mlme_get_enable_dynamic_nss_chains_cfg() - API to get whether dynamic + * nss and chain config is enabled or not + * @psoc: psoc context + * @value: data to be set + * + * API to get whether dynamic nss and chain config is enabled or not + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_enable_dynamic_nss_chains_cfg(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_enable_dynamic_nss_chains_cfg(psoc, value); +} + +/** + * ucfg_mlme_get_restart_sap_on_dynamic_nss_chains_cfg() - API to get whether + * SAP needs to be restarted or not on dynamic nss chain config + * @psoc: psoc context + * @value: data to be set + * + * API to get whether SAP needs to be restarted or not on dynamic nss chain + * config + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_restart_sap_on_dynamic_nss_chains_cfg( + struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_restart_sap_on_dynamic_nss_chains_cfg(psoc, value); +} + +/** + * ucfg_mlme_update_dynamic_nss_chains_support() - API to update + * dynamic_nss_chains_support + * + * @psoc: psoc context + * @val: data to be set + * + * API is used to update dynamic_nss_chains_support flag in wlan_mlme_cfg + * to maintain this value in mlme context + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_update_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return wlan_mlme_cfg_set_dynamic_nss_chains_support(psoc, val); +} + +/** + * ucfg_mlme_get_sta_num_tx_chains() - UCFG API to get station num tx chains + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @tx_chains : tx_chains out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_sta_num_tx_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *tx_chains) +{ + return wlan_mlme_get_sta_num_tx_chains(psoc, vdev, tx_chains); +} + +/** + * ucfg_mlme_get_sta_num_rx_chains() - UCFG API to get station num rx chains + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @rx_chains : rx_chains out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_sta_num_rx_chains(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *rx_chains) +{ + return wlan_mlme_get_sta_num_rx_chains(psoc, vdev, rx_chains); +} + +/** + * ucfg_mlme_get_sta_tx_nss() - UCFG API to get station tx NSS + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @tx_nss : tx_nss out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_sta_tx_nss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, uint8_t *tx_nss) +{ + return wlan_mlme_get_sta_tx_nss(psoc, vdev, tx_nss); +} + +/** + * ucfg_mlme_get_sta_rx_nss() - UCFG API to get station rx NSS + * + * @psoc: psoc context + * @vdev: pointer to vdev + * @rx_nss : rx_nss out parameter + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_sta_rx_nss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t *rx_nss) +{ + return wlan_mlme_get_sta_rx_nss(psoc, vdev, rx_nss); +} + +/** + * ucfg_mlme_get_vht_enable2x2() - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht_enable2x2(psoc, value); +} + +/** + * ucfg_mlme_get_force_sap_enabled() - Get the value of force SAP enabled + * @psoc: psoc context + * @value: data to get + * + * Get the value of force SAP enabled + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_force_sap_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_force_sap_enabled(psoc, value); +} + +/** + * ucfg_mlme_set_vht_enable2x2() - Enables/disables VHT Tx/Rx MCS values for 2x2 + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_set_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_vht_enable2x2(psoc, value); +} + +/** + * ucfg_mlme_get_vht_enable_paid() - Enables/disables paid feature + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_enable_paid(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht_enable_paid(psoc, value); +} + +/** + * ucfg_mlme_get_vht_enable_gid() - Enables/disables gid feature + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_enable_gid(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht_enable_gid(psoc, value); +} + +/** + * ucfg_mlme_get_vht_for_24ghz() - Get mlme cfg of vht for 24ghz + * @psoc: psoc context + * @value: data to get + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vht_for_24ghz(psoc, value); +} + +/** + * ucfg_mlme_set_vht_for_24ghz() - Enables/disables vht for 24ghz + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_set_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_vht_for_24ghz(psoc, value); +} + +/** + * ucfg_mlme_get_vendor_vht_for_24ghz() - Get mlme cfg of vendor vht for 24ghz + * @psoc: psoc context + * @value: data to be set + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_get_vendor_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_vendor_vht_for_24ghz(psoc, value); +} + +/** + * ucfg_mlme_update_vht_cap() - Update vht capabilities + * @psoc: psoc context + * @cfg: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline +QDF_STATUS ucfg_mlme_update_vht_cap(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_vht_cap *cfg) +{ + return mlme_update_vht_cap(psoc, cfg); +} + +/** + * ucfg_mlme_update_nss_vht_cap() - Update the number of spatial + * streams supported for vht + * @psoc: psoc context + * + * Inline UCFG API to be used by HDD/OSIF callers to get the + * ignore_peer_ht_opmode flag value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_update_nss_vht_cap(struct wlan_objmgr_psoc *psoc) +{ + return mlme_update_nss_vht_cap(psoc); +} + +/** + * ucfg_mlme_is_11h_enabled() - Get 11h flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_11h_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_is_11h_enabled(psoc, value); +} + +/** + * ucfg_mlme_set_11h_enabled() - Set 11h flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_11h_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_11h_enabled(psoc, value); +} + +/** + * ucfg_mlme_is_11d_enabled() - Get 11d flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_11d_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_is_11d_enabled(psoc, value); +} + +/** + * ucfg_mlme_set_11d_enabled() - Set 11d flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_11d_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_11d_enabled(psoc, value); +} + +/** + * ucfg_mlme_is_rf_test_mode_enabled() - Get rf test mode flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_rf_test_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_is_rf_test_mode_enabled(psoc, value); +} + +/** + * ucfg_mlme_set_rf_test_mode_enabled() - Set rf test mode flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_rf_test_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_rf_test_mode_enabled(psoc, value); +} + +/** + * ucfg_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled() - Get disable vlp sta + * conn to sp ap flag + * @psoc: pointer to psoc object + * @value: pointer to hold the value of flag + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled( + struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled(psoc, value); +} + +/** + * ucfg_mlme_is_standard_6ghz_conn_policy_enabled() - Get 6ghz standard + * connection policy flag + * @psoc: pointer to psoc object + * @value: pointer to hold the value of flag + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_standard_6ghz_conn_policy_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_is_standard_6ghz_conn_policy_enabled(psoc, value); +} + +/** + * ucfg_mlme_set_eht_mode() - Set EHT mode of operation + * @psoc: pointer to psoc object + * @value: EHT mode value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode value) +{ + return wlan_mlme_set_eht_mode(psoc, value); +} + +/** + * ucfg_mlme_get_eht_mode() - Get EHT mode of operation + * @psoc: pointer to psoc object + * @value: EHT mode value that is set by the user + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode *value) +{ + return wlan_mlme_get_eht_mode(psoc, value); +} + +/** + * ucfg_mlme_is_multipass_sap() - check whether FW supports + * multipass sap capabilities + * @psoc: pointer to psoc object + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: True if FW support mulitpass sap + */ +static inline bool +ucfg_mlme_is_multipass_sap(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_is_multipass_sap(psoc); +} + +/** + * ucfg_mlme_set_emlsr_mode_enabled() - Set eMLSR mode flag + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_emlsr_mode_enabled(psoc, value); +} + +/** + * ucfg_mlme_get_emlsr_mode_enabled() - Get eMLSR mode flag + * @psoc: pointer to psoc object + * @value: Value that is set by the user + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_emlsr_mode_enabled(psoc, value); +} + +/** + * ucfg_mlme_set_t2lm_negotiation_supported() - Enables/disables t2lm + * negotiation support value + * @psoc: psoc context + * @value: data to be set + * + * Inline UCFG API to be used by HDD/OSIF callers to set the + * t2lm negotiation supported value + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_set_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_t2lm_negotiation_supported(psoc, value); +} + +/** + * ucfg_mlme_get_opr_rate() - Get operational rate set + * @vdev: pointer to vdev object + * @buf: buffer to get rates set + * @len: length of the buffer + * + * Return: length of the rates set + */ +static inline qdf_size_t +ucfg_mlme_get_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *buf, + qdf_size_t len) +{ + return mlme_get_opr_rate(vdev, buf, len); +} + +/** + * ucfg_mlme_get_ext_opr_rate() - Get extended operational rate set + * @vdev: pointer to vdev object + * @buf: buffer to get rates set + * @len: length of the buffer + * + * Return: length of the rates set + */ +static inline qdf_size_t +ucfg_mlme_get_ext_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *buf, + qdf_size_t len) +{ + return mlme_get_ext_opr_rate(vdev, buf, len); +} + +/** + * ucfg_mlme_get_mcs_rate() - Get MCS based rate set + * @vdev: pointer to vdev object + * @buf: buffer to get rates set + * @len: length of the buffer + * + * Return: length of the rates set + */ +static inline qdf_size_t +ucfg_mlme_get_mcs_rate(struct wlan_objmgr_vdev *vdev, uint8_t *buf, + qdf_size_t len) +{ + return mlme_get_mcs_rate(vdev, buf, len); +} + +/** + * ucfg_mlme_get_supported_mcs_set() - Get Supported MCS set + * @psoc: pointer to psoc object + * @buf: caller buffer to copy mcs set info + * @len: length of the buffer + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_supported_mcs_set(struct wlan_objmgr_psoc *psoc, uint8_t *buf, + qdf_size_t *len); + +/** + * ucfg_mlme_set_supported_mcs_set() - Get Supported MCS set + * @psoc: pointer to psoc object + * @buf: caller buffer having mcs set info + * @len: length of the buffer + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_supported_mcs_set(struct wlan_objmgr_psoc *psoc, uint8_t *buf, + qdf_size_t len); + +/** + * ucfg_mlme_get_current_mcs_set() - Get current MCS set + * @psoc: pointer to psoc object + * @buf: caller buffer to copy mcs set info + * @len: length of the buffer + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_current_mcs_set(struct wlan_objmgr_psoc *psoc, uint8_t *buf, + qdf_size_t *len); + +/** + * ucfg_mlme_get_sta_keepalive_method() - Get sta_keepalive_method + * @psoc: pointer to psoc object + * @val: Value to pass to the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_sta_keepalive_method(struct wlan_objmgr_psoc *psoc, + enum station_keepalive_method *val); + +/** + * ucfg_mlme_stats_get_periodic_display_time() - get display time + * @psoc: pointer to psoc object + * @periodic_display_time: buffer to hold value + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_stats_get_periodic_display_time(struct wlan_objmgr_psoc *psoc, + uint32_t *periodic_display_time); + +/** + * ucfg_mlme_stats_get_cfg_values() - get stats cfg values + * @psoc: pointer to psoc object + * @link_speed_rssi_high: link speed high limit + * @link_speed_rssi_mid: link speed high mid + * @link_speed_rssi_low: link speed high low + * @link_speed_rssi_report: link speed report limit + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_stats_get_cfg_values(struct wlan_objmgr_psoc *psoc, + int *link_speed_rssi_high, + int *link_speed_rssi_mid, + int *link_speed_rssi_low, + uint32_t *link_speed_rssi_report); + +/** + * ucfg_mlme_stats_is_link_speed_report_actual() - is link speed report set + * actual + * @psoc: pointer to psoc object + * + * Return: True is report set to actual + */ +bool +ucfg_mlme_stats_is_link_speed_report_actual(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_stats_is_link_speed_report_max() - is link speed report set max + * @psoc: pointer to psoc object + * + * Return: True is report set to max + */ +bool +ucfg_mlme_stats_is_link_speed_report_max(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_stats_is_link_speed_report_max_scaled() - is link speed report set + * max scaled + * @psoc: pointer to psoc object + * + * Return: True is report set to max scaled + */ +bool +ucfg_mlme_stats_is_link_speed_report_max_scaled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_get_tl_delayed_trgr_frm_int() - Get delay interval(in ms) + * of UAPSD auto trigger. + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: None + */ +static inline +void ucfg_mlme_get_tl_delayed_trgr_frm_int(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + wlan_mlme_get_tl_delayed_trgr_frm_int(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_dir_ac_vi() - Get TSPEC direction for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_dir_ac_vi(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_wmm_dir_ac_vi(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_nom_msdu_size_ac_vi() - Get normal MSDU size for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_nom_msdu_size_ac_vi(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_wmm_nom_msdu_size_ac_vi(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_mean_data_rate_ac_vi() - mean data rate for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_mean_data_rate_ac_vi(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_mean_data_rate_ac_vi(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_min_phy_rate_ac_vi() - min PHY rate for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_min_phy_rate_ac_vi(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_min_phy_rate_ac_vi(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_sba_ac_vi() - surplus bandwidth allowance for VI + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_sba_ac_vi(struct wlan_objmgr_psoc *psoc, uint16_t *value) +{ + return wlan_mlme_get_wmm_sba_ac_vi(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_vi_srv_intv() - Get Uapsd service + * interval for video + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_vi_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_vi_srv_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_vi_sus_intv() - Get Uapsd suspension + * interval for video + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_vi_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_vi_sus_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_dir_ac_be() - Get TSPEC direction for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_dir_ac_be(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_wmm_dir_ac_be(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_nom_msdu_size_ac_be() - Get normal MSDU size for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_nom_msdu_size_ac_be(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_wmm_nom_msdu_size_ac_be(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_mean_data_rate_ac_be() - mean data rate for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_mean_data_rate_ac_be(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_mean_data_rate_ac_be(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_min_phy_rate_ac_be() - min PHY rate for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_min_phy_rate_ac_be(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_min_phy_rate_ac_be(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_sba_ac_be() - surplus bandwidth allowance for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_sba_ac_be(struct wlan_objmgr_psoc *psoc, uint16_t *value) +{ + return wlan_mlme_get_wmm_sba_ac_be(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_be_srv_intv() - Get Uapsd service interval for BE + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_be_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_be_srv_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_be_sus_intv() - Get Uapsd suspension interval for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_be_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_be_sus_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_dir_ac_bk() - Get TSPEC direction for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_dir_ac_bk(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_wmm_dir_ac_bk(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_nom_msdu_size_ac_bk() - Get normal MSDU size for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_nom_msdu_size_ac_bk(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_wmm_nom_msdu_size_ac_bk(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_mean_data_rate_ac_bk() - mean data rate for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_mean_data_rate_ac_bk(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_mean_data_rate_ac_bk(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_min_phy_rate_ac_bk() - min PHY rate for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_wmm_min_phy_rate_ac_bk(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_min_phy_rate_ac_bk(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_sba_ac_bk() - surplus bandwidt allowance for BE + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_sba_ac_bk(struct wlan_objmgr_psoc *psoc, uint16_t *value) +{ + return wlan_mlme_get_wmm_sba_ac_bk(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_bk_srv_intv() - Get Uapsd service interval for BK + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_bk_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_bk_srv_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_bk_sus_intv() - Get Uapsd suspension interval for BK + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_bk_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_wmm_uapsd_bk_sus_intv(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_mode() - Enable WMM feature + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_mode(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_wmm_mode(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_wlm_level() - Get the WLM level value + * @psoc: pointer to psoc object + * @level: level that needs to be filled. + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_wlm_level(struct wlan_objmgr_psoc *psoc, + uint8_t *level) +{ + return mlme_get_cfg_wlm_level(psoc, level); +} + +/** + * ucfg_mlme_cfg_get_wlm_reset() - Get the WLM reset flag + * @psoc: pointer to psoc object + * @reset: reset that needs to be filled. + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_wlm_reset(struct wlan_objmgr_psoc *psoc, + bool *reset) +{ + return mlme_get_cfg_wlm_reset(psoc, reset); +} + +#ifdef WLAN_FEATURE_11AX +/** + * ucfg_mlme_update_tgt_he_cap() - Update tgt he cap in mlme component + * + * @psoc: pointer to psoc object + * @cfg: pointer to config params from target + * + * Inline UCFG API to be used by HDD/OSIF callers to update + * he caps in mlme. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_update_tgt_he_cap(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_cfg *cfg) +{ + return mlme_update_tgt_he_caps_in_cfg(psoc, cfg); +} + +/** + * ucfg_mlme_cfg_get_he_caps() - Get the HE capability info + * @psoc: pointer to psoc object + * @he_cap: Caps that needs to be filled. + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_he_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEhe_cap *he_cap) +{ + return mlme_cfg_get_he_caps(psoc, he_cap); +} + +/** + * ucfg_mlme_cfg_get_he_ul_mumimo() - Get the HE Ul Mumio + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_he_ul_mumimo(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_cfg_get_he_ul_mumimo(psoc, value); +} + +/** + * ucfg_mlme_cfg_set_he_ul_mumimo() - Set the HE Ul Mumio + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_set_he_ul_mumimo(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + return wlan_mlme_cfg_set_he_ul_mumimo(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_enable_ul_mimo() - Get the HE Ul mimo + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_enable_ul_mimo(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_cfg_get_enable_ul_mimo(psoc, value); +} + +/** + * ucfg_mlme_cfg_get_enable_ul_ofdm() - Get enable ul ofdm + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_enable_ul_ofdm(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_cfg_get_enable_ul_ofdm(psoc, value); +} +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * ucfg_mlme_update_tgt_eht_cap() - Update tgt EHT cap in mlme component + * + * @psoc: pointer to psoc object + * @cfg: pointer to config params from target + * + * Inline UCFG API to be used by HDD/OSIF callers to update + * EHT caps in mlme. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_FAILURE + */ +static inline QDF_STATUS +ucfg_mlme_update_tgt_eht_cap(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_cfg *cfg) +{ + return mlme_update_tgt_eht_caps_in_cfg(psoc, cfg); +} + +static inline QDF_STATUS +ucfg_mlme_update_tgt_mlo_cap(struct wlan_objmgr_psoc *psoc) +{ + return mlme_update_tgt_mlo_caps_in_cfg(psoc); +} + +/** + * ucfg_mlme_get_usr_disable_sta_eht() - Get user disable sta eht flag + * @psoc: psoc object + * + * Return: true if user has disabled eht in connect request + */ +static inline +bool ucfg_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_usr_disable_sta_eht(psoc); +} + +/** + * ucfg_mlme_set_usr_disable_sta_eht() - Set user disable sta eht flag + * @psoc: psoc object + * @disable: eht disable flag + * + * Return: void + */ +static inline +void ucfg_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc, + bool disable) +{ + wlan_mlme_set_usr_disable_sta_eht(psoc, disable); +} +#else +static inline QDF_STATUS +ucfg_mlme_update_tgt_mlo_cap(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool ucfg_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline +void ucfg_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc, + bool disable) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * ucfg_mlme_get_eht_mld_id() - Get the MLD ID of the requested BSS + * @psoc: pointer to psoc object + * + * This API gives the MLD ID of the requested BSS + * + * Return: MLD ID of the requested BSS + */ +static inline uint8_t +ucfg_mlme_get_eht_mld_id(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_eht_mld_id(psoc); +} + +/** + * ucfg_mlme_set_eht_mld_id() - Set MLD ID of the requested BSS information + * @psoc: pointer to psoc object + * @value: set MLD ID + * + * This API sets the MLD ID of the requested BSS information within the ML + * probe request. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_set_eht_mld_id(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + return wlan_mlme_set_eht_mld_id(psoc, value); +} +#else +static inline uint8_t +ucfg_mlme_get_eht_mld_id(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_mlme_set_eht_mld_id(struct wlan_objmgr_psoc *psoc, uint8_t value) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +/** + * ucfg_mlme_get_80211e_is_enabled() - Enable 802.11e feature + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_80211e_is_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_80211e_is_enabled(psoc, value); +} + +/** + * ucfg_mlme_get_wmm_uapsd_mask() - setup U-APSD mask for ACs + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_wmm_uapsd_mask(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + return wlan_mlme_get_wmm_uapsd_mask(psoc, value); +} + +#ifdef FEATURE_WLAN_ESE +/** + * ucfg_mlme_get_inactivity_interval() - Infra Inactivity Interval + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: None + */ +static inline void +ucfg_mlme_get_inactivity_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + wlan_mlme_get_inactivity_interval(psoc, value); +} + +/** + * ucfg_mlme_is_ese_enabled() - ese feature enable or not + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_is_ese_enabled(struct wlan_objmgr_psoc *psoc, bool *val); +#endif /* FEATURE_WLAN_ESE */ + +/** + * ucfg_mlme_get_is_ts_burst_size_enable() - Get TS burst size flag + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: None + */ +static inline +void ucfg_mlme_get_is_ts_burst_size_enable(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + wlan_mlme_get_is_ts_burst_size_enable(psoc, value); +} + +/** + * ucfg_mlme_get_ts_info_ack_policy() - Get TS ack policy + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: None + */ +static inline void +ucfg_mlme_get_ts_info_ack_policy(struct wlan_objmgr_psoc *psoc, + enum mlme_ts_info_ack_policy *value) +{ + wlan_mlme_get_ts_info_ack_policy(psoc, value); +} + +/** + * ucfg_mlme_get_ts_acm_value_for_ac() - Get ACM value for AC + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_ts_acm_value_for_ac(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_get_ts_acm_value_for_ac(psoc, value); +} + +/* + * ucfg_mlme_is_sap_uapsd_enabled() - SAP UAPSD enabled status. + * @psoc: pointer to psoc object + * @value: sap uapsd enabled flag value requested from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_is_sap_uapsd_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_is_sap_uapsd_enabled(psoc, value); +} + +/* + * ucfg_mlme_set_sap_uapsd_flag() - SAP UAPSD enabled status. + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_sap_uapsd_flag(struct wlan_objmgr_psoc *psoc, bool value) +{ + return wlan_mlme_set_sap_uapsd_flag(psoc, value); +} + +/** + * ucfg_mlme_get_enable_deauth_to_disassoc_map() - Enable deauth_to_disassoc_map + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_enable_deauth_to_disassoc_map(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_ap_random_bssid_enable() - Enable random bssid + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_ap_random_bssid_enable(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_sta_miracast_mcc_rest_time() - Get STA/MIRACAST MCC rest time + * + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * This API gives rest time to be used when STA and MIRACAST MCC conc happens + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_get_sta_miracast_mcc_rest_time(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_sta_miracast_mcc_rest_time(psoc, value); +} + +/** + * ucfg_mlme_get_max_modulated_dtim_ms() - get sap max modulated dtim + * @psoc: pointer to psoc object + * @value: Value that needs to be set from the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_max_modulated_dtim_ms(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + return wlan_mlme_get_max_modulated_dtim_ms(psoc, value); +} + +/** + * ucfg_mlme_get_sap_mcc_chnl_avoid() - Check if SAP MCC needs to be avoided + * + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * This API fetches the user setting to determine if SAP MCC with other persona + * to be avoided. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_get_sap_mcc_chnl_avoid(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_sap_mcc_chnl_avoid(psoc, value); +} + +/** + * ucfg_mlme_get_mcc_bcast_prob_resp() - Get broadcast probe rsp in MCC + * + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * To get INI value which helps to determe whether to enable/disable use of + * broadcast probe response to increase the detectability of SAP in MCC mode. + * + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_get_mcc_bcast_prob_resp(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_mcc_bcast_prob_resp(psoc, value); +} + +/** + * ucfg_mlme_get_mcc_rts_cts_prot() - To get RTS-CTS protection in MCC. + * + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * To get INI value which helps to determine whether to enable/disable + * use of long duration RTS-CTS protection when SAP goes off + * channel in MCC mode. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_get_mcc_rts_cts_prot(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_mcc_rts_cts_prot(psoc, value); +} + +/** + * ucfg_mlme_get_mcc_feature() - To find out to enable/disable MCC feature + * + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * To get INI value which helps to determine whether to enable MCC feature + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_get_mcc_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_get_mcc_feature(psoc, value); +} + +/** + * ucfg_wlan_mlme_get_rrm_enabled() - Get the rrm enabled + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_wlan_mlme_get_rrm_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_rrm_enabled(psoc, value); +} + +/** + * ucfg_mlme_get_latency_enable() - Get the latency_enable + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_latency_enable(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * ucfg_mlme_get_latency_level() - Get the latency level + * @psoc: pointer to psoc object + * @value: Value that needs to be get from the caller + * latency values are defined in WMI_WLM_LATENCY_LEVEL + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_latency_level(struct wlan_objmgr_psoc *psoc, uint8_t *value); + +/** + * ucfg_mlme_get_latency_host_flags() - Get host flags for latency level + * @psoc: pointer to psoc object + * @latency_level: latency level + * @value: Value that needs to be get from the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_latency_host_flags(struct wlan_objmgr_psoc *psoc, + uint8_t latency_level, uint32_t *value); + +/** + * ucfg_mlme_get_dtim_selection_diversity() - get dtim selection diversity + * bitmap + * @psoc: pointer to psoc object + * @dtim_selection_div: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_get_dtim_selection_diversity(struct wlan_objmgr_psoc *psoc, + uint32_t *dtim_selection_div) +{ + return wlan_mlme_get_dtim_selection_diversity(psoc, dtim_selection_div); +} + +/** + * ucfg_mlme_get_bmps_min_listen_interval() - get beacon mode powersave + * minimum listen interval value + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_get_bmps_min_listen_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_bmps_min_listen_interval(psoc, value); +} + +/** + * ucfg_mlme_get_bmps_max_listen_interval() - get beacon mode powersave + * maximum listen interval value + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_get_bmps_max_listen_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_bmps_max_listen_interval(psoc, value); +} + +/** + * ucfg_mlme_get_auto_bmps_timer_value() - get bmps timer value + * minimum listen interval value + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_get_auto_bmps_timer_value(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_auto_bmps_timer_value(psoc, value); +} + +/** + * ucfg_mlme_is_bmps_enabled() - check if beacon mode powersave is + * enabled/disabled + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_is_bmps_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_is_bmps_enabled(psoc, value); +} + +/** + * ucfg_mlme_is_imps_enabled() - check if idle mode powersave is + * enabled/disabled + * @psoc: pointer to psoc object + * @value: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_is_imps_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return wlan_mlme_is_imps_enabled(psoc, value); +} + +/** + * ucfg_mlme_override_bmps_imps() - disable imps/bmps as part of + * override to disable all ps features + * @psoc: pointer to psoc object + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static inline QDF_STATUS +ucfg_mlme_override_bmps_imps(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_override_bmps_imps(psoc); +} + +#ifdef MWS_COEX +/** + * ucfg_mlme_get_mws_coex_4g_quick_tdm() - Get mws coex 4g quick tdm + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_mws_coex_4g_quick_tdm(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_get_mws_coex_5g_nr_pwr_limit() - Get mws coex 5g nr pwr limit + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_mws_coex_5g_nr_pwr_limit(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_get_mws_coex_pcc_channel_avoid_delay() - Get mws coex pcc + * avoid channel delay + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_mws_coex_pcc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * ucfg_mlme_get_mws_coex_scc_channel_avoid_delay() - Get mws coex scc + * avoidance channel delay + * @psoc: pointer to psoc object + * @val: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_mws_coex_scc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, + uint32_t *val); +#endif + +/** + * ucfg_mlme_get_etsi_srd_chan_in_master_mode - get etsi srd chan + * in master mode + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_etsi_srd_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * ucfg_mlme_get_5dot9_ghz_chan_in_master_mode - get fcc 5.9 GHz chan + * in master mode + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_5dot9_ghz_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_srd_master_mode_for_vdev() - Get SRD master mode for vdev + * @psoc: pointer to psoc object + * @vdev_opmode: vdev opmode + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value); + +#ifdef SAP_AVOID_ACS_FREQ_LIST +/** + * ucfg_mlme_get_acs_avoid_freq_list - get acs avoid frequency list + * @psoc: pointer to psoc object + * @freq_list: Pointer to output freq list + * @freq_list_num: Pointer to the output number of frequencies filled + * in the freq_list + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_acs_avoid_freq_list(struct wlan_objmgr_psoc *psoc, + uint16_t *freq_list, uint8_t *freq_list_num); + +#else +static inline QDF_STATUS +ucfg_mlme_get_acs_avoid_freq_list(struct wlan_objmgr_psoc *psoc, + uint16_t *freq_list, uint8_t *freq_list_num) +{ + *freq_list_num = 0; + return QDF_STATUS_E_INVAL; +} +#endif + +/** + * ucfg_mlme_get_11d_in_world_mode - get whether 11d is enabled in world mode + * in master mode + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_11d_in_world_mode(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_restart_beaconing_on_ch_avoid() - get restart beaconing on + * channel avoid + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_restart_beaconing_on_ch_avoid(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * ucfg_mlme_get_indoor_channel_support() - get indoor channel support + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_indoor_channel_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_scan_11d_interval() - get scan 11d interval + * @psoc: pointer to psoc object + * @value: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_scan_11d_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * ucfg_mlme_get_nol_across_regdmn() - get scan 11d interval + * @psoc: pointer to psoc object + * @value: Pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ + +QDF_STATUS +ucfg_mlme_get_nol_across_regdmn(struct wlan_objmgr_psoc *psoc, bool *value); + +/** + * ucfg_mlme_get_valid_channel_freq_list() - get valid channel + * list + * @psoc: pointer to psoc object + * @channel_list: pointer to return channel list + * @channel_list_num: pointer to return channel list number + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_valid_channel_freq_list(struct wlan_objmgr_psoc *psoc, + uint32_t *channel_list, + uint32_t *channel_list_num); + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * ucfg_mlme_is_subnet_detection_enabled() - check if sub net detection is + * enabled/disabled + * @psoc: pointer to psoc object + * @val: value that is requested by the caller + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +ucfg_mlme_is_subnet_detection_enabled(struct wlan_objmgr_psoc *psoc, bool *val); +#else +static QDF_STATUS +ucfg_mlme_is_subnet_detection_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * ucfg_mlme_set_current_tx_power_level() - set current tx power level + * @psoc: pointer to psoc object + * @value: data to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_current_tx_power_level(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * ucfg_mlme_get_current_tx_power_level() - get current tx power level + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_current_tx_power_level(struct wlan_objmgr_psoc *psoc, + uint8_t *value); + +/** + * ucfg_wlan_mlme_get_reg_tpc_info() - get current regulatory tpc info + * @vdev: pointer to vdev object + * @tpc_info: pointer to tpc info buffer + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_wlan_mlme_get_reg_tpc_info(struct wlan_objmgr_vdev *vdev, + struct reg_tpc_power_info *tpc_info); + +/** + * ucfg_mlme_set_obss_detection_offload_enabled() - Enable obss offload + * @psoc: pointer to psoc object + * @value: enable or disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_obss_detection_offload_enabled(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * ucfg_mlme_set_obss_color_collision_offload_enabled() - Enable obss color + * collision offload + * @psoc: pointer to psoc object + * @value: enable or disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_obss_color_collision_offload_enabled( + struct wlan_objmgr_psoc *psoc, uint8_t value); + +/** + * ucfg_mlme_set_bss_color_collision_det_sta() - Enable bss color + * collision detection offload for STA mode + * @psoc: pointer to psoc object + * @value: enable or disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_bss_color_collision_det_sta(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * ucfg_mlme_set_bss_color_collision_det_support() - Set bss color collision + * detection offload support from FW for STA mode + * @psoc: pointer to psoc object + * @value: enable or disable + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_bss_color_collision_det_support(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * ucfg_mlme_get_bss_color_collision_det_support() - Get bss color collision + * detection offload FW support for STA mode + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_bss_color_collision_det_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_set_restricted_80p80_bw_supp() - Set the restricted 80p80 support + * @psoc: pointer to psoc object + * @restricted_80p80_supp: Value to be set from the caller + * + * Return: QDF Status + */ +QDF_STATUS ucfg_mlme_set_restricted_80p80_bw_supp(struct wlan_objmgr_psoc *psoc, + bool restricted_80p80_supp); + +/** + * ucfg_mlme_get_restricted_80p80_bw_supp() - Get the restricted 80p80 support + * @psoc: pointer to psoc object + * + * Return: true or false + */ +bool ucfg_mlme_get_restricted_80p80_bw_supp(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_get_update_chan_width_allowed - Get value of INI + * is_update_chan_width_allowed + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_update_chan_width_allowed(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_channel_bonding_24ghz() - get channel bonding mode of 24ghz + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_channel_bonding_24ghz(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * ucfg_mlme_set_channel_bonding_24ghz() - set channel bonding mode for 24ghz + * @psoc: pointer to psoc object + * @value: channel bonding mode + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_channel_bonding_24ghz(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * ucfg_mlme_get_channel_bonding_5ghz() - get channel bonding mode of 5ghz + * @psoc: pointer to psoc object + * @value: pointer to the value which will be filled for the caller + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, + uint32_t *value); + +/** + * ucfg_mlme_set_channel_bonding_5ghz() - set channel bonding mode for 5ghz + * @psoc: pointer to psoc object + * @value: channel bonding mode + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, + uint32_t value); + +/** + * ucfg_mlme_get_scan_probe_unicast_ra() - Get scan probe unicast RA cfg + * + * @psoc: pointer to psoc object + * @value: value which needs to filled by API + * + * This API gives scan probe request with unicast RA user config + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_get_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_scan_probe_unicast_ra(psoc, value); +} + +/** + * ucfg_mlme_set_scan_probe_unicast_ra() - Set scan probe unicast RA cfg + * + * @psoc: pointer to psoc object + * @value: set value + * + * This API sets scan probe request with unicast RA user config + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_mlme_set_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return wlan_mlme_set_scan_probe_unicast_ra(psoc, value); +} + +/** + * ucfg_mlme_get_peer_phymode() - get phymode of peer + * @psoc: pointer to psoc object + * @mac: Pointer to the mac addr of the peer + * @peer_phymode: phymode + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_peer_phymode(struct wlan_objmgr_psoc *psoc, uint8_t *mac, + enum wlan_phymode *peer_phymode) +{ + return mlme_get_peer_phymode(psoc, mac, peer_phymode); +} + +/** + * ucfg_mlme_validate_full_roam_scan_period() - Validate full roam scan period + * @full_roam_scan_period: Idle period in seconds between two successive + * full channel roam scans + * + * Return: True if full_roam_scan_period is in expected range, false otherwise. + */ +bool ucfg_mlme_validate_full_roam_scan_period(uint32_t full_roam_scan_period); + +/** + * ucfg_mlme_validate_scan_period() - Validate if scan period is in valid range + * @psoc: Pointer to soc + * @roam_scan_period: Scan period in msec + * + * Return: True if roam_scan_period is in expected range, false otherwise. + */ +bool ucfg_mlme_validate_scan_period(struct wlan_objmgr_psoc *psoc, + uint32_t roam_scan_period); +/** + * ucfg_mlme_get_ignore_fw_reg_offload_ind() - Get the + * ignore_fw_reg_offload_ind ini + * @psoc: pointer to psoc object + * @disabled: output pointer to hold user config + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_get_ignore_fw_reg_offload_ind(struct wlan_objmgr_psoc *psoc, + bool *disabled) +{ + return wlan_mlme_get_ignore_fw_reg_offload_ind(psoc, disabled); +} + +/** + * ucfg_mlme_get_peer_unmap_conf() - Indicate if peer unmap confirmation + * support is enabled or disabled + * @psoc: pointer to psoc object + * + * Return: true if peer unmap confirmation support is enabled, else false + */ +static inline +QDF_STATUS ucfg_mlme_get_peer_unmap_conf(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_peer_unmap_conf(psoc); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * ucfg_mlme_get_roam_reason_vsie_status() - Get roam reason vsie is + * enabled or disabled + * @psoc: pointer to psoc object + * @roam_reason_vsie_enabled: pointer to hold value of roam reason vsie + * + * Return: Success if able to get bcn rpt err vsie value, else failure + */ +static inline QDF_STATUS +ucfg_mlme_get_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t *roam_reason_vsie_enabled) +{ + return wlan_mlme_get_roam_reason_vsie_status(psoc, + roam_reason_vsie_enabled); +} + +/** + * ucfg_mlme_set_roam_reason_vsie_status() - Update roam reason vsie status + * value with user configured value + * @psoc: pointer to psoc object + * @roam_reason_vsie_enabled: value of roam reason vsie status + * + * Return: Success if able to get bcn rpt err vsie value, else failure + */ +static inline QDF_STATUS +ucfg_mlme_set_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t roam_reason_vsie_enabled) +{ + return wlan_mlme_set_roam_reason_vsie_status(psoc, + roam_reason_vsie_enabled); +} + +#endif + +/** + * ucfg_mlme_set_vdev_wifi_std() - Set vdev wifi standard support + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @wifi_std: wifi standard version + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_set_vdev_wifi_std(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + WMI_HOST_WIFI_STANDARD wifi_std); + +/** + * ucfg_mlme_set_vdev_traffic_low_latency() - Set/clear vdev low latency + * config + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @set: Flag to indicate set or clear + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set); + +/** + * ucfg_mlme_update_bss_rate_flags() - update bss rate flag as per new channel + * width + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @ch_width: channel width to update + * @eht_present: connected bss is eht capable or not + * @he_present: connected bss is he capable or not + * @vht_present: connected bss is vht capable or not + * @ht_present: connected bss is ht capable or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width ch_width, + uint8_t eht_present, + uint8_t he_present, + uint8_t vht_present, + uint8_t ht_present); + +/** + * ucfg_mlme_send_ch_width_update_with_notify() - Send chwidth with notify + * capability of FW + * @psoc: pointer to psoc object + * @link_vdev: Link VDEV object + * @ch_width: channel width to update + * @link_vdev_id: vdev id for each link + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *link_vdev, + enum phy_ch_width ch_width, + uint8_t link_vdev_id); + +/** + * ucfg_mlme_is_chwidth_with_notify_supported() - Get chwidth with notify + * capability of FW + * @psoc: pointer to psoc object + * + * Return: true if chwidth with notify feature supported + */ +bool +ucfg_mlme_is_chwidth_with_notify_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_connected_chan_stats_request() - process connected channel stats + * request + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_mlme_set_vdev_traffic_high_throughput() - Set/clear vdev high + * throughput config + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @set: Flag to indicate set or clear + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_mlme_set_vdev_traffic_high_throughput(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set); + +/** + * ucfg_mlme_set_user_ps() - Set the PS user config + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @ps_enable: Flag to indicate if user PS is enabled + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_mlme_set_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + bool ps_enable) +{ + return mlme_set_user_ps(psoc, vdev_id, ps_enable); +} + +/** + * ucfg_mlme_get_user_ps() - Get user PS flag + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * + * Return: True if user ps is enabled else false + */ +static inline +bool ucfg_mlme_get_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return mlme_get_user_ps(psoc, vdev_id); +} + +/** + * ucfg_mlme_set_ft_over_ds() - update ft_over_ds status with user configured + * value + * @psoc: pointer to psoc object + * @ft_over_ds_enable: value of ft_over_ds + * + * Return: QDF Status + */ +static inline QDF_STATUS +ucfg_mlme_set_ft_over_ds(struct wlan_objmgr_psoc *psoc, + uint8_t ft_over_ds_enable) +{ + return wlan_mlme_set_ft_over_ds(psoc, ft_over_ds_enable); +} + +/** + * ucfg_mlme_is_sta_mon_conc_supported() - Check if STA + Monitor mode + * concurrency is supported + * @psoc: pointer to psoc object + * + * Return: True if supported, else false. + */ +static inline bool +ucfg_mlme_is_sta_mon_conc_supported(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_is_sta_mon_conc_supported(psoc); +} + +/** + * ucfg_mlme_cfg_get_eht_caps() - Get the EHT capability info + * @psoc: pointer to psoc object + * @eht_cap: Caps that needs to be filled. + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_cfg_get_eht_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEeht_cap *eht_cap) +{ + return mlme_cfg_get_eht_caps(psoc, eht_cap); +} + +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_ampdu_len_exp(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_cfg_get_vht_ampdu_len_exp(psoc, value); +} + +static inline QDF_STATUS +ucfg_mlme_cfg_get_vht_max_mpdu_len(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_cfg_get_vht_max_mpdu_len(psoc, value); +} + +static inline QDF_STATUS +ucfg_mlme_cfg_get_ht_smps(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + return wlan_mlme_cfg_get_ht_smps(psoc, value); +} + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +/** + * ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer() - get coex unsafe nb + * support + * @psoc: pointer to psoc object + * + * Return: coex_unsafe_chan_nb_user_prefer + */ +bool ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer( + struct wlan_objmgr_psoc *psoc); + +bool ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_mlme_get_coex_unsafe_chan_reg_disable() - get reg disable cap for + * coex unsafe channels support + * @psoc: pointer to psoc object + * + * Return: coex_unsafe_chan_reg_disable + */ +bool ucfg_mlme_get_coex_unsafe_chan_reg_disable( + struct wlan_objmgr_psoc *psoc); +#else +static inline +bool ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool ucfg_mlme_get_coex_unsafe_chan_reg_disable( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * ucfg_set_ratemask_params() - Set ratemask config + * @vdev: pointer to vdev object + * @num_ratemask: number of ratemask params + * @rate_params: ratemask params + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_set_ratemask_params(struct wlan_objmgr_vdev *vdev, + uint8_t num_ratemask, + struct config_ratemask_params *rate_params) +{ + return wlan_mlme_update_ratemask_params(vdev, num_ratemask, + rate_params); +} + +/* + * ucfg_mlme_set_user_mcc_quota() - Set the user set mcc quota in mlme + * value + * @psoc: pointer to psoc object + * @quota: pointer to user mcc quota object + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota) +{ + return wlan_mlme_set_user_mcc_quota(psoc, quota); +} + +/** + * ucfg_mlme_get_user_mcc_quota() - Get the user set mcc quota from mlme + * value + * @psoc: pointer to psoc object + * @quota: pointer to user mcc quota object + * + * Return: QDF Status + */ +static inline +QDF_STATUS ucfg_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota) +{ + return wlan_mlme_get_user_mcc_quota(psoc, quota); +} + +/** + * ucfg_mlme_get_user_mcc_quota_percentage() - Get user mcc quota percentage + * duty-cycle for a i/f type or mode + * @psoc: pointer to psoc object + * + * MCC duty-cycle value in below format + * ****************************************************** + * |bit 31-24 | bit 23-16 | bits 15-8 |bits 7-0 | + * | Unused | Quota for | chan. # for |chan. # for| + * | | 1st chan | 1st chan. |2nd chan. | + * ***************************************************** + * + * Return: primary iface MCC duty-cycle value + */ +static inline +uint32_t ucfg_mlme_get_user_mcc_quota_percentage(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_user_mcc_duty_cycle_percentage(psoc); +} + +/** + * ucfg_mlme_get_wds_mode() - Get the configured WDS mode + * @psoc: pointer to psoc object + * + * Return: supported wds mode from enum wlan_wds_mode + */ +static inline uint32_t +ucfg_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_wds_mode(psoc); +} + +/** + * ucfg_mlme_set_wds_mode() - Set the configured WDS mode + * @psoc: pointer to psoc object + * @mode: wds mode to set + * + * Return: void + */ +static inline void +ucfg_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc, uint32_t mode) +{ + wlan_mlme_set_wds_mode(psoc, mode); +} + +#ifdef WLAN_FEATURE_SON +/** + * ucfg_mlme_get_vdev_max_mcs_idx() - Get max mcs idx of given vdev + * @vdev: pointer to vdev object + * + * Return: max mcs idx of given vdev + */ +static inline uint8_t +ucfg_mlme_get_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev) +{ + return mlme_get_vdev_max_mcs_idx(vdev); +} +#endif /* WLAN_FEATURE_SON */ + +#if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_BAND_6GHZ) +/** + * ucfg_mlme_get_enable_6ghz_sp_mode_support() - Get 6 GHz SP mode support cfg + * @psoc: pointer to psoc object + * @value: value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_enable_6ghz_sp_mode_support(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_afc_disable_timer_check() - Get AFC timer check cfg + * @psoc: pointer to psoc object + * @value: value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_afc_disable_timer_check(struct wlan_objmgr_psoc *psoc, + bool *value); +/** + * ucfg_mlme_get_afc_disable_request_id_check() - Get AFC request id check cfg + * @psoc: pointer to psoc object + * @value: value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_afc_disable_request_id_check(struct wlan_objmgr_psoc *psoc, + bool *value); + +/** + * ucfg_mlme_get_afc_reg_noaction() - Get AFC no action cfg + * @psoc: pointer to psoc object + * @value: value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_afc_reg_noaction(struct wlan_objmgr_psoc *psoc, bool *value); +#else +static inline QDF_STATUS +ucfg_mlme_get_enable_6ghz_sp_mode_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_afc_disable_timer_check(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_afc_disable_request_id_check(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_afc_reg_noaction(struct wlan_objmgr_psoc *psoc, bool *value) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef CONNECTION_ROAMING_CFG +/** + * ucfg_mlme_set_connection_roaming_ini_present() - Set connection roaming ini + * present + * @psoc: pointer to psoc object + * @value: Value to be set + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_set_connection_roaming_ini_present(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * ucfg_mlme_get_connection_roaming_ini_present() - Get connection roaming ini + * present + * @psoc: pointer to psoc object + * @value: Value to be get + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_mlme_get_connection_roaming_ini_present(struct wlan_objmgr_psoc *psoc, + bool *value); +#else +static inline QDF_STATUS +ucfg_mlme_set_connection_roaming_ini_present(struct wlan_objmgr_psoc *psoc, + bool value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_mlme_get_connection_roaming_ini_present(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* CONNECTION_ROAMING_CFG */ + +/** + * ucfg_mlme_get_ch_width_from_phymode() - Convert phymode to ch_width + * @phy_mode: phy mode + * + * Return: enum phy_ch_width + */ +static inline enum phy_ch_width +ucfg_mlme_get_ch_width_from_phymode(enum wlan_phymode phy_mode) +{ + return wlan_mlme_get_ch_width_from_phymode(phy_mode); +} + +/** + * ucfg_mlme_get_peer_ch_width() - get ch_width of the given peer + * @psoc: pointer to psoc object + * @mac: peer mac + * + * Return: enum phy_ch_width + */ +static inline enum phy_ch_width +ucfg_mlme_get_peer_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t *mac) +{ + return wlan_mlme_get_peer_ch_width(psoc, mac); +} + +/** + * ucfg_mlme_get_vdev_phy_mode() - Get phymode of a vdev + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * + * Return: enum wlan_phymode + */ +enum wlan_phymode +ucfg_mlme_get_vdev_phy_mode(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +#if defined(WLAN_FEATURE_SR) +/** + * ucfg_mlme_get_sr_enable_modes() - check for which mode SR is enabled + * + * @psoc: pointer to psoc object + * @val: SR(Spatial Reuse) enable modes + * + * Return: void + */ +static inline void +ucfg_mlme_get_sr_enable_modes(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + wlan_mlme_get_sr_enable_modes(psoc, val); +} +#else +static inline void +ucfg_mlme_get_sr_enable_modes(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + *val = 0; +} +#endif + +/** + * ucfg_mlme_get_valid_channels - get valid channels for + * current regulatory domain + * @psoc: pointer to psoc object + * @ch_freq_list: list of the valid channel frequencies + * @list_len: length of the channel list + * + * This function will get valid channels for current regulatory domain + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS +ucfg_mlme_get_valid_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, uint32_t *list_len); + +/** + * ucfg_mlme_set_ul_mu_config - set ul mu config + * @psoc: pointer to psoc object + * @vdev_id : vdev ID + * @ulmu_disable: ul mu value + * + * Inline UCFG API to be used by HDD/OSIF callers + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +static inline +QDF_STATUS ucfg_mlme_set_ul_mu_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t ulmu_disable) +{ + return wlan_mlme_set_ul_mu_config(psoc, vdev_id, ulmu_disable); +} + +/** + * ucfg_mlme_assemble_rate_code - assemble rate code to be sent to FW + * @preamble: rate preamble + * @nss: number of spatial streams + * @rate: rate index + * + * Rate code assembling is different for targets which are 11ax capable. + * Check for the target support and assemble the rate code accordingly. + * + * Return: assembled rate code + */ +static inline uint32_t +ucfg_mlme_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate) +{ + return wlan_mlme_assemble_rate_code(preamble, nss, rate); +} + +/** + * ucfg_mlme_get_keepalive_period() - Get keep alive period + * @vdev: VDEV object + * + * Return: Keep alive period. + */ +static inline +uint16_t ucfg_mlme_get_keepalive_period(struct wlan_objmgr_vdev *vdev) +{ + return wlan_mlme_get_keepalive_period(vdev); +} +#endif /* _WLAN_MLME_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c new file mode 100644 index 0000000000..5b399f693a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_api.c @@ -0,0 +1,8475 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define public APIs exposed by the mlme component + */ + +#include "cfg_ucfg_api.h" +#include "wlan_mlme_main.h" +#include "wlan_mlme_ucfg_api.h" +#include "wma_types.h" +#include "wmi_unified.h" +#include "wma.h" +#include "wma_internal.h" +#include "wlan_crypto_global_api.h" +#include "wlan_utility.h" +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_vdev_mgr_utils_api.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include "wlan_psoc_mlme_api.h" +#include "wlan_action_oui_main.h" +#include "target_if.h" +#include "wlan_vdev_mgr_tgt_if_tx_api.h" +#include "wmi_unified_vdev_api.h" +#include "wlan_mlme_api.h" +#include "../../core/src/wlan_cp_stats_defs.h" +#include "wlan_reg_services_api.h" + +/* quota in milliseconds */ +#define MCC_DUTY_CYCLE 70 + +QDF_STATUS wlan_mlme_get_cfg_str(uint8_t *dst, struct mlme_cfg_str *cfg_str, + qdf_size_t *len) +{ + if (*len < cfg_str->len) { + mlme_legacy_err("Invalid len %zd", *len); + return QDF_STATUS_E_INVAL; + } + + *len = cfg_str->len; + qdf_mem_copy(dst, cfg_str->data, *len); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_cfg_str(uint8_t *src, struct mlme_cfg_str *dst_cfg_str, + qdf_size_t len) +{ + if (len > dst_cfg_str->max_len) { + mlme_legacy_err("Invalid len %zd (>%zd)", len, + dst_cfg_str->max_len); + return QDF_STATUS_E_INVAL; + } + + dst_cfg_str->len = len; + qdf_mem_copy(dst_cfg_str->data, src, len); + + return QDF_STATUS_SUCCESS; +} + +uint8_t wlan_mlme_get_tx_power(struct wlan_objmgr_psoc *psoc, + enum band_info band) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + switch (band) { + case BAND_2G: + return mlme_obj->cfg.power.tx_power_2g; + case BAND_5G: + return mlme_obj->cfg.power.tx_power_5g; + default: + break; + } + return 0; +} + +char *wlan_mlme_get_power_usage(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return NULL; + + return mlme_obj->cfg.power.power_usage.data; +} + +QDF_STATUS +wlan_mlme_get_enable_deauth_to_disassoc_map(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.gen.enable_deauth_to_disassoc_map; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_ht_cap_info(struct wlan_objmgr_psoc *psoc, + struct mlme_ht_capabilities_info + *ht_cap_info) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *ht_cap_info = mlme_obj->cfg.ht_caps.ht_cap_info; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_ht_cap_info(struct wlan_objmgr_psoc *psoc, + struct mlme_ht_capabilities_info + ht_cap_info) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.ht_caps.ht_cap_info = ht_cap_info; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_max_amsdu_num(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.ht_caps.max_num_amsdu; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_max_amsdu_num(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (!cfg_in_range(CFG_MAX_AMSDU_NUM, value)) { + mlme_legacy_err("Error in setting Max AMSDU Num"); + return QDF_STATUS_E_INVAL; + } + + mlme_obj->cfg.ht_caps.max_num_amsdu = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_ht_mpdu_density(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = (uint8_t)mlme_obj->cfg.ht_caps.ampdu_params.mpdu_density; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_ht_mpdu_density(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (!cfg_in_range(CFG_MPDU_DENSITY, value)) { + mlme_legacy_err("Invalid value %d", value); + return QDF_STATUS_E_INVAL; + } + + mlme_obj->cfg.ht_caps.ampdu_params.mpdu_density = value; + + return QDF_STATUS_SUCCESS; +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +bool wlan_mlme_get_wlm_multi_client_ll_caps(struct wlan_objmgr_psoc *psoc) +{ + return wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_SOC_WLM_MULTI_CLIENT_LL_SUPPORT); +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +uint32_t wlan_mlme_get_coex_unsafe_chan_nb_user_prefer( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return cfg_default(CFG_COEX_UNSAFE_CHAN_NB_USER_PREFER); + } + + return mlme_obj->cfg.reg.coex_unsafe_chan_nb_user_prefer; +} + +bool wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + struct wlan_objmgr_psoc *psoc) +{ + return !!(wlan_mlme_get_coex_unsafe_chan_nb_user_prefer(psoc) & + IGNORE_FW_COEX_INFO_ON_SAP_MODE); +} + +bool wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_p2p_go( + struct wlan_objmgr_psoc *psoc) +{ + return !!(wlan_mlme_get_coex_unsafe_chan_nb_user_prefer(psoc) & + IGNORE_FW_COEX_INFO_ON_P2P_GO_MODE); +} +#endif + +QDF_STATUS wlan_mlme_get_band_capability(struct wlan_objmgr_psoc *psoc, + uint32_t *band_capability) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *band_capability = mlme_obj->cfg.gen.band_capability; + + return QDF_STATUS_SUCCESS; +} + +#ifdef QCA_MULTIPASS_SUPPORT +QDF_STATUS +wlan_mlme_peer_config_vlan(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + struct peer_vlan_config_param param; + + wmi_handle = get_wmi_unified_hdl_from_pdev(wlan_vdev_get_pdev(vdev)); + if (!wmi_handle) { + mlme_err("unable to get wmi_handle"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_set(¶m, sizeof(param), 0); + + param.rx_cmd = 1; + /* Enabling Rx_insert_inner_vlan_tag */ + param.rx_insert_c_tag = 1; + param.vdev_id = wlan_vdev_get_id(vdev); + + status = wmi_send_peer_vlan_config(wmi_handle, mac_addr, param); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wlan_mlme_set_band_capability(struct wlan_objmgr_psoc *psoc, + uint32_t band_capability) + +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.band_capability = band_capability; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +bool wlan_mlme_get_vendor_handoff_control_caps(struct wlan_objmgr_psoc *psoc) +{ + return wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_SOC_VENDOR_HANDOFF_CONTROL); +} +#endif + +QDF_STATUS wlan_mlme_set_dual_sta_policy(struct wlan_objmgr_psoc *psoc, + uint8_t dual_sta_config) + +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.dual_sta_policy.concurrent_sta_policy = + dual_sta_config; + mlme_debug("Set dual_sta_config to :%d", dual_sta_config); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_dual_sta_policy(struct wlan_objmgr_psoc *psoc, + uint8_t *dual_sta_config) + +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *dual_sta_config = + mlme_obj->cfg.gen.dual_sta_policy.concurrent_sta_policy; + + return QDF_STATUS_SUCCESS; +} + +enum host_concurrent_ap_policy +wlan_mlme_convert_ap_policy_config( + enum qca_wlan_concurrent_ap_policy_config ap_config) +{ + switch (ap_config) { + case QCA_WLAN_CONCURRENT_AP_POLICY_UNSPECIFIED: + return HOST_CONCURRENT_AP_POLICY_UNSPECIFIED; + case QCA_WLAN_CONCURRENT_AP_POLICY_GAMING_AUDIO: + return HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO; + case QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: + return HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING; + case QCA_WLAN_CONCURRENT_AP_POLICY_XR: + return HOST_CONCURRENT_AP_POLICY_XR; + default: + return HOST_CONCURRENT_AP_POLICY_UNSPECIFIED; + } +} + +void wlan_mlme_ll_lt_sap_send_oce_flags_fw(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = NULL; + uint8_t vdev_id; + uint8_t updated_fw_value = 0; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return; + + updated_fw_value = mlme_obj->cfg.oce.feature_bitmap; + vdev_id = wlan_vdev_get_id(vdev); + wma_debug("Vdev %d Disable FILS discovery", vdev_id); + updated_fw_value &= ~(WMI_VDEV_OCE_FILS_DISCOVERY_FRAME_FEATURE_BITMAP); + if (wma_cli_set_command(vdev_id, + wmi_vdev_param_enable_disable_oce_features, + updated_fw_value, VDEV_CMD)) + mlme_legacy_err("Vdev %d failed to send OCE update", vdev_id); +} + +QDF_STATUS wlan_mlme_set_ap_policy(struct wlan_objmgr_vdev *vdev, + enum host_concurrent_ap_policy ap_cfg_policy) + +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->mlme_ap.ap_policy = ap_cfg_policy; + mlme_debug("Set ap_cfg_policy to :%d", mlme_priv->mlme_ap.ap_policy); + + return QDF_STATUS_SUCCESS; +} + +enum host_concurrent_ap_policy +wlan_mlme_get_ap_policy(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return HOST_CONCURRENT_AP_POLICY_UNSPECIFIED; + } + + mlme_debug("Get ap_cfg_policy to :%d", mlme_priv->mlme_ap.ap_policy); + + return mlme_priv->mlme_ap.ap_policy; +} + +QDF_STATUS wlan_mlme_get_prevent_link_down(struct wlan_objmgr_psoc *psoc, + bool *prevent_link_down) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *prevent_link_down = mlme_obj->cfg.gen.prevent_link_down; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_select_5ghz_margin(struct wlan_objmgr_psoc *psoc, + uint8_t *select_5ghz_margin) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *select_5ghz_margin = mlme_obj->cfg.gen.select_5ghz_margin; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_rtt_mac_randomization(struct wlan_objmgr_psoc *psoc, + bool *rtt_mac_randomization) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *rtt_mac_randomization = mlme_obj->cfg.gen.rtt_mac_randomization; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_crash_inject(struct wlan_objmgr_psoc *psoc, + bool *crash_inject) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *crash_inject = mlme_obj->cfg.gen.crash_inject; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_lpass_support(struct wlan_objmgr_psoc *psoc, + bool *lpass_support) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *lpass_support = mlme_obj->cfg.gen.lpass_support; + + return QDF_STATUS_SUCCESS; +} + +void wlan_mlme_get_wls_6ghz_cap(struct wlan_objmgr_psoc *psoc, + bool *wls_6ghz_capable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *wls_6ghz_capable = cfg_default(CFG_WLS_6GHZ_CAPABLE); + return; + } + *wls_6ghz_capable = mlme_obj->cfg.gen.wls_6ghz_capable; +} + +QDF_STATUS wlan_mlme_get_self_recovery(struct wlan_objmgr_psoc *psoc, + bool *self_recovery) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *self_recovery = mlme_obj->cfg.gen.self_recovery; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sub_20_chan_width(struct wlan_objmgr_psoc *psoc, + uint8_t *sub_20_chan_width) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *sub_20_chan_width = mlme_obj->cfg.gen.sub_20_chan_width; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_fw_timeout_crash(struct wlan_objmgr_psoc *psoc, + bool *fw_timeout_crash) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *fw_timeout_crash = mlme_obj->cfg.gen.fw_timeout_crash; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_ito_repeat_count(struct wlan_objmgr_psoc *psoc, + uint8_t *ito_repeat_count) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *ito_repeat_count = mlme_obj->cfg.gen.ito_repeat_count; + + return QDF_STATUS_SUCCESS; +} + +void wlan_mlme_get_sap_inactivity_override(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + *val = mlme_obj->cfg.qos_mlme_params.sap_max_inactivity_override; +} + +QDF_STATUS wlan_mlme_get_acs_with_more_param(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.acs.is_acs_with_more_param; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_auto_channel_weight(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *value = cfg_default(CFG_AUTO_CHANNEL_SELECT_WEIGHT); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.acs.auto_channel_select_weight; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_vendor_acs_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.acs.is_vendor_acs_support; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_acs_support_for_dfs_ltecoex(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.acs.is_acs_support_for_dfs_ltecoex; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_external_acs_policy(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.acs.is_external_acs_policy; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_tx_chainmask_cck(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.chainmask_cfg.tx_chain_mask_cck; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_tx_chainmask_1ss(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.chainmask_cfg.tx_chain_mask_1ss; + return QDF_STATUS_SUCCESS; +} + +bool +wlan_mlme_is_data_stall_recovery_fw_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("MLME obj is NULL"); + return false; + } + + return mlme_obj->cfg.gen.data_stall_recovery_fw_support; +} + +void +wlan_mlme_update_cfg_with_tgt_caps(struct wlan_objmgr_psoc *psoc, + struct mlme_tgt_caps *tgt_caps) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + /* Update the mlme cfg according to the tgt capability received */ + + mlme_obj->cfg.gen.data_stall_recovery_fw_support = + tgt_caps->data_stall_recovery_fw_support; + + mlme_obj->cfg.gen.bigtk_support = tgt_caps->bigtk_support; + mlme_obj->cfg.gen.stop_all_host_scan_support = + tgt_caps->stop_all_host_scan_support; + mlme_obj->cfg.gen.dual_sta_roam_fw_support = + tgt_caps->dual_sta_roam_fw_support; + mlme_obj->cfg.gen.ocv_support = tgt_caps->ocv_support; +} + +void +wlan_mlme_update_aux_dev_caps( + struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_aux_dev_caps wlan_mlme_aux_dev_caps[]) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + qdf_mem_copy(&mlme_obj->cfg.gen.wlan_mlme_aux0_dev_caps[0], + &wlan_mlme_aux_dev_caps[0], + sizeof(mlme_obj->cfg.gen.wlan_mlme_aux0_dev_caps)); +} + +bool wlan_mlme_cfg_get_aux_supported_modes( + struct wlan_objmgr_psoc *psoc, + uint32_t aux_index, + enum wlan_mlme_hw_mode_config_type hw_mode_id, + uint32_t *supported_modes_bitmap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_aux_dev_caps *wlan_mlme_aux0_dev_caps; + + if (aux_index != 0) { + mlme_err("current only support aux0"); + return false; + } + + if (hw_mode_id >= WLAN_MLME_HW_MODE_MAX) { + mlme_err("invalid hw mode id %d.", hw_mode_id); + return false; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("MLME obj is NULL"); + return false; + } + wlan_mlme_aux0_dev_caps = mlme_obj->cfg.gen.wlan_mlme_aux0_dev_caps; + *supported_modes_bitmap = + wlan_mlme_aux0_dev_caps[hw_mode_id].supported_modes_bitmap; + return true; +} + +/** + * wlan_mlme_is_aux_cap_support() - checking the corresponding capability + * @psoc: wlan_objmgr_psoc pointer + * @bit: the corresponding bit + * @hw_mode_id: hw mode id + * + * Return: true if corresponding capability supporting + */ +static bool +wlan_mlme_is_aux_cap_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_aux_caps_bit bit, + enum wlan_mlme_hw_mode_config_type hw_mode_id) +{ + uint32_t supported_modes_bitmap = 0; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_aux_dev_caps *wlan_mlme_aux0_dev_caps; + int idx; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("MLME obj is NULL"); + return false; + } + + wlan_mlme_aux0_dev_caps = mlme_obj->cfg.gen.wlan_mlme_aux0_dev_caps; + if (hw_mode_id >= WLAN_MLME_HW_MODE_MAX) { + for (idx = 0; idx < WLAN_MLME_HW_MODE_MAX; idx++) + supported_modes_bitmap |= + wlan_mlme_aux0_dev_caps[idx].supported_modes_bitmap; + } else { + supported_modes_bitmap = + wlan_mlme_aux0_dev_caps[hw_mode_id].supported_modes_bitmap; + } + + return (supported_modes_bitmap & (0x1 << bit)) ? true : false; +} + +bool +wlan_mlme_is_aux_scan_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_hw_mode_config_type hw_mode_id) +{ + return wlan_mlme_is_aux_cap_support(psoc, WLAN_MLME_AUX_MODE_SCAN_BIT, + hw_mode_id); +} + +bool +wlan_mlme_is_aux_listen_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_hw_mode_config_type hw_mode_id) +{ + return wlan_mlme_is_aux_cap_support(psoc, WLAN_MLME_AUX_MODE_LISTEN_BIT, + hw_mode_id); +} + +bool +wlan_mlme_is_aux_emlsr_support(struct wlan_objmgr_psoc *psoc, + enum wlan_mlme_hw_mode_config_type hw_mode_id) +{ + return wlan_mlme_is_aux_cap_support(psoc, WLAN_MLME_AUX_MODE_EMLSR_BIT, + hw_mode_id); +} + +#ifdef WLAN_FEATURE_11AX +QDF_STATUS wlan_mlme_cfg_get_he_ul_mumimo(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.he_caps.dot11_he_cap.ul_mu; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_cfg_get_he_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEhe_cap *he_cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *he_cap = mlme_obj->cfg.he_caps.he_cap_orig; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_set_he_ul_mumimo(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (!cfg_in_range(CFG_HE_UL_MUMIMO, value)) { + mlme_legacy_debug("Failed to set CFG_HE_UL_MUMIMO with %d", + value); + return QDF_STATUS_E_FAILURE; + } + + mlme_obj->cfg.he_caps.dot11_he_cap.ul_mu = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_enable_ul_mimo(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.he_caps.enable_ul_mimo; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_enable_ul_ofdm(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + + *value = mlme_obj->cfg.he_caps.enable_ul_ofdm; + + return QDF_STATUS_SUCCESS; +} + +/* mlme_get_min_rate_cap() - get minimum capability for HE-MCS between + * ini value and fw capability. + * + * Rx HE-MCS Map and Tx HE-MCS Map subfields format where 2-bit indicates + * 0 indicates support for HE-MCS 0-7 for n spatial streams + * 1 indicates support for HE-MCS 0-9 for n spatial streams + * 2 indicates support for HE-MCS 0-11 for n spatial streams + * 3 indicates that n spatial streams is not supported for HE PPDUs + * + */ +static uint16_t mlme_get_min_rate_cap(uint16_t val1, uint16_t val2) +{ + uint16_t ret = 0, i; + + for (i = 0; i < 8; i++) { + if (((val1 >> (2 * i)) & 0x3) == 0x3 || + ((val2 >> (2 * i)) & 0x3) == 0x3) { + ret |= 0x3 << (2 * i); + continue; + } + ret |= QDF_MIN((val1 >> (2 * i)) & 0x3, + (val2 >> (2 * i)) & 0x3) << (2 * i); + } + return ret; +} + +QDF_STATUS mlme_update_tgt_he_caps_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_cfg *wma_cfg) +{ + uint8_t chan_width; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tDot11fIEhe_cap *he_cap = &wma_cfg->he_cap; + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + uint8_t value, twt_req, twt_resp; + uint16_t tx_mcs_map = 0; + uint16_t rx_mcs_map = 0; + uint8_t nss; + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.he_caps.dot11_he_cap.present = 1; + mlme_obj->cfg.he_caps.dot11_he_cap.htc_he = he_cap->htc_he; + + twt_req = QDF_MIN(he_cap->twt_request, + mlme_obj->cfg.he_caps.dot11_he_cap.twt_request); + mlme_obj->cfg.he_caps.dot11_he_cap.twt_request = twt_req; + + twt_resp = QDF_MIN(he_cap->twt_responder, + mlme_obj->cfg.he_caps.dot11_he_cap.twt_responder); + mlme_obj->cfg.he_caps.dot11_he_cap.twt_responder = twt_resp; + + value = QDF_MIN(he_cap->fragmentation, + mlme_obj->cfg.he_caps.he_dynamic_fragmentation); + + if (cfg_in_range(CFG_HE_FRAGMENTATION, value)) + mlme_obj->cfg.he_caps.dot11_he_cap.fragmentation = value; + + if (cfg_in_range(CFG_HE_MAX_FRAG_MSDU, + he_cap->max_num_frag_msdu_amsdu_exp)) + mlme_obj->cfg.he_caps.dot11_he_cap.max_num_frag_msdu_amsdu_exp = + he_cap->max_num_frag_msdu_amsdu_exp; + if (cfg_in_range(CFG_HE_MIN_FRAG_SIZE, he_cap->min_frag_size)) + mlme_obj->cfg.he_caps.dot11_he_cap.min_frag_size = + he_cap->min_frag_size; + if (cfg_in_range(CFG_HE_TRIG_PAD, he_cap->trigger_frm_mac_pad)) + mlme_obj->cfg.he_caps.dot11_he_cap.trigger_frm_mac_pad = + QDF_MIN(he_cap->trigger_frm_mac_pad, + mlme_obj->cfg.he_caps.dot11_he_cap.trigger_frm_mac_pad); + if (cfg_in_range(CFG_HE_MTID_AGGR_RX, he_cap->multi_tid_aggr_rx_supp)) + mlme_obj->cfg.he_caps.dot11_he_cap.multi_tid_aggr_rx_supp = + he_cap->multi_tid_aggr_rx_supp; + if (cfg_in_range(CFG_HE_MTID_AGGR_TX, he_cap->multi_tid_aggr_tx_supp)) + mlme_obj->cfg.he_caps.dot11_he_cap.multi_tid_aggr_tx_supp = + he_cap->multi_tid_aggr_tx_supp; + if (cfg_in_range(CFG_HE_LINK_ADAPTATION, he_cap->he_link_adaptation)) + mlme_obj->cfg.he_caps.dot11_he_cap.he_link_adaptation = + he_cap->he_link_adaptation; + mlme_obj->cfg.he_caps.dot11_he_cap.all_ack = he_cap->all_ack; + mlme_obj->cfg.he_caps.dot11_he_cap.trigd_rsp_sched = + he_cap->trigd_rsp_sched; + mlme_obj->cfg.he_caps.dot11_he_cap.a_bsr = he_cap->a_bsr; + + value = QDF_MIN(he_cap->broadcast_twt, + mlme_obj->cfg.he_caps.dot11_he_cap.broadcast_twt); + mlme_obj->cfg.he_caps.dot11_he_cap.broadcast_twt = value; + + /* + * As per 802.11ax spec, Flexible TWT capability can be set + * independent of TWT Requestor/Responder capability. + * But currently we don't have any such usecase and firmware + * does not support it. Hence enabling Flexible TWT only when + * either or both of the TWT Requestor/Responder capability + * is set/enabled. + */ + value = QDF_MIN(he_cap->flex_twt_sched, (twt_req || twt_resp)); + mlme_obj->cfg.he_caps.dot11_he_cap.flex_twt_sched = value; + + mlme_obj->cfg.he_caps.dot11_he_cap.ba_32bit_bitmap = + he_cap->ba_32bit_bitmap; + mlme_obj->cfg.he_caps.dot11_he_cap.mu_cascade = he_cap->mu_cascade; + mlme_obj->cfg.he_caps.dot11_he_cap.ack_enabled_multitid = + he_cap->ack_enabled_multitid; + mlme_obj->cfg.he_caps.dot11_he_cap.omi_a_ctrl = he_cap->omi_a_ctrl; + mlme_obj->cfg.he_caps.dot11_he_cap.ofdma_ra = he_cap->ofdma_ra; + if (cfg_in_range(CFG_HE_MAX_AMPDU_LEN, he_cap->max_ampdu_len_exp_ext)) + mlme_obj->cfg.he_caps.dot11_he_cap.max_ampdu_len_exp_ext = + he_cap->max_ampdu_len_exp_ext; + mlme_obj->cfg.he_caps.dot11_he_cap.amsdu_frag = he_cap->amsdu_frag; + mlme_obj->cfg.he_caps.dot11_he_cap.rx_ctrl_frame = + he_cap->rx_ctrl_frame; + mlme_obj->cfg.he_caps.dot11_he_cap.bsrp_ampdu_aggr = + he_cap->bsrp_ampdu_aggr; + mlme_obj->cfg.he_caps.dot11_he_cap.qtp = he_cap->qtp; + mlme_obj->cfg.he_caps.dot11_he_cap.a_bqr = he_cap->a_bqr; + mlme_obj->cfg.he_caps.dot11_he_cap.spatial_reuse_param_rspder = + he_cap->spatial_reuse_param_rspder; + mlme_obj->cfg.he_caps.dot11_he_cap.ndp_feedback_supp = + he_cap->ndp_feedback_supp; + mlme_obj->cfg.he_caps.dot11_he_cap.ops_supp = he_cap->ops_supp; + mlme_obj->cfg.he_caps.dot11_he_cap.amsdu_in_ampdu = + he_cap->amsdu_in_ampdu; + mlme_obj->cfg.he_caps.dot11_he_cap.he_sub_ch_sel_tx_supp = + he_cap->he_sub_ch_sel_tx_supp; + mlme_obj->cfg.he_caps.dot11_he_cap.ul_2x996_tone_ru_supp = + he_cap->ul_2x996_tone_ru_supp; + mlme_obj->cfg.he_caps.dot11_he_cap.om_ctrl_ul_mu_data_dis_rx = + he_cap->om_ctrl_ul_mu_data_dis_rx; + mlme_obj->cfg.he_caps.dot11_he_cap.he_dynamic_smps = + he_cap->he_dynamic_smps; + mlme_obj->cfg.he_caps.dot11_he_cap.punctured_sounding_supp = + he_cap->punctured_sounding_supp; + mlme_obj->cfg.he_caps.dot11_he_cap.ht_vht_trg_frm_rx_supp = + he_cap->ht_vht_trg_frm_rx_supp; + + chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0, + he_cap->chan_width_1, + he_cap->chan_width_2, + he_cap->chan_width_3, + he_cap->chan_width_4, + he_cap->chan_width_5, + he_cap->chan_width_6); + if (cfg_in_range(CFG_HE_CHAN_WIDTH, chan_width)) { + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_0 = + he_cap->chan_width_0; + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_1 = + he_cap->chan_width_1; + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_2 = + he_cap->chan_width_2; + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_3 = + he_cap->chan_width_3; + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_4 = + he_cap->chan_width_4; + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_5 = + he_cap->chan_width_5; + mlme_obj->cfg.he_caps.dot11_he_cap.chan_width_6 = + he_cap->chan_width_6; + } + if (cfg_in_range(CFG_HE_RX_PREAM_PUNC, he_cap->rx_pream_puncturing)) + mlme_obj->cfg.he_caps.dot11_he_cap.rx_pream_puncturing = + he_cap->rx_pream_puncturing; + mlme_obj->cfg.he_caps.dot11_he_cap.device_class = he_cap->device_class; + mlme_obj->cfg.he_caps.dot11_he_cap.ldpc_coding = he_cap->ldpc_coding; + if (cfg_in_range(CFG_HE_LTF_PPDU, he_cap->he_1x_ltf_800_gi_ppdu)) + mlme_obj->cfg.he_caps.dot11_he_cap.he_1x_ltf_800_gi_ppdu = + he_cap->he_1x_ltf_800_gi_ppdu; + if (cfg_in_range(CFG_HE_MIDAMBLE_RX_MAX_NSTS, + he_cap->midamble_tx_rx_max_nsts)) + mlme_obj->cfg.he_caps.dot11_he_cap.midamble_tx_rx_max_nsts = + he_cap->midamble_tx_rx_max_nsts; + mlme_obj->cfg.he_caps.dot11_he_cap.he_4x_ltf_3200_gi_ndp = + he_cap->he_4x_ltf_3200_gi_ndp; + if (mlme_obj->cfg.vht_caps.vht_cap_info.rx_stbc) { + mlme_obj->cfg.he_caps.dot11_he_cap.rx_stbc_lt_80mhz = + he_cap->rx_stbc_lt_80mhz; + mlme_obj->cfg.he_caps.dot11_he_cap.rx_stbc_gt_80mhz = + he_cap->rx_stbc_gt_80mhz; + } else { + mlme_obj->cfg.he_caps.dot11_he_cap.rx_stbc_lt_80mhz = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.rx_stbc_gt_80mhz = 0; + } + if (mlme_obj->cfg.vht_caps.vht_cap_info.tx_stbc) { + mlme_obj->cfg.he_caps.dot11_he_cap.tb_ppdu_tx_stbc_lt_80mhz = + he_cap->tb_ppdu_tx_stbc_lt_80mhz; + mlme_obj->cfg.he_caps.dot11_he_cap.tb_ppdu_tx_stbc_gt_80mhz = + he_cap->tb_ppdu_tx_stbc_gt_80mhz; + } else { + mlme_obj->cfg.he_caps.dot11_he_cap.tb_ppdu_tx_stbc_lt_80mhz = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.tb_ppdu_tx_stbc_gt_80mhz = 0; + } + + if (cfg_in_range(CFG_HE_DOPPLER, he_cap->doppler)) + mlme_obj->cfg.he_caps.dot11_he_cap.doppler = he_cap->doppler; + if (cfg_in_range(CFG_HE_DCM_TX, he_cap->dcm_enc_tx)) + mlme_obj->cfg.he_caps.dot11_he_cap.dcm_enc_tx = + he_cap->dcm_enc_tx; + if (cfg_in_range(CFG_HE_DCM_RX, he_cap->dcm_enc_rx)) + mlme_obj->cfg.he_caps.dot11_he_cap.dcm_enc_rx = + he_cap->dcm_enc_rx; + mlme_obj->cfg.he_caps.dot11_he_cap.ul_he_mu = he_cap->ul_he_mu; + if (mlme_obj->cfg.vht_caps.vht_cap_info.su_bformer) { + mlme_obj->cfg.he_caps.dot11_he_cap.su_beamformer = + he_cap->su_beamformer; + if (cfg_in_range(CFG_HE_NUM_SOUND_LT80, + he_cap->num_sounding_lt_80)) + mlme_obj->cfg.he_caps.dot11_he_cap.num_sounding_lt_80 = + he_cap->num_sounding_lt_80; + if (cfg_in_range(CFG_HE_NUM_SOUND_GT80, + he_cap->num_sounding_gt_80)) + mlme_obj->cfg.he_caps.dot11_he_cap.num_sounding_gt_80 = + he_cap->num_sounding_gt_80; + mlme_obj->cfg.he_caps.dot11_he_cap.mu_beamformer = + he_cap->mu_beamformer; + + } else { + mlme_obj->cfg.he_caps.dot11_he_cap.su_beamformer = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.num_sounding_lt_80 = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.num_sounding_gt_80 = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.mu_beamformer = 0; + } + + if (mlme_obj->cfg.vht_caps.vht_cap_info.su_bformee) { + mlme_obj->cfg.he_caps.dot11_he_cap.su_beamformee = + he_cap->su_beamformee; + if (cfg_in_range(CFG_HE_BFEE_STS_LT80, he_cap->bfee_sts_lt_80)) + mlme_obj->cfg.he_caps.dot11_he_cap.bfee_sts_lt_80 = + he_cap->bfee_sts_lt_80; + if (cfg_in_range(CFG_HE_BFEE_STS_GT80, he_cap->bfee_sts_gt_80)) + mlme_obj->cfg.he_caps.dot11_he_cap.bfee_sts_gt_80 = + he_cap->bfee_sts_gt_80; + + } else { + mlme_obj->cfg.he_caps.dot11_he_cap.su_beamformee = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.bfee_sts_lt_80 = 0; + mlme_obj->cfg.he_caps.dot11_he_cap.bfee_sts_gt_80 = 0; + } + + if (!mlme_obj->cfg.he_caps.enable_ul_mimo) { + mlme_debug("UL MIMO feature is disabled via ini, fw caps :%d", + he_cap->ul_mu); + mlme_obj->cfg.he_caps.dot11_he_cap.ul_mu = 0; + } else { + mlme_obj->cfg.he_caps.dot11_he_cap.ul_mu = he_cap->ul_mu; + } + + mlme_obj->cfg.he_caps.dot11_he_cap.su_feedback_tone16 = + he_cap->su_feedback_tone16; + mlme_obj->cfg.he_caps.dot11_he_cap.mu_feedback_tone16 = + he_cap->mu_feedback_tone16; + mlme_obj->cfg.he_caps.dot11_he_cap.codebook_su = he_cap->codebook_su; + mlme_obj->cfg.he_caps.dot11_he_cap.codebook_mu = he_cap->codebook_mu; + if (cfg_in_range(CFG_HE_BFRM_FEED, he_cap->beamforming_feedback)) + mlme_obj->cfg.he_caps.dot11_he_cap.beamforming_feedback = + he_cap->beamforming_feedback; + mlme_obj->cfg.he_caps.dot11_he_cap.he_er_su_ppdu = + he_cap->he_er_su_ppdu; + mlme_obj->cfg.he_caps.dot11_he_cap.dl_mu_mimo_part_bw = + he_cap->dl_mu_mimo_part_bw; + mlme_obj->cfg.he_caps.dot11_he_cap.ppet_present = he_cap->ppet_present; + mlme_obj->cfg.he_caps.dot11_he_cap.srp = he_cap->srp; + mlme_obj->cfg.he_caps.dot11_he_cap.power_boost = he_cap->power_boost; + mlme_obj->cfg.he_caps.dot11_he_cap.he_ltf_800_gi_4x = + he_cap->he_ltf_800_gi_4x; + if (cfg_in_range(CFG_HE_MAX_NC, he_cap->max_nc)) + mlme_obj->cfg.he_caps.dot11_he_cap.max_nc = he_cap->max_nc; + mlme_obj->cfg.he_caps.dot11_he_cap.er_he_ltf_800_gi_4x = + he_cap->er_he_ltf_800_gi_4x; + mlme_obj->cfg.he_caps.dot11_he_cap.he_ppdu_20_in_40Mhz_2G = + he_cap->he_ppdu_20_in_40Mhz_2G; + mlme_obj->cfg.he_caps.dot11_he_cap.he_ppdu_20_in_160_80p80Mhz = + he_cap->he_ppdu_20_in_160_80p80Mhz; + mlme_obj->cfg.he_caps.dot11_he_cap.he_ppdu_80_in_160_80p80Mhz = + he_cap->he_ppdu_80_in_160_80p80Mhz; + mlme_obj->cfg.he_caps.dot11_he_cap.er_1x_he_ltf_gi = + he_cap->er_1x_he_ltf_gi; + mlme_obj->cfg.he_caps.dot11_he_cap.midamble_tx_rx_1x_he_ltf = + he_cap->midamble_tx_rx_1x_he_ltf; + if (cfg_in_range(CFG_HE_DCM_MAX_BW, he_cap->dcm_max_bw)) + mlme_obj->cfg.he_caps.dot11_he_cap.dcm_max_bw = + he_cap->dcm_max_bw; + mlme_obj->cfg.he_caps.dot11_he_cap.longer_than_16_he_sigb_ofdm_sym = + he_cap->longer_than_16_he_sigb_ofdm_sym; + mlme_obj->cfg.he_caps.dot11_he_cap.tx_1024_qam_lt_242_tone_ru = + he_cap->tx_1024_qam_lt_242_tone_ru; + mlme_obj->cfg.he_caps.dot11_he_cap.rx_1024_qam_lt_242_tone_ru = + he_cap->rx_1024_qam_lt_242_tone_ru; + mlme_obj->cfg.he_caps.dot11_he_cap.non_trig_cqi_feedback = + he_cap->non_trig_cqi_feedback; + mlme_obj->cfg.he_caps.dot11_he_cap.rx_full_bw_su_he_mu_compress_sigb = + he_cap->rx_full_bw_su_he_mu_compress_sigb; + mlme_obj->cfg.he_caps.dot11_he_cap.rx_full_bw_su_he_mu_non_cmpr_sigb = + he_cap->rx_full_bw_su_he_mu_non_cmpr_sigb; + + tx_mcs_map = mlme_get_min_rate_cap( + mlme_obj->cfg.he_caps.dot11_he_cap.tx_he_mcs_map_lt_80, + he_cap->tx_he_mcs_map_lt_80); + rx_mcs_map = mlme_get_min_rate_cap( + mlme_obj->cfg.he_caps.dot11_he_cap.rx_he_mcs_map_lt_80, + he_cap->rx_he_mcs_map_lt_80); + if (!mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2) { + nss = 2; + tx_mcs_map = HE_SET_MCS_4_NSS(tx_mcs_map, HE_MCS_DISABLE, nss); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, HE_MCS_DISABLE, nss); + } + + if (cfg_in_range(CFG_HE_RX_MCS_MAP_LT_80, rx_mcs_map)) + mlme_obj->cfg.he_caps.dot11_he_cap.rx_he_mcs_map_lt_80 = + rx_mcs_map; + if (cfg_in_range(CFG_HE_TX_MCS_MAP_LT_80, tx_mcs_map)) + mlme_obj->cfg.he_caps.dot11_he_cap.tx_he_mcs_map_lt_80 = + tx_mcs_map; + tx_mcs_map = mlme_get_min_rate_cap( + *((uint16_t *)mlme_obj->cfg.he_caps.dot11_he_cap.tx_he_mcs_map_160), + *((uint16_t *)he_cap->tx_he_mcs_map_160)); + rx_mcs_map = mlme_get_min_rate_cap( + *((uint16_t *)mlme_obj->cfg.he_caps.dot11_he_cap.rx_he_mcs_map_160), + *((uint16_t *)he_cap->rx_he_mcs_map_160)); + + if (!mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2) { + nss = 2; + tx_mcs_map = HE_SET_MCS_4_NSS(tx_mcs_map, HE_MCS_DISABLE, nss); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, HE_MCS_DISABLE, nss); + } + + if (cfg_in_range(CFG_HE_RX_MCS_MAP_160, rx_mcs_map)) + qdf_mem_copy(mlme_obj->cfg.he_caps.dot11_he_cap. + rx_he_mcs_map_160, + &rx_mcs_map, sizeof(uint16_t)); + + if (cfg_in_range(CFG_HE_TX_MCS_MAP_160, tx_mcs_map)) + qdf_mem_copy(mlme_obj->cfg.he_caps.dot11_he_cap. + tx_he_mcs_map_160, + &tx_mcs_map, sizeof(uint16_t)); + + if (cfg_in_range(CFG_HE_RX_MCS_MAP_80_80, + *((uint16_t *)he_cap->rx_he_mcs_map_80_80))) + qdf_mem_copy(mlme_obj->cfg.he_caps.dot11_he_cap. + rx_he_mcs_map_80_80, + he_cap->rx_he_mcs_map_80_80, sizeof(uint16_t)); + + if (cfg_in_range(CFG_HE_TX_MCS_MAP_80_80, + *((uint16_t *)he_cap->tx_he_mcs_map_80_80))) + qdf_mem_copy(mlme_obj->cfg.he_caps.dot11_he_cap. + tx_he_mcs_map_80_80, + he_cap->tx_he_mcs_map_80_80, sizeof(uint16_t)); + + qdf_mem_copy(mlme_obj->cfg.he_caps.he_ppet_2g, wma_cfg->ppet_2g, + HE_MAX_PPET_SIZE); + + qdf_mem_copy(mlme_obj->cfg.he_caps.he_ppet_5g, wma_cfg->ppet_5g, + HE_MAX_PPET_SIZE); + + mlme_obj->cfg.he_caps.he_cap_orig = mlme_obj->cfg.he_caps.dot11_he_cap; + /* Take intersection of host and FW capabilities */ + mlme_obj->cfg.he_caps.he_mcs_12_13_supp_2g &= + wma_cfg->he_mcs_12_13_supp_2g; + mlme_obj->cfg.he_caps.he_mcs_12_13_supp_5g &= + wma_cfg->he_mcs_12_13_supp_5g; + mlme_debug("mcs_12_13 2G: %x 5G: %x FW_cap: 2G: %x 5G: %x", + mlme_obj->cfg.he_caps.he_mcs_12_13_supp_2g, + mlme_obj->cfg.he_caps.he_mcs_12_13_supp_5g, + wma_cfg->he_mcs_12_13_supp_2g, + wma_cfg->he_mcs_12_13_supp_5g); + + return status; +} +#ifdef WLAN_FEATURE_SR +void +wlan_mlme_get_sr_enable_modes(struct wlan_objmgr_psoc *psoc, uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *val = cfg_default(CFG_SR_ENABLE_MODES); + return; + } + *val = mlme_obj->cfg.gen.sr_enable_modes; +} +#endif +#endif + +#ifdef WLAN_FEATURE_11BE +QDF_STATUS mlme_update_tgt_eht_caps_in_cfg(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_cfg *wma_cfg) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + tDot11fIEeht_cap *eht_cap = &wma_cfg->eht_cap; + tDot11fIEeht_cap *mlme_eht_cap; + bool eht_capab; + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); + if (!eht_capab) + return QDF_STATUS_SUCCESS; + + mlme_obj->cfg.eht_caps.dot11_eht_cap.present = 1; + qdf_mem_copy(&mlme_obj->cfg.eht_caps.dot11_eht_cap, eht_cap, + sizeof(tDot11fIEeht_cap)); + mlme_eht_cap = &mlme_obj->cfg.eht_caps.dot11_eht_cap; + if (mlme_obj->cfg.vht_caps.vht_cap_info.su_bformer) { + mlme_eht_cap->su_beamformer = eht_cap->su_beamformer; + if (cfg_in_range(CFG_EHT_NUM_SOUNDING_DIM_LE_80MHZ, + eht_cap->num_sounding_dim_le_80mhz)) + mlme_eht_cap->num_sounding_dim_le_80mhz = + eht_cap->num_sounding_dim_le_80mhz; + if (cfg_in_range(CFG_EHT_NUM_SOUNDING_DIM_160MHZ, + eht_cap->num_sounding_dim_160mhz)) + mlme_eht_cap->num_sounding_dim_160mhz = + eht_cap->num_sounding_dim_160mhz; + if (cfg_in_range(CFG_EHT_NUM_SOUNDING_DIM_320MHZ, + eht_cap->num_sounding_dim_320mhz)) + mlme_eht_cap->num_sounding_dim_320mhz = + eht_cap->num_sounding_dim_320mhz; + mlme_eht_cap->mu_bformer_le_80mhz = + eht_cap->mu_bformer_le_80mhz; + mlme_eht_cap->mu_bformer_160mhz = eht_cap->mu_bformer_160mhz; + mlme_eht_cap->mu_bformer_320mhz = eht_cap->mu_bformer_320mhz; + + } else { + mlme_eht_cap->su_beamformer = 0; + mlme_eht_cap->num_sounding_dim_le_80mhz = 0; + mlme_eht_cap->num_sounding_dim_160mhz = 0; + mlme_eht_cap->num_sounding_dim_320mhz = 0; + mlme_eht_cap->mu_bformer_le_80mhz = 0; + mlme_eht_cap->mu_bformer_160mhz = 0; + mlme_eht_cap->mu_bformer_320mhz = 0; + } + + if (mlme_obj->cfg.vht_caps.vht_cap_info.su_bformee) { + mlme_eht_cap->su_beamformee = eht_cap->su_beamformee; + if (cfg_in_range(CFG_EHT_BFEE_SS_LE_80MHZ, + eht_cap->bfee_ss_le_80mhz)) + mlme_eht_cap->bfee_ss_le_80mhz = + eht_cap->bfee_ss_le_80mhz; + if (cfg_in_range(CFG_EHT_BFEE_SS_160MHZ, + eht_cap->bfee_ss_160mhz)) + mlme_eht_cap->bfee_ss_160mhz = eht_cap->bfee_ss_160mhz; + if (cfg_in_range(CFG_EHT_BFEE_SS_320MHZ, + eht_cap->bfee_ss_320mhz)) + mlme_eht_cap->bfee_ss_320mhz = eht_cap->bfee_ss_320mhz; + + } else { + mlme_eht_cap->su_beamformee = 0; + mlme_eht_cap->bfee_ss_le_80mhz = 0; + mlme_eht_cap->bfee_ss_160mhz = 0; + mlme_eht_cap->bfee_ss_320mhz = 0; + } + mlme_obj->cfg.eht_caps.eht_cap_orig = + mlme_obj->cfg.eht_caps.dot11_eht_cap; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_update_tgt_mlo_caps_in_cfg(struct wlan_objmgr_psoc *psoc) +{ + struct target_psoc_info *tgt_hdl; + QDF_STATUS status; + uint16_t value; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); + if (!tgt_hdl) { + mlme_debug("target psoc info is NULL"); + return QDF_STATUS_E_FAILURE; + } + + value = target_if_res_cfg_get_num_max_mlo_link(tgt_hdl); + status = wlan_mlme_set_sta_mlo_conn_max_num(psoc, value); + mlme_debug("Max ML link supported: %d", value); + + return status; +} + +uint8_t wlan_mlme_convert_phy_ch_width_to_eht_op_bw(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_320MHZ: + return WLAN_EHT_CHWIDTH_320; + case CH_WIDTH_160MHZ: + return WLAN_EHT_CHWIDTH_160; + case CH_WIDTH_80MHZ: + return WLAN_EHT_CHWIDTH_80; + case CH_WIDTH_40MHZ: + return WLAN_EHT_CHWIDTH_40; + default: + return WLAN_EHT_CHWIDTH_20; + } +} + +enum phy_ch_width wlan_mlme_convert_eht_op_bw_to_phy_ch_width( + uint8_t channel_width) +{ + enum phy_ch_width phy_bw = CH_WIDTH_20MHZ; + + if (channel_width == WLAN_EHT_CHWIDTH_320) + phy_bw = CH_WIDTH_320MHZ; + else if (channel_width == WLAN_EHT_CHWIDTH_160) + phy_bw = CH_WIDTH_160MHZ; + else if (channel_width == WLAN_EHT_CHWIDTH_80) + phy_bw = CH_WIDTH_80MHZ; + else if (channel_width == WLAN_EHT_CHWIDTH_40) + phy_bw = CH_WIDTH_40MHZ; + + return phy_bw; +} + +bool wlan_mlme_get_epcs_capability(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return true; + + return mlme_obj->cfg.sta.epcs_capability; +} + +void wlan_mlme_set_epcs_capability(struct wlan_objmgr_psoc *psoc, bool flag) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mlme_obj || !mac_ctx) + return; + + mlme_debug("set mlme epcs capability from %d to %d", + mlme_obj->cfg.sta.epcs_capability, flag); + mlme_obj->cfg.sta.epcs_capability = flag; + if (flag) { + mlme_obj->cfg.eht_caps.dot11_eht_cap.epcs_pri_access = 1; + mac_ctx->eht_cap_2g.epcs_pri_access = 1; + mac_ctx->eht_cap_5g.epcs_pri_access = 1; + } else { + mlme_obj->cfg.eht_caps.dot11_eht_cap.epcs_pri_access = 0; + mac_ctx->eht_cap_2g.epcs_pri_access = 0; + mac_ctx->eht_cap_5g.epcs_pri_access = 0; + } +} + +bool wlan_mlme_get_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return false; + + return mlme_obj->cfg.sta.eht_disable_punct_in_us_lpi; +} + +void wlan_mlme_set_eht_disable_punct_in_us_lpi(struct wlan_objmgr_psoc *psoc, bool flag) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return; + + mlme_debug("set mlme epcs capability to %d", flag); + mlme_obj->cfg.sta.eht_disable_punct_in_us_lpi = flag; +} + +bool wlan_mlme_get_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return true; + + return mlme_obj->cfg.sta.usr_disable_eht; +} + +void wlan_mlme_set_usr_disable_sta_eht(struct wlan_objmgr_psoc *psoc, + bool disable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return; + + mlme_debug("set usr_disable_eht from %d to %d", + mlme_obj->cfg.sta.usr_disable_eht, disable); + mlme_obj->cfg.sta.usr_disable_eht = disable; +} + +enum phy_ch_width wlan_mlme_get_max_bw(void) +{ + uint32_t max_bw = wma_get_eht_ch_width(); + + if (max_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) + return CH_WIDTH_320MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + return CH_WIDTH_80P80MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + return CH_WIDTH_80MHZ; + else + return CH_WIDTH_40MHZ; +} +#else +enum phy_ch_width wlan_mlme_get_max_bw(void) +{ + uint32_t max_bw = wma_get_vht_ch_width(); + + if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + return CH_WIDTH_80P80MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + return CH_WIDTH_80MHZ; + else + return CH_WIDTH_40MHZ; +} +#endif + +QDF_STATUS wlan_mlme_get_sta_ch_width(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width *ch_width) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_objmgr_peer *peer; + enum wlan_phymode phymode; + enum QDF_OPMODE op_mode; + + peer = wlan_vdev_get_bsspeer(vdev); + op_mode = wlan_vdev_mlme_get_opmode(vdev); + + if (ch_width && peer && + (op_mode == QDF_STA_MODE || + op_mode == QDF_P2P_CLIENT_MODE)) { + wlan_peer_obj_lock(peer); + phymode = wlan_peer_get_phymode(peer); + wlan_peer_obj_unlock(peer); + *ch_width = wlan_mlme_get_ch_width_from_phymode(phymode); + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +void +wlan_mlme_set_bt_profile_con(struct wlan_objmgr_psoc *psoc, + bool bt_profile_con) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.gen.bt_profile_con = bt_profile_con; +} + +bool +wlan_mlme_get_bt_profile_con(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.gen.bt_profile_con; +} + +#ifdef WLAN_FEATURE_11BE_MLO +uint8_t wlan_mlme_get_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + return mlme_obj->cfg.sta.mlo_max_simultaneous_links; +} + +QDF_STATUS +wlan_mlme_set_sta_mlo_simultaneous_links(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.sta.mlo_max_simultaneous_links = value; + mlme_legacy_debug("mlo_max_simultaneous_links %d", value); + + return QDF_STATUS_SUCCESS; +} + +uint8_t wlan_mlme_get_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + return mlme_obj->cfg.sta.mlo_support_link_num; +} + +QDF_STATUS wlan_mlme_set_sta_mlo_conn_max_num(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct target_psoc_info *tgt_hdl; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); + if (!tgt_hdl) { + mlme_err("target psoc info is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!value) + mlme_obj->cfg.sta.mlo_support_link_num = + target_if_res_cfg_get_num_max_mlo_link(tgt_hdl); + else + mlme_obj->cfg.sta.mlo_support_link_num = value; + + mlme_legacy_debug("mlo_support_link_num user input %d intersected value :%d", + value, mlme_obj->cfg.sta.mlo_support_link_num); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_user_set_link_num(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.sta.user_set_link_num = value; + mlme_legacy_debug("user_set_link_num %d", value); + + return QDF_STATUS_SUCCESS; +} + +void wlan_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) + return; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + mlme_legacy_debug("not mlo vdev"); + goto release_ref; + } + + if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx) { + mlme_legacy_debug("mlo dev/sta ctx is null"); + goto release_ref; + } + + vdev->mlo_dev_ctx->sta_ctx->ml_link_control_mode = value; + mlme_legacy_debug("set ml_link_control_mode %d", value); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return; +} + +uint8_t wlan_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev; + uint8_t value = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) + return 0; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + mlme_legacy_debug("not mlo vdev"); + goto release_ref; + } + + if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx) { + mlme_legacy_debug("mlo dev/sta ctx is null"); + goto release_ref; + } + + value = vdev->mlo_dev_ctx->sta_ctx->ml_link_control_mode; + mlme_legacy_debug("get ml_link_control_mode %d", value); +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return value; +} + +void wlan_mlme_restore_user_set_link_num(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + if (!mlme_obj->cfg.sta.user_set_link_num) + return; + + mlme_obj->cfg.sta.mlo_support_link_num = + mlme_obj->cfg.sta.user_set_link_num; + mlme_legacy_debug("restore mlo_support_link_num %d", + mlme_obj->cfg.sta.user_set_link_num); +} + +void wlan_mlme_clear_user_set_link_num(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.sta.user_set_link_num = 0; +} + +uint8_t wlan_mlme_get_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + return mlme_obj->cfg.sta.mlo_support_link_band; +} + +QDF_STATUS wlan_mlme_set_sta_mlo_conn_band_bmp(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.sta.mlo_support_link_band = value; + mlme_legacy_debug("mlo_support_link_conn band %d", value); + + return QDF_STATUS_SUCCESS; +} + +bool wlan_mlme_is_5gl_5gh_mlsr_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + return mlme_obj->cfg.sta.mlo_5gl_5gh_mlsr; +} + +void +wlan_mlme_get_mlo_prefer_percentage(struct wlan_objmgr_psoc *psoc, + int8_t *mlo_prefer_percentage) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("invalid mlo object"); + return; + } + + *mlo_prefer_percentage = mlme_obj->cfg.sta.mlo_prefer_percentage; + mlme_legacy_debug("mlo_prefer_percentage %d", *mlo_prefer_percentage); +} + +bool wlan_mlme_get_sta_same_link_mld_addr(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.sta.mlo_same_link_mld_address; +} +#endif + +QDF_STATUS wlan_mlme_get_num_11b_tx_chains(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.chainmask_cfg.num_11b_tx_chains; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_bt_chain_separation_flag(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.chainmask_cfg.enable_bt_chain_separation; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_num_11ag_tx_chains(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.chainmask_cfg.num_11ag_tx_chains; + return QDF_STATUS_SUCCESS; +} + + +static +bool wlan_mlme_configure_chain_mask_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wma_caps_per_phy non_dbs_phy_cap = {0}; + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + QDF_STATUS status; + bool as_enabled, enable_bt_chain_sep, enable2x2; + uint8_t dual_mac_feature; + bool hw_dbs_2x2_cap; + + if (!mlme_obj) + return false; + + status = wma_get_caps_for_phyidx_hwmode(&non_dbs_phy_cap, + HW_MODE_DBS_NONE, + CDS_BAND_ALL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_legacy_err("couldn't get phy caps. skip chain mask programming"); + return false; + } + + if (non_dbs_phy_cap.tx_chain_mask_2G < 3 || + non_dbs_phy_cap.rx_chain_mask_2G < 3 || + non_dbs_phy_cap.tx_chain_mask_5G < 3 || + non_dbs_phy_cap.rx_chain_mask_5G < 3) { + mlme_legacy_debug("firmware not capable. skip chain mask programming"); + return false; + } + + enable_bt_chain_sep = + mlme_obj->cfg.chainmask_cfg.enable_bt_chain_separation; + as_enabled = mlme_obj->cfg.gen.as_enabled; + ucfg_policy_mgr_get_dual_mac_feature(psoc, &dual_mac_feature); + + hw_dbs_2x2_cap = policy_mgr_is_hw_dbs_2x2_capable(psoc); + enable2x2 = mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2; + + if ((enable2x2 && !enable_bt_chain_sep) || as_enabled || + (!hw_dbs_2x2_cap && (dual_mac_feature != DISABLE_DBS_CXN_AND_SCAN) && + enable2x2)) { + mlme_legacy_debug("Cannot configure chainmask enable_bt_chain_sep %d as_enabled %d enable2x2 %d hw_dbs_2x2_cap %d dual_mac_feature %d", + enable_bt_chain_sep, as_enabled, enable2x2, + hw_dbs_2x2_cap, dual_mac_feature); + return false; + } + + return true; +} + +bool wlan_mlme_is_chain_mask_supported(struct wlan_objmgr_psoc *psoc) + +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return false; + + if (!wlan_mlme_configure_chain_mask_supported(psoc)) + return false; + + /* If user has configured 1x1 from INI */ + if (mlme_obj->cfg.chainmask_cfg.txchainmask1x1 != 3 || + mlme_obj->cfg.chainmask_cfg.rxchainmask1x1 != 3) { + mlme_legacy_debug("txchainmask1x1 %d rxchainmask1x1 %d", + mlme_obj->cfg.chainmask_cfg.txchainmask1x1, + mlme_obj->cfg.chainmask_cfg.rxchainmask1x1); + return false; + } + + return true; + +} + +#define MAX_PDEV_CHAIN_MASK_PARAMS 6 +/* params being sent: + * wmi_pdev_param_tx_chain_mask + * wmi_pdev_param_rx_chain_mask + * wmi_pdev_param_tx_chain_mask_2g + * wmi_pdev_param_rx_chain_mask_2g + * wmi_pdev_param_tx_chain_mask_5g + * wmi_pdev_param_rx_chain_mask_5g + */ +QDF_STATUS wlan_mlme_configure_chain_mask(struct wlan_objmgr_psoc *psoc, + uint8_t session_id) +{ + QDF_STATUS ret_val = QDF_STATUS_E_FAILURE; + uint8_t ch_msk_val; + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + bool mrc_disabled_2g_rx, mrc_disabled_2g_tx; + bool mrc_disabled_5g_rx, mrc_disabled_5g_tx; + struct dev_set_param setparam[MAX_PDEV_CHAIN_MASK_PARAMS]; + uint8_t index = 0; + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_legacy_debug("txchainmask1x1: %d rxchainmask1x1: %d", + mlme_obj->cfg.chainmask_cfg.txchainmask1x1, + mlme_obj->cfg.chainmask_cfg.rxchainmask1x1); + mlme_legacy_debug("tx_chain_mask_2g: %d, rx_chain_mask_2g: %d", + mlme_obj->cfg.chainmask_cfg.tx_chain_mask_2g, + mlme_obj->cfg.chainmask_cfg.rx_chain_mask_2g); + mlme_legacy_debug("tx_chain_mask_5g: %d, rx_chain_mask_5g: %d", + mlme_obj->cfg.chainmask_cfg.tx_chain_mask_5g, + mlme_obj->cfg.chainmask_cfg.rx_chain_mask_5g); + + mrc_disabled_2g_rx = + mlme_obj->cfg.nss_chains_ini_cfg.disable_rx_mrc[NSS_CHAINS_BAND_2GHZ]; + mrc_disabled_2g_tx = + mlme_obj->cfg.nss_chains_ini_cfg.disable_tx_mrc[NSS_CHAINS_BAND_2GHZ]; + mrc_disabled_5g_rx = + mlme_obj->cfg.nss_chains_ini_cfg.disable_rx_mrc[NSS_CHAINS_BAND_5GHZ]; + mrc_disabled_5g_tx = + mlme_obj->cfg.nss_chains_ini_cfg.disable_tx_mrc[NSS_CHAINS_BAND_5GHZ]; + + mlme_legacy_debug("MRC values TX:- 2g %d 5g %d RX:- 2g %d 5g %d", + mrc_disabled_2g_tx, mrc_disabled_5g_tx, + mrc_disabled_2g_rx, mrc_disabled_5g_rx); + + if (!wlan_mlme_configure_chain_mask_supported(psoc)) + return QDF_STATUS_E_FAILURE; + + if (mlme_obj->cfg.chainmask_cfg.txchainmask1x1) { + ch_msk_val = mlme_obj->cfg.chainmask_cfg.txchainmask1x1; + if (wma_validate_txrx_chain_mask(wmi_pdev_param_tx_chain_mask, + ch_msk_val)) { + goto error; + } + ret_val = mlme_check_index_setparam( + setparam, + wmi_pdev_param_tx_chain_mask, + ch_msk_val, index++, + MAX_PDEV_CHAIN_MASK_PARAMS); + if (QDF_IS_STATUS_ERROR(ret_val)) { + mlme_err("failed at wmi_pdev_param_tx_chain_mask"); + goto error; + } + } + + if (mlme_obj->cfg.chainmask_cfg.rxchainmask1x1) { + ch_msk_val = mlme_obj->cfg.chainmask_cfg.rxchainmask1x1; + if (wma_validate_txrx_chain_mask(wmi_pdev_param_rx_chain_mask, + ch_msk_val)) { + goto error; + } + ret_val = mlme_check_index_setparam( + setparam, + wmi_pdev_param_rx_chain_mask, + ch_msk_val, index++, + MAX_PDEV_CHAIN_MASK_PARAMS); + if (QDF_IS_STATUS_ERROR(ret_val)) { + mlme_err("failed at wmi_pdev_param_rx_chain_mask"); + goto error; + } + } + + if (mlme_obj->cfg.chainmask_cfg.txchainmask1x1 || + mlme_obj->cfg.chainmask_cfg.rxchainmask1x1) { + mlme_legacy_debug("band agnostic tx/rx chain mask set. skip per band chain mask"); + goto sendparam; + } + + if (mlme_obj->cfg.chainmask_cfg.tx_chain_mask_2g && + mrc_disabled_2g_tx) { + ch_msk_val = mlme_obj->cfg.chainmask_cfg.tx_chain_mask_2g; + ret_val = mlme_check_index_setparam( + setparam, + wmi_pdev_param_tx_chain_mask_2g, + ch_msk_val, index++, + MAX_PDEV_CHAIN_MASK_PARAMS); + if (QDF_IS_STATUS_ERROR(ret_val)) { + mlme_err("failed at wmi_pdev_param_tx_chain_mask_2g"); + goto error; + } + } + + if (mlme_obj->cfg.chainmask_cfg.rx_chain_mask_2g && + mrc_disabled_2g_rx) { + ch_msk_val = mlme_obj->cfg.chainmask_cfg.rx_chain_mask_2g; + ret_val = mlme_check_index_setparam( + setparam, + wmi_pdev_param_rx_chain_mask_2g, + ch_msk_val, index++, + MAX_PDEV_CHAIN_MASK_PARAMS); + if (QDF_IS_STATUS_ERROR(ret_val)) { + mlme_err("failed at wmi_pdev_param_rx_chain_mask_2g"); + goto error; + } + } + + if (mlme_obj->cfg.chainmask_cfg.tx_chain_mask_5g && + mrc_disabled_5g_tx) { + ch_msk_val = mlme_obj->cfg.chainmask_cfg.tx_chain_mask_5g; + ret_val = mlme_check_index_setparam( + setparam, + wmi_pdev_param_tx_chain_mask_5g, + ch_msk_val, index++, + MAX_PDEV_CHAIN_MASK_PARAMS); + if (QDF_IS_STATUS_ERROR(ret_val)) { + mlme_err("failed at wmi_pdev_param_tx_chain_mask_5g"); + goto error; + } + } + + if (mlme_obj->cfg.chainmask_cfg.rx_chain_mask_5g && + mrc_disabled_5g_rx) { + ch_msk_val = mlme_obj->cfg.chainmask_cfg.rx_chain_mask_5g; + ret_val = mlme_check_index_setparam( + setparam, + wmi_pdev_param_rx_chain_mask_5g, + ch_msk_val, index++, + MAX_PDEV_CHAIN_MASK_PARAMS); + if (QDF_IS_STATUS_ERROR(ret_val)) { + mlme_err("failed at wmi_pdev_param_rx_chain_mask_5g"); + goto error; + } + } +sendparam: + ret_val = wma_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(ret_val)) + mlme_err("failed to send chainmask params"); +error: + return ret_val; +} + +QDF_STATUS +wlan_mlme_get_manufacturer_name(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *plen = qdf_str_lcopy(pbuf, + mlme_obj->cfg.product_details.manufacturer_name, + *plen); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_model_number(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *plen = qdf_str_lcopy(pbuf, + mlme_obj->cfg.product_details.model_number, + *plen); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_model_name(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *plen = qdf_str_lcopy(pbuf, + mlme_obj->cfg.product_details.model_name, + *plen); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_manufacture_product_version(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *plen = qdf_str_lcopy(pbuf, + mlme_obj->cfg.product_details.manufacture_product_version, + *plen); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_manufacture_product_name(struct wlan_objmgr_psoc *psoc, + uint8_t *pbuf, uint32_t *plen) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *plen = qdf_str_lcopy(pbuf, + mlme_obj->cfg.product_details.manufacture_product_name, + *plen); + return QDF_STATUS_SUCCESS; +} + + +void wlan_mlme_get_tl_delayed_trgr_frm_int(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_TL_DELAYED_TRGR_FRM_INTERVAL); + return; + } + + *value = mlme_obj->cfg.wmm_params.delayed_trigger_frm_int; +} + + +QDF_STATUS wlan_mlme_get_wmm_dir_ac_vo(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vo.dir_ac_vo; + + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_vo(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vo.nom_msdu_size_ac_vo; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_mean_data_rate_ac_vo(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vo.mean_data_rate_ac_vo; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_vo(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vo.min_phy_rate_ac_vo; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_vo(struct wlan_objmgr_psoc *psoc, uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.wmm_params.ac_vo.sba_ac_vo; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_uapsd_vo_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vo.uapsd_vo_srv_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_uapsd_vo_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vo.uapsd_vo_sus_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_vht_ampdu_len_exp(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.ampdu_len_exponent; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_vht_max_mpdu_len(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.ampdu_len; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_ht_smps(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.ht_caps.smps; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_vi(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vi.dir_ac_vi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_vi(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = + mlme_obj->cfg.wmm_params.ac_vi.nom_msdu_size_ac_vi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_mean_data_rate_ac_vi(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vi.mean_data_rate_ac_vi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_vi(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vi.min_phy_rate_ac_vi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_sba_ac_vi(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vi.sba_ac_vi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_uapsd_vi_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vi.uapsd_vi_srv_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_uapsd_vi_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_vi.uapsd_vi_sus_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_be(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.dir_ac_be; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_be(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.nom_msdu_size_ac_be; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_mean_data_rate_ac_be(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.mean_data_rate_ac_be; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_be(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.min_phy_rate_ac_be; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_be(struct wlan_objmgr_psoc *psoc, uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.sba_ac_be; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_uapsd_be_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.uapsd_be_srv_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_uapsd_be_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_be.uapsd_be_sus_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_dir_ac_bk(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.dir_ac_bk; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_nom_msdu_size_ac_bk(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.nom_msdu_size_ac_bk; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_mean_data_rate_ac_bk(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.mean_data_rate_ac_bk; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_wmm_min_phy_rate_ac_bk(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.min_phy_rate_ac_bk; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_sba_ac_bk(struct wlan_objmgr_psoc *psoc, uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.sba_ac_bk; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_uapsd_bk_srv_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.uapsd_bk_srv_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_uapsd_bk_sus_intv(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.ac_bk.uapsd_bk_sus_intv; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_mode(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.wmm_config.wmm_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_80211e_is_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.wmm_config.b80211e_is_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_wmm_uapsd_mask(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.wmm_config.uapsd_mask; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +void wlan_mlme_get_inactivity_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_QOS_WMM_INACTIVITY_INTERVAL); + return; + } + + *value = mlme_obj->cfg.wmm_params.wmm_tspec_element.inactivity_intv; +} +#endif + +void wlan_mlme_get_is_ts_burst_size_enable(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_QOS_WMM_BURST_SIZE_DEFN); + return; + } + + *value = mlme_obj->cfg.wmm_params.wmm_tspec_element.burst_size_def; +} + +void wlan_mlme_get_ts_info_ack_policy(struct wlan_objmgr_psoc *psoc, + enum mlme_ts_info_ack_policy *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_QOS_WMM_TS_INFO_ACK_POLICY); + return; + } + + *value = mlme_obj->cfg.wmm_params.wmm_tspec_element.ts_ack_policy; + +} + +QDF_STATUS +wlan_mlme_get_ts_acm_value_for_ac(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.wmm_params.wmm_tspec_element.ts_acm_is_off; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_listen_interval(struct wlan_objmgr_psoc *psoc, + int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.listen_interval; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_sap_listen_interval(struct wlan_objmgr_psoc *psoc, + int value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (cfg_in_range(CFG_LISTEN_INTERVAL, value)) + mlme_obj->cfg.sap_cfg.listen_interval = value; + else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_assoc_sta_limit(struct wlan_objmgr_psoc *psoc, + int value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (cfg_in_range(CFG_ASSOC_STA_LIMIT, value) && + (value <= mlme_obj->cfg.sap_cfg.sap_max_no_peers)) + mlme_obj->cfg.sap_cfg.assoc_sta_limit = value; + else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_assoc_sta_limit(struct wlan_objmgr_psoc *psoc, + int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.assoc_sta_limit; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_get_peer_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_get_peer_info; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_sap_get_peer_info(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.sap_cfg.sap_get_peer_info = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_sap_bcast_deauth_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.is_sap_bcast_deauth_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_is_6g_sap_fd_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.is_6g_sap_fd_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_allow_all_channels(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_allow_all_chan_param_name; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_max_peers(struct wlan_objmgr_psoc *psoc, + int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_max_no_peers; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_sap_max_peers(struct wlan_objmgr_psoc *psoc, + int value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (cfg_in_range(CFG_SAP_MAX_NO_PEERS, value)) + mlme_obj->cfg.sap_cfg.sap_max_no_peers = value; + else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_max_offload_peers(struct wlan_objmgr_psoc *psoc, + int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_max_offload_peers; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_max_offload_reorder_buffs(struct wlan_objmgr_psoc + *psoc, int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_max_offload_reorder_buffs; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_chn_switch_bcn_count(struct wlan_objmgr_psoc *psoc, + int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_ch_switch_beacon_cnt; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_chn_switch_mode(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_ch_switch_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_internal_restart(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_internal_restart; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_max_modulated_dtim(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.max_li_modulated_dtim_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_chan_pref_location(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_pref_chan_location; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_country_priority(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.country_code_priority; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_reduced_beacon_interval(struct wlan_objmgr_psoc + *psoc, int *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_REDUCED_BEACON_INTERVAL); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.sap_cfg.reduced_beacon_interval; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_chan_switch_rate_enabled(struct wlan_objmgr_psoc + *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.chan_switch_hostapd_rate_enabled_name; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_sap_force_11n_for_11ac(struct wlan_objmgr_psoc + *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_force_11n_for_11ac; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_go_force_11n_for_11ac(struct wlan_objmgr_psoc + *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.go_force_11n_for_11ac; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_is_sap_11ac_override(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_SAP_11AC_OVERRIDE); + return QDF_STATUS_E_FAILURE; + } + *value = mlme_obj->cfg.sap_cfg.sap_11ac_override; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_is_go_11ac_override(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_GO_11AC_OVERRIDE); + return QDF_STATUS_E_FAILURE; + } + *value = mlme_obj->cfg.sap_cfg.go_11ac_override; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_sap_11ac_override(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + mlme_obj->cfg.sap_cfg.sap_11ac_override = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_go_11ac_override(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + mlme_obj->cfg.sap_cfg.go_11ac_override = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_bigtk_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.bigtk_support; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_ocv_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.ocv_support; + + return QDF_STATUS_SUCCESS; +} + +bool wlan_mlme_get_host_scan_abort_support(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return false; + + return mlme_obj->cfg.gen.stop_all_host_scan_support; +} + +bool wlan_mlme_get_dual_sta_roam_support(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return false; + + return mlme_obj->cfg.gen.dual_sta_roam_fw_support; +} + +QDF_STATUS wlan_mlme_get_oce_sta_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.oce.oce_sta_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_oce_sap_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.oce.oce_sap_enabled; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_mlme_send_oce_flags_fw() - Send the oce flags to FW + * @pdev: pointer to pdev object + * @object: vdev object + * @arg: Arguments to the handler + * + * Return: void + */ +static void wlan_mlme_send_oce_flags_fw(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = object; + uint8_t *updated_fw_value = arg; + uint8_t *dynamic_fw_value = 0; + uint8_t vdev_id; + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) { + dynamic_fw_value = mlme_get_dynamic_oce_flags(vdev); + if (!dynamic_fw_value) + return; + if (*updated_fw_value == *dynamic_fw_value) { + mlme_legacy_debug("Current FW flags matches with updated value."); + return; + } + *dynamic_fw_value = *updated_fw_value; + vdev_id = wlan_vdev_get_id(vdev); + if (wma_cli_set_command(vdev_id, + wmi_vdev_param_enable_disable_oce_features, + *updated_fw_value, VDEV_CMD)) + mlme_legacy_err("Failed to send OCE update to FW"); + } +} + +void wlan_mlme_update_oce_flags(struct wlan_objmgr_pdev *pdev) +{ + uint16_t sap_connected_peer, go_connected_peer; + struct wlan_objmgr_psoc *psoc = NULL; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint8_t updated_fw_value = 0; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + sap_connected_peer = + wlan_util_get_peer_count_for_mode(pdev, QDF_SAP_MODE); + go_connected_peer = + wlan_util_get_peer_count_for_mode(pdev, QDF_P2P_GO_MODE); + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return; + + if (sap_connected_peer || go_connected_peer) { + updated_fw_value = mlme_obj->cfg.oce.feature_bitmap; + updated_fw_value &= + ~(WMI_VDEV_OCE_PROBE_REQUEST_RATE_FEATURE_BITMAP); + updated_fw_value &= + ~(WMI_VDEV_OCE_PROBE_REQUEST_DEFERRAL_FEATURE_BITMAP); + mlme_legacy_debug("Disable STA OCE probe req rate and defferal updated_fw_value :%d", + updated_fw_value); + } else { + updated_fw_value = mlme_obj->cfg.oce.feature_bitmap; + mlme_legacy_debug("Update the STA OCE flags to default INI updated_fw_value :%d", + updated_fw_value); + } + + wlan_objmgr_pdev_iterate_obj_list(pdev, WLAN_VDEV_OP, + wlan_mlme_send_oce_flags_fw, + &updated_fw_value, 0, WLAN_MLME_NB_ID); +} + +bool wlan_mlme_is_ap_prot_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.sap_protection_cfg.is_ap_prot_enabled; +} + +QDF_STATUS wlan_mlme_get_ap_protection_mode(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_protection_cfg.ap_protection_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_is_ap_obss_prot_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_protection_cfg.enable_ap_obss_protection; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_rts_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.threshold.rts_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_rts_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.threshold.rts_threshold = value; + wma_update_rts_params(wma_handle, value); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_frag_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.threshold.frag_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_frag_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.threshold.frag_threshold = value; + wma_update_frag_params(wma_handle, + value); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_fils_enabled_info(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.oce.fils_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_fils_enabled_info(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.oce.fils_enabled = value; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_primary_interface(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.dual_sta_policy.primary_vdev_id = value; + mlme_debug("Set primary iface to :%d", value); + + return QDF_STATUS_SUCCESS; +} + +bool wlan_mlme_is_primary_interface_configured(struct wlan_objmgr_psoc *psoc) +{ + return wlan_cm_same_band_sta_allowed(psoc); +} + +QDF_STATUS wlan_mlme_peer_get_assoc_rsp_ies(struct wlan_objmgr_peer *peer, + const uint8_t **ie_buf, + size_t *ie_len) +{ + struct peer_mlme_priv_obj *peer_priv; + + if (!peer || !ie_buf || !ie_len) + return QDF_STATUS_E_INVAL; + + *ie_buf = NULL; + *ie_len = 0; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + + if (!peer_priv || peer_priv->assoc_rsp.len == 0) + return QDF_STATUS_SUCCESS; + + *ie_buf = peer_priv->assoc_rsp.ptr; + *ie_len = peer_priv->assoc_rsp.len; + + return QDF_STATUS_SUCCESS; +} + +int wlan_mlme_get_mcc_duty_cycle_percentage(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc = NULL; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t i, operating_channel, quota_value = MCC_DUTY_CYCLE; + struct dual_sta_policy *dual_sta_policy; + uint32_t count, primary_sta_freq = 0, secondary_sta_freq = 0; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return -EINVAL; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return -EINVAL; + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + + if (dual_sta_policy->primary_vdev_id == WLAN_INVALID_VDEV_ID || + (dual_sta_policy->concurrent_sta_policy == + QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED)) { + mlme_debug("Invalid primary vdev id or policy is unbaised :%d", + dual_sta_policy->concurrent_sta_policy); + return -EINVAL; + } + + count = policy_mgr_get_mode_specific_conn_info(psoc, op_ch_freq_list, + vdev_id_list, + PM_STA_MODE); + + /* Proceed only in case of STA+STA */ + if (count != 2) { + mlme_debug("STA+STA concurrency is not present"); + return -EINVAL; + } + + for (i = 0; i < count; i++) { + if (vdev_id_list[i] == dual_sta_policy->primary_vdev_id) { + primary_sta_freq = op_ch_freq_list[i]; + mlme_debug("primary sta vdev:%d at inxex:%d, freq:%d", + i, vdev_id_list[i], op_ch_freq_list[i]); + } else { + secondary_sta_freq = op_ch_freq_list[i]; + mlme_debug("secondary sta vdev:%d at inxex:%d, freq:%d", + i, vdev_id_list[i], op_ch_freq_list[i]); + } + } + + if (!primary_sta_freq || !secondary_sta_freq) { + mlme_debug("Invalid primary or secondary sta freq"); + return -EINVAL; + } + + operating_channel = wlan_freq_to_chan(primary_sta_freq); + + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector + * ****************************************************** + * |bit 31-24 | bit 23-16 | bits 15-8 |bits 7-0 | + * | Unused | Quota for | chan. # for |chan. # for| + * | | 1st chan | 1st chan. |2nd chan. | + * ****************************************************** + */ + mlme_debug("First connection channel No.:%d and quota:%dms", + operating_channel, quota_value); + /* Move the time quota for first channel to bits 15-8 */ + quota_value = quota_value << 8; + /* + * Store the channel number of 1st channel at bits 7-0 + * of the bit vector + */ + quota_value |= operating_channel; + /* Second STA Connection */ + operating_channel = wlan_freq_to_chan(secondary_sta_freq); + if (!operating_channel) + mlme_debug("Secondary adapter op channel is invalid"); + /* + * Now move the time quota and channel number of the + * 1st adapter to bits 23-16 and bits 15-8 of the bit + * vector, respectively. + */ + quota_value = quota_value << 8; + /* + * Set the channel number for 2nd MCC vdev at bits + * 7-0 of set_value + */ + quota_value |= operating_channel; + mlme_debug("quota value:%x", quota_value); + + return quota_value; +} + +QDF_STATUS wlan_mlme_set_enable_bcast_probe_rsp(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.oce.enable_bcast_probe_rsp = value; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_sta_miracast_mcc_rest_time(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sta.sta_miracast_mcc_rest_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_max_modulated_dtim_ms(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sta.max_li_modulated_dtim_time_ms; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sta.usr_scan_probe_unicast_ra; + + mlme_legacy_debug("scan_probe_unicast_ra %d", *value); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_scan_probe_unicast_ra(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_legacy_debug("scan_probe_unicast_ra %d", value); + mlme_obj->cfg.sta.usr_scan_probe_unicast_ra = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_sap_mcc_chnl_avoid(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.sap_cfg.sap_mcc_chnl_avoid; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mcc_bcast_prob_resp(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.feature_flags.mcc_bcast_prob_rsp; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mcc_rts_cts_prot(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.feature_flags.mcc_rts_cts_prot; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mcc_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.feature_flags.enable_mcc; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_edca_params(struct wlan_mlme_edca_params *edca_params, + uint8_t *data, enum e_edca_type edca_ac) +{ + qdf_size_t len; + + switch (edca_ac) { + case edca_ani_acbe_local: + len = edca_params->ani_acbe_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acbe_l, &len); + break; + + case edca_ani_acbk_local: + len = edca_params->ani_acbk_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acbk_l, &len); + break; + + case edca_ani_acvi_local: + len = edca_params->ani_acvi_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acvi_l, &len); + break; + + case edca_ani_acvo_local: + len = edca_params->ani_acvo_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acvo_l, &len); + break; + + case edca_ani_acbk_bcast: + len = edca_params->ani_acbk_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acbk_b, &len); + break; + + case edca_ani_acbe_bcast: + len = edca_params->ani_acbe_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acbe_b, &len); + break; + + case edca_ani_acvi_bcast: + len = edca_params->ani_acvi_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acvi_b, &len); + break; + + case edca_ani_acvo_bcast: + len = edca_params->ani_acvo_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->ani_acvo_b, &len); + break; + + case edca_wme_acbe_local: + len = edca_params->wme_acbe_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acbe_l, &len); + break; + + case edca_wme_acbk_local: + len = edca_params->wme_acbk_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acbk_l, &len); + break; + + case edca_wme_acvi_local: + len = edca_params->wme_acvi_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acvi_l, &len); + break; + + case edca_wme_acvo_local: + len = edca_params->wme_acvo_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acvo_l, &len); + break; + + case edca_wme_acbe_bcast: + len = edca_params->wme_acbe_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acbe_b, &len); + break; + + case edca_wme_acbk_bcast: + len = edca_params->wme_acbk_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acbk_b, &len); + break; + + case edca_wme_acvi_bcast: + len = edca_params->wme_acvi_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acvi_b, &len); + break; + + case edca_wme_acvo_bcast: + len = edca_params->wme_acvo_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->wme_acvo_b, &len); + break; + + case edca_etsi_acbe_local: + len = edca_params->etsi_acbe_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acbe_l, &len); + break; + + case edca_etsi_acbk_local: + len = edca_params->etsi_acbk_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acbk_l, &len); + break; + + case edca_etsi_acvi_local: + len = edca_params->etsi_acvi_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acvi_l, &len); + break; + + case edca_etsi_acvo_local: + len = edca_params->etsi_acvo_l.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acvo_l, &len); + break; + + case edca_etsi_acbe_bcast: + len = edca_params->etsi_acbe_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acbe_b, &len); + break; + + case edca_etsi_acbk_bcast: + len = edca_params->etsi_acbk_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acbk_b, &len); + break; + + case edca_etsi_acvi_bcast: + len = edca_params->etsi_acvi_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acvi_b, &len); + break; + + case edca_etsi_acvo_bcast: + len = edca_params->etsi_acvo_b.len; + wlan_mlme_get_cfg_str(data, &edca_params->etsi_acvo_b, &len); + break; + default: + mlme_legacy_err("Invalid edca access category"); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_get_wep_key(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_wep_cfg *wep_params, + enum wep_key_id wep_keyid, uint8_t *default_key, + qdf_size_t *key_len) +{ + struct wlan_crypto_key *crypto_key = NULL; + + if (wep_keyid >= WLAN_CRYPTO_MAXKEYIDX) { + mlme_legacy_err("Incorrect wep key index %d", wep_keyid); + return QDF_STATUS_E_INVAL; + } + crypto_key = wlan_crypto_get_key(vdev, wep_keyid); + if (!crypto_key) { + mlme_legacy_err("Crypto KEY not present"); + return QDF_STATUS_E_INVAL; + } + + if (crypto_key->keylen > WLAN_CRYPTO_KEY_WEP104_LEN) { + mlme_legacy_err("Key too large to hold"); + return QDF_STATUS_E_INVAL; + } + *key_len = crypto_key->keylen; + qdf_mem_copy(default_key, &crypto_key->keyval, crypto_key->keylen); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_is_11h_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.enabled_11h; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_11h_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.enabled_11h = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_is_11d_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.enabled_11d; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_11d_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.enabled_11d = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_is_rf_test_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = false; + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.gen.enabled_rf_test_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_rf_test_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.enabled_rf_test_mode = value; + + return QDF_STATUS_SUCCESS; +} + +#ifdef CONFIG_BAND_6GHZ +QDF_STATUS +wlan_mlme_is_standard_6ghz_conn_policy_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.std_6ghz_conn_policy; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled( + struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.disable_vlp_sta_conn_to_sp_ap; + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +wlan_mlme_get_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.eht_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.gen.enable_emlsr_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_eht_mode(struct wlan_objmgr_psoc *psoc, enum wlan_eht_mode value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.eht_mode = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_emlsr_mode_enabled(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.enable_emlsr_mode = value; + + return QDF_STATUS_SUCCESS; +} + +void +wlan_mlme_set_eml_params(struct wlan_objmgr_psoc *psoc, + struct wlan_psoc_host_mac_phy_caps_ext2 *cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + if (!cap->emlcap.emlsr_supp) { + mlme_legacy_debug("EMLSR supp: %d", cap->emlcap.emlsr_supp); + return; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("No psoc object"); + return; + } + mlme_obj->cfg.eml_cap.emlsr_supp = cap->emlcap.emlsr_supp; + mlme_obj->cfg.eml_cap.emlsr_pad_delay = cap->emlcap.emlsr_pad_delay; + mlme_obj->cfg.eml_cap.emlsr_trans_delay = cap->emlcap.emlsr_trans_delay; + mlme_obj->cfg.eml_cap.emlmr_supp = cap->emlcap.emlmr_supp; +} + +void +wlan_mlme_get_eml_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlo_eml_cap *cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("No psoc object"); + return; + } + cap->emlsr_supp = mlme_obj->cfg.eml_cap.emlsr_supp; + cap->emlsr_pad_delay = mlme_obj->cfg.eml_cap.emlsr_pad_delay; + cap->emlsr_trans_delay = mlme_obj->cfg.eml_cap.emlsr_trans_delay; + cap->emlmr_supp = mlme_obj->cfg.eml_cap.emlmr_supp; +} + +void +wlan_mlme_cfg_set_emlsr_pad_delay(struct wlan_objmgr_psoc *psoc, uint8_t val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("No psoc object"); + return; + } + + if (val > mlme_obj->cfg.eml_cap.emlsr_pad_delay && + val <= WLAN_ML_BV_CINFO_EMLCAP_EMLSRDELAY_256US) { + mlme_obj->cfg.eml_cap.emlsr_pad_delay = val; + mlme_debug("EMLSR padding delay configured to %d", val); + } +} + +enum t2lm_negotiation_support +wlan_mlme_get_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return T2LM_NEGOTIATION_DISABLED; + + return mlme_obj->cfg.gen.t2lm_negotiation_support; +} + +QDF_STATUS +wlan_mlme_set_t2lm_negotiation_supported(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (value > T2LM_NEGOTIATION_MAX) { + mlme_err("Invalid value %d", value); + return QDF_STATUS_E_INVAL; + } + + mlme_obj->cfg.gen.t2lm_negotiation_support = value; + + return QDF_STATUS_SUCCESS; +} + +uint8_t +wlan_mlme_get_eht_mld_id(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + return mlme_obj->cfg.gen.mld_id; +} + +QDF_STATUS +wlan_mlme_set_eht_mld_id(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.gen.mld_id = value; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +wlan_mlme_set_btm_abridge_flag(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.btm.abridge_flag = value; + + return QDF_STATUS_SUCCESS; +} + +bool +wlan_mlme_get_btm_abridge_flag(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.btm.abridge_flag; +} + +QDF_STATUS +wlan_mlme_cfg_set_vht_chan_width(struct wlan_objmgr_psoc *psoc, uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.supp_chan_width = value; + if (value == VHT_CAP_160_AND_80P80_SUPP || + value == VHT_CAP_160_SUPP) { + mlme_obj->cfg.vht_caps.vht_cap_info.vht_extended_nss_bw_cap = 1; + mlme_obj->cfg.vht_caps.vht_cap_info.extended_nss_bw_supp = 0; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_vht_chan_width(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.supp_chan_width; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_set_vht_ldpc_coding_cap(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.ldpc_coding_cap = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_set_short_gi_160_mhz(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.short_gi_160mhz = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_short_gi_160_mhz(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.short_gi_160mhz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_vht_tx_stbc(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.tx_stbc; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_vht_rx_stbc(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.rx_stbc; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_set_vht_tx_bfee_ant_supp(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.tx_bfee_ant_supp = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_vht_tx_bfee_ant_supp(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.tx_bfee_ant_supp; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_vht_rx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.rx_mcs_map; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_set_vht_rx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.rx_mcs_map = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_get_vht_tx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.tx_mcs_map; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_cfg_set_vht_tx_mcs_map(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.tx_mcs_map = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_set_vht_rx_supp_data_rate(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.rx_supp_data_rate = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_set_vht_tx_supp_data_rate(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.tx_supp_data_rate = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_vht_basic_mcs_set(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.basic_mcs_set; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_set_vht_basic_mcs_set(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.basic_mcs_set = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_enable_tx_bf(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.su_bformee; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_tx_su_beamformer(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.su_bformer; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_channel_width(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.channel_width; + + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS +wlan_mlme_get_vht_rx_mcs_8_9(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.rx_mcs; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_tx_mcs_8_9(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.tx_mcs; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_rx_mcs_2x2(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.rx_mcs2x2; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_tx_mcs_2x2(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.tx_mcs2x2; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht20_mcs9(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.enable_vht20_mcs9; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_indoor_support_for_nan(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = false; + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.enable_nan_on_indoor_channels; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = false; + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + switch (vdev_opmode) { + case QDF_SAP_MODE: + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode & + MLME_SRD_MASTER_MODE_SAP; + break; + case QDF_P2P_GO_MODE: + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode & + MLME_SRD_MASTER_MODE_P2P_GO; + break; + case QDF_NAN_DISC_MODE: + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode & + MLME_SRD_MASTER_MODE_NAN; + break; + default: + mlme_legacy_err("Unexpected opmode %d", vdev_opmode); + *value = false; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_enable_dynamic_nss_chains_cfg(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.nss_chains_ini_cfg.enable_dynamic_nss_chains_cfg; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_restart_sap_on_dynamic_nss_chains_cfg( + struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = + mlme_obj->cfg.nss_chains_ini_cfg.restart_sap_on_dyn_nss_chains_cfg; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_get_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.dynamic_nss_chains_support; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_cfg_set_dynamic_nss_chains_support(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.dynamic_nss_chains_support = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_force_sap_enabled(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.acs.force_sap_start; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_vht_enable2x2(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2 = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_enable_paid(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.enable_paid; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_enable_gid(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.enable_gid; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.b24ghz_band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.vht_caps.vht_cap_info.b24ghz_band = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_vendor_vht_for_24ghz(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.vht_caps.vht_cap_info.vendor_24ghz_band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +mlme_update_vht_cap(struct wlan_objmgr_psoc *psoc, struct wma_tgt_vht_cap *cfg) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct mlme_vht_capabilities_info *vht_cap_info; + uint32_t value = 0; + bool hw_rx_ldpc_enabled; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + vht_cap_info = &mlme_obj->cfg.vht_caps.vht_cap_info; + + /* + * VHT max MPDU length: + * override if user configured value is too high + * that the target cannot support + */ + if (vht_cap_info->ampdu_len > cfg->vht_max_mpdu) + vht_cap_info->ampdu_len = cfg->vht_max_mpdu; + if (vht_cap_info->ampdu_len >= 1) + mlme_obj->cfg.ht_caps.ht_cap_info.maximal_amsdu_size = 1; + value = (CFG_VHT_BASIC_MCS_SET_STADEF & VHT_MCS_1x1) | + vht_cap_info->basic_mcs_set; + if (vht_cap_info->enable2x2) + value = (value & VHT_MCS_2x2) | (vht_cap_info->rx_mcs2x2 << 2); + vht_cap_info->basic_mcs_set = value; + + value = (CFG_VHT_RX_MCS_MAP_STADEF & VHT_MCS_1x1) | + vht_cap_info->rx_mcs; + + if (vht_cap_info->enable2x2) + value = (value & VHT_MCS_2x2) | (vht_cap_info->rx_mcs2x2 << 2); + vht_cap_info->rx_mcs_map = value; + + value = (CFG_VHT_TX_MCS_MAP_STADEF & VHT_MCS_1x1) | + vht_cap_info->tx_mcs; + if (vht_cap_info->enable2x2) + value = (value & VHT_MCS_2x2) | (vht_cap_info->tx_mcs2x2 << 2); + vht_cap_info->tx_mcs_map = value; + + /* Set HW RX LDPC capability */ + hw_rx_ldpc_enabled = !!cfg->vht_rx_ldpc; + if (vht_cap_info->ldpc_coding_cap && !hw_rx_ldpc_enabled) + vht_cap_info->ldpc_coding_cap = hw_rx_ldpc_enabled; + + /* set the Guard interval 80MHz */ + if (vht_cap_info->short_gi_80mhz && !cfg->vht_short_gi_80) + vht_cap_info->short_gi_80mhz = cfg->vht_short_gi_80; + + /* Set VHT TX/RX STBC cap */ + if (vht_cap_info->enable2x2) { + if (vht_cap_info->tx_stbc && !cfg->vht_tx_stbc) + vht_cap_info->tx_stbc = cfg->vht_tx_stbc; + + if (vht_cap_info->rx_stbc && !cfg->vht_rx_stbc) + vht_cap_info->rx_stbc = cfg->vht_rx_stbc; + } else { + vht_cap_info->tx_stbc = 0; + vht_cap_info->rx_stbc = 0; + } + + /* Set VHT SU Beamformer cap */ + if (vht_cap_info->su_bformer && !cfg->vht_su_bformer) + vht_cap_info->su_bformer = cfg->vht_su_bformer; + + /* check and update SU BEAMFORMEE capabality */ + if (vht_cap_info->su_bformee && !cfg->vht_su_bformee) + vht_cap_info->su_bformee = cfg->vht_su_bformee; + + /* Set VHT MU Beamformer cap */ + if (vht_cap_info->mu_bformer && !cfg->vht_mu_bformer) + vht_cap_info->mu_bformer = cfg->vht_mu_bformer; + + /* Set VHT MU Beamformee cap */ + if (vht_cap_info->enable_mu_bformee && !cfg->vht_mu_bformee) + vht_cap_info->enable_mu_bformee = cfg->vht_mu_bformee; + + /* + * VHT max AMPDU len exp: + * override if user configured value is too high + * that the target cannot support. + * Even though Rome publish ampdu_len=7, it can + * only support 4 because of some h/w bug. + */ + if (vht_cap_info->ampdu_len_exponent > cfg->vht_max_ampdu_len_exp) + vht_cap_info->ampdu_len_exponent = cfg->vht_max_ampdu_len_exp; + + /* Set VHT TXOP PS CAP */ + if (vht_cap_info->txop_ps && !cfg->vht_txop_ps) + vht_cap_info->txop_ps = cfg->vht_txop_ps; + + /* set the Guard interval 160MHz */ + if (vht_cap_info->short_gi_160mhz && !cfg->vht_short_gi_160) + vht_cap_info->short_gi_160mhz = cfg->vht_short_gi_160; + + if (cfg_get(psoc, CFG_ENABLE_VHT_MCS_10_11)) + vht_cap_info->vht_mcs_10_11_supp = cfg->vht_mcs_10_11_supp; + + mlme_legacy_debug("vht_mcs_10_11_supp %d", + vht_cap_info->vht_mcs_10_11_supp); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_update_nss_vht_cap(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct mlme_vht_capabilities_info *vht_cap_info; + uint32_t temp = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + vht_cap_info = &mlme_obj->cfg.vht_caps.vht_cap_info; + + temp = vht_cap_info->basic_mcs_set; + temp = (temp & 0xFFFC) | vht_cap_info->rx_mcs; + if (vht_cap_info->enable2x2) + temp = (temp & 0xFFF3) | (vht_cap_info->rx_mcs2x2 << 2); + else + temp |= 0x000C; + + vht_cap_info->basic_mcs_set = temp; + + temp = vht_cap_info->rx_mcs_map; + temp = (temp & 0xFFFC) | vht_cap_info->rx_mcs; + if (vht_cap_info->enable2x2) + temp = (temp & 0xFFF3) | (vht_cap_info->rx_mcs2x2 << 2); + else + temp |= 0x000C; + + vht_cap_info->rx_mcs_map = temp; + + temp = vht_cap_info->tx_mcs_map; + temp = (temp & 0xFFFC) | vht_cap_info->tx_mcs; + if (vht_cap_info->enable2x2) + temp = (temp & 0xFFF3) | (vht_cap_info->tx_mcs2x2 << 2); + else + temp |= 0x000C; + + vht_cap_info->tx_mcs_map = temp; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +bool mlme_get_bss_11be_allowed(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t *ie_data, + uint32_t ie_length) +{ + struct action_oui_search_attr search_attr; + + if (wlan_action_oui_is_empty(psoc, ACTION_OUI_11BE_OUI_ALLOW)) + return true; + + qdf_mem_zero(&search_attr, sizeof(search_attr)); + search_attr.ie_data = ie_data; + search_attr.ie_length = ie_length; + if (wlan_action_oui_search(psoc, &search_attr, + ACTION_OUI_11BE_OUI_ALLOW)) + return true; + + mlme_legacy_debug("AP not in 11be oui allow list "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid->bytes)); + + return false; +} + +QDF_STATUS wlan_mlme_get_oem_eht_mlo_config(struct wlan_objmgr_psoc *psoc, + uint32_t *oem_eht_cfg) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *oem_eht_cfg = mlme_obj->cfg.gen.oem_eht_mlo_crypto_bitmap; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wlan_mlme_is_sap_uapsd_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.qos_mlme_params.sap_uapsd_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_dtim_selection_diversity(struct wlan_objmgr_psoc *psoc, + uint32_t *dtim_selection_div) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *dtim_selection_div = cfg_default(CFG_DTIM_SELECTION_DIVERSITY); + return QDF_STATUS_E_FAILURE; + } + + *dtim_selection_div = mlme_obj->cfg.ps_params.dtim_selection_diversity; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_bmps_min_listen_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_BMPS_MINIMUM_LI); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.ps_params.bmps_min_listen_interval; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_bmps_max_listen_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_BMPS_MAXIMUM_LI); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.ps_params.bmps_max_listen_interval; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_set_sap_uapsd_flag(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.qos_mlme_params.sap_uapsd_enabled &= value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_rrm_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *value = mlme_obj->cfg.rrm_config.rrm_enabled; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_auto_bmps_timer_value(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_AUTO_BMPS_ENABLE_TIMER); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.ps_params.auto_bmps_timer_val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_is_bmps_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_ENABLE_PS); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.ps_params.is_bmps_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_is_imps_enabled(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_ENABLE_IMPS); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.ps_params.is_imps_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_override_bmps_imps(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.ps_params.is_imps_enabled = 0; + mlme_obj->cfg.ps_params.is_bmps_enabled = 0; + + return QDF_STATUS_SUCCESS; +} + +void wlan_mlme_get_wps_uuid(struct wlan_mlme_wps_params *wps_params, + uint8_t *data) +{ + qdf_size_t len = wps_params->wps_uuid.len; + + wlan_mlme_get_cfg_str(data, &wps_params->wps_uuid, &len); +} + +QDF_STATUS +wlan_mlme_get_self_gen_frm_pwr(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_SELF_GEN_FRM_PWR); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.reg.self_gen_frm_pwr; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_4way_hs_offload(struct wlan_objmgr_psoc *psoc, uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_DISABLE_4WAY_HS_OFFLOAD); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.gen.disable_4way_hs_offload; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bmiss_skip_full_scan_value(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_BMISS_SKIP_FULL_SCAN); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + *value = mlme_obj->cfg.gen.bmiss_skip_full_scan; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_get_peer_phymode(struct wlan_objmgr_psoc *psoc, uint8_t *mac, + enum wlan_phymode *peer_phymode) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_get_peer_by_mac(psoc, mac, WLAN_MLME_NB_ID); + if (!peer) { + mlme_legacy_err("peer object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + *peer_phymode = wlan_peer_get_phymode(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_set_tgt_wpa3_roam_cap(struct wlan_objmgr_psoc *psoc, + uint32_t akm_bitmap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.lfr.fw_akm_bitmap |= akm_bitmap; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_ignore_fw_reg_offload_ind(struct wlan_objmgr_psoc *psoc, + bool *disabled) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *disabled = mlme_obj->cfg.reg.ignore_fw_reg_offload_ind; + return QDF_STATUS_SUCCESS; +} + +char *mlme_get_roam_status_str(uint32_t roam_status) +{ + switch (roam_status) { + case 0: + return "SUCCESS"; + case 1: + return "FAILED"; + case 2: + return "NO ROAM"; + default: + return "UNKNOWN"; + } +} + +char *mlme_get_roam_trigger_str(uint32_t roam_scan_trigger) +{ + switch (roam_scan_trigger) { + case WMI_ROAM_TRIGGER_REASON_PER: + return "PER"; + case WMI_ROAM_TRIGGER_REASON_BMISS: + return "BEACON MISS"; + case WMI_ROAM_TRIGGER_REASON_LOW_RSSI: + return "LOW RSSI"; + case WMI_ROAM_TRIGGER_REASON_HIGH_RSSI: + return "HIGH RSSI"; + case WMI_ROAM_TRIGGER_REASON_PERIODIC: + return "PERIODIC SCAN"; + case WMI_ROAM_TRIGGER_REASON_MAWC: + return "MAWC"; + case WMI_ROAM_TRIGGER_REASON_DENSE: + return "DENSE ENVIRONMENT"; + case WMI_ROAM_TRIGGER_REASON_BACKGROUND: + return "BACKGROUND SCAN"; + case WMI_ROAM_TRIGGER_REASON_FORCED: + return "FORCED SCAN"; + case WMI_ROAM_TRIGGER_REASON_BTM: + return "BTM TRIGGER"; + case WMI_ROAM_TRIGGER_REASON_UNIT_TEST: + return "TEST COMMAND"; + case WMI_ROAM_TRIGGER_REASON_BSS_LOAD: + return "HIGH BSS LOAD"; + case WMI_ROAM_TRIGGER_REASON_DEAUTH: + return "DEAUTH RECEIVED"; + case WMI_ROAM_TRIGGER_REASON_IDLE: + return "IDLE STATE SCAN"; + case WMI_ROAM_TRIGGER_REASON_STA_KICKOUT: + return "STA KICKOUT"; + case WMI_ROAM_TRIGGER_REASON_ESS_RSSI: + return "ESS RSSI"; + case WMI_ROAM_TRIGGER_REASON_WTC_BTM: + return "WTC BTM"; + case WMI_ROAM_TRIGGER_REASON_NONE: + return "NONE"; + case WMI_ROAM_TRIGGER_REASON_PMK_TIMEOUT: + return "PMK Expired"; + case WMI_ROAM_TRIGGER_REASON_BTC: + return "BTC TRIGGER"; + default: + return "UNKNOWN"; + } +} + +void mlme_get_converted_timestamp(uint32_t timestamp, char *time) +{ + uint32_t hr, mins, secs; + + secs = timestamp / 1000; + mins = secs / 60; + hr = mins / 60; + qdf_snprint(time, TIME_STRING_LEN, "[%02d:%02d:%02d.%06u]", + (hr % 24), (mins % 60), (secs % 60), + (timestamp % 1000) * 1000); +} + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +void wlan_mlme_set_sae_single_pmk_bss_cap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + + if (!vdev) { + mlme_err("get vdev failed"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->mlme_roam.sae_single_pmk.sae_single_pmk_ap = val; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); +} + +void wlan_mlme_update_sae_single_pmk(struct wlan_objmgr_vdev *vdev, + struct mlme_pmk_info *sae_single_pmk) +{ + struct mlme_legacy_priv *mlme_priv; + int32_t keymgmt; + bool is_sae_connection = false; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + keymgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (keymgmt < 0) { + mlme_legacy_err("Invalid mgmt cipher"); + return; + } + + if (QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) + is_sae_connection = true; + + mlme_legacy_debug("SAE_SPMK: single_pmk_ap:%d, is_sae_connection:%d, pmk_len:%d", + mlme_priv->mlme_roam.sae_single_pmk.sae_single_pmk_ap, + is_sae_connection, sae_single_pmk->pmk_len); + + if (mlme_priv->mlme_roam.sae_single_pmk.sae_single_pmk_ap && + is_sae_connection) + mlme_priv->mlme_roam.sae_single_pmk.pmk_info = *sae_single_pmk; +} + +bool wlan_mlme_is_sae_single_pmk_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_SAE_SINGLE_PMK); + + return mlme_obj->cfg.lfr.sae_single_pmk_feature_enabled; +} + +void wlan_mlme_get_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_sae_single_pmk *pmksa) +{ + struct mlme_legacy_priv *mlme_priv; + struct mlme_pmk_info *pmk_info; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + pmk_info = &mlme_priv->mlme_roam.sae_single_pmk.pmk_info; + + pmksa->sae_single_pmk_ap = + mlme_priv->mlme_roam.sae_single_pmk.sae_single_pmk_ap; + pmksa->pmk_info.spmk_timeout_period = pmk_info->spmk_timeout_period; + pmksa->pmk_info.spmk_timestamp = pmk_info->spmk_timestamp; + + if (pmk_info->pmk_len) { + qdf_mem_copy(pmksa->pmk_info.pmk, pmk_info->pmk, + pmk_info->pmk_len); + pmksa->pmk_info.pmk_len = pmk_info->pmk_len; + return; + } + + qdf_mem_zero(pmksa->pmk_info.pmk, sizeof(*pmksa->pmk_info.pmk)); + pmksa->pmk_info.pmk_len = 0; +} + +void wlan_mlme_clear_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct mlme_pmk_info *pmk_recv) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_mlme_sae_single_pmk *sae_single_pmk; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + sae_single_pmk = &mlme_priv->mlme_roam.sae_single_pmk; + + if (!pmk_recv) { + /* Process flush pmk cmd */ + mlme_legacy_debug("Flush sae_single_pmk info"); + qdf_mem_zero(&sae_single_pmk->pmk_info, + sizeof(sae_single_pmk->pmk_info)); + } else if (pmk_recv->pmk_len != sae_single_pmk->pmk_info.pmk_len) { + mlme_legacy_debug("Invalid pmk len"); + return; + } else if (!qdf_mem_cmp(&sae_single_pmk->pmk_info.pmk, pmk_recv->pmk, + pmk_recv->pmk_len)) { + /* Process delete pmk cmd */ + mlme_legacy_debug("Clear sae_single_pmk info"); + qdf_mem_zero(&sae_single_pmk->pmk_info, + sizeof(sae_single_pmk->pmk_info)); + } +} +#endif + +char *mlme_get_roam_fail_reason_str(enum wlan_roam_failure_reason_code result) +{ + switch (result) { + case ROAM_FAIL_REASON_NO_SCAN_START: + return "SCAN NOT STARTED"; + case ROAM_FAIL_REASON_NO_AP_FOUND: + return "NO AP FOUND"; + case ROAM_FAIL_REASON_NO_CAND_AP_FOUND: + return "NO CANDIDATE FOUND"; + case ROAM_FAIL_REASON_HOST: + return "HOST ABORTED"; + case ROAM_FAIL_REASON_AUTH_SEND: + return "Send AUTH Failed"; + case ROAM_FAIL_REASON_AUTH_RECV: + return "Received AUTH with FAILURE Status"; + case ROAM_FAIL_REASON_NO_AUTH_RESP: + return "No Auth response from AP"; + case ROAM_FAIL_REASON_REASSOC_SEND: + return "Send Re-assoc request failed"; + case ROAM_FAIL_REASON_REASSOC_RECV: + return "Received Re-Assoc resp with Failure status"; + case ROAM_FAIL_REASON_NO_REASSOC_RESP: + return "No Re-assoc response from AP"; + case ROAM_FAIL_REASON_EAPOL_TIMEOUT: + return "EAPOL M1 timed out"; + case ROAM_FAIL_REASON_MLME: + return "MLME error"; + case ROAM_FAIL_REASON_INTERNAL_ABORT: + return "Fw aborted roam"; + case ROAM_FAIL_REASON_SCAN_START: + return "Unable to start roam scan"; + case ROAM_FAIL_REASON_AUTH_NO_ACK: + return "No ACK for Auth req"; + case ROAM_FAIL_REASON_AUTH_INTERNAL_DROP: + return "Auth req dropped internally"; + case ROAM_FAIL_REASON_REASSOC_NO_ACK: + return "No ACK for Re-assoc req"; + case ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP: + return "Re-assoc dropped internally"; + case ROAM_FAIL_REASON_EAPOL_M2_SEND: + return "Unable to send M2 frame"; + case ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP: + return "M2 Frame dropped internally"; + case ROAM_FAIL_REASON_EAPOL_M2_NO_ACK: + return "No ACK for M2 frame"; + case ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT: + return "EAPOL M3 timed out"; + case ROAM_FAIL_REASON_EAPOL_M4_SEND: + return "Unable to send M4 frame"; + case ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP: + return "M4 frame dropped internally"; + case ROAM_FAIL_REASON_EAPOL_M4_NO_ACK: + return "No ACK for M4 frame"; + case ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS: + return "No scan on final BMISS"; + case ROAM_FAIL_REASON_DISCONNECT: + return "Disconnect received during handoff"; + case ROAM_FAIL_REASON_SYNC: + return "Previous roam sync pending"; + case ROAM_FAIL_REASON_SAE_INVALID_PMKID: + return "Reason assoc reject - invalid PMKID"; + case ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: + return "SAE preauth timed out"; + case ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: + return "SAE preauth failed"; + case ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO: + return "Start handoff failed- internal error"; + case ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT: + return "No AP found on final BMISS"; + case ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT: + return "No Candidate AP found on final BMISS"; + case ROAM_FAIL_REASON_CURR_AP_STILL_OK: + return "CURRENT AP STILL OK"; + default: + return "UNKNOWN"; + } +} + +char *mlme_get_sub_reason_str(enum roam_trigger_sub_reason sub_reason) +{ + switch (sub_reason) { + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER: + return "PERIODIC TIMER"; + case ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC: + return "LOW RSSI PERIODIC TIMER1"; + case ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER: + return "BTM DISASSOC IMMINENT TIMER"; + case ROAM_TRIGGER_SUB_REASON_FULL_SCAN: + return "FULL SCAN"; + case ROAM_TRIGGER_SUB_REASON_CU_PERIODIC: + return "CU PERIODIC Timer1"; + case ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI: + return "LOW RSSI INACTIVE TIMER"; + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU: + return "CU PERIODIC TIMER2"; + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY: + return "LOW RSSI PERIODIC TIMER2"; + case ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU: + return "CU INACTIVITY TIMER"; + default: + return "NONE"; + } +} + +QDF_STATUS +wlan_mlme_get_mgmt_max_retry(struct wlan_objmgr_psoc *psoc, + uint8_t *max_retry) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *max_retry = cfg_default(CFG_MGMT_RETRY_MAX); + return QDF_STATUS_E_FAILURE; + } + + *max_retry = mlme_obj->cfg.gen.mgmt_retry_max; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mgmt_6ghz_rate_support(struct wlan_objmgr_psoc *psoc, + bool *enable_he_mcs0_for_6ghz_mgmt) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *enable_he_mcs0_for_6ghz_mgmt = + cfg_default(CFG_ENABLE_HE_MCS0_MGMT_6GHZ); + return QDF_STATUS_E_FAILURE; + } + + *enable_he_mcs0_for_6ghz_mgmt = + mlme_obj->cfg.gen.enable_he_mcs0_for_6ghz_mgmt; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_status_ring_buffer(struct wlan_objmgr_psoc *psoc, + bool *enable_ring_buffer) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *enable_ring_buffer = cfg_default(CFG_ENABLE_RING_BUFFER); + return QDF_STATUS_E_FAILURE; + } + + *enable_ring_buffer = mlme_obj->cfg.gen.enable_ring_buffer; + return QDF_STATUS_SUCCESS; +} + +bool wlan_mlme_get_peer_unmap_conf(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.gen.enable_peer_unmap_conf_support; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +wlan_mlme_get_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t *roam_reason_vsie_enable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *roam_reason_vsie_enable = + cfg_default(CFG_ENABLE_ROAM_REASON_VSIE); + return QDF_STATUS_E_FAILURE; + } + + *roam_reason_vsie_enable = mlme_obj->cfg.lfr.enable_roam_reason_vsie; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_roam_reason_vsie_status(struct wlan_objmgr_psoc *psoc, + uint8_t roam_reason_vsie_enable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.lfr.enable_roam_reason_vsie = roam_reason_vsie_enable; + return QDF_STATUS_SUCCESS; +} + +uint32_t wlan_mlme_get_roaming_triggers(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_ROAM_TRIGGER_BITMAP); + + return mlme_obj->cfg.lfr.roam_trigger_bitmap; +} + +void wlan_mlme_set_roaming_triggers(struct wlan_objmgr_psoc *psoc, + uint32_t trigger_bitmap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.lfr.roam_trigger_bitmap = trigger_bitmap; +} + +QDF_STATUS +wlan_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR3_ROAMING_OFFLOAD); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.lfr3_roaming_offload; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_enable_disconnect_roam_offload(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ENABLE_DISCONNECT_ROAM); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.enable_disconnect_roam_offload; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_enable_idle_roam(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ENABLE_IDLE_ROAM); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.enable_idle_roam; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_idle_roam_rssi_delta(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_IDLE_ROAM_RSSI_DELTA); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.idle_roam_rssi_delta; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_roam_info_stats_num(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR3_ROAM_INFO_STATS_NUM); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_info_stats_num; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_idle_roam_inactive_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_IDLE_ROAM_INACTIVE_TIME); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.idle_roam_inactive_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_idle_data_packet_count(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_IDLE_ROAM_PACKET_COUNT); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.idle_data_packet_count; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_idle_roam_min_rssi(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_IDLE_ROAM_MIN_RSSI); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.idle_roam_min_rssi; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_idle_roam_band(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_IDLE_ROAM_BAND); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.idle_roam_band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_self_bss_roam(struct wlan_objmgr_psoc *psoc, + uint8_t *enable_self_bss_roam) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *enable_self_bss_roam = + cfg_get(psoc, CFG_LFR3_ENABLE_SELF_BSS_ROAM); + return QDF_STATUS_E_FAILURE; + } + + *enable_self_bss_roam = mlme_obj->cfg.lfr.enable_self_bss_roam; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +wlan_mlme_get_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc, + struct peer_oper_mode_event *data) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!data) { + mlme_err("Data params is NULL"); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, data->peer_mac_address.bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_err("peer not found for mac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(data->peer_mac_address.bytes)); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_err("peer priv not found for mac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->macaddr)); + status = QDF_STATUS_E_NULL_VALUE; + goto done; + } + + if (peer_priv->peer_ind_bw == CH_WIDTH_INVALID) { + status = QDF_STATUS_E_INVAL; + goto done; + } + + data->new_bw = peer_priv->peer_ind_bw; + +done: + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS +wlan_mlme_set_peer_indicated_ch_width(struct wlan_objmgr_psoc *psoc, + struct peer_oper_mode_event *data) +{ + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!data) { + mlme_err("Data params is NULL"); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, data->peer_mac_address.bytes, + WLAN_MLME_NB_ID); + if (!peer) { + mlme_err("peer not found for mac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(data->peer_mac_address.bytes)); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + mlme_err("peer priv not found for mac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->macaddr)); + status = QDF_STATUS_E_NULL_VALUE; + goto done; + } + + peer_priv->peer_ind_bw = + target_if_wmi_chan_width_to_phy_ch_width(data->new_bw); + +done: + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS +wlan_mlme_set_ft_over_ds(struct wlan_objmgr_psoc *psoc, + uint8_t ft_over_ds_enable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.lfr.enable_ft_over_ds = ft_over_ds_enable; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_dfs_chan_ageout_time(struct wlan_objmgr_psoc *psoc, + uint8_t *dfs_chan_ageout_time) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *dfs_chan_ageout_time = + cfg_default(CFG_DFS_CHAN_AGEOUT_TIME); + return QDF_STATUS_E_FAILURE; + } + + *dfs_chan_ageout_time = mlme_obj->cfg.gen.dfs_chan_ageout_time; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_SAE + +#define NUM_RETRY_BITS 3 +#define ROAM_AUTH_INDEX 2 +#define ASSOC_INDEX 1 +#define AUTH_INDEX 0 +#define MAX_RETRIES 2 +#define MAX_ROAM_AUTH_RETRIES 1 +#define MAX_AUTH_RETRIES 3 + +QDF_STATUS +wlan_mlme_get_sae_assoc_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *retry_count = 0; + return QDF_STATUS_E_FAILURE; + } + + *retry_count = + QDF_GET_BITS(mlme_obj->cfg.gen.sae_connect_retries, + ASSOC_INDEX * NUM_RETRY_BITS, NUM_RETRY_BITS); + + *retry_count = QDF_MIN(MAX_RETRIES, *retry_count); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_sae_auth_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *retry_count = 0; + return QDF_STATUS_E_FAILURE; + } + + *retry_count = + QDF_GET_BITS(mlme_obj->cfg.gen.sae_connect_retries, + AUTH_INDEX * NUM_RETRY_BITS, NUM_RETRY_BITS); + + *retry_count = QDF_MIN(MAX_AUTH_RETRIES, *retry_count); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_sae_roam_auth_retry_count(struct wlan_objmgr_psoc *psoc, + uint8_t *retry_count) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *retry_count = 0; + return QDF_STATUS_E_FAILURE; + } + + *retry_count = + QDF_GET_BITS(mlme_obj->cfg.gen.sae_connect_retries, + ROAM_AUTH_INDEX * NUM_RETRY_BITS, NUM_RETRY_BITS); + + *retry_count = QDF_MIN(MAX_ROAM_AUTH_RETRIES, *retry_count); + + return QDF_STATUS_SUCCESS; +} + +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +bool +wlan_mlme_get_dual_sta_roaming_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + bool dual_sta_roaming_enabled; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return cfg_default(CFG_ENABLE_DUAL_STA_ROAM_OFFLOAD); + + dual_sta_roaming_enabled = + mlme_obj->cfg.lfr.lfr3_roaming_offload && + mlme_obj->cfg.lfr.lfr3_dual_sta_roaming_enabled && + wlan_mlme_get_dual_sta_roam_support(psoc) && + policy_mgr_is_hw_dbs_capable(psoc); + + return dual_sta_roaming_enabled; +} +#endif + +QDF_STATUS +wlan_mlme_get_roam_scan_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_scan_offload_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_roam_bmiss_final_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ROAM_BMISS_FINAL_BCNT); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_bmiss_final_bcnt; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bmiss_timeout_on_wakeup(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_BEACONLOSS_TIMEOUT_ON_WAKEUP); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.beaconloss_timeout_onwakeup; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bmiss_timeout_on_sleep(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_BEACONLOSS_TIMEOUT_ON_SLEEP); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.beaconloss_timeout_onsleep; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_roam_bmiss_first_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ROAM_BMISS_FIRST_BCNT); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_bmiss_first_bcnt; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_ADAPTIVE_11R +bool wlan_mlme_adaptive_11r_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_ADAPTIVE_11R); + + return mlme_obj->cfg.lfr.enable_adaptive_11r; +} +#endif + +QDF_STATUS +wlan_mlme_get_mawc_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_FEATURE_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.mawc_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mawc_roam_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_ROAM_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.mawc_roam_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mawc_roam_traffic_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_ROAM_TRAFFIC_THRESHOLD); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.mawc_roam_traffic_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mawc_roam_ap_rssi_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_ROAM_AP_RSSI_THRESHOLD); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.mawc_roam_ap_rssi_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mawc_roam_rssi_high_adjust(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_ROAM_RSSI_HIGH_ADJUST); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.mawc_roam_rssi_high_adjust; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_mawc_roam_rssi_low_adjust(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_ROAM_RSSI_LOW_ADJUST); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.mawc_roam_rssi_low_adjust; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bss_load_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_ENABLE_BSS_LOAD_TRIGGERED_ROAM); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.bss_load_trig.enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bss_load_threshold(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_BSS_LOAD_THRESHOLD); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.bss_load_trig.threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bss_load_sample_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_BSS_LOAD_SAMPLE_TIME); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.bss_load_trig.sample_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bss_load_rssi_threshold_6ghz(struct wlan_objmgr_psoc *psoc, + int32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_BSS_LOAD_TRIG_6G_RSSI_THRES); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.bss_load_trig.rssi_threshold_6ghz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bss_load_rssi_threshold_5ghz(struct wlan_objmgr_psoc *psoc, + int32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_BSS_LOAD_TRIG_5G_RSSI_THRES); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.bss_load_trig.rssi_threshold_5ghz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_bss_load_rssi_threshold_24ghz(struct wlan_objmgr_psoc *psoc, + int32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_BSS_LOAD_TRIG_2G_RSSI_THRES); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.bss_load_trig.rssi_threshold_24ghz; + + return QDF_STATUS_SUCCESS; +} + +bool +wlan_mlme_check_chan_param_has_dfs(struct wlan_objmgr_pdev *pdev, + struct ch_params *ch_params, + uint32_t chan_freq) +{ + bool is_dfs = false; + + if (ch_params->ch_width == CH_WIDTH_160MHZ) { + wlan_reg_set_create_punc_bitmap(ch_params, true); + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(pdev, + chan_freq, + ch_params, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_dfs = true; + } else if (ch_params->ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state_for_pwrmode( + pdev, + chan_freq, + REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS || + wlan_reg_get_channel_state_for_pwrmode( + pdev, + ch_params->mhz_freq_seg1, + REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS) + is_dfs = true; + } else if (wlan_reg_is_dfs_for_freq(pdev, chan_freq)) { + /*Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + is_dfs = true; + } + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq) || + WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) + is_dfs = false; + + return is_dfs; +} + +QDF_STATUS +wlan_mlme_set_usr_disabled_roaming(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.sta.usr_disabled_roaming = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_usr_disabled_roaming(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.sta.usr_disabled_roaming; + + return QDF_STATUS_SUCCESS; +} + +qdf_size_t mlme_get_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *dst, + qdf_size_t len) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev || !dst || !len) { + mlme_legacy_err("invalid params"); + return 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + if (len < mlme_priv->opr_rate_set.len) { + mlme_legacy_err("Invalid length %zd (<%zd)", len, + mlme_priv->opr_rate_set.len); + return 0; + } + + qdf_mem_copy(dst, mlme_priv->opr_rate_set.data, + mlme_priv->opr_rate_set.len); + + return mlme_priv->opr_rate_set.len; +} + +QDF_STATUS mlme_set_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *src, + qdf_size_t len) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev || !src) { + mlme_legacy_err("invalid params"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (len > mlme_priv->opr_rate_set.max_len) { + mlme_legacy_err("Invalid len %zd (>%zd)", len, + mlme_priv->opr_rate_set.max_len); + return QDF_STATUS_E_INVAL; + } + + mlme_priv->opr_rate_set.len = len; + qdf_mem_copy(mlme_priv->opr_rate_set.data, src, len); + + return QDF_STATUS_SUCCESS; +} + +qdf_size_t mlme_get_ext_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *dst, + qdf_size_t len) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev || !dst || !len) { + mlme_legacy_err("invalid params"); + return 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + if (len < mlme_priv->ext_opr_rate_set.len) { + mlme_legacy_err("Invalid length %zd (<%zd)", len, + mlme_priv->ext_opr_rate_set.len); + return 0; + } + + qdf_mem_copy(dst, mlme_priv->ext_opr_rate_set.data, + mlme_priv->ext_opr_rate_set.len); + + return mlme_priv->ext_opr_rate_set.len; +} + +QDF_STATUS mlme_set_ext_opr_rate(struct wlan_objmgr_vdev *vdev, uint8_t *src, + qdf_size_t len) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev || !src) { + mlme_legacy_err("invalid params"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (len > mlme_priv->ext_opr_rate_set.max_len) { + mlme_legacy_err("Invalid len %zd (>%zd)", len, + mlme_priv->ext_opr_rate_set.max_len); + return QDF_STATUS_E_INVAL; + } + + mlme_priv->ext_opr_rate_set.len = len; + qdf_mem_copy(mlme_priv->ext_opr_rate_set.data, src, len); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_clear_ext_opr_rate(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev) { + mlme_legacy_err("invalid params"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->ext_opr_rate_set.len = 0; + qdf_mem_set(mlme_priv->ext_opr_rate_set.data, CFG_STR_DATA_LEN, 0); + + return QDF_STATUS_SUCCESS; +} + +qdf_size_t mlme_get_mcs_rate(struct wlan_objmgr_vdev *vdev, uint8_t *dst, + qdf_size_t len) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev || !dst || !len) { + mlme_legacy_err("invalid params"); + return 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + if (len < mlme_priv->mcs_rate_set.len) { + mlme_legacy_err("Invalid length %zd (<%zd)", len, + mlme_priv->mcs_rate_set.len); + return 0; + } + + qdf_mem_copy(dst, mlme_priv->mcs_rate_set.data, + mlme_priv->mcs_rate_set.len); + + return mlme_priv->mcs_rate_set.len; +} + +QDF_STATUS mlme_set_mcs_rate(struct wlan_objmgr_vdev *vdev, uint8_t *src, + qdf_size_t len) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev || !src) { + mlme_legacy_err("invalid params"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (len > mlme_priv->mcs_rate_set.max_len) { + mlme_legacy_err("Invalid len %zd (>%zd)", len, + mlme_priv->mcs_rate_set.max_len); + return QDF_STATUS_E_INVAL; + } + + mlme_priv->mcs_rate_set.len = len; + qdf_mem_copy(mlme_priv->mcs_rate_set.data, src, len); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_clear_mcs_rate(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev) { + mlme_legacy_err("invalid params"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->mcs_rate_set.len = 0; + qdf_mem_set(mlme_priv->mcs_rate_set.data, CFG_STR_DATA_LEN, 0); + + return QDF_STATUS_SUCCESS; +} + +static enum monitor_mode_concurrency +wlan_mlme_get_monitor_mode_concurrency(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_MONITOR_MODE_CONCURRENCY); + + return mlme_obj->cfg.gen.monitor_mode_concurrency; +} + +#ifdef FEATURE_WDS +enum wlan_wds_mode +wlan_mlme_get_wds_mode(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_WDS_MODE); + + return mlme_obj->cfg.gen.wds_mode; +} + +void wlan_mlme_set_wds_mode(struct wlan_objmgr_psoc *psoc, + enum wlan_wds_mode mode) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + if (mode <= WLAN_WDS_MODE_MAX) + mlme_obj->cfg.gen.wds_mode = mode; +} +#endif + +bool wlan_mlme_is_sta_mon_conc_supported(struct wlan_objmgr_psoc *psoc) +{ + if (wlan_mlme_get_monitor_mode_concurrency(psoc) == + MONITOR_MODE_CONC_STA_SCAN_MON) + return true; + + return false; +} + +bool wlan_mlme_skip_tpe(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.power.skip_tpe; +} + +#ifdef WLAN_FEATURE_11BE +QDF_STATUS mlme_cfg_get_orig_eht_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEeht_cap *eht_cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *eht_cap = mlme_obj->cfg.eht_caps.eht_cap_orig; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mlme_cfg_get_eht_caps(struct wlan_objmgr_psoc *psoc, + tDot11fIEeht_cap *eht_cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + *eht_cap = mlme_obj->cfg.eht_caps.dot11_eht_cap; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +wlan_mlme_set_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev, bool found) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->ba_2k_jump_iot_ap = found; + + return QDF_STATUS_SUCCESS; +} + +bool wlan_mlme_is_ba_2k_jump_iot_ap(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return false; + } + + return mlme_priv->ba_2k_jump_iot_ap; +} + +QDF_STATUS +wlan_mlme_set_last_delba_sent_time(struct wlan_objmgr_vdev *vdev, + qdf_time_t delba_sent_time) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->last_delba_sent_time = delba_sent_time; + + return QDF_STATUS_SUCCESS; +} + +qdf_time_t +wlan_mlme_get_last_delba_sent_time(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return 0; + } + + return mlme_priv->last_delba_sent_time; +} + +QDF_STATUS mlme_set_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + bool ps_enable) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) + return status; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (mlme_priv) { + mlme_priv->is_usr_ps_enabled = ps_enable; + status = QDF_STATUS_SUCCESS; + mlme_legacy_debug("vdev:%d user PS:%d", vdev_id, + mlme_priv->is_usr_ps_enabled); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return status; +} + +bool mlme_get_user_ps(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + bool usr_ps_enable = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) + return false; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (mlme_priv) + usr_ps_enable = mlme_priv->is_usr_ps_enabled; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return usr_ps_enable; +} + +bool wlan_mlme_is_multipass_sap(struct wlan_objmgr_psoc *psoc) +{ + struct target_psoc_info *info; + + info = wlan_psoc_get_tgt_if_handle(psoc); + if (!info) { + mlme_legacy_err("target_psoc_info is null"); + return QDF_STATUS_E_FAILURE; + } + + return target_is_multipass_sap(info); +} + +QDF_STATUS wlan_mlme_get_phy_max_freq_range(struct wlan_objmgr_psoc *psoc, + uint32_t *low_2ghz_chan, + uint32_t *high_2ghz_chan, + uint32_t *low_5ghz_chan, + uint32_t *high_5ghz_chan) +{ + uint32_t i; + uint32_t reg_low_2ghz_chan; + uint32_t reg_high_2ghz_chan; + uint32_t reg_low_5ghz_chan; + uint32_t reg_high_5ghz_chan; + struct target_psoc_info *info; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + struct wlan_psoc_host_hal_reg_cap_ext *reg_cap_ext; + + info = wlan_psoc_get_tgt_if_handle(psoc); + if (!info) { + mlme_legacy_err("target_psoc_info is null"); + return QDF_STATUS_E_FAILURE; + } + mac_phy_cap = info->info.mac_phy_cap; + reg_cap_ext = &mac_phy_cap->reg_cap_ext; + reg_low_2ghz_chan = reg_cap_ext->low_2ghz_chan; + reg_high_2ghz_chan = reg_cap_ext->high_2ghz_chan; + reg_low_5ghz_chan = reg_cap_ext->low_5ghz_chan; + reg_high_5ghz_chan = reg_cap_ext->high_5ghz_chan; + for (i = 1; i < PSOC_MAX_MAC_PHY_CAP; i++) { + mac_phy_cap = &info->info.mac_phy_cap[i]; + reg_cap_ext = &mac_phy_cap->reg_cap_ext; + + if (reg_cap_ext->low_2ghz_chan) { + reg_low_2ghz_chan = reg_low_2ghz_chan ? + QDF_MIN(reg_cap_ext->low_2ghz_chan, + reg_low_2ghz_chan) : + reg_cap_ext->low_2ghz_chan; + } + if (reg_cap_ext->high_2ghz_chan) { + reg_high_2ghz_chan = reg_high_2ghz_chan ? + QDF_MAX(reg_cap_ext->high_2ghz_chan, + reg_high_2ghz_chan) : + reg_cap_ext->high_2ghz_chan; + } + if (reg_cap_ext->low_5ghz_chan) { + reg_low_5ghz_chan = reg_low_5ghz_chan ? + QDF_MIN(reg_cap_ext->low_5ghz_chan, + reg_low_5ghz_chan) : + reg_cap_ext->low_5ghz_chan; + } + if (reg_cap_ext->high_5ghz_chan) { + reg_high_5ghz_chan = reg_high_5ghz_chan ? + QDF_MAX(reg_cap_ext->high_5ghz_chan, + reg_high_5ghz_chan) : + reg_cap_ext->high_5ghz_chan; + } + } + /* For old hw, no reg_cap_ext reported from service ready ext, + * fill the low/high with default of regulatory. + */ + if (!reg_low_2ghz_chan && !reg_high_2ghz_chan && + !reg_low_5ghz_chan && !reg_high_5ghz_chan) { + mlme_legacy_debug("no reg_cap_ext in mac_phy_cap"); + reg_low_2ghz_chan = TWOG_STARTING_FREQ - 10; + reg_high_2ghz_chan = TWOG_CHAN_14_IN_MHZ + 10; + reg_low_5ghz_chan = FIVEG_STARTING_FREQ - 10; + reg_high_5ghz_chan = SIXG_CHAN_233_IN_MHZ + 10; + } + if (!wlan_reg_is_6ghz_supported(psoc)) { + mlme_legacy_debug("disabling 6ghz channels"); + reg_high_5ghz_chan = FIVEG_CHAN_177_IN_MHZ + 10; + } + mlme_legacy_debug("%d %d %d %d", reg_low_2ghz_chan, reg_high_2ghz_chan, + reg_low_5ghz_chan, reg_high_5ghz_chan); + *low_2ghz_chan = reg_low_2ghz_chan; + *high_2ghz_chan = reg_high_2ghz_chan; + *low_5ghz_chan = reg_low_5ghz_chan; + *high_5ghz_chan = reg_high_5ghz_chan; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_P2P_P2P_STA +bool +wlan_mlme_get_p2p_p2p_conc_support(struct wlan_objmgr_psoc *psoc) +{ + return wlan_psoc_nif_fw_ext_cap_get(psoc, + WLAN_SOC_EXT_P2P_P2P_CONC_SUPPORT); +} +#endif + +enum phy_ch_width mlme_get_vht_ch_width(void) +{ + enum phy_ch_width bandwidth = CH_WIDTH_INVALID; + uint32_t fw_ch_wd = wma_get_vht_ch_width(); + + if (fw_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + bandwidth = CH_WIDTH_80P80MHZ; + else if (fw_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + bandwidth = CH_WIDTH_160MHZ; + else + bandwidth = CH_WIDTH_80MHZ; + + return bandwidth; +} + +uint8_t +wlan_mlme_get_mgmt_hw_tx_retry_count(struct wlan_objmgr_psoc *psoc, + enum mlme_cfg_frame_type frm_type) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return 0; + + if (frm_type >= CFG_FRAME_TYPE_MAX) + return 0; + + return mlme_obj->cfg.gen.mgmt_hw_tx_retry_count[frm_type]; +} + +QDF_STATUS +wlan_mlme_get_tx_retry_multiplier(struct wlan_objmgr_psoc *psoc, + uint32_t *tx_retry_multiplier) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) { + *tx_retry_multiplier = + cfg_default(CFG_TX_RETRY_MULTIPLIER); + return QDF_STATUS_E_FAILURE; + } + + *tx_retry_multiplier = mlme_obj->cfg.gen.tx_retry_multiplier; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_update_chan_width_allowed(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_ALLOW_UPDATE_CHANNEL_WIDTH); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.feature_flags.update_cw_allowed; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_get_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_CHANNEL_BONDING_MODE_5GHZ); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.feature_flags.channel_bonding_mode_5ghz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_update_ratemask_params(struct wlan_objmgr_vdev *vdev, + uint8_t num_ratemask, + struct config_ratemask_params *rate_params) +{ + struct vdev_mlme_obj *vdev_mlme; + struct vdev_mlme_rate_info *rate_info; + QDF_STATUS ret; + uint8_t i = 0; + uint8_t index; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) + return QDF_STATUS_E_FAILURE; + + rate_info = &vdev_mlme->mgmt.rate_info; + while (i < num_ratemask) { + index = rate_params[i].type; + if (index >= WLAN_VDEV_RATEMASK_TYPE_MAX) { + mlme_legacy_err("Invalid ratemask type"); + ++i; + continue; + } + + if (rate_info->ratemask_params[index].lower32 != + rate_params[i].lower32 || + rate_info->ratemask_params[index].lower32_2 != + rate_params[i].lower32_2 || + rate_info->ratemask_params[index].higher32 != + rate_params[i].higher32 || + rate_info->ratemask_params[index].higher32_2 != + rate_params[i].higher32_2) { + rate_info->ratemask_params[index].lower32 = + rate_params[i].lower32; + rate_info->ratemask_params[index].higher32 = + rate_params[i].higher32; + rate_info->ratemask_params[index].lower32_2 = + rate_params[i].lower32_2; + rate_info->ratemask_params[index].higher32_2 = + rate_params[i].higher32_2; + ret = wlan_util_vdev_mlme_set_ratemask_config(vdev_mlme, + index); + if (ret != QDF_STATUS_SUCCESS) + mlme_legacy_err("ratemask config failed"); + } else { + mlme_legacy_debug("Ratemask same as configured mask"); + } + ++i; + } + return QDF_STATUS_SUCCESS; +} + +bool wlan_mlme_is_channel_valid(struct wlan_objmgr_psoc *psoc, + uint32_t chan_freq) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return wlan_roam_is_channel_valid(&mlme_obj->cfg.reg, + chan_freq); +} + +#ifdef WLAN_FEATURE_MCC_QUOTA +#define WLAN_MCC_MIN_QUOTA 10 /* in %age */ +#define WLAN_MCC_MAX_QUOTA 90 /* in %age */ +QDF_STATUS wlan_mlme_set_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota) + +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + if (!quota) + return QDF_STATUS_E_NULL_VALUE; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (quota->quota < WLAN_MCC_MIN_QUOTA) + quota->quota = WLAN_MCC_MIN_QUOTA; + else if (quota->quota > WLAN_MCC_MAX_QUOTA) + quota->quota = WLAN_MCC_MAX_QUOTA; + + mlme_obj->cfg.gen.user_mcc_quota.quota = quota->quota; + mlme_obj->cfg.gen.user_mcc_quota.op_mode = quota->op_mode; + mlme_obj->cfg.gen.user_mcc_quota.vdev_id = quota->vdev_id; + + mlme_debug("quota : %u, op_mode : %d, vdev_id : %u", + quota->quota, quota->op_mode, quota->vdev_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_mlme_get_user_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_user_mcc_quota *quota) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + if (!quota) + return QDF_STATUS_E_NULL_VALUE; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + quota->quota = mlme_obj->cfg.gen.user_mcc_quota.quota; + quota->op_mode = mlme_obj->cfg.gen.user_mcc_quota.op_mode; + quota->vdev_id = mlme_obj->cfg.gen.user_mcc_quota.vdev_id; + + return QDF_STATUS_SUCCESS; +} + +uint32_t +wlan_mlme_get_user_mcc_duty_cycle_percentage(struct wlan_objmgr_psoc *psoc) +{ + uint32_t mcc_freq, ch_freq, quota_value; + struct wlan_user_mcc_quota quota; + uint8_t operating_channel; + int status; + + quota.vdev_id = WLAN_UMAC_VDEV_ID_MAX; + quota.quota = 0; + if (QDF_IS_STATUS_ERROR(wlan_mlme_get_user_mcc_quota(psoc, "a))) { + mlme_debug("Error getting user quota set"); + return 0; + } + + if (quota.vdev_id == WLAN_UMAC_VDEV_ID_MAX || quota.quota == 0) { + mlme_debug("Invalid quota : vdev %u, quota %u", + quota.vdev_id, quota.quota); + return 0; + } + status = policy_mgr_get_chan_by_session_id(psoc, quota.vdev_id, + &ch_freq); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("Could not get vdev %u chan", quota.vdev_id); + return 0; + } + mcc_freq = policy_mgr_get_mcc_operating_channel(psoc, quota.vdev_id); + if (mcc_freq == INVALID_CHANNEL_ID) + return 0; + + operating_channel = wlan_freq_to_chan(ch_freq); + if (!operating_channel) { + mlme_debug("Primary op channel is invalid"); + return 0; + } + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector + * ****************************************************** + * |bit 31-24 | bit 23-16 | bits 15-8 |bits 7-0 | + * | Unused | Quota for | chan. # for |chan. # for| + * | | 1st chan | 1st chan. |2nd chan. | + * ****************************************************** + */ + mlme_debug("Opmode (%d) vdev (%u) channel %u and quota %u", + quota.op_mode, quota.vdev_id, + operating_channel, quota.quota); + quota_value = quota.quota; + /* Move the time quota for first channel to bits 15-8 */ + quota_value = quota_value << 8; + /* + * Store the channel number of 1st channel at bits 7-0 + * of the bit vector + */ + quota_value |= operating_channel; + + operating_channel = wlan_freq_to_chan(mcc_freq); + if (!operating_channel) { + mlme_debug("Secondary op channel is invalid"); + return 0; + } + + /* + * Now move the time quota and channel number of the + * 1st adapter to bits 23-16 and bits 15-8 of the bit + * vector, respectively. + */ + quota_value = quota_value << 8; + /* + * Set the channel number for 2nd MCC vdev at bits + * 7-0 of set_value + */ + quota_value |= operating_channel; + mlme_debug("quota value:%x", quota_value); + + return quota_value; +} +#endif /* WLAN_FEATURE_MCC_QUOTA */ + +uint8_t mlme_get_max_he_mcs_idx(enum phy_ch_width mcs_ch_width, + u_int16_t *hecap_rxmcsnssmap, + u_int16_t *hecap_txmcsnssmap) +{ + uint8_t rx_max_mcs, tx_max_mcs, max_mcs = INVALID_MCS_NSS_INDEX; + + switch (mcs_ch_width) { + case CH_WIDTH_80P80MHZ: + if (hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80] && + hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80]) { + rx_max_mcs = hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80] & 0x03; + tx_max_mcs = hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80] & 0x03; + max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs; + if (max_mcs < 0x03) + max_mcs = 7 + 2 * max_mcs; + } + fallthrough; + case CH_WIDTH_160MHZ: + if (hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160] && + hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160]) { + rx_max_mcs = hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160] & 0x03; + tx_max_mcs = hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160] & 0x03; + max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs; + if (max_mcs < 0x03) + max_mcs = 7 + 2 * max_mcs; + } + fallthrough; + default: + if (hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80] && + hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80]) { + rx_max_mcs = hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80] & 0x03; + tx_max_mcs = hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80] & 0x03; + max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs; + if (max_mcs < 0x03) + max_mcs = 7 + 2 * max_mcs; + } + } + + return max_mcs; +} + +uint8_t mlme_get_max_vht_mcs_idx(u_int16_t rx_vht_mcs_map, + u_int16_t tx_vht_mcs_map) +{ + uint8_t rx_max_mcs, tx_max_mcs, max_mcs = INVALID_MCS_NSS_INDEX; + + if (rx_vht_mcs_map && tx_vht_mcs_map) { + rx_max_mcs = rx_vht_mcs_map & 0x03; + tx_max_mcs = tx_vht_mcs_map & 0x03; + max_mcs = rx_max_mcs < tx_max_mcs ? rx_max_mcs : tx_max_mcs; + if (max_mcs < 0x03) + return 7 + max_mcs; + } + + return max_mcs; +} + +#ifdef WLAN_FEATURE_SON +QDF_STATUS mlme_save_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + uint8_t max_mcs_idx) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev) { + mlme_legacy_err("invalid vdev"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->max_mcs_index = max_mcs_idx; + + return QDF_STATUS_SUCCESS; +} + +uint8_t mlme_get_vdev_max_mcs_idx(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev) { + mlme_legacy_err("invalid vdev"); + return INVALID_MCS_NSS_INDEX; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return INVALID_MCS_NSS_INDEX; + } + + return mlme_priv->max_mcs_index; +} +#endif /* WLAN_FEATURE_SON */ + +void wlan_mlme_get_safe_mode_enable(struct wlan_objmgr_psoc *psoc, + bool *safe_mode_enable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("invalid mlme obj"); + *safe_mode_enable = false; + return; + } + + *safe_mode_enable = mlme_obj->cfg.gen.safe_mode_enable; +} + +void wlan_mlme_set_safe_mode_enable(struct wlan_objmgr_psoc *psoc, + bool safe_mode_enable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("invalid mlme obj"); + return; + } + + mlme_obj->cfg.gen.safe_mode_enable = safe_mode_enable; +} + +uint32_t wlan_mlme_get_6g_ap_power_type(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *mlme_obj; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + + if (!mlme_obj) { + mlme_legacy_err("vdev component object is NULL"); + return REG_MAX_AP_TYPE; + } + + return mlme_obj->reg_tpc_obj.power_type_6g; +} + +QDF_STATUS wlan_connect_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + wlan_cm_id cm_id, QDF_STATUS status) +{ + return wlan_cm_handle_hw_mode_change_resp(pdev, vdev_id, cm_id, + status); +} + +enum phy_ch_width +wlan_mlme_get_ch_width_from_phymode(enum wlan_phymode phy_mode) +{ + enum phy_ch_width ch_width; + + if (IS_WLAN_PHYMODE_320MHZ(phy_mode)) + ch_width = CH_WIDTH_320MHZ; + else if (IS_WLAN_PHYMODE_160MHZ(phy_mode)) + ch_width = CH_WIDTH_160MHZ; + else if (IS_WLAN_PHYMODE_80MHZ(phy_mode)) + ch_width = CH_WIDTH_80MHZ; + else if (IS_WLAN_PHYMODE_40MHZ(phy_mode)) + ch_width = CH_WIDTH_40MHZ; + else + ch_width = CH_WIDTH_20MHZ; + + mlme_legacy_debug("phymode: %d, ch_width: %d ", phy_mode, ch_width); + + return ch_width; +} + +enum phy_ch_width +wlan_mlme_get_peer_ch_width(struct wlan_objmgr_psoc *psoc, uint8_t *mac) +{ + enum wlan_phymode phy_mode; + QDF_STATUS status; + + status = mlme_get_peer_phymode(psoc, mac, &phy_mode); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_legacy_err("failed to fetch phy_mode status: %d for mac: " QDF_MAC_ADDR_FMT, + status, QDF_MAC_ADDR_REF(mac)); + return CH_WIDTH_20MHZ; + } + + return wlan_mlme_get_ch_width_from_phymode(phy_mode); +} + +#ifdef FEATURE_SET + +/** + * wlan_mlme_get_latency_enable() - get wlm latency cfg value + * @psoc: psoc context + * @value: Pointer in which wlam latency cfg value needs to be filled + * + * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_INVAL on failure + */ +static QDF_STATUS +wlan_mlme_get_latency_enable(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.wlm_config.latency_enable; + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_ADAPTIVE_11R +/** + * wlan_mlme_get_adaptive11r_enabled() - get adaptive 11r cfg value + * @psoc: psoc context + * @val: Pointer in which adaptive 11r cfg value needs to be filled + * + * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_INVAL on failure + */ +static QDF_STATUS +wlan_mlme_get_adaptive11r_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_ADAPTIVE_11R); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.enable_adaptive_11r; + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +wlan_mlme_get_adaptive11r_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(WLAN_FEATURE_P2P_P2P_STA) && \ + !defined(WLAN_FEATURE_NO_P2P_CONCURRENCY) +static bool +wlan_mlme_get_p2p_p2p_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_p2p_p2p_host_conc_support(void) +{ + return false; +} +#endif + +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY +static bool +wlan_mlme_get_sta_sap_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_sap_host_conc_support(void) +{ + return false; +} +#endif + +#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY +static bool +wlan_mlme_get_sta_nan_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_nan_host_conc_support(void) +{ + return false; +} +#endif + +#ifdef FEATURE_WLAN_TDLS +static bool +wlan_mlme_get_sta_tdls_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_tdls_host_conc_support(void) +{ + return false; +} +#endif + +#if !defined(WLAN_FEATURE_NO_STA_SAP_CONCURRENCY) && \ + (!defined(WLAN_FEATURE_NO_P2P_CONCURRENCY) || \ + defined(WLAN_FEATURE_STA_SAP_P2P_CONCURRENCY)) +static bool +wlan_mlme_get_sta_sap_p2p_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_sap_p2p_host_conc_support(void) +{ + return false; +} +#endif + +#if defined(FEATURE_WLAN_TDLS) +static bool +wlan_mlme_get_sta_p2p_tdls_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_p2p_tdls_host_conc_support(void) +{ + return false; +} +#endif + +#if defined(FEATURE_WLAN_TDLS) && !defined(WLAN_FEATURE_NO_STA_SAP_CONCURRENCY) +static bool +wlan_mlme_get_sta_sap_tdls_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_sap_tdls_host_conc_support(void) +{ + return false; +} +#endif + +#if defined(FEATURE_WLAN_TDLS) && \ + !defined(WLAN_FEATURE_NO_STA_SAP_CONCURRENCY) && \ + (!defined(WLAN_FEATURE_NO_P2P_CONCURRENCY) || \ + defined(WLAN_FEATURE_STA_SAP_P2P_CONCURRENCY)) + +static bool +wlan_mlme_get_sta_sap_p2p_tdls_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_sap_p2p_tdls_host_conc_support(void) +{ + return false; +} +#endif + +#if defined(FEATURE_WLAN_TDLS) && defined(WLAN_FEATURE_P2P_P2P_STA) && \ + !defined(WLAN_FEATURE_NO_P2P_CONCURRENCY) +static bool +wlan_mlme_get_sta_p2p_p2p_tdls_host_conc_support(void) +{ + return true; +} +#else +static bool +wlan_mlme_get_sta_p2p_p2p_tdls_host_conc_support(void) +{ + return false; +} +#endif + +/** + * wlan_mlme_set_iface_combinations() - Set interface combinations + * @mlme_feature_set: Pointer to wlan_mlme_features + * + * Return: None + */ +static void +wlan_mlme_set_iface_combinations(struct wlan_mlme_features *mlme_feature_set) +{ + mlme_feature_set->iface_combinations = 0; + mlme_feature_set->iface_combinations |= MLME_IFACE_STA_P2P_SUPPORT; + if (wlan_mlme_get_sta_sap_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_SAP_SUPPORT; + if (wlan_mlme_get_sta_nan_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_NAN_SUPPORT; + if (wlan_mlme_get_sta_tdls_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_TDLS_SUPPORT; + if (wlan_mlme_get_p2p_p2p_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_DUAL_P2P_SUPPORT; + if (wlan_mlme_get_sta_sap_p2p_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_SAP_P2P_SUPPORT; + if (wlan_mlme_get_sta_p2p_tdls_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_P2P_TDLS_SUPPORT; + if (wlan_mlme_get_sta_sap_tdls_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_SAP_TDLS_SUPPORT; + if (wlan_mlme_get_sta_sap_p2p_tdls_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_SAP_P2P_TDLS_SUPPORT; + if (wlan_mlme_get_sta_p2p_p2p_tdls_host_conc_support()) + mlme_feature_set->iface_combinations |= + MLME_IFACE_STA_P2P_P2P_TDLS_SUPPORT; + mlme_debug("iface combinations = %x", + mlme_feature_set->iface_combinations); +} + +void wlan_mlme_get_feature_info(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_features *mlme_feature_set) +{ + uint32_t roam_triggers; + int sap_max_num_clients = 0; + bool is_enable_idle_roam = false, is_bss_load_enabled = false; + + wlan_mlme_get_latency_enable(psoc, + &mlme_feature_set->enable_wifi_optimizer); + wlan_mlme_get_sap_max_peers(psoc, &sap_max_num_clients); + mlme_feature_set->sap_max_num_clients = sap_max_num_clients; + mlme_feature_set->vendor_req_1_version = + WMI_HOST_VENDOR1_REQ1_VERSION_4_00; + roam_triggers = wlan_mlme_get_roaming_triggers(psoc); + + wlan_mlme_get_bss_load_enabled(psoc, &is_bss_load_enabled); + mlme_feature_set->roaming_high_cu_roam_trigger = + (roam_triggers & BIT(ROAM_TRIGGER_REASON_BSS_LOAD)) && + is_bss_load_enabled; + + mlme_feature_set->roaming_emergency_trigger = + roam_triggers & BIT(ROAM_TRIGGER_REASON_FORCED); + mlme_feature_set->roaming_btm_trihgger = + roam_triggers & BIT(ROAM_TRIGGER_REASON_BTM); + + wlan_mlme_get_enable_idle_roam(psoc, &is_enable_idle_roam); + mlme_feature_set->roaming_idle_trigger = + (roam_triggers & BIT(ROAM_TRIGGER_REASON_IDLE)) && + is_enable_idle_roam; + + mlme_feature_set->roaming_wtc_trigger = + roam_triggers & BIT(ROAM_TRIGGER_REASON_WTC_BTM); + mlme_feature_set->roaming_btcoex_trigger = + roam_triggers & BIT(ROAM_TRIGGER_REASON_BTC); + mlme_feature_set->roaming_btw_wpa_wpa2 = true; + mlme_feature_set->roaming_manage_chan_list_api = true; + + wlan_mlme_get_adaptive11r_enabled( + psoc, + &mlme_feature_set->roaming_adaptive_11r); + mlme_feature_set->roaming_ctrl_api_get_set = true; + mlme_feature_set->roaming_ctrl_api_reassoc = true; + mlme_feature_set->roaming_ctrl_get_cu = true; + + mlme_feature_set->vendor_req_2_version = + WMI_HOST_VENDOR1_REQ2_VERSION_3_50; + wlan_mlme_set_iface_combinations(mlme_feature_set); + wlan_mlme_get_vht_enable2x2(psoc, &mlme_feature_set->enable2x2); +} +#endif + +void wlan_mlme_chan_stats_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + bool success = false; + + if (!util_is_scan_completed(event, &success)) + return; + + mlme_send_scan_done_complete_cb(event->vdev_id); +} + +static QDF_STATUS +wlan_mlme_update_vdev_chwidth_with_notify(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, + wmi_host_channel_width ch_width) +{ + struct vdev_mlme_obj *vdev_mlme; + struct vdev_set_params param = {0}; + QDF_STATUS status; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) + return QDF_STATUS_E_FAILURE; + + param.param_id = wmi_vdev_param_chwidth_with_notify; + param.vdev_id = vdev_id; + param.param_value = ch_width; + status = tgt_vdev_mgr_set_param_send(vdev_mlme, ¶m); + policy_mgr_handle_ml_sta_link_on_traffic_type_change(psoc, vdev); + + return status; +} + +#ifdef WLAN_FEATURE_11BE +static +void wlan_mlme_set_puncture(struct wlan_channel *des_chan, + uint16_t puncture_bitmap) +{ + des_chan->puncture_bitmap = puncture_bitmap; +} +#else +static +void wlan_mlme_set_puncture(struct wlan_channel *des_chan, + uint16_t puncture_bitmap) +{ +} +#endif + +static QDF_STATUS wlan_mlme_update_ch_width(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, + enum phy_ch_width ch_width, + uint16_t puncture_bitmap, + qdf_freq_t sec_2g_freq) +{ + struct wlan_channel *des_chan; + struct wlan_channel *bss_chan; + uint16_t curr_op_freq; + struct ch_params ch_params = {0}; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) + return QDF_STATUS_E_FAILURE; + + bss_chan = wlan_vdev_mlme_get_bss_chan(vdev); + if (!bss_chan) + return QDF_STATUS_E_FAILURE; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("vdev %d: Pdev is NULL", vdev_id); + return QDF_STATUS_E_INVAL; + } + + ch_params.ch_width = ch_width; + curr_op_freq = des_chan->ch_freq; + + wlan_reg_set_channel_params_for_pwrmode(pdev, curr_op_freq, + sec_2g_freq, &ch_params, + REG_CURRENT_PWR_MODE); + + des_chan->ch_width = ch_width; + des_chan->ch_freq_seg1 = ch_params.center_freq_seg0; + des_chan->ch_freq_seg2 = ch_params.center_freq_seg1; + des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0; + des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1; + wlan_mlme_set_puncture(des_chan, puncture_bitmap); + + status = wlan_update_peer_phy_mode(des_chan, vdev); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to update phymode"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel)); + + mlme_legacy_debug("vdev id %d freq %d seg0 %d seg1 %d ch_width %d mhz seg0 %d mhz seg1 %d", + vdev_id, curr_op_freq, ch_params.center_freq_seg0, + ch_params.center_freq_seg1, ch_params.ch_width, + ch_params.mhz_freq_seg0, ch_params.mhz_freq_seg1); + + return QDF_STATUS_SUCCESS; +} + +static uint32_t +wlan_mlme_get_vht_rate_flags(enum phy_ch_width ch_width) +{ + uint32_t rate_flags = 0; + + if (ch_width == CH_WIDTH_80P80MHZ || ch_width == CH_WIDTH_160MHZ) + rate_flags |= TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 | + TX_RATE_VHT20; + if (ch_width == CH_WIDTH_80MHZ) + rate_flags |= TX_RATE_VHT80 | TX_RATE_VHT40 | TX_RATE_VHT20; + else if (ch_width) + rate_flags |= TX_RATE_VHT40 | TX_RATE_VHT20; + else + rate_flags |= TX_RATE_VHT20; + return rate_flags; +} + +static uint32_t wlan_mlme_get_ht_rate_flags(enum phy_ch_width ch_width) +{ + uint32_t rate_flags = 0; + + if (ch_width) + rate_flags |= TX_RATE_HT40 | TX_RATE_HT20; + else + rate_flags |= TX_RATE_HT20; + + return rate_flags; +} + +#ifdef WLAN_FEATURE_11BE +static uint32_t +wlan_mlme_get_eht_rate_flags(enum phy_ch_width ch_width) +{ + uint32_t rate_flags = 0; + + if (ch_width == CH_WIDTH_320MHZ) + rate_flags |= TX_RATE_EHT320 | TX_RATE_EHT160 | + TX_RATE_EHT80 | TX_RATE_EHT40 | TX_RATE_EHT20; + else if (ch_width == CH_WIDTH_160MHZ || ch_width == CH_WIDTH_80P80MHZ) + rate_flags |= TX_RATE_EHT160 | TX_RATE_EHT80 | TX_RATE_EHT40 | + TX_RATE_EHT20; + else if (ch_width == CH_WIDTH_80MHZ) + rate_flags |= TX_RATE_EHT80 | TX_RATE_EHT40 | TX_RATE_EHT20; + else if (ch_width) + rate_flags |= TX_RATE_EHT40 | TX_RATE_EHT20; + else + rate_flags |= TX_RATE_EHT20; + + return rate_flags; +} + +static QDF_STATUS +wlan_mlme_set_bss_rate_flags_eht(uint32_t *rate_flags, uint8_t eht_present, + enum phy_ch_width ch_width) +{ + if (!eht_present) + return QDF_STATUS_E_NOSUPPORT; + + *rate_flags |= wlan_mlme_get_eht_rate_flags(ch_width); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +wlan_mlme_set_bss_rate_flags_eht(uint32_t *rate_flags, uint8_t eht_present, + enum phy_ch_width ch_width) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_11AX +static uint32_t wlan_mlme_get_he_rate_flags(enum phy_ch_width ch_width) +{ + uint32_t rate_flags = 0; + + if (ch_width == CH_WIDTH_160MHZ || + ch_width == CH_WIDTH_80P80MHZ) + rate_flags |= TX_RATE_HE160 | TX_RATE_HE80 | TX_RATE_HE40 | + TX_RATE_HE20; + else if (ch_width == CH_WIDTH_80MHZ) + rate_flags |= TX_RATE_HE80 | TX_RATE_HE40 | TX_RATE_HE20; + else if (ch_width) + rate_flags |= TX_RATE_HE40 | TX_RATE_HE20; + else + rate_flags |= TX_RATE_HE20; + + return rate_flags; +} + +static QDF_STATUS wlan_mlme_set_bss_rate_flags_he(uint32_t *rate_flags, + uint8_t he_present, + enum phy_ch_width ch_width) +{ + if (!he_present) + return QDF_STATUS_E_NOSUPPORT; + + *rate_flags |= wlan_mlme_get_he_rate_flags(ch_width); + + return QDF_STATUS_SUCCESS; +} + +#else +static inline QDF_STATUS +wlan_mlme_set_bss_rate_flags_he(uint32_t *rate_flags, + uint8_t he_present, + enum phy_ch_width ch_width) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +static QDF_STATUS +wlan_mlme_cp_stats_set_rate_flags(struct wlan_objmgr_vdev *vdev, + uint32_t flags) +{ + struct vdev_mc_cp_stats *vdev_mc_stats; + struct vdev_cp_stats *vdev_cp_stats_priv; + + vdev_cp_stats_priv = wlan_cp_stats_get_vdev_stats_obj(vdev); + if (!vdev_cp_stats_priv) { + cp_stats_err("vdev cp stats object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_cp_stats_vdev_obj_lock(vdev_cp_stats_priv); + vdev_mc_stats = vdev_cp_stats_priv->vdev_stats; + vdev_mc_stats->tx_rate_flags = flags; + wlan_cp_stats_vdev_obj_unlock(vdev_cp_stats_priv); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum phy_ch_width cw, uint8_t eht_present, + uint8_t he_present, uint8_t vht_present, + uint8_t ht_present) +{ + uint32_t *rate_flags; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!eht_present && !he_present && !vht_present && !ht_present) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + mlme_debug("vdev: %d vdev not found", vdev_id); + return QDF_STATUS_E_INVAL; + } + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_debug("vdev: %d mlme obj not found", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return QDF_STATUS_E_INVAL; + } + + rate_flags = &vdev_mlme->mgmt.rate_info.rate_flags; + *rate_flags = 0; + + status = wlan_mlme_set_bss_rate_flags_eht(rate_flags, eht_present, cw); + if (QDF_IS_STATUS_ERROR(status)) { + status = wlan_mlme_set_bss_rate_flags_he(rate_flags, + he_present, cw); + if (QDF_IS_STATUS_ERROR(status)) { + if (vht_present) + *rate_flags = wlan_mlme_get_vht_rate_flags(cw); + else if (ht_present) + *rate_flags |= wlan_mlme_get_ht_rate_flags(cw); + } + } + + mlme_debug("vdev:%d, eht:%u, he:%u, vht:%u, ht:%u, flag:%x, cw:%d", + vdev_id, eht_present, he_present, vht_present, ht_present, + *rate_flags, cw); + + status = wlan_mlme_cp_stats_set_rate_flags(vdev, *rate_flags); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return status; +} + +QDF_STATUS +wlan_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, + enum phy_ch_width ch_width) +{ + QDF_STATUS status; + wmi_host_channel_width wmi_chan_width; + enum phy_ch_width associated_ch_width, omn_ie_ch_width; + struct wlan_channel *des_chan; + struct mlme_legacy_priv *mlme_priv; + qdf_freq_t sec_2g_freq = 0; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_INVAL; + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) + return QDF_STATUS_E_INVAL; + + omn_ie_ch_width = + mlme_priv->connect_info.assoc_chan_info.omn_ie_ch_width; + if (omn_ie_ch_width != CH_WIDTH_INVALID && ch_width > omn_ie_ch_width) { + mlme_debug("vdev %d: Invalid new chwidth:%d, omn_ie_cw:%d", + vdev_id, ch_width, omn_ie_ch_width); + return QDF_STATUS_E_INVAL; + } + + associated_ch_width = + mlme_priv->connect_info.assoc_chan_info.assoc_ch_width; + if (associated_ch_width == CH_WIDTH_INVALID || + ch_width > associated_ch_width) { + mlme_debug("vdev %d: Invalid new chwidth:%d, assoc ch_width:%d", + vdev_id, ch_width, associated_ch_width); + return QDF_STATUS_E_INVAL; + } + + if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq)) { + if (ch_width == CH_WIDTH_40MHZ && + mlme_priv->connect_info.assoc_chan_info.sec_2g_freq) { + sec_2g_freq = + mlme_priv->connect_info.assoc_chan_info.sec_2g_freq; + } else if (ch_width != CH_WIDTH_20MHZ) { + mlme_debug("vdev %d: CW:%d update not supported for freq:%d sec_2g_freq %d", + vdev_id, ch_width, des_chan->ch_freq, + mlme_priv->connect_info.assoc_chan_info.sec_2g_freq); + return QDF_STATUS_E_NOSUPPORT; + } + } + + /* update ch width to internal host structure */ + status = wlan_mlme_update_ch_width(vdev, vdev_id, ch_width, 0, + sec_2g_freq); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("vdev %d: Failed to update CW:%d to host, status:%d", + vdev_id, ch_width, status); + return status; + } + + wmi_chan_width = target_if_phy_ch_width_to_wmi_chan_width(ch_width); + + /* update ch width to fw */ + status = wlan_mlme_update_vdev_chwidth_with_notify(psoc, vdev, vdev_id, + wmi_chan_width); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("vdev %d: Failed to update CW:%d to fw, status:%d", + vdev_id, ch_width, status); + + return status; +} + +enum phy_ch_width +wlan_mlme_convert_vht_op_bw_to_phy_ch_width(uint8_t channel_width, + uint8_t chan_id, + uint8_t ccfs0, + uint8_t ccfs1) +{ + /** channel_width in vht op from 802.11-2020 + * Set to 0 for 20 MHz or 40 MHz BSS bandwidth. + * Set to 1 for 80 MHz, 160 MHz or 80+80 MHz BSS + * bandwidth. + * Set to 2 for 160 MHz BSS bandwidth (deprecated). + * Set to 3 for noncontiguous 80+80 MHz BSS + * bandwidth (deprecated). + * Values in the range 4 to 255 are reserved + * + * 80+80 not supported by MCC platform, so downgrade to 80 + */ + enum phy_ch_width phy_bw = CH_WIDTH_20MHZ; + + if (channel_width == WLAN_VHTOP_CHWIDTH_2040) { + phy_bw = CH_WIDTH_20MHZ; + if (abs(ccfs0 - chan_id) == 2) + phy_bw = CH_WIDTH_40MHZ; + } else if (channel_width == WLAN_VHTOP_CHWIDTH_80) { + if (ccfs1 && (abs(ccfs1 - ccfs0) == 8)) + phy_bw = CH_WIDTH_160MHZ; + else + phy_bw = CH_WIDTH_80MHZ; + } else if (channel_width == WLAN_VHTOP_CHWIDTH_160) { + phy_bw = CH_WIDTH_160MHZ; + } else if (channel_width == WLAN_VHTOP_CHWIDTH_80_80) { + phy_bw = WLAN_VHTOP_CHWIDTH_80; + } + + return phy_bw; +} + +enum phy_ch_width +wlan_mlme_convert_he_6ghz_op_bw_to_phy_ch_width(uint8_t channel_width, + uint8_t chan_id, + uint8_t ccfs0, + uint8_t ccfs1) +{ + enum phy_ch_width phy_bw = CH_WIDTH_20MHZ; + + if (channel_width == WLAN_HE_6GHZ_CHWIDTH_20) { + phy_bw = CH_WIDTH_20MHZ; + } else if (channel_width == WLAN_HE_6GHZ_CHWIDTH_40) { + phy_bw = CH_WIDTH_40MHZ; + } else if (channel_width == WLAN_HE_6GHZ_CHWIDTH_80) { + phy_bw = CH_WIDTH_80MHZ; + } else if (channel_width == WLAN_HE_6GHZ_CHWIDTH_160_80_80) { + phy_bw = CH_WIDTH_160MHZ; + /* 80+80 not supported */ + if (ccfs1 && abs(ccfs0 - ccfs1) > 8) + phy_bw = CH_WIDTH_80MHZ; + } + + return phy_bw; +} + +void +wlan_mlme_set_edca_pifs_param(struct wlan_edca_pifs_param_ie *ep, + enum host_edca_param_type type) +{ + ep->edca_param_type = type; + + if (type == HOST_EDCA_PARAM_TYPE_AGGRESSIVE) { + ep->edca_pifs_param.eparam.acvo_aifsn = CFG_EDCA_PARAM_AIFSN; + ep->edca_pifs_param.eparam.acvo_acm = CFG_EDCA_PARAM_ACM; + ep->edca_pifs_param.eparam.acvo_aci = CFG_EDCA_PARAM_ACI; + ep->edca_pifs_param.eparam.acvo_cwmin = CFG_EDCA_PARAM_CWMIN; + ep->edca_pifs_param.eparam.acvo_cwmax = CFG_EDCA_PARAM_CWMAX; + ep->edca_pifs_param.eparam.acvo_txoplimit = CFG_EDCA_PARAM_TXOP; + } else if (type == HOST_EDCA_PARAM_TYPE_PIFS) { + ep->edca_pifs_param.pparam.sap_pifs_offset = + CFG_PIFS_PARAM_SAP_OFFSET; + ep->edca_pifs_param.pparam.leb_pifs_offset = + CFG_PIFS_PARAM_LEB_OFFSET; + ep->edca_pifs_param.pparam.reb_pifs_offset = + CFG_PIFS_PARAM_REB_OFFSET; + } +} + +QDF_STATUS +wlan_mlme_stats_get_periodic_display_time(struct wlan_objmgr_psoc *psoc, + uint32_t *periodic_display_time) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *periodic_display_time = + cfg_default(CFG_PERIODIC_STATS_DISPLAY_TIME); + return QDF_STATUS_E_INVAL; + } + + *periodic_display_time = + mlme_obj->cfg.stats.stats_periodic_display_time; + + return QDF_STATUS_SUCCESS; +} + +bool +wlan_mlme_is_bcn_prot_disabled_for_sap(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_DISABLE_SAP_BCN_PROT); + + return mlme_obj->cfg.sap_cfg.disable_bcn_prot; +} + +uint8_t *wlan_mlme_get_src_addr_from_frame(struct element_info *frame) +{ + struct wlan_frame_hdr *hdr; + + if (!frame || !frame->len || frame->len < WLAN_MAC_HDR_LEN_3A) + return NULL; + + hdr = (struct wlan_frame_hdr *)frame->ptr; + + return hdr->i_addr2; +} + +bool +wlan_mlme_get_sap_ps_with_twt(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return cfg_default(CFG_SAP_PS_WITH_TWT); + + return mlme_obj->cfg.sap_cfg.sap_ps_with_twt_enable; +} + +/** + * set_omi_ch_width() - set OMI ch_bw/eht_ch_bw_ext bit value from channel width + * @ch_width: channel width + * @omi_data: Pointer to omi_data object + * + * If the channel width is 20Mhz, 40Mhz, 80Mhz, 160Mhz and 80+80Mhz ch_bw set + * to 0, 1, 2, 3 accordingly, if channel width is 320Mhz then eht_ch_bw_ext + * set to 1 + * + * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_INVAL on failure + */ +static QDF_STATUS +set_omi_ch_width(enum phy_ch_width ch_width, struct omi_ctrl_tx *omi_data) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + omi_data->ch_bw = 0; + break; + case CH_WIDTH_40MHZ: + omi_data->ch_bw = 1; + break; + case CH_WIDTH_80MHZ: + omi_data->ch_bw = 2; + break; + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + omi_data->ch_bw = 3; + break; + case CH_WIDTH_320MHZ: + omi_data->eht_ch_bw_ext = 1; + break; + default: + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_mlme_set_ul_mu_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t ulmu_disable) +{ + struct omi_ctrl_tx omi_data = {0}; + uint32_t param_val = 0; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + enum phy_ch_width ch_width; + uint8_t rx_nss, tx_nsts; + struct qdf_mac_addr macaddr = {0}; + enum wlan_phymode peer_phymode; + qdf_freq_t op_chan_freq; + qdf_freq_t freq_seg_0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_err("vdev %d: vdev is NULL", vdev_id); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto err; + } + + if (!cm_is_vdevid_connected(pdev, vdev_id)) { + mlme_err("STA is not connected, Session_id: %d", vdev_id); + status = QDF_STATUS_E_INVAL; + goto err; + } + + status = wlan_vdev_get_bss_peer_mac(vdev, &macaddr); + if (QDF_STATUS_SUCCESS != status) { + mlme_err("Failed to get bss peer mac, Err : %d", status); + goto err; + } + + status = mlme_get_peer_phymode(psoc, macaddr.bytes, &peer_phymode); + if (QDF_STATUS_SUCCESS != status) { + mlme_err("Failed to get peer phymode, Err : %d", status); + goto err; + } + + if (!(IS_WLAN_PHYMODE_HE(peer_phymode) || + IS_WLAN_PHYMODE_EHT(peer_phymode))) { + mlme_err("Invalid mode"); + status = QDF_STATUS_E_INVAL; + goto err; + } + + status = wlan_mlme_get_sta_rx_nss(psoc, vdev, &rx_nss); + if (QDF_STATUS_SUCCESS != status) { + mlme_err("Failed to get sta_rx_nss, Err : %d", status); + goto err; + } + + status = wlan_mlme_get_sta_tx_nss(psoc, vdev, &tx_nsts); + if (QDF_STATUS_SUCCESS != status) { + mlme_err("Failed to get sta_tx_nss, Err : %d", status); + goto err; + } + + status = wlan_get_op_chan_freq_info_vdev_id(pdev, vdev_id, + &op_chan_freq, + &freq_seg_0, &ch_width); + if (QDF_STATUS_SUCCESS != status) { + mlme_err("Failed to get bw, Err : %d", status); + goto err; + } + + omi_data.omi_in_vht = 0x1; + omi_data.omi_in_he = 0x1; + omi_data.a_ctrl_id = 0x1; + + status = set_omi_ch_width(ch_width, &omi_data); + if (QDF_STATUS_SUCCESS != status) { + mlme_err("Failed to set bw, Err : %d", status); + goto err; + } + + omi_data.rx_nss = rx_nss - 1; + omi_data.tx_nsts = tx_nsts - 1; + omi_data.ul_mu_dis = ulmu_disable; + omi_data.ul_mu_data_dis = 0; + + qdf_mem_copy(¶m_val, &omi_data, sizeof(omi_data)); + + mlme_debug("OMI: BW %d TxNSTS %d RxNSS %d ULMU %d OMI_VHT %d OMI_HE %d, EHT OMI: BW %d RxNSS %d TxNSS %d, param val: %08X, bssid:" QDF_MAC_ADDR_FMT, + omi_data.ch_bw, omi_data.tx_nsts, omi_data.rx_nss, + omi_data.ul_mu_dis, omi_data.omi_in_vht, omi_data.omi_in_he, + omi_data.eht_ch_bw_ext, omi_data.eht_rx_nss_ext, + omi_data.eht_tx_nss_ext, param_val, + QDF_MAC_ADDR_REF(macaddr.bytes)); + + status = wlan_util_vdev_peer_set_param_send(vdev, macaddr.bytes, + WMI_PEER_PARAM_XMIT_OMI, + param_val); + if (QDF_STATUS_SUCCESS != status) + mlme_err("set_peer_param_cmd returned %d", status); + +err: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return status; +} + +uint32_t +wlan_mlme_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate) +{ + uint32_t set_value; + + if (wma_get_fw_wlan_feat_caps(DOT11AX)) + set_value = ASSEMBLE_RATECODE_V1(preamble, nss, rate); + else + set_value = (preamble << 6) | (nss << 4) | rate; + + return set_value; +} + +QDF_STATUS +wlan_mlme_set_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width ch_width) + +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev %d legacy private object is NULL", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->mlme_ap.oper_ch_width = ch_width; + mlme_debug("SAP oper ch_width: %d, vdev %d", + mlme_priv->mlme_ap.oper_ch_width, wlan_vdev_get_id(vdev)); + + return QDF_STATUS_SUCCESS; +} + +enum phy_ch_width +wlan_mlme_get_ap_oper_ch_width(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev %d legacy private object is NULL", + wlan_vdev_get_id(vdev)); + return CH_WIDTH_INVALID; + } + + return mlme_priv->mlme_ap.oper_ch_width; +} + +QDF_STATUS +wlan_mlme_send_csa_event_status_ind(struct wlan_objmgr_vdev *vdev, + uint8_t csa_status) +{ + return wlan_mlme_send_csa_event_status_ind_cmd(vdev, csa_status); +} + +#ifdef WLAN_FEATURE_11BE +QDF_STATUS +wlan_mlme_get_bw_no_punct(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_channel *bss_chan, + enum phy_ch_width *new_ch_width) +{ + uint16_t new_punct_bitmap = 0; + enum phy_ch_width ch_width; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t country[REG_ALPHA2_LEN + 1]; + + if (!wlan_mlme_get_eht_disable_punct_in_us_lpi(psoc)) + return status; + + wlan_reg_read_current_country(psoc, country); + + if (!wlan_reg_is_6ghz_chan_freq(bss_chan->ch_freq) || + !bss_chan->puncture_bitmap || + qdf_mem_cmp(country, "US", REG_ALPHA2_LEN) || + mlme_get_best_6g_power_type(vdev) != REG_INDOOR_AP || + !IS_WLAN_PHYMODE_EHT(bss_chan->ch_phymode)) + goto err; + + ch_width = bss_chan->ch_width; + + while (ch_width != CH_WIDTH_INVALID) { + status = wlan_reg_extract_puncture_by_bw(bss_chan->ch_width, + bss_chan->puncture_bitmap, + bss_chan->ch_freq, + bss_chan->ch_cfreq2, + ch_width, + &new_punct_bitmap); + if (QDF_IS_STATUS_SUCCESS(status) && new_punct_bitmap) + ch_width = wlan_get_next_lower_bandwidth(ch_width); + else + break; + } + + if (ch_width == bss_chan->ch_width) + return QDF_STATUS_E_FAILURE; + + mlme_debug("freq %d ccfs2 %d punct 0x%x BW old %d, new %d", + bss_chan->ch_freq, bss_chan->ch_cfreq2, bss_chan->puncture_bitmap, + bss_chan->ch_width, ch_width); + + *new_ch_width = ch_width; + bss_chan->puncture_bitmap = 0; +err: + return status; +} + +QDF_STATUS +wlan_mlme_update_bw_no_punct(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum phy_ch_width new_ch_width; + struct wlan_objmgr_pdev *pdev; + + if (!wlan_mlme_get_eht_disable_punct_in_us_lpi(psoc)) + return status; + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_MLME_NB_ID); + if (!pdev) { + sme_err("pdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("VDEV not found for vdev id : %d", vdev_id); + goto rel_pdev; + } + + status = wlan_mlme_get_bw_no_punct(psoc, vdev, + wlan_vdev_mlme_get_des_chan(vdev), + &new_ch_width); + if (QDF_IS_STATUS_ERROR(status)) + goto rel_vdev; + + status = wlan_mlme_send_ch_width_update_with_notify(psoc, + vdev, + vdev_id, + new_ch_width); +rel_vdev: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +rel_pdev: + wlan_objmgr_pdev_release_ref(pdev, WLAN_MLME_NB_ID); + + return status; +} +#endif + +QDF_STATUS +wlan_mlme_is_hs_20_btm_offload_disabled(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_HS_20_BTM_OFFLOAD_DISABLE); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.hs20_btm_offload_disable; + + return QDF_STATUS_SUCCESS; +} + +void wlan_mlme_set_keepalive_period(struct wlan_objmgr_vdev *vdev, + uint16_t keep_alive_period) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->keep_alive_period = keep_alive_period; +} + +uint16_t wlan_mlme_get_keepalive_period(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return 0; + } + + return mlme_priv->keep_alive_period; +} + +void wlan_mlme_reset_sta_keepalive_period(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("invalid mlem object"); + return; + } + mlme_obj->cfg.sta.sta_keep_alive_period = + cfg_default(CFG_INFRA_STA_KEEP_ALIVE_PERIOD); + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->keep_alive_period = + cfg_default(CFG_INFRA_STA_KEEP_ALIVE_PERIOD); +} + +QDF_STATUS +wlan_mlme_get_sta_keep_alive_period(struct wlan_objmgr_psoc *psoc, + uint32_t *keep_alive_period) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *keep_alive_period = + cfg_default(CFG_INFRA_STA_KEEP_ALIVE_PERIOD); + return QDF_STATUS_E_INVAL; + } + + *keep_alive_period = mlme_obj->cfg.sta.sta_keep_alive_period; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_twt_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_twt_ucfg_api.c new file mode 100644 index 0000000000..ae7fbdaa28 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_twt_ucfg_api.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: define UCFG APIs exposed for TWT by the mlme component + */ + +#include "wlan_mlme_main.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "cfg_mlme_twt.h" +#include "wlan_mlme_twt_ucfg_api.h" + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_FEATURE_11AX) && \ + !defined(WLAN_TWT_CONV_SUPPORTED) +QDF_STATUS +ucfg_mlme_get_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_TWT_REQUESTOR); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.he_caps.dot11_he_cap.twt_request; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_requestor(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.he_caps.dot11_he_cap.twt_request = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_responder(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_TWT_RESPONDER); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.he_caps.dot11_he_cap.twt_responder; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_responder(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.he_caps.dot11_he_cap.twt_responder = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_requestor_flag(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.req_flag = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_responder_flag(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.res_flag = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_reset_twt_active_cmd(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_macaddr, + uint8_t dialog_id) +{ + mlme_set_twt_command_in_progress(psoc, peer_macaddr, dialog_id, + WLAN_TWT_NONE); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_TWT_CONGESTION_TIMEOUT); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.twt_cfg.twt_congestion_timeout; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.twt_congestion_timeout = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_enable_twt(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.is_twt_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_bcast_requestor(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + uint32_t b_req_res; + + b_req_res = cfg_default(CFG_BCAST_TWT_REQ_RESP); + *val = CFG_TWT_GET_BCAST_REQ(b_req_res); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.twt_cfg.is_bcast_requestor_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_bcast_responder(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + uint32_t b_req_res; + + b_req_res = cfg_default(CFG_BCAST_TWT_REQ_RESP); + *val = CFG_TWT_GET_BCAST_RES(b_req_res); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.twt_cfg.is_bcast_responder_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_bcast_requestor(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.is_bcast_requestor_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_bcast_responder(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.is_bcast_responder_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_nudge_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.is_twt_nudge_tgt_cap_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_mlme_get_twt_peer_bcast_capabilities(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + uint8_t peer_cap; + + peer_cap = mlme_get_twt_peer_capabilities(psoc, peer_mac); + + if (peer_cap & WLAN_TWT_CAPA_BROADCAST) + return true; + + return false; +} + +bool ucfg_mlme_get_twt_peer_responder_capabilities( + struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac) +{ + uint8_t peer_cap; + + peer_cap = mlme_get_twt_peer_capabilities(psoc, peer_mac); + + if (peer_cap & WLAN_TWT_CAPA_RESPONDER) + return true; + + return false; +} + +QDF_STATUS +ucfg_mlme_get_twt_nudge_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.twt_cfg.is_twt_nudge_tgt_cap_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_all_twt_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.is_all_twt_tgt_cap_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_all_twt_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.twt_cfg.is_all_twt_tgt_cap_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_statistics_tgt_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.is_twt_statistics_tgt_cap_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_statistics_tgt_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.twt_cfg.is_twt_statistics_tgt_cap_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.twt_cfg.twt_res_svc_cap = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_twt_res_service_cap(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.twt_cfg.twt_res_svc_cap; + + return QDF_STATUS_SUCCESS; +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c new file mode 100644 index 0000000000..66aff1d41f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c @@ -0,0 +1,2123 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define UCFG APIs exposed by the mlme component + */ + +#include "cfg_ucfg_api.h" +#include "cfg_mlme_sta.h" +#include "wlan_mlme_main.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include +#include "wlan_pdev_mlme_api.h" +#include +#include "wlan_vdev_mgr_tgt_if_tx_api.h" +#include "wlan_policy_mgr_public_struct.h" +#include "spatial_reuse_api.h" + +QDF_STATUS ucfg_mlme_global_init(void) +{ + mlme_register_mlme_ext_ops(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mlme_global_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mlme_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_legacy_err("peer create register notification failed"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_legacy_err("peer destroy register notification failed"); + return QDF_STATUS_E_FAILURE; + } + + mlme_register_mlo_ext_ops(); + return status; +} + +QDF_STATUS ucfg_mlme_deinit(void) +{ + QDF_STATUS status; + + mlme_unregister_mlo_ext_ops(); + status = wlan_objmgr_unregister_peer_destroy_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + mlme_legacy_err("unable to unregister peer destroy handle"); + + status = wlan_objmgr_unregister_peer_create_handler( + WLAN_UMAC_COMP_MLME, + mlme_peer_object_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + mlme_legacy_err("unable to unregister peer create handle"); + + return status; +} + +QDF_STATUS ucfg_mlme_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = mlme_cfg_on_psoc_enable(psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) + mlme_legacy_err("Failed to initialize MLME CFG"); + + return status; +} + +void ucfg_mlme_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + /* Clear the MLME CFG Structure */ + wlan_mlme_psoc_flush_peer_trans_history(psoc); +} + +QDF_STATUS ucfg_mlme_pdev_open(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_mlme_obj *pdev_mlme; + + pdev_mlme = wlan_pdev_mlme_get_cmpt_obj(pdev); + if (!pdev_mlme) { + mlme_legacy_err(" PDEV MLME is NULL"); + return QDF_STATUS_E_FAILURE; + } + pdev_mlme->mlme_register_ops = mlme_register_vdev_mgr_ops; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mlme_pdev_close(struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} + +void ucfg_mlme_set_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t value) +{ + wlan_mlme_set_ml_link_control_mode(psoc, vdev_id, value); +} + +void ucfg_mlme_set_bt_profile_con(struct wlan_objmgr_psoc *psoc, + bool bt_profile_con) +{ + wlan_mlme_set_bt_profile_con(psoc, bt_profile_con); +} + +uint8_t ucfg_mlme_get_ml_link_control_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return wlan_mlme_get_ml_link_control_mode(psoc, vdev_id); +} + + +/** + * ucfg_mlme_convert_power_cfg_chan_to_freq() - converts channel numbers to + * frequencies and copies the triplets to power_freq_data array + * @pdev: pointer to pdev object + * @max_length: Max length of the power chan data array + * @length: length of the data present in power_chan_data array + * @power_chan_data: Power data array from which channel numbers needs to be + * converted to frequencies + * @power_freq_data: Power data array in which the power data needs to be copied + * after conversion of channel numbers to frequencies + * + * power_data is received in the form of (first_channel_number, + * number_of_channels, max_tx_power) triplet, convert the channel numbers from + * the power_chan_data array to frequencies and copy the triplets + * (first_frequency, number_of_channels, max_tx_power) values to + * the power_freq_data array + * + * Return: Number of bytes filled in power_freq_data + */ + +static uint32_t ucfg_mlme_convert_power_cfg_chan_to_freq( + struct wlan_objmgr_pdev *pdev, + uint32_t max_length, + qdf_size_t length, + uint8_t *power_chan_data, + uint8_t *power_freq_data) +{ + uint32_t count = 0, rem_length = length, copied_length = 0, i = 0; + struct pwr_channel_info *pwr_cfg_data; + + pwr_cfg_data = qdf_mem_malloc(max_length); + if (!pwr_cfg_data) + return 0; + + mlme_legacy_debug("max_length %d length %zu", max_length, length); + while ((rem_length >= 3) && + (copied_length <= (max_length - (sizeof(struct pwr_channel_info))))) { + pwr_cfg_data[i].first_freq = wlan_reg_legacy_chan_to_freq( + pdev, + power_chan_data[count++]); + pwr_cfg_data[i].num_chan = power_chan_data[count++]; + pwr_cfg_data[i].max_tx_pwr = power_chan_data[count++]; + copied_length += sizeof(struct pwr_channel_info); + rem_length -= 3; + mlme_legacy_debug("First freq %d num channels %d max tx power %d", + pwr_cfg_data[i].first_freq, + pwr_cfg_data[i].num_chan, + pwr_cfg_data[i].max_tx_pwr); + i++; + } + + qdf_mem_zero(power_freq_data, max_length); + qdf_mem_copy(power_freq_data, pwr_cfg_data, copied_length); + qdf_mem_free(pwr_cfg_data); + return copied_length; +} + +void ucfg_mlme_cfg_chan_to_freq(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_cfg *mlme_cfg; + uint32_t converted_data_len = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_cfg = &mlme_obj->cfg; + + mlme_cfg->power.max_tx_power_24.max_len = CFG_MAX_TX_POWER_2_4_LEN; + converted_data_len = ucfg_mlme_convert_power_cfg_chan_to_freq( + pdev, + mlme_cfg->power.max_tx_power_24_chan.max_len, + mlme_cfg->power.max_tx_power_24_chan.len, + mlme_cfg->power.max_tx_power_24_chan.data, + mlme_cfg->power.max_tx_power_24.data); + if (!converted_data_len) { + mlme_legacy_err("mlme cfg power 2_4 data chan number to freq failed"); + return; + } + + mlme_cfg->power.max_tx_power_24.len = converted_data_len; + + mlme_cfg->power.max_tx_power_5.max_len = CFG_MAX_TX_POWER_5_LEN; + converted_data_len = ucfg_mlme_convert_power_cfg_chan_to_freq( + pdev, + mlme_cfg->power.max_tx_power_5_chan.max_len, + mlme_cfg->power.max_tx_power_5_chan.len, + mlme_cfg->power.max_tx_power_5_chan.data, + mlme_cfg->power.max_tx_power_5.data); + if (!converted_data_len) { + mlme_legacy_err("mlme cfg power 5 data chan number to freq failed"); + return; + } + mlme_cfg->power.max_tx_power_5.len = converted_data_len; +} + +QDF_STATUS +ucfg_mlme_get_sta_keep_alive_period(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + return wlan_mlme_get_sta_keep_alive_period(psoc, val); +} + +QDF_STATUS +ucfg_mlme_get_dfs_master_capability(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_ENABLE_DFS_MASTER_CAPABILITY); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.dfs_cfg.dfs_master_capable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_oem_6g_supported(struct wlan_objmgr_psoc *psoc, + bool *oem_6g_disable) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *oem_6g_disable = + cfg_default(CFG_OEM_SIXG_SUPPORT_DISABLE); + return QDF_STATUS_E_INVAL; + } + + *oem_6g_disable = mlme_obj->cfg.wifi_pos_cfg.oem_6g_support_disable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc, + uint32_t *fine_time_meas_cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *fine_time_meas_cap = + cfg_default(CFG_FINE_TIME_MEAS_CAPABILITY); + return QDF_STATUS_E_INVAL; + } + + *fine_time_meas_cap = mlme_obj->cfg.wifi_pos_cfg.fine_time_meas_cap; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_fine_time_meas_cap(struct wlan_objmgr_psoc *psoc, + uint32_t fine_time_meas_cap) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.wifi_pos_cfg.fine_time_meas_cap = fine_time_meas_cap; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ucfg_mlme_set_vdev_traffic_type(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, bool set, + uint8_t bit_mask) +{ + struct mlme_legacy_priv *mlme_priv; + struct vdev_mlme_obj *vdev_mlme; + struct vdev_set_params param = {0}; + enum QDF_OPMODE mode; + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + uint8_t prev_traffic_type; + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_SAP_MODE && mode != QDF_P2P_CLIENT_MODE && + mode != QDF_P2P_GO_MODE) { + mlme_legacy_debug("vdev %d: not supported for opmode %d", + vdev_id, mode); + return QDF_STATUS_E_NOSUPPORT; + } + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_legacy_err("vdev %d: bit_mask 0x%x, set %d, vdev mlme is null", + vdev_id, bit_mask, set); + return QDF_STATUS_E_FAILURE; + } + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev %d: bit_mask 0x%x, set %d, vmlme_priv is null", + vdev_id, bit_mask, set); + return QDF_STATUS_E_FAILURE; + } + prev_traffic_type = mlme_priv->vdev_traffic_type; + if (set) + mlme_priv->vdev_traffic_type |= bit_mask; + else + mlme_priv->vdev_traffic_type &= ~bit_mask; + + if (prev_traffic_type == mlme_priv->vdev_traffic_type) { + mlme_legacy_debug("vdev %d: No change in value 0x%x, set %d mask 0x%x", + vdev_id, mlme_priv->vdev_traffic_type, set, + bit_mask); + return QDF_STATUS_SUCCESS; + } + mlme_legacy_debug("vdev %d: vdev_traffic_type 0x%x (set %d with bit_mask 0x%x)", + vdev_id, mlme_priv->vdev_traffic_type, set, bit_mask); + param.param_id = wmi_vdev_param_set_traffic_config; + param.vdev_id = vdev_id; + param.param_value = mlme_priv->vdev_traffic_type; + status = tgt_vdev_mgr_set_param_send(vdev_mlme, ¶m); + policy_mgr_handle_ml_sta_link_on_traffic_type_change(psoc, vdev); + + return status; +} + +QDF_STATUS ucfg_mlme_connected_chan_stats_request(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return mlme_connected_chan_stats_request(psoc, vdev_id); +} + +bool +ucfg_mlme_is_chwidth_with_notify_supported(struct wlan_objmgr_psoc *psoc) +{ + return wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_VDEV_PARAM_CHWIDTH_WITH_NOTIFY_SUPPORT); +} + +QDF_STATUS ucfg_mlme_update_bss_rate_flags(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width ch_width, + uint8_t eht_present, + uint8_t he_present, + uint8_t vht_present, + uint8_t ht_present) +{ + return wlan_mlme_update_bss_rate_flags(psoc, vdev_id, ch_width, + eht_present, he_present, + vht_present, ht_present); +} + +QDF_STATUS +ucfg_mlme_send_ch_width_update_with_notify(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *link_vdev, + enum phy_ch_width ch_width, + uint8_t link_vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = wlan_mlme_send_ch_width_update_with_notify(psoc, link_vdev, + link_vdev_id, + ch_width); + + return status; +} + +QDF_STATUS +ucfg_mlme_set_vdev_wifi_std(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + WMI_HOST_WIFI_STANDARD wifi_std) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev %d: vdev not found", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev %d: vmlme_priv is null", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->wifi_std = wifi_std; + mlme_priv->is_user_std_set = true; + + if (wifi_std < WMI_HOST_WIFI_STANDARD_7) + wlan_vdev_mlme_set_user_dis_eht_flag(vdev, true); + else + wlan_vdev_mlme_set_user_dis_eht_flag(vdev, false); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_vdev_traffic_low_latency(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev %d: vdev not found", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + status = ucfg_mlme_set_vdev_traffic_type(psoc, vdev, set, + PM_VDEV_TRAFFIC_LOW_LATENCY); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return status; +} + +QDF_STATUS +ucfg_mlme_set_vdev_traffic_high_throughput(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_legacy_err("vdev %d: vdev not found", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + status = ucfg_mlme_set_vdev_traffic_type(psoc, vdev, set, + PM_VDEV_TRAFFIC_HIGH_TPUT); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return status; +} + +QDF_STATUS +ucfg_mlme_get_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc, + bool *dfs_disable_channel_switch) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *dfs_disable_channel_switch = + cfg_default(CFG_DISABLE_DFS_CH_SWITCH); + return QDF_STATUS_E_INVAL; + } + + *dfs_disable_channel_switch = + mlme_obj->cfg.dfs_cfg.dfs_disable_channel_switch; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_dfs_disable_channel_switch(struct wlan_objmgr_psoc *psoc, + bool dfs_disable_channel_switch) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + return QDF_STATUS_E_INVAL; + } + + mlme_obj->cfg.dfs_cfg.dfs_disable_channel_switch = + dfs_disable_channel_switch; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc, + bool *dfs_ignore_cac) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *dfs_ignore_cac = cfg_default(CFG_IGNORE_CAC); + return QDF_STATUS_E_INVAL; + } + + *dfs_ignore_cac = mlme_obj->cfg.dfs_cfg.dfs_ignore_cac; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_dfs_ignore_cac(struct wlan_objmgr_psoc *psoc, + bool dfs_ignore_cac) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.dfs_cfg.dfs_ignore_cac = dfs_ignore_cac; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *sap_tx_leakage_threshold) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *sap_tx_leakage_threshold = + cfg_default(CFG_SAP_TX_LEAKAGE_THRESHOLD); + return QDF_STATUS_E_INVAL; + } + + *sap_tx_leakage_threshold = + mlme_obj->cfg.dfs_cfg.sap_tx_leakage_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_sap_tx_leakage_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t sap_tx_leakage_threshold) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.dfs_cfg.sap_tx_leakage_threshold = + sap_tx_leakage_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_dfs_pri_multiplier(struct wlan_objmgr_psoc *psoc, + uint32_t *dfs_pri_multiplier) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *dfs_pri_multiplier = + cfg_default(CFG_DFS_RADAR_PRI_MULTIPLIER); + return QDF_STATUS_E_INVAL; + } + + *dfs_pri_multiplier = + mlme_obj->cfg.dfs_cfg.dfs_pri_multiplier; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_dfs_pri_multiplier(struct wlan_objmgr_psoc *psoc, + uint32_t dfs_pri_multiplier) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.dfs_cfg.dfs_pri_multiplier = + dfs_pri_multiplier; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_dfs_filter_offload(struct wlan_objmgr_psoc *psoc, + bool *dfs_filter_offload) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *dfs_filter_offload = + cfg_default(CFG_ENABLE_DFS_PHYERR_FILTEROFFLOAD); + return QDF_STATUS_E_INVAL; + } + + *dfs_filter_offload = mlme_obj->cfg.dfs_cfg.dfs_filter_offload; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_dfs_filter_offload(struct wlan_objmgr_psoc *psoc, + bool dfs_filter_offload) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.dfs_cfg.dfs_filter_offload = dfs_filter_offload; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_pmkid_modes(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_PMKID_MODES); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.sta.pmkid_modes; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_pmkid_modes(struct wlan_objmgr_psoc *psoc, + uint32_t val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.sta.pmkid_modes = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_dot11p_mode(struct wlan_objmgr_psoc *psoc, + enum dot11p_mode *out_mode) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *out_mode = cfg_default(CFG_DOT11P_MODE); + return QDF_STATUS_E_INVAL; + } + + *out_mode = mlme_obj->cfg.sta.dot11p_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_go_cts2self_for_sta(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_ENABLE_GO_CTS2SELF_FOR_STA); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.sta.enable_go_cts2self_for_sta; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_qcn_ie_support(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_QCN_IE_SUPPORT); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.sta.qcn_ie_support; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_tgt_gtx_usr_cfg(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_TGT_GTX_USR_CFG); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.sta.tgt_gtx_usr_cfg; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_is_override_ht20_40_24g(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_OBSS_HT40_OVERRIDE_HT40_20_24GHZ); + return QDF_STATUS_E_INVAL; + } + *val = mlme_obj->cfg.obss_ht40.is_override_ht20_40_24g; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +ucfg_mlme_get_roam_disable_config(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_STA_DISABLE_ROAM); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.sta_roam_disable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + return wlan_mlme_get_roaming_offload(psoc, val); +} + +QDF_STATUS +ucfg_mlme_set_roaming_offload(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.lfr3_roaming_offload = val; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +ucfg_mlme_is_mawc_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_MAWC_FEATURE_ENABLED); + return QDF_STATUS_E_INVAL; + } + *val = mlme_obj->cfg.lfr.mawc_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_mawc_enabled(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.mawc_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_is_fast_transition_enabled(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.fast_transition_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_fast_transition_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.fast_transition_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_ADAPTIVE_11R +QDF_STATUS +ucfg_mlme_set_tgt_adaptive_11r_cap(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.tgt_adaptive_11r_cap = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_adaptive11r_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_ADAPTIVE_11R); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.enable_adaptive_11r; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +ucfg_mlme_is_roam_scan_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ROAM_SCAN_OFFLOAD_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_scan_offload_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_roam_scan_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.roam_scan_offload_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_neighbor_scan_max_chan_time(struct wlan_objmgr_psoc *psoc, + uint16_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.neighbor_scan_max_chan_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_neighbor_scan_min_chan_time(struct wlan_objmgr_psoc *psoc, + uint16_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.neighbor_scan_min_chan_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_delay_before_vdev_stop(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_DELAY_BEFORE_VDEV_STOP); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.delay_before_vdev_stop; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_roam_bmiss_final_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + return wlan_mlme_get_roam_bmiss_final_bcnt(psoc, val); +} + +bool +ucfg_mlme_validate_roam_bmiss_final_bcnt(uint32_t bmiss_final_bcnt) +{ + bool is_valid = true; + uint32_t min, max; + + if (!cfg_in_range(CFG_LFR_ROAM_BMISS_FINAL_BCNT, + bmiss_final_bcnt)) { + min = (cfg_min(CFG_LFR_ROAM_BMISS_FINAL_BCNT)); + max = (cfg_max(CFG_LFR_ROAM_BMISS_FINAL_BCNT)); + mlme_legacy_err("bmiss final bcnt %d is out of range " + "(Min: %d Max: %d)", + bmiss_final_bcnt, min, max); + is_valid = false; + } + + return is_valid; +} + +bool ucfg_mlme_get_dual_sta_roaming_enabled(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_dual_sta_roaming_enabled(psoc); +} + +QDF_STATUS +ucfg_mlme_get_roam_bmiss_first_bcnt(struct wlan_objmgr_psoc *psoc, + uint8_t *val) +{ + return wlan_mlme_get_roam_bmiss_first_bcnt(psoc, val); +} + +QDF_STATUS +ucfg_mlme_is_lfr_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_FEATURE_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.lfr_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_lfr_enabled(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.lfr_enabled = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_is_roam_prefer_5ghz(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ROAM_PREFER_5GHZ); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_prefer_5ghz; + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_mlme_is_roam_intra_band(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return true; + + return mlme_obj->cfg.lfr.roam_intra_band; +} + +QDF_STATUS +ucfg_mlme_set_roam_intra_band(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.roam_intra_band = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_home_away_time(struct wlan_objmgr_psoc *psoc, uint16_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.roam_scan_home_away_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_fast_roam_in_concurrency_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.lfr.enable_fast_roam_in_concurrency = val; + + return QDF_STATUS_SUCCESS; +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +bool ucfg_mlme_get_wlm_multi_client_ll_caps(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_wlm_multi_client_ll_caps(psoc); +} + +QDF_STATUS +ucfg_mlme_cfg_get_multi_client_ll_ini_support(struct wlan_objmgr_psoc *psoc, + bool *multi_client_ll_support) +{ + return mlme_get_cfg_multi_client_ll_ini_support(psoc, + multi_client_ll_support); +} +#endif + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +bool ucfg_mlme_get_vendor_handoff_control_caps(struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_vendor_handoff_control_caps(psoc); +} +#endif + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS +ucfg_mlme_is_ese_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.lfr.ese_enabled; + + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_ESE */ + +QDF_STATUS +ucfg_mlme_get_supported_mcs_set(struct wlan_objmgr_psoc *psoc, + uint8_t *buf, qdf_size_t *len) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + return wlan_mlme_get_cfg_str(buf, + &mlme_obj->cfg.rates.supported_mcs_set, + len); +} + +QDF_STATUS +ucfg_mlme_set_supported_mcs_set(struct wlan_objmgr_psoc *psoc, + uint8_t *buf, qdf_size_t len) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + return wlan_mlme_set_cfg_str(buf, + &mlme_obj->cfg.rates.supported_mcs_set, + len); +} + +QDF_STATUS +ucfg_mlme_get_current_mcs_set(struct wlan_objmgr_psoc *psoc, + uint8_t *buf, qdf_size_t *len) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + return wlan_mlme_get_cfg_str(buf, + &mlme_obj->cfg.rates.current_mcs_set, + len); +} + +QDF_STATUS +ucfg_mlme_get_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *wmi_wq_watchdog_timeout) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *wmi_wq_watchdog_timeout = cfg_default(CFG_WMI_WQ_WATCHDOG); + return QDF_STATUS_E_INVAL; + } + + *wmi_wq_watchdog_timeout = + mlme_obj->cfg.timeouts.wmi_wq_watchdog_timeout; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_wmi_wq_watchdog_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t wmi_wq_watchdog_timeout) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + if (!cfg_in_range(CFG_WMI_WQ_WATCHDOG, wmi_wq_watchdog_timeout)) { + mlme_legacy_err("wmi watchdog bite timeout is invalid %d", + wmi_wq_watchdog_timeout); + return QDF_STATUS_E_INVAL; + } + + mlme_obj->cfg.timeouts.wmi_wq_watchdog_timeout = + wmi_wq_watchdog_timeout; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_stats_get_periodic_display_time(struct wlan_objmgr_psoc *psoc, + uint32_t *periodic_display_time) +{ + return wlan_mlme_stats_get_periodic_display_time(psoc, + periodic_display_time); +} + +QDF_STATUS +ucfg_mlme_stats_get_cfg_values(struct wlan_objmgr_psoc *psoc, + int *link_speed_rssi_high, + int *link_speed_rssi_mid, + int *link_speed_rssi_low, + uint32_t *link_speed_rssi_report) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *link_speed_rssi_high = + cfg_default(CFG_LINK_SPEED_RSSI_HIGH); + *link_speed_rssi_mid = + cfg_default(CFG_LINK_SPEED_RSSI_MID); + *link_speed_rssi_low = + cfg_default(CFG_LINK_SPEED_RSSI_LOW); + *link_speed_rssi_report = + cfg_default(CFG_REPORT_MAX_LINK_SPEED); + return QDF_STATUS_E_INVAL; + } + + *link_speed_rssi_high = + mlme_obj->cfg.stats.stats_link_speed_rssi_high; + *link_speed_rssi_mid = + mlme_obj->cfg.stats.stats_link_speed_rssi_med; + *link_speed_rssi_low = + mlme_obj->cfg.stats.stats_link_speed_rssi_low; + *link_speed_rssi_report = + mlme_obj->cfg.stats.stats_report_max_link_speed_rssi; + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_mlme_stats_is_link_speed_report_actual(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + int report_link_speed = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + report_link_speed = cfg_default(CFG_REPORT_MAX_LINK_SPEED); + else + report_link_speed = + mlme_obj->cfg.stats.stats_report_max_link_speed_rssi; + + return (report_link_speed == CFG_STATS_LINK_SPEED_REPORT_ACTUAL); +} + +bool ucfg_mlme_stats_is_link_speed_report_max(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + int report_link_speed = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + report_link_speed = cfg_default(CFG_REPORT_MAX_LINK_SPEED); + else + report_link_speed = + mlme_obj->cfg.stats.stats_report_max_link_speed_rssi; + + return (report_link_speed == CFG_STATS_LINK_SPEED_REPORT_MAX); +} + +bool +ucfg_mlme_stats_is_link_speed_report_max_scaled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + int report_link_speed = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + report_link_speed = cfg_default(CFG_REPORT_MAX_LINK_SPEED); + else + report_link_speed = + mlme_obj->cfg.stats.stats_report_max_link_speed_rssi; + + return (report_link_speed == CFG_STATS_LINK_SPEED_REPORT_MAX_SCALED); +} + +QDF_STATUS +ucfg_mlme_get_sta_keepalive_method(struct wlan_objmgr_psoc *psoc, + enum station_keepalive_method *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.sta.sta_keepalive_method; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_enable_deauth_to_disassoc_map(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.gen.enable_deauth_to_disassoc_map; + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS +ucfg_mlme_get_ap_random_bssid_enable(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.sap_cfg.ap_random_bssid_enable; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_latency_enable(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.wlm_config.latency_enable; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_latency_level(struct wlan_objmgr_psoc *psoc, uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.wlm_config.latency_level; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_latency_host_flags(struct wlan_objmgr_psoc *psoc, + uint8_t latency_level, uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.wlm_config.latency_host_flags[latency_level]; + return QDF_STATUS_SUCCESS; +} + +#ifdef MWS_COEX +QDF_STATUS +ucfg_mlme_get_mws_coex_4g_quick_tdm(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_MWS_COEX_4G_QUICK_FTDM); + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.mwc.mws_coex_4g_quick_tdm; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_mws_coex_5g_nr_pwr_limit(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_MWS_COEX_5G_NR_PWR_LIMIT); + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_E_INVAL; + } + + *val = mlme_obj->cfg.mwc.mws_coex_5g_nr_pwr_limit; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_mws_coex_pcc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_MWS_COEX_PCC_CHANNEL_AVOID_DELAY); + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_SUCCESS; + } + + *val = mlme_obj->cfg.mwc.mws_coex_pcc_channel_avoid_delay; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_mws_coex_scc_channel_avoid_delay(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_MWS_COEX_SCC_CHANNEL_AVOID_DELAY); + mlme_legacy_err("mlme obj null"); + return QDF_STATUS_SUCCESS; + } + + *val = mlme_obj->cfg.mwc.mws_coex_scc_channel_avoid_delay; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +ucfg_mlme_get_etsi_srd_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_ETSI_SRD_CHAN_IN_MASTER_MODE); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.etsi_srd_chan_in_master_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_5dot9_ghz_chan_in_master_mode(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_FCC_5DOT9_GHZ_CHAN_IN_MASTER_MODE); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.fcc_5dot9_ghz_chan_in_master_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_srd_master_mode_for_vdev(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode, + bool *value) +{ + return wlan_mlme_get_srd_master_mode_for_vdev(psoc, vdev_opmode, value); +} + +#ifdef SAP_AVOID_ACS_FREQ_LIST +QDF_STATUS +ucfg_mlme_get_acs_avoid_freq_list(struct wlan_objmgr_psoc *psoc, + uint16_t *freq_list, uint8_t *freq_list_num) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + qdf_size_t avoid_acs_freq_list_num; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + qdf_uint16_array_parse( + cfg_default(CFG_SAP_AVOID_ACS_FREQ_LIST), + freq_list, CFG_VALID_CHANNEL_LIST_LEN, + &avoid_acs_freq_list_num); + *freq_list_num = avoid_acs_freq_list_num; + + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *freq_list_num = mlme_obj->cfg.reg.avoid_acs_freq_list_num; + qdf_mem_copy(freq_list, mlme_obj->cfg.reg.avoid_acs_freq_list, + *freq_list_num * sizeof(uint16_t)); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +ucfg_mlme_get_11d_in_world_mode(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_ENABLE_11D_IN_WORLD_MODE); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.enable_11d_in_world_mode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_restart_beaconing_on_ch_avoid(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_RESTART_BEACONING_ON_CH_AVOID); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.restart_beaconing_on_ch_avoid; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_indoor_channel_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_INDOOR_CHANNEL_SUPPORT); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.indoor_channel_support; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_scan_11d_interval(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_SCAN_11D_INTERVAL); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.scan_11d_interval; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_nol_across_regdmn(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_RETAIN_NOL_ACROSS_REG_DOMAIN); + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.reg.retain_nol_across_regdmn_update; + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS +ucfg_mlme_is_subnet_detection_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_LFR3_ENABLE_SUBNET_DETECTION); + return QDF_STATUS_E_INVAL; + } + *val = mlme_obj->cfg.lfr.enable_lfr_subnet_detection; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +ucfg_mlme_set_current_tx_power_level(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.power.current_tx_power_level = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_current_tx_power_level(struct wlan_objmgr_psoc *psoc, + uint8_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *value = cfg_default(CFG_CURRENT_TX_POWER_LEVEL); + return QDF_STATUS_E_INVAL; + } + + *value = mlme_obj->cfg.power.current_tx_power_level; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_wlan_mlme_get_reg_tpc_info(struct wlan_objmgr_vdev *vdev, + struct reg_tpc_power_info *tpc_info) +{ + struct vdev_mlme_obj *mlme_obj; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + + if (!mlme_obj) { + mlme_legacy_err("vdev component object is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(tpc_info, &mlme_obj->reg_tpc_obj, + sizeof(struct reg_tpc_power_info)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_obss_detection_offload_enabled(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.obss_ht40.obss_detection_offload_enabled = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_bss_color_collision_det_sta(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.obss_ht40.bss_color_collision_det_sta = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_bss_color_collision_det_support(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.obss_ht40.bss_color_collision_det_tgt_support = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_bss_color_collision_det_support(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.obss_ht40.bss_color_collision_det_tgt_support; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_obss_color_collision_offload_enabled( + struct wlan_objmgr_psoc *psoc, uint8_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.obss_ht40.obss_color_collision_offload_enabled = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_mlme_set_restricted_80p80_bw_supp(struct wlan_objmgr_psoc *psoc, + bool restricted_80p80_supp) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.vht_caps.vht_cap_info.restricted_80p80_bw_supp = + restricted_80p80_supp; + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_mlme_get_restricted_80p80_bw_supp(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return true; + + return mlme_obj->cfg.vht_caps.vht_cap_info.restricted_80p80_bw_supp; +} + +QDF_STATUS +ucfg_mlme_get_channel_bonding_24ghz(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *val = cfg_default(CFG_CHANNEL_BONDING_MODE_24GHZ); + return QDF_STATUS_E_INVAL; + } + *val = mlme_obj->cfg.feature_flags.channel_bonding_mode_24ghz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_set_channel_bonding_24ghz(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.feature_flags.channel_bonding_mode_24ghz = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_update_chan_width_allowed(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + return wlan_mlme_get_update_chan_width_allowed(psoc, value); +} + +QDF_STATUS +ucfg_mlme_get_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, + uint32_t *value) +{ + return wlan_mlme_get_channel_bonding_5ghz(psoc, value); +} + +QDF_STATUS +ucfg_mlme_set_channel_bonding_5ghz(struct wlan_objmgr_psoc *psoc, + uint32_t value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.feature_flags.channel_bonding_mode_5ghz = value; + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_mlme_validate_full_roam_scan_period(uint32_t full_roam_scan_period) +{ + bool is_valid = true; + uint32_t min, max; + + if (!cfg_in_range(CFG_LFR_FULL_ROAM_SCAN_REFRESH_PERIOD, + full_roam_scan_period)) { + min = (cfg_min(CFG_LFR_FULL_ROAM_SCAN_REFRESH_PERIOD)); + max = (cfg_max(CFG_LFR_FULL_ROAM_SCAN_REFRESH_PERIOD)); + mlme_legacy_err("Full roam scan period value %d is out of range (Min: %d Max: %d)", + full_roam_scan_period, min, max); + is_valid = false; + } + + return is_valid; +} + +bool ucfg_mlme_validate_scan_period(struct wlan_objmgr_psoc *psoc, + uint32_t roam_scan_period) +{ + bool is_valid = true, val = false; + + if (!cfg_in_range(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD, + roam_scan_period)) { + ucfg_mlme_get_connection_roaming_ini_present(psoc, &val); + if (val) + mlme_legacy_err("Roam scan period value %d msec is out of range (Min: %d msec Max: %d msec)", + roam_scan_period, + cfg_min(CFG_ROAM_SCAN_FIRST_TIMER) * 1000, + cfg_max(CFG_ROAM_SCAN_FIRST_TIMER) * 1000); + else + mlme_legacy_err("Roam scan period value %d msec is out of range (Min: %d msec Max: %d msec)", + roam_scan_period, + cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD), + cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD)); + is_valid = false; + } + + return is_valid; +} + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +bool ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer( + struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap(psoc); +} + +bool ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + struct wlan_objmgr_psoc *psoc) +{ + return wlan_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap(psoc); +} + +bool ucfg_mlme_get_coex_unsafe_chan_reg_disable( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return cfg_default(CFG_COEX_UNSAFE_CHAN_REG_DISABLE); + } + return mlme_obj->cfg.reg.coex_unsafe_chan_reg_disable; +} +#endif + +#if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_BAND_6GHZ) +QDF_STATUS +ucfg_mlme_get_enable_6ghz_sp_mode_support(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.reg.enable_6ghz_sp_pwrmode_supp; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_afc_disable_timer_check(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.reg.afc_disable_timer_check; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_afc_disable_request_id_check(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.reg.afc_disable_request_id_check; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_afc_reg_noaction(struct wlan_objmgr_psoc *psoc, bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.reg.is_afc_reg_noaction; + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef CONNECTION_ROAMING_CFG +QDF_STATUS +ucfg_mlme_set_connection_roaming_ini_present(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->cfg.connection_roaming_ini_flag = value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_mlme_get_connection_roaming_ini_present(struct wlan_objmgr_psoc *psoc, + bool *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.connection_roaming_ini_flag; + + return QDF_STATUS_SUCCESS; +} +#endif + +enum wlan_phymode +ucfg_mlme_get_vdev_phy_mode(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *mlme_obj; + enum wlan_phymode phymode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_err("get vdev failed for vdev_id: %d", vdev_id); + return WLAN_PHYMODE_AUTO; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + mlme_err("failed to get mlme_obj vdev_id: %d", vdev_id); + phymode = WLAN_PHYMODE_AUTO; + goto done; + } + phymode = mlme_obj->mgmt.generic.phy_mode; + +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return phymode; +} + +QDF_STATUS +ucfg_mlme_get_valid_channels(struct wlan_objmgr_psoc *psoc, + uint32_t *ch_freq_list, uint32_t *list_len) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint32_t num_valid_chan; + uint8_t i; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + *list_len = 0; + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + num_valid_chan = mlme_obj->cfg.reg.valid_channel_list_num; + if (num_valid_chan > *list_len) { + mlme_err("list len size %d less than expected %d", *list_len, + num_valid_chan); + num_valid_chan = *list_len; + } + *list_len = num_valid_chan; + for (i = 0; i < *list_len; i++) + ch_freq_list[i] = mlme_obj->cfg.reg.valid_channel_freq_list[i]; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/core/inc/nan_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/inc/nan_public_structs.h new file mode 100644 index 0000000000..6e589c99e1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/inc/nan_public_structs.h @@ -0,0 +1,901 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan definitions exposed to other modules + */ + +#ifndef _NAN_PUBLIC_STRUCTS_H_ +#define _NAN_PUBLIC_STRUCTS_H_ + +#include "qdf_types.h" +#include "qdf_status.h" +#include "scheduler_api.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; + +#define IFACE_NAME_SIZE 64 +#define NDP_QOS_INFO_LEN 255 +#define NDP_APP_INFO_LEN 255 +#define NDP_PMK_LEN 32 +#define NDP_SCID_BUF_LEN 256 +#define NDP_NUM_INSTANCE_ID 255 +#define NAN_MAX_SERVICE_NAME_LEN 255 +#define NAN_PASSPHRASE_MIN_LEN 8 +#define NAN_PASSPHRASE_MAX_LEN 63 +#define NAN_CH_INFO_MAX_CHANNELS 4 +#define WLAN_WAIT_TIME_NDP_END 4000 + +#define NAN_PSEUDO_VDEV_ID CFG_TGT_NUM_VDEV + +#define NAN_SER_CMD_TIMEOUT 4000 +#define NDP_SERVICE_ID_LEN 6 +/** + * enum nan_discovery_msg_type - NAN msg type + * @NAN_GENERIC_REQ: Type for all the NAN requests other than enable/disable + * @NAN_ENABLE_REQ: Request type for enabling the NAN Discovery + * @NAN_DISABLE_REQ: Request type for disabling the NAN Discovery + */ +enum nan_discovery_msg_type { + NAN_GENERIC_REQ = 0, + NAN_ENABLE_REQ = 1, + NAN_DISABLE_REQ = 2, +}; + +/** + * enum nan_datapath_msg_type - NDP msg type + * @NAN_DATAPATH_INF_CREATE_REQ: ndi create request + * @NAN_DATAPATH_INF_CREATE_RSP: ndi create response + * @NAN_DATAPATH_INF_DELETE_REQ: ndi delete request + * @NAN_DATAPATH_INF_DELETE_RSP: ndi delete response + * @NDP_INITIATOR_REQ: ndp initiator request + * @NDP_INITIATOR_RSP: ndp initiator response + * @NDP_RESPONDER_REQ: ndp responder request + * @NDP_RESPONDER_RSP: ndp responder response + * @NDP_END_REQ: ndp end request + * @NDP_END_RSP: ndp end response + * @NDP_INDICATION: ndp indication + * @NDP_CONFIRM: ndp confirm + * @NDP_END_IND: ndp end indication + * @NDP_NEW_PEER: ndp new peer created + * @NDP_PEER_DEPARTED: ndp peer departed/deleted + * @NDP_SCHEDULE_UPDATE: ndp schedule update + * @NDP_END_ALL: end all NDPs request + * @NDP_HOST_UPDATE: update host about ndp status + */ +enum nan_datapath_msg_type { + NAN_DATAPATH_INF_CREATE_REQ = 0, + NAN_DATAPATH_INF_CREATE_RSP = 1, + NAN_DATAPATH_INF_DELETE_REQ = 2, + NAN_DATAPATH_INF_DELETE_RSP = 3, + NDP_INITIATOR_REQ = 4, + NDP_INITIATOR_RSP = 5, + NDP_RESPONDER_REQ = 6, + NDP_RESPONDER_RSP = 7, + NDP_END_REQ = 8, + NDP_END_RSP = 9, + NDP_INDICATION = 10, + NDP_CONFIRM = 11, + NDP_END_IND = 12, + NDP_NEW_PEER = 13, + NDP_PEER_DEPARTED = 14, + NDP_SCHEDULE_UPDATE = 15, + NDP_END_ALL = 16, + NDP_HOST_UPDATE = 17, +}; + +/** + * enum nan_datapath_status_type - NDP status type + * @NAN_DATAPATH_RSP_STATUS_SUCCESS: request was successful + * @NAN_DATAPATH_RSP_STATUS_ERROR: request failed + */ +enum nan_datapath_status_type { + NAN_DATAPATH_RSP_STATUS_SUCCESS = 0x00, + NAN_DATAPATH_RSP_STATUS_ERROR = 0x01, +}; + +/** + * enum nan_datapath_reason_code - NDP command rsp reason code value + * @NAN_DATAPATH_UNSUPPORTED_CONCURRENCY: Will be used in unsupported + * concurrency cases + * @NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED: ndi create failed + * @NAN_DATAPATH_NAN_DATA_IFACE_DELETE_FAILED: ndi delete failed + * @NAN_DATAPATH_DATA_INITIATOR_REQ_FAILED: data initiator request failed + * @NAN_DATAPATH_DATA_RESPONDER_REQ_FAILED: data responder request failed + * @NAN_DATAPATH_INVALID_SERVICE_INSTANCE_ID: invalid service instance id + * @NAN_DATAPATH_INVALID_NDP_INSTANCE_ID: invalid ndp instance id + * @NAN_DATAPATH_INVALID_RSP_CODE: invalid response code in ndp responder + * request + * @NAN_DATAPATH_INVALID_APP_INFO_LEN: invalid app info length + * @NAN_DATAPATH_NMF_REQ_FAIL: OTA nan mgmt frame failure for data request + * @NAN_DATAPATH_NMF_RSP_FAIL: OTA nan mgmt frame failure for data response + * @NAN_DATAPATH_NMF_CNF_FAIL: OTA nan mgmt frame failure for confirm + * @NAN_DATAPATH_END_FAILED: ndp end failed + * @NAN_DATAPATH_NMF_END_REQ_FAIL: OTA nan mgmt frame failure for data end + * @NAN_DATAPATH_VENDOR_SPECIFIC_ERROR: other vendor specific failures + */ +enum nan_datapath_reason_code { + NAN_DATAPATH_UNSUPPORTED_CONCURRENCY = 9000, + NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED = 9001, + NAN_DATAPATH_NAN_DATA_IFACE_DELETE_FAILED = 9002, + NAN_DATAPATH_DATA_INITIATOR_REQ_FAILED = 9003, + NAN_DATAPATH_DATA_RESPONDER_REQ_FAILED = 9004, + NAN_DATAPATH_INVALID_SERVICE_INSTANCE_ID = 9005, + NAN_DATAPATH_INVALID_NDP_INSTANCE_ID = 9006, + NAN_DATAPATH_INVALID_RSP_CODE = 9007, + NAN_DATAPATH_INVALID_APP_INFO_LEN = 9008, + NAN_DATAPATH_NMF_REQ_FAIL = 9009, + NAN_DATAPATH_NMF_RSP_FAIL = 9010, + NAN_DATAPATH_NMF_CNF_FAIL = 9011, + NAN_DATAPATH_END_FAILED = 9012, + NAN_DATAPATH_NMF_END_REQ_FAIL = 9013, + /* 9500 onwards vendor specific error codes */ + NAN_DATAPATH_VENDOR_SPECIFIC_ERROR = 9500, +}; + +/** + * enum nan_datapath_response_code - responder's response code to nan data path + * request + * @NAN_DATAPATH_RESPONSE_ACCEPT: ndp request accepted + * @NAN_DATAPATH_RESPONSE_REJECT: ndp request rejected + * @NAN_DATAPATH_RESPONSE_DEFER: ndp request deferred until later (response to + * follow any time later) + */ +enum nan_datapath_response_code { + NAN_DATAPATH_RESPONSE_ACCEPT = 0, + NAN_DATAPATH_RESPONSE_REJECT = 1, + NAN_DATAPATH_RESPONSE_DEFER = 2, +}; + +/** + * enum nan_datapath_accept_policy - nan data path accept policy + * @NAN_DATAPATH_ACCEPT_POLICY_NONE: the framework will decide the policy + * @NAN_DATAPATH_ACCEPT_POLICY_ALL: accept policy offloaded to fw + */ +enum nan_datapath_accept_policy { + NAN_DATAPATH_ACCEPT_POLICY_NONE = 0, + NAN_DATAPATH_ACCEPT_POLICY_ALL = 1, +}; + +/** + * enum nan_datapath_self_role - nan data path role + * @NAN_DATAPATH_ROLE_INITIATOR: initiator of nan data path request + * @NAN_DATAPATH_ROLE_RESPONDER: responder to nan data path request + */ +enum nan_datapath_self_role { + NAN_DATAPATH_ROLE_INITIATOR = 0, + NAN_DATAPATH_ROLE_RESPONDER = 1, +}; + +/** + * enum nan_datapath_end_type - NDP end type + * @NAN_DATAPATH_END_TYPE_UNSPECIFIED: type is unspecified + * @NAN_DATAPATH_END_TYPE_PEER_UNAVAILABLE: type is peer unavailable + * @NAN_DATAPATH_END_TYPE_OTA_FRAME: NDP end frame received from peer + */ +enum nan_datapath_end_type { + NAN_DATAPATH_END_TYPE_UNSPECIFIED = 0x00, + NAN_DATAPATH_END_TYPE_PEER_UNAVAILABLE = 0x01, + NAN_DATAPATH_END_TYPE_OTA_FRAME = 0x02, +}; + +/** + * enum nan_datapath_end_reason_code - NDP end reason code + * @NAN_DATAPATH_END_REASON_UNSPECIFIED: reason is unspecified + * @NAN_DATAPATH_END_REASON_INACTIVITY: reason is peer inactivity + * @NAN_DATAPATH_END_REASON_PEER_DATA_END: data end indication received from + * peer + */ +enum nan_datapath_end_reason_code { + NAN_DATAPATH_END_REASON_UNSPECIFIED = 0x00, + NAN_DATAPATH_END_REASON_INACTIVITY = 0x01, + NAN_DATAPATH_END_REASON_PEER_DATA_END = 0x02, +}; + +/** + * enum nan_datapath_state - NAN datapath states + * @NAN_DATA_INVALID_STATE: Invalid state + * @NAN_DATA_NDI_CREATING_STATE: NDI create is in progress + * @NAN_DATA_NDI_CREATED_STATE: NDI successfully created + * @NAN_DATA_NDI_DELETING_STATE: NDI delete is in progress + * @NAN_DATA_NDI_DELETED_STATE: NDI delete is in progress + * @NAN_DATA_PEER_CREATE_STATE: Peer create is in progress + * @NAN_DATA_PEER_DELETE_STATE: Peer delete is in progress + * @NAN_DATA_CONNECTING_STATE: Data connection in progress + * @NAN_DATA_CONNECTED_STATE: Data connection successful + * @NAN_DATA_END_STATE: NDP end is in progress + * @NAN_DATA_DISCONNECTED_STATE: NDP is in disconnected state + */ +enum nan_datapath_state { + NAN_DATA_INVALID_STATE = -1, + NAN_DATA_NDI_CREATING_STATE = 0, + NAN_DATA_NDI_CREATED_STATE = 1, + NAN_DATA_NDI_DELETING_STATE = 2, + NAN_DATA_NDI_DELETED_STATE = 3, + NAN_DATA_PEER_CREATE_STATE = 4, + NAN_DATA_PEER_DELETE_STATE = 5, + NAN_DATA_CONNECTING_STATE = 6, + NAN_DATA_CONNECTED_STATE = 7, + NAN_DATA_END_STATE = 8, + NAN_DATA_DISCONNECTED_STATE = 9, +}; + +/** + * struct nan_datapath_app_info - application info shared during ndp setup + * @ndp_app_info_len: ndp app info length + * @ndp_app_info: variable length application information + */ +struct nan_datapath_app_info { + uint32_t ndp_app_info_len; + uint8_t ndp_app_info[NDP_APP_INFO_LEN]; +}; + +/** + * struct nan_datapath_cfg - ndp configuration + * @ndp_cfg_len: ndp configuration length + * @ndp_cfg: variable length ndp configuration + */ +struct nan_datapath_cfg { + uint32_t ndp_cfg_len; + uint8_t ndp_cfg[NDP_QOS_INFO_LEN]; +}; + +/** + * struct nan_datapath_pmk - structure to hold pairwise master key + * @pmk_len: length of pairwise master key + * @pmk: buffer containing pairwise master key + */ +struct nan_datapath_pmk { + uint32_t pmk_len; + uint8_t pmk[NDP_PMK_LEN]; +}; + +/** + * struct nan_datapath_scid - structure to hold security context identifier + * @scid_len: length of scid + * @scid: scid + */ +struct nan_datapath_scid { + uint32_t scid_len; + uint8_t scid[NDP_SCID_BUF_LEN]; +}; + +/** + * struct ndp_passphrase - structure to hold passphrase + * @passphrase_len: length of passphrase + * @passphrase: buffer containing passphrase + */ +struct ndp_passphrase { + uint32_t passphrase_len; + uint8_t passphrase[NAN_PASSPHRASE_MAX_LEN]; +}; + +/** + * struct ndp_service_name - structure to hold service_name + * @service_name_len: length of service_name + * @service_name: buffer containing service_name + */ +struct ndp_service_name { + uint32_t service_name_len; + uint8_t service_name[NAN_MAX_SERVICE_NAME_LEN]; +}; + +/** + * struct peer_nan_datapath_map - mapping of NDP instances to peer to VDEV + * @vdev_id: session id of the interface over which ndp is being created + * @peer_ndi_mac_addr: peer NDI mac address + * @num_active_ndp_sessions: number of active NDP sessions on the peer + * @type: NDP end indication type + * @reason_code: NDP end indication reason code + * @ndp_instance_id: NDP instance ID + */ +struct peer_nan_datapath_map { + uint32_t vdev_id; + struct qdf_mac_addr peer_ndi_mac_addr; + uint32_t num_active_ndp_sessions; + enum nan_datapath_end_type type; + enum nan_datapath_end_reason_code reason_code; + uint32_t ndp_instance_id; +}; + +/** + * struct nan_datapath_channel_info - ndp channel and channel bandwidth + * @freq: channel freq in mhz of the ndp connection + * @ch_width: channel width (wmi_channel_width) of the ndp connection + * @nss: nss used for ndp connection + * @mac_id: MAC ID associated with the NDP channel + */ +struct nan_datapath_channel_info { + uint32_t freq; + uint32_t ch_width; + uint32_t nss; + uint8_t mac_id; +}; + +#define NAN_CH_INFO_MAX_LEN \ + (NAN_CH_INFO_MAX_CHANNELS * sizeof(struct nan_datapath_channel_info)) + +/** + * struct nan_datapath_inf_create_req - ndi create request params + * @transaction_id: unique identifier + * @iface_name: interface name + */ +struct nan_datapath_inf_create_req { + uint32_t transaction_id; + char iface_name[IFACE_NAME_SIZE]; +}; + +/** + * struct nan_datapath_inf_create_rsp - ndi create response params + * @status: request status + * @reason: reason if any + */ +struct nan_datapath_inf_create_rsp { + uint32_t status; + uint32_t reason; +}; + +/** + * struct nan_datapath_inf_delete_rsp - ndi delete response params + * @status: request status + * @reason: reason if any + */ +struct nan_datapath_inf_delete_rsp { + uint32_t status; + uint32_t reason; +}; + +/** + * struct ndp_additional_params - NDP parameters + * @csid_cap: NAN Cipher Suite Capability field + * @gtk: GTK protection is required for the NDP + */ +struct ndp_additional_params { + uint32_t csid_cap; + uint32_t gtk; +}; + +/** + * struct nan_datapath_initiator_req - ndp initiator request params + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @channel: suggested channel for ndp creation + * @channel_cfg: channel config, 0=no channel, 1=optional, 2=mandatory + * @service_instance_id: Service identifier + * @peer_discovery_mac_addr: Peer's discovery mac address + * @self_ndi_mac_addr: self NDI mac address + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @pmk: pairwise master key + * @passphrase: passphrase + * @service_name: service name + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * @ndp_add_params: NDP additional parameters + */ +struct nan_datapath_initiator_req { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t channel; + uint32_t channel_cfg; + uint32_t service_instance_id; + uint32_t ncs_sk_type; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr self_ndi_mac_addr; + struct nan_datapath_cfg ndp_config; + struct nan_datapath_app_info ndp_info; + struct nan_datapath_pmk pmk; + struct ndp_passphrase passphrase; + struct ndp_service_name service_name; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; + struct ndp_additional_params ndp_add_params; +}; + +/** + * struct nan_datapath_initiator_rsp - response event from FW + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @ndp_instance_id: locally created NDP instance ID + * @status: status of the ndp request + * @reason: reason for failure if any + */ +struct nan_datapath_initiator_rsp { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t ndp_instance_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct nan_datapath_responder_req - responder's response to ndp create + * request + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @ndp_instance_id: locally created NDP instance ID + * @ndp_rsp: response to the ndp create request + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @pmk: pairwise master key + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @passphrase: passphrase + * @service_name: service name + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * @is_port_present: indicates if following port is valid + * @port: port specified by for this NDP + * @is_protocol_present: indicates if following protocol is valid + * @protocol: protocol used by this NDP + * @ndp_add_params: NDP additional parameters + */ +struct nan_datapath_responder_req { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t ndp_instance_id; + enum nan_datapath_response_code ndp_rsp; + struct nan_datapath_cfg ndp_config; + struct nan_datapath_app_info ndp_info; + struct nan_datapath_pmk pmk; + uint32_t ncs_sk_type; + struct ndp_passphrase passphrase; + struct ndp_service_name service_name; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; + bool is_port_present; + uint16_t port; + bool is_protocol_present; + uint8_t protocol; + struct ndp_additional_params ndp_add_params; +}; + +/** + * struct nan_datapath_responder_rsp - response to responder's request + * @vdev: pointer to vdev object + * @transaction_id: unique identifier + * @status: command status + * @reason: reason for failure if any + * @peer_mac_addr: Peer's mac address + * @create_peer: Flag to indicate to create peer + */ +struct nan_datapath_responder_rsp { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t status; + uint32_t reason; + struct qdf_mac_addr peer_mac_addr; + bool create_peer; +}; + +/** + * struct nan_datapath_end_req - ndp end request + * @vdev: pointer to vdev object + * @transaction_id: unique transaction identifier + * @num_ndp_instances: number of ndp instances to be terminated + * @ndp_ids: array of ndp_instance_id to be terminated + */ +struct nan_datapath_end_req { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t num_ndp_instances; + uint32_t ndp_ids[NDP_NUM_INSTANCE_ID]; +}; + +/** + * struct nan_datapath_end_all_ndps - Datapath termination request to end all + * NDPs on the given vdev + * @vdev: pointer to vdev object + */ +struct nan_datapath_end_all_ndps { + struct wlan_objmgr_vdev *vdev; +}; + +/** + * enum nan_event_id_types - NAN event ID types + * @nan_event_id_error_rsp: NAN event indicating error + * @nan_event_id_enable_rsp: NAN Enable Response event ID + * @nan_event_id_disable_ind: NAN Disable Indication event ID + * @nan_event_id_generic_rsp: All remaining NAN events, treated as passthrough + */ +enum nan_event_id_types { + nan_event_id_error_rsp = 0, + nan_event_id_enable_rsp, + nan_event_id_disable_ind, + nan_event_id_generic_rsp, +}; + +/** + * struct nan_event_params - NAN event received from the Target + * @psoc: Pointer to the psoc object + * @evt_type: NAN Discovery event type + * @is_nan_enable_success: Status from the NAN Enable Response event + * @mac_id: MAC ID associated with NAN Discovery from NAN Enable Response event + * @vdev_id: vdev id of the interface created for NAN discovery + * @buf_len: Event buffer length + * @buf: Event buffer starts here + */ +struct nan_event_params { + struct wlan_objmgr_psoc *psoc; + enum nan_event_id_types evt_type; + bool is_nan_enable_success; + uint8_t mac_id; + uint8_t vdev_id; + uint32_t buf_len; + /* Variable length, do not add anything after this */ + uint8_t buf[]; +}; + +#define NAN_MSG_ID_DISABLE_INDICATION 26 +/** + * struct nan_msg_hdr - NAN msg header to be sent to userspace + * @msg_version: NAN msg version + * @msg_id: NAN message id + * @reserved: Reserved for now to avoid padding + * + * 8-byte control message header used by NAN + * + */ +struct nan_msg_hdr { + uint16_t msg_version:4; + uint16_t msg_id:12; + uint16_t reserved[3]; +}; + +#define NAN_STATUS_SUCCESS 0 +#define NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED 12 + +/** + * struct nan_disable_ind_msg - NAN disable ind params + * @msg_hdr: NAN msg header + * @reason: NAN disable reason, below are valid reasons for NAN disable ind + * NAN_STATUS_SUCCESS + * NAN_STATUS_UNSUPPORTED_CONCURRENCY_NAN_DISABLED + * @reserved: Reserved for now to avoid padding + */ +struct nan_disable_ind_msg { + struct nan_msg_hdr msg_hdr; + uint16_t reason; + uint16_t reserved; +}; + +/** + * struct nan_msg_params - NAN request params + * @request_data_len: request data length + * @request_data: request data + * @rtt_cap: indicate if responder/initiator role is supported + * @disable_6g_nan: Disable NAN in 6Ghz + */ +struct nan_msg_params { + uint16_t request_data_len; + uint32_t rtt_cap; + bool disable_6g_nan; + /* Variable length, do not add anything after this */ + uint8_t request_data[]; +}; + +/** + * struct nan_generic_req - A NAN request for the Target + * @psoc: Pointer to the psoc object + * @params: NAN request structure containing message fr the Target + */ +struct nan_generic_req { + struct wlan_objmgr_psoc *psoc; + /* Variable length, do not add anything after this */ + struct nan_msg_params params; +}; + +/** + * struct nan_disable_req - NAN request to disable NAN Discovery + * @psoc: Pointer to the psoc object + * @disable_2g_discovery: Flag for disabling Discovery in 2G band + * @disable_5g_discovery: Flag for disabling Discovery in 5G band + * @params: NAN request structure containing message for the target + */ +struct nan_disable_req { + struct wlan_objmgr_psoc *psoc; + bool disable_2g_discovery; + bool disable_5g_discovery; + /* Variable length, do not add anything after this */ + struct nan_msg_params params; +}; + +/** + * struct nan_enable_req - NAN request to enable NAN Discovery + * @psoc: Pointer to the psoc object + * @social_chan_2g_freq: Social channel in 2G band for the NAN Discovery + * @social_chan_5g_freq: Social channel in 5G band for the NAN Discovery + * @pdev: Pointer to the pdev object + * @params: NAN request structure containing message for the target + */ +struct nan_enable_req { + struct wlan_objmgr_psoc *psoc; + uint32_t social_chan_2g_freq; + uint32_t social_chan_5g_freq; + struct wlan_objmgr_pdev *pdev; + /* Variable length, do not add anything after this */ + struct nan_msg_params params; +}; + +/** + * struct nan_datapath_end_rsp_event - firmware response to ndp end request + * @vdev: pointer to vdev object + * @transaction_id: unique identifier for the request + * @status: status of operation + * @reason: reason(opaque to host driver) + */ +struct nan_datapath_end_rsp_event { + struct wlan_objmgr_vdev *vdev; + uint32_t transaction_id; + uint32_t status; + uint32_t reason; +}; + +/** + * struct nan_datapath_end_indication_event - ndp termination notification from + * FW + * @vdev: pointer to vdev object + * @num_ndp_ids: number of NDP ids + * @ndp_map: mapping of NDP instances to peer and vdev + */ +struct nan_datapath_end_indication_event { + struct wlan_objmgr_vdev *vdev; + uint32_t num_ndp_ids; + struct peer_nan_datapath_map ndp_map[]; +}; + +/** + * struct nan_dump_msg - ndp logging message + * @msg: msg received by FW + * @data_len: data length + * + */ +struct nan_dump_msg { + uint8_t *msg; + uint32_t data_len; +}; + +/** + * struct nan_datapath_confirm_event - ndp confirmation event from FW + * @vdev: pointer to vdev object + * @ndp_instance_id: ndp instance id for which confirm is being generated + * @reason_code : reason code(opaque to driver) + * @num_active_ndps_on_peer: number of ndp instances on peer + * @peer_ndi_mac_addr: peer NDI mac address + * @rsp_code: ndp response code + * @num_channels: num channels + * @ch: channel info struct array + * @ndp_info: ndp application info + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * @is_port_present: indicates if following port is valid + * @port: port specified by for this NDP + * @is_protocol_present: indicates if following protocol is valid + * @protocol: protocol used by this NDP + */ +struct nan_datapath_confirm_event { + struct wlan_objmgr_vdev *vdev; + uint32_t ndp_instance_id; + uint32_t reason_code; + uint32_t num_active_ndps_on_peer; + struct qdf_mac_addr peer_ndi_mac_addr; + enum nan_datapath_response_code rsp_code; + uint32_t num_channels; + struct nan_datapath_channel_info ch[NAN_CH_INFO_MAX_CHANNELS]; + struct nan_datapath_app_info ndp_info; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; + bool is_port_present; + uint16_t port; + bool is_protocol_present; + uint8_t protocol; +}; + +/** + * struct nan_datapath_indication_event - create ndp indication on the responder + * @vdev: pointer to vdev object + * @service_instance_id: Service identifier + * @peer_discovery_mac_addr: Peer's discovery mac address + * @peer_mac_addr: Peer's NDI mac address + * @ndp_initiator_mac_addr: NDI mac address of the peer initiating NDP + * @ndp_instance_id: locally created NDP instance ID + * @role: self role for NDP + * @policy: accept policy configured by the upper layer + * @ndp_config: ndp configuration params + * @ndp_info: ndp application info + * @ncs_sk_type: indicates NCS_SK_128 or NCS_SK_256 + * @scid: security context identifier + * @is_ipv6_addr_present: indicates if following ipv6 address is valid + * @ipv6_addr: ipv6 address address used by ndp + * @is_service_id_present: indicates if service id is present + * @service_id: NDP service id + * @ndp_add_params: NDP additional parameters + */ +struct nan_datapath_indication_event { + struct wlan_objmgr_vdev *vdev; + uint32_t service_instance_id; + struct qdf_mac_addr peer_discovery_mac_addr; + struct qdf_mac_addr peer_mac_addr; + uint32_t ndp_instance_id; + enum nan_datapath_self_role role; + enum nan_datapath_accept_policy policy; + struct nan_datapath_cfg ndp_config; + struct nan_datapath_app_info ndp_info; + uint32_t ncs_sk_type; + struct nan_datapath_scid scid; + bool is_ipv6_addr_present; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; + bool is_service_id_present; + uint8_t service_id[NDP_SERVICE_ID_LEN]; + struct ndp_additional_params ndp_add_params; +}; + +/** + * struct nan_datapath_peer_ind - ndp peer indication + * @peer_mac_addr: peer mac address + * @sta_id: station id + * + */ +struct nan_datapath_peer_ind { + struct qdf_mac_addr peer_mac_addr; + uint16_t sta_id; +}; + +/** + * struct nan_datapath_sch_update_event - ndp schedule update indication + * @vdev: vdev schedule update was received + * @peer_addr: peer for which schedule update was received + * @flags: reason for sch update (opaque to driver) + * @num_channels: num of channels + * @num_ndp_instances: num of ndp instances + * @ch: channel info array + * @ndp_instances: array of ndp instances + */ +struct nan_datapath_sch_update_event { + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr peer_addr; + uint32_t flags; + uint32_t num_channels; + uint32_t num_ndp_instances; + struct nan_datapath_channel_info ch[NAN_CH_INFO_MAX_CHANNELS]; + uint32_t ndp_instances[NDP_NUM_INSTANCE_ID]; +}; + +/** + * struct nan_datapath_host_event - ndp host event parameters + * @vdev: vdev obj associated with the ndp + * @ndp_termination_in_progress: flag that indicates whether NDPs associated + * with the given vdev are being terminated + */ +struct nan_datapath_host_event { + struct wlan_objmgr_vdev *vdev; + bool ndp_termination_in_progress; +}; + +/** + * struct nan_callbacks - struct containing callback to non-converged driver + * @os_if_nan_event_handler: OS IF Callback for handling NAN Discovery events + * @os_if_ndp_event_handler: OS IF Callback for handling NAN Datapath events + * @ucfg_nan_request_process_cb: Callback to indicate NAN enable/disable + * request processing is complete + * @ndi_open: HDD callback for creating the NAN Datapath Interface + * @ndi_start: HDD callback for starting the NAN Datapath Interface + * @ndi_set_mode: HDD callback for setting the adapter mode to NDI + * @ndi_close: HDD callback for closing the NAN Datapath Interface + * @ndi_delete: HDD callback for deleting the NAN Datapath Interface + * @drv_ndi_create_rsp_handler: HDD callback for handling NDI interface creation + * @drv_ndi_delete_rsp_handler: HDD callback for handling NDI interface deletion + * @new_peer_ind: HDD callback for handling new NDP peer + * @add_ndi_peer: LIM callback for adding NDP peer + * @peer_departed_ind: HDD callback for handling departing of NDP peer + * @ndp_delete_peers: LIM callback for deleting NDP peer + * @delete_peers_by_addr: LIM callback for deleting peer by MAC address + * @update_ndi_conn: WMA callback to update NDI's connection info + * @nan_concurrency_update: Callback to handle nan concurrency + * @set_mc_list: HDD callback to set multicast peer list + * @nan_sr_concurrency_update: Callback to handle nan SR(Spatial Reuse) + * concurrency + */ +struct nan_callbacks { + /* callback to os_if layer from umac */ + void (*os_if_nan_event_handler)(struct nan_event_params *nan_event); + void (*os_if_ndp_event_handler)(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg); + void (*ucfg_nan_request_process_cb)(void *cookie); + int (*ndi_open)(const char *iface_name, bool is_add_virtual_iface); + int (*ndi_set_mode)(const char *iface_name); + int (*ndi_start)(const char *iface_name, uint16_t); + void (*ndi_close)(uint8_t); + int (*ndi_delete)(uint8_t, const char *iface_name, uint16_t transaction_id); + void (*drv_ndi_create_rsp_handler) + (uint8_t, struct nan_datapath_inf_create_rsp *); + void (*drv_ndi_delete_rsp_handler)(uint8_t); + int (*new_peer_ind)(uint8_t, uint16_t, struct qdf_mac_addr *, bool); + QDF_STATUS (*add_ndi_peer)(uint32_t, struct qdf_mac_addr); + void (*peer_departed_ind)(uint8_t, uint16_t, struct qdf_mac_addr *, + bool); + void (*ndp_delete_peers)(struct peer_nan_datapath_map*, uint8_t); + void (*delete_peers_by_addr)(uint8_t, struct qdf_mac_addr); + QDF_STATUS (*update_ndi_conn)(uint8_t vdev_id, + struct nan_datapath_channel_info + *chan_info); + void (*nan_concurrency_update)(void); + void (*set_mc_list)(struct wlan_objmgr_vdev *vdev); +#ifdef WLAN_FEATURE_SR + void (*nan_sr_concurrency_update)(struct nan_event_params *nan_evt); +#endif +}; + +/** + * struct wlan_nan_tx_ops - structure of tx function pointers for nan component + * @nan_discovery_req_tx: Msg handler for TX operations for the NAN Discovery + * @nan_datapath_req_tx: Msg handler for TX operations for the NAN Datapath + */ +struct wlan_nan_tx_ops { + QDF_STATUS (*nan_discovery_req_tx)(void *nan_req, uint32_t req_type); + QDF_STATUS (*nan_datapath_req_tx)(void *req, uint32_t req_id); +}; + +/** + * struct wlan_nan_rx_ops - structure of rx function pointers for nan component + * @nan_discovery_event_rx: Evt handler for RX operations for the NAN Discovery + * @nan_datapath_event_rx: Evt handler for RX operations for the NAN Datapath + */ +struct wlan_nan_rx_ops { + QDF_STATUS (*nan_discovery_event_rx)(struct scheduler_msg *event); + QDF_STATUS (*nan_datapath_event_rx)(struct scheduler_msg *event); +}; + +/** + * struct nan_tgt_caps - NAN Target capabilities + * @nan_conc_control: Target supports disabling NAN Discovery from host + * so that host is able to handle(disable) NAN + * concurrencies. + * @nan_dbs_supported: Target supports NAN Discovery with DBS + * @ndi_dbs_supported: Target supports NAN Datapath with DBS + * @nan_sap_supported: Target supports NAN Discovery with SAP concurrency + * @ndi_sap_supported: Target supports NAN Datapath with SAP concurrency + * @nan_vdev_allowed: Allow separate vdev creation for NAN discovery + * @sta_nan_ndi_ndi_allowed: 4 port concurrency of STA+NAN+NDI+NDI is supported + * @ndi_txbf_supported: Target supports NAN Datapath with TX beamforming + * by Fw or not. + * @mlo_sta_nan_ndi_allowed: MLO STA + NAN + NDI concurrency is supported + */ +struct nan_tgt_caps { + uint32_t nan_conc_control:1; + uint32_t nan_dbs_supported:1; + uint32_t ndi_dbs_supported:1; + uint32_t nan_sap_supported:1; + uint32_t ndi_sap_supported:1; + uint32_t nan_vdev_allowed:1; + uint32_t sta_nan_ndi_ndi_allowed:1; + uint32_t ndi_txbf_supported:1; +#ifdef WLAN_FEATURE_11BE_MLO + uint32_t mlo_sta_nan_ndi_allowed:1; +#endif +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h new file mode 100644 index 0000000000..549fcf71ae --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/inc/wlan_nan_api.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan definitions exposed to other modules + */ + +#ifndef _WLAN_NAN_API_H_ +#define _WLAN_NAN_API_H_ + +#include "wlan_objmgr_peer_obj.h" +#include "wlan_policy_mgr_public_struct.h" +#include "qdf_status.h" +#include +#include + +#ifdef WLAN_FEATURE_NAN + +#include "../src/nan_main_i.h" + +struct wlan_objmgr_psoc; + +/** + * nan_init: initializes NAN component, called by dispatcher init + * + * Return: status of operation + */ +QDF_STATUS nan_init(void); + +/** + * nan_deinit: de-initializes NAN component, called by dispatcher init + * + * Return: status of operation + */ +QDF_STATUS nan_deinit(void); + +/** + * nan_psoc_enable: psoc enable API for NANitioning component + * @psoc: pointer to PSOC + * + * Return: status of operation + */ +QDF_STATUS nan_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * nan_psoc_disable: psoc disable API for NANitioning component + * @psoc: pointer to PSOC + * + * Return: status of operation + */ +QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * nan_get_peer_priv_obj: get NAN priv object from peer object + * @peer: pointer to peer object + * + * Return: pointer to NAN peer private object + */ +static inline +struct nan_peer_priv_obj *nan_get_peer_priv_obj(struct wlan_objmgr_peer *peer) +{ + struct nan_peer_priv_obj *obj; + + if (!peer) { + nan_err("peer is null"); + return NULL; + } + obj = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_NAN); + + return obj; +} + +/** + * nan_get_vdev_priv_obj: get NAN priv object from vdev object + * @vdev: pointer to vdev object + * + * Return: pointer to NAN vdev private object + */ +static inline +struct nan_vdev_priv_obj *nan_get_vdev_priv_obj(struct wlan_objmgr_vdev *vdev) +{ + struct nan_vdev_priv_obj *obj; + + if (!vdev) { + nan_err("vdev is null"); + return NULL; + } + obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_UMAC_COMP_NAN); + + return obj; +} + +/** + * nan_get_psoc_priv_obj: get NAN priv object from psoc object + * @psoc: pointer to psoc object + * + * Return: pointer to NAN psoc private object + */ +static inline +struct nan_psoc_priv_obj *nan_get_psoc_priv_obj(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *obj; + + if (!psoc) { + nan_err("psoc is null"); + return NULL; + } + obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_NAN); + + return obj; +} + +/** + * nan_psoc_get_tx_ops: get TX ops from the NAN private object + * @psoc: pointer to psoc object + * + * Return: pointer to TX op callback + */ +static inline +struct wlan_nan_tx_ops *nan_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_priv; + + if (!psoc) { + nan_err("psoc is null"); + return NULL; + } + + nan_priv = nan_get_psoc_priv_obj(psoc); + if (!nan_priv) { + nan_err("psoc private object is null"); + return NULL; + } + + return &nan_priv->tx_ops; +} + +/** + * nan_psoc_get_rx_ops: get RX ops from the NAN private object + * @psoc: pointer to psoc object + * + * Return: pointer to RX op callback + */ +static inline +struct wlan_nan_rx_ops *nan_psoc_get_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_priv; + + if (!psoc) { + nan_err("psoc is null"); + return NULL; + } + + nan_priv = nan_get_psoc_priv_obj(psoc); + if (!nan_priv) { + nan_err("psoc private object is null"); + return NULL; + } + + return &nan_priv->rx_ops; +} + +/** + * wlan_nan_get_connection_info: Get NAN related connection info + * @psoc: pointer to psoc object + * @conn_info: Coonection info structure pointer + * + * Return: status of operation + */ +QDF_STATUS +wlan_nan_get_connection_info(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_vdev_entry_info *conn_info); + +/** + * wlan_nan_get_disc_5g_ch_freq: Get NAN Disc 5G channel frequency + * @psoc: pointer to psoc object + * + * Return: NAN Disc 5G channel frequency + */ +uint32_t wlan_nan_get_disc_5g_ch_freq(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_nan_get_sap_conc_support: Get NAN+SAP conc support + * @psoc: pointer to psoc object + * + * Return: True if NAN+SAP supported else false + */ +bool wlan_nan_get_sap_conc_support(struct wlan_objmgr_psoc *psoc); + +/** + * nan_disable_cleanup: Cleanup NAN state upon NAN disable + * @psoc: pointer to psoc object + * + * Return: Cleanup NAN state upon NAN disable + */ +QDF_STATUS nan_disable_cleanup(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_nan_is_beamforming_supported- Get support for beamforing + * @psoc: pointer to psoc object + * + * Return: True if beamforming is supported, false if not. + */ +bool wlan_nan_is_beamforming_supported(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_is_nan_allowed_on_freq() - Check if NAN is allowed on given freq + * @pdev: pdev context + * @freq: Frequency to be checked + * + * Check if NAN/NDP can be enabled on given frequency. + * + * Return: True if NAN is allowed on the given frequency + */ +bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq); + +/** + * nan_handle_emlsr_concurrency()- Handle NAN+eMLSR concurrency + * @psoc: pointer to psoc object + * @nan_enable: Carries true if NAN is getting enabled. + * Carries false upon NAN enable failure/NAN disabled indication + * + * Return: void + */ +void nan_handle_emlsr_concurrency(struct wlan_objmgr_psoc *psoc, + bool nan_enable); +#else /* WLAN_FEATURE_NAN */ +static inline QDF_STATUS nan_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS nan_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS nan_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_nan_get_connection_info(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_vdev_entry_info *conn_info) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline uint32_t +wlan_nan_get_disc_5g_ch_freq(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline +bool wlan_nan_get_sap_conc_support(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +QDF_STATUS nan_disable_cleanup(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +bool wlan_nan_is_beamforming_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + return false; +} + +static inline void +nan_handle_emlsr_concurrency(struct wlan_objmgr_psoc *psoc, bool nan_enable) +{} +#endif /* WLAN_FEATURE_NAN */ + +#if defined(WLAN_FEATURE_NAN) && defined(WLAN_FEATURE_11BE_MLO) +/** + * wlan_is_mlo_sta_nan_ndi_allowed()- Get support for MLO STA + + * NAN Disc + NDI concurrency + * @psoc: pointer to psoc object + * + * Return: True if mlo sta + nan + ndi concurrency allowed or not. + */ +bool wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +#if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS) +/** + * nan_cstats_log_nan_enable_resp_evt() - Chipset stats NAN enable + * response event + * + * @nan_event: pointer to nan_event_params object + * + * Return: void + */ +void nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event); + +/** + * nan_cstats_log_nan_disable_resp_evt() - Chipset stats NAN disable + * response event + * + * @vdev_id: vdev ID + * @psoc: pointer to psoc object + * + * Return: void + */ +void +nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id, + struct wlan_objmgr_psoc *psoc); +#else +static inline void +nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event) +{ +} + +static inline void +nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif /* WLAN_FEATURE_NAN && WLAN_CHIPSET_STATS */ +#endif /* _WLAN_NAN_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_api.c b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_api.c new file mode 100644 index 0000000000..8146678edf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_api.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan public API function definitions + */ + +#include "nan_main_i.h" +#include "wlan_nan_api.h" +#include "target_if_nan.h" +#include "nan_public_structs.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "nan_ucfg_api.h" +#include + +static QDF_STATUS nan_psoc_obj_created_notification( + struct wlan_objmgr_psoc *psoc, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *nan_obj; + + nan_debug("nan_psoc_create_notif called"); + nan_obj = qdf_mem_malloc(sizeof(*nan_obj)); + if (!nan_obj) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&nan_obj->lock); + status = wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_NAN, + nan_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + nan_alert("obj attach with psoc failed"); + goto nan_psoc_notif_failed; + } + + target_if_nan_register_tx_ops(&nan_obj->tx_ops); + target_if_nan_register_rx_ops(&nan_obj->rx_ops); + + return QDF_STATUS_SUCCESS; + +nan_psoc_notif_failed: + + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + return status; +} + +static QDF_STATUS nan_psoc_obj_destroyed_notification( + struct wlan_objmgr_psoc *psoc, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *nan_obj = nan_get_psoc_priv_obj(psoc); + + nan_debug("nan_psoc_delete_notif called"); + if (!nan_obj) { + nan_err("nan_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_NAN, + nan_obj); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("nan_obj detach failed"); + + nan_debug("nan_obj deleted with status %d", status); + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + + return status; +} + +static QDF_STATUS nan_vdev_obj_created_notification( + struct wlan_objmgr_vdev *vdev, void *arg_list) +{ + struct nan_vdev_priv_obj *nan_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_psoc *psoc; + + nan_debug("nan_vdev_create_notif called"); + if (ucfg_is_nan_vdev(vdev)) { + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + target_if_nan_set_vdev_feature_config(psoc, + wlan_vdev_get_id(vdev)); + } + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_NDI_MODE) { + nan_debug("not a ndi vdev. do nothing"); + return QDF_STATUS_SUCCESS; + } + + nan_obj = qdf_mem_malloc(sizeof(*nan_obj)); + if (!nan_obj) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&nan_obj->lock); + status = wlan_objmgr_vdev_component_obj_attach(vdev, WLAN_UMAC_COMP_NAN, + (void *)nan_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + nan_alert("obj attach with vdev failed"); + goto nan_vdev_notif_failed; + } + + return QDF_STATUS_SUCCESS; + +nan_vdev_notif_failed: + + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + return status; +} + +static QDF_STATUS nan_vdev_obj_destroyed_notification( + struct wlan_objmgr_vdev *vdev, void *arg_list) +{ + struct nan_vdev_priv_obj *nan_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + nan_debug("nan_vdev_delete_notif called"); + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_NDI_MODE) { + nan_debug("not a ndi vdev. do nothing"); + return QDF_STATUS_SUCCESS; + } + + nan_obj = nan_get_vdev_priv_obj(vdev); + if (!nan_obj) { + nan_err("nan_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_vdev_component_obj_detach(vdev, WLAN_UMAC_COMP_NAN, + nan_obj); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("nan_obj detach failed"); + + nan_debug("nan_obj deleted with status %d", status); + qdf_spinlock_destroy(&nan_obj->lock); + qdf_mem_free(nan_obj); + + return status; +} + +/** + * nan_peer_obj_created_notification() - Handler for peer object creation + * notification event + * @peer: Pointer to the PEER Object + * @arg_list: Pointer to private argument - NULL + * + * This function gets called from object manager when peer is being + * created. + * + * Return: QDF_STATUS + */ +static QDF_STATUS nan_peer_obj_created_notification( + struct wlan_objmgr_peer *peer, void *arg_list) +{ + struct nan_peer_priv_obj *nan_peer_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + nan_peer_obj = qdf_mem_malloc(sizeof(*nan_peer_obj)); + if (!nan_peer_obj) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&nan_peer_obj->lock); + status = wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_NAN, + (void *)nan_peer_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + nan_alert("obj attach with peer failed"); + goto nan_peer_notif_failed; + } + + return QDF_STATUS_SUCCESS; + +nan_peer_notif_failed: + + qdf_spinlock_destroy(&nan_peer_obj->lock); + qdf_mem_free(nan_peer_obj); + return status; +} + +/** + * nan_peer_obj_destroyed_notification() - Handler for peer object deletion + * notification event + * @peer: Pointer to the PEER Object + * @arg_list: Pointer to private argument - NULL + * + * This function gets called from object manager when peer is being destroyed. + * + * Return: QDF_STATUS + */ +static QDF_STATUS nan_peer_obj_destroyed_notification( + struct wlan_objmgr_peer *peer, void *arg_list) +{ + struct nan_peer_priv_obj *nan_peer_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + nan_peer_obj = nan_get_peer_priv_obj(peer); + if (!nan_peer_obj) { + nan_err("nan_peer_obj is NULL"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_NAN, + nan_peer_obj); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("nan_peer_obj detach failed"); + + nan_debug("nan_peer_obj deleted with status %d", status); + qdf_spinlock_destroy(&nan_peer_obj->lock); + qdf_mem_free(nan_peer_obj); + + return status; +} + +QDF_STATUS nan_init(void) +{ + QDF_STATUS status; + + /* register psoc create handler functions. */ + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_create_handler failed"); + return status; + } + + /* register psoc delete handler functions. */ + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_destroy_handler failed"); + goto err_psoc_destroy_reg; + } + + /* register vdev create handler functions. */ + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_create_handler failed"); + goto err_vdev_create_reg; + } + + /* register vdev delete handler functions. */ + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_psoc_destroy_handler failed"); + goto err_vdev_destroy_reg; + } + + /* register peer create handler functions. */ + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_NAN, + nan_peer_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_register_peer_create_handler failed"); + goto err_peer_create_reg; + } + + /* register peer delete handler functions. */ + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_peer_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("wlan_objmgr_register_peer_destroy_handler failed"); + else + return QDF_STATUS_SUCCESS; + + wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_NAN, + nan_peer_obj_created_notification, + NULL); +err_peer_create_reg: + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_NAN, + nan_vdev_obj_destroyed_notification, + NULL); +err_vdev_destroy_reg: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_NAN, + nan_vdev_obj_created_notification, + NULL); +err_vdev_create_reg: + wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_NAN, + nan_psoc_obj_destroyed_notification, + NULL); +err_psoc_destroy_reg: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_NAN, + nan_psoc_obj_created_notification, + NULL); + + return status; +} + +QDF_STATUS nan_deinit(void) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS, status; + + /* register psoc create handler functions. */ + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_unregister_psoc_create_handler failed"); + ret = status; + } + + /* register vdev create handler functions. */ + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_deregister_psoc_destroy_handler failed"); + ret = status; + } + + /* de-register vdev create handler functions. */ + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_unregister_psoc_create_handler failed"); + ret = status; + } + + /* de-register vdev delete handler functions. */ + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_vdev_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_deregister_psoc_destroy_handler failed"); + ret = status; + } + + /* de-register peer create handler functions. */ + status = wlan_objmgr_unregister_peer_create_handler( + WLAN_UMAC_COMP_NAN, + nan_peer_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_unregister_peer_create_handler failed"); + ret = status; + } + + /* de-register peer delete handler functions. */ + status = wlan_objmgr_unregister_peer_destroy_handler( + WLAN_UMAC_COMP_NAN, + nan_peer_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("wlan_objmgr_deregister_peer_destroy_handler failed"); + ret = status; + } + + return ret; +} + +QDF_STATUS nan_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = target_if_nan_register_events(psoc); + + if (QDF_IS_STATUS_ERROR(status)) + nan_err("target_if_nan_register_events failed"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = target_if_nan_deregister_events(psoc); + + if (QDF_IS_STATUS_ERROR(status)) + nan_err("target_if_nan_deregister_events failed"); + + return QDF_STATUS_SUCCESS; +} + +static bool +wlan_is_nan_allowed_on_6ghz_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + QDF_STATUS status; + struct regulatory_channel *chan_list; + uint32_t len_6g = + NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel); + uint16_t i; + bool ret = false; + + chan_list = qdf_mem_malloc(len_6g); + if (!chan_list) + return ret; + + status = wlan_reg_get_6g_ap_master_chan_list(pdev, + REG_VERY_LOW_POWER_AP, + chan_list); + + for (i = 0; i < NUM_6GHZ_CHANNELS; i++) { + if ((freq == chan_list[i].center_freq) && + (chan_list[i].state == CHANNEL_STATE_ENABLE)) { + ret = true; + goto end; + } + } + +end: + qdf_mem_free(chan_list); + return ret; +} + +bool wlan_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + bool nan_allowed = true; + + /* Check for 6GHz channels */ + if (wlan_reg_is_6ghz_chan_freq(freq)) { + nan_allowed = wlan_is_nan_allowed_on_6ghz_freq(pdev, freq); + return nan_allowed; + } + + /* Check for SRD channels */ + if (wlan_reg_is_etsi_srd_chan_for_freq(pdev, freq)) + wlan_mlme_get_srd_master_mode_for_vdev(wlan_pdev_get_psoc(pdev), + QDF_NAN_DISC_MODE, + &nan_allowed); + + /* Check for Indoor channels */ + if (wlan_reg_is_freq_indoor(pdev, freq)) + wlan_mlme_get_indoor_support_for_nan(wlan_pdev_get_psoc(pdev), + &nan_allowed); + /* + * Check for dfs only if channel is not indoor, + * Check for passive channels as well + */ + else if (wlan_reg_is_dfs_for_freq(pdev, freq) || + wlan_reg_is_passive_for_freq(pdev, freq)) + nan_allowed = false; + + return nan_allowed; +} + +#ifdef WLAN_FEATURE_11BE_MLO +bool wlan_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return false; + } + + return psoc_nan_obj->nan_caps.mlo_sta_nan_ndi_allowed; +} +#endif + +#if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS) +void nan_cstats_log_nan_enable_resp_evt(struct nan_event_params *nan_event) +{ + struct cstats_nan_disc_enable_resp stat = {0}; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(nan_event->psoc, + nan_event->vdev_id, + WLAN_NAN_ID); + if (!vdev) { + nan_err("Invalid vdev!"); + return; + } + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_NAN_DISCOVERY_ENABLE_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_disc_enable_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.is_enable_success = nan_event->is_nan_enable_success; + stat.mac_id = nan_event->mac_id; + stat.disc_state = nan_get_discovery_state(nan_event->psoc); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_enable_resp), + &stat); +} + +void nan_cstats_log_nan_disable_resp_evt(uint8_t vdev_id, + struct wlan_objmgr_psoc *psoc) +{ + struct cstats_nan_disc_disable_resp stat = {0}; + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_NAN_DISCOVERY_DISABLE_RESP_EVENT_ID; + stat.cmn.hdr.length = + sizeof(struct cstats_nan_disc_disable_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = QDF_NAN_DISC_MODE; + stat.cmn.vdev_id = vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.disc_state = nan_get_discovery_state(psoc); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_disable_resp), + &stat); +} +#endif /* WLAN_CHIPSET_STATS */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_main.c b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_main.c new file mode 100644 index 0000000000..2d71664ea6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_main.c @@ -0,0 +1,1597 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains core nan function definitions + */ + +#include "wlan_utility.h" +#include "nan_ucfg_api.h" +#include "wlan_nan_api.h" +#include "target_if_nan.h" +#include "scheduler_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_osif_request_manager.h" +#include "wlan_serialization_api.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_tdls_ucfg_api.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "qdf_platform.h" +#include "wlan_osif_request_manager.h" +#include "wlan_p2p_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" + +QDF_STATUS nan_set_discovery_state(struct wlan_objmgr_psoc *psoc, + enum nan_disc_state new_state) +{ + enum nan_disc_state cur_state; + struct nan_psoc_priv_obj *psoc_priv = nan_get_psoc_priv_obj(psoc); + bool nan_state_change_allowed = false; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&psoc_priv->lock); + cur_state = psoc_priv->disc_state; + if (cur_state == new_state) { + qdf_spin_unlock_bh(&psoc_priv->lock); + nan_err("curr_state: %u and new state: %u are same", + cur_state, new_state); + return status; + } + + switch (new_state) { + case NAN_DISC_DISABLED: + nan_state_change_allowed = true; + break; + case NAN_DISC_ENABLE_IN_PROGRESS: + if (cur_state == NAN_DISC_DISABLED) + nan_state_change_allowed = true; + break; + case NAN_DISC_ENABLED: + if (cur_state == NAN_DISC_ENABLE_IN_PROGRESS) + nan_state_change_allowed = true; + break; + case NAN_DISC_DISABLE_IN_PROGRESS: + if (cur_state == NAN_DISC_ENABLE_IN_PROGRESS || + cur_state == NAN_DISC_ENABLED) + nan_state_change_allowed = true; + break; + default: + break; + } + + if (nan_state_change_allowed) { + psoc_priv->disc_state = new_state; + status = QDF_STATUS_SUCCESS; + } + + qdf_spin_unlock_bh(&psoc_priv->lock); + + nan_debug("NAN State transitioned from %d -> %d", cur_state, + psoc_priv->disc_state); + + return status; +} + +enum nan_disc_state nan_get_discovery_state(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_priv = nan_get_psoc_priv_obj(psoc); + + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return NAN_DISC_DISABLED; + } + + return psoc_priv->disc_state; +} + +void nan_release_cmd(void *in_req, uint32_t cmdtype) +{ + struct wlan_objmgr_vdev *vdev = NULL; + + if (!in_req) + return; + + switch (cmdtype) { + case WLAN_SER_CMD_NDP_INIT_REQ: { + struct nan_datapath_initiator_req *req = in_req; + + vdev = req->vdev; + break; + } + case WLAN_SER_CMD_NDP_RESP_REQ: { + struct nan_datapath_responder_req *req = in_req; + + vdev = req->vdev; + break; + } + case WLAN_SER_CMD_NDP_DATA_END_INIT_REQ: { + struct nan_datapath_end_req *req = in_req; + + vdev = req->vdev; + break; + } + case WLAN_SER_CMD_NDP_END_ALL_REQ: { + struct nan_datapath_end_all_ndps *req = in_req; + + vdev = req->vdev; + break; + } + default: + nan_err("invalid req type: %d", cmdtype); + break; + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + else + nan_err("vdev is null"); + + qdf_mem_free(in_req); +} + +static void nan_req_incomplete(void *req, uint32_t cmdtype) +{ + /* send msg to userspace if needed that cmd got incomplete */ +} + +static void nan_req_activated(void *in_req, uint32_t cmdtype) +{ + uint32_t req_type; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct wlan_nan_tx_ops *tx_ops; + struct nan_psoc_priv_obj *psoc_nan_obj; + + switch (cmdtype) { + case WLAN_SER_CMD_NDP_INIT_REQ: { + struct nan_datapath_initiator_req *req = in_req; + + vdev = req->vdev; + req_type = NDP_INITIATOR_REQ; + break; + } + case WLAN_SER_CMD_NDP_RESP_REQ: { + struct nan_datapath_responder_req *req = in_req; + + vdev = req->vdev; + req_type = NDP_RESPONDER_REQ; + break; + } + case WLAN_SER_CMD_NDP_DATA_END_INIT_REQ: { + struct nan_datapath_end_req *req = in_req; + + vdev = req->vdev; + req_type = NDP_END_REQ; + break; + } + case WLAN_SER_CMD_NDP_END_ALL_REQ: { + struct nan_datapath_end_all_ndps *req = in_req; + + vdev = req->vdev; + req_type = NDP_END_ALL; + break; + } + default: + nan_alert("in correct cmdtype: %d", cmdtype); + return; + } + + if (!vdev) { + nan_alert("vdev is null"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + nan_alert("psoc is null"); + return; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return; + } + + tx_ops = &psoc_nan_obj->tx_ops; + if (!tx_ops) { + nan_alert("tx_ops is null"); + return; + } + + /* send ndp_intiator_req/responder_req/end_req to FW */ + tx_ops->nan_datapath_req_tx(in_req, req_type); +} + +static QDF_STATUS nan_serialized_cb(struct wlan_serialization_command *ser_cmd, + enum wlan_serialization_cb_reason reason) +{ + void *req; + + if (!ser_cmd || !ser_cmd->umac_cmd) { + nan_alert("cmd or umac_cmd is null"); + return QDF_STATUS_E_NULL_VALUE; + } + req = ser_cmd->umac_cmd; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + nan_req_activated(req, ser_cmd->cmd_type); + break; + case WLAN_SER_CB_CANCEL_CMD: + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + nan_req_incomplete(req, ser_cmd->cmd_type); + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + nan_release_cmd(req, ser_cmd->cmd_type); + break; + default: + /* Do nothing but logging */ + nan_alert("invalid serialized cb reason: %d", reason); + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg) +{ + enum wlan_serialization_status status = 0; + struct wlan_serialization_command cmd = {0}; + + if (!msg || !msg->bodyptr) { + nan_alert("msg or bodyptr is null"); + return QDF_STATUS_E_NULL_VALUE; + } + switch (msg->type) { + case NDP_INITIATOR_REQ: { + struct nan_datapath_initiator_req *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_INIT_REQ; + cmd.vdev = req->vdev; + break; + } + case NDP_RESPONDER_REQ: { + struct nan_datapath_responder_req *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_RESP_REQ; + cmd.vdev = req->vdev; + break; + } + case NDP_END_REQ: { + struct nan_datapath_end_req *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_DATA_END_INIT_REQ; + cmd.vdev = req->vdev; + break; + } + case NDP_END_ALL: { + struct nan_datapath_end_all_ndps *req = msg->bodyptr; + + cmd.cmd_type = WLAN_SER_CMD_NDP_END_ALL_REQ; + cmd.vdev = req->vdev; + break; + } + default: + nan_err("wrong request type: %d", msg->type); + return QDF_STATUS_E_INVAL; + } + + /* TBD - support more than one req of same type or avoid */ + cmd.cmd_id = 0; + cmd.cmd_cb = nan_serialized_cb; + cmd.umac_cmd = msg->bodyptr; + cmd.source = WLAN_UMAC_COMP_NAN; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = NAN_SER_CMD_TIMEOUT; + nan_debug("cmd_type: %d", cmd.cmd_type); + cmd.is_blocking = true; + + status = wlan_serialization_request(&cmd); + /* following is TBD */ + if (status != WLAN_SER_CMD_ACTIVE && status != WLAN_SER_CMD_PENDING) { + nan_err("unable to serialize command"); + wlan_objmgr_vdev_release_ref(cmd.vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +nan_increment_ndp_sessions(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_ndi_mac, + struct nan_datapath_channel_info *ndp_chan_info) +{ + struct wlan_objmgr_peer *peer; + struct nan_peer_priv_obj *peer_nan_obj; + + peer = wlan_objmgr_get_peer_by_mac(psoc, + peer_ndi_mac->bytes, + WLAN_NAN_ID); + + if (!peer) { + nan_err("peer object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_nan_obj = nan_get_peer_priv_obj(peer); + if (!peer_nan_obj) { + nan_err("peer_nan_obj is null"); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_spin_lock_bh(&peer_nan_obj->lock); + + /* + * Store the first channel info in NDP Confirm as the home channel info + * and store it in the peer private object. + */ + if (!peer_nan_obj->active_ndp_sessions) + qdf_mem_copy(&peer_nan_obj->home_chan_info, ndp_chan_info, + sizeof(struct nan_datapath_channel_info)); + + peer_nan_obj->active_ndp_sessions++; + nan_debug("Number of active session = %d for peer:"QDF_MAC_ADDR_FMT, + peer_nan_obj->active_ndp_sessions, + QDF_MAC_ADDR_REF(peer_ndi_mac->bytes)); + qdf_spin_unlock_bh(&peer_nan_obj->lock); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_decrement_ndp_sessions(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_ndi_mac) +{ + struct wlan_objmgr_peer *peer; + struct nan_peer_priv_obj *peer_nan_obj; + + peer = wlan_objmgr_get_peer_by_mac(psoc, + peer_ndi_mac->bytes, + WLAN_NAN_ID); + + if (!peer) { + nan_err("peer object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_nan_obj = nan_get_peer_priv_obj(peer); + if (!peer_nan_obj) { + nan_err("peer_nan_obj is null"); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&peer_nan_obj->lock); + if (!peer_nan_obj->active_ndp_sessions) { + qdf_spin_unlock_bh(&peer_nan_obj->lock); + nan_err("Active NDP sessions already zero!"); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + return QDF_STATUS_E_FAILURE; + } + peer_nan_obj->active_ndp_sessions--; + nan_debug("Number of active session = %d for peer:"QDF_MAC_ADDR_FMT, + peer_nan_obj->active_ndp_sessions, + QDF_MAC_ADDR_REF(peer_ndi_mac->bytes)); + qdf_spin_unlock_bh(&peer_nan_obj->lock); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ndi_remove_and_update_primary_connection(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct nan_vdev_priv_obj *vdev_nan_obj; + struct nan_psoc_priv_obj *psoc_nan_obj; + struct nan_peer_priv_obj *peer_nan_obj = NULL; + struct wlan_objmgr_peer *peer, *peer_next; + qdf_list_t *peer_list; + void (*nan_conc_callback)(void); + + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("Invalid psoc nan private obj"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_nan_obj = nan_get_vdev_priv_obj(vdev); + if (!vdev_nan_obj) { + nan_err("Invalid vdev nan private obj"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + nan_err("Peer list for vdev obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_NAN_ID); + + while (peer) { + peer_nan_obj = nan_get_peer_priv_obj(peer); + if (!peer_nan_obj) + nan_err("NAN peer object for Peer " QDF_MAC_ADDR_FMT " is NULL", + QDF_MAC_ADDR_REF(wlan_peer_get_macaddr(peer))); + else if (peer_nan_obj->active_ndp_sessions) + break; + + peer_next = wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_NAN_ID); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + peer = peer_next; + } + + if (!peer && NDI_CONCURRENCY_SUPPORTED(psoc)) { + policy_mgr_decr_session_set_pcl(psoc, QDF_NDI_MODE, + wlan_vdev_get_id(vdev)); + vdev_nan_obj->ndp_init_done = false; + + nan_conc_callback = psoc_nan_obj->cb_obj.nan_concurrency_update; + if (nan_conc_callback) + nan_conc_callback(); + + return QDF_STATUS_SUCCESS; + } + + if (peer_nan_obj && NDI_CONCURRENCY_SUPPORTED(psoc)) { + psoc_nan_obj->cb_obj.update_ndi_conn(wlan_vdev_get_id(vdev), + &peer_nan_obj->home_chan_info); + policy_mgr_update_connection_info(psoc, wlan_vdev_get_id(vdev)); + qdf_mem_copy(vdev_nan_obj->primary_peer_mac.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + policy_mgr_check_n_start_opportunistic_timer(psoc); + } + + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ndi_update_ndp_session(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_ndi_mac, + struct nan_datapath_channel_info *ndp_chan_info) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer; + struct nan_psoc_priv_obj *psoc_nan_obj; + struct nan_vdev_priv_obj *vdev_nan_obj; + struct nan_peer_priv_obj *peer_nan_obj; + + psoc = wlan_vdev_get_psoc(vdev); + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_nan_obj = nan_get_vdev_priv_obj(vdev); + if (!vdev_nan_obj) { + nan_err("NAN vdev private object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, + peer_ndi_mac->bytes, + WLAN_NAN_ID); + + if (!peer) { + nan_err("peer object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_nan_obj = nan_get_peer_priv_obj(peer); + if (!peer_nan_obj) { + nan_err("peer_nan_obj is null"); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&peer_nan_obj->lock); + qdf_mem_copy(&peer_nan_obj->home_chan_info, ndp_chan_info, + sizeof(*ndp_chan_info)); + psoc_nan_obj->cb_obj.update_ndi_conn(wlan_vdev_get_id(vdev), + &peer_nan_obj->home_chan_info); + qdf_spin_unlock_bh(&peer_nan_obj->lock); + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + + if (qdf_is_macaddr_equal(&vdev_nan_obj->primary_peer_mac, + peer_ndi_mac)) { + /* TODO: Update policy mgr with connection info */ + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ndi_update_policy_mgr_conn_table(struct nan_datapath_confirm_event *confirm, + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (policy_mgr_is_hw_dbs_capable(psoc)) { + status = policy_mgr_update_and_wait_for_connection_update(psoc, + vdev_id, confirm->ch[0].freq, + POLICY_MGR_UPDATE_REASON_NDP_UPDATE); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Failed to set or wait for HW mode change"); + return status; + } + } + + policy_mgr_incr_active_session(psoc, QDF_NDI_MODE, vdev_id); + + return status; +} + +static QDF_STATUS nan_handle_confirm(struct nan_datapath_confirm_event *confirm) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + struct nan_vdev_priv_obj *vdev_nan_obj; + struct wlan_objmgr_peer *peer; + void (*nan_conc_callback)(void); + + vdev_id = wlan_vdev_get_id(confirm->vdev); + psoc = wlan_vdev_get_psoc(confirm->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, + confirm->peer_ndi_mac_addr.bytes, + WLAN_NAN_ID); + if (!peer && confirm->rsp_code == NAN_DATAPATH_RESPONSE_ACCEPT) { + nan_debug("Drop NDP confirm as peer isn't available"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_NAN_ID); + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_nan_obj = nan_get_vdev_priv_obj(confirm->vdev); + if (!vdev_nan_obj) { + nan_err("vdev_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (confirm->rsp_code != NAN_DATAPATH_RESPONSE_ACCEPT && + confirm->num_active_ndps_on_peer == 0) { + /* + * This peer was created at ndp_indication but + * confirm failed, so it needs to be deleted + */ + nan_err("NDP confirm with reject and no active ndp sessions. deleting peer: "QDF_MAC_ADDR_FMT" on vdev_id: %d", + QDF_MAC_ADDR_REF(confirm->peer_ndi_mac_addr.bytes), + vdev_id); + psoc_nan_obj->cb_obj.delete_peers_by_addr(vdev_id, + confirm->peer_ndi_mac_addr); + } + + /* Increment NDP sessions for the Peer */ + if (confirm->rsp_code == NAN_DATAPATH_RESPONSE_ACCEPT) + nan_increment_ndp_sessions(psoc, &confirm->peer_ndi_mac_addr, + &confirm->ch[0]); + + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, confirm->vdev, + NDP_CONFIRM, confirm); + + if (confirm->rsp_code == NAN_DATAPATH_RESPONSE_ACCEPT && + !vdev_nan_obj->ndp_init_done) { + /* + * If this is the NDI's first NDP, store the NDP instance in + * vdev object as its primary connection. If this instance ends + * the second NDP should take its place. + */ + qdf_mem_copy(vdev_nan_obj->primary_peer_mac.bytes, + &confirm->peer_ndi_mac_addr, QDF_MAC_ADDR_SIZE); + + psoc_nan_obj->cb_obj.update_ndi_conn(vdev_id, &confirm->ch[0]); + + if (NAN_CONCURRENCY_SUPPORTED(psoc)) { + ndi_update_policy_mgr_conn_table(confirm, psoc, + vdev_id); + vdev_nan_obj->ndp_init_done = true; + + nan_conc_callback = psoc_nan_obj->cb_obj.nan_concurrency_update; + if (nan_conc_callback) + nan_conc_callback(); + } + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_initiator_rsp( + struct nan_datapath_initiator_rsp *rsp, + struct wlan_objmgr_vdev **vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + *vdev = rsp->vdev; + psoc = wlan_vdev_get_psoc(rsp->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, rsp->vdev, + NDP_INITIATOR_RSP, rsp); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_ndp_ind( + struct nan_datapath_indication_event *ndp_ind) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *psoc_nan_obj; + + vdev_id = wlan_vdev_get_id(ndp_ind->vdev); + psoc = wlan_vdev_get_psoc(ndp_ind->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_debug("role: %d, vdev: %d, csid: %d, peer_mac_addr " + QDF_MAC_ADDR_FMT, + ndp_ind->role, vdev_id, ndp_ind->ncs_sk_type, + QDF_MAC_ADDR_REF(ndp_ind->peer_mac_addr.bytes)); + + if ((ndp_ind->role == NAN_DATAPATH_ROLE_INITIATOR) || + ((NAN_DATAPATH_ROLE_RESPONDER == ndp_ind->role) && + (NAN_DATAPATH_ACCEPT_POLICY_ALL == ndp_ind->policy))) { + status = psoc_nan_obj->cb_obj.add_ndi_peer(vdev_id, + ndp_ind->peer_mac_addr); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't add ndi peer, ndp_role: %d", + ndp_ind->role); + return status; + } + } + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, + ndp_ind->vdev, + NDP_INDICATION, + ndp_ind); + + return status; +} + +static QDF_STATUS nan_handle_responder_rsp( + struct nan_datapath_responder_rsp *rsp, + struct wlan_objmgr_vdev **vdev) +{ + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nan_psoc_priv_obj *psoc_nan_obj; + + *vdev = rsp->vdev; + psoc = wlan_vdev_get_psoc(rsp->vdev); + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (QDF_IS_STATUS_SUCCESS(rsp->status) && rsp->create_peer) { + status = psoc_nan_obj->cb_obj.add_ndi_peer( + wlan_vdev_get_id(rsp->vdev), + rsp->peer_mac_addr); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't add ndi peer"); + rsp->status = QDF_STATUS_E_FAILURE; + } + } + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, rsp->vdev, + NDP_RESPONDER_RSP, rsp); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_ndp_end_rsp( + struct nan_datapath_end_rsp_event *rsp, + struct wlan_objmgr_vdev **vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + struct osif_request *request; + + *vdev = rsp->vdev; + psoc = wlan_vdev_get_psoc(rsp->vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* Unblock the wait here if NDP_END request is a failure */ + if (rsp->status != 0) { + request = osif_request_get(psoc_nan_obj->ndp_request_ctx); + if (request) { + osif_request_complete(request); + osif_request_put(request); + } + } + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, rsp->vdev, + NDP_END_RSP, rsp); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_end_ind( + struct nan_datapath_end_indication_event *ind) +{ + uint32_t i; + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + struct wlan_objmgr_vdev *vdev_itr; + struct nan_vdev_priv_obj *vdev_nan_obj; + struct osif_request *request; + + psoc = wlan_vdev_get_psoc(ind->vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* Decrement NDP sessions for all Peers in the event */ + for (i = 0; i < ind->num_ndp_ids; i++) + nan_decrement_ndp_sessions(psoc, + &ind->ndp_map[i].peer_ndi_mac_addr); + + for (i = 0; i < ind->num_ndp_ids; i++) { + vdev_itr = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + ind->ndp_map[i].vdev_id, + WLAN_NAN_ID); + if (!vdev_itr) { + nan_err("NAN vdev object is NULL"); + continue; + } + + vdev_nan_obj = nan_get_vdev_priv_obj(vdev_itr); + if (!vdev_nan_obj) { + wlan_objmgr_vdev_release_ref(vdev_itr, WLAN_NAN_ID); + nan_err("NAN vdev private object is NULL"); + continue; + } + + if (qdf_is_macaddr_equal(&vdev_nan_obj->primary_peer_mac, + &ind->ndp_map[i].peer_ndi_mac_addr)) + ndi_remove_and_update_primary_connection(psoc, + vdev_itr); + + wlan_objmgr_vdev_release_ref(vdev_itr, WLAN_NAN_ID); + } + + psoc_nan_obj->cb_obj.ndp_delete_peers(ind->ndp_map, ind->num_ndp_ids); + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, ind->vdev, + NDP_END_IND, ind); + + /* Unblock the NDP_END wait */ + request = osif_request_get(psoc_nan_obj->ndp_request_ctx); + if (request) { + osif_request_complete(request); + osif_request_put(request); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS nan_handle_enable_rsp(struct nan_event_params *nan_event) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + void (*call_back)(void *cookie); + uint8_t vdev_id; + void (*nan_conc_callback)(void); + + psoc = nan_event->psoc; + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (nan_event->is_nan_enable_success) { + status = nan_set_discovery_state(psoc, NAN_DISC_ENABLED); + + if (QDF_IS_STATUS_SUCCESS(status)) { + psoc_nan_obj->nan_disc_mac_id = nan_event->mac_id; + vdev_id = nan_event->vdev_id; + if (!ucfg_nan_is_vdev_creation_allowed(psoc)) { + vdev_id = NAN_PSEUDO_VDEV_ID; + } else if (vdev_id >= WLAN_MAX_VDEVS) { + nan_err("Invalid NAN vdev_id: %u", vdev_id); + goto fail; + } + nan_debug("NAN vdev_id: %u", vdev_id); + policy_mgr_incr_active_session(psoc, QDF_NAN_DISC_MODE, + vdev_id); + policy_mgr_process_force_scc_for_nan(psoc); + + } else { + /* + * State set to DISABLED OR DISABLE_IN_PROGRESS, try to + * restore the single MAC mode. + */ + psoc_nan_obj->nan_social_ch_2g_freq = 0; + psoc_nan_obj->nan_social_ch_5g_freq = 0; + policy_mgr_check_n_start_opportunistic_timer(psoc); + } + goto done; + } else { + nan_info("NAN enable has failed"); + /* NAN Enable has failed, restore changes */ + goto fail; + } + +fail: + psoc_nan_obj->nan_social_ch_2g_freq = 0; + psoc_nan_obj->nan_social_ch_5g_freq = 0; + nan_set_discovery_state(psoc, NAN_DISC_DISABLED); + if (ucfg_is_nan_dbs_supported(psoc)) + policy_mgr_check_n_start_opportunistic_timer(psoc); + + /* + * If FW respond with NAN enable failure, then TDLS should be enable + * again if there is TDLS connection exist earlier. + * decrement the active TDLS session. + */ + ucfg_tdls_notify_connect_failure(psoc); + +done: + nan_cstats_log_nan_enable_resp_evt(nan_event); + + nan_conc_callback = psoc_nan_obj->cb_obj.nan_concurrency_update; + if (nan_conc_callback) + nan_conc_callback(); + call_back = psoc_nan_obj->cb_obj.ucfg_nan_request_process_cb; + if (call_back) + call_back(psoc_nan_obj->nan_disc_request_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_disable_cleanup(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + QDF_STATUS status; + uint8_t vdev_id; + void (*nan_conc_callback)(void); + + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = nan_set_discovery_state(psoc, NAN_DISC_DISABLED); + if (QDF_IS_STATUS_SUCCESS(status)) { + void (*call_back)(void *cookie); + + call_back = psoc_nan_obj->cb_obj.ucfg_nan_request_process_cb; + vdev_id = policy_mgr_mode_specific_vdev_id(psoc, + PM_NAN_DISC_MODE); + nan_debug("NAN vdev_id: %u", vdev_id); + policy_mgr_decr_session_set_pcl(psoc, QDF_NAN_DISC_MODE, + vdev_id); + if (psoc_nan_obj->is_explicit_disable && call_back) + call_back(psoc_nan_obj->nan_disc_request_ctx); + + nan_handle_emlsr_concurrency(psoc, false); + policy_mgr_nan_sap_post_disable_conc_check(psoc); + nan_cstats_log_nan_disable_resp_evt(vdev_id, psoc); + } else { + /* Should not happen, NAN state can always be disabled */ + nan_err("Cannot set NAN state to disabled!"); + return QDF_STATUS_E_FAILURE; + } + nan_conc_callback = psoc_nan_obj->cb_obj.nan_concurrency_update; + if (nan_conc_callback) + nan_conc_callback(); + + return status; +} + +static QDF_STATUS nan_handle_disable_ind(struct nan_event_params *nan_event) +{ + return nan_disable_cleanup(nan_event->psoc); +} + +static QDF_STATUS nan_handle_schedule_update( + struct nan_datapath_sch_update_event *ind) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc = wlan_vdev_get_psoc(ind->vdev); + if (!psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + ndi_update_ndp_session(ind->vdev, &ind->peer_addr, &ind->ch[0]); + psoc_nan_obj->cb_obj.os_if_ndp_event_handler(psoc, ind->vdev, + NDP_SCHEDULE_UPDATE, ind); + + return QDF_STATUS_SUCCESS; +} + +/** + * nan_handle_host_update() - extract the vdev from host event + * @evt: Event data received from firmware + * @vdev: pointer to vdev + * + * Return: none + */ +static void nan_handle_host_update(struct nan_datapath_host_event *evt, + struct wlan_objmgr_vdev **vdev) +{ + *vdev = evt->vdev; +} + +QDF_STATUS nan_discovery_event_handler(struct scheduler_msg *msg) +{ + struct nan_event_params *nan_event; + struct nan_psoc_priv_obj *psoc_nan_obj; + + if (!msg || !msg->bodyptr) { + nan_err("msg body is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_event = msg->bodyptr; + if (!nan_event->psoc) { + nan_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(nan_event->psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (msg->type) { + case nan_event_id_enable_rsp: + nan_handle_enable_rsp(nan_event); + break; + case nan_event_id_disable_ind: + nan_handle_disable_ind(nan_event); + break; + case nan_event_id_generic_rsp: + case nan_event_id_error_rsp: + break; + default: + nan_err("Unknown event ID type - %d", msg->type); + break; + } + + psoc_nan_obj->cb_obj.os_if_nan_event_handler(nan_event); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_datapath_event_handler(struct scheduler_msg *pe_msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_serialization_queued_cmd_info cmd; + + cmd.requestor = WLAN_UMAC_COMP_NAN; + cmd.cmd_id = 0; + cmd.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; + cmd.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; + + if (!pe_msg->bodyptr) { + nan_err("msg body is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (pe_msg->type) { + case NDP_CONFIRM: { + nan_handle_confirm(pe_msg->bodyptr); + break; + } + case NDP_INITIATOR_RSP: { + nan_handle_initiator_rsp(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_INIT_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + } + case NDP_INDICATION: { + nan_handle_ndp_ind(pe_msg->bodyptr); + break; + } + case NDP_RESPONDER_RSP: + nan_handle_responder_rsp(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_RESP_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + case NDP_END_RSP: + nan_handle_ndp_end_rsp(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_DATA_END_INIT_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + case NDP_END_IND: + nan_handle_end_ind(pe_msg->bodyptr); + break; + case NDP_SCHEDULE_UPDATE: + nan_handle_schedule_update(pe_msg->bodyptr); + break; + case NDP_HOST_UPDATE: + nan_handle_host_update(pe_msg->bodyptr, &cmd.vdev); + cmd.cmd_type = WLAN_SER_CMD_NDP_END_ALL_REQ; + wlan_serialization_remove_cmd(&cmd); + break; + default: + nan_alert("Unhandled NDP event: %d", pe_msg->type); + status = QDF_STATUS_E_NOSUPPORT; + break; + } + return status; +} + +bool nan_is_enable_allowed(struct wlan_objmgr_psoc *psoc, uint32_t nan_ch_freq, + uint8_t vdev_id) +{ + if (!psoc) { + nan_err("psoc object object is NULL"); + return false; + } + + return (NAN_DISC_DISABLED == nan_get_discovery_state(psoc) && + policy_mgr_allow_concurrency(psoc, PM_NAN_DISC_MODE, + nan_ch_freq, HW_MODE_20_MHZ, + 0, vdev_id)); +} + +bool nan_is_disc_active(struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + nan_err("psoc object object is NULL"); + return false; + } + + return (NAN_DISC_ENABLED == nan_get_discovery_state(psoc) || + NAN_DISC_ENABLE_IN_PROGRESS == nan_get_discovery_state(psoc)); +} + +static QDF_STATUS nan_set_hw_mode(struct wlan_objmgr_psoc *psoc, + uint32_t nan_ch_freq) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_objmgr_pdev *pdev = NULL; + struct wlan_objmgr_vdev *vdev = NULL; + uint8_t vdev_id; + + policy_mgr_stop_opportunistic_timer(psoc); + + if (policy_mgr_is_hw_mode_change_in_progress(psoc)) { + status = policy_mgr_wait_for_connection_update(psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + nan_err("Failed to wait for connection update"); + goto pre_enable_failure; + } + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_NAN_ID); + if (!pdev) { + nan_err("null pdev"); + status = QDF_STATUS_E_INVAL; + goto pre_enable_failure; + } + + /* Piggyback on any available vdev for policy manager update */ + vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_NAN_ID); + if (!vdev) { + nan_err("No vdev is up yet, unable to proceed!"); + status = QDF_STATUS_E_INVAL; + goto pre_enable_failure; + } + vdev_id = wlan_vdev_get_id(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + status = policy_mgr_update_and_wait_for_connection_update(psoc, vdev_id, + nan_ch_freq, + POLICY_MGR_UPDATE_REASON_NAN_DISCOVERY); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Failed to set or wait for HW mode change"); + goto pre_enable_failure; + } + + if (wlan_util_is_vdev_in_cac_wait(pdev, WLAN_NAN_ID)) { + nan_err_rl("cac is in progress"); + status = QDF_STATUS_E_FAILURE; + goto pre_enable_failure; + } + +pre_enable_failure: + if (pdev) + wlan_objmgr_pdev_release_ref(pdev, WLAN_NAN_ID); + + return status; +} + +void nan_handle_emlsr_concurrency(struct wlan_objmgr_psoc *psoc, + bool nan_enable) +{ + if (nan_enable) { + /* + * Check if any set link is already progress, + * wait for it to complete + */ + policy_mgr_wait_for_set_link_update(psoc); + + wlan_handle_emlsr_sta_concurrency(psoc, true, false); + + /* Wait till rsp is received if NAN enable causes a set link */ + policy_mgr_wait_for_set_link_update(psoc); + } else { + wlan_handle_emlsr_sta_concurrency(psoc, false, true); + } +} + +bool nan_is_sta_sta_concurrency_present(struct wlan_objmgr_psoc *psoc) +{ + uint32_t sta_cnt; + + sta_cnt = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + /* Allow if STA is not in connected state */ + if (!sta_cnt) + return false; + + /* + * sta > 2 : (STA + STA + STA) or (ML STA + STA) or (ML STA + ML STA), + * STA concurrency will be present. + * + * ML STA: Although both links would be treated as separate STAs + * (sta cnt = 2) from policy mgr perspective, but it is not considered + * as STA concurrency + */ + if (sta_cnt > 2 || + (sta_cnt == 2 && policy_mgr_is_non_ml_sta_present(psoc))) + return true; + + return false; +} + +QDF_STATUS nan_discovery_pre_enable(struct wlan_objmgr_pdev *pdev, + uint32_t nan_ch_freq) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) { + nan_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + status = nan_set_discovery_state(psoc, NAN_DISC_ENABLE_IN_PROGRESS); + + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Unable to set NAN Disc State to ENABLE_IN_PROGRESS"); + goto pre_enable_failure; + } + + if ((policy_mgr_get_sap_mode_count(psoc, NULL)) && + !policy_mgr_nan_sap_pre_enable_conc_check(psoc, PM_NAN_DISC_MODE, + nan_ch_freq)) { + nan_debug("NAN not enabled due to concurrency constraints"); + status = QDF_STATUS_E_INVAL; + goto pre_enable_failure; + } + + /* + * Reject STA+STA in below case + * Non-ML STA: STA+STA+NAN concurrency is not supported + */ + if (nan_is_sta_sta_concurrency_present(psoc)) { + nan_err("STA+STA+NAN concurrency is not allowed"); + status = QDF_STATUS_E_FAILURE; + goto pre_enable_failure; + } + + wlan_p2p_abort_scan(pdev); + + if (policy_mgr_is_hw_dbs_capable(psoc)) { + status = nan_set_hw_mode(psoc, nan_ch_freq); + if (QDF_IS_STATUS_ERROR(status)) + goto pre_enable_failure; + } + + nan_handle_emlsr_concurrency(psoc, true); + + /* Try to teardown TDLS links, but do not wait */ + status = ucfg_tdls_teardown_links(psoc); + if (QDF_IS_STATUS_ERROR(status)) + nan_err("Failed to teardown TDLS links"); + +pre_enable_failure: + if (QDF_IS_STATUS_ERROR(status)) + nan_set_discovery_state(psoc, NAN_DISC_DISABLED); + + return status; +} + +static QDF_STATUS nan_discovery_disable_req(struct nan_disable_req *req) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + struct wlan_nan_tx_ops *tx_ops; + + /* + * State was already set to Disabled by failed Enable + * request OR by the Disable Indication event, drop the + * Disable request. + */ + if (NAN_DISC_DISABLED == nan_get_discovery_state(req->psoc)) + return QDF_STATUS_SUCCESS; + + psoc_nan_obj = nan_get_psoc_priv_obj(req->psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + tx_ops = &psoc_nan_obj->tx_ops; + if (!tx_ops->nan_discovery_req_tx) { + nan_err("NAN Discovery tx op is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + return tx_ops->nan_discovery_req_tx(req, NAN_DISABLE_REQ); +} + +static QDF_STATUS nan_discovery_enable_req(struct nan_enable_req *req) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + struct wlan_nan_tx_ops *tx_ops; + + /* + * State was already set to Disable in progress by a disable request, + * drop the Enable request, start opportunistic timer and move back to + * the Disabled state. + */ + if (NAN_DISC_DISABLE_IN_PROGRESS == + nan_get_discovery_state(req->psoc)) { + policy_mgr_check_n_start_opportunistic_timer(req->psoc); + return nan_set_discovery_state(req->psoc, NAN_DISC_DISABLED); + } + + psoc_nan_obj = nan_get_psoc_priv_obj(req->psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_nan_obj->nan_social_ch_2g_freq = req->social_chan_2g_freq; + psoc_nan_obj->nan_social_ch_5g_freq = req->social_chan_5g_freq; + + tx_ops = &psoc_nan_obj->tx_ops; + if (!tx_ops->nan_discovery_req_tx) { + nan_err("NAN Discovery tx op is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + return tx_ops->nan_discovery_req_tx(req, NAN_ENABLE_REQ); +} + +static QDF_STATUS nan_discovery_generic_req(struct nan_generic_req *req) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + struct wlan_nan_tx_ops *tx_ops; + + psoc_nan_obj = nan_get_psoc_priv_obj(req->psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + tx_ops = &psoc_nan_obj->tx_ops; + if (!tx_ops->nan_discovery_req_tx) { + nan_err("NAN Discovery tx op is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + return tx_ops->nan_discovery_req_tx(req, NAN_GENERIC_REQ); +} + +QDF_STATUS nan_discovery_flush_callback(struct scheduler_msg *msg) +{ + struct wlan_objmgr_psoc *psoc; + + if (!msg || !msg->bodyptr) { + nan_err("Null pointer for NAN Discovery message"); + return QDF_STATUS_E_INVAL; + } + + switch (msg->type) { + case NAN_ENABLE_REQ: + psoc = ((struct nan_enable_req *)msg->bodyptr)->psoc; + break; + case NAN_DISABLE_REQ: + psoc = ((struct nan_disable_req *)msg->bodyptr)->psoc; + break; + case NAN_GENERIC_REQ: + psoc = ((struct nan_generic_req *)msg->bodyptr)->psoc; + break; + default: + nan_err("Unsupported request type: %d", msg->type); + qdf_mem_free(msg->bodyptr); + return QDF_STATUS_E_INVAL; + } + + wlan_objmgr_psoc_release_ref(psoc, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS nan_discovery_scheduled_handler(struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!msg || !msg->bodyptr) { + nan_alert("msg or bodyptr is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (msg->type) { + case NAN_ENABLE_REQ: + status = nan_discovery_enable_req(msg->bodyptr); + break; + case NAN_DISABLE_REQ: + status = nan_discovery_disable_req(msg->bodyptr); + break; + case NAN_GENERIC_REQ: + status = nan_discovery_generic_req(msg->bodyptr); + break; + default: + nan_err("Unsupported request type: %d", msg->type); + qdf_mem_free(msg->bodyptr); + return QDF_STATUS_E_FAILURE; + } + + nan_discovery_flush_callback(msg); + return status; +} + +QDF_STATUS +wlan_nan_get_connection_info(struct wlan_objmgr_psoc *psoc, + struct policy_mgr_vdev_entry_info *conn_info) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + if (!psoc) { + nan_err("psoc obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (nan_get_discovery_state(psoc) != NAN_DISC_ENABLED) { + nan_err("NAN State needs to be Enabled"); + return QDF_STATUS_E_INVAL; + } + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* For policy_mgr use NAN mandatory Social ch 6 */ + conn_info->mhz = psoc_nan_obj->nan_social_ch_2g_freq; + conn_info->mac_id = psoc_nan_obj->nan_disc_mac_id; + conn_info->chan_width = CH_WIDTH_20MHZ; + conn_info->type = WMI_VDEV_TYPE_NAN; + + return QDF_STATUS_SUCCESS; +} + +uint32_t wlan_nan_get_disc_5g_ch_freq(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return 0; + } + + if (nan_get_discovery_state(psoc) != NAN_DISC_ENABLED) + return 0; + + return psoc_nan_obj->nan_social_ch_5g_freq; +} + +bool wlan_nan_get_sap_conc_support(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return 0; + } + + return (psoc_nan_obj->nan_caps.nan_sap_supported && + ucfg_is_nan_conc_control_supported(psoc)); +} + +bool wlan_nan_is_beamforming_supported(struct wlan_objmgr_psoc *psoc) +{ + return ucfg_nan_is_beamforming_supported(psoc); +} + +/* + * The NAN Cluster ID is a MAC address that takes a value from + * 50-6F-9A-01-00-00 to 50-6F-9A-01-FF-FF and is carried in the A3 field of + * some of the NAN frames. The NAN Cluster ID is randomly chosen by the device + * that initiates the NAN Cluster. + */ +#define NAN_CLUSTER_MATCH "\x50\x6F\x9A\x01" +#define NAN_CLUSTER_MATCH_SIZE 4 + +/** + * wlan_nan_is_bssid_in_cluster() - to check whether BSSID is a part of NAN + * cluster + * @bssid: BSSID present in mgmt frame + * + * Return: true if BSSID is part of NAN cluster + */ +static +bool wlan_nan_is_bssid_in_cluster(tSirMacAddr bssid) +{ + if (qdf_mem_cmp(bssid, NAN_CLUSTER_MATCH, NAN_CLUSTER_MATCH_SIZE) == 0) + return true; + + return false; +} + +/** + * wlan_nan_extract_vdev_id_from_vdev_list() -retrieve vdev from vdev list in + * pdev and check for nan vdev_id + * @pdev: PDEV object + * @dbg_id: Object Manager ref debug id + * + * API to get NAN vdev_id for only NAN BSSID. + * + * Return: NAN vdev_id + */ +static +uint8_t wlan_nan_extract_vdev_id_from_vdev_list(struct wlan_objmgr_pdev *pdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + struct wlan_objmgr_pdev_objmgr *objmgr = &pdev->pdev_objmgr; + qdf_list_t *vdev_list = NULL; + struct wlan_objmgr_vdev *vdev; + qdf_list_node_t *node = NULL; + qdf_list_node_t *prev_node = NULL; + uint8_t vdev_id = WLAN_UMAC_VDEV_ID_MAX; + + wlan_pdev_obj_lock(pdev); + + vdev_list = &objmgr->wlan_vdev_list; + if (qdf_list_peek_front(vdev_list, &node) != QDF_STATUS_SUCCESS) + goto end; + + do { + vdev = qdf_container_of(node, struct wlan_objmgr_vdev, + vdev_node); + if (wlan_objmgr_vdev_try_get_ref(vdev, dbg_id) == + QDF_STATUS_SUCCESS) { + if (wlan_vdev_mlme_get_opmode(vdev) == + QDF_NAN_DISC_MODE) { + vdev_id = wlan_vdev_get_id(vdev); + wlan_objmgr_vdev_release_ref(vdev, dbg_id); + goto end; + } + + wlan_objmgr_vdev_release_ref(vdev, dbg_id); + } + + prev_node = node; + } while (qdf_list_peek_next(vdev_list, prev_node, &node) == + QDF_STATUS_SUCCESS); +end: + wlan_pdev_obj_unlock(pdev); + + return vdev_id; +} + +uint8_t nan_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + tSirMacAddr bssid, + wlan_objmgr_ref_dbgid dbg_id) +{ + uint8_t vdev_id = WLAN_UMAC_VDEV_ID_MAX; + + if (wlan_nan_is_bssid_in_cluster(bssid)) + vdev_id = wlan_nan_extract_vdev_id_from_vdev_list(pdev, dbg_id); + + return vdev_id; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_main_i.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_main_i.h new file mode 100644 index 0000000000..23336f5bd2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/core/src/nan_main_i.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains declaration of common utility APIs and private structs to be + * used in NAN modules + */ + +#ifdef WLAN_FEATURE_NAN +#ifndef _WLAN_NAN_MAIN_I_H_ +#define _WLAN_NAN_MAIN_I_H_ + +#include "qdf_types.h" +#include "qdf_status.h" +#include "nan_public_structs.h" +#include "wlan_objmgr_cmn.h" +#include "cfg_nan.h" +#include "sir_mac_prot_def.h" + +struct wlan_objmgr_vdev; +struct wlan_objmgr_psoc; +struct scheduler_msg; + +#define nan_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_NAN, params) +#define nan_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_NAN, params) +#define nan_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_NAN, params) +#define nan_notice(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_NAN, params) +#define nan_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_NAN, params) +#define nan_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_NAN, params) + +#define nan_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_NAN, params) +#define nan_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_NAN, params) + +#define nan_alert_rl(params...) \ + QDF_TRACE_FATAL_RL(QDF_MODULE_ID_NAN, params) +#define nan_err_rl(params...) \ + QDF_TRACE_ERROR_RL(QDF_MODULE_ID_NAN, params) +#define nan_warn_rl(params...) \ + QDF_TRACE_WARN_RL(QDF_MODULE_ID_NAN, params) +#define nan_info_rl(params...) \ + QDF_TRACE_INFO_RL(QDF_MODULE_ID_NAN, params) +#define nan_debug_rl(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_NAN, params) + +/** + * enum nan_disc_state - NAN Discovery states + * @NAN_DISC_DISABLED: NAN Discovery is disabled + * @NAN_DISC_ENABLE_IN_PROGRESS: NAN Discovery enable is in progress + * @NAN_DISC_ENABLED: NAN Discovery is enabled + * @NAN_DISC_DISABLE_IN_PROGRESS: NAN Discovery disable is in progress + */ +enum nan_disc_state { + NAN_DISC_DISABLED, + NAN_DISC_ENABLE_IN_PROGRESS, + NAN_DISC_ENABLED, + NAN_DISC_DISABLE_IN_PROGRESS, +}; + +/** + * struct nan_cfg_params - NAN INI config params + * @enable: NAN feature enable + * @dp_enable: NAN Datapath feature enable + * @ndi_mac_randomize: Randomize NAN datapath interface MAC + * @ndp_inactivity_timeout: NDP inactivity timeout + * @nan_separate_iface_support: To supports separate iface creation for NAN + * @ndp_keep_alive_period: To configure duration of how many seconds to + * wait to kickout peer if peer is not reachable + * @support_mp0_discovery: To support discovery of NAN cluster with Master + * Preference (MP) as 0 when a new device is enabling NAN + * @max_ndp_sessions: max ndp sessions host supports + * @max_ndi: max number of ndi host supports + * @nan_feature_config: Bitmap to enable/disable a particular NAN feature + * configuration in firmware. It's sent to firmware through + * wmi_vdev_param_enable_disable_nan_config_features + * @disable_6g_nan: Disable NAN in 6GHz frequency band + * @enable_nan_eht_cap: Enable(1)/Disable(0) NAN EHT capability + */ +struct nan_cfg_params { + bool enable; + bool dp_enable; + bool ndi_mac_randomize; + uint16_t ndp_inactivity_timeout; + bool nan_separate_iface_support; + uint16_t ndp_keep_alive_period; + bool support_mp0_discovery; + uint32_t max_ndp_sessions; + uint32_t max_ndi; + uint32_t nan_feature_config; + bool disable_6g_nan; + bool enable_nan_eht_cap; +}; + +/** + * struct nan_psoc_priv_obj - nan private psoc obj + * @lock: lock to be acquired before reading or writing to object + * @cb_obj: struct containing callback pointers + * @cfg_param: NAN Config parameters in INI + * @nan_caps: NAN Target capabilities + * @tx_ops: Tx ops registered with Target IF interface + * @rx_ops: Rx ops registered with Target IF interface + * @disc_state: Present NAN Discovery state + * @nan_social_ch_2g_freq: NAN 2G Social channel for discovery + * @nan_social_ch_5g_freq: NAN 5G Social channel for discovery + * @nan_disc_mac_id: MAC id used for NAN Discovery + * @is_explicit_disable: Flag to indicate that NAN is being explicitly + * disabled by driver or user-space + * @ndp_request_ctx: NDP request context + * @nan_disc_request_ctx: NAN discovery enable/disable request context + */ +struct nan_psoc_priv_obj { + qdf_spinlock_t lock; + struct nan_callbacks cb_obj; + struct nan_cfg_params cfg_param; + struct nan_tgt_caps nan_caps; + struct wlan_nan_tx_ops tx_ops; + struct wlan_nan_rx_ops rx_ops; + enum nan_disc_state disc_state; + uint32_t nan_social_ch_2g_freq; + uint32_t nan_social_ch_5g_freq; + uint8_t nan_disc_mac_id; + bool is_explicit_disable; + void *ndp_request_ctx; + void *nan_disc_request_ctx; +}; + +/** + * struct nan_vdev_priv_obj - nan private vdev obj + * @lock: lock to be acquired before reading or writing to object + * @state: Current state of NDP + * @active_ndp_peers: number of active ndp peers + * @ndp_create_transaction_id: transaction id for create req + * @ndp_delete_transaction_id: transaction id for delete req + * @ndi_delete_rsp_reason: reason code for ndi_delete rsp + * @ndi_delete_rsp_status: status for ndi_delete rsp + * @primary_peer_mac: Primary NDP Peer mac address for the vdev + * @disable_context: Disable all NDP's operation context + * @ndp_init_done: Flag to indicate NDP initialization complete after first peer + * connection. + * @peer_mc_addr_list: Peer multicast address list + */ +struct nan_vdev_priv_obj { + qdf_spinlock_t lock; + enum nan_datapath_state state; + uint32_t active_ndp_peers; + uint16_t ndp_create_transaction_id; + uint16_t ndp_delete_transaction_id; + uint32_t ndi_delete_rsp_reason; + uint32_t ndi_delete_rsp_status; + struct qdf_mac_addr primary_peer_mac; + void *disable_context; + bool ndp_init_done; + struct qdf_mac_addr peer_mc_addr_list[MAX_NDP_SESSIONS]; +}; + +/** + * struct nan_peer_priv_obj - nan private peer obj + * @lock: lock to be acquired before reading or writing to object + * @active_ndp_sessions: number of active ndp sessions for this peer + * @home_chan_info: Home channel info for the NDP associated with the Peer + */ +struct nan_peer_priv_obj { + qdf_spinlock_t lock; + uint32_t active_ndp_sessions; + struct nan_datapath_channel_info home_chan_info; +}; + +/** + * nan_release_cmd: frees resources for NAN command. + * @in_req: pointer to msg buffer to be freed + * @req_type: type of request + * + * Return: None + */ +void nan_release_cmd(void *in_req, uint32_t req_type); + +/** + * nan_scheduled_msg_handler: callback pointer to be called when scheduler + * starts executing enqueued NAN command. + * @msg: pointer to msg + * + * Return: status of operation + */ +QDF_STATUS nan_scheduled_msg_handler(struct scheduler_msg *msg); + +/** + * nan_discovery_flush_callback: callback to flush the NAN scheduler msg + * @msg: pointer to msg + * + * Return: QDF_STATUS + */ +QDF_STATUS nan_discovery_flush_callback(struct scheduler_msg *msg); + +/** + * nan_discovery_scheduled_handler: callback pointer to be called when scheduler + * starts executing enqueued NAN command. + * @msg: pointer to msg + * + * Return: status of operation + */ +QDF_STATUS nan_discovery_scheduled_handler(struct scheduler_msg *msg); + +/* + * nan_discovery_event_handler: function to process NAN events from firmware + * @msg: message received from Target IF + * + * Return: status of operation + */ +QDF_STATUS nan_discovery_event_handler(struct scheduler_msg *msg); + +/* + * nan_datapath_event_handler: function to process NDP events from firmware + * @msg: message received from Target IF + * + * Return: status of operation + */ +QDF_STATUS nan_datapath_event_handler(struct scheduler_msg *msg); + +/* + * nan_set_discovery_state: Attempts to set NAN Discovery state as the given one + * @psoc: PSOC object + * @new_state: Attempting to this NAN discovery state + * + * Return: status of operation + */ +QDF_STATUS nan_set_discovery_state(struct wlan_objmgr_psoc *psoc, + enum nan_disc_state new_state); + +/* + * nan_discovery_pre_enable: Takes steps before sending NAN Enable to Firmware + * @pdev: pdev object + * @nan_ch_freq: Primary social channel for NAN Discovery + * + * Return: status of operation + */ +QDF_STATUS nan_discovery_pre_enable(struct wlan_objmgr_pdev *pdev, + uint32_t nan_ch_freq); + +/* + * nan_get_discovery_state: Returns the current NAN Discovery state + * @psoc: PSOC object + * + * Return: Current NAN Discovery state + */ +enum nan_disc_state nan_get_discovery_state(struct wlan_objmgr_psoc *psoc); + +/* + * nan_is_enable_allowed: Queries whether NAN Discovery is allowed + * @psoc: PSOC object + * @nan_ch_freq: Possible primary social channel for NAN Discovery + * @vdev_id: Vdev Id + * + * Return: True if NAN Enable is allowed on given channel, False otherwise + */ +bool nan_is_enable_allowed(struct wlan_objmgr_psoc *psoc, uint32_t nan_ch_freq, + uint8_t vdev_id); + +/* + * nan_is_disc_active: Queries whether NAN Discovery is active + * @psoc: PSOC object + * + * Return: True if NAN Disc is active, False otherwise + */ +bool nan_is_disc_active(struct wlan_objmgr_psoc *psoc); + +/* + * nan_get_connection_info: Gets connection info of the NAN Discovery interface + * @psoc: PSOC object + * @chan: NAN Social channel to be returned + * @mac_if: MAC ID associated with NAN Discovery + * + * Return: QDF_STATUS + */ +QDF_STATUS +nan_get_connection_info(struct wlan_objmgr_psoc *psoc, uint8_t *chan, + uint8_t *mac_id); + +/** + * nan_get_vdev_id_from_bssid() -get NAN vdev_id for NAN BSSID + * @pdev: PDEV object + * @bssid: BSSID present in mgmt frame + * @dbg_id: Object Manager ref debug id + * + * API to get NAN vdev_id for only NAN BSSID. + * + * Return: NAN vdev_id + */ +uint8_t nan_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + tSirMacAddr bssid, + wlan_objmgr_ref_dbgid dbg_id); + +/* + * nan_is_sta_sta_concurrency_present: Queries whether STA + STA concurrency + * present + * @psoc: PSOC object + * + * Return: True if concurrency is present, False otherwise + */ +bool nan_is_sta_sta_concurrency_present(struct wlan_objmgr_psoc *psoc); +#endif /* _WLAN_NAN_MAIN_I_H_ */ +#endif /* WLAN_FEATURE_NAN */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/cfg_nan.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/cfg_nan.h new file mode 100644 index 0000000000..adfae1ea5b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/cfg_nan.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__NAN_CFG_H__) +#define __NAN_CFG_H__ + +/** + * DOC: nan_cfg.h + * + * NAN feature INI configuration parameter definitions + */ +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" + +/* + * + * gEnableNanSupport - NAN feature support configuration + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When set to 1 NAN feature will be enabled. + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_ENABLE CFG_INI_BOOL("gEnableNanSupport", \ + 1, \ + "Enable NAN Support") + +/* + * + * nan_separate_iface_support: Separate iface creation for NAN + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Value is 1 when Host HDD supports separate iface creation + * for NAN. + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_SEPARATE_IFACE_SUPP CFG_INI_BOOL("nan_separate_iface_support", \ + 1, \ + "Separate iface for NAN") + + +/* + * + * genable_nan_datapath - Enable NaN data path feature. NaN data path + * enables NAN supported devices to exchange + * data over TCP/UDP network stack. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When set to 1 NAN Datapath feature will be enabled. + * + * Related: gEnableNanSupport + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_DATAPATH_ENABLE CFG_INI_BOOL("genable_nan_datapath", \ + 1, \ + "Enable NAN Datapath support") + +/* + * + * gEnableNDIMacRandomization - When enabled this will randomize NDI Mac + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When enabled this will randomize NDI Mac + * + * Related: gEnableNanSupport + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_RANDOMIZE_NDI_MAC CFG_INI_BOOL("gEnableNDIMacRandomization", \ + 1, \ + "Enable NAN MAC Randomization") + +/* + * + * ndp_inactivity_timeout - To configure duration of how many seconds + * without TX/RX data traffic, NDI vdev can kickout the connected + * peer(i.e. NDP Termination). + * + * @Min: 0 + * @Max: 1800 + * @Default: 60 + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_NDP_INACTIVITY_TIMEOUT CFG_INI_UINT("ndp_inactivity_timeout", \ + 0, \ + 1800, \ + 60, \ + CFG_VALUE_OR_DEFAULT, \ + "NDP Auto Terminate time") + +/* + * + * gNdpKeepAlivePeriod - To configure duration of how many seconds + * to wait to kickout peer if peer is not reachable. + * + * @Min: 10 + * @Max: 30 + * @Default: 14 + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ + +#define CFG_NDP_KEEP_ALIVE_PERIOD CFG_INI_UINT( \ + "gNdpKeepAlivePeriod", \ + 10, \ + 30, \ + 14, \ + CFG_VALUE_OR_DEFAULT, \ + "Keep alive timeout of a peer") + +/* MAX NDP sessions supported */ +#define MAX_NDP_SESSIONS 8 + +/* + * + * ndp_max_sessions - To configure max ndp sessions + * supported by host. + * + * @Min: 1 + * @Max: 8 + * @Default: 8 + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: Internal + * + * + */ + +#define CFG_NDP_MAX_SESSIONS CFG_INI_UINT( \ + "ndp_max_sessions", \ + 1, \ + MAX_NDP_SESSIONS, \ + 8, \ + CFG_VALUE_OR_DEFAULT, \ + "max ndp sessions host supports") + +/* + * + * gSupportMp0Discovery - To support discovery of NAN cluster with + * Master Preference (MP) as 0 when a new device is enabling NAN. + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_SUPPORT_MP0_DISCOVERY CFG_INI_BOOL( \ + "gSupportMp0Discovery", \ + 1, \ + "Enable/Disable discovery of NAN cluster with Master Preference (MP) as 0") +/* + * + * ndi_max_support - To configure max number of ndi host supports + * + * @Min: 1 + * @Max: 2 + * @Default: 1 + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: Internal + * + * + */ +#define CFG_NDI_MAX_SUPPORT CFG_INI_UINT( \ + "ndi_max_support", \ + 1, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Max number of NDI host supports") + +/* + * + * nan_feature_config - Bitmap to enable/disable a particular NAN/NDP feature + * + * @Min: 0 + * @Max: 0xFFFF + * @Default: 0 + * + * This parameter helps to enable/disable a particular feature config by setting + * corresponding bit and send to firmware through the VDEV param + * wmi_vdev_param_enable_disable_nan_config_features + * Acceptable values for this: + * BIT(0): Allow DW configuration from framework in sync role. + * If this is not set, firmware shall follow the spec/default behavior. + * BIT(1) to BIT(31): Reserved + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_NAN_FEATURE_CONFIG CFG_INI_UINT( \ + "nan_feature_config", \ + 0, \ + 0xFFFF, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable the specified NAN features in firmware") + +/* + * + * disable_6g_nan - Disable NAN feature support in 6GHz + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * When set to 1 NAN feature will be disabled in 6GHz. + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: External + * + * + */ +#define CFG_DISABLE_6G_NAN CFG_INI_BOOL("disable_6g_nan", \ + 0, \ + "Disable NAN Support in 6GHz") + +/* + * + * g_nan_enable_eht_cap- enable/disable NAN EHT CAP + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable NAN EHT capability + * + * Related: None + * + * Supported Feature: NAN + * + * Usage: Internal/External + * + * + */ +#define CFG_NAN_ENABLE_EHT_CAP CFG_INI_BOOL("g_nan_enable_eht_cap", \ + 0, \ + "Enable NAN EHT CAP") + + +#ifdef WLAN_FEATURE_NAN +#define CFG_NAN_DISC CFG(CFG_NAN_ENABLE) \ + CFG(CFG_DISABLE_6G_NAN) \ + CFG(CFG_NDP_KEEP_ALIVE_PERIOD) \ + CFG(CFG_SUPPORT_MP0_DISCOVERY) +#define CFG_NAN_DP CFG(CFG_NAN_DATAPATH_ENABLE) \ + CFG(CFG_NAN_RANDOMIZE_NDI_MAC) \ + CFG(CFG_NAN_NDP_INACTIVITY_TIMEOUT) \ + CFG(CFG_NAN_SEPARATE_IFACE_SUPP) +#else +#define CFG_NAN_DISC +#define CFG_NAN_DP +#endif + +#define CFG_NAN_ALL CFG_NAN_DISC \ + CFG_NAN_DP \ + CFG(CFG_NDP_MAX_SESSIONS) \ + CFG(CFG_NDI_MAX_SUPPORT) \ + CFG(CFG_NAN_FEATURE_CONFIG) \ + CFG(CFG_NAN_ENABLE_EHT_CAP) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/cfg_nan_api.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/cfg_nan_api.h new file mode 100644 index 0000000000..f91e4d30de --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/cfg_nan_api.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__NAN_CFG_API_H__) +#define __NAN_CFG_API_H__ + +/** + * DOC: nan_cfg_api.h + * + * NAN feature INI configuration parameters get/set APIs + */ +#include "qdf_types.h" + +struct wlan_objmgr_psoc; + +#ifdef WLAN_FEATURE_NAN +/** + * cfg_nan_get_enable() - get NAN support enable status + * @psoc: pointer to psoc object + * + * This function returns NAN enable status + */ +bool cfg_nan_get_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_get_datapath_enable() - get NAN Datapath support enable status + * @psoc: pointer to psoc object + * + * This function returns NAN Datapath enable status + */ +bool cfg_nan_get_datapath_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_get_ndi_mac_randomize() - get NDI MAC randomize enable status + * @psoc: pointer to psoc object + * + * This function returns NAN Datapath Interface MAC randomization status + */ +bool cfg_nan_get_ndi_mac_randomize(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_get_ndp_inactivity_timeout() - get NDP inactivity timeout value + * @psoc: pointer to psoc object + * @val: pointer to the value where inactivity timeout has to be copied to + * + * Return: QDF_STATUS + */ +QDF_STATUS cfg_nan_get_ndp_inactivity_timeout(struct wlan_objmgr_psoc *psoc, + uint16_t *val); + +/** + * cfg_nan_get_ndp_keepalive_period() - get NDP keepalive period + * @psoc: pointer to psoc object + * @val: pointer to the value where keepalive period has to be copied to + * + * Return: QDF_STATUS + */ +QDF_STATUS cfg_nan_get_ndp_keepalive_period(struct wlan_objmgr_psoc *psoc, + uint16_t *val); + +/** + * cfg_nan_get_ndp_max_sessions() - get NDP max sessions host supports + * @psoc: pointer to psoc object + * @val: pointer to hold max ndp sessions + * + * Return: QDF_STATUS + */ +QDF_STATUS cfg_nan_get_ndp_max_sessions(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * cfg_nan_get_max_ndi() - get max number of ndi host supports + * @psoc: pointer to psoc object + * @val: pointer to hold max number of ndi + * + * Return: QDF_STATUS + */ +QDF_STATUS cfg_nan_get_max_ndi(struct wlan_objmgr_psoc *psoc, uint32_t *val); + +/** + * cfg_nan_get_support_mp0_discovery() - get value of config support mp0 + * discovery + * @psoc: pointer to psoc object + * + * Return: Value of config join clustur with mp + */ +bool cfg_nan_get_support_mp0_discovery(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_is_roam_config_disabled() - get value of nan config roam disable + * discovery + * @psoc: pointer to psoc object + * + * Return: true on sta roam disable by nan else false + */ +bool cfg_nan_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_nan_is_eht_cap_enable() - Get NAN EHT capability + * @psoc: pointer to psoc object + * + * Return: Boolean flag indicating whether the NAN EHT capability is + * disabled or not + */ +bool cfg_nan_is_eht_cap_enable(struct wlan_objmgr_psoc *psoc); +#else +static inline +bool cfg_nan_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool cfg_nan_get_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool cfg_nan_get_datapath_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool cfg_nan_get_ndi_mac_randomize(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +QDF_STATUS cfg_nan_get_ndp_inactivity_timeout(struct wlan_objmgr_psoc *psoc, + uint16_t *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS cfg_nan_get_ndp_keepalive_period(struct wlan_objmgr_psoc *psoc, + uint16_t *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS cfg_nan_get_ndp_max_sessions(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS cfg_nan_get_max_ndi(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool cfg_nan_get_support_mp0_discovery( + struct wlan_objmgr_psoc *psoc) +{ + return false; +} + + +static inline bool cfg_nan_is_eht_cap_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +#endif + +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h new file mode 100644 index 0000000000..521d67ddbf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/nan_ucfg_api.h @@ -0,0 +1,690 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for OS_IF layer + */ + +#ifndef _NAN_UCFG_API_H_ +#define _NAN_UCFG_API_H_ + +#include "wlan_objmgr_cmn.h" +#include "nan_public_structs.h" + +#define NAN_CONCURRENCY_SUPPORTED(psoc) \ + (ucfg_is_nan_dbs_supported(psoc) || \ + ucfg_is_nan_conc_control_supported(psoc)) + +#define NDI_CONCURRENCY_SUPPORTED(psoc) \ + (ucfg_is_ndi_dbs_supported(psoc) || \ + ucfg_is_nan_conc_control_supported(psoc)) + +#ifdef WLAN_FEATURE_NAN +/** + * ucfg_nan_set_ndi_state: set ndi state + * @vdev: pointer to vdev object + * @state: value to set + * + * Return: status of operation + */ +#define ucfg_nan_set_ndi_state(vdev, state) \ + __ucfg_nan_set_ndi_state(vdev, state, __func__) + +/** + * __ucfg_nan_set_ndi_state: set ndi state + * @vdev: pointer to vdev object + * @state: value to set + * @func: Caller of this API + * + * Return: status of operation + */ +QDF_STATUS __ucfg_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev, + enum nan_datapath_state state, + const char *func); + +/** + * ucfg_nan_psoc_open: Setup NAN priv object params on PSOC open + * @psoc: Pointer to PSOC object + * + * Return: QDF Status of operation + */ +QDF_STATUS ucfg_nan_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_psoc_close: Clean up NAN priv data on PSOC close + * @psoc: Pointer to PSOC object + * + * Return: None + */ +void ucfg_nan_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_get_ndi_state: get ndi state from vdev obj + * @vdev: pointer to vdev object + * + * Return: ndi state + */ +enum nan_datapath_state ucfg_nan_get_ndi_state(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_active_peers: set active ndi peer + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_active_peers(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_nan_get_active_peers: get active ndi peer from vdev obj + * @vdev: pointer to vdev object + * + * Return: active ndi peer + */ +uint32_t ucfg_nan_get_active_peers(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_peer_mc_list: API to derive peer multicast address and add it + * to the list + * @vdev: pointer to vdev object + * @peer_mac_addr: Peer MAC address + * + * Return: None + */ +void ucfg_nan_set_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr peer_mac_addr); + +/** + * ucfg_nan_get_peer_mc_list: API to get peer multicast address list + * @vdev: pointer to vdev object + * @peer_mc_addr_list: Out pointer to the peer multicast address list + * + * Return: None + */ +void ucfg_nan_get_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr **peer_mc_addr_list); + +/** + * ucfg_nan_clear_peer_mc_list: Clear peer multicast address list + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @peer_mac_addr: Pointer to peer MAC address + * + * Return: None + */ +void ucfg_nan_clear_peer_mc_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac_addr); + +/** + * ucfg_nan_set_ndp_create_transaction_id: set ndp create transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndp_create_transaction_id(struct wlan_objmgr_vdev *vdev, + uint16_t val); + +/** + * ucfg_nan_get_ndp_create_transaction_id: get ndp create transaction id + * vdev obj + * @vdev: pointer to vdev object + * + * Return: ndp create transaction_id + */ +uint16_t ucfg_nan_get_ndp_create_transaction_id(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_ndp_delete_transaction_id: set ndp delete transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndp_delete_transaction_id(struct wlan_objmgr_vdev *vdev, + uint16_t val); + +/** + * ucfg_nan_get_ndp_delete_transaction_id: get ndp delete transaction id from + * vdev obj + * @vdev: pointer to vdev object + * + * Return: ndp delete transaction_id + */ +uint16_t ucfg_nan_get_ndp_delete_transaction_id(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_ndi_delete_rsp_reason: set ndi delete response reason + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndi_delete_rsp_reason(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_nan_get_ndi_delete_rsp_reason: get ndi delete response reason from vdev + * obj + * @vdev: pointer to vdev object + * + * Return: ndi delete rsp reason + */ +uint32_t ucfg_nan_get_ndi_delete_rsp_reason(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_ndi_delete_rsp_status: set ndi delete response reason + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_set_ndi_delete_rsp_status(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_nan_get_ndi_delete_rsp_status: get ndi delete response status from vdev + * obj + * @vdev: pointer to vdev object + * + * Return: ndi delete rsp status + */ +uint32_t ucfg_nan_get_ndi_delete_rsp_status(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_get_callbacks: ucfg API to return callbacks + * @psoc: pointer to psoc object + * @cb_obj: callback struct to populate + * + * Return: callback struct on success, NULL otherwise + */ +QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * ucfg_nan_req_processor: ucfg API to be called from HDD/OS_IF to + * process nan datapath initiator request from userspace + * @vdev: nan vdev pointer + * @in_req: NDP request + * @req_type: type of request + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_req_processor(struct wlan_objmgr_vdev *vdev, + void *in_req, uint32_t req_type); + +/** + * ucfg_nan_datapath_event_handler: ucfg API to be called from legacy code to + * post events to os_if/hdd layer + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * @type: message type + * @msg: msg buffer + * + * Return: None + */ +void ucfg_nan_datapath_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg); + +/** + * ucfg_nan_register_hdd_callbacks: ucfg API to set hdd callbacks + * @psoc: pointer to psoc object + * @cb_obj: structs containing callbacks + * + * Return: status of operation + */ +int ucfg_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * ucfg_nan_register_lim_callbacks: ucfg API to set lim callbacks + * @psoc: pointer to psoc object + * @cb_obj: structs containing callbacks + * + * Return: status of operation + */ +int ucfg_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * ucfg_nan_get_callbacks: ucfg API to return callbacks + * @psoc: pointer to psoc object + * @cb_obj: callback struct to populate + * + * Return: callback struct on success, NULL otherwise + */ +QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * ucfg_nan_discovery_req: ucfg API for NAN Discovery related requests + * @in_req: NAN request + * @req_type: Request type + * + * Return: status of operation + */ +QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type); + +/** + * ucfg_is_nan_conc_control_supported() - is NAN concurrency controlled by host + * @psoc: pointer to psoc object + * + * This function returns NAN concurrency support status + * + * Return: True if NAN concurrency is controlled by host, False otherwise + */ +bool ucfg_is_nan_conc_control_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_nan_dbs_supported() - ucfg API to query NAN DBS support + * @psoc: pointer to psoc object + * + * This function returns NAN DBS support status + * + * Return: True if NAN DBS is supported, False otherwise + */ +bool ucfg_is_nan_dbs_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_ndi_dbs_supported() - ucfg API to query NAN Datapath DBS support + * @psoc: pointer to psoc object + * + * This function returns NDI DBS support status + * + * Return: True if NDI DBS is supported, False otherwise + */ +bool ucfg_is_ndi_dbs_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_nan_sap_supported() - ucfg API to query NAN SAP support + * @psoc: pointer to psoc object + * + * This function returns NAN SAP support status + * + * Return: True if NAN SAP is supported, False otherwise + */ +bool ucfg_is_nan_sap_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_nan_enable_allowed() - ucfg API to query if NAN Discovery is + * allowed + * @psoc: pointer to psoc object + * @nan_ch_freq: NAN Discovery primary social channel + * @vdev_id: Vdev Id + * + * Return: True if NAN Discovery enable is allowed, False otherwise + */ +bool ucfg_is_nan_enable_allowed(struct wlan_objmgr_psoc *psoc, + uint32_t nan_ch_freq, + uint8_t vdev_id); + +/** + * ucfg_is_nan_disc_active() - ucfg API to query if NAN Discovery is + * active + * @psoc: pointer to psoc object + * + * Return: True if NAN Discovery is active, False otherwise + */ +bool ucfg_is_nan_disc_active(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_set_tgt_caps: ucfg API to set the NAN capabilities of the Target + * @psoc: pointer to psoc object + * @nan_caps: pointer to the structure of NAN capability bits + * + * Return: status of operation + */ +void ucfg_nan_set_tgt_caps(struct wlan_objmgr_psoc *psoc, + struct nan_tgt_caps *nan_caps); + +/** + * ucfg_nan_disable_concurrency: ucfg API to explicitly disable NAN Discovery + * @psoc: pointer to psoc object + * + * Return: None + */ +void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_register_wma_callbacks: ucfg API to register WMA callbacks + * @psoc: pointer to psoc object + * @cb_obj: Pointer to NAN callback structure + * + * Return: status of operation + */ +int ucfg_nan_register_wma_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); +/** + * ucfg_nan_check_and_disable_unsupported_ndi: ucfg API to check if NAN Datapath + * is active on multiple NDI's and disable the unsupported concurrencies. + * @psoc: pointer to psoc object + * @force: When set forces NDI disable + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_nan_check_and_disable_unsupported_ndi(struct wlan_objmgr_psoc *psoc, + bool force); + +/** + * ucfg_ndi_remove_entry_from_policy_mgr() - API to remove NDI entry from + * policy manager. + * @vdev: vdev pointer for NDI interface + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_ndi_remove_entry_from_policy_mgr(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_is_enable_disable_in_progress() - Is NAN enable/disable in progress + * @psoc: Pointer to PSOC object + * + * Return: True if NAN discovery enable/disable is in progress, false otherwise + */ +bool ucfg_nan_is_enable_disable_in_progress(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_is_sta_ndp_concurrency_allowed() - Indicates if NDP is allowed + * @psoc: pointer to psoc object + * @vdev: pointer to vdev object + * + * If STA+NDI(NDPs) exist and another NDI tries to establish + * NDP, then reject the second NDI(NDP). + * + * Return: true if allowed, false otherwise + */ +bool ucfg_nan_is_sta_ndp_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_set_vdev_creation_supp_by_fw()- Set the NAN separate vdev psoc param + * @psoc: pointer to psoc object + * @set: True if firmware supports NAN separate vdev feature + * + * Cache the value of set in NAN psoc object param. + * + * Return: None + */ +void +ucfg_nan_set_vdev_creation_supp_by_fw(struct wlan_objmgr_psoc *psoc, bool set); + +/** + * ucfg_nan_is_vdev_creation_allowed()- Get support for NAN vdev creation + * @psoc: pointer to psoc object + * + * Return: True if NAN vdev creation is allowed by host and firmware else false + */ +bool ucfg_nan_is_vdev_creation_allowed(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_is_sta_nan_ndi_4_port_allowed- Get support for 4 port (STA + + * NAN Disc + NDI + NDI) + * @psoc: pointer to psoc object + * + * Return: True if 4 port concurrency allowed or not. + */ +bool ucfg_nan_is_sta_nan_ndi_4_port_allowed(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_nan_is_beamforming_supported- Get support for beamforing + * @psoc: pointer to psoc object + * + * Return: True if beamforming is supported, false if not. + */ +bool ucfg_nan_is_beamforming_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_disable_nan_discovery() - Disable NAN discovery + * @psoc: pointer to psoc object + * @data: Data to be sent to NAN discovery engine, which runs in firmware + * @data_len: Length of the data + * + * Send NAN disable request to firmware by setting the mandatory + * params(disable_2g_discovery, disable_5g_discovery) along + * with the data, if provided. + * + * Return: status of operation + */ +QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc, + uint8_t *data, uint32_t data_len); + +/** + * ucfg_nan_disable_ndi() - Disable the NDI with given vdev_id + * @psoc: pointer to psoc object + * @ndi_vdev_id: vdev_id of the NDI to be disabled + * + * Disable all the NDPs present on the given NDI by sending NDP_END_ALL + * to firmware. Firmwere sends an immediate response(NDP_HOST_UPDATE) with + * ndp_disable param as 1 followed by NDP_END indication for all the NDPs. + * + * Return: status of operation + */ +QDF_STATUS +ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id); + +/** + * ucfg_get_nan_feature_config() - Get NAN feature bitmap + * @psoc: pointer to psoc object + * @nan_feature_config: NAN feature config bitmap to be enabled in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_get_nan_feature_config(struct wlan_objmgr_psoc *psoc, + uint32_t *nan_feature_config); + +/** + * ucfg_is_nan_vdev() - Check if the current vdev supports NAN or not + * @vdev: pointer to vdev object + * + * Return true + * 1. If the VDEV type is NAN_DISC or + * 2. If the VDEV type is STA and nan_separate_iface feature is not supported + * + * Return: Bool + */ +bool ucfg_is_nan_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_nan_disable_ind_to_userspace() - Send NAN disable ind to userspace + * @psoc: pointer to psoc object + * + * Prepare NAN disable indication and send it to userspace + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_nan_disable_ind_to_userspace(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_nan_allowed_on_freq() - Check if NAN is allowed on given freq + * @pdev: pdev context + * @freq: Frequency to be checked + * + * Check if NAN/NDP can be enabled on given frequency. + * Validate SRD channels based on the ini and reg domain. Assume rest of the + * channels support NAN/NDP for now. + * + * Return: True if NAN is allowed on the given frequency + */ +bool ucfg_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq); + +/** + * ucfg_get_disable_6g_nan() - Get NAN feature configuration for 6GHz + * @psoc: pointer to psoc object + * + * Return: Boolean flag indicating whether the NAN feature is disabled in + * 6GHz or not + */ +bool ucfg_get_disable_6g_nan(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_is_mlo_sta_nan_ndi_allowed()- Get support for MLO STA + + * NAN Disc + NDI concurrency + * @psoc: pointer to psoc object + * + * Return: True if mlo sta + nan + ndi concurrency allowed or not. + */ +bool ucfg_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc); + +#else /* WLAN_FEATURE_NAN */ + +static inline +void ucfg_nan_set_tgt_caps(struct wlan_objmgr_psoc *psoc, + struct nan_tgt_caps *nan_caps) +{ +} + +static inline void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS +ucfg_nan_check_and_disable_unsupported_ndi(struct wlan_objmgr_psoc *psoc, + bool force) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_nan_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ucfg_nan_psoc_close(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline bool ucfg_is_nan_disc_active(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +enum nan_datapath_state ucfg_nan_get_ndi_state(struct wlan_objmgr_vdev *vdev) +{ + return NAN_DATA_INVALID_STATE; +} + +static inline +bool ucfg_nan_is_enable_disable_in_progress(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool ucfg_nan_is_sta_ndp_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +ucfg_nan_set_vdev_creation_supp_by_fw(struct wlan_objmgr_psoc *psoc, bool set) +{ +} + +static inline +bool ucfg_nan_is_vdev_creation_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool ucfg_nan_is_sta_nan_ndi_4_port_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool ucfg_nan_is_beamforming_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc, + uint8_t *data, uint32_t data_len) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS +ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id) +{ + return QDF_STATUS_E_INVAL; +} + +static inline +bool ucfg_is_nan_conc_control_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +QDF_STATUS ucfg_get_nan_feature_config(struct wlan_objmgr_psoc *psoc, + uint32_t *nan_feature_config) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool ucfg_is_nan_vdev(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +bool ucfg_is_nan_dbs_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +QDF_STATUS ucfg_nan_disable_ind_to_userspace(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool ucfg_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + return false; +} + +static inline bool ucfg_get_disable_6g_nan(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline void +ucfg_nan_get_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr **peer_mc_addr_list) +{ +} + +static inline bool +ucfg_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /* WLAN_FEATURE_NAN */ +#endif /* _NAN_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/wlan_nan_api_i.h b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/wlan_nan_api_i.h new file mode 100644 index 0000000000..30caeaedda --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/inc/wlan_nan_api_i.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains prototypes for NAN component + */ + +#ifndef _WLAN_NAN_API_I_H_ +#define _WLAN_NAN_API_I_H_ + +#include "wlan_objmgr_cmn.h" +#include "nan_public_structs.h" + +#ifdef WLAN_FEATURE_NAN +/** + * wlan_nan_get_ndi_state: get ndi state from vdev obj + * @vdev: pointer to vdev object + * + * Return: ndi state + */ +enum nan_datapath_state wlan_nan_get_ndi_state(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_nan_get_vdev_id_from_bssid() - get NAN vdev_id for BSSID + * @pdev: PDEV object + * @bssid: BSSID present in mgmt frame + * @dbg_id: Object Manager ref debug id + * + * This is wrapper API for nan_get_vdev_id_from_bssid() + * + * Return: NAN vdev_id + */ +uint8_t wlan_nan_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + tSirMacAddr bssid, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * wlan_nan_is_disc_active() - Check if NAN discovery is active + * @psoc: Pointer to PSOC object + * + * Return: True if Discovery is active + */ +bool wlan_nan_is_disc_active(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_nan_is_eht_capable() - Get NAN EHT capability + * @psoc: pointer to psoc object + * + * Return: Boolean flag indicating whether the NAN EHT capability is + * disabled or not + */ +bool wlan_nan_is_eht_capable(struct wlan_objmgr_psoc *psoc); + +#else +static inline +enum nan_datapath_state wlan_nan_get_ndi_state(struct wlan_objmgr_vdev *vdev) +{ + return NAN_DATA_INVALID_STATE; +} + +static inline +uint8_t wlan_nan_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + tSirMacAddr bssid, + wlan_objmgr_ref_dbgid dbg_id) +{ + return INVALID_VDEV_ID; +} + +static inline +bool wlan_nan_is_disc_active(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool +wlan_nan_is_eht_capable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /*WLAN_FEATURE_NAN */ +#endif /*_WLAN_NAN_API_I_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/cfg_nan.c b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/cfg_nan.c new file mode 100644 index 0000000000..0230b95919 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/cfg_nan.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains NAN INI configurations + */ + +#include "wlan_objmgr_psoc_obj.h" +#include "cfg_nan_api.h" +#include "../../core/src/nan_main_i.h" +#include "wlan_mlme_ucfg_api.h" +#include "cfg_ucfg_api.h" +#include "cfg_nan.h" + +static inline struct nan_psoc_priv_obj + *cfg_nan_get_priv_obj(struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + nan_err("PSOC obj null"); + return NULL; + } + return wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_NAN); +} + +bool cfg_nan_get_enable(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + return nan_obj->cfg_param.enable; +} + +bool cfg_nan_get_datapath_enable(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + return nan_obj->cfg_param.dp_enable; +} + +bool cfg_nan_get_ndi_mac_randomize(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + return nan_obj->cfg_param.ndi_mac_randomize; +} + +QDF_STATUS cfg_nan_get_ndp_inactivity_timeout(struct wlan_objmgr_psoc *psoc, + uint16_t *val) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return QDF_STATUS_E_INVAL; + } + + *val = nan_obj->cfg_param.ndp_inactivity_timeout; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cfg_nan_get_ndp_keepalive_period(struct wlan_objmgr_psoc *psoc, + uint16_t *val) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return QDF_STATUS_E_INVAL; + } + + *val = nan_obj->cfg_param.ndp_keep_alive_period; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cfg_nan_get_ndp_max_sessions(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + *val = cfg_default(CFG_NDP_MAX_SESSIONS); + return QDF_STATUS_E_INVAL; + } + + *val = nan_obj->cfg_param.max_ndp_sessions; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cfg_nan_get_max_ndi(struct wlan_objmgr_psoc *psoc, uint32_t *val) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + *val = cfg_default(CFG_NDI_MAX_SUPPORT); + return QDF_STATUS_E_INVAL; + } + + *val = nan_obj->cfg_param.max_ndi; + return QDF_STATUS_SUCCESS; +} + +bool cfg_nan_get_support_mp0_discovery(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("NAN obj null"); + return false; + } + + return nan_obj->cfg_param.support_mp0_discovery; +} + +bool cfg_nan_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc) +{ + uint32_t sta_roam_disable; + + if (ucfg_mlme_get_roam_disable_config(psoc, &sta_roam_disable) == + QDF_STATUS_SUCCESS) + return sta_roam_disable & LFR3_STA_ROAM_DISABLE_BY_NAN; + + return false; +} + +bool cfg_nan_is_eht_cap_enable(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = cfg_nan_get_priv_obj(psoc); + + if (!nan_obj) { + nan_err("nan psoc priv object is NULL"); + return cfg_default(CFG_NAN_ENABLE_EHT_CAP); + } + + return nan_obj->cfg_param.enable_nan_eht_cap; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c new file mode 100644 index 0000000000..9b919cb905 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/nan_ucfg_api.c @@ -0,0 +1,1454 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface definitions for OS_IF layer + */ + +#include "nan_ucfg_api.h" +#include "nan_public_structs.h" +#include "wlan_nan_api.h" +#include "../../core/src/nan_main_i.h" +#include "scheduler_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_osif_request_manager.h" +#include "wlan_policy_mgr_api.h" +#include "cfg_ucfg_api.h" +#include "cfg_nan.h" +#include "wlan_mlme_api.h" +#include "cfg_nan_api.h" +#include "wlan_tdls_ucfg_api.h" +#include "wlan_nan_api_i.h" + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; + +#ifdef WLAN_FEATURE_NAN +/** + * nan_cfg_init() - Initialize NAN config params + * @psoc: Pointer to PSOC Object + * @nan_obj: Pointer to NAN private object + * + * This function initialize NAN config params + */ +static void nan_cfg_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ + nan_obj->cfg_param.enable = cfg_get(psoc, CFG_NAN_ENABLE); + nan_obj->cfg_param.support_mp0_discovery = + cfg_get(psoc, + CFG_SUPPORT_MP0_DISCOVERY); + nan_obj->cfg_param.ndp_keep_alive_period = + cfg_get(psoc, + CFG_NDP_KEEP_ALIVE_PERIOD); + nan_obj->cfg_param.max_ndp_sessions = cfg_get(psoc, + CFG_NDP_MAX_SESSIONS); + nan_obj->cfg_param.max_ndi = cfg_get(psoc, CFG_NDI_MAX_SUPPORT); + nan_obj->cfg_param.nan_feature_config = + cfg_get(psoc, CFG_NAN_FEATURE_CONFIG); + nan_obj->cfg_param.disable_6g_nan = cfg_get(psoc, CFG_DISABLE_6G_NAN); + nan_obj->cfg_param.enable_nan_eht_cap = + cfg_get(psoc, CFG_NAN_ENABLE_EHT_CAP); +} + +/** + * nan_cfg_dp_init() - Initialize NAN Datapath config params + * @psoc: Pointer to PSOC Object + * @nan_obj: Pointer to NAN private object + * + * This function initialize NAN config params + */ +static void nan_cfg_dp_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ + nan_obj->cfg_param.dp_enable = cfg_get(psoc, + CFG_NAN_DATAPATH_ENABLE); + nan_obj->cfg_param.ndi_mac_randomize = + cfg_get(psoc, CFG_NAN_RANDOMIZE_NDI_MAC); + nan_obj->cfg_param.ndp_inactivity_timeout = + cfg_get(psoc, CFG_NAN_NDP_INACTIVITY_TIMEOUT); + nan_obj->cfg_param.nan_separate_iface_support = + cfg_get(psoc, CFG_NAN_SEPARATE_IFACE_SUPP); + +} +#else +static void nan_cfg_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ +} + +static void nan_cfg_dp_init(struct wlan_objmgr_psoc *psoc, + struct nan_psoc_priv_obj *nan_obj) +{ +} +#endif + +bool ucfg_get_disable_6g_nan(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = nan_get_psoc_priv_obj(psoc); + + if (!nan_obj) { + nan_err("nan psoc priv object is NULL"); + return cfg_default(CFG_DISABLE_6G_NAN); + } + + return nan_obj->cfg_param.disable_6g_nan; +} + +QDF_STATUS ucfg_nan_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *nan_obj = nan_get_psoc_priv_obj(psoc); + + if (!nan_obj) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_cfg_init(psoc, nan_obj); + nan_cfg_dp_init(psoc, nan_obj); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_nan_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + /* No cleanup required on psoc close for NAN */ +} + +inline QDF_STATUS __ucfg_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev, + enum nan_datapath_state state, + const char *func) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + enum nan_datapath_state current_state; + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_spin_lock_bh(&priv_obj->lock); + current_state = priv_obj->state; + priv_obj->state = state; + qdf_spin_unlock_bh(&priv_obj->lock); + nan_nofl_debug("%s: ndi state: current: %u, new: %u", func, + current_state, state); + + return QDF_STATUS_SUCCESS; +} + +inline enum nan_datapath_state ucfg_nan_get_ndi_state( + struct wlan_objmgr_vdev *vdev) +{ + return wlan_nan_get_ndi_state(vdev); +} + +inline QDF_STATUS ucfg_nan_set_active_peers(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->active_ndp_peers = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_nan_update_mc_list() - update the multicast list + * @vdev: Pointer to VDEV Object + * + * This function will update the multicast list for NDP peer + */ +static void ucfg_nan_update_mc_list(struct wlan_objmgr_vdev *vdev) +{ + struct nan_callbacks cb_obj; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) { + nan_err("psoc is null"); + return; + } + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't get callback object"); + return; + } + + if (!cb_obj.set_mc_list) { + nan_err("set_mc_list callback not registered"); + return; + } + + cb_obj.set_mc_list(vdev); +} + +inline void ucfg_nan_set_peer_mc_list(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr peer_mac_addr) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + uint32_t max_ndp_sessions = 0; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + int i, list_idx = 0; + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + + if (!psoc) { + nan_err("psoc is null"); + return; + } + + cfg_nan_get_ndp_max_sessions(psoc, &max_ndp_sessions); + + qdf_spin_lock_bh(&priv_obj->lock); + for (i = 0; i < max_ndp_sessions; i++) { + if (qdf_is_macaddr_zero(&priv_obj->peer_mc_addr_list[i])) { + list_idx = i; + break; + } + } + if (list_idx == max_ndp_sessions) { + nan_err("Peer multicast address list is full"); + qdf_spin_unlock_bh(&priv_obj->lock); + } + /* Derive peer multicast addr */ + peer_mac_addr.bytes[0] = 0x33; + peer_mac_addr.bytes[1] = 0x33; + peer_mac_addr.bytes[2] = 0xff; + priv_obj->peer_mc_addr_list[list_idx] = peer_mac_addr; + + qdf_spin_unlock_bh(&priv_obj->lock); + + ucfg_nan_update_mc_list(vdev); +} + +inline void ucfg_nan_get_peer_mc_list( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr **peer_mc_addr_list) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + + *peer_mc_addr_list = priv_obj->peer_mc_addr_list; +} + +inline void ucfg_nan_clear_peer_mc_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac_addr) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + int i; + uint32_t max_ndp_sessions = 0; + struct qdf_mac_addr derived_peer_mc_addr; + + if (!priv_obj) { + nan_err("priv_obj is null"); + return; + } + + /* Derive peer multicast addr */ + derived_peer_mc_addr = *peer_mac_addr; + derived_peer_mc_addr.bytes[0] = 0x33; + derived_peer_mc_addr.bytes[1] = 0x33; + derived_peer_mc_addr.bytes[2] = 0xff; + qdf_spin_lock_bh(&priv_obj->lock); + cfg_nan_get_ndp_max_sessions(psoc, &max_ndp_sessions); + for (i = 0; i < max_ndp_sessions; i++) { + if (qdf_is_macaddr_equal(&priv_obj->peer_mc_addr_list[i], + &derived_peer_mc_addr)) { + qdf_zero_macaddr(&priv_obj->peer_mc_addr_list[i]); + break; + } + } + + qdf_spin_unlock_bh(&priv_obj->lock); + + ucfg_nan_update_mc_list(vdev); +} + +inline uint32_t ucfg_nan_get_active_peers(struct wlan_objmgr_vdev *vdev) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->active_ndp_peers; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} +inline QDF_STATUS ucfg_nan_set_ndp_create_transaction_id( + struct wlan_objmgr_vdev *vdev, uint16_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndp_create_transaction_id = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint16_t ucfg_nan_get_ndp_create_transaction_id( + struct wlan_objmgr_vdev *vdev) +{ + uint16_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndp_create_transaction_id; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndp_delete_transaction_id( + struct wlan_objmgr_vdev *vdev, uint16_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndp_delete_transaction_id = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint16_t ucfg_nan_get_ndp_delete_transaction_id( + struct wlan_objmgr_vdev *vdev) +{ + uint16_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndp_delete_transaction_id; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndi_delete_rsp_reason( + struct wlan_objmgr_vdev *vdev, uint32_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndi_delete_rsp_reason = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint32_t ucfg_nan_get_ndi_delete_rsp_reason( + struct wlan_objmgr_vdev *vdev) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return 0; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndi_delete_rsp_reason; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_set_ndi_delete_rsp_status( + struct wlan_objmgr_vdev *vdev, uint32_t val) +{ + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + priv_obj->ndi_delete_rsp_status = val; + qdf_spin_unlock_bh(&priv_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +inline uint32_t ucfg_nan_get_ndi_delete_rsp_status( + struct wlan_objmgr_vdev *vdev) +{ + uint32_t val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->ndi_delete_rsp_status; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +inline QDF_STATUS ucfg_nan_get_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_spin_lock_bh(&psoc_obj->lock); + qdf_mem_copy(cb_obj, &psoc_obj->cb_obj, sizeof(*cb_obj)); + qdf_spin_unlock_bh(&psoc_obj->lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ucfg_nan_sch_msg_flush_cb(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev = NULL; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_NULL_VALUE; + + switch (msg->type) { + case NDP_INITIATOR_REQ: + vdev = ((struct nan_datapath_initiator_req *) + msg->bodyptr)->vdev; + break; + case NDP_RESPONDER_REQ: + vdev = ((struct nan_datapath_responder_req *) + msg->bodyptr)->vdev; + break; + case NDP_END_REQ: + vdev = ((struct nan_datapath_end_req *)msg->bodyptr)->vdev; + break; + case NDP_END_ALL: + vdev = ((struct nan_datapath_end_all_ndps *)msg->bodyptr)->vdev; + break; + default: + nan_err("Invalid NAN msg type during sch flush"); + return QDF_STATUS_E_INVAL; + } + + if (vdev) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_nan_req_processor(struct wlan_objmgr_vdev *vdev, + void *in_req, uint32_t req_type) +{ + uint32_t len; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + int err; + struct nan_psoc_priv_obj *psoc_obj = NULL; + struct osif_request *request = NULL; + static const struct osif_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_NDP_END, + }; + + if (!in_req) { + nan_alert("req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (req_type) { + case NDP_INITIATOR_REQ: + len = sizeof(struct nan_datapath_initiator_req); + break; + case NDP_RESPONDER_REQ: + len = sizeof(struct nan_datapath_responder_req); + break; + case NDP_END_REQ: + len = sizeof(struct nan_datapath_end_req); + psoc_obj = nan_get_psoc_priv_obj(wlan_vdev_get_psoc(vdev)); + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_INVAL; + } + request = osif_request_alloc(¶ms); + if (!request) { + nan_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + psoc_obj->ndp_request_ctx = osif_request_cookie(request); + break; + case NDP_END_ALL: + len = sizeof(struct nan_datapath_end_all_ndps); + break; + default: + nan_err("in correct message req type: %d", req_type); + return QDF_STATUS_E_INVAL; + } + + msg.bodyptr = qdf_mem_malloc(len); + if (!msg.bodyptr) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + + qdf_mem_copy(msg.bodyptr, in_req, len); + msg.type = req_type; + msg.callback = nan_scheduled_msg_handler; + msg.flush_callback = ucfg_nan_sch_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_NAN, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("failed to post msg to NAN component, status: %d", + status); + goto fail; + } + + if (req_type == NDP_END_REQ) { + nan_debug("Wait for NDP END indication"); + err = osif_request_wait_for_response(request); + if (err) + nan_debug("NAN request timed out: %d", err); + osif_request_put(request); + psoc_obj->ndp_request_ctx = NULL; + } + + return QDF_STATUS_SUCCESS; + +fail: + qdf_mem_free(msg.bodyptr); + if (req_type == NDP_END_REQ) { + osif_request_put(request); + psoc_obj->ndp_request_ctx = NULL; + } + return status; +} + +void ucfg_nan_datapath_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return; + } + + psoc_obj->cb_obj.os_if_ndp_event_handler(psoc, vdev, type, msg); +} + +static void ucfg_nan_request_process_cb(void *cookie) +{ + struct osif_request *request; + + request = osif_request_get(cookie); + if (request) { + osif_request_complete(request); + osif_request_put(request); + } else { + nan_debug("Obsolete request (cookie:0x%pK), do nothing", + cookie); + } +} + +#ifdef WLAN_FEATURE_SR +static void +nan_register_sr_concurrency_callback(struct nan_psoc_priv_obj *psoc_obj, + struct nan_callbacks *cb_obj) +{ + psoc_obj->cb_obj.nan_sr_concurrency_update = + cb_obj->nan_sr_concurrency_update; +} +#else +static inline void +nan_register_sr_concurrency_callback(struct nan_psoc_priv_obj *psoc_obj, + struct nan_callbacks *cb_obj) +{} +#endif + +int ucfg_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return -EINVAL; + } + + psoc_obj->cb_obj.ndi_open = cb_obj->ndi_open; + psoc_obj->cb_obj.ndi_set_mode = cb_obj->ndi_set_mode; + psoc_obj->cb_obj.ndi_start = cb_obj->ndi_start; + psoc_obj->cb_obj.ndi_delete = cb_obj->ndi_delete; + psoc_obj->cb_obj.ndi_close = cb_obj->ndi_close; + psoc_obj->cb_obj.drv_ndi_create_rsp_handler = + cb_obj->drv_ndi_create_rsp_handler; + psoc_obj->cb_obj.drv_ndi_delete_rsp_handler = + cb_obj->drv_ndi_delete_rsp_handler; + + psoc_obj->cb_obj.new_peer_ind = cb_obj->new_peer_ind; + psoc_obj->cb_obj.peer_departed_ind = cb_obj->peer_departed_ind; + psoc_obj->cb_obj.os_if_ndp_event_handler = + cb_obj->os_if_ndp_event_handler; + psoc_obj->cb_obj.os_if_nan_event_handler = + cb_obj->os_if_nan_event_handler; + psoc_obj->cb_obj.ucfg_nan_request_process_cb = + ucfg_nan_request_process_cb; + psoc_obj->cb_obj.nan_concurrency_update = + cb_obj->nan_concurrency_update; + psoc_obj->cb_obj.set_mc_list = cb_obj->set_mc_list; + + nan_register_sr_concurrency_callback(psoc_obj, cb_obj); + return 0; +} + +int ucfg_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return -EINVAL; + } + + psoc_obj->cb_obj.add_ndi_peer = cb_obj->add_ndi_peer; + psoc_obj->cb_obj.ndp_delete_peers = cb_obj->ndp_delete_peers; + psoc_obj->cb_obj.delete_peers_by_addr = cb_obj->delete_peers_by_addr; + + return 0; +} + +int ucfg_nan_register_wma_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + struct nan_psoc_priv_obj *psoc_obj = nan_get_psoc_priv_obj(psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return -EINVAL; + } + + psoc_obj->cb_obj.update_ndi_conn = cb_obj->update_ndi_conn; + + return 0; +} + +void ucfg_nan_set_tgt_caps(struct wlan_objmgr_psoc *psoc, + struct nan_tgt_caps *nan_caps) +{ + struct nan_psoc_priv_obj *psoc_priv = nan_get_psoc_priv_obj(psoc); + + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return; + } + + psoc_priv->nan_caps = *nan_caps; +} + +bool ucfg_is_nan_conc_control_supported(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_priv; + + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return false; + } + + return (psoc_priv->nan_caps.nan_conc_control == 1); +} + +bool ucfg_is_nan_dbs_supported(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_priv; + + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return false; + } + + return (psoc_priv->nan_caps.nan_dbs_supported == 1); +} + +bool ucfg_is_ndi_dbs_supported(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_priv; + + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return false; + } + + return (psoc_priv->nan_caps.ndi_dbs_supported == 1); +} + +bool ucfg_is_nan_enable_allowed(struct wlan_objmgr_psoc *psoc, + uint32_t nan_ch_freq, uint8_t vdev_id) +{ + return nan_is_enable_allowed(psoc, nan_ch_freq, vdev_id); +} + +bool ucfg_is_nan_disc_active(struct wlan_objmgr_psoc *psoc) +{ + return nan_is_disc_active(psoc); +} + +QDF_STATUS ucfg_nan_discovery_req(void *in_req, uint32_t req_type) +{ + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg msg = {0}; + uint32_t len; + QDF_STATUS status; + struct nan_psoc_priv_obj *psoc_priv; + struct osif_request *request = NULL; + static const struct osif_request_params params = { + .priv_size = 0, + .timeout_ms = 4000, + }; + int err = 0; + bool recovery; + + if (!in_req) { + nan_alert("NAN Discovery req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (req_type) { + case NAN_ENABLE_REQ: { + struct nan_enable_req *req = in_req; + + psoc = req->psoc; + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (policy_mgr_is_sta_mon_concurrency(psoc)) + return QDF_STATUS_E_INVAL; + + /* + * Take a psoc reference while it is being used by the + * NAN requests. + */ + status = wlan_objmgr_psoc_try_get_ref(psoc, + WLAN_NAN_ID); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't obtain psoc ref"); + return status; + } + + status = nan_discovery_pre_enable(req->pdev, + req->social_chan_2g_freq); + if (QDF_IS_STATUS_SUCCESS(status)) { + len = sizeof(struct nan_enable_req) + + req->params.request_data_len; + } else { + wlan_objmgr_psoc_release_ref(psoc, + WLAN_NAN_ID); + return status; + } + break; + } + case NAN_DISABLE_REQ: { + struct nan_disable_req *req = in_req; + + psoc = req->psoc; + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = wlan_objmgr_psoc_try_get_ref(psoc, + WLAN_NAN_ID); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't obtain psoc ref"); + return status; + } + + status = + nan_set_discovery_state(req->psoc, + NAN_DISC_DISABLE_IN_PROGRESS); + if (QDF_IS_STATUS_SUCCESS(status)) { + len = sizeof(struct nan_disable_req) + + req->params.request_data_len; + } else { + wlan_objmgr_psoc_release_ref(psoc, + WLAN_NAN_ID); + return status; + } + break; + } + case NAN_GENERIC_REQ: { + struct nan_generic_req *req = in_req; + + psoc = req->psoc; + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = wlan_objmgr_psoc_try_get_ref(psoc, + WLAN_NAN_ID); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Couldn't obtain psoc ref"); + return status; + } + len = sizeof(struct nan_generic_req) + + req->params.request_data_len; + break; + } + default: + nan_err("in correct message req type: %d", req_type); + return QDF_STATUS_E_INVAL; + } + + msg.bodyptr = qdf_mem_malloc(len); + if (!msg.bodyptr) { + wlan_objmgr_psoc_release_ref(psoc, WLAN_NAN_ID); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(msg.bodyptr, in_req, len); + msg.type = req_type; + msg.callback = nan_discovery_scheduled_handler; + msg.flush_callback = nan_discovery_flush_callback; + + if (req_type == NAN_GENERIC_REQ) + goto post_msg; + + request = osif_request_alloc(¶ms); + if (!request) { + nan_err("Request allocation failure"); + nan_discovery_flush_callback(&msg); + return QDF_STATUS_E_NOMEM; + } + + psoc_priv->nan_disc_request_ctx = osif_request_cookie(request); + if (req_type == NAN_DISABLE_REQ) + psoc_priv->is_explicit_disable = true; + +post_msg: + status = scheduler_post_message(QDF_MODULE_ID_NAN, + QDF_MODULE_ID_NAN, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("failed to post msg to NAN component, status: %d", + status); + nan_discovery_flush_callback(&msg); + } + + if (req_type != NAN_GENERIC_REQ) { + recovery = cds_is_driver_recovering(); + if (!recovery) + err = osif_request_wait_for_response(request); + if (recovery || err) { + nan_debug("NAN request: %u recovery %d or timed out %d", + req_type, recovery, err); + + if (req_type == NAN_ENABLE_REQ) { + nan_set_discovery_state(psoc, + NAN_DISC_DISABLED); + if (ucfg_is_nan_dbs_supported(psoc)) + policy_mgr_check_n_start_opportunistic_timer(psoc); + nan_handle_emlsr_concurrency(psoc, false); + + /* + * If FW respond with NAN enable failure, then + * TDLS should be enable again if there is TDLS + * connection exist earlier. + * decrement the active TDLS session. + */ + ucfg_tdls_notify_connect_failure(psoc); + } else if (req_type == NAN_DISABLE_REQ) { + nan_disable_cleanup(psoc); + } + } + if (req_type == NAN_DISABLE_REQ) + psoc_priv->is_explicit_disable = false; + osif_request_put(request); + } + + return status; +} + +void ucfg_nan_disable_concurrency(struct wlan_objmgr_psoc *psoc) +{ + struct nan_disable_req nan_req = {0}; + enum nan_disc_state curr_nan_state; + struct nan_psoc_priv_obj *psoc_priv; + QDF_STATUS status; + + if (!psoc) { + nan_err("psoc object is NULL, no action will be taken"); + return; + } + + psoc_priv = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv) { + nan_err("nan psoc priv object is NULL"); + return; + } + + if (!ucfg_is_nan_conc_control_supported(psoc)) + return; + + qdf_spin_lock_bh(&psoc_priv->lock); + curr_nan_state = nan_get_discovery_state(psoc); + + if (curr_nan_state == NAN_DISC_DISABLED || + curr_nan_state == NAN_DISC_DISABLE_IN_PROGRESS) { + qdf_spin_unlock_bh(&psoc_priv->lock); + return; + } + qdf_spin_unlock_bh(&psoc_priv->lock); + + nan_req.psoc = psoc; + nan_req.disable_2g_discovery = true; + nan_req.disable_5g_discovery = true; + + status = ucfg_nan_discovery_req(&nan_req, NAN_DISABLE_REQ); + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Unable to disable NAN Discovery"); + return; + } + + nan_debug("NAN Disabled successfully"); +} + +QDF_STATUS +ucfg_nan_disable_ndi(struct wlan_objmgr_psoc *psoc, uint32_t ndi_vdev_id) +{ + enum nan_datapath_state curr_ndi_state; + struct nan_vdev_priv_obj *ndi_vdev_priv; + struct nan_datapath_end_all_ndps req = {0}; + struct wlan_objmgr_vdev *ndi_vdev; + struct osif_request *request; + QDF_STATUS status; + int err; + static const struct osif_request_params params = { + .priv_size = 0, + .timeout_ms = 2000, + }; + + if (!ucfg_is_ndi_dbs_supported(psoc)) + return QDF_STATUS_SUCCESS; + + ndi_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, ndi_vdev_id, + WLAN_NAN_ID); + if (!ndi_vdev) { + nan_err("Cannot obtain NDI vdev object!"); + return QDF_STATUS_E_INVAL; + } + + ndi_vdev_priv = nan_get_vdev_priv_obj(ndi_vdev); + if (!ndi_vdev_priv) { + nan_err("ndi vdev priv object is NULL"); + wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID); + return QDF_STATUS_E_INVAL; + } + curr_ndi_state = ucfg_nan_get_ndi_state(ndi_vdev); + + /* + * Nothing to do if NDI is in DATA_END state. + * Continue cleanup in NAN_DATA_NDI_DELETING_STATE as this API + * can be called from hdd_ndi_delete. + */ + if (curr_ndi_state == NAN_DATA_END_STATE) { + wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID); + return QDF_STATUS_SUCCESS; + } + ucfg_nan_set_ndi_state(ndi_vdev, NAN_DATA_END_STATE); + + request = osif_request_alloc(¶ms); + if (!request) { + nan_err("Request allocation failure"); + status = QDF_STATUS_E_NOMEM; + goto cleanup; + } + ndi_vdev_priv->disable_context = osif_request_cookie(request); + + req.vdev = ndi_vdev; + status = ucfg_nan_req_processor(NULL, &req, NDP_END_ALL); + + if (QDF_IS_STATUS_ERROR(status)) { + nan_err("Unable to disable NDP's on NDI"); + wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID); + goto cleanup; + } + + nan_debug("Disabling all NDP's on NDI vdev id - %d", ndi_vdev_id); + + err = osif_request_wait_for_response(request); + if (err) { + nan_err("Disabling NDP's timed out waiting for confirmation"); + status = QDF_STATUS_E_TIMEOUT; + } + +cleanup: + /* + * Host can assume NDP delete is successful and + * remove policy mgr entry + */ + policy_mgr_decr_session_set_pcl(psoc, QDF_NDI_MODE, ndi_vdev_id); + + ucfg_nan_set_ndi_state(ndi_vdev, NAN_DATA_DISCONNECTED_STATE); + + if (request) + osif_request_put(request); + + return status; +} + +QDF_STATUS +ucfg_nan_check_and_disable_unsupported_ndi(struct wlan_objmgr_psoc *psoc, + bool force) +{ + uint32_t ndi_count, first_ndi_vdev_id, i; + QDF_STATUS status; + + if (!psoc) { + nan_err("psoc object is NULL, no action will be taken"); + return QDF_STATUS_E_INVAL; + } + + if (!ucfg_is_ndi_dbs_supported(psoc)) + return QDF_STATUS_SUCCESS; + + ndi_count = policy_mgr_mode_specific_connection_count(psoc, PM_NDI_MODE, + NULL); + /* NDP force disable is done for unsupported concurrencies: NDI+SAP */ + if (force) { + nan_debug("Force disable all NDPs"); + for (i = 0; i < ndi_count; i++) { + first_ndi_vdev_id = + policy_mgr_mode_specific_vdev_id(psoc, + PM_NDI_MODE); + status = ucfg_nan_disable_ndi(psoc, first_ndi_vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + } + return QDF_STATUS_SUCCESS; + } + + if (ndi_count < 2) { + nan_debug("No more than one NDI is active, nothing to do..."); + return QDF_STATUS_SUCCESS; + } + + /* + * At least 2 NDI active concurrencies exist. Disable all NDP's on the + * first NDI to support an incoming connection. + */ + first_ndi_vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_NDI_MODE); + status = ucfg_nan_disable_ndi(psoc, first_ndi_vdev_id); + + return status; +} + +QDF_STATUS ucfg_ndi_remove_entry_from_policy_mgr(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct nan_psoc_priv_obj *psoc_priv_obj; + struct nan_vdev_priv_obj *vdev_priv_obj = nan_get_vdev_priv_obj(vdev); + enum nan_datapath_state state; + uint32_t active_ndp_peers; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + nan_err("can't get psoc"); + return QDF_STATUS_E_FAILURE; + } + + psoc_priv_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_priv_obj) { + nan_err("psoc_priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!vdev_priv_obj) { + nan_err("priv_obj is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&vdev_priv_obj->lock); + state = vdev_priv_obj->state; + active_ndp_peers = vdev_priv_obj->active_ndp_peers; + qdf_spin_unlock_bh(&vdev_priv_obj->lock); + + if (state == NAN_DATA_NDI_DELETED_STATE && + NDI_CONCURRENCY_SUPPORTED(psoc) && + active_ndp_peers) { + nan_info("Delete NDP peers: %u and remove NDI from policy mgr", + active_ndp_peers); + policy_mgr_decr_session_set_pcl(psoc, QDF_NDI_MODE, + wlan_vdev_get_id(vdev)); + } + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_nan_is_enable_disable_in_progress(struct wlan_objmgr_psoc *psoc) +{ + enum nan_disc_state nan_state; + + nan_state = nan_get_discovery_state(psoc); + if (nan_state == NAN_DISC_ENABLE_IN_PROGRESS || + nan_state == NAN_DISC_DISABLE_IN_PROGRESS) { + nan_info("NAN enable/disable is in progress, state: %u", + nan_state); + return true; + } + + return false; +} + +#ifdef NDP_SAP_CONCURRENCY_ENABLE +/** + * is_sap_ndp_concurrency_allowed() - Is SAP+NDP allowed + * + * Return: True if the NDP_SAP_CONCURRENCY_ENABLE feature define + * is enabled, false otherwise. + */ +static inline bool is_sap_ndp_concurrency_allowed(void) +{ + return true; +} +#else +static inline bool is_sap_ndp_concurrency_allowed(void) +{ + return false; +} +#endif + +bool ucfg_nan_is_sta_ndp_concurrency_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t ndi_cnt, id, conc_ext_flags; + + if (nan_is_sta_sta_concurrency_present(psoc)) { + nan_err("STA+STA+NDP concurrency is not allowed"); + return false; + } + + /* + * SAP+NDP concurrency is already validated in hdd_is_ndp_allowed(). + * If SAP+NDP concurrency is enabled, return true from here to avoid + * failure. + */ + if (is_sap_ndp_concurrency_allowed()) + return true; + + /* ML STA + NAN + NDP concurrency is allowed only if firmware + * support is present + */ + if (policy_mgr_is_mlo_sta_present(psoc) && + !wlan_is_mlo_sta_nan_ndi_allowed(psoc)) + return false; + + ndi_cnt = policy_mgr_get_mode_specific_conn_info(psoc, + freq_list, + vdev_id_list, + PM_NDI_MODE); + + /* Allow if no other NDP peers are present on the NDIs */ + if (!ndi_cnt) + return true; + + /* + * Allow NDP creation if the current NDP request is on + * the NDI which already has an NDP by checking the vdev id of + * the NDIs + */ + for (id = 0; id < ndi_cnt; id++) + if (wlan_vdev_get_id(vdev) == vdev_id_list[id]) + return true; + + /* If the flow reaches here then it is 4th NDI with STA */ + if (!ucfg_nan_is_sta_nan_ndi_4_port_allowed(psoc)) + return false; + + conc_ext_flags = policy_mgr_get_conc_ext_flags(vdev, false); + + /* The final freq would be provided by FW, it is not known now */ + return policy_mgr_allow_concurrency(psoc, PM_NDI_MODE, 0, + HW_MODE_20_MHZ, conc_ext_flags, + wlan_vdev_get_id(vdev)); +} + +bool +ucfg_nan_is_sta_nan_ndi_4_port_allowed(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return false; + } + + return psoc_nan_obj->nan_caps.sta_nan_ndi_ndi_allowed; +} + +bool ucfg_nan_is_beamforming_supported(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return false; + } + + return psoc_nan_obj->nan_caps.ndi_txbf_supported; +} + +static inline bool +ucfg_is_nan_enabled(struct nan_psoc_priv_obj *psoc_nan_obj) +{ + return psoc_nan_obj->cfg_param.enable; +} + +static inline bool +ucfg_nan_is_vdev_creation_supp_by_fw(struct nan_psoc_priv_obj *psoc_nan_obj) +{ + return psoc_nan_obj->nan_caps.nan_vdev_allowed; +} + +static inline bool +ucfg_nan_is_vdev_creation_supp_by_host(struct nan_psoc_priv_obj *nan_obj) +{ + return nan_obj->cfg_param.nan_separate_iface_support; +} + +static void ucfg_nan_cleanup_all_ndps(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + uint32_t ndi_count, vdev_id, i; + + ndi_count = policy_mgr_mode_specific_connection_count(psoc, PM_NDI_MODE, + NULL); + for (i = 0; i < ndi_count; i++) { + vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_NDI_MODE); + status = ucfg_nan_disable_ndi(psoc, vdev_id); + if (status == QDF_STATUS_E_TIMEOUT) + policy_mgr_decr_session_set_pcl(psoc, QDF_NDI_MODE, + vdev_id); + } +} + +QDF_STATUS ucfg_disable_nan_discovery(struct wlan_objmgr_psoc *psoc, + uint8_t *data, uint32_t data_len) +{ + struct nan_disable_req *nan_req; + QDF_STATUS status; + + ucfg_nan_cleanup_all_ndps(psoc); + + nan_req = qdf_mem_malloc(sizeof(*nan_req) + data_len); + if (!nan_req) + return -ENOMEM; + qdf_mem_zero(nan_req, sizeof(*nan_req) + data_len); + + nan_req->psoc = psoc; + nan_req->disable_2g_discovery = true; + nan_req->disable_5g_discovery = true; + if (data_len && data) { + nan_req->params.request_data_len = data_len; + qdf_mem_copy(nan_req->params.request_data, data, data_len); + } + + status = ucfg_nan_discovery_req(nan_req, NAN_DISABLE_REQ); + + if (QDF_IS_STATUS_SUCCESS(status)) + nan_debug("Successfully sent NAN Disable request"); + else + nan_debug("Unable to send NAN Disable request: %u", status); + + qdf_mem_free(nan_req); + return status; +} + +bool ucfg_nan_is_vdev_creation_allowed(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + bool host_support, fw_support; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return false; + } + + if (!ucfg_is_nan_enabled(psoc_nan_obj)) { + nan_debug("NAN is not enabled"); + return false; + } + + host_support = ucfg_nan_is_vdev_creation_supp_by_host(psoc_nan_obj); + fw_support = ucfg_nan_is_vdev_creation_supp_by_fw(psoc_nan_obj); + if (!host_support || !fw_support) { + nan_debug("NAN separate vdev%s supported by host,%s supported by firmware", + host_support ? "" : " not", fw_support ? "" : " not"); + return false; + } + + return true; +} + +void +ucfg_nan_set_vdev_creation_supp_by_fw(struct wlan_objmgr_psoc *psoc, bool set) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return; + } + + psoc_nan_obj->nan_caps.nan_vdev_allowed = set; +} + +QDF_STATUS ucfg_get_nan_feature_config(struct wlan_objmgr_psoc *psoc, + uint32_t *nan_feature_config) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + *nan_feature_config = cfg_default(CFG_NAN_FEATURE_CONFIG); + return QDF_STATUS_E_INVAL; + } + + *nan_feature_config = psoc_nan_obj->cfg_param.nan_feature_config; + return QDF_STATUS_SUCCESS; +} + +bool ucfg_is_nan_vdev(struct wlan_objmgr_vdev *vdev) +{ + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_NAN_DISC_MODE || + (!ucfg_nan_is_vdev_creation_allowed(wlan_vdev_get_psoc(vdev)) && + wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE)) + return true; + + return false; +} + +QDF_STATUS ucfg_nan_disable_ind_to_userspace(struct wlan_objmgr_psoc *psoc) +{ + struct nan_psoc_priv_obj *psoc_nan_obj; + struct nan_event_params *disable_ind; + struct nan_disable_ind_msg msg = { + .msg_hdr.msg_id = NAN_MSG_ID_DISABLE_INDICATION, + .reason = 0, /* success */ }; + + psoc_nan_obj = nan_get_psoc_priv_obj(psoc); + if (!psoc_nan_obj) { + nan_err("psoc_nan_obj is null"); + return QDF_STATUS_E_INVAL; + } + + disable_ind = qdf_mem_malloc(sizeof(struct nan_event_params) + + sizeof(msg)); + if (!disable_ind) + return QDF_STATUS_E_NOMEM; + + disable_ind->psoc = psoc, + disable_ind->evt_type = nan_event_id_disable_ind; + disable_ind->buf_len = sizeof(msg); + qdf_mem_copy(disable_ind->buf, &msg, disable_ind->buf_len); + + psoc_nan_obj->cb_obj.os_if_nan_event_handler(disable_ind); + + qdf_mem_free(disable_ind); + return QDF_STATUS_SUCCESS; +} + +bool ucfg_is_nan_allowed_on_freq(struct wlan_objmgr_pdev *pdev, uint32_t freq) +{ + return wlan_is_nan_allowed_on_freq(pdev, freq); +} + +bool ucfg_is_mlo_sta_nan_ndi_allowed(struct wlan_objmgr_psoc *psoc) +{ + return wlan_is_mlo_sta_nan_ndi_allowed(psoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/wlan_nan_api.c b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/wlan_nan_api.c new file mode 100644 index 0000000000..580fb56992 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/nan/dispatcher/src/wlan_nan_api.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains definitions for NAN component + */ + +#include "nan_public_structs.h" +#include "wlan_nan_api.h" +#include "../../core/src/nan_main_i.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_nan_api_i.h" +#include "cfg_nan_api.h" + +inline enum nan_datapath_state wlan_nan_get_ndi_state( + struct wlan_objmgr_vdev *vdev) +{ + enum nan_datapath_state val; + struct nan_vdev_priv_obj *priv_obj = nan_get_vdev_priv_obj(vdev); + + if (!priv_obj) { + nan_err("priv_obj is null"); + return NAN_DATA_INVALID_STATE; + } + + qdf_spin_lock_bh(&priv_obj->lock); + val = priv_obj->state; + qdf_spin_unlock_bh(&priv_obj->lock); + + return val; +} + +uint8_t wlan_nan_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + tSirMacAddr bssid, + wlan_objmgr_ref_dbgid dbg_id) +{ + return nan_get_vdev_id_from_bssid(pdev, bssid, dbg_id); +} + +bool wlan_nan_is_disc_active(struct wlan_objmgr_psoc *psoc) +{ + return nan_is_disc_active(psoc); +} + +bool wlan_nan_is_eht_capable(struct wlan_objmgr_psoc *psoc) +{ + return cfg_nan_is_eht_cap_enable(psoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/core/inc/wlan_ocb_main.h b/qcom/opensource/wlan/qcacld-3.0/components/ocb/core/inc/wlan_ocb_main.h new file mode 100644 index 0000000000..49a0aa5032 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/core/inc/wlan_ocb_main.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains ocb init/deinit public api + */ + +#ifndef _WLAN_OCB_MAIN_API_H_ +#define _WLAN_OCB_MAIN_API_H_ + +#include +#include +#include +#include +#include + +#define ocb_alert_rl(params...) QDF_TRACE_FATAL_RL(QDF_MODULE_ID_OCB, params) +#define ocb_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_OCB, params) +#define ocb_warn_rl(params...) QDF_TRACE_WARN_RL(QDF_MODULE_ID_OCB, params) +#define ocb_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_OCB, params) +#define ocb_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_OCB, params) + +#define ocb_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_OCB, params) +#define ocb_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_OCB, params) +#define ocb_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_OCB, params) +#define ocb_notice(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_OCB, params) +#define ocb_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_OCB, params) +#define ocb_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_OCB, params) + +#define ocb_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_OCB, params) +#define ocb_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_OCB, params) +#define ocb_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_OCB, params) +#define ocb_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_OCB, params) +#define ocb_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_OCB, params) + +/** + * enum ocb_southbound_event - OCB south bound event type + * @OCB_CHANNEL_CONFIG_STATUS: set channel config response + * @OCB_TSF_TIMER: get TSF timer response + * @OCB_DCC_STATS_RESPONSE: get DCC stats response + * @OCB_NDL_RESPONSE: NDL update response + * @OCB_DCC_INDICATION: DCC stats indication + */ +enum ocb_southbound_event { + OCB_CHANNEL_CONFIG_STATUS, + OCB_TSF_TIMER, + OCB_DCC_STATS_RESPONSE, + OCB_NDL_RESPONSE, + OCB_DCC_INDICATION, +}; + +/** + * struct ocb_pdev_obj - ocb pdev object + * @pdev: pdev handle + * @ocb_mac: MAC address for different channels + * @ocb_channel_count: channel count + * @channel_config: current channel configurations + * @dp_soc: psoc data path handle + * @dp_pdev_id: pdev data path ID + * @ocb_cbs: legacy callback functions + * @ocb_txops: tx operations for target interface + * @ocb_rxops: rx operations for target interface + */ +struct ocb_pdev_obj { + struct wlan_objmgr_pdev *pdev; + struct qdf_mac_addr ocb_mac[QDF_MAX_CONCURRENCY_PERSONA]; + uint32_t ocb_channel_count; + struct ocb_config *channel_config; + void *dp_soc; + uint8_t dp_pdev_id; + struct ocb_callbacks ocb_cbs; + struct wlan_ocb_tx_ops ocb_txops; + struct wlan_ocb_rx_ops ocb_rxops; +}; + +/** + * struct ocb_rx_event - event from south bound + * @psoc: psoc handle + * @vdev: vdev handle + * @evt_id: event ID + * @rsp: Union of response structs, @evt_id is the selector + * @channel_cfg_rsp: set channel config status + * @tsf_timer: get TSF timer response + * @ndl: NDL DCC response + * @dcc_stats: DCC stats + */ +struct ocb_rx_event { + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + uint32_t evt_id; + union event { + struct ocb_set_config_response channel_cfg_rsp; + struct ocb_get_tsf_timer_response tsf_timer; + struct ocb_dcc_update_ndl_response ndl; + struct ocb_dcc_get_stats_response dcc_stats; + } rsp; +}; + +/** + * wlan_get_pdev_ocb_obj() - private API to get ocb pdev object + * @pdev: pdev object + * + * Return: ocb object + */ +static inline struct ocb_pdev_obj * +wlan_get_pdev_ocb_obj(struct wlan_objmgr_pdev *pdev) +{ + struct ocb_pdev_obj *pdev_obj; + + pdev_obj = (struct ocb_pdev_obj *) + wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_OCB); + + return pdev_obj; +} + +/** + * wlan_ocb_get_callbacks() - get legacy layer callbacks + * @pdev: pdev handle + * + * Return: legacy layer callbacks + */ +static inline struct ocb_callbacks * +wlan_ocb_get_callbacks(struct wlan_objmgr_pdev *pdev) +{ + struct ocb_pdev_obj *pdev_obj; + + pdev_obj = wlan_get_pdev_ocb_obj(pdev); + + if (pdev_obj) + return &pdev_obj->ocb_cbs; + else + return NULL; +} + +/** + * wlan_pdev_get_ocb_tx_ops() - get OCB tx operations + * @pdev: pdev handle + * + * Return: fps to OCB tx operations + */ +static inline struct wlan_ocb_tx_ops * +wlan_pdev_get_ocb_tx_ops(struct wlan_objmgr_pdev *pdev) +{ + struct ocb_pdev_obj *ocb_obj; + + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + + return &ocb_obj->ocb_txops; +} + +/** + * wlan_ocb_release_rx_event() - Release OCB RX event + * @event: OCB RX event + * + * Return: none + */ +static inline void wlan_ocb_release_rx_event(struct ocb_rx_event *event) +{ + + if (!event) { + ocb_err("event is NULL"); + return; + } + + if (event->vdev) + wlan_objmgr_vdev_release_ref(event->vdev, WLAN_OCB_SB_ID); + if (event->psoc) + wlan_objmgr_psoc_release_ref(event->psoc, WLAN_OCB_SB_ID); + qdf_mem_free(event); +} + +/** + * ocb_pdev_obj_create_notification() - OCB pdev object creation notification + * @pdev: pdev handle + * @arg_list: arguments list + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, + void *arg_list); + +/** + * ocb_pdev_obj_destroy_notification() - OCB pdev object destroy notification + * @pdev: pdev handle + * @arg_list: arguments list + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, + void *arg_list); + +/** + * ocb_config_new() - Creates a new OCB configuration + * @num_channels: the number of channels + * @num_schedule: the schedule size + * @ndl_chan_list_len: length in bytes of the NDL chan blob + * @ndl_active_state_list_len: length in bytes of the active state blob + * + * Return: A pointer to the OCB configuration struct, NULL on failure. + */ +struct ocb_config *ocb_config_new(uint32_t num_channels, + uint32_t num_schedule, + uint32_t ndl_chan_list_len, + uint32_t ndl_active_state_list_len); + +/** + * ocb_copy_config() - Backup current config parameters + * @src: current config parameters + * + * Return: A pointer to the OCB configuration struct, NULL on failure. + */ +struct ocb_config *ocb_copy_config(struct ocb_config *src); + +/** + * ocb_process_evt() - API to process event from south bound + * @msg: south bound message + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ocb_process_evt(struct scheduler_msg *msg); + +/** + * ocb_vdev_start() - start OCB vdev + * @ocb_obj: OCB object + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ocb_vdev_start(struct ocb_pdev_obj *ocb_obj); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/core/src/wlan_ocb_main.c b/qcom/opensource/wlan/qcacld-3.0/components/ocb/core/src/wlan_ocb_main.c new file mode 100644 index 0000000000..03dc0da0f3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/core/src/wlan_ocb_main.c @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains core ocb function definitions + */ + +#include +#include "scheduler_api.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include +#include +#include +#include "wlan_ocb_main.h" +#include "wlan_ocb_tgt_api.h" +#include "target_if_ocb.h" + +/** + * ocb_get_evt_type_str() - parse event to string + * @evt_type: ocb event type + * + * This function parse ocb event to string. + * + * Return: command string + */ +static const char *ocb_get_evt_type_str(enum ocb_southbound_event evt_type) +{ + switch (evt_type) { + case OCB_CHANNEL_CONFIG_STATUS: + return "OCB channel config status"; + case OCB_TSF_TIMER: + return "OCB TSF timer"; + case OCB_DCC_STATS_RESPONSE: + return "OCB DCC get stats response"; + case OCB_NDL_RESPONSE: + return "OCB NDL indication"; + case OCB_DCC_INDICATION: + return "OCB DCC stats indication"; + default: + return "Invalid OCB command"; + } +} + +/** + * ocb_set_chan_info() - Set channel info to dp + * @dp_soc: data path soc handle + * @dp_pdev: data path pdev handle + * @vdev_id: OCB vdev_id + * @config: channel config parameters + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS ocb_set_chan_info(void *dp_soc, + void *dp_pdev, + uint32_t vdev_id, + struct ocb_config *config) +{ + struct ol_txrx_ocb_set_chan ocb_set_chan; + struct ol_txrx_ocb_chan_info *ocb_channel_info; + + if (!dp_soc || !dp_pdev) { + ocb_err("DP global handle is null"); + return QDF_STATUS_E_INVAL; + } + + ocb_set_chan.ocb_channel_count = config->channel_count; + + /* release old settings */ + ocb_channel_info = cdp_get_ocb_chan_info(dp_soc, vdev_id); + if (ocb_channel_info) + qdf_mem_free(ocb_channel_info); + + if (config->channel_count) { + int i, buf_size; + + buf_size = sizeof(*ocb_channel_info) * config->channel_count; + ocb_set_chan.ocb_channel_info = qdf_mem_malloc(buf_size); + if (!ocb_set_chan.ocb_channel_info) + return QDF_STATUS_E_NOMEM; + + ocb_channel_info = ocb_set_chan.ocb_channel_info; + for (i = 0; i < config->channel_count; i++) { + ocb_channel_info[i].chan_freq = + config->channels[i].chan_freq; + if (config->channels[i].flags & + OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR) + ocb_channel_info[i].disable_rx_stats_hdr = 1; + } + } else { + ocb_debug("No channel config to dp"); + ocb_set_chan.ocb_channel_info = NULL; + } + ocb_debug("Sync channel config to dp"); + cdp_set_ocb_chan_info(dp_soc, vdev_id, ocb_set_chan); + + return QDF_STATUS_SUCCESS; +} + +/** + * ocb_channel_config_status() - Process set channel config response + * @evt: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS ocb_channel_config_status(struct ocb_rx_event *evt) +{ + QDF_STATUS status; + uint32_t vdev_id; + struct ocb_rx_event *event; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct ocb_pdev_obj *ocb_obj; + struct ocb_callbacks *cbs; + struct ocb_set_config_response config_rsp; + + if (!evt) { + ocb_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + event = evt; + psoc = event->psoc; + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_OCB_SB_ID); + if (!pdev) { + ocb_alert("Pdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + if (!ocb_obj) { + ocb_err("Pdev object is NULL"); + status = QDF_STATUS_E_INVAL; + goto exit; + } + + cbs = &ocb_obj->ocb_cbs; + if (ocb_obj->channel_config) { + vdev_id = ocb_obj->channel_config->vdev_id; + config_rsp = event->rsp.channel_cfg_rsp; + + /* Sync channel status to data path */ + if (config_rsp.status == OCB_CHANNEL_CONFIG_SUCCESS) + ocb_set_chan_info(ocb_obj->dp_soc, + ocb_obj->pdev, + vdev_id, + ocb_obj->channel_config); + qdf_mem_free(ocb_obj->channel_config); + ocb_obj->channel_config = NULL; + } else { + ocb_err("Failed to sync channel info to DP"); + config_rsp.status = OCB_CHANNEL_CONFIG_FAIL; + } + + if (cbs->ocb_set_config_callback) { + cbs->ocb_set_config_callback(cbs->ocb_set_config_context, + &config_rsp); + status = QDF_STATUS_SUCCESS; + } else { + ocb_err("ocb_set_config_resp_cb is NULL"); + status = QDF_STATUS_E_INVAL; + } +exit: + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); + + return status; +} + +/** + * ocb_tsf_timer() - Process get TSF timer response + * @evt: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS ocb_tsf_timer(struct ocb_rx_event *evt) +{ + QDF_STATUS status; + struct ocb_rx_event *event; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct ocb_callbacks *cbs; + struct ocb_get_tsf_timer_response *tsf_timer; + + if (!evt) { + ocb_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + event = evt; + vdev = event->vdev; + pdev = wlan_vdev_get_pdev(vdev); + cbs = wlan_ocb_get_callbacks(pdev); + tsf_timer = &event->rsp.tsf_timer; + ocb_debug("TSF timer low=%d, high=%d", + tsf_timer->timer_low, tsf_timer->timer_high); + if (cbs && cbs->ocb_get_tsf_timer_callback) { + ocb_debug("send TSF timer"); + cbs->ocb_get_tsf_timer_callback(cbs->ocb_get_tsf_timer_context, + tsf_timer); + status = QDF_STATUS_SUCCESS; + } else { + ocb_err("ocb_get_tsf_timer_cb is NULL"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * ocb_dcc_stats_response() - Process get DCC stats response + * @evt: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS ocb_dcc_stats_response(struct ocb_rx_event *evt) +{ + QDF_STATUS status; + struct ocb_rx_event *event; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct ocb_callbacks *cbs; + struct ocb_dcc_get_stats_response *dcc_stats; + + if (!evt) { + ocb_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + event = evt; + vdev = event->vdev; + pdev = wlan_vdev_get_pdev(vdev); + cbs = wlan_ocb_get_callbacks(pdev); + dcc_stats = &event->rsp.dcc_stats; + if (cbs && cbs->ocb_dcc_get_stats_callback) { + ocb_debug("send DCC stats"); + cbs->ocb_dcc_get_stats_callback(cbs->ocb_dcc_get_stats_context, + dcc_stats); + status = QDF_STATUS_SUCCESS; + } else { + ocb_err("dcc_get_stats_cb is NULL"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * ocb_ndl_response() - Process NDL update response + * @evt: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS ocb_ndl_response(struct ocb_rx_event *evt) +{ + QDF_STATUS status; + struct ocb_rx_event *event; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct ocb_callbacks *cbs; + struct ocb_dcc_update_ndl_response *ndl; + + if (!evt) { + ocb_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + event = evt; + vdev = event->vdev; + pdev = wlan_vdev_get_pdev(vdev); + cbs = wlan_ocb_get_callbacks(pdev); + ndl = &event->rsp.ndl; + if (cbs && cbs->ocb_dcc_update_ndl_callback) { + ocb_debug("NDL update response"); + cbs->ocb_dcc_update_ndl_callback( + cbs->ocb_dcc_update_ndl_context, ndl); + status = QDF_STATUS_SUCCESS; + } else { + ocb_err("dcc_update_ndl is NULL"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * ocb_dcc_indication() - Process DCC stats indication + * @evt: response event + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS ocb_dcc_indication(struct ocb_rx_event *evt) +{ + QDF_STATUS status; + struct ocb_rx_event *event; + struct wlan_objmgr_vdev *vdev; + struct ocb_callbacks *cbs; + struct wlan_objmgr_pdev *pdev; + struct ocb_dcc_get_stats_response *dcc_stats; + + if (!evt) { + ocb_err("Event buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + event = evt; + vdev = event->vdev; + pdev = wlan_vdev_get_pdev(vdev); + cbs = wlan_ocb_get_callbacks(pdev); + dcc_stats = &event->rsp.dcc_stats; + if (cbs && cbs->ocb_dcc_stats_event_callback) { + ocb_debug("DCC stats indication"); + cbs->ocb_dcc_stats_event_callback( + cbs->ocb_dcc_stats_event_context, dcc_stats); + status = QDF_STATUS_SUCCESS; + } else { + ocb_err("dcc_get_stats_cb is NULL"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * ocb_flush_start_msg() - Flush ocb start message + * @msg: OCB start vdev message + * + * Return: QDF_STATUS_SUCCESS on success. + */ +static QDF_STATUS ocb_flush_start_msg(struct scheduler_msg *msg) +{ + struct ocb_pdev_obj *ocb_obj; + + if (!msg) { + ocb_err("Null point for OCB message"); + return QDF_STATUS_E_INVAL; + } + + ocb_obj = msg->bodyptr; + if (ocb_obj && ocb_obj->channel_config) { + ocb_info("release the backed config parameters"); + qdf_mem_free(ocb_obj->channel_config); + ocb_obj->channel_config = NULL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ocb_process_start_vdev_msg() - Handler for OCB vdev start message + * @msg: OCB start vdev message + * + * Return: QDF_STATUS_SUCCESS on success. + */ +static QDF_STATUS ocb_process_start_vdev_msg(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct ocb_config *config; + struct ocb_pdev_obj *ocb_obj; + struct ocb_callbacks *ocb_cbs; + struct wlan_objmgr_vdev *vdev; + + if (!msg || !msg->bodyptr) { + ocb_err("invalid message"); + return QDF_STATUS_E_INVAL; + } + + ocb_obj = msg->bodyptr; + ocb_cbs = &ocb_obj->ocb_cbs; + if (!ocb_cbs->start_ocb_vdev) { + ocb_err("No callback to start ocb vdev"); + return QDF_STATUS_E_FAILURE; + } + + config = ocb_obj->channel_config; + if (!config) { + ocb_err("NULL config parameters"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ocb_obj->pdev, + config->vdev_id, + WLAN_OCB_SB_ID); + if (!vdev) { + ocb_err("Cannot get vdev"); + return QDF_STATUS_E_FAILURE; + } + + ocb_debug("Start to send OCB vdev start cmd"); + status = ocb_cbs->start_ocb_vdev(config); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OCB_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to start OCB vdev"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ocb_vdev_start(struct ocb_pdev_obj *ocb_obj) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + + msg.bodyptr = ocb_obj; + msg.callback = ocb_process_start_vdev_msg; + msg.flush_callback = ocb_flush_start_msg; + status = scheduler_post_message(QDF_MODULE_ID_OCB, + QDF_MODULE_ID_OCB, + QDF_MODULE_ID_TARGET_IF, &msg); + + return status; +} + +QDF_STATUS ocb_process_evt(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct ocb_rx_event *event; + + ocb_debug("msg type %d, %s", msg->type, + ocb_get_evt_type_str(msg->type)); + + if (!(msg->bodyptr)) { + ocb_err("Invalid message body"); + return QDF_STATUS_E_INVAL; + } + event = msg->bodyptr; + switch (msg->type) { + case OCB_CHANNEL_CONFIG_STATUS: + status = ocb_channel_config_status(event); + break; + case OCB_TSF_TIMER: + status = ocb_tsf_timer(event); + break; + case OCB_DCC_STATS_RESPONSE: + status = ocb_dcc_stats_response(event); + break; + case OCB_NDL_RESPONSE: + status = ocb_ndl_response(event); + break; + case OCB_DCC_INDICATION: + status = ocb_dcc_indication(event); + break; + default: + status = QDF_STATUS_E_INVAL; + break; + } + + wlan_ocb_release_rx_event(event); + msg->bodyptr = NULL; + + return status; +} + +struct ocb_config *ocb_copy_config(struct ocb_config *src) +{ + struct ocb_config *dst; + uint32_t length; + uint8_t *cursor; + + length = sizeof(*src) + + src->channel_count * sizeof(*src->channels) + + src->schedule_size * sizeof(*src->schedule) + + src->dcc_ndl_chan_list_len + + src->dcc_ndl_active_state_list_len; + + dst = qdf_mem_malloc(length); + if (!dst) + return NULL; + + *dst = *src; + + cursor = (uint8_t *)dst; + cursor += sizeof(*dst); + dst->channels = (struct ocb_config_chan *)cursor; + cursor += src->channel_count * sizeof(*dst->channels); + qdf_mem_copy(dst->channels, src->channels, + src->channel_count * sizeof(*dst->channels)); + dst->schedule = (struct ocb_config_schdl *)cursor; + cursor += src->schedule_size * sizeof(*dst->schedule); + qdf_mem_copy(dst->schedule, src->schedule, + src->schedule_size * sizeof(*dst->schedule)); + dst->dcc_ndl_chan_list = cursor; + cursor += src->dcc_ndl_chan_list_len; + qdf_mem_copy(dst->dcc_ndl_chan_list, src->dcc_ndl_chan_list, + src->dcc_ndl_chan_list_len); + dst->dcc_ndl_active_state_list = cursor; + cursor += src->dcc_ndl_active_state_list_len; + qdf_mem_copy(dst->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list, + src->dcc_ndl_active_state_list_len); + + return dst; +} + +QDF_STATUS ocb_pdev_obj_create_notification(struct wlan_objmgr_pdev *pdev, + void *arg_list) +{ + QDF_STATUS status; + struct ocb_pdev_obj *ocb_obj; + + ocb_notice("ocb pdev created"); + ocb_obj = qdf_mem_malloc(sizeof(*ocb_obj)); + if (!ocb_obj) + return QDF_STATUS_E_FAILURE; + + status = wlan_objmgr_pdev_component_obj_attach(pdev, + WLAN_UMAC_COMP_OCB, + (void *)ocb_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to attach pdev ocb component"); + qdf_mem_free(ocb_obj); + return status; + } + ocb_obj->pdev = pdev; + + /* register OCB tx/rx ops */ + tgt_ocb_register_rx_ops(&ocb_obj->ocb_rxops); + target_if_ocb_register_tx_ops(&ocb_obj->ocb_txops); + ocb_notice("ocb pdev attached"); + + return status; +} + +QDF_STATUS ocb_pdev_obj_destroy_notification(struct wlan_objmgr_pdev *pdev, + void *arg_list) +{ + QDF_STATUS status; + struct ocb_pdev_obj *ocb_obj; + + ocb_obj = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_OCB); + if (!ocb_obj) { + ocb_err("Failed to get ocb pdev object"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_pdev_component_obj_detach(pdev, + WLAN_UMAC_COMP_OCB, + ocb_obj); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to detach ocb pdev object"); + + qdf_mem_free(ocb_obj); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_public_structs.h new file mode 100644 index 0000000000..4a65d4687b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_public_structs.h @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains ocb structure definitions + */ + +#ifndef _WLAN_OCB_STRUCTS_H_ +#define _WLAN_OCB_STRUCTS_H_ +#include +#include "qca_vendor.h" + +/* Don't add the RX stats header to packets received on this channel */ +#define OCB_CHANNEL_FLAG_DISABLE_RX_STATS_HDR (1 << 0) + +/* The size of the utc time in bytes. */ +#define OCB_SIZE_UTC_TIME (10) + +/* The size of the utc time error in bytes. */ +#define OCB_SIZE_UTC_TIME_ERROR (5) + +/** + * struct ocb_utc_param - parameters to set UTC time + * @vdev_id: vdev id + * @utc_time: number of nanoseconds from Jan 1st 1958 + * @time_error: the error in the UTC time. All 1's for unknown + */ +struct ocb_utc_param { + uint32_t vdev_id; + uint8_t utc_time[OCB_SIZE_UTC_TIME]; + uint8_t time_error[OCB_SIZE_UTC_TIME_ERROR]; +}; + +/** + * struct ocb_timing_advert_param - parameters to start/stop + * timing advertisement + * @vdev_id: vdev id + * @chan_freq: frequency on which to advertise (unit in Mhz) + * @repeat_rate: the number of times it will send TA in 5 seconds + * @timestamp_offset: offset of the timestamp field in the TA frame + * @time_value_offset: offset of the time_value field in the TA frame + * @template_length: size in bytes of the TA frame + * @template_value: the TA frame + */ +struct ocb_timing_advert_param { + uint32_t vdev_id; + uint32_t chan_freq; + uint32_t repeat_rate; + uint32_t timestamp_offset; + uint32_t time_value_offset; + uint32_t template_length; + uint8_t *template_value; +}; + +/** + * struct ocb_dcc_get_stats_param - parameters to get DCC stats + * @vdev_id: vdev id + * @channel_count: number of dcc channels + * @request_array_len: size in bytes of the request array + * @request_array: the request array + */ +struct ocb_dcc_get_stats_param { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t request_array_len; + void *request_array; +}; + +/** + * struct ocb_dcc_update_ndl_param - parameters to update NDL + * @vdev_id: vdev id + * @channel_count: number of channels to be updated + * @dcc_ndl_chan_list_len: size in bytes of the ndl_chan array + * @dcc_ndl_chan_list: the ndl_chan array + * @dcc_ndl_active_state_list_len: size in bytes of the active_state array + * @dcc_ndl_active_state_list: the active state array + */ +struct ocb_dcc_update_ndl_param { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +/** + * struct ocb_config_schdl - parameters for channel scheduling + * @chan_freq: frequency of the channel (unit in Mhz) + * @total_duration: duration of the schedule (unit in ms) + * @guard_interval: guard interval on the start of the schedule (unit in ms) + */ +struct ocb_config_schdl { + uint32_t chan_freq; + uint32_t total_duration; + uint32_t guard_interval; +}; + +/** + * struct ocb_wmm_param - WMM parameters + * @aifsn: AIFS number + * @cwmin: value of CWmin + * @cwmax: value of CWmax + */ +struct ocb_wmm_param { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct ocb_config_chan - parameters to configure a channel + * @chan_freq: frequency of the channel (unit in MHz) + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @mac_address: MAC address assigned to this channel + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (dBm) + * @min_pwr: minimum transmit power of the channel (dBm) + * @reg_pwr: maximum transmit power specified by the regulatory domain (dBm) + * @antenna_max: maximum antenna gain specified by the regulatory domain (dB) + * @flags: bit0: 0 enable RX stats on this channel; 1 disable RX stats + * bit1: flag to indicate TSF expiry time in TX control. + * 0 relative time is used. 1 absolute time is used. + * bit2: Frame mode from user layer. + * 0 for 802.3 frame, 1 for 802.11 frame. + * @ch_mode: channel mode + */ +struct ocb_config_chan { + uint32_t chan_freq; + uint32_t bandwidth; + struct qdf_mac_addr mac_address; + struct ocb_wmm_param qos_params[QCA_WLAN_AC_ALL]; + uint32_t max_pwr; + uint32_t min_pwr; + uint8_t reg_pwr; + uint8_t antenna_max; + uint16_t flags; + uint32_t ch_mode; +}; + +/** + * struct ocb_config - parameters for OCB vdev config + * @vdev_id: vdev id + * @channel_count: number of channels + * @schedule_size: size of the channel schedule + * @flags: reserved + * @channels: array of OCB channels + * @schedule: array of OCB schedule elements + * @dcc_ndl_chan_list_len: size in bytes of the ndl_chan array + * @dcc_ndl_chan_list: array of dcc channel info + * @dcc_ndl_active_state_list_len: size in bytes of the active state array + * @dcc_ndl_active_state_list: array of active states + */ +struct ocb_config { + uint32_t vdev_id; + uint32_t channel_count; + uint32_t schedule_size; + uint32_t flags; + struct ocb_config_chan *channels; + struct ocb_config_schdl *schedule; + uint32_t dcc_ndl_chan_list_len; + void *dcc_ndl_chan_list; + uint32_t dcc_ndl_active_state_list_len; + void *dcc_ndl_active_state_list; +}; + +/** + * enum ocb_channel_config_status - ocb config status + * @OCB_CHANNEL_CONFIG_SUCCESS: success + * @OCB_CHANNEL_CONFIG_FAIL: failure + * @OCB_CHANNEL_CONFIG_STATUS_MAX: place holder, not a real status + */ +enum ocb_channel_config_status { + OCB_CHANNEL_CONFIG_SUCCESS = 0, + OCB_CHANNEL_CONFIG_FAIL, + OCB_CHANNEL_CONFIG_STATUS_MAX +}; + +/** + * struct ocb_set_config_response - ocb config status + * @status: response status. OCB_CHANNEL_CONFIG_SUCCESS for success. + */ +struct ocb_set_config_response { + enum ocb_channel_config_status status; +}; + +/** + * struct ocb_get_tsf_timer_response - TSF timer response + * @vdev_id: vdev id + * @timer_high: higher 32-bits of the timer + * @timer_low: lower 32-bits of the timer + */ +struct ocb_get_tsf_timer_response { + uint32_t vdev_id; + uint32_t timer_high; + uint32_t timer_low; +}; + +/** + * struct ocb_get_tsf_timer_param - parameters to get tsf timer + * @vdev_id: vdev id + */ +struct ocb_get_tsf_timer_param { + uint32_t vdev_id; +}; + +/** + * struct ocb_dcc_get_stats_response - DCC stats response + * @vdev_id: vdev id + * @num_channels: number of dcc channels + * @channel_stats_array_len: size in bytes of the stats array + * @channel_stats_array: the stats array + */ +struct ocb_dcc_get_stats_response { + uint32_t vdev_id; + uint32_t num_channels; + uint32_t channel_stats_array_len; + void *channel_stats_array; +}; + +/** + * struct ocb_dcc_clear_stats_param - parameters to clear DCC stats + * @vdev_id: vdev id + * @dcc_stats_bitmap: bitmap of clear option + */ +struct ocb_dcc_clear_stats_param { + uint32_t vdev_id; + uint32_t dcc_stats_bitmap; +}; + +/** + * struct ocb_dcc_update_ndl_response - NDP update response + * @vdev_id: vdev id + * @status: response status + */ +struct ocb_dcc_update_ndl_response { + uint32_t vdev_id; + uint32_t status; +}; + +/** + * struct wlan_ocb_rx_ops - structure containing rx ops for OCB + * @ocb_set_config_status: fp to get channel config status + * @ocb_tsf_timer: fp to get TSF timer + * @ocb_dcc_ndl_update: fp to get NDL update status + * @ocb_dcc_stats_indicate: fp to get DCC stats + */ +struct wlan_ocb_rx_ops { + QDF_STATUS (*ocb_set_config_status)(struct wlan_objmgr_psoc *psoc, + uint32_t status); + QDF_STATUS (*ocb_tsf_timer)(struct wlan_objmgr_psoc *psoc, + struct ocb_get_tsf_timer_response *response); + QDF_STATUS (*ocb_dcc_ndl_update)(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_update_ndl_response *resp); + QDF_STATUS (*ocb_dcc_stats_indicate)(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_get_stats_response *response, bool indicate); +}; + +/** + * struct wlan_ocb_tx_ops - structures containing tx ops for OCB + * @ocb_set_config: fp to set channel config + * @ocb_set_utc_time: fp to set utc time + * @ocb_start_timing_advert: fp to start timing advertisement + * @ocb_stop_timing_advert: fp to stop timing advertisement + * @ocb_get_tsf_timer: fp to get tsf timer + * @ocb_dcc_get_stats: fp to get DCC stats + * @ocb_dcc_clear_stats: fp to clear DCC stats + * @ocb_dcc_update_ndl: fp to update ndl + * @ocb_reg_ev_handler: fp to register event handler + * @ocb_unreg_ev_handler: fp to unregister event handler + */ +struct wlan_ocb_tx_ops { + QDF_STATUS (*ocb_set_config)(struct wlan_objmgr_psoc *psoc, + struct ocb_config *config); + QDF_STATUS (*ocb_set_utc_time)(struct wlan_objmgr_psoc *psoc, + struct ocb_utc_param *utc); + QDF_STATUS (*ocb_start_timing_advert)(struct wlan_objmgr_psoc *psoc, + struct ocb_timing_advert_param *timing_advert); + QDF_STATUS (*ocb_stop_timing_advert)(struct wlan_objmgr_psoc *psoc, + struct ocb_timing_advert_param *timing_advert); + QDF_STATUS (*ocb_get_tsf_timer)(struct wlan_objmgr_psoc *psoc, + struct ocb_get_tsf_timer_param *request); + QDF_STATUS (*ocb_dcc_get_stats)(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_get_stats_param *get_stats_param); + QDF_STATUS (*ocb_dcc_clear_stats)(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_clear_stats_param *clear_stats); + QDF_STATUS (*ocb_dcc_update_ndl)(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_update_ndl_param *update_ndl_param); + QDF_STATUS (*ocb_reg_ev_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); + QDF_STATUS (*ocb_unreg_ev_handler)(struct wlan_objmgr_psoc *psoc, + void *arg); +}; + +typedef void (*ocb_sync_callback)(void *context, void *response); + +/** + * struct ocb_callbacks - structure containing callback to legacy driver + * @ocb_set_config_context: context for set channel config callback + * @ocb_set_config_callback: set channel config callback + * @ocb_get_tsf_timer_context: context for get tsf timer callback + * @ocb_get_tsf_timer_callback: get tsf timer callback + * @ocb_dcc_get_stats_context: context for get DCC stats callback + * @ocb_dcc_get_stats_callback: get DCC stats callback + * @ocb_dcc_update_ndl_context: context for NDL update callback + * @ocb_dcc_update_ndl_callback: NDL update callback + * @ocb_dcc_stats_event_context: context for DCC stats event callback + * @ocb_dcc_stats_event_callback: DCC stats event callback + * @start_ocb_vdev: start ocb callback + */ +struct ocb_callbacks { + void *ocb_set_config_context; + ocb_sync_callback ocb_set_config_callback; + void *ocb_get_tsf_timer_context; + ocb_sync_callback ocb_get_tsf_timer_callback; + void *ocb_dcc_get_stats_context; + ocb_sync_callback ocb_dcc_get_stats_callback; + void *ocb_dcc_update_ndl_context; + ocb_sync_callback ocb_dcc_update_ndl_callback; + void *ocb_dcc_stats_event_context; + ocb_sync_callback ocb_dcc_stats_event_callback; + QDF_STATUS (*start_ocb_vdev)(struct ocb_config *config); +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_tgt_api.h new file mode 100644 index 0000000000..4456f603b9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_tgt_api.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: OCB south bound interface declaration + */ +#ifndef _WLAN_OCB_TGT_API_H +#define _WLAN_OCB_TGT_API_H +#include + +/** + * tgt_ocb_register_ev_handler() - register south bound event handler + * @pdev: pdev handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_ocb_unregister_ev_handler() - unregister south bound event handler + * @pdev: pdev handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_ocb_register_rx_ops() - register OCB rx operations + * @ocb_rxops: fps to rx operations + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops *ocb_rxops); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_ucfg_api.h new file mode 100644 index 0000000000..59a539b616 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/inc/wlan_ocb_ucfg_api.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains OCB north bound interface definitions + */ + +#ifndef _WLAN_OCB_UCFG_API_H_ +#define _WLAN_OCB_UCFG_API_H_ +#include +#include "wlan_ocb_public_structs.h" + +#ifdef WLAN_FEATURE_DSRC +/** + * ucfg_ocb_set_channel_config() - send OCB config request + * @vdev: vdev handle + * @config: config parameters + * @set_config_cb: callback for set channel config + * @arg: arguments for the callback + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_set_channel_config(struct wlan_objmgr_vdev *vdev, + struct ocb_config *config, + ocb_sync_callback set_config_cb, + void *arg); + +/** + * ucfg_ocb_set_utc_time() - UCFG API to set UTC time + * @vdev: vdev handle + * @utc: UTC time + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_set_utc_time(struct wlan_objmgr_vdev *vdev, + struct ocb_utc_param *utc); + +/** + * ucfg_ocb_start_timing_advert() - ucfg API to start TA + * @vdev: vdev handle + * @ta: timing advertisement parameters + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_start_timing_advert(struct wlan_objmgr_vdev *vdev, + struct ocb_timing_advert_param *ta); + +/** + * ucfg_ocb_stop_timing_advert() - ucfg API to stop TA + * @vdev: vdev handle + * @ta: timing advertisement parameters + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_stop_timing_advert(struct wlan_objmgr_vdev *vdev, + struct ocb_timing_advert_param *ta); + +/** + * ucfg_ocb_get_tsf_timer() - ucfg API to get tsf timer + * @vdev: vdev handle + * @request: request for TSF timer + * @get_tsf_cb: callback for TSF timer response + * @arg: argument for the ccallback + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_get_tsf_timer(struct wlan_objmgr_vdev *vdev, + struct ocb_get_tsf_timer_param *request, + ocb_sync_callback get_tsf_cb, + void *arg); + +/** + * ucfg_ocb_dcc_get_stats() - get DCC stats + * @vdev: vdev handle + * @request: request for dcc stats + * @dcc_get_stats_cb: callback for get dcc stats response + * @arg: argument for the ccallback + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_dcc_get_stats(struct wlan_objmgr_vdev *vdev, + struct ocb_dcc_get_stats_param *request, + ocb_sync_callback dcc_get_stats_cb, + void *arg); + +/** + * ucfg_ocb_dcc_clear_stats() - Clear DCC stats + * @vdev: vdev handle + * @vdev_id: vdev ID + * @bitmap: bitmap for stats to be cleared + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_dcc_clear_stats(struct wlan_objmgr_vdev *vdev, + uint16_t vdev_id, + uint32_t bitmap); + +/** + * ucfg_ocb_dcc_update_ndl() - ucfg API to update NDL + * @vdev: vdev handle + * @request: request parameters + * @dcc_update_ndl_cb: callback for update response + * @arg: argument for the callback + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_dcc_update_ndl(struct wlan_objmgr_vdev *vdev, + struct ocb_dcc_update_ndl_param *request, + ocb_sync_callback dcc_update_ndl_cb, + void *arg); + +/** + * ucfg_ocb_register_for_dcc_stats_event() - register dcc stats + * events callback + * @pdev: pdev handle + * @ctx: argument for the callback + * @dcc_stats_cb: callback for dcc stats event + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_register_for_dcc_stats_event(struct wlan_objmgr_pdev *pdev, + void *ctx, ocb_sync_callback dcc_stats_cb); + +/** + * ucfg_ocb_init() - OCB module initialization + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_init(void); + +/** + * ucfg_ocb_deinit() - OCB module deinitialization + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_deinit(void); + +/** + * ucfg_ocb_config_channel() - Set channel config using after OCB started + * @pdev: pdev handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_config_channel(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_ocb_register_vdev_start() - register callback to start ocb vdev + * @pdev: pdev handle + * @ocb_start: legacy callback to start ocb vdev + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_register_vdev_start(struct wlan_objmgr_pdev *pdev, + QDF_STATUS (*ocb_start)(struct ocb_config *)); + +/** + * ocb_psoc_enable() - Trigger psoc enable for ocb + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +QDF_STATUS ocb_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ocb_psoc_disable() - Trigger psoc disable for ocb + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +QDF_STATUS ocb_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_ocb_update_dp_handle() - register DP handle + * @soc: soc handle + * @dp_soc: data path soc handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_update_dp_handle(struct wlan_objmgr_psoc *soc, + void *dp_soc); + +/** + * ucfg_ocb_set_txrx_pdev_id() - register txrx pdev id + * @psoc: soc handle + * @pdev_id: data path pdev ID + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS ucfg_ocb_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id); +#else +/** + * ucfg_ocb_init() - OCB module initialization + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline QDF_STATUS ucfg_ocb_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_ocb_deinit() - OCB module deinitialization + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline QDF_STATUS ucfg_ocb_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_ocb_config_channel() - Set channel config using after OCB started + * @pdev: pdev handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline QDF_STATUS +ucfg_ocb_config_channel(struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ocb_psoc_enable() - Trigger psoc enable for ocb + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +static inline +QDF_STATUS ocb_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ocb_psoc_disable() - Trigger psoc disable for ocb + * @psoc: objmgr psoc object + * + * Return: QDF status success or failure + */ +static inline +QDF_STATUS ocb_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_ocb_update_dp_handle() - register DP handle + * @soc: soc handle + * @dp_soc: data path soc handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline +QDF_STATUS ucfg_ocb_update_dp_handle(struct wlan_objmgr_psoc *soc, + void *dp_soc) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ucfg_ocb_set_txrx_pdev_id() - register txrx pdev id + * @psoc: soc handle + * @pdev_id: data path pdev ID + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline +QDF_STATUS ucfg_ocb_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_tgt_api.c new file mode 100644 index 0000000000..bab500b968 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_tgt_api.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains ocb south bound interface definitions + */ + +#include +#include +#include +#include +#include +#include "wlan_ocb_public_structs.h" +#include "wlan_ocb_ucfg_api.h" +#include "wlan_ocb_tgt_api.h" +#include "wlan_ocb_main.h" + +/** + * wlan_ocb_flush_callback() - OCB message flash callback + * @msg: OCB message + * + * Return: QDF_STATUS_SUCCESS on success. + */ +static QDF_STATUS wlan_ocb_flush_callback(struct scheduler_msg *msg) +{ + struct ocb_rx_event *event; + + if (!msg) { + ocb_err("Null point for OCB message"); + return QDF_STATUS_E_INVAL; + } + + event = msg->bodyptr; + wlan_ocb_release_rx_event(event); + + return QDF_STATUS_SUCCESS; +} + +/** + * tgt_ocb_channel_config_status() - handler for channel config response + * @psoc: psoc handle + * @status: status for last channel config + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +tgt_ocb_channel_config_status(struct wlan_objmgr_psoc *psoc, + uint32_t status) +{ + QDF_STATUS qdf_status; + struct scheduler_msg msg = {0}; + struct ocb_rx_event *event; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + qdf_status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + ocb_err("Failed to get psoc ref"); + wlan_ocb_release_rx_event(event); + return qdf_status; + } + event->psoc = psoc; + event->rsp.channel_cfg_rsp.status = status; + event->evt_id = OCB_CHANNEL_CONFIG_STATUS; + msg.type = OCB_CHANNEL_CONFIG_STATUS; + msg.bodyptr = event; + msg.callback = ocb_process_evt; + msg.flush_callback = wlan_ocb_flush_callback; + qdf_status = scheduler_post_message(QDF_MODULE_ID_OCB, + QDF_MODULE_ID_OCB, + QDF_MODULE_ID_TARGET_IF, &msg); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + return QDF_STATUS_SUCCESS; + + ocb_err("failed to send OCB_CHANNEL_CONFIG_STATUS msg"); + wlan_ocb_release_rx_event(event); + + return qdf_status; +} + +/** + * tgt_ocb_get_tsf_timer() - handle for TSF timer response + * @psoc: psoc handle + * @response: TSF timer response + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +tgt_ocb_get_tsf_timer(struct wlan_objmgr_psoc *psoc, + struct ocb_get_tsf_timer_response *response) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct ocb_rx_event *event; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to get psoc ref"); + goto flush_ref; + } + event->psoc = psoc; + event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + response->vdev_id, + WLAN_OCB_SB_ID); + if (!event->vdev) { + ocb_err("Cannot get vdev handle"); + status = QDF_STATUS_E_FAILURE; + goto flush_ref; + } + + event->evt_id = OCB_TSF_TIMER; + event->rsp.tsf_timer.vdev_id = response->vdev_id; + event->rsp.tsf_timer.timer_high = response->timer_high; + event->rsp.tsf_timer.timer_low = response->timer_low; + msg.type = OCB_TSF_TIMER; + msg.bodyptr = event; + msg.callback = ocb_process_evt; + msg.flush_callback = wlan_ocb_flush_callback; + + status = scheduler_post_message(QDF_MODULE_ID_OCB, + QDF_MODULE_ID_OCB, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + ocb_err("failed to send OCB_TSF_TIMER msg"); +flush_ref: + wlan_ocb_release_rx_event(event); + + return status; +} + +/** + * tgt_ocb_dcc_ndl_update() - handler for NDL update response + * @psoc: psoc handle + * @resp: NDL update response + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +tgt_ocb_dcc_ndl_update(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_update_ndl_response *resp) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct ocb_rx_event *event; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to get psoc ref"); + goto flush_ref; + } + event->psoc = psoc; + event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + resp->vdev_id, + WLAN_OCB_SB_ID); + if (!event->vdev) { + ocb_err("Cannot get vdev handle"); + status = QDF_STATUS_E_FAILURE; + goto flush_ref; + } + + event->evt_id = OCB_NDL_RESPONSE; + qdf_mem_copy(&event->rsp.ndl, resp, sizeof(*resp)); + msg.type = OCB_NDL_RESPONSE; + msg.bodyptr = event; + msg.callback = ocb_process_evt; + msg.flush_callback = wlan_ocb_flush_callback; + + status = scheduler_post_message(QDF_MODULE_ID_OCB, + QDF_MODULE_ID_OCB, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + ocb_err("failed to send OCB_NDL_RESPONSE msg"); +flush_ref: + wlan_ocb_release_rx_event(event); + + return status; +} + +/** + * tgt_ocb_dcc_stats_indicate() - handler for DCC stats indication + * @psoc: psoc handle + * @response: DCC stats + * @active: true for active query, false for passive indicate + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +tgt_ocb_dcc_stats_indicate(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_get_stats_response *response, + bool active) +{ + QDF_STATUS status; + uint8_t *buf; + uint32_t size; + struct scheduler_msg msg = {0}; + struct ocb_rx_event *event; + + size = sizeof(*event) + + response->channel_stats_array_len; + buf = qdf_mem_malloc(size); + if (!buf) + return QDF_STATUS_E_NOMEM; + + event = (struct ocb_rx_event *)buf; + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_OCB_SB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to get psoc ref"); + goto flush_ref; + } + event->psoc = psoc; + event->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + response->vdev_id, + WLAN_OCB_SB_ID); + if (!event->vdev) { + ocb_err("Cannot get vdev handle"); + status = QDF_STATUS_E_FAILURE; + goto flush_ref; + } + + event->rsp.dcc_stats.channel_stats_array = + (uint8_t *)&event->rsp.dcc_stats + + sizeof(struct ocb_dcc_get_stats_response); + event->rsp.dcc_stats.vdev_id = response->vdev_id; + event->rsp.dcc_stats.num_channels = response->num_channels; + event->rsp.dcc_stats.channel_stats_array_len = + response->channel_stats_array_len; + qdf_mem_copy(event->rsp.dcc_stats.channel_stats_array, + response->channel_stats_array, + response->channel_stats_array_len); + ocb_debug("Message type is %s", + active ? "Get stats response" : "DCC stats indication"); + if (active) + msg.type = OCB_DCC_STATS_RESPONSE; + else + msg.type = OCB_DCC_INDICATION; + event->evt_id = msg.type; + msg.bodyptr = event; + msg.callback = ocb_process_evt; + msg.flush_callback = wlan_ocb_flush_callback; + + status = scheduler_post_message(QDF_MODULE_ID_OCB, + QDF_MODULE_ID_OCB, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + ocb_err("failed to send DCC stats msg(%d)", msg.type); +flush_ref: + wlan_ocb_release_rx_event(event); + + return status; +} + +QDF_STATUS tgt_ocb_register_ev_handler(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_ocb_tx_ops *ocb_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + ocb_err("Null soc handle"); + return QDF_STATUS_E_INVAL; + } + ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev); + if (ocb_ops && ocb_ops->ocb_reg_ev_handler) { + status = ocb_ops->ocb_reg_ev_handler(psoc, NULL); + ocb_debug("register ocb event, status:%d", status); + } else { + ocb_alert("No ocb objects or ocb_reg_ev_handler"); + } + + return status; +} + +QDF_STATUS tgt_ocb_unregister_ev_handler(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_ocb_tx_ops *ocb_ops; + QDF_STATUS status; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + ocb_err("Null soc handle"); + return QDF_STATUS_E_INVAL; + } + ocb_ops = wlan_pdev_get_ocb_tx_ops(pdev); + if (ocb_ops && ocb_ops->ocb_unreg_ev_handler) { + status = ocb_ops->ocb_unreg_ev_handler(psoc, NULL); + ocb_debug("unregister ocb event, status:%d", status); + } else { + ocb_alert("No ocb objects or ocb_unreg_ev_handler"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS tgt_ocb_register_rx_ops(struct wlan_ocb_rx_ops *ocb_rxops) +{ + ocb_rxops->ocb_set_config_status = tgt_ocb_channel_config_status; + ocb_rxops->ocb_tsf_timer = tgt_ocb_get_tsf_timer; + ocb_rxops->ocb_dcc_ndl_update = tgt_ocb_dcc_ndl_update; + ocb_rxops->ocb_dcc_stats_indicate = tgt_ocb_dcc_stats_indicate; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c new file mode 100644 index 0000000000..0fea877645 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c @@ -0,0 +1,630 @@ +/* + * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains ocb north bound interface definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_ocb_main.h" +#include "reg_services_public_struct.h" + +/** + * wlan_ocb_get_tx_ops() - get target interface tx operations + * @pdev: pdev handle + * + * Return: fp to target interface operations + */ +static struct wlan_ocb_tx_ops * +wlan_ocb_get_tx_ops(struct wlan_objmgr_pdev *pdev) +{ + struct ocb_pdev_obj *ocb_obj; + + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + if (!ocb_obj) { + ocb_err("failed to get OCB pdev object"); + return NULL; + } + + return &ocb_obj->ocb_txops; +} + +QDF_STATUS ucfg_ocb_init(void) +{ + QDF_STATUS status; + + ocb_notice("ocb module dispatcher init"); + status = wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_OCB, + ocb_pdev_obj_create_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to register pdev create handler for ocb"); + + return status; + } + + status = wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_OCB, + ocb_pdev_obj_destroy_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + ocb_err("Failed to register pdev destroy handler for ocb"); + goto fail_delete_pdev; + } + + return status; + +fail_delete_pdev: + wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_OCB, + ocb_pdev_obj_create_notification, NULL); + + return status; +} + +QDF_STATUS ucfg_ocb_deinit(void) +{ + QDF_STATUS status; + + ocb_notice("ocb module dispatcher deinit"); + status = wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_OCB, + ocb_pdev_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to unregister pdev destroy handler"); + + status = wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_OCB, + ocb_pdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to unregister pdev create handler"); + + return status; +} + +QDF_STATUS ocb_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_NB_ID); + if (!pdev) { + ocb_err("Failed to get pdev handle"); + + return QDF_STATUS_E_FAILURE; + } + tgt_ocb_register_ev_handler(pdev); + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ocb_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_NB_ID); + if (!pdev) { + ocb_err("Failed to get pdev handle"); + return QDF_STATUS_E_FAILURE; + } + tgt_ocb_unregister_ev_handler(pdev); + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_ocb_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id) +{ + struct wlan_objmgr_pdev *pdev; + struct ocb_pdev_obj *ocb_obj; + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_NB_ID); + if (!pdev) { + ocb_err("Failed to get pdev handle"); + return QDF_STATUS_E_FAILURE; + } + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_NB_ID); + if (!ocb_obj) { + ocb_err("OCB object is NULL"); + return QDF_STATUS_E_FAILURE; + } + ocb_obj->dp_pdev_id = pdev_id; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_ocb_update_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_soc) +{ + struct wlan_objmgr_pdev *pdev; + struct ocb_pdev_obj *ocb_obj; + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_NB_ID); + if (!pdev) { + ocb_err("Failed to get pdev handle"); + return QDF_STATUS_E_FAILURE; + } + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_NB_ID); + if (!ocb_obj) { + ocb_err("OCB object is NULL"); + return QDF_STATUS_E_FAILURE; + } + ocb_obj->dp_soc = dp_soc; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_ocb_config_channel(struct wlan_objmgr_pdev *pdev) +{ + QDF_STATUS status; + struct ocb_config *config; + struct ocb_pdev_obj *ocb_obj; + struct wlan_objmgr_psoc *psoc; + struct wlan_ocb_tx_ops *tx_ops; + + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + if (!ocb_obj || !ocb_obj->channel_config) { + ocb_alert("The request could not be found"); + return QDF_STATUS_E_FAILURE; + } + + config = ocb_obj->channel_config; + ocb_debug("Set config to vdev%d", config->vdev_id); + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + ocb_err("Null pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (tx_ops && tx_ops->ocb_set_config) + status = tx_ops->ocb_set_config(psoc, ocb_obj->channel_config); + else + status = QDF_STATUS_E_IO; + + if (QDF_IS_STATUS_SUCCESS(status)) { + ocb_debug("Set channel cmd is sent to southbound"); + } else { + ocb_err("Failed to set channel config to southbound"); + + if (ocb_obj->channel_config) { + /* + * On success case, backup parameters will be released + * after channel info is synced to DP + */ + ocb_info("release the backed config parameters"); + qdf_mem_free(ocb_obj->channel_config); + ocb_obj->channel_config = NULL; + } + } + + return status; +} + +QDF_STATUS ucfg_ocb_set_channel_config(struct wlan_objmgr_vdev *vdev, + struct ocb_config *config, + ocb_sync_callback set_config_cb, + void *arg) +{ + QDF_STATUS status; + enum wlan_vdev_state state; + uint32_t i; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_ocb_tx_ops *tx_ops; + struct ocb_pdev_obj *ocb_obj; + struct ocb_callbacks *ocb_cbs; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + if (!ocb_obj) { + ocb_alert("Failed to get OCB vdev object"); + return QDF_STATUS_E_IO; + } + + if (!config) { + ocb_err("Invalid config input"); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < config->channel_count; i++) { + if (wlan_reg_freq_to_band(config->channels[i].chan_freq) + == REG_BAND_2G) + config->channels[i].ch_mode = MODE_11G; + else + config->channels[i].ch_mode = MODE_11A; + } + + /* + * backup the new configuration, + * it will be released after target's response + */ + ocb_obj->channel_config = ocb_copy_config(config); + if (!ocb_obj->channel_config) { + ocb_err("Failed to backup config"); + return QDF_STATUS_E_NOMEM; + } + + ocb_cbs = &ocb_obj->ocb_cbs; + ocb_cbs->ocb_set_config_callback = set_config_cb; + ocb_cbs->ocb_set_config_context = arg; + + state = wlan_vdev_mlme_get_state(vdev); + if (state != WLAN_VDEV_S_START) { + /* Vdev is not started, start it */ + ocb_debug("OCB vdev%d is not up", config->vdev_id); + status = ocb_vdev_start(ocb_obj); + } else { + psoc = wlan_vdev_get_psoc(vdev); + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (tx_ops && tx_ops->ocb_set_config) + status = tx_ops->ocb_set_config(psoc, config); + else + status = QDF_STATUS_E_IO; + + ocb_debug("Set config to vdev%d", config->vdev_id); + if (QDF_IS_STATUS_SUCCESS(status)) + ocb_debug("Set channel cmd is sent to southbound"); + else + ocb_err("Failed to set channel config to southbound"); + } + + if (QDF_IS_STATUS_ERROR(status) && ocb_obj->channel_config) { + /* + * On success case, backup parameters will be released + * after channel info is synced to DP + */ + ocb_info("release the backed config parameters"); + qdf_mem_free(ocb_obj->channel_config); + ocb_obj->channel_config = NULL; + } + + return status; +} + +QDF_STATUS ucfg_ocb_set_utc_time(struct wlan_objmgr_vdev *vdev, + struct ocb_utc_param *utc) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_ocb_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + pdev = wlan_vdev_get_pdev(vdev); + if (!psoc || !pdev) { + ocb_err("Null pointer for psoc/pdev"); + return QDF_STATUS_E_INVAL; + } + tx_ops = wlan_ocb_get_tx_ops(pdev); + + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + if (!tx_ops->ocb_set_utc_time) { + ocb_alert("ocb_set_utc_time is null"); + return QDF_STATUS_E_IO; + } + + status = tx_ops->ocb_set_utc_time(psoc, utc); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to set UTC time to southbound"); + else + ocb_debug("UTC time is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_start_timing_advert(struct wlan_objmgr_vdev *vdev, + struct ocb_timing_advert_param *ta) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_ocb_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + pdev = wlan_vdev_get_pdev(vdev); + if (!psoc || !pdev) { + ocb_err("Null pointer for psoc/pdev"); + return QDF_STATUS_E_INVAL; + } + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + if (!tx_ops->ocb_start_timing_advert) { + ocb_alert("ocb_start_timing_advert is null"); + return QDF_STATUS_E_IO; + } + status = tx_ops->ocb_start_timing_advert(psoc, ta); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to sent start timing advert to southbound"); + else + ocb_debug("Start timing advert is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_stop_timing_advert(struct wlan_objmgr_vdev *vdev, + struct ocb_timing_advert_param *ta) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_ocb_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + pdev = wlan_vdev_get_pdev(vdev); + if (!psoc || !pdev) { + ocb_err("Null pointer for psoc/pdev"); + return QDF_STATUS_E_INVAL; + } + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + if (!tx_ops->ocb_stop_timing_advert) { + ocb_alert("ocb_stop_timing_advert is null"); + return QDF_STATUS_E_IO; + } + status = tx_ops->ocb_stop_timing_advert(psoc, ta); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to sent start timing advert to southbound"); + else + ocb_debug("Start timing advert is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_get_tsf_timer(struct wlan_objmgr_vdev *vdev, + struct ocb_get_tsf_timer_param *req, + ocb_sync_callback get_tsf_cb, + void *arg) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct ocb_get_tsf_timer_param request; + struct wlan_ocb_tx_ops *tx_ops; + struct ocb_callbacks *ocb_cbs; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + if (!tx_ops->ocb_get_tsf_timer) { + ocb_alert("ocb_get_tsf_timer is null"); + return QDF_STATUS_E_IO; + } + + ocb_cbs = wlan_ocb_get_callbacks(pdev); + ocb_cbs->ocb_get_tsf_timer_context = arg; + ocb_cbs->ocb_get_tsf_timer_callback = get_tsf_cb; + request.vdev_id = req->vdev_id; + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ocb_err("Null pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + status = tx_ops->ocb_get_tsf_timer(psoc, &request); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to sent get tsf timer to southbound"); + else + ocb_debug("Get tsf timer is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_dcc_get_stats(struct wlan_objmgr_vdev *vdev, + struct ocb_dcc_get_stats_param *request, + ocb_sync_callback dcc_get_stats_cb, + void *arg) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct ocb_callbacks *ocb_cbs; + struct wlan_ocb_tx_ops *tx_ops; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + ocb_cbs = wlan_ocb_get_callbacks(pdev); + ocb_cbs->ocb_dcc_get_stats_context = arg; + ocb_cbs->ocb_dcc_get_stats_callback = dcc_get_stats_cb; + + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + + if (!tx_ops->ocb_dcc_get_stats) { + ocb_alert("ocb_dcc_get_stats is null"); + return QDF_STATUS_E_IO; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ocb_err("Null pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + status = tx_ops->ocb_dcc_get_stats(psoc, request); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to sent get dcc stats to southbound"); + else + ocb_debug("Get dcc stats is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_dcc_clear_stats(struct wlan_objmgr_vdev *vdev, + uint16_t vdev_id, + uint32_t bitmap) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_ocb_tx_ops *tx_ops; + struct ocb_dcc_clear_stats_param clear_stats_param; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + + if (!tx_ops->ocb_dcc_clear_stats) { + ocb_alert("ocb_dcc_clear_stats is null"); + return QDF_STATUS_E_IO; + } + + clear_stats_param.vdev_id = vdev_id; + clear_stats_param.dcc_stats_bitmap = bitmap; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ocb_err("Null pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + status = tx_ops->ocb_dcc_clear_stats(psoc, &clear_stats_param); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to sent clear dcc stats to southbound"); + else + ocb_debug("clear dcc stats is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_dcc_update_ndl(struct wlan_objmgr_vdev *vdev, + struct ocb_dcc_update_ndl_param *request, + ocb_sync_callback dcc_update_ndl_cb, + void *arg) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct ocb_callbacks *ocb_cbs; + struct wlan_objmgr_pdev *pdev; + struct wlan_ocb_tx_ops *tx_ops; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + ocb_cbs = wlan_ocb_get_callbacks(pdev); + ocb_cbs->ocb_dcc_update_ndl_context = arg; + ocb_cbs->ocb_dcc_update_ndl_callback = dcc_update_ndl_cb; + + tx_ops = wlan_ocb_get_tx_ops(pdev); + if (!tx_ops) { + ocb_alert("tx_ops is null"); + return QDF_STATUS_E_IO; + } + if (!tx_ops->ocb_dcc_update_ndl) { + ocb_alert("dcc_update_ndl is null"); + return QDF_STATUS_E_IO; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + ocb_err("Null pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + status = tx_ops->ocb_dcc_update_ndl(psoc, request); + if (QDF_IS_STATUS_ERROR(status)) + ocb_err("Failed to sent update ndl to southbound"); + else + ocb_debug("Update ndl is sent to southbound"); + + return status; +} + +QDF_STATUS ucfg_ocb_register_for_dcc_stats_event(struct wlan_objmgr_pdev *pdev, + void *ctx, ocb_sync_callback dcc_stats_cb) +{ + struct ocb_callbacks *ocb_cbs; + + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + ocb_cbs = wlan_ocb_get_callbacks(pdev); + + if (!ocb_cbs) { + ocb_err("Failed to register dcc stats callback"); + return QDF_STATUS_E_FAILURE; + } + ocb_cbs->ocb_dcc_stats_event_context = ctx; + ocb_cbs->ocb_dcc_stats_event_callback = dcc_stats_cb; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_ocb_register_vdev_start(struct wlan_objmgr_pdev *pdev, + QDF_STATUS (*ocb_start)(struct ocb_config *)) +{ + struct ocb_callbacks *ocb_cbs; + + if (!pdev) { + ocb_err("Null pointer for pdev"); + return QDF_STATUS_E_INVAL; + } + ocb_cbs = wlan_ocb_get_callbacks(pdev); + + if (!ocb_cbs) { + ocb_err("Failed to register dcc stats callback"); + return QDF_STATUS_E_FAILURE; + } + ocb_cbs->start_ocb_vdev = ocb_start; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_main.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_main.c new file mode 100644 index 0000000000..66d3cf33b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_main.c @@ -0,0 +1,1572 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains main P2P function definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_p2p_tgt_api.h" +#include "wlan_p2p_mcc_quota_tgt_api.h" +#include "wlan_p2p_main.h" +#include "wlan_p2p_roc.h" +#include "wlan_p2p_off_chan_tx.h" +#include "cfg_p2p.h" +#include "cfg_ucfg_api.h" +#include "wlan_mlme_api.h" + +/** + * p2p_get_cmd_type_str() - parse cmd to string + * @cmd_type: P2P cmd type + * + * This function parse P2P cmd to string. + * + * Return: command string + */ +static char *p2p_get_cmd_type_str(enum p2p_cmd_type cmd_type) +{ + switch (cmd_type) { + case P2P_ROC_REQ: + return "P2P roc request"; + case P2P_CANCEL_ROC_REQ: + return "P2P cancel roc request"; + case P2P_MGMT_TX: + return "P2P mgmt tx request"; + case P2P_MGMT_TX_CANCEL: + return "P2P cancel mgmt tx request"; + case P2P_CLEANUP_ROC: + return "P2P cleanup roc"; + case P2P_CLEANUP_TX: + return "P2P cleanup tx"; + case P2P_SET_RANDOM_MAC: + return "P2P set random mac"; + default: + return "Invalid P2P command"; + } +} + +/** + * p2p_get_event_type_str() - parase event to string + * @event_type: P2P event type + * + * This function parse P2P event to string. + * + * Return: event string + */ +static char *p2p_get_event_type_str(enum p2p_event_type event_type) +{ + switch (event_type) { + case P2P_EVENT_SCAN_EVENT: + return "P2P scan event"; + case P2P_EVENT_MGMT_TX_ACK_CNF: + return "P2P mgmt tx ack event"; + case P2P_EVENT_RX_MGMT: + return "P2P mgmt rx event"; + case P2P_EVENT_LO_STOPPED: + return "P2P lo stop event"; + case P2P_EVENT_NOA: + return "P2P noa event"; + case P2P_EVENT_ADD_MAC_RSP: + return "P2P add mac filter resp event"; + default: + return "Invalid P2P event"; + } +} + +/** + * p2p_psoc_obj_create_notification() - Function to allocate per P2P + * soc private object + * @soc: soc context + * @data: Pointer to data + * + * This function gets called from object manager when psoc is being + * created and creates p2p soc context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_psoc_obj_create_notification( + struct wlan_objmgr_psoc *soc, void *data) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = qdf_mem_malloc(sizeof(*p2p_soc_obj)); + if (!p2p_soc_obj) + return QDF_STATUS_E_NOMEM; + + p2p_soc_obj->soc = soc; + + status = wlan_objmgr_psoc_component_obj_attach(soc, + WLAN_UMAC_COMP_P2P, p2p_soc_obj, + QDF_STATUS_SUCCESS); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(p2p_soc_obj); + p2p_err("Failed to attach p2p component, %d", status); + return status; + } + + p2p_debug("p2p soc object create successful, %pK", p2p_soc_obj); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_psoc_obj_destroy_notification() - Free soc private object + * @soc: soc context + * @data: Pointer to data + * + * This function gets called from object manager when psoc is being + * deleted and delete p2p soc context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_psoc_obj_destroy_notification( + struct wlan_objmgr_psoc *soc, void *data) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + p2p_soc_obj->soc = NULL; + + status = wlan_objmgr_psoc_component_obj_detach(soc, + WLAN_UMAC_COMP_P2P, p2p_soc_obj); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to detach p2p component, %d", status); + return status; + } + + p2p_debug("destroy p2p soc object, %pK", p2p_soc_obj); + + qdf_mem_free(p2p_soc_obj); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_vdev_obj_create_notification() - Allocate per p2p vdev object + * @vdev: vdev context + * @data: Pointer to data + * + * This function gets called from object manager when vdev is being + * created and creates p2p vdev context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_vdev_obj_create_notification( + struct wlan_objmgr_vdev *vdev, void *data) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj; + QDF_STATUS status; + enum QDF_OPMODE mode; + + if (!vdev) { + p2p_err("vdev context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + p2p_debug("vdev mode:%d", mode); + if (mode != QDF_P2P_GO_MODE && + mode != QDF_STA_MODE && + mode != QDF_P2P_CLIENT_MODE && + mode != QDF_P2P_DEVICE_MODE) { + p2p_debug("won't create p2p vdev private object for mode %d", + mode); + return QDF_STATUS_SUCCESS; + } + + p2p_vdev_obj = + qdf_mem_malloc(sizeof(*p2p_vdev_obj)); + if (!p2p_vdev_obj) + return QDF_STATUS_E_NOMEM; + + p2p_vdev_obj->vdev = vdev; + p2p_vdev_obj->noa_status = true; + p2p_vdev_obj->non_p2p_peer_count = 0; + p2p_init_random_mac_vdev(p2p_vdev_obj); + qdf_mem_copy(p2p_vdev_obj->prev_action_frame_addr2, + wlan_vdev_mlme_get_macaddr(vdev), QDF_MAC_ADDR_SIZE); + + status = wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_UMAC_COMP_P2P, p2p_vdev_obj, + QDF_STATUS_SUCCESS); + if (status != QDF_STATUS_SUCCESS) { + p2p_deinit_random_mac_vdev(p2p_vdev_obj); + qdf_mem_free(p2p_vdev_obj); + p2p_err("Failed to attach p2p component to vdev, %d", + status); + return status; + } + + p2p_debug("p2p vdev object create successful, %pK", p2p_vdev_obj); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_vdev_obj_destroy_notification() - Free per P2P vdev object + * @vdev: vdev context + * @data: Pointer to data + * + * This function gets called from object manager when vdev is being + * deleted and delete p2p vdev context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_vdev_obj_destroy_notification( + struct wlan_objmgr_vdev *vdev, void *data) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj; + QDF_STATUS status; + enum QDF_OPMODE mode; + + if (!vdev) { + p2p_err("vdev context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + p2p_debug("vdev mode:%d", mode); + if (mode != QDF_P2P_GO_MODE && + mode != QDF_STA_MODE && + mode != QDF_P2P_CLIENT_MODE && + mode != QDF_P2P_DEVICE_MODE){ + p2p_debug("no p2p vdev private object for mode %d", mode); + return QDF_STATUS_SUCCESS; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_debug("p2p vdev object is NULL"); + return QDF_STATUS_SUCCESS; + } + p2p_deinit_random_mac_vdev(p2p_vdev_obj); + + p2p_vdev_obj->vdev = NULL; + + status = wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_P2P, p2p_vdev_obj); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to detach p2p component, %d", status); + return status; + } + + p2p_debug("destroy p2p vdev object, p2p vdev obj:%pK, noa info:%pK", + p2p_vdev_obj, p2p_vdev_obj->noa_info); + + if (p2p_vdev_obj->noa_info) + qdf_mem_free(p2p_vdev_obj->noa_info); + + qdf_mem_free(p2p_vdev_obj); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_peer_obj_create_notification() - manages peer details per vdev + * @peer: peer object + * @arg: Pointer to private argument - NULL + * + * This function gets called from object manager when peer is being + * created. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_peer_obj_create_notification( + struct wlan_objmgr_peer *peer, void *arg) +{ + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE mode; + + if (!peer) { + p2p_err("peer context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_peer_get_vdev(peer); + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_GO_MODE) + return QDF_STATUS_SUCCESS; + + p2p_debug("p2p peer object create successful"); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_peer_obj_destroy_notification() - clears peer details per vdev + * @peer: peer object + * @arg: Pointer to private argument - NULL + * + * This function gets called from object manager when peer is being + * destroyed. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_peer_obj_destroy_notification( + struct wlan_objmgr_peer *peer, void *arg) +{ + struct wlan_objmgr_vdev *vdev; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE mode; + enum wlan_peer_type peer_type; + uint8_t vdev_id; + + if (!peer) { + p2p_err("peer context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_peer_get_vdev(peer); + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_GO_MODE) + return QDF_STATUS_SUCCESS; + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + psoc = wlan_vdev_get_psoc(vdev); + if (!p2p_vdev_obj || !psoc) { + p2p_debug("p2p_vdev_obj:%pK psoc:%pK", p2p_vdev_obj, psoc); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + + peer_type = wlan_peer_get_peer_type(peer); + + if ((peer_type == WLAN_PEER_STA) && (mode == QDF_P2P_GO_MODE)) { + + p2p_vdev_obj->non_p2p_peer_count--; + + if (!p2p_vdev_obj->non_p2p_peer_count && + (p2p_vdev_obj->noa_status == false)) { + + vdev_id = wlan_vdev_get_id(vdev); + + if (ucfg_p2p_set_noa(psoc, vdev_id, + false) == QDF_STATUS_SUCCESS) + p2p_vdev_obj->noa_status = true; + else + p2p_vdev_obj->noa_status = false; + + p2p_debug("Non p2p peer disconnected from GO,NOA status: %d.", + p2p_vdev_obj->noa_status); + } + p2p_debug("Non P2P peer count: %d", + p2p_vdev_obj->non_p2p_peer_count); + } + p2p_debug("p2p peer object destroy successful"); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_send_noa_to_pe() - send noa information to pe + * @noa_info: vdev context + * + * This function sends noa information to pe since MCL layer need noa + * event. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_send_noa_to_pe(struct p2p_noa_info *noa_info) +{ + struct p2p_noa_attr *noa_attr; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + if (!noa_info) { + p2p_err("noa info is null"); + return QDF_STATUS_E_INVAL; + } + + noa_attr = qdf_mem_malloc(sizeof(*noa_attr)); + if (!noa_attr) + return QDF_STATUS_E_NOMEM; + + noa_attr->index = noa_info->index; + noa_attr->opps_ps = noa_info->opps_ps; + noa_attr->ct_win = noa_info->ct_window; + if (!noa_info->num_desc) { + p2p_debug("Zero noa descriptors"); + } else { + p2p_debug("%d noa descriptors", noa_info->num_desc); + + noa_attr->noa1_count = + noa_info->noa_desc[0].type_count; + noa_attr->noa1_duration = + noa_info->noa_desc[0].duration; + noa_attr->noa1_interval = + noa_info->noa_desc[0].interval; + noa_attr->noa1_start_time = + noa_info->noa_desc[0].start_time; + if (noa_info->num_desc > 1) { + noa_attr->noa2_count = + noa_info->noa_desc[1].type_count; + noa_attr->noa2_duration = + noa_info->noa_desc[1].duration; + noa_attr->noa2_interval = + noa_info->noa_desc[1].interval; + noa_attr->noa2_start_time = + noa_info->noa_desc[1].start_time; + } + } + + p2p_debug("Sending P2P_NOA_ATTR_IND to pe"); + + msg.type = P2P_NOA_ATTR_IND; + msg.bodyval = 0; + msg.bodyptr = noa_attr; + status = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_PE, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(noa_attr); + p2p_err("post msg fail:%d", status); + } + + return status; +} + +/** + * process_peer_for_noa() - disable NoA + * @vdev: vdev object + * @psoc: soc object + * @peer: peer object + * + * This function disables NoA + * + * + * Return: QDF_STATUS + */ +static QDF_STATUS process_peer_for_noa(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj = NULL; + enum QDF_OPMODE mode; + enum wlan_peer_type peer_type; + bool disable_noa; + uint8_t vdev_id; + + if (!vdev || !psoc || !peer) { + p2p_err("vdev:%pK psoc:%pK peer:%pK", vdev, psoc, peer); + return QDF_STATUS_E_INVAL; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) + return QDF_STATUS_E_INVAL; + + mode = wlan_vdev_mlme_get_opmode(vdev); + + peer_type = wlan_peer_get_peer_type(peer); + if (peer_type == WLAN_PEER_STA) + p2p_vdev_obj->non_p2p_peer_count++; + + disable_noa = ((mode == QDF_P2P_GO_MODE) + && p2p_vdev_obj->non_p2p_peer_count + && p2p_vdev_obj->noa_status); + + if (disable_noa && (peer_type == WLAN_PEER_STA)) { + + vdev_id = wlan_vdev_get_id(vdev); + + if (ucfg_p2p_set_noa(psoc, vdev_id, + true) == QDF_STATUS_SUCCESS) { + p2p_vdev_obj->noa_status = false; + } else { + p2p_vdev_obj->noa_status = true; + } + p2p_debug("NoA status: %d", p2p_vdev_obj->noa_status); + } + p2p_debug("process_peer_for_noa"); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_object_init_params() - init parameters for p2p object + * @psoc: pointer to psoc object + * @p2p_soc_obj: pointer to p2p psoc object + * + * This function init parameters for p2p object + */ +static QDF_STATUS p2p_object_init_params( + struct wlan_objmgr_psoc *psoc, + struct p2p_soc_priv_obj *p2p_soc_obj) +{ + if (!psoc || !p2p_soc_obj) { + p2p_err("invalid param"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj->param.go_keepalive_period = + cfg_get(psoc, CFG_GO_KEEP_ALIVE_PERIOD); + p2p_soc_obj->param.go_link_monitor_period = + cfg_get(psoc, CFG_GO_LINK_MONITOR_PERIOD); + p2p_soc_obj->param.p2p_device_addr_admin = + cfg_get(psoc, CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED); + p2p_soc_obj->param.is_random_seq_num_enabled = + cfg_get(psoc, CFG_ACTION_FRAME_RANDOM_SEQ_NUM_ENABLED); + p2p_soc_obj->param.indoor_channel_support = + cfg_get(psoc, CFG_P2P_GO_ON_5GHZ_INDOOR_CHANNEL); + p2p_soc_obj->param.go_ignore_non_p2p_probe_req = + cfg_get(psoc, CFG_GO_IGNORE_NON_P2P_PROBE_REQ); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_P2P_DEBUG +/** + * wlan_p2p_init_connection_status() - init connection status + * @p2p_soc_obj: pointer to p2p psoc object + * + * This function initial p2p connection status. + * + * Return: None + */ +static void wlan_p2p_init_connection_status( + struct p2p_soc_priv_obj *p2p_soc_obj) +{ + if (!p2p_soc_obj) { + p2p_err("invalid p2p soc obj"); + return; + } + + p2p_soc_obj->connection_status = P2P_NOT_ACTIVE; +} +#else +static void wlan_p2p_init_connection_status( + struct p2p_soc_priv_obj *p2p_soc_obj) +{ +} +#endif /* WLAN_FEATURE_P2P_DEBUG */ + +QDF_STATUS p2p_component_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_P2P, + p2p_psoc_obj_create_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p obj create handler"); + goto err_reg_psoc_create; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_P2P, + p2p_psoc_obj_destroy_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p obj delete handler"); + goto err_reg_psoc_delete; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_create_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p vdev create handler"); + goto err_reg_vdev_create; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_destroy_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p vdev delete handler"); + goto err_reg_vdev_delete; + } + + status = wlan_objmgr_register_peer_create_handler( + WLAN_UMAC_COMP_P2P, + p2p_peer_obj_create_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p peer create handler"); + goto err_reg_peer_create; + } + + status = wlan_objmgr_register_peer_destroy_handler( + WLAN_UMAC_COMP_P2P, + p2p_peer_obj_destroy_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to register p2p peer destroy handler"); + goto err_reg_peer_destroy; + } + + p2p_debug("Register p2p obj handler successful"); + + return QDF_STATUS_SUCCESS; +err_reg_peer_destroy: + wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_P2P, + p2p_peer_obj_create_notification, NULL); +err_reg_peer_create: + wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_destroy_notification, NULL); +err_reg_vdev_delete: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_create_notification, NULL); +err_reg_vdev_create: + wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_P2P, + p2p_psoc_obj_destroy_notification, NULL); +err_reg_psoc_delete: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_P2P, + p2p_psoc_obj_create_notification, NULL); +err_reg_psoc_create: + return status; +} + +QDF_STATUS p2p_component_deinit(void) +{ + QDF_STATUS status; + QDF_STATUS ret_status = QDF_STATUS_SUCCESS; + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_create_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to unregister p2p vdev create handler, %d", + status); + ret_status = status; + } + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_P2P, + p2p_vdev_obj_destroy_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to unregister p2p vdev delete handler, %d", + status); + ret_status = status; + } + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_P2P, + p2p_psoc_obj_create_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to unregister p2p obj create handler, %d", + status); + ret_status = status; + } + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_P2P, + p2p_psoc_obj_destroy_notification, + NULL); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to unregister p2p obj delete handler, %d", + status); + ret_status = status; + } + + p2p_debug("Unregister p2p obj handler complete"); + + return ret_status; +} + +QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc) +{ + QDF_STATUS status; + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + p2p_object_init_params(soc, p2p_soc_obj); + qdf_list_create(&p2p_soc_obj->roc_q, MAX_QUEUE_LENGTH); + qdf_list_create(&p2p_soc_obj->tx_q_roc, MAX_QUEUE_LENGTH); + qdf_list_create(&p2p_soc_obj->tx_q_ack, MAX_QUEUE_LENGTH); + + status = qdf_event_create(&p2p_soc_obj->cleanup_roc_done); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("failed to create cleanup roc done event"); + goto fail_cleanup_roc; + } + + status = qdf_event_create(&p2p_soc_obj->cleanup_tx_done); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("failed to create cleanup roc done event"); + goto fail_cleanup_tx; + } + + qdf_runtime_lock_init(&p2p_soc_obj->roc_runtime_lock); + p2p_soc_obj->cur_roc_vdev_id = P2P_INVALID_VDEV_ID; + qdf_idr_create(&p2p_soc_obj->p2p_idr); + + p2p_debug("p2p psoc object open successful"); + + return QDF_STATUS_SUCCESS; + +fail_cleanup_tx: + qdf_event_destroy(&p2p_soc_obj->cleanup_roc_done); + +fail_cleanup_roc: + qdf_list_destroy(&p2p_soc_obj->tx_q_ack); + qdf_list_destroy(&p2p_soc_obj->tx_q_roc); + qdf_list_destroy(&p2p_soc_obj->roc_q); + + return status; +} + +QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_idr_destroy(&p2p_soc_obj->p2p_idr); + qdf_runtime_lock_deinit(&p2p_soc_obj->roc_runtime_lock); + qdf_event_destroy(&p2p_soc_obj->cleanup_tx_done); + qdf_event_destroy(&p2p_soc_obj->cleanup_roc_done); + qdf_list_destroy(&p2p_soc_obj->tx_q_ack); + qdf_list_destroy(&p2p_soc_obj->tx_q_roc); + qdf_list_destroy(&p2p_soc_obj->roc_q); + + p2p_debug("p2p psoc object close successful"); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +static inline void p2p_init_lo_event(struct p2p_start_param *start_param, + struct p2p_start_param *req) +{ + start_param->lo_event_cb = req->lo_event_cb; + start_param->lo_event_cb_data = req->lo_event_cb_data; +} +#else +static inline void p2p_init_lo_event(struct p2p_start_param *start_param, + struct p2p_start_param *req) +{ +} +#endif + +QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc, + struct p2p_start_param *req) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_start_param *start_param; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("P2P soc object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + start_param = qdf_mem_malloc(sizeof(*start_param)); + if (!start_param) + return QDF_STATUS_E_NOMEM; + + start_param->rx_cb = req->rx_cb; + start_param->rx_cb_data = req->rx_cb_data; + start_param->event_cb = req->event_cb; + start_param->event_cb_data = req->event_cb_data; + start_param->tx_cnf_cb = req->tx_cnf_cb; + start_param->tx_cnf_cb_data = req->tx_cnf_cb_data; + p2p_init_lo_event(start_param, req); + p2p_soc_obj->start_param = start_param; + + wlan_p2p_init_connection_status(p2p_soc_obj); + + /* register p2p lo stop and noa event */ + tgt_p2p_register_lo_ev_handler(soc); + tgt_p2p_register_noa_ev_handler(soc); + tgt_p2p_register_macaddr_rx_filter_evt_handler(soc, true); + tgt_p2p_register_mcc_quota_ev_handler(soc, true); + /* register scan request id */ + p2p_soc_obj->scan_req_id = wlan_scan_register_requester( + soc, P2P_MODULE_NAME, tgt_p2p_scan_event_cb, + p2p_soc_obj); + + /* register rx action frame */ + p2p_mgmt_rx_action_ops(soc, true); + + p2p_debug("p2p psoc start successful, scan request id:%d", + p2p_soc_obj->scan_req_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_start_param *start_param; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("P2P soc object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + start_param = p2p_soc_obj->start_param; + p2p_soc_obj->start_param = NULL; + if (!start_param) { + p2p_err("start parameters is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* unregister rx action frame */ + p2p_mgmt_rx_action_ops(soc, false); + + /* clean up queue of p2p psoc private object */ + p2p_cleanup_tx_sync(p2p_soc_obj, NULL); + p2p_cleanup_roc(p2p_soc_obj, NULL, true); + + /* unrgister scan request id*/ + wlan_scan_unregister_requester(soc, p2p_soc_obj->scan_req_id); + + tgt_p2p_register_mcc_quota_ev_handler(soc, false); + /* unregister p2p lo stop and noa event */ + tgt_p2p_register_macaddr_rx_filter_evt_handler(soc, false); + tgt_p2p_unregister_lo_ev_handler(soc); + tgt_p2p_unregister_noa_ev_handler(soc); + + start_param->rx_cb = NULL; + start_param->rx_cb_data = NULL; + start_param->event_cb = NULL; + start_param->event_cb_data = NULL; + start_param->tx_cnf_cb = NULL; + start_param->tx_cnf_cb_data = NULL; + qdf_mem_free(start_param); + + p2p_debug("p2p psoc stop successful"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg) +{ + QDF_STATUS status; + + p2p_debug("msg type %d, %s", msg->type, + p2p_get_cmd_type_str(msg->type)); + + if (!(msg->bodyptr)) { + p2p_err("Invalid message body"); + return QDF_STATUS_E_INVAL; + } + switch (msg->type) { + case P2P_ROC_REQ: + status = p2p_process_roc_req( + (struct p2p_roc_context *) + msg->bodyptr); + break; + case P2P_CANCEL_ROC_REQ: + status = p2p_process_cancel_roc_req( + (struct cancel_roc_context *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case P2P_MGMT_TX: + status = p2p_process_mgmt_tx( + (struct tx_action_context *) + msg->bodyptr); + break; + case P2P_MGMT_TX_CANCEL: + status = p2p_process_mgmt_tx_cancel( + (struct cancel_roc_context *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case P2P_CLEANUP_ROC: + status = p2p_process_cleanup_roc_queue( + (struct p2p_cleanup_param *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case P2P_CLEANUP_TX: + status = p2p_process_cleanup_tx_queue( + (struct p2p_cleanup_param *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case P2P_SET_RANDOM_MAC: + status = p2p_process_set_rand_mac(msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + default: + p2p_err("drop unexpected message received %d", + msg->type); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +QDF_STATUS p2p_process_evt(struct scheduler_msg *msg) +{ + QDF_STATUS status; + + p2p_debug("msg type %d, %s", msg->type, + p2p_get_event_type_str(msg->type)); + + if (!(msg->bodyptr)) { + p2p_err("Invalid message body"); + return QDF_STATUS_E_INVAL; + } + + switch (msg->type) { + case P2P_EVENT_MGMT_TX_ACK_CNF: + status = p2p_process_mgmt_tx_ack_cnf( + (struct p2p_tx_conf_event *) + msg->bodyptr); + break; + case P2P_EVENT_RX_MGMT: + status = p2p_process_rx_mgmt( + (struct p2p_rx_mgmt_event *) + msg->bodyptr); + break; + case P2P_EVENT_LO_STOPPED: + status = p2p_process_lo_stop( + (struct p2p_lo_stop_event *) + msg->bodyptr); + break; + case P2P_EVENT_NOA: + status = p2p_process_noa( + (struct p2p_noa_event *) + msg->bodyptr); + break; + case P2P_EVENT_ADD_MAC_RSP: + status = p2p_process_set_rand_mac_rsp( + (struct p2p_mac_filter_rsp *) + msg->bodyptr); + break; + default: + p2p_err("Drop unexpected message received %d", + msg->type); + status = QDF_STATUS_E_INVAL; + break; + } + + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + return status; +} + +QDF_STATUS p2p_msg_flush_callback(struct scheduler_msg *msg) +{ + struct tx_action_context *tx_action; + + if (!msg || !(msg->bodyptr)) { + p2p_err("invalid msg"); + return QDF_STATUS_E_INVAL; + } + + p2p_debug("flush msg, type:%d", msg->type); + switch (msg->type) { + case P2P_MGMT_TX: + tx_action = (struct tx_action_context *)msg->bodyptr; + qdf_mem_free(tx_action->buf); + qdf_mem_free(tx_action); + break; + default: + qdf_mem_free(msg->bodyptr); + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_event_flush_callback(struct scheduler_msg *msg) +{ + struct p2p_noa_event *noa_event; + struct p2p_rx_mgmt_event *rx_mgmt_event; + struct p2p_tx_conf_event *tx_conf_event; + struct p2p_lo_stop_event *lo_stop_event; + + if (!msg || !(msg->bodyptr)) { + p2p_err("invalid msg"); + return QDF_STATUS_E_INVAL; + } + + p2p_debug("flush event, type:%d", msg->type); + switch (msg->type) { + case P2P_EVENT_NOA: + noa_event = (struct p2p_noa_event *)msg->bodyptr; + qdf_mem_free(noa_event->noa_info); + qdf_mem_free(noa_event); + break; + case P2P_EVENT_RX_MGMT: + rx_mgmt_event = (struct p2p_rx_mgmt_event *)msg->bodyptr; + qdf_mem_free(rx_mgmt_event->rx_mgmt); + qdf_mem_free(rx_mgmt_event); + break; + case P2P_EVENT_MGMT_TX_ACK_CNF: + tx_conf_event = (struct p2p_tx_conf_event *)msg->bodyptr; + qdf_nbuf_free(tx_conf_event->nbuf); + qdf_mem_free(tx_conf_event); + break; + case P2P_EVENT_LO_STOPPED: + lo_stop_event = (struct p2p_lo_stop_event *)msg->bodyptr; + qdf_mem_free(lo_stop_event->lo_event); + qdf_mem_free(lo_stop_event); + break; + default: + qdf_mem_free(msg->bodyptr); + break; + } + + return QDF_STATUS_SUCCESS; +} + +bool p2p_check_oui_and_force_1x1(uint8_t *assoc_ie, uint32_t assoc_ie_len) +{ + const uint8_t *vendor_ie, *p2p_ie, *pos; + uint8_t rem_len, attr; + uint16_t attr_len; + + vendor_ie = (uint8_t *)p2p_get_p2pie_ptr(assoc_ie, assoc_ie_len); + if (!vendor_ie) { + p2p_debug("P2P IE not found"); + return false; + } + + rem_len = vendor_ie[1]; + if (rem_len < (2 + OUI_SIZE_P2P) || rem_len > WLAN_MAX_IE_LEN) { + p2p_err("Invalid IE len %d", rem_len); + return false; + } + + p2p_ie = vendor_ie + HEADER_LEN_P2P_IE; + rem_len -= OUI_SIZE_P2P; + + while (rem_len) { + attr = p2p_ie[0]; + attr_len = LE_READ_2(&p2p_ie[1]); + if (attr_len > rem_len) { + p2p_err("Invalid len %d for elem:%d", attr_len, attr); + return false; + } + + switch (attr) { + case P2P_ATTR_CAPABILITY: + case P2P_ATTR_DEVICE_ID: + case P2P_ATTR_GROUP_OWNER_INTENT: + case P2P_ATTR_STATUS: + case P2P_ATTR_LISTEN_CHANNEL: + case P2P_ATTR_OPERATING_CHANNEL: + case P2P_ATTR_GROUP_INFO: + case P2P_ATTR_MANAGEABILITY: + case P2P_ATTR_CHANNEL_LIST: + break; + + case P2P_ATTR_DEVICE_INFO: + if (attr_len < (QDF_MAC_ADDR_SIZE + + MAX_CONFIG_METHODS_LEN + 8 + + DEVICE_CATEGORY_MAX_LEN)) { + p2p_err("Invalid Device info attr len %d", + attr_len); + return false; + } + + /* move by attr id and 2 bytes of attr len */ + pos = p2p_ie + 3; + + /* + * the P2P Device info is of format: + * attr_id - 1 byte + * attr_len - 2 bytes + * device mac addr - 6 bytes + * config methods - 2 bytes + * primary device type - 8bytes + * -primary device type category - 1 byte + * -primary device type oui - 4bytes + * number of secondary device type - 2 bytes + */ + pos += ETH_ALEN + MAX_CONFIG_METHODS_LEN + + DEVICE_CATEGORY_MAX_LEN; + + if (!qdf_mem_cmp(pos, P2P_1X1_WAR_OUI, + P2P_1X1_OUI_LEN)) + return true; + + break; + default: + p2p_err("Invalid P2P attribute"); + break; + } + p2p_ie += (3 + attr_len); + rem_len -= (3 + attr_len); + } + + return false; +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +QDF_STATUS p2p_process_lo_stop( + struct p2p_lo_stop_event *lo_stop_event) +{ + struct p2p_lo_event *lo_evt; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_start_param *start_param; + + if (!lo_stop_event) { + p2p_err("invalid lo stop event"); + return QDF_STATUS_E_INVAL; + } + + lo_evt = lo_stop_event->lo_event; + if (!lo_evt) { + p2p_err("invalid lo event"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = lo_stop_event->p2p_soc_obj; + + p2p_debug("vdev_id %d, reason %d", + lo_evt->vdev_id, lo_evt->reason_code); + + if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) { + p2p_err("Invalid p2p soc object or start parameters"); + qdf_mem_free(lo_evt); + return QDF_STATUS_E_INVAL; + } + start_param = p2p_soc_obj->start_param; + if (start_param->lo_event_cb) + start_param->lo_event_cb( + start_param->lo_event_cb_data, lo_evt); + else + p2p_err("Invalid p2p soc obj or hdd lo event callback"); + + qdf_mem_free(lo_evt); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS p2p_process_noa(struct p2p_noa_event *noa_event) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct p2p_noa_info *noa_info; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE mode; + + if (!noa_event) { + p2p_err("invalid noa event"); + return QDF_STATUS_E_INVAL; + } + noa_info = noa_event->noa_info; + p2p_soc_obj = noa_event->p2p_soc_obj; + psoc = p2p_soc_obj->soc; + + p2p_debug("psoc:%pK, index:%d, opps_ps:%d, ct_window:%d, num_desc:%d, vdev_id:%d", + psoc, noa_info->index, noa_info->opps_ps, + noa_info->ct_window, noa_info->num_desc, + noa_info->vdev_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + noa_info->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_err("vdev obj is NULL"); + qdf_mem_free(noa_event->noa_info); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + p2p_debug("vdev mode:%d", mode); + if (mode != QDF_P2P_GO_MODE) { + p2p_err("invalid p2p vdev mode:%d", mode); + status = QDF_STATUS_E_INVAL; + goto fail; + } + + /* must send noa to pe since of limitation*/ + p2p_send_noa_to_pe(noa_info); + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + if (!(p2p_vdev_obj->noa_info)) { + p2p_vdev_obj->noa_info = + qdf_mem_malloc(sizeof(struct p2p_noa_info)); + if (!(p2p_vdev_obj->noa_info)) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + } + qdf_mem_copy(p2p_vdev_obj->noa_info, noa_info, + sizeof(struct p2p_noa_info)); +fail: + qdf_mem_free(noa_event->noa_info); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return status; +} + +void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer; + uint8_t pdev_id; + + if (!vdev) { + p2p_err("vdev:%pK", vdev); + return; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + p2p_err("psoc:%pK", psoc); + return; + } + pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_P2P_ID); + if (!peer) { + p2p_debug("peer info not found"); + return; + } + status = process_peer_for_noa(vdev, psoc, peer); + wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID); + + if (status != QDF_STATUS_SUCCESS) + return; + + p2p_debug("peer is authorized"); +} + +#ifdef WLAN_FEATURE_P2P_DEBUG + +void p2p_status_update(struct p2p_soc_priv_obj *p2p_soc_obj, + enum p2p_connection_status status) +{ + p2p_soc_obj->connection_status = status; +} + +static struct p2p_soc_priv_obj * +get_p2p_soc_obj_by_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct wlan_objmgr_psoc *soc; + + if (!vdev) { + p2p_err("vdev context passed is NULL"); + return NULL; + } + + soc = wlan_vdev_get_psoc(vdev); + if (!soc) { + p2p_err("soc context is NULL"); + return NULL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) + p2p_err("P2P soc context is NULL"); + + return p2p_soc_obj; +} + +QDF_STATUS p2p_status_scan(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + enum QDF_OPMODE mode; + + p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev); + if (!p2p_soc_obj) { + p2p_err("P2P soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_CLIENT_MODE && + mode != QDF_P2P_DEVICE_MODE) { + p2p_debug("this is not P2P CLIENT or DEVICE, mode:%d", + mode); + return QDF_STATUS_SUCCESS; + } + + p2p_debug("connection status:%d", p2p_soc_obj->connection_status); + switch (p2p_soc_obj->connection_status) { + case P2P_GO_NEG_COMPLETED: + case P2P_GO_NEG_PROCESS: + p2p_status_update(p2p_soc_obj, + P2P_CLIENT_CONNECTING_STATE_1); + p2p_debug("[P2P State] Changing state from Go nego completed to Connection is started"); + p2p_debug("P2P Scanning is started for 8way Handshake"); + break; + case P2P_CLIENT_DISCONNECTED_STATE: + p2p_status_update(p2p_soc_obj, + P2P_CLIENT_CONNECTING_STATE_2); + p2p_debug("[P2P State] Changing state from Disconnected state to Connection is started"); + p2p_debug("P2P Scanning is started for 4way Handshake"); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_status_connect(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + enum QDF_OPMODE mode; + + p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev); + if (!p2p_soc_obj) { + p2p_err("P2P soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_SUCCESS; + + p2p_debug("connection status:%d", p2p_soc_obj->connection_status); + switch (p2p_soc_obj->connection_status) { + case P2P_CLIENT_CONNECTING_STATE_1: + p2p_status_update(p2p_soc_obj, + P2P_CLIENT_CONNECTED_STATE_1); + p2p_debug("[P2P State] Changing state from Connecting state to Connected State for 8-way Handshake"); + break; + case P2P_CLIENT_DISCONNECTED_STATE: + p2p_debug("No scan before 4-way handshake"); + /* + * since no scan before 4-way handshake and + * won't enter state P2P_CLIENT_CONNECTING_STATE_2: + */ + fallthrough; + case P2P_CLIENT_CONNECTING_STATE_2: + p2p_status_update(p2p_soc_obj, + P2P_CLIENT_COMPLETED_STATE); + p2p_debug("[P2P State] Changing state from Connecting state to P2P Client Connection Completed"); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_status_disconnect(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + enum QDF_OPMODE mode; + + p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev); + if (!p2p_soc_obj) { + p2p_err("P2P soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_SUCCESS; + + p2p_debug("connection status:%d", p2p_soc_obj->connection_status); + switch (p2p_soc_obj->connection_status) { + case P2P_CLIENT_CONNECTED_STATE_1: + p2p_status_update(p2p_soc_obj, + P2P_CLIENT_DISCONNECTED_STATE); + p2p_debug("[P2P State] 8 way Handshake completed and moved to disconnected state"); + break; + case P2P_CLIENT_COMPLETED_STATE: + p2p_status_update(p2p_soc_obj, P2P_NOT_ACTIVE); + p2p_debug("[P2P State] P2P Client is removed and moved to inactive state"); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_status_start_bss(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + enum QDF_OPMODE mode; + + p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev); + if (!p2p_soc_obj) { + p2p_err("P2P soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_GO_MODE) { + p2p_debug("this is not P2P GO, mode:%d", mode); + return QDF_STATUS_SUCCESS; + } + + p2p_debug("connection status:%d", p2p_soc_obj->connection_status); + switch (p2p_soc_obj->connection_status) { + case P2P_GO_NEG_COMPLETED: + p2p_status_update(p2p_soc_obj, + P2P_GO_COMPLETED_STATE); + p2p_debug("[P2P State] From Go nego completed to Non-autonomous Group started"); + break; + case P2P_NOT_ACTIVE: + p2p_status_update(p2p_soc_obj, + P2P_GO_COMPLETED_STATE); + p2p_debug("[P2P State] From Inactive to Autonomous Group started"); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + enum QDF_OPMODE mode; + + p2p_soc_obj = get_p2p_soc_obj_by_vdev(vdev); + if (!p2p_soc_obj) { + p2p_err("P2P soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_P2P_GO_MODE) { + p2p_debug("this is not P2P GO, mode:%d", mode); + return QDF_STATUS_SUCCESS; + } + + p2p_debug("connection status:%d", p2p_soc_obj->connection_status); + if (p2p_soc_obj->connection_status == P2P_GO_COMPLETED_STATE) { + p2p_status_update(p2p_soc_obj, P2P_NOT_ACTIVE); + p2p_debug("[P2P State] From GO completed to Inactive state GO got removed"); + } + + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_FEATURE_P2P_DEBUG */ + +#ifdef WLAN_FEATURE_P2P_P2P_STA +QDF_STATUS p2p_check_and_force_scc_go_plus_go(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + int go_count = 0; + uint32_t existing_chan_freq, chan_freq; + enum phy_ch_width existing_ch_width, ch_width; + uint8_t existing_vdev_id = WLAN_UMAC_VDEV_ID_MAX, vdev_id; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + bool go_force_scc = false; + + go_count = policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, NULL); + go_force_scc = policy_mgr_go_scc_enforced(psoc); + if (go_count > 1 && go_force_scc) { + vdev_id = wlan_vdev_get_id(vdev); + chan_freq = wlan_get_operation_chan_freq(vdev); + ch_width = vdev->vdev_mlme.bss_chan->ch_width; + p2p_debug("Current vdev_id %d, chan_freq %d and ch_width %d", + vdev_id, chan_freq, ch_width); + existing_vdev_id = policy_mgr_fetch_existing_con_info( + psoc, vdev_id, + chan_freq, + &existing_vdev_mode, + &existing_chan_freq, + &existing_ch_width); + p2p_debug("Existing vdev_id %d, chan_freq %d and ch_width %d", + existing_vdev_id, existing_chan_freq, + existing_ch_width); + if (existing_vdev_id == WLAN_UMAC_VDEV_ID_MAX) { + p2p_debug("force scc not required"); + return QDF_STATUS_SUCCESS; + } + if (existing_vdev_mode == PM_P2P_GO_MODE) { + policy_mgr_process_forcescc_for_go(psoc, + existing_vdev_id, + chan_freq, + ch_width, + PM_P2P_GO_MODE); + p2p_debug("CSA for vdev_id %d", existing_vdev_id); + } + } + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_main.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_main.h new file mode 100644 index 0000000000..ff500c47b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_main.h @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Defines main P2P functions & structures + */ + +#ifndef _WLAN_P2P_MAIN_H_ +#define _WLAN_P2P_MAIN_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_p2p_ucfg_api.h" + +#define MAX_QUEUE_LENGTH 20 +#define P2P_NOA_ATTR_IND 0x1090 +#define P2P_MODULE_NAME "P2P" +#define P2P_INVALID_VDEV_ID 0xFFFFFFFF +#define MAX_RANDOM_MAC_ADDRS 4 + +#define p2p_debug(params ...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_P2P, params) +#define p2p_info(params ...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_P2P, params) +#define p2p_warn(params ...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_P2P, params) +#define p2p_err(params ...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_P2P, params) +#define p2p_debug_rl(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_P2P, params) +#define p2p_info_rl(params...) \ + QDF_TRACE_INFO_RL(QDF_MODULE_ID_P2P, params) + +#define p2p_alert(params ...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_P2P, params) + +#define p2p_nofl_debug(params ...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_P2P, params) +#define p2p_nofl_info(params ...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_P2P, params) +#define p2p_nofl_warn(params ...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_P2P, params) +#define p2p_nofl_err(params ...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_P2P, params) +#define p2p_nofl_alert(params ...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_P2P, params) + +struct scheduler_msg; +struct p2p_tx_cnf; +struct p2p_rx_mgmt_frame; +struct p2p_lo_event; +struct p2p_start_param; +struct p2p_noa_info; +struct tx_action_context; + +/** + * enum p2p_cmd_type - P2P request type + * @P2P_ROC_REQ: P2P roc request + * @P2P_CANCEL_ROC_REQ: Cancel P2P roc request + * @P2P_MGMT_TX: P2P tx action frame request + * @P2P_MGMT_TX_CANCEL: Cancel tx action frame request + * @P2P_CLEANUP_ROC: Cleanup roc queue + * @P2P_CLEANUP_TX: Cleanup tx mgmt queue + * @P2P_SET_RANDOM_MAC: Set Random MAC addr filter request + */ +enum p2p_cmd_type { + P2P_ROC_REQ = 0, + P2P_CANCEL_ROC_REQ, + P2P_MGMT_TX, + P2P_MGMT_TX_CANCEL, + P2P_CLEANUP_ROC, + P2P_CLEANUP_TX, + P2P_SET_RANDOM_MAC, +}; + +/** + * enum p2p_event_type - P2P event type + * @P2P_EVENT_SCAN_EVENT: P2P scan event + * @P2P_EVENT_MGMT_TX_ACK_CNF: P2P mgmt tx confirm frame + * @P2P_EVENT_RX_MGMT: P2P rx mgmt frame + * @P2P_EVENT_LO_STOPPED: P2P listen offload stopped event + * @P2P_EVENT_NOA: P2P noa event + * @P2P_EVENT_ADD_MAC_RSP: Set Random MAC addr event + */ +enum p2p_event_type { + P2P_EVENT_SCAN_EVENT = 0, + P2P_EVENT_MGMT_TX_ACK_CNF, + P2P_EVENT_RX_MGMT, + P2P_EVENT_LO_STOPPED, + P2P_EVENT_NOA, + P2P_EVENT_ADD_MAC_RSP, +}; + +/** + * struct p2p_tx_conf_event - p2p tx confirm event + * @p2p_soc_obj: p2p soc private object + * @nbuf: buffer address + * @status: tx status + */ +struct p2p_tx_conf_event { + struct p2p_soc_priv_obj *p2p_soc_obj; + qdf_nbuf_t nbuf; + uint32_t status; +}; + +/** + * struct p2p_rx_mgmt_event - p2p rx mgmt frame event + * @p2p_soc_obj: p2p soc private object + * @rx_mgmt: p2p rx mgmt frame structure + */ +struct p2p_rx_mgmt_event { + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_rx_mgmt_frame *rx_mgmt; +}; + +/** + * struct p2p_lo_stop_event - p2p listen offload stop event + * @p2p_soc_obj: p2p soc private object + * @lo_event: p2p lo stop structure + */ +struct p2p_lo_stop_event { + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_lo_event *lo_event; +}; + +/** + * struct p2p_noa_event - p2p noa event + * @p2p_soc_obj: p2p soc private object + * @noa_info: p2p noa information structure + */ +struct p2p_noa_event { + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_noa_info *noa_info; +}; + +/** + * struct p2p_mac_filter_rsp - p2p set mac filter respone + * @p2p_soc_obj: p2p soc private object + * @vdev_id: vdev id + * @status: successfully(1) or not (0) + */ +struct p2p_mac_filter_rsp { + struct p2p_soc_priv_obj *p2p_soc_obj; + uint32_t vdev_id; + uint32_t status; +}; + +#ifdef WLAN_FEATURE_P2P_DEBUG +/** + * enum p2p_connection_status - p2p connection status + * @P2P_NOT_ACTIVE: P2P not active status + * @P2P_GO_NEG_PROCESS: P2P GO negotiation in process + * @P2P_GO_NEG_COMPLETED: P2P GO negotiation complete + * @P2P_CLIENT_CONNECTING_STATE_1: P2P client connecting state 1 + * @P2P_GO_COMPLETED_STATE: P2P GO complete state + * @P2P_CLIENT_CONNECTED_STATE_1: P2P client connected state 1 + * @P2P_CLIENT_DISCONNECTED_STATE: P2P client disconnected state + * @P2P_CLIENT_CONNECTING_STATE_2: P2P client connecting state 2 + * @P2P_CLIENT_COMPLETED_STATE: P2P client complete state + */ +enum p2p_connection_status { + P2P_NOT_ACTIVE, + P2P_GO_NEG_PROCESS, + P2P_GO_NEG_COMPLETED, + P2P_CLIENT_CONNECTING_STATE_1, + P2P_GO_COMPLETED_STATE, + P2P_CLIENT_CONNECTED_STATE_1, + P2P_CLIENT_DISCONNECTED_STATE, + P2P_CLIENT_CONNECTING_STATE_2, + P2P_CLIENT_COMPLETED_STATE +}; + +/** + * p2p_status_update() - Update p2p connection status + * @p2p_soc_obj: p2p priv object + * @status: p2p connection status + * + * Return: void + */ +void p2p_status_update(struct p2p_soc_priv_obj *p2p_soc_obj, + enum p2p_connection_status status); +#endif + +/** + * struct p2p_param - p2p parameters to be used + * @go_keepalive_period: P2P GO keep alive period + * @go_link_monitor_period: period where link is idle and + * where we send NULL frame + * @p2p_device_addr_admin: enable/disable to derive the P2P + * MAC address from the primary MAC address + * @skip_dfs_channel_p2p_search: skip DFS Channel in case of P2P Search + * @is_random_seq_num_enabled: Flag to generate random sequence numbers + * @indoor_channel_support: support to allow GO in indoor channels + * @go_ignore_non_p2p_probe_req: P2P GO ignore non-P2P probe req + */ +struct p2p_param { + uint32_t go_keepalive_period; + uint32_t go_link_monitor_period; + bool p2p_device_addr_admin; + bool is_random_seq_num_enabled; + bool indoor_channel_support; + bool go_ignore_non_p2p_probe_req; +}; + +/** + * struct p2p_soc_priv_obj - Per SoC p2p private object + * @soc: Pointer to SoC context + * @roc_q: Queue for pending roc requests + * @tx_q_roc: Queue for tx frames waiting for RoC + * @tx_q_ack: Queue for tx frames waiting for ack + * @scan_req_id: Scan requestor id + * @start_param: Start parameters, include callbacks and user + * data to HDD + * @cancel_roc_done: Cancel roc done event + * @cleanup_roc_done: Cleanup roc done event + * @cleanup_tx_done: Cleanup tx done event + * @roc_runtime_lock: Runtime lock for roc request + * @p2p_cb: Callbacks to protocol stack + * @cur_roc_vdev_id: Vdev id of current roc + * @p2p_idr: p2p idr + * @param: p2p parameters to be used + * @connection_status:Global P2P connection status + * @mcc_quota_ev_os_if_cb: callback to OS IF to indicate mcc quota event + */ +struct p2p_soc_priv_obj { + struct wlan_objmgr_psoc *soc; + qdf_list_t roc_q; + qdf_list_t tx_q_roc; + qdf_list_t tx_q_ack; + wlan_scan_requester scan_req_id; + struct p2p_start_param *start_param; + qdf_event_t cleanup_roc_done; + qdf_event_t cleanup_tx_done; + qdf_runtime_lock_t roc_runtime_lock; + struct p2p_protocol_callbacks p2p_cb; + uint32_t cur_roc_vdev_id; + qdf_idr p2p_idr; + struct p2p_param param; +#ifdef WLAN_FEATURE_P2P_DEBUG + enum p2p_connection_status connection_status; +#endif +#ifdef WLAN_FEATURE_MCC_QUOTA + mcc_quota_event_callback mcc_quota_ev_os_if_cb; +#endif +}; + +/** + * struct action_frame_cookie - Action frame cookie item in cookie list + * @cookie_node: qdf_list_node + * @cookie: Cookie value + */ +struct action_frame_cookie { + qdf_list_node_t cookie_node; + uint64_t cookie; +}; + +/** + * struct action_frame_random_mac - Action Frame random mac addr & + * related attrs + * @p2p_vdev_obj: p2p vdev private obj ptr + * @in_use: Checks whether random mac is in use + * @addr: Contains random mac addr + * @freq: Channel frequency + * @clear_timer: timer to clear random mac filter + * @cookie_list: List of cookies tied with random mac + */ +struct action_frame_random_mac { + struct p2p_vdev_priv_obj *p2p_vdev_obj; + bool in_use; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + uint32_t freq; + qdf_mc_timer_t clear_timer; + qdf_list_t cookie_list; +}; + +/** + * typedef p2p_request_mgr_callback_t() - callback to process set mac filter + * result + * @result: bool + * @context: callback context. + * + * Return: void + */ +typedef void (*p2p_request_mgr_callback_t)(bool result, void *context); + +/** + * struct random_mac_priv - request private data struct + * @result: result of request. + */ +struct random_mac_priv { + bool result; +}; + +/** + * struct p2p_set_mac_filter_req - set mac addr filter cmd data structure + * @soc: soc object + * @vdev_id: vdev id + * @mac: mac address to be set + * @freq: frequency + * @set: set or clear + * @cb: callback func to be called when the request completion + * @req_cookie: cookie to be used when request completed + */ +struct p2p_set_mac_filter_req { + struct wlan_objmgr_psoc *soc; + uint32_t vdev_id; + uint8_t mac[QDF_MAC_ADDR_SIZE]; + uint32_t freq; + bool set; + p2p_request_mgr_callback_t cb; + void *req_cookie; +}; + +/** + * struct p2p_vdev_priv_obj - Per vdev p2p private object + * @vdev: Pointer to vdev context + * @noa_info: NoA information + * @noa_status: NoA status i.e. Enabled / Disabled (TRUE/FALSE) + * @non_p2p_peer_count: Number of legacy stations connected to this GO + * @random_mac_lock: lock for random_mac list + * @random_mac: active random mac filter lists + * @pending_req: pending set mac filter request. + * @prev_action_frame_addr2: Address2 field (TA) of the last transmitted + * action frame. + */ +struct p2p_vdev_priv_obj { + struct wlan_objmgr_vdev *vdev; + struct p2p_noa_info *noa_info; + bool noa_status; + uint16_t non_p2p_peer_count; + + /* random address management for management action frames */ + qdf_spinlock_t random_mac_lock; + struct action_frame_random_mac random_mac[MAX_RANDOM_MAC_ADDRS]; + struct p2p_set_mac_filter_req pending_req; + uint8_t prev_action_frame_addr2[QDF_MAC_ADDR_SIZE]; +}; + +/** + * struct p2p_noa_attr - p2p noa attribute + * @rsvd1: reserved bits 1 + * @opps_ps: opps ps state of the AP + * @ct_win: ct window in TUs + * @index: identifies instance of NOA su element + * @rsvd2: reserved bits 2 + * @noa1_count: interval count of noa1 + * @noa1_duration: absent period duration of noa1 + * @noa1_interval: absent period interval of noa1 + * @noa1_start_time: 32 bit tsf time of noa1 + * @rsvd3: reserved bits 3 + * @noa2_count: interval count of noa2 + * @noa2_duration: absent period duration of noa2 + * @noa2_interval: absent period interval of noa2 + * @noa2_start_time: 32 bit tsf time of noa2 + */ +struct p2p_noa_attr { + uint32_t rsvd1:16; + uint32_t ct_win:7; + uint32_t opps_ps:1; + uint32_t index:8; + uint32_t rsvd2:24; + uint32_t noa1_count:8; + uint32_t noa1_duration; + uint32_t noa1_interval; + uint32_t noa1_start_time; + uint32_t rsvd3:24; + uint32_t noa2_count:8; + uint32_t noa2_duration; + uint32_t noa2_interval; + uint32_t noa2_start_time; +}; + +/** + * p2p_component_init() - P2P component initialization + * + * This function registers psoc/vdev create/delete handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_component_init(void); + +/** + * p2p_component_deinit() - P2P component de-init + * + * This function deregisters psoc/vdev create/delete handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_component_deinit(void); + +/** + * p2p_psoc_object_open() - Open P2P component + * @soc: soc context + * + * This function initialize p2p psoc object + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_psoc_object_open(struct wlan_objmgr_psoc *soc); + +/** + * p2p_psoc_object_close() - Close P2P component + * @soc: soc context + * + * This function de-init p2p psoc object. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_psoc_object_close(struct wlan_objmgr_psoc *soc); + +/** + * p2p_psoc_start() - Start P2P component + * @soc: soc context + * @req: P2P start parameters + * + * This function sets up layer call back in p2p psoc object + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_psoc_start(struct wlan_objmgr_psoc *soc, + struct p2p_start_param *req); + +/** + * p2p_psoc_stop() - Stop P2P component + * @soc: soc context + * + * This function clears up layer call back in p2p psoc object. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_psoc_stop(struct wlan_objmgr_psoc *soc); + +/** + * p2p_process_cmd() - Process P2P messages in OS interface queue + * @msg: message information + * + * This function is main handler for P2P messages in OS interface + * queue, it gets called by message scheduler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_cmd(struct scheduler_msg *msg); + +/** + * p2p_process_evt() - Process P2P messages in target interface queue + * @msg: message information + * + * This function is main handler for P2P messages in target interface + * queue, it gets called by message scheduler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_evt(struct scheduler_msg *msg); + +/** + * p2p_msg_flush_callback() - Callback used to flush P2P messages + * @msg: message information + * + * This callback will be called when scheduler flush some of P2P messages. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_msg_flush_callback(struct scheduler_msg *msg); + +/** + * p2p_event_flush_callback() - Callback used to flush P2P events + * @msg: event information + * + * This callback will be called when scheduler flush some of P2P events. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_event_flush_callback(struct scheduler_msg *msg); + +/** + * p2p_check_oui_and_force_1x1() - Function to get P2P client device + * attributes from assoc request frame IE passed in. + * @assoc_ie: Pointer to the IEs in the association req frame + * @assoc_ie_len: Total length of the IE in association req frame + * + * Return: true if the OUI is present else false + */ +bool p2p_check_oui_and_force_1x1(uint8_t *assoc_ie, uint32_t assoc_ie_len); + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * p2p_process_lo_stop() - Process lo stop event + * @lo_stop_event: listen offload stop event information + * + * This function handles listen offload stop event and deliver this + * event to HDD layer by registered callback. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_lo_stop( + struct p2p_lo_stop_event *lo_stop_event); +#else +static inline QDF_STATUS p2p_process_lo_stop( + struct p2p_lo_stop_event *lo_stop_event) +{ + return QDF_STATUS_SUCCESS; +} +#endif +/** + * p2p_process_noa() - Process noa event + * @noa_event: noa event information + * + * This function handles noa event and save noa information in p2p + * vdev object. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_noa(struct p2p_noa_event *noa_event); + +#ifdef WLAN_FEATURE_P2P_DEBUG +/** + * p2p_status_scan() - Update P2P connection status + * @vdev: vdev context + * + * This function updates P2P connection status when scanning + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_status_scan(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_status_connect() - Update P2P connection status + * @vdev: vdev context + * + * This function updates P2P connection status when connecting. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_status_connect(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_status_disconnect() - Update P2P connection status + * @vdev: vdev context + * + * This function updates P2P connection status when disconnecting. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_status_disconnect(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_status_start_bss() - Update P2P connection status + * @vdev: vdev context + * + * This function updates P2P connection status when starting BSS. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_status_start_bss(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_status_stop_bss() - Update P2P connection status + * @vdev: vdev context + * + * This function updates P2P connection status when stopping BSS. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS p2p_status_scan(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS p2p_status_connect(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS p2p_status_disconnect(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS p2p_status_start_bss(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_P2P_DEBUG */ +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * p2p_check_and_force_scc_go_plus_go() - Check and do force scc for + * go plus go + * @psoc: psoc object + * @vdev: vdev object + * + * This function checks whether force scc is enabled or not. If it + * is enabled then it will do force scc to remaining p2p go vdev if + * user has initiated CSA to current vdev. + * + * Return: status + */ + +QDF_STATUS +p2p_check_and_force_scc_go_plus_go(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); +#endif /* WLAN_FEATURE_P2P_P2P_STA */ +#endif /* _WLAN_P2P_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_mcc_quota.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_mcc_quota.c new file mode 100644 index 0000000000..55a6844025 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_mcc_quota.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains main P2P mcc quota event process core function + * implementation + */ + +#include +#include +#include +#include "wlan_p2p_mcc_quota_public_struct.h" +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_p2p_main.h" +#include "wlan_p2p_mcc_quota.h" + +/** + * struct wlan_mcc_quota_context - context for vdev iterate handler + * @indicated: mcc quota info indicated to os + * @quota_info: mcc quota information + * @p2p_soc_obj: p2p soc object + */ +struct wlan_mcc_quota_context { + bool indicated; + struct mcc_quota_info *quota_info; + struct p2p_soc_priv_obj *p2p_soc_obj; +}; + +/** + * wlan_indicate_quota_vdev_handler() - Vdev iterate handler to indicate + * mcc quota event to vdev object + * @psoc: psoc object + * @obj: vdev object + * @args: handler context + * + * Return: void + */ +static void wlan_indicate_quota_vdev_handler(struct wlan_objmgr_psoc *psoc, + void *obj, void *args) +{ + struct wlan_objmgr_vdev *vdev = obj; + struct wlan_mcc_quota_context *context = args; + struct p2p_soc_priv_obj *p2p_soc_obj = context->p2p_soc_obj; + enum QDF_OPMODE op_mode; + QDF_STATUS status; + + op_mode = wlan_vdev_mlme_get_opmode(vdev); + if (op_mode != QDF_STA_MODE && + op_mode != QDF_SAP_MODE && + op_mode != QDF_P2P_CLIENT_MODE && + op_mode != QDF_P2P_GO_MODE) + return; + + status = p2p_soc_obj->mcc_quota_ev_os_if_cb(psoc, vdev, + context->quota_info); + if (status != QDF_STATUS_SUCCESS) + return; + + context->indicated = true; +} + +QDF_STATUS p2p_mcc_quota_event_process(struct wlan_objmgr_psoc *psoc, + struct mcc_quota_info *event_info) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct wlan_mcc_quota_context context; + + if (!event_info) { + p2p_err("invalid mcc quota event information"); + return QDF_STATUS_E_INVAL; + } + + if (!psoc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc object is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!p2p_soc_obj->mcc_quota_ev_os_if_cb) { + p2p_err("mcc_quota_ev_os_if_cb is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_zero(&context, sizeof(struct wlan_mcc_quota_context)); + context.quota_info = event_info; + context.p2p_soc_obj = p2p_soc_obj; + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + wlan_indicate_quota_vdev_handler, + &context, true, WLAN_P2P_ID); + + if (context.indicated) + return QDF_STATUS_SUCCESS; + else + return p2p_soc_obj->mcc_quota_ev_os_if_cb(psoc, NULL, + event_info); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_mcc_quota.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_mcc_quota.h new file mode 100644 index 0000000000..92a59736a8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_mcc_quota.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Defines main MCC Quota core functions + */ + +#ifndef _WLAN_P2P_MCC_QUOTA_H_ +#define _WLAN_P2P_MCC_QUOTA_H_ + +struct wlan_objmgr_psoc; +struct mcc_quota_info; +/** + * p2p_mcc_quota_event_process() - Process mcc quota event + * @psoc: psoc object + * @event_info: mcc quota info + * + * This function handles the target mcc quota event to indicate + * the quota information to existing vdev's interface. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_mcc_quota_event_process(struct wlan_objmgr_psoc *psoc, + struct mcc_quota_info *event_info); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_off_chan_tx.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_off_chan_tx.c new file mode 100644 index 0000000000..39717c26ad --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_off_chan_tx.c @@ -0,0 +1,3515 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains off channel tx API definitions + */ + +#include +#include +#include +#include +#include +#include +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_tgt_api.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_p2p_roc.h" +#include "wlan_p2p_main.h" +#include "wlan_p2p_off_chan_tx.h" +#include "wlan_osif_request_manager.h" +#include +#include "wlan_mlme_api.h" +#include +#include + +/** + * p2p_psoc_get_tx_ops() - get p2p tx ops + * @psoc: psoc object + * + * This function returns p2p tx ops callbacks. + * + * Return: wlan_lmac_if_p2p_tx_ops + */ +static inline struct wlan_lmac_if_p2p_tx_ops * +p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.tx_ops->p2p; +} + +/** + * p2p_tx_context_check_valid() - check tx action context + * @tx_ctx: tx context + * + * This function check if tx action context and parameters are valid. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_tx_context_check_valid(struct tx_action_context *tx_ctx) +{ + struct wlan_objmgr_psoc *psoc; + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!tx_ctx) { + p2p_err("null tx action context"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + if (!p2p_soc_obj) { + p2p_err("null p2p soc private object"); + return QDF_STATUS_E_INVAL; + } + + psoc = p2p_soc_obj->soc; + if (!psoc) { + p2p_err("null p2p soc object"); + return QDF_STATUS_E_INVAL; + } + + if (!tx_ctx->buf) { + p2p_err("null tx buffer"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_vdev_check_valid() - check vdev and vdev mode + * @tx_ctx: tx context + * + * This function check if vdev and vdev mode are valid. It will drop + * probe response in sta mode. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +#ifdef SUPPORT_P2P_BY_ONE_INTF_WLAN +static QDF_STATUS p2p_vdev_check_valid(struct tx_action_context *tx_ctx) +{ + enum QDF_OPMODE mode; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + psoc = p2p_soc_obj->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, tx_ctx->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_err("null vdev object"); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + p2p_debug("vdev mode:%d", mode); + + /* drop probe response/disassoc/deauth for go, sap */ + if ((mode == QDF_SAP_MODE || + mode == QDF_P2P_GO_MODE) && + ((tx_ctx->frame_info.sub_type == P2P_MGMT_PROBE_RSP) || + (tx_ctx->frame_info.sub_type == P2P_MGMT_DISASSOC) || + (tx_ctx->frame_info.sub_type == P2P_MGMT_DEAUTH))) { + p2p_debug("drop frame, mode:%d, sub type:%d", mode, + tx_ctx->frame_info.sub_type); + status = QDF_STATUS_E_FAILURE; + } + + /* drop action frame for sap */ + if ((mode == QDF_SAP_MODE) && + (tx_ctx->frame_info.sub_type == P2P_MGMT_ACTION) && + (tx_ctx->frame_info.public_action_type == + P2P_PUBLIC_ACTION_NOT_SUPPORT) && + (tx_ctx->frame_info.action_type == P2P_ACTION_NOT_SUPPORT) && + !(wlan_vdev_mlme_feat_cap_get(vdev, WLAN_VDEV_F_SON) && + !tx_ctx->off_chan)) { + p2p_debug("drop action frame for SAP"); + status = QDF_STATUS_E_FAILURE; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return status; +} +#else +static QDF_STATUS p2p_vdev_check_valid(struct tx_action_context *tx_ctx) +{ + enum QDF_OPMODE mode; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + psoc = p2p_soc_obj->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, tx_ctx->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_err("null vdev object"); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + p2p_debug("vdev mode:%d", mode); + + /* drop probe response/disassoc/deauth for sta, go, sap */ + if ((mode == QDF_STA_MODE && + tx_ctx->frame_info.sub_type == P2P_MGMT_PROBE_RSP) || + ((mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) && + ((tx_ctx->frame_info.sub_type == P2P_MGMT_PROBE_RSP) || + (tx_ctx->frame_info.sub_type == P2P_MGMT_DISASSOC) || + (tx_ctx->frame_info.sub_type == P2P_MGMT_DEAUTH)))) { + p2p_debug("drop frame, mode:%d, sub type:%d", mode, + tx_ctx->frame_info.sub_type); + status = QDF_STATUS_E_FAILURE; + } + + /* drop ation frame for sap */ + if ((mode == QDF_SAP_MODE) && + (tx_ctx->frame_info.sub_type == P2P_MGMT_ACTION) && + (tx_ctx->frame_info.public_action_type == + P2P_PUBLIC_ACTION_NOT_SUPPORT) && + (tx_ctx->frame_info.action_type == P2P_ACTION_NOT_SUPPORT) && + !(wlan_vdev_mlme_feat_cap_get(vdev, WLAN_VDEV_F_SON) && + !tx_ctx->off_chan)) { + p2p_debug("drop action frame for SAP"); + status = QDF_STATUS_E_FAILURE; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return status; +} +#endif /* SUPPORT_P2P_BY_ONE_INTF_WLAN */ + +/** + * p2p_check_and_update_channel() - check and update tx channel + * @tx_ctx: tx context + * + * This function checks and updates tx channel if channel is 0 in tx context. + * It will update channel to current roc channel if vdev mode is + * P2P DEVICE/CLIENT/GO. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_check_and_update_channel(struct tx_action_context *tx_ctx) +{ + enum QDF_OPMODE mode; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *curr_roc_ctx; + + if (!tx_ctx || tx_ctx->chan_freq) { + p2p_err("NULL tx ctx or channel valid"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + psoc = p2p_soc_obj->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, tx_ctx->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_err("null vdev object"); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); + + if (curr_roc_ctx && + (mode == QDF_P2P_DEVICE_MODE || + mode == QDF_P2P_CLIENT_MODE || + mode == QDF_P2P_GO_MODE)) + tx_ctx->chan_freq = curr_roc_ctx->chan_freq; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_get_p2pie_ptr() - get the pointer to p2p ie + * @ie: source ie + * @ie_len: source ie length + * + * This function finds out p2p ie by p2p oui and return the pointer. + * + * Return: pointer to p2p ie + */ +const uint8_t *p2p_get_p2pie_ptr(const uint8_t *ie, uint16_t ie_len) +{ + return wlan_get_vendor_ie_ptr_from_oui(P2P_OUI, + P2P_OUI_SIZE, ie, ie_len); +} + +/** + * p2p_get_p2pie_from_probe_rsp() - get the pointer to p2p ie from + * probe response + * @tx_ctx: tx context + * + * This function finds out p2p ie and return the pointer if it is a + * probe response frame. + * + * Return: pointer to p2p ie + */ +static const uint8_t *p2p_get_p2pie_from_probe_rsp( + struct tx_action_context *tx_ctx) +{ + const uint8_t *ie; + const uint8_t *p2p_ie; + const uint8_t *tmp_p2p_ie = NULL; + uint16_t ie_len; + + if (tx_ctx->buf_len <= PROBE_RSP_IE_OFFSET) { + p2p_err("Invalid header len for probe response"); + return NULL; + } + + ie = tx_ctx->buf + PROBE_RSP_IE_OFFSET; + ie_len = tx_ctx->buf_len - PROBE_RSP_IE_OFFSET; + p2p_ie = p2p_get_p2pie_ptr(ie, ie_len); + while ((p2p_ie) && + (WLAN_MAX_IE_LEN == p2p_ie[1])) { + ie_len = tx_ctx->buf_len - (p2p_ie - tx_ctx->buf); + if (ie_len > 2) { + ie = p2p_ie + WLAN_MAX_IE_LEN + 2; + tmp_p2p_ie = p2p_get_p2pie_ptr(ie, ie_len); + } + + if (tmp_p2p_ie) { + p2p_ie = tmp_p2p_ie; + tmp_p2p_ie = NULL; + } else { + break; + } + } + + return p2p_ie; +} + +/** + * p2p_get_presence_noa_attr() - get the pointer to noa attr + * @pies: source ie + * @length: source ie length + * + * This function finds out noa attr by noa eid and return the pointer. + * + * Return: pointer to noa attr + */ +static const uint8_t *p2p_get_presence_noa_attr(const uint8_t *pies, int length) +{ + int left = length; + const uint8_t *ptr = pies; + uint8_t elem_id; + uint16_t elem_len; + + p2p_debug("pies:%pK, length:%d", pies, length); + + while (left >= 3) { + elem_id = ptr[0]; + elem_len = ((uint16_t) ptr[1]) | (ptr[2] << 8); + + left -= 3; + if (elem_len > left) { + p2p_err("****Invalid IEs, elem_len=%d left=%d*****", + elem_len, left); + return NULL; + } + if (elem_id == P2P_NOA_ATTR) + return ptr; + + left -= elem_len; + ptr += (elem_len + 3); + } + + return NULL; +} + +/** + * p2p_get_noa_attr_stream_in_mult_p2p_ies() - get the pointer to noa + * attr from multi p2p ie + * @noa_stream: noa stream + * @noa_len: noa stream length + * @overflow_len: overflow length + * + * This function finds out noa attr from multi p2p ies. + * + * Return: noa length + */ +static uint8_t p2p_get_noa_attr_stream_in_mult_p2p_ies(uint8_t *noa_stream, + uint8_t noa_len, uint8_t overflow_len) +{ + uint8_t overflow_p2p_stream[P2P_MAX_NOA_ATTR_LEN]; + + p2p_debug("noa_stream:%pK, noa_len:%d, overflow_len:%d", + noa_stream, noa_len, overflow_len); + if ((noa_len <= (P2P_MAX_NOA_ATTR_LEN + P2P_IE_HEADER_LEN)) && + (noa_len >= overflow_len) && + (overflow_len <= P2P_MAX_NOA_ATTR_LEN)) { + qdf_mem_copy(overflow_p2p_stream, + noa_stream + noa_len - overflow_len, + overflow_len); + noa_stream[noa_len - overflow_len] = + P2P_EID_VENDOR; + noa_stream[noa_len - overflow_len + 1] = + overflow_len + P2P_OUI_SIZE; + qdf_mem_copy(noa_stream + noa_len - overflow_len + 2, + P2P_OUI, P2P_OUI_SIZE); + qdf_mem_copy(noa_stream + noa_len + 2 + P2P_OUI_SIZE - + overflow_len, overflow_p2p_stream, + overflow_len); + } + + return noa_len + P2P_IE_HEADER_LEN; +} + +/** + * p2p_get_vdev_noa_info() - get vdev noa information + * @tx_ctx: tx context + * + * This function gets vdev noa information + * + * Return: pointer to noa information + */ +static struct p2p_noa_info *p2p_get_vdev_noa_info( + struct tx_action_context *tx_ctx) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE mode; + struct p2p_noa_info *noa_info = NULL; + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + psoc = p2p_soc_obj->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + tx_ctx->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_err("vdev obj is NULL"); + return NULL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + p2p_debug("vdev mode:%d", mode); + if (mode != QDF_P2P_GO_MODE) { + p2p_debug("invalid p2p vdev mode:%d", mode); + goto fail; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + + if (!p2p_vdev_obj || !(p2p_vdev_obj->noa_info)) { + p2p_debug("null noa info"); + goto fail; + } + + noa_info = p2p_vdev_obj->noa_info; + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return noa_info; +} + +/** + * p2p_get_noa_attr_stream() - get noa stream from p2p vdev object + * @tx_ctx: tx context + * @pnoa_stream: pointer to noa stream + * + * This function finds out noa stream from p2p vdev object + * + * Return: noa stream length + */ +static uint8_t p2p_get_noa_attr_stream( + struct tx_action_context *tx_ctx, uint8_t *pnoa_stream) +{ + struct p2p_noa_info *noa_info; + struct noa_descriptor *noa_desc_0; + struct noa_descriptor *noa_desc_1; + uint8_t *pbody = pnoa_stream; + uint8_t len = 0; + + noa_info = p2p_get_vdev_noa_info(tx_ctx); + if (!noa_info) { + p2p_debug("not valid noa information"); + return 0; + } + + noa_desc_0 = &(noa_info->noa_desc[0]); + noa_desc_1 = &(noa_info->noa_desc[1]); + if ((!(noa_desc_0->duration)) && + (!(noa_desc_1->duration)) && + (!noa_info->opps_ps)) { + p2p_debug("opps ps and duration are 0"); + return 0; + } + + pbody[0] = P2P_NOA_ATTR; + pbody[3] = noa_info->index; + pbody[4] = noa_info->ct_window | (noa_info->opps_ps << 7); + len = 5; + pbody += len; + + if (noa_desc_0->duration) { + *pbody = noa_desc_0->type_count; + pbody += 1; + len += 1; + + *((uint32_t *) (pbody)) = noa_desc_0->duration; + pbody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pbody)) = noa_desc_0->interval; + pbody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pbody)) = noa_desc_0->start_time; + pbody += sizeof(uint32_t); + len += 4; + } + + if (noa_desc_1->duration) { + *pbody = noa_desc_1->type_count; + pbody += 1; + len += 1; + + *((uint32_t *) (pbody)) = noa_desc_1->duration; + pbody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pbody)) = noa_desc_1->interval; + pbody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pbody)) = noa_desc_1->start_time; + pbody += sizeof(uint32_t); + len += 4; + } + + pbody = pnoa_stream + 1; + /* one byte for Attr and 2 bytes for length */ + *((uint16_t *) (pbody)) = len - 3; + + return len; +} + +/** + * p2p_update_noa_stream() - update noa stream + * @tx_ctx: tx context + * @p2p_ie: pointer to p2p ie + * @noa_attr: pointer to noa attr + * @total_len: pointer to total length of ie + * @noa_stream: noa stream + * + * This function updates noa stream. + * + * Return: noa stream length + */ +static uint16_t p2p_update_noa_stream(struct tx_action_context *tx_ctx, + uint8_t *p2p_ie, const uint8_t *noa_attr, uint32_t *total_len, + uint8_t *noa_stream) +{ + uint16_t noa_len; + uint16_t overflow_len; + uint8_t orig_len; + uint32_t nbytes_copy; + uint32_t buf_len = *total_len; + + noa_len = p2p_get_noa_attr_stream(tx_ctx, noa_stream); + if (noa_len <= 0) { + p2p_debug("do not find out noa attr"); + return 0; + } + + orig_len = p2p_ie[1]; + if (noa_attr) { + noa_len = noa_attr[1] | (noa_attr[2] << 8); + orig_len -= (noa_len + 1 + 2); + buf_len -= (noa_len + 1 + 2); + p2p_ie[1] = orig_len; + } + + if ((p2p_ie[1] + noa_len) > WLAN_MAX_IE_LEN) { + overflow_len = p2p_ie[1] + noa_len - + WLAN_MAX_IE_LEN; + noa_len = p2p_get_noa_attr_stream_in_mult_p2p_ies( + noa_stream, noa_len, overflow_len); + p2p_ie[1] = WLAN_MAX_IE_LEN; + } else { + /* increment the length of P2P IE */ + p2p_ie[1] += noa_len; + } + + *total_len = buf_len; + nbytes_copy = (p2p_ie + orig_len + 2) - tx_ctx->buf; + + p2p_debug("noa_len=%d orig_len=%d p2p_ie=%pK buf_len=%d nbytes copy=%d ", + noa_len, orig_len, p2p_ie, buf_len, nbytes_copy); + + return noa_len; +} + +/** + * p2p_set_ht_caps() - set ht capability + * @tx_ctx: tx context + * @num_bytes: number bytes + * + * This function sets ht capability + * + * Return: None + */ +static void p2p_set_ht_caps(struct tx_action_context *tx_ctx, + uint32_t num_bytes) +{ +} + +/** + * p2p_get_next_seq_num() - get next sequence number to fill mac header + * @peer: PEER object + * @tx_ctx: tx context + * @ta : transmitter address + * + * API to get next sequence number of action frame for the peer. + * + * Return: Next sequence number of the peer + */ +static uint16_t p2p_get_next_seq_num(struct wlan_objmgr_peer *peer, + struct tx_action_context *tx_ctx, + uint8_t *ta) +{ + uint16_t random_num, random_num_bitmask = 0x03FF; + uint16_t seq_num, seq_num_bitmask = 0x0FFF; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + bool is_new_random_ta; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(tx_ctx->p2p_soc_obj->soc, + tx_ctx->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return false; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("p2p vdev object is NULL"); + return false; + } + + is_new_random_ta = qdf_mem_cmp(p2p_vdev_obj->prev_action_frame_addr2, + ta, QDF_MAC_ADDR_SIZE); + if (is_new_random_ta && + tx_ctx->p2p_soc_obj->param.is_random_seq_num_enabled) { + /** + * Increment the previous sequence number with 10-bits + * random number to get the next sequence number. + */ + + qdf_get_random_bytes(&random_num, sizeof(random_num)); + random_num &= random_num_bitmask; + seq_num = (peer->peer_mlme.seq_num + random_num) & + seq_num_bitmask; + peer->peer_mlme.seq_num = seq_num; + + qdf_mem_copy(p2p_vdev_obj->prev_action_frame_addr2, ta, + QDF_MAC_ADDR_SIZE); + + } else { + seq_num = wlan_peer_mlme_get_next_seq_num(peer); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return seq_num; +} + +/** + * p2p_populate_mac_header() - update sequence number + * @tx_ctx: tx context + * + * This function updates sequence number of this mgmt frame + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_populate_mac_header( + struct tx_action_context *tx_ctx) +{ + struct wlan_seq_ctl *seq_ctl; + struct wlan_frame_hdr *wh; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + void *mac_addr; + uint16_t seq_num; + uint8_t pdev_id; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode; + + psoc = tx_ctx->p2p_soc_obj->soc; + + wh = (struct wlan_frame_hdr *)tx_ctx->buf; + /* + * Remove the WEP bit if already set, p2p_populate_rmf_field will set it + * if required. + */ + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + mac_addr = wh->i_addr1; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, tx_ctx->vdev_id, + WLAN_P2P_ID); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_P2P_ID); + if (!peer) { + mac_addr = wh->i_addr2; + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_P2P_ID); + } + if (!peer) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + tx_ctx->vdev_id, + WLAN_P2P_ID); + if (vdev) { + opmode = wlan_vdev_mlme_get_opmode(vdev); + /* + * For NAN iface, retrieves mac address from vdev + * as it is self peer. Also, rand_mac_tx would be + * false as tx channel is not available. + */ + if (opmode == QDF_NAN_DISC_MODE || + tx_ctx->rand_mac_tx) { + mac_addr = wlan_vdev_mlme_get_macaddr(vdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, + mac_addr, + WLAN_P2P_ID); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + } + } + if (!peer) { + p2p_err("no valid peer"); + return QDF_STATUS_E_INVAL; + } + seq_num = (uint16_t)p2p_get_next_seq_num(peer, tx_ctx, wh->i_addr2); + seq_ctl = (struct wlan_seq_ctl *)(tx_ctx->buf + + WLAN_SEQ_CTL_OFFSET); + seq_ctl->seq_num_lo = (seq_num & WLAN_LOW_SEQ_NUM_MASK); + seq_ctl->seq_num_hi = ((seq_num & WLAN_HIGH_SEQ_NUM_MASK) >> + WLAN_HIGH_SEQ_NUM_OFFSET); + p2p_debug("seq num: %d", seq_num); + + wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_get_frame_type_str() - parse frame type to string + * @frame_info: frame information + * + * This function parse frame type to string. + * + * Return: command string + */ +static char *p2p_get_frame_type_str(struct p2p_frame_info *frame_info) +{ + if (frame_info->type == P2P_FRAME_NOT_SUPPORT) + return "Not support frame"; + + if (frame_info->sub_type == P2P_MGMT_NOT_SUPPORT) + return "Not support sub frame"; + + if (frame_info->action_type == P2P_ACTION_PRESENCE_REQ) + return "P2P action presence request"; + if (frame_info->action_type == P2P_ACTION_PRESENCE_RSP) + return "P2P action presence response"; + + switch (frame_info->public_action_type) { + case P2P_PUBLIC_ACTION_NEG_REQ: + return "GO negotiation request frame"; + case P2P_PUBLIC_ACTION_NEG_RSP: + return "GO negotiation response frame"; + case P2P_PUBLIC_ACTION_NEG_CNF: + return "GO negotiation confirm frame"; + case P2P_PUBLIC_ACTION_INVIT_REQ: + return "P2P invitation request"; + case P2P_PUBLIC_ACTION_INVIT_RSP: + return "P2P invitation response"; + case P2P_PUBLIC_ACTION_DEV_DIS_REQ: + return "Device discoverability request"; + case P2P_PUBLIC_ACTION_DEV_DIS_RSP: + return "Device discoverability response"; + case P2P_PUBLIC_ACTION_PROV_DIS_REQ: + return "Provision discovery request"; + case P2P_PUBLIC_ACTION_PROV_DIS_RSP: + return "Provision discovery response"; + case P2P_PUBLIC_ACTION_GAS_INIT_REQ: + return "GAS init request"; + case P2P_PUBLIC_ACTION_GAS_INIT_RSP: + return "GAS init response"; + case P2P_PUBLIC_ACTION_GAS_COMB_REQ: + return "GAS come back request"; + case P2P_PUBLIC_ACTION_GAS_COMB_RSP: + return "GAS come back response"; + case P2P_PUBLIC_ACTION_WNM_BTM_REQ: + return "BTM request"; + case P2P_PUBLIC_ACTION_RRM_BEACON_REQ: + return "BEACON request"; + case P2P_PUBLIC_ACTION_RRM_NEIGHBOR_RSP: + return "NEIGHBOR response"; + default: + return "Other frame"; + } +} + +/** + * p2p_init_frame_info() - init frame information structure + * @frame_info: pointer to frame information + * + * This function init frame information structure. + * + * Return: None + */ +static void p2p_init_frame_info(struct p2p_frame_info *frame_info) +{ + frame_info->type = P2P_FRAME_NOT_SUPPORT; + frame_info->sub_type = P2P_MGMT_NOT_SUPPORT; + frame_info->public_action_type = + P2P_PUBLIC_ACTION_NOT_SUPPORT; + frame_info->action_type = P2P_ACTION_NOT_SUPPORT; +} + +/** + * p2p_get_frame_info() - get frame information from packet + * @data_buf: data buffer address + * @length: buffer length + * @frame_info: frame information + * + * This function gets frame information from packet. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_get_frame_info(uint8_t *data_buf, uint32_t length, + struct p2p_frame_info *frame_info) +{ + uint8_t type; + uint8_t sub_type; + uint8_t action_type; + uint8_t *buf = data_buf; + + p2p_init_frame_info(frame_info); + + if (length < P2P_ACTION_OFFSET + 1) { + p2p_err("invalid p2p mgmt hdr len"); + return QDF_STATUS_E_INVAL; + } + + type = P2P_GET_TYPE_FRM_FC(buf[0]); + sub_type = P2P_GET_SUBTYPE_FRM_FC(buf[0]); + if (type != P2P_FRAME_MGMT) { + p2p_err("just support mgmt frame"); + return QDF_STATUS_E_FAILURE; + } + + frame_info->type = type; + frame_info->sub_type = sub_type; + + if (sub_type != P2P_MGMT_ACTION) + return QDF_STATUS_SUCCESS; + + buf += P2P_ACTION_OFFSET; + if (length > P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET) { + switch (buf[0]) { + case P2P_PUBLIC_ACTION_FRAME: + if (buf[1] == P2P_PUBLIC_ACTION_VENDOR_SPECIFIC && + !qdf_mem_cmp(&buf[2], P2P_OUI, P2P_OUI_SIZE)) { + buf = data_buf + + P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET; + action_type = buf[0]; + if (action_type > P2P_PUBLIC_ACTION_PROV_DIS_RSP) + frame_info->public_action_type = + P2P_PUBLIC_ACTION_NOT_SUPPORT; + else + frame_info->public_action_type = + action_type; + } + break; + case WNM_ACTION_FRAME: + if (buf[1] == WNM_BSS_TM_REQUEST) { + action_type = buf[0]; + frame_info->public_action_type = + P2P_PUBLIC_ACTION_WNM_BTM_REQ; + } + break; + case RRM_ACTION_FRAME: + if (buf[1] == RRM_RADIO_MEASURE_REQ) { + action_type = buf[0]; + frame_info->public_action_type = + P2P_PUBLIC_ACTION_RRM_BEACON_REQ; + } else if (buf[1] == RRM_NEIGHBOR_RPT) { + action_type = buf[0]; + frame_info->public_action_type = + P2P_PUBLIC_ACTION_RRM_NEIGHBOR_RSP; + } + break; + default: + break; + } + } else if (length > P2P_ACTION_FRAME_TYPE_OFFSET && + buf[0] == P2P_ACTION_VENDOR_SPECIFIC_CATEGORY && + !qdf_mem_cmp(&buf[1], P2P_OUI, P2P_OUI_SIZE)) { + buf = data_buf + + P2P_ACTION_FRAME_TYPE_OFFSET; + action_type = buf[0]; + if (action_type == P2P_ACTION_PRESENCE_REQ) + frame_info->action_type = + P2P_ACTION_PRESENCE_REQ; + if (action_type == P2P_ACTION_PRESENCE_RSP) + frame_info->action_type = + P2P_ACTION_PRESENCE_RSP; + } else { + p2p_debug("this is not vendor specific p2p action frame"); + return QDF_STATUS_SUCCESS; + } + + p2p_debug("%s", p2p_get_frame_type_str(frame_info)); + + return QDF_STATUS_SUCCESS; +} + +bool p2p_is_action_frame_of_p2p_type(uint8_t *data_buf, uint32_t length) +{ + struct p2p_frame_info frame_info = {0}; + QDF_STATUS status; + + status = p2p_get_frame_info(data_buf, length, &frame_info); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + if (frame_info.public_action_type != P2P_PUBLIC_ACTION_NOT_SUPPORT || + frame_info.action_type != P2P_ACTION_NOT_SUPPORT) + return true; + + return false; +} + +#ifdef WLAN_FEATURE_P2P_DEBUG +/** + * p2p_tx_update_connection_status() - Update P2P connection status + * with tx frame + * @p2p_soc_obj: P2P soc private object + * @tx_frame_info: frame information + * @mac_to: Pointer to dest MAC address + * + * This function updates P2P connection status with tx frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_tx_update_connection_status( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct p2p_frame_info *tx_frame_info, + uint8_t *mac_to) +{ + if (!p2p_soc_obj || !tx_frame_info || !mac_to) { + p2p_err("invalid p2p_soc_obj:%pK or tx_frame_info:%pK or mac_to:%pK", + p2p_soc_obj, tx_frame_info, mac_to); + return QDF_STATUS_E_INVAL; + } + + if (tx_frame_info->public_action_type != + P2P_PUBLIC_ACTION_NOT_SUPPORT) + p2p_debug("%s ---> OTA to " QDF_MAC_ADDR_FMT, + p2p_get_frame_type_str(tx_frame_info), + QDF_MAC_ADDR_REF(mac_to)); + + if ((tx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_PROV_DIS_REQ) || + (tx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_INVIT_REQ) || + (tx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_NEG_REQ) || + (tx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_NEG_RSP)) { + p2p_status_update(p2p_soc_obj, P2P_GO_NEG_PROCESS); + p2p_debug("[P2P State]Inactive state to GO negotiation progress state"); + } else if ((tx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_NEG_CNF) || + (tx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_INVIT_RSP)) { + p2p_status_update(p2p_soc_obj, P2P_GO_NEG_COMPLETED); + p2p_debug("[P2P State]GO nego progress to GO nego completed state"); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_rx_update_connection_status() - Update P2P connection status + * with rx frame + * @p2p_soc_obj: P2P soc private object + * @rx_frame_info: frame information + * @mac_from: Pointer to source MAC address + * + * This function updates P2P connection status with rx frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_rx_update_connection_status( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct p2p_frame_info *rx_frame_info, + uint8_t *mac_from) +{ + if (!p2p_soc_obj || !rx_frame_info || !mac_from) { + p2p_err("invalid p2p_soc_obj:%pK or rx_frame_info:%pK, mac_from:%pK", + p2p_soc_obj, rx_frame_info, mac_from); + return QDF_STATUS_E_INVAL; + } + + if (rx_frame_info->public_action_type != + P2P_PUBLIC_ACTION_NOT_SUPPORT) + p2p_info_rl("%s <--- OTA from " QDF_MAC_ADDR_FMT, + p2p_get_frame_type_str(rx_frame_info), + QDF_MAC_ADDR_REF(mac_from)); + + if ((rx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_PROV_DIS_REQ) || + (rx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_NEG_REQ) || + (rx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_NEG_RSP)) { + p2p_status_update(p2p_soc_obj, P2P_GO_NEG_PROCESS); + p2p_info_rl("[P2P State]Inactive state to GO negotiation progress state"); + } else if (((rx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_NEG_CNF) || + (rx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_INVIT_RSP)) && + (p2p_soc_obj->connection_status == + P2P_GO_NEG_PROCESS)) { + p2p_status_update(p2p_soc_obj, P2P_GO_NEG_COMPLETED); + p2p_info_rl("[P2P State]GO negotiation progress to GO negotiation completed state"); + } else if ((rx_frame_info->public_action_type == + P2P_PUBLIC_ACTION_INVIT_REQ) && + (p2p_soc_obj->connection_status == P2P_NOT_ACTIVE)) { + p2p_status_update(p2p_soc_obj, P2P_GO_NEG_COMPLETED); + p2p_info_rl("[P2P State]Inactive state to GO negotiation completed state Autonomous GO formation"); + } + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS p2p_tx_update_connection_status( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct p2p_frame_info *tx_frame_info, + uint8_t *mac_to) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS p2p_rx_update_connection_status( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct p2p_frame_info *rx_frame_info, + uint8_t *mac_from) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * p2p_packet_alloc() - allocate qdf nbuf + * @size: buffe size + * @data: pointer to qdf nbuf data point + * @ppPacket: pointer to qdf nbuf point + * + * This function allocates qdf nbuf. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_packet_alloc(uint16_t size, void **data, + qdf_nbuf_t *ppPacket) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + qdf_nbuf_t nbuf; + + nbuf = qdf_nbuf_alloc(NULL, + roundup(size + P2P_TX_PKT_MIN_HEADROOM, 4), + P2P_TX_PKT_MIN_HEADROOM, sizeof(uint32_t), + false); + + if (nbuf) { + qdf_nbuf_put_tail(nbuf, size); + qdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = qdf_nbuf_data(nbuf); + qdf_mem_zero(*data, size); + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +/** + * p2p_send_tx_conf() - send tx confirm + * @tx_ctx: tx context + * @status: tx status + * + * This function send tx confirm to osif + * + * Return: QDF_STATUS_SUCCESS - pointer to tx context + */ +static QDF_STATUS p2p_send_tx_conf(struct tx_action_context *tx_ctx, + bool status) +{ + struct p2p_tx_cnf tx_cnf; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_start_param *start_param; + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + + if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) { + p2p_err("Invalid p2p soc object or start parameters"); + return QDF_STATUS_E_INVAL; + } + + start_param = p2p_soc_obj->start_param; + if (!(start_param->tx_cnf_cb)) { + p2p_err("no tx confirm callback"); + return QDF_STATUS_E_INVAL; + } + + if (tx_ctx->no_ack) + tx_cnf.action_cookie = 0; + else + tx_cnf.action_cookie = (uint64_t)tx_ctx->id; + + tx_cnf.vdev_id = tx_ctx->vdev_id; + tx_cnf.buf = tx_ctx->buf; + tx_cnf.buf_len = tx_ctx->buf_len; + tx_cnf.status = status ? 0 : 1; + + p2p_debug("soc:%pK, vdev_id:%d, action_cookie:%llx, len:%d, status:%d, buf:%pK", + p2p_soc_obj->soc, tx_cnf.vdev_id, + tx_cnf.action_cookie, tx_cnf.buf_len, + tx_cnf.status, tx_cnf.buf); + + p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx); + + start_param->tx_cnf_cb(start_param->tx_cnf_cb_data, &tx_cnf); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_get_hw_retry_count() - Get hw tx retry count from config store + * @psoc: psoc object + * @tx_ctx: tx context + * + * This function return the hw tx retry count for p2p action frame. + * 0 value means target will use fw default mgmt tx retry count 15. + * + * Return: frame hw tx retry count + */ +static uint8_t p2p_get_hw_retry_count(struct wlan_objmgr_psoc *psoc, + struct tx_action_context *tx_ctx) +{ + if (tx_ctx->frame_info.type != P2P_FRAME_MGMT) + return 0; + + if (tx_ctx->frame_info.sub_type != P2P_MGMT_ACTION) + return 0; + + switch (tx_ctx->frame_info.public_action_type) { + case P2P_PUBLIC_ACTION_NEG_REQ: + return wlan_mlme_get_mgmt_hw_tx_retry_count( + psoc, + CFG_GO_NEGOTIATION_REQ_FRAME_TYPE); + case P2P_PUBLIC_ACTION_INVIT_REQ: + return wlan_mlme_get_mgmt_hw_tx_retry_count( + psoc, + CFG_P2P_INVITATION_REQ_FRAME_TYPE); + case P2P_PUBLIC_ACTION_PROV_DIS_REQ: + return wlan_mlme_get_mgmt_hw_tx_retry_count( + psoc, + CFG_PROVISION_DISCOVERY_REQ_FRAME_TYPE); + default: + return 0; + } +} + +#define GET_HW_RETRY_LIMIT(count) QDF_GET_BITS(count, 0, 4) +#define GET_HW_RETRY_LIMIT_EXT(count) QDF_GET_BITS(count, 4, 3) + +/** + * p2p_mgmt_set_hw_retry_count() - Set mgmt hw tx retry count + * @psoc: psoc object + * @tx_ctx: tx context + * @mgmt_param: mgmt frame tx parameter + * + * This function will set mgmt frame hw tx retry count to tx parameter + * + * Return: void + */ +static void +p2p_mgmt_set_hw_retry_count(struct wlan_objmgr_psoc *psoc, + struct tx_action_context *tx_ctx, + struct wmi_mgmt_params *mgmt_param) +{ + uint8_t retry_count = p2p_get_hw_retry_count(psoc, tx_ctx); + + mgmt_param->tx_param.retry_limit = GET_HW_RETRY_LIMIT(retry_count); + mgmt_param->tx_param.retry_limit_ext = + GET_HW_RETRY_LIMIT_EXT(retry_count); + if (mgmt_param->tx_param.retry_limit || + mgmt_param->tx_param.retry_limit_ext) + mgmt_param->tx_params_valid = true; +} + +/** + * p2p_mgmt_tx() - call mgmt tx api + * @tx_ctx: tx context + * @buf_len: buffer length + * @packet: pointer to qdf nbuf + * @frame: pointer to qdf nbuf data + * + * This function call mgmt tx api to tx this action frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_mgmt_tx(struct tx_action_context *tx_ctx, + uint32_t buf_len, qdf_nbuf_t packet, uint8_t *frame) +{ + QDF_STATUS status; + mgmt_tx_download_comp_cb tx_comp_cb; + mgmt_ota_comp_cb tx_ota_comp_cb; + struct wlan_frame_hdr *wh; + struct wlan_objmgr_peer *peer = NULL; + struct wmi_mgmt_params mgmt_param = { 0 }; + struct wlan_objmgr_psoc *psoc; + void *mac_addr; + uint8_t pdev_id; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode; + bool mlo_link_agnostic; + + psoc = tx_ctx->p2p_soc_obj->soc; + mgmt_param.tx_frame = packet; + mgmt_param.frm_len = buf_len; + mgmt_param.vdev_id = tx_ctx->vdev_id; + mgmt_param.pdata = frame; + mgmt_param.chanfreq = tx_ctx->chan_freq; + mgmt_param.qdf_ctx = wlan_psoc_get_qdf_dev(psoc); + if (!(mgmt_param.qdf_ctx)) { + p2p_err("qdf ctx is null"); + return QDF_STATUS_E_INVAL; + } + p2p_mgmt_set_hw_retry_count(psoc, tx_ctx, &mgmt_param); + + wh = (struct wlan_frame_hdr *)frame; + mac_addr = wh->i_addr1; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, tx_ctx->vdev_id, + WLAN_P2P_ID); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, tx_ctx->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_err("VDEV null"); + return QDF_STATUS_E_INVAL; + } + + mlo_link_agnostic = wlan_get_mlo_link_agnostic_flag(vdev, mac_addr); + + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_P2P_ID); + if (!peer) { + mac_addr = wh->i_addr2; + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_P2P_ID); + } + if (!peer) { + opmode = wlan_vdev_mlme_get_opmode(vdev); + /* + * For NAN iface, retrieves mac address from vdev + * as it is self peer. Also, rand_mac_tx would be + * false as tx channel is not available. + */ + if (opmode == QDF_NAN_DISC_MODE || tx_ctx->rand_mac_tx) { + mac_addr = wlan_vdev_mlme_get_mldaddr(vdev); + /* for non-MLO case, mld address will zero */ + if (qdf_is_macaddr_zero( + (struct qdf_mac_addr *)mac_addr)) + mac_addr = wlan_vdev_mlme_get_macaddr(vdev); + + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_P2P_ID); + } + } + if (!peer) { + p2p_err("no valid peer"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + return QDF_STATUS_E_INVAL; + } + + if (tx_ctx->no_ack) { + tx_comp_cb = tgt_p2p_mgmt_download_comp_cb; + tx_ota_comp_cb = NULL; + } else { + tx_comp_cb = NULL; + tx_ota_comp_cb = tgt_p2p_mgmt_ota_comp_cb; + } + + p2p_debug("length:%d, chanfreq:%d retry count:%d(%d, %d)", + mgmt_param.frm_len, mgmt_param.chanfreq, + (mgmt_param.tx_param.retry_limit_ext << 4) | + mgmt_param.tx_param.retry_limit, + mgmt_param.tx_param.retry_limit, + mgmt_param.tx_param.retry_limit_ext); + + tx_ctx->nbuf = packet; + + if (mlo_is_mld_sta(vdev) && tx_ctx->frame_info.type == P2P_FRAME_MGMT && + tx_ctx->frame_info.sub_type == P2P_MGMT_ACTION && + mlo_link_agnostic) { + mgmt_param.mlo_link_agnostic = true; + } + status = wlan_mgmt_txrx_mgmt_frame_tx(peer, tx_ctx->p2p_soc_obj, + packet, tx_comp_cb, tx_ota_comp_cb, + WLAN_UMAC_COMP_P2P, &mgmt_param); + + wlan_objmgr_peer_release_ref(peer, WLAN_P2P_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return status; +} + +/** + * p2p_roc_req_for_tx_action() - new a roc request for tx + * @tx_ctx: tx context + * + * This function new a roc request for tx and call roc api to process + * this new roc request. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_roc_req_for_tx_action( + struct tx_action_context *tx_ctx) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *roc_ctx; + QDF_STATUS status; + + roc_ctx = qdf_mem_malloc(sizeof(struct p2p_roc_context)); + if (!roc_ctx) + return QDF_STATUS_E_NOMEM; + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + roc_ctx->p2p_soc_obj = p2p_soc_obj; + roc_ctx->vdev_id = tx_ctx->vdev_id; + roc_ctx->chan_freq = tx_ctx->chan_freq; + roc_ctx->duration = tx_ctx->duration; + roc_ctx->roc_state = ROC_STATE_IDLE; + roc_ctx->roc_type = OFF_CHANNEL_TX; + roc_ctx->tx_ctx = tx_ctx; + roc_ctx->id = tx_ctx->id; + tx_ctx->roc_cookie = (uintptr_t)roc_ctx; + + p2p_debug("create roc request for off channel tx, tx ctx:%pK, roc ctx:%pK", + tx_ctx, roc_ctx); + + status = p2p_process_roc_req(roc_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("request roc for tx action frrame fail"); + return status; + } + + status = qdf_list_insert_back(&p2p_soc_obj->tx_q_roc, + &tx_ctx->node); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to insert off chan tx context to wait roc req queue"); + + return status; +} + +/** + * p2p_find_tx_ctx() - find tx context by cookie + * @p2p_soc_obj: p2p soc object + * @cookie: cookie to this p2p tx context + * @is_roc_q: it is in waiting for roc queue + * @is_ack_q: it is in waiting for ack queue + * + * This function finds out tx context by cookie. + * + * Return: pointer to tx context + */ +static struct tx_action_context *p2p_find_tx_ctx( + struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie, + bool *is_roc_q, bool *is_ack_q) +{ + struct tx_action_context *cur_tx_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + *is_roc_q = false; + *is_ack_q = false; + + p2p_debug("Start to find tx ctx, p2p soc_obj:%pK, cookie:%llx", + p2p_soc_obj, cookie); + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + cur_tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + if ((uintptr_t) cur_tx_ctx == cookie) { + *is_roc_q = true; + p2p_debug("find tx ctx, cookie:%llx", cookie); + return cur_tx_ctx; + } + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc, + p_node, &p_node); + } + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + cur_tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + if ((uintptr_t) cur_tx_ctx == cookie) { + *is_ack_q = true; + p2p_debug("find tx ctx, cookie:%llx", cookie); + return cur_tx_ctx; + } + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack, + p_node, &p_node); + } + + return NULL; +} + +/** + * p2p_find_tx_ctx_by_roc() - find tx context by roc + * @p2p_soc_obj: p2p soc object + * @cookie: cookie to roc context + * + * This function finds out tx context by roc context. + * + * Return: pointer to tx context + */ +static struct tx_action_context *p2p_find_tx_ctx_by_roc( + struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie) +{ + struct tx_action_context *cur_tx_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + p2p_debug("Start to find tx ctx, p2p soc_obj:%pK, cookie:%llx", + p2p_soc_obj, cookie); + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + cur_tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + if (cur_tx_ctx->roc_cookie == cookie) { + p2p_debug("find tx ctx, cookie:%llx", cookie); + return cur_tx_ctx; + } + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc, + p_node, &p_node); + } + + return NULL; +} + +/** + * p2p_move_tx_context_to_ack_queue() - move tx context to tx_q_ack + * @tx_ctx: tx context + * + * This function moves tx context to waiting for ack queue. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_move_tx_context_to_ack_queue( + struct tx_action_context *tx_ctx) +{ + bool is_roc_q = false; + bool is_ack_q = false; + struct p2p_soc_priv_obj *p2p_soc_obj = tx_ctx->p2p_soc_obj; + struct tx_action_context *cur_tx_ctx; + QDF_STATUS status; + + cur_tx_ctx = p2p_find_tx_ctx(p2p_soc_obj, (uintptr_t)tx_ctx, + &is_roc_q, &is_ack_q); + if (cur_tx_ctx) { + if (is_roc_q) { + p2p_debug("find in wait for roc queue"); + status = qdf_list_remove_node( + &p2p_soc_obj->tx_q_roc, + (qdf_list_node_t *)tx_ctx); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to remove off chan tx context from wait roc req queue"); + } + + if (is_ack_q) { + p2p_debug("Already in waiting for ack queue"); + return QDF_STATUS_SUCCESS; + } + } + + status = qdf_list_insert_back( + &p2p_soc_obj->tx_q_ack, + &tx_ctx->node); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to insert off chan tx context to wait ack req queue"); + + return status; +} + +/** + * p2p_extend_roc_timer() - extend roc timer + * @p2p_soc_obj: p2p soc private object + * @frame_info: pointer to frame information + * + * This function extends roc timer for some of p2p public action frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_extend_roc_timer( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct p2p_frame_info *frame_info) +{ + struct p2p_roc_context *curr_roc_ctx; + uint32_t extend_time; + + curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); + if (!curr_roc_ctx) { + p2p_debug("no running roc request currently"); + return QDF_STATUS_SUCCESS; + } + + if (!frame_info) { + p2p_err("invalid frame information"); + return QDF_STATUS_E_INVAL; + } + + switch (frame_info->public_action_type) { + case P2P_PUBLIC_ACTION_NEG_REQ: + case P2P_PUBLIC_ACTION_NEG_RSP: + extend_time = 2 * P2P_ACTION_FRAME_DEFAULT_WAIT; + break; + case P2P_PUBLIC_ACTION_INVIT_REQ: + case P2P_PUBLIC_ACTION_DEV_DIS_REQ: + extend_time = P2P_ACTION_FRAME_DEFAULT_WAIT; + break; + default: + extend_time = 0; + break; + } + + if (extend_time) { + p2p_debug("extend roc timer, duration:%d", extend_time); + curr_roc_ctx->duration = extend_time; + return p2p_restart_roc_timer(curr_roc_ctx); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_adjust_tx_wait() - adjust tx wait + * @tx_ctx: tx context + * + * This function adjust wait time of this tx context + * + * Return: None + */ +static void p2p_adjust_tx_wait(struct tx_action_context *tx_ctx) +{ + struct p2p_frame_info *frame_info; + + frame_info = &(tx_ctx->frame_info); + switch (frame_info->public_action_type) { + case P2P_PUBLIC_ACTION_NEG_RSP: + case P2P_PUBLIC_ACTION_PROV_DIS_RSP: + tx_ctx->duration += P2P_ACTION_FRAME_RSP_WAIT; + break; + case P2P_PUBLIC_ACTION_NEG_CNF: + case P2P_PUBLIC_ACTION_INVIT_RSP: + tx_ctx->duration += P2P_ACTION_FRAME_ACK_WAIT; + break; + default: + break; + } +} + +/** + * p2p_remove_tx_context() - remove tx ctx from queue + * @tx_ctx: tx context + * + * This function remove tx context from waiting for roc queue or + * waiting for ack queue. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_remove_tx_context( + struct tx_action_context *tx_ctx) +{ + bool is_roc_q = false; + bool is_ack_q = false; + struct tx_action_context *cur_tx_ctx; + uint64_t cookie = (uintptr_t)tx_ctx; + struct p2p_soc_priv_obj *p2p_soc_obj = tx_ctx->p2p_soc_obj; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_debug("tx context:%pK", tx_ctx); + + cur_tx_ctx = p2p_find_tx_ctx(p2p_soc_obj, cookie, &is_roc_q, + &is_ack_q); + + /* for not off channel tx case, won't find from queue */ + if (!cur_tx_ctx) { + p2p_debug("Do not find tx context from queue"); + goto end; + } + + if (is_roc_q) { + status = qdf_list_remove_node( + &p2p_soc_obj->tx_q_roc, + (qdf_list_node_t *)cur_tx_ctx); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to tx context from wait roc req queue"); + } + + if (is_ack_q) { + status = qdf_list_remove_node( + &p2p_soc_obj->tx_q_ack, + (qdf_list_node_t *)cur_tx_ctx); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to tx context from wait ack req queue"); + } + +end: + if (!tx_ctx->roc_cookie) + qdf_idr_remove(&p2p_soc_obj->p2p_idr, tx_ctx->id); + qdf_mem_free(tx_ctx->buf); + qdf_mem_free(tx_ctx); + + return status; +} + +/** + * p2p_tx_timeout() - Callback for tx timeout + * @pdata: pointer to tx context + * + * This function is callback for tx time out. + * + * Return: None + */ +static void p2p_tx_timeout(void *pdata) +{ + QDF_STATUS status, ret; + qdf_list_node_t *p_node; + struct tx_action_context *tx_ctx; + struct p2p_soc_priv_obj *p2p_soc_obj; + + p2p_info("pdata:%pK", pdata); + p2p_soc_obj = (struct p2p_soc_priv_obj *)pdata; + if (!p2p_soc_obj) { + p2p_err("null p2p soc obj"); + return; + } + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack, + p_node, &p_node); + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&tx_ctx->tx_timer)) { + ret = qdf_list_remove_node(&p2p_soc_obj->tx_q_ack, + &tx_ctx->node); + if (ret == QDF_STATUS_SUCCESS) { + qdf_mc_timer_destroy(&tx_ctx->tx_timer); + p2p_send_tx_conf(tx_ctx, false); + qdf_mem_free(tx_ctx->buf); + qdf_mem_free(tx_ctx); + } else + p2p_err("remove %pK from roc_q fail", + tx_ctx); + } + } +} + +/** + * p2p_enable_tx_timer() - enable tx timer + * @tx_ctx: tx context + * + * This function enable tx timer for action frame required ota tx. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_enable_tx_timer(struct tx_action_context *tx_ctx) +{ + QDF_STATUS status; + + status = qdf_mc_timer_init(&tx_ctx->tx_timer, + QDF_TIMER_TYPE_SW, p2p_tx_timeout, + tx_ctx->p2p_soc_obj); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("failed to init tx timer tx_ctx:%pK", tx_ctx); + return status; + } + + status = qdf_mc_timer_start(&tx_ctx->tx_timer, + P2P_ACTION_FRAME_TX_TIMEOUT); + if (status != QDF_STATUS_SUCCESS) + p2p_err("tx timer start failed tx_ctx:%pK", tx_ctx); + + return status; +} + +/** + * p2p_disable_tx_timer() - disable tx timer + * @tx_ctx: tx context + * + * This function disable tx timer for action frame required ota tx. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_disable_tx_timer(struct tx_action_context *tx_ctx) +{ + QDF_STATUS status; + + p2p_debug("tx context:%pK", tx_ctx); + + status = qdf_mc_timer_stop(&tx_ctx->tx_timer); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to stop tx timer, status:%d", status); + + status = qdf_mc_timer_destroy(&tx_ctx->tx_timer); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to destroy tx timer, status:%d", status); + + return status; +} + +/** + * p2p_populate_rmf_field() - populate unicast rmf frame + * @tx_ctx: tx_action_context + * @size: input size of frame, and output new size + * @ppbuf: input frame ptr, and output new frame + * @ppkt: input pkt, output new pkt. + * + * This function allocates new pkt for rmf frame. The + * new frame has extra space for ccmp field. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_populate_rmf_field(struct tx_action_context *tx_ctx, + uint32_t *size, uint8_t **ppbuf, qdf_nbuf_t *ppkt) +{ + struct wlan_frame_hdr *wh, *rmf_wh; + struct action_frm_hdr *action_hdr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + qdf_nbuf_t pkt = NULL; + uint8_t *frame; + uint32_t frame_len; + struct p2p_soc_priv_obj *p2p_soc_obj; + uint8_t action_category; + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + + if (tx_ctx->frame_info.sub_type != P2P_MGMT_ACTION || + !p2p_soc_obj->p2p_cb.is_mgmt_protected) + return QDF_STATUS_SUCCESS; + if (*size < (sizeof(struct wlan_frame_hdr) + + sizeof(struct action_frm_hdr))) { + return QDF_STATUS_E_INVAL; + } + + wh = (struct wlan_frame_hdr *)(*ppbuf); + action_hdr = (struct action_frm_hdr *)(*ppbuf + sizeof(*wh)); + + /* + * For Action frame which are not handled, the resp is sent back to the + * source without change, except that MSB of the Category set to 1, so + * to get the actual action category we need to ignore the MSB. + */ + action_category = action_hdr->action_category & 0x7f; + if (!wlan_mgmt_is_rmf_mgmt_action_frame(action_category)) { + p2p_debug("non rmf act frame 0x%x category %x", + tx_ctx->frame_info.sub_type, + action_hdr->action_category); + return QDF_STATUS_SUCCESS; + } + + if (!p2p_soc_obj->p2p_cb.is_mgmt_protected( + tx_ctx->vdev_id, wh->i_addr1)) { + p2p_debug("non rmf connection vdev %d "QDF_MAC_ADDR_FMT, + tx_ctx->vdev_id, QDF_MAC_ADDR_REF(wh->i_addr1)); + return QDF_STATUS_SUCCESS; + } + if (!qdf_is_macaddr_group((struct qdf_mac_addr *)wh->i_addr1) && + !qdf_is_macaddr_broadcast((struct qdf_mac_addr *)wh->i_addr1)) { + uint8_t mic_len, mic_hdr_len, pdev_id; + + pdev_id = + wlan_get_pdev_id_from_vdev_id(tx_ctx->p2p_soc_obj->soc, + tx_ctx->vdev_id, + WLAN_P2P_ID); + status = mlme_get_peer_mic_len(p2p_soc_obj->soc, pdev_id, + wh->i_addr1, &mic_len, + &mic_hdr_len); + if (QDF_IS_STATUS_ERROR(status)) { + p2p_err("Failed to get peer mic length."); + return status; + } + + frame_len = *size + mic_hdr_len + mic_len; + status = p2p_packet_alloc((uint16_t)frame_len, (void **)&frame, + &pkt); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to allocate %d bytes for rmf frame.", + frame_len); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(frame, wh, sizeof(*wh)); + qdf_mem_copy(frame + sizeof(*wh) + mic_hdr_len, + *ppbuf + sizeof(*wh), + *size - sizeof(*wh)); + rmf_wh = (struct wlan_frame_hdr *)frame; + (rmf_wh)->i_fc[1] |= IEEE80211_FC1_WEP; + p2p_debug("set protection 0x%x cat %d "QDF_MAC_ADDR_FMT, + tx_ctx->frame_info.sub_type, + action_hdr->action_category, + QDF_MAC_ADDR_REF(wh->i_addr1)); + + qdf_nbuf_free(*ppkt); + *ppbuf = frame; + *ppkt = pkt; + *size = frame_len; + /* + * Some target which support sending mgmt frame based on htt + * would DMA write this PMF tx frame buffer, it may cause smmu + * check permission fault, set a flag to do bi-direction DMA + * map, normal tx unmap is enough for this case. + */ + QDF_NBUF_CB_TX_DMA_BI_MAP(pkt) = 1; + } + + return status; +} + +/** + * p2p_execute_tx_action_frame() - execute tx action frame + * @tx_ctx: tx context + * + * This function modify p2p ie and tx this action frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_execute_tx_action_frame( + struct tx_action_context *tx_ctx) +{ + uint8_t *frame; + qdf_nbuf_t packet; + QDF_STATUS status; + uint8_t noa_len = 0; + uint8_t noa_stream[P2P_NOA_STREAM_ARR_SIZE]; + uint8_t orig_len = 0; + const uint8_t *ie; + uint8_t ie_len; + uint8_t *p2p_ie = NULL; + const uint8_t *presence_noa_attr = NULL; + uint32_t nbytes_copy; + uint32_t buf_len = tx_ctx->buf_len; + struct p2p_frame_info *frame_info; + struct wlan_objmgr_vdev *vdev; + + frame_info = &(tx_ctx->frame_info); + if (frame_info->sub_type == P2P_MGMT_PROBE_RSP) { + p2p_ie = (uint8_t *)p2p_get_p2pie_from_probe_rsp(tx_ctx); + } else if (frame_info->action_type == + P2P_ACTION_PRESENCE_RSP) { + ie = tx_ctx->buf + + P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET; + ie_len = tx_ctx->buf_len - + P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET; + p2p_ie = (uint8_t *)p2p_get_p2pie_ptr(ie, ie_len); + if (p2p_ie) { + /* extract the presence of NoA attribute inside + * P2P IE */ + ie = p2p_ie + P2P_IE_HEADER_LEN; + ie_len = p2p_ie[1]; + presence_noa_attr = p2p_get_presence_noa_attr( + ie, ie_len); + } + } else if (frame_info->type == P2P_FRAME_MGMT && + frame_info->sub_type == P2P_MGMT_ACTION) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + tx_ctx->p2p_soc_obj->soc, tx_ctx->vdev_id, + WLAN_P2P_ID); + + if (vdev) { + wlan_mlo_update_action_frame_from_user(vdev, + tx_ctx->buf, + tx_ctx->buf_len); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + } + } + + if ((frame_info->sub_type != P2P_MGMT_NOT_SUPPORT) && + p2p_ie) { + orig_len = p2p_ie[1]; + noa_len = p2p_update_noa_stream(tx_ctx, p2p_ie, + presence_noa_attr, &buf_len, + noa_stream); + buf_len += noa_len; + } + + if (frame_info->sub_type == P2P_MGMT_PROBE_RSP) + p2p_set_ht_caps(tx_ctx, buf_len); + + /* Ok-- try to allocate some memory: */ + status = p2p_packet_alloc((uint16_t) buf_len, (void **)&frame, + &packet); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to allocate %d bytes for a Probe Request.", + buf_len); + return status; + } + + /* + * Add sequence number to action frames + * Frames are handed over in .11 format by supplicant already + */ + p2p_populate_mac_header(tx_ctx); + + if ((noa_len > 0) && p2p_ie + && (noa_len < (P2P_MAX_NOA_ATTR_LEN + + P2P_IE_HEADER_LEN))) { + /* Add 2 bytes for length and Arribute field */ + nbytes_copy = (p2p_ie + orig_len + 2) - tx_ctx->buf; + qdf_mem_copy(frame, tx_ctx->buf, nbytes_copy); + qdf_mem_copy((frame + nbytes_copy), noa_stream, + noa_len); + qdf_mem_copy((frame + nbytes_copy + noa_len), + tx_ctx->buf + nbytes_copy, + buf_len - nbytes_copy - noa_len); + } else { + qdf_mem_copy(frame, tx_ctx->buf, buf_len); + } + + status = p2p_populate_rmf_field(tx_ctx, &buf_len, &frame, &packet); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("failed to populate rmf frame"); + qdf_nbuf_free(packet); + return status; + } + + status = p2p_mgmt_tx(tx_ctx, buf_len, packet, frame); + if (status == QDF_STATUS_SUCCESS) { + if (tx_ctx->no_ack) { + p2p_send_tx_conf(tx_ctx, true); + p2p_remove_tx_context(tx_ctx); + } else { + p2p_enable_tx_timer(tx_ctx); + p2p_move_tx_context_to_ack_queue(tx_ctx); + } + } else { + p2p_err("failed to tx mgmt frame"); + qdf_nbuf_free(packet); + } + + return status; +} + +struct tx_action_context *p2p_find_tx_ctx_by_nbuf( + struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf) +{ + struct tx_action_context *cur_tx_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + if (!p2p_soc_obj) { + p2p_err("invalid p2p soc object"); + return NULL; + } + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + cur_tx_ctx = + qdf_container_of(p_node, struct tx_action_context, node); + if (cur_tx_ctx->nbuf == nbuf) { + p2p_debug("find tx ctx, nbuf:%pK", nbuf); + return cur_tx_ctx; + } + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack, + p_node, &p_node); + } + + return NULL; +} + +void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj) +{ + struct tx_action_context *tx_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + p2p_debug("dump tx queue wait for roc, p2p soc obj:%pK, size:%d", + p2p_soc_obj, qdf_list_size(&p2p_soc_obj->tx_q_roc)); + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + p2p_debug("p2p soc object:%pK, tx ctx:%pK, vdev_id:%d, " + "scan_id:%d, roc_cookie:%llx, freq:%d, buf:%pK, " + "len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", + p2p_soc_obj, tx_ctx, + tx_ctx->vdev_id, tx_ctx->scan_id, + tx_ctx->roc_cookie, tx_ctx->chan_freq, + tx_ctx->buf, tx_ctx->buf_len, + tx_ctx->off_chan, tx_ctx->no_cck, + tx_ctx->no_ack, tx_ctx->duration); + + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc, + p_node, &p_node); + } + + p2p_debug("dump tx queue wait for ack, size:%d", + qdf_list_size(&p2p_soc_obj->tx_q_ack)); + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + p2p_debug("p2p soc object:%pK, tx_ctx:%pK, vdev_id:%d, " + "scan_id:%d, roc_cookie:%llx, freq:%d, buf:%pK, " + "len:%d, off_chan:%d, cck:%d, ack:%d, duration:%d", + p2p_soc_obj, tx_ctx, + tx_ctx->vdev_id, tx_ctx->scan_id, + tx_ctx->roc_cookie, tx_ctx->chan_freq, + tx_ctx->buf, tx_ctx->buf_len, + tx_ctx->off_chan, tx_ctx->no_cck, + tx_ctx->no_ack, tx_ctx->duration); + + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack, + p_node, &p_node); + } +} + +QDF_STATUS p2p_ready_to_tx_frame(struct p2p_soc_priv_obj *p2p_soc_obj, + uint64_t cookie) +{ + struct tx_action_context *cur_tx_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + cur_tx_ctx = p2p_find_tx_ctx_by_roc(p2p_soc_obj, cookie); + + while (cur_tx_ctx) { + p2p_debug("tx_ctx:%pK", cur_tx_ctx); + status = p2p_execute_tx_action_frame(cur_tx_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_send_tx_conf(cur_tx_ctx, false); + p2p_remove_tx_context(cur_tx_ctx); + } + cur_tx_ctx = p2p_find_tx_ctx_by_roc(p2p_soc_obj, cookie); + } + + return status; +} + +QDF_STATUS p2p_cleanup_tx_sync( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct wlan_objmgr_vdev *vdev) +{ + struct scheduler_msg msg = {0}; + struct p2p_cleanup_param *param; + QDF_STATUS status; + uint32_t vdev_id; + + if (!p2p_soc_obj) { + p2p_err("p2p soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + p2p_debug("p2p_soc_obj:%pK, vdev:%pK", p2p_soc_obj, vdev); + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_NOMEM; + + param->p2p_soc_obj = p2p_soc_obj; + if (vdev) + vdev_id = (uint32_t)wlan_vdev_get_id(vdev); + else + vdev_id = P2P_INVALID_VDEV_ID; + param->vdev_id = vdev_id; + qdf_event_reset(&p2p_soc_obj->cleanup_tx_done); + msg.type = P2P_CLEANUP_TX; + msg.bodyptr = param; + msg.callback = p2p_process_cmd; + status = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, &msg); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(param); + return status; + } + + status = qdf_wait_single_event( + &p2p_soc_obj->cleanup_tx_done, + P2P_WAIT_CLEANUP_ROC); + + if (status != QDF_STATUS_SUCCESS) + p2p_err("wait for cleanup tx timeout, %d", status); + + return status; +} + +QDF_STATUS p2p_process_cleanup_tx_queue(struct p2p_cleanup_param *param) +{ + struct tx_action_context *curr_tx_ctx; + qdf_list_node_t *p_node; + struct p2p_soc_priv_obj *p2p_soc_obj; + uint32_t vdev_id; + QDF_STATUS status, ret; + + if (!param || !(param->p2p_soc_obj)) { + p2p_err("Invalid cleanup param"); + return QDF_STATUS_E_FAILURE; + } + + p2p_soc_obj = param->p2p_soc_obj; + vdev_id = param->vdev_id; + + p2p_debug("clean up tx queue wait for roc, size:%d, vdev_id:%d", + qdf_list_size(&p2p_soc_obj->tx_q_roc), vdev_id); + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_roc, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_roc, + p_node, &p_node); + if ((vdev_id == P2P_INVALID_VDEV_ID) || + (vdev_id == curr_tx_ctx->vdev_id)) { + ret = qdf_list_remove_node(&p2p_soc_obj->tx_q_roc, + &curr_tx_ctx->node); + if (ret == QDF_STATUS_SUCCESS) { + p2p_send_tx_conf(curr_tx_ctx, false); + qdf_mem_free(curr_tx_ctx->buf); + qdf_mem_free(curr_tx_ctx); + } else + p2p_err("remove %pK from roc_q fail", + curr_tx_ctx); + } + } + + p2p_debug("clean up tx queue wait for ack, size:%d", + qdf_list_size(&p2p_soc_obj->tx_q_ack)); + + status = qdf_list_peek_front(&p2p_soc_obj->tx_q_ack, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_tx_ctx = qdf_container_of(p_node, + struct tx_action_context, node); + status = qdf_list_peek_next(&p2p_soc_obj->tx_q_ack, + p_node, &p_node); + if ((vdev_id == P2P_INVALID_VDEV_ID) || + (vdev_id == curr_tx_ctx->vdev_id)) { + ret = qdf_list_remove_node(&p2p_soc_obj->tx_q_ack, + &curr_tx_ctx->node); + if (ret == QDF_STATUS_SUCCESS) { + p2p_disable_tx_timer(curr_tx_ctx); + p2p_send_tx_conf(curr_tx_ctx, false); + qdf_mem_free(curr_tx_ctx->buf); + qdf_mem_free(curr_tx_ctx); + } else + p2p_err("remove %pK from roc_q fail", + curr_tx_ctx); + } + } + + qdf_event_set(&p2p_soc_obj->cleanup_tx_done); + + return QDF_STATUS_SUCCESS; +} + +bool p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr) +{ + uint32_t i = 0; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return false; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("p2p vdev object is NULL"); + return false; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + if ((p2p_vdev_obj->random_mac[i].in_use) && + (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr, + random_mac_addr, QDF_MAC_ADDR_SIZE))) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + return true; + } + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return false; +} + +/** + * find_action_frame_cookie() - Checks for action cookie in cookie list + * @cookie_list: List of cookies + * @rnd_cookie: Cookie to be searched + * + * Return: If search is successful return pointer to action_frame_cookie + * object in which cookie item is encapsulated. + */ +static struct action_frame_cookie * +find_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie) +{ + struct action_frame_cookie *action_cookie; + + qdf_list_for_each(cookie_list, action_cookie, cookie_node) { + if (action_cookie->cookie == rnd_cookie) + return action_cookie; + } + + return NULL; +} + +/** + * allocate_action_frame_cookie() - Allocate and add action cookie to + * given list + * @cookie_list: List of cookies + * @rnd_cookie: Cookie to be added + * + * Return: If allocation and addition is successful return pointer to + * action_frame_cookie object in which cookie item is encapsulated. + */ +static struct action_frame_cookie * +allocate_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie) +{ + struct action_frame_cookie *action_cookie; + + action_cookie = qdf_mem_malloc(sizeof(*action_cookie)); + if (!action_cookie) + return NULL; + + action_cookie->cookie = rnd_cookie; + qdf_list_insert_front(cookie_list, &action_cookie->cookie_node); + + return action_cookie; +} + +/** + * delete_action_frame_cookie() - Delete the cookie from given list + * @cookie_list: List of cookies + * @action_cookie: Cookie to be deleted + * + * This function deletes the cookie item from given list and corresponding + * object in which it is encapsulated. + * + * Return: None + */ +static void +delete_action_frame_cookie(qdf_list_t *cookie_list, + struct action_frame_cookie *action_cookie) +{ + qdf_list_remove_node(cookie_list, &action_cookie->cookie_node); + qdf_mem_free(action_cookie); +} + +/** + * delete_all_action_frame_cookie() - Delete all the cookies to given list + * @cookie_list: List of cookies + * + * This function deletes all the cookies from from given list. + * + * Return: None + */ +static void +delete_all_action_frame_cookie(qdf_list_t *cookie_list) +{ + qdf_list_node_t *node = NULL; + + p2p_debug("Delete cookie list %pK, size %d", cookie_list, + qdf_list_size(cookie_list)); + + while (!qdf_list_empty(cookie_list)) { + qdf_list_remove_front(cookie_list, &node); + qdf_mem_free(node); + } +} + +/** + * append_action_frame_cookie() - Append action cookie to given list + * @cookie_list: List of cookies + * @rnd_cookie: Cookie to be append + * + * This is a wrapper function which invokes allocate_action_frame_cookie + * if the cookie to be added is not duplicate + * + * Return: true - for successful case + * false - failed. + */ +static bool +append_action_frame_cookie(qdf_list_t *cookie_list, uint64_t rnd_cookie) +{ + struct action_frame_cookie *action_cookie; + + /* + * There should be no mac entry with empty cookie list, + * check and ignore if duplicate + */ + action_cookie = find_action_frame_cookie(cookie_list, rnd_cookie); + if (action_cookie) + /* random mac address is already programmed */ + return true; + + /* insert new cookie in cookie list */ + action_cookie = allocate_action_frame_cookie(cookie_list, rnd_cookie); + if (!action_cookie) + return false; + + return true; +} + +/** + * p2p_add_random_mac() - add or append random mac to given vdev rand mac list + * @soc: soc object + * @vdev_id: vdev id + * @mac: mac addr to be added or append + * @freq: frequency + * @rnd_cookie: random mac mgmt tx cookie + * + * This function will add or append the mac addr entry to vdev random mac list. + * Once the mac addr filter is not needed, it can be removed by + * p2p_del_random_mac. + * + * Return: QDF_STATUS_E_EXISTS - append to existing list + * QDF_STATUS_SUCCESS - add a new entry. + * other : failed to add the mac address entry. + */ +static QDF_STATUS +p2p_add_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, uint64_t rnd_cookie) +{ + uint32_t i; + uint32_t first_unused = MAX_RANDOM_MAC_ADDRS; + struct action_frame_cookie *action_cookie; + int32_t append_ret; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + p2p_debug("random_mac:vdev %d mac_addr:"QDF_MAC_ADDR_FMT" rnd_cookie=%llu freq = %u", + vdev_id, QDF_MAC_ADDR_REF(mac), rnd_cookie, freq); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + + return QDF_STATUS_E_INVAL; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_debug("random_mac:p2p vdev object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + /* + * Following loop checks whether random mac entry is already + * present, if present get the index of matched entry else + * get the first unused slot to store this new random mac + */ + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + if (!p2p_vdev_obj->random_mac[i].in_use) { + if (first_unused == MAX_RANDOM_MAC_ADDRS) + first_unused = i; + continue; + } + + if (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr, mac, + QDF_MAC_ADDR_SIZE)) + break; + } + + if (i != MAX_RANDOM_MAC_ADDRS) { + append_ret = append_action_frame_cookie( + &p2p_vdev_obj->random_mac[i].cookie_list, + rnd_cookie); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:append %d vdev %d freq %d "QDF_MAC_ADDR_FMT" rnd_cookie %llu", + append_ret, vdev_id, freq, QDF_MAC_ADDR_REF(mac), rnd_cookie); + if (!append_ret) { + p2p_debug("random_mac:failed to append rnd_cookie"); + return QDF_STATUS_E_NOMEM; + } + + return QDF_STATUS_E_EXISTS; + } + + if (first_unused == MAX_RANDOM_MAC_ADDRS) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:Reached the limit of Max random addresses"); + + return QDF_STATUS_E_RESOURCES; + } + + /* get the first unused buf and store new random mac */ + i = first_unused; + + action_cookie = allocate_action_frame_cookie( + &p2p_vdev_obj->random_mac[i].cookie_list, + rnd_cookie); + if (!action_cookie) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_err("random_mac:failed to alloc rnd cookie"); + + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(p2p_vdev_obj->random_mac[i].addr, mac, QDF_MAC_ADDR_SIZE); + p2p_vdev_obj->random_mac[i].in_use = true; + p2p_vdev_obj->random_mac[i].freq = freq; + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:add vdev %d freq %d "QDF_MAC_ADDR_FMT" rnd_cookie %llu", + vdev_id, freq, QDF_MAC_ADDR_REF(mac), rnd_cookie); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +p2p_del_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint64_t rnd_cookie) +{ + uint32_t i; + struct action_frame_cookie *action_cookie; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + p2p_debug("random_mac:vdev %d cookie %llu", vdev_id, rnd_cookie); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return QDF_STATUS_E_INVAL; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("p2p vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + struct action_frame_random_mac *random_mac; + qdf_freq_t freq; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + + random_mac = &p2p_vdev_obj->random_mac[i]; + if (!random_mac->in_use) + continue; + + action_cookie = find_action_frame_cookie( + &random_mac->cookie_list, rnd_cookie); + if (!action_cookie) + continue; + + delete_action_frame_cookie( + &random_mac->cookie_list, + action_cookie); + + if (qdf_list_empty(&random_mac->cookie_list)) { + random_mac->in_use = false; + freq = random_mac->freq; + qdf_mem_copy(addr, random_mac->addr, QDF_MAC_ADDR_SIZE); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + if (qdf_mc_timer_get_current_state( + &random_mac->clear_timer) == + QDF_TIMER_STATE_RUNNING) { + p2p_debug("random_mac:stop timer on vdev %d addr " QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(addr)); + qdf_mc_timer_stop(&random_mac->clear_timer); + } + + p2p_clear_mac_filter( + wlan_vdev_get_psoc(p2p_vdev_obj->vdev), + vdev_id, addr, freq); + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + p2p_debug("random_mac:noref on vdev %d addr "QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(addr)); + } + break; + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +p2p_random_mac_handle_tx_done(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint64_t rnd_cookie, uint32_t duration) +{ + uint32_t i; + struct action_frame_cookie *action_cookie; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + p2p_debug("random_mac:vdev %d cookie %llu duration %d", vdev_id, + rnd_cookie, duration); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("p2p vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + struct action_frame_random_mac *random_mac; + qdf_freq_t freq; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + + random_mac = &p2p_vdev_obj->random_mac[i]; + if (!random_mac->in_use) + continue; + action_cookie = find_action_frame_cookie( + &random_mac->cookie_list, rnd_cookie); + if (!action_cookie) + continue; + + /* If duration is zero then remove the cookie and also remove + * the filter from firmware. + */ + if (!duration) { + delete_action_frame_cookie(&random_mac->cookie_list, + action_cookie); + p2p_debug("random mac:clear mac addr on vdev %d addr " QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(random_mac->addr)); + + if (qdf_list_empty(&random_mac->cookie_list)) { + random_mac->in_use = false; + freq = random_mac->freq; + qdf_mem_copy(addr, random_mac->addr, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + p2p_clear_mac_filter( + wlan_vdev_get_psoc(p2p_vdev_obj->vdev), + vdev_id, addr, freq); + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + } + } else { + /* As duration is non zero start the timer for this + * duration. while the timer is running if tx cancel + * comes from supplicant then cookie will be removed + * and random mac filter will be removed from firmware. + * same thing will happen if timer expires without tx + * cancel from supplicant + */ + qdf_mem_copy(addr, random_mac->addr, QDF_MAC_ADDR_SIZE); + + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + if (qdf_mc_timer_get_current_state( + &random_mac->clear_timer) == + QDF_TIMER_STATE_RUNNING) + qdf_mc_timer_stop(&random_mac->clear_timer); + qdf_mc_timer_start(&random_mac->clear_timer, duration); + p2p_debug("random_mac:start timer on vdev %d addr " QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(addr)); + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + } + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +void p2p_del_all_rand_mac_vdev(struct wlan_objmgr_vdev *vdev) +{ + int32_t i; + uint32_t freq; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + + if (!vdev) + return; + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) + return; + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + struct action_frame_cookie *action_cookie; + struct action_frame_cookie *action_cookie_next; + + if (!p2p_vdev_obj->random_mac[i].in_use) + continue; + + /* empty the list and clear random addr */ + qdf_list_for_each_del(&p2p_vdev_obj->random_mac[i].cookie_list, + action_cookie, action_cookie_next, + cookie_node) { + qdf_list_remove_node( + &p2p_vdev_obj->random_mac[i].cookie_list, + &action_cookie->cookie_node); + qdf_mem_free(action_cookie); + } + + p2p_vdev_obj->random_mac[i].in_use = false; + freq = p2p_vdev_obj->random_mac[i].freq; + qdf_mem_copy(addr, p2p_vdev_obj->random_mac[i].addr, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + qdf_mc_timer_stop(&p2p_vdev_obj->random_mac[i].clear_timer); + p2p_clear_mac_filter(wlan_vdev_get_psoc(vdev), + wlan_vdev_get_id(vdev), addr, freq); + p2p_debug("random_mac:delall vdev %d freq %d addr "QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(vdev), freq, QDF_MAC_ADDR_REF(addr)); + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); +} + +static void +p2p_del_rand_mac_vdev_enum_handler(struct wlan_objmgr_psoc *psoc, + void *obj, void *arg) +{ + struct wlan_objmgr_vdev *vdev = obj; + + if (!vdev) { + p2p_err("random_mac:invalid vdev"); + return; + } + + if (!p2p_is_vdev_support_rand_mac(vdev)) + return; + + p2p_del_all_rand_mac_vdev(vdev); +} + +void p2p_del_all_rand_mac_soc(struct wlan_objmgr_psoc *soc) +{ + if (!soc) { + p2p_err("random_mac:soc object is NULL"); + return; + } + + wlan_objmgr_iterate_obj_list(soc, WLAN_VDEV_OP, + p2p_del_rand_mac_vdev_enum_handler, + NULL, 0, WLAN_P2P_ID); +} + +/** + * p2p_is_random_mac() - check mac addr is random mac for vdev + * @soc: soc object + * @vdev_id: vdev id + * @mac: mac addr to be added or append + * + * This function will check the source mac addr same as vdev's mac addr or not. + * If not same, then the source mac addr should be random mac addr. + * + * Return: true if mac is random mac, otherwise false + */ +static bool +p2p_is_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, uint8_t *mac) +{ + bool ret = false; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("random_mac:vdev is null"); + return false; + } + + if (qdf_mem_cmp(wlan_vdev_mlme_get_macaddr(vdev), + mac, QDF_MAC_ADDR_SIZE)) + ret = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return ret; +} + +static void p2p_set_mac_filter_callback(bool result, void *context) +{ + struct osif_request *request; + struct random_mac_priv *priv; + + p2p_debug("random_mac:set random mac filter result %d", result); + request = osif_request_get(context); + if (!request) { + p2p_err("random_mac:invalid response"); + return; + } + + priv = osif_request_priv(request); + priv->result = result; + + osif_request_complete(request); + osif_request_put(request); +} + +QDF_STATUS p2p_process_set_rand_mac_rsp(struct p2p_mac_filter_rsp *resp) +{ + struct wlan_objmgr_psoc *soc; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + if (!resp || !resp->p2p_soc_obj || !resp->p2p_soc_obj->soc) { + p2p_debug("random_mac:set_filter_req is null"); + return QDF_STATUS_E_INVAL; + } + p2p_debug("random_mac:process rsp on vdev %d status %d", resp->vdev_id, + resp->status); + soc = resp->p2p_soc_obj->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, resp->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_debug("random_mac:vdev is null vdev %d", resp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:p2p_vdev_obj is null vdev %d", + resp->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!p2p_vdev_obj->pending_req.soc) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("random_mac:no pending set req for vdev %d", + resp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + p2p_debug("random_mac:get pending req on vdev %d set %d mac filter "QDF_MAC_ADDR_FMT" freq %d", + p2p_vdev_obj->pending_req.vdev_id, + p2p_vdev_obj->pending_req.set, + QDF_MAC_ADDR_REF(p2p_vdev_obj->pending_req.mac), + p2p_vdev_obj->pending_req.freq); + if (p2p_vdev_obj->pending_req.cb) + p2p_vdev_obj->pending_req.cb( + !!resp->status, p2p_vdev_obj->pending_req.req_cookie); + + qdf_mem_zero(&p2p_vdev_obj->pending_req, + sizeof(p2p_vdev_obj->pending_req)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +p2p_process_set_rand_mac(struct p2p_set_mac_filter_req *set_filter_req) +{ + struct wlan_objmgr_psoc *soc; + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct set_rx_mac_filter param; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + struct wlan_objmgr_vdev *vdev; + + if (!set_filter_req || !set_filter_req->soc) { + p2p_debug("random_mac:set_filter_req is null"); + return QDF_STATUS_E_INVAL; + } + p2p_debug("random_mac:vdev %d set %d mac filter "QDF_MAC_ADDR_FMT" freq %d", + set_filter_req->vdev_id, set_filter_req->set, + QDF_MAC_ADDR_REF(set_filter_req->mac), set_filter_req->freq); + + soc = set_filter_req->soc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + soc, set_filter_req->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("random_mac:vdev is null vdev %d", + set_filter_req->vdev_id); + goto get_vdev_failed; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_debug("random_mac:p2p_vdev_obj is null vdev %d", + set_filter_req->vdev_id); + goto get_p2p_obj_failed; + } + if (p2p_vdev_obj->pending_req.soc) { + p2p_debug("random_mac:Busy on vdev %d set %d mac filter "QDF_MAC_ADDR_FMT" freq %d", + p2p_vdev_obj->pending_req.vdev_id, + p2p_vdev_obj->pending_req.set, + QDF_MAC_ADDR_REF(p2p_vdev_obj->pending_req.mac), + p2p_vdev_obj->pending_req.freq); + goto get_p2p_obj_failed; + } + + p2p_ops = p2p_psoc_get_tx_ops(soc); + if (p2p_ops && p2p_ops->set_mac_addr_rx_filter_cmd) { + qdf_mem_zero(¶m, sizeof(param)); + param.vdev_id = set_filter_req->vdev_id; + qdf_mem_copy(param.mac, set_filter_req->mac, + QDF_MAC_ADDR_SIZE); + param.freq = set_filter_req->freq; + param.set = set_filter_req->set; + status = p2p_ops->set_mac_addr_rx_filter_cmd(soc, ¶m); + if (status == QDF_STATUS_SUCCESS && set_filter_req->set) + qdf_mem_copy(&p2p_vdev_obj->pending_req, + set_filter_req, sizeof(*set_filter_req)); + p2p_debug("random_mac:p2p set mac addr rx filter, status:%d", + status); + } + +get_p2p_obj_failed: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + +get_vdev_failed: + if (status != QDF_STATUS_SUCCESS && + set_filter_req->cb) + set_filter_req->cb(false, set_filter_req->req_cookie); + + return status; +} + +/** + * p2p_set_mac_filter() - send set mac addr filter cmd + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * @set: set or clear + * @cb: callback func to be called when the request completed. + * @req_cookie: cookie to be returned + * + * This function send set random mac addr filter command to p2p component + * msg core + * + * Return: QDF_STATUS_SUCCESS - if sent successfully. + * otherwise : failed. + */ +static QDF_STATUS +p2p_set_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, bool set, + p2p_request_mgr_callback_t cb, void *req_cookie) +{ + struct p2p_set_mac_filter_req *set_filter_req; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + p2p_debug("random_mac:vdev %d freq %d set %d "QDF_MAC_ADDR_FMT, + vdev_id, freq, set, QDF_MAC_ADDR_REF(mac)); + + set_filter_req = qdf_mem_malloc(sizeof(*set_filter_req)); + if (!set_filter_req) + return QDF_STATUS_E_NOMEM; + + set_filter_req->soc = soc; + set_filter_req->vdev_id = vdev_id; + set_filter_req->freq = freq; + qdf_mem_copy(set_filter_req->mac, mac, QDF_MAC_ADDR_SIZE); + set_filter_req->set = set; + set_filter_req->cb = cb; + set_filter_req->req_cookie = req_cookie; + + msg.type = P2P_SET_RANDOM_MAC; + msg.bodyptr = set_filter_req; + msg.callback = p2p_process_cmd; + status = scheduler_post_message(QDF_MODULE_ID_P2P, QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, &msg); + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(set_filter_req); + + return status; +} + +QDF_STATUS +p2p_clear_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq) +{ + return p2p_set_mac_filter(soc, vdev_id, mac, freq, false, NULL, NULL); +} + +bool +p2p_is_vdev_support_rand_mac(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE mode; + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode == QDF_STA_MODE || + mode == QDF_P2P_CLIENT_MODE || + mode == QDF_P2P_DEVICE_MODE || + mode == QDF_NAN_DISC_MODE) + return true; + return false; +} + +/** + * p2p_is_vdev_support_rand_mac_by_id() - check vdev type support random mac + * mgmt tx or not + * @soc: soc obj + * @vdev_id: vdev id + * + * Return: true: support random mac mgmt tx + * false: not support random mac mgmt tx. + */ +static bool +p2p_is_vdev_support_rand_mac_by_id(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool ret = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) + return false; + ret = p2p_is_vdev_support_rand_mac(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return ret; +} + +/** + * p2p_set_rand_mac() - set random mac address rx filter + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * @rnd_cookie: cookie to be returned + * + * This function will post msg to p2p core to set random mac addr rx filter. + * It will wait the respone and return the result to caller. + * + * Return: true: set successfully + * false: failed + */ +static bool +p2p_set_rand_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, uint64_t rnd_cookie) +{ + bool ret = false; + int err; + QDF_STATUS status; + struct osif_request *request; + static const struct osif_request_params params = { + .priv_size = sizeof(struct random_mac_priv), + .timeout_ms = WLAN_WAIT_TIME_SET_RND, + }; + void *req_cookie; + struct random_mac_priv *priv; + + request = osif_request_alloc(¶ms); + if (!request) { + p2p_err("Request allocation failure"); + return false; + } + + req_cookie = osif_request_cookie(request); + + status = p2p_set_mac_filter(soc, vdev_id, mac, freq, true, + p2p_set_mac_filter_callback, req_cookie); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("random_mac:set mac filter failure %d", status); + } else { + err = osif_request_wait_for_response(request); + if (err) { + p2p_err("random_mac:timeout for set mac filter %d", + err); + } else { + priv = osif_request_priv(request); + ret = priv->result; + p2p_debug("random_mac:vdev %d freq %d result %d "QDF_MAC_ADDR_FMT" rnd_cookie %llu", + vdev_id, freq, priv->result, + QDF_MAC_ADDR_REF(mac), rnd_cookie); + } + } + osif_request_put(request); + + return ret; +} + +/** + * p2p_mac_clear_timeout() - clear random mac filter timeout + * @context: timer context + * + * This function will clear the mac addr rx filter in target if no + * reference to it. + * + * Return: void + */ +static void p2p_mac_clear_timeout(void *context) +{ + struct action_frame_random_mac *random_mac = context; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + uint32_t freq; + uint8_t addr[QDF_MAC_ADDR_SIZE]; + uint32_t vdev_id; + + if (!random_mac || !random_mac->p2p_vdev_obj) { + p2p_err("invalid context for mac_clear timeout"); + return; + } + p2p_vdev_obj = random_mac->p2p_vdev_obj; + if (!p2p_vdev_obj || !p2p_vdev_obj->vdev) + return; + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + + delete_all_action_frame_cookie(&random_mac->cookie_list); + random_mac->in_use = false; + freq = random_mac->freq; + qdf_mem_copy(addr, random_mac->addr, QDF_MAC_ADDR_SIZE); + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + + vdev_id = wlan_vdev_get_id(p2p_vdev_obj->vdev); + p2p_debug("random_mac:clear timeout vdev %d " QDF_MAC_ADDR_FMT " freq %d", + vdev_id, QDF_MAC_ADDR_REF(addr), freq); + + p2p_clear_mac_filter(wlan_vdev_get_psoc(p2p_vdev_obj->vdev), + vdev_id, addr, freq); +} + +/** + * p2p_request_random_mac() - request random mac mgmt tx + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * @rnd_cookie: cookie to be returned + * @duration: duration of tx timeout + * + * This function will add/append the random mac addr filter entry to vdev. + * If it is new added entry, it will request to set filter in target. + * + * Return: QDF_STATUS_SUCCESS: request successfully + * other: failed + */ +static QDF_STATUS +p2p_request_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq, uint64_t rnd_cookie, + uint32_t duration) +{ + QDF_STATUS status; + uint32_t i; + struct wlan_objmgr_vdev *vdev; + struct p2p_vdev_priv_obj *p2p_vdev_obj; + + status = p2p_add_random_mac(soc, vdev_id, mac, freq, rnd_cookie); + if (status == QDF_STATUS_E_EXISTS) + return QDF_STATUS_SUCCESS; + + else if (status != QDF_STATUS_SUCCESS) + return status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_debug("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_P2P); + if (!p2p_vdev_obj) { + p2p_debug("random_mac:p2p vdev object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + return QDF_STATUS_E_INVAL; + } + + if (!p2p_set_rand_mac(soc, vdev_id, mac, freq, rnd_cookie)) { + p2p_debug("random mac: failed to set rand mac address"); + + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + if (!qdf_mem_cmp(p2p_vdev_obj->random_mac[i].addr, mac, + QDF_MAC_ADDR_SIZE)) { + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + p2p_mac_clear_timeout( + &p2p_vdev_obj->random_mac[i]); + status = QDF_STATUS_SUCCESS; + qdf_spin_lock(&p2p_vdev_obj->random_mac_lock); + break; + } + } + qdf_spin_unlock(&p2p_vdev_obj->random_mac_lock); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + return status; +} + +void p2p_rand_mac_tx(struct wlan_objmgr_pdev *pdev, + struct tx_action_context *tx_action) +{ + struct wlan_objmgr_psoc *soc; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + bool is_vdev_up; + + if (!tx_action || !tx_action->p2p_soc_obj || + !tx_action->p2p_soc_obj->soc) + return; + soc = tx_action->p2p_soc_obj->soc; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, tx_action->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_err("vdev is null id:%d", tx_action->vdev_id); + return; + } + + /* + * For PASN authentication frames, fw may request PASN authentication + * with source address same as vdev mac address when vdev is not already + * started. Allow RX_FILTER configuration for vdev mac address also if + * vdev is not started to prevent PASN authentication frame drops. + */ + is_vdev_up = QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(vdev)); + if (!tx_action->no_ack && tx_action->chan_freq && + tx_action->buf_len > MIN_MAC_HEADER_LEN && + p2p_is_vdev_support_rand_mac_by_id(soc, tx_action->vdev_id) && + (p2p_is_random_mac(soc, tx_action->vdev_id, + &tx_action->buf[SRC_MAC_ADDR_OFFSET]) || + !is_vdev_up)) { + status = p2p_request_random_mac( + soc, tx_action->vdev_id, + &tx_action->buf[SRC_MAC_ADDR_OFFSET], + tx_action->chan_freq, + tx_action->id, + tx_action->duration); + if (status == QDF_STATUS_SUCCESS) + tx_action->rand_mac_tx = true; + else + tx_action->rand_mac_tx = false; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); +} + +void +p2p_rand_mac_tx_done(struct wlan_objmgr_psoc *soc, + struct tx_action_context *tx_ctx) +{ + if (!tx_ctx || !tx_ctx->rand_mac_tx || !soc) + return; + + p2p_random_mac_handle_tx_done(soc, tx_ctx->vdev_id, tx_ctx->id, + tx_ctx->duration); +} + +void p2p_init_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj) +{ + int32_t i; + + qdf_spinlock_create(&p2p_vdev_obj->random_mac_lock); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + qdf_mem_zero(&p2p_vdev_obj->random_mac[i], + sizeof(struct action_frame_random_mac)); + p2p_vdev_obj->random_mac[i].in_use = false; + p2p_vdev_obj->random_mac[i].p2p_vdev_obj = p2p_vdev_obj; + qdf_list_create(&p2p_vdev_obj->random_mac[i].cookie_list, 0); + qdf_mc_timer_init(&p2p_vdev_obj->random_mac[i].clear_timer, + QDF_TIMER_TYPE_SW, p2p_mac_clear_timeout, + &p2p_vdev_obj->random_mac[i]); + } +} + +void p2p_deinit_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj) +{ + int32_t i; + + p2p_del_all_rand_mac_vdev(p2p_vdev_obj->vdev); + for (i = 0; i < MAX_RANDOM_MAC_ADDRS; i++) { + qdf_mc_timer_destroy(&p2p_vdev_obj->random_mac[i].clear_timer); + qdf_list_destroy(&p2p_vdev_obj->random_mac[i].cookie_list); + } + qdf_spinlock_destroy(&p2p_vdev_obj->random_mac_lock); +} + +QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *curr_roc_ctx; + uint8_t *mac_to; + enum QDF_OPMODE mode; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + bool is_vdev_connected = false; + + status = p2p_tx_context_check_valid(tx_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("invalid tx action context"); + if (tx_ctx) { + if (tx_ctx->buf) { + p2p_send_tx_conf(tx_ctx, false); + qdf_mem_free(tx_ctx->buf); + } + qdf_mem_free(tx_ctx); + } + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = tx_ctx->p2p_soc_obj; + + p2p_debug("soc:%pK, tx_ctx:%pK, vdev_id:%d, scan_id:%d, " + "roc_cookie:%llx, freq:%d, buf:%pK, len:%d, " + "off_chan:%d, cck:%d, ack:%d, duration:%d", + p2p_soc_obj->soc, tx_ctx, tx_ctx->vdev_id, + tx_ctx->scan_id, tx_ctx->roc_cookie, tx_ctx->chan_freq, + tx_ctx->buf, tx_ctx->buf_len, tx_ctx->off_chan, + tx_ctx->no_cck, tx_ctx->no_ack, tx_ctx->duration); + + status = p2p_get_frame_info(tx_ctx->buf, tx_ctx->buf_len, + &(tx_ctx->frame_info)); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("unsupported frame"); + status = QDF_STATUS_E_INVAL; + goto fail; + } + + /* update P2P connection status with tx frame info */ + mac_to = &(tx_ctx->buf[DST_MAC_ADDR_OFFSET]); + p2p_tx_update_connection_status(p2p_soc_obj, + &(tx_ctx->frame_info), mac_to); + + status = p2p_vdev_check_valid(tx_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_debug("invalid vdev or vdev mode"); + status = QDF_STATUS_E_INVAL; + goto fail; + } + + /* Do not wait for ack for probe response */ + if (tx_ctx->frame_info.sub_type == P2P_MGMT_PROBE_RSP && + !(tx_ctx->no_ack)) { + p2p_debug("Force set no ack to 1"); + tx_ctx->no_ack = 1; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + p2p_soc_obj->soc, tx_ctx->vdev_id, WLAN_P2P_ID); + if (!vdev) { + p2p_err("null vdev object"); + goto fail; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode == QDF_STA_MODE) + is_vdev_connected = wlan_cm_is_vdev_connected(vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + if (!tx_ctx->off_chan || !tx_ctx->chan_freq) { + if (!tx_ctx->chan_freq) + p2p_check_and_update_channel(tx_ctx); + if (!tx_ctx->chan_freq && mode == QDF_STA_MODE && + !is_vdev_connected) { + p2p_debug("chan freq is zero, drop tx mgmt frame"); + goto fail; + } + status = p2p_execute_tx_action_frame(tx_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("execute tx fail"); + goto fail; + } else + return QDF_STATUS_SUCCESS; + } + + /* For off channel tx case */ + curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); + if (curr_roc_ctx && (curr_roc_ctx->chan_freq == tx_ctx->chan_freq)) { + if ((curr_roc_ctx->roc_state == ROC_STATE_REQUESTED) || + (curr_roc_ctx->roc_state == ROC_STATE_STARTED)) { + tx_ctx->roc_cookie = (uintptr_t)curr_roc_ctx; + status = qdf_list_insert_back( + &p2p_soc_obj->tx_q_roc, + &tx_ctx->node); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to insert off chan tx context to wait roc req queue"); + goto fail; + } else + return QDF_STATUS_SUCCESS; + } else if (curr_roc_ctx->roc_state == ROC_STATE_ON_CHAN) { + p2p_adjust_tx_wait(tx_ctx); + if (curr_roc_ctx->duration < tx_ctx->duration) + curr_roc_ctx->duration = tx_ctx->duration; + status = p2p_restart_roc_timer(curr_roc_ctx); + curr_roc_ctx->tx_ctx = tx_ctx; + if (status != QDF_STATUS_SUCCESS) { + p2p_err("restart roc timer fail"); + goto fail; + } + status = p2p_execute_tx_action_frame(tx_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("execute tx fail"); + goto fail; + } else + return QDF_STATUS_SUCCESS; + } + } + + curr_roc_ctx = p2p_find_roc_by_chan_freq(p2p_soc_obj, + tx_ctx->chan_freq); + if (curr_roc_ctx && (curr_roc_ctx->roc_state == ROC_STATE_IDLE)) { + tx_ctx->roc_cookie = (uintptr_t)curr_roc_ctx; + status = qdf_list_insert_back( + &p2p_soc_obj->tx_q_roc, + &tx_ctx->node); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to insert off chan tx context to wait roc req queue"); + goto fail; + } else { + return QDF_STATUS_SUCCESS; + } + } + + if (!tx_ctx->duration) { + tx_ctx->duration = P2P_ACTION_FRAME_DEFAULT_WAIT; + p2p_debug("use default wait %d", + P2P_ACTION_FRAME_DEFAULT_WAIT); + } + status = p2p_roc_req_for_tx_action(tx_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to request roc before off chan tx"); + goto fail; + } + + return QDF_STATUS_SUCCESS; + +fail: + p2p_send_tx_conf(tx_ctx, false); + qdf_idr_remove(&p2p_soc_obj->p2p_idr, tx_ctx->id); + qdf_mem_free(tx_ctx->buf); + qdf_mem_free(tx_ctx); + + return status; +} + +QDF_STATUS p2p_process_mgmt_tx_cancel( + struct cancel_roc_context *cancel_tx) +{ + bool is_roc_q = false; + bool is_ack_q = false; + struct tx_action_context *cur_tx_ctx; + struct p2p_roc_context *cur_roc_ctx; + struct cancel_roc_context cancel_roc; + + if (!cancel_tx || !(cancel_tx->cookie)) { + p2p_info("invalid cancel info"); + return QDF_STATUS_SUCCESS; + } + + cur_tx_ctx = p2p_find_tx_ctx(cancel_tx->p2p_soc_obj, + cancel_tx->cookie, &is_roc_q, &is_ack_q); + if (cur_tx_ctx) { + if (is_roc_q) { + cancel_roc.p2p_soc_obj = + cancel_tx->p2p_soc_obj; + cancel_roc.cookie = + cur_tx_ctx->roc_cookie; + p2p_remove_tx_context(cur_tx_ctx); + return p2p_process_cancel_roc_req(&cancel_roc); + } + if (is_ack_q) { + /*Has tx action frame, waiting for ack*/ + p2p_debug("Waiting for ack, cookie %llx", + cancel_tx->cookie); + } + } else { + p2p_debug("Failed to find tx ctx by cookie, cookie %llx", + cancel_tx->cookie); + + cur_roc_ctx = p2p_find_roc_by_tx_ctx(cancel_tx->p2p_soc_obj, + cancel_tx->cookie); + if (cur_roc_ctx) { + p2p_debug("tx ctx:%llx, roc:%pK", + cancel_tx->cookie, cur_roc_ctx); + cancel_roc.p2p_soc_obj = + cancel_tx->p2p_soc_obj; + cancel_roc.cookie = (uintptr_t) cur_roc_ctx; + return p2p_process_cancel_roc_req(&cancel_roc); + } + + p2p_debug("Failed to find roc by tx ctx"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_process_mgmt_tx_ack_cnf( + struct p2p_tx_conf_event *tx_cnf_event) +{ + struct p2p_tx_cnf tx_cnf; + struct tx_action_context *tx_ctx; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_start_param *start_param; + + p2p_soc_obj = tx_cnf_event->p2p_soc_obj; + + if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) { + qdf_nbuf_free(tx_cnf_event->nbuf); + p2p_err("Invalid p2p soc object or start parameters"); + return QDF_STATUS_E_INVAL; + } + + tx_ctx = p2p_find_tx_ctx_by_nbuf(p2p_soc_obj, tx_cnf_event->nbuf); + qdf_nbuf_free(tx_cnf_event->nbuf); + if (!tx_ctx) { + p2p_err("can't find tx_ctx, tx ack comes late"); + return QDF_STATUS_SUCCESS; + } + + /* disable tx timer */ + p2p_disable_tx_timer(tx_ctx); + tx_cnf.vdev_id = tx_ctx->vdev_id; + tx_cnf.action_cookie = (uint64_t)tx_ctx->id; + tx_cnf.buf = tx_ctx->buf; + tx_cnf.buf_len = tx_ctx->buf_len; + tx_cnf.status = tx_cnf_event->status; + + p2p_debug("soc:%pK, vdev_id:%d, action_cookie:%llx, len:%d, status:%d, buf:%pK", + p2p_soc_obj->soc, tx_cnf.vdev_id, + tx_cnf.action_cookie, tx_cnf.buf_len, + tx_cnf.status, tx_cnf.buf); + + p2p_rand_mac_tx_done(p2p_soc_obj->soc, tx_ctx); + + start_param = p2p_soc_obj->start_param; + if (start_param->tx_cnf_cb) + start_param->tx_cnf_cb(start_param->tx_cnf_cb_data, + &tx_cnf); + else + p2p_debug("Got tx conf, but no valid up layer callback"); + + p2p_remove_tx_context(tx_ctx); + + return QDF_STATUS_SUCCESS; +} + +#define P2P_IS_SOCIAL_CHANNEL(center_freq) \ + (((center_freq) == 2412) || ((center_freq) == 2437) || \ + ((center_freq) == 2462)) + +QDF_STATUS p2p_process_rx_mgmt( + struct p2p_rx_mgmt_event *rx_mgmt_event) +{ + struct p2p_rx_mgmt_frame *rx_mgmt; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_start_param *start_param; + struct p2p_frame_info frame_info; + uint8_t *mac_from; + + p2p_soc_obj = rx_mgmt_event->p2p_soc_obj; + rx_mgmt = rx_mgmt_event->rx_mgmt; + + if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) { + p2p_err("Invalid psoc object or start parameters"); + qdf_mem_free(rx_mgmt); + return QDF_STATUS_E_INVAL; + } + + p2p_debug("soc:%pK, frame_len:%d, rx_freq:%d, vdev_id:%d, frm_type:%d, rx_rssi:%d, buf:%pK", + p2p_soc_obj->soc, rx_mgmt->frame_len, + rx_mgmt->rx_freq, rx_mgmt->vdev_id, rx_mgmt->frm_type, + rx_mgmt->rx_rssi, rx_mgmt->buf); + + if (rx_mgmt->frm_type == MGMT_ACTION_VENDOR_SPECIFIC) { + p2p_get_frame_info(rx_mgmt->buf, rx_mgmt->frame_len, + &frame_info); + + /* update P2P connection status with rx frame info */ + mac_from = &(rx_mgmt->buf[SRC_MAC_ADDR_OFFSET]); + p2p_rx_update_connection_status(p2p_soc_obj, + &frame_info, mac_from); + + p2p_debug("action_sub_type %u, action_type %d", + frame_info.public_action_type, + frame_info.action_type); + + if ((frame_info.public_action_type == + P2P_PUBLIC_ACTION_NOT_SUPPORT) && + (frame_info.action_type == + P2P_ACTION_NOT_SUPPORT)) { + p2p_debug("non-p2p frame, drop it"); + qdf_mem_free(rx_mgmt); + return QDF_STATUS_SUCCESS; + } else { + p2p_debug("p2p frame, extend roc accordingly"); + p2p_extend_roc_timer(p2p_soc_obj, &frame_info); + } + + if (frame_info.public_action_type == + P2P_PUBLIC_ACTION_NEG_REQ && + wlan_reg_is_24ghz_ch_freq(rx_mgmt->rx_freq) && + !P2P_IS_SOCIAL_CHANNEL(rx_mgmt->rx_freq)) { + p2p_debug("Drop P2P Negotiation Req due to non-Social channel: %d", + rx_mgmt->rx_freq); + qdf_mem_free(rx_mgmt); + return QDF_STATUS_SUCCESS; + } + } + + if (rx_mgmt->frm_type == MGMT_ACTION_CATEGORY_VENDOR_SPECIFIC) + p2p_get_frame_info(rx_mgmt->buf, rx_mgmt->frame_len, + &frame_info); + + start_param = p2p_soc_obj->start_param; + if (start_param->rx_cb) + start_param->rx_cb(start_param->rx_cb_data, rx_mgmt); + else + p2p_debug("rx mgmt, but no valid up layer callback"); + + qdf_mem_free(rx_mgmt); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_off_chan_tx.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_off_chan_tx.h new file mode 100644 index 0000000000..9883d7da8c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_off_chan_tx.h @@ -0,0 +1,508 @@ +/* + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Defines off channel tx API & structures + */ + +#ifndef _WLAN_P2P_OFF_CHAN_TX_H_ +#define _WLAN_P2P_OFF_CHAN_TX_H_ + +#include +#include +#include + +#define P2P_EID_VENDOR 0xdd +#define P2P_ACTION_VENDOR_SPECIFIC_CATEGORY 0x7F +#define P2P_PUBLIC_ACTION_FRAME 0x4 +#define P2P_MAC_MGMT_ACTION 0xD +#define P2P_PUBLIC_ACTION_VENDOR_SPECIFIC 0x9 +#define P2P_NOA_ATTR 0xC +#define WNM_ACTION_FRAME 0xA +#define RRM_ACTION_FRAME 0x5 + +#define P2P_MAX_NOA_ATTR_LEN 31 +#define P2P_IE_HEADER_LEN 6 +#define P2P_ACTION_OFFSET 24 +#define P2P_PUBLIC_ACTION_FRAME_TYPE_OFFSET 30 +#define P2P_ACTION_FRAME_TYPE_OFFSET 29 +#define PROBE_RSP_IE_OFFSET 36 + +#define P2P_TX_PKT_MIN_HEADROOM (64) + +#define P2P_OUI "\x50\x6f\x9a\x09" +#define P2P_OUI_SIZE 4 + +#define P2P_ACTION_FRAME_RSP_WAIT 500 +#define P2P_ACTION_FRAME_ACK_WAIT 300 +#define P2P_ACTION_FRAME_TX_TIMEOUT 2000 + +#define DST_MAC_ADDR_OFFSET 4 +#define SRC_MAC_ADDR_OFFSET (DST_MAC_ADDR_OFFSET + QDF_MAC_ADDR_SIZE) + +#define P2P_NOA_STREAM_ARR_SIZE (P2P_MAX_NOA_ATTR_LEN + (2 * P2P_IE_HEADER_LEN)) + +#define P2P_GET_TYPE_FRM_FC(__fc__) (((__fc__) & 0x0F) >> 2) +#define P2P_GET_SUBTYPE_FRM_FC(__fc__) (((__fc__) & 0xF0) >> 4) + +#define WLAN_WAIT_TIME_SET_RND 1000 + +struct p2p_soc_priv_obj; +struct cancel_roc_context; +struct p2p_tx_conf_event; +struct p2p_rx_mgmt_event; + +/** + * enum p2p_frame_type - frame type + * @P2P_FRAME_MGMT: mgmt frame + * @P2P_FRAME_NOT_SUPPORT: not support frame type + */ +enum p2p_frame_type { + P2P_FRAME_MGMT = 0, + P2P_FRAME_NOT_SUPPORT, +}; + +/** + * enum p2p_frame_sub_type - frame sub type + * @P2P_MGMT_PROBE_REQ: probe request frame + * @P2P_MGMT_PROBE_RSP: probe response frame + * @P2P_MGMT_DISASSOC: disassociation frame + * @P2P_MGMT_AUTH: authentication frame + * @P2P_MGMT_DEAUTH: deauthentication frame + * @P2P_MGMT_ACTION: action frame + * @P2P_MGMT_NOT_SUPPORT: not support sub frame type + */ +enum p2p_frame_sub_type { + P2P_MGMT_PROBE_REQ = 4, + P2P_MGMT_PROBE_RSP, + P2P_MGMT_DISASSOC = 10, + P2P_MGMT_AUTH, + P2P_MGMT_DEAUTH, + P2P_MGMT_ACTION, + P2P_MGMT_NOT_SUPPORT, +}; + +/** + * enum p2p_public_action_type - public action frame type + * @P2P_PUBLIC_ACTION_NEG_REQ: go negotiation request frame + * @P2P_PUBLIC_ACTION_NEG_RSP: go negotiation response frame + * @P2P_PUBLIC_ACTION_NEG_CNF: go negotiation confirm frame + * @P2P_PUBLIC_ACTION_INVIT_REQ: p2p invitation request frame + * @P2P_PUBLIC_ACTION_INVIT_RSP: p2p invitation response frame + * @P2P_PUBLIC_ACTION_DEV_DIS_REQ: device discoverability request + * @P2P_PUBLIC_ACTION_DEV_DIS_RSP: device discoverability response + * @P2P_PUBLIC_ACTION_PROV_DIS_REQ: provision discovery request + * @P2P_PUBLIC_ACTION_PROV_DIS_RSP: provision discovery response + * @P2P_PUBLIC_ACTION_GAS_INIT_REQ: gas initial request, + * @P2P_PUBLIC_ACTION_GAS_INIT_RSP: gas initial response + * @P2P_PUBLIC_ACTION_GAS_COMB_REQ: gas comeback request + * @P2P_PUBLIC_ACTION_GAS_COMB_RSP: gas comeback response + * @P2P_PUBLIC_ACTION_WNM_BTM_REQ: bss transition management request + * @P2P_PUBLIC_ACTION_RRM_BEACON_REQ:rrm beacon request + * @P2P_PUBLIC_ACTION_RRM_NEIGHBOR_RSP:rrm neighbor response + * @P2P_PUBLIC_ACTION_NOT_SUPPORT: not support p2p public action frame + */ +enum p2p_public_action_type { + P2P_PUBLIC_ACTION_NEG_REQ = 0, + P2P_PUBLIC_ACTION_NEG_RSP, + P2P_PUBLIC_ACTION_NEG_CNF, + P2P_PUBLIC_ACTION_INVIT_REQ, + P2P_PUBLIC_ACTION_INVIT_RSP, + P2P_PUBLIC_ACTION_DEV_DIS_REQ, + P2P_PUBLIC_ACTION_DEV_DIS_RSP, + P2P_PUBLIC_ACTION_PROV_DIS_REQ, + P2P_PUBLIC_ACTION_PROV_DIS_RSP, + P2P_PUBLIC_ACTION_GAS_INIT_REQ = 10, + P2P_PUBLIC_ACTION_GAS_INIT_RSP, + P2P_PUBLIC_ACTION_GAS_COMB_REQ, + P2P_PUBLIC_ACTION_GAS_COMB_RSP, + P2P_PUBLIC_ACTION_WNM_BTM_REQ, + P2P_PUBLIC_ACTION_RRM_BEACON_REQ, + P2P_PUBLIC_ACTION_RRM_NEIGHBOR_RSP, + P2P_PUBLIC_ACTION_NOT_SUPPORT, +}; + +/** + * enum p2p_action_type - p2p action frame type + * @P2P_ACTION_PRESENCE_REQ: presence request frame + * @P2P_ACTION_PRESENCE_RSP: presence response frame + * @P2P_ACTION_NOT_SUPPORT: not support action frame type + */ +enum p2p_action_type { + P2P_ACTION_PRESENCE_REQ = 1, + P2P_ACTION_PRESENCE_RSP = 2, + P2P_ACTION_NOT_SUPPORT, +}; + +struct p2p_frame_info { + enum p2p_frame_type type; + enum p2p_frame_sub_type sub_type; + enum p2p_public_action_type public_action_type; + enum p2p_action_type action_type; +}; + +/** + * struct tx_action_context - tx action frame context + * @node: Node for next element in the list + * @p2p_soc_obj: Pointer to SoC global p2p private object + * @vdev_id: Vdev id on which this request has come + * @scan_id: Scan id given by scan component for this roc req + * @roc_cookie: Cookie for remain on channel request + * @id: Identifier of this tx context + * @chan_freq: Chan frequency for which this tx has been requested + * @buf: tx buffer + * @buf_len: Length of tx buffer + * @off_chan: Is this off channel tx + * @no_cck: Required cck or not + * @no_ack: Required ack or not + * @rand_mac_tx: Use random MAC address + * @duration: Duration for the RoC + * @tx_timer: RoC timer + * @frame_info: Frame type information + * @nbuf: Network buffer + */ +struct tx_action_context { + qdf_list_node_t node; + struct p2p_soc_priv_obj *p2p_soc_obj; + int vdev_id; + int scan_id; + uint64_t roc_cookie; + int32_t id; + qdf_freq_t chan_freq; + uint8_t *buf; + int buf_len; + bool off_chan; + bool no_cck; + bool no_ack; + bool rand_mac_tx; + uint32_t duration; + qdf_mc_timer_t tx_timer; + struct p2p_frame_info frame_info; + qdf_nbuf_t nbuf; +}; + +/** + * p2p_get_frame_info() - get frame information from packet + * @data_buf: data buffer address + * @length: buffer length + * @frame_info: frame information + * + * This function gets frame information from packet. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_get_frame_info(uint8_t *data_buf, uint32_t length, + struct p2p_frame_info *frame_info); + +/** + * p2p_is_action_frame_of_p2p_type() - Given action frame is p2p type or not + * @data_buf: data buffer address + * @length: buffer length + * + * Return: bool + */ +bool p2p_is_action_frame_of_p2p_type(uint8_t *data_buf, uint32_t length); + +/** + * p2p_rand_mac_tx_done() - process random mac mgmt tx done + * @soc: soc + * @tx_ctx: tx context + * + * This function will remove the random mac addr filter reference. + * + * Return: void + */ +void +p2p_rand_mac_tx_done(struct wlan_objmgr_psoc *soc, + struct tx_action_context *tx_ctx); + +/** + * p2p_clear_mac_filter() - send clear mac addr filter cmd + * @soc: soc + * @vdev_id: vdev id + * @mac: mac addr + * @freq: freq + * + * This function send clear random mac addr filter command to p2p component + * msg core + * + * Return: QDF_STATUS_SUCCESS - if sent successfully. + * otherwise: failed. + */ +QDF_STATUS +p2p_clear_mac_filter(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *mac, uint32_t freq); + +/** + * p2p_is_vdev_support_rand_mac() - check vdev type support random mac mgmt + * tx or not + * @vdev: vdev object + * + * Return: true: support random mac mgmt tx + * false: not support random mac mgmt tx. + */ +bool +p2p_is_vdev_support_rand_mac(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_dump_tx_queue() - dump tx queue + * @p2p_soc_obj: p2p soc private object + * + * This function dumps tx queue and output details about tx context in + * queue. + * + * Return: None + */ +void p2p_dump_tx_queue(struct p2p_soc_priv_obj *p2p_soc_obj); + +/** + * p2p_ready_to_tx_frame() - dump tx queue + * @p2p_soc_obj: p2p soc private object + * @cookie: cookie is pointer to roc + * + * This function find out the tx context in wait for roc queue and tx + * this frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_ready_to_tx_frame(struct p2p_soc_priv_obj *p2p_soc_obj, + uint64_t cookie); + +/** + * p2p_cleanup_tx_sync() - Cleanup tx queue + * @p2p_soc_obj: p2p psoc private object + * @vdev: vdev object + * + * This function cleanup tx context in queue until cancellation done. + * To avoid deadlock, don't call from scheduler thread. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_cleanup_tx_sync( + struct p2p_soc_priv_obj *p2p_soc_obj, + struct wlan_objmgr_vdev *vdev); + +/** + * p2p_process_cleanup_tx_queue() - process the message to cleanup tx + * @param: pointer to cleanup parameters + * + * This function cleanup wait for roc queue and wait for ack queue. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_cleanup_tx_queue( + struct p2p_cleanup_param *param); + +/** + * p2p_process_mgmt_tx() - Process mgmt frame tx request + * @tx_ctx: tx context + * + * This function handles mgmt frame tx request. It will call API from + * mgmt txrx component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_mgmt_tx(struct tx_action_context *tx_ctx); + +/** + * p2p_process_mgmt_tx_cancel() - Process cancel mgmt frame tx request + * @cancel_tx: cancel tx context + * + * This function cancel mgmt frame tx request by cookie. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_mgmt_tx_cancel( + struct cancel_roc_context *cancel_tx); + +/** + * p2p_process_mgmt_tx_ack_cnf() - Process tx ack event + * @tx_cnf_event: tx confirmation event information + * + * This function mgmt frame tx confirmation. It will deliver this + * event to up layer + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_mgmt_tx_ack_cnf( + struct p2p_tx_conf_event *tx_cnf_event); + +/** + * p2p_process_rx_mgmt() - Process rx mgmt frame event + * @rx_mgmt_event: rx mgmt frame event information + * + * This function mgmt frame rx mgmt frame event. It will deliver this + * event to up layer + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_rx_mgmt( + struct p2p_rx_mgmt_event *rx_mgmt_event); + +/** + * p2p_find_tx_ctx_by_nbuf() - find tx context by nbuf + * @p2p_soc_obj: p2p soc object + * @nbuf: pointer to nbuf + * + * This function finds out tx context by nbuf. + * + * Return: pointer to tx context + */ +struct tx_action_context *p2p_find_tx_ctx_by_nbuf( + struct p2p_soc_priv_obj *p2p_soc_obj, void *nbuf); + +#define P2P_80211_FRM_SA_OFFSET 10 + +/** + * p2p_del_random_mac() - del mac filter from given vdev rand mac list + * @soc: soc object + * @vdev_id: vdev id + * @rnd_cookie: random mac mgmt tx cookie + * + * This function will del the mac addr filter from vdev random mac addr list. + * If there is no reference to mac addr, it will set a clear timer to flush it + * in target finally. + * + * Return: QDF_STATUS_SUCCESS - del successfully. + * other : failed to del the mac address entry. + */ +QDF_STATUS +p2p_del_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint64_t rnd_cookie); + +/** + * p2p_random_mac_handle_tx_done() - del mac filter from given vdev rand mac + * list when mgmt tx done + * @soc: soc object + * @vdev_id: vdev id + * @rnd_cookie: random mac mgmt tx cookie + * @duration: timeout value to flush the addr in target. + * + * This function will del the mac addr filter from vdev random mac addr list + * and also remove the filter from firmware if duration is zero else start + * the timer for that duration. + * + * Return: QDF_STATUS_SUCCESS - del successfully. + * other : failed to del the mac address entry. + */ +QDF_STATUS +p2p_random_mac_handle_tx_done(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint64_t rnd_cookie, uint32_t duration); + +/** + * p2p_check_random_mac() - check random mac addr or not + * @soc: soc context + * @vdev_id: vdev id + * @random_mac_addr: mac addr to be checked + * + * This function check the input addr is random mac addr or not for vdev. + * + * Return: true if addr is random mac address else false. + */ +bool p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr); + +/** + * p2p_process_set_rand_mac() - process the set random mac command + * @set_filter_req: request data + * + * This function will process the set mac addr filter command. + * + * Return: QDF_STATUS_SUCCESS: if process successfully + * other: failed. + */ +QDF_STATUS p2p_process_set_rand_mac( + struct p2p_set_mac_filter_req *set_filter_req); + +/** + * p2p_process_set_rand_mac_rsp() - process the set random mac response + * @resp: response date + * + * This function will process the set mac addr filter event. + * + * Return: QDF_STATUS_SUCCESS: if process successfully + * other: failed. + */ +QDF_STATUS p2p_process_set_rand_mac_rsp(struct p2p_mac_filter_rsp *resp); + +/** + * p2p_del_all_rand_mac_vdev() - del all random mac filter in vdev + * @vdev: vdev object + * + * This function will del all random mac filter in vdev + * + * Return: void + */ +void p2p_del_all_rand_mac_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * p2p_del_all_rand_mac_soc() - del all random mac filter in soc + * @soc: soc object + * + * This function will del all random mac filter in all vdev of soc + * + * Return: void + */ +void p2p_del_all_rand_mac_soc(struct wlan_objmgr_psoc *soc); + +/** + * p2p_rand_mac_tx() - handle random mac mgmt tx + * @pdev: pdev object + * @tx_action: tx action context + * + * This function will check whether need to set random mac tx filter for a + * given mgmt tx request and do the mac addr filter process as needed. + * + * Return: void + */ +void p2p_rand_mac_tx(struct wlan_objmgr_pdev *pdev, + struct tx_action_context *tx_action); + +/** + * p2p_init_random_mac_vdev() - Init random mac data for vdev + * @p2p_vdev_obj: p2p vdev private object + * + * This function will init the per vdev random mac data structure. + * + * Return: void + */ +void p2p_init_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj); + +/** + * p2p_deinit_random_mac_vdev() - Init random mac data for vdev + * @p2p_vdev_obj: p2p vdev private object + * + * This function will deinit the per vdev random mac data structure. + * + * Return: void + */ +void p2p_deinit_random_mac_vdev(struct p2p_vdev_priv_obj *p2p_vdev_obj); + +/** + * p2p_get_p2pie_ptr() - get the pointer to p2p ie + * @ie: source ie + * @ie_len: source ie length + * + * This function finds out p2p ie by p2p oui and return the pointer. + * + * Return: pointer to p2p ie + */ +const uint8_t *p2p_get_p2pie_ptr(const uint8_t *ie, uint16_t ie_len); + +#endif /* _WLAN_P2P_OFF_CHAN_TX_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_roc.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_roc.c new file mode 100644 index 0000000000..d72807e9d5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_roc.c @@ -0,0 +1,1001 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains RoC API definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_tgt_api.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_p2p_roc.h" +#include "wlan_p2p_main.h" +#include "wlan_p2p_off_chan_tx.h" + +/** + * p2p_mgmt_rx_ops() - register or unregister rx callback + * @psoc: psoc object + * @isregister: register if true, unregister if false + * + * This function registers or unregisters rx callback to mgmt txrx + * component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, + bool isregister) +{ + struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info; + QDF_STATUS status; + + p2p_debug("psoc:%pK, is register rx:%d", psoc, isregister); + + frm_cb_info.frm_type = MGMT_PROBE_REQ; + frm_cb_info.mgmt_rx_cb = tgt_p2p_mgmt_frame_rx_cb; + + if (isregister) + status = wlan_mgmt_txrx_register_rx_cb(psoc, + WLAN_UMAC_COMP_P2P, &frm_cb_info, 1); + else + status = wlan_mgmt_txrx_deregister_rx_cb(psoc, + WLAN_UMAC_COMP_P2P, &frm_cb_info, 1); + + return status; +} + +/** + * p2p_scan_start() - Start scan + * @roc_ctx: remain on channel request + * + * This function trigger a start scan request to scan component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_scan_start(struct p2p_roc_context *roc_ctx) +{ + QDF_STATUS status; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + uint32_t go_num; + uint8_t ndp_num = 0, nan_disc_enabled_num = 0; + struct wlan_objmgr_pdev *pdev; + bool is_dbs; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + p2p_soc_obj->soc, roc_ctx->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + + wlan_scan_init_default_params(vdev, req); + + if (!roc_ctx->duration) { + roc_ctx->duration = P2P_ROC_DEFAULT_DURATION; + p2p_debug("use default duration %d", + P2P_ROC_DEFAULT_DURATION); + } + + pdev = wlan_vdev_get_pdev(vdev); + roc_ctx->scan_id = wlan_scan_get_scan_id(p2p_soc_obj->soc); + req->vdev = vdev; + req->scan_req.scan_id = roc_ctx->scan_id; + req->scan_req.scan_type = SCAN_TYPE_P2P_LISTEN; + req->scan_req.scan_req_id = p2p_soc_obj->scan_req_id; + req->scan_req.chan_list.num_chan = 1; + req->scan_req.chan_list.chan[0].freq = roc_ctx->chan_freq; + req->scan_req.dwell_time_passive = roc_ctx->duration; + req->scan_req.dwell_time_active = 0; + req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; + req->scan_req.num_bssid = 1; + qdf_set_macaddr_broadcast(&req->scan_req.bssid_list[0]); + + if (req->scan_req.dwell_time_passive < P2P_MAX_ROC_DURATION) { + go_num = policy_mgr_mode_specific_connection_count( + p2p_soc_obj->soc, PM_P2P_GO_MODE, NULL); + policy_mgr_mode_specific_num_active_sessions(p2p_soc_obj->soc, + QDF_NDI_MODE, + &ndp_num); + policy_mgr_mode_specific_num_active_sessions(p2p_soc_obj->soc, + QDF_NAN_DISC_MODE, + &nan_disc_enabled_num); + p2p_debug("present go number:%d, NDP number:%d, NAN number:%d", + go_num, ndp_num, nan_disc_enabled_num); + + is_dbs = policy_mgr_is_hw_dbs_capable(p2p_soc_obj->soc); + /* Modify the ROC duration only for P2P modes */ + if (opmode == QDF_P2P_DEVICE_MODE || + opmode == QDF_P2P_CLIENT_MODE || + opmode == QDF_P2P_GO_MODE) { + if (go_num) + /* Check any P2P GO is already present or not. If it's + * present then add fixed ROC timer value by 300ms + * instead of multiplying with const value which may + * lead ROC timer to become 1.5sec. So, in this case fw + * will advertize NOA for 1.5 secs and if supplicant + * wants to cancel the ROC after 200 or 300ms then fw + * can not cancel NOA as ROC is already set to 1.5sec. + * And if supplicant sends the next ROC then it might + * delay as firmware is already running the presvious + * NOA. This may cause the P2P find issue because P2P GO + * is already present. + * To fix this, add fixed 300ms duration to ROC and + * later check if max limit reaches to 600ms then set + * max ROC duartion as 600ms only. + */ + req->scan_req.dwell_time_passive += + P2P_ROC_DURATION_MULTI_GO_PRESENT; + else + req->scan_req.dwell_time_passive *= + P2P_ROC_DURATION_MULTI_GO_ABSENT; + } + /* this is to protect too huge value if some customers + * give a higher value from supplicant + */ + if (go_num && req->scan_req.dwell_time_passive > + P2P_MAX_ROC_DURATION_GO_PRESENT) { + req->scan_req.dwell_time_passive = + P2P_MAX_ROC_DURATION_GO_PRESENT; + } else if (ndp_num) { + if (is_dbs && req->scan_req.dwell_time_passive > + P2P_MAX_ROC_DURATION_DBS_NDP_PRESENT) + req->scan_req.dwell_time_passive = + P2P_MAX_ROC_DURATION_DBS_NDP_PRESENT; + else if (!is_dbs && req->scan_req.dwell_time_passive > + P2P_MAX_ROC_DURATION_NON_DBS_NDP_PRESENT) + req->scan_req.dwell_time_passive = + P2P_MAX_ROC_DURATION_NON_DBS_NDP_PRESENT; + } else if (nan_disc_enabled_num) { + if (is_dbs && req->scan_req.dwell_time_passive > + P2P_MAX_ROC_DURATION_DBS_NAN_PRESENT) + req->scan_req.dwell_time_passive = + P2P_MAX_ROC_DURATION_DBS_NAN_PRESENT; + else if (!is_dbs && req->scan_req.dwell_time_passive > + P2P_MAX_ROC_DURATION_NON_DBS_NAN_PRESENT) + req->scan_req.dwell_time_passive = + P2P_MAX_ROC_DURATION_NON_DBS_NAN_PRESENT; + } else if (req->scan_req.dwell_time_passive > + P2P_MAX_ROC_DURATION) { + req->scan_req.dwell_time_passive = P2P_MAX_ROC_DURATION; + } + } + p2p_debug("FW requested roc duration is:%d", + req->scan_req.dwell_time_passive); + + status = wlan_scan_start(req); + + p2p_debug("start scan, scan req id:%d, scan id:%d, status:%d", + p2p_soc_obj->scan_req_id, roc_ctx->scan_id, status); +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return status; +} + +/** + * p2p_roc_abort() - Abort roc + * @roc_ctx: remain on channel request + * + * This function triggers an abort scan request to scan component to abort the + * ROC request which is running through roc_ctx. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_roc_abort(struct p2p_roc_context *roc_ctx) +{ + QDF_STATUS status; + struct scan_cancel_request *req; + struct wlan_objmgr_vdev *vdev; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("abort scan, scan req id:%d, scan id:%d", + p2p_soc_obj->scan_req_id, roc_ctx->scan_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + p2p_soc_obj->soc, roc_ctx->vdev_id, + WLAN_P2P_ID); + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + + req->vdev = vdev; + req->cancel_req.requester = p2p_soc_obj->scan_req_id; + req->cancel_req.scan_id = roc_ctx->scan_id; + req->cancel_req.vdev_id = roc_ctx->vdev_id; + req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE; + + qdf_mtrace(QDF_MODULE_ID_P2P, QDF_MODULE_ID_SCAN, + req->cancel_req.req_type, + req->vdev->vdev_objmgr.vdev_id, req->cancel_req.scan_id); + status = wlan_scan_cancel(req); + + p2p_debug("abort scan, scan req id:%d, scan id:%d, status:%d", + p2p_soc_obj->scan_req_id, roc_ctx->scan_id, status); +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + + return status; +} + +/** + * p2p_send_roc_event() - Send roc event + * @roc_ctx: remain on channel request + * @evt: roc event information + * + * This function send out roc event to up layer. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_send_roc_event( + struct p2p_roc_context *roc_ctx, enum p2p_roc_event evt) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_event p2p_evt; + struct p2p_start_param *start_param; + + p2p_soc_obj = roc_ctx->p2p_soc_obj; + if (!p2p_soc_obj || !(p2p_soc_obj->start_param)) { + p2p_err("Invalid p2p soc object or start parameters"); + return QDF_STATUS_E_INVAL; + } + start_param = p2p_soc_obj->start_param; + if (!(start_param->event_cb)) { + p2p_err("Invalid p2p event callback to up layer"); + return QDF_STATUS_E_INVAL; + } + + p2p_evt.vdev_id = roc_ctx->vdev_id; + p2p_evt.roc_event = evt; + p2p_evt.cookie = (uint64_t)roc_ctx->id; + p2p_evt.chan_freq = roc_ctx->chan_freq; + p2p_evt.duration = roc_ctx->duration; + + p2p_debug("roc_event: %d, cookie:%llx", p2p_evt.roc_event, + p2p_evt.cookie); + + start_param->event_cb(start_param->event_cb_data, &p2p_evt); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_destroy_roc_ctx() - destroy roc ctx + * @roc_ctx: remain on channel request + * @up_layer_event: if send uplayer event + * @in_roc_queue: if roc context in roc queue + * + * This function destroy roc context. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_destroy_roc_ctx(struct p2p_roc_context *roc_ctx, + bool up_layer_event, bool in_roc_queue) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("p2p_soc_obj:%pK, roc_ctx:%pK, up_layer_event:%d," + " in_roc_queue:%d vdev_id:%d freq:%d duration:%d", + p2p_soc_obj, roc_ctx, up_layer_event, in_roc_queue, + roc_ctx->vdev_id, roc_ctx->chan_freq, roc_ctx->duration); + + if (up_layer_event) { + if (roc_ctx->roc_state < ROC_STATE_ON_CHAN) + p2p_send_roc_event(roc_ctx, ROC_EVENT_READY_ON_CHAN); + p2p_send_roc_event(roc_ctx, ROC_EVENT_COMPLETED); + } + + if (in_roc_queue) { + status = qdf_list_remove_node(&p2p_soc_obj->roc_q, + (qdf_list_node_t *)roc_ctx); + if (QDF_STATUS_SUCCESS != status) + p2p_err("Failed to remove roc req, status %d", status); + } + + qdf_idr_remove(&p2p_soc_obj->p2p_idr, roc_ctx->id); + qdf_mem_free(roc_ctx); + + return status; +} + +/** + * p2p_execute_cancel_roc_req() - Execute cancel roc request + * @roc_ctx: remain on channel request + * + * This function stop roc timer, abort scan and unregister mgmt rx + * callback. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_execute_cancel_roc_req( + struct p2p_roc_context *roc_ctx) +{ + QDF_STATUS status; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("p2p execute cancel roc req"); + + roc_ctx->roc_state = ROC_STATE_CANCEL_IN_PROG; + + status = qdf_mc_timer_stop_sync(&roc_ctx->roc_timer); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to stop roc timer, roc %pK", roc_ctx); + + status = p2p_roc_abort(roc_ctx); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to abort scan, status:%d, destroy roc %pK", + status, roc_ctx); + qdf_mc_timer_destroy(&roc_ctx->roc_timer); + p2p_mgmt_rx_ops(p2p_soc_obj->soc, false); + p2p_destroy_roc_ctx(roc_ctx, true, true); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_roc_timeout() - Callback for roc timeout + * @pdata: pointer to p2p soc private object + * + * This function is callback for roc time out. + * + * Return: None + */ +static void p2p_roc_timeout(void *pdata) +{ + struct p2p_roc_context *roc_ctx; + struct p2p_soc_priv_obj *p2p_soc_obj; + + p2p_debug("p2p soc obj:%pK", pdata); + + p2p_soc_obj = pdata; + if (!p2p_soc_obj) { + p2p_err("Invalid p2p soc object"); + return; + } + + roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); + if (!roc_ctx) { + p2p_debug("No P2P roc is pending"); + return; + } + + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d," + " tx ctx:%pK, freq:%d, phy_mode:%d, duration:%d," + " roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + + if (roc_ctx->roc_state == ROC_STATE_CANCEL_IN_PROG) { + p2p_err("Cancellation already in progress"); + return; + } + p2p_execute_cancel_roc_req(roc_ctx); +} + +/** + * p2p_execute_roc_req() - Execute roc request + * @roc_ctx: remain on channel request + * + * This function init roc timer, start scan and register mgmt rx + * callback. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_execute_roc_req(struct p2p_roc_context *roc_ctx) +{ + QDF_STATUS status; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d," + " tx ctx:%pK, freq:%d, phy_mode:%d, duration:%d," + " roc_type:%d, roc_state:%d", + p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + + /* prevent runtime suspend */ + qdf_runtime_pm_prevent_suspend(&p2p_soc_obj->roc_runtime_lock); + + status = qdf_mc_timer_init(&roc_ctx->roc_timer, + QDF_TIMER_TYPE_SW, p2p_roc_timeout, + p2p_soc_obj); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("failed to init roc timer, status:%d", status); + goto fail; + } + + roc_ctx->roc_state = ROC_STATE_REQUESTED; + status = p2p_scan_start(roc_ctx); + if (status != QDF_STATUS_SUCCESS) { + qdf_mc_timer_destroy(&roc_ctx->roc_timer); + p2p_err("Failed to start scan, status:%d", status); + goto fail; + } + +fail: + if (status != QDF_STATUS_SUCCESS) { + p2p_destroy_roc_ctx(roc_ctx, true, true); + qdf_runtime_pm_allow_suspend( + &p2p_soc_obj->roc_runtime_lock); + return status; + } + + p2p_soc_obj->cur_roc_vdev_id = roc_ctx->vdev_id; + status = p2p_mgmt_rx_ops(p2p_soc_obj->soc, true); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to register mgmt rx callback, status:%d", + status); + + return status; +} + +/** + * p2p_find_roc_ctx() - Find out roc context by cookie + * @p2p_soc_obj: p2p psoc private object + * @cookie: cookie is the key to find out roc context + * + * This function find out roc context by cookie from p2p psoc private + * object + * + * Return: Pointer to roc context - success + * NULL - failure + */ +static struct p2p_roc_context *p2p_find_roc_ctx( + struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie) +{ + struct p2p_roc_context *curr_roc_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + p2p_debug("p2p soc obj:%pK, cookie:%llx", p2p_soc_obj, cookie); + + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_roc_ctx = qdf_container_of(p_node, + struct p2p_roc_context, node); + if ((uintptr_t) curr_roc_ctx == cookie) + return curr_roc_ctx; + status = qdf_list_peek_next(&p2p_soc_obj->roc_q, + p_node, &p_node); + } + + return NULL; +} + +/** + * p2p_process_scan_start_evt() - Process scan start event + * @roc_ctx: remain on channel request + * + * This function process scan start event. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_process_scan_start_evt( + struct p2p_roc_context *roc_ctx) +{ + roc_ctx->roc_state = ROC_STATE_STARTED; + p2p_debug("scan started, scan id:%d", roc_ctx->scan_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * p2p_process_ready_on_channel_evt() - Process ready on channel event + * @roc_ctx: remain on channel request + * + * This function process ready on channel event. Starts roc timer. + * Indicates this event to up layer if this is user request roc. Sends + * mgmt frame if this is off channel rx roc. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_process_ready_on_channel_evt( + struct p2p_roc_context *roc_ctx) +{ + uint64_t cookie; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + p2p_soc_obj = roc_ctx->p2p_soc_obj; + roc_ctx->roc_state = ROC_STATE_ON_CHAN; + + p2p_debug("scan_id:%d, roc_state:%d", roc_ctx->scan_id, + roc_ctx->roc_state); + + status = qdf_mc_timer_start(&roc_ctx->roc_timer, + (roc_ctx->duration + P2P_EVENT_PROPAGATE_TIME)); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Remain on Channel timer start failed"); + if (roc_ctx->roc_type == USER_REQUESTED) { + p2p_debug("user required roc, send roc event"); + status = p2p_send_roc_event(roc_ctx, + ROC_EVENT_READY_ON_CHAN); + } + + cookie = (uintptr_t)roc_ctx; + /* ready to tx frame */ + p2p_ready_to_tx_frame(p2p_soc_obj, cookie); + + return status; +} + +/** + * p2p_process_scan_complete_evt() - Process scan complete event + * @roc_ctx: remain on channel request + * + * This function process scan complete event. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS p2p_process_scan_complete_evt( + struct p2p_roc_context *roc_ctx) +{ + QDF_STATUS status; + qdf_list_node_t *next_node; + uint32_t size; + struct p2p_soc_priv_obj *p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("vdev_id:%d scan_id:%d", roc_ctx->vdev_id, roc_ctx->scan_id); + + /* allow runtime suspend */ + qdf_runtime_pm_allow_suspend(&p2p_soc_obj->roc_runtime_lock); + + + status = qdf_mc_timer_stop_sync(&roc_ctx->roc_timer); + if (QDF_IS_STATUS_ERROR(status)) + p2p_err("Failed to stop roc timer"); + + status = qdf_mc_timer_destroy(&roc_ctx->roc_timer); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to destroy roc timer"); + + status = p2p_mgmt_rx_ops(p2p_soc_obj->soc, false); + p2p_soc_obj->cur_roc_vdev_id = P2P_INVALID_VDEV_ID; + if (status != QDF_STATUS_SUCCESS) + p2p_err("Failed to deregister mgmt rx callback"); + + if (roc_ctx->roc_type == USER_REQUESTED) + status = p2p_send_roc_event(roc_ctx, + ROC_EVENT_COMPLETED); + + p2p_destroy_roc_ctx(roc_ctx, false, true); + qdf_event_set(&p2p_soc_obj->cleanup_roc_done); + + size = qdf_list_size(&p2p_soc_obj->roc_q); + + if (size > 0) { + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, + &next_node); + if (QDF_STATUS_SUCCESS != status) { + p2p_err("Failed to peek roc req from front, status %d", + status); + return status; + } + roc_ctx = qdf_container_of(next_node, + struct p2p_roc_context, node); + status = p2p_execute_roc_req(roc_ctx); + } + return status; +} + +QDF_STATUS p2p_mgmt_rx_action_ops(struct wlan_objmgr_psoc *psoc, + bool isregister) +{ + struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info[2]; + QDF_STATUS status; + + p2p_debug("psoc:%pK, is register rx:%d", psoc, isregister); + + frm_cb_info[0].frm_type = MGMT_ACTION_VENDOR_SPECIFIC; + frm_cb_info[0].mgmt_rx_cb = tgt_p2p_mgmt_frame_rx_cb; + frm_cb_info[1].frm_type = MGMT_ACTION_CATEGORY_VENDOR_SPECIFIC; + frm_cb_info[1].mgmt_rx_cb = tgt_p2p_mgmt_frame_rx_cb; + + if (isregister) + status = wlan_mgmt_txrx_register_rx_cb(psoc, + WLAN_UMAC_COMP_P2P, frm_cb_info, 2); + else + status = wlan_mgmt_txrx_deregister_rx_cb(psoc, + WLAN_UMAC_COMP_P2P, frm_cb_info, 2); + + return status; +} + +struct p2p_roc_context *p2p_find_current_roc_ctx( + struct p2p_soc_priv_obj *p2p_soc_obj) +{ + struct p2p_roc_context *roc_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + roc_ctx = qdf_container_of(p_node, + struct p2p_roc_context, node); + if (roc_ctx->roc_state != ROC_STATE_IDLE) { + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id" + ":%d, scan_id:%d, tx ctx:%pK, freq:" + "%d, phy_mode:%d, duration:%d, " + "roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, + roc_ctx->vdev_id, roc_ctx->scan_id, + roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + + return roc_ctx; + } + status = qdf_list_peek_next(&p2p_soc_obj->roc_q, + p_node, &p_node); + } + + return NULL; +} + +struct p2p_roc_context *p2p_find_roc_by_tx_ctx( + struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie) +{ + struct p2p_roc_context *curr_roc_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + p2p_debug("p2p soc obj:%pK, cookie:%llx", p2p_soc_obj, cookie); + + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_roc_ctx = qdf_container_of(p_node, + struct p2p_roc_context, node); + if ((uintptr_t) curr_roc_ctx->tx_ctx == cookie) + return curr_roc_ctx; + status = qdf_list_peek_next(&p2p_soc_obj->roc_q, + p_node, &p_node); + } + + return NULL; +} + +struct p2p_roc_context *p2p_find_roc_by_chan_freq( + struct p2p_soc_priv_obj *p2p_soc_obj, qdf_freq_t chan_freq) +{ + struct p2p_roc_context *roc_ctx; + qdf_list_node_t *p_node; + QDF_STATUS status; + + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + roc_ctx = qdf_container_of(p_node, + struct p2p_roc_context, + node); + if (roc_ctx->chan_freq == chan_freq) { + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d," + " scan_id:%d, tx ctx:%pK, freq:%d," + " phy_mode:%d, duration:%d," + " roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, + roc_ctx->vdev_id, roc_ctx->scan_id, + roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + + return roc_ctx; + } + status = qdf_list_peek_next(&p2p_soc_obj->roc_q, + p_node, &p_node); + } + + return NULL; +} + +QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&roc_ctx->roc_timer)) { + p2p_debug("roc restart duration:%d", roc_ctx->duration); + status = qdf_mc_timer_stop_sync(&roc_ctx->roc_timer); + if (status != QDF_STATUS_SUCCESS) { + p2p_err("Failed to stop roc timer"); + return status; + } + + status = qdf_mc_timer_start(&roc_ctx->roc_timer, + roc_ctx->duration); + if (status != QDF_STATUS_SUCCESS) + p2p_err("Remain on Channel timer start failed"); + } + + return status; +} + +QDF_STATUS p2p_cleanup_roc(struct p2p_soc_priv_obj *p2p_soc_obj, + struct wlan_objmgr_vdev *vdev, + bool sync) +{ + struct scheduler_msg msg = {0}; + struct p2p_cleanup_param *param; + QDF_STATUS status; + uint32_t vdev_id; + + if (!p2p_soc_obj) { + p2p_err("p2p soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + p2p_debug("p2p_soc_obj:%pK, vdev:%pK, sync:%d", p2p_soc_obj, vdev, + sync); + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_NOMEM; + + param->p2p_soc_obj = p2p_soc_obj; + if (vdev) + vdev_id = (uint32_t)wlan_vdev_get_id(vdev); + else + vdev_id = P2P_INVALID_VDEV_ID; + param->vdev_id = vdev_id; + qdf_event_reset(&p2p_soc_obj->cleanup_roc_done); + msg.type = P2P_CLEANUP_ROC; + msg.bodyptr = param; + msg.callback = p2p_process_cmd; + status = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, &msg); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(param); + return status; + } + + if (!sync) + return status; + + status = qdf_wait_single_event( + &p2p_soc_obj->cleanup_roc_done, + P2P_WAIT_CLEANUP_ROC); + + if (status != QDF_STATUS_SUCCESS) + p2p_err("wait for cleanup roc timeout, %d", status); + + return status; +} + +QDF_STATUS p2p_process_cleanup_roc_queue( + struct p2p_cleanup_param *param) +{ + uint32_t vdev_id; + uint8_t count = 0; + QDF_STATUS status, ret; + struct p2p_roc_context *roc_ctx; + qdf_list_node_t *p_node; + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!param || !(param->p2p_soc_obj)) { + p2p_err("Invalid cleanup param"); + return QDF_STATUS_E_FAILURE; + } + + p2p_soc_obj = param->p2p_soc_obj; + vdev_id = param->vdev_id; + + p2p_debug("clean up idle roc request, roc queue size:%d, vdev id:%d", + qdf_list_size(&p2p_soc_obj->roc_q), vdev_id); + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + roc_ctx = qdf_container_of(p_node, + struct p2p_roc_context, node); + + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, " + "scan_id:%d, tx ctx:%pK, freq:%d, phy_mode:%d, " + "duration:%d, roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, + roc_ctx->vdev_id, roc_ctx->scan_id, + roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + status = qdf_list_peek_next(&p2p_soc_obj->roc_q, + p_node, &p_node); + if ((roc_ctx->roc_state == ROC_STATE_IDLE) && + ((vdev_id == P2P_INVALID_VDEV_ID) || + (vdev_id == roc_ctx->vdev_id))) { + ret = qdf_list_remove_node( + &p2p_soc_obj->roc_q, + (qdf_list_node_t *)roc_ctx); + if (ret == QDF_STATUS_SUCCESS) + qdf_mem_free(roc_ctx); + else + p2p_err("Failed to remove roc ctx from queue"); + } + } + + p2p_debug("clean up started roc request, roc queue size:%d", + qdf_list_size(&p2p_soc_obj->roc_q)); + status = qdf_list_peek_front(&p2p_soc_obj->roc_q, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + roc_ctx = qdf_container_of(p_node, + struct p2p_roc_context, node); + + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, " + "scan_id:%d, tx ctx:%pK, freq:%d, phy_mode:%d, " + "duration:%d, roc_type:%d, roc_state:%d", + roc_ctx->p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + + status = qdf_list_peek_next(&p2p_soc_obj->roc_q, + p_node, &p_node); + if ((roc_ctx->roc_state != ROC_STATE_IDLE) && + ((vdev_id == P2P_INVALID_VDEV_ID) || + (vdev_id == roc_ctx->vdev_id))) { + if (roc_ctx->roc_state != + ROC_STATE_CANCEL_IN_PROG) + p2p_execute_cancel_roc_req(roc_ctx); + + count++; + } + } + + p2p_debug("count %d", count); + if (!count) + qdf_event_set(&p2p_soc_obj->cleanup_roc_done); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *curr_roc_ctx; + QDF_STATUS status; + uint32_t size; + + p2p_soc_obj = roc_ctx->p2p_soc_obj; + + p2p_debug("p2p soc obj:%pK, roc ctx:%pK, vdev_id:%d, scan_id:%d, " + "tx_ctx:%pK, freq:%d, phy_mode:%d, duration:%d, " + "roc_type:%d, roc_state:%d", + p2p_soc_obj, roc_ctx, roc_ctx->vdev_id, + roc_ctx->scan_id, roc_ctx->tx_ctx, roc_ctx->chan_freq, + roc_ctx->phy_mode, roc_ctx->duration, + roc_ctx->roc_type, roc_ctx->roc_state); + + status = qdf_list_insert_back(&p2p_soc_obj->roc_q, + &roc_ctx->node); + if (QDF_STATUS_SUCCESS != status) { + p2p_destroy_roc_ctx(roc_ctx, true, false); + p2p_debug("Failed to insert roc req, status %d", status); + return status; + } + + size = qdf_list_size(&p2p_soc_obj->roc_q); + if (size == 1) { + status = p2p_execute_roc_req(roc_ctx); + } else if (size > 1) { + curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); + /*TODO, to handle extend roc */ + } + + return status; +} + +QDF_STATUS p2p_process_cancel_roc_req( + struct cancel_roc_context *cancel_roc_ctx) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *curr_roc_ctx; + QDF_STATUS status; + + p2p_soc_obj = cancel_roc_ctx->p2p_soc_obj; + curr_roc_ctx = p2p_find_roc_ctx(p2p_soc_obj, + cancel_roc_ctx->cookie); + + if (!curr_roc_ctx) { + p2p_debug("Failed to find roc req by cookie, cookie %llx", + cancel_roc_ctx->cookie); + return QDF_STATUS_E_INVAL; + } + + p2p_debug("roc ctx:%pK vdev_id:%d, scan_id:%d, roc_type:%d, roc_state:%d", + curr_roc_ctx, curr_roc_ctx->vdev_id, curr_roc_ctx->scan_id, + curr_roc_ctx->roc_type, curr_roc_ctx->roc_state); + + if (curr_roc_ctx->roc_state == ROC_STATE_IDLE) { + status = p2p_destroy_roc_ctx(curr_roc_ctx, true, true); + } else if (curr_roc_ctx->roc_state == + ROC_STATE_CANCEL_IN_PROG) { + p2p_debug("Receive cancel roc req when roc req is canceling, cookie %llx", + cancel_roc_ctx->cookie); + status = QDF_STATUS_SUCCESS; + } else { + status = p2p_execute_cancel_roc_req(curr_roc_ctx); + } + + return status; +} + +void p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *curr_roc_ctx; + + p2p_debug("soc:%pK, scan event:%d", arg, event->type); + + p2p_soc_obj = (struct p2p_soc_priv_obj *)arg; + if (!p2p_soc_obj) { + p2p_err("Invalid P2P context"); + return; + } + + curr_roc_ctx = p2p_find_current_roc_ctx(p2p_soc_obj); + if (!curr_roc_ctx) { + p2p_err("Failed to find valid P2P roc context"); + return; + } + + qdf_mtrace(QDF_MODULE_ID_SCAN, QDF_MODULE_ID_P2P, event->type, + event->vdev_id, event->scan_id); + switch (event->type) { + case SCAN_EVENT_TYPE_STARTED: + p2p_process_scan_start_evt(curr_roc_ctx); + break; + case SCAN_EVENT_TYPE_FOREIGN_CHANNEL: + p2p_process_ready_on_channel_evt(curr_roc_ctx); + break; + case SCAN_EVENT_TYPE_COMPLETED: + case SCAN_EVENT_TYPE_DEQUEUED: + case SCAN_EVENT_TYPE_START_FAILED: + p2p_process_scan_complete_evt(curr_roc_ctx); + break; + default: + p2p_debug("drop scan event, %d", event->type); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_roc.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_roc.h new file mode 100644 index 0000000000..5b75b29169 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/core/src/wlan_p2p_roc.h @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Defines RoC API & structures + */ + +#ifndef _WLAN_P2P_ROC_H_ +#define _WLAN_P2P_ROC_H_ + +#include +#include +#include + +#define P2P_EVENT_PROPAGATE_TIME 10 +#define P2P_WAIT_CANCEL_ROC 1000 +#define P2P_WAIT_CLEANUP_ROC 2000 +#define P2P_MAX_ROC_DURATION 1500 +#define P2P_MAX_ROC_DURATION_GO_PRESENT 600 +#define P2P_MAX_ROC_DURATION_DBS_NDP_PRESENT 350 +#define P2P_MAX_ROC_DURATION_NON_DBS_NDP_PRESENT 250 +#define P2P_MAX_ROC_DURATION_DBS_NAN_PRESENT 350 +#define P2P_MAX_ROC_DURATION_NON_DBS_NAN_PRESENT 300 + +#define P2P_ROC_DURATION_MULTI_GO_PRESENT 300 +#define P2P_ROC_DURATION_MULTI_GO_ABSENT 10 +#define P2P_ACTION_FRAME_DEFAULT_WAIT 200 +#define P2P_ROC_DEFAULT_DURATION 200 + +struct wlan_objmgr_vdev; +struct scan_event; + +/** + * enum roc_type - user requested or off channel tx + * @USER_REQUESTED: Requested by supplicant + * @OFF_CHANNEL_TX: Issued internally for off channel tx + */ +enum roc_type { + USER_REQUESTED, + OFF_CHANNEL_TX, +}; + +/** + * enum roc_state - P2P RoC state + * @ROC_STATE_IDLE: RoC not yet started or completed + * @ROC_STATE_REQUESTED: Sent scan command to scan manager + * @ROC_STATE_STARTED: Got started event from scan manager + * @ROC_STATE_ON_CHAN: Got foreign channel event from SCM + * @ROC_STATE_CANCEL_IN_PROG: Requested abort scan to SCM + * @ROC_STATE_INVALID: We should not come to this state + */ +enum roc_state { + ROC_STATE_IDLE = 0, + ROC_STATE_REQUESTED, + ROC_STATE_STARTED, + ROC_STATE_ON_CHAN, + ROC_STATE_CANCEL_IN_PROG, + ROC_STATE_INVALID, +}; + +/** + * struct p2p_roc_context - RoC request context + * @node: Node for next element in the list + * @p2p_soc_obj: Pointer to SoC global p2p private object + * @vdev_id: Vdev id on which this request has come + * @scan_id: Scan id given by scan component for this roc req + * @tx_ctx: TX context if this ROC is for tx MGMT + * @chan_freq: Chan frequency for which this RoC has been requested + * @phy_mode: PHY mode + * @duration: Duration for the RoC + * @roc_type: RoC type User requested or internal + * @roc_timer: RoC timer + * @roc_state: Roc state + * @id: identifier of roc + */ +struct p2p_roc_context { + qdf_list_node_t node; + struct p2p_soc_priv_obj *p2p_soc_obj; + uint32_t vdev_id; + uint32_t scan_id; + void *tx_ctx; + qdf_freq_t chan_freq; + uint8_t phy_mode; + uint32_t duration; + enum roc_type roc_type; + qdf_mc_timer_t roc_timer; + enum roc_state roc_state; + int32_t id; +}; + +/** + * struct cancel_roc_context - p2p cancel roc context + * @p2p_soc_obj: Pointer to SoC global p2p private object + * @cookie: Cookie which is given by supplicant + */ +struct cancel_roc_context { + struct p2p_soc_priv_obj *p2p_soc_obj; + uint64_t cookie; +}; + +/** + * struct p2p_cleanup_param - p2p cleanup parameters + * @p2p_soc_obj: Pointer to SoC global p2p private object + * @vdev_id: vdev id + */ +struct p2p_cleanup_param { + struct p2p_soc_priv_obj *p2p_soc_obj; + uint32_t vdev_id; +}; + +/** + * p2p_mgmt_rx_action_ops() - register or unregister rx action callback + * @psoc: psoc object + * @isregister: register if true, unregister if false + * + * This function registers or unregisters rx action frame callback to + * mgmt txrx component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_mgmt_rx_action_ops(struct wlan_objmgr_psoc *psoc, + bool isregister); + +/** + * p2p_find_current_roc_ctx() - Find out roc context in progressing + * @p2p_soc_obj: p2p psoc private object + * + * This function finds out roc context in progressing from p2p psoc + * private object + * + * Return: Pointer to roc context - success + * NULL - failure + */ +struct p2p_roc_context *p2p_find_current_roc_ctx( + struct p2p_soc_priv_obj *p2p_soc_obj); + +/** + * p2p_find_roc_by_tx_ctx() - Find out roc context by tx context + * @p2p_soc_obj: p2p psoc private object + * @cookie: cookie is the key to find out roc context + * + * This function finds out roc context by tx context from p2p psoc + * private object + * + * Return: Pointer to roc context - success + * NULL - failure + */ +struct p2p_roc_context *p2p_find_roc_by_tx_ctx( + struct p2p_soc_priv_obj *p2p_soc_obj, uint64_t cookie); + +/** + * p2p_find_roc_by_chan_freq() - Find out roc context by channel + * @p2p_soc_obj: p2p psoc private object + * @chan_freq: channel frequency of the ROC + * + * This function finds out roc context by channel from p2p psoc + * private object + * + * Return: Pointer to roc context - success + * NULL - failure + */ +struct p2p_roc_context *p2p_find_roc_by_chan_freq( + struct p2p_soc_priv_obj *p2p_soc_obj, qdf_freq_t chan_freq); + +/** + * p2p_restart_roc_timer() - Restarts roc timer + * @roc_ctx: remain on channel context + * + * This function restarts roc timer with updated duration. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_restart_roc_timer(struct p2p_roc_context *roc_ctx); + +/** + * p2p_cleanup_roc() - Cleanup roc context in queue + * @p2p_soc_obj: p2p psoc private object + * @vdev: vdev object + * @sync: whether to wait for complete event + * + * This function cleanup roc context in queue, include the roc + * context in progressing until cancellation done. To avoid deadlock, + * don't call from scheduler thread. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_cleanup_roc(struct p2p_soc_priv_obj *p2p_soc_obj, + struct wlan_objmgr_vdev *vdev, + bool sync); + +/** + * p2p_process_cleanup_roc_queue() - process the message to cleanup roc + * @param: pointer to cleanup parameters + * + * This function process the message to cleanup roc context in queue, + * include the roc context in progressing. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_cleanup_roc_queue( + struct p2p_cleanup_param *param); + +/** + * p2p_process_roc_req() - Process roc request + * @roc_ctx: roc request context + * + * This function handles roc request. It will call API from scan/mgmt + * txrx component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_roc_req(struct p2p_roc_context *roc_ctx); + +/** + * p2p_process_cancel_roc_req() - Process cancel roc request + * @cancel_roc_ctx: cancel roc request context + * + * This function cancel roc request by cookie. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_process_cancel_roc_req( + struct cancel_roc_context *cancel_roc_ctx); + +/** + * p2p_scan_event_cb() - Process scan event + * @vdev: vdev associated to this scan event + * @event: event information + * @arg: registered arguments + * + * This function handles P2P scan event and deliver P2P event to HDD + * layer by registered callback. + * + * Return: None + */ +void p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); + +#endif /* _WLAN_P2P_ROC_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/cfg_p2p.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/cfg_p2p.h new file mode 100644 index 0000000000..ae79e17d2f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/cfg_p2p.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(CONFIG_P2P_H__) +#define CONFIG_P2P_H__ + +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" + +/* + * + * gGoKeepAlivePeriod - P2P GO keep alive period. + * @Min: 1 + * @Max: 65535 + * @Default: 20 + * + * This is P2P GO keep alive period. + * + * Related: None. + * + * Supported Feature: P2P + * + * Usage: External + * + * + */ +#define CFG_GO_KEEP_ALIVE_PERIOD CFG_INI_UINT( \ + "gGoKeepAlivePeriod", \ + 1, \ + 65535, \ + 20, \ + CFG_VALUE_OR_DEFAULT, \ + "P2P GO keep alive period") + +/* + * + * gGoLinkMonitorPeriod - period where link is idle and where + * we send NULL frame + * @Min: 3 + * @Max: 50 + * @Default: 10 + * + * This is period where link is idle and where we send NULL frame for P2P GO. + * + * Related: None. + * + * Supported Feature: P2P + * + * Usage: External + * + * + */ +#define CFG_GO_LINK_MONITOR_PERIOD CFG_INI_UINT( \ + "gGoLinkMonitorPeriod", \ + 3, \ + 50, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "period where link is idle and where we send NULL frame") + +/* + * + * isP2pDeviceAddrAdministrated - Enables to derive the P2P MAC address from + * the primary MAC address + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable to derive the P2P MAC address from the + * primary MAC address. + * + * Related: None. + * + * Supported Feature: P2P + * + * Usage: External + * + * + */ +#define CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED CFG_INI_BOOL( \ + "isP2pDeviceAddrAdministrated", \ + 1, \ + "derive the P2P MAC address from the primary MAC address") + +/* + * + * action_frame_random_seq_num_enabled - Enables random sequence number + * generation for action frames + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable random sequence number generation for + * action frames. + * + * Related: None. + * + * Supported Feature: P2P + * + * Usage: external + * + * + */ +#define CFG_ACTION_FRAME_RANDOM_SEQ_NUM_ENABLED CFG_INI_BOOL( \ + "action_frame_random_seq_num_enabled", \ + 1, \ + "Enable random seq nums for action frames") + +/* + * + * p2p_go_on_5ghz_indoor_chan - Allow P2P GO to operate on 5 GHz indoor channels + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable P2P-GO operation on 5 GHz + * indoor channels. + * + * Related: sta_sap_scc_on_indoor_channel, gindoor_channel_support + * + * Supported Feature: P2P GO + * + * Usage: external + * + * + */ +#define CFG_P2P_GO_ON_5GHZ_INDOOR_CHANNEL CFG_INI_BOOL(\ + "p2p_go_on_5ghz_indoor_chan", \ + 0, \ + "Allow P2P GO on 5 GHz indoor channels") + +/* + * + * p2p_go_ignore_non_p2p_probe_req - P2P GO ignore non-P2P probe req + * + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable P2P GO ignore non-P2P probe req and don't + * send probe rsp to non-p2p device like STA. + * + * + * Supported Feature: P2P GO + * + * Usage: external + * + * + */ +#define CFG_GO_IGNORE_NON_P2P_PROBE_REQ CFG_INI_BOOL(\ + "go_ignore_non_p2p_probe_req", \ + 0, \ + "P2P GO ignore non-P2P probe req") + +#define CFG_P2P_ALL \ + CFG(CFG_ACTION_FRAME_RANDOM_SEQ_NUM_ENABLED) \ + CFG(CFG_GO_KEEP_ALIVE_PERIOD) \ + CFG(CFG_GO_LINK_MONITOR_PERIOD) \ + CFG(CFG_P2P_DEVICE_ADDRESS_ADMINISTRATED) \ + CFG(CFG_P2P_GO_ON_5GHZ_INDOOR_CHANNEL) \ + CFG(CFG_GO_IGNORE_NON_P2P_PROBE_REQ) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_api.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_api.h new file mode 100644 index 0000000000..6140d3c9cf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_api.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p public data structure definitions + */ + +#ifndef _WLAN_P2P_API_H_ +#define _WLAN_P2P_API_H_ + +#include +#include + +/** + * wlan_p2p_check_oui_and_force_1x1() - Function to get P2P client device + * attributes from assoc request frames + * @assoc_ie: pointer to assoc request frame IEs + * @ie_len: length of the assoc request frame IE + * + * When assoc request is received from P2P STA device, this function checks + * for specific OUI present in the P2P device info attribute. The caller should + * take care of checking if this is called only in P2P GO mode. + * + * Return: True if OUI is present, else false. + */ +bool wlan_p2p_check_oui_and_force_1x1(uint8_t *assoc_ie, uint32_t ie_len); + +/** + * wlan_p2p_cleanup_roc_by_vdev() - Cleanup roc request by vdev + * @vdev: pointer to vdev object + * @sync: whether to wait for complete event + * + * This function call P2P API to cleanup roc request by vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev, + bool sync); + +/** + * wlan_p2p_status_connect() - Update P2P connection status + * @vdev: vdev context + * + * Updates P2P connection status by up layer when connecting. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_p2p_status_connect(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_p2p_is_action_frame_of_p2p_type() - Given action frame is p2p type or + * not + * @data_buf: data buffer address + * @length: buffer length + * + * Return: bool + */ +bool wlan_p2p_is_action_frame_of_p2p_type(uint8_t *data_buf, uint32_t length); + +/** + * wlan_p2p_abort_scan() - Abort on going scan on p2p interfaces + * @pdev: pdev object + * + * This function triggers an abort scan request to scan component to abort the + * ongoing scan request on p2p vdevs. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS wlan_p2p_abort_scan(struct wlan_objmgr_pdev *pdev); + +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * wlan_p2p_check_and_force_scc_go_plus_go() - Check and do force scc for + * go plus go + * @psoc: psoc object + * @vdev: vdev object + * + * This function checks whether force scc is enabled or not. If it + * is enabled then it will do force scc to remaining p2p go vdev if + * user has initiated CSA to current vdev. + * + * Return: status + */ +QDF_STATUS +wlan_p2p_check_and_force_scc_go_plus_go(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +wlan_p2p_check_and_force_scc_go_plus_go(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h new file mode 100644 index 0000000000..8a6a332e3d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_cfg_api.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p configures interface definitions + */ + +#ifndef _WLAN_P2P_CFG_API_H_ +#define _WLAN_P2P_CFG_API_H_ + +#include + +struct wlan_objmgr_psoc; + +/** + * cfg_p2p_get_go_keepalive_period() - get go keepalive period + * @psoc: pointer to psoc object + * @period: go keepalive period + * + * This function gets go keepalive period to p2p component + */ +QDF_STATUS +cfg_p2p_get_go_keepalive_period(struct wlan_objmgr_psoc *psoc, + uint32_t *period); + +/** + * cfg_p2p_get_go_link_monitor_period() - get go link monitor period + * @psoc: pointer to psoc object + * @period: go link monitor period + * + * This function gets go link monitor period to p2p component + */ +QDF_STATUS +cfg_p2p_get_go_link_monitor_period(struct wlan_objmgr_psoc *psoc, + uint32_t *period); + +/** + * cfg_p2p_get_device_addr_admin() - get enable/disable p2p device + * addr administrated + * @psoc: pointer to psoc object + * @enable: enable/disable p2p device addr administrated + * + * This function gets enable/disable p2p device addr administrated + */ +QDF_STATUS +cfg_p2p_get_device_addr_admin(struct wlan_objmgr_psoc *psoc, + bool *enable); + +/** + * cfg_p2p_is_roam_config_disabled() - get disable roam config on sta interface + * during p2p connection + * @psoc: pointer to psoc object + * + * Get disable roam configuration during p2p connection + */ +bool cfg_p2p_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_p2p_is_go_ignore_non_p2p_probe_req() - Is P2P GO ignore non-P2P probe + * req enabled + * @psoc: pointer to psoc object + * + * If P2P GO ignore non-P2P probe req enabled, don't send probe rsp to STA + */ +bool cfg_p2p_is_go_ignore_non_p2p_probe_req(struct wlan_objmgr_psoc *psoc); +#endif /* _WLAN_P2P_CFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_mcc_quota_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_mcc_quota_public_struct.h new file mode 100644 index 0000000000..fdf67e124d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_mcc_quota_public_struct.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains mcc quota event public data structure definitions + */ + +#ifndef _WLAN_P2P_MCC_QUOTA_PUBLIC_STRUCT_H_ +#define _WLAN_P2P_MCC_QUOTA_PUBLIC_STRUCT_H_ + +#include + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; + +/* + * Max possible unique home channel numbers that host can receive to + * struct mcc_quota_info from FW event. In real case, for two MACs DBS, + * each MAC has two unique home channels, max home channel can't exceed 4. + */ +#define MAX_MCC_QUOTA_CH_NUM 4 + +/** + * enum mcc_quota_type - mcc channel quota type + * @QUOTA_TYPE_CLEAR: target exits MCC state and clear mcc quota information + * @QUOTA_TYPE_FIXED: channel time quota is fixed and will not be changed + * @QUOTA_TYPE_DYNAMIC: channel time quota is dynamic and targe may change + * the quota based on the data activity + * @QUOTA_TYPE_UNKNOWN: unknown type + */ +enum mcc_quota_type { + QUOTA_TYPE_CLEAR, + QUOTA_TYPE_FIXED, + QUOTA_TYPE_DYNAMIC, + QUOTA_TYPE_UNKNOWN = 0xff +}; + +/** + * struct channel_quota - mcc channel quota + * @chan_mhz: frequency of the channel for which the quota is set + * @channel_time_quota: channel time quota expressed as percentage + */ +struct channel_quota { + uint32_t chan_mhz; + uint32_t channel_time_quota; +}; + +/** + * struct mcc_quota_info - mcc quota information + * @type: mcc quota type + * @num_chan_quota: number of channel quota in chan_quota + * @chan_quota: channel quota array + */ +struct mcc_quota_info { + enum mcc_quota_type type; + uint32_t num_chan_quota; + struct channel_quota chan_quota[MAX_MCC_QUOTA_CH_NUM]; +}; +#endif /* _WLAN_P2P_MCC_QUOTA_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_mcc_quota_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_mcc_quota_tgt_api.h new file mode 100644 index 0000000000..1a74c2bc36 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_mcc_quota_tgt_api.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p mcc quota event south bound interface definitions + */ + +#ifndef _WLAN_P2P_MCC_QUOTA_TGT_API_H_ +#define _WLAN_P2P_MCC_QUOTA_TGT_API_H_ + +#include + +struct wlan_objmgr_psoc; + +#ifdef WLAN_FEATURE_MCC_QUOTA +/** + * tgt_p2p_register_mcc_quota_ev_handler() - register/unregister mcc quota + * wmi event handler + * @psoc: psoc object + * @reg: true for register, false for unregister + * + * This function will register or unregister mcc quota event handler + * in target if. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_register_mcc_quota_ev_handler(struct wlan_objmgr_psoc *psoc, + bool reg); + +/** + * tgt_p2p_mcc_quota_event_cb() - mcc quota event callback handler + * @psoc: psoc object + * @event_info: mcc quota event + * + * This function will be called by target if to indicate mcc quota event + * to stack. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_mcc_quota_event_cb(struct wlan_objmgr_psoc *psoc, + struct mcc_quota_info *event_info); +#else +static inline +QDF_STATUS tgt_p2p_register_mcc_quota_ev_handler(struct wlan_objmgr_psoc *psoc, + bool reg) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* _WLAN_P2P_MCC_QUOTA_TGT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h new file mode 100644 index 0000000000..e7b10b7b51 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_public_struct.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p public data structure definitions + */ + +#ifndef _WLAN_P2P_PUBLIC_STRUCT_H_ +#define _WLAN_P2P_PUBLIC_STRUCT_H_ + +#include + +#define P2P_MAX_NOA_DESC 4 + +#define HEADER_LEN_P2P_IE 6 +#define OUI_SIZE_P2P 4 + +#define P2P_1X1_WAR_OUI "\x00\x50\xf2\x04" +#define P2P_1X1_OUI_LEN 4 + +#define MAX_CONFIG_METHODS_LEN 2 +#define DEVICE_CATEGORY_MAX_LEN 1 + +/** + * struct p2p_ps_params - P2P powersave related params + * @opp_ps: opportunistic power save + * @ctwindow: CT window + * @count: count + * @duration: duration + * @interval: interval + * @single_noa_duration: single shot noa duration + * @ps_selection: power save selection + * @session_id: session id + * @start: start time + */ +struct p2p_ps_params { + uint8_t opp_ps; + uint32_t ctwindow; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t ps_selection; + uint8_t session_id; + uint32_t start; +}; + +/** + * struct p2p_roc_req - P2P roc request + * @vdev_id: Vdev id on which this request has come + * @chan_freq: Chan frequency for which this RoC has been requested + * @phy_mode: PHY mode + * @duration: Duration for the RoC + */ +struct p2p_roc_req { + uint32_t vdev_id; + qdf_freq_t chan_freq; + uint32_t phy_mode; + uint32_t duration; +}; + +/** + * enum p2p_roc_event - P2P RoC event + * @ROC_EVENT_READY_ON_CHAN: RoC has started now + * @ROC_EVENT_COMPLETED: RoC has been completed + * @ROC_EVENT_INAVLID: Invalid event + */ +enum p2p_roc_event { + ROC_EVENT_READY_ON_CHAN = 0, + ROC_EVENT_COMPLETED, + ROC_EVENT_INAVLID, +}; + +/** + * struct p2p_event - p2p event + * @vdev_id: Vdev id + * @roc_event: RoC event + * @cookie: Cookie which is given to supplicant for this roc req + * @chan_freq: Chan frequency for which this RoC has been requested + * @duration: Duration for the RoC + */ +struct p2p_event { + uint32_t vdev_id; + enum p2p_roc_event roc_event; + uint64_t cookie; + qdf_freq_t chan_freq; + uint32_t duration; +}; + +/** + * struct p2p_rx_mgmt_frame - rx mgmt frame structure + * @frame_len: Frame length + * @rx_freq: RX Frequency + * @vdev_id: Vdev id + * @frm_type: Frame type + * @rx_rssi: RX rssi + * @buf: Buffer address + */ +struct p2p_rx_mgmt_frame { + uint32_t frame_len; + uint32_t rx_freq; + uint32_t vdev_id; + uint32_t frm_type; + uint32_t rx_rssi; + QDF_FLEX_ARRAY(uint8_t, buf); +}; + +/** + * struct p2p_tx_cnf - tx confirm structure + * @vdev_id: Vdev id + * @action_cookie: TX cookie for this action frame + * @buf_len: Frame length + * @status: TX status + * @buf: Buffer address + */ +struct p2p_tx_cnf { + uint32_t vdev_id; + uint64_t action_cookie; + uint32_t buf_len; + uint32_t status; + uint8_t *buf; +}; + +/** + * struct p2p_mgmt_tx - p2p mgmt tx structure + * @vdev_id: Vdev id + * @chan_freq: Chan frequency for which this RoC has been requested + * @wait: Duration for the RoC + * @len: Length of tx buffer + * @no_cck: Required cck or not + * @dont_wait_for_ack: Wait for ack or not + * @off_chan: Off channel tx or not + * @buf: TX buffer + */ +struct p2p_mgmt_tx { + uint32_t vdev_id; + qdf_freq_t chan_freq; + uint32_t wait; + uint32_t len; + uint32_t no_cck; + uint32_t dont_wait_for_ack; + uint32_t off_chan; + const uint8_t *buf; +}; + +/** + * struct p2p_set_mac_filter_evt + * @vdev_id: Vdev id + * @status: target reported result of set mac addr filter + */ +struct p2p_set_mac_filter_evt { + uint32_t vdev_id; + uint32_t status; +}; + +/** + * struct p2p_ps_config + * @vdev_id: Vdev id + * @opp_ps: Opportunistic power save + * @ct_window: CT window + * @count: Count + * @duration: Duration + * @interval: Interval + * @single_noa_duration: Single shot noa duration + * @ps_selection: power save selection + * @start: Start time + */ +struct p2p_ps_config { + uint32_t vdev_id; + uint32_t opp_ps; + uint32_t ct_window; + uint32_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint32_t ps_selection; + uint32_t start; +}; + +/** + * struct p2p_lo_start - p2p listen offload start + * @vdev_id: Vdev id + * @ctl_flags: Control flag + * @freq: P2P listen frequency + * @period: Listen offload period + * @interval: Listen offload interval + * @count: Number listen offload intervals + * @dev_types_len: Device types length + * @probe_resp_len: Probe response template length + * @device_types: Device types + * @probe_resp_tmplt: Probe response template + */ +struct p2p_lo_start { + uint32_t vdev_id; + uint32_t ctl_flags; + uint32_t freq; + uint32_t period; + uint32_t interval; + uint32_t count; + uint32_t dev_types_len; + uint32_t probe_resp_len; + uint8_t *device_types; + uint8_t *probe_resp_tmplt; +}; + +/** + * struct p2p_lo_event + * @vdev_id: vdev id + * @reason_code: reason code + */ +struct p2p_lo_event { + uint32_t vdev_id; + uint32_t reason_code; +}; + +/** + * struct noa_descriptor - noa descriptor + * @type_count: 255: continuous schedule, 0: reserved + * @duration: Absent period duration in micro seconds + * @interval: Absent period interval in micro seconds + * @start_time: 32 bit tsf time when in starts + */ +struct noa_descriptor { + uint32_t type_count; + uint32_t duration; + uint32_t interval; + uint32_t start_time; +}; + +/** + * struct p2p_noa_info - p2p noa information + * @index: identifies instance of NOA su element + * @opps_ps: opps ps state of the AP + * @ct_window: ct window in TUs + * @vdev_id: vdev id + * @num_desc: number of NOA descriptors + * @noa_desc: noa descriptors + */ +struct p2p_noa_info { + uint32_t index; + uint32_t opps_ps; + uint32_t ct_window; + uint32_t vdev_id; + uint32_t num_desc; + struct noa_descriptor noa_desc[P2P_MAX_NOA_DESC]; +}; + +/** + * struct p2p_protocol_callbacks - callback to non-converged driver + * @is_mgmt_protected: func to get 11w mgmt protection status + */ +struct p2p_protocol_callbacks { + bool (*is_mgmt_protected)(uint32_t vdev_id, const uint8_t *peer_addr); +}; + +/** + * enum p2p_attr_id - enum for P2P attributes ID in P2P IE + * @P2P_ATTR_STATUS: Attribute Status none + * @P2P_ATTR_MINOR_REASON_CODE: Minor reason code attribute + * @P2P_ATTR_CAPABILITY: Capability attribute + * @P2P_ATTR_DEVICE_ID: device ID attribute + * @P2P_ATTR_GROUP_OWNER_INTENT: Group owner intent attribute + * @P2P_ATTR_CONFIGURATION_TIMEOUT: Config timeout attribute + * @P2P_ATTR_LISTEN_CHANNEL: listen channel attribute + * @P2P_ATTR_GROUP_BSSID: Group BSSID attribute + * @P2P_ATTR_EXT_LISTEN_TIMING: Listen timing attribute + * @P2P_ATTR_INTENDED_INTERFACE_ADDR: Intended interface address attribute + * @P2P_ATTR_MANAGEABILITY: Manageability attribute + * @P2P_ATTR_CHANNEL_LIST: Channel list attribute + * @P2P_ATTR_NOTICE_OF_ABSENCE: Notice of Absence attribute + * @P2P_ATTR_DEVICE_INFO: Device Info attribute + * @P2P_ATTR_GROUP_INFO: Group Info attribute + * @P2P_ATTR_GROUP_ID: Group ID attribute + * @P2P_ATTR_INTERFACE: Interface attribute + * @P2P_ATTR_OPERATING_CHANNEL: Operating channel attribute + * @P2P_ATTR_INVITATION_FLAGS: Invitation flags attribute + * @P2P_ATTR_OOB_GO_NEG_CHANNEL: GO neg channel attribute + * @P2P_ATTR_SERVICE_HASH: Service HASH attribute + * @P2P_ATTR_SESSION_INFORMATION_DATA: Session Info data attribute + * @P2P_ATTR_CONNECTION_CAPABILITY: Connection capability attribute + * @P2P_ATTR_ADVERTISEMENT_ID: Advertisement ID attribute + * @P2P_ATTR_ADVERTISED_SERVICE: Advertised Service attribute + * @P2P_ATTR_SESSION_ID: Session ID attribute + * @P2P_ATTR_FEATURE_CAPABILITY: Feature capability attribute + * @P2P_ATTR_PERSISTENT_GROUP: Persistent group attribute + * @P2P_ATTR_VENDOR_SPECIFIC: Vendor specific attribute + */ +enum p2p_attr_id { + P2P_ATTR_STATUS = 0, + P2P_ATTR_MINOR_REASON_CODE = 1, + P2P_ATTR_CAPABILITY = 2, + P2P_ATTR_DEVICE_ID = 3, + P2P_ATTR_GROUP_OWNER_INTENT = 4, + P2P_ATTR_CONFIGURATION_TIMEOUT = 5, + P2P_ATTR_LISTEN_CHANNEL = 6, + P2P_ATTR_GROUP_BSSID = 7, + P2P_ATTR_EXT_LISTEN_TIMING = 8, + P2P_ATTR_INTENDED_INTERFACE_ADDR = 9, + P2P_ATTR_MANAGEABILITY = 10, + P2P_ATTR_CHANNEL_LIST = 11, + P2P_ATTR_NOTICE_OF_ABSENCE = 12, + P2P_ATTR_DEVICE_INFO = 13, + P2P_ATTR_GROUP_INFO = 14, + P2P_ATTR_GROUP_ID = 15, + P2P_ATTR_INTERFACE = 16, + P2P_ATTR_OPERATING_CHANNEL = 17, + P2P_ATTR_INVITATION_FLAGS = 18, + P2P_ATTR_OOB_GO_NEG_CHANNEL = 19, + P2P_ATTR_SERVICE_HASH = 21, + P2P_ATTR_SESSION_INFORMATION_DATA = 22, + P2P_ATTR_CONNECTION_CAPABILITY = 23, + P2P_ATTR_ADVERTISEMENT_ID = 24, + P2P_ATTR_ADVERTISED_SERVICE = 25, + P2P_ATTR_SESSION_ID = 26, + P2P_ATTR_FEATURE_CAPABILITY = 27, + P2P_ATTR_PERSISTENT_GROUP = 28, + P2P_ATTR_VENDOR_SPECIFIC = 221 +}; +#endif /* _WLAN_P2P_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h new file mode 100644 index 0000000000..f5938d6981 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_tgt_api.h @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p south bound interface definitions + */ + +#ifndef _WLAN_P2P_TGT_API_H_ +#define _WLAN_P2P_TGT_API_H_ + +#include +#include + +struct scan_event; +struct wlan_objmgr_psoc; +struct wlan_objmgr_peer; +struct p2p_noa_info; +struct p2p_lo_event; +struct mgmt_rx_event_params; +enum mgmt_frame_type; +struct p2p_set_mac_filter_evt; + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD + +/** + * tgt_p2p_lo_event_cb() - Listen offload stop request + * @psoc: soc object + * @event_info: lo stop event buffer + * + * This function gets called from target interface. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc, + struct p2p_lo_event *event_info); + +/** + * tgt_p2p_register_lo_ev_handler() - register lo event + * @psoc: soc object + * + * p2p tgt api to register listen offload event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_register_lo_ev_handler( + struct wlan_objmgr_psoc *psoc); + +/** + * tgt_p2p_unregister_lo_ev_handler() - unregister lo event + * @psoc: soc object + * + * p2p tgt api to unregister listen offload event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_unregister_lo_ev_handler( + struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS tgt_p2p_register_lo_ev_handler( + struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS tgt_p2p_unregister_lo_ev_handler( + struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * tgt_p2p_register_macaddr_rx_filter_evt_handler() - register add mac rx + * filter status event + * @psoc: soc object + * @register: register or unregister + * + * p2p tgt api to register add mac rx filter status event + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_register_macaddr_rx_filter_evt_handler( + struct wlan_objmgr_psoc *psoc, bool register); + +/** + * tgt_p2p_register_noa_ev_handler() - register noa event + * @psoc: soc object + * + * p2p tgt api to register noa event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_register_noa_ev_handler( + struct wlan_objmgr_psoc *psoc); + +/** + * tgt_p2p_unregister_noa_ev_handler() - unregister noa event + * @psoc: soc object + * + * p2p tgt api to unregister noa event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_unregister_noa_ev_handler( + struct wlan_objmgr_psoc *psoc); + +/** + * tgt_p2p_scan_event_cb() - Callback for scan event + * @vdev: vdev object + * @event: event information + * @arg: registered arguments + * + * This function gets called from scan component when getting P2P + * scan event. + * + * Return: None + */ +void tgt_p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); + +/** + * tgt_p2p_mgmt_download_comp_cb() - Callback for mgmt frame tx + * complete + * @context: tx context + * @buf: buffer address + * @free: need to free or not + * + * This function gets called from mgmt tx/rx component when mgmt + * frame tx complete. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_mgmt_download_comp_cb(void *context, + qdf_nbuf_t buf, bool free); + +/** + * tgt_p2p_mgmt_ota_comp_cb() - Callback for mgmt frame tx ack + * @context: tx context + * @buf: buffer address + * @status: tx status + * @tx_compl_params: tx complete parameters + * + * This function gets called from mgmt tx/rx component when getting + * mgmt frame tx ack. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf, + uint32_t status, void *tx_compl_params); + +/** + * tgt_p2p_mgmt_frame_rx_cb() - Callback for rx mgmt frame + * @psoc: soc context + * @peer: peer context + * @buf: rx buffer + * @mgmt_rx_params: mgmt rx parameters + * @frm_type: frame type + * + * This function gets called from mgmt tx/rx component when rx mgmt + * frame. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type); +/** + * tgt_p2p_noa_event_cb() - Callback for noa event + * @psoc: soc object + * @event_info: noa event information + * + * This function gets called from target interface. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc, + struct p2p_noa_info *event_info); + +/** + * tgt_p2p_add_mac_addr_status_event_cb() - Callback for set mac addr filter evt + * @psoc: soc object + * @event_info: event information type of p2p_set_mac_filter_evt + * + * This function gets called from target interface. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS +tgt_p2p_add_mac_addr_status_event_cb( + struct wlan_objmgr_psoc *psoc, + struct p2p_set_mac_filter_evt *event_info); + +#endif /* _WLAN_P2P_TGT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h new file mode 100644 index 0000000000..24bf8cfa38 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/inc/wlan_p2p_ucfg_api.h @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2017-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p north bound interface definitions + */ + +#ifndef _WLAN_P2P_UCFG_API_H_ +#define _WLAN_P2P_UCFG_API_H_ + +#include "wlan_p2p_cfg_api.h" +#include + +struct wlan_objmgr_psoc; +struct p2p_roc_req; +struct p2p_event; +struct p2p_rx_mgmt_frame; +struct p2p_tx_cnf; +struct p2p_mgmt_tx; +struct p2p_ps_config; +struct p2p_lo_start; +struct p2p_lo_event; +struct p2p_protocol_callbacks; +struct mcc_quota_info; + +/** + * typedef p2p_rx_callback() - Callback for rx mgmt frame + * @user_data: user data associated to this rx mgmt frame. + * @rx_frame: RX mgmt frame + * + * This callback will be used to give rx frames to hdd. + * + * Return: None + */ +typedef void (*p2p_rx_callback)(void *user_data, + struct p2p_rx_mgmt_frame *rx_frame); + +/** + * typedef p2p_action_tx_cnf_callback() - Callback for tx confirmation + * @user_data: user data associated to this tx confirmation + * @tx_cnf: tx confirmation information + * + * This callback will be used to give tx mgmt frame confirmation to + * hdd. + * + * Return: None + */ +typedef void (*p2p_action_tx_cnf_callback)(void *user_data, + struct p2p_tx_cnf *tx_cnf); + +/** + * typedef p2p_lo_event_callback() - Callback for listen offload event + * @user_data: user data associated to this lo event + * @p2p_lo_event: listen offload event information + * + * This callback will be used to give listen offload event to hdd. + * + * Return: None + */ +typedef void (*p2p_lo_event_callback)(void *user_data, + struct p2p_lo_event *p2p_lo_event); + +/** + * typedef p2p_event_callback() - Callback for P2P event + * @user_data: user data associated to this p2p event + * @p2p_event: p2p event information + * + * This callback will be used to give p2p event to hdd. + * + * Return: None + */ +typedef void (*p2p_event_callback)(void *user_data, + struct p2p_event *p2p_event); + +/** + * typedef mcc_quota_event_callback() - Callback for mcc quota + * @psoc: psoc object + * @vdev: vdev object + * @mcc_quota: mcc quota event information + * + * Callback to notify mcc quota event. + * + * Return: None + */ +typedef QDF_STATUS (*mcc_quota_event_callback)(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mcc_quota_info *mcc_quota); + +/** + * struct p2p_start_param - p2p soc start parameters. Below callbacks + * will be registered by the HDD + * @rx_cb: Function pointer to hdd rx callback. This + * function will be used to give rx frames to hdd + * @rx_cb_data: RX callback user data + * @event_cb: Function pointer to hdd p2p event callback. + * This function will be used to give p2p event + * to hdd + * @event_cb_data: Pointer to p2p event callback user data + * @tx_cnf_cb: Function pointer to hdd tx confirm callback. + * This function will be used to give tx confirm + * to hdd + * @tx_cnf_cb_data: Pointer to p2p tx confirm callback user data + * @lo_event_cb: Function pointer to p2p listen offload + * callback. This function will be used to give + * listen offload stopped event to hdd + * @lo_event_cb_data: Pointer to p2p listen offload callback user data + */ +struct p2p_start_param { + p2p_rx_callback rx_cb; + void *rx_cb_data; + p2p_event_callback event_cb; + void *event_cb_data; + p2p_action_tx_cnf_callback tx_cnf_cb; + void *tx_cnf_cb_data; +#ifdef FEATURE_P2P_LISTEN_OFFLOAD + p2p_lo_event_callback lo_event_cb; + void *lo_event_cb_data; +#endif +}; + +/** + * ucfg_p2p_init() - P2P component initialization + * + * This function gets called when dispatcher initializing. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_init(void); + +/** + * ucfg_p2p_deinit() - P2P component de-init + * + * This function gets called when dispatcher de-init. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_deinit(void); + +/** + * ucfg_p2p_psoc_open() - Open P2P component + * @soc: soc context + * + * This function gets called when dispatcher opening. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_psoc_open(struct wlan_objmgr_psoc *soc); + +/** + * ucfg_p2p_psoc_close() - Close P2P component + * @soc: soc context + * + * This function gets called when dispatcher closing. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_psoc_close(struct wlan_objmgr_psoc *soc); + +/** + * ucfg_p2p_psoc_start() - Start P2P component + * @soc: soc context + * @req: P2P start parameters + * + * This function gets called when up layer starting up. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_psoc_start(struct wlan_objmgr_psoc *soc, + struct p2p_start_param *req); + +/** + * ucfg_p2p_psoc_stop() - Stop P2P component + * @soc: soc context + * + * This function gets called when up layer exit. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_psoc_stop(struct wlan_objmgr_psoc *soc); + +/** + * ucfg_p2p_roc_req() - Roc request + * @soc: soc context + * @roc_req: Roc request parameters + * @cookie: return cookie to caller + * + * This function delivers roc request to P2P component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc, + struct p2p_roc_req *roc_req, uint64_t *cookie); + +/** + * ucfg_p2p_roc_cancel_req() - Cancel roc request + * @soc: soc context + * @cookie: Find out the roc request by cookie + * + * This function delivers cancel roc request to P2P component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc, + uint64_t cookie); + +/** + * ucfg_p2p_cleanup_roc_by_vdev() - Cleanup roc request by vdev + * @vdev: pointer to vdev object + * + * This function call P2P API to cleanup roc request by vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_cleanup_roc_by_psoc() - Cleanup roc request by psoc + * @psoc: pointer to psoc object + * + * This function call P2P API to cleanup roc request by psoc + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_cleanup_roc_by_psoc(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_p2p_cleanup_tx_by_vdev() - Cleanup tx request by vdev + * @vdev: pointer to vdev object + * + * This function call P2P API to cleanup tx action frame request by vdev + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_cleanup_tx_by_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_cleanup_tx_by_psoc() - Cleanup tx request by psoc + * @psoc: pointer to psoc object + * + * This function call P2P API to cleanup tx action frame request by psoc + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_cleanup_tx_by_psoc(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_p2p_mgmt_tx() - Mgmt frame tx request + * @soc: soc context + * @mgmt_frm: TX mgmt frame parameters + * @cookie: Return the cookie to caller + * @pdev: pdev object + * + * This function delivers mgmt frame tx request to P2P component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, + struct p2p_mgmt_tx *mgmt_frm, + uint64_t *cookie, + struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_p2p_mgmt_tx_cancel() - Cancel mgmt frame tx request + * @soc: soc context + * @vdev: vdev object + * @cookie: Find out the mgmt tx request by cookie + * + * This function delivers cancel mgmt frame tx request request to P2P + * component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc, + struct wlan_objmgr_vdev *vdev, uint64_t cookie); + +/** + * ucfg_p2p_set_ps() - P2P set power save + * @soc: soc context + * @ps_config: power save configure + * + * This function delivers p2p power save request to P2P component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc, + struct p2p_ps_config *ps_config); + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * ucfg_p2p_lo_start() - Listen offload start request + * @soc: soc context + * @p2p_lo_start: lo start parameters + * + * This function delivers listen offload start request to P2P + * component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_lo_start(struct wlan_objmgr_psoc *soc, + struct p2p_lo_start *p2p_lo_start); + +/** + * ucfg_p2p_lo_stop() - Listen offload stop request + * @soc: soc context + * @vdev_id: vdev id + * + * This function delivers listen offload stop request to P2P component. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_lo_stop(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id); +#endif + +/** + * p2p_peer_authorized() - Process peer authorized event + * @vdev: vdev structure to which peer is associated + * @mac_addr: peer mac address + * + * This function handles disables noa whenever a legacy station + * complete 4-way handshake after association. + * + * Return: void + */ +void p2p_peer_authorized(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr); + +/** + * ucfg_p2p_set_noa() - Disable/Enable NOA + * @soc: soc context + * @vdev_id: vdev id + * @disable_noa: TRUE - Disable NoA, FALSE - Enable NoA + * + * This function send wmi command to enable / disable NoA. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id, bool disable_noa); + +/** + * ucfg_p2p_check_random_mac() - check random mac addr or not + * @soc: soc context + * @vdev_id: vdev id + * @random_mac_addr: mac addr to be checked + * + * This function check the input addr is random mac addr or not for vdev. + * + * Return: true if addr is random mac address else false. + */ +bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr); + +/** + * ucfg_p2p_register_callbacks() - register p2p callbacks + * @soc: soc context + * @cb_obj: p2p_protocol_callbacks struct + * + * This function registers lim callbacks to p2p components to provide + * protocol information. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_register_callbacks(struct wlan_objmgr_psoc *soc, + struct p2p_protocol_callbacks *cb_obj); + +#ifdef WLAN_FEATURE_MCC_QUOTA +/** + * ucfg_p2p_register_mcc_quota_event_os_if_cb() - Register OS IF mcc quota + * event callback + * @psoc: soc object + * @cb: os if callback for mcc quota event + * + * Return: QDF_STATUS_SUCCESS for success + */ +QDF_STATUS +ucfg_p2p_register_mcc_quota_event_os_if_cb(struct wlan_objmgr_psoc *psoc, + mcc_quota_event_callback cb); +#else +static inline QDF_STATUS +ucfg_p2p_register_mcc_quota_event_os_if_cb(struct wlan_objmgr_psoc *psoc, + mcc_quota_event_callback cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ucfg_p2p_status_scan() - Show P2P connection status when scanning + * @vdev: vdev context + * + * This function shows P2P connection status when scanning. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_status_scan(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_status_connect() - Update P2P connection status + * @vdev: vdev context + * + * Updates P2P connection status by up layer when connecting. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_status_connect(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_status_disconnect() - Update P2P connection status + * @vdev: vdev context + * + * Updates P2P connection status by up layer when disconnecting. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_status_disconnect(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_status_start_bss() - Update P2P connection status + * @vdev: vdev context + * + * Updates P2P connection status by up layer when starting bss. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_status_start_bss(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_status_stop_bss() - Update P2P connection status + * @vdev: vdev context + * + * Updates P2P connection status by up layer when stopping bss. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ucfg_p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_p2p_is_roam_config_disabled() - Roam disable config during p2p + * connection + * @psoc: psoc context + * + * During P2P connection disable roam on STA interface + * + * Return: p2p disable roam - in case of success else false + */ +static inline +bool ucfg_p2p_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc) +{ + return cfg_p2p_is_roam_config_disabled(psoc); +} + +/** + * ucfg_p2p_get_indoor_ch_support() - Get indoor channel support + * for P2P GO + * + * @psoc: pointer to psoc obj + * + * Get the indoor channel support for P2P GO + * + * Return: p2p go supported on indoor channel + */ +bool ucfg_p2p_get_indoor_ch_support(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +/** + * ucfg_is_p2p_device_dynamic_set_mac_addr_supported() - API to check P2P device + * dynamic MAC address update is supported or not + * + * @psoc: Pointer to psoc + * + * Return: true or false + */ +bool +ucfg_is_p2p_device_dynamic_set_mac_addr_supported(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_is_p2p_device_dynamic_set_mac_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif +#endif /* _WLAN_P2P_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_api.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_api.c new file mode 100644 index 0000000000..b1b3c4c6cd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_api.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains P2P public API's exposed. + */ + +#include "wlan_p2p_api.h" +#include +#include "wlan_p2p_public_struct.h" +#include "../../core/src/wlan_p2p_main.h" +#include "../../core/src/wlan_p2p_roc.h" +#include +#include "wlan_scan_api.h" +#include "../../core/src/wlan_p2p_off_chan_tx.h" + +bool wlan_p2p_check_oui_and_force_1x1(uint8_t *assoc_ie, uint32_t assoc_ie_len) +{ + if (!assoc_ie || !assoc_ie_len) + return false; + + return p2p_check_oui_and_force_1x1(assoc_ie, assoc_ie_len); +} + +QDF_STATUS wlan_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev, + bool sync) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + struct wlan_objmgr_psoc *psoc; + + p2p_debug("vdev:%pK", vdev); + + if (!vdev) { + p2p_debug("null vdev"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + p2p_err("null psoc"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + return p2p_cleanup_roc(p2p_soc_obj, vdev, sync); +} + +QDF_STATUS wlan_p2p_status_connect(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_status_connect(vdev); +} + +bool +wlan_p2p_is_action_frame_of_p2p_type(uint8_t *data_buf, + uint32_t length) +{ + return p2p_is_action_frame_of_p2p_type(data_buf, length); +} + +#ifdef WLAN_FEATURE_P2P_P2P_STA +QDF_STATUS +wlan_p2p_check_and_force_scc_go_plus_go(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_check_and_force_scc_go_plus_go(psoc, vdev); +} +#endif + +static void wlan_p2p_abort_vdev_scan(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct scan_cancel_request *req; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_DEVICE_MODE) + return; + + p2p_soc_obj = + wlan_objmgr_psoc_get_comp_private_obj(wlan_vdev_get_psoc(vdev), + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("P2P soc object is NULL"); + return; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return; + + req->vdev = vdev; + req->cancel_req.requester = p2p_soc_obj->scan_req_id; + req->cancel_req.scan_id = INVALID_SCAN_ID; + req->cancel_req.vdev_id = wlan_vdev_get_id(vdev); + req->cancel_req.req_type = WLAN_SCAN_CANCEL_VDEV_ALL; + + qdf_mtrace(QDF_MODULE_ID_P2P, QDF_MODULE_ID_SCAN, + req->cancel_req.req_type, + req->cancel_req.vdev_id, + req->cancel_req.scan_id); + status = wlan_scan_cancel(req); + + p2p_debug("abort scan, scan req id:%d, scan id:%d, status:%d", + req->cancel_req.requester, + req->cancel_req.scan_id, status); +} + +QDF_STATUS wlan_p2p_abort_scan(struct wlan_objmgr_pdev *pdev) +{ + return wlan_objmgr_pdev_iterate_obj_list(pdev, + WLAN_VDEV_OP, + wlan_p2p_abort_vdev_scan, + NULL, 0, WLAN_P2P_ID); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_cfg.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_cfg.c new file mode 100644 index 0000000000..9668a0a0fe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_cfg.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains p2p configures interface definitions + */ + +#include +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_cfg_api.h" +#include "../../core/src/wlan_p2p_main.h" +#include "wlan_mlme_ucfg_api.h" + +static inline struct p2p_soc_priv_obj * +wlan_psoc_get_p2p_object(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); +} + +QDF_STATUS +cfg_p2p_get_go_keepalive_period(struct wlan_objmgr_psoc *psoc, + uint32_t *period) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + p2p_soc_obj = wlan_psoc_get_p2p_object(psoc); + if (!p2p_soc_obj) { + *period = 0; + p2p_err("p2p psoc null"); + return QDF_STATUS_E_INVAL; + } + + *period = p2p_soc_obj->param.go_keepalive_period; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_p2p_get_go_link_monitor_period(struct wlan_objmgr_psoc *psoc, + uint32_t *period) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + p2p_soc_obj = wlan_psoc_get_p2p_object(psoc); + if (!p2p_soc_obj) { + *period = 0; + p2p_err("p2p psoc null"); + return QDF_STATUS_E_INVAL; + } + + *period = p2p_soc_obj->param.go_link_monitor_period; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_p2p_get_device_addr_admin(struct wlan_objmgr_psoc *psoc, + bool *enable) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + p2p_soc_obj = wlan_psoc_get_p2p_object(psoc); + if (!p2p_soc_obj) { + *enable = false; + p2p_err("p2p psoc null"); + return QDF_STATUS_E_INVAL; + } + + *enable = p2p_soc_obj->param.p2p_device_addr_admin; + + return QDF_STATUS_SUCCESS; +} + +bool cfg_p2p_is_roam_config_disabled(struct wlan_objmgr_psoc *psoc) +{ + uint32_t sta_roam_disable = 0; + + if (ucfg_mlme_get_roam_disable_config(psoc, &sta_roam_disable) == + QDF_STATUS_SUCCESS) + return sta_roam_disable & LFR3_STA_ROAM_DISABLE_BY_P2P; + + return false; +} + +bool +cfg_p2p_is_go_ignore_non_p2p_probe_req(struct wlan_objmgr_psoc *psoc) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + p2p_soc_obj = wlan_psoc_get_p2p_object(psoc); + if (!p2p_soc_obj) { + p2p_err("p2p psoc null"); + return false; + } + + return p2p_soc_obj->param.go_ignore_non_p2p_probe_req; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_mcc_quota_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_mcc_quota_tgt_api.c new file mode 100644 index 0000000000..a26a7735cf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_mcc_quota_tgt_api.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains mcc quota event processing south bound interface + * API implementation + */ + +#include +#include +#include "wlan_p2p_public_struct.h" +#include "../../core/src/wlan_p2p_main.h" +#include "../../core/src/wlan_p2p_mcc_quota.h" +#include "wlan_p2p_mcc_quota_tgt_api.h" + +QDF_STATUS tgt_p2p_mcc_quota_event_cb(struct wlan_objmgr_psoc *psoc, + struct mcc_quota_info *event_info) +{ + if (!event_info) { + p2p_err("invalid mcc quota event information"); + return QDF_STATUS_E_INVAL; + } + + if (!psoc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_mcc_quota_event_process(psoc, event_info); +} + +QDF_STATUS +tgt_p2p_register_mcc_quota_ev_handler(struct wlan_objmgr_psoc *psoc, + bool reg) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + p2p_err("invalid lmac if tx ops"); + return QDF_STATUS_E_FAILURE; + } + p2p_tx_ops = &tx_ops->p2p; + if (p2p_tx_ops->reg_mcc_quota_ev_handler) + status = p2p_tx_ops->reg_mcc_quota_ev_handler(psoc, reg); + + p2p_debug("register %d mcc quota event, status:%d", + reg, status); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_tgt_api.c new file mode 100644 index 0000000000..0d37e79acc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_tgt_api.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains p2p south bound interface definitions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_p2p_tgt_api.h" +#include "wlan_p2p_public_struct.h" +#include "../../core/src/wlan_p2p_main.h" +#include "../../core/src/wlan_p2p_roc.h" +#include "../../core/src/wlan_p2p_off_chan_tx.h" + +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define P2P_NOISE_FLOOR_DBM_DEFAULT (-96) + +static inline struct wlan_lmac_if_p2p_tx_ops * +wlan_psoc_get_p2p_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &(psoc->soc_cb.tx_ops->p2p); +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +QDF_STATUS tgt_p2p_register_lo_ev_handler( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc); + if (p2p_ops && p2p_ops->reg_lo_ev_handler) { + status = p2p_ops->reg_lo_ev_handler(psoc, NULL); + p2p_debug("register lo event, status:%d", status); + } + + return status; +} + +QDF_STATUS tgt_p2p_unregister_lo_ev_handler( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc); + if (p2p_ops && p2p_ops->unreg_lo_ev_handler) { + status = p2p_ops->unreg_lo_ev_handler(psoc, NULL); + p2p_debug("unregister lo event, status:%d", status); + } + + return status; +} + +QDF_STATUS tgt_p2p_lo_event_cb(struct wlan_objmgr_psoc *psoc, + struct p2p_lo_event *event_info) +{ + struct p2p_lo_stop_event *lo_stop_event; + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + p2p_debug("soc:%pK, event_info:%pK", psoc, event_info); + + if (!psoc) { + p2p_err("psoc context passed is NULL"); + if (event_info) + qdf_mem_free(event_info); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc object is NULL"); + if (event_info) + qdf_mem_free(event_info); + return QDF_STATUS_E_INVAL; + } + + if (!event_info) { + p2p_err("invalid lo stop event information"); + return QDF_STATUS_E_INVAL; + } + + lo_stop_event = qdf_mem_malloc(sizeof(*lo_stop_event)); + if (!lo_stop_event) { + qdf_mem_free(event_info); + return QDF_STATUS_E_NOMEM; + } + + lo_stop_event->p2p_soc_obj = p2p_soc_obj; + lo_stop_event->lo_event = event_info; + msg.type = P2P_EVENT_LO_STOPPED; + msg.bodyptr = lo_stop_event; + msg.callback = p2p_process_evt; + msg.flush_callback = p2p_event_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_TARGET_IF, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(lo_stop_event->lo_event); + qdf_mem_free(lo_stop_event); + p2p_err("post msg fail:%d", status); + } + + return status; +} +#endif /* FEATURE_P2P_LISTEN_OFFLOAD */ + +QDF_STATUS +tgt_p2p_add_mac_addr_status_event_cb(struct wlan_objmgr_psoc *psoc, + struct p2p_set_mac_filter_evt *event_info) +{ + struct p2p_mac_filter_rsp *mac_filter_rsp; + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + if (!psoc) { + p2p_err("random_mac:psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!event_info) { + p2p_err("random_mac:invalid event_info"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("random_mac:p2p soc object is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac_filter_rsp = qdf_mem_malloc(sizeof(*mac_filter_rsp)); + if (!mac_filter_rsp) + return QDF_STATUS_E_NOMEM; + + mac_filter_rsp->p2p_soc_obj = p2p_soc_obj; + mac_filter_rsp->vdev_id = event_info->vdev_id; + mac_filter_rsp->status = event_info->status; + + msg.type = P2P_EVENT_ADD_MAC_RSP; + msg.bodyptr = mac_filter_rsp; + msg.callback = p2p_process_evt; + status = scheduler_post_message(QDF_MODULE_ID_P2P, QDF_MODULE_ID_P2P, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(mac_filter_rsp); + + return status; +} + +QDF_STATUS tgt_p2p_register_macaddr_rx_filter_evt_handler( + struct wlan_objmgr_psoc *psoc, bool reg) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc); + if (p2p_ops && p2p_ops->reg_mac_addr_rx_filter_handler) { + status = p2p_ops->reg_mac_addr_rx_filter_handler(psoc, reg); + p2p_debug("register mac addr rx filter event, register %d status:%d", + reg, status); + } + + return status; +} + +QDF_STATUS tgt_p2p_register_noa_ev_handler( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc); + if (p2p_ops && p2p_ops->reg_noa_ev_handler) { + status = p2p_ops->reg_noa_ev_handler(psoc, NULL); + p2p_debug("register noa event, status:%d", status); + } + + return status; +} + +QDF_STATUS tgt_p2p_unregister_noa_ev_handler( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_ops = wlan_psoc_get_p2p_tx_ops(psoc); + if (p2p_ops && p2p_ops->unreg_noa_ev_handler) { + status = p2p_ops->unreg_noa_ev_handler(psoc, NULL); + p2p_debug("unregister noa event, status:%d", status); + } + + return status; +} + +void tgt_p2p_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + p2p_scan_event_cb(vdev, event, arg); +} + +QDF_STATUS tgt_p2p_mgmt_download_comp_cb(void *context, + qdf_nbuf_t buf, bool free) +{ + p2p_debug("context:%pK, buf:%pK, free:%d", context, + qdf_nbuf_data(buf), free); + + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_p2p_mgmt_ota_comp_cb(void *context, qdf_nbuf_t buf, + uint32_t status, void *tx_compl_params) +{ + struct p2p_tx_conf_event *tx_conf_event; + struct scheduler_msg msg = {0}; + QDF_STATUS ret; + + p2p_debug("context:%pK, buf:%pK, status:%d, tx complete params:%pK", + context, buf, status, tx_compl_params); + + if (!context) { + p2p_err("invalid context"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_INVAL; + } + + tx_conf_event = qdf_mem_malloc(sizeof(*tx_conf_event)); + if (!tx_conf_event) { + qdf_nbuf_free(buf); + return QDF_STATUS_E_NOMEM; + } + + tx_conf_event->status = status; + tx_conf_event->nbuf = buf; + tx_conf_event->p2p_soc_obj = (struct p2p_soc_priv_obj *)context; + msg.type = P2P_EVENT_MGMT_TX_ACK_CNF; + msg.bodyptr = tx_conf_event; + msg.callback = p2p_process_evt; + msg.flush_callback = p2p_event_flush_callback; + ret = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_TARGET_IF, + &msg); + if (QDF_IS_STATUS_ERROR(ret)) { + qdf_mem_free(tx_conf_event); + qdf_nbuf_free(buf); + p2p_err("post msg fail:%d", status); + } + + return ret; +} + +QDF_STATUS tgt_p2p_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type) +{ + struct p2p_rx_mgmt_frame *rx_mgmt; + struct p2p_rx_mgmt_event *rx_mgmt_event; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct scheduler_msg msg = {0}; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + uint8_t *pdata; + QDF_STATUS status; + + p2p_debug("psoc:%pK, peer:%pK, type:%d", psoc, peer, frm_type); + + if (!mgmt_rx_params) { + p2p_err("mgmt rx params is NULL"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p ctx is NULL, drop this frame"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + if (!peer) { + if (p2p_soc_obj->cur_roc_vdev_id == P2P_INVALID_VDEV_ID) { + p2p_debug("vdev id of current roc invalid"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_FAILURE; + } else { + vdev_id = p2p_soc_obj->cur_roc_vdev_id; + } + } else { + vdev = wlan_peer_get_vdev(peer); + if (!vdev) { + p2p_err("vdev is NULL in peer, drop this frame"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_FAILURE; + } + vdev_id = wlan_vdev_get_id(vdev); + } + + rx_mgmt_event = qdf_mem_malloc_atomic(sizeof(*rx_mgmt_event)); + if (!rx_mgmt_event) { + p2p_debug_rl("Failed to allocate rx mgmt event"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_NOMEM; + } + + rx_mgmt = qdf_mem_malloc_atomic(sizeof(*rx_mgmt) + + mgmt_rx_params->buf_len); + if (!rx_mgmt) { + p2p_debug_rl("Failed to allocate rx mgmt frame"); + qdf_nbuf_free(buf); + return QDF_STATUS_E_NOMEM; + } + + pdata = (uint8_t *)qdf_nbuf_data(buf); + rx_mgmt->frame_len = mgmt_rx_params->buf_len; + rx_mgmt->rx_freq = mgmt_rx_params->chan_freq; + rx_mgmt->vdev_id = vdev_id; + rx_mgmt->frm_type = frm_type; + rx_mgmt->rx_rssi = mgmt_rx_params->snr + + P2P_NOISE_FLOOR_DBM_DEFAULT; + rx_mgmt_event->rx_mgmt = rx_mgmt; + rx_mgmt_event->p2p_soc_obj = p2p_soc_obj; + qdf_mem_copy(rx_mgmt->buf, pdata, mgmt_rx_params->buf_len); + msg.type = P2P_EVENT_RX_MGMT; + msg.bodyptr = rx_mgmt_event; + msg.callback = p2p_process_evt; + msg.flush_callback = p2p_event_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_TARGET_IF, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(rx_mgmt_event->rx_mgmt); + qdf_mem_free(rx_mgmt_event); + p2p_err("post msg fail:%d", status); + } + qdf_nbuf_free(buf); + + return status; +} + +QDF_STATUS tgt_p2p_noa_event_cb(struct wlan_objmgr_psoc *psoc, + struct p2p_noa_info *event_info) +{ + struct p2p_noa_event *noa_event; + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + QDF_STATUS status; + + p2p_debug("soc:%pK, event_info:%pK", psoc, event_info); + + if (!psoc) { + p2p_err("psoc context passed is NULL"); + if (event_info) + qdf_mem_free(event_info); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc object is NULL"); + if (event_info) + qdf_mem_free(event_info); + return QDF_STATUS_E_INVAL; + } + + if (!event_info) { + p2p_err("invalid noa event information"); + return QDF_STATUS_E_INVAL; + } + + noa_event = qdf_mem_malloc(sizeof(*noa_event)); + if (!noa_event) { + qdf_mem_free(event_info); + return QDF_STATUS_E_NOMEM; + } + + noa_event->p2p_soc_obj = p2p_soc_obj; + noa_event->noa_info = event_info; + msg.type = P2P_EVENT_NOA; + msg.bodyptr = noa_event; + msg.callback = p2p_process_evt; + msg.flush_callback = p2p_event_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_P2P, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_TARGET_IF, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(noa_event->noa_info); + qdf_mem_free(noa_event); + p2p_err("post msg fail:%d", status); + } + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c new file mode 100644 index 0000000000..6a16e59c05 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains p2p north bound interface definitions + */ + +#include +#include +#include +#include +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_p2p_api.h" +#include "../../core/src/wlan_p2p_main.h" +#include "../../core/src/wlan_p2p_roc.h" +#include "../../core/src/wlan_p2p_off_chan_tx.h" +#include "target_if.h" + +static inline struct wlan_lmac_if_p2p_tx_ops * +ucfg_p2p_psoc_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &(psoc->soc_cb.tx_ops->p2p); +} + +/** + * is_p2p_ps_allowed() - If P2P power save is allowed or not + * @vdev: vdev object + * @id: umac component id + * + * This function returns TRUE if P2P power-save is allowed + * else returns FALSE. + * + * Return: bool + */ +static bool is_p2p_ps_allowed(struct wlan_objmgr_vdev *vdev, + enum wlan_umac_comp_id id) +{ + struct p2p_vdev_priv_obj *p2p_vdev_obj; + uint8_t is_p2pgo = 0; + + if (!vdev) { + p2p_err("vdev:%pK", vdev); + return true; + } + p2p_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_P2P); + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + is_p2pgo = 1; + + if (!p2p_vdev_obj || !is_p2pgo) { + p2p_err("p2p_vdev_obj:%pK is_p2pgo:%u", + p2p_vdev_obj, is_p2pgo); + return false; + } + if (p2p_vdev_obj->non_p2p_peer_count && + p2p_vdev_obj->noa_status == false) { + p2p_debug("non_p2p_peer_count: %u, noa_status: %d", + p2p_vdev_obj->non_p2p_peer_count, + p2p_vdev_obj->noa_status); + return false; + } + + return true; +} + +QDF_STATUS ucfg_p2p_init(void) +{ + return p2p_component_init(); +} + +QDF_STATUS ucfg_p2p_deinit(void) +{ + return p2p_component_deinit(); +} + +QDF_STATUS ucfg_p2p_psoc_open(struct wlan_objmgr_psoc *soc) +{ + return p2p_psoc_object_open(soc); +} + +QDF_STATUS ucfg_p2p_psoc_close(struct wlan_objmgr_psoc *soc) +{ + return p2p_psoc_object_close(soc); +} + +QDF_STATUS ucfg_p2p_psoc_start(struct wlan_objmgr_psoc *soc, + struct p2p_start_param *req) +{ + return p2p_psoc_start(soc, req); +} + +QDF_STATUS ucfg_p2p_psoc_stop(struct wlan_objmgr_psoc *soc) +{ + return p2p_psoc_stop(soc); +} + +QDF_STATUS ucfg_p2p_roc_req(struct wlan_objmgr_psoc *soc, + struct p2p_roc_req *roc_req, uint64_t *cookie) +{ + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct p2p_roc_context *roc_ctx; + QDF_STATUS status; + int32_t id; + + p2p_debug("soc:%pK, vdev_id:%d, chanfreq:%d, phy_mode:%d, duration:%d", + soc, roc_req->vdev_id, roc_req->chan_freq, + roc_req->phy_mode, roc_req->duration); + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("P2P soc object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + roc_ctx = qdf_mem_malloc(sizeof(*roc_ctx)); + if (!roc_ctx) + return QDF_STATUS_E_NOMEM; + + status = qdf_idr_alloc(&p2p_soc_obj->p2p_idr, roc_ctx, &id); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(roc_ctx); + p2p_err("failed to alloc idr, status %d", status); + return status; + } + + *cookie = (uint64_t)id; + roc_ctx->p2p_soc_obj = p2p_soc_obj; + roc_ctx->vdev_id = roc_req->vdev_id; + roc_ctx->chan_freq = roc_req->chan_freq; + roc_ctx->phy_mode = roc_req->phy_mode; + roc_ctx->duration = roc_req->duration; + roc_ctx->roc_state = ROC_STATE_IDLE; + roc_ctx->roc_type = USER_REQUESTED; + roc_ctx->id = id; + msg.type = P2P_ROC_REQ; + msg.bodyptr = roc_ctx; + msg.callback = p2p_process_cmd; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(roc_ctx); + qdf_idr_remove(&p2p_soc_obj->p2p_idr, id); + p2p_err("post msg fail:%d", status); + } + p2p_debug("cookie = 0x%llx", *cookie); + + return status; +} + +QDF_STATUS ucfg_p2p_roc_cancel_req(struct wlan_objmgr_psoc *soc, + uint64_t cookie) +{ + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct cancel_roc_context *cancel_roc; + void *roc_ctx = NULL; + QDF_STATUS status; + + p2p_debug("soc:%pK, cookie:0x%llx", soc, cookie); + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_idr_find(&p2p_soc_obj->p2p_idr, + cookie, &roc_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + p2p_debug("invalid id for cookie 0x%llx", cookie); + return QDF_STATUS_E_INVAL; + } + + cancel_roc = qdf_mem_malloc(sizeof(*cancel_roc)); + if (!cancel_roc) + return QDF_STATUS_E_NOMEM; + + + cancel_roc->p2p_soc_obj = p2p_soc_obj; + cancel_roc->cookie = (uintptr_t)roc_ctx; + msg.type = P2P_CANCEL_ROC_REQ; + msg.bodyptr = cancel_roc; + msg.callback = p2p_process_cmd; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, + &msg); + + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(cancel_roc); + p2p_err("post msg fail:%d", status); + } + + return status; +} + +QDF_STATUS ucfg_p2p_cleanup_roc_by_vdev(struct wlan_objmgr_vdev *vdev) +{ + return wlan_p2p_cleanup_roc_by_vdev(vdev, true); +} + +QDF_STATUS ucfg_p2p_cleanup_roc_by_psoc(struct wlan_objmgr_psoc *psoc) +{ + struct p2p_soc_priv_obj *obj; + + if (!psoc) { + p2p_err("null psoc"); + return QDF_STATUS_E_INVAL; + } + + obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_P2P); + if (!obj) { + p2p_err("null p2p soc obj"); + return QDF_STATUS_E_FAILURE; + } + + return p2p_cleanup_roc(obj, NULL, true); +} + +QDF_STATUS ucfg_p2p_cleanup_tx_by_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct p2p_soc_priv_obj *obj; + struct wlan_objmgr_psoc *psoc; + + if (!vdev) { + p2p_debug("null vdev"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + p2p_err("null psoc"); + return QDF_STATUS_E_INVAL; + } + + obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_P2P); + if (!obj) { + p2p_err("null p2p soc obj"); + return QDF_STATUS_E_FAILURE; + } + p2p_del_all_rand_mac_vdev(vdev); + + return p2p_cleanup_tx_sync(obj, vdev); +} + +QDF_STATUS ucfg_p2p_cleanup_tx_by_psoc(struct wlan_objmgr_psoc *psoc) +{ + struct p2p_soc_priv_obj *obj; + + if (!psoc) { + p2p_err("null psoc"); + return QDF_STATUS_E_INVAL; + } + + obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_P2P); + if (!obj) { + p2p_err("null p2p soc obj"); + return QDF_STATUS_E_FAILURE; + } + p2p_del_all_rand_mac_soc(psoc); + + return p2p_cleanup_tx_sync(obj, NULL); +} + +QDF_STATUS ucfg_p2p_mgmt_tx(struct wlan_objmgr_psoc *soc, + struct p2p_mgmt_tx *mgmt_frm, uint64_t *cookie, + struct wlan_objmgr_pdev *pdev) +{ + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct tx_action_context *tx_action; + QDF_STATUS status; + int32_t id; + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("P2P soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + tx_action = qdf_mem_malloc(sizeof(*tx_action)); + if (!tx_action) + return QDF_STATUS_E_NOMEM; + + /* return cookie just for ota ack frames */ + if (mgmt_frm->dont_wait_for_ack) + id = 0; + else { + status = qdf_idr_alloc(&p2p_soc_obj->p2p_idr, + tx_action, &id); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(tx_action); + p2p_err("failed to alloc idr, status :%d", status); + return status; + } + } + + *cookie = (uint64_t)id; + tx_action->p2p_soc_obj = p2p_soc_obj; + tx_action->vdev_id = mgmt_frm->vdev_id; + tx_action->chan_freq = mgmt_frm->chan_freq; + tx_action->duration = mgmt_frm->wait; + tx_action->buf_len = mgmt_frm->len; + tx_action->no_cck = mgmt_frm->no_cck; + tx_action->no_ack = mgmt_frm->dont_wait_for_ack; + tx_action->off_chan = mgmt_frm->off_chan; + tx_action->buf = qdf_mem_malloc(tx_action->buf_len); + if (!(tx_action->buf)) { + qdf_mem_free(tx_action); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(tx_action->buf, mgmt_frm->buf, tx_action->buf_len); + tx_action->nbuf = NULL; + tx_action->id = id; + + p2p_rand_mac_tx(pdev, tx_action); + + p2p_debug("soc:%pK, vdev_id:%d, freq:%d, wait:%d, buf_len:%d, cck:%d, no ack:%d, off chan:%d cookie = 0x%llx", + soc, mgmt_frm->vdev_id, mgmt_frm->chan_freq, + mgmt_frm->wait, mgmt_frm->len, mgmt_frm->no_cck, + mgmt_frm->dont_wait_for_ack, mgmt_frm->off_chan, *cookie); + + msg.type = P2P_MGMT_TX; + msg.bodyptr = tx_action; + msg.callback = p2p_process_cmd; + msg.flush_callback = p2p_msg_flush_callback; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + if (id) + qdf_idr_remove(&p2p_soc_obj->p2p_idr, id); + qdf_mem_free(tx_action->buf); + qdf_mem_free(tx_action); + p2p_err("post msg fail:%d", status); + } + + return status; +} + +QDF_STATUS ucfg_p2p_mgmt_tx_cancel(struct wlan_objmgr_psoc *soc, + struct wlan_objmgr_vdev *vdev, uint64_t cookie) +{ + struct scheduler_msg msg = {0}; + struct p2p_soc_priv_obj *p2p_soc_obj; + struct cancel_roc_context *cancel_tx; + void *tx_ctx; + QDF_STATUS status; + + p2p_debug("soc:%pK, cookie:0x%llx", soc, cookie); + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = qdf_idr_find(&p2p_soc_obj->p2p_idr, + (int32_t)cookie, &tx_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + p2p_debug("invalid id for cookie 0x%llx", cookie); + return QDF_STATUS_E_INVAL; + } + p2p_del_random_mac(soc, wlan_vdev_get_id(vdev), cookie); + + cancel_tx = qdf_mem_malloc(sizeof(*cancel_tx)); + if (!cancel_tx) + return QDF_STATUS_E_NOMEM; + + cancel_tx->p2p_soc_obj = p2p_soc_obj; + cancel_tx->cookie = (uintptr_t)tx_ctx; + msg.type = P2P_MGMT_TX_CANCEL; + msg.bodyptr = cancel_tx; + msg.callback = p2p_process_cmd; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_P2P, + QDF_MODULE_ID_OS_IF, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(cancel_tx); + p2p_err("post msg fail: %d", status); + } + + return status; +} + +bool ucfg_p2p_check_random_mac(struct wlan_objmgr_psoc *soc, uint32_t vdev_id, + uint8_t *random_mac_addr) +{ + return p2p_check_random_mac(soc, vdev_id, random_mac_addr); +} + +QDF_STATUS ucfg_p2p_set_ps(struct wlan_objmgr_psoc *soc, + struct p2p_ps_config *ps_config) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t obj_id; + struct wlan_objmgr_vdev *vdev; + struct p2p_ps_config go_ps_config; + + p2p_debug("soc:%pK, vdev_id:%d, opp_ps:%d, ct_window:%d, count:%d, interval:%d, duration:%d, start:%d, single noa duration:%d, ps_selection:%d", + soc, ps_config->vdev_id, ps_config->opp_ps, + ps_config->ct_window, ps_config->count, + ps_config->interval, ps_config->duration, + ps_config->start, ps_config->single_noa_duration, + ps_config->ps_selection); + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + for (obj_id = 0; obj_id < WLAN_UMAC_PSOC_MAX_VDEVS; obj_id++) { + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(soc, obj_id, + WLAN_P2P_ID); + if (vdev) { + if (is_p2p_ps_allowed(vdev, WLAN_UMAC_COMP_P2P)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + break; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); + p2p_debug("skip p2p set ps vdev %d, NoA is disabled as legacy STA is connected to GO.", + obj_id); + } + } + if (obj_id >= WLAN_UMAC_PSOC_MAX_VDEVS) { + p2p_debug("No GO found!"); + return QDF_STATUS_E_INVAL; + } + go_ps_config = *ps_config; + go_ps_config.vdev_id = obj_id; + + p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc); + if (p2p_ops->set_ps) { + status = p2p_ops->set_ps(soc, &go_ps_config); + p2p_debug("p2p set ps vdev %d, status:%d", obj_id, status); + } + + return status; +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +QDF_STATUS ucfg_p2p_lo_start(struct wlan_objmgr_psoc *soc, + struct p2p_lo_start *p2p_lo_start) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_debug("soc:%pK, vdev_id:%d, ctl_flags:%d, freq:%d, period:%d, interval:%d, count:%d, dev_types_len:%d, probe_resp_len:%d, device_types:%pK, probe_resp_tmplt:%pK", + soc, p2p_lo_start->vdev_id, p2p_lo_start->ctl_flags, + p2p_lo_start->freq, p2p_lo_start->period, + p2p_lo_start->interval, p2p_lo_start->count, + p2p_lo_start->dev_types_len, p2p_lo_start->probe_resp_len, + p2p_lo_start->device_types, p2p_lo_start->probe_resp_tmplt); + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc); + if (p2p_ops->lo_start) { + status = p2p_ops->lo_start(soc, p2p_lo_start); + p2p_debug("p2p lo start, status:%d", status); + } + + return status; +} + +QDF_STATUS ucfg_p2p_lo_stop(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + p2p_debug("soc:%pK, vdev_id:%d", soc, vdev_id); + + if (!soc) { + p2p_err("psoc context passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc); + if (p2p_ops->lo_stop) { + status = p2p_ops->lo_stop(soc, vdev_id); + p2p_debug("p2p lo stop, status:%d", status); + } + + return status; +} +#endif + +QDF_STATUS ucfg_p2p_set_noa(struct wlan_objmgr_psoc *soc, + uint32_t vdev_id, bool disable_noa) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_ops; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + p2p_ops = ucfg_p2p_psoc_get_tx_ops(soc); + if (p2p_ops->set_noa) { + status = p2p_ops->set_noa(soc, vdev_id, disable_noa); + p2p_debug("p2p set noa, status:%d", status); + } + + return status; +} + +QDF_STATUS ucfg_p2p_register_callbacks(struct wlan_objmgr_psoc *soc, + struct p2p_protocol_callbacks *cb_obj) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!soc || !cb_obj) { + p2p_err("psoc: %pK or cb_obj: %pK context passed is NULL", + soc, cb_obj); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(soc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + p2p_soc_obj->p2p_cb = *cb_obj; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_MCC_QUOTA +QDF_STATUS +ucfg_p2p_register_mcc_quota_event_os_if_cb(struct wlan_objmgr_psoc *psoc, + mcc_quota_event_callback cb) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!psoc) { + p2p_err("invalid psoc"); + return QDF_STATUS_E_INVAL; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + p2p_soc_obj->mcc_quota_ev_os_if_cb = cb; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS ucfg_p2p_status_scan(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_status_scan(vdev); +} + +QDF_STATUS ucfg_p2p_status_connect(struct wlan_objmgr_vdev *vdev) +{ + return wlan_p2p_status_connect(vdev); +} + +QDF_STATUS ucfg_p2p_status_disconnect(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_status_disconnect(vdev); +} + +QDF_STATUS ucfg_p2p_status_start_bss(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_status_start_bss(vdev); +} + +QDF_STATUS ucfg_p2p_status_stop_bss(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + p2p_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + return p2p_status_stop_bss(vdev); +} + +bool ucfg_p2p_get_indoor_ch_support(struct wlan_objmgr_psoc *psoc) +{ + struct p2p_soc_priv_obj *p2p_soc_obj; + + if (!psoc) { + p2p_err("invalid psoc"); + return false; + } + + p2p_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_P2P); + if (!p2p_soc_obj) { + p2p_err("p2p soc private object is NULL"); + return false; + } + + return p2p_soc_obj->param.indoor_channel_support; +} + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +bool +ucfg_is_p2p_device_dynamic_set_mac_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + p2p_err("wmi handle is NULL"); + return false; + } + + return wmi_service_enabled(wmi_handle, + wmi_service_p2p_device_update_mac_addr_support); +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h new file mode 100644 index 0000000000..002741f329 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_data_txrx.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in pkt_capture component. This file shall include prototypes of + * pkt_capture data tx and data rx. + * + * Note: This API should be never accessed out of pkt_capture component. + */ + +#ifndef _WLAN_PKT_CAPTURE_DATA_TXRX_H_ +#define _WLAN_PKT_CAPTURE_DATA_TXRX_H_ + +#include "cdp_txrx_cmn_struct.h" +#include +#include +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +#include +#endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +#define IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN 0x0020 +#define IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN 0x4000 +#define IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN 0x0002 +#define IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN 0x0080 +#define IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN 0x0200 +#endif + +#define HAL_TX_PKT_TYPE_11B 1 + +/** + * enum pkt_capture_data_process_type - data pkt types to process + * for packet capture mode + * @TXRX_PROCESS_TYPE_DATA_RX: process RX packets (normal rx + offloaded rx) + * @TXRX_PROCESS_TYPE_DATA_TX: process TX packets (ofloaded tx) + * @TXRX_PROCESS_TYPE_DATA_TX_COMPL: process TX compl packets (normal tx) + */ +enum pkt_capture_data_process_type { + TXRX_PROCESS_TYPE_DATA_RX, + TXRX_PROCESS_TYPE_DATA_TX, + TXRX_PROCESS_TYPE_DATA_TX_COMPL, +}; + +#define TXRX_PKTCAPTURE_PKT_FORMAT_8023 0 +#define TXRX_PKTCAPTURE_PKT_FORMAT_80211 1 + +#define SHORT_PREAMBLE 1 +#define LONG_PREAMBLE 0 + +/** + * pkt_capture_datapkt_process() - process data tx and rx packets + * for pkt capture mode. (normal tx/rx + offloaded tx/rx) + * @vdev_id: vdev id for which packet is captured + * @mon_buf_list: netbuf list + * @type: data process type + * @tid: tid number + * @status: Tx status + * @pkt_format: Frame format + * @bssid: bssid + * @pdev: pdev handle + * @tx_retry_cnt: tx retry count + * + * Return: none + */ +void pkt_capture_datapkt_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, void *pdev, + uint8_t tx_retry_cnt); + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_msdu_process_pkts() - process data rx pkts + * @bssid: bssid + * @head_msdu: pointer to head msdu + * @vdev_id: vdev_id + * @pdev: pdev handle + * @status: capture status + * + * Return: none + */ +void pkt_capture_msdu_process_pkts( + uint8_t *bssid, + qdf_nbuf_t head_msdu, + uint8_t vdev_id, + htt_pdev_handle pdev, uint16_t status); +#else +void pkt_capture_msdu_process_pkts( + uint8_t *bssid, + qdf_nbuf_t head_msdu, + uint8_t vdev_id, + void *psoc, uint16_t status); +#endif + +/** + * pkt_capture_rx_in_order_drop_offload_pkt() - drop offload packets + * @head_msdu: pointer to head msdu + * + * Return: none + */ +void pkt_capture_rx_in_order_drop_offload_pkt(qdf_nbuf_t head_msdu); + +/** + * pkt_capture_rx_in_order_offloaded_pkt() - check offloaded data pkt or not + * @rx_ind_msg: rx_ind_msg + * + * Return: false, if it is not offload pkt + * true, if it is offload pkt + */ +bool pkt_capture_rx_in_order_offloaded_pkt(qdf_nbuf_t rx_ind_msg); + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_offload_deliver_indication_handler() - Handle offload data pkts + * @msg: offload netbuf msg + * @vdev_id: vdev id + * @bssid: bssid + * @pdev: pdev handle + * + * Return: none + */ +void pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev); +#else +/** + * pkt_capture_offload_deliver_indication_handler() - Handle offload data pkts + * @msg: offload netbuf msg + * @vdev_id: vdev id + * @bssid: bssid + * @soc: dp_soc handle + * + * Return: none + */ +void pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, void *soc); +#endif + +/** + * struct pkt_capture_tx_hdr_elem_t - tx packets header structure to + * be used to update radiotap header for packet capture mode + * @timestamp: timestamp + * @preamble: preamble + * @mcs: MCS + * @rate: rate + * @rssi_comb: rssi in dBm + * @nss: if nss 1 means 1ss and 2 means 2ss + * @bw: BW (0=>20 MHz, 1=>40 MHz, 2=>80 MHz, 3=>160 MHz) + * @stbc: STBC + * @sgi: SGI + * @ldpc: LDPC + * @beamformed: beamformed + * @dir: direction rx: 0 and tx: 1 + * @status: tx status + * @tx_retry_cnt: tx retry count + * @framectrl: frame control + * @seqno: sequence number + * @ppdu_id: ppdu_id of msdu + */ +struct pkt_capture_tx_hdr_elem_t { + uint32_t timestamp; + uint8_t preamble; + uint8_t mcs; + uint8_t rate; + uint8_t rssi_comb; + uint8_t nss; + uint8_t bw; + bool stbc; + bool sgi; + bool ldpc; + bool beamformed; + bool dir; + uint8_t status; + uint8_t tx_retry_cnt; + uint16_t framectrl; + uint16_t seqno; + uint32_t ppdu_id; +}; + +/** + * struct pkt_capture_ppdu_stats_q_node - node structure to be enqueued + * in ppdu_stats_q + * @node: list node + * @buf: buffer data received from ppdu_stats + */ +struct pkt_capture_ppdu_stats_q_node { + qdf_list_node_t node; + uint32_t buf[]; +}; + +/** + * pkt_capture_tx_get_txcomplete_data_hdr() - extract Tx data hdr from Tx + * completion for pkt capture mode + * @msg_word: Tx completion htt msg + * @num_msdus: number of msdus + * + * Return: tx data hdr information + */ +struct htt_tx_data_hdr_information *pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus); + +#endif /* End of _WLAN_PKT_CAPTURE_DATA_TXRX_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_main.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_main.h new file mode 100644 index 0000000000..8d82116e9d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_main.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in pkt_capture component. This file shall include prototypes of + * various notification handlers and logging functions. + * + * Note: This API should be never accessed out of pkt_capture component. + */ + +#ifndef _WLAN_PKT_CAPTURE_MAIN_H_ +#define _WLAN_PKT_CAPTURE_MAIN_H_ + +#include +#include "wlan_pkt_capture_priv.h" +#include "wlan_pkt_capture_objmgr.h" +#include "wlan_objmgr_vdev_obj.h" +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +#include "cdp_txrx_stats_struct.h" +#endif + +#define pkt_capture_log(level, args...) \ + QDF_TRACE(QDF_MODULE_ID_PKT_CAPTURE, level, ## args) + +#define pkt_capture_logfl(level, format, args...) \ + pkt_capture_log(level, FL(format), ## args) + +#define pkt_capture_fatal(format, args...) \ + pkt_capture_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define pkt_capture_err(format, args...) \ + pkt_capture_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define pkt_capture_warn(format, args...) \ + pkt_capture_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define pkt_capture_info(format, args...) \ + pkt_capture_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define pkt_capture_debug(format, args...) \ + pkt_capture_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define PKT_CAPTURE_ENTER() pkt_capture_debug("enter") +#define PKT_CAPTURE_EXIT() pkt_capture_debug("exit") + +/** + * enum pkt_capture_tx_status - packet capture tx status + * @pkt_capture_tx_status_ok: successfully sent + acked + * @pkt_capture_tx_status_discard: discard - not sent + * @pkt_capture_tx_status_no_ack: no_ack - sent, but no ack + * + * This enum has tx status types for packet capture mode + */ +enum pkt_capture_tx_status { + pkt_capture_tx_status_ok, + pkt_capture_tx_status_discard, + pkt_capture_tx_status_no_ack, +}; + +/** + * pkt_capture_get_vdev() - Get pkt capture objmgr vdev. + * + * Return: pkt capture objmgr vdev + */ +struct wlan_objmgr_vdev *pkt_capture_get_vdev(void); + +/** + * pkt_capture_vdev_create_notification() - Handler for vdev create notify. + * @vdev: vdev which is going to be created by objmgr + * @arg: argument for notification handler. + * + * Allocate and attach vdev private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg); + +/** + * pkt_capture_vdev_destroy_notification() - Handler for vdev destroy notify. + * @vdev: vdev which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach vdev private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg); + +/** + * pkt_capture_get_mode() - get packet capture mode + * @psoc: pointer to psoc object + * + * Return: enum pkt_capture_mode + */ +enum pkt_capture_mode pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc); + +/** + * pkt_capture_psoc_create_notification() - Handler for psoc create notify. + * @psoc: psoc which is going to be created by objmgr + * @arg: argument for notification handler. + * + * Allocate and attach psoc private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * pkt_capture_psoc_destroy_notification() - Handler for psoc destroy notify. + * @psoc: psoc which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach psoc private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * pkt_capture_register_callbacks - Register packet capture callbacks + * @vdev: pointer to wlan vdev object manager + * @mon_cb: callback to call + * @context: callback context + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context); + +/** + * pkt_capture_deregister_callbacks - De-register packet capture callbacks + * @vdev: pointer to wlan vdev object manager + * + * Return: QDF_STATUS + */ +QDF_STATUS pkt_capture_deregister_callbacks(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_set_pktcap_mode - Set packet capture mode + * @psoc: pointer to psoc object + * @mode: mode to be set + * + * Return: None + */ +void pkt_capture_set_pktcap_mode(struct wlan_objmgr_psoc *psoc, + enum pkt_capture_mode mode); + +/** + * pkt_capture_get_pktcap_mode - Get packet capture mode + * @psoc: pointer to psoc object + * + * Return: enum pkt_capture_mode + */ +enum pkt_capture_mode +pkt_capture_get_pktcap_mode(struct wlan_objmgr_psoc *psoc); + +/** + * pkt_capture_set_pktcap_config - Set packet capture config + * @vdev: pointer to vdev object + * @config: config to be set + * + * Return: None + */ +void pkt_capture_set_pktcap_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config); + +/** + * pkt_capture_get_pktcap_config - Get packet capture config + * @vdev: pointer to vdev object + * + * Return: config value + */ +enum pkt_capture_config +pkt_capture_get_pktcap_config(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_drop_nbuf_list() - drop an nbuf list + * @buf_list: buffer list to be dropepd + * + * Return: number of buffers dropped + */ +uint32_t pkt_capture_drop_nbuf_list(qdf_nbuf_t buf_list); + +/** + * pkt_capture_record_channel() - Update Channel Information + * for packet capture mode + * @vdev: pointer to vdev + * + * Return: None + */ +void pkt_capture_record_channel(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_mon() - Wrapper function to invoke mon cb + * @cb_ctx: packet capture callback context + * @msdu: packet + * @vdev: pointer to vdev + * @ch_freq: channel frequency + * + * Return: None + */ +void pkt_capture_mon(struct pkt_capture_cb_context *cb_ctx, qdf_nbuf_t msdu, + struct wlan_objmgr_vdev *vdev, uint16_t ch_freq); + +/** + * pkt_capture_set_filter - Set packet capture frame filter + * @frame_filter: pkt capture frame filter data + * @vdev: pointer to vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS pkt_capture_set_filter(struct pkt_capture_frame_filter frame_filter, + struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_is_tx_mgmt_enable - Check if tx mgmt frames enabled + * @pdev: pointer to pdev + * + * Return: bool + */ +bool pkt_capture_is_tx_mgmt_enable(struct wlan_objmgr_pdev *pdev); + +/** + * pkt_capture_is_frame_filter_set - Check if filter type set by user and packet + * type matches + * @buf: netbuf + * @frame_filter: filter set by user via vendor command + * @direction: Tx or Rx + * + * Return: bool + */ +bool +pkt_capture_is_frame_filter_set(qdf_nbuf_t buf, + struct pkt_capture_frame_filter *frame_filter, + bool direction); + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_get_pktcap_mode_v2 - Get packet capture mode + * + * Return: enum pkt_capture_mode + */ +enum pkt_capture_mode +pkt_capture_get_pktcap_mode_v2(void); + +/** + * pkt_capture_callback() - callback function for dp wdi events + * @soc: dp_soc handle + * @event: wdi event + * @log_data: nbuf data + * @peer_id: peer id + * @status: status + * + * Return: None + */ +void pkt_capture_callback(void *soc, enum WDI_EVENT event, void *log_data, + u_int16_t peer_id, uint32_t status); +#endif +#endif /* end of _WLAN_PKT_CAPTURE_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_mgmt_txrx.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_mgmt_txrx.h new file mode 100644 index 0000000000..86e3156f2a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_mgmt_txrx.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare mgmt txrx APIs which shall be used internally only + * in pkt_capture component. + * Note: These APIs should be never accessed out of pkt_capture component. + */ + +#ifndef _WLAN_PKT_CAPTURE_MGMT_TXRX_H_ +#define _WLAN_PKT_CAPTURE_MGMT_TXRX_H_ + +#include "wlan_pkt_capture_public_structs.h" + +#define PKTCAPTURE_PKT_FORMAT_8023 (0) +#define PKTCAPTURE_PKT_FORMAT_80211 (1) +#define WLAN_INVALID_TID (31) +#define RESERVE_BYTES (100) +#define RATE_LIMIT (16) +#define INVALID_RSSI_FOR_TX (-128) +#define PKTCAPTURE_RATECODE_CCK (1) + +/** + * pkt_capture_process_mgmt_tx_data() - process management tx packets + * @pdev: pointer to pdev object + * @params: management offload event params + * @nbuf: netbuf + * @status: status + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_process_mgmt_tx_data(struct wlan_objmgr_pdev *pdev, + struct mgmt_offload_event_params *params, + qdf_nbuf_t nbuf, + uint8_t status); +/** + * pkt_capture_mgmt_tx() - process mgmt tx completion + * for pkt capture mode + * @pdev: pointer to pdev object + * @nbuf: netbuf + * @chan_freq: channel freq + * @preamble_type: preamble_type + * + * Return: none + */ +void pkt_capture_mgmt_tx(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t nbuf, + uint16_t chan_freq, + uint8_t preamble_type); + +/** + * pkt_capture_mgmt_tx_completion() - process mgmt tx completion + * for pkt capture mode + * @pdev: pointer to pdev object + * @desc_id: desc_id + * @status: status + * @params: management offload event params + * + * Return: none + */ +void +pkt_capture_mgmt_tx_completion(struct wlan_objmgr_pdev *pdev, + uint32_t desc_id, + uint32_t status, + struct mgmt_offload_event_params *params); + +/** + * pkt_capture_mgmt_rx_ops() - Register packet capture mgmt rx ops + * @psoc: psoc context + * @is_register: register if true, unregister if false + * + * This function registers or deregisters rx callback + * to mgmt txrx component. + * + * Return: QDF_STATUS + */ +QDF_STATUS pkt_capture_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, + bool is_register); + +/** + * pkt_capture_mgmt_status_map() - map Tx status for MGMT packets + * with packet capture Tx status + * @status: Tx status + * + * Return: pkt_capture_tx_status enum + */ +enum pkt_capture_tx_status +pkt_capture_mgmt_status_map(uint8_t status); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h new file mode 100644 index 0000000000..bac764d886 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_mon_thread.h @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare APIs which shall be used for monitor thread access. + */ + +#ifndef _WLAN_PKT_CAPTURE_MON_THREAD_H_ +#define _WLAN_PKT_CAPTURE_MON_THREAD_H_ + +#include "wlan_pkt_capture_main.h" + +#define PKT_CAPTURE_RX_POST_EVENT 0x01 +#define PKT_CAPTURE_RX_SUSPEND_EVENT 0x02 +#define PKT_CAPTURE_RX_SHUTDOWN_EVENT 0x04 +#define PKT_CAPTURE_REGISTER_EVENT 0x08 + +/* + * Maximum number of packets to be allocated for + * Packet Capture Monitor thread. + */ +#define MAX_MON_PKT_SIZE 4000 + +/* timeout in msec to wait for mon thread to suspend */ +#define PKT_CAPTURE_SUSPEND_TIMEOUT 200 + +typedef void (*pkt_capture_mon_thread_cb)( + void *context, void *ppdev, void *monpkt, + uint8_t vdev_id, uint8_t tid, + uint16_t status, bool pkt_format, + uint8_t *bssid, + uint8_t tx_retry_cnt); + +/** + * struct pkt_capture_mon_pkt - mon packet wrapper for mon data from TXRX + * @list: List for storing mon packets + * @context: Callback context + * @pdev: pointer to pdev handle + * @monpkt: Mon skb + * @vdev_id: Vdev id to which this packet is destined + * @tid: Tid of mon packet + * @status: Tx packet status + * @pkt_format: Mon packet format, 0 = 802.3 format , 1 = 802.11 format + * @bssid: bssid + * @tx_retry_cnt: tx retry count + * @callback: Mon callback + */ +struct pkt_capture_mon_pkt { + struct list_head list; + void *context; + void *pdev; + void *monpkt; + uint8_t vdev_id; + uint8_t tid; + uint16_t status; + bool pkt_format; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t tx_retry_cnt; + pkt_capture_mon_thread_cb callback; +}; + +/** + * struct pkt_capture_mon_context - packet capture mon thread context + * @mon_thread_lock: MON thread lock + * @mon_thread: MON thread handle + * @mon_start_event: Handle of Event for MON thread to signal startup + * @suspend_mon_event: Completion to suspend packet capture MON thread + * @resume_mon_event: Completion to resume packet capture MON thread + * @mon_shutdown: Completion for packet capture MON thread shutdown + * @mon_register_event: Completion for packet capture register + * @mon_wait_queue: Waitq for packet capture MON thread + * @mon_event_flag: Mon event flag + * @mon_thread_queue: MON buffer queue + * @mon_queue_lock: Spinlock to synchronize between tasklet and thread + * @mon_pkt_freeq_lock: Lock to synchronize free buffer queue access + * @mon_pkt_freeq: Free message queue for packet capture MON processing + * @is_mon_thread_suspended: flag to check mon thread suspended or not + */ +struct pkt_capture_mon_context { + /* MON thread lock */ + spinlock_t mon_thread_lock; + struct task_struct *mon_thread; + struct completion mon_start_event; + struct completion suspend_mon_event; + struct completion resume_mon_event; + struct completion mon_shutdown; + struct completion mon_register_event; + wait_queue_head_t mon_wait_queue; + unsigned long mon_event_flag; + struct list_head mon_thread_queue; + + /* Spinlock to synchronize between tasklet and thread */ + spinlock_t mon_queue_lock; + + /* Lock to synchronize free buffer queue access */ + spinlock_t mon_pkt_freeq_lock; + + struct list_head mon_pkt_freeq; + bool is_mon_thread_suspended; +}; + +/** + * struct radiotap_header - base radiotap header + * @it_version: radiotap version, always 0 + * @it_pad: padding (or alignment) + * @it_len: overall radiotap header length + * @it_present: (first) present word + */ +struct radiotap_header { + uint8_t it_version; + uint8_t it_pad; + __le16 it_len; + __le32 it_present; +} __packed; + +/** + * pkt_capture_suspend_mon_thread() - suspend packet capture mon thread + * @vdev: pointer to vdev object manager + * + * Return: 0 on success, -EINVAL on failure + */ +int pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_resume_mon_thread() - resume packet capture mon thread + * @vdev: pointer to vdev object manager + * + * Resume packet capture MON thread by completing RX thread resume event. + * + * Return: None + */ +void pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_drop_monpkt() - API to drop pending mon packets + * @mon_ctx: pointer to packet capture mon context + * + * This api drops all the pending packets in the queue. + * + * Return: None + */ +void pkt_capture_drop_monpkt(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_indicate_monpkt() - API to Indicate rx data packet + * @vdev: pointer to vdev object manager + * @pkt: MON pkt pointer containing to mon data message buffer + * + * Return: None + */ +void pkt_capture_indicate_monpkt(struct wlan_objmgr_vdev *vdev, + struct pkt_capture_mon_pkt *pkt); + +/** + * pkt_capture_wakeup_mon_thread() - wakeup packet capture mon thread + * @vdev: pointer to vdev object + * + * This api wake up pkt_capture_mon_thread() to process pkt. + * + * Return: None + */ +void pkt_capture_wakeup_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_close_mon_thread() - close packet capture MON thread + * @mon_ctx: pointer to packet capture mon context + * + * This api closes packet capture MON thread. + * + * Return: None + */ +void pkt_capture_close_mon_thread(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_open_mon_thread() - open packet capture MON thread + * @mon_ctx: pointer to packet capture mon context + * + * This api opens the packet capture MON thread. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_open_mon_thread(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_alloc_mon_thread() - alloc resources for + * packet capture MON thread + * @mon_ctx: pointer to packet capture mon context + * + * This api alloc resources for packet capture MON thread. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pkt_capture_alloc_mon_thread(struct pkt_capture_mon_context *mon_ctx); + +/** + * pkt_capture_alloc_mon_pkt() - API to return next available mon packet + * @vdev: pointer to vdev object manager + * + * This api returns next available mon packet buffer used for mon data + * processing. + * + * Return: Pointer to pkt_capture_mon_pkt + */ +struct pkt_capture_mon_pkt * +pkt_capture_alloc_mon_pkt(struct wlan_objmgr_vdev *vdev); + +/** + * pkt_capture_free_mon_pkt_freeq() - free mon packet free queue + * @mon_ctx: pointer to packet capture mon context + * + * This API does mem free of the buffers available in free mon packet + * queue which is used for mon Data processing. + * + * Return: None + */ +void pkt_capture_free_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx); +#endif /* _WLAN_PKT_CAPTURE_MON_THREAD_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_objmgr.h new file mode 100644 index 0000000000..4da27aed72 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_objmgr.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains various object manager related wrappers and helpers + */ + +#ifndef _WLAN_PKT_CAPTURE_OBJMGR_H +#define _WLAN_PKT_CAPTURE_OBJMGR_H + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_global_obj.h" + +/** + * pkt_capture_vdev_get_ref() - Wrapper to increment pkt_capture ref count + * @vdev: vdev object + * + * Wrapper for pkt_capture to increment ref count after checking valid + * object state. + * + * Return: SUCCESS/FAILURE + */ +static inline +QDF_STATUS pkt_capture_vdev_get_ref(struct wlan_objmgr_vdev *vdev) +{ + return wlan_objmgr_vdev_try_get_ref(vdev, WLAN_PKT_CAPTURE_ID); +} + +/** + * pkt_capture_vdev_put_ref() - Wrapper to decrement pkt_capture ref count + * @vdev: vdev object + * + * Wrapper for pkt_capture to decrement ref count of vdev. + * + * Return: SUCCESS/FAILURE + */ +static inline +void pkt_capture_vdev_put_ref(struct wlan_objmgr_vdev *vdev) +{ + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); +} + +/** + * pkt_capture_vdev_get_priv() - Wrapper to retrieve vdev priv obj + * @vdev: vdev pointer + * + * Wrapper for pkt_capture to get vdev private object pointer. + * + * Return: Private object of vdev + */ +static inline struct pkt_capture_vdev_priv * +pkt_capture_vdev_get_priv(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + + vdev_priv = wlan_objmgr_vdev_get_comp_private_obj( + vdev, + WLAN_UMAC_COMP_PKT_CAPTURE); + QDF_BUG(vdev_priv); + + return vdev_priv; +} + +/** + * pkt_capture_psoc_get_ref() - Wrapper to increment pkt_capture ref count + * @psoc: psoc object + * + * Wrapper for pkt_capture to increment ref count after checking valid + * object state. + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS pkt_capture_psoc_get_ref(struct wlan_objmgr_psoc *psoc) +{ + return wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PKT_CAPTURE_ID); +} + +/** + * pkt_capture_psoc_put_ref() - Wrapper to decrement pkt_capture ref count + * @psoc: psoc object + * + * Wrapper for pkt_capture to decrement ref count of psoc. + * + * Return: None + */ +static inline +void pkt_capture_psoc_put_ref(struct wlan_objmgr_psoc *psoc) +{ + wlan_objmgr_psoc_release_ref(psoc, WLAN_PKT_CAPTURE_ID); +} + +/** + * pkt_capture_psoc_get_priv(): Wrapper to retrieve psoc priv obj + * @psoc: psoc pointer + * + * Wrapper for pkt_capture to get psoc private object pointer. + * + * Return: pkt_capture psoc private object + */ +static inline struct pkt_psoc_priv * +pkt_capture_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct pkt_psoc_priv *psoc_priv; + + psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_PKT_CAPTURE); + QDF_BUG(psoc_priv); + + return psoc_priv; +} +#endif /* _WLAN_PKT_CAPTURE_OBJMGR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h new file mode 100644 index 0000000000..0000422130 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/inc/wlan_pkt_capture_priv.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in pkt_capture component. This file shall include prototypes of + * pkt_capture parsing and send logic. + * + * Note: This API should be never accessed out of pkt_capture component. + */ + +#ifndef _WLAN_PKT_CAPTURE_PRIV_STRUCT_H_ +#define _WLAN_PKT_CAPTURE_PRIV_STRUCT_H_ + +#include "wlan_pkt_capture_objmgr.h" +#include "wlan_pkt_capture_public_structs.h" +#include "wlan_pkt_capture_mon_thread.h" + +/** + * struct pkt_capture_cfg - struct to store config values + * @pkt_capture_mode: packet capture mode + * @pkt_capture_config: config for trigger, qos and beacon frames + */ +struct pkt_capture_cfg { + enum pkt_capture_mode pkt_capture_mode; + enum pkt_capture_config pkt_capture_config; +}; + +/** + * struct pkt_capture_cb_context - packet capture callback context + * @mon_cb: monitor callback function pointer + * @mon_ctx: monitor callback context + */ +struct pkt_capture_cb_context { + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t); + void *mon_ctx; +}; + +/** + * struct pkt_capture_vdev_priv - Private object to be stored in vdev + * @vdev: pointer to vdev object + * @mon_ctx: pointer to packet capture mon context + * @cb_ctx: pointer to packet capture mon callback context + * @frame_filter: config filter set by vendor command + * @cfg_params: packet capture config params + * @ppdu_stats_q: list used for storing smu related ppdu stats + * @lock_q: spinlock for ppdu_stats q + * @tx_nss: nss of tx data packets received from ppdu stats + * @last_freq: Last connected freq + * @curr_freq: current connected freq + * @rx_vht_sgi: guard interval of vht rx packet + * @wake_lock: wake lock for packet capture + * @runtime_lock: runtime lock for packet capture + */ +struct pkt_capture_vdev_priv { + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_mon_context *mon_ctx; + struct pkt_capture_cb_context *cb_ctx; + struct pkt_capture_frame_filter frame_filter; + struct pkt_capture_cfg cfg_params; + qdf_list_t ppdu_stats_q; + qdf_spinlock_t lock_q; + uint8_t tx_nss; + qdf_freq_t last_freq; + qdf_freq_t curr_freq; + uint8_t rx_vht_sgi; + qdf_wake_lock_t wake_lock; + qdf_runtime_lock_t runtime_lock; +}; + +/** + * struct pkt_psoc_priv - Private object to be stored in psoc + * @psoc: pointer to psoc object + * @cfg_param: INI config params for packet capture + * @cb_obj: struct containing callback pointers + * @rx_ops: rx ops + * @tx_ops: tx ops + */ +struct pkt_psoc_priv { + struct wlan_objmgr_psoc *psoc; + struct pkt_capture_cfg cfg_param; + struct pkt_capture_callbacks cb_obj; + struct wlan_pkt_capture_rx_ops rx_ops; + struct wlan_pkt_capture_tx_ops tx_ops; +}; +#endif /* End of _WLAN_PKT_CAPTURE_PRIV_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c new file mode 100644 index 0000000000..e61c18103e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c @@ -0,0 +1,1735 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement various notification handlers which are accessed + * internally in pkt_capture component only. + */ + +#include +#include +#include +#include +#include +#include +#include "wlan_policy_mgr_ucfg.h" +#include "hal_rx.h" +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +#include "dp_internal.h" +#include "cds_utils.h" +#include "htt_ppdu_stats.h" +#include +#endif + +#define RESERVE_BYTES (100) + +/** + * pkt_capture_txrx_status_map() - map Tx status for data packets + * with packet capture Tx status + * @status: Tx status + * + * Return: pkt_capture_tx_status enum + */ +static enum pkt_capture_tx_status +pkt_capture_txrx_status_map(uint8_t status) +{ + enum pkt_capture_tx_status tx_status; + + switch (status) { + case htt_tx_status_ok: + tx_status = pkt_capture_tx_status_ok; + break; + case htt_tx_status_no_ack: + tx_status = pkt_capture_tx_status_no_ack; + break; + default: + tx_status = pkt_capture_tx_status_discard; + break; + } + + return tx_status; +} + +/** + * pkt_capture_get_tx_rate() - get tx rate for tx packet + * @preamble_type: preamble type + * @rate: rate code + * @preamble: preamble + * + * Return: rate + */ +static unsigned char pkt_capture_get_tx_rate( + uint8_t preamble_type, + uint8_t rate, + uint8_t *preamble) +{ + char ret = 0x0; + *preamble = LONG_PREAMBLE; + + if (preamble_type == 0) { + switch (rate) { + case 0x0: + ret = 0x60; + break; + case 0x1: + ret = 0x30; + break; + case 0x2: + ret = 0x18; + break; + case 0x3: + ret = 0x0c; + break; + case 0x4: + ret = 0x6c; + break; + case 0x5: + ret = 0x48; + break; + case 0x6: + ret = 0x24; + break; + case 0x7: + ret = 0x12; + break; + default: + break; + } + } else if (preamble_type == 1) { + switch (rate) { + case 0x0: + ret = 0x16; + *preamble = LONG_PREAMBLE; + break; + case 0x1: + ret = 0xB; + *preamble = LONG_PREAMBLE; + break; + case 0x2: + ret = 0x4; + *preamble = LONG_PREAMBLE; + break; + case 0x3: + ret = 0x2; + *preamble = LONG_PREAMBLE; + break; + case 0x4: + ret = 0x16; + *preamble = SHORT_PREAMBLE; + break; + case 0x5: + ret = 0xB; + *preamble = SHORT_PREAMBLE; + break; + case 0x6: + ret = 0x4; + *preamble = SHORT_PREAMBLE; + break; + default: + break; + } + } else { + qdf_print("Invalid rate info\n"); + } + return ret; +} + +/** + * pkt_capture_tx_get_phy_info() - get phy info for tx packets for pkt + * capture mode(normal tx + offloaded tx) to prepare radiotap header + * @pktcapture_hdr: tx data header + * @tx_status: tx status to be updated with phy info + * + * Return: none + */ +static void pkt_capture_tx_get_phy_info( + struct pkt_capture_tx_hdr_elem_t *pktcapture_hdr, + struct mon_rx_status *tx_status) +{ + uint8_t preamble = 0; + uint8_t preamble_type = pktcapture_hdr->preamble; + uint8_t mcs = 0; + + switch (preamble_type) { + case 0x0: + case 0x1: + /* legacy */ + tx_status->rate = pkt_capture_get_tx_rate( + preamble_type, + pktcapture_hdr->rate, + &preamble); + break; + case 0x2: + tx_status->ht_flags = 1; + if (pktcapture_hdr->nss == 2) + mcs = 8 + pktcapture_hdr->mcs; + else + mcs = pktcapture_hdr->mcs; + + tx_status->ht_mcs = mcs; + break; + case 0x3: + tx_status->vht_flags = 1; + mcs = pktcapture_hdr->mcs; + tx_status->vht_flag_values3[0] = + mcs << 0x4 | (pktcapture_hdr->nss); + tx_status->vht_flag_values2 = pktcapture_hdr->bw; + break; + case 0x4: + tx_status->he_flags = 1; + tx_status->he_data1 |= + IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_CODING_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_STBC_KNOWN; + tx_status->he_data2 |= IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN; + tx_status->he_data3 |= (pktcapture_hdr->mcs << 0x8) | + (pktcapture_hdr->ldpc << 0xd) | + (pktcapture_hdr->stbc << 0xf); + tx_status->he_data5 |= + (pktcapture_hdr->bw | (pktcapture_hdr->sgi << 0x4)); + tx_status->he_data6 |= pktcapture_hdr->nss; + default: + break; + } + + if (preamble_type != HAL_TX_PKT_TYPE_11B) + tx_status->ofdm_flag = 1; + else + tx_status->cck_flag = 1; + + tx_status->mcs = mcs; + tx_status->bw = pktcapture_hdr->bw; + tx_status->nr_ant = pktcapture_hdr->nss; + tx_status->nss = pktcapture_hdr->nss; + tx_status->is_stbc = pktcapture_hdr->stbc; + tx_status->sgi = pktcapture_hdr->sgi; + tx_status->ldpc = pktcapture_hdr->ldpc; + tx_status->beamformed = pktcapture_hdr->beamformed; + tx_status->rtap_flags |= ((preamble == 1) ? BIT(1) : 0); +} + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_update_tx_status() - tx status for tx packets, for + * pkt capture mode(normal tx + offloaded tx) to prepare radiotap header + * @pdev: device handler + * @tx_status: tx status to be updated + * @pktcapture_hdr: tx data header + * + * Return: none + */ +static void +pkt_capture_update_tx_status( + htt_pdev_handle pdev, + struct mon_rx_status *tx_status, + struct pkt_capture_tx_hdr_elem_t *pktcapture_hdr) +{ + struct mon_channel *ch_info = &pdev->mon_ch_info; + + tx_status->tsft = (u_int64_t)(pktcapture_hdr->timestamp); + tx_status->chan_freq = ch_info->ch_freq; + tx_status->chan_num = ch_info->ch_num; + + pkt_capture_tx_get_phy_info(pktcapture_hdr, tx_status); + + if (pktcapture_hdr->preamble == 0) + tx_status->ofdm_flag = 1; + else if (pktcapture_hdr->preamble == 1) + tx_status->cck_flag = 1; + + tx_status->ant_signal_db = pktcapture_hdr->rssi_comb; + tx_status->rssi_comb = pktcapture_hdr->rssi_comb; + tx_status->tx_status = pktcapture_hdr->status; + tx_status->tx_retry_cnt = pktcapture_hdr->tx_retry_cnt; + tx_status->add_rtap_ext = true; +} +#else +static void +pkt_capture_update_tx_status( + void *context, + struct mon_rx_status *tx_status, + struct pkt_capture_tx_hdr_elem_t *pktcapture_hdr) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev = context; + htt_ppdu_stats_for_smu_tlv *smu; + struct wlan_objmgr_psoc *psoc; + struct pkt_capture_ppdu_stats_q_node *q_node; + qdf_list_node_t *node; + cdp_config_param_type val; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("Failed to get psoc"); + return; + } + + if (!pdev) { + pkt_capture_err("pdev is NULL"); + return; + } + + if (!cdp_txrx_get_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_CHANNEL, &val)) + tx_status->chan_num = val.cdp_pdev_param_monitor_chan; + + if (!cdp_txrx_get_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_FREQUENCY, &val)) + tx_status->chan_freq = val.cdp_pdev_param_mon_freq; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (qdf_unlikely(!vdev_priv)) + goto skip_ppdu_stats; + + /* Fill the nss received from ppdu_stats */ + pktcapture_hdr->nss = vdev_priv->tx_nss; + + /* Remove the ppdu stats from front of list and fill it in tx_status */ + qdf_spin_lock_bh(&vdev_priv->lock_q); + if (QDF_STATUS_SUCCESS == + qdf_list_remove_front(&vdev_priv->ppdu_stats_q, &node)) { + qdf_spin_unlock_bh(&vdev_priv->lock_q); + q_node = qdf_container_of( + node, struct pkt_capture_ppdu_stats_q_node, node); + smu = (htt_ppdu_stats_for_smu_tlv *)(q_node->buf); + tx_status->prev_ppdu_id = smu->ppdu_id; + tx_status->start_seq = smu->start_seq; + tx_status->tid = smu->tid_num; + + if (smu->win_size == 8) + qdf_mem_copy(tx_status->ba_bitmap, smu->ba_bitmap, + 8 * sizeof(uint32_t)); + else if (smu->win_size == 2) + qdf_mem_copy(tx_status->ba_bitmap, smu->ba_bitmap, + 2 * sizeof(uint32_t)); + + qdf_mem_free(q_node); + } else { + qdf_spin_unlock_bh(&vdev_priv->lock_q); + } + +skip_ppdu_stats: + pkt_capture_tx_get_phy_info(pktcapture_hdr, tx_status); + + tx_status->tsft = (u_int64_t)(pktcapture_hdr->timestamp); + tx_status->ant_signal_db = pktcapture_hdr->rssi_comb; + tx_status->rssi_comb = pktcapture_hdr->rssi_comb; + tx_status->tx_status = pktcapture_hdr->status; + tx_status->tx_retry_cnt = pktcapture_hdr->tx_retry_cnt; + tx_status->ppdu_id = pktcapture_hdr->ppdu_id; + tx_status->add_rtap_ext = true; + tx_status->add_rtap_ext2 = true; +} +#endif + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_rx_convert8023to80211() - convert 802.3 packet to 802.11 + * format from rx desc + * @bssid: bssid + * @msdu: netbuf + * @desc: rx desc + * + * Return: none + */ +static void +pkt_capture_rx_convert8023to80211(uint8_t *bssid, qdf_nbuf_t msdu, void *desc) +{ + struct ethernet_hdr_t *eth_hdr; + struct llc_snap_hdr_t *llc_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + uint16_t seq_no; + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + uint16_t ether_type; + + struct htt_host_rx_desc_base *rx_desc = desc; + + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + *(uint16_t *)wh->i_dur = 0; + + new_hdsize = 0; + + /* DA , BSSID , SA */ + qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, bssid, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + + wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; + + if (rx_desc->attention.more_data) + wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; + + if (rx_desc->attention.power_mgmt) + wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; + + if (rx_desc->attention.fragment) + wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; + + if (rx_desc->attention.order) + wh->i_fc[1] |= IEEE80211_FC1_ORDER; + + if (rx_desc->mpdu_start.retry) + wh->i_fc[1] |= IEEE80211_FC1_RETRY; + + seq_no = rx_desc->mpdu_start.seq_num; + seq_no = (seq_no << IEEE80211_SEQ_SEQ_SHIFT) & IEEE80211_SEQ_SEQ_MASK; + qdf_mem_copy(wh->i_seq, &seq_no, sizeof(seq_no)); + + new_hdsize = sizeof(struct ieee80211_frame); + + if (rx_desc->attention.non_qos == 0) { + qos_cntl = + (struct ieee80211_qoscntl *)(localbuf + new_hdsize); + qos_cntl->i_qos[0] = + (rx_desc->mpdu_start.tid & IEEE80211_QOS_TID); + wh->i_fc[0] |= QDF_IEEE80211_FC0_SUBTYPE_QOS; + + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + } + + /* + * Prepare llc Header + */ + llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize); + ether_type = (eth_hdr->ethertype[0] << 8) | + (eth_hdr->ethertype[1]); + if (ether_type >= ETH_P_802_3_MIN) { + qdf_mem_copy(llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = + BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } + + /* + * Remove 802.3 Header by adjusting the head + */ + qdf_nbuf_pull_head(msdu, hdsize); + + /* + * Adjust the head and prepare 802.11 Header + */ + qdf_nbuf_push_head(msdu, new_hdsize); + qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize); +} +#else +static void +pkt_capture_rx_convert8023to80211(hal_soc_handle_t hal_soc_hdl, + qdf_nbuf_t msdu, void *desc) +{ + struct ethernet_hdr_t *eth_hdr; + struct llc_snap_hdr_t *llc_hdr; + struct ieee80211_frame *wh; + uint8_t *pwh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + static uint8_t first_msdu_hdr[sizeof(struct ieee80211_frame)]; + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + uint16_t ether_type; + + uint32_t tid = 0; + + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + + wh = (struct ieee80211_frame *)localbuf; + + new_hdsize = sizeof(struct ieee80211_frame); + + /* + * Only first msdu in mpdu has rx_tlv_hdr(802.11 hdr) filled by HW, so + * copy the 802.11 hdr to all other msdu's which are received in + * single mpdu from first msdu. + */ + if (qdf_nbuf_is_rx_chfrag_start(msdu)) { + pwh = hal_rx_desc_get_80211_hdr(hal_soc_hdl, desc); + qdf_mem_copy(first_msdu_hdr, pwh, + sizeof(struct ieee80211_frame)); + } + + qdf_mem_copy(localbuf, first_msdu_hdr, new_hdsize); + + /* Flush the cached 802.11 hdr once last msdu in mpdu is received */ + if (qdf_nbuf_is_rx_chfrag_end(msdu)) + qdf_mem_zero(first_msdu_hdr, sizeof(struct ieee80211_frame)); + + wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA; + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + + if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + qos_cntl = + (struct ieee80211_qoscntl *)(localbuf + new_hdsize); + tid = hal_rx_mpdu_start_tid_get(hal_soc_hdl, desc); + qos_cntl->i_qos[0] = (tid & IEEE80211_QOS_TID); + wh->i_fc[0] |= QDF_IEEE80211_FC0_SUBTYPE_QOS; + + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + } + + /* + * Prepare llc Header + */ + + llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize); + ether_type = (eth_hdr->ethertype[0] << 8) | + (eth_hdr->ethertype[1]); + if (ether_type >= ETH_P_802_3_MIN) { + qdf_mem_copy(llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = + BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } + + /* + * Remove 802.3 Header by adjusting the head + */ + qdf_nbuf_pull_head(msdu, hdsize); + + /* + * Adjust the head and prepare 802.11 Header + */ + qdf_nbuf_push_head(msdu, new_hdsize); + qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize); +} +#endif + +void pkt_capture_rx_in_order_drop_offload_pkt(qdf_nbuf_t head_msdu) +{ + while (head_msdu) { + qdf_nbuf_t msdu = head_msdu; + + head_msdu = qdf_nbuf_next(head_msdu); + qdf_nbuf_free(msdu); + } +} + +bool pkt_capture_rx_in_order_offloaded_pkt(qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *)qdf_nbuf_data(rx_ind_msg); + + /* check if it is for offloaded data pkt */ + return HTT_RX_IN_ORD_PADDR_IND_PKT_CAPTURE_MODE_IS_MONITOR_SET + (*(msg_word + 1)); +} + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +void pkt_capture_msdu_process_pkts( + uint8_t *bssid, + qdf_nbuf_t head_msdu, uint8_t vdev_id, + htt_pdev_handle pdev, uint16_t status) +{ + qdf_nbuf_t loop_msdu, pktcapture_msdu; + qdf_nbuf_t msdu, prev = NULL; + + pktcapture_msdu = NULL; + loop_msdu = head_msdu; + while (loop_msdu) { + msdu = qdf_nbuf_copy(loop_msdu); + + if (msdu) { + qdf_nbuf_push_head(msdu, + HTT_RX_STD_DESC_RESERVATION); + qdf_nbuf_set_next(msdu, NULL); + + if (!(pktcapture_msdu)) { + pktcapture_msdu = msdu; + prev = msdu; + } else { + qdf_nbuf_set_next(prev, msdu); + prev = msdu; + } + } + loop_msdu = qdf_nbuf_next(loop_msdu); + } + + if (!pktcapture_msdu) + return; + + pkt_capture_datapkt_process( + vdev_id, pktcapture_msdu, + TXRX_PROCESS_TYPE_DATA_RX, 0, 0, + TXRX_PKTCAPTURE_PKT_FORMAT_8023, + bssid, pdev, 0); +} +#else +#define RX_OFFLOAD_PKT 1 +void pkt_capture_msdu_process_pkts( + uint8_t *bssid, qdf_nbuf_t head_msdu, + uint8_t vdev_id, void *psoc, uint16_t status) +{ + qdf_nbuf_t loop_msdu, pktcapture_msdu, offload_msdu = NULL; + qdf_nbuf_t msdu, prev = NULL; + + pktcapture_msdu = NULL; + loop_msdu = head_msdu; + while (loop_msdu) { + msdu = qdf_nbuf_copy(loop_msdu); + + if (msdu) { + qdf_nbuf_set_next(msdu, NULL); + + if (!(pktcapture_msdu)) { + pktcapture_msdu = msdu; + prev = msdu; + } else { + qdf_nbuf_set_next(prev, msdu); + prev = msdu; + } + } + if (status == RX_OFFLOAD_PKT) + offload_msdu = loop_msdu; + loop_msdu = qdf_nbuf_next(loop_msdu); + + /* Free offload msdu as it is delivered only to pkt capture */ + if (offload_msdu) { + qdf_nbuf_free(offload_msdu); + offload_msdu = NULL; + } + } + + if (!pktcapture_msdu) + return; + + pkt_capture_datapkt_process( + vdev_id, pktcapture_msdu, + TXRX_PROCESS_TYPE_DATA_RX, 0, 0, + TXRX_PKTCAPTURE_PKT_FORMAT_8023, + bssid, psoc, 0); +} +#endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_dp_rx_skip_tlvs() - Skip TLVs len + L2 hdr_offset, save in nbuf + * @soc: DP soc context + * @nbuf: nbuf to be updated + * @l3_padding: l3_padding + * + * Return: None + */ +static void pkt_capture_dp_rx_skip_tlvs(struct dp_soc *soc, qdf_nbuf_t nbuf, + uint32_t l3_padding) +{ + QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(nbuf) = l3_padding; + qdf_nbuf_pull_head(nbuf, l3_padding + soc->rx_pkt_tlv_size); +} + +/** + * pkt_capture_rx_get_phy_info() - Get phy info + * @context: objmgr vdev + * @psoc: dp_soc handle + * @rx_tlv_hdr: Pointer to struct rx_pkt_tlvs + * @rx_status: Pointer to struct mon_rx_status + * + * Return: none + */ +static void pkt_capture_rx_get_phy_info(void *context, void *psoc, + uint8_t *rx_tlv_hdr, + struct mon_rx_status *rx_status) +{ + uint8_t preamble = 0; + uint8_t preamble_type; + uint16_t mcs = 0, nss = 0, sgi = 0, bw = 0; + uint8_t beamformed = 0; + bool is_stbc = 0, ldpc = 0; + struct dp_soc *soc = psoc; + hal_soc_handle_t hal_soc; + struct wlan_objmgr_vdev *vdev = context; + struct pkt_capture_vdev_priv *vdev_priv; + + hal_soc = soc->hal_soc; + preamble_type = hal_rx_tlv_get_pkt_type(hal_soc, rx_tlv_hdr); + nss = hal_rx_msdu_start_nss_get(hal_soc, rx_tlv_hdr); /* NSS */ + bw = hal_rx_tlv_bw_get(hal_soc, rx_tlv_hdr); + mcs = hal_rx_tlv_rate_mcs_get(hal_soc, rx_tlv_hdr); + sgi = hal_rx_tlv_sgi_get(hal_soc, rx_tlv_hdr); + vdev_priv = pkt_capture_vdev_get_priv(vdev); + + switch (preamble_type) { + case HAL_RX_PKT_TYPE_11A: + case HAL_RX_PKT_TYPE_11B: + /* legacy */ + rx_status->rate = pkt_capture_get_tx_rate( + preamble_type, + mcs, + &preamble); + rx_status->mcs = mcs; + break; + case HAL_RX_PKT_TYPE_11N: + rx_status->ht_flags = 1; + if (nss == 2) + mcs = 8 + mcs; + rx_status->ht_mcs = mcs; + break; + case HAL_RX_PKT_TYPE_11AC: + sgi = vdev_priv->rx_vht_sgi; + rx_status->vht_flags = 1; + rx_status->vht_flag_values3[0] = mcs << 0x4 | nss; + bw = vdev->vdev_mlme.des_chan->ch_width; + rx_status->vht_flag_values2 = bw; + break; + case HAL_RX_PKT_TYPE_11AX: + rx_status->he_flags = 1; + rx_status->he_data1 |= + IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | + IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN; + rx_status->he_data2 |= IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN; + rx_status->he_data3 |= mcs << 0x8; + + /* Map uCode SGI values to Radiotap header + * as per Radiotap header expectation. + * + * uCode has: + * enum 0 0_8_us_sgi + * enum 1 0_4_us_sgi + * enum 2 1_6_us_sgi + * enum 3 3_2_us_sgi + * + * Radiotap header expectation: + * enum 0 0_8_us_sgi + * enum 1 1_6_us_sgi + * enum 2 3_2_us_sgi + */ + if (sgi == HE_GI_1_6) + sgi = HE_GI_RADIOTAP_1_6; + else if (sgi == HE_GI_3_2) + sgi = HE_GI_RADIOTAP_3_2; + + rx_status->he_data5 |= (bw | (sgi << 0x4)); + rx_status->he_data6 |= nss; + default: + break; + } + + if (preamble_type != HAL_RX_PKT_TYPE_11B) + rx_status->ofdm_flag = 1; + else + rx_status->cck_flag = 1; + + rx_status->bw = bw; + rx_status->nr_ant = nss; + rx_status->nss = nss; + /* is_stbc not available */ + rx_status->is_stbc = is_stbc; + rx_status->sgi = sgi; + /* ldpc not available */ + rx_status->ldpc = ldpc; + /* beamformed not available */ + rx_status->beamformed = beamformed; + rx_status->rtap_flags |= ((preamble == SHORT_PREAMBLE) ? BIT(1) : 0); +} + +/** + * pkt_capture_get_rx_rtap_flags() - Get radiotap flags + * @flags: Pointer to struct hal_rx_pkt_capture_flags + * + * Return: Bitmapped radiotap flags. + */ +static +uint8_t pkt_capture_get_rx_rtap_flags(struct hal_rx_pkt_capture_flags *flags) +{ + uint8_t rtap_flags = 0; + + /* WEP40 || WEP104 || WEP128 */ + if (flags->encrypt_type == 0 || + flags->encrypt_type == 1 || + flags->encrypt_type == 3) + rtap_flags |= BIT(2); + + /* IEEE80211_RADIOTAP_F_FRAG */ + if (flags->fragment_flag) + rtap_flags |= BIT(3); + + /* IEEE80211_RADIOTAP_F_FCS */ + rtap_flags |= BIT(4); + + /* IEEE80211_RADIOTAP_F_BADFCS */ + if (flags->fcs_err) + rtap_flags |= BIT(6); + + return rtap_flags; +} + +/** + * pkt_capture_rx_mon_get_rx_status() - Get rx status + * @context: objmgr vdev + * @dp_soc: dp_soc handle + * @desc: Pointer to struct rx_pkt_tlvs + * @rx_status: Pointer to struct mon_rx_status + * + * Return: none + */ +static void pkt_capture_rx_mon_get_rx_status(void *context, void *dp_soc, + void *desc, + struct mon_rx_status *rx_status) +{ + uint8_t *rx_tlv_hdr = desc; + struct dp_soc *soc = dp_soc; + struct hal_rx_pkt_capture_flags flags = {0}; + struct wlan_objmgr_vdev *vdev = context; + uint8_t primary_chan_num; + uint32_t center_chan_freq; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + enum reg_wifi_band band; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("Failed to get psoc"); + return; + } + + hal_rx_tlv_get_pkt_capture_flags(soc->hal_soc, (uint8_t *)rx_tlv_hdr, + &flags); + + rx_status->rtap_flags |= pkt_capture_get_rx_rtap_flags(&flags); + rx_status->ant_signal_db = flags.rssi_comb; + rx_status->rssi_comb = flags.rssi_comb; + rx_status->tsft = flags.tsft; + primary_chan_num = flags.chan_freq; + center_chan_freq = flags.chan_freq >> 16; + rx_status->chan_num = primary_chan_num; + band = wlan_reg_freq_to_band(center_chan_freq); + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_PKT_CAPTURE_ID); + if (!pdev) { + pkt_capture_err("Failed to get pdev"); + return; + } + + rx_status->chan_freq = + wlan_reg_chan_band_to_freq(pdev, primary_chan_num, BIT(band)); + wlan_objmgr_pdev_release_ref(pdev, WLAN_PKT_CAPTURE_ID); + + pkt_capture_rx_get_phy_info(context, dp_soc, desc, rx_status); +} +#endif + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_rx_data_cb(): callback to process data rx packets + * for pkt capture mode. (normal rx + offloaded rx) + * @context: objmgr vdev + * @ppdev: device handler + * @nbuf_list: netbuf list + * @vdev_id: vdev id for which packet is captured + * @tid: tid number + * @status: Tx status + * @pkt_format: Frame format + * @bssid: bssid + * @tx_retry_cnt: tx retry count + * + * Return: none + */ +static void +pkt_capture_rx_data_cb( + void *context, void *ppdev, void *nbuf_list, + uint8_t vdev_id, uint8_t tid, + uint16_t status, bool pkt_format, + uint8_t *bssid, uint8_t tx_retry_cnt) +{ + struct pkt_capture_vdev_priv *vdev_priv; + qdf_nbuf_t buf_list = (qdf_nbuf_t)nbuf_list; + struct wlan_objmgr_vdev *vdev; + htt_pdev_handle pdev = ppdev; + struct pkt_capture_cb_context *cb_ctx; + qdf_nbuf_t msdu, next_buf; + uint8_t drop_count; + struct htt_host_rx_desc_base *rx_desc; + struct mon_rx_status rx_status = {0}; + uint32_t headroom; + static uint8_t preamble_type, rssi_comb; + static uint32_t vht_sig_a_1; + static uint32_t vht_sig_a_2; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto free_buf; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + cb_ctx = vdev_priv->cb_ctx; + if (!cb_ctx || !cb_ctx->mon_cb || !cb_ctx->mon_ctx) { + pkt_capture_vdev_put_ref(vdev); + goto free_buf; + } + + msdu = buf_list; + while (msdu) { + struct ethernet_hdr_t *eth_hdr; + + next_buf = qdf_nbuf_queue_next(msdu); + qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */ + + rx_desc = htt_rx_desc(msdu); + + /* + * Only the first mpdu has valid preamble type, so use it + * till the last mpdu is reached + */ + if (rx_desc->attention.first_mpdu) { + rssi_comb = rx_desc->ppdu_start.rssi_comb; + preamble_type = rx_desc->ppdu_start.preamble_type; + if (preamble_type == 8 || preamble_type == 9 || + preamble_type == 0x0c || preamble_type == 0x0d) { + vht_sig_a_1 = VHT_SIG_A_1(rx_desc); + vht_sig_a_2 = VHT_SIG_A_2(rx_desc); + } + } else { + rx_desc->ppdu_start.rssi_comb = rssi_comb; + rx_desc->ppdu_start.preamble_type = preamble_type; + if (preamble_type == 8 || preamble_type == 9 || + preamble_type == 0x0c || preamble_type == 0x0d) { + VHT_SIG_A_1(rx_desc) = vht_sig_a_1; + VHT_SIG_A_2(rx_desc) = vht_sig_a_2; + } + } + + if (rx_desc->attention.last_mpdu) { + rssi_comb = 0; + preamble_type = 0; + vht_sig_a_1 = 0; + vht_sig_a_2 = 0; + } + + qdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION); + + /* + * Get the channel info and update the rx status + */ + + /* need to update this to fill rx_status*/ + htt_rx_mon_get_rx_status(pdev, rx_desc, &rx_status); + rx_status.chan_noise_floor = NORMALIZED_TO_NOISE_FLOOR; + + /* clear IEEE80211_RADIOTAP_F_FCS flag*/ + rx_status.rtap_flags &= ~(BIT(4)); + rx_status.rtap_flags &= ~(BIT(2)); + + /* + * convert 802.3 header format into 802.11 format + */ + if (vdev_id == HTT_INVALID_VDEV) { + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + qdf_mem_copy(bssid, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + } + + pkt_capture_rx_convert8023to80211(bssid, msdu, rx_desc); + + /* + * Calculate the headroom and adjust head + * to prepare radiotap header. + */ + headroom = qdf_nbuf_headroom(msdu); + qdf_nbuf_update_radiotap(&rx_status, msdu, headroom); + pkt_capture_mon(cb_ctx, msdu, vdev, 0); + msdu = next_buf; + } + + pkt_capture_vdev_put_ref(vdev); + return; + +free_buf: + drop_count = pkt_capture_drop_nbuf_list(buf_list); +} +#else +/** + * pkt_capture_rx_data_cb(): callback to process data rx packets + * for pkt capture mode. (normal rx + offloaded rx) + * @context: objmgr vdev + * @psoc: dp_soc handle + * @nbuf_list: netbuf list + * @vdev_id: vdev id for which packet is captured + * @tid: tid number + * @status: Tx status + * @pkt_format: Frame format + * @bssid: bssid + * @tx_retry_cnt: tx retry count + * + * Return: none + */ +static void +pkt_capture_rx_data_cb( + void *context, void *psoc, void *nbuf_list, + uint8_t vdev_id, uint8_t tid, + uint16_t status, bool pkt_format, + uint8_t *bssid, uint8_t tx_retry_cnt) +{ + struct pkt_capture_vdev_priv *vdev_priv; + qdf_nbuf_t buf_list = (qdf_nbuf_t)nbuf_list; + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_cb_context *cb_ctx; + qdf_nbuf_t msdu, next_buf; + uint8_t drop_count; + struct mon_rx_status rx_status = {0}; + uint32_t headroom; + uint8_t *rx_tlv_hdr = NULL; + struct dp_soc *soc = psoc; + hal_soc_handle_t hal_soc; + struct hal_rx_msdu_metadata msdu_metadata; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + vdev = pkt_capture_get_vdev(); + ret = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(ret)) + goto free_buf; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + cb_ctx = vdev_priv->cb_ctx; + if (!cb_ctx || !cb_ctx->mon_cb || !cb_ctx->mon_ctx) { + pkt_capture_vdev_put_ref(vdev); + goto free_buf; + } + + hal_soc = soc->hal_soc; + msdu = buf_list; + while (msdu) { + struct ethernet_hdr_t *eth_hdr; + + /* push the tlvs to get rx_tlv_hdr pointer */ + qdf_nbuf_push_head(msdu, soc->rx_pkt_tlv_size + + QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(msdu)); + + rx_tlv_hdr = qdf_nbuf_data(msdu); + hal_rx_msdu_metadata_get(hal_soc, rx_tlv_hdr, &msdu_metadata); + /* Pull rx_tlv_hdr */ + pkt_capture_dp_rx_skip_tlvs(soc, msdu, + msdu_metadata.l3_hdr_pad); + + next_buf = qdf_nbuf_queue_next(msdu); + qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */ + + /* + * Get the channel info and update the rx status + */ + + /* need to update this to fill rx_status*/ + pkt_capture_rx_mon_get_rx_status(vdev, psoc, + rx_tlv_hdr, &rx_status); + + /* clear IEEE80211_RADIOTAP_F_FCS flag*/ + rx_status.rtap_flags &= ~(BIT(4)); + rx_status.rtap_flags &= ~(BIT(2)); + + /* + * convert 802.3 header format into 802.11 format + */ + if (vdev_id == HTT_INVALID_VDEV) { + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + qdf_mem_copy(bssid, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + } + + pkt_capture_rx_convert8023to80211(hal_soc, msdu, rx_tlv_hdr); + + /* + * Calculate the headroom and adjust head + * to prepare radiotap header. + */ + headroom = qdf_nbuf_headroom(msdu); + qdf_nbuf_update_radiotap(&rx_status, msdu, headroom); + pkt_capture_mon(cb_ctx, msdu, vdev, 0); + msdu = next_buf; + } + + pkt_capture_vdev_put_ref(vdev); + return; + +free_buf: + drop_count = pkt_capture_drop_nbuf_list(buf_list); +} + +#endif + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * pkt_capture_tx_data_cb() - process data tx and rx packets + * for pkt capture mode. (normal tx/rx + offloaded tx/rx) + * @context: capture context (unused) + * @ppdev: pdev handle + * @nbuf_list: netbuf list + * @vdev_id: vdev id for which packet is captured + * @tid: tid number + * @status: Tx status + * @pkt_format: Frame format + * @bssid: bssid + * @tx_retry_cnt: tx retry count + * + * Return: none + */ +static void +pkt_capture_tx_data_cb( + void *context, void *ppdev, void *nbuf_list, uint8_t vdev_id, + uint8_t tid, uint16_t status, bool pkt_format, + uint8_t *bssid, uint8_t tx_retry_cnt) +{ + qdf_nbuf_t msdu, next_buf; + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + htt_pdev_handle pdev = ppdev; + struct pkt_capture_cb_context *cb_ctx; + uint8_t drop_count; + struct htt_tx_data_hdr_information *cmpl_desc = NULL; + struct pkt_capture_tx_hdr_elem_t pktcapture_hdr = {0}; + struct ethernet_hdr_t *eth_hdr; + struct llc_snap_hdr_t *llc_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + uint16_t ether_type; + uint32_t headroom; + uint16_t seq_no, fc_ctrl; + struct mon_rx_status tx_status = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto free_buf; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + cb_ctx = vdev_priv->cb_ctx; + if (!cb_ctx || !cb_ctx->mon_cb || !cb_ctx->mon_ctx) { + pkt_capture_vdev_put_ref(vdev); + goto free_buf; + } + + msdu = nbuf_list; + while (msdu) { + next_buf = qdf_nbuf_queue_next(msdu); + qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */ + + cmpl_desc = (struct htt_tx_data_hdr_information *) + (qdf_nbuf_data(msdu)); + + pktcapture_hdr.timestamp = cmpl_desc->phy_timestamp_l32; + pktcapture_hdr.preamble = cmpl_desc->preamble; + pktcapture_hdr.mcs = cmpl_desc->mcs; + pktcapture_hdr.bw = cmpl_desc->bw; + pktcapture_hdr.nss = cmpl_desc->nss; + pktcapture_hdr.rssi_comb = cmpl_desc->rssi; + pktcapture_hdr.rate = cmpl_desc->rate; + pktcapture_hdr.stbc = cmpl_desc->stbc; + pktcapture_hdr.sgi = cmpl_desc->sgi; + pktcapture_hdr.ldpc = cmpl_desc->ldpc; + pktcapture_hdr.beamformed = cmpl_desc->beamformed; + pktcapture_hdr.status = status; + pktcapture_hdr.tx_retry_cnt = tx_retry_cnt; + + qdf_nbuf_pull_head( + msdu, + sizeof(struct htt_tx_data_hdr_information)); + + if (pkt_format == TXRX_PKTCAPTURE_PKT_FORMAT_8023) { + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + + *(uint16_t *)wh->i_dur = 0; + + new_hdsize = 0; + + if (vdev_id == HTT_INVALID_VDEV) + qdf_mem_copy(bssid, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + + /* BSSID , SA , DA */ + qdf_mem_copy(wh->i_addr1, bssid, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + + seq_no = cmpl_desc->seqno; + seq_no = (seq_no << IEEE80211_SEQ_SEQ_SHIFT) & + IEEE80211_SEQ_SEQ_MASK; + fc_ctrl = cmpl_desc->framectrl; + qdf_mem_copy(wh->i_fc, &fc_ctrl, sizeof(fc_ctrl)); + qdf_mem_copy(wh->i_seq, &seq_no, sizeof(seq_no)); + + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + + new_hdsize = sizeof(struct ieee80211_frame); + + if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + qos_cntl = (struct ieee80211_qoscntl *) + (localbuf + new_hdsize); + qos_cntl->i_qos[0] = + (tid & IEEE80211_QOS_TID); + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + } + /* + * Prepare llc Header + */ + llc_hdr = (struct llc_snap_hdr_t *) + (localbuf + new_hdsize); + ether_type = (eth_hdr->ethertype[0] << 8) | + (eth_hdr->ethertype[1]); + if (ether_type >= ETH_P_802_3_MIN) { + qdf_mem_copy( + llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = + BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } + + /* + * Remove 802.3 Header by adjusting the head + */ + qdf_nbuf_pull_head(msdu, hdsize); + + /* + * Adjust the head and prepare 802.11 Header + */ + qdf_nbuf_push_head(msdu, new_hdsize); + qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize); + } + + pkt_capture_update_tx_status( + pdev, + &tx_status, + &pktcapture_hdr); + /* + * Calculate the headroom and adjust head + * to prepare radiotap header. + */ + headroom = qdf_nbuf_headroom(msdu); + qdf_nbuf_update_radiotap(&tx_status, msdu, headroom); + pkt_capture_mon(cb_ctx, msdu, vdev, 0); + msdu = next_buf; + } + pkt_capture_vdev_put_ref(vdev); + return; + +free_buf: + drop_count = pkt_capture_drop_nbuf_list(nbuf_list); +} +#else +/** + * pkt_capture_get_vdev_bss_peer_mac_addr() - API to get bss peer mac address + * @vdev: objmgr vdev + * @bss_peer_mac_address: bss peer mac address + *. + * Helper function to get bss peer mac address + * + * Return: if success pmo vdev ctx else NULL + */ +static QDF_STATUS pkt_capture_get_vdev_bss_peer_mac_addr( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bss_peer_mac_address) +{ + struct wlan_objmgr_peer *peer; + + if (!vdev) { + qdf_print("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_PKT_CAPTURE_ID); + if (!peer) { + qdf_print("peer is null"); + return QDF_STATUS_E_INVAL; + } + wlan_peer_obj_lock(peer); + qdf_mem_copy(bss_peer_mac_address->bytes, wlan_peer_get_macaddr(peer), + QDF_MAC_ADDR_SIZE); + wlan_peer_obj_unlock(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_PKT_CAPTURE_ID); + + return QDF_STATUS_SUCCESS; +} + +static void +pkt_capture_tx_data_cb( + void *context, void *ppdev, void *nbuf_list, uint8_t vdev_id, + uint8_t tid, uint16_t status, bool pkt_format, + uint8_t *bssid, uint8_t tx_retry_cnt) +{ + qdf_nbuf_t msdu, next_buf; + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_cb_context *cb_ctx; + uint8_t drop_count; + struct pkt_capture_tx_hdr_elem_t *ptr_pktcapture_hdr = NULL; + struct pkt_capture_tx_hdr_elem_t pktcapture_hdr = {0}; + uint32_t txcap_hdr_size = sizeof(struct pkt_capture_tx_hdr_elem_t); + struct ethernet_hdr_t *eth_hdr; + struct llc_snap_hdr_t *llc_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + uint16_t ether_type; + uint32_t headroom; + uint16_t seq_no, fc_ctrl; + struct mon_rx_status tx_status = {0}; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + struct qdf_mac_addr bss_peer_mac_address; + + vdev = pkt_capture_get_vdev(); + ret = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(ret)) + goto free_buf; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + cb_ctx = vdev_priv->cb_ctx; + if (!cb_ctx || !cb_ctx->mon_cb || !cb_ctx->mon_ctx) { + pkt_capture_vdev_put_ref(vdev); + goto free_buf; + } + + msdu = nbuf_list; + while (msdu) { + next_buf = qdf_nbuf_queue_next(msdu); + qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */ + + ptr_pktcapture_hdr = (struct pkt_capture_tx_hdr_elem_t *) + (qdf_nbuf_data(msdu)); + + qdf_mem_copy(&pktcapture_hdr, ptr_pktcapture_hdr, + txcap_hdr_size); + pktcapture_hdr.status = status; + + qdf_nbuf_pull_head(msdu, txcap_hdr_size); + + if (pkt_format == TXRX_PKTCAPTURE_PKT_FORMAT_8023) { + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + + *(uint16_t *)wh->i_dur = 0; + + new_hdsize = 0; + + pkt_capture_get_vdev_bss_peer_mac_addr( + vdev, + &bss_peer_mac_address); + qdf_mem_copy(bssid, bss_peer_mac_address.bytes, + QDF_MAC_ADDR_SIZE); + if (vdev_id == HTT_INVALID_VDEV) + qdf_mem_copy(bssid, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + + /* BSSID , SA , DA */ + qdf_mem_copy(wh->i_addr1, bssid, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + + seq_no = pktcapture_hdr.seqno; + seq_no = (seq_no << IEEE80211_SEQ_SEQ_SHIFT) & + IEEE80211_SEQ_SEQ_MASK; + fc_ctrl = pktcapture_hdr.framectrl; + qdf_mem_copy(wh->i_fc, &fc_ctrl, sizeof(fc_ctrl)); + qdf_mem_copy(wh->i_seq, &seq_no, sizeof(seq_no)); + + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + + if (tx_retry_cnt) + wh->i_fc[1] |= IEEE80211_FC1_RETRY; + + new_hdsize = sizeof(struct ieee80211_frame); + + if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + qos_cntl = (struct ieee80211_qoscntl *) + (localbuf + new_hdsize); + qos_cntl->i_qos[0] = + (tid & IEEE80211_QOS_TID); + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + } + /* + * Prepare llc Header + */ + llc_hdr = (struct llc_snap_hdr_t *) + (localbuf + new_hdsize); + ether_type = (eth_hdr->ethertype[0] << 8) | + (eth_hdr->ethertype[1]); + if (ether_type >= ETH_P_802_3_MIN) { + qdf_mem_copy( + llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = + BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } + + /* + * Remove 802.3 Header by adjusting the head + */ + qdf_nbuf_pull_head(msdu, hdsize); + + /* + * Adjust the head and prepare 802.11 Header + */ + qdf_nbuf_push_head(msdu, new_hdsize); + qdf_mem_copy(qdf_nbuf_data(msdu), localbuf, new_hdsize); + } + + pkt_capture_update_tx_status( + vdev, + &tx_status, + &pktcapture_hdr); + /* + * Calculate the headroom and adjust head + * to prepare radiotap header. + */ + headroom = qdf_nbuf_headroom(msdu); + qdf_nbuf_update_radiotap(&tx_status, msdu, headroom); + pkt_capture_mon(cb_ctx, msdu, vdev, 0); + msdu = next_buf; + } + pkt_capture_vdev_put_ref(vdev); + return; + +free_buf: + drop_count = pkt_capture_drop_nbuf_list(nbuf_list); +} +#endif + +void pkt_capture_datapkt_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, void *pdev, + uint8_t tx_retry_cnt) +{ + uint8_t drop_count; + struct pkt_capture_mon_pkt *pkt; + pkt_capture_mon_thread_cb callback = NULL; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + status = pkt_capture_txrx_status_map(status); + vdev = pkt_capture_get_vdev(); + ret = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(ret)) + goto drop_rx_buf; + + switch (type) { + case TXRX_PROCESS_TYPE_DATA_RX: + callback = pkt_capture_rx_data_cb; + break; + case TXRX_PROCESS_TYPE_DATA_TX: + case TXRX_PROCESS_TYPE_DATA_TX_COMPL: + callback = pkt_capture_tx_data_cb; + break; + default: + pkt_capture_vdev_put_ref(vdev); + goto drop_rx_buf; + } + + pkt = pkt_capture_alloc_mon_pkt(vdev); + if (!pkt) { + pkt_capture_vdev_put_ref(vdev); + goto drop_rx_buf; + } + + pkt->callback = callback; + pkt->context = NULL; + pkt->pdev = (void *)pdev; + pkt->monpkt = (void *)mon_buf_list; + pkt->vdev_id = vdev_id; + pkt->tid = tid; + pkt->status = status; + pkt->pkt_format = pkt_format; + qdf_mem_copy(pkt->bssid, bssid, QDF_MAC_ADDR_SIZE); + pkt->tx_retry_cnt = tx_retry_cnt; + pkt_capture_indicate_monpkt(vdev, pkt); + pkt_capture_vdev_put_ref(vdev); + return; + +drop_rx_buf: + drop_count = pkt_capture_drop_nbuf_list(mon_buf_list); +} + +struct htt_tx_data_hdr_information *pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus) +{ + int offset_dwords; + u_int32_t has_tx_tsf; + u_int32_t has_retry; + u_int32_t has_ack_rssi; + u_int32_t has_tx_tsf64; + u_int32_t has_tx_compl_payload; + struct htt_tx_compl_ind_append_retries *retry_list = NULL; + struct htt_tx_data_hdr_information *txcomplete_data_hrd_list = NULL; + + has_tx_compl_payload = HTT_TX_COMPL_IND_APPEND4_GET(*msg_word); + if (num_msdus <= 0 || !has_tx_compl_payload) + return NULL; + + offset_dwords = 1 + ((num_msdus + 1) >> 1); + + has_retry = HTT_TX_COMPL_IND_APPEND_GET(*msg_word); + if (has_retry) { + int retry_index = 0; + int width_for_each_retry = + (sizeof(struct htt_tx_compl_ind_append_retries) + + 3) >> 2; + + retry_list = (struct htt_tx_compl_ind_append_retries *) + (msg_word + offset_dwords); + while (retry_list) { + if (retry_list[retry_index++].flag == 0) + break; + } + offset_dwords += retry_index * width_for_each_retry; + } + has_tx_tsf = HTT_TX_COMPL_IND_APPEND1_GET(*msg_word); + if (has_tx_tsf) { + int width_for_each_tsf = + (sizeof(struct htt_tx_compl_ind_append_tx_tstamp)) >> 2; + offset_dwords += width_for_each_tsf * num_msdus; + } + + has_ack_rssi = HTT_TX_COMPL_IND_APPEND2_GET(*msg_word); + if (has_ack_rssi) + offset_dwords += ((num_msdus + 1) >> 1); + + has_tx_tsf64 = HTT_TX_COMPL_IND_APPEND3_GET(*msg_word); + if (has_tx_tsf64) + offset_dwords += (num_msdus << 1); + + txcomplete_data_hrd_list = (struct htt_tx_data_hdr_information *) + (msg_word + offset_dwords); + + return txcomplete_data_hrd_list; +} + +#ifndef WLAN_FEATURE_PKT_CAPTURE_V2 +void pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev) +{ + int nbuf_len; + qdf_nbuf_t netbuf; + uint8_t status; + uint8_t tid = 0; + bool pkt_format; + u_int32_t *msg_word = (u_int32_t *)msg; + u_int8_t *buf = (u_int8_t *)msg; + struct htt_tx_data_hdr_information *txhdr; + struct htt_tx_offload_deliver_ind_hdr_t *offload_deliver_msg; + + offload_deliver_msg = (struct htt_tx_offload_deliver_ind_hdr_t *)msg; + + txhdr = (struct htt_tx_data_hdr_information *) + (msg_word + 1); + + nbuf_len = offload_deliver_msg->tx_mpdu_bytes; + + netbuf = qdf_nbuf_alloc(NULL, + roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + + if (!netbuf) + return; + + qdf_nbuf_put_tail(netbuf, nbuf_len); + + qdf_mem_copy(qdf_nbuf_data(netbuf), + buf + sizeof(struct htt_tx_offload_deliver_ind_hdr_t), + nbuf_len); + + qdf_nbuf_push_head( + netbuf, + sizeof(struct htt_tx_data_hdr_information)); + + qdf_mem_copy(qdf_nbuf_data(netbuf), txhdr, + sizeof(struct htt_tx_data_hdr_information)); + + status = offload_deliver_msg->status; + pkt_format = offload_deliver_msg->format; + tid = offload_deliver_msg->tid_num; + + pkt_capture_datapkt_process( + vdev_id, + netbuf, TXRX_PROCESS_TYPE_DATA_TX, + tid, status, pkt_format, bssid, pdev, + offload_deliver_msg->tx_retry_cnt); +} +#else +void pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, void *soc) +{ + int nbuf_len; + qdf_nbuf_t netbuf; + uint8_t status; + uint8_t tid = 0; + bool pkt_format; + u_int8_t *buf = (u_int8_t *)msg; + struct htt_tx_offload_deliver_ind_hdr_t *offload_deliver_msg; + + struct pkt_capture_tx_hdr_elem_t *ptr_pktcapture_hdr; + struct pkt_capture_tx_hdr_elem_t pktcapture_hdr = {0}; + uint32_t txcap_hdr_size = sizeof(struct pkt_capture_tx_hdr_elem_t); + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_frame_filter *frame_filter; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + offload_deliver_msg = (struct htt_tx_offload_deliver_ind_hdr_t *)msg; + + vdev = pkt_capture_get_vdev(); + ret = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(ret)) + return; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + return; + } + + frame_filter = &vdev_priv->frame_filter; + + nbuf_len = offload_deliver_msg->tx_mpdu_bytes; + netbuf = qdf_nbuf_alloc(NULL, + roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!netbuf) { + pkt_capture_vdev_put_ref(vdev); + return; + } + + qdf_nbuf_put_tail(netbuf, nbuf_len); + + qdf_mem_copy(qdf_nbuf_data(netbuf), + buf + sizeof(struct htt_tx_offload_deliver_ind_hdr_t), + nbuf_len); + + if (!(frame_filter->data_tx_frame_filter & + PKT_CAPTURE_DATA_FRAME_TYPE_ALL) && + !pkt_capture_is_frame_filter_set( + netbuf, frame_filter, IEEE80211_FC1_DIR_TODS)) { + qdf_nbuf_free(netbuf); + pkt_capture_vdev_put_ref(vdev); + return; + } + + pktcapture_hdr.timestamp = offload_deliver_msg->phy_timestamp_l32; + pktcapture_hdr.preamble = offload_deliver_msg->preamble; + pktcapture_hdr.mcs = offload_deliver_msg->mcs; + pktcapture_hdr.bw = offload_deliver_msg->bw; + pktcapture_hdr.nss = offload_deliver_msg->nss; + pktcapture_hdr.rssi_comb = offload_deliver_msg->rssi; + pktcapture_hdr.rate = offload_deliver_msg->rate; + pktcapture_hdr.stbc = offload_deliver_msg->stbc; + pktcapture_hdr.sgi = offload_deliver_msg->sgi; + pktcapture_hdr.ldpc = offload_deliver_msg->ldpc; + /* Beamformed not available */ + pktcapture_hdr.beamformed = 0; + pktcapture_hdr.framectrl = offload_deliver_msg->framectrl; + pktcapture_hdr.tx_retry_cnt = offload_deliver_msg->tx_retry_cnt; + pktcapture_hdr.seqno = offload_deliver_msg->seqno; + tid = offload_deliver_msg->tid_num; + status = offload_deliver_msg->status; + pkt_format = offload_deliver_msg->format; + + qdf_nbuf_push_head(netbuf, txcap_hdr_size); + + ptr_pktcapture_hdr = + (struct pkt_capture_tx_hdr_elem_t *)qdf_nbuf_data(netbuf); + + qdf_mem_copy(ptr_pktcapture_hdr, &pktcapture_hdr, txcap_hdr_size); + + pkt_capture_datapkt_process( + vdev_id, + netbuf, TXRX_PROCESS_TYPE_DATA_TX, + tid, status, pkt_format, bssid, soc, + offload_deliver_msg->tx_retry_cnt); + + pkt_capture_vdev_put_ref(vdev); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_main.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_main.c new file mode 100644 index 0000000000..87996ec703 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_main.c @@ -0,0 +1,1418 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement various notification handlers which are accessed + * internally in pkt_capture component only. + */ + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +#include +#include "htt_ppdu_stats.h" +#endif +#include "wlan_pkt_capture_main.h" +#include "cfg_ucfg_api.h" +#include "wlan_pkt_capture_mon_thread.h" +#include "wlan_pkt_capture_mgmt_txrx.h" +#include "target_if_pkt_capture.h" +#include "cdp_txrx_ctrl.h" +#include "wlan_pkt_capture_tgt_api.h" +#include +#include "wlan_vdev_mgr_utils_api.h" + +static struct wlan_objmgr_vdev *gp_pkt_capture_vdev; + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +wdi_event_subscribe PKT_CAPTURE_TX_SUBSCRIBER; +wdi_event_subscribe PKT_CAPTURE_RX_SUBSCRIBER; +wdi_event_subscribe PKT_CAPTURE_RX_NO_PEER_SUBSCRIBER; +wdi_event_subscribe PKT_CAPTURE_OFFLOAD_TX_SUBSCRIBER; +wdi_event_subscribe PKT_CAPTURE_PPDU_STATS_SUBSCRIBER; + +/** + * pkt_capture_wdi_event_subscribe() - Subscribe pkt capture callbacks + * @psoc: pointer to psoc object + * + * Return: None + */ +static void pkt_capture_wdi_event_subscribe(struct wlan_objmgr_psoc *psoc) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t pdev_id = WMI_PDEV_ID_SOC; + + /* subscribing for tx data packets */ + PKT_CAPTURE_TX_SUBSCRIBER.callback = + pkt_capture_callback; + + PKT_CAPTURE_TX_SUBSCRIBER.context = wlan_psoc_get_dp_handle(psoc); + + cdp_wdi_event_sub(soc, pdev_id, &PKT_CAPTURE_TX_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_TX_DATA); + + /* subscribing for rx data packets */ + PKT_CAPTURE_RX_SUBSCRIBER.callback = + pkt_capture_callback; + + PKT_CAPTURE_RX_SUBSCRIBER.context = wlan_psoc_get_dp_handle(psoc); + + cdp_wdi_event_sub(soc, pdev_id, &PKT_CAPTURE_RX_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_RX_DATA); + + /* subscribe for rx data packets when no peer is there*/ + PKT_CAPTURE_RX_NO_PEER_SUBSCRIBER.callback = + pkt_capture_callback; + + PKT_CAPTURE_RX_NO_PEER_SUBSCRIBER.context = + wlan_psoc_get_dp_handle(psoc); + + cdp_wdi_event_sub(soc, pdev_id, &PKT_CAPTURE_RX_NO_PEER_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_RX_DATA_NO_PEER); + + /* subscribing for offload tx data packets */ + PKT_CAPTURE_OFFLOAD_TX_SUBSCRIBER.callback = + pkt_capture_callback; + + PKT_CAPTURE_OFFLOAD_TX_SUBSCRIBER.context = + wlan_psoc_get_dp_handle(psoc); + + cdp_wdi_event_sub(soc, pdev_id, &PKT_CAPTURE_OFFLOAD_TX_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_OFFLOAD_TX_DATA); + + /* subscribe for packet capture mode related ppdu stats */ + PKT_CAPTURE_PPDU_STATS_SUBSCRIBER.callback = + pkt_capture_callback; + + PKT_CAPTURE_PPDU_STATS_SUBSCRIBER.context = + wlan_psoc_get_dp_handle(psoc); + + cdp_wdi_event_sub(soc, pdev_id, &PKT_CAPTURE_PPDU_STATS_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_PPDU_STATS); +} + +/** + * pkt_capture_wdi_event_unsubscribe() - Unsubscribe pkt capture callbacks + * @psoc: pointer to psoc object + * + * Return: None + */ +static void pkt_capture_wdi_event_unsubscribe(struct wlan_objmgr_psoc *psoc) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t pdev_id = WMI_PDEV_ID_SOC; + + /* unsubscribe ppdu smu stats */ + cdp_wdi_event_unsub(soc, pdev_id, &PKT_CAPTURE_PPDU_STATS_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_PPDU_STATS); + + /* unsubscribing for offload tx data packets */ + cdp_wdi_event_unsub(soc, pdev_id, &PKT_CAPTURE_OFFLOAD_TX_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_OFFLOAD_TX_DATA); + + /* unsubscribe for rx data no peer packets */ + cdp_wdi_event_unsub(soc, pdev_id, &PKT_CAPTURE_RX_NO_PEER_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_RX_DATA_NO_PEER); + + /* unsubscribing for rx data packets */ + cdp_wdi_event_unsub(soc, pdev_id, &PKT_CAPTURE_RX_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_RX_DATA); + + /* unsubscribing for tx data packets */ + cdp_wdi_event_unsub(soc, pdev_id, &PKT_CAPTURE_TX_SUBSCRIBER, + WDI_EVENT_PKT_CAPTURE_TX_DATA); +} + +enum pkt_capture_mode +pkt_capture_get_pktcap_mode_v2() +{ + enum pkt_capture_mode mode = PACKET_CAPTURE_MODE_DISABLE; + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return PACKET_CAPTURE_MODE_DISABLE; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) + pkt_capture_err("vdev_priv is NULL"); + else + mode = vdev_priv->cfg_params.pkt_capture_mode; + + pkt_capture_vdev_put_ref(vdev); + return mode; +} + +#define RX_OFFLOAD_PKT 1 +#define PPDU_STATS_Q_MAX_SIZE 500 + +static void +pkt_capture_process_rx_data_no_peer(void *soc, uint16_t vdev_id, uint8_t *bssid, + uint32_t status, qdf_nbuf_t nbuf) +{ + uint32_t pkt_len, l3_hdr_pad, nbuf_len; + struct dp_soc *psoc = soc; + qdf_nbuf_t msdu; + uint8_t *rx_tlv_hdr; + + nbuf_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf); + rx_tlv_hdr = qdf_nbuf_data(nbuf); + l3_hdr_pad = hal_rx_msdu_end_l3_hdr_padding_get(psoc->hal_soc, + rx_tlv_hdr); + pkt_len = nbuf_len + l3_hdr_pad + psoc->rx_pkt_tlv_size; + qdf_nbuf_set_pktlen(nbuf, pkt_len); + + /* + * Offload rx packets are delivered only to pkt capture component, so + * can modify the received nbuf, in other cases create a private copy + * of the received nbuf so that pkt capture component can modify it + * without altering the original nbuf + */ + if (status == RX_OFFLOAD_PKT) + msdu = nbuf; + else + msdu = qdf_nbuf_copy(nbuf); + + if (!msdu) + return; + + QDF_NBUF_CB_RX_PACKET_L3_HDR_PAD(msdu) = l3_hdr_pad; + + qdf_nbuf_pull_head(msdu, l3_hdr_pad + psoc->rx_pkt_tlv_size); + pkt_capture_datapkt_process( + vdev_id, msdu, + TXRX_PROCESS_TYPE_DATA_RX, 0, 0, + TXRX_PKTCAPTURE_PKT_FORMAT_8023, + bssid, psoc, 0); +} + +static void +pkt_capture_process_ppdu_stats(void *log_data) +{ + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_ppdu_stats_q_node *q_node; + htt_ppdu_stats_for_smu_tlv *smu; + uint32_t stats_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (qdf_unlikely(!vdev_priv)) { + pkt_capture_vdev_put_ref(vdev); + return; + } + + smu = (htt_ppdu_stats_for_smu_tlv *)log_data; + vdev_priv->tx_nss = smu->nss; + + qdf_spin_lock_bh(&vdev_priv->lock_q); + if (qdf_list_size(&vdev_priv->ppdu_stats_q) < + PPDU_STATS_Q_MAX_SIZE) { + qdf_spin_unlock_bh(&vdev_priv->lock_q); + /* + * win size indicates the size of block ack bitmap, currently + * we support only 256 bit ba bitmap. + */ + if (smu->win_size > 8) { + pkt_capture_vdev_put_ref(vdev); + pkt_capture_err("win size %d > 8 not supported\n", + smu->win_size); + return; + } + + stats_len = sizeof(htt_ppdu_stats_for_smu_tlv) + + smu->win_size * sizeof(uint32_t); + + q_node = qdf_mem_malloc(sizeof(*q_node) + stats_len); + if (!q_node) { + pkt_capture_vdev_put_ref(vdev); + pkt_capture_err("stats node and buf allocation fail\n"); + return; + } + + qdf_mem_copy(q_node->buf, log_data, stats_len); + /* Insert received ppdu stats in queue */ + qdf_spin_lock_bh(&vdev_priv->lock_q); + qdf_list_insert_back(&vdev_priv->ppdu_stats_q, + &q_node->node); + } + qdf_spin_unlock_bh(&vdev_priv->lock_q); + pkt_capture_vdev_put_ref(vdev); +} + +static void +pkt_capture_process_tx_data(void *soc, void *log_data, u_int16_t vdev_id, + uint32_t status) +{ + struct dp_soc *psoc = soc; + uint8_t tid = 0; + uint8_t bssid[QDF_MAC_ADDR_SIZE] = {0}; + struct pkt_capture_tx_hdr_elem_t *ptr_pktcapture_hdr; + struct pkt_capture_tx_hdr_elem_t pktcapture_hdr = {0}; + struct hal_tx_completion_status tx_comp_status = {0}; + struct qdf_tso_seg_elem_t *tso_seg = NULL; + uint32_t txcap_hdr_size = + sizeof(struct pkt_capture_tx_hdr_elem_t); + + struct dp_tx_desc_s *desc = log_data; + qdf_nbuf_t netbuf; + int nbuf_len; + + hal_tx_comp_get_status(&desc->comp, &tx_comp_status, + psoc->hal_soc); + + if (tx_comp_status.valid) + pktcapture_hdr.ppdu_id = tx_comp_status.ppdu_id; + pktcapture_hdr.timestamp = tx_comp_status.tsf; + pktcapture_hdr.preamble = tx_comp_status.pkt_type; + pktcapture_hdr.mcs = tx_comp_status.mcs; + pktcapture_hdr.bw = tx_comp_status.bw; + /* nss not available */ + pktcapture_hdr.nss = 0; + pktcapture_hdr.rssi_comb = tx_comp_status.ack_frame_rssi; + /* update rate from available mcs */ + pktcapture_hdr.rate = tx_comp_status.mcs; + pktcapture_hdr.stbc = tx_comp_status.stbc; + pktcapture_hdr.sgi = tx_comp_status.sgi; + pktcapture_hdr.ldpc = tx_comp_status.ldpc; + /* Beamformed not available */ + pktcapture_hdr.beamformed = 0; + pktcapture_hdr.framectrl = IEEE80211_FC0_TYPE_DATA | + (IEEE80211_FC1_DIR_TODS << 8); + pktcapture_hdr.tx_retry_cnt = tx_comp_status.transmit_cnt - 1; + /* seqno not available */ + pktcapture_hdr.seqno = 0; + tid = tx_comp_status.tid; + status = tx_comp_status.status; + + if (desc->frm_type == dp_tx_frm_tso) { + if (!desc->msdu_ext_desc->tso_desc) + return; + tso_seg = desc->msdu_ext_desc->tso_desc; + nbuf_len = tso_seg->seg.total_len; + } else { + nbuf_len = qdf_nbuf_len(desc->nbuf); + } + + netbuf = qdf_nbuf_alloc(NULL, + roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + + if (!netbuf) + return; + + qdf_nbuf_put_tail(netbuf, nbuf_len); + + if (desc->frm_type == dp_tx_frm_tso) { + uint8_t frag_cnt, num_frags = 0; + int frag_len = 0; + uint32_t tcp_seq_num; + uint16_t ip_len; + + if (tso_seg->seg.num_frags > 0) + num_frags = tso_seg->seg.num_frags - 1; + + /*Num of frags in a tso seg cannot be less than 2 */ + if (num_frags < 1) { + pkt_capture_err("num of frags in tso segment is %d\n", + (num_frags + 1)); + qdf_nbuf_free(netbuf); + return; + } + + tcp_seq_num = tso_seg->seg.tso_flags.tcp_seq_num; + tcp_seq_num = qdf_cpu_to_be32(tcp_seq_num); + + ip_len = tso_seg->seg.tso_flags.ip_len; + ip_len = qdf_cpu_to_be16(ip_len); + + for (frag_cnt = 0; frag_cnt <= num_frags; frag_cnt++) { + qdf_mem_copy( + qdf_nbuf_data(netbuf) + frag_len, + tso_seg->seg.tso_frags[frag_cnt].vaddr, + tso_seg->seg.tso_frags[frag_cnt].length); + frag_len += + tso_seg->seg.tso_frags[frag_cnt].length; + } + + qdf_mem_copy((qdf_nbuf_data(netbuf) + + IPV4_PKT_LEN_OFFSET), + &ip_len, sizeof(ip_len)); + qdf_mem_copy((qdf_nbuf_data(netbuf) + + IPV4_TCP_SEQ_NUM_OFFSET), + &tcp_seq_num, sizeof(tcp_seq_num)); + } else { + qdf_mem_copy(qdf_nbuf_data(netbuf), + qdf_nbuf_data(desc->nbuf), nbuf_len); + } + + if (qdf_unlikely(qdf_nbuf_headroom(netbuf) < txcap_hdr_size)) { + netbuf = qdf_nbuf_realloc_headroom(netbuf, + txcap_hdr_size); + if (!netbuf) { + QDF_TRACE(QDF_MODULE_ID_PKT_CAPTURE, + QDF_TRACE_LEVEL_ERROR, + FL("No headroom")); + return; + } + } + + if (!qdf_nbuf_push_head(netbuf, txcap_hdr_size)) { + QDF_TRACE(QDF_MODULE_ID_PKT_CAPTURE, + QDF_TRACE_LEVEL_ERROR, FL("No headroom")); + qdf_nbuf_free(netbuf); + return; + } + + ptr_pktcapture_hdr = + (struct pkt_capture_tx_hdr_elem_t *)qdf_nbuf_data(netbuf); + qdf_mem_copy(ptr_pktcapture_hdr, &pktcapture_hdr, + txcap_hdr_size); + + pkt_capture_datapkt_process( + vdev_id, netbuf, TXRX_PROCESS_TYPE_DATA_TX_COMPL, + tid, status, TXRX_PKTCAPTURE_PKT_FORMAT_8023, + bssid, NULL, pktcapture_hdr.tx_retry_cnt); +} + +/** + * pkt_capture_is_frame_filter_set() - Check frame filter is set + * @buf: buffer address + * @frame_filter: frame filter address + * @direction: frame direction + * + * Return: true, if filter bit is set + * false, if filter bit is not set + */ +bool +pkt_capture_is_frame_filter_set(qdf_nbuf_t buf, + struct pkt_capture_frame_filter *frame_filter, + bool direction) +{ + enum pkt_capture_data_frame_type data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_ALL; + + if (qdf_nbuf_is_ipv4_arp_pkt(buf)) { + data_frame_type = PKT_CAPTURE_DATA_FRAME_TYPE_ARP; + } else if (qdf_nbuf_is_ipv4_eapol_pkt(buf)) { + data_frame_type = PKT_CAPTURE_DATA_FRAME_TYPE_EAPOL; + } else if (qdf_nbuf_data_is_tcp_syn(buf)) { + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_SYN; + } else if (qdf_nbuf_data_is_tcp_syn_ack(buf)) { + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_SYNACK; + } else if (qdf_nbuf_data_is_tcp_syn(buf)) { + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_FIN; + } else if (qdf_nbuf_data_is_tcp_syn_ack(buf)) { + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_FINACK; + } else if (qdf_nbuf_data_is_tcp_ack(buf)) { + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_ACK; + } else if (qdf_nbuf_data_is_tcp_rst(buf)) { + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_RST; + } else if (qdf_nbuf_is_ipv4_pkt(buf)) { + if (qdf_nbuf_is_ipv4_dhcp_pkt(buf)) + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_DHCPV4; + else if (qdf_nbuf_is_icmp_pkt(buf)) + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_ICMPV4; + else if (qdf_nbuf_data_is_dns_query(buf)) + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_DNSV4; + else if (qdf_nbuf_data_is_dns_response(buf)) + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_DNSV4; + } else if (qdf_nbuf_is_ipv6_pkt(buf)) { + if (qdf_nbuf_is_ipv6_dhcp_pkt(buf)) + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_DHCPV6; + else if (qdf_nbuf_is_icmpv6_pkt(buf)) + data_frame_type = + PKT_CAPTURE_DATA_FRAME_TYPE_ICMPV6; + /* need to add code for + * PKT_CAPTURE_DATA_FRAME_TYPE_DNSV6 + */ + } + /* Add code for + * PKT_CAPTURE_DATA_FRAME_TYPE_RTP + * PKT_CAPTURE_DATA_FRAME_TYPE_SIP + * PKT_CAPTURE_DATA_FRAME_QOS_NULL + */ + + if (direction == IEEE80211_FC1_DIR_TODS) { + if (data_frame_type & frame_filter->data_tx_frame_filter) + return true; + else + return false; + } else { + if (data_frame_type & frame_filter->data_rx_frame_filter) + return true; + else + return false; + } +} + +void pkt_capture_callback(void *soc, enum WDI_EVENT event, void *log_data, + u_int16_t peer_id, uint32_t status) +{ + uint8_t bssid[QDF_MAC_ADDR_SIZE] = {0}; + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_frame_filter *frame_filter; + uint16_t vdev_id = 0; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + vdev = pkt_capture_get_vdev(); + ret = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(ret)) + return; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + return; + } + + frame_filter = &vdev_priv->frame_filter; + + switch (event) { + case WDI_EVENT_PKT_CAPTURE_TX_DATA: + { + struct dp_tx_desc_s *desc = log_data; + + if (!frame_filter->data_tx_frame_filter) { + pkt_capture_vdev_put_ref(vdev); + return; + } + + if (frame_filter->data_tx_frame_filter & + PKT_CAPTURE_DATA_FRAME_TYPE_ALL) { + pkt_capture_process_tx_data(soc, log_data, + vdev_id, status); + } else if (pkt_capture_is_frame_filter_set( + desc->nbuf, frame_filter, IEEE80211_FC1_DIR_TODS)) { + pkt_capture_process_tx_data(soc, log_data, + vdev_id, status); + } + break; + } + + case WDI_EVENT_PKT_CAPTURE_RX_DATA: + { + qdf_nbuf_t nbuf = (qdf_nbuf_t)log_data; + + if (!frame_filter->data_rx_frame_filter) { + /* + * Rx offload packets are delivered only to pkt capture + * component and not to stack so free them. + */ + if (status == RX_OFFLOAD_PKT) + qdf_nbuf_free(nbuf); + + pkt_capture_vdev_put_ref(vdev); + return; + } + + if (frame_filter->data_rx_frame_filter & + PKT_CAPTURE_DATA_FRAME_TYPE_ALL) { + pkt_capture_msdu_process_pkts(bssid, log_data, + vdev_id, soc, status); + } else if (pkt_capture_is_frame_filter_set( + nbuf, frame_filter, IEEE80211_FC1_DIR_FROMDS)) { + pkt_capture_msdu_process_pkts(bssid, log_data, + vdev_id, soc, status); + } else { + if (status == RX_OFFLOAD_PKT) + qdf_nbuf_free(nbuf); + } + + break; + } + + case WDI_EVENT_PKT_CAPTURE_RX_DATA_NO_PEER: + { + qdf_nbuf_t nbuf = (qdf_nbuf_t)log_data; + + if (!frame_filter->data_rx_frame_filter) { + /* + * Rx offload packets are delivered only to pkt capture + * component and not to stack so free them. + */ + if (status == RX_OFFLOAD_PKT) + qdf_nbuf_free(nbuf); + + pkt_capture_vdev_put_ref(vdev); + return; + } + + if (frame_filter->data_rx_frame_filter & + PKT_CAPTURE_DATA_FRAME_TYPE_ALL) { + pkt_capture_process_rx_data_no_peer(soc, vdev_id, bssid, + status, nbuf); + } else if (pkt_capture_is_frame_filter_set( + nbuf, frame_filter, IEEE80211_FC1_DIR_FROMDS)) { + pkt_capture_process_rx_data_no_peer(soc, vdev_id, bssid, + status, nbuf); + } else { + if (status == RX_OFFLOAD_PKT) + qdf_nbuf_free(nbuf); + } + + break; + } + + case WDI_EVENT_PKT_CAPTURE_OFFLOAD_TX_DATA: + { + struct htt_tx_offload_deliver_ind_hdr_t *offload_deliver_msg; + bool is_pkt_during_roam = false; + uint32_t freq = 0; + + if (!frame_filter->data_tx_frame_filter) { + pkt_capture_vdev_put_ref(vdev); + return; + } + + offload_deliver_msg = + (struct htt_tx_offload_deliver_ind_hdr_t *)log_data; + is_pkt_during_roam = + (offload_deliver_msg->reserved_2 ? true : false); + + if (is_pkt_during_roam) { + vdev_id = HTT_INVALID_VDEV; + freq = + (uint32_t)offload_deliver_msg->reserved_3; + } else { + vdev_id = offload_deliver_msg->vdev_id; + } + + pkt_capture_offload_deliver_indication_handler( + log_data, + vdev_id, bssid, soc); + break; + } + + case WDI_EVENT_PKT_CAPTURE_PPDU_STATS: + pkt_capture_process_ppdu_stats(log_data); + break; + + default: + break; + } + pkt_capture_vdev_put_ref(vdev); +} + +#else +static void pkt_capture_wdi_event_subscribe(struct wlan_objmgr_psoc *psoc) +{ +} + +static void pkt_capture_wdi_event_unsubscribe(struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +struct wlan_objmgr_vdev *pkt_capture_get_vdev() +{ + return gp_pkt_capture_vdev; +} + +enum pkt_capture_mode pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pkt_psoc_priv *psoc_priv; + + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return PACKET_CAPTURE_MODE_DISABLE; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return PACKET_CAPTURE_MODE_DISABLE; + } + + return psoc_priv->cfg_param.pkt_capture_mode; +} + +bool pkt_capture_is_tx_mgmt_enable(struct wlan_objmgr_pdev *pdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum pkt_capture_config config; + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("failed to get vdev ref"); + return false; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev_priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + return false; + } + + config = pkt_capture_get_pktcap_config(vdev); + + if (!(vdev_priv->frame_filter.mgmt_tx_frame_filter & + PKT_CAPTURE_MGMT_FRAME_TYPE_ALL)) { + if (!(config & PACKET_CAPTURE_CONFIG_QOS_ENABLE)) { + pkt_capture_vdev_put_ref(vdev); + return false; + } + } + + pkt_capture_vdev_put_ref(vdev); + return true; +} + +QDF_STATUS +pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_psoc_priv *psoc_priv; + struct wlan_objmgr_psoc *psoc; + enum pkt_capture_mode mode; + QDF_STATUS status; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev priv is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev_priv->cb_ctx->mon_cb = mon_cb; + vdev_priv->cb_ctx->mon_ctx = context; + + status = pkt_capture_mgmt_rx_ops(psoc, true); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to register pkt capture mgmt rx ops"); + goto mgmt_rx_ops_fail; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return QDF_STATUS_E_INVAL; + } + + target_if_pkt_capture_register_tx_ops(&psoc_priv->tx_ops); + target_if_pkt_capture_register_rx_ops(&psoc_priv->rx_ops); + pkt_capture_wdi_event_subscribe(psoc); + pkt_capture_record_channel(vdev); + vdev_priv->curr_freq = vdev->vdev_mlme.des_chan->ch_freq; + vdev_priv->last_freq = vdev_priv->curr_freq; + + status = tgt_pkt_capture_register_ev_handler(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto register_ev_handlers_fail; + + /* + * set register event bit so that mon thread will start + * processing packets in queue. + */ + set_bit(PKT_CAPTURE_REGISTER_EVENT, + &vdev_priv->mon_ctx->mon_event_flag); + + mode = pkt_capture_get_mode(psoc); + status = tgt_pkt_capture_send_mode(vdev, mode); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Unable to send packet capture mode to fw"); + goto send_mode_fail; + } + + qdf_wake_lock_acquire(&vdev_priv->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + qdf_runtime_pm_prevent_suspend(&vdev_priv->runtime_lock); + + return QDF_STATUS_SUCCESS; + +send_mode_fail: + tgt_pkt_capture_unregister_ev_handler(vdev); +register_ev_handlers_fail: + pkt_capture_mgmt_rx_ops(psoc, false); +mgmt_rx_ops_fail: + vdev_priv->cb_ctx->mon_cb = NULL; + vdev_priv->cb_ctx->mon_ctx = NULL; + + return status; +} + +QDF_STATUS pkt_capture_deregister_callbacks(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev priv is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = tgt_pkt_capture_send_mode(vdev, PACKET_CAPTURE_MODE_DISABLE); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to send packet capture mode to fw"); + + /* + * Clear packet capture register event so that mon thread will + * stop processing packets in queue. + */ + clear_bit(PKT_CAPTURE_REGISTER_EVENT, + &vdev_priv->mon_ctx->mon_event_flag); + set_bit(PKT_CAPTURE_RX_POST_EVENT, + &vdev_priv->mon_ctx->mon_event_flag); + reinit_completion(&vdev_priv->mon_ctx->mon_register_event); + wake_up_interruptible(&vdev_priv->mon_ctx->mon_wait_queue); + + /* + * Wait till current packet process completes in mon thread and + * flush the remaining packet in queue. + */ + wait_for_completion(&vdev_priv->mon_ctx->mon_register_event); + pkt_capture_drop_monpkt(vdev_priv->mon_ctx); + + pkt_capture_wdi_event_unsubscribe(psoc); + status = tgt_pkt_capture_unregister_ev_handler(vdev); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to unregister event handlers"); + + status = pkt_capture_mgmt_rx_ops(psoc, false); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Failed to unregister pkt capture mgmt rx ops"); + + vdev_priv->cb_ctx->mon_cb = NULL; + vdev_priv->cb_ctx->mon_ctx = NULL; + + qdf_wake_lock_release(&vdev_priv->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + qdf_runtime_pm_allow_suspend(&vdev_priv->runtime_lock); + + return QDF_STATUS_SUCCESS; +} + +void pkt_capture_set_pktcap_mode(struct wlan_objmgr_psoc *psoc, + enum pkt_capture_mode mode) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, + QDF_STA_MODE, + WLAN_PKT_CAPTURE_ID); + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (vdev_priv) + vdev_priv->cfg_params.pkt_capture_mode = mode; + else + pkt_capture_err("vdev_priv is NULL"); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); +} + +enum pkt_capture_mode +pkt_capture_get_pktcap_mode(struct wlan_objmgr_psoc *psoc) +{ + enum pkt_capture_mode mode = PACKET_CAPTURE_MODE_DISABLE; + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return 0; + } + + if (!pkt_capture_get_mode(psoc)) + return 0; + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, + QDF_STA_MODE, + WLAN_PKT_CAPTURE_ID); + if (!vdev) + return 0; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) + pkt_capture_err("vdev_priv is NULL"); + else + mode = vdev_priv->cfg_params.pkt_capture_mode; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); + return mode; +} + +void pkt_capture_set_pktcap_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config) +{ + struct pkt_capture_vdev_priv *vdev_priv; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (vdev_priv) + vdev_priv->cfg_params.pkt_capture_config = config; + else + pkt_capture_err("vdev_priv is NULL"); +} + +enum pkt_capture_config +pkt_capture_get_pktcap_config(struct wlan_objmgr_vdev *vdev) +{ + enum pkt_capture_config config = 0; + struct pkt_capture_vdev_priv *vdev_priv; + + if (!vdev) + return 0; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) + pkt_capture_err("vdev_priv is NULL"); + else + config = vdev_priv->cfg_params.pkt_capture_config; + + return config; +} + +/** + * pkt_capture_callback_ctx_create() - Create packet capture callback context + * @vdev_priv: pointer to packet capture vdev priv obj + * + * Return: QDF_STATUS + */ +static QDF_STATUS +pkt_capture_callback_ctx_create(struct pkt_capture_vdev_priv *vdev_priv) +{ + struct pkt_capture_cb_context *cb_ctx; + + cb_ctx = qdf_mem_malloc(sizeof(*cb_ctx)); + if (!cb_ctx) + return QDF_STATUS_E_NOMEM; + + vdev_priv->cb_ctx = cb_ctx; + + return QDF_STATUS_SUCCESS; +} + +/** + * pkt_capture_callback_ctx_destroy() - Destroy packet capture callback context + * @vdev_priv: pointer to packet capture vdev priv obj + * + * Return: None + */ +static void +pkt_capture_callback_ctx_destroy(struct pkt_capture_vdev_priv *vdev_priv) +{ + qdf_mem_free(vdev_priv->cb_ctx); +} + +/** + * pkt_capture_mon_context_create() - Create packet capture mon context + * @vdev_priv: pointer to packet capture vdev priv obj + * + * This function allocates memory for packet capture mon context + * + * Return: QDF_STATUS + */ +static QDF_STATUS +pkt_capture_mon_context_create(struct pkt_capture_vdev_priv *vdev_priv) +{ + struct pkt_capture_mon_context *mon_context; + + mon_context = qdf_mem_malloc(sizeof(*mon_context)); + if (!mon_context) + return QDF_STATUS_E_NOMEM; + + vdev_priv->mon_ctx = mon_context; + + return QDF_STATUS_SUCCESS; +} + +/** + * pkt_capture_mon_context_destroy() - Destroy packet capture mon context + * @vdev_priv: pointer to packet capture vdev priv obj + * + * Free packet capture mon context + * + * Return: None + */ +static void +pkt_capture_mon_context_destroy(struct pkt_capture_vdev_priv *vdev_priv) +{ + qdf_mem_free(vdev_priv->mon_ctx); +} + +uint32_t pkt_capture_drop_nbuf_list(qdf_nbuf_t buf_list) +{ + qdf_nbuf_t buf, next_buf; + uint32_t num_dropped = 0; + + buf = buf_list; + while (buf) { + QDF_NBUF_CB_RX_PEER_CACHED_FRM(buf) = 1; + next_buf = qdf_nbuf_queue_next(buf); + qdf_nbuf_free(buf); + buf = next_buf; + num_dropped++; + } + return num_dropped; +} + +/** + * pkt_capture_cfg_init() - Initialize packet capture cfg ini params + * @psoc_priv: psoc private object + * + * Return: None + */ +static void +pkt_capture_cfg_init(struct pkt_psoc_priv *psoc_priv) +{ + struct pkt_capture_cfg *cfg_param; + + cfg_param = &psoc_priv->cfg_param; + + cfg_param->pkt_capture_mode = cfg_get(psoc_priv->psoc, + CFG_PKT_CAPTURE_MODE); +} + +QDF_STATUS +pkt_capture_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct pkt_capture_mon_context *mon_ctx; + struct pkt_capture_vdev_priv *vdev_priv; + QDF_STATUS status; + + if ((wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) || + !pkt_capture_get_mode(wlan_vdev_get_psoc(vdev))) + return QDF_STATUS_SUCCESS; + + vdev_priv = qdf_mem_malloc(sizeof(*vdev_priv)); + if (!vdev_priv) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_component_obj_attach( + vdev, + WLAN_UMAC_COMP_PKT_CAPTURE, + vdev_priv, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to attach vdev component obj"); + goto free_vdev_priv; + } + + vdev_priv->vdev = vdev; + gp_pkt_capture_vdev = vdev; + + status = pkt_capture_callback_ctx_create(vdev_priv); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pkt_capture_err("Failed to create callback context"); + goto detach_vdev_priv; + } + + status = pkt_capture_mon_context_create(vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to create mon context"); + goto destroy_pkt_capture_cb_context; + } + + mon_ctx = vdev_priv->mon_ctx; + + status = pkt_capture_alloc_mon_thread(mon_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to alloc mon thread"); + goto destroy_mon_context; + } + + status = pkt_capture_open_mon_thread(mon_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to open mon thread"); + goto open_mon_thread_fail; + } + qdf_spinlock_create(&vdev_priv->lock_q); + qdf_list_create(&vdev_priv->ppdu_stats_q, PPDU_STATS_Q_MAX_SIZE); + qdf_wake_lock_create(&vdev_priv->wake_lock, "pkt_capture_mode"); + qdf_runtime_lock_init(&vdev_priv->runtime_lock); + + return status; + +open_mon_thread_fail: + pkt_capture_free_mon_pkt_freeq(mon_ctx); +destroy_mon_context: + pkt_capture_mon_context_destroy(vdev_priv); +destroy_pkt_capture_cb_context: + pkt_capture_callback_ctx_destroy(vdev_priv); +detach_vdev_priv: + wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_PKT_CAPTURE, + vdev_priv); +free_vdev_priv: + qdf_mem_free(vdev_priv); + return status; +} + +QDF_STATUS +pkt_capture_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_ppdu_stats_q_node *stats_node; + qdf_list_node_t *node; + QDF_STATUS status; + + if ((wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) || + !pkt_capture_get_mode(wlan_vdev_get_psoc(vdev))) + return QDF_STATUS_SUCCESS; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_runtime_lock_deinit(&vdev_priv->runtime_lock); + qdf_wake_lock_destroy(&vdev_priv->wake_lock); + + while (qdf_list_remove_front(&vdev_priv->ppdu_stats_q, &node) + == QDF_STATUS_SUCCESS) { + stats_node = qdf_container_of( + node, struct pkt_capture_ppdu_stats_q_node, node); + qdf_mem_free(stats_node); + } + qdf_list_destroy(&vdev_priv->ppdu_stats_q); + qdf_spinlock_destroy(&vdev_priv->lock_q); + + status = wlan_objmgr_vdev_component_obj_detach( + vdev, + WLAN_UMAC_COMP_PKT_CAPTURE, + vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Failed to detach vdev component obj"); + + pkt_capture_close_mon_thread(vdev_priv->mon_ctx); + pkt_capture_mon_context_destroy(vdev_priv); + pkt_capture_callback_ctx_destroy(vdev_priv); + + qdf_mem_free(vdev_priv); + gp_pkt_capture_vdev = NULL; + return status; +} + +QDF_STATUS +pkt_capture_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct pkt_psoc_priv *psoc_priv; + QDF_STATUS status; + + psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv)); + if (!psoc_priv) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_PKT_CAPTURE, + psoc_priv, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to attach psoc component obj"); + goto free_psoc_priv; + } + + psoc_priv->psoc = psoc; + pkt_capture_cfg_init(psoc_priv); + + return status; + +free_psoc_priv: + qdf_mem_free(psoc_priv); + return status; +} + +QDF_STATUS +pkt_capture_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct pkt_psoc_priv *psoc_priv; + QDF_STATUS status; + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_PKT_CAPTURE, + psoc_priv); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to detach psoc component obj"); + return status; + } + + qdf_mem_free(psoc_priv); + return status; +} + +void pkt_capture_record_channel(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_channel *des_chan; + cdp_config_param_type val; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + + if (!pkt_capture_get_mode(psoc)) + return; + /* + * Record packet capture channel here + */ + des_chan = vdev->vdev_mlme.des_chan; + val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee; + cdp_txrx_set_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_CHANNEL, val); + val.cdp_pdev_param_mon_freq = des_chan->ch_freq; + cdp_txrx_set_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_FREQUENCY, val); +} + +QDF_STATUS pkt_capture_set_filter(struct pkt_capture_frame_filter frame_filter, + struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_psoc *psoc; + enum pkt_capture_mode mode = PACKET_CAPTURE_MODE_DISABLE; + ol_txrx_soc_handle soc; + QDF_STATUS status; + enum pkt_capture_config config = 0; + bool send_bcn = 0; + struct vdev_mlme_obj *vdev_mlme; + uint32_t bcn_interval, nth_beacon_value; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev_priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return QDF_STATUS_E_FAILURE; + } + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) { + pkt_capture_err("Invalid soc"); + return QDF_STATUS_E_FAILURE; + } + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE)) + vdev_priv->frame_filter.data_tx_frame_filter = + frame_filter.data_tx_frame_filter; + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE)) + vdev_priv->frame_filter.data_rx_frame_filter = + frame_filter.data_rx_frame_filter; + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE)) + vdev_priv->frame_filter.mgmt_tx_frame_filter = + frame_filter.mgmt_tx_frame_filter; + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE)) + vdev_priv->frame_filter.mgmt_rx_frame_filter = + frame_filter.mgmt_rx_frame_filter; + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE)) + vdev_priv->frame_filter.ctrl_tx_frame_filter = + frame_filter.ctrl_tx_frame_filter; + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE)) + vdev_priv->frame_filter.ctrl_rx_frame_filter = + frame_filter.ctrl_rx_frame_filter; + + if (frame_filter.vendor_attr_to_set & + BIT(PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL)) { + if (frame_filter.connected_beacon_interval != + vdev_priv->frame_filter.connected_beacon_interval) { + vdev_priv->frame_filter.connected_beacon_interval = + frame_filter.connected_beacon_interval; + send_bcn = 1; + } + } + + if (vdev_priv->frame_filter.mgmt_tx_frame_filter) + mode |= PACKET_CAPTURE_MODE_MGMT_ONLY; + + if (vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_FRAME_TYPE_ALL) { + mode |= PACKET_CAPTURE_MODE_MGMT_ONLY; + vdev_priv->frame_filter.mgmt_rx_frame_filter |= + PKT_CAPTURE_MGMT_CONNECT_BEACON; + vdev_priv->frame_filter.mgmt_rx_frame_filter |= + PKT_CAPTURE_MGMT_CONNECT_SCAN_BEACON; + if (!send_bcn) + config |= PACKET_CAPTURE_CONFIG_BEACON_ENABLE; + config |= PACKET_CAPTURE_CONFIG_OFF_CHANNEL_BEACON_ENABLE; + } else { + if (vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_CONNECT_NO_BEACON) { + mode |= PACKET_CAPTURE_MODE_MGMT_ONLY; + config |= PACKET_CAPTURE_CONFIG_NO_BEACON_ENABLE; + } + + if (vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_CONNECT_BEACON) { + if (!send_bcn) + config |= PACKET_CAPTURE_CONFIG_BEACON_ENABLE; + } + + if (vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_CONNECT_SCAN_BEACON) + config |= + PACKET_CAPTURE_CONFIG_OFF_CHANNEL_BEACON_ENABLE; + } + + if (vdev_priv->frame_filter.data_tx_frame_filter || + vdev_priv->frame_filter.data_rx_frame_filter) + mode |= PACKET_CAPTURE_MODE_DATA_ONLY; + + if (mode != pkt_capture_get_pktcap_mode(psoc)) { + status = tgt_pkt_capture_send_mode(vdev, mode); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Unable to send packet capture mode"); + return status; + } + + if (mode & PACKET_CAPTURE_MODE_DATA_ONLY) + cdp_set_pkt_capture_mode(soc, true); + } + + if (vdev_priv->frame_filter.ctrl_tx_frame_filter || + vdev_priv->frame_filter.ctrl_rx_frame_filter) + config |= PACKET_CAPTURE_CONFIG_TRIGGER_ENABLE; + + if ((vdev_priv->frame_filter.data_tx_frame_filter & + PKT_CAPTURE_DATA_FRAME_TYPE_ALL) || + (vdev_priv->frame_filter.data_tx_frame_filter & + PKT_CAPTURE_DATA_FRAME_QOS_NULL)) + config |= PACKET_CAPTURE_CONFIG_QOS_ENABLE; + + if (config != pkt_capture_get_pktcap_config(vdev)) { + status = tgt_pkt_capture_send_config(vdev, config); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("packet capture send config failed"); + return status; + } + } + + if (send_bcn) { + vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj( + vdev, + WLAN_UMAC_COMP_MLME); + + if (!vdev_mlme) + return QDF_STATUS_E_FAILURE; + + wlan_util_vdev_mlme_get_param(vdev_mlme, + WLAN_MLME_CFG_BEACON_INTERVAL, + &bcn_interval); + + if (bcn_interval && + (vdev_priv->frame_filter.connected_beacon_interval > + bcn_interval || vdev_priv-> + frame_filter.connected_beacon_interval == 0)) { + nth_beacon_value = + vdev_priv-> + frame_filter.connected_beacon_interval / + bcn_interval; + + status = tgt_pkt_capture_send_beacon_interval( + vdev, + nth_beacon_value); + + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("send beacon interval fail"); + return status; + } + } else { + pkt_capture_debug( + "Failed to set beacon interval %d, it should be >= %d", + vdev_priv->frame_filter.connected_beacon_interval, + bcn_interval); + } + } + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c new file mode 100644 index 0000000000..32756f4033 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c @@ -0,0 +1,782 @@ +/* + * Copyright (c) 2020, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement mgmt txrx APIs which shall be used internally only + * in pkt_capture component. + * Note: These APIs should be never accessed out of pkt_capture component. + */ + +#include "wlan_pkt_capture_main.h" +#include "wlan_pkt_capture_priv.h" +#include "wlan_pkt_capture_mgmt_txrx.h" +#include "wlan_mlme_main.h" +#include "wlan_lmac_if_api.h" +#include "wlan_mgmt_txrx_utils_api.h" +#include "wlan_utility.h" +#include "cds_ieee80211_common.h" +#include "cdp_txrx_ctrl.h" + +enum pkt_capture_tx_status +pkt_capture_mgmt_status_map(uint8_t status) +{ + enum pkt_capture_tx_status tx_status; + + switch (status) { + case WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK: + tx_status = pkt_capture_tx_status_ok; + break; + case WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK: + tx_status = pkt_capture_tx_status_no_ack; + break; + default: + tx_status = pkt_capture_tx_status_discard; + break; + } + + return tx_status; +} + +/** + * pkt_capture_mgmtpkt_cb() - callback to process management packets + * for pkt capture mode + * @context: vdev handler + * @ppdev: unused param + * @nbuf_list: netbuf list + * @vdev_id: vdev id for which packet is captured + * @tid: tid number + * @ch_freq: channel frequency + * @pkt_format: Frame format + * @bssid: + * @tx_retry_cnt: tx retry count + * + * Return: none + */ +static void +pkt_capture_mgmtpkt_cb(void *context, void *ppdev, void *nbuf_list, + uint8_t vdev_id, uint8_t tid, uint16_t ch_freq, + bool pkt_format, uint8_t *bssid, uint8_t tx_retry_cnt) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_psoc *psoc = context; + struct pkt_capture_cb_context *cb_ctx; + struct wlan_objmgr_vdev *vdev; + qdf_nbuf_t msdu, next_buf; + uint32_t drop_count; + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, + QDF_STA_MODE, + WLAN_PKT_CAPTURE_ID); + if (!vdev) { + pkt_capture_err("vdev is NULL"); + goto free_buf; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + goto release_vdev_ref; + } + + cb_ctx = vdev_priv->cb_ctx; + if (!cb_ctx || !cb_ctx->mon_cb || !cb_ctx->mon_ctx) { + pkt_capture_err("mon cb params are NULL"); + goto release_vdev_ref; + } + + msdu = nbuf_list; + while (msdu) { + next_buf = qdf_nbuf_queue_next(msdu); + qdf_nbuf_set_next(msdu, NULL); /* Add NULL terminator */ + pkt_capture_mon(cb_ctx, msdu, vdev, ch_freq); + msdu = next_buf; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); + return; + +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); +free_buf: + drop_count = pkt_capture_drop_nbuf_list(nbuf_list); + pkt_capture_debug("Dropped frames %u", drop_count); +} + +/** + * pkt_capture_mgmtpkt_process() - process management packets + * for pkt capture mode + * @psoc: pointer to psoc object + * @txrx_status: mon_rx_status to update radiotap header + * @nbuf: netbuf + * @status: Tx status + * + * Return: QDF_STATUS Enumeration + */ +static QDF_STATUS +pkt_capture_mgmtpkt_process(struct wlan_objmgr_psoc *psoc, + struct mon_rx_status *txrx_status, + qdf_nbuf_t nbuf, uint8_t status) +{ + struct wlan_objmgr_vdev *vdev; + struct pkt_capture_mon_pkt *pkt; + uint32_t headroom; + uint8_t type, sub_type; + struct ieee80211_frame *wh; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_pdev *pdev; + cdp_config_param_type val; + tSirMacAuthFrameBody *auth; + struct pkt_capture_vdev_priv *vdev_priv; + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, + QDF_STA_MODE, + WLAN_PKT_CAPTURE_ID); + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + pkt_capture_err("pdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wh = (struct ieee80211_frame *)(qdf_nbuf_data(nbuf)); + type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + sub_type = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + /* + * Update channel only if successful AUTH Resp is received. + * This is done so that EAPOL M1 data frame have correct + * channel + */ + if ((type == IEEE80211_FC0_TYPE_MGT) && + (sub_type == MGMT_SUBTYPE_AUTH)) { + uint8_t chan = wlan_freq_to_chan(txrx_status->chan_freq); + + auth = (tSirMacAuthFrameBody *)(qdf_nbuf_data(nbuf) + + sizeof(tSirMacMgmtHdr)); + + if (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2 || + auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4) { + if (auth->authStatusCode == STATUS_SUCCESS) { + val.cdp_pdev_param_monitor_chan = chan; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_CHANNEL, val); + + val.cdp_pdev_param_mon_freq = + txrx_status->chan_freq; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_FREQUENCY, val); + } + } + } + + /* + * Update channel to last connected channel in case of assoc/reassoc + * response failure and save current chan in case of success + */ + if ((type == IEEE80211_FC0_TYPE_MGT) && + ((sub_type == MGMT_SUBTYPE_ASSOC_RESP) || + (sub_type == MGMT_SUBTYPE_REASSOC_RESP))) { + if (qdf_nbuf_len(nbuf) < (sizeof(tSirMacMgmtHdr) + + SIR_MAC_ASSOC_RSP_STATUS_CODE_OFFSET)) { + pkt_capture_err("Packet length is less than expected"); + qdf_nbuf_free(nbuf); + return QDF_STATUS_E_FAILURE; + } + + status = (uint16_t)(*(qdf_nbuf_data(nbuf) + + sizeof(tSirMacMgmtHdr) + + SIR_MAC_ASSOC_RSP_STATUS_CODE_OFFSET)); + + if (status == STATUS_SUCCESS) { + vdev_priv->last_freq = vdev_priv->curr_freq; + vdev_priv->curr_freq = txrx_status->chan_freq; + } else { + uint8_t chan_num; + + chan_num = wlan_reg_freq_to_chan(pdev, + vdev_priv->last_freq); + + val.cdp_pdev_param_monitor_chan = chan_num; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_CHANNEL, val); + + val.cdp_pdev_param_mon_freq = vdev_priv->last_freq; + cdp_txrx_set_pdev_param( + soc, wlan_objmgr_pdev_get_pdev_id(pdev), + CDP_MONITOR_FREQUENCY, val); + + vdev_priv->curr_freq = vdev_priv->last_freq; + } + } + + /* + * Calculate the headroom and adjust head to prepare radiotap header + */ + headroom = qdf_nbuf_headroom(nbuf); + qdf_nbuf_update_radiotap(txrx_status, nbuf, headroom); + + pkt = pkt_capture_alloc_mon_pkt(vdev); + if (!pkt) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); + return QDF_STATUS_E_FAILURE; + } + + pkt->callback = pkt_capture_mgmtpkt_cb; + pkt->context = psoc; + pkt->monpkt = nbuf; + pkt->vdev_id = WLAN_INVALID_VDEV_ID; + pkt->tid = WLAN_INVALID_TID; + pkt->status = txrx_status->chan_freq; + pkt->pkt_format = PKTCAPTURE_PKT_FORMAT_80211; + pkt_capture_indicate_monpkt(vdev, pkt); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * pkt_capture_is_rmf_enabled - API to check if rmf is enabled or not + * @pdev: pointer to pdev object + * @psoc: pointer to psoc object + * @addr: mac address + */ +static bool +pkt_capture_is_rmf_enabled(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc, + uint8_t *addr) +{ + struct pkt_psoc_priv *psoc_priv; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + int rmf_enabled; + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc priv is NULL"); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(pdev, + addr, + WLAN_PKT_CAPTURE_ID); + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return false; + } + + vdev_id = wlan_vdev_get_id(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); + + rmf_enabled = psoc_priv->cb_obj.get_rmf_status(vdev_id); + if (rmf_enabled < 0) { + pkt_capture_err("unable to get rmf status"); + return false; + } + + return true; +} + +/** + * pkt_capture_process_rmf_frame - process rmf frame + * @pdev: pointer to pdev object + * @psoc: pointer to psoc object + * @nbuf: netbuf + */ +static QDF_STATUS +pkt_capture_process_rmf_frame(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc, + qdf_nbuf_t nbuf) +{ + tpSirMacFrameCtl pfc = (tpSirMacFrameCtl)(qdf_nbuf_data(nbuf)); + uint8_t mic_len, hdr_len, pdev_id; + struct ieee80211_frame *wh; + uint8_t *orig_hdr; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(nbuf); + + if (!QDF_IS_ADDR_BROADCAST(wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (pfc->wep) { + QDF_STATUS status; + + orig_hdr = (uint8_t *)qdf_nbuf_data(nbuf); + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + status = mlme_get_peer_mic_len(psoc, pdev_id, + wh->i_addr1, + &mic_len, + &hdr_len); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to get mic hdr"); + return QDF_STATUS_E_FAILURE; + } + + /* Strip privacy headers (and trailer) + * for a received frame + */ + qdf_mem_move(orig_hdr + hdr_len, wh, sizeof(*wh)); + qdf_nbuf_pull_head(nbuf, hdr_len); + qdf_nbuf_trim_tail(nbuf, mic_len); + } + } else { + qdf_nbuf_trim_tail(nbuf, IEEE80211_MMIE_LEN); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +pkt_capture_process_mgmt_tx_data(struct wlan_objmgr_pdev *pdev, + struct mgmt_offload_event_params *params, + qdf_nbuf_t nbuf, + uint8_t status) +{ + struct mon_rx_status txrx_status = {0}; + struct wlan_objmgr_psoc *psoc; + tpSirMacFrameCtl pfc = (tpSirMacFrameCtl)(qdf_nbuf_data(nbuf)); + struct ieee80211_frame *wh; + uint16_t rate; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wh = (struct ieee80211_frame *)qdf_nbuf_data(nbuf); + + if ((pfc->type == IEEE80211_FC0_TYPE_MGT) && + (pfc->subType == SIR_MAC_MGMT_DISASSOC || + pfc->subType == SIR_MAC_MGMT_DEAUTH || + pfc->subType == SIR_MAC_MGMT_ACTION)) { + if (pkt_capture_is_rmf_enabled(pdev, psoc, wh->i_addr2)) { + QDF_STATUS status; + + status = pkt_capture_process_rmf_frame(pdev, psoc, + nbuf); + if (QDF_IS_STATUS_ERROR(status)) + return status; + } + } + + txrx_status.tsft = (u_int64_t)params->tsf_l32; + txrx_status.chan_num = wlan_reg_freq_to_chan(pdev, params->chan_freq); + txrx_status.chan_freq = params->chan_freq; + if (params->rssi == INVALID_RSSI_FOR_TX) + /* RSSI -128 is invalid rssi for TX, make it 0 here, + * will be normalized during radiotap updation + */ + txrx_status.ant_signal_db = 0; + else + txrx_status.ant_signal_db = params->rssi; + + txrx_status.rssi_comb = txrx_status.ant_signal_db; + txrx_status.nr_ant = 1; + rate = params->rate_kbps * 2; + /* params->rate is in Kbps, convert into Mbps */ + txrx_status.rate = (uint8_t)(rate / 1000); + + txrx_status.rtap_flags |= + ((txrx_status.rate == 12 /* Mbps */) ? BIT(1) : 0); + + if (txrx_status.rate == 12) + txrx_status.ofdm_flag = 1; + else + txrx_status.cck_flag = 1; + + txrx_status.tx_status = status; + txrx_status.tx_retry_cnt = params->tx_retry_cnt; + txrx_status.add_rtap_ext = true; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(nbuf); + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + + return pkt_capture_mgmtpkt_process(psoc, &txrx_status, + nbuf, status); +} + +void pkt_capture_mgmt_tx(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t nbuf, + uint16_t chan_freq, + uint8_t preamble_type) +{ + struct mgmt_offload_event_params params = {0}; + tpSirMacFrameCtl pfc = (tpSirMacFrameCtl)(qdf_nbuf_data(nbuf)); + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + qdf_nbuf_t wbuf; + int nbuf_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pdev) { + pkt_capture_err("pdev is NULL"); + return; + } + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("failed to get vdev ref"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + return; + } + + if (pfc->type == IEEE80211_FC0_TYPE_MGT && + !(vdev_priv->frame_filter.mgmt_tx_frame_filter & + PKT_CAPTURE_MGMT_FRAME_TYPE_ALL)) + goto exit; + + if (pfc->type == IEEE80211_FC0_TYPE_CTL && + !vdev_priv->frame_filter.ctrl_tx_frame_filter) + goto exit; + + nbuf_len = qdf_nbuf_len(nbuf); + wbuf = qdf_nbuf_alloc(NULL, roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!wbuf) { + pkt_capture_err("Failed to allocate wbuf for mgmt len(%u)", + nbuf_len); + goto exit; + } + + qdf_nbuf_put_tail(wbuf, nbuf_len); + qdf_mem_copy(qdf_nbuf_data(wbuf), qdf_nbuf_data(nbuf), nbuf_len); + + params.chan_freq = chan_freq; + /* + * Filling Tpc in rssi field. + * As Tpc is not available, filling with default value of tpc + */ + params.rssi = 0; + /* Assigning the local timestamp as TSF timestamp is not available*/ + params.tsf_l32 = (uint32_t)jiffies; + + if (preamble_type == (1 << WMI_RATE_PREAMBLE_CCK)) + params.rate_kbps = 1000; /* Rate is 1 Mbps for CCK */ + else + params.rate_kbps = 6000; /* Rate is 6 Mbps for OFDM */ + + /* + * The mgmt tx packet is send to mon interface before tx completion. + * we do not have status for this packet, using magic number(0xFF) + * as status for mgmt tx packet + */ + if (QDF_STATUS_SUCCESS != + pkt_capture_process_mgmt_tx_data(pdev, ¶ms, wbuf, 0xFF)) + qdf_nbuf_free(wbuf); +exit: + pkt_capture_vdev_put_ref(vdev); +} + +void +pkt_capture_mgmt_tx_completion(struct wlan_objmgr_pdev *pdev, + uint32_t desc_id, + uint32_t status, + struct mgmt_offload_event_params *params) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + tpSirMacFrameCtl pfc; + qdf_nbuf_t wbuf, nbuf; + int nbuf_len; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + if (!pdev) { + pkt_capture_err("pdev is NULL"); + return; + } + + vdev = pkt_capture_get_vdev(); + ret = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(ret)) { + pkt_capture_err("failed to get vdev ref"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + return; + } + + nbuf = mgmt_txrx_get_nbuf(pdev, desc_id); + if (!nbuf) + goto exit; + + pfc = (tpSirMacFrameCtl)(qdf_nbuf_data(nbuf)); + if (pfc->type == IEEE80211_FC0_TYPE_MGT && + !(vdev_priv->frame_filter.mgmt_tx_frame_filter & + PKT_CAPTURE_MGMT_FRAME_TYPE_ALL)) + goto exit; + + if (pfc->type == IEEE80211_FC0_TYPE_CTL && + !vdev_priv->frame_filter.ctrl_tx_frame_filter) + goto exit; + + nbuf_len = qdf_nbuf_len(nbuf); + wbuf = qdf_nbuf_alloc(NULL, roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!wbuf) { + pkt_capture_err("Failed to allocate wbuf for mgmt len(%u)", + nbuf_len); + goto exit; + } + + qdf_nbuf_put_tail(wbuf, nbuf_len); + qdf_mem_copy(qdf_nbuf_data(wbuf), qdf_nbuf_data(nbuf), nbuf_len); + + if (QDF_STATUS_SUCCESS != + pkt_capture_process_mgmt_tx_data( + pdev, params, wbuf, + pkt_capture_mgmt_status_map(status))) + qdf_nbuf_free(wbuf); + +exit: + pkt_capture_vdev_put_ref(vdev); +} + +/** + * pkt_capture_is_beacon_forward_enable() - API to check whether particular + * beacon needs to be forwarded on mon interface based on vendor command + * @vdev: vdev object + * @wbuf: netbuf + * + * Return: bool + */ +static bool +pkt_capture_is_beacon_forward_enable(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t wbuf) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct qdf_mac_addr connected_bssid = {0}; + tpSirMacMgmtHdr mac_hdr; + bool my_beacon = false; + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return false; + } + + mac_hdr = (tpSirMacMgmtHdr)(qdf_nbuf_data(wbuf)); + wlan_vdev_get_bss_peer_mac(vdev, &connected_bssid); + + if (qdf_is_macaddr_equal((struct qdf_mac_addr *)mac_hdr->bssId, + &connected_bssid)) + my_beacon = true; + + if (((vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_CONNECT_BEACON) || + vdev_priv->frame_filter.connected_beacon_interval) && my_beacon) + return true; + + if (vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_CONNECT_SCAN_BEACON && !my_beacon) + return true; + + return false; +} + +#ifdef DP_MON_RSSI_IN_DBM +#define PKT_CAPTURE_FILL_RSSI(rx_params) \ +((rx_params)->snr + NORMALIZED_TO_NOISE_FLOOR) +#else +#define PKT_CAPTURE_FILL_RSSI(rx_status) \ +((rx_params)->snr) +#endif + +/** + * pkt_capture_mgmt_rx_data_cb() - process management rx packets + * @psoc: psoc object + * @peer: Peer object + * @wbuf: netbuf + * @rx_params: mgmt rx event params + * @frm_type: frame type + * + * Return: none + */ +static QDF_STATUS +pkt_capture_mgmt_rx_data_cb(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + qdf_nbuf_t wbuf, + struct mgmt_rx_event_params *rx_params, + enum mgmt_frame_type frm_type) +{ + struct mon_rx_status txrx_status = {0}; + struct pkt_capture_vdev_priv *vdev_priv; + struct ieee80211_frame *wh; + tpSirMacFrameCtl pfc; + qdf_nbuf_t nbuf; + int buf_len; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = pkt_capture_get_vdev(); + status = pkt_capture_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("failed to get vdev ref"); + qdf_nbuf_free(wbuf); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + qdf_nbuf_free(wbuf); + return QDF_STATUS_E_FAILURE; + } + + pfc = (tpSirMacFrameCtl)(qdf_nbuf_data(wbuf)); + + if (pfc->type == SIR_MAC_CTRL_FRAME && + !vdev_priv->frame_filter.ctrl_rx_frame_filter) + goto exit; + + if (pfc->type == SIR_MAC_MGMT_FRAME && + !vdev_priv->frame_filter.mgmt_rx_frame_filter) + goto exit; + + if (pfc->type == SIR_MAC_MGMT_FRAME) { + if (pfc->subType == SIR_MAC_MGMT_BEACON) { + if (!pkt_capture_is_beacon_forward_enable(vdev, wbuf)) + goto exit; + } else { + if (!((vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_FRAME_TYPE_ALL) || + (vdev_priv->frame_filter.mgmt_rx_frame_filter & + PKT_CAPTURE_MGMT_CONNECT_NO_BEACON))) + goto exit; + } + } + + buf_len = qdf_nbuf_len(wbuf); + nbuf = qdf_nbuf_alloc(NULL, roundup( + buf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!nbuf) { + pkt_capture_vdev_put_ref(vdev); + qdf_nbuf_free(wbuf); + return QDF_STATUS_E_FAILURE; + } + + qdf_nbuf_put_tail(nbuf, buf_len); + qdf_mem_copy(qdf_nbuf_data(nbuf), qdf_nbuf_data(wbuf), buf_len); + + qdf_nbuf_free(wbuf); + + pfc = (tpSirMacFrameCtl)(qdf_nbuf_data(nbuf)); + wh = (struct ieee80211_frame *)qdf_nbuf_data(nbuf); + + pdev = wlan_vdev_get_pdev(vdev); + pkt_capture_vdev_put_ref(vdev); + + if ((pfc->type == IEEE80211_FC0_TYPE_MGT) && + (pfc->subType == SIR_MAC_MGMT_DISASSOC || + pfc->subType == SIR_MAC_MGMT_DEAUTH || + pfc->subType == SIR_MAC_MGMT_ACTION)) { + if (pkt_capture_is_rmf_enabled(pdev, psoc, wh->i_addr1)) { + QDF_STATUS status; + + status = pkt_capture_process_rmf_frame(pdev, psoc, + nbuf); + if (QDF_IS_STATUS_ERROR(status)) + return status; + } + } + + txrx_status.tsft = (u_int64_t)rx_params->tsf_l32; + txrx_status.chan_num = rx_params->channel; + txrx_status.chan_freq = rx_params->chan_freq; + /* rx_params->rate is in Kbps, convert into Mbps */ + txrx_status.rate = (rx_params->rate / 1000); + txrx_status.ant_signal_db = rx_params->snr; + txrx_status.chan_noise_floor = NORMALIZED_TO_NOISE_FLOOR; + txrx_status.rssi_comb = PKT_CAPTURE_FILL_RSSI(rx_params); + txrx_status.nr_ant = 1; + txrx_status.rtap_flags |= + ((txrx_status.rate == 6 /* Mbps */) ? BIT(1) : 0); + + if (rx_params->phy_mode != PKTCAPTURE_RATECODE_CCK) + txrx_status.ofdm_flag = 1; + else + txrx_status.cck_flag = 1; + + /* Convert rate from Mbps to 500 Kbps */ + txrx_status.rate = txrx_status.rate * 2; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(nbuf); + wh->i_fc[1] &= ~IEEE80211_FC1_WEP; + + if (QDF_STATUS_SUCCESS != + pkt_capture_mgmtpkt_process(psoc, &txrx_status, nbuf, 0)) + qdf_nbuf_free(nbuf); + + return QDF_STATUS_SUCCESS; +exit: + pkt_capture_vdev_put_ref(vdev); + qdf_nbuf_free(wbuf); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pkt_capture_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, + bool is_register) +{ + struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info[2]; + QDF_STATUS status; + int num_of_entries; + + frm_cb_info[0].frm_type = MGMT_FRAME_TYPE_ALL; + frm_cb_info[0].mgmt_rx_cb = pkt_capture_mgmt_rx_data_cb; + frm_cb_info[1].frm_type = MGMT_CTRL_FRAME; + frm_cb_info[1].mgmt_rx_cb = pkt_capture_mgmt_rx_data_cb; + num_of_entries = 2; + + if (is_register) + status = wlan_mgmt_txrx_register_rx_cb( + psoc, WLAN_UMAC_COMP_PKT_CAPTURE, + frm_cb_info, num_of_entries); + else + status = wlan_mgmt_txrx_deregister_rx_cb( + psoc, WLAN_UMAC_COMP_PKT_CAPTURE, + frm_cb_info, num_of_entries); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c new file mode 100644 index 0000000000..2343008fa8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Define internal APIs related to the packet capture component + */ + +#include "wlan_pkt_capture_mon_thread.h" +#include "cds_ieee80211_common.h" +#include "wlan_mgmt_txrx_utils_api.h" +#include "cfg_ucfg_api.h" +#include "wlan_mgmt_txrx_utils_api.h" + +/* + * The following commit was introduced in v5.17: + * cead18552660 ("exit: Rename complete_and_exit to kthread_complete_and_exit") + * Use the old name for kernels before 5.17 + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)) +#define kthread_complete_and_exit(c, s) complete_and_exit(c, s) +#endif + +void pkt_capture_mon(struct pkt_capture_cb_context *cb_ctx, qdf_nbuf_t msdu, + struct wlan_objmgr_vdev *vdev, uint16_t ch_freq) +{ + if (cb_ctx->mon_cb(cb_ctx->mon_ctx, msdu) != QDF_STATUS_SUCCESS) { + pkt_capture_err("Frame Rx to HDD failed"); + qdf_nbuf_free(msdu); + } +} + +void pkt_capture_free_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt; + + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + while (!list_empty(&mon_ctx->mon_pkt_freeq)) { + pkt = list_entry((&mon_ctx->mon_pkt_freeq)->next, + typeof(*pkt), list); + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + } + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); +} + +/** + * pkt_capture_alloc_mon_pkt_freeq() - Function to allocate free buffer queue + * @mon_ctx: pointer to packet capture mon context + * + * This API allocates MAX_MON_PKT_SIZE number of mon packets + * which are used for mon data processing. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +pkt_capture_alloc_mon_pkt_freeq(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt, *tmp; + int i; + + for (i = 0; i < MAX_MON_PKT_SIZE; i++) { + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) + goto free; + + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + list_add_tail(&pkt->list, + &mon_ctx->mon_pkt_freeq); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + } + + return QDF_STATUS_SUCCESS; +free: + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, + &mon_ctx->mon_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + } + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + + return QDF_STATUS_E_NOMEM; +} + +/** + * pkt_capture_free_mon_pkt() - api to release mon packet to the freeq + * @mon_ctx: Pointer to packet capture mon context + * @pkt: MON packet buffer to be returned to free queue. + * + * This api returns the mon packet used for mon data to the free queue + * + * Return: None + */ +static void +pkt_capture_free_mon_pkt(struct pkt_capture_mon_context *mon_ctx, + struct pkt_capture_mon_pkt *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + list_add_tail(&pkt->list, &mon_ctx->mon_pkt_freeq); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); +} + +struct pkt_capture_mon_pkt * +pkt_capture_alloc_mon_pkt(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + struct pkt_capture_mon_pkt *pkt; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return NULL; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return NULL; + } + + mon_ctx = vdev_priv->mon_ctx; + if (!mon_ctx) { + pkt_capture_err("packet capture mon context is NULL"); + return NULL; + } + + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + if (list_empty(&mon_ctx->mon_pkt_freeq)) { + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + return NULL; + } + + pkt = list_first_entry(&mon_ctx->mon_pkt_freeq, + struct pkt_capture_mon_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + + return pkt; +} + +void pkt_capture_indicate_monpkt(struct wlan_objmgr_vdev *vdev, + struct pkt_capture_mon_pkt *pkt) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + mon_ctx = vdev_priv->mon_ctx; + + spin_lock_bh(&mon_ctx->mon_queue_lock); + list_add_tail(&pkt->list, &mon_ctx->mon_thread_queue); + spin_unlock_bh(&mon_ctx->mon_queue_lock); + set_bit(PKT_CAPTURE_RX_POST_EVENT, &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); +} + +void pkt_capture_wakeup_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + mon_ctx = vdev_priv->mon_ctx; + + set_bit(PKT_CAPTURE_RX_POST_EVENT, &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); +} + +/** + * pkt_capture_process_from_queue() - function to process pending mon packets + * @mon_ctx: Pointer to packet capture mon context + * + * This api traverses the pending buffer list and calling the callback. + * This callback would essentially send the packet to HDD. + * + * Return: None + */ +static void +pkt_capture_process_from_queue(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt; + uint8_t vdev_id; + uint8_t tid; + + spin_lock_bh(&mon_ctx->mon_queue_lock); + while (!list_empty(&mon_ctx->mon_thread_queue)) { + if (!test_bit(PKT_CAPTURE_REGISTER_EVENT, + &mon_ctx->mon_event_flag)) { + complete(&mon_ctx->mon_register_event); + break; + } + pkt = list_first_entry(&mon_ctx->mon_thread_queue, + struct pkt_capture_mon_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&mon_ctx->mon_queue_lock); + vdev_id = pkt->vdev_id; + tid = pkt->tid; + pkt->callback(pkt->context, pkt->pdev, pkt->monpkt, vdev_id, + tid, pkt->status, pkt->pkt_format, pkt->bssid, + pkt->tx_retry_cnt); + pkt_capture_free_mon_pkt(mon_ctx, pkt); + spin_lock_bh(&mon_ctx->mon_queue_lock); + } + spin_unlock_bh(&mon_ctx->mon_queue_lock); +} + +/** + * pkt_capture_mon_thread() - packet capture mon thread + * @arg: Pointer to vdev object manager + * + * This api is the thread handler for mon Data packet processing. + * + * Return: thread exit code + */ +static int pkt_capture_mon_thread(void *arg) +{ + struct pkt_capture_mon_context *mon_ctx; + unsigned long pref_cpu = 0; + bool shutdown = false; + int status, i; + + if (!arg) { + pkt_capture_err("Bad Args passed to mon thread"); + return 0; + } + mon_ctx = (struct pkt_capture_mon_context *)arg; + set_user_nice(current, -1); +#ifdef MSM_PLATFORM + qdf_set_wake_up_idle(true); +#endif + + /** + * Find the available cpu core other than cpu 0 and + * bind the thread + */ + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + break; + } + + set_cpus_allowed_ptr(current, cpumask_of(pref_cpu)); + + complete(&mon_ctx->mon_start_event); + + while (!shutdown) { + status = + wait_event_interruptible(mon_ctx->mon_wait_queue, + test_bit(PKT_CAPTURE_RX_POST_EVENT, + &mon_ctx->mon_event_flag) || + test_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag)); + if (status == -ERESTARTSYS) + break; + + clear_bit(PKT_CAPTURE_RX_POST_EVENT, + &mon_ctx->mon_event_flag); + while (true) { + if (test_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT, + &mon_ctx->mon_event_flag)) { + clear_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT, + &mon_ctx->mon_event_flag); + if (test_bit( + PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag)) { + clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + complete(&mon_ctx->suspend_mon_event); + } + pkt_capture_info("Shutting down pktcap thread"); + shutdown = true; + break; + } + + /* + * if packet capture deregistratin happens stop + * processing packets in queue because mon cb will + * be set to NULL. + */ + if (test_bit(PKT_CAPTURE_REGISTER_EVENT, + &mon_ctx->mon_event_flag)) + pkt_capture_process_from_queue(mon_ctx); + else + complete(&mon_ctx->mon_register_event); + + if (test_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag)) { + clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + spin_lock(&mon_ctx->mon_thread_lock); + INIT_COMPLETION(mon_ctx->resume_mon_event); + complete(&mon_ctx->suspend_mon_event); + spin_unlock(&mon_ctx->mon_thread_lock); + wait_for_completion_interruptible + (&mon_ctx->resume_mon_event); + } + break; + } + } + pkt_capture_debug("Exiting packet capture mon thread"); + kthread_complete_and_exit(&mon_ctx->mon_shutdown, 0); + + return 0; +} + +void pkt_capture_close_mon_thread(struct pkt_capture_mon_context *mon_ctx) +{ + if (!mon_ctx->mon_thread) + return; + + /* Shut down mon thread */ + set_bit(PKT_CAPTURE_RX_SHUTDOWN_EVENT, + &mon_ctx->mon_event_flag); + set_bit(PKT_CAPTURE_RX_POST_EVENT, + &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); + wait_for_completion(&mon_ctx->mon_shutdown); + mon_ctx->mon_thread = NULL; + pkt_capture_drop_monpkt(mon_ctx); + pkt_capture_free_mon_pkt_freeq(mon_ctx); +} + +QDF_STATUS +pkt_capture_open_mon_thread(struct pkt_capture_mon_context *mon_ctx) +{ + mon_ctx->mon_thread = kthread_create(pkt_capture_mon_thread, + mon_ctx, + "pkt_capture_mon_thread"); + + if (IS_ERR(mon_ctx->mon_thread)) { + pkt_capture_fatal("Could not Create packet capture mon thread"); + return QDF_STATUS_E_FAILURE; + } + wake_up_process(mon_ctx->mon_thread); + pkt_capture_debug("packet capture MON thread Created"); + + wait_for_completion_interruptible(&mon_ctx->mon_start_event); + pkt_capture_debug("packet capture MON Thread has started"); + + return QDF_STATUS_SUCCESS; +} + +void pkt_capture_drop_monpkt(struct pkt_capture_mon_context *mon_ctx) +{ + struct pkt_capture_mon_pkt *pkt, *tmp; + struct list_head local_list; + qdf_nbuf_t buf, next_buf; + + INIT_LIST_HEAD(&local_list); + spin_lock_bh(&mon_ctx->mon_queue_lock); + if (list_empty(&mon_ctx->mon_thread_queue)) { + spin_unlock_bh(&mon_ctx->mon_queue_lock); + return; + } + list_for_each_entry_safe(pkt, tmp, + &mon_ctx->mon_thread_queue, + list) + list_move_tail(&pkt->list, &local_list); + + spin_unlock_bh(&mon_ctx->mon_queue_lock); + + list_for_each_entry_safe(pkt, tmp, &local_list, list) { + list_del(&pkt->list); + buf = pkt->monpkt; + while (buf) { + next_buf = qdf_nbuf_queue_next(buf); + qdf_nbuf_free(buf); + buf = next_buf; + } + pkt_capture_free_mon_pkt(mon_ctx, pkt); + } +} + +int pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + int rc; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return -EINVAL; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return -EINVAL; + } + mon_ctx = vdev_priv->mon_ctx; + if (!mon_ctx) { + pkt_capture_err("packet capture mon context is NULL"); + return -EINVAL; + } + + set_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + wake_up_interruptible(&mon_ctx->mon_wait_queue); + rc = wait_for_completion_timeout( + &mon_ctx->suspend_mon_event, + msecs_to_jiffies(PKT_CAPTURE_SUSPEND_TIMEOUT)); + if (!rc) { + clear_bit(PKT_CAPTURE_RX_SUSPEND_EVENT, + &mon_ctx->mon_event_flag); + pkt_capture_err("Failed to suspend packet capture mon thread"); + return -EINVAL; + } + mon_ctx->is_mon_thread_suspended = true; + + return 0; +} + +void pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct pkt_capture_mon_context *mon_ctx; + + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("packet capture vdev priv is NULL"); + return; + } + mon_ctx = vdev_priv->mon_ctx; + if (!mon_ctx) { + pkt_capture_err("packet capture mon context is NULL"); + return; + } + + if (mon_ctx->is_mon_thread_suspended) + complete(&mon_ctx->resume_mon_event); +} + +QDF_STATUS +pkt_capture_alloc_mon_thread(struct pkt_capture_mon_context *mon_ctx) +{ + spin_lock_init(&mon_ctx->mon_thread_lock); + init_waitqueue_head(&mon_ctx->mon_wait_queue); + init_completion(&mon_ctx->mon_start_event); + init_completion(&mon_ctx->suspend_mon_event); + init_completion(&mon_ctx->resume_mon_event); + init_completion(&mon_ctx->mon_shutdown); + init_completion(&mon_ctx->mon_register_event); + mon_ctx->mon_event_flag = 0; + spin_lock_init(&mon_ctx->mon_queue_lock); + spin_lock_init(&mon_ctx->mon_pkt_freeq_lock); + INIT_LIST_HEAD(&mon_ctx->mon_thread_queue); + spin_lock_bh(&mon_ctx->mon_pkt_freeq_lock); + INIT_LIST_HEAD(&mon_ctx->mon_pkt_freeq); + spin_unlock_bh(&mon_ctx->mon_pkt_freeq_lock); + + return pkt_capture_alloc_mon_pkt_freeq(mon_ctx); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/cfg_pkt_capture.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/cfg_pkt_capture.h new file mode 100644 index 0000000000..08a2f116b6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/cfg_pkt_capture.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _CFG_PKT_CAPTURE_H_ +#define _CFG_PKT_CAPTURE_H_ + +#ifdef WLAN_FEATURE_PKT_CAPTURE + +#define CFG_PKT_CAPTURE_MODE_DEFAULT (0) +#define CFG_PKT_CAPTURE_MODE_MGMT_PKT BIT(0) +#define CFG_PKT_CAPTURE_MODE_DATA_PKT BIT(1) +#define CFG_PKT_CAPTURE_MODE_MAX (CFG_PKT_CAPTURE_MODE_MGMT_PKT | \ + CFG_PKT_CAPTURE_MODE_DATA_PKT) + +/* + * + * packet_capture_mode - Packet capture mode + * @Min: 0 + * @Max: 3 + * Default: 0 - Capture no packets + * + * This ini is used to decide packet capture mode + * + * packet_capture_mode = 0 - Capture no packets + * packet_capture_mode = 1 - Capture management packets only + * packet_capture_mode = 2 - Capture data packets only + * packet_capture_mode = 3 - Capture both data and management packets + * + * Supported Feature: packet capture + * + * Usage: External + * + * + */ +#define CFG_PKT_CAPTURE_MODE \ + CFG_INI_UINT("packet_capture_mode", \ + 0, \ + CFG_PKT_CAPTURE_MODE_MAX, \ + CFG_PKT_CAPTURE_MODE_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Value for packet capture mode") + +#define CFG_PKT_CAPTURE_MODE_ALL \ + CFG(CFG_PKT_CAPTURE_MODE) +#else +#define CFG_PKT_CAPTURE_MODE_ALL +#endif /* WLAN_FEATURE_PKT_CAPTURE */ +#endif /* _CFG_PKT_CAPTURE_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_api.h new file mode 100644 index 0000000000..0e31796c26 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_api.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains pkt_capture public API declarations + */ + +#ifndef _WLAN_PKT_CAPTURE_API_H_ +#define _WLAN_PKT_CAPTURE_API_H_ + +#include "wlan_pkt_capture_objmgr.h" + +/** + * wlan_pkt_capture_is_tx_mgmt_enable() - Check if tx mgmt frames filter + * is enabled + * @pdev: pointer to pdev + * + * Return: bool + */ +bool wlan_pkt_capture_is_tx_mgmt_enable(struct wlan_objmgr_pdev *pdev); + +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * wlan_pkt_capture_register_callbacks - Register packet capture callbacks + * @vdev: pointer to wlan vdev object manager + * @mon_cb: callback to call + * @context: callback context + * + * Return: 0 in case of success, invalid in case of failure. + */ +QDF_STATUS +wlan_pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context); + +#else +static inline QDF_STATUS +wlan_pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ +#endif /* _WLAN_PKT_CAPTURE_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_public_structs.h new file mode 100644 index 0000000000..33dc6d6779 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_public_structs.h @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_PKT_CAPTURE_PUBLIC_STRUCTS_H_ +#define _WLAN_PKT_CAPTURE_PUBLIC_STRUCTS_H_ + +#define PACKET_CAPTURE_DATA_MAX_FILTER BIT(18) +#define PACKET_CAPTURE_MGMT_MAX_FILTER BIT(5) +#define PACKET_CAPTURE_CTRL_MAX_FILTER BIT(3) + +/** + * enum pkt_capture_mode - packet capture modes + * @PACKET_CAPTURE_MODE_DISABLE: packet capture mode disable + * @PACKET_CAPTURE_MODE_MGMT_ONLY: capture mgmt packets only + * @PACKET_CAPTURE_MODE_DATA_ONLY: capture data packets only + */ +enum pkt_capture_mode { + PACKET_CAPTURE_MODE_DISABLE = 0, + PACKET_CAPTURE_MODE_MGMT_ONLY = BIT(0), + PACKET_CAPTURE_MODE_DATA_ONLY = BIT(1), +}; + +/** + * enum pkt_capture_config - packet capture config + * @PACKET_CAPTURE_CONFIG_TRIGGER_ENABLE: enable capture for trigger frames only + * @PACKET_CAPTURE_CONFIG_QOS_ENABLE: enable capture for qos frames only + * @PACKET_CAPTURE_CONFIG_BEACON_ENABLE: enable only connected BSSID + * beacons, when device in connected state + * @PACKET_CAPTURE_CONFIG_OFF_CHANNEL_BEACON_ENABLE: enable off channel + * beacons, when device in connected state + * @PACKET_CAPTURE_CONFIG_NO_BEACON_ENABLE: drop all beacons, when + * device in connected state + */ +enum pkt_capture_config { + PACKET_CAPTURE_CONFIG_TRIGGER_ENABLE = BIT(0), + PACKET_CAPTURE_CONFIG_QOS_ENABLE = BIT(1), + PACKET_CAPTURE_CONFIG_BEACON_ENABLE = BIT(2), + PACKET_CAPTURE_CONFIG_OFF_CHANNEL_BEACON_ENABLE = BIT(3), + PACKET_CAPTURE_CONFIG_NO_BEACON_ENABLE = BIT(4), +}; + +/** + * struct mgmt_offload_event_params - Management offload event params + * @tsf_l32: The lower 32 bits of the TSF + * @chan_freq: channel frequency in MHz + * @rate_kbps: Rate kbps + * @rssi: combined RSSI, i.e. the sum of the snr + noise floor (dBm units) + * @buf_len: length of the frame in bytes + * @tx_status: 0: xmit ok + * 1: excessive retries + * 2: blocked by tx filtering + * 4: fifo underrun + * 8: swabort + * @buf: management frame buffer + * @tx_retry_cnt: tx retry count + */ +struct mgmt_offload_event_params { + uint32_t tsf_l32; + uint32_t chan_freq; + uint16_t rate_kbps; + uint32_t rssi; + uint32_t buf_len; + uint32_t tx_status; + uint8_t *buf; + uint8_t tx_retry_cnt; +}; + +struct smu_event_params { + uint32_t vdev_id; + uint8_t rx_vht_sgi; +}; + +/** + * struct pkt_capture_callbacks - callbacks to non-converged driver + * @get_rmf_status: callback to get rmf status + */ +struct pkt_capture_callbacks { + int (*get_rmf_status)(uint8_t vdev_id); +}; + +/** + * struct wlan_pkt_capture_tx_ops - structure of tx operation function + * pointers for packet capture component + * @pkt_capture_send_mode: send packet capture mode + * @pkt_capture_send_config: send packet capture config + * @pkt_capture_send_beacon_interval: send beacon interval + * + */ +struct wlan_pkt_capture_tx_ops { + QDF_STATUS (*pkt_capture_send_mode)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pkt_capture_mode mode); + QDF_STATUS (*pkt_capture_send_config) + (struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pkt_capture_config config); + QDF_STATUS (*pkt_capture_send_beacon_interval) + (struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t nth_value); +}; + +/** + * struct wlan_pkt_capture_rx_ops - structure of rx operation function + * pointers for packet capture component + * @pkt_capture_register_ev_handlers: register mgmt offload event + * @pkt_capture_unregister_ev_handlers: unregister mgmt offload event + * @pkt_capture_register_smart_monitor_event: register smu event + * @pkt_capture_unregister_smart_monitor_event: unregister smu event + */ +struct wlan_pkt_capture_rx_ops { + QDF_STATUS (*pkt_capture_register_ev_handlers) + (struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*pkt_capture_unregister_ev_handlers) + (struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*pkt_capture_register_smart_monitor_event) + (struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*pkt_capture_unregister_smart_monitor_event) + (struct wlan_objmgr_psoc *psoc); +}; + +/** + * enum pkt_capture_data_frame_type - Represent the various + * data types to be filtered in packet capture. + * @PKT_CAPTURE_DATA_FRAME_TYPE_ALL: + * @PKT_CAPTURE_DATA_FRAME_TYPE_ARP: + * @PKT_CAPTURE_DATA_FRAME_TYPE_DHCPV4: + * @PKT_CAPTURE_DATA_FRAME_TYPE_DHCPV6: + * @PKT_CAPTURE_DATA_FRAME_TYPE_EAPOL: + * @PKT_CAPTURE_DATA_FRAME_TYPE_DNSV4: + * @PKT_CAPTURE_DATA_FRAME_TYPE_DNSV6: + * @PKT_CAPTURE_DATA_FRAME_TYPE_TCP_SYN: + * @PKT_CAPTURE_DATA_FRAME_TYPE_TCP_SYNACK: + * @PKT_CAPTURE_DATA_FRAME_TYPE_TCP_FIN: + * @PKT_CAPTURE_DATA_FRAME_TYPE_TCP_FINACK: + * @PKT_CAPTURE_DATA_FRAME_TYPE_TCP_ACK: + * @PKT_CAPTURE_DATA_FRAME_TYPE_TCP_RST: + * @PKT_CAPTURE_DATA_FRAME_TYPE_ICMPV4: + * @PKT_CAPTURE_DATA_FRAME_TYPE_ICMPV6: + * @PKT_CAPTURE_DATA_FRAME_TYPE_RTP: + * @PKT_CAPTURE_DATA_FRAME_TYPE_SIP: + * @PKT_CAPTURE_DATA_FRAME_QOS_NULL: + */ +enum pkt_capture_data_frame_type { + PKT_CAPTURE_DATA_FRAME_TYPE_ALL = BIT(0), + /* valid only if PKT_CAPTURE_DATA_DATA_FRAME_TYPE_ALL is not set */ + PKT_CAPTURE_DATA_FRAME_TYPE_ARP = BIT(1), + PKT_CAPTURE_DATA_FRAME_TYPE_DHCPV4 = BIT(2), + PKT_CAPTURE_DATA_FRAME_TYPE_DHCPV6 = BIT(3), + PKT_CAPTURE_DATA_FRAME_TYPE_EAPOL = BIT(4), + PKT_CAPTURE_DATA_FRAME_TYPE_DNSV4 = BIT(5), + PKT_CAPTURE_DATA_FRAME_TYPE_DNSV6 = BIT(6), + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_SYN = BIT(7), + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_SYNACK = BIT(8), + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_FIN = BIT(9), + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_FINACK = BIT(10), + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_ACK = BIT(11), + PKT_CAPTURE_DATA_FRAME_TYPE_TCP_RST = BIT(12), + PKT_CAPTURE_DATA_FRAME_TYPE_ICMPV4 = BIT(13), + PKT_CAPTURE_DATA_FRAME_TYPE_ICMPV6 = BIT(14), + PKT_CAPTURE_DATA_FRAME_TYPE_RTP = BIT(15), + PKT_CAPTURE_DATA_FRAME_TYPE_SIP = BIT(16), + PKT_CAPTURE_DATA_FRAME_QOS_NULL = BIT(17), +}; + +/** + * enum pkt_capture_mgmt_frame_type - Represent the various + * mgmt types to be sent over the monitor interface. + * @PKT_CAPTURE_MGMT_FRAME_TYPE_ALL: All the MGMT Frames. + * @PKT_CAPTURE_MGMT_CONNECT_NO_BEACON: All the MGMT Frames + * except the Beacons. Valid only in the Connect state. + * @PKT_CAPTURE_MGMT_CONNECT_BEACON: Only the connected + * BSSID Beacons. Valid only in the Connect state. + * @PKT_CAPTURE_MGMT_CONNECT_SCAN_BEACON: Represents + * the Beacons obtained during the scan (off channel and connected channel) + * when in connected state. + */ + +enum pkt_capture_mgmt_frame_type { + PKT_CAPTURE_MGMT_FRAME_TYPE_ALL = BIT(0), + /* valid only if PKT_CAPTURE_MGMT_FRAME_TYPE_ALL is not set */ + PKT_CAPTURE_MGMT_CONNECT_NO_BEACON = BIT(1), + PKT_CAPTURE_MGMT_CONNECT_BEACON = BIT(2), + PKT_CAPTURE_MGMT_CONNECT_SCAN_BEACON = BIT(3), +}; + +/** + * enum pkt_capture_ctrl_frame_type - Represent the various + * ctrl types to be sent over the monitor interface. + * @PKT_CAPTURE_CTRL_FRAME_TYPE_ALL: All the ctrl Frames. + * @PKT_CAPTURE_CTRL_TRIGGER_FRAME: Trigger Frame. + */ +enum pkt_capture_ctrl_frame_type { + PKT_CAPTURE_CTRL_FRAME_TYPE_ALL = BIT(0), + /* valid only if PKT_CAPTURE_CTRL_FRAME_TYPE_ALL is not set */ + PKT_CAPTURE_CTRL_TRIGGER_FRAME = BIT(1), +}; + +/** + * enum pkt_capture_attr_set_monitor_mode - Used by the + * vendor command QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE to set the + * monitor mode. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_INVALID: Invalid value + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE: u32 attribute, + * Represents the tx data packet type to be monitored (u32). These data packets + * are represented by enum pkt_capture_data_frame_type. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE: u32 attribute, + * Represents the tx data packet type to be monitored (u32). These data packets + * are represented by enum pkt_capture_data_frame_type. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE: u32 attribute, + * Represents the tx data packet type to be monitored (u32). These mgmt packets + * are represented by enum pkt_capture_mgmt_frame_type. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE: u32 attribute, + * Represents the tx data packet type to be monitored (u32). These mgmt packets + * are represented by enum pkt_capture_mgmt_frame_type. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE: u32 attribute, + * Represents the tx data packet type to be monitored (u32). These ctrl packets + * are represented by enum pkt_capture_ctrl_frame_type. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE: u32 attribute, + * Represents the tx data packet type to be monitored (u32). These ctrl packets + * are represented by enum pkt_capture_ctrl_frame_type. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL: u32 attribute, + * An interval only for the connected beacon interval, which expects that the + * connected BSSID's beacons shall be sent on the monitor interface only on this + * specific interval. + * + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_AFTER_LAST: Internal use + * @PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MAX: Value of last valid enumeration + */ +enum pkt_capture_attr_set_monitor_mode { + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_INVALID = 0, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE = 1, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE = 2, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE = 3, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE = 4, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE = 5, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE = 6, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL = 7, + + /* keep last */ + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_AFTER_LAST, + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_MAX = + PKT_CAPTURE_ATTR_SET_MONITOR_MODE_AFTER_LAST - 1, + +}; + +struct pkt_capture_frame_filter { + enum pkt_capture_data_frame_type data_tx_frame_filter; + enum pkt_capture_data_frame_type data_rx_frame_filter; + enum pkt_capture_mgmt_frame_type mgmt_tx_frame_filter; + enum pkt_capture_mgmt_frame_type mgmt_rx_frame_filter; + enum pkt_capture_ctrl_frame_type ctrl_tx_frame_filter; + enum pkt_capture_ctrl_frame_type ctrl_rx_frame_filter; + uint32_t connected_beacon_interval; + uint8_t vendor_attr_to_set; +}; +#endif /* _WLAN_PKT_CAPTURE_PUBLIC_STRUCTS_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_tgt_api.h new file mode 100644 index 0000000000..fc26e89b85 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_tgt_api.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: packet capture south bound interface declaration + */ +#ifndef _WLAN_PKT_CAPTURE_TGT_API_H +#define _WLAN_PKT_CAPTURE_TGT_API_H + +#include "wlan_pkt_capture_objmgr.h" +#include "wlan_pkt_capture_main.h" +#include "wlan_pkt_capture_public_structs.h" + +/** + * tgt_pkt_capture_register_ev_handler() - register pkt capture ev handler + * @vdev: pointer to vdev object + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_pkt_capture_register_ev_handler(struct wlan_objmgr_vdev *vdev); + +/** + * tgt_pkt_capture_unregister_ev_handler() - unregister pkt capture ev handler + * @vdev: pointer to vdev object + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_pkt_capture_unregister_ev_handler(struct wlan_objmgr_vdev *vdev); + +/** + * tgt_pkt_capture_send_mode() - send packet capture mode to firmware + * @vdev: pointer to vdev object + * @mode: packet capture mode + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_pkt_capture_send_mode(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_mode mode); + +/** + * tgt_pkt_capture_send_beacon_interval() - send beacon interval to firmware + * @vdev: pointer to vdev object + * @nth_value: Beacon report period + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_pkt_capture_send_beacon_interval(struct wlan_objmgr_vdev *vdev, + uint32_t nth_value); + +/** + * tgt_pkt_capture_send_config() - send packet capture config to firmware + * @vdev: pointer to vdev object + * @config: packet capture config + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_pkt_capture_send_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config); + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * tgt_pkt_capture_smu_event() - Receive smart monitor event from firmware + * @psoc: pointer to psoc + * @param: smart monitor event params + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_pkt_capture_smu_event(struct wlan_objmgr_psoc *psoc, + struct smu_event_params *param); +#else +static inline QDF_STATUS +tgt_pkt_capture_smu_event(struct wlan_objmgr_psoc *psoc, + struct smu_event_params *param) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#endif /* _WLAN_PKT_CAPTURE_TGT_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h new file mode 100644 index 0000000000..30c1f10b3c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/inc/wlan_pkt_capture_ucfg_api.h @@ -0,0 +1,451 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare public API related to the pkt_capture called by north bound + * HDD/OSIF/LIM + */ + +#ifndef _WLAN_PKT_CAPTURE_UCFG_API_H_ +#define _WLAN_PKT_CAPTURE_UCFG_API_H_ + +#include +#include +#include "wlan_pkt_capture_objmgr.h" +#include "wlan_pkt_capture_public_structs.h" +#include "wlan_pkt_capture_mon_thread.h" +#include +#include "wlan_pkt_capture_data_txrx.h" +#include + +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * ucfg_pkt_capture_init() - Packet capture component initialization. + * + * This function gets called when packet capture initializing. + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pkt_capture_init(void); + +/** + * ucfg_pkt_capture_deinit() - Packet capture component de-init. + * + * This function gets called when packet capture de-init. + * + * Return: None + */ +void ucfg_pkt_capture_deinit(void); + +/** + * ucfg_pkt_capture_get_mode() - get packet capture mode + * @psoc: objmgr psoc handle + * + * Return: enum pkt_capture_mode + */ +enum pkt_capture_mode +ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pkt_capture_suspend_mon_thread() - suspend packet capture mon thread + * @vdev: pointer to vdev object manager + * + * Return: 0 on success, -EINVAL on failure + */ +int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pkt_capture_resume_mon_thread() - resume packet capture mon thread + * @vdev: pointer to vdev object manager + * + * Resume packet capture MON thread by completing RX thread resume event + * + * Return: None + */ +void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pkt_capture_register_callbacks - Register packet capture callbacks + * @vdev: pointer to wlan vdev object manager + * @mon_cb: callback to call + * @context: callback context + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context); + +/** + * ucfg_pkt_capture_deregister_callbacks - De-register packet capture callbacks + * @vdev: pointer to wlan vdev object manager + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pkt_capture_deregister_callbacks(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pkt_capture_set_pktcap_mode - Set packet capture mode + * @psoc: pointer to psoc object + * @val: mode to be set + * + * Return: None + */ +void ucfg_pkt_capture_set_pktcap_mode(struct wlan_objmgr_psoc *psoc, + enum pkt_capture_mode val); + +/** + * ucfg_pkt_capture_get_pktcap_mode - Get packet capture mode + * @psoc: pointer to psoc object + * + * Return: enum pkt_capture_mode + */ +enum pkt_capture_mode +ucfg_pkt_capture_get_pktcap_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pkt_capture_set_pktcap_config - Set packet capture config + * @vdev: pointer to vdev object + * @config: config to be set + * + * Return: None + */ +void ucfg_pkt_capture_set_pktcap_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config); + +/** + * ucfg_pkt_capture_get_pktcap_config - Get packet capture config + * @vdev: pointer to vdev object + * + * Return: config value + */ +enum pkt_capture_config +ucfg_pkt_capture_get_pktcap_config(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pkt_capture_process_mgmt_tx_data() - process management tx packets + * @pdev: pointer to pdev object + * @params: management offload event params + * @nbuf: netbuf + * @status: status + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pkt_capture_process_mgmt_tx_data(struct wlan_objmgr_pdev *pdev, + struct mgmt_offload_event_params *params, + qdf_nbuf_t nbuf, + uint8_t status); + +/** + * ucfg_pkt_capture_mgmt_tx() - process mgmt tx completion + * for pkt capture mode + * @pdev: pointer to pdev object + * @nbuf: netbuf + * @chan_freq: channel freq + * @preamble_type: preamble_type + * + * Return: none + */ +void +ucfg_pkt_capture_mgmt_tx(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t nbuf, + uint16_t chan_freq, + uint8_t preamble_type); + +/** + * ucfg_pkt_capture_mgmt_tx_completion() - process mgmt tx completion + * for pkt capture mode + * @pdev: pointer to pdev object + * @desc_id: desc_id + * @status: status + * @params: management offload event params + * + * Return: none + */ +void +ucfg_pkt_capture_mgmt_tx_completion( + struct wlan_objmgr_pdev *pdev, + uint32_t desc_id, + uint32_t status, + struct mgmt_offload_event_params *params); + +/** + * ucfg_pkt_capture_rx_msdu_process() - process data rx pkts + * @bssid: bssid + * @head_msdu: pointer to head msdu + * @vdev_id: vdev_id + * @pdev: pdev handle + * + * Return: none + */ +void ucfg_pkt_capture_rx_msdu_process( + uint8_t *bssid, + qdf_nbuf_t head_msdu, + uint8_t vdev_id, htt_pdev_handle pdev); + +/** + * ucfg_pkt_capture_rx_offloaded_pkt() - check offloaded data pkt or not + * @rx_ind_msg: rx_ind_msg + * + * Return: 0 not an offload pkt + * 1 offload pkt + */ +bool ucfg_pkt_capture_rx_offloaded_pkt(qdf_nbuf_t rx_ind_msg); + +/** + * ucfg_pkt_capture_rx_drop_offload_pkt() - drop offload packets + * @head_msdu: pointer to head msdu + * + * Return: none + */ +void ucfg_pkt_capture_rx_drop_offload_pkt(qdf_nbuf_t head_msdu); + +/** + * ucfg_pkt_capture_offload_deliver_indication_handler() - Handle offload + * data pkts + * @msg: offload netbuf msg + * @vdev_id: vdev id + * @bssid: bssid + * @pdev: pdev handle + * + * Return: none + */ +void ucfg_pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev); + +/** + * ucfg_pkt_capture_tx_get_txcomplete_data_hdr() - extract Tx data hdr from Tx + * completion for pkt capture mode + * @msg_word: Tx completion htt msg + * @num_msdus: number of msdus + * + * Return: tx data hdr information + */ +struct htt_tx_data_hdr_information *ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus); + +/** + * ucfg_pkt_capture_tx_completion_process() - process data tx packets + * @vdev_id: vdev id for which packet is captured + * @mon_buf_list: netbuf list + * @type: data process type + * @tid: tid number + * @status: Tx status + * @pkt_format: Frame format + * @bssid: bssid + * @pdev: pdev handle + * @tx_retry_cnt: tx retry count + * + * Return: none + */ +void ucfg_pkt_capture_tx_completion_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, htt_pdev_handle pdev, + uint8_t tx_retry_cnt); + +/** + * ucfg_pkt_capture_record_channel() - Update Channel Information + * for packet capture mode + * @vdev: pointer to vdev + * + * Return: None + */ +void ucfg_pkt_capture_record_channel(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pkt_capture_register_wma_callbacks - ucfg API to register WMA callbacks + * @psoc: pointer to psoc object + * @cb_obj: Pointer to packet capture callback structure + * + * Return: status of operation + */ +int +ucfg_pkt_capture_register_wma_callbacks(struct wlan_objmgr_psoc *psoc, + struct pkt_capture_callbacks *cb_obj); + +/** + * ucfg_pkt_capture_set_filter() - ucfg API to set frame filter + * @frame_filter: pkt capture frame filter data + * @vdev: pointer to vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pkt_capture_set_filter(struct pkt_capture_frame_filter frame_filter, + struct wlan_objmgr_vdev *vdev); + +#else +static inline +QDF_STATUS ucfg_pkt_capture_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_pkt_capture_deinit(void) +{ +} + +static inline +enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) +{ + return PACKET_CAPTURE_MODE_DISABLE; +} + +static inline +void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_pkt_capture_deregister_callbacks(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_pkt_capture_set_pktcap_mode(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ +} + +static inline enum pkt_capture_mode +ucfg_pkt_capture_get_pktcap_mode(struct wlan_objmgr_psoc *psoc) +{ + return PACKET_CAPTURE_MODE_DISABLE; +} + +static inline +void ucfg_pkt_capture_set_pktcap_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config) +{ +} + +static inline enum pkt_capture_config +ucfg_pkt_capture_get_pktcap_config(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_pkt_capture_process_mgmt_tx_data( + struct mgmt_offload_event_params *params, + qdf_nbuf_t nbuf, + uint8_t status) +{ + return 0; +} + +static inline void +ucfg_pkt_capture_mgmt_tx(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t nbuf, + uint16_t chan_freq, + uint8_t preamble_type) +{ +} + +static inline void +ucfg_pkt_capture_mgmt_tx_completion(struct wlan_objmgr_pdev *pdev, + uint32_t desc_id, + uint32_t status, + struct mgmt_offload_event_params *params) +{ +} + +static inline void +ucfg_pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev) +{ +} + +static inline +struct htt_tx_data_hdr_information *ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus) +{ + return NULL; +} + +static inline void +ucfg_pkt_capture_rx_msdu_process( + uint8_t *bssid, + qdf_nbuf_t head_msdu, + uint8_t vdev_id, htt_pdev_handle pdev) +{ +} + +static inline bool +ucfg_pkt_capture_rx_offloaded_pkt(qdf_nbuf_t rx_ind_msg) +{ + return false; +} + +static inline void +ucfg_pkt_capture_rx_drop_offload_pkt(qdf_nbuf_t head_msdu) +{ +} + +static inline void +ucfg_pkt_capture_tx_completion_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, htt_pdev_handle pdev, + uint8_t tx_retry_cnt) +{ +} + +static inline void +ucfg_pkt_capture_record_channel(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline QDF_STATUS +ucfg_pkt_capture_set_filter(struct pkt_capture_frame_filter frame_filter, + struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_FEATURE_PKT_CAPTURE */ +#endif /* _WLAN_PKT_CAPTURE_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_api.c new file mode 100644 index 0000000000..08b12717fa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_api.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains pkt_capture public API's exposed. + */ + +#include "wlan_pkt_capture_api.h" +#include "wlan_pkt_capture_main.h" + +bool wlan_pkt_capture_is_tx_mgmt_enable(struct wlan_objmgr_pdev *pdev) +{ + return pkt_capture_is_tx_mgmt_enable(pdev); +} + +QDF_STATUS +wlan_pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context) +{ + return pkt_capture_register_callbacks(vdev, mon_cb, context); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_tgt_api.c new file mode 100644 index 0000000000..1300b8aba1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_tgt_api.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains packet capture south bound interface definitions + */ + +#include "wlan_pkt_capture_tgt_api.h" + +QDF_STATUS +tgt_pkt_capture_register_ev_handler(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct pkt_psoc_priv *psoc_priv; + struct wlan_pkt_capture_rx_ops *rx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return status; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return status; + } + + rx_ops = &psoc_priv->rx_ops; + + if (!rx_ops->pkt_capture_register_ev_handlers) + return status; + + status = rx_ops->pkt_capture_register_ev_handlers(psoc); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to register mgmt offload handler"); + + status = rx_ops->pkt_capture_register_smart_monitor_event(psoc); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to register smart monitor handler"); + + return status; +} + +QDF_STATUS +tgt_pkt_capture_unregister_ev_handler(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct pkt_psoc_priv *psoc_priv; + struct wlan_pkt_capture_rx_ops *rx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return status; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return status; + } + + rx_ops = &psoc_priv->rx_ops; + + if (!rx_ops->pkt_capture_unregister_ev_handlers) + return status; + + status = rx_ops->pkt_capture_unregister_ev_handlers(psoc); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to register mgmt offload handler"); + + status = rx_ops->pkt_capture_unregister_smart_monitor_event(psoc); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to unregister smart monitor handler"); + + return status; +} + +QDF_STATUS +tgt_pkt_capture_send_mode(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_mode mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct pkt_psoc_priv *psoc_priv; + struct wlan_pkt_capture_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return status; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return status; + } + + tx_ops = &psoc_priv->tx_ops; + + if (!tx_ops->pkt_capture_send_mode) + return status; + + status = tx_ops->pkt_capture_send_mode(psoc, wlan_vdev_get_id(vdev), + mode); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to send packet capture mode to fw"); + + return status; +} + +QDF_STATUS +tgt_pkt_capture_send_beacon_interval(struct wlan_objmgr_vdev *vdev, + uint32_t nth_value) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct pkt_psoc_priv *psoc_priv; + struct wlan_pkt_capture_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return status; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return status; + } + + tx_ops = &psoc_priv->tx_ops; + + if (!tx_ops->pkt_capture_send_beacon_interval) + return status; + + status = tx_ops->pkt_capture_send_beacon_interval + (psoc, + wlan_vdev_get_id(vdev), + nth_value); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to send beacon interval to fw"); + + return status; +} + +QDF_STATUS +tgt_pkt_capture_send_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct pkt_psoc_priv *psoc_priv; + struct wlan_pkt_capture_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return status; + } + + psoc_priv = pkt_capture_psoc_get_priv(psoc); + if (!psoc_priv) { + pkt_capture_err("psoc_priv is NULL"); + return status; + } + + tx_ops = &psoc_priv->tx_ops; + + if (!tx_ops->pkt_capture_send_config) + return status; + + status = tx_ops->pkt_capture_send_config(psoc, wlan_vdev_get_id(vdev), + config); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Unable to send packet capture config to fw"); + + return status; +} + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +QDF_STATUS +tgt_pkt_capture_smu_event(struct wlan_objmgr_psoc *psoc, + struct smu_event_params *param) +{ + struct pkt_capture_vdev_priv *vdev_priv; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + + vdev_id = param->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PKT_CAPTURE_ID); + if (!vdev) { + pkt_capture_err("failed to get vdev"); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv = pkt_capture_vdev_get_priv(vdev); + if (!vdev_priv) { + pkt_capture_err("vdev priv is NULL"); + pkt_capture_vdev_put_ref(vdev); + return QDF_STATUS_E_FAILURE; + } + + vdev_priv->rx_vht_sgi = param->rx_vht_sgi; + + pkt_capture_vdev_put_ref(vdev); + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c new file mode 100644 index 0000000000..91d739547d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Public API implementation of pkt_capture called by north bound HDD/OSIF. + */ + +#include "wlan_pkt_capture_objmgr.h" +#include "wlan_pkt_capture_main.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_pkt_capture_mon_thread.h" +#include "wlan_pkt_capture_mgmt_txrx.h" +#include "target_if_pkt_capture.h" +#include "wlan_pkt_capture_data_txrx.h" +#include "wlan_pkt_capture_tgt_api.h" + +enum pkt_capture_mode ucfg_pkt_capture_get_mode(struct wlan_objmgr_psoc *psoc) +{ + return pkt_capture_get_mode(psoc); +} + +QDF_STATUS +ucfg_pkt_capture_register_callbacks(struct wlan_objmgr_vdev *vdev, + QDF_STATUS (*mon_cb)(void *, qdf_nbuf_t), + void *context) +{ + return pkt_capture_register_callbacks(vdev, mon_cb, context); +} + +QDF_STATUS ucfg_pkt_capture_deregister_callbacks(struct wlan_objmgr_vdev *vdev) +{ + return pkt_capture_deregister_callbacks(vdev); +} + +void ucfg_pkt_capture_set_pktcap_mode(struct wlan_objmgr_psoc *psoc, + enum pkt_capture_mode mode) +{ + pkt_capture_set_pktcap_mode(psoc, mode); +} + +enum pkt_capture_mode +ucfg_pkt_capture_get_pktcap_mode(struct wlan_objmgr_psoc *psoc) +{ + return pkt_capture_get_pktcap_mode(psoc); +} + +void ucfg_pkt_capture_set_pktcap_config(struct wlan_objmgr_vdev *vdev, + enum pkt_capture_config config) +{ + pkt_capture_set_pktcap_config(vdev, config); +} + +enum pkt_capture_config +ucfg_pkt_capture_get_pktcap_config(struct wlan_objmgr_vdev *vdev) +{ + return pkt_capture_get_pktcap_config(vdev); +} + +QDF_STATUS ucfg_pkt_capture_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_psoc_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to register psoc create handler"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_psoc_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to register psoc delete handler"); + goto fail_destroy_psoc; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_vdev_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to register vdev create handler"); + goto fail_create_vdev; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_vdev_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to register vdev destroy handler"); + goto fail_destroy_vdev; + } + return status; + +fail_destroy_vdev: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_vdev_create_notification, NULL); + +fail_create_vdev: + wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_psoc_destroy_notification, NULL); + +fail_destroy_psoc: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_psoc_create_notification, NULL); + + return status; +} + +void ucfg_pkt_capture_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_vdev_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Failed to unregister vdev destroy handler"); + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_vdev_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Failed to unregister vdev create handler"); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_psoc_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Failed to unregister psoc destroy handler"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_PKT_CAPTURE, + pkt_capture_psoc_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("Failed to unregister psoc create handler"); +} + +int ucfg_pkt_capture_suspend_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + return pkt_capture_suspend_mon_thread(vdev); +} + +void ucfg_pkt_capture_resume_mon_thread(struct wlan_objmgr_vdev *vdev) +{ + pkt_capture_resume_mon_thread(vdev); +} + +QDF_STATUS +ucfg_pkt_capture_process_mgmt_tx_data(struct wlan_objmgr_pdev *pdev, + struct mgmt_offload_event_params *params, + qdf_nbuf_t nbuf, + uint8_t status) +{ + return pkt_capture_process_mgmt_tx_data( + pdev, params, nbuf, + pkt_capture_mgmt_status_map(status)); + +} + +void +ucfg_pkt_capture_mgmt_tx(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t nbuf, + uint16_t chan_freq, + uint8_t preamble_type) +{ + pkt_capture_mgmt_tx(pdev, nbuf, chan_freq, preamble_type); +} + +void +ucfg_pkt_capture_mgmt_tx_completion(struct wlan_objmgr_pdev *pdev, + uint32_t desc_id, + uint32_t status, + struct mgmt_offload_event_params *params) +{ + pkt_capture_mgmt_tx_completion(pdev, desc_id, status, params); +} + +void ucfg_pkt_capture_rx_msdu_process( + uint8_t *bssid, + qdf_nbuf_t head_msdu, + uint8_t vdev_id, htt_pdev_handle pdev) +{ + pkt_capture_msdu_process_pkts(bssid, head_msdu, + vdev_id, pdev, 0); +} + +bool ucfg_pkt_capture_rx_offloaded_pkt(qdf_nbuf_t rx_ind_msg) +{ + return pkt_capture_rx_in_order_offloaded_pkt(rx_ind_msg); +} + +void ucfg_pkt_capture_rx_drop_offload_pkt(qdf_nbuf_t head_msdu) +{ + pkt_capture_rx_in_order_drop_offload_pkt(head_msdu); +} + +void +ucfg_pkt_capture_offload_deliver_indication_handler( + void *msg, uint8_t vdev_id, + uint8_t *bssid, htt_pdev_handle pdev) +{ + pkt_capture_offload_deliver_indication_handler(msg, vdev_id, + bssid, pdev); +} + +struct htt_tx_data_hdr_information *ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + uint32_t *msg_word, + int num_msdus) +{ + return pkt_capture_tx_get_txcomplete_data_hdr(msg_word, num_msdus); +} + +void +ucfg_pkt_capture_tx_completion_process( + uint8_t vdev_id, + qdf_nbuf_t mon_buf_list, + enum pkt_capture_data_process_type type, + uint8_t tid, uint8_t status, bool pkt_format, + uint8_t *bssid, htt_pdev_handle pdev, + uint8_t tx_retry_cnt) +{ + pkt_capture_datapkt_process( + vdev_id, + mon_buf_list, TXRX_PROCESS_TYPE_DATA_TX_COMPL, + tid, status, pkt_format, bssid, pdev, + tx_retry_cnt); +} + +void ucfg_pkt_capture_record_channel(struct wlan_objmgr_vdev *vdev) +{ + pkt_capture_record_channel(vdev); +} + +int +ucfg_pkt_capture_register_wma_callbacks(struct wlan_objmgr_psoc *psoc, + struct pkt_capture_callbacks *cb_obj) +{ + struct pkt_psoc_priv *psoc_priv = pkt_capture_psoc_get_priv(psoc); + + if (!psoc_priv) { + pkt_capture_err("psoc priv is NULL"); + return -EINVAL; + } + + psoc_priv->cb_obj.get_rmf_status = cb_obj->get_rmf_status; + + return 0; +} + +QDF_STATUS +ucfg_pkt_capture_set_filter(struct pkt_capture_frame_filter frame_filter, + struct wlan_objmgr_vdev *vdev) +{ + return pkt_capture_set_filter(frame_filter, vdev); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_apf.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_apf.h new file mode 100644 index 0000000000..64dfa341d9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_apf.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Android Packet Filter (APF) headers for PMO + */ + +#ifndef __WLAN_PMO_APF_H +#define __WLAN_PMO_APF_H + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" + +/** + * pmo_get_apf_instruction_size() - get the current APF instruction size + * @psoc: the psoc to query + * + * Return: APF instruction size + */ +uint32_t pmo_get_apf_instruction_size(struct wlan_objmgr_psoc *psoc); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* __WLAN_PMO_APF_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_arp.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_arp.h new file mode 100644 index 0000000000..f5035b4fcc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_arp.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare arp offload feature API's + */ + +#ifndef _WLAN_PMO_ARP_H_ +#define _WLAN_PMO_ARP_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_arp_public_struct.h" + +/** + * pmo_core_cache_arp_offload_req() - API to cache arp req in pmo vdev priv ctx + * @arp_req: arp offload request + * + * API To cache ARP offload in pmo vdev priv ctx + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_cache_arp_offload_req(struct pmo_arp_req *arp_req); + +/** + * pmo_core_arp_check_offload(): API to check if arp offload cache/send is req + * @psoc: objmgr psoc handle + * @trigger: trigger reason + * @vdev_id: vdev id + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_arp_check_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id); + +/** + * pmo_core_flush_arp_offload_req() - API to flush arp req from pmo vdev ctx + * @vdev: objmgr vdev + * + * API To flush saved ARP request from pmo vdev prov ctx + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_enable_arp_offload_in_fwr() - API to enable arp offload in fwr + * @vdev: objmgr vdev + * @trigger: trigger reason + * + * API to enable arp offload in fwr from vdev priv ctx + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_core_disable_arp_offload_in_fwr() - API to disable arp offload in fwr + * @vdev: objmgr vdev + * @trigger: trigger reason + * + * API to disable arp offload in fwr + * + * Return: QQDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_core_get_arp_offload_params() - API to get arp offload params + * @vdev: objmgr vdev + * @params: output pointer to hold offload params + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS +pmo_core_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_ARP_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_gtk.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_gtk.h new file mode 100644 index 0000000000..f08f2b5b8b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_gtk.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare gtk offload feature API's + */ + +#ifndef _WLAN_PMO_GTK_H_ +#define _WLAN_PMO_GTK_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_gtk_public_struct.h" + +/** + * pmo_core_cache_gtk_offload_req(): API to cache gtk req in pmo vdev priv obj + * @vdev: objmgr vdev handle + * @gtk_req: pmo gtk req param + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req); + +/** + * pmo_core_flush_gtk_offload_req(): Flush saved gtk req from pmo vdev priv obj + * @vdev: objmgr vdev handle + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_enable_gtk_offload_in_fwr(): enable cached gtk request in fwr + * @vdev: objmgr vdev handle + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_disable_gtk_offload_in_fwr(): disable cached gtk request in fwr + * @vdev: objmgr vdev handle + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_get_gtk_rsp(): API to send gtk response request to fwr + * @vdev: objmgr vdev handle + * @gtk_rsp_req: pmo gtk response request + * + * This api will send gtk response request to fwr + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_get_gtk_rsp(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_GTK_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_hw_filter.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_hw_filter.h new file mode 100644 index 0000000000..6739cd0cf0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_hw_filter.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare hardware filter offload feature APIs + */ + +#ifndef _WLAN_PMO_HW_FILTER_H_ +#define _WLAN_PMO_HW_FILTER_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "qdf_status.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_pmo_hw_filter_public_struct.h" + +/** + * pmo_core_enable_hw_filter_in_fwr() - enable previously configured hw filter + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_disable_hw_filter_in_fwr() - disable previously configured hw filter + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* _WLAN_PMO_HW_FILTER_H_*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_icmp.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_icmp.h new file mode 100644 index 0000000000..31a66ec1da --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_icmp.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare icmp offload feature API's + */ + +#ifndef _WLAN_PMO_ICMP_H_ +#define _WLAN_PMO_ICMP_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" + +/** + * pmo_core_icmp_check_offload() - API to check if icmp offload is enabled + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_core_icmp_check_offload(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_ICMP_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_lphb.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_lphb.h new file mode 100644 index 0000000000..00cacccb9f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_lphb.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare low power heart beat offload feature API's + */ + +#ifndef _WLAN_PMO_LPHB_H_ +#define _WLAN_PMO_LPHB_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_lphb_public_struct.h" + +/** + * pmo_core_lphb_config_req() - API to configure lphb request + * @psoc: objmgr psoc handle + * @lphb_req: low power heart beat configuration request + * @lphb_cb_ctx: low power heart beat context + * @callback: osif callback which need to be called when host get lphb event + * + * API to configure lphb request + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_lphb_config_req(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx, + pmo_lphb_callback callback); + +/** + * pmo_core_apply_lphb(): apply cached LPHB settings + * @psoc: objmgr psoc handle + * + * LPHB cache, if any item was enabled, should be + * applied. + */ +void pmo_core_apply_lphb(struct wlan_objmgr_psoc *psoc); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_LPHB_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_main.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_main.h new file mode 100644 index 0000000000..c72009ae55 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_main.h @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare various api which shall be used by + * pmo user configuration and target interface + */ + +#ifndef _WLAN_PMO_MAIN_H_ +#define _WLAN_PMO_MAIN_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_priv.h" +#include "wlan_pmo_objmgr.h" + +#define pmo_fatal(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_PMO, params) +#define pmo_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_PMO, params) +#define pmo_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_PMO, params) +#define pmo_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_PMO, params) +#define pmo_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_PMO, params) + +#define pmo_nofl_fatal(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_PMO, params) +#define pmo_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_PMO, params) +#define pmo_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_PMO, params) +#define pmo_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_PMO, params) +#define pmo_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_PMO, params) + +#define pmo_enter() QDF_TRACE_ENTER(QDF_MODULE_ID_PMO, "enter") +#define pmo_exit() QDF_TRACE_EXIT(QDF_MODULE_ID_PMO, "exit") + +#define PMO_VDEV_IN_STA_MODE(mode) \ + ((mode) == QDF_STA_MODE || (mode) == QDF_P2P_CLIENT_MODE ? 1 : 0) + +static inline enum QDF_OPMODE pmo_get_vdev_opmode(struct wlan_objmgr_vdev *vdev) +{ + return wlan_vdev_mlme_get_opmode(vdev); +} + +/** + * pmo_allocate_ctx() - Api to allocate pmo ctx + * + * Helper function to allocate pmo ctx + * + * Return: Success or failure. + */ +QDF_STATUS pmo_allocate_ctx(void); + +/** + * pmo_free_ctx() - to free pmo context + * + * Helper function to free pmo context + * + * Return: None. + */ +void pmo_free_ctx(void); + +/** + * pmo_get_context() - to get pmo context + * + * Helper function to get pmo context + * + * Return: pmo context. + */ +struct wlan_pmo_ctx *pmo_get_context(void); + +/** + * pmo_psoc_open() - pmo psoc object open + * @psoc: objmgr vdev + *. + * This function used to open pmo psoc object + * + * Return: Success or failure + */ +QDF_STATUS pmo_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_psoc_close() - pmo psoc object close + * @psoc: objmgr vdev + *. + * This function used to close pmo psoc object + * + * Return: Success or failure + */ +QDF_STATUS pmo_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_get_vdev_bss_peer_mac_addr() - API to get bss peer mac address + * @vdev: objmgr vdev + * @bss_peer_mac_address: bss peer mac address + * + * Helper function to get bss peer mac address + * + * Return: if success pmo vdev ctx else NULL + */ +QDF_STATUS pmo_get_vdev_bss_peer_mac_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bss_peer_mac_address); + +/** + * pmo_is_vdev_in_beaconning_mode() - check if vdev is in a beaconning mode + * @vdev_opmode: vdev opmode + * + * Helper function to know whether given vdev + * is in a beaconning mode or not. + * + * Return: True if vdev needs to beacon. + */ +bool pmo_is_vdev_in_beaconning_mode(enum QDF_OPMODE vdev_opmode); + +/** + * pmo_core_is_ap_mode_supports_arp_ns() - To check ap mode supports arp/ns + * @psoc: objmgr psoc handle + * @vdev_opmode: vdev opmode + * + * API to check if ap mode supports arp/ns offload + * + * Return: True if ap mode supports arp/ns offload + */ + +bool pmo_core_is_ap_mode_supports_arp_ns(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode); + +/** + * pmo_core_is_vdev_supports_offload() - Check offload is supported on vdev + * @vdev: objmgr vdev + * + * Return: true in case success else false + */ +bool pmo_core_is_vdev_supports_offload(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_get_psoc_config(): API to get the psoc user configurations of pmo + * @psoc: objmgr psoc handle + * @psoc_cfg: fill the current psoc user configurations. + * + * Return pmo psoc configurations + */ +QDF_STATUS pmo_core_get_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg); + +/** + * pmo_core_update_psoc_config(): API to update the psoc user configurations + * @psoc: objmgr psoc handle + * @psoc_cfg: pmo psoc configurations + * + * This api shall be used for soc config initialization as well update. + * In case of update caller must first call pmo_get_psoc_cfg to get + * current config and then apply changes on top of current config. + * + * Return QDF_STATUS -in case of success else return error + */ +QDF_STATUS pmo_core_update_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg); + +/** + * pmo_psoc_set_caps() - overwrite configured device capability flags + * @psoc: the psoc for which the capabilities apply + * @caps: the cabability information to configure + * + * Return: None + */ +void pmo_psoc_set_caps(struct wlan_objmgr_psoc *psoc, + struct pmo_device_caps *caps); + +/** + * pmo_core_get_vdev_op_mode(): API to get the vdev operation mode + * @vdev: objmgr vdev handle + * + * API to get the vdev operation mode + * + * Return QDF_MAX_NO_OF_MODE - in case of error else return vdev opmode + */ +static inline enum QDF_OPMODE pmo_core_get_vdev_op_mode( + struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE op_mode = QDF_MAX_NO_OF_MODE; + + if (!vdev) + return op_mode; + op_mode = wlan_vdev_mlme_get_opmode(vdev); + + return op_mode; +} + +/** + * pmo_core_psoc_update_dp_handle() - update psoc data path handle + * @psoc: objmgr psoc handle + * @dp_hdl: psoc data path handle + * + * Return: None + */ +static inline void +pmo_core_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc, void *dp_hdl) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->dp_hdl = dp_hdl; + } +} + +/** + * pmo_core_psoc_get_dp_handle() - Get psoc data path handle + * @psoc: objmgr psoc handle + * + * Return: psoc data path handle + */ +static inline void *pmo_core_psoc_get_dp_handle(struct wlan_objmgr_psoc *psoc) +{ + void *dp_hdl = NULL; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + dp_hdl = psoc_ctx->dp_hdl; + } + + return dp_hdl; +} + +/** + * pmo_core_vdev_get_dp_handle() - Get vdev data path handle + * @psoc_ctx: pmo psoc private context + * @vdev_id: vdev id config to get data path handle + * + * Return: Vdev data path handle + */ +static inline +struct cdp_vdev *pmo_core_vdev_get_dp_handle(struct pmo_psoc_priv_obj *psoc_ctx, + uint8_t vdev_id) +{ + struct cdp_vdev *dp_hdl = NULL; + pmo_get_vdev_dp_handle handler; + + qdf_spin_lock_bh(&psoc_ctx->lock); + handler = psoc_ctx->get_vdev_dp_handle; + qdf_spin_unlock_bh(&psoc_ctx->lock); + + if (handler) + dp_hdl = handler(vdev_id); + + return dp_hdl; +} + +/** + * pmo_core_psoc_update_htc_handle() - update psoc htc layer handle + * @psoc: objmgr psoc handle + * @htc_hdl: psoc htc layer handle + * + * Return: None + */ +static inline void +pmo_core_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc, void *htc_hdl) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->htc_hdl = htc_hdl; + } +} + +/** + * pmo_core_psoc_get_htc_handle() - Get psoc htc layer handle + * @psoc: objmgr psoc handle + * + * Return: psoc htc layer handle + */ +static inline void *pmo_core_psoc_get_htc_handle(struct wlan_objmgr_psoc *psoc) +{ + void *htc_hdl = NULL; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + htc_hdl = psoc_ctx->htc_hdl; + } + + return htc_hdl; +} + +/** + * pmo_core_psoc_set_hif_handle() - update psoc hif layer handle + * @psoc: objmgr psoc handle + * @hif_hdl: hif context handle + * + * Return: None + */ +void pmo_core_psoc_set_hif_handle(struct wlan_objmgr_psoc *psoc, + void *hif_hdl); + +/** + * pmo_core_psoc_get_hif_handle() - Get psoc hif layer handle + * @psoc: objmgr psoc handle + * + * Return: psoc hif layer handle + */ +void *pmo_core_psoc_get_hif_handle(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_psoc_set_txrx_pdev_id() - update psoc pdev txrx layer handle + * @psoc: objmgr psoc handle + * @txrx_pdev_id: txrx pdev identifier + * + * Return: None + */ +void pmo_core_psoc_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t txrx_pdev_id); + +/** + * pmo_core_psoc_get_txrx_handle() - Get psoc pdev txrx handle + * @psoc: objmgr psoc handle + * + * Return: txrx pdev identifier + */ +uint8_t pmo_core_psoc_get_txrx_handle(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_intersect_arp_ns_offload() - intersect config and firmware capability for + * the ARP/NS Offload feature + * @psoc_ctx: A PMO psoc context + * + * Note: The caller is expected to grab the PMO context lock. + * + * Return: True if firmware supports and configuration has enabled the feature + */ +static inline bool +pmo_intersect_arp_ns_offload(struct pmo_psoc_priv_obj *psoc_ctx) +{ + struct pmo_psoc_cfg *cfg = &psoc_ctx->psoc_cfg; + bool arp_ns_enabled = + cfg->ns_offload_enable_static || + cfg->ns_offload_enable_dynamic || + cfg->arp_offload_enable; + + return arp_ns_enabled && psoc_ctx->caps.arp_ns_offload; +} + +/** + * pmo_intersect_apf() - intersect config and firmware capability for + * the APF feature + * @psoc_ctx: A PMO psoc context + * + * Note: The caller is expected to grab the PMO context lock. + * + * Return: True if firmware supports and configuration has enabled the feature + */ +static inline bool pmo_intersect_apf(struct pmo_psoc_priv_obj *psoc_ctx) +{ + return psoc_ctx->psoc_cfg.apf_enable && psoc_ctx->caps.apf; +} + +/** + * pmo_intersect_packet_filter() - intersect config and firmware capability for + * the APF feature + * @psoc_ctx: A PMO psoc context + * + * Note: The caller is expected to grab the PMO context lock. + * + * Return: True if firmware supports and configuration has enabled the feature + */ +static inline bool +pmo_intersect_packet_filter(struct pmo_psoc_priv_obj *psoc_ctx) +{ + return psoc_ctx->psoc_cfg.packet_filter_enabled && + psoc_ctx->caps.packet_filter; +} + +/* + * pmo_host_action_on_page_fault() - Returns action host will take on page fault + * @psoc: PSOC object manager pointer. + * + * Returns: Host action on page fault event + */ +enum pmo_page_fault_action +pmo_host_action_on_page_fault(struct wlan_objmgr_psoc *psoc); + +#define pmo_is_host_pagefault_action(_psoc, _action) \ + (pmo_host_action_on_page_fault(_psoc) == (_action)) + +static inline bool pmo_no_op_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + return pmo_is_host_pagefault_action(psoc, PMO_PF_HOST_ACTION_NO_OP); +} + +static inline bool pmo_enable_ssr_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + return pmo_is_host_pagefault_action(psoc, PMO_PF_HOST_ACTION_TRIGGER_SSR); +} + +/* + * pmo_get_min_pagefault_wakeups_for_action() - get pagefault wakeups for host + * to initiate action + * @psoc: objmgr psoc + * + * Return: Min wakeups interval for host action on pagefault + */ +uint8_t +pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc *psoc); + +/* + * pmo_get_interval_for_pagefault_wakeup_counts: get ssr interval for pagefault + * @psoc: objmgr psoc + * + * Return: SSR interval for pagefault + */ +uint32_t +pmo_get_interval_for_pagefault_wakeup_counts(struct wlan_objmgr_psoc *psoc); + +/* + * pmo_get_ssr_frequency_on_pagefault: get ssr frequency on pagefault + * @psoc: objmgr psoc + * + * Return: SSR frequency on pagefault + */ +uint32_t pmo_get_ssr_frequency_on_pagefault(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_get_vdev_bridge_addr() - API to get Bridge mac address + * @vdev: vdev object + * @bridgeaddr: Bridge mac address + * + * Helper function to get Bridge mac address + * + * Return: if success pmo vdev ctx else NULL + */ +QDF_STATUS pmo_get_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr); + +/** + * pmo_set_vdev_bridge_addr() - API to set Bridge mac address + * @vdev: vdev object + * @bridgeaddr: Bridge mac address + * + * API to set the Bridge MAC address + * + * Return: if success pmo vdev ctx else NULL + */ +QDF_STATUS pmo_set_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +/** + * pmo_core_get_listen_interval() - function to get configured + * listen interval + * @vdev: vdev objmgr vdev + * @listen_interval: Pointer variable to return listen interval + * + * This function allows get configured listen interval + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval); + +#endif /* end of _WLAN_PMO_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h new file mode 100644 index 0000000000..5c03593ac0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_mc_addr_filtering.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare mc addr filtering offload feature API's + */ + +#ifndef _WLAN_PMO_MC_ADDR_FILTERING_H_ +#define _WLAN_PMO_MC_ADDR_FILTERING_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" + +/** + * pmo_core_set_mc_filter_req() -send mc filter set request + * @vdev: objmgr vdev + * @mc_list: a list of mc addresses to set in fwr + * + * Return: QDF_STATUS_SUCCESS in success else error codes + */ +QDF_STATUS pmo_core_set_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + +/** + * pmo_core_clear_mc_filter_req() -send mc filter clear request + * @vdev: objmgr vdev + * @mc_list: a list of mc addresses to clear in fwr + * + * Return: QDF_STATUS_SUCCESS in success else error codes + */ +QDF_STATUS pmo_core_clear_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + +/** + * pmo_core_cache_mc_addr_list(): API to cache mc addr list in pmo vdev priv obj + * @mc_list_config: Multicast list configuration + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config); + +/** + * pmo_core_flush_mc_addr_list(): API to flush mc addr list in pmo vdev priv obj + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_flush_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * pmo_core_enhanced_mc_filter_enable() - enable enhanced multicast filtering + * @vdev: the vdev to enable enhanced multicast filtering for + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_enhanced_mc_filter_disable() - disable enhanced multicast filtering + * @vdev: the vdev to disable enhanced multicast filtering for + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_enable_mc_addr_filtering_in_fwr(): Enable cached mc add list in fwr + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @trigger: pmo trigger reason + * + * API to enable cached mc add list in fwr + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_enable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger); + +/** + * pmo_core_disable_mc_addr_filtering_in_fwr(): Disable cached mc addr list + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @trigger: pmo trigger reason + * + * API to disable cached mc add list in fwr + * + * Return QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS pmo_core_disable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger); + +/** + * pmo_core_set_mc_addr_list_count() - set mc address count + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @count: mc address count + * + * Return: void + */ +void pmo_core_set_mc_addr_list_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t count); + +/** + * pmo_core_get_mc_addr_list_count() -get current mc address count + * @psoc: objmgr psoc + * @vdev_id: vdev id + * + * Return: current mc address count + */ +int pmo_core_get_mc_addr_list_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * pmo_core_max_mc_addr_supported() -get max supported mc addresses + * @psoc: objmgr psoc + * + * Return: max supported mc addresses + */ +uint8_t pmo_core_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_get_mc_addr_list() - Get mc addr list configured + * @psoc: objmgr psoc + * @vdev_id: vdev identifier + * @mc_list_req: output pointer to hold mc addr list params + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS +pmo_core_get_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct pmo_mc_addr_list *mc_list_req); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_MC_ADDR_FILTERING_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_ns.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_ns.h new file mode 100644 index 0000000000..c53d4c67bf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_ns.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare ns offload feature API's + */ + +#ifndef _WLAN_PMO_NS_H_ +#define _WLAN_PMO_NS_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" + +/** + * pmo_core_cache_ns_offload_req() - API to cache ns req in pmo vdev priv ctx + * @ns_req: ns offload request + * + * API to cache ns offload in pmo vdev priv ctx + * + * Return:QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_cache_ns_offload_req(struct pmo_ns_req *ns_req); + +/** + * pmo_core_ns_check_offload() - API to check if offload cache/send is required + * @psoc: objmgr psoc handle + * @trigger: trigger reason enable ns offload + * @vdev_id: vdev id + * + * Return:QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_ns_check_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id); + +/** + * pmo_core_flush_ns_offload_req() - API to flush ns req from pmo vdev priv ctx + * @vdev: vdev objmgr handle + * + * API to flush ns offload from pmo vdev priv ctx + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_enable_ns_offload_in_fwr() - API to enable ns offload in fwr + * @vdev: objmgr vdev + * @trigger: trigger reason enable ns offload + * + * API to enable ns offload in fwr from vdev priv ctx + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_core_disable_ns_offload_in_fwr() - API to disable ns offload in fwr + * @vdev: objmgr vdev + * @trigger: trigger reason disable ns offload + * + * API to disable arp offload in fwr + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * pmo_core_get_ns_offload_params() - API to get ns offload params + * @vdev: objmgr vdev + * @params: output pointer to hold offload params + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS +pmo_core_get_ns_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ns_offload_params *params); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_NS_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_objmgr.h new file mode 100644 index 0000000000..4c4f54adb7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_objmgr.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains various object manager related wrappers and helpers + */ + +#ifndef _WLAN_PMO_OBJMGR_H +#define _WLAN_PMO_OBJMGR_H + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_peer_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_utility.h" + + +/* Get/Put Ref */ + +#define pmo_peer_get_ref(peer) wlan_objmgr_peer_try_get_ref(peer, WLAN_PMO_ID) +#define pmo_peer_put_ref(peer) wlan_objmgr_peer_release_ref(peer, WLAN_PMO_ID) + +#define pmo_vdev_get_ref(vdev) wlan_objmgr_vdev_try_get_ref(vdev, WLAN_PMO_ID) + +#define pmo_pdev_get_ref(pdev) wlan_objmgr_pdev_try_get_ref(pdev, WLAN_PMO_ID) +#define pmo_pdev_put_ref(pdev) wlan_objmgr_pdev_release_ref(pdev, WLAN_PMO_ID) + +#define pmo_psoc_get_ref(psoc) wlan_objmgr_psoc_try_get_ref(psoc, WLAN_PMO_ID) +#define pmo_psoc_put_ref(psoc) wlan_objmgr_psoc_release_ref(psoc, WLAN_PMO_ID) + +/* Private Data */ + +#define pmo_vdev_get_priv_nolock(vdev) \ + wlan_objmgr_vdev_get_comp_private_obj(vdev, WLAN_UMAC_COMP_PMO) +#define pmo_psoc_get_priv_nolock(psoc) \ + wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_PMO) + +/* Ids */ + +static inline uint8_t +pmo_vdev_get_id(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + QDF_BUG(vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS); + + return vdev_id; +} + +/* Tree Navigation */ + +/* + * !PLEASE READ! + * + * The following are objmgr naviation helpers for traversing objmgr object + * trees. + * + * Objmgr ensures parents of an objmgr object cannot be freed while a valid + * reference to one of its children is held. Based on this fact, all of these + * navigation helpers make the following assumptions to ensure safe usage: + * + * 1) The caller must hold a valid reference to the input objmgr object! + * E.g. Use pmo_[peer|vdev|pdev|psoc]_get_ref() on the input objmgr object + * before using these APIs + * 2) Given assumption #1, the caller does not need to hold a reference to the + * parents of the input objmgr object + * 3) Given assumption #1, parents of the input objmgr object cannot be null + * 4) Given assumption #1, private contexts of any parent of the input objmgr + * object cannot be null + * + * These characteristics remove the need for most sanity checks when dealing + * with objmgr objects. However, please note that if you ever walk the tree + * from parent to child, references must be acquired all the way down! + * + * Example #1: + * + * psoc = pmo_vdev_get_psoc(vdev); + * if (!psoc) + * // this is dead code + * + * Example #2: + * + * psoc_priv = pmo_psoc_get_priv(psoc); + * if (!psoci_priv) + * // this is dead code + * + * Example #3: + * + * status = pmo_vdev_get_ref(vdev); + * + * ... + * + * psoc = pmo_vdev_get_psoc(vdev); + * + * // the next line is redundant, don't do it! + * status = pmo_psoc_get_ref(psoc); + */ + +/* Tree Navigation: psoc */ + +static inline struct pmo_psoc_priv_obj * +pmo_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_priv; + + psoc_priv = pmo_psoc_get_priv_nolock(psoc); + QDF_BUG(psoc_priv); + + return psoc_priv; +} + +static inline bool __pmo_spinlock_bh_safe(struct pmo_psoc_priv_obj *psoc_ctx) +{ + if (!psoc_ctx) + return false; + + qdf_spin_lock_bh(&psoc_ctx->lock); + + return true; +} + +#define pmo_psoc_with_ctx(psoc, cursor) \ + for (cursor = pmo_psoc_get_priv(psoc); \ + __pmo_spinlock_bh_safe(cursor); \ + qdf_spin_unlock_bh(&cursor->lock), cursor = NULL) + +/* Tree Navigation: pdev */ + +static inline struct wlan_objmgr_psoc * +pmo_pdev_get_psoc(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + QDF_BUG(psoc); + + return psoc; +} + +static inline struct pmo_psoc_priv_obj * +pmo_pdev_get_psoc_priv(struct wlan_objmgr_pdev *pdev) +{ + return pmo_psoc_get_priv(pmo_pdev_get_psoc(pdev)); +} + +/* Tree Navigation: vdev */ + +static inline struct pmo_vdev_priv_obj * +pmo_vdev_get_priv(struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_priv; + + vdev_priv = pmo_vdev_get_priv_nolock(vdev); + QDF_BUG(vdev_priv); + + return vdev_priv; +} + +static inline struct wlan_objmgr_pdev * +pmo_vdev_get_pdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + QDF_BUG(pdev); + + return pdev; +} + +static inline struct wlan_objmgr_psoc * +pmo_vdev_get_psoc(struct wlan_objmgr_vdev *vdev) +{ + return pmo_pdev_get_psoc(pmo_vdev_get_pdev(vdev)); +} + +static inline struct pmo_psoc_priv_obj * +pmo_vdev_get_psoc_priv(struct wlan_objmgr_vdev *vdev) +{ + return pmo_psoc_get_priv(pmo_pdev_get_psoc(pmo_vdev_get_pdev(vdev))); +} + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* _WLAN_PMO_OBJMGR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_pkt_filter.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_pkt_filter.h new file mode 100644 index 0000000000..29684b0d93 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_pkt_filter.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare packet filter feature API's + */ + +#ifndef _WLAN_PMO_PKT_FILTER_H_ +#define _WLAN_PMO_PKT_FILTER_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_pkt_filter_public_struct.h" + +struct wlan_objmgr_psoc; + +/** + * pmo_get_num_packet_filters() - get the number of packet filters + * @psoc: the psoc to query + * + * Return: number of packet filters + */ +uint32_t pmo_get_num_packet_filters(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_set_pkt_filter() - Set packet filter + * @psoc: objmgr psoc + * @pmo_set_pkt_fltr_req: packet filter set param + * @vdev_id: vdev id + * + * API to set packet filter + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_set_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id); + +/** + * pmo_core_clear_pkt_filter() - Clear packet filter + * @psoc: objmgr psoc + * @pmo_clr_pkt_fltr_param: packet filter clear param + * @vdev_id: vdev id + * + * API to clear packet filter + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_core_clear_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id); + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* _WLAN_PMO_PKT_FILTER_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_priv.h new file mode 100644 index 0000000000..4d58a0f0c6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_priv.h @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: Declare various struct, macros which are used for private to PMO. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_PRIV_STRUCT_H_ +#define _WLAN_PMO_PRIV_STRUCT_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_arp_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_gtk_public_struct.h" +#include "wlan_pmo_wow_public_struct.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" + +#define PMO_PS_DATA_INACTIVITY_TIMEOUT (200) +#define PMO_PS_DATA_SPEC_WAKE (0) + +/** + * struct pmo_psoc_priv_obj - psoc related data require for pmo + * @psoc_cfg: place holder for psoc configuration + * @pmo_tx_ops: transmit ops for PMO + * @wow: wow configuration + * @caps: PMO specific device capability bits + * @dp_hdl: psoc data path handle + * @htc_hdl: htc layer handle + * @hif_hdl: hif layer handle + * @txrx_pdev_id: txrx pdev identifier + * @pause_bitmap_notifier: registered callback to update pause bitmap value + * @get_pause_bitmap: registered callback to get pause bitmap value + * @get_vdev_dp_handle: registered callback to get vdev's DP handle + * @is_device_in_low_pwr_mode: registered callback to determine if the + * device is in low power mode + * @get_dtim_period: register callback to get dtim period from mlme + * @get_beacon_interval: register callback to get beacon interval from mlme + * @lock: spin lock for pmo psoc + */ +struct pmo_psoc_priv_obj { + struct pmo_psoc_cfg psoc_cfg; + struct wlan_pmo_tx_ops pmo_tx_ops; + struct pmo_wow wow; + struct pmo_device_caps caps; + void *dp_hdl; + void *htc_hdl; + void *hif_hdl; + uint8_t txrx_pdev_id; + pmo_notify_pause_bitmap pause_bitmap_notifier; + pmo_get_pause_bitmap get_pause_bitmap; + pmo_get_vdev_dp_handle get_vdev_dp_handle; + pmo_is_device_in_low_pwr_mode is_device_in_low_pwr_mode; + pmo_get_dtim_period get_dtim_period; + pmo_get_beacon_interval get_beacon_interval; + qdf_spinlock_t lock; +}; + +/** + * struct wlan_pmo_ctx -offload mgr context + * @psoc_context: psoc context + * @pmo_suspend_handler: suspend handler table for all components + * @pmo_suspend_handler_arg: suspend handler argument sfor all components + * @pmo_resume_handler: resume handler table for all components + * @pmo_resume_handler_arg: resume handler argument for all components + * @lock: lock for global pmo ctx + */ +struct wlan_pmo_ctx { + pmo_psoc_suspend_handler + pmo_suspend_handler[WLAN_UMAC_MAX_COMPONENTS]; + void *pmo_suspend_handler_arg[WLAN_UMAC_MAX_COMPONENTS]; + pmo_psoc_resume_handler + pmo_resume_handler[WLAN_UMAC_MAX_COMPONENTS]; + void *pmo_resume_handler_arg[WLAN_UMAC_MAX_COMPONENTS]; + qdf_spinlock_t lock; +}; + +/** + * struct pmo_vdev_priv_obj -vdev specific user configuration required for pmo + * @pmo_psoc_ctx: pmo psoc ctx + * @vdev_arp_req: place holder for arp request for vdev + * @vdev_ns_req: place holder for ns request for vdev + * @vdev_mc_list_req: place holder for mc addr list for vdev + * @addr_filter_pattern: addr filter pattern for vdev + * @vdev_gtk_req: place holder for gtk request for vdev + * @vdev_gtk_rsp_req: place holder for gtk response request for vdev + * @ps_params: OPM params + * @gtk_err_enable: gtk error is enabled or not + * @vdev_bpf_req: place holder for apf/bpf for vdev + * @vdev_pkt_filter: place holder for vdev packet filter + * @magic_ptrn_enable: true when magic pattern is enabled else false + * @ptrn_match_enable: true when pattern match is enabled else false + * @num_wow_default_patterns: number of wow default patterns for vdev + * @num_wow_user_patterns: number of user wow patterns for vdev + * @extscan_in_progress: true when extscan in progress else false + * @p2plo_in_progress: true when p2plo_in_progress in progress else false + * @dtim_period: dtim period for vdev + * @beacon_interval: vdev beacon interval + * @dyn_modulated_dtim: dynamically configured modulated dtim value + * @dyn_modulated_dtim_enabled: if dynamically modulated dtim is set or not + * @is_dyn_modulated_dtim_activated: if dynamically modulated dtim is sent to fw + * @dyn_listen_interval: dynamically user configured listen interval + * @restore_dtim_setting: DTIM settings restore flag + * @pmo_vdev_lock: spin lock for pmo vdev priv ctx + * @dyn_arp_ns_offload_disable: true when arp/ns offload is disable + * @dyn_arp_ns_offload_rt_lock: wake lock which prevent runtime pm happen if + * arp/ns offload is disable + * @bridgeaddr: Bridge MAC address + */ +struct pmo_vdev_priv_obj { + struct pmo_psoc_priv_obj *pmo_psoc_ctx; + struct pmo_arp_offload_params vdev_arp_req; + struct pmo_ns_offload_params vdev_ns_req; + struct pmo_mc_addr_list vdev_mc_list_req; + uint8_t addr_filter_pattern; + struct pmo_gtk_req vdev_gtk_req; + struct pmo_gtk_rsp_req vdev_gtk_rsp_req; + struct pmo_ps_params ps_params; + qdf_atomic_t gtk_err_enable; + bool magic_ptrn_enable; + bool ptrn_match_enable; + uint8_t num_wow_default_patterns; + uint8_t num_wow_user_patterns; + bool extscan_in_progress; + bool p2plo_in_progress; + uint8_t dtim_period; + uint8_t beacon_interval; + uint32_t dyn_modulated_dtim; + bool dyn_modulated_dtim_enabled; + bool is_dyn_modulated_dtim_activated; + uint32_t dyn_listen_interval; + bool restore_dtim_setting; + qdf_spinlock_t pmo_vdev_lock; +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD + bool dyn_arp_ns_offload_disable; + qdf_runtime_lock_t dyn_arp_ns_offload_rt_lock; +#endif + uint8_t bridgeaddr[QDF_MAC_ADDR_SIZE]; +}; + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ +#endif /* end of _WLAN_PMO_PRIV_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_static_config.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_static_config.h new file mode 100644 index 0000000000..5c76ccf1ef --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_static_config.h @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare static configuration on vdev attach + */ + +#ifndef _WLAN_PMO_STATIC_CONFIG_H_ +#define _WLAN_PMO_STATIC_CONFIG_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_wow.h" + +/** + * pmo_register_wow_wakeup_events() - register vdev specific wake events with fw + * @vdev: objmgr vdev + * + * WoW wake up event rule is following: + * 1) STA mode and P2P CLI mode wake up events are same + * 2) SAP mode and P2P GO mode wake up events are same + * 3) IBSS mode wake events are same as STA mode plus WOW_BEACON_EVENT + * + * Return: none + */ +void pmo_register_wow_wakeup_events(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_register_wow_default_patterns() - register default wow patterns with fw + * @vdev: objmgr vdev + * + * WoW default wake up pattern rule is: + * - For STA & P2P CLI mode register for same STA specific wow patterns + * - For SAP/P2P GO & IBSS mode register for same SAP specific wow patterns + * + * Return: none + */ +void pmo_register_wow_default_patterns(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_register_action_frame_patterns() - register action frame map to fw + * @vdev: objmgr vdev + * @suspend_type: suspend mode runtime pm suspend or normal suspend. + * + * This is called to push action frames wow patterns from local + * cache to firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pmo_register_action_frame_patterns(struct wlan_objmgr_vdev *vdev, + enum qdf_suspend_type suspend_type); + +/** + * pmo_clear_action_frame_patterns() - clear the action frame + * pattern bitmap in firmware + * @vdev: objmgr vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_clear_action_frame_patterns(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_set_wow_event_bitmap() - Assign bitmask with wow event + * @event: wow event + * @wow_bitmap_size: wow bitmask size + * @bitmask: wow bitmask field + * + * Return: none + */ +void pmo_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event, + uint32_t wow_bitmap_size, + uint32_t *bitmask); + +/** + * pmo_set_sta_wow_bitmask() - set predefined STA wow wakeup events + * @bitmask: bitmask field + * @wow_bitmask_size: bitmask field size + * + * Return: none + */ +void pmo_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size); + +/** + * pmo_set_sap_wow_bitmask() - set predefined SAP wow wakeup events + * @bitmask: bitmask field + * @wow_bitmask_size: bitmask field size + * + * Return: none + */ +void pmo_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size); + +/** + * pmo_core_vdev_set_ps_params() - set vdev ps_params + * @vdev: objmgr vdev handle + * @ps_params: vdev OPM parameters + * + * Return: None + */ +static inline +void pmo_core_vdev_set_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->ps_params = *ps_params; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} + +/** + * pmo_core_vdev_get_ps_params() - get vdev ps_params + * @vdev: objmgr vdev handle + * @ps_params: pointer to get vdev ps_params + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS pmo_core_vdev_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (!vdev_ctx) + return QDF_STATUS_E_NULL_VALUE; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + *ps_params = vdev_ctx->ps_params; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + return QDF_STATUS_SUCCESS; +} + +/** + * pmo_vdev_set_ps_opm_mode() - set OPM mode + * @vdev: objmgr vdev handle + * @opm_mode: OPM mode + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS pmo_vdev_set_ps_opm_mode(struct wlan_objmgr_vdev *vdev, + enum powersave_mode opm_mode) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (!vdev_ctx) { + pmo_err("vdev ctx is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->ps_params.opm_mode = opm_mode; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * pmo_vdev_get_ps_opm_mode() - get OPM mode + * @vdev: objmgr vdev handle + * @opm_mode: OPM mode + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS pmo_vdev_get_ps_opm_mode(struct wlan_objmgr_vdev *vdev, + enum powersave_mode *opm_mode) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (!vdev_ctx) + return QDF_STATUS_E_NULL_VALUE; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + *opm_mode = vdev_ctx->ps_params.opm_mode; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_NAN +/** + * pmo_set_ndp_wow_bitmask() - set predefined NDP wow wakeup events + * @bitmask: bitmask field + * @wow_bitmask_size: bitmask field size + * + * Return: none + */ +void pmo_set_ndp_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size); +#else +static inline +void pmo_set_ndp_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmask_size) +{ +} +#endif + +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_STATIC_CONFIG_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_suspend_resume.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_suspend_resume.h new file mode 100644 index 0000000000..455344af2b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_suspend_resume.h @@ -0,0 +1,628 @@ +/* + * Copyright (c) 2017-2018, 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare suspend / resume related API's + */ + +#ifndef _WLAN_PMO_SUSPEND_RESUME_H_ +#define _WLAN_PMO_SUSPEND_RESUME_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_wow.h" + +/** + * pmo_core_configure_dynamic_wake_events(): configure dynamic wake events + * @psoc: objmgr psoc handle + * + * Some wake events need to be enabled dynamically. Control those here. + * + * Return: none + */ +void pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_get_wow_bus_suspend(): API to get wow bus is suspended or not + * @psoc: objmgr psoc handle + * + * Return: True if bus suspende else false + */ +static inline bool pmo_core_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + bool value = false; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + value = psoc_ctx->wow.is_wow_bus_suspended; + } + + return value; +} + +/** + * pmo_core_psoc_user_space_suspend_req() - Core handle user space suspend req + * @psoc: objmgr psoc handle + * @type: type of suspend + * + * Pmo core Handles user space suspend request for psoc + * + * Return: QDF status + */ +QDF_STATUS pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * pmo_core_psoc_user_space_resume_req() - Core handle user space resume req + * @psoc: objmgr psoc handle + * @type: type of suspend from resume required + * + * Pmo core Handles user space resume request for psoc + * + * Return: QDF status + */ +QDF_STATUS pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * pmo_core_psoc_bus_suspend_req(): handles bus suspend for psoc + * @psoc: objmgr psoc + * @type: is this suspend part of runtime suspend or system suspend? + * @wow_params: collection of wow enable override parameters + * + * Bails if a scan is in progress. + * Calls the appropriate handlers based on configuration and event. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type, + struct pmo_wow_enable_params *wow_params); + +#ifdef FEATURE_RUNTIME_PM +/** + * pmo_core_psoc_bus_runtime_suspend(): handles bus runtime suspend + * @psoc: objmgr psoc + * @pld_cb: callback to do link auto suspend + * + * Suspend the wlan bus without apps suspend. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb); + +/** + * pmo_core_psoc_bus_runtime_resume(): handles bus runtime resume + * @psoc: objmgr psoc + * @pld_cb: callback to do link auto resume + * + * Resume the wlan bus from runtime suspend. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_resume_cb pld_cb); +#endif + +/** + * pmo_core_psoc_suspend_target() -Send suspend target command + * @psoc: objmgr psoc handle + * @disable_target_intr: disable target interrupt + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, + int disable_target_intr); + +/** + * pmo_core_psoc_bus_resume_req() - handle bus resume request for psoc + * @psoc: objmgr psoc handle + * @type: is this suspend part of runtime suspend or system suspend? + * + * Return:QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * pmo_core_vdev_set_restore_dtim() - vdev dtim restore setting value + * @vdev: objmgr vdev handle + * @value: dtim restore policy value + * + * Return: None + */ +static inline +void pmo_core_vdev_set_restore_dtim(struct wlan_objmgr_vdev *vdev, + bool value) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->restore_dtim_setting = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} + +/** + * pmo_core_vdev_get_restore_dtim() - Get vdev restore dtim setting + * @vdev: objmgr vdev handle + * + * Return: dtim restore policy + */ +static inline +bool pmo_core_vdev_get_restore_dtim(struct wlan_objmgr_vdev *vdev) +{ + bool value; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + value = vdev_ctx->restore_dtim_setting; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return value; +} + +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD +/** + * pmo_core_dynamic_arp_ns_offload_enable() - Enable vdev arp/ns offload + * @vdev: objmgr vdev handle + * + * Return: QDF_STATUS_E_ALREADY if arp/ns offload already enable + */ +static inline QDF_STATUS +pmo_core_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev) +{ + bool value; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + value = vdev_ctx->dyn_arp_ns_offload_disable; + if (!value) + status = QDF_STATUS_E_ALREADY; + else + vdev_ctx->dyn_arp_ns_offload_disable = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return status; +} + +/** + * pmo_core_dynamic_arp_ns_offload_disable() - Disable vdev arp/ns offload + * @vdev: objmgr vdev handle + * + * Return: QDF_STATUS_E_ALREADY if arp/ns offload already disable + */ +static inline QDF_STATUS +pmo_core_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev) +{ + bool value; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + value = vdev_ctx->dyn_arp_ns_offload_disable; + if (value) + status = QDF_STATUS_E_ALREADY; + else + vdev_ctx->dyn_arp_ns_offload_disable = true; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return status; +} + +/** + * pmo_core_get_dynamic_arp_ns_offload_disable() - Get arp/ns offload state + * @vdev: objmgr vdev handle + * + * Return: true if vdev arp/ns offload is disable + */ +static inline bool +pmo_core_get_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev) +{ + bool value; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + value = vdev_ctx->dyn_arp_ns_offload_disable; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return value; +} + +/** + * pmo_core_dynamic_arp_ns_offload_runtime_prevent() - Prevent runtime suspend + * @vdev: objmgr vdev handle + * + * API to prevent runtime suspend happen when arp/ns offload is disable + * + * Return: None + */ +static inline void +pmo_core_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_runtime_pm_prevent_suspend(&vdev_ctx->dyn_arp_ns_offload_rt_lock); +} + +/** + * pmo_core_dynamic_arp_ns_offload_runtime_allow() - Allow runtime suspend + * @vdev: objmgr vdev handle + * + * API to allow runtime suspend happen when arp/ns offload is enable + * + * Return: None + */ +static inline void +pmo_core_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_runtime_pm_allow_suspend(&vdev_ctx->dyn_arp_ns_offload_rt_lock); +} +#endif + +/** + * pmo_core_psoc_update_power_save_mode() - update power save mode + * @psoc: objmgr psoc handle + * @value:describe vdev power save mode + * + * Return: None + */ +static inline void +pmo_core_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->psoc_cfg.power_save_mode = value; + } +} + +/** + * pmo_core_psoc_get_power_save_mode() - Get psoc power save mode + * @psoc: objmgr psoc handle + * + * Return: vdev psoc power save mode value + */ +static inline uint8_t +pmo_core_psoc_get_power_save_mode(struct wlan_objmgr_psoc *psoc) +{ + uint8_t value = 0; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + value = psoc_ctx->psoc_cfg.power_save_mode; + } + + return value; +} + +/** + * pmo_core_vdev_get_pause_bitmap() - Get vdev pause bitmap + * @psoc_ctx: psoc priv ctx + * @vdev_id: vdev id + * + * Return: vdev pause bitmap + */ +static inline +uint16_t pmo_core_vdev_get_pause_bitmap(struct pmo_psoc_priv_obj *psoc_ctx, + uint8_t vdev_id) +{ + uint16_t value = 0; + pmo_get_pause_bitmap handler; + + qdf_spin_lock_bh(&psoc_ctx->lock); + handler = psoc_ctx->get_pause_bitmap; + qdf_spin_unlock_bh(&psoc_ctx->lock); + + if (handler) + value = handler(vdev_id); + + return value; +} + +/** + * pmo_is_vdev_in_ap_mode() - check that vdev is in ap mode or not + * @vdev: objmgr vdev handle + * + * Helper function to know whether given vdev is in AP mode or not. + * + * Return: True/False + */ +static inline +bool pmo_is_vdev_in_ap_mode(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE mode; + + mode = pmo_get_vdev_opmode(vdev); + + return (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) == 1 ? 1 : 0; +} + +/** + * pmo_core_psoc_handle_initial_wake_up() - handle initial wake up + * @cb_ctx: callback context + * + * Return: None + */ +void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx); + +/** + * pmo_core_psoc_is_target_wake_up_received() - check for initial wake up + * @psoc: objmgr psoc handle + * + * Check if target initial wake up is received and fail PM suspend gracefully + * + * Return: -EAGAIN if initial wake up is received else 0 + */ +int pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_psoc_clear_target_wake_up() - clear initial wake up + * @psoc: objmgr psoc handle + * + * Clear target initial wake up reason + * + * Return: 0 for success and negative error code for failure + */ +int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_psoc_target_suspend_acknowledge() - update target susspend status + * @context: HTC_INIT_INFO->context + * @wow_nack: true when wow is rejected + * @reason_code : WoW status reason code + * + * Return: none + */ +void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack, + uint16_t reason_code); + +/** + * pmo_core_psoc_wakeup_host_event_received() - received host wake up event + * @psoc: objmgr psoc handle + * + * Return: None + */ +void pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_config_listen_interval() - function to dynamically configure + * listen interval + * @vdev: objmgr vdev + * @listen_interval: new listen interval passed by user + * + * This function allows user to configure listen interval dynamically + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval); + +/** + * pmo_core_config_modulated_dtim() - function to configure modulated dtim + * @vdev: objmgr vdev handle + * @mod_dtim: New modulated dtim value passed by user + * + * This function configures the modulated dtim in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim); + +/** + * pmo_core_txrx_suspend() - suspends TXRX + * @psoc: objmgr psoc handle + * + * This function disables the EXT grp irqs and drains the TX/RX pipes; + * this essentially suspends the TXRX activity + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_txrx_resume() - resumes TXRX + * @psoc: objmgr psoc handle + * + * This function enables the EXT grp irqs, which inturn resumes + * the TXRX activity + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_config_forced_dtim() - function to configure forced dtim + * @vdev: objmgr vdev handle + * @dynamic_dtim: dynamic dtim value passed by user + * + * This function configures the forced modulated dtim in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_core_config_forced_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t dynamic_dtim); + +#ifdef SYSTEM_PM_CHECK +/** + * pmo_core_system_resume() - function to handle system resume notification + * @psoc: objmgr psoc handle + * + * Return: None + */ +void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc); +#else +static inline void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc) +{} +#endif +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * pmo_core_enable_igmp_offload() - function to offload igmp + * @vdev: objmgr vdev handle + * @pmo_igmp_req: igmp req + * + * This function to offload igmp to fw + * + * Return: QDF_STATUS + */ +QDF_STATUS +pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req); +#else +static inline QDF_STATUS +pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * pmo_core_vdev_get_moddtim_user_enabled() - Get vdev if mod dtim set + * by user + * @vdev: objmgr vdev handle + * + * Return: mod dtim set by user or not + */ +static inline +bool pmo_core_vdev_get_moddtim_user_enabled(struct wlan_objmgr_vdev *vdev) +{ + bool value; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + value = vdev_ctx->dyn_modulated_dtim_enabled; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return value; +} + +/** + * pmo_core_vdev_set_moddtim_user_enabled() - vdev moddtim user enable setting + * @vdev: objmgr vdev handle + * @value: vdev moddtim user enable or not + * + * Return: None + */ +static inline +void pmo_core_vdev_set_moddtim_user_enabled(struct wlan_objmgr_vdev *vdev, + bool value) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->dyn_modulated_dtim_enabled = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} + +/** + * pmo_core_vdev_get_moddtim_user_active() - Get vdev if moddtim user is + * sent to fw + * @vdev: objmgr vdev handle + * + * Return: moddtim user is sent to fw or not + */ +static inline +bool pmo_core_vdev_get_moddtim_user_active(struct wlan_objmgr_vdev *vdev) +{ + bool retval; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + retval = vdev_ctx->is_dyn_modulated_dtim_activated; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return retval; +} + +/** + * pmo_core_vdev_set_moddtim_user_active() - vdev moddtim user active setting + * @vdev: objmgr vdev handle + * @value: vdev moddtim user active or not + * + * Return: None + */ +static inline +void pmo_core_vdev_set_moddtim_user_active(struct wlan_objmgr_vdev *vdev, + bool value) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->is_dyn_modulated_dtim_activated = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} + +/** + * pmo_core_vdev_get_moddtim_user() - Get vdev moddtim set by user + * @vdev: objmgr vdev handle + * + * Return: moddtim value set by user + */ +static inline +uint32_t pmo_core_vdev_get_moddtim_user(struct wlan_objmgr_vdev *vdev) +{ + uint32_t value; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + value = vdev_ctx->dyn_modulated_dtim; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return value; +} + +/** + * pmo_core_vdev_set_moddtim_user() - vdev moddtim user value setting + * @vdev: objmgr vdev handle + * @value: vdev moddtim value set by user + * + * Return: None + */ +static inline +void pmo_core_vdev_set_moddtim_user(struct wlan_objmgr_vdev *vdev, + uint32_t value) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->dyn_modulated_dtim = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_SUSPEND_RESUME_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_wow.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_wow.h new file mode 100644 index 0000000000..837646024f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/inc/wlan_pmo_wow.h @@ -0,0 +1,705 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare API's for wow pattern addition and deletion in fwr + */ + +#ifndef _WLAN_PMO_WOW_H_ +#define _WLAN_PMO_WOW_H_ + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +#include "wlan_pmo_main.h" +#include "wlan_pmo_wow_public_struct.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +/** + * DOC: wlan_pmo_wowl + * + * This module houses all the logic for WOW(wake on wireless) in + * PMO(Power Management and Offload). + * + * It provides the following APIs + * + * - Ability to enable/disable following WoWL modes + * 1) Magic packet (MP) mode + * 2) Pattern Byte Matching (PBM) mode + * - Ability to add/remove patterns for PBM + * + * A Magic Packet is a packet that contains 6 0xFFs followed by 16 + * contiguous copies of the receiving NIC's Ethernet address. There is + * no API to configure Magic Packet Pattern. + * + * Wakeup pattern (used for PBM) is defined as following: + * struct + * { + * U8 PatternSize; // Non-Zero pattern size + * U8 PatternMaskSize; // Non-zero pattern mask size + * U8 PatternMask[PatternMaskSize]; // Pattern mask + * U8 Pattern[PatternSize]; // Pattern + * } hdd_wowl_ptrn_t; + * + * PatternSize and PatternMaskSize indicate size of the variable + * length Pattern and PatternMask. PatternMask indicates which bytes + * of an incoming packet should be compared with corresponding bytes + * in the pattern. + * + * Maximum allowed pattern size is 128 bytes. Maximum allowed + * PatternMaskSize is 16 bytes. + * + * Maximum number of patterns that can be configured is 8 + * + * PMO will add following 2 commonly used patterns for PBM by default: + * 1) ARP Broadcast Pattern + * 2) Unicast Pattern + * + * However note that WoWL will not be enabled by default by PMO. WoWL + * needs to enabled explcitly by exercising the iwpriv command. + * + * PMO will expose an API that accepts patterns as Hex string in the + * following format: + * "PatternSize:PatternMaskSize:PatternMask:Pattern" + * + * Multiple patterns can be specified by deleimiting each pattern with + * the ';' token: + * "PatternSize1:PatternMaskSize1:PatternMask1:Pattern1;PatternSize2:..." + * + * Patterns can be configured dynamically via iwpriv cmd or statically + * via qcom_cfg.ini file + * + * PBM (when enabled) can perform filtering on unicast data or + * broadcast data or both. These configurations are part of factory + * default (cfg.dat) and the default behavior is to perform filtering + * on both unicast and data frames. + * + * MP filtering (when enabled) is performed ALWAYS on both unicast and + * broadcast data frames. + * + * Management frames are not subjected to WoWL filtering and are + * discarded when WoWL is enabled. + * + * Whenever a pattern match succeeds, RX path is restored and packets + * (both management and data) will be pushed to the host from that + * point onwards. Therefore, exit from WoWL is implicit and happens + * automatically when the first packet match succeeds. + * + * WoWL works on top of BMPS. So when WoWL is requested, SME will + * attempt to put the device in BMPS mode (if not already in BMPS). If + * attempt to BMPS fails, request for WoWL will be rejected. + */ + +#define PMO_WOW_MAX_EVENT_BM_LEN 4 + +#define PMO_WOW_FILTERS_ARP_NS 2 +#define PMO_WOW_FILTERS_PKT_OR_APF 6 + +/** + * pmo_get_and_increment_wow_default_ptrn() -Get and increment wow default ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to get and increment wow default ptrn + * + * Return: current wow default ptrn count + */ +static inline uint8_t pmo_get_and_increment_wow_default_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + uint8_t count; + + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + count = vdev_ctx->num_wow_default_patterns++; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + count = vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_def++; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } + + return count; +} + +/** + * pmo_increment_wow_default_ptrn() -increment wow default ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to increment wow default ptrn + * + * Return: None + */ +static inline void pmo_increment_wow_default_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->num_wow_default_patterns++; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_def++; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } +} + +/** + * pmo_decrement_wow_default_ptrn() -decrement wow default ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to decrement wow default ptrn + * + * Return: None + */ +static inline void pmo_decrement_wow_default_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->num_wow_default_patterns--; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_def--; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } +} + +/** + * pmo_get_wow_default_ptrn() -Get wow default ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to get wow default ptrn + * + * Return: current wow default ptrn count + */ +static inline uint8_t pmo_get_wow_default_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + uint8_t count; + + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + count = vdev_ctx->num_wow_default_patterns; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + count = vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_def; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } + + return count; +} + +/** + * pmo_set_wow_default_ptrn() - Set wow default ptrn + * @vdev_ctx: pmo vdev priv ctx + * @value: WoW default pattern + * + * API to set wow default ptrn + * + * Return: Set wow default ptrn count + */ +static inline void pmo_set_wow_default_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx, uint8_t value) +{ + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->num_wow_default_patterns = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_def = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } +} + +/** + * pmo_increment_wow_user_ptrn() -increment wow user ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to increment wow user ptrn + * + * Return: None + */ +static inline void pmo_increment_wow_user_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->num_wow_user_patterns++; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_usr++; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } +} + +/** + * pmo_decrement_wow_user_ptrn() -decrement wow user ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to decrement wow user ptrn + * + * Return: None + */ +static inline void pmo_decrement_wow_user_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->num_wow_user_patterns--; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_usr--; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } +} + +/** + * pmo_get_wow_user_ptrn() -Get wow user ptrn + * @vdev_ctx: pmo vdev priv ctx + * + * API to Get wow user ptrn + * + * Return: None + */ +static inline uint8_t pmo_get_wow_user_ptrn( + struct pmo_vdev_priv_obj *vdev_ctx) +{ + uint8_t count; + + if (vdev_ctx->pmo_psoc_ctx->caps.unified_wow) { + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + count = vdev_ctx->num_wow_user_patterns; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + } else { + qdf_spin_lock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + count = vdev_ctx->pmo_psoc_ctx->wow.ptrn_id_usr; + qdf_spin_unlock_bh(&vdev_ctx->pmo_psoc_ctx->lock); + } + + return count; +} + +/** + * pmo_core_del_wow_pattern() - Function which will delete the WoWL pattern + * @vdev: pointer to the vdev + * + * This function deletes all the user WoWl patterns and default WoWl patterns + * + * Return: error if any errors encountered, QDF_STATUS_SUCCESS otherwise + */ + +QDF_STATUS pmo_core_del_wow_pattern(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_core_add_wow_user_pattern() - Function which will add the WoWL pattern + * to be used when PBM filtering is enabled + * @vdev: pointer to the vdev + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS pmo_core_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn); + +/** + * pmo_core_del_wow_user_pattern() - Function which will delete the WoWL pattern + * @vdev: pointer to the vdev + * @pattern_id: pointer to the pattern string to be delete + * + * Return: error if any errors encountered, QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS pmo_core_del_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id); + +/** + * pmo_core_enable_wakeup_event() - enable wow wakeup events + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @wow_event: wow event to enable + * + * Return: none + */ +void pmo_core_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event); + +/** + * pmo_core_disable_wakeup_event() - disable wow wakeup events + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @wow_event: wow event to disable + * + * Return: none + */ +void pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event); + +/** + * pmo_core_is_wow_applicable(): should enable wow + * @psoc: objmgr psoc object + * + * Enable WOW if any one of the condition meets, + * 1) Is any one of vdev in beaconning mode (in AP mode) ? + * 2) Is any one of vdev in connected state (in STA mode) ? + * 3) Is PNO in progress in any one of vdev ? + * 4) Is Extscan in progress in any one of vdev ? + * 5) Is P2P listen offload in any one of vdev? + * 6) Is any vdev in NAN data mode? BSS is already started at the + * the time of device creation. It is ready to accept data + * requests. + * 7) If LPASS feature is enabled + * 8) If NaN feature is enabled + * If none of above conditions is true then return false + * + * Return: true if wma needs to configure wow false otherwise. + */ +bool pmo_core_is_wow_applicable(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_update_wow_enable() - update wow enable flag + * @psoc_ctx: Pointer to objmgr psoc handle + * @value: true if wow mode enable else false + * + * Return: None + */ +static inline +void pmo_core_update_wow_enable(struct pmo_psoc_priv_obj *psoc_ctx, + bool value) +{ + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.wow_enable = value; + qdf_spin_unlock_bh(&psoc_ctx->lock); +} + +/** + * pmo_core_is_wow_enabled() - check if wow needs to be enabled in fw + * @psoc_ctx: Pointer to objmgr psoc handle + * + * API to check if wow mode is enabled in fwr as part of apps suspend or not + * + * Return: true is wow mode is enabled else false + */ +static inline +bool pmo_core_is_wow_enabled(struct pmo_psoc_priv_obj *psoc_ctx) +{ + bool value; + + if (!psoc_ctx) { + pmo_err("psoc_ctx is null"); + return false; + } + + qdf_spin_lock_bh(&psoc_ctx->lock); + value = psoc_ctx->wow.wow_enable; + qdf_spin_unlock_bh(&psoc_ctx->lock); + pmo_debug("WoW enable %d", value); + + return value; +} + +/** + * pmo_core_set_wow_nack() - Set wow nack flag + * @psoc_ctx: Pointer to objmgr psoc handle + * @value: true if received wow nack from else false + * @reason_code: WoW status reason code + * + * Return: None + */ +static inline +void pmo_core_set_wow_nack(struct pmo_psoc_priv_obj *psoc_ctx, bool value, + uint16_t reason_code) +{ + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.wow_nack = value; + psoc_ctx->wow.reason_code = reason_code; + qdf_spin_unlock_bh(&psoc_ctx->lock); +} + +/** + * pmo_core_get_wow_nack() - Get wow nack flag + * @psoc_ctx: Pointer to objmgr psoc handle + * + * Return: wow nack flag + */ +static inline +bool pmo_core_get_wow_nack(struct pmo_psoc_priv_obj *psoc_ctx) +{ + bool value; + + qdf_spin_lock_bh(&psoc_ctx->lock); + value = psoc_ctx->wow.wow_nack; + qdf_spin_unlock_bh(&psoc_ctx->lock); + + return value; +} + +/** + * pmo_core_get_wow_reason_code() - Get wow status reason code + * @psoc_ctx: Pointer to objmgr psoc handle + * + * Return: wow status reason code + */ +static inline +uint16_t pmo_core_get_wow_reason_code(struct pmo_psoc_priv_obj *psoc_ctx) +{ + uint16_t value; + + qdf_spin_lock_bh(&psoc_ctx->lock); + value = psoc_ctx->wow.reason_code; + qdf_spin_unlock_bh(&psoc_ctx->lock); + + return value; +} + +/** + * pmo_core_update_wow_enable_cmd_sent() - update wow enable cmd sent flag + * @psoc_ctx: Pointer to objmgr psoc handle + * @value: true if wow enable cmd sent else false + * + * Return: None + */ +static inline +void pmo_core_update_wow_enable_cmd_sent(struct pmo_psoc_priv_obj *psoc_ctx, + bool value) +{ + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.wow_enable_cmd_sent = value; + qdf_spin_unlock_bh(&psoc_ctx->lock); +} + +/** + * pmo_core_get_wow_enable_cmd_sent() - Get wow enable cmd sent flag + * @psoc_ctx: Pointer to objmgr psoc handle + * + * Return: return true if wow enable cmd sent else false + */ +static inline +bool pmo_core_get_wow_enable_cmd_sent(struct pmo_psoc_priv_obj *psoc_ctx) +{ + bool value; + + qdf_spin_lock_bh(&psoc_ctx->lock); + value = psoc_ctx->wow.wow_enable_cmd_sent; + qdf_spin_unlock_bh(&psoc_ctx->lock); + + return value; +} + +/** + * pmo_core_update_wow_initial_wake_up() - update wow initial wake up + * @psoc_ctx: Pointer to objmgr psoc handle + * @value: set to 1 if wow initial wake up is received; + * if clean state, reset it to 0; + * + * Return: None + */ +static inline +void pmo_core_update_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx, + int value) +{ + qdf_atomic_set(&psoc_ctx->wow.wow_initial_wake_up, value); +} + +/** + * pmo_core_get_wow_initial_wake_up() - Get wow initial wake up + * @psoc_ctx: Pointer to objmgr psoc handle + * + * Return: 1 if wow initial wake up is received; + * 0 if wow iniital wake up is not received; + */ +static inline +int pmo_core_get_wow_initial_wake_up(struct pmo_psoc_priv_obj *psoc_ctx) +{ + return qdf_atomic_read(&psoc_ctx->wow.wow_initial_wake_up); +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * pmo_core_is_extscan_in_progress(): check if a extscan is in progress + * @vdev: objmgr vdev handle + * + * Return: TRUE/FALSE + */ +static inline +bool pmo_core_is_extscan_in_progress(struct wlan_objmgr_vdev *vdev) +{ + bool extscan_in_progress; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + extscan_in_progress = vdev_ctx->extscan_in_progress; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return extscan_in_progress; +} + +/** + * pmo_core_update_extscan_in_progress(): update extscan is in progress flags + * @vdev: objmgr vdev handle + * @value:true if extscan is in progress else false + * + * Return: TRUE/FALSE + */ +static inline +void pmo_core_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->extscan_in_progress = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} +#else +static inline +bool pmo_core_is_extscan_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +void pmo_core_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ +} +#endif + +/** + * pmo_core_is_p2plo_in_progress(): check if p2plo is in progress + * @vdev: objmgr vdev handle + * + * Return: TRUE/FALSE + */ +static inline +bool pmo_core_is_p2plo_in_progress(struct wlan_objmgr_vdev *vdev) +{ + bool p2plo_in_progress; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + p2plo_in_progress = vdev_ctx->p2plo_in_progress; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return p2plo_in_progress; +} + +/** + * pmo_core_update_p2plo_in_progress(): update p2plo is in progress flags + * @vdev: objmgr vdev handle + * @value:true if p2plo is in progress else false + * + * Return: TRUE/FALSE + */ +static inline +void pmo_core_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->p2plo_in_progress = value; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +} + +#ifdef WLAN_FEATURE_LPSS +/** + * pmo_core_is_lpass_enabled() - check if lpass is enabled + * @psoc: objmgr psoc object + * + * WoW is needed if LPASS or NaN feature is enabled in INI because + * target can't wake up itself if its put in PDEV suspend when LPASS + * or NaN features are supported + * + * Return: true if lpass is enabled else false + */ +static inline +bool pmo_core_is_lpass_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.lpass_enable; +} +#else +static inline +bool pmo_core_is_lpass_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * pmo_get_event_bitmap_idx() - get indices for extended wow bitmaps + * @event: wow event + * @wow_bitmap_size: WOW bitmap size + * @bit_idx: bit index + * @idx: byte index + * + * Return: none + */ +static inline void pmo_get_event_bitmap_idx(WOW_WAKE_EVENT_TYPE event, + uint32_t wow_bitmap_size, + uint32_t *bit_idx, + uint32_t *idx) +{ + + if (!bit_idx || !idx || wow_bitmap_size == 0) { + pmo_err("bit_idx:%pK idx:%pK wow_bitmap_size:%u", + bit_idx, idx, wow_bitmap_size); + return; + } + if (event == 0) { + *idx = *bit_idx = 0; + } else { + *idx = event / (wow_bitmap_size * 8); + *bit_idx = event % (wow_bitmap_size * 8); + } +} + +/** + * pmo_get_num_wow_filters() - get the supported number of WoW filters + * @psoc: the psoc to query + * + * Return: number of WoW filters supported + */ +uint8_t pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_core_get_wow_state() - Get wow state + * @pmo_ctx: Pointer to pmo priv object + * + * Return: current WoW status(none/D0/D3) + */ +static inline +enum pmo_wow_state pmo_core_get_wow_state(struct pmo_psoc_priv_obj *pmo_ctx) +{ + return pmo_ctx->wow.wow_state; +} +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_WOW_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_apf.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_apf.c new file mode 100644 index 0000000000..8acc3c11f9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_apf.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: PMO implementations for Android Packet Filter (APF) functions + */ + +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_pmo_apf.h" +#include "wlan_pmo_main.h" + +#define PMO_APF_SIZE_AUTO 0 +#define PMO_APF_SIZE_DISABLE 0xffffffff + +uint32_t pmo_get_apf_instruction_size(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + bool apf = false; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + apf = pmo_intersect_apf(psoc_ctx); + } + + return apf ? PMO_APF_SIZE_AUTO : PMO_APF_SIZE_DISABLE; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_arp.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_arp.c new file mode 100644 index 0000000000..ff280642ae --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_arp.c @@ -0,0 +1,442 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implements arp offload feature API's + */ + +#include "wlan_pmo_arp.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +static QDF_STATUS pmo_core_cache_arp_in_vdev_priv( + struct pmo_arp_req *arp_req, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_arp_offload_params *request = NULL; + struct pmo_vdev_priv_obj *vdev_ctx; + int index; + struct qdf_mac_addr peer_bssid; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + request = qdf_mem_malloc(sizeof(*request)); + if (!request) { + status = QDF_STATUS_E_NOMEM; + goto exit_with_status; + } + + status = pmo_get_vdev_bss_peer_mac_addr(vdev, &peer_bssid); + if (status != QDF_STATUS_SUCCESS) + goto free_req; + + qdf_mem_copy(&request->bssid.bytes, &peer_bssid.bytes, + QDF_MAC_ADDR_SIZE); + pmo_debug("vdev self mac addr: "QDF_MAC_ADDR_FMT" bss peer mac addr: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev)), + QDF_MAC_ADDR_REF(peer_bssid.bytes)); + + request->enable = PMO_OFFLOAD_ENABLE; + request->is_offload_applied = false; + /* converting u32 to IPV4 address */ + for (index = 0; index < QDF_IPV4_ADDR_SIZE; index++) + request->host_ipv4_addr[index] = + (arp_req->ipv4_addr >> (index * 8)) & 0xFF; + + /* cache arp request */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(&vdev_ctx->vdev_arp_req, request, + sizeof(vdev_ctx->vdev_arp_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_debug("cached arp offload; addr:" QDF_IPV4_ADDR_STR ", enable:%d", + QDF_IPV4_ADDR_ARRAY(request->host_ipv4_addr), + request->enable); + +free_req: + qdf_mem_free(request); + +exit_with_status: + + return status; +} + +static QDF_STATUS pmo_core_flush_arp_from_vdev_priv( + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + /* clear arp request */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_zero(&vdev_ctx->vdev_arp_req, sizeof(vdev_ctx->vdev_arp_req)); + vdev_ctx->vdev_arp_req.enable = PMO_OFFLOAD_DISABLE; + vdev_ctx->vdev_arp_req.is_offload_applied = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_exit(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +pmo_core_do_enable_arp_offload(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + struct pmo_psoc_priv_obj *psoc_ctx; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + if (!psoc_ctx) { + pmo_err("psoc_ctx is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + switch (trigger) { + case pmo_ipv4_change_notify: + if (!psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is disabled, skip in mode %d", + trigger); + status = QDF_STATUS_SUCCESS; + goto out; + } + /* enable arp when active offload is true (ipv4 notifier) */ + status = pmo_tgt_enable_arp_offload_req(vdev, vdev_id); + break; + case pmo_apps_suspend: + case pmo_arp_ns_offload_dynamic_update: + /* enable arp when active offload is false (apps suspend) */ + status = pmo_tgt_enable_arp_offload_req(vdev, vdev_id); + break; + default: + status = QDF_STATUS_E_INVAL; + pmo_err("invalid pmo trigger"); + break; + } +out: + + return status; +} + +static QDF_STATUS pmo_core_do_disable_arp_offload(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, enum pmo_offload_trigger trigger) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_psoc_priv_obj *psoc_ctx; + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + if (!psoc_ctx) { + pmo_err("psoc_ctx is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + switch (trigger) { + case pmo_apps_resume: + case pmo_arp_ns_offload_dynamic_update: + /* disable arp on apps resume when active offload is disable */ + status = pmo_tgt_disable_arp_offload_req(vdev, vdev_id); + break; + default: + status = QDF_STATUS_E_INVAL; + pmo_err("invalid pmo trigger"); + break; + } +out: + pmo_exit(); + + return status; +} + +static QDF_STATUS pmo_core_arp_offload_sanity( + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + if (!vdev) { + pmo_err("vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.arp_offload_enable) { + pmo_err("user disabled arp offload using ini"); + return QDF_STATUS_E_INVAL; + } + + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for arp offload %d", + pmo_get_vdev_opmode(vdev)); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_arp_check_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_psoc_priv_obj *psoc_ctx; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_vdev *vdev; + bool active_offload_cond, is_applied_cond; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + opmode = pmo_get_vdev_opmode(vdev); + if (opmode == QDF_NDI_MODE) { + pmo_debug("ARP offload is not supported in NaN mode"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + pmo_debug("ARP offload not supported for MLO partner link " + "with vdev_id[%d]", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + + if (trigger == pmo_apps_suspend || trigger == pmo_apps_resume) { + active_offload_cond = psoc_ctx->psoc_cfg.active_mode_offload; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + is_applied_cond = vdev_ctx->vdev_arp_req.enable && + vdev_ctx->vdev_arp_req.is_offload_applied; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + if (active_offload_cond && is_applied_cond) { + pmo_debug("active offload is enabled and offload already sent"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + return status; +} + +QDF_STATUS pmo_core_cache_arp_offload_req(struct pmo_arp_req *arp_req) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + if (!arp_req) { + pmo_err("arp_req is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + if (!arp_req->psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(arp_req->psoc, + arp_req->vdev_id, + WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_core_arp_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + pmo_debug("Cache arp for vdev id: %d psoc: %pK vdev: %pK", + arp_req->vdev_id, arp_req->psoc, vdev); + + status = pmo_core_cache_arp_in_vdev_priv(arp_req, vdev); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS pmo_core_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + uint8_t vdev_id; + + pmo_enter(); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + status = pmo_core_arp_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto def_ref; + + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("Flush arp for vdev id: %d vdev: %pK", vdev_id, vdev); + + status = pmo_core_flush_arp_from_vdev_priv(vdev); +def_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + uint8_t vdev_id; + + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + status = pmo_core_arp_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto put_ref; + + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("Enable arp offload in fwr vdev id: %d vdev: %pK", + vdev_id, vdev); + + status = pmo_core_do_enable_arp_offload(vdev, vdev_id, trigger); + +put_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out:; + + return status; +} + +QDF_STATUS pmo_core_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + uint8_t vdev_id; + + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + status = pmo_core_arp_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto def_ref; + + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("Disable arp offload in fwr vdev id: %d vdev: %pK", + vdev_id, vdev); + + status = pmo_core_do_disable_arp_offload(vdev, vdev_id, trigger); +def_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS +pmo_core_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + uint8_t vdev_id; + + pmo_enter(); + + if (!params) + return QDF_STATUS_E_INVAL; + + qdf_mem_zero(params, sizeof(*params)); + + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + status = pmo_core_arp_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto put_ref; + + vdev_id = pmo_vdev_get_id(vdev); + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + *params = vdev_ctx->vdev_arp_req; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +put_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_gtk.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_gtk.c new file mode 100644 index 0000000000..d62fbb1c76 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_gtk.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements gtk offload feature API's + */ + +#include "wlan_pmo_gtk.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +static QDF_STATUS pmo_core_cache_gtk_req_in_vdev_priv( + struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + QDF_STATUS status; + struct qdf_mac_addr peer_bssid; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + status = pmo_get_vdev_bss_peer_mac_addr(vdev, &peer_bssid); + if (status != QDF_STATUS_SUCCESS) + return status; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(&vdev_ctx->vdev_gtk_req, gtk_req, + sizeof(vdev_ctx->vdev_gtk_req)); + qdf_mem_copy(&vdev_ctx->vdev_gtk_req.bssid, + &peer_bssid, QDF_MAC_ADDR_SIZE); + vdev_ctx->vdev_gtk_req.flags = PMO_GTK_OFFLOAD_ENABLE; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS pmo_core_flush_gtk_req_from_vdev_priv( + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_zero(&vdev_ctx->vdev_gtk_req, sizeof(vdev_ctx->vdev_gtk_req)); + vdev_ctx->vdev_gtk_req.flags = PMO_GTK_OFFLOAD_DISABLE; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS pmo_core_do_enable_gtk_offload( + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx, + struct pmo_gtk_req *op_gtk_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id; + enum QDF_OPMODE op_mode; + + op_mode = pmo_get_vdev_opmode(vdev); + if (QDF_NDI_MODE == op_mode) { + pmo_debug("gtk offload is not supported in NaN mode"); + return QDF_STATUS_E_INVAL; + } + + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for gtk offload %d", + pmo_get_vdev_opmode(vdev)); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + vdev_id = pmo_vdev_get_id(vdev); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(op_gtk_req, &vdev_ctx->vdev_gtk_req, + sizeof(*op_gtk_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + if ((op_gtk_req->flags == PMO_GTK_OFFLOAD_ENABLE) && + (qdf_atomic_read(&vdev_ctx->gtk_err_enable) == 1)) { + pmo_debug("GTK Offload already enabled, Disabling vdev_id: %d", + vdev_id); + op_gtk_req->flags = PMO_GTK_OFFLOAD_DISABLE; + status = pmo_tgt_send_gtk_offload_req(vdev, op_gtk_req); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to disable GTK Offload"); + goto out; + } + pmo_debug("Enable GTK Offload again with updated inputs"); + op_gtk_req->flags = PMO_GTK_OFFLOAD_ENABLE; + } + + status = pmo_tgt_send_gtk_offload_req(vdev, op_gtk_req); +out: + + return status; +} + +static QDF_STATUS pmo_core_is_gtk_enabled_in_fwr( + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx) +{ + QDF_STATUS status; + struct qdf_mac_addr peer_bssid; + + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for gtk offload enable %d", + pmo_get_vdev_opmode(vdev)); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + status = pmo_get_vdev_bss_peer_mac_addr(vdev, + &peer_bssid); + if (status != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (qdf_mem_cmp(&vdev_ctx->vdev_gtk_req.bssid, + &peer_bssid, QDF_MAC_ADDR_SIZE)) { + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + pmo_err("cache request mac:"QDF_MAC_ADDR_FMT", peer mac:"QDF_MAC_ADDR_FMT" are not same", + QDF_MAC_ADDR_REF(vdev_ctx->vdev_gtk_req.bssid.bytes), + QDF_MAC_ADDR_REF(peer_bssid.bytes)); + return QDF_STATUS_E_INVAL; + } + + if (vdev_ctx->vdev_gtk_req.flags != PMO_GTK_OFFLOAD_ENABLE) { + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + pmo_err("gtk flag is disabled hence no gtk rsp required"); + return QDF_STATUS_E_INVAL; + } + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS pmo_core_do_disable_gtk_offload( + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx, + struct pmo_gtk_req *op_gtk_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum QDF_OPMODE op_mode; + + op_mode = pmo_get_vdev_opmode(vdev); + if (QDF_NDI_MODE == op_mode) { + pmo_debug("gtk offload is not supported in NaN mode"); + return QDF_STATUS_E_INVAL; + } + + status = pmo_core_is_gtk_enabled_in_fwr(vdev, vdev_ctx); + if (status != QDF_STATUS_SUCCESS) + return status; + + op_gtk_req->flags = PMO_GTK_OFFLOAD_DISABLE; + status = pmo_tgt_send_gtk_offload_req(vdev, op_gtk_req); + + return status; +} + +QDF_STATUS pmo_core_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + QDF_STATUS status; + enum QDF_OPMODE opmode; + uint8_t vdev_id; + + if (!gtk_req) { + pmo_err("gtk_req is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + opmode = pmo_get_vdev_opmode(vdev); + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("vdev opmode: %d vdev_id: %d", opmode, vdev_id); + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for caching gtk request %d", + opmode); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + + status = pmo_core_cache_gtk_req_in_vdev_priv(vdev, gtk_req); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS pmo_core_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE opmode; + uint8_t vdev_id; + QDF_STATUS status; + + if (!vdev) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + opmode = pmo_get_vdev_opmode(vdev); + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("vdev opmode: %d vdev_id: %d", opmode, vdev_id); + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for flushing gtk request %d", + opmode); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + + status = pmo_core_flush_gtk_req_from_vdev_priv(vdev); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS pmo_core_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_gtk_req *op_gtk_req = NULL; + + pmo_enter(); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + op_gtk_req = qdf_mem_malloc(sizeof(*op_gtk_req)); + if (!op_gtk_req) { + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + status = pmo_core_do_enable_gtk_offload(vdev, vdev_ctx, op_gtk_req); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + if (op_gtk_req) + qdf_mem_free(op_gtk_req); + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_gtk_req *op_gtk_req = NULL; + + pmo_enter(); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + op_gtk_req = qdf_mem_malloc(sizeof(*op_gtk_req)); + if (!op_gtk_req) { + status = QDF_STATUS_E_NOMEM; + goto dec_ref; + } + + status = pmo_core_do_disable_gtk_offload(vdev, vdev_ctx, op_gtk_req); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + if (op_gtk_req) + qdf_mem_free(op_gtk_req); + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_get_gtk_rsp(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + if (!gtk_rsp_req || !vdev) { + pmo_err("%s is null", !vdev ? "vdev":"gtk_rsp_req"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + status = pmo_core_is_gtk_enabled_in_fwr(vdev, vdev_ctx); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + /* cache gtk rsp request */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(&vdev_ctx->vdev_gtk_rsp_req, gtk_rsp_req, + sizeof(vdev_ctx->vdev_gtk_rsp_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + /* send cmd to fwr */ + status = pmo_tgt_get_gtk_rsp(vdev); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_hw_filter.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_hw_filter.c new file mode 100644 index 0000000000..bdee718502 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_hw_filter.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements arp offload feature API's + */ + +#include "qdf_lock.h" +#include "wlan_pmo_hw_filter.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +QDF_STATUS pmo_core_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct pmo_psoc_priv_obj *psoc_priv; + enum pmo_hw_filter_mode mode_bitmap; + struct pmo_hw_filter_params req = {0}; + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) { + status = QDF_STATUS_E_NOSUPPORT; + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + goto exit_with_status; + } + + psoc_priv = pmo_vdev_get_psoc_priv(vdev); + qdf_spin_lock_bh(&psoc_priv->lock); + mode_bitmap = psoc_priv->psoc_cfg.hw_filter_mode_bitmap; + qdf_spin_unlock_bh(&psoc_priv->lock); + + req.vdev_id = pmo_vdev_get_id(vdev); + req.mode_bitmap = psoc_priv->psoc_cfg.hw_filter_mode_bitmap; + req.enable = true; + status = pmo_tgt_conf_hw_filter(pmo_vdev_get_psoc(vdev), &req); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +exit_with_status: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct pmo_psoc_priv_obj *psoc_priv; + enum pmo_hw_filter_mode mode_bitmap; + struct pmo_hw_filter_params req = {0}; + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) { + status = QDF_STATUS_E_NOSUPPORT; + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + goto exit_with_status; + } + + psoc_priv = pmo_vdev_get_psoc_priv(vdev); + qdf_spin_lock_bh(&psoc_priv->lock); + mode_bitmap = psoc_priv->psoc_cfg.hw_filter_mode_bitmap; + qdf_spin_unlock_bh(&psoc_priv->lock); + + req.vdev_id = pmo_vdev_get_id(vdev); + req.mode_bitmap = mode_bitmap; + req.enable = false; + status = pmo_tgt_conf_hw_filter(pmo_vdev_get_psoc(vdev), &req); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +exit_with_status: + pmo_exit(); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_icmp.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_icmp.c new file mode 100644 index 0000000000..eee4229500 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_icmp.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements icmp offload feature API's + */ + +#include "wlan_pmo_icmp.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +QDF_STATUS pmo_core_icmp_check_offload(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL. vdev_id is %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + opmode = pmo_get_vdev_opmode(vdev); + if (opmode != QDF_STA_MODE) { + pmo_debug("ICMP offload is supported in STA mode only"); + status = QDF_STATUS_E_INVAL; + goto out; + } + +out: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_lphb.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_lphb.c new file mode 100644 index 0000000000..9ca0be70d1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_lphb.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implements low power heart beat offload feature API's + */ + +#include "wlan_pmo_main.h" +#include "wlan_pmo_lphb.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +#ifdef FEATURE_WLAN_LPHB +/** + * pmo_core_send_lphb_enable() - enable command of LPHB configuration requests + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo private psoc ctx + * @lphb_conf_req: lphb request which need s to configure in fwr + * @by_user: whether this call is from user or cached resent + * + * Return: QDF status + */ +static QDF_STATUS pmo_core_send_lphb_enable(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx, + struct pmo_lphb_req *lphb_conf_req, bool by_user) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct pmo_lphb_enable_req *ts_lphb_enable; + int i; + + if (!lphb_conf_req) { + pmo_err("LPHB configuration is NULL"); + return QDF_STATUS_E_FAILURE; + } + + ts_lphb_enable = &(lphb_conf_req->params.lphb_enable_req); + qdf_status = pmo_tgt_send_lphb_enable(psoc, ts_lphb_enable); + if (qdf_status != QDF_STATUS_SUCCESS) + goto out; + + /* No need to cache non user request */ + if (!by_user) { + qdf_status = QDF_STATUS_SUCCESS; + goto out; + } + + /* target already configured, now cache command status */ + if (ts_lphb_enable->enable && ts_lphb_enable->item > 0) { + i = ts_lphb_enable->item - 1; + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.lphb_cache[i].cmd + = pmo_lphb_set_en_param_indid; + psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.enable = + ts_lphb_enable->enable; + psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.item = + ts_lphb_enable->item; + psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.session = + ts_lphb_enable->session; + qdf_spin_unlock_bh(&psoc_ctx->lock); + pmo_debug("cached LPHB status in WMA context for item %d", i); + } else { + qdf_spin_lock_bh(&psoc_ctx->lock); + qdf_mem_zero((void *)&psoc_ctx->wow.lphb_cache, + sizeof(psoc_ctx->wow.lphb_cache)); + qdf_spin_unlock_bh(&psoc_ctx->lock); + pmo_debug("cleared all cached LPHB status in WMA context"); + } + +out: + return qdf_status; +} + +/** + * pmo_core_send_lphb_tcp_params() - Send tcp params of LPHB requests + * @psoc: objmgr psoc handle + * @lphb_conf_req: lphb request which needs to be configured in fwr + * + * Return: QDF status + */ +static +QDF_STATUS pmo_core_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_conf_req) +{ + return pmo_tgt_send_lphb_tcp_params(psoc, + &lphb_conf_req->params.lphb_tcp_params); + +} + +/** + * pmo_core_send_lphb_tcp_pkt_filter() - Send tcp packet filter command of LPHB + * @psoc: objmgr psoc handle + * @lphb_conf_req: lphb request which needs to be configured in fwr + * + * Return: QDF status + */ +static +QDF_STATUS pmo_core_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_conf_req) +{ + return pmo_tgt_send_lphb_tcp_pkt_filter(psoc, + &lphb_conf_req->params.lphb_tcp_filter_req); +} + +/** + * pmo_core_send_lphb_udp_params() - Send udp param command of LPHB + * @psoc: objmgr psoc handle + * @lphb_conf_req: lphb request which needs to be configured in fwr + * + * Return: QDF status + */ +static +QDF_STATUS pmo_core_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_conf_req) +{ + return pmo_tgt_send_lphb_udp_params(psoc, + &lphb_conf_req->params.lphb_udp_params); +} + +/** + * pmo_core_send_lphb_udp_pkt_filter() - Send udp pkt filter command of LPHB + * @psoc: objmgr psoc handle + * @lphb_conf_req: lphb request which need s to configure in fwr + * + * Return: QDF status + */ +static +QDF_STATUS pmo_core_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_conf_req) +{ + return pmo_tgt_send_lphb_udp_pkt_filter(psoc, + &lphb_conf_req->params.lphb_udp_filter_req); +} + +/** + * pmo_process_lphb_conf_req() - handle LPHB configuration requests + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo private psoc ctx + * @lphb_conf_req: lphb request which needs to be configured in fwr + * + * Return: QDF status + */ +static QDF_STATUS pmo_process_lphb_conf_req(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx, + struct pmo_lphb_req *lphb_conf_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_debug("LPHB configuration cmd id is %d", lphb_conf_req->cmd); + switch (lphb_conf_req->cmd) { + case pmo_lphb_set_en_param_indid: + status = pmo_core_send_lphb_enable(psoc, psoc_ctx, + lphb_conf_req, true); + break; + + case pmo_lphb_set_tcp_pararm_indid: + status = pmo_core_send_lphb_tcp_params(psoc, lphb_conf_req); + break; + + case pmo_lphb_set_tcp_pkt_filter_indid: + status = pmo_core_send_lphb_tcp_pkt_filter(psoc, lphb_conf_req); + break; + + case pmo_lphb_set_udp_pararm_indid: + status = pmo_core_send_lphb_udp_params(psoc, lphb_conf_req); + break; + + case pmo_lphb_set_udp_pkt_filter_indid: + status = pmo_core_send_lphb_udp_pkt_filter(psoc, lphb_conf_req); + break; + + case pmo_lphb_set_network_info_indid: + default: + break; + } + + return status; +} + +void pmo_core_apply_lphb(struct wlan_objmgr_psoc *psoc) +{ + int i; + struct pmo_psoc_priv_obj *psoc_ctx; + + psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_debug("checking LPHB cache"); + for (i = 0; i < 2; i++) { + if (psoc_ctx->wow.lphb_cache[i].params.lphb_enable_req.enable) { + pmo_debug("LPHB cache for item %d is marked as enable", + i + 1); + pmo_core_send_lphb_enable(psoc, psoc_ctx, + &(psoc_ctx->wow.lphb_cache[i]), false); + } + } +} + +QDF_STATUS pmo_core_lphb_config_req(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx, + pmo_lphb_callback callback) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + if (!lphb_req) { + pmo_err("LPHB configuration is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + + if (pmo_lphb_set_en_param_indid == lphb_req->cmd) { + if (!lphb_cb_ctx) { + pmo_err("lphb callback context is null"); + return QDF_STATUS_E_NULL_VALUE; + } + if (!callback) { + pmo_err("lphb callback function is null"); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.lphb_cb_ctx = lphb_cb_ctx; + psoc_ctx->wow.lphb_cb = callback; + qdf_spin_unlock_bh(&psoc_ctx->lock); + } + + return pmo_process_lphb_conf_req(psoc, psoc_ctx, lphb_req); +} + +#endif /* FEATURE_WLAN_LPHB */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_main.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_main.c new file mode 100644 index 0000000000..6644b5d102 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_main.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021,2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implement various api / helper function which shall be used + * PMO user and target interface. + */ + +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_cfg.h" +#include "cfg_ucfg_api.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_ipa_obj_mgmt_api.h" +#include "wlan_pmo_icmp.h" + +static struct wlan_pmo_ctx *gp_pmo_ctx; + +QDF_STATUS pmo_allocate_ctx(void) +{ + /* If it is already created, ignore */ + if (gp_pmo_ctx) { + pmo_debug("already allocated pmo_ctx"); + return QDF_STATUS_SUCCESS; + } + + /* allocate offload mgr ctx */ + gp_pmo_ctx = (struct wlan_pmo_ctx *)qdf_mem_malloc( + sizeof(*gp_pmo_ctx)); + if (!gp_pmo_ctx) + return QDF_STATUS_E_NOMEM; + + qdf_spinlock_create(&gp_pmo_ctx->lock); + + return QDF_STATUS_SUCCESS; +} + +void pmo_free_ctx(void) +{ + if (!gp_pmo_ctx) { + pmo_err("pmo ctx is already freed"); + QDF_ASSERT(0); + return; + } + qdf_spinlock_destroy(&gp_pmo_ctx->lock); + qdf_mem_free(gp_pmo_ctx); + gp_pmo_ctx = NULL; +} + +struct wlan_pmo_ctx *pmo_get_context(void) +{ + return gp_pmo_ctx; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static void wlan_extwow_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->extwow_goto_suspend = + cfg_get(psoc, CFG_EXTWOW_GOTO_SUSPEND); + psoc_cfg->extwow_app1_wakeup_pin_num = + cfg_get(psoc, CFG_EXTWOW_APP1_WAKE_PIN_NUMBER); + psoc_cfg->extwow_app2_wakeup_pin_num = + cfg_get(psoc, CFG_EXTWOW_APP2_WAKE_PIN_NUMBER); + psoc_cfg->extwow_app2_init_ping_interval = + cfg_get(psoc, CFG_EXTWOW_KA_INIT_PING_INTERVAL); + psoc_cfg->extwow_app2_min_ping_interval = + cfg_get(psoc, CFG_EXTWOW_KA_MIN_PING_INTERVAL); + psoc_cfg->extwow_app2_max_ping_interval = + cfg_get(psoc, CFG_EXTWOW_KA_MAX_PING_INTERVAL); + psoc_cfg->extwow_app2_inc_ping_interval = + cfg_get(psoc, CFG_EXTWOW_KA_INC_PING_INTERVAL); + psoc_cfg->extwow_app2_tcp_src_port = + cfg_get(psoc, CFG_EXTWOW_TCP_SRC_PORT); + psoc_cfg->extwow_app2_tcp_dst_port = + cfg_get(psoc, CFG_EXTWOW_TCP_DST_PORT); + psoc_cfg->extwow_app2_tcp_tx_timeout = + cfg_get(psoc, CFG_EXTWOW_TCP_TX_TIMEOUT); + psoc_cfg->extwow_app2_tcp_rx_timeout = + cfg_get(psoc, CFG_EXTWOW_TCP_RX_TIMEOUT); +} +#else +static void wlan_extwow_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_WOW_PULSE +static void wlan_pmo_wow_pulse_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->is_wow_pulse_supported = + cfg_get(psoc, CFG_PMO_WOW_PULSE_ENABLE); + psoc_cfg->wow_pulse_pin = cfg_get(psoc, CFG_PMO_WOW_PULSE_PIN); + psoc_cfg->wow_pulse_interval_high = + cfg_get(psoc, CFG_PMO_WOW_PULSE_HIGH); + psoc_cfg->wow_pulse_interval_low = + cfg_get(psoc, CFG_PMO_WOW_PULSE_LOW); + psoc_cfg->wow_pulse_repeat_count = + cfg_get(psoc, CFG_PMO_WOW_PULSE_REPEAT); + psoc_cfg->wow_pulse_init_state = + cfg_get(psoc, CFG_PMO_WOW_PULSE_INIT); +} +#else +static void wlan_pmo_wow_pulse_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_PACKET_FILTERING +static void wlan_pmo_pkt_filter_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->packet_filters_bitmap = cfg_get(psoc, CFG_PMO_PKT_FILTER); + psoc_cfg->packet_filter_enabled = + !cfg_get(psoc, CFG_PMO_DISABLE_PKT_FILTER); +} +#else +static void wlan_pmo_pkt_filter_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->packet_filter_enabled = + !cfg_get(psoc, CFG_PMO_DISABLE_PKT_FILTER); +} +#endif + +#ifdef FEATURE_RUNTIME_PM +static void wlan_pmo_runtime_pm_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->runtime_pm_delay = cfg_get(psoc, CFG_PMO_RUNTIME_PM_DELAY); +} +#else +static void wlan_pmo_runtime_pm_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ +} +#endif + +#ifdef FEATURE_WLAN_RA_FILTERING +static void wlan_pmo_ra_filtering_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + bool ra_enable; + + if (QDF_IS_STATUS_SUCCESS(ucfg_fwol_get_is_rate_limit_enabled(psoc, + &ra_enable))) + psoc_cfg->ra_ratelimit_enable = ra_enable; + + psoc_cfg->ra_ratelimit_interval = + cfg_get(psoc, CFG_RA_RATE_LIMIT_INTERVAL); +} +#else +static void wlan_pmo_ra_filtering_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ +} +#endif + +#ifdef WLAN_ENABLE_GPIO_WAKEUP +static void wlan_pmo_gpio_wakeup_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->enable_gpio_wakeup = + cfg_get(psoc, CFG_PMO_ENABLE_GPIO_WAKEUP); + psoc_cfg->gpio_wakeup_pin = + cfg_get(psoc, CFG_PMO_GPIO_WAKEUP_PIN); + psoc_cfg->gpio_wakeup_mode = + cfg_get(psoc, CFG_PMO_GPIO_WAKEUP_MODE); +} +#else +static void wlan_pmo_gpio_wakeup_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +static void +wlan_pmo_get_igmp_version_support_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->igmp_version_support = + cfg_get(psoc, CFG_IGMP_VERSION_SUPPORT); +} + +static void +wlan_pmo_get_igmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->igmp_offload_enable = cfg_get(psoc, + CFG_PMO_ENABLE_IGMP_OFFLOAD); +} +#else +static void +wlan_pmo_get_igmp_version_support_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{} + +static void +wlan_pmo_get_igmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{} +#endif + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +static void +wlan_pmo_get_icmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->is_icmp_offload_enable = + cfg_get(psoc, CFG_ENABLE_ICMP_OFFLOAD); +} +#else +static inline void +wlan_pmo_get_icmp_offload_enable_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{} +#endif + +static void wlan_pmo_init_cfg(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + psoc_cfg->arp_offload_enable = + cfg_get(psoc, CFG_PMO_ENABLE_HOST_ARPOFFLOAD); + psoc_cfg->hw_filter_mode_bitmap = cfg_get(psoc, CFG_PMO_HW_FILTER_MODE); + psoc_cfg->ssdp = cfg_get(psoc, CFG_PMO_ENABLE_HOST_SSDP); + psoc_cfg->ns_offload_enable_static = + cfg_get(psoc, CFG_PMO_ENABLE_HOST_NSOFFLOAD); + psoc_cfg->ns_offload_enable_dynamic = + cfg_get(psoc, CFG_PMO_ENABLE_HOST_NSOFFLOAD); + psoc_cfg->sta_dynamic_dtim = cfg_get(psoc, CFG_PMO_ENABLE_DYNAMIC_DTIM); + wlan_pmo_get_igmp_version_support_cfg(psoc, psoc_cfg); + psoc_cfg->sta_mod_dtim = cfg_get(psoc, CFG_PMO_ENABLE_MODULATED_DTIM); + psoc_cfg->enable_mc_list = cfg_get(psoc, CFG_PMO_MC_ADDR_LIST_ENABLE); + psoc_cfg->power_save_mode = cfg_get(psoc, CFG_PMO_POWERSAVE_MODE); + psoc_cfg->sta_forced_dtim = cfg_get(psoc, CFG_PMO_ENABLE_FORCED_DTIM); + psoc_cfg->is_mod_dtim_on_sys_suspend_enabled = + cfg_get(psoc, CFG_PMO_MOD_DTIM_ON_SYS_SUSPEND); + psoc_cfg->is_bus_suspend_enabled_in_sap_mode = + cfg_get(psoc, CFG_ENABLE_BUS_SUSPEND_IN_SAP_MODE); + psoc_cfg->is_bus_suspend_enabled_in_go_mode = + cfg_get(psoc, CFG_ENABLE_BUS_SUSPEND_IN_GO_MODE); + if (wlan_ipa_config_is_enabled() && + !ipa_config_is_opt_wifi_dp_enabled()) { + pmo_info("ipa is enabled and hence disable sap/go d3 wow"); + psoc_cfg->is_bus_suspend_enabled_in_sap_mode = 0; + psoc_cfg->is_bus_suspend_enabled_in_go_mode = 0; + } + psoc_cfg->default_power_save_mode = psoc_cfg->power_save_mode; + psoc_cfg->max_ps_poll = cfg_get(psoc, CFG_PMO_MAX_PS_POLL); + + psoc_cfg->wow_enable = cfg_get(psoc, CFG_PMO_WOW_ENABLE); + psoc_cfg->suspend_mode = cfg_get(psoc, CFG_PMO_SUSPEND_MODE); + + wlan_extwow_init_cfg(psoc, psoc_cfg); + psoc_cfg->apf_enable = cfg_get(psoc, CFG_PMO_APF_ENABLE); + psoc_cfg->active_mode_offload = cfg_get(psoc, CFG_PMO_ACTIVE_MODE); + wlan_pmo_wow_pulse_init_cfg(psoc, psoc_cfg); + wlan_pmo_pkt_filter_init_cfg(psoc, psoc_cfg); + wlan_pmo_runtime_pm_init_cfg(psoc, psoc_cfg); + psoc_cfg->auto_power_save_fail_mode = + cfg_get(psoc, CFG_PMO_PWR_FAILURE); + psoc_cfg->enable_sap_suspend = cfg_get(psoc, CFG_ENABLE_SAP_SUSPEND); + psoc_cfg->wow_data_inactivity_timeout = + cfg_get(psoc, CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT); + psoc_cfg->wow_spec_wake_interval = + cfg_get(psoc, CFG_PMO_WOW_SPEC_WAKE_INTERVAL); + psoc_cfg->active_uc_apf_mode = + cfg_get(psoc, CFG_ACTIVE_UC_APF_MODE); + psoc_cfg->active_mc_bc_apf_mode = + cfg_get(psoc, CFG_ACTIVE_MC_BC_APF_MODE); + psoc_cfg->ito_repeat_count = cfg_get(psoc, CFG_ITO_REPEAT_COUNT); + wlan_pmo_ra_filtering_init_cfg(psoc, psoc_cfg); + wlan_pmo_gpio_wakeup_init_cfg(psoc, psoc_cfg); + wlan_pmo_get_igmp_offload_enable_cfg(psoc, psoc_cfg); + psoc_cfg->disconnect_sap_tdls_in_wow = + cfg_get(psoc, CFG_DISCONNECT_SAP_TDLS_IN_WOW); + wlan_pmo_get_icmp_offload_enable_cfg(psoc, psoc_cfg); + + psoc_cfg->host_pf_action = cfg_get(psoc, CFG_HOST_ACTION_ON_PAGEFAULT); + psoc_cfg->min_pagefault_wakeups_for_action = + cfg_get(psoc, + CFG_MIN_PAGEFAULT_WAKEUPS_FOR_ACTION); + psoc_cfg->interval_for_pagefault_wakeup_counts = + cfg_get(psoc, + CFG_INTERVAL_FOR_PAGEFAULT_WAKEUP_COUNT); + psoc_cfg->ssr_frequency_on_pagefault = + cfg_get(psoc, CFG_SSR_FREQUENCY_ON_PAGEFAULT); +} + +QDF_STATUS pmo_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx; + + if (!psoc) { + pmo_err("null psoc"); + return QDF_STATUS_E_INVAL; + } + + pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + wlan_pmo_init_cfg(psoc, &pmo_psoc_ctx->psoc_cfg); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +bool pmo_is_vdev_in_beaconning_mode(enum QDF_OPMODE vdev_opmode) +{ + switch (vdev_opmode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + case QDF_IBSS_MODE: + return true; + default: + return false; + } +} + +QDF_STATUS pmo_get_vdev_bss_peer_mac_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bss_peer_mac_address) +{ + struct wlan_objmgr_peer *peer; + + if (!vdev) { + pmo_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_PMO_ID); + if (!peer) { + pmo_err("peer is null"); + return QDF_STATUS_E_INVAL; + } + wlan_peer_obj_lock(peer); + qdf_mem_copy(bss_peer_mac_address->bytes, wlan_peer_get_macaddr(peer), + QDF_MAC_ADDR_SIZE); + wlan_peer_obj_unlock(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_PMO_ID); + + return QDF_STATUS_SUCCESS; +} + +bool pmo_core_is_ap_mode_supports_arp_ns(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + psoc_ctx = pmo_psoc_get_priv(psoc); + + if ((vdev_opmode == QDF_SAP_MODE || + vdev_opmode == QDF_P2P_GO_MODE) && + !psoc_ctx->psoc_cfg.ap_arpns_support) { + pmo_debug("ARP/NS Offload is not supported in SAP/P2PGO mode"); + return false; + } + + return true; +} + +bool pmo_core_is_vdev_supports_offload(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE opmode; + bool val; + + opmode = pmo_get_vdev_opmode(vdev); + pmo_debug("vdev opmode: %d", opmode); + switch (opmode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_NDI_MODE: + val = true; + break; + default: + val = false; + break; + } + + return val; +} + +QDF_STATUS pmo_core_get_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + if (!psoc || !psoc_cfg) { + pmo_err("%s is null", !psoc ? "psoc":"psoc_cfg"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + qdf_mem_copy(psoc_cfg, &psoc_ctx->psoc_cfg, sizeof(*psoc_cfg)); + } + +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_update_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + if (!psoc || !psoc_cfg) { + pmo_err("%s is null", !psoc ? "psoc":"psoc_cfg"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + qdf_mem_copy(&psoc_ctx->psoc_cfg, psoc_cfg, sizeof(*psoc_cfg)); + } + +out: + pmo_exit(); + + return status; +} + +void pmo_psoc_set_caps(struct wlan_objmgr_psoc *psoc, + struct pmo_device_caps *caps) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + qdf_mem_copy(&psoc_ctx->caps, caps, sizeof(psoc_ctx->caps)); + } +} + +void pmo_core_psoc_set_hif_handle(struct wlan_objmgr_psoc *psoc, + void *hif_hdl) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->hif_hdl = hif_hdl; + } +} + +void *pmo_core_psoc_get_hif_handle(struct wlan_objmgr_psoc *psoc) +{ + void *hif_hdl = NULL; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + hif_hdl = psoc_ctx->hif_hdl; + } + + return hif_hdl; +} + +void pmo_core_psoc_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t txrx_pdev_id) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->txrx_pdev_id = txrx_pdev_id; + } +} + +uint8_t pmo_core_psoc_get_txrx_handle(struct wlan_objmgr_psoc *psoc) +{ + uint8_t txrx_pdev_id = OL_TXRX_INVALID_PDEV_ID; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + txrx_pdev_id = psoc_ctx->txrx_pdev_id; + } + + return txrx_pdev_id; +} + +enum pmo_page_fault_action +pmo_host_action_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return PMO_PF_HOST_ACTION_NO_OP; + + return pmo_psoc_ctx->psoc_cfg.host_pf_action; +} + +uint8_t pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return 0; + + return pmo_psoc_ctx->psoc_cfg.min_pagefault_wakeups_for_action; +} + +uint32_t +pmo_get_interval_for_pagefault_wakeup_counts(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return 0; + + return pmo_psoc_ctx->psoc_cfg.interval_for_pagefault_wakeup_counts; +} + +uint32_t pmo_get_ssr_frequency_on_pagefault(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return 0; + + return pmo_psoc_ctx->psoc_cfg.ssr_frequency_on_pagefault; +} + +QDF_STATUS pmo_get_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + if (!vdev) { + pmo_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_mem_copy(bridgeaddr->bytes, vdev_ctx->bridgeaddr, + QDF_MAC_ADDR_SIZE); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_set_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + if (!vdev) { + pmo_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_mem_copy(vdev_ctx->bridgeaddr, bridgeaddr->bytes, QDF_MAC_ADDR_SIZE); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + if (!vdev || !listen_interval) { + pmo_err("vdev NULL or NULL ptr"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + *listen_interval = vdev_ctx->dyn_listen_interval; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c new file mode 100644 index 0000000000..da5e0fe62f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_mc_addr_filtering.c @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements mc addr filtering offload feature API's + */ + +#include "wlan_pmo_mc_addr_filtering.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +#define PMO_INVALID_MC_ADDR_COUNT (-1) + +static void pmo_core_fill_mc_list(struct pmo_vdev_priv_obj **vdev_ctx, + struct pmo_mc_addr_list_params *ip) +{ + struct pmo_mc_addr_list *op_list; + int i, j = 0; + static const uint8_t ipv6_rs[] = { + 0x33, 0x33, 0x00, 0x00, 0x00, 0x02}; + struct pmo_vdev_priv_obj *temp_ctx; + uint8_t addr_fp; + + temp_ctx = *vdev_ctx; + addr_fp = temp_ctx->addr_filter_pattern; + op_list = &temp_ctx->vdev_mc_list_req; + + qdf_spin_lock_bh(&temp_ctx->pmo_vdev_lock); + op_list->mc_cnt = ip->count; + qdf_spin_unlock_bh(&temp_ctx->pmo_vdev_lock); + + for (i = 0; i < ip->count; i++) { + /* + * Skip following addresses: + * 1)IPv6 router solicitation address + * 2)Any other address pattern if its set during + * RXFILTER REMOVE driver command based on + * addr_filter_pattern + */ + if ((!qdf_mem_cmp(ip->mc_addr[i].bytes, ipv6_rs, + QDF_MAC_ADDR_SIZE)) || + (addr_fp && + (!qdf_mem_cmp(ip->mc_addr[i].bytes, &addr_fp, 1)))) { + pmo_debug("MC/BC filtering Skip addr "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ip->mc_addr[i].bytes)); + qdf_spin_lock_bh(&temp_ctx->pmo_vdev_lock); + op_list->mc_cnt--; + qdf_spin_unlock_bh(&temp_ctx->pmo_vdev_lock); + continue; + } + qdf_spin_lock_bh(&temp_ctx->pmo_vdev_lock); + qdf_mem_zero(&op_list->mc_addr[j].bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&op_list->mc_addr[j].bytes, + ip->mc_addr[i].bytes, QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh(&temp_ctx->pmo_vdev_lock); + pmo_debug("Index = %d, mac["QDF_MAC_ADDR_FMT"]", j, + QDF_MAC_ADDR_REF(op_list->mc_addr[j].bytes)); + j++; + } +} + +static QDF_STATUS pmo_core_cache_mc_addr_list_in_vdev_priv( + struct pmo_mc_addr_list_params *mc_list_config, + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + pmo_core_fill_mc_list(&vdev_ctx, mc_list_config); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS pmo_core_flush_mc_addr_list_from_vdev_priv( + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_zero(&vdev_ctx->vdev_mc_list_req, + sizeof(vdev_ctx->vdev_mc_list_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + pmo_tgt_send_enhance_multicast_offload_req(vdev, true); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +exit_with_status: + + return status; +} + +QDF_STATUS pmo_core_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + pmo_tgt_send_enhance_multicast_offload_req(vdev, false); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +exit_with_status: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_set_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list) +{ + int i; + + if (pmo_tgt_get_multiple_mc_filter_support(vdev)) { + pmo_debug("FW supports multiple mcast filter"); + pmo_tgt_set_multiple_mc_filter_req(vdev, mc_list); + } else { + pmo_debug("FW does not support multiple mcast filter"); + for (i = 0; i < mc_list->mc_cnt; i++) + pmo_tgt_set_mc_filter_req(vdev, mc_list->mc_addr[i]); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_clear_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list) +{ + int i; + + if (pmo_tgt_get_multiple_mc_filter_support(vdev)) { + pmo_debug("FW supports multiple mcast filter"); + pmo_tgt_clear_multiple_mc_filter_req(vdev, mc_list); + } else { + pmo_debug("FW does not support multiple mcast filter"); + for (i = 0; i < mc_list->mc_cnt; i++) + pmo_tgt_clear_mc_filter_req(vdev, mc_list->mc_addr[i]); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS pmo_core_do_enable_mc_addr_list(struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx, + struct pmo_mc_addr_list *op_mc_list_req) +{ + QDF_STATUS status; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (!vdev_ctx->vdev_mc_list_req.mc_cnt) { + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + pmo_err("mc_cnt is zero so skip to add mc list"); + status = QDF_STATUS_E_INVAL; + goto out; + } + qdf_mem_copy(op_mc_list_req, &vdev_ctx->vdev_mc_list_req, + sizeof(*op_mc_list_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + status = pmo_core_set_mc_filter_req(vdev, op_mc_list_req); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("cannot apply mc filter request"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->vdev_mc_list_req.is_filter_applied = true; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +out: + + return status; +} + +static QDF_STATUS pmo_core_do_disable_mc_addr_list( + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx, + struct pmo_mc_addr_list *op_mc_list_req) +{ + QDF_STATUS status; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + /* validate filter is applied before clearing in fwr */ + if (!vdev_ctx->vdev_mc_list_req.is_filter_applied) { + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + pmo_debug("mc filter is not applied in fwr"); + status = QDF_STATUS_E_INVAL; + goto out; + } + qdf_mem_copy(op_mc_list_req, &vdev_ctx->vdev_mc_list_req, + sizeof(*op_mc_list_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + status = pmo_core_clear_mc_filter_req(vdev, op_mc_list_req); + if (status != QDF_STATUS_SUCCESS) { + pmo_debug("cannot apply mc filter request"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->vdev_mc_list_req.is_filter_applied = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +out: + + return status; +} + +uint8_t pmo_core_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + return PMO_MAX_MC_ADDR_LIST; +} + +int pmo_core_get_mc_addr_list_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct pmo_vdev_priv_obj *vdev_ctx; + uint8_t mc_cnt; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + return PMO_INVALID_MC_ADDR_COUNT; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + mc_cnt = vdev_ctx->vdev_mc_list_req.mc_cnt; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + + return mc_cnt; +} + +void pmo_core_set_mc_addr_list_count(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t count) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + return; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->vdev_mc_list_req.mc_cnt = count; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +} + +static QDF_STATUS pmo_core_mc_addr_flitering_sanity( + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + if (!vdev) { + pmo_err("vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + + /* Check if INI is enabled or not, otherwise just return */ + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.enable_mc_list) { + pmo_debug("user disabled mc_addr_list using INI"); + return QDF_STATUS_E_INVAL; + } + + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for mc addr filtering %d", + pmo_get_vdev_opmode(vdev)); + return QDF_STATUS_E_INVAL; + } + + if (vdev_ctx->vdev_mc_list_req.mc_cnt > PMO_MAX_MC_ADDR_LIST) { + pmo_debug("Passed more than max supported MC address count :%d", + vdev_ctx->vdev_mc_list_req.mc_cnt); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} +QDF_STATUS pmo_core_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!mc_list_config->psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mc_list_config->psoc, + mc_list_config->vdev_id, + WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_core_mc_addr_flitering_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + pmo_debug("Cache mc addr list for vdev id: %d psoc: %pK", + mc_list_config->vdev_id, mc_list_config->psoc); + + status = pmo_core_cache_mc_addr_list_in_vdev_priv(mc_list_config, vdev); + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS pmo_core_flush_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_core_mc_addr_flitering_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + pmo_debug("Flush mc addr list for vdev id: %d psoc: %pK", + vdev_id, psoc); + + status = pmo_core_flush_mc_addr_list_from_vdev_priv(vdev); + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +static QDF_STATUS pmo_core_handle_enable_mc_list_trigger( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_mc_addr_list *op_mc_list_req; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + op_mc_list_req = qdf_mem_malloc(sizeof(*op_mc_list_req)); + if (!op_mc_list_req) { + status = QDF_STATUS_E_NOMEM; + goto exit_with_status; + } + + switch (trigger) { + case pmo_mc_list_change_notify: + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is disabled, skip in mode %d", + trigger); + goto free_req; + } + status = pmo_core_do_enable_mc_addr_list(vdev, vdev_ctx, + op_mc_list_req); + break; + case pmo_apps_suspend: + if (vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is enabled, skip in mode %d", + trigger); + goto free_req; + } + status = pmo_core_do_enable_mc_addr_list(vdev, vdev_ctx, + op_mc_list_req); + break; + default: + status = QDF_STATUS_E_INVAL; + pmo_err("invalid pmo trigger for enable mc list"); + break; + } + +free_req: + qdf_mem_free(op_mc_list_req); + +exit_with_status: + + return status; +} + +QDF_STATUS pmo_core_enable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto put_psoc; + } + + status = pmo_core_mc_addr_flitering_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto put_vdev; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) { + status = QDF_STATUS_E_INVAL; + goto put_vdev; + } + + pmo_debug("enable mclist trigger: %d", trigger); + status = pmo_core_handle_enable_mc_list_trigger(vdev, trigger); + +put_vdev: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +put_psoc: + pmo_psoc_put_ref(psoc); + +exit_with_status: + + return status; +} + +static QDF_STATUS pmo_core_handle_disable_mc_list_trigger( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_mc_addr_list *op_mc_list_req; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + op_mc_list_req = qdf_mem_malloc(sizeof(*op_mc_list_req)); + if (!op_mc_list_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + switch (trigger) { + case pmo_peer_disconnect: + case pmo_mc_list_change_notify: + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is disabled, skip in mode %d", + trigger); + goto free_req; + } + status = pmo_core_do_disable_mc_addr_list(vdev, vdev_ctx, + op_mc_list_req); + break; + case pmo_apps_resume: + if (vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is enabled, skip in mode %d", + trigger); + goto free_req; + } + status = pmo_core_do_disable_mc_addr_list(vdev, vdev_ctx, + op_mc_list_req); + break; + default: + status = QDF_STATUS_E_INVAL; + pmo_err("invalid pmo trigger for disable mc list"); + break; + } + +free_req: + qdf_mem_free(op_mc_list_req); + +out: + return status; +} + +QDF_STATUS pmo_core_disable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_core_mc_addr_flitering_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto put_ref; + + pmo_debug("disable mclist trigger: %d", trigger); + + status = pmo_core_handle_disable_mc_list_trigger(vdev, trigger); + +put_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +out: + + return status; +} + +QDF_STATUS +pmo_core_get_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct pmo_mc_addr_list *mc_list_req) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + + if (!mc_list_req) + return QDF_STATUS_E_INVAL; + + qdf_mem_zero(mc_list_req, sizeof(*mc_list_req)); + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto exit_with_status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto put_psoc; + } + + status = pmo_core_mc_addr_flitering_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto put_vdev; + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + *mc_list_req = vdev_ctx->vdev_mc_list_req; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +put_vdev: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +put_psoc: + pmo_psoc_put_ref(psoc); + +exit_with_status: + pmo_exit(); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_ns.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_ns.c new file mode 100644 index 0000000000..b7436402aa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_ns.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements ns offload feature API's + */ + +#include "wlan_pmo_ns.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +static void pmo_core_fill_ns_addr(struct pmo_ns_offload_params *request, + struct pmo_ns_req *ns_req) +{ + int i; + + for (i = 0; i < ns_req->count; i++) { + /* + * Filling up the request structure + * Filling the selfIPv6Addr with solicited address + * A Solicited-Node multicast address is created by + * taking the last 24 bits of a unicast or anycast + * address and appending them to the prefix + * + * FF02:0000:0000:0000:0000:0001:FFXX:XXXX + * + * here XX is the unicast/anycast bits + */ + request->self_ipv6_addr[i][0] = 0xFF; + request->self_ipv6_addr[i][1] = 0x02; + request->self_ipv6_addr[i][11] = 0x01; + request->self_ipv6_addr[i][12] = 0xFF; + request->self_ipv6_addr[i][13] = + ns_req->ipv6_addr[i][13]; + request->self_ipv6_addr[i][14] = + ns_req->ipv6_addr[i][14]; + request->self_ipv6_addr[i][15] = + ns_req->ipv6_addr[i][15]; + request->slot_idx = i; + qdf_mem_copy(&request->target_ipv6_addr[i], + &ns_req->ipv6_addr[i][0], QDF_IPV6_ADDR_SIZE); + + request->target_ipv6_addr_valid[i] = + PMO_IPV6_ADDR_VALID; + request->target_ipv6_addr_ac_type[i] = + ns_req->ipv6_addr_type[i]; + + request->scope[i] = ns_req->scope[i]; + + pmo_debug("NSoffload solicitIp: %pI6 targetIp: %pI6 Index: %d", + &request->self_ipv6_addr[i], + &request->target_ipv6_addr[i], i); + } +} + +static QDF_STATUS pmo_core_cache_ns_in_vdev_priv( + struct pmo_ns_req *ns_req, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_ns_offload_params *request; + struct wlan_objmgr_peer *peer; + uint8_t *self_addr, *peer_addr; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + request = qdf_mem_malloc(sizeof(*request)); + if (!request) { + pmo_err("malloc failed for offload params"); + return QDF_STATUS_E_NOMEM; + } + + pmo_core_fill_ns_addr(request, ns_req); + + request->enable = PMO_OFFLOAD_ENABLE; + request->is_offload_applied = false; + + /* set number of ns offload address count */ + request->num_ns_offload_count = ns_req->count; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_PMO_ID); + if (!peer) { + pmo_err("peer is null"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + self_addr = wlan_vdev_mlme_get_mldaddr(vdev); + peer_addr = wlan_peer_mlme_get_mldaddr(peer); + } else { + self_addr = wlan_vdev_mlme_get_macaddr(vdev); + peer_addr = wlan_peer_get_macaddr(peer); + } + + pmo_debug("vdev self mac addr: "QDF_MAC_ADDR_FMT" bss peer mac addr: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(self_addr), + QDF_MAC_ADDR_REF(peer_addr)); + + qdf_mem_copy(&request->self_macaddr.bytes, self_addr, + QDF_MAC_ADDR_SIZE); + /* get peer and peer mac accdress aka ap mac address */ + qdf_mem_copy(&request->bssid, peer_addr, + QDF_MAC_ADDR_SIZE); + wlan_objmgr_peer_release_ref(peer, WLAN_PMO_ID); + /* cache ns request */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(&vdev_ctx->vdev_ns_req, request, + sizeof(vdev_ctx->vdev_ns_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); +out: + qdf_mem_free(request); + return status; +} + +static QDF_STATUS pmo_core_flush_ns_from_vdev_priv( + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + /* clear ns request */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_zero(&vdev_ctx->vdev_ns_req, sizeof(vdev_ctx->vdev_ns_req)); + vdev_ctx->vdev_ns_req.enable = PMO_OFFLOAD_DISABLE; + vdev_ctx->vdev_ns_req.is_offload_applied = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_exit(); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS pmo_core_do_enable_ns_offload(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, enum pmo_offload_trigger trigger) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_psoc_priv_obj *psoc_ctx; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + if (!psoc_ctx) { + pmo_err("psoc_ctx is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + switch (trigger) { + case pmo_ipv6_change_notify: + case pmo_ns_offload_dynamic_update: + if (!psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is disabled, skip in mode:%d", + trigger); + goto out; + } + /* enable arp when active offload is true (ipv6 notifier) */ + status = pmo_tgt_enable_ns_offload_req(vdev, vdev_id); + break; + case pmo_apps_suspend: + case pmo_arp_ns_offload_dynamic_update: + /* enable arp when active offload is false (apps suspend) */ + status = pmo_tgt_enable_ns_offload_req(vdev, vdev_id); + break; + default: + status = QDF_STATUS_E_INVAL; + pmo_err("invalid pmo trigger"); + break; + } +out: + + return status; +} + +static QDF_STATUS pmo_core_do_disable_ns_offload(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, enum pmo_offload_trigger trigger) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_psoc_priv_obj *psoc_ctx; + + pmo_enter(); + + psoc_ctx = pmo_vdev_get_psoc_priv(vdev); + + switch (trigger) { + case pmo_ipv6_change_notify: + case pmo_ns_offload_dynamic_update: + if (!psoc_ctx->psoc_cfg.active_mode_offload) { + pmo_debug("active offload is disabled, skip in mode:%d", + trigger); + goto out; + } + /* config ns when active offload is enable */ + status = pmo_tgt_disable_ns_offload_req(vdev, vdev_id); + break; + case pmo_apps_resume: + case pmo_arp_ns_offload_dynamic_update: + status = pmo_tgt_disable_ns_offload_req(vdev, vdev_id); + break; + default: + status = QDF_STATUS_E_INVAL; + pmo_err("invalid pmo trigger"); + break; + } +out: + pmo_exit(); + + return status; +} + + +static QDF_STATUS pmo_core_ns_offload_sanity(struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_static) { + pmo_debug("ns offload statically disable"); + return QDF_STATUS_E_INVAL; + } + + if (!pmo_core_is_vdev_supports_offload(vdev)) { + pmo_debug("vdev in invalid opmode for ns offload %d", + pmo_get_vdev_opmode(vdev)); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_ns_check_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pmo_psoc_priv_obj *psoc_ctx; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_vdev *vdev; + bool active_offload_cond, is_applied_cond; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + opmode = pmo_get_vdev_opmode(vdev); + if (opmode == QDF_NDI_MODE) { + pmo_debug("NS offload not supported in NaN mode"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + pmo_debug("NS offload not supported for MLO partner link " + "with vdev_id[%d]", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + + if (trigger == pmo_apps_suspend || trigger == pmo_apps_resume) { + active_offload_cond = psoc_ctx->psoc_cfg.active_mode_offload; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + is_applied_cond = vdev_ctx->vdev_ns_req.enable && + vdev_ctx->vdev_ns_req.is_offload_applied; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + if (active_offload_cond && is_applied_cond) { + pmo_debug("active offload is enabled and offload already sent"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + return status; +} + +QDF_STATUS pmo_core_cache_ns_offload_req(struct pmo_ns_req *ns_req) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + if (!ns_req) { + pmo_err("ns is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + if (!ns_req->psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(ns_req->psoc, + ns_req->vdev_id, + WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_core_ns_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + if (ns_req->count == 0) { + pmo_debug("skip ns offload caching as ns count is 0"); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + + status = pmo_core_cache_ns_in_vdev_priv(ns_req, vdev); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS pmo_core_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + uint8_t vdev_id; + + pmo_enter(); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + status = pmo_core_ns_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("Flush ns offload on vdev id: %d vdev: %pK", vdev_id, vdev); + + status = pmo_core_flush_ns_from_vdev_priv(vdev); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *pmo_psoc_ctx; + uint8_t vdev_id; + + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + pmo_psoc_ctx = vdev_ctx->pmo_psoc_ctx; + + status = pmo_core_ns_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + if (trigger == pmo_ns_offload_dynamic_update) { + /* + * user enable ns offload using ioctl/vendor cmd dynamically. + */ + pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic = true; + goto skip_ns_dynamic_check; + } + + if (!pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) { + pmo_debug("ns offload dynamically disable"); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + +skip_ns_dynamic_check: + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (vdev_ctx->vdev_ns_req.num_ns_offload_count == 0) { + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + pmo_debug("skip ns offload enable as ns count is 0"); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("Enable ns offload in fwr vdev id: %d vdev: %pK trigger: %d", + vdev_id, vdev, trigger); + status = pmo_core_do_enable_ns_offload(vdev, vdev_id, trigger); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + + return status; +} + +QDF_STATUS pmo_core_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + uint8_t vdev_id; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *pmo_psoc_ctx; + + pmo_enter(); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + pmo_psoc_ctx = vdev_ctx->pmo_psoc_ctx; + + status = pmo_core_ns_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + if (trigger == pmo_ns_offload_dynamic_update) { + /* + * user disable ns offload using ioctl/vendor cmd dynamically. + */ + if (!pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) { + /* Already disabled, skip to end */ + status = QDF_STATUS_SUCCESS; + goto dec_ref; + } + + pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic = false; + goto skip_ns_dynamic_check; + } + + if (!pmo_psoc_ctx->psoc_cfg.ns_offload_enable_dynamic) { + pmo_debug("ns offload dynamically disable"); + status = QDF_STATUS_E_INVAL; + goto dec_ref; + } + +skip_ns_dynamic_check: + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("disable ns offload in fwr vdev id: %d vdev: %pK trigger: %d", + vdev_id, vdev, trigger); + + status = pmo_core_do_disable_ns_offload(vdev, vdev_id, trigger); +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS +pmo_core_get_ns_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ns_offload_params *params) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + + if (!params) + return QDF_STATUS_E_INVAL; + + qdf_mem_zero(params, sizeof(*params)); + + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + status = pmo_core_ns_offload_sanity(vdev); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + *params = vdev_ctx->vdev_ns_req; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_pkt_filter.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_pkt_filter.c new file mode 100644 index 0000000000..2624c5cabf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_pkt_filter.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implements Packet filter feature API's + */ + +#include "wlan_pmo_pkt_filter.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +#define PMO_PKT_FILTERS_DEFAULT 12 +#define PMO_PKT_FILTERS_DISABLED 0xffffffff + +uint32_t pmo_get_num_packet_filters(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + bool pkt_filter = false; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + pkt_filter = pmo_intersect_packet_filter(psoc_ctx); + } + + return pkt_filter ? PMO_PKT_FILTERS_DEFAULT : PMO_PKT_FILTERS_DISABLED; +} + +QDF_STATUS pmo_core_set_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + pmo_enter(); + + if (!psoc) { + pmo_err("psoc is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tgt_set_pkt_filter(vdev, pmo_set_pkt_fltr_req, vdev_id); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; + +} + +QDF_STATUS pmo_core_clear_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + pmo_enter(); + + if (!psoc) { + pmo_err("psoc is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tgt_clear_pkt_filter(vdev, pmo_clr_pkt_fltr_param, + vdev_id); + if (status != QDF_STATUS_SUCCESS) + goto dec_ref; + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; + +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_static_config.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_static_config.c new file mode 100644 index 0000000000..072c8cb5e4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_static_config.c @@ -0,0 +1,552 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implements static configuration on vdev attach + */ + +#include "wlan_pmo_static_config.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_wow.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +static const uint8_t arp_ptrn[] = {0x08, 0x06}; +static const uint8_t arp_mask[] = {0xff, 0xff}; +static const uint8_t ns_ptrn[] = {0x86, 0xDD}; +static const uint8_t discvr_ptrn[] = {0xe0, 0x00, 0x00, 0xf8}; +static const uint8_t discvr_mask[] = {0xf0, 0x00, 0x00, 0xf8}; +static const uint8_t arp_offset = 12; + +void pmo_register_wow_wakeup_events(struct wlan_objmgr_vdev *vdev) +{ + uint32_t event_bitmap[PMO_WOW_MAX_EVENT_BM_LEN] = {0}; + uint8_t vdev_id; + enum QDF_OPMODE vdev_opmode; + struct pmo_psoc_priv_obj *psoc_ctx; + pmo_is_device_in_low_pwr_mode is_low_pwr_mode; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_opmode = pmo_get_vdev_opmode(vdev); + vdev_id = pmo_vdev_get_id(vdev); + pmo_debug("vdev_opmode %d vdev_id %d", vdev_opmode, vdev_id); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + switch (vdev_opmode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + /* set power on failure event only for STA and P2P_CLI mode*/ + psoc_ctx = pmo_vdev_get_psoc_priv(vdev); + if (psoc_ctx->psoc_cfg.auto_power_save_fail_mode == + PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE){ + qdf_spin_lock(&psoc_ctx->lock); + is_low_pwr_mode = psoc_ctx->is_device_in_low_pwr_mode; + qdf_spin_unlock(&psoc_ctx->lock); + if (is_low_pwr_mode && is_low_pwr_mode(vdev_id)) + pmo_set_wow_event_bitmap( + WOW_CHIP_POWER_FAILURE_DETECT_EVENT, + PMO_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + } + + fallthrough; + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_MONITOR_MODE: + pmo_set_sta_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + if (vdev_ctx->magic_ptrn_enable) + pmo_set_wow_event_bitmap(WOW_MAGIC_PKT_RECVD_EVENT, + PMO_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + break; + + case QDF_IBSS_MODE: + pmo_set_sta_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + if (vdev_ctx->magic_ptrn_enable) + pmo_set_wow_event_bitmap(WOW_MAGIC_PKT_RECVD_EVENT, + PMO_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + pmo_set_wow_event_bitmap(WOW_BEACON_EVENT, + PMO_WOW_MAX_EVENT_BM_LEN, + event_bitmap); + break; + + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + pmo_set_sap_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + break; + + case QDF_NDI_MODE: + pmo_set_ndp_wow_bitmask(event_bitmap, PMO_WOW_MAX_EVENT_BM_LEN); + break; + + default: + pmo_err("Skipping wake event configuration for vdev_opmode %d", + vdev_opmode); + return; + } + + pmo_tgt_enable_wow_wakeup_event(vdev, event_bitmap); +} + +/** + * pmo_configure_wow_ap() - set WOW patterns in ap mode + * @vdev: objmgr vdev handle + * + * Configures default WOW pattern for the given vdev_id which is in AP mode. + * + * Return: QDF status + */ +static QDF_STATUS pmo_configure_wow_ap(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS ret; + uint8_t mac_mask[QDF_MAC_ADDR_SIZE]; + struct pmo_vdev_priv_obj *vdev_ctx; + struct qdf_mac_addr bridgeaddr; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + /* + * Setup unicast pkt pattern + * WoW pattern id should be unique for each vdev + * WoW pattern id can be same on 2 different VDEVs + */ + qdf_mem_set(&mac_mask, QDF_MAC_ADDR_SIZE, 0xFF); + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE, 0, mac_mask, + QDF_MAC_ADDR_SIZE, false); + if (ret != QDF_STATUS_SUCCESS) { + pmo_err("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + /* Setup Bridge MAC address */ + pmo_get_vdev_bridge_addr(vdev, &bridgeaddr); + if (!qdf_is_macaddr_zero(&bridgeaddr)) { + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + bridgeaddr.bytes, QDF_MAC_ADDR_SIZE, 0, mac_mask, + QDF_MAC_ADDR_SIZE, false); + if (ret != QDF_STATUS_SUCCESS) { + pmo_err("Failed to add Bridge MAC address"); + return ret; + } + } + + /* Setup ARP pkt pattern */ + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + arp_ptrn, sizeof(arp_ptrn), arp_offset, arp_mask, + sizeof(arp_mask), false); + if (ret != QDF_STATUS_SUCCESS) { + pmo_err("Failed to add WOW ARP pattern"); + return ret; + } + + return ret; +} + +/** + * pmo_configure_mc_ssdp() - API to configure SSDP address as MC list + * @vdev: objmgr vdev handle. + * + * SSDP address 239.255.255.250 is converted to Multicast Mac address + * and configure it to FW. Firmware will apply this pattern on the incoming + * packets to filter them out during chatter/wow mode. + * + * Return: Success/Failure + */ +static QDF_STATUS pmo_configure_mc_ssdp( + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + const uint8_t ssdp_addr[QDF_MAC_ADDR_SIZE] = { + 0x01, 0x00, 0x5e, 0x7f, 0xff, 0xfa }; + struct qdf_mac_addr multicast_addr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + psoc = pmo_vdev_get_psoc(vdev); + + qdf_mem_copy(&multicast_addr.bytes, &ssdp_addr, QDF_MAC_ADDR_SIZE); + status = pmo_tgt_set_mc_filter_req(vdev, + multicast_addr); + if (status != QDF_STATUS_SUCCESS) + pmo_err("unable to set ssdp as mc addr list filter"); + + return status; +} + +/** + * pmo_configure_wow_ssdp() - API to configure WoW SSDP + *@vdev: objmgr vdev handle + * + * API to configure SSDP pattern as WoW pattern + * + * Return: Success/Failure + */ +static QDF_STATUS pmo_configure_wow_ssdp( + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t discvr_offset = 30; + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + /* + * WoW pattern ID should be unique for each vdev + * Different WoW patterns can use same pattern ID + */ + status = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + discvr_ptrn, sizeof(discvr_ptrn), discvr_offset, + discvr_mask, sizeof(discvr_ptrn), false); + + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add WOW mDNS/SSDP/LLMNR pattern"); + + return status; +} + +/** + * pmo_configure_ssdp() - API to Configure SSDP pattern to FW + *@vdev: objmgr vdev handle + * + * Setup multicast pattern for mDNS 224.0.0.251, SSDP 239.255.255.250 and LLMNR + * 224.0.0.252 + * + * Return: Success/Failure. + */ +static QDF_STATUS pmo_configure_ssdp(struct wlan_objmgr_vdev *vdev) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ssdp) { + pmo_debug("mDNS, SSDP, LLMNR patterns are disabled from ini"); + return QDF_STATUS_SUCCESS; + } + + pmo_debug("enable_mc_list:%d", + vdev_ctx->pmo_psoc_ctx->psoc_cfg.enable_mc_list); + + if (vdev_ctx->pmo_psoc_ctx->psoc_cfg.enable_mc_list) + return pmo_configure_mc_ssdp(vdev); + + return pmo_configure_wow_ssdp(vdev); +} + +/** + * pmo_configure_wow_sta() - set WOW patterns in sta mode + * @vdev: objmgr vdev handle + * + * Configures default WOW pattern for the given vdev_id which is in sta mode. + * + * Return: QDF status + */ +static QDF_STATUS pmo_configure_wow_sta(struct wlan_objmgr_vdev *vdev) +{ + uint8_t mac_mask[QDF_MAC_ADDR_SIZE]; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct pmo_vdev_priv_obj *vdev_ctx; + struct qdf_mac_addr *ucast_addr; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + qdf_mem_set(&mac_mask, QDF_MAC_ADDR_SIZE, 0xFF); + /* + * Set up unicast wow pattern + * WoW pattern ID should be unique for each vdev + * Different WoW patterns can use same pattern ID + */ + + /* On ML VDEV, configure WoW pattern with MLD address only */ + ucast_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + if (qdf_is_macaddr_zero(ucast_addr)) { + ucast_addr = + (struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev); + } + + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn(vdev_ctx), + (uint8_t *)ucast_addr, QDF_MAC_ADDR_SIZE, 0, + mac_mask, QDF_MAC_ADDR_SIZE, false); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_err("Failed to add WOW unicast pattern ret %d", ret); + return ret; + } + + ret = pmo_configure_ssdp(vdev); + if (ret != QDF_STATUS_SUCCESS) + pmo_err("Failed to configure SSDP patterns to FW"); + + /* + * when arp offload or ns offloaded is disabled + * or active offload is disabled from ini file, + * configure broad cast arp pattern to fw, so + * that host can wake up + */ + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.arp_offload_enable || + !vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) { + /* Setup all ARP pkt pattern */ + pmo_debug("ARP offload is disabled in INI enable WoW for ARP"); + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn( + vdev_ctx), + arp_ptrn, sizeof(arp_ptrn), arp_offset, + arp_mask, sizeof(arp_mask), false); + if (ret != QDF_STATUS_SUCCESS) { + pmo_err("Failed to add WOW ARP pattern"); + return ret; + } + } + /* for NS or NDP offload packets */ + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.ns_offload_enable_static || + !vdev_ctx->pmo_psoc_ctx->psoc_cfg.active_mode_offload) { + /* Setup all NS pkt pattern */ + pmo_debug("NS offload is disabled in INI enable WoW for NS"); + ret = pmo_tgt_send_wow_patterns_to_fw(vdev, + pmo_get_and_increment_wow_default_ptrn( + vdev_ctx), + ns_ptrn, sizeof(arp_ptrn), arp_offset, + arp_mask, sizeof(arp_mask), false); + if (ret != QDF_STATUS_SUCCESS) { + pmo_err("Failed to add WOW NS pattern"); + return ret; + } + } + + return ret; +} + +void pmo_register_wow_default_patterns(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE vdev_opmode = QDF_MAX_NO_OF_MODE; + struct pmo_vdev_priv_obj *vdev_ctx; + uint8_t vdev_id; + struct pmo_psoc_priv_obj *psoc_ctx; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + vdev_id = pmo_vdev_get_id(vdev); + if (vdev_id > WLAN_UMAC_PSOC_MAX_VDEVS) { + pmo_err("Invalid vdev id %d", vdev_id); + return; + } + + vdev_opmode = pmo_get_vdev_opmode(vdev); + if (vdev_opmode == QDF_MAX_NO_OF_MODE) { + pmo_err("Invalid vdev opmode %d", vdev_id); + return; + } + + if (!vdev_ctx->ptrn_match_enable) { + pmo_err("ptrn_match is disable for vdev %d", vdev_id); + return; + } + + if (pmo_is_vdev_in_beaconning_mode(vdev_opmode)) { + /* Configure SAP/GO/IBSS mode default wow patterns */ + pmo_debug("Config SAP default wow patterns vdev_id %d", + vdev_id); + pmo_configure_wow_ap(vdev); + } else { + /* Configure STA/P2P CLI mode default wow patterns */ + pmo_debug("Config STA default wow patterns vdev_id %d", + vdev_id); + pmo_configure_wow_sta(vdev); + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + if (!psoc_ctx) { + pmo_err("PMO PSOC Context is NULL!"); + return; + } + + /* + * No need for configuring RA filter while APF is enabled, since + * APF internally handles RA filtering. + */ + if (psoc_ctx->psoc_cfg.ra_ratelimit_enable && + !pmo_intersect_apf(psoc_ctx)) { + pmo_debug("Config STA RA wow pattern vdev_id %d", + vdev_id); + pmo_tgt_send_ra_filter_req(vdev); + } + } + +} + +#ifdef CONFIG_LITHIUM +static void +set_action_id_drop_pattern_for_block_ack(uint32_t *action_category_map) +{ + action_category_map[0] |= 1 << PMO_MAC_ACTION_BLKACK; +} +#else +static inline void +set_action_id_drop_pattern_for_block_ack(uint32_t *action_category_map) +{ +} +#endif + +/** + * set_action_id_drop_pattern_for_spec_mgmt() - Set action id of action + * frames for spectrum mgmt frames to be dropped in fw. + * + * @action_id_per_category: Pointer to action id bitmaps. + */ +static void set_action_id_drop_pattern_for_spec_mgmt( + uint32_t *action_id_per_category) +{ + action_id_per_category[PMO_MAC_ACTION_SPECTRUM_MGMT] + = DROP_SPEC_MGMT_ACTION_FRAME_BITMAP; +} + +/** + * set_action_id_drop_pattern_for_public_action() - Set action id of action + * frames for public action frames to be dropped in fw. + * + * @action_id_per_category: Pointer to action id bitmaps. + */ +static void set_action_id_drop_pattern_for_public_action( + uint32_t *action_id_per_category) +{ + action_id_per_category[PMO_MAC_ACTION_PUBLIC_USAGE] + = DROP_PUBLIC_ACTION_FRAME_BITMAP; +} + +#define PMO_MAX_WAKE_PATTERN_LEN 350 + +/* Considering 4 char for i and 10 char for action wakeup pattern and + * 2 char for brackets, 2 char for 0x and 1 for space and 1 to end string + */ +#define PMO_MAX_SINGLE_WAKE_PATTERN_LEN 20 + +QDF_STATUS +pmo_register_action_frame_patterns(struct wlan_objmgr_vdev *vdev, + enum qdf_suspend_type suspend_type) +{ + struct pmo_action_wakeup_set_params *cmd; + int i = 0; + uint8_t *info; + uint32_t len = 0; + int ret; + + QDF_STATUS status = QDF_STATUS_SUCCESS; + + cmd = qdf_mem_malloc(sizeof(*cmd)); + if (!cmd) { + pmo_err("memory allocation failed for wakeup set params"); + return QDF_STATUS_E_NOMEM; + } + + cmd->vdev_id = pmo_vdev_get_id(vdev); + cmd->operation = pmo_action_wakeup_set; + + if (suspend_type == QDF_SYSTEM_SUSPEND) + cmd->action_category_map[i++] = + SYSTEM_SUSPEND_ALLOWED_ACTION_FRAMES_BITMAP0; + else + cmd->action_category_map[i++] = + RUNTIME_PM_ALLOWED_ACTION_FRAMES_BITMAP0; + + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP1; + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP2; + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP3; + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP4; + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP5; + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP6; + cmd->action_category_map[i++] = ALLOWED_ACTION_FRAMES_BITMAP7; + + set_action_id_drop_pattern_for_spec_mgmt(cmd->action_per_category); + set_action_id_drop_pattern_for_public_action(cmd->action_per_category); + set_action_id_drop_pattern_for_block_ack(&cmd->action_category_map[0]); + + info = qdf_mem_malloc(PMO_MAX_WAKE_PATTERN_LEN); + if (!info) { + qdf_mem_free(cmd); + return -ENOMEM; + } + + for (i = 0; i < PMO_SUPPORTED_ACTION_CATE_ELE_LIST; i++) { + if (i < ALLOWED_ACTION_FRAME_MAP_WORDS) { + ret = qdf_scnprintf(info + len, + PMO_MAX_WAKE_PATTERN_LEN - len, + " %d[0x%x]", i, cmd->action_category_map[i]); + if (ret <= 0) + break; + len += ret; + + if (len >= (PMO_MAX_WAKE_PATTERN_LEN - + PMO_MAX_SINGLE_WAKE_PATTERN_LEN)) { + pmo_nofl_debug("serial_num[action wakeup pattern in fw]:%s", + info); + len = 0; + } + } else { + cmd->action_category_map[i] = 0; + } + } + + if (len > 0) + pmo_nofl_debug("serial_num[action wakeup pattern in fw]:%s", + info); + pmo_debug("Spectrum mgmt action id drop bitmap: 0x%x, Public action id drop bitmap: 0x%x", + cmd->action_per_category[PMO_MAC_ACTION_SPECTRUM_MGMT], + cmd->action_per_category[PMO_MAC_ACTION_PUBLIC_USAGE]); + + /* config action frame patterns */ + status = pmo_tgt_send_action_frame_pattern_req(vdev, cmd); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to config wow action frame map, ret %d", + status); + + qdf_mem_free(cmd); + qdf_mem_free(info); + + return status; +} + +QDF_STATUS +pmo_clear_action_frame_patterns(struct wlan_objmgr_vdev *vdev) +{ + struct pmo_action_wakeup_set_params *cmd; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + cmd = qdf_mem_malloc(sizeof(*cmd)); + if (!cmd) { + pmo_err("memory allocation failed for wakeup set params"); + return QDF_STATUS_E_NOMEM; + } + + cmd->vdev_id = pmo_vdev_get_id(vdev); + cmd->operation = pmo_action_wakeup_reset; + + /* clear action frame pattern */ + status = pmo_tgt_send_action_frame_pattern_req(vdev, cmd); + if (QDF_IS_STATUS_ERROR(status)) + pmo_err("Failed to clear wow action frame map, ret %d", + status); + + qdf_mem_free(cmd); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c new file mode 100644 index 0000000000..0e3c6804a1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_suspend_resume.c @@ -0,0 +1,2017 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Define API's for suspend / resume handling + */ + +#include "wlan_pmo_wow.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_lphb.h" +#include "wlan_pmo_hw_filter.h" +#include "wlan_pmo_suspend_resume.h" +#include "cdp_txrx_ops.h" +#include "cdp_txrx_misc.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "hif.h" +#include "htc_api.h" +#include "wlan_pmo_obj_mgmt_api.h" +#include +#include +#include "cds_api.h" +#include "wlan_pmo_static_config.h" +#include "wlan_mlme_ucfg_api.h" +#include "cfg_mlme_sap.h" +#include "cfg_ucfg_api.h" +#include "cdp_txrx_bus.h" +#include "wlan_pmo_ucfg_api.h" +#include "hif.h" +#include "target_type.h" + +/** + * pmo_core_get_vdev_dtim_period() - Get vdev dtim period + * @vdev: objmgr vdev handle + * + * Return: Vdev dtim period + */ +static uint8_t pmo_core_get_vdev_dtim_period(struct wlan_objmgr_vdev *vdev) +{ + uint8_t dtim_period = 0; + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + if (psoc_ctx->get_dtim_period) + ret = psoc_ctx->get_dtim_period(pmo_vdev_get_id(vdev), + &dtim_period); + } + + if (QDF_IS_STATUS_ERROR(ret)) + pmo_err("Failed to get to dtim period for vdevId %d", + pmo_vdev_get_id(vdev)); + + return dtim_period; +} + +/** + * pmo_core_get_vdev_beacon_interval() - Get vdev beacon interval + * @vdev: objmgr vdev handle + * + * Return: Vdev beacon interval + */ +static uint16_t pmo_core_get_vdev_beacon_interval(struct wlan_objmgr_vdev *vdev) +{ + uint16_t beacon_interval = 0; + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + if (psoc_ctx->get_beacon_interval) + ret = psoc_ctx->get_beacon_interval( + pmo_vdev_get_id(vdev), + &beacon_interval); + } + + if (QDF_IS_STATUS_ERROR(ret)) + pmo_err("Failed to get beacon interval for vdev id %d", + pmo_vdev_get_id(vdev)); + + return beacon_interval; +} + +/** + * pmo_core_calculate_listen_interval() - Calculate vdev listen interval + * @vdev: objmgr vdev handle + * @vdev_ctx: pmo vdev priv ctx + * @listen_interval: listen interval which is computed for vdev + * + * Return: QDF_STATUS + */ +static QDF_STATUS pmo_core_calculate_listen_interval( + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx, + uint32_t *listen_interval) +{ + uint32_t max_mod_dtim, max_dtim = 0; + uint32_t beacon_interval_mod; + struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (psoc_cfg->sta_dynamic_dtim) { + *listen_interval = psoc_cfg->sta_dynamic_dtim; + } else if ((psoc_cfg->sta_mod_dtim) && + (psoc_cfg->sta_max_li_mod_dtim)) { + /* + * When the system is in suspend + * (maximum beacon will be at 1s == 10) + * If maxModulatedDTIM ((MAX_LI_VAL = 10) / AP_DTIM) + * equal or larger than MDTIM + * (configured in WCNSS_qcom_cfg.ini) + * Set LI to MDTIM * AP_DTIM + * If Dtim = 2 and Mdtim = 2 then LI is 4 + * Else + * Set LI to maxModulatedDTIM * AP_DTIM + */ + beacon_interval_mod = + pmo_core_get_vdev_beacon_interval(vdev) / 100; + if (beacon_interval_mod == 0) + beacon_interval_mod = 1; + + max_dtim = pmo_core_get_vdev_dtim_period(vdev) * + beacon_interval_mod; + + if (!max_dtim) { + pmo_err("Invalid dtim period"); + return QDF_STATUS_E_INVAL; + } + + max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim / max_dtim; + + if (max_mod_dtim <= 0) + max_mod_dtim = 1; + + if (max_mod_dtim >= psoc_cfg->sta_mod_dtim) { + *listen_interval = + (psoc_cfg->sta_mod_dtim * + pmo_core_get_vdev_dtim_period(vdev)); + } else { + *listen_interval = + (max_mod_dtim * + pmo_core_get_vdev_dtim_period(vdev)); + } + } else { + /* Get Listen Interval */ + if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_listen_interval(psoc, + listen_interval))) { + pmo_err("Failed to get value for listen interval"); + *listen_interval = cfg_default(CFG_LISTEN_INTERVAL); + } + } + + pmo_info("sta dynamic dtim %d sta mod dtim %d sta_max_li_mod_dtim %d max_dtim %d", + psoc_cfg->sta_dynamic_dtim, psoc_cfg->sta_mod_dtim, + psoc_cfg->sta_max_li_mod_dtim, max_dtim); + + return QDF_STATUS_SUCCESS; +} + +static void pmo_configure_vdev_suspend_params( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx) +{ + QDF_STATUS ret; + uint8_t vdev_id; + enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); + struct pmo_psoc_cfg *psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; + uint8_t ito_repeat_count_value = 0; + uint32_t non_wow_inactivity_time, wow_inactivity_time; + + vdev_id = pmo_vdev_get_id(vdev); + if (!PMO_VDEV_IN_STA_MODE(opmode)) + return; + ret = pmo_tgt_send_vdev_sta_ps_param(vdev, + pmo_sta_ps_param_inactivity_time, + psoc_cfg->wow_data_inactivity_timeout); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_err("Failed to Set wow inactivity timeout vdevId %d", + vdev_id); + } + ret = pmo_tgt_send_vdev_sta_ps_param(vdev, + pmo_sta_ps_param_spec_wake_interval, + psoc_cfg->wow_spec_wake_interval); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_err("Failed to Set wow spec wake interval vdevId %d", + vdev_id); + } + + non_wow_inactivity_time = PMO_PS_DATA_INACTIVITY_TIMEOUT; + wow_inactivity_time = psoc_cfg->wow_data_inactivity_timeout; + /* + * To keep ito repeat count same in wow mode as in non wow mode, + * modulating ito repeat count value. + */ + ito_repeat_count_value = (non_wow_inactivity_time / + wow_inactivity_time) * + psoc_cfg->ito_repeat_count; + if (ito_repeat_count_value) + ret = pmo_tgt_send_vdev_sta_ps_param(vdev, + pmo_sta_ps_param_ito_repeat_count, + psoc_cfg->wow_data_inactivity_timeout); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_err("Failed to Set ito repeat count vdevId %d", + vdev_id); + } + + pmo_exit(); +} + +static void pmo_configure_vdev_resume_params( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx) +{ + QDF_STATUS ret; + uint8_t vdev_id; + enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); + + pmo_enter(); + + vdev_id = pmo_vdev_get_id(vdev); + if (!PMO_VDEV_IN_STA_MODE(opmode)) + return; + ret = pmo_tgt_send_vdev_sta_ps_param(vdev, + pmo_sta_ps_param_inactivity_time, + vdev_ctx->ps_params.ps_ito); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_err("Failed to Set inactivity timeout vdevId %d", + vdev_id); + } + ret = pmo_tgt_send_vdev_sta_ps_param(vdev, + pmo_sta_ps_param_spec_wake_interval, + vdev_ctx->ps_params.spec_wake); + if (QDF_IS_STATUS_ERROR(ret)) { + pmo_err("Failed to Set wow spec wake interval vdevId %d", + vdev_id); + } +} + +/** + * pmo_core_set_vdev_suspend_dtim() - set suspend dtim parameters in fw + * @psoc: objmgr psoc handle + * @vdev: objmgr vdev handle + * @vdev_ctx: pmo vdev priv ctx + * + * Return: none + */ +static void pmo_core_set_vdev_suspend_dtim(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx) +{ + QDF_STATUS ret; + uint8_t vdev_id; + enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); + uint32_t listen_interval = cfg_default(CFG_LISTEN_INTERVAL); + + vdev_id = pmo_vdev_get_id(vdev); + if (PMO_VDEV_IN_STA_MODE(opmode) && + pmo_core_get_vdev_dtim_period(vdev) != 0) { + /* calculate listen interval */ + ret = pmo_core_calculate_listen_interval(vdev, vdev_ctx, + &listen_interval); + if (ret != QDF_STATUS_SUCCESS) { + /* even it fails continue fwr will take default LI */ + pmo_debug("Fail to calculate listen interval"); + } + ret = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_listen_interval, + listen_interval); + if (QDF_IS_STATUS_ERROR(ret)) { + /* even it fails continue fwr will take default LI */ + pmo_debug("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + pmo_debug("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, listen_interval); + + pmo_core_vdev_set_restore_dtim(vdev, true); + } +} + +/* + * pmo_is_listen_interval_user_set() - Check if listen interval is configured + * by user or not + * @vdev_ctx: PMO vdev private object + * + * Return: true if listen interval is user configured else false + */ +static inline +bool pmo_is_listen_interval_user_set(struct pmo_vdev_priv_obj *vdev_ctx) +{ + bool retval; + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + retval = vdev_ctx->dyn_modulated_dtim_enabled + || vdev_ctx->dyn_listen_interval; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + return retval; +} + +/** + * pmo_core_set_suspend_dtim() - set suspend dtim + * @psoc: objmgr psoc handle + * + * Return: none + */ +static void pmo_core_set_suspend_dtim(struct wlan_objmgr_psoc *psoc) +{ + uint8_t vdev_id; + struct wlan_objmgr_vdev *vdev; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *psoc_ctx; + bool li_offload_support = false; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + li_offload_support = psoc_ctx->caps.li_offload; + } + + if (li_offload_support) + pmo_debug("listen interval offload support is enabled"); + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (!pmo_is_listen_interval_user_set(vdev_ctx) + && !li_offload_support) + pmo_core_set_vdev_suspend_dtim(psoc, vdev, vdev_ctx); + pmo_configure_vdev_suspend_params(psoc, vdev, vdev_ctx); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + } +} + +/** + * pmo_core_update_wow_bus_suspend() - set wow bus suspend flag + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo psoc priv ctx + * @val: true for enable else false + * Return: none + */ +static inline +void pmo_core_update_wow_bus_suspend(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx, int val) +{ + qdf_spin_lock_bh(&psoc_ctx->lock); + psoc_ctx->wow.is_wow_bus_suspended = val; + qdf_spin_unlock_bh(&psoc_ctx->lock); + pmo_tgt_psoc_update_wow_bus_suspend_state(psoc, val); +} + +/* Define for conciseness */ +#define BM_LEN PMO_WOW_MAX_EVENT_BM_LEN +#define EV_NLO WOW_NLO_SCAN_COMPLETE_EVENT +#define EV_PWR WOW_CHIP_POWER_FAILURE_DETECT_EVENT + +void pmo_core_configure_dynamic_wake_events(struct wlan_objmgr_psoc *psoc) +{ + int vdev_id; + uint32_t adapter_type; + uint32_t enable_mask[BM_LEN]; + uint32_t disable_mask[BM_LEN]; + struct wlan_objmgr_vdev *vdev; + struct pmo_psoc_priv_obj *psoc_ctx; + bool enable_configured; + bool disable_configured; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + + enable_configured = false; + disable_configured = false; + + qdf_mem_zero(enable_mask, sizeof(uint32_t) * BM_LEN); + qdf_mem_zero(disable_mask, sizeof(uint32_t) * BM_LEN); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + if (ucfg_scan_get_pno_in_progress(vdev)) { + if (ucfg_scan_get_pno_match(vdev)) { + pmo_set_wow_event_bitmap(EV_NLO, + BM_LEN, + enable_mask); + enable_configured = true; + } else { + pmo_set_wow_event_bitmap(EV_NLO, + BM_LEN, + disable_mask); + disable_configured = true; + } + } + + adapter_type = pmo_get_vdev_opmode(vdev); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + if (psoc_ctx->psoc_cfg.auto_power_save_fail_mode == + PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE && + (adapter_type == QDF_STA_MODE || + adapter_type == QDF_P2P_CLIENT_MODE)) { + if (psoc_ctx->is_device_in_low_pwr_mode && + psoc_ctx->is_device_in_low_pwr_mode(vdev_id)) { + pmo_set_wow_event_bitmap(EV_PWR, + BM_LEN, + enable_mask); + enable_configured = true; + } + } + + if (enable_configured) + pmo_tgt_enable_wow_wakeup_event(vdev, enable_mask); + if (disable_configured) + pmo_tgt_disable_wow_wakeup_event(vdev, disable_mask); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + } + +} + +static void pmo_core_enable_runtime_pm_offloads(struct wlan_objmgr_psoc *psoc) +{ + uint8_t vdev_id; + struct wlan_objmgr_vdev *vdev; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + pmo_register_action_frame_patterns(vdev, QDF_RUNTIME_SUSPEND); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + } +} + +static void pmo_core_disable_runtime_pm_offloads(struct wlan_objmgr_psoc *psoc) +{ + uint8_t vdev_id; + struct wlan_objmgr_vdev *vdev; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + pmo_clear_action_frame_patterns(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + } +} + +/** + * pmo_core_psoc_configure_suspend(): configure suspend req events + * @psoc: objmgr psoc + * @is_runtime_pm: indicate if it is used by runtime PM + * + * Responsibility of the caller to take the psoc reference. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS pmo_core_psoc_configure_suspend(struct wlan_objmgr_psoc *psoc, + bool is_runtime_pm) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + struct hif_target_info *tgt_info; + struct hif_opaque_softc *hif_ctx; + + psoc_ctx = pmo_psoc_get_priv(psoc); + + if (is_runtime_pm) + pmo_core_enable_runtime_pm_offloads(psoc); + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + if (!hif_ctx) { + pmo_err("Invalid hif ctx"); + return QDF_STATUS_E_NULL_VALUE; + } + tgt_info = hif_get_target_info_handle(hif_ctx); + + if ((is_runtime_pm) || + (psoc_ctx->psoc_cfg.suspend_mode == PMO_SUSPEND_WOW && + ((tgt_info->target_type == TARGET_TYPE_QCA6490) || + pmo_core_is_wow_applicable(psoc)))) { + pmo_debug("WOW Suspend"); + pmo_core_apply_lphb(psoc); + /* + * Dynamic wake events should not be needed for runtime PM. + * Any wake events can be configured by default if they are + * really needed for runtime PM. In fact, most of them are + * only needed for system suspend. + */ + if (!is_runtime_pm) + pmo_core_configure_dynamic_wake_events(psoc); + pmo_core_update_wow_enable(psoc_ctx, true); + pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false); + } else { + pmo_debug("Non WOW PDEV Suspend"); + pmo_core_update_wow_enable(psoc_ctx, false); + } + + /* + * For runtime PM, since system is awake, DTIM related commands + * do not have to be sent with WOW sequence. They can be sent + * through other paths which will just trigger a runtime resume. + */ + if (!is_runtime_pm) + pmo_core_set_suspend_dtim(psoc); + + /* + * To handle race between hif_pci_suspend and unpause/pause tx handler. + * This happens when host sending WMI_WOW_ENABLE_CMDID to FW and receive + * WMI_TX_PAUSE_EVENT with ACTON_UNPAUSE almost at same time. + */ + pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, true); + + pmo_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + QDF_STATUS status; + + pmo_enter(); + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + goto out; + } + + status = pmo_core_psoc_configure_suspend(psoc, false); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to configure suspend"); + + pmo_psoc_put_ref(psoc); +out: + return status; +} + +/** + * pmo_core_set_vdev_resume_dtim() - set resume dtim parameters in fw + * @psoc: objmgr psoc handle + * @vdev: objmgr vdev handle + * @vdev_ctx: pmo vdev priv ctx + * + * Return: none + */ +static void pmo_core_set_vdev_resume_dtim(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct pmo_vdev_priv_obj *vdev_ctx) +{ + QDF_STATUS ret; + uint8_t vdev_id; + enum QDF_OPMODE opmode = pmo_core_get_vdev_op_mode(vdev); + int32_t cfg_data_val = 0; + + vdev_id = pmo_vdev_get_id(vdev); + if ((PMO_VDEV_IN_STA_MODE(opmode)) && + (pmo_core_vdev_get_restore_dtim(vdev))) { + /* Get Listen Interval */ + if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_listen_interval(psoc, + &cfg_data_val))) { + pmo_err("Failed to get value for listen interval"); + cfg_data_val = cfg_default(CFG_LISTEN_INTERVAL); + } + + ret = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_listen_interval, cfg_data_val); + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + pmo_err("Failed to Set Listen Interval vdevId %d", + vdev_id); + } + pmo_debug("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, cfg_data_val); + pmo_core_vdev_set_restore_dtim(vdev, false); + } +} + +/** + * pmo_core_set_resume_dtim() - set resume time dtim + * @psoc: objmgr psoc handle + * + * Return: none + */ +static void pmo_core_set_resume_dtim(struct wlan_objmgr_psoc *psoc) +{ + uint8_t vdev_id; + struct wlan_objmgr_vdev *vdev; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *psoc_ctx; + bool li_offload_support = false; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + li_offload_support = psoc_ctx->caps.li_offload; + } + + if (li_offload_support) + pmo_debug("listen interval offload support is enabled"); + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (!pmo_is_listen_interval_user_set(vdev_ctx) + && !li_offload_support) + pmo_core_set_vdev_resume_dtim(psoc, vdev, vdev_ctx); + pmo_configure_vdev_resume_params(psoc, vdev, vdev_ctx); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + } +} + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +/** + * pmo_unpause_all_vdev() - unpause all vdev + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo psoc contaxt + * + * unpause all vdev aftter resume/coming out of wow mode + * + * Return: none + */ +static void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx) +{ + uint8_t vdev_id; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + /* When host resumes, by default unpause all active vdev */ + if (pmo_core_vdev_get_pause_bitmap(psoc_ctx, vdev_id)) { + cdp_fc_vdev_unpause(pmo_core_psoc_get_dp_handle(psoc), + vdev_id, + 0xffffffff, 0); + if (psoc_ctx->pause_bitmap_notifier) + psoc_ctx->pause_bitmap_notifier(vdev_id, 0); + } + } +} +#else +static inline void pmo_unpause_all_vdev(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx) +{ +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * pmo_core_psoc_configure_resume(): configure events after bus resume + * @psoc: objmgr psoc + * @is_runtime_pm: indicate if it is used by runtime PM + * + * Responsibility of the caller to take the psoc reference. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS pmo_core_psoc_configure_resume(struct wlan_objmgr_psoc *psoc, + bool is_runtime_pm) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + psoc_ctx = pmo_psoc_get_priv(psoc); + if (is_runtime_pm) + pmo_core_disable_runtime_pm_offloads(psoc); + + /* + * For runtime PM, since system is awake, DTIM related commands + * do not have to be sent with WOW sequence. They can be sent + * through other paths which will just trigger a runtime resume. + */ + if (!is_runtime_pm) + pmo_core_set_resume_dtim(psoc); + pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false); + pmo_unpause_all_vdev(psoc, psoc_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_core_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + goto out; + } + + status = pmo_core_psoc_configure_resume(psoc, false); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to configure resume"); + + pmo_psoc_put_ref(psoc); +out: + pmo_exit(); + + return status; +} + +/** + * pmo_core_enable_wow_in_fw() - enable wow in fw + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo psoc private ctx + * @wow_params: collection of wow enable override parameters + * @type: type of wow suspend + * + * Return: QDF status + */ +static QDF_STATUS +pmo_core_enable_wow_in_fw(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx, + struct pmo_wow_enable_params *wow_params, + enum qdf_suspend_type type) +{ + int host_credits, wmi_pending_cmds; + struct pmo_wow_cmd_params param = {0}; + struct pmo_psoc_cfg *psoc_cfg = &psoc_ctx->psoc_cfg; + QDF_STATUS status; + void *hif_ctx; + uint16_t reason_code; + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + qdf_event_reset(&psoc_ctx->wow.target_suspend); + pmo_core_set_wow_nack(psoc_ctx, false, 0); + host_credits = pmo_tgt_psoc_get_host_credits(psoc); + wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc); + pmo_debug("Credits:%d; Pending_Cmds: %d", + host_credits, wmi_pending_cmds); + + param.enable = true; + if (wow_params->is_unit_test) + param.flags = WMI_WOW_FLAG_UNIT_TEST_ENABLE; + + switch (wow_params->interface_pause) { + default: + pmo_err("Invalid interface pause setting: %d", + wow_params->interface_pause); + /* intentional to default */ + fallthrough; + case PMO_WOW_INTERFACE_PAUSE_DEFAULT: + param.can_suspend_link = + htc_can_suspend_link( + pmo_core_psoc_get_htc_handle(psoc)); + break; + case PMO_WOW_INTERFACE_PAUSE_ENABLE: + param.can_suspend_link = true; + break; + case PMO_WOW_INTERFACE_PAUSE_DISABLE: + param.can_suspend_link = false; + break; + } + + switch (wow_params->resume_trigger) { + default: + pmo_err("Invalid resume trigger setting: %d", + wow_params->resume_trigger); + fallthrough; + case PMO_WOW_RESUME_TRIGGER_DEFAULT: + case PMO_WOW_RESUME_TRIGGER_GPIO: + /* + * GPIO is currently implicit. This means you can't actually + * force GPIO if a platform's default wake trigger is HTC wakeup + */ + break; + case PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP: + param.flags |= WMI_WOW_FLAG_DO_HTC_WAKEUP; + break; + } + + if (psoc_ctx->psoc_cfg.d0_wow_supported && + !psoc_ctx->caps.unified_wow && + !param.can_suspend_link) { + psoc_ctx->wow.wow_state = pmo_wow_state_legacy_d0; + } else if (param.can_suspend_link) { + psoc_ctx->wow.wow_state = pmo_wow_state_unified_d3; + } else { + psoc_ctx->wow.wow_state = pmo_wow_state_unified_d0; + } + + if (htc_can_suspend_link(pmo_core_psoc_get_htc_handle(psoc))) { + if (qdf_is_drv_connected()) { + pmo_info("drv wow is enabled"); + param.flags |= WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP; + } else { + pmo_debug("non-drv wow is enabled"); + } + } else { + pmo_info("Prevent link down, non-drv wow is enabled"); + if (hif_ctx) { + hif_rtpm_print_prevent_list(); + htc_log_link_user_votes(); + } + } + if (wow_params->is_unit_test) { + pmo_info("Unit test WoW, force DRV mode"); + param.flags |= WMI_WOW_FLAG_ENABLE_DRV_PCIE_L1SS_SLEEP; + } + if (type == QDF_SYSTEM_SUSPEND) { + pmo_info("system suspend wow"); + param.flags |= WMI_WOW_FLAG_SYSTEM_SUSPEND_WOW; + } else if (type == QDF_UNIT_TEST_WOW_SUSPEND) { + pmo_info("unit test wow suspend"); + } else { + pmo_debug("RTPM wow"); + } + + if (psoc_cfg->is_mod_dtim_on_sys_suspend_enabled) { + pmo_debug("mod DTIM enabled"); + param.flags |= WMI_WOW_FLAG_MOD_DTIM_ON_SYS_SUSPEND; + } + + if (psoc_cfg->sta_forced_dtim) { + pmo_debug("forced DTIM enabled"); + param.flags |= WMI_WOW_FLAG_FORCED_DTIM_ON_SYS_SUSPEND; + } + status = pmo_tgt_psoc_send_wow_enable_req(psoc, ¶m); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to enable wow in fw"); + goto out; + } + + pmo_tgt_update_target_suspend_flag(psoc, true); + + status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_suspend, + PMO_TARGET_SUSPEND_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) { + if (hif_ctx) { + hif_display_ctrl_traffic_pipes_state(hif_ctx); + hif_display_latest_desc_hist(hif_ctx); + } + pmo_err("Failed to receive WoW Enable Ack from FW"); + pmo_err("Credits:%d; Pending_Cmds: %d", + pmo_tgt_psoc_get_host_credits(psoc), + pmo_tgt_psoc_get_pending_cmnds(psoc)); + if (!psoc_ctx->wow.target_suspend.force_set) { + pmo_tgt_psoc_set_wow_enable_ack_failed(psoc); + qdf_trigger_self_recovery(psoc, QDF_SUSPEND_TIMEOUT); + } + pmo_tgt_update_target_suspend_flag(psoc, false); + goto out; + } + + if (pmo_core_get_wow_nack(psoc_ctx)) { + reason_code = pmo_core_get_wow_reason_code(psoc_ctx); + pmo_err("FW not ready to WOW reason code: %d", reason_code); + pmo_tgt_update_target_suspend_flag(psoc, false); + status = QDF_STATUS_E_AGAIN; + goto out; + } + + pmo_tgt_update_target_suspend_acked_flag(psoc, true); + + host_credits = pmo_tgt_psoc_get_host_credits(psoc); + wmi_pending_cmds = pmo_tgt_psoc_get_pending_cmnds(psoc); + + if (host_credits < PMO_WOW_REQUIRED_CREDITS) { + pmo_err("No Credits after HTC ACK:%d, pending_cmds:%d," + "cannot resume back", host_credits, wmi_pending_cmds); + htc_dump_counter_info(pmo_core_psoc_get_htc_handle(psoc)); + qdf_trigger_self_recovery(psoc, QDF_SUSPEND_NO_CREDIT); + } + pmo_debug("WOW enabled successfully in fw: credits:%d pending_cmds: %d", + host_credits, wmi_pending_cmds); + + hif_latency_detect_timer_stop(pmo_core_psoc_get_hif_handle(psoc)); + + if (hif_rtpm_get_autosuspend_delay() == WOW_LARGE_RX_RTPM_DELAY) + hif_rtpm_restore_autosuspend_delay(); + + pmo_core_update_wow_enable_cmd_sent(psoc_ctx, true); + +out: + return status; +} + +QDF_STATUS pmo_core_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, + int disable_target_intr) +{ + QDF_STATUS status; + struct pmo_suspend_params param; + struct pmo_psoc_priv_obj *psoc_ctx; + void *dp_soc = pmo_core_psoc_get_dp_handle(psoc); + + pmo_enter(); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + cdp_process_target_suspend_req(dp_soc, OL_TXRX_PDEV_ID); + qdf_event_reset(&psoc_ctx->wow.target_suspend); + param.disable_target_intr = disable_target_intr; + status = pmo_tgt_psoc_send_supend_req(psoc, ¶m); + if (status != QDF_STATUS_SUCCESS) + goto out; + + pmo_tgt_update_target_suspend_flag(psoc, true); + + status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_suspend, + PMO_TARGET_SUSPEND_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("Failed to get ACK from firmware for pdev suspend"); + pmo_tgt_update_target_suspend_flag(psoc, false); + if (!psoc_ctx->wow.target_suspend.force_set) + qdf_trigger_self_recovery(psoc, QDF_SUSPEND_TIMEOUT); + } else { + pmo_tgt_update_target_suspend_acked_flag(psoc, true); + } + +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type, + struct pmo_wow_enable_params *wow_params) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + bool wow_mode_selected = false; + qdf_time_t begin, end; + + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + if (!wow_params) { + pmo_err("wow_params is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + goto out; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + + wow_mode_selected = pmo_core_is_wow_enabled(psoc_ctx); + + begin = qdf_get_log_timestamp_usecs(); + if (wow_mode_selected) + status = pmo_core_enable_wow_in_fw(psoc, psoc_ctx, + wow_params, + type); + else + status = pmo_core_psoc_suspend_target(psoc, 0); + end = qdf_get_log_timestamp_usecs(); + pmo_debug("fw took total time %lu microseconds to enable wow", + end - begin); + + pmo_psoc_put_ref(psoc); +out: + return status; +} + +QDF_STATUS pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_ctx; + QDF_STATUS status; + void *hif_ctx; + void *dp_soc; + int ret; + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_ctx = pmo_psoc_get_priv(psoc); + if (pmo_core_get_wow_state(pmo_ctx) != pmo_wow_state_unified_d3) + goto out; + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + dp_soc = pmo_core_psoc_get_dp_handle(psoc); + if (!hif_ctx || !dp_soc) { + pmo_err("Invalid ctx hif: %pK, dp: %pK", hif_ctx, dp_soc); + status = QDF_STATUS_E_INVAL; + goto out; + } + + ret = hif_disable_grp_irqs(hif_ctx); + if (ret && ret != -EOPNOTSUPP) { + pmo_err("Prevent suspend, failed to disable grp irqs: %d", ret); + status = qdf_status_from_os_return(ret); + goto out; + } + + if (ret == -EOPNOTSUPP) { + /* For chips, which not support IRQ disable, + * drain will not be called, display and check + * rings HP/TP once again + */ + if (!cdp_display_txrx_hw_info(dp_soc)) { + pmo_err("Prevent suspend, ring not empty"); + status = QDF_STATUS_E_AGAIN; + } + + goto out; + } + + status = cdp_drain_txrx(dp_soc, 0); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("Prevent suspend unable to drain txrx status:%u", + status); + ret = hif_enable_grp_irqs(hif_ctx); + if (ret && ret != -EOPNOTSUPP) { + pmo_err("Failed to enable grp irqs: %d", ret); + qdf_trigger_self_recovery(psoc, QDF_ENABLE_IRQ_FAILURE); + } + goto out; + } + + pmo_ctx->wow.txrx_suspended = true; +out: + pmo_psoc_put_ref(psoc); + return status; +} + +QDF_STATUS pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_ctx; + QDF_STATUS status; + void *hif_ctx; + int ret; + + status = pmo_psoc_get_ref(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_ctx = pmo_psoc_get_priv(psoc); + if (!pmo_ctx->wow.txrx_suspended) + goto out; + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + if (!hif_ctx) { + pmo_err("Invalid hif ctx"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + ret = hif_enable_grp_irqs(hif_ctx); + if (ret && ret != -EOPNOTSUPP) { + pmo_err("Failed to enable grp irqs: %d", ret); + status = qdf_status_from_os_return(ret); + goto out; + } + + pmo_ctx->wow.txrx_suspended = false; +out: + pmo_psoc_put_ref(psoc); + return status; +} + +#ifdef FEATURE_RUNTIME_PM +#define PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(__condition) ({ \ + typeof(__condition) condition = __condition; \ + if (condition && !qdf_is_fw_down()) \ + QDF_BUG(0); \ +}) + +QDF_STATUS pmo_core_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb) +{ + void *hif_ctx; + void *dp_soc; + uint8_t pdev_id; + void *htc_ctx; + QDF_STATUS status; + int ret; + struct pmo_wow_enable_params wow_params = {0}; + struct pmo_psoc_priv_obj *psoc_ctx; + qdf_time_t begin, end; + int pending; + + pmo_enter(); + + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + goto out; + } + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + dp_soc = pmo_core_psoc_get_dp_handle(psoc); + pdev_id = pmo_core_psoc_get_txrx_handle(psoc); + htc_ctx = pmo_core_psoc_get_htc_handle(psoc); + if (!hif_ctx || !dp_soc || !htc_ctx || + pdev_id == OL_TXRX_INVALID_PDEV_ID) { + pmo_err("Invalid hif: %pK, dp: %pK, pdev_id: %d, htc: %pK", + hif_ctx, dp_soc, pdev_id, htc_ctx); + status = QDF_STATUS_E_INVAL; + goto dec_psoc_ref; + } + + wow_params.interface_pause = PMO_WOW_INTERFACE_PAUSE_ENABLE; + wow_params.resume_trigger = PMO_WOW_RESUME_TRIGGER_GPIO; + + ret = hif_pre_runtime_suspend(hif_ctx); + if (ret) { + status = qdf_status_from_os_return(ret); + goto runtime_failure; + } + + status = wlan_dp_runtime_suspend(dp_soc, pdev_id); + if (status != QDF_STATUS_SUCCESS) + goto runtime_failure; + + ret = htc_runtime_suspend(htc_ctx); + if (ret) { + status = qdf_status_from_os_return(ret); + goto dp_runtime_resume; + } + + status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, true); + if (status != QDF_STATUS_SUCCESS) + goto resume_htc; + + status = pmo_core_psoc_configure_suspend(psoc, true); + if (status != QDF_STATUS_SUCCESS) + goto resume_htc; + + status = pmo_core_psoc_bus_suspend_req(psoc, QDF_RUNTIME_SUSPEND, + &wow_params); + if (status != QDF_STATUS_SUCCESS) + goto pmo_resume_configure; + + ret = hif_runtime_suspend(hif_ctx); + if (ret) { + status = qdf_status_from_os_return(ret); + goto pmo_bus_resume; + } + + status = pmo_core_txrx_suspend(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto resume_hif; + + pending = cdp_rx_get_pending(cds_get_context(QDF_MODULE_ID_SOC)); + if (pending) { + pmo_debug("Prevent suspend, RX frame pending %d", pending); + status = QDF_STATUS_E_BUSY; + goto resume_txrx; + } + + if (pld_cb) { + begin = qdf_get_log_timestamp_usecs(); + ret = pld_cb(); + end = qdf_get_log_timestamp_usecs(); + pmo_debug("runtime pci bus suspend took total time %lu microseconds", + end - begin); + + if (ret) { + status = qdf_status_from_os_return(ret); + goto resume_txrx; + } + } + + if (hif_pm_get_wake_irq_type(hif_ctx) == HIF_PM_CE_WAKE) { + /* + * In moselle, there is no separate interrupt for wake_irq, + * shares CE interrupt, there is a chance of wow wakeup + * while suspend is in-progress, so handling such scenario + */ + hif_rtpm_suspend_lock(); + psoc_ctx = pmo_psoc_get_priv(psoc); + if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) { + hif_rtpm_suspend_unlock(); + pmo_err("Target wake up received before suspend completion"); + status = QDF_STATUS_E_BUSY; + goto resume_txrx; + } + hif_process_runtime_suspend_success(); + hif_rtpm_suspend_unlock(); + } else { + hif_process_runtime_suspend_success(); + } + + if (hif_try_prevent_ep_vote_access(hif_ctx)) { + pmo_debug("Prevent suspend, ep work pending"); + status = QDF_STATUS_E_BUSY; + goto resume_txrx; + } + + goto dec_psoc_ref; + +resume_txrx: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != + pmo_core_txrx_resume(psoc)); + +resume_hif: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(hif_runtime_resume(hif_ctx)); + +pmo_bus_resume: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != + pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND)); + +pmo_resume_configure: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != + pmo_core_psoc_configure_resume(psoc, true)); + +resume_htc: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != + pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false)); + +dp_runtime_resume: + PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(QDF_STATUS_SUCCESS != + wlan_dp_runtime_resume(dp_soc, pdev_id)); + +runtime_failure: + hif_process_runtime_suspend_failure(); + +/* always make sure HTC queue kicker is at the end, so if any + * cmd is pending during suspending, it can re-trigger if suspend + * failure. + */ +PMO_CORE_PSOC_RUNTIME_PM_QDF_BUG(htc_runtime_resume(htc_ctx)); + +dec_psoc_ref: + pmo_psoc_put_ref(psoc); + +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_resume_cb pld_cb) +{ + int ret; + void *hif_ctx; + void *dp_soc; + uint8_t pdev_id; + void *htc_ctx; + QDF_STATUS status; + qdf_time_t begin, end; + + pmo_enter(); + + if (!psoc) { + pmo_err("psoc is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + goto out; + } + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + dp_soc = pmo_core_psoc_get_dp_handle(psoc); + pdev_id = pmo_core_psoc_get_txrx_handle(psoc); + htc_ctx = pmo_core_psoc_get_htc_handle(psoc); + if (!hif_ctx || !dp_soc || !htc_ctx || + pdev_id == OL_TXRX_INVALID_PDEV_ID) { + pmo_err("Invalid hif: %pK, dp: %pK, pdev_id: %d, htc: %pK", + hif_ctx, dp_soc, pdev_id, htc_ctx); + status = QDF_STATUS_E_INVAL; + goto dec_psoc_ref; + } + + hif_pre_runtime_resume(); + if (pld_cb) { + begin = qdf_get_log_timestamp_usecs(); + ret = pld_cb(); + end = qdf_get_log_timestamp_usecs(); + pmo_debug("pci bus resume took total time %lu microseconds", + end - begin); + if (ret) { + status = QDF_STATUS_E_FAILURE; + goto fail; + } + } + + if (hif_runtime_resume(hif_ctx)) { + status = QDF_STATUS_E_FAILURE; + goto fail; + } + + status = pmo_core_psoc_bus_resume_req(psoc, QDF_RUNTIME_SUSPEND); + if (status != QDF_STATUS_SUCCESS) + goto fail; + + status = pmo_core_txrx_resume(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto fail; + + hif_process_runtime_resume_linkup(); + + status = pmo_core_psoc_configure_resume(psoc, true); + if (status != QDF_STATUS_SUCCESS) + goto fail; + + status = pmo_tgt_psoc_set_runtime_pm_inprogress(psoc, false); + if (status != QDF_STATUS_SUCCESS) + goto fail; + + hif_process_runtime_resume_success(); + + if (htc_runtime_resume(htc_ctx)) { + status = QDF_STATUS_E_FAILURE; + goto fail; + } + + status = wlan_dp_runtime_resume(dp_soc, pdev_id); + if (status != QDF_STATUS_SUCCESS) + goto fail; + +fail: + if (status != QDF_STATUS_SUCCESS) + qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT); + +dec_psoc_ref: + pmo_psoc_put_ref(psoc); + +out: + return status; +} +#endif + +/** + * pmo_core_psoc_send_host_wakeup_ind_to_fw() - send wakeup ind to fw + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo psoc private context + * + * Sends host wakeup indication to FW. On receiving this indication, + * FW will come out of WOW. + * + * Return: QDF status + */ +static +QDF_STATUS pmo_core_psoc_send_host_wakeup_ind_to_fw( + struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + void *hif_ctx; + + hif_ctx = pmo_core_psoc_get_hif_handle(psoc); + + if (!hif_ctx) { + pmo_err("hif_ctx is NULL"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + hif_set_ep_intermediate_vote_access(hif_ctx); + + qdf_event_reset(&psoc_ctx->wow.target_resume); + + status = pmo_tgt_psoc_send_host_wakeup_ind(psoc); + if (status) { + hif_set_ep_vote_access(hif_ctx, + HIF_EP_VOTE_NONDP_ACCESS, + HIF_EP_VOTE_ACCESS_DISABLE); + status = QDF_STATUS_E_FAILURE; + goto out; + } + pmo_info("Host wakeup indication sent to fw"); + + status = qdf_wait_for_event_completion(&psoc_ctx->wow.target_resume, + PMO_RESUME_TIMEOUT); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Timeout waiting for resume event from FW"); + pmo_err("Pending commands %d credits %d", + pmo_tgt_psoc_get_pending_cmnds(psoc), + pmo_tgt_psoc_get_host_credits(psoc)); + + if (!psoc_ctx->wow.target_resume.force_set) + qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT); + } else { + pmo_debug("Host wakeup received"); + pmo_tgt_update_target_suspend_flag(psoc, false); + pmo_tgt_update_target_suspend_acked_flag(psoc, false); + hif_set_ep_vote_access(hif_ctx, + HIF_EP_VOTE_NONDP_ACCESS, + HIF_EP_VOTE_ACCESS_ENABLE); + hif_set_ep_vote_access(hif_ctx, + HIF_EP_VOTE_DP_ACCESS, + HIF_EP_VOTE_ACCESS_ENABLE); + } +out: + return status; +} + +/** + * pmo_core_psoc_disable_wow_in_fw() - Disable wow in bus resume context. + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo psoc private context + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static +QDF_STATUS pmo_core_psoc_disable_wow_in_fw(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx) +{ + QDF_STATUS ret; + + ret = pmo_core_psoc_send_host_wakeup_ind_to_fw(psoc, psoc_ctx); + if (ret != QDF_STATUS_SUCCESS) + goto out; + + pmo_core_update_wow_enable_cmd_sent(psoc_ctx, false); + + /* To allow the tx pause/unpause events */ + pmo_core_update_wow_bus_suspend(psoc, psoc_ctx, false); + /* Unpause the vdev as we are resuming */ + pmo_unpause_all_vdev(psoc, psoc_ctx); +out: + return ret; +} + +/** + * pmo_core_psoc_resume_target() - resume target + * @psoc: objmgr psoc handle + * @psoc_ctx: pmo psoc private context + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static +QDF_STATUS pmo_core_psoc_resume_target(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_priv_obj *psoc_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + qdf_event_reset(&psoc_ctx->wow.target_resume); + + status = pmo_tgt_psoc_send_target_resume_req(psoc); + if (status != QDF_STATUS_SUCCESS) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + status = qdf_wait_single_event(&psoc_ctx->wow.target_resume, + PMO_RESUME_TIMEOUT); + if (status != QDF_STATUS_SUCCESS) { + pmo_fatal("Timeout waiting for resume event from FW"); + pmo_fatal("Pending commands %d credits %d", + pmo_tgt_psoc_get_pending_cmnds(psoc), + pmo_tgt_psoc_get_host_credits(psoc)); + if (!psoc_ctx->wow.target_resume.force_set) + qdf_trigger_self_recovery(psoc, QDF_RESUME_TIMEOUT); + } else { + pmo_debug("Host wakeup received"); + pmo_tgt_update_target_suspend_flag(psoc, false); + pmo_tgt_update_target_suspend_acked_flag(psoc, false); + } +out: + return status; +} + +QDF_STATUS pmo_core_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + bool wow_mode; + QDF_STATUS status; + qdf_time_t begin, end; + + if (!psoc) { + pmo_err("psoc is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + goto out; + } + + hif_latency_detect_timer_start(pmo_core_psoc_get_hif_handle(psoc)); + + psoc_ctx = pmo_psoc_get_priv(psoc); + wow_mode = pmo_core_is_wow_enabled(psoc_ctx); + pmo_debug("wow mode %d", wow_mode); + + pmo_core_update_wow_initial_wake_up(psoc_ctx, 0); + + /* If target was not suspended, bail out */ + if (qdf_is_fw_down() || !pmo_tgt_is_target_suspended(psoc)) { + pmo_psoc_put_ref(psoc); + status = QDF_STATUS_E_AGAIN; + goto out; + } + + begin = qdf_get_log_timestamp_usecs(); + if (wow_mode) + status = pmo_core_psoc_disable_wow_in_fw(psoc, psoc_ctx); + else + status = pmo_core_psoc_resume_target(psoc, psoc_ctx); + end = qdf_get_log_timestamp_usecs(); + pmo_debug("fw took total time %lu microseconds to disable wow", + end - begin); + + pmo_psoc_put_ref(psoc); + +out: + return status; +} + +void pmo_core_psoc_target_suspend_acknowledge(void *context, bool wow_nack, + uint16_t reason_code) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)context; + void *dp_soc = pmo_core_psoc_get_dp_handle(psoc); + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to get psoc reference"); + goto out; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_core_set_wow_nack(psoc_ctx, wow_nack, reason_code); + qdf_event_set(&psoc_ctx->wow.target_suspend); + if (!pmo_tgt_psoc_get_runtime_pm_in_progress(psoc)) { + if (wow_nack) + qdf_wake_lock_timeout_acquire( + &psoc_ctx->wow.wow_wake_lock, + PMO_WAKE_LOCK_TIMEOUT); + else + cdp_process_wow_ack_rsp(dp_soc, OL_TXRX_PDEV_ID); + } + + pmo_psoc_put_ref(psoc); +out: + pmo_exit(); +} + +void pmo_core_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + if (!psoc) { + pmo_err("psoc is null"); + return; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + psoc_ctx->wow.wow_state = pmo_wow_state_none; + qdf_event_set(&psoc_ctx->wow.target_resume); +} + +int pmo_core_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + int ret = 0; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is NULL"); + ret = -EAGAIN; + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to get psoc reference"); + ret = -EAGAIN; + goto out; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + if (pmo_core_get_wow_initial_wake_up(psoc_ctx)) { + pmo_err("Target initial wake up received try again"); + ret = -EAGAIN; + } + + pmo_psoc_put_ref(psoc); +out: + pmo_exit(); + + return ret; +} + + +int pmo_core_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + int ret = 0; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is NULL"); + ret = -EAGAIN; + goto out; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to get psoc reference"); + ret = -EAGAIN; + goto out; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + pmo_core_update_wow_initial_wake_up(psoc_ctx, 0); + + pmo_psoc_put_ref(psoc); +out: + return ret; +} + +void pmo_core_psoc_handle_initial_wake_up(void *cb_ctx) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)cb_ctx; + void *hif_ctx; + + if (!psoc) { + pmo_err("cb ctx/psoc is null"); + return; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + hif_ctx = psoc_ctx->hif_hdl; + if (!hif_ctx) + pmo_err("hif ctx is null, request resume not called"); + else if(hif_pm_get_wake_irq_type(hif_ctx) == HIF_PM_CE_WAKE) + hif_rtpm_check_and_request_resume(true); + + pmo_core_update_wow_initial_wake_up(psoc_ctx, 1); +} + +QDF_STATUS pmo_core_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t new_li) +{ + QDF_STATUS status; + uint8_t vdev_id; + uint32_t listen_interval; + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + vdev_id = pmo_vdev_get_id(vdev); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (vdev_ctx->dyn_listen_interval == new_li) { + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + status = QDF_STATUS_SUCCESS; + pmo_debug("Listen Interval(%d) already set for vdev id %d", + new_li, vdev_id); + goto dec_ref; + } + + vdev_ctx->dyn_listen_interval = new_li; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + listen_interval = new_li ? new_li : cfg_default(CFG_LISTEN_INTERVAL); + + if (!new_li) { + /* Configure default LI as we do on resume */ + pmo_psoc_with_ctx(pmo_vdev_get_psoc(vdev), psoc_ctx) { + if (QDF_IS_STATUS_ERROR( + ucfg_mlme_get_listen_interval(psoc, + &listen_interval))) { + pmo_err("Failed to get listen interval"); + listen_interval = + cfg_default(CFG_LISTEN_INTERVAL); + } + } + } + + pmo_debug("Set Listen Interval %d for vdevId %d", listen_interval, + vdev_id); + ucfg_mlme_set_sap_listen_interval(psoc, listen_interval); + status = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_listen_interval, + listen_interval); + if (QDF_IS_STATUS_ERROR(status)) { + /* even it fails continue fwr will take default LI */ + pmo_err("Failed to Set Listen Interval"); + } + + /* Set it to Normal DTIM */ + status = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_dtim_policy, + pmo_normal_dtim); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("Failed to set Normal DTIM for vdev id %d", vdev_id); + } else { + pmo_debug("Set DTIM Policy to Normal for vdev id %d", vdev_id); + pmo_core_vdev_set_restore_dtim(vdev, true); + } + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +QDF_STATUS +pmo_core_enable_igmp_offload(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id; + enum QDF_OPMODE op_mode; + struct pmo_vdev_priv_obj *vdev_ctx; + uint32_t version_support; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_INVAL; + + op_mode = pmo_get_vdev_opmode(vdev); + if (QDF_STA_MODE != op_mode) { + pmo_debug("igmp offload supported in STA mode"); + return QDF_STATUS_E_INVAL; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (!vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_offload_enable) { + pmo_debug("igmp offload not supported"); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + return QDF_STATUS_E_NOSUPPORT; + } + version_support = + vdev_ctx->pmo_psoc_ctx->psoc_cfg.igmp_version_support; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_id = pmo_vdev_get_id(vdev); + pmo_igmp_req->vdev_id = vdev_id; + pmo_igmp_req->version_support = version_support; + status = pmo_tgt_send_igmp_offload_req(vdev, pmo_igmp_req); + + return status; +} +#endif + +QDF_STATUS pmo_core_config_forced_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t dynamic_dtim) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + uint8_t vdev_id; + QDF_STATUS status; + + vdev_id = pmo_vdev_get_id(vdev); + vdev_ctx = pmo_vdev_get_priv(vdev); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->dyn_modulated_dtim = dynamic_dtim; + vdev_ctx->dyn_modulated_dtim_enabled = dynamic_dtim >= 1; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + status = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_forced_dtim_count, + dynamic_dtim); + + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("Failed to set forced DTIM for vdev id %d", + vdev_id); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return status; +} + +static QDF_STATUS +pmo_core_config_non_li_offload_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_cfg *psoc_cfg; + bool prev_dtim_enabled; + uint32_t listen_interval; + uint32_t beacon_interval_mod; + uint32_t max_mod_dtim; + QDF_STATUS status; + uint8_t vdev_id; + uint32_t max_dtim; + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_id = pmo_vdev_get_id(vdev); + vdev_ctx = pmo_vdev_get_priv(vdev); + psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; + + if (psoc_cfg->sta_forced_dtim) + return pmo_core_config_forced_dtim(vdev, mod_dtim); + + /* Calculate Maximum allowed modulated DTIM */ + beacon_interval_mod = + pmo_core_get_vdev_beacon_interval(vdev) / 100; + if (!beacon_interval_mod) + beacon_interval_mod = 1; + + max_dtim = (pmo_core_get_vdev_dtim_period(vdev) + * beacon_interval_mod); + + if (!max_dtim) { + pmo_err("Invalid dtim period"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + return QDF_STATUS_E_INVAL; + } + + max_mod_dtim = psoc_cfg->sta_max_li_mod_dtim / + max_dtim; + + if (!max_mod_dtim) + max_mod_dtim = 1; + + /* Calculate Listen Interval from provided mod DTIM */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->dyn_modulated_dtim = mod_dtim; + prev_dtim_enabled = vdev_ctx->dyn_modulated_dtim_enabled; + vdev_ctx->dyn_modulated_dtim_enabled = mod_dtim != 1; + if (vdev_ctx->dyn_modulated_dtim > max_mod_dtim) { + listen_interval = max_mod_dtim * + pmo_core_get_vdev_dtim_period(vdev); + } else { + listen_interval = vdev_ctx->dyn_modulated_dtim * + pmo_core_get_vdev_dtim_period(vdev); + } + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + if (prev_dtim_enabled || mod_dtim != 1) { + status = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_listen_interval, + listen_interval); + if (QDF_IS_STATUS_ERROR(status)) + /* even it fails continue fwr will take default LI */ + pmo_err("Failed to set Listen Interval for vdev id %d", + vdev_id); + else + pmo_debug("Set Listen Interval %d for vdev id %d", + listen_interval, vdev_id); + + status = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_dtim_policy, + pmo_normal_dtim); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("Failed to set Normal DTIM for vdev id %d", + vdev_id); + } else { + pmo_debug("Set DTIM Policy to Normal for vdev id %d", + vdev_id); + pmo_core_vdev_set_restore_dtim(vdev, true); + } + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + return status; +} + +static QDF_STATUS +pmo_core_config_li_offload_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_cfg *psoc_cfg; + QDF_STATUS status; + uint8_t vdev_id; + + pmo_enter(); + + status = pmo_vdev_get_ref(vdev); + if (status != QDF_STATUS_SUCCESS) + goto out; + + vdev_id = pmo_vdev_get_id(vdev); + vdev_ctx = pmo_vdev_get_priv(vdev); + psoc_cfg = &vdev_ctx->pmo_psoc_ctx->psoc_cfg; + + if (mod_dtim > psoc_cfg->sta_max_li_mod_dtim) + mod_dtim = psoc_cfg->sta_max_li_mod_dtim; + pmo_core_vdev_set_moddtim_user(vdev, mod_dtim); + pmo_core_vdev_set_moddtim_user_enabled(vdev, true); + + if (!ucfg_pmo_is_vdev_connected(vdev)) { + pmo_core_vdev_set_moddtim_user_active(vdev, false); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + goto out; + } + + status = pmo_tgt_vdev_update_param_req(vdev, + pmo_vdev_param_moddtim, + mod_dtim); + if (QDF_IS_STATUS_SUCCESS(status)) { + pmo_debug("Set modulated dtim for vdev id %d", + vdev_id); + pmo_core_vdev_set_moddtim_user_active(vdev, true); + } else { + pmo_err("Failed to Set modulated dtim for vdev id %d", + vdev_id); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + return status; +} + +QDF_STATUS pmo_core_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + struct pmo_vdev_priv_obj *vdev_ctx; + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + vdev_ctx = pmo_vdev_get_priv(vdev); + psoc_ctx = vdev_ctx->pmo_psoc_ctx; + + if (psoc_ctx->caps.li_offload) + status = pmo_core_config_li_offload_modulated_dtim(vdev, + mod_dtim); + else + status = pmo_core_config_non_li_offload_modulated_dtim(vdev, + mod_dtim); + + return status; +} + +#ifdef SYSTEM_PM_CHECK +void pmo_core_system_resume(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is NULL"); + return; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return; + } + + psoc_ctx = pmo_psoc_get_priv(psoc); + + htc_system_resume(psoc_ctx->htc_hdl); + + pmo_psoc_put_ref(psoc); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_wow.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_wow.c new file mode 100644 index 0000000000..f93f4d3296 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/core/src/wlan_pmo_wow.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Define API's for wow pattern addition and deletion in fwr + */ + +#include "wlan_pmo_wow.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include +#include "wlan_pmo_static_config.h" +#include "wlan_reg_services_api.h" +#include "cfg_nan_api.h" +#include "wlan_utility.h" + +void pmo_set_wow_event_bitmap(WOW_WAKE_EVENT_TYPE event, + uint32_t wow_bitmap_size, + uint32_t *bitmask) +{ + uint32_t bit_idx = 0, idx = 0; + + if (!bitmask || wow_bitmap_size < PMO_WOW_MAX_EVENT_BM_LEN) { + pmo_err("wow bitmask length shorter than %d", + PMO_WOW_MAX_EVENT_BM_LEN); + return; + } + pmo_get_event_bitmap_idx(event, wow_bitmap_size, &bit_idx, &idx); + bitmask[idx] |= 1 << bit_idx; +} + +QDF_STATUS pmo_core_del_wow_pattern(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + uint8_t id; + uint8_t pattern_count; + struct pmo_vdev_priv_obj *vdev_ctx; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + pattern_count = pmo_get_wow_default_ptrn(vdev_ctx); + /* clear all default patterns configured by pmo */ + for (id = 0; id < pattern_count; id++) + status = pmo_tgt_del_wow_pattern(vdev, id, false); + + /* clear all user patterns configured by pmo */ + pattern_count = pmo_get_wow_user_ptrn(vdev_ctx); + for (id = 0; id < pattern_count; id++) + status = pmo_tgt_del_wow_pattern(vdev, id, true); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + return status; +} + +QDF_STATUS pmo_core_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn) +{ + QDF_STATUS status; + uint8_t id; + uint8_t bit_to_check, pos; + uint8_t new_mask[PMO_WOWL_BCAST_PATTERN_MAX_SIZE]; + struct pmo_vdev_priv_obj *vdev_ctx; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + /* clear all default patterns configured by pmo */ + for (id = 0; id < pmo_get_wow_default_ptrn(vdev_ctx); id++) + pmo_tgt_del_wow_pattern(vdev, id, false); + + pmo_set_wow_default_ptrn(vdev_ctx, 0); + + pmo_debug("Add user passed wow pattern id %d vdev id %d", + ptrn->pattern_id, wlan_vdev_get_id(vdev)); + /* + * Convert received pattern mask value from bit representation + * to byte representation. + * + * For example, received value from umac, + * + * Mask value : A1 (equivalent binary is "1010 0001") + * Pattern value : 12:00:13:00:00:00:00:44 + * + * The value which goes to FW after the conversion from this + * function (1 in mask value will become FF and 0 will + * become 00), + * + * Mask value : FF:00:FF:00:00:00:00:FF + * Pattern value : 12:00:13:00:00:00:00:44 + */ + qdf_mem_zero(new_mask, sizeof(new_mask)); + for (pos = 0; pos < ptrn->pattern_size; pos++) { + bit_to_check = (PMO_NUM_BITS_IN_BYTE - 1) - + (pos % PMO_NUM_BITS_IN_BYTE); + bit_to_check = 0x1 << bit_to_check; + if (ptrn->pattern_mask[pos / PMO_NUM_BITS_IN_BYTE] & + bit_to_check) + new_mask[pos] = PMO_WOW_PTRN_MASK_VALID; + } + + status = pmo_tgt_send_wow_patterns_to_fw(vdev, + ptrn->pattern_id, + ptrn->pattern, + ptrn->pattern_size, + ptrn->pattern_byte_offset, + new_mask, + ptrn->pattern_size, true); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add wow pattern %d", ptrn->pattern_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_core_del_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + vdev_ctx = pmo_vdev_get_priv(vdev); + if (pmo_get_wow_user_ptrn(vdev_ctx) <= 0) { + pmo_err("No valid user pattern. Num user pattern %u", + pmo_get_wow_user_ptrn(vdev_ctx)); + status = QDF_STATUS_E_INVAL; + goto rel_ref; + } + + pmo_debug("Delete user passed wow pattern id %d total user pattern %d", + pattern_id, pmo_get_wow_user_ptrn(vdev_ctx)); + + pmo_tgt_del_wow_pattern(vdev, pattern_id, true); + + /* configure default patterns once all user patterns are deleted */ + if (!pmo_get_wow_user_ptrn(vdev_ctx)) + pmo_register_wow_default_patterns(vdev); +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + +void pmo_core_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t bitmap[PMO_WOW_MAX_EVENT_BM_LEN] = {0}; + + pmo_enter(); + + if (!psoc) { + pmo_err("psoc is null"); + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + goto out; + } + + pmo_set_wow_event_bitmap(wow_event, PMO_WOW_MAX_EVENT_BM_LEN, bitmap); + + pmo_tgt_enable_wow_wakeup_event(vdev, bitmap); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + +out: + pmo_exit(); +} + +void pmo_core_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t bitmap[PMO_WOW_MAX_EVENT_BM_LEN] = {0}; + + if (!psoc) { + pmo_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is NULL"); + return; + } + + pmo_set_wow_event_bitmap(wow_event, PMO_WOW_MAX_EVENT_BM_LEN, bitmap); + + pmo_tgt_disable_wow_wakeup_event(vdev, bitmap); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +} + +/** + * pmo_is_beaconing_vdev_up(): check if a beaconning vdev is up + * @psoc: objmgr psoc handle + * + * Return TRUE if beaconning vdev is up + */ +static +bool pmo_is_beaconing_vdev_up(struct wlan_objmgr_psoc *psoc) +{ + int vdev_id; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE vdev_opmode; + bool is_beaconing; + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + vdev_opmode = pmo_get_vdev_opmode(vdev); + is_beaconing = pmo_is_vdev_in_beaconning_mode(vdev_opmode) && + QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(vdev)); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + + if (is_beaconing) + return true; + } + + return false; +} + +/** + * pmo_support_wow_for_beaconing: wow query for beaconning + * @psoc: objmgr psoc handle + * + * Need to configure wow to enable beaconning offload when + * a beaconing vdev is up and beaonning offload is configured. + * + * Return: true if we need to enable wow for beaconning offload + */ +static +bool pmo_support_wow_for_beaconing(struct wlan_objmgr_psoc *psoc) +{ + /* + * if (wmi_service_enabled(wma->wmi_handle, + * wmi_service_beacon_offload)) + */ + return pmo_is_beaconing_vdev_up(psoc); +} + +bool pmo_core_is_wow_applicable(struct wlan_objmgr_psoc *psoc) +{ + int vdev_id; + struct wlan_objmgr_vdev *vdev; + bool is_wow_applicable = false; + + if (!psoc) { + pmo_err("psoc is null"); + return false; + } + + if (pmo_support_wow_for_beaconing(psoc)) { + pmo_debug("one of vdev is in beaconning mode, enabling wow"); + return true; + } + + if (wlan_reg_is_11d_scan_inprogress(psoc)) { + pmo_debug("11d scan is in progress, enabling wow"); + return true; + } + + if (pmo_core_is_lpass_enabled(psoc)) { + pmo_info("lpass enabled, enabling wow"); + return true; + } + + if (cfg_nan_get_enable(psoc)) { + pmo_debug("nan enabled, enabling wow"); + return true; + } + + /* Iterate through VDEV list */ + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PMO_ID); + if (!vdev) + continue; + + if (wlan_vdev_is_up(vdev) == QDF_STATUS_SUCCESS) { + pmo_debug("STA is connected, enabling wow"); + is_wow_applicable = true; + } else if (ucfg_scan_get_pno_in_progress(vdev)) { + pmo_debug("NLO is in progress, enabling wow"); + is_wow_applicable = true; + } else if (pmo_core_is_extscan_in_progress(vdev)) { + pmo_debug("EXT is in progress, enabling wow"); + is_wow_applicable = true; + } else if (pmo_core_is_p2plo_in_progress(vdev)) { + pmo_debug("P2P LO is in progress, enabling wow"); + is_wow_applicable = true; + } else if (pmo_core_get_vdev_op_mode(vdev) == QDF_NDI_MODE) { + pmo_debug("vdev %d is in NAN data mode, enabling wow", + vdev_id); + is_wow_applicable = true; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + + if (is_wow_applicable) + return true; + } + + pmo_debug("All vdev are in disconnected state\n" + "and pno/extscan is not in progress, skipping wow"); + + return false; +} + +void pmo_set_sta_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) +{ + + pmo_set_wow_event_bitmap(WOW_CSA_IE_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_BMISS_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_GTK_ERR_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_BETTER_AP_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_HTT_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_RA_MATCH_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_NLO_DETECTED_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_EXTSCAN_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_OEM_RESPONSE_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_TDLS_CONN_TRACKER_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_11D_SCAN_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_NLO_SCAN_COMPLETE_EVENT, + wow_bitmap_size, + bitmask); + /* + * WPA3 roaming offloads SAE authentication to wpa_supplicant + * Firmware will send WMI_ROAM_PREAUTH_START_EVENTID + */ + pmo_set_wow_event_bitmap(WOW_ROAM_PREAUTH_START_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_ROAM_PMKID_REQUEST_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_VDEV_DISCONNECT_EVENT, + wow_bitmap_size, + bitmask); + + pmo_set_wow_event_bitmap(WOW_TWT_EVENT, + wow_bitmap_size, + bitmask); + + pmo_set_wow_event_bitmap(WOW_DCS_INTERFERENCE_DET, + wow_bitmap_size, + bitmask); + + pmo_set_wow_event_bitmap(WOW_RTT_11AZ_EVENT, + wow_bitmap_size, bitmask); +} + +void pmo_set_sap_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) +{ + pmo_set_wow_event_bitmap(WOW_CLIENT_KICKOUT_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_PROBE_REQ_WPS_IE_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_AUTH_REQ_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_ASSOC_REQ_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_DEAUTH_RECVD_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_DISASSOC_RECVD_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_HTT_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_SAP_OBSS_DETECTION_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_BSS_COLOR_COLLISION_DETECT_EVENT, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_DCS_INTERFERENCE_DET, + wow_bitmap_size, + bitmask); + pmo_set_wow_event_bitmap(WOW_RTT_11AZ_EVENT, + wow_bitmap_size, bitmask); + pmo_set_wow_event_bitmap(WOW_XGAP_EVENT, + wow_bitmap_size, bitmask); +} + +uint8_t pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + bool apf = false; + bool pkt_filter = false; + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + apf = pmo_intersect_apf(psoc_ctx); + pkt_filter = pmo_intersect_packet_filter(psoc_ctx); + } + + if (!apf && !pkt_filter) + return PMO_WOW_FILTERS_MAX; + + return PMO_WOW_FILTERS_PKT_OR_APF; +} + +#ifdef WLAN_FEATURE_NAN +void pmo_set_ndp_wow_bitmask(uint32_t *bitmask, uint32_t wow_bitmap_size) +{ + /* wake up host when Nan Management Frame is received */ + pmo_set_wow_event_bitmap(WOW_NAN_DATA_EVENT, + wow_bitmap_size, + bitmask); + /* wake up host when NDP data packet is received */ + pmo_set_wow_event_bitmap(WOW_PATTERN_MATCH_EVENT, + wow_bitmap_size, + bitmask); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_apf_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_apf_cfg.h new file mode 100644 index 0000000000..8612b727e9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_apf_cfg.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_APF_CFG_H__ +#define WLAN_PMO_APF_CFG_H__ + +/* + * + * gBpfFilterEnable - APF feature support configuration + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When set to 1 APF feature will be enabled. + * + * Supported Feature: Android packet filter + * + * Usage: External + * + * + */ +#define CFG_PMO_APF_ENABLE CFG_INI_BOOL("gBpfFilterEnable", \ + 1, \ + "Enable APF Support") + +/* + * + * gActiveUcBpfMode - Control UC active APF mode + * @Min: 0 (disabled) + * @Max: 2 (adaptive) + * @Default: 0 (disabled) + * + * This config item controls UC APF in active mode. There are 3 modes: + * 0) disabled - APF is disabled in active mode + * 1) enabled - APF is enabled for all packets in active mode + * 2) adaptive - APF is enabled for packets up to some throughput threshold + * + * Related: gActiveMcBcBpfMode + * + * Supported Feature: Active Mode APF + * + * Usage: Internal/External + * + */ +#define CFG_ACTIVE_UC_APF_MODE CFG_INI_UINT( \ + "gActiveUcBpfMode", \ + ACTIVE_APF_DISABLED, \ + (ACTIVE_APF_MODE_COUNT - 1), \ + ACTIVE_APF_DISABLED, \ + CFG_VALUE_OR_DEFAULT, \ + "Control UC active APF mode") + +/* + * + * gActiveMcBcBpfMode - Control MC/BC active APF mode + * @Min: 0 (disabled) + * @Max: 1 (enabled) + * @Default: 0 (disabled) + * + * This config item controls MC/BC APF in active mode. There are 3 modes: + * 0) disabled - APF is disabled in active mode + * 1) enabled - APF is enabled for all packets in active mode + * 2) adaptive - APF is enabled for packets up to some throughput threshold + * + * Related: gActiveUcBpfMode + * + * Supported Feature: Active Mode APF + * + * Usage: Internal/External + * + */ +#define CFG_ACTIVE_MC_BC_APF_MODE CFG_INI_UINT( \ + "gActiveMcBcBpfMode", \ + ACTIVE_APF_DISABLED, \ + ACTIVE_APF_ENABLED, \ + ACTIVE_APF_DISABLED, \ + CFG_VALUE_OR_DEFAULT, \ + "Control MC/BC active APF mode") + +#define CFG_PMO_APF_ALL \ + CFG(CFG_PMO_APF_ENABLE) \ + CFG(CFG_ACTIVE_UC_APF_MODE) \ + CFG(CFG_ACTIVE_MC_BC_APF_MODE) + +#endif /* WLAN_PMO_APF_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h new file mode 100644 index 0000000000..6265bae807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_arp_public_struct.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo arp offload feature. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_ARP_PUBLIC_STRUCT_H_ +#define _WLAN_PMO_ARP_PUBLIC_STRUCT_H_ + +#include "wlan_pmo_common_public_struct.h" + +/** + * struct pmo_arp_req - pmo arp request + * @psoc: objmgr psoc + * @vdev_id: vdev id on which arp offload needed + * @ipv4_addr: ipv4 address for the interface + * @trigger: context from where arp offload triggered + */ +struct pmo_arp_req { + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + uint32_t ipv4_addr; + enum pmo_offload_trigger trigger; +}; + +/** + * struct pmo_arp_offload_params - pmo arp offload param for target interface + * @enable: true when arp offload is enabled else false + * @host_ipv4_addr: host interface ipv4 address + * @bssid: peer ap address + * @is_offload_applied: Has offload been applied to the target + */ +struct pmo_arp_offload_params { + uint8_t enable; + uint8_t host_ipv4_addr[QDF_IPV4_ADDR_SIZE]; + struct qdf_mac_addr bssid; + bool is_offload_applied; +}; + +#endif /* end of _WLAN_PMO_ARP_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_cfg.h new file mode 100644 index 0000000000..beebe66c5b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_cfg.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_CFG_H__ +#define WLAN_PMO_CFG_H__ + +#include "wlan_pmo_apf_cfg.h" +#include "wlan_pmo_common_cfg.h" +#include "wlan_pmo_extwow_cfg.h" +#include "wlan_pmo_pkt_filter_cfg.h" +#include "wlan_pmo_runtime_pm_cfg.h" +#include "wlan_pmo_wow_pulse_cfg.h" +#include "wlan_pmo_gpio_wakeup_cfg.h" + +#define CFG_PMO_ALL \ + CFG_EXTWOW_ALL \ + CFG_PACKET_FILTER_ALL \ + CFG_PMO_APF_ALL \ + CFG_PMO_COMMON_ALL \ + CFG_RUNTIME_PM_ALL \ + CFG_WOW_PULSE_ALL \ + CFG_GPIO_WAKEUP_ALL + +#endif /* WLAN_PMO_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h new file mode 100644 index 0000000000..4fc27d6202 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_cfg.h @@ -0,0 +1,802 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_COMMON_CFG_H__ +#define WLAN_PMO_COMMON_CFG_H__ + +#include "wlan_pmo_common_public_struct.h" + +#ifdef CONNECTION_ROAMING_CFG +# define CONDTIMSKIPPING_NUMBER_MIN 0 +# define CONDTIMSKIPPING_NUMBER_MAX 10 +# define CONDTIMSKIPPING_NUMBER_DEFAULT 3 +#else +# define CONDTIMSKIPPING_NUMBER_MIN 0 +# define CONDTIMSKIPPING_NUMBER_MAX 10 +# define CONDTIMSKIPPING_NUMBER_DEFAULT 0 +#endif + +/* + * + * hostArpOffload - Enable/disable host ARP offload + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable firmware's capability of sending ARP + * response to clients. + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_HOST_ARPOFFLOAD CFG_INI_BOOL( \ + "hostArpOffload", \ + 1, \ + "enable/disable host ARP offload") + +/* + * + * gHwFilterMode - configure hardware filter for DTIM mode + * @Min: 0 + * @Max: 3 + * @Default: 1 + * + * The hardware filter is only effective in DTIM mode. Use this configuration + * to blanket drop broadcast/multicast packets at the hardware level, without + * waking up the firmware + * + * Takes a bitmap of frame types to drop + * @E.g. + * # disable feature + * gHwFilterMode=0 + * # drop all broadcast frames, except ARP (default) + * gHwFilterMode=1 + * # drop all multicast frames, except ICMPv6 + * gHwFilterMode=2 + * # drop all broadcast and multicast frames, except ARP and ICMPv6 + * gHwFilterMode=3 + * + * Related: N/A + * + * Usage: Internal/External + * + * + */ +#define CFG_PMO_HW_FILTER_MODE CFG_INI_UINT( \ + "gHwFilterMode", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "hardware filter for DTIM mode") + +/* + * + * ssdp - Enable/disable SSDP + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable Simple Service Discovery Protocol(SSDP). + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_HOST_SSDP CFG_INI_BOOL( \ + "ssdp", \ + 1, \ + "Enable/disable ssdp") + +/* + * + * hostNSOffload - Enable/disable NS offload + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable NS offload. + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_HOST_NSOFFLOAD CFG_INI_BOOL( \ + "hostNSOffload", \ + 1, \ + "Enable/disable NS offload") + +/* + * + * CFG_PMO_ENABLE_IGMP_OFFLOAD - Enable/disable igmp offload + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable igmp offload feature to fw. + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_IGMP_OFFLOAD CFG_INI_BOOL( \ + "igmp_offload_enable", \ + 0, \ + "Enable/disable IGMP offload") + +/* + * + * gEnableDynamicDTIM - Enable Dynamic DTIM + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to enable/disable dynamic DTIM. + * + * 0 - Disable Dynamic DTIM + * 1 to 10 - SLM will switch to DTIM specified here when host suspends and + * switch DTIM1 when host resumes + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_DYNAMIC_DTIM CFG_INI_UINT( \ + "gEnableDynamicDTIM", \ + 0, \ + 10, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable Dynamic DTIM") + +/* + * + * gEnableModulatedDTIM/ConDTIMSkipping_Number - Enable/Disable modulated DTIM + * feature + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to enable/disable modulated DTIM feature. + * + * 0 - Disable modulated DTIM. + * 1 to 10 - The maximum No. of modulated DTIM period used for calculating the + * target listen interval. + * + * The target listen interval will be updated to firmware when host driver is + * setting the suspend DTIM parameters. + * + * This configuration will be ignored when dynamic DTIM is enabled(by + * gEnableDynamicDTIM). + * + * Usage: External + * + * + */ + +/* + * + * gEnableModulatedDTIM/ConDTIMSkipping_Number - Enable/Disable modulated DTIM + * feature + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to enable/disable modulated DTIM feature. + * + * 0 - Disable modulated DTIM. + * 1 to 10 - The maximum No. of modulated DTIM period used for calculating the + * target listen interval. + * + * The target listen interval will be updated to firmware when host driver is + * setting the suspend DTIM parameters. + * + * This configuration will be ignored when dynamic DTIM is enabled(by + * gEnableDynamicDTIM). + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_MODULATED_DTIM CFG_INI_UINT( \ + "gEnableModulatedDTIM ConDTIMSkipping_Number", \ + CONDTIMSKIPPING_NUMBER_MIN, \ + CONDTIMSKIPPING_NUMBER_MAX, \ + CONDTIMSKIPPING_NUMBER_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable/disable modulated DTIM feature") + +/* + * + * gMCAddrListEnable - Enable/disable multicast MAC address list feature + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable multicast MAC address list feature. + * Default: Enable + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_PMO_MC_ADDR_LIST_ENABLE CFG_INI_BOOL( \ + "gMCAddrListEnable", \ + 1, \ + "Enable/disable multicast MAC address list feature") + +/* + * + * gOptimizedPowerManagement - Optimized Power Management + * @Min: 0 + * @Max: 2 + * @Default: 1 + * + * This ini is used to set Optimized Power Management configuration: + * Current values of gOptimizedPowerManagement: + * 0 -> Disable optimized power management + * 1 -> Enable optimized power management + * 2 -> User Defined + * + * Related: None + * + * Supported Feature: Optimized Power Management + * + * Usage: External + * + * + */ +#define CFG_PMO_POWERSAVE_MODE CFG_INI_UINT( \ + "gOptimizedPowerManagement", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Optimized Power Management") + +/* + * + * enable_mod_dtim_on_system_suspend - enable modulated DTIM + * on system suspend display off case + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to set modulated DTIM configuration: + * Current values of enable_mod_dtim_on_system_suspend: + * 0 -> Modulated DTIM will be enabled for every wow entry + * (RTPM wow + System suspend wow) + * 1 -> Enable modulated DTIM only for System suspend wow. + * For RTPM wow, the device will stay in DTIM 1 (non-modulated DTIM) + * + * Related: None + * + * Supported Feature: Modulated DTIM + * + * Usage: External + * + * + */ +#define CFG_PMO_MOD_DTIM_ON_SYS_SUSPEND CFG_INI_BOOL( \ + "enable_mod_dtim_on_system_suspend", \ + 0, \ + "Modulated DTIM on System suspend wow") + +/* + * + * gEnableForcedDTIM - Enable/Disable forced DTIM feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable forced DTIM feature. + * + * 0 - Disable forced DTIM. + * 1 - Enable forced DTIM + * + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_FORCED_DTIM CFG_INI_BOOL( \ + "gEnableForcedDTIM", \ + 0, \ + "Enable/disable Forced DTIM feature") + +/* + * + * gMaxPsPoll - Max powersave poll + * @Min: 0 + * @Max: 255 + * @Default: 0 + * + * This ini is used to set max powersave poll. + * + * Usage: External + * + * + */ +#define CFG_PMO_MAX_PS_POLL CFG_INI_UINT( \ + "gMaxPsPoll", \ + 0, \ + 255, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Max powersave poll") + +/* + * + * gEnableWoW - Enable/Disable WoW + * @Min: 0 + * @Max: 3 + * @Default: 3 + * + * This ini is used to enable/disable WoW. Configurations are as follows: + * 0 - Disable both magic pattern match and pattern byte match. + * 1 - Enable magic pattern match on all interfaces. + * 2 - Enable pattern byte match on all interfaces. + * 3 - Enable both magic pattern and pattern byte match on all interfaces. + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_ENABLE CFG_INI_UINT("gEnableWoW", \ + 0, 3, 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable WoW Support") + +/* + * + * gSuspendMode - Suspend mode configuration + * @Min: 0 + * @Max: 3 + * @Default: 2 + * + * This ini is used to set suspend mode. Configurations are as follows: + * 0 - Does not support suspend. + * 1 - Legency suspend mode, PDEV suspend. + * 2 - WOW suspend mode. + * 3 - Shutdown wlan while suspend. + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_PMO_SUSPEND_MODE CFG_INI_UINT("gSuspendMode", \ + 0, 3, 2, \ + CFG_VALUE_OR_DEFAULT, \ + "Suspend mode") + +/* + * + * gActiveModeOffload - Active offload mode configuration + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * When set to 1 active mode offload will be enabled. + * + * If active mode offload is enabled then all applicable data offload/filtering + * is enabled immediately in FW once config is available in WLAN driver and FW + * caches this configuration across suspend/resume; + * If active mode offload is disabled then all applicable data offload/filtering + * is enabled during cfg80211 suspend and disabled during cfg80211 resume. + * + * Supported Feature: Active mode offload + * + * Usage: External + * + * + */ +#define CFG_PMO_ACTIVE_MODE CFG_INI_BOOL("gActiveModeOffload", \ + 1, \ + "Enable active mode offload") + +/* + * + * g_auto_detect_power_failure_mode - Auto detect power save failure mode + * @Min: PMO_FW_TO_CRASH_ON_PWR_FAILURE + * @Max: PMO_AUTO_PWR_FAILURE_DETECT_DISABLE + * @Default: PMO_FW_TO_CRASH_ON_PWR_FAILURE + * + * Specifies the behavior of FW in case of CHIP_POWER_SAVE_FAIL_DETECTED event + * + * Supported Feature: Auto detect power save failure + * + * Usage: External + * + * + */ +#define CFG_PMO_PWR_FAILURE CFG_INI_UINT("g_auto_detect_power_failure_mode", \ + PMO_FW_TO_CRASH_ON_PWR_FAILURE, \ + PMO_AUTO_PWR_FAILURE_DETECT_DISABLE, \ + PMO_FW_TO_CRASH_ON_PWR_FAILURE, \ + CFG_VALUE_OR_DEFAULT, \ + "Auto detect power save failure mode") + +/* + * + * gEnableSapSuspend - Enable/disable SAP Suspend + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * + * Related: None + * + * Supported Feature: SAP + * + * Usage: External + * + * + */ +#define CFG_ENABLE_SAP_SUSPEND CFG_INI_BOOL( \ + "gEnableSapSuspend", \ + 1, \ + "Enable/disable SAP Suspend") + +/* + * + * g_wow_data_inactivity_timeout - Data activity timeout in wow mode. + * @Min: 1 + * @Max: 255 + * @Default: 50 + * + * This ini is used to set data inactivity timeout in wow mode and + * the value is honored in firmware when User defined OPM is set + * + * Supported Feature: inactivity timeout in wow mode + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT CFG_INI_UINT( \ + "g_wow_data_inactivity_timeout", \ + 1, \ + 255, \ + 50, \ + CFG_VALUE_OR_DEFAULT, \ + "Data activity timeout in wow mode") +/* + * + * g_wow_spec_wake_interval - OPM Speculative wake interval in wow mode. + * @Min: 0 + * @Max: 255 + * @Default: 0 + * + * This ini is used to set OPM speculative wake interval in wow mode and + * the value is honored in firmware when User defined OPM is set + * + * Supported Feature: OPM Speculative wake interval in wow mode + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_SPEC_WAKE_INTERVAL CFG_INI_UINT( \ + "g_wow_spec_wake_interval", \ + 0, \ + 255, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Speculative wake interval in wow mode") +/* + * + * gRArateLimitInterval - RA rate limit interval + * @Min: 60 + * @Max: 3600 + * @Default: 60 + * This ini is used to set RA rate limit interval. + * + * Usage: External + * + * + */ +#define CFG_RA_RATE_LIMIT_INTERVAL CFG_INI_UINT( \ + "gRArateLimitInterval", \ + 60, \ + 3600, \ + 60, \ + CFG_VALUE_OR_DEFAULT, \ + "RA rate limit interval") + +/* + * + * enable_bus_suspend_in_sap_mode - enable PCIe bus suspend as part of + * platform system suspend for SAP with one or more clients connected + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to PCIe bus suspend as part of platform system suspend for + * SAP with one or more clients connected + * + * 0: PCIe Bus suspend is not supported in SAP mode with one or more clients + * connected + * 1: PCIe Bus suspend is supported in SAP mode with one or more clients + * connected + * Related: SAP clients connected bus suspend(D3 WoW) is only supported + * when IPA is disabled + * + * Supported Feature: Power Save + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_BUS_SUSPEND_IN_SAP_MODE CFG_INI_BOOL( \ + "enable_bus_suspend_in_sap_mode", \ + 1, \ + "This ini is used to enable bus suspend in SAP mode") + +/* + * + * enable_bus_suspend_in_go_mode - enable PCIe bus suspend as part of + * platform system suspend for P2PGO with one or more clients connected + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to PCIe bus suspend as part of platform system suspend for + * P2PGO with one or more clients connected + * + * 0: PCIe Bus suspend is not supported in P2PGO mode with one or more clients + * connected + * 1: PCIe Bus suspend is supported in P2PGO mode with one or more clients + * connected + * Related: P2P GO clients connected bus suspend(D3 WoW) is only supported + * when IPA is disabled + * + * Supported Feature: Power Save + * + * Usage: Internal + * + * + */ +#define CFG_ENABLE_BUS_SUSPEND_IN_GO_MODE CFG_INI_BOOL( \ + "enable_bus_suspend_in_go_mode", \ + 1, \ + "This ini is used to enable bus suspend in P2PGO mode") + +/* + * + * igmp_version_support - Configure igmp version + * @Min: 0x00000000 + * @Max: 0x7 + * @Default: 0x7 + * + * This ini is used to configure version while offloading igmp + * + * Bit 0: support igmp version 1 + * Bit 1: support igmp version 2 + * Bit 2: support igmp version 3 + */ +#define CFG_IGMP_VERSION_SUPPORT CFG_INI_UINT( \ + "igmp_version_support", \ + 0x00000000, \ + 0x7, \ + 0x7, \ + CFG_VALUE_OR_DEFAULT, \ + "configure igmp offload support version") + +/* + * + * disconnect_sap_tdls_in_wow - disconnect sap tdls in wow + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Due to the limitation on third party platform, add ini to take + * special care of the below wow case to avoid fw crash. + * The sap/p2p_go shall kick out all the connected sta/p2p_gc and + * then go to suspend considering d0wow/d3wow is not supported. + * Teardown tdls link proactively since auto sleep mechanism not + * supported. + * + * Usage: External + * + * + */ +#define CFG_DISCONNECT_SAP_TDLS_IN_WOW CFG_INI_BOOL( \ + "disconnect_sap_tdls_in_wow", \ + 0, \ + "disconnect sap tdls in wow") + +/* + * + * action_on_page_fault - Host action on page fault wakeup event + * @Min: PMO_PF_HOST_ACTION_NO_OP + * @Max: PMO_PF_HOST_ACTION_MAX - 1 + * @Default: PMO_PF_HOST_ACTION_NO_OP + * + * This INI is used to determine host behavior on WOW_REASON_PAGE_FAULT wakeup + * event. + * For ex: If action is to trigger SSR, min_pagefault_wakeups_for_action = 30, + * interval_for_pagefault_wakeup_counts = 180000 (3 mins) and + * ssr_frequency_on_pagefault = 3600000 (1hr), in this case host will trigger + * the SSR if it receives 30 wakeups because of pagefaults in 3 mins, host will + * trigger SSR only once in 1 hr. Once the SSR is triggered, host will not + * trigger next SSR for next 1 hr even if it receives 30 wakeups from fw because + * of pagefaults. This 1 hr time is getting monitored from last SSR. + * + * + */ +#define CFG_HOST_ACTION_ON_PAGEFAULT CFG_INI_UINT( \ + "action_on_page_fault", \ + PMO_PF_HOST_ACTION_NO_OP, \ + PMO_PF_HOST_ACTION_MAX - 1, \ + PMO_PF_HOST_ACTION_NO_OP, \ + CFG_VALUE_OR_DEFAULT, \ + "Host action on FW pagefault event") + +/* + * + * min_pagefault_wakeups_for_action - Min number of pagefaults wakeups to + * initiate host action. + * @Min: 2 + * @Max: 255 + * @Default: 30 + * + * This ini is used to get the count of max pagefault wakeups to reach before + * host takes action. + * If the count is reached within the wakeup time interval host will either + * trigger SSR (within the limits of SSR trigger freq) or may notify APPS or + * ignore if no action is set. + * For ex: If SSR on pagefault = 1, min_pagefault_wakeups_for_action = 30, + * interval_for_pagefault_wakeup_counts = 180000 (3 mins) and + * ssr_frequency_on_pagefault = 3600000 (1hr), in this case host will trigger + * the SSR if it receives 30 wakeups because of pagefaults in 3 mins, host will + * trigger SSR only once in 1 hr. Once the SSR is triggered, host will not + * trigger next SSR for next 1 hr even if it receives 30 wakeups from fw because + * of pagefaults. This 1 hr time is getting monitored from last SSR. + */ +#define CFG_MIN_PAGEFAULT_WAKEUPS_FOR_ACTION CFG_INI_UINT( \ + "min_pagefault_wakeups_for_action", \ + 2, \ + 255, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "Max number of pagefaults wakeups to trigger SSR") + +/* + * + * interval_for_pagefault_wakeup_counts - Time in ms in which + * min_pagefault_wakeups_for_action needs to be monitored + * @Min: 60000 (1min) + * @Max: 18000000 (5hrs) + * @Default: 180000 (3 mins) + * + * This ini define time in ms in which min_pagefault_wakeups_for_host action + * needs to be monitored. If in interval_for_pagefault_wakeup_counts ms, + * min_pagefault_wakeups_for_action is reached host will trigger the action. + * SSR is triggered only once in ssr_frequency_on_pagefault interval. + * For ex: If SSR on pagefault = 1, min_pagefault_wakeups_for_action = 30, + * interval_for_pagefault_wakeup_counts = 180000 (3 mins) and + * ssr_frequency_on_pagefault = 3600000 (1hr), in this case host will trigger + * the SSR if it receives 30 wakeups because of pagefaults in 3 mins, host will + * trigger SSR only once in 1 hr. Once the SSR is triggered, host will not + * trigger next SSR for next 1 hr even if it receives 30 wakeups from fw because + * of pagefaults. This 1 hr time is getting monitored from last SSR. + */ +#define CFG_INTERVAL_FOR_PAGEFAULT_WAKEUP_COUNT CFG_INI_UINT( \ + "interval_for_pagefault_wakeup_counts", \ + 60000, \ + 18000000, \ + 180000, \ + CFG_VALUE_OR_DEFAULT, \ + "Interval in which min_pagefault_wakeups_for_ssr needs to be monitored") + +/* + * + * ssr_frequency_on_pagefault - Time in ms in which host needs to trigger the + * next SSR + * @Min: 60000 + * @Max: 7200000 + * @Default: 3600000 (1 hr) + * + * This ini define time in ms in which next SSR needs to be triggered if + * min_pagefault_wakeups_for_action is reached in + * interval_for_pagefault_wakeup_counts time. + * INIs max_pagefault_wakeups_for_ssr, interval_for_pagefault_wakeup_counts and + * ssr_frequency_on_pagefault needs to be considered together. + * For ex: If enable_ssr_on_page_fault = 1, min_pagefault_wakeups_for_ssr = 30, + * interval_for_pagefault_wakeup_counts = 180000 (3 mins) and + * ssr_frequency_on_pagefault = 3600000 (1hr), in this case host will trigger + * the SSR if it receives 30 wakeups because of pagefaults in 3 mins, host will + * trigger SSR only once in 1 hr. Once the SSR is triggered, host will not + * trigger next SSR for next 1 hr even if it receives 30 wakeups from fw because + * of pagefaults. This 1 hr time is getting monitored from last SSR. + */ +#define CFG_SSR_FREQUENCY_ON_PAGEFAULT CFG_INI_UINT( \ + "ssr_frequency_on_pagefault", \ + 60000, \ + 7200000, \ + 3600000, \ + CFG_VALUE_OR_DEFAULT, \ + "Interval in which min_pagefault_wakeups_for_ssr needs to be monitored") + +/* + * + * gEnableIcmpOffload - Enable/disable ICMP offload + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable firmware's capability of sending ICMP + * response to clients. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_ENABLE_ICMP_OFFLOAD CFG_INI_BOOL( \ + "gEnableIcmpOffload", \ + 0, \ + "enable/disable ICMP offload") + +#define CFG_PMO_COMMON_ALL \ + CFG(CFG_ENABLE_SAP_SUSPEND) \ + CFG(CFG_PMO_ENABLE_HOST_ARPOFFLOAD) \ + CFG(CFG_PMO_HW_FILTER_MODE) \ + CFG(CFG_PMO_ENABLE_HOST_SSDP) \ + CFG(CFG_PMO_ENABLE_HOST_NSOFFLOAD) \ + CFG(CFG_PMO_ENABLE_IGMP_OFFLOAD) \ + CFG(CFG_PMO_ENABLE_DYNAMIC_DTIM) \ + CFG(CFG_PMO_ENABLE_MODULATED_DTIM) \ + CFG(CFG_PMO_ENABLE_FORCED_DTIM) \ + CFG(CFG_PMO_MC_ADDR_LIST_ENABLE) \ + CFG(CFG_PMO_POWERSAVE_MODE) \ + CFG(CFG_PMO_MAX_PS_POLL) \ + CFG(CFG_PMO_WOW_ENABLE) \ + CFG(CFG_PMO_SUSPEND_MODE) \ + CFG(CFG_PMO_ACTIVE_MODE) \ + CFG(CFG_PMO_PWR_FAILURE) \ + CFG(CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT) \ + CFG(CFG_PMO_WOW_SPEC_WAKE_INTERVAL) \ + CFG(CFG_RA_RATE_LIMIT_INTERVAL) \ + CFG(CFG_PMO_MOD_DTIM_ON_SYS_SUSPEND) \ + CFG(CFG_ENABLE_BUS_SUSPEND_IN_SAP_MODE) \ + CFG(CFG_ENABLE_BUS_SUSPEND_IN_GO_MODE)\ + CFG(CFG_DISCONNECT_SAP_TDLS_IN_WOW) \ + CFG(CFG_IGMP_VERSION_SUPPORT) \ + CFG(CFG_ENABLE_ICMP_OFFLOAD) \ + CFG(CFG_HOST_ACTION_ON_PAGEFAULT) \ + CFG(CFG_MIN_PAGEFAULT_WAKEUPS_FOR_ACTION) \ + CFG(CFG_INTERVAL_FOR_PAGEFAULT_WAKEUP_COUNT) \ + CFG(CFG_SSR_FREQUENCY_ON_PAGEFAULT) + +#endif /* WLAN_PMO_COMMON_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h new file mode 100644 index 0000000000..5765877233 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_common_public_struct.h @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which are common for + * various pmo related features. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_COMMONP_PUBLIC_STRUCT_H_ +#define _WLAN_PMO_COMMONP_PUBLIC_STRUCT_H_ + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_global_obj.h" +#include "wmi_unified.h" +#include "qdf_status.h" +#include "qdf_lock.h" +#include "qdf_event.h" +#include "wlan_pmo_hw_filter_public_struct.h" + + +#define PMO_IPV4_ARP_REPLY_OFFLOAD 0 +#define PMO_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 +#define PMO_IPV6_NS_OFFLOAD 2 +#define PMO_OFFLOAD_DISABLE 0 +#define PMO_OFFLOAD_ENABLE 1 + +#define PMO_MAC_NS_OFFLOAD_SIZE 1 +#define PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA 16 +#define PMO_IPV6_ADDR_VALID 1 +#define PMO_IPV6_ADDR_UC_TYPE 0 +#define PMO_IPV6_ADDR_AC_TYPE 1 + + +#define PMO_WOW_REQUIRED_CREDITS 1 + +#define MAX_MC_IP_ADDR 10 +#define IGMP_QUERY_ADDRESS 0x10000e0 + +#define WOW_LARGE_RX_RTPM_DELAY 1200 + +/** + * enum pmo_vdev_param_id: tell vdev param id + * @pmo_vdev_param_listen_interval: vdev listen interval param id + * @pmo_vdev_param_dtim_policy: vdev param dtim policy + * @pmo_vdev_param_forced_dtim_count: vdev param forced dtim count + * @pmo_vdev_param_moddtim: vdev param moddtim + * @pmo_vdev_max_param: Max vdev param id + */ +enum pmo_vdev_param_id { + pmo_vdev_param_listen_interval = 0, + pmo_vdev_param_dtim_policy, + pmo_vdev_param_forced_dtim_count, + pmo_vdev_param_moddtim, + pmo_vdev_max_param +}; + +/** + * enum pmo_beacon_dtim_policy: tell vdev beacon policy + * @pmo_ignore_dtim: fwr need to igonre dtime policy + * @pmo_normal_dtim: fwr need to use normal dtime policy + * @pmo_stick_dtim: fwr need to use stick dtime policy + * @pmo_auto_dtim: fwr need to auto dtime policy + */ +enum pmo_beacon_dtim_policy { + pmo_ignore_dtim = 0x01, + pmo_normal_dtim = 0x02, + pmo_stick_dtim = 0x03, + pmo_auto_dtim = 0x04, +}; + +/** + * enum pmo_sta_powersave_param - STA powersave parameters + * @pmo_sta_ps_param_rx_wake_policy: Controls how frames are retrievd from AP + * while STA is sleeping. + * @pmo_sta_ps_param_tx_wake_threshold: STA will go active after this many TX + * @pmo_sta_ps_param_pspoll_count:No of PS-Poll to send before STA wakes up + * @pmo_sta_ps_param_inactivity_time: TX/RX inactivity time in msec before + * going to sleep. + * @pmo_sta_ps_param_uapsd: Set uapsd configuration. + * @pmo_sta_ps_param_advanced_power_pspoll_count: No of PS-Poll to send before + * STA wakes up in Advanced Power Save Mode. + * @pmo_sta_ps_enable_advanced_power: Enable Advanced Power Save + * @pmo_sta_ps_param_advanced_power_max_tx_before_wake: Number of TX frames + * before the entering the Active state + * @pmo_sta_ps_param_ito_repeat_count: Indicates ito repeated count + * @pmo_sta_ps_param_spec_wake_interval: OPM speculative wake interval + */ +enum pmo_sta_powersave_param { + pmo_sta_ps_param_rx_wake_policy = 0, + pmo_sta_ps_param_tx_wake_threshold = 1, + pmo_sta_ps_param_pspoll_count = 2, + pmo_sta_ps_param_inactivity_time = 3, + pmo_sta_ps_param_uapsd = 4, + pmo_sta_ps_param_advanced_power_pspoll_count = 5, + pmo_sta_ps_enable_advanced_power = 6, + pmo_sta_ps_param_advanced_power_max_tx_before_wake = 7, + pmo_sta_ps_param_ito_repeat_count = 8, + pmo_sta_ps_param_spec_wake_interval = 9, +}; + +/** + * enum pmo_wow_resume_trigger - resume trigger override setting values + * @PMO_WOW_RESUME_TRIGGER_DEFAULT: fw to use platform default resume trigger + * @PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP: force fw to use HTC Wakeup to resume + * @PMO_WOW_RESUME_TRIGGER_GPIO: force fw to use GPIO to resume + * @PMO_WOW_RESUME_TRIGGER_COUNT: number of resume trigger options + */ +enum pmo_wow_resume_trigger { + /* always first */ + PMO_WOW_RESUME_TRIGGER_DEFAULT = 0, + PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP, + PMO_WOW_RESUME_TRIGGER_GPIO, + /* always last */ + PMO_WOW_RESUME_TRIGGER_COUNT +}; + +/** + * enum pmo_wow_interface_pause - interface pause override setting values + * @PMO_WOW_INTERFACE_PAUSE_DEFAULT: use platform default iface pause setting + * @PMO_WOW_INTERFACE_PAUSE_ENABLE: force interface pause setting to enabled + * @PMO_WOW_INTERFACE_PAUSE_DISABLE: force interface pause setting to disabled + * @PMO_WOW_INTERFACE_PAUSE_COUNT: number of interface pause options + */ +enum pmo_wow_interface_pause { + /* always first */ + PMO_WOW_INTERFACE_PAUSE_DEFAULT = 0, + PMO_WOW_INTERFACE_PAUSE_ENABLE, + PMO_WOW_INTERFACE_PAUSE_DISABLE, + /* always last */ + PMO_WOW_INTERFACE_PAUSE_COUNT +}; + +/** + * enum pmo_wow_enable_type - used to enable/disable WoW. + * @PMO_WOW_DISABLE_BOTH: Disable both magic pattern match and pattern + * byte match. + * @PMO_WOW_ENABLE_MAGIC_PATTERN: Enable magic pattern match on all interfaces. + * @PMO_WOW_ENABLE_PATTERN_BYTE: Enable pattern byte match on all interfaces. + * @PMO_WOW_ENABLE_BOTH: Enable both magic pattern and pattern byte match on + * all interfaces. + */ +enum pmo_wow_enable_type { + PMO_WOW_DISABLE_BOTH = 0, + PMO_WOW_ENABLE_MAGIC_PATTERN, + PMO_WOW_ENABLE_PATTERN_BYTE, + PMO_WOW_ENABLE_BOTH +}; + +/** + * enum powersave_mode - powersave_mode + * @PMO_PS_ADVANCED_POWER_SAVE_DISABLE: Disable advanced power save mode + * @PMO_PS_ADVANCED_POWER_SAVE_ENABLE: Enable power save mode + * @PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED: User Defined + */ +enum powersave_mode { + PMO_PS_ADVANCED_POWER_SAVE_DISABLE = 0, + PMO_PS_ADVANCED_POWER_SAVE_ENABLE = 1, + PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED = 2 +}; + +/** + * enum pmo_suspend_mode - suspend_mode + * @PMO_SUSPEND_NONE: Does not support suspend + * @PMO_SUSPEND_LEGENCY: Legency PDEV suspend mode + * @PMO_SUSPEND_WOW: WoW suspend mode + * @PMO_SUSPEND_SHUTDOWN: Shutdown suspend mode. Shutdown while suspend + */ +enum pmo_suspend_mode { + PMO_SUSPEND_NONE = 0, + PMO_SUSPEND_LEGENCY, + PMO_SUSPEND_WOW, + PMO_SUSPEND_SHUTDOWN +}; + +#define PMO_TARGET_SUSPEND_TIMEOUT (4000) +#define PMO_WAKE_LOCK_TIMEOUT 1000 +#define PMO_RESUME_TIMEOUT (4000) + +/** + * struct pmo_wow_enable_params - A collection of wow enable override parameters + * @is_unit_test: true to notify fw this is a unit-test suspend + * @interface_pause: used to override the interface pause indication sent to fw + * @resume_trigger: used to force fw to use a particular resume method + */ +struct pmo_wow_enable_params { + bool is_unit_test; + enum pmo_wow_interface_pause interface_pause; + enum pmo_wow_resume_trigger resume_trigger; +}; + +/** + * typedef pmo_psoc_suspend_handler() - psoc suspend handler + * @psoc: psoc being suspended + * @arg: iterator argument + * + * Return: QDF_STATUS_SUCCESS if suspended, QDF_STATUS_E_* if failure + */ +typedef QDF_STATUS(*pmo_psoc_suspend_handler) + (struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * typedef pmo_psoc_resume_handler() - psoc resume handler + * @psoc: psoc being resumed + * @arg: iterator argument + * + * Return: QDF_STATUS_SUCCESS if resumed, QDF_STATUS_E_* if failure + */ +typedef QDF_STATUS (*pmo_psoc_resume_handler) + (struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * enum pmo_offload_trigger: trigger information + * @pmo_apps_suspend: trigger is apps suspend + * @pmo_apps_resume: trigger is apps resume + * @pmo_runtime_suspend: trigger is runtime suspend + * @pmo_runtime_resume: trigger is runtime resume + * @pmo_ipv4_change_notify: trigger is ipv4 change handler + * @pmo_ipv6_change_notify: trigger is ipv6 change handler + * @pmo_mc_list_change_notify: trigger is multicast list change + * @pmo_ns_offload_dynamic_update: enable/disable ns offload on the fly + * @pmo_peer_disconnect: trigger is peer disconnect + * @pmo_mcbc_setting_dynamic_update: mcbc value update on the fly + * @pmo_arp_ns_offload_dynamic_update: enable/disable arp/ns offload on the fly + * + * @pmo_offload_trigger_max: Max trigger value + */ +enum pmo_offload_trigger { + pmo_apps_suspend = 0, + pmo_apps_resume, + pmo_runtime_suspend, + pmo_runtime_resume, + pmo_ipv4_change_notify, + pmo_ipv6_change_notify, + pmo_mc_list_change_notify, + pmo_ns_offload_dynamic_update, + pmo_peer_disconnect, + pmo_mcbc_setting_dynamic_update, + pmo_arp_ns_offload_dynamic_update, + + pmo_offload_trigger_max, +}; + +/** + * enum pmo_auto_pwr_detect_failure_mode - auto detect failure modes + * @PMO_FW_TO_CRASH_ON_PWR_FAILURE: Don't register wow wakeup event and FW + * crashes on power failure + * @PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE: Register wow wakeup event and FW + * sends failure event to host on power failure + * @PMO_FW_TO_REJUVENATE_ON_PWR_FAILURE: Don't register wow wakeup event and + * FW silently rejuvenate on power failure + * @PMO_AUTO_PWR_FAILURE_DETECT_DISABLE: Don't register wow wakeup event and the + * auto power failure detect feature is disabled in FW. + */ +enum pmo_auto_pwr_detect_failure_mode { + PMO_FW_TO_CRASH_ON_PWR_FAILURE, + PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE, + PMO_FW_TO_REJUVENATE_ON_PWR_FAILURE, + PMO_AUTO_PWR_FAILURE_DETECT_DISABLE +}; + +/** + * enum active_apf_mode - the modes active APF can operate in + * @ACTIVE_APF_DISABLED: APF is disabled in active mode + * @ACTIVE_APF_ENABLED: APF is enabled for all packets + * @ACTIVE_APF_ADAPTIVE: APF is enabled for packets up to some threshold + * @ACTIVE_APF_MODE_COUNT: The number of active APF modes + */ +enum active_apf_mode { + ACTIVE_APF_DISABLED = 0, + ACTIVE_APF_ENABLED, + ACTIVE_APF_ADAPTIVE, + ACTIVE_APF_MODE_COUNT +}; + +/** + * enum pmo_gpio_wakeup_mode - gpio wakeup mode + * @PMO_GPIO_WAKEUP_MODE_INVALID: gpio wakeup trigger invalid + * @PMO_GPIO_WAKEUP_MODE_RISING: gpio wakeup trigger rising + * @PMO_GPIO_WAKEUP_MODE_FALLING: gpio wakeup trigger failing + * @PMO_GPIO_WAKEUP_MODE_HIGH: gpio wakeup trigger high + * @PMO_GPIO_WAKEUP_MODE_LOW: gpio wakeup trigger low + */ +enum pmo_gpio_wakeup_mode { + PMO_GPIO_WAKEUP_MODE_INVALID, + PMO_GPIO_WAKEUP_MODE_RISING, + PMO_GPIO_WAKEUP_MODE_FALLING, + PMO_GPIO_WAKEUP_MODE_HIGH, + PMO_GPIO_WAKEUP_MODE_LOW, +}; + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +#define ICMP_MAX_IPV6_ADDRESS 16 + +/** + * struct pmo_icmp_offload - structure to hold icmp param + * + * @vdev_id: vdev id + * @enable: enable/disable + * @trigger: icmp offload trigger information + * @ipv6_count: number of host ipv6 address + * @ipv4_addr: host interface ipv4 address + * @ipv6_addr: array of host ipv6 address + * + **/ +struct pmo_icmp_offload { + uint8_t vdev_id; + bool enable; + enum pmo_offload_trigger trigger; + uint8_t ipv6_count; + uint8_t ipv4_addr[QDF_IPV4_ADDR_SIZE]; + uint8_t ipv6_addr[ICMP_MAX_IPV6_ADDRESS][QDF_IPV6_ADDR_SIZE]; +}; +#endif + +/* + * enum pmo_page_fault_action - Host action on FW page fault + * @PMO_PF_HOST_ACTION_NO_OP: Host will ignore PF wakeup event. + * @PMO_PF_HOST_ACTION_TRIGGER_SSR: Host will trigger SSR on PF threshold. + * @PMO_PF_HOST_ACTION_NOTIFY_APPS: Host will notify APPS on PF threshold. + * + * @PMO_PF_HOST_ACTION_MAX: Reserved and invalid value + */ +enum pmo_page_fault_action { + PMO_PF_HOST_ACTION_NO_OP = 0, + PMO_PF_HOST_ACTION_TRIGGER_SSR = 1, + PMO_PF_HOST_ACTION_NOTIFY_APPS = 2, + + /* Keep it last */ + PMO_PF_HOST_ACTION_MAX, +}; + +/** + * struct pmo_psoc_cfg - user configuration required for pmo + * @ptrn_match_enable_all_vdev: true when pattern match is enable for all vdev + * @apf_enable: true if psoc supports apf else false + * @arp_offload_enable: true if arp offload is supported for psoc else false + * @hw_filter_mode_bitmap: which mode the hardware filter should use during DTIM + * @ns_offload_enable_static: true if psoc supports ns offload in ini else false + * @ns_offload_enable_dynamic: to enable / disable the ns offload using + * ioctl or vendor command. + * @packet_filter_enabled: true if feature is enabled by configuration + * @ssdp: true if psoc supports if ssdp configuration in wow mode + * @enable_mc_list: true if psoc supports mc addr list else false + * @active_mode_offload: true if psoc supports active mode offload else false + * @ap_arpns_support: true if psoc supports arp ns for ap mode + * @d0_wow_supported: true if psoc supports D0 wow command + * @ra_ratelimit_enable: true when ra filtering ins eanbled else false + * @ra_ratelimit_interval: ra packets interval + * @magic_ptrn_enable: true when magic pattern is enabled else false + * @deauth_enable: true when wake up on deauth is enabled else false + * @disassoc_enable: true when wake up on disassoc is enabled else false + * @lpass_enable: true when lpass is enabled else false + * @max_ps_poll: max power save poll + * @sta_dynamic_dtim: station dynamic DTIM value + * @sta_mod_dtim: station modulated DTIM value + * @sta_max_li_mod_dtim: station max listen interval DTIM value + * @sta_forced_dtim: station forced DTIM value + * @wow_enable: enable wow with majic pattern match or pattern byte match + * @power_save_mode: power save mode for psoc + * @default_power_save_mode: default power save mode for psoc + * @suspend_mode: suspend mode for psoc + * @runtime_pm_delay: set runtime pm's inactivity timer + * @extwow_goto_suspend: true when extended WoW enabled else false + * @extwow_app1_wakeup_pin_num: set wakeup1 PIN number + * @extwow_app2_wakeup_pin_num: set wakeup2 PIN number + * @extwow_app2_init_ping_interval: set keep alive init ping interval + * @extwow_app2_min_ping_interval: set keep alive minimum ping interval + * @extwow_app2_max_ping_interval: set keep alive maximum ping interval + * @extwow_app2_inc_ping_interval: set keep alive increment ping interval + * @extwow_app2_tcp_src_port: set TCP source port + * @extwow_app2_tcp_dst_port: set TCP dest port + * @extwow_app2_tcp_tx_timeout: set TCP TX timeout + * @extwow_app2_tcp_rx_timeout: set TCP RX timeout + * @auto_power_save_fail_mode: auto detect power save failure + * @is_wow_pulse_supported: true when wow pulse feature is enabled else false + * @wow_pulse_pin: GPIO pin of wow pulse feature + * @wow_pulse_interval_high: The interval of high level in the pulse + * @wow_pulse_interval_low: The interval of low level in the pulse + * @wow_pulse_repeat_count: Pulse repeat count + * @wow_pulse_init_state: Pulse init level + * @packet_filters_bitmap: Packet filter bitmap configuration + * @enable_sap_suspend: enable SoftAP suspend + * @wow_data_inactivity_timeout: power save wow data inactivity timeout + * wow mode + * @wow_spec_wake_interval: OPM speculatvie wkae interval in wow mode + * @active_uc_apf_mode: Setting that determines how APF is applied in active + * mode for uc packets + * @active_mc_bc_apf_mode: Setting that determines how APF is applied in + * active mode for MC/BC packets + * @ito_repeat_count: Indicates ito repeated count + * @is_mod_dtim_on_sys_suspend_enabled: true when mod dtim is enabled for + * system suspend wow else false + * @is_bus_suspend_enabled_in_sap_mode: Can bus suspend in SoftAP mode + * @is_bus_suspend_enabled_in_go_mode: Can bus suspend in P2P GO mode + * @enable_gpio_wakeup: enable gpio wakeup + * @gpio_wakeup_pin: gpio wakeup pin + * @gpio_wakeup_mode: gpio wakeup mode + * @igmp_version_support: igmp version support + * @igmp_offload_enable: enable/disable igmp offload feature to fw + * @disconnect_sap_tdls_in_wow: sap/p2p_go disconnect or teardown tdls link + * @is_icmp_offload_enable: true if icmp offload is supported + * for psoc else false + * @host_pf_action: Action to take on page fault + * @min_pagefault_wakeups_for_action: Min number of pagefaults after which + * host needs to start act upon. + * @interval_for_pagefault_wakeup_counts: Time in ms in which max pagefault + * wakeups needs to be monitored. + * @ssr_frequency_on_pagefault: Time in ms in which SSR needs to be triggered + * on max pagefault + */ +struct pmo_psoc_cfg { + bool ptrn_match_enable_all_vdev; + bool apf_enable; + bool arp_offload_enable; + enum pmo_hw_filter_mode hw_filter_mode_bitmap; + bool ns_offload_enable_static; + bool ns_offload_enable_dynamic; + bool packet_filter_enabled; + bool ssdp; + bool enable_mc_list; + bool active_mode_offload; + bool ap_arpns_support; + bool d0_wow_supported; + bool ra_ratelimit_enable; +#ifdef FEATURE_WLAN_RA_FILTERING + uint16_t ra_ratelimit_interval; +#endif + bool magic_ptrn_enable; + bool deauth_enable; + bool disassoc_enable; + bool lpass_enable; + uint8_t max_ps_poll; + uint8_t sta_dynamic_dtim; + uint8_t sta_mod_dtim; + uint8_t sta_max_li_mod_dtim; + bool sta_forced_dtim; + enum pmo_wow_enable_type wow_enable; + enum powersave_mode power_save_mode; + enum powersave_mode default_power_save_mode; + enum pmo_suspend_mode suspend_mode; +#ifdef FEATURE_RUNTIME_PM + uint32_t runtime_pm_delay; +#endif +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + bool extwow_goto_suspend; + uint8_t extwow_app1_wakeup_pin_num; + uint8_t extwow_app2_wakeup_pin_num; + uint32_t extwow_app2_init_ping_interval; + uint32_t extwow_app2_min_ping_interval; + uint32_t extwow_app2_max_ping_interval; + uint32_t extwow_app2_inc_ping_interval; + uint16_t extwow_app2_tcp_src_port; + uint16_t extwow_app2_tcp_dst_port; + uint32_t extwow_app2_tcp_tx_timeout; + uint32_t extwow_app2_tcp_rx_timeout; +#endif + enum pmo_auto_pwr_detect_failure_mode auto_power_save_fail_mode; +#ifdef WLAN_FEATURE_WOW_PULSE + bool is_wow_pulse_supported; + uint8_t wow_pulse_pin; + uint16_t wow_pulse_interval_high; + uint16_t wow_pulse_interval_low; + uint32_t wow_pulse_repeat_count; + uint32_t wow_pulse_init_state; +#endif +#ifdef WLAN_FEATURE_PACKET_FILTERING + uint8_t packet_filters_bitmap; +#endif + bool enable_sap_suspend; + uint8_t wow_data_inactivity_timeout; + uint8_t wow_spec_wake_interval; + enum active_apf_mode active_uc_apf_mode; + enum active_apf_mode active_mc_bc_apf_mode; + uint8_t ito_repeat_count; + bool is_mod_dtim_on_sys_suspend_enabled; + bool is_bus_suspend_enabled_in_sap_mode; + bool is_bus_suspend_enabled_in_go_mode; +#ifdef WLAN_ENABLE_GPIO_WAKEUP + bool enable_gpio_wakeup; + uint32_t gpio_wakeup_pin; + enum pmo_gpio_wakeup_mode gpio_wakeup_mode; +#endif +#ifdef WLAN_FEATURE_IGMP_OFFLOAD + uint32_t igmp_version_support; + bool igmp_offload_enable; +#endif + bool disconnect_sap_tdls_in_wow; +#ifdef WLAN_FEATURE_ICMP_OFFLOAD + bool is_icmp_offload_enable; +#endif + enum pmo_page_fault_action host_pf_action; + uint8_t min_pagefault_wakeups_for_action; + uint32_t interval_for_pagefault_wakeup_counts; + uint32_t ssr_frequency_on_pagefault; +}; + +/** + * struct pmo_device_caps - device capability flags (true if feature is + * supported) + * @apf: Android Packet Filter (aka BPF) + * @arp_ns_offload: APR/NS offload + * @packet_filter: Legacy "Packet Filter" + * @unified_wow: Firmware supports "interface pause" flag in WoW command. + * This allows both D0-WoW (bus up) and Non-D0-WoW (bus down) to use one + * unified command + * @li_offload: Firmware has listen interval offload support + */ +struct pmo_device_caps { + bool apf; + bool arp_ns_offload; + bool packet_filter; + bool unified_wow; + bool li_offload; +}; + +/** + * struct pmo_igmp_offload_req - structure to hold igmp param + * + * @vdev_id: vdev id + * @enable: enable/disable + * @version_support: version support + * @num_grp_ip_address: num grp ip addr + * @grp_ip_address: array of grp_ip_address + * + **/ +struct pmo_igmp_offload_req { + uint32_t vdev_id; + bool enable; + uint32_t version_support; + uint32_t num_grp_ip_address; + uint32_t grp_ip_address[MAX_MC_IP_ADDR]; +}; + +/** + * struct pmo_ps_params - structure to hold OPM params + * + * @opm_mode: OPM mode + * @ps_ito: power save inactivity timeout + * @spec_wake: OPM speculative wake interval + */ +struct pmo_ps_params { + enum powersave_mode opm_mode; + uint16_t ps_ito; + uint16_t spec_wake; +}; +#endif /* end of _WLAN_PMO_COMMONP_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_extwow_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_extwow_cfg.h new file mode 100644 index 0000000000..94f01304c5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_extwow_cfg.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_EXTWOW_CFG_H__ +#define WLAN_PMO_EXTWOW_CFG_H__ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/* + * + * gExtWoWgotoSuspend - Enable/Disable Extended WoW + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable Extended WoW. + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_GOTO_SUSPEND CFG_INI_BOOL("gExtWoWgotoSuspend", \ + 1, \ + "Enable Ext WoW goto support") +/* + * + * gExtWowApp1WakeupPinNumber - Set wakeup1 PIN number + * @Min: 0 + * @Max: 255 + * @Default: 12 + * + * This ini is used to set EXT WOW APP1 wakeup PIN number + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_APP1_WAKE_PIN_NUMBER \ + CFG_INI_UINT("gExtWowApp1WakeupPinNumber", \ + 0, 255, 12, \ + CFG_VALUE_OR_DEFAULT, \ + "Set wakeup1 PIN number") +/* + * + * gExtWowApp2WakeupPinNumber - Set wakeup2 PIN number + * @Min: 0 + * @Max: 255 + * @Default: 16 + * + * This ini is used to set EXT WOW APP2 wakeup PIN number + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_APP2_WAKE_PIN_NUMBER \ + CFG_INI_UINT("gExtWowApp2WakeupPinNumber", \ + 0, 255, 16, \ + CFG_VALUE_OR_DEFAULT, \ + "Set wakeup2 PIN number") +/* + * + * gExtWoWApp2KAInitPingInterval - Set Keep Alive Init Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 240 + * + * This ini is used to set Keep Alive Init Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_INIT_PING_INTERVAL \ + CFG_INI_UINT("gExtWoWApp2KAInitPingInterval", \ + 0, 0xffffffff, 240, \ + CFG_VALUE_OR_DEFAULT, \ + "Set Keep Alive Init Ping Interval") +/* + * + * gExtWoWApp2KAMinPingInterval - Set Keep Alive Minimum Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 240 + * + * This ini is used to set Keep Alive Minimum Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_MIN_PING_INTERVAL \ + CFG_INI_UINT("gExtWoWApp2KAMinPingInterval", \ + 0, 0xffffffff, 240, \ + CFG_VALUE_OR_DEFAULT, \ + "Set Keep Alive Minimum Ping Interval") +/* + * + * gExtWoWApp2KAMaxPingInterval - Set Keep Alive Maximum Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 1280 + * + * This ini is used to set Keep Alive Maximum Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_MAX_PING_INTERVAL \ + CFG_INI_UINT("gExtWoWApp2KAMaxPingInterval", \ + 0, 0xffffffff, 1280, \ + CFG_VALUE_OR_DEFAULT, \ + "Set Keep Alive Maximum Ping Interval") +/* + * + * gExtWoWApp2KAIncPingInterval - Set Keep Alive increment of Ping Interval + * @Min: 0 + * @Max: 0xffffffff + * @Default: 4 + * + * This ini is used to set Keep Alive increment of Ping Interval for EXT WOW + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_KA_INC_PING_INTERVAL \ + CFG_INI_UINT("gExtWoWApp2KAIncPingInterval", \ + 0, 0xffffffff, 4, \ + CFG_VALUE_OR_DEFAULT, \ + "Set Keep Alive increment of Ping Interval") +/* + * + * gExtWoWApp2TcpSrcPort - Set TCP source port + * @Min: 0 + * @Max: 65535 + * @Default: 5000 + * + * This ini is used to set TCP source port when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_SRC_PORT \ + CFG_INI_UINT("gExtWoWApp2TcpSrcPort", \ + 0, 65535, 5000, \ + CFG_VALUE_OR_DEFAULT, \ + "Set TCP source port") +/* + * + * gExtWoWApp2TcpDstPort - Set TCP Destination port + * @Min: 0 + * @Max: 65535 + * @Default: 5001 + * + * This ini is used to set TCP Destination port when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_DST_PORT \ + CFG_INI_UINT("gExtWoWApp2TcpDstPort", \ + 0, 65535, 5001, \ + CFG_VALUE_OR_DEFAULT, \ + "Set TCP Destination port") +/* + * + * gExtWoWApp2TcpTxTimeout - Set TCP tx timeout + * @Min: 0 + * @Max: 0xffffffff + * @Default: 200 + * + * This ini is used to set TCP Tx timeout when EXT WOW is enabled + * + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_TX_TIMEOUT \ + CFG_INI_UINT("gExtWoWApp2TcpTxTimeout", \ + 0, 0xffffffff, 200, \ + CFG_VALUE_OR_DEFAULT, \ + "Set TCP tx timeout") + +/* + * + * gExtWoWApp2TcpRxTimeout - Set TCP rx timeout + * @Min: 0 + * @Max: 0xffffffff + * @Default: 200 + * + * This ini is used to set TCP Rx timeout when EXT WOW is enabled + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_EXTWOW_TCP_RX_TIMEOUT \ + CFG_INI_UINT("gExtWoWApp2TcpRxTimeout", \ + 0, 0xffffffff, 200, \ + CFG_VALUE_OR_DEFAULT, \ + "ExtWow App2 tcp rx timeout") + +#define CFG_EXTWOW_ALL \ + CFG(CFG_EXTWOW_GOTO_SUSPEND) \ + CFG(CFG_EXTWOW_APP1_WAKE_PIN_NUMBER) \ + CFG(CFG_EXTWOW_APP2_WAKE_PIN_NUMBER) \ + CFG(CFG_EXTWOW_KA_INIT_PING_INTERVAL) \ + CFG(CFG_EXTWOW_KA_MIN_PING_INTERVAL) \ + CFG(CFG_EXTWOW_KA_MAX_PING_INTERVAL) \ + CFG(CFG_EXTWOW_KA_INC_PING_INTERVAL) \ + CFG(CFG_EXTWOW_TCP_SRC_PORT) \ + CFG(CFG_EXTWOW_TCP_DST_PORT) \ + CFG(CFG_EXTWOW_TCP_TX_TIMEOUT) \ + CFG(CFG_EXTWOW_TCP_RX_TIMEOUT) +#else +#define CFG_EXTWOW_ALL +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ +#endif /* WLAN_PMO_EXTWOW_CFG_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gpio_wakeup_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gpio_wakeup_cfg.h new file mode 100644 index 0000000000..163aeb489c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gpio_wakeup_cfg.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_GPIO_WAKEUP_CFG_H__ +#define WLAN_PMO_GPIO_WAKEUP_CFG_H__ + +#ifdef WLAN_ENABLE_GPIO_WAKEUP +/* + * + * genable_gpio_wakeup - Enable gpio wakeup + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Enable gpio wakeup + * + * Supported Feature: gpio wakeup + * + * Usage: External + * + * + */ +#define CFG_PMO_ENABLE_GPIO_WAKEUP CFG_INI_BOOL("genable_gpio_wakeup", \ + 0, \ + "Enable gpio wakeup") + +/* + * + * ggpio_wakeup_pin - Wakeup gpio pin of host platform + * @Min: 0 + * @Max: 255 + * @Default: 255 + * + * Wakeup gpio pin of host platform + * + * Supported Feature: gpio wakeup + * + * Usage: External + * + * + */ +#define CFG_PMO_GPIO_WAKEUP_PIN CFG_INI_UINT("ggpio_wakeup_pin", \ + 0, 255, 255, \ + CFG_VALUE_OR_DEFAULT, \ + "Wakeup gpio pin of host platform") + +/* + * + * ggpio_wakeup_mode - Wakeup gpio mode + * @Min: 0 + * @Max: 4 + * @Default: 0 + * + * Wakeup gpio mode + * 1 indicates rising trigger + * 2 indicates failing trigger + * 3 indicates high trigger + * 4 indicates low trigger + * + * Supported Feature: gpio wakeup + * + * Usage: External + * + * + */ +#define CFG_PMO_GPIO_WAKEUP_MODE CFG_INI_UINT("ggpio_wakeup_mode", \ + 0, 4, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Wakeup gpio mode") + +#define CFG_GPIO_WAKEUP_ALL \ + CFG(CFG_PMO_ENABLE_GPIO_WAKEUP) \ + CFG(CFG_PMO_GPIO_WAKEUP_PIN) \ + CFG(CFG_PMO_GPIO_WAKEUP_MODE) +#else +#define CFG_GPIO_WAKEUP_ALL +#endif /* WLAN_ENABLE_GPIO_WAKEUP */ +#endif /* WLAN_PMO_GPIO_WAKEUP_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gtk_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gtk_public_struct.h new file mode 100644 index 0000000000..c661e2919c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_gtk_public_struct.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo gtk related feature. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_GTK_PUBLIC_STRUCT_H +#define _WLAN_PMO_GTK_PUBLIC_STRUCT_H + +#include "wlan_pmo_common_public_struct.h" + +#define PMO_GTK_OFFLOAD_ENABLE 0 +#define PMO_GTK_OFFLOAD_DISABLE 1 +#define PMO_KEK_LEN 64 +#define PMO_KCK_LEN 32 +#define PMO_REPLAY_COUNTER_LEN 8 +#define PMO_MAC_MAX_KEY_LENGTH 32 +#define PMO_IGTK_PN_SIZE 6 + +/** + * struct pmo_gtk_req - pmo gtk request + * @flags: optional flags + * @kck: Key confirmation key + * @kck_len: Key confirmation key length + * @kek: key encryption key + * @kek_len: KEK Length + * @replay_counter: replay_counter + * @bssid: bssid + * @is_fils_connection: is current connection with peer FILS or not. + */ +struct pmo_gtk_req { + uint32_t flags; + uint8_t kck[PMO_KCK_LEN]; + uint8_t kck_len; + uint8_t kek[PMO_KEK_LEN]; + uint32_t kek_len; + uint64_t replay_counter; + struct qdf_mac_addr bssid; + bool is_fils_connection; +}; + +/** + * struct pmo_gtk_rsp_params - pmo gtk response + * @vdev_id: vdev id on which arp offload needed + * @status_flag: status flags + * @refresh_cnt: number of successful GTK refresh exchanges since SET operation + * @replay_counter:GTK replay counter + * @igtk_key_index: igtk key index + * @igtk_key_length: igtk key length + * @igtk_key_rsc: igtk key index + * @igtk_key: igtk key length + * @bssid: BSSID + */ +struct pmo_gtk_rsp_params { + uint8_t vdev_id; + uint32_t status_flag; + uint32_t refresh_cnt; + uint64_t replay_counter; + uint8_t igtk_key_index; + uint8_t igtk_key_length; + uint8_t igtk_key_rsc[PMO_IGTK_PN_SIZE]; + uint8_t igtk_key[PMO_MAC_MAX_KEY_LENGTH]; + struct qdf_mac_addr bssid; +}; + +/** + * typedef pmo_gtk_rsp_callback() - gtk response callback + * @callback_context: client context + * @gtk_rsp: GTK response + */ +typedef void (*pmo_gtk_rsp_callback)(void *callback_context, + struct pmo_gtk_rsp_params *gtk_rsp); + +/** + * struct pmo_gtk_rsp_req - gtk respsonse request + * @callback: client callback for providing gtk response when fwr send event + * @callback_context: client callback response + */ +struct pmo_gtk_rsp_req { + pmo_gtk_rsp_callback callback; + void *callback_context; +}; + +#endif /* end of _WLAN_PMO_GTK_PUBLIC_STRUCT_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_hw_filter_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_hw_filter_public_struct.h new file mode 100644 index 0000000000..b7bb96f961 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_hw_filter_public_struct.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file shall contain all public parameter (struct/macro/enum) + * definitions to support hardware filtering configuration. No APIs, or + * implementations of APIs, shall be contained within. + */ + +#ifndef _WLAN_PMO_HW_FILTER_PUBLIC_STRUCT_H +#define _WLAN_PMO_HW_FILTER_PUBLIC_STRUCT_H + +/** + * enum pmo_hw_filter_mode - bitmap for enabled hardware filters + * @PMO_HW_FILTER_DISABLED: hardware filter is completely disabled + * @PMO_HW_FILTER_NON_ARP_BC: drop all broadcast frames, except ARP + * @PMO_HW_FILTER_NON_ICMPV6_MC: drop all multicast frames, except ICMPv6 + * + * The hardware filter is only effective in DTIM mode. Use this configuration + * to blanket drop broadcast/multicast packets at the hardware level, without + * waking up the firmware. + */ +enum pmo_hw_filter_mode { + PMO_HW_FILTER_DISABLED = 0, + PMO_HW_FILTER_NON_ARP_BC = (1 << 0), + PMO_HW_FILTER_NON_ICMPV6_MC = (1 << 1), +}; + +/** + * struct pmo_hw_filter_params - hardware filter configuration parameters + * @vdev_id: Id of the virtual device to configure + * @enable: Enable/Disable the given hw filter modes + * @mode_bitmap: the hardware filter mode bitmap to configure + */ +struct pmo_hw_filter_params { + uint8_t vdev_id; + bool enable; + enum pmo_hw_filter_mode mode_bitmap; +}; + +#endif /* _WLAN_PMO_HW_FILTER_PUBLIC_STRUCT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_lphb_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_lphb_public_struct.h new file mode 100644 index 0000000000..8959bd20e2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_lphb_public_struct.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo lphb offload feature. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_LPHB_PUBLIC_STRUCT_H_ +#define _WLAN_PMO_LPHB_PUBLIC_STRUCT_H_ + +#include "wlan_pmo_common_public_struct.h" + +#define PMO_SIR_LPHB_FILTER_LEN 64 + +/** + * enum lphb_ind_type -Low power heart beat indication type + * @pmo_lphb_set_en_param_indid: lphb enable indication + * @pmo_lphb_set_tcp_pararm_indid: lphb tcp param indication + * @pmo_lphb_set_tcp_pkt_filter_indid: lphb tcp packet filter indication + * @pmo_lphb_set_udp_pararm_indid: lphb udp param indication + * @pmo_lphb_set_udp_pkt_filter_indid: lphb udp packet filter indication + * @pmo_lphb_set_network_info_indid: lphb network information indication + */ +enum lphb_ind_type { + pmo_lphb_set_en_param_indid, + pmo_lphb_set_tcp_pararm_indid, + pmo_lphb_set_tcp_pkt_filter_indid, + pmo_lphb_set_udp_pararm_indid, + pmo_lphb_set_udp_pkt_filter_indid, + pmo_lphb_set_network_info_indid, +}; + +/** + * struct pmo_lphb_enable_req -Low power heart beat enable request + * @enable: lphb enable request + * @item: request item + * @session: lphb session + */ +struct pmo_lphb_enable_req { + uint8_t enable; + uint8_t item; + uint8_t session; +}; + +/** + * struct pmo_lphb_tcp_params - Low power heart beat tcp params + * @srv_ip: source ip address + * @dev_ip: destination ip address + * @src_port: source port + * @dst_port: destination port + * @timeout: tcp timeout value + * @session: session on which lphb needs to be configured + * @gateway_mac: gateway mac address + * @time_period_sec: time period in seconds + * @tcp_sn: tcp sequence number + */ +struct pmo_lphb_tcp_params { + uint32_t srv_ip; + uint32_t dev_ip; + uint16_t src_port; + uint16_t dst_port; + uint16_t timeout; + uint8_t session; + struct qdf_mac_addr gateway_mac; + uint16_t time_period_sec; + uint32_t tcp_sn; +}; + +/** + * struct pmo_lphb_tcp_filter_req - Low power heart beat tcp filter request + * @length: length of filter + * @offset: offset of filter + * @session: session on which lphb needs to be configured + * @filter: filter buffer + */ +struct pmo_lphb_tcp_filter_req { + uint16_t length; + uint8_t offset; + uint8_t session; + uint8_t filter[PMO_SIR_LPHB_FILTER_LEN]; +}; + +/** + * struct pmo_lphb_udp_params - Low power heart beat udp params + * @srv_ip: source ip address + * @dev_ip: destination ip address + * @src_port: source port + * @dst_port: destination port + * @interval: time period in seconds + * @timeout: tcp timeout value + * @session: session on which lphb needs to be configured + * @gateway_mac: gateway mac address + */ +struct pmo_lphb_udp_params { + uint32_t srv_ip; + uint32_t dev_ip; + uint16_t src_port; + uint16_t dst_port; + uint16_t interval; + uint16_t timeout; + uint8_t session; + struct qdf_mac_addr gateway_mac; +}; + +/** + * struct pmo_lphb_udp_filter_req - Low power heart beat udp filter request + * @length: length of filter + * @offset: offset of filter + * @session: session on which lphb needs to be configured + * @filter: filter buffer + */ +struct pmo_lphb_udp_filter_req { + uint16_t length; + uint8_t offset; + uint8_t session; + uint8_t filter[PMO_SIR_LPHB_FILTER_LEN]; +}; + +/** + * struct pmo_lphb_req - Low power heart beat request + * @cmd: lphb command type + * @dummy: whether dummy or not + * @params: based on command lphb request buffer + */ +struct pmo_lphb_req { + uint16_t cmd; + uint16_t dummy; + union { + struct pmo_lphb_enable_req lphb_enable_req; + struct pmo_lphb_tcp_params lphb_tcp_params; + struct pmo_lphb_tcp_filter_req lphb_tcp_filter_req; + struct pmo_lphb_udp_params lphb_udp_params; + struct pmo_lphb_udp_filter_req lphb_udp_filter_req; + } params; +}; + +/** + * struct pmo_lphb_rsp - Low power heart beat response + * @session_idx: session id + * @protocol_type: tell protocol type + * @event_reason: carry reason of lphb event + */ +struct pmo_lphb_rsp { + uint8_t session_idx; + uint8_t protocol_type; /*TCP or UDP */ + uint8_t event_reason; +}; + +/* + * Define typedef for lphb callback when fwr send response + */ +typedef +void (*pmo_lphb_callback)(void *cb_ctx, struct pmo_lphb_rsp *ind_param); + +#endif /* end of _WLAN_PMO_LPHB_PUBLIC_STRUCT_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_mc_addr_filtering_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_mc_addr_filtering_public_struct.h new file mode 100644 index 0000000000..1d9afc8bf9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_mc_addr_filtering_public_struct.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo mc address filterign related features. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_MC_ADDR_FILTERING_STRUCT_H_ +#define _WLAN_PMO_MC_ADDR_FILTERING_STRUCT_H_ + +#include "wlan_pmo_common_public_struct.h" + +#define PMO_MAX_MC_ADDR_LIST 32 +#define PMO_MAX_NUM_MULTICAST_ADDRESS 240 + +/** + * struct pmo_mc_addr_list_params -pmo mc address list request params + * @psoc: objmgr psoc + * @vdev_id: vdev id on which arp offload needed + * @count: multicast address count + * @mc_addr: multicast address array + */ +struct pmo_mc_addr_list_params { + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + int count; + struct qdf_mac_addr mc_addr[PMO_MAX_MC_ADDR_LIST]; +}; + +/** + * struct pmo_mc_addr_list - pmo mc address list params for vdev + * @is_filter_applied: is mc list filter applied on vdev + * @mc_cnt: mc address count + * @mc_addr:mc address list + */ +struct pmo_mc_addr_list { + uint8_t is_filter_applied; + uint8_t mc_cnt; + struct qdf_mac_addr mc_addr[PMO_MAX_MC_ADDR_LIST]; +}; + +/** + * struct pmo_mcast_filter_params - mcast filter parameters + * @multicast_addr_cnt: num of addresses + * @multicast_addr: address array + * @action: operation to perform + */ +struct pmo_mcast_filter_params { + uint32_t multicast_addr_cnt; + struct qdf_mac_addr multicast_addr[PMO_MAX_NUM_MULTICAST_ADDRESS]; + uint8_t action; +}; +#endif /* end of _WLAN_PMO_MC_ADDR_FILTERING_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h new file mode 100644 index 0000000000..6e785f16ea --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ns_public_struct.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo ns offload feature. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_NS_PUBLIC_STRUCT_H_ +#define _WLAN_PMO_NS_PUBLIC_STRUCT_H_ + +#include "wlan_pmo_common_public_struct.h" + +/** + * enum pmo_ns_addr_scope - Internal identification of IPv6 addr scope + * @PMO_NS_ADDR_SCOPE_INVALID: invalid scope + * @PMO_NS_ADDR_SCOPE_NODELOCAL: node local scope + * @PMO_NS_ADDR_SCOPE_LINKLOCAL: link local scope + * @PMO_NS_ADDR_SCOPE_SITELOCAL: site local scope + * @PMO_NS_ADDR_SCOPE_ORGLOCAL: org local scope + * @PMO_NS_ADDR_SCOPE_GLOBAL: global scope + */ +enum pmo_ns_addr_scope { + PMO_NS_ADDR_SCOPE_INVALID = 0, + PMO_NS_ADDR_SCOPE_NODELOCAL = 1, + PMO_NS_ADDR_SCOPE_LINKLOCAL = 2, + PMO_NS_ADDR_SCOPE_SITELOCAL = 3, + PMO_NS_ADDR_SCOPE_ORGLOCAL = 4, + PMO_NS_ADDR_SCOPE_GLOBAL = 5 +}; + +/** + * struct pmo_ns_offload_params - pmo ns offload parameters + * @enable: true when ns offload enable + * @num_ns_offload_count: total ns entries + * @src_ipv6_addr: in request source ipv 6 address + * @self_ipv6_addr: self ipv6 address + * @target_ipv6_addr: target ipv6 address + * @self_macaddr: self mac address + * @src_ipv6_addr_valid: true if source ipv6 address is valid else false + * @target_ipv6_addr_valid: target ipv6 address are valid or not + * @target_ipv6_addr_ac_type: target ipv6 address type (unicast or anycast) + * @slot_idx: slot index + * @bssid: BSSID + * @scope: scope + * @is_offload_applied: has the offload been applied to firmware + */ +struct pmo_ns_offload_params { + uint8_t enable; + uint32_t num_ns_offload_count; + uint8_t src_ipv6_addr[QDF_IPV6_ADDR_SIZE]; + uint8_t self_ipv6_addr[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [QDF_IPV6_ADDR_SIZE]; + uint8_t target_ipv6_addr[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [QDF_IPV6_ADDR_SIZE]; + struct qdf_mac_addr self_macaddr; + uint8_t src_ipv6_addr_valid; + uint8_t target_ipv6_addr_valid[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t target_ipv6_addr_ac_type[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + uint8_t slot_idx; + struct qdf_mac_addr bssid; + enum pmo_ns_addr_scope scope[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + bool is_offload_applied; +}; + +/** + * struct pmo_ns_req - pmo ns request + * @psoc: objmgr psoc + * @vdev_id: vdev id on which arp offload needed + * @trigger: context from where arp offload triggered + * @count: ns entries count + * @ipv6_addr: ipv6 address array + * @ipv6_addr_type: ipv6 address type (unicast/anycast) array + * @scope: scope + */ +struct pmo_ns_req { + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + enum pmo_offload_trigger trigger; + uint32_t count; + uint8_t ipv6_addr[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA] + [QDF_IPV6_ADDR_SIZE]; + uint8_t ipv6_addr_type[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; + enum pmo_ns_addr_scope scope[PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA]; +}; +#endif /* end of _WLAN_PMO_NS_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h new file mode 100644 index 0000000000..f49bf0cb2f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_api.h @@ -0,0 +1,563 @@ +/* + * Copyright (c) 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare utility API related to the pmo component + * called by other components + */ + +#ifndef _WLAN_PMO_OBJ_MGMT_API_H_ +#define _WLAN_PMO_OBJ_MGMT_API_H_ + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD +/** + * pmo_init() - initialize pmo_ctx context. + * + * This function initializes the power manager offloads (a.k.a pmo) context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS pmo_init(void); + +/** + * pmo_deinit() - De initialize pmo_ctx context. + * + * This function De initializes power manager offloads (a.k.a pmo) context. + * + * Return: QDF_STATUS_SUCCESS - in case of success else return error + */ +QDF_STATUS pmo_deinit(void); + +/** + * pmo_psoc_object_created_notification(): pmo psoc create handler + * @psoc: psoc which is going to created by objmgr + * @arg: argument for vdev create handler + * + * PMO, register this api with objmgr to detect psoc is created in fwr + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS pmo_psoc_object_created_notification(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * pmo_psoc_object_destroyed_notification(): pmo psoc delete handler + * @psoc: psoc which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * PMO, register this api with objmgr to detect psoc is deleted in fwr + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS pmo_psoc_object_destroyed_notification(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * pmo_vdev_object_created_notification(): pmo vdev create handler + * @vdev: vdev which is going to created by objmgr + * @arg: argument for vdev create handler + * + * PMO, register this api with objmgr to detect vdev is created in fwr + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS pmo_vdev_object_created_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * pmo_vdev_ready() - handles vdev ready in firmware event + * @vdev: vdev which is ready in firmware + * @bridgeaddr: Bridge MAC address + * + * Objmgr vdev_create event does not guarantee vdev creation in firmware. + * Any logic that would normally go in the vdev_create event, but needs to + * communicate with firmware, needs to go here instead. + * + * Return QDF_STATUS + */ +QDF_STATUS pmo_vdev_ready(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr); + +/** + * pmo_vdev_object_destroyed_notification(): pmo vdev delete handler + * @vdev: vdev which is going to delete by objmgr + * @arg: argument for vdev delete handler + * + * PMO, register this api with objmgr to detect vdev is deleted in fwr + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS pmo_vdev_object_destroyed_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * pmo_register_suspend_handler(): register suspend handler for components + * @id: component id + * @handler: resume handler for the mention component + * @arg: argument to pass while calling resume handler + * + * Return QDF_STATUS status -in case of success else return error + */ +QDF_STATUS pmo_register_suspend_handler(enum wlan_umac_comp_id id, + pmo_psoc_suspend_handler handler, + void *arg); + +/** + * pmo_unregister_suspend_handler():unregister suspend handler for components + * @id: component id + * @handler: resume handler for the mention component + * + * Return QDF_STATUS status -in case of success else return error + */ +QDF_STATUS pmo_unregister_suspend_handler(enum wlan_umac_comp_id id, + pmo_psoc_suspend_handler handler); + +/** + * pmo_register_resume_handler(): API to register resume handler for components + * @id: component id + * @handler: resume handler for the mention component + * @arg: argument to pass while calling resume handler + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_register_resume_handler(enum wlan_umac_comp_id id, + pmo_psoc_resume_handler handler, + void *arg); + +/** + * pmo_unregister_resume_handler(): unregister resume handler for components + * @id: component id + * @handler: resume handler for the mention component + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_unregister_resume_handler(enum wlan_umac_comp_id id, + pmo_psoc_resume_handler handler); + +/** + * pmo_suspend_all_components(): API to suspend all component + * @psoc:objmgr psoc + * @suspend_type: Tell suspend type (apps suspend / runtime suspend) + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type suspend_type); + +/** + * pmo_resume_all_components(): API to resume all component + * @psoc:objmgr psoc + * @suspend_type: Tell suspend type from which resume is required + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type suspend_type); + +/** + * pmo_register_pause_bitmap_notifier(): API to register pause bitmap notifier + * @psoc: objmgr psoc handle + * @handler: pause bitmap updated notifier + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc, + pmo_notify_pause_bitmap handler); + +/** + * pmo_unregister_pause_bitmap_notifier(): API to unregister pause bitmap + * notifier + * @psoc: objmgr psoc handle + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_unregister_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_register_get_pause_bitmap(): API to get register pause bitmap notifier + * @psoc: objmgr psoc handle + * @handler: pause bitmap updated notifier + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_register_get_pause_bitmap(struct wlan_objmgr_psoc *psoc, + pmo_get_pause_bitmap handler); + +/** + * pmo_unregister_get_pause_bitmap(): API to unregister get pause bitmap + * callback + * @psoc: objmgr psoc handle + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_unregister_get_pause_bitmap(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_register_get_dtim_period_callback(): API to register callback that gets + * dtim period from mlme + * @psoc: objmgr psoc handle + * @handler: pointer to the callback function + * + * Return: QDF_STATUS_SUCCESS in case of success else error + */ +QDF_STATUS pmo_register_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_dtim_period handler); + +/** + * pmo_unregister_get_dtim_period_callback(): API to unregister callback that + * gets dtim period from mlme + * @psoc: objmgr psoc handle + * + * Return: QDF_STATUS_SUCCESS in case of success else error + */ +QDF_STATUS +pmo_unregister_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_register_get_beacon_interval_callback(): API to register callback that + * gets beacon interval from mlme + * @psoc: objmgr psoc handle + * @handler: pointer to the callback function + * + * Return: QDF_STATUS_SUCCESS in case of success else error + */ +QDF_STATUS +pmo_register_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_beacon_interval handler); + +/** + * pmo_unregister_get_beacon_interval_callback(): API to unregister callback + * that gets beacon interval from mlme + * @psoc: objmgr psoc handle + * + * Return: QDF_STATUS_SUCCESS in case of success else error + */ +QDF_STATUS +pmo_unregister_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_register_is_device_in_low_pwr_mode(): API to get register device power + * save check notifier. + * @psoc: objmgr psoc handle + * @handler: device power save check notifier + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS pmo_register_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc, + pmo_is_device_in_low_pwr_mode handler); + +/** + * pmo_unregister_is_device_in_low_pwr_mode(): API to unregister device power + * save check notifier. + * @psoc: objmgr psoc handle + * + * Return QDF_STATUS status - in case of success else return error + */ +QDF_STATUS +pmo_unregister_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_pmo_get_sap_mode_bus_suspend(): API to get SAP bus suspend config + * @psoc: objmgr psoc handle + * + * Return true in case of peer connected SAP bus suspend is allowed + * else return false + */ +bool +wlan_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_pmo_get_go_mode_bus_suspend(): API to get GO bus suspend config + * @psoc: objmgr psoc handle + * + * Return true in case of peer connected GO bus suspend is allowed + * else return false + */ +bool +wlan_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc); + +/* + * wlan_pmo_no_op_on_page_fault() - Whether to ignore page fault wakeups + * @psoc: PSOC object manager + * + * Return: true if host has to ignore page fault wakeup events else false. + */ +bool wlan_pmo_no_op_on_page_fault(struct wlan_objmgr_psoc *psoc); + +/* + * wlan_pmo_enable_ssr_on_page_fault: Enable/disable ssr on pagefault + * @psoc: objmgr psoc + * + * Return: True if SSR is enabled on pagefault + */ +bool wlan_pmo_enable_ssr_on_page_fault(struct wlan_objmgr_psoc *psoc); + +/* + * wlan_pmo_get_min_pagefault_wakeups_for_action() - get min pagefault wakeups + * for host to initiate action + * @psoc: objmgr psoc + * + * Return: Min pagefault wakeups for action + */ +uint8_t +wlan_pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc *psoc); + +/* + * wlan_pmo_get_interval_for_pagefault_wakeup_counts: get ssr interval for + * pagefault + * @psoc: objmgr psoc + * + * Return: SSR interval for pagefault + */ +uint32_t +wlan_pmo_get_interval_for_pagefault_wakeup_counts( + struct wlan_objmgr_psoc *psoc); + +QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval); + +/** + * wlan_pmo_set_ps_params() - Set vdev OPM params + * @vdev: pointer to vdev object + * @ps_params: pointer to OPM params + * + * Return: None + */ +void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params); + +/** + * wlan_pmo_get_ps_params() - Get vdev OPM params + * @vdev: pointer to vdev object + * @ps_params: Pointer to get OPM params + * + * Return: QDF Status + */ +QDF_STATUS wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params); + +#else /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +static inline QDF_STATUS pmo_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS pmo_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_psoc_object_created_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_psoc_object_destroyed_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_vdev_object_created_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_vdev_ready(struct wlan_objmgr_vdev *vdev, struct qdf_mac_addr *bridgeaddr) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_vdev_object_destroyed_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_suspend_handler(enum wlan_umac_comp_id id, + pmo_psoc_suspend_handler handler, + void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_suspend_handler(enum wlan_umac_comp_id id, + pmo_psoc_suspend_handler handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_resume_handler(enum wlan_umac_comp_id id, + pmo_psoc_resume_handler handler, + void *arg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_resume_handler(enum wlan_umac_comp_id id, + pmo_psoc_resume_handler handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type suspend_type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_resume_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type suspend_type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc, + pmo_notify_pause_bitmap handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_get_pause_bitmap(struct wlan_objmgr_psoc *psoc, + pmo_get_pause_bitmap handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_get_pause_bitmap(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc, + pmo_is_device_in_low_pwr_mode handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_dtim_period handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_register_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_beacon_interval handler) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +pmo_unregister_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool +wlan_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool wlan_pmo_no_op_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline bool +wlan_pmo_enable_ssr_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint8_t +wlan_pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +wlan_pmo_get_interval_for_pagefault_wakeup_counts(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ +} + +static inline QDF_STATUS +wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#endif /* end of _WLAN_PMO_OBJ_MGMT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h new file mode 100644 index 0000000000..af37e51392 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_obj_mgmt_public_struct.h @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which are used for object mgmt in pmo. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_OBJ_MGMT_PUBLIC_STRUCT_H_ +#define _WLAN_PMO_OBJ_MGMT_PUBLIC_STRUCT_H_ + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_arp_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_gtk_public_struct.h" +#include "wlan_pmo_wow_public_struct.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" +#include "wlan_pmo_hw_filter_public_struct.h" +#include "wlan_pmo_pkt_filter_public_struct.h" +#include "wlan_pmo_lphb_public_struct.h" + +/** + * typedef pmo_notify_pause_bitmap() - function for vdev notifying the vdev + * pause bitmap new value to mlme + * @vdev_id: ID of objmgr vdev object + * @value: new pause bitmap value + */ +typedef void (*pmo_notify_pause_bitmap)(uint8_t vdev_id, uint16_t value); + +/** + * typedef pmo_get_cfg_int() - function that gets cfg integer from mlme + * @cfg_id: configuration item to retrieve + * @value: location to store the configuration item's value + * + * Return: QDF_STATUS_SUCCESS on success, otherwise QDF_STATUS_E_* + */ +typedef QDF_STATUS (*pmo_get_cfg_int)(int cfg_id, int *value); + +/** + * typedef pmo_get_dtim_period() - function that gets dtim period from mlme + * @vdev_id: ID of objmgr vdev object + * @value: location to store the DTIM period + * + * Return: QDF_STATUS_SUCCESS on success, otherwise QDF_STATUS_E_* + */ +typedef QDF_STATUS (*pmo_get_dtim_period)(uint8_t vdev_id, uint8_t *value); + +/** + * typedef pmo_get_beacon_interval() - function that gets beacon interval + * from mlme + * @vdev_id: ID of objmgr vdev object + * @value: location to store the beacon interval + * + * Return: QDF_STATUS_SUCCESS on success, otherwise QDF_STATUS_E_* + */ +typedef QDF_STATUS (*pmo_get_beacon_interval)(uint8_t vdev_id, uint16_t *value); + +/** + * typedef pmo_get_pause_bitmap() - function for getting vdev pause bitmap + * @vdev_id: ID of objmgr vdev object + * + * Return: vdev pause bitmap + */ +typedef uint16_t(*pmo_get_pause_bitmap)(uint8_t vdev_id); + +/** + * typedef pmo_get_vdev_dp_handle() - for getting vdev datapath handle + * @vdev_id: ID of objmgr vdev object + * + * Return: datapath handle of the associated vdev if found, or NULL + */ +typedef struct cdp_vdev *(*pmo_get_vdev_dp_handle)(uint8_t vdev_id); + +/** + * typedef pmo_is_device_in_low_pwr_mode() - to know is device is in power + * save mode + * @vdev_id: ID of objmgr vdev object + * + * Return: true if associated devicce is in power save + */ +typedef bool (*pmo_is_device_in_low_pwr_mode)(uint8_t vdev_id); + +/** + * typedef pmo_pld_auto_suspend_cb() - pld auto suspend callback during runtime + * suspend + * + * Return: 0 on success, negative errno on failure + */ +typedef int (*pmo_pld_auto_suspend_cb)(void); + +/** + * typedef pmo_pld_auto_resume_cb() - pld auto resume callback during runtime + * resume + * + * Return: 0 on success, negative errno on failure + */ +typedef int (*pmo_pld_auto_resume_cb)(void); + +/** + * struct wlan_pmo_tx_ops - structure of tx function + * pointers for pmo component + * @send_arp_offload_req: fp to send arp offload request + * @send_conf_hw_filter_req: fp to configure hardware filter in DTIM mode + * @send_ns_offload_req: fp to send ns offload request + * @send_non_arp_bcast_filter_req: for enable/disable broadcast filter + * @send_set_pkt_filter: send set packet filter + * @send_clear_pkt_filter: send clear packet filter + * @send_enable_wow_wakeup_event_req: fp to send enable wow wakeup events req + * @send_disable_wow_wakeup_event_req: fp to send disable wow wakeup events req + * @send_add_wow_pattern: fp to send wow pattern request + * @del_wow_pattern: fp to delete wow pattern from firmware + * @send_enhance_mc_offload_req: fp to send enhanced multicast offload request + * @send_set_mc_filter_req: fp to send set mc filter request + * @send_clear_mc_filter_req: fp to send clear mc filter request + * @get_multiple_mc_filter_support: fp to get mc filter support + * @send_set_multiple_mc_filter_req: fp to send set multiple mc filter request + * @send_clear_multiple_mc_filter_req: fp to send clear multiple mc filter req + * @send_ra_filter_req: fp to send ra filter request + * @send_gtk_offload_req: fp to send gtk offload request command + * @send_get_gtk_rsp_cmd: fp to send get gtk response request cmd to firmware + * @send_action_frame_pattern_req: fp to send wow action frame patterns request + * @send_lphb_enable: fp to send lphb enable request command + * @send_lphb_tcp_params: fp to send lphb tcp params request command + * @send_lphb_tcp_filter_req: fp to send lphb tcp packet filter request command + * @send_lphb_upd_params: fp to send lphb udp params request command + * @send_lphb_udp_filter_req: fp to send lphb udp packet filter request command + * @send_vdev_param_update_req: fp to send vdev param request + * @send_vdev_sta_ps_param_req: fp to send sta vdev ps power set req + * @send_igmp_offload_req: fp to send IGMP offload request + * @psoc_update_wow_bus_suspend: fp to update bus suspend req flag at wmi + * @psoc_get_host_credits: fp to get the host credits + * @psoc_get_pending_cmnds: fp to get the host pending wmi commands + * @update_target_suspend_flag: fp to update target suspend flag at wmi + * @update_target_suspend_acked_flag: fp to update target suspend acked flag + * at wmi + * @is_target_suspended: fp to test if target is suspended + * @psoc_send_wow_enable_req: fp to send wow enable request + * @psoc_send_supend_req: fp to send target suspend request + * @psoc_set_runtime_pm_in_progress: fp to set runtime pm is in progress status + * @psoc_get_runtime_pm_in_progress: fp to get runtime pm is in progress status + * @psoc_send_host_wakeup_ind: fp tp send host wake indication to fwr + * @psoc_send_target_resume_req: fp to send target resume request + * @psoc_send_d0wow_enable_req: fp to send D0 WOW enable request + * @psoc_send_d0wow_disable_req: fp to send D0 WOW disable request + * @psoc_send_idle_roam_suspend_mode: fp to send suspend mode for + * idle roam trigger to firmware. + * @send_icmp_offload_req: fp to send icmp offload request + * @psoc_set_wow_enable_ack_failed: fp to set wow enable ack failure status + */ +struct wlan_pmo_tx_ops { + QDF_STATUS (*send_arp_offload_req)(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req); + QDF_STATUS (*send_conf_hw_filter_req)( + struct wlan_objmgr_psoc *psoc, + struct pmo_hw_filter_params *req); + QDF_STATUS (*send_ns_offload_req)(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req); +#ifdef WLAN_FEATURE_PACKET_FILTERING + QDF_STATUS(*send_set_pkt_filter)(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req); + QDF_STATUS(*send_clear_pkt_filter)(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_clear_param + *pmo_clr_pkt_fltr_param); +#endif + QDF_STATUS (*send_enable_wow_wakeup_event_req)( + struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap); + QDF_STATUS (*send_disable_wow_wakeup_event_req)( + struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap); + QDF_STATUS (*send_add_wow_pattern)( + struct wlan_objmgr_vdev *vdev, + uint8_t ptrn_id, const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user); + QDF_STATUS (*del_wow_pattern)( + struct wlan_objmgr_vdev *vdev, uint8_t ptrn_id); + QDF_STATUS (*send_enhance_mc_offload_req)( + struct wlan_objmgr_vdev *vdev, bool enable); + QDF_STATUS (*send_set_mc_filter_req)( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr); + QDF_STATUS (*send_clear_mc_filter_req)( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr); + bool (*get_multiple_mc_filter_support)( + struct wlan_objmgr_psoc *psoc); + QDF_STATUS(*send_set_multiple_mc_filter_req)( + struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + QDF_STATUS(*send_clear_multiple_mc_filter_req)( + struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + QDF_STATUS (*send_ra_filter_req)( + struct wlan_objmgr_vdev *vdev, + uint8_t default_pattern, uint16_t rate_limit_interval); + QDF_STATUS (*send_gtk_offload_req)( + struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_offload_req); + QDF_STATUS (*send_get_gtk_rsp_cmd)(struct wlan_objmgr_vdev *vdev); + QDF_STATUS (*send_action_frame_pattern_req)( + struct wlan_objmgr_vdev *vdev, + struct pmo_action_wakeup_set_params *ip_cmd); + QDF_STATUS (*send_lphb_enable)( + struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_enable_req *ts_lphb_enable); + QDF_STATUS (*send_lphb_tcp_params)( + struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_params *ts_lphb_tcp_param); + QDF_STATUS (*send_lphb_tcp_filter_req)( + struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter); + QDF_STATUS (*send_lphb_upd_params)( + struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_params *ts_lphb_udp_param); + QDF_STATUS (*send_lphb_udp_filter_req)( + struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter); + QDF_STATUS (*send_vdev_param_update_req)( + struct wlan_objmgr_vdev *vdev, + uint32_t param_id, uint32_t param_value); + QDF_STATUS (*send_vdev_sta_ps_param_req)( + struct wlan_objmgr_vdev *vdev, + uint32_t ps_mode, uint32_t value); +#ifdef WLAN_FEATURE_IGMP_OFFLOAD + QDF_STATUS (*send_igmp_offload_req)( + struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req); +#endif + void (*psoc_update_wow_bus_suspend)( + struct wlan_objmgr_psoc *psoc, uint8_t value); + int (*psoc_get_host_credits)( + struct wlan_objmgr_psoc *psoc); + int (*psoc_get_pending_cmnds)( + struct wlan_objmgr_psoc *psoc); + void (*update_target_suspend_flag)( + struct wlan_objmgr_psoc *psoc, uint8_t value); + void (*update_target_suspend_acked_flag)( + struct wlan_objmgr_psoc *psoc, uint8_t value); + bool (*is_target_suspended)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*psoc_send_wow_enable_req)(struct wlan_objmgr_psoc *psoc, + struct pmo_wow_cmd_params *param); + QDF_STATUS (*psoc_send_supend_req)(struct wlan_objmgr_psoc *psoc, + struct pmo_suspend_params *param); + void (*psoc_set_runtime_pm_in_progress)(struct wlan_objmgr_psoc *psoc, + bool value); + bool (*psoc_get_runtime_pm_in_progress)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*psoc_send_host_wakeup_ind)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*psoc_send_target_resume_req)( + struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*psoc_send_d0wow_enable_req)( + struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*psoc_send_d0wow_disable_req)( + struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*psoc_send_idle_roam_suspend_mode)( + struct wlan_objmgr_psoc *psoc, uint8_t val); +#ifdef WLAN_FEATURE_ICMP_OFFLOAD + QDF_STATUS (*send_icmp_offload_req)( + struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req); +#endif + void (*psoc_set_wow_enable_ack_failed)(struct wlan_objmgr_psoc *psoc); +}; + +#endif /* end of _WLAN_PMO_OBJ_MGMT_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_cfg.h new file mode 100644 index 0000000000..3b1a28d530 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_cfg.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_PACKET_FILTER_CFG_H__ +#define WLAN_PMO_PACKET_FILTER_CFG_H__ + +/* + * + * gDisablePacketFilter - Disable packet filter disable + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_PMO_DISABLE_PKT_FILTER CFG_INI_BOOL( \ + "gDisablePacketFilter", \ + true, \ + "Disable packet filter feature") + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/* + * + * g_enable_packet_filter_bitmap - Packet filters configuration + * @Min: 0 + * @Max: 63 + * @Default: 0 + * + * To enable packet filters when target goes to suspend, clear when resume: + * bit-0 : IPv6 multicast + * bit-1 : IPv4 multicast + * bit-2 : IPv4 broadcast + * bit-3 : XID - Exchange station Identification packet, solicits the + * identification of the receiving station + * bit-4 : STP - Spanning Tree Protocol, builds logical loop free topology + * bit-5 : DTP/LLC/CDP + * DTP - Dynamic Trunking Protocol is used by Cisco switches to + * negotiate whether an interconnection between two switches + * should be put into access or trunk mode + * LLC - Logical link control, used for multiplexing, flow & error + * control + * CDP - Cisco Discovery Protocol packet contains information + * about the cisco devices in the network + * + * Supported Feature: Packet filtering + * + * Usage: Internal/External + * + * + */ +#define CFG_PMO_PKT_FILTER CFG_INI_UINT( \ + "g_enable_packet_filter_bitmap", \ + 0, 63, 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Packet filter bitmap configure") + +#define CFG_PACKET_FILTER_ALL \ + CFG(CFG_PMO_PKT_FILTER) \ + CFG(CFG_PMO_DISABLE_PKT_FILTER) +#else +#define CFG_PACKET_FILTER_ALL \ + CFG(CFG_PMO_DISABLE_PKT_FILTER) +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +#endif /* WLAN_PMO_PACKET_FILTER_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_public_struct.h new file mode 100644 index 0000000000..d654b9664f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_pkt_filter_public_struct.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo packet filter feature. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_PKT_FILTER_PUBLIC_STRUCT_H_ +#define _WLAN_PMO_PKT_FILTER_PUBLIC_STRUCT_H_ + +#include "qdf_types.h" + +#define PMO_MAX_FILTER_TEST_DATA_LEN 8 +#define PMO_MAX_NUM_TESTS_PER_FILTER 10 + +/** + * enum pmo_rcv_pkt_fltr_type: Receive Filter Parameters + * @PMO_RCV_FILTER_TYPE_INVALID: invalied filter type + * @PMO_RCV_FILTER_TYPE_FILTER_PKT: packet filter + * @PMO_RCV_FILTER_TYPE_BUFFER_PKT: buffer packet + * @PMO_RCV_FILTER_TYPE_MAX_ENUM_SIZE: max filter + */ +enum pmo_rcv_pkt_fltr_type { + PMO_RCV_FILTER_TYPE_INVALID, + PMO_RCV_FILTER_TYPE_FILTER_PKT, + PMO_RCV_FILTER_TYPE_BUFFER_PKT, + PMO_RCV_FILTER_TYPE_MAX_ENUM_SIZE +}; + +/** + * enum pmo_rcv_pkt_fltr_flag_type: Receive Filter flags + * @PMO_FILTER_CMP_TYPE_INVALID: invalied flag + * @PMO_FILTER_CMP_TYPE_EQUAL: equal + * @PMO_FILTER_CMP_TYPE_MASK_EQUAL: mask + * @PMO_FILTER_CMP_TYPE_NOT_EQUAL: not equal + * @PMO_FILTER_CMP_TYPE_MASK_NOT_EQUAL: mask not equal + * @PMO_FILTER_CMP_TYPE_MAX: max size of flag + */ +enum pmo_rcv_pkt_fltr_flag_type { + PMO_FILTER_CMP_TYPE_INVALID, + PMO_FILTER_CMP_TYPE_EQUAL, + PMO_FILTER_CMP_TYPE_MASK_EQUAL, + PMO_FILTER_CMP_TYPE_NOT_EQUAL, + PMO_FILTER_CMP_TYPE_MASK_NOT_EQUAL, + PMO_FILTER_CMP_TYPE_MAX +}; + +/** + * enum pmo_rcv_pkt_fltr_protocol_params: Receive Filter protocol parameters + * @PMO_FILTER_HDR_TYPE_INVALID: invalied type + * @PMO_FILTER_HDR_TYPE_MAC: mac protocol + * @PMO_FILTER_HDR_TYPE_ARP: arp protocol + * @PMO_FILTER_HDR_TYPE_IPV4: ipv4 protocol + * @PMO_FILTER_HDR_TYPE_IPV6: ipv6 protocol + * @PMO_FILTER_HDR_TYPE_UDP: udp protocol + * @PMO_FILTER_HDR_TYPE_MAX: max of type of protocol + */ +enum pmo_rcv_pkt_fltr_protocol_params { + PMO_FILTER_HDR_TYPE_INVALID, + PMO_FILTER_HDR_TYPE_MAC, + PMO_FILTER_HDR_TYPE_ARP, + PMO_FILTER_HDR_TYPE_IPV4, + PMO_FILTER_HDR_TYPE_IPV6, + PMO_FILTER_HDR_TYPE_UDP, + PMO_FILTER_HDR_TYPE_MAX +}; + +/** + * struct pmo_rcv_pkt_fltr_field_params - pmo packet filter field parameters + * @protocol_layer: Protocol layer + * @compare_flag: Comparison flag + * @data_length: Length of the data to compare + * @data_offset: from start of the respective frame header + * @reserved: Reserved field + * @compare_data: Data to compare + * @data_mask: Mask to be applied on the received packet data before compare + */ +struct pmo_rcv_pkt_fltr_field_params { + enum pmo_rcv_pkt_fltr_protocol_params protocol_layer; + enum pmo_rcv_pkt_fltr_flag_type compare_flag; + uint16_t data_length; + uint8_t data_offset; + uint8_t reserved; + uint8_t compare_data[PMO_MAX_FILTER_TEST_DATA_LEN]; + uint8_t data_mask[PMO_MAX_FILTER_TEST_DATA_LEN]; +}; + +/** + * struct pmo_rcv_pkt_fltr_cfg - pmo packet filter config + * @filter_id: filter id + * @filter_type: filter type + * @num_params: number of parameters + * @coalesce_time: time + * @self_macaddr: mac address + * @bssid: Bssid of the connected AP + * @params_data: data + */ +struct pmo_rcv_pkt_fltr_cfg { + uint8_t filter_id; + enum pmo_rcv_pkt_fltr_type filter_type; + uint32_t num_params; + uint32_t coalesce_time; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; + struct pmo_rcv_pkt_fltr_field_params + params_data[PMO_MAX_NUM_TESTS_PER_FILTER]; +}; + +/** + * struct pmo_rcv_pkt_fltr_clear_param - pmo receive Filter Clear Parameters + * @status: only valid for response message + * @filter_id: + * @self_macaddr: + * @bssid: peer ap address + */ +struct pmo_rcv_pkt_fltr_clear_param { + uint32_t status; + uint8_t filter_id; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; +}; + +#endif /* end of _WLAN_PMO_PKT_FILTER_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_runtime_pm_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_runtime_pm_cfg.h new file mode 100644 index 0000000000..4b03cdf498 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_runtime_pm_cfg.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_RUNTIME_PM_CFG_H__ +#define WLAN_PMO_RUNTIME_PM_CFG_H__ + +#ifdef FEATURE_RUNTIME_PM +/* + * + * gRuntimePMDelay - Set runtime pm's inactivity timer + * @Min: 100 + * @Max: 10000 + * @Default: 500 + * + * This ini is used to set runtime pm's inactivity timer value. + * the wlan driver will wait for this number of milliseconds of + * inactivity before performing a runtime suspend. + * + * Related: gRuntimePM + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_PMO_RUNTIME_PM_DELAY CFG_INI_UINT( \ + "gRuntimePMDelay", \ + 100, \ + 10000, \ + 500, \ + CFG_VALUE_OR_DEFAULT, \ + "Set runtime pm's inactivity timer") + +#define CFG_RUNTIME_PM_ALL \ + CFG(CFG_PMO_RUNTIME_PM_DELAY) +#else +#define CFG_RUNTIME_PM_ALL +#endif /* FEATURE_RUNTIME_PM */ +#endif /* WLAN_PMO_RUNTIME_PM_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h new file mode 100644 index 0000000000..6b76df9f01 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_tgt_api.h @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare public API for pmo to interact with target/WMI + */ + +#ifndef _WLAN_PMO_TGT_API_H_ +#define _WLAN_PMO_TGT_API_H_ + +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_arp_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_gtk_public_struct.h" +#include "wlan_pmo_wow_public_struct.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" +#include "wlan_pmo_hw_filter_public_struct.h" +#include "wlan_pmo_pkt_filter_public_struct.h" + +#define GET_PMO_TX_OPS_FROM_PSOC(psoc) \ + (pmo_psoc_get_priv(psoc)->pmo_tx_ops) + +/** + * pmo_tgt_conf_hw_filter() - configure hardware filter mode in firmware + * @psoc: the psoc to use to communicate with firmware + * @req: the configuration request + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_tgt_conf_hw_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_hw_filter_params *req); + +/** + * pmo_tgt_set_pkt_filter() - Set packet filter + * @vdev: objmgr vdev + * @pmo_set_pkt_fltr_req: + * @vdev_id: vdev id + * + * API to set packet filter + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_tgt_set_pkt_filter(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id); + +/** + * pmo_tgt_clear_pkt_filter() - Clear packet filter + * @vdev: objmgr vdev + * @pmo_clr_pkt_fltr_param: + * @vdev_id: vdev id + * + * API to clear packet filter + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS pmo_tgt_clear_pkt_filter(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id); + +/** + * pmo_tgt_enable_arp_offload_req() - Enable arp offload req to target + * @vdev: objmgr vdev + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_enable_arp_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id); + +/** + * pmo_tgt_disable_arp_offload_req() - Disable arp offload req to target + * @vdev: objmgr vdev + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_disable_arp_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id); + +#ifdef WLAN_NS_OFFLOAD +/** + * pmo_tgt_enable_ns_offload_req() - Send ns offload req to targe + * @vdev: objmgr vdev + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_enable_ns_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id); + +/** + * pmo_tgt_disable_ns_offload_req() - Disable arp offload req to target + * @vdev: objmgr vdev + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_disable_ns_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id); +#endif /* WLAN_NS_OFFLOAD */ + +/** + * pmo_tgt_enable_wow_wakeup_event() - Send Enable wow wakeup events req to fwr + * @vdev: objmgr vdev handle + * @bitmap: Event bitmap + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_enable_wow_wakeup_event(struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap); + +/** + * pmo_tgt_disable_wow_wakeup_event() - Send Disable wow wakeup events to fwr + * @vdev: objmgr vdev handle + * @bitmap: Event bitmap + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_disable_wow_wakeup_event(struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap); + +/** + * pmo_tgt_send_wow_patterns_to_fw() - Sends WOW patterns to FW. + * @vdev: objmgr vdev + * @ptrn_id: pattern id + * @ptrn: pattern + * @ptrn_len: pattern length + * @ptrn_offset: pattern offset + * @mask: mask + * @mask_len: mask length + * @user: true for user configured pattern and false for default pattern + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_wow_patterns_to_fw(struct wlan_objmgr_vdev *vdev, + uint8_t ptrn_id, const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user); + +QDF_STATUS pmo_tgt_del_wow_pattern( + struct wlan_objmgr_vdev *vdev, uint8_t ptrn_id, + bool user); + +/** + * pmo_tgt_set_mc_filter_req() - Set mcast filter command to fw + * @vdev: objmgr vdev + * @multicast_addr: mcast address + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_tgt_set_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr); + +/** + * pmo_tgt_clear_mc_filter_req() - Clear mcast filter command to fw + * @vdev: objmgr vdev + * @multicast_addr: mcast address + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_tgt_clear_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr); + +/** + * pmo_tgt_get_multiple_mc_filter_support() - get multiple mcast filter support + * @vdev: objmgr vdev + * + * Return: true if FW supports else false + */ +bool pmo_tgt_get_multiple_mc_filter_support(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_tgt_set_multiple_mc_filter_req() - Set multiple mcast filter cmd to fw + * @vdev: objmgr vdev + * @mc_list: mcast address list + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_tgt_set_multiple_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + +/** + * pmo_tgt_clear_multiple_mc_filter_req() - clear multiple mcast filter + * to fw + * @vdev: objmgr vdev + * @mc_list: mcast address list + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS pmo_tgt_clear_multiple_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + +/** + * pmo_tgt_send_enhance_multicast_offload_req() - send enhance mc offload req + * @vdev: the vdev to configure + * @action: enable or disable enhance multicast offload + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_send_enhance_multicast_offload_req( + struct wlan_objmgr_vdev *vdev, + uint8_t action); + +/** + * pmo_tgt_send_ra_filter_req() - send ra filter request to target + * @vdev: objmgr vdev handle + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_send_ra_filter_req(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_tgt_send_action_frame_pattern_req - send wow action frame patterns req + * @vdev: objmgr vdev handle + * @cmd: action frame pattern cmd + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_send_action_frame_pattern_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_action_wakeup_set_params *cmd); + +/** + * pmo_tgt_send_gtk_offload_req() - send GTK offload command to fw + * @vdev: objmgr vdev + * @gtk_req: pmo gtk req + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req); + +/** + * pmo_tgt_get_gtk_rsp() - send get gtk rsp command to fw + * @vdev: objmgr vdev + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_get_gtk_rsp(struct wlan_objmgr_vdev *vdev); + +/** + * pmo_tgt_gtk_rsp_evt() - receive gtk rsp event from fwr + * @psoc: objmgr psoc + * @rsp_param: gtk response parameters + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_gtk_rsp_evt(struct wlan_objmgr_psoc *psoc, + struct pmo_gtk_rsp_params *rsp_param); + +/** + * pmo_tgt_send_lphb_enable() - enable command of LPHB configuration requests + * @psoc: objmgr psoc handle + * @ts_lphb_enable: lphb enable request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_lphb_enable(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_enable_req *ts_lphb_enable); + +/** + * pmo_tgt_send_lphb_tcp_params() - set tcp params of LPHB configuration req + * @psoc: objmgr psoc handle + * @ts_lphb_tcp_param: lphb tcp params which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_params *ts_lphb_tcp_param); + +/** + * pmo_tgt_send_lphb_tcp_pkt_filter() - send tcp packet filter command of LPHB + * @psoc: objmgr psoc handle + * @ts_lphb_tcp_filter: lphb tcp filter request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter); + +/** + * pmo_tgt_send_lphb_udp_params() - Send udp param command of LPHB + * @psoc: objmgr psoc handle + * @ts_lphb_udp_param: lphb udp params which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_params *ts_lphb_udp_param); + +/** + * pmo_tgt_send_lphb_udp_pkt_filter() - Send udp pkt filter command of LPHB + * @psoc: objmgr psoc handle + * @ts_lphb_udp_filter: lphb udp filter request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter); + + +/** + * pmo_tgt_lphb_rsp_evt() - receive lphb rsp event from fwr + * @psoc: objmgr psoc + * @rsp_param: lphb response parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS pmo_tgt_lphb_rsp_evt(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_rsp *rsp_param); + +/** + * pmo_tgt_vdev_update_param_req() - Update vdev param value to fwr + * @vdev: objmgr vdev + * @param_id: tell vdev param id which needs to be updated in fwr + * @param_value: vdev parameter value + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_vdev_update_param_req(struct wlan_objmgr_vdev *vdev, + enum pmo_vdev_param_id param_id, uint32_t param_value); + +/** + * pmo_tgt_send_vdev_sta_ps_param() - Send vdev sta power save param to fwr + * @vdev: objmgr vdev + * @ps_param: sta mode ps power save params type + * @param_value: power save parameter value + * + * Return: QDF status + */ +QDF_STATUS pmo_tgt_send_vdev_sta_ps_param(struct wlan_objmgr_vdev *vdev, + enum pmo_sta_powersave_param ps_param, uint32_t param_value); + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * pmo_tgt_send_igmp_offload_req() - Send igmp offload request to fw + * @vdev: objmgr vdev + * @pmo_igmp_req: igmp offload params + * + * Return: QDF status + */ +QDF_STATUS +pmo_tgt_send_igmp_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req); +#else +static inline QDF_STATUS +pmo_tgt_send_igmp_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * pmo_tgt_psoc_update_wow_bus_suspend_state() - update wow bus suspend state + * flag + * @psoc: objmgr psoc + * @val: true for setting wow suspend flag to set else false + * + * Return: None + */ +void pmo_tgt_psoc_update_wow_bus_suspend_state(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * pmo_tgt_psoc_get_host_credits() - Get host credits + * @psoc: objmgr psoc + * + * Return: Pending WMI commands on success else EAGAIN on error + */ +int pmo_tgt_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_tgt_psoc_get_pending_cmnds() - Get pending commands + * @psoc: objmgr psoc + * + * Return: Pending WMI commands on success else EAGAIN on error + */ +int pmo_tgt_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_tgt_update_target_suspend_flag() - Set WMI target Suspend flag + * @psoc: objmgr psoc + * @val: true on suspend false for resume + * + * Return: None + */ +void pmo_tgt_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * pmo_tgt_update_target_suspend_acked_flag() - Set WMI target Suspend acked + * flag + * @psoc: objmgr psoc + * @val: true on suspend false for resume + * + * Return: None + */ +void pmo_tgt_update_target_suspend_acked_flag(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * pmo_tgt_is_target_suspended() - Get WMI target Suspend flag + * @psoc: objmgr psoc + * + * Return: true if target suspended, false otherwise. + */ +bool pmo_tgt_is_target_suspended(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_tgt_psoc_send_wow_enable_req() -Send wow enable request + * @psoc: objmgr psoc + * @param: WOW enable request buffer + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc, + struct pmo_wow_cmd_params *param); + +/** + * pmo_tgt_psoc_send_supend_req() -Send target suspend request to fwr + * @psoc: objmgr psoc + * @param: suspend request buffer + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_psoc_send_supend_req(struct wlan_objmgr_psoc *psoc, + struct pmo_suspend_params *param); + +/** + * pmo_tgt_psoc_set_runtime_pm_inprogress() -set runtime status + * @psoc: objmgr psoc + * @value: set runtime pm in progress true or false + * + * Return: none + */ +QDF_STATUS pmo_tgt_psoc_set_runtime_pm_inprogress(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * pmo_tgt_psoc_get_runtime_pm_in_progress() -get runtime status + * @psoc: objmgr psoc + * + * Return: true if runtime pm is in progress else false + */ +bool pmo_tgt_psoc_get_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_tgt_psoc_send_host_wakeup_ind() -Send host wake up indication to fwr + * @psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_psoc_send_host_wakeup_ind(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_tgt_psoc_send_target_resume_req() -Send target resume request + * @psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_psoc_send_target_resume_req(struct wlan_objmgr_psoc *psoc); + +/** + * pmo_tgt_psoc_send_idle_roam_monitor() - Send idle roam set suspend mode + * command to firmware + * @psoc: objmgr psoc + * @val: Set suspend mode value + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS pmo_tgt_psoc_send_idle_roam_monitor(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +/** + * pmo_tgt_config_icmp_offload_req() - Configure icmp offload req to target + * @psoc: objmgr psoc + * @pmo_icmp_req: ICMP offload parameters + * + * Return: QDF status + */ +QDF_STATUS +pmo_tgt_config_icmp_offload_req(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req); +#endif + +/** + * pmo_tgt_psoc_set_wow_enable_ack_failed() -set wow enable ack failure status + * @psoc: objmgr psoc + * + * Return: none + */ +QDF_STATUS +pmo_tgt_psoc_set_wow_enable_ack_failed(struct wlan_objmgr_psoc *psoc); + +#endif /* end of _WLAN_PMO_TGT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h new file mode 100644 index 0000000000..8267dbab4c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_ucfg_api.h @@ -0,0 +1,2462 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare public API related to the pmo called by north bound HDD/OSIF + */ + +#ifndef _WLAN_PMO_UCFG_API_H_ +#define _WLAN_PMO_UCFG_API_H_ + +#include "wlan_pmo_arp_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_gtk_public_struct.h" +#include "wlan_pmo_mc_addr_filtering.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" +#include "wlan_pmo_wow_public_struct.h" +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_obj_mgmt_api.h" +#include "wlan_pmo_pkt_filter_public_struct.h" +#include "wlan_pmo_hw_filter_public_struct.h" + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD + +/** + * ucfg_pmo_psoc_open() - pmo psoc object open + * @psoc: objmgr vdev + *. + * This function used to open pmo psoc object by user space + * + * Return: true in case success else false + */ +QDF_STATUS ucfg_pmo_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_psoc_close() - pmo psoc object close + * @psoc: objmgr vdev + *. + * This function used to close pmo psoc object by user space + * + * Return: true in case success else false + */ +QDF_STATUS ucfg_pmo_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_apf_instruction_size() - get the current APF instruction size + * @psoc: the psoc to query + * + * Return: APF instruction size + */ +uint32_t ucfg_pmo_get_apf_instruction_size(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_num_wow_filters() - get the supported number of WoW filters + * @psoc: the psoc to query + * + * Return: number of WoW filters supported + */ +uint8_t ucfg_pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_is_ap_mode_supports_arp_ns() - Check ap mode support arp&ns offload + * @psoc: objmgr psoc + * @vdev_opmode: vdev opmode + * + * Return: true in case support else false + */ +bool ucfg_pmo_is_ap_mode_supports_arp_ns(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode); + +/** + * ucfg_pmo_is_vdev_connected() - to check whether peer is associated or not + * @vdev: objmgr vdev + * + * Return: true in case success else false + */ +bool ucfg_pmo_is_vdev_connected(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_is_vdev_supports_offload() - check offload is supported on vdev + * @vdev: objmgr vdev + * + * Return: true in case success else false + */ +bool ucfg_pmo_is_vdev_supports_offload(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_get_psoc_config(): API to get the psoc user configurations of pmo + * @psoc: objmgr psoc handle + * @psoc_cfg: fill the current psoc user configurations. + * + * Return: pmo psoc configurations + */ +QDF_STATUS ucfg_pmo_get_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg); + +/** + * ucfg_pmo_update_psoc_config(): API to update the psoc user configurations + * @psoc: objmgr psoc handle + * @psoc_cfg: pmo psoc configurations + * + * This api shall be used for soc config initialization as well update. + * In case of update caller must first call pmo_get_psoc_cfg to get + * current config and then apply changes on top of current config. + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_update_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg); + +/** + * ucfg_pmo_psoc_set_caps() - overwrite configured device capability flags + * @psoc: the psoc for which the capabilities apply + * @caps: the cabability information to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pmo_psoc_set_caps(struct wlan_objmgr_psoc *psoc, + struct pmo_device_caps *caps); + +/** + * ucfg_pmo_is_arp_offload_enabled() - Get arp offload enable or not + * @psoc: pointer to psoc object + * + * Return: arp offload enable or not + */ +bool +ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * ucfg_pmo_is_igmp_offload_enabled() - Get igmp offload enable or not + * @psoc: pointer to psoc object + * + * Return: igmp offload enable or not + */ +bool +ucfg_pmo_is_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_set_igmp_offload_enabled() - Set igmp offload enable or not + * @psoc: pointer to psoc object + * @val: enable/disable igmp offload + * + * Return: None + */ +void +ucfg_pmo_set_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val); +#endif + +/** + * ucfg_pmo_set_arp_offload_enabled() - Set arp offload enable or not + * @psoc: pointer to psoc object + * @val: enable/disable arp offload + * + * Return: None + */ +void +ucfg_pmo_set_arp_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * ucfg_pmo_is_ssdp_enabled() - Get ssdp enable or not + * @psoc: pointer to psoc object + * + * Return: enable/disable ssdp + */ +bool +ucfg_pmo_is_ssdp_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_is_ns_offloaded() - Get ns offload support or not + * @psoc: pointer to psoc object + * + * Return: ns offload or not + */ +bool +ucfg_pmo_is_ns_offloaded(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_sta_dynamic_dtim() - Get dynamic dtim + * @psoc: pointer to psoc object + * + * Return: dynamic dtim + */ +uint8_t +ucfg_pmo_get_sta_dynamic_dtim(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_sta_mod_dtim() - Get modulated dtim + * @psoc: pointer to psoc object + * + * Return: modulated dtim + */ +uint8_t +ucfg_pmo_get_sta_mod_dtim(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_set_sta_mod_dtim() - Set modulated dtim + * @psoc: pointer to psoc object + * @val: modulated dtim + * + * Return: None + */ +void +ucfg_pmo_set_sta_mod_dtim(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * ucfg_pmo_is_mc_addr_list_enabled() - Get multicast address list enable or not + * @psoc: pointer to psoc object + * + * Return: multicast address list enable or not + */ +bool +ucfg_pmo_is_mc_addr_list_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_power_save_mode() - Get power save mode + * @psoc: pointer to psoc object + * + * Return: power save mode + */ +enum powersave_mode +ucfg_pmo_get_power_save_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_default_power_save_mode() - Get default power save mode + * from ini config + * @psoc: pointer to psoc object + * + * Return: power save mode + */ +enum powersave_mode +ucfg_pmo_get_default_power_save_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_set_power_save_mode() - Set power save mode + * @psoc: pointer to psoc object + * @val: power save mode + * + * Return: None + */ +void +ucfg_pmo_set_power_save_mode(struct wlan_objmgr_psoc *psoc, + enum powersave_mode val); + +/** + * ucfg_pmo_get_max_ps_poll() - Get max power save poll + * @psoc: pointer to psoc object + * + * Return: power save poll + */ +uint8_t +ucfg_pmo_get_max_ps_poll(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_power_save_offload_enabled() - Get power save offload enabled type + * @psoc: pointer to psoc object + * + * Return: power save offload enabled type + */ +uint8_t +ucfg_pmo_power_save_offload_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode() - Send suspend mode to + * firmware + * @psoc: pointer to psoc object + * @val: Set suspend mode on/off sent from userspace + * + * Return: QDF_STATUS_SUCCESS if suspend mode is sent to fw else return + * corresponding QDF_STATUS failure code. + */ +QDF_STATUS +ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * ucfg_pmo_enable_wakeup_event() - enable wow wakeup events + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @wow_event: wow event to enable + * + * Return: none + */ +void ucfg_pmo_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event); + +/** + * ucfg_pmo_disable_wakeup_event() - disable wow wakeup events + * @psoc: objmgr psoc + * @vdev_id: vdev id + * @wow_event: wow event to disable + * + * Return: none + */ +void ucfg_pmo_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event); + +/** + * ucfg_pmo_cache_arp_offload_req(): API to cache arp req in pmo vdev priv ctx + * @arp_req: pmo arp req param + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_cache_arp_offload_req(struct pmo_arp_req *arp_req); + +/** + * ucfg_pmo_check_arp_offload(): API to check if arp offload cache/send is req + * @psoc: objmgr psoc handle + * @trigger: trigger reason + * @vdev_id: vdev_id + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_check_arp_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id); + +/** + * ucfg_pmo_flush_arp_offload_req(): API to flush arp req from pmo vdev priv ctx + * @vdev: objmgr vdev param + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_enable_arp_offload_in_fwr(): API to enable arp req in fwr + * @vdev: objmgr vdev param + * @trigger: trigger reason for enable arp offload + * + * API to enable cache arp req in fwr from pmo vdev priv ctx + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS +ucfg_pmo_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * ucfg_pmo_disable_arp_offload_in_fwr(): API to disable arp req in fwr + * @vdev: objmgr vdev param + * @trigger: trigger reason for disable arp offload + * API to disable cache arp req in fwr + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS +ucfg_pmo_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * ucfg_pmo_get_arp_offload_params() - API to get arp offload params + * @vdev: objmgr vdev + * @params: output pointer to hold offload params + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS +ucfg_pmo_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params); + +/** + * ucfg_pmo_cache_ns_offload_req(): API to cache ns req in pmo vdev priv ctx + * @ns_req: pmo ns req param + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_cache_ns_offload_req(struct pmo_ns_req *ns_req); + +/** + * ucfg_pmo_ns_offload_check(): API to check if offload cache/send is required + * @psoc: pbjmgr psoc handle + * @trigger: trigger reason to enable ns offload + * @vdev_id: vdev id + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_ns_offload_check(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id); + +/** + * ucfg_pmo_flush_ns_offload_req(): API to flush ns req from pmo vdev priv ctx + * @vdev: vdev ojbmgr handle + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_enable_ns_offload_in_fwr(): API to enable ns req in fwr + * @vdev: objmgr vdev + * @trigger: trigger reason to enable ns offload + * + * API to enable cache ns req in fwr from pmo vdev priv ctx + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS +ucfg_pmo_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * ucfg_pmo_disable_ns_offload_in_fwr(): API to disable ns req in fwr + * @vdev: objmgr vdev + * @trigger: trigger reason to disable ns offload + * + * API to disable ns req in fwr + * + * Return: QDF_STATUS -in case of success else return error + */ +QDF_STATUS +ucfg_pmo_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * ucfg_pmo_get_ns_offload_params() - API to get ns offload params + * @vdev: objmgr vdev + * @params: output pointer to hold offload params + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS +ucfg_pmo_get_ns_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ns_offload_params *params); + +/** + * ucfg_pmo_ns_addr_scope() - Convert linux specific IPv6 addr scope to + * WLAN driver specific value + * @ipv6_scope: linux specific IPv6 addr scope + * + * Return: PMO identifier of linux IPv6 addr scope + */ +enum pmo_ns_addr_scope +ucfg_pmo_ns_addr_scope(uint32_t ipv6_scope); + +/** + * ucfg_pmo_enable_hw_filter_in_fwr() - enable previously configured hw filter + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pmo_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_enable_action_frame_patterns() - enable the action frame wake up + * patterns as part of the enable host offloads. + * @vdev: objmgr vdev to configure + * @suspend_type: Suspend type. Runtime PM or System Suspend mode + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pmo_enable_action_frame_patterns(struct wlan_objmgr_vdev *vdev, + enum qdf_suspend_type suspend_type); + +/** + * ucfg_pmo_disable_action_frame_patterns() - Reset the action frame wake up + * patterns as a part of suspend resume. + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pmo_disable_action_frame_patterns(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_disable_hw_filter_in_fwr() - disable previously configured hw filter + * @vdev: objmgr vdev to configure + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pmo_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_max_mc_addr_supported() - to get max support mc address + * @psoc: objmgr psoc + * + * Return: max mc addr supported count for all vdev in corresponding psoc + */ +uint8_t ucfg_pmo_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_cache_mc_addr_list(): API to cache mc addr list in pmo vdev priv obj + * @mc_list_config: list configuration + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config); + +/** + * ucfg_pmo_flush_mc_addr_list(): API to flush mc addr list in pmo vdev priv obj + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_flush_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_pmo_enhanced_mc_filter_enable() - enable enhanced multicast filtering + * @vdev: the vdev to enable enhanced multicast filtering for + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_pmo_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enhanced_mc_filter_enable(vdev); +} + +/** + * ucfg_pmo_enhanced_mc_filter_disable() - disable enhanced multicast filtering + * @vdev: the vdev to disable enhanced multicast filtering for + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_pmo_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enhanced_mc_filter_disable(vdev); +} + +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD +/** + * ucfg_pmo_dynamic_arp_ns_offload_enable() - enable arp/ns offload + * @vdev: vdev objmgr handle + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pmo_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_dynamic_arp_ns_offload_disable() - disable arp/ns offload + * @vdev: vdev objmgr handle + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_pmo_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_get_arp_ns_offload_dynamic_disable() - get arp/ns offload state + * @vdev: vdev objmgr handle + * + * Return: QDF_STATUS + */ +bool +ucfg_pmo_get_arp_ns_offload_dynamic_disable(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent() - prevent runtime suspend + * @vdev: vdev objmgr handle + * + * Return: none + */ +void +ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_dynamic_arp_ns_offload_runtime_allow() - allow runtime suspend + * @vdev: vdev objmgr handle + * + * Return: none + */ +void +ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +ucfg_pmo_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_pmo_get_arp_ns_offload_dynamic_disable(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev) {} +#endif + +/** + * ucfg_pmo_enable_mc_addr_filtering_in_fwr(): Enable cached mc add list in fwr + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @trigger: reason for trigger + * + * API to enable cached mc add list in fwr + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_enable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger); + +/** + * ucfg_pmo_disable_mc_addr_filtering_in_fwr(): Disable cached mc addr list + * @psoc: objmgr psoc handle + * @vdev_id: vdev id + * @trigger: reason for trigger + * + * API to disable cached mc add list in fwr + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_disable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger); + +/** + * ucfg_pmo_get_mc_addr_list() - API to get mc addr list configured + * @psoc: objmgr psoc + * @vdev_id: vdev identifier + * @mc_list_req: output pointer to hold mc addr list params + * + * Return: QDF_STATUS_SUCCESS in case of success else return error + */ +QDF_STATUS +ucfg_pmo_get_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct pmo_mc_addr_list *mc_list_req); + +/** + * ucfg_pmo_cache_gtk_offload_req(): API to cache gtk req in pmo vdev priv obj + * @vdev: objmgr vdev handle + * @gtk_req: pmo gtk req param + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req); + +/** + * ucfg_pmo_flush_gtk_offload_req(): Flush saved gtk req from pmo vdev priv obj + * @vdev: objmgr vdev handle + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_enable_gtk_offload_in_fwr(): enable cached gtk request in fwr + * @vdev: objmgr vdev handle + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * ucfg_pmo_enable_igmp_offload(): enable igmp request in fwr + * @vdev: objmgr vdev handle + * @pmo_igmp_req: struct pmo_igmp_offload_req + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_enable_igmp_offload( + struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req); +#else +static inline +QDF_STATUS ucfg_pmo_enable_igmp_offload( + struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ucfg_pmo_disable_gtk_offload_in_fwr(): disable cached gtk request in fwr + * @vdev: objmgr vdev handle + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * ucfg_pmo_get_pkt_filter_bitmap() - get default packet filters bitmap + * @psoc: the psoc to query + * + * Return: retrieve packet filter bitmap configuration + */ +uint8_t ucfg_pmo_get_pkt_filter_bitmap(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_num_packet_filters() - get the number of packet filters + * @psoc: the psoc to query + * + * Return: number of packet filters + */ +uint32_t ucfg_pmo_get_num_packet_filters(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_set_pkt_filter() - Set packet filter + * @psoc: objmgr psoc handle + * @pmo_set_pkt_fltr_req: packet filter set param + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS +ucfg_pmo_set_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id); + +/** + * ucfg_pmo_clear_pkt_filter() - Clear packet filter + * @psoc: objmgr psoc handle + * @pmo_clr_pkt_fltr_param: packet filter clear param + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS ucfg_pmo_clear_pkt_filter( + struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id); +#else +static inline uint8_t +ucfg_pmo_get_pkt_filter_bitmap(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_get_num_packet_filters(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_pmo_set_pkt_filter( + struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_clear_pkt_filter( + struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ucfg_pmo_get_wow_enable() - Get wow enable type + * @psoc: pointer to psoc object + * + * Return: wow enable type + */ +enum pmo_wow_enable_type +ucfg_pmo_get_wow_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_set_wow_enable() - Set wow enable type + * @psoc: pointer to psoc object + * @val: wow enable value + * + * Return: None + */ +void +ucfg_pmo_set_wow_enable(struct wlan_objmgr_psoc *psoc, + enum pmo_wow_enable_type val); + +/** + * ucfg_pmo_set_ps_params() - Set vdev OPM params + * @vdev: pointer to vdev object + * @ps_params: pointer to OPM params + * + * Return: None + */ +void +ucfg_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params); + +/** + * ucfg_pmo_get_ps_params() - Get vdev OPM params + * @vdev: pointer to vdev object + * @ps_params: Pointer to get OPM params + * + * Return: QDF Status + */ +QDF_STATUS ucfg_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params); + +/** + * ucfg_pmo_core_vdev_set_ps_opm_mode() - Set OPM mode + * @vdev: pointer to vdev object + * @opm_mode: OPM mode + * + * Return: QDF Status + */ +QDF_STATUS ucfg_pmo_core_vdev_set_ps_opm_mode(struct wlan_objmgr_vdev *vdev, + enum powersave_mode opm_mode); + +/** + * ucfg_pmo_core_vdev_get_ps_opm_mode() - Get OPM mode + * @vdev: pointer to vdev object + * @opm_mode: OPM mode + * + * Return: QDF Status + */ +QDF_STATUS ucfg_pmo_core_vdev_get_ps_opm_mode(struct wlan_objmgr_vdev *vdev, + enum powersave_mode *opm_mode); + +/** + * ucfg_pmo_get_gtk_rsp(): API to send gtk response request to fwr + * @vdev: objmgr vdev handle + * @gtk_rsp_req: pmo gtk response request + * + * This api will send gtk response request to fwr + * + * Return: QDF_STATUS_SUCCESS -in case of success else return error + */ +QDF_STATUS +ucfg_pmo_get_gtk_rsp(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req); + +/** + * ucfg_pmo_update_extscan_in_progress(): update extscan is in progress flags + * @vdev: objmgr vdev handle + * @value:true if extscan is in progress else false + * + * Return: TRUE/FALSE + */ +void ucfg_pmo_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev, + bool value); + +/** + * ucfg_pmo_update_p2plo_in_progress(): update p2plo is in progress flags + * @vdev: objmgr vdev handle + * @value:true if p2plo is in progress else false + * + * Return: TRUE/FALSE + */ +void ucfg_pmo_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev, + bool value); + +/** + * ucfg_pmo_lphb_config_req() - Handles lphb config request for psoc + * @psoc: objmgr psoc handle + * @lphb_req: low power heart beat request + * @lphb_cb_ctx: Context which needs to pass to soif when lphb callback called + * @callback: upon receiving of lphb indication from fwr call lphb callback + * + * Return: QDF status + */ +QDF_STATUS ucfg_pmo_lphb_config_req(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_req, + void *lphb_cb_ctx, + pmo_lphb_callback callback); + +/** + * ucfg_pmo_psoc_update_power_save_mode() - update power save mode + * @psoc: objmgr psoc handle + * @value: power save mode + * + * Return: None + */ +void ucfg_pmo_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * ucfg_pmo_psoc_update_dp_handle() - update psoc data path handle + * @psoc: objmgr psoc handle + * @dp_hdl: psoc data path handle + * + * Return: None + */ +void ucfg_pmo_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_hdl); + +/** + * ucfg_pmo_psoc_update_htc_handle() - update psoc htc layer handle + * @psoc: objmgr psoc handle + * @htc_handle: psoc host-to-tagret layer (htc) handle + * + * Return: None + */ +void ucfg_pmo_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc, + void *htc_handle); + +/** + * ucfg_pmo_psoc_set_hif_handle() - Set psoc hif layer handle + * @psoc: objmgr psoc handle + * @hif_handle: hif context handle + * + * Return: None + */ +void ucfg_pmo_psoc_set_hif_handle(struct wlan_objmgr_psoc *psoc, + void *hif_handle); + +/** + * ucfg_pmo_psoc_set_txrx_pdev_id() - Set psoc pdev txrx layer handle + * @psoc: objmgr psoc handle + * @txrx_pdev_id: txrx pdev identifier + * + * Return: None + */ +void ucfg_pmo_psoc_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t txrx_pdev_id); + +/** + * ucfg_pmo_psoc_user_space_suspend_req() - Handles user space suspend req + * @psoc: objmgr psoc handle + * @type: type of suspend + * + * Handles user space suspend indication for psoc + * + * Return: QDF status + */ +QDF_STATUS ucfg_pmo_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * ucfg_pmo_psoc_user_space_resume_req() - Handles user space resume req + * @psoc: objmgr psoc handle + * @type: type of suspend from which resume needed + * + * Handles user space resume indication for psoc + * + * Return: QDF status + */ +QDF_STATUS ucfg_pmo_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * ucfg_pmo_suspend_all_components() - Suspend all components + * @psoc: objmgr psoc handle + * @type: type of suspend + * + * Suspend all components registered to pmo + * + * Return: QDF status + */ +QDF_STATUS ucfg_pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * ucfg_pmo_resume_all_components() - Resume all components + * @psoc: objmgr psoc handle + * @type: type of suspend from which resume needed + * + * Resume all components registered to pmo + * + * Return: QDF status + */ +QDF_STATUS ucfg_pmo_resume_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * ucfg_pmo_psoc_bus_suspend_req(): handles bus suspend for psoc + * @psoc: objmgr psoc + * @type: is this suspend part of runtime suspend or system suspend? + * @wow_params: collection of wow enable override parameters + * + * Bails if a scan is in progress. + * Calls the appropriate handlers based on configuration and event. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_psoc_bus_suspend_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type, + struct pmo_wow_enable_params *wow_params); + +#ifdef FEATURE_RUNTIME_PM +/** + * ucfg_pmo_psoc_bus_runtime_suspend(): handles bus runtime suspend for psoc + * @psoc: objmgr psoc + * @pld_cb: callback to call link auto suspend + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb); + +/** + * ucfg_pmo_psoc_bus_runtime_resume(): handles bus runtime resume for psoc + * @psoc: objmgr psoc + * @pld_cb: callback to call link auto resume + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_resume_cb pld_cb); +#endif + +/** + * ucfg_pmo_psoc_suspend_target() -Send suspend target command + * @psoc: objmgr psoc handle + * @disable_target_intr: disable target interrupt + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +ucfg_pmo_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, + int disable_target_intr); + +QDF_STATUS +ucfg_pmo_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn); + +/** + * ucfg_pmo_register_wow_default_patterns() - register default wow patterns + * with fw + * @vdev: Pointer to object manager vdev + * + * Return: none + */ +void ucfg_pmo_register_wow_default_patterns(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_del_wow_pattern() - Delete WoWl patterns + * @vdev: objmgr vdev + * + * Return:QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS +ucfg_pmo_del_wow_pattern(struct wlan_objmgr_vdev *vdev); + +QDF_STATUS +ucfg_pmo_del_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id); + +/** + * ucfg_pmo_psoc_bus_resume_req() - handle bus resume request for psoc + * @psoc: objmgr psoc handle + * @type: is this suspend part of runtime suspend or system suspend? + * + * Return:QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS ucfg_pmo_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type); + +/** + * ucfg_pmo_get_wow_bus_suspend(): API to check if wow bus is suspended or not + * @psoc: objmgr psoc handle + * + * Return: True if bus suspende else false + */ +bool ucfg_pmo_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_psoc_handle_initial_wake_up() - update initial wake up + * @cb_ctx: objmgr psoc handle as void * due to htc layer is not aware psoc + * + * Return: None + */ +void ucfg_pmo_psoc_handle_initial_wake_up(void *cb_ctx); + +/** + * ucfg_pmo_psoc_is_target_wake_up_received() - Get initial wake up status + * @psoc: objmgr psoc handle + * + * Return: 0 on success else error code + */ +int ucfg_pmo_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_psoc_clear_target_wake_up() - Clear initial wake up status + * @psoc: objmgr psoc handle + * + * Return: 0 on success else error code + */ +int ucfg_pmo_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_psoc_target_suspend_acknowledge() - Clear initial wake up status + * @context: caller-provided context + * @wow_nack: Was WoW NACK'ed + * @reason_code: WoW status reason code + * + * Return: None + */ +void ucfg_pmo_psoc_target_suspend_acknowledge(void *context, bool wow_nack, + uint16_t reason_code); + +/** + * ucfg_pmo_psoc_wakeup_host_event_received() - got host wake up evennt from fwr + * @psoc: objmgr psoc handle + * + * Return: None + */ +void ucfg_pmo_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_config_listen_interval() - function to configure listen interval + * @vdev: objmgr vdev + * @listen_interval: new listen interval passed by user + * + * This function allows user to configure listen interval dynamically + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pmo_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval); + +/** + * ucfg_pmo_get_listen_interval() - function to get listen interval + * @vdev: objmgr vdev + * @listen_interval: pointer to store listen interval + * + * This function allows user to get listen interval dynamically + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval); + +/** + * ucfg_pmo_config_modulated_dtim() - function to configure modulated dtim + * @vdev: objmgr vdev handle + * @mod_dtim: New modulated dtim value passed by user + * + * This function configures the modulated dtim in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_pmo_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim); + +#ifdef WLAN_FEATURE_WOW_PULSE +/** + * ucfg_pmo_is_wow_pulse_enabled() - to get wow pulse enable configuration + * @psoc: objmgr psoc handle + * + * Return: wow pulse enable configuration + */ +bool ucfg_pmo_is_wow_pulse_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_wow_pulse_pin() - to get wow pulse pin configuration + * @psoc: objmgr psoc handle + * + * Return: wow pulse pin configuration + */ +uint8_t ucfg_pmo_get_wow_pulse_pin(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_wow_pulse_interval_high() - to get wow pulse interval high + * @psoc: objmgr psoc handle + * + * Return: wow pulse interval high configuration + */ +uint16_t ucfg_pmo_get_wow_pulse_interval_high(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_wow_pulse_interval_low() - to get wow pulse interval low + * @psoc: objmgr psoc handle + * + * Return: wow pulse interval high configuration + */ +uint16_t ucfg_pmo_get_wow_pulse_interval_low(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_wow_pulse_repeat_count() - to get wow pulse repeat count + * @psoc: objmgr psoc handle + * + * Return: wow pulse repeat count configuration + */ +uint32_t ucfg_pmo_get_wow_pulse_repeat_count(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_wow_pulse_init_state() - to get wow pulse init state + * @psoc: objmgr psoc handle + * + * Return: wow pulse init state configuration + */ +uint32_t ucfg_pmo_get_wow_pulse_init_state(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_pmo_is_wow_pulse_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint8_t +ucfg_pmo_get_wow_pulse_pin(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint16_t +ucfg_pmo_get_wow_pulse_interval_high(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_get_wow_pulse_repeat_count(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_get_wow_pulse_init_state(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} +#endif + +/** + * ucfg_pmo_is_active_mode_offloaded() - get active mode offload configuration + * @psoc: objmgr psoc handle + * + * Return: retrieve active mode offload configuration + */ +bool ucfg_pmo_is_active_mode_offloaded(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_auto_power_fail_mode() - to get auto power save failure mode + * @psoc: objmgr psoc handle + * + * Return: auto power save failure mode configuration + */ +enum pmo_auto_pwr_detect_failure_mode +ucfg_pmo_get_auto_power_fail_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_set_wow_data_inactivity_timeout() - Set wow data inactivity timeout + * @psoc: pointer to psoc object + * @val: wow data inactivity timeout value + * + * Return: None + */ +void +ucfg_pmo_set_wow_data_inactivity_timeout(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * ucfg_pmo_is_pkt_filter_enabled() - pmo packet filter feature enable or not + * @psoc: objmgr psoc handle + * + * Return: pmo packet filter feature enable/disable + */ +bool ucfg_pmo_is_pkt_filter_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_active_uc_apf_mode() - to get the modes active APF + * for MC/BC packets + * @psoc: objmgr psoc handle + * + * Return: the modes active APF + */ +enum active_apf_mode +ucfg_pmo_get_active_uc_apf_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_active_mc_bc_apf_mode() - to get the modes active APF + * for uc packets + * @psoc: objmgr psoc handle + * + * Return: the modes active APF + */ +enum active_apf_mode +ucfg_pmo_get_active_mc_bc_apf_mode(struct wlan_objmgr_psoc *psoc); +#ifdef FEATURE_WLAN_APF +/** + * ucfg_pmo_is_apf_enabled() - to get apf configuration + * @psoc: objmgr psoc handle + * + * Return: true if enabled, it is intersection of ini and target cap + */ +bool ucfg_pmo_is_apf_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool ucfg_pmo_is_apf_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +#ifdef WLAN_ENABLE_GPIO_WAKEUP +/** + * ucfg_pmo_is_gpio_wakeup_enabled() - to get gpio wakeup enable configuration + * @psoc: objmgr psoc handle + * + * Return: gpio wakeup enable configuration + */ +bool ucfg_pmo_is_gpio_wakeup_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_gpio_wakeup_pin() - to get gpio wakeup pin number + * @psoc: objmgr psoc handle + * + * Return: gpio wakeup pin number + */ +uint32_t ucfg_pmo_get_gpio_wakeup_pin(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_gpio_wakeup_mode() - to get gpio wakeup interrupt mode + * @psoc: objmgr psoc handle + * + * Return: gpio wakeup mode + */ +enum pmo_gpio_wakeup_mode +ucfg_pmo_get_gpio_wakeup_mode(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_pmo_is_gpio_wakeup_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint32_t +ucfg_pmo_get_gpio_wakeup_pin(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline enum pmo_gpio_wakeup_mode +ucfg_pmo_get_gpio_wakeup_mode(struct wlan_objmgr_psoc *psoc) +{ + return PMO_GPIO_WAKEUP_MODE_INVALID; +} +#endif + +/** + * ucfg_pmo_core_txrx_suspend(): suspends TX/RX + * @psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_core_txrx_resume(): resumes TX/RX + * @psoc: objmgr psoc + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_moddtim_user_enable() - Get moddtim user enable + * @vdev: objmgr vdev handle + * + * Return: moddtim user enabled or not + */ +bool ucfg_pmo_get_moddtim_user_enable(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_set_moddtim_user_enable() - Set moddtim user enable + * @vdev: objmgr vdev handle + * @value: moddtim user enable or not + * + * Return: none + */ +void ucfg_pmo_set_moddtim_user_enable(struct wlan_objmgr_vdev *vdev, + bool value); +/** + * ucfg_pmo_get_moddtim_user_active() - Get moddtim user active + * @vdev: objmgr vdev handle + * + * Return: moddtim user active + */ +bool ucfg_pmo_get_moddtim_user_active(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pmo_get_moddtim_user() - Get moddtim user value + * @vdev: objmgr vdev handle + * + * Return: moddtim user value + */ +uint32_t ucfg_pmo_get_moddtim_user(struct wlan_objmgr_vdev *vdev); + +/* + * ucfg_pmo_get_ssr_frequency_on_pagefault: get ssr frequency on pagefault + * @psoc: objmgr psoc + * + * Return: SSR frequency on pagefault + */ +uint32_t ucfg_pmo_get_ssr_frequency_on_pagefault(struct wlan_objmgr_psoc *psoc); + +/* + * ucfg_pmo_get_disconnect_sap_tdls_in_wow: get if disconnect sap/p2p_go + * or tdls in wow + * @psoc: objmgr psoc + * + * Return: true in case support else false + */ +bool +ucfg_pmo_get_disconnect_sap_tdls_in_wow(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +/** + * ucfg_pmo_check_icmp_offload() - API to check if icmp offload is enabled + * @psoc: objmgr psoc handle + * @vdev_id: vdev_id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS ucfg_pmo_check_icmp_offload(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_pmo_is_icmp_offload_enabled() - Get icmp offload enable or not + * @psoc: pointer to psoc object + * + * Return: icmp offload enable or not + */ +bool +ucfg_pmo_is_icmp_offload_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_config_icmp_offload() - API to enable icmp offload request + * @psoc: pointer to psoc object + * @pmo_icmp_req: ICMP offload parameters + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +ucfg_pmo_config_icmp_offload(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req); +#endif +#else /* WLAN_POWER_MANAGEMENT_OFFLOAD */ +static inline QDF_STATUS +ucfg_pmo_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint32_t +ucfg_pmo_get_apf_instruction_size(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint8_t +ucfg_pmo_get_pkt_filter_bitmap(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_get_num_packet_filters(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint8_t +ucfg_pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_pmo_get_psoc_config( + struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_update_psoc_config( + struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_psoc_set_caps( + struct wlan_objmgr_psoc *psoc, + struct pmo_device_caps *caps) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_pmo_is_ap_mode_supports_arp_ns( + struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode) +{ + return true; +} + +static inline bool +ucfg_pmo_is_vdev_connected(struct wlan_objmgr_vdev *vdev) +{ + return true; +} + +static inline bool +ucfg_pmo_is_vdev_supports_offload(struct wlan_objmgr_vdev *vdev) +{ + return true; +} + +static inline void +ucfg_pmo_enable_wakeup_event( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint32_t *bitmap) +{ +} + +static inline void +ucfg_pmo_disable_wakeup_event( + struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint32_t bitmap) +{ +} + +static inline QDF_STATUS +ucfg_pmo_cache_arp_offload_req(struct pmo_arp_req *arp_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_pmo_check_arp_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enable_arp_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_disable_arp_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_cache_ns_offload_req(struct pmo_ns_req *ns_req) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_pmo_ns_offload_check(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enable_ns_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_disable_ns_offload_in_fwr( + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_get_ns_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ns_offload_params *params) +{ + return QDF_STATUS_SUCCESS; +} + +static inline enum pmo_ns_addr_scope +ucfg_pmo_ns_addr_scope(uint32_t ipv6_scope) +{ + return PMO_NS_ADDR_SCOPE_INVALID; +} + +static inline QDF_STATUS +ucfg_pmo_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_flush_mc_addr_list( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_disable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t +ucfg_pmo_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_pmo_get_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct pmo_mc_addr_list *mc_list_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_cache_gtk_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enable_igmp_offload(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_pmo_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_set_pkt_filter( + struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_clear_pkt_filter( + struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_get_gtk_rsp( + struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_pmo_update_extscan_in_progress( + struct wlan_objmgr_vdev *vdev, + bool value) +{ +} + +static inline void +ucfg_pmo_update_p2plo_in_progress( + struct wlan_objmgr_vdev *vdev, + bool value) +{ +} + +static inline QDF_STATUS +ucfg_pmo_lphb_config_req( + struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_req, void *lphb_cb_ctx, + pmo_lphb_callback callback) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_pmo_psoc_update_power_save_mode( + struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ +} + +static inline void +ucfg_pmo_psoc_update_dp_handle( + struct wlan_objmgr_psoc *psoc, + void *dp_handle) +{ +} + +static inline void +ucfg_pmo_psoc_update_htc_handle( + struct wlan_objmgr_psoc *psoc, + void *htc_handle) +{ +} + +static inline void +ucfg_pmo_psoc_set_hif_handle( + struct wlan_objmgr_psoc *psoc, + void *hif_handle) +{ +} + +static inline void +ucfg_pmo_psoc_set_txrx_pdev_id( + struct wlan_objmgr_psoc *psoc, + uint8_t txrx_pdev_id) +{ +} + +static inline void +ucfg_pmo_psoc_handle_initial_wake_up(void *cb_ctx) +{ +} + +static inline QDF_STATUS +ucfg_pmo_psoc_user_space_suspend_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_psoc_user_space_resume_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_resume_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_psoc_bus_suspend_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type, + struct pmo_wow_enable_params *wow_params) +{ + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_RUNTIME_PM +static inline QDF_STATUS +ucfg_pmo_psoc_bus_runtime_suspend( + struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_psoc_bus_runtime_resume( + struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static inline QDF_STATUS +ucfg_pmo_psoc_suspend_target( + struct wlan_objmgr_psoc *psoc, + int disable_target_intr) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_add_wow_user_pattern( + struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_del_wow_user_pattern( + struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_pmo_register_wow_default_patterns(struct wlan_objmgr_vdev *vdev) +{ +} + +QDF_STATUS +ucfg_pmo_del_wow_pattern(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_psoc_bus_resume_req( + struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_pmo_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline int +ucfg_pmo_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline int +ucfg_pmo_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline void +ucfg_pmo_psoc_target_suspend_acknowledge(void *context, bool wow_nack, + uint16_t reason_code) +{ +} + +static inline void +ucfg_pmo_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS +ucfg_pmo_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enhanced_mc_filter_enable(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_enhanced_mc_filter_disable(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_pmo_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool +ucfg_pmo_is_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline void +ucfg_pmo_set_arp_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ +} + +static inline void +ucfg_pmo_set_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ +} + +static inline bool +ucfg_pmo_is_wow_pulse_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint8_t +ucfg_pmo_get_wow_pulse_pin(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint16_t +ucfg_pmo_get_wow_pulse_interval_high(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint16_t +ucfg_pmo_get_wow_pulse_interval_low(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline bool +ucfg_pmo_is_active_mode_offloaded(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +static inline enum pmo_auto_pwr_detect_failure_mode +ucfg_pmo_get_auto_power_fail_mode(struct wlan_objmgr_psoc *psoc) +{ + return PMO_FW_TO_CRASH_ON_PWR_FAILURE; +} + +static inline bool ucfg_pmo_is_apf_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool ucfg_pmo_is_ssdp_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline bool ucfg_pmo_is_ns_offloaded(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint8_t +ucfg_pmo_get_sta_dynamic_dtim(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint8_t +ucfg_pmo_get_sta_mod_dtim(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline void +ucfg_pmo_set_sta_mod_dtim(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ +} + +static inline bool +ucfg_pmo_is_mc_addr_list_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline enum powersave_mode +ucfg_pmo_get_power_save_mode(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline enum powersave_mode +ucfg_pmo_get_default_power_save_mode(struct wlan_objmgr_psoc *psoc) +{ + return PMO_PS_ADVANCED_POWER_SAVE_DISABLE; +} + +static inline void +ucfg_pmo_set_power_save_mode(struct wlan_objmgr_psoc *psoc, + enum powersave_mode val) +{ +} + +static inline uint8_t +ucfg_pmo_get_max_ps_poll(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint8_t +ucfg_pmo_power_save_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline void +ucfg_pmo_set_wow_data_inactivity_timeout(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ +} + +static inline bool +ucfg_pmo_is_pkt_filter_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +enum active_apf_mode +ucfg_pmo_get_active_uc_apf_mode(struct wlan_objmgr_psoc *psoc); +{ + return 0; +} + +enum active_apf_mode +ucfg_pmo_get_active_mc_bc_apf_mode(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +QDF_STATUS ucfg_pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_pmo_get_moddtim_user_enable(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +ucfg_pmo_set_moddtim_user_enable(struct wlan_objmgr_vdev *vdev, + bool value) +{ +} + +static inline bool +ucfg_pmo_get_moddtim_user_active(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline uint32_t +ucfg_pmo_get_moddtim_user(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_get_ssr_frequency_on_pagefault(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline bool +ucfg_pmo_get_disconnect_sap_tdls_in_wow(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +QDF_STATUS ucfg_pmo_check_icmp_offload(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_pmo_is_icmp_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +QDF_STATUS +ucfg_pmo_config_icmp_offload(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * ucfg_pmo_extwow_is_goto_suspend_enabled() - Get extwow goto suspend enable + * @psoc: pointer to psoc object + * + * Return: extend wow goto suspend enable or not + */ +bool +ucfg_pmo_extwow_is_goto_suspend_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app1_wakeup_pin_num() - Get wakeup1 PIN number + * @psoc: pointer to psoc object + * + * Return: wakeup1 PIN number + */ +uint8_t +ucfg_pmo_extwow_app1_wakeup_pin_num(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_wakeup_pin_num() - Get wakeup2 PIN number + * @psoc: pointer to psoc object + * + * Return: wakeup2 PIN number + */ +uint8_t +ucfg_pmo_extwow_app2_wakeup_pin_num(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_init_ping_interval() - Get keep alive init ping interval + * @psoc: pointer to psoc object + * + * Return: keep alive init ping interval + */ +uint32_t +ucfg_pmo_extwow_app2_init_ping_interval(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_min_ping_interval() - Get keep alive min ping interval + * @psoc: pointer to psoc object + * + * Return: keep alive min ping interval + */ +uint32_t +ucfg_pmo_extwow_app2_min_ping_interval(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_max_ping_interval() - Get keep alive max ping interval + * @psoc: pointer to psoc object + * + * Return: keep alive max ping interval + */ +uint32_t +ucfg_pmo_extwow_app2_max_ping_interval(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_inc_ping_interval() - Get keep alive inc ping interval + * @psoc: pointer to psoc object + * + * Return: keep alive inc ping interval + */ +uint32_t +ucfg_pmo_extwow_app2_inc_ping_interval(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_tcp_src_port() - Get TCP source port + * @psoc: pointer to psoc object + * + * Return: TCP source port + */ +uint16_t +ucfg_pmo_extwow_app2_tcp_src_port(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_tcp_dst_port() - Get TCP Destination port + * @psoc: pointer to psoc object + * + * Return: TCP Destination port + */ +uint16_t +ucfg_pmo_extwow_app2_tcp_dst_port(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_tcp_tx_timeout() - Get TCP Tx timeout + * @psoc: pointer to psoc object + * + * Return: TCP Tx timeout + */ +uint32_t +ucfg_pmo_extwow_app2_tcp_tx_timeout(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_extwow_app2_tcp_rx_timeout() - to get extwow tcp rx timeout + * @psoc: objmgr psoc handle + * + * Return: retrieve extwow app2 tcp rx timeout configuration + */ +uint32_t +ucfg_pmo_extwow_app2_tcp_rx_timeout(struct wlan_objmgr_psoc *psoc); + +#else +static inline bool +ucfg_pmo_extwow_is_goto_suspend_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline uint32_t +ucfg_pmo_extwow_app1_wakeup_pin_num(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_wakeup_pin_num(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_init_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_min_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_max_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_inc_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint16_t +ucfg_pmo_extwow_app2_tcp_src_port(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint16_t +ucfg_pmo_extwow_app2_tcp_dst_port(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_tcp_tx_timeout(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint32_t +ucfg_pmo_extwow_app2_tcp_rx_timeout(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} +#endif + +#ifdef FEATURE_RUNTIME_PM +/** + * ucfg_pmo_get_runtime_pm_delay() - Get runtime pm's inactivity timer + * @psoc: pointer to psoc object + * + * Return: runtime pm's inactivity timer + */ +uint32_t +ucfg_pmo_get_runtime_pm_delay(struct wlan_objmgr_psoc *psoc); +#else +static inline uint32_t +ucfg_pmo_get_runtime_pm_delay(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} +#endif /* FEATURE_RUNTIME_PM */ + +/** + * ucfg_pmo_get_enable_sap_suspend - Return enable_sap_suspend value to caller + * @psoc: Pointer to psoc object + * + * Return: The value of enable_sap_suspend as stored in CFG + */ +bool +ucfg_pmo_get_enable_sap_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_sap_mode_bus_suspend() - get PMO config for PCIe bus + * suspend in SAP mode with one or more clients + * @psoc: pointer to psoc object + * + * Return: bool + */ +bool +ucfg_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_go_mode_bus_suspend() - get PMO config for PCIe bus + * suspend in P2PGO mode with one or more clients + * @psoc: pointer to psoc object + * + * Return: bool + */ +bool +ucfg_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pmo_get_suspend_mode - Return pmo_suspend_mode value to caller + * @psoc: Pointer to psoc object + * + * Return: The value of suspend_mode as stored in CFG + */ +enum pmo_suspend_mode +ucfg_pmo_get_suspend_mode(struct wlan_objmgr_psoc *psoc); + +#ifdef SYSTEM_PM_CHECK +/** + * ucfg_pmo_notify_system_resume() - system resume notification to pmo + * @psoc: pointer to psoc object + * + * Return: None + */ +void +ucfg_pmo_notify_system_resume(struct wlan_objmgr_psoc *psoc); +#else +static inline +void ucfg_pmo_notify_system_resume(struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +/** + * ucfg_pmo_set_vdev_bridge_addr() - API to set Bridge mac address + * @vdev: objmgr vdev + * @bridgeaddr: Bridge mac address + * + * Return: if success pmo vdev ctx else NULL + */ +QDF_STATUS ucfg_pmo_set_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr); + +/** + * ucfg_pmo_get_vdev_bridge_addr() - API to get Bridge mac address + * @vdev: objmgr vdev + * @bridgeaddr: Bridge mac address + * + * Return: if success pmo vdev ctx else NULL + */ +QDF_STATUS ucfg_pmo_get_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr); +#endif /* end of _WLAN_PMO_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h new file mode 100644 index 0000000000..c1a2ff6fdf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_public_struct.h @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various struct, macros which shall be used in + * pmo wow related features. + * + * Note: This file shall not contain public API's prototype/declarations. + * + */ + +#ifndef _WLAN_PMO_WOW_PUBLIC_STRUCT_H_ +#include "wlan_pmo_lphb_public_struct.h" + +#define _WLAN_PMO_WOW_PUBLIC_STRUCT_H_ + +#ifndef PMO_WOW_FILTERS_MAX +#define PMO_WOW_FILTERS_MAX 22 +#endif + +#define PMO_WOWL_PTRN_MAX_SIZE 146 +#define PMO_WOWL_PTRN_MASK_MAX_SIZE 19 +#define PMO_WOWL_BCAST_PATTERN_MAX_SIZE 146 + +#define PMO_WOW_INTER_PTRN_TOKENIZER ';' +#define PMO_WOW_INTRA_PTRN_TOKENIZER ':' + +#define PMO_WOW_PTRN_MASK_VALID 0xFF +#define PMO_NUM_BITS_IN_BYTE 8 + + +/* Action frame categories */ + +#define PMO_MAC_ACTION_SPECTRUM_MGMT 0 +#define PMO_MAC_ACTION_QOS_MGMT 1 +#define PMO_MAC_ACTION_DLP 2 +#define PMO_MAC_ACTION_BLKACK 3 +#define PMO_MAC_ACTION_PUBLIC_USAGE 4 +#define PMO_MAC_ACTION_RRM 5 +#define PMO_MAC_ACTION_FAST_BSS_TRNST 6 +#define PMO_MAC_ACTION_HT 7 +#define PMO_MAC_ACTION_SA_QUERY 8 +#define PMO_MAC_ACTION_PROT_DUAL_PUB 9 +#define PMO_MAC_ACTION_WNM 10 +#define PMO_MAC_ACTION_UNPROT_WNM 11 +#define PMO_MAC_ACTION_TDLS 12 +#define PMO_MAC_ACITON_MESH 13 +#define PMO_MAC_ACTION_MHF 14 +#define PMO_MAC_SELF_PROTECTED 15 +#define PMO_MAC_ACTION_WME 17 +#define PMO_MAC_ACTION_FST 18 +#define PMO_MAC_ACTION_RVS 19 +#define PMO_MAC_ACTION_VHT 21 +#define PMO_MAC_ACTION_EHT 36 +#define PMO_MAC_ACTION_PROT_EHT 37 +#define PMO_VENDOR_PROTECTED 126 +#define PMO_MAC_ACTION_MAX 256 + +/* + * ALLOWED_ACTION_FRAMES_BITMAP + * + * Bitmask is based on the below. The frames with 0's + * set to their corresponding bit can be dropped in FW. + * + * -----------------------------+-----+-------+ + * Type | Bit | Allow | + * -----------------------------+-----+-------+ + * PMO_ACTION_SPECTRUM_MGMT 0 1 + * PMO_ACTION_QOS_MGMT 1 1 + * PMO_ACTION_DLP 2 0 + * PMO_ACTION_BLKACK 3 0 + * PMO_ACTION_PUBLIC_USAGE 4 1 + * PMO_ACTION_RRM 5 0 + * PMO_ACTION_FAST_BSS_TRNST 6 0 + * PMO_ACTION_HT 7 0 + * PMO_ACTION_SA_QUERY 8 1 + * PMO_ACTION_PROT_DUAL_PUB 9 1 + * PMO_ACTION_WNM 10 1 + * PMO_ACTION_UNPROT_WNM 11 0 + * PMO_ACTION_TDLS 12 0 + * PMO_ACITON_MESH 13 0 + * PMO_ACTION_MHF 14 0 + * PMO_SELF_PROTECTED 15 0 + * PMO_ACTION_WME 17 1 + * PMO_ACTION_FST 18 1 + * PMO_ACTION_RVS 19 1 + * PMO_ACTION_VHT 21 1 + * PMO_MAC_ACTION_EHT 36 1 + * PMO_MAC_ACTION_PROT_EHT 37 1 + * PMO_VENDOR_PROTECTED 126 1 + * ----------------------------+------+-------+ + */ +#define SYSTEM_SUSPEND_ALLOWED_ACTION_FRAMES_BITMAP0 \ + ((1 << PMO_MAC_ACTION_SPECTRUM_MGMT) | \ + (1 << PMO_MAC_ACTION_QOS_MGMT) | \ + (1 << PMO_MAC_ACTION_PUBLIC_USAGE) | \ + (1 << PMO_MAC_ACTION_SA_QUERY) | \ + (1 << PMO_MAC_ACTION_PROT_DUAL_PUB) | \ + (1 << PMO_MAC_ACTION_WNM) | \ + (1 << PMO_MAC_ACTION_WME) | \ + (1 << PMO_MAC_ACTION_FST) | \ + (1 << PMO_MAC_ACTION_RVS) | \ + (1 << PMO_MAC_ACTION_VHT)) + +#define ALLOWED_ACTION_FRAMES_BITMAP1 \ + ((1 << (PMO_MAC_ACTION_EHT % 32)) |\ + (1 << (PMO_MAC_ACTION_PROT_EHT % 32))) +#define ALLOWED_ACTION_FRAMES_BITMAP2 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP3 \ + (1 << (PMO_VENDOR_PROTECTED % 32)) + +#define ALLOWED_ACTION_FRAMES_BITMAP4 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP5 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP6 0x0 +#define ALLOWED_ACTION_FRAMES_BITMAP7 0x0 + +#define ALLOWED_ACTION_FRAME_MAP_WORDS (PMO_MAC_ACTION_MAX / 32) + +#define RUNTIME_PM_ALLOWED_ACTION_FRAMES_BITMAP0 \ + ((1 << PMO_MAC_ACTION_SPECTRUM_MGMT) | \ + (1 << PMO_MAC_ACTION_QOS_MGMT) | \ + (1 << PMO_MAC_ACTION_PUBLIC_USAGE) | \ + (1 << PMO_MAC_ACTION_RRM) | \ + (1 << PMO_MAC_ACTION_SA_QUERY) | \ + (1 << PMO_MAC_ACTION_PROT_DUAL_PUB) | \ + (1 << PMO_MAC_ACTION_WNM) | \ + (1 << PMO_MAC_ACTION_WME) | \ + (1 << PMO_MAC_ACTION_FST) | \ + (1 << PMO_MAC_ACTION_RVS) | \ + (1 << PMO_MAC_ACTION_VHT)) + +/* Public Action for 20/40 BSS Coexistence */ +#define PMO_MAC_ACTION_MEASUREMENT_PILOT 7 + +#define DROP_PUBLIC_ACTION_FRAME_BITMAP \ + (1 << PMO_MAC_ACTION_MEASUREMENT_PILOT) + +#ifndef ANI_SUPPORT_11H +/* + * DROP_SPEC_MGMT_ACTION_FRAME_BITMAP + * + * Bitmask is based on the below. The frames with 1's + * set to their corresponding bit can be dropped in FW. + * + * ----------------------------------+-----+------+ + * Type | Bit | Drop | + * ----------------------------------+-----+------+ + * ACTION_SPCT_MSR_REQ 0 1 + * ACTION_SPCT_TPC_REQ 2 1 + * ----------------------------------+-----+------+ + */ +#define DROP_SPEC_MGMT_ACTION_FRAME_BITMAP \ + ((1 << ACTION_SPCT_MSR_REQ) |\ + (1 << ACTION_SPCT_TPC_REQ)) +#else +/* + * If 11H support is defined, dont drop the above action category of + * spectrum mgmt action frames as host driver is processing them. + */ +#define DROP_SPEC_MGMT_ACTION_FRAME_BITMAP 0 +#endif /* ANI_SUPPORT_11H */ + +#define PMO_SUPPORTED_ACTION_CATE 256 +#define PMO_SUPPORTED_ACTION_CATE_ELE_LIST (PMO_SUPPORTED_ACTION_CATE/32) + +/** + * struct pmo_action_wakeup_set_params - action wakeup set params + * @vdev_id: virtual device id + * @operation: 0 reset to fw default, 1 set the bits, + * 2 add the setting bits, 3 delete the setting bits + * @action_category_map: bit mapping. + * @action_per_category: bitmap per action category + */ +struct pmo_action_wakeup_set_params { + uint32_t vdev_id; + uint32_t operation; + uint32_t action_category_map[PMO_SUPPORTED_ACTION_CATE_ELE_LIST]; + uint32_t action_per_category[PMO_SUPPORTED_ACTION_CATE]; +}; + +/** + * enum pmo_wow_action_wakeup_operation - describe action wakeup operation + * @pmo_action_wakeup_reset: reset + * @pmo_action_wakeup_set: set + * @pmo_action_wakeup_add_set: add and set + * @pmo_action_wakeup_del_set: delete and set + */ +enum pmo_wow_action_wakeup_operation { + pmo_action_wakeup_reset = 0, + pmo_action_wakeup_set, + pmo_action_wakeup_add_set, + pmo_action_wakeup_del_set, +}; + +/** + * enum pmo_wow_state: enumeration of wow state + * @pmo_wow_state_none: not in wow state + * @pmo_wow_state_legacy_d0: in d0 wow state trigger by legacy d0 wow command + * @pmo_wow_state_unified_d0: in d0 wow state trigger by unified wow command + * @pmo_wow_state_unified_d3: in d3 wow state trigger by unified wow command + */ +enum pmo_wow_state { + pmo_wow_state_none = 0, + pmo_wow_state_legacy_d0, + pmo_wow_state_unified_d0, + pmo_wow_state_unified_d3, +}; + +/** + * struct pmo_wow - store wow patterns + * @wow_enable: wow enable/disable + * @wow_enable_cmd_sent: is wow enable command sent to fw + * @is_wow_bus_suspended: true if bus is suspended + * @wow_state: state of wow + * @target_suspend: target suspend event + * @target_resume: target resume event + * @wow_nack: wow negative ack flag + * @reason_code : wow status reason code + * @wow_initial_wake_up: target initial wake up is received + * @wow_wake_lock: wow wake lock + * @lphb_cache: lphb cache + * @lphb_cb_ctx: callback context for lphb, kept as void* as + * osif structures are opaque to pmo. + * @lphb_cb: registered os if calllback function + * @ptrn_id_def: default pattern id counter for legacy firmware + * @ptrn_id_usr: user pattern id counter for legacy firmware + * @txrx_suspended: flag to determine if TX/RX is suspended + * during WoW + * + * This structure stores wow patterns and + * wow related parameters in host. + */ +struct pmo_wow { + bool wow_enable; + bool wow_enable_cmd_sent; + bool is_wow_bus_suspended; + enum pmo_wow_state wow_state; + qdf_event_t target_suspend; + qdf_event_t target_resume; + bool wow_nack; + uint16_t reason_code; + atomic_t wow_initial_wake_up; + qdf_wake_lock_t wow_wake_lock; + /* + * currently supports only vdev 0. + * cache has two entries: one for TCP and one for UDP. + */ + struct pmo_lphb_req lphb_cache[2]; + void *lphb_cb_ctx; + pmo_lphb_callback lphb_cb; + + uint8_t ptrn_id_def; + uint8_t ptrn_id_usr; + bool txrx_suspended; +}; + +/* WOW related structures */ +/** + * struct pmo_wow_add_pattern - wow pattern add structure + * @pattern_id: pattern id + * @pattern_byte_offset: pattern byte offset from beginning of the 802.11 + * packet to start of the wake-up pattern + * @pattern_size: pattern size + * @pattern: pattern byte stream + * @pattern_mask_size: pattern mask size + * @pattern_mask: pattern mask + */ +struct pmo_wow_add_pattern { + uint8_t pattern_id; + uint8_t pattern_byte_offset; + uint8_t pattern_size; + uint8_t pattern[PMO_WOWL_BCAST_PATTERN_MAX_SIZE]; + uint8_t pattern_mask_size; + uint8_t pattern_mask[PMO_WOWL_BCAST_PATTERN_MAX_SIZE]; +}; + +/** + * struct pmo_wow_cmd_params - wow cmd parameter + * @enable: wow enable or disable flag + * @can_suspend_link: flag to indicate if link can be suspended + * @pause_iface_config: interface config + * @flags: bitmap of WMI_WOW_FLAG_* flags + */ +struct pmo_wow_cmd_params { + bool enable; + bool can_suspend_link; + uint8_t pause_iface_config; + uint32_t flags; +}; + +/** + * struct pmo_suspend_params - suspend cmd parameter + * @disable_target_intr: disable target interrupt + */ +struct pmo_suspend_params { + uint8_t disable_target_intr; +}; + +#endif /* end of _WLAN_PMO_WOW_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_pulse_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_pulse_cfg.h new file mode 100644 index 0000000000..a7ff8de2bd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/inc/wlan_pmo_wow_pulse_cfg.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_PMO_WOW_PULSE_CFG_H__ +#define WLAN_PMO_WOW_PULSE_CFG_H__ + +#ifdef WLAN_FEATURE_WOW_PULSE +/* + * + * gwow_pulse_support - WOW pulse feature configuration + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * When set to 1 WOW pulse feature will be enabled. + * + * Related: gwow_pulse_pin, gwow_pulse_interval_low, gwow_pulse_interval_high + * + * Supported Feature: WOW pulse + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_PULSE_ENABLE CFG_INI_BOOL("gwow_pulse_support", \ + 0, \ + "Enable wow pulse") + +/* + * + * gwow_pulse_pin - GPIO pin for WOW pulse + * @Min: 0 + * @Max: 254 + * @Default: 35 + * + * Which PIN to send the Pulse + * + * Supported Feature: WOW pulse + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_PULSE_PIN CFG_INI_UINT("gwow_pulse_pin", \ + 0, 254, 35, \ + CFG_VALUE_OR_DEFAULT, \ + "Pin for wow pulse") + +/* + * + * gwow_pulse_interval_low - Pulse interval low + * @Min: 160 + * @Max: 480 + * @Default: 180 + * + * The interval of low level in the pulse + * + * Supported Feature: WOW pulse + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_PULSE_LOW CFG_INI_UINT("gwow_pulse_interval_low", \ + 160, 480, 180, \ + CFG_VALUE_OR_DEFAULT, \ + "Interval of low pulse") + +/* + * + * gwow_pulse_interval_high - Pulse interval high + * @Min: 20 + * @Max: 40 + * @Default: 20 + * + * The interval of high level in the pulse + * + * Supported Feature: WOW pulse + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_PULSE_HIGH CFG_INI_UINT("gwow_pulse_interval_high", \ + 20, 40, 20, \ + CFG_VALUE_OR_DEFAULT, \ + "Interval of high pulse") + +/* + * + * gwow_pulse_repeat_count - wow pulse repetition count + * @Min: 1 + * @Max: 0xffffffff + * @Default: 1 + * + * The repeat count of wow pin wave. + * Level low to level high is one time, 0xffffffff means endless. + * + * Supported Feature: WOW pulse + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_PULSE_REPEAT CFG_INI_UINT("gwow_pulse_repeat_count", \ + 1, 0xffffffff, 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Pulse repetition count") + +/* + * + * gwow_pulse_init_state - wow pulse init level + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * The init level of wow pin, 1 is high level, 0 is low level. + * + * Supported Feature: WOW pulse + * + * Usage: External + * + * + */ +#define CFG_PMO_WOW_PULSE_INIT CFG_INI_UINT("gwow_pulse_init_state", \ + 0, 1, 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Pulse init level") + +#define CFG_WOW_PULSE_ALL \ + CFG(CFG_PMO_WOW_PULSE_ENABLE) \ + CFG(CFG_PMO_WOW_PULSE_PIN) \ + CFG(CFG_PMO_WOW_PULSE_LOW) \ + CFG(CFG_PMO_WOW_PULSE_HIGH) \ + CFG(CFG_PMO_WOW_PULSE_REPEAT) \ + CFG(CFG_PMO_WOW_PULSE_INIT) +#else +#define CFG_WOW_PULSE_ALL +#endif /* WLAN_FEATURE_WOW_PULSE */ +#endif /* WLAN_PMO_WOW_PULSE_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c new file mode 100644 index 0000000000..433e8ba69e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c @@ -0,0 +1,934 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define utility API related to the pmo component + * called by other components + */ + +#include "wlan_pmo_obj_mgmt_api.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_static_config.h" +#include "wlan_pmo_main.h" +#include "target_if_pmo.h" + +QDF_STATUS pmo_init(void) +{ + QDF_STATUS status; + struct wlan_pmo_ctx *pmo_ctx; + + pmo_enter(); + if (pmo_allocate_ctx() != QDF_STATUS_SUCCESS) { + pmo_err("unable to allocate psoc ctx"); + status = QDF_STATUS_E_FAULT; + goto out; + } + + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_PMO, + pmo_psoc_object_created_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to register psoc create handle"); + goto out; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_PMO, + pmo_psoc_object_destroyed_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to register psoc create handle"); + goto out; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_PMO, + pmo_vdev_object_created_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to register vdev create handle"); + goto out; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_PMO, + pmo_vdev_object_destroyed_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) + pmo_err("unable to register vdev create handle"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_deinit(void) +{ + QDF_STATUS status; + struct wlan_pmo_ctx *pmo_ctx; + + pmo_enter(); + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_PMO, + pmo_psoc_object_created_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to unregister psoc create handle"); + goto out; + } + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_PMO, + pmo_psoc_object_destroyed_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to unregister psoc create handle"); + goto out; + } + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_PMO, + pmo_vdev_object_created_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to unregister vdev create handle"); + goto out; + } + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_PMO, + pmo_vdev_object_destroyed_notification, + (void *)pmo_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("unable to unregister vdev create handle"); + goto out; + } + +out: + pmo_free_ctx(); + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_psoc_object_created_notification( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct pmo_psoc_priv_obj *psoc_ctx = NULL; + QDF_STATUS status; + struct wlan_pmo_ctx *pmo_ctx; + + pmo_enter(); + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + QDF_ASSERT(0); + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + psoc_ctx = qdf_mem_malloc(sizeof(*psoc_ctx)); + if (!psoc_ctx) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_PMO, + psoc_ctx, + QDF_STATUS_SUCCESS); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to attach psoc_ctx with psoc"); + qdf_mem_free(psoc_ctx); + status = QDF_STATUS_E_FAILURE; + goto out; + } + qdf_spinlock_create(&psoc_ctx->lock); + qdf_wake_lock_create(&psoc_ctx->wow.wow_wake_lock, "pmo_wow_wl"); + status = qdf_event_create(&psoc_ctx->wow.target_suspend); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("target suspend event initialization failed"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + status = qdf_event_create(&psoc_ctx->wow.target_resume); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("target resume event initialization failed"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_atomic_init(&psoc_ctx->wow.wow_initial_wake_up); + /* Register PMO tx ops*/ + target_if_pmo_register_tx_ops(&psoc_ctx->pmo_tx_ops); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_psoc_object_destroyed_notification( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct pmo_psoc_priv_obj *psoc_ctx = NULL; + QDF_STATUS status; + + pmo_enter(); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_PMO, + psoc_ctx); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to detach psoc_ctx from psoc"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_spinlock_destroy(&psoc_ctx->lock); + qdf_event_destroy(&psoc_ctx->wow.target_suspend); + qdf_event_destroy(&psoc_ctx->wow.target_resume); + qdf_wake_lock_destroy(&psoc_ctx->wow.wow_wake_lock); + qdf_mem_zero(psoc_ctx, sizeof(*psoc_ctx)); + qdf_mem_free(psoc_ctx); +out: + pmo_exit(); + + return status; +} + +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD +static inline void +pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj *vdev_ctx) +{ + qdf_runtime_lock_init(&vdev_ctx->dyn_arp_ns_offload_rt_lock); +} + +static inline void +pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj *vdev_ctx) +{ + qdf_runtime_lock_deinit(&vdev_ctx->dyn_arp_ns_offload_rt_lock); +} +#else +static inline void +pmo_vdev_dynamic_arp_ns_offload_init(struct pmo_vdev_priv_obj *vdev_ctx) {} + +static inline void +pmo_vdev_dynamic_arp_ns_offload_deinit(struct pmo_vdev_priv_obj *vdev_ctx) {} +#endif + +QDF_STATUS pmo_vdev_object_created_notification( + struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct pmo_psoc_priv_obj *psoc_ctx = NULL; + struct wlan_objmgr_psoc *psoc; + struct pmo_vdev_priv_obj *vdev_ctx; + QDF_STATUS status; + + pmo_enter(); + + psoc = pmo_vdev_get_psoc(vdev); + + psoc_ctx = pmo_psoc_get_priv(psoc); + + vdev_ctx = qdf_mem_malloc(sizeof(*vdev_ctx)); + if (!vdev_ctx) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + status = wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_UMAC_COMP_PMO, + (void *)vdev_ctx, QDF_STATUS_SUCCESS); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to attach vdev_ctx with vdev"); + qdf_mem_free(vdev_ctx); + goto out; + } + + qdf_spinlock_create(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->magic_ptrn_enable = + psoc_ctx->psoc_cfg.magic_ptrn_enable; + vdev_ctx->ptrn_match_enable = + psoc_ctx->psoc_cfg.ptrn_match_enable_all_vdev; + vdev_ctx->pmo_psoc_ctx = psoc_ctx; + qdf_atomic_init(&vdev_ctx->gtk_err_enable); + pmo_vdev_dynamic_arp_ns_offload_init(vdev_ctx); + /* + * Update Powersave mode + * 0 - PMO_PS_ADVANCED_POWER_SAVE_DISABLE + * 1 - PMO_PS_ADVANCED_POWER_SAVE_ENABLE + * 2 - PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED + */ + vdev_ctx->ps_params.opm_mode = psoc_ctx->psoc_cfg.power_save_mode; + vdev_ctx->ps_params.ps_ito = PMO_PS_DATA_INACTIVITY_TIMEOUT; + vdev_ctx->ps_params.spec_wake = PMO_PS_DATA_SPEC_WAKE; + +out: + pmo_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_vdev_ready(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr) +{ + QDF_STATUS status; + + status = pmo_vdev_get_ref(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* Set Bridge MAC address */ + pmo_set_vdev_bridge_addr(vdev, bridgeaddr); + + /* Register static configuration with firmware */ + pmo_register_wow_wakeup_events(vdev); + + /* Register default wow patterns with firmware */ + pmo_register_wow_default_patterns(vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); + + /* + * The above APIs should return a status but don't. + * Just return success for now. + */ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_vdev_object_destroyed_notification( + struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct pmo_vdev_priv_obj *vdev_ctx = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + status = wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_PMO, + (void *)vdev_ctx); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to detach vdev_ctx with vdev"); + + qdf_spinlock_destroy(&vdev_ctx->pmo_vdev_lock); + pmo_vdev_dynamic_arp_ns_offload_deinit(vdev_ctx); + qdf_mem_free(vdev_ctx); + + return status; +} + +QDF_STATUS pmo_register_suspend_handler( + enum wlan_umac_comp_id id, + pmo_psoc_suspend_handler handler, + void *arg) +{ + struct wlan_pmo_ctx *pmo_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + QDF_ASSERT(0); + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) { + pmo_err("component id: %d is %s then valid components id", + id, id < 0 ? "Less" : "More"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_spin_lock_bh(&pmo_ctx->lock); + pmo_ctx->pmo_suspend_handler[id] = handler; + pmo_ctx->pmo_suspend_handler_arg[id] = arg; + qdf_spin_unlock_bh(&pmo_ctx->lock); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_unregister_suspend_handler( + enum wlan_umac_comp_id id, + pmo_psoc_suspend_handler handler) +{ + struct wlan_pmo_ctx *pmo_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + QDF_ASSERT(0); + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) { + pmo_err("component id: %d is %s then valid components id", + id, id < 0 ? "Less" : "More"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_spin_lock_bh(&pmo_ctx->lock); + if (pmo_ctx->pmo_suspend_handler[id] == handler) { + pmo_ctx->pmo_suspend_handler[id] = NULL; + pmo_ctx->pmo_suspend_handler_arg[id] = NULL; + qdf_spin_unlock_bh(&pmo_ctx->lock); + } else { + qdf_spin_unlock_bh(&pmo_ctx->lock); + pmo_err("can't find suspend handler for component id: %d ", id); + status = QDF_STATUS_E_FAILURE; + } +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_register_resume_handler( + enum wlan_umac_comp_id id, + pmo_psoc_resume_handler handler, + void *arg) +{ + struct wlan_pmo_ctx *pmo_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) { + pmo_err("component id: %d is %s then valid components id", + id, id < 0 ? "Less" : "More"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_spin_lock_bh(&pmo_ctx->lock); + pmo_ctx->pmo_resume_handler[id] = handler; + pmo_ctx->pmo_resume_handler_arg[id] = arg; + qdf_spin_unlock_bh(&pmo_ctx->lock); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_unregister_resume_handler( + enum wlan_umac_comp_id id, + pmo_psoc_resume_handler handler) +{ + struct wlan_pmo_ctx *pmo_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pmo_enter(); + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (id < 0 || id >= WLAN_UMAC_MAX_COMPONENTS) { + pmo_err("component id: %d is %s then valid components id", + id, id < 0 ? "Less" : "More"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + qdf_spin_lock_bh(&pmo_ctx->lock); + if (pmo_ctx->pmo_resume_handler[id] == handler) { + pmo_ctx->pmo_resume_handler[id] = NULL; + pmo_ctx->pmo_resume_handler_arg[id] = NULL; + qdf_spin_unlock_bh(&pmo_ctx->lock); + } else { + qdf_spin_unlock_bh(&pmo_ctx->lock); + pmo_err("can't find resume handler for component id: %d ", id); + status = QDF_STATUS_E_FAILURE; + } +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type suspend_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS resume_status; + struct wlan_pmo_ctx *pmo_ctx; + int i; + pmo_psoc_suspend_handler handler; + void *arg; + + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + pmo_err("unable to get pmo ctx"); + status = QDF_STATUS_E_FAILURE; + goto exit_with_status; + } + + /* call each component's suspend handler */ + for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) { + qdf_spin_lock_bh(&pmo_ctx->lock); + handler = pmo_ctx->pmo_suspend_handler[i]; + arg = pmo_ctx->pmo_suspend_handler_arg[i]; + qdf_spin_unlock_bh(&pmo_ctx->lock); + + if (!handler) + continue; + + status = handler(psoc, arg); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_err("component %d failed to suspend; status: %d", + i, status); + goto suspend_recovery; + } + } + + goto exit_with_status; + +suspend_recovery: + /* resume, starting with the last successfully suspended component */ + for (i -= 1; i >= 0; i--) { + qdf_spin_lock_bh(&pmo_ctx->lock); + handler = pmo_ctx->pmo_resume_handler[i]; + arg = pmo_ctx->pmo_resume_handler_arg[i]; + qdf_spin_unlock_bh(&pmo_ctx->lock); + + if (!handler) + continue; + + resume_status = handler(psoc, arg); + if (QDF_IS_STATUS_ERROR(resume_status)) + QDF_DEBUG_PANIC("component %d failed resume; status:%d", + i, resume_status); + } + +exit_with_status: + return status; +} + +QDF_STATUS pmo_resume_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type suspend_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_pmo_ctx *pmo_ctx; + uint8_t i; + pmo_psoc_suspend_handler handler; + void *arg; + + pmo_ctx = pmo_get_context(); + if (!pmo_ctx) { + pmo_err("unable to get pmo ctx"); + QDF_ASSERT(0); + status = QDF_STATUS_E_FAILURE; + goto exit_with_status; + } + + /* call each component's resume handler */ + for (i = 0; i < WLAN_UMAC_MAX_COMPONENTS; i++) { + qdf_spin_lock_bh(&pmo_ctx->lock); + handler = pmo_ctx->pmo_resume_handler[i]; + arg = pmo_ctx->pmo_resume_handler_arg[i]; + qdf_spin_unlock_bh(&pmo_ctx->lock); + + if (!handler) + continue; + + status = handler(psoc, arg); + if (QDF_IS_STATUS_ERROR(status)) { + pmo_fatal("Non-recoverable failure occurred!"); + pmo_fatal("component %d failed to resume; status: %d", + i, status); + QDF_BUG(0); + } + } + +exit_with_status: + return status; +} + +QDF_STATUS pmo_register_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc, + pmo_notify_pause_bitmap handler) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!handler) { + pmo_err("pmo_notify_vdev_pause_bitmap is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->pause_bitmap_notifier = handler; + } + + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_unregister_pause_bitmap_notifier(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->pause_bitmap_notifier = NULL; + } + + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_register_get_pause_bitmap(struct wlan_objmgr_psoc *psoc, + pmo_get_pause_bitmap handler) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!handler) { + pmo_err("pmo_get_pause_bitmap is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->get_pause_bitmap = handler; + } + + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_unregister_get_pause_bitmap(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->get_pause_bitmap = NULL; + } + + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_register_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc, + pmo_is_device_in_low_pwr_mode handler) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!handler) { + pmo_err("pmo_get_pause_bitmap is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->is_device_in_low_pwr_mode = handler; + } + + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +pmo_unregister_is_device_in_low_pwr_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->is_device_in_low_pwr_mode = NULL; + } + + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS pmo_register_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_dtim_period handler) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!handler) { + pmo_err("pmo_get_dtim_period is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->get_dtim_period = handler; + } + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +pmo_unregister_get_dtim_period_callback(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->get_dtim_period = NULL; + } + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +pmo_register_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc, + pmo_get_beacon_interval handler) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!handler) { + pmo_err("pmo_get_beacon_interval is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->get_beacon_interval = handler; + } + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +pmo_unregister_get_beacon_interval_callback(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + QDF_STATUS status; + + if (!psoc) { + pmo_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_psoc_get_ref(psoc); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("pmo cannot get the reference out of psoc"); + return status; + } + + pmo_psoc_with_ctx(psoc, psoc_ctx) { + psoc_ctx->get_beacon_interval = NULL; + } + pmo_psoc_put_ref(psoc); + + return QDF_STATUS_SUCCESS; +} + +bool +wlan_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return false; + + return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_sap_mode; +} + +bool +wlan_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return false; + + return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_go_mode; +} + +bool wlan_pmo_no_op_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + return pmo_no_op_on_page_fault(psoc); +} + +bool wlan_pmo_enable_ssr_on_page_fault(struct wlan_objmgr_psoc *psoc) +{ + return pmo_enable_ssr_on_page_fault(psoc); +} + +uint8_t +wlan_pmo_get_min_pagefault_wakeups_for_action(struct wlan_objmgr_psoc *psoc) +{ + return pmo_get_min_pagefault_wakeups_for_action(psoc); +} + +uint32_t +wlan_pmo_get_interval_for_pagefault_wakeup_counts(struct wlan_objmgr_psoc *psoc) +{ + return pmo_get_interval_for_pagefault_wakeup_counts(psoc); +} + +QDF_STATUS wlan_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval) +{ + return pmo_core_get_listen_interval(vdev, listen_interval); +} + +void wlan_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + pmo_core_vdev_set_ps_params(vdev, ps_params); +} + +QDF_STATUS wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + return pmo_core_vdev_get_ps_params(vdev, ps_params); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c new file mode 100644 index 0000000000..e2721e6ee6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_arp_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_enable_arp_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id) +{ + struct pmo_arp_offload_params *arp_offload_req = NULL; + struct pmo_ns_offload_params *ns_offload_req = NULL; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc = pmo_vdev_get_psoc(vdev); + + arp_offload_req = qdf_mem_malloc(sizeof(*arp_offload_req)); + if (!arp_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(arp_offload_req, &vdev_ctx->vdev_arp_req, + sizeof(*arp_offload_req)); + qdf_mem_copy(ns_offload_req, &vdev_ctx->vdev_ns_req, + sizeof(*ns_offload_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_debug("vdev_id: %d: ARP offload %d NS offload %d ns_count %u", + vdev_id, arp_offload_req->enable, ns_offload_req->enable, + ns_offload_req->num_ns_offload_count); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_arp_offload_req) { + pmo_err("send_arp_offload_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_arp_offload_req( + vdev, arp_offload_req, ns_offload_req); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to send ARP offload"); + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (vdev_ctx->vdev_arp_req.enable) + vdev_ctx->vdev_arp_req.is_offload_applied = true; + if (vdev_ctx->vdev_ns_req.enable) + vdev_ctx->vdev_ns_req.is_offload_applied = true; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +out: + if (arp_offload_req) + qdf_mem_free(arp_offload_req); + if (ns_offload_req) + qdf_mem_free(ns_offload_req); + + return status; +} + +QDF_STATUS pmo_tgt_disable_arp_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id) +{ + struct pmo_arp_offload_params *arp_offload_req = NULL; + struct pmo_ns_offload_params *ns_offload_req = NULL; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc = pmo_vdev_get_psoc(vdev); + + arp_offload_req = qdf_mem_malloc(sizeof(*arp_offload_req)); + if (!arp_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(arp_offload_req, &vdev_ctx->vdev_arp_req, + sizeof(*arp_offload_req)); + qdf_mem_copy(ns_offload_req, &vdev_ctx->vdev_ns_req, + sizeof(*ns_offload_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_debug("ARP Offload vdev_id: %d enable: %d", + vdev_id, + arp_offload_req->enable); + pmo_debug("NS Offload vdev_id: %d enable: %d ns_count: %u", + vdev_id, + ns_offload_req->enable, + ns_offload_req->num_ns_offload_count); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_arp_offload_req) { + pmo_err("send_arp_offload_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_arp_offload_req( + vdev, arp_offload_req, ns_offload_req); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send ARP offload"); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->vdev_arp_req.is_offload_applied = false; + vdev_ctx->vdev_ns_req.is_offload_applied = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +out: + if (arp_offload_req) + qdf_mem_free(arp_offload_req); + if (ns_offload_req) + qdf_mem_free(ns_offload_req); + pmo_exit(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c new file mode 100644 index 0000000000..666d8957af --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for PMO GTK offload feature to interact + * with target/wmi. + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_gtk_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_send_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + struct pmo_gtk_req *op_gtk_req = NULL; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pmo_err("Failed to find psoc from from vdev:%pK", + vdev); + status = QDF_STATUS_E_INVAL; + goto out; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_gtk_offload_req) { + pmo_err("send_gtk_offload_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + op_gtk_req = qdf_mem_malloc(sizeof(*op_gtk_req)); + if (!op_gtk_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + if (gtk_req->flags == PMO_GTK_OFFLOAD_ENABLE) { + qdf_atomic_set(&vdev_ctx->gtk_err_enable, true); + qdf_mem_copy(op_gtk_req->kck, gtk_req->kck, + gtk_req->kck_len); + op_gtk_req->kck_len = gtk_req->kck_len; + qdf_mem_copy(op_gtk_req->kek, gtk_req->kek, + PMO_KEK_LEN); + op_gtk_req->kek_len = gtk_req->kek_len; + qdf_mem_copy(&op_gtk_req->replay_counter, + >k_req->replay_counter, PMO_REPLAY_COUNTER_LEN); + } else { + qdf_atomic_set(&vdev_ctx->gtk_err_enable, false); + } + + pmo_debug("replay counter %llu", op_gtk_req->replay_counter); + op_gtk_req->flags = gtk_req->flags; + status = pmo_tx_ops.send_gtk_offload_req(vdev, op_gtk_req); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send gtk offload req event"); +out: + if (op_gtk_req) + qdf_mem_free(op_gtk_req); + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_get_gtk_rsp(struct wlan_objmgr_vdev *vdev) +{ + + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pmo_err("Failed to find psoc from from vdev:%pK", + vdev); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_get_gtk_rsp_cmd) { + pmo_err("send_get_gtk_rsp_cmd is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_get_gtk_rsp_cmd(vdev); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send_get_gtk_rsp_cmd event"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_gtk_rsp_evt(struct wlan_objmgr_psoc *psoc, + struct pmo_gtk_rsp_params *rsp_param) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct pmo_vdev_priv_obj *vdev_ctx; + + pmo_enter(); + if (!rsp_param) { + pmo_err("gtk rsp param is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp_param->vdev_id, + WLAN_PMO_ID); + if (!vdev) { + pmo_err("vdev is null vdev_id:%d psoc:%pK", + rsp_param->vdev_id, psoc); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + vdev_ctx = pmo_vdev_get_priv(vdev); + + status = pmo_get_vdev_bss_peer_mac_addr(vdev, &rsp_param->bssid); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("cannot find peer mac address"); + goto dec_ref; + } + + /* update cached replay counter */ + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->vdev_gtk_req.replay_counter = rsp_param->replay_counter; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + if (vdev_ctx->vdev_gtk_rsp_req.callback) { + pmo_debug("callback:%pK context:%pK psoc:%pK vdev_id:%d", + vdev_ctx->vdev_gtk_rsp_req.callback, + vdev_ctx->vdev_gtk_rsp_req.callback_context, + psoc, rsp_param->vdev_id); + vdev_ctx->vdev_gtk_rsp_req.callback( + vdev_ctx->vdev_gtk_rsp_req.callback_context, + rsp_param); + } else { + pmo_err("gtk rsp callback is null for vdev_id:%d psoc %pK", + rsp_param->vdev_id, + psoc); + } + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PMO_ID); +out: + pmo_exit(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_hw_filter.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_hw_filter.c new file mode 100644 index 0000000000..396d3074df --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_hw_filter.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_hw_filter_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_conf_hw_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_hw_filter_params *req) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops ops; + + pmo_enter(); + + pmo_debug("Send %s hw filter mode 0x%X for vdev_id %u", + req->enable ? "Enable" : "Disable", req->mode_bitmap, + req->vdev_id); + + ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!ops.send_conf_hw_filter_req) { + pmo_err("send_conf_hw_filter_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto exit_with_status; + } + + status = ops.send_conf_hw_filter_req(psoc, req); + +exit_with_status: + pmo_exit(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_icmp.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_icmp.c new file mode 100644 index 0000000000..b230cc67be --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_icmp.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS +pmo_tgt_config_icmp_offload_req(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_debug("vdev_id: %d: ICMP offload %d", pmo_icmp_req->vdev_id, + pmo_icmp_req->enable); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_icmp_offload_req) { + pmo_err("send_icmp_offload_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = pmo_tx_ops.send_icmp_offload_req(psoc, pmo_icmp_req); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_lphb.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_lphb.c new file mode 100644 index 0000000000..f363e5614a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_lphb.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo low power hear beat feature + * to interact with target/WMI. + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_lphb_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_send_lphb_enable(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_enable_req *ts_lphb_enable) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_lphb_enable) { + pmo_err("send_lphb_enable is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_lphb_enable(psoc, ts_lphb_enable); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send lphb enable"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_params *ts_lphb_tcp_param) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_lphb_tcp_params) { + pmo_err("send_lphb_tcp_params is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_lphb_tcp_params(psoc, ts_lphb_tcp_param); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send lphb tcp params"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_lphb_tcp_filter_req) { + pmo_err("send_lphb_tcp_filter_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_lphb_tcp_filter_req(psoc, ts_lphb_tcp_filter); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send lphb tcp filter req"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_params *ts_lphb_udp_param) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_lphb_upd_params) { + pmo_err("send_lphb_upd_params is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_lphb_upd_params(psoc, ts_lphb_udp_param); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send lphb udp param"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter) +{ + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_lphb_udp_filter_req) { + pmo_err("send_lphb_udp_filter_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_lphb_udp_filter_req(psoc, ts_lphb_udp_filter); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send lphb udp filter req"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_lphb_rsp_evt(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_rsp *rsp_param) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + + psoc_ctx = pmo_psoc_get_priv(psoc); + if (psoc_ctx->wow.lphb_cb && psoc_ctx->wow.lphb_cb_ctx) { + psoc_ctx->wow.lphb_cb(psoc_ctx->wow.lphb_cb_ctx, rsp_param); + } else { + pmo_err("lphb rsp callback/context is null for psoc %pK", + psoc); + } + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c new file mode 100644 index 0000000000..e8118f81ca --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_set_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_set_mc_filter_req) { + pmo_err("send_add_clear_mcbc_filter_request is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_set_mc_filter_req( + vdev, multicast_addr); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add/clear mc filter"); +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_clear_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_clear_mc_filter_req) { + pmo_err("send_add_clear_mcbc_filter_request is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_clear_mc_filter_req( + vdev, multicast_addr); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add/clear mc filter"); +out: + pmo_exit(); + + return status; +} + +bool pmo_tgt_get_multiple_mc_filter_support(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.get_multiple_mc_filter_support) { + pmo_err("get_multiple_mc_filter_support is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return pmo_tx_ops.get_multiple_mc_filter_support(psoc); +} + +QDF_STATUS pmo_tgt_set_multiple_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_set_multiple_mc_filter_req) { + pmo_err("send_set_multiple_mc_filter_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_set_multiple_mc_filter_req( + vdev, mc_list); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add/clear multiple mc filter"); +out: + + return status; +} + +QDF_STATUS pmo_tgt_clear_multiple_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_clear_multiple_mc_filter_req) { + pmo_err("send_clear_multiple_mc_filter_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_clear_multiple_mc_filter_req( + vdev, mc_list); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add/clear multiple mc filter"); +out: + + return status; +} + + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c new file mode 100644 index 0000000000..8970e7aa4f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for PMO NS offload feature to interact + * with target/wmi. + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_arp_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_enable_ns_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id) +{ + struct pmo_arp_offload_params *arp_offload_req = NULL; + struct pmo_ns_offload_params *ns_offload_req = NULL; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc = pmo_vdev_get_psoc(vdev); + + arp_offload_req = qdf_mem_malloc(sizeof(*arp_offload_req)); + if (!arp_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(arp_offload_req, &vdev_ctx->vdev_arp_req, + sizeof(*arp_offload_req)); + qdf_mem_copy(ns_offload_req, &vdev_ctx->vdev_ns_req, + sizeof(*ns_offload_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_debug("vdev_id: %d: ARP offload %d NS offload %d ns_count %u", + vdev_id, + arp_offload_req->enable, ns_offload_req->enable, + ns_offload_req->num_ns_offload_count); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_ns_offload_req) { + pmo_err("send_ns_offload_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_ns_offload_req( + vdev, arp_offload_req, ns_offload_req); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to send NS offload"); + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + if (vdev_ctx->vdev_arp_req.enable) + vdev_ctx->vdev_arp_req.is_offload_applied = true; + if (vdev_ctx->vdev_ns_req.enable) + vdev_ctx->vdev_ns_req.is_offload_applied = true; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +out: + if (arp_offload_req) + qdf_mem_free(arp_offload_req); + if (ns_offload_req) + qdf_mem_free(ns_offload_req); + + return status; +} + +QDF_STATUS pmo_tgt_disable_ns_offload_req(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id) +{ + struct pmo_arp_offload_params *arp_offload_req = NULL; + struct pmo_ns_offload_params *ns_offload_req = NULL; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + psoc = pmo_vdev_get_psoc(vdev); + + arp_offload_req = qdf_mem_malloc(sizeof(*arp_offload_req)); + if (!arp_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + ns_offload_req = qdf_mem_malloc(sizeof(*ns_offload_req)); + if (!ns_offload_req) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + qdf_mem_copy(arp_offload_req, &vdev_ctx->vdev_arp_req, + sizeof(*arp_offload_req)); + qdf_mem_copy(ns_offload_req, &vdev_ctx->vdev_ns_req, + sizeof(*ns_offload_req)); + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_debug("ARP Offload vdev_id: %d enable: %d", + vdev_id, + arp_offload_req->enable); + pmo_debug("NS Offload vdev_id: %d enable: %d ns_count: %u", + vdev_id, + ns_offload_req->enable, + ns_offload_req->num_ns_offload_count); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_ns_offload_req) { + pmo_err("send_ns_offload_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_ns_offload_req( + vdev, arp_offload_req, ns_offload_req); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to send NS offload"); + + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + vdev_ctx->vdev_arp_req.is_offload_applied = false; + vdev_ctx->vdev_ns_req.is_offload_applied = false; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + +out: + if (arp_offload_req) + qdf_mem_free(arp_offload_req); + if (ns_offload_req) + qdf_mem_free(ns_offload_req); + pmo_exit(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c new file mode 100644 index 0000000000..ecc8d2d905 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_pkt_filter_public_struct.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_set_pkt_filter(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct pmo_rcv_pkt_fltr_cfg *request_buf = NULL; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + struct qdf_mac_addr peer_bssid; + + pmo_enter(); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pmo_err("psoc unavailable for vdev %pK", vdev); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_debug("filter_type=%d, filter_id = %d", + pmo_set_pkt_fltr_req->filter_type, + pmo_set_pkt_fltr_req->filter_id); + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (!request_buf) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + status = pmo_get_vdev_bss_peer_mac_addr(vdev, + &peer_bssid); + if (status != QDF_STATUS_SUCCESS) { + status = QDF_STATUS_E_INVAL; + goto out; + } + + qdf_mem_copy(request_buf, pmo_set_pkt_fltr_req, sizeof(*request_buf)); + + qdf_mem_copy(&request_buf->self_macaddr.bytes, + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE); + + qdf_copy_macaddr(&pmo_set_pkt_fltr_req->bssid, + &peer_bssid); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_set_pkt_filter) { + pmo_err("send_set_pkt_filter is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_set_pkt_filter(vdev, request_buf); + if (status != QDF_STATUS_SUCCESS) + goto out; + +out: + if (request_buf) + qdf_mem_free(request_buf); + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_clear_pkt_filter(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct pmo_rcv_pkt_fltr_clear_param *request_buf = NULL; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + struct qdf_mac_addr peer_bssid; + + pmo_enter(); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pmo_err("psoc unavailable for vdev %pK", vdev); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_debug("filter_id = %d", pmo_clr_pkt_fltr_param->filter_id); + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (!request_buf) { + status = QDF_STATUS_E_NOMEM; + goto out; + } + + status = pmo_get_vdev_bss_peer_mac_addr(vdev, + &peer_bssid); + if (status != QDF_STATUS_SUCCESS) { + status = QDF_STATUS_E_INVAL; + goto out; + } + + qdf_mem_copy(request_buf, pmo_clr_pkt_fltr_param, sizeof(*request_buf)); + + qdf_mem_copy(&request_buf->self_macaddr.bytes, + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE); + + qdf_copy_macaddr(&pmo_clr_pkt_fltr_param->bssid, + &peer_bssid); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_clear_pkt_filter) { + pmo_err("send_clear_pkt_filter is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_clear_pkt_filter(vdev, request_buf); + if (status != QDF_STATUS_SUCCESS) + goto out; + +out: + if (request_buf) + qdf_mem_free(request_buf); + pmo_exit(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c new file mode 100644 index 0000000000..4ffd406992 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_wow.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_send_enhance_multicast_offload_req( + struct wlan_objmgr_vdev *vdev, + uint8_t action) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_enhance_mc_offload_req) { + pmo_err("send_enhance_multicast_offload is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_enhance_mc_offload_req(vdev, action); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to config enhance multicast offload"); +out: + + return status; +} + +QDF_STATUS pmo_tgt_send_ra_filter_req(struct wlan_objmgr_vdev *vdev) +{ + + QDF_STATUS status; + uint8_t default_pattern; + uint16_t ra_interval; + struct pmo_vdev_priv_obj *vdev_ctx; + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + + psoc = pmo_vdev_get_psoc(vdev); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + vdev_id = pmo_vdev_get_id(vdev); + qdf_spin_lock_bh(&vdev_ctx->pmo_vdev_lock); + ra_interval = vdev_ctx->pmo_psoc_ctx->psoc_cfg.ra_ratelimit_interval; + qdf_spin_unlock_bh(&vdev_ctx->pmo_vdev_lock); + + pmo_debug("send RA rate limit [%d] to fw vdev = %d", + ra_interval, vdev_id); + + default_pattern = pmo_get_and_increment_wow_default_ptrn(vdev_ctx); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_ra_filter_req) { + pmo_err("send_ra_filter_cmd is null"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + status = pmo_tx_ops.send_ra_filter_req( + vdev, default_pattern, ra_interval); + if (status != QDF_STATUS_SUCCESS) { + pmo_err("Failed to send RA rate limit to fw"); + pmo_decrement_wow_default_ptrn(vdev_ctx); + } +out: + pmo_exit(); + + return status; +} + +QDF_STATUS pmo_tgt_send_action_frame_pattern_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_action_wakeup_set_params *cmd) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_action_frame_pattern_req) { + pmo_err("send_add_action_frame_pattern_cmd is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_action_frame_pattern_req(vdev, cmd); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to add filter"); +out: + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c new file mode 100644 index 0000000000..0588984767 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_wow.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_vdev_update_param_req(struct wlan_objmgr_vdev *vdev, + enum pmo_vdev_param_id param_id, uint32_t param_value) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_enter(); + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_vdev_param_update_req) { + pmo_err("send_vdev_param_update_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_vdev_param_update_req(vdev, param_id, + param_value); +out: + pmo_exit(); + + return status; +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +QDF_STATUS +pmo_tgt_send_igmp_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_igmp_offload_req) { + pmo_err("send_vdev_param_set_req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = pmo_tx_ops.send_igmp_offload_req(vdev, pmo_igmp_req); + + return status; +} +#endif + +QDF_STATUS pmo_tgt_send_vdev_sta_ps_param(struct wlan_objmgr_vdev *vdev, + enum pmo_sta_powersave_param ps_param, uint32_t param_value) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_vdev_sta_ps_param_req) { + pmo_err("send_vdev_param_set_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + status = pmo_tx_ops.send_vdev_sta_ps_param_req(vdev, ps_param, + param_value); +out: + return status; +} + +void pmo_tgt_psoc_update_wow_bus_suspend_state(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_update_wow_bus_suspend) { + pmo_err("psoc_update_wow_bus_suspend is null"); + return; + } + pmo_tx_ops.psoc_update_wow_bus_suspend(psoc, val); +} + +int pmo_tgt_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc) +{ + + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_get_host_credits) { + pmo_err("psoc_get_host_credits is null"); + return 0; + } + + return pmo_tx_ops.psoc_get_host_credits(psoc); +} + +int pmo_tgt_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc) +{ + + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_get_pending_cmnds) { + pmo_err("psoc_get_pending_cmnds is null"); + return -EAGAIN; + } + + return pmo_tx_ops.psoc_get_pending_cmnds(psoc); +} + +void pmo_tgt_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.update_target_suspend_flag) { + pmo_err("update_target_suspend_flag is null"); + return; + } + pmo_tx_ops.update_target_suspend_flag(psoc, val); +} + +void pmo_tgt_update_target_suspend_acked_flag(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.update_target_suspend_acked_flag) { + pmo_err("update_target_suspend_acked_flag is null"); + return; + } + pmo_tx_ops.update_target_suspend_acked_flag(psoc, val); +} + +bool pmo_tgt_is_target_suspended(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.is_target_suspended) { + pmo_err("is_target_suspended is null"); + return false; + } + return pmo_tx_ops.is_target_suspended(psoc); +} + +QDF_STATUS pmo_tgt_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc, + struct pmo_wow_cmd_params *param) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc_ctx = pmo_psoc_get_priv(psoc); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + + if (psoc_ctx->wow.wow_state == pmo_wow_state_legacy_d0) { + if (!pmo_tx_ops.psoc_send_d0wow_enable_req) { + pmo_err("psoc_send_d0wow_enable_req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + pmo_debug("Sending D0WOW enable command..."); + return pmo_tx_ops.psoc_send_d0wow_enable_req(psoc); + } + + if (!pmo_tx_ops.psoc_send_wow_enable_req) { + pmo_err("psoc_send_wow_enable_req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + return pmo_tx_ops.psoc_send_wow_enable_req(psoc, param); +} + +QDF_STATUS pmo_tgt_psoc_send_supend_req(struct wlan_objmgr_psoc *psoc, + struct pmo_suspend_params *param) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_send_supend_req) { + pmo_err("psoc_send_supend_req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return pmo_tx_ops.psoc_send_supend_req(psoc, param); +} + +QDF_STATUS pmo_tgt_psoc_set_runtime_pm_inprogress(struct wlan_objmgr_psoc *psoc, + bool value) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_set_runtime_pm_in_progress) { + pmo_err("pmo ops is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + pmo_tx_ops.psoc_set_runtime_pm_in_progress(psoc, value); + + return QDF_STATUS_SUCCESS; +} + +bool pmo_tgt_psoc_get_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_get_runtime_pm_in_progress) { + pmo_err("psoc_get_runtime_pm_in_progress is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return pmo_tx_ops.psoc_get_runtime_pm_in_progress(psoc); +} + +QDF_STATUS pmo_tgt_psoc_send_host_wakeup_ind(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *psoc_ctx; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc_ctx = pmo_psoc_get_priv(psoc); + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + + if (psoc_ctx->psoc_cfg.d0_wow_supported && + psoc_ctx->wow.wow_state == pmo_wow_state_legacy_d0) { + if (!pmo_tx_ops.psoc_send_d0wow_disable_req) { + pmo_err("psoc_send_d0wow_disable_req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + pmo_debug("Sending D0WOW disable command..."); + return pmo_tx_ops.psoc_send_d0wow_disable_req(psoc); + } + + if (!pmo_tx_ops.psoc_send_host_wakeup_ind) { + pmo_err("psoc_send_host_wakeup_ind is null"); + return QDF_STATUS_E_NULL_VALUE; + } + return pmo_tx_ops.psoc_send_host_wakeup_ind(psoc); +} + +QDF_STATUS pmo_tgt_psoc_send_target_resume_req(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_send_target_resume_req) { + pmo_err("send_target_resume_req is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return pmo_tx_ops.psoc_send_target_resume_req(psoc); +} + +QDF_STATUS pmo_tgt_psoc_send_idle_roam_monitor(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_send_idle_roam_suspend_mode) { + pmo_err("NULL fp"); + return QDF_STATUS_E_NULL_VALUE; + } + return pmo_tx_ops.psoc_send_idle_roam_suspend_mode(psoc, val); +} + +QDF_STATUS pmo_tgt_psoc_set_wow_enable_ack_failed(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_pmo_tx_ops pmo_tx_ops; + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.psoc_set_wow_enable_ack_failed) { + pmo_err("pmo ops is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + pmo_tx_ops.psoc_set_wow_enable_ack_failed(psoc); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c new file mode 100644 index 0000000000..3824065006 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements public API for pmo to interact with target/WMI + */ + +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_wow.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" +#include "wlan_pmo_main.h" + +QDF_STATUS pmo_tgt_enable_wow_wakeup_event( + struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + int vdev_id; + + psoc = pmo_vdev_get_psoc(vdev); + vdev_id = pmo_vdev_get_id(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_enable_wow_wakeup_event_req) { + pmo_err("send_enable_wow_wakeup_event_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_debug("Enable wakeup events 0x%08x%08x%08x%08x for vdev_id %d", + bitmap[3], bitmap[2], bitmap[1], bitmap[0], vdev_id); + + status = pmo_tx_ops.send_enable_wow_wakeup_event_req(vdev, bitmap); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to enable wow wakeup event"); +out: + + return status; +} + +QDF_STATUS pmo_tgt_disable_wow_wakeup_event( + struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + int vdev_id; + + psoc = pmo_vdev_get_psoc(vdev); + vdev_id = pmo_vdev_get_id(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_disable_wow_wakeup_event_req) { + pmo_err("send_disable_wow_wakeup_event_req is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + pmo_debug("Disable wakeup events 0x%x%x%x%x for vdev_id %d", + bitmap[3], bitmap[2], bitmap[1], bitmap[0], vdev_id); + + status = pmo_tx_ops.send_disable_wow_wakeup_event_req(vdev, bitmap); + if (status != QDF_STATUS_SUCCESS) + pmo_err("Failed to disable wow wakeup event"); +out: + + return status; +} + +QDF_STATUS pmo_tgt_send_wow_patterns_to_fw( + struct wlan_objmgr_vdev *vdev, uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + + vdev_ctx = pmo_vdev_get_priv(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.send_add_wow_pattern) { + pmo_err("send_add_wow_pattern is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.send_add_wow_pattern( + vdev, ptrn_id, ptrn, + ptrn_len, ptrn_offset, mask, + mask_len, user); + if (status != QDF_STATUS_SUCCESS) { + if (!user) + pmo_decrement_wow_default_ptrn(vdev_ctx); + pmo_err("Failed to send wow pattern event"); + goto out; + } + + if (user) + pmo_increment_wow_user_ptrn(vdev_ctx); +out: + + return status; +} + +QDF_STATUS pmo_tgt_del_wow_pattern( + struct wlan_objmgr_vdev *vdev, uint8_t ptrn_id, + bool user) +{ + QDF_STATUS status; + struct pmo_vdev_priv_obj *vdev_ctx; + struct wlan_objmgr_psoc *psoc; + struct wlan_pmo_tx_ops pmo_tx_ops; + + psoc = pmo_vdev_get_psoc(vdev); + vdev_ctx = pmo_vdev_get_priv(vdev); + + pmo_tx_ops = GET_PMO_TX_OPS_FROM_PSOC(psoc); + if (!pmo_tx_ops.del_wow_pattern) { + pmo_err("del_wow_pattern is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + status = pmo_tx_ops.del_wow_pattern(vdev, ptrn_id); + if (status) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (user) + pmo_decrement_wow_user_ptrn(vdev_ctx); + else + pmo_decrement_wow_default_ptrn(vdev_ctx); +out: + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c new file mode 100644 index 0000000000..3a075009c2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c @@ -0,0 +1,1109 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: public API related to the pmo called by north bound HDD/OSIF + */ + +#include "wlan_pmo_ucfg_api.h" +#include "wlan_pmo_apf.h" +#include "wlan_pmo_arp.h" +#include "wlan_pmo_ns.h" +#include "wlan_pmo_gtk.h" +#include "wlan_pmo_wow.h" +#include "wlan_pmo_mc_addr_filtering.h" +#include "wlan_pmo_main.h" +#include "wlan_pmo_lphb.h" +#include "wlan_pmo_suspend_resume.h" +#include "wlan_pmo_pkt_filter.h" +#include "wlan_pmo_hw_filter.h" +#include "wlan_pmo_cfg.h" +#include "wlan_pmo_static_config.h" +#include "cfg_ucfg_api.h" +#include "wlan_pmo_icmp.h" + +QDF_STATUS ucfg_pmo_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return pmo_psoc_open(psoc); +} + +QDF_STATUS ucfg_pmo_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return pmo_psoc_close(psoc); +} + +uint32_t ucfg_pmo_get_apf_instruction_size(struct wlan_objmgr_psoc *psoc) +{ + QDF_BUG(psoc); + if (!psoc) + return 0; + + return pmo_get_apf_instruction_size(psoc); +} + +uint8_t ucfg_pmo_get_num_wow_filters(struct wlan_objmgr_psoc *psoc) +{ + QDF_BUG(psoc); + if (!psoc) + return 0; + + return pmo_get_num_wow_filters(psoc); +} + +QDF_STATUS ucfg_pmo_get_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + return pmo_core_get_psoc_config(psoc, psoc_cfg); +} + +QDF_STATUS ucfg_pmo_update_psoc_config(struct wlan_objmgr_psoc *psoc, + struct pmo_psoc_cfg *psoc_cfg) +{ + return pmo_core_update_psoc_config(psoc, psoc_cfg); +} + +QDF_STATUS ucfg_pmo_psoc_set_caps(struct wlan_objmgr_psoc *psoc, + struct pmo_device_caps *caps) +{ + QDF_BUG(psoc); + if (!psoc) + return QDF_STATUS_E_INVAL; + + QDF_BUG(caps); + if (!caps) + return QDF_STATUS_E_INVAL; + + pmo_psoc_set_caps(psoc, caps); + + return QDF_STATUS_SUCCESS; +} + +bool ucfg_pmo_is_ap_mode_supports_arp_ns(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE vdev_opmode) +{ + return pmo_core_is_ap_mode_supports_arp_ns(psoc, vdev_opmode); +} + +bool ucfg_pmo_is_vdev_connected(struct wlan_objmgr_vdev *vdev) +{ + if (wlan_vdev_is_up(vdev) == QDF_STATUS_SUCCESS) + return true; + else + return false; +} + +bool ucfg_pmo_is_vdev_supports_offload(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_is_vdev_supports_offload(vdev); +} + +void ucfg_pmo_enable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event) +{ + pmo_core_enable_wakeup_event(psoc, vdev_id, wow_event); +} + +void ucfg_pmo_disable_wakeup_event(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + WOW_WAKE_EVENT_TYPE wow_event) +{ + pmo_core_disable_wakeup_event(psoc, vdev_id, wow_event); +} + +QDF_STATUS ucfg_pmo_cache_arp_offload_req(struct pmo_arp_req *arp_req) +{ + return pmo_core_cache_arp_offload_req(arp_req); +} + +QDF_STATUS ucfg_pmo_check_arp_offload(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id) +{ + return pmo_core_arp_check_offload(psoc, trigger, vdev_id); +} + +QDF_STATUS ucfg_pmo_flush_arp_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_flush_arp_offload_req(vdev); +} + +QDF_STATUS ucfg_pmo_enable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return pmo_core_enable_arp_offload_in_fwr(vdev, trigger); +} + +QDF_STATUS +ucfg_pmo_disable_arp_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return pmo_core_disable_arp_offload_in_fwr(vdev, trigger); +} + +QDF_STATUS +ucfg_pmo_get_arp_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *params) +{ + return pmo_core_get_arp_offload_params(vdev, params); +} + +#ifdef WLAN_NS_OFFLOAD +QDF_STATUS ucfg_pmo_cache_ns_offload_req(struct pmo_ns_req *ns_req) +{ + return pmo_core_cache_ns_offload_req(ns_req); +} + +QDF_STATUS ucfg_pmo_ns_offload_check(struct wlan_objmgr_psoc *psoc, + enum pmo_offload_trigger trigger, + uint8_t vdev_id) +{ + return pmo_core_ns_check_offload(psoc, trigger, vdev_id); +} + +QDF_STATUS ucfg_pmo_flush_ns_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_flush_ns_offload_req(vdev); +} + +QDF_STATUS +ucfg_pmo_enable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return pmo_core_enable_ns_offload_in_fwr(vdev, trigger); +} + +QDF_STATUS +ucfg_pmo_disable_ns_offload_in_fwr(struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + return pmo_core_disable_ns_offload_in_fwr(vdev, trigger); +} +#endif /* WLAN_NS_OFFLOAD */ + +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD +QDF_STATUS +ucfg_pmo_dynamic_arp_ns_offload_enable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_dynamic_arp_ns_offload_enable(vdev); +} + +QDF_STATUS +ucfg_pmo_dynamic_arp_ns_offload_disable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_dynamic_arp_ns_offload_disable(vdev); +} + +bool +ucfg_pmo_get_arp_ns_offload_dynamic_disable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_get_dynamic_arp_ns_offload_disable(vdev); +} + +void +ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_dynamic_arp_ns_offload_runtime_prevent(vdev); +} + +void +ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_dynamic_arp_ns_offload_runtime_allow(vdev); +} +#endif + +QDF_STATUS +ucfg_pmo_get_ns_offload_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ns_offload_params *params) +{ + return pmo_core_get_ns_offload_params(vdev, params); +} + +enum pmo_ns_addr_scope +ucfg_pmo_ns_addr_scope(uint32_t ipv6_scope) +{ + switch (ipv6_scope) { + case IPV6_ADDR_SCOPE_NODELOCAL: + return PMO_NS_ADDR_SCOPE_NODELOCAL; + case IPV6_ADDR_SCOPE_LINKLOCAL: + return PMO_NS_ADDR_SCOPE_LINKLOCAL; + case IPV6_ADDR_SCOPE_SITELOCAL: + return PMO_NS_ADDR_SCOPE_SITELOCAL; + case IPV6_ADDR_SCOPE_ORGLOCAL: + return PMO_NS_ADDR_SCOPE_ORGLOCAL; + case IPV6_ADDR_SCOPE_GLOBAL: + return PMO_NS_ADDR_SCOPE_GLOBAL; + } + + return PMO_NS_ADDR_SCOPE_INVALID; +} + +QDF_STATUS ucfg_pmo_cache_mc_addr_list( + struct pmo_mc_addr_list_params *mc_list_config) +{ + return pmo_core_cache_mc_addr_list(mc_list_config); +} + +QDF_STATUS ucfg_pmo_flush_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return pmo_core_flush_mc_addr_list(psoc, vdev_id); +} + +QDF_STATUS ucfg_pmo_enable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + return pmo_core_enable_mc_addr_filtering_in_fwr(psoc, + vdev_id, trigger); +} + +QDF_STATUS ucfg_pmo_disable_mc_addr_filtering_in_fwr( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pmo_offload_trigger trigger) +{ + return pmo_core_disable_mc_addr_filtering_in_fwr(psoc, + vdev_id, trigger); +} + +uint8_t ucfg_pmo_max_mc_addr_supported(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_max_mc_addr_supported(psoc); +} + +QDF_STATUS +ucfg_pmo_get_mc_addr_list(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct pmo_mc_addr_list *mc_list_req) +{ + return pmo_core_get_mc_addr_list(psoc, vdev_id, mc_list_req); +} + +QDF_STATUS +ucfg_pmo_cache_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + return pmo_core_cache_gtk_offload_req(vdev, gtk_req); +} + +QDF_STATUS ucfg_pmo_flush_gtk_offload_req(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_flush_gtk_offload_req(vdev); +} + +QDF_STATUS ucfg_pmo_enable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enable_gtk_offload_in_fwr(vdev); +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +QDF_STATUS ucfg_pmo_enable_igmp_offload(struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *igmp_req) +{ + return pmo_core_enable_igmp_offload(vdev, igmp_req); +} +#endif + +QDF_STATUS ucfg_pmo_disable_gtk_offload_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_disable_gtk_offload_in_fwr(vdev); +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +uint8_t ucfg_pmo_get_pkt_filter_bitmap(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.packet_filters_bitmap; +} + +uint32_t ucfg_pmo_get_num_packet_filters(struct wlan_objmgr_psoc *psoc) +{ + QDF_BUG(psoc); + if (!psoc) + return 0; + + return pmo_get_num_packet_filters(psoc); +} + +QDF_STATUS +ucfg_pmo_set_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req, + uint8_t vdev_id) +{ + return pmo_core_set_pkt_filter(psoc, pmo_set_pkt_fltr_req, vdev_id); +} + +QDF_STATUS ucfg_pmo_clear_pkt_filter( + struct wlan_objmgr_psoc *psoc, + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param, + uint8_t vdev_id) +{ + return pmo_core_clear_pkt_filter(psoc, + pmo_clr_pkt_fltr_param, vdev_id); +} +#endif + +QDF_STATUS ucfg_pmo_get_gtk_rsp(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_rsp_req *gtk_rsp_req) +{ + return pmo_core_get_gtk_rsp(vdev, gtk_rsp_req); +} + +void ucfg_pmo_update_extscan_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ + pmo_core_update_extscan_in_progress(vdev, value); +} + +void ucfg_pmo_update_p2plo_in_progress(struct wlan_objmgr_vdev *vdev, + bool value) +{ + pmo_core_update_p2plo_in_progress(vdev, value); +} + +QDF_STATUS ucfg_pmo_lphb_config_req(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_req *lphb_req, + void *lphb_cb_ctx, + pmo_lphb_callback callback) +{ + return pmo_core_lphb_config_req(psoc, lphb_req, lphb_cb_ctx, callback); +} + +void ucfg_pmo_psoc_update_power_save_mode(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + pmo_core_psoc_update_power_save_mode(psoc, value); +} + +void ucfg_pmo_psoc_update_dp_handle(struct wlan_objmgr_psoc *psoc, + void *dp_handle) +{ + pmo_core_psoc_update_dp_handle(psoc, dp_handle); +} + +void ucfg_pmo_psoc_update_htc_handle(struct wlan_objmgr_psoc *psoc, + void *htc_handle) +{ + pmo_core_psoc_update_htc_handle(psoc, htc_handle); +} + +void ucfg_pmo_psoc_set_hif_handle(struct wlan_objmgr_psoc *psoc, + void *hif_handle) +{ + pmo_core_psoc_set_hif_handle(psoc, hif_handle); +} + +void ucfg_pmo_psoc_set_txrx_pdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t txrx_pdev_id) +{ + pmo_core_psoc_set_txrx_pdev_id(psoc, txrx_pdev_id); +} + +void ucfg_pmo_psoc_handle_initial_wake_up(void *cb_ctx) +{ + return pmo_core_psoc_handle_initial_wake_up(cb_ctx); +} + +QDF_STATUS +ucfg_pmo_psoc_user_space_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return pmo_core_psoc_user_space_suspend_req(psoc, type); +} + +QDF_STATUS +ucfg_pmo_psoc_user_space_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return pmo_core_psoc_user_space_resume_req(psoc, type); +} + +QDF_STATUS ucfg_pmo_suspend_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return pmo_suspend_all_components(psoc, type); +} + +QDF_STATUS ucfg_pmo_resume_all_components(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return pmo_resume_all_components(psoc, type); +} + +QDF_STATUS +ucfg_pmo_psoc_bus_suspend_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type, + struct pmo_wow_enable_params *wow_params) +{ + return pmo_core_psoc_bus_suspend_req(psoc, type, wow_params); +} + +#ifdef FEATURE_RUNTIME_PM +QDF_STATUS ucfg_pmo_psoc_bus_runtime_suspend(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb) +{ + return pmo_core_psoc_bus_runtime_suspend(psoc, pld_cb); +} + +QDF_STATUS ucfg_pmo_psoc_bus_runtime_resume(struct wlan_objmgr_psoc *psoc, + pmo_pld_auto_suspend_cb pld_cb) +{ + return pmo_core_psoc_bus_runtime_resume(psoc, pld_cb); +} +#endif + +QDF_STATUS +ucfg_pmo_psoc_suspend_target(struct wlan_objmgr_psoc *psoc, + int disable_target_intr) +{ + return pmo_core_psoc_suspend_target(psoc, disable_target_intr); +} + +QDF_STATUS +ucfg_pmo_add_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + struct pmo_wow_add_pattern *ptrn) +{ + return pmo_core_add_wow_user_pattern(vdev, ptrn); +} + +void ucfg_pmo_register_wow_default_patterns(struct wlan_objmgr_vdev *vdev) +{ + pmo_register_wow_default_patterns(vdev); +} + +QDF_STATUS +ucfg_pmo_del_wow_pattern(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_del_wow_pattern(vdev); +} + +QDF_STATUS +ucfg_pmo_del_wow_user_pattern(struct wlan_objmgr_vdev *vdev, + uint8_t pattern_id) +{ + return pmo_core_del_wow_user_pattern(vdev, pattern_id); +} + +QDF_STATUS +ucfg_pmo_psoc_bus_resume_req(struct wlan_objmgr_psoc *psoc, + enum qdf_suspend_type type) +{ + return pmo_core_psoc_bus_resume_req(psoc, type); +} + +bool ucfg_pmo_get_wow_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_get_wow_bus_suspend(psoc); +} + +int ucfg_pmo_psoc_is_target_wake_up_received(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_psoc_is_target_wake_up_received(psoc); +} + +int ucfg_pmo_psoc_clear_target_wake_up(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_psoc_clear_target_wake_up(psoc); +} + +void ucfg_pmo_psoc_target_suspend_acknowledge(void *context, bool wow_nack, + uint16_t reason_code) +{ + pmo_core_psoc_target_suspend_acknowledge(context, wow_nack, + reason_code); +} + +void ucfg_pmo_psoc_wakeup_host_event_received(struct wlan_objmgr_psoc *psoc) +{ + pmo_core_psoc_wakeup_host_event_received(psoc); +} + +QDF_STATUS ucfg_pmo_enable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_enable_hw_filter_in_fwr(vdev); +} + +QDF_STATUS +ucfg_pmo_enable_action_frame_patterns(struct wlan_objmgr_vdev *vdev, + enum qdf_suspend_type suspend_type) +{ + return pmo_register_action_frame_patterns(vdev, suspend_type); +} + +QDF_STATUS ucfg_pmo_disable_action_frame_patterns(struct wlan_objmgr_vdev *vdev) +{ + return pmo_clear_action_frame_patterns(vdev); +} + +QDF_STATUS ucfg_pmo_disable_hw_filter_in_fwr(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_disable_hw_filter_in_fwr(vdev); +} + +QDF_STATUS ucfg_pmo_config_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t listen_interval) +{ + return pmo_core_config_listen_interval(vdev, listen_interval); +} + +QDF_STATUS ucfg_pmo_get_listen_interval(struct wlan_objmgr_vdev *vdev, + uint32_t *listen_interval) +{ + return pmo_core_get_listen_interval(vdev, listen_interval); +} + +QDF_STATUS ucfg_pmo_config_modulated_dtim(struct wlan_objmgr_vdev *vdev, + uint32_t mod_dtim) +{ + return pmo_core_config_modulated_dtim(vdev, mod_dtim); +} + +enum pmo_wow_enable_type +ucfg_pmo_get_wow_enable(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.wow_enable; +} + +void +ucfg_pmo_set_wow_enable(struct wlan_objmgr_psoc *psoc, + enum pmo_wow_enable_type val) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_psoc_ctx->psoc_cfg.wow_enable = val; +} + +void +ucfg_pmo_set_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + pmo_core_vdev_set_ps_params(vdev, ps_params); +} + +QDF_STATUS ucfg_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct pmo_ps_params *ps_params) +{ + return pmo_core_vdev_get_ps_params(vdev, ps_params); +} + +QDF_STATUS ucfg_pmo_core_vdev_set_ps_opm_mode(struct wlan_objmgr_vdev *vdev, + enum powersave_mode opm_mode) +{ + return pmo_vdev_set_ps_opm_mode(vdev, opm_mode); +} + +QDF_STATUS ucfg_pmo_core_vdev_get_ps_opm_mode(struct wlan_objmgr_vdev *vdev, + enum powersave_mode *opm_mode) +{ + return pmo_vdev_get_ps_opm_mode(vdev, opm_mode); +} + +bool +ucfg_pmo_is_arp_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.arp_offload_enable; +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +bool +ucfg_pmo_is_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.igmp_offload_enable; +} +#endif + +void +ucfg_pmo_set_arp_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_psoc_ctx->psoc_cfg.arp_offload_enable = val; +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +void +ucfg_pmo_set_igmp_offload_enabled(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_psoc_ctx->psoc_cfg.igmp_offload_enable = val; +} +#endif + +enum pmo_auto_pwr_detect_failure_mode +ucfg_pmo_get_auto_power_fail_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.auto_power_save_fail_mode; +} + +#ifdef WLAN_FEATURE_WOW_PULSE +bool ucfg_pmo_is_wow_pulse_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.is_wow_pulse_supported; +} + +uint8_t ucfg_pmo_get_wow_pulse_pin(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.wow_pulse_pin; +} + +uint16_t ucfg_pmo_get_wow_pulse_interval_high(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.wow_pulse_interval_high; +} + +uint16_t ucfg_pmo_get_wow_pulse_interval_low(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.wow_pulse_interval_low; +} + +uint32_t ucfg_pmo_get_wow_pulse_repeat_count(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.wow_pulse_repeat_count; +} + +uint32_t ucfg_pmo_get_wow_pulse_init_state(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.wow_pulse_init_state; +} +#endif + +bool ucfg_pmo_is_active_mode_offloaded(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.active_mode_offload; +} + +#ifdef FEATURE_WLAN_APF +bool ucfg_pmo_is_apf_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_intersect_apf(pmo_psoc_ctx); +} +#endif + +bool +ucfg_pmo_is_ssdp_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.ssdp; +} + +#ifdef FEATURE_RUNTIME_PM +uint32_t +ucfg_pmo_get_runtime_pm_delay(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx) + return 0; + + return pmo_psoc_ctx->psoc_cfg.runtime_pm_delay; +} +#endif /* FEATURE_RUNTIME_PM */ + +bool +ucfg_pmo_is_ns_offloaded(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.ns_offload_enable_static; +} + +uint8_t +ucfg_pmo_get_sta_dynamic_dtim(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.sta_dynamic_dtim; +} + +uint8_t +ucfg_pmo_get_sta_mod_dtim(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.sta_mod_dtim; +} + +void +ucfg_pmo_set_sta_mod_dtim(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_psoc_ctx->psoc_cfg.sta_mod_dtim = val; +} + +bool +ucfg_pmo_is_mc_addr_list_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.enable_mc_list; +} + +enum powersave_mode +ucfg_pmo_get_power_save_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.power_save_mode; +} + +enum powersave_mode +ucfg_pmo_get_default_power_save_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.default_power_save_mode; +} + +void +ucfg_pmo_set_power_save_mode(struct wlan_objmgr_psoc *psoc, + enum powersave_mode val) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_psoc_ctx->psoc_cfg.power_save_mode = val; +} + +uint8_t +ucfg_pmo_get_max_ps_poll(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.max_ps_poll; +} + +uint8_t +ucfg_pmo_power_save_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + uint8_t powersave_offload_enabled = PMO_PS_ADVANCED_POWER_SAVE_ENABLE; + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + if (!pmo_psoc_ctx->psoc_cfg.max_ps_poll || + !pmo_psoc_ctx->psoc_cfg.power_save_mode) + powersave_offload_enabled = + pmo_psoc_ctx->psoc_cfg.power_save_mode; + + pmo_debug("powersave offload enabled type:%d", + powersave_offload_enabled); + + return powersave_offload_enabled; +} + +QDF_STATUS +ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + return pmo_tgt_psoc_send_idle_roam_monitor(psoc, val); +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +bool +ucfg_pmo_extwow_is_goto_suspend_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_goto_suspend; +} + +uint8_t +ucfg_pmo_extwow_app1_wakeup_pin_num(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app1_wakeup_pin_num; +} + +uint8_t +ucfg_pmo_extwow_app2_wakeup_pin_num(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_wakeup_pin_num; +} + +uint32_t +ucfg_pmo_extwow_app2_init_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_init_ping_interval; +} + +uint32_t +ucfg_pmo_extwow_app2_min_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_min_ping_interval; +} + +uint32_t +ucfg_pmo_extwow_app2_max_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_max_ping_interval; +} + +uint32_t +ucfg_pmo_extwow_app2_inc_ping_interval(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_inc_ping_interval; +} + +uint16_t +ucfg_pmo_extwow_app2_tcp_src_port(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_tcp_src_port; +} + +uint16_t +ucfg_pmo_extwow_app2_tcp_dst_port(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_tcp_dst_port; +} + +uint32_t +ucfg_pmo_extwow_app2_tcp_tx_timeout(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_tcp_tx_timeout; +} + +uint32_t +ucfg_pmo_extwow_app2_tcp_rx_timeout(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.extwow_app2_tcp_rx_timeout; +} +#endif + +bool +ucfg_pmo_get_enable_sap_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.enable_sap_suspend; +} + +void +ucfg_pmo_set_wow_data_inactivity_timeout(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + pmo_psoc_ctx->psoc_cfg.wow_data_inactivity_timeout = val; +} + +bool ucfg_pmo_is_pkt_filter_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.packet_filter_enabled; +} + +enum active_apf_mode +ucfg_pmo_get_active_uc_apf_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.active_uc_apf_mode; +} + +enum active_apf_mode +ucfg_pmo_get_active_mc_bc_apf_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.active_mc_bc_apf_mode; +} + +#ifdef WLAN_ENABLE_GPIO_WAKEUP +bool ucfg_pmo_is_gpio_wakeup_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.enable_gpio_wakeup; +} + +uint32_t ucfg_pmo_get_gpio_wakeup_pin(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.gpio_wakeup_pin; +} + +enum pmo_gpio_wakeup_mode +ucfg_pmo_get_gpio_wakeup_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.gpio_wakeup_mode; +} +#endif + +bool +ucfg_pmo_get_sap_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_sap_mode; +} + +bool +ucfg_pmo_get_go_mode_bus_suspend(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.is_bus_suspend_enabled_in_go_mode; +} + +enum pmo_suspend_mode +ucfg_pmo_get_suspend_mode(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.suspend_mode; +} + +QDF_STATUS ucfg_pmo_core_txrx_suspend(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_txrx_suspend(psoc); +} + +QDF_STATUS ucfg_pmo_core_txrx_resume(struct wlan_objmgr_psoc *psoc) +{ + return pmo_core_txrx_resume(psoc); +} + +#ifdef SYSTEM_PM_CHECK +void ucfg_pmo_notify_system_resume(struct wlan_objmgr_psoc *psoc) +{ + pmo_core_system_resume(psoc); +} +#endif + +bool ucfg_pmo_get_moddtim_user_enable(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_vdev_get_moddtim_user_enabled(vdev); +} + +void ucfg_pmo_set_moddtim_user_enable(struct wlan_objmgr_vdev *vdev, + bool value) +{ + pmo_core_vdev_set_moddtim_user_enabled(vdev, value); +} + +bool ucfg_pmo_get_moddtim_user_active(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_vdev_get_moddtim_user_active(vdev); +} + +uint32_t ucfg_pmo_get_moddtim_user(struct wlan_objmgr_vdev *vdev) +{ + return pmo_core_vdev_get_moddtim_user(vdev); +} + +uint32_t +ucfg_pmo_get_ssr_frequency_on_pagefault(struct wlan_objmgr_psoc *psoc) +{ + return pmo_get_ssr_frequency_on_pagefault(psoc); +} + +bool +ucfg_pmo_get_disconnect_sap_tdls_in_wow(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.disconnect_sap_tdls_in_wow; +} + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +QDF_STATUS ucfg_pmo_check_icmp_offload(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return pmo_core_icmp_check_offload(psoc, vdev_id); +} + +bool +ucfg_pmo_is_icmp_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct pmo_psoc_priv_obj *pmo_psoc_ctx = pmo_psoc_get_priv(psoc); + + return pmo_psoc_ctx->psoc_cfg.is_icmp_offload_enable; +} + +QDF_STATUS ucfg_pmo_config_icmp_offload(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req) +{ + return pmo_tgt_config_icmp_offload_req(psoc, pmo_icmp_req); +} +#endif + +QDF_STATUS ucfg_pmo_set_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr) +{ + return pmo_set_vdev_bridge_addr(vdev, bridgeaddr); +} + +QDF_STATUS ucfg_pmo_get_vdev_bridge_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr) +{ + return pmo_get_vdev_bridge_addr(vdev, bridgeaddr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/core/src/wlan_pre_cac_main.c b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/core/src/wlan_pre_cac_main.c new file mode 100644 index 0000000000..59d3ddaf69 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/core/src/wlan_pre_cac_main.c @@ -0,0 +1,659 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement various notification handlers which are accessed + * internally in pre_cac component only. + */ + +#include "wlan_pre_cac_main.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_reg_services_api.h" +#include "wlan_mlme_api.h" + +struct pre_cac_ops *glbl_pre_cac_ops; + +void pre_cac_stop(struct wlan_objmgr_psoc *psoc) +{ + struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc); + + if (!psoc_priv) + return; + pre_cac_debug("flush pre_cac_work"); + if (psoc_priv->pre_cac_work.fn) + qdf_flush_work(&psoc_priv->pre_cac_work); +} + +void pre_cac_set_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return; + + vdev_priv->pre_cac_freq = freq; +} + +qdf_freq_t pre_cac_get_freq(struct wlan_objmgr_vdev *vdev) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return 0; + + return vdev_priv->pre_cac_freq; +} + +void pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return; + + vdev_priv->freq_before_pre_cac = freq; +} + +qdf_freq_t pre_cac_get_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return 0; + + return vdev_priv->freq_before_pre_cac; +} + +void pre_cac_adapter_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ + struct pre_cac_vdev_priv *vdev_priv; + + if (!vdev) { + pre_cac_debug("vdev is NULL"); + return; + } + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return; + + vdev_priv->is_pre_cac_adapter = status; +} + +bool pre_cac_adapter_is_active(struct wlan_objmgr_vdev *vdev) +{ + struct pre_cac_vdev_priv *vdev_priv; + + if (!vdev) { + pre_cac_debug("vdev is NULL"); + return false; + } + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return false; + + return vdev_priv->is_pre_cac_adapter; +} + +void pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ + struct pre_cac_vdev_priv *vdev_priv; + + if (!vdev) { + pre_cac_debug("vdev is NULL"); + return; + } + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return; + + vdev_priv->pre_cac_complete = status; +} + +bool pre_cac_complete_get(struct wlan_objmgr_vdev *vdev) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return false; + + return vdev_priv->pre_cac_complete; +} + +static void pre_cac_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + QDF_STATUS status) +{ + if (glbl_pre_cac_ops && + glbl_pre_cac_ops->pre_cac_complete_cb) + glbl_pre_cac_ops->pre_cac_complete_cb(psoc, vdev_id, status); +} + +static void pre_cac_handle_success(void *data) +{ + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data; + struct pre_cac_psoc_priv *psoc_priv; + + psoc_priv = pre_cac_psoc_get_priv(psoc); + if (!psoc_priv) { + pre_cac_err("Invalid psoc priv"); + return; + } + pre_cac_debug("vdev id %d", psoc_priv->pre_cac_vdev_id); + pre_cac_complete(psoc, psoc_priv->pre_cac_vdev_id, QDF_STATUS_SUCCESS); +} + +static void pre_cac_conditional_csa_ind(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool status) +{ + if (glbl_pre_cac_ops && + glbl_pre_cac_ops->pre_cac_conditional_csa_ind_cb) + glbl_pre_cac_ops->pre_cac_conditional_csa_ind_cb(psoc, + vdev_id, status); +} + +static void pre_cac_handle_failure(void *data) +{ + struct wlan_objmgr_psoc *psoc = (struct wlan_objmgr_psoc *)data; + struct pre_cac_psoc_priv *psoc_priv; + + psoc_priv = pre_cac_psoc_get_priv(psoc); + if (!psoc_priv) { + pre_cac_err("Invalid psoc priv"); + return; + } + pre_cac_debug("vdev id %d", psoc_priv->pre_cac_vdev_id); + pre_cac_complete(psoc, psoc_priv->pre_cac_vdev_id, + QDF_STATUS_E_FAILURE); +} + +void pre_cac_clean_up(struct wlan_objmgr_psoc *psoc) +{ + struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc); + uint8_t vdev_id; + + if (!psoc_priv) { + pre_cac_err("invalid psoc"); + return; + } + + if (!pre_cac_is_active(psoc)) + return; + + if (pre_cac_is_active(psoc) && psoc_priv->pre_cac_work.fn) { + pre_cac_debug("pre_cac_work already shceduled"); + return; + } + pre_cac_get_vdev_id(psoc, &vdev_id); + pre_cac_debug("schedue pre_cac_work vdev %d", vdev_id); + psoc_priv->pre_cac_vdev_id = vdev_id; + qdf_create_work(0, &psoc_priv->pre_cac_work, + pre_cac_handle_failure, + psoc); + qdf_sched_work(0, &psoc_priv->pre_cac_work); +} + +void pre_cac_handle_radar_ind(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc); + + if (!psoc_priv) { + pre_cac_err("invalid psoc"); + return; + } + + pre_cac_conditional_csa_ind(psoc, wlan_vdev_get_id(vdev), false); + + pre_cac_debug("schedue pre_cac_work vdev %d", wlan_vdev_get_id(vdev)); + psoc_priv->pre_cac_vdev_id = wlan_vdev_get_id(vdev); + qdf_create_work(0, &psoc_priv->pre_cac_work, + pre_cac_handle_failure, + psoc); + qdf_sched_work(0, &psoc_priv->pre_cac_work); +} + +void pre_cac_handle_cac_end(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc); + + if (!psoc_priv) { + pre_cac_err("invalid psoc"); + return; + } + + pre_cac_conditional_csa_ind(psoc, wlan_vdev_get_id(vdev), true); + + pre_cac_debug("schedue pre_cac_work vdev %d", wlan_vdev_get_id(vdev)); + psoc_priv->pre_cac_vdev_id = wlan_vdev_get_id(vdev); + qdf_create_work(0, &psoc_priv->pre_cac_work, + pre_cac_handle_success, + psoc); + qdf_sched_work(0, &psoc_priv->pre_cac_work); +} + +static void pre_cac_get_vdev_id_handler(struct wlan_objmgr_psoc *psoc, + void *obj, void *args) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj; + struct pre_cac_vdev_priv *vdev_priv; + uint8_t *vdev_id = (uint8_t *)args; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return; + + if (vdev_priv->is_pre_cac_on) + *vdev_id = vdev->vdev_objmgr.vdev_id; +} + +void pre_cac_get_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id) +{ + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + pre_cac_get_vdev_id_handler, + vdev_id, true, WLAN_PRE_CAC_ID); +} + +int pre_cac_validate_and_get_freq(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq, + uint32_t *pre_cac_chan_freq, + enum phy_ch_width cac_ch_width) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + uint32_t len = CFG_VALID_CHANNEL_LIST_LEN; + uint8_t pcl_weights[NUM_CHANNELS] = {0}; + uint32_t freq_list[NUM_CHANNELS] = {0}; + uint32_t weight_len = 0; + QDF_STATUS status; + uint32_t i; + bool is_ch_dfs = false; + struct ch_params ch_params; + + pre_cac_stop(psoc); + + if (pre_cac_is_active(psoc)) { + pre_cac_err("pre cac is already in progress"); + return -EINVAL; + } + + if (!chan_freq) { + /* Channel is not obtained from PCL because PCL may not have + * the entire channel list. For example: if SAP is up on + * channel 6 and PCL is queried for the next SAP interface, + * if SCC is preferred, the PCL will contain only the channel + * 6. But, we are in need of a DFS channel. So, going with the + * first channel from the valid channel list. + */ + status = policy_mgr_get_valid_chans(psoc, + freq_list, &len); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to get channel list"); + return -EINVAL; + } + + policy_mgr_update_with_safe_channel_list(psoc, + freq_list, &len, + pcl_weights, + weight_len); +try_next_bw: + for (i = 0; i < len; i++) { + is_ch_dfs = false; + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = cac_ch_width; + wlan_reg_set_create_punc_bitmap(&ch_params, true); + if (wlan_reg_is_5ghz_ch_freq(freq_list[i]) && + wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq_list[i], &ch_params, + REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS) + is_ch_dfs = true; + + if (is_ch_dfs) { + *pre_cac_chan_freq = freq_list[i]; + break; + } + } + + if (*pre_cac_chan_freq == 0 && + cac_ch_width != CH_WIDTH_20MHZ && + wlan_get_next_lower_bandwidth(cac_ch_width) + != CH_WIDTH_INVALID) { + cac_ch_width = + wlan_get_next_lower_bandwidth(cac_ch_width); + pre_cac_debug("try next bw %d", cac_ch_width); + goto try_next_bw; + } + + if (*pre_cac_chan_freq == 0) { + pre_cac_err("unable to find outdoor channel"); + return -EINVAL; + } + } else { + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = cac_ch_width; + wlan_reg_set_create_punc_bitmap(&ch_params, true); + if (wlan_reg_is_5ghz_ch_freq(chan_freq) && + wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, chan_freq, &ch_params, + REG_CURRENT_PWR_MODE) == CHANNEL_STATE_DFS) + is_ch_dfs = true; + + /* Only when driver selects a channel, check is done for + * unnsafe and NOL channels. When user provides a fixed channel + * the user is expected to take care of this. + */ + if (!wlan_mlme_is_channel_valid(psoc, chan_freq) || + !is_ch_dfs) { + pre_cac_err("Invalid channel for pre cac:%d dfs %d", + chan_freq, is_ch_dfs); + return -EINVAL; + } + *pre_cac_chan_freq = chan_freq; + } + + pre_cac_debug("selected pre cac channel:%d bw %d", *pre_cac_chan_freq, + cac_ch_width); + + return 0; +} + +QDF_STATUS pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return QDF_STATUS_E_INVAL; + + vdev_priv->is_pre_cac_on = status; + + return QDF_STATUS_SUCCESS; +} + +static void pre_cac_is_active_vdev_handler(struct wlan_objmgr_psoc *psoc, + void *obj, void *args) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj; + struct pre_cac_vdev_priv *vdev_priv; + bool *is_pre_cac_on = (bool *)args; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) + return; + + *is_pre_cac_on = vdev_priv->is_pre_cac_on; +} + +bool pre_cac_is_active(struct wlan_objmgr_psoc *psoc) +{ + bool is_pre_cac_on = false; + + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + pre_cac_is_active_vdev_handler, + &is_pre_cac_on, true, WLAN_PRE_CAC_ID); + return is_pre_cac_on; +} + +void pre_cac_clear_work(struct wlan_objmgr_psoc *psoc) +{ + struct pre_cac_psoc_priv *psoc_priv = pre_cac_psoc_get_priv(psoc); + + if (!psoc_priv) + return; + + psoc_priv->pre_cac_work.fn = NULL; + psoc_priv->pre_cac_work.arg = NULL; + + return; +} + +struct pre_cac_vdev_priv * +pre_cac_vdev_get_priv_fl(struct wlan_objmgr_vdev *vdev, + const char *func, uint32_t line) +{ + struct pre_cac_vdev_priv *vdev_priv; + + vdev_priv = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_PRE_CAC); + if (!vdev_priv) { + pre_cac_nofl_err("%s:%u: vdev id: %d, vdev_priv is NULL", + func, line, wlan_vdev_get_id(vdev)); + } + + return vdev_priv; +} + +struct pre_cac_psoc_priv * +pre_cac_psoc_get_priv_fl(struct wlan_objmgr_psoc *psoc, + const char *func, uint32_t line) +{ + struct pre_cac_psoc_priv *psoc_priv; + + psoc_priv = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_PRE_CAC); + if (!psoc_priv) + pre_cac_nofl_err("%s:%u: psoc_priv is NULL", func, line); + + return psoc_priv; +} + +void pre_cac_set_osif_cb(struct pre_cac_ops *osif_pre_cac_ops) +{ + glbl_pre_cac_ops = osif_pre_cac_ops; +} + +QDF_STATUS +pre_cac_vdev_create_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct pre_cac_vdev_priv *vdev_priv; + QDF_STATUS status; + + vdev_priv = qdf_mem_malloc(sizeof(*vdev_priv)); + if (!vdev_priv) { + status = QDF_STATUS_E_NOMEM; + goto exit; + } + + status = wlan_objmgr_vdev_component_obj_attach( + vdev, WLAN_UMAC_COMP_PRE_CAC, + (void *)vdev_priv, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to attach priv with vdev"); + goto free_vdev_priv; + } + + goto exit; + +free_vdev_priv: + qdf_mem_free(vdev_priv); + status = QDF_STATUS_E_INVAL; +exit: + return status; +} + +QDF_STATUS +pre_cac_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, void *arg) +{ + struct pre_cac_vdev_priv *vdev_priv = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev_priv = pre_cac_vdev_get_priv(vdev); + if (!vdev_priv) { + pre_cac_err("vdev priv is NULL"); + goto exit; + } + + status = wlan_objmgr_vdev_component_obj_detach( + vdev, WLAN_UMAC_COMP_PRE_CAC, + (void *)vdev_priv); + if (QDF_IS_STATUS_ERROR(status)) + pre_cac_err("Failed to detach priv with vdev"); + + qdf_mem_free(vdev_priv); + vdev_priv = NULL; + +exit: + return status; +} + +QDF_STATUS +pre_cac_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct pre_cac_psoc_priv *psoc_priv; + QDF_STATUS status; + + psoc_priv = qdf_mem_malloc(sizeof(*psoc_priv)); + if (!psoc_priv) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_PRE_CAC, + psoc_priv, QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to attach psoc component obj"); + goto free_psoc_priv; + } + + return status; + +free_psoc_priv: + qdf_mem_free(psoc_priv); + return status; +} + +QDF_STATUS +pre_cac_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct pre_cac_psoc_priv *psoc_priv; + QDF_STATUS status; + + psoc_priv = pre_cac_psoc_get_priv(psoc); + if (!psoc_priv) { + pre_cac_err("psoc priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_PRE_CAC, + psoc_priv); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to detach psoc component obj"); + return status; + } + + qdf_mem_free(psoc_priv); + return status; +} + +QDF_STATUS pre_cac_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_psoc_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to register psoc create handler"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_psoc_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to register psoc delete handler"); + goto fail_destroy_psoc; + } + + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_vdev_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to register vdev create handler"); + goto fail_create_vdev; + } + + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_vdev_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + pre_cac_err("Failed to register vdev destroy handler"); + goto fail_destroy_vdev; + } + return status; + +fail_destroy_vdev: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_PRE_CAC, + pre_cac_vdev_create_notification, NULL); + +fail_create_vdev: + wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_PRE_CAC, + pre_cac_psoc_destroy_notification, NULL); + +fail_destroy_psoc: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_PRE_CAC, + pre_cac_psoc_create_notification, NULL); + + return status; +} + +void pre_cac_deinit(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_vdev_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + pre_cac_err("Failed to unregister vdev destroy handler"); + + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_vdev_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + pre_cac_err("Failed to unregister vdev create handler"); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_psoc_destroy_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + pre_cac_err("Failed to unregister psoc destroy handler"); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_PRE_CAC, + pre_cac_psoc_create_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + pre_cac_err("Failed to unregister psoc create handler"); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/core/src/wlan_pre_cac_main.h b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/core/src/wlan_pre_cac_main.h new file mode 100644 index 0000000000..8be6c2f1b5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/core/src/wlan_pre_cac_main.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare private API which shall be used internally only + * in pre_cac component. This file shall include prototypes of + * various notification handlers and logging functions. + * + * Note: This API should be never accessed out of pre_cac component. + */ + +#ifndef _WLAN_PRE_CAC_MAIN_H_ +#define _WLAN_PRE_CAC_MAIN_H_ + +#include +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_pre_cac_public_struct.h" + +#define pre_cac_log(level, args...) \ + QDF_TRACE(QDF_MODULE_ID_WLAN_PRE_CAC, level, ## args) + +#define pre_cac_logfl(level, format, args...) \ + pre_cac_log(level, FL(format), ## args) + +#define pre_cac_fatal(format, args...) \ + pre_cac_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args) +#define pre_cac_err(format, args...) \ + pre_cac_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define pre_cac_warn(format, args...) \ + pre_cac_logfl(QDF_TRACE_LEVEL_WARN, format, ## args) +#define pre_cac_info(format, args...) \ + pre_cac_logfl(QDF_TRACE_LEVEL_INFO, format, ## args) +#define pre_cac_debug(format, args...) \ + pre_cac_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define pre_cac_nofl_err(format, args...) \ + pre_cac_log(QDF_TRACE_LEVEL_ERROR, format, ## args) +#define pre_cac_nofl_warn(format, args...) \ + pre_cac_log(QDF_TRACE_LEVEL_WARN, format, ## args) +#define pre_cac_nofl_info(format, args...) \ + pre_cac_log(QDF_TRACE_LEVEL_INFO, format, ## args) +#define pre_cac_nofl_debug(format, args...) \ + pre_cac_log(QDF_TRACE_LEVEL_DEBUG, format, ## args) + +#define PRE_CAC_ENTER() pre_cac_debug("enter") +#define PRE_CAC_EXIT() pre_cac_debug("exit") + +/** + * struct pre_cac_vdev_priv - Private object to be stored in vdev + * @is_pre_cac_on: status of pre_cac + * @pre_cac_complete: pre cac complete status + * @is_pre_cac_adapter: pre cac adapter status + * @freq_before_pre_cac: frequency before pre cac + * @pre_cac_freq: pre cac frequency + */ +struct pre_cac_vdev_priv { + bool is_pre_cac_on; + bool pre_cac_complete; + bool is_pre_cac_adapter; + qdf_freq_t freq_before_pre_cac; + qdf_freq_t pre_cac_freq; +}; + +/** + * struct pre_cac_psoc_priv - Private object to be stored in psoc + * @pre_cac_work: pre cac work handler + * @pre_cac_vdev_id: pre cac vdev id + */ +struct pre_cac_psoc_priv { + qdf_work_t pre_cac_work; + uint8_t pre_cac_vdev_id; +}; + +/** + * pre_cac_vdev_create_notification() - Handler for vdev create notify. + * @vdev: vdev which is going to be created by objmgr + * @arg: argument for notification handler. + * + * Allocate and attach vdev private object. + * + * Return: QDF_STATUS status in case of success else return error. + */ +QDF_STATUS pre_cac_vdev_create_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * pre_cac_vdev_destroy_notification() - Handler for vdev destroy notify. + * @vdev: vdev which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach vdev private object. + * + * Return QDF_STATUS status in case of success else return error + */ +QDF_STATUS +pre_cac_vdev_destroy_notification(struct wlan_objmgr_vdev *vdev, + void *arg); + +/** + * pre_cac_psoc_create_notification() - Handler for psoc create notify. + * @psoc: psoc which is going to be created by objmgr + * @arg: argument for notification handler. + * + * Allocate and attach psoc private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pre_cac_psoc_create_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * pre_cac_psoc_destroy_notification() - Handler for psoc destroy notify. + * @psoc: psoc which is going to be destroyed by objmgr + * @arg: argument for notification handler. + * + * Deallocate and detach psoc private object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pre_cac_psoc_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * pre_cac_vdev_get_priv_fl() - retrieve vdev priv obj + * @vdev: vdev pointer + * @func: invoking function (for debugging) + * @line: invoking source file line number (for debugging) + * + * Retrieves pre_cac vdev private object pointer. + * + * Return: Private object of vdev + */ +struct pre_cac_vdev_priv * +pre_cac_vdev_get_priv_fl(struct wlan_objmgr_vdev *vdev, + const char *func, uint32_t line); + +/** + * pre_cac_vdev_get_priv() - Wrapper to retrieve vdev priv obj + * @vdev: vdev pointer + * + * Wrapper for pre_cac to get vdev private object pointer. + * + * Return: Private object of vdev + */ +#define pre_cac_vdev_get_priv(vdev) \ + pre_cac_vdev_get_priv_fl(vdev, __func__, __LINE__) + +/** + * pre_cac_psoc_get_priv_fl() - retrieve psoc priv obj + * @psoc: psoc pointer + * @func: invoking function (for debugging) + * @line: invoking source file line number (for debugging) + * + * Retrieves pre_cac psoc private object pointer. + * + * Return: pre_cac psoc private object + */ +struct pre_cac_psoc_priv * +pre_cac_psoc_get_priv_fl(struct wlan_objmgr_psoc *psoc, + const char *func, uint32_t line); + +/** + * pre_cac_psoc_get_priv() - Wrapper to retrieve psoc priv obj + * @psoc: psoc pointer + * + * Wrapper for pre_cac to get psoc private object pointer. + * + * Return: pre_cac psoc private object + */ +#define pre_cac_psoc_get_priv(psoc) \ + pre_cac_psoc_get_priv_fl(psoc, __func__, __LINE__) + +/** + * pre_cac_init() - pre cac component initialization. + * + * This function initializes the pre cac component and registers + * the handlers which are invoked on vdev creation. + * + * Return: For successful registration - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +QDF_STATUS pre_cac_init(void); + +/** + * pre_cac_deinit() - pre cac component deinit. + * + * This function deinits pre cac component. + * + * Return: None + */ +void pre_cac_deinit(void); + +/** + * pre_cac_set_osif_cb() - set pre cac osif callbacks + * @osif_pre_cac_ops: pre cac ops + * + * + * Return: None + */ +void pre_cac_set_osif_cb(struct pre_cac_ops *osif_pre_cac_ops); + +/** + * pre_cac_is_active() - status of pre_cac + * @psoc: psoc pointer + * + * Return: status of pre_cac + */ +bool pre_cac_is_active(struct wlan_objmgr_psoc *psoc); + +/** + * pre_cac_clear_work() - clear pre cac work fn and arg + * @psoc: psoc object manager + * + * Return: None + */ +void pre_cac_clear_work(struct wlan_objmgr_psoc *psoc); + +/** + * pre_cac_validate_and_get_freq() - Validate and get pre cac frequency + * @pdev: pdev object manager + * @chan_freq: Channel frequency requested by userspace + * @pre_cac_chan_freq: Pointer to the pre CAC channel frequency storage + * @cac_ch_width: bandwidth of channel frequency pre_cac_chan_freq + * + * Validates the channel provided by userspace. If user provided channel 0, + * a valid outdoor channel must be selected from the regulatory channel. + * + * Return: Zero on success and non zero value on error + */ +int pre_cac_validate_and_get_freq(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq, + uint32_t *pre_cac_chan_freq, + enum phy_ch_width cac_ch_width); + +/** + * pre_cac_set_status() - Set pre cac status + * @vdev: vdev object manager + * @status: status of pre_cac + * + * Sets pre_cac status + * + * Return: QDF_STATUS + */ +QDF_STATUS pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status); + +/** + * pre_cac_get_vdev_id() - Get pre cac vdev id + * @psoc: psoc object manager + * @vdev_id: pointer to the pre cac vdev id + * + * Return: None + */ +void pre_cac_get_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id); + +/** + * pre_cac_handle_cac_end() - Handle pre cac end + * @vdev: vdev object manager + * + * Return: None + */ +void pre_cac_handle_cac_end(struct wlan_objmgr_vdev *vdev); + +/** + * pre_cac_complete_set() - Set pre cac complete status + * @vdev: vdev object manager + * @status: status + * + * Return: None + */ +void pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status); + +/** + * pre_cac_complete_get() - Get pre cac complete status + * @vdev: vdev object manager + * + * Return: pre cac complete status + */ +bool pre_cac_complete_get(struct wlan_objmgr_vdev *vdev); + +/** + * pre_cac_adapter_set() - Set pre cac adapter flag + * @vdev: vdev object manager + * @status: status + * + * Return: None + */ +void pre_cac_adapter_set(struct wlan_objmgr_vdev *vdev, + bool status); + +/** + * pre_cac_adapter_is_active() - Get pre cac adapter status + * @vdev: vdev object manager + * + * Return: pre cac adapter status + */ +bool pre_cac_adapter_is_active(struct wlan_objmgr_vdev *vdev); + +/** + * pre_cac_set_freq_before_pre_cac() - Set frequency before pre cac + * @vdev: vdev object manager + * @freq: frequency before pre cac + * + * Return: None + */ +void pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + +/** + * pre_cac_get_freq_before_pre_cac() - Get frequency before pre cac + * @vdev: vdev object manager + * + * Return: frequency before pre cac + */ +qdf_freq_t pre_cac_get_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev); + +/** + * pre_cac_set_freq() - Set pre cac frequency + * @vdev: vdev object manager + * @freq: pre cac frequency + * + * Return: None + */ +void pre_cac_set_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + +/** + * pre_cac_get_freq() - Get pre cac frequency + * @vdev: vdev object manager + * + * Return: pre cac frequency + */ +qdf_freq_t pre_cac_get_freq(struct wlan_objmgr_vdev *vdev); + +/** + * pre_cac_handle_radar_ind() - Handle pre cac radar indication + * @vdev: vdev object manager + * + * Return: None + */ +void pre_cac_handle_radar_ind(struct wlan_objmgr_vdev *vdev); + +/** + * pre_cac_stop() - Stop pre cac + * @psoc: psoc object manager + * + * Return: None + */ +void pre_cac_stop(struct wlan_objmgr_psoc *psoc); + +/** + * pre_cac_clean_up() - Cleanup pre cac + * @psoc: psoc object manager + * + * Return: None + */ +void pre_cac_clean_up(struct wlan_objmgr_psoc *psoc); +#endif /* end of _WLAN_PRE_CAC_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_api.h new file mode 100644 index 0000000000..7b5f84071b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_api.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Public API declarations of pre cac called from SAP module + */ + +#ifndef _WLAN_PRE_CAC_API_H_ +#define _WLAN_PRE_CAC_API_H_ + +#ifdef PRE_CAC_SUPPORT +/** + * wlan_pre_cac_get_status(): status of pre_cac + * @psoc: psoc object manager + * + * Return: status of pre_cac + */ +bool wlan_pre_cac_get_status(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_pre_cac_set_status() - Set pre cac status + * @vdev: vdev object manager + * @status: status of pre_cac + * + * Sets pre_cac status + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status); + +/** + * wlan_pre_cac_handle_cac_end() - Handle pre cac end + * @vdev: vdev object manager + * + * Return: None + */ +void wlan_pre_cac_handle_cac_end(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_pre_cac_complete_set() - Set pre cac complete status + * @vdev: vdev object manager + * @status: status + * + * Return: None + */ +void wlan_pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status); + +/** + * wlan_pre_cac_complete_get() - Get pre cac complete status + * @vdev: vdev object manager + * + * Return: pre cac complete status + */ +bool wlan_pre_cac_complete_get(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_pre_cac_set_freq_before_pre_cac() - Set frequency before pre cac + * @vdev: vdev object manager + * @freq: frequency + * + * Return: None + */ +void wlan_pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + +/** + * wlan_pre_cac_get_freq_before_pre_cac() - Get frequency before pre cac + * @vdev: vdev object manager + * + * Return: Frequency before pre cac + */ +qdf_freq_t +wlan_pre_cac_get_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_pre_cac_handle_radar_ind() - Handle pre cac radar indication + * @vdev: vdev object manager + * + * Return: None + */ +void wlan_pre_cac_handle_radar_ind(struct wlan_objmgr_vdev *vdev); +#else +static inline void +wlansap_pre_cac_end_notify(struct sap_context *sap_context, + struct mac_context *mac, + uint8_t intf) +{ +} + +static inline bool wlan_pre_cac_get_status(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +wlan_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status) +{ + return false; +} + +static inline void +wlan_pre_cac_handle_cac_end(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +wlan_pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ +} + +static inline bool +wlan_pre_cac_complete_get(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +wlan_pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ +} + +static inline qdf_freq_t +wlan_pre_cac_get_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} +#endif /* PRE_CAC_SUPPORT */ +#endif /* _WLAN_PRE_CAC_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_public_struct.h new file mode 100644 index 0000000000..e09c247292 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_public_struct.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_PRE_CAC_PUBLIC_STRUCT_H_ +#define _WLAN_PRE_CAC_PUBLIC_STRUCT_H_ + +#include "wlan_objmgr_psoc_obj.h" + +/** + * struct pre_cac_ops - pre cac osif callbacks + * @pre_cac_conditional_csa_ind_cb: send conditional frequency switch status + * @pre_cac_complete_cb: Pre cac complete callback + */ +struct pre_cac_ops { + void (*pre_cac_conditional_csa_ind_cb)( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + bool status); + void (*pre_cac_complete_cb)( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + QDF_STATUS status); +}; +#endif /* _WLAN_PRE_CAC_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_ucfg_api.h new file mode 100644 index 0000000000..4351a08e95 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/inc/wlan_pre_cac_ucfg_api.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare public API related to the pre_cac called by north bound + * HDD/OSIF/LIM + */ + +#ifndef _WLAN_PRE_CAC_UCFG_API_H_ +#define _WLAN_PRE_CAC_UCFG_API_H_ + +#include +#include +#include "wlan_pre_cac_public_struct.h" +#include "wlan_objmgr_psoc_obj.h" + +#ifdef PRE_CAC_SUPPORT +/** + * ucfg_pre_cac_init() - pre cac component initialization. + * + * This function initializes the pre cac component and registers + * the handlers which are invoked on vdev creation. + * + * Return: For successful registration - QDF_STATUS_SUCCESS, + * else QDF_STATUS error codes. + */ +QDF_STATUS ucfg_pre_cac_init(void); + +/** + * ucfg_pre_cac_deinit() - pre cac component deinit. + * + * This function deinits pre cac component. + * + * Return: None + */ +void ucfg_pre_cac_deinit(void); + +/* + * ucfg_pre_cac_set_osif_cb() - set pre cac osif callbacks. + * @pre_cac_ops: pre cac ops + * + * Return: None + */ +void ucfg_pre_cac_set_osif_cb(struct pre_cac_ops *pre_cac_ops); + +/** + * ucfg_pre_cac_clear_work() - clear pre cac work fn and arg. + * @psoc: psoc object manager + * + * Return: None + */ +void ucfg_pre_cac_clear_work(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pre_cac_is_active(): status of pre_cac + * @psoc: psoc object manager + * + * Return: status of pre_cac + */ +bool ucfg_pre_cac_is_active(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pre_cac_validate_and_get_freq() - Validate and get pre cac frequency + * @pdev: pdev object manager + * @chan_freq: Channel frequency requested by userspace + * @pre_cac_chan_freq: Pointer to the pre CAC channel frequency storage + * @cac_ch_width: bandwidth of channel frequency pre_cac_chan_freq + * + * Validates the channel provided by userspace. If user provided channel 0, + * a valid outdoor channel must be selected from the regulatory channel. + * + * Return: Zero on success and non zero value on error + */ +int ucfg_pre_cac_validate_and_get_freq(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq, + uint32_t *pre_cac_chan_freq, + enum phy_ch_width cac_ch_width); + +#if defined(FEATURE_SAP_COND_CHAN_SWITCH) +/** + * ucfg_pre_cac_set_status() - Set pre cac status + * @vdev: vdev object manager + * @status: status of pre_cac + * + * Sets pre_cac status + * + * Return: Zero on success and non zero value on error + */ +QDF_STATUS ucfg_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status); +#else +static inline QDF_STATUS +ucfg_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ucfg_pre_cac_get_vdev_id() - Get pre cac vdev id + * @psoc: psoc object manager + * @vdev_id: pre cac vdev id + * + * Return: None + */ +void ucfg_pre_cac_get_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id); + +/** + * ucfg_pre_cac_adapter_set() - Set pre cac adapter flag + * @vdev: vdev object manager + * @status: status + * + * Return: None + */ +void ucfg_pre_cac_adapter_set(struct wlan_objmgr_vdev *vdev, + bool status); + +/** + * ucfg_pre_cac_adapter_is_active() - Get pre cac adapter status + * @vdev: vdev object manager + * + * Return: pre cac complete status + */ +bool ucfg_pre_cac_adapter_is_active(struct wlan_objmgr_vdev *vdev); + +#if defined(FEATURE_SAP_COND_CHAN_SWITCH) +/** + * ucfg_pre_cac_set_freq_before_pre_cac() - Set frequency before pre cac + * @vdev: vdev object manager + * @freq: frequency + * + * Return: None + */ +void ucfg_pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); +#else +static inline void +ucfg_pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ +} +#endif + +/** + * ucfg_pre_cac_set_freq() - Set pre cac frequency + * @vdev: vdev object manager + * @freq: pre cac frequency + * + * Return: None + */ +void ucfg_pre_cac_set_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + +/** + * ucfg_pre_cac_get_freq() - Get pre cac frequency + * @vdev: vdev object manager + * + * Return: pre cac frequency + */ +qdf_freq_t ucfg_pre_cac_get_freq(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_pre_cac_complete_set() - Set pre cac complete status + * @vdev: vdev object manager + * @status: status + * + * Return: None + */ +void ucfg_pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status); + +/** + * ucfg_pre_cac_stop() - Stop pre cac + * @psoc: psoc object manager + * + * Return: None + */ +void ucfg_pre_cac_stop(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_pre_cac_clean_up() - Cleanup pre cac + * @psoc: psoc object manager + * + * Return: None + */ +void ucfg_pre_cac_clean_up(struct wlan_objmgr_psoc *psoc); +#else +static inline +QDF_STATUS ucfg_pre_cac_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_pre_cac_deinit(void) +{ +} + +static inline void +ucfg_pre_cac_set_osif_cb(struct pre_cac_ops *pre_cac_ops) +{ +} + +static inline +void ucfg_pre_cac_clear_work(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline bool +ucfg_pre_cac_is_active(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline int +ucfg_pre_cac_validate_and_get_freq(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq, + uint32_t *pre_cac_chan_freq, + enum phy_ch_width cac_ch_width) +{ + return 0; +} + +static inline QDF_STATUS +ucfg_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +ucfg_pre_cac_get_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id) +{ +} + +static inline void +ucfg_pre_cac_adapter_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ +} + +static inline bool +ucfg_pre_cac_adapter_is_active(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +ucfg_pre_cac_set_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ +} + +static inline qdf_freq_t +ucfg_pre_cac_get_freq(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline void +ucfg_pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ +} + +static inline void +ucfg_pre_cac_stop(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline void +ucfg_pre_cac_clean_up(struct wlan_objmgr_psoc *psoc) +{ +} +#endif /* PRE_CAC_SUPPORT */ +#endif /* _WLAN_PRE_CAC_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/src/wlan_pre_cac_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/src/wlan_pre_cac_api.c new file mode 100644 index 0000000000..de1c0bb3e9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/src/wlan_pre_cac_api.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Public API implementation of pre cac called from SAP module + */ + +#include "wlan_pre_cac_main.h" +#include "wlan_pre_cac_api.h" + +bool wlan_pre_cac_get_status(struct wlan_objmgr_psoc *psoc) +{ + return pre_cac_is_active(psoc); +} + +QDF_STATUS wlan_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status) +{ + return pre_cac_set_status(vdev, status); +} + +void wlan_pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + pre_cac_set_freq_before_pre_cac(vdev, freq); +} + +qdf_freq_t wlan_pre_cac_get_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev) +{ + return pre_cac_get_freq_before_pre_cac(vdev); +} + +void wlan_pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ + pre_cac_complete_set(vdev, status); +} + +bool wlan_pre_cac_complete_get(struct wlan_objmgr_vdev *vdev) +{ + return pre_cac_complete_get(vdev); +} + +void wlan_pre_cac_handle_radar_ind(struct wlan_objmgr_vdev *vdev) +{ + pre_cac_handle_radar_ind(vdev); +} + +void wlan_pre_cac_handle_cac_end(struct wlan_objmgr_vdev *vdev) +{ + pre_cac_handle_cac_end(vdev); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/src/wlan_pre_cac_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/src/wlan_pre_cac_ucfg_api.c new file mode 100644 index 0000000000..138cd8fbda --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/pre_cac/dispatcher/src/wlan_pre_cac_ucfg_api.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2022, 2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Public API implementation of pre cac called by north bound iface. + */ + +#include "../../core/src/wlan_pre_cac_main.h" +#include "wlan_pre_cac_ucfg_api.h" + +void ucfg_pre_cac_complete_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ + pre_cac_complete_set(vdev, status); +} + +void ucfg_pre_cac_clean_up(struct wlan_objmgr_psoc *psoc) +{ + pre_cac_clean_up(psoc); +} + +void ucfg_pre_cac_stop(struct wlan_objmgr_psoc *psoc) +{ + pre_cac_stop(psoc); +} + +void ucfg_pre_cac_set_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + pre_cac_set_freq(vdev, freq); +} + +qdf_freq_t ucfg_pre_cac_get_freq(struct wlan_objmgr_vdev *vdev) +{ + return pre_cac_get_freq(vdev); +} + +void ucfg_pre_cac_set_freq_before_pre_cac(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + return pre_cac_set_freq_before_pre_cac(vdev, freq); +} + +void ucfg_pre_cac_adapter_set(struct wlan_objmgr_vdev *vdev, + bool status) +{ + pre_cac_adapter_set(vdev, status); +} + +bool ucfg_pre_cac_adapter_is_active(struct wlan_objmgr_vdev *vdev) +{ + return pre_cac_adapter_is_active(vdev); +} + +void ucfg_pre_cac_get_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id) +{ + pre_cac_get_vdev_id(psoc, vdev_id); +} + +int ucfg_pre_cac_validate_and_get_freq(struct wlan_objmgr_pdev *pdev, + uint32_t chan_freq, + uint32_t *pre_cac_chan_freq, + enum phy_ch_width cac_ch_width) +{ + return pre_cac_validate_and_get_freq(pdev, chan_freq, + pre_cac_chan_freq, + cac_ch_width); +} + +#if defined(FEATURE_SAP_COND_CHAN_SWITCH) +QDF_STATUS ucfg_pre_cac_set_status(struct wlan_objmgr_vdev *vdev, bool status) +{ + return pre_cac_set_status(vdev, status); +} +#endif + +bool ucfg_pre_cac_is_active(struct wlan_objmgr_psoc *psoc) +{ + return pre_cac_is_active(psoc); +} + +void ucfg_pre_cac_set_osif_cb(struct pre_cac_ops *osif_pre_cac_ops) +{ + pre_cac_set_osif_cb(osif_pre_cac_ops); +} + +void ucfg_pre_cac_clear_work(struct wlan_objmgr_psoc *psoc) +{ + return pre_cac_clear_work(psoc); +} + +QDF_STATUS ucfg_pre_cac_init(void) +{ + return pre_cac_init(); +} + +void ucfg_pre_cac_deinit(void) +{ + pre_cac_deinit(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_main.h b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_main.h new file mode 100644 index 0000000000..ecb4997a68 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_main.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_main.h + * + * QMI component core function declarations + */ + +#ifndef _WLAN_QMI_MAIN_H_ +#define _WLAN_QMI_MAIN_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include + +#define qmi_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_QMI, params) +#define qmi_debug_rl(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_QMI, params) + +#define qmi_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_QMI, params) +#define qmi_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_QMI, params) +#define qmi_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_QMI, params) +#define qmi_fatal(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_QMI, params) + +#define qmi_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_QMI, params) +#define qmi_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_QMI, params) +#define qmi_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_QMI, params) +#define qmi_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_QMI, params) +#define qmi_nofl_fatal(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_QMI, params) + +/** + * qmi_psoc_obj_create_notification() - Function to allocate per psoc QMI + * private object + * @psoc: psoc context + * @arg: Pointer to arguments + * + * This function gets called from object manager when psoc is being + * created and creates QMI soc context. + * + * Return: QDF status + */ +QDF_STATUS +qmi_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * qmi_psoc_obj_destroy_notification() - Free per psoc QMI private object + * @psoc: psoc context + * @arg: Pointer to arguments + * + * This function gets called from object manager when psoc is being + * deleted and delete QMI soc context. + * + * Return: QDF status + */ +QDF_STATUS +qmi_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_objmgr.h b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_objmgr.h new file mode 100644 index 0000000000..1783b505a6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_objmgr.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_objmgr.h + * + * This file contains various object manager related wrappers and helpers + */ + +#ifndef _WLAN_QMI_OBJMGR_H_ +#define _WLAN_QMI_OBJMGR_H_ + +#include "wlan_cmn.h" +#include "wlan_objmgr_cmn.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_qmi_priv.h" + +#define qmi_comp_psoc_get_ref(psoc) wlan_objmgr_psoc_try_get_ref(psoc, \ + WLAN_QMI_ID) + +#define qmi_comp_psoc_put_ref(psoc) wlan_objmgr_psoc_release_ref(psoc, \ + WLAN_QMI_ID) + +/** + * qmi_psoc_get_priv() - Wrapper to retrieve psoc priv obj + * @psoc: psoc pointer + * + * Return: QMI psoc private object + */ +static inline +struct wlan_qmi_psoc_context *qmi_psoc_get_priv(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_qmi_psoc_context *qmi_ctx; + + qmi_ctx = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_QMI); + QDF_BUG(qmi_ctx); + + return qmi_ctx; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_priv.h b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_priv.h new file mode 100644 index 0000000000..80eae6a73c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/inc/wlan_qmi_priv.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_priv.h + * + * Declare various struct, macros which are used private to QMI component. + */ + +#ifndef _WLAN_QMI_PRIV_H_ +#define _WLAN_QMI_PRIV_H_ + +#include "wlan_qmi_public_struct.h" +#include "wlan_objmgr_psoc_obj.h" + +/** + * struct wlan_qmi_psoc_context - psoc related data required for QMI + * @psoc: object manager psoc context + * @qmi_cbs: QMI callbacks + */ +struct wlan_qmi_psoc_context { + struct wlan_objmgr_psoc *psoc; + struct wlan_qmi_psoc_callbacks qmi_cbs; +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/src/wlan_qmi_main.c b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/src/wlan_qmi_main.c new file mode 100644 index 0000000000..31597900a3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/core/src/wlan_qmi_main.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_main.c + * + * QMI component core function definitions + */ + +#include "wlan_qmi_main.h" +#include "wlan_qmi_public_struct.h" +#include "wlan_qmi_objmgr.h" + +QDF_STATUS +qmi_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_qmi_psoc_context *qmi_ctx; + QDF_STATUS status; + + qmi_ctx = qdf_mem_malloc(sizeof(*qmi_ctx)); + if (!qmi_ctx) + return QDF_STATUS_E_NOMEM; + + qmi_ctx->psoc = psoc; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_QMI, + qmi_ctx, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + qmi_err("Failed to attach psoc QMI component obj"); + qdf_mem_free(qmi_ctx); + return status; + } + + return status; +} + +QDF_STATUS +qmi_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct wlan_qmi_psoc_context *qmi_ctx; + QDF_STATUS status; + + qmi_ctx = qmi_psoc_get_priv(psoc); + if (!qmi_ctx) { + qmi_err("psoc priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_QMI, + qmi_ctx); + if (QDF_IS_STATUS_ERROR(status)) + qmi_err("Failed to detach psoc QMI component obj"); + + qdf_mem_free(qmi_ctx); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_public_struct.h new file mode 100644 index 0000000000..c670eb1de2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_public_struct.h @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_public_struct.h + * + * Contains QMI public data structure definitions. + */ + +#ifndef _WLAN_QMI_PUBLIC_STRUCT_H_ +#define _WLAN_QMI_PUBLIC_STRUCT_H_ + +#include "qdf_status.h" +#include + +#ifdef QMI_WFDS +#define QMI_WFDS_CE_MAX_SRNG 3 +#define QMI_WFDS_MEM_ARENA_MAX 8 +#define QMI_WFDS_PAGE_INFO_ARRAY_MAX_SIZE 255 + +/** + * enum wlan_qmi_wfds_srng_dir - SRNG direction + * @QMI_WFDS_SRNG_SOURCE_RING: SRNG source ring + * @QMI_WFDS_SRNG_DESTINATION_RING: SRNG destination ring + */ +enum wlan_qmi_wfds_srng_dir { + QMI_WFDS_SRNG_SOURCE_RING = 0, + QMI_WFDS_SRNG_DESTINATION_RING = 1, +}; + +/** + * struct wlan_qmi_wfds_srng_info - SRNG information + * @ring_id: SRNG ring id + * @dir: SRNG direction + * @num_entries: number of entries in SRNG + * @entry_size: size of SRNG descriptor + * @ring_base_paddr: ring base physical address of SRNG + * @hp_paddr: HP physical address of SRNG + * @tp_paddr: TP physical address of SRNG + */ +struct wlan_qmi_wfds_srng_info { + uint8_t ring_id; + enum wlan_qmi_wfds_srng_dir dir; + uint32_t num_entries; + uint32_t entry_size; + uint64_t ring_base_paddr; + uint64_t hp_paddr; + uint64_t tp_paddr; +}; + +/** + * enum wlan_qmi_wfds_pipe_dir - pipe direction + * @QMI_WFDS_PIPEDIR_NONE: none pipe direction + * @QMI_WFDS_PIPEDIR_IN: target to host pipe direction + * @QMI_WFDS_PIPEDIR_OUT: host to target pipe direction + */ +enum wlan_qmi_wfds_pipe_dir { + QMI_WFDS_PIPEDIR_NONE = 0, + QMI_WFDS_PIPEDIR_IN = 1, + QMI_WFDS_PIPEDIR_OUT = 2, +}; + +/** + * struct wlan_qmi_wfds_ce_info - CE information + * @ce_id: CE id + * @ce_dir: CE direction + * @srng_info: SRNG information + */ +struct wlan_qmi_wfds_ce_info { + uint8_t ce_id; + enum wlan_qmi_wfds_pipe_dir ce_dir; + struct wlan_qmi_wfds_srng_info srng_info; +}; + +/** + * struct wlan_qmi_wfds_config_req_msg - WFDS config request message + * @ce_info_len: size of ce_info with valid entries + * @ce_info: CE information array + * @rx_refill_ring: refill SRNG information + * @shadow_rdptr_mem_paddr: shadow read memory physical address + * @shadow_rdptr_mem_size: shadow read memory size + * @shadow_wrptr_mem_paddr: shadow write memory physical address + * @shadow_wrptr_mem_size: shadow write memory size + * @rx_pkt_tlv_len: rx packet tlvs length + * @rx_rbm: return buffer manager for rx buffers + * @pcie_bar_pa: PCIe BAR physical address + * @pci_slot: PCIe slot + * @lpass_ep_id: LPASS data message service endpoint id + */ +struct wlan_qmi_wfds_config_req_msg { + uint32_t ce_info_len; + struct wlan_qmi_wfds_ce_info ce_info[QMI_WFDS_CE_MAX_SRNG]; + struct wlan_qmi_wfds_srng_info rx_refill_ring; + uint64_t shadow_rdptr_mem_paddr; + uint64_t shadow_rdptr_mem_size; + uint64_t shadow_wrptr_mem_paddr; + uint64_t shadow_wrptr_mem_size; + uint32_t rx_pkt_tlv_len; + uint32_t rx_rbm; + uint64_t pcie_bar_pa; + uint32_t pci_slot; + uint32_t lpass_ep_id; +}; + +/** + * enum wlan_qmi_wfds_mem_arenas - Memory arenas + * @QMI_WFDS_MEM_ARENA_TX_BUFFERS: tx buffers memory arena + * @QMI_WFDS_MEM_ARENA_CE_TX_MSG_BUFFERS: ce tx message buffers memory arena + * @QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS: ce rx message buffers memory arena + */ +enum wlan_qmi_wfds_mem_arenas { + QMI_WFDS_MEM_ARENA_TX_BUFFERS = 0, + QMI_WFDS_MEM_ARENA_CE_TX_MSG_BUFFERS = 1, + QMI_WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS = 2, +}; + +/** + * struct wlan_qmi_wfds_mem_arena_info - Memory arena information + * @entry_size: entry size + * @num_entries: total number of entries required + */ +struct wlan_qmi_wfds_mem_arena_info { + uint16_t entry_size; + uint16_t num_entries; +}; + +/** + * struct wlan_qmi_wfds_mem_ind_msg - Memory indication message + * @mem_arena_info_len: number of valid entries in mem_arena_info array + * @mem_arena_info: memory arena information array + */ +struct wlan_qmi_wfds_mem_ind_msg { + uint32_t mem_arena_info_len; + struct wlan_qmi_wfds_mem_arena_info mem_arena_info[QMI_WFDS_MEM_ARENA_MAX]; +}; + +/** + * struct wlan_qmi_wfds_mem_arena_page_info - Memory arena + * page information + * @num_entries_per_page: number of entries per page + * @page_dma_addr_len: number of valid entries in page_dma_addr array + * @page_dma_addr: page dma address array + */ +struct wlan_qmi_wfds_mem_arena_page_info { + uint16_t num_entries_per_page; + uint32_t page_dma_addr_len; + uint64_t page_dma_addr[QMI_WFDS_PAGE_INFO_ARRAY_MAX_SIZE]; +}; + +/** + * struct wlan_qmi_wfds_mem_req_msg - Memory request message + * page information + * @mem_arena_page_info_len: number of valid entries in + * mem_arena_page_info array + * @mem_arena_page_info: memory arena information + */ +struct wlan_qmi_wfds_mem_req_msg { + uint32_t mem_arena_page_info_len; + struct wlan_qmi_wfds_mem_arena_page_info mem_arena_page_info[QMI_WFDS_MEM_ARENA_MAX]; +}; + +/** + * struct wlan_qmi_wfds_ipcc_info - IPCC information + * @ce_id: CE id + * @ipcc_trig_addr: IPCC trigger address + * @ipcc_trig_data: IPCC trigger data + */ +struct wlan_qmi_wfds_ipcc_info { + uint8_t ce_id; + uint64_t ipcc_trig_addr; + uint32_t ipcc_trig_data; +}; + +/** + * struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg - IPCC map and configure + * indication message + * @ipcc_ce_info_len: number of valid entries in ipcc_ce_info array + * @ipcc_ce_info: IPCC information for CE + */ +struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg { + uint32_t ipcc_ce_info_len; + struct wlan_qmi_wfds_ipcc_info ipcc_ce_info[QMI_WFDS_CE_MAX_SRNG]; +}; + +/** + * enum wlan_qmi_wfds_status - status + * @QMI_WFDS_STATUS_SUCCESS: success status + * @QMI_WFDS_STATUS_FAILURE: failure status + */ +enum wlan_qmi_wfds_status { + QMI_WFDS_STATUS_SUCCESS = 0, + QMI_WFDS_STATUS_FAILURE = 1, +}; + +/** + * struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg - IPCC map and configure + * request message + * @status: IPCC configuration status + */ +struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg { + enum wlan_qmi_wfds_status status; +}; +#endif + +/** + * struct wlan_qmi_psoc_callbacks - struct containing callbacks + * to osif QMI APIs + * @qmi_wfds_init: Callback to initialize WFDS QMI handle + * @qmi_wfds_deinit: Callback to deinitialize WFDS QMI handle + * @qmi_wfds_send_config_msg: Callback to send WFDS configuration message + * @qmi_wfds_send_req_mem_msg: Callback to send WFDS request memory message + * @qmi_wfds_send_ipcc_map_n_cfg_msg: Callback to send WFDS IPCC map and + * configure message + * @qmi_wfds_send_misc_req_msg: Callback to send WFDS misc request message + */ +struct wlan_qmi_psoc_callbacks { +#ifdef QMI_WFDS + QDF_STATUS (*qmi_wfds_init)(void); + void (*qmi_wfds_deinit)(void); + QDF_STATUS (*qmi_wfds_send_config_msg)( + struct wlan_qmi_wfds_config_req_msg *src_info); + QDF_STATUS (*qmi_wfds_send_req_mem_msg)( + struct wlan_qmi_wfds_mem_req_msg *src_info); + QDF_STATUS (*qmi_wfds_send_ipcc_map_n_cfg_msg)( + struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg *src_info); + QDF_STATUS (*qmi_wfds_send_misc_req_msg)(bool is_ssr); +#endif +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_ucfg_api.h new file mode 100644 index 0000000000..e6ead5c575 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_ucfg_api.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_ucfg_api.h + * + * QMI component north bound interface + */ + +#ifndef _WLAN_QMI_UCFG_API_H_ +#define _WLAN_QMI_UCFG_API_H_ + +#include +#include + +#ifdef QMI_COMPONENT_ENABLE +/** + * ucfg_qmi_init() - API to init QMI component + * + * This API is invoked from hdd_component_init during all component init. + * This API will register all required handlers for psoc object + * create/delete notification. + * + * Return: QDF status + */ +QDF_STATUS ucfg_qmi_init(void); + +/** + * ucfg_qmi_deinit() - API to deinit QMI component + * + * This API is invoked from hdd_component_deinit during all component deinit. + * This API will unregister all required handlers for psoc object + * create/delete notification. + * + * Return: QDF status + */ +QDF_STATUS ucfg_qmi_deinit(void); + +/** + * ucfg_qmi_register_os_if_callbacks() - API to register os if callbacks with + * QMI component + * @psoc: PSOC handle + * @cb_obj: callback object + * + * Return: None + */ +void ucfg_qmi_register_os_if_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_psoc_callbacks *cb_obj); +#else +static inline QDF_STATUS ucfg_qmi_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_qmi_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_qmi_register_os_if_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_psoc_callbacks *cb_obj) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_wfds_api.h b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_wfds_api.h new file mode 100644 index 0000000000..bcf2537515 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/inc/wlan_qmi_wfds_api.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_wfds_api.h + * + * Contains QMI wrapper API declarations to connect and send messages to + * QMI WFDS server + */ +#ifndef _WLAN_QMI_WFDS_API_H_ +#define _WLAN_QMI_WFDS_API_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_qmi_public_struct.h" + +#ifdef QMI_WFDS +/** + * wlan_qmi_wfds_init() - Initialize WFDS QMI client + * @psoc: PSOC handle + * + * Returns: QDF status + */ +QDF_STATUS wlan_qmi_wfds_init(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_qmi_wfds_deinit() - Deinitialize WFDS QMI client + * @psoc: PSOC handle + * + * Returns: None + */ +void wlan_qmi_wfds_deinit(struct wlan_objmgr_psoc *psoc); + +/* + * wlan_qmi_wfds_send_config_msg() - Send config message to QMI server + * to QMI server + * @psoc: PSOC handle + * @src_info: source information to be filled in QMI message + * + * Return: QDF status + */ +QDF_STATUS +wlan_qmi_wfds_send_config_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_config_req_msg *src_info); + +/* + * wlan_qmi_wfds_send_req_mem_msg() - Send Request Memory message to QMI server + * @psoc: PSOC handle + * @src_info: source information to be filled in QMI message + * + * Return: QDF status + */ +QDF_STATUS +wlan_qmi_wfds_send_req_mem_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_mem_req_msg *src_info); + +/* + * wlan_qmi_wfds_ipcc_map_n_cfg_msg() - Send the IPCC map and configure message + * to QMI server + * @psoc: PSOC handle + * @src_info: source information to be filled in QMI message + * + * Return: QDF status + */ +QDF_STATUS +wlan_qmi_wfds_ipcc_map_n_cfg_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg *src_info); + +/* + * wlan_qmi_wfds_send_misc_req_msg() - Send the misc req message + * to QMI server + * @psoc: PSOC handle + * @is_ssr: true if SSR is in progress else false + * + * Return: QDF status + */ +QDF_STATUS +wlan_qmi_wfds_send_misc_req_msg(struct wlan_objmgr_psoc *psoc, bool is_ssr); +#else +static inline +QDF_STATUS wlan_qmi_wfds_init(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +void wlan_qmi_wfds_deinit(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS +wlan_qmi_wfds_send_config_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_config_req_msg *src_info); +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_qmi_wfds_send_req_mem_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_mem_req_msg *src_info); +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_qmi_wfds_ipcc_map_n_cfg_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg *src_info) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_qmi_wfds_send_misc_req_msg(struct wlan_objmgr_psoc *psoc, bool is_ssr) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/src/wlan_qmi_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/src/wlan_qmi_ucfg_api.c new file mode 100644 index 0000000000..5810bdebae --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/src/wlan_qmi_ucfg_api.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_ucfg_api.c + * + * QMI component north bound interface definitions + */ + +#include "wlan_qmi_ucfg_api.h" +#include "wlan_qmi_main.h" +#include "wlan_qmi_objmgr.h" +#include "wlan_objmgr_global_obj.h" +#include "wlan_cmn.h" + +QDF_STATUS ucfg_qmi_init(void) +{ + QDF_STATUS status; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_QMI, + qmi_psoc_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + qmi_err("Failed to register psoc create handler for QMI"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_QMI, + qmi_psoc_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + qmi_err("Failed to register psoc destroy handler for QMI"); + goto fail_destroy_psoc; + } + + return status; + +fail_destroy_psoc: + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_QMI, + qmi_psoc_obj_create_notification, NULL); + + return status; +} + +QDF_STATUS ucfg_qmi_deinit(void) +{ + QDF_STATUS status; + + qmi_debug("QMI module dispatcher deinit"); + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_QMI, + qmi_psoc_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + qmi_err("Failed to unregister QMI psoc delete handle:%d", + status); + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_QMI, + qmi_psoc_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(status)) + qmi_err("Failed to unregister QMI psoc create handle:%d", + status); + + return status; +} + +#ifdef QMI_WFDS +/** + * ucfg_qmi_wfds_register_os_if_callbacks() - API to register wfds os if + * callbacks with QMI component + * @qmi_ctx: QMI component context + * @cb_obj: callback object + * + * Return: None + */ +static void +ucfg_qmi_wfds_register_os_if_callbacks(struct wlan_qmi_psoc_context *qmi_ctx, + struct wlan_qmi_psoc_callbacks *cb_obj) +{ + qmi_ctx->qmi_cbs.qmi_wfds_init = cb_obj->qmi_wfds_init; + qmi_ctx->qmi_cbs.qmi_wfds_deinit = cb_obj->qmi_wfds_deinit; + qmi_ctx->qmi_cbs.qmi_wfds_send_config_msg = + cb_obj->qmi_wfds_send_config_msg; + qmi_ctx->qmi_cbs.qmi_wfds_send_req_mem_msg = + cb_obj->qmi_wfds_send_req_mem_msg; + qmi_ctx->qmi_cbs.qmi_wfds_send_ipcc_map_n_cfg_msg = + cb_obj->qmi_wfds_send_ipcc_map_n_cfg_msg; + qmi_ctx->qmi_cbs.qmi_wfds_send_misc_req_msg = + cb_obj->qmi_wfds_send_misc_req_msg; +} +#else +static inline void +ucfg_qmi_wfds_register_os_if_callbacks(struct wlan_qmi_psoc_context *qmi_ctx, + struct wlan_qmi_psoc_callbacks *cb_obj) +{ +} +#endif + +void ucfg_qmi_register_os_if_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_psoc_callbacks *cb_obj) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return; + } + + ucfg_qmi_wfds_register_os_if_callbacks(qmi_ctx, cb_obj); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/src/wlan_qmi_wfds_api.c b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/src/wlan_qmi_wfds_api.c new file mode 100644 index 0000000000..9a8c5bb059 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/qmi/dispatcher/src/wlan_qmi_wfds_api.c @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qmi_wfds_api.c + * + * QMI component north bound interface definitions + */ + +#include "wlan_qmi_wfds_api.h" +#include "wlan_qmi_objmgr.h" +#include "wlan_qmi_priv.h" +#include "wlan_qmi_main.h" + +QDF_STATUS wlan_qmi_wfds_init(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qmi_ctx->qmi_cbs.qmi_wfds_init) + return qmi_ctx->qmi_cbs.qmi_wfds_init(); + + return QDF_STATUS_E_FAILURE; +} + +void wlan_qmi_wfds_deinit(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return; + } + + if (qmi_ctx->qmi_cbs.qmi_wfds_deinit) + qmi_ctx->qmi_cbs.qmi_wfds_deinit(); +} + +QDF_STATUS +wlan_qmi_wfds_send_config_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_config_req_msg *src_info) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qmi_ctx->qmi_cbs.qmi_wfds_send_config_msg) + return qmi_ctx->qmi_cbs.qmi_wfds_send_config_msg(src_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wlan_qmi_wfds_send_req_mem_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_mem_req_msg *src_info) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qmi_ctx->qmi_cbs.qmi_wfds_send_req_mem_msg) + return qmi_ctx->qmi_cbs.qmi_wfds_send_req_mem_msg(src_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wlan_qmi_wfds_ipcc_map_n_cfg_msg(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg *src_info) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qmi_ctx->qmi_cbs.qmi_wfds_send_ipcc_map_n_cfg_msg) + return qmi_ctx->qmi_cbs.qmi_wfds_send_ipcc_map_n_cfg_msg(src_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wlan_qmi_wfds_send_misc_req_msg(struct wlan_objmgr_psoc *psoc, bool is_ssr) +{ + struct wlan_qmi_psoc_context *qmi_ctx = qmi_psoc_get_priv(psoc); + + if (!qmi_ctx) { + qmi_err("QMI context is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qmi_ctx->qmi_cbs.qmi_wfds_send_misc_req_msg) + return qmi_ctx->qmi_cbs.qmi_wfds_send_misc_req_msg(is_ssr); + + return QDF_STATUS_E_FAILURE; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/inc/son_api.h b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/inc/son_api.h new file mode 100644 index 0000000000..578fa1ff6c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/inc/son_api.h @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for son api + */ +#ifndef _SON_API_H_ +#define _SON_API_H_ + +#include +#include +#include +#include +#include + +#define son_alert(format, args...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_SON, format, ## args) + +#define son_err(format, args...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_SON, format, ## args) + +#define son_warn(format, args...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_SON, format, ## args) + +#define son_info(format, args...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_SON, format, ## args) + +#define son_debug(format, args...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_alert(format, args...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_err(format, args...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_warn(format, args...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_info(format, args...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_debug(format, args...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_alert_rl(format, args...) \ + QDF_TRACE_FATAL_RL(QDF_MODULE_ID_SON, format, ## args) + +#define son_err_rl(format, args...) \ + QDF_TRACE_ERROR_RL(QDF_MODULE_ID_SON, format, ## args) + +#define son_warn_rl(format, args...) \ + QDF_TRACE_WARN_RL(QDF_MODULE_ID_SON, format, ## args) + +#define son_info_rl(format, args...) \ + QDF_TRACE_INFO_RL(QDF_MODULE_ID_SON, format, ## args) + +#define son_debug_rl(format, args...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_alert_rl(format, args...) \ + QDF_TRACE_FATAL_RL_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_err_rl(format, args...) \ + QDF_TRACE_ERROR_RL_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_warn_rl(format, args...) \ + QDF_TRACE_WARN_RL_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_info_rl(format, args...) \ + QDF_TRACE_INFO_RL_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define son_nofl_debug_rl(format, args...) \ + QDF_TRACE_DEBUG_RL_NO_FL(QDF_MODULE_ID_SON, format, ## args) + +#define TOTAL_DWELL_TIME 200 + +#define CBS_DEFAULT_RESTTIME 500 /* msec */ +#define CBS_DEFAULT_DWELL_TIME 50 /* msec */ +#define CBS_DEFAULT_WAIT_TIME 1000 /* 1 sec */ +#define CBS_DEFAULT_DWELL_SPLIT_TIME 50 /* msec */ +#define CBS_DEFAULT_DWELL_REST_TIME 500 /* msec */ +#define CBS_DEFAULT_MIN_REST_TIME 50 /* msec */ + +#define DEFAULT_BEACON_INTERVAL 100 + +#define CBS_DWELL_TIME_10MS 10 +#define CBS_DWELL_TIME_25MS 25 +#define CBS_DWELL_TIME_50MS 50 +#define CBS_DWELL_TIME_75MS 75 +#define MIN_SCAN_OFFSET_ARRAY_SIZE 0 +#define MAX_SCAN_OFFSET_ARRAY_SIZE 9 +#define SCAN_START_OFFSET_MIN 26 + +#define DEFAULT_SCAN_MAX_REST_TIME 500 + +/** + * enum son_cbs_state - son cbs state enumeration + * @CBS_INIT: init state + * @CBS_SCAN: scanning state + * @CBS_REST: rest state + * @CBS_RANK: rank state + * @CBS_WAIT: wait state + */ +enum son_cbs_state { + CBS_INIT, + CBS_SCAN, + CBS_REST, + CBS_RANK, + CBS_WAIT, +}; + +/** + * struct son_cbs - son cbs struction + * @vdev: vdev + * @cbs_lock: cbs spin lock + * @cbs_timer: cbs timer + * @cbs_state: cbs state + * @cbs_scan_requestor: scan requestor + * @cbs_scan_id: scan id + * @dwell_time: dwell time configuration + * @rest_time: rest time configuration + * @wait_time: wait time configuration + * @scan_intvl_time: interval time configuration + * @scan_params: scan params + * @max_dwell_split_cnt: max dwell split counter + * @dwell_split_cnt: dwell split counter + * @scan_offset: scan offset array + * @scan_dwell_rest: scan dwell rest array + * @min_dwell_rest_time: nub dwell rest time + * @dwell_split_time: dwell split time + * @max_arr_size_used: max array size used + */ +struct son_cbs { + struct wlan_objmgr_vdev *vdev; + + spinlock_t cbs_lock; + qdf_timer_t cbs_timer; + + enum son_cbs_state cbs_state; + + wlan_scan_requester cbs_scan_requestor; + wlan_scan_id cbs_scan_id; + + uint32_t dwell_time; + uint32_t rest_time; + uint32_t wait_time; + int32_t scan_intvl_time; + + struct scan_start_request scan_params; + + uint8_t max_dwell_split_cnt; + int8_t dwell_split_cnt; + uint32_t scan_offset[10]; + uint32_t scan_dwell_rest[10]; + uint32_t min_dwell_rest_time; + uint32_t dwell_split_time; + uint8_t max_arr_size_used; +}; + +/** + * typedef mlme_deliver_cb() - cb to deliver mlme event + * @vdev: pointer to vdev + * @event_len: event length + * @event_buf: event buffer + * + * Return: 0 if event is sent successfully + */ +typedef int (*mlme_deliver_cb)(struct wlan_objmgr_vdev *vdev, + uint32_t event_len, + const uint8_t *event_buf); + +/** + * enum SON_MLME_DELIVER_CB_TYPE - mlme deliver cb type + * @SON_MLME_DELIVER_CB_TYPE_OPMODE: cb to deliver opmode + * @SON_MLME_DELIVER_CB_TYPE_SMPS: cb to deliver smps + */ +enum SON_MLME_DELIVER_CB_TYPE { + SON_MLME_DELIVER_CB_TYPE_OPMODE, + SON_MLME_DELIVER_CB_TYPE_SMPS, +}; + +/** + * wlan_son_register_mlme_deliver_cb - register mlme deliver cb + * @psoc: pointer to psoc + * @cb: mlme deliver cb + * @type: mlme deliver cb type + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_son_register_mlme_deliver_cb(struct wlan_objmgr_psoc *psoc, + mlme_deliver_cb cb, + enum SON_MLME_DELIVER_CB_TYPE type); +/** + * wlan_son_peer_ext_stat_enable() - sends EXT stats command to FW + * @pdev: pointer to pdev + * @mac_addr: MAC address of the target peer + * @vdev: Pointer to vdev + * @stats_count: Stats count + * @enable: Enable / disable ext stats + * + * Return: QDF_STATUS_SUCCESS on success else failure + */ +QDF_STATUS wlan_son_peer_ext_stat_enable(struct wlan_objmgr_pdev *pdev, + uint8_t *mac_addr, + struct wlan_objmgr_vdev *vdev, + uint32_t stats_count, + uint32_t enable); + +/** + * wlan_son_peer_req_inst_stats() - Requests for instantaneous stats for + * the target mac_addr from FW via + * WMI_REQUEST_STATS_CMDID. + * @pdev: pointer to pdev + * @mac_addr: MAC address of the target peer + * @vdev: Pointer to vdev + * + * Return: QDF_STATUS_SUCCESS on success else failure + */ +QDF_STATUS wlan_son_peer_req_inst_stats(struct wlan_objmgr_pdev *pdev, + uint8_t *mac_addr, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_son_get_chan_flag() - get chan flag + * @pdev: pointer to pdev + * @freq: qdf_freq_t + * @flag_160: If true, 160 channel info will be obtained; + * otherwise 80+80, 80 channel info will be obtained + * @chan_params: chan parameters + * + * Return: combination of enum qca_wlan_vendor_channel_prop_flags and + * enum qca_wlan_vendor_channel_prop_flags_2 + */ +uint32_t wlan_son_get_chan_flag(struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq, bool flag_160, + struct ch_params *chan_params); + +/** + * wlan_son_peer_set_kickout_allow() - set the peer is allowed to kickout + * @vdev: pointer to vdev + * @peer: pointer to peer + * @kickout_allow: kickout_allow to set + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ +QDF_STATUS wlan_son_peer_set_kickout_allow(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + bool kickout_allow); + +/** + * wlan_son_cbs_init() - son cbs init + * + * Return: 0 if succeed + */ +int wlan_son_cbs_init(void); + +/* wlan_son_cbs_deinit - son cbs deinit + * + * Return: 0 if succeed + */ +int wlan_son_cbs_deinit(void); + +/* wlan_son_cbs_enable() - son cbs enable + * @vdev: pointer to vdev + * + * Return: 0 if succeed + */ +int wlan_son_cbs_enable(struct wlan_objmgr_vdev *vdev); + +/* wlan_son_cbs_disable() - son cbs disable + * @vdev: pointer to vdev + * + * Return: 0 if succeed + */ +int wlan_son_cbs_disable(struct wlan_objmgr_vdev *vdev); + +/* wlan_son_set_cbs() - son cbs set + * @vdev: pointer to vdev + * @enable: enable or disable son cbs + * + * Return: 0 if succeed + */ +int wlan_son_set_cbs(struct wlan_objmgr_vdev *vdev, + bool enable); + +/* wlan_son_set_cbs_wait_time() - cbs wait time configure + * @vdev: pointer to vdev + * @val: wait time value + * + * Return: 0 if succeed + */ +int wlan_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/* wlan_son_set_cbs_dwell_split_time() - cbs dwell spilt time configure + * @vdev: pointer to vdev + * @val: dwell spilt time value + * + * Return: 0 if succeed + */ +int wlan_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * wlan_son_vdev_get_supported_txrx_streams() - get supported spatial streams + * @vdev: pointer to vdev + * @num_tx_streams: pointer to number of tx streams + * @num_rx_streams: pointer to number of rx streams + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ +QDF_STATUS +wlan_son_vdev_get_supported_txrx_streams(struct wlan_objmgr_vdev *vdev, + uint32_t *num_tx_streams, + uint32_t *num_rx_streams); + +#ifdef WLAN_FEATURE_SON +/** + * wlan_son_peer_is_kickout_allow() - Is peer is allowed to kickout + * @vdev: pointer to vdev + * @macaddr: mac addr of the peer + * + * Return: True if it is allowed to kickout. + */ +bool wlan_son_peer_is_kickout_allow(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr); + +/** + * wlan_son_ind_assoc_req_frm() - indicate assoc req frame to son + * @vdev: pointer to vdev + * @macaddr: MAC address + * @is_reassoc: true if it is reassoc req + * @frame: frame body + * @frame_len: frame body length + * @status: assoc req frame is handled successfully + * + * Return: Void + */ +void wlan_son_ind_assoc_req_frm(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, bool is_reassoc, + uint8_t *frame, uint16_t frame_len, + QDF_STATUS status); + +/** + * wlan_son_deliver_tx_power() - notify son module of tx power + * @vdev: vdev + * @max_pwr: max power in dBm unit + * + * Return: 0 if event is sent successfully + */ +int wlan_son_deliver_tx_power(struct wlan_objmgr_vdev *vdev, + int32_t max_pwr); + +/** + * wlan_son_deliver_vdev_stop() - notify son module of vdev stop + * @vdev: vdev + * + * Return: 0 if event is sent successfully + */ +int wlan_son_deliver_vdev_stop(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_son_deliver_inst_rssi() - notify son module of inst rssi + * @vdev: vdev + * @peer: peer device + * @irssi: inst rssi above the noise floor in dB unit + * + * Return: 0 if event is sent successfully + */ +int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + uint32_t irssi); + +/** + * wlan_son_deliver_opmode() - notify user app of opmode + * @vdev: vdev objmgr + * @bw: channel width defined in enum eSirMacHTChannelWidth + * @nss: supported rx nss + * @addr: source addr + * + * Return: 0 if event is sent successfully + */ +int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev, + uint8_t bw, + uint8_t nss, + uint8_t *addr); + +/** + * wlan_son_deliver_smps() - notify user app of smps + * @vdev: vdev objmgr + * @is_static: is_static + * @addr: source addr + * + * Return: 0 if event is sent successfully + */ +int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev, + uint8_t is_static, + uint8_t *addr); + +/** + * wlan_son_deliver_rrm_rpt() - notify son module of rrm rpt + * @vdev: vdev objmgr + * @addr: sender addr + * @frm: points to measurement report + * @flen: frame length + * + * Return: 0 if event is sent successfully + */ +int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev, + uint8_t *addr, + uint8_t *frm, + uint32_t flen); +/** + * wlan_son_anqp_frame() - notify son module of mgmt frames + * @vdev: vdev + * @subtype: frame subtype + * @frame: the 802.11 frame + * @frame_len: frame length + * @action_hdr: Action header of the frame + * @macaddr: source mac address + * + * Return: 0 if event is sent successfully + */ +int wlan_son_anqp_frame(struct wlan_objmgr_vdev *vdev, int subtype, + uint8_t *frame, uint16_t frame_len, void *action_hdr, + uint8_t *macaddr); + +/** + * wlan_son_get_node_tx_power() - Gets the max transmit power for peer + * @assoc_req_ies: assoc req ies + * + * Return: Returns the max tx power + */ +uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies); + +/** + * wlan_son_get_peer_rrm_info() - Get RRM info for peer + * @assoc_req_ies: assoc req ies + * @rrmcaps: rrm capabilities + * @is_beacon_meas_supported: if beacon meas is supported + * + * Return: Returns QDF_STATUS_SUCCESS if succeed + */ +QDF_STATUS wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies, + uint8_t *rrmcaps, + bool *is_beacon_meas_supported); +#else + +static inline bool wlan_son_peer_is_kickout_allow(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr) +{ + return true; +} + +static inline +void wlan_son_ind_assoc_req_frm(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, bool is_reassoc, + uint8_t *frame, uint16_t frame_len, + QDF_STATUS status) +{ +} + +static inline +int wlan_son_deliver_tx_power(struct wlan_objmgr_vdev *vdev, + int32_t max_pwr) +{ + return -EINVAL; +} + +static inline +int wlan_son_deliver_vdev_stop(struct wlan_objmgr_vdev *vdev) +{ + return -EINVAL; +} + +static inline +int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + uint32_t irssi) +{ + return -EINVAL; +} + +static inline +int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev, + uint8_t bw, + uint8_t nss, + uint8_t *addr) +{ + return -EINVAL; +} + +static inline +int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev, + uint8_t is_static, + uint8_t *addr) +{ + return -EINVAL; +} + +static inline +int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + uint8_t *frm, + uint32_t flen) +{ + return -EINVAL; +} + +static inline +int wlan_son_anqp_frame(struct wlan_objmgr_vdev *vdev, int subtype, + uint8_t *frame, uint16_t frame_len, void *action_hdr, + uint8_t *macaddr) +{ + return -EINVAL; +} + +static inline +uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies) +{ + return 0; +} + +static inline +QDF_STATUS wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies, + uint8_t *rrmcaps, + bool *is_beacon_meas_supported) +{ + return QDF_STATUS_E_INVAL; +} +#endif /*WLAN_FEATURE_SON*/ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/inc/son_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/inc/son_ucfg_api.h new file mode 100644 index 0000000000..1804647159 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/inc/son_ucfg_api.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for OS_IF layer + */ +#ifndef _SON_UCFG_API_H_ +#define _SON_UCFG_API_H_ + +#include +#include +#include +#include + +/** + * ucfg_son_get_operation_chan_freq_vdev_id() - get operating chan freq of + * given vdev id + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: chan freq of given vdev id + */ +qdf_freq_t +ucfg_son_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * ucfg_son_get_min_and_max_power() - get min and max power + * @psoc: pointer to psoc + * @max_tx_power: max tx power(dBm units) to get. + * @min_tx_power: min tx power(dBm units) to get. + * + * Return: Void + */ +void ucfg_son_get_min_and_max_power(struct wlan_objmgr_psoc *psoc, + int8_t *max_tx_power, + int8_t *min_tx_power); + +/** + * ucfg_son_is_cac_in_progress() - whether cac in progress or not + * @vdev: Pointer to vdev + * + * Return: whether vdev in cac or not + */ +bool ucfg_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_son_get_sta_count() - get sta count + * @vdev: Pointer to vdev + * + * Return: sta count + */ +uint32_t ucfg_son_get_sta_count(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_son_get_chan_flag() - get chan flag + * @pdev: pointer to pdev + * @freq: qdf_freq_t + * @flag_160: whether 160 band width is enabled or not + * @chan_params: chan parameters + * + * Return: chan flag + */ +uint32_t ucfg_son_get_chan_flag(struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq, bool flag_160, + struct ch_params *chan_params); + +/** + * ucfg_son_get_he_supported() - get he supported + * @psoc: pointer to psoc + * @he_supported: he supported or not + * + * Return: void + */ +#ifdef WLAN_FEATURE_11AX +void ucfg_son_get_he_supported(struct wlan_objmgr_psoc *psoc, + bool *he_supported); +#else +static inline void ucfg_son_get_he_supported(struct wlan_objmgr_psoc *psoc, + bool *he_supported) +{ + *he_supported = false; +} +#endif /*WLAN_FEATURE_11AX*/ + +/** + * ucfg_son_set_peer_kickout_allow() - set the peer is allowed to kickout + * @vdev: pointer to vdev + * @peer: pointer to peer + * @kickout_allow: kickout_allow to set + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ +QDF_STATUS ucfg_son_set_peer_kickout_allow(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + bool kickout_allow); + +/** + * ucfg_son_register_deliver_opmode_cb() - register deliver opmode cb + * @psoc: pointer to psoc + * @cb: deliver opmode callback + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ +QDF_STATUS ucfg_son_register_deliver_opmode_cb(struct wlan_objmgr_psoc *psoc, + mlme_deliver_cb cb); + +/** + * ucfg_son_register_deliver_smps_cb() - register deliver smps cb + * @psoc: pointer to psoc + * @cb: deliver smps callback + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ + +QDF_STATUS ucfg_son_register_deliver_smps_cb(struct wlan_objmgr_psoc *psoc, + mlme_deliver_cb cb); + +/** + * ucfg_son_cbs_init() - son cbs init + * + * Return: 0 if succeed + */ +int ucfg_son_cbs_init(void); + +/** + * ucfg_son_cbs_deinit() - son cbs deinit + * + * Return: 0 if succeed + */ +int ucfg_son_cbs_deinit(void); + +/** + * ucfg_son_set_cbs() - son cbs set + * @vdev: pointer to vdev + * @enable: enable or disable son cbs + * + * Return: 0 if succeed + */ +int ucfg_son_set_cbs(struct wlan_objmgr_vdev *vdev, + bool enable); + +/** + * ucfg_son_set_cbs_wait_time() - cbs wait time configure + * @vdev: pointer to vdev + * @val: wait time value + * + * Return: 0 if succeed + */ +int ucfg_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_son_set_cbs_dwell_split_time() - cbs dwell spilt time configure + * @vdev: pointer to vdev + * @val: dwell spilt time value + * + * Return: 0 if succeed + */ +int ucfg_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * ucfg_son_get_tx_power() - Gets the max transmit power for peer + * @assoc_req_ies: assoc req ies + * + * Return: Returns the max tx power + */ +uint8_t ucfg_son_get_tx_power(struct element_info assoc_req_ies); + +/** + * ucfg_son_get_peer_rrm_info() - Get RRM info for peer + * @assoc_req_ies: assoc req ies + * @rrmcaps: rrm capabilities + * @is_beacon_meas_supported: if beacon meas is supported + * + * Return: Returns QDF_STATUS_SUCCESS if succeed + */ +QDF_STATUS ucfg_son_get_peer_rrm_info(struct element_info assoc_req_ies, + uint8_t *rrmcaps, + bool *is_beacon_meas_supported); + +/** + * ucfg_son_vdev_get_supported_txrx_streams() - get supported spatial streams + * @vdev: pointer to vdev + * @num_tx_streams: pointer to number of tx streams + * @num_rx_streams: pointer to number of rx streams + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ +QDF_STATUS +ucfg_son_vdev_get_supported_txrx_streams(struct wlan_objmgr_vdev *vdev, + uint32_t *num_tx_streams, + uint32_t *num_rx_streams); +/** + * ucfg_son_get_vht_cap() - get the vht capability ie + * @psoc: psoc object + * @vht_caps: VHT caps bit fields + * + * Return: QDF_STATUS_SUCCESS on Success else failure. + */ +QDF_STATUS ucfg_son_get_vht_cap(struct wlan_objmgr_psoc *psoc, + int32_t *vht_caps); + +#ifdef WLAN_FEATURE_SON +/* ucfg_son_disable_cbs() - son cbs disable + * @vdev: vdev pointer + * + * Return: 0 if succeed + */ +int ucfg_son_disable_cbs(struct wlan_objmgr_vdev *vdev); +#else +static inline int ucfg_son_disable_cbs(struct wlan_objmgr_vdev *vdev) +{ + return -EINVAL; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/src/son_api.c b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/src/son_api.c new file mode 100644 index 0000000000..6dc344eec9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/src/son_api.c @@ -0,0 +1,1408 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for son api + */ + +#include +#include +#include +#include +#include +#include + +/** + * struct son_mlme_deliver_cbs - son mlme deliver callbacks + * @deliver_opmode: cb to deliver opmode + * @deliver_smps: cb to deliver smps + */ +struct son_mlme_deliver_cbs { + mlme_deliver_cb deliver_opmode; + mlme_deliver_cb deliver_smps; +}; + +static struct son_mlme_deliver_cbs g_son_mlme_deliver_cbs; + +static struct son_cbs *g_son_cbs[WLAN_MAX_VDEVS]; +static qdf_spinlock_t g_cbs_lock; + +QDF_STATUS +wlan_son_register_mlme_deliver_cb(struct wlan_objmgr_psoc *psoc, + mlme_deliver_cb cb, + enum SON_MLME_DELIVER_CB_TYPE type) +{ + if (!psoc) { + son_err("invalid psoc"); + return QDF_STATUS_E_INVAL; + } + + switch (type) { + case SON_MLME_DELIVER_CB_TYPE_OPMODE: + g_son_mlme_deliver_cbs.deliver_opmode = cb; + break; + case SON_MLME_DELIVER_CB_TYPE_SMPS: + g_son_mlme_deliver_cbs.deliver_smps = cb; + break; + default: + son_err("invalid type"); + break; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_son_is_he_supported() - is he supported or not + * @psoc: pointer to psoc + * + * Return: true if supports, false otherwise + */ +#ifdef WLAN_FEATURE_11AX +static bool wlan_son_is_he_supported(struct wlan_objmgr_psoc *psoc) +{ + tDot11fIEhe_cap he_cap = {0}; + + mlme_cfg_get_he_caps(psoc, &he_cap); + return !!he_cap.present; +} +#else +static bool wlan_son_is_he_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif /*WLAN_FEATURE_11AX*/ + +QDF_STATUS wlan_son_peer_ext_stat_enable(struct wlan_objmgr_pdev *pdev, + uint8_t *mac_addr, + struct wlan_objmgr_vdev *vdev, + uint32_t stats_count, + uint32_t enable) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + if (!pdev) { + son_err("invalid pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + son_err("invalid psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + son_err("invalid tx_ops"); + return QDF_STATUS_E_NULL_VALUE; + } + if (tx_ops->son_tx_ops.peer_ext_stats_enable) + return tx_ops->son_tx_ops.peer_ext_stats_enable(pdev, + mac_addr, vdev, + stats_count, + enable); + + return QDF_STATUS_E_NULL_VALUE; +} + +QDF_STATUS wlan_son_peer_req_inst_stats(struct wlan_objmgr_pdev *pdev, + uint8_t *mac_addr, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + if (!pdev) { + son_err("invalid pdev"); + return QDF_STATUS_E_NULL_VALUE; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + son_err("invalid psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + son_err("invalid tx_ops"); + return QDF_STATUS_E_NULL_VALUE; + } + if (tx_ops->son_tx_ops.son_send_null) + return tx_ops->son_tx_ops.son_send_null(pdev, mac_addr, vdev); + + return QDF_STATUS_E_NULL_VALUE; +} + +uint32_t wlan_son_get_chan_flag(struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq, bool flag_160, + struct ch_params *chan_params) +{ + uint32_t flags = 0; + qdf_freq_t sec_freq; + struct ch_params ch_width40_ch_params; + uint8_t sub_20_channel_width = 0; + enum phy_ch_width bandwidth = mlme_get_vht_ch_width(); + struct wlan_objmgr_psoc *psoc; + bool is_he_enabled; + struct ch_params ch_params; + + if (!pdev) { + son_err("invalid pdev"); + return flags; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + son_err("invalid psoc"); + return flags; + } + + is_he_enabled = wlan_son_is_he_supported(psoc); + wlan_mlme_get_sub_20_chan_width(wlan_pdev_get_psoc(pdev), + &sub_20_channel_width); + + qdf_mem_zero(chan_params, sizeof(*chan_params)); + qdf_mem_zero(&ch_params, sizeof(ch_params)); + qdf_mem_zero(&ch_width40_ch_params, sizeof(ch_width40_ch_params)); + if (wlan_reg_is_24ghz_ch_freq(freq)) { + if (bandwidth == CH_WIDTH_80P80MHZ || + bandwidth == CH_WIDTH_160MHZ || + bandwidth == CH_WIDTH_80MHZ) + bandwidth = CH_WIDTH_40MHZ; + } + + ch_params.ch_width = bandwidth; + switch (bandwidth) { + case CH_WIDTH_80P80MHZ: + ch_params.ch_width = CH_WIDTH_80P80MHZ; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq, + &ch_params, REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (!flag_160) { + chan_params->ch_width = CH_WIDTH_80P80MHZ; + wlan_reg_set_channel_params_for_pwrmode( + pdev, freq, 0, chan_params, + REG_CURRENT_PWR_MODE); + } + if (is_he_enabled) + flags |= VENDOR_CHAN_FLAG2( + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80_80); + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80_80; + } + bandwidth = CH_WIDTH_160MHZ; + fallthrough; + case CH_WIDTH_160MHZ: + ch_params.ch_width = CH_WIDTH_160MHZ; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq, + &ch_params, REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (flag_160) { + chan_params->ch_width = CH_WIDTH_160MHZ; + wlan_reg_set_channel_params_for_pwrmode( + pdev, freq, 0, chan_params, + REG_CURRENT_PWR_MODE); + } + if (is_he_enabled) + flags |= VENDOR_CHAN_FLAG2( + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE160); + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT160; + } + bandwidth = CH_WIDTH_80MHZ; + fallthrough; + case CH_WIDTH_80MHZ: + ch_params.ch_width = CH_WIDTH_80MHZ; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq, + &ch_params, REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (!flag_160 && + chan_params->ch_width != CH_WIDTH_80P80MHZ) { + chan_params->ch_width = CH_WIDTH_80MHZ; + wlan_reg_set_channel_params_for_pwrmode( + pdev, freq, 0, chan_params, + REG_CURRENT_PWR_MODE); + } + if (is_he_enabled) + flags |= VENDOR_CHAN_FLAG2( + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE80); + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT80; + } + bandwidth = CH_WIDTH_40MHZ; + fallthrough; + case CH_WIDTH_40MHZ: + ch_width40_ch_params.ch_width = bandwidth; + wlan_reg_set_channel_params_for_pwrmode(pdev, freq, 0, + &ch_width40_ch_params, + REG_CURRENT_PWR_MODE); + + if (ch_width40_ch_params.sec_ch_offset == LOW_PRIMARY_CH) + sec_freq = freq + 20; + else if (ch_width40_ch_params.sec_ch_offset == HIGH_PRIMARY_CH) + sec_freq = freq - 20; + else + sec_freq = 0; + + if (wlan_reg_get_bonded_channel_state_for_pwrmode( + pdev, freq, + bandwidth, sec_freq, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (ch_width40_ch_params.sec_ch_offset == + LOW_PRIMARY_CH) { + if (is_he_enabled) + flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40PLUS; + flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40PLUS; + flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS; + } else if (ch_width40_ch_params.sec_ch_offset == + HIGH_PRIMARY_CH) { + if (is_he_enabled) + flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE40MINUS; + flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT40MINUS; + flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT40PLUS; + } + } + bandwidth = CH_WIDTH_20MHZ; + fallthrough; + case CH_WIDTH_20MHZ: + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HT20; + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_VHT20; + if (is_he_enabled) + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HE20; + bandwidth = CH_WIDTH_10MHZ; + fallthrough; + case CH_WIDTH_10MHZ: + if (wlan_reg_get_bonded_channel_state_for_pwrmode( + pdev, freq, + bandwidth, 0, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID && + sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_10) + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF; + bandwidth = CH_WIDTH_5MHZ; + fallthrough; + case CH_WIDTH_5MHZ: + if (wlan_reg_get_bonded_channel_state_for_pwrmode( + pdev, freq, + bandwidth, 0, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID && + sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_5) + flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER; + break; + default: + son_info("invalid channel width value %d", bandwidth); + } + + return flags; +} + +QDF_STATUS wlan_son_peer_set_kickout_allow(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + bool kickout_allow) +{ + struct peer_mlme_priv_obj *peer_priv; + + if (!peer) { + son_err("invalid peer"); + return QDF_STATUS_E_INVAL; + } + if (!vdev) { + son_err("invalid vdev"); + return QDF_STATUS_E_INVAL; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + son_err("invalid vdev"); + return QDF_STATUS_E_INVAL; + } + + peer_priv->allow_kickout = kickout_allow; + + return QDF_STATUS_SUCCESS; +} + +bool wlan_son_peer_is_kickout_allow(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr) +{ + bool kickout_allow = true; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + struct peer_mlme_priv_obj *peer_priv; + + if (!vdev) { + son_err("invalid vdev"); + return kickout_allow; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + son_err("invalid psoc"); + return kickout_allow; + } + peer = wlan_objmgr_get_peer_by_mac(psoc, macaddr, + WLAN_SON_ID); + + if (!peer) { + son_err("peer is null"); + return kickout_allow; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + son_err("invalid vdev"); + wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID); + return kickout_allow; + } + kickout_allow = peer_priv->allow_kickout; + wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID); + + return kickout_allow; +} + +void wlan_son_ind_assoc_req_frm(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddr, bool is_reassoc, + uint8_t *frame, uint16_t frame_len, + QDF_STATUS status) +{ + struct wlan_objmgr_peer *peer; + struct wlan_lmac_if_rx_ops *rx_ops; + struct wlan_objmgr_psoc *psoc; + uint16_t assocstatus = STATUS_UNSPECIFIED_FAILURE; + uint16_t sub_type = IEEE80211_FC0_SUBTYPE_ASSOC_REQ; + + if (!vdev) { + son_err("invalid vdev"); + return; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + son_err("invalid psoc"); + return; + } + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (!rx_ops || !rx_ops->son_rx_ops.process_mgmt_frame) { + son_err("invalid rx ops"); + return; + } + peer = wlan_objmgr_get_peer_by_mac(psoc, macaddr, + WLAN_SON_ID); + if (!peer) { + son_err("peer is null"); + return; + } + + if (is_reassoc) + sub_type = IEEE80211_FC0_SUBTYPE_REASSOC_REQ; + if (QDF_IS_STATUS_SUCCESS(status)) + assocstatus = STATUS_SUCCESS; + son_debug("subtype %u frame_len %u assocstatus %u", + sub_type, frame_len, assocstatus); + rx_ops->son_rx_ops.process_mgmt_frame(vdev, peer, sub_type, + frame, frame_len, + &assocstatus); + wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID); +} + +static int wlan_son_deliver_mlme_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + uint32_t event, + void *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_rx_ops *rx_ops; + int ret; + + if (!vdev) + return -EINVAL; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (rx_ops && rx_ops->son_rx_ops.deliver_event) { + son_debug("deliver mlme event %d", event); + ret = rx_ops->son_rx_ops.deliver_event(vdev, + peer, + event, + event_data); + } else { + return -EINVAL; + } + + return ret; +} + +int wlan_son_deliver_tx_power(struct wlan_objmgr_vdev *vdev, + int32_t max_pwr) +{ + int ret; + + son_debug("tx power %d", max_pwr); + ret = wlan_son_deliver_mlme_event(vdev, + NULL, + MLME_EVENT_TX_PWR_CHANGE, + &max_pwr); + + return ret; +} + +int wlan_son_deliver_vdev_stop(struct wlan_objmgr_vdev *vdev) +{ + int ret; + + struct wlan_vdev_state_event event; + + event.state = VDEV_STATE_STOPPED; + son_debug("state %d", event.state); + ret = wlan_son_deliver_mlme_event(vdev, + NULL, + MLME_EVENT_VDEV_STATE, + &event); + + return ret; +} + +int wlan_son_deliver_inst_rssi(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + uint32_t irssi) +{ + struct wlan_peer_inst_rssi event; + int ret; + + if (irssi > 0 && irssi <= 127) { + event.iRSSI = irssi; + event.valid = true; + son_debug("irssi %d", event.iRSSI); + } else { + event.valid = false; + son_debug("irssi invalid"); + } + + ret = wlan_son_deliver_mlme_event(vdev, + peer, + MLME_EVENT_INST_RSSI, + &event); + + return ret; +} + +int wlan_son_deliver_opmode(struct wlan_objmgr_vdev *vdev, + uint8_t bw, + uint8_t nss, + uint8_t *addr) +{ + struct wlan_objmgr_psoc *psoc; + struct ieee80211_opmode_update_data opmode; + + if (!vdev) + return -EINVAL; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + opmode.max_chwidth = bw; + opmode.num_streams = nss; + qdf_mem_copy(opmode.macaddr, addr, QDF_MAC_ADDR_SIZE); + + son_debug("bw %d, nss %d, addr " QDF_MAC_ADDR_FMT, + bw, nss, QDF_MAC_ADDR_REF(addr)); + + if (!g_son_mlme_deliver_cbs.deliver_opmode) { + son_err("invalid deliver opmode cb"); + return -EINVAL; + } + + g_son_mlme_deliver_cbs.deliver_opmode(vdev, + sizeof(opmode), + (uint8_t *)&opmode); + + return 0; +} + +int wlan_son_deliver_smps(struct wlan_objmgr_vdev *vdev, + uint8_t is_static, + uint8_t *addr) +{ + struct wlan_objmgr_psoc *psoc; + struct ieee80211_smps_update_data smps; + + if (!vdev) + return -EINVAL; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + smps.is_static = is_static; + qdf_mem_copy(smps.macaddr, addr, QDF_MAC_ADDR_SIZE); + + son_debug("is_static %d, addr" QDF_MAC_ADDR_FMT, + is_static, QDF_MAC_ADDR_REF(addr)); + + if (!g_son_mlme_deliver_cbs.deliver_smps) { + son_err("invalid deliver smps cb"); + return -EINVAL; + } + + g_son_mlme_deliver_cbs.deliver_smps(vdev, + sizeof(smps), + (uint8_t *)&smps); + + return 0; +} + +int wlan_son_deliver_rrm_rpt(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + uint8_t *frm, + uint32_t flen) +{ + struct wlan_act_frm_info rrm_info; + struct wlan_lmac_if_rx_ops *rx_ops; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer; + uint8_t sub_type = IEEE80211_FC0_SUBTYPE_ACTION; + struct ieee80211_action ia; + const uint8_t *ie, *pos, *end; + uint8_t total_bcnrpt_count = 0; + + if (!vdev) { + son_err("invalid vdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + son_err("invalid psoc"); + return -EINVAL; + } + + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (!rx_ops || !rx_ops->son_rx_ops.process_mgmt_frame) { + son_err("invalid rx ops"); + return -EINVAL; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, mac_addr, WLAN_SON_ID); + if (!peer) { + son_err("peer is null"); + return -EINVAL; + } + + ia.ia_category = ACTION_CATEGORY_RRM; + ia.ia_action = RRM_RADIO_MEASURE_RPT; + qdf_mem_zero(&rrm_info, sizeof(rrm_info)); + rrm_info.ia = &ia; + rrm_info.ald_info = 0; + qdf_mem_copy(rrm_info.data.rrm_data.macaddr, + mac_addr, + QDF_MAC_ADDR_SIZE); + /* IEEE80211_ACTION_RM_TOKEN */ + rrm_info.data.rrm_data.dialog_token = *frm; + + /* Points to Measurement Report Element */ + ++frm; + --flen; + pos = frm; + end = pos + flen; + + while ((ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_MEASREP, + pos, end - pos))) { + if (ie[1] < 3) { + son_err("Bad Measurement Report element"); + wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID); + return -EINVAL; + } + if (ie[4] == SIR_MAC_RRM_BEACON_TYPE) + ++total_bcnrpt_count; + pos = ie + ie[1] + 2; + } + + rrm_info.data.rrm_data.num_meas_rpts = total_bcnrpt_count; + + son_debug("Sta: " QDF_MAC_ADDR_FMT + "Category %d Action %d Num_Report %d Rptlen %d", + QDF_MAC_ADDR_REF(mac_addr), + ACTION_CATEGORY_RRM, + RRM_RADIO_MEASURE_RPT, + total_bcnrpt_count, + flen); + + rx_ops->son_rx_ops.process_mgmt_frame(vdev, peer, sub_type, + frm, flen, &rrm_info); + + wlan_objmgr_peer_release_ref(peer, WLAN_SON_ID); + + return 0; +} + +int wlan_son_anqp_frame(struct wlan_objmgr_vdev *vdev, int subtype, + uint8_t *frame, uint16_t frame_len, void *action_hdr, + uint8_t *macaddr) +{ + struct son_act_frm_info info; + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_rx_ops *rx_ops; + int ret; + + if (!vdev) + return -EINVAL; + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + qdf_mem_zero(&info, sizeof(info)); + info.ia = (struct ieee80211_action *)action_hdr; + info.ald_info = 1; + qdf_mem_copy(info.data.macaddr, macaddr, sizeof(tSirMacAddr)); + + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (rx_ops && rx_ops->son_rx_ops.process_mgmt_frame) + ret = rx_ops->son_rx_ops.process_mgmt_frame(vdev, NULL, + subtype, frame, + frame_len, &info); + else + return -EINVAL; + return ret; +} + +static int wlan_son_deliver_cbs(struct wlan_objmgr_vdev *vdev, + wlan_cbs_event_type type) +{ + int ret; + + ret = wlan_son_deliver_mlme_event(vdev, + NULL, + MLME_EVENT_CBS_STATUS, + &type); + + return ret; +} + +static int wlan_son_deliver_cbs_completed(struct wlan_objmgr_vdev *vdev) +{ + return wlan_son_deliver_cbs(vdev, CBS_COMPLETE); +} + +static int wlan_son_deliver_cbs_cancelled(struct wlan_objmgr_vdev *vdev) +{ + return wlan_son_deliver_cbs(vdev, CBS_CANCELLED); +} + +static void +wlan_son_cbs_set_state(struct son_cbs *cbs, enum son_cbs_state state) +{ + son_debug("Change State CBS OLD[%d] --> NEW[%d]", + cbs->cbs_state, state); + cbs->cbs_state = state; +} + +static enum +son_cbs_state wlan_son_cbs_get_state(struct son_cbs *cbs) +{ + return cbs->cbs_state; +} + +static void +wlan_son_cbs_init_dwell_params(struct son_cbs *cbs, + int dwell_split_time, + int dwell_rest_time) +{ + int i; + + if (!cbs || !cbs->vdev) + return; + son_debug("dwell_split_time %d, dwell_rest_time %d", + dwell_split_time, dwell_rest_time); + son_debug("vdev_id: %d\n", wlan_vdev_get_id(cbs->vdev)); + + switch (dwell_split_time) { + case CBS_DWELL_TIME_10MS: + cbs->max_arr_size_used = 10; + cbs->dwell_split_cnt = cbs->max_arr_size_used - 1; + cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1; + for (i = 0; i < cbs->max_arr_size_used; i++) + cbs->scan_dwell_rest[i] = dwell_rest_time; + for (i = 0; i < cbs->max_arr_size_used; i++) + cbs->scan_offset[i] = i * dwell_split_time; + break; + case CBS_DWELL_TIME_25MS: + cbs->max_arr_size_used = 8; + cbs->dwell_split_cnt = cbs->max_arr_size_used - 1; + cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1; + if (dwell_rest_time % TOTAL_DWELL_TIME == 0) { + cbs->scan_dwell_rest[0] = dwell_rest_time; + cbs->scan_dwell_rest[1] = dwell_rest_time; + cbs->scan_dwell_rest[2] = dwell_rest_time; + cbs->scan_dwell_rest[3] = dwell_rest_time; + cbs->scan_dwell_rest[4] = dwell_rest_time + + TOTAL_DWELL_TIME - + DEFAULT_BEACON_INTERVAL; + cbs->scan_dwell_rest[5] = dwell_rest_time + + TOTAL_DWELL_TIME - + DEFAULT_BEACON_INTERVAL; + cbs->scan_dwell_rest[6] = dwell_rest_time; + cbs->scan_dwell_rest[7] = dwell_rest_time; + cbs->scan_dwell_rest[8] = 0; + cbs->scan_dwell_rest[9] = 0; + cbs->scan_offset[0] = 0; + cbs->scan_offset[1] = 0; + cbs->scan_offset[2] = dwell_split_time; + cbs->scan_offset[3] = dwell_split_time; + cbs->scan_offset[4] = 2 * dwell_split_time; + cbs->scan_offset[5] = 2 * dwell_split_time; + cbs->scan_offset[6] = 3 * dwell_split_time; + cbs->scan_offset[7] = 3 * dwell_split_time; + cbs->scan_offset[8] = 0; + cbs->scan_offset[9] = 0; + } else { + for (i = 0; i < cbs->max_arr_size_used - 1; i++) + cbs->scan_dwell_rest[i] = dwell_rest_time; + + cbs->scan_dwell_rest[8] = 0; + cbs->scan_dwell_rest[9] = 0; + cbs->scan_offset[0] = 0; + cbs->scan_offset[1] = dwell_split_time; + cbs->scan_offset[2] = 2 * dwell_split_time; + cbs->scan_offset[3] = 3 * dwell_split_time; + cbs->scan_offset[4] = 0; + cbs->scan_offset[5] = dwell_split_time; + cbs->scan_offset[6] = 2 * dwell_split_time; + cbs->scan_offset[7] = 3 * dwell_split_time; + cbs->scan_offset[8] = 0; + cbs->scan_offset[9] = 0; + } + break; + case CBS_DWELL_TIME_50MS: + cbs->max_arr_size_used = 4; + cbs->dwell_split_cnt = cbs->max_arr_size_used - 1; + cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1; + if (dwell_rest_time % TOTAL_DWELL_TIME == 0) { + cbs->scan_dwell_rest[0] = dwell_rest_time; + cbs->scan_dwell_rest[1] = dwell_rest_time; + cbs->scan_dwell_rest[2] = dwell_rest_time + + TOTAL_DWELL_TIME - + DEFAULT_BEACON_INTERVAL; + cbs->scan_dwell_rest[3] = dwell_rest_time + + TOTAL_DWELL_TIME - + DEFAULT_BEACON_INTERVAL; + cbs->scan_dwell_rest[4] = 0; + cbs->scan_dwell_rest[5] = 0; + cbs->scan_dwell_rest[6] = 0; + cbs->scan_dwell_rest[7] = 0; + cbs->scan_dwell_rest[8] = 0; + cbs->scan_dwell_rest[9] = 0; + cbs->scan_offset[0] = 0; + cbs->scan_offset[1] = 0; + cbs->scan_offset[2] = dwell_split_time; + cbs->scan_offset[3] = dwell_split_time; + cbs->scan_offset[4] = 0; + cbs->scan_offset[5] = 0; + cbs->scan_offset[6] = 0; + cbs->scan_offset[7] = 0; + cbs->scan_offset[8] = 0; + cbs->scan_offset[9] = 0; + } else { + cbs->scan_dwell_rest[0] = dwell_rest_time; + cbs->scan_dwell_rest[1] = dwell_rest_time; + cbs->scan_dwell_rest[2] = dwell_rest_time; + cbs->scan_dwell_rest[3] = dwell_rest_time; + cbs->scan_dwell_rest[4] = 0; + cbs->scan_dwell_rest[5] = 0; + cbs->scan_dwell_rest[6] = 0; + cbs->scan_dwell_rest[7] = 0; + cbs->scan_dwell_rest[8] = 0; + cbs->scan_dwell_rest[9] = 0; + cbs->scan_offset[0] = 0; + cbs->scan_offset[1] = dwell_split_time; + cbs->scan_offset[2] = 0; + cbs->scan_offset[3] = dwell_split_time; + cbs->scan_offset[4] = 0; + cbs->scan_offset[5] = 0; + cbs->scan_offset[6] = 0; + cbs->scan_offset[7] = 0; + cbs->scan_offset[8] = 0; + cbs->scan_offset[9] = 0; + } + break; + case CBS_DWELL_TIME_75MS: + cbs->max_arr_size_used = 4; + cbs->dwell_split_cnt = cbs->max_arr_size_used - 1; + cbs->max_dwell_split_cnt = cbs->max_arr_size_used - 1; + if (dwell_rest_time % TOTAL_DWELL_TIME == 0) { + cbs->scan_dwell_rest[0] = dwell_rest_time; + cbs->scan_dwell_rest[1] = dwell_rest_time; + cbs->scan_dwell_rest[2] = dwell_rest_time + + TOTAL_DWELL_TIME - + DEFAULT_BEACON_INTERVAL; + cbs->scan_dwell_rest[3] = dwell_rest_time + + TOTAL_DWELL_TIME - + DEFAULT_BEACON_INTERVAL; + cbs->scan_dwell_rest[4] = 0; + cbs->scan_dwell_rest[5] = 0; + cbs->scan_dwell_rest[6] = 0; + cbs->scan_dwell_rest[7] = 0; + cbs->scan_dwell_rest[8] = 0; + cbs->scan_dwell_rest[9] = 0; + cbs->scan_offset[0] = 0; + cbs->scan_offset[1] = 0; + cbs->scan_offset[2] = DEFAULT_BEACON_INTERVAL - + dwell_split_time; + cbs->scan_offset[3] = DEFAULT_BEACON_INTERVAL - + dwell_split_time; + cbs->scan_offset[4] = 0; + cbs->scan_offset[5] = 0; + cbs->scan_offset[6] = 0; + cbs->scan_offset[7] = 0; + cbs->scan_offset[8] = 0; + cbs->scan_offset[9] = 0; + } else { + cbs->scan_dwell_rest[0] = dwell_rest_time; + cbs->scan_dwell_rest[1] = dwell_rest_time; + cbs->scan_dwell_rest[2] = dwell_rest_time; + cbs->scan_dwell_rest[3] = dwell_rest_time; + cbs->scan_dwell_rest[4] = 0; + cbs->scan_dwell_rest[5] = 0; + cbs->scan_dwell_rest[6] = 0; + cbs->scan_dwell_rest[7] = 0; + cbs->scan_dwell_rest[8] = 0; + cbs->scan_dwell_rest[9] = 0; + cbs->scan_offset[0] = 0; + cbs->scan_offset[1] = DEFAULT_BEACON_INTERVAL - + dwell_split_time; + cbs->scan_offset[2] = 0; + cbs->scan_offset[3] = DEFAULT_BEACON_INTERVAL - + dwell_split_time; + cbs->scan_offset[4] = 0; + cbs->scan_offset[5] = 0; + cbs->scan_offset[6] = 0; + cbs->scan_offset[7] = 0; + cbs->scan_offset[8] = 0; + cbs->scan_offset[9] = 0; + } + break; + default: + son_err("Dwell time not supported\n"); + break; + } +} + +static int wlan_son_cbs_start(struct son_cbs *cbs) +{ + struct scan_start_request *req; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(cbs->vdev); + if (!psoc) { + son_err("invalid psoc"); + return -EINVAL; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + son_err("failed to malloc"); + return -ENOMEM; + } + qdf_mem_copy(req, &cbs->scan_params, sizeof(*req)); + + cbs->cbs_scan_id = ucfg_scan_get_scan_id(psoc); + req->scan_req.scan_id = cbs->cbs_scan_id; + son_debug("vdev_id: %d req->scan_req.scan_id: %u", + wlan_vdev_get_id(cbs->vdev), req->scan_req.scan_id); + + status = ucfg_scan_start(req); + if (QDF_IS_STATUS_ERROR(status)) { + son_err("failed to start cbs"); + wlan_son_deliver_cbs_cancelled(cbs->vdev); + return -EINVAL; + } + + son_debug("cbs start"); + + return 0; +} + +static int wlan_son_cbs_stop(struct son_cbs *cbs) +{ + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + + pdev = wlan_vdev_get_pdev(cbs->vdev); + if (!pdev) { + son_err("invalid pdev"); + return -EINVAL; + } + son_debug("vdev_id: %d", wlan_vdev_get_id(cbs->vdev)); + + if (ucfg_scan_get_pdev_status(pdev) != SCAN_NOT_IN_PROGRESS) { + son_info("cbs_scan_id: %u abort scan", cbs->cbs_scan_id); + status = wlan_abort_scan(pdev, + wlan_objmgr_pdev_get_pdev_id(pdev), + cbs->vdev->vdev_objmgr.vdev_id, + cbs->cbs_scan_id, + true); + if (QDF_IS_STATUS_ERROR(status)) { + son_err("failed to abort cbs"); + return -EBUSY; + } + } + + return 0; +} + +static void wlan_cbs_timer_handler(void *arg) +{ + struct son_cbs *cbs = (struct son_cbs *)arg; + enum son_cbs_state state; + + state = wlan_son_cbs_get_state(cbs); + son_debug("state: %d", state); + if (state == CBS_REST) { + son_debug("vdev_id: %d dwell_split_cnt: %d", + wlan_vdev_get_id(cbs->vdev), + cbs->dwell_split_cnt); + qdf_spin_lock_bh(&g_cbs_lock); + wlan_son_cbs_set_state(cbs, CBS_SCAN); + cbs->dwell_split_cnt--; + wlan_son_cbs_start(cbs); + qdf_spin_unlock_bh(&g_cbs_lock); + } else if (state == CBS_WAIT) { + wlan_son_cbs_enable(cbs->vdev); + } +} + +static int wlan_cbs_iterate(struct son_cbs *cbs) +{ + int offset_array_idx; + struct wlan_objmgr_psoc *psoc; + + qdf_spin_lock_bh(&g_cbs_lock); + if (!cbs || !cbs->vdev) { + qdf_spin_unlock_bh(&g_cbs_lock); + return -EINVAL; + } + son_debug("dwell_split_cnt: %d", cbs->dwell_split_cnt); + if (cbs->dwell_split_cnt < 0) { + psoc = wlan_vdev_get_psoc(cbs->vdev); + if (!psoc) { + qdf_spin_unlock_bh(&g_cbs_lock); + return -EINVAL; + } + wlan_son_deliver_cbs_completed(cbs->vdev); + + ucfg_scan_unregister_requester(psoc, + cbs->cbs_scan_requestor); + son_debug("Unregister cbs_scan_requestor: %u", + cbs->cbs_scan_requestor); + + if (cbs->wait_time) { + wlan_son_cbs_set_state(cbs, CBS_WAIT); + qdf_timer_mod(&cbs->cbs_timer, + cbs->wait_time); + } else { + wlan_son_cbs_set_state(cbs, CBS_INIT); + } + } else { + offset_array_idx = cbs->max_arr_size_used - + cbs->dwell_split_cnt - 1; + if (offset_array_idx < MIN_SCAN_OFFSET_ARRAY_SIZE || + offset_array_idx > MAX_SCAN_OFFSET_ARRAY_SIZE) { + qdf_spin_unlock_bh(&g_cbs_lock); + return -EINVAL; + } + if (cbs->scan_dwell_rest[offset_array_idx] == 0) { + cbs->dwell_split_cnt--; + wlan_son_cbs_start(cbs); + } else { + wlan_son_cbs_set_state(cbs, CBS_REST); + qdf_timer_mod(&cbs->cbs_timer, + cbs->scan_dwell_rest[offset_array_idx]); + } + } + qdf_spin_unlock_bh(&g_cbs_lock); + + return 0; +} + +static void wlan_cbs_scan_event_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + son_debug("event type: %d", event->type); + switch (event->type) { + case SCAN_EVENT_TYPE_FOREIGN_CHANNEL: + case SCAN_EVENT_TYPE_FOREIGN_CHANNEL_GET_NF: + break; + case SCAN_EVENT_TYPE_COMPLETED: + wlan_cbs_iterate(arg); + break; + default: + break; + } +} + +int wlan_son_cbs_init(void) +{ + int i, j; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (g_son_cbs[i]) { + qdf_mem_free(g_son_cbs[i]); + g_son_cbs[i] = NULL; + } + g_son_cbs[i] = qdf_mem_malloc(sizeof(*g_son_cbs[i])); + if (!g_son_cbs[i]) { + for (j = i - 1; j >= 0; j--) { + qdf_mem_free(g_son_cbs[j]); + g_son_cbs[i] = NULL; + } + return -ENOMEM; + } + qdf_timer_init(NULL, + &g_son_cbs[i]->cbs_timer, + wlan_cbs_timer_handler, + g_son_cbs[i], + QDF_TIMER_TYPE_WAKE_APPS); + + g_son_cbs[i]->rest_time = CBS_DEFAULT_RESTTIME; + g_son_cbs[i]->dwell_time = CBS_DEFAULT_DWELL_TIME; + g_son_cbs[i]->wait_time = CBS_DEFAULT_WAIT_TIME; + g_son_cbs[i]->dwell_split_time = CBS_DEFAULT_DWELL_SPLIT_TIME; + g_son_cbs[i]->min_dwell_rest_time = CBS_DEFAULT_DWELL_REST_TIME; + + wlan_son_cbs_set_state(g_son_cbs[i], CBS_INIT); + } + qdf_spinlock_create(&g_cbs_lock); + son_debug("cbs init"); + + return 0; +} + +int wlan_son_cbs_deinit(void) +{ + int i; + + qdf_spinlock_destroy(&g_cbs_lock); + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (!g_son_cbs[i]) + return -EINVAL; + if (g_son_cbs[i]->vdev) { + wlan_objmgr_vdev_release_ref(g_son_cbs[i]->vdev, + WLAN_SON_ID); + son_debug("vdev_id: %d dereferenced", + wlan_vdev_get_id(g_son_cbs[i]->vdev)); + } + qdf_timer_free(&g_son_cbs[i]->cbs_timer); + qdf_mem_free(g_son_cbs[i]); + g_son_cbs[i] = NULL; + } + + son_debug("cbs deinit"); + + return 0; +} + +int wlan_son_cbs_enable(struct wlan_objmgr_vdev *vdev) +{ + struct scan_start_request *req; + struct wlan_objmgr_psoc *psoc; + enum son_cbs_state state; + struct son_cbs *cbs; + QDF_STATUS status; + + cbs = g_son_cbs[wlan_vdev_get_id(vdev)]; + if (!cbs) { + son_err("invalid cbs"); + return -EINVAL; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + son_err("invalid psoc"); + return -EINVAL; + } + + state = wlan_son_cbs_get_state(cbs); + if (state != CBS_INIT && + state != CBS_WAIT) { + son_err("can't start scan in state %d", state); + return -EINVAL; + } + son_debug("State: %d", state); + + qdf_spin_lock_bh(&g_cbs_lock); + if (!cbs->vdev) { + cbs->vdev = vdev; + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_SON_ID); + if (status != QDF_STATUS_SUCCESS) { + qdf_spin_unlock_bh(&g_cbs_lock); + son_err("Failed to get VDEV reference"); + return -EAGAIN; + } + son_debug("vdev_id: %d referenced", + wlan_vdev_get_id(vdev)); + } + cbs->cbs_scan_requestor = + ucfg_scan_register_requester(psoc, + (uint8_t *)"cbs", + wlan_cbs_scan_event_cb, + (void *)cbs); + son_debug("cbs_scan_requestor: %u vdev_id: %d", + cbs->cbs_scan_requestor, wlan_vdev_get_id(vdev)); + + if (!cbs->cbs_scan_requestor) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_SON_ID); + qdf_spin_unlock_bh(&g_cbs_lock); + son_err("ucfg_scan_register_requestor failed"); + return -EINVAL; + } + + req = &cbs->scan_params; + ucfg_scan_init_default_params(vdev, req); + req->scan_req.scan_req_id = cbs->cbs_scan_requestor; + + req->scan_req.vdev_id = wlan_vdev_get_id(vdev); + req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; + req->scan_req.scan_f_bcast_probe = true; + + req->scan_req.scan_f_passive = true; + req->scan_req.max_rest_time = DEFAULT_SCAN_MAX_REST_TIME; + req->scan_req.scan_f_forced = true; + + req->scan_req.scan_flags = 0; + req->scan_req.dwell_time_active = cbs->dwell_split_time; + req->scan_req.dwell_time_passive = cbs->dwell_split_time + 5; + req->scan_req.min_rest_time = CBS_DEFAULT_MIN_REST_TIME; + req->scan_req.max_rest_time = CBS_DEFAULT_DWELL_REST_TIME; + req->scan_req.scan_f_passive = false; + req->scan_req.scan_f_2ghz = true; + req->scan_req.scan_f_5ghz = true; + req->scan_req.scan_f_offchan_mgmt_tx = true; + req->scan_req.scan_f_offchan_data_tx = true; + req->scan_req.scan_f_chan_stat_evnt = true; + + if (cbs->min_dwell_rest_time % DEFAULT_BEACON_INTERVAL) { + cbs->min_dwell_rest_time = + (cbs->min_dwell_rest_time / + (2 * DEFAULT_BEACON_INTERVAL)) * + (2 * DEFAULT_BEACON_INTERVAL) + + (cbs->min_dwell_rest_time % 200 < 100) ? 100 : 200; + } + + wlan_son_cbs_init_dwell_params(cbs, + cbs->dwell_split_time, + cbs->min_dwell_rest_time); + + cbs->dwell_split_cnt--; + wlan_son_cbs_set_state(cbs, CBS_SCAN); + + wlan_son_cbs_start(cbs); + qdf_spin_unlock_bh(&g_cbs_lock); + + son_debug("cbs enable"); + + return 0; +} + +int wlan_son_cbs_disable(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct son_cbs *cbs; + + if (!vdev) { + son_err("invalid vdev"); + return -EINVAL; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + son_err("invalid psoc"); + return -EINVAL; + } + cbs = g_son_cbs[wlan_vdev_get_id(vdev)]; + if (!cbs || !cbs->vdev) { + son_err("vdev null"); + return -EINVAL; + } + wlan_son_deliver_cbs_cancelled(vdev); + + qdf_timer_sync_cancel(&cbs->cbs_timer); + + wlan_son_cbs_stop(cbs); + + son_debug("cbs_scan_requestor: %d vdev_id: %d", + cbs->cbs_scan_requestor, wlan_vdev_get_id(vdev)); + ucfg_scan_unregister_requester(psoc, cbs->cbs_scan_requestor); + + qdf_spin_lock_bh(&g_cbs_lock); + wlan_son_cbs_set_state(cbs, CBS_INIT); + if (vdev == cbs->vdev) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_SON_ID); + son_debug("vdev_id: %d dereferenced", + vdev->vdev_objmgr.vdev_id); + } + cbs->vdev = NULL; + qdf_spin_unlock_bh(&g_cbs_lock); + + son_debug("cbs disable"); + + return 0; +} + +int wlan_son_set_cbs(struct wlan_objmgr_vdev *vdev, + bool enable) +{ + son_debug("Enable: %u", enable); + + if (!vdev || !g_son_cbs[wlan_vdev_get_id(vdev)]) + return -EINVAL; + + if (enable) + wlan_son_cbs_enable(vdev); + else + wlan_son_cbs_disable(vdev); + + return 0; +} + +int wlan_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + if (!g_son_cbs[wlan_vdev_get_id(vdev)]) + return -EINVAL; + + son_debug("vdev_id: %d wait time %d", wlan_vdev_get_id(vdev), val); + wlan_son_set_cbs(vdev, false); + + if (val % DEFAULT_BEACON_INTERVAL != 0) { + val = (val / (2 * DEFAULT_BEACON_INTERVAL)) * + (2 * DEFAULT_BEACON_INTERVAL) + + (val % (2 * DEFAULT_BEACON_INTERVAL) < + DEFAULT_BEACON_INTERVAL) ? + DEFAULT_BEACON_INTERVAL : + 2 * DEFAULT_BEACON_INTERVAL; + } + qdf_spin_lock_bh(&g_cbs_lock); + g_son_cbs[wlan_vdev_get_id(vdev)]->wait_time = val; + qdf_spin_unlock_bh(&g_cbs_lock); + + wlan_son_set_cbs(vdev, true); + + return 0; +} + +int wlan_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + if (!g_son_cbs[wlan_vdev_get_id(vdev)]) + return -EINVAL; + + son_debug("vdev_id: %d dwell split time %d", + wlan_vdev_get_id(vdev), val); + if (val != CBS_DWELL_TIME_10MS && + val != CBS_DWELL_TIME_25MS && + val != CBS_DWELL_TIME_50MS && + val != CBS_DWELL_TIME_75MS) { + son_err("dwell time not supported "); + return -EINVAL; + } + + wlan_son_set_cbs(vdev, false); + + qdf_spin_lock_bh(&g_cbs_lock); + g_son_cbs[wlan_vdev_get_id(vdev)]->dwell_split_time = val; + qdf_spin_unlock_bh(&g_cbs_lock); + + wlan_son_set_cbs(vdev, true); + + return 0; +} + +uint8_t wlan_son_get_node_tx_power(struct element_info assoc_req_ies) +{ + const uint8_t *power_cap_ie_data; + + power_cap_ie_data = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_PWRCAP, + assoc_req_ies.ptr, + assoc_req_ies.len); + if (power_cap_ie_data) + return *(power_cap_ie_data + 3); + else + return 0; +} + +QDF_STATUS wlan_son_get_peer_rrm_info(struct element_info assoc_req_ies, + uint8_t *rrmcaps, + bool *is_beacon_meas_supported) +{ + const uint8_t *eid; + + eid = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RRM, + assoc_req_ies.ptr, + assoc_req_ies.len); + if (eid) { + qdf_mem_copy(rrmcaps, &eid[2], eid[1]); + if ((rrmcaps[0] & + IEEE80211_RRM_CAPS_BEACON_REPORT_PASSIVE) || + (rrmcaps[0] & + IEEE80211_RRM_CAPS_BEACON_REPORT_ACTIVE)) + *is_beacon_meas_supported = true; + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_RESOURCES; +} + +QDF_STATUS +wlan_son_vdev_get_supported_txrx_streams(struct wlan_objmgr_vdev *vdev, + uint32_t *num_tx_streams, + uint32_t *num_rx_streams) +{ + struct wlan_mlme_nss_chains *nss_cfg; + enum nss_chains_band_info band = NSS_CHAINS_BAND_MAX; + struct wlan_channel *chan; + qdf_freq_t chan_freq = 0; + + nss_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!nss_cfg) + return QDF_STATUS_NOT_INITIALIZED; + + chan = wlan_vdev_get_active_channel(vdev); + if (chan) + chan_freq = chan->ch_freq; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) + band = NSS_CHAINS_BAND_2GHZ; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) + band = NSS_CHAINS_BAND_5GHZ; + + if (band == NSS_CHAINS_BAND_MAX) + return QDF_STATUS_NOT_INITIALIZED; + + *num_tx_streams = nss_cfg->tx_nss[band]; + *num_rx_streams = nss_cfg->rx_nss[band]; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/src/son_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/src/son_ucfg_api.c new file mode 100644 index 0000000000..615a742f24 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/son/dispatcher/src/son_ucfg_api.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for OS_IF layer + */ + +#include +#include +#include +#include + +qdf_freq_t +ucfg_son_get_operation_chan_freq_vdev_id(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + return wlan_get_operation_chan_freq_vdev_id(pdev, vdev_id); +} + +void ucfg_son_get_min_and_max_power(struct wlan_objmgr_psoc *psoc, + int8_t *max_tx_power, + int8_t *min_tx_power) +{ + struct wlan_psoc_target_capability_info *target_cap = + lmac_get_target_cap(psoc); + + *max_tx_power = 0; + *min_tx_power = 0; + + if (target_cap) { + *max_tx_power = target_cap->hw_max_tx_power; + *min_tx_power = target_cap->hw_min_tx_power; + } +} + +bool ucfg_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return QDF_IS_STATUS_SUCCESS(wlan_vdev_is_dfs_cac_wait(vdev)); +} + +uint32_t ucfg_son_get_sta_count(struct wlan_objmgr_vdev *vdev) +{ + uint32_t sta_count = wlan_vdev_get_peer_count(vdev); + + /* Don't include self peer in the count */ + if (sta_count > 0) + --sta_count; + + return sta_count; +} + +uint32_t ucfg_son_get_chan_flag(struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq, bool flag_160, + struct ch_params *chan_params) +{ + return wlan_son_get_chan_flag(pdev, freq, flag_160, + chan_params); +} + +QDF_STATUS ucfg_son_set_peer_kickout_allow(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + bool kickout_allow) +{ + return wlan_son_peer_set_kickout_allow(vdev, peer, kickout_allow); +} + +QDF_STATUS ucfg_son_register_deliver_opmode_cb(struct wlan_objmgr_psoc *psoc, + mlme_deliver_cb cb) +{ + return wlan_son_register_mlme_deliver_cb(psoc, cb, + SON_MLME_DELIVER_CB_TYPE_OPMODE); +} + +QDF_STATUS ucfg_son_register_deliver_smps_cb(struct wlan_objmgr_psoc *psoc, + mlme_deliver_cb cb) +{ + return wlan_son_register_mlme_deliver_cb(psoc, cb, + SON_MLME_DELIVER_CB_TYPE_SMPS); +} + +int ucfg_son_cbs_init(void) +{ + return wlan_son_cbs_init(); +} + +int ucfg_son_cbs_deinit(void) +{ + return wlan_son_cbs_deinit(); +} + +int ucfg_son_set_cbs(struct wlan_objmgr_vdev *vdev, + bool enable) +{ + return wlan_son_set_cbs(vdev, enable); +} + +int ucfg_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + return wlan_son_set_cbs_wait_time(vdev, val); +} + +int ucfg_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + return wlan_son_set_cbs_dwell_split_time(vdev, val); +} + +int ucfg_son_disable_cbs(struct wlan_objmgr_vdev *vdev) +{ + return wlan_son_cbs_disable(vdev); +} + +uint8_t ucfg_son_get_tx_power(struct element_info assoc_req_ies) +{ + return wlan_son_get_node_tx_power(assoc_req_ies); +} + +QDF_STATUS ucfg_son_get_peer_rrm_info(struct element_info assoc_req_ies, + uint8_t *rrmcaps, + bool *is_beacon_meas_supported) +{ + return wlan_son_get_peer_rrm_info(assoc_req_ies, rrmcaps, + is_beacon_meas_supported); +} + +QDF_STATUS +ucfg_son_vdev_get_supported_txrx_streams(struct wlan_objmgr_vdev *vdev, + uint32_t *num_tx_streams, + uint32_t *num_rx_streams) +{ + return wlan_son_vdev_get_supported_txrx_streams(vdev, + num_tx_streams, + num_rx_streams); +} + +QDF_STATUS ucfg_son_get_vht_cap(struct wlan_objmgr_psoc *psoc, + int32_t *vht_caps) +{ + struct wlan_psoc_target_capability_info *target_cap = + lmac_get_target_cap(psoc); + + if (!target_cap) + return QDF_STATUS_E_NULL_VALUE; + *vht_caps = target_cap->vht_cap_info; + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/inc/spatial_reuse_api.h b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/inc/spatial_reuse_api.h new file mode 100644 index 0000000000..442451859d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/inc/spatial_reuse_api.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for spatial_reuse api + */ + +#ifndef _SPATIAL_REUSE_API_H_ +#define _SPATIAL_REUSE_API_H_ + +#include +#include +#include + +/** + * enum sr_osif_operation - Spatial Reuse operation + * @SR_OPERATION_SUSPEND: Spatial Reuse suspend indication + * @SR_OPERATION_RESUME: Spatial Reuse resume indication + * @SR_OPERATION_UPDATE_PARAMS: Spatial Reuse parameters are updated + */ +enum sr_osif_operation { + SR_OPERATION_SUSPEND = 0, + SR_OPERATION_RESUME = 1, + SR_OPERATION_UPDATE_PARAMS = 2, +}; + +/** + * enum sr_osif_reason_code - Spatial Reuse reason codes + * @SR_REASON_CODE_ROAMING: Spatial Reuse reason code is Roaming will be + * set when SR is suspended / resumed due to roaming + * @SR_REASON_CODE_CONCURRENCY: Spatial Reuse reason code is concurrency + * will be set when SR is suspended / resumed + * due to concurrency + * @SR_REASON_CODE_BCN_IE_CHANGE: Spatial Reuse reason code is SRP IE change + * in the beacon/probe rsp of the associated AP + */ +enum sr_osif_reason_code { + SR_REASON_CODE_ROAMING = 0, + SR_REASON_CODE_CONCURRENCY = 1, + SR_REASON_CODE_BCN_IE_CHANGE = 2, +}; + +/** + * typedef sr_osif_event_cb() - CB to deliver SR events + * @vdev: objmgr manager vdev + * @sr_osif_oper: SR Operation like suspend / resume + * @sr_osif_rc: Event reason code + * + * Return: void + */ +typedef void (*sr_osif_event_cb)(struct wlan_objmgr_vdev *vdev, + enum sr_osif_operation sr_osif_oper, + enum sr_osif_reason_code sr_osif_rc); + +#ifdef WLAN_FEATURE_SR +/** + * wlan_spatial_reuse_config_set() - Set spatial reuse config + * @vdev: objmgr manager vdev + * @sr_ctrl: spatial reuse control + * @non_srg_max_pd_offset: non-srg max pd offset + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_spatial_reuse_config_set(struct wlan_objmgr_vdev *vdev, + uint8_t sr_ctrl, + uint8_t non_srg_max_pd_offset); + +/** + * wlan_sr_register_callback() - registers SR osif events + * @psoc: pointer to psoc + * @cb: Callback to be registered + * + * Return: void + */ +void wlan_sr_register_callback(struct wlan_objmgr_psoc *psoc, + sr_osif_event_cb cb); + +/** + * wlan_spatial_reuse_osif_event() - Send SR asynchronous events + * @vdev: objmgr manager vdev + * @sr_osif_oper: SR Operation like suspend / resume + * @sr_osif_rc: Event reason code + * + * Return: void + */ +void wlan_spatial_reuse_osif_event(struct wlan_objmgr_vdev *vdev, + enum sr_osif_operation sr_osif_oper, + enum sr_osif_reason_code sr_osif_rc); +#else +static inline +QDF_STATUS wlan_spatial_reuse_config_set(struct wlan_objmgr_vdev *vdev, + uint8_t sr_ctrl, + uint8_t non_srg_max_pd_offset) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void wlan_spatial_reuse_osif_event(struct wlan_objmgr_vdev *vdev, + enum sr_osif_operation sr_osif_oper, + enum sr_osif_reason_code sr_osif_rc) +{ +} +#endif + +/** + * wlan_spatial_reuse_he_siga_val15_allowed_set() - Set spatial reuse config + * he_siga_val15_allowed + * @vdev: objmgr manager vdev + * @he_siga_va15_allowed: enable/disable he_siga_val15_allowed + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_spatial_reuse_he_siga_val15_allowed_set( + struct wlan_objmgr_vdev *vdev, + bool he_siga_va15_allowed); + +/** + * wlan_sr_setup_req() - Enable SR with provided pd threshold + * @vdev: objmgr vdev + * @pdev: objmgr pdev + * @is_sr_enable: sr enable/disable + * @srg_pd_threshold: SRG pd threshold + * @non_srg_pd_threshold: NON SRG PD threshold + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_sr_setup_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_pdev *pdev, bool is_sr_enable, + int32_t srg_pd_threshold, int32_t non_srg_pd_threshold); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/inc/spatial_reuse_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/inc/spatial_reuse_ucfg_api.h new file mode 100644 index 0000000000..a8a0d34862 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/inc/spatial_reuse_ucfg_api.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for OS_IF layer + */ +#ifndef _SPATIAL_REUSE_UCFG_API_H_ +#define _SPATIAL_REUSE_UCFG_API_H_ + +#include +#include +#include + +#ifdef WLAN_FEATURE_SR +/** + * ucfg_spatial_reuse_register_cb() - Registers CB for SR + * @psoc: pointer to psoc + * @cb: SR osif event callback + * + * Return: void + */ +void ucfg_spatial_reuse_register_cb(struct wlan_objmgr_psoc *psoc, + sr_osif_event_cb cb); + +/** + * ucfg_spatial_reuse_get_sr_config() - Spatial reuse config get + * + * @vdev: object manager vdev + * @sr_ctrl: spatial reuse sr control + * @non_srg_max_pd_offset: non-srg max pd offset + * @he_spr_enabled: spatial reuse enabled + * + * Return: void + */ +void ucfg_spatial_reuse_get_sr_config(struct wlan_objmgr_vdev *vdev, + uint8_t *sr_ctrl, + uint8_t *non_srg_max_pd_offset, + bool *he_spr_enabled); +/** + * ucfg_spatial_reuse_set_sr_config() - Spatial reuse config set + * + * @vdev: object manager vdev + * @sr_ctrl: spatial reuse sr control + * @non_srg_max_pd_offset: non-srg max pd offset + * + * Return: void + */ +void ucfg_spatial_reuse_set_sr_config(struct wlan_objmgr_vdev *vdev, + uint8_t sr_ctrl, + uint8_t non_srg_max_pd_offset); + +/** + * ucfg_spatial_reuse_is_sr_disabled_due_conc() - Spatial reuse get concurrency + * status + * + * @vdev: object manager vdev + * + * Return: True when SR is disabled due to concurrency or else False + */ +bool ucfg_spatial_reuse_is_sr_disabled_due_conc(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_spatial_reuse_set_sr_conc_stat() - Spatial reuse disable config set + * + * @vdev: object manager vdev + * @sr_conc_disabled: spatial reuse disabled due to concurrency + * + * Return: void + */ +void ucfg_spatial_reuse_set_sr_conc_stat(struct wlan_objmgr_vdev *vdev, + bool sr_conc_disabled); + +/** + * ucfg_spatial_reuse_send_sr_config() - Send spatial reuse config to fw + * + * @vdev: object manager vdev + * @enable: spatial reuse config to be enabled or not + * + * Return: void + */ +void ucfg_spatial_reuse_send_sr_config(struct wlan_objmgr_vdev *vdev, + bool enable); + +/** + * ucfg_spatial_reuse_set_sr_enable() - set enable/disable Spatial reuse + * + * @vdev: object manager vdev + * @enable: spatial reuse to be enabled or not + * + * Return: void + */ +void ucfg_spatial_reuse_set_sr_enable(struct wlan_objmgr_vdev *vdev, + bool enable); + +/** + * ucfg_spatial_reuse_send_sr_prohibit() - Send spatial reuse config to enable + * or disable he_siga_val15_allowed + * + * @vdev: object manager vdev + * @enable_he_siga_val15_prohibit: enable/disable he_siga_val15_allowed + * + * Return: success/failure + */ +QDF_STATUS +ucfg_spatial_reuse_send_sr_prohibit(struct wlan_objmgr_vdev *vdev, + bool enable_he_siga_val15_prohibit); + +/** + * ucfg_spatial_reuse_setup_req() - To enable/disable SR (Spatial Reuse) + * @vdev: object manager vdev + * @pdev: object manager pdev + * @is_sr_enable: SR enable/disable + * @srg_pd_threshold: SRG pd threshold + * @non_srg_pd_threshold: NON SRG pd threshold + * + * Return: Success/Failure + */ +QDF_STATUS +ucfg_spatial_reuse_setup_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_pdev *pdev, + bool is_sr_enable, int32_t srg_pd_threshold, + int32_t non_srg_pd_threshold); + +/** + * ucfg_spatial_reuse_operation_allowed() - Checks whether SR is allowed or not + * @psoc: Object manager psoc + * @vdev: object manager vdev + * + * Return: QDF_STATUS_SUCCESS when SR is allowed else Failure + */ +QDF_STATUS +ucfg_spatial_reuse_operation_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); +#else +static inline +void ucfg_spatial_reuse_register_cb(struct wlan_objmgr_psoc *psoc, + sr_osif_event_cb cb) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/src/spatial_reuse_api.c b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/src/spatial_reuse_api.c new file mode 100644 index 0000000000..30f9d563b8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/src/spatial_reuse_api.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for spatial_reuse api + */ +#include +#include + +struct sr_cb { + sr_osif_event_cb send_osif_event; +} sr_cb; + +QDF_STATUS wlan_spatial_reuse_config_set(struct wlan_objmgr_vdev *vdev, + uint8_t sr_ctrl, + uint8_t non_srg_max_pd_offset) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) + return QDF_STATUS_E_NULL_VALUE; + + if (tx_ops->spatial_reuse_tx_ops.send_cfg) + return tx_ops->spatial_reuse_tx_ops.send_cfg(vdev, sr_ctrl, + non_srg_max_pd_offset); + + return QDF_STATUS_E_NULL_VALUE; +} + +QDF_STATUS wlan_spatial_reuse_he_siga_val15_allowed_set( + struct wlan_objmgr_vdev *vdev, + bool he_siga_va15_allowed) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) + return QDF_STATUS_E_NULL_VALUE; + + if (tx_ops->spatial_reuse_tx_ops.send_sr_prohibit_cfg) + return tx_ops->spatial_reuse_tx_ops.send_sr_prohibit_cfg( + vdev, + he_siga_va15_allowed); + return QDF_STATUS_E_NULL_VALUE; +} + +QDF_STATUS +wlan_sr_setup_req(struct wlan_objmgr_vdev *vdev, struct wlan_objmgr_pdev *pdev, + bool is_sr_enable, int32_t srg_pd_threshold, + int32_t non_srg_pd_threshold) { + struct wlan_lmac_if_tx_ops *tx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + tx_ops = wlan_psoc_get_lmac_if_txops(wlan_pdev_get_psoc(pdev)); + if (tx_ops && + tx_ops->spatial_reuse_tx_ops.target_if_set_sr_enable_disable) { + status = + tx_ops->spatial_reuse_tx_ops.target_if_set_sr_enable_disable( + vdev, pdev, is_sr_enable, + srg_pd_threshold, non_srg_pd_threshold); + return status; + } + return status; +} + +void wlan_sr_register_callback(struct wlan_objmgr_psoc *psoc, + sr_osif_event_cb cb) +{ + if (!psoc) + return; + sr_cb.send_osif_event = cb; +} + +void wlan_spatial_reuse_osif_event(struct wlan_objmgr_vdev *vdev, + enum sr_osif_operation sr_osif_oper, + enum sr_osif_reason_code sr_osif_rc) +{ + if (sr_cb.send_osif_event) + sr_cb.send_osif_event(vdev, sr_osif_oper, sr_osif_rc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/src/spatial_reuse_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/src/spatial_reuse_ucfg_api.c new file mode 100644 index 0000000000..552624325b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/spatial_reuse/dispatcher/src/spatial_reuse_ucfg_api.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains interface prototypes for OS_IF layer + */ +#include +#include +#include +#include + +void ucfg_spatial_reuse_register_cb(struct wlan_objmgr_psoc *psoc, + sr_osif_event_cb cb) +{ + wlan_sr_register_callback(psoc, cb); +} + +void ucfg_spatial_reuse_get_sr_config(struct wlan_objmgr_vdev *vdev, + uint8_t *sr_ctrl, + uint8_t *non_srg_max_pd_offset, + bool *he_spr_enabled) +{ + *sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev); + *non_srg_max_pd_offset = wlan_vdev_mlme_get_non_srg_pd_offset(vdev); + *he_spr_enabled = wlan_vdev_mlme_get_he_spr_enabled(vdev); +} + +void ucfg_spatial_reuse_set_sr_config(struct wlan_objmgr_vdev *vdev, + uint8_t sr_ctrl, + uint8_t non_srg_max_pd_offset) +{ + wlan_vdev_mlme_set_sr_ctrl(vdev, sr_ctrl); + wlan_vdev_mlme_set_non_srg_pd_offset(vdev, non_srg_max_pd_offset); +} + +bool ucfg_spatial_reuse_is_sr_disabled_due_conc(struct wlan_objmgr_vdev *vdev) +{ + return wlan_vdev_mlme_is_sr_disable_due_conc(vdev); +} + +void ucfg_spatial_reuse_set_sr_conc_stat(struct wlan_objmgr_vdev *vdev, + bool sr_conc_disabled) +{ + wlan_vdev_mlme_set_sr_disable_due_conc(vdev, sr_conc_disabled); +} + +void ucfg_spatial_reuse_send_sr_config(struct wlan_objmgr_vdev *vdev, + bool enable) +{ + uint8_t sr_ctrl = 0; + /* Disabled PD Threshold */ + uint8_t non_srg_max_pd_offset = 0x80; + + /* SR feature itself is disabled by user */ + if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) + return; + /* SR is disabled due to conccurrency */ + if (ucfg_spatial_reuse_is_sr_disabled_due_conc(vdev)) + return; + + if (enable) { + sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev); + non_srg_max_pd_offset = + wlan_vdev_mlme_get_non_srg_pd_offset(vdev); + if (sr_ctrl && non_srg_max_pd_offset) + wlan_spatial_reuse_config_set(vdev, sr_ctrl, + non_srg_max_pd_offset); + } else { + wlan_spatial_reuse_config_set(vdev, sr_ctrl, + non_srg_max_pd_offset); + } +} + +void ucfg_spatial_reuse_set_sr_enable(struct wlan_objmgr_vdev *vdev, + bool enable) +{ + wlan_vdev_mlme_set_he_spr_enabled(vdev, enable); +} + +QDF_STATUS ucfg_spatial_reuse_send_sr_prohibit( + struct wlan_objmgr_vdev *vdev, + bool enable_he_siga_val15_prohibit) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool sr_enabled = wlan_vdev_mlme_get_he_spr_enabled(vdev); + bool sr_prohibited = wlan_vdev_mlme_is_sr_prohibit_en(vdev); + uint8_t sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev); + + /* Enable PD prohibit only when it is allowed by the AP, + * Check if it is not enabled already, then only enable it + */ + if (sr_enabled && (sr_ctrl & WLAN_HE_SIGA_SR_VAL15_ALLOWED) && + sr_prohibited != enable_he_siga_val15_prohibit) { + status = wlan_spatial_reuse_he_siga_val15_allowed_set + (vdev, + enable_he_siga_val15_prohibit); + + if (QDF_IS_STATUS_SUCCESS(status)) + wlan_vdev_mlme_set_sr_prohibit_en + (vdev, + enable_he_siga_val15_prohibit); + } else { + mlme_debug("Prohibit command can not be sent sr_enabled %d, sr_ctrl %d , sr_prohibited %d", + sr_enabled, + sr_ctrl, + sr_prohibited); + + return QDF_STATUS_E_FAILURE; + } + return status; +} + +QDF_STATUS +ucfg_spatial_reuse_setup_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_pdev *pdev, + bool is_sr_enable, int32_t srg_pd_threshold, + int32_t non_srg_pd_threshold) +{ + return wlan_sr_setup_req(vdev, pdev, is_sr_enable, + srg_pd_threshold, non_srg_pd_threshold); +} + +QDF_STATUS ucfg_spatial_reuse_operation_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint32_t conc_vdev_id; + uint8_t vdev_id, mac_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!vdev || !psoc) + return QDF_STATUS_E_NULL_VALUE; + + vdev_id = wlan_vdev_get_id(vdev); + if (!policy_mgr_get_connection_count(psoc)) { + mlme_debug("No active vdev"); + return status; + } + status = policy_mgr_get_mac_id_by_session_id(psoc, vdev_id, &mac_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + conc_vdev_id = policy_mgr_get_conc_vdev_on_same_mac(psoc, vdev_id, + mac_id); + if (conc_vdev_id != WLAN_INVALID_VDEV_ID && + !policy_mgr_sr_same_mac_conc_enabled(psoc)) + return QDF_STATUS_E_NOSUPPORT; + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/action_oui/inc/target_if_action_oui.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/action_oui/inc/target_if_action_oui.h new file mode 100644 index 0000000000..4bd65b7d06 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/action_oui/inc/target_if_action_oui.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare various api/struct which shall be used + * by action_oui component for wmi command path. + */ + +#ifndef _TARGET_IF_ACTION_OUI_H_ +#define _TARGET_IF_ACTION_OUI_H_ + +#include "target_if.h" +#include +#include +#include +#include "wlan_action_oui_tgt_api.h" +#include "wlan_action_oui_public_struct.h" + +/** + * target_if_action_oui_register_tx_ops() - Register action_oui component TX OPS + * @tx_ops: action_oui transmit ops + * + * Return: None + */ +void +target_if_action_oui_register_tx_ops(struct action_oui_tx_ops *tx_ops); + +#endif /* _TARGET_IF_ACTION_OUI_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/action_oui/src/target_if_action_oui.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/action_oui/src/target_if_action_oui.c new file mode 100644 index 0000000000..4893b633e1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/action_oui/src/target_if_action_oui.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Target interface file for action_oui component to + * Implement api's which shall be used by action_oui component + * in target_if internally. + */ + +#include "target_if_action_oui.h" +#include "wlan_action_oui_tgt_api.h" +#include "wlan_action_oui_public_struct.h" + +static QDF_STATUS +target_if_action_oui_send_req(struct wlan_objmgr_psoc *psoc, + struct action_oui_request *req) +{ + void *wmi_hdl; + + wmi_hdl = GET_WMI_HDL_FROM_PSOC(psoc); + if (!wmi_hdl) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_send_action_oui_cmd(wmi_hdl, req); +} + +void +target_if_action_oui_register_tx_ops(struct action_oui_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("action_oui tx_ops is null"); + return; + } + + tx_ops->send_req = target_if_action_oui_send_req; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/coap/inc/target_if_coap.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coap/inc/target_if_coap.h new file mode 100644 index 0000000000..eb6917027e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coap/inc/target_if_coap.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains CoAP target if declarations + */ +#ifndef __TARGET_IF_COAP_H__ +#define __TARGET_IF_COAP_H__ + +#include + +/** + * target_if_coap_register_tx_ops() - Register CoAP target_if tx ops + * @tx_ops: pointer to target if tx ops + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_coap_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); + +/** + * target_if_coap_get_tx_ops() - get tx ops + * @psoc: pointer to psoc object + * + * API to retrieve the CoAP tx ops from the psoc context + * + * Return: pointer to tx ops + */ +static inline struct wlan_lmac_if_coap_tx_ops * +target_if_coap_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_tx_ops *tx_ops; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + target_if_err("tx_ops is NULL"); + return NULL; + } + return &tx_ops->coap_ops; +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/coap/src/target_if_coap.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coap/src/target_if_coap.c new file mode 100644 index 0000000000..9471d334a2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coap/src/target_if_coap.c @@ -0,0 +1,314 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains CoAP target if functions + */ +#include +#include +#include + +/** + * target_if_wow_coap_buf_info_event_handler() - function to handle CoAP + * buf info event from firmware. + * @scn: scn handle + * @data: data buffer for event + * @datalen: data length + * + * Return: status of operation. + */ +static int +target_if_wow_coap_buf_info_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_coap_comp_priv *coap_priv; + struct coap_buf_info info = {0}; + struct coap_buf_node *cur, *next; + + if (!scn || !data) { + coap_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + coap_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + coap_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_list_create(&info.info_list, 0); + status = wmi_unified_coap_extract_buf_info(wmi_handle, data, + &info); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, info.vdev_id, + WLAN_COAP_ID); + if (!vdev) { + coap_err("vdev is NULL, vdev_id: %d", info.vdev_id); + status = QDF_STATUS_E_INVAL; + goto out; + } + + coap_priv = wlan_get_vdev_coap_obj(vdev); + if (!coap_priv->cache_get_cbk || !coap_priv->cache_get_context) { + coap_err("req id %d: callback or context is NULL", + coap_priv->req_id); + status = QDF_STATUS_E_INVAL; + goto out; + } + + coap_priv->cache_get_cbk(coap_priv->cache_get_context, &info); +out: + qdf_list_for_each_del(&info.info_list, cur, next, node) { + qdf_list_remove_node(&info.info_list, &cur->node); + qdf_mem_free(cur->payload); + qdf_mem_free(cur); + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_COAP_ID); + return qdf_status_to_os_return(status); +} + +/** + * target_if_coap_register_event_handler() - Register CoAP related wmi events + * @psoc: psoc handle + * + * Register CoAP related WMI events + * + * return: QDF_STATUS + */ +static QDF_STATUS +target_if_coap_register_event_handler(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret_val; + struct wmi_unified *wmi_handle; + + if (!psoc) { + coap_err("PSOC is NULL!"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + coap_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + ret_val = wmi_unified_register_event_handler(wmi_handle, + wmi_wow_coap_buf_info_eventid, + target_if_wow_coap_buf_info_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(ret_val)) + coap_err("Failed to register coap buf info event cb"); + + return ret_val; +} + +/** + * target_if_coap_unregister_event_handler() - Unregister CoAP related wmi + * events + * @psoc: psoc handle + * + * Register CoAP related WMI events + * + * return: QDF_STATUS + */ +static QDF_STATUS +target_if_coap_unregister_event_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + coap_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + coap_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + wmi_unified_unregister_event_handler(wmi_handle, + wmi_wow_coap_buf_info_eventid); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_coap_offload_reply_enable() - enable CoAP offload reply + * @vdev: pointer to vdev object + * @param: parameters for CoAP offload reply + * + * Return: status of operation + */ +static QDF_STATUS +target_if_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_reply_param *param) +{ + wmi_unified_t wmi_handle; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!wmi_handle) { + coap_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_coap_add_pattern_cmd(wmi_handle, param); +} + +/** + * target_if_coap_offload_reply_disable() - disable CoAP offload reply + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +static QDF_STATUS +target_if_coap_offload_reply_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + wmi_unified_t wmi_handle; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!wmi_handle) { + coap_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_coap_del_pattern_cmd(wmi_handle, + wlan_vdev_get_id(vdev), + req_id); +} + +/** + * target_if_coap_offload_periodic_tx_enable() - enable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @param: parameters for CoAP periodic transmitting + * + * Return: status of operation + */ +static QDF_STATUS +target_if_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + struct coap_offload_periodic_tx_param *param) +{ + wmi_unified_t wmi_handle; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!wmi_handle) { + coap_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_coap_add_keepalive_pattern_cmd(wmi_handle, param); +} + +/** + * target_if_coap_offload_periodic_tx_disable() - disable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +static QDF_STATUS +target_if_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + wmi_unified_t wmi_handle; + struct wlan_objmgr_pdev *pdev; + uint8_t vdev_id; + + pdev = wlan_vdev_get_pdev(vdev); + wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!wmi_handle) { + coap_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = wlan_vdev_get_id(vdev); + return wmi_unified_coap_del_keepalive_pattern_cmd(wmi_handle, + vdev_id, req_id); +} + +/** + * target_if_coap_offload_cache_get() - get cached CoAP messages + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: status of operation + */ +static QDF_STATUS +target_if_coap_offload_cache_get(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + wmi_unified_t wmi_handle; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(vdev); + wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!wmi_handle) { + coap_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_coap_cache_get(wmi_handle, wlan_vdev_get_id(vdev), + req_id); +} + +QDF_STATUS +target_if_coap_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_coap_tx_ops *coap_ops; + + if (!tx_ops) { + coap_err("target if tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + coap_ops = &tx_ops->coap_ops; + coap_ops->attach = target_if_coap_register_event_handler; + coap_ops->detach = target_if_coap_unregister_event_handler; + coap_ops->offload_reply_enable = + target_if_coap_offload_reply_enable; + coap_ops->offload_reply_disable = + target_if_coap_offload_reply_disable; + coap_ops->offload_periodic_tx_enable = + target_if_coap_offload_periodic_tx_enable; + coap_ops->offload_periodic_tx_disable = + target_if_coap_offload_periodic_tx_disable; + coap_ops->offload_cache_get = target_if_coap_offload_cache_get; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/coex/inc/target_if_coex.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coex/inc/target_if_coex.h new file mode 100644 index 0000000000..563f8f42aa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coex/inc/target_if_coex.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains coex target if declarations + */ +#ifndef __TARGET_IF_COEX_H__ +#define __TARGET_IF_COEX_H__ + +#include +#include "wlan_coex_public_structs.h" + +/** + * target_if_coex_register_tx_ops() - Register coex target_if tx ops + * @tx_ops: pointer to target if tx ops + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * target_if_dbam_register_tx_ops() - Register dbam target_if tx ops + * @tx_ops: pointer to target if tx ops + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_dbam_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); + +/** + * target_if_dbam_process_event() - dbam response function handler + * @psoc: pointer to psoc + * @resp: response received from FW to dbam config command + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_dbam_process_event(struct wlan_objmgr_psoc *psoc, + enum coex_dbam_comp_status resp); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/coex/src/target_if_coex.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coex/src/target_if_coex.c new file mode 100644 index 0000000000..787be0720d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/coex/src/target_if_coex.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains coex target if functions + */ +#include +#include +#include "wlan_coex_public_structs.h" + +/** + * target_if_coex_config_send() - Function to send coex config command + * @pdev: PDEV object + * @param: Pointer to coex config parameters + * + * Return: QDF STATUS + */ +static QDF_STATUS +target_if_coex_config_send(struct wlan_objmgr_pdev *pdev, + struct coex_config_params *param) +{ + wmi_unified_t pdev_wmi_handle; + + pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!pdev_wmi_handle) { + coex_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_send_coex_config_cmd(pdev_wmi_handle, param); +} + +/** + * target_if_coex_multi_config_send() - Function to send coex multiple config + * command + * @pdev: PDEV object + * @param: Pointer to coex multiple config parameters + * + * Return: QDF STATUS + */ +static QDF_STATUS +target_if_coex_multi_config_send(struct wlan_objmgr_pdev *pdev, + struct coex_multi_config *param) +{ + wmi_unified_t pdev_wmi_handle; + + pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev); + if (!pdev_wmi_handle) { + coex_err("Invalid PDEV WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_send_coex_multi_config_cmd(pdev_wmi_handle, param); +} + +/** + * target_if_coex_get_multi_config_support() - Function to get coex multiple + * config command support + * @psoc: PSOC object + * + * Return: true if target support coex multiple config command + */ +static bool +target_if_coex_get_multi_config_support(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return false; + } + + return wmi_service_enabled(wmi_handle, + wmi_service_multiple_coex_config_support); +} + +QDF_STATUS +target_if_coex_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_coex_tx_ops *coex_ops; + + if (!tx_ops) { + coex_err("target if tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + coex_ops = &tx_ops->coex_ops; + coex_ops->coex_config_send = target_if_coex_config_send; + coex_ops->coex_multi_config_send = target_if_coex_multi_config_send; + coex_ops->coex_get_multi_config_support = + target_if_coex_get_multi_config_support; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_DBAM_CONFIG +QDF_STATUS +target_if_dbam_process_event(struct wlan_objmgr_psoc *psoc, + enum coex_dbam_comp_status resp) +{ + struct coex_psoc_obj *coex_obj; + struct wlan_coex_callback *cb; + + if (!psoc) { + coex_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) { + coex_err("failed to get coex_obj"); + return QDF_STATUS_E_INVAL; + } + + cb = &coex_obj->cb; + if (cb->set_dbam_config_cb) + cb->set_dbam_config_cb(cb->set_dbam_config_ctx, &resp); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dbam_response_event_handler() - function to handle dbam response + * event from firmware. + * @scn: scn handle + * @data: data buffer foe the event + * @len: data length + * + * Return: 0 on success, and error code on failure + */ +static int target_if_dbam_response_event_handler(ol_scn_t scn, + uint8_t *data, + uint32_t len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + struct wlan_lmac_if_dbam_rx_ops *rx_ops; + struct coex_dbam_config_resp resp = {0}; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, len); + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is Null"); + return -EINVAL; + } + + rx_ops = wlan_psoc_get_dbam_rx_ops(psoc); + if (!rx_ops || !rx_ops->dbam_resp_event) { + target_if_err("callback not registered"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_dbam_config_response(wmi_handle, data, &resp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to extract dbam config response"); + return -EINVAL; + } + + status = rx_ops->dbam_resp_event(psoc, resp.dbam_resp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("process dbam response event failed"); + return -EINVAL; + } + + return 0; +} + +/** + * target_if_dbam_config_send() - Send WMI command for DBAM configuration + * @psoc: psoc pointer + * @param: dbam config parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_dbam_config_send(struct wlan_objmgr_psoc *psoc, + struct coex_dbam_config_params *param) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + status = wmi_unified_send_dbam_config_cmd(wmi_handle, param); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to send DBAM config %d", status); + + return status; +} + +static QDF_STATUS +target_if_dbam_register_event_handler(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_coex_dbam_complete_event_id, + target_if_dbam_response_event_handler, + WMI_RX_WORK_CTX); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to register dbam complete event cb"); + + return status; +} + +static QDF_STATUS +target_if_dbam_unregister_event_handler(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return QDF_STATUS_E_INVAL; + } + + wmi_unified_unregister_event_handler(wmi_handle, + wmi_coex_dbam_complete_event_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +target_if_dbam_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_dbam_tx_ops *dbam_tx_ops; + + if (!tx_ops) { + target_if_err("target if tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + dbam_tx_ops = &tx_ops->dbam_tx_ops; + if (!dbam_tx_ops) { + target_if_err("target if dbam ops is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + dbam_tx_ops->set_dbam_config = target_if_dbam_config_send; + dbam_tx_ops->dbam_event_attach = target_if_dbam_register_event_handler; + dbam_tx_ops->dbam_event_detach = + target_if_dbam_unregister_event_handler; + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/inc/target_if_cm_roam_event.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/inc/target_if_cm_roam_event.h new file mode 100644 index 0000000000..9b770e8f8d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/inc/target_if_cm_roam_event.h @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for target_if + * roaming events. + */ + +#ifndef TARGET_IF_CM_ROAM_EVENT_H__ +#define TARGET_IF_CM_ROAM_EVENT_H__ + +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_cm_roam_public_struct.h" +#include + +/** + * target_if_cm_get_roam_rx_ops() - Get CM roam rx ops registered + * @psoc: pointer to psoc object + * + * Return: roam rx ops of connection mgr + */ +struct wlan_cm_roam_rx_ops * +target_if_cm_get_roam_rx_ops(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_cm_roam_register_rx_ops - Target IF API to register roam + * related rx op. + * @rx_ops: Pointer to rx ops fp struct + * + * Return: none + */ +void +target_if_cm_roam_register_rx_ops(struct wlan_cm_roam_rx_ops *rx_ops); + +/** + * target_if_cm_roam_event() - Target IF handler for roam events + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int target_if_cm_roam_event(ol_scn_t scn, uint8_t *event, uint32_t len); + +/** + * target_if_roam_register_common_events() - register common roam events + * of LFR2/3 + * @psoc: pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_roam_register_common_events(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * target_if_cm_roam_sync_event() - Target IF handler for roam sync events + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int target_if_cm_roam_sync_event(ol_scn_t scn, uint8_t *event, + uint32_t len); + +/** + * target_if_cm_roam_sync_frame_event() - Target IF handler for + * roam sync frame events + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_cm_roam_sync_frame_event(ol_scn_t scn, + uint8_t *event, + uint32_t len); + +/** + * target_if_cm_roam_stats_event() - Target IF handler for roam stats event + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_cm_roam_stats_event(ol_scn_t scn, uint8_t *event, uint32_t len); + +/** + * target_if_cm_roam_auth_offload_event - auth roam offload event handler + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_cm_roam_auth_offload_event(ol_scn_t scn, uint8_t *event, + uint32_t len); + +/** + * target_if_roam_offload_register_events() - register roam offload events + * @psoc: pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_cm_roam_vdev_disconnect_event_handler - vdev disconnect evt handler + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_cm_roam_vdev_disconnect_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len); + +/** + * target_if_cm_roam_scan_chan_list_event_handler - roam scan ch evt handler + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_cm_roam_scan_chan_list_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len); + +/** + * target_if_pmkid_request_event_handler - pmkid request event handler + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_pmkid_request_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len); + +/** + * target_if_roam_frame_event_handler - Target IF API to receive + * Beacon/probe for the roaming candidate. + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int +target_if_roam_frame_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len); +#else /* WLAN_FEATURE_ROAM_OFFLOAD */ +static inline +QDF_STATUS +target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline int +target_if_cm_roam_vdev_disconnect_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + return 0; +} + +static inline int +target_if_cm_roam_scan_chan_list_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + return 0; +} + +static inline int +target_if_pmkid_request_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + return 0; +} + +static inline int +target_if_roam_frame_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * target_if_get_roam_vendor_control_param_event_handler - event handler for + * vendor control params event + * @scn: target handle + * @event: event buffer + * @len: event buffer length + * + * Return: int for success or error code + */ +int target_if_get_roam_vendor_control_param_event_handler(ol_scn_t scn, + uint8_t *event, + uint32_t len); +#else +static inline int +target_if_get_roam_vendor_control_param_event_handler(ol_scn_t scn, + uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h new file mode 100644 index 0000000000..7ccf40680b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/inc/target_if_cm_roam_offload.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for target_if roaming offload. + */ + +#ifndef TARGET_IF_CM_ROAM_OFFLOAD_H__ +#define TARGET_IF_CM_ROAM_OFFLOAD_H__ + +#include "wlan_cm_roam_public_struct.h" + +/** + * target_if_cm_roam_register_tx_ops - Target IF API to register roam + * related tx op. + * @tx_ops: Pointer to tx ops fp struct + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_cm_roam_register_tx_ops(struct wlan_cm_roam_tx_ops *tx_ops); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * target_if_stop_rso_stop_timer() - Stop the RSO_STOP timer + * @roam_event: Roam event data + * + * This stops the RSO stop timer in below cases, + * 1. If the reason is RSO_STATUS and notif is CM_ROAM_NOTIF_SCAN_MODE_SUCCESS + * 2. If wait started already and received HO_FAIL event + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_stop_rso_stop_timer(struct roam_offload_roam_event *roam_event); +#else +static inline QDF_STATUS +target_if_stop_rso_stop_timer(struct roam_offload_roam_event *roam_event) +{ + roam_event->rso_timer_stopped = false; + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * target_if_cm_send_rso_stop_failure_rsp() - Send RSO_STOP failure rsp to CM + * @psoc: psoc object + * @vdev_id: vdev_id on which RSO stop is issued + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_cm_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#else +static inline QDF_STATUS +target_if_cm_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/src/target_if_cm_roam_event.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/src/target_if_cm_roam_event.c new file mode 100644 index 0000000000..34d0a2bfdd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/src/target_if_cm_roam_event.c @@ -0,0 +1,1007 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for target_if roaming events. + */ +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wmi_unified_api.h" +#include "scheduler_api.h" +#include +#include "target_if_cm_roam_event.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_mlme_main.h" +#include <../../core/src/wlan_cm_roam_i.h> +#include "wlan_cm_roam_api.h" +#include "target_if_cm_roam_offload.h" +#include +#include +#include "wlan_mlo_mgr_peer.h" +#include "wlan_crypto_global_api.h" + +struct wlan_cm_roam_rx_ops * +target_if_cm_get_roam_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *psoc_ext_priv; + struct wlan_cm_roam_rx_ops *rx_ops; + + if (!psoc) { + target_if_err("psoc object is NULL"); + return NULL; + } + psoc_ext_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!psoc_ext_priv) { + target_if_err("psoc legacy private object is NULL"); + return NULL; + } + + rx_ops = &psoc_ext_priv->rso_rx_ops; + return rx_ops; +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +static void target_if_cm_roam_register_vendor_handoff_rx_ops( + struct wlan_cm_roam_rx_ops *rx_ops) +{ + rx_ops->roam_vendor_handoff_event = + cm_roam_vendor_handoff_event_handler; +} +#else +static inline void +target_if_cm_roam_register_vendor_handoff_rx_ops( + struct wlan_cm_roam_rx_ops *rx_ops) +{ +} +#endif + +void +target_if_cm_roam_register_rx_ops(struct wlan_cm_roam_rx_ops *rx_ops) +{ + rx_ops->roam_sync_event = cm_roam_sync_event_handler; + rx_ops->roam_sync_frame_event = cm_roam_sync_frame_event_handler; + rx_ops->roam_sync_key_event = cm_roam_sync_key_event_handler; + rx_ops->roam_event_rx = cm_roam_event_handler; + rx_ops->btm_denylist_event = cm_btm_denylist_event_handler; + rx_ops->vdev_disconnect_event = cm_vdev_disconnect_event_handler; + rx_ops->roam_scan_chan_list_event = cm_roam_scan_ch_list_event_handler; + rx_ops->roam_stats_event_rx = cm_roam_stats_event_handler; + rx_ops->roam_auth_offload_event = cm_roam_auth_offload_event_handler; + rx_ops->roam_pmkid_request_event_rx = cm_roam_pmkid_request_handler; + rx_ops->roam_candidate_frame_event = cm_roam_candidate_event_handler; + target_if_cm_roam_register_vendor_handoff_rx_ops(rx_ops); +} + +int target_if_cm_roam_event(ol_scn_t scn, uint8_t *event, uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct roam_offload_roam_event *roam_event = NULL; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + roam_event = qdf_mem_malloc(sizeof(*roam_event)); + if (!roam_event) + return -ENOMEM; + + qdf_status = wmi_extract_roam_event(wmi_handle, event, len, roam_event); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + qdf_status = QDF_STATUS_E_INVAL; + goto done; + } + + roam_event->psoc = psoc; + + /** + * Stop the timer upon RSO stop status success. The timer shall continue + * to run upon HO_FAIL status and would be stopped upon HO_FAILED event + */ + if ((roam_event->reason == ROAM_REASON_RSO_STATUS && + roam_event->notif_params == WMI_ROAM_SCAN_MODE_NONE) || + roam_event->reason == ROAM_REASON_HO_FAILED) + target_if_stop_rso_stop_timer(roam_event); + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_event_rx) { + target_if_err("No valid roam rx ops"); + qdf_status = QDF_STATUS_E_INVAL; + goto done; + } + + /** + * This can be called from IRQ context for WOW events such as + * WOW_REASON_LOW_RSSI and WOW_REASON_HO_FAIL. There is no issue + * currently, as these events are posted to schedular thread from + * cm_roam_event_handler, to access umac which use mutex. + * If any new ROAM event is added in IRQ context in future, avoid taking + * mutex. If mutex/sleep is needed, post a message to scheduler thread. + */ + qdf_status = roam_rx_ops->roam_event_rx(roam_event); + +done: + qdf_mem_free(roam_event); + return qdf_status_to_os_return(qdf_status); +} + +QDF_STATUS +target_if_roam_register_common_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Register for LFR2/3 common roam event */ + ret = wmi_unified_register_event_handler(handle, wmi_roam_event_id, + target_if_cm_roam_event, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void +target_if_free_roam_synch_frame_ind(struct roam_synch_frame_ind *frame_ind) +{ + if (frame_ind->bcn_probe_rsp) { + qdf_mem_free(frame_ind->bcn_probe_rsp); + frame_ind->bcn_probe_rsp_len = 0; + frame_ind->bcn_probe_rsp = NULL; + } + if (frame_ind->link_bcn_probe_rsp) { + qdf_mem_free(frame_ind->link_bcn_probe_rsp); + frame_ind->link_bcn_probe_rsp_len = 0; + frame_ind->link_bcn_probe_rsp = NULL; + } + if (frame_ind->reassoc_req) { + qdf_mem_free(frame_ind->reassoc_req); + frame_ind->reassoc_req_len = 0; + frame_ind->reassoc_req = NULL; + } + if (frame_ind->reassoc_rsp) { + qdf_mem_free(frame_ind->reassoc_rsp); + frame_ind->reassoc_rsp_len = 0; + frame_ind->reassoc_rsp = NULL; + } + + qdf_mem_free(frame_ind); +} + +int +target_if_cm_roam_sync_frame_event(ol_scn_t scn, + uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct roam_synch_frame_ind *frame_ind_ptr; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + int status = 0; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + frame_ind_ptr = qdf_mem_malloc(sizeof(*frame_ind_ptr)); + if (!frame_ind_ptr) + return -ENOMEM; + + qdf_status = wmi_extract_roam_sync_frame_event(wmi_handle, event, + len, + frame_ind_ptr); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + status = -EINVAL; + goto err; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + + if (!roam_rx_ops || !roam_rx_ops->roam_sync_frame_event) { + target_if_err("No valid roam rx ops"); + status = -EINVAL; + goto err; + } + + qdf_status = roam_rx_ops->roam_sync_frame_event(psoc, + frame_ind_ptr); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + status = -EINVAL; + goto err; + } + qdf_mem_free(frame_ind_ptr); + + return 0; + +err: + target_if_free_roam_synch_frame_ind(frame_ind_ptr); + + return status; +} + +int target_if_cm_roam_sync_event(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + struct roam_offload_synch_ind *sync_ind = NULL; + int status = 0; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + target_if_prevent_pm_during_roam_sync(psoc); + + qdf_status = wmi_extract_roam_sync_event(wmi_handle, event, + len, &sync_ind); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + status = -EINVAL; + goto err; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + + if (!roam_rx_ops || !roam_rx_ops->roam_sync_event) { + target_if_err("No valid roam rx ops"); + status = -EINVAL; + goto err; + } + + qdf_status = roam_rx_ops->roam_sync_event(psoc, + event, + len, + sync_ind); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + status = -EINVAL; + +err: + if (status == -EINVAL) + target_if_allow_pm_after_roam_sync(psoc); + + if (sync_ind && sync_ind->ric_tspec_data) + qdf_mem_free(sync_ind->ric_tspec_data); + if (sync_ind) + qdf_mem_free(sync_ind); + return status; +} + +static int +target_if_cm_btm_denylist_event(ol_scn_t scn, uint8_t *event, uint32_t len) +{ + QDF_STATUS qdf_status; + int status = 0; + struct roam_denylist_event *dst_list = NULL; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_btm_denylist_event(wmi_handle, event, len, + &dst_list); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + + if (!dst_list) { + /* No APs to denylist, just return */ + target_if_err_rl("No APs in denylist received"); + return 0; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->btm_denylist_event) { + target_if_err("No valid roam rx ops"); + status = -EINVAL; + goto done; + } + qdf_status = roam_rx_ops->btm_denylist_event(psoc, dst_list); + if (QDF_IS_STATUS_ERROR(qdf_status)) + status = -EINVAL; + +done: + qdf_mem_free(dst_list); + return status; +} + +int +target_if_cm_roam_vdev_disconnect_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct vdev_disconnect_event_data *data; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return -ENOMEM; + qdf_status = wmi_extract_vdev_disconnect_event(wmi_handle, event, len, + data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + goto done; + } + + data->psoc = psoc; + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->vdev_disconnect_event) { + target_if_err("No valid roam rx ops"); + qdf_status = QDF_STATUS_E_INVAL; + goto done; + } + + /** + * This can be called from IRQ context for WOW events. There is no + * issue currently as this event is posted to scheduler thread from + * wma_handle_disconnect_reason(). Avoid acquiring mutex/sleep in this + * context in future and post a message to scheduler thread if needed. + */ + qdf_status = roam_rx_ops->vdev_disconnect_event(data); + +done: + qdf_mem_free(data); + return qdf_status_to_os_return(qdf_status); +} + +int +target_if_cm_roam_scan_chan_list_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + int status = 0; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + struct cm_roam_scan_ch_resp *data = NULL; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_roam_scan_chan_list(wmi_handle, event, len, + &data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_scan_chan_list_event) { + target_if_err("No valid roam rx ops"); + qdf_mem_free(data); + return -EINVAL; + } + qdf_status = roam_rx_ops->roam_scan_chan_list_event(data); + if (QDF_IS_STATUS_ERROR(qdf_status)) + status = -EINVAL; + + return status; +} + +int +target_if_cm_roam_stats_event(ol_scn_t scn, uint8_t *event, uint32_t len) +{ + QDF_STATUS qdf_status; + int status = 0; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + struct roam_stats_event *stats_info = NULL; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_roam_stats_event(wmi_handle, event, len, + &stats_info); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_stats_event_rx) { + target_if_err("No valid roam rx ops"); + status = -EINVAL; + if (stats_info) { + if (stats_info->roam_msg_info) + qdf_mem_free(stats_info->roam_msg_info); + qdf_mem_free(stats_info); + } + goto err; + } + + qdf_status = roam_rx_ops->roam_stats_event_rx(psoc, stats_info); + if (QDF_IS_STATUS_ERROR(qdf_status)) + status = -EINVAL; + +err: + return status; +} + +int +target_if_cm_roam_auth_offload_event(ol_scn_t scn, uint8_t *event, uint32_t len) +{ + QDF_STATUS qdf_status; + int status = 0; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + struct auth_offload_event auth_event = {0}; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_auth_offload_event(wmi_handle, event, len, + &auth_event); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_auth_offload_event) { + target_if_err("No valid roam rx ops"); + return -EINVAL; + } + qdf_status = roam_rx_ops->roam_auth_offload_event(&auth_event); + if (QDF_IS_STATUS_ERROR(status)) + status = -EINVAL; + + return status; +} + +int +target_if_pmkid_request_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct roam_pmkid_req_event *data = NULL; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_roam_pmkid_request(wmi_handle, event, len, + &data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + goto done; + } + + data->psoc = psoc; + + roam_rx_ops = target_if_cm_get_roam_rx_ops(data->psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_pmkid_request_event_rx) { + target_if_err("No valid roam rx ops"); + qdf_status = QDF_STATUS_E_INVAL; + goto done; + } + + /** + * This can be called from IRQ context for WOW events. There is no + * issue currently as this event doesn't take any mutex. + * If there is a mutex/sleep is needed in future, post a message to + * scheduler thread. + */ + qdf_status = roam_rx_ops->roam_pmkid_request_event_rx(data); + +done: + if (data) + qdf_mem_free(data); + return qdf_status_to_os_return(qdf_status); +} + +int +target_if_roam_frame_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct roam_scan_candidate_frame frame = {0}; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + QDF_STATUS qdf_status; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_roam_candidate_frame_event(wmi_handle, event, + len, &frame); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_candidate_frame_event) { + target_if_err("No valid roam rx ops"); + return -EINVAL; + } + + qdf_status = roam_rx_ops->roam_candidate_frame_event(psoc, + &frame); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return -EINVAL; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +int target_if_get_roam_vendor_control_param_event_handler(ol_scn_t scn, + uint8_t *event, + uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct roam_vendor_handoff_params *vendor_handoff_params = NULL; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + QDF_STATUS qdf_status; + int ret = 0; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + qdf_status = wmi_extract_roam_vendor_control_param_event(wmi_handle, + event, len, + &vendor_handoff_params); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + ret = -EINVAL; + goto done; + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_vendor_handoff_event) { + target_if_err("No valid roam rx ops"); + ret = -EINVAL; + goto done; + } + + roam_rx_ops->roam_vendor_handoff_event(psoc, vendor_handoff_params); + +done: + if (vendor_handoff_params) + qdf_mem_free(vendor_handoff_params); + + return ret; +} + +static QDF_STATUS +target_if_register_roam_vendor_control_param_event(wmi_unified_t handle) +{ + QDF_STATUS ret; + + ret = wmi_unified_register_event_handler(handle, + wmi_get_roam_vendor_control_param_event_id, + target_if_get_roam_vendor_control_param_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_get_roam_vendor_control_param_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +target_if_register_roam_vendor_control_param_event(wmi_unified_t handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +static void +target_if_update_pairwise_key_peer_mac(struct wlan_crypto_key_entry *crypto_entry, + struct qdf_mac_addr *ap_link_addr) +{ + uint8_t i; + + if (crypto_entry->link_id == MLO_INVALID_LINK_IDX) + return; + + for (i = 0; i < WLAN_CRYPTO_MAX_VLANKEYIX; i++) { + if (!crypto_entry->keys.key[i]) + continue; + + if (crypto_entry->keys.key[i]->key_type == + WLAN_CRYPTO_KEY_TYPE_UNICAST) + qdf_copy_macaddr((struct qdf_mac_addr *)crypto_entry->keys.key[i]->macaddr, + ap_link_addr); + } +} + +static int +target_if_roam_synch_key_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_cm_roam_rx_ops *roam_rx_ops; + struct wlan_crypto_key_entry *keys; + struct qdf_mac_addr mld_addr; + struct wlan_mlo_dev_context *ml_ctx = NULL; + struct wlan_objmgr_vdev *vdev_list; + struct mlo_link_info *link_info; + uint8_t num_keys = 0; + int ret = 0; + QDF_STATUS status; + uint8_t i, j; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_roam_synch_key_event(wmi_handle, event, len, &keys, + &num_keys, &mld_addr); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of roam sync key event failed"); + ret = -EINVAL; + goto done; + } + + wlan_mlo_get_mlpeer_by_peer_mladdr(&mld_addr, &ml_ctx); + if (!ml_ctx) { + target_if_err("ML context is not found mld addr: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mld_addr.bytes)); + ret = -EINVAL; + goto done; + } + + target_if_debug("num_keys:%d ML context is found mld addr: " + QDF_MAC_ADDR_FMT, num_keys, + QDF_MAC_ADDR_REF(mld_addr.bytes)); + + /* + * Fill VDEV ID & AP mac address for the pairwise keys + * from link id received in the key event + */ + for (i = 0; i < num_keys; i++) { + keys[i].vdev_id = WLAN_INVALID_VDEV_ID; + for (j = 0; j < WLAN_UMAC_MLO_MAX_VDEVS; j++) { + vdev_list = ml_ctx->wlan_vdev_list[j]; + if (!vdev_list) + continue; + + if (keys[i].link_id == + wlan_vdev_get_link_id(vdev_list)) { + keys[i].vdev_id = wlan_vdev_get_id(vdev_list); + qdf_copy_macaddr((struct qdf_mac_addr *)keys[i].mac_addr.raw, + (struct qdf_mac_addr *)vdev_list->vdev_mlme.linkaddr); + link_info = mlo_mgr_get_ap_link_by_link_id( + vdev_list->mlo_dev_ctx, + keys[i].link_id); + if (!link_info) { + target_if_err("Link info not found for link_id:%d", + keys[i].link_id); + break; + } + target_if_debug("i:%d link_id:%d vdev_id:%d self link_addr: " QDF_MAC_ADDR_FMT " AP link addr: " QDF_MAC_ADDR_FMT, + i, keys[i].link_id, keys[i].vdev_id, + QDF_MAC_ADDR_REF(keys[i].mac_addr.raw), + QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); + + target_if_update_pairwise_key_peer_mac(&keys[i], &link_info->ap_link_addr); + break; + } + } + + /* update for standby vdev also here from link_switch context*/ + if (keys[i].vdev_id == WLAN_INVALID_VDEV_ID && + keys[i].link_id != MLO_INVALID_LINK_IDX && + ml_ctx->link_ctx) { + for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) { + link_info = &ml_ctx->link_ctx->links_info[j]; + if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) + continue; + + if (qdf_is_macaddr_zero(&link_info->link_addr)) + continue; + + if (link_info->link_id == keys[i].link_id) { + target_if_debug("i:%d Standby vdev: link_id:%d ap_link_addr: " QDF_MAC_ADDR_FMT, + i, keys[i].link_id, + QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); + qdf_copy_macaddr((struct qdf_mac_addr *)keys[i].mac_addr.raw, + &link_info->link_addr); + target_if_update_pairwise_key_peer_mac(&keys[i], + &link_info->ap_link_addr); + } + } + } + } + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_sync_key_event) { + target_if_err("No valid roam rx ops"); + ret = -EINVAL; + goto done; + } + + status = roam_rx_ops->roam_sync_key_event(psoc, keys, num_keys); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Add keys failed"); + ret = 0; + } +done: + qdf_mem_zero(keys, WLAN_MAX_ML_BSS_LINKS * sizeof(*keys)); + qdf_mem_free(keys); + + return ret; +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +static void target_if_register_mlo_roam_events(wmi_unified_t handle) +{ + QDF_STATUS status; + + status = wmi_unified_register_event_handler( + handle, + wmi_roam_synch_key_event_id, + target_if_roam_synch_key_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("wmi event(%u) registration failed, status: %d", + wmi_roam_synch_key_event_id, status); +} +#else +static inline void target_if_register_mlo_roam_events(wmi_unified_t handle) +{} +#endif + +QDF_STATUS +target_if_roam_offload_register_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Register for roam offload event */ + ret = wmi_unified_register_event_handler(handle, + wmi_roam_synch_event_id, + target_if_cm_roam_sync_event, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + /* Register for roam offload event */ + ret = wmi_unified_register_event_handler(handle, + wmi_roam_synch_frame_event_id, + target_if_cm_roam_sync_frame_event, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_roam_denylist_event_id, + target_if_cm_btm_denylist_event, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_roam_denylist_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_vdev_disconnect_event_id, + target_if_cm_roam_vdev_disconnect_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_vdev_disconnect_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_roam_scan_chan_list_id, + target_if_cm_roam_scan_chan_list_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_roam_scan_chan_list_id, ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_roam_stats_event_id, + target_if_cm_roam_stats_event, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_roam_auth_offload_event_id, + target_if_cm_roam_auth_offload_event, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_roam_auth_offload_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_roam_pmkid_request_event_id, + target_if_pmkid_request_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_roam_stats_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + + target_if_register_roam_vendor_control_param_event(handle); + + ret = wmi_unified_register_event_handler(handle, + wmi_roam_frame_event_id, + target_if_roam_frame_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event(%u) registration failed, ret: %d", + wmi_roam_frame_event_id, ret); + return QDF_STATUS_E_FAILURE; + } + + target_if_register_mlo_roam_events(handle); + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c new file mode 100644 index 0000000000..84bb6819b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/connection_mgr/src/target_if_cm_roam_offload.c @@ -0,0 +1,2349 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for target_if roaming offload. + */ + +#include "qdf_types.h" +#include "target_if_cm_roam_offload.h" +#include "target_if.h" +#include "wmi_unified_sta_api.h" +#include "wlan_mlme_dbg.h" +#include "wlan_mlme_api.h" +#include "wlan_crypto_global_api.h" +#include "wlan_mlme_main.h" +#include "wlan_cm_roam_api.h" +#include +#include +#include "target_if_cm_roam_event.h" +#include +#include "wlan_psoc_mlme_api.h" + +static struct wmi_unified +*target_if_cm_roam_get_wmi_handle_from_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + struct wmi_unified *wmi_handle; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + target_if_err("PDEV is NULL"); + return NULL; + } + + wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return NULL; + } + + return wmi_handle; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * target_if_cm_roam_send_vdev_set_pcl_cmd - Send set vdev pcl + * command to wmi. + * @vdev: VDEV object pointer + * @req: Pointer to the pcl request msg + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_vdev_set_pcl_cmd(struct wlan_objmgr_vdev *vdev, + struct set_pcl_req *req) +{ + wmi_unified_t wmi_handle; + struct set_pcl_cmd_params params; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + params.weights = &req->chan_weights; + params.vdev_id = req->vdev_id; + + return wmi_unified_vdev_set_pcl_cmd(wmi_handle, ¶ms); +} + +/** + * target_if_cm_roam_send_roam_invoke_cmd - Send roam invoke command to wmi. + * @vdev: VDEV object pointer + * @req: Pointer to the roam invoke request msg + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_roam_invoke_cmd(struct wlan_objmgr_vdev *vdev, + struct roam_invoke_req *req) +{ + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_roam_invoke_cmd(wmi_handle, req); +} + +/** + * target_if_cm_roam_send_roam_sync_complete - Send roam sync complete to wmi. + * @vdev: VDEV object pointer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_roam_sync_complete(struct wlan_objmgr_vdev *vdev) +{ + wmi_unified_t wmi_handle; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + status = wmi_unified_roam_synch_complete_cmd(wmi_handle, + wlan_vdev_get_id(vdev)); + target_if_allow_pm_after_roam_sync(psoc); + + return status; +} + +/** + * target_if_roam_set_param() - set roam params in fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param_id: parameter id + * @param_value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +target_if_roam_set_param(wmi_unified_t wmi_handle, uint8_t vdev_id, + uint32_t param_id, uint32_t param_value) +{ + struct vdev_set_params roam_param = {0}; + + roam_param.vdev_id = vdev_id; + roam_param.param_id = param_id; + roam_param.param_value = param_value; + + return wmi_unified_roam_set_param_send(wmi_handle, &roam_param); +} + +/** + * target_if_cm_roam_rt_stats_config() - Send enable/disable roam event stats + * commands to wmi + * @vdev: vdev object + * @vdev_id: vdev id + * @rstats_config: roam event stats config parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_rt_stats_config(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint8_t rstats_config) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + status = target_if_roam_set_param(wmi_handle, + vdev_id, + WMI_ROAM_PARAM_ROAM_EVENTS_CONFIG, + rstats_config); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set " + "WMI_ROAM_PARAM_ROAM_EVENTS_CONFIG"); + + return status; +} + +/** + * target_if_cm_roam_mcc_disallow() - Send enable/disable roam mcc disallow + * commands to wmi + * @vdev: vdev object + * @vdev_id: vdev id + * @is_mcc_disallowed: is mcc disallowed + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_mcc_disallow(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint8_t is_mcc_disallowed) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + status = target_if_roam_set_param(wmi_handle, + vdev_id, + WMI_ROAM_PARAM_ROAM_MCC_DISALLOW, + is_mcc_disallowed); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set roam mcc disallow"); + + return status; +} + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * target_if_cm_roam_linkspeed_state() - Send link speed state for roaming + * commands to wmi + * @vdev: vdev object + * @vdev_id: vdev id + * @is_linkspeed_good: true, don't need low rssi roaming + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_linkspeed_state(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, bool is_linkspeed_good) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + status = target_if_roam_set_param(wmi_handle, + vdev_id, + WMI_ROAM_PARAM_LINKSPEED_STATE, + is_linkspeed_good); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set WMI_ROAM_PARAM_LINKSPEED_STATE"); + + return status; +} +#else +static inline QDF_STATUS +target_if_cm_roam_linkspeed_state(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, bool is_linkspeed_good) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * target_if_cm_roam_vendor_handoff_config() - Send vendor handoff config + * command to fw + * @vdev: vdev object + * @vdev_id: vdev id + * @param_id: param id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_vendor_handoff_config(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint32_t param_id) +{ + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_roam_vendor_handoff_req_cmd(wmi_handle, + vdev_id, param_id); +} + +/** + * target_if_cm_roam_register_vendor_handoff_ops() - Register tx ops to send + * vendor handoff config command to fw + * @tx_ops: structure of tx function pointers for roaming related commands + * + * Return: none + */ +static void target_if_cm_roam_register_vendor_handoff_ops( + struct wlan_cm_roam_tx_ops *tx_ops) +{ + tx_ops->send_roam_vendor_handoff_config = + target_if_cm_roam_vendor_handoff_config; +} +#else +static inline void target_if_cm_roam_register_vendor_handoff_ops( + struct wlan_cm_roam_tx_ops *tx_ops) +{ +} +#endif + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * target_if_cm_roam_register_linkspeed_state() - Register tx ops to send + * roam link speed state command to fw + * @tx_ops: structure of tx function pointers for roaming related commands + * + * Return: none + */ +static inline void +target_if_cm_roam_register_linkspeed_state(struct wlan_cm_roam_tx_ops *tx_ops) +{ + tx_ops->send_roam_linkspeed_state = + target_if_cm_roam_linkspeed_state; +} +#else +static inline void +target_if_cm_roam_register_linkspeed_state(struct wlan_cm_roam_tx_ops *tx_ops) +{ +} +#endif + +/** + * target_if_cm_roam_ho_delay_config() - Send roam HO delay value to wmi + * @vdev: vdev object + * @vdev_id: vdev id + * @roam_ho_delay: roam hand-off delay value + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_ho_delay_config(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint16_t roam_ho_delay) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + status = target_if_roam_set_param( + wmi_handle, + vdev_id, + WMI_ROAM_PARAM_ROAM_HO_DELAY_RUNTIME_CONFIG, + roam_ho_delay); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set " + "WMI_ROAM_PARAM_ROAM_HO_DELAY_RUNTIME_CONFIG"); + + return status; +} + +/** + * target_if_cm_exclude_rm_partial_scan_freq() - Indicate to FW whether to + * exclude the channels in roam full scan that are already scanned as part of + * partial scan or not. + * @vdev: vdev object + * @exclude_rm_partial_scan_freq: Include/exclude the channels in roam full scan + * that are already scanned as part of partial scan. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_vdev *vdev, + uint8_t exclude_rm_partial_scan_freq) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t vdev_id; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + vdev_id = wlan_vdev_get_id(vdev); + status = target_if_roam_set_param( + wmi_handle, vdev_id, + WMI_ROAM_PARAM_ROAM_CONTROL_FULL_SCAN_CHANNEL_OPTIMIZATION, + exclude_rm_partial_scan_freq); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set WMI_ROAM_PARAM_ROAM_CONTROL_FULL_SCAN_CHANNEL_OPTIMIZATION"); + + return status; +} + +/** + * target_if_cm_roam_full_scan_6ghz_on_disc() - Indicate to FW whether to + * include the 6 GHz channels in roam full scan only on prior discovery of any + * 6 GHz support in the environment or by default. + * @vdev: vdev object + * @roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full scan: + * 1 - Include only on prior discovery of any 6 GHz support in the environment + * 0 - Include all the supported 6 GHz channels by default + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_vdev *vdev, + uint8_t roam_full_scan_6ghz_on_disc) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t vdev_id; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + vdev_id = wlan_vdev_get_id(vdev); + status = target_if_roam_set_param(wmi_handle, vdev_id, + WMI_ROAM_PARAM_ROAM_CONTROL_FULL_SCAN_6GHZ_PSC_ONLY_WITH_RNR, + roam_full_scan_6ghz_on_disc); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set WMI_ROAM_PARAM_ROAM_CONTROL_FULL_SCAN_6GHZ_PSC_ONLY_WITH_RNR"); + + return status; +} + +/** + * target_if_cm_roam_rssi_diff_6ghz() - Send the roam RSSI diff value to FW + * which is used to decide how better the RSSI of the new/roamable 6GHz AP + * should be for roaming. + * @vdev: vdev object + * @roam_rssi_diff_6ghz: RSSI diff value to be used for roaming to 6 GHz AP + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_rssi_diff_6ghz(struct wlan_objmgr_vdev *vdev, + uint8_t roam_rssi_diff_6ghz) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t vdev_id; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + vdev_id = wlan_vdev_get_id(vdev); + status = target_if_roam_set_param( + wmi_handle, vdev_id, + WMI_ROAM_PARAM_ROAM_RSSI_BOOST_FOR_6GHZ_CAND_AP, + roam_rssi_diff_6ghz); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set WMI_ROAM_PARAM_ROAM_RSSI_BOOST_FOR_6GHZ_CAND_AP"); + + return status; +} + +static QDF_STATUS +target_if_cm_roam_scan_offload_rssi_thresh( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *req); + +/** + * target_if_cm_roam_scan_offload_rssi_params() - Set the RSSI parameters + * for roam offload scan + * @vdev: vdev object + * @roam_rssi_params: structure containing parameters for roam offload scan + * based on RSSI + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_scan_offload_rssi_params( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + status = target_if_cm_roam_scan_offload_rssi_thresh(wmi_handle, + roam_rssi_params); + + return status; +} + +static void +target_if_check_hi_rssi_5ghz_support( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params) +{ + if ((roam_rssi_params->flags & + ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G) && + wmi_service_enabled(wmi_handle, + wmi_service_5ghz_hi_rssi_roam_support)) { + target_if_debug("FW supports Hi RSSI roam in 5 GHz"); + roam_rssi_params->flags |= + WMI_ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G; + } else { + roam_rssi_params->flags &= + ~ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G; + } +} + +static void +target_if_cm_roam_register_lfr3_ops(struct wlan_cm_roam_tx_ops *tx_ops) +{ + tx_ops->send_vdev_set_pcl_cmd = target_if_cm_roam_send_vdev_set_pcl_cmd; + tx_ops->send_roam_invoke_cmd = target_if_cm_roam_send_roam_invoke_cmd; + tx_ops->send_roam_sync_complete_cmd = target_if_cm_roam_send_roam_sync_complete; + tx_ops->send_roam_rt_stats_config = target_if_cm_roam_rt_stats_config; + tx_ops->send_roam_ho_delay_config = target_if_cm_roam_ho_delay_config; + tx_ops->send_roam_mcc_disallow = target_if_cm_roam_mcc_disallow; + tx_ops->send_exclude_rm_partial_scan_freq = + target_if_cm_exclude_rm_partial_scan_freq; + tx_ops->send_roam_full_scan_6ghz_on_disc = + target_if_cm_roam_full_scan_6ghz_on_disc; + tx_ops->send_roam_scan_offload_rssi_params = + target_if_cm_roam_scan_offload_rssi_params; + target_if_cm_roam_register_vendor_handoff_ops(tx_ops); + target_if_cm_roam_register_linkspeed_state(tx_ops); +} +#else +static inline void +target_if_cm_roam_register_lfr3_ops(struct wlan_cm_roam_tx_ops *tx_ops) +{} + +static QDF_STATUS +target_if_cm_roam_rt_stats_config(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint8_t rstats_config) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static QDF_STATUS +target_if_cm_roam_ho_delay_config(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint16_t roam_ho_delay) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static QDF_STATUS +target_if_cm_roam_mcc_disallow(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint8_t is_mcc_disallowed) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static QDF_STATUS +target_if_cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_vdev *vdev, + uint8_t exclude_rm_partial_scan_freq) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static QDF_STATUS +target_if_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_vdev *vdev, + uint8_t roam_full_scan_6ghz_on_disc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static QDF_STATUS +target_if_cm_roam_rssi_diff_6ghz(struct wlan_objmgr_vdev *vdev, + uint8_t roam_rssi_diff_6ghz) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +target_if_check_hi_rssi_5ghz_support( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params) +{} +#endif + +/** + * target_if_vdev_set_param() - set per vdev params in fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param_id: parameter id + * @param_value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +target_if_vdev_set_param(wmi_unified_t wmi_handle, uint32_t vdev_id, + uint32_t param_id, uint32_t param_value) +{ + struct vdev_set_params param = {0}; + + if (!target_if_is_vdev_valid(vdev_id)) { + target_if_err("vdev_id: %d is invalid, reject the req: param id %d val %d", + vdev_id, param_id, param_value); + return QDF_STATUS_E_INVAL; + } + + param.vdev_id = vdev_id; + param.param_id = param_id; + param.param_value = param_value; + + return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); +} + +static QDF_STATUS target_if_cm_roam_scan_offload_mode( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_offload_params *rso_mode_cfg) +{ + return wmi_unified_roam_scan_offload_mode_cmd(wmi_handle, + rso_mode_cfg); +} + +static +QDF_STATUS target_if_check_index_setparam(struct dev_set_param *param, + uint32_t paramid, + uint32_t paramvalue, + uint8_t index, uint8_t n_params) +{ + if (index >= n_params) { + target_if_err("Index:%d OOB to fill param", index); + return QDF_STATUS_E_FAILURE; + } + param[index].param_id = paramid; + param[index].param_value = paramvalue; + return QDF_STATUS_SUCCESS; +} + +#define MAX_PARAMS_CM_ROAM_SCAN_BMISS 2 +/* + * params being sent: + * wmi_vdev_param_bmiss_first_bcnt + * wmi_vdev_param_bmiss_final_bcnt + */ + +/** + * target_if_cm_roam_scan_bmiss_cnt() - set bmiss count to fw + * @wmi_handle: wmi handle + * @req: bmiss count parameters + * + * Set first & final bmiss count to fw. + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_bmiss_cnt(wmi_unified_t wmi_handle, + struct wlan_roam_beacon_miss_cnt *req) +{ + QDF_STATUS status; + struct dev_set_param setparam[MAX_PARAMS_CM_ROAM_SCAN_BMISS]; + struct set_multiple_pdev_vdev_param params = {}; + uint8_t index = 0; + + target_if_debug("vdev_id:%d, first_bcnt: %d, final_bcnt: %d", + req->vdev_id, req->roam_bmiss_first_bcnt, + req->roam_bmiss_final_bcnt); + + status = target_if_check_index_setparam( + setparam, + wmi_vdev_param_bmiss_first_bcnt, + req->roam_bmiss_first_bcnt, + index++, + MAX_PARAMS_CM_ROAM_SCAN_BMISS); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + status = target_if_check_index_setparam( + setparam, + wmi_vdev_param_bmiss_final_bcnt, + req->roam_bmiss_final_bcnt, index++, + MAX_PARAMS_CM_ROAM_SCAN_BMISS); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + params.param_type = MLME_VDEV_SETPARAM; + params.dev_id = req->vdev_id; + params.n_params = index; + params.params = setparam; + + status = wmi_unified_multiple_vdev_param_send(wmi_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("failed to set bmiss first,final bcntset params"); + +error: + return status; +} + +#define MAX_PARAMS_CM_ROAM_SCAN_BMISS_TIMEOUT 2 +/* + * params being sent: + * wmi_vdev_param_bmiss_first_bcnt + * wmi_vdev_param_bmiss_final_bcnt + */ + +/** + * target_if_cm_roam_scan_bmiss_timeout() - set conbmiss timeout to fw + * @wmi_handle: wmi handle + * @req: bmiss timeout parameters + * + * Set bmiss timeout to fw. + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_bmiss_timeout(wmi_unified_t wmi_handle, + struct wlan_roam_bmiss_timeout *req) +{ + QDF_STATUS status; + uint32_t vdev_id; + uint8_t bmiss_timeout_onwakeup; + uint8_t bmiss_timeout_onsleep; + struct dev_set_param setparam[MAX_PARAMS_CM_ROAM_SCAN_BMISS_TIMEOUT]; + struct set_multiple_pdev_vdev_param params = {}; + uint8_t index = 0; + + vdev_id = req->vdev_id; + bmiss_timeout_onwakeup = req->bmiss_timeout_onwakeup; + bmiss_timeout_onsleep = req->bmiss_timeout_onsleep; + + target_if_debug("vdev_id %d bmiss_timeout_onwakeup: %dsec, bmiss_timeout_onsleep: %dsec", vdev_id, + bmiss_timeout_onwakeup, bmiss_timeout_onsleep); + status = target_if_check_index_setparam( + setparam, + wmi_vdev_param_final_bmiss_time_sec, + req->bmiss_timeout_onwakeup, index++, + MAX_PARAMS_CM_ROAM_SCAN_BMISS_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + status = target_if_check_index_setparam( + setparam, + wmi_vdev_param_final_bmiss_time_wow_sec, + req->bmiss_timeout_onsleep, index++, + MAX_PARAMS_CM_ROAM_SCAN_BMISS_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + params.param_type = MLME_VDEV_SETPARAM; + params.dev_id = req->vdev_id; + params.n_params = index; + params.params = setparam; + status = wmi_unified_multiple_vdev_param_send(wmi_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("failed to set bmiss first,final bcntset params"); + +error: + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * target_if_cm_roam_reason_vsie() - set vdev param + * wmi_vdev_param_enable_disable_roam_reason_vsie + * @wmi_handle: handle to WMI + * @req: roam reason vsie enable parameters + * + * Return: void + */ +static void +target_if_cm_roam_reason_vsie(wmi_unified_t wmi_handle, + struct wlan_roam_reason_vsie_enable *req) +{ + QDF_STATUS status; + + status = target_if_vdev_set_param( + wmi_handle, + req->vdev_id, + wmi_vdev_param_enable_disable_roam_reason_vsie, + req->enable_roam_reason_vsie); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set vdev param %d", + wmi_vdev_param_enable_disable_roam_reason_vsie); +} + +/** + * target_if_cm_roam_triggers() - send roam triggers to WMI + * @vdev: vdev + * @req: roam triggers parameters + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_triggers(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_triggers *req) +{ + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + if (!target_if_is_vdev_valid(req->vdev_id)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_set_roam_triggers(wmi_handle, req); +} + +/** + * target_if_cm_roam_scan_get_cckm_mode() - Get the CCKM auth mode + * @vdev: vdev object + * @auth_mode: Auth mode to be converted + * + * Based on LFR2.0 or LFR3.0, return the proper auth type + * + * Return: if LFR2.0, then return WMI_AUTH_CCKM for backward compatibility + * if LFR3.0 then return the appropriate auth type + */ +static uint32_t +target_if_cm_roam_scan_get_cckm_mode(struct wlan_objmgr_vdev *vdev, + uint32_t auth_mode) +{ + struct wlan_objmgr_psoc *psoc; + bool roam_offload_enable; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return WMI_AUTH_CCKM; + } + + wlan_mlme_get_roaming_offload(psoc, &roam_offload_enable); + if (roam_offload_enable) + return auth_mode; + else + return WMI_AUTH_CCKM; +} + +/* target_if_cm_roam_disconnect_params(): Send the disconnect roam parameters + * to wmi + * @wmi_handle: handle to WMI + * @command: rso command + * @req: disconnect roam parameters + * + * Return: void + */ +static void +target_if_cm_roam_disconnect_params(wmi_unified_t wmi_handle, uint8_t command, + struct wlan_roam_disconnect_params *req) +{ + QDF_STATUS status; + + switch (command) { + case ROAM_SCAN_OFFLOAD_START: + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + if (!req->enable) + return; + break; + case ROAM_SCAN_OFFLOAD_STOP: + req->enable = false; + break; + default: + break; + } + + status = wmi_unified_send_disconnect_roam_params(wmi_handle, req); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("failed to send disconnect roam parameters"); +} + +/* target_if_cm_roam_idle_params(): Send the roam idle parameters to wmi + * @wmi_handle: handle to WMI + * @command: rso command + * @req: roam idle parameters + * + * Return: void + */ +static void +target_if_cm_roam_idle_params(wmi_unified_t wmi_handle, uint8_t command, + struct wlan_roam_idle_params *req) +{ + QDF_STATUS status; + bool db2dbm_enabled; + + switch (command) { + case ROAM_SCAN_OFFLOAD_START: + case ROAM_SCAN_OFFLOAD_UPDATE_CFG: + break; + case ROAM_SCAN_OFFLOAD_STOP: + req->enable = false; + break; + default: + break; + } + + db2dbm_enabled = wmi_service_enabled(wmi_handle, + wmi_service_hw_db2dbm_support); + if (!db2dbm_enabled) { + req->conn_ap_min_rssi -= NOISE_FLOOR_DBM_DEFAULT; + req->conn_ap_min_rssi &= 0x000000ff; + } + + status = wmi_unified_send_idle_roam_params(wmi_handle, req); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("failed to send idle roam parameters"); +} +#else +static void +target_if_cm_roam_reason_vsie(wmi_unified_t wmi_handle, + struct wlan_roam_reason_vsie_enable *req) +{ +} + +static QDF_STATUS +target_if_cm_roam_triggers(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_triggers *req) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static uint32_t +target_if_cm_roam_scan_get_cckm_mode(struct wlan_objmgr_vdev *vdev, + uint32_t auth_mode) +{ + return WMI_AUTH_CCKM; +} + +static void +target_if_cm_roam_disconnect_params(wmi_unified_t wmi_handle, uint8_t command, + struct wlan_roam_disconnect_params *req) +{ +} + +static void +target_if_cm_roam_idle_params(wmi_unified_t wmi_handle, uint8_t command, + struct wlan_roam_idle_params *req) +{ +} +#endif + +/** + * target_if_cm_roam_scan_offload_rssi_thresh() - Send roam scan rssi threshold + * commands to wmi + * @wmi_handle: wmi handle + * @req: roam scan rssi threshold related parameters + * + * This function fills some parameters @req and send down roam scan rssi + * threshold command to wmi + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_scan_offload_rssi_thresh( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool db2dbm_enabled; + + db2dbm_enabled = wmi_service_enabled(wmi_handle, + wmi_service_hw_db2dbm_support); + if (!db2dbm_enabled) { + req->rssi_thresh -= NOISE_FLOOR_DBM_DEFAULT; + req->rssi_thresh &= 0x000000ff; + req->hi_rssi_scan_rssi_ub -= NOISE_FLOOR_DBM_DEFAULT; + req->bg_scan_bad_rssi_thresh -= NOISE_FLOOR_DBM_DEFAULT; + req->roam_data_rssi_threshold -= NOISE_FLOOR_DBM_DEFAULT; + req->good_rssi_threshold -= NOISE_FLOOR_DBM_DEFAULT; + req->good_rssi_threshold &= 0x000000ff; + } + + req->hi_rssi_scan_rssi_ub &= 0x000000ff; + /* + * The current Noise floor in firmware is -96dBm. Penalty/Boost + * threshold is applied on a weaker signal to make it even more weaker. + * So, there is a chance that the user may configure a very low + * Penalty/Boost threshold beyond the noise floor. If that is the case, + * then suppress the penalty/boost threshold to the noise floor. + */ + if (req->raise_rssi_thresh_5g < NOISE_FLOOR_DBM_DEFAULT) { + if (db2dbm_enabled) { + req->penalty_threshold_5g = RSSI_MIN_VALUE; + req->boost_threshold_5g = RSSI_MAX_VALUE; + } else { + req->penalty_threshold_5g = 0; + } + } else { + if (db2dbm_enabled) { + req->boost_threshold_5g = req->raise_rssi_thresh_5g; + } else { + req->boost_threshold_5g = + (req->raise_rssi_thresh_5g - + NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + } + } + + if (req->drop_rssi_thresh_5g < NOISE_FLOOR_DBM_DEFAULT) { + if (db2dbm_enabled) + req->penalty_threshold_5g = RSSI_MIN_VALUE; + else + req->penalty_threshold_5g = 0; + } else { + if (db2dbm_enabled) { + req->penalty_threshold_5g = req->drop_rssi_thresh_5g; + } else { + req->penalty_threshold_5g = + (req->drop_rssi_thresh_5g - + NOISE_FLOOR_DBM_DEFAULT) & 0x000000ff; + } + } + + if (req->early_stop_scan_enable) { + if (!db2dbm_enabled) { + req->roam_earlystop_thres_min -= + NOISE_FLOOR_DBM_DEFAULT; + req->roam_earlystop_thres_max -= + NOISE_FLOOR_DBM_DEFAULT; + } + } else { + if (db2dbm_enabled) { + req->roam_earlystop_thres_min = RSSI_MIN_VALUE; + req->roam_earlystop_thres_max = RSSI_MIN_VALUE; + } else { + req->roam_earlystop_thres_min = 0; + req->roam_earlystop_thres_max = 0; + } + } + + if (req->hi_rssi_scan_rssi_delta) + target_if_check_hi_rssi_5ghz_support(wmi_handle, req); + + target_if_debug("RSO_CFG: vdev %d: db2dbm enabled:%d, good_rssi_threshold:%d, early_stop_thresholds en:%d, min:%d, max:%d, roam_scan_rssi_thresh:%d, roam_rssi_thresh_diff:%d", + req->vdev_id, db2dbm_enabled, req->good_rssi_threshold, + req->early_stop_scan_enable, + req->roam_earlystop_thres_min, + req->roam_earlystop_thres_max, req->rssi_thresh, + req->rssi_thresh_diff); + target_if_debug("RSO_CFG: hirssi max cnt:%d, delta:%d, hirssi upper bound:%d, dense rssi thresh offset:%d, dense min aps cnt:%d, traffic_threshold:%d, dense_status:%d", + req->hi_rssi_scan_max_count, + req->hi_rssi_scan_rssi_delta, + req->hi_rssi_scan_rssi_ub, + req->dense_rssi_thresh_offset, + req->dense_min_aps_cnt, + req->traffic_threshold, + req->initial_dense_status); + target_if_debug("RSO_CFG: raise rssi threshold 5g:%d, drop rssi threshold 5g:%d, penalty threshold 5g:%d, boost threshold 5g:%d", + req->raise_rssi_thresh_5g, + req->drop_rssi_thresh_5g, + req->penalty_threshold_5g, + req->boost_threshold_5g); + target_if_debug("RSO_CFG: raise factor 5g:%d, drop factor 5g:%d, max raise rssi 5g:%d, max drop rssi 5g:%d, rssi threshold offset 5g:%d", + req->raise_factor_5g, + req->raise_factor_5g, + req->max_raise_rssi_5g, + req->max_drop_rssi_5g, + req->rssi_thresh_offset_5g); + target_if_debug("RSO_CFG: BG Scan Bad RSSI:%d, bitmap:0x%x Offset for 2G to 5G Roam:%d", + req->bg_scan_bad_rssi_thresh, + req->bg_scan_client_bitmap, + req->roam_bad_rssi_thresh_offset_2g); + target_if_debug("RSO_CFG: Roam data rssi triggers:0x%x, threshold:%d, rx time:%d", + req->roam_data_rssi_threshold_triggers, + req->roam_data_rssi_threshold, + req->rx_data_inactivity_time); + + status = wmi_unified_roam_scan_offload_rssi_thresh_cmd(wmi_handle, req); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("roam_scan_offload_rssi_thresh_cmd failed %d", + status); + return status; + } + + return status; +} + +/** + * target_if_cm_roam_scan_offload_scan_period() - set roam offload scan period + * @wmi_handle: wmi handle + * @req: roam scan period parameters + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_offload_scan_period( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_period_params *req) +{ + if (!target_if_is_vdev_valid(req->vdev_id)) { + target_if_err("Invalid vdev id:%d", req->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_roam_scan_offload_scan_period(wmi_handle, req); +} + +/** + * target_if_cm_roam_scan_offload_ap_profile() - send roam ap profile to + * firmware + * @vdev: vdev object + * @wmi_handle: wmi handle + * @req: roam ap profile parameters + * + * Send WMI_ROAM_AP_PROFILE parameters to firmware + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_offload_ap_profile( + struct wlan_objmgr_vdev *vdev, + wmi_unified_t wmi_handle, + struct ap_profile_params *req) +{ + uint32_t rsn_authmode; + bool db2dbm_enabled; + + if (!target_if_is_vdev_valid(req->vdev_id)) { + target_if_err("Invalid vdev id:%d", req->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + rsn_authmode = req->profile.rsn_authmode; + if (rsn_authmode == WMI_AUTH_CCKM_WPA || + rsn_authmode == WMI_AUTH_CCKM_RSNA) + req->profile.rsn_authmode = + target_if_cm_roam_scan_get_cckm_mode(vdev, rsn_authmode); + + db2dbm_enabled = wmi_service_enabled(wmi_handle, + wmi_service_hw_db2dbm_support); + if (!req->profile.rssi_abs_thresh) { + if (db2dbm_enabled) + req->profile.rssi_abs_thresh = RSSI_MIN_VALUE; + } else { + if (!db2dbm_enabled) + req->profile.rssi_abs_thresh -= + NOISE_FLOOR_DBM_DEFAULT; + } + + if (!db2dbm_enabled) { + req->min_rssi_params[DEAUTH_MIN_RSSI].min_rssi -= + NOISE_FLOOR_DBM_DEFAULT; + req->min_rssi_params[DEAUTH_MIN_RSSI].min_rssi &= 0x000000ff; + + req->min_rssi_params[BMISS_MIN_RSSI].min_rssi -= + NOISE_FLOOR_DBM_DEFAULT; + req->min_rssi_params[BMISS_MIN_RSSI].min_rssi &= 0x000000ff; + + req->min_rssi_params[MIN_RSSI_2G_TO_5G_ROAM].min_rssi -= + NOISE_FLOOR_DBM_DEFAULT; + req->min_rssi_params[MIN_RSSI_2G_TO_5G_ROAM].min_rssi &= + 0x000000ff; + + } + + return wmi_unified_send_roam_scan_offload_ap_cmd(wmi_handle, req); +} + +/** + * target_if_cm_roam_scan_mawc_params() - send roam macw to + * firmware + * @wmi_handle: wmi handle + * @req: roam macw parameters + * + * Send WMI_ROAM_CONFIGURE_MAWC_CMDID parameters to firmware + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_mawc_params(wmi_unified_t wmi_handle, + struct wlan_roam_mawc_params *req) +{ + if (!wmi_service_enabled(wmi_handle, wmi_service_hw_db2dbm_support)) + req->best_ap_rssi_threshold -= NOISE_FLOOR_DBM_DEFAULT; + + return wmi_unified_roam_mawc_params_cmd(wmi_handle, req); +} + +/** + * target_if_cm_roam_scan_filter() - send roam scan filter to firmware + * @wmi_handle: wmi handle + * @command: rso command + * @req: roam scan filter parameters + * + * Send WMI_ROAM_FILTER_CMDID parameters to firmware + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_filter(wmi_unified_t wmi_handle, uint8_t command, + struct wlan_roam_scan_filter_params *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!target_if_is_vdev_valid(req->filter_params.vdev_id)) { + target_if_err("Invalid vdev id:%d", + req->filter_params.vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (command != ROAM_SCAN_OFFLOAD_STOP) { + switch (req->reason) { + case REASON_ROAM_SET_DENYLIST_BSSID: + case REASON_ROAM_SET_SSID_ALLOWED: + case REASON_ROAM_SET_FAVORED_BSSID: + break; + case REASON_CTX_INIT: + if (command == ROAM_SCAN_OFFLOAD_START) { + req->filter_params.op_bitmap |= + ROAM_FILTER_OP_BITMAP_LCA_DISALLOW | + ROAM_FILTER_OP_BITMAP_RSSI_REJECTION_OCE; + } else { + target_if_debug("Roam Filter need not be sent"); + return QDF_STATUS_SUCCESS; + } + break; + default: + if (command != ROAM_SCAN_OFFLOAD_START) { + target_if_debug("Roam Filter need not be sent"); + return QDF_STATUS_SUCCESS; + } + } + } + + target_if_debug("RSO_CFG: vdev %d op_bitmap:0x%x num_rssi_rejection_ap:%d delta_rssi:%d", + req->filter_params.vdev_id, + req->filter_params.op_bitmap, + req->filter_params.num_rssi_rejection_ap, + req->filter_params.delta_rssi); + status = wmi_unified_roam_scan_filter_cmd(wmi_handle, + &req->filter_params); + return status; +} + +/** + * target_if_cm_roam_scan_btm_offload() - send roam scan btm offload to firmware + * @wmi_handle: wmi handle + * @req: roam scan btm offload parameters + * + * Send WMI_ROAM_BTM_CONFIG_CMDID parameters to firmware + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_scan_btm_offload(wmi_unified_t wmi_handle, + struct wlan_roam_btm_config *req) +{ + return wmi_unified_send_btm_config(wmi_handle, req); +} + +/** + * target_if_cm_roam_offload_11k_params() - send 11k offload params to firmware + * @wmi_handle: wmi handle + * @req: 11k offload parameters + * + * Send WMI_11K_OFFLOAD_REPORT_CMDID parameters to firmware + * + * Return: QDF status + */ +static QDF_STATUS +target_if_cm_roam_offload_11k_params(wmi_unified_t wmi_handle, + struct wlan_roam_11k_offload_params *req) +{ + QDF_STATUS status; + + if (!wmi_service_enabled(wmi_handle, + wmi_service_11k_neighbour_report_support)) { + target_if_err("FW doesn't support 11k offload"); + return QDF_STATUS_SUCCESS; + } + + /* If 11k enable command and ssid length is 0, drop it */ + if (req->offload_11k_bitmask && + !req->neighbor_report_params.ssid.length) { + target_if_debug("SSID Len 0"); + return QDF_STATUS_SUCCESS; + } + + status = wmi_unified_offload_11k_cmd(wmi_handle, req); + + if (status != QDF_STATUS_SUCCESS) + target_if_err("failed to send 11k offload command"); + + return status; +} + +/** + * target_if_cm_roam_bss_load_config() - send bss load config params to firmware + * @wmi_handle: wmi handle + * @req: bss load config parameters + * + * Send WMI_ROAM_BSS_LOAD_CONFIG_CMDID parameters to firmware + * + * Return: QDF status + */ +static void +target_if_cm_roam_bss_load_config(wmi_unified_t wmi_handle, + struct wlan_roam_bss_load_config *req) +{ + QDF_STATUS status; + bool db2dbm_enabled; + + db2dbm_enabled = wmi_service_enabled(wmi_handle, + wmi_service_hw_db2dbm_support); + if (!db2dbm_enabled) { + req->rssi_threshold_6ghz -= NOISE_FLOOR_DBM_DEFAULT; + req->rssi_threshold_6ghz &= 0x000000ff; + + req->rssi_threshold_5ghz -= NOISE_FLOOR_DBM_DEFAULT; + req->rssi_threshold_5ghz &= 0x000000ff; + + req->rssi_threshold_24ghz -= NOISE_FLOOR_DBM_DEFAULT; + req->rssi_threshold_24ghz &= 0x000000ff; + } + + target_if_debug("RSO_CFG: bss load trig params vdev_id:%u threshold:%u sample_time:%u 5Ghz RSSI threshold:%d 2.4G rssi threshold:%d", + req->vdev_id, req->bss_load_threshold, + req->bss_load_sample_time, req->rssi_threshold_5ghz, + req->rssi_threshold_24ghz); + + status = wmi_unified_send_bss_load_config(wmi_handle, req); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("failed to send bss load trigger config command"); +} + +static uint32_t +target_if_get_wmi_roam_offload_flag(uint32_t flag) +{ + uint32_t roam_offload_flag = 0; + + if (flag & WLAN_ROAM_FW_OFFLOAD_ENABLE) + roam_offload_flag |= WMI_ROAM_FW_OFFLOAD_ENABLE_FLAG; + + if (flag & WLAN_ROAM_BMISS_FINAL_SCAN_ENABLE) + roam_offload_flag |= WMI_ROAM_BMISS_FINAL_SCAN_ENABLE_FLAG; + + if (flag & WLAN_ROAM_SKIP_EAPOL_4WAY_HANDSHAKE) + roam_offload_flag |= + wmi_vdev_param_skip_roam_eapol_4way_handshake; + + if (flag & WLAN_ROAM_BMISS_FINAL_SCAN_TYPE) + roam_offload_flag |= WMI_ROAM_BMISS_FINAL_SCAN_TYPE_FLAG; + + if (flag & WLAN_ROAM_SKIP_SAE_ROAM_4WAY_HANDSHAKE) + roam_offload_flag |= + wmi_vdev_param_skip_sae_roam_4way_handshake; + + return roam_offload_flag; +} + +/** + * target_if_cm_roam_send_roam_init - Send roam module init/deinit to firmware + * @vdev: Pointer to Objmgr vdev + * @params: Roam offload init params + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_roam_init(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_offload_init_params *params) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + uint32_t flag; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + flag = target_if_get_wmi_roam_offload_flag(params->roam_offload_flag); + status = target_if_vdev_set_param(wmi_handle, params->vdev_id, + wmi_vdev_param_roam_fw_offload, flag); + + return status; +} + +/** + * target_if_cm_roam_scan_rssi_change_cmd() - Send WMI_ROAM_SCAN_RSSI_CHANGE + * command to firmware + * @wmi_handle: WMI handle + * @params: RSSI change parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS target_if_cm_roam_scan_rssi_change_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_rssi_change_params *params) +{ + /* + * Start new rssi triggered scan only if it changes by + * RoamRssiDiff value. Beacon weight of 14 means average rssi + * is taken over 14 previous samples + 2 times the current + * beacon's rssi. + */ + return wmi_unified_roam_scan_offload_rssi_change_cmd(wmi_handle, + params); +} + +/** + * target_if_cm_roam_offload_chan_list - Send WMI_ROAM_CHAN_LIST command to + * firmware + * @wmi_handle: Pointer to wmi handle + * @rso_chan_info: RSO channel list info + * + * Return: QDF_STATUS + */ +static QDF_STATUS target_if_cm_roam_offload_chan_list( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_channel_list *rso_chan_info) +{ + return wmi_unified_roam_scan_offload_chan_list_cmd(wmi_handle, + rso_chan_info); +} + +/** + * target_if_cm_roam_send_time_sync_cmd - Send time of the day in millisecs + * to firmware. + * @wmi_handle: WMI handle + * + * Return: None + */ +static void +target_if_cm_roam_send_time_sync_cmd(wmi_unified_t wmi_handle) +{ + return wmi_send_time_stamp_sync_cmd_tlv(wmi_handle); +} + +#ifdef WLAN_FEATURE_11BE +static QDF_STATUS +target_if_cm_roam_oem_eht_mlo_bitmap(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + uint32_t oem_eht_bitmap; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return status; + + status = wlan_mlme_get_oem_eht_mlo_config(psoc, &oem_eht_bitmap); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_roam_set_param(wmi_handle, + wlan_vdev_get_id(vdev), + WMI_ROAM_PARAM_CRYPTO_EHT_CONFIG, + oem_eht_bitmap); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set roam oem eht bitmap"); + + return status; +} +#else +static inline QDF_STATUS +target_if_cm_roam_oem_eht_mlo_bitmap(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * target_if_cm_roam_send_mlo_config() - Send roam mlo related commands + * to wmi + * @vdev: vdev object + * @req: roam mlo config parameters + * + * This function is used to send roam mlo related commands to wmi + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_mlo_config(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_mlo_config *req) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + status = wmi_unified_roam_mlo_config_cmd(wmi_handle, req); + + if (status != QDF_STATUS_SUCCESS) + target_if_err("failed to send WMI_ROAM_MLO_CONFIG_CMDID command"); + + return status; +} + +static void +target_if_cm_roam_register_mlo_req_ops(struct wlan_cm_roam_tx_ops *tx_ops) +{ + tx_ops->send_roam_mlo_config = target_if_cm_roam_send_mlo_config; +} +#else +static QDF_STATUS +target_if_cm_roam_send_mlo_config(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_mlo_config *req) +{ + return QDF_STATUS_SUCCESS; +} + +static void +target_if_cm_roam_register_mlo_req_ops(struct wlan_cm_roam_tx_ops *tx_ops) +{ +} +#endif + +/** + * target_if_cm_roam_send_start() - Send roam start related commands + * to wmi + * @vdev: vdev object + * @req: roam start config parameters + * + * This function is used to send roam start related commands to wmi + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_start(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_start_config *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_unified_t wmi_handle; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + bool bss_load_enabled; + bool eht_capab = false; + bool is_mcc_disallowed; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + target_if_cm_roam_send_time_sync_cmd(wmi_handle); + + status = target_if_cm_roam_scan_offload_rssi_thresh( + wmi_handle, + &req->rssi_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending roam scan offload rssi thresh failed"); + goto end; + } + + status = target_if_cm_roam_scan_bmiss_cnt(wmi_handle, + &req->beacon_miss_cnt); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev set bmiss bcnt param failed"); + goto end; + } + status = target_if_cm_roam_scan_bmiss_timeout(wmi_handle, + &req->bmiss_timeout); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev set bmiss timeout param failed"); + goto end; + } + + target_if_cm_roam_reason_vsie(wmi_handle, &req->reason_vsie_enable); + + target_if_cm_roam_triggers(vdev, &req->roam_triggers); + + /* Opportunistic scan runs on a timer, value set by + * empty_scan_refresh_period. Age out the entries after 3 such + * cycles. + */ + if (req->scan_period_params.empty_scan_refresh_period > 0) { + status = target_if_cm_roam_scan_offload_scan_period( + wmi_handle, + &req->scan_period_params); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + } + + status = target_if_cm_roam_scan_rssi_change_cmd( + wmi_handle, &req->rssi_change_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev:%d Sending rssi change threshold failed", + req->rssi_change_params.vdev_id); + goto end; + } + + status = target_if_cm_roam_scan_offload_ap_profile( + vdev, wmi_handle, + &req->profile_params); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + status = target_if_cm_roam_offload_chan_list(wmi_handle, + &req->rso_chan_info); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev:%d Send channel list command failed", + req->rso_chan_info.vdev_id); + goto end; + } + + if (wmi_service_enabled(wmi_handle, wmi_service_mawc_support)) { + status = target_if_cm_roam_scan_mawc_params(wmi_handle, + &req->mawc_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending roaming MAWC params failed"); + goto end; + } + } else { + target_if_debug("MAWC roaming not supported by firmware"); + } + + status = target_if_cm_roam_scan_offload_mode(wmi_handle, + &req->rso_config); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev:%d Send RSO mode cmd failed", + req->rso_config.vdev_id); + goto end; + } + + status = target_if_cm_roam_scan_filter(wmi_handle, + ROAM_SCAN_OFFLOAD_START, + &req->scan_filter_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending start for roam scan filter failed"); + goto end; + } + + status = target_if_cm_roam_scan_btm_offload(wmi_handle, + &req->btm_config); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending BTM config to fw failed"); + goto end; + } + + /* + * Send 11k offload enable and bss load trigger parameters + * to FW as part of RSO Start + */ + status = target_if_cm_roam_offload_11k_params(wmi_handle, + &req->roam_11k_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("11k offload enable not sent, status %d", status); + goto end; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wlan_mlme_get_bss_load_enabled(psoc, &bss_load_enabled); + if (bss_load_enabled) + target_if_cm_roam_bss_load_config(wmi_handle, + &req->bss_load_config); + + target_if_cm_roam_disconnect_params(wmi_handle, ROAM_SCAN_OFFLOAD_START, + &req->disconnect_params); + + target_if_cm_roam_idle_params(wmi_handle, ROAM_SCAN_OFFLOAD_START, + &req->idle_params); + wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); + if (eht_capab) + target_if_cm_roam_send_mlo_config(vdev, &req->roam_mlo_params); + + vdev_id = wlan_vdev_get_id(vdev); + if (req->wlan_roam_rt_stats_config) + target_if_cm_roam_rt_stats_config(vdev, vdev_id, + req->wlan_roam_rt_stats_config); + + if (req->wlan_roam_ho_delay_config) + target_if_cm_roam_ho_delay_config( + vdev, vdev_id, req->wlan_roam_ho_delay_config); + + if (req->wlan_exclude_rm_partial_scan_freq) + target_if_cm_exclude_rm_partial_scan_freq( + vdev, req->wlan_exclude_rm_partial_scan_freq); + + if (req->wlan_roam_full_scan_6ghz_on_disc) + target_if_cm_roam_full_scan_6ghz_on_disc( + vdev, req->wlan_roam_full_scan_6ghz_on_disc); + + is_mcc_disallowed = !wlan_cm_same_band_sta_allowed(psoc); + target_if_cm_roam_mcc_disallow(vdev, vdev_id, is_mcc_disallowed); + + if (req->wlan_roam_rssi_diff_6ghz) + target_if_cm_roam_rssi_diff_6ghz(vdev, + req->wlan_roam_rssi_diff_6ghz); + + status = target_if_cm_roam_oem_eht_mlo_bitmap(vdev); + /* add other wmi commands */ +end: + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +target_if_start_rso_stop_timer(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + struct wlan_lmac_if_mlme_rx_ops *rx_ops; + struct vdev_response_timer *vdev_rsp; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); + if (!rx_ops || !rx_ops->psoc_get_vdev_response_timer_info) { + mlme_err("VEV_%d: PSOC_%d No Rx Ops", vdev_id, + wlan_psoc_get_id(psoc)); + return QDF_STATUS_E_INVAL; + } + + vdev_rsp = rx_ops->psoc_get_vdev_response_timer_info(psoc, vdev_id); + if (!vdev_rsp) { + mlme_err("VDEV_%d: PSOC_%d No vdev rsp timer", vdev_id, + wlan_psoc_get_id(psoc)); + return QDF_STATUS_E_INVAL; + } + + vdev_rsp->expire_time = RSO_STOP_RESPONSE_TIMER; + + return target_if_vdev_mgr_rsp_timer_start(psoc, vdev_rsp, + RSO_STOP_RESPONSE_BIT); +} + +static bool +target_if_is_vdev_rsp_valid(struct wlan_objmgr_psoc *psoc, + struct vdev_response_timer **vdev_rsp, + struct wlan_lmac_if_mlme_rx_ops *rx_ops, + uint8_t vdev_id) +{ + *vdev_rsp = rx_ops->psoc_get_vdev_response_timer_info(psoc, vdev_id); + if (!*vdev_rsp) { + mlme_err("MLO_ROAM: vdev rsp not found for vdev:%d", vdev_id); + return false; + } + + if (qdf_atomic_test_bit(RSO_STOP_RESPONSE_BIT, + &((*vdev_rsp)->rsp_status))) { + mlme_debug("MLO_ROAM: RSO bit set on vdev id %d", + (*vdev_rsp)->vdev_id); + return true; + } + + /* Failure case vdev_rsp is set to NULL */ + *vdev_rsp = NULL; + + return false; +} + +/** + * target_if_find_active_rso_stop_rsp() - Iterate through ml vdevs to find + * the vdev rsp for which RSO_STOP_RESPONSE_BIT is set. + * @roam_event: Roam event data + * + * This is needed when for e.g.: host sends rso stop on vdev id 0, fw response + * is received on vdev 1. + * Since the timer is vdev specific, this function will iterate through ml vdevs + * to find the vdev_rsp on which RSO_STOP_RESPONSE_BIT is set. + * + * Return: struct vdev_response_timer for success, NULL for failure + */ +static struct vdev_response_timer * +target_if_find_active_rso_stop_rsp(struct roam_offload_roam_event *roam_event) +{ + struct vdev_response_timer *vdev_rsp = NULL; + struct wlan_lmac_if_mlme_rx_ops *rx_ops; + struct wlan_objmgr_vdev *vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint8_t i; + QDF_STATUS status; + + rx_ops = target_if_vdev_mgr_get_rx_ops(roam_event->psoc); + if (!rx_ops || !rx_ops->psoc_get_vdev_response_timer_info) { + mlme_err("No Rx Ops"); + return NULL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(roam_event->psoc, + roam_event->vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) + return NULL; + + /* For legacy case use the incoming vdev */ + if (target_if_is_vdev_rsp_valid(roam_event->psoc, &vdev_rsp, + rx_ops, roam_event->vdev_id)) + goto end; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) + goto end; + + /* + * if vdev_rsp with RSO_STOP_RESPONSE bit is not set then check for + * the same on other ML vdevs + */ + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + status = wlan_objmgr_vdev_try_get_ref(mlo_dev_ctx->wlan_vdev_list[i], + WLAN_MLO_MGR_ID); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + if (target_if_is_vdev_rsp_valid(roam_event->psoc, &vdev_rsp, + rx_ops, + wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]))) { + mlo_release_vdev_ref(mlo_dev_ctx->wlan_vdev_list[i]); + goto end; + } + + mlo_release_vdev_ref(mlo_dev_ctx->wlan_vdev_list[i]); + } + + if (i == WLAN_UMAC_MLO_MAX_VDEVS) { + mlme_err("RSO bit not set on any mlo vdev"); + goto end; + } + +end: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return vdev_rsp; +} + +QDF_STATUS +target_if_stop_rso_stop_timer(struct roam_offload_roam_event *roam_event) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct vdev_response_timer *vdev_rsp; + + roam_event->rso_timer_stopped = false; + if (roam_event->reason == ROAM_REASON_RSO_STATUS && + roam_event->notif == CM_ROAM_NOTIF_HO_FAIL) { + mlme_debug("HO_FAIL happened, wait for HO_FAIL event vdev_id: %u", + roam_event->vdev_id); + } + + vdev_rsp = target_if_find_active_rso_stop_rsp(roam_event); + if (!vdev_rsp) { + mlme_err("vdev response timer is null VDEV_%d PSOC_%d", + roam_event->vdev_id, + wlan_psoc_get_id(roam_event->psoc)); + return QDF_STATUS_E_INVAL; + } + + switch (roam_event->reason) { + case ROAM_REASON_RSO_STATUS: + if (roam_event->notif != CM_ROAM_NOTIF_SCAN_MODE_SUCCESS && + roam_event->notif != CM_ROAM_NOTIF_SCAN_MODE_FAIL) + break; + + /* + * fallthrough if notif == CM_ROAM_NOTIF_SCAN_MODE_SUCCESS or + * notif == CM_ROAM_NOTIF_SCAN_MODE_FAIL + */ + fallthrough; + case ROAM_REASON_HO_FAILED: + status = target_if_vdev_mgr_rsp_timer_stop(roam_event->psoc, + vdev_rsp, + RSO_STOP_RESPONSE_BIT); + roam_event->rso_timer_stopped = true; + if (QDF_IS_STATUS_ERROR(status)) { + roam_event->rso_timer_stopped = false; + mlme_err("PSOC_%d VDEV_%d: VDEV MGR RSO Stop RSP Timer stop failed", + roam_event->psoc->soc_objmgr.psoc_id, + roam_event->vdev_id); + } + break; + default: + return status; + } + + return status; +} +#else +static inline QDF_STATUS +target_if_start_rso_stop_timer(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +target_if_cm_send_rso_stop_failure_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_cm_roam_rx_ops *roam_rx_ops; + struct roam_offload_roam_event roam_event = {0}; + + roam_event.vdev_id = vdev_id; + roam_event.psoc = psoc; + roam_event.reason = ROAM_REASON_RSO_STATUS; + roam_event.notif = CM_ROAM_NOTIF_SCAN_MODE_FAIL; + roam_event.rso_timer_stopped = true; + + roam_rx_ops = target_if_cm_get_roam_rx_ops(psoc); + if (!roam_rx_ops || !roam_rx_ops->roam_event_rx) { + target_if_err("No valid roam rx ops"); + return QDF_STATUS_E_INVAL; + } + roam_rx_ops->roam_event_rx(&roam_event); + + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS +target_if_cm_roam_abort_rso_stop_timer(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct vdev_response_timer *vdev_rsp; + struct wlan_lmac_if_mlme_rx_ops *rx_ops; + + rx_ops = target_if_vdev_mgr_get_rx_ops(psoc); + if (!rx_ops || !rx_ops->vdev_mgr_start_response) { + mlme_err("No Rx Ops"); + return QDF_STATUS_E_INVAL; + } + vdev_rsp = rx_ops->psoc_get_vdev_response_timer_info(psoc, vdev_id); + if (!vdev_rsp) { + mlme_err("vdev response timer is null VDEV_%d PSOC_%d", + vdev_id, wlan_psoc_get_id(psoc)); + return QDF_STATUS_E_INVAL; + } + + return target_if_vdev_mgr_rsp_timer_stop(psoc, vdev_rsp, + RSO_STOP_RESPONSE_BIT); +} + +/** + * target_if_cm_roam_send_stop() - Send roam stop related commands + * to wmi + * @vdev: vdev object + * @req: roam stop config parameters + * + * This function is used to send roam stop related commands to wmi + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_stop(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_stop_config *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS timer_start_status = QDF_STATUS_E_NOSUPPORT; + QDF_STATUS rso_stop_status = QDF_STATUS_E_INVAL; + wmi_unified_t wmi_handle; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* Send 11k offload disable command to FW as part of RSO Stop */ + status = target_if_cm_roam_offload_11k_params(wmi_handle, + &req->roam_11k_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("11k offload disable not sent, status %d", + status); + goto end; + } + + /* Send BTM config as disabled during RSO Stop */ + status = target_if_cm_roam_scan_btm_offload(wmi_handle, + &req->btm_config); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending BTM config to fw failed"); + goto end; + } + + if (req->start_rso_stop_timer) + timer_start_status = target_if_start_rso_stop_timer(vdev); + + rso_stop_status = target_if_cm_roam_scan_offload_mode(wmi_handle, + &req->rso_config); + if (QDF_IS_STATUS_ERROR(rso_stop_status)) { + target_if_err("vdev:%d Send RSO mode cmd failed", + req->rso_config.vdev_id); + goto end; + } + + /* + * After sending the roam scan mode because of a disconnect, + * clear the scan bitmap client as well by sending + * the following command + */ + target_if_cm_roam_scan_offload_rssi_thresh(wmi_handle, + &req->rssi_params); + + /* + * If the STOP command is due to a disconnect, then + * send the filter command to clear all the filter + * entries. If it is roaming scenario, then do not + * send the cleared entries. + */ + if (!req->middle_of_roaming) { + status = target_if_cm_roam_scan_filter( + wmi_handle, ROAM_SCAN_OFFLOAD_STOP, + &req->scan_filter_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("clear for roam scan filter failed"); + goto end; + } + } + + target_if_cm_roam_disconnect_params(wmi_handle, ROAM_SCAN_OFFLOAD_STOP, + &req->disconnect_params); + + target_if_cm_roam_idle_params(wmi_handle, ROAM_SCAN_OFFLOAD_STOP, + &req->idle_params); + /* + * Disable all roaming triggers if RSO stop is as part of + * disconnect + */ + vdev_id = wlan_vdev_get_id(vdev); + if (req->rso_config.rso_mode_info.roam_scan_mode == + WMI_ROAM_SCAN_MODE_NONE) { + req->roam_triggers.vdev_id = vdev_id; + req->roam_triggers.trigger_bitmap = 0; + req->roam_triggers.roam_scan_scheme_bitmap = 0; + target_if_cm_roam_triggers(vdev, &req->roam_triggers); + } +end: + if (QDF_IS_STATUS_SUCCESS(timer_start_status)) { + if (QDF_IS_STATUS_SUCCESS(rso_stop_status)) { + /* + * Started the timer and send RSO stop to firmware + * successfully. Wait for RSO STOP response from fw. + */ + req->send_rso_stop_resp = false; + } else { + /* + * Started the timer and but failed to send RSO stop to + * firmware. Stop the timer and let the response be + * poseted from CM. + */ + target_if_cm_roam_abort_rso_stop_timer(psoc, + wlan_vdev_get_id(vdev)); + } + } + + return status; +} + +/** + * target_if_cm_roam_send_update_config() - Send roam update config related + * commands to wmi + * @vdev: vdev object + * @req: roam update config parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_update_config(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_update_config *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_unified_t wmi_handle; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + bool is_mcc_disallowed; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + status = target_if_cm_roam_scan_bmiss_cnt(wmi_handle, + &req->beacon_miss_cnt); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev set bmiss bcnt param failed"); + goto end; + } + + status = target_if_cm_roam_scan_bmiss_timeout(wmi_handle, + &req->bmiss_timeout); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev set bmiss timeout param failed"); + goto end; + } + + status = target_if_cm_roam_scan_filter(wmi_handle, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + &req->scan_filter_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending update for roam scan filter failed"); + goto end; + } + + status = target_if_cm_roam_scan_offload_rssi_thresh( + wmi_handle, + &req->rssi_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Sending roam scan offload rssi thresh failed"); + goto end; + } + + if (req->scan_period_params.empty_scan_refresh_period > 0) { + status = target_if_cm_roam_scan_offload_scan_period( + wmi_handle, + &req->scan_period_params); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + } + + status = target_if_cm_roam_scan_rssi_change_cmd( + wmi_handle, &req->rssi_change_params); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev:%d Sending rssi change threshold failed", + req->rssi_change_params.vdev_id); + goto end; + } + + status = target_if_cm_roam_scan_offload_ap_profile( + vdev, wmi_handle, + &req->profile_params); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + status = target_if_cm_roam_offload_chan_list(wmi_handle, + &req->rso_chan_info); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev:%d Send channel list command failed", + req->rso_chan_info.vdev_id); + goto end; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + vdev_id = wlan_vdev_get_id(vdev); + + if (MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + status = target_if_cm_roam_scan_offload_mode(wmi_handle, + &req->rso_config); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("vdev:%d Send RSO mode cmd failed", + req->rso_config.vdev_id); + goto end; + } + + target_if_cm_roam_disconnect_params( + wmi_handle, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + &req->disconnect_params); + + target_if_cm_roam_idle_params( + wmi_handle, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + &req->idle_params); + target_if_cm_roam_triggers(vdev, &req->roam_triggers); + + if (req->wlan_roam_rt_stats_config) + target_if_cm_roam_rt_stats_config( + vdev, vdev_id, + req->wlan_roam_rt_stats_config); + + if (req->wlan_roam_ho_delay_config) + target_if_cm_roam_ho_delay_config( + vdev, vdev_id, + req->wlan_roam_ho_delay_config); + + if (req->wlan_exclude_rm_partial_scan_freq) + target_if_cm_exclude_rm_partial_scan_freq( + vdev, req->wlan_exclude_rm_partial_scan_freq); + + if (req->wlan_roam_full_scan_6ghz_on_disc) + target_if_cm_roam_full_scan_6ghz_on_disc( + vdev, req->wlan_roam_full_scan_6ghz_on_disc); + + is_mcc_disallowed = !wlan_cm_same_band_sta_allowed(psoc); + target_if_cm_roam_mcc_disallow(vdev, vdev_id, + is_mcc_disallowed); + + if (req->wlan_roam_rssi_diff_6ghz) + target_if_cm_roam_rssi_diff_6ghz( + vdev, req->wlan_roam_rssi_diff_6ghz); + + status = target_if_cm_roam_oem_eht_mlo_bitmap(vdev); + } +end: + return status; +} + +/** + * target_if_cm_roam_update_freqs() - Send roam frequencies to fw + * @vdev: vdev object + * @req: roam channels to update to firmware + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_update_freqs(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_scan_channel_list *req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + status = target_if_cm_roam_offload_chan_list(wmi_handle, req); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("vdev:%d Send channel list command failed", + req->vdev_id); + + return status; +} + +/** + * target_if_cm_roam_abort() - Send roam abort to wmi + * @vdev: vdev object + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_abort(struct wlan_objmgr_vdev *vdev, uint8_t vdev_id) +{ + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + if (!target_if_is_vdev_valid(vdev_id)) { + target_if_err("Invalid vdev id:%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + return wmi_unified_roam_scan_offload_cmd(wmi_handle, + WMI_ROAM_SCAN_STOP_CMD, + vdev_id); +} + +/** + * target_if_cm_roam_per_config() - Send roam per config related + * commands to wmi + * @vdev: vdev object + * @req: roam per config parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_per_config(struct wlan_objmgr_vdev *vdev, + struct wlan_per_roam_config_req *req) +{ + wmi_unified_t wmi_handle; + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_set_per_roam_config(wmi_handle, req); +} + +/** + * target_if_cm_roam_send_disable_config() - Send roam disable config related + * commands to wmi + * @vdev: vdev object + * @req: roam disable config parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_cm_roam_send_disable_config(struct wlan_objmgr_vdev *vdev, + struct roam_disable_cfg *req) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + wmi_unified_t wmi_handle; + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + target_if_err("Failed to get vdev mlme obj!"); + goto end; + } + + if (vdev_mlme->mgmt.generic.type != WMI_VDEV_TYPE_STA || + vdev_mlme->mgmt.generic.subtype != 0) { + target_if_err("This isn't a STA: %d", req->vdev_id); + goto end; + } + + wmi_handle = target_if_cm_roam_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + goto end; + + status = target_if_vdev_set_param( + wmi_handle, + req->vdev_id, + wmi_vdev_param_roam_11kv_ctrl, + req->cfg); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set wmi_vdev_param_roam_11kv_ctrl"); + +end: + return status; +} + +/** + * target_if_cm_roam_register_rso_req_ops() - Register rso req tx ops functions + * @tx_ops: tx ops + * + * This function is used to register rso req tx ops functions + * + * Return: none + */ +static void +target_if_cm_roam_register_rso_req_ops(struct wlan_cm_roam_tx_ops *tx_ops) +{ + tx_ops->send_roam_offload_init_req = target_if_cm_roam_send_roam_init; + tx_ops->send_roam_start_req = target_if_cm_roam_send_start; + tx_ops->send_roam_stop_offload = target_if_cm_roam_send_stop; + tx_ops->send_roam_update_config = target_if_cm_roam_send_update_config; + tx_ops->send_roam_abort = target_if_cm_roam_abort; + tx_ops->send_roam_per_config = target_if_cm_roam_per_config; + tx_ops->send_roam_triggers = target_if_cm_roam_triggers; + tx_ops->send_roam_disable_config = + target_if_cm_roam_send_disable_config; + tx_ops->send_roam_frequencies = target_if_cm_roam_update_freqs; + target_if_cm_roam_register_mlo_req_ops(tx_ops); +} + +QDF_STATUS target_if_cm_roam_register_tx_ops(struct wlan_cm_roam_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("target if tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + target_if_cm_roam_register_lfr3_ops(tx_ops); + target_if_cm_roam_register_rso_req_ops(tx_ops); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/cp_stats/src/target_if_mc_cp_stats.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/cp_stats/src/target_if_mc_cp_stats.c new file mode 100644 index 0000000000..6ea610a486 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/cp_stats/src/target_if_mc_cp_stats.c @@ -0,0 +1,1872 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_cp_stats.c + * + * This file provide definition for APIs registered through lmac Tx Ops + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../umac/cmn_services/utils/inc/wlan_utility.h" +#include +#include +#include +#include +#include +#include +#ifdef WLAN_FEATURE_SON +#include "son_api.h" +#endif + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +static QDF_STATUS +target_if_twt_session_params_unregister_evt_hdlr(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +target_if_twt_session_params_register_evt_hdlr(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#elif defined(WLAN_SUPPORT_TWT) && !defined(WLAN_TWT_CONV_SUPPORTED) + +#include +#include + +/** + * target_if_twt_fill_peer_twt_session_params() - Fills peer twt session + * parameter obtained from firmware into mc_cp_stats of peer + * @mc_cp_stats: Pointer to Peer mc_cp stats + * @twt_params: twt session parameters to be copied + * + * Return: None + */ +static void target_if_twt_fill_peer_twt_session_params +( + struct peer_mc_cp_stats *mc_cp_stats, + struct wmi_host_twt_session_stats_info *twt_params +) +{ + uint32_t event_type; + int i = 0; + + if (!mc_cp_stats || !twt_params) + return; + + if ((twt_params->event_type == HOST_TWT_SESSION_UPDATE) || + (twt_params->event_type == HOST_TWT_SESSION_TEARDOWN)) { + /* Update for a existing session, find by dialog_id */ + for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { + if (mc_cp_stats->twt_param[i].dialog_id != + twt_params->dialog_id) + continue; + qdf_mem_copy(&mc_cp_stats->twt_param[i], twt_params, + sizeof(*twt_params)); + return; + } + } else if (twt_params->event_type == HOST_TWT_SESSION_SETUP) { + /* New session, fill in any existing invalid session */ + for (i = 0; i < TWT_PEER_MAX_SESSIONS; i++) { + event_type = mc_cp_stats->twt_param[i].event_type; + if ((event_type != HOST_TWT_SESSION_SETUP) && + (event_type != HOST_TWT_SESSION_UPDATE)) { + qdf_mem_copy(&mc_cp_stats->twt_param[i], + twt_params, + sizeof(*twt_params)); + return; + } + } + } + + target_if_err("Unable to save twt session params with dialog id %d", + twt_params->dialog_id); +} + +/** + * target_if_obtain_mc_cp_stat_obj() - Retrieves peer mc cp stats object + * @peer_obj: peer object + * + * Return: mc cp stats object on success or NULL + */ +static struct peer_mc_cp_stats * +target_if_obtain_mc_cp_stat_obj(struct wlan_objmgr_peer *peer_obj) +{ + struct peer_cp_stats *cp_stats_peer_obj; + struct peer_mc_cp_stats *mc_cp_stats; + + cp_stats_peer_obj = wlan_objmgr_peer_get_comp_private_obj + (peer_obj, WLAN_UMAC_COMP_CP_STATS); + if (!cp_stats_peer_obj) { + target_if_err("cp peer stats obj err"); + return NULL; + } + + mc_cp_stats = cp_stats_peer_obj->peer_stats; + if (!mc_cp_stats) { + target_if_err("mc stats obj err"); + return NULL; + } + return mc_cp_stats; +} + +/** + * target_if_twt_session_params_event_handler() - Handles twt session stats + * event from firmware and store the per peer twt session parameters in + * mc_cp_stats + * @scn: scn handle + * @evt_buf: data buffer for event + * @evt_data_len: data length of event + * + * Return: 0 on success, else error values + */ +static int target_if_twt_session_params_event_handler(ol_scn_t scn, + uint8_t *evt_buf, + uint32_t evt_data_len) +{ + struct wlan_objmgr_psoc *psoc_obj; + struct wlan_objmgr_peer *peer_obj; + struct wmi_unified *wmi_hdl; + struct wmi_host_twt_session_stats_info twt_params; + struct wmi_twt_session_stats_event_param params = {0}; + struct peer_mc_cp_stats *mc_cp_stats; + struct peer_cp_stats *peer_cp_stats_priv; + uint32_t expected_len; + int i; + QDF_STATUS status; + + if (!scn || !evt_buf) { + target_if_err("scn: 0x%pK, evt_buf: 0x%pK", scn, evt_buf); + return -EINVAL; + } + + psoc_obj = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc_obj) { + target_if_err("psoc object is null!"); + return -EINVAL; + } + + wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc_obj); + if (!wmi_hdl) { + target_if_err("wmi_handle is null!"); + return -EINVAL; + } + + status = wmi_extract_twt_session_stats_event(wmi_hdl, evt_buf, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Could not extract twt session stats event"); + return qdf_status_to_os_return(status); + } + + if (params.num_sessions > TWT_PEER_MAX_SESSIONS) { + target_if_err("no of twt sessions exceeded the max supported"); + return -EINVAL; + } + + expected_len = (sizeof(wmi_pdev_twt_session_stats_event_fixed_param) + + WMI_TLV_HDR_SIZE + (params.num_sessions * + sizeof(wmi_twt_session_stats_info))); + + if (evt_data_len < expected_len) { + target_if_err("Got invalid len of data from FW %d expected %d", + evt_data_len, expected_len); + return -EINVAL; + } + + for (i = 0; i < params.num_sessions; i++) { + status = wmi_extract_twt_session_stats_data(wmi_hdl, evt_buf, + ¶ms, + &twt_params, i); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Unable to extract twt params for idx %d", + i); + return -EINVAL; + } + + peer_obj = wlan_objmgr_get_peer_by_mac(psoc_obj, + twt_params.peer_mac, + WLAN_CP_STATS_ID); + if (!peer_obj) { + target_if_err("peer obj not found for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(twt_params.peer_mac)); + continue; + } + + peer_cp_stats_priv = wlan_cp_stats_get_peer_stats_obj(peer_obj); + if (!peer_cp_stats_priv) { + target_if_err("peer_cp_stats_priv is null"); + continue; + } + + mc_cp_stats = target_if_obtain_mc_cp_stat_obj(peer_obj); + if (!mc_cp_stats) { + target_if_err("Unable to retrieve mc cp stats obj for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(twt_params.peer_mac)); + wlan_objmgr_peer_release_ref(peer_obj, + WLAN_CP_STATS_ID); + continue; + } + + wlan_cp_stats_peer_obj_lock(peer_cp_stats_priv); + target_if_twt_fill_peer_twt_session_params(mc_cp_stats, + &twt_params); + wlan_cp_stats_peer_obj_unlock(peer_cp_stats_priv); + + wlan_objmgr_peer_release_ref(peer_obj, WLAN_CP_STATS_ID); + } + return 0; +} + +/** + * target_if_twt_session_params_unregister_evt_hdlr() - Unregister the + * event handler registered for wmi event wmi_twt_session_stats_event_id + * @psoc: psoc object + * + * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure + */ +static QDF_STATUS +target_if_twt_session_params_unregister_evt_hdlr(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("psoc obj in null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null!"); + return QDF_STATUS_E_INVAL; + } + + wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_session_stats_event_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_twt_session_params_register_evt_hdlr() - Register a event + * handler with wmi layer for wmi event wmi_twt_session_stats_event_id + * @psoc: psoc object + * + * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure + */ +static QDF_STATUS +target_if_twt_session_params_register_evt_hdlr(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret_val; + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("psoc obj in null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null!"); + return QDF_STATUS_E_INVAL; + } + + ret_val = wmi_unified_register_event_handler( + wmi_handle, + wmi_twt_session_stats_event_id, + target_if_twt_session_params_event_handler, + WMI_RX_WORK_CTX); + + if (QDF_IS_STATUS_ERROR(ret_val)) + target_if_err("Failed to register twt session stats event cb"); + + return ret_val; +} +#else +static QDF_STATUS +target_if_twt_session_params_register_evt_hdlr(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +target_if_twt_session_params_unregister_evt_hdlr(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_SUPPORT_TWT */ + +#ifdef WLAN_FEATURE_MIB_STATS +static void target_if_cp_stats_free_mib_stats(struct stats_event *ev) +{ + qdf_mem_free(ev->mib_stats); + ev->mib_stats = NULL; +} +#else +static void target_if_cp_stats_free_mib_stats(struct stats_event *ev) +{ +} +#endif + +/** + * target_if_cp_stats_free_peer_stats_info_ext() - API to free peer stats + * info ext structure + * @ev: structure from where peer stats info ext needs to be freed + * + * Return: none + */ +static void target_if_cp_stats_free_peer_stats_info_ext(struct stats_event *ev) +{ + struct peer_stats_info_ext_event *peer_stats_info = + ev->peer_stats_info_ext; + uint16_t i; + + for (i = 0; i < ev->num_peer_stats_info_ext; i++) { + qdf_mem_free(peer_stats_info->tx_pkt_per_mcs); + peer_stats_info->tx_pkt_per_mcs = NULL; + qdf_mem_free(peer_stats_info->rx_pkt_per_mcs); + peer_stats_info->rx_pkt_per_mcs = NULL; + peer_stats_info++; + } + + qdf_mem_free(ev->peer_stats_info_ext); + ev->peer_stats_info_ext = NULL; + ev->num_peer_stats_info_ext = 0; +} + +static void target_if_cp_stats_free_stats_event(struct stats_event *ev) +{ + qdf_mem_free(ev->pdev_stats); + ev->pdev_stats = NULL; + qdf_mem_free(ev->pdev_extd_stats); + ev->pdev_extd_stats = NULL; + qdf_mem_free(ev->peer_stats); + ev->peer_stats = NULL; + qdf_mem_free(ev->peer_adv_stats); + ev->peer_adv_stats = NULL; + qdf_mem_free(ev->peer_extended_stats); + ev->peer_extended_stats = NULL; + qdf_mem_free(ev->cca_stats); + ev->cca_stats = NULL; + qdf_mem_free(ev->vdev_summary_stats); + ev->vdev_summary_stats = NULL; + qdf_mem_free(ev->vdev_chain_rssi); + ev->vdev_chain_rssi = NULL; + target_if_cp_stats_free_mib_stats(ev); + target_if_cp_stats_free_peer_stats_info_ext(ev); + qdf_mem_free(ev->vdev_extd_stats); + ev->vdev_extd_stats = NULL; +} + +static QDF_STATUS target_if_cp_stats_extract_pdev_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, + uint8_t *data) +{ + uint32_t i; + QDF_STATUS status; + wmi_host_pdev_stats *pdev_stats; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + cdp_config_param_type val; + + ev->num_pdev_stats = stats_param->num_pdev_stats; + if (!ev->num_pdev_stats) + return QDF_STATUS_SUCCESS; + + /* + * num_pdev_stats is validated within function wmi_extract_stats_param + * which is called to populated wmi_host_stats_event stats_param + */ + ev->pdev_stats = qdf_mem_malloc(sizeof(*ev->pdev_stats) * + ev->num_pdev_stats); + if (!ev->pdev_stats) + return QDF_STATUS_E_NOMEM; + + pdev_stats = qdf_mem_malloc(sizeof(*pdev_stats)); + + if (!pdev_stats) { + cp_stats_err("malloc failed for pdev_stats"); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < ev->num_pdev_stats; i++) { + status = wmi_extract_pdev_stats(wmi_hdl, data, i, pdev_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_pdev_stats failed"); + qdf_mem_free(pdev_stats); + return status; + } + + /* + * It's 0.5 db unit from halphy. so correct the value here + */ + ev->pdev_stats[i].max_pwr = pdev_stats->chan_tx_pwr >> 1; + + ev->pdev_stats[i].pdev_id = pdev_stats->pdev_id; + ev->pdev_stats[i].rx_clear_count = pdev_stats->rx_clear_count; + ev->pdev_stats[i].tx_frame_count = pdev_stats->tx_frame_count; + ev->pdev_stats[i].cycle_count = pdev_stats->cycle_count; + + val.cdp_pdev_param_chn_noise_flr = pdev_stats->chan_nf; + cdp_txrx_set_pdev_param(soc, 0, CDP_CHAN_NOISE_FLOOR, val); + } + qdf_mem_free(pdev_stats); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS target_if_cp_stats_extract_pmf_bcn_protect_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + QDF_STATUS status; + wmi_host_pmf_bcn_protect_stats pmf_bcn_stats = {0}; + + if (!(stats_param->stats_id & WMI_HOST_REQUEST_PMF_BCN_PROTECT_STAT)) + return QDF_STATUS_SUCCESS; + + qdf_mem_zero(&ev->bcn_protect_stats, sizeof(ev->bcn_protect_stats)); + status = wmi_extract_pmf_bcn_protect_stats(wmi_hdl, data, + &pmf_bcn_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_pmf_bcn_protect_stats failed"); + return status; + } + + ev->bcn_protect_stats.pmf_bcn_stats_valid = true; + ev->bcn_protect_stats.igtk_mic_fail_cnt = + pmf_bcn_stats.igtk_mic_fail_cnt; + ev->bcn_protect_stats.igtk_replay_cnt = + pmf_bcn_stats.igtk_replay_cnt; + ev->bcn_protect_stats.bcn_mic_fail_cnt = + pmf_bcn_stats.bcn_mic_fail_cnt; + ev->bcn_protect_stats.bcn_replay_cnt = + pmf_bcn_stats.bcn_replay_cnt; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +target_if_cp_stats_extract_pdev_extd_stats(struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, + uint8_t *data) +{ + uint32_t i; + QDF_STATUS status; + wmi_host_pdev_ext_stats *pdev_extd_stats; + + if (!(stats_param->stats_id & WMI_REQUEST_PDEV_EXTD_STAT)) + return QDF_STATUS_SUCCESS; + + ev->pdev_extd_stats = qdf_mem_malloc(sizeof(*ev->pdev_extd_stats) * + WLAN_UMAC_MAX_RP_PID); + if (!ev->pdev_extd_stats) + return QDF_STATUS_E_NOMEM; + + pdev_extd_stats = qdf_mem_malloc(sizeof(*pdev_extd_stats)); + if (!pdev_extd_stats) + return QDF_STATUS_E_NOMEM; + + ev->num_pdev_extd_stats = 0; + for (i = 0; i < stats_param->num_pdev_ext_stats; i++) { + qdf_mem_set(pdev_extd_stats, sizeof(*pdev_extd_stats), 0); + + status = wmi_extract_pdev_ext_stats(wmi_hdl, data, i, + pdev_extd_stats); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(pdev_extd_stats); + cp_stats_err("wmi_extract_pdev_ext_stats failed"); + return status; + } + + ev->num_pdev_extd_stats++; + ev->pdev_extd_stats[i].pdev_id = + pdev_extd_stats->pdev_id; + ev->pdev_extd_stats[i].my_rx_count = + pdev_extd_stats->my_rx_count; + ev->pdev_extd_stats[i].rx_matched_11ax_msdu_cnt = + pdev_extd_stats->rx_matched_11ax_msdu_cnt; + ev->pdev_extd_stats[i].rx_other_11ax_msdu_cnt = + pdev_extd_stats->rx_other_11ax_msdu_cnt; + } + + qdf_mem_free(pdev_extd_stats); + return QDF_STATUS_SUCCESS; +} + +static void target_if_cp_stats_extract_peer_extd_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, + uint8_t *data) + +{ + QDF_STATUS status; + uint32_t i; + wmi_host_peer_extd_stats peer_extd_stats; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_peer_stats *peer_stats; + + if (!stats_param->num_peer_extd_stats) + return; + + ev->peer_extended_stats = + qdf_mem_malloc(sizeof(*ev->peer_extended_stats) * + stats_param->num_peer_extd_stats); + if (!ev->peer_extended_stats) + return; + + ev->num_peer_extd_stats = stats_param->num_peer_extd_stats; + + for (i = 0; i < ev->num_peer_extd_stats; i++) { + status = wmi_extract_peer_extd_stats(wmi_hdl, data, i, + &peer_extd_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_peer_extd_stats failed"); + continue; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY( + &peer_extd_stats.peer_macaddr, + ev->peer_extended_stats[i].peer_macaddr); + ev->peer_extended_stats[i].rx_mc_bc_cnt = + peer_extd_stats.rx_mc_bc_cnt; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) + continue; + + status = cdp_host_get_peer_stats(soc, VDEV_ALL, + ev->peer_extended_stats[i].peer_macaddr, + peer_stats); + if (status == QDF_STATUS_SUCCESS) + ev->peer_extended_stats[i].rx_mc_bc_cnt = + peer_stats->rx.multicast.num + + peer_stats->rx.bcast.num; + + qdf_mem_free(peer_stats); + } +} + +static QDF_STATUS target_if_cp_stats_extract_peer_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, + uint8_t *data) +{ + uint32_t i; + QDF_STATUS status; + wmi_host_peer_stats peer_stats; + bool db2dbm_enabled; + struct wmi_host_peer_adv_stats *peer_adv_stats; + + /* Extract peer_stats */ + if (!stats_param->num_peer_stats) + goto adv_stats; + + ev->peer_stats = qdf_mem_malloc(sizeof(*ev->peer_stats) * + stats_param->num_peer_stats); + if (!ev->peer_stats) + return QDF_STATUS_E_NOMEM; + ev->num_peer_stats = stats_param->num_peer_stats; + + db2dbm_enabled = wmi_service_enabled(wmi_hdl, + wmi_service_hw_db2dbm_support); + for (i = 0; i < ev->num_peer_stats; i++) { + status = wmi_extract_peer_stats(wmi_hdl, data, i, &peer_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_peer_stats failed"); + continue; + } + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_stats.peer_macaddr, + ev->peer_stats[i].peer_macaddr); + ev->peer_stats[i].tx_rate = peer_stats.peer_tx_rate; + ev->peer_stats[i].rx_rate = peer_stats.peer_rx_rate; + if (db2dbm_enabled) + ev->peer_stats[i].peer_rssi = peer_stats.peer_rssi; + else + ev->peer_stats[i].peer_rssi = peer_stats.peer_rssi + + TGT_NOISE_FLOOR_DBM; + } + +adv_stats: + target_if_cp_stats_extract_peer_extd_stats(wmi_hdl, stats_param, ev, + data); + + /* Extract peer_adv_stats */ + ev->num_peer_adv_stats = stats_param->num_peer_adv_stats; + if (!ev->num_peer_adv_stats) + return QDF_STATUS_SUCCESS; + + ev->peer_adv_stats = qdf_mem_malloc(sizeof(*ev->peer_adv_stats) * + ev->num_peer_adv_stats); + if (!ev->peer_adv_stats) + return QDF_STATUS_E_NOMEM; + + peer_adv_stats = qdf_mem_malloc(sizeof(*peer_adv_stats) * + ev->num_peer_adv_stats); + if (!peer_adv_stats) { + qdf_mem_free(ev->peer_adv_stats); + return QDF_STATUS_E_NOMEM; + } + + status = wmi_extract_peer_adv_stats(wmi_hdl, data, peer_adv_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_peer_stats failed"); + qdf_mem_free(peer_adv_stats); + qdf_mem_free(ev->peer_adv_stats); + ev->peer_adv_stats = NULL; + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < ev->num_peer_adv_stats; i++) { + qdf_mem_copy(&ev->peer_adv_stats[i].peer_macaddr, + &peer_adv_stats[i].peer_macaddr, + QDF_MAC_ADDR_SIZE); + ev->peer_adv_stats[i].fcs_count = peer_adv_stats[i].fcs_count; + ev->peer_adv_stats[i].rx_bytes = peer_adv_stats[i].rx_bytes; + ev->peer_adv_stats[i].rx_count = peer_adv_stats[i].rx_count; + } + qdf_mem_free(peer_adv_stats); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS target_if_cp_stats_extract_cca_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + QDF_STATUS status; + struct wmi_host_congestion_stats stats = {0}; + + status = wmi_extract_cca_stats(wmi_hdl, data, &stats); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_SUCCESS; + + ev->cca_stats = qdf_mem_malloc(sizeof(*ev->cca_stats)); + if (!ev->cca_stats) + return QDF_STATUS_E_NOMEM; + + ev->cca_stats->vdev_id = stats.vdev_id; + ev->cca_stats->congestion = stats.congestion; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_MIB_STATS +static QDF_STATUS target_if_cp_stats_extract_mib_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + QDF_STATUS status; + + if (!stats_param->num_mib_stats) + return QDF_STATUS_SUCCESS; + + if (stats_param->num_mib_stats != MAX_MIB_STATS || + (stats_param->num_mib_extd_stats && + stats_param->num_mib_extd_stats != MAX_MIB_STATS)) { + cp_stats_err("number of mib stats wrong, num_mib_stats %d, num_mib_extd_stats %d", + stats_param->num_mib_stats, + stats_param->num_mib_extd_stats); + return QDF_STATUS_E_INVAL; + } + + ev->num_mib_stats = stats_param->num_mib_stats; + + ev->mib_stats = qdf_mem_malloc(sizeof(*ev->mib_stats)); + if (!ev->mib_stats) + return QDF_STATUS_E_NOMEM; + + status = wmi_extract_mib_stats(wmi_hdl, data, ev->mib_stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_mib_stats failed"); + return status; + } + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS target_if_cp_stats_extract_mib_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS target_if_cp_stats_extract_vdev_summary_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + uint32_t i, j; + QDF_STATUS status; + int32_t bcn_snr, dat_snr; + wmi_host_vdev_stats *vdev_stats; + bool db2dbm_enabled; + + ev->num_summary_stats = stats_param->num_vdev_stats; + if (!ev->num_summary_stats) + return QDF_STATUS_SUCCESS; + + ev->vdev_summary_stats = qdf_mem_malloc(sizeof(*ev->vdev_summary_stats) + * ev->num_summary_stats); + + if (!ev->vdev_summary_stats) + return QDF_STATUS_E_NOMEM; + + db2dbm_enabled = wmi_service_enabled(wmi_hdl, + wmi_service_hw_db2dbm_support); + + vdev_stats = qdf_mem_malloc(sizeof(*vdev_stats)); + if (!vdev_stats) { + cp_stats_err("malloc failed for vdev stats"); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < ev->num_summary_stats; i++) { + status = wmi_extract_vdev_stats(wmi_hdl, data, i, vdev_stats); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + bcn_snr = vdev_stats->vdev_snr.bcn_snr; + dat_snr = vdev_stats->vdev_snr.dat_snr; + ev->vdev_summary_stats[i].vdev_id = vdev_stats->vdev_id; + /*bcn_snr parameter can come as RSSi/SNR from the FW depending + on whether FW supports the RSSI reporting or not */ + if (!db2dbm_enabled) { + cp_stats_debug("vdev %d SNR bcn: %d data: %d", + ev->vdev_summary_stats[i].vdev_id, + bcn_snr, dat_snr); + } else { + cp_stats_debug("vdev %d RSSI bcn: %d data: %d", + ev->vdev_summary_stats[i].vdev_id, + bcn_snr, dat_snr); + } + for (j = 0; j < 4; j++) { + ev->vdev_summary_stats[i].stats.tx_frm_cnt[j] = + vdev_stats->tx_frm_cnt[j]; + ev->vdev_summary_stats[i].stats.fail_cnt[j] = + vdev_stats->fail_cnt[j]; + ev->vdev_summary_stats[i].stats.multiple_retry_cnt[j] = + vdev_stats->multiple_retry_cnt[j]; + } + + ev->vdev_summary_stats[i].stats.rx_frm_cnt = + vdev_stats->rx_frm_cnt; + ev->vdev_summary_stats[i].stats.rx_error_cnt = + vdev_stats->rx_err_cnt; + ev->vdev_summary_stats[i].stats.rx_discard_cnt = + vdev_stats->rx_discard_cnt; + ev->vdev_summary_stats[i].stats.ack_fail_cnt = + vdev_stats->ack_fail_cnt; + ev->vdev_summary_stats[i].stats.rts_succ_cnt = + vdev_stats->rts_succ_cnt; + ev->vdev_summary_stats[i].stats.rts_fail_cnt = + vdev_stats->rts_fail_cnt; + /* Update SNR and RSSI in SummaryStats */ + wlan_util_stats_get_rssi(db2dbm_enabled, bcn_snr, dat_snr, + &ev->vdev_summary_stats[i].stats.rssi); + ev->vdev_summary_stats[i].stats.snr = + ev->vdev_summary_stats[i].stats.rssi - + TGT_NOISE_FLOOR_DBM; + } + qdf_mem_free(vdev_stats); + + return QDF_STATUS_SUCCESS; +} + + +static QDF_STATUS target_if_cp_stats_extract_vdev_chain_rssi_stats( + struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, uint8_t *data) +{ + uint32_t i, j; + QDF_STATUS status; + int32_t bcn_snr, dat_snr; + struct wmi_host_per_chain_rssi_stats rssi_stats; + bool db2dbm_enabled; + + ev->num_chain_rssi_stats = stats_param->num_rssi_stats; + if (!ev->num_chain_rssi_stats) + return QDF_STATUS_SUCCESS; + + ev->vdev_chain_rssi = qdf_mem_malloc(sizeof(*ev->vdev_chain_rssi) * + ev->num_chain_rssi_stats); + if (!ev->vdev_chain_rssi) + return QDF_STATUS_E_NOMEM; + + db2dbm_enabled = wmi_service_enabled(wmi_hdl, + wmi_service_hw_db2dbm_support); + for (i = 0; i < ev->num_chain_rssi_stats; i++) { + status = wmi_extract_per_chain_rssi_stats(wmi_hdl, data, i, + &rssi_stats); + if (QDF_IS_STATUS_ERROR(status)) + continue; + ev->vdev_chain_rssi[i].vdev_id = rssi_stats.vdev_id; + + for (j = 0; j < MAX_NUM_CHAINS; j++) { + dat_snr = rssi_stats.rssi_avg_data[j]; + bcn_snr = rssi_stats.rssi_avg_beacon[j]; + cp_stats_nofl_debug("Chain %d SNR bcn: %d data: %d", j, + bcn_snr, dat_snr); + /* + * Get the absolute rssi value from the current rssi + * value the snr value is hardcoded into 0 in the + * qcacld-new/CORE stack + */ + wlan_util_stats_get_rssi(db2dbm_enabled, bcn_snr, + dat_snr, + &ev->vdev_chain_rssi[i]. + chain_rssi[j]); + } + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +target_if_cp_stats_extract_vdev_extd_stats(struct wmi_unified *wmi_hdl, + wmi_host_stats_event *stats_param, + struct stats_event *ev, + uint8_t *data) +{ + uint8_t i; + QDF_STATUS status; + struct wmi_host_vdev_prb_fils_stats *stats; + + ev->num_vdev_extd_stats = stats_param->num_vdev_extd_stats; + if (!ev->num_vdev_extd_stats) + return QDF_STATUS_SUCCESS; + + if (ev->num_vdev_extd_stats > WLAN_MAX_VDEVS) { + cp_stats_err("num_vdev_extd_stats is invalid: %u", + ev->num_vdev_extd_stats); + return QDF_STATUS_E_INVAL; + } + + ev->vdev_extd_stats = qdf_mem_malloc(sizeof(*ev->vdev_extd_stats) * + ev->num_vdev_extd_stats); + if (!ev->vdev_extd_stats) + return QDF_STATUS_E_NOMEM; + + stats = qdf_mem_malloc(sizeof(*stats) * ev->num_vdev_extd_stats); + + if (!stats) { + cp_stats_err("malloc failed for vdev extended stats"); + status = QDF_STATUS_E_NOMEM; + goto end; + } + + for (i = 0 ; i < ev->num_vdev_extd_stats; i++) { + status = wmi_extract_vdev_prb_fils_stats(wmi_hdl, data, + i, stats); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("wmi_extract_vdev_extd_stats failed"); + qdf_mem_free(stats); + goto end; + } + ev->vdev_extd_stats[i].vdev_id = stats[0].vdev_id; + ev->vdev_extd_stats[i].is_mlo_vdev_active = + stats[0].is_mlo_vdev_active; + ev->vdev_extd_stats[i].vdev_tx_power = stats[i].vdev_tx_power; + } + + qdf_mem_free(stats); + return status; + +end: + qdf_mem_free(ev->vdev_extd_stats); + ev->vdev_extd_stats = NULL; + return status; +} + +static QDF_STATUS target_if_cp_stats_extract_event(struct wmi_unified *wmi_hdl, + struct stats_event *ev, + uint8_t *data) +{ + QDF_STATUS status; + static uint8_t mac_seq = 0; + wmi_host_stats_event stats_param = {0}; + + status = wmi_extract_stats_param(wmi_hdl, data, &stats_param); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("stats param extract failed: %d", status); + return status; + } + cp_stats_nofl_debug("num: pdev: %d, pdev_extd: %d, vdev: %d, vdev_extd: %d, " + "peer: %d, peer_extd: %d rssi: %d, mib %d, mib_extd %d, " + "bcnflt: %d, channel: %d, bcn: %d, peer_extd2: %d, " + "last_event: %x, stats id: %d", + stats_param.num_pdev_stats, + stats_param.num_pdev_ext_stats, + stats_param.num_vdev_stats, + stats_param.num_vdev_extd_stats, + stats_param.num_peer_stats, + stats_param.num_peer_extd_stats, + stats_param.num_rssi_stats, + stats_param.num_mib_stats, + stats_param.num_mib_extd_stats, + stats_param.num_bcnflt_stats, + stats_param.num_chan_stats, + stats_param.num_bcn_stats, + stats_param.num_peer_adv_stats, + stats_param.last_event, + stats_param.stats_id); + + ev->last_event = stats_param.last_event; + ev->mac_seq_num = mac_seq; + if (IS_MSB_SET(ev->last_event) && IS_LSB_SET(ev->last_event)) + mac_seq = 0; + else + mac_seq++; + + status = target_if_cp_stats_extract_pdev_stats(wmi_hdl, &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_peer_stats(wmi_hdl, &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_cca_stats(wmi_hdl, &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_vdev_summary_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_vdev_chain_rssi_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_mib_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_pmf_bcn_protect_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_pdev_extd_stats(wmi_hdl, + &stats_param, + ev, data); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = target_if_cp_stats_extract_vdev_extd_stats(wmi_hdl, + &stats_param, + ev, data); + return status; +} + +uint8_t target_if_mc_cp_get_mac_id(struct vdev_mlme_obj *vdev_mlme) +{ + uint8_t mac_id = 0; + + if (wlan_reg_is_24ghz_ch_freq(vdev_mlme->vdev->vdev_mlme.des_chan->ch_freq)) + mac_id = TGT_MAC_ID_24G; + else + mac_id = TGT_MAC_ID_5G; + + return mac_id; +} + +/** + * target_if_mc_cp_stats_stats_event_handler() - function to handle stats event + * from firmware. + * @scn: scn handle + * @data: data buffer for event + * @datalen: data length + * + * Return: status of operation. + */ +static int target_if_mc_cp_stats_stats_event_handler(ol_scn_t scn, + uint8_t *data, + uint32_t datalen) +{ + QDF_STATUS status; + struct stats_event *ev; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_cp_stats_rx_ops *rx_ops; + + if (!scn || !data) { + cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + cp_stats_err("null psoc"); + return -EINVAL; + } + + rx_ops = target_if_cp_stats_get_rx_ops(psoc); + if (!rx_ops || !rx_ops->process_stats_event) { + cp_stats_err("callback not registered"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return -EINVAL; + } + + ev = qdf_mem_malloc(sizeof(*ev)); + if (!ev) { + cp_stats_err(""); + return -EINVAL; + } + + status = target_if_cp_stats_extract_event(wmi_handle, ev, data); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("extract event failed"); + goto end; + } + + status = rx_ops->process_stats_event(psoc, ev); + +end: + target_if_cp_stats_free_stats_event(ev); + qdf_mem_free(ev); + + return qdf_status_to_os_return(status); +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +static int target_if_mc_cp_stats_big_data_stats_event_handler(ol_scn_t scn, + uint8_t *data, + uint32_t datalen) +{ + QDF_STATUS status; + struct big_data_stats_event ev = {0}; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_cp_stats_rx_ops *rx_ops; + + if (!scn || !data) { + cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + cp_stats_err("null psoc"); + return -EINVAL; + } + + rx_ops = target_if_cp_stats_get_rx_ops(psoc); + if (!rx_ops || !rx_ops->process_big_data_stats_event) { + cp_stats_err("callback not registered"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_big_data_stats_param(wmi_handle, data, &ev); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("extract event failed"); + goto end; + } + + status = rx_ops->process_big_data_stats_event(psoc, &ev); + +end: + return qdf_status_to_os_return(status); +} + +/** + * target_if_cp_stats_send_big_data_stats_req() - API to send request to wmi + * @psoc: pointer to psoc object + * @req: pointer to object containing stats request parameters + * + * Return: status of operation. + */ +static QDF_STATUS target_if_cp_stats_send_big_data_stats_req( + struct wlan_objmgr_psoc *psoc, + struct request_info *req) + +{ + struct wmi_unified *wmi_handle; + struct stats_request_params param = {0}; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + param.vdev_id = req->vdev_id; + + return wmi_unified_big_data_stats_request_send(wmi_handle, + ¶m); +} +#endif + +static QDF_STATUS +target_if_cp_stats_extract_peer_stats_event(struct wmi_unified *wmi_hdl, + struct stats_event *ev, + uint8_t *data) +{ + QDF_STATUS status; + wmi_host_stats_event stats_param = {0}; + struct peer_stats_info_ext_event *peer_stats_info; + wmi_host_peer_stats_info stats_info; + uint32_t peer_stats_info_size; + int i, j; + uint32_t tx_rate_count_idx = 0, rx_rate_count_idx = 0; + + status = wmi_extract_peer_stats_param(wmi_hdl, data, &stats_param); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("peer stats param extract failed: %d", status); + return status; + } + + if (stats_param.num_peer_stats_info_ext == 0) { + cp_stats_err("num_peer_stats_info_ext is 0"); + return status; + } + + ev->num_peer_stats_info_ext = stats_param.num_peer_stats_info_ext; + peer_stats_info_size = sizeof(*ev->peer_stats_info_ext) * + ev->num_peer_stats_info_ext; + ev->peer_stats_info_ext = qdf_mem_malloc(peer_stats_info_size); + if (!ev->peer_stats_info_ext) { + ev->num_peer_stats_info_ext = 0; + return QDF_STATUS_E_NOMEM; + } + + peer_stats_info = ev->peer_stats_info_ext; + for (i = 0; i < ev->num_peer_stats_info_ext; i++) { + status = wmi_extract_peer_stats_info(wmi_hdl, data, + i, &stats_info); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("peer stats info extract failed: %d", + status); + target_if_cp_stats_free_peer_stats_info_ext(ev); + return status; + } + qdf_mem_copy(&peer_stats_info->peer_macaddr, + &stats_info.peer_macaddr, + sizeof(peer_stats_info->peer_macaddr)); + peer_stats_info->tx_packets = stats_info.tx_packets; + peer_stats_info->tx_bytes = stats_info.tx_bytes; + peer_stats_info->rx_packets = stats_info.rx_packets; + peer_stats_info->rx_bytes = stats_info.rx_bytes; + peer_stats_info->tx_retries = stats_info.tx_retries; + peer_stats_info->tx_failed = stats_info.tx_failed; + peer_stats_info->tx_succeed = stats_info.tx_succeed; + peer_stats_info->rssi = stats_info.peer_rssi; + peer_stats_info->tx_rate = stats_info.last_tx_bitrate_kbps; + peer_stats_info->tx_rate_code = stats_info.last_tx_rate_code; + peer_stats_info->rx_rate = stats_info.last_rx_bitrate_kbps; + peer_stats_info->rx_rate_code = stats_info.last_rx_rate_code; + for (j = 0; j < WMI_MAX_CHAINS; j++) + peer_stats_info->peer_rssi_per_chain[j] = + stats_info.peer_rssi_per_chain[j]; + + if (stats_info.num_tx_rate_counts) { + peer_stats_info->num_tx_rate_counts = + stats_info.num_tx_rate_counts; + status = wmi_extract_peer_tx_pkt_per_mcs( + wmi_hdl, data, + tx_rate_count_idx, + &stats_info); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("tx rate count extract failed"); + target_if_cp_stats_free_peer_stats_info_ext(ev); + return status; + } + tx_rate_count_idx += + peer_stats_info->num_tx_rate_counts; + + peer_stats_info->tx_pkt_per_mcs = + stats_info.tx_pkt_per_mcs; + stats_info.tx_pkt_per_mcs = NULL; + } + if (stats_info.num_rx_rate_counts) { + peer_stats_info->num_rx_rate_counts = + stats_info.num_rx_rate_counts; + status = wmi_extract_peer_rx_pkt_per_mcs( + wmi_hdl, data, + rx_rate_count_idx, + &stats_info); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("rx rate count extract failed"); + target_if_cp_stats_free_peer_stats_info_ext(ev); + return status; + } + rx_rate_count_idx += + peer_stats_info->num_rx_rate_counts; + + peer_stats_info->rx_pkt_per_mcs = + stats_info.rx_pkt_per_mcs; + stats_info.rx_pkt_per_mcs = NULL; + } + peer_stats_info++; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_mc_cp_stats_peer_stats_info_event_handler() - function to handle + * peer stats info event from firmware. + * @scn: scn handle + * @data: data buffer for event + * @datalen: data length + * + * Return: status of operation. + */ +static int target_if_mc_cp_stats_peer_stats_info_event_handler(ol_scn_t scn, + uint8_t *data, + uint32_t datalen) +{ + QDF_STATUS status; + struct stats_event ev = {0}; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_cp_stats_rx_ops *rx_ops; + + if (!scn || !data) { + cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + cp_stats_err("null psoc"); + return -EINVAL; + } + + rx_ops = target_if_cp_stats_get_rx_ops(psoc); + if (!rx_ops || !rx_ops->process_stats_event) { + cp_stats_err("callback not registered"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return -EINVAL; + } + + status = target_if_cp_stats_extract_peer_stats_event(wmi_handle, + &ev, data); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("extract event failed"); + goto end; + } + + status = rx_ops->process_stats_event(psoc, &ev); + +end: + target_if_cp_stats_free_stats_event(&ev); + + return qdf_status_to_os_return(status); +} + +static void target_if_cp_stats_inc_wake_lock_stats(uint32_t reason, + struct wake_lock_stats *stats, + uint32_t *unspecified_wake_count) +{ + switch (reason) { + case WOW_REASON_UNSPECIFIED: + (*unspecified_wake_count)++; + break; + + case WOW_REASON_ASSOC_REQ_RECV: + stats->mgmt_assoc++; + break; + + case WOW_REASON_DISASSOC_RECVD: + stats->mgmt_disassoc++; + break; + + case WOW_REASON_ASSOC_RES_RECV: + stats->mgmt_assoc_resp++; + break; + + case WOW_REASON_REASSOC_REQ_RECV: + stats->mgmt_reassoc++; + break; + + case WOW_REASON_REASSOC_RES_RECV: + stats->mgmt_reassoc_resp++; + break; + + case WOW_REASON_AUTH_REQ_RECV: + stats->mgmt_auth++; + break; + + case WOW_REASON_DEAUTH_RECVD: + stats->mgmt_deauth++; + break; + + case WOW_REASON_ACTION_FRAME_RECV: + stats->mgmt_action++; + break; + + case WOW_REASON_NLOD: + stats->pno_match_wake_up_count++; + break; + + case WOW_REASON_NLO_SCAN_COMPLETE: + stats->pno_complete_wake_up_count++; + break; + + case WOW_REASON_LOW_RSSI: + stats->low_rssi_wake_up_count++; + break; + + case WOW_REASON_EXTSCAN: + stats->gscan_wake_up_count++; + break; + + case WOW_REASON_RSSI_BREACH_EVENT: + stats->rssi_breach_wake_up_count++; + break; + + case WOW_REASON_OEM_RESPONSE_EVENT: + stats->oem_response_wake_up_count++; + break; + + case WOW_REASON_11D_SCAN: + stats->scan_11d++; + break; + + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + stats->pwr_save_fail_detected++; + break; + + case WOW_REASON_LOCAL_DATA_UC_DROP: + stats->uc_drop_wake_up_count++; + break; + + case WOW_REASON_FATAL_EVENT_WAKE: + stats->fatal_event_wake_up_count++; + break; + + default: + break; + } +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +static QDF_STATUS +target_if_register_big_data_event_handler(struct wmi_unified *wmi_handle) +{ + return wmi_unified_register_event_handler( + wmi_handle, wmi_vdev_send_big_data_p2_eventid, + target_if_mc_cp_stats_big_data_stats_event_handler, + WMI_RX_WORK_CTX); +} + +static void +target_if_unregister_big_data_event_handler(struct wmi_unified *wmi_handle) +{ + wmi_unified_unregister_event_handler(wmi_handle, + wmi_vdev_send_big_data_p2_eventid); +} + +static QDF_STATUS +target_if_big_data_stats_register_tx_ops(struct wlan_lmac_if_cp_stats_tx_ops + *cp_stats_tx_ops) +{ + cp_stats_tx_ops->send_req_big_data_stats = + target_if_cp_stats_send_big_data_stats_req; + return QDF_STATUS_SUCCESS; +} + +static void +target_if_big_data_stats_unregister_tx_ops(struct wlan_lmac_if_cp_stats_tx_ops + *cp_stats_tx_ops) +{ + cp_stats_tx_ops->send_req_big_data_stats = NULL; +} +#else +static QDF_STATUS +target_if_register_big_data_event_handler(struct wmi_unified *wmi_handle) +{ + return QDF_STATUS_SUCCESS; +} + +static void +target_if_unregister_big_data_event_handler(struct wmi_unified *wmi_handle) +{} + +static QDF_STATUS +target_if_big_data_stats_register_tx_ops(struct wlan_lmac_if_cp_stats_tx_ops + *cp_stats_tx_ops) +{ + return QDF_STATUS_SUCCESS; +} + +static void +target_if_big_data_stats_unregister_tx_ops(struct wlan_lmac_if_cp_stats_tx_ops + *cp_stats_tx_ops) +{} +#endif + +#ifdef WLAN_FEATURE_SON +static int +target_if_mc_cp_stats_inst_rssi_stats_event_handler(ol_scn_t scn, + uint8_t *data, + uint32_t datalen) +{ + QDF_STATUS status; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wmi_host_inst_rssi_stats_resp ev = {0}; + + if (!scn || !data) { + cp_stats_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + cp_stats_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_inst_rssi_stats_resp(wmi_handle, data, &ev); + if (QDF_IS_STATUS_ERROR(status)) { + cp_stats_err("extract event failed"); + return qdf_status_to_os_return(status); + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, ev.peer_macaddr.bytes, + WLAN_CP_STATS_ID); + if (!peer) { + cp_stats_err("null peer"); + return -EINVAL; + } + + wlan_son_deliver_inst_rssi(wlan_peer_get_vdev(peer), + peer, + ev.inst_rssi); + + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + return 0; +} + +static QDF_STATUS +target_if_register_inst_rssi_event_handler(struct wmi_unified *wmi_handle) +{ + return wmi_unified_register_event_handler(wmi_handle, + wmi_inst_rssi_stats_event_id, + target_if_mc_cp_stats_inst_rssi_stats_event_handler, + WMI_RX_SERIALIZER_CTX); +} + +static void +target_if_unregister_inst_rssi_event_handler(struct wmi_unified *wmi_handle) +{ + wmi_unified_unregister_event_handler(wmi_handle, + wmi_inst_rssi_stats_event_id); +} +#else +static QDF_STATUS +target_if_register_inst_rssi_event_handler(struct wmi_unified *wmi_handle) +{ + return QDF_STATUS_SUCCESS; +} + +static void +target_if_unregister_inst_rssi_event_handler(struct wmi_unified *wmi_handle) +{ +} +#endif + +static QDF_STATUS +target_if_mc_cp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret_val; + struct wmi_unified *wmi_handle; + + if (!psoc) { + cp_stats_err("PSOC is NULL!"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + ret_val = wmi_unified_register_event_handler( + wmi_handle, + wmi_update_stats_event_id, + target_if_mc_cp_stats_stats_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(ret_val)) + cp_stats_err("Failed to register stats event cb"); + + ret_val = wmi_unified_register_event_handler(wmi_handle, + wmi_peer_stats_info_event_id, + target_if_mc_cp_stats_peer_stats_info_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(ret_val)) + cp_stats_err("Failed to register peer stats info event cb"); + + ret_val = target_if_register_big_data_event_handler(wmi_handle); + if (QDF_IS_STATUS_ERROR(ret_val)) + cp_stats_err("Failed to register big data stats info event cb"); + + ret_val = target_if_register_inst_rssi_event_handler(wmi_handle); + if (QDF_IS_STATUS_ERROR(ret_val)) + cp_stats_err("Failed to register inst rssi stats event cb"); + + return ret_val; +} + +static QDF_STATUS +target_if_mc_cp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + cp_stats_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + target_if_unregister_inst_rssi_event_handler(wmi_handle); + target_if_unregister_big_data_event_handler(wmi_handle); + + wmi_unified_unregister_event_handler(wmi_handle, + wmi_peer_stats_info_event_id); + wmi_unified_unregister_event_handler(wmi_handle, + wmi_update_stats_event_id); + + return QDF_STATUS_SUCCESS; +} + +static uint32_t get_stats_id(enum stats_req_type type) +{ + switch (type) { + default: + break; + case TYPE_CONNECTION_TX_POWER: + return WMI_REQUEST_PDEV_STAT | WMI_REQUEST_VDEV_EXTD_STAT; + case TYPE_CONGESTION_STATS: + return WMI_REQUEST_PDEV_STAT | WMI_REQUEST_PDEV_EXTD_STAT; + case TYPE_PEER_STATS: + return WMI_REQUEST_PEER_STAT | WMI_REQUEST_PEER_EXTD_STAT; + case TYPE_STATION_STATS: + return (WMI_REQUEST_AP_STAT | + WMI_REQUEST_PEER_STAT | + WMI_REQUEST_VDEV_STAT | + WMI_REQUEST_VDEV_EXTD_STAT | + WMI_REQUEST_PDEV_STAT | + WMI_REQUEST_PEER_EXTD2_STAT | + WMI_REQUEST_RSSI_PER_CHAIN_STAT | + WMI_REQUEST_PMF_BCN_PROTECT_STAT); + case TYPE_MIB_STATS: + return (WMI_REQUEST_MIB_STAT | WMI_REQUEST_MIB_EXTD_STAT); + } + + return 0; +} + +/** + * target_if_cp_stats_send_stats_req() - API to send stats request to wmi + * @psoc: pointer to psoc object + * @type: Type of stats requested + * @req: pointer to object containing stats request parameters + * + * Return: status of operation. + */ +static QDF_STATUS target_if_cp_stats_send_stats_req( + struct wlan_objmgr_psoc *psoc, + enum stats_req_type type, + struct request_info *req) + +{ + struct wmi_unified *wmi_handle; + struct stats_request_params param = {0}; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + /* refer (WMI_REQUEST_STATS_CMDID) */ + param.stats_id = get_stats_id(type); + param.vdev_id = req->vdev_id; + param.pdev_id = req->pdev_id; + + /* only very frequent periodic stats needs to go over QMI. + * for that, wlan_hdd_qmi_get_sync_resume/wlan_hdd_qmi_put_suspend + * needs to be called to cover the period between qmi send and + * qmi response. + */ + if (TYPE_STATION_STATS == type) + param.is_qmi_send_support = true; + + return wmi_unified_stats_request_send(wmi_handle, req->peer_mac_addr, + ¶m); +} + +/** + * target_if_set_pdev_stats_update_period(): API to set pdev stats update + * period to FW + * @psoc: pointer to psoc object + * @pdev_id: pdev id + * @val: pdev stats update period, 0: disabled periodical stats report. + * + * Return: status of operation + */ +static QDF_STATUS +target_if_set_pdev_stats_update_period(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t val) +{ + struct wmi_unified *wmi_handle; + struct pdev_params pdev_param = {0}; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + cp_stats_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + pdev_param.param_id = wmi_pdev_param_pdev_stats_update_period; + pdev_param.param_value = val; + return wmi_unified_pdev_param_send(wmi_handle, + &pdev_param, + pdev_id); +} + +/** + * target_if_mc_cp_stats_unregister_handlers() - Unregisters wmi event handlers + * of control plane stats & twt session stats info + * @psoc: PSOC object + * + * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure + */ +static QDF_STATUS +target_if_mc_cp_stats_unregister_handlers(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + + qdf_status = target_if_twt_session_params_unregister_evt_hdlr(psoc); + if (qdf_status == QDF_STATUS_SUCCESS) + qdf_status = + target_if_mc_cp_stats_unregister_event_handler(psoc); + + return qdf_status; +} + +/** + * target_if_mc_cp_stats_register_handlers() - Registers wmi event handlers for + * control plane stats & twt session stats info + * @psoc: PSOC object + * + * Return: QDF_STATUS_SUCCESS on success or QDF error values on failure + */ +static QDF_STATUS +target_if_mc_cp_stats_register_handlers(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + + qdf_status = target_if_mc_cp_stats_register_event_handler(psoc); + if (qdf_status != QDF_STATUS_SUCCESS) + return qdf_status; + + qdf_status = target_if_twt_session_params_register_evt_hdlr(psoc); + if (qdf_status != QDF_STATUS_SUCCESS) + target_if_mc_cp_stats_unregister_event_handler(psoc); + + return qdf_status; +} + +/** + * target_if_cp_stats_send_peer_stats_req() - API to send peer stats request + * to wmi + * @psoc: pointer to psoc object + * @req: pointer to object containing peer stats request parameters + * + * Return: status of operation. + */ +static QDF_STATUS +target_if_cp_stats_send_peer_stats_req(struct wlan_objmgr_psoc *psoc, + struct request_info *req) + +{ + struct wmi_unified *wmi_handle; + struct peer_stats_request_params param = {0}; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + cp_stats_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + param.request_type = WMI_REQUEST_ONE_PEER_STATS_INFO; + param.vdev_id = req->vdev_id; + qdf_mem_copy(param.peer_mac_addr, req->peer_mac_addr, + QDF_MAC_ADDR_SIZE); + param.reset_after_request = 0; + + return wmi_unified_peer_stats_request_send(wmi_handle, ¶m); +} + +static QDF_STATUS +target_if_mc_cp_stats_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_cp_stats_tx_ops *cp_stats_tx_ops; + + if (!tx_ops) { + cp_stats_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + cp_stats_tx_ops = &tx_ops->cp_stats_tx_ops; + if (!cp_stats_tx_ops) { + cp_stats_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + cp_stats_tx_ops->inc_wake_lock_stats = + target_if_cp_stats_inc_wake_lock_stats; + cp_stats_tx_ops->send_req_stats = target_if_cp_stats_send_stats_req; + cp_stats_tx_ops->set_pdev_stats_update_period = + target_if_set_pdev_stats_update_period; + cp_stats_tx_ops->send_req_peer_stats = + target_if_cp_stats_send_peer_stats_req; + + target_if_big_data_stats_register_tx_ops(cp_stats_tx_ops); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +target_if_mc_cp_stats_unregister_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_cp_stats_tx_ops *cp_stats_tx_ops; + + if (!tx_ops) { + cp_stats_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + cp_stats_tx_ops = &tx_ops->cp_stats_tx_ops; + if (!cp_stats_tx_ops) { + cp_stats_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + target_if_big_data_stats_unregister_tx_ops(cp_stats_tx_ops); + cp_stats_tx_ops->inc_wake_lock_stats = NULL; + cp_stats_tx_ops->send_req_stats = NULL; + cp_stats_tx_ops->set_pdev_stats_update_period = NULL; + cp_stats_tx_ops->send_req_peer_stats = NULL; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_SUPPORT_LEGACY_CP_STATS_HANDLERS +QDF_STATUS +target_if_cp_stats_register_legacy_event_handler(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct wlan_lmac_if_tx_ops *tx_ops; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + cp_stats_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + status = target_if_mc_cp_stats_register_tx_ops(tx_ops); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return target_if_mc_cp_stats_register_handlers(psoc); +} + +QDF_STATUS +target_if_cp_stats_unregister_legacy_event_handler( + struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct wlan_lmac_if_tx_ops *tx_ops; + + tx_ops = wlan_psoc_get_lmac_if_txops(psoc); + if (!tx_ops) { + cp_stats_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + status = target_if_mc_cp_stats_unregister_tx_ops(tx_ops); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return target_if_mc_cp_stats_unregister_handlers(psoc); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/denylist_mgr/inc/target_if_dlm.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/denylist_mgr/inc/target_if_dlm.h new file mode 100644 index 0000000000..d620ae65f3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/denylist_mgr/inc/target_if_dlm.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Target interface file for denylist manager component to + * declare api's which shall be used by denylist manager component + * in target if internally. + */ + +#ifndef __TARGET_IF_DLM_H +#define __TARGET_IF_DLM_H + +#include "wlan_dlm_public_struct.h" + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * target_if_dlm_send_reject_ap_list() - API to send reject ap list to FW + * @pdev: pdev object + * @reject_params: This contains the reject ap list, and the num of BSSIDs + * + * This API will send the reject ap list to the target for it to handle roaming + * case scenarios. + * + * Return: Qdf status + */ +QDF_STATUS +target_if_dlm_send_reject_ap_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_params *reject_params); + +/** + * target_if_dlm_register_tx_ops() - Register dlm tx ops + * @dlm_tx_ops: DLM tx ops + * + * This API will register the tx ops used by the DLM to send commands to the + * target. + * + * Return: void + */ +void target_if_dlm_register_tx_ops(struct wlan_dlm_tx_ops *dlm_tx_ops); +#else +static inline void target_if_dlm_register_tx_ops( + struct wlan_dlm_tx_ops *dlm_tx_ops) +{ +} +#endif //WLAN_FEATURE_ROAM_OFFLOAD + +#endif //__TARGET_IF_DLM_H diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/denylist_mgr/src/target_if_dlm.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/denylist_mgr/src/target_if_dlm.c new file mode 100644 index 0000000000..79de674e64 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/denylist_mgr/src/target_if_dlm.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Target interface file for denylist manager component to + * Implement api's which shall be used by denylist manager component + * in target if internally. + */ + +#include +#include "target_if.h" + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS +target_if_dlm_send_reject_ap_list(struct wlan_objmgr_pdev *pdev, + struct reject_ap_params *reject_params) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_send_reject_ap_list(wmi_handle, reject_params); +} + +void target_if_dlm_register_tx_ops(struct wlan_dlm_tx_ops *dlm_tx_ops) +{ + if (!dlm_tx_ops) { + target_if_err("dlm_tx_ops is null"); + return; + } + + dlm_tx_ops->dlm_send_reject_ap_list = target_if_dlm_send_reject_ap_list; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/disa/inc/target_if_disa.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/disa/inc/target_if_disa.h new file mode 100644 index 0000000000..c6753bdef8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/disa/inc/target_if_disa.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various api/struct which shall be used + * by disa component for wmi cmd (tx path) and + * event (rx) handling. + */ + +#ifndef _TARGET_IF_DISA_H_ +#define _TARGET_IF_DISA_H_ + +#include +#include +#include "wlan_disa_obj_mgmt_public_struct.h" + +/** + * target_if_disa_encrypt_decrypt_req() - Send encrypt/decrypt request to + * target. + * @psoc: objmgr psoc handle + * @req: Encrypt/decrypt request params + * + * Return: QDF status + */ +QDF_STATUS target_if_disa_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req); + +/** + * target_if_encrypt_decrypt_event_handler() - Collect encrypt/decrypt request + * event from the target and pass on the data to tgt api of DISA. + * @scn_handle: target handle + * @data: event data + * @data_len: data length + * + * Return: QDF status + */ +int target_if_encrypt_decrypt_event_handler(ol_scn_t scn_handle, uint8_t *data, + uint32_t data_len); + +/** + * target_if_disa_register_tx_ops() - Register DISA component TX OPS + * @tx_ops: DISA if transmit ops + * + * Return: None + */ +void target_if_disa_register_tx_ops(struct wlan_disa_tx_ops *tx_ops); + +/** + * target_if_disa_register_ev_handlers() - Register disa event handlers. + * @psoc:objmgr psoc handle + * + * Return: QDF status + */ +QDF_STATUS +target_if_disa_register_ev_handlers(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_disa_unregister_ev_handlers() - Unregister disa event handlers. + * @psoc:objmgr psoc handle + * + * Return: QDF status + */ +QDF_STATUS +target_if_disa_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc); +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/disa/src/target_if_disa.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/disa/src/target_if_disa.c new file mode 100644 index 0000000000..6f0e1fbaac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/disa/src/target_if_disa.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Target interface file for disa component to + * Implement api's which shall be used by disa component + * in target if internally. + */ + +#include "target_if.h" +#include "target_if_disa.h" +#include "wlan_disa_tgt_api.h" +#include "wlan_disa_public_struct.h" +#include + +int +target_if_encrypt_decrypt_event_handler(ol_scn_t scn_handle, uint8_t *data, + uint32_t data_len) +{ + struct disa_encrypt_decrypt_resp_params resp; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + + if (!data) { + target_if_err("Invalid pointer"); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn_handle); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return -EINVAL; + } + + if (wmi_extract_encrypt_decrypt_resp_params(wmi_handle, data, &resp) != + QDF_STATUS_SUCCESS) { + target_if_err("Extraction of encrypt decrypt resp params failed"); + return -EINVAL; + } + + tgt_disa_encrypt_decrypt_resp(psoc, &resp); + + return 0; +} + +QDF_STATUS +target_if_disa_register_ev_handlers(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event(wmi_handle, + wmi_vdev_encrypt_decrypt_data_rsp_event_id, + target_if_encrypt_decrypt_event_handler); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register Scan match event cb"); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS +target_if_disa_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_unregister_event(wmi_handle, + wmi_vdev_encrypt_decrypt_data_rsp_event_id); + if (status) { + target_if_err("Failed to unregister Scan match event cb"); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS +target_if_disa_encrypt_decrypt_req(struct wlan_objmgr_psoc *psoc, + struct disa_encrypt_decrypt_req_params *req) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_encrypt_decrypt_send_cmd(wmi_handle, req); +} + + +void target_if_disa_register_tx_ops(struct wlan_disa_tx_ops *disa_tx_ops) +{ + if (!disa_tx_ops) { + target_if_err("disa_tx_ops is null"); + return; + } + + disa_tx_ops->disa_encrypt_decrypt_req = + target_if_disa_encrypt_decrypt_req; + disa_tx_ops->disa_register_ev_handlers = + target_if_disa_register_ev_handlers; + disa_tx_ops->disa_unregister_ev_handlers = + target_if_disa_unregister_ev_handlers; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/dp/inc/target_if_dp_comp.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/dp/inc/target_if_dp_comp.h new file mode 100644 index 0000000000..56c558385b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/dp/inc/target_if_dp_comp.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_dp_comp.h + */ + +#ifndef _WLAN_DP_COMP_TGT_IF_H_ +#define _WLAN_DP_COMP_TGT_IF_H_ + +#include "qdf_types.h" +#include "wlan_dp_public_struct.h" +#include +#include +#include +#include +#include +#include +#include + +/** + * target_if_dp_register_tx_ops() - registers dp tx ops + * @sb_ops: tx ops + * + * Return: none + */ +void target_if_dp_register_tx_ops(struct wlan_dp_psoc_sb_ops *sb_ops); + +/** + * target_if_dp_register_rx_ops() - registers dp rx ops + * @nb_ops: rx ops + * + * Return: none + */ +void target_if_dp_register_rx_ops(struct wlan_dp_psoc_nb_ops *nb_ops); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/dp/src/target_if_dp_comp.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/dp/src/target_if_dp_comp.c new file mode 100644 index 0000000000..0fe7e5bd78 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/dp/src/target_if_dp_comp.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_dp_comp.c + */ + +#include "target_if_dp_comp.h" +#include "target_if.h" +#include "qdf_status.h" +#include "wmi.h" +#include "wmi_unified_api.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_dp_public_struct.h" +#include "cdp_txrx_cmn.h" +#include "cdp_txrx_ops.h" +#include "wlan_dp_main.h" +#include + +/** + * target_if_dp_get_arp_stats_event_handler() - arp stats event handler + * @scn: scn + * @data: buffer with event + * @datalen: buffer length + * + * Return: Return: 0 on success, failure code otherwise. + */ +static int +target_if_dp_get_arp_stats_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *param_buf; + wmi_vdev_get_arp_stats_event_fixed_param *data_event; + wmi_vdev_get_connectivity_check_stats *connect_stats_event; + struct wlan_objmgr_psoc *psoc; + struct wlan_dp_psoc_nb_ops *nb_ops; + uint8_t *buf_ptr; + struct dp_rsp_stats rsp = {0}; + + if (!scn || !data) { + dp_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + param_buf = (WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *)data; + if (!param_buf) { + dp_err("Invalid get arp stats event"); + return -EINVAL; + } + data_event = param_buf->fixed_param; + if (!data_event) { + dp_err("Invalid get arp stats data event"); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + dp_err("null psoc"); + return -EINVAL; + } + + nb_ops = dp_intf_get_rx_ops(psoc); + if (!nb_ops) { + dp_err("null tx ops"); + return -EINVAL; + } + + rsp.arp_req_enqueue = data_event->arp_req_enqueue; + rsp.vdev_id = data_event->vdev_id; + rsp.arp_req_tx_success = data_event->arp_req_tx_success; + rsp.arp_req_tx_failure = data_event->arp_req_tx_failure; + rsp.arp_rsp_recvd = data_event->arp_rsp_recvd; + rsp.out_of_order_arp_rsp_drop_cnt = + data_event->out_of_order_arp_rsp_drop_cnt; + rsp.dad_detected = data_event->dad_detected; + rsp.connect_status = data_event->connect_status; + rsp.ba_session_establishment_status = + data_event->ba_session_establishment_status; + + buf_ptr = (uint8_t *)data_event; + buf_ptr = buf_ptr + sizeof(wmi_vdev_get_arp_stats_event_fixed_param) + + WMI_TLV_HDR_SIZE; + connect_stats_event = (wmi_vdev_get_connectivity_check_stats *)buf_ptr; + + if (((connect_stats_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_vdev_get_connectivity_check_stats)) { + rsp.connect_stats_present = true; + rsp.tcp_ack_recvd = connect_stats_event->tcp_ack_recvd; + rsp.icmpv4_rsp_recvd = connect_stats_event->icmpv4_rsp_recvd; + dp_debug("tcp_ack_recvd %d icmpv4_rsp_recvd %d", + connect_stats_event->tcp_ack_recvd, + connect_stats_event->icmpv4_rsp_recvd); + } + + nb_ops->osif_dp_get_arp_stats_evt(psoc, &rsp); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dp_arp_stats_register_event_handler() - register event handler + * @psoc: psoc handle + * + * Return: Return: 0 on success, failure code otherwise. + */ +static QDF_STATUS +target_if_dp_arp_stats_register_event_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + QDF_STATUS ret_val; + + if (!psoc) { + dp_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + dp_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + ret_val = wmi_unified_register_event_handler(wmi_handle, + wmi_get_arp_stats_req_id, + target_if_dp_get_arp_stats_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(ret_val)) + dp_err("Failed to register event_handler"); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dp_arp_stats_unregister_event_handler() - unregister event handler + * @psoc: psoc handle + * + * Return: Return: 0 on success, failure code otherwise. + */ +static QDF_STATUS +target_if_dp_arp_stats_unregister_event_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + dp_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + dp_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + wmi_unified_unregister_event_handler(wmi_handle, + wmi_get_arp_stats_req_id); + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dp_get_arp_req_stats() - send get arp stats request command to fw + * @psoc: psoc handle + * @req_buf: get arp stats request buffer + * + * Return: Return: 0 on success, failure code otherwise. + */ +static QDF_STATUS +target_if_dp_get_arp_req_stats(struct wlan_objmgr_psoc *psoc, + struct dp_get_arp_stats_params *req_buf) +{ + QDF_STATUS status; + struct get_arp_stats *arp_stats; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) { + dp_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + dp_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + req_buf->vdev_id, + WLAN_DP_ID); + if (!vdev) { + dp_err("Can't get vdev by vdev_id:%d", req_buf->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!wlan_cm_is_vdev_active(vdev)) { + dp_debug("vdev id:%d is not started", req_buf->vdev_id); + status = QDF_STATUS_E_INVAL; + goto release_ref; + } + + arp_stats = (struct get_arp_stats *)req_buf; + status = wmi_unified_get_arp_stats_req(wmi_handle, arp_stats); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("failed to send get arp stats to FW"); +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + return status; +} + +/** + * target_if_dp_set_arp_req_stats() - send set arp stats request command to fw + * @psoc: psoc handle + * @req_buf: set srp stats request buffer + * + * Return: Return: 0 on success, failure code otherwise. + */ +static QDF_STATUS +target_if_dp_set_arp_req_stats(struct wlan_objmgr_psoc *psoc, + struct dp_set_arp_stats_params *req_buf) +{ + QDF_STATUS status; + struct set_arp_stats *arp_stats; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) { + dp_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + dp_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + req_buf->vdev_id, + WLAN_DP_ID); + if (!vdev) { + dp_err("Can't get vdev by vdev_id:%d", req_buf->vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wlan_vdev_is_up(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + dp_err("vdev id:%d is not started", req_buf->vdev_id); + status = QDF_STATUS_E_INVAL; + goto release_ref; + } + arp_stats = (struct set_arp_stats *)req_buf; + status = wmi_unified_set_arp_stats_req(wmi_handle, arp_stats); + if (QDF_IS_STATUS_ERROR(status)) + dp_err("failed to set arp stats to FW"); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + return status; +} + +/** + * target_if_dp_lro_config_cmd() - process the LRO config command + * @psoc: Pointer to psoc handle + * @dp_lro_cmd: Pointer to LRO configuration parameters + * + * This function sends down the LRO configuration parameters to + * the firmware to enable LRO, sets the TCP flags and sets the + * seed values for the toeplitz hash generation + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +static QDF_STATUS +target_if_dp_lro_config_cmd(struct wlan_objmgr_psoc *psoc, + struct cdp_lro_hash_config *dp_lro_cmd) +{ + struct wmi_lro_config_cmd_t wmi_lro_cmd = {0}; + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!dp_lro_cmd || !wmi_handle) { + dp_err("wmi_handle or dp_lro_cmd is null"); + return QDF_STATUS_E_FAILURE; + } + + wmi_lro_cmd.lro_enable = dp_lro_cmd->lro_enable; + wmi_lro_cmd.tcp_flag = dp_lro_cmd->tcp_flag; + wmi_lro_cmd.tcp_flag_mask = dp_lro_cmd->tcp_flag_mask; + qdf_mem_copy(wmi_lro_cmd.toeplitz_hash_ipv4, + dp_lro_cmd->toeplitz_hash_ipv4, + LRO_IPV4_SEED_ARR_SZ * sizeof(uint32_t)); + qdf_mem_copy(wmi_lro_cmd.toeplitz_hash_ipv6, + dp_lro_cmd->toeplitz_hash_ipv6, + LRO_IPV6_SEED_ARR_SZ * sizeof(uint32_t)); + + return wmi_unified_lro_config_cmd(wmi_handle, &wmi_lro_cmd); +} + +/** + * target_if_dp_send_dhcp_ind() - process set arp stats request command to fw + * @vdev_id: vdev id + * @dhcp_ind: DHCP indication. + * + * Return: 0 on success, failure code otherwise. + */ +static QDF_STATUS +target_if_dp_send_dhcp_ind(uint16_t vdev_id, + struct dp_dhcp_ind *dhcp_ind) +{ + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + wmi_peer_set_param_cmd_fixed_param peer_set_param_fp = {0}; + QDF_STATUS status; + + psoc = wlan_objmgr_get_psoc_by_id(0, WLAN_PSOC_TARGET_IF_ID); + if (!psoc) { + dp_err("psoc null"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + dp_err("Unable to get wmi handle"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* fill in values */ + peer_set_param_fp.vdev_id = vdev_id; + peer_set_param_fp.param_id = WMI_HOST_PEER_CRIT_PROTO_HINT_ENABLED; + + if (dhcp_ind->dhcp_start) + peer_set_param_fp.param_value = 1; + else + peer_set_param_fp.param_value = 0; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(dhcp_ind->peer_mac_addr.bytes, + &peer_set_param_fp.peer_macaddr); + + status = wmi_unified_process_dhcp_ind(wmi_handle, + &peer_set_param_fp); + wlan_objmgr_psoc_release_ref(psoc, WLAN_PSOC_TARGET_IF_ID); + + return status; +} + +void target_if_dp_register_tx_ops(struct wlan_dp_psoc_sb_ops *sb_ops) +{ + sb_ops->dp_arp_stats_register_event_handler = + target_if_dp_arp_stats_register_event_handler; + sb_ops->dp_arp_stats_unregister_event_handler = + target_if_dp_arp_stats_unregister_event_handler; + sb_ops->dp_get_arp_req_stats = + target_if_dp_get_arp_req_stats; + sb_ops->dp_set_arp_req_stats = + target_if_dp_set_arp_req_stats; + sb_ops->dp_lro_config_cmd = target_if_dp_lro_config_cmd; + sb_ops->dp_send_dhcp_ind = + target_if_dp_send_dhcp_ind; +} + +void target_if_dp_register_rx_ops(struct wlan_dp_psoc_nb_ops *nb_ops) +{ +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h new file mode 100644 index 0000000000..05fe3fdcd1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ftm_time_sync/inc/target_if_ftm_time_sync.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare various api/struct which shall be used + * by FTM time sync component for wmi cmd (tx path) and + * event (rx) handling. + */ + +#ifndef _TARGET_IF_FTM_TIME_SYNC_H_ +#define _TARGET_IF_FTM_TIME_SYNC_H_ + +#include +#include +#include "wlan_ftm_time_sync_public_struct.h" + +/** + * target_if_ftm_time_sync_register_rx_ops() - Register FTM TIME SYNC component + * RX ops + * @rx_ops: FTM time sync component reception ops + * + * Return: None + */ +void target_if_ftm_time_sync_register_rx_ops(struct wlan_ftm_time_sync_rx_ops + *rx_ops); + +/** + * target_if_ftm_time_sync_register_tx_ops() - Register FTM TIME SYNC component + * TX OPS + * @tx_ops: FTM time sync component transmit ops + * + * Return: None + */ +void target_if_ftm_time_sync_register_tx_ops(struct wlan_ftm_time_sync_tx_ops + *tx_ops); + +/** + * target_if_ftm_time_sync_unregister_ev_handlers() - Unregister wmi events + * handlers + * @psoc: psoc context + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_ftm_time_sync_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc); +#endif /*_TARGET_IF_FTM_TIME_SYNC_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c new file mode 100644 index 0000000000..b811248bfd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Target interface file for ftm time sync component to + * Implement api's which shall be used by ftm time sync component + * in target_if internally. + */ + +#include "target_if.h" +#include "target_if_ftm_time_sync.h" +#include "wlan_ftm_time_sync_public_struct.h" +#include "wlan_ftm_time_sync_tgt_api.h" +#include + +static QDF_STATUS +target_if_ftm_time_sync_send_qtime(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint64_t lpass_ts) +{ + wmi_unified_t wmi_hdl; + + wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_hdl) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_send_wlan_time_sync_qtime(wmi_hdl, vdev_id, + lpass_ts); +} + +static QDF_STATUS +target_if_ftm_time_sync_send_trigger(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool mode) +{ + wmi_unified_t wmi_hdl; + + wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_hdl) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_send_wlan_time_sync_ftm_trigger(wmi_hdl, vdev_id, + mode); +} + +static int +target_if_time_sync_ftm_start_stop_event_handler(ol_scn_t scn_handle, + uint8_t *data, uint32_t len) +{ + struct ftm_time_sync_start_stop_params param; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + + if (!data) { + target_if_err("Invalid pointer"); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn_handle); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return -EINVAL; + } + + if (wmi_unified_extract_time_sync_ftm_start_stop_params( + wmi_handle, data, ¶m) != QDF_STATUS_SUCCESS) { + target_if_err("Extraction of time sync ftm start stop failed"); + return -EINVAL; + } + + tgt_ftm_ts_start_stop_evt(psoc, ¶m); + + return 0; +} + +static QDF_STATUS +target_if_ftm_time_sync_start_stop_event(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event_handler( + wmi_handle, wmi_wlan_time_sync_ftm_start_stop_event_id, + target_if_time_sync_ftm_start_stop_event_handler, + WMI_RX_SERIALIZER_CTX); + if (status) { + target_if_err("Ftm time_sync start stop event register failed"); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +static int +target_if_time_sync_initiator_target_offset_event_handler(ol_scn_t scn_handle, + uint8_t *data, + uint32_t len) +{ + struct ftm_time_sync_offset param; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + + if (!data) { + target_if_err("Invalid pointer"); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn_handle); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return -EINVAL; + } + + if (wmi_unified_extract_time_sync_ftm_offset( + wmi_handle, data, ¶m) != QDF_STATUS_SUCCESS) { + target_if_err("Extraction of time_sync ftm offset param failed"); + return -EINVAL; + } + + tgt_ftm_ts_offset_evt(psoc, ¶m); + + return 0; +} + +static QDF_STATUS +target_if_ftm_time_sync_initiator_target_offset(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_wlan_time_sync_q_initiator_target_offset_eventid, + target_if_time_sync_initiator_target_offset_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Ftm time_sync offset event register failed"); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS +target_if_ftm_time_sync_unregister_ev_handlers(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + QDF_STATUS ret, status = QDF_STATUS_SUCCESS; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_unregister_event( + wmi_handle, + wmi_wlan_time_sync_ftm_start_stop_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("failed to unregister time sync start/stop evt"); + status = ret; + } + + ret = wmi_unified_unregister_event( + wmi_handle, + wmi_wlan_time_sync_q_initiator_target_offset_eventid); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("failed to unregister time sync offset evt"); + status = ret; + } + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + +void target_if_ftm_time_sync_register_rx_ops( + struct wlan_ftm_time_sync_rx_ops *rx_ops) +{ + if (!rx_ops) { + target_if_err("FTM time_sync rx_ops is null"); + return; + } + + rx_ops->ftm_time_sync_register_start_stop = + target_if_ftm_time_sync_start_stop_event; + rx_ops->ftm_time_sync_regiser_initiator_target_offset = + target_if_ftm_time_sync_initiator_target_offset; +} + +void target_if_ftm_time_sync_register_tx_ops( + struct wlan_ftm_time_sync_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("FTM time_sync tx_ops is null"); + return; + } + + tx_ops->ftm_time_sync_send_qtime = target_if_ftm_time_sync_send_qtime; + tx_ops->ftm_time_sync_send_trigger = + target_if_ftm_time_sync_send_trigger; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/fw_offload/inc/target_if_fwol.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/fw_offload/inc/target_if_fwol.h new file mode 100644 index 0000000000..61601f6506 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/fw_offload/inc/target_if_fwol.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target interface APIs for fw offload + * + */ + +#ifndef __TARGET_IF_FWOL_H__ +#define __TARGET_IF_FWOL_H__ + +/** + * target_if_fwol_register_event_handler() - register fw offload event handler + * @psoc: psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_fwol_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_fwol_unregister_event_handler() - unregister fw offload event + * handler + * @psoc: psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_fwol_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_fwol_register_tx_ops() - register fw offload tx ops callback + * functions + * @tx_ops: fw offload tx operations + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_fwol_register_tx_ops(struct wlan_fwol_tx_ops *tx_ops); + +/** + * target_if_fwol_notify_thermal_throttle() - Notify thermal throttle level + * to upper layer + * @psoc: PSOC object manager + * @info: Thermal throttle information from target + * + * This function is used to notify thermal throttle level to upper layer + * when thermal management event receive. + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +#ifdef FW_THERMAL_THROTTLE_SUPPORT +QDF_STATUS +target_if_fwol_notify_thermal_throttle(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info); +#else +static inline QDF_STATUS +target_if_fwol_notify_thermal_throttle(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info) +{ + return QDF_STATUS_E_INVAL; +} +#endif +#endif /* __TARGET_IF_FWOL_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/fw_offload/src/target_if_fwol.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/fw_offload/src/target_if_fwol.c new file mode 100644 index 0000000000..16b82c4172 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/fw_offload/src/target_if_fwol.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target interface APIs for fw offload + * + */ + +#include "qdf_mem.h" +#include "target_if.h" +#include "qdf_status.h" +#include "wmi_unified_api.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_utility.h" +#include "wlan_defs.h" +#include "wlan_fwol_public_structs.h" +#include "wlan_fw_offload_main.h" +#include "target_if_fwol.h" + +#ifdef WLAN_FEATURE_ELNA +/** + * target_if_fwol_set_elna_bypass() - send set eLNA bypass request to FW + * @psoc: pointer to PSOC object + * @req: set eLNA bypass request + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_set_elna_bypass(struct wlan_objmgr_psoc *psoc, + struct set_elna_bypass_request *req) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_set_elna_bypass_cmd(wmi_handle, req); + if (status) + target_if_err("Failed to set eLNA bypass %d", status); + + return status; +} + +/** + * target_if_fwol_get_elna_bypass() - send get eLNA bypass request to FW + * @psoc: pointer to PSOC object + * @req: get eLNA bypass request + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_get_elna_bypass(struct wlan_objmgr_psoc *psoc, + struct get_elna_bypass_request *req) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_get_elna_bypass_cmd(wmi_handle, req); + if (status) + target_if_err("Failed to set eLNA bypass %d", status); + + return status; +} + +/** + * target_if_fwol_get_elna_bypass_resp() - handler for get eLNA bypass response + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int target_if_fwol_get_elna_bypass_resp(ol_scn_t scn, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS status; + struct get_elna_bypass_response resp; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_rx_ops *rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, event_buf, len); + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return -EINVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + target_if_err("Failed to get FWOL Obj"); + return -EINVAL; + } + + rx_ops = &fwol_obj->rx_ops; + if (rx_ops->get_elna_bypass_resp) { + status = wmi_extract_get_elna_bypass_resp(wmi_handle, + event_buf, &resp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to extract eLNA bypass"); + return -EINVAL; + } + status = rx_ops->get_elna_bypass_resp(psoc, &resp); + if (status != QDF_STATUS_SUCCESS) { + target_if_err("get_elna_bypass_resp failed."); + return -EINVAL; + } + } else { + target_if_fatal("No get_elna_bypass_resp callback"); + return -EINVAL; + } + + return 0; +}; + +static void +target_if_fwol_register_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + QDF_STATUS rc; + + rc = wmi_unified_register_event(get_wmi_unified_hdl_from_psoc(psoc), + wmi_get_elna_bypass_event_id, + target_if_fwol_get_elna_bypass_resp); + if (QDF_IS_STATUS_ERROR(rc)) + target_if_debug("Failed to register get eLNA bypass event cb"); +} + +static void +target_if_fwol_unregister_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + QDF_STATUS rc; + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_get_elna_bypass_event_id); + if (QDF_IS_STATUS_ERROR(rc)) + target_if_debug("Failed to unregister get eLNA bypass event cb"); +} + +static void +target_if_fwol_register_elna_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + tx_ops->set_elna_bypass = target_if_fwol_set_elna_bypass; + tx_ops->get_elna_bypass = target_if_fwol_get_elna_bypass; +} +#else +static void +target_if_fwol_register_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ +} + +static void +target_if_fwol_unregister_elna_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ +} + +static void +target_if_fwol_register_elna_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ +} +#endif /* WLAN_FEATURE_ELNA */ + +#ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW +/** + * target_if_fwol_send_dscp_up_map_to_fw() - send dscp up map to FW + * @psoc: pointer to PSOC object + * @dscp_to_up_map: DSCP to UP map array + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_send_dscp_up_map_to_fw(struct wlan_objmgr_psoc *psoc, + uint32_t *dscp_to_up_map) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_dscp_tip_map_cmd(wmi_handle, dscp_to_up_map); + if (status) + target_if_err("Failed to send dscp_up_map_to_fw %d", status); + + return status; +} + +static void +target_if_fwol_register_dscp_up_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + tx_ops->send_dscp_up_map_to_fw = target_if_fwol_send_dscp_up_map_to_fw; +} +#else +static void +target_if_fwol_register_dscp_up_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ +} +#endif + +#ifdef THERMAL_STATS_SUPPORT +/** + * target_if_fwol_get_thermal_stats() - send get thermal stats request to FW + * @psoc: pointer to PSOC object + * @req_type: get thermal stats request type + * @therm_stats_offset: thermal temp stats offset for each temp range + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_get_thermal_stats(struct wlan_objmgr_psoc *psoc, + enum thermal_stats_request_type req_type, + uint8_t therm_stats_offset) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_get_thermal_stats_cmd(wmi_handle, req_type, + therm_stats_offset); + if (status) + target_if_err("Failed to send get thermal stats cmd %d", + status); + + return status; +} + +static void +target_if_fwol_register_thermal_stats_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + tx_ops->get_thermal_stats = target_if_fwol_get_thermal_stats; +} + +static QDF_STATUS +target_if_fwol_handle_thermal_lvl_stats_evt(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_rx_ops *rx_ops, + struct thermal_throttle_info *info) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (rx_ops->get_thermal_stats_resp && info->therm_throt_levels) + status = rx_ops->get_thermal_stats_resp(psoc, info); + + return status; +} + +static bool +target_if_fwol_is_thermal_stats_enable(struct wlan_fwol_psoc_obj *fwol_obj) +{ + return (fwol_obj->capability_info.fw_thermal_stats_cap && + fwol_obj->cfg.thermal_temp_cfg.therm_stats_offset); +} +#else +static void +target_if_fwol_register_thermal_stats_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ +} + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +static QDF_STATUS +target_if_fwol_handle_thermal_lvl_stats_evt(struct wlan_objmgr_psoc *psoc, + struct wlan_fwol_rx_ops *rx_ops, + struct thermal_throttle_info *info) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static bool +target_if_fwol_is_thermal_stats_enable(struct wlan_fwol_psoc_obj *fwol_obj) +{ + return false; +} +#endif +#endif + +#if defined FW_THERMAL_THROTTLE_SUPPORT || defined THERMAL_STATS_SUPPORT +QDF_STATUS +target_if_fwol_notify_thermal_throttle(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info) +{ + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_rx_ops *rx_ops; + QDF_STATUS status; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + target_if_err("Failed to get FWOL Obj"); + return QDF_STATUS_E_INVAL; + } + + rx_ops = &fwol_obj->rx_ops; + if (!rx_ops) { + target_if_err("rx_ops Null"); + return QDF_STATUS_E_INVAL; + } + + if (!info) { + target_if_err("info Null"); + return QDF_STATUS_E_INVAL; + } + + if (rx_ops->notify_thermal_throttle_handler) { + if (info->level == THERMAL_UNKNOWN) { + target_if_debug("Invalid thermal target lvl"); + return QDF_STATUS_E_INVAL; + } + status = rx_ops->notify_thermal_throttle_handler(psoc, info); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_debug("notify thermal_throttle failed."); + return QDF_STATUS_E_INVAL; + } + } else { + target_if_debug("No notify thermal_throttle callback"); + return QDF_STATUS_E_INVAL; + } + + return status; +} + +/** + * target_if_fwol_thermal_throttle_event_handler() - handler for thermal + * throttle event + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int +target_if_fwol_thermal_throttle_event_handler(ol_scn_t scn, uint8_t *event_buf, + uint32_t len) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct thermal_throttle_info info = {0}; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + struct wlan_fwol_psoc_obj *fwol_obj; + struct wlan_fwol_rx_ops *rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, event_buf, len); + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return -EINVAL; + } + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + target_if_err("Failed to get FWOL Obj"); + return -EINVAL; + } + + status = wmi_extract_thermal_stats(wmi_handle, + event_buf, + &info.temperature, + &info.level, + &info.therm_throt_levels, + info.level_info, + &info.pdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_debug("Failed to convert thermal target level"); + return -EINVAL; + } + rx_ops = &fwol_obj->rx_ops; + if (!rx_ops) { + target_if_debug("rx_ops Null"); + return -EINVAL; + } + + status = target_if_fwol_handle_thermal_lvl_stats_evt(psoc, rx_ops, + &info); + if (QDF_IS_STATUS_ERROR(status)) + target_if_debug("thermal stats level response failed."); + + if (rx_ops->notify_thermal_throttle_handler) + { + if (info.level == THERMAL_UNKNOWN) { + target_if_debug("Failed to convert thermal target lvl"); + return -EINVAL; + } + status = rx_ops->notify_thermal_throttle_handler(psoc, &info); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_debug("notify thermal_throttle failed."); + return -EINVAL; + } + } else { + target_if_debug("No notify thermal_throttle callback"); + return -EINVAL; + } + return 0; +} + +/** + * target_if_fwol_register_thermal_throttle_handler() - Register handler for + * thermal throttle stats firmware event + * @psoc: psoc object + * + * Return: void + */ +static void +target_if_fwol_register_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct wlan_fwol_psoc_obj *fwol_obj; + + fwol_obj = fwol_get_psoc_obj(psoc); + if (!fwol_obj) { + target_if_err("Failed to get FWOL Obj"); + return; + } + if (!fwol_obj->cfg.thermal_temp_cfg.thermal_mitigation_enable && + !target_if_fwol_is_thermal_stats_enable(fwol_obj)) { + target_if_debug("thermal mitigation or stats offload not enabled"); + return; + } + status = wmi_unified_register_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_tt_stats_event_id, + target_if_fwol_thermal_throttle_event_handler, + WMI_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) + target_if_debug("Failed to register thermal stats event cb"); +} + +/** + * target_if_fwol_unregister_thermal_throttle_handler() - Unregister handler for + * thermal throttle stats firmware event + * @psoc: psoc object + * + * Return: void + */ +static void +target_if_fwol_unregister_thermal_throttle_handler( + struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_tt_stats_event_id); + if (QDF_IS_STATUS_ERROR(status)) + target_if_debug("Failed to unregister thermal stats event cb"); +} +#else +static void +target_if_fwol_register_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc) +{ +} + +static void +target_if_fwol_unregister_thermal_throttle_handler( + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD +/** + * target_if_fwol_set_mdns_config() - Set mdns Config to FW + * @psoc: pointer to PSOC object + * @mdns_info: pointer to mdns config info + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_fwol_set_mdns_config(struct wlan_objmgr_psoc *psoc, + struct mdns_config_info *mdns_info) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi_handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_set_mdns_config_cmd(wmi_handle, + mdns_info); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to set mDNS Config %d", status); + + return status; +} + +static void +target_if_fwol_register_mdns_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + tx_ops->set_mdns_config = target_if_fwol_set_mdns_config; +} +#else +static void +target_if_fwol_register_mdns_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ +} +#endif /* WLAN_FEATURE_MDNS_OFFLOAD */ + +QDF_STATUS +target_if_fwol_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + target_if_fwol_register_elna_event_handler(psoc, arg); + target_if_fwol_register_thermal_throttle_handler(psoc); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +target_if_fwol_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + target_if_fwol_unregister_thermal_throttle_handler(psoc); + target_if_fwol_unregister_elna_event_handler(psoc, arg); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_fwol_register_tx_ops(struct wlan_fwol_tx_ops *tx_ops) +{ + target_if_fwol_register_elna_tx_ops(tx_ops); + target_if_fwol_register_dscp_up_tx_ops(tx_ops); + target_if_fwol_register_mdns_tx_ops(tx_ops); + target_if_fwol_register_thermal_stats_tx_ops(tx_ops); + + tx_ops->reg_evt_handler = target_if_fwol_register_event_handler; + tx_ops->unreg_evt_handler = target_if_fwol_unregister_event_handler; + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/interop_issues_ap/inc/target_if_interop_issues_ap.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/interop_issues_ap/inc/target_if_interop_issues_ap.h new file mode 100644 index 0000000000..b65314a0d6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/interop_issues_ap/inc/target_if_interop_issues_ap.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for interop issues ap + */ +#ifndef __TARGET_IF_INTEROP_ISSUES_AP_H__ +#define __TARGET_IF_INTEROP_ISSUES_AP_H__ + +#ifdef WLAN_FEATURE_INTEROP_ISSUES_AP +#include +#include +#include +#include +#include + +/** + * target_if_interop_issues_ap_register_event_handler() - register callback + * @psoc: the pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_interop_issues_ap_register_event_handler( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_interop_issues_ap_unregister_event_handler() - unregister callback + * @psoc: the pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_interop_issues_ap_unregister_event_handler( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_interop_issues_ap_register_tx_ops() - register tx ops funcs + * @psoc: the pointer of psoc object + * @tx_ops: pointer to rap_ps tx ops + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_interop_issues_ap_register_tx_ops(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_tx_ops *tx_ops); +/** + * target_if_interop_issues_ap_unregister_tx_ops() - unregister tx ops funcs + * @psoc: the pointer of psoc object + * @tx_ops: pointer to rap_ps tx ops + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_interop_issues_ap_unregister_tx_ops(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_tx_ops *tx_ops); +#endif +#endif /* __TARGET_IF_INTEROP_ISSUES_AP_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/interop_issues_ap/src/target_if_interop_issues_ap.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/interop_issues_ap/src/target_if_interop_issues_ap.c new file mode 100644 index 0000000000..4a3e2ff557 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/interop_issues_ap/src/target_if_interop_issues_ap.c @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_interop_issues_ap.c + * + * This file provide definition for APIs registered through lmac Tx Ops + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * target_if_interop_issues_ap_event_handler() - callback for event + * @sc: scn handle + * @event: firmware event + * @len: the event length + * + * Return: 0 or error status + */ +static int target_if_interop_issues_ap_event_handler(ol_scn_t sc, + uint8_t *event, + uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_interop_issues_ap_event data = {0}; + int ret; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(sc); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + return -EINVAL; + } + data.psoc = psoc; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + ret = wmi_extract_interop_issues_ap_ev_param(wmi_handle, event, &data); + if (ret) + return -EINVAL; + + target_if_debug("interop issues ap macaddr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(data.rap_addr.bytes)); + + return tgt_interop_issues_ap_info_callback(psoc, &data); +} + +/** + * target_if_interop_issues_ap_register_event_handler() - register callback + * @psoc: the pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_interop_issues_ap_register_event_handler( + struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret_val; + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("PSOC is NULL!"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + ret_val = + wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_interop_issues_ap_event_id, + target_if_interop_issues_ap_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(ret_val)) + target_if_err("Failed to register event cb"); + + return ret_val; +} + +/** + * target_if_interop_issues_ap_unregister_event_handler() - unregister callback + * @psoc: the pointer to psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_interop_issues_ap_unregister_event_handler( + struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + wmi_unified_unregister_event_handler(wmi_handle, + wmi_pdev_interop_issues_ap_event_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_set_interop_issues_ap_req() - API to send stats request to wmi + * @psoc: pointer to psoc object + * @rap: pointer to interop issues ap info + * + * Return: status of operation. + */ +static QDF_STATUS +target_if_set_interop_issues_ap_req(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_info *rap) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_set_rap_ps_cmd(wmi_handle, rap); +} + +QDF_STATUS +target_if_interop_issues_ap_register_tx_ops(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + tx_ops->set_rap_ps = target_if_set_interop_issues_ap_req; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +target_if_interop_issues_ap_unregister_tx_ops(struct wlan_objmgr_psoc *psoc, + struct wlan_interop_issues_ap_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + tx_ops->set_rap_ps = NULL; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/mlme/inc/target_if_mlme.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/mlme/inc/target_if_mlme.h new file mode 100644 index 0000000000..a9c75b8e76 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/mlme/inc/target_if_mlme.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/** + * DOC: contains mlme target if declarations + */ + +#ifndef _WLAN_MLME_TGT_IF_H_ +#define _WLAN_MLME_TGT_IF_H_ + +#include "qdf_types.h" +#include "wlan_mlme_dbg.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_main.h" +#include "target_if.h" + +/** + * target_if_mlme_register_tx_ops() - registers mlme tx ops + * @tx_ops: tx ops + * + * Return: none + */ +void target_if_mlme_register_tx_ops(struct wlan_mlme_tx_ops *tx_ops); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/mlme/src/target_if_mlme.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/mlme/src/target_if_mlme.c new file mode 100644 index 0000000000..5ad3bc506f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/mlme/src/target_if_mlme.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/** + * DOC: contains mlme target if declarations + */ + +#include "target_if_mlme.h" +#include + +static struct wmi_unified +*target_if_mlme_get_wmi_handle_from_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + struct wmi_unified *wmi_handle; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + target_if_err("PDEV is NULL"); + return NULL; + } + + wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return NULL; + } + + return wmi_handle; +} + +static QDF_STATUS +target_if_mlme_send_csa_event_status_ind(struct wlan_objmgr_vdev *vdev, + uint8_t csa_status) +{ + wmi_unified_t wmi_handle; + struct csa_event_status_ind params = {0}; + + params.vdev_id = wlan_vdev_get_id(vdev); + params.status = csa_status; + + wmi_handle = target_if_mlme_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_send_csa_event_status_ind(wmi_handle, params); +} + +void +target_if_mlme_register_tx_ops(struct wlan_mlme_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("target if tx ops is NULL!"); + return; + } + + tx_ops->send_csa_event_status_ind = + target_if_mlme_send_csa_event_status_ind; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/nan/inc/target_if_nan.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/nan/inc/target_if_nan.h new file mode 100644 index 0000000000..f4516b134b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/nan/inc/target_if_nan.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan target if declarations + */ + +#ifndef _WLAN_NAN_TGT_IF_H_ +#define _WLAN_NAN_TGT_IF_H_ + +#include "qdf_types.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "nan_public_structs.h" + +struct wlan_objmgr_psoc; + +/** + * target_if_nan_get_tx_ops() - retrieve the nan tx_ops + * @psoc: psoc context + * + * API to retrieve the nan tx_ops from the psoc context + * + * Return: nan tx_ops pointer + */ +struct wlan_nan_tx_ops *target_if_nan_get_tx_ops(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_get_rx_ops() - retrieve the nan rx_ops + * @psoc: psoc context + * + * API to retrieve the nan rx_ops from the psoc context + * + * Return: nan rx_ops pointer + */ +struct wlan_nan_rx_ops *target_if_nan_get_rx_ops(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_register_tx_ops() - registers nan tx ops + * @tx_ops: tx ops + * + * Return: none + */ +void target_if_nan_register_tx_ops(struct wlan_nan_tx_ops *tx_ops); + +/** + * target_if_nan_register_rx_ops() - registers nan rx ops + * @rx_ops: rx ops + * + * Return: none + */ +void target_if_nan_register_rx_ops(struct wlan_nan_rx_ops *rx_ops); + +/** + * target_if_nan_register_events() - registers with NDP events + * @psoc: pointer to psoc object + * + * Return: status of operation + */ +QDF_STATUS target_if_nan_register_events(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_deregister_events() - registers nan rx ops + * @psoc: pointer to psoc object + * + * Return: status of operation + */ +QDF_STATUS target_if_nan_deregister_events(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_nan_rsp_handler() - Target IF handler for NAN Discovery events + * @scn: target handle + * @data: event buffer + * @len: event buffer length + * + * Return: 0 for success or error code + */ +int target_if_nan_rsp_handler(ol_scn_t scn, uint8_t *data, uint32_t len); + +/** + * target_if_nan_set_vdev_feature_config() - Init NAN feature config params + * @psoc: Pointer to PSOC Object + * @vdev_id: vdev_id of the current vdev + * + * This function updates NAN feature config bitmap to firmware + */ +void target_if_nan_set_vdev_feature_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#endif /* _WIFI_POS_TGT_IF_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/nan/src/target_if_nan.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/nan/src/target_if_nan.c new file mode 100644 index 0000000000..60c0d9673d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/nan/src/target_if_nan.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nan target if functions + */ + +#include "../../../nan/core/src/nan_main_i.h" +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" +#include "target_if_nan.h" +#include "wlan_nan_api.h" +#include "target_if.h" +#include "wmi_unified_api.h" +#include "scheduler_api.h" +#include + +static QDF_STATUS target_if_nan_event_flush_cb(struct scheduler_msg *msg) +{ + struct wlan_objmgr_psoc *psoc; + + if (!msg || !msg->bodyptr) { + target_if_err("Empty message for NAN Discovery event"); + return QDF_STATUS_E_INVAL; + } + + psoc = ((struct nan_event_params *)msg->bodyptr)->psoc; + wlan_objmgr_psoc_release_ref(psoc, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS target_if_nan_event_dispatcher(struct scheduler_msg *msg) +{ + struct wlan_nan_rx_ops *nan_rx_ops; + struct nan_event_params *nan_rsp; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + nan_rsp = msg->bodyptr; + psoc = nan_rsp->psoc; + + nan_rx_ops = nan_psoc_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + } else { + status = nan_rx_ops->nan_discovery_event_rx(msg); + } + + target_if_nan_event_flush_cb(msg); + return status; +} + +static QDF_STATUS target_if_ndp_event_flush_cb(struct scheduler_msg *msg) +{ + void *ptr = msg->bodyptr; + struct wlan_objmgr_vdev *vdev = NULL; + + switch (msg->type) { + case NDP_INITIATOR_RSP: + vdev = ((struct nan_datapath_initiator_rsp *)ptr)->vdev; + break; + case NDP_INDICATION: + vdev = ((struct nan_datapath_indication_event *)ptr)->vdev; + break; + case NDP_CONFIRM: + vdev = ((struct nan_datapath_confirm_event *)ptr)->vdev; + break; + case NDP_RESPONDER_RSP: + vdev = ((struct nan_datapath_responder_rsp *)ptr)->vdev; + break; + case NDP_END_RSP: + vdev = ((struct nan_datapath_end_rsp_event *)ptr)->vdev; + break; + case NDP_END_IND: + vdev = ((struct nan_datapath_end_indication_event *)ptr)->vdev; + break; + case NDP_SCHEDULE_UPDATE: + vdev = ((struct nan_datapath_sch_update_event *)ptr)->vdev; + break; + case NDP_HOST_UPDATE: + vdev = ((struct nan_datapath_host_event *)ptr)->vdev; + break; + default: + break; + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS target_if_ndp_event_dispatcher(struct scheduler_msg *msg) +{ + QDF_STATUS status; + void *ptr = msg->bodyptr; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_nan_rx_ops *nan_rx_ops; + + switch (msg->type) { + case NDP_INITIATOR_RSP: + vdev = ((struct nan_datapath_initiator_rsp *)ptr)->vdev; + break; + case NDP_INDICATION: + vdev = ((struct nan_datapath_indication_event *)ptr)->vdev; + break; + case NDP_CONFIRM: + vdev = ((struct nan_datapath_confirm_event *)ptr)->vdev; + break; + case NDP_RESPONDER_RSP: + vdev = ((struct nan_datapath_responder_rsp *)ptr)->vdev; + break; + case NDP_END_RSP: + vdev = ((struct nan_datapath_end_rsp_event *)ptr)->vdev; + break; + case NDP_END_IND: + vdev = ((struct nan_datapath_end_indication_event *)ptr)->vdev; + break; + case NDP_SCHEDULE_UPDATE: + vdev = ((struct nan_datapath_sch_update_event *)ptr)->vdev; + break; + case NDP_HOST_UPDATE: + vdev = ((struct nan_datapath_host_event *)ptr)->vdev; + break; + default: + target_if_err("invalid msg type %d", msg->type); + status = QDF_STATUS_E_INVAL; + goto free_res; + } + + if (!vdev) { + target_if_err("vdev is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto free_res; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto free_res; + } + + nan_rx_ops = nan_psoc_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto free_res; + } + + status = nan_rx_ops->nan_datapath_event_rx(msg); +free_res: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return status; +} + +static QDF_STATUS target_if_nan_ndp_initiator_req( + struct nan_datapath_initiator_req *ndp_req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg pe_msg = {0}; + struct wlan_nan_rx_ops *nan_rx_ops; + struct nan_datapath_initiator_rsp ndp_rsp = {0}; + + if (!ndp_req) { + target_if_err("ndp_req is null."); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(ndp_req->vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_INVAL; + } + + nan_rx_ops = nan_psoc_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null."); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_ndp_initiator_req_cmd_send(wmi_handle, ndp_req); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + ndp_rsp.vdev = ndp_req->vdev; + ndp_rsp.transaction_id = ndp_req->transaction_id; + ndp_rsp.ndp_instance_id = ndp_req->service_instance_id; + ndp_rsp.status = NAN_DATAPATH_DATA_INITIATOR_REQ_FAILED; + pe_msg.type = NDP_INITIATOR_RSP; + pe_msg.bodyptr = &ndp_rsp; + if (nan_rx_ops->nan_datapath_event_rx) + nan_rx_ops->nan_datapath_event_rx(&pe_msg); + + return status; +} + +static int target_if_nan_dmesg_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct nan_dump_msg msg; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_nan_msg(wmi_handle, data, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + return -EINVAL; + } + + if (!msg.msg) { + target_if_err("msg not present %d", msg.data_len); + return -EINVAL; + } + + target_if_info("%s", msg.msg); + + return 0; +} + +static int target_if_ndp_initiator_rsp_handler(ol_scn_t scn, uint8_t *data, + uint32_t len) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg msg = {0}; + struct nan_datapath_initiator_rsp *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + + status = wmi_extract_ndp_initiator_rsp(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_INITIATOR_RSP; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_INITIATOR_RSP sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_ind_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_indication_event *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + + status = wmi_extract_ndp_ind(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_INDICATION; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_INDICATION sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_confirm_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_confirm_event *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + + status = wmi_extract_ndp_confirm(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_CONFIRM; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_CONFIRM sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_ndp_responder_req( + struct nan_datapath_responder_req *req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg pe_msg = {0}; + struct wlan_nan_rx_ops *nan_rx_ops; + struct nan_datapath_responder_rsp rsp = {0}; + + if (!req) { + target_if_err("Invalid req."); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(req->vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_rx_ops = nan_psoc_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wmi_unified_ndp_responder_req_cmd_send(wmi_handle, req); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + rsp.vdev = req->vdev; + rsp.transaction_id = req->transaction_id; + rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + rsp.reason = NAN_DATAPATH_DATA_RESPONDER_REQ_FAILED; + pe_msg.bodyptr = &rsp; + pe_msg.type = NDP_RESPONDER_RSP; + if (nan_rx_ops->nan_datapath_event_rx) + nan_rx_ops->nan_datapath_event_rx(&pe_msg); + + return status; +} + +static int target_if_ndp_responder_rsp_handler(ol_scn_t scn, uint8_t *data, + uint32_t len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_responder_rsp *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + + status = wmi_extract_ndp_responder_rsp(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_RESPONDER_RSP; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_INITIATOR_RSP sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_ndp_end_req(struct nan_datapath_end_req *req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct scheduler_msg msg = {0}; + struct wlan_nan_rx_ops *nan_rx_ops; + struct nan_datapath_end_rsp_event end_rsp = {0}; + + if (!req) { + target_if_err("req is null"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(req->vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + nan_rx_ops = nan_psoc_get_rx_ops(psoc); + if (!nan_rx_ops) { + target_if_err("nan_rx_ops is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wmi_unified_ndp_end_req_cmd_send(wmi_handle, req); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + end_rsp.vdev = req->vdev; + msg.type = NDP_END_RSP; + end_rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + end_rsp.reason = NAN_DATAPATH_END_FAILED; + end_rsp.transaction_id = req->transaction_id; + msg.bodyptr = &end_rsp; + + if (nan_rx_ops->nan_datapath_event_rx) + nan_rx_ops->nan_datapath_event_rx(&msg); + + return status; +} + +static int target_if_ndp_end_rsp_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_end_rsp_event *end_rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + end_rsp = qdf_mem_malloc(sizeof(*end_rsp)); + if (!end_rsp) + return -ENOMEM; + + status = wmi_extract_ndp_end_rsp(wmi_handle, data, end_rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(end_rsp); + return -EINVAL; + } + + msg.bodyptr = end_rsp; + msg.type = NDP_END_RSP; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_END_RSP sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_end_ind_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_end_indication_event *rsp = NULL; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + status = wmi_extract_ndp_end_ind(wmi_handle, data, &rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + return -EINVAL; + } + + rsp->vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc( + wmi_handle->soc->wmi_psoc, QDF_NDI_MODE, WLAN_NAN_ID); + if (!rsp->vdev) { + target_if_err("vdev is null"); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_END_IND; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_END_IND sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static int target_if_ndp_sch_update_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_sch_update_event *rsp; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return -ENOMEM; + + status = wmi_extract_ndp_sch_update(wmi_handle, data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(rsp); + return -EINVAL; + } + + msg.bodyptr = rsp; + msg.type = NDP_SCHEDULE_UPDATE; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_SCHEDULE_UPDATE sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_end_all_ndps_req(void *req) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + uint8_t vdev_id; + + vdev = ((struct nan_datapath_end_all_ndps *)req)->vdev; + if (!vdev) { + target_if_err("vdev object is NULL!"); + return QDF_STATUS_E_INVAL; + } + vdev_id = wlan_vdev_get_id(vdev); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_terminate_all_ndps_req_cmd(wmi_handle, vdev_id); +} + +static int target_if_ndp_host_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct scheduler_msg msg = {0}; + struct nan_datapath_host_event *host_evt = NULL; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return -EINVAL; + } + + host_evt = qdf_mem_malloc(sizeof(*host_evt)); + if (!host_evt) + return -ENOMEM; + + status = wmi_extract_ndp_host_event(wmi_handle, data, host_evt); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + qdf_mem_free(host_evt); + return -EINVAL; + } + + if (!host_evt->vdev) { + target_if_err("vdev is null"); + qdf_mem_free(host_evt); + return -EINVAL; + } + + msg.bodyptr = host_evt; + msg.type = NDP_HOST_UPDATE; + msg.callback = target_if_ndp_event_dispatcher; + msg.flush_callback = target_if_ndp_event_flush_cb; + target_if_debug("NDP_HOST_UPDATE sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_ndp_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +static QDF_STATUS target_if_nan_datapath_req(void *req, uint32_t req_type) +{ + /* send cmd to fw */ + switch (req_type) { + case NDP_INITIATOR_REQ: + target_if_nan_ndp_initiator_req(req); + break; + case NDP_RESPONDER_REQ: + target_if_nan_ndp_responder_req(req); + break; + case NDP_END_REQ: + target_if_nan_ndp_end_req(req); + break; + case NDP_END_ALL: + target_if_nan_end_all_ndps_req(req); + break; + default: + target_if_err("invalid req type"); + break; + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS target_if_nan_generic_req(struct wlan_objmgr_psoc *psoc, + void *nan_req) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!nan_req) { + target_if_err("Invalid req."); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_nan_req_cmd(wmi_handle, nan_req); +} + +static QDF_STATUS target_if_nan_disable_req(struct nan_disable_req *nan_req) +{ + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + + if (!nan_req) { + target_if_err("Invalid req."); + return QDF_STATUS_E_INVAL; + } + psoc = nan_req->psoc; + + if (!psoc) { + target_if_err("psoc is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_nan_disable_req_cmd(wmi_handle, nan_req); +} + +static QDF_STATUS target_if_nan_discovery_req(void *req, uint32_t req_type) +{ + QDF_STATUS status; + + if (!req) { + target_if_err("Invalid req."); + return QDF_STATUS_E_INVAL; + } + + switch (req_type) { + case NAN_DISABLE_REQ: + status = target_if_nan_disable_req(req); + break; + case NAN_GENERIC_REQ: { + struct nan_generic_req *nan_req = req; + + status = target_if_nan_generic_req(nan_req->psoc, + &nan_req->params); + break; + } + case NAN_ENABLE_REQ: { + struct nan_enable_req *nan_req = req; + + status = target_if_nan_generic_req(nan_req->psoc, + &nan_req->params); + break; + } + default: + target_if_err("Invalid NAN req type"); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +void target_if_nan_register_tx_ops(struct wlan_nan_tx_ops *tx_ops) +{ + tx_ops->nan_discovery_req_tx = target_if_nan_discovery_req; + tx_ops->nan_datapath_req_tx = target_if_nan_datapath_req; +} + +void target_if_nan_register_rx_ops(struct wlan_nan_rx_ops *rx_ops) +{ + rx_ops->nan_discovery_event_rx = nan_discovery_event_handler; + rx_ops->nan_datapath_event_rx = nan_datapath_event_handler; +} + +int target_if_nan_rsp_handler(ol_scn_t scn, uint8_t *data, uint32_t len) +{ + struct nan_event_params *nan_rsp, temp_evt_params = {0}; + struct scheduler_msg msg = {0}; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + uint8_t *buf_ptr; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + status = wmi_extract_nan_event_rsp(wmi_handle, data, &temp_evt_params, + &buf_ptr); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("parsing of event failed, %d", status); + return -EINVAL; + } + + nan_rsp = qdf_mem_malloc(sizeof(*nan_rsp) + temp_evt_params.buf_len); + if (!nan_rsp) + return -ENOMEM; + + qdf_mem_copy(nan_rsp, &temp_evt_params, sizeof(*nan_rsp)); + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_NAN_ID); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to obtain psoc ref"); + return -EACCES; + } + + nan_rsp->psoc = psoc; + qdf_mem_copy(nan_rsp->buf, buf_ptr, nan_rsp->buf_len); + + msg.bodyptr = nan_rsp; + msg.type = nan_rsp->evt_type; + msg.callback = target_if_nan_event_dispatcher; + msg.flush_callback = target_if_nan_event_flush_cb; + target_if_debug("NAN Event sent: %d", msg.type); + status = scheduler_post_message(QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("failed to post msg, status: %d", status); + target_if_nan_event_flush_cb(&msg); + return -EINVAL; + } + + return 0; +} + +QDF_STATUS target_if_nan_register_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Register for nan response event */ + ret = wmi_unified_register_event_handler(handle, wmi_nan_event_id, + target_if_nan_rsp_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_initiator_rsp_event_id, + target_if_ndp_initiator_rsp_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, wmi_nan_dmesg_event_id, + target_if_nan_dmesg_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_indication_event_id, + target_if_ndp_ind_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_confirm_event_id, + target_if_ndp_confirm_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_responder_rsp_event_id, + target_if_ndp_responder_rsp_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_end_indication_event_id, + target_if_ndp_end_ind_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndp_end_rsp_event_id, + target_if_ndp_end_rsp_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, + wmi_ndl_schedule_update_event_id, + target_if_ndp_sch_update_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler(handle, wmi_ndp_event_id, + target_if_ndp_host_event_handler, + WMI_RX_UMAC_CTX); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event registration failed, ret: %d", ret); + target_if_nan_deregister_events(psoc); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_nan_deregister_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret, status = QDF_STATUS_SUCCESS; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndl_schedule_update_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_end_rsp_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_end_indication_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_responder_rsp_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_confirm_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_indication_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_nan_dmesg_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, + wmi_ndp_initiator_rsp_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + ret = wmi_unified_unregister_event_handler(handle, wmi_ndp_event_id); + if (QDF_IS_STATUS_ERROR(ret)) { + target_if_err("wmi event deregistration failed, ret: %d", ret); + status = ret; + } + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + +void target_if_nan_set_vdev_feature_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint32_t nan_features; + struct vdev_set_params param; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return; + } + + if (!target_if_is_vdev_valid(vdev_id)) { + target_if_err("vdev_id: %d is invalid, reject the req: param id %d", + vdev_id, + wmi_vdev_param_enable_disable_nan_config_features); + return; + } + + ucfg_get_nan_feature_config(psoc, &nan_features); + target_if_debug("vdev_id:%d NAN features:0x%x", vdev_id, nan_features); + + param.vdev_id = vdev_id; + param.param_id = wmi_vdev_param_enable_disable_nan_config_features; + param.param_value = nan_features; + + status = wmi_unified_vdev_set_param_send(wmi_handle, ¶m); + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("failed to set NAN_CONFIG_FEATURES(status = %d)", + status); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/ocb/inc/target_if_ocb.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ocb/inc/target_if_ocb.h new file mode 100644 index 0000000000..13f9afb9c8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ocb/inc/target_if_ocb.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for ocb + * + */ + +#ifndef __TARGET_IF_OCB_H__ +#define __TARGET_IF_OCB_H__ + +/** + * target_if_ocb_register_event_handler() - lmac handler to register ocb event + * handler + * @psoc : psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_ocb_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_ocb_unregister_event_handler() - lmac handler to unregister ocb + * event handler + * @psoc : psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_ocb_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); +/** + * target_if_ocb_register_tx_ops() - lmac handler to register ocb tx ops + * callback functions + * @tx_ops: ocb tx operations + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_ocb_register_tx_ops( + struct wlan_ocb_tx_ops *tx_ops); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/ocb/src/target_if_ocb.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ocb/src/target_if_ocb.c new file mode 100644 index 0000000000..c673a716e4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/ocb/src/target_if_ocb.c @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for ocb + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * target_if_ocb_get_rx_ops() - get target interface RX operations + * @pdev: pdev handle + * + * Return: fp to target interface RX operations + */ +static inline struct wlan_ocb_rx_ops * +target_if_ocb_get_rx_ops(struct wlan_objmgr_pdev *pdev) +{ + struct ocb_pdev_obj *ocb_obj; + + ocb_obj = wlan_get_pdev_ocb_obj(pdev); + + return &ocb_obj->ocb_rxops; +} + +/** + * target_if_ocb_set_config() - send the OCB config to the FW + * @psoc: pointer to PSOC object + * @config: OCB channel configuration + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS target_if_ocb_set_config(struct wlan_objmgr_psoc *psoc, + struct ocb_config *config) +{ + QDF_STATUS status; + + status = wmi_unified_ocb_set_config(get_wmi_unified_hdl_from_psoc(psoc), + config); + if (status) + target_if_err("Failed to set OCB config %d", status); + + return status; +} + +/** + * target_if_ocb_set_utc_time() - send the UTC time to the firmware + * @psoc: pointer to PSOC object + * @utc: pointer to the UTC time structure + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS target_if_ocb_set_utc_time(struct wlan_objmgr_psoc *psoc, + struct ocb_utc_param *utc) +{ + QDF_STATUS status; + + status = wmi_unified_ocb_set_utc_time_cmd( + get_wmi_unified_hdl_from_psoc(psoc), utc); + if (status) + target_if_err("Failed to set OCB UTC time %d", status); + + return status; +} + +/** + * target_if_ocb_start_timing_advert() - start sending the timing + * advertisement frame on a channel + * @psoc: pointer to PSOC object + * @ta: pointer to the timing advertisement + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_ocb_start_timing_advert(struct wlan_objmgr_psoc *psoc, + struct ocb_timing_advert_param *ta) +{ + QDF_STATUS status; + + status = wmi_unified_ocb_start_timing_advert( + get_wmi_unified_hdl_from_psoc(psoc), ta); + if (status) + target_if_err("Failed to start OCB timing advert %d", status); + + return status; +} + +/** + * target_if_ocb_stop_timing_advert() - stop sending the timing + * advertisement frame on a channel + * @psoc: pointer to PSOC object + * @ta: pointer to the timing advertisement + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_ocb_stop_timing_advert(struct wlan_objmgr_psoc *psoc, + struct ocb_timing_advert_param *ta) +{ + QDF_STATUS status; + + status = + wmi_unified_ocb_stop_timing_advert( + get_wmi_unified_hdl_from_psoc(psoc), ta); + if (status) + target_if_err("Failed to stop OCB timing advert %d", status); + + return status; +} + +/** + * target_if_ocb_get_tsf_timer() - get tsf timer + * @psoc: pointer to PSOC object + * @request: pointer to the request + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_ocb_get_tsf_timer(struct wlan_objmgr_psoc *psoc, + struct ocb_get_tsf_timer_param *request) +{ + QDF_STATUS status; + + status = wmi_unified_ocb_get_tsf_timer( + get_wmi_unified_hdl_from_psoc(psoc), request); + if (status) + target_if_err("Failed to send get tsf timer cmd: %d", status); + + return status; +} + +/** + * target_if_dcc_get_stats() - get the DCC channel stats + * @psoc: pointer to PSOC object + * @get_stats_param: pointer to the dcc stats request + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_dcc_get_stats(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_get_stats_param *get_stats_param) +{ + QDF_STATUS status; + + status = wmi_unified_dcc_get_stats_cmd( + get_wmi_unified_hdl_from_psoc(psoc), get_stats_param); + if (status) + target_if_err("Failed to send get DCC stats cmd: %d", status); + + return status; +} + +/** + * target_if_dcc_clear_stats() - send command to clear the DCC stats + * @psoc: pointer to PSOC object + * @clear_stats_param: parameters to the command + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_dcc_clear_stats(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_clear_stats_param *clear_stats_param) +{ + QDF_STATUS status; + + status = wmi_unified_dcc_clear_stats( + get_wmi_unified_hdl_from_psoc(psoc), clear_stats_param); + if (status) + target_if_err("Failed to send clear DCC stats cmd: %d", status); + + return status; +} + +/** + * target_if_dcc_update_ndl() - command to update the NDL data + * @psoc: pointer to PSOC object + * @update_ndl_param: pointer to the request parameters + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +target_if_dcc_update_ndl(struct wlan_objmgr_psoc *psoc, + struct ocb_dcc_update_ndl_param *update_ndl_param) +{ + QDF_STATUS status; + + /* Send the WMI command */ + status = wmi_unified_dcc_update_ndl(get_wmi_unified_hdl_from_psoc(psoc), + update_ndl_param); + if (status) + target_if_err("Failed to send NDL update cmd: %d", status); + + return status; +} + +/** + * target_if_ocb_set_config_resp() - handler for channel config response + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int +target_if_ocb_set_config_resp(ol_scn_t scn, uint8_t *event_buf, + uint32_t len) +{ + int rc; + QDF_STATUS status; + uint32_t resp; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_ocb_rx_ops *ocb_rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", + scn, event_buf, len); + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_SB_ID); + if (!pdev) { + target_if_err("pdev is NULL"); + return -EINVAL; + } + + ocb_rx_ops = target_if_ocb_get_rx_ops(pdev); + if (ocb_rx_ops->ocb_set_config_status) { + status = wmi_extract_ocb_set_channel_config_resp( + get_wmi_unified_hdl_from_psoc(psoc), + event_buf, &resp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to extract config status"); + rc = -EINVAL; + goto exit; + } + status = ocb_rx_ops->ocb_set_config_status(psoc, resp); + if (status != QDF_STATUS_SUCCESS) { + target_if_err("ocb_set_config_status failed."); + rc = -EINVAL; + goto exit; + } + rc = 0; + } else { + target_if_fatal("No ocb_set_config_status callback"); + rc = -EINVAL; + } +exit: + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); + + return rc; +}; + +/** + * target_if_ocb_get_tsf_timer_resp() - handler for TSF timer response + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int target_if_ocb_get_tsf_timer_resp(ol_scn_t scn, + uint8_t *event_buf, + uint32_t len) +{ + int rc; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct ocb_get_tsf_timer_response response; + struct wlan_ocb_rx_ops *ocb_rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", + scn, event_buf, len); + + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_SB_ID); + if (!pdev) { + target_if_err("pdev is NULL"); + return -EINVAL; + } + + ocb_rx_ops = target_if_ocb_get_rx_ops(pdev); + if (ocb_rx_ops->ocb_tsf_timer) { + status = wmi_extract_ocb_tsf_timer( + get_wmi_unified_hdl_from_psoc(psoc), + event_buf, &response); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to extract tsf timer"); + rc = -EINVAL; + goto exit; + } + status = ocb_rx_ops->ocb_tsf_timer(psoc, &response); + if (status != QDF_STATUS_SUCCESS) { + target_if_err("ocb_tsf_timer failed."); + rc = -EINVAL; + goto exit; + } + rc = 0; + } else { + target_if_fatal("No ocb_tsf_timer callback"); + rc = -EINVAL; + } +exit: + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); + + return rc; +} + +/** + * target_if_dcc_update_ndl_resp() - handler for update NDL response + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int target_if_dcc_update_ndl_resp(ol_scn_t scn, + uint8_t *event_buf, + uint32_t len) +{ + int rc; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct ocb_dcc_update_ndl_response *resp; + struct wlan_ocb_rx_ops *ocb_rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", + scn, event_buf, len); + + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_SB_ID); + if (!pdev) { + target_if_err("pdev is NULL"); + return -EINVAL; + } + + /* Allocate and populate the response */ + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + rc = -ENOMEM; + goto exit; + } + + ocb_rx_ops = target_if_ocb_get_rx_ops(pdev); + if (ocb_rx_ops->ocb_dcc_ndl_update) { + status = wmi_extract_dcc_update_ndl_resp( + get_wmi_unified_hdl_from_psoc(psoc), + event_buf, resp); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to extract ndl status"); + rc = -EINVAL; + goto exit; + } + status = ocb_rx_ops->ocb_dcc_ndl_update(psoc, resp); + if (status != QDF_STATUS_SUCCESS) { + target_if_err("dcc_ndl_update failed."); + rc = -EINVAL; + goto exit; + } + rc = 0; + } else { + target_if_fatal("No dcc_ndl_update callback"); + rc = -EINVAL; + } +exit: + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); + if (resp) + qdf_mem_free(resp); + + return rc; +} + +/** + * target_if_dcc_get_stats_resp() - handler for get stats response + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int target_if_dcc_get_stats_resp(ol_scn_t scn, + uint8_t *event_buf, + uint32_t len) +{ + int rc; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct ocb_dcc_get_stats_response *response; + struct wlan_ocb_rx_ops *ocb_rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", + scn, event_buf, len); + + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_SB_ID); + if (!pdev) { + target_if_err("pdev is NULL"); + return -EINVAL; + } + + ocb_rx_ops = target_if_ocb_get_rx_ops(pdev); + if (ocb_rx_ops->ocb_dcc_stats_indicate) { + status = wmi_extract_dcc_stats( + get_wmi_unified_hdl_from_psoc(psoc), + event_buf, &response); + if (!response || QDF_IS_STATUS_ERROR(status)) { + target_if_err("Cannot get DCC stats"); + rc = -ENOMEM; + goto exit; + } + + status = ocb_rx_ops->ocb_dcc_stats_indicate(psoc, + response, + true); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("dcc_stats_indicate failed."); + rc = -EINVAL; + goto exit; + } + rc = 0; + } else { + target_if_fatal("No dcc_stats_indicate callback"); + rc = -EINVAL; + } +exit: + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); + if (response) + qdf_mem_free(response); + + return rc; +} + +/** + * target_if_dcc_stats_resp() - handler for DCC stats indication event + * @scn: scn handle + * @event_buf: pointer to the event buffer + * @len: length of the buffer + * + * Return: 0 on success + */ +static int target_if_dcc_stats_resp(ol_scn_t scn, uint8_t *event_buf, + uint32_t len) +{ + int rc; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct ocb_dcc_get_stats_response *response; + struct wlan_ocb_rx_ops *ocb_rx_ops; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", + scn, event_buf, len); + + if (!scn || !event_buf) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, event_buf); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, + WLAN_OCB_SB_ID); + if (!pdev) { + target_if_err("pdev is NULL"); + return -EINVAL; + } + + ocb_rx_ops = target_if_ocb_get_rx_ops(pdev); + if (ocb_rx_ops->ocb_dcc_stats_indicate) { + status = wmi_extract_dcc_stats( + get_wmi_unified_hdl_from_psoc(psoc), + event_buf, &response); + if (!response || QDF_IS_STATUS_ERROR(status)) { + target_if_err("Cannot get DCC stats"); + rc = -ENOMEM; + goto exit; + } + status = ocb_rx_ops->ocb_dcc_stats_indicate(psoc, + response, + false); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("dcc_stats_indicate failed."); + rc = -EINVAL; + goto exit; + } + rc = 0; + } else { + target_if_fatal("dcc_stats_indicate failed."); + response = NULL; + rc = -EINVAL; + } +exit: + wlan_objmgr_pdev_release_ref(pdev, WLAN_OCB_SB_ID); + if (response) + qdf_mem_free(response); + + return rc; +} + +QDF_STATUS target_if_ocb_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + QDF_STATUS rc; + + /* Initialize the members in WMA used by wma_ocb */ + rc = wmi_unified_register_event(get_wmi_unified_hdl_from_psoc(psoc), + wmi_ocb_set_config_resp_event_id, + target_if_ocb_set_config_resp); + if (QDF_IS_STATUS_ERROR(rc)) { + target_if_err("Failed to register OCB config resp event cb"); + return QDF_STATUS_E_FAILURE; + } + + rc = wmi_unified_register_event( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_ocb_get_tsf_timer_resp_event_id, + target_if_ocb_get_tsf_timer_resp); + if (QDF_IS_STATUS_ERROR(rc)) { + target_if_err("Failed to register OCB TSF resp event cb"); + goto unreg_set_config; + } + + rc = wmi_unified_register_event( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_get_stats_resp_event_id, + target_if_dcc_get_stats_resp); + if (QDF_IS_STATUS_ERROR(rc)) { + target_if_err("Failed to register DCC get stats resp event cb"); + goto unreg_tsf_timer; + } + + rc = wmi_unified_register_event( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_update_ndl_resp_event_id, + target_if_dcc_update_ndl_resp); + if (QDF_IS_STATUS_ERROR(rc)) { + target_if_err("Failed to register NDL update event cb"); + goto unreg_get_stats; + } + + rc = wmi_unified_register_event(get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_stats_event_id, + target_if_dcc_stats_resp); + if (QDF_IS_STATUS_ERROR(rc)) { + target_if_err("Failed to register DCC stats event cb"); + goto unreg_ndl; + } + + return QDF_STATUS_SUCCESS; + +unreg_ndl: + wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_update_ndl_resp_event_id); +unreg_get_stats: + wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_get_stats_resp_event_id); +unreg_tsf_timer: + wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_ocb_get_tsf_timer_resp_event_id); +unreg_set_config: + wmi_unified_unregister_event(get_wmi_unified_hdl_from_psoc(psoc), + wmi_ocb_set_config_resp_event_id); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +target_if_ocb_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + QDF_STATUS rc; + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_stats_event_id); + + if (QDF_IS_STATUS_ERROR(rc)) + target_if_err("Failed to unregister DCC stats event cb"); + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_update_ndl_resp_event_id); + + if (QDF_IS_STATUS_ERROR(rc)) + target_if_err("Failed to unregister NDL update event cb"); + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_dcc_get_stats_resp_event_id); + + if (QDF_IS_STATUS_ERROR(rc)) + target_if_err("Failed to unregister DCC get stats resp cb"); + + rc = wmi_unified_unregister_event_handler( + get_wmi_unified_hdl_from_psoc(psoc), + wmi_ocb_get_tsf_timer_resp_event_id); + + if (QDF_IS_STATUS_ERROR(rc)) + target_if_err("Failed to unregister OCB TSF resp event cb"); + + rc = wmi_unified_unregister_event(get_wmi_unified_hdl_from_psoc(psoc), + wmi_ocb_set_config_resp_event_id); + + if (QDF_IS_STATUS_ERROR(rc)) + target_if_err("Failed to unregister OCB config resp event cb"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +target_if_ocb_register_tx_ops(struct wlan_ocb_tx_ops *ocb_txops) +{ + ocb_txops->ocb_set_config = target_if_ocb_set_config; + ocb_txops->ocb_set_utc_time = target_if_ocb_set_utc_time; + ocb_txops->ocb_start_timing_advert = target_if_ocb_start_timing_advert; + ocb_txops->ocb_stop_timing_advert = target_if_ocb_stop_timing_advert; + ocb_txops->ocb_get_tsf_timer = target_if_ocb_get_tsf_timer; + ocb_txops->ocb_dcc_get_stats = target_if_dcc_get_stats; + ocb_txops->ocb_dcc_clear_stats = target_if_dcc_clear_stats; + ocb_txops->ocb_dcc_update_ndl = target_if_dcc_update_ndl; + ocb_txops->ocb_reg_ev_handler = target_if_ocb_register_event_handler; + ocb_txops->ocb_unreg_ev_handler = + target_if_ocb_unregister_event_handler; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/inc/target_if_p2p.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/inc/target_if_p2p.h new file mode 100644 index 0000000000..f8acd98a46 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/inc/target_if_p2p.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for P2P + */ + +#ifndef _TARGET_IF_P2P_H_ +#define _TARGET_IF_P2P_H_ + +#include + +struct wlan_objmgr_psoc; +struct p2p_ps_config; +struct p2p_lo_start; + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD + +/** + * target_if_p2p_register_lo_event_handler() - Register lo event handler + * @psoc: soc object + * @arg: additional argument + * + * Target interface API to register P2P listen offload event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_register_lo_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * target_if_p2p_unregister_lo_event_handler() - Unregister lo event handler + * @psoc: soc object + * @arg: additional argument + * + * Target interface API to unregister P2P listen offload event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_unregister_lo_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * target_if_p2p_lo_start() - Start listen offload + * @psoc: soc object + * @lo_start: lo start information + * + * Target interface API to start listen offload. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc, + struct p2p_lo_start *lo_start); + +/** + * target_if_p2p_lo_stop() - Stop listen offload + * @psoc: soc object + * @vdev_id: vdev id + * + * Target interface API to stop listen offload. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id); +#endif + +/** + * target_if_p2p_register_tx_ops() - Register P2P component TX OPS + * @tx_ops: lmac if transmit ops + * + * Return: None + */ +void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); + +/** + * target_if_p2p_register_noa_event_handler() - Register noa event handler + * @psoc: soc object + * @arg: additional argument + * + * Target interface API to register P2P noa event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_register_noa_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * target_if_p2p_unregister_noa_event_handler() - Unregister noa event handler + * @psoc: soc object + * @arg: additional argument + * + * Target interface API to unregister P2P listen offload event handler. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_unregister_noa_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * target_if_p2p_set_ps() - Set power save + * @psoc: soc object + * @ps_config: powersave configuration + * + * Target interface API to set power save. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc, + struct p2p_ps_config *ps_config); + +/** + * target_if_p2p_set_noa() - Disable / Enable NOA + * @psoc: soc object + * @vdev_id: vdev id + * @disable_noa: TRUE - Disable NoA, FALSE - Enable NoA + * + * Target interface API to Disable / Enable P2P NOA. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool disable_noa); + +#endif /* _TARGET_IF_P2P_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/inc/target_if_p2p_mcc_quota.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/inc/target_if_p2p_mcc_quota.h new file mode 100644 index 0000000000..54f3de63c1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/inc/target_if_p2p_mcc_quota.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for P2P MCC quota event processing + */ + +#ifndef _TARGET_IF_P2P_MCC_QUOTA_H_ +#define _TARGET_IF_P2P_MCC_QUOTA_H_ + +struct wlan_lmac_if_tx_ops; + +#ifdef WLAN_FEATURE_MCC_QUOTA +/** + * target_if_mcc_quota_register_tx_ops() - Register mcc quota TX OPS + * @tx_ops: lmac if transmit ops + * + * Return: None + */ +void +target_if_mcc_quota_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); +#else +static inline void +target_if_mcc_quota_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ +} +#endif +#endif /* _TARGET_IF_P2P_MCC_QUOTA_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/src/target_if_p2p.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/src/target_if_p2p.c new file mode 100644 index 0000000000..db2c72d9f8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/src/target_if_p2p.c @@ -0,0 +1,484 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs definitions for P2P + */ + +#include +#include +#include "target_if.h" +#include "target_if_p2p.h" +#include "target_if_p2p_mcc_quota.h" +#include "init_deinit_lmac.h" + +static inline struct wlan_lmac_if_p2p_rx_ops * +target_if_psoc_get_p2p_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &(psoc->soc_cb.rx_ops->p2p); +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +static inline void +target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops) +{ + p2p_tx_ops->lo_start = target_if_p2p_lo_start; + p2p_tx_ops->lo_stop = target_if_p2p_lo_stop; + p2p_tx_ops->reg_lo_ev_handler = + target_if_p2p_register_lo_event_handler; + p2p_tx_ops->unreg_lo_ev_handler = + target_if_p2p_unregister_lo_event_handler; +} + +/** + * target_p2p_lo_event_handler() - WMI callback for lo stop event + * @scn: pointer to scn + * @data: event buffer + * @datalen: buffer length + * + * This function gets called from WMI when triggered wmi event + * wmi_p2p_lo_stop_event_id. + * + * Return: 0 - success + * others - failure + */ +static int target_p2p_lo_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct p2p_lo_event *event_info; + struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen); + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi handle"); + return -EINVAL; + } + + event_info = qdf_mem_malloc(sizeof(*event_info)); + if (!event_info) + return -ENOMEM; + + if (wmi_extract_p2p_lo_stop_ev_param(wmi_handle, data, + event_info)) { + target_if_err("Failed to extract wmi p2p lo stop event"); + qdf_mem_free(event_info); + return -EINVAL; + } + + p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); + if (p2p_rx_ops->lo_ev_handler) { + status = p2p_rx_ops->lo_ev_handler(psoc, event_info); + target_if_debug("call lo event handler, status:%d", + status); + } else { + qdf_mem_free(event_info); + target_if_debug("no valid lo event handler"); + } + + return qdf_status_to_os_return(status); +} + +QDF_STATUS target_if_p2p_register_lo_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, arg:%pK", psoc, arg); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event(wmi_handle, + wmi_p2p_lo_stop_event_id, + target_p2p_lo_event_handler); + + target_if_debug("wmi register lo event handle, status:%d", status); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_p2p_unregister_lo_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, arg:%pK", psoc, arg); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_unregister_event(wmi_handle, + wmi_p2p_lo_stop_event_id); + + target_if_debug("wmi unregister lo event handle, status:%d", status); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_p2p_lo_start(struct wlan_objmgr_psoc *psoc, + struct p2p_lo_start *lo_start) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + if (!lo_start) { + target_if_err("lo start parameters is null"); + return QDF_STATUS_E_INVAL; + } + target_if_debug("psoc:%pK, vdev_id:%d", psoc, lo_start->vdev_id); + + return wmi_unified_p2p_lo_start_cmd(wmi_handle, lo_start); +} + +QDF_STATUS target_if_p2p_lo_stop(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, vdev_id:%d", psoc, vdev_id); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_p2p_lo_stop_cmd(wmi_handle, + (uint8_t)vdev_id); +} +#else +static inline void +target_if_p2p_lo_register_tx_ops(struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops) +{ +} +#endif /* FEATURE_P2P_LISTEN_OFFLOAD */ + +/** + * target_p2p_noa_event_handler() - WMI callback for noa event + * @scn: pointer to scn + * @data: event buffer + * @datalen: buffer length + * + * This function gets called from WMI when triggered WMI event + * wmi_p2p_noa_event_id. + * + * Return: 0 - success + * others - failure + */ +static int target_p2p_noa_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct p2p_noa_info *event_info; + struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen); + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi handle"); + return -EINVAL; + } + + event_info = qdf_mem_malloc(sizeof(*event_info)); + if (!event_info) + return -ENOMEM; + + if (wmi_extract_p2p_noa_ev_param(wmi_handle, data, + event_info)) { + target_if_err("failed to extract wmi p2p noa event"); + qdf_mem_free(event_info); + return -EINVAL; + } + + p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); + if (p2p_rx_ops->noa_ev_handler) { + status = p2p_rx_ops->noa_ev_handler(psoc, event_info); + target_if_debug("call noa event handler, status:%d", + status); + } else { + qdf_mem_free(event_info); + target_if_debug("no valid noa event handler"); + } + + return qdf_status_to_os_return(status); +} + +QDF_STATUS target_if_p2p_register_noa_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + int status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, arg:%pK", psoc, arg); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event(wmi_handle, + wmi_p2p_noa_event_id, + target_p2p_noa_event_handler); + + target_if_debug("wmi register noa event handle, status:%d", + status); + + return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +QDF_STATUS target_if_p2p_unregister_noa_event_handler( + struct wlan_objmgr_psoc *psoc, void *arg) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, arg:%pK", psoc, arg); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_unregister_event(wmi_handle, + wmi_p2p_noa_event_id); + + target_if_debug("wmi unregister noa event handle, status:%d", + status); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_p2p_set_ps(struct wlan_objmgr_psoc *psoc, + struct p2p_ps_config *ps_config) +{ + struct p2p_ps_params cmd; + QDF_STATUS status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + if (!ps_config) { + target_if_err("ps config parameters is null"); + return QDF_STATUS_E_INVAL; + } + + target_if_debug("psoc:%pK, vdev_id:%d, opp_ps:%d", psoc, + ps_config->vdev_id, ps_config->opp_ps); + + cmd.opp_ps = ps_config->opp_ps; + cmd.ctwindow = ps_config->ct_window; + cmd.count = ps_config->count; + cmd.duration = ps_config->duration; + cmd.interval = ps_config->interval; + cmd.single_noa_duration = ps_config->single_noa_duration; + cmd.ps_selection = ps_config->ps_selection; + cmd.session_id = ps_config->vdev_id; + cmd.start = ps_config->start; + + if (ps_config->opp_ps) + status = wmi_unified_set_p2pgo_oppps_req(wmi_handle, + &cmd); + else + status = wmi_unified_set_p2pgo_noa_req_cmd(wmi_handle, + &cmd); + + if (status != QDF_STATUS_SUCCESS) + target_if_err("Failed to send set uapsd param, %d", + status); + + return status; +} + +QDF_STATUS target_if_p2p_set_noa(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, bool disable_noa) +{ + struct vdev_set_params param; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + target_if_debug("psoc:%pK, vdev_id:%d disable_noa:%d", + psoc, vdev_id, disable_noa); + param.vdev_id = vdev_id; + param.param_id = wmi_vdev_param_disable_noa_p2p_go; + param.param_value = (uint32_t)disable_noa; + + return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); +} + +static int target_p2p_mac_rx_filter_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct p2p_set_mac_filter_evt event_info; + struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi handle"); + return -EINVAL; + } + + if (wmi_extract_mac_addr_rx_filter_evt_param(wmi_handle, data, + &event_info)) { + target_if_err("failed to extract wmi p2p noa event"); + return -EINVAL; + } + target_if_debug("vdev_id %d status %d", event_info.vdev_id, + event_info.status); + p2p_rx_ops = target_if_psoc_get_p2p_rx_ops(psoc); + if (p2p_rx_ops && p2p_rx_ops->add_mac_addr_filter_evt_handler) + status = p2p_rx_ops->add_mac_addr_filter_evt_handler( + psoc, &event_info); + else + target_if_debug("no add mac addr filter event handler"); + + return qdf_status_to_os_return(status); +} + +static QDF_STATUS target_if_p2p_register_macaddr_rx_filter_evt_handler( + struct wlan_objmgr_psoc *psoc, bool reg) +{ + int status; + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + target_if_debug("psoc:%pK, register %d mac addr rx evt", psoc, reg); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + if (reg) + status = wmi_unified_register_event( + wmi_handle, + wmi_vdev_add_macaddr_rx_filter_event_id, + target_p2p_mac_rx_filter_event_handler); + else + status = wmi_unified_unregister_event( + wmi_handle, + wmi_vdev_add_macaddr_rx_filter_event_id); + + return status == 0 ? QDF_STATUS_SUCCESS : QDF_STATUS_E_FAILURE; +} + +static QDF_STATUS target_if_p2p_set_mac_addr_rx_filter_cmd( + struct wlan_objmgr_psoc *psoc, struct set_rx_mac_filter *param) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_set_mac_addr_rx_filter(wmi_handle, param); +} + +void target_if_p2p_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops; + + if (!tx_ops) { + target_if_err("lmac tx_ops is null"); + return; + } + + p2p_tx_ops = &tx_ops->p2p; + p2p_tx_ops->set_ps = target_if_p2p_set_ps; + p2p_tx_ops->set_noa = target_if_p2p_set_noa; + p2p_tx_ops->reg_noa_ev_handler = + target_if_p2p_register_noa_event_handler; + p2p_tx_ops->unreg_noa_ev_handler = + target_if_p2p_unregister_noa_event_handler; + p2p_tx_ops->reg_mac_addr_rx_filter_handler = + target_if_p2p_register_macaddr_rx_filter_evt_handler; + p2p_tx_ops->set_mac_addr_rx_filter_cmd = + target_if_p2p_set_mac_addr_rx_filter_cmd; + target_if_mcc_quota_register_tx_ops(tx_ops); + + /* register P2P listen offload callbacks */ + target_if_p2p_lo_register_tx_ops(p2p_tx_ops); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/src/target_if_p2p_mcc_quota.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/src/target_if_p2p_mcc_quota.c new file mode 100644 index 0000000000..1612ee1102 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/p2p/src/target_if_p2p_mcc_quota.c @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs implementation for P2P mcc quota event + * processing + */ + +#include +#include "wlan_p2p_mcc_quota_public_struct.h" +#include "target_if.h" +#include "target_if_p2p_mcc_quota.h" + +/** + * target_if_mcc_quota_event_handler() - WMI callback for mcc_quota + * @scn: pointer to scn + * @data: event buffer + * @datalen: buffer length + * + * This function gets called from WMI when triggered WMI event + * WMI_RESMGR_CHAN_TIME_QUOTA_CHANGED_EVENTID + * + * Return: 0 - success, others - failure + */ +static int target_if_mcc_quota_event_handler(ol_scn_t scn, uint8_t *data, + uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct mcc_quota_info *event_info; + struct wlan_lmac_if_rx_ops *rx_ops; + struct wlan_lmac_if_p2p_rx_ops *p2p_rx_ops; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, data, datalen); + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi handle"); + return -EINVAL; + } + + event_info = qdf_mem_malloc(sizeof(*event_info)); + if (!event_info) + return -ENOMEM; + + if (wmi_extract_mcc_quota_ev_param(wmi_handle, data, + event_info)) { + target_if_err("failed to extract mcc quota event"); + qdf_mem_free(event_info); + return -EINVAL; + } + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (!rx_ops) { + target_if_err("failed to get soc rx ops"); + qdf_mem_free(event_info); + return -EINVAL; + } + p2p_rx_ops = &rx_ops->p2p; + if (p2p_rx_ops->mcc_quota_ev_handler) { + status = p2p_rx_ops->mcc_quota_ev_handler(psoc, event_info); + if (QDF_IS_STATUS_ERROR(status)) + target_if_debug("quota event handler, status:%d", + status); + } else { + target_if_debug("no valid mcc quota event handler"); + } + qdf_mem_free(event_info); + + return qdf_status_to_os_return(status); +} + +/** + * target_if_register_mcc_quota_event_handler() - Register or unregister + * mcc quota wmi event handler + * @psoc: psoc object + * @reg: register or unregister flag + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS +target_if_register_mcc_quota_event_handler(struct wlan_objmgr_psoc *psoc, + bool reg) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + if (reg) { + status = wmi_unified_register_event_handler(wmi_handle, + wmi_resmgr_chan_time_quota_changed_eventid, + target_if_mcc_quota_event_handler, + WMI_RX_SERIALIZER_CTX); + + target_if_debug("wmi register mcc_quota event handle, status:%d", + status); + } else { + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_resmgr_chan_time_quota_changed_eventid); + + target_if_debug("wmi unregister mcc_quota event handle, status:%d", + status); + } + + return status; +} + +void target_if_mcc_quota_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_p2p_tx_ops *p2p_tx_ops = &tx_ops->p2p; + + p2p_tx_ops->reg_mcc_quota_ev_handler = + target_if_register_mcc_quota_event_handler; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pkt_capture/inc/target_if_pkt_capture.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pkt_capture/inc/target_if_pkt_capture.h new file mode 100644 index 0000000000..10ded23c95 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pkt_capture/inc/target_if_pkt_capture.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare various api/struct which shall be used + * by packet capture component for wmi cmd (tx path) and + * event (rx) handling. + */ + +#ifndef _TARGET_IF_PKT_CAPTURE_H_ +#define _TARGET_IF_PKT_CAPTURE_H_ + +#include +#include +#include +#include +#include +#include + +/** + * target_if_pkt_capture_register_rx_ops() - Register packet capture RX ops + * @rx_ops: packet capture component reception ops + * Return: None + */ +void +target_if_pkt_capture_register_rx_ops(struct wlan_pkt_capture_rx_ops *rx_ops); + +/** + * target_if_pkt_capture_register_tx_ops() - Register packet capture TX ops + * @tx_ops: pkt capture component transmit ops + * + * Return: None + */ +void target_if_pkt_capture_register_tx_ops(struct wlan_pkt_capture_tx_ops + *tx_ops); +#endif /* _TARGET_IF_PKT_CAPTURE_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pkt_capture/src/target_if_pkt_capture.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pkt_capture/src/target_if_pkt_capture.c new file mode 100644 index 0000000000..6fa49693b3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pkt_capture/src/target_if_pkt_capture.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Target interface file for pkt_capture component to + * Implement api's which shall be used by pkt_capture component + * in target_if internally. + */ + +#include +#include +#include +#include +#include +#include + +/** + * target_if_set_packet_capture_mode() - set packet capture mode + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @mode: mode to set + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_set_packet_capture_mode(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pkt_capture_mode mode) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct vdev_set_params param; + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + target_if_debug("psoc:%pK, vdev_id:%d mode:%d", + psoc, vdev_id, mode); + + param.vdev_id = vdev_id; + param.param_id = wmi_vdev_param_packet_capture_mode; + param.param_value = (uint32_t)mode; + + status = wmi_unified_vdev_set_param_send(wmi_handle, ¶m); + if (QDF_IS_STATUS_SUCCESS(status)) + ucfg_pkt_capture_set_pktcap_mode(psoc, mode); + else + pkt_capture_err("failed to set packet capture mode"); + + return status; +} + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +/** + * target_if_set_packet_capture_config() - set packet capture config + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @config_value: config value + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_set_packet_capture_config + (struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pkt_capture_config config_value) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_objmgr_vdev *vdev; + struct vdev_set_params param; + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PKT_CAPTURE_ID); + if (!vdev) { + pkt_capture_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + target_if_debug("psoc:%pK, vdev_id:%d config_value:%d", + psoc, vdev_id, config_value); + + param.vdev_id = vdev_id; + param.param_id = wmi_vdev_param_smart_monitor_config; + param.param_value = (uint32_t)config_value; + + status = wmi_unified_vdev_set_param_send(wmi_handle, ¶m); + if (QDF_IS_STATUS_SUCCESS(status)) + ucfg_pkt_capture_set_pktcap_config(vdev, config_value); + else + pkt_capture_err("failed to set packet capture config"); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_PKT_CAPTURE_ID); + return status; +} +#else +static QDF_STATUS +target_if_set_packet_capture_config + (struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum pkt_capture_config config_value) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * target_if_set_packet_capture_beacon_interval() - set packet capture beacon + * interval + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @nth_value: Beacon report period + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_set_packet_capture_beacon_interval + (struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t nth_value) +{ + wmi_unified_t wmi_handle = lmac_get_wmi_unified_hdl(psoc); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct vdev_set_params param; + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + target_if_debug("psoc:%pK, vdev_id:%d nth_value:%d", + psoc, vdev_id, nth_value); + + param.vdev_id = vdev_id; + param.param_id = wmi_vdev_param_nth_beacon_to_host; + param.param_value = nth_value; + + status = wmi_unified_vdev_set_param_send(wmi_handle, ¶m); + if (QDF_IS_STATUS_ERROR(status)) + pkt_capture_err("failed to set beacon interval"); + + return status; +} + +/** + * target_if_mgmt_offload_data_event_handler() - offload event handler + * @handle: scn handle + * @data: mgmt data + * @data_len: data length + * + * Process management offload frame. + * + * Return: 0 for success or error code + */ +static int +target_if_mgmt_offload_data_event_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + static uint8_t limit_prints_invalid_len = RATE_LIMIT - 1; + struct mgmt_offload_event_params params; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + qdf_nbuf_t wbuf; + + psoc = target_if_get_psoc_from_scn_hdl(handle); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return -EINVAL; + } + + pdev = target_if_get_pdev_from_scn_hdl(handle); + if (!pdev) { + pkt_capture_err("pdev is NULL"); + return -EINVAL; + } + + if (!(wlan_pkt_capture_is_tx_mgmt_enable(pdev))) + return -EINVAL; + + status = wmi_unified_extract_vdev_mgmt_offload_event(wmi_handle, data, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Extract mgmt offload event failed"); + return -EINVAL; + } + + if (!params.buf) { + pkt_capture_err("Mgmt offload buf is NULL"); + return -EINVAL; + } + + if (params.buf_len < sizeof(struct ieee80211_hdr_3addr) || + params.buf_len > data_len) { + limit_prints_invalid_len++; + if (limit_prints_invalid_len == RATE_LIMIT) { + pkt_capture_debug( + "Invalid mgmt packet, data_len %u, params.buf_len %u", + data_len, params.buf_len); + limit_prints_invalid_len = 0; + } + return -EINVAL; + } + + wbuf = qdf_nbuf_alloc(NULL, + roundup(params.buf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!wbuf) { + pkt_capture_err("Failed to allocate wbuf for mgmt pkt len(%u)", + params.buf_len); + return -ENOMEM; + } + + qdf_nbuf_put_tail(wbuf, params.buf_len); + qdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL); + qdf_mem_copy(qdf_nbuf_data(wbuf), params.buf, params.buf_len); + + status = params.tx_status; + if (QDF_STATUS_SUCCESS != + ucfg_pkt_capture_process_mgmt_tx_data(pdev, ¶ms, + wbuf, status)) + qdf_nbuf_free(wbuf); + + return 0; +} + +/** + * target_if_register_mgmt_data_offload_event() - Register mgmt data offload + * event handler + * @psoc: wlan psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_register_mgmt_data_offload_event(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + PKT_CAPTURE_ENTER(); + + if (!psoc) { + pkt_capture_err("psoc got NULL"); + return QDF_STATUS_E_FAILURE; + } + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + pkt_capture_err("wmi_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if ((ucfg_pkt_capture_get_mode(psoc) != PACKET_CAPTURE_MODE_DISABLE) && + wmi_service_enabled(wmi_handle, + wmi_service_packet_capture_support)) { + QDF_STATUS status; + + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_mgmt_offload_data_event_id, + target_if_mgmt_offload_data_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Failed to register MGMT offload handler"); + return QDF_STATUS_E_FAILURE; + } + } + + PKT_CAPTURE_EXIT(); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_unregister_mgmt_data_offload_event() - Unregister mgmt data offload + * event handler + * @psoc: wlan psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_unregister_mgmt_data_offload_event(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + QDF_STATUS status; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + pkt_capture_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_unregister_event(wmi_handle, + wmi_mgmt_offload_data_event_id); + if (status) + pkt_capture_err("unregister mgmt data offload event cb failed"); + + return status; +} + +#ifdef WLAN_FEATURE_PKT_CAPTURE_V2 +static int +target_if_smart_monitor_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + struct smu_event_params params; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = target_if_get_psoc_from_scn_hdl(handle); + if (!psoc) { + pkt_capture_err("psoc is NULL"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return -EINVAL; + } + + if (!(ucfg_pkt_capture_get_pktcap_mode(psoc) & + PKT_CAPTURE_MODE_MGMT_ONLY)) + return -EINVAL; + + status = wmi_unified_extract_smart_monitor_event(wmi_handle, data, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + pkt_capture_err("Extract smart monitor event failed"); + return -EINVAL; + } + + tgt_pkt_capture_smu_event(psoc, ¶ms); + return 0; +} + +/** + * target_if_register_smart_monitor_event() - Register smu event + * @psoc: wlan psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_register_smart_monitor_event(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + if (!psoc) { + pkt_capture_err("psoc got NULL"); + return QDF_STATUS_E_FAILURE; + } + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + pkt_capture_err("wmi_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if ((ucfg_pkt_capture_get_mode(psoc) != PACKET_CAPTURE_MODE_DISABLE) && + wmi_service_enabled(wmi_handle, + wmi_service_packet_capture_support)) { + uint8_t status; + + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_vdev_smart_monitor_event_id, + target_if_smart_monitor_event_handler, + WMI_RX_WORK_CTX); + if (status) { + pkt_capture_err("Failed to register smart monitor handler"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_unregister_smart_monitor_event() - Unregister smu event + * @psoc: wlan psoc object + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_unregister_smart_monitor_event(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + QDF_STATUS status; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + pkt_capture_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_unregister_event(wmi_handle, + wmi_vdev_smart_monitor_event_id); + if (status) + pkt_capture_err("unregister smart monitor event handler failed"); + + return status; +} +#else +static QDF_STATUS +target_if_register_smart_monitor_event(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +target_if_unregister_smart_monitor_event(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif +void +target_if_pkt_capture_register_rx_ops(struct wlan_pkt_capture_rx_ops *rx_ops) +{ + if (!rx_ops) { + target_if_err("packet capture rx_ops is null"); + return; + } + + rx_ops->pkt_capture_register_ev_handlers = + target_if_register_mgmt_data_offload_event; + + rx_ops->pkt_capture_unregister_ev_handlers = + target_if_unregister_mgmt_data_offload_event; + + rx_ops->pkt_capture_register_smart_monitor_event = + target_if_register_smart_monitor_event; + + rx_ops->pkt_capture_unregister_smart_monitor_event = + target_if_unregister_smart_monitor_event; +} + +void +target_if_pkt_capture_register_tx_ops(struct wlan_pkt_capture_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("packet capture tx_ops is null"); + return; + } + + tx_ops->pkt_capture_send_mode = target_if_set_packet_capture_mode; + tx_ops->pkt_capture_send_config = target_if_set_packet_capture_config; + tx_ops->pkt_capture_send_beacon_interval = + target_if_set_packet_capture_beacon_interval; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/inc/target_if_pmo.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/inc/target_if_pmo.h new file mode 100644 index 0000000000..c4f1f49c33 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/inc/target_if_pmo.h @@ -0,0 +1,546 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Declare various api/struct which shall be used + * by pmo component for wmi cmd (tx path) and + * event (rx) handling. + */ + +#ifndef _TARGET_IF_PMO_H_ +#define _TARGET_IF_PMO_H_ + +#include "target_if.h" +#include "wlan_pmo_tgt_api.h" +#include "wlan_pmo_obj_mgmt_public_struct.h" + +/** + * target_if_pmo_enable_wow_wakeup_event() - Enable wow wakeup events. + * @vdev:objmgr vdev handle + * @bitmap: Event bitmap + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_enable_wow_wakeup_event(struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap); + +/** + * target_if_pmo_disable_wow_wakeup_event() - Disable wow wakeup events. + * @vdev:objmgr vdev handle + * @bitmap: Event bitmap + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_disable_wow_wakeup_event( + struct wlan_objmgr_vdev *vdev, uint32_t *bitmap); + +/** + * target_if_pmo_send_wow_patterns_to_fw() - Sends WOW patterns to FW. + * @vdev: objmgr vdev handle + * @ptrn_id: pattern id + * @ptrn: pattern + * @ptrn_len: pattern length + * @ptrn_offset: pattern offset + * @mask: mask + * @mask_len: mask length + * @user: true for user configured pattern and false for default pattern + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_wow_patterns_to_fw(struct wlan_objmgr_vdev *vdev, + uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user); + +QDF_STATUS target_if_pmo_del_wow_patterns_to_fw(struct wlan_objmgr_vdev *vdev, + uint8_t ptrn_id); + +/** + * target_if_pmo_send_enhance_mc_offload_req() - send enhance mc offload req + * @vdev: objmgr vdev + * @enable: enable or disable enhance multicast offload + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_send_enhance_mc_offload_req( + struct wlan_objmgr_vdev *vdev, + bool enable); + +/** + * target_if_pmo_set_mc_filter_req() - set mcast filter command to fw + * @vdev: objmgr vdev handle + * @multicast_addr: mcast address + * + * Return: 0 for success or error code + */ +QDF_STATUS target_if_pmo_set_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr); + +/** + * target_if_pmo_clear_mc_filter_req() - clear mcast filter command to fw + * @vdev: objmgr vdev handle + * @multicast_addr: mcast address + * + * Return: 0 for success or error code + */ +QDF_STATUS target_if_pmo_clear_mc_filter_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr); + +/** + * target_if_pmo_get_multiple_mc_filter_support() - get multiple mc filter + * request fw support + * @psoc: the psoc containing the vdev to configure + * + * Return: true if fw supports else false + */ +bool target_if_pmo_get_multiple_mc_filter_support( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_set_multiple_mc_filter_req() - set multiple mcast filter + * command to fw + * @vdev: objmgr vdev handle + * @mc_list: mcast address list + * + * Return: 0 for success or error code + */ +QDF_STATUS target_if_pmo_set_multiple_mc_filter_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + +/** + * target_if_pmo_clear_multiple_mc_filter_req() - clear multiple mcast + * filter command to fw + * @vdev: objmgr vdev handle + * @mc_list: mcast address list + * + * Return: 0 for success or error code + */ +QDF_STATUS target_if_pmo_clear_multiple_mc_filter_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list); + +/** + * target_if_pmo_send_ra_filter_req() - set RA filter pattern in fw + * @vdev: objmgr vdev handle + * @default_pattern: default pattern id + * @rate_limit_interval: ra rate limit interval + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_ra_filter_req(struct wlan_objmgr_vdev *vdev, + uint8_t default_pattern, uint16_t rate_limit_interval); + +/** + * target_if_pmo_send_action_frame_patterns() - register action frame map to fw + * @vdev: objmgr vdev handle + * @ip_cmd: Action frame wakeup params + * + * This is called to push action frames wow patterns from local + * cache to firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_pmo_send_action_frame_patterns( + struct wlan_objmgr_vdev *vdev, + struct pmo_action_wakeup_set_params *ip_cmd); + +/** + * target_if_pmo_conf_hw_filter() - configure hardware filter in DTIM mode + * @psoc: the psoc containing the vdev to configure + * @req: the request parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_pmo_conf_hw_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_hw_filter_params *req); + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * target_if_pmo_send_pkt_filter_req() - enable packet filter + * @vdev: objmgr vdev + * @rcv_filter_param: filter params + * + * This function enable packet filter + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS target_if_pmo_send_pkt_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_cfg *rcv_filter_param); + +/** + * target_if_pmo_clear_pkt_filter_req() - disable packet filter + * @vdev: objmgr vdev + * @rcv_clear_param: filter params + * + * This function disable packet filter + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS target_if_pmo_clear_pkt_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_clear_param *rcv_clear_param); +#endif + +/** + * target_if_pmo_send_arp_offload_req() - sends arp request to fwr + * @vdev: objmgr vdev + * @arp_offload_req: arp offload req + * @ns_offload_req: ns offload request + * + * This functions sends arp request to fwr. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS target_if_pmo_send_arp_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req); + +#ifdef WLAN_NS_OFFLOAD +/** + * target_if_pmo_send_ns_offload_req() - sends ns request to fwr + * @vdev: objmgr vdev + * @arp_offload_req: arp offload req + * @ns_offload_req: ns offload request + * + * This functions sends ns request to fwr. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS target_if_pmo_send_ns_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req); +#else /* WLAN_NS_OFFLOAD */ +static inline QDF_STATUS +target_if_pmo_send_ns_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_NS_OFFLOAD */ +/** + * target_if_pmo_send_gtk_offload_req() - send gtk offload request in fwr + * @vdev: objmgr vdev handle + * @gtk_offload_req: gtk offload request + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_offload_req); + +/** + * target_if_pmo_send_gtk_response_req() - send gtk response request in fwr + * @vdev: objmgr vdev handle + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_gtk_response_req(struct wlan_objmgr_vdev *vdev); + +/** + * target_if_pmo_gtk_offload_status_event() - GTK offload status event handler + * @scn_handle: scn handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int target_if_pmo_gtk_offload_status_event(void *scn_handle, + uint8_t *event, uint32_t len); + +/** + * target_if_pmo_send_lphb_enable() - enable command of LPHB config req + * @psoc: objmgr psoc handle + * @ts_lphb_enable: lphb enable request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_lphb_enable(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_enable_req *ts_lphb_enable); + +/** + * target_if_pmo_send_lphb_tcp_params() - set lphb tcp params config request + * @psoc: objmgr psoc handle + * @ts_lphb_tcp_param: lphb tcp params which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_params *ts_lphb_tcp_param); + +/** + * target_if_pmo_send_lphb_tcp_pkt_filter() - send lphb tcp packet filter req + * @psoc: objmgr psoc handle + * @ts_lphb_tcp_filter: lphb tcp filter request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter); + +/** + * target_if_pmo_send_lphb_udp_params() - Send udp param command of LPHB + * @psoc: objmgr psoc handle + * @ts_lphb_udp_param: lphb udp params which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_params *ts_lphb_udp_param); + +/** + * target_if_pmo_send_lphb_udp_pkt_filter() - Send lphb udp pkt filter cmd req + * @psoc: objmgr psoc handle + * @ts_lphb_udp_filter: lphb udp filter request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter); + +/** + * target_if_pmo_lphb_evt_handler() - send LPHB indication to os if /HDD + * @psoc: objmgr psoc handle + * @event: lphb event buffer + * + * Return: QDF_STATUS_SUCCESS for success else error code + */ +QDF_STATUS target_if_pmo_lphb_evt_handler(struct wlan_objmgr_psoc *psoc, + uint8_t *event); + +/** + * target_if_pmo_send_vdev_update_param_req() - Send vdev param value to fwr + * @vdev: objmgr vdev + * @param_id: tell vdev param id which needs to be updated in fwr + * @param_value: vdev parameter value + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_vdev_update_param_req( + struct wlan_objmgr_vdev *vdev, + uint32_t param_id, uint32_t param_value); + +/** + * target_if_pmo_send_vdev_ps_param_req() - Send vdev ps param value to fwr + * @vdev: objmgr vdev + * @param_id: tell vdev param id which needs to be updated in fwr + * @param_value: vdev parameter value + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_vdev_ps_param_req( + struct wlan_objmgr_vdev *vdev, + uint32_t param_id, + uint32_t param_value); + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * target_if_pmo_send_igmp_offload_req() - Send igmp offload req to fw + * @vdev: objmgr vdev + * @pmo_igmp_req: igmp req + * + * Return: QDF status + */ +QDF_STATUS +target_if_pmo_send_igmp_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req); +#else +static inline QDF_STATUS +target_if_pmo_send_igmp_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * target_if_pmo_psoc_update_bus_suspend() - update wmi bus suspend flag + * @psoc: objmgr psoc + * @value: bus suspend value + * + * Return: None + */ +void target_if_pmo_psoc_update_bus_suspend(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * target_if_pmo_psoc_get_host_credits() - get available host credits + * @psoc: objmgr psoc + * + * Return: return host credits + */ +int target_if_pmo_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_get_pending_cmnds() - get wmi pending commands + * @psoc: objmgr psoc + * + * Return: return wmi pending commands + */ +int target_if_pmo_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_update_target_suspend_flag() - set wmi target suspend flag + * @psoc: objmgr psoc + * @value: value + * + * Return: None + */ +void target_if_pmo_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * target_if_pmo_update_target_suspend_acked_flag() - set wmi target suspend + * acked flag + * @psoc: objmgr psoc + * @value: value + * + * Return: None + */ +void target_if_pmo_update_target_suspend_acked_flag( + struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * target_if_pmo_is_target_suspended() - get wmi target suspend flag + * @psoc: objmgr psoc + * + * Return: true if target suspended, false otherwise + */ +bool target_if_pmo_is_target_suspended(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_send_wow_enable_req() -send wow enable request + * @psoc: objmgr psoc + * @param: wow command params + * + * Return: return QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_psoc_send_wow_enable_req(struct wlan_objmgr_psoc *psoc, + struct pmo_wow_cmd_params *param); + +/** + * target_if_pmo_psoc_send_suspend_req() - fp to send suspend request + * @psoc: objmgr psoc + * @param: target suspend params + * + * Return: return QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_psoc_send_suspend_req(struct wlan_objmgr_psoc *psoc, + struct pmo_suspend_params *param); + +/** + * target_if_pmo_set_runtime_pm_in_progress() - set runtime pm status + * @psoc: objmgr psoc + * @value: set runtime pm status + * + * Return: none + */ +void target_if_pmo_set_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc, + bool value); + +/** + * target_if_pmo_get_runtime_pm_in_progress() - fp to get runtime pm status + * @psoc: objmgr psoc + * + * Return: true if runtime pm in progress else false + */ +bool target_if_pmo_get_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_send_host_wakeup_ind() - send host wake ind to fwr + * @psoc: objmgr psoc + * + * Return: return QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_psoc_send_host_wakeup_ind( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_send_target_resume_req() -send target resume request + * @psoc: objmgr psoc + * + * Return: return QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_psoc_send_target_resume_req( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_send_d0wow_enable_req() - send d0 wow enable request + * @psoc: objmgr psoc + * + * Return: return QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_psoc_send_d0wow_enable_req( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_send_d0wow_disable_req() - send d0 wow disable request + * @psoc: objmgr psoc + * + * Return: return QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS target_if_pmo_psoc_send_d0wow_disable_req( + struct wlan_objmgr_psoc *psoc); + +/** + * target_if_pmo_psoc_send_idle_monitor_cmd() - send screen status to firmware + * @psoc: objmgr psoc + * @val: Idle monitor value + * + * Return: QDF_STATUS_SUCCESS on success else error code + */ +QDF_STATUS +target_if_pmo_psoc_send_idle_monitor_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * target_if_pmo_register_tx_ops() - Register PMO component TX OPS + * @tx_ops: PMO if transmit ops + * + * Return: None + */ +void target_if_pmo_register_tx_ops(struct wlan_pmo_tx_ops *tx_ops); + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +/** + * target_if_pmo_send_icmp_offload_req() - sends icmp request to fwr + * @psoc: objmgr psoc + * @pmo_icmp_req: icmp offload request + * + * This functions sends icmp request to fwr. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +target_if_pmo_send_icmp_offload_req(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req); +#endif + +/** + * target_if_pmo_set_wow_enable_ack_failed() - set wow enable ack failure status + * @psoc: objmgr psoc + * + * Return: none + */ +void target_if_pmo_set_wow_enable_ack_failed(struct wlan_objmgr_psoc *psoc); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_arp.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_arp.c new file mode 100644 index 0000000000..c8e4aefe4c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_arp.c @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_arp.c + * + * Target interface file for pmo component to + * send arp offload related cmd and process event. + */ + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS target_if_pmo_send_arp_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_enable_arp_ns_offload_cmd(wmi_handle, + arp_offload_req, + ns_offload_req, + vdev_id); + if (status != QDF_STATUS_SUCCESS) + target_if_err("Failed to enable ARP NDP/NSffload"); + + return status; +} + + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_gtk.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_gtk.c new file mode 100644 index 0000000000..6c9af05939 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_gtk.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_gtk.c + * + * Target interface file for pmo component to + * send gtk offload related cmd and process event. + */ + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS target_if_pmo_send_gtk_offload_req(struct wlan_objmgr_vdev *vdev, + struct pmo_gtk_req *gtk_req) +{ + uint8_t vdev_id; + QDF_STATUS status; + uint32_t gtk_offload_opcode; + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (gtk_req->flags == PMO_GTK_OFFLOAD_ENABLE) + gtk_offload_opcode = GTK_OFFLOAD_ENABLE_OPCODE; + else + gtk_offload_opcode = GTK_OFFLOAD_DISABLE_OPCODE; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_gtk_offload_cmd(wmi_handle, + vdev_id, + gtk_req, + gtk_req->flags, + gtk_offload_opcode); + if (status) + target_if_err("Failed to send gtk offload cmd to fw"); + + return status; +} + +QDF_STATUS target_if_pmo_send_gtk_response_req(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t offload_req_opcode; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* Request for GTK offload status */ + offload_req_opcode = GTK_OFFLOAD_REQUEST_STATUS_OPCODE; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + /* send the wmi command */ + status = wmi_unified_process_gtk_offload_getinfo_cmd(wmi_handle, + vdev_id, offload_req_opcode); + + return status; +} + +int target_if_pmo_gtk_offload_status_event(void *scn_handle, + uint8_t *event, uint32_t len) +{ + struct pmo_gtk_rsp_params *gtk_rsp_param; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS ret; + wmi_unified_t wmi_handle; + + TARGET_IF_ENTER(); + psoc = target_if_get_psoc_from_scn_hdl(scn_handle); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + ret = -EINVAL; + goto out; + } + + gtk_rsp_param = qdf_mem_malloc(sizeof(*gtk_rsp_param)); + if (!gtk_rsp_param) { + ret = -ENOMEM; + goto out; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + qdf_mem_free(gtk_rsp_param); + ret = -EINVAL; + goto out; + } + + if (wmi_extract_gtk_rsp_event(wmi_handle, event, gtk_rsp_param, len) != + QDF_STATUS_SUCCESS) { + target_if_err("Extraction of gtk rsp event failed"); + qdf_mem_free(gtk_rsp_param); + ret = -EINVAL; + goto out; + } + + ret = pmo_tgt_gtk_rsp_evt(psoc, (void *)gtk_rsp_param); + if (ret != QDF_STATUS_SUCCESS) { + target_if_err("Failed to rx_gtk_rsp_event"); + ret = -EINVAL; + } + qdf_mem_free(gtk_rsp_param); +out: + TARGET_IF_EXIT(); + + return ret; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_hw_filter.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_hw_filter.c new file mode 100644 index 0000000000..d378f1cdc4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_hw_filter.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_non_arp_bcast_fltr.c + * + * Target interface file for pmo component to + * send non arp hw bcast filtering related cmd and process event. + */ + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" +#include "wlan_pmo_hw_filter_public_struct.h" + +QDF_STATUS target_if_pmo_conf_hw_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_hw_filter_params *req) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!psoc) { + target_if_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_conf_hw_filter_cmd(wmi_handle, req); + + if (QDF_IS_STATUS_ERROR(status)) + target_if_err("Failed to configure HW Filter"); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_icmp.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_icmp.c new file mode 100644 index 0000000000..b0aadcc9bc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_icmp.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_pmo_icmp.c + * + * Target interface file for pmo component to + * send icmp offload related cmd and process event. + */ + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS +target_if_pmo_send_icmp_offload_req(struct wlan_objmgr_psoc *psoc, + struct pmo_icmp_offload *pmo_icmp_req) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_config_icmp_offload_cmd(wmi_handle, pmo_icmp_req); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_lphb.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_lphb.c new file mode 100644 index 0000000000..b1eb15049c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_lphb.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_lphb.c + * + * Target interface file for pmo component to + * send lphb offload related cmd and process event. + */ +#ifdef FEATURE_WLAN_LPHB + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_pmo_api.h" + +QDF_STATUS target_if_pmo_send_lphb_enable(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_enable_req *ts_lphb_enable) +{ + wmi_hb_set_enable_cmd_fixed_param hb_enable_fp; + wmi_unified_t wmi_handle; + + if (!ts_lphb_enable) { + target_if_err("LPHB Enable configuration is NULL"); + return QDF_STATUS_E_FAILURE; + } + + target_if_info("PMO_HB_SET_ENABLE enable=%d, item=%d, session=%d", + ts_lphb_enable->enable, + ts_lphb_enable->item, ts_lphb_enable->session); + + if ((ts_lphb_enable->item != 1) && (ts_lphb_enable->item != 2)) { + target_if_err("LPHB configuration wrong item %d", + ts_lphb_enable->item); + return QDF_STATUS_E_FAILURE; + } + + /* fill in values */ + hb_enable_fp.vdev_id = ts_lphb_enable->session; + hb_enable_fp.enable = ts_lphb_enable->enable; + hb_enable_fp.item = ts_lphb_enable->item; + hb_enable_fp.session = ts_lphb_enable->session; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_lphb_config_hbenable_cmd(wmi_handle, &hb_enable_fp); +} + +QDF_STATUS target_if_pmo_send_lphb_tcp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_params *ts_lphb_tcp_param) +{ + wmi_hb_set_tcp_params_cmd_fixed_param hb_tcp_params_fp = {0}; + wmi_unified_t wmi_handle; + + if (!ts_lphb_tcp_param) { + target_if_err("TCP params LPHB configuration is NULL"); + return QDF_STATUS_E_FAILURE; + } + + target_if_info("PMO --> WMI_HB_SET_TCP_PARAMS srv_ip=%08x, " + "dev_ip=%08x, src_port=%d, dst_port=%d, timeout=%d, " + "session=%d, gateway_mac= "QDF_MAC_ADDR_FMT", time_period_sec=%d," + "tcp_sn=%d", ts_lphb_tcp_param->srv_ip, + ts_lphb_tcp_param->dev_ip, ts_lphb_tcp_param->src_port, + ts_lphb_tcp_param->dst_port, ts_lphb_tcp_param->timeout, + ts_lphb_tcp_param->session, + QDF_MAC_ADDR_REF(ts_lphb_tcp_param->gateway_mac.bytes), + ts_lphb_tcp_param->time_period_sec, ts_lphb_tcp_param->tcp_sn); + + /* fill in values */ + hb_tcp_params_fp.vdev_id = ts_lphb_tcp_param->session; + hb_tcp_params_fp.srv_ip = ts_lphb_tcp_param->srv_ip; + hb_tcp_params_fp.dev_ip = ts_lphb_tcp_param->dev_ip; + hb_tcp_params_fp.seq = ts_lphb_tcp_param->tcp_sn; + hb_tcp_params_fp.src_port = ts_lphb_tcp_param->src_port; + hb_tcp_params_fp.dst_port = ts_lphb_tcp_param->dst_port; + hb_tcp_params_fp.interval = ts_lphb_tcp_param->time_period_sec; + hb_tcp_params_fp.timeout = ts_lphb_tcp_param->timeout; + hb_tcp_params_fp.session = ts_lphb_tcp_param->session; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_tcp_param->gateway_mac.bytes, + &hb_tcp_params_fp.gateway_mac); + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_lphb_config_tcp_params_cmd(wmi_handle, + &hb_tcp_params_fp); +} + +QDF_STATUS target_if_pmo_send_lphb_tcp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_tcp_filter_req *ts_lphb_tcp_filter) +{ + wmi_hb_set_tcp_pkt_filter_cmd_fixed_param hb_tcp_filter_fp = {0}; + wmi_unified_t wmi_handle; + + if (!ts_lphb_tcp_filter) { + target_if_err("TCP PKT FILTER LPHB configuration is NULL"); + return QDF_STATUS_E_FAILURE; + } + + target_if_info("SET_TCP_PKT_FILTER length=%d, offset=%d, session=%d, " + "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", + ts_lphb_tcp_filter->length, ts_lphb_tcp_filter->offset, + ts_lphb_tcp_filter->session, ts_lphb_tcp_filter->filter[0], + ts_lphb_tcp_filter->filter[1], ts_lphb_tcp_filter->filter[2], + ts_lphb_tcp_filter->filter[3], ts_lphb_tcp_filter->filter[4], + ts_lphb_tcp_filter->filter[5]); + + /* fill in values */ + hb_tcp_filter_fp.vdev_id = ts_lphb_tcp_filter->session; + hb_tcp_filter_fp.length = ts_lphb_tcp_filter->length; + hb_tcp_filter_fp.offset = ts_lphb_tcp_filter->offset; + hb_tcp_filter_fp.session = ts_lphb_tcp_filter->session; + memcpy((void *)&hb_tcp_filter_fp.filter, + (void *)&ts_lphb_tcp_filter->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_lphb_config_tcp_pkt_filter_cmd(wmi_handle, + &hb_tcp_filter_fp); +} + +QDF_STATUS target_if_pmo_send_lphb_udp_params(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_params *ts_lphb_udp_param) +{ + wmi_hb_set_udp_params_cmd_fixed_param hb_udp_params_fp = {0}; + wmi_unified_t wmi_handle; + + if (!ts_lphb_udp_param) { + target_if_err("UDP param for LPHB configuration is NULL"); + return QDF_STATUS_E_FAILURE; + } + + target_if_info("HB_SET_UDP_PARAMS srv_ip=%d, dev_ip=%d, src_port=%d, " + "dst_port=%d, interval=%d, timeout=%d, session=%d, " + "gateway_mac= "QDF_MAC_ADDR_FMT, + ts_lphb_udp_param->srv_ip, ts_lphb_udp_param->dev_ip, + ts_lphb_udp_param->src_port, ts_lphb_udp_param->dst_port, + ts_lphb_udp_param->interval, ts_lphb_udp_param->timeout, + ts_lphb_udp_param->session, + QDF_MAC_ADDR_REF(ts_lphb_udp_param->gateway_mac.bytes)); + + /* fill in values */ + hb_udp_params_fp.vdev_id = ts_lphb_udp_param->session; + hb_udp_params_fp.srv_ip = ts_lphb_udp_param->srv_ip; + hb_udp_params_fp.dev_ip = ts_lphb_udp_param->dev_ip; + hb_udp_params_fp.src_port = ts_lphb_udp_param->src_port; + hb_udp_params_fp.dst_port = ts_lphb_udp_param->dst_port; + hb_udp_params_fp.interval = ts_lphb_udp_param->interval; + hb_udp_params_fp.timeout = ts_lphb_udp_param->timeout; + hb_udp_params_fp.session = ts_lphb_udp_param->session; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ts_lphb_udp_param->gateway_mac.bytes, + &hb_udp_params_fp.gateway_mac); + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_lphb_config_udp_params_cmd(wmi_handle, + &hb_udp_params_fp); +} + +/** + * target_if_pmo_send_lphb_udp_pkt_filter() - Send LPHB udp pkt filter req + * @psoc: objmgr psoc handle + * @ts_lphb_udp_filter: lphb udp filter request which needs to configure in fwr + * + * Return: QDF status + */ +QDF_STATUS target_if_pmo_send_lphb_udp_pkt_filter(struct wlan_objmgr_psoc *psoc, + struct pmo_lphb_udp_filter_req *ts_lphb_udp_filter) +{ + wmi_hb_set_udp_pkt_filter_cmd_fixed_param hb_udp_filter_fp = {0}; + wmi_unified_t wmi_handle; + + if (!ts_lphb_udp_filter) { + target_if_err("LPHB UDP packet filter configuration is NULL"); + return QDF_STATUS_E_FAILURE; + } + + target_if_info("SET_UDP_PKT_FILTER length=%d, offset=%d, session=%d, " + "filter=%2x:%2x:%2x:%2x:%2x:%2x ...", + ts_lphb_udp_filter->length, ts_lphb_udp_filter->offset, + ts_lphb_udp_filter->session, ts_lphb_udp_filter->filter[0], + ts_lphb_udp_filter->filter[1], ts_lphb_udp_filter->filter[2], + ts_lphb_udp_filter->filter[3], ts_lphb_udp_filter->filter[4], + ts_lphb_udp_filter->filter[5]); + + /* fill in values */ + hb_udp_filter_fp.vdev_id = ts_lphb_udp_filter->session; + hb_udp_filter_fp.length = ts_lphb_udp_filter->length; + hb_udp_filter_fp.offset = ts_lphb_udp_filter->offset; + hb_udp_filter_fp.session = ts_lphb_udp_filter->session; + qdf_mem_copy(&hb_udp_filter_fp.filter, &ts_lphb_udp_filter->filter, + WMI_WLAN_HB_MAX_FILTER_SIZE); + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_lphb_config_udp_pkt_filter_cmd(wmi_handle, + &hb_udp_filter_fp); +} + +QDF_STATUS target_if_pmo_lphb_evt_handler(struct wlan_objmgr_psoc *psoc, + uint8_t *event) +{ + wmi_hb_ind_event_fixed_param *hb_fp; + struct pmo_lphb_rsp *slphb_indication = NULL; + QDF_STATUS qdf_status; + + TARGET_IF_ENTER(); + if (!psoc) { + target_if_err("psoc ptr is NULL"); + qdf_status = QDF_STATUS_E_NULL_VALUE; + goto out; + } + + hb_fp = (wmi_hb_ind_event_fixed_param *) event; + if (!hb_fp) { + target_if_err("Invalid wmi_hb_ind_event_fixed_param buffer"); + qdf_status = QDF_STATUS_E_INVAL; + goto out; + } + + target_if_debug("lphb indication received with\n" + "vdev_id=%d, session=%d, reason=%d", + hb_fp->vdev_id, hb_fp->session, hb_fp->reason); + + slphb_indication = (struct pmo_lphb_rsp *)qdf_mem_malloc( + sizeof(struct pmo_lphb_rsp)); + if (!slphb_indication) { + qdf_status = QDF_STATUS_E_NOMEM; + goto out; + } + + slphb_indication->session_idx = hb_fp->session; + slphb_indication->protocol_type = hb_fp->reason; + slphb_indication->event_reason = hb_fp->reason; + + qdf_status = pmo_tgt_lphb_rsp_evt(psoc, slphb_indication); + if (qdf_status != QDF_STATUS_SUCCESS) + target_if_err("Failed to lphb_rsp_event"); +out: + if (slphb_indication) + qdf_mem_free(slphb_indication); + + return qdf_status; +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_main.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_main.c new file mode 100644 index 0000000000..fb7138646f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_main.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Target interface file for pmo component to + * Implement api's which shall be used by pmo component + * in target if internally. + */ + +#include "target_if_pmo.h" +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_icmp.h" + +#ifdef WLAN_FEATURE_PACKET_FILTERING +static inline +void tgt_if_pmo_reg_pkt_filter_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{ + pmo_tx_ops->send_set_pkt_filter = + target_if_pmo_send_pkt_filter_req; + pmo_tx_ops->send_clear_pkt_filter = + target_if_pmo_clear_pkt_filter_req; +} +#else +static inline void +tgt_if_pmo_reg_pkt_filter_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{ +} +#endif +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +static void +update_pmo_igmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{ + pmo_tx_ops->send_igmp_offload_req = + target_if_pmo_send_igmp_offload_req; +} +#else +static inline void +update_pmo_igmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{} +#endif +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +static void tgt_if_pmo_icmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{ + pmo_tx_ops->send_icmp_offload_req = + target_if_pmo_send_icmp_offload_req; +} +#else +static inline void +tgt_if_pmo_icmp_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{} +#endif +void target_if_pmo_register_tx_ops(struct wlan_pmo_tx_ops *pmo_tx_ops) +{ + if (!pmo_tx_ops) { + target_if_err("pmo_tx_ops is null"); + return; + } + + pmo_tx_ops->send_arp_offload_req = + target_if_pmo_send_arp_offload_req; + pmo_tx_ops->send_conf_hw_filter_req = + target_if_pmo_conf_hw_filter; + pmo_tx_ops->send_ns_offload_req = + target_if_pmo_send_ns_offload_req; + pmo_tx_ops->send_enable_wow_wakeup_event_req = + target_if_pmo_enable_wow_wakeup_event; + pmo_tx_ops->send_disable_wow_wakeup_event_req = + target_if_pmo_disable_wow_wakeup_event; + pmo_tx_ops->send_add_wow_pattern = + target_if_pmo_send_wow_patterns_to_fw; + pmo_tx_ops->del_wow_pattern = + target_if_pmo_del_wow_patterns_to_fw; + pmo_tx_ops->send_enhance_mc_offload_req = + target_if_pmo_send_enhance_mc_offload_req; + pmo_tx_ops->send_set_mc_filter_req = + target_if_pmo_set_mc_filter_req; + pmo_tx_ops->send_clear_mc_filter_req = + target_if_pmo_clear_mc_filter_req; + pmo_tx_ops->get_multiple_mc_filter_support = + target_if_pmo_get_multiple_mc_filter_support; + pmo_tx_ops->send_set_multiple_mc_filter_req = + target_if_pmo_set_multiple_mc_filter_req; + pmo_tx_ops->send_clear_multiple_mc_filter_req = + target_if_pmo_clear_multiple_mc_filter_req; + pmo_tx_ops->send_ra_filter_req = + target_if_pmo_send_ra_filter_req; + pmo_tx_ops->send_gtk_offload_req = + target_if_pmo_send_gtk_offload_req; + pmo_tx_ops->send_get_gtk_rsp_cmd = + target_if_pmo_send_gtk_response_req; + pmo_tx_ops->send_action_frame_pattern_req = + target_if_pmo_send_action_frame_patterns; + pmo_tx_ops->send_lphb_enable = + target_if_pmo_send_lphb_enable; + pmo_tx_ops->send_lphb_tcp_params = + target_if_pmo_send_lphb_tcp_params; + pmo_tx_ops->send_lphb_tcp_filter_req = + target_if_pmo_send_lphb_tcp_pkt_filter; + pmo_tx_ops->send_lphb_upd_params = + target_if_pmo_send_lphb_udp_params; + pmo_tx_ops->send_lphb_udp_filter_req = + target_if_pmo_send_lphb_udp_pkt_filter; + pmo_tx_ops->send_vdev_param_update_req = + target_if_pmo_send_vdev_update_param_req; + pmo_tx_ops->send_vdev_sta_ps_param_req = + target_if_pmo_send_vdev_ps_param_req; + pmo_tx_ops->psoc_update_wow_bus_suspend = + target_if_pmo_psoc_update_bus_suspend; + pmo_tx_ops->psoc_get_host_credits = + target_if_pmo_psoc_get_host_credits; + update_pmo_igmp_tx_ops(pmo_tx_ops); + pmo_tx_ops->psoc_get_pending_cmnds = + target_if_pmo_psoc_get_pending_cmnds; + pmo_tx_ops->update_target_suspend_flag = + target_if_pmo_update_target_suspend_flag; + pmo_tx_ops->update_target_suspend_acked_flag = + target_if_pmo_update_target_suspend_acked_flag; + pmo_tx_ops->is_target_suspended = + target_if_pmo_is_target_suspended; + pmo_tx_ops->psoc_send_wow_enable_req = + target_if_pmo_psoc_send_wow_enable_req; + pmo_tx_ops->psoc_send_supend_req = + target_if_pmo_psoc_send_suspend_req; + pmo_tx_ops->psoc_set_runtime_pm_in_progress = + target_if_pmo_set_runtime_pm_in_progress; + pmo_tx_ops->psoc_get_runtime_pm_in_progress = + target_if_pmo_get_runtime_pm_in_progress; + pmo_tx_ops->psoc_send_host_wakeup_ind = + target_if_pmo_psoc_send_host_wakeup_ind; + pmo_tx_ops->psoc_send_target_resume_req = + target_if_pmo_psoc_send_target_resume_req; + pmo_tx_ops->psoc_send_d0wow_enable_req = + target_if_pmo_psoc_send_d0wow_enable_req; + pmo_tx_ops->psoc_send_d0wow_disable_req = + target_if_pmo_psoc_send_d0wow_disable_req; + pmo_tx_ops->psoc_send_idle_roam_suspend_mode = + target_if_pmo_psoc_send_idle_monitor_cmd; + tgt_if_pmo_reg_pkt_filter_ops(pmo_tx_ops); + tgt_if_pmo_icmp_tx_ops(pmo_tx_ops); + pmo_tx_ops->psoc_set_wow_enable_ack_failed = + target_if_pmo_set_wow_enable_ack_failed; + +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c new file mode 100644 index 0000000000..427ec62eb7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2017-2018, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_mc_addr_filtering.c + * + * Target interface file for pmo component to + * send mc address filtering offload related cmd and process event. + */ + + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS target_if_pmo_set_mc_filter_req( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_add_clear_mcbc_filter_cmd(wmi_handle, vdev_id, + multicast_addr, false); + if (status) + target_if_err("Failed to send add/clear mcbc filter cmd"); + + return status; +} + +QDF_STATUS target_if_pmo_clear_mc_filter_req( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr multicast_addr) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_add_clear_mcbc_filter_cmd(wmi_handle, vdev_id, + multicast_addr, true); + if (status) + target_if_err("Failed to send add/clear mcbc filter cmd"); + + return status; + +} + +bool target_if_pmo_get_multiple_mc_filter_support( + struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return false; + } + + return wmi_service_enabled(wmi_handle, + wmi_service_multiple_mcast_filter_set); +} + +QDF_STATUS target_if_pmo_set_multiple_mc_filter_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct pmo_mcast_filter_params *filter_params; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + filter_params = qdf_mem_malloc(sizeof(*filter_params)); + if (!filter_params) { + target_if_err("memory alloc failed for filter_params"); + return QDF_STATUS_E_NOMEM; + } + + filter_params->multicast_addr_cnt = mc_list->mc_cnt; + qdf_mem_copy(filter_params->multicast_addr, + mc_list->mc_addr, + mc_list->mc_cnt * ATH_MAC_LEN); + /* add one/multiple mc list */ + filter_params->action = 1; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + qdf_mem_free(filter_params); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_multiple_add_clear_mcbc_filter_cmd(wmi_handle, + vdev_id, + filter_params); + if (status) + target_if_err("Failed to send add/clear mcbc filter cmd"); + + qdf_mem_free(filter_params); + + return status; +} + +QDF_STATUS target_if_pmo_clear_multiple_mc_filter_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_mc_addr_list *mc_list) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct pmo_mcast_filter_params *filter_params; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + filter_params = qdf_mem_malloc(sizeof(*filter_params)); + if (!filter_params) { + target_if_err("memory alloc failed for filter_params"); + return QDF_STATUS_E_NOMEM; + } + + filter_params->multicast_addr_cnt = mc_list->mc_cnt; + qdf_mem_copy(filter_params->multicast_addr, + mc_list->mc_addr, + mc_list->mc_cnt * ATH_MAC_LEN); + /* delete one/multiple mc list */ + filter_params->action = 0; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + qdf_mem_free(filter_params); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_multiple_add_clear_mcbc_filter_cmd(wmi_handle, + vdev_id, + filter_params); + if (status) + target_if_err("Failed to send add/clear mcbc filter cmd"); + + qdf_mem_free(filter_params); + + return status; +} + + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_ns.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_ns.c new file mode 100644 index 0000000000..0f23bb1905 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_ns.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_ns.c + * + * Target interface file for pmo component to + * send ns offload related cmd and process event. + */ + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS target_if_pmo_send_ns_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_arp_offload_params *arp_offload_req, + struct pmo_ns_offload_params *ns_offload_req) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_enable_arp_ns_offload_cmd(wmi_handle, + arp_offload_req, + ns_offload_req, + vdev_id); + if (status != QDF_STATUS_SUCCESS) + target_if_err("Failed to enable ARP NDP/NSffload"); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_pkt_filter.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_pkt_filter.c new file mode 100644 index 0000000000..85725b936d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_pkt_filter.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_pkt_filter.c + * + * Target interface file for pmo component to + * send packet filter related cmd and process event. + */ + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_pmo_api.h" +#include "wlan_pmo_pkt_filter_public_struct.h" + +QDF_STATUS target_if_pmo_send_pkt_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_cfg *rcv_filter_param) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + /* send the command along with data */ + status = wmi_unified_config_packet_filter_cmd(wmi_handle, vdev_id, + rcv_filter_param, + rcv_filter_param->filter_id, true); + if (status) { + target_if_err("Failed to send pkt_filter cmd"); + return QDF_STATUS_E_INVAL; + } + + /* Enable packet filter */ + status = wmi_unified_enable_disable_packet_filter_cmd(wmi_handle, + vdev_id, true); + if (status) + target_if_err("Failed to send packet filter wmi cmd to fw"); + + return status; +} + +QDF_STATUS target_if_pmo_clear_pkt_filter_req(struct wlan_objmgr_vdev *vdev, + struct pmo_rcv_pkt_fltr_clear_param *rcv_clear_param) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + /* send the command along with data */ + status = wmi_unified_config_packet_filter_cmd(wmi_handle, vdev_id, NULL, + rcv_clear_param->filter_id, false); + + if (status) + target_if_err("Failed to clear filter cmd"); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_static_config.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_static_config.c new file mode 100644 index 0000000000..79d11386ab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_static_config.c @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_static.c + * + * Target interface file for pmo component to + * send wow related cmd and process event. + */ + + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS target_if_pmo_send_ra_filter_req(struct wlan_objmgr_vdev *vdev, + uint8_t default_pattern, uint16_t rate_limit_interval) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_wow_sta_ra_filter_cmd(wmi_handle, + vdev_id, + default_pattern, + rate_limit_interval); + if (status) + target_if_err("Failed to send RA rate limit to fw"); + + return status; +} + +QDF_STATUS target_if_pmo_send_action_frame_patterns( + struct wlan_objmgr_vdev *vdev, + struct pmo_action_wakeup_set_params *ip_cmd) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_action_frame_patterns_cmd(wmi_handle, ip_cmd); + if (status != QDF_STATUS_SUCCESS) + target_if_err("Failed to config wow action frame map, ret %d", + status); + + return status; +} + +QDF_STATUS target_if_pmo_send_enhance_mc_offload_req( + struct wlan_objmgr_vdev *vdev, bool enable) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_enable_enhance_multicast_offload_cmd(wmi_handle, + vdev_id, + enable); + if (status) + target_if_err("Failed to config wow wakeup event"); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_suspend_resume.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_suspend_resume.c new file mode 100644 index 0000000000..a28a668eec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_suspend_resume.c @@ -0,0 +1,460 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_static.c + * + * Target interface file for pmo component to + * send suspend / resume related cmd and process event. + */ + +#include "wma.h" +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" +#include "qdf_types.h" +#include "pld_common.h" +#include +#include + +#define TGT_WILDCARD_PDEV_ID 0x0 + +QDF_STATUS target_if_pmo_send_vdev_update_param_req( + struct wlan_objmgr_vdev *vdev, + uint32_t param_id, uint32_t param_value) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct vdev_set_params param = {0}; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* Any new param_id added here please also add it to + * wmi_tag_vdev_set_cmd to be tagged for runtime PM feature + * so that it will not invoke runtime PM "get" which will + * result resume right after suspend (WOW_ENABLE). + */ + + switch (param_id) { + case pmo_vdev_param_listen_interval: + param_id = wmi_vdev_param_listen_interval; + break; + case pmo_vdev_param_dtim_policy: + param_id = wmi_vdev_param_dtim_policy; + break; + case pmo_vdev_param_forced_dtim_count: + param_id = wmi_vdev_param_force_dtim_cnt; + break; + case pmo_vdev_param_moddtim: + param_id = wmi_vdev_param_moddtim_cnt; + break; + default: + target_if_err("invalid vdev param id %d", param_id); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + param.vdev_id = vdev_id; + param.param_id = param_id; + param.param_value = param_value; + target_if_debug("set vdev param vdev_id: %d value: %d for param_id: %d", + vdev_id, param_value, param_id); + return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +QDF_STATUS target_if_pmo_send_igmp_offload_req( + struct wlan_objmgr_vdev *vdev, + struct pmo_igmp_offload_req *pmo_igmp_req) +{ + struct wlan_objmgr_psoc *psoc; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_send_igmp_offload_cmd(wmi_handle, + pmo_igmp_req); +} +#endif + +QDF_STATUS target_if_pmo_send_vdev_ps_param_req( + struct wlan_objmgr_vdev *vdev, + uint32_t param_id, + uint32_t param_value) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + struct sta_ps_params sta_ps_param = {0}; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* + * Any new param_id added here must be added to + * wmi_tag_sta_powersave_cmd() to be tagged for runtime PM feature + * so that it will not invoke runtime PM "get" which will + * result resume right after suspend (WOW_ENABLE). + */ + switch (param_id) { + case pmo_sta_ps_enable_advanced_power: + param_id = WMI_STA_PS_ENABLE_OPM; + break; + case pmo_sta_ps_param_inactivity_time: + param_id = WMI_STA_PS_PARAM_INACTIVITY_TIME; + break; + case pmo_sta_ps_param_ito_repeat_count: + param_id = WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX; + break; + case pmo_sta_ps_param_spec_wake_interval: + param_id = WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL; + break; + default: + target_if_err("invalid vdev param id %d", param_id); + return QDF_STATUS_E_INVAL; + } + + sta_ps_param.vdev_id = vdev_id; + sta_ps_param.param_id = param_id; + sta_ps_param.value = param_value; + target_if_debug("set vdev param vdev_id: %d value: %d for param_id: %d", + vdev_id, param_value, param_id); + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_sta_ps_cmd_send(wmi_handle, &sta_ps_param); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return status; +} + +void target_if_pmo_psoc_update_bus_suspend(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return; + } + + wmi_set_is_wow_bus_suspended(wmi_handle, value); +} + +int target_if_pmo_psoc_get_host_credits(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return 0; + } + + return wmi_get_host_credits(wmi_handle); +} + +int target_if_pmo_psoc_get_pending_cmnds(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return 0; + } + + return wmi_get_pending_cmds(wmi_handle); +} + +void target_if_pmo_update_target_suspend_flag(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return; + } + + wmi_set_target_suspend(wmi_handle, value); +} + +void target_if_pmo_update_target_suspend_acked_flag( + struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return; + } + + wmi_set_target_suspend_acked(wmi_handle, value); +} + +bool target_if_pmo_is_target_suspended(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return false; + } + + return wmi_is_target_suspended(wmi_handle); +} + +QDF_STATUS target_if_pmo_psoc_send_wow_enable_req( + struct wlan_objmgr_psoc *psoc, + struct pmo_wow_cmd_params *param) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + wma_check_and_set_wake_timer(INSTALL_KEY_TIMEOUT_MS); + return wmi_unified_wow_enable_send(wmi_handle, + (struct wow_cmd_params *)param, + TGT_WILDCARD_PDEV_ID); +} + +QDF_STATUS target_if_pmo_psoc_send_suspend_req( + struct wlan_objmgr_psoc *psoc, + struct pmo_suspend_params *param) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_suspend_send(wmi_handle, + (struct suspend_params *) param, + TGT_WILDCARD_PDEV_ID); +} + +void target_if_pmo_set_runtime_pm_in_progress(struct wlan_objmgr_psoc *psoc, + bool value) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return; + } + + return wmi_set_runtime_pm_inprogress(wmi_handle, value); +} + +bool target_if_pmo_get_runtime_pm_in_progress( + struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return false; + } + + return wmi_get_runtime_pm_inprogress(wmi_handle); +} + +#ifdef HOST_WAKEUP_OVER_QMI +QDF_STATUS target_if_pmo_psoc_send_host_wakeup_ind( + struct wlan_objmgr_psoc *psoc) +{ + qdf_device_t qdf_dev; + int ret; + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + if (!qdf_dev) + return QDF_STATUS_E_INVAL; + + ret = pld_exit_power_save(qdf_dev->dev); + if (ret) { + target_if_err("Failed to exit power save, ret: %d", ret); + return qdf_status_from_os_return(ret); + } + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS target_if_pmo_psoc_send_host_wakeup_ind( + struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + bool tx_pending_ind = false; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + if (cdp_get_tx_inqueue(cds_get_context(QDF_MODULE_ID_SOC))) + tx_pending_ind = true; + + return wmi_unified_host_wakeup_ind_to_fw_cmd(wmi_handle, + tx_pending_ind); +} +#endif + +QDF_STATUS target_if_pmo_psoc_send_target_resume_req( + struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_resume_send(wmi_handle, TGT_WILDCARD_PDEV_ID); +} + +QDF_STATUS +target_if_pmo_psoc_send_idle_monitor_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_send_idle_trigger_monitor(wmi_handle, val); +} + +#ifdef FEATURE_WLAN_D0WOW +QDF_STATUS target_if_pmo_psoc_send_d0wow_enable_req( + struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_d0wow_enable_send(wmi_handle, TGT_WILDCARD_PDEV_ID); +} + +QDF_STATUS target_if_pmo_psoc_send_d0wow_disable_req( + struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_d0wow_disable_send(wmi_handle, TGT_WILDCARD_PDEV_ID); +} +#else +QDF_STATUS target_if_pmo_psoc_send_d0wow_enable_req( + struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS target_if_pmo_psoc_send_d0wow_disable_req( + struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_E_INVAL; +} +#endif + +void target_if_pmo_set_wow_enable_ack_failed(struct wlan_objmgr_psoc *psoc) +{ + wmi_unified_t wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return; + } + + return wmi_set_wow_enable_ack_failed(wmi_handle); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_wow.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_wow.c new file mode 100644 index 0000000000..6c2481eeb8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/pmo/src/target_if_pmo_wow.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: target_if_pmo_wow.c + * + * Target interface file for pmo component to + * send wow related cmd and process event. + */ + + +#include "target_if.h" +#include "target_if_pmo.h" +#include "wmi_unified_api.h" + +QDF_STATUS target_if_pmo_enable_wow_wakeup_event(struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_add_wow_wakeup_event_cmd(wmi_handle, vdev_id, + bitmap, true); + if (status) + target_if_err("Failed to config wow wakeup event"); + + return status; +} + +QDF_STATUS target_if_pmo_disable_wow_wakeup_event(struct wlan_objmgr_vdev *vdev, + uint32_t *bitmap) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_add_wow_wakeup_event_cmd(wmi_handle, vdev_id, + bitmap, false); + if (status) + target_if_err("Failed to config wow wakeup event"); + + return status; +} + +QDF_STATUS target_if_pmo_send_wow_patterns_to_fw(struct wlan_objmgr_vdev *vdev, + uint8_t ptrn_id, + const uint8_t *ptrn, uint8_t ptrn_len, + uint8_t ptrn_offset, const uint8_t *mask, + uint8_t mask_len, bool user) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_wow_patterns_to_fw_cmd(wmi_handle, + vdev_id, ptrn_id, ptrn, + ptrn_len, ptrn_offset, + mask, mask_len, user, 0); + + return status; +} + +QDF_STATUS target_if_pmo_del_wow_patterns_to_fw(struct wlan_objmgr_vdev *vdev, + uint8_t ptrn_id) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!vdev) { + target_if_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + target_if_err("psoc handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid wmi handle"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_wow_delete_pattern_cmd(wmi_handle, ptrn_id, + vdev_id); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/sap/ll_sap/inc/target_if_ll_sap.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/sap/ll_sap/inc/target_if_ll_sap.h new file mode 100644 index 0000000000..b550769aa9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/sap/ll_sap/inc/target_if_ll_sap.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_lt_sap declarations specific to the bearer + * switch functionalities + */ +#include "wlan_ll_sap_public_structs.h" + +/** + * target_if_ll_sap_register_tx_ops() - register ll_lt_sap tx ops + * @tx_ops: pointer to ll_sap tx ops + * + * Return: None + */ +void target_if_ll_sap_register_tx_ops(struct wlan_ll_sap_tx_ops *tx_ops); + +/** + * target_if_ll_sap_register_rx_ops() - register ll_lt_sap rx ops + * @rx_ops: pointer to ll_sap rx ops + * + * Return: None + */ +void target_if_ll_sap_register_rx_ops(struct wlan_ll_sap_rx_ops *rx_ops); + +/** + * target_if_ll_sap_register_events() - register ll_lt_sap fw event handlers + * @psoc: pointer to psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS target_if_ll_sap_register_events(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_ll_sap_deregister_events() - deregister ll_lt_sap fw event handlers + * @psoc: pointer to psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_ll_sap_deregister_events(struct wlan_objmgr_psoc *psoc); + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/sap/ll_sap/src/target_if_ll_sap.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/sap/ll_sap/src/target_if_ll_sap.c new file mode 100644 index 0000000000..13a0398e97 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/sap/ll_sap/src/target_if_ll_sap.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "target_if.h" +#include "target_if_ll_sap.h" +#include "wlan_ll_sap_public_structs.h" +#include "wmi_unified_ll_sap_api.h" +#include "../../umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h" +#include "wlan_ll_sap_api.h" + +/** + * target_if_send_audio_transport_switch_resp() - Send audio transport switch + * response to fw + * @psoc: pointer to psoc + * @req_type: Bearer switch request type + * @status: Status of the bearer switch request + * + * Return: pointer to tx ops + */ +static QDF_STATUS target_if_send_audio_transport_switch_resp( + struct wlan_objmgr_psoc *psoc, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null."); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_audio_transport_switch_resp_send(wmi_handle, + req_type, status); +} + +static int target_if_send_audio_transport_switch_req_event_handler( + ol_scn_t scn, + uint8_t *event, + uint32_t len) +{ + struct wlan_objmgr_psoc *psoc; + struct ll_sap_psoc_priv_obj *psoc_ll_sap_obj; + enum bearer_switch_req_type req_type; + struct wmi_unified *wmi_handle; + struct wlan_ll_sap_rx_ops *rx_ops; + QDF_STATUS qdf_status; + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + psoc_ll_sap_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, + WLAN_UMAC_COMP_LL_SAP); + + if (!psoc_ll_sap_obj) { + target_if_err("psoc_ll_sap_obj is null"); + return -EINVAL; + } + + rx_ops = &psoc_ll_sap_obj->rx_ops; + if (!rx_ops || !rx_ops->audio_transport_switch_req) { + target_if_err("Invalid ll_sap rx ops"); + return -EINVAL; + } + + qdf_status = wmi_extract_audio_transport_switch_req_event(wmi_handle, + event, len, + &req_type); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("parsing of event failed, %d", qdf_status); + return -EINVAL; + } + rx_ops->audio_transport_switch_req(psoc, req_type); + + return 0; +} + +void +target_if_ll_sap_register_tx_ops(struct wlan_ll_sap_tx_ops *tx_ops) +{ + tx_ops->send_audio_transport_switch_resp = + target_if_send_audio_transport_switch_resp; +} + +void +target_if_ll_sap_register_rx_ops(struct wlan_ll_sap_rx_ops *rx_ops) +{ + rx_ops->audio_transport_switch_req = + wlan_ll_sap_fw_bearer_switch_req; +} + +QDF_STATUS +target_if_ll_sap_register_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_register_event_handler( + handle, + wmi_audio_transport_switch_type_event_id, + target_if_send_audio_transport_switch_req_event_handler, + WMI_RX_SERIALIZER_CTX); + return ret; +} + +QDF_STATUS +target_if_ll_sap_deregister_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS ret; + wmi_unified_t handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!handle) { + target_if_err("handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_unified_unregister_event_handler( + handle, + wmi_audio_transport_switch_type_event_id); + return ret; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/tdls/inc/target_if_tdls.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/tdls/inc/target_if_tdls.h new file mode 100644 index 0000000000..6f4d2399eb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/tdls/inc/target_if_tdls.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for tdls + * + */ + +#ifndef __TARGET_IF_TDLS_H__ +#define __TARGET_IF_TDLS_H__ + +struct tdls_info; +struct wlan_objmgr_psoc; +struct tdls_peer_update_state; +struct tdls_channel_switch_params; +struct sta_uapsd_trig_params; + +/** + * target_if_tdls_update_fw_state() - lmac handler to update tdls fw state + * @psoc: psoc object + * @param: tdls state parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_tdls_update_fw_state(struct wlan_objmgr_psoc *psoc, + struct tdls_info *param); + +/** + * target_if_tdls_update_peer_state() - lmac handler to update tdls peer state + * @psoc: psoc object + * @peer_params: tdls peer state params + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_tdls_update_peer_state(struct wlan_objmgr_psoc *psoc, + struct tdls_peer_update_state *peer_params); + +/** + * target_if_tdls_set_offchan_mode() - lmac handler to set tdls off channel mode + * @psoc: psoc object + * @params: tdls channel switch params + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc, + struct tdls_channel_switch_params *params); + +/** + * target_if_tdls_register_event_handler() - lmac handler to register tdls event + * handler + * @psoc : psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_tdls_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_tdls_unregister_event_handler() - lmac handler to unregister tdls + * event handler + * @psoc : psoc object + * @arg: argument passed to lmac + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_tdls_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg); + +/** + * target_if_tdls_register_tx_ops() - lmac handler to register tdls tx ops + * callback functions + * @tx_ops: wlan_lmac_if_tx_ops object + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_tdls_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/tdls/src/target_if_tdls.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/tdls/src/target_if_tdls.c new file mode 100644 index 0000000000..f9791f93f9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/tdls/src/target_if_tdls.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: offload lmac interface APIs for tdls + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline struct wlan_lmac_if_tdls_rx_ops * +target_if_tdls_get_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.rx_ops->tdls_rx_ops; +} + +static int +target_if_tdls_event_handler(ol_scn_t scn, uint8_t *data, uint32_t datalen) +{ + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_lmac_if_tdls_rx_ops *tdls_rx_ops; + struct tdls_event_info info; + QDF_STATUS status; + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + + if (!wmi_handle) { + target_if_err("null wmi_handle"); + return -EINVAL; + } + + if (wmi_extract_vdev_tdls_ev_param(wmi_handle, data, &info)) { + target_if_err("Failed to extract wmi tdls event"); + return -EINVAL; + } + + tdls_rx_ops = target_if_tdls_get_rx_ops(psoc); + if (tdls_rx_ops && tdls_rx_ops->tdls_ev_handler) { + status = tdls_rx_ops->tdls_ev_handler(psoc, &info); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("fail to handle tdls event"); + return -EINVAL; + } + } + + return 0; +} + +QDF_STATUS +target_if_tdls_update_fw_state(struct wlan_objmgr_psoc *psoc, + struct tdls_info *param) +{ + QDF_STATUS status; + enum wmi_tdls_state tdls_state; + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return QDF_STATUS_E_FAILURE; + } + + if (TDLS_SUPPORT_EXP_TRIG_ONLY == param->tdls_state) + tdls_state = WMI_TDLS_ENABLE_PASSIVE; + else if (TDLS_SUPPORT_IMP_MODE == param->tdls_state || + TDLS_SUPPORT_EXT_CONTROL == param->tdls_state) + tdls_state = WMI_TDLS_ENABLE_CONNECTION_TRACKER_IN_HOST; + else + tdls_state = WMI_TDLS_DISABLE; + + status = wmi_unified_update_fw_tdls_state_cmd(wmi_handle, + param, tdls_state); + + target_if_debug("vdev_id %d", param->vdev_id); + return status; +} + +QDF_STATUS +target_if_tdls_update_peer_state(struct wlan_objmgr_psoc *psoc, + struct tdls_peer_update_state *peer_params) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +target_if_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc, + struct tdls_channel_switch_params *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("Invalid WMI handle"); + return QDF_STATUS_E_FAILURE; + } + status = wmi_unified_set_tdls_offchan_mode_cmd(wmi_handle, + params); + + return status; +} + +QDF_STATUS +target_if_tdls_register_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi_handle"); + return QDF_STATUS_E_INVAL; + } + return wmi_unified_register_event(wmi_handle, + wmi_tdls_peer_event_id, + target_if_tdls_event_handler); +} + +QDF_STATUS +target_if_tdls_unregister_event_handler(struct wlan_objmgr_psoc *psoc, + void *arg) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null wmi_handle"); + return QDF_STATUS_E_INVAL; + } + return wmi_unified_unregister_event(wmi_handle, + wmi_tdls_peer_event_id); +} + +QDF_STATUS +target_if_tdls_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_lmac_if_tdls_tx_ops *tdls_txops; + + tdls_txops = &tx_ops->tdls_tx_ops; + + tdls_txops->update_fw_state = target_if_tdls_update_fw_state; + tdls_txops->update_peer_state = target_if_tdls_update_peer_state; + tdls_txops->set_offchan_mode = target_if_tdls_set_offchan_mode; + tdls_txops->tdls_reg_ev_handler = target_if_tdls_register_event_handler; + tdls_txops->tdls_unreg_ev_handler = + target_if_tdls_unregister_event_handler; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/twt/src/target_if_ext_twt_cmd.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/twt/src/target_if_ext_twt_cmd.c new file mode 100644 index 0000000000..42dafb9686 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/twt/src/target_if_ext_twt_cmd.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_ext_twt_cmd.c + * This file contains twt component's target related function definitions + */ +#include +#include +#include +#include +#include + +QDF_STATUS +target_if_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *req) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_twt_add_dialog_cmd(wmi_handle, req); +} + +QDF_STATUS +target_if_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_twt_del_dialog_cmd(wmi_handle, req); +} + +QDF_STATUS +target_if_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *req) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_twt_pause_dialog_cmd(wmi_handle, req); +} + +QDF_STATUS +target_if_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *req) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_twt_resume_dialog_cmd(wmi_handle, req); +} + +QDF_STATUS +target_if_twt_nudge_req(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *req) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + return wmi_unified_twt_nudge_dialog_cmd(wmi_handle, req); +} + +/** + * target_if_twt_convert_ac_value() - map ac setting to the value to be used in FW. + * @ac_value: ac value to be mapped. + * + * Return: enum wmi_traffic_ac + */ +static inline +wmi_traffic_ac target_if_twt_convert_ac_value(enum twt_traffic_ac ac_value) +{ + switch (ac_value) { + case TWT_AC_BE: + return WMI_AC_BE; + case TWT_AC_BK: + return WMI_AC_BK; + case TWT_AC_VI: + return WMI_AC_VI; + case TWT_AC_VO: + return WMI_AC_VO; + case TWT_AC_MAX: + return WMI_AC_MAX; + } + target_if_err("invalid enum: %u", ac_value); + return WMI_AC_MAX; +} + +QDF_STATUS +target_if_twt_ac_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac, uint8_t mac_id) +{ + struct wmi_unified *wmi_handle; + struct pdev_params params = {0}; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + params.param_id = wmi_pdev_param_twt_ac_config; + params.param_value = target_if_twt_convert_ac_value(twt_ac); + + return wmi_unified_pdev_param_send(wmi_handle, ¶ms, mac_id); +} + +QDF_STATUS +target_if_twt_register_ext_tx_ops(struct wlan_lmac_if_twt_tx_ops *twt_tx_ops) +{ + twt_tx_ops->setup_req = target_if_twt_setup_req; + twt_tx_ops->teardown_req = target_if_twt_teardown_req; + twt_tx_ops->pause_req = target_if_twt_pause_req; + twt_tx_ops->resume_req = target_if_twt_resume_req; + twt_tx_ops->nudge_req = target_if_twt_nudge_req; + twt_tx_ops->set_ac_param = target_if_twt_ac_param_send; + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/twt/src/target_if_ext_twt_evt.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/twt/src/target_if_ext_twt_evt.c new file mode 100644 index 0000000000..e8279cd55c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/twt/src/target_if_ext_twt_evt.c @@ -0,0 +1,558 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_ext_twt_evt.c + * This file contains twt component's target related function definitions + */ +#include +#include +#include +#include +#include +#include +#include "twt/core/src/wlan_twt_main.h" + +static int +target_if_twt_setup_complete_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_add_dialog_complete_event *data; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_setup_comp_cb) { + target_if_err("No valid twt setup complete rx ops"); + return -EINVAL; + } + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + qdf_status = wmi_extract_twt_add_dialog_comp_event(wmi_handle, + event, &data->params); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt add dialog event failed (status=%d)", + qdf_status); + goto done; + } + + if (data->params.num_additional_twt_params) { + qdf_status = wmi_extract_twt_add_dialog_comp_additional_params( + wmi_handle, event, len, 0, + &data->additional_params); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto done; + } + + qdf_status = twt_rx_ops->twt_setup_comp_cb(psoc, data); + +done: + qdf_mem_free(data); + + return qdf_status_to_os_return(qdf_status); +} + +static int +target_if_twt_teardown_complete_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_del_dialog_complete_event_param *data; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_teardown_comp_cb) { + target_if_err("No valid twt teardown complete rx ops"); + return -EINVAL; + } + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + qdf_status = wmi_extract_twt_del_dialog_comp_event(wmi_handle, + event, data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt del dialog event failed (status=%d)", + qdf_status); + goto done; + } + + qdf_status = twt_rx_ops->twt_teardown_comp_cb(psoc, data); + +done: + qdf_mem_free(data); + + return qdf_status_to_os_return(qdf_status); + +} + +/** + * target_if_twt_pause_complete_event_handler - TWT pause complete handler + * @scn: scn + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int +target_if_twt_pause_complete_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_pause_dialog_complete_event_param *param; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_pause_comp_cb) { + target_if_err("No valid twt pause complete rx ops"); + return -EINVAL; + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + qdf_status = wmi_extract_twt_pause_dialog_comp_event(wmi_handle, + event, param); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt pause dialog event failed (status=%d)", + qdf_status); + goto done; + } + + qdf_status = twt_rx_ops->twt_pause_comp_cb(psoc, param); + +done: + qdf_mem_free(param); + + return qdf_status_to_os_return(qdf_status); +} + +/** + * target_if_twt_resume_complete_event_handler - TWT resume complete evt handler + * @scn: scn + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int +target_if_twt_resume_complete_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_resume_dialog_complete_event_param *param; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_resume_comp_cb) { + target_if_err("No valid twt resume complete rx ops"); + return -EINVAL; + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + qdf_status = wmi_extract_twt_resume_dialog_comp_event(wmi_handle, + event, param); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt resume event failed (status=%d)", + qdf_status); + goto done; + } + + qdf_status = twt_rx_ops->twt_resume_comp_cb(psoc, param); + +done: + qdf_mem_free(param); + + return qdf_status_to_os_return(qdf_status); +} + +/** + * target_if_twt_nudge_complete_event_handler - TWT nudge complete evt handler + * @scn: scn + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static int +target_if_twt_nudge_complete_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_nudge_dialog_complete_event_param *param; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_nudge_comp_cb) { + target_if_err("No valid twt nudge complete rx ops"); + return -EINVAL; + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + qdf_status = wmi_extract_twt_nudge_dialog_comp_event(wmi_handle, + event, param); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt nudge event failed (status=%d)", + qdf_status); + goto done; + } + + qdf_status = twt_rx_ops->twt_nudge_comp_cb(psoc, param); + +done: + qdf_mem_free(param); + + return qdf_status_to_os_return(qdf_status); +} + +static int +target_if_twt_notify_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_notify_event_param *data; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_notify_comp_cb) { + target_if_err("No valid twt notify rx ops"); + return -EINVAL; + } + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + qdf_status = wmi_extract_twt_notify_event(wmi_handle, event, data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt notify event failed (status=%d)", + qdf_status); + goto done; + } + + qdf_status = twt_rx_ops->twt_notify_comp_cb(psoc, data); + +done: + qdf_mem_free(data); + + return qdf_status_to_os_return(qdf_status); +} + +static int +target_if_twt_ack_complete_event_handler(ol_scn_t scn, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct twt_ack_complete_event_param *data; + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops; + + TARGET_IF_ENTER(); + + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("psoc is null"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + twt_rx_ops = wlan_twt_get_rx_ops(psoc); + if (!twt_rx_ops || !twt_rx_ops->twt_ack_comp_cb) { + target_if_err("No valid twt ack rx ops"); + return -EINVAL; + } + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + qdf_status = wmi_extract_twt_ack_comp_event(wmi_handle, event, data); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + target_if_err("extract twt ack event failed (status=%d)", + qdf_status); + goto done; + } + + qdf_status = twt_rx_ops->twt_ack_comp_cb(psoc, data); + +done: + qdf_mem_free(data); + + return qdf_status_to_os_return(qdf_status); +} + +QDF_STATUS +target_if_twt_register_ext_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null!"); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_add_dialog_complete_event_id, + target_if_twt_setup_complete_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt add dialog event cb"); + return status; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_del_dialog_complete_event_id, + target_if_twt_teardown_complete_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt del dialog event cb"); + return status; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_pause_dialog_complete_event_id, + target_if_twt_pause_complete_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt pause dialog event cb"); + return status; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_resume_dialog_complete_event_id, + target_if_twt_resume_complete_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt resume dialog event cb"); + return status; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_nudge_dialog_complete_event_id, + target_if_twt_nudge_complete_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt nudge dialog event cb"); + return status; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_notify_event_id, + target_if_twt_notify_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt notify event cb"); + return status; + } + + status = wmi_unified_register_event_handler + (wmi_handle, + wmi_twt_ack_complete_event_id, + target_if_twt_ack_complete_event_handler, + WMI_RX_WORK_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to register twt ack event cb"); + return status; + } + + return status; +} + +QDF_STATUS +target_if_twt_deregister_ext_events(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_add_dialog_complete_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt add dialog event cb"); + return status; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_del_dialog_complete_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt del dialog event cb"); + return status; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_pause_dialog_complete_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt pause dialog event cb"); + return status; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_resume_dialog_complete_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt resume dialog event"); + return status; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_nudge_dialog_complete_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt nudge dialog event cb"); + return status; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_notify_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt notify event cb"); + return status; + } + + status = wmi_unified_unregister_event_handler(wmi_handle, + wmi_twt_ack_complete_event_id); + if (QDF_IS_STATUS_ERROR(status)) { + target_if_err("Failed to deregister twt ack complete event cb"); + return status; + } + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/wfa_config/inc/target_if_wfa_testcmd.h b/qcom/opensource/wlan/qcacld-3.0/components/target_if/wfa_config/inc/target_if_wfa_testcmd.h new file mode 100644 index 0000000000..9ee351cac1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/wfa_config/inc/target_if_wfa_testcmd.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for target_if WFA test commands sent + * to FW. + */ + +#ifndef TARGET_IF_WFA_TESTCMD_H__ +#define TARGET_IF_WFA_TESTCMD_H__ + +#include "wlan_mlme_main.h" + +/** + * target_if_wfatestcmd_register_tx_ops() - Target IF API to register WFA + * test command related tx op. + * @tx_ops: Pointer to tx ops fp struct + * + * Return: QDF_STATUS + */ +QDF_STATUS +target_if_wfatestcmd_register_tx_ops(struct wlan_wfa_cmd_tx_ops *tx_ops); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/target_if/wfa_config/src/target_if_wfa_testcmd.c b/qcom/opensource/wlan/qcacld-3.0/components/target_if/wfa_config/src/target_if_wfa_testcmd.c new file mode 100644 index 0000000000..60935d1a8b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/target_if/wfa_config/src/target_if_wfa_testcmd.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for target_if wfa send test cmd. + */ + +#include "qdf_types.h" +#include "target_if_wfa_testcmd.h" +#include "target_if.h" +#include "wlan_mlme_dbg.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_main.h" + +static struct wmi_unified +*target_if_wfa_get_wmi_handle_from_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + struct wmi_unified *wmi_handle; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + target_if_err("PDEV is NULL"); + return NULL; + } + + wmi_handle = get_wmi_unified_hdl_from_pdev(pdev); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return NULL; + } + + return wmi_handle; +} + +/** + * target_if_wfa_send_cmd() - Send WFA test cmd to WMI + * @vdev: VDEV object pointer + * @wfa_test: Pointer to WFA test params + * + * Return: QDF_STATUS + */ +static QDF_STATUS +target_if_wfa_send_cmd(struct wlan_objmgr_vdev *vdev, + struct set_wfatest_params *wfa_test) +{ + wmi_unified_t wmi_handle; + + wmi_handle = target_if_wfa_get_wmi_handle_from_vdev(vdev); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_wfa_test_cmd(wmi_handle, wfa_test); +} + +QDF_STATUS +target_if_wfatestcmd_register_tx_ops(struct wlan_wfa_cmd_tx_ops *tx_ops) +{ + if (!tx_ops) { + target_if_err("target if tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + tx_ops->send_wfa_test_cmd = target_if_wfa_send_cmd; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_cmds_process.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_cmds_process.c new file mode 100644 index 0000000000..750d9b32ac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_cmds_process.c @@ -0,0 +1,2724 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_cmds_process.c + * + * TDLS north bound commands implementation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_tdls_main.h" +#include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" +#include "wlan_tdls_mgmt.h" +#include "wlan_tdls_cmds_process.h" +#include "wlan_tdls_tgt_api.h" +#include "wlan_policy_mgr_api.h" +#include "nan_ucfg_api.h" +#include "wlan_mlme_main.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_mlo_mgr_link_switch.h" + +static uint16_t tdls_get_connected_peer_count(struct tdls_soc_priv_obj *soc_obj) +{ + return soc_obj->connected_peer_count; +} + +uint16_t tdls_get_connected_peer_count_from_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + + if (!soc_obj) + return 0; + + return tdls_get_connected_peer_count(soc_obj); +} + +#ifdef WLAN_FEATURE_11AX +static +uint8_t tdls_get_mlme_ch_power(struct vdev_mlme_obj *mlme_obj, qdf_freq_t freq) +{ + uint8_t num_power = mlme_obj->reg_tpc_obj.num_pwr_levels; + uint8_t idx; + struct reg_tpc_power_info *reg_power_info; + + reg_power_info = &mlme_obj->reg_tpc_obj; + for (idx = 0; idx < num_power; idx++) { + if (freq == reg_power_info->chan_power_info[idx].chan_cfreq) + return reg_power_info->chan_power_info[idx].tx_power; + } + + tdls_debug("channel %d not present in reg power info", freq); + return 0; +} + +static +void tdls_set_mlme_ch_power(struct wlan_objmgr_vdev *vdev, + struct vdev_mlme_obj *mlme_obj, + struct tdls_soc_priv_obj *tdls_soc_obj, + qdf_freq_t freq) +{ + uint8_t num_power = mlme_obj->reg_tpc_obj.num_pwr_levels; + uint8_t idx, tx_power; + struct reg_tpc_power_info *reg_power_info = &mlme_obj->reg_tpc_obj; + + if (REG_VERY_LOW_POWER_AP == reg_power_info->power_type_6g) + tx_power = tdls_get_6g_pwr_for_power_type(vdev, freq, + REG_CLI_DEF_VLP); + else + tx_power = tdls_soc_obj->bss_sta_power; + + for (idx = 0; idx < num_power; idx++) { + if (freq == reg_power_info->chan_power_info[idx].chan_cfreq) { + reg_power_info->chan_power_info[idx].tx_power = + tx_power; + return; + } + } + + tdls_debug("channel %d not present in reg power info", freq); +} + +static +void tdls_update_6g_power(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *tdls_soc_obj, + bool enable_link) +{ + struct wlan_lmac_if_reg_tx_ops *tx_ops; + struct vdev_mlme_obj *mlme_obj; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + qdf_freq_t freq = wlan_get_operation_chan_freq(vdev); + + if (!psoc) { + tdls_err("psoc is NULL"); + return; + } + + /* + * Check whether the frequency is 6ghz and tdls connection on 6ghz freq + * is allowed. + */ + if (!tdls_is_6g_freq_allowed(vdev, freq)) + return; + + /* + * Since, 8 TDLS peers can be connected. If connected peer already + * exist then no need to set the power again. + * Similarly, for disconnection case, this function is called after + * just after connected peer count is decreased. If connected peer + * count exist after decrement of peer count that mean another peer + * exist and then no need to reset the BSS power. + * The power should only be set/reset when 1st peer gets connected or + * last connected peer gets disconnected. + */ + if (tdls_soc_obj->connected_peer_count) { + tdls_debug("Number of connected peer %d", + tdls_soc_obj->connected_peer_count); + return; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + tdls_err("vdev component object is NULL"); + return; + } + + if (enable_link) { + tdls_soc_obj->bss_sta_power_type = REG_VERY_LOW_POWER_AP; + /* + * No need to update power if BSS-STA link is already configured + * as VLP + */ + if (tdls_soc_obj->bss_sta_power_type == + mlme_obj->reg_tpc_obj.power_type_6g) + return; + + tdls_soc_obj->bss_sta_power_type = + mlme_obj->reg_tpc_obj.power_type_6g; + mlme_obj->reg_tpc_obj.power_type_6g = REG_VERY_LOW_POWER_AP; + tdls_soc_obj->bss_sta_power = tdls_get_mlme_ch_power(mlme_obj, + freq); + tdls_debug("Updated power_type from %d to %d bss link power %d", + tdls_soc_obj->bss_sta_power_type, + mlme_obj->reg_tpc_obj.power_type_6g, + tdls_soc_obj->bss_sta_power); + } else { + if (REG_VERY_LOW_POWER_AP == tdls_soc_obj->bss_sta_power_type) + return; + + tdls_debug("Updated power_type_6g from %d to %d", + mlme_obj->reg_tpc_obj.power_type_6g, + tdls_soc_obj->bss_sta_power_type); + mlme_obj->reg_tpc_obj.power_type_6g = + tdls_soc_obj->bss_sta_power_type; + } + tdls_set_mlme_ch_power(vdev, mlme_obj, tdls_soc_obj, freq); + + tx_ops = wlan_reg_get_tx_ops(psoc); + if (tx_ops->set_tpc_power) + tx_ops->set_tpc_power(psoc, + wlan_vdev_get_id(vdev), + &mlme_obj->reg_tpc_obj); +} +#else +static +void tdls_update_6g_power(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *tdls_soc_obj, + bool enable_link) +{ +} +#endif + +/** + * tdls_decrement_peer_count() - decrement connected TDLS peer counter + * @vdev: vdev object + * @soc_obj: TDLS soc object + * + * Used in scheduler thread context, no lock needed. + * + * Return: None. + */ +void tdls_decrement_peer_count(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *soc_obj) +{ + if (soc_obj->connected_peer_count) + soc_obj->connected_peer_count--; + + tdls_debug("Connected peer count %d", soc_obj->connected_peer_count); + + /* Need to update osif params when last peer gets disconnected */ + if (!soc_obj->connected_peer_count && + soc_obj->tdls_osif_update_cb.tdls_osif_disconn_update) + soc_obj->tdls_osif_update_cb.tdls_osif_disconn_update(vdev); + tdls_update_6g_power(vdev, soc_obj, false); + + /* + * Offchannel is allowed only when TDLS is connected with one peer. + * If more than one peer is connected then Offchannel is disabled by + * WMI_TDLS_SET_OFFCHAN_MODE_CMDID with DISABLE_CHANSWITCH. + * Hence, re-enable offchannel when only one connected peer is left. + */ + if (soc_obj->connected_peer_count == 1) + tdls_set_tdls_offchannelmode(vdev, ENABLE_CHANSWITCH); +} + +/** + * tdls_increment_peer_count() - increment connected TDLS peer counter + * @soc_obj: TDLS soc object + * + * Used in scheduler thread context, no lock needed. + * + * Return: None. + */ +static void tdls_increment_peer_count(struct tdls_soc_priv_obj *soc_obj) +{ + soc_obj->connected_peer_count++; + tdls_debug("Connected peer count %d", soc_obj->connected_peer_count); +} + +/** + * tdls_validate_current_mode() - check current TDL mode + * @soc_obj: TDLS soc object + * + * Return: QDF_STATUS_SUCCESS if TDLS enabled, other for disabled + */ +static QDF_STATUS tdls_validate_current_mode(struct tdls_soc_priv_obj *soc_obj) +{ + if (soc_obj->tdls_current_mode == TDLS_SUPPORT_DISABLED || + soc_obj->tdls_current_mode == TDLS_SUPPORT_SUSPENDED) { + tdls_err("TDLS mode disabled OR not enabled, current mode %d", + soc_obj->tdls_current_mode); + return QDF_STATUS_E_NOSUPPORT; + } + return QDF_STATUS_SUCCESS; +} + +static char *tdls_get_ser_cmd_str(enum wlan_serialization_cmd_type type) +{ + switch (type) { + case WLAN_SER_CMD_TDLS_ADD_PEER: + return "TDLS_ADD_PEER_CMD"; + case WLAN_SER_CMD_TDLS_DEL_PEER: + return "TDLS_DEL_PEER_CMD"; + case WLAN_SER_CMD_TDLS_SEND_MGMT: + return "TDLS_SEND_MGMT_CMD"; + default: + return "UNKNOWN"; + } +} + +void +tdls_release_serialization_command(struct wlan_objmgr_vdev *vdev, + enum wlan_serialization_cmd_type type) +{ + struct wlan_serialization_queued_cmd_info cmd = {0}; + + cmd.cmd_type = type; + cmd.cmd_id = 0; + cmd.vdev = vdev; + + tdls_debug("release %s", tdls_get_ser_cmd_str(type)); + /* Inform serialization for command completion */ + wlan_serialization_remove_cmd(&cmd); +} + +/** + * tdls_pe_add_peer() - send TDLS add peer request to PE + * @req: TDL add peer request + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +static QDF_STATUS tdls_pe_add_peer(struct tdls_add_peer_request *req) +{ + struct tdls_add_sta_req *addstareq; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + struct scheduler_msg msg = {0,}; + QDF_STATUS status; + + addstareq = qdf_mem_malloc(sizeof(*addstareq)); + if (!addstareq) + return QDF_STATUS_E_NOMEM; + + vdev = req->vdev; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!soc_obj) { + tdls_err("NULL tdls soc object"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + addstareq->tdls_oper = TDLS_OPER_ADD; + addstareq->transaction_id = 0; + + addstareq->session_id = wlan_vdev_get_id(vdev); + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID); + if (!peer) { + tdls_err("bss peer is NULL"); + status = QDF_STATUS_E_INVAL; + goto error; + } + wlan_peer_obj_lock(peer); + qdf_mem_copy(addstareq->bssid.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID); + qdf_mem_copy(addstareq->peermac.bytes, req->add_peer_req.peer_addr, + QDF_MAC_ADDR_SIZE); + + tdls_debug("for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(addstareq->peermac.bytes)); + msg.type = soc_obj->tdls_add_sta_req; + msg.bodyptr = addstareq; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("fail to post pe msg to add peer"); + goto error; + } + return status; +error: + qdf_mem_free(addstareq); + return status; +} + +/** + * tdls_pe_del_peer() - send TDLS delete peer request to PE + * @req: TDLS delete peer request + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req) +{ + struct tdls_del_sta_req *delstareq; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + struct scheduler_msg msg = {0,}; + QDF_STATUS status; + + delstareq = qdf_mem_malloc(sizeof(*delstareq)); + if (!delstareq) + return QDF_STATUS_E_NOMEM; + + vdev = req->vdev; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!soc_obj) { + tdls_err("NULL tdls soc object"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + delstareq->transaction_id = 0; + + delstareq->session_id = wlan_vdev_get_id(vdev); + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID); + if (!peer) { + tdls_err("bss peer is NULL"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + wlan_peer_obj_lock(peer); + qdf_mem_copy(delstareq->bssid.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID); + qdf_mem_copy(delstareq->peermac.bytes, req->del_peer_req.peer_addr, + QDF_MAC_ADDR_SIZE); + + tdls_debug("for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(delstareq->peermac.bytes)); + msg.type = soc_obj->tdls_del_sta_req; + msg.bodyptr = delstareq; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("fail to post pe msg to del peer"); + goto error; + } + return status; +error: + qdf_mem_free(delstareq); + return status; +} +#ifdef WLAN_FEATURE_11AX +static void tdls_pe_update_peer_6ghz_capa(struct tdls_add_sta_req *addstareq, + struct tdls_update_peer_params *update_peer) +{ + qdf_mem_copy(&addstareq->he_6ghz_cap, &update_peer->he_6ghz_cap, + sizeof(update_peer->he_6ghz_cap)); +} + +static void tdls_pe_update_peer_he_capa(struct tdls_add_sta_req *addstareq, + struct tdls_update_peer_params *update_peer) +{ + addstareq->he_cap_len = update_peer->he_cap_len; + qdf_mem_copy(&addstareq->he_cap, + &update_peer->he_cap, + sizeof(update_peer->he_cap)); + + tdls_pe_update_peer_6ghz_capa(addstareq, update_peer); +} +#else +static void tdls_pe_update_peer_he_capa(struct tdls_add_sta_req *addstareq, + struct tdls_update_peer_params *update_peer) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +static inline void +tdls_pe_update_peer_eht_capa(struct tdls_add_sta_req *addstareq, + struct tdls_update_peer_params *update_peer) +{ + if (update_peer->ehtcap_present) { + addstareq->ehtcap_present = update_peer->ehtcap_present; + addstareq->eht_cap_len = update_peer->eht_cap_len; + qdf_mem_copy(&addstareq->eht_cap, + &update_peer->eht_cap, + sizeof(update_peer->eht_cap)); + } +} +#else +static inline void +tdls_pe_update_peer_eht_capa(struct tdls_add_sta_req *addstareq, + struct tdls_update_peer_params *update_peer) +{ +} +#endif +/** + * tdls_pe_update_peer() - send TDLS update peer request to PE + * @req: TDLS update peer request + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +static QDF_STATUS tdls_pe_update_peer(struct tdls_update_peer_request *req) +{ + struct tdls_add_sta_req *addstareq; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + struct scheduler_msg msg = {0,}; + struct tdls_update_peer_params *update_peer; + QDF_STATUS status; + + addstareq = qdf_mem_malloc(sizeof(*addstareq)); + if (!addstareq) + return QDF_STATUS_E_NOMEM; + + vdev = req->vdev; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!soc_obj) { + tdls_err("NULL tdls soc object"); + status = QDF_STATUS_E_INVAL; + goto error; + } + update_peer = &req->update_peer_req; + + addstareq->tdls_oper = TDLS_OPER_UPDATE; + addstareq->transaction_id = 0; + + addstareq->session_id = wlan_vdev_get_id(vdev); + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID); + if (!peer) { + tdls_err("bss peer is NULL"); + status = QDF_STATUS_E_INVAL; + goto error; + } + wlan_peer_obj_lock(peer); + qdf_mem_copy(addstareq->bssid.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID); + qdf_mem_copy(addstareq->peermac.bytes, update_peer->peer_addr, + QDF_MAC_ADDR_SIZE); + addstareq->capability = update_peer->capability; + addstareq->uapsd_queues = update_peer->uapsd_queues; + addstareq->max_sp = update_peer->max_sp; + + qdf_mem_copy(addstareq->extn_capability, + update_peer->extn_capability, WLAN_MAC_MAX_EXTN_CAP); + addstareq->htcap_present = update_peer->htcap_present; + qdf_mem_copy(&addstareq->ht_cap, + &update_peer->ht_cap, + sizeof(update_peer->ht_cap)); + addstareq->vhtcap_present = update_peer->vhtcap_present; + qdf_mem_copy(&addstareq->vht_cap, + &update_peer->vht_cap, + sizeof(update_peer->vht_cap)); + tdls_pe_update_peer_he_capa(addstareq, update_peer); + tdls_pe_update_peer_eht_capa(addstareq, update_peer); + addstareq->supported_rates_length = update_peer->supported_rates_len; + addstareq->is_pmf = update_peer->is_pmf; + qdf_mem_copy(&addstareq->supported_rates, + update_peer->supported_rates, + update_peer->supported_rates_len); + tdls_debug("for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(addstareq->peermac.bytes)); + + msg.type = soc_obj->tdls_add_sta_req; + msg.bodyptr = addstareq; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("fail to post pe msg to update peer"); + goto error; + } + return status; +error: + qdf_mem_free(addstareq); + return status; +} + +static QDF_STATUS +tdls_internal_add_peer_rsp(struct tdls_add_peer_request *req, + QDF_STATUS status) +{ + struct tdls_soc_priv_obj *soc_obj; + struct wlan_objmgr_vdev *vdev; + struct tdls_osif_indication ind; + QDF_STATUS ret; + + if (!req || !req->vdev) { + tdls_err("req: %pK", req); + return QDF_STATUS_E_INVAL; + } + vdev = req->vdev; + ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_SB_ID); + if (QDF_IS_STATUS_ERROR(ret)) { + tdls_err("can't get vdev object"); + return ret; + } + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (soc_obj && soc_obj->tdls_event_cb) { + ind.vdev = vdev; + ind.status = status; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ADD_PEER, &ind); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +tdls_internal_update_peer_rsp(struct tdls_update_peer_request *req, + QDF_STATUS status) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_osif_indication ind; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS ret; + + if (!req || !req->vdev) { + tdls_err("req: %pK", req); + return QDF_STATUS_E_INVAL; + } + vdev = req->vdev; + ret = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_SB_ID); + if (QDF_IS_STATUS_ERROR(ret)) { + tdls_err("can't get vdev object"); + return ret; + } + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (soc_obj && soc_obj->tdls_event_cb) { + ind.vdev = vdev; + ind.status = status; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ADD_PEER, &ind); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tdls_internal_del_peer_rsp(struct tdls_oper_request *req) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_osif_indication ind; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!req || !req->vdev) { + tdls_err("req: %pK", req); + return QDF_STATUS_E_INVAL; + } + vdev = req->vdev; + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev object"); + return status; + } + + soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev); + if (soc_obj && soc_obj->tdls_event_cb) { + ind.vdev = req->vdev; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_DEL_PEER, &ind); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tdls_activate_add_peer(struct tdls_add_peer_request *req) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_peer *peer; + uint16_t curr_tdls_peers; + const uint8_t *mac; + struct tdls_osif_indication ind; + + if (!req->vdev) { + tdls_err("vdev null when add tdls peer"); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + mac = req->add_peer_req.peer_addr; + soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(req->vdev); + + if (!soc_obj || !vdev_obj) { + tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj); + return QDF_STATUS_E_INVAL; + } + status = tdls_validate_current_mode(soc_obj); + if (QDF_IS_STATUS_ERROR(status)) + goto addrsp; + + peer = tdls_get_peer(vdev_obj, mac); + if (!peer) { + tdls_err("peer: " QDF_MAC_ADDR_FMT " not exist. invalid", + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_INVAL; + goto addrsp; + } + + /* in add station, we accept existing valid sta_id if there is */ + if ((peer->link_status > TDLS_LINK_CONNECTING) || + (peer->valid_entry)) { + tdls_notice("link_status %d add peer ignored", + peer->link_status); + status = QDF_STATUS_SUCCESS; + goto addrsp; + } + + /* when others are on-going, we want to change link_status to idle */ + if (tdls_is_progress(vdev_obj, mac, true)) { + tdls_notice(QDF_MAC_ADDR_FMT " TDLS setuping. Req declined.", + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_PERM; + goto setlink; + } + + /* first to check if we reached to maximum supported TDLS peer. */ + curr_tdls_peers = tdls_get_connected_peer_count(soc_obj); + if (soc_obj->max_num_tdls_sta <= curr_tdls_peers) { + tdls_err(QDF_MAC_ADDR_FMT + " Request declined. Current %d, Max allowed %d.", + QDF_MAC_ADDR_REF(mac), curr_tdls_peers, + soc_obj->max_num_tdls_sta); + status = QDF_STATUS_E_PERM; + goto setlink; + } + + tdls_set_peer_link_status(peer, + TDLS_LINK_CONNECTING, TDLS_LINK_SUCCESS); + + status = tdls_pe_add_peer(req); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err(QDF_MAC_ADDR_FMT " add peer failed with status %d", + QDF_MAC_ADDR_REF(mac), status); + goto setlink; + } + + return QDF_STATUS_SUCCESS; + +setlink: + tdls_set_link_status(vdev_obj, mac, TDLS_LINK_IDLE, + TDLS_LINK_UNSPECIFIED); +addrsp: + if (soc_obj->tdls_event_cb) { + ind.status = status; + ind.vdev = req->vdev; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ADD_PEER, &ind); + } + + return QDF_STATUS_E_PERM; +} + +static QDF_STATUS +tdls_add_peer_serialize_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + struct tdls_add_peer_request *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!cmd || !cmd->umac_cmd) { + tdls_err("cmd: %pK, reason: %d", cmd, reason); + return QDF_STATUS_E_NULL_VALUE; + } + + req = cmd->umac_cmd; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + /* command moved to active list + */ + status = tdls_activate_add_peer(req); + break; + + case WLAN_SER_CB_CANCEL_CMD: + /* command removed from pending list. + * notify os interface the status + */ + status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE); + break; + + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + /* active command time out. */ + status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE); + break; + + case WLAN_SER_CB_RELEASE_MEM_CMD: + /* command successfully completed. + * release memory & vdev reference count + */ + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + break; + + default: + /* Do nothing but logging */ + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc, + uint8_t action_code) +{ + if (!tdls_soc) + return; + + if (TDLS_TEARDOWN != action_code || + !tdls_soc->tdls_nss_switch_in_progress) + return; + + if (tdls_soc->tdls_teardown_peers_cnt != 0) + tdls_soc->tdls_teardown_peers_cnt--; + if (tdls_soc->tdls_teardown_peers_cnt == 0) { + if (tdls_soc->tdls_nss_transition_mode == + TDLS_NSS_TRANSITION_S_1x1_to_2x2) { + /* TDLS NSS switch is fully completed, so + * reset the flags. + */ + tdls_notice("TDLS NSS switch is fully completed"); + tdls_soc->tdls_nss_switch_in_progress = false; + tdls_soc->tdls_nss_teardown_complete = false; + } else { + /* TDLS NSS switch is not yet completed, but + * tdls teardown is completed for all the + * peers. + */ + tdls_notice("teardown done & NSS switch in progress"); + tdls_soc->tdls_nss_teardown_complete = true; + } + tdls_soc->tdls_nss_transition_mode = + TDLS_NSS_TRANSITION_S_UNKNOWN; + } + +} + +/** + * tdls_set_cap() - set TDLS capability type + * @tdls_vdev: tdls vdev object + * @mac: peer mac address + * @cap: TDLS capability type + * + * Return: 0 if successful or negative errno otherwise + */ +int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac, + enum tdls_peer_capab cap) +{ + struct tdls_peer *curr_peer; + + curr_peer = tdls_get_peer(tdls_vdev, mac); + if (!curr_peer) { + tdls_err("curr_peer is NULL"); + return -EINVAL; + } + + curr_peer->tdls_support = cap; + return 0; +} + +static int tdls_validate_setup_frames(struct tdls_soc_priv_obj *tdls_soc, + struct tdls_validate_action_req *tdls_validate) +{ + /* supplicant still sends tdls_mgmt(SETUP_REQ) + * even after we return error code at + * 'add_station()'. Hence we have this check + * again in addition to add_station(). Anyway, + * there is no harm to double-check. + */ + if (TDLS_SETUP_REQUEST == tdls_validate->action_code) { + tdls_err(QDF_MAC_ADDR_FMT " TDLS Max peer already connected. action (%d) declined. Num of peers (%d), Max allowed (%d).", + QDF_MAC_ADDR_REF(tdls_validate->peer_mac), + tdls_validate->action_code, + tdls_soc->connected_peer_count, + tdls_soc->max_num_tdls_sta); + return -EINVAL; + } + /* maximum reached. tweak to send + * error code to peer and return error + * code to supplicant + */ + tdls_validate->status_code = QDF_STATUS_E_RESOURCES; + tdls_err(QDF_MAC_ADDR_FMT " TDLS Max peer already connected, send response status (%d). Num of peers (%d), Max allowed (%d).", + QDF_MAC_ADDR_REF(tdls_validate->peer_mac), + tdls_validate->action_code, + tdls_soc->connected_peer_count, + tdls_soc->max_num_tdls_sta); + + return -EPERM; +} + +int tdls_validate_mgmt_request(struct tdls_action_frame_request *tdls_mgmt_req) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc; + struct tdls_peer *curr_peer; + struct tdls_peer *temp_peer; + QDF_STATUS status; + uint8_t vdev_id; + + struct wlan_objmgr_vdev *vdev = tdls_mgmt_req->vdev; + struct tdls_validate_action_req *tdls_validate = + &tdls_mgmt_req->chk_frame; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, + &tdls_vdev, + &tdls_soc)) + return -ENOTSUPP; + + /* + * STA or P2P client should be connected and authenticated before + * sending any TDLS frames + */ + if ((wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) || + !tdls_is_vdev_authenticated(vdev)) { + tdls_err("STA is not connected or not authenticated."); + return -EAGAIN; + } + + if (mlo_mgr_is_link_switch_in_progress(vdev)) { + tdls_notice("vdev:%d Link Switch in progress. TDLS is not allowed", + wlan_vdev_get_id(vdev)); + return -EAGAIN; + } + + /* other than teardown frame, mgmt frames are not sent if disabled */ + if (TDLS_TEARDOWN != tdls_validate->action_code) { + if (!tdls_check_is_tdls_allowed(vdev)) { + tdls_err("TDLS not allowed, reject MGMT, action = %d", + tdls_validate->action_code); + return -EPERM; + } + + /* if tdls_mode is disabled, then decline the peer's request */ + if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode || + TDLS_SUPPORT_SUSPENDED == tdls_soc->tdls_current_mode) { + tdls_notice(QDF_MAC_ADDR_FMT + " TDLS mode is disabled. action %d declined.", + QDF_MAC_ADDR_REF(tdls_validate->peer_mac), + tdls_validate->action_code); + return -ENOTSUPP; + } + if (tdls_soc->tdls_nss_switch_in_progress) { + tdls_err("nss switch in progress, action %d declined " + QDF_MAC_ADDR_FMT, + tdls_validate->action_code, + QDF_MAC_ADDR_REF(tdls_validate->peer_mac)); + return -EAGAIN; + } + } + /* + * In case another tdls request comes while tdls setup is already + * ongoing with one peer. Reject only when status code is 0. If status + * code is non-zero, it means supplicant already rejected it and + * the same should be notified to peer. + */ + if (TDLS_IS_SETUP_ACTION(tdls_validate->action_code)) { + if (tdls_is_progress(tdls_vdev, tdls_validate->peer_mac, + true) && + tdls_validate->status_code == 0) { + tdls_err("setup is ongoing. action %d declined for " + QDF_MAC_ADDR_FMT, + tdls_validate->action_code, + QDF_MAC_ADDR_REF(tdls_validate->peer_mac)); + return -EPERM; + } + } + + /* call hdd_wmm_is_acm_allowed() */ + vdev_id = wlan_vdev_get_id(vdev); + if (!tdls_soc->tdls_wmm_cb(vdev_id)) { + tdls_debug("admission ctrl set to VI, send the frame with least AC (BK) for action %d", + tdls_validate->action_code); + tdls_mgmt_req->use_default_ac = false; + } else { + tdls_mgmt_req->use_default_ac = true; + } + + if (TDLS_SETUP_REQUEST == tdls_validate->action_code || + TDLS_SETUP_RESPONSE == tdls_validate->action_code) { + if (tdls_soc->max_num_tdls_sta <= + tdls_soc->connected_peer_count) { + status = tdls_validate_setup_frames(tdls_soc, + tdls_validate); + if (QDF_STATUS_SUCCESS != status) + return status; + /* fall through to send setup resp + * with failure status code + */ + } else { + curr_peer = + tdls_find_peer(tdls_vdev, + tdls_validate->peer_mac); + if (curr_peer) { + if (TDLS_IS_LINK_CONNECTED(curr_peer)) { + tdls_err(QDF_MAC_ADDR_FMT " already connected action %d declined.", + QDF_MAC_ADDR_REF( + tdls_validate->peer_mac), + tdls_validate->action_code); + + return -EPERM; + } + } + } + } + + tdls_debug("tdls_mgmt " QDF_MAC_ADDR_FMT " action %d, dialog_token %d status %d, len = %zu", + QDF_MAC_ADDR_REF(tdls_validate->peer_mac), + tdls_validate->action_code, tdls_validate->dialog_token, + tdls_validate->status_code, tdls_validate->len); + + /*Except teardown responder will not be used so just make 0 */ + tdls_validate->responder = 0; + if (TDLS_TEARDOWN == tdls_validate->action_code) { + temp_peer = tdls_find_peer(tdls_vdev, tdls_validate->peer_mac); + if (!temp_peer) { + tdls_err(QDF_MAC_ADDR_FMT " peer doesn't exist", + QDF_MAC_ADDR_REF( + tdls_validate->peer_mac)); + return -EPERM; + } + + if (TDLS_IS_LINK_CONNECTED(temp_peer)) + tdls_validate->responder = temp_peer->is_responder; + else { + tdls_err(QDF_MAC_ADDR_FMT " peer doesn't exist or not connected %d dialog_token %d status %d, tdls_validate->len = %zu", + QDF_MAC_ADDR_REF(tdls_validate->peer_mac), + temp_peer->link_status, + tdls_validate->dialog_token, + tdls_validate->status_code, + tdls_validate->len); + return -EPERM; + } + } + + /* For explicit trigger of DIS_REQ come out of BMPS for + * successfully receiving DIS_RSP from peer. + */ + if ((TDLS_SETUP_RESPONSE == tdls_validate->action_code) || + (TDLS_SETUP_CONFIRM == tdls_validate->action_code) || + (TDLS_DISCOVERY_RESPONSE == tdls_validate->action_code) || + (TDLS_DISCOVERY_REQUEST == tdls_validate->action_code)) { + /* Fw will take care if PS offload is enabled. */ + if (TDLS_DISCOVERY_REQUEST != tdls_validate->action_code) + tdls_set_cap(tdls_vdev, tdls_validate->peer_mac, + TDLS_CAP_SUPPORTED); + } + return 0; +} + +QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req) +{ + struct wlan_serialization_command cmd = {0,}; + enum wlan_serialization_status ser_cmd_status; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_objmgr_psoc *psoc; + + if (!req || !req->vdev) { + tdls_err("req: %pK", req); + goto free_req; + } + vdev = req->vdev; + if (!tdls_check_is_tdls_allowed(vdev)) { + tdls_err("TDLS not allowed, reject add station for vdev: %d", + wlan_vdev_get_id(vdev)); + goto error; + } + + if (mlo_mgr_is_link_switch_in_progress(vdev)) { + tdls_err("Link Switch in progress, reject add sta for vdev: %d", + wlan_vdev_get_id(vdev)); + goto error; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + tdls_err("can't get psoc"); + goto error; + } + + status = QDF_STATUS_SUCCESS; + + cmd.cmd_type = WLAN_SER_CMD_TDLS_ADD_PEER; + cmd.cmd_id = 0; + cmd.cmd_cb = tdls_add_peer_serialize_callback; + cmd.umac_cmd = req; + cmd.source = WLAN_UMAC_COMP_TDLS; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT; + cmd.vdev = vdev; + cmd.is_blocking = true; + + ser_cmd_status = wlan_serialization_request(&cmd); + tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req, + ser_cmd_status); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list. Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + default: + goto error; + } + + return status; +error: + /* notify os interface about internal error*/ + status = tdls_internal_add_peer_rsp(req, QDF_STATUS_E_FAILURE); + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); +free_req: + qdf_mem_free(req); + return status; +} + +static QDF_STATUS +tdls_activate_update_peer(struct tdls_update_peer_request *req) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct wlan_objmgr_vdev *vdev; + struct tdls_peer *curr_peer; + uint16_t curr_tdls_peers; + const uint8_t *mac; + struct tdls_update_peer_params *update_peer; + struct tdls_osif_indication ind; + + if (!req->vdev) { + tdls_err("vdev object NULL when add TDLS peer"); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + mac = req->update_peer_req.peer_addr; + vdev = req->vdev; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!soc_obj || !vdev_obj) { + tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj); + return QDF_STATUS_E_INVAL; + } + + status = tdls_validate_current_mode(soc_obj); + if (QDF_IS_STATUS_ERROR(status)) + goto updatersp; + + curr_peer = tdls_find_peer(vdev_obj, mac); + if (!curr_peer) { + tdls_err(QDF_MAC_ADDR_FMT " not exist. return invalid", + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_INVAL; + goto updatersp; + } + + /* in change station, we accept only when sta_id is valid */ + if (curr_peer->link_status == TDLS_LINK_TEARING || + !curr_peer->valid_entry) { + tdls_err(QDF_MAC_ADDR_FMT " link %d. update peer rejected", + QDF_MAC_ADDR_REF(mac), curr_peer->link_status); + status = QDF_STATUS_E_PERM; + goto updatersp; + } + + if (curr_peer->link_status == TDLS_LINK_CONNECTED && + curr_peer->valid_entry) { + tdls_err(QDF_MAC_ADDR_FMT " link %d. update peer is igonored as tdls state is already connected ", + QDF_MAC_ADDR_REF(mac), curr_peer->link_status); + status = QDF_STATUS_SUCCESS; + goto updatersp; + } + + /* when others are on-going, we want to change link_status to idle */ + if (tdls_is_progress(vdev_obj, mac, true)) { + tdls_notice(QDF_MAC_ADDR_FMT " TDLS setuping. Req declined.", + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_PERM; + goto setlink; + } + + curr_tdls_peers = tdls_get_connected_peer_count(soc_obj); + if (soc_obj->max_num_tdls_sta <= curr_tdls_peers) { + tdls_err(QDF_MAC_ADDR_FMT + " Request declined. Current: %d, Max allowed: %d.", + QDF_MAC_ADDR_REF(mac), curr_tdls_peers, + soc_obj->max_num_tdls_sta); + status = QDF_STATUS_E_PERM; + goto setlink; + } + update_peer = &req->update_peer_req; + + if (update_peer->htcap_present) + curr_peer->spatial_streams = update_peer->ht_cap.mcsset[1]; + + tdls_set_peer_caps(vdev_obj, mac, &req->update_peer_req); + status = tdls_pe_update_peer(req); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err(QDF_MAC_ADDR_FMT " update peer failed with status %d", + QDF_MAC_ADDR_REF(mac), status); + goto setlink; + } + + return QDF_STATUS_SUCCESS; + +setlink: + tdls_set_link_status(vdev_obj, mac, TDLS_LINK_IDLE, + TDLS_LINK_UNSPECIFIED); +updatersp: + if (soc_obj->tdls_event_cb) { + ind.status = status; + ind.vdev = vdev; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ADD_PEER, &ind); + } + + return QDF_STATUS_E_PERM; +} + +static QDF_STATUS +tdls_update_peer_serialize_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + struct tdls_update_peer_request *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!cmd || !cmd->umac_cmd) { + tdls_err("cmd: %pK, reason: %d", cmd, reason); + return QDF_STATUS_E_NULL_VALUE; + } + + req = cmd->umac_cmd; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + /* command moved to active list + */ + status = tdls_activate_update_peer(req); + break; + + case WLAN_SER_CB_CANCEL_CMD: + /* command removed from pending list. + * notify os interface the status + */ + status = tdls_internal_update_peer_rsp(req, + QDF_STATUS_E_FAILURE); + break; + + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + /* active command time out. */ + status = tdls_internal_update_peer_rsp(req, + QDF_STATUS_E_FAILURE); + break; + + case WLAN_SER_CB_RELEASE_MEM_CMD: + /* command successfully completed. + * release memory & release reference count + */ + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + break; + + default: + /* Do nothing but logging */ + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req) +{ + struct wlan_serialization_command cmd = {0,}; + enum wlan_serialization_status ser_cmd_status; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!req || !req->vdev) { + tdls_err("req: %pK", req); + status = QDF_STATUS_E_FAILURE; + goto free_req; + } + + vdev = req->vdev; + cmd.cmd_type = WLAN_SER_CMD_TDLS_ADD_PEER; + cmd.cmd_id = 0; + cmd.cmd_cb = tdls_update_peer_serialize_callback; + cmd.umac_cmd = req; + cmd.source = WLAN_UMAC_COMP_TDLS; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT; + cmd.vdev = req->vdev; + cmd.is_blocking = true; + + ser_cmd_status = wlan_serialization_request(&cmd); + tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req, + ser_cmd_status); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list. Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + default: + goto error; + } + + return status; +error: + /* notify os interface about internal error*/ + status = tdls_internal_update_peer_rsp(req, QDF_STATUS_E_FAILURE); + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); +free_req: + qdf_mem_free(req); + return status; +} + +static QDF_STATUS tdls_activate_del_peer(struct tdls_oper_request *req) +{ + struct tdls_del_peer_request request = {0,}; + + request.vdev = req->vdev; + request.del_peer_req.peer_addr = req->peer_addr; + + return tdls_pe_del_peer(&request); +} + +static QDF_STATUS +tdls_del_peer_serialize_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + struct tdls_oper_request *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!cmd || !cmd->umac_cmd) { + tdls_err("cmd: %pK, reason: %d", cmd, reason); + return QDF_STATUS_E_NULL_VALUE; + } + + req = cmd->umac_cmd; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + /* command moved to active list + */ + status = tdls_activate_del_peer(req); + break; + + case WLAN_SER_CB_CANCEL_CMD: + /* command removed from pending list. + * notify os interface the status + */ + status = tdls_internal_del_peer_rsp(req); + break; + + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + /* active command time out. */ + status = tdls_internal_del_peer_rsp(req); + break; + + case WLAN_SER_CB_RELEASE_MEM_CMD: + /* command successfully completed. + * release memory & vdev reference count + */ + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + break; + + default: + /* Do nothing but logging */ + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req) +{ + struct wlan_serialization_command cmd = {0,}; + enum wlan_serialization_status ser_cmd_status; + struct wlan_objmgr_vdev *vdev; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_soc_priv_obj *soc_obj; + uint8_t *mac; + struct tdls_peer *peer; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!req || !req->vdev) { + tdls_err("req: %pK", req); + status = QDF_STATUS_E_INVAL; + goto free_req; + } + + vdev = req->vdev; + + /* vdev reference cnt is acquired in ucfg_tdls_oper */ + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + + if (!vdev_obj || !soc_obj) { + tdls_err("tdls vdev_obj: %pK soc_obj: %pK", vdev_obj, soc_obj); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + mac = req->peer_addr; + peer = tdls_find_peer(vdev_obj, mac); + if (!peer) { + tdls_err(QDF_MAC_ADDR_FMT + " not found, ignore NL80211_TDLS_ENABLE_LINK", + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_INVAL; + goto error; + } + + if (!peer->valid_entry) { + tdls_err("invalid peer:" QDF_MAC_ADDR_FMT " link state %d", + QDF_MAC_ADDR_REF(mac), peer->link_status); + status = QDF_STATUS_E_INVAL; + goto error; + } + + if (soc_obj->tdls_dp_vdev_update) + soc_obj->tdls_dp_vdev_update(&soc_obj->soc, + wlan_vdev_get_id(vdev), + soc_obj->tdls_update_dp_vdev_flags, + false); + + cmd.cmd_type = WLAN_SER_CMD_TDLS_DEL_PEER; + cmd.cmd_id = 0; + cmd.cmd_cb = tdls_del_peer_serialize_callback; + cmd.umac_cmd = req; + cmd.source = WLAN_UMAC_COMP_TDLS; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = TDLS_DELETE_PEER_CMD_TIMEOUT; + cmd.vdev = vdev; + cmd.is_blocking = true; + + ser_cmd_status = wlan_serialization_request(&cmd); + tdls_debug("req: 0x%pK wlan_serialization_request status:%d", req, + ser_cmd_status); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list. Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + default: + goto error; + } + + return status; +error: + /* notify os interface about internal error*/ + status = tdls_internal_del_peer_rsp(req); + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); +free_req: + qdf_mem_free(req); + return status; +} + +/** + * tdls_update_peer_rsp() - handle response for update TDLS peer + * @rsp: TDLS add peer response + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +static QDF_STATUS tdls_update_peer_rsp(struct tdls_add_sta_rsp *rsp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_soc_priv_obj *soc_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_osif_indication ind; + + psoc = rsp->psoc; + if (!psoc) { + tdls_err("psoc is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id, + WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("invalid vdev: %d", rsp->session_id); + status = QDF_STATUS_E_INVAL; + goto error; + } + + tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_ADD_PEER); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); +error: + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (soc_obj && soc_obj->tdls_event_cb) { + ind.status = rsp->status_code; + ind.vdev = vdev; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ADD_PEER, &ind); + } + qdf_mem_free(rsp); + + return status; +} + +/** + * tdls_process_send_mgmt_rsp() - handle response for send mgmt + * @rsp: TDLS send mgmt response + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_osif_indication ind; + + psoc = rsp->psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->vdev_id, + WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("invalid vdev"); + status = QDF_STATUS_E_INVAL; + qdf_mem_free(rsp); + return status; + } + tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_soc || !tdls_vdev) { + tdls_err("soc object:%pK, vdev object:%pK", tdls_soc, tdls_vdev); + status = QDF_STATUS_E_FAILURE; + } + + tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_SEND_MGMT); + + if (legacy_result_success == rsp->status_code) + goto free_rsp; + tdls_err("send mgmt failed. status code(=%d)", rsp->status_code); + status = QDF_STATUS_E_FAILURE; + + if (tdls_soc && tdls_soc->tdls_event_cb) { + ind.vdev = vdev; + ind.status = status; + tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data, + TDLS_EVENT_MGMT_TX_ACK_CNF, &ind); + } + +free_rsp: + qdf_mem_free(rsp); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + return status; +} + +/** + * tdls_send_mgmt_tx_completion() - process tx completion + * @tx_complete: TDLS mgmt completion info + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_send_mgmt_tx_completion( + struct tdls_mgmt_tx_completion_ind *tx_complete) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_osif_indication ind; + + psoc = tx_complete->psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + tx_complete->vdev_id, + WLAN_TDLS_SB_ID); + + if (!vdev) { + tdls_err("invalid vdev"); + status = QDF_STATUS_E_INVAL; + goto free_tx_complete; + } + + tdls_soc = wlan_psoc_get_tdls_soc_obj(psoc); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + + if (!tdls_soc || !tdls_vdev) { + tdls_err("soc object:%pK, vdev object:%pK", tdls_soc, tdls_vdev); + status = QDF_STATUS_E_FAILURE; + } + + if (tdls_soc && tdls_soc->tdls_event_cb) { + ind.vdev = vdev; + ind.status = tx_complete->tx_complete_status; + tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data, + TDLS_EVENT_MGMT_TX_ACK_CNF, &ind); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); +free_tx_complete: + qdf_mem_free(tx_complete); + return status; +} + +/** + * tdls_add_peer_rsp() - handle response for add TDLS peer + * @rsp: TDLS add peer response + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +static QDF_STATUS tdls_add_peer_rsp(struct tdls_add_sta_rsp *rsp) +{ + uint8_t sta_idx; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_soc_priv_obj *soc_obj = NULL; + struct tdls_conn_info *conn_rec; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_osif_indication ind; + + psoc = rsp->psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id, + WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("invalid vdev: %d", rsp->session_id); + status = QDF_STATUS_E_INVAL; + goto error; + } + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!soc_obj || !vdev_obj) { + tdls_err("soc object:%pK, vdev object:%pK", soc_obj, vdev_obj); + status = QDF_STATUS_E_FAILURE; + goto cmddone; + } + if (rsp->status_code) { + tdls_err("add sta failed. status code(=%d)", rsp->status_code); + status = QDF_STATUS_E_FAILURE; + } else { + conn_rec = soc_obj->tdls_conn_info; + for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; + sta_idx++) { + if (!conn_rec[sta_idx].valid_entry) { + conn_rec[sta_idx].session_id = rsp->session_id; + conn_rec[sta_idx].valid_entry = true; + conn_rec[sta_idx].index = sta_idx; + qdf_copy_macaddr(&conn_rec[sta_idx].peer_mac, + &rsp->peermac); + tdls_debug("TDLS: Add sta mac at idx %d" + QDF_MAC_ADDR_FMT, sta_idx, + QDF_MAC_ADDR_REF + (rsp->peermac.bytes)); + break; + } + } + + if (sta_idx < soc_obj->max_num_tdls_sta) { + status = tdls_set_valid(vdev_obj, rsp->peermac.bytes); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("set staid failed"); + status = QDF_STATUS_E_FAILURE; + } + } else { + status = QDF_STATUS_E_FAILURE; + } + } + +cmddone: + tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_ADD_PEER); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); +error: + if (soc_obj && soc_obj->tdls_event_cb) { + ind.vdev = vdev; + ind.status = rsp->status_code; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ADD_PEER, &ind); + } + qdf_mem_free(rsp); + + return status; +} + +QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp) +{ + tdls_debug("peer oper %d", rsp->tdls_oper); + + if (rsp->tdls_oper == TDLS_OPER_ADD) + return tdls_add_peer_rsp(rsp); + else if (rsp->tdls_oper == TDLS_OPER_UPDATE) + return tdls_update_peer_rsp(rsp); + + return QDF_STATUS_E_INVAL; +} + +static void tdls_process_unforce_link_mode(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + QDF_STATUS status; + bool unforce = true; + int i; + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + return; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + + tdls_debug("Peer: " QDF_MAC_ADDR_FMT "link status %d, vdev id %d", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes), + peer->link_status, wlan_vdev_get_id(vdev)); + + if (peer->link_status == TDLS_LINK_CONNECTED || + peer->link_status == TDLS_LINK_CONNECTING) { + unforce = false; + goto unforce_exit; + } + + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + +unforce_exit: + if (unforce) { + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(vdev)); + tdls_set_link_unforce(vdev); + } +} + +QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp) +{ + uint8_t sta_idx, id; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_soc_priv_obj *soc_obj = NULL; + struct tdls_conn_info *conn_rec; + struct tdls_peer *curr_peer = NULL; + const uint8_t *macaddr; + struct tdls_osif_indication ind; + + tdls_debug("del peer rsp: vdev %d peer " QDF_MAC_ADDR_FMT, + rsp->session_id, QDF_MAC_ADDR_REF(rsp->peermac.bytes)); + psoc = rsp->psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rsp->session_id, + WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("invalid vdev: %d", rsp->session_id); + status = QDF_STATUS_E_INVAL; + goto error; + } + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!soc_obj || !vdev_obj) { + tdls_err("soc object:%pK, vdev object:%pK", soc_obj, vdev_obj); + status = QDF_STATUS_E_FAILURE; + goto cmddone; + } + + conn_rec = soc_obj->tdls_conn_info; + for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) { + if (conn_rec[sta_idx].session_id != rsp->session_id || + qdf_mem_cmp(conn_rec[sta_idx].peer_mac.bytes, + rsp->peermac.bytes, QDF_MAC_ADDR_SIZE)) + continue; + + macaddr = rsp->peermac.bytes; + tdls_debug("TDLS: del STA with sta_idx %d", sta_idx); + curr_peer = tdls_find_peer(vdev_obj, macaddr); + if (curr_peer) { + tdls_debug(QDF_MAC_ADDR_FMT " status is %d", + QDF_MAC_ADDR_REF(macaddr), + curr_peer->link_status); + + id = wlan_vdev_get_id(vdev); + + if (TDLS_IS_LINK_CONNECTED(curr_peer)) + tdls_decrement_peer_count(vdev, soc_obj); + } + tdls_reset_peer(vdev_obj, macaddr); + conn_rec[sta_idx].valid_entry = false; + conn_rec[sta_idx].session_id = 0xff; + conn_rec[sta_idx].index = INVALID_TDLS_PEER_INDEX; + qdf_mem_zero(&conn_rec[sta_idx].peer_mac, + QDF_MAC_ADDR_SIZE); + + status = QDF_STATUS_SUCCESS; + break; + } + macaddr = rsp->peermac.bytes; + if (!curr_peer) { + curr_peer = tdls_find_peer(vdev_obj, macaddr); + + if (curr_peer) + tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE, + (curr_peer->link_status == + TDLS_LINK_TEARING) ? + TDLS_LINK_UNSPECIFIED : + TDLS_LINK_DROPPED_BY_REMOTE); + } + + tdls_process_unforce_link_mode(vdev); + +cmddone: + tdls_release_serialization_command(vdev, WLAN_SER_CMD_TDLS_DEL_PEER); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); +error: + + if (soc_obj && soc_obj->tdls_event_cb) { + ind.vdev = vdev; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_DEL_PEER, &ind); + } + qdf_mem_free(rsp); + + return status; +} + +static QDF_STATUS +tdls_wma_update_peer_state(struct tdls_soc_priv_obj *soc_obj, + struct tdls_peer_update_state *peer_state) +{ + struct scheduler_msg msg = {0,}; + QDF_STATUS status; + + tdls_debug("update TDLS peer " QDF_MAC_ADDR_FMT " vdev %d, state %d", + QDF_MAC_ADDR_REF(peer_state->peer_macaddr), + peer_state->vdev_id, peer_state->peer_state); + msg.type = soc_obj->tdls_update_peer_state; + msg.reserved = 0; + msg.bodyptr = peer_state; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("scheduler_post_msg failed"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS tdls_process_enable_link(struct tdls_oper_request *req) +{ + struct tdls_peer *peer; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_soc_priv_obj *soc_obj; + struct wlan_objmgr_vdev *vdev; + uint8_t *mac; + struct tdls_peer_update_state *peer_update_param; + QDF_STATUS status; + uint32_t feature; + uint8_t id; + + vdev = req->vdev; + if (!vdev) { + tdls_err("NULL vdev object"); + qdf_mem_free(req); + return QDF_STATUS_E_NULL_VALUE; + } + + /* vdev reference cnt is acquired in ucfg_tdls_oper */ + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + + if (!vdev_obj || !soc_obj) { + tdls_err("tdls vdev_obj: %pK soc_obj: %pK", vdev_obj, soc_obj); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + mac = req->peer_addr; + peer = tdls_find_peer(vdev_obj, mac); + if (!peer) { + tdls_err(QDF_MAC_ADDR_FMT + " not found, ignore NL80211_TDLS_ENABLE_LINK", + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_INVAL; + goto error; + } + + tdls_debug("enable link for peer " QDF_MAC_ADDR_FMT " link state %d", + QDF_MAC_ADDR_REF(mac), peer->link_status); + if (!peer->valid_entry) { + tdls_err("invalid entry " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + status = QDF_STATUS_E_INVAL; + goto error; + } + + /* + * Offchannel is allowed only when TDLS is connected with one peer. + * If more than one peer is connected then Disable Offchannel by sending + * WMI_TDLS_SET_OFFCHAN_MODE_CMDID with DISABLE_CHANSWITCH. + * So, basically when the 2nd peer enable_link is there, offchannel + * should be disabled and will remain disabled for all subsequent + * TDLS peer connection. + * Offchannel will be re-enabled when connected peer count again + * becomes 1. + */ + if (soc_obj->connected_peer_count == 1) + tdls_set_tdls_offchannelmode(vdev, DISABLE_CHANSWITCH); + + peer->tdls_support = TDLS_CAP_SUPPORTED; + if (TDLS_LINK_CONNECTED != peer->link_status) + tdls_set_peer_link_status(peer, TDLS_LINK_CONNECTED, + TDLS_LINK_SUCCESS); + + id = wlan_vdev_get_id(vdev); + status = soc_obj->tdls_reg_peer(soc_obj->tdls_peer_context, + id, mac, peer->qos); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("TDLS register peer fail, status %d", status); + goto error; + } + + peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param)); + if (!peer_update_param) { + status = QDF_STATUS_E_NOMEM; + goto error; + } + + tdls_extract_peer_state_param(peer_update_param, peer); + + status = tdls_wma_update_peer_state(soc_obj, peer_update_param); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(peer_update_param); + status = QDF_STATUS_E_PERM; + goto error; + } + + tdls_update_6g_power(vdev, soc_obj, true); + tdls_increment_peer_count(soc_obj); + /* Need to update osif params when first peer gets connected */ + if (soc_obj->connected_peer_count == 1 && + soc_obj->tdls_osif_update_cb.tdls_osif_conn_update) + soc_obj->tdls_osif_update_cb.tdls_osif_conn_update(vdev); + feature = soc_obj->tdls_configs.tdls_feature_flags; + + if (soc_obj->tdls_dp_vdev_update) + soc_obj->tdls_dp_vdev_update( + &soc_obj->soc, + wlan_vdev_get_id(vdev), + soc_obj->tdls_update_dp_vdev_flags, + ((peer->link_status == TDLS_LINK_CONNECTED) ? + true : false)); + + tdls_debug("TDLS buffer sta: %d, uapsd_mask %d", + TDLS_IS_BUFFER_STA_ENABLED(feature), + soc_obj->tdls_configs.tdls_uapsd_mask); + +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + + return status; +} + +/** + * tdls_config_force_peer() - configure an externally controllable TDLS peer + * @req: TDLS operation request + * + * This is not the tdls_process_cmd function. No need to acquire the reference + * count, release reference count and free the request, the caller handle it + * correctly. + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +static QDF_STATUS tdls_config_force_peer( + struct tdls_oper_config_force_peer_request *req) +{ + struct tdls_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + const uint8_t *macaddr; + uint32_t feature; + QDF_STATUS status; + uint32_t chan_freq; + struct tdls_peer_update_state *peer_update_param; + + macaddr = req->peer_addr; + + vdev = req->vdev; + pdev = wlan_vdev_get_pdev(vdev); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!pdev || !vdev_obj || !soc_obj) { + tdls_err("pdev: %pK, vdev_obj: %pK, soc_obj: %pK", + pdev, vdev_obj, soc_obj); + return QDF_STATUS_E_INVAL; + } + + feature = soc_obj->tdls_configs.tdls_feature_flags; + if (!(TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) || + TDLS_IS_LIBERAL_EXTERNAL_CONTROL_ENABLED(feature)) || + !TDLS_IS_IMPLICIT_TRIG_ENABLED(feature)) { + tdls_err("TDLS ext ctrl or Imp Trig not enabled, %x", feature); + return QDF_STATUS_E_NOSUPPORT; + } + + /* + * In case of liberal external mode, supplicant will provide peer mac + * address but driver has to behave similar to implicit mode ie + * establish tdls link with any peer that supports tdls and meets stats + */ + if (TDLS_IS_LIBERAL_EXTERNAL_CONTROL_ENABLED(feature)) { + tdls_debug("liberal mode set"); + return QDF_STATUS_SUCCESS; + } + + peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param)); + if (!peer_update_param) + return QDF_STATUS_E_NOMEM; + + peer = tdls_get_peer(vdev_obj, macaddr); + if (!peer) { + tdls_err("peer " QDF_MAC_ADDR_FMT " does not exist", + QDF_MAC_ADDR_REF(macaddr)); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + status = tdls_set_force_peer(vdev_obj, macaddr, true); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("set force peer failed"); + goto error; + } + + /* Update the peer mac to firmware, so firmware could update the + * connection table + */ + peer_update_param->vdev_id = wlan_vdev_get_id(vdev); + qdf_mem_copy(peer_update_param->peer_macaddr, + macaddr, QDF_MAC_ADDR_SIZE); + peer_update_param->peer_state = TDLS_PEER_ADD_MAC_ADDR; + + status = tdls_wma_update_peer_state(soc_obj, peer_update_param); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("update peer state failed"); + goto error; + } + + soc_obj->tdls_external_peer_count++; + chan_freq = req->ch_freq; + + /* Validate if off channel is DFS channel */ + if (wlan_reg_is_dfs_for_freq(pdev, chan_freq)) { + tdls_err("Resetting TDLS off-channel freq from %d to %d", + req->ch_freq, WLAN_TDLS_PREFERRED_OFF_CHANNEL_FRQ_DEF); + req->ch_freq = WLAN_TDLS_PREFERRED_OFF_CHANNEL_FRQ_DEF; + } + tdls_set_extctrl_param(peer, req->ch_freq, req->max_latency, + req->op_class, req->min_bandwidth); + + tdls_set_callback(peer, req->callback); + tdls_set_ct_mode(soc_obj->soc, vdev); + + return status; +error: + qdf_mem_free(peer_update_param); + return status; +} + +/** + * tdls_process_setup_peer() - process configure an externally + * controllable TDLS peer + * @req: TDLS operation request + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_process_setup_peer(struct tdls_oper_request *req) +{ + struct tdls_oper_config_force_peer_request peer_req; + struct tdls_soc_priv_obj *soc_obj; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + uint8_t reg_bw_offset = 0; + qdf_freq_t pref_freq; + uint32_t pref_width; + struct wlan_objmgr_pdev *pdev; + + + /* reference cnt is acquired in ucfg_tdls_oper */ + vdev = req->vdev; + if (!vdev) { + tdls_err("NULL vdev object"); + status = QDF_STATUS_E_NULL_VALUE; + goto freereq; + } + + if (!tdls_check_is_tdls_allowed(vdev)) { + tdls_err("TDLS not allowed on vdev:%d, Reject setup peer", + wlan_vdev_get_id(vdev)); + status = QDF_STATUS_E_INVAL; + goto error; + } + + if (mlo_mgr_is_link_switch_in_progress(vdev)) { + tdls_err("TDLS not allowed on vdev:%d, Link switch in progress", + wlan_vdev_get_id(vdev)); + status = QDF_STATUS_E_INVAL; + goto error; + } + + tdls_debug("vdev:%d Configure external TDLS peer " QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(vdev), + QDF_MAC_ADDR_REF(req->peer_addr)); + qdf_mem_zero(&peer_req, sizeof(peer_req)); + peer_req.vdev = vdev; + qdf_mem_copy(peer_req.peer_addr, req->peer_addr, QDF_MAC_ADDR_SIZE); + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!soc_obj) { + tdls_err("NULL soc object"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + pref_freq = tdls_get_offchan_freq(vdev, soc_obj); + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + tdls_err("NULL pdev object"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + peer_req.ch_freq = pref_freq; + pref_width = tdls_get_offchan_bw(soc_obj, pref_freq); + + if (!peer_req.op_class) + peer_req.op_class = tdls_get_opclass_from_bandwidth(vdev, + pref_freq, + pref_width, + ®_bw_offset); + + tdls_debug("peer chan %d peer opclass %d reg_bw_offset %d", + peer_req.ch_freq, + peer_req.op_class, + reg_bw_offset); + status = tdls_config_force_peer(&peer_req); +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +freereq: + qdf_mem_free(req); + + return status; +} + +QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req) +{ + struct tdls_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct wlan_objmgr_vdev *vdev; + const uint8_t *macaddr; + uint32_t feature; + QDF_STATUS status; + struct tdls_peer_update_state *peer_update_param; + struct tdls_osif_indication ind; + + macaddr = req->peer_addr; + tdls_debug("NL80211_TDLS_TEARDOWN for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(macaddr)); + + vdev = req->vdev; + if (!vdev) { + tdls_err("NULL vdev object"); + qdf_mem_free(req); + return QDF_STATUS_E_NULL_VALUE; + } + + /* reference cnt is acquired in ucfg_tdls_oper */ + vdev_obj = wlan_vdev_get_tdls_vdev_obj(req->vdev); + soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev); + if (!soc_obj || !vdev_obj) { + tdls_err("soc_obj: %pK, vdev_obj: %pK", soc_obj, vdev_obj); + status = QDF_STATUS_E_INVAL; + goto error; + } + + feature = soc_obj->tdls_configs.tdls_feature_flags; + if (!(TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) || + TDLS_IS_LIBERAL_EXTERNAL_CONTROL_ENABLED(feature)) || + !TDLS_IS_IMPLICIT_TRIG_ENABLED(feature)) { + tdls_err("TDLS ext ctrl or Imp Trig not enabled, %x", feature); + status = QDF_STATUS_E_NOSUPPORT; + goto error; + } + + peer = tdls_find_peer(vdev_obj, macaddr); + if (!peer) { + tdls_err("peer matching " QDF_MAC_ADDR_FMT " not found", + QDF_MAC_ADDR_REF(macaddr)); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + if (peer->link_status == TDLS_LINK_CONNECTED) + tdls_set_peer_link_status(peer, TDLS_LINK_TEARING, + TDLS_LINK_UNSPECIFIED); + + if (soc_obj->tdls_dp_vdev_update) + soc_obj->tdls_dp_vdev_update( + &soc_obj->soc, + wlan_vdev_get_id(vdev), + soc_obj->tdls_update_dp_vdev_flags, + false); + + if (soc_obj->tdls_event_cb) { + qdf_mem_copy(ind.peer_mac, macaddr, QDF_MAC_ADDR_SIZE); + ind.vdev = vdev; + ind.reason = TDLS_TEARDOWN_PEER_UNSPEC_REASON; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_TEARDOWN_REQ, &ind); + } + + status = tdls_set_force_peer(vdev_obj, macaddr, false); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("set force peer failed"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + if (soc_obj->tdls_external_peer_count) + soc_obj->tdls_external_peer_count--; + + tdls_set_callback(peer, NULL); + peer_update_param = qdf_mem_malloc(sizeof(*peer_update_param)); + if (!peer_update_param) { + status = QDF_STATUS_E_NOMEM; + goto error; + } + + peer_update_param->vdev_id = wlan_vdev_get_id(vdev); + qdf_mem_copy(peer_update_param->peer_macaddr, + macaddr, QDF_MAC_ADDR_SIZE); + peer_update_param->peer_state = TDLS_PEER_REMOVE_MAC_ADDR; + status = tdls_wma_update_peer_state(soc_obj, peer_update_param); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(peer_update_param); + goto error; + } + tdls_set_ct_mode(soc_obj->soc, vdev); + +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + + return status; +} + +static const char *tdls_evt_to_str(enum tdls_event_msg_type type) +{ + switch (type) { + case TDLS_SHOULD_DISCOVER: + return "SHOULD_DISCOVER"; + case TDLS_SHOULD_TEARDOWN: + return "SHOULD_TEARDOWN"; + case TDLS_PEER_DISCONNECTED: + return "SHOULD_PEER_DISCONNECTED"; + case TDLS_CONNECTION_TRACKER_NOTIFY: + return "CONNECTION_TRACKER_NOTIFICATION"; + default: + return "INVALID_TYPE"; + } +} + +QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev, + struct tdls_event_info *evt) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_peer *curr_peer; + uint32_t feature; + uint16_t type; + + /*TODO ignore this if any concurrency detected*/ + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + type = evt->message_type; + + tdls_debug("TDLS %s: " QDF_MAC_ADDR_FMT "reason %d", + tdls_evt_to_str(type), + QDF_MAC_ADDR_REF(evt->peermac.bytes), + evt->peer_reason); + if (!soc_obj || !vdev_obj) { + tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s", + soc_obj, vdev_obj, tdls_evt_to_str(type)); + return QDF_STATUS_E_NULL_VALUE; + } + if (soc_obj->tdls_nss_switch_in_progress) { + tdls_err("TDLS antenna switching, ignore %s", + tdls_evt_to_str(type)); + return QDF_STATUS_SUCCESS; + } + + curr_peer = tdls_get_peer(vdev_obj, evt->peermac.bytes); + if (!curr_peer) { + tdls_notice("curr_peer is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (TDLS_LINK_CONNECTED == curr_peer->link_status) { + tdls_err("TDLS link status is connected, ignore"); + return QDF_STATUS_SUCCESS; + } + + feature = soc_obj->tdls_configs.tdls_feature_flags; + if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature) && + !curr_peer->is_forced_peer) { + tdls_debug("curr_peer is not forced, ignore %s", + tdls_evt_to_str(type)); + return QDF_STATUS_SUCCESS; + } + + tdls_debug("initiate TDLS setup on %s, ext: %d, force: %d, reason: %d", + tdls_evt_to_str(type), + TDLS_IS_EXTERNAL_CONTROL_ENABLED(feature), + curr_peer->is_forced_peer, evt->peer_reason); + vdev_obj->curr_candidate = curr_peer; + tdls_implicit_send_discovery_request(vdev_obj); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev, + struct tdls_event_info *evt) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_peer *curr_peer; + uint32_t reason; + uint16_t type; + + type = evt->message_type; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + + tdls_debug("TDLS %s: " QDF_MAC_ADDR_FMT "reason %d", + tdls_evt_to_str(type), + QDF_MAC_ADDR_REF(evt->peermac.bytes), evt->peer_reason); + + if (!soc_obj || !vdev_obj) { + tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s", + soc_obj, vdev_obj, tdls_evt_to_str(type)); + return QDF_STATUS_E_NULL_VALUE; + } + + curr_peer = tdls_find_peer(vdev_obj, evt->peermac.bytes); + if (!curr_peer) { + tdls_notice("curr_peer is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + reason = evt->peer_reason; + if (TDLS_LINK_CONNECTED == curr_peer->link_status) { + tdls_err("%s reason: %d for" QDF_MAC_ADDR_FMT, + tdls_evt_to_str(type), evt->peer_reason, + QDF_MAC_ADDR_REF(evt->peermac.bytes)); + if (reason == TDLS_TEARDOWN_RSSI || + reason == TDLS_DISCONNECTED_PEER_DELETE || + reason == TDLS_TEARDOWN_PTR_TIMEOUT || + reason == TDLS_TEARDOWN_NO_RSP) + reason = TDLS_TEARDOWN_PEER_UNREACHABLE; + else + reason = TDLS_TEARDOWN_PEER_UNSPEC_REASON; + + tdls_indicate_teardown(vdev_obj, curr_peer, reason); + } else { + tdls_err("TDLS link is not connected, ignore %s", + tdls_evt_to_str(type)); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_process_connection_tracker_notify(struct wlan_objmgr_vdev *vdev, + struct tdls_event_info *evt) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + uint16_t type; + + type = evt->message_type; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + + if (!soc_obj || !vdev_obj) { + tdls_err("soc_obj: %pK, vdev_obj: %pK, ignore %s", + soc_obj, vdev_obj, tdls_evt_to_str(type)); + return QDF_STATUS_E_NULL_VALUE; + } + + /*TODO connection tracker update*/ + return QDF_STATUS_SUCCESS; +} + +/** + * tdls_process_set_responder() - Set/clear TDLS peer's responder role + * @set_req: set responder request + * + * Return: 0 for success or -EINVAL otherwise + */ +static +int tdls_process_set_responder(struct tdls_set_responder_req *set_req) +{ + struct tdls_peer *curr_peer; + struct tdls_vdev_priv_obj *tdls_vdev; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(set_req->vdev); + if (!tdls_vdev) { + tdls_err("tdls vdev obj is NULL"); + return -EINVAL; + } + curr_peer = tdls_get_peer(tdls_vdev, set_req->peer_mac); + if (!curr_peer) { + tdls_err("curr_peer is NULL"); + return -EINVAL; + } + + curr_peer->is_responder = set_req->responder; + + psoc = wlan_vdev_get_psoc(tdls_vdev->vdev); + if (!psoc) { + tdls_err("psoc not found"); + return -EINVAL; + } + + status = policy_mgr_update_nss_req(psoc, + wlan_vdev_get_id(tdls_vdev->vdev), + HW_MODE_SS_2x2, HW_MODE_SS_2x2); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Unable to process NSS request"); + return -EINVAL; + } + + return 0; +} + + +/** + * tdls_set_responder() - Set/clear TDLS peer's responder role + * @set_req: set responder request + * + * Return: 0 for success or -EINVAL otherwise + */ +int tdls_set_responder(struct tdls_set_responder_req *set_req) +{ + int status; + + if (!set_req) { + tdls_err("Invalid input params"); + return -EINVAL; + } + + if (!set_req->vdev) { + tdls_err("Invalid input params %pK", set_req); + status = -EINVAL; + goto free_req; + } + + status = wlan_objmgr_vdev_try_get_ref(set_req->vdev, WLAN_TDLS_NB_ID); + if (QDF_STATUS_SUCCESS != status) { + tdls_err("vdev object is deleted"); + status = -EINVAL; + goto error; + } + + status = tdls_process_set_responder(set_req); + +error: + wlan_objmgr_vdev_release_ref(set_req->vdev, WLAN_TDLS_NB_ID); +free_req: + qdf_mem_free(set_req); + return status; +} + +static int tdls_teardown_links(struct tdls_soc_priv_obj *soc_obj, uint32_t mode) +{ + uint8_t staidx; + struct tdls_peer *curr_peer; + struct tdls_conn_info *conn_rec; + int ret = 0; + + conn_rec = soc_obj->tdls_conn_info; + for (staidx = 0; staidx < soc_obj->max_num_tdls_sta; staidx++) { + if (!conn_rec[staidx].valid_entry) + continue; + + curr_peer = tdls_find_all_peer(soc_obj, + conn_rec[staidx].peer_mac.bytes); + if (!curr_peer) + continue; + + /* if supported only 1x1, skip it */ + if (curr_peer->spatial_streams == HW_MODE_SS_1x1) + continue; + + tdls_debug("Indicate TDLS teardown peer bssid " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF( + curr_peer->peer_mac.bytes)); + tdls_indicate_teardown(curr_peer->vdev_priv, curr_peer, + TDLS_TEARDOWN_PEER_UNSPEC_REASON); + + soc_obj->tdls_teardown_peers_cnt++; + } + + if (soc_obj->tdls_teardown_peers_cnt >= 1) { + soc_obj->tdls_nss_switch_in_progress = true; + tdls_debug("TDLS peers to be torn down = %d", + soc_obj->tdls_teardown_peers_cnt); + + /* set the antenna switch transition mode */ + if (mode == HW_MODE_SS_1x1) { + soc_obj->tdls_nss_transition_mode = + TDLS_NSS_TRANSITION_S_2x2_to_1x1; + ret = -EAGAIN; + } else { + soc_obj->tdls_nss_transition_mode = + TDLS_NSS_TRANSITION_S_1x1_to_2x2; + ret = 0; + } + tdls_debug("TDLS teardown for antenna switch operation starts"); + } + + return ret; +} + +QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct wlan_objmgr_vdev *vdev = NULL; + uint32_t vdev_nss; + int ant_switch_state = 0; + uint32_t vdev_id; + enum QDF_OPMODE opmode; + qdf_freq_t freq; + struct tdls_osif_indication ind; + enum policy_mgr_con_mode mode; + + if (!req) { + tdls_err("null req"); + return QDF_STATUS_E_INVAL; + } + + vdev = req->vdev; + if (!vdev) { + tdls_err("null vdev"); + qdf_mem_free(req); + return QDF_STATUS_E_INVAL; + } + + status = tdls_get_vdev_objects(vdev, &vdev_obj, &soc_obj); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev_obj & soc_obj"); + goto get_obj_err; + } + + if (soc_obj->connected_peer_count == 0) + goto ant_sw_done; + + if (soc_obj->tdls_nss_switch_in_progress) { + if (!soc_obj->tdls_nss_teardown_complete) { + tdls_err("TDLS antenna switch is in progress"); + goto ant_sw_in_progress; + } else { + goto ant_sw_done; + } + } + + vdev_id = wlan_vdev_get_id(vdev); + opmode = wlan_vdev_mlme_get_opmode(vdev); + mode = policy_mgr_qdf_opmode_to_pm_con_mode(wlan_vdev_get_psoc(vdev), + opmode, vdev_id); + freq = policy_mgr_get_channel(soc_obj->soc, + mode, + &vdev_id); + + /* Check supported nss for TDLS, if is 1x1, no need to teardown links */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_2g; + else + vdev_nss = soc_obj->tdls_configs.tdls_vdev_nss_5g; + + if (vdev_nss == HW_MODE_SS_1x1) { + tdls_debug("Supported NSS is 1x1, no need to teardown TDLS links"); + goto ant_sw_done; + } + + if (tdls_teardown_links(soc_obj, req->mode) == 0) + goto ant_sw_done; + +ant_sw_in_progress: + ant_switch_state = -EAGAIN; +ant_sw_done: + if (soc_obj->tdls_event_cb) { + ind.vdev = vdev; + ind.status = ant_switch_state; + soc_obj->tdls_event_cb(soc_obj->tdls_evt_cb_data, + TDLS_EVENT_ANTENNA_SWITCH, &ind); + } + + if (soc_obj->tdls_nss_switch_in_progress && + soc_obj->tdls_nss_teardown_complete) { + soc_obj->tdls_nss_switch_in_progress = false; + soc_obj->tdls_nss_teardown_complete = false; + } + tdls_debug("tdls_nss_switch_in_progress: %d tdls_nss_teardown_complete: %d", + soc_obj->tdls_nss_switch_in_progress, + soc_obj->tdls_nss_teardown_complete); + +get_obj_err: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + + return status; +} + +QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg) +{ + struct tdls_antenna_switch_request *req; + + if (!msg || !msg->bodyptr) { + tdls_err("msg: 0x%pK", msg); + return QDF_STATUS_E_NULL_VALUE; + } + req = msg->bodyptr; + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + + return QDF_STATUS_SUCCESS; +} + +void wlan_tdls_offchan_parms_callback(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + tdls_err("vdev is NULL"); + return; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +} + +int tdls_process_set_offchannel(struct tdls_set_offchannel *req) +{ + int status; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + + if (tdls_get_vdev_objects(req->vdev, &tdls_vdev_obj, &tdls_soc_obj) != + QDF_STATUS_SUCCESS) { + status = -ENOTSUPP; + goto free; + } + + tdls_debug("TDLS offchannel to be configured %d", req->offchannel); + + if (req->offchannel) + status = tdls_set_tdls_offchannel(tdls_soc_obj, + req->offchannel); + else + status = -ENOTSUPP; + +free: + + if (req->callback) + req->callback(req->vdev); + qdf_mem_free(req); + + return status; +} + +int tdls_process_set_offchan_mode(struct tdls_set_offchanmode *req) +{ + int status = QDF_STATUS_E_FAILURE; + struct tdls_soc_priv_obj *tdls_soc_obj; + + tdls_debug("TDLS offchan mode to be configured %d", req->offchan_mode); + + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev); + if (!tdls_soc_obj) + goto free; + + if ((tdls_get_connected_peer_count(tdls_soc_obj) > 1) && + req->offchan_mode == ENABLE_CHANSWITCH) { + tdls_debug("Reject off chan enable, Connected peer count %d", + tdls_get_connected_peer_count(tdls_soc_obj)); + goto free; + } + + status = tdls_set_tdls_offchannelmode(req->vdev, req->offchan_mode); + + if (req->callback) + req->callback(req->vdev); + +free: + qdf_mem_free(req); + + return status; +} + +int tdls_process_set_secoffchanneloffset( + struct tdls_set_secoffchanneloffset *req) +{ + int status; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + + if (tdls_get_vdev_objects(req->vdev, &tdls_vdev_obj, &tdls_soc_obj) != + QDF_STATUS_SUCCESS) { + status = -ENOTSUPP; + goto free; + } + + tdls_debug("TDLS offchannel offset to be configured %d", + req->offchan_offset); + status = tdls_set_tdls_secoffchanneloffset(tdls_soc_obj, + req->offchan_offset); + +free: + + if (req->callback) + req->callback(req->vdev); + qdf_mem_free(req); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_cmds_process.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_cmds_process.h new file mode 100644 index 0000000000..95e2cc9d83 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_cmds_process.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_cmds_process.h + * + * TDLS north bound commands include file + */ + +#ifndef _WLAN_TDLS_CMDS_PROCESS_H_ +#define _WLAN_TDLS_CMDS_PROCESS_H_ + +#define TDLS_IS_SETUP_ACTION(action) \ + ((TDLS_SETUP_REQUEST <= action) && \ + (TDLS_SETUP_CONFIRM >= action)) + +/** + * tdls_process_add_peer() - add TDLS peer + * @req: TDLS add peer request + * + * Return: QDF_STATUS_SUCCESS if success; other value if failed + */ +QDF_STATUS tdls_process_add_peer(struct tdls_add_peer_request *req); + +/** + * tdls_process_del_peer() - del TDLS peer + * @req: TDLS del peer request + * + * Return: QDF_STATUS_SUCCESS if success; other value if failed + */ +QDF_STATUS tdls_process_del_peer(struct tdls_oper_request *req); + +/** + * tdls_process_enable_link() - enable TDLS link + * @req: TDLS enable link request + * + * Return: QDF_STATUS_SUCCESS if success; other value if failed + */ +QDF_STATUS tdls_process_enable_link(struct tdls_oper_request *req); + +/** + * tdls_process_setup_peer() - process configure an externally + * controllable TDLS peer + * @req: TDLS configure force peer request + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_process_setup_peer(struct tdls_oper_request *req); + +/** + * tdls_process_remove_force_peer() - process remove an externally controllable + * TDLS peer + * @req: TDLS operation request + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_process_remove_force_peer(struct tdls_oper_request *req); + +/** + * tdls_process_update_peer() - update TDLS peer + * @req: TDLS update peer request + * + * Return: QDF_STATUS_SUCCESS if success; other value if failed + */ +QDF_STATUS tdls_process_update_peer(struct tdls_update_peer_request *req); + +/** + * tdls_process_antenna_switch() - handle TDLS antenna switch + * @req: TDLS antenna switch request + * + * Rely on callback to indicate the antenna switch state to caller. + * + * Return: QDF_STATUS_SUCCESS if success; other value if failed. + */ +QDF_STATUS tdls_process_antenna_switch(struct tdls_antenna_switch_request *req); + +/** + * tdls_antenna_switch_flush_callback() - flush TDLS antenna switch request + * @msg: scheduler message contains tdls antenna switch event + * + * This function call is invoked when scheduler thread is going down + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_antenna_switch_flush_callback(struct scheduler_msg *msg); + +/** + * tdls_pe_del_peer() - send TDLS delete peer request to PE + * @req: TDLS delete peer request + * + * Return: QDF status + */ +QDF_STATUS tdls_pe_del_peer(struct tdls_del_peer_request *req); + +/** + * tdls_process_add_peer_rsp() - handle response for add or update TDLS peer + * @rsp: TDLS add peer response + * + * Return: QDF status + */ +QDF_STATUS tdls_process_add_peer_rsp(struct tdls_add_sta_rsp *rsp); + +/** + * tdls_reset_nss() - reset tdls nss parameters + * @tdls_soc: TDLS soc object + * @action_code: action code + * + * Return: None + */ +void tdls_reset_nss(struct tdls_soc_priv_obj *tdls_soc, + uint8_t action_code); + +/** + * tdls_release_serialization_command() - TDLS wrapper to + * releases serialization command. + * @vdev: Object manager vdev + * @type: command to release. + * + * Return: None + */ + +void +tdls_release_serialization_command(struct wlan_objmgr_vdev *vdev, + enum wlan_serialization_cmd_type type); + +/** + * tdls_get_connected_peer_count_from_vdev() - Get TDLS connected peer count + * @vdev: Pointer to vdev obj + * + * Return: Connected peer count + */ +uint16_t tdls_get_connected_peer_count_from_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_set_cap() - set TDLS capability type + * @tdls_vdev: tdls vdev object + * @mac: peer mac address + * @cap: TDLS capability type + * + * Return: 0 if successful or negative errno otherwise + */ +int tdls_set_cap(struct tdls_vdev_priv_obj *tdls_vdev, const uint8_t *mac, + enum tdls_peer_capab cap); + +/** + * tdls_process_send_mgmt_rsp() - handle response for send mgmt + * @rsp: TDLS send mgmt response + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_process_send_mgmt_rsp(struct tdls_send_mgmt_rsp *rsp); + +/** + * tdls_send_mgmt_tx_completion() - process tx completion + * @tx_complete: TDLS mgmt completion info + * + * Return: QDF_STATUS_SUCCESS for success; other values if failed + */ +QDF_STATUS tdls_send_mgmt_tx_completion( + struct tdls_mgmt_tx_completion_ind *tx_complete); + +/** + * tdls_process_del_peer_rsp() - handle response for delete TDLS peer + * @rsp: TDLS delete peer response + * + * Return: QDF status + */ +QDF_STATUS tdls_process_del_peer_rsp(struct tdls_del_sta_rsp *rsp); + +/** + * tdls_process_should_discover() - handle tdls should_discover event + * @vdev: vdev object + * @evt: event info + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_should_discover(struct wlan_objmgr_vdev *vdev, + struct tdls_event_info *evt); + +/** + * tdls_process_should_teardown() - handle tdls should_teardown event + * @vdev: vdev object + * @evt: event info + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_should_teardown(struct wlan_objmgr_vdev *vdev, + struct tdls_event_info *evt); + +/** + * tdls_process_connection_tracker_notify() -handle tdls connect tracker notify + * @vdev: vdev object + * @evt: event info + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_connection_tracker_notify(struct wlan_objmgr_vdev *vdev, + struct tdls_event_info *evt); + +/** + * tdls_validate_mgmt_request() - validate mgmt request + * @tdls_mgmt_req: action frame request + * + * Return: 0 for success or -EINVAL otherwise + */ +int tdls_validate_mgmt_request(struct tdls_action_frame_request *tdls_mgmt_req); + +/** + * tdls_set_responder() - Set/clear TDLS peer's responder role + * @set_req: set responder request + * + * Return: 0 for success or -EINVAL otherwise + */ +int tdls_set_responder(struct tdls_set_responder_req *set_req); + +/** + * tdls_decrement_peer_count() - decrement connected TDLS peer counter + * @vdev: vdev obj mgr + * @soc_obj: TDLS soc object + * + * Used in scheduler thread context, no lock needed. + * + * Return: None. + */ +void tdls_decrement_peer_count(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *soc_obj); + +/** + * wlan_tdls_offchan_parms_callback() - Callback to release ref count + * @vdev: vdev object + * + * Return: none + */ +void wlan_tdls_offchan_parms_callback(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_process_set_offchannel() - Handle set offchannel request for TDLS + * @req: TDLS set offchannel request + * + * Return: int status + */ +int tdls_process_set_offchannel(struct tdls_set_offchannel *req); + +/** + * tdls_process_set_offchan_mode() - Handle set offchan mode request for TDLS + * @req: TDLS set offchannel mode request + * + * Return: int status + */ +int tdls_process_set_offchan_mode(struct tdls_set_offchanmode *req); + +/** + * tdls_process_set_secoffchanneloffset() - Handle set sec offchannel + * offset request for TDLS + * @req: TDLS set secoffchannel offchannel request + * + * Return: int status + */ +int tdls_process_set_secoffchanneloffset( + struct tdls_set_secoffchanneloffset *req); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_ct.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_ct.c new file mode 100644 index 0000000000..21e1ab2b04 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_ct.c @@ -0,0 +1,1628 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_ct.c + * + * TDLS connection tracker function definitions + */ + +#include "wlan_tdls_main.h" +#include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" +#include "wlan_tdls_mgmt.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_tdls_cmds_process.h" +#include "wlan_reg_services_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_tdls_tgt_api.h" +#include "wlan_mlo_mgr_link_switch.h" + +bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *peer; + bool is_authenticated = false; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID); + if (!peer) { + tdls_err("peer is null"); + return false; + } + + is_authenticated = wlan_peer_mlme_get_auth_state(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID); + return is_authenticated; +} + +/** + * tdls_peer_reset_discovery_processed() - reset discovery status + * @tdls_vdev: TDLS vdev object + * + * This function resets discovery processing bit for all TDLS peers + * + * Caller has to take the lock before calling this function + * + * Return: 0 + */ +static int32_t tdls_peer_reset_discovery_processed( + struct tdls_vdev_priv_obj *tdls_vdev) +{ + int i; + qdf_list_t *head; + qdf_list_node_t *p_node; + struct tdls_peer *peer; + QDF_STATUS status; + + tdls_vdev->discovery_peer_cnt = 0; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + peer->discovery_processed = 0; + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + + return 0; +} + +void tdls_discovery_timeout_peer_cb(void *user_data) +{ + int i; + qdf_list_t *head; + qdf_list_node_t *p_node; + struct tdls_peer *peer; + QDF_STATUS status; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *select_vdev; + struct wlan_objmgr_vdev *tdls_link_vdev; + struct tdls_rx_mgmt_frame *rx_mgmt; + uint8_t *mac; + bool unforce = true; + + vdev = user_data; + if (!vdev) { + tdls_err("discovery time out vdev is null"); + return; + } + + tdls_soc = wlan_vdev_get_tdls_soc_obj(vdev); + if (!tdls_soc) + return; + + /* timer_cnt is reset when link switch happens */ + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + qdf_atomic_read(&tdls_soc->timer_cnt) == 0) + return; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + qdf_atomic_dec_and_test(&tdls_soc->timer_cnt)) { + tdls_process_mlo_cal_tdls_link_score(vdev); + select_vdev = tdls_process_mlo_choice_tdls_vdev(vdev); + tdls_link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (select_vdev) { + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(select_vdev, + WLAN_UMAC_COMP_TDLS); + rx_mgmt = tdls_vdev->rx_mgmt; + if (tdls_link_vdev && tdls_link_vdev != select_vdev) { + tdls_debug("tdls link created on vdev %d", + wlan_vdev_get_id(tdls_link_vdev)); + } else { + mac = + &rx_mgmt->buf[TDLS_80211_PEER_ADDR_OFFSET]; + tdls_notice("[TDLS] TDLS Discovery Response," + "QDF_MAC_ADDR_FMT RSSI[%d]<---OTA", + rx_mgmt->rx_rssi); + tdls_debug("discovery resp on vdev %d", + wlan_vdev_get_id(tdls_vdev->vdev)); + tdls_recv_discovery_resp(tdls_vdev, mac); + tdls_set_rssi(tdls_vdev->vdev, mac, + rx_mgmt->rx_rssi); + if (tdls_soc && tdls_soc->tdls_rx_cb) + tdls_soc->tdls_rx_cb( + tdls_soc->tdls_rx_cb_data, + rx_mgmt); + } + + qdf_mem_free(tdls_vdev->rx_mgmt); + tdls_vdev->rx_mgmt = NULL; + tdls_vdev->link_score = 0; + + return; + } + + tdls_debug("no discovery response"); + } + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + return; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, + node); + + tdls_debug("Peer: " QDF_MAC_ADDR_FMT " link status %d, vdev id %d", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes), + peer->link_status, wlan_vdev_get_id(vdev)); + + if (peer->link_status != TDLS_LINK_DISCOVERING && + peer->link_status != TDLS_LINK_IDLE) + unforce = false; + + if (TDLS_LINK_DISCOVERING != peer->link_status) { + status = qdf_list_peek_next(head, p_node, + &p_node); + continue; + } + tdls_debug(QDF_MAC_ADDR_FMT " to idle state", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes)); + tdls_set_peer_link_status(peer, + TDLS_LINK_IDLE, + TDLS_LINK_NOT_SUPPORTED); + } + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && unforce) { + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(vdev)); + tdls_set_link_unforce(vdev); + } + + tdls_vdev->discovery_sent_cnt = 0; + /* add tdls power save prohibited */ + + return; +} + +/** + * tdls_reset_tx_rx() - reset tx/rx counters for all tdls peers + * @tdls_vdev: TDLS vdev object + * + * Caller has to take the TDLS lock before calling this function + * + * Return: Void + */ +static void tdls_reset_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev) +{ + int i; + qdf_list_t *head; + qdf_list_node_t *p_node; + struct tdls_peer *peer; + QDF_STATUS status; + struct tdls_soc_priv_obj *tdls_soc; + + tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev); + if (!tdls_soc) + return; + + /* reset stale connection tracker */ + qdf_spin_lock_bh(&tdls_soc->tdls_ct_spinlock); + tdls_vdev->valid_mac_entries = 0; + qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock); + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + peer->tx_pkt = 0; + peer->rx_pkt = 0; + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + return; +} + +void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev) +{ + tdls_debug("Disable Implicit TDLS"); + tdls_timers_stop(tdls_vdev); +} + +/** + * tdls_implicit_enable() - enable implicit tdls triggering + * @tdls_vdev: TDLS vdev + * + * Return: Void + */ +void tdls_implicit_enable(struct tdls_vdev_priv_obj *tdls_vdev) +{ + if (!tdls_vdev) + return; + + tdls_debug("vdev:%d Enable Implicit TDLS", + wlan_vdev_get_id(tdls_vdev->vdev)); + + tdls_peer_reset_discovery_processed(tdls_vdev); + tdls_reset_tx_rx(tdls_vdev); + /* TODO check whether tdls power save prohibited */ + + /* Restart the connection tracker timer */ + tdls_timer_restart(tdls_vdev->vdev, &tdls_vdev->peer_update_timer, + tdls_vdev->threshold_config.tx_period_t); +} + +/** + * tdls_ct_sampling_tx_rx() - collect tx/rx traffic sample + * @tdls_vdev: tdls vdev object + * @tdls_soc: tdls soc object + * + * Function to update data traffic information in tdls connection + * tracker data structure for connection tracker operation + * + * Return: None + */ +static void tdls_ct_sampling_tx_rx(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_soc_priv_obj *tdls_soc) +{ + struct tdls_peer *curr_peer; + uint8_t mac[QDF_MAC_ADDR_SIZE]; + uint8_t mac_cnt; + uint8_t mac_entries; + struct tdls_conn_tracker_mac_table mac_table[WLAN_TDLS_CT_TABLE_SIZE]; + + qdf_spin_lock_bh(&tdls_soc->tdls_ct_spinlock); + + if (0 == tdls_vdev->valid_mac_entries) { + qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock); + return; + } + + mac_entries = QDF_MIN(tdls_vdev->valid_mac_entries, + WLAN_TDLS_CT_TABLE_SIZE); + + qdf_mem_copy(mac_table, tdls_vdev->ct_peer_table, + (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries); + + qdf_mem_zero(tdls_vdev->ct_peer_table, + (sizeof(struct tdls_conn_tracker_mac_table)) * mac_entries); + + tdls_vdev->valid_mac_entries = 0; + + qdf_spin_unlock_bh(&tdls_soc->tdls_ct_spinlock); + + for (mac_cnt = 0; mac_cnt < mac_entries; mac_cnt++) { + qdf_mem_copy(mac, mac_table[mac_cnt].mac_address.bytes, + QDF_MAC_ADDR_SIZE); + curr_peer = tdls_get_peer(tdls_vdev, mac); + if (curr_peer) { + curr_peer->tx_pkt = + mac_table[mac_cnt].tx_packet_cnt; + curr_peer->rx_pkt = + mac_table[mac_cnt].rx_packet_cnt; + } + } +} + +void tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct tdls_conn_tracker_mac_table *mac_table; + struct wlan_objmgr_peer *bss_peer; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj, + &tdls_soc_obj)) + return; + + if (!tdls_soc_obj->enable_tdls_connection_tracker) + return; + + /* Here we do without lock to ensure that in high throughput scenarios + * its fast and we quickly check the right mac entry and increment + * the pkt count. Here it may happen that + * "tdls_vdev_obj->valid_mac_entries", "tdls_vdev_obj->ct_peer_table" + * becomes zero in another thread but we are ok as this will not + * lead to any crash. + */ + valid_mac_entries = tdls_vdev_obj->valid_mac_entries; + mac_table = tdls_vdev_obj->ct_peer_table; + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) { + mac_table[mac_cnt].rx_packet_cnt++; + return; + } + } + + if (qdf_is_macaddr_group(mac_addr)) + return; + + if (qdf_is_macaddr_group(dest_mac_addr)) + return; + + if (!qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr, + QDF_MAC_ADDR_SIZE)) + return; + + bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID); + if (bss_peer) { + if (!qdf_mem_cmp(bss_peer->macaddr, mac_addr, + QDF_MAC_ADDR_SIZE)) { + wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID); + return; + } + wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID); + } + qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock); + + /* when we take the lock we need to get the valid mac entries + * again as it may become zero in another thread and if is 0 then + * we need to reset "mac_cnt" to zero so that at zeroth index we + * add new entry + */ + valid_mac_entries = tdls_vdev_obj->valid_mac_entries; + if (!valid_mac_entries) + mac_cnt = 0; + + /* If we have more than 8 peers within 30 mins. we will + * stop tracking till the old entries are removed + */ + if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) { + qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + tdls_vdev_obj->valid_mac_entries = mac_cnt+1; + mac_table[mac_cnt].rx_packet_cnt = 1; + } + + qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock); + return; +} + +void tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + uint8_t mac_cnt; + uint8_t valid_mac_entries; + struct tdls_conn_tracker_mac_table *mac_table; + struct wlan_objmgr_peer *bss_peer; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj, + &tdls_soc_obj)) + return; + + if (!tdls_soc_obj->enable_tdls_connection_tracker) + return; + + /* Here we do without lock to ensure that in high throughput scenarios + * its fast and we quickly check the right mac entry and increment + * the pkt count. Here it may happen that + * "tdls_vdev_obj->valid_mac_entries", "tdls_vdev_obj->ct_peer_table" + * becomes zero in another thread but we are ok as this will not + * lead to any crash. + */ + mac_table = tdls_vdev_obj->ct_peer_table; + valid_mac_entries = tdls_vdev_obj->valid_mac_entries; + + for (mac_cnt = 0; mac_cnt < valid_mac_entries; mac_cnt++) { + if (qdf_mem_cmp(mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE) == 0) { + mac_table[mac_cnt].tx_packet_cnt++; + return; + } + } + + if (qdf_is_macaddr_group(mac_addr)) + return; + + if (!qdf_mem_cmp(vdev->vdev_mlme.macaddr, mac_addr, + QDF_MAC_ADDR_SIZE)) + return; + bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_NB_ID); + if (bss_peer) { + if (!qdf_mem_cmp(bss_peer->macaddr, mac_addr, + QDF_MAC_ADDR_SIZE)) { + wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID); + return; + } + wlan_objmgr_peer_release_ref(bss_peer, WLAN_TDLS_NB_ID); + } + + qdf_spin_lock_bh(&tdls_soc_obj->tdls_ct_spinlock); + + /* when we take the lock we need to get the valid mac entries + * again as it may become zero in another thread and if is 0 then + * we need to reset "mac_cnt" to zero so that at zeroth index we + * add new entry + */ + valid_mac_entries = tdls_vdev_obj->valid_mac_entries; + if (!valid_mac_entries) + mac_cnt = 0; + + /* If we have more than 8 peers within 30 mins. we will + * stop tracking till the old entries are removed + */ + if (mac_cnt < WLAN_TDLS_CT_TABLE_SIZE) { + qdf_mem_copy(mac_table[mac_cnt].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + mac_table[mac_cnt].tx_packet_cnt = 1; + tdls_vdev_obj->valid_mac_entries++; + } + + qdf_spin_unlock_bh(&tdls_soc_obj->tdls_ct_spinlock); + return; +} + +void +tdls_implicit_send_discovery_request(struct tdls_vdev_priv_obj *tdls_vdev_obj) +{ + struct tdls_peer *curr_peer; + struct tdls_peer *temp_peer; + struct tdls_soc_priv_obj *tdls_psoc; + struct tdls_osif_indication tdls_ind; + + if (!tdls_vdev_obj) { + tdls_notice("tdls_vdev_obj is NULL"); + return; + } + + tdls_psoc = wlan_vdev_get_tdls_soc_obj(tdls_vdev_obj->vdev); + + if (!tdls_psoc) { + tdls_notice("tdls_psoc_obj is NULL"); + return; + } + + if (mlo_mgr_is_link_switch_in_progress(tdls_vdev_obj->vdev)) { + tdls_notice("vdev:%d Link Switch in progress. TDLS discovery not allowed", + wlan_vdev_get_id(tdls_vdev_obj->vdev)); + return; + } + + curr_peer = tdls_vdev_obj->curr_candidate; + + if (!curr_peer) { + tdls_err("curr_peer is NULL"); + return; + } + + /* This function is called in mutex_lock */ + temp_peer = tdls_is_progress(tdls_vdev_obj, NULL, 0); + if (temp_peer) { + tdls_notice(QDF_MAC_ADDR_FMT " ongoing. pre_setup ignored", + QDF_MAC_ADDR_REF(temp_peer->peer_mac.bytes)); + goto done; + } + + if (TDLS_CAP_UNKNOWN != curr_peer->tdls_support) + tdls_set_peer_link_status(curr_peer, + TDLS_LINK_DISCOVERING, + TDLS_LINK_SUCCESS); + + qdf_mem_copy(tdls_ind.peer_mac, curr_peer->peer_mac.bytes, + QDF_MAC_ADDR_SIZE); + + tdls_ind.vdev = tdls_vdev_obj->vdev; + + tdls_debug("Implicit TDLS, Send Discovery request event"); + + tdls_psoc->tdls_event_cb(tdls_psoc->tdls_evt_cb_data, + TDLS_EVENT_DISCOVERY_REQ, &tdls_ind); + + if (!wlan_vdev_mlme_is_mlo_vdev(tdls_vdev_obj->vdev)) { + tdls_vdev_obj->discovery_sent_cnt++; + tdls_timer_restart(tdls_vdev_obj->vdev, + &tdls_vdev_obj->peer_discovery_timer, + tdls_vdev_obj->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE); + + tdls_debug("discovery count %u timeout %u msec", + tdls_vdev_obj->discovery_sent_cnt, + tdls_vdev_obj->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE); + } +done: + tdls_vdev_obj->curr_candidate = NULL; + tdls_vdev_obj->magic = 0; + return; +} + +int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev, + const uint8_t *mac) +{ + struct tdls_peer *curr_peer; + struct tdls_soc_priv_obj *tdls_soc; + struct tdls_osif_indication indication; + struct tdls_config_params *tdls_cfg; + int status = 0; + + if (!tdls_vdev) + return -EINVAL; + + tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev); + if (!tdls_soc) { + tdls_err("tdls soc is NULL"); + return -EINVAL; + } + + curr_peer = tdls_get_peer(tdls_vdev, mac); + if (!curr_peer) { + tdls_err("curr_peer is NULL"); + return -EINVAL; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(tdls_vdev->vdev)) { + if (tdls_vdev->discovery_sent_cnt) + tdls_vdev->discovery_sent_cnt--; + + if (tdls_vdev->discovery_sent_cnt == 0) + qdf_mc_timer_stop(&tdls_vdev->peer_discovery_timer); + } + + tdls_debug("[TDLS] vdev:%d action:%d (%s) sent_count:%u from peer " QDF_MAC_ADDR_FMT + " link_status %d", wlan_vdev_get_id(tdls_vdev->vdev), + TDLS_DISCOVERY_RESPONSE, + "TDLS_DISCOVERY_RESPONSE", + tdls_vdev->discovery_sent_cnt, + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + curr_peer->link_status); + + /* + * Since peer link status bases on vdev and stream goes through + * vdev0 (assoc link) at start, rx/tx pkt count on vdev0, but + * it choices vdev1 as tdls link, the peer status does not change on + * vdev1 though it has been changed for vdev0 per the rx/tx pkt count. + */ + if (wlan_vdev_mlme_is_mlo_vdev(tdls_vdev->vdev) && + curr_peer->link_status == TDLS_LINK_IDLE) + tdls_set_peer_link_status(curr_peer, TDLS_LINK_DISCOVERING, + TDLS_LINK_SUCCESS); + + tdls_cfg = &tdls_vdev->threshold_config; + if (TDLS_LINK_DISCOVERING == curr_peer->link_status) { + /* Since we are here, it means Throughput threshold is + * already met. Make sure RSSI threshold is also met + * before setting up TDLS link. + */ + if ((int32_t) curr_peer->rssi > + (int32_t) tdls_cfg->rssi_trigger_threshold) { + tdls_set_peer_link_status(curr_peer, + TDLS_LINK_DISCOVERED, + TDLS_LINK_SUCCESS); + tdls_debug("Rssi Threshold met: " QDF_MAC_ADDR_FMT + " rssi = %d threshold= %d", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + curr_peer->rssi, + tdls_cfg->rssi_trigger_threshold); + + qdf_mem_copy(indication.peer_mac, mac, + QDF_MAC_ADDR_SIZE); + + indication.vdev = tdls_vdev->vdev; + + tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data, + TDLS_EVENT_SETUP_REQ, + &indication); + } else { + tdls_debug("Rssi Threshold not met: " QDF_MAC_ADDR_FMT + " rssi = %d threshold = %d ", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + curr_peer->rssi, + tdls_cfg->rssi_trigger_threshold); + + tdls_set_peer_link_status(curr_peer, + TDLS_LINK_IDLE, + TDLS_LINK_UNSPECIFIED); + + /* if RSSI threshold is not met then allow + * further discovery attempts by decrementing + * count for the last attempt + */ + if (curr_peer->discovery_attempt) + curr_peer->discovery_attempt--; + } + } + + curr_peer->tdls_support = TDLS_CAP_SUPPORTED; + + return status; +} + +void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_peer *curr_peer, + uint16_t reason) +{ + struct tdls_soc_priv_obj *tdls_soc; + struct tdls_osif_indication indication; + + if (!tdls_vdev || !curr_peer) { + tdls_err("tdls_vdev: %pK, curr_peer: %pK", + tdls_vdev, curr_peer); + return; + } + + tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev); + if (!tdls_soc) { + tdls_err("tdls_soc: %pK", tdls_soc); + return; + } + + if (curr_peer->link_status != TDLS_LINK_CONNECTED) { + tdls_err("link state %d peer:" QDF_MAC_ADDR_FMT, + curr_peer->link_status, + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + return; + } + + tdls_set_peer_link_status(curr_peer, TDLS_LINK_TEARING, + TDLS_LINK_UNSPECIFIED); + tdls_notice("vdev:%d Teardown reason %d peer:" QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(tdls_vdev->vdev), reason, + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + + if (tdls_soc->tdls_dp_vdev_update) + tdls_soc->tdls_dp_vdev_update( + &tdls_soc->soc, + wlan_vdev_get_id(tdls_vdev->vdev), + tdls_soc->tdls_update_dp_vdev_flags, + false); + + indication.reason = reason; + indication.vdev = tdls_vdev->vdev; + qdf_mem_copy(indication.peer_mac, curr_peer->peer_mac.bytes, + QDF_MAC_ADDR_SIZE); + + if (tdls_soc->tdls_event_cb) + tdls_soc->tdls_event_cb(tdls_soc->tdls_evt_cb_data, + TDLS_EVENT_TEARDOWN_REQ, &indication); +} + +/** + * tdls_get_conn_info() - get the tdls connection information. + * @tdls_soc: tdls soc object + * @peer_mac: peer MAC address + * + * Function to check tdls sta index + * + * Return: tdls connection information + */ +static struct tdls_conn_info * +tdls_get_conn_info(struct tdls_soc_priv_obj *tdls_soc, + struct qdf_mac_addr *peer_mac) +{ + uint8_t sta_idx; + /* check if there is available index for this new TDLS STA */ + for (sta_idx = 0; sta_idx < WLAN_TDLS_STA_MAX_NUM; sta_idx++) { + if (!qdf_mem_cmp( + tdls_soc->tdls_conn_info[sta_idx].peer_mac.bytes, + peer_mac->bytes, QDF_MAC_ADDR_SIZE)) { + tdls_debug("tdls peer exists idx %d " QDF_MAC_ADDR_FMT, + sta_idx, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + tdls_soc->tdls_conn_info[sta_idx].index = sta_idx; + return &tdls_soc->tdls_conn_info[sta_idx]; + } + } + + tdls_err("tdls peer does not exists"); + return NULL; +} + +static void +tdls_ct_process_idle_handler(struct wlan_objmgr_vdev *vdev, + struct tdls_conn_info *tdls_info) +{ + struct tdls_peer *curr_peer; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + + if (QDF_STATUS_SUCCESS != tdls_get_vdev_objects(vdev, &tdls_vdev_obj, + &tdls_soc_obj)) + return; + + if (!tdls_info->valid_entry) { + tdls_err("peer doesn't exists"); + return; + } + + curr_peer = tdls_find_peer(tdls_vdev_obj, + (u8 *) &tdls_info->peer_mac.bytes[0]); + + if (!curr_peer) { + tdls_err("Invalid tdls idle timer expired"); + return; + } + + tdls_debug(QDF_MAC_ADDR_FMT + " tx_pkt: %d, rx_pkt: %d, idle_packet_n: %d", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + curr_peer->tx_pkt, + curr_peer->rx_pkt, + tdls_vdev_obj->threshold_config.idle_packet_n); + + /* Check tx/rx statistics on this tdls link for recent activities and + * then decide whether to tear down the link or keep it. + */ + if ((curr_peer->tx_pkt >= + tdls_vdev_obj->threshold_config.idle_packet_n) || + (curr_peer->rx_pkt >= + tdls_vdev_obj->threshold_config.idle_packet_n)) { + /* this tdls link got back to normal, so keep it */ + tdls_debug("tdls link to " QDF_MAC_ADDR_FMT + " back to normal, will stay", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + } else { + /* this tdls link needs to get torn down */ + tdls_notice("trigger tdls link to "QDF_MAC_ADDR_FMT" down", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + tdls_indicate_teardown(tdls_vdev_obj, + curr_peer, + TDLS_TEARDOWN_PEER_UNSPEC_REASON); + } + + return; +} + +void tdls_ct_idle_handler(void *user_data) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_conn_info *tdls_info; + struct tdls_soc_priv_obj *tdls_soc_obj; + uint32_t idx; + + tdls_info = (struct tdls_conn_info *)user_data; + if (!tdls_info) + return; + + idx = tdls_info->index; + if (idx == INVALID_TDLS_PEER_INDEX || idx >= WLAN_TDLS_STA_MAX_NUM) { + tdls_debug("invalid peer index %d" QDF_MAC_ADDR_FMT, idx, + QDF_MAC_ADDR_REF(tdls_info->peer_mac.bytes)); + return; + } + + tdls_soc_obj = qdf_container_of(tdls_info, struct tdls_soc_priv_obj, + tdls_conn_info[idx]); + + vdev = tdls_get_vdev(tdls_soc_obj->soc, WLAN_TDLS_NB_ID); + if (!vdev) { + tdls_err("Unable to fetch the vdev"); + return; + } + + tdls_ct_process_idle_handler(vdev, tdls_info); + wlan_objmgr_vdev_release_ref(vdev, + WLAN_TDLS_NB_ID); +} + +/** + * tdls_ct_process_idle_and_discovery() - process the traffic data + * @curr_peer: tdls peer needs to be examined + * @tdls_vdev_obj: tdls vdev object + * @tdls_soc_obj: tdls soc object + * + * Function to check the peer traffic data in idle link and tdls + * discovering link + * + * Return: None + */ +static void +tdls_ct_process_idle_and_discovery(struct tdls_peer *curr_peer, + struct tdls_vdev_priv_obj *tdls_vdev_obj, + struct tdls_soc_priv_obj *tdls_soc_obj) +{ + uint16_t valid_peers; + + valid_peers = tdls_soc_obj->connected_peer_count; + + if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >= + tdls_vdev_obj->threshold_config.tx_packet_n) { + if (WLAN_TDLS_STA_MAX_NUM > valid_peers) { + tdls_notice("Tput trigger TDLS pre-setup"); + tdls_vdev_obj->curr_candidate = curr_peer; + tdls_implicit_send_discovery_request(tdls_vdev_obj); + } else { + tdls_notice("Maximum peers connected already! %d", + valid_peers); + } + } +} + +/** + * tdls_ct_process_connected_link() - process the traffic + * @curr_peer: tdls peer needs to be examined + * @tdls_vdev: tdls vdev + * @tdls_soc: tdls soc context + * + * Function to check the peer traffic data in active STA + * session + * + * Return: None + */ +static void tdls_ct_process_connected_link( + struct tdls_peer *curr_peer, + struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_soc_priv_obj *tdls_soc) +{ + /* Don't trigger low rssi tear down here since FW will do it */ + /* Only teardown based on non zero idle packet threshold, to address + * a use case where this threshold does not get consider for TEAR DOWN + */ + if ((0 != tdls_vdev->threshold_config.idle_packet_n) && + ((curr_peer->tx_pkt < + tdls_vdev->threshold_config.idle_packet_n) && + (curr_peer->rx_pkt < + tdls_vdev->threshold_config.idle_packet_n))) { + if (!curr_peer->is_peer_idle_timer_initialised) { + struct tdls_conn_info *tdls_info; + tdls_info = tdls_get_conn_info(tdls_soc, + &curr_peer->peer_mac); + qdf_mc_timer_init(&curr_peer->peer_idle_timer, + QDF_TIMER_TYPE_SW, + tdls_ct_idle_handler, + (void *)tdls_info); + curr_peer->is_peer_idle_timer_initialised = true; + } + if (QDF_TIMER_STATE_RUNNING != + curr_peer->peer_idle_timer.state) { + tdls_warn("Tx/Rx Idle timer start: " + QDF_MAC_ADDR_FMT "!", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + tdls_timer_restart(tdls_vdev->vdev, + &curr_peer->peer_idle_timer, + tdls_vdev->threshold_config.idle_timeout_t); + } + } else if (QDF_TIMER_STATE_RUNNING == + curr_peer->peer_idle_timer.state) { + tdls_warn("Tx/Rx Idle timer stop: " QDF_MAC_ADDR_FMT "!", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + } +} + +/** + * tdls_ct_process_cap_supported() - process TDLS supported peer. + * @curr_peer: tdls peer needs to be examined + * @tdls_vdev: tdls vdev context + * @tdls_soc_obj: tdls soc context + * + * Function to check the peer traffic data for tdls supported peer + * + * Return: None + */ +static void +tdls_ct_process_cap_supported(struct tdls_peer *curr_peer, + struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_soc_priv_obj *tdls_soc_obj) +{ + if (curr_peer->rx_pkt || curr_peer->tx_pkt) + tdls_debug(QDF_MAC_ADDR_FMT "link_status %d tdls_support %d tx %d rx %d rssi %d vdev %d", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + curr_peer->link_status, curr_peer->tdls_support, + curr_peer->tx_pkt, curr_peer->rx_pkt, + curr_peer->rssi, wlan_vdev_get_id(tdls_vdev->vdev)); + + switch (curr_peer->link_status) { + case TDLS_LINK_IDLE: + case TDLS_LINK_DISCOVERING: + if (!curr_peer->is_forced_peer && + TDLS_IS_EXTERNAL_CONTROL_ENABLED( + tdls_soc_obj->tdls_configs.tdls_feature_flags)) + break; + + tdls_ct_process_idle_and_discovery(curr_peer, tdls_vdev, + tdls_soc_obj); + break; + case TDLS_LINK_CONNECTED: + tdls_ct_process_connected_link(curr_peer, tdls_vdev, + tdls_soc_obj); + break; + default: + break; + } +} + +/** + * tdls_ct_process_cap_unknown() - process unknown peer + * @curr_peer: tdls peer needs to be examined + * @tdls_vdev: tdls vdev object + * @tdls_soc: tdls soc object + * + * Function check the peer traffic data , when tdls capability is unknown + * + * Return: None + */ +static void tdls_ct_process_cap_unknown(struct tdls_peer *curr_peer, + struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_soc_priv_obj *tdls_soc) +{ + if (!curr_peer->is_forced_peer && + TDLS_IS_EXTERNAL_CONTROL_ENABLED( + tdls_soc->tdls_configs.tdls_feature_flags)) + return; + + if (curr_peer->rx_pkt || curr_peer->tx_pkt) + tdls_debug(QDF_MAC_ADDR_FMT " link_status %d tdls_support %d tx %d rx %d vdev %d", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + curr_peer->link_status, curr_peer->tdls_support, + curr_peer->tx_pkt, curr_peer->rx_pkt, + wlan_vdev_get_id(tdls_vdev->vdev)); + + if (TDLS_IS_LINK_CONNECTED(curr_peer)) + return; + + if ((curr_peer->tx_pkt + curr_peer->rx_pkt) >= + tdls_vdev->threshold_config.tx_packet_n) { + /* + * Ignore discovery attempt if External Control is enabled, that + * is, peer is forced. In that case, continue discovery attempt + * regardless attempt count + */ + tdls_debug("TDLS UNKNOWN pre discover "); + if (curr_peer->is_forced_peer || + curr_peer->discovery_attempt < + tdls_vdev->threshold_config.discovery_tries_n) { + tdls_debug("TDLS UNKNOWN discover num_attempts:%d num_left:%d forced_peer:%d", + curr_peer->discovery_attempt, + tdls_vdev->threshold_config.discovery_tries_n, + curr_peer->is_forced_peer); + tdls_vdev->curr_candidate = curr_peer; + tdls_implicit_send_discovery_request(tdls_vdev); + + return; + } + + if (curr_peer->link_status != TDLS_LINK_CONNECTING) { + curr_peer->tdls_support = TDLS_CAP_NOT_SUPPORTED; + tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE, + TDLS_LINK_NOT_SUPPORTED); + } + } +} + +/** + * tdls_ct_process_peers() - process the peer + * @curr_peer: tdls peer needs to be examined + * @tdls_vdev_obj: tdls vdev object + * @tdls_soc_obj: tdls soc object + * + * This function check the peer capability and process the metadata from + * the peer + * + * Return: None + */ +static void tdls_ct_process_peers(struct tdls_peer *curr_peer, + struct tdls_vdev_priv_obj *tdls_vdev_obj, + struct tdls_soc_priv_obj *tdls_soc_obj) +{ + switch (curr_peer->tdls_support) { + case TDLS_CAP_SUPPORTED: + tdls_ct_process_cap_supported(curr_peer, tdls_vdev_obj, + tdls_soc_obj); + break; + + case TDLS_CAP_UNKNOWN: + tdls_ct_process_cap_unknown(curr_peer, tdls_vdev_obj, + tdls_soc_obj); + break; + default: + break; + } + +} + +static void tdls_ct_process_handler(struct wlan_objmgr_vdev *vdev) +{ + int i; + qdf_list_t *head; + qdf_list_node_t *list_node; + struct tdls_peer *curr_peer; + QDF_STATUS status; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + + status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) + return; + + /* If any concurrency is detected */ + if (!tdls_soc_obj->enable_tdls_connection_tracker) { + tdls_notice("Connection tracker is disabled"); + return; + } + + /* Update tx rx traffic sample in tdls data structures */ + tdls_ct_sampling_tx_rx(tdls_vdev_obj, tdls_soc_obj); + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev_obj->peer_list[i]; + status = qdf_list_peek_front(head, &list_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_peer = qdf_container_of(list_node, + struct tdls_peer, node); + tdls_ct_process_peers(curr_peer, tdls_vdev_obj, + tdls_soc_obj); + curr_peer->tx_pkt = 0; + curr_peer->rx_pkt = 0; + status = qdf_list_peek_next(head, + list_node, &list_node); + } + } + + tdls_timer_restart(tdls_vdev_obj->vdev, + &tdls_vdev_obj->peer_update_timer, + tdls_vdev_obj->threshold_config.tx_period_t); + +} + +void tdls_ct_handler(void *user_data) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *link_vdev; + QDF_STATUS status; + + if (!user_data) + return; + + vdev = (struct wlan_objmgr_vdev *)user_data; + if (!vdev) + return; + + link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (link_vdev) { + status = wlan_objmgr_vdev_try_get_ref(link_vdev, + WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_SUCCESS(status)) { + tdls_ct_process_handler(link_vdev); + wlan_objmgr_vdev_release_ref(link_vdev, + WLAN_TDLS_NB_ID); + } + } else { + tdls_ct_process_handler(vdev); + } +} + +int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc, + int offchannel) +{ + uint32_t tdls_feature_flags; + + tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags; + + if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) && + (TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_current_mode || + TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_current_mode || + TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_current_mode)) { + if (offchannel < TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN || + offchannel > TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX) { + tdls_err("Invalid tdls off channel %u", offchannel); + return -EINVAL; + } + } else { + tdls_err("Either TDLS or TDLS Off-channel is not enabled"); + return -ENOTSUPP; + } + tdls_notice("change tdls off channel from %d to %d", + tdls_soc->tdls_off_channel, offchannel); + tdls_soc->tdls_off_channel = offchannel; + return 0; +} + +int tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj *tdls_soc, + int offchanoffset) +{ + uint32_t tdls_feature_flags; + + tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags; + + if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) || + TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) { + tdls_err("Either TDLS or TDLS Off-channel is not enabled"); + return -ENOTSUPP; + } + + tdls_soc->tdls_channel_offset = BW_INVALID; + + switch (offchanoffset) { + case TDLS_SEC_OFFCHAN_OFFSET_0: + tdls_soc->tdls_channel_offset = BW20; + break; + case TDLS_SEC_OFFCHAN_OFFSET_40PLUS: + tdls_soc->tdls_channel_offset = BW40_HIGH_PRIMARY; + break; + case TDLS_SEC_OFFCHAN_OFFSET_40MINUS: + tdls_soc->tdls_channel_offset = BW40_LOW_PRIMARY; + break; + case TDLS_SEC_OFFCHAN_OFFSET_80: + tdls_soc->tdls_channel_offset = BW80; + break; + case TDLS_SEC_OFFCHAN_OFFSET_160: + tdls_soc->tdls_channel_offset = BWALL; + break; + default: + tdls_err("Invalid tdls secondary off channel offset %d", + offchanoffset); + return -EINVAL; + } /* end switch */ + + tdls_notice("change tdls secondary off channel offset to 0x%x", + tdls_soc->tdls_channel_offset); + return 0; +} + +static inline void +tdls_update_opclass(struct wlan_objmgr_psoc *psoc, + struct tdls_channel_switch_params *params) +{ + params->oper_class = tdls_find_opclass(psoc, params->tdls_off_ch, + params->tdls_off_ch_bw_offset); + if (params->oper_class) + return; + + if (params->tdls_off_ch_bw_offset == BW40_HIGH_PRIMARY) + params->oper_class = tdls_find_opclass(psoc, + params->tdls_off_ch, + BW40_LOW_PRIMARY); + else if (params->tdls_off_ch_bw_offset == BW40_LOW_PRIMARY) + params->oper_class = tdls_find_opclass(psoc, + params->tdls_off_ch, + BW40_HIGH_PRIMARY); +} + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +static inline QDF_STATUS +tdls_update_peer_off_channel_list(struct wlan_objmgr_pdev *pdev, + struct tdls_soc_priv_obj *tdls_soc, + struct wlan_objmgr_vdev *vdev, + struct tdls_peer *peer, + struct tdls_channel_switch_params *params) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + struct tdls_peer_update_state *peer_info; + struct tdls_ch_params *off_channels = params->allowed_off_channels; + uint16_t i; + qdf_freq_t freq, peer_freq; + + if (!wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_TDLS_CONCURRENCIES_SUPPORT)) { + tdls_debug("TDLS Concurrencies FW cap is not supported"); + return QDF_STATUS_SUCCESS; + } + + if (!policy_mgr_get_allowed_tdls_offchannel_freq(psoc, vdev, &freq)) { + tdls_debug("off channel not allowed for current concurrency"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* + * Overwrite the preferred off channel freq in case of concurrency + */ + if (freq) { + params->tdls_off_ch = wlan_reg_freq_to_chan(pdev, freq); + params->tdls_off_chan_freq = freq; + + /* + * tdls_off_ch_bw_offset is already filled in the caller + */ + if (tdls_soc->tdls_off_channel && + tdls_soc->tdls_channel_offset != BW_INVALID) { + tdls_update_opclass(psoc, params); + } else if (peer->off_channel_capable && + peer->pref_off_chan_freq) { + params->oper_class = + tdls_get_opclass_from_bandwidth( + vdev, params->tdls_off_chan_freq, + peer->pref_off_chan_width, + ¶ms->tdls_off_ch_bw_offset); + } + } + + peer_info = qdf_mem_malloc(sizeof(*peer_info)); + if (!peer_info) + return QDF_STATUS_E_NOMEM; + + tdls_extract_peer_state_param(peer_info, peer); + params->num_off_channels = 0; + + /* + * If TDLS concurrency is supported and freq == 0, + * then allow all the 5GHz and 6GHz peer supported frequencies for + * off-channel operation. If particular frequency is provided based on + * concurrency combination then only allow that channel for off-channel. + */ + for (i = 0; i < peer_info->peer_cap.peer_chanlen; i++) { + peer_freq = peer_info->peer_cap.peer_chan[i].ch_freq; + if ((!freq || freq == peer_freq) && + (!wlan_reg_is_24ghz_ch_freq(peer_freq) || + (wlan_reg_is_6ghz_chan_freq(peer_freq) && + tdls_is_6g_freq_allowed(vdev, peer_freq)))) { + off_channels[params->num_off_channels] = + peer_info->peer_cap.peer_chan[i]; + tdls_debug("allowd_chan:%d idx:%d", + off_channels[params->num_off_channels].ch_freq, + params->num_off_channels); + params->num_off_channels++; + } + } + tdls_debug("Num allowed off channels:%d freq:%u", + params->num_off_channels, freq); + qdf_mem_free(peer_info); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +tdls_update_peer_off_channel_list(struct wlan_objmgr_pdev *pdev, + struct tdls_soc_priv_obj *tdls_soc, + struct wlan_objmgr_vdev *vdev, + struct tdls_peer *peer, + struct tdls_channel_switch_params *params) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev, + int offchanmode) +{ + struct tdls_peer *conn_peer = NULL; + struct tdls_channel_switch_params *chan_switch_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int ret_value = 0; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc; + uint32_t tdls_feature_flags; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + + status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc); + + if (status != QDF_STATUS_SUCCESS) + return -EINVAL; + + + if (offchanmode < ENABLE_CHANSWITCH || + offchanmode > DISABLE_ACTIVE_CHANSWITCH) { + tdls_err("Invalid tdls off channel mode %d", offchanmode); + return -EINVAL; + } + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) { + tdls_err("tdls off channel req in not associated state %d", + offchanmode); + return -EPERM; + } + + tdls_feature_flags = tdls_soc->tdls_configs.tdls_feature_flags; + if (!TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) || + TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) { + tdls_err("Either TDLS or TDLS Off-channel is not enabled"); + return -ENOTSUPP; + } + + conn_peer = tdls_find_first_connected_peer(tdls_vdev); + if (!conn_peer) { + tdls_debug("No TDLS Connected Peer"); + return -EPERM; + } + + tdls_notice("TDLS Channel Switch in off_chan_mode=%d tdls_off_channel %d offchanoffset %d", + offchanmode, tdls_soc->tdls_off_channel, + tdls_soc->tdls_channel_offset); + + chan_switch_params = qdf_mem_malloc(sizeof(*chan_switch_params)); + if (!chan_switch_params) + return -ENOMEM; + + switch (offchanmode) { + case ENABLE_CHANSWITCH: + if (tdls_soc->tdls_off_channel && + tdls_soc->tdls_channel_offset != BW_INVALID) { + chan_switch_params->tdls_off_ch = + tdls_soc->tdls_off_channel; + chan_switch_params->tdls_off_ch_bw_offset = + tdls_soc->tdls_channel_offset; + tdls_update_opclass(wlan_pdev_get_psoc(pdev), + chan_switch_params); + } else if (conn_peer->off_channel_capable && + conn_peer->pref_off_chan_freq) { + chan_switch_params->tdls_off_ch = + wlan_reg_freq_to_chan(pdev, + conn_peer->pref_off_chan_freq); + chan_switch_params->oper_class = + tdls_get_opclass_from_bandwidth( + vdev, conn_peer->pref_off_chan_freq, + conn_peer->pref_off_chan_width, + &chan_switch_params->tdls_off_ch_bw_offset); + chan_switch_params->tdls_off_chan_freq = + conn_peer->pref_off_chan_freq; + } else { + tdls_err("TDLS off-channel parameters are not set yet!!!"); + qdf_mem_free(chan_switch_params); + return -EINVAL; + + } + + /* + * Retain the connected peer preferred off-channel frequency + * and opclass that was calculated during update peer caps and + * don't overwrite it based on concurrency in + * tdls_update_peer_off_channel_list(). + */ + conn_peer->pref_off_chan_freq = + wlan_reg_chan_opclass_to_freq( + chan_switch_params->tdls_off_ch, + chan_switch_params->oper_class, false); + conn_peer->op_class_for_pref_off_chan = + chan_switch_params->oper_class; + + /* + * Don't enable TDLS off channel if concurrency is not allowed + */ + status = tdls_update_peer_off_channel_list(pdev, tdls_soc, vdev, + conn_peer, + chan_switch_params); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(chan_switch_params); + return -EINVAL; + } + + break; + case DISABLE_CHANSWITCH: + case DISABLE_ACTIVE_CHANSWITCH: + chan_switch_params->tdls_off_ch = 0; + chan_switch_params->tdls_off_ch_bw_offset = 0; + chan_switch_params->oper_class = 0; + break; + default: + tdls_err("Incorrect Parameters mode: %d tdls_off_channel: %d offchanoffset: %d", + offchanmode, tdls_soc->tdls_off_channel, + tdls_soc->tdls_channel_offset); + qdf_mem_free(chan_switch_params); + return -EINVAL; + } /* end switch */ + + chan_switch_params->vdev_id = tdls_vdev->session_id; + chan_switch_params->tdls_sw_mode = offchanmode; + chan_switch_params->is_responder = conn_peer->is_responder; + qdf_mem_copy(&chan_switch_params->peer_mac_addr, + &conn_peer->peer_mac.bytes, QDF_MAC_ADDR_SIZE); + tdls_notice("Peer " QDF_MAC_ADDR_FMT " vdevId: %d, off channel: %d, offset: %d, num_allowed_off_chan:%d mode: %d, is_responder: %d", + QDF_MAC_ADDR_REF(chan_switch_params->peer_mac_addr), + chan_switch_params->vdev_id, + chan_switch_params->tdls_off_ch, + chan_switch_params->tdls_off_ch_bw_offset, + chan_switch_params->num_off_channels, + chan_switch_params->tdls_sw_mode, + chan_switch_params->is_responder); + + status = tgt_tdls_set_offchan_mode(tdls_soc->soc, chan_switch_params); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(chan_switch_params); + tdls_err("Failed to send channel switch request to wmi"); + return -EINVAL; + } + + tdls_soc->tdls_fw_off_chan_mode = offchanmode; + qdf_mem_free(chan_switch_params); + + return ret_value; +} + +static QDF_STATUS tdls_delete_all_tdls_peers_flush_cb(struct scheduler_msg *msg) +{ + if (msg && msg->bodyptr) { + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + + return QDF_STATUS_SUCCESS; +} +/** + * tdls_delete_all_tdls_peers(): send request to delete tdls peers + * @vdev: vdev object + * @tdls_soc: tdls soc object + * + * This function sends request to lim to delete tdls peers + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *tdls_soc) +{ + struct wlan_objmgr_peer *peer; + struct tdls_del_all_tdls_peers *del_msg; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TDLS_SB_ID); + if (!peer) { + tdls_err("bss peer is null"); + return QDF_STATUS_E_FAILURE; + } + + del_msg = qdf_mem_malloc(sizeof(*del_msg)); + if (!del_msg) { + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(del_msg->bssid.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID); + + del_msg->msg_type = tdls_soc->tdls_del_all_peers; + del_msg->msg_len = (uint16_t) sizeof(*del_msg); + + /* Send the request to PE. */ + qdf_mem_zero(&msg, sizeof(msg)); + + tdls_debug("sending delete all peers req to PE "); + + msg.type = del_msg->msg_type; + msg.bodyptr = del_msg; + msg.flush_callback = tdls_delete_all_tdls_peers_flush_cb; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post delete all peer req failed, status %d", status); + qdf_mem_free(del_msg); + } + + return status; +} + +void tdls_disable_offchan_and_teardown_links( + struct wlan_objmgr_vdev *vdev) +{ + uint16_t connected_tdls_peers = 0; + uint8_t staidx; + struct tdls_peer *curr_peer = NULL; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc; + QDF_STATUS status; + uint8_t vdev_id; + bool tdls_in_progress = false; + bool is_mlo_vdev; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(vdev)); + tdls_set_link_unforce(vdev); + } + + status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc); + if (QDF_STATUS_SUCCESS != status) { + tdls_err("tdls objects are NULL "); + return; + } + + if (TDLS_SUPPORT_SUSPENDED >= tdls_soc->tdls_current_mode) { + tdls_debug("TDLS mode %d is disabled OR not suspended now", + tdls_soc->tdls_current_mode); + return; + } + + connected_tdls_peers = tdls_soc->connected_peer_count; + if (tdls_is_progress(tdls_vdev, NULL, 0)) + tdls_in_progress = true; + + if (!(connected_tdls_peers || tdls_in_progress)) { + vdev_id = vdev->vdev_objmgr.vdev_id; + tdls_debug("No TDLS connected/progress peers to delete Disable tdls for vdev id %d, " + "FW as second interface is coming up", vdev_id); + tdls_send_update_to_fw(tdls_vdev, tdls_soc, true, true, false, + vdev_id); + return; + } + + /* TDLS is not supported in case of concurrency. + * Disable TDLS Offchannel in FW to avoid more + * than two concurrent channels and generate TDLS + * teardown indication to supplicant. + * Below function Finds the first connected peer and + * disables TDLS offchannel for that peer. + * FW enables TDLS offchannel only when there is + * one TDLS peer. When there are more than one TDLS peer, + * there will not be TDLS offchannel in FW. + * So to avoid sending multiple request to FW, for now, + * just invoke offchannel mode functions only once + */ + tdls_set_tdls_offchannel(tdls_soc, + tdls_soc->tdls_configs.tdls_pre_off_chan_num); + tdls_set_tdls_secoffchanneloffset(tdls_soc, + TDLS_SEC_OFFCHAN_OFFSET_40PLUS); + tdls_set_tdls_offchannelmode(vdev, DISABLE_ACTIVE_CHANSWITCH); + + /* Send Msg to PE for deleting all the TDLS peers */ + tdls_delete_all_tdls_peers(vdev, tdls_soc); + + for (staidx = 0; staidx < tdls_soc->max_num_tdls_sta; staidx++) { + if (!tdls_soc->tdls_conn_info[staidx].valid_entry) + continue; + + curr_peer = tdls_find_all_peer(tdls_soc, + tdls_soc->tdls_conn_info[staidx].peer_mac.bytes); + if (!curr_peer) + continue; + + tdls_notice("indicate TDLS teardown "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + + /* Indicate teardown to supplicant */ + tdls_indicate_teardown(tdls_vdev, curr_peer, + TDLS_TEARDOWN_PEER_UNSPEC_REASON); + + tdls_decrement_peer_count(vdev, tdls_soc); + + /* + * Del Sta happened already as part of tdls_delete_all_tdls_peers + * Hence clear tdls vdev data structure. + */ + tdls_reset_peer(tdls_vdev, curr_peer->peer_mac.bytes); + + tdls_soc->tdls_conn_info[staidx].valid_entry = false; + tdls_soc->tdls_conn_info[staidx].session_id = 255; + tdls_soc->tdls_conn_info[staidx].index = + INVALID_TDLS_PEER_INDEX; + + qdf_mem_zero(&tdls_soc->tdls_conn_info[staidx].peer_mac, + sizeof(struct qdf_mac_addr)); + } +} + +void tdls_teardown_connections(struct tdls_link_teardown *tdls_teardown) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct wlan_objmgr_vdev *tdls_vdev; + + /* Get the tdls specific vdev and clear the links */ + tdls_vdev = tdls_get_vdev(tdls_teardown->psoc, WLAN_TDLS_SB_ID); + if (!tdls_vdev) { + tdls_err("Unable get the vdev"); + goto fail_vdev; + } + + tdls_vdev_obj = wlan_vdev_get_tdls_vdev_obj(tdls_vdev); + if (!tdls_vdev_obj) { + tdls_err("vdev priv is NULL"); + goto fail_tdls_vdev; + } + + tdls_debug("tdls teardown connections"); + wlan_vdev_mlme_feat_ext2_cap_clear(tdls_vdev, + WLAN_VDEV_FEXT2_MLO_STA_TDLS); + + tdls_disable_offchan_and_teardown_links(tdls_vdev); + qdf_event_set(&tdls_vdev_obj->tdls_teardown_comp); +fail_tdls_vdev: + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_SB_ID); +fail_vdev: + wlan_objmgr_psoc_release_ref(tdls_teardown->psoc, WLAN_TDLS_SB_ID); + qdf_mem_free(tdls_teardown); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_ct.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_ct.h new file mode 100644 index 0000000000..5adfaf89a2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_ct.h @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_ct.h + * + * TDLS connection tracker declarations + */ + +#ifndef _WLAN_TDLS_CT_H_ +#define _WLAN_TDLS_CT_H_ + + /* + * Before UpdateTimer expires, we want to timeout discovery response + * should not be more than 2000. + */ +#define TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE 1000 + +#define TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN 1 +#define TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX 165 +#define TDLS_PREFERRED_OFF_CHANNEL_NUM_DEFAULT 36 + +/** + * tdls_implicit_enable() - enable implicit tdls triggering + * @tdls_vdev: TDLS vdev + * + * Return: Void + */ +void tdls_implicit_enable(struct tdls_vdev_priv_obj *tdls_vdev); + +/** + * tdls_update_rx_pkt_cnt() - Update rx packet count + * @vdev: vdev object manager + * @mac_addr: mac address of the data + * @dest_mac_addr: dest mac address of the data + * + * Increase the rx packet count, if the sender is not bssid and the packet is + * not broadcast and multicast packet + * + * This sampling information will be used in TDLS connection tracker + * + * This function expected to be called in an atomic context so blocking APIs + * not allowed + * + * Return: None + */ +void tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr); + +/** + * tdls_update_tx_pkt_cnt() - update tx packet + * @vdev: vdev object + * @mac_addr: mac address of the data + * + * Increase the tx packet count, if the sender is not bssid and the packet is + * not broadcast and multicast packet + * + * This sampling information will be used in TDLS connection tracker + * + * This function expected to be called in an atomic context so blocking APIs + * not allowed + * + * Return: None + */ +void tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr); + +/** + * tdls_implicit_send_discovery_request() - send discovery request + * @tdls_vdev_obj: tdls vdev object + * + * Return: None + */ +void tdls_implicit_send_discovery_request( + struct tdls_vdev_priv_obj *tdls_vdev_obj); + +/** + * tdls_recv_discovery_resp() - handling of tdls discovery response + * @tdls_vdev: tdls vdev object + * @mac: mac address of peer from which the response was received + * + * Return: 0 for success or negative errno otherwise + */ +int tdls_recv_discovery_resp(struct tdls_vdev_priv_obj *tdls_vdev, + const uint8_t *mac); + +/** + * tdls_indicate_teardown() - indicate teardown to upper layer + * @tdls_vdev: tdls vdev object + * @curr_peer: teardown peer + * @reason: teardown reason + * + * Return: Void + */ +void tdls_indicate_teardown(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_peer *curr_peer, + uint16_t reason); + +/** + * tdls_ct_handler() - TDLS connection tracker handler + * @user_data: user data from timer + * + * tdls connection tracker timer starts, when the STA connected to AP + * and it's scan the traffic between two STA peers and make TDLS + * connection and teardown, based on the traffic threshold + * + * Return: None + */ +void tdls_ct_handler(void *user_data); + +/** + * tdls_ct_idle_handler() - Check tdls idle traffic + * @user_data: data from tdls idle timer + * + * Function to check the tdls idle traffic and make a decision about + * tdls teardown + * + * Return: None + */ +void tdls_ct_idle_handler(void *user_data); + +/** + * tdls_discovery_timeout_peer_cb() - tdls discovery timeout callback + * @user_data: tdls vdev + * + * Return: None + */ +void tdls_discovery_timeout_peer_cb(void *user_data); + +/** + * tdls_implicit_disable() - disable implicit tdls triggering + * @tdls_vdev: TDLS vdev context + * + * Return: Void + */ +void tdls_implicit_disable(struct tdls_vdev_priv_obj *tdls_vdev); + +/** + * tdls_is_vdev_authenticated() - check the vdev authentication state + * @vdev: vdev object + * + * Return: true or false + */ +bool tdls_is_vdev_authenticated(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_teardown_connections() - teardown and delete all the tdls peers + * @tdls_teardown: tdls teardown struct + * + * Return: true or false + */ +void tdls_teardown_connections(struct tdls_link_teardown *tdls_teardown); + +/** + * tdls_disable_offchan_and_teardown_links - Disable offchannel + * and teardown TDLS links + * @vdev: vdev object + * + * Return: None + */ +void tdls_disable_offchan_and_teardown_links( + struct wlan_objmgr_vdev *vdev); + +/** + * tdls_delete_all_tdls_peers() - send request to delete tdls peers + * @vdev: vdev object + * @tdls_soc: tdls soc object + * + * This function sends request to lim to delete tdls peers + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *tdls_soc); + +/** + * tdls_set_tdls_offchannel() - set tdls off-channel number + * @tdls_soc: tdls soc object + * @offchannel: tdls off-channel number + * + * This function sets tdls off-channel number + * + * Return: 0 on success; negative errno otherwise + */ +int tdls_set_tdls_offchannel(struct tdls_soc_priv_obj *tdls_soc, + int offchannel); + +/** + * tdls_set_tdls_offchannelmode() - set tdls off-channel mode + * @vdev: vdev object + * @offchanmode: tdls off-channel mode + * + * This function sets tdls off-channel mode + * + * Return: 0 on success; negative errno otherwise + */ + +int tdls_set_tdls_offchannelmode(struct wlan_objmgr_vdev *vdev, + int offchanmode); + +/** + * tdls_set_tdls_secoffchanneloffset() - set secondary tdls off-channel offset + * @tdls_soc: tdls soc object + * @offchanoffset: tdls off-channel offset + * + * This function sets secondary tdls off-channel offset + * + * Return: 0 on success; negative errno otherwise + */ + +int tdls_set_tdls_secoffchanneloffset(struct tdls_soc_priv_obj *tdls_soc, + int offchanoffset); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_main.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_main.c new file mode 100644 index 0000000000..b457422cb4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_main.c @@ -0,0 +1,2335 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_main.c + * + * TDLS core function definitions + */ + +#include "wlan_tdls_main.h" +#include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" +#include "wlan_tdls_mgmt.h" +#include "wlan_tdls_api.h" +#include "wlan_tdls_tgt_api.h" +#include "wlan_policy_mgr_public_struct.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_scan_ucfg_api.h" +#include "wlan_tdls_ucfg_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_cfg80211_tdls.h" +#include "wlan_nan_api_i.h" +#include "wlan_mlme_vdev_mgr_interface.h" + +/* Global tdls soc pvt object + * this is useful for some functions which does not receive either vdev or psoc + * objects. + */ +static struct tdls_soc_priv_obj *tdls_soc_global; + +#ifdef WLAN_DEBUG +/** + * tdls_get_cmd_type_str() - parse cmd to string + * @cmd_type: tdls cmd type + * + * This function parse tdls cmd to string. + * + * Return: command string + */ +static char *tdls_get_cmd_type_str(enum tdls_command_type cmd_type) +{ + switch (cmd_type) { + CASE_RETURN_STRING(TDLS_CMD_TX_ACTION); + CASE_RETURN_STRING(TDLS_CMD_ADD_STA); + CASE_RETURN_STRING(TDLS_CMD_CHANGE_STA); + CASE_RETURN_STRING(TDLS_CMD_ENABLE_LINK); + CASE_RETURN_STRING(TDLS_CMD_DISABLE_LINK); + CASE_RETURN_STRING(TDLS_CMD_CONFIG_FORCE_PEER); + CASE_RETURN_STRING(TDLS_CMD_REMOVE_FORCE_PEER); + CASE_RETURN_STRING(TDLS_CMD_STATS_UPDATE); + CASE_RETURN_STRING(TDLS_CMD_CONFIG_UPDATE); + CASE_RETURN_STRING(TDLS_CMD_SCAN_DONE); + CASE_RETURN_STRING(TDLS_CMD_SET_RESPONDER); + CASE_RETURN_STRING(TDLS_NOTIFY_STA_CONNECTION); + CASE_RETURN_STRING(TDLS_NOTIFY_STA_DISCONNECTION); + CASE_RETURN_STRING(TDLS_CMD_SET_TDLS_MODE); + CASE_RETURN_STRING(TDLS_CMD_SESSION_INCREMENT); + CASE_RETURN_STRING(TDLS_CMD_SESSION_DECREMENT); + CASE_RETURN_STRING(TDLS_CMD_TEARDOWN_LINKS); + CASE_RETURN_STRING(TDLS_NOTIFY_RESET_ADAPTERS); + CASE_RETURN_STRING(TDLS_CMD_ANTENNA_SWITCH); + CASE_RETURN_STRING(TDLS_CMD_SET_OFFCHANMODE); + CASE_RETURN_STRING(TDLS_CMD_SET_OFFCHANNEL); + CASE_RETURN_STRING(TDLS_CMD_SET_SECOFFCHANOFFSET); + CASE_RETURN_STRING(TDLS_DELETE_ALL_PEERS_INDICATION); + CASE_RETURN_STRING(TDLS_CMD_START_BSS); + CASE_RETURN_STRING(TDLS_CMD_SET_LINK_UNFORCE); + default: + return "Invalid TDLS command"; + } +} + +/** + * tdls_get_event_type_str() - parase event to string + * @event_type: tdls event type + * + * This function parse tdls event to string. + * + * Return: event string + */ +static char *tdls_get_event_type_str(enum tdls_event_type event_type) +{ + switch (event_type) { + case TDLS_SHOULD_DISCOVER: + return "TDLS_SHOULD_DISCOVER"; + case TDLS_SHOULD_TEARDOWN: + return "TDLS_SHOULD_TEARDOWN"; + case TDLS_PEER_DISCONNECTED: + return "TDLS_PEER_DISCONNECTED"; + case TDLS_CONNECTION_TRACKER_NOTIFY: + return "TDLS_CONNECTION_TRACKER_NOTIFY"; + + default: + return "Invalid TDLS event"; + } +} +#else +static char *tdls_get_cmd_type_str(enum tdls_command_type cmd_type) +{ + return ""; +} + +static char *tdls_get_event_type_str(enum tdls_event_type event_type) +{ + return ""; +} +#endif + +QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *tdls_soc_obj; + + tdls_soc_obj = qdf_mem_malloc(sizeof(*tdls_soc_obj)); + if (!tdls_soc_obj) + return QDF_STATUS_E_NOMEM; + + tdls_soc_obj->soc = psoc; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_TDLS, + (void *)tdls_soc_obj, + QDF_STATUS_SUCCESS); + + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to attach psoc tdls component"); + qdf_mem_free(tdls_soc_obj); + return status; + } + + tdls_soc_global = tdls_soc_obj; + tdls_notice("TDLS obj attach to psoc successfully"); + + return status; +} + +QDF_STATUS tdls_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *tdls_soc_obj; + + tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!tdls_soc_obj) { + tdls_err("Failed to get tdls obj in psoc"); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_TDLS, + tdls_soc_obj); + + if (QDF_IS_STATUS_ERROR(status)) + tdls_err("Failed to detach psoc tdls component"); + qdf_mem_free(tdls_soc_obj); + + return status; +} + +static QDF_STATUS tdls_vdev_init(struct tdls_vdev_priv_obj *vdev_obj) +{ + uint8_t i; + struct tdls_config_params *config; + struct tdls_user_config *user_config; + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + if (!soc_obj) { + tdls_err("tdls soc obj NULL"); + return QDF_STATUS_E_FAILURE; + } + + config = &vdev_obj->threshold_config; + user_config = &soc_obj->tdls_configs; + config->tx_period_t = user_config->tdls_tx_states_period; + config->tx_packet_n = user_config->tdls_tx_pkt_threshold; + config->discovery_tries_n = user_config->tdls_max_discovery_attempt; + config->idle_timeout_t = user_config->tdls_idle_timeout; + config->idle_packet_n = user_config->tdls_idle_pkt_threshold; + config->rssi_trigger_threshold = + user_config->tdls_rssi_trigger_threshold; + config->rssi_teardown_threshold = + user_config->tdls_rssi_teardown_threshold; + config->rssi_delta = user_config->tdls_rssi_delta; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + qdf_list_create(&vdev_obj->peer_list[i], + WLAN_TDLS_PEER_SUB_LIST_SIZE); + } + qdf_mc_timer_init(&vdev_obj->peer_update_timer, QDF_TIMER_TYPE_SW, + tdls_ct_handler, vdev_obj->vdev); + qdf_mc_timer_init(&vdev_obj->peer_discovery_timer, QDF_TIMER_TYPE_SW, + tdls_discovery_timeout_peer_cb, vdev_obj->vdev); + + return QDF_STATUS_SUCCESS; +} + +static void tdls_vdev_deinit(struct tdls_vdev_priv_obj *vdev_obj) +{ + qdf_mc_timer_stop_sync(&vdev_obj->peer_update_timer); + qdf_mc_timer_stop_sync(&vdev_obj->peer_discovery_timer); + + qdf_mc_timer_destroy(&vdev_obj->peer_update_timer); + qdf_mc_timer_destroy(&vdev_obj->peer_discovery_timer); + + tdls_peer_idle_timers_destroy(vdev_obj); + tdls_free_peer_list(vdev_obj); +} + +QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, + void *arg) +{ + QDF_STATUS status; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct wlan_objmgr_pdev *pdev; + struct tdls_soc_priv_obj *tdls_soc_obj; + uint32_t tdls_feature_flags; + + tdls_debug("tdls vdev mode %d", wlan_vdev_mlme_get_opmode(vdev)); + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE && + wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_SUCCESS; + + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!tdls_soc_obj) { + tdls_err("get soc by vdev failed"); + return QDF_STATUS_E_NOMEM; + } + + tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags; + if (!TDLS_IS_ENABLED(tdls_feature_flags)) { + tdls_debug("disabled in ini"); + return QDF_STATUS_E_NOSUPPORT; + } + + if (tdls_soc_obj->tdls_osif_init_cb) { + status = tdls_soc_obj->tdls_osif_init_cb(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + } + + /* TODO: Add concurrency check */ + + tdls_vdev_obj = qdf_mem_malloc(sizeof(*tdls_vdev_obj)); + if (!tdls_vdev_obj) { + status = QDF_STATUS_E_NOMEM; + goto err_attach; + } + + status = wlan_objmgr_vdev_component_obj_attach(vdev, + WLAN_UMAC_COMP_TDLS, + (void *)tdls_vdev_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to attach vdev tdls component"); + goto err_attach; + } + tdls_vdev_obj->vdev = vdev; + status = tdls_vdev_init(tdls_vdev_obj); + if (QDF_IS_STATUS_ERROR(status)) + goto err_vdev_init; + + status = qdf_event_create(&tdls_vdev_obj->tdls_teardown_comp); + if (QDF_IS_STATUS_ERROR(status)) + goto err_event_create; + + pdev = wlan_vdev_get_pdev(vdev); + + status = ucfg_scan_register_event_handler(pdev, + tdls_scan_complete_event_handler, + tdls_soc_obj); + + if (QDF_STATUS_SUCCESS != status) { + tdls_err("scan event register failed "); + goto err_register; + } + + tdls_debug("tdls object attach to vdev successfully"); + return status; + +err_register: + qdf_event_destroy(&tdls_vdev_obj->tdls_teardown_comp); +err_event_create: + tdls_vdev_deinit(tdls_vdev_obj); +err_vdev_init: + wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_TDLS, + (void *)tdls_vdev_obj); +err_attach: + if (tdls_soc_obj->tdls_osif_deinit_cb) + tdls_soc_obj->tdls_osif_deinit_cb(vdev); + if (tdls_vdev_obj) { + qdf_mem_free(tdls_vdev_obj); + tdls_vdev_obj = NULL; + } + + return status; +} + +QDF_STATUS tdls_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, + void *arg) +{ + QDF_STATUS status; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + uint32_t tdls_feature_flags; + + tdls_debug("tdls vdev mode %d", wlan_vdev_mlme_get_opmode(vdev)); + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE && + wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_SUCCESS; + + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!tdls_soc_obj) { + tdls_err("get soc by vdev failed"); + return QDF_STATUS_E_NOMEM; + } + + tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags; + if (!TDLS_IS_ENABLED(tdls_feature_flags)) { + tdls_debug("disabled in ini"); + return QDF_STATUS_E_NOSUPPORT; + } + + tdls_vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + if (!tdls_vdev_obj) { + tdls_err("Failed to get tdls vdev object"); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state( + &tdls_vdev_obj->peer_discovery_timer)) + qdf_mc_timer_stop(&tdls_vdev_obj->peer_discovery_timer); + } + + qdf_event_destroy(&tdls_vdev_obj->tdls_teardown_comp); + tdls_vdev_deinit(tdls_vdev_obj); + + status = wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_TDLS, + tdls_vdev_obj); + if (QDF_IS_STATUS_ERROR(status)) + tdls_err("Failed to detach vdev tdls component"); + + if (tdls_soc_obj->tdls_osif_deinit_cb) + tdls_soc_obj->tdls_osif_deinit_cb(vdev); + qdf_mem_free(tdls_vdev_obj); + + return status; +} + +/** + * __tdls_get_all_peers_from_list() - get all the tdls peers from the list + * @get_tdls_peers: get_tdls_peers object + * + * Return: int + */ +static int __tdls_get_all_peers_from_list( + struct tdls_get_all_peers *get_tdls_peers) +{ + int i; + int len, init_len; + qdf_list_t *head; + qdf_list_node_t *p_node; + struct tdls_peer *curr_peer; + char *buf; + int buf_len; + struct tdls_vdev_priv_obj *tdls_vdev; + QDF_STATUS status; + + tdls_notice("Enter "); + + buf = get_tdls_peers->buf; + buf_len = get_tdls_peers->buf_len; + + if (wlan_vdev_is_up(get_tdls_peers->vdev) != QDF_STATUS_SUCCESS) { + len = qdf_scnprintf(buf, buf_len, + "\nSTA is not associated\n"); + return len; + } + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(get_tdls_peers->vdev); + + if (!tdls_vdev) { + len = qdf_scnprintf(buf, buf_len, "TDLS not enabled\n"); + return len; + } + + init_len = buf_len; + len = qdf_scnprintf(buf, buf_len, + "\n%-18s%-3s%-4s%-3s%-5s\n", + "MAC", "Id", "cap", "up", "RSSI"); + buf += len; + buf_len -= len; + len = qdf_scnprintf(buf, buf_len, + "---------------------------------\n"); + buf += len; + buf_len -= len; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_peer = qdf_container_of(p_node, + struct tdls_peer, node); + if (buf_len < 32 + 1) + break; + len = qdf_scnprintf(buf, buf_len, + QDF_MAC_ADDR_FMT "%4s%3s%5d\n", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes), + (curr_peer->tdls_support == + TDLS_CAP_SUPPORTED) ? "Y" : "N", + TDLS_IS_LINK_CONNECTED(curr_peer) ? "Y" : + "N", curr_peer->rssi); + buf += len; + buf_len -= len; + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + + tdls_notice("Exit "); + return init_len - buf_len; +} + +/** + * tdls_get_all_peers_from_list() - get all the tdls peers from the list + * @get_tdls_peers: get_tdls_peers object + * + * Return: None + */ +static void tdls_get_all_peers_from_list( + struct tdls_get_all_peers *get_tdls_peers) +{ + int32_t len; + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_osif_indication indication; + + if (!get_tdls_peers->vdev) { + qdf_mem_free(get_tdls_peers); + return; + } + len = __tdls_get_all_peers_from_list(get_tdls_peers); + + indication.status = len; + indication.vdev = get_tdls_peers->vdev; + + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(get_tdls_peers->vdev); + if (tdls_soc_obj && tdls_soc_obj->tdls_event_cb) + tdls_soc_obj->tdls_event_cb(tdls_soc_obj->tdls_evt_cb_data, + TDLS_EVENT_USER_CMD, &indication); + + qdf_mem_free(get_tdls_peers); +} + +/** + * tdls_process_reset_all_peers() - Reset all tdls peers + * @vdev: vdev object + * + * This function is called to reset all tdls peers and + * notify upper layers of teardown inidcation + * + * Return: QDF_STATUS + */ + +static QDF_STATUS tdls_process_reset_all_peers(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t staidx; + struct tdls_peer *curr_peer = NULL; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_soc_priv_obj *tdls_soc; + uint8_t reset_session_id; + + status = tdls_get_vdev_objects(vdev, &tdls_vdev, &tdls_soc); + if (QDF_STATUS_SUCCESS != status) { + tdls_err("tdls objects are NULL "); + return status; + } + + reset_session_id = tdls_vdev->session_id; + for (staidx = 0; staidx < tdls_soc->max_num_tdls_sta; + staidx++) { + if (!tdls_soc->tdls_conn_info[staidx].valid_entry) + continue; + if (tdls_soc->tdls_conn_info[staidx].session_id != + reset_session_id) + continue; + + curr_peer = + tdls_find_all_peer(tdls_soc, + tdls_soc->tdls_conn_info[staidx]. + peer_mac.bytes); + if (!curr_peer) + continue; + + tdls_notice("indicate TDLS teardown "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + + /* Indicate teardown to supplicant */ + tdls_indicate_teardown(tdls_vdev, + curr_peer, + TDLS_TEARDOWN_PEER_UNSPEC_REASON); + + tdls_reset_peer(tdls_vdev, curr_peer->peer_mac.bytes); + + tdls_decrement_peer_count(vdev, tdls_soc); + tdls_soc->tdls_conn_info[staidx].valid_entry = false; + tdls_soc->tdls_conn_info[staidx].session_id = 255; + tdls_soc->tdls_conn_info[staidx].index = + INVALID_TDLS_PEER_INDEX; + + qdf_mem_zero(&tdls_soc->tdls_conn_info[staidx].peer_mac, + sizeof(struct qdf_mac_addr)); + } + return status; +} + +/** + * tdls_reset_all_peers() - Reset all tdls peers + * @delete_all_peers_ind: Delete all peers indication + * + * This function is called to reset all tdls peers and + * notify upper layers of teardown inidcation + * + * Return: QDF_STATUS + */ +static QDF_STATUS tdls_reset_all_peers( + struct tdls_delete_all_peers_params *delete_all_peers_ind) +{ + QDF_STATUS status; + + if (!delete_all_peers_ind || !delete_all_peers_ind->vdev) { + tdls_err("invalid param"); + qdf_mem_free(delete_all_peers_ind); + return QDF_STATUS_E_INVAL; + } + + status = tdls_process_reset_all_peers(delete_all_peers_ind->vdev); + + wlan_objmgr_vdev_release_ref(delete_all_peers_ind->vdev, + WLAN_TDLS_SB_ID); + qdf_mem_free(delete_all_peers_ind); + + return status; +} + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +QDF_STATUS tdls_handle_start_bss(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_vdev *tdls_vdev; + + tdls_vdev = tdls_get_vdev(psoc, WLAN_TDLS_NB_ID); + if (!tdls_vdev) { + tdls_err("Unable get the tdls vdev"); + return QDF_STATUS_E_FAILURE; + } + + tdls_set_tdls_offchannelmode(tdls_vdev, DISABLE_ACTIVE_CHANSWITCH); + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + + return QDF_STATUS_SUCCESS; +} +#endif + +static void tdls_handle_link_unforce(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_action_frame_request req = {0}; + + req.vdev = vdev; + req.tdls_mgmt.frame_type = TDLS_MAX_ACTION_CODE; + + tdls_debug("set vdev %d unforce", wlan_vdev_get_id(vdev)); + tdls_set_link_mode(&req); +} + +QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!msg || !msg->bodyptr) { + tdls_err("msg %s is NULL", !msg ? "" : "body ptr"); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_debug(" %s(%d)", tdls_get_cmd_type_str(msg->type), msg->type); + + switch (msg->type) { + case TDLS_CMD_TX_ACTION: + tdls_process_mgmt_req(msg->bodyptr); + break; + case TDLS_CMD_ADD_STA: + tdls_process_add_peer(msg->bodyptr); + break; + case TDLS_CMD_CHANGE_STA: + tdls_process_update_peer(msg->bodyptr); + break; + case TDLS_CMD_ENABLE_LINK: + tdls_process_enable_link(msg->bodyptr); + break; + case TDLS_CMD_DISABLE_LINK: + tdls_process_del_peer(msg->bodyptr); + break; + case TDLS_CMD_CONFIG_FORCE_PEER: + tdls_process_setup_peer(msg->bodyptr); + break; + case TDLS_CMD_REMOVE_FORCE_PEER: + tdls_process_remove_force_peer(msg->bodyptr); + break; + case TDLS_CMD_STATS_UPDATE: + break; + case TDLS_CMD_CONFIG_UPDATE: + break; + case TDLS_CMD_SET_RESPONDER: + tdls_set_responder(msg->bodyptr); + break; + case TDLS_CMD_SCAN_DONE: + tdls_scan_done_callback(msg->bodyptr); + break; + case TDLS_NOTIFY_STA_CONNECTION: + tdls_notify_sta_connect(msg->bodyptr); + break; + case TDLS_NOTIFY_STA_DISCONNECTION: + tdls_notify_sta_disconnect(msg->bodyptr); + break; + case TDLS_CMD_SET_TDLS_MODE: + tdls_set_operation_mode(msg->bodyptr); + break; + case TDLS_CMD_SESSION_DECREMENT: + tdls_process_decrement_active_session(msg->bodyptr); + break; + case TDLS_CMD_SESSION_INCREMENT: + tdls_process_policy_mgr_notification(msg->bodyptr); + break; + case TDLS_CMD_TEARDOWN_LINKS: + tdls_teardown_connections(msg->bodyptr); + break; + case TDLS_NOTIFY_RESET_ADAPTERS: + tdls_notify_reset_adapter(msg->bodyptr); + break; + case TDLS_CMD_ANTENNA_SWITCH: + tdls_process_antenna_switch(msg->bodyptr); + break; + case TDLS_CMD_GET_ALL_PEERS: + tdls_get_all_peers_from_list(msg->bodyptr); + break; + case TDLS_CMD_SET_OFFCHANNEL: + tdls_process_set_offchannel(msg->bodyptr); + break; + case TDLS_CMD_SET_OFFCHANMODE: + tdls_process_set_offchan_mode(msg->bodyptr); + break; + case TDLS_CMD_SET_SECOFFCHANOFFSET: + tdls_process_set_secoffchanneloffset(msg->bodyptr); + break; + case TDLS_DELETE_ALL_PEERS_INDICATION: + tdls_reset_all_peers(msg->bodyptr); + break; + case TDLS_CMD_START_BSS: + tdls_handle_start_bss(msg->bodyptr); + break; + case TDLS_CMD_SET_LINK_UNFORCE: + tdls_handle_link_unforce(msg->bodyptr); + break; + default: + break; + } + + return status; +} + +QDF_STATUS tdls_process_evt(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_event_notify *notify; + struct tdls_event_info *event; + + if (!msg || !msg->bodyptr) { + tdls_err("msg is not valid: %pK", msg); + return QDF_STATUS_E_NULL_VALUE; + } + notify = msg->bodyptr; + vdev = notify->vdev; + if (!vdev) { + tdls_err("NULL vdev object"); + qdf_mem_free(notify); + return QDF_STATUS_E_NULL_VALUE; + } + event = ¬ify->event; + + tdls_debug(" %s(%d)", tdls_get_event_type_str(event->message_type), + event->message_type); + + switch (event->message_type) { + case TDLS_SHOULD_DISCOVER: + tdls_process_should_discover(vdev, event); + break; + case TDLS_SHOULD_TEARDOWN: + case TDLS_PEER_DISCONNECTED: + tdls_process_should_teardown(vdev, event); + break; + case TDLS_CONNECTION_TRACKER_NOTIFY: + tdls_process_connection_tracker_notify(vdev, event); + break; + default: + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + qdf_mem_free(notify); + + return QDF_STATUS_SUCCESS; +} + +void tdls_timer_restart(struct wlan_objmgr_vdev *vdev, + qdf_mc_timer_t *timer, uint32_t expiration_time) +{ + if (!wlan_cm_is_vdev_connected(vdev)) { + tdls_debug("vdev:%d is not connected. Can't restart timer", + wlan_vdev_get_id(vdev)); + return; + } + + if (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state(timer)) + qdf_mc_timer_start(timer, expiration_time); +} + +/** + * tdls_monitor_timers_stop() - stop all monitoring timers + * @tdls_vdev: TDLS vdev object + * + * Return: none + */ +static void tdls_monitor_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev) +{ + if (!wlan_vdev_mlme_is_mlo_vdev(tdls_vdev->vdev)) + qdf_mc_timer_stop_sync(&tdls_vdev->peer_discovery_timer); +} + +/** + * tdls_peer_idle_timers_stop() - stop peer idle timers + * @tdls_vdev: TDLS vdev object + * + * Loop through the idle peer list and stop their timers + * + * Return: None + */ +static void tdls_peer_idle_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev) +{ + int i; + qdf_list_t *head; + qdf_list_node_t *p_node; + struct tdls_peer *curr_peer; + QDF_STATUS status; + + tdls_vdev->discovery_peer_cnt = 0; + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_peer = qdf_container_of(p_node, struct tdls_peer, + node); + if (curr_peer->is_peer_idle_timer_initialised) + qdf_mc_timer_stop_sync(&curr_peer->peer_idle_timer); + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + +} + +/** + * tdls_ct_timers_stop() - stop tdls connection tracker timers + * @tdls_vdev: TDLS vdev + * + * Return: None + */ +static void tdls_ct_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev) +{ + qdf_mc_timer_stop_sync(&tdls_vdev->peer_update_timer); + + tdls_peer_idle_timers_stop(tdls_vdev); +} + +/** + * tdls_timers_stop() - stop all the tdls timers running + * @tdls_vdev: TDLS vdev + * + * Return: none + */ +void tdls_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev) +{ + tdls_debug("Stop TDLS timers"); + tdls_monitor_timers_stop(tdls_vdev); + tdls_ct_timers_stop(tdls_vdev); +} + +QDF_STATUS tdls_get_vdev_objects(struct wlan_objmgr_vdev *vdev, + struct tdls_vdev_priv_obj **tdls_vdev_obj, + struct tdls_soc_priv_obj **tdls_soc_obj) +{ + enum QDF_OPMODE device_mode; + + if (!vdev) + return QDF_STATUS_E_FAILURE; + + *tdls_vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + if (NULL == (*tdls_vdev_obj)) + return QDF_STATUS_E_FAILURE; + + *tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (NULL == (*tdls_soc_obj)) + return QDF_STATUS_E_FAILURE; + + device_mode = wlan_vdev_mlme_get_opmode(vdev); + + if (device_mode != QDF_STA_MODE && + device_mode != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11AX +uint32_t tdls_get_6g_pwr_for_power_type(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq, + enum supported_6g_pwr_types pwr_typ) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct regulatory_channel *chan; + uint8_t chn_idx, num_chan; + uint8_t band_mask = BIT(REG_BAND_6G); + uint32_t tx_power = 0; + + if (!pdev) + return 0; + + /* No power check is required for non 6 Ghz channel */ + if (!wlan_reg_is_6ghz_chan_freq(freq)) + return 0; + + chan = qdf_mem_malloc(sizeof(struct regulatory_channel) * NUM_CHANNELS); + if (!chan) + return 0; + + num_chan = wlan_reg_get_band_channel_list_for_pwrmode(pdev, + band_mask, + chan, + REG_CLI_DEF_VLP); + + for (chn_idx = 0; chn_idx < num_chan; chn_idx++) { + if (chan[chn_idx].center_freq == freq) { + tdls_debug("VLP power for channel %d is %d", + chan[chn_idx].center_freq, + chan[chn_idx].tx_power); + tx_power = chan[chn_idx].tx_power; + } + } + + qdf_mem_free(chan); + return tx_power; +} + +bool tdls_is_6g_freq_allowed(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct regulatory_channel *chan; + bool is_allowed = false; + uint8_t country_code[REG_ALPHA2_LEN + 1]; + uint8_t chn_idx, num_chan = 0; + uint8_t band_mask = BIT(REG_BAND_6G); + + /* Return if freq is not 6 Ghz freq */ + if (!wlan_reg_is_6ghz_chan_freq(freq)) + return false; + + if (!wlan_cfg80211_tdls_is_fw_6ghz_capable(vdev)) + return false; + + if (!pdev) + return false; + + wlan_cm_get_country_code(pdev, wlan_vdev_get_id(vdev), country_code); + if (!wlan_reg_ctry_support_vlp(country_code)) + return false; + + chan = qdf_mem_malloc(sizeof(struct regulatory_channel) * NUM_CHANNELS); + if (!chan) + return false; + + num_chan = wlan_reg_get_band_channel_list_for_pwrmode(pdev, + band_mask, + chan, + REG_CLI_DEF_VLP); + tdls_debug("Country IE:%c%c freq %d num_chan %d", country_code[0], + country_code[1], freq, num_chan); + if (!num_chan) + goto error; + + for (chn_idx = 0; chn_idx < num_chan; chn_idx++) { + if (chan[chn_idx].center_freq == freq) { + tdls_debug("TDLS 6ghz freq: %d supports VLP power", + chan[chn_idx].center_freq); + is_allowed = true; + break; + } + } + +error: + qdf_mem_free(chan); + return is_allowed; +} +#else +bool tdls_is_6g_freq_allowed(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + return false; +} + +uint32_t tdls_get_6g_pwr_for_power_type(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq, + enum supported_6g_pwr_types pwr_typ) +{ + return 0; +} +#endif + +bool tdls_check_is_user_tdls_enable(struct tdls_soc_priv_obj *tdls_soc_obj) +{ + return tdls_soc_obj->is_user_tdls_enable; +} + +bool tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + bool state = false; + qdf_freq_t ch_freq; + QDF_STATUS status; + uint32_t connection_count; + uint8_t sta_count, p2p_cli_count; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) + return state; + + status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to get TDLS objects"); + goto exit; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + !wlan_tdls_is_fw_11be_mlo_capable(tdls_soc_obj->soc)) { + tdls_debug("TDLS not supported on MLO vdev"); + goto exit; + } + + if (wlan_nan_is_disc_active(tdls_soc_obj->soc)) { + tdls_err("NAN active. NAN+TDLS not supported"); + goto exit; + } + + if (!tdls_check_is_user_tdls_enable(tdls_soc_obj)) { + tdls_err("TDLS Disabled from userspace"); + goto exit; + } + + connection_count = + policy_mgr_get_connection_count_with_mlo(tdls_soc_obj->soc); + sta_count = + policy_mgr_mode_specific_connection_count(tdls_soc_obj->soc, + PM_STA_MODE, NULL); + p2p_cli_count = + policy_mgr_mode_specific_connection_count(tdls_soc_obj->soc, + PM_P2P_CLIENT_MODE, + NULL); + if ((connection_count == 1 && (sta_count || p2p_cli_count)) || + (connection_count > 1 && + tdls_is_concurrency_allowed(tdls_soc_obj->soc))) { + state = true; + } else { + tdls_warn("vdev:%d Concurrent sessions exist disable TDLS", + wlan_vdev_get_id(vdev)); + state = false; + goto exit; + } + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE && sta_count) { + tdls_warn("vdev:%d Concurrent STA exists. TDLS not allowed for P2P vdev", + wlan_vdev_get_id(vdev)); + state = false; + goto exit; + } + + ch_freq = wlan_get_operation_chan_freq(vdev); + if (wlan_reg_is_6ghz_chan_freq(ch_freq) && + !tdls_is_6g_freq_allowed(vdev, ch_freq)) { + tdls_debug("6GHz freq:%d not allowed for TDLS", ch_freq); + state = false; + } + +exit: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + + return state; +} + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +bool tdls_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc) +{ + if (policy_mgr_is_mlo_in_mode_emlsr(psoc, NULL, NULL)) { + tdls_debug("eMLSR STA present. Don't allow TDLS"); + return false; + } + + if (!wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_TDLS_CONCURRENCIES_SUPPORT)) { + tdls_debug("fw cap is not advertised"); + return false; + } + + if (policy_mgr_get_connection_count_with_mlo(psoc) > + WLAN_TDLS_MAX_CONCURRENT_VDEV_SUPPORTED) + return false; + + if (policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL) > 1) { + tdls_debug("More than one STA exist. Don't allow TDLS"); + return false; + } + + if (policy_mgr_is_mcc_on_any_sta_vdev(psoc)) { + tdls_debug("Base channel MCC. Don't allow TDLS"); + return false; + } + + /* + * Don't enable TDLS for P2P_CLI in concurrency cases + */ + if (policy_mgr_get_connection_count_with_mlo(psoc) > 1 && + !policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL)) + return false; + + return true; +} +#endif + +void tdls_set_ct_mode(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + uint32_t tdls_feature_flags = 0, sta_count, p2p_count; + bool state = false; + bool tdls_mlo; + QDF_STATUS status; + + if (!tdls_check_is_tdls_allowed(vdev)) + return; + + status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to get TDLS objects"); + return; + } + + qdf_atomic_set(&tdls_soc_obj->timer_cnt, 0); + tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags; + if (TDLS_SUPPORT_DISABLED == tdls_soc_obj->tdls_current_mode || + TDLS_SUPPORT_SUSPENDED == tdls_soc_obj->tdls_current_mode || + !TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags)) { + state = false; + goto set_state; + } + + sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + p2p_count = + policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL); + tdls_mlo = wlan_tdls_is_fw_11be_mlo_capable(psoc); + if (sta_count == 1 || (sta_count >= 2 && tdls_mlo) || + (policy_mgr_get_connection_count_with_mlo(psoc) == 1 && + p2p_count == 1)) { + state = true; + /* + * In case of TDLS external control, peer should be added + * by the user space to start connection tracker. + */ + if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(tdls_feature_flags) && + !tdls_soc_obj->tdls_external_peer_count) + state = false; + + goto set_state; + } + + state = false; + +set_state: + tdls_soc_obj->enable_tdls_connection_tracker = state; + if (tdls_soc_obj->enable_tdls_connection_tracker) + tdls_implicit_enable(tdls_vdev_obj); + else + tdls_implicit_disable(tdls_vdev_obj); + + tdls_debug("vdev:%d enable_tdls_connection_tracker %d current_mode:%d feature_flags:0x%x", + wlan_vdev_get_id(vdev), + tdls_soc_obj->enable_tdls_connection_tracker, + tdls_soc_obj->tdls_current_mode, tdls_feature_flags); +} + +void tdls_set_user_tdls_enable(struct wlan_objmgr_vdev *vdev, + bool is_user_tdls_enable) +{ + QDF_STATUS status; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) + return; + + status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to get TDLS objects"); + goto exit; + } + + tdls_soc_obj->is_user_tdls_enable = is_user_tdls_enable; + tdls_debug("TDLS enable:%d via userspace", + tdls_soc_obj->is_user_tdls_enable); + +exit: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +} + +QDF_STATUS +tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_vdev *tdls_vdev; + struct tdls_vdev_priv_obj *tdls_priv_vdev; + struct tdls_soc_priv_obj *tdls_priv_soc; + QDF_STATUS status; + + if (!psoc) { + tdls_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_vdev = tdls_get_vdev(psoc, WLAN_TDLS_NB_ID); + if (!tdls_vdev) { + tdls_debug("No TDLS vdev"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_get_vdev_objects(tdls_vdev, &tdls_priv_vdev, + &tdls_priv_soc); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_debug("TDLS vdev objects NULL"); + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!tdls_check_is_tdls_allowed(tdls_vdev)) { + tdls_debug("Disable the tdls in FW due to concurrency"); + if (wlan_vdev_mlme_is_mlo_vdev(tdls_vdev)) + tdls_process_enable_disable_for_ml_vdev(tdls_vdev, + false); + else + tdls_disable_offchan_and_teardown_links(tdls_vdev); + + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_debug("vdev:%d enter", wlan_vdev_get_id(tdls_vdev)); + + tdls_set_tdls_offchannelmode(tdls_vdev, ENABLE_CHANSWITCH); + tdls_set_ct_mode(psoc, tdls_vdev); + + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + tdls_debug("exit "); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tdls_process_decrement_active_session(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_vdev *tdls_obj_vdev; + + tdls_debug("Enter"); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + if(!policy_mgr_is_hw_dbs_2x2_capable(psoc) && + !policy_mgr_is_hw_dbs_required_for_band(psoc, HW_MODE_MAC_BAND_2G) && + policy_mgr_is_current_hwmode_dbs(psoc)) { + tdls_debug("Current HW mode is 1*1 DBS. Wait for Opportunistic timer to expire to enable TDLS in FW"); + return QDF_STATUS_SUCCESS; + } + + tdls_obj_vdev = tdls_get_vdev(psoc, WLAN_TDLS_NB_ID); + if (!tdls_obj_vdev) + return QDF_STATUS_E_FAILURE; + + if (!tdls_check_is_tdls_allowed(tdls_obj_vdev)) + goto release_ref; + + /* + * 2 Port MCC -> 1 port scenario or + * 3 Port MCC -> 2 port SCC scenario or + * 4 Port -> 3 Port SCC scenario + * So enable TDLS in firmware + */ + tdls_debug("Enable TDLS as active sta/p2p_cli interface is present"); + if (wlan_vdev_mlme_is_mlo_vdev(tdls_obj_vdev)) + tdls_process_enable_disable_for_ml_vdev(tdls_obj_vdev, true); + else + tdls_process_enable_for_vdev(tdls_obj_vdev); + +release_ref: + wlan_objmgr_vdev_release_ref(tdls_obj_vdev, WLAN_TDLS_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +struct wlan_objmgr_vdev *wlan_tdls_get_mlo_vdev(struct wlan_objmgr_vdev *vdev, + uint8_t index, + wlan_objmgr_ref_dbgid dbg_id) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *mlo_vdev; + + if (!vdev) + return NULL; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) + return NULL; + + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[index]; + if (mlo_vdev && + wlan_objmgr_vdev_try_get_ref(mlo_vdev, dbg_id) == + QDF_STATUS_SUCCESS) + return mlo_vdev; + + return NULL; +} + +void wlan_tdls_release_mlo_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + if (!vdev) + return; + + wlan_objmgr_vdev_release_ref(vdev, dbg_id); +} +#else +struct wlan_objmgr_vdev *wlan_tdls_get_mlo_vdev(struct wlan_objmgr_vdev *vdev, + uint8_t index, + wlan_objmgr_ref_dbgid dbg_id) +{ + return NULL; +} + +void wlan_tdls_release_mlo_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ +} +#endif +/** + * tdls_get_vdev() - Get tdls specific vdev object manager + * @psoc: wlan psoc object manager + * @dbg_id: debug id + * + * If TDLS possible, return the corresponding vdev + * to enable TDLS in the system. + * + * Return: vdev manager pointer or NULL. + */ +struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id) +{ + uint32_t vdev_id; + + vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_STA_MODE); + if (WLAN_INVALID_VDEV_ID != vdev_id) + return wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + dbg_id); + /* + * For P2P_Client mode, TDLS is not supported on concurrency + * so return P2P_client vdev only if P2P client mode exists without + * any concurreny + */ + vdev_id = policy_mgr_mode_specific_vdev_id(psoc, PM_P2P_CLIENT_MODE); + if (WLAN_INVALID_VDEV_ID != vdev_id && + policy_mgr_get_connection_count_with_mlo(psoc) == 1) + return wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + dbg_id); + + return NULL; +} + +static QDF_STATUS tdls_post_msg_flush_cb(struct scheduler_msg *msg) +{ + void *ptr = msg->bodyptr; + struct wlan_objmgr_vdev *vdev = NULL; + + switch (msg->type) { + case TDLS_NOTIFY_STA_DISCONNECTION: + vdev = ((struct tdls_sta_notify_params *)ptr)->vdev; + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(ptr); + break; + + case TDLS_DELETE_ALL_PEERS_INDICATION: + vdev = ((struct tdls_delete_all_peers_params *)ptr)->vdev; + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + qdf_mem_free(ptr); + break; + + case TDLS_CMD_SCAN_DONE: + case TDLS_CMD_SESSION_INCREMENT: + case TDLS_CMD_SESSION_DECREMENT: + break; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * tdls_process_session_update() - update session count information + * @psoc: soc object + * @cmd_type: type of command + * + * update the session information in connection tracker + * + * Return: None + */ +static void tdls_process_session_update(struct wlan_objmgr_psoc *psoc, + enum tdls_command_type cmd_type) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + msg.bodyptr = psoc; + msg.callback = tdls_process_cmd; + msg.flush_callback = tdls_post_msg_flush_cb; + msg.type = (uint16_t)cmd_type; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + tdls_alert("message post failed "); +} + +void tdls_notify_increment_session(struct wlan_objmgr_psoc *psoc) +{ + tdls_process_session_update(psoc, TDLS_CMD_SESSION_INCREMENT); +} + +void tdls_notify_decrement_session(struct wlan_objmgr_psoc *psoc) +{ + tdls_process_session_update(psoc, TDLS_CMD_SESSION_DECREMENT); +} + +void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj, + struct tdls_soc_priv_obj *tdls_soc_obj, + bool tdls_prohibited, + bool tdls_chan_swit_prohibited, + bool sta_connect_event, + uint8_t session_id) +{ + struct tdls_info *tdls_info_to_fw; + struct tdls_config_params *threshold_params; + uint32_t tdls_feature_flags; + QDF_STATUS status; + bool tdls_mlo; + + tdls_feature_flags = tdls_soc_obj->tdls_configs.tdls_feature_flags; + if (!TDLS_IS_ENABLED(tdls_feature_flags)) { + tdls_debug("TDLS mode is not enabled"); + return; + } + + tdls_mlo = wlan_tdls_is_fw_11be_mlo_capable(tdls_soc_obj->soc); + + /* If AP or caller indicated TDLS Prohibited then disable tdls mode */ + if (sta_connect_event) { + if (tdls_prohibited) { + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_DISABLED; + } else { + if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags)) + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_EXP_TRIG_ONLY; + else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED( + tdls_feature_flags)) + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_EXT_CONTROL; + else + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_IMP_MODE; + } + } else { + tdls_soc_obj->tdls_current_mode = + TDLS_SUPPORT_DISABLED; + } + + tdls_info_to_fw = qdf_mem_malloc(sizeof(struct tdls_info)); + if (!tdls_info_to_fw) + return; + + threshold_params = &tdls_vdev_obj->threshold_config; + + tdls_info_to_fw->notification_interval_ms = + threshold_params->tx_period_t; + tdls_info_to_fw->tx_discovery_threshold = + threshold_params->tx_packet_n; + tdls_info_to_fw->tx_teardown_threshold = + threshold_params->idle_packet_n; + tdls_info_to_fw->rssi_teardown_threshold = + threshold_params->rssi_teardown_threshold; + tdls_info_to_fw->rssi_delta = threshold_params->rssi_delta; + tdls_info_to_fw->vdev_id = session_id; + + /* record the session id in vdev context */ + tdls_vdev_obj->session_id = session_id; + tdls_info_to_fw->tdls_state = tdls_soc_obj->tdls_current_mode; + tdls_info_to_fw->tdls_options = 0; + + /* + * Do not enable TDLS offchannel, if AP prohibited TDLS + * channel switch + */ + if (TDLS_IS_OFF_CHANNEL_ENABLED(tdls_feature_flags) && + (!tdls_chan_swit_prohibited)) + tdls_info_to_fw->tdls_options = ENA_TDLS_OFFCHAN; + + if (TDLS_IS_BUFFER_STA_ENABLED(tdls_feature_flags)) + tdls_info_to_fw->tdls_options |= ENA_TDLS_BUFFER_STA; + if (TDLS_IS_SLEEP_STA_ENABLED(tdls_feature_flags)) + tdls_info_to_fw->tdls_options |= ENA_TDLS_SLEEP_STA; + + + tdls_info_to_fw->peer_traffic_ind_window = + tdls_soc_obj->tdls_configs.tdls_uapsd_pti_window; + tdls_info_to_fw->peer_traffic_response_timeout = + tdls_soc_obj->tdls_configs.tdls_uapsd_ptr_timeout; + tdls_info_to_fw->puapsd_mask = + tdls_soc_obj->tdls_configs.tdls_uapsd_mask; + tdls_info_to_fw->puapsd_inactivity_time = + tdls_soc_obj->tdls_configs.tdls_uapsd_inactivity_time; + tdls_info_to_fw->puapsd_rx_frame_threshold = + tdls_soc_obj->tdls_configs.tdls_rx_pkt_threshold; + tdls_info_to_fw->teardown_notification_ms = + tdls_soc_obj->tdls_configs.tdls_idle_timeout; + tdls_info_to_fw->tdls_peer_kickout_threshold = + tdls_soc_obj->tdls_configs.tdls_peer_kickout_threshold; + tdls_info_to_fw->tdls_discovery_wake_timeout = + tdls_soc_obj->tdls_configs.tdls_discovery_wake_timeout; + + status = tgt_tdls_set_fw_state(tdls_soc_obj->soc, tdls_info_to_fw); + if (QDF_IS_STATUS_ERROR(status)) + goto done; + + if (sta_connect_event) { + tdls_soc_obj->set_state_info.vdev_id = session_id; + } + + tdls_debug("FW tdls state sent for vdev id %d", session_id); +done: + qdf_mem_free(tdls_info_to_fw); + return; +} + +void tdls_process_enable_for_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + enum QDF_OPMODE opmode; + QDF_STATUS status; + uint8_t sta_count; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode == QDF_P2P_CLIENT_MODE && sta_count) { + tdls_debug("STA + P2P concurrency. Don't allow TDLS on P2P vdev:%d", + wlan_vdev_get_id(vdev)); + return; + } + + status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) + return; + + tdls_send_update_to_fw(tdls_vdev_obj, tdls_soc_obj, + mlme_get_tdls_prohibited(vdev), + mlme_get_tdls_chan_switch_prohibited(vdev), + true, wlan_vdev_get_id(vdev)); + + /* check and set the connection tracker */ + tdls_set_ct_mode(tdls_soc_obj->soc, vdev); +} + +#ifdef WLAN_FEATURE_11BE_MLO +void tdls_process_enable_disable_for_ml_vdev(struct wlan_objmgr_vdev *vdev, + bool is_enable) +{ + struct wlan_mlo_dev_context *ml_dev_ctx; + QDF_STATUS status; + uint8_t i; + struct wlan_objmgr_vdev *vdev_iter; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + ml_dev_ctx = vdev->mlo_dev_ctx; + if (!ml_dev_ctx) + return; + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!ml_dev_ctx->wlan_vdev_list[i]) + continue; + + vdev_iter = ml_dev_ctx->wlan_vdev_list[i]; + status = wlan_objmgr_vdev_try_get_ref(vdev_iter, + WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + if (is_enable) + tdls_process_enable_for_vdev(vdev_iter); + else + tdls_disable_offchan_and_teardown_links(vdev_iter); + + wlan_objmgr_vdev_release_ref(vdev_iter, WLAN_TDLS_NB_ID); + } +} +#endif + +static QDF_STATUS +tdls_process_sta_connect(struct tdls_sta_notify_params *notify) +{ + if (!tdls_check_is_tdls_allowed(notify->vdev)) + return QDF_STATUS_E_NOSUPPORT; + + tdls_process_enable_for_vdev(notify->vdev); + + return QDF_STATUS_SUCCESS; +} + +static void +tdls_update_discovery_tries(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_user_config *tdls_config; + struct tdls_config_params *vdev_config; + QDF_STATUS status; + + status = tdls_get_vdev_objects(vdev, &vdev_obj, &soc_obj); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev_obj & soc_obj"); + return; + } + + vdev_config = &vdev_obj->threshold_config; + tdls_config = &soc_obj->tdls_configs; + + vdev_config->discovery_tries_n = + tdls_config->tdls_max_discovery_attempt; +} + +QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify) +{ + QDF_STATUS status; + + if (!notify) { + tdls_err("invalid param"); + return QDF_STATUS_E_INVAL; + } + + if (!notify->vdev) { + tdls_err("invalid param"); + qdf_mem_free(notify); + return QDF_STATUS_E_INVAL; + } + + status = tdls_process_sta_connect(notify); + if (QDF_IS_STATUS_SUCCESS(status)) + tdls_update_discovery_tries(notify->vdev); + + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + + return status; +} + +static QDF_STATUS +tdls_process_sta_disconnect(struct tdls_sta_notify_params *notify) +{ + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_soc_priv_obj *tdls_soc_obj; + struct wlan_objmgr_vdev *temp_vdev = NULL; + QDF_STATUS status; + + status = tdls_get_vdev_objects(notify->vdev, &tdls_vdev_obj, + &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* if the disconnect comes from user space, we have to delete all the + * tdls peers before sending the set state cmd. + */ + if (notify->user_disconnect) + return tdls_delete_all_tdls_peers(notify->vdev, tdls_soc_obj); + + tdls_debug("vdev:%d Disable TDLS peer_count:%d", + notify->session_id, tdls_soc_obj->connected_peer_count); + + /* Disassociation event */ + tdls_send_update_to_fw(tdls_vdev_obj, tdls_soc_obj, false, + false, false, notify->session_id); + + tdls_timers_stop(tdls_vdev_obj); + + /* + * If concurrency is not marked, then we have to + * check, whether TDLS could be enabled in the + * system after this disassoc event. + */ + if (notify->lfr_roam) + return status; + + temp_vdev = tdls_get_vdev(tdls_soc_obj->soc, WLAN_TDLS_NB_ID); + if (!temp_vdev) + return status; + + if (wlan_vdev_mlme_is_mlo_vdev(temp_vdev)) + tdls_process_enable_disable_for_ml_vdev(temp_vdev, true); + else + tdls_process_enable_for_vdev(temp_vdev); + + wlan_objmgr_vdev_release_ref(temp_vdev, WLAN_TDLS_NB_ID); + + wlan_vdev_mlme_feat_ext2_cap_clear(notify->vdev, + WLAN_VDEV_FEXT2_MLO_STA_TDLS); + + return status; +} + +QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode; + struct wlan_objmgr_psoc *psoc; + uint8_t sta_count; + + if (!notify) { + tdls_err("invalid param"); + return QDF_STATUS_E_INVAL; + } + + vdev = notify->vdev; + if (!vdev) { + tdls_err("invalid param"); + qdf_mem_free(notify); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + sta_count = policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + if (opmode == QDF_P2P_CLIENT_MODE && sta_count) { + tdls_debug("STA + P2P concurrency. No action on P2P vdev"); + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + return QDF_STATUS_E_INVAL; + } + + status = tdls_process_sta_disconnect(notify); + + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + + return status; +} + +static void tdls_process_reset_adapter(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + return; + tdls_timers_stop(tdls_vdev); +} + +void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + QDF_ASSERT(0); + return; + } + + if (QDF_STATUS_SUCCESS != wlan_objmgr_vdev_try_get_ref(vdev, + WLAN_TDLS_NB_ID)) + return; + + tdls_process_reset_adapter(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +} + +QDF_STATUS tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct scheduler_msg msg = {0, }; + struct tdls_sta_notify_params *notify; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + notify = qdf_mem_malloc(sizeof(*notify)); + if (!notify) + return QDF_STATUS_E_NULL_VALUE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_TDLS_NB_ID); + + if (!vdev) { + tdls_err("vdev not exist for the vdev id %d", + vdev_id); + qdf_mem_free(notify); + return QDF_STATUS_E_INVAL; + } + + notify->lfr_roam = true; + notify->tdls_chan_swit_prohibited = false; + notify->tdls_prohibited = false; + notify->session_id = vdev_id; + notify->vdev = vdev; + notify->user_disconnect = false; + + msg.bodyptr = notify; + msg.callback = tdls_process_cmd; + msg.flush_callback = tdls_post_msg_flush_cb; + msg.type = TDLS_NOTIFY_STA_DISCONNECTION; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + tdls_alert("message post failed "); + + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct scheduler_msg msg = {0, }; + struct tdls_delete_all_peers_params *indication; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + indication = qdf_mem_malloc(sizeof(*indication)); + if (!indication) + return QDF_STATUS_E_NULL_VALUE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("vdev:%d does not exist", vdev_id); + qdf_mem_free(indication); + return QDF_STATUS_E_INVAL; + } + + indication->vdev = vdev; + + msg.bodyptr = indication; + msg.callback = tdls_process_cmd; + msg.type = TDLS_DELETE_ALL_PEERS_INDICATION; + msg.flush_callback = tdls_post_msg_flush_cb; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + qdf_mem_free(indication); + tdls_alert("message post failed "); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tdls_check_and_indicate_delete_all_peers(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_pdev *pdev; + uint32_t pdev_id; + enum QDF_OPMODE opmode; + uint8_t sta_count = + policy_mgr_mode_specific_connection_count(psoc, PM_STA_MODE, + NULL); + + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TDLS_SB_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + tdls_debug("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TDLS_SB_ID); + if (!pdev) { + tdls_debug("pdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + wlan_objmgr_pdev_release_ref(pdev, WLAN_TDLS_SB_ID); + + if (opmode == QDF_P2P_CLIENT_MODE && sta_count) { + tdls_debug("STA + P2P concurrency. No action on P2P vdev"); + return QDF_STATUS_E_INVAL; + } + + return tdls_delete_all_peers_indication(psoc, vdev_id); +} + +/** + * tdls_set_mode_in_vdev() - set TDLS mode + * @tdls_vdev: tdls vdev object + * @tdls_soc: tdls soc object + * @tdls_mode: TDLS mode + * @source: TDLS disable source enum values + * + * Return: Void + */ +static void tdls_set_mode_in_vdev(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_soc_priv_obj *tdls_soc, + enum tdls_feature_mode tdls_mode, + enum tdls_disable_sources source) +{ + tdls_debug("set tdls mode: %d source:%d", tdls_mode, + source); + + switch (tdls_mode) { + case TDLS_SUPPORT_IMP_MODE: + fallthrough; + case TDLS_SUPPORT_EXT_CONTROL: + clear_bit((unsigned long)source, &tdls_soc->tdls_source_bitmap); + /* + * Check if any TDLS source bit is set and if + * bitmap is not zero then we should not enable TDLS + */ + if (tdls_soc->tdls_source_bitmap) { + tdls_notice("Don't enable TDLS, source bitmap: %lu", + tdls_soc->tdls_source_bitmap); + return; + } + tdls_implicit_enable(tdls_vdev); + /* + * tdls implicit mode is enabled, so enable the connection + * tracker + */ + tdls_soc->enable_tdls_connection_tracker = true; + + return; + + case TDLS_SUPPORT_DISABLED: + set_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_implicit_disable(tdls_vdev); + /* If tdls implicit mode is disabled, then + * stop the connection tracker. + */ + tdls_soc->enable_tdls_connection_tracker = false; + + return; + + case TDLS_SUPPORT_EXP_TRIG_ONLY: + clear_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_implicit_disable(tdls_vdev); + /* If tdls implicit mode is disabled, then + * stop the connection tracker. + */ + tdls_soc->enable_tdls_connection_tracker = false; + + /* + * Check if any TDLS source bit is set and if + * bitmap is not zero then we should not + * enable TDLS + */ + if (tdls_soc->tdls_source_bitmap) + return; + + return; + default: + return; + } +} + +/** + * tdls_set_current_mode() - set TDLS mode + * @tdls_soc: tdls soc object + * @tdls_mode: TDLS mode + * @update_last: indicate to record the last tdls mode + * @source: TDLS disable source enum values + * + * Return: Void + */ +static void tdls_set_current_mode(struct tdls_soc_priv_obj *tdls_soc, + enum tdls_feature_mode tdls_mode, + bool update_last, + enum tdls_disable_sources source) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_vdev_priv_obj *tdls_vdev; + + if (!tdls_soc) + return; + + tdls_debug("mode %d", (int)tdls_mode); + + if (update_last) + tdls_soc->tdls_last_mode = tdls_mode; + + if (tdls_soc->tdls_current_mode == tdls_mode) { + tdls_debug("already in mode %d", tdls_mode); + + switch (tdls_mode) { + /* TDLS is already enabled hence clear source mask, return */ + case TDLS_SUPPORT_IMP_MODE: + case TDLS_SUPPORT_EXP_TRIG_ONLY: + case TDLS_SUPPORT_EXT_CONTROL: + clear_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_debug("clear source mask:%d", source); + return; + /* TDLS is already disabled hence set source mask, return */ + case TDLS_SUPPORT_DISABLED: + set_bit((unsigned long)source, + &tdls_soc->tdls_source_bitmap); + tdls_debug("set source mask:%d", source); + return; + default: + return; + } + } + + /* get sta vdev */ + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(tdls_soc->soc, + QDF_STA_MODE, + WLAN_TDLS_NB_ID); + if (vdev) { + tdls_debug("set mode in tdls STA vdev:%d", + wlan_vdev_get_id(vdev)); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (tdls_vdev) + tdls_set_mode_in_vdev(tdls_vdev, tdls_soc, + tdls_mode, source); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + + goto exit; + } + + /* get p2p client vdev */ + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(tdls_soc->soc, + QDF_P2P_CLIENT_MODE, + WLAN_TDLS_NB_ID); + if (vdev) { + tdls_debug("set mode in tdls P2P cli vdev:%d", + wlan_vdev_get_id(vdev)); + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (tdls_vdev) + tdls_set_mode_in_vdev(tdls_vdev, tdls_soc, + tdls_mode, source); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + } + +exit: + if (!update_last) + tdls_soc->tdls_last_mode = tdls_soc->tdls_current_mode; + + tdls_soc->tdls_current_mode = tdls_mode; +} + +QDF_STATUS tdls_set_operation_mode(struct tdls_set_mode_params *tdls_set_mode) +{ + struct tdls_soc_priv_obj *tdls_soc; + struct tdls_vdev_priv_obj *tdls_vdev; + QDF_STATUS status; + + if (!tdls_set_mode) + return QDF_STATUS_E_INVAL; + + if (!tdls_set_mode->vdev) { + qdf_mem_free(tdls_set_mode); + return QDF_STATUS_E_INVAL; + } + + status = tdls_get_vdev_objects(tdls_set_mode->vdev, + &tdls_vdev, &tdls_soc); + + if (QDF_IS_STATUS_ERROR(status)) + goto release_mode_ref; + + tdls_set_current_mode(tdls_soc, + tdls_set_mode->tdls_mode, + tdls_set_mode->update_last, + tdls_set_mode->source); + +release_mode_ref: + wlan_objmgr_vdev_release_ref(tdls_set_mode->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(tdls_set_mode); + return status; +} + +/** + * tdls_scan_done_callback() - callback for tdls scan done event + * @tdls_soc: tdls soc object + * + * Return: Void + */ +void tdls_scan_done_callback(struct tdls_soc_priv_obj *tdls_soc) +{ + if (!tdls_soc) + return; + + /* if tdls was enabled before scan, re-enable tdls mode */ + if (TDLS_SUPPORT_IMP_MODE == tdls_soc->tdls_last_mode || + TDLS_SUPPORT_EXT_CONTROL == tdls_soc->tdls_last_mode || + TDLS_SUPPORT_EXP_TRIG_ONLY == tdls_soc->tdls_last_mode) + tdls_set_current_mode(tdls_soc, tdls_soc->tdls_last_mode, + false, TDLS_SET_MODE_SOURCE_SCAN); +} + +/** + * tdls_post_scan_done_msg() - post scan done message to tdls cmd queue + * @tdls_soc: tdls soc object + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_NULL_VALUE + */ +static QDF_STATUS tdls_post_scan_done_msg(struct tdls_soc_priv_obj *tdls_soc) +{ + struct scheduler_msg msg = {0, }; + + if (!tdls_soc) { + tdls_err("tdls_soc: %pK ", tdls_soc); + return QDF_STATUS_E_NULL_VALUE; + } + + msg.bodyptr = tdls_soc; + msg.callback = tdls_process_cmd; + msg.flush_callback = tdls_post_msg_flush_cb; + msg.type = TDLS_CMD_SCAN_DONE; + + return scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); +} + +void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + enum QDF_OPMODE device_mode; + struct tdls_soc_priv_obj *tdls_soc; + + if (!vdev || !event || !arg) + return; + + if (SCAN_EVENT_TYPE_COMPLETED != event->type) + return; + + device_mode = wlan_vdev_mlme_get_opmode(vdev); + + tdls_soc = (struct tdls_soc_priv_obj *) arg; + tdls_post_scan_done_msg(tdls_soc); +} + +void tdls_set_link_unforce(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_LINK_UNFORCE; + msg.bodyptr = vdev; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + tdls_err("failed to set tdls link mode"); +} + +/** + * tdls_check_peer_buf_capable() - Check buffer sta capable of tdls peers + * @tdls_vdev: TDLS vdev object + * + * Used in scheduler thread context, no lock needed. + * + * Return: false if there is connected peer and not support buffer sta. + */ +static bool tdls_check_peer_buf_capable(struct tdls_vdev_priv_obj *tdls_vdev) +{ + uint16_t i; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + QDF_STATUS status; + + if (!tdls_vdev) { + tdls_err("invalid tdls vdev object"); + return false; + } + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_vdev->peer_list[i]; + + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + + if (peer && + (TDLS_LINK_CONNECTED == peer->link_status) && + (!peer->buf_sta_capable)) + return false; + + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + + return true; +} + +QDF_STATUS tdls_scan_callback(struct tdls_soc_priv_obj *tdls_soc) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + struct wlan_objmgr_vdev *vdev; + uint16_t tdls_peer_count; + uint32_t feature; + bool peer_buf_capable; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* if tdls is not enabled, then continue scan */ + if (TDLS_SUPPORT_DISABLED == tdls_soc->tdls_current_mode) + return status; + + /* Get the vdev based on vdev operating mode*/ + vdev = tdls_get_vdev(tdls_soc->soc, WLAN_TDLS_NB_ID); + if (!vdev) + return status; + + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!tdls_vdev) + goto return_success; + + if (tdls_is_progress(tdls_vdev, NULL, 0)) { + if (tdls_soc->scan_reject_count++ >= TDLS_SCAN_REJECT_MAX) { + tdls_notice("Allow this scan req. as already max no of scan's are rejected"); + tdls_soc->scan_reject_count = 0; + status = QDF_STATUS_SUCCESS; + + } else { + tdls_warn("tdls in progress. scan rejected %d", + tdls_soc->scan_reject_count); + status = QDF_STATUS_E_BUSY; + } + } + + tdls_peer_count = tdls_soc->connected_peer_count; + if (!tdls_peer_count) + goto disable_tdls; + + feature = tdls_soc->tdls_configs.tdls_feature_flags; + if (TDLS_IS_SCAN_ENABLED(feature)) { + tdls_debug("TDLS Scan enabled, keep tdls link and allow scan, connected tdls peers: %d", + tdls_peer_count); + goto disable_tdls; + } + + if (TDLS_IS_BUFFER_STA_ENABLED(feature) && + (tdls_peer_count <= TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN)) { + peer_buf_capable = tdls_check_peer_buf_capable(tdls_vdev); + if (peer_buf_capable) { + tdls_debug("All peers (num %d) bufSTAs, we can be sleep sta, so allow scan, tdls mode changed to %d", + tdls_peer_count, + tdls_soc->tdls_current_mode); + goto disable_tdls; + } + } + + tdls_disable_offchan_and_teardown_links(vdev); + +disable_tdls: + tdls_set_current_mode(tdls_soc, TDLS_SUPPORT_DISABLED, + false, TDLS_SET_MODE_SOURCE_SCAN); + +return_success: + wlan_objmgr_vdev_release_ref(vdev, + WLAN_TDLS_NB_ID); + return status; +} + +void tdls_scan_serialization_comp_info_cb(struct wlan_objmgr_vdev *vdev, + union wlan_serialization_rules_info *comp_info, + struct wlan_serialization_command *cmd) +{ + struct tdls_soc_priv_obj *tdls_soc; + QDF_STATUS status; + if (!comp_info) + return; + + tdls_soc = tdls_soc_global; + comp_info->scan_info.is_tdls_in_progress = false; + status = tdls_scan_callback(tdls_soc); + if (QDF_STATUS_E_BUSY == status) + comp_info->scan_info.is_tdls_in_progress = true; +} + +static uint8_t tdls_find_opclass_frm_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t ch_freq, uint8_t bw_offset, + uint16_t behav_limit) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + uint8_t channel, opclass; + + if (!pdev) { + tdls_err("pdev is NULL"); + return 0; + } + + wlan_reg_freq_width_to_chan_op_class(pdev, ch_freq, bw_offset, false, + BIT(behav_limit), &opclass, + &channel); + + return opclass; +} + +uint8_t tdls_get_opclass_from_bandwidth(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq, uint8_t bw_offset, + uint8_t *reg_bw_offset) +{ + uint8_t opclass; + + if (bw_offset & (1 << BW_160_OFFSET_BIT)) { + opclass = tdls_find_opclass_frm_freq(vdev, + freq, BW_160_MHZ, + BEHAV_NONE); + *reg_bw_offset = BWALL; + } else if (bw_offset & (1 << BW_80_OFFSET_BIT)) { + opclass = tdls_find_opclass_frm_freq(vdev, + freq, BW_80_MHZ, + BEHAV_NONE); + *reg_bw_offset = BW80; + } else if (bw_offset & (1 << BW_40_OFFSET_BIT)) { + opclass = tdls_find_opclass_frm_freq(vdev, + freq, BW_40_MHZ, + BEHAV_BW40_LOW_PRIMARY); + *reg_bw_offset = BW40_LOW_PRIMARY; + if (!opclass) { + opclass = tdls_find_opclass_frm_freq(vdev, + freq, + BW_40_MHZ, + BEHAV_BW40_HIGH_PRIMARY); + *reg_bw_offset = BW40_HIGH_PRIMARY; + } + } else if (bw_offset & (1 << BW_20_OFFSET_BIT)) { + opclass = tdls_find_opclass_frm_freq(vdev, + freq, BW_20_MHZ, + BEHAV_NONE); + *reg_bw_offset = BW20; + } else { + opclass = tdls_find_opclass_frm_freq(vdev, + freq, BW_160_MHZ, + BEHAV_NONE); + *reg_bw_offset = BWALL; + } + + return opclass; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_main.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_main.h new file mode 100644 index 0000000000..a9614bddad --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_main.h @@ -0,0 +1,942 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_main.h + * + * TDLS core function declaration + */ + +#if !defined(_WLAN_TDLS_MAIN_H_) +#define _WLAN_TDLS_MAIN_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_serialization_api.h" +#include + + +/* Bit mask flag for tdls_option to FW */ +#define ENA_TDLS_OFFCHAN (1 << 0) /* TDLS Off Channel support */ +#define ENA_TDLS_BUFFER_STA (1 << 1) /* TDLS Buffer STA support */ +#define ENA_TDLS_SLEEP_STA (1 << 2) /* TDLS Sleep STA support */ + +#define BW_20_OFFSET_BIT 0 +#define BW_40_OFFSET_BIT 1 +#define BW_80_OFFSET_BIT 2 +#define BW_160_OFFSET_BIT 3 + +#define TDLS_SEC_OFFCHAN_OFFSET_0 0 +#define TDLS_SEC_OFFCHAN_OFFSET_40PLUS 40 +#define TDLS_SEC_OFFCHAN_OFFSET_40MINUS (-40) +#define TDLS_SEC_OFFCHAN_OFFSET_80 80 +#define TDLS_SEC_OFFCHAN_OFFSET_160 160 +/* + * Before UpdateTimer expires, we want to timeout discovery response + * should not be more than 2000. + */ +#define TDLS_DISCOVERY_TIMEOUT_BEFORE_UPDATE 1000 +#define TDLS_SCAN_REJECT_MAX 5 +#define TDLS_MAX_CONNECTED_PEERS_TO_ALLOW_SCAN 1 + +#define tdls_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_TDLS, params) +#define tdls_debug_rl(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_TDLS, params) + +#define tdls_notice(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_TDLS, params) +#define tdls_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_TDLS, params) +#define tdls_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_TDLS, params) +#define tdls_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_TDLS, params) + +#define tdls_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_TDLS, params) +#define tdls_nofl_notice(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_TDLS, params) +#define tdls_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_TDLS, params) +#define tdls_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_TDLS, params) +#define tdls_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_TDLS, params) + +#define TDLS_IS_LINK_CONNECTED(peer) \ + ((TDLS_LINK_CONNECTED == (peer)->link_status) || \ + (TDLS_LINK_TEARING == (peer)->link_status)) + +#define SET_BIT(value, mask) ((value) |= (1 << (mask))) +#define CLEAR_BIT(value, mask) ((value) &= ~(1 << (mask))) +#define CHECK_BIT(value, mask) ((value) & (1 << (mask))) +/** + * struct tdls_conn_info - TDLS connection record + * @session_id: session id + * @valid_entry: valid entry(set to true upon peer create resp from firmware) + * @peer_mac: peer address + * @index: index to store array offset. + */ +struct tdls_conn_info { + uint8_t session_id; + bool valid_entry; + uint8_t index; + struct qdf_mac_addr peer_mac; +}; + +/** + * enum tdls_nss_transition_state - TDLS NSS transition states + * @TDLS_NSS_TRANSITION_S_UNKNOWN: default state + * @TDLS_NSS_TRANSITION_S_2x2_to_1x1: transition from 2x2 to 1x1 stream + * @TDLS_NSS_TRANSITION_S_1x1_to_2x2: transition from 1x1 to 2x2 stream + */ +enum tdls_nss_transition_state { + TDLS_NSS_TRANSITION_S_UNKNOWN = 0, + TDLS_NSS_TRANSITION_S_2x2_to_1x1, + TDLS_NSS_TRANSITION_S_1x1_to_2x2, +}; + +/** + * struct tdls_conn_tracker_mac_table - connection tracker peer table + * @mac_address: peer mac address + * @tx_packet_cnt: number of tx pkts + * @rx_packet_cnt: number of rx pkts + * @peer_timestamp_ms: time stamp of latest peer traffic + */ +struct tdls_conn_tracker_mac_table { + struct qdf_mac_addr mac_address; + uint32_t tx_packet_cnt; + uint32_t rx_packet_cnt; + uint32_t peer_timestamp_ms; +}; + +/** + * struct tdls_set_state_info - vdev id state info + * @vdev_id: vdev id of last set state command + */ +struct tdls_set_state_info { + uint8_t vdev_id; +}; + +/** + * struct tdls_callbacks - vdev id state info + * @delete_all_tdls_peers: Callback to lim to delete TDLS peers + */ +struct tdls_callbacks { + QDF_STATUS (*delete_all_tdls_peers) (struct wlan_objmgr_vdev *vdev); +}; + +/** + * struct tdls_soc_priv_obj - tdls soc private context + * @soc: objmgr psoc + * @tdls_current_mode: current tdls mode + * @tdls_last_mode: last tdls mode + * @scan_reject_count: number of times scan rejected due to TDLS + * @tdls_source_bitmap: bit map to set/reset TDLS by different sources + * @tdls_conn_info: this tdls_conn_info can be removed and we can use peer type + * of peer object to get the active tdls peers + * @tdls_configs: tdls user configure + * @max_num_tdls_sta: maximum TDLS station number allowed upon runtime condition + * @connected_peer_count: tdls peer connected count + * @tdls_off_channel: tdls off channel number + * @tdls_channel_offset: tdls channel offset + * @tdls_fw_off_chan_mode: tdls fw off channel mode + * @enable_tdls_connection_tracker: enable tdls connection tracker + * @tdls_external_peer_count: external tdls peer count + * @tdls_nss_switch_in_progress: tdls antenna switch in progress + * @tdls_nss_teardown_complete: tdls tear down complete + * @tdls_nss_transition_mode: tdls nss transition mode + * @tdls_teardown_peers_cnt: tdls tear down peer count + * @set_state_info: set tdls state info + * @tdls_rx_cb: TDLS RX callback + * @tdls_rx_cb_data: TDLS RX callback context + * @tdls_wmm_cb: TDLS WMM check callback + * @tdls_wmm_cb_data: TDLS WMM check callback context + * @tdls_event_cb: tdls event callback + * @tdls_evt_cb_data: tdls event user data + * @tdls_peer_context: userdata for register/deregister TDLS peer + * @tdls_reg_peer: register tdls peer with datapath + * @tdls_dp_vdev_update: notify datapath of vdev updates + * @tx_q_ack: queue for tx frames waiting for ack + * @tdls_con_cap: tdls concurrency support + * @tdls_send_mgmt_req: store eWNI_SME_TDLS_SEND_MGMT_REQ value + * @tdls_add_sta_req: store eWNI_SME_TDLS_ADD_STA_REQ value + * @tdls_del_sta_req: store eWNI_SME_TDLS_DEL_STA_REQ value + * @tdls_update_peer_state: store WMA_UPDATE_TDLS_PEER_STATE value + * @tdls_del_all_peers:store eWNI_SME_DEL_ALL_TDLS_PEERS + * @tdls_update_dp_vdev_flags: store CDP_UPDATE_TDLS_FLAGS + * @tdls_idle_peer_data: provide information about idle peer + * @tdls_ct_spinlock: connection tracker spin lock + * @is_prevent_suspend: prevent suspend or not + * @is_drv_supported: platform supports drv or not, enable/disable tdls wow + * based on this flag. + * @wake_lock: wake lock + * @runtime_lock: runtime lock + * @fw_tdls_mlo_capable: is fw tdls mlo capable + * @tdls_osif_init_cb: Callback to initialize the tdls private + * @tdls_osif_deinit_cb: Callback to deinitialize the tdls private + * @tdls_osif_update_cb: Callback for updating osif params + * @fw_tdls_11ax_capability: bool for tdls 11ax fw capability + * @fw_tdls_6g_capability: bool for tdls 6g fw capability + * @bss_sta_power: bss sta power + * @bss_sta_power_type: bss sta power type + * @timer_cnt: used for mlo tdls to monitor discovery response + * @fw_tdls_wideband_capability: bool for tdls wideband fw capability + * @is_user_tdls_enable: bool to check whether TDLS enable through userspace + * @tdls_cb: TDLS callbacks to other modules + */ +struct tdls_soc_priv_obj { + struct wlan_objmgr_psoc *soc; + enum tdls_feature_mode tdls_current_mode; + enum tdls_feature_mode tdls_last_mode; + int scan_reject_count; + unsigned long tdls_source_bitmap; + struct tdls_conn_info tdls_conn_info[WLAN_TDLS_STA_MAX_NUM]; + struct tdls_user_config tdls_configs; + uint16_t max_num_tdls_sta; + uint16_t connected_peer_count; + uint8_t tdls_off_channel; + uint16_t tdls_channel_offset; + int32_t tdls_fw_off_chan_mode; + bool enable_tdls_connection_tracker; + uint8_t tdls_external_peer_count; + bool tdls_nss_switch_in_progress; + bool tdls_nss_teardown_complete; + enum tdls_nss_transition_state tdls_nss_transition_mode; + int32_t tdls_teardown_peers_cnt; + struct tdls_set_state_info set_state_info; + tdls_rx_callback tdls_rx_cb; + void *tdls_rx_cb_data; + tdls_wmm_check tdls_wmm_cb; + void *tdls_wmm_cb_data; + tdls_evt_callback tdls_event_cb; + void *tdls_evt_cb_data; + void *tdls_peer_context; + tdls_register_peer_callback tdls_reg_peer; + tdls_dp_vdev_update_flags_callback tdls_dp_vdev_update; + qdf_list_t tx_q_ack; + enum tdls_conc_cap tdls_con_cap; + uint16_t tdls_send_mgmt_req; + uint16_t tdls_add_sta_req; + uint16_t tdls_del_sta_req; + uint16_t tdls_update_peer_state; + uint16_t tdls_del_all_peers; + uint32_t tdls_update_dp_vdev_flags; + qdf_spinlock_t tdls_ct_spinlock; +#ifdef TDLS_WOW_ENABLED + bool is_prevent_suspend; + bool is_drv_supported; + qdf_wake_lock_t wake_lock; + qdf_runtime_lock_t runtime_lock; +#endif +#ifdef WLAN_FEATURE_11BE_MLO + bool fw_tdls_mlo_capable; +#endif + tdls_vdev_init_cb tdls_osif_init_cb; + tdls_vdev_deinit_cb tdls_osif_deinit_cb; + struct tdls_osif_cb tdls_osif_update_cb; +#ifdef WLAN_FEATURE_11AX + bool fw_tdls_11ax_capability; + bool fw_tdls_6g_capability; + uint8_t bss_sta_power; + uint8_t bss_sta_power_type; +#endif + qdf_atomic_t timer_cnt; + bool fw_tdls_wideband_capability; + bool is_user_tdls_enable; + struct tdls_callbacks tdls_cb; +}; + +/** + * struct tdls_vdev_priv_obj - tdls private vdev object + * @vdev: vdev objmgr object + * @peer_list: tdls peer list on this vdev + * @peer_update_timer: connection tracker timer + * @peer_discovery_timer: peer discovery timer + * @threshold_config: threshold config + * @discovery_peer_cnt: discovery peer count + * @discovery_sent_cnt: discovery sent count + * @curr_candidate: current candidate + * @ct_peer_table: linear mac address table for counting the packets + * @valid_mac_entries: number of valid mac entry in @ct_peer_mac_table + * @rx_mgmt: the pointer of rx mgmt info + * @link_score: select tdls vdev per the score + * @magic: magic + * @session_id: vdev ID + * @tx_queue: tx frame queue + * @tdls_teardown_comp: tdls teardown completion + */ +struct tdls_vdev_priv_obj { + struct wlan_objmgr_vdev *vdev; + qdf_list_t peer_list[WLAN_TDLS_PEER_LIST_SIZE]; + qdf_mc_timer_t peer_update_timer; + qdf_mc_timer_t peer_discovery_timer; + struct tdls_config_params threshold_config; + int32_t discovery_peer_cnt; + uint32_t discovery_sent_cnt; + struct tdls_peer *curr_candidate; + struct tdls_conn_tracker_mac_table + ct_peer_table[WLAN_TDLS_CT_TABLE_SIZE]; + uint8_t valid_mac_entries; + struct tdls_rx_mgmt_frame *rx_mgmt; + uint32_t link_score; + uint32_t magic; + uint8_t session_id; + qdf_list_t tx_queue; + qdf_event_t tdls_teardown_comp; +}; + +/** + * struct tdls_peer_mlme_info - tdls peer mlme info + **/ +struct tdls_peer_mlme_info { +}; + +/** + * struct tdls_peer - tdls peer data + * @node: node + * @vdev_priv: tdls vdev priv obj + * @peer_mac: peer mac address + * @valid_entry: entry valid or not (set to true when peer create resp is + * received from FW) + * @rssi: rssi + * @tdls_support: tdls support + * @link_status: tdls link status + * @is_responder: is responder + * @discovery_processed: discovery processed + * @discovery_attempt: discovery attempt + * @tx_pkt: tx packet + * @rx_pkt: rx packet + * @uapsd_queues: uapsd queues + * @max_sp: max sp + * @buf_sta_capable: is buffer sta + * @off_channel_capable: is offchannel supported flag + * @supported_channels_len: supported channels length + * @supported_chan_freq: supported channel frequency + * @supported_oper_classes_len: supported operation classes length + * @supported_oper_classes: supported operation classes + * @is_forced_peer: is forced peer + * @op_class_for_pref_off_chan: op class for preferred off channel + * @pref_off_chan_freq: preferred off channel frequency + * @pref_off_chan_width: preferred off channel width + * @peer_idle_timer: time to check idle traffic in tdls peers + * @is_peer_idle_timer_initialised: Flag to check idle timer init + * @spatial_streams: Number of TX/RX spatial streams for TDLS + * @reason: reason + * @state_change_notification: state change notification + * @qos: QOS capability of TDLS link + * @tdls_info: MLME info + */ +struct tdls_peer { + qdf_list_node_t node; + struct tdls_vdev_priv_obj *vdev_priv; + struct qdf_mac_addr peer_mac; + bool valid_entry; + int8_t rssi; + enum tdls_peer_capab tdls_support; + enum tdls_link_state link_status; + uint8_t is_responder; + uint8_t discovery_processed; + uint16_t discovery_attempt; + uint16_t tx_pkt; + uint16_t rx_pkt; + uint8_t uapsd_queues; + uint8_t max_sp; + uint8_t buf_sta_capable; + uint8_t off_channel_capable; + uint8_t supported_channels_len; + qdf_freq_t supported_chan_freq[WLAN_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[WLAN_MAX_SUPP_OPER_CLASSES]; + bool is_forced_peer; + uint8_t op_class_for_pref_off_chan; + qdf_freq_t pref_off_chan_freq; + uint8_t pref_off_chan_width; + qdf_mc_timer_t peer_idle_timer; + bool is_peer_idle_timer_initialised; + uint8_t spatial_streams; + enum tdls_link_state_reason reason; + tdls_state_change_callback state_change_notification; + uint8_t qos; + struct tdls_peer_mlme_info *tdls_info; +}; + +/** + * struct tdls_os_if_event - TDLS os event info + * @type: type of event + * @info: pointer to event information + */ +struct tdls_os_if_event { + uint32_t type; + void *info; +}; + +/** + * enum tdls_os_if_notification - TDLS notification from OS IF + * @TDLS_NOTIFY_STA_SESSION_INCREMENT: sta session count incremented + * @TDLS_NOTIFY_STA_SESSION_DECREMENT: sta session count decremented + */ +enum tdls_os_if_notification { + TDLS_NOTIFY_STA_SESSION_INCREMENT, + TDLS_NOTIFY_STA_SESSION_DECREMENT +}; +/** + * wlan_vdev_get_tdls_soc_obj - private API to get tdls soc object from vdev + * @vdev: vdev object + * + * Return: tdls soc object + */ +static inline struct tdls_soc_priv_obj * +wlan_vdev_get_tdls_soc_obj(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct tdls_soc_priv_obj *soc_obj; + + if (!vdev) { + tdls_err("NULL vdev"); + return NULL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + tdls_err("can't get psoc"); + return NULL; + } + + soc_obj = (struct tdls_soc_priv_obj *) + wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + + return soc_obj; +} + +/** + * wlan_psoc_get_tdls_soc_obj - private API to get tdls soc object from psoc + * @psoc: psoc object + * + * Return: tdls soc object + */ +static inline struct tdls_soc_priv_obj * +wlan_psoc_get_tdls_soc_obj(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + if (!psoc) { + tdls_err("NULL psoc"); + return NULL; + } + soc_obj = (struct tdls_soc_priv_obj *) + wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + + return soc_obj; +} + +/** + * wlan_vdev_get_tdls_vdev_obj - private API to get tdls vdev object from vdev + * @vdev: vdev object + * + * Return: tdls vdev object + */ +static inline struct tdls_vdev_priv_obj * +wlan_vdev_get_tdls_vdev_obj(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *vdev_obj; + + if (!vdev) { + tdls_err("NULL vdev"); + return NULL; + } + + vdev_obj = (struct tdls_vdev_priv_obj *) + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + + return vdev_obj; +} + +/** + * tdls_set_link_status - tdls set link status + * @vdev: vdev object + * @mac: mac address of tdls peer + * @link_state: tdls link state + * @link_reason: reason + * + * Return: None + */ +void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev, + const uint8_t *mac, + enum tdls_link_state link_state, + enum tdls_link_state_reason link_reason); +/** + * tdls_psoc_obj_create_notification() - tdls psoc create notification handler + * @psoc: psoc object + * @arg_list: Argument list + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list); + +/** + * tdls_psoc_obj_destroy_notification() - tdls psoc destroy notification handler + * @psoc: psoc object + * @arg_list: Argument list + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list); + +/** + * tdls_vdev_obj_create_notification() - tdls vdev create notification handler + * @vdev: vdev object + * @arg_list: Argument list + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_vdev_obj_create_notification(struct wlan_objmgr_vdev *vdev, + void *arg_list); + +/** + * tdls_vdev_obj_destroy_notification() - tdls vdev destroy notification handler + * @vdev: vdev object + * @arg_list: Argument list + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_vdev_obj_destroy_notification(struct wlan_objmgr_vdev *vdev, + void *arg_list); + +/** + * tdls_process_cmd() - tdls main command process function + * @msg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_cmd(struct scheduler_msg *msg); + +/** + * tdls_process_evt() - tdls main event process function + * @msg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_evt(struct scheduler_msg *msg); + +/** + * tdls_timer_restart() - restart TDLS timer + * @vdev: VDEV object manager + * @timer: timer to restart + * @expiration_time: new expiration time to set for the timer + * + * Return: Void + */ +void tdls_timer_restart(struct wlan_objmgr_vdev *vdev, + qdf_mc_timer_t *timer, + uint32_t expiration_time); + +/** + * tdls_timers_stop() - stop all the tdls timers running + * @tdls_vdev: TDLS vdev + * + * Return: none + */ +void tdls_timers_stop(struct tdls_vdev_priv_obj *tdls_vdev); + +/** + * tdls_get_vdev_objects() - Get TDLS private objects + * @vdev: VDEV object manager + * @tdls_vdev_obj: tdls vdev object + * @tdls_soc_obj: tdls soc object + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_get_vdev_objects(struct wlan_objmgr_vdev *vdev, + struct tdls_vdev_priv_obj **tdls_vdev_obj, + struct tdls_soc_priv_obj **tdls_soc_obj); + +/** + * tdls_set_ct_mode() - Set the tdls connection tracker mode + * @psoc: objmgr psoc object + * @vdev: Pointer to vdev object + * + * This routine is called to set the tdls connection tracker operation status + * + * Return: NONE + */ +void tdls_set_ct_mode(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * tdls_set_user_tdls_enable()- Set the tdls enable from userspace + * @vdev: Pointer to vdev object + * @is_user_tdls_enable: true if tdls is enable from userspace + * + * return: NONE + */ +void tdls_set_user_tdls_enable(struct wlan_objmgr_vdev *vdev, + bool is_user_tdls_enable); +/** + * tdls_set_operation_mode() - set tdls operating mode + * @tdls_set_mode: tdls mode set params + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_set_operation_mode(struct tdls_set_mode_params *tdls_set_mode); + +/** + * tdls_notify_sta_connect() - Update tdls state for every + * connect event. + * @notify: sta connect params + * + * After every connect event in the system, check whether TDLS + * can be enabled in the system. If TDLS can be enabled, update the + * TDLS state as needed. + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_notify_sta_connect(struct tdls_sta_notify_params *notify); + +/** + * tdls_process_enable_for_vdev() - Enable TDLS in firmware and activate the + * connection tracker + * @vdev: Pointer to vdev object + * + * Return: void + */ +void tdls_process_enable_for_vdev(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * tdls_process_enable_disable_for_ml_vdev() - Enable TDLS in firmware & active + * connection tracker for all the ML vdevs belonging to same MLD as the + * given vdev + * @vdev: Pointer to vdev object + * @is_enable: Flag to indicate if operation is enable TDLS or disable TDLS + * + * Return: None + */ +void tdls_process_enable_disable_for_ml_vdev(struct wlan_objmgr_vdev *vdev, + bool is_enable); +#else +static inline +void tdls_process_enable_disable_for_ml_vdev(struct wlan_objmgr_vdev *vdev, + bool is_enable) +{} +#endif + +/** + * tdls_notify_sta_disconnect() - Update tdls state for every + * disconnect event. + * @notify: sta disconnect params + * + * After every disconnect event in the system, check whether TDLS + * can be disabled/enabled in the system and update the + * TDLS state as needed. + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_notify_sta_disconnect(struct tdls_sta_notify_params *notify); + +/** + * tdls_notify_reset_adapter() - notify reset adapter + * @vdev: vdev object + * + * Notify TDLS about the adapter reset + * + * Return: None + */ +void tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_peers_deleted_notification() - peer delete notification + * @psoc: soc object + * @vdev_id: vdev id + * + * Legacy lim layer will delete tdls peers for roaming and heart beat failures + * and notify the component about the delete event to update the tdls. + * state. + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * tdls_notify_decrement_session() - Notify the session decrement + * @psoc: psoc object manager + * + * Policy manager notify TDLS about session decrement + * + * Return: None + */ +void tdls_notify_decrement_session(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_send_update_to_fw - update tdls status info + * @tdls_vdev_obj: tdls vdev private object. + * @tdls_soc_obj: TDLS soc private object + * @tdls_prohibited: indicates whether tdls is prohibited. + * @tdls_chan_swit_prohibited: indicates whether tdls channel switch + * is prohibited. + * @sta_connect_event: indicate sta connect or disconnect event + * @session_id: session id + * + * Normally an AP does not influence TDLS connection between STAs + * associated to it. But AP may set bits for TDLS Prohibited or + * TDLS Channel Switch Prohibited in Extended Capability IE in + * Assoc/Re-assoc response to STA. So after STA is connected to + * an AP, call this function to update TDLS status as per those + * bits set in Ext Cap IE in received Assoc/Re-assoc response + * from AP. + * + * Return: void + */ +void tdls_send_update_to_fw(struct tdls_vdev_priv_obj *tdls_vdev_obj, + struct tdls_soc_priv_obj *tdls_soc_obj, + bool tdls_prohibited, + bool tdls_chan_swit_prohibited, + bool sta_connect_event, + uint8_t session_id); + +/** + * tdls_notify_increment_session() - Notify the session increment + * @psoc: psoc object manager + * + * Policy manager notify TDLS about session increment + * + * Return: None + */ +void tdls_notify_increment_session(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_get_6g_pwr_for_power_type() - get power for a 6g freq for particular + * power type + * @vdev: vdev object + * @freq: 6g freq + * @pwr_typ: power type + * + * Function that gets power for a 6g freq for particular power type + * + * Return: true or false + */ +uint32_t tdls_get_6g_pwr_for_power_type(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq, + enum supported_6g_pwr_types pwr_typ); + +/** + * tdls_is_6g_freq_allowed() - check is tdls 6ghz allowed or not + * @vdev: vdev object + * @freq: 6g freq + * + * Function determines the whether TDLS on 6ghz is allowed in the system + * + * Return: true or false + */ +bool tdls_is_6g_freq_allowed(struct wlan_objmgr_vdev *vdev, qdf_freq_t freq); + +/** + * tdls_check_is_user_tdls_enable() - Check is tdls enabled or not + * @tdls_soc_obj: TDLS soc object + * + * Return: true or false + */ +bool tdls_check_is_user_tdls_enable(struct tdls_soc_priv_obj *tdls_soc_obj); + +/** + * tdls_check_is_tdls_allowed() - check is tdls allowed or not + * @vdev: vdev object + * + * Function determines the whether TDLS allowed in the system + * + * Return: true or false + */ +bool tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_get_vdev() - Get tdls specific vdev object manager + * @psoc: wlan psoc object manager + * @dbg_id: debug id + * + * If TDLS possible, return the corresponding vdev + * to enable TDLS in the system. + * + * Return: vdev manager pointer or NULL. + */ +struct wlan_objmgr_vdev *tdls_get_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * tdls_process_policy_mgr_notification() - process policy manager notification + * @psoc: soc object manager + * + * Return: QDF_STATUS + */ +QDF_STATUS +tdls_process_policy_mgr_notification(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_process_decrement_active_session() - process policy manager decrement + * sessions. + * @psoc: soc object manager + * + * Return: QDF_STATUS + */ +QDF_STATUS +tdls_process_decrement_active_session(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_tdls_get_mlo_vdev() - get mlo vdev for tdls + * @vdev: vdev object + * @index: index of vdev in mlo list + * @dbg_id: debug id + * + * Return: vdev pointer + */ +struct wlan_objmgr_vdev *wlan_tdls_get_mlo_vdev(struct wlan_objmgr_vdev *vdev, + uint8_t index, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * wlan_tdls_release_mlo_vdev() - release mlo vdev for tdls + * @vdev: vdev object + * @dbg_id: debug id + * + * Return: void + */ +void wlan_tdls_release_mlo_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * tdls_scan_complete_event_handler() - scan complete event handler for tdls + * @vdev: vdev object + * @event: scan event + * @arg: tdls soc object + * + * Return: None + */ +void tdls_scan_complete_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg); + +/** + * tdls_set_link_unforce() - set link unforce + * @vdev: vdev object + * + * Return: void + */ +void tdls_set_link_unforce(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_scan_callback() - callback for TDLS scan operation + * @tdls_soc: tdls soc pvt object + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_scan_callback(struct tdls_soc_priv_obj *tdls_soc); + +/** + * tdls_scan_done_callback() - callback for tdls scan done event + * @tdls_soc: tdls soc object + * + * Return: Void + */ +void tdls_scan_done_callback(struct tdls_soc_priv_obj *tdls_soc); + +/** + * tdls_scan_serialization_comp_info_cb() - callback for scan start + * @vdev: VDEV on which the scan command is being processed + * @comp_info: serialize rules info + * @cmd: the serialization command + * + * Return: Void + */ +void tdls_scan_serialization_comp_info_cb(struct wlan_objmgr_vdev *vdev, + union wlan_serialization_rules_info *comp_info, + struct wlan_serialization_command *cmd); +/** + * tdls_check_and_indicate_delete_all_peers() - Check if delete all peers is + * allowed for the vdev based on current concurrency. + * @psoc: soc object + * @vdev_id: vdev id + * + * Notify tdls component to cleanup all peers based on current concurrency + * combination. + * + * Return: QDF_STATUS + */ +QDF_STATUS +tdls_check_and_indicate_delete_all_peers(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * tdls_get_opclass_from_bandwidth() - Return opclass for corresponding BW and + * channel. + * @vdev: Pointer to vdev + * @freq: Channel frequency. + * @bw_offset: Bandwidth offset. + * @reg_bw_offset: enum offset_t type bandwidth + * + * To return the opclas. + * + * Return: opclass + */ +uint8_t tdls_get_opclass_from_bandwidth(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq, uint8_t bw_offset, + uint8_t *reg_bw_offset); + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +/** + * tdls_handle_start_bss() - Handle start BSS event to act on concurrent + * session offchannel mode + * @psoc: Pointer to PSOC object + * + * Return: None + */ +QDF_STATUS tdls_handle_start_bss(struct wlan_objmgr_psoc *psoc); + +/** + * tdls_is_concurrency_allowed() - Is TDLS allowed with the current concurrency + * @psoc: Pointer to PSOC + * + * Return: True or False + */ +bool tdls_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc); +#else +static inline +QDF_STATUS tdls_handle_start_bss(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +tdls_is_concurrency_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +#endif /* WLAN_FEATURE_TDLS_CONCURRENCIES */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_mgmt.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_mgmt.c new file mode 100644 index 0000000000..f15c89d939 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_mgmt.c @@ -0,0 +1,1043 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_mgmt.c + * + * TDLS management frames implementation + */ + +#include "wlan_tdls_main.h" +#include "wlan_tdls_tgt_api.h" +#include +#include "wlan_mgmt_txrx_utils_api.h" +#include "wlan_tdls_peer.h" +#include "wlan_tdls_ct.h" +#include "wlan_tdls_mgmt.h" +#include "wlan_policy_mgr_api.h" +#include +#include +#include "wlan_mlo_link_force.h" + +static +const char *const tdls_action_frames_type[] = { "TDLS Setup Request", + "TDLS Setup Response", + "TDLS Setup Confirm", + "TDLS Teardown", + "TDLS Peer Traffic Indication", + "TDLS Channel Switch Request", + "TDLS Channel Switch Response", + "TDLS Peer PSM Request", + "TDLS Peer PSM Response", + "TDLS Peer Traffic Response", + "TDLS Discovery Request"}; + +QDF_STATUS tdls_set_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac, int8_t rssi) +{ + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_peer *curr_peer; + + if (!vdev || !mac) { + tdls_err("null pointer"); + return QDF_STATUS_E_INVAL; + } + + tdls_debug("rssi %d, peer " QDF_MAC_ADDR_FMT, + rssi, QDF_MAC_ADDR_REF(mac)); + + tdls_vdev = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_TDLS); + + if (!tdls_vdev) { + tdls_err("null tdls vdev"); + return QDF_STATUS_E_EXISTS; + } + + curr_peer = tdls_find_peer(tdls_vdev, mac); + if (!curr_peer) { + tdls_debug("null peer"); + return QDF_STATUS_E_EXISTS; + } + + curr_peer->rssi = rssi; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +struct wlan_objmgr_vdev * +tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev) +{ + return wlan_mlo_get_tdls_link_vdev(vdev); +} + +void +tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *mlo_vdev; + int i; + + /* TDLS link is selected, unforce link for other vdevs */ + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev || mlo_vdev == vdev) + continue; + + tdls_debug("try to set vdev %d to unforce", + wlan_vdev_get_id(mlo_vdev)); + tdls_set_link_unforce(mlo_vdev); + } +} + +QDF_STATUS +tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *mlo_vdev; + struct tdls_vdev_priv_obj *tdls_vdev; + struct tdls_rx_mgmt_frame *rx_mgmt; + uint32_t score; + int i; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + score = 0; + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev) + continue; + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(mlo_vdev, + WLAN_UMAC_COMP_TDLS); + tdls_vdev->link_score = 0; + rx_mgmt = tdls_vdev->rx_mgmt; + if (!rx_mgmt) + continue; + + switch (wlan_reg_freq_to_band(rx_mgmt->rx_freq)) { + case REG_BAND_2G: + score += 50; + break; + case REG_BAND_5G: + score += 70; + break; + case REG_BAND_6G: + score += 80; + break; + default: + score += 40; + break; + } + + tdls_vdev->link_score = score; + status = QDF_STATUS_SUCCESS; + } + + return status; +} + +/** + * tdls_check_wait_more() - wait until the timer timeout if necessary + * @vdev: vdev object + * + * Return: true if need to wait else false + */ +static bool tdls_check_wait_more(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *mlo_vdev; + struct tdls_vdev_priv_obj *tdls_vdev; + /* expect response number */ + int expect_num; + /* received response number */ + int receive_num; + int i; + + expect_num = 0; + receive_num = 0; + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev) + continue; + + expect_num++; + + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(mlo_vdev, + WLAN_UMAC_COMP_TDLS); + if (tdls_vdev->rx_mgmt) + receive_num++; + } + + /* +1 means the one received last has not been recorded */ + if (expect_num > receive_num + 1) + return true; + else + return false; +} + +struct wlan_objmgr_vdev * +tdls_process_mlo_choice_tdls_vdev(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_vdev *mlo_vdev; + struct wlan_objmgr_vdev *select_vdev = NULL; + struct tdls_vdev_priv_obj *tdls_vdev; + uint32_t score = 0; + int i; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev) + continue; + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(mlo_vdev, + WLAN_UMAC_COMP_TDLS); + if (score < tdls_vdev->link_score) { + select_vdev = mlo_vdev; + score = tdls_vdev->link_score; + } + } + + /* free the memory except the choice one */ + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev || mlo_vdev == select_vdev) + continue; + + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(mlo_vdev, + WLAN_UMAC_COMP_TDLS); + qdf_mem_free(tdls_vdev->rx_mgmt); + tdls_vdev->rx_mgmt = NULL; + tdls_vdev->link_score = 0; + } + + return select_vdev; +} + +static struct tdls_vdev_priv_obj +*tdls_get_correct_vdev(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_rx_mgmt_frame *rx_mgmt) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + struct tdls_link_identifier *linkid_ie; + uint8_t vdev_id; + uint8_t *ies; + uint32_t ie_len; + uint8_t elem_id_param = WLAN_ELEMID_LINK_IDENTIFIER; + + if (!tdls_vdev || !rx_mgmt) + return NULL; + + ies = &rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_TDLS_IE_OFFSET]; + ie_len = rx_mgmt->frame_len - TDLS_PUBLIC_ACTION_FRAME_TDLS_IE_OFFSET; + + linkid_ie = + (struct tdls_link_identifier *)wlan_get_ie_ptr_from_eid(elem_id_param, + ies, ie_len); + if (!linkid_ie) + return tdls_vdev; + + pdev = wlan_vdev_get_pdev(tdls_vdev->vdev); + if (!pdev) + return tdls_vdev; + + if (!wlan_get_connected_vdev_by_bssid(pdev, + linkid_ie->bssid, &vdev_id)) + return tdls_vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_TDLS_NB_ID); + if (!vdev) + return tdls_vdev; + + tdls_vdev = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + rx_mgmt->vdev_id = vdev_id; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + tdls_debug("received discovery response on vdev %d", rx_mgmt->vdev_id); + + return tdls_vdev; +} + +static bool tdls_check_peer_mlo_dev(struct wlan_objmgr_vdev *vdev, + struct tdls_rx_mgmt_frame *rx_mgmt) +{ + uint8_t *ies; + const uint8_t *ie; + uint32_t ie_len; + const uint8_t ext_id_param = WLAN_EXTN_ELEMID_MULTI_LINK; + uint8_t elem_id_param = WLAN_ELEMID_LINK_IDENTIFIER; + + if (!vdev || !rx_mgmt) + return QDF_STATUS_E_INVAL; + + ies = &rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_TDLS_IE_OFFSET]; + ie_len = rx_mgmt->frame_len - TDLS_PUBLIC_ACTION_FRAME_TDLS_IE_OFFSET; + + ie = wlan_get_ie_ptr_from_eid(elem_id_param, ies, ie_len); + if (ie) + qdf_trace_hex_dump(QDF_MODULE_ID_TDLS, QDF_TRACE_LEVEL_DEBUG, + (void *)&ie[0], ie[1] + 2); + + ie = wlan_get_ext_ie_ptr_from_ext_id(&ext_id_param, + 1, ies, ie_len); + if (ie) + return true; + + return false; +} + +static QDF_STATUS +tdls_process_mlo_rx_mgmt_sync(struct tdls_soc_priv_obj *tdls_soc, + struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_rx_mgmt_frame *rx_mgmt) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *mlo_vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + bool peer_mlo; + bool waitmore = false; + uint8_t i; + + vdev = tdls_vdev->vdev; + peer_mlo = tdls_check_peer_mlo_dev(vdev, rx_mgmt); + if (!peer_mlo) { + mlo_dev_ctx = vdev->mlo_dev_ctx; + /* stop all timers */ + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev) + continue; + + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(mlo_vdev, + WLAN_UMAC_COMP_TDLS); + tdls_vdev->discovery_sent_cnt = 0; + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &tdls_vdev->peer_discovery_timer)) { + qdf_mc_timer_stop( + &tdls_vdev->peer_discovery_timer); + qdf_atomic_dec(&tdls_soc->timer_cnt); + } + } + tdls_debug("peer is legacy device, timer_cnt %d", + qdf_atomic_read(&tdls_soc->timer_cnt)); + + status = QDF_STATUS_E_INVAL; + } else { + tdls_debug("peer is mlo device, timer_cnt %d", + qdf_atomic_read(&tdls_soc->timer_cnt)); + + /* If peer is MLD, it uses ml mac address to send the + * disconvery response, it needs to find out the + * corresponding vdev per the bssid in link identifier ie. + */ + tdls_vdev = tdls_get_correct_vdev(tdls_vdev, rx_mgmt); + status = QDF_STATUS_TDLS_MLO_SYNC; + if (!tdls_vdev || tdls_vdev->rx_mgmt) { + tdls_err("rx dup tdls discovery resp on same vdev."); + goto exit; + } + + if (qdf_atomic_read(&tdls_soc->timer_cnt) == 1) + waitmore = tdls_check_wait_more(vdev); + + if (waitmore) { + /* do not stop the timer */ + tdls_debug("wait more tdls response"); + } else { + tdls_vdev->discovery_sent_cnt = 0; + qdf_mc_timer_stop(&tdls_vdev->peer_discovery_timer); + qdf_atomic_dec(&tdls_soc->timer_cnt); + } + + tdls_vdev->rx_mgmt = qdf_mem_malloc_atomic(sizeof(*rx_mgmt) + + rx_mgmt->frame_len); + if (tdls_vdev->rx_mgmt) { + tdls_vdev->rx_mgmt->frame_len = rx_mgmt->frame_len; + tdls_vdev->rx_mgmt->rx_freq = rx_mgmt->rx_freq; + tdls_vdev->rx_mgmt->vdev_id = rx_mgmt->vdev_id; + tdls_vdev->rx_mgmt->frm_type = rx_mgmt->frm_type; + tdls_vdev->rx_mgmt->rx_rssi = rx_mgmt->rx_rssi; + qdf_mem_copy(tdls_vdev->rx_mgmt->buf, + rx_mgmt->buf, rx_mgmt->frame_len); + } else { + tdls_err("alloc rx mgmt buf error"); + } + + if (qdf_atomic_read(&tdls_soc->timer_cnt) == 0) { + tdls_process_mlo_cal_tdls_link_score(vdev); + status = QDF_STATUS_SUCCESS; + } + } + +exit: + return status; +} + +void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag) +{ + uint8_t i; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *mlo_vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + bool is_mlo_vdev; + struct ml_nlink_change_event data; + QDF_STATUS status; + + if (!vdev) + return; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (!is_mlo_vdev) + return; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + qdf_mem_zero(&data, sizeof(data)); + + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!mlo_vdev) + continue; + + /* flag: true means no force all vdevs, + * false means except the current one + */ + if (!flag && (mlo_vdev == vdev)) + continue; + data.evt.tdls.link_bitmap |= + 1 << wlan_vdev_get_link_id(mlo_vdev); + data.evt.tdls.mlo_vdev_lst[data.evt.tdls.vdev_count] = + wlan_vdev_get_id(mlo_vdev); + data.evt.tdls.vdev_count++; + } + + data.evt.tdls.mode = MLO_LINK_FORCE_MODE_NO_FORCE; + data.evt.tdls.reason = MLO_LINK_FORCE_REASON_TDLS; + status = ml_nlink_conn_change_notify(psoc, + wlan_vdev_get_id(vdev), + ml_nlink_tdls_request_evt, + &data); +} +#else +struct wlan_objmgr_vdev * +tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev) +{ + return NULL; +} + +void +tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev) +{ +} + +QDF_STATUS +tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +struct wlan_objmgr_vdev * +tdls_process_mlo_choice_tdls_vdev(struct wlan_objmgr_vdev *vdev) +{ + return NULL; +} + +static struct tdls_vdev_priv_obj +*tdls_get_correct_vdev(struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_rx_mgmt_frame *rx_mgmt) +{ + return NULL; +} + +static QDF_STATUS +tdls_process_mlo_rx_mgmt_sync(struct tdls_soc_priv_obj *tdls_soc, + struct tdls_vdev_priv_obj *tdls_vdev, + struct tdls_rx_mgmt_frame *rx_mgmt) +{ + return QDF_STATUS_SUCCESS; +} + +void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag) +{ +} +#endif + +static bool +tdls_needs_wait_discovery_response(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *tdls_soc) +{ + bool is_mlo_vdev; + bool wait = false; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev && qdf_atomic_read(&tdls_soc->timer_cnt)) + wait = true; + + return wait; +} + +/** + * tdls_process_rx_mgmt() - process tdls rx mgmt frames + * @rx_mgmt_event: tdls rx mgmt event + * @tdls_vdev: tdls vdev object + * + * Return: QDF_STATUS + */ +static QDF_STATUS tdls_process_rx_mgmt( + struct tdls_rx_mgmt_event *rx_mgmt_event, + struct tdls_vdev_priv_obj *tdls_vdev) +{ + struct tdls_rx_mgmt_frame *rx_mgmt; + struct tdls_soc_priv_obj *tdls_soc_obj; + uint8_t *mac; + enum tdls_actioncode action_frame_type; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *tdls_link_vdev; + bool tdls_vdev_select = false; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (!rx_mgmt_event) + return QDF_STATUS_E_INVAL; + + tdls_soc_obj = rx_mgmt_event->tdls_soc_obj; + rx_mgmt = rx_mgmt_event->rx_mgmt; + + if (!tdls_soc_obj || !rx_mgmt) { + tdls_err("invalid psoc object or rx mgmt"); + return QDF_STATUS_E_INVAL; + } + + vdev = tdls_vdev->vdev; + tdls_debug("received mgmt on vdev %d", wlan_vdev_get_id(vdev)); + tdls_debug("soc:%pK, frame_len:%d, rx_freq:%d, vdev_id:%d, frm_type:%d, rx_rssi:%d, buf:%pK", + tdls_soc_obj->soc, rx_mgmt->frame_len, + rx_mgmt->rx_freq, rx_mgmt->vdev_id, rx_mgmt->frm_type, + rx_mgmt->rx_rssi, rx_mgmt->buf); + + if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET + 1] == + TDLS_PUBLIC_ACTION_DISC_RESP) { + if (tdls_needs_wait_discovery_response(vdev, tdls_soc_obj)) { + status = tdls_process_mlo_rx_mgmt_sync(tdls_soc_obj, + tdls_vdev, + rx_mgmt); + if (status == QDF_STATUS_TDLS_MLO_SYNC) { + return QDF_STATUS_SUCCESS; + } else if (status == QDF_STATUS_SUCCESS) { + vdev = tdls_process_mlo_choice_tdls_vdev(vdev); + if (!vdev) + return QDF_STATUS_SUCCESS; + tdls_vdev = + wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + if (!tdls_vdev) + return QDF_STATUS_E_EXISTS; + rx_mgmt = tdls_vdev->rx_mgmt; + tdls_vdev_select = true; + tdls_debug("choice vdev %d as tdls vdev", + wlan_vdev_get_id(vdev)); + } else { + tdls_vdev = tdls_get_correct_vdev(tdls_vdev, + rx_mgmt); + if (!tdls_vdev) + return QDF_STATUS_SUCCESS; + vdev = tdls_vdev->vdev; + } + } else { + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + tdls_link_vdev = + tdls_mlo_get_tdls_link_vdev(vdev); + tdls_vdev = + tdls_get_correct_vdev(tdls_vdev, rx_mgmt); + if (!tdls_link_vdev || !tdls_vdev) { + tdls_debug("not expected frame"); + return QDF_STATUS_SUCCESS; + } + if (tdls_link_vdev != tdls_vdev->vdev) { + tdls_debug("not forward to userspace"); + return QDF_STATUS_SUCCESS; + } + rx_mgmt->vdev_id = + wlan_vdev_get_id(tdls_link_vdev); + vdev = tdls_link_vdev; + } + } + + /* this is mld mac address for mlo case*/ + mac = &rx_mgmt->buf[TDLS_80211_PEER_ADDR_OFFSET]; + tdls_notice("[TDLS] TDLS Discovery Response," + QDF_MAC_ADDR_FMT " RSSI[%d] <--- OTA", + QDF_MAC_ADDR_REF(mac), rx_mgmt->rx_rssi); + + tdls_debug("discovery resp on vdev %d", wlan_vdev_get_id(vdev)); + tdls_recv_discovery_resp(tdls_vdev, mac); + tdls_set_rssi(tdls_vdev->vdev, mac, rx_mgmt->rx_rssi); + } + + if (rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET] == + TDLS_ACTION_FRAME) { + action_frame_type = + rx_mgmt->buf[TDLS_PUBLIC_ACTION_FRAME_OFFSET + 1]; + if (action_frame_type >= TDLS_ACTION_FRAME_TYPE_MAX) { + tdls_debug("[TDLS] unknown[%d] <--- OTA", + action_frame_type); + } else { + tdls_notice("[TDLS] %s <--- OTA", + tdls_action_frames_type[action_frame_type]); + } + } + + /* tdls_soc_obj->tdls_rx_cb ==> wlan_cfg80211_tdls_rx_callback() */ + if (tdls_soc_obj && tdls_soc_obj->tdls_rx_cb) + tdls_soc_obj->tdls_rx_cb(tdls_soc_obj->tdls_rx_cb_data, + rx_mgmt); + else + tdls_debug("rx mgmt, but no valid up layer callback"); + + if (tdls_vdev_select && tdls_vdev->rx_mgmt) { + qdf_mem_free(tdls_vdev->rx_mgmt); + tdls_vdev->rx_mgmt = NULL; + tdls_vdev->link_score = 0; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_rx_mgmt_event *tdls_rx; + struct tdls_vdev_priv_obj *tdls_vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!(msg->bodyptr)) { + tdls_err("invalid message body"); + return QDF_STATUS_E_INVAL; + } + + tdls_rx = (struct tdls_rx_mgmt_event *) msg->bodyptr; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(tdls_rx->tdls_soc_obj->soc, + tdls_rx->rx_mgmt->vdev_id, WLAN_TDLS_NB_ID); + + if (vdev) { + tdls_debug("tdls rx mgmt frame received"); + tdls_vdev = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + if (tdls_vdev) + status = tdls_process_rx_mgmt(tdls_rx, tdls_vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + } + + qdf_mem_free(tdls_rx->rx_mgmt); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + return status; +} + +QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, + bool isregister) +{ + struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info; + QDF_STATUS status; + int num_of_entries; + + tdls_debug("psoc:%pK, is register rx:%d", psoc, isregister); + + frm_cb_info.frm_type = MGMT_ACTION_TDLS_DISCRESP; + frm_cb_info.mgmt_rx_cb = tgt_tdls_mgmt_frame_rx_cb; + num_of_entries = 1; + + if (isregister) + status = wlan_mgmt_txrx_register_rx_cb(psoc, + WLAN_UMAC_COMP_TDLS, &frm_cb_info, + num_of_entries); + else + status = wlan_mgmt_txrx_deregister_rx_cb(psoc, + WLAN_UMAC_COMP_TDLS, &frm_cb_info, + num_of_entries); + + return status; +} + +static QDF_STATUS +tdls_internal_send_mgmt_tx_done(struct tdls_action_frame_request *req, + QDF_STATUS status) +{ + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_osif_indication indication; + + if (!req || !req->vdev) + return QDF_STATUS_E_NULL_VALUE; + + indication.status = status; + indication.vdev = req->vdev; + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(req->vdev); + if (tdls_soc_obj && tdls_soc_obj->tdls_event_cb) + tdls_soc_obj->tdls_event_cb(tdls_soc_obj->tdls_evt_cb_data, + TDLS_EVENT_MGMT_TX_ACK_CNF, &indication); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tdls_activate_send_mgmt_request_flush_cb( + struct scheduler_msg *msg) +{ + struct tdls_send_mgmt_request *tdls_mgmt_req; + + tdls_mgmt_req = msg->bodyptr; + + qdf_mem_free(tdls_mgmt_req); + msg->bodyptr = NULL; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +tdls_activate_send_mgmt_request(struct tdls_action_frame_request *action_req) +{ + struct tdls_soc_priv_obj *tdls_soc_obj; + QDF_STATUS status; + struct tdls_send_mgmt_request *tdls_mgmt_req; + struct wlan_objmgr_peer *peer; + struct scheduler_msg msg = {0}; + struct tdls_vdev_priv_obj *tdls_vdev; + + if (!action_req || !action_req->vdev) + return QDF_STATUS_E_NULL_VALUE; + + tdls_soc_obj = wlan_vdev_get_tdls_soc_obj(action_req->vdev); + if (!tdls_soc_obj) { + status = QDF_STATUS_E_NULL_VALUE; + goto release_cmd; + } + + tdls_mgmt_req = qdf_mem_malloc(sizeof(struct tdls_send_mgmt_request) + + action_req->tdls_mgmt.len); + if (!tdls_mgmt_req) { + status = QDF_STATUS_E_NOMEM; + goto release_cmd; + } + + tdls_debug("session_id %d " + "tdls_mgmt.dialog %d " + "tdls_mgmt.frame_type %d " + "tdls_mgmt.status_code %d " + "tdls_mgmt.responder %d " + "tdls_mgmt.peer_capability %d", + action_req->session_id, + action_req->tdls_mgmt.dialog, + action_req->tdls_mgmt.frame_type, + action_req->tdls_mgmt.status_code, + action_req->tdls_mgmt.responder, + action_req->tdls_mgmt.peer_capability); + + tdls_mgmt_req->session_id = action_req->session_id; + tdls_mgmt_req->req_type = action_req->tdls_mgmt.frame_type; + tdls_mgmt_req->dialog = action_req->tdls_mgmt.dialog; + tdls_mgmt_req->status_code = action_req->tdls_mgmt.status_code; + tdls_mgmt_req->responder = action_req->tdls_mgmt.responder; + tdls_mgmt_req->peer_capability = action_req->tdls_mgmt.peer_capability; + + peer = wlan_objmgr_vdev_try_get_bsspeer(action_req->vdev, + WLAN_TDLS_SB_ID); + if (!peer) { + tdls_err("bss peer is null"); + qdf_mem_free(tdls_mgmt_req); + status = QDF_STATUS_E_NULL_VALUE; + goto release_cmd; + } + + qdf_mem_copy(tdls_mgmt_req->bssid.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID); + + qdf_mem_copy(tdls_mgmt_req->peer_mac.bytes, + action_req->tdls_mgmt.peer_mac.bytes, QDF_MAC_ADDR_SIZE); + + if (action_req->tdls_mgmt.len) { + qdf_mem_copy(tdls_mgmt_req->add_ie, action_req->tdls_mgmt.buf, + action_req->tdls_mgmt.len); + } + + tdls_mgmt_req->length = sizeof(struct tdls_send_mgmt_request) + + action_req->tdls_mgmt.len; + if (action_req->use_default_ac) + tdls_mgmt_req->ac = WIFI_AC_VI; + else + tdls_mgmt_req->ac = WIFI_AC_BK; + + if (wlan_vdev_mlme_is_mlo_vdev(action_req->vdev) && + !tdls_mlo_get_tdls_link_vdev(action_req->vdev) && + tdls_mgmt_req->req_type == TDLS_DISCOVERY_REQUEST) { + tdls_vdev = wlan_vdev_get_tdls_vdev_obj(action_req->vdev); + if (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state( + &tdls_vdev->peer_discovery_timer)) { + tdls_timer_restart(tdls_vdev->vdev, + &tdls_vdev->peer_discovery_timer, + tdls_vdev->threshold_config.tx_period_t - + TDLS_DISCOVERY_TIMEOUT_ERE_UPDATE); + qdf_atomic_inc(&tdls_soc_obj->timer_cnt); + } else { + qdf_mem_free(tdls_mgmt_req); + status = QDF_STATUS_E_NULL_VALUE; + goto release_cmd; + } + } + + /* Send the request to PE. */ + qdf_mem_zero(&msg, sizeof(msg)); + + tdls_debug("sending TDLS Mgmt Frame req to PE "); + tdls_mgmt_req->message_type = tdls_soc_obj->tdls_send_mgmt_req; + + msg.type = tdls_soc_obj->tdls_send_mgmt_req; + msg.bodyptr = tdls_mgmt_req; + msg.flush_callback = tdls_activate_send_mgmt_request_flush_cb; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(tdls_mgmt_req); + +release_cmd: + /*update tdls nss infornation based on action code */ + tdls_reset_nss(tdls_soc_obj, action_req->chk_frame.action_code); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_internal_send_mgmt_tx_done(action_req, status); + tdls_release_serialization_command(action_req->vdev, + WLAN_SER_CMD_TDLS_SEND_MGMT); + } + + return status; +} + +static QDF_STATUS +tdls_send_mgmt_serialize_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + struct tdls_action_frame_request *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!cmd || !cmd->umac_cmd) { + tdls_err("invalid params cmd: %pK, ", cmd); + return QDF_STATUS_E_NULL_VALUE; + } + req = cmd->umac_cmd; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + /* command moved to active list */ + status = tdls_activate_send_mgmt_request(req); + break; + + case WLAN_SER_CB_CANCEL_CMD: + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + /* command removed from pending list. + * notify status complete with failure + */ + status = tdls_internal_send_mgmt_tx_done(req, + QDF_STATUS_E_FAILURE); + break; + + case WLAN_SER_CB_RELEASE_MEM_CMD: + /* command successfully completed. + * release tdls_action_frame_request memory + */ + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + break; + + default: + /* Do nothing but logging */ + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *mlo_tdls_vdev; + bool is_mlo_vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ml_nlink_change_event data; + uint8_t num_ml_sta = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(req->vdev); + if (!is_mlo_vdev) + return status; + + psoc = wlan_vdev_get_psoc(req->vdev); + if (!psoc) { + tdls_err("psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + + if (req->tdls_mgmt.frame_type == TDLS_DISCOVERY_RESPONSE || + req->tdls_mgmt.frame_type == TDLS_DISCOVERY_REQUEST) { + mlo_tdls_vdev = wlan_mlo_get_tdls_link_vdev(req->vdev); + if (mlo_tdls_vdev) + return status; + + status = policy_mgr_is_ml_links_in_mcc_allowed( + psoc, req->vdev, + ml_sta_vdev_lst, + &num_ml_sta); + if (QDF_IS_STATUS_SUCCESS(status)) { + tdls_err("ML STA Links in MCC, so don't send the TDLS frames"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&data, sizeof(data)); + data.evt.tdls.link_bitmap = + 1 << wlan_vdev_get_link_id(req->vdev); + data.evt.tdls.mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev); + data.evt.tdls.vdev_count = 1; + data.evt.tdls.mode = MLO_LINK_FORCE_MODE_ACTIVE; + data.evt.tdls.reason = MLO_LINK_FORCE_REASON_TDLS; + status = + ml_nlink_conn_change_notify(psoc, + wlan_vdev_get_id(req->vdev), + ml_nlink_tdls_request_evt, + &data); + if (status == QDF_STATUS_SUCCESS || + status == QDF_STATUS_E_PENDING) + req->link_active = true; + } else if (req->tdls_mgmt.frame_type == TDLS_MAX_ACTION_CODE) { + qdf_mem_zero(&data, sizeof(data)); + data.evt.tdls.link_bitmap = + 1 << wlan_vdev_get_link_id(req->vdev); + data.evt.tdls.mlo_vdev_lst[0] = wlan_vdev_get_id(req->vdev); + data.evt.tdls.vdev_count = 1; + data.evt.tdls.mode = MLO_LINK_FORCE_MODE_NO_FORCE; + data.evt.tdls.reason = MLO_LINK_FORCE_REASON_TDLS; + status = + ml_nlink_conn_change_notify(psoc, + wlan_vdev_get_id(req->vdev), + ml_nlink_tdls_request_evt, + &data); + } + if (status == QDF_STATUS_E_PENDING) + status = QDF_STATUS_SUCCESS; + + return status; +} +#else +QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS tdls_process_mgmt_req( + struct tdls_action_frame_request *tdls_mgmt_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_serialization_command cmd = {0, }; + enum wlan_serialization_status ser_cmd_status; + + /* If connected and in Infra. Only then allow this */ + status = tdls_validate_mgmt_request(tdls_mgmt_req); + if (status != QDF_STATUS_SUCCESS) { + status = tdls_internal_send_mgmt_tx_done(tdls_mgmt_req, + status); + goto error_mgmt; + } + + status = tdls_set_link_mode(tdls_mgmt_req); + if (status != QDF_STATUS_SUCCESS) { + tdls_err("failed to set link:%d active", + wlan_vdev_get_link_id(tdls_mgmt_req->vdev)); + status = tdls_internal_send_mgmt_tx_done(tdls_mgmt_req, + status); + goto error_mgmt; + } + + /* update the responder, status code information + * after the cmd validation + */ + tdls_mgmt_req->tdls_mgmt.responder = + !tdls_mgmt_req->chk_frame.responder; + tdls_mgmt_req->tdls_mgmt.status_code = + tdls_mgmt_req->chk_frame.status_code; + + cmd.cmd_type = WLAN_SER_CMD_TDLS_SEND_MGMT; + /* Cmd Id not applicable for non scan cmds */ + cmd.cmd_id = 0; + cmd.cmd_cb = tdls_send_mgmt_serialize_callback; + cmd.umac_cmd = tdls_mgmt_req; + cmd.source = WLAN_UMAC_COMP_TDLS; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT; + + cmd.vdev = tdls_mgmt_req->vdev; + cmd.is_blocking = true; + + ser_cmd_status = wlan_serialization_request(&cmd); + tdls_debug("wlan_serialization_request status:%d", ser_cmd_status); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list.Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + case WLAN_SER_CMD_DENIED_LIST_FULL: + case WLAN_SER_CMD_DENIED_RULES_FAILED: + case WLAN_SER_CMD_DENIED_UNSPECIFIED: + status = QDF_STATUS_E_FAILURE; + goto error_mgmt; + default: + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + goto error_mgmt; + } + return status; + +error_mgmt: + wlan_objmgr_vdev_release_ref(tdls_mgmt_req->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(tdls_mgmt_req); + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_mgmt.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_mgmt.h new file mode 100644 index 0000000000..5d29b60d13 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_mgmt.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_mgmt.h + * + * TDLS management frames include file + */ + +#ifndef _WLAN_TDLS_MGMT_H_ +#define _WLAN_TDLS_MGMT_H_ + +#include "wlan_tdls_cmds_process.h" + +#define TDLS_PUBLIC_ACTION_FRAME_OFFSET 24 +/* TDLS_PUBLIC_ACTION_FRAME_OFFSET(category[1]) + action[1] + dialog[1] + * + cap[2] + */ +#define TDLS_PUBLIC_ACTION_FRAME_TDLS_IE_OFFSET 29 +#define TDLS_PUBLIC_ACTION_FRAME 4 +#define TDLS_PUBLIC_ACTION_DISC_RESP 14 +#define TDLS_ACTION_FRAME 12 +#define TDLS_80211_PEER_ADDR_OFFSET (TDLS_PUBLIC_ACTION_FRAME + \ + QDF_MAC_ADDR_SIZE) +#define TDLS_ACTION_FRAME_TYPE_MAX 11 + +/** + * struct tdls_link_identifier - tdls link identifier ie + * @id: element id + * @len: length + * @bssid: bssid + * @initsta: the mac address of initiator + * @respsta: the mac address of responder + */ +struct tdls_link_identifier { + uint8_t id; + uint8_t len; + uint8_t bssid[6]; + uint8_t initsta[6]; + uint8_t respsta[6]; +}; + +/** + * struct tdls_rx_mgmt_event - tdls rx mgmt frame event + * @tdls_soc_obj: tdls soc private object + * @rx_mgmt: tdls rx mgmt frame structure + */ +struct tdls_rx_mgmt_event { + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_rx_mgmt_frame *rx_mgmt; +}; + +/** + * tdls_process_mgmt_req() - send a TDLS mgmt request to serialize module + * @tdls_mgmt_req: tdls management request + * + * TDLS request API, called from cfg80211 to send a TDLS frame in + * serialized manner to PE + * + *Return: QDF_STATUS + */ +QDF_STATUS tdls_process_mgmt_req( + struct tdls_action_frame_request *tdls_mgmt_req); + +/** + * tdls_process_mlo_cal_tdls_link_score() - process mlo cal tdls link + * @vdev: object manager vdev + * + * Converts rx tdls frame freq to a link score and stores the score + * in relative tdls_vdev object. + * + *Return: QDF_STATUS + */ +QDF_STATUS +tdls_process_mlo_cal_tdls_link_score(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_mlo_get_tdls_link_vdev() - wrapper function + * @vdev: vdev object + * + * Return: tdls vdev + */ +struct wlan_objmgr_vdev * +tdls_mlo_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_set_remain_links_unforce() - unforce links + * @vdev: vdev object + * + * Return: void + */ +void tdls_set_remain_links_unforce(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_mgmt_rx_ops() - register or unregister rx callback + * @psoc: psoc object + * @isregister: register if true, unregister if false + * + * This function registers or unregisters rx callback to mgmt txrx + * component. + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_mgmt_rx_ops(struct wlan_objmgr_psoc *psoc, + bool isregister); + +/** + * tdls_process_rx_frame() - process tdls rx frames + * @msg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_process_rx_frame(struct scheduler_msg *msg); + +/** + * tdls_set_rssi() - Set TDLS RSSI on peer given by mac + * @vdev: vdev object + * @mac: MAC address of Peer + * @rssi: rssi value + * + * Set RSSI on TDSL peer + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_set_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac, int8_t rssi); + +/** + * tdls_process_mlo_choice_tdls_vdev() - choice one vdev for tdls vdev + * @vdev: object manager vdev + * + * Return: pointer of vdev object + */ +struct wlan_objmgr_vdev * +tdls_process_mlo_choice_tdls_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * tdls_set_no_force_vdev() - set no force for the vdev + * @vdev: object manager vdev + * @flag: true, set all vdev as no force; false, except the current one. + * + * Return: void + */ +void tdls_set_no_force_vdev(struct wlan_objmgr_vdev *vdev, bool flag); + +/** + * tdls_set_link_mode() - force active or unfore link for MLO case + * @req: the pointer of tdls_action_frame_request + * + * Return: QDF_STATUS + */ +QDF_STATUS tdls_set_link_mode(struct tdls_action_frame_request *req); +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c new file mode 100644 index 0000000000..d8043c01f0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.c @@ -0,0 +1,1267 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_peer.c + * + * TDLS peer basic operations + */ +#include "wlan_tdls_main.h" +#include "wlan_tdls_peer.h" +#include +#include +#include +#include "wlan_reg_ucfg_api.h" +#include +#include "wlan_policy_mgr_api.h" + +static uint8_t calculate_hash_key(const uint8_t *macaddr) +{ + uint8_t i, key; + + for (i = 0, key = 0; i < 6; i++) + key ^= macaddr[i]; + + return key % WLAN_TDLS_PEER_LIST_SIZE; +} + +struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr) +{ + uint8_t key; + QDF_STATUS status; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + + key = calculate_hash_key(macaddr); + head = &vdev_obj->peer_list[key]; + + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + if (WLAN_ADDR_EQ(&peer->peer_mac, macaddr) + == QDF_STATUS_SUCCESS) { + return peer; + } + status = qdf_list_peek_next(head, p_node, &p_node); + } + + tdls_debug("no tdls peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(macaddr)); + return NULL; +} + +/** + * tdls_find_peer_handler() - helper function for tdls_find_all_peer + * @psoc: soc object + * @obj: vdev object + * @arg: used to keep search peer parameters + * + * Return: None. + */ +static void +tdls_find_peer_handler(struct wlan_objmgr_psoc *psoc, void *obj, void *arg) +{ + struct wlan_objmgr_vdev *vdev = obj; + struct tdls_search_peer_param *tdls_param = arg; + struct tdls_vdev_priv_obj *vdev_obj; + + if (tdls_param->peer) + return; + + if (!vdev) { + tdls_err("invalid vdev"); + return; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE && + wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE) + return; + + vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + if (!vdev_obj) + return; + + tdls_param->peer = tdls_find_peer(vdev_obj, tdls_param->macaddr); +} + +struct tdls_peer * +tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr) +{ + struct tdls_search_peer_param tdls_search_param; + struct wlan_objmgr_psoc *psoc; + + if (!soc_obj) { + tdls_err("tdls soc object is NULL"); + return NULL; + } + + psoc = soc_obj->soc; + if (!psoc) { + tdls_err("psoc is NULL"); + return NULL; + } + tdls_search_param.macaddr = macaddr; + tdls_search_param.peer = NULL; + + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + tdls_find_peer_handler, + &tdls_search_param, 0, WLAN_TDLS_NB_ID); + + return tdls_search_param.peer; +} + +uint8_t tdls_find_opclass(struct wlan_objmgr_psoc *psoc, uint8_t channel, + uint8_t bw_offset) +{ + char country[REG_ALPHA2_LEN + 1]; + QDF_STATUS status; + + if (!psoc) { + tdls_err("psoc is NULL"); + return 0; + } + + status = wlan_reg_read_default_country(psoc, country); + if (QDF_IS_STATUS_ERROR(status)) + return 0; + + return wlan_reg_dmn_get_opclass_from_channel(country, channel, + bw_offset); +} + +#ifdef WLAN_FEATURE_11AX +qdf_freq_t tdls_get_offchan_freq(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *soc_obj) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + qdf_freq_t pref_freq, pref_6g_freq; + uint8_t pref_non6g_ch; + + if (!pdev) { + tdls_err("pdev is NULL"); + return 0; + } + + pref_6g_freq = soc_obj->tdls_configs.tdls_pre_off_chan_freq_6g; + pref_non6g_ch = soc_obj->tdls_configs.tdls_pre_off_chan_num; + + /* + * Fill preferred offchannel frequency here. If TDLS on 6 GHz is + * allowed then fill pref 6 GHz frequency + * Otherwise, fill 5 GHz preferred frequency + */ + if (pref_6g_freq && tdls_is_6g_freq_allowed(vdev, pref_6g_freq)) + pref_freq = pref_6g_freq; + else + pref_freq = wlan_reg_legacy_chan_to_freq(pdev, pref_non6g_ch); + + return pref_freq; +} + +#else +qdf_freq_t tdls_get_offchan_freq(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *soc_obj) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + uint32_t pref_leg_chan = soc_obj->tdls_configs.tdls_pre_off_chan_num; + + if (!pdev) { + tdls_err("pdev is NULL"); + return 0; + } + + return wlan_reg_legacy_chan_to_freq(pdev, pref_leg_chan); +} +#endif + +uint32_t tdls_get_offchan_bw(struct tdls_soc_priv_obj *soc_obj, + qdf_freq_t off_chan_freq) +{ + uint32_t pre_off_chan_bw; + + if (wlan_reg_is_5ghz_ch_freq(off_chan_freq) && + CHECK_BIT(soc_obj->tdls_configs.tdls_pre_off_chan_bw, + BW_160_OFFSET_BIT)) + pre_off_chan_bw = soc_obj->tdls_configs.tdls_pre_off_chan_bw & + ~(1 << BW_160_OFFSET_BIT); + else + pre_off_chan_bw = soc_obj->tdls_configs.tdls_pre_off_chan_bw; + + return pre_off_chan_bw; +} + +static void tdls_fill_pref_off_chan_info(struct tdls_vdev_priv_obj *vdev_obj, + struct tdls_soc_priv_obj *soc_obj, + struct tdls_peer *peer) +{ + peer->pref_off_chan_freq = tdls_get_offchan_freq(vdev_obj->vdev, + soc_obj); + peer->pref_off_chan_width = tdls_get_offchan_bw(soc_obj, + peer->pref_off_chan_freq); + tdls_debug("Pref off channel freq %d chan width %d", + peer->pref_off_chan_freq, peer->pref_off_chan_width); +} + +static QDF_STATUS +tdls_remove_first_idle_peer(qdf_list_t *head) { + QDF_STATUS status; + qdf_list_node_t *p_node; + struct tdls_peer *peer; + + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + if (peer && peer->link_status == TDLS_LINK_IDLE) { + if (peer->is_peer_idle_timer_initialised) { + tdls_debug(QDF_MAC_ADDR_FMT + ": destroy idle timer ", + QDF_MAC_ADDR_REF( + peer->peer_mac.bytes)); + qdf_mc_timer_stop(&peer->peer_idle_timer); + qdf_mc_timer_destroy(&peer->peer_idle_timer); + } + + tdls_debug(QDF_MAC_ADDR_FMT ": free peer", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes)); + qdf_list_remove_node(head, p_node); + qdf_mem_free(peer); + + return status; + } + status = qdf_list_peek_next(head, p_node, &p_node); + } + + return QDF_STATUS_E_INVAL; +} + +/** + * tdls_add_peer() - add TDLS peer in TDLS vdev object + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of peer + * + * Allocate memory for the new peer, and add it to hash table. + * + * Return: new added TDLS peer, NULL if failed. + */ +static struct tdls_peer *tdls_add_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr) +{ + struct tdls_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + uint8_t key = 0; + qdf_list_t *head; + uint8_t reg_bw_offset; + + peer = qdf_mem_malloc(sizeof(*peer)); + if (!peer) + return NULL; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + if (!soc_obj) { + tdls_err("NULL tdls soc object"); + return NULL; + } + + key = calculate_hash_key(macaddr); + head = &vdev_obj->peer_list[key]; + + qdf_mem_copy(&peer->peer_mac, macaddr, sizeof(peer->peer_mac)); + peer->vdev_priv = vdev_obj; + + tdls_fill_pref_off_chan_info(vdev_obj, soc_obj, peer); + peer->op_class_for_pref_off_chan = + tdls_get_opclass_from_bandwidth( + vdev_obj->vdev, peer->pref_off_chan_freq, + peer->pref_off_chan_width, + ®_bw_offset); + + peer->valid_entry = false; + + if (qdf_list_size(head) >= qdf_list_max_size(head)) { + if (QDF_IS_STATUS_ERROR(tdls_remove_first_idle_peer(head))) { + tdls_err("list size exceed max and remove idle peer failed, key %d", + key); + qdf_mem_free(peer); + return NULL; + } + } + + qdf_list_insert_back(head, &peer->node); + + tdls_debug("add tdls peer: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(macaddr)); + return peer; +} + +struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr) +{ + struct tdls_peer *peer; + + peer = tdls_find_peer(vdev_obj, macaddr); + if (!peer) + peer = tdls_add_peer(vdev_obj, macaddr); + + return peer; +} + +static struct tdls_peer * +tdls_find_progress_peer_in_list(qdf_list_t *head, + const uint8_t *macaddr, uint8_t skip_self) +{ + QDF_STATUS status; + struct tdls_peer *peer; + qdf_list_node_t *p_node; + + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + if (skip_self && macaddr && + WLAN_ADDR_EQ(&peer->peer_mac, macaddr) + == QDF_STATUS_SUCCESS) { + status = qdf_list_peek_next(head, p_node, &p_node); + continue; + } else if (TDLS_LINK_CONNECTING == peer->link_status) { + tdls_debug(QDF_MAC_ADDR_FMT " TDLS_LINK_CONNECTING", + QDF_MAC_ADDR_REF(peer->peer_mac.bytes)); + return peer; + } + status = qdf_list_peek_next(head, p_node, &p_node); + } + + return NULL; +} + +/** + * tdls_find_progress_peer() - find the peer with ongoing TDLS progress + * on present vdev + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of peer, if NULL check for all the peer list + * @skip_self: If true, skip this macaddr. Otherwise, check all the peer list. + * if macaddr is NULL, this argument is ignored, and check for all + * the peer list. + * + * Return: Pointer to tdls_peer if TDLS is ongoing. Otherwise return NULL. + */ +static struct tdls_peer * +tdls_find_progress_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, uint8_t skip_self) +{ + uint8_t i; + struct tdls_peer *peer; + qdf_list_t *head; + + if (!vdev_obj) { + tdls_err("invalid tdls vdev object"); + return NULL; + } + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &vdev_obj->peer_list[i]; + + peer = tdls_find_progress_peer_in_list(head, macaddr, + skip_self); + if (peer) + return peer; + } + + return NULL; +} + +/** + * tdls_find_progress_peer_handler() - helper function for tdls_is_progress + * @psoc: soc object + * @obj: vdev object + * @arg: used to keep search peer parameters + * + * Return: None. + */ +static void +tdls_find_progress_peer_handler(struct wlan_objmgr_psoc *psoc, + void *obj, void *arg) +{ + struct wlan_objmgr_vdev *vdev = obj; + struct tdls_search_progress_param *tdls_progress = arg; + struct tdls_vdev_priv_obj *vdev_obj; + + if (tdls_progress->peer) + return; + + if (!vdev) { + tdls_err("invalid vdev"); + return; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE && + wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_CLIENT_MODE) + return; + + vdev_obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TDLS); + + tdls_progress->peer = tdls_find_progress_peer(vdev_obj, + tdls_progress->macaddr, + tdls_progress->skip_self); +} + +struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, uint8_t skip_self) +{ + struct tdls_search_progress_param tdls_progress; + struct wlan_objmgr_psoc *psoc; + + if (!vdev_obj) { + tdls_err("invalid tdls vdev object"); + return NULL; + } + + psoc = wlan_vdev_get_psoc(vdev_obj->vdev); + if (!psoc) { + tdls_err("invalid psoc"); + return NULL; + } + tdls_progress.macaddr = macaddr; + tdls_progress.skip_self = skip_self; + tdls_progress.peer = NULL; + + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + tdls_find_progress_peer_handler, + &tdls_progress, 0, WLAN_TDLS_NB_ID); + + return tdls_progress.peer; +} + +struct tdls_peer * +tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj) +{ + uint16_t i; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + QDF_STATUS status; + + if (!vdev_obj) { + tdls_err("invalid tdls vdev object"); + return NULL; + } + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &vdev_obj->peer_list[i]; + + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + + if (peer && TDLS_LINK_CONNECTED == peer->link_status) { + tdls_debug(QDF_MAC_ADDR_FMT + " TDLS_LINK_CONNECTED", + QDF_MAC_ADDR_REF( + peer->peer_mac.bytes)); + return peer; + } + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + + return NULL; +} + +/** + * tdls_determine_channel_opclass() - determine channel and opclass + * @soc_obj: TDLS soc object + * @vdev_obj: TDLS vdev object + * @peer: TDLS peer + * @channel: pointer to channel + * @opclass: pointer to opclass + * + * Function determines the channel and operating class + * + * Return: None. + */ +static void tdls_determine_channel_opclass(struct tdls_soc_priv_obj *soc_obj, + struct tdls_vdev_priv_obj *vdev_obj, + struct tdls_peer *peer, + uint32_t *channel, uint32_t *opclass) +{ + uint32_t vdev_id; + enum QDF_OPMODE opmode; + struct wlan_objmgr_pdev *pdev = NULL; + struct wlan_objmgr_psoc *psoc = NULL; + enum policy_mgr_con_mode mode; + /* + * If tdls offchannel is not enabled then we provide base channel + * and in that case pass opclass as 0 since opclass is mainly needed + * for offchannel cases. + */ + if (!(TDLS_IS_OFF_CHANNEL_ENABLED( + soc_obj->tdls_configs.tdls_feature_flags)) || + soc_obj->tdls_fw_off_chan_mode != ENABLE_CHANSWITCH) { + vdev_id = wlan_vdev_get_id(vdev_obj->vdev); + opmode = wlan_vdev_mlme_get_opmode(vdev_obj->vdev); + pdev = wlan_vdev_get_pdev(vdev_obj->vdev); + psoc = wlan_pdev_get_psoc(pdev); + + mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, opmode, + vdev_id); + *channel = wlan_reg_freq_to_chan(pdev, policy_mgr_get_channel( + soc_obj->soc, + mode, + &vdev_id)); + *opclass = 0; + } else { + *channel = wlan_reg_freq_to_chan(pdev, + peer->pref_off_chan_freq); + *opclass = peer->op_class_for_pref_off_chan; + } + tdls_debug("channel:%d opclass:%d", *channel, *opclass); +} + +/** + * tdls_get_wifi_hal_state() - get TDLS wifi hal state on current peer + * @peer: TDLS peer + * @state: output parameter to store the TDLS wifi hal state + * @reason: output parameter to store the reason of the current peer + * + * Return: None. + */ +static void tdls_get_wifi_hal_state(struct tdls_peer *peer, uint32_t *state, + int32_t *reason) +{ + struct wlan_objmgr_vdev *vdev; + struct tdls_soc_priv_obj *soc_obj; + + vdev = peer->vdev_priv->vdev; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev); + if (!soc_obj) { + tdls_err("can't get tdls object"); + return; + } + + *reason = peer->reason; + + switch (peer->link_status) { + case TDLS_LINK_IDLE: + case TDLS_LINK_DISCOVERED: + case TDLS_LINK_DISCOVERING: + case TDLS_LINK_CONNECTING: + *state = QCA_WIFI_HAL_TDLS_S_ENABLED; + break; + case TDLS_LINK_CONNECTED: + if ((TDLS_IS_OFF_CHANNEL_ENABLED( + soc_obj->tdls_configs.tdls_feature_flags)) && + (soc_obj->tdls_fw_off_chan_mode == ENABLE_CHANSWITCH)) + *state = QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL; + else + *state = QCA_WIFI_HAL_TDLS_S_ENABLED; + break; + case TDLS_LINK_TEARING: + *state = QCA_WIFI_HAL_TDLS_S_DROPPED; + break; + } +} + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +/** + * tdls_get_allowed_off_channel_for_concurrency() - Get allowed off-channel + * frequency based on current concurrency. Return 0 if all frequencies are + * allowed + * @pdev: Pointer to PDEV object + * @vdev: Pointer to vdev object + * + * Return: Frequency + */ +static inline qdf_freq_t +tdls_get_allowed_off_channel_for_concurrency(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + qdf_freq_t freq = 0; + + if (!psoc) + return 0; + + if (!wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_TDLS_CONCURRENCIES_SUPPORT)) + return 0; + + if (!policy_mgr_get_allowed_tdls_offchannel_freq(psoc, vdev, &freq)) { + tdls_debug("off channel not allowed for current concurrency"); + return 0; + } + + return freq; +} +#else +static inline qdf_freq_t +tdls_get_allowed_off_channel_for_concurrency(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + return 0; +} +#endif + +/** + * tdls_extract_peer_state_param() - extract peer update params from TDLS peer + * @peer_param: output peer update params + * @peer: TDLS peer + * + * This is used when enable TDLS link + * + * Return: None. + */ +void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param, + struct tdls_peer *peer) +{ + uint16_t i, num; + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_soc_priv_obj *soc_obj; + enum channel_state ch_state; + struct wlan_objmgr_pdev *pdev; + uint32_t cur_band; + qdf_freq_t ch_freq, allowed_freq; + uint32_t tx_power = 0; + + vdev_obj = peer->vdev_priv; + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + pdev = wlan_vdev_get_pdev(vdev_obj->vdev); + if (!soc_obj || !pdev) { + tdls_err("soc_obj: %pK, pdev: %pK", soc_obj, pdev); + return; + } + + qdf_mem_zero(peer_param, sizeof(*peer_param)); + peer_param->vdev_id = wlan_vdev_get_id(vdev_obj->vdev); + + qdf_mem_copy(peer_param->peer_macaddr, + peer->peer_mac.bytes, QDF_MAC_ADDR_SIZE); + peer_param->peer_state = TDLS_PEER_STATE_CONNECTED; + peer_param->peer_cap.is_peer_responder = peer->is_responder; + peer_param->peer_cap.peer_uapsd_queue = peer->uapsd_queues; + peer_param->peer_cap.peer_max_sp = peer->max_sp; + peer_param->peer_cap.peer_buff_sta_support = peer->buf_sta_capable; + peer_param->peer_cap.peer_off_chan_support = + peer->off_channel_capable; + peer_param->peer_cap.peer_curr_operclass = 0; + peer_param->peer_cap.self_curr_operclass = + peer->op_class_for_pref_off_chan; + peer_param->peer_cap.pref_off_channum = wlan_reg_freq_to_chan(pdev, + peer->pref_off_chan_freq); + peer_param->peer_cap.pref_off_chan_bandwidth = + peer->pref_off_chan_width; + peer_param->peer_cap.opclass_for_prefoffchan = + peer->op_class_for_pref_off_chan; + peer_param->peer_cap.pref_offchan_freq = peer->pref_off_chan_freq; + + if (QDF_STATUS_SUCCESS != ucfg_reg_get_band(pdev, &cur_band)) { + tdls_err("not able get the current frequency band"); + return; + } + + if (BIT(REG_BAND_2G) == cur_band) { + tdls_err("sending the offchannel value as 0 as only 2g is supported"); + peer_param->peer_cap.pref_off_channum = 0; + peer_param->peer_cap.opclass_for_prefoffchan = 0; + peer_param->peer_cap.pref_offchan_freq = 0; + } + + ch_freq = peer->pref_off_chan_freq; + if (wlan_reg_is_dfs_for_freq(pdev, ch_freq)) { + /* + * If pref_off_chan_freq is DFS frequency, that means it is 5Ghz + * case. So, reset to default 5 GHz frequency + */ + tdls_err("Resetting TDLS off-channel from %d to %d", + peer_param->peer_cap.pref_off_channum, + WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF); + peer_param->peer_cap.pref_off_channum = + WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF; + peer_param->peer_cap.pref_offchan_freq = + WLAN_TDLS_PREFERRED_OFF_CHANNEL_FRQ_DEF; + } + + num = 0; + allowed_freq = + tdls_get_allowed_off_channel_for_concurrency(pdev, + vdev_obj->vdev); + tdls_debug("allowed freq:%u", allowed_freq); + + for (i = 0; i < peer->supported_channels_len; i++) { + ch_freq = peer->supported_chan_freq[i]; + if (allowed_freq && allowed_freq != ch_freq) + continue; + + ch_state = wlan_reg_get_channel_state_for_pwrmode( + pdev, ch_freq, + REG_CURRENT_PWR_MODE); + + if (CHANNEL_STATE_INVALID != ch_state && + !wlan_reg_is_dfs_for_freq(pdev, ch_freq) && + !wlan_reg_is_dsrc_freq(ch_freq)) { + peer_param->peer_cap.peer_chan[num].ch_freq = ch_freq; + if (!wlan_reg_is_6ghz_chan_freq(ch_freq)) { + tx_power = + wlan_reg_get_channel_reg_power_for_freq(pdev, + ch_freq); + } else { + tx_power = + tdls_get_6g_pwr_for_power_type(vdev_obj->vdev, + ch_freq, + REG_CLI_DEF_VLP); + } + peer_param->peer_cap.peer_chan[num].pwr = tx_power; + peer_param->peer_cap.peer_chan[num].dfs_set = false; + peer_param->peer_cap.peer_chanlen++; + num++; + } + } + + peer_param->peer_cap.peer_oper_classlen = + peer->supported_oper_classes_len; + for (i = 0; i < peer->supported_oper_classes_len; i++) + peer_param->peer_cap.peer_oper_class[i] = + peer->supported_oper_classes[i]; +} + +#ifdef TDLS_WOW_ENABLED +/** + * tdls_prevent_suspend(): Prevent suspend for TDLS + * @tdls_soc: TDLS soc object + * + * Acquire wake lock and prevent suspend for TDLS + * + * Return None + */ +static void tdls_prevent_suspend(struct tdls_soc_priv_obj *tdls_soc) +{ + if (tdls_soc->is_prevent_suspend) + return; + + qdf_wake_lock_acquire(&tdls_soc->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_TDLS); + qdf_runtime_pm_prevent_suspend(&tdls_soc->runtime_lock); + tdls_soc->is_prevent_suspend = true; + tdls_debug("Acquire WIFI_POWER_EVENT_WAKELOCK_TDLS"); +} + +/** + * tdls_allow_suspend(): Allow suspend for TDLS + * @tdls_soc: TDLS soc object + * + * Release wake lock and allow suspend for TDLS + * + * Return None + */ +static void tdls_allow_suspend(struct tdls_soc_priv_obj *tdls_soc) +{ + if (!tdls_soc->is_prevent_suspend) + return; + + qdf_wake_lock_release(&tdls_soc->wake_lock, + WIFI_POWER_EVENT_WAKELOCK_TDLS); + qdf_runtime_pm_allow_suspend(&tdls_soc->runtime_lock); + tdls_soc->is_prevent_suspend = false; + tdls_debug("Release WIFI_POWER_EVENT_WAKELOCK_TDLS"); +} + +/** + * tdls_update_pmo_status() - Update PMO status by TDLS status + * @tdls_vdev: TDLS vdev object + * @old_status: old link status + * @new_status: new link status + * + * Return: None. + */ +static void tdls_update_pmo_status(struct tdls_vdev_priv_obj *tdls_vdev, + enum tdls_link_state old_status, + enum tdls_link_state new_status) +{ + struct tdls_soc_priv_obj *tdls_soc; + + tdls_soc = wlan_vdev_get_tdls_soc_obj(tdls_vdev->vdev); + if (!tdls_soc) { + tdls_err("NULL psoc object"); + return; + } + + if (tdls_soc->is_drv_supported) + return; + + if ((old_status < TDLS_LINK_CONNECTING) && + (new_status == TDLS_LINK_CONNECTING)) + tdls_prevent_suspend(tdls_soc); + + if ((old_status > TDLS_LINK_IDLE) && + (new_status == TDLS_LINK_IDLE) && + (!tdls_soc->connected_peer_count) && + (!tdls_is_progress(tdls_vdev, NULL, 0))) + tdls_allow_suspend(tdls_soc); +} +#else +static void tdls_update_pmo_status(struct tdls_vdev_priv_obj *tdls_vdev, + enum tdls_link_state old_status, + enum tdls_link_state new_status) +{ +} +#endif + +void tdls_set_link_status(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *mac, + enum tdls_link_state link_status, + enum tdls_link_state_reason link_reason) +{ + uint32_t state = 0; + int32_t res = 0; + uint32_t op_class = 0; + uint32_t channel = 0; + struct tdls_peer *peer; + struct tdls_soc_priv_obj *soc_obj; + enum tdls_link_state old_status; + + peer = tdls_find_peer(vdev_obj, mac); + if (!peer) { + tdls_err("peer is NULL, can't set link status %d, reason %d", + link_status, link_reason); + return; + } + + old_status = peer->link_status; + peer->link_status = link_status; + tdls_update_pmo_status(vdev_obj, old_status, link_status); + + if (link_status >= TDLS_LINK_DISCOVERED) + peer->discovery_attempt = 0; + + if (peer->is_forced_peer && peer->state_change_notification) { + peer->reason = link_reason; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + if (!soc_obj) { + tdls_err("NULL psoc object"); + return; + } + + tdls_determine_channel_opclass(soc_obj, vdev_obj, + peer, &channel, &op_class); + tdls_get_wifi_hal_state(peer, &state, &res); + peer->state_change_notification(mac, op_class, channel, + state, res, soc_obj->soc); + } +} + +static inline char * +tdls_link_status_str(enum tdls_link_state link_status) +{ + switch (link_status) { + CASE_RETURN_STRING(TDLS_LINK_IDLE); + CASE_RETURN_STRING(TDLS_LINK_DISCOVERING); + CASE_RETURN_STRING(TDLS_LINK_DISCOVERED); + CASE_RETURN_STRING(TDLS_LINK_CONNECTING); + CASE_RETURN_STRING(TDLS_LINK_CONNECTED); + CASE_RETURN_STRING(TDLS_LINK_TEARING); + default: + return "UNKNOWN"; + } +} + +void tdls_set_peer_link_status(struct tdls_peer *peer, + enum tdls_link_state link_status, + enum tdls_link_state_reason link_reason) +{ + uint32_t state = 0; + int32_t res = 0; + uint32_t op_class = 0; + uint32_t channel = 0; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_vdev_priv_obj *vdev_obj; + enum tdls_link_state old_status; + + vdev_obj = peer->vdev_priv; + + old_status = peer->link_status; + peer->link_status = link_status; + tdls_debug("vdev:%d new state: %s old state:%s reason %d peer:" QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(vdev_obj->vdev), + tdls_link_status_str(link_status), + tdls_link_status_str(old_status), link_reason, + QDF_MAC_ADDR_REF(peer->peer_mac.bytes)); + tdls_update_pmo_status(vdev_obj, old_status, link_status); + + if (link_status >= TDLS_LINK_DISCOVERED) + peer->discovery_attempt = 0; + + if (peer->is_forced_peer && peer->state_change_notification) { + peer->reason = link_reason; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + if (!soc_obj) { + tdls_err("NULL psoc object"); + return; + } + + tdls_determine_channel_opclass(soc_obj, vdev_obj, + peer, &channel, &op_class); + tdls_get_wifi_hal_state(peer, &state, &res); + peer->state_change_notification(peer->peer_mac.bytes, + op_class, channel, state, + res, soc_obj->soc); + } +} + +static void +tdls_fill_peer_pref_offchan_bw(struct tdls_peer *peer, + uint16_t bw) +{ + if (bw < BW_160_MHZ) + peer->pref_off_chan_width &= ~(1 << BW_160_OFFSET_BIT); + + if (bw < BW_80_MHZ) + peer->pref_off_chan_width &= ~(1 << BW_80_OFFSET_BIT); + + if (bw < BW_40_MHZ) + peer->pref_off_chan_width &= ~(1 << BW_40_OFFSET_BIT); +} + +static void tdls_update_off_chan_peer_caps(struct tdls_vdev_priv_obj *vdev_obj, + struct tdls_soc_priv_obj *soc_obj, + struct tdls_peer *peer) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev_obj->vdev); + qdf_freq_t ini_pref_6g_freq, ini_pref_non6g_freq, peer_freq; + enum channel_enum peer_chan; + qdf_freq_t peer_5g_freq = 0, peer_6g_freq = 0; + bool is_6g_support = false; + bool peer_6g_supportd = false; + bool peer_5g_supportd = false; + uint8_t i; + uint16_t temp_bw, max_pref_width, peer_supportd_max_bw = 0; + uint8_t reg_bw_offset; + + if (!pdev) { + tdls_err("pdev is NULL"); + return; + } + + /* + * Update Pref Offcahnnel BW such that: + * 1. If 6 GHz is supported then select the ini preferred 6 GHz channel + * frequency. + * 2. If 6 GHz is supported and peer doesn't support the ini preferred + * channel frequency then select the very first 6 GHz channel which + * peer supports as prefferd offchannel. + * 3. If peer doesn't support 6 GHz, then select ini preferred 5 GHz + * off channel frequency, given that peer should also support it + * 4. If peer doesn support 6 GHz and also doesn't support ini preferred + * 5 GHz offcahnnel, then select the very first 5 GHz channel it + * supports. + */ + ini_pref_6g_freq = soc_obj->tdls_configs.tdls_pre_off_chan_freq_6g; + ini_pref_non6g_freq = wlan_reg_legacy_chan_to_freq(pdev, + soc_obj->tdls_configs.tdls_pre_off_chan_num); + + if (ini_pref_6g_freq == peer->pref_off_chan_freq) + is_6g_support = true; + + for (i = 0; i < peer->supported_channels_len; i++) { + peer_freq = peer->supported_chan_freq[i]; + peer_chan = wlan_reg_get_chan_enum_for_freq(peer_freq); + + if (!wlan_reg_is_freq_idx_enabled(pdev, peer_chan, + REG_CLI_DEF_VLP)) + continue; + + if (peer->pref_off_chan_freq == peer_freq) + break; + + if (ini_pref_non6g_freq == peer_freq) { + peer_5g_supportd = true; + peer_5g_freq = ini_pref_non6g_freq; + } + if (!peer_5g_supportd && + wlan_reg_is_5ghz_ch_freq(peer_freq)) { + peer_5g_freq = peer_freq; + peer_5g_supportd = true; + } + if (!peer_6g_supportd && + wlan_reg_is_6ghz_chan_freq(peer_freq)) { + peer_6g_freq = peer_freq; + peer_6g_supportd = true; + } + } + + if (peer->pref_off_chan_freq == peer->supported_chan_freq[i]) + goto bw_check; + + if (is_6g_support && peer_6g_freq) + peer->pref_off_chan_freq = peer_6g_freq; + else if (peer_5g_freq) + peer->pref_off_chan_freq = peer_5g_freq; + else + peer->pref_off_chan_freq = 0; + +bw_check: + max_pref_width = wlan_reg_get_max_chwidth(pdev, + peer->pref_off_chan_freq); + for (i = 0; i < peer->supported_oper_classes_len; i++) { + temp_bw = wlan_reg_get_op_class_width(pdev, + peer->supported_oper_classes[i], + false); + if (temp_bw > peer_supportd_max_bw) + peer_supportd_max_bw = temp_bw; + } + + peer_supportd_max_bw = (peer_supportd_max_bw > max_pref_width) ? + max_pref_width : peer_supportd_max_bw; + if (wlan_reg_is_6ghz_chan_freq(peer->pref_off_chan_freq) && + peer_supportd_max_bw < BW_160_MHZ) + tdls_fill_peer_pref_offchan_bw(peer, peer_supportd_max_bw); + else if (wlan_reg_is_5ghz_ch_freq(peer->pref_off_chan_freq) && + peer_supportd_max_bw < BW_80_MHZ) + tdls_fill_peer_pref_offchan_bw(peer, peer_supportd_max_bw); + + if (wlan_reg_is_5ghz_ch_freq(peer->pref_off_chan_freq) && + CHECK_BIT(peer->pref_off_chan_width, BW_160_OFFSET_BIT)) + peer->pref_off_chan_width &= ~(1 << BW_160_OFFSET_BIT); + + peer->op_class_for_pref_off_chan = + tdls_get_opclass_from_bandwidth( + vdev_obj->vdev, peer->pref_off_chan_freq, + peer->pref_off_chan_width, + ®_bw_offset); + + tdls_debug("Updated preff offchannel freq %d width %d opclass %d", + peer->pref_off_chan_freq, peer->pref_off_chan_width, + peer->op_class_for_pref_off_chan); +} + +void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, + struct tdls_update_peer_params *req_info) +{ + uint8_t is_buffer_sta = 0; + uint8_t is_off_channel_supported = 0; + uint8_t is_qos_wmm_sta = 0; + struct tdls_soc_priv_obj *soc_obj; + struct tdls_peer *curr_peer; + uint32_t feature; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + if (!soc_obj) { + tdls_err("NULL psoc object"); + return; + } + + curr_peer = tdls_find_peer(vdev_obj, macaddr); + if (!curr_peer) { + tdls_err("NULL tdls peer"); + return; + } + + feature = soc_obj->tdls_configs.tdls_feature_flags; + if ((1 << 4) & req_info->extn_capability[3]) + is_buffer_sta = 1; + + if ((1 << 6) & req_info->extn_capability[3]) + is_off_channel_supported = 1; + + if (TDLS_IS_WMM_ENABLED(feature) && req_info->is_qos_wmm_sta) + is_qos_wmm_sta = 1; + + curr_peer->uapsd_queues = req_info->uapsd_queues; + curr_peer->max_sp = req_info->max_sp; + curr_peer->buf_sta_capable = is_buffer_sta; + curr_peer->off_channel_capable = is_off_channel_supported; + + qdf_mem_copy(curr_peer->supported_chan_freq, + req_info->supported_chan_freq, + sizeof(qdf_freq_t) * req_info->supported_channels_len); + + curr_peer->supported_channels_len = req_info->supported_channels_len; + + qdf_mem_copy(curr_peer->supported_oper_classes, + req_info->supported_oper_classes, + req_info->supported_oper_classes_len); + + curr_peer->supported_oper_classes_len = + req_info->supported_oper_classes_len; + + curr_peer->qos = is_qos_wmm_sta; + + tdls_update_off_chan_peer_caps(vdev_obj, soc_obj, curr_peer); +} + +QDF_STATUS tdls_set_valid(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr) +{ + struct tdls_peer *peer; + + peer = tdls_find_peer(vdev_obj, macaddr); + if (!peer) { + tdls_err("peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + peer->valid_entry = true; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, bool forcepeer) +{ + struct tdls_peer *peer; + + peer = tdls_find_peer(vdev_obj, macaddr); + if (!peer) { + tdls_err("peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + peer->is_forced_peer = forcepeer; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_set_callback(struct tdls_peer *peer, + tdls_state_change_callback callback) +{ + if (!peer) { + tdls_err("peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + peer->state_change_notification = callback; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, qdf_freq_t ch_freq, + uint32_t max_latency, uint32_t op_class, + uint32_t min_bandwidth) +{ + if (!peer) { + tdls_err("peer is NULL"); + return QDF_STATUS_E_FAILURE; + } + peer->op_class_for_pref_off_chan = (uint8_t)op_class; + peer->pref_off_chan_freq = ch_freq; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr) +{ + struct tdls_soc_priv_obj *soc_obj; + struct tdls_peer *curr_peer; + struct tdls_user_config *config; + uint8_t reg_bw_offset; + + soc_obj = wlan_vdev_get_tdls_soc_obj(vdev_obj->vdev); + if (!soc_obj) { + tdls_err("NULL psoc object"); + return QDF_STATUS_E_FAILURE; + } + + curr_peer = tdls_find_peer(vdev_obj, macaddr); + if (!curr_peer) { + tdls_err("NULL tdls peer"); + return QDF_STATUS_E_FAILURE; + } + + if (!curr_peer->is_forced_peer) { + config = &soc_obj->tdls_configs; + tdls_fill_pref_off_chan_info(vdev_obj, soc_obj, curr_peer); + curr_peer->op_class_for_pref_off_chan = + tdls_get_opclass_from_bandwidth( + vdev_obj->vdev, curr_peer->pref_off_chan_freq, + curr_peer->pref_off_chan_width, + ®_bw_offset); + } + + if (curr_peer->is_peer_idle_timer_initialised) { + tdls_debug(QDF_MAC_ADDR_FMT ": destroy idle timer ", + QDF_MAC_ADDR_REF(curr_peer->peer_mac.bytes)); + qdf_mc_timer_stop(&curr_peer->peer_idle_timer); + qdf_mc_timer_destroy(&curr_peer->peer_idle_timer); + curr_peer->is_peer_idle_timer_initialised = false; + } + + tdls_set_peer_link_status(curr_peer, TDLS_LINK_IDLE, + TDLS_LINK_UNSPECIFIED); + curr_peer->valid_entry = false; + + return QDF_STATUS_SUCCESS; +} + +void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj) +{ + uint16_t i; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + QDF_STATUS status; + + if (!vdev_obj) { + tdls_err("NULL tdls vdev object"); + return; + } + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &vdev_obj->peer_list[i]; + + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + if (peer && peer->is_peer_idle_timer_initialised) { + tdls_debug(QDF_MAC_ADDR_FMT + ": destroy idle timer ", + QDF_MAC_ADDR_REF( + peer->peer_mac.bytes)); + qdf_mc_timer_stop(&peer->peer_idle_timer); + qdf_mc_timer_destroy(&peer->peer_idle_timer); + } + status = qdf_list_peek_next(head, p_node, &p_node); + } + } +} + +void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj) +{ + uint16_t i; + struct tdls_peer *peer; + qdf_list_t *head; + qdf_list_node_t *p_node; + + if (!vdev_obj) { + tdls_err("NULL tdls vdev object"); + return; + } + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &vdev_obj->peer_list[i]; + + while (QDF_IS_STATUS_SUCCESS( + qdf_list_remove_front(head, &p_node))) { + peer = qdf_container_of(p_node, struct tdls_peer, node); + qdf_mem_free(peer); + } + qdf_list_destroy(head); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.h new file mode 100644 index 0000000000..95ba485ee1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_peer.h @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_peer.h + * + * TDLS peer function declaration + */ + +#if !defined(_WLAN_TDLS_PEER_H_) +#define _WLAN_TDLS_PEER_H_ + +/** + * struct tdls_search_peer_param - used to search TDLS peer + * @macaddr: MAC address of peer + * @peer: pointer to the found peer + */ +struct tdls_search_peer_param { + const uint8_t *macaddr; + struct tdls_peer *peer; +}; + +/** + * struct tdls_search_progress_param - used to search progress TDLS peer + * @skip_self: skip self peer + * @macaddr: MAC address of peer + * @peer: pointer to the found peer + */ +struct tdls_search_progress_param { + uint8_t skip_self; + const uint8_t *macaddr; + struct tdls_peer *peer; +}; + +/** + * tdls_get_peer() - find or add an TDLS peer in TDLS vdev object + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of peer + * + * Search the TDLS peer in the hash table and create a new one if not found. + * + * Return: Pointer to tdls_peer, NULL if failed. + */ +struct tdls_peer *tdls_get_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr); + +/** + * tdls_find_peer() - find TDLS peer in TDLS vdev object + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of peer + * + * This is in scheduler thread context, no lock required. + * + * Return: If peer is found, then it returns pointer to tdls_peer; + * otherwise, it returns NULL. + */ +struct tdls_peer *tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr); + +/** + * tdls_find_all_peer() - find peer matching the input MACaddr in soc range + * @soc_obj: TDLS soc object + * @macaddr: MAC address of TDLS peer + * + * This is in scheduler thread context, no lock required. + * + * Return: TDLS peer if a matching is detected; NULL otherwise + */ +struct tdls_peer * +tdls_find_all_peer(struct tdls_soc_priv_obj *soc_obj, const uint8_t *macaddr); + +/** + * tdls_find_opclass() - find Operating Class based upon channel + * @psoc: objmgr soc object + * @channel:channel number + * @bw_offset: offset to bandwidth + * + * This is in scheduler thread context, no lock required. + * + * Return: Operating class + */ +uint8_t tdls_find_opclass(struct wlan_objmgr_psoc *psoc, + uint8_t channel, + uint8_t bw_offset); + +/** + * tdls_find_first_connected_peer() - find the 1st connected tdls peer from vdev + * @vdev_obj: tdls vdev object + * + * This function searches for the 1st connected TDLS peer + * + * Return: The 1st connected TDLS peer if found; NULL otherwise + */ +struct tdls_peer * +tdls_find_first_connected_peer(struct tdls_vdev_priv_obj *vdev_obj); + +/** + * tdls_is_progress() - find the peer with ongoing TDLS progress on present psoc + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of the peer + * @skip_self: if 1, skip checking self. If 0, search include self + * + * This is used in scheduler thread context, no lock required. + * + * Return: TDLS peer if found; NULL otherwise + */ +struct tdls_peer *tdls_is_progress(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, uint8_t skip_self); + +/** + * tdls_get_offchan_freq() - Get preferred offchannel frequency + * @vdev: Pointer to vdev + * @soc_obj: TDLS SOC object + * + * This function gets preferred offchannel frequency. + * + * Return: Preferred offchannel frequency + */ +qdf_freq_t tdls_get_offchan_freq(struct wlan_objmgr_vdev *vdev, + struct tdls_soc_priv_obj *soc_obj); + +/** + * tdls_get_offchan_bw() - Get preferred offchannel bandwidth on basis of + * frequency + * @soc_obj: TDLS SOC object + * @off_chan_freq: Offchannel frequency + * + * + * This function gets preferred offchannel bandwidth on basis of frequency. + * + * Return: Preferred offchannel bw + */ +uint32_t tdls_get_offchan_bw(struct tdls_soc_priv_obj *soc_obj, + qdf_freq_t off_chan_freq); + +/** + * tdls_extract_peer_state_param() - extract peer update params from TDL peer + * @peer_param: output peer update params + * @peer: TDLS peer + * + * This is used when enable TDLS link + * + * Return: None. + */ +void tdls_extract_peer_state_param(struct tdls_peer_update_state *peer_param, + struct tdls_peer *peer); + +/** + * tdls_set_peer_link_status() - set link statue for TDLS peer + * @peer: TDLS peer + * @link_state: link state + * @link_reason: reason with link status + * + * This is in scheduler thread context, no lock required. + * + * Return: None. + */ +void tdls_set_peer_link_status(struct tdls_peer *peer, + enum tdls_link_state link_state, + enum tdls_link_state_reason link_reason); + +/** + * tdls_set_peer_caps() - set capability for TDLS peer + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address for the TDLS peer + * @req_info: parameters to update peer capability + * + * This is in scheduler thread context, no lock required. + * + * Return: None. + */ +void tdls_set_peer_caps(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, + struct tdls_update_peer_params *req_info); + +/** + * tdls_set_valid() - set station ID on a TDLS peer + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of the TDLS peer + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_set_valid(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr); + +/** + * tdls_set_force_peer() - set/clear is_forced_peer flag on peer + * @vdev_obj: TDLS vdev object + * @macaddr: MAC address of TDLS peer + * @forcepeer: value used to set is_forced_peer flag + * + * This is used in scheduler thread context, no lock required. + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_set_force_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr, bool forcepeer); + +/** + * tdls_set_callback() - set state change callback on current TDLS peer + * @peer: TDLS peer + * @callback: state change callback + * + * This is used in scheduler thread context, no lock required. + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_set_callback(struct tdls_peer *peer, + tdls_state_change_callback callback); + +/** + * tdls_set_extctrl_param() - set external control parameter on TDLS peer + * @peer: TDLS peer + * @ch_freq: channel frequency + * @max_latency: maximum latency + * @op_class: operation class + * @min_bandwidth: minimal bandwidth + * + * This is used in scheduler thread context, no lock required. + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_set_extctrl_param(struct tdls_peer *peer, qdf_freq_t ch_freq, + uint32_t max_latency, uint32_t op_class, + uint32_t min_bandwidth); + +/** + * tdls_reset_peer() - reset TDLS peer identified by MAC address + * @vdev_obj: TDLS vdev object + * @mac: MAC address of the peer + * + * Return: QDF_STATUS_SUCCESS if success; other values if failed + */ +QDF_STATUS tdls_reset_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *mac); + +/** + * tdls_peer_idle_timers_destroy() - destroy peer idle timers + * @vdev_obj: TDLS vdev object + * + * Loop through the idle peer list and destroy their timers + * + * Return: None + */ +void tdls_peer_idle_timers_destroy(struct tdls_vdev_priv_obj *vdev_obj); + +/** + * tdls_free_peer_list() - free TDLS peer list + * @vdev_obj: TDLS vdev object + * + * Free all the tdls peers + * + * Return: None + */ +void tdls_free_peer_list(struct tdls_vdev_priv_obj *vdev_obj); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_txrx.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_txrx.c new file mode 100644 index 0000000000..6ded57c974 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_txrx.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_txrx.c + * + * TDLS txrx function definitions + */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_txrx.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_txrx.h new file mode 100644 index 0000000000..b001ffe745 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/core/src/wlan_tdls_txrx.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_txrx.h + * + * TDLS txrx api declaration + */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/cfg_tdls.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/cfg_tdls.h new file mode 100644 index 0000000000..2fd16bb300 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/cfg_tdls.h @@ -0,0 +1,777 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(CONFIG_TDLS_H__) +#define CONFIG_TDLS_H__ + +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" + +/* + * + * gTDLSUapsdMask - ACs to setup U-APSD for TDLS Sta. + * @Min: 0 + * @Max: 0x0F + * @Default: 0x0F + * + * This ini is used to configure the ACs for which mask needs to be enabled. + * 0x1: Background 0x2: Best effort + * 0x4: Video 0x8: Voice + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_QOS_WMM_UAPSD_MASK CFG_INI_UINT( \ + "gTDLSUapsdMask", \ + 0, \ + 0x0F, \ + 0x0F, \ + CFG_VALUE_OR_DEFAULT, \ + "ACs to setup U-APSD for TDLS Sta") + +/* + * + * gEnableTDLSBufferSta - Controls the TDLS buffer. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to control the TDLS buffer. + * Buffer STA is not enabled in CLD 2.0 yet. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_BUF_STA_ENABLED CFG_INI_BOOL( \ + "gEnableTDLSBufferSta", \ + 1, \ + "Controls the TDLS buffer") + +/* + * + * gTDLSPuapsdInactivityTime - Peer UAPSD Inactivity time. + * @Min: 0 + * @Max: 10 + * @Default: 0 + * + * This ini is used to configure peer uapsd inactivity time(in ms). + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_INACT_TIME CFG_INI_UINT( \ + "gTDLSPuapsdInactivityTime", \ + 0, \ + 10, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Peer UAPSD Inactivity time") + +/* + * + * gTDLSPuapsdRxFrameThreshold - Peer UAPSD Rx frame threshold. + * @Min: 10 + * @Max: 20 + * @Default: 10 + * + * This ini is used to configure maximum Rx frame during SP. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RX_FRAME_THRESHOLD CFG_INI_UINT( \ + "gTDLSPuapsdRxFrameThreshold", \ + 10, \ + 20, \ + 10, \ + CFG_VALUE_OR_DEFAULT, \ + "Peer UAPSD Rx frame threshold") + +/* + * + * gEnableTDLSOffChannel - Enables off-channel support for TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable off-channel support for TDLS link. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_OFF_CHANNEL_ENABLED CFG_INI_BOOL( \ + "gEnableTDLSOffChannel", \ + 1, \ + "Enables off-channel support for TDLS") + +/* + * + * gEnableTDLSSupport - Enable support for TDLS. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable TDLS support. + * + * Related: None. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_SUPPORT_ENABLE CFG_INI_BOOL( \ + "gEnableTDLSSupport", \ + 1, \ + "enable/disable TDLS support") + +/* + * + * gEnableTDLSImplicitTrigger - Enable Implicit TDLS. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable implicit TDLS. + * CLD driver initiates TDLS Discovery towards a peer whenever TDLS Setup + * criteria (throughput and RSSI thresholds) is met and then it tears down + * TDLS when teardown criteria (idle packet count and RSSI) is met. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_IMPLICIT_TRIGGER CFG_INI_BOOL( \ + "gEnableTDLSImplicitTrigger", \ + 1, \ + "enable/disable implicit TDLS") + +/* + * + * gTDLSTxStatsPeriod - TDLS TX statistics time period. + * @Min: 1000 + * @Max: 4294967295 + * @Default: 2000 + * + * This ini is used to configure the time period (in ms) to evaluate whether + * the number of Tx/Rx packets exceeds TDLSTxPacketThreshold and triggers a + * TDLS Discovery request. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_TX_STATS_PERIOD CFG_INI_UINT( \ + "gTDLSTxStatsPeriod", \ + 1000, \ + 4294967295UL, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "TDLS TX statistics time period") + +/* + * + * gTDLSTxPacketThreshold - Tx/Rx Packet threshold for initiating TDLS. + * @Min: 0 + * @Max: 4294967295 + * @Default: 40 + * + * This ini is used to configure the number of Tx/Rx packets during the + * period of gTDLSTxStatsPeriod when exceeded, a TDLS Discovery request + * is triggered. + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_TX_PACKET_THRESHOLD CFG_INI_UINT( \ + "gTDLSTxPacketThreshold", \ + 0, \ + 4294967295UL, \ + 40, \ + CFG_VALUE_OR_DEFAULT, \ + "Tx/Rx Packet threshold for initiating TDLS") + +/* + * + * gTDLSMaxDiscoveryAttempt - Attempts for sending TDLS discovery requests. + * @Min: 1 + * @Max: 100 + * @Default: 5 + * + * This ini is used to configure the number of failures of discover request, + * when exceeded, the peer is assumed to be not TDLS capable and no further + * TDLS Discovery request is made. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_MAX_DISCOVERY_ATTEMPT CFG_INI_UINT( \ + "gTDLSMaxDiscoveryAttempt", \ + 1, \ + 100, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Attempts for sending TDLS discovery requests") + +/* + * gTDLSMaxPeerCount - Max TDLS connected peer count + * @Min: 1 + * @Max: 8 + * @Default: 8 + * + * This ini is used to configure the max connected TDLS peer count. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: External + * + * + */ +#define CFG_TDLS_MAX_PEER_COUNT CFG_INI_UINT( \ + "gTDLSMaxPeerCount", \ + 1, \ + 8, \ + 8, \ + CFG_VALUE_OR_DEFAULT, \ + "Max TDLS peer count") + +/* + * + * gTDLSIdleTimeout - Duration within which number of TX / RX frames meet the + * criteria for TDLS teardown. + * @Min: 500 + * @Max: 40000 + * @Default: 5000 + * + * This ini is used to configure the time period (in ms) to evaluate whether + * the number of Tx/Rx packets exceeds gTDLSIdlePacketThreshold and thus meets + * criteria for TDLS teardown. + * Teardown notification interval (gTDLSIdleTimeout) should be multiple of + * setup notification (gTDLSTxStatsPeriod) interval. + * e.g. + * if setup notification (gTDLSTxStatsPeriod) interval = 500, then + * teardown notification (gTDLSIdleTimeout) interval should be 1000, + * 1500, 2000, 2500... + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + */ +#define CFG_TDLS_IDLE_TIMEOUT CFG_INI_UINT( \ + "gTDLSIdleTimeout", \ + 500, \ + 40000, \ + 5000, \ + CFG_VALUE_OR_DEFAULT, \ + "this is idle time period") + +/* + * + * gTDLSIdlePacketThreshold - Number of idle packet. + * @Min: 0 + * @Max: 40000 + * @Default: 3 + * + * This ini is used to configure the number of Tx/Rx packet, below which + * within last gTDLSTxStatsPeriod period is considered as idle condition. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_IDLE_PACKET_THRESHOLD CFG_INI_UINT( \ + "gTDLSIdlePacketThreshold", \ + 0, \ + 40000, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Number of idle packet") + +/* + * + * gTDLSRSSITriggerThreshold - RSSI threshold for TDLS connection. + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * This ini is used to configure the absolute value (in dB) of the peer RSSI, + * below which a TDLS setup request is triggered. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RSSI_TRIGGER_THRESHOLD CFG_INI_INT( \ + "gTDLSRSSITriggerThreshold", \ + -120, \ + 0, \ + -75, \ + CFG_VALUE_OR_DEFAULT, \ + "RSSI threshold for TDLS connection") + +/* + * + * gTDLSRSSITeardownThreshold - RSSI threshold for TDLS teardown. + * @Min: -120 + * @Max: 0 + * @Default: -75 + * + * This ini is used to configure the absolute value (in dB) of the peer RSSI, + * when exceed, a TDLS teardown is triggered. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RSSI_TEARDOWN_THRESHOLD CFG_INI_INT( \ + "gTDLSRSSITeardownThreshold", \ + -120, \ + 0, \ + -75, \ + CFG_VALUE_OR_DEFAULT, \ + "RSSI threshold for TDLS teardown") + +/* + * + * gTDLSRSSIDelta - Delta value for the peer RSSI that can trigger teardown. + * @Min: -30 + * @Max: 0 + * @Default: -20 + * + * This ini is used to configure delta for peer RSSI such that if Peer RSSI + * is less than AP RSSI plus delta will trigger a teardown. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_RSSI_DELTA CFG_INI_INT( \ + "gTDLSRSSIDelta", \ + -30, \ + 0, \ + -20, \ + CFG_VALUE_OR_DEFAULT, \ + "Delta value for the peer RSSI that can trigger teardown") + +/* + * + * gTDLSPrefOffChanNum - Preferred TDLS channel number when off-channel support + * is enabled. + * @Min: 1 + * @Max: 165 + * @Default: 36 + * + * This ini is used to configure preferred TDLS channel number when off-channel + * support is enabled. + * + * Related: gEnableTDLSSupport, gEnableTDLSOffChannel. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM CFG_INI_UINT( \ + "gTDLSPrefOffChanNum", \ + 1, \ + 165, \ + 36, \ + CFG_VALUE_OR_DEFAULT, \ + "Preferred TDLS channel number") + +/* + * + * tdls_pref_off_chan_num_6g - Preferred TDLS 6g channel freq when off-channel + * support is enabled. + * @Min: 0 + * @Max: 7115 + * @Default: 5975 + * + * This ini is used to configure preferred TDLS 6G channel number when + * off-channel support is enabled. If this is set to 0, 6Ghz offchannel is + * disabled. + * + * Related: gEnableTDLSSupport, gEnableTDLSOffChannel. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_FREQ_6G CFG_INI_UINT( \ + "tdls_pref_off_chan_freq_6g", \ + 0, \ + 7115, \ + 5975, \ + CFG_VALUE_OR_DEFAULT, \ + "Preferred TDLS channel frequency for 6ghz channels") + +/* + * + * gTDLSPrefOffChanBandwidth - Preferred TDLS channel bandwidth when + * off-channel support is enabled. + * @Min: 1 + * @Max: 15 + * @Default: 15 + * + * This ini is used to configure preferred TDLS channel bandwidth when + * off-channel support is enabled. + * 0x1: 20 MHz 0x2: 40 MHz 0x4: 80 MHz 0x8: 160 MHz + * When more than one bits are set then firmware starts from the highest and + * selects one based on capability of peer. So, that means if 0xF is set that + * means fw will try intersect with 160 MHz BW and the peer supported BW. + * + * Related: gEnableTDLSSupport, gEnableTDLSOffChannel. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PREFERRED_OFF_CHANNEL_BW CFG_INI_UINT( \ + "gTDLSPrefOffChanBandwidth", \ + 1, \ + 15, \ + 15, \ + CFG_VALUE_OR_DEFAULT, \ + "Preferred TDLS channel bandwidth") + +/* + * + * gTDLSPuapsdPTIWindow - This ini is used to configure peer traffic indication + * window. + * @Min: 1 + * @Max: 5 + * @Default: 2 + * + * This ini is used to configure buffering time in number of beacon intervals. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW CFG_INI_UINT( \ + "gTDLSPuapsdPTIWindow", \ + 1, \ + 5, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "This ini is used to configure peer traffic indication") + +/* + * + * gTDLSPuapsdPTIWindow - This ini is used to configure peer traffic indication + * window. + * @Min: 1 + * @Max: 5 + * @Default: 2 + * + * This ini is used to configure buffering time in number of beacon intervals. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT CFG_INI_UINT( \ + "gTDLSPuapsdPTRTimeout", \ + 0, \ + 10000, \ + 5000, \ + CFG_VALUE_OR_DEFAULT, \ + "Peer Traffic Response timer duration in ms") + +/* + * + * gTDLSExternalControl - Enable external TDLS control. + * @Min: 0 + * @Max: 2 + * @Default: 1 + * + * This ini is used to enable/disable external TDLS control. + * TDLS external control works with TDLS implicit trigger. TDLS external + * control allows a user to add a MAC address of potential TDLS peers so + * that the CLD driver can initiate implicit TDLS setup to only those peers + * when criteria for TDLS setup (throughput and RSSI threshold) is met. + * There are two flavors of external control supported. If control default + * is set 1 it means strict external control where only for configured + * tdls peer mac address tdls link will be established. If control default + * is set 2 liberal tdls external control is needed which means + * tdls link will be established with configured peer mac address as well + * as any other peer which supports tdls. + * + * Related: gEnableTDLSSupport, gEnableTDLSImplicitTrigger. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_EXTERNAL_CONTROL CFG_INI_UINT( \ + "gTDLSExternalControl", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable external TDLS control") + +/* + * + * gEnableTDLSWmmMode - Enables WMM support over TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable WMM support over TDLS link. + * This is required to be set to 1 for any TDLS and uAPSD functionality. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_WMM_MODE_ENABLE CFG_INI_BOOL( \ + "gEnableTDLSWmmMode", \ + 1, \ + "Enables WMM support over TDLS link") + +/* + * + * gEnableTDLSScan - Allow scan and maintain TDLS link. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable TDLS scan. + * 0: If peer is not buffer STA capable and device is not sleep STA + * capable, then teardown TDLS link when scan is initiated. If peer + * is buffer STA and we can be sleep STA then TDLS link is maintained + * during scan. + * 1: Maintain TDLS link and allow scan even if peer is not buffer STA + * capable and device is not sleep STA capable. There will be loss of + * Rx pkts since peer would not know when device moves away from tdls + * channel. Tx on TDLS link would stop when device moves away from tdls + * channel. + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_SCAN_ENABLE CFG_INI_BOOL( \ + "gEnableTDLSScan", \ + 1, \ + "Allow scan and maintain TDLS link") + +/* + * + * gTDLSPeerKickoutThreshold - TDLS peer kick out threshold to firmware. + * @Min: 10 + * @Max: 5000 + * @Default: 96 + * + * This ini is used to configure TDLS peer kick out threshold to firmware. + * Firmware will use this value to determine, when to send TDLS + * peer kick out event to host. + * E.g. + * if peer kick out threshold is 10, then firmware will wait for 10 + * consecutive packet failures and then send TDLS kick out + * notification to host driver + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_PEER_KICKOUT_THRESHOLD CFG_INI_UINT( \ + "gTDLSPeerKickoutThreshold", \ + 10, \ + 5000, \ + 96, \ + CFG_VALUE_OR_DEFAULT, \ + "TDLS peer kick out threshold to firmware") +/* + * + * gTDLSDiscoveryWakeTimeout - TDLS discovery WAKE timeout in ms. + * @Min: 10 + * @Max: 5000 + * @Default: 96 + * + * DUT will wake until this timeout to receive TDLS discovery response + * from peer. If tdls_discovery_wake_timeout is 0x0, the DUT will + * choose autonomously what wake timeout value to use. + * + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: External + * + * + */ + #define CFG_TDLS_DISCOVERY_WAKE_TIMEOUT CFG_INI_UINT( \ + "gTDLSDiscoveryWakeTimeout", \ + 0, \ + 2000, \ + 200, \ + CFG_VALUE_OR_DEFAULT, \ + "TDLS peer kick out threshold to firmware") + +/* + * + * gTDLSEnableDeferTime - Timer to defer for enabling TDLS on P2P listen. + * @Min: 500 + * @Max: 6000 + * @Default: 2000 + * + * This ini is used to set the timer to defer for enabling TDLS on P2P + * listen (value in milliseconds). + * + * Related: gEnableTDLSSupport. + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define CFG_TDLS_ENABLE_DEFER_TIMER CFG_INI_UINT( \ + "gTDLSEnableDeferTime", \ + 500, \ + 6000, \ + 2000, \ + CFG_VALUE_OR_DEFAULT, \ + "Timer to defer for enabling TDLS on P2P listen") + +#define CFG_TDLS_ALL \ + CFG(CFG_TDLS_QOS_WMM_UAPSD_MASK) \ + CFG(CFG_TDLS_BUF_STA_ENABLED) \ + CFG(CFG_TDLS_PUAPSD_INACT_TIME) \ + CFG(CFG_TDLS_RX_FRAME_THRESHOLD) \ + CFG(CFG_TDLS_OFF_CHANNEL_ENABLED) \ + CFG(CFG_TDLS_SUPPORT_ENABLE) \ + CFG(CFG_TDLS_IMPLICIT_TRIGGER) \ + CFG(CFG_TDLS_TX_STATS_PERIOD) \ + CFG(CFG_TDLS_TX_PACKET_THRESHOLD) \ + CFG(CFG_TDLS_MAX_DISCOVERY_ATTEMPT) \ + CFG(CFG_TDLS_MAX_PEER_COUNT) \ + CFG(CFG_TDLS_IDLE_TIMEOUT) \ + CFG(CFG_TDLS_IDLE_PACKET_THRESHOLD) \ + CFG(CFG_TDLS_RSSI_TRIGGER_THRESHOLD) \ + CFG(CFG_TDLS_RSSI_TEARDOWN_THRESHOLD) \ + CFG(CFG_TDLS_RSSI_DELTA) \ + CFG(CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM) \ + CFG(CFG_TDLS_PREFERRED_OFF_CHANNEL_FREQ_6G) \ + CFG(CFG_TDLS_PREFERRED_OFF_CHANNEL_BW) \ + CFG(CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW) \ + CFG(CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT) \ + CFG(CFG_TDLS_EXTERNAL_CONTROL) \ + CFG(CFG_TDLS_WMM_MODE_ENABLE) \ + CFG(CFG_TDLS_SCAN_ENABLE) \ + CFG(CFG_TDLS_PEER_KICKOUT_THRESHOLD) \ + CFG(CFG_TDLS_DISCOVERY_WAKE_TIMEOUT) \ + CFG(CFG_TDLS_ENABLE_DEFER_TIMER) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_api.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_api.h new file mode 100644 index 0000000000..b13b94e6ce --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_api.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains tdls link teardown declarations + */ + #ifndef _WLAN_TDLS_API_H_ + #define _WLAN_TDLS_API_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_tdls_main.h" + +#ifdef FEATURE_WLAN_TDLS +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_tdls_is_fw_11be_mlo_capable() - Get TDLS 11be mlo capab + * @psoc: psoc context + * + * Return: True if 11be mlo capable + */ +bool wlan_tdls_is_fw_11be_mlo_capable(struct wlan_objmgr_psoc *psoc); +#else +static inline +bool wlan_tdls_is_fw_11be_mlo_capable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif +#ifdef FEATURE_SET +/** + * wlan_tdls_get_features_info() - Get tdls features info + * @psoc: psoc context + * @tdls_feature_set: TDLS feature set info structure + * + * Return: None + */ + +void wlan_tdls_get_features_info(struct wlan_objmgr_psoc *psoc, + struct wlan_tdls_features *tdls_feature_set); +#endif + +/** + * wlan_tdls_register_lim_callbacks() - Register callbacks for legacy LIM API + * @psoc: Pointer to psoc object + * @cbs: Pointer to callback struct + * + * Return: None + */ +void wlan_tdls_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct tdls_callbacks *cbs); + +/** + * wlan_tdls_teardown_links() - notify TDLS module to teardown all TDLS links + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_tdls_teardown_links(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_tdls_check_and_teardown_links_sync() - teardown all the TDLS links + * @psoc: psoc object + * @vdev: Vdev object pointer + * + * Return: None + */ +void wlan_tdls_check_and_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_tdls_notify_sta_disconnect() - notify sta disconnect + * @vdev_id: pointer to soc object + * @lfr_roam: indicate, whether disconnect due to lfr roam + * @user_disconnect: disconnect from user space + * @vdev: vdev object manager + * + * Notify sta disconnect event to TDLS component + * + * Return: QDF_STATUS + */ +void wlan_tdls_notify_sta_disconnect(uint8_t vdev_id, + bool lfr_roam, bool user_disconnect, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_tdls_notify_sta_connect() - notify sta connect to TDLS + * @vdev_id: pointer to soc object + * @tdls_chan_swit_prohibited: indicates channel switch capability + * @tdls_prohibited: indicates tdls allowed or not + * @vdev: vdev object manager + * + * Notify sta connect event to TDLS component + * + * Return: None + */ +void +wlan_tdls_notify_sta_connect(uint8_t vdev_id, + bool tdls_chan_swit_prohibited, + bool tdls_prohibited, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_is_tdls_session_present() - Get TDLS session status + * @vdev: vdev pointer + * + * Return: QDF_STATUS_SUCCESS if success; other value if failed + */ +QDF_STATUS +wlan_is_tdls_session_present(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_tdls_update_tx_pkt_cnt() - update tx pkt count + * @vdev: tdls vdev object + * @mac_addr: peer mac address + * + * Return: None + */ +void wlan_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr); + +/** + * wlan_tdls_update_rx_pkt_cnt() - update rx pkt count + * @vdev: tdls vdev object + * @mac_addr: peer mac address + * @dest_mac_addr: dest mac address + * + * Return: None + */ +void wlan_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr); +/** + * wlan_tdls_notify_start_bss_failure() - Notify TDLS module on start bss + * failure + * @psoc: Pointer to PSOC object + * + * Return: None + */ +void wlan_tdls_notify_start_bss_failure(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_tdls_notify_start_bss() - Notify TDLS module on start bss + * @psoc: Pointer to PSOC object + * @vdev: Vdev object pointer + * + * Return: None + */ +void wlan_tdls_notify_start_bss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +/** + * wlan_tdls_notify_channel_switch_complete() - Notify TDLS module about the + * channel switch completion + * @psoc: Pointer to PSOC object + * @vdev_id: vdev id + * + * Return: None + */ +void wlan_tdls_notify_channel_switch_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_tdls_notify_channel_switch_start() - Process channel switch start + * for SAP/P2P GO vdev. For STA vdev, TDLS teardown happens, so explicit + * disable off channel is not required. + * @psoc: Pointer to PSOC object + * @vdev: Pointer to current vdev on which CSA is triggered + * + * Return: None + */ +void wlan_tdls_notify_channel_switch_start(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_tdls_handle_p2p_client_connect() - Handle P2P Client connect start + * @psoc: Pointer to PSOC object + * @vdev: Pointer to P2P client vdev + * + * Return: None + */ +void wlan_tdls_handle_p2p_client_connect(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); +#else +static inline +void wlan_tdls_notify_channel_switch_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{} + +static inline +void wlan_tdls_notify_channel_switch_start(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} + +static inline +void wlan_tdls_handle_p2p_client_connect(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} +#endif /* WLAN_FEATURE_TDLS_CONCURRENCIES */ + +/** + * wlan_tdls_increment_discovery_attempts() - Increment TDLS peer discovery + * attempts + * @psoc: Pointer to PSOC object + * @vdev_id: Vdev id + * @peer_addr: Peer mac address + * + * Return: None + */ +void wlan_tdls_increment_discovery_attempts(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t *peer_addr); +/** + * wlan_tdls_is_addba_request_allowed() - API to check if Add Block ack request + * is allowed for TDLS peer in current state. + * @vdev: Vdev object pointer + * @mac_addr: Mac address of the peer + * + * Return: True if ADDBA frame can be allowed + */ +bool wlan_tdls_is_addba_request_allowed(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr); +/* + * wlan_tdls_delete_all_peers() - Delete all TDLS peers in lim + * @vdev: Pointer to vdev object + * + * Return: None + */ +void wlan_tdls_delete_all_peers(struct wlan_objmgr_vdev *vdev); +#else + +static inline +void wlan_tdls_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct tdls_callbacks *cbs) +{} + +#ifdef FEATURE_SET +static inline +void wlan_tdls_get_features_info(struct wlan_objmgr_psoc *psoc, + struct wlan_tdls_features *tdls_feature_set) +{ +} +#endif + +static inline +bool wlan_tdls_is_fw_11be_mlo_capable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS wlan_tdls_teardown_links(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +wlan_tdls_check_and_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} + +static inline +void wlan_tdls_notify_sta_disconnect(uint8_t vdev_id, + bool lfr_roam, bool user_disconnect, + struct wlan_objmgr_vdev *vdev) +{} + +static inline void +wlan_tdls_notify_sta_connect(uint8_t vdev_id, + bool tdls_chan_swit_prohibited, + bool tdls_prohibited, + struct wlan_objmgr_vdev *vdev) {} + +static inline void +wlan_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ +} + +static inline +void wlan_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr) +{ +} + +static inline +void wlan_tdls_notify_start_bss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} + +static inline +void wlan_tdls_notify_channel_switch_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{} + +static inline +void wlan_tdls_notify_channel_switch_start(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} + +static inline +void wlan_tdls_handle_p2p_client_connect(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{} + +static inline +void wlan_tdls_notify_start_bss_failure(struct wlan_objmgr_psoc *psoc) +{} + +static inline +void wlan_tdls_increment_discovery_attempts(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t *peer_addr) +{} + +static inline +bool wlan_tdls_is_addba_request_allowed(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + return false; +} + +static inline +void wlan_tdls_delete_all_peers(struct wlan_objmgr_vdev *vdev) +{} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h new file mode 100644 index 0000000000..084670626c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_cfg_api.h @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Contains p2p configures interface definitions + */ + +#ifndef _WLAN_TDLS_CFG_API_H_ +#define _WLAN_TDLS_CFG_API_H_ + +#include + +struct wlan_objmgr_psoc; + +#ifdef FEATURE_WLAN_TDLS +/** + * cfg_tdls_get_support_enable() - get tdls support enable + * @psoc: pointer to psoc object + * @val: pointer to tdls support enable/disable + * + * This function gets tdls support enable + */ +QDF_STATUS +cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_set_support_enable() - set tdls support enable + * @psoc: pointer to psoc object + * @val: set tdls support enable/disable + * + * This function sets tdls support enable + */ +QDF_STATUS +cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * cfg_tdls_get_external_control() - get tdls external control + * @psoc: pointer to psoc object + * @val: pointer to tdls external control enable/disable + * + * This function gets tdls external control + */ +QDF_STATUS +cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_get_uapsd_mask() - get tdls uapsd mask + * @psoc: pointer to psoc object + * @val: pointer to tdls uapsd mask + * + * This function gets tdls uapsd mask + */ +QDF_STATUS +cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * cfg_tdls_get_buffer_sta_enable() - get tdls buffer sta enable + * @psoc: pointer to psoc object + * @val: pointer to tdls buffer sta enable + * + * This function gets tdls buffer sta enable + */ +QDF_STATUS +cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_set_buffer_sta_enable() - set tdls buffer sta enable + * @psoc: pointer to psoc object + * @val: tdls buffer sta enable + * + * This function sets tdls buffer sta enable + */ +QDF_STATUS +cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * cfg_tdls_get_uapsd_inactivity_time() - get tdls uapsd inactivity time + * @psoc: pointer to psoc object + * @val: pointer to tdls uapsd inactivity time + * + * This function gets tdls uapsd inactivity time + */ +QDF_STATUS +cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * cfg_tdls_get_rx_pkt_threshold() - get tdls rx pkt threshold + * @psoc: pointer to psoc object + * @val: pointer to tdls tdls rx pkt threshold + * + * This function gets tdls rx pkt threshold + */ +QDF_STATUS +cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * cfg_tdls_get_off_channel_enable() - get tdls off channel enable + * @psoc: pointer to psoc object + * @val: pointer to tdls off channel enable + * + * This function gets tdls off channel enable + */ +QDF_STATUS +cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_set_off_channel_enable() - set tdls off channel enable + * @psoc: pointer to psoc object + * @val: tdls off channel enable + * + * This function sets tdls off channel enable + */ +QDF_STATUS +cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * cfg_tdls_get_off_channel_enable_orig() - get tdls off channel enable orig + * @psoc: pointer to psoc object + * @val: pointer to tdls off channel enable + * + * This function gets tdls off channel enable orig + */ +QDF_STATUS +cfg_tdls_get_off_channel_enable_orig(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_restore_off_channel_enable() - set tdls off channel enable to + * tdls_off_chan_enable_orig + * @psoc: pointer to psoc object + * + * Return: NULL + */ +void cfg_tdls_restore_off_channel_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_tdls_store_off_channel_enable() - save tdls off channel enable to + * tdls_off_chan_enable_orig + * @psoc: pointer to psoc object + * + * Return: NULL + */ +void cfg_tdls_store_off_channel_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_tdls_get_wmm_mode_enable() - get tdls wmm mode enable + * @psoc: pointer to psoc object + * @val: pointer to tdls wmm mode enable + * + * This function gets tdls wmm mode enable + */ +QDF_STATUS +cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_set_vdev_nss_2g() - set tdls vdev nss 2g + * @psoc: pointer to psoc object + * @val: tdls vdev nss 2g + * + * This function sets tdls vdev nss 2g + */ +QDF_STATUS +cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * cfg_tdls_set_vdev_nss_5g() - set tdls vdev nss 5g + * @psoc: pointer to psoc object + * @val: tdls vdev nss 5g + * + * This function sets tdls vdev nss 5g + */ +QDF_STATUS +cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc, + uint8_t val); + +/** + * cfg_tdls_get_sleep_sta_enable() - get tdls sleep sta enable + * @psoc: pointer to psoc object + * @val: pointer to tdls sleep sta enable + * + * This function gets tdls sleep sta enable + */ +QDF_STATUS +cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_set_sleep_sta_enable() - set tdls sleep sta enable + * @psoc: pointer to psoc object + * @val: tdls sleep sta enable + * + * This function sets tdls sleep sta enable + */ +QDF_STATUS +cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * cfg_tdls_get_scan_enable() - get tdls scan enable + * @psoc: pointer to psoc object + * @val: pointer to tdls scan enable + * + * This function gets tdls scan enable + */ +QDF_STATUS +cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * cfg_tdls_get_link_id() - get tdls link id + * @psoc: pointer to psoc object + * + * This function gets tdls link id + * + * Return: int + */ +int cfg_tdls_get_link_id(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_tdls_set_link_id() - get tdls link id + * @psoc: pointer to psoc object + * @val: the value of link id + * + * This function gets tdls link id + * + * Return: QDF_STATUS + */ +QDF_STATUS +cfg_tdls_set_link_id(struct wlan_objmgr_psoc *psoc, + int val); +/** + * cfg_tdls_set_scan_enable() - set tdls scan enable + * @psoc: pointer to psoc object + * @val: tdls scan enable + * + * This function sets tdls scan enable + */ +QDF_STATUS +cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc, + bool val); + +/** + * cfg_tdls_get_max_peer_count() - get tdls max peer count + * @psoc: pointer to psoc object + * + * This function gets tdls max peer count + */ +uint16_t cfg_tdls_get_max_peer_count(struct wlan_objmgr_psoc *psoc); + +/** + * cfg_tdls_get_connected_peer_count() - get tdls connected peer count + * @psoc: pointer to psoc object + * + * This function gets tdls connected peer count + */ +uint16_t cfg_tdls_get_connected_peer_count(struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS +cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + *val = 0; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + *val = 0; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + *val = 0; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_off_channel_enable_orig(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline void +cfg_tdls_restore_off_channel_enable(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline void +cfg_tdls_store_off_channel_enable(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline QDF_STATUS +cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + *val = false; + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline int +cfg_tdls_get_link_id(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline QDF_STATUS +cfg_tdls_set_link_id(struct wlan_objmgr_psoc *psoc, + int val) +{ + return QDF_STATUS_SUCCESS; +} +static inline uint16_t +cfg_tdls_get_max_peer_count(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint16_t +cfg_tdls_get_connected_peer_count(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +#endif /* FEATURE_WLAN_TDLS */ +#endif /* _WLAN_TDLS_CFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h new file mode 100644 index 0000000000..e6534ffd66 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_public_structs.h @@ -0,0 +1,1512 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_public_structs.h + * + * TDLS public structure definitions + */ + +#ifndef _WLAN_TDLS_STRUCTS_H_ +#define _WLAN_TDLS_STRUCTS_H_ +#include +#include +#include +#include +#include +#ifdef FEATURE_RUNTIME_PM +#include +#endif + +#define WLAN_TDLS_STA_MAX_NUM 8 +#define WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM 1 +#define WLAN_TDLS_PEER_LIST_SIZE 16 +#define WLAN_TDLS_CT_TABLE_SIZE 8 +#define WLAN_TDLS_PEER_SUB_LIST_SIZE 10 +#define WLAN_MAC_MAX_EXTN_CAP 8 +#define WLAN_MAC_MAX_SUPP_CHANNELS 100 +#define WLAN_MAC_WMI_MAX_SUPP_CHANNELS 128 +#define WLAN_MAX_SUPP_OPER_CLASSES 32 +#define WLAN_MAC_MAX_SUPP_RATES 32 +#define WLAN_CHANNEL_14 14 + +/* Enable TDLS off-channel switch */ +#define ENABLE_CHANSWITCH 1 + +/* + * Passive(peer requested) responder mode off-channel switch. + * If peer initiates off channel request, that will be honored in + * this mode + */ +#define DISABLE_CHANSWITCH 2 + +/* + * Disable TDLS off-channel operation completely. + * Peer initiated requests will also be discarded. + */ +#define DISABLE_ACTIVE_CHANSWITCH 3 + +#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_MIN 1 +#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_MAX 165 +#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_NUM_DEF 36 +#define WLAN_TDLS_PREFERRED_OFF_CHANNEL_FRQ_DEF 5180 +#define WLAN_TDLS_MAX_CONCURRENT_VDEV_SUPPORTED 3 + +#define AC_PRIORITY_NUM 4 + +/* Default tdls serialize timeout is set to 4 (peer delete) + 1 secs */ +#ifdef FEATURE_RUNTIME_PM +/* Add extra PMO_RESUME_TIMEOUT for runtime PM resume timeout */ +#define TDLS_DELETE_PEER_CMD_TIMEOUT (4000 + 1000 + PMO_RESUME_TIMEOUT) +#else +#define TDLS_DELETE_PEER_CMD_TIMEOUT (4000 + 1000) +#endif + +/** Maximum time(ms) to wait for tdls del sta to complete **/ +#define WAIT_TIME_TDLS_DEL_STA (TDLS_DELETE_PEER_CMD_TIMEOUT + 1000) + +#define TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT (4000) + +/** Maximum time(ms) to wait for tdls add sta to complete **/ +#define WAIT_TIME_TDLS_ADD_STA (TDLS_DEFAULT_SERIALIZE_CMD_TIMEOUT + 1000) + +/** Maximum time(ms) to wait for Link Establish Req to complete **/ +#define WAIT_TIME_TDLS_LINK_ESTABLISH_REQ 1500 + +/** Maximum time(ms) to wait for tdls mgmt to complete **/ +#define WAIT_TIME_FOR_TDLS_MGMT 3000 + +/** Maximum time(ms) to wait for tdls mgmt to complete **/ +#define WAIT_TIME_FOR_TDLS_USER_CMD 11000 + +/** Maximum waittime for TDLS teardown links **/ +#define WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS 10000 + +/** Maximum waittime for TDLS antenna switch **/ +#define WAIT_TIME_FOR_TDLS_ANTENNA_SWITCH 1000 + +#define TDLS_TEARDOWN_PEER_UNREACHABLE 25 +#define TDLS_TEARDOWN_PEER_UNSPEC_REASON 26 + +#define INVALID_TDLS_PEER_INDEX 0xFF + +#ifdef WLAN_FEATURE_11AX +#define MIN_TDLS_HE_CAP_LEN 17 +#define MAX_TDLS_HE_CAP_LEN 29 +#endif + +/** + * enum tdls_add_oper - add peer type + * @TDLS_OPER_NONE: none + * @TDLS_OPER_ADD: add new peer + * @TDLS_OPER_UPDATE: used to update peer + */ +enum tdls_add_oper { + TDLS_OPER_NONE, + TDLS_OPER_ADD, + TDLS_OPER_UPDATE +}; + +/** + * enum tdls_conc_cap - tdls concurrency support + * @TDLS_SUPPORTED_ONLY_ON_STA: only support sta tdls + * @TDLS_SUPPORTED_ONLY_ON_P2P_CLIENT: only support p2p client tdls + */ +enum tdls_conc_cap { + TDLS_SUPPORTED_ONLY_ON_STA = 0, + TDLS_SUPPORTED_ONLY_ON_P2P_CLIENT, +}; + +/** + * enum tdls_peer_capab - tdls capability type + * @TDLS_CAP_NOT_SUPPORTED: tdls not supported + * @TDLS_CAP_UNKNOWN: unknown capability + * @TDLS_CAP_SUPPORTED: tdls capability supported + */ +enum tdls_peer_capab { + TDLS_CAP_NOT_SUPPORTED = -1, + TDLS_CAP_UNKNOWN = 0, + TDLS_CAP_SUPPORTED = 1, +}; + +/** + * enum tdls_peer_state - tdls peer state + * @TDLS_PEER_STATE_PEERING: tdls connection in progress + * @TDLS_PEER_STATE_CONNECTED: tdls peer is connected + * @TDLS_PEER_STATE_TEARDOWN: tdls peer is tear down + * @TDLS_PEER_ADD_MAC_ADDR: add peer mac into connection table + * @TDLS_PEER_REMOVE_MAC_ADDR: remove peer mac from connection table + */ +enum tdls_peer_state { + TDLS_PEER_STATE_PEERING, + TDLS_PEER_STATE_CONNECTED, + TDLS_PEER_STATE_TEARDOWN, + TDLS_PEER_ADD_MAC_ADDR, + TDLS_PEER_REMOVE_MAC_ADDR +}; + +/** + * enum tdls_link_state - tdls link state + * @TDLS_LINK_IDLE: tdls link idle + * @TDLS_LINK_DISCOVERING: tdls link discovering + * @TDLS_LINK_DISCOVERED: tdls link discovered + * @TDLS_LINK_CONNECTING: tdls link connecting + * @TDLS_LINK_CONNECTED: tdls link connected + * @TDLS_LINK_TEARING: tdls link tearing + */ +enum tdls_link_state { + TDLS_LINK_IDLE = 0, + TDLS_LINK_DISCOVERING, + TDLS_LINK_DISCOVERED, + TDLS_LINK_CONNECTING, + TDLS_LINK_CONNECTED, + TDLS_LINK_TEARING, +}; + +/** + * enum tdls_link_state_reason - tdls link reason + * @TDLS_LINK_SUCCESS: Success + * @TDLS_LINK_UNSPECIFIED: Unspecified reason + * @TDLS_LINK_NOT_SUPPORTED: Remote side doesn't support TDLS + * @TDLS_LINK_UNSUPPORTED_BAND: Remote side doesn't support this band + * @TDLS_LINK_NOT_BENEFICIAL: Going to AP is better than direct + * @TDLS_LINK_DROPPED_BY_REMOTE: Remote side doesn't want it anymore + */ +enum tdls_link_state_reason { + TDLS_LINK_SUCCESS, + TDLS_LINK_UNSPECIFIED = -1, + TDLS_LINK_NOT_SUPPORTED = -2, + TDLS_LINK_UNSUPPORTED_BAND = -3, + TDLS_LINK_NOT_BENEFICIAL = -4, + TDLS_LINK_DROPPED_BY_REMOTE = -5, +}; + +/** + * enum tdls_feature_mode - TDLS support mode + * @TDLS_SUPPORT_DISABLED: Disabled in ini or FW + * @TDLS_SUPPORT_SUSPENDED: TDLS supported by ini and FW, but disabled + * temporarily due to off-channel operations or due to other reasons + * @TDLS_SUPPORT_EXP_TRIG_ONLY: Explicit trigger mode + * @TDLS_SUPPORT_IMP_MODE: Implicit mode + * @TDLS_SUPPORT_EXT_CONTROL: External control mode + */ +enum tdls_feature_mode { + TDLS_SUPPORT_DISABLED = 0, + TDLS_SUPPORT_SUSPENDED, + TDLS_SUPPORT_EXP_TRIG_ONLY, + TDLS_SUPPORT_IMP_MODE, + TDLS_SUPPORT_EXT_CONTROL, +}; + +/** + * enum tdls_command_type - TDLS command type + * @TDLS_CMD_TX_ACTION: send tdls action frame + * @TDLS_CMD_ADD_STA: add tdls peer + * @TDLS_CMD_CHANGE_STA: change tdls peer + * @TDLS_CMD_ENABLE_LINK: enable tdls link + * @TDLS_CMD_DISABLE_LINK: disable tdls link + * @TDLS_CMD_CONFIG_FORCE_PEER: config external peer + * @TDLS_CMD_REMOVE_FORCE_PEER: remove external peer + * @TDLS_CMD_STATS_UPDATE: update tdls stats + * @TDLS_CMD_CONFIG_UPDATE: config tdls + * @TDLS_CMD_SCAN_DONE: scon done event + * @TDLS_CMD_SET_RESPONDER: responder event + * @TDLS_NOTIFY_STA_CONNECTION: notify sta connection + * @TDLS_NOTIFY_STA_DISCONNECTION: notify sta disconnection + * @TDLS_CMD_SET_TDLS_MODE: set the tdls mode + * @TDLS_CMD_SESSION_INCREMENT: notify session increment + * @TDLS_CMD_SESSION_DECREMENT: notify session decrement + * @TDLS_CMD_TEARDOWN_LINKS: notify teardown + * @TDLS_NOTIFY_RESET_ADAPTERS: notify adapter reset + * @TDLS_CMD_GET_ALL_PEERS: get all the tdls peers from the list + * @TDLS_CMD_ANTENNA_SWITCH: dynamic tdls antenna switch + * @TDLS_CMD_SET_OFFCHANNEL: tdls offchannel + * @TDLS_CMD_SET_OFFCHANMODE: tdls offchannel mode + * @TDLS_CMD_SET_SECOFFCHANOFFSET: tdls secondary offchannel offset + * @TDLS_DELETE_ALL_PEERS_INDICATION: tdls delete all peers indication + * @TDLS_CMD_START_BSS: SAP start indication to tdls module + * @TDLS_CMD_SET_LINK_UNFORCE: tdls to unforce link for MLO case + */ +enum tdls_command_type { + TDLS_CMD_TX_ACTION = 1, + TDLS_CMD_ADD_STA, + TDLS_CMD_CHANGE_STA, + TDLS_CMD_ENABLE_LINK, + TDLS_CMD_DISABLE_LINK, + TDLS_CMD_CONFIG_FORCE_PEER, + TDLS_CMD_REMOVE_FORCE_PEER, + TDLS_CMD_STATS_UPDATE, + TDLS_CMD_CONFIG_UPDATE, + TDLS_CMD_SCAN_DONE, + TDLS_CMD_SET_RESPONDER, + TDLS_NOTIFY_STA_CONNECTION, + TDLS_NOTIFY_STA_DISCONNECTION, + TDLS_CMD_SET_TDLS_MODE, + TDLS_CMD_SESSION_INCREMENT, + TDLS_CMD_SESSION_DECREMENT, + TDLS_CMD_TEARDOWN_LINKS, + TDLS_NOTIFY_RESET_ADAPTERS, + TDLS_CMD_GET_ALL_PEERS, + TDLS_CMD_ANTENNA_SWITCH, + TDLS_CMD_SET_OFFCHANNEL, + TDLS_CMD_SET_OFFCHANMODE, + TDLS_CMD_SET_SECOFFCHANOFFSET, + TDLS_DELETE_ALL_PEERS_INDICATION, + TDLS_CMD_START_BSS, + TDLS_CMD_SET_LINK_UNFORCE +}; + +/** + * enum tdls_event_type - TDLS event type + * @TDLS_EVENT_VDEV_STATE_CHANGE: umac connect/disconnect event + * @TDLS_EVENT_MGMT_TX_ACK_CNF: tx tdls frame ack event + * @TDLS_EVENT_RX_MGMT: rx discovery response frame + * @TDLS_EVENT_ADD_PEER: add peer or update peer + * @TDLS_EVENT_DEL_PEER: delete peer + * @TDLS_EVENT_DISCOVERY_REQ: discovery request + * @TDLS_EVENT_TEARDOWN_REQ: teardown request + * @TDLS_EVENT_SETUP_REQ: setup request + * @TDLS_EVENT_TEARDOWN_LINKS_DONE: teardown completion event + * @TDLS_EVENT_USER_CMD: tdls user command + * @TDLS_EVENT_ANTENNA_SWITCH: antenna switch event + */ +enum tdls_event_type { + TDLS_EVENT_VDEV_STATE_CHANGE = 0, + TDLS_EVENT_MGMT_TX_ACK_CNF, + TDLS_EVENT_RX_MGMT, + TDLS_EVENT_ADD_PEER, + TDLS_EVENT_DEL_PEER, + TDLS_EVENT_DISCOVERY_REQ, + TDLS_EVENT_TEARDOWN_REQ, + TDLS_EVENT_SETUP_REQ, + TDLS_EVENT_TEARDOWN_LINKS_DONE, + TDLS_EVENT_USER_CMD, + TDLS_EVENT_ANTENNA_SWITCH, +}; + +/** + * enum tdls_state_t - tdls state + * @QCA_WIFI_HAL_TDLS_S_DISABLED: TDLS is not enabled, or is disabled now + * @QCA_WIFI_HAL_TDLS_S_ENABLED: TDLS is enabled, but not yet tried + * @QCA_WIFI_HAL_TDLS_S_ESTABLISHED: Direct link is established + * @QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL: Direct link established using + * MCC + * @QCA_WIFI_HAL_TDLS_S_DROPPED: Direct link was established, but is now dropped + * @QCA_WIFI_HAL_TDLS_S_FAILED: Direct link failed + */ +enum tdls_state_t { + QCA_WIFI_HAL_TDLS_S_DISABLED = 1, + QCA_WIFI_HAL_TDLS_S_ENABLED, + QCA_WIFI_HAL_TDLS_S_ESTABLISHED, + QCA_WIFI_HAL_TDLS_S_ESTABLISHED_OFF_CHANNEL, + QCA_WIFI_HAL_TDLS_S_DROPPED, + QCA_WIFI_HAL_TDLS_S_FAILED, +}; + +/** + * enum tdls_off_chan_mode - mode for WMI_TDLS_SET_OFFCHAN_MODE_CMDID + * @TDLS_ENABLE_OFFCHANNEL: enable off channel + * @TDLS_DISABLE_OFFCHANNEL: disable off channel + */ +enum tdls_off_chan_mode { + TDLS_ENABLE_OFFCHANNEL, + TDLS_DISABLE_OFFCHANNEL +}; + +/** + * enum tdls_event_msg_type - TDLS event message type + * @TDLS_SHOULD_DISCOVER: should do discover for peer (based on tx bytes per + * second > tx_discover threshold) + * @TDLS_SHOULD_TEARDOWN: recommend teardown the link for peer due to tx bytes + * per second below tx_teardown_threshold + * @TDLS_PEER_DISCONNECTED: tdls peer disconnected + * @TDLS_CONNECTION_TRACKER_NOTIFY: TDLS/BT role change notification for + * connection tracker + */ +enum tdls_event_msg_type { + TDLS_SHOULD_DISCOVER = 0, + TDLS_SHOULD_TEARDOWN, + TDLS_PEER_DISCONNECTED, + TDLS_CONNECTION_TRACKER_NOTIFY +}; + +/** + * enum tdls_event_reason - TDLS event reason + * @TDLS_TEARDOWN_TX: tdls teardown recommended due to low transmits + * @TDLS_TEARDOWN_RSSI: tdls link tear down recommended due to poor RSSI + * @TDLS_TEARDOWN_SCAN: tdls link tear down recommended due to offchannel scan + * @TDLS_TEARDOWN_PTR_TIMEOUT: tdls peer disconnected due to PTR timeout + * @TDLS_TEARDOWN_BAD_PTR: tdls peer disconnected due wrong PTR format + * @TDLS_TEARDOWN_NO_RSP: tdls peer not responding + * @TDLS_DISCONNECTED_PEER_DELETE: tdls peer disconnected due to peer deletion + * @TDLS_PEER_ENTER_BUF_STA: tdls entered buffer STA role, TDLS connection + * tracker needs to handle this + * @TDLS_PEER_EXIT_BUF_STA: tdls exited buffer STA role, TDLS connection tracker + * needs to handle this + * @TDLS_ENTER_BT_BUSY: BT entered busy mode, TDLS connection tracker needs to + * handle this + * @TDLS_EXIT_BT_BUSY: BT exited busy mode, TDLS connection tracker needs to + * handle this + * @TDLS_SCAN_STARTED: TDLS module received a scan start event, TDLS connection + * tracker needs to handle this + * @TDLS_SCAN_COMPLETED: TDLS module received a scan complete event, TDLS + * connection tracker needs to handle this + */ +enum tdls_event_reason { + TDLS_TEARDOWN_TX, + TDLS_TEARDOWN_RSSI, + TDLS_TEARDOWN_SCAN, + TDLS_TEARDOWN_PTR_TIMEOUT, + TDLS_TEARDOWN_BAD_PTR, + TDLS_TEARDOWN_NO_RSP, + TDLS_DISCONNECTED_PEER_DELETE, + TDLS_PEER_ENTER_BUF_STA, + TDLS_PEER_EXIT_BUF_STA, + TDLS_ENTER_BT_BUSY, + TDLS_EXIT_BT_BUSY, + TDLS_SCAN_STARTED, + TDLS_SCAN_COMPLETED, +}; + +/** + * enum tdls_disable_sources - TDLS disable sources + * @TDLS_SET_MODE_SOURCE_USER: disable from user + * @TDLS_SET_MODE_SOURCE_SCAN: disable during scan + * @TDLS_SET_MODE_SOURCE_OFFCHANNEL: disable during offchannel + * @TDLS_SET_MODE_SOURCE_BTC: disable during bluetooth + * @TDLS_SET_MODE_SOURCE_P2P: disable during p2p + */ +enum tdls_disable_sources { + TDLS_SET_MODE_SOURCE_USER = 0, + TDLS_SET_MODE_SOURCE_SCAN, + TDLS_SET_MODE_SOURCE_OFFCHANNEL, + TDLS_SET_MODE_SOURCE_BTC, + TDLS_SET_MODE_SOURCE_P2P, +}; + +/** + * struct tdls_osif_indication - tdls indication to os if layer + * @vdev: vdev object + * @reason: used with teardown indication + * @peer_mac: MAC address of the TDLS peer + * @status: operation status + */ +struct tdls_osif_indication { + struct wlan_objmgr_vdev *vdev; + uint16_t reason; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + QDF_STATUS status; +}; + +/** + * struct tx_frame - tx frame + * @buf: frame buffer + * @buf_len: buffer length + * @tx_timer: tx send timer + */ +struct tx_frame { + uint8_t *buf; + size_t buf_len; + qdf_timer_t tx_timer; +}; + +enum tdls_configured_external_control { + TDLS_STRICT_EXTERNAL_CONTROL = 1, + TDLS_LIBERAL_EXTERNAL_CONTROL = 2, +}; + +/** + * enum tdls_feature_bit + * @TDLS_FEATURE_OFF_CHANNEL: tdls off channel + * @TDLS_FEATURE_WMM: tdls wmm + * @TDLS_FEATURE_BUFFER_STA: tdls buffer sta + * @TDLS_FEATURE_SLEEP_STA: tdls sleep sta feature + * @TDLS_FEATURE_SCAN: tdls scan + * @TDLS_FEATURE_ENABLE: tdls enabled + * @TDLS_FEAUTRE_IMPLICIT_TRIGGER: tdls implicit trigger + * @TDLS_FEATURE_EXTERNAL_CONTROL: enforce strict tdls external control + * @TDLS_FEATURE_LIBERAL_EXTERNAL_CONTROL: liberal external tdls control + */ +enum tdls_feature_bit { + TDLS_FEATURE_OFF_CHANNEL, + TDLS_FEATURE_WMM, + TDLS_FEATURE_BUFFER_STA, + TDLS_FEATURE_SLEEP_STA, + TDLS_FEATURE_SCAN, + TDLS_FEATURE_ENABLE, + TDLS_FEAUTRE_IMPLICIT_TRIGGER, + TDLS_FEATURE_EXTERNAL_CONTROL, + TDLS_FEATURE_LIBERAL_EXTERNAL_CONTROL, +}; + +#define TDLS_IS_OFF_CHANNEL_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_OFF_CHANNEL) +#define TDLS_IS_WMM_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_WMM) +#define TDLS_IS_BUFFER_STA_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_BUFFER_STA) +#define TDLS_IS_SLEEP_STA_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_SLEEP_STA) +#define TDLS_IS_SCAN_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_SCAN) +#define TDLS_IS_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_ENABLE) +#define TDLS_IS_IMPLICIT_TRIG_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEAUTRE_IMPLICIT_TRIGGER) +#define TDLS_IS_EXTERNAL_CONTROL_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_EXTERNAL_CONTROL) +#define TDLS_IS_LIBERAL_EXTERNAL_CONTROL_ENABLED(flags) \ + CHECK_BIT(flags, TDLS_FEATURE_LIBERAL_EXTERNAL_CONTROL) + +/** + * struct tdls_user_config - TDLS user configuration + * @tdls_tx_states_period: tdls tx states period + * @tdls_tx_pkt_threshold: tdls tx packets threshold + * @tdls_rx_pkt_threshold: tdls rx packets threshold + * @tdls_max_discovery_attempt: tdls discovery max times + * @tdls_idle_timeout: tdls idle timeout + * @tdls_idle_pkt_threshold: tdls idle packets threshold + * @tdls_rssi_trigger_threshold: tdls rssi trigger threshold + * @tdls_rssi_teardown_threshold: tdls rssi tear down threshold + * @tdls_rssi_delta: tdls rssi delta + * @tdls_uapsd_mask: tdls uapsd mask + * @tdls_uapsd_inactivity_time: tdls uapsd inactivity time + * @tdls_uapsd_pti_window: tdls peer traffic indication window + * @tdls_uapsd_ptr_timeout: tdls peer response timeout + * @tdls_feature_flags: tdls feature flags + * @tdls_pre_off_chan_num: tdls off channel number + * @tdls_pre_off_chan_freq_6g: tdls pref off channel freq for 6g band + * @tdls_pre_off_chan_bw: tdls off channel bandwidth + * @tdls_peer_kickout_threshold: sta kickout threshold for tdls peer + * @tdls_discovery_wake_timeout: tdls discovery wake timeout + * @delayed_trig_framint: delayed trigger frame interval + * @tdls_vdev_nss_2g: tdls NSS setting for 2G band + * @tdls_vdev_nss_5g: tdls NSS setting for 5G band + * @tdls_buffer_sta_enable: tdls buffer station enable + * @tdls_off_chan_enable: tdls off channel enable + * @tdls_off_chan_enable_orig: original tdls off channel enable + * @tdls_wmm_mode_enable: tdls wmm mode enable + * @tdls_external_control: tdls external control enable + * @tdls_implicit_trigger_enable: tdls implicit trigger enable + * @tdls_scan_enable: tdls scan enable + * @tdls_sleep_sta_enable: tdls sleep sta enable + * @tdls_support_enable: tdls support enable + * @tdls_link_id: mlo link id + */ +struct tdls_user_config { + uint32_t tdls_tx_states_period; + uint32_t tdls_tx_pkt_threshold; + uint32_t tdls_rx_pkt_threshold; + uint32_t tdls_max_discovery_attempt; + uint32_t tdls_idle_timeout; + uint32_t tdls_idle_pkt_threshold; + int32_t tdls_rssi_trigger_threshold; + int32_t tdls_rssi_teardown_threshold; + uint32_t tdls_rssi_delta; + uint32_t tdls_uapsd_mask; + uint32_t tdls_uapsd_inactivity_time; + uint32_t tdls_uapsd_pti_window; + uint32_t tdls_uapsd_ptr_timeout; + uint32_t tdls_feature_flags; + uint32_t tdls_pre_off_chan_num; + uint32_t tdls_pre_off_chan_freq_6g; + uint32_t tdls_pre_off_chan_bw; + uint32_t tdls_peer_kickout_threshold; + uint32_t tdls_discovery_wake_timeout; + uint32_t delayed_trig_framint; + uint8_t tdls_vdev_nss_2g; + uint8_t tdls_vdev_nss_5g; + bool tdls_buffer_sta_enable; + bool tdls_off_chan_enable; + bool tdls_off_chan_enable_orig; + bool tdls_wmm_mode_enable; + uint8_t tdls_external_control; + bool tdls_implicit_trigger_enable; + bool tdls_scan_enable; + bool tdls_sleep_sta_enable; + bool tdls_support_enable; + int tdls_link_id; +}; + +/** + * struct tdls_config_params - tdls configure paramets + * @tdls: tdls support mode + * @tx_period_t: tdls tx stats period + * @tx_packet_n: tdls tx packets number threshold + * @discovery_tries_n: tdls max discovery attempt count + * @idle_timeout_t: tdls idle time timeout + * @idle_packet_n: tdls idle pkt threshold + * @rssi_trigger_threshold: tdls rssi trigger threshold, checked before setup + * @rssi_teardown_threshold: tdls rssi teardown threshold + * @rssi_delta: rssi delta + */ +struct tdls_config_params { + uint32_t tdls; + uint32_t tx_period_t; + uint32_t tx_packet_n; + uint32_t discovery_tries_n; + uint32_t idle_timeout_t; + uint32_t idle_packet_n; + int32_t rssi_trigger_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; +}; + +/** + * struct tdls_tx_cnf: tdls tx ack + * @vdev_id: vdev id + * @action_cookie: frame cookie + * @buf: frame buf + * @buf_len: buffer length + * @status: tx send status + */ +struct tdls_tx_cnf { + int vdev_id; + uint64_t action_cookie; + void *buf; + size_t buf_len; + int status; +}; + +/** + * struct tdls_rx_mgmt_frame - rx mgmt frame structure + * @frame_len: frame length + * @rx_freq: rx freq + * @vdev_id: vdev id + * @frm_type: frame type + * @rx_rssi: rx rssi + * @buf: buffer address + */ +struct tdls_rx_mgmt_frame { + uint32_t frame_len; + uint32_t rx_freq; + uint32_t vdev_id; + uint32_t frm_type; + uint32_t rx_rssi; + QDF_FLEX_ARRAY(uint8_t, buf); +}; + +/** + * typedef tdls_rx_callback() - Callback for rx mgmt frame + * @user_data: user data associated to this rx mgmt frame. + * @rx_frame: RX mgmt frame + * + * This callback will be used to give rx frames to hdd. + * + * Return: None + */ +typedef void (*tdls_rx_callback)(void *user_data, + struct tdls_rx_mgmt_frame *rx_frame); + +/** + * typedef tdls_wmm_check() - Callback for wmm info + * @vdev_id: ID of the vdev to check + * + * This callback will be used to check wmm information + * + * Return: true or false + */ +typedef bool (*tdls_wmm_check)(uint8_t vdev_id); + + +/* This callback is used to report state change of peer to wpa_supplicant */ +typedef int (*tdls_state_change_callback)(const uint8_t *mac, + uint32_t opclass, + uint32_t channel, + uint32_t state, + int32_t reason, void *ctx); + +/* This callback is used to report events to os_if layer */ +typedef void (*tdls_evt_callback) (void *data, + enum tdls_event_type ev_type, + struct tdls_osif_indication *event); + +/* This callback is used to register TDLS peer with the datapath */ +typedef QDF_STATUS (*tdls_register_peer_callback)(void *userdata, + uint32_t vdev_id, + const uint8_t *mac, + uint8_t qos); + +/* This callback is used to deregister TDLS peer from the datapath */ +typedef QDF_STATUS +(*tdls_deregister_peer_callback)(void *userdata, + uint32_t vdev_id, + struct qdf_mac_addr *peer_mac); + +/* This callback is used to update datapath vdev flags */ +typedef QDF_STATUS +(*tdls_dp_vdev_update_flags_callback)(void *cbk_data, + uint8_t vdev_id, + uint32_t vdev_param, + bool is_link_up); + +/* This callback is to release vdev ref for tdls offchan param related msg */ +typedef void (*tdls_offchan_parms_callback)(struct wlan_objmgr_vdev *vdev); + +/** + * typedef tdls_vdev_init_cb() - Callback for initializing the tdls private + * structure + * @vdev: vdev object + * + * This callback will be used to create the vdev private object and store + * in os_priv. + * + * Return: QDF_STATUS + */ +typedef QDF_STATUS (*tdls_vdev_init_cb)(struct wlan_objmgr_vdev *vdev); + +/** + * typedef tdls_vdev_deinit_cb() - Callback for deinitializing the tdls + * private structure + * @vdev: vdev object + * + * This callback will be used to destroy the vdev private object. + * + * Return: None + */ +typedef void (*tdls_vdev_deinit_cb)(struct wlan_objmgr_vdev *vdev); + +/** + * struct tdls_osif_cb - Callbacks for updating osif params. + * @tdls_osif_conn_update: Update osif params when TDLS peer is connected + * @tdls_osif_disconn_update: Update osif params when TDLS peer is disconnected + * + * These callbacks will be used for updating osif params. + */ +struct tdls_osif_cb { + void (*tdls_osif_conn_update)(struct wlan_objmgr_vdev *vdev); + void (*tdls_osif_disconn_update)(struct wlan_objmgr_vdev *vdev); +}; + +/** + * struct tdls_start_params - tdls start params + * @config: tdls user config + * @tdls_send_mgmt_req: pass eWNI_SME_TDLS_SEND_MGMT_REQ value + * @tdls_add_sta_req: pass eWNI_SME_TDLS_ADD_STA_REQ value + * @tdls_del_sta_req: pass eWNI_SME_TDLS_DEL_STA_REQ value + * @tdls_update_peer_state: pass WMA_UPDATE_TDLS_PEER_STATE value + * @tdls_del_all_peers: pass eWNI_SME_DEL_ALL_TDLS_PEERS + * @tdls_update_dp_vdev_flags: pass CDP_UPDATE_TDLS_FLAGS + * @tdls_rx_cb: TDLS RX callback + * @tdls_rx_cb_data: TDLS RX callback context + * @tdls_wmm_cb: TDLS WMM check callback + * @tdls_wmm_cb_data: TDLS WMM check callback context + * @tdls_event_cb: tdls event callback + * @tdls_evt_cb_data: tdls event data + * @tdls_peer_context: userdata for register/deregister TDLS peer + * @tdls_reg_peer: register tdls peer with datapath + * @tdls_dp_vdev_update: update vdev flags in datapath + * @tdls_osif_init_cb: callback to initialize the tdls priv + * @tdls_osif_deinit_cb: callback to deinitialize the tdls priv + * @tdls_osif_update_cb: callback to update osif params + */ +struct tdls_start_params { + struct tdls_user_config config; + uint16_t tdls_send_mgmt_req; + uint16_t tdls_add_sta_req; + uint16_t tdls_del_sta_req; + uint16_t tdls_update_peer_state; + uint16_t tdls_del_all_peers; + uint32_t tdls_update_dp_vdev_flags; + tdls_rx_callback tdls_rx_cb; + void *tdls_rx_cb_data; + tdls_wmm_check tdls_wmm_cb; + void *tdls_wmm_cb_data; + tdls_evt_callback tdls_event_cb; + void *tdls_evt_cb_data; + void *tdls_peer_context; + tdls_register_peer_callback tdls_reg_peer; + tdls_dp_vdev_update_flags_callback tdls_dp_vdev_update; + tdls_vdev_init_cb tdls_osif_init_cb; + tdls_vdev_deinit_cb tdls_osif_deinit_cb; + struct tdls_osif_cb tdls_osif_update_cb; +}; + +/** + * struct tdls_add_peer_params - add peer request parameter + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + */ +struct tdls_add_peer_params { + uint8_t peer_addr[QDF_MAC_ADDR_SIZE]; + uint32_t peer_type; + uint32_t vdev_id; +}; + +/** + * struct tdls_add_peer_request - peer add request + * @vdev: vdev + * @add_peer_req: add peer request parameters + */ +struct tdls_add_peer_request { + struct wlan_objmgr_vdev *vdev; + struct tdls_add_peer_params add_peer_req; +}; + +/** + * struct tdls_del_peer_params - delete peer request parameter + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + */ +struct tdls_del_peer_params { + const uint8_t *peer_addr; + uint32_t peer_type; + uint32_t vdev_id; +}; + +/** + * struct tdls_del_peer_request - peer delete request + * @vdev: vdev + * @del_peer_req: delete peer request parameters + */ +struct tdls_del_peer_request { + struct wlan_objmgr_vdev *vdev; + struct tdls_del_peer_params del_peer_req; +}; + +/** + * struct vhtmcsinfo - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams + * @rx_highest: Indicates highest long GI VHT PPDU data rate + * STA can receive. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams + * @tx_highest: Indicates highest long GI VHT PPDU data rate + * STA can transmit. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest TX data rate supported. + */ +struct vhtmcsinfo { + uint16_t rx_mcs_map; + uint16_t rx_highest; + uint16_t tx_mcs_map; + uint16_t tx_highest; +}; + +/** + * struct vhtcap - VHT capabilities + * + * This structure is the "VHT capabilities element" as + * described in 802.11ac D3.0 8.4.2.160 + * @vht_capinfo: VHT capability info + * @supp_mcs: VHT MCS supported rates + */ +struct vhtcap { + uint32_t vht_capinfo; + struct vhtmcsinfo supp_mcs; +}; + +#ifdef WLAN_FEATURE_11AX +/** + * struct hecap - HE capabilities + * + * This structure is the "HE capabilities element" as + * described in 802.11ax D4.0 section 9.4.2.232.3 + * @mac_cap_info: MAC capability info + * @phycap_info: Phy Capability info + * @he_cap_mcs_info: HE capabilities MCS information + */ +struct hecap { + uint8_t mac_cap_info[6]; + uint8_t phycap_info[11]; + struct { + uint16_t rx_he_mcs_map_lt_80; + uint16_t tx_he_mcs_map_lt_80; + uint16_t rx_he_mcs_map_160; + uint16_t tx_he_mcs_map_160; + uint16_t rx_he_mcs_map_80_80; + uint16_t tx_he_mcs_map_80_80; + } he_cap_mcs_info; +} qdf_packed; + +struct hecap_6ghz { + /* Minimum MPDU Start Spacing B0..B2 + * Maximum A-MPDU Length Exponent B3..B5 + * Maximum MPDU Length B6..B7 */ + uint8_t a_mpdu_params; /* B0..B7 */ + uint8_t info; /* B8..B15 */ +}; +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * struct ehtcapfixed - EHT capabilities fixed data + * @mac_cap_info: MAC capabilities + * @phy_cap_info: PHY capabilities + */ +struct ehtcapfixed { + uint8_t mac_cap_info[2]; + uint8_t phy_cap_info[9]; +}; + +/** + * struct ehtcap - EHT capabilities + * @eht_cap_fixed: fixed parts, see &ehtcapfixed + * @optional: optional parts + */ +struct ehtcap { + struct ehtcapfixed eht_cap_fixed; + uint8_t optional[]; +} qdf_packed; +#endif + +struct tdls_update_peer_params { + uint8_t peer_addr[QDF_MAC_ADDR_SIZE]; + uint32_t peer_type; + uint32_t vdev_id; + uint16_t capability; + uint8_t extn_capability[WLAN_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_len; + uint8_t supported_rates[WLAN_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + struct htcap_cmn_ie ht_cap; + uint8_t vhtcap_present; + struct vhtcap vht_cap; +#ifdef WLAN_FEATURE_11AX + uint8_t he_cap_len; + struct hecap he_cap; + struct hecap_6ghz he_6ghz_cap; +#endif +#ifdef WLAN_FEATURE_11BE + uint8_t ehtcap_present; + uint8_t eht_cap_len; + struct ehtcap eht_cap; +#endif + uint8_t uapsd_queues; + uint8_t max_sp; + uint8_t supported_channels_len; + qdf_freq_t supported_chan_freq[WLAN_MAC_MAX_SUPP_CHANNELS]; + uint8_t supported_oper_classes_len; + uint8_t supported_oper_classes[WLAN_MAX_SUPP_OPER_CLASSES]; + bool is_qos_wmm_sta; + bool is_pmf; +}; + +struct tdls_update_peer_request { + struct wlan_objmgr_vdev *vdev; + struct tdls_update_peer_params update_peer_req; +}; + +/** + * struct tdls_oper_request - tdls operation request + * @vdev: vdev object + * @peer_addr: MAC address of the TDLS peer + */ +struct tdls_oper_request { + struct wlan_objmgr_vdev *vdev; + uint8_t peer_addr[QDF_MAC_ADDR_SIZE]; +}; + +/** + * struct tdls_oper_config_force_peer_request - tdls enable force peer request + * @vdev: vdev object + * @peer_addr: MAC address of the TDLS peer + * @chan: channel + * @ch_freq: ch_freq + * @max_latency: maximum latency + * @op_class: operation class + * @min_bandwidth: minimal bandwidth + * @callback: state change callback + */ +struct tdls_oper_config_force_peer_request { + struct wlan_objmgr_vdev *vdev; + uint8_t peer_addr[QDF_MAC_ADDR_SIZE]; + uint32_t chan; + qdf_freq_t ch_freq; + uint32_t max_latency; + uint32_t op_class; + uint32_t min_bandwidth; + tdls_state_change_callback callback; +}; + +/** + * struct tdls_info - tdls info + * + * @vdev_id: vdev id + * @tdls_state: tdls state + * @notification_interval_ms: notification interval in ms + * @tx_discovery_threshold: tx discovery threshold + * @tx_teardown_threshold: tx teardown threshold + * @rssi_teardown_threshold: rx teardown threshold + * @rssi_delta: rssi delta + * @tdls_options: tdls options + * @peer_traffic_ind_window: peer traffic indication window + * @peer_traffic_response_timeout: peer traffic response timeout + * @puapsd_mask: puapsd mask + * @puapsd_inactivity_time: puapsd inactivity time + * @puapsd_rx_frame_threshold: puapsd rx frame threshold + * @teardown_notification_ms: tdls teardown notification interval + * @tdls_peer_kickout_threshold: tdls packets threshold + * for peer kickout operation + * @tdls_discovery_wake_timeout: tdls discovery wake timeout + */ +struct tdls_info { + uint32_t vdev_id; + uint32_t tdls_state; + uint32_t notification_interval_ms; + uint32_t tx_discovery_threshold; + uint32_t tx_teardown_threshold; + int32_t rssi_teardown_threshold; + int32_t rssi_delta; + uint32_t tdls_options; + uint32_t peer_traffic_ind_window; + uint32_t peer_traffic_response_timeout; + uint32_t puapsd_mask; + uint32_t puapsd_inactivity_time; + uint32_t puapsd_rx_frame_threshold; + uint32_t teardown_notification_ms; + uint32_t tdls_peer_kickout_threshold; + uint32_t tdls_discovery_wake_timeout; +}; + +/** + * struct tdls_ch_params - channel parameters + * @ch_freq: Channel frequency + * @pwr: power level + * @dfs_set: is dfs supported or not + * @half_rate: is the channel operating at 10MHz + * @quarter_rate: is the channel operating at 5MHz + */ +struct tdls_ch_params { + qdf_freq_t ch_freq; + uint8_t pwr; + bool dfs_set; + bool half_rate; + bool quarter_rate; +}; + +/** + * struct tdls_peer_params - TDLS peer capabilities parameters + * @is_peer_responder: is peer responder or not + * @peer_uapsd_queue: peer uapsd queue + * @peer_max_sp: peer max SP value + * @peer_buff_sta_support: peer buffer sta supported or not + * @peer_off_chan_support: peer offchannel support + * @peer_curr_operclass: peer current operating class + * @self_curr_operclass: self current operating class + * @peer_chanlen: peer channel length + * @peer_chan: peer channel list + * @peer_oper_classlen: peer operating class length + * @peer_oper_class: peer operating class + * @pref_off_channum: preferred offchannel number + * @pref_off_chan_bandwidth: peer offchannel bandwidth + * @opclass_for_prefoffchan: operating class for offchannel + * @pref_offchan_freq: preferred offchannel frequency + */ +struct tdls_peer_params { + uint8_t is_peer_responder; + uint8_t peer_uapsd_queue; + uint8_t peer_max_sp; + uint8_t peer_buff_sta_support; + uint8_t peer_off_chan_support; + uint8_t peer_curr_operclass; + uint8_t self_curr_operclass; + uint8_t peer_chanlen; + struct tdls_ch_params peer_chan[WLAN_MAC_WMI_MAX_SUPP_CHANNELS]; + uint8_t peer_oper_classlen; + uint8_t peer_oper_class[WLAN_MAX_SUPP_OPER_CLASSES]; + uint8_t pref_off_channum; + uint8_t pref_off_chan_bandwidth; + uint8_t opclass_for_prefoffchan; + uint32_t pref_offchan_freq; +}; + +/** + * struct tdls_peer_update_state - TDLS peer state parameters + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @peer_state: peer state + * @peer_cap: peer capabality + * @resp_reqd: response needed + */ +struct tdls_peer_update_state { + uint32_t vdev_id; + uint8_t peer_macaddr[QDF_MAC_ADDR_SIZE]; + uint32_t peer_state; + struct tdls_peer_params peer_cap; + bool resp_reqd; +}; + +/** + * struct tdls_channel_switch_params - channel switch parameter structure + * @vdev_id: vdev ID + * @peer_mac_addr: Peer mac address + * @tdls_off_ch_bw_offset: Target off-channel bandwidth offset + * @tdls_off_ch: Target Off Channel + * @tdls_sw_mode: Switch mode + * @oper_class: Operating class for target channel + * @is_responder: Responder or initiator + * @tdls_off_chan_freq: Target Off Channel frequency + * @num_off_channels: Number of channels allowed for off channel operation + * @allowed_off_channels: Channel list allowed for off channels + */ +struct tdls_channel_switch_params { + uint32_t vdev_id; + uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE]; + uint8_t tdls_off_ch_bw_offset; + uint8_t tdls_off_ch; + uint8_t tdls_sw_mode; + uint8_t oper_class; + uint8_t is_responder; + uint32_t tdls_off_chan_freq; + uint16_t num_off_channels; + struct tdls_ch_params allowed_off_channels[WLAN_MAC_WMI_MAX_SUPP_CHANNELS]; +}; + +/** + * enum uapsd_access_cat - U-APSD Access Categories + * @UAPSD_AC_BE: best effort + * @UAPSD_AC_BK: back ground + * @UAPSD_AC_VI: video + * @UAPSD_AC_VO: voice + */ +enum uapsd_access_cat { + UAPSD_AC_BE, + UAPSD_AC_BK, + UAPSD_AC_VI, + UAPSD_AC_VO +}; + +/** + * enum tspec_dir_type - TSPEC Direction type + * @TX_DIR: uplink + * @RX_DIR: downlink + * @BI_DIR: bidirectional + */ +enum tspec_dir_type { + TX_DIR = 0, + RX_DIR = 1, + BI_DIR = 2, +}; + +/** + * struct tdls_event_info - firmware tdls event + * @vdev_id: vdev id + * @peermac: peer mac address + * @message_type: message type + * @peer_reason: reason + */ +struct tdls_event_info { + uint8_t vdev_id; + struct qdf_mac_addr peermac; + uint16_t message_type; + uint32_t peer_reason; +}; + +/** + * struct tdls_event_notify - tdls event notify + * @vdev: vdev object + * @event: tdls event + */ +struct tdls_event_notify { + struct wlan_objmgr_vdev *vdev; + struct tdls_event_info event; +}; + +/** + * struct tdls_send_mgmt - tdls send management frame + * @peer_mac: peer's mac address + * @frame_type: Type of TDLS mgmt frame to be sent + * @dialog: dialog token used in the frame. + * @status_code: status to be included in the frame + * @responder: Tdls request type + * @peer_capability: peer cpabilities + * @len: length of additional Ies + * @buf: additional IEs to be included + */ +struct tdls_send_mgmt { + struct qdf_mac_addr peer_mac; + uint8_t frame_type; + uint8_t dialog; + uint16_t status_code; + uint8_t responder; + uint32_t peer_capability; + uint8_t len; + /* Variable length, do not add anything after this */ + uint8_t buf[]; +}; + +/** + * struct tdls_validate_action_req - tdls validate mgmt request + * @action_code: action code + * @peer_mac: peer mac address + * @dialog_token: dialog code + * @status_code: status code to add + * @len: len of the frame + * @responder: whether to respond or not + */ +struct tdls_validate_action_req { + uint8_t action_code; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + uint8_t dialog_token; + uint8_t status_code; + size_t len; + int responder; +}; + +/** + * struct tdls_get_all_peers - get all peers from the list + * @vdev: vdev object + * @buf: output string buffer to hold the peer info + * @buf_len: the size of output string buffer + */ +struct tdls_get_all_peers { + struct wlan_objmgr_vdev *vdev; + char *buf; + int buf_len; +}; + +/** + * struct tdls_action_frame_request - tdls send mgmt request + * @vdev: vdev object + * @chk_frame: This struct used to validate mgmt frame + * @session_id: session id + * @link_id: link id + * @vdev_id: vdev id + * @cmd_buf: cmd buffer + * @len: length of the frame + * @use_default_ac: access category + * @link_active: whether link active command send successfully + * @tdls_mgmt: tdls management + */ +struct tdls_action_frame_request { + struct wlan_objmgr_vdev *vdev; + struct tdls_validate_action_req chk_frame; + uint8_t session_id; + uint8_t link_id; + uint8_t vdev_id; + const uint8_t *cmd_buf; + uint8_t len; + bool use_default_ac; + bool link_active; + /* Variable length, do not add anything after this */ + struct tdls_send_mgmt tdls_mgmt; +}; + +/** + * struct tdls_set_responder_req - tdls set responder in peer + * @vdev: vdev object + * @peer_mac: peer mac address + * @responder: whether to respond or not + */ +struct tdls_set_responder_req { + struct wlan_objmgr_vdev *vdev; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + uint8_t responder; +}; + +/** + * struct tdls_sta_notify_params - STA connection notify info + * @vdev: vdev object + * @tdls_prohibited: peer mac addr + * @tdls_chan_swit_prohibited: peer type + * @lfr_roam: is trigger due to lfr + * @user_disconnect: should userspace be notified of disconnect + * @session_id: session id + */ +struct tdls_sta_notify_params { + struct wlan_objmgr_vdev *vdev; + bool tdls_prohibited; + bool tdls_chan_swit_prohibited; + bool lfr_roam; + bool user_disconnect; + uint8_t session_id; +}; + +/** + * struct tdls_delete_all_peers_params - TDLS set mode params + * @vdev: vdev object + */ +struct tdls_delete_all_peers_params { + struct wlan_objmgr_vdev *vdev; +}; + +/** + * struct tdls_set_mode_params - TDLS set mode params + * @vdev: vdev object + * @tdls_mode: tdls mode to set + * @update_last: inform to update last tdls mode + * @source: mode change requester + */ +struct tdls_set_mode_params { + struct wlan_objmgr_vdev *vdev; + enum tdls_feature_mode tdls_mode; + bool update_last; + enum tdls_disable_sources source; +}; + +/** + * struct tdls_del_all_tdls_peers - delete all tdls peers + * @msg_type: type of message + * @msg_len: length of message + * @bssid: bssid of peer device + */ +struct tdls_del_all_tdls_peers { + uint16_t msg_type; + uint16_t msg_len; + struct qdf_mac_addr bssid; +}; + +/** + * struct tdls_antenna_switch_request - TDLS antenna switch request + * @vdev: vdev object + * @mode: antenna mode, 1x1 or 2x2 + */ +struct tdls_antenna_switch_request { + struct wlan_objmgr_vdev *vdev; + uint32_t mode; +}; + +/** + * struct tdls_set_offchannel - TDLS set offchannel + * @vdev: vdev object + * @offchannel: Updated tdls offchannel value. + * @callback: callback to release vdev ref. + */ +struct tdls_set_offchannel { + struct wlan_objmgr_vdev *vdev; + uint16_t offchannel; + tdls_offchan_parms_callback callback; +}; + +/** + * struct tdls_set_offchanmode - TDLS set offchannel mode + * @vdev: vdev object + * @offchan_mode: Updated tdls offchannel mode value. + * @callback: callback to release vdev ref. + */ +struct tdls_set_offchanmode { + struct wlan_objmgr_vdev *vdev; + uint8_t offchan_mode; + tdls_offchan_parms_callback callback; +}; + +/** + * struct tdls_set_secoffchanneloffset - TDLS set secondary offchannel offset + * @vdev: vdev object + * @offchan_offset: Offchan offset value. + * @callback: callback to release vdev ref. + */ +struct tdls_set_secoffchanneloffset { + struct wlan_objmgr_vdev *vdev; + int offchan_offset; + tdls_offchan_parms_callback callback; +}; + +/** + * enum legacy_result_code - defined to comply with tSirResultCodes, need refine + * when mlme converged. + * @legacy_result_success: success + * @legacy_result_max: max result value + */ +enum legacy_result_code { + legacy_result_success, + legacy_result_max = 0x7FFFFFFF +}; + +/** + * struct tdls_send_mgmt_rsp - TDLS Response struct PE --> TDLS module + * @vdev_id: vdev id + * @status_code: status code as tSirResultCodes + * @psoc: soc object + */ +struct tdls_send_mgmt_rsp { + uint8_t vdev_id; + enum legacy_result_code status_code; + struct wlan_objmgr_psoc *psoc; +}; + +/** + * struct tdls_mgmt_tx_completion_ind - TDLS TX completion PE --> TDLS module + * @vdev_id: vdev_id + * @tx_complete_status: tx complete status + * @psoc: soc object + */ +struct tdls_mgmt_tx_completion_ind { + uint8_t vdev_id; + uint32_t tx_complete_status; + struct wlan_objmgr_psoc *psoc; +}; + +/** + * struct tdls_add_sta_rsp - TDLS Response struct PE --> TDLS module + * @status_code: status code as tSirResultCodes + * @peermac: MAC address of the TDLS peer + * @session_id: session id + * @sta_type: sta type + * @tdls_oper: add peer type + * @psoc: soc object + */ +struct tdls_add_sta_rsp { + QDF_STATUS status_code; + struct qdf_mac_addr peermac; + uint8_t session_id; + uint16_t sta_type; + enum tdls_add_oper tdls_oper; + struct wlan_objmgr_psoc *psoc; +}; + +/** + * struct tdls_del_sta_rsp - TDLS Response struct PE --> TDLS module + * @session_id: session id + * @status_code: status code as tSirResultCodes + * @peermac: MAC address of the TDLS peer + * @psoc: soc object + */ +struct tdls_del_sta_rsp { + uint8_t session_id; + QDF_STATUS status_code; + struct qdf_mac_addr peermac; + struct wlan_objmgr_psoc *psoc; +}; + +/** + * struct tdls_send_mgmt_request - tdls management request + * @message_type: type of pe message + * @length: length of the frame. + * @session_id: session id + * @req_type: type of action frame + * @dialog: dialog token used in the frame. + * @status_code: status to be included in the frame. + * @responder: tdls request type + * @peer_capability: peer capability information + * @bssid: bssid + * @peer_mac: mac address of the peer + * @ac: Access Category to use + * @add_ie: additional ie's to be included + */ +struct tdls_send_mgmt_request { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint8_t req_type; + uint8_t dialog; + uint16_t status_code; + uint8_t responder; + uint32_t peer_capability; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_mac; + enum wifi_traffic_ac ac; + /* Variable length. Dont add any field after this. */ + QDF_FLEX_ARRAY(uint8_t, add_ie); +}; + +/** + * struct tdls_add_sta_req - TDLS request struct TDLS module --> PE + * @message_type: eWNI_SME_TDLS_ADD_STA_REQ + * @length: message length + * @session_id: session id + * @transaction_id: transaction id for cmd + * @bssid: bssid + * @tdls_oper: add peer type + * @peermac: MAC address for TDLS peer + * @capability: mac capability as sSirMacCapabilityInfo + * @extn_capability: extent capability + * @supported_rates_length: rates length + * @supported_rates: supported rates + * @htcap_present: ht capability present + * @ht_cap: ht capability + * @vhtcap_present: vht capability present + * @vht_cap: vht capability + * @he_cap_len: he capability length + * @he_cap: he capability + * @he_6ghz_cap: HE 6 GHz capability + * @ehtcap_present: eht capability present + * @eht_cap_len: eht capability length + * @eht_cap: eht capability + * @uapsd_queues: uapsd queue as sSirMacQosInfoStation + * @max_sp: maximum service period + * @is_pmf: is PMF active + */ +struct tdls_add_sta_req { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint16_t transaction_id; + struct qdf_mac_addr bssid; + enum tdls_add_oper tdls_oper; + struct qdf_mac_addr peermac; + uint16_t capability; + uint8_t extn_capability[WLAN_MAC_MAX_EXTN_CAP]; + uint8_t supported_rates_length; + uint8_t supported_rates[WLAN_MAC_MAX_SUPP_RATES]; + uint8_t htcap_present; + struct htcap_cmn_ie ht_cap; + uint8_t vhtcap_present; + struct vhtcap vht_cap; +#ifdef WLAN_FEATURE_11AX + uint8_t he_cap_len; + struct hecap he_cap; + struct hecap_6ghz he_6ghz_cap; +#endif +#ifdef WLAN_FEATURE_11BE + uint8_t ehtcap_present; + uint8_t eht_cap_len; + struct ehtcap eht_cap; +#endif + uint8_t uapsd_queues; + uint8_t max_sp; + bool is_pmf; +}; + +/** + * struct tdls_del_sta_req - TDLS Request struct TDLS module --> PE + * @message_type: message type eWNI_SME_TDLS_DEL_STA_REQ + * @length: message length + * @session_id: session id + * @transaction_id: transaction id for cmd + * @bssid: bssid + * @peermac: MAC address of the TDLS peer + */ +struct tdls_del_sta_req { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + uint16_t transaction_id; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peermac; +}; + +/** + * struct tdls_link_teardown - TDLS link teardown struct + * @psoc: soc object + */ +struct tdls_link_teardown { + struct wlan_objmgr_psoc *psoc; +}; + +#ifdef FEATURE_SET +/** + * struct wlan_tdls_features - TDLS feature set struct + * @enable_tdls: enable/disable tdls + * @enable_tdls_offchannel: enable/disable tdls offchannel + * @max_tdls_peers: Max tdls Peers + * @enable_tdls_capability_enhance: enable tdls capability enhance + */ +struct wlan_tdls_features { + bool enable_tdls; + bool enable_tdls_offchannel; + uint8_t max_tdls_peers; + bool enable_tdls_capability_enhance; +}; +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h new file mode 100644 index 0000000000..f0930f9cdb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_tgt_api.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_tgt_api.h + * + * TDLS south bound interface declaration + */ + +#ifndef _WLAN_TDLS_TGT_API_H_ +#define _WLAN_TDLS_TGT_API_H_ +#include +#include "wlan_tdls_main.h" + +/** + * tgt_tdls_set_fw_state() - invoke lmac tdls update fw + * @psoc: soc object + * @tdls_param: update tdls state parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_set_fw_state(struct wlan_objmgr_psoc *psoc, + struct tdls_info *tdls_param); + +/** + * tgt_tdls_set_peer_state() - invoke lmac tdls update peer state + * @psoc: soc object + * @peer_param: update tdls peer parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_set_peer_state(struct wlan_objmgr_psoc *psoc, + struct tdls_peer_update_state *peer_param); + +/** + * tgt_tdls_set_offchan_mode() - invoke lmac tdls set off-channel mode + * @psoc: soc object + * @param: set tdls off channel parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc, + struct tdls_channel_switch_params *param); + +/** + * tgt_tdls_send_mgmt_rsp() - process tdls mgmt response + * @pmsg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg); + +/** + * tgt_tdls_send_mgmt_tx_completion() -process tx completion message + * @pmsg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg); + +/** + * tgt_tdls_del_peer_rsp() - handle TDLS del peer response + * @pmsg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_del_peer_rsp(struct scheduler_msg *pmsg); + +/** + * tgt_tdls_add_peer_rsp() - handle TDLS add peer response + * @pmsg: scheduler msg + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_tdls_add_peer_rsp(struct scheduler_msg *pmsg); + +/** + * tgt_tdls_register_ev_handler() - invoke lmac register tdls event handler + * @psoc: soc object + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS tgt_tdls_register_ev_handler(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_tdls_unregister_ev_handler() - invoke lmac unregister tdls event handler + * @psoc: soc object + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS tgt_tdls_unregister_ev_handler(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_tdls_event_handler() - The callback registered to WMI for tdls events + * @psoc: psoc object + * @info: tdls event info + * + * The callback is registered by tgt as tdls rx ops handler. + * + * Return: 0 for success or err code. + */ +QDF_STATUS +tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc, + struct tdls_event_info *info); + +/** + * tgt_tdls_mgmt_frame_rx_cb() - callback for rx mgmt frame + * @psoc: soc context + * @peer: peer context + * @buf: rx buffer + * @mgmt_rx_params: mgmt rx parameters + * @frm_type: frame type + * + * This function gets called from mgmt tx/rx component when rx mgmt + * received. + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS tgt_tdls_mgmt_frame_rx_cb(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type); + +/** + * tgt_tdls_peers_deleted_notification()- notification from legacy lim + * @psoc: soc object + * @session_id: session id + * + * This function called from legacy lim to notify tdls peer deletion + * + * Return: None + */ +void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc, + uint32_t session_id); + +/** + * tgt_tdls_delete_all_peers_indication()- Indication to tdls component + * @psoc: soc object + * @session_id: session id + * + * This function called from legacy lim to tdls component to delete tdls peers. + * + * Return: None + */ +void tgt_tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc, + uint32_t session_id); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h new file mode 100644 index 0000000000..b031b7d497 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/inc/wlan_tdls_ucfg_api.h @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_ucfg_api.h + * + * TDLS north bound interface declaration + */ + +#if !defined(_WLAN_TDLS_UCFG_API_H_) +#define _WLAN_TDLS_UCFG_API_H_ + +#include +#include +#include +#include +#include +#include + +#ifdef FEATURE_WLAN_TDLS + +/** + * ucfg_tdls_init() - TDLS module initialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_init(void); + +/** + * ucfg_tdls_deinit() - TDLS module deinitialization API + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_deinit(void); + +/** + * ucfg_tdls_psoc_open() - TDLS module psoc open API + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_tdls_psoc_close() - TDLS module psoc close API + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_tdls_update_config() - TDLS module start + * @psoc: psoc object + * @req: tdls start paramets + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, + struct tdls_start_params *req); + +/** + * ucfg_tdls_update_fw_wideband_capability() - Update FW TDLS wideband + * capability in TDLS component + * + * @psoc: psoc object + * @is_fw_tdls_wideband_capable: if fw is tdls wideband capable then it is true + * + * Return: void + */ +void ucfg_tdls_update_fw_wideband_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_wideband_capable); + +/** + * ucfg_tdls_is_fw_wideband_capable() - Get FW TDLS wideband capability from + * TDLS component. + * @psoc: psoc object + * + * Return: true if fw supports tdls wideband + */ +bool ucfg_tdls_is_fw_wideband_capable(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_11AX +/** + * ucfg_tdls_update_fw_11ax_capability() - Update FW TDLS 11ax capability in + * TDLS Component + * @psoc: psoc object + * @is_fw_tdls_11ax_capable: bool if fw is tdls 11ax capable then it is true + * + * Return: void + */ +void ucfg_tdls_update_fw_11ax_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_11ax_capable); + +/** + * ucfg_update_fw_tdls_6g_capability() - Update FW TDLS 6g capability in TDLS + * Component + * @psoc: psoc object + * @is_fw_tdls_6g_capable: set to true if firmware supports TDLS on 6G band + * + * Return: void + */ +void ucfg_update_fw_tdls_6g_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_6g_capable); + +/** + * ucfg_tdls_is_fw_11ax_capable() - Get FW TDLS 11ax capability from TLDS + * component. + * @psoc: psoc object + * + * Return: true if fw supports tdls 11ax + */ +bool ucfg_tdls_is_fw_11ax_capable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_tdls_is_fw_6g_capable() - Get FW TDLS 6g capability from TLDS + * component. + * @psoc: psoc object + * + * Return: true if fw supports tdls on 6ghz band + */ +bool ucfg_tdls_is_fw_6g_capable(struct wlan_objmgr_psoc *psoc); + +#else +static inline +void ucfg_tdls_update_fw_11ax_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_11ax_capable) +{ +} + +static inline +bool ucfg_tdls_is_fw_11ax_capable(struct wlan_objmgr_psoc *psoc) +{ +return false; +} + +static inline +void ucfg_update_fw_tdls_6g_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_6g_capable) +{ +} + +static inline +bool ucfg_tdls_is_fw_6g_capable(struct wlan_objmgr_psoc *psoc) +{ +return false; +} +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * ucfg_tdls_update_fw_mlo_capability() - update fw mlo capability + * @psoc: psoc object + * @is_fw_tdls_mlo_capable: bool value + * + * Return: none + */ +void ucfg_tdls_update_fw_mlo_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_mlo_capable); +#else +static inline +void ucfg_tdls_update_fw_mlo_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_mlo_capable) +{ +} +#endif + +/** + * ucfg_tdls_link_vdev_is_matching() - check whether vdev is matching link vdev + * @vdev: vdev object + * + * Return: bool + */ +bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_tdls_get_tdls_link_vdev() - get tdls link vdev + * @vdev: vdev object + * @dbg_id: debug id + * + * Return: vdev pointer + */ +struct wlan_objmgr_vdev * +ucfg_tdls_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * ucfg_tdls_put_tdls_link_vdev() - put tdls link vdev + * @vdev: vdev odject + * @dbg_id: debug id + * + * Return: void + */ +void ucfg_tdls_put_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * ucfg_tdls_psoc_enable() - TDLS module enable API + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_tdls_psoc_disable() - TDLS module disable API + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_tdls_add_peer() - handle TDLS add peer + * @vdev: vdev object + * @add_peer_req: add peer request parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_add_peer(struct wlan_objmgr_vdev *vdev, + struct tdls_add_peer_params *add_peer_req); + +/** + * ucfg_tdls_update_peer() - handle TDLS update peer + * @vdev: vdev object + * @update_peer: update TDLS request parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev, + struct tdls_update_peer_params *update_peer); + +/** + * ucfg_tdls_oper() - handle TDLS oper functions + * @vdev: vdev object + * @macaddr: MAC address of TDLS peer + * @cmd: oper cmd + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_oper(struct wlan_objmgr_vdev *vdev, + const uint8_t *macaddr, enum tdls_command_type cmd); + +/** + * ucfg_tdls_get_all_peers() - get all tdls peers from the list + * @vdev: vdev object + * @buf: output buffer + * @buflen: length of written data + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen); + +/** + * ucfg_tdls_send_mgmt_frame() - send TDLS mgmt frame + * @mgmt_req: pointer to TDLS action frame request struct + * + * This will TDLS action frames to peer + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_send_mgmt_frame( + struct tdls_action_frame_request *mgmt_req); + +/** + * ucfg_tdls_responder() - set responder in TDLS peer + * @msg_req: responder msg + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_responder(struct tdls_set_responder_req *msg_req); + +/** + * ucfg_tdls_teardown_links() - notify TDLS modules to teardown all TDLS links. + * @psoc: psoc object + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_teardown_links(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_tdls_teardown_links_sync() - teardown all TDLS links. + * @psoc: psoc object + * @vdev: Vdev object pointer + * + * Return: None + */ +void ucfg_tdls_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_tdls_notify_reset_adapter() - notify reset adapter + * @vdev: vdev object manager + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_tdls_set_operating_mode() - set operating mode + * @set_mode_params: set mode params + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_set_operating_mode( + struct tdls_set_mode_params *set_mode_params); + +/** + * ucfg_tdls_update_rx_pkt_cnt() - update rx pkt count + * @vdev: tdls vdev object + * @mac_addr: peer mac address + * @dest_mac_addr: dest mac address + * + * Return: None + */ +void ucfg_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr); + +/** + * ucfg_tdls_update_tx_pkt_cnt() - update tx pkt count + * @vdev: tdls vdev object + * @mac_addr: peer mac address + * + * Return: None + */ +void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr); + +/** + * ucfg_tdls_antenna_switch() - tdls antenna switch + * @vdev: tdls vdev object + * @mode: antenna mode + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, + uint32_t mode); + +/** + * ucfg_set_tdls_offchannel() - Handle TDLS set offchannel + * @vdev: vdev object + * @offchannel: updated offchannel + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_set_tdls_offchannel(struct wlan_objmgr_vdev *vdev, + int offchannel); + +/** + * ucfg_set_tdls_offchan_mode() - Handle TDLS set offchannel mode + * @vdev: vdev object + * @offchanmode: updated off-channel mode + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_set_tdls_offchan_mode(struct wlan_objmgr_vdev *vdev, + int offchanmode); + +/** + * ucfg_set_tdls_secoffchanneloffset() - Handle TDLS set offchannel offset + * @vdev: vdev object + * @offchanoffset: tdls off-channel offset + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_set_tdls_secoffchanneloffset(struct wlan_objmgr_vdev *vdev, + int offchanoffset); + +/** + * ucfg_tdls_discovery_on_going() - check discovery is on going + * @vdev: vdev object + * + * Return: true if tdls discovery on going else false + */ +bool ucfg_tdls_discovery_on_going(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_tdls_get_mlo_vdev() - get mlo vdev for tdls + * @vdev: vdev object + * @index: index of vdev in mlo list + * @dbg_id: debug id + * + * Return: vdev pointer + */ +struct wlan_objmgr_vdev *ucfg_tdls_get_mlo_vdev(struct wlan_objmgr_vdev *vdev, + uint8_t index, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * ucfg_tdls_release_mlo_vdev() - release mlo vdev for tdls + * @vdev: vdev object + * @dbg_id: debug id + * + * Return: void + */ +void ucfg_tdls_release_mlo_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id); +/** + * ucfg_tdls_set_rssi() - API to set TDLS RSSI on peer given by mac + * @vdev: vdev object + * @mac: MAC address of Peer + * @rssi: rssi value + * + * Set RSSI on TDLS peer + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_tdls_set_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac, int8_t rssi); + +/** + * ucfg_tdls_notify_connect_failure() - This api is called if STA/P2P + * connection fails on one iface and to enable/disable TDLS on the other + * STA/P2P iface which is already connected.It is a wrapper function to + * API wlan_tdls_notify_connect_failure() + * @psoc: psoc object + * + * Return: void + */ +void ucfg_tdls_notify_connect_failure(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_get_tdls_conn_peer_count() - This api is called to get number of + * connected TDLS peer + * @vdev: vdev object + * + * Return: tdls connected peer count + */ +uint16_t ucfg_get_tdls_conn_peer_count(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_get_tdls_vdev() - Ucfg api to get tdls specific vdev object + * @psoc: wlan psoc object manager + * @dbg_id: debug id + * + * If TDLS is enabled on any vdev then return the corresponding vdev. + * + * This api increases the ref count of the returned vdev. + * Return: vdev manager pointer or NULL. + */ +struct wlan_objmgr_vdev *ucfg_get_tdls_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id); + +/** + * ucfg_tdls_check_is_tdls_allowed() - Ucfg api to check is tdls allowed or not + * @vdev: vdev object + * + * Function determines the whether TDLS allowed in the system + * + * Return: true or false + */ +bool ucfg_tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_tdls_set_user_tdls_enable() - ucfg api to set tdls is enable or not + * from userspace + * @vdev: vdev object + * @is_user_tdls_enable: true if tdls is enabled from userspace + * + * Return: void + */ +void ucfg_tdls_set_user_tdls_enable(struct wlan_objmgr_vdev *vdev, + bool is_user_tdls_enable); + +#else +static inline +bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +struct wlan_objmgr_vdev * +ucfg_tdls_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + return NULL; +} + +static inline +void ucfg_tdls_put_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ +} + +static inline +QDF_STATUS ucfg_tdls_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_tdls_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_tdls_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr) +{ +} + +static inline +void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ +} + +static inline +QDF_STATUS ucfg_tdls_teardown_links(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_tdls_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +QDF_STATUS ucfg_tdls_set_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac, int8_t rssi) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void ucfg_tdls_notify_connect_failure(struct wlan_objmgr_psoc *psoc) +{ +} + +static inline +struct wlan_objmgr_vdev *ucfg_get_tdls_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id) +{ + return NULL; +} + +static inline +bool ucfg_tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +void ucfg_tdls_set_user_tdls_enable(struct wlan_objmgr_vdev *vdev, + bool is_user_tdls_enable) +{ +} + +static inline +void ucfg_tdls_update_fw_11ax_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_11ax_capable) +{ +} + +static inline +bool ucfg_tdls_is_fw_11ax_capable(struct wlan_objmgr_psoc *psoc) +{ +return false; +} +#endif /* FEATURE_WLAN_TDLS */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_api.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_api.c new file mode 100644 index 0000000000..be72baddf8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_api.c @@ -0,0 +1,621 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains tdls link teardown definitions + */ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_tdls_api.h" +#include "../../core/src/wlan_tdls_main.h" +#include "../../core/src/wlan_tdls_ct.h" +#include "../../core/src/wlan_tdls_mgmt.h" +#include "wlan_tdls_peer.h" +#include +#include +#include "wlan_tdls_cfg_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_mlo_mgr_sta.h" + +void wlan_tdls_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct tdls_callbacks *cbs) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return; + } + + soc_obj->tdls_cb.delete_all_tdls_peers = cbs->delete_all_tdls_peers; +} + +static QDF_STATUS tdls_teardown_flush_cb(struct scheduler_msg *msg) +{ + struct tdls_link_teardown *tdls_teardown = msg->bodyptr; + struct wlan_objmgr_psoc *psoc = tdls_teardown->psoc; + + wlan_objmgr_psoc_release_ref(psoc, WLAN_TDLS_SB_ID); + qdf_mem_free(tdls_teardown); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_tdls_teardown_links(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0, }; + struct tdls_link_teardown *link_teardown; + + link_teardown = qdf_mem_malloc(sizeof(*link_teardown)); + if (!link_teardown) + return QDF_STATUS_E_NOMEM; + + wlan_objmgr_psoc_get_ref(psoc, WLAN_TDLS_SB_ID); + link_teardown->psoc = psoc; + msg.bodyptr = link_teardown; + msg.callback = tdls_process_cmd; + msg.flush_callback = tdls_teardown_flush_cb; + msg.type = TDLS_CMD_TEARDOWN_LINKS; + + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post msg fail, %d", status); + wlan_objmgr_psoc_release_ref(psoc, WLAN_TDLS_SB_ID); + qdf_mem_free(link_teardown); + } + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +bool wlan_tdls_is_fw_11be_mlo_capable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return false; + } + tdls_debug("FW 11BE capability %d", soc_obj->fw_tdls_mlo_capable); + + return soc_obj->fw_tdls_mlo_capable; +} +#endif + +static void wlan_tdls_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct tdls_vdev_priv_obj *vdev_priv_obj; + QDF_STATUS status; + struct wlan_objmgr_vdev *tdls_vdev; + + tdls_vdev = tdls_get_vdev(psoc, WLAN_TDLS_NB_ID); + if (!tdls_vdev) + return; + + vdev_priv_obj = wlan_vdev_get_tdls_vdev_obj(tdls_vdev); + if (!vdev_priv_obj) { + tdls_err("vdev priv is NULL"); + goto release_ref; + } + + qdf_event_reset(&vdev_priv_obj->tdls_teardown_comp); + + status = wlan_tdls_teardown_links(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("wlan_tdls_teardown_links failed err %d", status); + goto release_ref; + } + + tdls_debug("vdev:%d Wait for tdls teardown completion. Timeout %u ms", + wlan_vdev_get_id(tdls_vdev), + WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS); + + status = qdf_wait_for_event_completion( + &vdev_priv_obj->tdls_teardown_comp, + WAIT_TIME_FOR_TDLS_TEARDOWN_LINKS); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err(" Teardown Completion timed out %d", status); + goto release_ref; + } + + tdls_debug("TDLS teardown completion status %d ", status); + +release_ref: + wlan_objmgr_vdev_release_ref(tdls_vdev, + WLAN_TDLS_NB_ID); +} + +void wlan_tdls_check_and_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t sta_count; + enum QDF_OPMODE opmode; + bool tgt_tdls_concurrency_supported; + + tgt_tdls_concurrency_supported = + wlan_psoc_nif_fw_ext2_cap_get(psoc, + WLAN_TDLS_CONCURRENCIES_SUPPORT); + /* Don't initiate teardown in case of STA + P2P Client concurreny */ + sta_count = policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL); + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (tgt_tdls_concurrency_supported && opmode == QDF_P2P_CLIENT_MODE && + sta_count) { + tdls_debug("Don't teardown tdls for existing STA vdev"); + return; + } + + wlan_tdls_teardown_links_sync(psoc, vdev); +} + +#ifdef WLAN_FEATURE_TDLS_CONCURRENCIES +static void wlan_tdls_handle_sap_start(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_START_BSS; + msg.bodyptr = psoc; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post start bss msg fail"); + return; + } +} + +void wlan_tdls_notify_channel_switch_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *tdls_vdev; + struct tdls_vdev_priv_obj *tdls_vdev_priv; + struct tdls_soc_priv_obj *tdls_soc_priv; + QDF_STATUS status; + + tdls_vdev = tdls_get_vdev(psoc, WLAN_TDLS_NB_ID); + if (!tdls_vdev) + return; + + status = tdls_get_vdev_objects(tdls_vdev, &tdls_vdev_priv, + &tdls_soc_priv); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to get TDLS objects"); + goto exit; + } + + tdls_debug("CSA complete"); + /* + * Channel Switch can cause SCC -> MCC switch on + * STA vdev. Disable TDLS if CSA causes STA vdev to be in MCC with + * other vdev. + */ + if (!tdls_is_concurrency_allowed(psoc)) { + tdls_disable_offchan_and_teardown_links(tdls_vdev); + tdls_debug("Disable the tdls in FW after CSA"); + } else { + tdls_process_enable_for_vdev(tdls_vdev); + tdls_set_tdls_offchannelmode(tdls_vdev, ENABLE_CHANSWITCH); + } + +exit: + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); +} + +static QDF_STATUS +wlan_tdls_post_set_off_channel_mode(struct wlan_objmgr_psoc *psoc, + uint8_t off_chan_mode) +{ + struct wlan_objmgr_vdev *tdls_vdev; + struct tdls_vdev_priv_obj *tdls_vdev_priv; + struct tdls_soc_priv_obj *tdls_soc_priv; + struct tdls_set_offchanmode *req; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + tdls_vdev = tdls_get_vdev(psoc, WLAN_TDLS_NB_ID); + if (!tdls_vdev) + return QDF_STATUS_E_FAILURE; + + status = tdls_get_vdev_objects(tdls_vdev, &tdls_vdev_priv, + &tdls_soc_priv); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + tdls_err("Failed to get TDLS objects"); + return QDF_STATUS_E_FAILURE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + return QDF_STATUS_E_NOMEM; + } + + req->offchan_mode = off_chan_mode; + req->vdev = tdls_vdev; + req->callback = wlan_tdls_offchan_parms_callback; + + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_OFFCHANMODE; + msg.bodyptr = req; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post set offchanmode msg fail"); + wlan_objmgr_vdev_release_ref(tdls_vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(req); + } + + return QDF_STATUS_SUCCESS; +} + +void wlan_tdls_notify_channel_switch_start(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + tdls_debug("Send Channel Switch start to TDLS module"); + wlan_tdls_post_set_off_channel_mode(psoc, DISABLE_ACTIVE_CHANSWITCH); +} + +void wlan_tdls_handle_p2p_client_connect(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + if (!policy_mgr_get_connection_count(psoc)) + return; + + /* + * Disable TDLS off-channel when P2P CLI comes up as + * 3rd interface. It will be re-enabled based on the + * concurrency once P2P connection is complete + */ + wlan_tdls_post_set_off_channel_mode(psoc, DISABLE_ACTIVE_CHANSWITCH); +} +#else +static inline void +wlan_tdls_handle_sap_start(struct wlan_objmgr_psoc *psoc) +{} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +wlan_mlo_is_tdls_session_present(struct wlan_objmgr_vdev *vdev) +{ + uint8_t i; + struct wlan_mlo_dev_context *ml_dev = vdev->mlo_dev_ctx; + + if (!ml_dev) { + tdls_err("MLO dev ctx is null"); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < ml_dev->wlan_vdev_count; i++) { + vdev = ml_dev->wlan_vdev_list[i]; + if (tdls_get_connected_peer_count_from_vdev(vdev) > 0) { + tdls_debug("TDLS session is present"); + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_INVAL; +} +#else +static QDF_STATUS +wlan_mlo_is_tdls_session_present(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_INVAL; +} +#endif + +QDF_STATUS +wlan_is_tdls_session_present(struct wlan_objmgr_vdev *vdev) +{ + if (mlo_is_mld_sta(vdev)) + return wlan_mlo_is_tdls_session_present(vdev); + + if (tdls_get_connected_peer_count_from_vdev(vdev) > 0) { + tdls_debug("TDLS session is present"); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_INVAL; +} + +void wlan_tdls_notify_start_bss(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + if (tdls_is_concurrency_allowed(psoc)) { + wlan_tdls_handle_sap_start(psoc); + return; + } + + wlan_tdls_check_and_teardown_links_sync(psoc, vdev); +} + +void wlan_tdls_notify_start_bss_failure(struct wlan_objmgr_psoc *psoc) +{ + tdls_notify_decrement_session(psoc); +} + +static QDF_STATUS tdls_notify_flush_cb(struct scheduler_msg *msg) +{ + struct tdls_sta_notify_params *notify = msg->bodyptr; + struct wlan_objmgr_vdev *vdev = notify->vdev; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +tdls_notify_disconnect(struct tdls_sta_notify_params *notify_info) +{ + struct scheduler_msg msg = {0, }; + struct tdls_sta_notify_params *notify; + QDF_STATUS status; + + if (!notify_info || !notify_info->vdev) { + tdls_err("notify_info %pK", notify_info); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_debug("Enter "); + + notify = qdf_mem_malloc(sizeof(*notify)); + if (!notify) { + wlan_objmgr_vdev_release_ref(notify_info->vdev, WLAN_TDLS_NB_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + *notify = *notify_info; + + msg.bodyptr = notify; + msg.callback = tdls_process_cmd; + msg.type = TDLS_NOTIFY_STA_DISCONNECTION; + msg.flush_callback = tdls_notify_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + } + + tdls_debug("Exit "); + + return QDF_STATUS_SUCCESS; +} + +void wlan_tdls_notify_sta_disconnect(uint8_t vdev_id, + bool lfr_roam, bool user_disconnect, + struct wlan_objmgr_vdev *vdev) +{ + struct tdls_sta_notify_params notify_info = {0}; + QDF_STATUS status; + + if (!vdev) { + tdls_err("vdev is NULL"); + return; + } + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + return; + } + + notify_info.session_id = vdev_id; + notify_info.lfr_roam = lfr_roam; + notify_info.tdls_chan_swit_prohibited = false; + notify_info.tdls_prohibited = false; + notify_info.vdev = vdev; + notify_info.user_disconnect = user_disconnect; + tdls_notify_disconnect(¬ify_info); +} + +static QDF_STATUS +tdls_notify_connect(struct tdls_sta_notify_params *notify_info) +{ + struct scheduler_msg msg = {0, }; + struct tdls_sta_notify_params *notify; + QDF_STATUS status; + + if (!notify_info || !notify_info->vdev) { + tdls_err("notify_info %pK", notify_info); + return QDF_STATUS_E_NULL_VALUE; + } + tdls_debug("Enter "); + + notify = qdf_mem_malloc(sizeof(*notify)); + if (!notify) { + wlan_objmgr_vdev_release_ref(notify_info->vdev, + WLAN_TDLS_NB_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + *notify = *notify_info; + + msg.bodyptr = notify; + msg.callback = tdls_process_cmd; + msg.type = TDLS_NOTIFY_STA_CONNECTION; + msg.flush_callback = tdls_notify_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(notify); + } + + tdls_debug("Exit "); + return status; +} + +void +wlan_tdls_notify_sta_connect(uint8_t session_id, + bool tdls_chan_swit_prohibited, + bool tdls_prohibited, + struct wlan_objmgr_vdev *vdev) +{ + struct tdls_sta_notify_params notify_info = {0}; + QDF_STATUS status; + + if (!vdev) { + tdls_err("vdev is NULL"); + return; + } + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + return; + } + + notify_info.session_id = session_id; + notify_info.vdev = vdev; + notify_info.tdls_chan_swit_prohibited = tdls_chan_swit_prohibited; + notify_info.tdls_prohibited = tdls_prohibited; + tdls_notify_connect(¬ify_info); +} + +#ifdef FEATURE_SET +void wlan_tdls_get_features_info(struct wlan_objmgr_psoc *psoc, + struct wlan_tdls_features *tdls_feature_set) +{ + cfg_tdls_get_support_enable(psoc, &tdls_feature_set->enable_tdls); + if (tdls_feature_set->enable_tdls) { + cfg_tdls_get_off_channel_enable( + psoc, + &tdls_feature_set->enable_tdls_offchannel); + tdls_feature_set->max_tdls_peers = + cfg_tdls_get_max_peer_count(psoc); + tdls_feature_set->enable_tdls_capability_enhance = true; + } +} +#endif + +void wlan_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + tdls_update_tx_pkt_cnt(vdev, mac_addr); +} + +void wlan_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr) +{ + tdls_update_rx_pkt_cnt(vdev, mac_addr, dest_mac_addr); +} + +void wlan_tdls_increment_discovery_attempts(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t *peer_addr) +{ + struct tdls_soc_priv_obj *tdls_soc_obj; + struct tdls_vdev_priv_obj *tdls_vdev_obj; + struct tdls_peer *peer; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TDLS_NB_ID); + if (!vdev) + return; + + status = tdls_get_vdev_objects(vdev, &tdls_vdev_obj, &tdls_soc_obj); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to get TDLS objects"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + return; + } + + peer = tdls_get_peer(tdls_vdev_obj, peer_addr); + if (!peer) { + tdls_err("tdls_peer is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + return; + } + + peer->discovery_attempt++; + tdls_debug("vdev:%d peer: " QDF_MAC_ADDR_FMT " discovery attempts:%d ", vdev_id, + QDF_MAC_ADDR_REF(peer_addr), peer->discovery_attempt); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +} + +static +struct tdls_peer *wlan_tdls_find_peer(struct tdls_vdev_priv_obj *vdev_obj, + const uint8_t *macaddr) +{ + return tdls_find_peer(vdev_obj, macaddr); +} + +bool wlan_tdls_is_addba_request_allowed(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + struct tdls_vdev_priv_obj *vdev_obj; + struct tdls_peer *curr_peer; + + vdev_obj = wlan_vdev_get_tdls_vdev_obj(vdev); + if (!vdev_obj) { + tdls_err("vdev_obj: %pK is null", vdev_obj); + return false; + } + + curr_peer = wlan_tdls_find_peer(vdev_obj, mac_addr->bytes); + if (!curr_peer) { + tdls_err("tdls peer is null"); + return false; + } + + if (curr_peer->valid_entry && + curr_peer->link_status == TDLS_LINK_CONNECTED) + return true; + + return false; +} + +void wlan_tdls_delete_all_peers(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct tdls_soc_priv_obj *soc_obj; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return; + } + + if (soc_obj->tdls_cb.delete_all_tdls_peers) + soc_obj->tdls_cb.delete_all_tdls_peers(vdev); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_cfg.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_cfg.c new file mode 100644 index 0000000000..729f11f24c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_cfg.c @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains TDLS configures interface definitions + */ + +#include +#include "wlan_tdls_cfg_api.h" +#include "../../core/src/wlan_tdls_main.h" + +QDF_STATUS +cfg_tdls_get_support_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_support_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_support_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_support_enable = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_external_control(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_external_control; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_uapsd_mask(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = 0; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_uapsd_mask; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_buffer_sta_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_buffer_sta_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_buffer_sta_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_buffer_sta_enable = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_uapsd_inactivity_time(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = 0; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_uapsd_inactivity_time; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_rx_pkt_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = 0; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_rx_pkt_threshold; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_off_channel_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_off_chan_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_off_channel_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_off_chan_enable = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_off_channel_enable_orig(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_off_chan_enable_orig; + + return QDF_STATUS_SUCCESS; +} + +void cfg_tdls_store_off_channel_enable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return; + } + + soc_obj->tdls_configs.tdls_off_chan_enable_orig = + soc_obj->tdls_configs.tdls_off_chan_enable; +} + +void cfg_tdls_restore_off_channel_enable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return; + } + + soc_obj->tdls_configs.tdls_off_chan_enable = + soc_obj->tdls_configs.tdls_off_chan_enable_orig; + soc_obj->tdls_configs.tdls_off_chan_enable_orig = false; +} + +QDF_STATUS +cfg_tdls_get_wmm_mode_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_wmm_mode_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_vdev_nss_2g(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_vdev_nss_2g = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_vdev_nss_5g(struct wlan_objmgr_psoc *psoc, + uint8_t val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_vdev_nss_5g = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_sleep_sta_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_sleep_sta_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_sleep_sta_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_sleep_sta_enable = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_get_scan_enable(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + *val = false; + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + *val = soc_obj->tdls_configs.tdls_scan_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cfg_tdls_set_scan_enable(struct wlan_objmgr_psoc *psoc, + bool val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_scan_enable = val; + + return QDF_STATUS_SUCCESS; +} + +int cfg_tdls_get_link_id(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + return soc_obj->tdls_configs.tdls_link_id; +} + +QDF_STATUS +cfg_tdls_set_link_id(struct wlan_objmgr_psoc *psoc, int val) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return QDF_STATUS_E_INVAL; + } + + soc_obj->tdls_configs.tdls_link_id = val; + + return QDF_STATUS_SUCCESS; +} + +uint16_t +cfg_tdls_get_max_peer_count(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return 1; + } + + return soc_obj->max_num_tdls_sta; +} + +uint16_t +cfg_tdls_get_connected_peer_count(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_psoc_get_tdls_soc_obj(psoc); + if (!soc_obj) { + tdls_err("tdls soc null"); + return 0; + } + + return soc_obj->connected_peer_count; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_tgt_api.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_tgt_api.c new file mode 100644 index 0000000000..94b52dad0c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_tgt_api.c @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_tgt_api.c + * + * TDLS south bound interface definitions + */ + +#include "qdf_status.h" +#include +#include "../../core/src/wlan_tdls_main.h" +#include "../../core/src/wlan_tdls_cmds_process.h" +#include "../../core/src/wlan_tdls_mgmt.h" + +static inline struct wlan_lmac_if_tdls_tx_ops * +wlan_psoc_get_tdls_txops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.tx_ops->tdls_tx_ops; +} + +static inline struct wlan_lmac_if_tdls_rx_ops * +wlan_psoc_get_tdls_rxops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.rx_ops->tdls_rx_ops; +} + +QDF_STATUS tgt_tdls_set_fw_state(struct wlan_objmgr_psoc *psoc, + struct tdls_info *tdls_param) +{ + struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL; + + tdls_ops = wlan_psoc_get_tdls_txops(psoc); + if (tdls_ops && tdls_ops->update_fw_state) + return tdls_ops->update_fw_state(psoc, tdls_param); + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_tdls_set_peer_state(struct wlan_objmgr_psoc *psoc, + struct tdls_peer_update_state *peer_param) +{ + struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL; + + tdls_ops = wlan_psoc_get_tdls_txops(psoc); + if (tdls_ops && tdls_ops->update_peer_state) + return tdls_ops->update_peer_state(psoc, peer_param); + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_tdls_set_offchan_mode(struct wlan_objmgr_psoc *psoc, + struct tdls_channel_switch_params *param) +{ + struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL; + + tdls_ops = wlan_psoc_get_tdls_txops(psoc); + if (tdls_ops && tdls_ops->set_offchan_mode) + return tdls_ops->set_offchan_mode(psoc, param); + else + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_tdls_send_mgmt_tx_completion(struct scheduler_msg *pmsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pmsg || !pmsg->bodyptr) { + tdls_err("msg: 0x%pK", pmsg); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_send_mgmt_tx_completion(pmsg->bodyptr); + + return status; +} + +QDF_STATUS tgt_tdls_send_mgmt_rsp(struct scheduler_msg *pmsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pmsg || !pmsg->bodyptr) { + tdls_err("msg: 0x%pK", pmsg); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_process_send_mgmt_rsp(pmsg->bodyptr); + + return status; +} + +QDF_STATUS tgt_tdls_add_peer_rsp(struct scheduler_msg *pmsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pmsg || !pmsg->bodyptr) { + tdls_err("msg: 0x%pK", pmsg); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_process_add_peer_rsp(pmsg->bodyptr); + + return status; +} + +QDF_STATUS tgt_tdls_del_peer_rsp(struct scheduler_msg *pmsg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pmsg || !pmsg->bodyptr) { + tdls_err("msg: 0x%pK", pmsg); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + status = tdls_process_del_peer_rsp(pmsg->bodyptr); + + return status; +} + +QDF_STATUS tgt_tdls_register_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL; + + tdls_ops = wlan_psoc_get_tdls_txops(psoc); + if (tdls_ops && tdls_ops->tdls_reg_ev_handler) + return tdls_ops->tdls_reg_ev_handler(psoc, NULL); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS tgt_tdls_unregister_ev_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_tdls_tx_ops *tdls_ops = NULL; + + tdls_ops = wlan_psoc_get_tdls_txops(psoc); + if (tdls_ops->tdls_unreg_ev_handler) + return tdls_ops->tdls_unreg_ev_handler(psoc, NULL); + else + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tgt_tdls_event_flush_cb(struct scheduler_msg *msg) +{ + struct tdls_event_notify *notify; + + notify = msg->bodyptr; + if (notify && notify->vdev) { + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_SB_ID); + qdf_mem_free(notify); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +tgt_tdls_event_handler(struct wlan_objmgr_psoc *psoc, + struct tdls_event_info *info) +{ + struct scheduler_msg msg = {0,}; + struct tdls_event_notify *notify; + uint8_t vdev_id; + QDF_STATUS status; + + if (!psoc || !info) { + tdls_err("psoc: 0x%pK, info: 0x%pK", psoc, info); + return QDF_STATUS_E_NULL_VALUE; + } + tdls_debug("vdev: %d, type: %d, reason: %d" QDF_MAC_ADDR_FMT, + info->vdev_id, info->message_type, info->peer_reason, + QDF_MAC_ADDR_REF(info->peermac.bytes)); + notify = qdf_mem_malloc(sizeof(*notify)); + if (!notify) + return QDF_STATUS_E_NOMEM; + + vdev_id = info->vdev_id; + notify->vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, WLAN_TDLS_SB_ID); + if (!notify->vdev) { + tdls_err("null vdev, vdev_id: %d, psoc: 0x%pK", vdev_id, psoc); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(¬ify->event, info, sizeof(*info)); + + msg.bodyptr = notify; + msg.callback = tdls_process_evt; + msg.flush_callback = tgt_tdls_event_flush_cb; + + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't post msg to handle tdls event"); + wlan_objmgr_vdev_release_ref(notify->vdev, WLAN_TDLS_SB_ID); + qdf_mem_free(notify); + } + + return status; +} + +static QDF_STATUS tgt_tdls_mgmt_frame_rx_flush_cb(struct scheduler_msg *msg) +{ + struct tdls_rx_mgmt_event *rx_mgmt_event; + + rx_mgmt_event = msg->bodyptr; + + if (rx_mgmt_event) { + if (rx_mgmt_event->rx_mgmt) + qdf_mem_free(rx_mgmt_event->rx_mgmt); + + qdf_mem_free(rx_mgmt_event); + } + msg->bodyptr = NULL; + + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS tgt_tdls_mgmt_frame_process_rx_cb( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type) +{ + struct tdls_rx_mgmt_frame *rx_mgmt; + struct tdls_rx_mgmt_event *rx_mgmt_event; + struct tdls_soc_priv_obj *tdls_soc_obj; + struct scheduler_msg msg = {0}; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + uint8_t *pdata; + QDF_STATUS status; + + tdls_soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!tdls_soc_obj) { + tdls_err("tdls ctx is NULL, drop this frame"); + return QDF_STATUS_E_FAILURE; + } + + if (!peer) { + vdev = tdls_get_vdev(psoc, WLAN_TDLS_SB_ID); + if (!vdev) { + tdls_err("current tdls vdev is null, can't get vdev id"); + return QDF_STATUS_E_FAILURE; + } + vdev_id = wlan_vdev_get_id(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_SB_ID); + } else { + vdev = wlan_peer_get_vdev(peer); + if (!vdev) { + tdls_err("vdev is NULL in peer, drop this frame"); + return QDF_STATUS_E_FAILURE; + } + vdev_id = wlan_vdev_get_id(vdev); + } + + rx_mgmt_event = qdf_mem_malloc_atomic(sizeof(*rx_mgmt_event)); + if (!rx_mgmt_event) + return QDF_STATUS_E_NOMEM; + + rx_mgmt = qdf_mem_malloc_atomic(sizeof(*rx_mgmt) + + mgmt_rx_params->buf_len); + if (!rx_mgmt) { + tdls_debug_rl("Failed to allocate rx mgmt frame"); + qdf_mem_free(rx_mgmt_event); + return QDF_STATUS_E_NOMEM; + } + + pdata = (uint8_t *)qdf_nbuf_data(buf); + rx_mgmt->frame_len = mgmt_rx_params->buf_len; + rx_mgmt->rx_freq = mgmt_rx_params->chan_freq; + rx_mgmt->vdev_id = vdev_id; + rx_mgmt->frm_type = frm_type; + rx_mgmt->rx_rssi = mgmt_rx_params->rssi; + + rx_mgmt_event->rx_mgmt = rx_mgmt; + rx_mgmt_event->tdls_soc_obj = tdls_soc_obj; + qdf_mem_copy(rx_mgmt->buf, pdata, mgmt_rx_params->buf_len); + msg.type = TDLS_EVENT_RX_MGMT; + msg.bodyptr = rx_mgmt_event; + msg.callback = tdls_process_rx_frame; + msg.flush_callback = tgt_tdls_mgmt_frame_rx_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(rx_mgmt); + qdf_mem_free(rx_mgmt_event); + } + + qdf_nbuf_free(buf); + + return status; +} + +QDF_STATUS tgt_tdls_mgmt_frame_rx_cb( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type) +{ + QDF_STATUS status; + + tdls_debug("psoc:%pK, peer:%pK, type:%d", psoc, peer, frm_type); + + + if (!buf) { + tdls_err("rx frame buff is null buf:%pK", buf); + return QDF_STATUS_E_INVAL; + } + + if (!mgmt_rx_params || !psoc) { + tdls_err("input is NULL mgmt_rx_params:%pK psoc:%pK, peer:%pK", + mgmt_rx_params, psoc, peer); + status = QDF_STATUS_E_INVAL; + goto release_nbuf; + } + + status = wlan_objmgr_peer_try_get_ref(peer, WLAN_TDLS_SB_ID); + if (QDF_STATUS_SUCCESS != status) + goto release_nbuf; + + status = tgt_tdls_mgmt_frame_process_rx_cb(psoc, peer, buf, + mgmt_rx_params, frm_type); + + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_SB_ID); + + if (QDF_STATUS_SUCCESS != status) +release_nbuf: + qdf_nbuf_free(buf); + return status; +} + +void tgt_tdls_peers_deleted_notification(struct wlan_objmgr_psoc *psoc, + uint32_t session_id) +{ + tdls_peers_deleted_notification(psoc, session_id); +} + +void tgt_tdls_delete_all_peers_indication(struct wlan_objmgr_psoc *psoc, + uint32_t session_id) +{ + tdls_check_and_indicate_delete_all_peers(psoc, session_id); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c new file mode 100644 index 0000000000..4194c77b37 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c @@ -0,0 +1,1302 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_ucfg_api.c + * + * TDLS north bound interface definitions + */ + +#include +#include +#include "../../core/src/wlan_tdls_main.h" +#include "../../core/src/wlan_tdls_cmds_process.h" +#include "../../core/src/wlan_tdls_ct.h" +#include "../../core/src/wlan_tdls_mgmt.h" +#include +#include +#include "wlan_policy_mgr_api.h" +#include "wlan_scan_ucfg_api.h" +#include "cfg_tdls.h" +#include "wlan_mlo_mgr_sta.h" +#include "cfg_ucfg_api.h" +#include "wlan_tdls_api.h" + +QDF_STATUS ucfg_tdls_init(void) +{ + QDF_STATUS status; + + tdls_notice("tdls module dispatcher init"); + status = wlan_objmgr_register_psoc_create_handler(WLAN_UMAC_COMP_TDLS, + tdls_psoc_obj_create_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to register psoc create handler for tdls"); + return status; + } + + status = wlan_objmgr_register_psoc_destroy_handler(WLAN_UMAC_COMP_TDLS, + tdls_psoc_obj_destroy_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to register psoc delete handler for tdls"); + goto fail_delete_psoc; + } + + status = wlan_objmgr_register_vdev_create_handler(WLAN_UMAC_COMP_TDLS, + tdls_vdev_obj_create_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to register vdev create handler for tdls"); + goto fail_create_vdev; + } + + status = wlan_objmgr_register_vdev_destroy_handler(WLAN_UMAC_COMP_TDLS, + tdls_vdev_obj_destroy_notification, NULL); + + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Failed to register vdev create handler for tdls"); + goto fail_delete_vdev; + } + tdls_notice("tdls module dispatcher init done"); + + return status; +fail_delete_vdev: + wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_TDLS, + tdls_vdev_obj_create_notification, NULL); + +fail_create_vdev: + wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_TDLS, + tdls_psoc_obj_destroy_notification, NULL); + +fail_delete_psoc: + wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_TDLS, + tdls_psoc_obj_create_notification, NULL); + + return status; +} + +QDF_STATUS ucfg_tdls_deinit(void) +{ + QDF_STATUS ret; + + tdls_notice("tdls module dispatcher deinit"); + ret = wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_TDLS, + tdls_psoc_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(ret)) + tdls_err("Failed to unregister psoc create handler"); + + ret = wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_TDLS, + tdls_psoc_obj_destroy_notification, NULL); + if (QDF_IS_STATUS_ERROR(ret)) + tdls_err("Failed to unregister psoc delete handler"); + + ret = wlan_objmgr_unregister_vdev_create_handler(WLAN_UMAC_COMP_TDLS, + tdls_vdev_obj_create_notification, NULL); + if (QDF_IS_STATUS_ERROR(ret)) + tdls_err("Failed to unregister vdev create handler"); + + ret = wlan_objmgr_unregister_vdev_destroy_handler(WLAN_UMAC_COMP_TDLS, + tdls_vdev_obj_destroy_notification, NULL); + + if (QDF_IS_STATUS_ERROR(ret)) + tdls_err("Failed to unregister vdev delete handler"); + + return ret; +} + +/** + * tdls_update_feature_flag() - update tdls feature flag + * @tdls_soc_obj: pointer to tdls psoc object + * + * This function updates tdls feature flag + */ +static void +tdls_update_feature_flag(struct tdls_soc_priv_obj *tdls_soc_obj) +{ + tdls_soc_obj->tdls_configs.tdls_feature_flags = + ((tdls_soc_obj->tdls_configs.tdls_off_chan_enable ? + 1 << TDLS_FEATURE_OFF_CHANNEL : 0) | + (tdls_soc_obj->tdls_configs.tdls_wmm_mode_enable ? + 1 << TDLS_FEATURE_WMM : 0) | + (tdls_soc_obj->tdls_configs.tdls_buffer_sta_enable ? + 1 << TDLS_FEATURE_BUFFER_STA : 0) | + (tdls_soc_obj->tdls_configs.tdls_sleep_sta_enable ? + 1 << TDLS_FEATURE_SLEEP_STA : 0) | + (tdls_soc_obj->tdls_configs.tdls_scan_enable ? + 1 << TDLS_FEATURE_SCAN : 0) | + (tdls_soc_obj->tdls_configs.tdls_support_enable ? + 1 << TDLS_FEATURE_ENABLE : 0) | + (tdls_soc_obj->tdls_configs.tdls_implicit_trigger_enable ? + 1 << TDLS_FEAUTRE_IMPLICIT_TRIGGER : 0) | + (tdls_soc_obj->tdls_configs.tdls_external_control & + TDLS_STRICT_EXTERNAL_CONTROL ? + 1 << TDLS_FEATURE_EXTERNAL_CONTROL : 0) | + (tdls_soc_obj->tdls_configs.tdls_external_control & + TDLS_LIBERAL_EXTERNAL_CONTROL ? + 1 << TDLS_FEATURE_LIBERAL_EXTERNAL_CONTROL : 0)); +} + +/** + * tdls_object_init_params() - init parameters for tdls object + * @tdls_soc_obj: pointer to tdls psoc object + * + * This function init parameters for tdls object + */ +static QDF_STATUS tdls_object_init_params( + struct tdls_soc_priv_obj *tdls_soc_obj) +{ + struct wlan_objmgr_psoc *psoc; + + if (!tdls_soc_obj) { + tdls_err("invalid param"); + return QDF_STATUS_E_INVAL; + } + + psoc = tdls_soc_obj->soc; + if (!psoc) { + tdls_err("invalid psoc object"); + return QDF_STATUS_E_INVAL; + } + + tdls_soc_obj->tdls_configs.tdls_tx_states_period = + cfg_get(psoc, CFG_TDLS_TX_STATS_PERIOD); + tdls_soc_obj->tdls_configs.tdls_tx_pkt_threshold = + cfg_get(psoc, CFG_TDLS_TX_PACKET_THRESHOLD); + tdls_soc_obj->tdls_configs.tdls_rx_pkt_threshold = + cfg_get(psoc, CFG_TDLS_RX_FRAME_THRESHOLD); + tdls_soc_obj->tdls_configs.tdls_max_discovery_attempt = + cfg_get(psoc, CFG_TDLS_MAX_DISCOVERY_ATTEMPT); + tdls_soc_obj->tdls_configs.tdls_idle_timeout = + cfg_get(psoc, CFG_TDLS_IDLE_TIMEOUT); + tdls_soc_obj->tdls_configs.tdls_idle_pkt_threshold = + cfg_get(psoc, CFG_TDLS_IDLE_PACKET_THRESHOLD); + tdls_soc_obj->tdls_configs.tdls_rssi_trigger_threshold = + cfg_get(psoc, CFG_TDLS_RSSI_TRIGGER_THRESHOLD); + tdls_soc_obj->tdls_configs.tdls_rssi_teardown_threshold = + cfg_get(psoc, CFG_TDLS_RSSI_TEARDOWN_THRESHOLD); + tdls_soc_obj->tdls_configs.tdls_rssi_delta = + cfg_get(psoc, CFG_TDLS_RSSI_DELTA); + tdls_soc_obj->tdls_configs.tdls_uapsd_mask = + cfg_get(psoc, CFG_TDLS_QOS_WMM_UAPSD_MASK); + tdls_soc_obj->tdls_configs.tdls_uapsd_inactivity_time = + cfg_get(psoc, CFG_TDLS_PUAPSD_INACT_TIME); + tdls_soc_obj->tdls_configs.tdls_uapsd_pti_window = + cfg_get(psoc, CFG_TDLS_PUAPSD_PEER_TRAFFIC_IND_WINDOW); + tdls_soc_obj->tdls_configs.tdls_uapsd_ptr_timeout = + cfg_get(psoc, CFG_TDLS_PUAPSD_PEER_TRAFFIC_RSP_TIMEOUT); + tdls_soc_obj->tdls_configs.tdls_pre_off_chan_num = + cfg_get(psoc, CFG_TDLS_PREFERRED_OFF_CHANNEL_NUM); + tdls_soc_obj->tdls_configs.tdls_pre_off_chan_freq_6g = + cfg_get(psoc, CFG_TDLS_PREFERRED_OFF_CHANNEL_FREQ_6G); + tdls_soc_obj->tdls_configs.tdls_pre_off_chan_bw = + cfg_get(psoc, CFG_TDLS_PREFERRED_OFF_CHANNEL_BW); + tdls_soc_obj->tdls_configs.tdls_peer_kickout_threshold = + cfg_get(psoc, CFG_TDLS_PEER_KICKOUT_THRESHOLD); + tdls_soc_obj->tdls_configs.tdls_discovery_wake_timeout = + cfg_get(psoc, CFG_TDLS_DISCOVERY_WAKE_TIMEOUT); + tdls_soc_obj->tdls_configs.delayed_trig_framint = + cfg_get(psoc, CFG_TL_DELAYED_TRGR_FRM_INTERVAL); + tdls_soc_obj->tdls_configs.tdls_wmm_mode_enable = + cfg_get(psoc, CFG_TDLS_WMM_MODE_ENABLE); + tdls_soc_obj->tdls_configs.tdls_off_chan_enable = + cfg_get(psoc, CFG_TDLS_OFF_CHANNEL_ENABLED); + tdls_soc_obj->tdls_configs.tdls_buffer_sta_enable = + cfg_get(psoc, CFG_TDLS_BUF_STA_ENABLED); + tdls_soc_obj->tdls_configs.tdls_scan_enable = + cfg_get(psoc, CFG_TDLS_SCAN_ENABLE); + tdls_soc_obj->tdls_configs.tdls_support_enable = + cfg_get(psoc, CFG_TDLS_SUPPORT_ENABLE); + tdls_soc_obj->tdls_configs.tdls_implicit_trigger_enable = + cfg_get(psoc, CFG_TDLS_IMPLICIT_TRIGGER); + tdls_soc_obj->tdls_configs.tdls_external_control = + cfg_get(psoc, CFG_TDLS_EXTERNAL_CONTROL); + tdls_soc_obj->max_num_tdls_sta = + cfg_get(psoc, CFG_TDLS_MAX_PEER_COUNT); + + tdls_update_feature_flag(tdls_soc_obj); + + return QDF_STATUS_SUCCESS; +} + +#ifdef TDLS_WOW_ENABLED +/** + * tdls_wow_init() - Create/init wake lock for TDLS + * @soc_obj: TDLS private soc object + * + * Create/init wake lock for TDLS if DVR isn't supported + * + * Return None + */ +static void tdls_wow_init(struct tdls_soc_priv_obj *soc_obj) +{ + soc_obj->is_prevent_suspend = false; + soc_obj->is_drv_supported = qdf_is_drv_supported(); + if (!soc_obj->is_drv_supported) { + qdf_wake_lock_create(&soc_obj->wake_lock, "wlan_tdls"); + qdf_runtime_lock_init(&soc_obj->runtime_lock); + } +} + +/** + * tdls_wow_deinit() - Destroy/deinit wake lock for TDLS + * @soc_obj: TDLS private soc object + * + * Destroy/deinit wake lock for TDLS if DVR isn't supported + * + * Return None + */ +static void tdls_wow_deinit(struct tdls_soc_priv_obj *soc_obj) +{ + if (!soc_obj->is_drv_supported) { + qdf_runtime_lock_deinit(&soc_obj->runtime_lock); + qdf_wake_lock_destroy(&soc_obj->wake_lock); + } +} +#else +static void tdls_wow_init(struct tdls_soc_priv_obj *soc_obj) +{ +} + +static void tdls_wow_deinit(struct tdls_soc_priv_obj *soc_obj) +{ +} +#endif + +static QDF_STATUS tdls_global_init(struct tdls_soc_priv_obj *soc_obj) +{ + tdls_object_init_params(soc_obj); + soc_obj->connected_peer_count = 0; + soc_obj->tdls_nss_switch_in_progress = false; + soc_obj->tdls_teardown_peers_cnt = 0; + soc_obj->tdls_nss_teardown_complete = false; + soc_obj->tdls_nss_transition_mode = TDLS_NSS_TRANSITION_S_UNKNOWN; + soc_obj->enable_tdls_connection_tracker = false; + soc_obj->tdls_external_peer_count = 0; + soc_obj->is_user_tdls_enable = true; + + qdf_spinlock_create(&soc_obj->tdls_ct_spinlock); + tdls_wow_init(soc_obj); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tdls_global_deinit(struct tdls_soc_priv_obj *soc_obj) +{ + tdls_wow_deinit(soc_obj); + qdf_spinlock_destroy(&soc_obj->tdls_ct_spinlock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_tdls_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *soc_obj; + + tdls_debug("tdls psoc open"); + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return QDF_STATUS_E_FAILURE; + } + + status = tdls_global_init(soc_obj); + + return status; +} + +void ucfg_tdls_update_fw_wideband_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_wideband_capable) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return; + } + + soc_obj->fw_tdls_wideband_capability = is_fw_tdls_wideband_capable; +} + +bool ucfg_tdls_is_fw_wideband_capable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return false; + } + + tdls_debug("FW wideband capability %d", + soc_obj->fw_tdls_wideband_capability); + + return soc_obj->fw_tdls_wideband_capability; +} + +#ifdef WLAN_FEATURE_11BE +void ucfg_tdls_update_fw_mlo_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_mlo_capable) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return; + } + + soc_obj->fw_tdls_mlo_capable = is_fw_tdls_mlo_capable; +} +#endif + +#ifdef WLAN_FEATURE_11AX +void ucfg_tdls_update_fw_11ax_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_11ax_capable) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return; + } + + soc_obj->fw_tdls_11ax_capability = is_fw_tdls_11ax_capable; +} + +void ucfg_update_fw_tdls_6g_capability(struct wlan_objmgr_psoc *psoc, + bool is_fw_tdls_6g_capable) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return; + } + + soc_obj->fw_tdls_6g_capability = is_fw_tdls_6g_capable; +} + +bool ucfg_tdls_is_fw_11ax_capable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return false; + } + tdls_debug("FW 11AX capability %d", soc_obj->fw_tdls_11ax_capability); + + return soc_obj->fw_tdls_11ax_capability; +} + +bool ucfg_tdls_is_fw_6g_capable(struct wlan_objmgr_psoc *psoc) +{ + struct tdls_soc_priv_obj *soc_obj; + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return false; + } + tdls_debug("FW 6g capability %d", soc_obj->fw_tdls_6g_capability); + + return soc_obj->fw_tdls_6g_capability; +} +#endif + +QDF_STATUS ucfg_tdls_update_config(struct wlan_objmgr_psoc *psoc, + struct tdls_start_params *req) +{ + struct tdls_soc_priv_obj *soc_obj; + uint32_t tdls_feature_flags; + struct policy_mgr_tdls_cbacks tdls_pm_call_backs; + uint8_t sta_idx; + + tdls_debug("tdls update config "); + if (!psoc || !req) { + tdls_err("psoc: 0x%pK, req: 0x%pK", psoc, req); + return QDF_STATUS_E_FAILURE; + } + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return QDF_STATUS_E_FAILURE; + } + + soc_obj->tdls_rx_cb = req->tdls_rx_cb; + soc_obj->tdls_rx_cb_data = req->tdls_rx_cb_data; + + soc_obj->tdls_wmm_cb = req->tdls_wmm_cb; + soc_obj->tdls_wmm_cb_data = req->tdls_wmm_cb_data; + + soc_obj->tdls_event_cb = req->tdls_event_cb; + soc_obj->tdls_evt_cb_data = req->tdls_evt_cb_data; + + /* Save callbacks to register/deregister TDLS sta with datapath */ + soc_obj->tdls_reg_peer = req->tdls_reg_peer; + soc_obj->tdls_peer_context = req->tdls_peer_context; + + /* Save legacy PE/WMA commands in TDLS soc object */ + soc_obj->tdls_send_mgmt_req = req->tdls_send_mgmt_req; + soc_obj->tdls_add_sta_req = req->tdls_add_sta_req; + soc_obj->tdls_del_sta_req = req->tdls_del_sta_req; + soc_obj->tdls_update_peer_state = req->tdls_update_peer_state; + soc_obj->tdls_del_all_peers = req->tdls_del_all_peers; + soc_obj->tdls_update_dp_vdev_flags = req->tdls_update_dp_vdev_flags; + soc_obj->tdls_dp_vdev_update = req->tdls_dp_vdev_update; + soc_obj->tdls_osif_init_cb = req->tdls_osif_init_cb; + soc_obj->tdls_osif_deinit_cb = req->tdls_osif_deinit_cb; + soc_obj->tdls_osif_update_cb.tdls_osif_conn_update = + req->tdls_osif_update_cb.tdls_osif_conn_update; + soc_obj->tdls_osif_update_cb.tdls_osif_disconn_update = + req->tdls_osif_update_cb.tdls_osif_disconn_update; + tdls_pm_call_backs.tdls_notify_increment_session = + tdls_notify_increment_session; + + tdls_pm_call_backs.tdls_notify_decrement_session = + tdls_notify_decrement_session; + if (QDF_STATUS_SUCCESS != policy_mgr_register_tdls_cb( + psoc, &tdls_pm_call_backs)) { + tdls_err("policy manager callback registration failed "); + return QDF_STATUS_E_FAILURE; + } + + tdls_update_feature_flag(soc_obj); + tdls_feature_flags = soc_obj->tdls_configs.tdls_feature_flags; + + if (!TDLS_IS_IMPLICIT_TRIG_ENABLED(tdls_feature_flags)) + soc_obj->tdls_current_mode = TDLS_SUPPORT_EXP_TRIG_ONLY; + else if (TDLS_IS_EXTERNAL_CONTROL_ENABLED(tdls_feature_flags)) + soc_obj->tdls_current_mode = TDLS_SUPPORT_EXT_CONTROL; + else + soc_obj->tdls_current_mode = TDLS_SUPPORT_IMP_MODE; + + soc_obj->tdls_last_mode = soc_obj->tdls_current_mode; + if (TDLS_IS_BUFFER_STA_ENABLED(tdls_feature_flags) || + TDLS_IS_SLEEP_STA_ENABLED(tdls_feature_flags)) + soc_obj->max_num_tdls_sta = + WLAN_TDLS_STA_P_UAPSD_OFFCHAN_MAX_NUM; + + for (sta_idx = 0; sta_idx < soc_obj->max_num_tdls_sta; sta_idx++) { + soc_obj->tdls_conn_info[sta_idx].valid_entry = false; + soc_obj->tdls_conn_info[sta_idx].index = + INVALID_TDLS_PEER_INDEX; + soc_obj->tdls_conn_info[sta_idx].session_id = 255; + qdf_mem_zero(&soc_obj->tdls_conn_info[sta_idx].peer_mac, + QDF_MAC_ADDR_SIZE); + } + return QDF_STATUS_SUCCESS; +} + +bool ucfg_tdls_link_vdev_is_matching(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_vdev *tdls_link_vdev; + + tdls_link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (!tdls_link_vdev) { + wlan_vdev_mlme_feat_ext2_cap_set(vdev, + WLAN_VDEV_FEXT2_MLO_STA_TDLS); + tdls_set_remain_links_unforce(vdev); + return true; + } + + if (tdls_link_vdev && tdls_link_vdev != vdev) { + tdls_debug("tdls vdev has been created on vdev %d", + wlan_vdev_get_id(tdls_link_vdev)); + return false; + } + + return true; +} + +struct wlan_objmgr_vdev * +ucfg_tdls_get_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + struct wlan_objmgr_vdev *link_vdev; + + link_vdev = tdls_mlo_get_tdls_link_vdev(vdev); + if (!link_vdev) + return NULL; + + if (wlan_objmgr_vdev_try_get_ref(link_vdev, dbg_id) != + QDF_STATUS_SUCCESS) + return NULL; + + return link_vdev; +} + +void ucfg_tdls_put_tdls_link_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + wlan_objmgr_vdev_release_ref(vdev, dbg_id); +} + +QDF_STATUS ucfg_tdls_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + tdls_debug("psoc tdls enable: 0x%pK", psoc); + if (!psoc) { + tdls_err("NULL psoc"); + return QDF_STATUS_E_FAILURE; + } + + status = tgt_tdls_register_ev_handler(psoc); + + if (status != QDF_STATUS_SUCCESS) + return status; + + status = wlan_serialization_register_comp_info_cb(psoc, + WLAN_UMAC_COMP_TDLS, + WLAN_SER_CMD_SCAN, + tdls_scan_serialization_comp_info_cb); + if (QDF_STATUS_SUCCESS != status) { + tdls_err("Serialize scan cmd register failed "); + return status; + } + + /* register callbacks with tx/rx mgmt */ + status = tdls_mgmt_rx_ops(psoc, true); + if (status != QDF_STATUS_SUCCESS) + tdls_err("Failed to register mgmt rx callback, status:%d", + status); + return status; +} + +QDF_STATUS ucfg_tdls_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct tdls_soc_priv_obj *soc_obj = NULL; + + tdls_debug("psoc tdls disable: 0x%pK", psoc); + if (!psoc) { + tdls_err("NULL psoc"); + return QDF_STATUS_E_FAILURE; + } + + status = tgt_tdls_unregister_ev_handler(psoc); + if (QDF_IS_STATUS_ERROR(status)) + tdls_err("Failed to unregister tdls event handler"); + + status = tdls_mgmt_rx_ops(psoc, false); + if (QDF_IS_STATUS_ERROR(status)) + tdls_err("Failed to unregister mgmt rx callback"); + + soc_obj = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!soc_obj) { + tdls_err("Failed to get tdls psoc component"); + return QDF_STATUS_E_FAILURE; + } + + soc_obj->tdls_event_cb = NULL; + soc_obj->tdls_evt_cb_data = NULL; + + return status; +} + +QDF_STATUS ucfg_tdls_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct tdls_soc_priv_obj *tdls_soc; + + tdls_debug("tdls psoc close"); + tdls_soc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TDLS); + if (!tdls_soc) { + tdls_err("Failed to get tdls psoc component"); + return QDF_STATUS_E_FAILURE; + } + + status = tdls_global_deinit(tdls_soc); + + return status; +} + +static QDF_STATUS ucfg_tdls_post_msg_flush_cb(struct scheduler_msg *msg) +{ + void *ptr = msg->bodyptr; + struct wlan_objmgr_vdev *vdev = NULL; + + switch (msg->type) { + case TDLS_NOTIFY_RESET_ADAPTERS: + ptr = NULL; + break; + case TDLS_CMD_SET_TDLS_MODE: + vdev = ((struct tdls_set_mode_params *)ptr)->vdev; + break; + case TDLS_CMD_TX_ACTION: + case TDLS_CMD_SET_RESPONDER: + break; + case TDLS_CMD_ADD_STA: + vdev = ((struct tdls_add_peer_request *)ptr)->vdev; + break; + case TDLS_CMD_CHANGE_STA: + vdev = ((struct tdls_update_peer_request *)ptr)->vdev; + break; + case TDLS_CMD_ENABLE_LINK: + case TDLS_CMD_DISABLE_LINK: + case TDLS_CMD_REMOVE_FORCE_PEER: + case TDLS_CMD_CONFIG_FORCE_PEER: + vdev = ((struct tdls_oper_request *)ptr)->vdev; + break; + case TDLS_CMD_SET_OFFCHANNEL: + vdev = ((struct tdls_set_offchannel *)ptr)->vdev; + break; + case TDLS_CMD_SET_OFFCHANMODE: + vdev = ((struct tdls_set_offchanmode *)ptr)->vdev; + break; + case TDLS_CMD_SET_SECOFFCHANOFFSET: + vdev = ((struct tdls_set_secoffchanneloffset *)ptr)->vdev; + break; + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + + if (ptr) + qdf_mem_free(ptr); + + msg->bodyptr = NULL; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_tdls_add_peer(struct wlan_objmgr_vdev *vdev, + struct tdls_add_peer_params *add_peer_req) +{ + struct scheduler_msg msg = {0, }; + struct tdls_add_peer_request *req; + QDF_STATUS status; + + if (!vdev || !add_peer_req) { + tdls_err("vdev: %pK, req %pK", vdev, add_peer_req); + return QDF_STATUS_E_NULL_VALUE; + } + tdls_debug("vdevid: %d, peertype: %d", + add_peer_req->vdev_id, add_peer_req->peer_type); + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + return status; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto dec_ref; + } + + qdf_mem_copy(&req->add_peer_req, add_peer_req, sizeof(*add_peer_req)); + req->vdev = vdev; + + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_ADD_STA; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post add peer msg fail"); + qdf_mem_free(req); + goto dec_ref; + } + + return status; +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + return status; +} + +QDF_STATUS ucfg_tdls_update_peer(struct wlan_objmgr_vdev *vdev, + struct tdls_update_peer_params *update_peer) +{ + struct scheduler_msg msg = {0,}; + struct tdls_update_peer_request *req; + QDF_STATUS status; + + if (!vdev || !update_peer) { + tdls_err("vdev: %pK, update_peer: %pK", vdev, update_peer); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_debug("vdev_id: %d, peertype: %d", + update_peer->vdev_id, update_peer->peer_type); + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + return status; + } + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto dec_ref; + } + qdf_mem_copy(&req->update_peer_req, update_peer, sizeof(*update_peer)); + req->vdev = vdev; + + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_CHANGE_STA; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post update peer msg fail"); + qdf_mem_free(req); + goto dec_ref; + } + + return status; +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + return status; +} + +static char *tdls_get_oper_str(enum tdls_command_type cmd_type) +{ + switch (cmd_type) { + case TDLS_CMD_ENABLE_LINK: + return "Enable_TDLS_LINK"; + case TDLS_CMD_DISABLE_LINK: + return "DISABLE_TDLS_LINK"; + case TDLS_CMD_REMOVE_FORCE_PEER: + return "REMOVE_FORCE_PEER"; + case TDLS_CMD_CONFIG_FORCE_PEER: + return "CONFIG_FORCE_PEER"; + default: + return "ERR:UNKNOWN OPER"; + } +} + +QDF_STATUS ucfg_tdls_oper(struct wlan_objmgr_vdev *vdev, + const uint8_t *macaddr, enum tdls_command_type cmd) +{ + struct scheduler_msg msg = {0,}; + struct tdls_oper_request *req; + QDF_STATUS status; + + if (!vdev || !macaddr) { + tdls_err("vdev: %pK, mac %pK", vdev, macaddr); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_debug("%s for peer " QDF_MAC_ADDR_FMT, + tdls_get_oper_str(cmd), + QDF_MAC_ADDR_REF(macaddr)); + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + goto error; + } + + qdf_mem_copy(req->peer_addr, macaddr, QDF_MAC_ADDR_SIZE); + req->vdev = vdev; + + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.type = cmd; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post msg for %s fail", tdls_get_oper_str(cmd)); + goto dec_ref; + } + + return status; +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +error: + qdf_mem_free(req); + return status; +} + +QDF_STATUS ucfg_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen) +{ + struct scheduler_msg msg = {0, }; + struct tdls_get_all_peers *tdls_peers; + QDF_STATUS status; + + tdls_peers = qdf_mem_malloc(sizeof(*tdls_peers)); + if (!tdls_peers) + return QDF_STATUS_E_NOMEM; + + tdls_peers->vdev = vdev; + tdls_peers->buf_len = buflen; + tdls_peers->buf = buf; + + msg.bodyptr = tdls_peers; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_GET_ALL_PEERS; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(tdls_peers); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS tdls_send_mgmt_frame_flush_callback(struct scheduler_msg *msg) +{ + struct tdls_action_frame_request *req; + + if (!msg || !msg->bodyptr) { + tdls_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + req = msg->bodyptr; + if (req->vdev) + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); + + qdf_mem_free(req); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ucfg_tdls_send_mgmt_frame( + struct tdls_action_frame_request *req) +{ + struct scheduler_msg msg = {0, }; + struct tdls_action_frame_request *mgmt_req; + QDF_STATUS status; + + if (!req || !req->vdev) { + tdls_err("Invalid mgmt req params %pK", req); + return QDF_STATUS_E_NULL_VALUE; + } + + mgmt_req = qdf_mem_malloc(sizeof(*mgmt_req) + + req->len); + if (!mgmt_req) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(mgmt_req, req, sizeof(*req)); + + /*populate the additional IE's */ + if ((0 != req->len) && (req->cmd_buf)) { + qdf_mem_copy(mgmt_req->tdls_mgmt.buf, req->cmd_buf, + req->len); + mgmt_req->tdls_mgmt.len = req->len; + } else { + mgmt_req->tdls_mgmt.len = 0; + } + + tdls_debug("vdev id: %d, session id : %d, action %d", mgmt_req->vdev_id, + mgmt_req->session_id, req->chk_frame.action_code); + status = wlan_objmgr_vdev_try_get_ref(req->vdev, WLAN_TDLS_NB_ID); + + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("Unable to get vdev reference for tdls module"); + goto mem_free; + } + + msg.bodyptr = mgmt_req; + msg.callback = tdls_process_cmd; + msg.flush_callback = tdls_send_mgmt_frame_flush_callback; + msg.type = TDLS_CMD_TX_ACTION; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + goto release_ref; + + return status; + +release_ref: + wlan_objmgr_vdev_release_ref(req->vdev, WLAN_TDLS_NB_ID); +mem_free: + qdf_mem_free(mgmt_req); + return status; +} + +QDF_STATUS ucfg_tdls_responder(struct tdls_set_responder_req *req) +{ + struct scheduler_msg msg = {0, }; + struct tdls_set_responder_req *msg_req; + QDF_STATUS status; + + if (!req || !req->vdev) { + tdls_err("invalid input %pK", req); + return QDF_STATUS_E_NULL_VALUE; + } + + msg_req = qdf_mem_malloc(sizeof(*msg_req)); + if (!msg_req) + return QDF_STATUS_E_NULL_VALUE; + + msg_req->responder = req->responder; + msg_req->vdev = req->vdev; + qdf_mem_copy(msg_req->peer_mac, req->peer_mac, QDF_MAC_ADDR_SIZE); + + msg.bodyptr = msg_req; + msg.callback = tdls_process_cmd; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + msg.type = TDLS_CMD_SET_RESPONDER; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(msg_req); + + return status; +} + +void ucfg_tdls_teardown_links_sync(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + return wlan_tdls_check_and_teardown_links_sync(psoc, vdev); +} + +QDF_STATUS ucfg_tdls_teardown_links(struct wlan_objmgr_psoc *psoc) +{ + return wlan_tdls_teardown_links(psoc); +} + +QDF_STATUS ucfg_tdls_notify_reset_adapter(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0, }; + + if (!vdev) { + tdls_err("vdev is NULL "); + return QDF_STATUS_E_NULL_VALUE; + } + tdls_debug("Enter "); + msg.bodyptr = vdev; + msg.callback = tdls_process_cmd; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + msg.type = TDLS_NOTIFY_RESET_ADAPTERS; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + return status; +} + +QDF_STATUS ucfg_tdls_set_operating_mode( + struct tdls_set_mode_params *set_mode_params) +{ + struct scheduler_msg msg = {0, }; + struct tdls_set_mode_params *set_mode; + QDF_STATUS status; + + if (!set_mode_params || !set_mode_params->vdev) { + tdls_err("set_mode_params %pK", set_mode_params); + return QDF_STATUS_E_NULL_VALUE; + } + + tdls_debug("Enter "); + + set_mode = qdf_mem_malloc(sizeof(*set_mode)); + if (!set_mode) + return QDF_STATUS_E_NULL_VALUE; + + status = wlan_objmgr_vdev_try_get_ref(set_mode->vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("failed to get vdev ref"); + qdf_mem_free(set_mode); + return status; + } + + set_mode->source = set_mode_params->source; + set_mode->tdls_mode = set_mode_params->tdls_mode; + set_mode->update_last = set_mode_params->update_last; + set_mode->vdev = set_mode_params->vdev; + + msg.bodyptr = set_mode; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_TDLS_MODE; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_objmgr_vdev_release_ref(set_mode->vdev, WLAN_TDLS_NB_ID); + qdf_mem_free(set_mode); + } + + tdls_debug("Exit "); + + return QDF_STATUS_SUCCESS; +} + +void ucfg_tdls_update_rx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr, + struct qdf_mac_addr *dest_mac_addr) +{ + tdls_update_rx_pkt_cnt(vdev, mac_addr, dest_mac_addr); + +} + +void ucfg_tdls_update_tx_pkt_cnt(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_addr) +{ + tdls_update_tx_pkt_cnt(vdev, mac_addr); +} + +QDF_STATUS ucfg_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, + uint32_t mode) +{ + QDF_STATUS status; + struct tdls_antenna_switch_request *req; + struct scheduler_msg msg = {0, }; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + goto error; + } + + req->vdev = vdev; + req->mode = mode; + + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.flush_callback = tdls_antenna_switch_flush_callback; + msg.type = TDLS_CMD_ANTENNA_SWITCH; + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post antenna switch msg fail"); + goto dec_ref; + } + + return status; + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +error: + qdf_mem_free(req); + return status; +} + +QDF_STATUS ucfg_set_tdls_offchannel(struct wlan_objmgr_vdev *vdev, + int offchannel) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0, }; + struct tdls_set_offchannel *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + goto free; + } + + req->offchannel = offchannel; + req->vdev = vdev; + req->callback = wlan_tdls_offchan_parms_callback; + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_OFFCHANNEL; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post set tdls offchannel msg fail"); + goto dec_ref; + } + + return status; + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + +free: + qdf_mem_free(req); + return status; +} + +QDF_STATUS ucfg_set_tdls_offchan_mode(struct wlan_objmgr_vdev *vdev, + int offchanmode) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0, }; + struct tdls_set_offchanmode *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + goto free; + } + + req->offchan_mode = offchanmode; + req->vdev = vdev; + req->callback = wlan_tdls_offchan_parms_callback; + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_OFFCHANMODE; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post set offchanmode msg fail"); + goto dec_ref; + } + + return status; + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + +free: + qdf_mem_free(req); + return status; +} + +QDF_STATUS ucfg_set_tdls_secoffchanneloffset(struct wlan_objmgr_vdev *vdev, + int offchanoffset) +{ + int status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0, }; + struct tdls_set_secoffchanneloffset *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_TDLS_NB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("can't get vdev"); + goto free; + } + + req->offchan_offset = offchanoffset; + req->vdev = vdev; + req->callback = wlan_tdls_offchan_parms_callback; + msg.bodyptr = req; + msg.callback = tdls_process_cmd; + msg.type = TDLS_CMD_SET_SECOFFCHANOFFSET; + msg.flush_callback = ucfg_tdls_post_msg_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_HDD, QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + tdls_err("post set secoffchan offset msg fail"); + goto dec_ref; + } + return status; + +dec_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); + +free: + qdf_mem_free(req); + return status; +} + +struct wlan_objmgr_vdev *ucfg_tdls_get_mlo_vdev(struct wlan_objmgr_vdev *vdev, + uint8_t index, + wlan_objmgr_ref_dbgid dbg_id) +{ + return wlan_tdls_get_mlo_vdev(vdev, index, dbg_id); +} + +void ucfg_tdls_release_mlo_vdev(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid dbg_id) +{ + return wlan_tdls_release_mlo_vdev(vdev, dbg_id); +} + +bool ucfg_tdls_discovery_on_going(struct wlan_objmgr_vdev *vdev) +{ + struct tdls_soc_priv_obj *tdls_soc; + uint8_t count; + + tdls_soc = wlan_vdev_get_tdls_soc_obj(vdev); + if (!tdls_soc) + return false; + count = qdf_atomic_read(&tdls_soc->timer_cnt); + tdls_debug("discovery req timer count %d", count); + + return count ? true : false; +} + +QDF_STATUS ucfg_tdls_set_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac, int8_t rssi) +{ + return tdls_set_rssi(vdev, mac, rssi); +} + +void ucfg_tdls_notify_connect_failure(struct wlan_objmgr_psoc *psoc) +{ + return tdls_notify_decrement_session(psoc); +} + +uint16_t ucfg_get_tdls_conn_peer_count(struct wlan_objmgr_vdev *vdev) +{ + return tdls_get_connected_peer_count_from_vdev(vdev); +} + +struct wlan_objmgr_vdev *ucfg_get_tdls_vdev(struct wlan_objmgr_psoc *psoc, + wlan_objmgr_ref_dbgid dbg_id) +{ + return tdls_get_vdev(psoc, dbg_id); +} + +bool ucfg_tdls_check_is_tdls_allowed(struct wlan_objmgr_vdev *vdev) +{ + return tdls_check_is_tdls_allowed(vdev); +} + +void ucfg_tdls_set_user_tdls_enable(struct wlan_objmgr_vdev *vdev, + bool is_user_tdls_enable) +{ + return tdls_set_user_tdls_enable(vdev, is_user_tdls_enable); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_utils_api.c b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_utils_api.c new file mode 100644 index 0000000000..2e9b2ad43e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/tdls/dispatcher/src/wlan_tdls_utils_api.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_tdls_utils_api.c + * + * TDLS utility functions definitions + */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam_preauth.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam_preauth.c new file mode 100644 index 0000000000..38c2376af4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam_preauth.c @@ -0,0 +1,770 @@ +/* + * Copyright (c) 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cm_host_roam_preauth.c + * + * Implements general roam pre-auth functionality for connection manager + */ + +#include "wlan_cm_vdev_api.h" +#include "wni_api.h" +#include +#include "wlan_cm_roam_api.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_cm_public_struct.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "connection_mgr/core/src/wlan_cm_roam.h" +#include "connection_mgr/core/src/wlan_cm_sm.h" +#include "connection_mgr/core/src/wlan_cm_main_api.h" + +#define MAX_NUM_PREAUTH_RETRIES 3 +#define CM_PREAUTH_TIMEOUT 10000 +#define REASSOC_TIMER_DURATION 60 + +static QDF_STATUS cm_get_valid_preauth_candidate(struct cm_roam_req *cm_req) +{ + qdf_list_t *candidate_list; + qdf_list_node_t *cur_node = NULL; + struct scan_cache_node *prev_candidate; + bool new_candidate = false; + uint8_t vdev_id = cm_req->req.vdev_id; + + candidate_list = cm_req->candidate_list; + if (!candidate_list || !qdf_list_size(candidate_list)) { + mlme_info(CM_PREFIX_FMT "no valid candidate found", + CM_PREFIX_REF(vdev_id, cm_req->cm_id)); + return QDF_STATUS_E_EMPTY; + } + + prev_candidate = cm_req->cur_candidate; + if (!prev_candidate) { + qdf_list_peek_front(candidate_list, &cur_node); + new_candidate = true; + } else if (cm_req->num_preauth_retry >= MAX_NUM_PREAUTH_RETRIES) { + qdf_list_peek_next(candidate_list, &prev_candidate->node, + &cur_node); + new_candidate = true; + } + + if (new_candidate) { + if (!cur_node) { + mlme_debug(CM_PREFIX_FMT "All candidates tried", + CM_PREFIX_REF(vdev_id, cm_req->cm_id)); + return QDF_STATUS_E_FAILURE; + } + cm_req->num_preauth_retry = 0; + cm_req->cur_candidate = qdf_container_of(cur_node, + struct scan_cache_node, + node); + } + + cm_req->num_preauth_retry++; + + mlme_debug(CM_PREFIX_FMT "Try preauth attempt no. %d for " QDF_MAC_ADDR_FMT, + CM_PREFIX_REF(vdev_id, cm_req->cm_id), + cm_req->num_preauth_retry, + QDF_MAC_ADDR_REF(cm_req->cur_candidate->entry->bssid.bytes)); + + return QDF_STATUS_SUCCESS; +} + +void cm_preauth_fail(struct cnx_mgr *cm_ctx, + struct wlan_cm_preauth_fail *preauth_fail_rsp) +{ + struct cm_req *cm_req; + wlan_cm_id cm_id; + + cm_id = preauth_fail_rsp->cm_id; + cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id); + /* + * If the entry is not present in the list, it must have been cleared + * already. + */ + if (!cm_req) + return; + + if (cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED) + cm_mlme_roam_preauth_fail(cm_ctx->vdev, &cm_req->roam_req.req, + preauth_fail_rsp->reason); + + mlme_debug(CM_PREFIX_FMT, + CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id)); + + if (cm_req->roam_req.req.source == CM_ROAMING_HOST && + cm_get_state(cm_ctx) == WLAN_CM_S_CONNECTED) + wlan_cm_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT, + REASON_USER_TRIGGERED_ROAM_FAILURE, NULL); + + cm_remove_cmd(cm_ctx, &cm_id); +} + +static void +cm_preauth_handle_event_post_fail(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) +{ + struct wlan_cm_preauth_fail preauth_fail_rsp; + + preauth_fail_rsp.cm_id = cm_id; + preauth_fail_rsp.reason = CM_ABORT_DUE_TO_NEW_REQ_RECVD; + + cm_preauth_fail(cm_ctx, &preauth_fail_rsp); +} + +static QDF_STATUS +cm_preauth_cmd_timeout(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) +{ + QDF_STATUS status; + struct wlan_cm_preauth_fail preauth_fail_rsp; + + preauth_fail_rsp.cm_id = cm_id; + preauth_fail_rsp.reason = CM_SER_TIMEOUT; + + status = cm_sm_deliver_event( + cm_ctx->vdev, WLAN_CM_SM_EV_PREAUTH_FAIL, + sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp); + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); + + return status; +} + +static QDF_STATUS +cm_ser_preauth_cb(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + struct cnx_mgr *cm_ctx; + + if (!cmd) { + mlme_err("cmd is NULL, reason: %d", reason); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev = cmd->vdev; + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) + return QDF_STATUS_E_NULL_VALUE; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + if (cmd->activation_reason == SER_PENDING_TO_ACTIVE) + status = cm_sm_deliver_event( + vdev, WLAN_CM_SM_EV_PREAUTH_ACTIVE, + sizeof(wlan_cm_id), &cmd->cmd_id); + else + status = cm_sm_deliver_event_sync( + cm_ctx, WLAN_CM_SM_EV_PREAUTH_ACTIVE, + sizeof(wlan_cm_id), &cmd->cmd_id); + if (QDF_IS_STATUS_SUCCESS(status)) + break; + /* + * Handle failure if posting fails, i.e. the SM state has + * changed or head cm_id doesn't match the active cm_id. + * connect active should be handled only in JOIN_PENDING. If + * new command has been received connect activation should be + * aborted from here with connect req cleanup. + */ + cm_preauth_handle_event_post_fail(cm_ctx, cmd->cmd_id); + break; + case WLAN_SER_CB_CANCEL_CMD: + /* command removed from pending list. */ + break; + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + mlme_err(CM_PREFIX_FMT "Active command timeout", + CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id)); + QDF_ASSERT(0); + + cm_preauth_cmd_timeout(cm_ctx, cmd->cmd_id); + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + cm_reset_active_cm_id(vdev, cmd->cmd_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + break; + default: + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +static QDF_STATUS cm_ser_preauth_req(struct cnx_mgr *cm_ctx, + struct cm_req *cm_req) +{ + struct wlan_serialization_command cmd = {0, }; + enum wlan_serialization_status ser_cmd_status; + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev); + + status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "unable to get reference", + CM_PREFIX_REF(vdev_id, cm_req->cm_id)); + return status; + } + + cmd.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; + cmd.cmd_id = cm_req->cm_id; + cmd.cmd_cb = cm_ser_preauth_cb; + cmd.source = WLAN_UMAC_COMP_MLME; + cmd.is_high_priority = false; + cmd.cmd_timeout_duration = CM_PREAUTH_TIMEOUT; + cmd.vdev = cm_ctx->vdev; + cmd.is_blocking = true; + + ser_cmd_status = wlan_serialization_request(&cmd); + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list.Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + default: + mlme_err(CM_PREFIX_FMT "ser cmd status %d", + CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status); + wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_send_preauth_start_fail(struct cnx_mgr *cm_ctx, + wlan_cm_id cm_id, + enum wlan_cm_connect_fail_reason reason) +{ + QDF_STATUS status; + struct wlan_cm_preauth_fail preauth_fail_rsp; + + preauth_fail_rsp.cm_id = cm_id; + preauth_fail_rsp.reason = reason; + + status = cm_sm_deliver_event_sync( + cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL, + sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp); + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); + + return status; +} + +static void cm_flush_invalid_preauth_ap(struct cnx_mgr *cm_ctx, + struct cm_roam_req *roam_req) +{ + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + qdf_list_t *candidate_list; + struct scan_cache_node *scan_node = NULL; + struct qdf_mac_addr connected_bssid; + bool is_valid; + uint8_t vdev_id = roam_req->req.vdev_id; + struct wlan_objmgr_psoc *psoc; + uint8_t enable_mcc_mode = false; + qdf_freq_t conc_freq, bss_freq; + + /* + * Only When entering first time (ie cur_candidate is NULL), + * flush invalid APs from the list and if list is not NULL. + */ + if (roam_req->cur_candidate || !roam_req->candidate_list) + return; + + psoc = wlan_vdev_get_psoc(cm_ctx->vdev); + if (!psoc) + return; + + wlan_mlme_get_mcc_feature(psoc, &enable_mcc_mode); + + wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &connected_bssid); + + candidate_list = roam_req->candidate_list; + + qdf_list_peek_front(candidate_list, &cur_node); + + while (cur_node) { + is_valid = true; + qdf_list_peek_next(candidate_list, cur_node, &next_node); + scan_node = qdf_container_of(cur_node, struct scan_cache_node, + node); + bss_freq = scan_node->entry->channel.chan_freq; + if (qdf_is_macaddr_equal(&connected_bssid, + &scan_node->entry->bssid)) { + mlme_debug(CM_PREFIX_FMT "Remove connected AP " QDF_MAC_ADDR_FMT " from list", + CM_PREFIX_REF(vdev_id, roam_req->cm_id), + QDF_MAC_ADDR_REF(connected_bssid.bytes)); + is_valid = false; + } + + /* + * Continue if MCC is disabled in INI and if AP + * will create MCC + */ + if (policy_mgr_concurrent_open_sessions_running(psoc) && + !enable_mcc_mode) { + conc_freq = wlan_get_conc_freq(); + if (conc_freq && (conc_freq != bss_freq)) { + mlme_info(CM_PREFIX_FMT "Remove AP " QDF_MAC_ADDR_FMT ", MCC not supported. freq %d conc_freq %d", + CM_PREFIX_REF(vdev_id, roam_req->cm_id), + QDF_MAC_ADDR_REF(connected_bssid.bytes), + bss_freq, conc_freq); + is_valid = false; + } + } + + if (!is_valid) { + qdf_list_remove_node(candidate_list, cur_node); + util_scan_free_cache_entry(scan_node->entry); + qdf_mem_free(scan_node); + } + + cur_node = next_node; + next_node = NULL; + } +} + +QDF_STATUS cm_host_roam_preauth_start(struct cnx_mgr *cm_ctx, + struct cm_req *cm_req) +{ + QDF_STATUS status; + + cm_flush_invalid_preauth_ap(cm_ctx, &cm_req->roam_req); + + status = cm_get_valid_preauth_candidate(&cm_req->roam_req); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return cm_ser_preauth_req(cm_ctx, cm_req); +} + +void cm_free_preauth_req(struct wlan_preauth_req *preauth_req) +{ + if (!preauth_req) + return; + + util_scan_free_cache_entry(preauth_req->entry); + preauth_req->entry = NULL; + qdf_mem_free(preauth_req); +} + +static QDF_STATUS cm_flush_preauth_req(struct scheduler_msg *msg) +{ + struct wlan_preauth_req *preauth_req; + + if (!msg || !msg->bodyptr) { + mlme_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + preauth_req = msg->bodyptr; + cm_free_preauth_req(preauth_req); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +cm_issue_preauth_req(struct cnx_mgr *cm_ctx, struct cm_roam_req *roam_req) +{ + struct wlan_preauth_req *preauth_req; + struct scheduler_msg msg; + QDF_STATUS status; + + qdf_mem_zero(&msg, sizeof(msg)); + preauth_req = qdf_mem_malloc(sizeof(*preauth_req)); + if (!preauth_req) + return QDF_STATUS_E_NOMEM; + + preauth_req->vdev_id = wlan_vdev_get_id(cm_ctx->vdev); + preauth_req->entry = + util_scan_copy_cache_entry(roam_req->cur_candidate->entry); + + if (!preauth_req->entry) { + qdf_mem_free(preauth_req); + return QDF_STATUS_E_NOMEM; + } + + msg.bodyptr = preauth_req; + msg.type = CM_PREAUTH_REQ; + msg.flush_callback = cm_flush_preauth_req; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "msg post fail", + CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), + roam_req->cm_id)); + cm_free_preauth_req(preauth_req); + } + + return status; +} + +QDF_STATUS cm_preauth_active(struct cnx_mgr *cm_ctx, wlan_cm_id *cm_id) +{ + struct cm_req *cm_req; + struct cm_roam_req *roam_req; + QDF_STATUS status; + + cm_req = cm_get_req_by_cm_id(cm_ctx, *cm_id); + if (!cm_req) + return QDF_STATUS_E_INVAL; + + cm_ctx->active_cm_id = *cm_id; + roam_req = &cm_req->roam_req; + + status = cm_issue_preauth_req(cm_ctx, roam_req); + if (QDF_IS_STATUS_ERROR(status)) + cm_send_preauth_start_fail(cm_ctx, *cm_id, CM_GENERIC_FAILURE); + + return status; +} + +#ifdef FEATURE_WLAN_ESE +static void cm_update_cckmtsf(uint32_t *timestamp0, uint32_t *timestamp1, + uint64_t *incr) +{ + uint64_t timestamp64 = ((uint64_t)*timestamp1 << 32) | (*timestamp0); + + timestamp64 = (uint64_t)(timestamp64 + (*incr)); + *timestamp0 = (uint32_t)(timestamp64 & 0xffffffff); + *timestamp1 = (uint32_t)((timestamp64 >> 32) & 0xffffffff); +} + +/** + * cm_roam_read_tsf() - read TSF + * @cm_ctx: connection manager context + * @rsp: preauth response + * + * This function reads the TSF and also add the time elapsed since last + * beacon or probe response reception from the hand off AP to arrive at + * the latest TSF value. + * + * Return: none + */ +static void cm_roam_read_tsf(struct cnx_mgr *cm_ctx, + struct wlan_preauth_rsp *rsp) +{ + struct cm_req *cm_req; + struct scan_cache_entry *scan_entry; + uint64_t timer_diff = 0; + + cm_req = cm_get_req_by_cm_id(cm_ctx, rsp->cm_id); + if (!cm_req) + return; + if (!cm_req->roam_req.cur_candidate || + !cm_req->roam_req.cur_candidate->entry) + return; + + scan_entry = cm_req->roam_req.cur_candidate->entry; + qdf_mem_copy(rsp->timestamp, scan_entry->tsf_info.data, 8); + + /* Get the time diff in nano seconds */ + timer_diff = qdf_get_monotonic_boottime_ns() - scan_entry->boottime_ns; + /* Convert msec to micro sec timer */ + timer_diff = do_div(timer_diff, SYSTEM_TIME_NSEC_TO_USEC); + /* Update the TSF with the difference in system time */ + cm_update_cckmtsf(&rsp->timestamp[0], &rsp->timestamp[1], + &timer_diff); +} +#else +static inline void cm_roam_read_tsf(struct cnx_mgr *cm_ctx, + struct wlan_preauth_rsp *rsp) +{} +#endif + +#define MD_IE_ID 54 + +void cm_reassoc_timer_callback(void *context) +{ + QDF_STATUS status; + struct reassoc_timer_ctx *ctx = context; + struct cnx_mgr *cm_ctx; + struct wlan_objmgr_vdev *vdev; + wlan_cm_id cm_id = ctx->cm_id; + uint8_t vdev_id = ctx->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(ctx->pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err(CM_PREFIX_FMT "vdev object is NULL", + CM_PREFIX_REF(vdev_id, cm_id)); + return; + } + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) + goto rel_ref; + + status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_REASSOC_TIMER, + sizeof(wlan_cm_id), &cm_id); + + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); + +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void cm_preauth_success(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp) +{ + QDF_STATUS status; + struct mlme_legacy_priv *mlme_priv; + struct rso_config *rso_cfg; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id = rsp->vdev_id; + wlan_cm_id cm_id = rsp->cm_id; + struct cm_roam_values_copy config; + bool is_11r; + + vdev = cm_ctx->vdev; + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev || !rsp->psoc) { + mlme_err(CM_PREFIX_FMT "pdev or psoc is NULL", + CM_PREFIX_REF(vdev_id, cm_id)); + goto err; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err(CM_PREFIX_FMT "vdev ext priv is NULL", + CM_PREFIX_REF(vdev_id, cm_id)); + goto err; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + mlme_err(CM_PREFIX_FMT "rso_cfg is NULL", + CM_PREFIX_REF(vdev_id, cm_id)); + goto err; + } + + mlme_err(CM_PREFIX_FMT "Preauth success with " QDF_MAC_ADDR_FMT, + CM_PREFIX_REF(vdev_id, rsp->cm_id), + QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes)); + + cm_csr_preauth_done(vdev); + + qdf_mem_copy(rsp->ric_ies, + mlme_priv->connect_info.ft_info.ric_ies, + mlme_priv->connect_info.ft_info.ric_ies_length); + rsp->ric_ies_length = mlme_priv->connect_info.ft_info.ric_ies_length; + + mlme_priv->connect_info.ft_info.ft_state = FT_REASSOC_REQ_WAIT; + + /* start reassoc timer */ + rso_cfg->ctx.pdev = pdev; + rso_cfg->ctx.vdev_id = vdev_id; + rso_cfg->ctx.cm_id = cm_id; + + status = qdf_mc_timer_start(&rso_cfg->reassoc_timer, + REASSOC_TIMER_DURATION); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "start reassoc timer failed, status %d", + CM_PREFIX_REF(vdev_id, cm_id), status); + goto err; + } + + wlan_cm_roam_cfg_get_value(rsp->psoc, vdev_id, IS_11R_CONNECTION, + &config); + is_11r = config.bool_value; + if (is_11r) + mlme_cm_osif_ft_preauth_complete(vdev, rsp); + + if (wlan_cm_get_ese_assoc(pdev, vdev_id)) { + cm_roam_read_tsf(cm_ctx, rsp); + mlme_cm_osif_cckm_preauth_complete(vdev, rsp); + } + + if (cm_is_fast_roam_enabled(rsp->psoc) && + cm_is_rsn_or_8021x_sha256_auth_type(vdev)) + mlme_cm_osif_pmksa_candidate_notify(vdev, &rsp->pre_auth_bssid, + 1, false); + + mlme_priv->connect_info.ft_info.add_mdie = false; + if (!(is_11r && cm_is_open_mode(vdev))) + return; + + qdf_mem_zero(mlme_priv->connect_info.ft_info.reassoc_ft_ie, + MAX_FTIE_SIZE); + mlme_priv->connect_info.ft_info.reassoc_ie_len = 0; + + if (wlan_get_ie_ptr_from_eid(MD_IE_ID, rsp->ft_ie, rsp->ft_ie_length)) + mlme_priv->connect_info.ft_info.add_mdie = true; + + if (!mlme_priv->connect_info.ft_info.ric_ies_length) + return; + + /* Copy the RIC IEs to reassoc IEs */ + qdf_mem_copy(mlme_priv->connect_info.ft_info.reassoc_ft_ie, + mlme_priv->connect_info.ft_info.ric_ies, + mlme_priv->connect_info.ft_info.ric_ies_length); + mlme_priv->connect_info.ft_info.reassoc_ie_len = + mlme_priv->connect_info.ft_info.ric_ies_length; + mlme_priv->connect_info.ft_info.add_mdie = true; + return; + +err: + rsp->status = QDF_STATUS_E_ABORTED; + status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_PREAUTH_RESP, + sizeof(*rsp), rsp); + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); +} + +static QDF_STATUS +cm_hanlde_preauth_failure(struct cnx_mgr *cm_ctx, wlan_cm_id cm_id) +{ + QDF_STATUS status; + struct wlan_cm_preauth_fail preauth_fail_rsp; + + preauth_fail_rsp.cm_id = cm_id; + preauth_fail_rsp.reason = CM_GENERIC_FAILURE; + + status = cm_sm_deliver_event_sync( + cm_ctx, WLAN_CM_SM_EV_PREAUTH_FAIL, + sizeof(struct wlan_cm_preauth_fail), &preauth_fail_rsp); + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); + + return status; +} + +void cm_preauth_done_resp(struct cnx_mgr *cm_ctx, struct wlan_preauth_rsp *rsp) +{ + QDF_STATUS status; + struct cm_req *cm_req; + wlan_cm_id cm_id = rsp->cm_id; + + if (QDF_IS_STATUS_ERROR(rsp->status)) { + cm_req = cm_get_req_by_cm_id(cm_ctx, cm_id); + if (!cm_req) + return; + mlme_info(CM_PREFIX_FMT "Preauth attempt no. %d failed for " QDF_MAC_ADDR_FMT, + CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), + cm_req->roam_req.num_preauth_retry, + QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes)); + + /* retry again with same or new candidate */ + status = cm_host_roam_preauth_start(cm_ctx, cm_req); + if (QDF_IS_STATUS_ERROR(status)) + cm_hanlde_preauth_failure(cm_ctx, cm_id); + } else { + status = cm_sm_deliver_event_sync(cm_ctx, + WLAN_CM_SM_EV_PREAUTH_DONE, + sizeof(*rsp), rsp); + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); + } +} + +/** + * cm_remove_preauth_cmd_from_serialization() - Remove preauth cmd + * from serialization + * @cm_ctx: connection manager context + * @cm_id: cm id of roam req + * + * Return: void + */ +static void cm_remove_preauth_cmd_from_serialization(struct cnx_mgr *cm_ctx, + wlan_cm_id cm_id) +{ + struct wlan_serialization_queued_cmd_info cmd_info; + + qdf_mem_zero(&cmd_info, sizeof(cmd_info)); + cmd_info.vdev = cm_ctx->vdev; + cmd_info.cmd_id = cm_id; + cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; + cmd_info.cmd_type = WLAN_SER_CMD_PERFORM_PRE_AUTH; + + mlme_debug(CM_PREFIX_FMT "Remove cmd type %d from active", + CM_PREFIX_REF(wlan_vdev_get_id(cm_ctx->vdev), cm_id), + cmd_info.cmd_type); + cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; + wlan_serialization_remove_cmd(&cmd_info); +} + +static QDF_STATUS cm_preauth_rsp(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp) +{ + QDF_STATUS status; + struct cnx_mgr *cm_ctx; + wlan_cm_id cm_id; + uint32_t prefix; + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) + return QDF_STATUS_E_NULL_VALUE; + + cm_id = cm_ctx->active_cm_id; + prefix = CM_ID_GET_PREFIX(cm_id); + + if (prefix != ROAM_REQ_PREFIX) { + mlme_err(CM_PREFIX_FMT "active req is not roam req", + CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id)); + return QDF_STATUS_E_INVAL; + } + rsp->cm_id = cm_id; + + mlme_debug(CM_PREFIX_FMT "preauth resp status %d for " QDF_MAC_ADDR_FMT, + CM_PREFIX_REF(wlan_vdev_get_id(vdev), cm_id), + rsp->status, QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes)); + + cm_remove_preauth_cmd_from_serialization(cm_ctx, cm_id); + + status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_PREAUTH_RESP, + sizeof(*rsp), rsp); + if (QDF_IS_STATUS_ERROR(status)) + cm_preauth_handle_event_post_fail(cm_ctx, cm_id); + + return status; +} + +QDF_STATUS cm_handle_preauth_rsp(struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_preauth_rsp *rsp = NULL; + struct wlan_objmgr_vdev *vdev; + + if (!msg || !msg->bodyptr) { + status = QDF_STATUS_E_FAILURE; + goto end; + } + + rsp = (struct wlan_preauth_rsp *)msg->bodyptr; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(rsp->psoc, rsp->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev_id: %d : vdev not found, status %d", + rsp->vdev_id, rsp->status); + status = QDF_STATUS_E_INVAL; + goto end; + } + + status = cm_preauth_rsp(vdev, rsp); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +end: + if (rsp) + qdf_mem_free(rsp); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c new file mode 100644 index 0000000000..d0b2fa1258 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cm_host_util.c + * + * Implements Host roam (LFR2) reassoc specific legacy code for + * connection manager + */ + +#include "wlan_cm_vdev_api.h" +#include "wlan_scan_api.h" +#include "wlan_scan_utils_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_roam_debug.h" +#include "wni_api.h" +#include "wlan_logging_sock_svc.h" +#include "connection_mgr/core/src/wlan_cm_roam.h" + +/* + * cm_copy_ssids_from_rso_config_params() - copy SSID from rso_config_params + * to scan filter + * @rso_usr_cfg: rso user config + * @filter: scan filter + * + * Return void + */ +static void +cm_copy_ssids_from_rso_config_params(struct rso_user_config *rso_usr_cfg, + struct scan_filter *filter) +{ + uint8_t i; + uint8_t max_ssid; + + if (!rso_usr_cfg->num_ssid_allowed_list) + return; + max_ssid = QDF_MIN(WLAN_SCAN_FILTER_NUM_SSID, MAX_SSID_ALLOWED_LIST); + + filter->num_of_ssid = rso_usr_cfg->num_ssid_allowed_list; + if (filter->num_of_ssid > max_ssid) + filter->num_of_ssid = max_ssid; + for (i = 0; i < filter->num_of_ssid; i++) + qdf_mem_copy(&filter->ssid_list[i], + &rso_usr_cfg->ssid_allowed_list[i], + sizeof(struct wlan_ssid)); +} + +QDF_STATUS cm_update_advance_roam_scan_filter( + struct wlan_objmgr_vdev *vdev, struct scan_filter *filter) +{ + uint8_t num_ch = 0; + struct wlan_objmgr_psoc *psoc; + struct rso_config *rso_cfg; + struct rso_chan_info *chan_lst; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct rso_user_config *rso_usr_cfg; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_debug("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + rso_usr_cfg = wlan_cm_get_rso_user_config(vdev); + if (!rso_usr_cfg) + return QDF_STATUS_E_INVAL; + + mlme_debug("No of Allowed SSID List:%d", + rso_usr_cfg->num_ssid_allowed_list); + + if (rso_usr_cfg->num_ssid_allowed_list) { + cm_copy_ssids_from_rso_config_params(rso_usr_cfg, filter); + } else { + filter->num_of_ssid = 1; + wlan_vdev_mlme_get_ssid(vdev, filter->ssid_list[0].ssid, + &filter->ssid_list[0].length); + + mlme_debug("Filtering for SSID " QDF_SSID_FMT ",length of SSID = %u", + QDF_SSID_REF(filter->ssid_list[0].length, + filter->ssid_list[0].ssid), + filter->ssid_list[0].length); + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_FAILURE; + + chan_lst = &rso_cfg->roam_scan_freq_lst; + num_ch = chan_lst->num_chan; + if (num_ch) { + filter->num_of_channels = num_ch; + if (filter->num_of_channels > NUM_CHANNELS) + filter->num_of_channels = NUM_CHANNELS; + qdf_mem_copy(filter->chan_freq_list, chan_lst->freq_list, + filter->num_of_channels * + sizeof(filter->chan_freq_list[0])); + } + + if (rso_cfg->is_11r_assoc) + /* + * MDIE should be added as a part of profile. This should be + * added as a part of filter as well + */ + filter->mobility_domain = rso_cfg->mdid.mobility_domain; + filter->enable_adaptive_11r = + wlan_mlme_adaptive_11r_enabled(psoc); + + if (rso_cfg->orig_sec_info.rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED) + filter->pmf_cap = WLAN_PMF_REQUIRED; + else if (rso_cfg->orig_sec_info.rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) + filter->pmf_cap = WLAN_PMF_CAPABLE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_handle_reassoc_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_reassoc_req *req) +{ + struct cm_vdev_join_req *join_req; + struct scheduler_msg msg; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct rso_config *rso_cfg; + + if (!vdev || !req) + return QDF_STATUS_E_FAILURE; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "pdev not found", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + return QDF_STATUS_E_INVAL; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "psoc not found", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + return QDF_STATUS_E_INVAL; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_NOSUPPORT; + + qdf_mem_zero(&msg, sizeof(msg)); + join_req = qdf_mem_malloc(sizeof(*join_req)); + if (!join_req) + return QDF_STATUS_E_NOMEM; + + wlan_cm_set_disable_hi_rssi(pdev, req->vdev_id, true); + mlme_debug(CM_PREFIX_FMT "Disabling HI_RSSI, AP freq=%d, rssi=%d", + CM_PREFIX_REF(req->vdev_id, req->cm_id), + req->bss->entry->channel.chan_freq, + req->bss->entry->rssi_raw); + + if (rso_cfg->assoc_ie.ptr) { + join_req->assoc_ie.ptr = qdf_mem_malloc(rso_cfg->assoc_ie.len); + if (!join_req->assoc_ie.ptr) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(join_req->assoc_ie.ptr, rso_cfg->assoc_ie.ptr, + rso_cfg->assoc_ie.len); + join_req->assoc_ie.len = rso_cfg->assoc_ie.len; + } + + join_req->entry = util_scan_copy_cache_entry(req->bss->entry); + if (!join_req->entry) { + mlme_err(CM_PREFIX_FMT "Failed to copy scan entry", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + cm_free_join_req(join_req); + return QDF_STATUS_E_NOMEM; + } + join_req->vdev_id = req->vdev_id; + join_req->cm_id = req->cm_id; + + status = cm_csr_handle_join_req(vdev, NULL, join_req, true); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "fail to fill params from legacy", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + cm_free_join_req(join_req); + return QDF_STATUS_E_FAILURE; + } + + wlan_rec_conn_info(req->vdev_id, DEBUG_CONN_CONNECTING, + req->bss->entry->bssid.bytes, + req->bss->entry->neg_sec_info.key_mgmt, + req->bss->entry->channel.chan_freq); + + msg.bodyptr = join_req; + msg.type = CM_REASSOC_REQ; + msg.flush_callback = cm_flush_join_req; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "msg post fail", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + cm_free_join_req(join_req); + } + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) + wlan_register_txrx_packetdump(OL_TXRX_PDEV_ID); + + return status; +} + +QDF_STATUS cm_handle_roam_start(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_roam_req *req) +{ + if (!vdev || !req) { + mlme_err("vdev or req is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (req->source == CM_ROAMING_HOST) + cm_roam_state_change(wlan_vdev_get_pdev(vdev), + wlan_vdev_get_id(vdev), + WLAN_ROAM_RSO_STOPPED, + REASON_OS_REQUESTED_ROAMING_NOW, + NULL, false); + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c new file mode 100644 index 0000000000..0f0b75b58a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c @@ -0,0 +1,1728 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_fw_sync.c + * + * Implementation for the FW based roaming sync api interfaces. + */ +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_cm_roam_i.h" +#include "wlan_dlm_api.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_utility.h" +#include "wlan_scan_api.h" +#include "wlan_crypto_global_api.h" +#include "wlan_cm_tgt_if_tx_api.h" +#include "wlan_cm_vdev_api.h" +#include "wlan_p2p_api.h" +#include "wlan_tdls_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include "cds_utils.h" +#include "wlan_roam_debug.h" +#include "wlan_mlme_twt_api.h" +#include "connection_mgr/core/src/wlan_cm_roam.h" +#include "connection_mgr/core/src/wlan_cm_main.h" +#include "connection_mgr/core/src/wlan_cm_sm.h" +#include +#include "wlan_mlo_mgr_roam.h" +#include "wlan_vdev_mgr_utils_api.h" +#include "wlan_mlo_link_force.h" +#include +#include + +/* + * cm_is_peer_preset_on_other_sta() - Check if peer exists on other STA + * @psoc: Pointer to psoc + * @vdev: pointer to vdev + * @vdev_id: vdev id + * @event: Roam sync event pointer + * + * Return: True is peer found on other STA else return false + */ +static bool +cm_is_peer_preset_on_other_sta(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, void *event) +{ + bool peer_exists_other_sta = false; + struct roam_offload_synch_ind *sync_ind; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint8_t peer_vdev_id; + + if (!wma) { + wma_err("wma_handle is NULL"); + return false; + } + + sync_ind = (struct roam_offload_synch_ind *)event; + + if (wma_objmgr_peer_exist(wma, sync_ind->bssid.bytes, &peer_vdev_id)) { + if (vdev_id != peer_vdev_id && + !mlo_check_is_given_vdevs_on_same_mld(psoc, vdev_id, + peer_vdev_id)) { + wma_debug("Peer " QDF_MAC_ADDR_FMT + " already exists on vdev %d, current vdev %d", + QDF_MAC_ADDR_REF(sync_ind->bssid.bytes), + peer_vdev_id, vdev_id); + peer_exists_other_sta = true; + } + } + + return peer_exists_other_sta; +} + +QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + void *event, uint32_t event_data_len) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (mlo_is_mld_disconnecting_connecting(vdev) || + cm_is_vdev_connecting(vdev) || + cm_is_vdev_disconnecting(vdev) || + cm_is_peer_preset_on_other_sta(psoc, vdev, vdev_id, event)) { + mlme_err("vdev %d Roam sync not handled in connecting/disconnecting state", + vdev_id); + wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), + vdev_id, + WLAN_ROAM_RSO_STOPPED, + REASON_ROAM_SYNCH_FAILED); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return QDF_STATUS_E_INVAL; + } + mlo_sta_stop_reconfig_timer(vdev); + wlan_clear_mlo_sta_link_removed_flag(vdev); + + status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_SYNC, + event_data_len, event); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Roam sync was not handled"); + wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), + vdev_id, WLAN_ROAM_RSO_STOPPED, + REASON_ROAM_SYNCH_FAILED); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} + +QDF_STATUS +cm_fw_send_vdev_roam_event(struct cnx_mgr *cm_ctx, uint16_t data_len, + void *data) +{ + QDF_STATUS status; + wlan_cm_id cm_id; + struct wlan_objmgr_psoc *psoc; + struct cm_roam_req *roam_req = NULL; + + roam_req = cm_get_first_roam_command(cm_ctx->vdev); + if (!roam_req) { + mlme_err("Failed to find roam req from list"); + cm_id = CM_ID_INVALID; + status = QDF_STATUS_E_FAILURE; + goto error; + } + + cm_id = roam_req->cm_id; + psoc = wlan_vdev_get_psoc(cm_ctx->vdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "Failed to find psoc", + CM_PREFIX_REF(roam_req->req.vdev_id, + roam_req->cm_id)); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + status = wlan_vdev_mlme_sm_deliver_evt(cm_ctx->vdev, + WLAN_VDEV_SM_EV_ROAM, + data_len, + data); + +error: + + return status; +} + +QDF_STATUS +cm_fw_roam_sync_start_ind(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_pdev *pdev; + struct qdf_mac_addr connected_bssid; + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + uint8_t good_rssi_cfg; + struct psoc_mlme_obj *mlme_psoc_obj; + struct scoring_cfg *score_config; + + pdev = wlan_vdev_get_pdev(vdev); + vdev_id = wlan_vdev_get_id(vdev); + psoc = wlan_pdev_get_psoc(pdev); + + mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); + if (!mlme_psoc_obj) + return QDF_STATUS_E_INVAL; + + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { + if (!MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, + sync_ind->roamed_vdev_id)) + status = wlan_cm_roam_state_change(pdev, + sync_ind->roamed_vdev_id, + WLAN_ROAM_SYNCH_IN_PROG, + REASON_ROAM_HANDOFF_DONE); + + status = wlan_cm_roam_state_change(pdev, + vdev_id, + WLAN_MLO_ROAM_SYNCH_IN_PROG, + REASON_ROAM_HANDOFF_DONE); + return status; + } + + /* + * Get old bssid as, new AP is not updated yet and do cleanup + * for old bssid. + */ + wlan_mlme_get_bssid_vdev_id(pdev, vdev_id, + &connected_bssid); + + /* Update the DLM that the previous profile has disconnected */ + wlan_dlm_update_bssid_connect_params(pdev, + connected_bssid, + DLM_AP_DISCONNECTED); + + if (IS_ROAM_REASON_STA_KICKOUT(sync_ind->roam_reason)) { + struct reject_ap_info ap_info; + + score_config = &mlme_psoc_obj->psoc_cfg.score_config; + good_rssi_cfg = score_config->rssi_score.good_rssi_threshold; + if (good_rssi_cfg > sync_ind->rssi) { + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + ap_info.bssid = connected_bssid; + ap_info.reject_ap_type = DRIVER_AVOID_TYPE; + ap_info.reject_reason = REASON_STA_KICKOUT; + ap_info.source = ADDED_BY_DRIVER; + wlan_dlm_add_bssid_to_reject_list(pdev, &ap_info); + } + } + + cm_update_scan_mlme_on_roam(vdev, &connected_bssid, + SCAN_ENTRY_CON_STATE_NONE); + + if (!MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) + status = wlan_cm_roam_state_change(pdev, + vdev_id, + WLAN_ROAM_SYNCH_IN_PROG, + REASON_ROAM_HANDOFF_DONE); + + mlme_init_twt_context(wlan_pdev_get_psoc(pdev), &connected_bssid, + TWT_ALL_SESSIONS_DIALOG_ID); + + mlme_cm_osif_roam_sync_ind(vdev); + + return status; +} + +void +cm_update_scan_mlme_on_roam(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *connected_bssid, + enum scan_entry_connection_state state) +{ + struct wlan_objmgr_pdev *pdev; + struct bss_info bss_info; + struct mlme_info mlme; + struct wlan_channel *chan; + QDF_STATUS status; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("failed to find pdev"); + return; + } + + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + mlme_err("failed to get active channel"); + return; + } + + status = wlan_vdev_mlme_get_ssid(vdev, bss_info.ssid.ssid, + &bss_info.ssid.length); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("failed to get ssid"); + return; + } + + mlme.assoc_state = state; + qdf_copy_macaddr(&bss_info.bssid, connected_bssid); + + bss_info.freq = chan->ch_freq; + + wlan_scan_update_mlme_by_bssinfo(pdev, &bss_info, &mlme); +} + +#ifdef WLAN_FEATURE_FILS_SK +static QDF_STATUS +cm_fill_fils_ie(struct wlan_connect_rsp_ies *connect_ies, + struct roam_offload_synch_ind *roam_synch_data) +{ + struct fils_connect_rsp_params *fils_ie; + + if (!roam_synch_data->hlp_data_len) + return QDF_STATUS_SUCCESS; + + connect_ies->fils_ie = qdf_mem_malloc(sizeof(*fils_ie)); + if (!connect_ies->fils_ie) + return QDF_STATUS_E_NOMEM; + + fils_ie = connect_ies->fils_ie; + cds_copy_hlp_info(&roam_synch_data->dst_mac, + &roam_synch_data->src_mac, + roam_synch_data->hlp_data_len, + roam_synch_data->hlp_data, + &fils_ie->dst_mac, + &fils_ie->src_mac, + &fils_ie->hlp_data_len, + fils_ie->hlp_data); + + fils_ie->fils_seq_num = roam_synch_data->next_erp_seq_num; + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +cm_fill_fils_ie(struct wlan_connect_rsp_ies *connect_ies, + struct roam_offload_synch_ind *roam_synch_data) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS +cm_populate_connect_ies(struct roam_offload_synch_ind *roam_synch_data, + struct cm_vdev_join_rsp *rsp) +{ + struct wlan_connect_rsp_ies *connect_ies; + uint8_t *bcn_probe_rsp_ptr; + uint8_t *reassoc_rsp_ptr; + uint8_t *reassoc_req_ptr; + + connect_ies = &rsp->connect_rsp.connect_ies; + + /* Beacon/Probe Rsp frame */ + if (roam_synch_data->beacon_probe_resp_length) { + connect_ies->bcn_probe_rsp.len = + roam_synch_data->beacon_probe_resp_length; + bcn_probe_rsp_ptr = (uint8_t *)roam_synch_data + + roam_synch_data->beacon_probe_resp_offset; + + connect_ies->bcn_probe_rsp.ptr = + qdf_mem_malloc(connect_ies->bcn_probe_rsp.len); + if (!connect_ies->bcn_probe_rsp.ptr) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(connect_ies->bcn_probe_rsp.ptr, bcn_probe_rsp_ptr, + connect_ies->bcn_probe_rsp.len); + } + + /* Beacon/Probe Rsp frame */ + if (roam_synch_data->link_beacon_probe_resp_length) { + connect_ies->link_bcn_probe_rsp.len = + roam_synch_data->link_beacon_probe_resp_length; + bcn_probe_rsp_ptr = (uint8_t *)roam_synch_data + + roam_synch_data->link_beacon_probe_resp_offset; + + connect_ies->link_bcn_probe_rsp.ptr = + qdf_mem_malloc(connect_ies->link_bcn_probe_rsp.len); + if (!connect_ies->link_bcn_probe_rsp.ptr) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(connect_ies->link_bcn_probe_rsp.ptr, + bcn_probe_rsp_ptr, + connect_ies->link_bcn_probe_rsp.len); + } + + /* ReAssoc Rsp IE data */ + if (roam_synch_data->reassoc_resp_length > + sizeof(struct wlan_frame_hdr)) { + connect_ies->assoc_rsp.len = + roam_synch_data->reassoc_resp_length - + sizeof(struct wlan_frame_hdr); + reassoc_rsp_ptr = (uint8_t *)roam_synch_data + + roam_synch_data->reassoc_resp_offset + + sizeof(struct wlan_frame_hdr); + connect_ies->assoc_rsp.ptr = + qdf_mem_malloc(connect_ies->assoc_rsp.len); + if (!connect_ies->assoc_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(connect_ies->assoc_rsp.ptr, reassoc_rsp_ptr, + connect_ies->assoc_rsp.len); + } + + /* ReAssoc Req IE data */ + if (roam_synch_data->reassoc_req_length > + sizeof(struct wlan_frame_hdr)) { + connect_ies->assoc_req.len = + roam_synch_data->reassoc_req_length - + sizeof(struct wlan_frame_hdr); + reassoc_req_ptr = (uint8_t *)roam_synch_data + + roam_synch_data->reassoc_req_offset + + sizeof(struct wlan_frame_hdr); + connect_ies->assoc_req.ptr = + qdf_mem_malloc(connect_ies->assoc_req.len); + if (!connect_ies->assoc_req.ptr) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(connect_ies->assoc_req.ptr, reassoc_req_ptr, + connect_ies->assoc_req.len); + } + rsp->connect_rsp.is_assoc = roam_synch_data->is_assoc; + + cm_fill_fils_ie(connect_ies, roam_synch_data); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +static QDF_STATUS +cm_copy_tspec_ie(struct cm_vdev_join_rsp *rsp, + struct roam_offload_synch_ind *roam_synch_data) +{ + if (roam_synch_data->tspec_len) { + rsp->tspec_ie.len = roam_synch_data->tspec_len; + rsp->tspec_ie.ptr = + qdf_mem_malloc(rsp->tspec_ie.len); + if (!rsp->tspec_ie.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(rsp->tspec_ie.ptr, + roam_synch_data->ric_tspec_data + + roam_synch_data->ric_data_len, + rsp->tspec_ie.len); + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +cm_copy_tspec_ie(struct cm_vdev_join_rsp *rsp, + struct roam_offload_synch_ind *roam_synch_data) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +static void +cm_fils_update_erp_seq_num(struct wlan_objmgr_vdev *vdev, + uint16_t next_erp_seq_num, + wlan_cm_id cm_id) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_fils_connection_info *fils_info; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "Failed to find pdev", + CM_PREFIX_REF(vdev_id, cm_id)); + return; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "Failed to find psoc", + CM_PREFIX_REF(vdev_id, cm_id)); + return; + } + + fils_info = wlan_cm_get_fils_connection_info(psoc, vdev_id); + if (!fils_info) + return; + + /* + * update the erp sequence number to the vdev level + * FILS cache. This will be sent in the next RSO + * command. + */ + fils_info->erp_sequence_number = next_erp_seq_num; +} +#else +static inline void +cm_fils_update_erp_seq_num(struct wlan_objmgr_vdev *vdev, + uint16_t next_erp_seq_num, wlan_cm_id cm_id) +{} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static void +cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *roam_synch_data) +{ + struct wlan_channel channel = {0}; + struct ml_setup_link_param *ml_link; + uint8_t i; + + if (!is_multi_link_roam(roam_synch_data)) + return; + + mlo_mgr_reset_ap_link_info(vdev); + for (i = 0; i < roam_synch_data->num_setup_links; i++) { + ml_link = &roam_synch_data->ml_link[i]; + + qdf_mem_zero(&channel, sizeof(channel)); + + channel.ch_freq = ml_link->channel.mhz; + channel.ch_cfreq1 = ml_link->channel.band_center_freq1; + channel.ch_cfreq2 = ml_link->channel.band_center_freq2; + + /* + * Update Link switch context for each vdev with roamed AP link + * address and self link address for each vdev + */ + mlo_mgr_roam_update_ap_link_info(vdev, ml_link, &channel); + } +} + +static QDF_STATUS +cm_fill_bssid_freq_info(uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch_data, + struct cm_vdev_join_rsp *rsp) +{ + uint8_t i; + struct ml_setup_link_param *ml_link; + + /* The @bssid field in roam synch indication will + * contain MLD address in case of roaming to ML + * candidate or else legacy MAC address for non-ML + * roaming. + */ + if (is_multi_link_roam(roam_synch_data)) + qdf_copy_macaddr(&rsp->connect_rsp.mld_addr, + &roam_synch_data->bssid); + else + qdf_zero_macaddr(&rsp->connect_rsp.mld_addr); + + for (i = 0; i < roam_synch_data->num_setup_links; i++) { + ml_link = &roam_synch_data->ml_link[i]; + if (vdev_id == ml_link->vdev_id) { + qdf_copy_macaddr(&rsp->connect_rsp.bssid, + &ml_link->link_addr); + rsp->connect_rsp.freq = ml_link->channel.mhz; + + return QDF_STATUS_SUCCESS; + } + } + + qdf_copy_macaddr(&rsp->connect_rsp.bssid, &roam_synch_data->bssid); + rsp->connect_rsp.freq = roam_synch_data->chan_freq; + + return QDF_STATUS_SUCCESS; +} + +static void +cm_mlo_roam_copy_partner_info(struct wlan_cm_connect_resp *connect_rsp, + struct roam_offload_synch_ind *roam_synch_data) +{ + mlo_roam_copy_partner_info(&connect_rsp->ml_parnter_info, + roam_synch_data, WLAN_INVALID_VDEV_ID, + true); +} +#else +static inline void +cm_roam_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *roam_synch_data) +{} +static QDF_STATUS +cm_fill_bssid_freq_info(uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch_data, + struct cm_vdev_join_rsp *rsp) +{ + qdf_copy_macaddr(&rsp->connect_rsp.bssid, &roam_synch_data->bssid); + rsp->connect_rsp.freq = roam_synch_data->chan_freq; + + return QDF_STATUS_SUCCESS; +} + +static void +cm_mlo_roam_copy_partner_info(struct wlan_cm_connect_resp *connect_rsp, + struct roam_offload_synch_ind *roam_synch_data) +{ +} +#endif + +static void +cm_update_assoc_btm_cap(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_rsp *rsp) +{ + struct wlan_connect_rsp_ies *connect_ies; + const uint8_t *ext_cap_ie; + struct s_ext_cap *extcap; + uint8_t offset; + + connect_ies = &rsp->connect_rsp.connect_ies; + /* + * Retain the btm cap from initial assoc if + * there is no assoc request + */ + if (!connect_ies->assoc_req.ptr || + !connect_ies->assoc_req.len) + return; + + if (rsp->connect_rsp.is_assoc) + offset = WLAN_ASSOC_REQ_IES_OFFSET; + else + offset = WLAN_REASSOC_REQ_IES_OFFSET; + + ext_cap_ie = + wlan_get_ie_ptr_from_eid(WLAN_ELEMID_XCAPS, + connect_ies->assoc_req.ptr + offset, + connect_ies->assoc_req.len - offset); + + if (!ext_cap_ie) { + mlme_debug("Ext cap is not present, disable btm"); + wlan_cm_set_assoc_btm_cap(vdev, false); + return; + } + extcap = (struct s_ext_cap *)&ext_cap_ie[2]; + wlan_cm_set_assoc_btm_cap(vdev, extcap->bss_transition); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static inline void +cm_fill_num_roam_links_info(struct wlan_roam_sync_info *roam_info, + struct roam_offload_synch_ind *roam_synch_ind) +{ + roam_info->num_setup_links = roam_synch_ind->num_setup_links; +} +#else +static inline void +cm_fill_num_roam_links_info(struct wlan_roam_sync_info *roam_info, + struct roam_offload_synch_ind *roam_synch_ind) +{ +} +#endif + +static QDF_STATUS +cm_fill_roam_info(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *roam_synch_data, + struct cm_vdev_join_rsp *rsp, wlan_cm_id cm_id) +{ + struct wlan_roam_sync_info *roaming_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + rsp->connect_rsp.roaming_info = qdf_mem_malloc(sizeof(*roaming_info)); + if (!rsp->connect_rsp.roaming_info) + return QDF_STATUS_E_NOMEM; + + rsp->connect_rsp.vdev_id = wlan_vdev_get_id(vdev); + status = cm_fill_bssid_freq_info(wlan_vdev_get_id(vdev), + roam_synch_data, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "Failed to get bssid and freq", + CM_PREFIX_REF(rsp->connect_rsp.vdev_id, cm_id)); + return QDF_STATUS_E_FAILURE; + } + + if (!util_scan_is_null_ssid(&roam_synch_data->ssid)) + wlan_vdev_mlme_set_ssid(vdev, + roam_synch_data->ssid.ssid, + roam_synch_data->ssid.length); + + status = wlan_vdev_mlme_get_ssid(vdev, + rsp->connect_rsp.ssid.ssid, + &rsp->connect_rsp.ssid.length); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "Failed to get ssid", + CM_PREFIX_REF(rsp->connect_rsp.vdev_id, cm_id)); + return QDF_STATUS_E_FAILURE; + } + + rsp->connect_rsp.is_reassoc = true; + rsp->connect_rsp.connect_status = QDF_STATUS_SUCCESS; + rsp->connect_rsp.cm_id = cm_id; + rsp->nss = roam_synch_data->nss; + + if (roam_synch_data->ric_data_len) { + rsp->ric_resp_ie.len = roam_synch_data->ric_data_len; + rsp->ric_resp_ie.ptr = + qdf_mem_malloc(rsp->ric_resp_ie.len); + if (!rsp->ric_resp_ie.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(rsp->ric_resp_ie.ptr, + roam_synch_data->ric_tspec_data, + rsp->ric_resp_ie.len); + } + cm_copy_tspec_ie(rsp, roam_synch_data); + + status = cm_populate_connect_ies(roam_synch_data, rsp); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + roaming_info = rsp->connect_rsp.roaming_info; + roaming_info->auth_status = roam_synch_data->auth_status; + cm_fill_num_roam_links_info(roaming_info, roam_synch_data); + roaming_info->kck_len = roam_synch_data->kck_len; + if (roaming_info->kck_len) + qdf_mem_copy(roaming_info->kck, roam_synch_data->kck, + roam_synch_data->kck_len); + roaming_info->kek_len = roam_synch_data->kek_len; + if (roaming_info->kek_len) + qdf_mem_copy(roaming_info->kek, roam_synch_data->kek, + roam_synch_data->kek_len); + qdf_mem_copy(roaming_info->replay_ctr, roam_synch_data->replay_ctr, + REPLAY_CTR_LEN); + roaming_info->roam_reason = + roam_synch_data->roam_reason & ROAM_REASON_MASK; + roaming_info->subnet_change_status = + CM_GET_SUBNET_STATUS(roam_synch_data->roam_reason); + roaming_info->pmk_len = roam_synch_data->pmk_len; + if (roaming_info->pmk_len) + qdf_mem_copy(roaming_info->pmk, roam_synch_data->pmk, + roaming_info->pmk_len); + + qdf_mem_copy(roaming_info->pmkid, roam_synch_data->pmkid, + PMKID_LEN); + roaming_info->update_erp_next_seq_num = + roam_synch_data->update_erp_next_seq_num; + roaming_info->next_erp_seq_num = roam_synch_data->next_erp_seq_num; + + cm_fils_update_erp_seq_num(vdev, roaming_info->next_erp_seq_num, cm_id); + cm_update_assoc_btm_cap(vdev, rsp); + + return status; +} + +static QDF_STATUS cm_process_roam_keys(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_rsp *rsp, + wlan_cm_id cm_id) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_roam_sync_info *roaming_info; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct cm_roam_values_copy config; + uint8_t mdie_present; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int32_t akm; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "Failed to find pdev", + CM_PREFIX_REF(vdev_id, cm_id)); + status = QDF_STATUS_E_FAILURE; + goto end; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "Failed to find psoc", + CM_PREFIX_REF(vdev_id, cm_id)); + status = QDF_STATUS_E_FAILURE; + goto end; + } + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err(CM_PREFIX_FMT "Failed to mlme psoc obj", + CM_PREFIX_REF(vdev_id, cm_id)); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + roaming_info = rsp->connect_rsp.roaming_info; + akm = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + + /* + * Encryption keys for new connection are obtained as follows: + * auth_status = CSR_ROAM_AUTH_STATUS_AUTHENTICATED + * Open - No keys required. + * Static WEP - Firmware copies keys from old AP to new AP. + * Fast roaming authentications e.g. PSK, FT, CCKM - firmware + * supplicant obtains them through 4-way handshake. + * + * auth_status = CSR_ROAM_AUTH_STATUS_CONNECTED + * All other authentications - Host supplicant performs EAPOL + * with AP after this point and sends new keys to the driver. + * Driver starts wait_for_key timer for that purpose. + * Allow cm_lookup_pmkid_using_bssid() if akm is SAE/OWE since + * SAE/OWE roaming uses hybrid model and eapol is offloaded to + * supplicant unlike in WPA2 802.1x case, after 8 way handshake + * the __wlan_hdd_cfg80211_keymgmt_set_key ->sme_roam_set_psk_pmk() + * will get called after roam synch complete to update the + * session->psk_pmk, but in SAE/OWE roaming this sequence is not + * present and set_pmksa will come before roam synch indication & + * eapol. So the session->psk_pmk will be stale in PMKSA cached + * SAE/OWE roaming case. + */ + + if (roaming_info->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) { + struct wlan_crypto_pmksa *pmkid_cache, *pmksa; + + cm_csr_set_ss_none(vdev_id); + /* + * If authStatus is AUTHENTICATED, then we have done successful + * 4 way handshake in FW using the cached PMKID. + * However, the session->psk_pmk has the PMK of the older AP + * as set_key is not received from supplicant. + * When any RSO command is sent for the current AP, the older + * AP's PMK is sent to the FW which leads to incorrect PMK and + * leads to 4 way handshake failure when roaming happens to + * this AP again. + * Check if a PMK cache exists for the roamed AP and update + * it into the session pmk. + */ + pmkid_cache = qdf_mem_malloc(sizeof(*pmkid_cache)); + if (!pmkid_cache) { + status = QDF_STATUS_E_NOMEM; + mlme_err(CM_PREFIX_FMT "Mem alloc failed", + CM_PREFIX_REF(vdev_id, cm_id)); + goto end; + } + wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, &pmkid_cache->bssid); + mlme_debug(CM_PREFIX_FMT "Trying to find PMKID for " + QDF_MAC_ADDR_FMT " AKM Type:%d", + CM_PREFIX_REF(vdev_id, cm_id), + QDF_MAC_ADDR_REF(pmkid_cache->bssid.bytes), akm); + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + MOBILITY_DOMAIN, &config); + mdie_present = config.bool_value; + + if (cm_lookup_pmkid_using_bssid(psoc, + vdev_id, + pmkid_cache)) { + /* + * Consider two APs: AP1, AP2 + * Both APs configured with EAP 802.1x security mode + * and OKC is enabled in both APs by default. Initially + * DUT successfully associated with AP1, and generated + * PMK1 by performing full EAP and added an entry for + * AP1 in pmk table. At this stage, pmk table has only + * one entry for PMK1 (1. AP1-->PMK1). Now DUT try to + * roam to AP2 using PMK1 (as OKC is enabled) but + * session timeout happens on AP2 just before 4 way + * handshake completion in FW. At this point of time + * DUT not in authenticated state. Due to this DUT + * performs full EAP with AP2 and generates PMK2. As + * there is no previous entry of AP2 (AP2-->PMK1) in pmk + * table. When host gets pmk delete command for BSSID of + * AP2, the BSSID match fails. Hence host will not + * delete pmk entry of AP1 as well. + * At this point of time, the PMK table has two entry + * 1. AP1-->PMK1 and 2. AP2 --> PMK2. + * Ideally, if OKC is enabled then whenever timeout + * occurs in a mobility domain, then the driver should + * clear all APs cache entries related to that domain + * but as the BSSID doesn't exist yet in the driver + * cache there is no way of clearing the cache entries, + * without disturbing the legacy roaming. + * Now security profile for both APs changed to FT-RSN. + * DUT first disassociate with AP2 and successfully + * associated with AP2 and perform full EAP and + * generates PMK3. DUT first deletes PMK entry for AP2 + * and then adds a new entry for AP2. + * At this point of time pmk table has two entry + * AP2--> PMK3 and AP1-->PMK1. Now DUT roamed to AP1 + * using PMK3 but sends stale entry of AP1 (PMK1) to + * fw via RSO command. This override PMK for both APs + * with PMK1 (as FW uses mlme session PMK for both APs + * in case of FT roaming) and next time when FW try to + * roam to AP2 using PMK1, AP2 rejects PMK1 (As AP2 is + * expecting PMK3) and initiates full EAP with AP2, + * which is wrong. + * To address this issue update pmk table entry for + * roamed AP1 with pmk3 value comes to host via roam + * sync indication event. By this host override stale + * entry (if any) with the latest valid pmk for that AP + * at a point of time. + */ + if (roaming_info->pmk_len) { + pmksa = qdf_mem_malloc(sizeof(*pmksa)); + if (!pmksa) { + status = QDF_STATUS_E_NOMEM; + qdf_mem_zero(pmkid_cache, + sizeof(*pmkid_cache)); + qdf_mem_free(pmkid_cache); + goto end; + } + + /* + * This pmksa buffer is to update the + * crypto table + */ + wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, + &pmksa->bssid); + qdf_mem_copy(pmksa->pmkid, + roaming_info->pmkid, PMKID_LEN); + qdf_mem_copy(pmksa->pmk, roaming_info->pmk, + roaming_info->pmk_len); + pmksa->pmk_len = roaming_info->pmk_len; + status = wlan_crypto_set_del_pmksa(vdev, + pmksa, true); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_zero(pmksa, sizeof(*pmksa)); + qdf_mem_free(pmksa); + } + + /* update the pmkid_cache buffer to + * update the global session pmk + */ + qdf_mem_copy(pmkid_cache->pmkid, + roaming_info->pmkid, PMKID_LEN); + qdf_mem_copy(pmkid_cache->pmk, + roaming_info->pmk, + roaming_info->pmk_len); + pmkid_cache->pmk_len = roaming_info->pmk_len; + } else { + mlme_debug("PMK not received from fw"); + } + + wlan_cm_set_psk_pmk(pdev, vdev_id, + pmkid_cache->pmk, + pmkid_cache->pmk_len); + mlme_debug(CM_PREFIX_FMT "pmkid found for " + QDF_MAC_ADDR_FMT " len %d", + CM_PREFIX_REF(vdev_id, cm_id), + QDF_MAC_ADDR_REF(pmkid_cache->bssid.bytes), + pmkid_cache->pmk_len); + } else { + mlme_debug(CM_PREFIX_FMT "PMKID Not found in cache for " + QDF_MAC_ADDR_FMT, + CM_PREFIX_REF(vdev_id, cm_id), + QDF_MAC_ADDR_REF(pmkid_cache->bssid.bytes)); + /* + * In FT roam when the CSR lookup fails then the PMK + * details from the roam sync indication will be + * updated to Session/PMK cache. This will result in + * having multiple PMK cache entries for the same MDID, + * So do not add the PMKSA cache entry in all the + * FT-Roam cases. + */ + if (!cm_is_auth_type_11r(mlme_obj, vdev, + mdie_present) && + roaming_info->pmk_len) { + /* + * This pmksa buffer is to update the + * crypto table + */ + pmksa = qdf_mem_malloc(sizeof(*pmksa)); + if (!pmksa) { + status = QDF_STATUS_E_NOMEM; + qdf_mem_zero(pmkid_cache, + sizeof(*pmkid_cache)); + qdf_mem_free(pmkid_cache); + goto end; + } + wlan_cm_set_psk_pmk(pdev, vdev_id, + roaming_info->pmk, + roaming_info->pmk_len); + wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, + &pmksa->bssid); + qdf_mem_copy(pmksa->pmkid, + roaming_info->pmkid, PMKID_LEN); + qdf_mem_copy(pmksa->pmk, + roaming_info->pmk, + roaming_info->pmk_len); + pmksa->pmk_len = roaming_info->pmk_len; + + status = wlan_crypto_set_del_pmksa(vdev, + pmksa, + true); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_zero(pmksa, sizeof(*pmksa)); + qdf_mem_free(pmksa); + } + } + } + qdf_mem_zero(pmkid_cache, sizeof(*pmkid_cache)); + qdf_mem_free(pmkid_cache); + } + + if (roaming_info->auth_status != ROAM_AUTH_STATUS_AUTHENTICATED) + cm_update_wait_for_key_timer(vdev, vdev_id, + WAIT_FOR_KEY_TIMEOUT_PERIOD); +end: + return status; +} + +static void +cm_update_scan_db_on_roam_success(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *resp, + struct roam_offload_synch_ind *roam_synch_ind, + wlan_cm_id cm_id) +{ + struct cnx_mgr *cm_ctx; + qdf_freq_t frame_freq; + struct wlan_connect_rsp_ies *ies = &resp->connect_ies; + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) + return; + + if (ies->link_bcn_probe_rsp.len) { + frame_freq = mlo_roam_get_link_freq_from_mac_addr( + roam_synch_ind, + wlan_mlme_get_src_addr_from_frame( + &ies->link_bcn_probe_rsp)); + cm_inform_bcn_probe(cm_ctx, + ies->link_bcn_probe_rsp.ptr, + ies->link_bcn_probe_rsp.len, + frame_freq, + roam_synch_ind->rssi, + cm_id); + } + + frame_freq = mlo_roam_get_link_freq_from_mac_addr( + roam_synch_ind, + wlan_mlme_get_src_addr_from_frame( + &ies->bcn_probe_rsp)); + /* + * Firmware might have roamed to a link but got ML probe + * response from the other link. Then the link freq is not + * present in roam link info and it returns 0. No need to add + * the original probe rsp in such cases as roam sync indication + * handling would add it to scan db. Add the entry to scan + * db only if valid link freq is found. + */ + if (frame_freq) + cm_inform_bcn_probe(cm_ctx, + ies->bcn_probe_rsp.ptr, + ies->bcn_probe_rsp.len, + frame_freq, + roam_synch_ind->rssi, + cm_id); + + cm_update_scan_mlme_on_roam(vdev, &resp->bssid, + SCAN_ENTRY_CON_STATE_ASSOC); + + cm_standby_link_update_mlme_by_bssid(vdev, SCAN_ENTRY_CON_STATE_ASSOC, + resp->ssid); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +cm_roam_ml_clear_prev_ap_keys(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *ml_dev; + struct mlo_link_info *link_info; + uint8_t i; + + ml_dev = vdev->mlo_dev_ctx; + if (!ml_dev || !ml_dev->link_ctx) + return; + + link_info = &ml_dev->link_ctx->links_info[0]; + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { + if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) + continue; + + if (qdf_is_macaddr_zero(&link_info->link_addr)) + continue; + + wlan_crypto_free_key_by_link_id(wlan_vdev_get_psoc(vdev), + &link_info->link_addr, + link_info->link_id); + link_info++; + } +} +#else +static void +cm_roam_ml_clear_prev_ap_keys(struct wlan_objmgr_vdev *vdev) +{} +#endif + +QDF_STATUS +cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch_data) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct cnx_mgr *cm_ctx; + struct cm_roam_req *roam_req = NULL; + struct cm_vdev_join_rsp *rsp = NULL; + wlan_cm_id cm_id; + struct wlan_objmgr_pdev *pdev; + struct wlan_cm_connect_resp *connect_rsp; + bool eht_capab = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + status = QDF_STATUS_E_FAILURE; + goto rel_ref; + } + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) { + status = QDF_STATUS_E_FAILURE; + goto rel_ref; + } + + roam_req = cm_get_first_roam_command(vdev); + if (!roam_req) { + mlme_err("Failed to find roam req from list"); + cm_id = CM_ID_INVALID; + status = QDF_STATUS_E_FAILURE; + goto error; + } + wlan_rec_conn_info(vdev_id, DEBUG_CONN_ROAMING, + roam_synch_data->bssid.bytes, 0, 0); + + cm_roam_update_mlo_mgr_info(vdev, roam_synch_data); + cm_roam_ml_clear_prev_ap_keys(vdev); + + cm_id = roam_req->cm_id; + rsp = qdf_mem_malloc(sizeof(struct cm_vdev_join_rsp)); + if (!rsp) { + status = QDF_STATUS_E_NOMEM; + goto error; + } + status = cm_fill_roam_info(vdev, roam_synch_data, rsp, cm_id); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT " fail to prepare rsp", + CM_PREFIX_REF(vdev_id, cm_id)); + goto error; + } + + connect_rsp = &rsp->connect_rsp; + cm_update_scan_db_on_roam_success(vdev, connect_rsp, + roam_synch_data, cm_id); + + status = cm_csr_connect_rsp(vdev, rsp); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Roam sync propagation failed, abort roaming"); + goto error; + } + + cm_process_roam_keys(vdev, rsp, cm_id); + /* + * Re-enable the disabled link on roaming as decision + * will be taken again to disable the link on roam sync completion. + */ + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + policy_mgr_move_vdev_from_disabled_to_connection_tbl(psoc, + vdev_id); + cm_mlo_roam_copy_partner_info(connect_rsp, roam_synch_data); + mlo_roam_init_cu_bpcc(vdev, roam_synch_data); + mlo_roam_set_link_id(vdev, roam_synch_data); + + /** + * Don't send roam_sync complete for MLO link vdevs. + * Send only for legacy STA/MLO STA vdev. + */ + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { + cm_inform_dlm_connect_complete(cm_ctx->vdev, connect_rsp); + wlan_p2p_status_connect(vdev); + + if (!cm_csr_is_ss_wait_for_key(vdev_id)) { + mlme_debug(CM_PREFIX_FMT "WLAN link up with AP = " + QDF_MAC_ADDR_FMT, + CM_PREFIX_REF(vdev_id, cm_id), + QDF_MAC_ADDR_REF(connect_rsp->bssid.bytes)); + cm_roam_start_init_on_connect(pdev, vdev_id); + } + wlan_cm_tgt_send_roam_sync_complete_cmd(psoc, vdev_id); + mlo_roam_update_connected_links(vdev, connect_rsp); + mlo_set_single_link_ml_roaming(psoc, vdev_id, + false); + } + cm_connect_info(vdev, true, &connect_rsp->bssid, &connect_rsp->ssid, + connect_rsp->freq); + wlan_tdls_notify_sta_connect(vdev_id, + mlme_get_tdls_chan_switch_prohibited(vdev), + mlme_get_tdls_prohibited(vdev), vdev); + + wlan_cm_update_scan_mlme_info(vdev, connect_rsp); + cm_update_associated_ch_info(vdev, true); + + status = cm_sm_deliver_event_sync(cm_ctx, WLAN_CM_SM_EV_ROAM_DONE, + sizeof(*roam_synch_data), + roam_synch_data); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT " fail to post WLAN_CM_SM_EV_ROAM_DONE", + CM_PREFIX_REF(vdev_id, cm_id)); + goto error; + } + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + mlo_roam_update_connected_links(vdev, connect_rsp); + mlme_cm_osif_connect_complete(vdev, connect_rsp); + mlme_cm_osif_roam_complete(vdev); + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + mlo_roam_copy_reassoc_rsp(vdev, connect_rsp); + + mlme_debug(CM_PREFIX_FMT, CM_PREFIX_REF(vdev_id, cm_id)); + cm_remove_cmd(cm_ctx, &cm_id); + + wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); + if (eht_capab) { + status = policy_mgr_current_connections_update( + psoc, vdev_id, + connect_rsp->freq, + POLICY_MGR_UPDATE_REASON_LFR3_ROAM, + POLICY_MGR_DEF_REQ_ID); + if (status == QDF_STATUS_E_NOSUPPORT) + status = QDF_STATUS_SUCCESS; + else if (status == QDF_STATUS_E_FAILURE) + mlme_err("Failed to take next action LFR3_ROAM"); + } + +error: + if (rsp) + wlan_cm_free_connect_rsp(rsp); + + if (QDF_IS_STATUS_ERROR(status)) + mlo_update_connected_links(vdev, 0); +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +cm_get_and_disable_link_from_roam_ind(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct roam_offload_synch_ind *synch_data) +{ + uint8_t i; + struct wlan_objmgr_vdev *vdev; + + for (i = 0; i < synch_data->num_setup_links; i++) { + if (synch_data->ml_link[i].vdev_id == vdev_id && + synch_data->ml_link[i].flags & CM_ROAM_LINK_FLAG_DISABLE) { + mlme_info("Vdev %d: link id %d flags 0x%x, indicate link disable", + vdev_id, synch_data->ml_link[i].link_id, + synch_data->ml_link[i].flags); + policy_mgr_move_vdev_from_connection_to_disabled_tbl( + psoc, vdev_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_debug("no vdev for id %d", vdev_id); + break; + } + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, 1 << synch_data->ml_link[i].link_id, + LINK_ADD); + ml_nlink_init_concurrency_link_request(psoc, vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + break; + } + } +} +#else +static inline void +cm_get_and_disable_link_from_roam_ind(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct roam_offload_synch_ind *synch_data) +{} +#endif +QDF_STATUS cm_fw_roam_complete(struct cnx_mgr *cm_ctx, void *data) +{ + struct roam_offload_synch_ind *roam_synch_data; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id; + + roam_synch_data = (struct roam_offload_synch_ind *)data; + vdev_id = wlan_vdev_get_id(cm_ctx->vdev); + + pdev = wlan_vdev_get_pdev(cm_ctx->vdev); + if (!pdev) { + mlme_err("Failed to find pdev"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!pdev) { + mlme_err("Failed to find psoc"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Handle one race condition that if candidate is already + *selected & FW has gone ahead with roaming or about to go + * ahead when set_band comes, it will be complicated for FW + * to stop the current roaming. Instead, host will check the + * roam sync to make sure the new AP is not on disable freq + * or disconnect the AP. + */ + if (wlan_reg_is_disable_for_pwrmode(pdev, roam_synch_data->chan_freq, + REG_CURRENT_PWR_MODE)) { + mlo_disconnect(cm_ctx->vdev, CM_ROAM_DISCONNECT, + REASON_OPER_CHANNEL_BAND_CHANGE, NULL); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* + * Following operations need to be done once roam sync + * completion is sent to FW, hence called here: + * 1) Firmware has already updated DBS policy. Update connection + * table in the host driver. + * 2) Force SCC switch if needed + */ + /* first update connection info from wma interface */ + status = policy_mgr_update_connection_info(psoc, vdev_id); + if (status == QDF_STATUS_NOT_INITIALIZED) + policy_mgr_incr_active_session(psoc, QDF_STA_MODE, vdev_id); + + /* Check if FW as indicated this link as disabled */ + cm_get_and_disable_link_from_roam_ind(psoc, vdev_id, roam_synch_data); + + /* then update remaining parameters from roam sync ctx */ + if (roam_synch_data->hw_mode_trans_present) + policy_mgr_hw_mode_transition_cb( + roam_synch_data->hw_mode_trans_ind.old_hw_mode_index, + roam_synch_data->hw_mode_trans_ind.new_hw_mode_index, + roam_synch_data->hw_mode_trans_ind.num_vdev_mac_entries, + roam_synch_data->hw_mode_trans_ind.vdev_mac_map, + 0, NULL, psoc); + ml_nlink_conn_change_notify( + psoc, vdev_id, + ml_nlink_roam_sync_completion_evt, NULL); + + if (roam_synch_data->pmk_len) { + mlme_debug("Received pmk in roam sync. Length: %d", + roam_synch_data->pmk_len); + cm_check_and_set_sae_single_pmk_cap(psoc, vdev_id, + roam_synch_data->pmk, + roam_synch_data->pmk_len); + } + + cm_csr_send_set_ie(cm_ctx->vdev); + + if (ucfg_pkt_capture_get_pktcap_mode(psoc)) + ucfg_pkt_capture_record_channel(cm_ctx->vdev); + + /* + * Firmware will take care of checking hi_scan rssi delta, take care of + * legacy -> legacy hi-rssi roam also if self mld roam supported. + */ + if (!wlan_cm_is_self_mld_roam_supported(psoc)) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(roam_synch_data->chan_freq)) { + wlan_cm_set_disable_hi_rssi(pdev, + vdev_id, false); + } else { + wlan_cm_set_disable_hi_rssi(pdev, + vdev_id, true); + mlme_debug("Disabling HI_RSSI, AP freq=%d rssi %d vdev id %d", + roam_synch_data->chan_freq, + roam_synch_data->rssi, vdev_id); + } + } + policy_mgr_check_n_start_opportunistic_timer(psoc); + + wlan_cm_handle_sta_sta_roaming_enablement(psoc, vdev_id); + + if (wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) { + status = wlan_cm_roam_state_change(pdev, + vdev_id, + WLAN_ROAM_DEINIT, + REASON_ROAM_HANDOFF_DONE); + } + + if (roam_synch_data->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED) + wlan_cm_roam_state_change(pdev, vdev_id, + WLAN_ROAM_RSO_ENABLED, + REASON_CONNECT); + else + /* + * STA is just in associated state here, RSO + * enable will be sent once EAP & EAPOL will be done by + * user-space and after set key response is received. + * + * When firmware roaming state is connected, EAP/EAPOL will be + * done at the supplicant. If EAP/EAPOL fails and supplicant + * sends disconnect, then the RSO state machine sends + * deinit directly to firmware without RSO stop with roam + * scan mode value 0. So to avoid this move state to RSO + * stop. + */ + wlan_cm_roam_state_change(pdev, vdev_id, + WLAN_ROAM_RSO_STOPPED, + REASON_DISCONNECTED); + policy_mgr_check_concurrent_intf_and_restart_sap(psoc, + wlan_util_vdev_mgr_get_acs_mode_for_vdev(cm_ctx->vdev)); +end: + return status; +} + +static QDF_STATUS +cm_disconnect_roam_invoke_fail(struct wlan_objmgr_vdev *vdev, + wlan_cm_id cm_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + bool nud_disconnect; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct rso_config *rso_cfg; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "psoc not found", + CM_PREFIX_REF(vdev_id, cm_id)); + return QDF_STATUS_E_INVAL; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_NULL_VALUE; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + mlme_err(CM_PREFIX_FMT "rso cfg not found", + CM_PREFIX_REF(vdev_id, cm_id)); + return QDF_STATUS_E_NULL_VALUE; + } + + nud_disconnect = mlme_obj->cfg.lfr.disconnect_on_nud_roam_invoke_fail; + mlme_debug(CM_PREFIX_FMT "disconnect on NUD %d, source %d forced roaming %d", + CM_PREFIX_REF(vdev_id, cm_id), + nud_disconnect, rso_cfg->roam_invoke_source, + rso_cfg->is_forced_roaming); + + /* + * If reassoc MAC from user space is broadcast MAC as: + * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0", + * user space invoked roaming candidate selection will base on firmware + * score algorithm, current connection will be kept if current AP has + * highest score. It is requirement from customer which can avoid + * ping-pong roaming. + */ + if (qdf_is_macaddr_broadcast(&rso_cfg->roam_invoke_bssid)) { + qdf_zero_macaddr(&rso_cfg->roam_invoke_bssid); + return status; + } + + if (rso_cfg->roam_invoke_source == CM_ROAMING_HOST || + (rso_cfg->roam_invoke_source == CM_ROAMING_NUD_FAILURE && + (nud_disconnect || rso_cfg->is_forced_roaming)) || + rso_cfg->roam_invoke_source == CM_ROAMING_LINK_REMOVAL) { + rso_cfg->roam_invoke_source = CM_SOURCE_INVALID; + if (rso_cfg->is_forced_roaming) + rso_cfg->is_forced_roaming = false; + status = mlo_disconnect(vdev, CM_ROAM_DISCONNECT, + REASON_USER_TRIGGERED_ROAM_FAILURE, + NULL); + } + + return status; +} + +QDF_STATUS cm_fw_roam_invoke_fail(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + wlan_cm_id cm_id = CM_ID_INVALID; + struct cnx_mgr *cm_ctx; + struct cm_roam_req *roam_req = NULL; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) { + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + roam_req = cm_get_first_roam_command(vdev); + if (roam_req) + cm_id = roam_req->cm_id; + + status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_INVOKE_FAIL, + sizeof(wlan_cm_id), &cm_id); + if (QDF_IS_STATUS_ERROR(status)) + cm_remove_cmd(cm_ctx, &cm_id); + + cm_disconnect_roam_invoke_fail(vdev, cm_id); +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return status; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +static void cm_ho_fail_diag_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(roam_connection, + host_event_wlan_status_payload_type); + qdf_mem_zero(&roam_connection, + sizeof(host_event_wlan_status_payload_type)); + + roam_connection.eventId = DIAG_WLAN_STATUS_DISCONNECT; + roam_connection.reason = DIAG_REASON_ROAM_HO_FAIL; + WLAN_HOST_DIAG_EVENT_REPORT(&roam_connection, EVENT_WLAN_STATUS_V2); +} +#else +static inline void cm_ho_fail_diag_event(void) {} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static bool +cm_ho_fail_is_avoid_list_candidate(struct wlan_objmgr_vdev *vdev, + struct cm_ho_fail_ind *ho_fail_ind) +{ + uint8_t link_info_iter = 0; + struct qdf_mac_addr peer_macaddr = {0}; + struct mlo_link_info *mlo_link_info; + uint32_t akm; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + wlan_vdev_get_bss_peer_mac(vdev, &peer_macaddr); + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (WLAN_CRYPTO_IS_WPA_WPA2(akm)) + return true; + + if (qdf_is_macaddr_equal(&peer_macaddr, &ho_fail_ind->bssid)) + return false; + else + return true; + } + + mlo_link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; + for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; + link_info_iter++, mlo_link_info++) { + if (qdf_is_macaddr_equal(&mlo_link_info->ap_link_addr, + &ho_fail_ind->bssid)) + return false; + } + + return true; +} +#else +static bool +cm_ho_fail_is_avoid_list_candidate(struct wlan_objmgr_vdev *vdev, + struct cm_ho_fail_ind *ho_fail_ind) +{ + struct qdf_mac_addr peer_macaddr = {0}; + uint32_t akm; + + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (WLAN_CRYPTO_IS_WPA_WPA2(akm)) + return true; + + wlan_vdev_get_bss_peer_mac(vdev, &peer_macaddr); + if (qdf_is_macaddr_equal(&peer_macaddr, &ho_fail_ind->bssid)) + return false; + else + return true; +} +#endif + +static QDF_STATUS cm_handle_ho_fail(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct cm_ho_fail_ind *ind = NULL; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct cnx_mgr *cm_ctx; + wlan_cm_id cm_id = CM_ID_INVALID; + struct reject_ap_info ap_info; + struct cm_roam_req *roam_req = NULL; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_objmgr_psoc *psoc; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + ind = msg->bodyptr; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(ind->psoc, ind->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev_id: %d : vdev not found", ind->vdev_id); + qdf_mem_free(ind); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev object is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err("psoc object is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("Failed to mlme psoc obj"); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) { + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + roam_req = cm_get_first_roam_command(vdev); + if (roam_req) { + mlme_debug("Roam req found, get cm id to remove it, before disconnect"); + cm_id = roam_req->cm_id; + } + /* CPU freq is boosted during roam sync to improve roam latency, + * upon HO failure reset that request to restore cpu freq back to normal + */ + mlme_cm_osif_perfd_reset_cpufreq(); + + cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_HO_FAIL, + sizeof(wlan_cm_id), &cm_id); + + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + if (cm_ho_fail_is_avoid_list_candidate(vdev, ind)) { + ap_info.bssid = ind->bssid; + ap_info.reject_ap_type = DRIVER_AVOID_TYPE; + ap_info.reject_reason = REASON_ROAM_HO_FAILURE; + ap_info.source = ADDED_BY_DRIVER; + wlan_dlm_add_bssid_to_reject_list(pdev, &ap_info); + } + + cm_ho_fail_diag_event(); + wlan_roam_debug_log(ind->vdev_id, + DEBUG_ROAM_SYNCH_FAIL, + DEBUG_INVALID_PEER_ID, NULL, NULL, 0, 0); + + status = mlo_disconnect(vdev, CM_MLME_DISCONNECT, + REASON_FW_TRIGGERED_ROAM_FAILURE, NULL); + + if (mlme_obj->cfg.gen.fatal_event_trigger) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_ROAM_HO_FAILURE, false, false); + + if (QDF_IS_STATUS_ERROR(status)) + cm_remove_cmd(cm_ctx, &cm_id); + +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + qdf_mem_free(ind); + + return QDF_STATUS_SUCCESS; +} + +void cm_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct qdf_mac_addr bssid) +{ + QDF_STATUS status; + struct scheduler_msg ind_msg = {0}; + struct cm_ho_fail_ind *ind = NULL; + + ind = qdf_mem_malloc(sizeof(*ind)); + if (!ind) + return; + + ind->vdev_id = vdev_id; + ind->psoc = psoc; + ind->bssid = bssid; + + ind_msg.bodyptr = ind; + ind_msg.callback = cm_handle_ho_fail; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &ind_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to post HO fail indication on vdev_id %d", + vdev_id); + qdf_mem_free(ind); + return; + } +} + +QDF_STATUS wlan_cm_free_roam_synch_frame_ind(struct rso_config *rso_cfg) +{ + struct roam_synch_frame_ind *frame_ind; + + if (!rso_cfg) + return QDF_STATUS_E_FAILURE; + + frame_ind = &rso_cfg->roam_sync_frame_ind; + + if (frame_ind->bcn_probe_rsp) { + qdf_mem_free(frame_ind->bcn_probe_rsp); + frame_ind->bcn_probe_rsp_len = 0; + frame_ind->bcn_probe_rsp = NULL; + } + if (frame_ind->link_bcn_probe_rsp) { + qdf_mem_free(frame_ind->link_bcn_probe_rsp); + frame_ind->link_bcn_probe_rsp_len = 0; + frame_ind->link_bcn_probe_rsp = NULL; + } + if (frame_ind->reassoc_req) { + qdf_mem_free(frame_ind->reassoc_req); + frame_ind->reassoc_req_len = 0; + frame_ind->reassoc_req = NULL; + } + if (frame_ind->reassoc_rsp) { + qdf_mem_free(frame_ind->reassoc_rsp); + frame_ind->reassoc_rsp_len = 0; + frame_ind->reassoc_rsp = NULL; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_i.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_i.h new file mode 100644 index 0000000000..d6c45f3442 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_i.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_i.h + * + * Implementation for the common roaming api interfaces. + */ + +#ifndef _WLAN_CM_ROAM_I_H_ +#define _WLAN_CM_ROAM_I_H_ + +#include "qdf_types.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "connection_mgr/core/src/wlan_cm_main.h" +#include "wlan_cm_roam_public_struct.h" + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * cm_add_fw_roam_dummy_ser_cb() - Add dummy blocking command + * @pdev: pdev pointer + * @cm_ctx: connection mgr context + * @cm_req: connect req + * + * This function adds dummy blocking command with high priority to avoid + * any other vdev command till roam is completed.Any NB operations will be + * blocked in serialization until roam logic completes execution. + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_add_fw_roam_dummy_ser_cb(struct wlan_objmgr_pdev *pdev, + struct cnx_mgr *cm_ctx, + struct cm_req *cm_req); +/** + * cm_fw_roam_start_req() - Post roam start req to CM SM + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This function posts roam start event change to connection manager + * state machine + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_fw_roam_start_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); +/** + * cm_fw_roam_abort_req() - Post roam abort req to CM SM + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This function posts roam abort event change to connection manager + * state machine + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_fw_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * cm_update_scan_mlme_on_roam() - update the scan mlme info + * on roam sync ind + * @vdev: Object manager vdev + * @connected_bssid: Bssid addr + * @state: scan entry state + * + * Return: void + */ +void +cm_update_scan_mlme_on_roam(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *connected_bssid, + enum scan_entry_connection_state state); + +/** + * cm_abort_fw_roam() - abort fw roaming + * + * @cm_ctx: Connection mgr context + * @cm_id: CM command id + * + * Return: qdf status + */ +QDF_STATUS cm_abort_fw_roam(struct cnx_mgr *cm_ctx, + wlan_cm_id cm_id); + +/** + * cm_fw_roam_sync_req() - Post roam sync to CM SM + * @psoc: psoc pointer + * @vdev_id: vdev id + * @event: Vdev mgr event + * @event_data_len: data size + * + * This function posts roam sync event change to connection manager + * state machine + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + void *event, uint32_t event_data_len); + +/** + * cm_fw_roam_sync_start_ind() - Handle roam sync req + * @vdev: Vdev objmgr + * @sync_ind: Roam sync ind + * + * This function handles roam sync event to connection manager + * state machine + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_fw_roam_sync_start_ind(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind); + +/** + * cm_fw_roam_sync_propagation() - Post roam sync propagation to CM SM + * @psoc: psoc pointer + * @vdev_id: vdev id + * @roam_synch_data: Roam sync data ptr + * + * This function posts roam sync propagation event change to connection manager + * state machine + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_fw_roam_sync_propagation(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch_data); + +/** + * cm_fw_ho_fail_req() - Post roam ho fail req to CM SM + * @psoc: psoc pointer + * @vdev_id: vdev id + * @bssid: bssid mac addr + * + * This function posts roam ho fail event change to + * connection manager state machine + * + * Return: void + */ +void cm_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct qdf_mac_addr bssid); + +/** + * cm_fw_roam_invoke_fail() - Post roam invoke fail to CM SM + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This function posts roam invoke fail event change to + * connection manager state machine + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_fw_roam_invoke_fail(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#else /*WLAN_FEATURE_ROAM_OFFLOAD */ +static inline +QDF_STATUS cm_fw_roam_invoke_fail(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#endif /* _WLAN_CM_ROAM_I_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c new file mode 100644 index 0000000000..e57021c5c1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c @@ -0,0 +1,7472 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_offload.c + * + * Implementation for the common roaming offload api interfaces. + */ + +#include "wlan_mlme_main.h" +#include "wlan_cm_roam_offload.h" +#include "wlan_cm_tgt_if_tx_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_crypto_global_api.h" +#include "wlan_psoc_mlme_api.h" +#include "pld_common.h" +#include "wlan_dlm_api.h" +#include "wlan_scan_api.h" +#include "wlan_vdev_mgr_ucfg_api.h" +#include "wlan_p2p_cfg_api.h" +#include "wlan_cm_vdev_api.h" +#include "cfg_nan_api.h" +#include "wlan_mlme_api.h" +#include "connection_mgr/core/src/wlan_cm_roam.h" +#include "connection_mgr/core/src/wlan_cm_main.h" +#include "connection_mgr/core/src/wlan_cm_sm.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_if_mgr_roam.h" +#include "wlan_roam_debug.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlme_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_vdev_mgr_api.h" + +#ifdef WLAN_FEATURE_SAE +#define CM_IS_FW_FT_SAE_SUPPORTED(fw_akm_bitmap) \ + (((fw_akm_bitmap) & (1 << AKM_FT_SAE)) ? true : false) + +#define CM_IS_FW_SAE_ROAM_SUPPORTED(fw_akm_bitmap) \ + (((fw_akm_bitmap) & (1 << AKM_SAE)) ? true : false) + +#define CM_IS_FW_SAE_EXT_ROAM_SUPPORTED(fw_akm_bitmap) \ + (((fw_akm_bitmap) & (1 << AKM_SAE_EXT)) ? true : false) +#else +#define CM_IS_FW_FT_SAE_SUPPORTED(fw_akm_bitmap) (false) + +#define CM_IS_FW_SAE_ROAM_SUPPORTED(fw_akm_bitmap) (false) + +#define CM_IS_FW_SAE_EXT_SUPPORTED(fw_akm_bitmap) (false) +#endif + +/** + * cm_roam_scan_bmiss_cnt() - set roam beacon miss count + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: roam beacon miss count parameters + * + * This function is used to set roam beacon miss count parameters + * + * Return: None + */ +static void +cm_roam_scan_bmiss_cnt(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_beacon_miss_cnt *params) +{ + uint8_t beacon_miss_count; + + params->vdev_id = vdev_id; + + wlan_mlme_get_roam_bmiss_first_bcnt(psoc, &beacon_miss_count); + params->roam_bmiss_first_bcnt = beacon_miss_count; + + wlan_mlme_get_roam_bmiss_final_bcnt(psoc, &beacon_miss_count); + params->roam_bmiss_final_bcnt = beacon_miss_count; +} + +/** + * cm_roam_scan_bmiss_timeout() - set connection bmiss timeout + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: roam bmiss timeout parameters + * + * This function is used to set roam conbmiss timeout parameters + * + * Return: None + */ +static void +cm_roam_scan_bmiss_timeout(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_bmiss_timeout *params) +{ + uint8_t bmiss_timeout; + + params->vdev_id = vdev_id; + + wlan_mlme_get_bmiss_timeout_on_wakeup(psoc, &bmiss_timeout); + params->bmiss_timeout_onwakeup = bmiss_timeout; + + wlan_mlme_get_bmiss_timeout_on_sleep(psoc, &bmiss_timeout); + params->bmiss_timeout_onsleep = bmiss_timeout; +} + +QDF_STATUS +cm_roam_fill_rssi_change_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_rssi_change_params *params) +{ + struct cm_roam_values_copy temp; + + params->vdev_id = vdev_id; + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + RSSI_CHANGE_THRESHOLD, &temp); + params->rssi_change_thresh = temp.int_value; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + BEACON_RSSI_WEIGHT, &temp); + params->bcn_rssi_weight = temp.uint_value; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + HI_RSSI_DELAY_BTW_SCANS, &temp); + params->hirssi_delay_btw_scans = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_is_per_roam_allowed() - Check if PER roam trigger needs to be + * disabled based on the current connected rates. + * @psoc: Pointer to the psoc object + * @vdev_id: Vdev id + * + * Return: true if PER roam trigger is allowed + */ +static bool +cm_roam_is_per_roam_allowed(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct qdf_mac_addr connected_bssid = {0}; + struct wlan_objmgr_vdev *vdev; + enum wlan_phymode peer_phymode = WLAN_PHYMODE_AUTO; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("Vdev is null for vdev_id:%d", vdev_id); + return false; + } + + status = wlan_vdev_get_bss_peer_mac(vdev, &connected_bssid); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + if (QDF_IS_STATUS_ERROR(status)) + return false; + + mlme_get_peer_phymode(psoc, connected_bssid.bytes, &peer_phymode); + if (peer_phymode < WLAN_PHYMODE_11NA_HT20) { + mlme_debug("vdev:%d PER roam trigger disabled for phymode:%d", + peer_phymode, vdev_id); + return false; + } + + return true; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * cm_roam_reason_vsie() - set roam reason vsie + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: roam reason vsie parameters + * + * This function is used to set roam reason vsie parameters + * + * Return: None + */ +static void +cm_roam_reason_vsie(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_reason_vsie_enable *params) +{ + uint8_t enable_roam_reason_vsie; + + params->vdev_id = vdev_id; + + wlan_mlme_get_roam_reason_vsie_status(psoc, &enable_roam_reason_vsie); + params->enable_roam_reason_vsie = enable_roam_reason_vsie; +} + +/** + * cm_is_only_2g_band_supported() - Check if BTC trigger and IDLE trigger needs + * to be disabled based on the current connected band. + * @psoc: Pointer to the psoc object + * @vdev_id: Vdev id + * + * Return: true if BTC trigger and IDLE trigger are allowed or not + */ +static bool +cm_is_only_2g_band_supported(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + bool only_2g_band_supported = false; + uint32_t band_bitmap; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("Vdev is null for vdev_id:%d", vdev_id); + return false; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev is null for vdev_id:%d", vdev_id); + goto release; + } + + if (QDF_IS_STATUS_ERROR(ucfg_reg_get_band(pdev, &band_bitmap))) { + mlme_debug("Failed to get band"); + goto release; + } + + mlme_debug("Current band bitmap:%d", band_bitmap); + + if (band_bitmap & BIT(REG_BAND_2G) && + !(band_bitmap & BIT(REG_BAND_5G)) && + !(band_bitmap & BIT(REG_BAND_6G))) + only_2g_band_supported = true; + + +release: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return only_2g_band_supported; +} + +/** + * cm_roam_triggers() - set roam triggers + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: roam triggers parameters + * + * This function is used to set roam triggers parameters + * + * Return: None + */ +static void +cm_roam_triggers(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_triggers *params) +{ + bool is_per_roam_enabled; + + params->vdev_id = vdev_id; + params->trigger_bitmap = + mlme_get_roam_trigger_bitmap(psoc, vdev_id); + + /* + * Disable PER trigger for phymode less than 11n to avoid + * frequent roams as the PER rate threshold is greater than + * 11a/b/g rates + */ + is_per_roam_enabled = cm_roam_is_per_roam_allowed(psoc, vdev_id); + if (!is_per_roam_enabled) + params->trigger_bitmap &= ~BIT(ROAM_TRIGGER_REASON_PER); + + /* + * Enable BTC trigger and IDLE trigger only when DUT is dual band + * capable(2g + 5g/6g) + */ + if (cm_is_only_2g_band_supported(psoc, vdev_id)) { + params->trigger_bitmap &= ~BIT(ROAM_TRIGGER_REASON_IDLE); + params->trigger_bitmap &= ~BIT(ROAM_TRIGGER_REASON_BTC); + } + + mlme_debug("[ROAM_TRIGGER] trigger_bitmap:%d", params->trigger_bitmap); + + params->roam_scan_scheme_bitmap = + wlan_cm_get_roam_scan_scheme_bitmap(psoc, vdev_id); + wlan_cm_roam_get_vendor_btm_params(psoc, ¶ms->vendor_btm_param); + wlan_cm_roam_get_score_delta_params(psoc, params); + wlan_cm_roam_get_min_rssi_params(psoc, params); +} + +/** + * cm_roam_bss_load_config() - set bss load config + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: bss load config parameters + * + * This function is used to set bss load config parameters + * + * Return: None + */ +static void +cm_roam_bss_load_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_bss_load_config *params) +{ + params->vdev_id = vdev_id; + wlan_mlme_get_bss_load_threshold(psoc, ¶ms->bss_load_threshold); + wlan_mlme_get_bss_load_sample_time(psoc, ¶ms->bss_load_sample_time); + wlan_mlme_get_bss_load_rssi_threshold_6ghz( + psoc, ¶ms->rssi_threshold_6ghz); + wlan_mlme_get_bss_load_rssi_threshold_5ghz( + psoc, ¶ms->rssi_threshold_5ghz); + wlan_mlme_get_bss_load_rssi_threshold_24ghz( + psoc, ¶ms->rssi_threshold_24ghz); +} + +/** + * cm_roam_disconnect_params() - set disconnect roam parameters + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: disconnect roam parameters + * + * This function is used to set disconnect roam parameters + * + * Return: None + */ +static void +cm_roam_disconnect_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_disconnect_params *params) +{ + params->vdev_id = vdev_id; + wlan_mlme_get_enable_disconnect_roam_offload(psoc, ¶ms->enable); +} + +/** + * cm_roam_idle_params() - set roam idle parameters + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: roam idle parameters + * + * This function is used to set roam idle parameters + * + * Return: None + */ +static void +cm_roam_idle_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_idle_params *params) +{ + params->vdev_id = vdev_id; + wlan_mlme_get_enable_idle_roam(psoc, ¶ms->enable); + wlan_mlme_get_idle_roam_rssi_delta(psoc, ¶ms->conn_ap_rssi_delta); + wlan_mlme_get_idle_roam_inactive_time(psoc, ¶ms->inactive_time); + wlan_mlme_get_idle_data_packet_count(psoc, ¶ms->data_pkt_count); + wlan_mlme_get_idle_roam_min_rssi(psoc, ¶ms->conn_ap_min_rssi); + wlan_mlme_get_idle_roam_band(psoc, ¶ms->band); +} + +#define RSN_CAPS_SHIFT 16 + +#ifdef WLAN_ADAPTIVE_11R +static inline void +cm_update_rso_adaptive_11r(struct wlan_rso_11r_params *dst, + struct rso_config *rso_cfg) +{ + dst->is_adaptive_11r = rso_cfg->is_adaptive_11r_connection; +} +#else +static inline void +cm_update_rso_adaptive_11r(struct wlan_rso_11r_params *dst, + struct rso_config *rso_cfg) +{} +#endif + +#ifdef FEATURE_WLAN_ESE +static void +cm_update_rso_ese_info(struct rso_config *rso_cfg, + struct wlan_roam_scan_offload_params *rso_config) +{ + rso_config->rso_ese_info.is_ese_assoc = rso_cfg->is_ese_assoc; + rso_config->rso_11r_info.is_11r_assoc = rso_cfg->is_11r_assoc; + if (rso_cfg->is_ese_assoc) { + qdf_mem_copy(rso_config->rso_ese_info.krk, rso_cfg->krk, + WMI_KRK_KEY_LEN); + qdf_mem_copy(rso_config->rso_ese_info.btk, rso_cfg->btk, + WMI_BTK_KEY_LEN); + rso_config->rso_11i_info.fw_okc = 0; + rso_config->rso_11i_info.fw_pmksa_cache = 0; + rso_config->rso_11i_info.pmk_len = 0; + qdf_mem_zero(&rso_config->rso_11i_info.psk_pmk[0], + sizeof(rso_config->rso_11i_info.psk_pmk)); + } +} +#else +static inline void +cm_update_rso_ese_info(struct rso_config *rso_cfg, + struct wlan_roam_scan_offload_params *rso_config) +{} +#endif + +#ifdef WLAN_SAE_SINGLE_PMK +static bool +cm_fill_rso_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_offload_params *rso_cfg) +{ + struct wlan_mlme_sae_single_pmk single_pmk = {0}; + struct wlan_rso_11i_params *rso_11i_info = &rso_cfg->rso_11i_info; + uint64_t time_expired; + + wlan_mlme_get_sae_single_pmk_info(vdev, &single_pmk); + + if (single_pmk.pmk_info.pmk_len && single_pmk.sae_single_pmk_ap && + mlme_obj->cfg.lfr.sae_single_pmk_feature_enabled) { + + rso_11i_info->pmk_len = single_pmk.pmk_info.pmk_len; + /* Update sae same pmk info in rso */ + qdf_mem_copy(rso_11i_info->psk_pmk, single_pmk.pmk_info.pmk, + rso_11i_info->pmk_len); + rso_11i_info->is_sae_same_pmk = single_pmk.sae_single_pmk_ap; + + /* get the time expired in seconds */ + time_expired = (qdf_get_system_timestamp() - + single_pmk.pmk_info.spmk_timestamp) / 1000; + + rso_cfg->sae_offload_params.spmk_timeout = 0; + if (time_expired < single_pmk.pmk_info.spmk_timeout_period) + rso_cfg->sae_offload_params.spmk_timeout = + (single_pmk.pmk_info.spmk_timeout_period - + time_expired); + + mlme_debug("Update spmk with len:%d is_spmk_ap:%d time_exp:%lld time left:%d", + single_pmk.pmk_info.pmk_len, + single_pmk.sae_single_pmk_ap, time_expired, + rso_cfg->sae_offload_params.spmk_timeout); + + return true; + } + + return false; +} +#else +static inline bool +cm_fill_rso_sae_single_pmk_info(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_offload_params *rso_cfg) +{ + return false; +} +#endif + +static QDF_STATUS +cm_roam_scan_offload_fill_lfr3_config(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_roam_scan_offload_params *rso_config, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + uint8_t command, uint32_t *mode) +{ + tSirMacCapabilityInfo self_caps; + tSirMacQosInfoStation sta_qos_info; + uint16_t *final_caps_val; + uint8_t *qos_cfg_val, temp_val; + uint32_t pmkid_modes = mlme_obj->cfg.sta.pmkid_modes; + uint32_t val = 0; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + qdf_size_t val_len; + QDF_STATUS status; + uint16_t rsn_caps = 0; + int32_t uccipher, authmode, akm; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct cm_roam_values_copy roam_config; + struct mlme_legacy_priv *mlme_priv; + uint8_t uapsd_mask; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return QDF_STATUS_E_FAILURE; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_INVAL; + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + rso_config->roam_offload_enabled = + mlme_obj->cfg.lfr.lfr3_roaming_offload; + if (!rso_config->roam_offload_enabled) + return QDF_STATUS_SUCCESS; + + /* FILL LFR3 specific roam scan mode TLV parameters */ + rso_config->rso_lfr3_params.roam_rssi_cat_gap = + mlme_obj->cfg.lfr.rso_user_config.cat_rssi_offset; + rso_config->rso_lfr3_params.prefer_5ghz = + mlme_obj->cfg.lfr.roam_prefer_5ghz; + rso_config->rso_lfr3_params.select_5ghz_margin = + mlme_obj->cfg.gen.select_5ghz_margin; + rso_config->rso_lfr3_params.reassoc_failure_timeout = + mlme_obj->cfg.timeouts.reassoc_failure_timeout; + rso_config->rso_lfr3_params.ho_delay_for_rx = + mlme_obj->cfg.lfr.ho_delay_for_rx; + rso_config->rso_lfr3_params.roam_retry_count = + mlme_obj->cfg.lfr.roam_preauth_retry_count; + rso_config->rso_lfr3_params.roam_preauth_no_ack_timeout = + mlme_obj->cfg.lfr.roam_preauth_no_ack_timeout; + rso_config->rso_lfr3_params.rct_validity_timer = + mlme_obj->cfg.btm.rct_validity_timer; + rso_config->rso_lfr3_params.disable_self_roam = + !mlme_obj->cfg.lfr.enable_self_bss_roam; + if (!rso_cfg->roam_control_enable && + mlme_obj->cfg.lfr.roam_force_rssi_trigger) + *mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + /* + * Self rsn caps aren't sent to firmware, so in case of PMF required, + * the firmware connects to a non PMF AP advertising PMF not required + * in the re-assoc request which violates protocol. + * So send self RSN caps to firmware in roam SCAN offload command to + * let it configure the params in the re-assoc request too. + * Instead of making another infra, send the RSN-CAPS in MSB of + * beacon Caps. + */ + /* RSN caps with global user MFP which can be used for cross-AKM roam */ + rsn_caps = rso_cfg->rso_rsn_caps; + + /* Fill LFR3 specific self capabilities for roam scan mode TLV */ + self_caps.ess = 1; + self_caps.ibss = 0; + + val = mlme_obj->cfg.wep_params.is_privacy_enabled; + if (val) + self_caps.privacy = 1; + + if (mlme_obj->cfg.ht_caps.short_preamble) + self_caps.shortPreamble = 1; + + self_caps.criticalUpdateFlag = 0; + self_caps.channelAgility = 0; + + if (mlme_obj->cfg.feature_flags.enable_short_slot_time_11g) + self_caps.shortSlotTime = 1; + + if (mlme_obj->cfg.gen.enabled_11h) + self_caps.spectrumMgt = 1; + + if (mlme_obj->cfg.wmm_params.qos_enabled) + self_caps.qos = 1; + + if (mlme_obj->cfg.roam_scoring.apsd_enabled) + self_caps.apsd = 1; + + self_caps.rrm = mlme_obj->cfg.rrm_config.rrm_enabled; + + val = mlme_obj->cfg.feature_flags.enable_block_ack; + self_caps.delayedBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + self_caps.immediateBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + final_caps_val = (uint16_t *)&self_caps; + + rso_config->rso_lfr3_caps.capability = + (rsn_caps << RSN_CAPS_SHIFT) | ((*final_caps_val) & 0xFFFF); + + rso_config->rso_lfr3_caps.ht_caps_info = + *(uint16_t *)&mlme_obj->cfg.ht_caps.ht_cap_info; + rso_config->rso_lfr3_caps.ampdu_param = + *(uint8_t *)&mlme_obj->cfg.ht_caps.ampdu_params; + rso_config->rso_lfr3_caps.ht_ext_cap = + *(uint16_t *)&mlme_obj->cfg.ht_caps.ext_cap_info; + + temp_val = (uint8_t)mlme_obj->cfg.vht_caps.vht_cap_info.tx_bf_cap; + rso_config->rso_lfr3_caps.ht_txbf = temp_val & 0xFF; + temp_val = (uint8_t)mlme_obj->cfg.vht_caps.vht_cap_info.as_cap; + rso_config->rso_lfr3_caps.asel_cap = temp_val & 0xFF; + + qdf_mem_zero(&sta_qos_info, sizeof(tSirMacQosInfoStation)); + sta_qos_info.maxSpLen = + (uint8_t)mlme_obj->cfg.wmm_params.max_sp_length; + sta_qos_info.moreDataAck = 0; + sta_qos_info.qack = 0; + wlan_cm_roam_cfg_get_value(psoc, vdev_id, UAPSD_MASK, &roam_config); + uapsd_mask = roam_config.uint_value; + sta_qos_info.acbe_uapsd = SIR_UAPSD_GET(ACBE, uapsd_mask); + sta_qos_info.acbk_uapsd = SIR_UAPSD_GET(ACBK, uapsd_mask); + sta_qos_info.acvi_uapsd = SIR_UAPSD_GET(ACVI, uapsd_mask); + sta_qos_info.acvo_uapsd = SIR_UAPSD_GET(ACVO, uapsd_mask); + qos_cfg_val = (uint8_t *)&sta_qos_info; + rso_config->rso_lfr3_caps.qos_caps = (*qos_cfg_val) & 0xFF; + if (rso_config->rso_lfr3_caps.qos_caps) + rso_config->rso_lfr3_caps.qos_enabled = true; + + rso_config->rso_lfr3_caps.wmm_caps = 0x4; + + val_len = ROAM_OFFLOAD_NUM_MCS_SET; + status = + wlan_mlme_get_cfg_str((uint8_t *)rso_config->rso_lfr3_caps.mcsset, + &mlme_obj->cfg.rates.supported_mcs_set, + &val_len); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to get CFG_SUPPORTED_MCS_SET"); + return QDF_STATUS_E_FAILURE; + } + + /* Update 11i TLV related Fields */ + rso_config->rso_11i_info.roam_key_mgmt_offload_enabled = + mlme_obj->cfg.lfr.lfr3_roaming_offload; + rso_config->rso_11i_info.fw_okc = + (pmkid_modes & CFG_PMKID_MODES_OKC) ? 1 : 0; + rso_config->rso_11i_info.fw_pmksa_cache = + (pmkid_modes & CFG_PMKID_MODES_PMKSA_CACHING) ? 1 : 0; + + /* Check whether to send psk_pmk or sae_single pmk info */ + if (!cm_fill_rso_sae_single_pmk_info(vdev, mlme_obj, rso_config)) { + rso_config->rso_11i_info.is_sae_same_pmk = false; + wlan_cm_get_psk_pmk(pdev, vdev_id, + rso_config->rso_11i_info.psk_pmk, + &rso_config->rso_11i_info.pmk_len); + } + + rso_config->rso_11r_info.enable_ft_im_roaming = + mlme_obj->cfg.lfr.enable_ft_im_roaming; + rso_config->rso_11r_info.mdid.mdie_present = + rso_cfg->mdid.mdie_present; + rso_config->rso_11r_info.mdid.mobility_domain = + rso_cfg->mdid.mobility_domain; + rso_config->rso_11r_info.r0kh_id_length = + mlme_priv->connect_info.ft_info.r0kh_id_len; + qdf_mem_copy(rso_config->rso_11r_info.r0kh_id, + mlme_priv->connect_info.ft_info.r0kh_id, + mlme_priv->connect_info.ft_info.r0kh_id_len); + wlan_cm_get_psk_pmk(pdev, vdev_id, + rso_config->rso_11r_info.psk_pmk, + &rso_config->rso_11r_info.pmk_len); + rso_config->rso_11r_info.enable_ft_over_ds = + mlme_obj->cfg.lfr.enable_ft_over_ds; + + cm_update_rso_adaptive_11r(&rso_config->rso_11r_info, rso_cfg); + cm_update_rso_ese_info(rso_cfg, rso_config); + uccipher = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER); + authmode = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_AUTH_MODE); + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + + rso_config->akm = + cm_crypto_authmode_to_wmi_authmode(authmode, akm, uccipher); + + return QDF_STATUS_SUCCESS; +} + +bool +cm_roam_is_change_in_band_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t roam_band_mask) +{ + struct wlan_objmgr_vdev *vdev; + bool sta_concurrency_is_with_different_mac; + struct wlan_channel *chan; + + if (policy_mgr_is_hw_sbs_capable(psoc)) + return true; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev is NULL"); + return false; + } + + chan = wlan_vdev_get_active_channel(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + if (!chan) { + mlme_err("no active channel"); + return false; + } + + sta_concurrency_is_with_different_mac = + policy_mgr_concurrent_sta_on_different_mac(psoc); + if (!sta_concurrency_is_with_different_mac) + return true; + + mlme_debug("sta concurrency on different mac, ch freq %d, roam band:%d", + chan->ch_freq, roam_band_mask); + + if (wlan_reg_freq_to_band(chan->ch_freq) == REG_BAND_2G && + (!(roam_band_mask & BIT(REG_BAND_2G)))) { + mlme_debug("Change in band (2G to 5G/6G) not allowed"); + return false; + } + + if ((wlan_reg_freq_to_band(chan->ch_freq) == REG_BAND_5G || + wlan_reg_freq_to_band(chan->ch_freq) == REG_BAND_6G) && + (!(roam_band_mask & BIT(REG_BAND_5G)) && + !(roam_band_mask & BIT(REG_BAND_6G)))) { + mlme_debug("Change in band (5G/6G to 2G) not allowed"); + return false; + } + + return true; +} + +/** + * cm_roam_send_rt_stats_config() - set roam stats parameters + * @psoc: psoc pointer + * @vdev_id: vdev id + * @param_value: roam stats param value + * + * This function is used to set roam event stats parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_send_rt_stats_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + struct roam_disable_cfg *req; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + req->vdev_id = vdev_id; + req->cfg = param_value; + + status = wlan_cm_tgt_send_roam_rt_stats_config(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send roam rt stats config"); + + qdf_mem_free(req); + + return status; +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +bool +cm_roam_is_vendor_handoff_control_enable(struct wlan_objmgr_psoc *psoc) +{ + bool ini_flag, handoff_control_support; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + + if (!mlme_obj) + return false; + + ini_flag = mlme_obj->cfg.connection_roaming_ini_flag; + + handoff_control_support = + wlan_mlme_get_vendor_handoff_control_caps(psoc); + + mlme_debug("ini flag:%d, fw caps:%d", ini_flag, + handoff_control_support); + + if (ini_flag && handoff_control_support) + return true; + + return false; +} + +QDF_STATUS +cm_roam_send_vendor_handoff_param_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t param_id, + void *vendor_handoff_context) +{ + struct vendor_handoff_cfg *req; + QDF_STATUS status; + struct mlme_legacy_priv *mlme_priv; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("get vdev failed"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + status = QDF_STATUS_E_FAILURE; + goto error; + } + + if (mlme_priv->cm_roam.vendor_handoff_param.req_in_progress) { + mlme_debug("vendor handoff request is already in progress"); + status = QDF_STATUS_E_FAILURE; + goto error; + } else { + mlme_debug("Set vendor handoff req in progress context"); + mlme_priv->cm_roam.vendor_handoff_param.req_in_progress = true; + mlme_priv->cm_roam.vendor_handoff_param.vendor_handoff_context = + vendor_handoff_context; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto error; + } + + req->vdev_id = vdev_id; + req->param_id = param_id; + + status = wlan_cm_tgt_send_roam_vendor_handoff_config(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send roam rt stats config"); + + qdf_mem_free(req); + +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return status; +} + +QDF_STATUS cm_roam_update_vendor_handoff_config(struct wlan_objmgr_psoc *psoc, + struct roam_vendor_handoff_params *list) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + uint8_t vdev_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t param_value, i; + enum vendor_control_roam_param param_id; + + vdev_id = list->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + status = QDF_STATUS_E_FAILURE; + goto error; + } + + cfg_params = &rso_cfg->cfg_param; + + mlme_debug("received vendor handoff event from FW with num_entries %d", + list->num_entries); + + for (i = 0; i < list->num_entries; i++) { + param_id = list->param_info[i].param_id; + param_value = list->param_info[i].param_value; + mlme_debug("param id:%d, param value:%d", param_id, + param_value); + switch (param_id) { + case VENDOR_CONTROL_PARAM_ROAM_TRIGGER: + cfg_params->neighbor_lookup_threshold = + abs(param_value); + cfg_params->next_rssi_threshold = + cfg_params->neighbor_lookup_threshold; + break; + case VENDOR_CONTROL_PARAM_ROAM_DELTA: + cfg_params->roam_rssi_diff = param_value; + break; + case VENDOR_CONTROL_PARAM_ROAM_FULL_SCANPERIOD: + cfg_params->full_roam_scan_period = param_value; + break; + case VENDOR_CONTROL_PARAM_ROAM_PARTIAL_SCANPERIOD: + cfg_params->empty_scan_refresh_period = + param_value * 1000; + break; + case VENDOR_CONTROL_PARAM_ROAM_ACTIVE_CH_DWELLTIME: + cfg_params->max_chan_scan_time = param_value; + break; + case VENDOR_CONTROL_PARAM_ROAM_PASSIVE_CH_DWELLTIME: + cfg_params->passive_max_chan_time = param_value; + break; + case VENDOR_CONTROL_PARAM_ROAM_HOME_CH_TIME: + cfg_params->neighbor_scan_period = param_value; + break; + case VENDOR_CONTROL_PARAM_ROAM_AWAY_TIME: + cfg_params->roam_scan_home_away_time = param_value; + break; + default: + mlme_debug("Invalid param id"); + status = QDF_STATUS_E_FAILURE; + goto error; + } + } +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return status; +} + +#endif +#else +static inline void +cm_roam_reason_vsie(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_reason_vsie_enable *params) +{ +} + +static inline void +cm_roam_triggers(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_triggers *params) +{ +} + +static void +cm_roam_bss_load_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_bss_load_config *params) +{ +} + +static void +cm_roam_disconnect_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_disconnect_params *params) +{ +} + +static void +cm_roam_idle_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_idle_params *params) +{ +} +static inline QDF_STATUS +cm_roam_scan_offload_fill_lfr3_config(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_roam_scan_offload_params *rso_config, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + uint8_t command, uint32_t *mode) +{ + if (mlme_obj->cfg.lfr.roam_force_rssi_trigger) + *mode |= WMI_ROAM_SCAN_MODE_RSSI_CHANGE; + + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_FILS_SK) +static QDF_STATUS +cm_roam_scan_offload_add_fils_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_scan_offload_params *rso_cfg, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint32_t usr_name_len; + struct wlan_fils_connection_info *fils_info; + struct wlan_roam_fils_params *fils_roam_config = + &rso_cfg->fils_roam_config; + + fils_info = wlan_cm_get_fils_connection_info(psoc, vdev_id); + if (!fils_info) + return QDF_STATUS_SUCCESS; + + if (fils_info->key_nai_length > FILS_MAX_KEYNAME_NAI_LENGTH || + fils_info->r_rk_length > WLAN_FILS_MAX_RRK_LENGTH) { + mlme_err("Fils info len error: keyname nai len(%d) rrk len(%d)", + fils_info->key_nai_length, fils_info->r_rk_length); + return QDF_STATUS_E_FAILURE; + } + + fils_roam_config->next_erp_seq_num = fils_info->erp_sequence_number; + + usr_name_len = + qdf_str_copy_all_before_char(fils_info->keyname_nai, + sizeof(fils_info->keyname_nai), + fils_roam_config->username, + sizeof(fils_roam_config->username), + '@'); + if (fils_info->key_nai_length <= usr_name_len) { + mlme_err("Fils info len error: key nai len %d, user name len %d", + fils_info->key_nai_length, usr_name_len); + return QDF_STATUS_E_INVAL; + } + + fils_roam_config->username_length = usr_name_len; + qdf_mem_copy(fils_roam_config->rrk, fils_info->r_rk, + fils_info->r_rk_length); + fils_roam_config->rrk_length = fils_info->r_rk_length; + fils_roam_config->realm_len = fils_info->key_nai_length - + fils_roam_config->username_length - 1; + qdf_mem_copy(fils_roam_config->realm, + (fils_info->keyname_nai + + fils_roam_config->username_length + 1), + fils_roam_config->realm_len); + + /* + * Set add FILS tlv true for initial FULL EAP connection and subsequent + * FILS connection. + */ + rso_cfg->add_fils_tlv = true; + mlme_debug("Fils: next_erp_seq_num %d rrk_len %d realm_len:%d", + fils_info->erp_sequence_number, + fils_info->r_rk_length, + fils_info->realm_len); + if (!fils_info->is_fils_connection) + return QDF_STATUS_SUCCESS; + + /* Update rik from crypto to fils roam config buffer */ + status = wlan_crypto_create_fils_rik(fils_info->r_rk, + fils_info->r_rk_length, + fils_info->rik, + &fils_info->rik_length); + qdf_mem_copy(fils_roam_config->rik, fils_info->rik, + fils_info->rik_length); + fils_roam_config->rik_length = fils_info->rik_length; + + fils_roam_config->fils_ft_len = fils_info->fils_ft_len; + qdf_mem_copy(fils_roam_config->fils_ft, fils_info->fils_ft, + fils_info->fils_ft_len); + + return status; +} +#else +static inline +QDF_STATUS cm_roam_scan_offload_add_fils_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_scan_offload_params *rso_cfg, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * cm_roam_mawc_params() - set roam mawc parameters + * @psoc: psoc pointer + * @vdev_id: vdev id + * @params: roam mawc parameters + * + * This function is used to set roam mawc parameters + * + * Return: None + */ +static void +cm_roam_mawc_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_mawc_params *params) +{ + bool mawc_enabled; + bool mawc_roam_enabled; + + params->vdev_id = vdev_id; + wlan_mlme_get_mawc_enabled(psoc, &mawc_enabled); + wlan_mlme_get_mawc_roam_enabled(psoc, &mawc_roam_enabled); + params->enable = mawc_enabled && mawc_roam_enabled; + wlan_mlme_get_mawc_roam_traffic_threshold( + psoc, ¶ms->traffic_load_threshold); + wlan_mlme_get_mawc_roam_ap_rssi_threshold( + psoc, ¶ms->best_ap_rssi_threshold); + wlan_mlme_get_mawc_roam_rssi_high_adjust( + psoc, ¶ms->rssi_stationary_high_adjust); + wlan_mlme_get_mawc_roam_rssi_low_adjust( + psoc, ¶ms->rssi_stationary_low_adjust); +} + +QDF_STATUS +cm_roam_send_disable_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t cfg) +{ + struct roam_disable_cfg *req; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + req->vdev_id = vdev_id; + req->cfg = cfg; + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_debug("MLO ROAM: skip RSO cmd for link vdev %d", vdev_id); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wlan_cm_tgt_send_roam_disable_config(psoc, vdev_id, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send roam disable config"); + +end: + qdf_mem_free(req); + + return status; +} + +/** + * cm_roam_init_req() - roam init request handling + * @psoc: psoc pointer + * @vdev_id: vdev id + * @enable: should the offload be enabled + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_init_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, bool enable) +{ + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_debug("MLO ROAM: skip RSO cmd for link vdev %d", vdev_id); + return QDF_STATUS_SUCCESS; + } + + return wlan_cm_tgt_send_roam_offload_init(psoc, vdev_id, enable); +} + +QDF_STATUS cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct wlan_roam_triggers *trigger) +{ + QDF_STATUS status; + uint8_t reason = REASON_SUPPLICANT_DE_INIT_ROAMING; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) + return QDF_STATUS_E_INVAL; + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_debug("MLO ROAM: skip RSO cmd for link vdev %d", vdev_id); + return QDF_STATUS_SUCCESS; + } + + mlme_set_roam_trigger_bitmap(psoc, trigger->vdev_id, + trigger->trigger_bitmap); + + if (trigger->trigger_bitmap) + reason = REASON_SUPPLICANT_INIT_ROAMING; + + status = cm_roam_state_change(pdev, vdev_id, + trigger->trigger_bitmap ? WLAN_ROAM_RSO_ENABLED : + WLAN_ROAM_DEINIT, + reason, NULL, false); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return wlan_cm_tgt_send_roam_triggers(psoc, vdev_id, trigger); +} + +static void cm_roam_set_roam_reason_better_ap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool set) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return; + mlme_set_roam_reason_better_ap(vdev, set); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +} + +/** + * cm_roam_scan_offload_rssi_thresh() - set roam offload scan rssi + * parameters + * @psoc: psoc ctx + * @vdev_id: vdev id + * @params: roam offload scan rssi related parameters + * @rso_cfg: rso config + * + * This function is used to set roam offload scan rssi related parameters + * + * Return: None + */ +static void +cm_roam_scan_offload_rssi_thresh(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_offload_scan_rssi_params *params, + struct rso_config *rso_cfg) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_lfr_cfg *lfr_cfg; + struct rso_config_params *rso_config; + struct wlan_objmgr_vdev *vdev; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + rso_config = &mlme_obj->cfg.lfr.rso_user_config; + + lfr_cfg = &mlme_obj->cfg.lfr; + + if (rso_config->alert_rssi_threshold) { + params->rssi_thresh = rso_config->alert_rssi_threshold; + } else { + mlme_debug("lookup_threshold:%d", + rso_cfg->cfg_param.neighbor_lookup_threshold); + params->rssi_thresh = + (int8_t)rso_cfg->cfg_param.neighbor_lookup_threshold * + (-1); + } + + params->vdev_id = vdev_id; + params->rssi_thresh_diff = + rso_cfg->cfg_param.opportunistic_threshold_diff & 0x000000ff; + params->hi_rssi_scan_max_count = + rso_cfg->cfg_param.hi_rssi_scan_max_count; + /* + * If the current operation channel is 5G frequency band, then + * there is no need to enable the HI_RSSI feature. This feature + * is useful only if we are connected to a 2.4 GHz AP and we wish + * to connect to a better 5GHz AP is available. + */ + if (rso_cfg->disable_hi_rssi) + params->hi_rssi_scan_rssi_delta = 0; + else + params->hi_rssi_scan_rssi_delta = + rso_cfg->cfg_param.hi_rssi_scan_rssi_delta; + /* + * When the STA operating band is 2.4/5 GHz and if the high RSSI delta + * is configured through vendor command then the priority should be + * given to it and the high RSSI delta value will be overridden with it. + */ + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("Cannot set high RSSI offset as vdev object is NULL for vdev %d", + vdev_id); + } else { + qdf_freq_t op_freq; + + op_freq = wlan_get_operation_chan_freq(vdev); + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(op_freq)) { + uint8_t roam_high_rssi_delta; + + roam_high_rssi_delta = + wlan_cm_get_roam_scan_high_rssi_offset(psoc); + if (roam_high_rssi_delta) + params->hi_rssi_scan_rssi_delta = + roam_high_rssi_delta; + /* + * Firmware will use this flag to enable 5 to 6 GHz + * high RSSI roam + */ + if (roam_high_rssi_delta && + WLAN_REG_IS_5GHZ_CH_FREQ(op_freq)) + params->flags |= + ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + } + + params->hi_rssi_scan_rssi_ub = + rso_cfg->cfg_param.hi_rssi_scan_rssi_ub; + params->raise_rssi_thresh_5g = lfr_cfg->rssi_boost_threshold_5g; + params->dense_rssi_thresh_offset = lfr_cfg->roam_dense_rssi_thre_offset; + params->dense_min_aps_cnt = lfr_cfg->roam_dense_min_aps; + params->traffic_threshold = lfr_cfg->roam_dense_traffic_threshold; + + /* Set initial dense roam status */ + if (rso_cfg->roam_candidate_count > params->dense_min_aps_cnt) + params->initial_dense_status = true; + + params->bg_scan_bad_rssi_thresh = + lfr_cfg->roam_bg_scan_bad_rssi_threshold; + params->bg_scan_client_bitmap = lfr_cfg->roam_bg_scan_client_bitmap; + params->roam_bad_rssi_thresh_offset_2g = + lfr_cfg->roam_bg_scan_bad_rssi_offset_2g; + params->roam_data_rssi_threshold_triggers = + lfr_cfg->roam_data_rssi_threshold_triggers; + params->roam_data_rssi_threshold = lfr_cfg->roam_data_rssi_threshold; + params->rx_data_inactivity_time = lfr_cfg->rx_data_inactivity_time; + + params->drop_rssi_thresh_5g = lfr_cfg->rssi_penalize_threshold_5g; + + params->raise_factor_5g = lfr_cfg->rssi_boost_factor_5g; + params->drop_factor_5g = lfr_cfg->rssi_penalize_factor_5g; + params->max_raise_rssi_5g = lfr_cfg->max_rssi_boost_5g; + params->max_drop_rssi_5g = lfr_cfg->max_rssi_penalize_5g; + + if (rso_config->good_rssi_roam) + params->good_rssi_threshold = NOISE_FLOOR_DBM_DEFAULT; + else + params->good_rssi_threshold = 0; + + params->early_stop_scan_enable = lfr_cfg->early_stop_scan_enable; + if (params->early_stop_scan_enable) { + params->roam_earlystop_thres_min = + lfr_cfg->early_stop_scan_min_threshold; + params->roam_earlystop_thres_max = + lfr_cfg->early_stop_scan_max_threshold; + } + + params->rssi_thresh_offset_5g = + rso_cfg->cfg_param.rssi_thresh_offset_5g; +} + +/** + * cm_roam_scan_offload_scan_period() - set roam offload scan period + * parameters + * @vdev_id: vdev id + * @params: roam offload scan period related parameters + * @rso_cfg: rso config + * + * This function is used to set roam offload scan period related parameters + * + * Return: None + */ +static void +cm_roam_scan_offload_scan_period(uint8_t vdev_id, + struct wlan_roam_scan_period_params *params, + struct rso_config *rso_cfg) +{ + struct rso_cfg_params *cfg_params; + + cfg_params = &rso_cfg->cfg_param; + + params->vdev_id = vdev_id; + params->empty_scan_refresh_period = + cfg_params->empty_scan_refresh_period; + params->scan_period = params->empty_scan_refresh_period; + params->scan_age = (3 * params->empty_scan_refresh_period); + params->roam_scan_inactivity_time = + cfg_params->roam_scan_inactivity_time; + params->roam_inactive_data_packet_count = + cfg_params->roam_inactive_data_packet_count; + params->full_scan_period = + cfg_params->full_roam_scan_period; + mlme_debug("full_scan_period:%d, empty_scan_refresh_period:%d", + params->full_scan_period, params->empty_scan_refresh_period); +} + +static void +cm_roam_fill_11w_params(struct wlan_objmgr_vdev *vdev, + struct ap_profile *profile) +{ + uint32_t group_mgmt_cipher; + bool peer_rmf_capable = false; + uint32_t keymgmt; + uint16_t rsn_caps; + + /* + * Get rsn cap of link, intersection of self cap and bss cap, + * Only set PMF flags when both STA and current AP has MFP enabled + */ + rsn_caps = (uint16_t)wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_RSN_CAP); + if (wlan_crypto_vdev_has_mgmtcipher(vdev, + (1 << WLAN_CRYPTO_CIPHER_AES_GMAC) | + (1 << WLAN_CRYPTO_CIPHER_AES_GMAC_256) | + (1 << WLAN_CRYPTO_CIPHER_AES_CMAC)) && + (rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) + peer_rmf_capable = true; + + keymgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MGMT_CIPHER); + + if (keymgmt & (1 << WLAN_CRYPTO_CIPHER_AES_CMAC)) + group_mgmt_cipher = WMI_CIPHER_AES_CMAC; + else if (keymgmt & (1 << WLAN_CRYPTO_CIPHER_AES_GMAC)) + group_mgmt_cipher = WMI_CIPHER_AES_GMAC; + else if (keymgmt & (1 << WLAN_CRYPTO_CIPHER_AES_GMAC_256)) + group_mgmt_cipher = WMI_CIPHER_BIP_GMAC_256; + else + group_mgmt_cipher = WMI_CIPHER_NONE; + + if (peer_rmf_capable) { + profile->rsn_mcastmgmtcipherset = group_mgmt_cipher; + profile->flags |= WMI_AP_PROFILE_FLAG_PMF; + } else { + profile->rsn_mcastmgmtcipherset = WMI_CIPHER_NONE; + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +cm_update_mlo_score_params(struct scoring_param *req_score_params, + struct weight_cfg *weight_config) +{ + req_score_params->eht_caps_weightage = + weight_config->eht_caps_weightage; + req_score_params->mlo_weightage = + weight_config->mlo_weightage; +} +#else +static void +cm_update_mlo_score_params(struct scoring_param *req_score_params, + struct weight_cfg *weight_config) +{ +} +#endif + +void cm_update_owe_info(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp, uint8_t vdev_id) +{ + struct rso_config *rso_cfg; + struct owe_transition_mode_info *owe_info; + uint8_t *ie_ptr; + uint32_t ie_len, akm; + const uint8_t *owe_transition_ie = NULL; + uint8_t length; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + owe_info = &rso_cfg->owe_info; + + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (!QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE)) + goto reset; + + mlme_debug("[OWE_TRANSITION]:Update the owe open bss's ssid"); + + if (!rsp->connect_ies.bcn_probe_rsp.ptr || + !rsp->connect_ies.bcn_probe_rsp.len || + (rsp->connect_ies.bcn_probe_rsp.len <= + (sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)))) { + mlme_debug("invalid beacon probe rsp len %d", + rsp->connect_ies.bcn_probe_rsp.len); + goto reset; + } + + ie_len = (rsp->connect_ies.bcn_probe_rsp.len - + sizeof(struct wlan_frame_hdr) - + offsetof(struct wlan_bcn_frame, ie)); + ie_ptr = (uint8_t *)(rsp->connect_ies.bcn_probe_rsp.ptr + + sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)); + + owe_transition_ie = wlan_get_vendor_ie_ptr_from_oui( + OWE_TRANSITION_OUI_TYPE, + OWE_TRANSITION_OUI_SIZE, ie_ptr, ie_len); + if (!owe_transition_ie || owe_transition_ie[1] <= OWE_SSID_OFFSET) { + mlme_debug("[OWE_TRANSITION]: Invalid owe transition ie"); + goto reset; + } + + owe_info->is_owe_transition_conn = true; + + length = *(owe_transition_ie + OWE_SSID_LEN_OFFSET); + if (length > WLAN_SSID_MAX_LEN) { + mlme_debug("[OWE_TRANSITION] Invalid ssid len %d", length); + goto reset; + } + owe_info->ssid.length = length; + qdf_mem_copy(owe_info->ssid.ssid, owe_transition_ie + OWE_SSID_OFFSET, + owe_info->ssid.length); + + mlme_debug("[OWE_TRANSITION] open bss ssid: \"" QDF_SSID_FMT "\"", + QDF_SSID_REF(owe_info->ssid.length, owe_info->ssid.ssid)); + return; + +reset: + if (owe_info->is_owe_transition_conn) + owe_info->is_owe_transition_conn = false; + + return; +} + +/** + * cm_update_owe_ap_profile() - set owe ap profile + * @params: roam offload scan period related parameters + * @rso_cfg: rso config + * + * This function is used to set OPEN SSID value when STA is connected to OWE + * transition AP in OWE security + * + * Return: None + */ +static void cm_update_owe_ap_profile(struct ap_profile_params *params, + struct rso_config *rso_cfg) +{ + struct owe_transition_mode_info *owe_ap_profile; + bool is_owe_transition_conn; + + owe_ap_profile = ¶ms->owe_ap_profile; + is_owe_transition_conn = rso_cfg->owe_info.is_owe_transition_conn; + mlme_debug("set owe ap profile:%d", is_owe_transition_conn); + owe_ap_profile->is_owe_transition_conn = is_owe_transition_conn; + owe_ap_profile->ssid.length = rso_cfg->owe_info.ssid.length; + qdf_mem_copy(owe_ap_profile->ssid.ssid, rso_cfg->owe_info.ssid.ssid, + rso_cfg->owe_info.ssid.length); +} + +static void cm_update_score_params(struct wlan_objmgr_psoc *psoc, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct scoring_param *req_score_params, + struct rso_config *rso_cfg) +{ + struct wlan_mlme_roam_scoring_cfg *roam_score_params; + struct weight_cfg *weight_config; + struct psoc_mlme_obj *mlme_psoc_obj; + struct scoring_cfg *score_config; + struct dual_sta_policy *dual_sta_policy; + + mlme_psoc_obj = wlan_psoc_mlme_get_cmpt_obj(psoc); + if (!mlme_psoc_obj) + return; + + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + + score_config = &mlme_psoc_obj->psoc_cfg.score_config; + roam_score_params = &mlme_obj->cfg.roam_scoring; + weight_config = &score_config->weight_config; + + if (!rso_cfg->cfg_param.enable_scoring_for_roam) + req_score_params->disable_bitmap = + WLAN_ROAM_SCORING_DISABLE_ALL; + + req_score_params->rssi_weightage = weight_config->rssi_weightage; + req_score_params->ht_weightage = weight_config->ht_caps_weightage; + req_score_params->vht_weightage = weight_config->vht_caps_weightage; + req_score_params->he_weightage = weight_config->he_caps_weightage; + req_score_params->bw_weightage = weight_config->chan_width_weightage; + req_score_params->band_weightage = weight_config->chan_band_weightage; + req_score_params->nss_weightage = weight_config->nss_weightage; + req_score_params->security_weightage = + weight_config->security_weightage; + req_score_params->esp_qbss_weightage = + weight_config->channel_congestion_weightage; + req_score_params->beamforming_weightage = + weight_config->beamforming_cap_weightage; + + /* + * Don’t consider pcl weightage if: + * a) primary interface is configured (or) + * b) HW is non-DBS + */ + if (policy_mgr_is_pcl_weightage_required(psoc) && + policy_mgr_is_hw_dbs_capable(psoc)) + req_score_params->pcl_weightage = weight_config->pcl_weightage; + else + req_score_params->pcl_weightage = 0; + + req_score_params->oce_wan_weightage = weight_config->oce_wan_weightage; + req_score_params->oce_ap_tx_pwr_weightage = + weight_config->oce_ap_tx_pwr_weightage; + req_score_params->oce_subnet_id_weightage = + weight_config->oce_subnet_id_weightage; + req_score_params->sae_pk_ap_weightage = + weight_config->sae_pk_ap_weightage; + + cm_update_mlo_score_params(req_score_params, weight_config); + + /* TODO: update scoring params corresponding to ML scoring */ + req_score_params->bw_index_score = + score_config->bandwidth_weight_per_index[0]; + req_score_params->band_index_score = + score_config->band_weight_per_index; + req_score_params->nss_index_score = + score_config->nss_weight_per_index[0]; + req_score_params->security_index_score = + score_config->security_weight_per_index; + req_score_params->vendor_roam_score_algorithm = + score_config->vendor_roam_score_algorithm; + + req_score_params->roam_score_delta = + roam_score_params->roam_score_delta; + req_score_params->roam_trigger_bitmap = + roam_score_params->roam_trigger_bitmap; + + qdf_mem_copy(&req_score_params->rssi_scoring, &score_config->rssi_score, + sizeof(struct rssi_config_score)); + qdf_mem_copy(&req_score_params->esp_qbss_scoring, + &score_config->esp_qbss_scoring, + sizeof(struct per_slot_score)); + qdf_mem_copy(&req_score_params->oce_wan_scoring, + &score_config->oce_wan_scoring, + sizeof(struct per_slot_score)); + req_score_params->cand_min_roam_score_delta = + roam_score_params->min_roam_score_delta; +} + +static uint32_t cm_crpto_cipher_wmi_cipher(int32_t cipherset) +{ + + if (!cipherset || cipherset < 0) + return WMI_CIPHER_NONE; + + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GCM) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GCM_256)) + return WMI_CIPHER_AES_GCM; + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CCM) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_OCB) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CCM_256)) + return WMI_CIPHER_AES_CCM; + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_TKIP)) + return WMI_CIPHER_TKIP; + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CMAC) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CMAC_256)) + return WMI_CIPHER_AES_CMAC; + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WAPI_GCM4) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WAPI_SMS4)) + return WMI_CIPHER_WAPI; + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GMAC) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GMAC_256)) + return WMI_CIPHER_AES_GMAC; + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP_104)) + return WMI_CIPHER_WEP; + + return WMI_CIPHER_NONE; +} + +static uint32_t cm_get_rsn_wmi_auth_type(int32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) + return WMI_AUTH_FT_RSNA_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) + return WMI_AUTH_FT_RSNA_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) + return WMI_AUTH_RSNA_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) + return WMI_AUTH_RSNA_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + return WMI_AUTH_FT_RSNA_SAE_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) + return WMI_AUTH_WPA3_SAE_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) + return WMI_AUTH_FT_RSNA_SAE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE)) + return WMI_AUTH_WPA3_SAE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE)) + return WMI_AUTH_WPA3_OWE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) + return WMI_AUTH_FT_RSNA; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) + return WMI_AUTH_FT_RSNA_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return WMI_AUTH_RSNA; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + return WMI_AUTH_RSNA_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return WMI_AUTH_CCKM_RSNA; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) + return WMI_AUTH_RSNA_PSK_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) + return WMI_AUTH_RSNA_8021X_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B)) + return WMI_AUTH_RSNA_SUITE_B_8021X_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) + return WMI_AUTH_RSNA_SUITE_B_8021X_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) + return WMI_AUTH_FT_RSNA_SUITE_B_8021X_SHA384; + else + return WMI_AUTH_NONE; +} + +static uint32_t cm_get_wpa_wmi_auth_type(int32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return WMI_AUTH_WPA; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + return WMI_AUTH_WPA_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return WMI_AUTH_CCKM_WPA; + else + return WMI_AUTH_NONE; +} + +static uint32_t cm_get_wapi_wmi_auth_type(int32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT)) + return WMI_AUTH_WAPI; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK)) + return WMI_AUTH_WAPI_PSK; + else + return WMI_AUTH_NONE; +} + +uint32_t cm_crypto_authmode_to_wmi_authmode(int32_t authmodeset, + int32_t akm, int32_t ucastcipherset) +{ + if (!authmodeset || authmodeset < 0) + return WMI_AUTH_OPEN; + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_OPEN)) + return WMI_AUTH_OPEN; + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_AUTO) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_NONE)) { + if ((QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucastcipherset, + WLAN_CRYPTO_CIPHER_WEP_104) || + QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_TKIP) || + QDF_HAS_PARAM(ucastcipherset, + WLAN_CRYPTO_CIPHER_AES_GCM) || + QDF_HAS_PARAM(ucastcipherset, + WLAN_CRYPTO_CIPHER_AES_GCM_256) || + QDF_HAS_PARAM(ucastcipherset, + WLAN_CRYPTO_CIPHER_AES_CCM) || + QDF_HAS_PARAM(ucastcipherset, + WLAN_CRYPTO_CIPHER_AES_OCB) || + QDF_HAS_PARAM(ucastcipherset, + WLAN_CRYPTO_CIPHER_AES_CCM_256))) + return WMI_AUTH_OPEN; + else + return WMI_AUTH_NONE; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_SHARED)) + return WMI_AUTH_SHARED; + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_8021X) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_RSNA) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_CCKM) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_SAE) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_FILS_SK)) + return cm_get_rsn_wmi_auth_type(akm); + + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_WPA)) + return cm_get_wpa_wmi_auth_type(akm); + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_WAPI)) + return cm_get_wapi_wmi_auth_type(akm); + + return WMI_AUTH_OPEN; +} + +static void cm_update_crypto_params(struct wlan_objmgr_vdev *vdev, + struct ap_profile *profile) +{ + int32_t keymgmt, connected_akm, authmode, uccipher, mccipher; + enum wlan_crypto_key_mgmt i; + int32_t num_allowed_authmode = 0; + struct rso_config *rso_cfg; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + + /* Pairwise cipher suite */ + uccipher = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER); + profile->rsn_ucastcipherset = cm_crpto_cipher_wmi_cipher(uccipher); + + /* Group cipher suite */ + mccipher = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MCAST_CIPHER); + profile->rsn_mcastcipherset = cm_crpto_cipher_wmi_cipher(mccipher); + + /* Group management cipher suite */ + cm_roam_fill_11w_params(vdev, profile); + + authmode = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_AUTH_MODE); + /* Get connected akm */ + connected_akm = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + profile->rsn_authmode = + cm_crypto_authmode_to_wmi_authmode(authmode, + connected_akm, + uccipher); + /* Get keymgmt from self security info */ + keymgmt = rso_cfg->orig_sec_info.key_mgmt; + + for (i = 0; i < WLAN_CRYPTO_KEY_MGMT_MAX; i++) { + /* + * Send AKM in allowed list which are not present in connected + * akm + */ + if (QDF_HAS_PARAM(keymgmt, i) && + num_allowed_authmode < WLAN_CRYPTO_AUTH_MAX) { + profile->allowed_authmode[num_allowed_authmode++] = + cm_crypto_authmode_to_wmi_authmode(authmode, + (keymgmt & (1 << i)), + uccipher); + } + } + + profile->num_allowed_authmode = num_allowed_authmode; +} + +/** + * cm_roam_scan_offload_ap_profile() - set roam ap profile parameters + * @psoc: psoc ctx + * @vdev: vdev id + * @rso_cfg: rso config + * @params: roam ap profile related parameters + * + * This function is used to set roam ap profile related parameters + * + * Return: None + */ +static void +cm_roam_scan_offload_ap_profile(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct ap_profile_params *params) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct ap_profile *profile = ¶ms->profile; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + params->vdev_id = vdev_id; + wlan_vdev_mlme_get_ssid(vdev, profile->ssid.ssid, + &profile->ssid.length); + + cm_update_crypto_params(vdev, profile); + + profile->rssi_threshold = rso_cfg->cfg_param.roam_rssi_diff; + mlme_debug("profile->rssi_threshold:%d", profile->rssi_threshold); + profile->bg_rssi_threshold = rso_cfg->cfg_param.bg_rssi_threshold; + /* + * rssi_diff which is updated via framework is equivalent to the + * INI RoamRssiDiff parameter and hence should be updated. + */ + if (mlme_obj->cfg.lfr.rso_user_config.rssi_diff) + profile->rssi_threshold = + mlme_obj->cfg.lfr.rso_user_config.rssi_diff; + + profile->rssi_abs_thresh = + mlme_obj->cfg.lfr.roam_rssi_abs_threshold; + + if (rso_cfg->owe_info.is_owe_transition_conn) + cm_update_owe_ap_profile(params, rso_cfg); + + cm_update_score_params(psoc, mlme_obj, ¶ms->param, rso_cfg); + + params->min_rssi_params[DEAUTH_MIN_RSSI] = + mlme_obj->cfg.trig_min_rssi[DEAUTH_MIN_RSSI]; + params->min_rssi_params[BMISS_MIN_RSSI] = + mlme_obj->cfg.trig_min_rssi[BMISS_MIN_RSSI]; + params->min_rssi_params[MIN_RSSI_2G_TO_5G_ROAM] = + mlme_obj->cfg.trig_min_rssi[MIN_RSSI_2G_TO_5G_ROAM]; + + params->score_delta_param[IDLE_ROAM_TRIGGER] = + mlme_obj->cfg.trig_score_delta[IDLE_ROAM_TRIGGER]; + params->score_delta_param[BTM_ROAM_TRIGGER] = + mlme_obj->cfg.trig_score_delta[BTM_ROAM_TRIGGER]; +} + +static bool +cm_check_band_freq_match(enum band_info band, qdf_freq_t freq) +{ + if (band == BAND_ALL) + return true; + + if (band == BAND_2G && WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + return true; + + if (band == BAND_5G && WLAN_REG_IS_5GHZ_CH_FREQ(freq)) + return true; + + /* + * Not adding the band check for now as band_info will be soon + * replaced with reg_wifi_band enum + */ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) + return true; + + return false; +} + +/** + * cm_is_dfs_unsafe_extra_band_chan() - check if dfs unsafe or extra band + * channel + * @vdev: vdev + * @mlme_obj: psoc mlme obj + * @freq: channel freq to check + * @band: band for intra band check +.*. + * Return: bool if match else false + */ +static bool +cm_is_dfs_unsafe_extra_band_chan(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + qdf_freq_t freq, + enum band_info band) +{ + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + bool is_unsafe_chan; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct rso_roam_policy_params *roam_policy; + struct wlan_objmgr_pdev *pdev; + + if (!qdf_ctx) + return true; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return true; + + roam_policy = &mlme_obj->cfg.lfr.rso_user_config.policy_params; + if ((mlme_obj->cfg.lfr.roaming_dfs_channel == + ROAMING_DFS_CHANNEL_DISABLED || + roam_policy->dfs_mode == STA_ROAM_POLICY_DFS_DISABLED) && + (wlan_reg_is_dfs_for_freq(pdev, freq))) + return true; + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + if (roam_policy->skip_unsafe_channels && unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == freq) { + is_unsafe_chan = true; + mlme_debug("ignoring unsafe channel freq %d", + freq); + return true; + } + } + } + if (!cm_check_band_freq_match(band, freq)) { + mlme_debug("ignoring non-intra band freq %d", freq); + return true; + } + + return false; +} + +/** + * cm_populate_roam_chan_list() - Populate roam channel list + * parameters + * @vdev: vdev + * @mlme_obj: mlme_obj + * @dst: Destination roam channel buf to populate the roam chan list + * @src: Source channel list + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +cm_populate_roam_chan_list(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_channel_list *dst, + struct rso_chan_info *src) +{ + enum band_info band; + uint32_t band_cap; + uint8_t i = 0; + uint8_t num_channels = 0; + qdf_freq_t *freq_lst = src->freq_list; + + /* + * The INI channels need to be filtered with respect to the current band + * that is supported. + */ + band_cap = mlme_obj->cfg.gen.band_capability; + if (!band_cap) { + mlme_err("Invalid band_cap(%d), roam scan offload req aborted", + band_cap); + return QDF_STATUS_E_FAILURE; + } + + band = wlan_reg_band_bitmap_to_band_info(band_cap); + num_channels = dst->chan_count; + for (i = 0; i < src->num_chan; i++) { + if (wlan_is_channel_present_in_list(dst->chan_freq_list, + num_channels, *freq_lst)) { + freq_lst++; + continue; + } + if (cm_is_dfs_unsafe_extra_band_chan(vdev, mlme_obj, + *freq_lst, band)) { + freq_lst++; + continue; + } + dst->chan_freq_list[num_channels++] = *freq_lst; + freq_lst++; + } + dst->chan_count = num_channels; + + return QDF_STATUS_SUCCESS; +} + +void +cm_update_tried_candidate_freq_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *connect_rsp) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct rso_config *rso_cfg; + struct wlan_chan_list *tried_freq_list; + enum band_info band; + uint32_t band_cap; + + if (!connect_rsp->freq || (connect_rsp->reason != CM_JOIN_TIMEOUT && + connect_rsp->reason != CM_AUTH_TIMEOUT && + connect_rsp->reason != CM_ASSOC_TIMEOUT)) + return; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + band_cap = mlme_obj->cfg.gen.band_capability; + if (!band_cap) { + mlme_err("vdev: %d Invalid band_cap(%d)", connect_rsp->vdev_id, + band_cap); + return; + } + + band = wlan_reg_band_bitmap_to_band_info(band_cap); + if (cm_is_dfs_unsafe_extra_band_chan(vdev, mlme_obj, + connect_rsp->freq, band)) + return; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + + tried_freq_list = &rso_cfg->tried_candidate_freq_list; + + if (tried_freq_list->num_chan >= CFG_VALID_CHANNEL_LIST_LEN) + return; + + if (wlan_is_channel_present_in_list(tried_freq_list->freq_list, + tried_freq_list->num_chan, + connect_rsp->freq)) + return; + + tried_freq_list->freq_list[tried_freq_list->num_chan++] = + connect_rsp->freq; + + mlme_debug("vdev: %d added freq:%d, total num freq %d", + connect_rsp->vdev_id, connect_rsp->freq, + tried_freq_list->num_chan); +} + +static QDF_STATUS +cm_fetch_ch_lst_from_ini(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_channel_list *chan_info, + struct rso_chan_info *specific_chan_info) +{ + QDF_STATUS status; + + status = cm_populate_roam_chan_list(vdev, mlme_obj, chan_info, + specific_chan_info); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to copy channels to roam list"); + return status; + } + chan_info->chan_cache_type = CHANNEL_LIST_STATIC; + + return QDF_STATUS_SUCCESS; +} + +static void +cm_fetch_ch_lst_from_occupied_lst(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info, + uint8_t reason) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + qdf_freq_t op_freq; + enum band_info band = BAND_ALL; + struct wlan_chan_list *occupied_channels; + + occupied_channels = &rso_cfg->occupied_chan_lst; + op_freq = wlan_get_operation_chan_freq(vdev); + if (mlme_obj->cfg.lfr.roam_intra_band) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(op_freq)) + band = BAND_5G; + else if (WLAN_REG_IS_24GHZ_CH_FREQ(op_freq)) + band = BAND_2G; + else + band = BAND_UNKNOWN; + } + + for (i = 0; i < occupied_channels->num_chan && + occupied_channels->num_chan < CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (cm_is_dfs_unsafe_extra_band_chan(vdev, mlme_obj, + occupied_channels->freq_list[i], band)) + continue; + + chan_info->chan_freq_list[num_channels++] = + occupied_channels->freq_list[i]; + } + chan_info->chan_count = num_channels; + chan_info->chan_cache_type = CHANNEL_LIST_DYNAMIC; +} + +/** + * cm_add_ch_lst_from_roam_scan_list() - channel from roam scan chan list + * parameters + * @vdev: vdev + * @mlme_obj: mlme_obj + * @chan_info: RSO channel info + * @rso_cfg: rso config + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_add_ch_lst_from_roam_scan_list(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_channel_list *chan_info, + struct rso_config *rso_cfg) +{ + QDF_STATUS status; + struct rso_chan_info *pref_chan_info = + &rso_cfg->cfg_param.pref_chan_info; + + if (!pref_chan_info->num_chan) + return QDF_STATUS_SUCCESS; + + status = cm_populate_roam_chan_list(vdev, mlme_obj, chan_info, + pref_chan_info); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to copy channels to roam list"); + return status; + } + cm_dump_freq_list(pref_chan_info); + chan_info->chan_cache_type = CHANNEL_LIST_DYNAMIC; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +static void +cm_fetch_ch_lst_from_received_list(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info) +{ + uint8_t i = 0; + uint8_t num_channels = 0; + qdf_freq_t *freq_lst = NULL; + enum band_info band = BAND_ALL; + struct rso_chan_info *curr_ch_lst_info = &rso_cfg->roam_scan_freq_lst; + + if (curr_ch_lst_info->num_chan == 0) + return; + + freq_lst = curr_ch_lst_info->freq_list; + for (i = 0; i < curr_ch_lst_info->num_chan; i++) { + if (cm_is_dfs_unsafe_extra_band_chan(vdev, mlme_obj, + freq_lst[i], band)) + continue; + + chan_info->chan_freq_list[num_channels++] = freq_lst[i]; + } + chan_info->chan_count = num_channels; + chan_info->chan_cache_type = CHANNEL_LIST_DYNAMIC; +} + +static inline bool cm_is_ese_assoc(struct rso_config *rso_cfg) +{ + return rso_cfg->is_ese_assoc; +} +static void cm_esr_populate_version_ie( + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_offload_params *rso_mode_cfg) +{ + static const uint8_t ese_ie[] = {0x0, 0x40, 0x96, 0x3, + ESE_VERSION_SUPPORTED}; + + /* Append ESE version IE if isEseIniFeatureEnabled INI is enabled */ + if (mlme_obj->cfg.lfr.ese_enabled) + wlan_cm_append_assoc_ies(rso_mode_cfg, WLAN_ELEMID_VENDOR, + sizeof(ese_ie), ese_ie); +} + +#else +static inline void +cm_fetch_ch_lst_from_received_list(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info) +{} +static inline bool cm_is_ese_assoc(struct rso_config *rso_cfg) +{ + return false; +} +static inline void cm_esr_populate_version_ie( + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_offload_params *rso_mode_cfg) +{} +#endif + +/** + * cm_fetch_valid_ch_lst() - fetch channel list from valid channel list and + * update rso req msg parameters + * @vdev: vdev + * @mlme_obj: mlme_obj + * @chan_info: channel info + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_fetch_valid_ch_lst(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_channel_list *chan_info) +{ + qdf_freq_t *ch_freq_list = NULL; + uint8_t i = 0, num_channels = 0; + enum band_info band = BAND_ALL; + qdf_freq_t op_freq; + + op_freq = wlan_get_operation_chan_freq(vdev); + if (mlme_obj->cfg.lfr.roam_intra_band) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(op_freq)) + band = BAND_5G; + else if (WLAN_REG_IS_24GHZ_CH_FREQ(op_freq)) + band = BAND_2G; + else + band = BAND_UNKNOWN; + } + + ch_freq_list = mlme_obj->cfg.reg.valid_channel_freq_list; + for (i = 0; i < mlme_obj->cfg.reg.valid_channel_list_num; i++) { + if (wlan_reg_is_dsrc_freq(ch_freq_list[i])) + continue; + if (cm_is_dfs_unsafe_extra_band_chan(vdev, mlme_obj, + ch_freq_list[i], + band)) + continue; + chan_info->chan_freq_list[num_channels++] = ch_freq_list[i]; + } + chan_info->chan_count = num_channels; + chan_info->chan_cache_type = CHANNEL_LIST_DYNAMIC; + + return QDF_STATUS_SUCCESS; +} + +static void +cm_update_rso_freq_list(struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info) +{ + struct wlan_chan_list *tried_freq_list; + uint8_t i; + + tried_freq_list = &rso_cfg->tried_candidate_freq_list; + + if (!tried_freq_list->num_chan) + return; + + for (i = 0; i < tried_freq_list->num_chan && + chan_info->chan_count < CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (wlan_is_channel_present_in_list(chan_info->chan_freq_list, + chan_info->chan_count, + tried_freq_list->freq_list[i])) + continue; + chan_info->chan_freq_list[chan_info->chan_count++] = + tried_freq_list->freq_list[i]; + } +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static void cm_update_rso_freq_list_from_partner_link( + struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_channel_list *chan_info) +{ + struct mlo_link_info *mlo_link_info; + uint8_t link_info_iter = 0; + qdf_freq_t chan_freq; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + mlo_link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; + for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; + link_info_iter++, mlo_link_info++) { + if (qdf_is_macaddr_zero(&mlo_link_info->ap_link_addr) || + mlo_link_info->link_id == WLAN_INVALID_LINK_ID) + continue; + chan_freq = mlo_link_info->link_chan_info->ch_freq; + if (wlan_is_channel_present_in_list(chan_info->chan_freq_list, + chan_info->chan_count, + chan_freq)) + continue; + chan_info->chan_freq_list[chan_info->chan_count++] = + chan_freq; + mlme_debug("link_id: %d added freq:%d ", + mlo_link_info->link_id, + mlo_link_info->link_chan_info->ch_freq); + } +} + +#else +static void cm_update_rso_freq_list_from_partner_link( + struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_channel_list *chan_info) +{ +} +#endif + +void cm_fill_rso_channel_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info, + uint8_t reason) +{ + QDF_STATUS status; + uint8_t ch_cache_str[128] = {0}; + uint8_t i, j; + struct rso_chan_info *specific_chan_info; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + specific_chan_info = &rso_cfg->cfg_param.specific_chan_info; + chan_info->vdev_id = vdev_id; + if (cm_is_ese_assoc(rso_cfg) || + rso_cfg->roam_scan_freq_lst.num_chan == 0) { + /* + * Retrieve the Channel Cache either from ini or from + * the occupied channels list along with preferred + * channel list configured by the client. + * Give Preference to INI Channels + */ + if (specific_chan_info->num_chan) { + status = cm_fetch_ch_lst_from_ini(vdev, mlme_obj, + chan_info, + specific_chan_info); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Fetch channel list from ini failed"); + return; + } + } else if (reason == REASON_FLUSH_CHANNEL_LIST) { + chan_info->chan_cache_type = CHANNEL_LIST_STATIC; + chan_info->chan_count = 0; + } else { + cm_fetch_ch_lst_from_occupied_lst(vdev, mlme_obj, + rso_cfg, + chan_info, reason); + /* Add the preferred channel list configured by + * client to the roam channel list along with + * occupied channel list. + */ + cm_add_ch_lst_from_roam_scan_list(vdev, mlme_obj, + chan_info, rso_cfg); + + /* + * update channel list for non assoc link + */ + cm_update_rso_freq_list_from_partner_link( + vdev, mlme_obj, chan_info); + + /* + * update the roam channel list on the top of entries + * present in the scan db which gets stored in the rso + * config during connect resp failure in + * wlan_cm_send_connect_rsp + */ + cm_update_rso_freq_list(rso_cfg, chan_info); + } + } else { + /* + * If ESE is enabled, and a neighbor Report is received, + * then Ignore the INI Channels or the Occupied Channel + * List. Consider the channels in the neighbor list sent + * by the ESE AP + */ + cm_fetch_ch_lst_from_received_list(vdev, mlme_obj, rso_cfg, + chan_info); + } + + if (!chan_info->chan_count && + reason != REASON_FLUSH_CHANNEL_LIST) { + /* Maintain the Valid Channels List */ + status = cm_fetch_valid_ch_lst(vdev, mlme_obj, chan_info); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Fetch channel list fail"); + return; + } + } + + for (i = 0, j = 0; i < chan_info->chan_count; i++) { + if (j < sizeof(ch_cache_str)) + j += snprintf(ch_cache_str + j, + sizeof(ch_cache_str) - j, " %d", + chan_info->chan_freq_list[i]); + else + break; + } + + mlme_debug("chan_cache_type:%d, No of chan:%d, chan: %s", + chan_info->chan_cache_type, + chan_info->chan_count, ch_cache_str); +} + +static void +cm_add_denylist_ap_list(struct wlan_objmgr_pdev *pdev, + struct roam_scan_filter_params *params) +{ + int i = 0; + struct reject_ap_config_params *reject_list; + + reject_list = qdf_mem_malloc(sizeof(*reject_list) * + MAX_RSSI_AVOID_BSSID_LIST); + if (!reject_list) + return; + + params->num_bssid_deny_list = + wlan_dlm_get_bssid_reject_list(pdev, reject_list, + MAX_RSSI_AVOID_BSSID_LIST, + USERSPACE_DENYLIST_TYPE); + if (!params->num_bssid_deny_list) { + qdf_mem_free(reject_list); + return; + } + + for (i = 0; i < params->num_bssid_deny_list; i++) { + qdf_copy_macaddr(¶ms->bssid_avoid_list[i], + &reject_list[i].bssid); + mlme_debug("Denylist bssid[%d]:" QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF(params->bssid_avoid_list[i].bytes)); + } + + qdf_mem_free(reject_list); +} + +/** + * cm_roam_scan_filter() - set roam scan filter parameters + * @psoc: psoc + * @pdev: pdev + * @vdev_id: vdev id + * @command: rso command + * @reason: reason to roam + * @scan_filter_params: roam scan filter related parameters + * + * There are filters such as allowlist, denylist and preferred + * list that need to be applied to the scan results to form the + * probable candidates for roaming. + * + * Return: None + */ +static void +cm_roam_scan_filter(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t command, uint8_t reason, + struct wlan_roam_scan_filter_params *scan_filter_params) +{ + int i; + uint32_t num_ssid_allow_list = 0, num_bssid_preferred_list = 0; + uint32_t op_bitmap = 0; + struct roam_scan_filter_params *params; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct rso_config_params *rso_usr_cfg; + struct rso_user_config *rso_usr_config; + struct wlan_objmgr_vdev *vdev; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + scan_filter_params->reason = reason; + params = &scan_filter_params->filter_params; + rso_usr_cfg = &mlme_obj->cfg.lfr.rso_user_config; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return; + + rso_usr_config = wlan_cm_get_rso_user_config(vdev); + if (!rso_usr_config) + goto end; + + if (command != ROAM_SCAN_OFFLOAD_STOP) { + switch (reason) { + case REASON_ROAM_SET_DENYLIST_BSSID: + op_bitmap |= ROAM_FILTER_OP_BITMAP_BLACK_LIST; + cm_add_denylist_ap_list(pdev, params); + break; + case REASON_ROAM_SET_SSID_ALLOWED: + op_bitmap |= ROAM_FILTER_OP_BITMAP_WHITE_LIST; + num_ssid_allow_list = + rso_usr_config->num_ssid_allowed_list; + break; + case REASON_ROAM_SET_FAVORED_BSSID: + op_bitmap |= ROAM_FILTER_OP_BITMAP_PREFER_BSSID; + num_bssid_preferred_list = + rso_usr_cfg->num_bssid_favored; + break; + case REASON_CTX_INIT: + if (command == ROAM_SCAN_OFFLOAD_START) { + num_ssid_allow_list = + rso_usr_config->num_ssid_allowed_list; + if (num_ssid_allow_list) + op_bitmap |= + ROAM_FILTER_OP_BITMAP_WHITE_LIST; + cm_add_denylist_ap_list(pdev, params); + if (params->num_bssid_deny_list) + op_bitmap |= + ROAM_FILTER_OP_BITMAP_BLACK_LIST; + + params->lca_disallow_config_present = true; + /* + * If rssi disallow bssid list have any member + * fill it and send it to firmware so that + * firmware does not try to roam to these BSS + * until RSSI OR time condition are matched. + */ + params->num_rssi_rejection_ap = + wlan_dlm_get_bssid_reject_list(pdev, + params->rssi_rejection_ap, + MAX_RSSI_AVOID_BSSID_LIST, + DRIVER_RSSI_REJECT_TYPE); + } else { + mlme_debug("Roam Filter need not be sent, no need to fill parameters"); + goto end; + } + break; + default: + if (command == ROAM_SCAN_OFFLOAD_START) { + num_ssid_allow_list = + rso_usr_config->num_ssid_allowed_list; + if (num_ssid_allow_list) + op_bitmap |= + ROAM_FILTER_OP_BITMAP_WHITE_LIST; + cm_add_denylist_ap_list(pdev, params); + if (params->num_bssid_deny_list) + op_bitmap |= + ROAM_FILTER_OP_BITMAP_BLACK_LIST; + } + if (!op_bitmap) { + mlme_debug("Roam Filter need not be sent, no need to fill parameters"); + goto end; + } + break; + } + } else { + /* In case of STOP command, reset all the variables + * except for denylist BSSID which should be retained + * across connections. + */ + op_bitmap = ROAM_FILTER_OP_BITMAP_WHITE_LIST | + ROAM_FILTER_OP_BITMAP_PREFER_BSSID; + if (reason == REASON_ROAM_SET_SSID_ALLOWED) + num_ssid_allow_list = + rso_usr_config->num_ssid_allowed_list; + num_bssid_preferred_list = rso_usr_cfg->num_bssid_favored; + } + + /* fill in fixed values */ + params->vdev_id = vdev_id; + params->op_bitmap = op_bitmap; + params->num_ssid_allow_list = num_ssid_allow_list; + params->num_bssid_preferred_list = num_bssid_preferred_list; + params->delta_rssi = + wlan_dlm_get_rssi_denylist_threshold(pdev); + + for (i = 0; i < num_ssid_allow_list; i++) { + qdf_mem_copy(params->ssid_allowed_list[i].ssid, + rso_usr_config->ssid_allowed_list[i].ssid, + rso_usr_config->ssid_allowed_list[i].length); + params->ssid_allowed_list[i].length = + rso_usr_config->ssid_allowed_list[i].length; + mlme_debug("SSID %d: " QDF_SSID_FMT, i, + QDF_SSID_REF(params->ssid_allowed_list[i].length, + params->ssid_allowed_list[i].ssid)); + } + + if (params->num_bssid_preferred_list) { + qdf_mem_copy(params->bssid_favored, rso_usr_cfg->bssid_favored, + MAX_BSSID_FAVORED * sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params->bssid_favored_factor, + rso_usr_cfg->bssid_favored_factor, + MAX_BSSID_FAVORED); + } + for (i = 0; i < params->num_rssi_rejection_ap; i++) + mlme_debug("RSSI reject BSSID "QDF_MAC_ADDR_FMT" expected rssi %d remaining duration %d", + QDF_MAC_ADDR_REF(params->rssi_rejection_ap[i].bssid.bytes), + params->rssi_rejection_ap[i].expected_rssi, + params->rssi_rejection_ap[i].reject_duration); + + for (i = 0; i < params->num_bssid_preferred_list; i++) + mlme_debug("Preferred Bssid[%d]:"QDF_MAC_ADDR_FMT" score: %d", i, + QDF_MAC_ADDR_REF(params->bssid_favored[i].bytes), + params->bssid_favored_factor[i]); + + if (params->lca_disallow_config_present) { + params->disallow_duration + = mlme_obj->cfg.lfr.lfr3_disallow_duration; + params->rssi_channel_penalization + = mlme_obj->cfg.lfr.lfr3_rssi_channel_penalization; + params->num_disallowed_aps + = mlme_obj->cfg.lfr.lfr3_num_disallowed_aps; + mlme_debug("disallow_dur %d rssi_chan_pen %d num_disallowed_aps %d", + params->disallow_duration, + params->rssi_channel_penalization, + params->num_disallowed_aps); + } + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; +} + +#ifdef CONFIG_BAND_6GHZ +static void +cm_fill_6ghz_dwell_times(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_scan_params *scan_params) +{ + wlan_scan_cfg_get_active_6g_dwelltime( + psoc, + &scan_params->dwell_time_active_6ghz); + + wlan_scan_cfg_get_passive_6g_dwelltime( + psoc, + &scan_params->dwell_time_passive_6ghz); +} +#else +static inline void +cm_fill_6ghz_dwell_times(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_scan_params *scan_params) +{} +#endif + +static void +cm_roam_scan_offload_fill_scan_params(struct wlan_objmgr_psoc *psoc, + struct rso_config *rso_cfg, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_offload_params *rso_mode_cfg, + struct wlan_roam_scan_channel_list *rso_chan_info, + uint8_t command) +{ + struct wlan_roam_scan_params *scan_params = + &rso_mode_cfg->rso_scan_params; + uint8_t channels_per_burst = 0; + uint16_t roam_scan_home_away_time; + enum roaming_dfs_channel_type allow_dfs_ch_roam; + struct rso_cfg_params *cfg_params; + + qdf_mem_zero(scan_params, sizeof(*scan_params)); + if (command == ROAM_SCAN_OFFLOAD_STOP) + return; + + cfg_params = &rso_cfg->cfg_param; + + /* Parameters updated after association is complete */ + scan_params->dwell_time_passive = cfg_params->passive_max_chan_time; + + wlan_scan_cfg_get_min_dwelltime_6g(psoc, + &scan_params->min_dwell_time_6ghz); + /* + * Here is the formula, + * T(HomeAway) = N * T(dwell) + (N+1) * T(cs) + * where N is number of channels scanned in single burst + */ + scan_params->dwell_time_active = cfg_params->max_chan_scan_time; + + roam_scan_home_away_time = cfg_params->roam_scan_home_away_time; + + if (roam_scan_home_away_time < + (scan_params->dwell_time_active + + (2 * ROAM_SCAN_CHANNEL_SWITCH_TIME))) { + mlme_debug("Disable Home away time(%d) as it is less than (2*RF switching time + channel max time)(%d)", + roam_scan_home_away_time, + (scan_params->dwell_time_active + + (2 * ROAM_SCAN_CHANNEL_SWITCH_TIME))); + roam_scan_home_away_time = 0; + } + + if (roam_scan_home_away_time < (2 * ROAM_SCAN_CHANNEL_SWITCH_TIME)) { + /* clearly we can't follow home away time. + * Make it a split scan. + */ + scan_params->burst_duration = 0; + } else { + channels_per_burst = + (roam_scan_home_away_time - ROAM_SCAN_CHANNEL_SWITCH_TIME) / + (scan_params->dwell_time_active + ROAM_SCAN_CHANNEL_SWITCH_TIME); + + if (channels_per_burst < 1) { + /* dwell time and home away time conflicts */ + /* we will override dwell time */ + scan_params->dwell_time_active = + roam_scan_home_away_time - + (2 * ROAM_SCAN_CHANNEL_SWITCH_TIME); + scan_params->burst_duration = + scan_params->dwell_time_active; + } else { + scan_params->burst_duration = + channels_per_burst * + scan_params->dwell_time_active; + } + } + + allow_dfs_ch_roam = mlme_obj->cfg.lfr.roaming_dfs_channel; + /* Roaming on DFS channels is supported and it is not + * app channel list. It is ok to override homeAwayTime + * to accommodate DFS dwell time in burst + * duration. + */ + if (allow_dfs_ch_roam == ROAMING_DFS_CHANNEL_ENABLED_NORMAL && + roam_scan_home_away_time > 0 && + rso_chan_info->chan_cache_type != CHANNEL_LIST_STATIC) + scan_params->burst_duration = + QDF_MAX(scan_params->burst_duration, + scan_params->dwell_time_passive); + + scan_params->min_rest_time = cfg_params->neighbor_scan_min_period; + scan_params->max_rest_time = cfg_params->neighbor_scan_period; + scan_params->repeat_probe_time = + (cfg_params->roam_scan_n_probes > 0) ? + QDF_MAX(scan_params->dwell_time_active / + cfg_params->roam_scan_n_probes, 1) : 0; + scan_params->probe_spacing_time = 0; + scan_params->probe_delay = 0; + /* 30 seconds for full scan cycle */ + scan_params->max_scan_time = ROAM_SCAN_HW_DEF_SCAN_MAX_DURATION; + scan_params->idle_time = scan_params->min_rest_time; + scan_params->n_probes = cfg_params->roam_scan_n_probes; + + if (allow_dfs_ch_roam == ROAMING_DFS_CHANNEL_DISABLED) { + scan_params->scan_ctrl_flags |= WMI_SCAN_BYPASS_DFS_CHN; + } else { + /* Roaming scan on DFS channel is allowed. + * No need to change any flags for default + * allowDFSChannelRoam = 1. + * Special case where static channel list is given by\ + * application that contains DFS channels. + * Assume that the application has knowledge of matching + * APs being active and that probe request transmission + * is permitted on those channel. + * Force active scans on those channels. + */ + + if (allow_dfs_ch_roam == + ROAMING_DFS_CHANNEL_ENABLED_ACTIVE && + rso_chan_info->chan_cache_type == CHANNEL_LIST_STATIC && + rso_chan_info->chan_count) + scan_params->scan_ctrl_flags |= + WMI_SCAN_FLAG_FORCE_ACTIVE_ON_DFS; + } + + scan_params->rso_adaptive_dwell_mode = + mlme_obj->cfg.lfr.adaptive_roamscan_dwell_mode; + + cm_fill_6ghz_dwell_times(psoc, scan_params); + + mlme_debug("dwell time passive:%d, active:%d, home_away_time:%d, burst_duration:%d, max_rest_time:%d", + scan_params->dwell_time_passive, + scan_params->dwell_time_active, roam_scan_home_away_time, + scan_params->burst_duration, scan_params->max_rest_time); +} + +void wlan_cm_append_assoc_ies(struct wlan_roam_scan_offload_params *rso_mode_cfg, + uint8_t ie_id, uint8_t ie_len, + const uint8_t *ie_data) +{ + uint32_t curr_length = rso_mode_cfg->assoc_ie_length; + + if ((MAC_MAX_ADD_IE_LENGTH - curr_length) < ie_len) { + mlme_err("Appending IE id: %d failed", ie_id); + return; + } + + rso_mode_cfg->assoc_ie[curr_length] = ie_id; + rso_mode_cfg->assoc_ie[curr_length + 1] = ie_len; + qdf_mem_copy(&rso_mode_cfg->assoc_ie[curr_length + 2], ie_data, ie_len); + rso_mode_cfg->assoc_ie_length += (ie_len + 2); +} + +void wlan_add_supported_5Ghz_channels(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t *chan_list, + uint8_t *num_chnl, + bool supp_chan_ie) +{ + uint16_t i, j = 0; + uint32_t size = 0; + uint32_t *freq_list; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + if (!chan_list) { + mlme_err("chan_list buffer NULL"); + *num_chnl = 0; + return; + } + size = mlme_obj->cfg.reg.valid_channel_list_num; + freq_list = mlme_obj->cfg.reg.valid_channel_freq_list; + for (i = 0, j = 0; i < size; i++) { + if (wlan_reg_is_dsrc_freq(freq_list[i])) + continue; + /* Only add 5ghz channels.*/ + if (WLAN_REG_IS_5GHZ_CH_FREQ(freq_list[i])) { + chan_list[j] = + wlan_reg_freq_to_chan(pdev, + freq_list[i]); + j++; + + if (supp_chan_ie) { + chan_list[j] = 1; + j++; + } + } + } + *num_chnl = (uint8_t)j; +} + +static void cm_update_driver_assoc_ies(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_roam_scan_offload_params *rso_mode_cfg) +{ + bool power_caps_populated = false; + uint8_t *rrm_cap_ie_data; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + uint8_t power_cap_ie_data[DOT11F_IE_POWERCAPS_MAX_LEN] = { + MIN_TX_PWR_CAP, MAX_TX_PWR_CAP}; + uint8_t max_tx_pwr_cap = 0; + struct wlan_objmgr_pdev *pdev; + uint8_t supp_chan_ie[DOT11F_IE_SUPPCHANNELS_MAX_LEN], supp_chan_ie_len; + static const uint8_t qcn_ie[] = {0x8C, 0xFD, 0xF0, 0x1, + QCN_IE_VERSION_SUBATTR_ID, + QCN_IE_VERSION_SUBATTR_DATA_LEN, + QCN_IE_VERSION_SUPPORTED, + QCN_IE_SUBVERSION_SUPPORTED}; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return; + + rrm_cap_ie_data = wlan_cm_get_rrm_cap_ie_data(); + /* Re-Assoc IE TLV parameters */ + rso_mode_cfg->assoc_ie_length = rso_cfg->assoc_ie.len; + qdf_mem_copy(rso_mode_cfg->assoc_ie, rso_cfg->assoc_ie.ptr, + rso_mode_cfg->assoc_ie_length); + + max_tx_pwr_cap = wlan_get_cfg_max_tx_power(psoc, pdev, + wlan_get_operation_chan_freq(vdev)); + + if (max_tx_pwr_cap && max_tx_pwr_cap < MAX_TX_PWR_CAP) + power_cap_ie_data[1] = max_tx_pwr_cap; + else + power_cap_ie_data[1] = MAX_TX_PWR_CAP; + + if (mlme_obj->cfg.gen.enabled_11h) { + /* Append power cap IE */ + wlan_cm_append_assoc_ies(rso_mode_cfg, WLAN_ELEMID_PWRCAP, + DOT11F_IE_POWERCAPS_MAX_LEN, + power_cap_ie_data); + power_caps_populated = true; + + /* Append Supported channels IE */ + wlan_add_supported_5Ghz_channels(psoc, pdev, supp_chan_ie, + &supp_chan_ie_len, true); + + wlan_cm_append_assoc_ies(rso_mode_cfg, + WLAN_ELEMID_SUPPCHAN, + supp_chan_ie_len, supp_chan_ie); + } + + cm_esr_populate_version_ie(mlme_obj, rso_mode_cfg); + + if (mlme_obj->cfg.rrm_config.rrm_enabled) { + /* Append RRM IE */ + if (rrm_cap_ie_data) + wlan_cm_append_assoc_ies(rso_mode_cfg, WLAN_ELEMID_RRM, + DOT11F_IE_RRMENABLEDCAP_MAX_LEN, + rrm_cap_ie_data); + + /* Append Power cap IE if not appended already */ + if (!power_caps_populated) + wlan_cm_append_assoc_ies(rso_mode_cfg, + WLAN_ELEMID_PWRCAP, + DOT11F_IE_POWERCAPS_MAX_LEN, + power_cap_ie_data); + } + + wlan_cm_ese_populate_additional_ies(pdev, mlme_obj, vdev_id, + rso_mode_cfg); + + /* Append QCN IE if g_support_qcn_ie INI is enabled */ + if (mlme_obj->cfg.sta.qcn_ie_support) + wlan_cm_append_assoc_ies(rso_mode_cfg, WLAN_ELEMID_VENDOR, + sizeof(qcn_ie), qcn_ie); +} + +static void +cm_roam_scan_offload_fill_rso_configs(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_roam_scan_offload_params *rso_mode_cfg, + struct wlan_roam_scan_channel_list *rso_chan_info, + uint8_t command, uint16_t reason) +{ + uint32_t mode = 0; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + qdf_mem_zero(rso_mode_cfg, sizeof(*rso_mode_cfg)); + rso_mode_cfg->vdev_id = vdev_id; + rso_mode_cfg->is_rso_stop = (command == ROAM_SCAN_OFFLOAD_STOP); + rso_mode_cfg->roaming_scan_policy = + mlme_obj->cfg.lfr.roaming_scan_policy; + + /* Fill ROAM SCAN mode TLV parameters */ + if (rso_cfg->cfg_param.empty_scan_refresh_period) + mode |= WMI_ROAM_SCAN_MODE_PERIODIC; + + rso_mode_cfg->rso_mode_info.min_delay_btw_scans = + mlme_obj->cfg.lfr.min_delay_btw_roam_scans; + rso_mode_cfg->rso_mode_info.min_delay_roam_trigger_bitmask = + mlme_obj->cfg.lfr.roam_trigger_reason_bitmask; + + if (command == ROAM_SCAN_OFFLOAD_STOP) { + if (reason == REASON_ROAM_STOP_ALL || + reason == REASON_DISCONNECTED || + reason == REASON_ROAM_SYNCH_FAILED || + reason == REASON_ROAM_SET_PRIMARY) { + mode = WMI_ROAM_SCAN_MODE_NONE; + } else { + if (wlan_is_roam_offload_enabled(mlme_obj->cfg.lfr)) + mode = WMI_ROAM_SCAN_MODE_NONE | + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; + else + mode = WMI_ROAM_SCAN_MODE_NONE; + } + } + + rso_mode_cfg->rso_mode_info.roam_scan_mode = mode; + if (command == ROAM_SCAN_OFFLOAD_STOP) + return; + + cm_roam_scan_offload_fill_lfr3_config(vdev, rso_cfg, rso_mode_cfg, + mlme_obj, command, &mode); + rso_mode_cfg->rso_mode_info.roam_scan_mode = mode; + cm_roam_scan_offload_fill_scan_params(psoc, rso_cfg, mlme_obj, + rso_mode_cfg, rso_chan_info, + command); + cm_update_driver_assoc_ies(psoc, vdev, rso_cfg, mlme_obj, rso_mode_cfg); + cm_roam_scan_offload_add_fils_params(psoc, rso_mode_cfg, vdev_id); +} + +bool cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_peer *peer; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + struct cm_roam_values_copy temp; + bool is_pmf_enabled, mbo_oce_enabled_ap, is_open_connection; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return false; + } + is_open_connection = cm_is_open_mode(vdev); + wlan_vdev_mgr_get_param_bssid(vdev, bssid); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + peer = wlan_objmgr_get_peer_by_mac(psoc, bssid, WLAN_MLME_CM_ID); + if (!peer) { + mlme_debug("Peer of peer_mac "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(bssid)); + return false; + } + is_pmf_enabled = mlme_get_peer_pmf_status(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_CM_ID); + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, MBO_OCE_ENABLED_AP, &temp); + mbo_oce_enabled_ap = !!temp.uint_value; + + mlme_debug("vdev %d, is_pmf_enabled %d mbo_oce_enabled_ap:%d is_open_connection: %d for "QDF_MAC_ADDR_FMT, + vdev_id, is_pmf_enabled, mbo_oce_enabled_ap, + is_open_connection, QDF_MAC_ADDR_REF(bssid)); + + return !is_pmf_enabled && mbo_oce_enabled_ap && !is_open_connection; +} + +/** + * cm_update_btm_offload_config() - Update btm config param to fw + * @psoc: psoc + * @vdev: vdev + * @command: Roam offload command + * @btm_offload_config: btm offload config + * + * Return: None + */ +static void +cm_update_btm_offload_config(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t command, uint32_t *btm_offload_config) + +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_btm *btm_cfg; + bool is_hs_20_ap, is_hs_20_btm_offload_disabled; + struct cm_roam_values_copy temp; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + bool abridge_flag, is_disable_btm, assoc_btm_cap; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + btm_cfg = &mlme_obj->cfg.btm; + *btm_offload_config = btm_cfg->btm_offload_config; + /* Return if INI is disabled */ + if (!(*btm_offload_config)) + return; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, IS_DISABLE_BTM, &temp); + is_disable_btm = temp.bool_value; + assoc_btm_cap = wlan_cm_get_assoc_btm_cap(psoc, vdev_id); + if (!assoc_btm_cap || is_disable_btm) { + mlme_debug("disable btm offload vdev:%d btm_cap: %d is_btm: %d", + vdev_id, assoc_btm_cap, is_disable_btm); + *btm_offload_config = 0; + return; + } + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, HS_20_AP, &temp); + is_hs_20_ap = temp.bool_value; + wlan_mlme_is_hs_20_btm_offload_disabled(psoc, + &is_hs_20_btm_offload_disabled); + + /* + * For RSO Stop/Passpoint R2 cert test case 5.11(when STA is connected + * to Hotspot-2.0 AP), disable BTM offload to firmware + */ + if (command == ROAM_SCAN_OFFLOAD_STOP || + (is_hs_20_ap && is_hs_20_btm_offload_disabled)) { + mlme_debug("RSO cmd: %d is_hs_20_ap:%d", command, + is_hs_20_ap); + *btm_offload_config = 0; + return; + } + + abridge_flag = wlan_mlme_get_btm_abridge_flag(psoc); + if (!abridge_flag) + MLME_CLEAR_BIT(*btm_offload_config, + BTM_OFFLOAD_CONFIG_BIT_7); + /* + * If peer does not support PMF in case of OCE/MBO + * Connection, Disable BTM offload to firmware. + */ + if (cm_is_mbo_ap_without_pmf(psoc, vdev_id)) + *btm_offload_config = 0; + + mlme_debug("Abridge flag: %d, btm offload: %u", abridge_flag, + *btm_offload_config); +} + +/** + * cm_roam_scan_btm_offload() - set roam scan btm offload parameters + * @psoc: psoc ctx + * @vdev: vdev + * @params: roam scan btm offload parameters + * @rso_cfg: rso config + * + * This function is used to set roam scan btm offload related parameters + * + * Return: None + */ +static void +cm_roam_scan_btm_offload(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_btm_config *params, + struct rso_config *rso_cfg) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_btm *btm_cfg; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + btm_cfg = &mlme_obj->cfg.btm; + params->vdev_id = wlan_vdev_get_id(vdev); + cm_update_btm_offload_config(psoc, vdev, ROAM_SCAN_OFFLOAD_START, + ¶ms->btm_offload_config); + params->btm_solicited_timeout = btm_cfg->btm_solicited_timeout; + params->btm_max_attempt_cnt = btm_cfg->btm_max_attempt_cnt; + params->btm_sticky_time = btm_cfg->btm_sticky_time; + params->disassoc_timer_threshold = btm_cfg->disassoc_timer_threshold; + params->btm_query_bitmask = btm_cfg->btm_query_bitmask; + params->btm_candidate_min_score = btm_cfg->btm_trig_min_candidate_score; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * cm_roam_mlo_config() - set roam mlo offload parameters + * @psoc: psoc ctx + * @vdev: vdev + * @start_req: request to fill + * + * This function is used to set roam mlo offload related parameters + * + * Return: None + */ +static void +cm_roam_mlo_config(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_start_config *start_req) +{ + struct wlan_roam_mlo_config *roam_mlo_params; + struct rso_config *rso_cfg; + + roam_mlo_params = &start_req->roam_mlo_params; + roam_mlo_params->vdev_id = wlan_vdev_get_id(vdev); + roam_mlo_params->support_link_num = + wlan_mlme_get_sta_mlo_conn_max_num(psoc); + roam_mlo_params->support_link_band = + wlan_mlme_get_sta_mlo_conn_band_bmp(psoc); + roam_mlo_params->mlo_5gl_5gh_mlsr = + wlan_mlme_is_5gl_5gh_mlsr_supported(psoc); + + /* + * Update the supported link band based on roam_band_bitmap + * Roam band bitmap is modified during NCHO mode enable, disable and + * regulatory supported band changes. + */ + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + + roam_mlo_params->support_link_band &= + rso_cfg->roam_band_bitmask; +} +#else +static void +cm_roam_mlo_config(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_start_config *start_req) +{ +} +#endif + +/** + * cm_roam_offload_11k_params() - set roam 11k offload parameters + * @psoc: psoc ctx + * @vdev: vdev + * @params: roam 11k offload parameters + * @enabled: 11k offload enabled/disabled + * + * This function is used to set roam 11k offload related parameters + * + * Return: None + */ +static void +cm_roam_offload_11k_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_11k_offload_params *params, + bool enabled) +{ + struct cm_roam_neighbor_report_offload_params *neighbor_report_offload; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + neighbor_report_offload = + &mlme_obj->cfg.lfr.rso_user_config.neighbor_report_offload; + + params->vdev_id = wlan_vdev_get_id(vdev); + + if (enabled) { + params->offload_11k_bitmask = + neighbor_report_offload->offload_11k_enable_bitmask; + } else { + params->offload_11k_bitmask = 0; + return; + } + + /* + * If none of the parameters are enabled, then set the + * offload_11k_bitmask to 0, so that we don't send the command + * to the FW and drop it in WMA + */ + if ((neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_ALL) == 0) { + mlme_err("No valid neighbor report offload params %x", + neighbor_report_offload->params_bitmask); + params->offload_11k_bitmask = 0; + return; + } + + /* + * First initialize all params to NEIGHBOR_REPORT_PARAM_INVALID + * Then set the values that are enabled + */ + params->neighbor_report_params.time_offset = + NEIGHBOR_REPORT_PARAM_INVALID; + params->neighbor_report_params.low_rssi_offset = + NEIGHBOR_REPORT_PARAM_INVALID; + params->neighbor_report_params.bmiss_count_trigger = + NEIGHBOR_REPORT_PARAM_INVALID; + params->neighbor_report_params.per_threshold_offset = + NEIGHBOR_REPORT_PARAM_INVALID; + params->neighbor_report_params.neighbor_report_cache_timeout = + NEIGHBOR_REPORT_PARAM_INVALID; + params->neighbor_report_params.max_neighbor_report_req_cap = + NEIGHBOR_REPORT_PARAM_INVALID; + + if (neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_TIME_OFFSET) + params->neighbor_report_params.time_offset = + neighbor_report_offload->time_offset; + + if (neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_LOW_RSSI_OFFSET) + params->neighbor_report_params.low_rssi_offset = + neighbor_report_offload->low_rssi_offset; + + if (neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_BMISS_COUNT_TRIGGER) + params->neighbor_report_params.bmiss_count_trigger = + neighbor_report_offload->bmiss_count_trigger; + + if (neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_PER_THRESHOLD_OFFSET) + params->neighbor_report_params.per_threshold_offset = + neighbor_report_offload->per_threshold_offset; + + if (neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_CACHE_TIMEOUT) + params->neighbor_report_params.neighbor_report_cache_timeout = + neighbor_report_offload->neighbor_report_cache_timeout; + + if (neighbor_report_offload->params_bitmask & + NEIGHBOR_REPORT_PARAMS_MAX_REQ_CAP) + params->neighbor_report_params.max_neighbor_report_req_cap = + neighbor_report_offload->max_neighbor_report_req_cap; + + wlan_vdev_mlme_get_ssid(vdev, params->neighbor_report_params.ssid.ssid, + ¶ms->neighbor_report_params.ssid.length); +} + +/** + * cm_roam_start_req() - roam start request handling + * @psoc: psoc pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_start_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + struct wlan_roam_start_config *start_req; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct cm_roam_values_copy temp; + + start_req = qdf_mem_malloc(sizeof(*start_req)); + if (!start_req) + return QDF_STATUS_E_NOMEM; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + goto free_mem; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto rel_vdev_ref; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + goto rel_vdev_ref; + + cm_roam_set_roam_reason_better_ap(psoc, vdev_id, false); + /* fill from mlme directly */ + cm_roam_scan_bmiss_cnt(psoc, vdev_id, &start_req->beacon_miss_cnt); + cm_roam_scan_bmiss_timeout(psoc, vdev_id, &start_req->bmiss_timeout); + cm_roam_reason_vsie(psoc, vdev_id, &start_req->reason_vsie_enable); + cm_roam_triggers(psoc, vdev_id, &start_req->roam_triggers); + cm_roam_fill_rssi_change_params(psoc, vdev_id, + &start_req->rssi_change_params); + cm_roam_mawc_params(psoc, vdev_id, &start_req->mawc_params); + cm_roam_bss_load_config(psoc, vdev_id, &start_req->bss_load_config); + cm_roam_disconnect_params(psoc, vdev_id, &start_req->disconnect_params); + cm_roam_idle_params(psoc, vdev_id, &start_req->idle_params); + if (!(BIT(ROAM_TRIGGER_REASON_IDLE) & + start_req->roam_triggers.trigger_bitmap)) + start_req->idle_params.enable = false; + + cm_roam_scan_offload_rssi_thresh(psoc, vdev_id, + &start_req->rssi_params, rso_cfg); + cm_roam_scan_offload_scan_period(vdev_id, + &start_req->scan_period_params, + rso_cfg); + cm_roam_scan_offload_ap_profile(psoc, vdev, rso_cfg, + &start_req->profile_params); + cm_fill_rso_channel_list(psoc, vdev, rso_cfg, &start_req->rso_chan_info, + reason); + cm_roam_scan_filter(psoc, pdev, vdev_id, ROAM_SCAN_OFFLOAD_START, + reason, &start_req->scan_filter_params); + cm_roam_scan_offload_fill_rso_configs(psoc, vdev, rso_cfg, + &start_req->rso_config, + &start_req->rso_chan_info, + ROAM_SCAN_OFFLOAD_START, + reason); + cm_roam_scan_btm_offload(psoc, vdev, &start_req->btm_config, rso_cfg); + cm_roam_offload_11k_params(psoc, vdev, &start_req->roam_11k_params, + true); + start_req->wlan_roam_rt_stats_config = + wlan_cm_get_roam_rt_stats(psoc, ROAM_RT_STATS_ENABLE); + cm_roam_mlo_config(psoc, vdev, start_req); + + start_req->wlan_roam_ho_delay_config = + wlan_cm_roam_get_ho_delay_config(psoc); + + start_req->wlan_exclude_rm_partial_scan_freq = + wlan_cm_get_exclude_rm_partial_scan_freq(psoc); + + start_req->wlan_roam_full_scan_6ghz_on_disc = + wlan_cm_roam_get_full_scan_6ghz_on_disc(psoc); + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_RSSI_DIFF_6GHZ, &temp); + start_req->wlan_roam_rssi_diff_6ghz = temp.uint_value; + + status = wlan_cm_tgt_send_roam_start_req(psoc, vdev_id, start_req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send roam start"); + +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +free_mem: + qdf_mem_free(start_req); + + return status; +} + +/** + * cm_roam_update_config_req() - roam update config request handling + * @psoc: psoc pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_update_config_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + struct wlan_roam_update_config *update_req; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct cm_roam_values_copy temp; + + cm_roam_set_roam_reason_better_ap(psoc, vdev_id, false); + + update_req = qdf_mem_malloc(sizeof(*update_req)); + if (!update_req) + return QDF_STATUS_E_NOMEM; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + goto free_mem; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto rel_vdev_ref; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + goto rel_vdev_ref; + + /* fill from mlme directly */ + cm_roam_scan_bmiss_cnt(psoc, vdev_id, &update_req->beacon_miss_cnt); + cm_roam_scan_bmiss_timeout(psoc, vdev_id, &update_req->bmiss_timeout); + cm_roam_fill_rssi_change_params(psoc, vdev_id, + &update_req->rssi_change_params); + if (MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + cm_roam_disconnect_params(psoc, vdev_id, + &update_req->disconnect_params); + cm_roam_triggers(psoc, vdev_id, + &update_req->roam_triggers); + cm_roam_idle_params(psoc, vdev_id, + &update_req->idle_params); + if (!(BIT(ROAM_TRIGGER_REASON_IDLE) & + update_req->roam_triggers.trigger_bitmap)) + update_req->idle_params.enable = false; + } + cm_roam_scan_offload_rssi_thresh(psoc, vdev_id, + &update_req->rssi_params, rso_cfg); + cm_roam_scan_offload_scan_period(vdev_id, + &update_req->scan_period_params, + rso_cfg); + cm_roam_scan_offload_ap_profile(psoc, vdev, rso_cfg, + &update_req->profile_params); + cm_fill_rso_channel_list(psoc, vdev, rso_cfg, + &update_req->rso_chan_info, reason); + cm_roam_scan_filter(psoc, pdev, vdev_id, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + reason, &update_req->scan_filter_params); + cm_roam_scan_offload_fill_rso_configs(psoc, vdev, rso_cfg, + &update_req->rso_config, + &update_req->rso_chan_info, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + reason); + update_req->wlan_roam_rt_stats_config = + wlan_cm_get_roam_rt_stats(psoc, ROAM_RT_STATS_ENABLE); + + update_req->wlan_roam_ho_delay_config = + wlan_cm_roam_get_ho_delay_config(psoc); + + update_req->wlan_exclude_rm_partial_scan_freq = + wlan_cm_get_exclude_rm_partial_scan_freq(psoc); + + update_req->wlan_roam_full_scan_6ghz_on_disc = + wlan_cm_roam_get_full_scan_6ghz_on_disc(psoc); + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_RSSI_DIFF_6GHZ, &temp); + update_req->wlan_roam_rssi_diff_6ghz = temp.uint_value; + + status = wlan_cm_tgt_send_roam_update_req(psoc, vdev_id, update_req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send update config"); + +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +free_mem: + qdf_mem_free(update_req); + + return status; +} + +/** + * cm_roam_restart_req() - roam restart req for LFR2 + * @psoc: psoc pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_restart_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + /* Rome offload engine does not stop after any scan. + * If this command is sent because all preauth attempts failed + * and WMI_ROAM_REASON_SUITABLE_AP event was received earlier, + * now it is time to call it heartbeat failure. + */ + if ((reason == REASON_PREAUTH_FAILED_FOR_ALL || + reason == REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW) && + mlme_get_roam_reason_better_ap(vdev)) { + mlme_err("Sending heartbeat failure, reason %d", reason); + wlan_cm_send_beacon_miss(vdev_id, mlme_get_hb_ap_rssi(vdev)); + mlme_set_roam_reason_better_ap(vdev, false); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_abort_req() - roam scan abort req + * @psoc: psoc pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + QDF_STATUS status; + + status = wlan_cm_tgt_send_roam_abort_req(psoc, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send abort start"); + + return status; +} + +static void cm_fill_stop_reason(struct wlan_roam_stop_config *stop_req, + uint8_t reason) +{ + if (reason == REASON_ROAM_SYNCH_FAILED) + stop_req->reason = REASON_ROAM_SYNCH_FAILED; + else if (reason == REASON_DRIVER_DISABLED || + reason == REASON_VDEV_RESTART_FROM_HOST) + stop_req->reason = REASON_ROAM_STOP_ALL; + else if (reason == REASON_SUPPLICANT_DISABLED_ROAMING) + stop_req->reason = REASON_SUPPLICANT_DISABLED_ROAMING; + else if (reason == REASON_DISCONNECTED) + stop_req->reason = REASON_DISCONNECTED; + else if (reason == REASON_OS_REQUESTED_ROAMING_NOW) + stop_req->reason = REASON_OS_REQUESTED_ROAMING_NOW; + else if (reason == REASON_ROAM_SET_PRIMARY) + stop_req->reason = REASON_ROAM_SET_PRIMARY; + else + stop_req->reason = REASON_SME_ISSUED; +} + +QDF_STATUS +cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason, bool *send_resp, bool start_timer) +{ + struct wlan_roam_stop_config *stop_req; + QDF_STATUS status; + struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + + cm_roam_set_roam_reason_better_ap(psoc, vdev_id, false); + stop_req = qdf_mem_malloc(sizeof(*stop_req)); + if (!stop_req) + return QDF_STATUS_E_NOMEM; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + goto free_mem; + } + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_debug("MLO ROAM: skip RSO cmd for link vdev %d", vdev_id); + goto rel_vdev_ref; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto rel_vdev_ref; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + goto rel_vdev_ref; + + mlme_debug("vdev:%d process rso stop for reason: %d", vdev_id, reason); + + stop_req->btm_config.vdev_id = vdev_id; + if (reason == REASON_SUPPLICANT_DISABLED_ROAMING) + MLME_SET_BIT(stop_req->btm_config.btm_offload_config, + BTM_OFFLOAD_CONFIG_BIT_0); + stop_req->disconnect_params.vdev_id = vdev_id; + stop_req->idle_params.vdev_id = vdev_id; + stop_req->roam_triggers.vdev_id = vdev_id; + stop_req->rssi_params.vdev_id = vdev_id; + stop_req->roam_11k_params.vdev_id = vdev_id; + cm_fill_stop_reason(stop_req, reason); + if (wlan_cm_host_roam_in_progress(psoc, vdev_id)) + stop_req->middle_of_roaming = 1; + if (send_resp) + stop_req->send_rso_stop_resp = *send_resp; + stop_req->start_rso_stop_timer = start_timer; + /* + * If roam synch propagation is in progress and an user space + * disconnect is requested, then there is no need to send the + * RSO STOP to firmware, since the roaming is already complete. + * If the RSO STOP is sent to firmware, then an HO_FAIL will be + * generated and the expectation from firmware would be to + * clean up the peer context on the host and not send down any + * WMI PEER DELETE commands to firmware. But, if the user space + * disconnect gets processed first, then there is a chance to + * send down the PEER DELETE commands. Hence, if we do not + * receive the HO_FAIL, and we complete the roam sync + * propagation, then the host and firmware will be in sync with + * respect to the peer and then the user space disconnect can + * be handled gracefully in a normal way. + * + * Ensure to check the reason code since the RSO Stop might + * come when roam sync failed as well and at that point it + * should go through to the firmware and receive HO_FAIL + * and clean up. + */ + if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) && + stop_req->reason == REASON_ROAM_STOP_ALL) { + mlme_info("vdev_id:%d : Drop RSO stop during roam sync", + vdev_id); + goto rel_vdev_ref; + } + + wlan_mlme_defer_pmk_set_in_roaming(psoc, vdev_id, false); + + cm_roam_scan_filter(psoc, pdev, vdev_id, ROAM_SCAN_OFFLOAD_STOP, + reason, &stop_req->scan_filter_params); + cm_roam_scan_offload_fill_rso_configs(psoc, vdev, rso_cfg, + &stop_req->rso_config, + NULL, ROAM_SCAN_OFFLOAD_STOP, + stop_req->reason); + + status = wlan_cm_tgt_send_roam_stop_req(psoc, vdev_id, stop_req); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("fail to send roam stop"); + } + if (send_resp) + *send_resp = stop_req->send_rso_stop_resp; + +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +free_mem: + qdf_mem_free(stop_req); + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_fill_per_roam_request() - create PER roam offload config request + * @psoc: psoc context + * @req: request to fill + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_fill_per_roam_request(struct wlan_objmgr_psoc *psoc, + struct wlan_per_roam_config_req *req) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + req->per_config.enable = mlme_obj->cfg.lfr.per_roam_enable; + req->per_config.tx_high_rate_thresh = + mlme_obj->cfg.lfr.per_roam_config_high_rate_th; + req->per_config.rx_high_rate_thresh = + mlme_obj->cfg.lfr.per_roam_config_high_rate_th; + req->per_config.tx_low_rate_thresh = + mlme_obj->cfg.lfr.per_roam_config_low_rate_th; + req->per_config.rx_low_rate_thresh = + mlme_obj->cfg.lfr.per_roam_config_low_rate_th; + req->per_config.per_rest_time = mlme_obj->cfg.lfr.per_roam_rest_time; + req->per_config.tx_per_mon_time = + mlme_obj->cfg.lfr.per_roam_monitor_time; + req->per_config.rx_per_mon_time = + mlme_obj->cfg.lfr.per_roam_monitor_time; + req->per_config.tx_rate_thresh_percnt = + mlme_obj->cfg.lfr.per_roam_config_rate_th_percent; + req->per_config.rx_rate_thresh_percnt = + mlme_obj->cfg.lfr.per_roam_config_rate_th_percent; + req->per_config.min_candidate_rssi = + mlme_obj->cfg.lfr.per_roam_min_candidate_rssi; + + mlme_debug("PER based roaming configuration enable: %d vdev: %d high_rate_thresh: %d low_rate_thresh: %d rate_thresh_percnt: %d per_rest_time: %d monitor_time: %d min cand rssi: %d", + req->per_config.enable, req->vdev_id, + req->per_config.tx_high_rate_thresh, + req->per_config.tx_low_rate_thresh, + req->per_config.tx_rate_thresh_percnt, + req->per_config.per_rest_time, + req->per_config.tx_per_mon_time, + req->per_config.min_candidate_rssi); + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_offload_per_config() - populates roam offload scan request and sends + * to fw + * @psoc: psoc context + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_offload_per_config(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_per_roam_config_req *req; + bool is_per_roam_enabled; + QDF_STATUS status; + + /* + * Disable PER trigger for phymode less than 11n to avoid + * frequent roams as the PER rate threshold is greater than + * 11a/b/g rates + */ + is_per_roam_enabled = cm_roam_is_per_roam_allowed(psoc, vdev_id); + if (!is_per_roam_enabled) + return QDF_STATUS_SUCCESS; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + req->vdev_id = vdev_id; + status = cm_roam_fill_per_roam_request(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(req); + mlme_debug("fail to fill per config"); + return status; + } + + status = wlan_cm_tgt_send_roam_per_config(psoc, vdev_id, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send roam stop"); + + qdf_mem_free(req); + + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +cm_akm_roam_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + int32_t akm; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint32_t fw_akm_bitmap; + + akm = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + mlme_debug("akm %x", akm); + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if ((QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) && + !mlme_obj->cfg.lfr.rso_user_config.is_fils_roaming_supported) { + mlme_info("FILS Roaming not suppprted by fw"); + return QDF_STATUS_E_NOSUPPORT; + } + fw_akm_bitmap = mlme_obj->cfg.lfr.fw_akm_bitmap; + /* Roaming is not supported currently for OWE akm */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE) && + !(fw_akm_bitmap & (1 << AKM_OWE))) { + mlme_info("OWE Roaming not suppprted by fw"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* Roaming is not supported for SAE authentication */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) && + !CM_IS_FW_SAE_ROAM_SUPPORTED(fw_akm_bitmap)) { + mlme_info("Roaming not suppprted for SAE connection"); + return QDF_STATUS_E_NOSUPPORT; + } + + if ((QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) && + !CM_IS_FW_SAE_EXT_ROAM_SUPPORTED(fw_akm_bitmap)) { + mlme_info("Roaming not supported for SAE EXT akm"); + return QDF_STATUS_E_NOSUPPORT; + } + + if ((QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) && + !(fw_akm_bitmap & (1 << AKM_SUITEB))) { + mlme_info("Roaming not supported for SUITEB connection"); + return QDF_STATUS_E_NOSUPPORT; + } + + /* + * If fw doesn't advertise FT SAE, FT-FILS or FT-Suite-B capability, + * don't support roaming to that profile + */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) && + !CM_IS_FW_FT_SAE_SUPPORTED(fw_akm_bitmap)) { + mlme_info("Roaming not suppprted for FT SAE akm"); + return QDF_STATUS_E_NOSUPPORT; + } + + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384) && + !(fw_akm_bitmap & (1 << AKM_FT_SUITEB_SHA384))) { + mlme_info("Roaming not suppprted for FT Suite-B akm"); + return QDF_STATUS_E_NOSUPPORT; + } + + if ((QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) && + !(fw_akm_bitmap & (1 << AKM_FT_FILS))) { + mlme_info("Roaming not suppprted for FT FILS akm"); + return QDF_STATUS_E_NOSUPPORT; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t param_value) +{ + struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params; + QDF_STATUS status = QDF_STATUS_E_INVAL; + qdf_freq_t op_freq; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + op_freq = wlan_get_operation_chan_freq(vdev); + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(op_freq)) { + mlme_err("vdev:%d High RSSI offset can't be set in 6 GHz band", + vdev_id); + goto rel_vdev_ref; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto rel_vdev_ref; + + roam_rssi_params = qdf_mem_malloc(sizeof(*roam_rssi_params)); + if (!roam_rssi_params) + goto rel_vdev_ref; + + wlan_cm_set_roam_scan_high_rssi_offset(psoc, param_value); + qdf_mem_zero(roam_rssi_params, sizeof(*roam_rssi_params)); + cm_roam_scan_offload_rssi_thresh(psoc, vdev_id, + roam_rssi_params, rso_cfg); + mlme_debug("vdev:%d Configured high RSSI delta=%d, 5 GHZ roam flag=%d", + vdev_id, roam_rssi_params->hi_rssi_scan_rssi_delta, + (roam_rssi_params->flags & + ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G)); + + status = wlan_cm_tgt_send_roam_scan_offload_rssi_params( + vdev, roam_rssi_params); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("fail to set roam scan high RSSI offset"); + + qdf_mem_free(roam_rssi_params); +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} +#endif + +#ifdef WLAN_ADAPTIVE_11R +static bool +cm_is_adaptive_11r_roam_supported(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct rso_config *rso_cfg) +{ + if (rso_cfg->is_adaptive_11r_connection) + return mlme_obj->cfg.lfr.tgt_adaptive_11r_cap; + + return true; +} +#else +static bool +cm_is_adaptive_11r_roam_supported(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct rso_config *rso_cfg) + +{ + return true; +} +#endif + +static QDF_STATUS +cm_roam_cmd_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t command, uint8_t reason) +{ + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct rso_config *rso_cfg; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + bool p2p_disable_sta_roaming = 0, nan_disable_sta_roaming = 0; + QDF_STATUS status; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_FAILURE; + + mlme_debug("RSO Command %d, vdev %d, Reason %d", + command, vdev_id, reason); + + if (!cm_is_vdev_connected(vdev) && + (command == ROAM_SCAN_OFFLOAD_UPDATE_CFG || + command == ROAM_SCAN_OFFLOAD_START || + command == ROAM_SCAN_OFFLOAD_RESTART)) { + mlme_debug("vdev not in connected state and command %d ", + command); + return QDF_STATUS_E_FAILURE; + } + + if (!cm_is_adaptive_11r_roam_supported(mlme_obj, rso_cfg)) { + mlme_info("Adaptive 11r Roaming not suppprted by fw"); + return QDF_STATUS_E_NOSUPPORT; + } + + status = cm_akm_roam_allowed(psoc, vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + p2p_disable_sta_roaming = + (cfg_p2p_is_roam_config_disabled(psoc) && + (policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_CLIENT_MODE, NULL) || + policy_mgr_mode_specific_connection_count( + psoc, PM_P2P_GO_MODE, NULL))); + nan_disable_sta_roaming = + (cfg_nan_is_roam_config_disabled(psoc) && + policy_mgr_mode_specific_connection_count(psoc, PM_NDI_MODE, NULL)); + + if ((command == ROAM_SCAN_OFFLOAD_START || + command == ROAM_SCAN_OFFLOAD_UPDATE_CFG) && + (p2p_disable_sta_roaming || nan_disable_sta_roaming)) { + mlme_info("roaming not supported for active %s connection", + p2p_disable_sta_roaming ? "p2p" : "ndi"); + return QDF_STATUS_E_FAILURE; + } + + /* + * The Dynamic Config Items Update may happen even if the state is in + * INIT. It is important to ensure that the command is passed down to + * the FW only if the Infra Station is in a connected state. A connected + * station could also be in a PREAUTH or REASSOC states. + * 1) Block all CMDs that are not STOP in INIT State. For STOP always + * inform firmware irrespective of state. + * 2) Block update cfg CMD if its for REASON_ROAM_SET_DENYLIST_BSSID, + * because we need to inform firmware of denylisted AP for PNO in + * all states. + */ + if ((cm_is_vdev_disconnecting(vdev) || + cm_is_vdev_disconnected(vdev)) && + (command != ROAM_SCAN_OFFLOAD_STOP) && + (reason != REASON_ROAM_SET_DENYLIST_BSSID)) { + mlme_info("Scan Command not sent to FW and cmd=%d", command); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS cm_is_rso_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t command, + uint8_t reason) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev_id: %d: vdev not found", vdev_id); + return QDF_STATUS_E_FAILURE; + } + status = cm_roam_cmd_allowed(psoc, vdev, command, reason); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +void cm_handle_sta_sta_roaming_enablement(struct wlan_objmgr_psoc *psoc, + uint8_t curr_vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + uint32_t sta_count, conn_idx = 0; + struct dual_sta_policy *dual_sta_policy; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint8_t temp_vdev_id; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, curr_vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_debug("vdev object is NULL"); + return; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + goto rel_ref; + + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + sta_count = policy_mgr_get_mode_specific_conn_info(psoc, NULL, + vdev_id_list, + PM_STA_MODE); + + if (!(wlan_mlme_get_dual_sta_roaming_enabled(psoc) && sta_count >= 2)) { + mlme_debug("Dual sta roaming is not enabled or count:%d", + sta_count); + goto rel_ref; + } + + if (policy_mgr_concurrent_sta_on_different_mac(psoc)) { + mlme_debug("After roam on vdev_id:%d, sta concurrency on different mac:%d", + curr_vdev_id, sta_count); + for (conn_idx = 0; conn_idx < sta_count; conn_idx++) { + temp_vdev_id = vdev_id_list[conn_idx]; + wlan_cm_roam_activate_pcl_per_vdev(psoc, + temp_vdev_id, + true); + /* Set PCL after sending roam complete */ + policy_mgr_set_pcl_for_existing_combo(psoc, + PM_STA_MODE, + temp_vdev_id); + if (temp_vdev_id != curr_vdev_id) { + /* Enable roaming on secondary vdev */ + if_mgr_enable_roaming(pdev, vdev, RSO_SET_PCL); + } + } + } else { + mlme_debug("After roam STA + STA concurrency is in MCC/SCC"); + } +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +QDF_STATUS cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t rso_command, + uint8_t reason) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = cm_is_rso_allowed(psoc, vdev_id, rso_command, reason); + + if (status == QDF_STATUS_E_NOSUPPORT) + return QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("ROAM: not allowed"); + return status; + } + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_debug("MLO ROAM: skip RSO cmd for link vdev %d", vdev_id); + return QDF_STATUS_SUCCESS; + } + + /* + * Update PER config to FW. No need to update in case of stop command, + * FW takes care of stopping this internally + */ + if (rso_command != ROAM_SCAN_OFFLOAD_STOP) + cm_roam_offload_per_config(psoc, vdev_id); + + if (rso_command == ROAM_SCAN_OFFLOAD_START) + status = cm_roam_start_req(psoc, vdev_id, reason); + else if (rso_command == ROAM_SCAN_OFFLOAD_UPDATE_CFG) + status = cm_roam_update_config_req(psoc, vdev_id, reason); + else if (rso_command == ROAM_SCAN_OFFLOAD_RESTART) + status = cm_roam_restart_req(psoc, vdev_id, reason); + else if (rso_command == ROAM_SCAN_OFFLOAD_ABORT_SCAN) + status = cm_roam_abort_req(psoc, vdev_id, reason); + else + mlme_debug("ROAM: invalid RSO command %d", rso_command); + + return status; +} + +/** + * cm_roam_switch_to_rso_stop() - roam state handling for rso stop + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * @send_resp: + * @start_timer: + * + * This function is used for WLAN_ROAM_RSO_STOPPED roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_switch_to_rso_stop(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t reason, bool *send_resp, bool start_timer) +{ + enum roam_offload_state cur_state; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cur_state = mlme_get_roam_state(psoc, vdev_id); + switch (cur_state) { + case WLAN_ROAM_RSO_ENABLED: + case WLAN_ROAMING_IN_PROG: + case WLAN_ROAM_SYNCH_IN_PROG: + status = cm_roam_stop_req(psoc, vdev_id, reason, + send_resp, start_timer); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("ROAM: Unable to switch to RSO STOP State"); + return QDF_STATUS_E_FAILURE; + } + break; + + case WLAN_ROAM_DEINIT: + case WLAN_ROAM_RSO_STOPPED: + case WLAN_ROAM_INIT: + /* + * Already the roaming module is initialized at fw, + * nothing to do here + */ + default: + return QDF_STATUS_SUCCESS; + } + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_RSO_STOPPED); + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_switch_to_deinit() - roam state handling for roam deinit + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * This function is used for WLAN_ROAM_DEINIT roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_switch_to_deinit(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t reason) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + enum roam_offload_state cur_state = mlme_get_roam_state(psoc, vdev_id); + bool sup_disabled_roam; + + switch (cur_state) { + /* + * If RSO stop is not done already, send RSO stop first and + * then post deinit. + */ + case WLAN_ROAM_RSO_ENABLED: + case WLAN_ROAMING_IN_PROG: + case WLAN_ROAM_SYNCH_IN_PROG: + cm_roam_switch_to_rso_stop(pdev, vdev_id, reason, NULL, false); + break; + case WLAN_ROAM_RSO_STOPPED: + /* + * When Supplicant disabled roaming is set and roam invoke + * command is received from userspace, fw starts to roam. + * But meanwhile if a disassoc/deauth is received from AP or if + * NB disconnect is initiated while supplicant disabled roam, + * RSO stop with ROAM scan mode as 0 is not sent to firmware + * since the previous state was RSO_STOPPED. This could lead + * to firmware not sending peer unmap event for the current + * AP. To avoid this, if previous RSO stop was sent with + * ROAM scan mode as 4, send RSO stop with Roam scan mode as 0 + * and then switch to ROAM_DEINIT. + */ + sup_disabled_roam = + mlme_get_supplicant_disabled_roaming(psoc, + vdev_id); + if (sup_disabled_roam) { + mlme_err("vdev[%d]: supplicant disabled roam. clear roam scan mode", + vdev_id); + status = cm_roam_stop_req(psoc, vdev_id, + REASON_DISCONNECTED, + NULL, false); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("ROAM: Unable to clear roam scan mode"); + } + break; + case WLAN_ROAM_INIT: + break; + + case WLAN_MLO_ROAM_SYNCH_IN_PROG: + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_DEINIT); + break; + + case WLAN_ROAM_DEINIT: + /* + * Already the roaming module is de-initialized at fw, + * do nothing here + */ + default: + return QDF_STATUS_SUCCESS; + } + + status = cm_roam_init_req(psoc, vdev_id, false); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_DEINIT); + mlme_clear_operations_bitmap(psoc, vdev_id); + wlan_cm_roam_activate_pcl_per_vdev(psoc, vdev_id, false); + + /* In case of roaming getting disabled due to + * REASON_ROAM_SET_PRIMARY reason, don't enable roaming on + * the other vdev as that is taken care by the caller once roaming + * on this "vdev_id" is disabled. + */ + if (reason != REASON_SUPPLICANT_INIT_ROAMING && + reason != REASON_ROAM_SET_PRIMARY) { + mlme_debug("vdev_id:%d enable roaming on other connected sta - reason:%d", + vdev_id, reason); + wlan_cm_enable_roaming_on_connected_sta(pdev, vdev_id); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_switch_to_init() - roam state handling for roam init + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * This function is used for WLAN_ROAM_INIT roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_switch_to_init(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t reason) +{ + enum roam_offload_state cur_state; + uint8_t temp_vdev_id, roam_enabled_vdev_id; + uint32_t roaming_bitmap; + bool dual_sta_roam_active, usr_disabled_roaming; + bool sta_concurrency_is_with_different_mac; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct dual_sta_policy *dual_sta_policy; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) + return QDF_STATUS_E_FAILURE; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + dual_sta_roam_active = wlan_mlme_get_dual_sta_roaming_enabled(psoc); + sta_concurrency_is_with_different_mac = + policy_mgr_concurrent_sta_on_different_mac(psoc); + cur_state = mlme_get_roam_state(psoc, vdev_id); + + mlme_info("dual_sta_roam_active:%d, sta concurrency on different mac:%d, state:%d", + dual_sta_roam_active, sta_concurrency_is_with_different_mac, + cur_state); + + switch (cur_state) { + case WLAN_ROAM_DEINIT: + roaming_bitmap = mlme_get_roam_trigger_bitmap(psoc, vdev_id); + if (!roaming_bitmap) { + mlme_info("CM_RSO: Cannot change to INIT state for vdev[%d]", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* + * Enable roaming on other interface only if STA + STA + * concurrency on different mac. + */ + if (dual_sta_roam_active && + sta_concurrency_is_with_different_mac) { + mlme_info("sta concurrency on different mac"); + break; + } + + /* + * If dual sta roaming is not supported, do not enable + * the RSO on the second STA interface, even if the + * primary interface config is present via dual sta policy + */ + temp_vdev_id = policy_mgr_get_roam_enabled_sta_session_id( + psoc, vdev_id); + if (!dual_sta_roam_active && + temp_vdev_id != WLAN_UMAC_VDEV_ID_MAX) { + mlme_debug("Do not enable RSO on %d, RSO is enabled on %d", + vdev_id, temp_vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* + * set_primary_vdev usecase is to use that + * interface(e.g. wlan0) over the other + * interface(i.e. wlan1) for data transfer. Non-primary + * vdev use case is to check the quality of that link + * and decide if data can be switched to it and make it + * primary. + * Enabling roaming on non-primary vdev also in this + * context would always helps to find better AP. + */ + if (wlan_mlme_is_primary_interface_configured(psoc) && + (reason != REASON_SUPPLICANT_INIT_ROAMING)) { + mlme_info("STA + STA concurrency with a primary iface, have roaming enabled on both interfaces"); + break; + } + + /* + * Disable roaming on the enabled sta if supplicant wants to + * enable roaming on this vdev id + */ + if (temp_vdev_id != WLAN_UMAC_VDEV_ID_MAX) { + /* + * Roam init state can be requested as part of + * initial connection or due to enable from + * supplicant via vendor command. This check will + * ensure roaming does not get enabled on this STA + * vdev id if it is not an explicit enable from + * supplicant. + */ + mlme_debug("Interface vdev_id: %d, roaming enabled on vdev_id: %d, reason:%d", + vdev_id, temp_vdev_id, + reason); + + if (reason == REASON_SUPPLICANT_INIT_ROAMING) { + cm_roam_state_change(pdev, temp_vdev_id, + WLAN_ROAM_DEINIT, + reason, + NULL, false); + } else { + mlme_info("CM_RSO: Roam module already initialized on vdev:[%d]", + temp_vdev_id); + return QDF_STATUS_E_FAILURE; + } + } + break; + + case WLAN_ROAM_SYNCH_IN_PROG: + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_INIT); + return QDF_STATUS_SUCCESS; + + case WLAN_ROAM_INIT: + case WLAN_ROAM_RSO_STOPPED: + case WLAN_ROAM_RSO_ENABLED: + case WLAN_ROAMING_IN_PROG: + /* + * Already the roaming module is initialized at fw, + * just return from here + */ + default: + return QDF_STATUS_SUCCESS; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("CM_RSO: vdev:%d is null", vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!cm_is_vdev_connected(vdev)) { + mlme_debug("CM_RSO: vdev:%d RSO Init received in non-connected state", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + status = cm_roam_init_req(psoc, vdev_id, true); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_INIT); + + roam_enabled_vdev_id = + policy_mgr_get_roam_enabled_sta_session_id(psoc, vdev_id); + + /* Send PDEV pcl command if only one STA is in connected state + * If there is another STA connection exist, then set the + * PCL type to vdev level + */ + if (roam_enabled_vdev_id != WLAN_UMAC_VDEV_ID_MAX && + dual_sta_roam_active && sta_concurrency_is_with_different_mac) + wlan_cm_roam_activate_pcl_per_vdev(psoc, vdev_id, true); + + /* Set PCL before sending RSO start */ + policy_mgr_set_pcl_for_existing_combo(psoc, PM_STA_MODE, vdev_id); + + wlan_mlme_get_usr_disabled_roaming(psoc, &usr_disabled_roaming); + if (usr_disabled_roaming) { + status = + cm_roam_send_disable_config( + psoc, vdev_id, + WMI_VDEV_ROAM_11KV_CTRL_DISABLE_FW_TRIGGER_ROAMING); + + if (!QDF_IS_STATUS_SUCCESS(status)) + mlme_err("ROAM: fast roaming disable failed. status %d", + status); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_switch_to_rso_enable() - roam state handling for rso started + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * This function is used for WLAN_ROAM_RSO_ENABLED roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_switch_to_rso_enable(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t reason) +{ + enum roam_offload_state cur_state, new_roam_state; + QDF_STATUS status; + uint8_t control_bitmap; + bool sup_disabled_roaming; + bool rso_allowed; + uint8_t rso_command = ROAM_SCAN_OFFLOAD_START; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + wlan_mlme_get_roam_scan_offload_enabled(psoc, &rso_allowed); + sup_disabled_roaming = mlme_get_supplicant_disabled_roaming(psoc, + vdev_id); + control_bitmap = mlme_get_operations_bitmap(psoc, vdev_id); + + cur_state = mlme_get_roam_state(psoc, vdev_id); + mlme_debug("CM_RSO: vdev%d: cur_state : %d reason:%d control_bmap:0x%x sup_disabled_roam:%d", + vdev_id, cur_state, reason, control_bitmap, + sup_disabled_roaming); + + switch (cur_state) { + case WLAN_ROAM_INIT: + case WLAN_ROAM_RSO_STOPPED: + break; + + case WLAN_ROAM_DEINIT: + status = cm_roam_switch_to_init(pdev, vdev_id, reason); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + break; + case WLAN_ROAM_RSO_ENABLED: + /* + * Send RSO update config if roaming already enabled + */ + rso_command = ROAM_SCAN_OFFLOAD_UPDATE_CFG; + break; + case WLAN_ROAMING_IN_PROG: + /* + * When roam abort happens, the roam offload + * state machine moves to RSO_ENABLED state. + * But if Supplicant disabled roaming is set in case + * of roam invoke or if roaming was disabled due to + * other reasons like SAP start/connect on other vdev, + * the state should be transitioned to RSO STOPPED. + */ + if (sup_disabled_roaming || control_bitmap) + new_roam_state = WLAN_ROAM_RSO_STOPPED; + else + new_roam_state = WLAN_ROAM_RSO_ENABLED; + + mlme_set_roam_state(psoc, vdev_id, new_roam_state); + + return QDF_STATUS_SUCCESS; + case WLAN_ROAM_SYNCH_IN_PROG: + if (reason == REASON_ROAM_ABORT) { + mlme_debug("Roam synch in progress, drop Roam abort"); + return QDF_STATUS_SUCCESS; + } + /* + * After roam sych propagation is complete, send + * RSO start command to firmware to update AP profile, + * new PCL. + * If this is roam invoke case and supplicant has already + * disabled firmware roaming, then move to RSO stopped state + * instead of RSO enabled. + */ + if (sup_disabled_roaming || control_bitmap) { + new_roam_state = WLAN_ROAM_RSO_STOPPED; + mlme_set_roam_state(psoc, vdev_id, new_roam_state); + + return QDF_STATUS_SUCCESS; + } + + break; + default: + return QDF_STATUS_SUCCESS; + } + + if (!rso_allowed) { + mlme_debug("ROAM: RSO disabled via INI"); + return QDF_STATUS_E_FAILURE; + } + + if (control_bitmap) { + mlme_debug("ROAM: RSO Disabled internally: vdev[%d] bitmap[0x%x]", + vdev_id, control_bitmap); + return QDF_STATUS_E_FAILURE; + } + + status = cm_roam_send_rso_cmd(psoc, vdev_id, rso_command, reason); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("ROAM: vdev:%d RSO start failed", vdev_id); + return status; + } + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_RSO_ENABLED); + + /* If the set_key for the connected bssid was received during Roam sync + * in progress, then the RSO update to the FW will be rejected. The RSO + * start which might be in progress during set_key could send stale pmk + * to the FW. Therefore, once RSO is enabled, send the RSO update with + * the PMK received from the __wlan_hdd_cfg80211_keymgmt_set_key. + */ + if (wlan_mlme_is_pmk_set_deferred(psoc, vdev_id)) { + cm_roam_send_rso_cmd(psoc, vdev_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_ROAM_PSK_PMK_CHANGED); + wlan_mlme_defer_pmk_set_in_roaming(psoc, vdev_id, false); + } + + /* + * If supplicant disabled roaming, driver does not send + * RSO cmd to fw. This causes roam invoke to fail in FW + * since RSO start never happened at least once to + * configure roaming engine in FW. So send RSO start followed + * by RSO stop if supplicant disabled roaming is true. + */ + if (!sup_disabled_roaming) + return QDF_STATUS_SUCCESS; + + mlme_debug("ROAM: RSO disabled by Supplicant on vdev[%d]", vdev_id); + return cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_STOPPED, + REASON_SUPPLICANT_DISABLED_ROAMING, + NULL, false); +} + +/** + * cm_roam_switch_to_roam_start() - roam state handling for ROAMING_IN_PROG + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * This function is used for WLAN_ROAMING_IN_PROG roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_switch_to_roam_start(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + enum roam_offload_state cur_state = + mlme_get_roam_state(psoc, vdev_id); + switch (cur_state) { + case WLAN_ROAMING_IN_PROG: + mlme_debug("Roam started already on vdev[%d]", vdev_id); + break; + case WLAN_ROAM_RSO_ENABLED: + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAMING_IN_PROG); + break; + + case WLAN_ROAM_RSO_STOPPED: + /* + * When supplicant has disabled roaming, roam invoke triggered + * from supplicant can cause firmware to send roam start + * notification. Allow roam start in this condition. + */ + if (mlme_get_supplicant_disabled_roaming(psoc, vdev_id) && + + wlan_cm_roaming_in_progress(pdev, vdev_id)) { + mlme_set_roam_state(psoc, vdev_id, + WLAN_ROAMING_IN_PROG); + break; + } + fallthrough; + case WLAN_ROAM_INIT: + case WLAN_ROAM_DEINIT: + case WLAN_ROAM_SYNCH_IN_PROG: + default: + mlme_err("ROAM: Roaming start received in invalid state: %d", + cur_state); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_roam_switch_to_roam_sync() - roam state handling for roam sync + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * This function is used for WLAN_ROAM_SYNCH_IN_PROG roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_switch_to_roam_sync(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + enum roam_offload_state cur_state = mlme_get_roam_state(psoc, vdev_id); + QDF_STATUS status; + + switch (cur_state) { + case WLAN_ROAM_RSO_ENABLED: + /* + * Roam synch can come directly without roam start + * after waking up from power save mode or in case of + * deauth roam trigger to stop data path queues + */ + case WLAN_ROAMING_IN_PROG: + if (!cm_is_vdevid_active(pdev, vdev_id)) { + mlme_err("ROAM: STA not in connected state"); + return QDF_STATUS_E_FAILURE; + } + + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_SYNCH_IN_PROG); + break; + case WLAN_ROAM_RSO_STOPPED: + /* + * If roaming is disabled by Supplicant and if this transition + * is due to roaming invoked by the supplicant, then allow + * this state transition + */ + if (mlme_get_supplicant_disabled_roaming(psoc, vdev_id) && + wlan_cm_roaming_in_progress(pdev, vdev_id)) { + mlme_set_roam_state(psoc, vdev_id, + WLAN_ROAM_SYNCH_IN_PROG); + break; + } + + mlme_debug("ROAM: ROAM_SYNCH received in state: %d", cur_state); + /* + * If ROAM SYNC come to host in below scenario: + * 1. HOST sends RSO stop command with scan mode 4, in order + * to process supplicant disabled roaming request + * 2. FW already queued the roam sync event before RSO STOP + * command receive from host + * In this case host should send RSO STOP with scan mode = 0 + * to allow FW to move into RSO STOP state + */ + status = cm_roam_stop_req(psoc, vdev_id, REASON_ROAM_ABORT, + NULL, false); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("ROAM: Unable to process RSO STOP req"); + + return QDF_STATUS_E_FAILURE; + case WLAN_ROAM_INIT: + case WLAN_ROAM_DEINIT: + case WLAN_ROAM_SYNCH_IN_PROG: + default: + mlme_err("ROAM: Roam synch not allowed in [%d] state", + cur_state); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_ROAM_DEBUG +/** + * union rso_rec_arg1 - argument 1 record rso state change + * @value: aggregate value of the structured param + * @request_st: requested rso state + * @cur_st: current rso state + * @new_st: new rso state + * @status: qdf status for the request + */ +union rso_rec_arg1 { + uint32_t value; + struct { + uint32_t request_st:4, + cur_st:4, + new_st:4, + status:8; + }; +}; + +/** + * get_rso_arg1 - get argument 1 record rso state change + * @request_st: requested rso state + * @cur_st: current rso state + * @new_st: new rso state + * @status: qdf status for the request + * + * Return: u32 value of rso information + */ +static uint32_t get_rso_arg1(enum roam_offload_state request_st, + enum roam_offload_state cur_st, + enum roam_offload_state new_st, + QDF_STATUS status) +{ + union rso_rec_arg1 rso_arg1; + + rso_arg1.value = 0; + rso_arg1.request_st = request_st; + rso_arg1.cur_st = cur_st; + rso_arg1.new_st = new_st; + rso_arg1.status = status; + + return rso_arg1.value; +} + +/** + * union rso_rec_arg2 - argument 2 record rso state change + * @value: aggregate value of the structured param + * @is_up: vdev is up + * @supp_dis_roam: supplicant disable roam + * @roam_progress: roam in progress + * @ctrl_bitmap: control bitmap + * @reason: reason code + * + * Return: u32 value of rso information + */ +union rso_rec_arg2 { + uint32_t value; + struct { + uint32_t is_up: 1, + supp_dis_roam:1, + roam_progress:1, + ctrl_bitmap:8, + reason:8; + }; +}; + +/** + * get_rso_arg2 - get argument 2 record rso state change + * @is_up: vdev is up + * @supp_dis_roam: supplicant disable roam + * @roam_progress: roam in progress + * @ctrl_bitmap: control bitmap + * @reason: reason code + */ +static uint32_t get_rso_arg2(bool is_up, + bool supp_dis_roam, + bool roam_progress, + uint8_t ctrl_bitmap, + uint8_t reason) +{ + union rso_rec_arg2 rso_arg2; + + rso_arg2.value = 0; + if (is_up) + rso_arg2.is_up = 1; + if (supp_dis_roam) + rso_arg2.supp_dis_roam = 1; + if (roam_progress) + rso_arg2.roam_progress = 1; + rso_arg2.ctrl_bitmap = ctrl_bitmap; + rso_arg2.reason = reason; + + return rso_arg2.value; +} + +/** + * cm_record_state_change() - record rso state change to roam history log + * @pdev: pdev object + * @vdev_id: vdev id + * @cur_st: current state + * @requested_state: requested state + * @reason: reason + * @is_up: vdev is up + * @status: request result code + * + * This function will record the RSO state change to roam history log. + * + * Return: void + */ +static void +cm_record_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state cur_st, + enum roam_offload_state requested_state, + uint8_t reason, + bool is_up, + QDF_STATUS status) +{ + enum roam_offload_state new_state; + bool supp_dis_roam; + bool roam_progress; + uint8_t control_bitmap; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) + return; + + new_state = mlme_get_roam_state(psoc, vdev_id); + control_bitmap = mlme_get_operations_bitmap(psoc, vdev_id); + supp_dis_roam = mlme_get_supplicant_disabled_roaming(psoc, vdev_id); + roam_progress = wlan_cm_roaming_in_progress(pdev, vdev_id); + wlan_rec_conn_info(vdev_id, DEBUG_CONN_RSO, + NULL, + get_rso_arg1(requested_state, cur_st, + new_state, status), + get_rso_arg2(is_up, + supp_dis_roam, roam_progress, + control_bitmap, reason)); +} +#else +static inline void +cm_record_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state cur_st, + enum roam_offload_state requested_state, + uint8_t reason, + bool is_up, + QDF_STATUS status) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * cm_mlo_roam_switch_for_link() - roam state handling during mlo roam + * for link/s. + * @pdev: pdev pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * This function is used for WLAN_MLO_ROAM_SYNCH_IN_PROG roam state handling + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_mlo_roam_switch_for_link(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + enum roam_offload_state cur_state = mlme_get_roam_state(psoc, vdev_id); + + if (reason != REASON_ROAM_HANDOFF_DONE && + reason != REASON_ROAM_ABORT && + reason != REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE) { + mlo_debug("CM_RSO: link vdev:%d state switch received with invalid reason:%d", + vdev_id, reason); + return QDF_STATUS_E_FAILURE; + } + + /* + * change roam state to deinit for assoc vdev that has now changed to + * link vdev + */ + if (reason == REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE) { + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_DEINIT); + return QDF_STATUS_SUCCESS; + } + + switch (cur_state) { + case WLAN_ROAM_DEINIT: + /* Only used for link vdev during MLO roaming */ + mlme_set_roam_state(psoc, vdev_id, WLAN_MLO_ROAM_SYNCH_IN_PROG); + break; + case WLAN_MLO_ROAM_SYNCH_IN_PROG: + mlme_set_roam_state(psoc, vdev_id, WLAN_ROAM_DEINIT); + break; + default: + mlme_err("ROAM: vdev:%d MLO Roam synch not allowed in [%d] state reason:%d", + vdev_id, cur_state, reason); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev, uint8_t *vdev_id, + enum roam_offload_state requested_state, + uint8_t reason, bool *is_rso_skip) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *assoc_vdev = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, *vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + /* + * When link switch is in progress, the MLO link flag would be reset and + * set back on assoc vdev, so avoid any state transition during link + * switch. + */ + if (wlan_vdev_mlme_get_is_mlo_vdev(psoc, *vdev_id) && + mlo_mgr_is_link_switch_in_progress(vdev)) { + mlme_debug("MLO ROAM: Link switch in prog! skip RSO cmd:%d on vdev %d", + requested_state, *vdev_id); + *is_rso_skip = true; + goto end; + } + + if (wlan_vdev_mlme_get_is_mlo_vdev(psoc, *vdev_id) && + cm_is_vdev_disconnecting(vdev) && + (reason == REASON_DISCONNECTED || + reason == REASON_DRIVER_DISABLED)) { + /* + * Processing disconnect on assoc vdev but roaming is still + * enabled. It's either due to single ML usecase or failed to + * connect to second link. + */ + if (!wlan_vdev_mlme_get_is_mlo_link(psoc, *vdev_id) && + wlan_is_roaming_enabled(pdev, *vdev_id)) { + mlme_debug("MLO ROAM: Process RSO cmd:%d on assoc vdev : %d", + requested_state, *vdev_id); + *is_rso_skip = false; + } else { + mlme_debug("MLO ROAM: skip RSO cmd:%d on assoc vdev %d", + requested_state, *vdev_id); + *is_rso_skip = true; + } + } + + /* + * Send RSO STOP before triggering a vdev restart on an MLO vdev + * Send RSO START after CSA is completed on an MLO vdev + */ + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + mlo_check_if_all_vdev_up(vdev) && + reason == REASON_VDEV_RESTART_FROM_HOST) { + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + + *is_rso_skip = false; + *vdev_id = wlan_vdev_get_id(assoc_vdev); + mlme_debug("MLO_CSA: Send RSO on assoc vdev %d", *vdev_id); + goto end; + } + + if (!wlan_vdev_mlme_get_is_mlo_link(wlan_pdev_get_psoc(pdev), + *vdev_id)) + goto end; + + if (reason == REASON_ROAM_HANDOFF_DONE || reason == REASON_ROAM_ABORT) { + status = cm_mlo_roam_switch_for_link(pdev, *vdev_id, reason); + mlme_debug("MLO ROAM: update rso state on link vdev %d", + *vdev_id); + *is_rso_skip = true; + } else if ((reason == REASON_DISCONNECTED || + reason == REASON_DRIVER_DISABLED) && + cm_is_vdev_disconnecting(vdev)) { + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + + if (!assoc_vdev) { + mlme_err("Assoc vdev is NULL"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + /* Update the vdev id to send RSO stop on assoc vdev */ + *vdev_id = wlan_vdev_get_id(assoc_vdev); + *is_rso_skip = false; + mlme_debug("MLO ROAM: process RSO stop on assoc vdev %d", + *vdev_id); + goto end; + } else { + mlme_debug("MLO ROAM: skip RSO cmd on link vdev %d", *vdev_id); + *is_rso_skip = true; + } +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return status; +} +#endif + +QDF_STATUS +cm_roam_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state requested_state, + uint8_t reason, bool *send_resp, bool start_timer) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + bool is_up; + bool is_rso_skip = false; + enum roam_offload_state cur_state; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return status; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + is_up = mlo_check_if_all_vdev_up(vdev); + else + is_up = QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(vdev)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + if ((requested_state != WLAN_ROAM_DEINIT && + requested_state != WLAN_ROAM_RSO_STOPPED) && !is_up) { + mlme_debug("ROAM: roam state(%d) change requested in non-connected state", + requested_state); + goto end; + } + + status = cm_handle_mlo_rso_state_change(pdev, &vdev_id, requested_state, + reason, &is_rso_skip); + if (is_rso_skip) + return status; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("Invalid vdev:%d", vdev_id); + goto end; + } + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Fail to acquire lock, status: %d", status); + goto release_ref; + } + + switch (requested_state) { + case WLAN_ROAM_DEINIT: + status = cm_roam_switch_to_deinit(pdev, vdev_id, reason); + break; + case WLAN_ROAM_INIT: + status = cm_roam_switch_to_init(pdev, vdev_id, reason); + break; + case WLAN_ROAM_RSO_ENABLED: + status = cm_roam_switch_to_rso_enable(pdev, vdev_id, reason); + break; + case WLAN_ROAM_RSO_STOPPED: + status = cm_roam_switch_to_rso_stop(pdev, vdev_id, reason, + send_resp, start_timer); + break; + case WLAN_ROAMING_IN_PROG: + status = cm_roam_switch_to_roam_start(pdev, vdev_id, reason); + break; + case WLAN_ROAM_SYNCH_IN_PROG: + status = cm_roam_switch_to_roam_sync(pdev, vdev_id, reason); + break; + default: + mlme_debug("ROAM: Invalid roam state %d", requested_state); + break; + } + + cm_roam_release_lock(vdev); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +end: + cur_state = mlme_get_roam_state(psoc, vdev_id); + cm_record_state_change(pdev, vdev_id, cur_state, requested_state, + reason, is_up, status); + + return status; +} + +#ifdef FEATURE_WLAN_ESE +static QDF_STATUS +cm_roam_channels_filter_by_current_band(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t *in_chan_freq_list, + uint8_t in_num_chan, + qdf_freq_t *out_chan_freq_list, + uint8_t *merged_num_chan) +{ + uint8_t i = 0; + uint8_t num_chan = 0; + uint32_t curr_ap_op_chan_freq = + wlan_get_operation_chan_freq_vdev_id(pdev, vdev_id); + + /* Check for NULL pointer */ + if (!in_chan_freq_list) + return QDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!out_chan_freq_list) + return QDF_STATUS_E_INVAL; + + if (in_num_chan > CFG_VALID_CHANNEL_LIST_LEN) { + mlme_err("Wrong Number of Input Channels %d", in_num_chan); + return QDF_STATUS_E_INVAL; + } + for (i = 0; i < in_num_chan; i++) { + if (WLAN_REG_IS_SAME_BAND_FREQS(curr_ap_op_chan_freq, + in_chan_freq_list[i])) { + out_chan_freq_list[num_chan] = in_chan_freq_list[i]; + num_chan++; + } + } + + /* Return final number of channels */ + *merged_num_chan = num_chan; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS cm_roam_merge_channel_lists(qdf_freq_t *in_chan_freq_list, + uint8_t in_num_chan, + qdf_freq_t *out_chan_freq_list, + uint8_t out_num_chan, + uint8_t *merged_num_chan) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t num_chan = out_num_chan; + + /* Check for NULL pointer */ + if (!in_chan_freq_list) + return QDF_STATUS_E_INVAL; + + /* Check for NULL pointer */ + if (!out_chan_freq_list) + return QDF_STATUS_E_INVAL; + + if (in_num_chan > CFG_VALID_CHANNEL_LIST_LEN) { + mlme_err("Wrong Number of Input Channels %d", in_num_chan); + return QDF_STATUS_E_INVAL; + } + if (out_num_chan >= CFG_VALID_CHANNEL_LIST_LEN) { + mlme_err("Wrong Number of Output Channels %d", out_num_chan); + return QDF_STATUS_E_INVAL; + } + /* Add the "new" channels in the input list to the end of the + * output list. + */ + for (i = 0; i < in_num_chan; i++) { + for (j = 0; j < out_num_chan; j++) { + if (in_chan_freq_list[i] == out_chan_freq_list[j]) + break; + } + if (j == out_num_chan) { + if (in_chan_freq_list[i]) { + mlme_debug("Adding extra %d to roam channel list", + in_chan_freq_list[i]); + out_chan_freq_list[num_chan] = + in_chan_freq_list[i]; + num_chan++; + } + } + if (num_chan >= CFG_VALID_CHANNEL_LIST_LEN) { + mlme_debug("Merge Neighbor channel list reached Max limit %d", + in_num_chan); + break; + } + } + + /* Return final number of channels */ + *merged_num_chan = num_chan; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_create_roam_scan_channel_list(struct wlan_objmgr_pdev *pdev, + struct rso_config *rso_cfg, + uint8_t vdev_id, + qdf_freq_t *chan_freq_list, + uint8_t num_chan, + const enum band_info band) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t out_num_chan = 0; + uint8_t in_chan_num = num_chan; + qdf_freq_t *in_ptr = chan_freq_list; + uint8_t i = 0; + qdf_freq_t *freq_list; + qdf_freq_t *tmp_chan_freq_list; + uint8_t merged_out_chan_num = 0; + struct rso_chan_info *chan_lst; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_reg *reg; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + reg = &mlme_obj->cfg.reg; + chan_lst = &rso_cfg->roam_scan_freq_lst; + /* + * Create a Union of occupied channel list learnt by the DUT along + * with the Neighbor report Channels. This increases the chances of + * the DUT to get a candidate AP while roaming even if the Neighbor + * Report is not able to provide sufficient information. + */ + if (rso_cfg->occupied_chan_lst.num_chan) { + cm_roam_merge_channel_lists(rso_cfg->occupied_chan_lst.freq_list, + rso_cfg->occupied_chan_lst.num_chan, + in_ptr, in_chan_num, + &merged_out_chan_num); + in_chan_num = merged_out_chan_num; + } + + freq_list = qdf_mem_malloc(CFG_VALID_CHANNEL_LIST_LEN * + sizeof(qdf_freq_t)); + if (!freq_list) + return QDF_STATUS_E_NOMEM; + + if (band == BAND_2G) { + for (i = 0; i < in_chan_num; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(in_ptr[i]) && + wlan_roam_is_channel_valid(reg, in_ptr[i])) { + freq_list[out_num_chan++] = in_ptr[i]; + } + } + } else if (band == BAND_5G) { + for (i = 0; i < in_chan_num; i++) { + /* Add 5G Non-DFS channel */ + if (WLAN_REG_IS_5GHZ_CH_FREQ(in_ptr[i]) && + wlan_roam_is_channel_valid(reg, in_ptr[i]) && + !wlan_reg_is_dfs_for_freq(pdev, in_ptr[i])) { + freq_list[out_num_chan++] = in_ptr[i]; + } + } + } else if (band == BAND_ALL) { + for (i = 0; i < in_chan_num; i++) { + if (wlan_roam_is_channel_valid(reg, in_ptr[i]) && + !wlan_reg_is_dfs_for_freq(pdev, in_ptr[i])) { + freq_list[out_num_chan++] = in_ptr[i]; + } + } + } else { + mlme_warn("Invalid band, No operation carried out (Band %d)", + band); + qdf_mem_free(freq_list); + return QDF_STATUS_E_INVAL; + } + + tmp_chan_freq_list = qdf_mem_malloc(CFG_VALID_CHANNEL_LIST_LEN * + sizeof(qdf_freq_t)); + if (!tmp_chan_freq_list) { + qdf_mem_free(freq_list); + return QDF_STATUS_E_NOMEM; + } + + /* + * if roaming within band is enabled, then select only the + * in band channels . + * This is required only if the band capability is set to ALL, + * E.g., if band capability is only 2.4G then all the channels in the + * list are already filtered for 2.4G channels, hence ignore this check + */ + if ((band == BAND_ALL) && mlme_obj->cfg.lfr.roam_intra_band) + cm_roam_channels_filter_by_current_band(pdev, vdev_id, + freq_list, out_num_chan, + tmp_chan_freq_list, + &out_num_chan); + + /* Prepare final roam scan channel list */ + if (out_num_chan) { + /* Clear the channel list first */ + cm_flush_roam_channel_list(chan_lst); + chan_lst->freq_list = + qdf_mem_malloc(out_num_chan * sizeof(qdf_freq_t)); + if (!chan_lst->freq_list) { + chan_lst->num_chan = 0; + status = QDF_STATUS_E_NOMEM; + goto error; + } + for (i = 0; i < out_num_chan; i++) + chan_lst->freq_list[i] = tmp_chan_freq_list[i]; + + chan_lst->num_chan = out_num_chan; + } + +error: + qdf_mem_free(tmp_chan_freq_list); + qdf_mem_free(freq_list); + + return status; +} +#endif + +static const char *cm_get_config_item_string(uint8_t reason) +{ + switch (reason) { + CASE_RETURN_STRING(REASON_LOOKUP_THRESH_CHANGED); + CASE_RETURN_STRING(REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_BMISS_FIRST_BCNT_CHANGED); + CASE_RETURN_STRING(REASON_ROAM_BMISS_FINAL_BCNT_CHANGED); + default: + return "unknown"; + } +} + +QDF_STATUS cm_neighbor_roam_update_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t value, + uint8_t reason) +{ + uint8_t old_value; + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_FAILURE; + } + cfg_params = &rso_cfg->cfg_param; + switch (reason) { + case REASON_LOOKUP_THRESH_CHANGED: + old_value = cfg_params->neighbor_lookup_threshold; + cfg_params->neighbor_lookup_threshold = value; + cfg_params->next_rssi_threshold = value; + break; + case REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED: + old_value = cfg_params->opportunistic_threshold_diff; + cfg_params->opportunistic_threshold_diff = value; + break; + case REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED: + old_value = cfg_params->roam_rescan_rssi_diff; + cfg_params->roam_rescan_rssi_diff = value; + rso_cfg->rescan_rssi_delta = value; + break; + case REASON_ROAM_BMISS_FIRST_BCNT_CHANGED: + old_value = cfg_params->roam_bmiss_first_bcn_cnt; + cfg_params->roam_bmiss_first_bcn_cnt = value; + break; + case REASON_ROAM_BMISS_FINAL_BCNT_CHANGED: + old_value = cfg_params->roam_bmiss_final_cnt; + cfg_params->roam_bmiss_final_cnt = value; + break; + default: + mlme_debug("Unknown update cfg reason"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_FAILURE; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + mlme_debug("CONNECTED, send update cfg cmd"); + wlan_roam_update_cfg(psoc, vdev_id, reason); + + mlme_debug("LFR config for %s changed from %d to %d", + cm_get_config_item_string(reason), old_value, value); + + return QDF_STATUS_SUCCESS; +} + +void cm_flush_roam_channel_list(struct rso_chan_info *channel_info) +{ + /* Free up the memory first (if required) */ + if (channel_info->freq_list) { + qdf_mem_free(channel_info->freq_list); + channel_info->freq_list = NULL; + channel_info->num_chan = 0; + } +} + +static void +cm_restore_default_roaming_params(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_objmgr_vdev *vdev) +{ + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + uint32_t current_band = REG_BAND_MASK_ALL; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + cfg_params = &rso_cfg->cfg_param; + cfg_params->enable_scoring_for_roam = + mlme_obj->cfg.roam_scoring.enable_scoring_for_roam; + cfg_params->empty_scan_refresh_period = + mlme_obj->cfg.lfr.empty_scan_refresh_period; + cfg_params->full_roam_scan_period = + mlme_obj->cfg.lfr.roam_full_scan_period; + cfg_params->neighbor_scan_period = + mlme_obj->cfg.lfr.neighbor_scan_timer_period; + cfg_params->neighbor_lookup_threshold = + mlme_obj->cfg.lfr.neighbor_lookup_rssi_threshold; + cfg_params->next_rssi_threshold = + mlme_obj->cfg.lfr.neighbor_lookup_rssi_threshold; + cfg_params->roam_rssi_diff = + mlme_obj->cfg.lfr.roam_rssi_diff; + cfg_params->roam_rssi_diff_6ghz = + mlme_obj->cfg.lfr.roam_rssi_diff_6ghz; + cfg_params->bg_rssi_threshold = + mlme_obj->cfg.lfr.bg_rssi_threshold; + + cfg_params->max_chan_scan_time = + mlme_obj->cfg.lfr.neighbor_scan_max_chan_time; + cfg_params->passive_max_chan_time = + mlme_obj->cfg.lfr.passive_max_channel_time; + cfg_params->roam_scan_home_away_time = + mlme_obj->cfg.lfr.roam_scan_home_away_time; + cfg_params->roam_scan_n_probes = + mlme_obj->cfg.lfr.roam_scan_n_probes; + cfg_params->roam_scan_inactivity_time = + mlme_obj->cfg.lfr.roam_scan_inactivity_time; + cfg_params->roam_inactive_data_packet_count = + mlme_obj->cfg.lfr.roam_inactive_data_packet_count; + ucfg_reg_get_band(wlan_vdev_get_pdev(vdev), ¤t_band); + rso_cfg->roam_band_bitmask = current_band; +} + +QDF_STATUS cm_roam_control_restore_default_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct rso_chan_info *chan_info; + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + goto out; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + goto out; + + if (!mlme_obj->cfg.lfr.roam_scan_offload_enabled) { + mlme_err("roam_scan_offload_enabled is not supported"); + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + goto out; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + goto out; + } + cfg_params = &rso_cfg->cfg_param; + + chan_info = &cfg_params->pref_chan_info; + cm_flush_roam_channel_list(chan_info); + + chan_info = &cfg_params->specific_chan_info; + cm_flush_roam_channel_list(chan_info); + + mlme_reinit_control_config_lfr_params(psoc, &mlme_obj->cfg.lfr); + + cm_restore_default_roaming_params(mlme_obj, vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + if (MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + cm_roam_send_rso_cmd(psoc, vdev_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_FLUSH_CHANNEL_LIST); + cm_roam_send_rso_cmd(psoc, vdev_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, + REASON_SCORING_CRITERIA_CHANGED); + } + + status = QDF_STATUS_SUCCESS; +out: + return status; +} + +void cm_update_pmk_cache_ft(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wlan_objmgr_vdev *vdev; + struct wlan_crypto_pmksa pmksa; + enum QDF_OPMODE vdev_mode; + struct cm_roam_values_copy src_cfg; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev is NULL"); + return; + } + + vdev_mode = wlan_vdev_mlme_get_opmode(vdev); + /* If vdev mode is STA then proceed further */ + if (vdev_mode != QDF_STA_MODE) { + mlme_err("vdev mode is not STA"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + + /* + * In FT connection fetch the MDID from Session or scan result whichever + * and send it to crypto so that it will update the crypto PMKSA table + * with the MDID for the matching BSSID or SSID PMKSA entry. And delete + * the old/stale PMK cache entries for the same mobility domain as of + * the newly added entry to avoid multiple PMK cache entries for the + * same MDID. + */ + wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, &pmksa.bssid); + wlan_vdev_mlme_get_ssid(vdev, pmksa.ssid, &pmksa.ssid_len); + wlan_cm_roam_cfg_get_value(psoc, vdev_id, MOBILITY_DOMAIN, &src_cfg); + + if (pmk_cache) + qdf_mem_copy(pmksa.cache_id, pmk_cache->cache_id, + WLAN_CACHE_ID_LEN); + + if (src_cfg.bool_value) { + pmksa.mdid.mdie_present = 1; + pmksa.mdid.mobility_domain = src_cfg.uint_value; + mlme_debug("MDID:0x%x copied to PMKSA", src_cfg.uint_value); + + status = wlan_crypto_update_pmk_cache_ft(vdev, &pmksa); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("Failed to update the crypto table"); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +bool cm_lookup_pmkid_using_bssid(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + struct wlan_crypto_pmksa *pmksa; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("Invalid vdev"); + return false; + } + + pmksa = wlan_crypto_get_pmksa(vdev, &pmk_cache->bssid); + if (!pmksa) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return false; + } + qdf_mem_copy(pmk_cache->pmkid, pmksa->pmkid, sizeof(pmk_cache->pmkid)); + qdf_mem_copy(pmk_cache->pmk, pmksa->pmk, pmksa->pmk_len); + pmk_cache->pmk_len = pmksa->pmk_len; + pmk_cache->pmk_lifetime = pmksa->pmk_lifetime; + pmk_cache->pmk_lifetime_threshold = pmksa->pmk_lifetime_threshold; + pmk_cache->pmk_entry_ts = pmksa->pmk_entry_ts; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return true; +} + +/** + * cm_roam_clear_is_disable_btm_flag - API to clear is_disable_btm flag + * @pdev: pdev pointer + * @vdev_id: dvev ID + * + * Return: None + */ +static void cm_roam_clear_is_disable_btm_flag(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + mlme_debug("vdev: %d rso_cfg is NULL", vdev_id); + goto release_ref; + } + + if (rso_cfg->is_disable_btm) { + mlme_debug("vdev: %d clear is_disable_btm flag", vdev_id); + rso_cfg->is_disable_btm = false; + } + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void cm_roam_restore_default_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + struct cm_roam_values_copy src_config = {}; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + uint32_t roam_trigger_bitmap; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + cm_roam_clear_is_disable_btm_flag(pdev, vdev_id); + + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) { + /* + * When vendor handoff is enabled and disconnection is received, + * then restore the roam trigger bitmap from the ini + * configuration + */ + wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_CONFIG_ENABLE, + &src_config); + if (src_config.bool_value) { + roam_trigger_bitmap = + wlan_mlme_get_roaming_triggers(psoc); + mlme_set_roam_trigger_bitmap(psoc, vdev_id, + roam_trigger_bitmap); + } + + src_config.bool_value = 0; + wlan_cm_roam_cfg_set_value(psoc, vdev_id, ROAM_CONFIG_ENABLE, + &src_config); + } + + cm_roam_control_restore_default_config(pdev, vdev_id); +} + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +void +cm_store_sae_single_pmk_to_global_cache(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + struct mlme_pmk_info *pmk_info; + struct wlan_crypto_pmksa *pmksa; + struct cm_roam_values_copy src_cfg; + struct qdf_mac_addr bssid; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + int32_t akm; + + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + IS_SINGLE_PMK, &src_cfg); + if (!src_cfg.bool_value || + !(QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY))) + return; + /* + * Mark the AP as single PMK capable in Crypto Table + */ + wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, &bssid); + wlan_crypto_set_sae_single_pmk_bss_cap(vdev, &bssid, true); + + pmk_info = qdf_mem_malloc(sizeof(*pmk_info)); + if (!pmk_info) + return; + + wlan_cm_get_psk_pmk(pdev, vdev_id, pmk_info->pmk, &pmk_info->pmk_len); + + pmksa = wlan_crypto_get_pmksa(vdev, &bssid); + if (pmksa) { + pmk_info->spmk_timeout_period = + (pmksa->pmk_lifetime * + pmksa->pmk_lifetime_threshold / 100); + pmk_info->spmk_timestamp = pmksa->pmk_entry_ts; + mlme_debug("spmk_ts:%ld spmk_timeout_prd:%d secs", + pmk_info->spmk_timestamp, + pmk_info->spmk_timeout_period); + } else { + mlme_debug("PMK entry not found for bss:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + } + + wlan_mlme_update_sae_single_pmk(vdev, pmk_info); + + qdf_mem_zero(pmk_info, sizeof(*pmk_info)); + qdf_mem_free(pmk_info); +} + +void cm_check_and_set_sae_single_pmk_cap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t pmk_len) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_pmk_info *pmk_info; + struct wlan_crypto_pmksa *pmkid_cache, *roam_sync_pmksa; + int32_t keymgmt; + bool lookup_success; + QDF_STATUS status; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_ZERO_INIT; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("get vdev failed"); + return; + } + status = wlan_vdev_get_bss_peer_mac_for_pmksa(vdev, &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to find connected bssid"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + keymgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (keymgmt < 0) { + mlme_err("Invalid mgmt cipher"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + + if (keymgmt & (1 << WLAN_CRYPTO_KEY_MGMT_SAE)) { + struct cm_roam_values_copy src_cfg; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, IS_SINGLE_PMK, + &src_cfg); + wlan_mlme_set_sae_single_pmk_bss_cap(psoc, vdev_id, + src_cfg.bool_value); + if (!src_cfg.bool_value) + goto end; + + roam_sync_pmksa = qdf_mem_malloc(sizeof(*roam_sync_pmksa)); + if (roam_sync_pmksa) { + qdf_copy_macaddr(&roam_sync_pmksa->bssid, &bssid); + roam_sync_pmksa->single_pmk_supported = true; + roam_sync_pmksa->pmk_len = pmk_len; + qdf_mem_copy(roam_sync_pmksa->pmk, psk_pmk, + roam_sync_pmksa->pmk_len); + mlme_debug("SPMK received for " QDF_MAC_ADDR_FMT "pmk_len:%d", + QDF_MAC_ADDR_REF(roam_sync_pmksa->bssid.bytes), + roam_sync_pmksa->pmk_len); + /* update single pmk info for roamed ap to pmk table */ + wlan_crypto_set_sae_single_pmk_info(vdev, + roam_sync_pmksa); + + qdf_mem_zero(roam_sync_pmksa, sizeof(*roam_sync_pmksa)); + qdf_mem_free(roam_sync_pmksa); + } else { + goto end; + } + + pmkid_cache = qdf_mem_malloc(sizeof(*pmkid_cache)); + if (!pmkid_cache) + goto end; + + qdf_copy_macaddr(&pmkid_cache->bssid, &bssid); + /* + * In SAE single pmk roaming case, there will + * be no PMK entry found for the AP in pmk cache. + * So if the lookup is successful, then we have done + * a FULL sae here. In that case, clear all other + * single pmk entries. + */ + lookup_success = + cm_lookup_pmkid_using_bssid(psoc, vdev_id, pmkid_cache); + if (lookup_success) { + wlan_crypto_selective_clear_sae_single_pmk_entries(vdev, + &bssid); + + pmk_info = qdf_mem_malloc(sizeof(*pmk_info)); + if (!pmk_info) { + qdf_mem_zero(pmkid_cache, sizeof(*pmkid_cache)); + qdf_mem_free(pmkid_cache); + goto end; + } + + qdf_mem_copy(pmk_info->pmk, pmkid_cache->pmk, + pmkid_cache->pmk_len); + pmk_info->pmk_len = pmkid_cache->pmk_len; + pmk_info->spmk_timestamp = pmkid_cache->pmk_entry_ts; + pmk_info->spmk_timeout_period = + (pmkid_cache->pmk_lifetime * + pmkid_cache->pmk_lifetime_threshold / 100); + + wlan_mlme_update_sae_single_pmk(vdev, pmk_info); + + qdf_mem_zero(pmk_info, sizeof(*pmk_info)); + qdf_mem_free(pmk_info); + } + + qdf_mem_zero(pmkid_cache, sizeof(*pmkid_cache)); + qdf_mem_free(pmkid_cache); + } + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} +#endif + +bool cm_is_auth_type_11r(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_objmgr_vdev *vdev, + bool mdie_present) +{ + int32_t akm; + + akm = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + + if (cm_is_open_mode(vdev)) { + if (mdie_present && mlme_obj->cfg.lfr.enable_ftopen) + return true; + } else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK) || + QDF_HAS_PARAM(akm, + WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) { + return true; + } + + return false; +} + +#ifdef FEATURE_WLAN_ESE +bool +cm_ese_open_present(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + bool ese_version_present) +{ + if (cm_is_open_mode(vdev) && ese_version_present && + mlme_obj->cfg.lfr.ese_enabled) + return true; + + return false; +} + +bool +cm_is_ese_connection(struct wlan_objmgr_vdev *vdev, bool ese_version_present) +{ + int32_t akm; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("psoc not found"); + return false; + } + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + if (!mlme_obj->cfg.lfr.ese_enabled) + return false; + + akm = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return true; + + /* + * A profile can not be both ESE and 11R. But an 802.11R AP + * may be advertising support for ESE as well. So if we are + * associating Open or explicitly ESE then we will get ESE. + * If we are associating explicitly 11R only then we will get + * 11R. + */ + return cm_ese_open_present(vdev, mlme_obj, ese_version_present); +} +#endif + +static void cm_roam_start_init(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + struct cm_roam_values_copy src_cfg = {}; + bool mdie_present; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_mlme_psoc_ext_obj *mlme_obj; + enum QDF_OPMODE opmode; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE) { + mlme_debug("Wrong opmode %d", opmode); + return; + } + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + wlan_cm_init_occupied_ch_freq_list(pdev, psoc, vdev_id); + + /* + * Update RSSI change params to vdev + */ + src_cfg.uint_value = mlme_obj->cfg.lfr.roam_rescan_rssi_diff; + wlan_cm_roam_cfg_set_value(psoc, vdev_id, + RSSI_CHANGE_THRESHOLD, &src_cfg); + + src_cfg.uint_value = mlme_obj->cfg.lfr.roam_scan_hi_rssi_delay; + wlan_cm_roam_cfg_set_value(psoc, vdev_id, + HI_RSSI_DELAY_BTW_SCANS, &src_cfg); + + wlan_cm_update_roam_scan_scheme_bitmap(psoc, vdev_id, + DEFAULT_ROAM_SCAN_SCHEME_BITMAP); + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + MOBILITY_DOMAIN, &src_cfg); + + mdie_present = src_cfg.bool_value; + /* Based on the auth scheme tell if we are 11r */ + if (cm_is_auth_type_11r(mlme_obj, vdev, mdie_present)) { + src_cfg.bool_value = true; + } else { + src_cfg.bool_value = false; + } + wlan_cm_roam_cfg_set_value(psoc, vdev_id, + IS_11R_CONNECTION, &src_cfg); + + src_cfg.uint_value = mlme_obj->cfg.lfr.roam_rssi_diff_6ghz; + wlan_cm_roam_cfg_set_value(psoc, vdev_id, + ROAM_RSSI_DIFF_6GHZ, &src_cfg); + + if (!mlme_obj->cfg.lfr.roam_scan_offload_enabled) + return; + /* + * Store the current PMK info of the AP + * to the single pmk global cache if the BSS allows + * single pmk roaming capable. + */ + cm_store_sae_single_pmk_to_global_cache(psoc, pdev, vdev); + + if (!MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) { + wlan_clear_sae_auth_logs_cache(psoc, vdev_id); + wlan_cm_roam_state_change(pdev, vdev_id, + WLAN_ROAM_RSO_ENABLED, + REASON_CTX_INIT); + } +} + +void cm_roam_start_init_on_connect(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev_id: %d: vdev not found", vdev_id); + return; + } + cm_roam_start_init(psoc, pdev, vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void cm_update_session_assoc_ie(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct element_info *assoc_ie) +{ + struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto rel_vdev_ref; + + if (rso_cfg->assoc_ie.ptr) { + qdf_mem_free(rso_cfg->assoc_ie.ptr); + rso_cfg->assoc_ie.ptr = NULL; + rso_cfg->assoc_ie.len = 0; + } + if (!assoc_ie->len) { + sme_debug("Assoc IE len 0"); + goto rel_vdev_ref; + } + rso_cfg->assoc_ie.ptr = qdf_mem_malloc(assoc_ie->len); + if (!rso_cfg->assoc_ie.ptr) + goto rel_vdev_ref; + + rso_cfg->assoc_ie.len = assoc_ie->len; + qdf_mem_copy(rso_cfg->assoc_ie.ptr, assoc_ie->ptr, assoc_ie->len); +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +/** + * cm_dlm_is_bssid_in_reject_list() - Check whether a BSSID is present in + * reject list or not + * @psoc: psoc pointer + * @bssid: bssid to check + * @vdev_id: vdev id + * + * Return: true if BSSID is present in reject list + */ +static bool cm_dlm_is_bssid_in_reject_list(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *bssid, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + bool is_bssid_in_reject_list = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return is_bssid_in_reject_list; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + goto rel_vdev_ref; + + is_bssid_in_reject_list = + wlan_dlm_is_bssid_in_reject_list(pdev, bssid); + +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return is_bssid_in_reject_list; +} + +QDF_STATUS cm_start_roam_invoke(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid, + qdf_freq_t chan_freq, + enum wlan_cm_source source) +{ + struct cm_req *cm_req; + QDF_STATUS status; + uint8_t roam_control_bitmap; + struct qdf_mac_addr connected_bssid; + uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; + bool roam_offload_enabled = cm_roam_offload_enabled(psoc); + struct rso_config *rso_cfg; + + roam_control_bitmap = mlme_get_operations_bitmap(psoc, vdev_id); + if (roam_offload_enabled && (roam_control_bitmap || + !MLME_IS_ROAM_INITIALIZED(psoc, vdev_id))) { + mlme_debug("ROAM: RSO Disabled internally: vdev[%d] bitmap[0x%x]", + vdev_id, roam_control_bitmap); + return QDF_STATUS_E_FAILURE; + } + + cm_req = qdf_mem_malloc(sizeof(*cm_req)); + if (!cm_req) + return QDF_STATUS_E_NOMEM; + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_err("MLO ROAM: Invalid Roam req on link vdev %d", vdev_id); + qdf_mem_free(cm_req); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_NULL_VALUE; + + /* Ignore BSSID and channel validation for FW host roam */ + if (source == CM_ROAMING_FW) + goto send_evt; + if (source == CM_ROAMING_LINK_REMOVAL) { + cm_req->roam_req.req.forced_roaming = true; + goto send_evt; + } + + if (cm_dlm_is_bssid_in_reject_list(psoc, bssid, vdev_id)) { + mlme_debug("BSSID is in reject list, aborting roam invoke"); + qdf_mem_free(cm_req); + return QDF_STATUS_E_FAILURE; + } + + if (qdf_is_macaddr_zero(bssid)) { + if (!wlan_mlme_is_data_stall_recovery_fw_supported(psoc)) { + mlme_debug("FW does not support data stall recovery, aborting roam invoke"); + qdf_mem_free(cm_req); + return QDF_STATUS_E_NOSUPPORT; + } + + cm_req->roam_req.req.forced_roaming = true; + if (source == CM_ROAMING_HOST || source == CM_ROAMING_USER) + rso_cfg->is_forced_roaming = true; + source = CM_ROAMING_NUD_FAILURE; + goto send_evt; + } + + if (qdf_is_macaddr_broadcast(bssid)) { + qdf_copy_macaddr(&cm_req->roam_req.req.bssid, bssid); + qdf_copy_macaddr(&rso_cfg->roam_invoke_bssid, bssid); + mlme_debug("Roam only if better candidate found else stick to current AP"); + goto send_evt; + } + + wlan_vdev_get_bss_peer_mac(vdev, &connected_bssid); + if (qdf_is_macaddr_equal(bssid, &connected_bssid)) { + mlme_debug("Reassoc BSSID is same as currently associated AP"); + chan_freq = wlan_get_operation_chan_freq(vdev); + } + + if (!chan_freq || qdf_is_macaddr_zero(bssid)) { + mlme_debug("bssid " QDF_MAC_ADDR_FMT " chan_freq %d", + QDF_MAC_ADDR_REF(bssid->bytes), chan_freq); + qdf_mem_free(cm_req); + return QDF_STATUS_E_FAILURE; + } + + qdf_copy_macaddr(&cm_req->roam_req.req.bssid, bssid); + cm_req->roam_req.req.chan_freq = chan_freq; + +send_evt: + cm_req->roam_req.req.source = source; + + /* Storing source information in rso cfg as if FW aborts + * roam host will delete roam req from queue. + * In roam invoke failure, host will read rso cfg params + * information and disconnect if needed. + */ + if (source == CM_ROAMING_HOST || + source == CM_ROAMING_NUD_FAILURE || + source == CM_ROAMING_LINK_REMOVAL || + source == CM_ROAMING_USER) + rso_cfg->roam_invoke_source = source; + + cm_req->roam_req.req.vdev_id = vdev_id; + /* + * For LFR3 WLAN_CM_SM_EV_ROAM_REQ will be converted to + * WLAN_CM_SM_EV_ROAM_INVOKE. + */ + status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_REQ, + sizeof(*cm_req), cm_req); + + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(cm_req); + + return status; +} + +#if (defined(CONNECTIVITY_DIAG_EVENT) || \ + defined(WLAN_FEATURE_CONNECTIVITY_LOGGING)) && \ + defined(WLAN_FEATURE_ROAM_OFFLOAD) +static bool wlan_is_valid_frequency(uint32_t freq, uint32_t band_capability, + uint32_t band_mask) +{ + bool is_2g_band, is_5g_band, is_6g_band; + + if (band_capability == REG_BAND_MASK_ALL && + band_mask == REG_BAND_MASK_ALL) + return true; + + is_2g_band = (band_capability & BIT(REG_BAND_2G)) && + (band_mask & BIT(REG_BAND_2G)); + is_5g_band = (band_capability & BIT(REG_BAND_5G)) && + (band_mask & BIT(REG_BAND_5G)); + is_6g_band = (band_capability & BIT(REG_BAND_6G)) && + (band_mask & BIT(REG_BAND_6G)); + + if (!is_6g_band && WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) + return false; + + if (!is_5g_band && WLAN_REG_IS_5GHZ_CH_FREQ(freq)) + return false; + + if (!is_2g_band && WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + return false; + + return true; +} + +static +void cm_roam_send_beacon_loss_event(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr bssid, + uint8_t vdev_id, + uint8_t trig_reason, + uint8_t is_roam_success, + bool is_full_scan, + uint8_t roam_fail_reason) +{ + bool bmiss_skip_full_scan = false; + + /* + * When roam trigger reason is Beacon Miss, 2 roam scan + * stats TLV will be received with reason as BMISS. + * 1. First TLV is for partial roam scan data and + * 2. Second TLV is for the full scan data when there is no candidate + * found in the partial scan. + * When bmiss_skip_full_scan flag is disabled, prints for 1 & 2 will be + * seen. + * when bmiss_skip_full_scan flag is enabled, only print for 1st TLV + * will be seen. + * + * 1. BMISS_DISCONN event should be triggered only once for BMISS roam + * trigger if roam result is failure after full scan TLV is received and + * bmiss_skip_full_scan is disabled. + * + * 2. But if bmiss_skip_full_scan is enabled, then trigger + * BMISS_DISCONN event after partial scan TLV is received + * + * 3. In some cases , Keepalive ACK from AP might come after the + * final BMISS and FW can choose to stay connected to the current AP. + * In this case, don't send discon event. + */ + + wlan_mlme_get_bmiss_skip_full_scan_value(psoc, &bmiss_skip_full_scan); + + if (trig_reason == ROAM_TRIGGER_REASON_BMISS && + !is_roam_success && + ((!bmiss_skip_full_scan && is_full_scan) || + (bmiss_skip_full_scan && !is_full_scan)) && + (roam_fail_reason == + ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT || + roam_fail_reason == + ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT)) + cm_roam_beacon_loss_disconnect_event(psoc, bssid, vdev_id); +} +#endif + +#if defined(CONNECTIVITY_DIAG_EVENT) && \ + defined(WLAN_FEATURE_ROAM_OFFLOAD) +static enum diag_roam_reason +cm_get_diag_roam_reason(enum roam_trigger_reason roam_reason) +{ + switch (roam_reason) { + case ROAM_TRIGGER_REASON_PER: + return DIAG_ROAM_REASON_PER; + case ROAM_TRIGGER_REASON_BMISS: + return DIAG_ROAM_REASON_BEACON_MISS; + case ROAM_TRIGGER_REASON_LOW_RSSI: + return DIAG_ROAM_REASON_POOR_RSSI; + case ROAM_TRIGGER_REASON_HIGH_RSSI: + return DIAG_ROAM_REASON_BETTER_RSSI; + case ROAM_TRIGGER_REASON_PERIODIC: + return DIAG_ROAM_REASON_PERIODIC_TIMER; + case ROAM_TRIGGER_REASON_DENSE: + return DIAG_ROAM_REASON_CONGESTION; + case ROAM_TRIGGER_REASON_BACKGROUND: + return DIAG_ROAM_REASON_BACKGROUND_SCAN; + case ROAM_TRIGGER_REASON_FORCED: + return DIAG_ROAM_REASON_USER_TRIGGER; + case ROAM_TRIGGER_REASON_BTM: + return DIAG_ROAM_REASON_BTM; + case ROAM_TRIGGER_REASON_BSS_LOAD: + return DIAG_ROAM_REASON_BSS_LOAD; + case ROAM_TRIGGER_REASON_DEAUTH: + return DIAG_ROAM_REASON_DISCONNECTION; + case ROAM_TRIGGER_REASON_IDLE: + return DIAG_ROAM_REASON_IDLE; + case ROAM_TRIGGER_REASON_WTC_BTM: + return DIAG_ROAM_REASON_WTC; + case ROAM_TRIGGER_REASON_BTC: + return DIAG_ROAM_REASON_BT_ACTIVITY; + default: + break; + } + + return DIAG_ROAM_REASON_UNKNOWN; +} + +static enum diag_roam_sub_reason +cm_get_diag_roam_sub_reason(enum roam_trigger_sub_reason sub_reason) +{ + switch (sub_reason) { + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER: + return DIAG_ROAM_SUB_REASON_PERIODIC_TIMER; + + case ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI: + return DIAG_ROAM_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI; + + case ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER: + return DIAG_ROAM_SUB_REASON_BTM_DI_TIMER; + + case ROAM_TRIGGER_SUB_REASON_FULL_SCAN: + return DIAG_ROAM_SUB_REASON_FULL_SCAN; + + case ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC: + return DIAG_ROAM_SUB_REASON_LOW_RSSI_PERIODIC; + + case ROAM_TRIGGER_SUB_REASON_CU_PERIODIC: + return DIAG_ROAM_SUB_REASON_CU_PERIODIC; + + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY: + return DIAG_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_LOW_RSSI; + + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU: + return DIAG_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU; + + case ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU: + return DIAG_ROAM_SUB_REASON_INACTIVITY_TIMER_CU; + + default: + break; + } + + return DIAG_ROAM_SUB_REASON_UNKNOWN; +} + + +static void populate_diag_cmn(struct wlan_connectivity_log_diag_cmn *cmn, + uint8_t vdev_id, uint64_t fw_timestamp, + struct qdf_mac_addr *bssid) +{ + cmn->vdev_id = vdev_id; + cmn->timestamp_us = qdf_get_time_of_the_day_us(); + cmn->ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + cmn->fw_timestamp = fw_timestamp * 1000; + + if (!bssid) + return; + + qdf_mem_copy(cmn->bssid, bssid->bytes, QDF_MAC_ADDR_SIZE); +} + +void cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_scan_data *scan, uint8_t vdev_id) +{ + int i; + struct wmi_roam_candidate_info *ap = scan->ap; + uint32_t *chan_freq = NULL; + uint8_t count = 0, status, num_chan; + uint32_t band_capability = 0, band_mask = 0, scan_band_mask = 0; + struct wlan_diag_roam_scan_done *wlan_diag_event = NULL; + + wlan_diag_event = qdf_mem_malloc(sizeof(*wlan_diag_event)); + if (!wlan_diag_event) { + mlme_err("Mem malloc failed for wlan_diag_event"); + return; + } + + chan_freq = qdf_mem_malloc(sizeof(uint32_t) * NUM_CHANNELS); + if (!chan_freq) { + qdf_mem_free(wlan_diag_event); + mlme_err("Mem malloc failed for chan_freq"); + return; + } + + populate_diag_cmn(&wlan_diag_event->diag_cmn, vdev_id, + (uint64_t)scan->scan_complete_timestamp, &ap->bssid); + + wlan_diag_event->version = DIAG_SCAN_DONE_VERSION; + + /* + * scan->num_ap includes current connected AP also + * so subtract 1 from the count to get total candidate APs + */ + + if (scan->num_ap) + wlan_diag_event->cand_ap_count = scan->num_ap - 1; + + if (scan->present && + (scan->type == ROAM_STATS_SCAN_TYPE_FULL || + scan->type == ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ || + scan->type == ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ)) { + status = mlme_get_fw_scan_channels(psoc, chan_freq, &num_chan); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + if (num_chan > NUM_CHANNELS) { + mlme_err("unexpected num chan %d", num_chan); + goto out; + } + + status = wlan_mlme_get_band_capability(psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + + num_chan = QDF_MIN(WLAN_MAX_LOGGING_FREQ, NUM_CHANNELS); + + band_mask = policy_mgr_get_connected_roaming_vdev_band_mask( + psoc, vdev_id); + + mlme_debug("mask:%d, capability:%d, scan_type:%d, num_chan:%d", + band_mask, band_capability, scan->type, num_chan); + if (scan->type == ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ) + scan_band_mask = BIT(REG_BAND_6G); + else if (scan->type == + ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ) + scan_band_mask = BIT(REG_BAND_5G) | BIT(REG_BAND_6G); + + if (scan_band_mask) + band_mask &= scan_band_mask; + + for (i = 0; i < num_chan; i++) { + if (!wlan_is_valid_frequency(chan_freq[i], + band_capability, + band_mask)) + continue; + + wlan_diag_event->scan_freq[count] = chan_freq[i]; + count++; + } + + wlan_diag_event->num_scanned_freq = count; + } else { + if (scan->num_chan > MAX_ROAM_SCAN_CHAN) + scan->num_chan = MAX_ROAM_SCAN_CHAN; + + wlan_diag_event->num_scanned_freq = scan->num_chan; + for (i = 0; i < scan->num_chan; i++) + wlan_diag_event->scan_freq[i] = scan->chan_freq[i]; + } + + wlan_diag_event->btcoex_active = scan->is_btcoex_active; + +out: + WLAN_HOST_DIAG_EVENT_REPORT(wlan_diag_event, + EVENT_WLAN_ROAM_SCAN_DONE); + qdf_mem_free(chan_freq); + qdf_mem_free(wlan_diag_event); +} + +void cm_roam_trigger_info_event(struct wmi_roam_trigger_info *data, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id, bool is_full_scan) +{ + uint8_t i; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_roam_scan_start); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)data->timestamp, NULL); + + wlan_diag_event.trigger_reason = + cm_get_diag_roam_reason(data->trigger_reason); + + wlan_diag_event.trigger_sub_reason = + cm_get_diag_roam_sub_reason(data->trigger_sub_reason); + + wlan_diag_event.version = DIAG_ROAM_SCAN_START_VERSION_V2; + + /* + * Get the current AP rssi & CU load from the + * wmi_roam_ap_info tlv in roam scan results + */ + if (scan_data->present) { + for (i = 0; i < scan_data->num_ap; i++) { + if (i >= MAX_ROAM_CANDIDATE_AP) + break; + + if (scan_data->ap[i].type == + WLAN_ROAM_SCAN_CURRENT_AP) { + wlan_diag_event.rssi = + (-1) * scan_data->ap[i].rssi; + wlan_diag_event.cu = + scan_data->ap[i].cu_load; + break; + } + } + } + + if (data->trigger_reason == ROAM_TRIGGER_REASON_PERIODIC || + data->trigger_reason == ROAM_TRIGGER_REASON_LOW_RSSI) { + if (data->common_roam) + wlan_diag_event.rssi_thresh = + (-1) * data->low_rssi_trig_data.roam_rssi_threshold; + else + wlan_diag_event.rssi_thresh = + (-1) * data->rssi_trig_data.threshold; + } + + wlan_diag_event.is_full_scan = is_full_scan; + wlan_diag_event.band = scan_data->band; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_ROAM_SCAN_START); +} + +#define ETP_MAX_VALUE 10000000 + +void cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap, + uint8_t cand_ap_idx) +{ + uint32_t etp; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_roam_candidate_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, 0, (uint64_t)ap->timestamp, + &ap->bssid); + + wlan_diag_event.is_current_ap = (ap->type == 1); + if (wlan_diag_event.is_current_ap) + wlan_diag_event.subtype = + WLAN_CONN_DIAG_ROAM_SCORE_CUR_AP_EVENT; + else + wlan_diag_event.subtype = + WLAN_CONN_DIAG_ROAM_SCORE_CAND_AP_EVENT; + + wlan_diag_event.version = DIAG_ROAM_CAND_VERSION_V2; + wlan_diag_event.rssi = (-1) * ap->rssi; + wlan_diag_event.cu_load = ap->cu_load; + wlan_diag_event.total_score = ap->total_score; + + etp = ap->etp * 1000; + + if (etp > ETP_MAX_VALUE) + wlan_diag_event.etp = ETP_MAX_VALUE; + else + wlan_diag_event.etp = etp; + + wlan_diag_event.idx = cand_ap_idx; + wlan_diag_event.freq = ap->freq; + wlan_diag_event.is_mlo = ap->is_mlo; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_ROAM_CAND_INFO); +} + +#define WLAN_ROAM_SCAN_TYPE_PARTIAL_SCAN 0 +#define WLAN_ROAM_SCAN_TYPE_FULL_SCAN 1 + +#ifdef WLAN_FEATURE_11BE_MLO +static void +cm_populate_roam_success_mlo_param(struct wlan_objmgr_psoc *psoc, + struct wlan_diag_roam_result *event, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_objmgr_vdev *assoc_vdev = NULL; + struct qdf_mac_addr bss_peer; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev: %d not found", vdev_id); + return; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + goto out; + + event->is_mlo = true; + + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + if (!assoc_vdev) { + mlme_err("assoc vdev not found"); + goto out; + } + + status = wlan_vdev_get_bss_peer_mac(assoc_vdev, + &bss_peer); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("vdev: %d bss peer not found", + wlan_vdev_get_id(assoc_vdev)); + goto out; + } + + qdf_mem_copy(event->diag_cmn.bssid, + bss_peer.bytes, QDF_MAC_ADDR_SIZE); + +out: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} +#else +static void +cm_populate_roam_success_mlo_param(struct wlan_objmgr_psoc *psoc, + struct wlan_diag_roam_result *event, + uint8_t vdev_id) +{ +} +#endif + +/** + * cm_roam_cancel_event() - Send roam cancelled diag event + * @vdev_id: Vdev id + * @reason: Roam failure reason code + * @fw_timestamp: Firmware timestamp + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_cancel_event(uint8_t vdev_id, enum wlan_roam_failure_reason_code reason, + uint64_t fw_timestamp) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_roam_result); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, fw_timestamp, + NULL); + + wlan_diag_event.version = DIAG_ROAM_RESULT_VERSION; + wlan_diag_event.roam_fail_reason = reason; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_ROAM_CANCEL); + + return QDF_STATUS_SUCCESS; +} + +void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_trigger_info *trigger, + struct wmi_roam_result *res, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id) +{ + uint8_t i; + struct qdf_mac_addr bssid = {0}; + enum wlan_roam_failure_reason_code roam_cancel_reason; + bool roam_abort = (res->fail_reason == ROAM_FAIL_REASON_SYNC || + res->fail_reason == ROAM_FAIL_REASON_DISCONNECT || + res->fail_reason == ROAM_FAIL_REASON_HOST || + res->fail_reason == + ROAM_FAIL_REASON_INTERNAL_ABORT || + res->fail_reason == + ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO); + bool is_full_scan = (scan_data->present && + scan_data->type == WLAN_ROAM_SCAN_TYPE_FULL_SCAN); + bool is_roam_cancel = + (res->fail_reason == ROAM_FAIL_REASON_SCAN_CANCEL); + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_roam_result); + + if (is_roam_cancel) { + if (res->roam_abort_reason == + WMI_ROAM_SCAN_CANCEL_IDLE_SCREEN_ON) { + roam_cancel_reason = ROAM_FAIL_REASON_SCREEN_ACTIVITY; + } else if (res->roam_abort_reason == + WMI_ROAM_SCAN_CANCEL_OTHER_PRIORITY_ROAM_SCAN) { + roam_cancel_reason = + ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN; + } else { + mlme_debug("vdev:%d Unsupported abort reason:%d", + vdev_id, res->roam_abort_reason); + return; + } + + cm_roam_cancel_event(vdev_id, roam_cancel_reason, + res->timestamp); + return; + } + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)res->timestamp, NULL); + + wlan_diag_event.version = DIAG_ROAM_RESULT_VERSION; + wlan_diag_event.roam_fail_reason = res->fail_reason; + /* + * Print ROAM if, + * 1. FW sends res->status == 0 on successful roaming to AP + * 2. FW sends res->status == 1 if FW triggered roaming but failed due + * to the reason other than below reasons + * + * Print NO_ROAM for below reasons where either candidate AP is not + * found or we roamed to current AP itself irrespective of the + * res->status value: + * ROAM_FAIL_REASON_NO_AP_FOUND + * ROAM_FAIL_REASON_NO_CAND_AP_FOUND + * ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT + * ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT + * ROAM_FAIL_REASON_CURR_AP_STILL_OK + */ + wlan_diag_event.is_roam_successful = true; + + if (res->fail_reason == ROAM_FAIL_REASON_NO_AP_FOUND || + res->fail_reason == ROAM_FAIL_REASON_NO_CAND_AP_FOUND || + res->fail_reason == ROAM_FAIL_REASON_CURR_AP_STILL_OK || + res->fail_reason == + ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT || + res->fail_reason == + ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT) + wlan_diag_event.is_roam_successful = false; + + for (i = 0; i < scan_data->num_ap; i++) { + if (i >= MAX_ROAM_CANDIDATE_AP) + break; + if (scan_data->ap[i].type == + WLAN_ROAM_SCAN_CURRENT_AP) { + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, + scan_data->ap[i].bssid.bytes, + QDF_MAC_ADDR_SIZE); + bssid = scan_data->ap[i].bssid; + break; + } + } + + if (!qdf_is_macaddr_zero(&res->fail_bssid)) { + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, + res->fail_bssid.bytes, + QDF_MAC_ADDR_SIZE); + } + + if (!wlan_diag_event.is_roam_successful) + cm_populate_roam_success_mlo_param(psoc, &wlan_diag_event, + vdev_id); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_ROAM_RESULT); + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + if (roam_abort) { + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)res->timestamp, NULL); + + wlan_diag_event.roam_fail_reason = res->fail_reason; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, + EVENT_WLAN_ROAM_CANCEL); + } + + cm_roam_send_beacon_loss_event(psoc, bssid, vdev_id, + trigger->trigger_reason, + wlan_diag_event.is_roam_successful, + is_full_scan, res->fail_reason); +} + +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static QDF_STATUS +cm_find_roam_candidate(struct wlan_objmgr_pdev *pdev, + struct cnx_mgr *cm_ctx, + struct cm_roam_req *roam_req, + struct roam_invoke_req *roam_invoke_req) +{ + struct scan_filter *filter; + qdf_list_t *candidate_list; + uint32_t num_bss = 0; + qdf_list_node_t *cur_node = NULL; + struct scan_cache_node *candidate = NULL; + + if (!roam_invoke_req) + return QDF_STATUS_E_FAILURE; + + if (qdf_is_macaddr_zero(&roam_invoke_req->target_bssid) || + !roam_invoke_req->ch_freq) + return QDF_STATUS_E_FAILURE; + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return QDF_STATUS_E_NOMEM; + + filter->num_of_bssid = 1; + qdf_copy_macaddr(&filter->bssid_list[0], + &roam_invoke_req->target_bssid); + filter->num_of_channels = 1; + filter->chan_freq_list[0] = roam_invoke_req->ch_freq; + + candidate_list = wlan_scan_get_result(pdev, filter); + if (candidate_list) { + num_bss = qdf_list_size(candidate_list); + mlme_debug(CM_PREFIX_FMT "num_entries found %d", + CM_PREFIX_REF(roam_req->req.vdev_id, + roam_req->cm_id), + num_bss); + } + qdf_mem_free(filter); + + if (!candidate_list || !qdf_list_size(candidate_list)) { + if (candidate_list) + wlan_scan_purge_results(candidate_list); + mlme_info(CM_PREFIX_FMT "no valid candidate found, num_bss %d", + CM_PREFIX_REF(roam_req->req.vdev_id, + roam_req->cm_id), + num_bss); + + return QDF_STATUS_E_EMPTY; + } + + qdf_list_peek_front(candidate_list, &cur_node); + candidate = qdf_container_of(cur_node, + struct scan_cache_node, + node); + + roam_invoke_req->frame_len = candidate->entry->raw_frame.len; + + if (!roam_invoke_req->frame_len) + return QDF_STATUS_E_INVAL; + + roam_invoke_req->frame_buf = qdf_mem_malloc(roam_invoke_req->frame_len); + + if (!roam_invoke_req->frame_buf) { + roam_invoke_req->frame_len = 0; + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(roam_invoke_req->frame_buf, + candidate->entry->raw_frame.ptr, + roam_invoke_req->frame_len); + + wlan_scan_purge_results(candidate_list); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_send_roam_invoke_req(struct cnx_mgr *cm_ctx, struct cm_req *req) +{ + QDF_STATUS status; + struct qdf_mac_addr connected_bssid; + struct cm_roam_req *roam_req; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct roam_invoke_req *roam_invoke_req = NULL; + wlan_cm_id cm_id; + uint8_t vdev_id; + uint8_t enable_self_bss_roam = false; + + if (!req) + return QDF_STATUS_E_FAILURE; + + roam_req = &req->roam_req; + cm_id = req->cm_id; + vdev_id = roam_req->req.vdev_id; + + pdev = wlan_vdev_get_pdev(cm_ctx->vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "Failed to find pdev", + CM_PREFIX_REF(vdev_id, cm_id)); + status = QDF_STATUS_E_FAILURE; + goto roam_err; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "Failed to find psoc", + CM_PREFIX_REF(vdev_id, cm_id)); + status = QDF_STATUS_E_FAILURE; + goto roam_err; + } + + if (wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + mlme_debug("MLO ROAM: skip RSO cmd for link vdev %d", vdev_id); + status = QDF_STATUS_E_FAILURE; + goto roam_err; + } + + wlan_vdev_get_bss_peer_mac(cm_ctx->vdev, &connected_bssid); + wlan_mlme_get_self_bss_roam(psoc, &enable_self_bss_roam); + if (!enable_self_bss_roam && + qdf_is_macaddr_equal(&roam_req->req.bssid, &connected_bssid)) { + mlme_err(CM_PREFIX_FMT "self bss roam disabled", + CM_PREFIX_REF(vdev_id, cm_id)); + status = QDF_STATUS_E_FAILURE; + goto roam_err; + } + + roam_invoke_req = qdf_mem_malloc(sizeof(*roam_invoke_req)); + if (!roam_invoke_req) { + status = QDF_STATUS_E_NOMEM; + goto roam_err; + } + + roam_invoke_req->vdev_id = vdev_id; + if (roam_req->req.forced_roaming) { + roam_invoke_req->forced_roaming = true; + goto send_cmd; + } + + if (qdf_is_macaddr_broadcast(&roam_req->req.bssid)) { + qdf_copy_macaddr(&roam_invoke_req->target_bssid, + &roam_req->req.bssid); + goto send_cmd; + } + if (qdf_is_macaddr_equal(&roam_req->req.bssid, &connected_bssid)) + roam_invoke_req->is_same_bssid = true; + + qdf_copy_macaddr(&roam_invoke_req->target_bssid, &roam_req->req.bssid); + roam_invoke_req->ch_freq = roam_req->req.chan_freq; + + status = cm_find_roam_candidate(pdev, cm_ctx, roam_req, + roam_invoke_req); + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "No Candidate found, send roam invoke req, fw will perform scan", + CM_PREFIX_REF(vdev_id, cm_id)); + } + + if (wlan_cm_get_ese_assoc(pdev, vdev_id)) { + mlme_debug(CM_PREFIX_FMT "Beacon is not required for ESE", + CM_PREFIX_REF(vdev_id, cm_id)); + if (roam_invoke_req->frame_len) { + qdf_mem_free(roam_invoke_req->frame_buf); + roam_invoke_req->frame_buf = NULL; + roam_invoke_req->frame_len = 0; + } + } +send_cmd: + status = wlan_cm_tgt_send_roam_invoke_req(psoc, roam_invoke_req); + +roam_err: + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug(CM_PREFIX_FMT "fail to send roam invoke req", + CM_PREFIX_REF(vdev_id, cm_id)); + status = cm_sm_deliver_event_sync(cm_ctx, + WLAN_CM_SM_EV_ROAM_INVOKE_FAIL, + sizeof(wlan_cm_id), + &cm_id); + if (QDF_IS_STATUS_ERROR(status)) + cm_remove_cmd(cm_ctx, &cm_id); + } + + if (roam_invoke_req) { + if (roam_invoke_req->frame_len) + qdf_mem_free(roam_invoke_req->frame_buf); + qdf_mem_free(roam_invoke_req); + } + + return status; +} + +bool cm_roam_offload_enabled(struct wlan_objmgr_psoc *psoc) +{ + bool val; + + wlan_mlme_get_roaming_offload(psoc, &val); + + return val; +} + +#if defined(WLAN_FEATURE_CONNECTIVITY_LOGGING) || \ + defined(CONNECTIVITY_DIAG_EVENT) +static enum wlan_main_tag +cm_roam_get_tag(enum mgmt_subtype subtype, bool is_tx) +{ + switch (subtype) { + case MGMT_SUBTYPE_ASSOC_REQ: + return WLAN_ASSOC_REQ; + case MGMT_SUBTYPE_ASSOC_RESP: + return WLAN_ASSOC_RSP; + case MGMT_SUBTYPE_REASSOC_REQ: + return WLAN_REASSOC_REQ; + case MGMT_SUBTYPE_REASSOC_RESP: + return WLAN_REASSOC_RSP; + case MGMT_SUBTYPE_DISASSOC: + if (is_tx) + return WLAN_DISASSOC_TX; + else + return WLAN_DISASSOC_RX; + break; + case MGMT_SUBTYPE_AUTH: + if (is_tx) + return WLAN_AUTH_REQ; + else + return WLAN_AUTH_RESP; + break; + case MGMT_SUBTYPE_DEAUTH: + if (is_tx) + return WLAN_DEAUTH_TX; + else + return WLAN_DEAUTH_RX; + default: + break; + } + + return WLAN_TAG_MAX; +} + +static enum wlan_main_tag +cm_roam_get_eapol_tag(enum wlan_roam_frame_subtype subtype) +{ + switch (subtype) { + case ROAM_FRAME_SUBTYPE_M1: + return WLAN_EAPOL_M1; + case ROAM_FRAME_SUBTYPE_M2: + return WLAN_EAPOL_M2; + case ROAM_FRAME_SUBTYPE_M3: + return WLAN_EAPOL_M3; + case ROAM_FRAME_SUBTYPE_M4: + return WLAN_EAPOL_M4; + case ROAM_FRAME_SUBTYPE_GTK_M1: + return WLAN_GTK_M1; + case ROAM_FRAME_SUBTYPE_GTK_M2: + return WLAN_GTK_M2; + default: + break; + } + + return WLAN_TAG_MAX; +} +#endif + +#if defined(CONNECTIVITY_DIAG_EVENT) +QDF_STATUS +cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_btm_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)btm_data->req_time, NULL); + + wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_QUERY_EVENT; + wlan_diag_event.version = DIAG_BTM_VERSION_2; + wlan_diag_event.token = btm_data->btm_query_token; + wlan_diag_event.reason = btm_data->btm_query_reason; + wlan_diag_event.band = btm_data->band; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM); + + return status; +} + +void +cm_roam_neigh_rpt_req_event(struct wmi_neighbor_report_data *neigh_rpt, + struct wlan_objmgr_vdev *vdev) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_nbr_rpt); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, wlan_vdev_get_id(vdev), + (uint64_t)neigh_rpt->timestamp, NULL); + + wlan_diag_event.subtype = WLAN_CONN_DIAG_NBR_RPT_REQ_EVENT; + wlan_diag_event.version = DIAG_NBR_RPT_VERSION_2; + wlan_diag_event.token = neigh_rpt->req_token; + wlan_diag_event.band = neigh_rpt->band; + + wlan_vdev_mlme_get_ssid(vdev, wlan_diag_event.ssid, + (uint8_t *)&wlan_diag_event.ssid_len); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_NBR_RPT); +} + +void +cm_roam_neigh_rpt_resp_event(struct wmi_neighbor_report_data *neigh_rpt, + uint8_t vdev_id) +{ + uint8_t i; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_nbr_rpt); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)neigh_rpt->timestamp, NULL); + + wlan_diag_event.subtype = WLAN_CONN_DIAG_NBR_RPT_RESP_EVENT; + wlan_diag_event.version = DIAG_NBR_RPT_VERSION_2; + wlan_diag_event.token = neigh_rpt->resp_token; + wlan_diag_event.num_freq = neigh_rpt->num_freq; + + for (i = 0; i < neigh_rpt->num_freq; i++) + wlan_diag_event.freq[i] = neigh_rpt->freq[i]; + + wlan_diag_event.num_rpt = neigh_rpt->num_rpt; + wlan_diag_event.band = neigh_rpt->band; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_NBR_RPT); +} + +#define WTC_BTM_RESPONSE_SUBCODE 0xFF +static void +cm_roam_wtc_btm_event(struct wmi_roam_trigger_info *trigger_info, + struct roam_btm_response_data *btm_data, + uint8_t vdev_id, bool is_wtc) +{ + struct wmi_roam_wtc_btm_trigger_data *wtc_data = + &trigger_info->wtc_btm_trig_data; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_btm_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)trigger_info->timestamp, NULL); + + wlan_diag_event.version = DIAG_BTM_VERSION; + wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_WTC_EVENT; + + if (is_wtc) { + wlan_diag_event.reason = wtc_data->vsie_trigger_reason; + wlan_diag_event.sub_reason = wtc_data->sub_code; + wlan_diag_event.wtc_duration = wtc_data->duration; + } else { + if (!btm_data) + return; + + wlan_diag_event.reason = btm_data->vsie_reason; + wlan_diag_event.sub_reason = WTC_BTM_RESPONSE_SUBCODE; + } + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM); +} + +QDF_STATUS +cm_roam_btm_resp_event(struct wmi_roam_trigger_info *trigger_info, + struct roam_btm_response_data *btm_data, + uint8_t vdev_id, bool is_wtc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_btm_info); + + if (is_wtc) { + cm_roam_wtc_btm_event(trigger_info, btm_data, vdev_id, is_wtc); + return status; + } + + if (!btm_data) { + mlme_err("vdev_id:%d btm data is NULL", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (btm_data->vsie_reason) + cm_roam_wtc_btm_event(trigger_info, btm_data, vdev_id, is_wtc); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)btm_data->timestamp, + &btm_data->target_bssid); + + wlan_diag_event.version = DIAG_BTM_VERSION_2; + wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_RESP_EVENT; + wlan_diag_event.token = btm_data->btm_resp_dialog_token; + wlan_diag_event.status = btm_data->btm_status; + wlan_diag_event.delay = btm_data->btm_delay; + wlan_diag_event.band = btm_data->band; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM); + + return status; +} + +/** + * cm_roam_btm_candidate_event() - Send BTM roam candidate logging event + * @btm_data: BTM data + * @vdev_id: Vdev id + * @idx: Candidate instance + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_roam_btm_candidate_event(struct wmi_btm_req_candidate_info *btm_data, + uint8_t vdev_id, uint8_t idx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, + struct wlan_diag_btm_cand_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)btm_data->timestamp, + &btm_data->candidate_bssid); + + wlan_diag_event.version = DIAG_BTM_CAND_VERSION; + wlan_diag_event.preference = btm_data->preference; + wlan_diag_event.idx = idx; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM_CAND); + + return status; +} + +QDF_STATUS +cm_roam_btm_req_event(struct wmi_neighbor_report_data *neigh_rpt, + struct wmi_roam_btm_trigger_data *btm_data, + struct wmi_roam_trigger_info *trigger_info, + uint8_t vdev_id, bool is_wtc) +{ + uint8_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_btm_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + /* The BTM req and BTM candidate event is logged twice + * for both partial and full scan but the OTA frame is received + * is received only once on the device. Restricting the + * BTM req and BTM candidate event to be logged only for partial scan + */ + if (trigger_info->present && + trigger_info->scan_type == ROAM_STATS_SCAN_TYPE_FULL && + btm_data->disassoc_timer) + return status; + + if (neigh_rpt->resp_time) + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)neigh_rpt->resp_time, NULL); + else + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + (uint64_t)trigger_info->timestamp, NULL); + + + wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_REQ_EVENT; + wlan_diag_event.version = DIAG_BTM_VERSION_2; + wlan_diag_event.token = btm_data->token; + wlan_diag_event.mode = btm_data->btm_request_mode; + /* + * Diassoc Timer and Validity interval are in secs in the frame + * firmware sends it in millisecs to the host. + * Send it in secs to the userspace. + */ + wlan_diag_event.disassoc_tim = btm_data->disassoc_timer / 1000; + wlan_diag_event.validity_timer = + btm_data->validity_interval / 1000; + wlan_diag_event.cand_lst_cnt = btm_data->candidate_list_count; + wlan_diag_event.band = btm_data->band; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM); + + if (is_wtc) + cm_roam_wtc_btm_event(trigger_info, NULL, vdev_id, true); + + for (i = 0; i < btm_data->candidate_list_count; i++) + cm_roam_btm_candidate_event(&btm_data->btm_cand[i], vdev_id, i); + + return status; +} + +QDF_STATUS +cm_roam_btm_block_event(uint8_t vdev_id, uint8_t token, + enum wlan_diag_btm_block_reason reason) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_btm_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, 0, NULL); + + wlan_diag_event.subtype = WLAN_CONN_DIAG_BTM_BLOCK_EVENT; + wlan_diag_event.version = DIAG_BTM_VERSION_2; + wlan_diag_event.token = token; + wlan_diag_event.sub_reason = reason; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BTM); + + return QDF_STATUS_SUCCESS; +} + +static enum wlan_diag_wifi_band +wlan_convert_bitmap_to_band(uint8_t bitmap) +{ + uint8_t i; + enum wlan_diag_wifi_band band = WLAN_INVALID_BAND; + + for (i = WLAN_24GHZ_BAND; i <= WLAN_6GHZ_BAND; i++) { + /* 2.4 GHz band will be populated at 0th bit in the bitmap*/ + if (qdf_test_bit((i - 1), (unsigned long *)&bitmap)) { + band = i; + break; + } + } + + return band; +} + +QDF_STATUS +cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev, + struct roam_frame_info *frame_data, + struct wmi_roam_scan_data *scan_data, + struct wmi_roam_result *result) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + uint16_t diag_event; + bool is_mlo = false; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_packet_info); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, wlan_vdev_get_id(vdev), + (uint64_t)frame_data->timestamp, + &frame_data->bssid); + + wlan_diag_event.version = DIAG_MGMT_VERSION_V2; + wlan_diag_event.sn = frame_data->seq_num; + wlan_diag_event.auth_algo = frame_data->auth_algo; + wlan_diag_event.rssi = frame_data->rssi; + wlan_diag_event.tx_status = + wlan_get_diag_tx_status(frame_data->tx_status); + wlan_diag_event.status = frame_data->status_code; + wlan_diag_event.assoc_id = frame_data->assoc_id; + + if (scan_data->present) { + for (i = 0; i < scan_data->num_ap; i++) { + if (i >= MAX_ROAM_CANDIDATE_AP) + break; + if (scan_data->ap[i].type == WLAN_ROAM_SCAN_ROAMED_AP) { + wlan_diag_event.rssi = + (-1) * scan_data->ap[i].rssi; + + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, + scan_data->ap[i].bssid.bytes, + QDF_MAC_ADDR_SIZE); + break; + } else if (!memcmp(wlan_diag_event.diag_cmn.bssid, + scan_data->ap[i].bssid.bytes, + QDF_MAC_ADDR_SIZE)) { + wlan_diag_event.rssi = + (-1) * scan_data->ap[i].rssi; + break; + } + } + } + + if (frame_data->type == ROAM_FRAME_INFO_FRAME_TYPE_EXT) { + wlan_diag_event.subtype = + (uint8_t)cm_roam_get_eapol_tag(frame_data->subtype); + diag_event = EVENT_WLAN_CONN_DP; + wlan_diag_event.supported_links = + wlan_convert_bitmap_to_band(frame_data->band); + + } else { + wlan_diag_event.subtype = + (uint8_t)cm_roam_get_tag(frame_data->subtype, + !frame_data->is_rsp); + diag_event = EVENT_WLAN_MGMT; + + wlan_diag_event.supported_links = frame_data->band; + + /* + * Frame_data->band will be '0' for legacy connection and + * And will be band bit map for MLO connection where band bitmap + * as follows: + * BIT 0: 2 GHz link + * BIT 1: 5 GHz link + * BIT 2: 6 GHz link + */ + if (frame_data->band) { + is_mlo = true; + status = + wlan_populate_roam_mld_log_param(vdev, + &wlan_diag_event, + wlan_diag_event.subtype); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("vdev: %d Unable to populate MLO parameter", + wlan_vdev_get_id(vdev)); + return status; + } + } + + } + + if (wlan_diag_event.subtype > WLAN_CONN_DIAG_REASSOC_RESP_EVENT && + wlan_diag_event.subtype < WLAN_CONN_DIAG_BMISS_EVENT) + wlan_diag_event.reason = frame_data->status_code; + + if (wlan_diag_event.subtype == WLAN_CONN_DIAG_DEAUTH_RX_EVENT || + wlan_diag_event.subtype == WLAN_CONN_DIAG_DISASSOC_RX_EVENT) + wlan_populate_vsie(vdev, &wlan_diag_event, false); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, diag_event); + if (wlan_diag_event.subtype == WLAN_CONN_DIAG_REASSOC_RESP_EVENT || + wlan_diag_event.subtype == WLAN_CONN_DIAG_ASSOC_RESP_EVENT) { + wlan_connectivity_mlo_setup_event(vdev, is_mlo); + + /* + * Send STA info event when roaming is successful + */ + if (result->present && !result->status) + wlan_connectivity_sta_info_event(wlan_vdev_get_psoc(vdev), + wlan_vdev_get_id(vdev), + true); + } + + return status; +} + +QDF_STATUS +cm_roam_beacon_loss_disconnect_event(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr bssid, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_packet_info); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("Vdev[%d] is null", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return status; + } + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + populate_diag_cmn(&wlan_diag_event.diag_cmn, vdev_id, + 0, &bssid); + + wlan_diag_event.subtype = WLAN_CONN_DIAG_BMISS_EVENT; + wlan_diag_event.version = DIAG_MGMT_VERSION; + wlan_diag_event.rssi = mlme_get_hb_ap_rssi(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_MGMT); + + return status; +} +#endif + +QDF_STATUS +cm_send_rso_stop(struct wlan_objmgr_vdev *vdev) +{ + bool send_resp = true, start_timer; + + if (!vdev) { + mlme_err("vdev is NULL"); + return QDF_STATUS_E_INVAL; + } + start_timer = cm_roam_offload_enabled(wlan_vdev_get_psoc(vdev)); + + cm_roam_state_change(wlan_vdev_get_pdev(vdev), wlan_vdev_get_id(vdev), + WLAN_ROAM_RSO_STOPPED, REASON_DISCONNECTED, + &send_resp, start_timer); + /* + * RSO stop resp is not supported or RSO STOP timer/req failed, + * send QDF_STATUS_E_NOSUPPORT so that we continue from the caller + */ + if (send_resp) + return QDF_STATUS_E_NOSUPPORT; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_roam_send_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t param_value) +{ + QDF_STATUS status; + + wlan_cm_roam_set_ho_delay_config(psoc, param_value); + status = wlan_cm_tgt_send_roam_ho_delay_config(psoc, + vdev_id, param_value); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send roam HO delay config"); + + return status; +} + +QDF_STATUS +cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + QDF_STATUS status; + + wlan_cm_set_exclude_rm_partial_scan_freq(psoc, param_value); + status = wlan_cm_tgt_exclude_rm_partial_scan_freq(psoc, vdev_id, + param_value); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to exclude roam partial scan channels"); + + return status; +} + +QDF_STATUS cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t param_value) +{ + QDF_STATUS status; + + wlan_cm_roam_set_full_scan_6ghz_on_disc(psoc, param_value); + status = wlan_cm_tgt_send_roam_full_scan_6ghz_on_disc(psoc, vdev_id, + param_value); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("fail to send 6 GHz channels inclusion in full scan"); + + return status; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h new file mode 100644 index 0000000000..1573a25b1c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.h @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_offload.h + * + * Implementation for the common roaming offload api interfaces. + */ + +#ifndef _WLAN_CM_ROAM_OFFLOAD_H_ +#define _WLAN_CM_ROAM_OFFLOAD_H_ + +#include "qdf_str.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_connectivity_logging.h" + +#if defined(CONNECTIVITY_DIAG_EVENT) && \ + defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * cm_roam_scan_info_event() - send scan info to userspace + * @psoc: psoc common object + * @scan: roam scan data + * @vdev_id: vdev id + * + * Return: None + */ +void cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_scan_data *scan, uint8_t vdev_id); + +/** + * cm_roam_trigger_info_event() - send trigger info to userspace + * @data: roam trigger data + * @scan_data: Roam scan data + * @vdev_id: vdev id + * @is_full_scan: is full scan or partial scan + * + * Return: None + */ +void cm_roam_trigger_info_event(struct wmi_roam_trigger_info *data, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id, bool is_full_scan); + +/** + * cm_roam_candidate_info_event() - send trigger info to userspace + * @ap: roam candidate info + * @cand_ap_idx: Candidate AP index + * + * Return: void + */ +void cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap, + uint8_t cand_ap_idx); + +/** + * cm_roam_result_info_event() - send scan results info to userspace + * @psoc: Pointer to PSOC object + * @trigger: Roam trigger data + * @res: roam result data + * @scan_data: Roam scan info + * @vdev_id: vdev id + * + * Return: void + */ +void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_trigger_info *trigger, + struct wmi_roam_result *res, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id); +#elif defined(WLAN_FEATURE_CONNECTIVITY_LOGGING) && \ + defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * cm_roam_scan_info_event() - send scan info to userspace + * @psoc: psoc common object + * @scan: roam scan data + * @vdev_id: vdev id + * + * Return: None + */ +void cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_scan_data *scan, uint8_t vdev_id); + +/** + * cm_roam_trigger_info_event() - send trigger info to userspace + * @data: roam trigger data + * @scan_data: Roam scan data + * @vdev_id: vdev id + * @is_full_scan: is full scan or partial scan + * + * Return: None + */ +void cm_roam_trigger_info_event(struct wmi_roam_trigger_info *data, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id, bool is_full_scan); + +/** + * cm_roam_candidate_info_event() - send trigger info to userspace + * @ap: roam candidate info + * @cand_ap_idx: Candidate AP index + * + * Return: void + */ +void cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap, + uint8_t cand_ap_idx); + +/** + * cm_roam_result_info_event() - send scan results info to userspace + * @psoc: Pointer to PSOC object + * @trigger: Roam trigger data + * @res: roam result data + * @scan_data: Roam scan info + * @vdev_id: vdev id + * + * Return: void + */ +void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_trigger_info *trigger, + struct wmi_roam_result *res, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id); +#else +static inline void +cm_roam_scan_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_scan_data *scan, uint8_t vdev_id) +{ +} + +static inline void +cm_roam_trigger_info_event(struct wmi_roam_trigger_info *data, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id, bool is_full_scan) +{ +} + +static inline void +cm_roam_candidate_info_event(struct wmi_roam_candidate_info *ap, + uint8_t cand_idx) +{ +} + +static inline +void cm_roam_result_info_event(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_trigger_info *trigger, + struct wmi_roam_result *res, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id) +{ +} +#endif /* WLAN_FEATURE_CONNECTIVITY_LOGGING */ + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) + +/** + * cm_roam_state_change() - Post roam state change to roam state machine + * @pdev: pdev pointer + * @vdev_id: vdev id + * @requested_state: roam state to be set + * @reason: reason for changing roam state for the requested vdev id + * @send_resp: send rso stop response + * @start_timer: start timer for rso stop + * + * This function posts roam state change to roam state machine handling + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state requested_state, + uint8_t reason, bool *send_resp, bool start_timer); + +/** + * cm_handle_sta_sta_roaming_enablement() - To handle roaming in case + * of STA + STA + * @psoc: psoc common object + * @curr_vdev_id: Vdev id + * + * This function is to process STA + STA concurrency scenarios after roaming + * and take care of following: + * 1. Set PCL to vdev/pdev as per DBS, SCC or MCC + * 2. Enable/disable roaming based on the concurrency (DBS vs SCC/MCC) after + * roaming + * + * Return: none + */ +void cm_handle_sta_sta_roaming_enablement(struct wlan_objmgr_psoc *psoc, + uint8_t curr_vdev_id); + +/** + * cm_roam_send_rso_cmd() - send rso command + * @psoc: psoc pointer + * @vdev_id: vdev id + * @rso_command: roam command to send + * @reason: reason for changing roam state for the requested vdev id + * + * similar to csr_roam_offload_scan, will be used from many legacy + * process directly, generate a new function wlan_cm_roam_send_rso_cmd + * for external usage. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t rso_command, + uint8_t reason); + +/** + * cm_rso_set_roam_trigger() - Send roam trigger bitmap firmware + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @trigger: Carries pointer of the object containing vdev id and + * roam_trigger_bitmap. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct wlan_roam_triggers *trigger); + +/** + * cm_roam_stop_req() - roam stop request handling + * @psoc: psoc pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * @send_resp: send rso stop response + * @start_timer: start timer for rso stop + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason, bool *send_resp, bool start_timer); + +/** + * cm_roam_fill_rssi_change_params() - Fill roam scan rssi change parameters + * @psoc: PSOC pointer + * @vdev_id: vdev_id + * @params: RSSI change parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_fill_rssi_change_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_roam_rssi_change_params *params); + +/** + * cm_roam_is_change_in_band_allowed - Check whether change in roam band is + * allowed in FW or not + * @psoc: psoc pointer + * @vdev_id: VDEV id + * @roam_band_mask: band mask to check + * + * Return: return true if change in band allowed + */ +bool +cm_roam_is_change_in_band_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t roam_band_mask); + +/** + * cm_dump_freq_list() - dump chan list + * @chan_info: chan info to dump + * + * Return: void + */ +void cm_dump_freq_list(struct rso_chan_info *chan_info); + +/** + * cm_start_roam_invoke() - Validate and send Roam invoke req to CM + * @psoc: Psoc pointer + * @vdev: vdev + * @bssid: Target bssid + * @chan_freq: channel frequency on which reassoc should be send + * @source: source of the roam invoke + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_start_roam_invoke(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid, + uint32_t chan_freq, + enum wlan_cm_source source); +#endif + +/** + * cm_update_tried_candidate_freq_list() - on connection failure update + * tried_candidate_freq_list structure present in struct rso_config + * @psoc: psoc pointer + * @vdev: vdev pointer + * @connect_rsp: connect resp from VDEV mgr + * + * Return: void + */ +void +cm_update_tried_candidate_freq_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *connect_rsp); + +#ifdef FEATURE_WLAN_ESE +/** + * cm_create_roam_scan_channel_list() - create roam scan channel list + * @pdev: pdev + * @rso_cfg: roam config + * @vdev_id: vdev id + * @chan_freq_list: pointer to channel list + * @num_chan: number of channels + * @band: band enumeration + * + * This function modifies the roam scan channel list as per AP neighbor + * report; AP neighbor report may be empty or may include only other AP + * channels; in any case, we merge the channel list with the learned occupied + * channels list. + * if the band is 2.4G, then make sure channel list contains only 2.4G + * valid channels if the band is 5G, then make sure channel list contains + * only 5G valid channels + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS cm_create_roam_scan_channel_list(struct wlan_objmgr_pdev *pdev, + struct rso_config *rso_cfg, + uint8_t vdev_id, + qdf_freq_t *chan_freq_list, + uint8_t num_chan, + const enum band_info band); +#endif + +QDF_STATUS cm_neighbor_roam_update_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t value, + uint8_t reason); +void cm_flush_roam_channel_list(struct rso_chan_info *channel_info); + +QDF_STATUS cm_roam_control_restore_default_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * cm_update_pmk_cache_ft - API to update MDID in PMKSA cache entry + * @psoc: psoc pointer + * @vdev_id: dvev ID + * @pmk_cache: pmksa from the userspace + * + * Return: None + */ +void cm_update_pmk_cache_ft(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache); + +/** + * cm_lookup_pmkid_using_bssid() - lookup pmkid using bssid + * @psoc: pointer to psoc + * @vdev_id: vdev_id + * @pmk_cache: pointer to pmk cache + * + * Return: true if pmkid is found else false + */ +bool cm_lookup_pmkid_using_bssid(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache); + +void cm_roam_restore_default_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * cm_roam_send_disable_config() - Send roam module enable/disable cfg to fw + * @psoc: PSOC pointer + * @vdev_id: vdev id + * @cfg: roaming enable/disable cfg + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_send_disable_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t cfg); + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * cm_roam_send_vendor_handoff_param_req() - send vendor handoff param cmd + * @psoc: psoc pointer + * @vdev_id: vdev id + * @param_value: roam stats param value + * @vendor_handoff_context: vendor handoff context request + * + * This function is used to send vendor handoff param cmd + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_send_vendor_handoff_param_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t param_value, + void *vendor_handoff_context); + +/** + * cm_roam_is_vendor_handoff_control_enable() - check whether vendor handoff + * control feature is enable or not in driver + * @psoc: psoc pointer + * + * Return: true if feature supports + */ +bool +cm_roam_is_vendor_handoff_control_enable(struct wlan_objmgr_psoc *psoc); + +/** + * cm_roam_update_vendor_handoff_config() - update vendor handoff param to + * rso config structure + * @psoc: psoc pointer + * @list: vendor handoff parameters to be updated + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_update_vendor_handoff_config(struct wlan_objmgr_psoc *psoc, + struct roam_vendor_handoff_params *list); +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * cm_roam_send_rt_stats_config() - Send roam event stats cfg value to FW + * @psoc: PSOC pointer + * @vdev_id: vdev id + * @param_value: roam stats enable/disable cfg + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_send_rt_stats_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value); + +/** + * cm_roam_send_ho_delay_config() - Send HO delay value to FW to delay + * hand-off (in msec) by the specified duration to receive pending rx frames + * from current BSS. + * @psoc: PSOC pointer + * @vdev_id: vdev id + * @param_value: HO delay value + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_send_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t param_value); + +/** + * cm_exclude_rm_partial_scan_freq() - Exclude the channels in roam full scan + * that are already scanned as part of partial scan. + * @psoc: PSOC pointer + * @vdev_id: vdev id + * @param_value: include/exclude the partial scan channels in roam full scan + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value); + +/** + * cm_roam_full_scan_6ghz_on_disc() - Include the 6 GHz channels in roam full + * scan only on prior discovery of any 6 GHz support in the environment + * @psoc: Pointer to psoc + * @vdev_id: vdev id + * @param_value: Include the 6 GHz channels in roam full scan: + * 1 - Include only on prior discovery of any 6 GHz support in the environment + * 0 - Include all the supported 6 GHz channels by default + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value); + +/** + * cm_set_roam_scan_high_rssi_offset() - Set the delta change in high RSSI at + * which roam scan is triggered in 2.4/5 GHz. + * @psoc: PSOC pointer + * @vdev_id: vdev id + * @param_value: Set the High RSSI delta for roam scan trigger + * * 1-16 - Set an offset value in this range + * * 0 - Disable + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value); +#else +static inline QDF_STATUS +cm_roam_send_rt_stats_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +cm_roam_send_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t param_value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +void +cm_store_sae_single_pmk_to_global_cache(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev); +/** + * cm_check_and_set_sae_single_pmk_cap() - check if the Roamed AP support + * roaming using single pmk + * with same pmk or not + * @psoc: psoc + * @vdev_id: vdev id + * @psk_pmk: pmk of roamed AP + * @pmk_len: pml length + * + * Return: void + */ +void cm_check_and_set_sae_single_pmk_cap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t pmk_len); +#else +static inline void +cm_store_sae_single_pmk_to_global_cache(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{} +static inline void +cm_check_and_set_sae_single_pmk_cap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t pmk_len) +{} +#endif + +bool cm_is_auth_type_11r(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_objmgr_vdev *vdev, + bool mdie_present); + +/** + * cm_update_owe_info() - Update owe transition mode element info + * @vdev: Object manager VDEV + * @rsp: connect resp from VDEV mgr + * @vdev_id: vdev id + * + * Return: none + */ +void cm_update_owe_info(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev, uint8_t *vdev_id, + enum roam_offload_state requested_state, + uint8_t reason, bool *is_rso_skip); +#else +static inline QDF_STATUS +cm_handle_mlo_rso_state_change(struct wlan_objmgr_pdev *pdev, uint8_t *vdev_id, + enum roam_offload_state requested_state, + uint8_t reason, bool *is_rso_skip) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +#endif + +#if (defined(CONNECTIVITY_DIAG_EVENT) && \ + defined(WLAN_FEATURE_ROAM_OFFLOAD)) +/** + * cm_roam_mgmt_frame_event() - Roam management frame event + * @vdev: vdev pointer + * @frame_data: frame_data + * @scan_data: Roam scan data + * @result: Roam result + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev, + struct roam_frame_info *frame_data, + struct wmi_roam_scan_data *scan_data, + struct wmi_roam_result *result); + +/** + * cm_roam_btm_req_event - Send BTM request related logging event + * @neigh_rpt: Neighbor report/BTM request related data + * @btm_data: BTM trigger related data + * @trigger_info: Roam trigger related info + * @vdev_id: vdev id + * @is_wtc: Is WTC or BTM response + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_btm_req_event(struct wmi_neighbor_report_data *neigh_rpt, + struct wmi_roam_btm_trigger_data *btm_data, + struct wmi_roam_trigger_info *trigger_info, + uint8_t vdev_id, bool is_wtc); + +/** + * cm_roam_btm_resp_event() - Send BTM response logging event + * @trigger_info: Roam trigger related data + * @btm_data: BTM response data + * @vdev_id: Vdev id + * @is_wtc: Is WTC or BTM response + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_btm_resp_event(struct wmi_roam_trigger_info *trigger_info, + struct roam_btm_response_data *btm_data, + uint8_t vdev_id, bool is_wtc); + +/** + * cm_roam_btm_query_event() - Send BTM query logging event + * @btm_data: BTM data + * @vdev_id: Vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data, + uint8_t vdev_id); + +/** + * cm_roam_beacon_loss_disconnect_event() - Send BMISS disconnection logging + * event + * @psoc: Pointer to PSOC object + * @bssid: BSSID + * @vdev_id: Vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_beacon_loss_disconnect_event(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr bssid, + uint8_t vdev_id); + +/** + * cm_roam_neigh_rpt_req_event() - Send Neighbor Report request logging + * event + * @neigh_rpt: Neighbor Report parameter + * @vdev: vdev pointer + */ +void +cm_roam_neigh_rpt_req_event(struct wmi_neighbor_report_data *neigh_rpt, + struct wlan_objmgr_vdev *vdev); + +/** + * cm_roam_neigh_rpt_resp_event() - Send Neighbor Report response logging + * event + * @neigh_rpt: Neighbor Report parameter + * @vdev_id: vdev id + */ +void +cm_roam_neigh_rpt_resp_event(struct wmi_neighbor_report_data *neigh_rpt, + uint8_t vdev_id); + +/** + * cm_roam_btm_block_event() - Send BTM block/drop logging event + * @vdev_id: vdev id + * @token: BTM token + * @reason: Reason for dropping the BTM frame + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_btm_block_event(uint8_t vdev_id, uint8_t token, + enum wlan_diag_btm_block_reason reason); +#else +static inline QDF_STATUS +cm_roam_mgmt_frame_event(struct wlan_objmgr_vdev *vdev, + struct roam_frame_info *frame_data, + struct wmi_roam_scan_data *scan_data, + struct wmi_roam_result *result) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +cm_roam_btm_req_event(struct wmi_neighbor_report_data *neigh_rpt, + struct wmi_roam_btm_trigger_data *btm_data, + struct wmi_roam_trigger_info *trigger_info, + uint8_t vdev_id, bool is_wtc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +cm_roam_btm_resp_event(struct wmi_roam_trigger_info *trigger_info, + struct roam_btm_response_data *btm_data, + uint8_t vdev_id, bool is_wtc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +cm_roam_btm_query_event(struct wmi_neighbor_report_data *btm_data, + uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +cm_roam_beacon_loss_disconnect_event(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr bssid, + uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +cm_roam_neigh_rpt_req_event(struct wmi_neighbor_report_data *neigh_rpt, + struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +cm_roam_neigh_rpt_resp_event(struct wmi_neighbor_report_data *neigh_rpt, + uint8_t vdev_id) +{ +} + +static inline QDF_STATUS +cm_roam_btm_block_event(uint8_t vdev_id, uint8_t token, + enum wlan_diag_btm_block_reason reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* FEATURE_CONNECTIVITY_LOGGING */ + +/** + * cm_is_mbo_ap_without_pmf() - Check if the connected AP is MBO without PMF + * @psoc: PSOC pointer + * @vdev_id: vdev id + * + * Return: True if connected AP is MBO capable without PMF + */ +bool cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * cm_fill_rso_channel_list() - Fill roam frequencies in chan_info + * @psoc: PSOC pointer + * @vdev: vdev pointer + * @rso_cfg: roam config + * @chan_info: roam scan channel list + * @reason: Channel update reason + * + * Return: None + */ +void cm_fill_rso_channel_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info, + uint8_t reason); +#endif /* _WLAN_CM_ROAM_OFFLOAD_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c new file mode 100644 index 0000000000..db4721a47e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_offload_event.c + * + * Implementation for the FW based roaming events api interfaces. + */ +#include "qdf_status.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_cm_roam_i.h" +#include +#include "wlan_scan_public_structs.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_serialization_api.h" +#include "wlan_cm_roam_api.h" +#include +#include "connection_mgr/core/src/wlan_cm_roam.h" +#include "connection_mgr/core/src/wlan_cm_sm.h" +#include "connection_mgr/core/src/wlan_cm_main_api.h" +#include "wlan_roam_debug.h" +#include "wlan_mlo_mgr_roam.h" + +#define FW_ROAM_SYNC_TIMEOUT 7000 + +static QDF_STATUS +cm_fw_roam_ser_cb(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + struct cnx_mgr *cm_ctx; + + if (!cmd) { + mlme_err("cmd is NULL, reason: %d", reason); + QDF_ASSERT(0); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev = cmd->vdev; + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) + return QDF_STATUS_E_NULL_VALUE; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + cm_ctx->active_cm_id = cmd->cmd_id; + break; + case WLAN_SER_CB_CANCEL_CMD: + /* command removed from pending list. */ + break; + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + mlme_err(CM_PREFIX_FMT "Active command timeout", + CM_PREFIX_REF(wlan_vdev_get_id(vdev), cmd->cmd_id)); + + cm_abort_fw_roam(cm_ctx, cmd->cmd_id); + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + cm_reset_active_cm_id(vdev, cmd->cmd_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + break; + default: + QDF_ASSERT(0); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +QDF_STATUS cm_abort_fw_roam(struct cnx_mgr *cm_ctx, + wlan_cm_id cm_id) +{ + QDF_STATUS status; + enum wlan_cm_source source = CM_SOURCE_INVALID; + struct cm_roam_req *roam_req; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_ZERO_INIT; + + roam_req = cm_get_first_roam_command(cm_ctx->vdev); + if (roam_req) { + source = roam_req->req.source; + bssid = roam_req->req.bssid; + } + + mlme_cm_osif_roam_abort_ind(cm_ctx->vdev); + status = cm_sm_deliver_event(cm_ctx->vdev, + WLAN_CM_SM_EV_ROAM_ABORT, + sizeof(wlan_cm_id), &cm_id); + if (QDF_IS_STATUS_ERROR(status)) + cm_remove_cmd(cm_ctx, &cm_id); + + return status; +} + +QDF_STATUS +cm_add_fw_roam_dummy_ser_cb(struct wlan_objmgr_pdev *pdev, + struct cnx_mgr *cm_ctx, + struct cm_req *cm_req) +{ + struct wlan_serialization_command cmd = {0, }; + enum wlan_serialization_status ser_cmd_status; + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(cm_ctx->vdev); + + status = wlan_objmgr_vdev_try_get_ref(cm_ctx->vdev, WLAN_MLME_CM_ID); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "unable to get reference", + CM_PREFIX_REF(vdev_id, cm_req->cm_id)); + return status; + } + + cmd.cmd_type = WLAN_SER_CMD_VDEV_ROAM; + cmd.cmd_id = cm_req->cm_id; + cmd.cmd_cb = cm_fw_roam_ser_cb; + cmd.source = WLAN_UMAC_COMP_MLME; + cmd.is_high_priority = true; + cmd.cmd_timeout_duration = FW_ROAM_SYNC_TIMEOUT; + cmd.vdev = cm_ctx->vdev; + cmd.is_blocking = cm_ser_get_blocking_cmd(); + + ser_cmd_status = wlan_serialization_request(&cmd); + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + /* command moved to pending list.Do nothing */ + break; + case WLAN_SER_CMD_ACTIVE: + /* command moved to active list. Do nothing */ + break; + default: + mlme_err(CM_PREFIX_FMT "ser cmd status %d", + CM_PREFIX_REF(vdev_id, cm_req->cm_id), ser_cmd_status); + wlan_objmgr_vdev_release_ref(cm_ctx->vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_prepare_roam_cmd(struct cnx_mgr *cm_ctx, + struct cm_req **roam_req, + enum wlan_cm_source source) +{ + struct cm_req *req; + + *roam_req = qdf_mem_malloc(sizeof(**roam_req)); + if (!*roam_req) + return QDF_STATUS_E_NOMEM; + + req = *roam_req; + req->roam_req.req.source = source; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_add_fw_roam_cmd_to_list_n_ser(struct cnx_mgr *cm_ctx, + struct cm_req *cm_req) +{ + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + + pdev = wlan_vdev_get_pdev(cm_ctx->vdev); + + if (!pdev) { + mlme_err("Failed to find pdev for vdev id %d", + wlan_vdev_get_id(cm_ctx->vdev)); + return QDF_STATUS_E_FAILURE; + } + + status = cm_add_roam_req_to_list(cm_ctx, cm_req); + if (QDF_IS_STATUS_ERROR(status)) { + cm_abort_fw_roam(cm_ctx, CM_ID_INVALID); + cm_free_roam_req_mem(&cm_req->roam_req); + qdf_mem_free(cm_req); + return status; + } + + /** + * Skip adding dummy SER command for MLO link vdev. It's expected to add + * only for MLO sta in case of MLO connection + */ + if (wlan_vdev_mlme_is_mlo_link_vdev(cm_ctx->vdev)) + return status; + + status = cm_add_fw_roam_dummy_ser_cb(pdev, cm_ctx, cm_req); + if (QDF_IS_STATUS_ERROR(status)) { + cm_abort_fw_roam(cm_ctx, cm_req->roam_req.cm_id); + return status; + } + + return status; +} + +QDF_STATUS cm_fw_roam_start_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = cm_sm_deliver_event(vdev, WLAN_CM_SM_EV_ROAM_START, + 0, NULL); + + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("EV ROAM START not handled"); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} + +QDF_STATUS cm_fw_roam_start(struct cnx_mgr *cm_ctx) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + wlan_scan_id scan_id; + bool abort_host_scan_cap = false; + wlan_cm_id cm_id; + struct cm_roam_req *roam_req = NULL; + + roam_req = cm_get_first_roam_command(cm_ctx->vdev); + if (!roam_req) { + mlme_err("Failed to find roam req from list"); + cm_id = CM_ID_INVALID; + status = QDF_STATUS_E_FAILURE; + goto error; + } + + cm_id = roam_req->cm_id; + pdev = wlan_vdev_get_pdev(cm_ctx->vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "Failed to find pdev", + CM_PREFIX_REF(roam_req->req.vdev_id, + roam_req->cm_id)); + status = QDF_STATUS_E_FAILURE; + goto error; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "Failed to find psoc", + CM_PREFIX_REF(roam_req->req.vdev_id, + roam_req->cm_id)); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + status = wlan_cm_roam_state_change(pdev, + roam_req->req.vdev_id, + WLAN_ROAMING_IN_PROG, + REASON_ROAM_CANDIDATE_FOUND); + + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + mlme_cm_osif_roam_start_ind(cm_ctx->vdev); + /* + * For emergency deauth roaming, firmware sends ROAM start + * instead of ROAM scan start notification as data path queues + * will be stopped only during roam start notification. + * This is because, for deauth/disassoc triggered roam, the + * AP has sent deauth, and packets shouldn't be sent to AP + * after that. Since firmware is sending roam start directly + * host sends scan abort during roam scan, but in other + * triggers, the host receives roam start after candidate + * selection and roam scan is complete. So when host sends + * roam abort for emergency deauth roam trigger, the firmware + * roam scan is also aborted. This results in roaming failure. + * So send scan_id as CANCEL_HOST_SCAN_ID to scan module to + * abort only host triggered scans. + */ + abort_host_scan_cap = + wlan_mlme_get_host_scan_abort_support(psoc); + if (abort_host_scan_cap) + scan_id = CANCEL_HOST_SCAN_ID; + else + scan_id = INVAL_SCAN_ID; + + wlan_abort_scan(pdev, INVAL_PDEV_ID, + roam_req->req.vdev_id, + scan_id, false); +error: + if (QDF_IS_STATUS_ERROR(status)) + cm_abort_fw_roam(cm_ctx, cm_id); + + return status; +} + +QDF_STATUS cm_fw_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + struct cnx_mgr *cm_ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct cm_roam_req *roam_req = NULL; + wlan_cm_id cm_id = CM_ID_INVALID; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("Failed to find pdev for vdev id %d", + vdev_id); + goto rel_ref; + } + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) + goto rel_ref; + + roam_req = cm_get_first_roam_command(vdev); + if (roam_req) + cm_id = roam_req->cm_id; + + /* continue even if no roam command is found */ + + /* + * Switch to RSO enabled state only if the current state is + * WLAN_ROAMING_IN_PROG or WLAN_ROAM_SYNCH_IN_PROG. + * This API can be called in internal roam aborts also when + * RSO state is deinit and cause RSO start to be sent in + * disconnected state. + */ + if (MLME_IS_ROAMING_IN_PROG(psoc, vdev_id) || + MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) + status = wlan_cm_roam_state_change(pdev, vdev_id, + WLAN_ROAM_RSO_ENABLED, + REASON_ROAM_ABORT); + else if (MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) + status = wlan_cm_roam_state_change(pdev, vdev_id, + WLAN_ROAM_DEINIT, + REASON_ROAM_ABORT); + + cm_abort_fw_roam(cm_ctx, cm_id); +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} + +QDF_STATUS +cm_roam_sync_event_handler(struct wlan_objmgr_psoc *psoc, + uint8_t *event, + uint32_t len, + struct roam_offload_synch_ind *sync_ind) +{ + if (!sync_ind) { + mlme_err("invalid sync_ind"); + return QDF_STATUS_E_NULL_VALUE; + } + if (sync_ind->hw_mode_trans_present) + cm_handle_roam_sync_update_hw_mode( + &sync_ind->hw_mode_trans_ind); + + return mlo_fw_roam_sync_req(psoc, sync_ind->roamed_vdev_id, + sync_ind, sizeof(sync_ind)); +} + +QDF_STATUS +cm_roam_sync_frame_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_synch_frame_ind *frame_ind) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct roam_synch_frame_ind *sync_frame_ind = frame_ind; + struct roam_synch_frame_ind *roam_synch_frame_ind; + struct roam_scan_candidate_frame roam_candidate = {0}; + uint8_t vdev_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!sync_frame_ind) + return QDF_STATUS_E_NULL_VALUE; + + vdev_id = sync_frame_ind->vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + status = QDF_STATUS_E_FAILURE; + goto complete; + } + + roam_synch_frame_ind = &rso_cfg->roam_sync_frame_ind; + + if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id)) { + mlme_err("Ignoring this event as it is unexpected"); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + status = QDF_STATUS_E_FAILURE; + goto complete; + } + + if (sync_frame_ind->bcn_probe_rsp_len) { + roam_synch_frame_ind->bcn_probe_rsp_len = + sync_frame_ind->bcn_probe_rsp_len; + roam_synch_frame_ind->is_beacon = + sync_frame_ind->is_beacon; + if (roam_synch_frame_ind->bcn_probe_rsp) + qdf_mem_free(roam_synch_frame_ind->bcn_probe_rsp); + roam_synch_frame_ind->bcn_probe_rsp = + sync_frame_ind->bcn_probe_rsp; + } + + if (sync_frame_ind->link_bcn_probe_rsp_len) { + roam_synch_frame_ind->link_bcn_probe_rsp_len = + sync_frame_ind->link_bcn_probe_rsp_len; + roam_synch_frame_ind->is_link_beacon = + sync_frame_ind->is_link_beacon; + if (roam_synch_frame_ind->link_bcn_probe_rsp) + qdf_mem_free(roam_synch_frame_ind->link_bcn_probe_rsp); + roam_synch_frame_ind->link_bcn_probe_rsp = + sync_frame_ind->link_bcn_probe_rsp; + } + + if (sync_frame_ind->reassoc_req_len) { + roam_synch_frame_ind->reassoc_req_len = + sync_frame_ind->reassoc_req_len; + if (roam_synch_frame_ind->reassoc_req) + qdf_mem_free(roam_synch_frame_ind->reassoc_req); + roam_synch_frame_ind->reassoc_req = + sync_frame_ind->reassoc_req; + } + + if (sync_frame_ind->reassoc_rsp_len) { + roam_synch_frame_ind->reassoc_rsp_len = + sync_frame_ind->reassoc_rsp_len; + if (roam_synch_frame_ind->reassoc_rsp) + qdf_mem_free(roam_synch_frame_ind->reassoc_rsp); + roam_synch_frame_ind->reassoc_rsp = + sync_frame_ind->reassoc_rsp; + } + + if (!sync_frame_ind->bcn_probe_rsp_len && + !sync_frame_ind->link_bcn_probe_rsp_len) + goto complete; + + roam_candidate.vdev_id = vdev_id; + + if (sync_frame_ind->bcn_probe_rsp_len) { + roam_candidate.frame_length = sync_frame_ind->bcn_probe_rsp_len; + roam_candidate.frame = sync_frame_ind->bcn_probe_rsp; + roam_candidate.rssi = sync_frame_ind->rssi; + roam_candidate.roam_offload_candidate_frm = false; + wlan_cm_add_all_link_probe_rsp_to_scan_db(psoc, + &roam_candidate); + } + + if (sync_frame_ind->link_bcn_probe_rsp_len) { + roam_candidate.frame_length = + sync_frame_ind->link_bcn_probe_rsp_len; + roam_candidate.frame = sync_frame_ind->link_bcn_probe_rsp; + roam_candidate.rssi = sync_frame_ind->rssi; + roam_candidate.roam_offload_candidate_frm = false; + wlan_cm_add_all_link_probe_rsp_to_scan_db(psoc, + &roam_candidate); + } + +complete: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return status; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS cm_roam_sync_key_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_crypto_key_entry *keys, + uint8_t num_keys) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + + for (i = 0; i < num_keys; i++) { + status = wlan_crypto_add_key_entry(psoc, &keys[i]); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to add key entry for link:%d", + keys[i].link_id); + wlan_crypto_free_key(&keys[i].keys); + qdf_mem_zero(&keys[i], + sizeof(struct wlan_crypto_key_entry)); + qdf_mem_free(&keys[i]); + } + } + + return status; +} +#endif + +QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev, + uint8_t *event, + uint32_t len) +{ + struct roam_offload_synch_ind *sync_ind = NULL; + struct wlan_objmgr_psoc *psoc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct rso_config *rso_cfg; + uint16_t ie_len = 0; + uint8_t vdev_id; + + sync_ind = (struct roam_offload_synch_ind *)event; + if (!sync_ind) { + mlme_err("Roam Sync ind ptr is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!vdev) { + mlme_err("Vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("Psoc is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_id = wlan_vdev_get_id(vdev); + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_NULL_VALUE; + + wlan_roam_debug_log(sync_ind->roamed_vdev_id, DEBUG_ROAM_SYNCH_IND, + DEBUG_INVALID_PEER_ID, sync_ind->bssid.bytes, NULL, + 0, 0); + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + sync_ind->roamed_vdev_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_EVENT, + QDF_ROAM_SYNCH)); + + if (MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, sync_ind->roamed_vdev_id) && + !is_multi_link_roam(sync_ind)) { + mlme_err("vdev:%d Ignoring RSI as its already in progress on roamed vdev:%d", + vdev_id, sync_ind->roamed_vdev_id); + return QDF_STATUS_E_FAILURE; + } + + status = cm_fw_roam_sync_start_ind(vdev, sync_ind); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("LFR3: vdev:%d CSR Roam synch cb failed", vdev_id); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return status; + } + + /* 24 byte MAC header and 12 byte to ssid IE */ + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) && + sync_ind->link_beacon_probe_resp_length) { + if (sync_ind->link_beacon_probe_resp_length > + (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET)) { + ie_len = MAX_MGMT_MPDU_LEN - + (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET); + } else { + mlme_err("LFR3: MLO: vdev:%d Invalid link Beacon Length", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + } else if (sync_ind->beacon_probe_resp_length > + (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET)) { + /* + * When STA roams to an MLO AP, non-assoc link might be superior + * in features compared to assoc link and the per-STA profile + * info may carry corresponding IEs. These IEs are extracted + * and added to IE list of link probe response while generating + * it. So, the link probe response generated from assoc link + * probe response might be of more size than assoc link probe + * rsp. Allocate buffer for the bss descriptor to accommodate + * all of the IEs got generated as part of link probe rsp + * generation. Allocate MAX_MGMT_MPDU_LEN bytes for IEs as the + * max frame size that can be received from AP is + * MAX_MGMT_MPDU_LEN bytes. + */ + if (is_multi_link_roam(sync_ind)) + ie_len = MAX_MGMT_MPDU_LEN - + (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET); + else + ie_len = sync_ind->beacon_probe_resp_length - + (QDF_IEEE80211_3ADDR_HDR_LEN + MAC_B_PR_SSID_OFFSET); + + } else { + mlme_err("LFR3: vdev:%d Invalid Beacon Length:%d", vdev_id, + sync_ind->beacon_probe_resp_length); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_IS_STATUS_ERROR(cm_roam_pe_sync_callback(sync_ind, vdev_id, + ie_len))) { + mlme_err("LFR3: vdev:%d PE roam synch cb failed", vdev_id); + return QDF_STATUS_E_BUSY; + } + + status = cm_roam_update_vdev(vdev, sync_ind); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* + * update phy_mode in wma to avoid mismatch in phymode between host and + * firmware. The phymode stored in peer->peer_mlme.phymode is + * sent to firmware as part of opmode update during either - vht opmode + * action frame received or during opmode change detected while + * processing beacon. Any mismatch of this value with firmware phymode + * results in firmware assert. + */ + cm_update_phymode_on_roam(vdev_id, + sync_ind); + status = cm_fw_roam_sync_propagation(psoc, + vdev_id, + sync_ind); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h new file mode 100644 index 0000000000..272bdb7cad --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_api.h @@ -0,0 +1,777 @@ +/* + * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cm_vdev_api.h + * + * This header file maintain legacy connect, disconnect APIs of connection + * manager to initiate vdev manager operations + */ + +#ifndef __WLAN_CM_VDEV_API_H__ +#define __WLAN_CM_VDEV_API_H__ + +#include +#include "scheduler_api.h" +#include "connection_mgr/core/src/wlan_cm_main.h" +#include "connection_mgr/core/src/wlan_cm_main_api.h" +#include +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_public_structs.h" +#endif + +#define HS20_OUI_TYPE "\x50\x6f\x9a\x10" +#define HS20_OUI_TYPE_SIZE 4 + +/** + * struct cm_vdev_join_req - connect req from legacy CM to vdev manager + * @vdev_id: vdev id + * @cm_id: Connect manager id + * @force_rsne_override: force the arbitrary rsne received in connect req to be + * used with out validation, used for the scenarios where the device is used + * as a testbed device with special functionality and not recommended + * for production. + * @is_wps_connection: is wps connection + * @is_osen_connection: is osen connection + * @is_ssid_hidden: AP SSID is hidden + * @assoc_ie: assoc ie to be used in assoc req + * @scan_ie: Default scan ie to be used in the uncast probe req + * @entry: scan entry for the candidate + * @partner_info: Partner link information for an ML connection + * @assoc_link_id: Assoc link ID of an ML connection + * @owe_trans_ssid: owe trans ssid to be used when scan entry ssid is wildcard + */ +struct cm_vdev_join_req { + uint8_t vdev_id; + wlan_cm_id cm_id; + uint8_t force_rsne_override:1, + is_wps_connection:1, + is_osen_connection:1, + is_ssid_hidden:1; + struct element_info assoc_ie; + struct element_info scan_ie; + struct scan_cache_entry *entry; +#ifdef WLAN_FEATURE_11BE_MLO + struct mlo_partner_info partner_info; + uint8_t assoc_link_id; +#endif + struct wlan_ssid owe_trans_ssid; +}; + +/** + * struct wlan_cm_discon_ind - disconnect ind from VDEV mgr and will be sent to + * SME + * @vdev_id: vdev id + * @source: source of disconnection + * @reason_code: reason of disconnection + * @bssid: BSSID of AP + */ +struct wlan_cm_discon_ind { + uint8_t vdev_id; + enum wlan_cm_source source; + enum wlan_reason_code reason_code; + struct qdf_mac_addr bssid; +}; + +/** + * struct cm_vdev_discon_ind - disconnect ind from vdev mgr to connection mgr + * @psoc: psoc object + * @disconnect_param: DisConnect indication to be sent to CM + */ +struct cm_vdev_discon_ind { + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_discon_ind disconnect_param; +}; + +/** + * struct cm_vdev_disconnect_rsp - disconnect rsp from vdev mgr to CM + * @vdev_id: vdev id + * @psoc: psoc object + */ +struct cm_vdev_disconnect_rsp { + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; +}; + +/* + * struct cm_vdev_hw_mode_rsp - hw mode change from vdev mgr to CM + * @pdev: pdev pointer + * @vdev_id: vdev id + * @cm_id: connection ID which gave the hw mode change request + * @status: status of the HW mode change. + */ +struct cm_vdev_hw_mode_rsp { + struct wlan_objmgr_pdev *pdev; + uint8_t vdev_id; + wlan_cm_id cm_id; + QDF_STATUS status; +}; + +/** + * struct cm_vdev_join_rsp - connect rsp from vdev mgr to connection mgr + * @psoc: psoc object + * @connect_rsp: Connect response to be sent to CM + * @ric_resp_ie: ric ie data + * @tspec_ie: tspec ie + * @nss: used nss + * @uapsd_mask: uapsd mask + */ +struct cm_vdev_join_rsp { + struct wlan_objmgr_psoc *psoc; + struct wlan_cm_connect_resp connect_rsp; + struct element_info ric_resp_ie; +#ifdef FEATURE_WLAN_ESE + struct element_info tspec_ie; +#endif + uint8_t nss; + uint8_t uapsd_mask; +}; + +/** + * struct cm_peer_create_req - bss peer create req + * @vdev_id: vdev_id + * @peer_mac: peer mac to create + * @mld_mac: peer mld mac + * @is_assoc_peer: is assoc peer or not + */ +struct cm_peer_create_req { + uint8_t vdev_id; + struct qdf_mac_addr peer_mac; +#ifdef WLAN_FEATURE_11BE_MLO + struct qdf_mac_addr mld_mac; + bool is_assoc_peer; +#endif +}; + +/** + * struct cm_host_roam_start_ind - roam start ind for host roam from FW + * @vdev_id: vdev id + * @pdev: pdev object + */ +struct cm_host_roam_start_ind { + uint8_t vdev_id; + struct wlan_objmgr_pdev *pdev; +}; + +/** + * struct cm_ext_obj - Connection manager legacy object + * @rso_cfg: connect info to be used in RSO. + * @rso_usr_cfg: roam related userspace RSO configs. + */ +struct cm_ext_obj { + struct rso_config rso_cfg; + struct rso_user_config rso_usr_cfg; +}; + +#ifdef WLAN_FEATURE_FILS_SK +/** + * cm_update_hlp_info - API to save HLP IE + * @vdev: vdev ptr + * @gen_ie: IE buffer to store + * @len: length of the IE buffer @gen_ie + * @flush: Flush the older saved HLP if any + * + * Return: None + */ +void cm_update_hlp_info(struct wlan_objmgr_vdev *vdev, + const uint8_t *gen_ie, uint16_t len, + bool flush); +#else +static inline void cm_update_hlp_info(struct wlan_objmgr_vdev *vdev, + const uint8_t *gen_ie, uint16_t len, + bool flush) +{} +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +/** + * cm_connect_info - send connect info to diag + * @vdev: vdev ptr + * @connect_success: if connect was success + * @bssid: bssid + * @ssid: ssid + * @freq: freq + * + * Return: none + */ +void cm_connect_info(struct wlan_objmgr_vdev *vdev, bool connect_success, + struct qdf_mac_addr *bssid, struct wlan_ssid *ssid, + qdf_freq_t freq); + +void cm_diag_get_auth_enc_type_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *auth_type, + uint8_t *ucast_cipher, + uint8_t *mcast_cipher, + uint8_t vdev_id); + +#ifdef WLAN_UNIT_TEST +/** + * cm_get_sta_cxn_info - fill sta context info in buffer + * @vdev: Pointer to vdev + * @buf: buffer to fill + * @buf_sz: buf size + * + * Return: none + */ +void cm_get_sta_cxn_info(struct wlan_objmgr_vdev *vdev, + char *buf, uint32_t buf_sz); +#endif +#else +static inline void +cm_connect_info(struct wlan_objmgr_vdev *vdev, bool connect_success, + struct qdf_mac_addr *bssid, struct wlan_ssid *ssid, + qdf_freq_t freq) +{} +#endif + +/** + * cm_wait_for_key_time_out_handler() - Wait key time out handler API + * @data: Pointer to wait key timer data + * + * Return: none + */ +void cm_wait_for_key_time_out_handler(void *data); + +/** + * cm_start_wait_for_key_timer() - Wait for key start API + * @vdev: Pointer to vdev + * @interval: timer trigger interval + * + * Return: QDF_STATUS + */ + +QDF_STATUS cm_start_wait_for_key_timer(struct wlan_objmgr_vdev *vdev, + uint32_t interval); + +/** + * cm_stop_wait_for_key_timer() - Wait key stop API + * @psoc: Pointer to psoc + * @vdev_id: vdev id + * + * Return: none + */ +void cm_stop_wait_for_key_timer(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +void cm_update_wait_for_key_timer(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint32_t interval); + +void cm_update_prev_ap_ie(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t len, uint8_t *bcn_ptr); +bool cm_csr_is_ss_wait_for_key(uint8_t vdev_id); +void cm_csr_set_ss_wait_for_key(uint8_t vdev_id); +void cm_csr_set_ss_none(uint8_t vdev_id); +void cm_csr_set_joining(uint8_t vdev_id); +void cm_csr_set_joined(uint8_t vdev_id); +void cm_csr_set_idle(uint8_t vdev_id); + +/** + * cm_get_rssi_snr_by_bssid() - get rssi and snr by bssid + * @pdev: Pointer to pdev + * @bssid: bssid to get rssi and snr + * @rssi: pointer to fill rssi + * @snr: pointer to fill snr + * + * Return: none + */ +QDF_STATUS cm_get_rssi_snr_by_bssid(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid, + int8_t *rssi, int8_t *snr); + +/** + * cm_csr_send_set_ie() - CM wrapper to send the set IE request + * @vdev: Object manager VDEV + * + * Return: None + */ +void cm_csr_send_set_ie(struct wlan_objmgr_vdev *vdev); + +/** + * cm_csr_get_vdev_dot11_mode() - Wrapper for CM to get the dot11mode for + * the vdev id + * @vdev_id: vdev id + * + * Return: dot11 mode + */ +uint16_t cm_csr_get_vdev_dot11_mode(uint8_t vdev_id); + +static inline QDF_STATUS +cm_ext_hdl_create(struct wlan_objmgr_vdev *vdev, cm_ext_t **ext_cm_ptr) +{ + struct cm_ext_obj *cm_obj; + + *ext_cm_ptr = qdf_mem_malloc(sizeof(struct cm_ext_obj)); + if (!*ext_cm_ptr) + return QDF_STATUS_E_NOMEM; + + cm_obj = *ext_cm_ptr; + wlan_cm_rso_config_init(vdev, &cm_obj->rso_cfg); + + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cm_ext_hdl_destroy(struct wlan_objmgr_vdev *vdev, cm_ext_t *ext_cm_ptr) +{ + wlan_cm_rso_config_deinit(vdev, &ext_cm_ptr->rso_cfg); + qdf_mem_free(ext_cm_ptr); + + return QDF_STATUS_SUCCESS; +} + +/** + * cm_connect_start_ind() - Connection manager ext connect start indication + * vdev and peer assoc state machine + * @vdev: VDEV object + * @req: connect request + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_connect_start_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_req *req); + +/** + * cm_csr_handle_join_req() - Connection manager cb to csr to fill csr + * session and update join req from legacy structures + * @vdev: VDEV object + * @req: Vdev connect request + * @join_req: join req to be sent to LIM + * @reassoc: if reassoc + * + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_csr_handle_join_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_connect_req *req, + struct cm_vdev_join_req *join_req, + bool reassoc); + +/** + * cm_handle_connect_req() - Connection manager ext connect request to + * start vdev and peer assoc state machine + * @vdev: VDEV object + * @req: Vdev connect request + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_connect_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_connect_req *req); + +/** + * cm_send_bss_peer_create_req() - Connection manager ext bss peer create + * request + * @vdev: VDEV object + * @peer_mac: Peer mac address + * @mld_mac: peer mld mac address + * @is_assoc_peer: is assoc peer or not + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_send_bss_peer_create_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + struct qdf_mac_addr *mld_mac, + bool is_assoc_peer); + +/** + * cm_csr_connect_rsp() - Connection manager ext connect resp indication + * @vdev: VDEV object + * @rsp: Connection vdev response + * + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_csr_connect_rsp(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_rsp *rsp); + +/** + * cm_connect_complete_ind() - Connection manager ext connect complete + * indication + * @vdev: VDEV object + * @rsp: Connection manager connect response + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); + +/** + * cm_csr_connect_done_ind() - Connection manager call to csr to update + * legacy structures on connect complete + * @vdev: VDEV object + * @rsp: Connection manager connect response + * + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead. + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_csr_connect_done_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); + +/** + * cm_is_vdevid_connected() - check if vdev_id is in conneted state + * @pdev: pdev pointer + * @vdev_id: vdev ID + * + * Return: bool + */ +bool cm_is_vdevid_connected(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * cm_is_vdevid_active() - check if vdev_id is in conneted/roaming state + * @pdev: pdev pointer + * @vdev_id: vdev ID + * + * Return: bool + */ +bool cm_is_vdevid_active(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * cm_disconnect_start_ind() - Connection manager ext disconnect start + * indication + * vdev and peer assoc state machine + * @vdev: VDEV object + * @req: disconnect request + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_disconnect_start_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_disconnect_req *req); + +/** + * cm_handle_disconnect_req() - Connection manager ext disconnect + * req to vdev and peer sm + * @vdev: VDEV object + * @req: vdev disconnect request + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_disconnect_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_discon_req *req); + +/** + * cm_csr_handle_diconnect_req() - Connection manager cb to csr to update legacy + * structures on disconnect + * @vdev: VDEV object + * @req: vdev disconnect request + * + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead. + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_csr_handle_diconnect_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_discon_req *req); + +/** + * cm_send_bss_peer_delete_req() - Connection manager ext bss peer delete + * request + * @vdev: VDEV object + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_send_bss_peer_delete_req(struct wlan_objmgr_vdev *vdev); + +/** + * cm_disconnect_complete_ind() - Connection manager ext disconnect + * complete indication + * @vdev: VDEV object + * @rsp: Connection manager disconnect response + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_disconnect_complete_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp); + +/** + * cm_csr_disconnect_done_ind() - Connection manager call to csr to update + * legacy structures on disconnect complete + * @vdev: VDEV object + * @rsp: Connection manager disconnect response + * + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead. + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_csr_disconnect_done_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp); + +/** + * cm_send_vdev_down_req() - Connection manager ext req to send vdev down + * to FW + * @vdev: VDEV object + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_send_vdev_down_req(struct wlan_objmgr_vdev *vdev); + +/** + * cm_free_join_req() - Free cm vdev connect req params + * @join_req: join request + * + * Return: void + */ +void cm_free_join_req(struct cm_vdev_join_req *join_req); + +/** + * cm_flush_join_req() - Process join req flush + * @msg: scheduler message + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_flush_join_req(struct scheduler_msg *msg); + +/** + * cm_process_join_req() - Process vdev join req + * @msg: scheduler message + * + * Process connect request in LIM and copy all join req params. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_process_join_req(struct scheduler_msg *msg); + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * cm_process_preauth_req() - Process preauth request + * @msg: scheduler message + * + * Process preauth request in LIM. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_process_preauth_req(struct scheduler_msg *msg); + +/** + * cm_process_reassoc_req() - Process vdev reassoc req + * @msg: scheduler message + * + * Process reassoc request in LIM and copy all reassoc req params. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_process_reassoc_req(struct scheduler_msg *msg); + +/** + * cm_handle_reassoc_req() - Connection manager ext reassoc request to start + * vdev and peer assoc state machine + * @vdev: VDEV object + * @req: Vdev reassoc request + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_reassoc_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_reassoc_req *req); + +/** + * cm_handle_roam_start() - roam start indication + * @vdev: VDEV object + * @req: Connection manager roam request + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_roam_start(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_roam_req *req); + +/** + * cm_csr_preauth_done() - Process preauth done from csr part + * @vdev: vdev object pointer + * + * Return: void + */ +void cm_csr_preauth_done(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS cm_process_preauth_req(struct scheduler_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS cm_process_reassoc_req(struct scheduler_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cm_handle_reassoc_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_reassoc_req *req) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS +cm_handle_roam_start(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_roam_req *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * cm_process_peer_create() - Process bss peer create req + * @msg: scheduler message + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_process_peer_create(struct scheduler_msg *msg); + +/** + * cm_process_disconnect_req() - Process vdev disconnect request + * @msg: scheduler message + * + * Process disconnect request in LIM. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_process_disconnect_req(struct scheduler_msg *msg); + +/** + * cm_disconnect() - disconnect start request + * @psoc: psoc pointer + * @vdev_id: vdev id + * @source: disconnect source + * @reason_code: disconnect reason + * @bssid: bssid of AP to disconnect, can be null if not known + * + * Context: can be called from any context, should not hold sme global lock + * while calling as can lead to deadlock (disconnect access sme lock holding CM + * lock and thus calling cm api (which will hold CM lock) while holding sme lock + * can lead to deadlock) + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_disconnect(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum wlan_cm_source source, + enum wlan_reason_code reason_code, + struct qdf_mac_addr *bssid); + +/** + * cm_send_sb_disconnect_req() - Process vdev discon ind from sb and send to CM + * @msg: scheduler message + * + * Process disconnect indication and send it to CM SM. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_send_sb_disconnect_req(struct scheduler_msg *msg); + +/** + * cm_handle_disconnect_resp() - Process vdev discon rsp and send to CM + * @msg: scheduler message + * + * Process disconnect rsp and send it to CM SM. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_handle_disconnect_resp(struct scheduler_msg *msg); + +/** + * wlan_cm_send_connect_rsp() - Process vdev join rsp and send to CM + * @msg: scheduler message + * + * Process connect response and send it to CM SM. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_send_connect_rsp(struct scheduler_msg *msg); + +/** + * wlan_cm_free_connect_rsp() - Function to free all params in join rsp + * @rsp: CM join response + * + * Function to free up all the memory in join rsp. + * + * Return: void + */ +void wlan_cm_free_connect_rsp(struct cm_vdev_join_rsp *rsp); + +/** + * wlan_cm_handle_hw_mode_change_resp() - Process hw_mode_change_resp + * @pdev: pdev pointer + * @vdev_id: vdev_id + * @cm_id: connection manager id + * @status: status + * + * This API is to break the context and avoid calling CM API to take CM lock + * while holding SME lock. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_handle_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + wlan_cm_id cm_id, QDF_STATUS status); +/** + * wlan_cm_rso_stop_continue_disconnect() - Continue disconnect after RSO stop + * @psoc: psoc object + * @vdev_id: vdev id + * @is_ho_fail: Carries true if HO_FAIL happened + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_rso_stop_continue_disconnect(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_ho_fail); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * cm_send_rso_stop() - Send RSP stop req to firmware + * @vdev: VDEV object + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_send_rso_stop(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +cm_send_rso_stop(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * cm_get_ml_partner_info() - Fill ML partner info from scan entry + * @pdev: PDEV object + * @conn_req: Connect request pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev, + struct cm_connect_req *conn_req); +#endif +#endif /* __WLAN_CM_VDEV_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c new file mode 100644 index 0000000000..14ca1b6500 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c @@ -0,0 +1,1995 @@ +/* + * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements legacy connect specific APIs of connection manager to + * initiate vdev manager operations + */ + +#include "wlan_cm_vdev_api.h" +#include "wlan_scan_utils_api.h" +#include "wlan_mlme_dbg.h" +#include "wlan_cm_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_p2p_api.h" +#include "wlan_tdls_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wni_api.h" +#include "wlan_crypto_global_api.h" +#include "wlan_scan_api.h" +#include "wlan_logging_sock_svc.h" +#include "cfg_ucfg_api.h" +#include "wlan_roam_debug.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_mlme_api.h" +#include "wlan_reg_services_api.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_t2lm_api.h" +#include "wlan_mlo_t2lm.h" +#include "wlan_mlo_link_force.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "wlan_dp_api.h" +#include + +#ifdef WLAN_FEATURE_FILS_SK +void cm_update_hlp_info(struct wlan_objmgr_vdev *vdev, + const uint8_t *gen_ie, uint16_t len, + bool flush) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + if (flush) { + mlme_priv->connect_info.hlp_ie_len = 0; + if (mlme_priv->connect_info.hlp_ie) { + qdf_mem_free(mlme_priv->connect_info.hlp_ie); + mlme_priv->connect_info.hlp_ie = NULL; + } + } + + if (!len || !gen_ie) + return; + + if ((mlme_priv->connect_info.hlp_ie_len + len) > + FILS_MAX_HLP_DATA_LEN) { + mlme_err("HLP len exceeds: hlp_ie_len %d len %d", + mlme_priv->connect_info.hlp_ie_len, len); + return; + } + + if (!mlme_priv->connect_info.hlp_ie) { + mlme_priv->connect_info.hlp_ie = + qdf_mem_malloc(FILS_MAX_HLP_DATA_LEN); + if (!mlme_priv->connect_info.hlp_ie) + return; + } + + qdf_mem_copy(mlme_priv->connect_info.hlp_ie + + mlme_priv->connect_info.hlp_ie_len, gen_ie, len); + mlme_priv->connect_info.hlp_ie_len += len; + mlme_debug("hlp_ie_len %d len %d", mlme_priv->connect_info.hlp_ie_len, + len); +} +#endif + +static bool wlan_cm_is_vdev_id_roam_reassoc_state(struct wlan_objmgr_vdev *vdev) +{ + return wlan_cm_is_vdev_roam_reassoc_state(vdev); +} + +static void +wlan_cm_disconnect_on_wait_key_timeout(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + mlo_disconnect(vdev, CM_MLME_DISCONNECT, REASON_KEY_TIMEOUT, NULL); +} + +void cm_wait_for_key_time_out_handler(void *data) +{ + uint8_t vdev_id; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wait_for_key_timer *wait_key_timer = + (struct wait_for_key_timer *)data; + + vdev = wait_key_timer->vdev; + vdev_id = vdev->vdev_objmgr.vdev_id; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("psoc obj is NULL for vdev id %d", vdev_id); + return; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("psoc mlme obj is NULL for vdev id %d", vdev_id); + return; + } + + if (cm_csr_is_ss_wait_for_key(vdev_id)) { + cm_csr_set_ss_none(vdev_id); + if (wlan_cm_is_vdev_id_roam_reassoc_state(vdev)) + mlme_obj->cfg.timeouts.heart_beat_threshold = + cfg_default(CFG_HEART_BEAT_THRESHOLD); + + wlan_cm_disconnect_on_wait_key_timeout(psoc, vdev); + } +} + +QDF_STATUS cm_start_wait_for_key_timer(struct wlan_objmgr_vdev *vdev, + uint32_t interval) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev priv mlme obj is NULL"); + return QDF_STATUS_E_INVAL; + } + vdev_id = vdev->vdev_objmgr.vdev_id; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("psoc obj is NULL for vdev id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("psoc mlme obj is NULL for vdev id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (wlan_cm_is_vdev_id_roam_reassoc_state(vdev)) + mlme_obj->cfg.timeouts.heart_beat_threshold = 0; + + return qdf_mc_timer_start(&vdev_mlme->ext_vdev_ptr->wait_key_timer.timer, + interval / QDF_MC_TIMER_TO_MS_UNIT); +} + +void cm_stop_wait_for_key_timer(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev is NULL for vdev id %d", vdev_id); + return; + } + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev priv mlme obj is NULL"); + goto end; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_err("psoc mlme obj is NULL for vdev id %d", vdev_id); + goto end; + } + + if (wlan_cm_is_vdev_id_roam_reassoc_state(vdev)) + mlme_obj->cfg.timeouts.heart_beat_threshold = + cfg_default(CFG_HEART_BEAT_THRESHOLD); + + qdf_mc_timer_stop(&vdev_mlme->ext_vdev_ptr->wait_key_timer.timer); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void cm_update_wait_for_key_timer(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint32_t interval) +{ + cm_csr_set_ss_wait_for_key(vdev_id); + + if (QDF_IS_STATUS_ERROR(cm_start_wait_for_key_timer(vdev, interval))) { + mlme_err("Failed wait for key timer start"); + cm_csr_set_ss_none(vdev_id); + } +} + +void cm_update_prev_ap_ie(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t len, uint8_t *bcn_ptr) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct element_info *bcn_ie; + + if (!len || !bcn_ptr) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev is NULL for vdev id %d", vdev_id); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto end; + + bcn_ie = &rso_cfg->prev_ap_bcn_ie; + if (bcn_ie->ptr) { + qdf_mem_free(bcn_ie->ptr); + bcn_ie->ptr = NULL; + bcn_ie->len = 0; + } + bcn_ie->ptr = qdf_mem_malloc(len); + if (!bcn_ie->ptr) { + bcn_ie->len = 0; + goto end; + } + + qdf_mem_copy(bcn_ie->ptr, bcn_ptr, len); +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +QDF_STATUS cm_get_rssi_snr_by_bssid(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid, + int8_t *rssi, int8_t *snr) +{ + struct scan_filter *scan_filter; + qdf_list_t *list = NULL; + struct scan_cache_node *first_node = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (snr) + *snr = 0; + if (rssi) + *rssi = 0; + scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); + if (!scan_filter) + return QDF_STATUS_E_NOMEM; + + scan_filter->num_of_bssid = 1; + qdf_mem_copy(scan_filter->bssid_list[0].bytes, + bssid, sizeof(struct qdf_mac_addr)); + scan_filter->ignore_auth_enc_type = true; + list = wlan_scan_get_result(pdev, scan_filter); + qdf_mem_free(scan_filter); + + if (!list || (list && !qdf_list_size(list))) { + mlme_debug("scan list empty"); + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + qdf_list_peek_front(list, (qdf_list_node_t **) &first_node); + if (first_node && first_node->entry) { + if (rssi) + *rssi = first_node->entry->rssi_raw; + if (snr) + *snr = first_node->entry->snr; + } + +error: + if (list) + wlan_scan_purge_results(list); + + return status; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +#ifdef WLAN_FEATURE_11BE +static const +char *cm_diag_get_eht_dot11_mode_str(enum mgmt_dot11_mode dot11mode) +{ + + switch (dot11mode) { + CASE_RETURN_STRING(DOT11_MODE_11BE); + CASE_RETURN_STRING(DOT11_MODE_11BE_ONLY); + default: + return "Unknown"; + } +} + +static const char *cm_diag_get_320_ch_width_str(uint8_t ch_width) +{ + switch (ch_width) { + CASE_RETURN_STRING(BW_320MHZ); + default: + return "Unknown"; + } +} +#else +static const +char *cm_diag_get_eht_dot11_mode_str(enum mgmt_dot11_mode dot11mode) +{ + return "Unknown"; +} + +static const char *cm_diag_get_320_ch_width_str(uint8_t ch_width) +{ + return "Unknown"; +} +#endif + +static const char *cm_diag_get_ch_width_str(uint8_t ch_width) +{ + switch (ch_width) { + CASE_RETURN_STRING(BW_20MHZ); + CASE_RETURN_STRING(BW_40MHZ); + CASE_RETURN_STRING(BW_80MHZ); + CASE_RETURN_STRING(BW_160MHZ); + CASE_RETURN_STRING(BW_80P80MHZ); + CASE_RETURN_STRING(BW_5MHZ); + CASE_RETURN_STRING(BW_10MHZ); + default: + return cm_diag_get_320_ch_width_str(ch_width); + } +} + +static const char *cm_diag_get_dot11_mode_str(enum mgmt_dot11_mode dot11mode) +{ + switch (dot11mode) { + CASE_RETURN_STRING(DOT11_MODE_AUTO); + CASE_RETURN_STRING(DOT11_MODE_ABG); + CASE_RETURN_STRING(DOT11_MODE_11A); + CASE_RETURN_STRING(DOT11_MODE_11B); + CASE_RETURN_STRING(DOT11_MODE_11G); + CASE_RETURN_STRING(DOT11_MODE_11N); + CASE_RETURN_STRING(DOT11_MODE_11AC); + CASE_RETURN_STRING(DOT11_MODE_11G_ONLY); + CASE_RETURN_STRING(DOT11_MODE_11N_ONLY); + CASE_RETURN_STRING(DOT11_MODE_11AC_ONLY); + CASE_RETURN_STRING(DOT11_MODE_11AX); + CASE_RETURN_STRING(DOT11_MODE_11AX_ONLY); + default: + return cm_diag_get_eht_dot11_mode_str(dot11mode); + } +} + +static const char *cm_diag_get_encr_type_str(uint8_t encr_type) +{ + switch (encr_type) { + CASE_RETURN_STRING(ENC_MODE_OPEN); + CASE_RETURN_STRING(ENC_MODE_WEP40); + CASE_RETURN_STRING(ENC_MODE_WEP104); + CASE_RETURN_STRING(ENC_MODE_TKIP); + CASE_RETURN_STRING(ENC_MODE_AES); + CASE_RETURN_STRING(ENC_MODE_AES_GCMP); + CASE_RETURN_STRING(ENC_MODE_AES_GCMP_256); + CASE_RETURN_STRING(ENC_MODE_SMS4); + default: + return "Unknown"; + } +} + +static const uint8_t *cm_diag_get_akm_str(enum mgmt_auth_type auth_type, + uint32_t akm) +{ + if (auth_type == AUTH_OPEN) + return "Open"; + else if (auth_type == AUTH_SHARED) + return "Shared Key"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) + return "FT-FILS-SHA384"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) + return "FT-FILS-SHA256"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) + return "FILS-SHA384"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) + return "FILS-SHA256"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + return "FT-SAE-EXT-KEY"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) + return "FT-SAE"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) + return "SAE-EXT-KEY"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE)) + return "SAE"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_DPP)) + return "DPP"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OSEN)) + return "OSEN"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE)) + return "OWE"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) + return "FT-802.1x"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) + return "FT-PSK"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return "EAP 802.1x"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + return "WPA2-PSK"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return "RSN-CCKM"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) + return "PSK-SHA256"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) + return "EAP 802.1x-SHA256"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B)) + return "EAP Suite-B SHA256"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) + return "EAP Suite-B SHA384"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) + return "FT-Suite-B SHA384"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return "WPA"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + return "WPA-PSK"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return "WPA-CCKM"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WPA_NONE)) + return "WPA-NONE"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT)) + return "WAPI-CERT"; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK)) + return "WAPI-PSK"; + else + return "NONE"; +} + +#if defined(WLAN_FEATURE_11BE) +static enum mgmt_dot11_mode +cm_diag_eht_dot11_mode_from_phy_mode(enum wlan_phymode phymode) +{ + if (IS_WLAN_PHYMODE_EHT(phymode)) + return DOT11_MODE_11BE; + else + return DOT11_MODE_MAX; +} + +static enum mgmt_ch_width +cm_get_diag_eht_320_ch_width(enum phy_ch_width ch_width) +{ + if (ch_width == CH_WIDTH_320MHZ) + return BW_320MHZ; + else + return BW_MAX; +} +#else +static enum mgmt_dot11_mode +cm_diag_eht_dot11_mode_from_phy_mode(enum wlan_phymode phymode) +{ + return DOT11_MODE_MAX; +} + +static enum mgmt_ch_width +cm_get_diag_eht_320_ch_width(enum phy_ch_width ch_width) +{ + return BW_MAX; +} +#endif + +static enum mgmt_dot11_mode +cm_diag_dot11_mode_from_phy_mode(enum wlan_phymode phymode) +{ + switch (phymode) { + case WLAN_PHYMODE_11A: + return DOT11_MODE_11A; + case WLAN_PHYMODE_11B: + return DOT11_MODE_11B; + case WLAN_PHYMODE_11G: + return DOT11_MODE_11G; + case WLAN_PHYMODE_11G_ONLY: + return DOT11_MODE_11G_ONLY; + case WLAN_PHYMODE_AUTO: + return DOT11_MODE_AUTO; + default: + if (IS_WLAN_PHYMODE_HT(phymode)) + return DOT11_MODE_11N; + else if (IS_WLAN_PHYMODE_VHT(phymode)) + return DOT11_MODE_11AC; + else if (IS_WLAN_PHYMODE_HE(phymode)) + return DOT11_MODE_11AX; + else + return cm_diag_eht_dot11_mode_from_phy_mode(phymode); + } +} + +static enum mgmt_ch_width cm_get_diag_ch_width(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + return BW_20MHZ; + case CH_WIDTH_40MHZ: + return BW_40MHZ; + case CH_WIDTH_80MHZ: + return BW_80MHZ; + case CH_WIDTH_160MHZ: + return BW_160MHZ; + case CH_WIDTH_80P80MHZ: + return BW_80P80MHZ; + case CH_WIDTH_5MHZ: + return BW_5MHZ; + case CH_WIDTH_10MHZ: + return BW_10MHZ; + default: + return cm_get_diag_eht_320_ch_width(ch_width); + } +} + +static enum mgmt_bss_type cm_get_diag_persona(enum QDF_OPMODE persona) +{ + switch (persona) { + case QDF_STA_MODE: + return STA_PERSONA; + case QDF_SAP_MODE: + return SAP_PERSONA; + case QDF_P2P_CLIENT_MODE: + return P2P_CLIENT_PERSONA; + case QDF_P2P_GO_MODE: + return P2P_GO_PERSONA; + case QDF_FTM_MODE: + return FTM_PERSONA; + case QDF_MONITOR_MODE: + return MONITOR_PERSONA; + case QDF_P2P_DEVICE_MODE: + return P2P_DEVICE_PERSONA; + case QDF_OCB_MODE: + return OCB_PERSONA; + case QDF_EPPING_MODE: + return EPPING_PERSONA; + case QDF_QVIT_MODE: + return QVIT_PERSONA; + case QDF_NDI_MODE: + return NDI_PERSONA; + case QDF_WDS_MODE: + return WDS_PERSONA; + case QDF_BTAMP_MODE: + return BTAMP_PERSONA; + case QDF_AHDEMO_MODE: + return AHDEMO_PERSONA; + default: + return MAX_PERSONA; + } +} + +static enum mgmt_encrypt_type cm_get_diag_enc_type(uint32_t cipherset) +{ + enum mgmt_encrypt_type n = ENC_MODE_OPEN; + + if (!cipherset) + return n; + + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GCM_256)) + n = ENC_MODE_AES_GCMP_256; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GCM)) + n = ENC_MODE_AES_GCMP; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CCM) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_OCB) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CCM_256) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CMAC) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CMAC_256) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GMAC) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GMAC_256)) + n = ENC_MODE_AES; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_TKIP)) + n = ENC_MODE_TKIP; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WAPI_GCM4) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WAPI_SMS4)) + n = ENC_MODE_SMS4; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP)) + n = ENC_MODE_WEP40; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP_40)) + n = ENC_MODE_WEP40; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP_104)) + n = ENC_MODE_WEP104; + + return n; +} + +static void cm_diag_fill_rsn_auth_type(uint8_t *auth_type, uint32_t akm) +{ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) + *auth_type = AUTH_WPA2_EAP; + else + *auth_type = AUTH_WPA2_PSK; +} + +static void cm_diag_fill_wpa_auth_type(uint8_t *auth_type, uint32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + *auth_type = AUTH_WPA_EAP; + else + *auth_type = AUTH_WPA_PSK; +} + +static void cm_diag_fill_wapi_auth_type(uint8_t *auth_type, uint32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT)) + *auth_type = AUTH_WAPI_CERT; + else + *auth_type = AUTH_WAPI_PSK; +} + +static void cm_diag_get_auth_type(uint8_t *auth_type, + uint32_t authmodeset, uint32_t akm, + uint32_t ucastcipherset) +{ + if (!authmodeset) { + *auth_type = AUTH_OPEN; + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_NONE) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_OPEN)) { + *auth_type = AUTH_OPEN; + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_AUTO)) { + if ((QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP_104))) + *auth_type = AUTH_SHARED; + else + *auth_type = AUTH_OPEN; + + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_SHARED)) { + *auth_type = AUTH_SHARED; + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_8021X) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_RSNA) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_CCKM) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_SAE) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_FILS_SK)) { + cm_diag_fill_rsn_auth_type(auth_type, akm); + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_WPA)) { + cm_diag_fill_wpa_auth_type(auth_type, akm); + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_WAPI)) { + cm_diag_fill_wapi_auth_type(auth_type, akm); + return; + } + + *auth_type = AUTH_OPEN; +} + +static void +cm_connect_success_diag(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct host_event_wlan_connection_stats *stats) +{ + WLAN_HOST_DIAG_EVENT_DEF(connect_status, + host_event_wlan_status_payload_type); + + qdf_mem_zero(&connect_status, + sizeof(host_event_wlan_status_payload_type)); + + connect_status.eventId = DIAG_WLAN_STATUS_CONNECT; + connect_status.bssType = 0; + mlme_obj->cfg.sta.current_rssi = stats->rssi; + + connect_status.qosCapability = stats->qos_capability; + connect_status.authType = stats->auth_type; + connect_status.encryptionType = stats->encryption_type; + qdf_mem_copy(connect_status.ssid, stats->ssid, stats->ssid_len); + connect_status.reason = DIAG_REASON_UNSPECIFIED; + qdf_mem_copy(&mlme_obj->cfg.sta.event_payload, &connect_status, + sizeof(host_event_wlan_status_payload_type)); + WLAN_HOST_DIAG_EVENT_REPORT(&connect_status, EVENT_WLAN_STATUS_V2); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void cm_print_mlo_info(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *peer; + struct qdf_mac_addr *mld_addr; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + peer = wlan_vdev_get_bsspeer(vdev); + if (!peer) + return; + + mlme_nofl_debug("self_mld_addr:" QDF_MAC_ADDR_FMT " link_id:%d", + QDF_MAC_ADDR_REF(mld_addr->bytes), + wlan_vdev_get_link_id(vdev)); + mlme_nofl_debug("peer_mld_mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mldaddr)); +} +#else +static void cm_print_mlo_info(struct wlan_objmgr_vdev *vdev) +{ +} +#endif + +void cm_connect_info(struct wlan_objmgr_vdev *vdev, bool connect_success, + struct qdf_mac_addr *bssid, struct wlan_ssid *ssid, + qdf_freq_t freq) +{ + struct wlan_channel *des_chan; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_crypto_params *crypto_params; + uint8_t max_supported_nss; + enum QDF_OPMODE opmode; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + WLAN_HOST_DIAG_EVENT_DEF(conn_stats, + struct host_event_wlan_connection_stats); + + if (!ssid || !bssid) + return; + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return; + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + qdf_mem_zero(&conn_stats, + sizeof(struct host_event_wlan_connection_stats)); + + qdf_mem_copy(conn_stats.bssid, bssid->bytes, + QDF_MAC_ADDR_SIZE); + + conn_stats.ssid_len = ssid->length; + if (conn_stats.ssid_len > WLAN_SSID_MAX_LEN) + conn_stats.ssid_len = WLAN_SSID_MAX_LEN; + qdf_mem_copy(conn_stats.ssid, ssid->ssid, conn_stats.ssid_len); + + cm_get_rssi_snr_by_bssid(pdev, bssid, &conn_stats.rssi, NULL); + conn_stats.est_link_speed = 0; + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + + wlan_mlme_get_sta_ch_width(vdev, &ch_width); + conn_stats.chnl_bw = cm_get_diag_ch_width(ch_width); + conn_stats.dot11mode = + cm_diag_dot11_mode_from_phy_mode(des_chan->ch_phymode); + + opmode = wlan_vdev_mlme_get_opmode(vdev); + conn_stats.bss_type = cm_get_diag_persona(opmode); + + if (freq) + conn_stats.operating_channel = + wlan_reg_freq_to_chan(pdev, freq); + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev component object is NULL"); + return; + } + conn_stats.qos_capability = + vdev_mlme->ext_vdev_ptr->connect_info.qos_enabled; + + crypto_params = wlan_crypto_vdev_get_crypto_params(vdev); + + if (!crypto_params) { + mlme_err("crypto params is null"); + return; + } + + cm_diag_get_auth_type(&conn_stats.auth_type, + crypto_params->authmodeset, + crypto_params->key_mgmt, + crypto_params->ucastcipherset); + + conn_stats.encryption_type = + cm_get_diag_enc_type(crypto_params->ucastcipherset); + + conn_stats.result_code = connect_success; + conn_stats.reason_code = 0; + conn_stats.op_freq = freq; + + max_supported_nss = mlme_obj->cfg.vht_caps.vht_cap_info.enable2x2 ? + MAX_VDEV_NSS : 1; + mlme_nofl_debug("+---------CONNECTION INFO START------------+"); + mlme_nofl_debug("VDEV-ID: %d self_mac:"QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(vdev), + QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev))); + mlme_nofl_debug("ssid: " QDF_SSID_FMT " bssid: " QDF_MAC_ADDR_FMT " RSSI: %d dBm", + QDF_SSID_REF(conn_stats.ssid_len, conn_stats.ssid), + QDF_MAC_ADDR_REF(conn_stats.bssid), conn_stats.rssi); + mlme_nofl_debug("Channel Freq: %d channel_bw: %s dot11Mode: %s", + conn_stats.op_freq, + cm_diag_get_ch_width_str(conn_stats.chnl_bw), + cm_diag_get_dot11_mode_str(conn_stats.dot11mode)); + mlme_nofl_debug("AKM: %s Encry-type: %s", + cm_diag_get_akm_str(conn_stats.auth_type, + crypto_params->key_mgmt), + cm_diag_get_encr_type_str(conn_stats.encryption_type)); + mlme_nofl_debug("DUT_NSS: %d | Intersected NSS:%d", + max_supported_nss, wlan_vdev_mlme_get_nss(vdev)); + mlme_nofl_debug("Qos enable: %d | Associated: %s", + conn_stats.qos_capability, + (conn_stats.result_code ? "yes" : "no")); + cm_print_mlo_info(vdev); + mlme_nofl_debug("+---------CONNECTION INFO END------------+"); + + WLAN_HOST_DIAG_EVENT_REPORT(&conn_stats, EVENT_WLAN_CONN_STATS_V2); + + if (!connect_success) + return; + + /* store connect info on success */ + cm_connect_success_diag(mlme_obj, &conn_stats); +} + +void cm_diag_get_auth_enc_type_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *auth_type, + uint8_t *ucast_cipher, + uint8_t *mcast_cipher, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_crypto_params *crypto_params; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return; + } + + crypto_params = wlan_crypto_vdev_get_crypto_params(vdev); + if (!crypto_params) { + mlme_err("crypto params is null"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + if (auth_type) + cm_diag_get_auth_type(auth_type, + crypto_params->authmodeset, + crypto_params->key_mgmt, + crypto_params->ucastcipherset); + if (ucast_cipher) + *ucast_cipher = + cm_get_diag_enc_type(crypto_params->ucastcipherset); + if (mcast_cipher) + *mcast_cipher = + cm_get_diag_enc_type(crypto_params->ucastcipherset); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + +} + +#ifdef WLAN_UNIT_TEST +static const char *cm_diag_get_persona(enum mgmt_bss_type persona) +{ + switch (persona) { + CASE_RETURN_STRING(STA_PERSONA); + CASE_RETURN_STRING(SAP_PERSONA); + CASE_RETURN_STRING(P2P_CLIENT_PERSONA); + CASE_RETURN_STRING(P2P_GO_PERSONA); + CASE_RETURN_STRING(FTM_PERSONA); + CASE_RETURN_STRING(MONITOR_PERSONA); + CASE_RETURN_STRING(P2P_DEVICE_PERSONA); + CASE_RETURN_STRING(NDI_PERSONA); + CASE_RETURN_STRING(WDS_PERSONA); + default: + return "Unknown"; + } +} + +static const char *cm_diag_get_auth_type_str(uint8_t auth_type) +{ + switch (auth_type) { + CASE_RETURN_STRING(AUTH_OPEN); + CASE_RETURN_STRING(AUTH_SHARED); + CASE_RETURN_STRING(AUTH_WPA_EAP); + CASE_RETURN_STRING(AUTH_WPA_PSK); + CASE_RETURN_STRING(AUTH_WPA2_EAP); + CASE_RETURN_STRING(AUTH_WPA2_PSK); + CASE_RETURN_STRING(AUTH_WAPI_CERT); + CASE_RETURN_STRING(AUTH_WAPI_PSK); + default: + return "Unknown"; + } +} + +void cm_get_sta_cxn_info(struct wlan_objmgr_vdev *vdev, + char *buf, uint32_t buf_sz) +{ + struct qdf_mac_addr bss_peer_mac; + struct wlan_ssid ssid; + QDF_STATUS status; + struct wlan_channel *des_chan; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_crypto_params *crypto_params; + qdf_freq_t oper_freq; + int8_t rssi = 0; + uint32_t nss, hw_mode; + struct policy_mgr_conc_connection_info *conn_info; + uint32_t i = 0, len = 0, max_cxn = 0; + enum mgmt_ch_width ch_width; + enum mgmt_dot11_mode dot11mode; + enum mgmt_bss_type type; + uint8_t authtype; + enum mgmt_encrypt_type enctype; + enum QDF_OPMODE opmode; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return; + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + qdf_mem_set(buf, buf_sz, '\0'); + + status = wlan_vdev_get_bss_peer_mac(vdev, &bss_peer_mac); + if (QDF_IS_STATUS_ERROR(status)) + return; + + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tbssid: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bss_peer_mac.bytes)); + + status = wlan_vdev_mlme_get_ssid(vdev, ssid.ssid, &ssid.length); + if (QDF_IS_STATUS_ERROR(status)) + return; + if (ssid.length > WLAN_SSID_MAX_LEN) + ssid.length = WLAN_SSID_MAX_LEN; + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tssid: %.*s", ssid.length, + ssid.ssid); + + cm_get_rssi_snr_by_bssid(pdev, &bss_peer_mac, &rssi, NULL); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\trssi: %d", rssi); + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + ch_width = cm_get_diag_ch_width(des_chan->ch_width); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tbw: %s", cm_diag_get_ch_width_str(ch_width)); + dot11mode = cm_diag_dot11_mode_from_phy_mode(des_chan->ch_phymode); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tdot11mode: %s", + cm_diag_get_dot11_mode_str(dot11mode)); + + opmode = wlan_vdev_mlme_get_opmode(vdev); + type = cm_get_diag_persona(opmode); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tbss_type: %s", cm_diag_get_persona(type)); + + oper_freq = wlan_get_operation_chan_freq(vdev); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tch_freq: %d", oper_freq); + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev component object is NULL"); + return; + } + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tQoS: %d", + vdev_mlme->ext_vdev_ptr->connect_info.qos_enabled); + + crypto_params = wlan_crypto_vdev_get_crypto_params(vdev); + + if (!crypto_params) { + mlme_err("crypto params is null"); + return; + } + + cm_diag_get_auth_type(&authtype, crypto_params->authmodeset, + crypto_params->key_mgmt, + crypto_params->ucastcipherset); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tauth_type: %s", + cm_diag_get_auth_type_str(authtype)); + + enctype = cm_get_diag_enc_type(crypto_params->ucastcipherset); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tencry_type: %s", + cm_diag_get_encr_type_str(enctype)); + + conn_info = policy_mgr_get_conn_info(&max_cxn); + for (i = 0; i < max_cxn; i++) + if ((conn_info->vdev_id == wlan_vdev_get_id(vdev)) && + (conn_info->in_use)) + break; + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tmac: %d", conn_info->mac); + nss = wlan_vdev_mlme_get_nss(vdev); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\torig_nss: %dx%d neg_nss: %dx%d", + conn_info->original_nss, conn_info->original_nss, + nss, nss); + hw_mode = policy_mgr_is_current_hwmode_dbs(psoc); + len += qdf_scnprintf(buf + len, buf_sz - len, + "\n\tis_current_hw_mode_dbs: %s", + ((hw_mode != 0) ? "yes" : "no")); +} +#endif +#endif + +#define MGMT_FRAME_FULL_PROTECTION (RSN_CAP_MFP_REQUIRED | RSN_CAP_MFP_CAPABLE) + +QDF_STATUS cm_connect_start_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_req *req) +{ + struct wlan_objmgr_psoc *psoc; + struct rso_config *rso_cfg; + struct cm_roam_values_copy src_cfg = {}; + + if (!vdev || !req) { + mlme_err("vdev or req is NULL"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err("vdev_id: %d psoc not found", req->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!wlan_dp_is_local_pkt_capture_active(psoc) && + policy_mgr_is_sta_mon_concurrency(psoc)) + return QDF_STATUS_E_NOSUPPORT; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (rso_cfg) { + uint8_t rso_user_mfp; + + rso_cfg->orig_sec_info.rsn_caps = req->crypto.rsn_caps; + rso_cfg->orig_sec_info.authmodeset = req->crypto.auth_type; + rso_cfg->orig_sec_info.ucastcipherset = + req->crypto.ciphers_pairwise; + rso_cfg->orig_sec_info.mcastcipherset = + req->crypto.group_cipher; + rso_cfg->orig_sec_info.key_mgmt = req->crypto.akm_suites; + /* + * reset the roam channel list entries present in the rso + * config which gets stored during connect resp failure in + * wlan_cm_send_connect_rsp + */ + rso_cfg->tried_candidate_freq_list.num_chan = 0; + + /* + * This user configure MFP capability is global and is for + * multiple profiles which can be used by firmware for cross-AKM + * roaming. When user configures MFP required then we should + * set both MFPC and MFPR in RSN caps. + */ + rso_user_mfp = req->crypto.user_mfp; + if (rso_user_mfp == RSN_CAP_MFP_REQUIRED) + rso_user_mfp = MGMT_FRAME_FULL_PROTECTION; + rso_cfg->rso_rsn_caps = (req->crypto.rsn_caps) & + (~MGMT_FRAME_FULL_PROTECTION); + rso_cfg->rso_rsn_caps = (rso_cfg->rso_rsn_caps) | rso_user_mfp; + } + + if (wlan_get_vendor_ie_ptr_from_oui(HS20_OUI_TYPE, + HS20_OUI_TYPE_SIZE, + req->assoc_ie.ptr, + req->assoc_ie.len)) + src_cfg.bool_value = true; + wlan_cm_roam_cfg_set_value(wlan_vdev_get_psoc(vdev), + wlan_vdev_get_id(vdev), + HS_20_AP, &src_cfg); + if (req->source != CM_MLO_LINK_SWITCH_CONNECT) + ml_nlink_conn_change_notify( + psoc, wlan_vdev_get_id(vdev), + ml_nlink_connect_start_evt, NULL); + + return QDF_STATUS_SUCCESS; +} + +void cm_free_join_req(struct cm_vdev_join_req *join_req) +{ + if (!join_req) + return; + + util_scan_free_cache_entry(join_req->entry); + join_req->entry = NULL; + qdf_mem_free(join_req->assoc_ie.ptr); + qdf_mem_free(join_req->scan_ie.ptr); + join_req->assoc_ie.ptr = NULL; + join_req->scan_ie.ptr = NULL; + qdf_mem_free(join_req); +} + +QDF_STATUS cm_flush_join_req(struct scheduler_msg *msg) +{ + struct cm_vdev_join_req *join_req; + + if (!msg || !msg->bodyptr) { + mlme_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + join_req = msg->bodyptr; + cm_free_join_req(join_req); + + return QDF_STATUS_SUCCESS; +} +#ifdef WLAN_FEATURE_11BE_MLO +#if defined (SAP_MULTI_LINK_EMULATION) +static void +set_partner_info_for_2link_sap(struct scan_cache_entry *scan_entry, + struct mlo_partner_info *partner_info) +{ + partner_info->partner_link_info[0].link_addr = + scan_entry->ml_info.link_info[0].link_addr; + partner_info->partner_link_info[0].link_id = + scan_entry->ml_info.link_info[0].link_id; + partner_info->partner_link_info[0].chan_freq = + scan_entry->ml_info.link_info[0].freq; + partner_info->num_partner_links = 1; + +} +#else +static void +set_partner_info_for_2link_sap(struct scan_cache_entry *scan_entry, + struct mlo_partner_info *partner_info) +{ +} +#endif + +QDF_STATUS +cm_get_ml_partner_info(struct wlan_objmgr_pdev *pdev, + struct cm_connect_req *conn_req) +{ + uint8_t i, j = 0; + uint8_t mlo_support_link_num; + struct wlan_objmgr_psoc *psoc; + struct scan_cache_entry *scan_entry = conn_req->cur_candidate->entry; + struct mlo_partner_info *partner_info = &conn_req->req.ml_parnter_info; + + /* Initialize number of partner links as zero */ + partner_info->num_partner_links = 0; + + /* If ML IE is not present then return failure*/ + if (!scan_entry->ie_list.multi_link_bv) + return QDF_STATUS_E_FAILURE; + + /* In case of single link ML return success*/ + if (!scan_entry->ml_info.num_links) + return QDF_STATUS_SUCCESS; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + mlo_support_link_num = wlan_mlme_get_sta_mlo_conn_max_num(psoc); + mlme_debug("sta mlo support link num: %d", mlo_support_link_num); + + /* TODO: Make sure that scan_entry->ml_info->link_info is a sorted + * list. + * When candidates are selected by filter, partner link is set as + * valid in scan entry when mlo band match, then valid partner link is + * copied to join request, after that partner link valid bit in scan + * entry should be cleared to not affect next connect request. + */ + for (i = 0; i < scan_entry->ml_info.num_links; i++) { + mlme_debug("freq: %d, link id: %d is valid %d "QDF_MAC_ADDR_FMT, + scan_entry->ml_info.link_info[i].freq, + scan_entry->ml_info.link_info[i].link_id, + scan_entry->ml_info.link_info[i].is_valid_link, + QDF_MAC_ADDR_REF( + scan_entry->ml_info.link_info[i].link_addr.bytes)); + if (mlo_support_link_num && j >= mlo_support_link_num - 1) + break; + + if (!scan_entry->ml_info.link_info[i].is_valid_link) + continue; + + partner_info->partner_link_info[j].link_addr = + scan_entry->ml_info.link_info[i].link_addr; + partner_info->partner_link_info[j].link_id = + scan_entry->ml_info.link_info[i].link_id; + partner_info->partner_link_info[j].chan_freq = + scan_entry->ml_info.link_info[i].freq; + j++; + } + + partner_info->num_partner_links = j; + mlme_debug("sta and ap intersect num of partner link: %d", j); + + set_partner_info_for_2link_sap(scan_entry, partner_info); + + return QDF_STATUS_SUCCESS; +} + +static void cm_update_mlo_mgr_info(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_req *join_req) +{ + struct qdf_mac_addr link_addr; + uint8_t link_id, i; + struct wlan_channel channel = {0}; + struct mlo_partner_info *partner_info; + + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return; + + link_id = join_req->entry->ml_info.self_link_id; + qdf_mem_copy(link_addr.bytes, join_req->entry->bssid.bytes, + QDF_MAC_ADDR_SIZE); + + /* Reset Previous info if any and update the AP self link info */ + mlo_mgr_reset_ap_link_info(vdev); + mlo_mgr_update_ap_link_info(vdev, link_id, link_addr.bytes, channel); + + partner_info = &join_req->partner_info; + for (i = 0; i < partner_info->num_partner_links; i++) { + link_id = partner_info->partner_link_info[i].link_id; + qdf_mem_copy(link_addr.bytes, + partner_info->partner_link_info[i].link_addr.bytes, + QDF_MAC_ADDR_SIZE); + /* Updating AP partner link info */ + mlo_mgr_update_ap_link_info(vdev, link_id, link_addr.bytes, + channel); + } +} + +static void +cm_copy_join_req_info_from_cm_connect_req(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_req *join_req, + struct wlan_cm_vdev_connect_req *req) +{ + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + qdf_mem_copy(&join_req->partner_info, &req->ml_parnter_info, + sizeof(struct mlo_partner_info)); + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + join_req->assoc_link_id = join_req->entry->ml_info.self_link_id; + + mlme_debug("Num of partner links %d assoc_link_id:%d", + join_req->partner_info.num_partner_links, + join_req->assoc_link_id); + + cm_update_mlo_mgr_info(vdev, join_req); +} +#else +static inline void +cm_copy_join_req_info_from_cm_connect_req(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_req *join_req, + struct wlan_cm_vdev_connect_req *req) +{ +} +#endif + +static QDF_STATUS +cm_copy_join_params(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_req *join_req, + struct wlan_cm_vdev_connect_req *req) +{ + if (req->assoc_ie.len) { + join_req->assoc_ie.ptr = qdf_mem_malloc(req->assoc_ie.len); + if (!join_req->assoc_ie.ptr) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(join_req->assoc_ie.ptr, req->assoc_ie.ptr, + req->assoc_ie.len); + join_req->assoc_ie.len = req->assoc_ie.len; + } + if (req->scan_ie.len) { + join_req->scan_ie.ptr = qdf_mem_malloc(req->scan_ie.len); + if (!join_req->scan_ie.ptr) + return QDF_STATUS_E_NOMEM; + join_req->scan_ie.len = req->scan_ie.len; + qdf_mem_copy(join_req->scan_ie.ptr, req->scan_ie.ptr, + req->scan_ie.len); + } + join_req->entry = util_scan_copy_cache_entry(req->bss->entry); + if (!join_req->entry) + return QDF_STATUS_E_NOMEM; + + cm_copy_join_req_info_from_cm_connect_req(vdev, join_req, req); + + if (req->owe_trans_ssid.length) + join_req->owe_trans_ssid = req->owe_trans_ssid; + + join_req->vdev_id = req->vdev_id; + join_req->cm_id = req->cm_id; + join_req->force_rsne_override = req->force_rsne_override; + join_req->is_wps_connection = req->is_wps_connection; + join_req->is_osen_connection = req->is_osen_connection; + join_req->is_ssid_hidden = req->bss->entry->is_hidden_ssid; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cm_send_connect_rsp(struct scheduler_msg *msg) +{ + struct cm_vdev_join_rsp *rsp; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + struct wlan_objmgr_peer *peer; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + rsp = msg->bodyptr; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(rsp->psoc, + rsp->connect_rsp.vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err(CM_PREFIX_FMT "vdev not found", + CM_PREFIX_REF(rsp->connect_rsp.vdev_id, + rsp->connect_rsp.cm_id)); + wlan_cm_free_connect_rsp(rsp); + return QDF_STATUS_E_INVAL; + } + + /* check and delete bss peer in case of failure */ + if (QDF_IS_STATUS_ERROR(rsp->connect_rsp.connect_status) && + (wlan_vdev_mlme_is_init_state(vdev) == QDF_STATUS_SUCCESS)) { + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, + WLAN_MLME_CM_ID); + if (peer) { + cm_send_bss_peer_delete_req(vdev); + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_CM_ID); + } + } + + /* + * Host creates a ROAM_SCAN_CHAN list with BSSID entries present + * in the scan database. If the connection to an AP fails due to + * Auth/Join/Assoc timeout, Host removes the AP entry from the + * Scan database, assuming it’s not reachable (to avoid + * reconnecting to the AP as it's not responding). Due to this, + * FW does not include the frequency(s), for which the + * connection failed, in roam scan. + * To avoid this, store the frequency(s) of all the candidates + * to which the driver tried connection in the rso config during + * connect resp failure and use the same list to update the roam + * channel list on the top of entries present in scan db. + */ + if (QDF_IS_STATUS_ERROR(rsp->connect_rsp.connect_status)) + cm_update_tried_candidate_freq_list(rsp->psoc, vdev, + &rsp->connect_rsp); + + cm_csr_connect_rsp(vdev, rsp); + if (rsp->connect_rsp.is_reassoc) + status = wlan_cm_reassoc_rsp(vdev, &rsp->connect_rsp); + else + status = wlan_cm_connect_rsp(vdev, &rsp->connect_rsp); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + wlan_cm_free_connect_rsp(rsp); + + return status; +} + +#define FILS_HLP_OUI_TYPE "\x5" +#define FILS_HLP_OUI_LEN 1 + +static void +cm_update_hlp_data_from_assoc_ie(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_connect_req *req) +{ + const uint8_t *hlp_ext_ie; + const uint8_t *fragment_ie; + + /* clear hlp IE */ + cm_update_hlp_info(vdev, NULL, 0, true); + + hlp_ext_ie = wlan_get_ext_ie_ptr_from_ext_id(FILS_HLP_OUI_TYPE, + FILS_HLP_OUI_LEN, + req->assoc_ie.ptr, + req->assoc_ie.len); + if (hlp_ext_ie) + cm_update_hlp_info(vdev, hlp_ext_ie, hlp_ext_ie[1] + 2, false); + + fragment_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_FRAGMENT_IE, + req->assoc_ie.ptr, + req->assoc_ie.len); + if (fragment_ie) + cm_update_hlp_info(vdev, fragment_ie, + fragment_ie[1] + 2, false); +} + +QDF_STATUS +cm_handle_connect_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_connect_req *req) +{ + struct cm_vdev_join_req *join_req; + struct scheduler_msg msg; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + if (!vdev || !req) + return QDF_STATUS_E_FAILURE; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "psoc not found", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + return QDF_STATUS_E_INVAL; + } + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + qdf_mem_zero(&msg, sizeof(msg)); + join_req = qdf_mem_malloc(sizeof(*join_req)); + if (!join_req) + return QDF_STATUS_E_NOMEM; + + status = cm_copy_join_params(vdev ,join_req, req); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "Failed to copy join req", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + cm_free_join_req(join_req); + return QDF_STATUS_E_FAILURE; + } + + cm_update_hlp_data_from_assoc_ie(vdev, req); + + status = cm_csr_handle_join_req(vdev, req, join_req, false); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "fail to fill params from legacy", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + cm_free_join_req(join_req); + return QDF_STATUS_E_FAILURE; + } + + mlme_debug(CM_PREFIX_FMT "HT cap %x", + CM_PREFIX_REF(req->vdev_id, req->cm_id), req->ht_caps); + wlan_rec_conn_info(req->vdev_id, DEBUG_CONN_CONNECTING, + req->bss->entry->bssid.bytes, + req->bss->entry->neg_sec_info.key_mgmt, + req->bss->entry->channel.chan_freq); + + msg.bodyptr = join_req; + msg.type = CM_CONNECT_REQ; + msg.flush_callback = cm_flush_join_req; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "msg post fail", + CM_PREFIX_REF(req->vdev_id, req->cm_id)); + cm_free_join_req(join_req); + } + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) + wlan_register_txrx_packetdump(OL_TXRX_PDEV_ID); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * cm_set_peer_mld_info() - set mld_mac and is_assoc_peer flag + * @req: cm_peer_create_req + * @mld_mac: mld mac addr + * @is_assoc_peer: is assoc peer + * + * Return: void + */ +static void cm_set_peer_mld_info(struct cm_peer_create_req *req, + struct qdf_mac_addr *mld_mac, + bool is_assoc_peer) +{ + if (req && mld_mac) { + qdf_copy_macaddr(&req->mld_mac, mld_mac); + req->is_assoc_peer = is_assoc_peer; + } +} +#else +static void cm_set_peer_mld_info(struct cm_peer_create_req *req, + struct qdf_mac_addr *mld_mac, + bool is_assoc_peer) +{ +} +#endif + +QDF_STATUS +cm_send_bss_peer_create_req(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + struct qdf_mac_addr *mld_mac, + bool is_assoc_peer) +{ + struct scheduler_msg msg; + QDF_STATUS status; + struct cm_peer_create_req *req; + + if (!vdev || !peer_mac) + return QDF_STATUS_E_FAILURE; + + qdf_mem_zero(&msg, sizeof(msg)); + req = qdf_mem_malloc(sizeof(*req)); + + if (!req) + return QDF_STATUS_E_NOMEM; + + cm_set_peer_mld_info(req, mld_mac, is_assoc_peer); + + req->vdev_id = wlan_vdev_get_id(vdev); + qdf_copy_macaddr(&req->peer_mac, peer_mac); + msg.bodyptr = req; + msg.type = CM_BSS_PEER_CREATE_REQ; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("vdev %d: post fail", req->vdev_id); + qdf_mem_free(req); + } + + return status; + +} + +#ifdef WLAN_FEATURE_FILS_SK +static inline bool is_fils_connection(struct wlan_cm_connect_resp *resp) +{ + return resp->is_fils_connection; +} +#else +static inline bool is_fils_connection(struct wlan_cm_connect_resp *resp) +{ + return false; +} +#endif + +static void cm_process_connect_complete(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + uint8_t vdev_id = wlan_vdev_get_id(vdev); + int32_t ucast_cipher, akm; + uint32_t key_interval; + struct element_info *bcn_probe_rsp = &rsp->connect_ies.bcn_probe_rsp; + + if (bcn_probe_rsp->ptr && + bcn_probe_rsp->len > sizeof(struct wlan_frame_hdr)) { + cm_update_prev_ap_ie(psoc, vdev_id, + bcn_probe_rsp->len - + sizeof(struct wlan_frame_hdr), + bcn_probe_rsp->ptr + + sizeof(struct wlan_frame_hdr)); + } + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) { + mlme_debug("Update the MDID in PMK cache for FT-SAE case"); + cm_update_pmk_cache_ft(psoc, vdev_id, NULL); + } + + cm_update_owe_info(vdev, rsp, vdev_id); + cm_csr_set_joined(vdev_id); + cm_csr_send_set_ie(vdev); + + ucast_cipher = wlan_crypto_get_param(vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + if (!rsp->is_wps_connection && + (is_fils_connection(rsp) || !ucast_cipher || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_NONE) == + ucast_cipher || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP))) { + cm_csr_set_ss_none(vdev_id); + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + mlo_enable_rso(pdev, vdev, rsp); + else + cm_roam_start_init_on_connect(pdev, vdev_id); + } else { + if (rsp->is_wps_connection) + key_interval = + WAIT_FOR_WPS_KEY_TIMEOUT_PERIOD; + else + key_interval = + WAIT_FOR_KEY_TIMEOUT_PERIOD; + cm_update_wait_for_key_timer(vdev, vdev_id, key_interval); + } + +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +cm_update_tid_mapping(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_t2lm_context *t2lm_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!vdev || !vdev->mlo_dev_ctx) + return QDF_STATUS_E_NULL_VALUE; + + if (!wlan_cm_is_vdev_connected(vdev)) + return QDF_STATUS_E_AGAIN; + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) || + !mlo_check_if_all_links_up(vdev)) + return QDF_STATUS_E_FAILURE; + + t2lm_ctx = &vdev->mlo_dev_ctx->sta_ctx->copied_t2lm_ie_assoc_rsp; + if (!t2lm_ctx) { + mlme_err("T2LM ctx is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wlan_update_t2lm_mapping(vdev, t2lm_ctx, t2lm_ctx->tsf); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("T2LM IE beacon process failed"); + } + wlan_connectivity_t2lm_status_event(vdev); + + return status; +} +#else +static inline QDF_STATUS +cm_update_tid_mapping(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif +static void +cm_install_link_vdev_keys(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_crypto_key *crypto_key; + struct wlan_crypto_params *crypto_params; + enum QDF_OPMODE op_mode; + uint16_t i; + bool pairwise; + uint8_t vdev_id, link_id; + bool key_present = false; + uint16_t max_key_index = WLAN_CRYPTO_MAXKEYIDX + + WLAN_CRYPTO_MAXIGTKKEYIDX + + WLAN_CRYPTO_MAXBIGTKKEYIDX; + + if (!vdev) + return; + + vdev_id = wlan_vdev_get_id(vdev); + op_mode = wlan_vdev_mlme_get_opmode(vdev); + if (op_mode != QDF_STA_MODE || + !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return; + + crypto_params = wlan_crypto_vdev_get_crypto_params(vdev); + if (!crypto_params) { + mlme_err("crypto params is null"); + return; + } + + if (!crypto_params->ucastcipherset || + QDF_HAS_PARAM(crypto_params->ucastcipherset, WLAN_CRYPTO_CIPHER_NONE)) + return; + + link_id = wlan_vdev_get_link_id(vdev); + + if (!mlo_is_set_key_defered(vdev, link_id) && + !mlo_mgr_is_link_switch_in_progress(vdev)) { + mlme_debug("keys are not deferred for link_id %d", link_id); + return; + } + + wlan_crypto_aquire_lock(); + for (i = 0; i < max_key_index; i++) { + crypto_key = wlan_crypto_get_key(vdev, i); + if (!crypto_key) + continue; + + pairwise = crypto_key->key_type ? WLAN_CRYPTO_KEY_TYPE_UNICAST : WLAN_CRYPTO_KEY_TYPE_GROUP; + mlo_debug("MLO:send keys for vdev_id %d link_id %d , key_idx %d, pairwise %d", + vdev_id, link_id, i, pairwise); + mlme_cm_osif_send_keys(vdev, i, pairwise, + crypto_key->cipher_type); + key_present = true; + } + wlan_crypto_release_lock(); + + if (!key_present && mlo_mgr_is_link_switch_in_progress(vdev)) { + mlme_err("No key found for link_id %d", link_id); + QDF_BUG(0); + } + mlo_defer_set_keys(vdev, link_id, false); +} + +#ifdef WLAN_CHIPSET_STATS +void cm_cp_stats_cstats_log_connect_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct vdev_mlme_obj *vdev_mlme; + struct wlan_channel *des_chan; + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + struct wlan_crypto_params *crypto_params; + struct cstats_sta_connect_resp stat = {0}; + + if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_STA_CONNECT_SUCCESS_EVENT_ID; + } else { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_STA_CONNECT_FAIL_EVENT_ID; + } + + wlan_mlme_get_sta_ch_width(vdev, &ch_width); + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + mlme_err("vdev component object is NULL"); + return; + } + + crypto_params = wlan_crypto_vdev_get_crypto_params(vdev); + if (!crypto_params) { + mlme_err("crypto params is null"); + return; + } + + cm_diag_get_auth_type(&stat.auth_type, + crypto_params->authmodeset, + crypto_params->key_mgmt, + crypto_params->ucastcipherset); + + stat.cmn.hdr.length = sizeof(struct cstats_sta_connect_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.freq = rsp->freq; + stat.chnl_bw = cm_get_diag_ch_width(ch_width); + stat.dot11mode = cm_diag_dot11_mode_from_phy_mode(des_chan->ch_phymode); + stat.qos_capability = vdev_mlme->ext_vdev_ptr->connect_info.qos_enabled; + stat.encryption_type = + cm_get_diag_enc_type(crypto_params->ucastcipherset); + stat.result_code = rsp->connect_status; + stat.ssid_len = rsp->ssid.length; + qdf_mem_copy(stat.ssid, rsp->ssid.ssid, rsp->ssid.length); + CSTATS_MAC_COPY(stat.bssid, rsp->bssid.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_sta_connect_resp), &stat); +} +#else +static inline void +cm_cp_stats_cstats_log_connect_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ +} +#endif /* WLAN_CHIPSET_STATS */ + +QDF_STATUS +cm_connect_complete_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + uint8_t vdev_id; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE op_mode; + bool eht_capab = false; + QDF_STATUS status; + + if (!vdev || !rsp) { + mlme_err("vdev or rsp is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + op_mode = wlan_vdev_mlme_get_opmode(vdev); + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "pdev not found", + CM_PREFIX_REF(vdev_id, rsp->cm_id)); + return QDF_STATUS_E_INVAL; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "psoc not found", + CM_PREFIX_REF(vdev_id, rsp->cm_id)); + return QDF_STATUS_E_INVAL; + } + + cm_csr_connect_done_ind(vdev, rsp); + + cm_cp_stats_cstats_log_connect_event(vdev, rsp); + + cm_connect_info(vdev, QDF_IS_STATUS_SUCCESS(rsp->connect_status) ? + true : false, &rsp->bssid, &rsp->ssid, + rsp->freq); + + if (QDF_IS_STATUS_SUCCESS(rsp->connect_status)) { + if (rsp->cm_id & CM_ID_LSWITCH_BIT) + ml_nlink_conn_change_notify( + psoc, vdev_id, + ml_nlink_link_switch_pre_completion_evt, NULL); + + if (policy_mgr_ml_link_vdev_need_to_be_disabled(psoc, vdev, + false)) + policy_mgr_move_vdev_from_connection_to_disabled_tbl( + psoc, vdev_id); + else + policy_mgr_incr_active_session(psoc, op_mode, vdev_id); + ml_nlink_conn_change_notify( + psoc, vdev_id, + ml_nlink_connect_completion_evt, NULL); + cm_process_connect_complete(psoc, pdev, vdev, rsp); + cm_install_link_vdev_keys(vdev); + wlan_tdls_notify_sta_connect(vdev_id, + mlme_get_tdls_chan_switch_prohibited(vdev), + mlme_get_tdls_prohibited(vdev), + vdev); + wlan_p2p_status_connect(vdev); + cm_update_tid_mapping(vdev); + cm_update_associated_ch_info(vdev, true); + + wlan_psoc_mlme_get_11be_capab(psoc, &eht_capab); + if (eht_capab) { + status = policy_mgr_current_connections_update( + psoc, vdev_id, + rsp->freq, + POLICY_MGR_UPDATE_REASON_STA_CONNECT, + POLICY_MGR_DEF_REQ_ID); + if (status == QDF_STATUS_E_FAILURE) + mlme_debug("Failed to take next action after connect"); + } + } + + mlo_roam_connect_complete(vdev); + + if (op_mode == QDF_STA_MODE && + (wlan_vdev_mlme_is_mlo_link_vdev(vdev) || + !wlan_vdev_mlme_is_mlo_vdev(vdev))) + wlan_cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_INIT, + REASON_CONNECT); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +static void cm_free_tspec_ie(struct cm_vdev_join_rsp *rsp) +{ + qdf_mem_free(rsp->tspec_ie.ptr); + rsp->tspec_ie.ptr = NULL; + rsp->tspec_ie.len = 0; +} + +#else +static void cm_free_tspec_ie(struct cm_vdev_join_rsp *rsp) +{} +#endif + +void wlan_cm_free_connect_rsp(struct cm_vdev_join_rsp *rsp) +{ + cm_free_tspec_ie(rsp); + qdf_mem_free(rsp->ric_resp_ie.ptr); + cm_free_connect_rsp_ies(&rsp->connect_rsp); + qdf_mem_zero(rsp, sizeof(*rsp)); + qdf_mem_free(rsp); +} + +bool cm_is_vdevid_connected(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool connected; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev %d: vdev not found", vdev_id); + return false; + } + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return false; + } + connected = cm_is_vdev_connected(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return connected; +} + +bool cm_is_vdevid_active(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool active; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev %d: vdev not found", vdev_id); + return false; + } + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return false; + } + active = cm_is_vdev_active(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return active; +} + +static +QDF_STATUS cm_handle_hw_mode_change_resp_cb(struct scheduler_msg *msg) +{ + struct cm_vdev_hw_mode_rsp *rsp; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + rsp = msg->bodyptr; + wlan_cm_hw_mode_change_resp(rsp->pdev, rsp->vdev_id, rsp->cm_id, + rsp->status); + + qdf_mem_free(rsp); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cm_handle_hw_mode_change_resp(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + wlan_cm_id cm_id, QDF_STATUS status) +{ + struct cm_vdev_hw_mode_rsp *rsp; + struct scheduler_msg rsp_msg = {0}; + QDF_STATUS qdf_status; + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return QDF_STATUS_E_FAILURE; + + rsp->pdev = pdev; + rsp->vdev_id = vdev_id; + rsp->cm_id = cm_id; + rsp->status = status; + + rsp_msg.bodyptr = rsp; + rsp_msg.callback = cm_handle_hw_mode_change_resp_cb; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_TARGET_IF, + QDF_MODULE_ID_TARGET_IF, &rsp_msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + mlme_err(CM_PREFIX_FMT "Failed to post HW mode change rsp", + CM_PREFIX_REF(vdev_id, cm_id)); + qdf_mem_free(rsp); + } + + return qdf_status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c new file mode 100644 index 0000000000..8b75c5ee66 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2012-2015, 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implements legacy disconnect connect specific APIs of + * connection mgr to initiate vdev manager operations + */ + +#include "wlan_cm_vdev_api.h" +#include "wlan_mlme_main.h" +#include "wlan_cm_api.h" +#include "wlan_p2p_api.h" +#include "wlan_tdls_api.h" +#include +#include +#include +#include +#include +#include "wni_api.h" +#include "connection_mgr/core/src/wlan_cm_roam.h" +#include +#include "wlan_mlo_mgr_roam.h" +#include "wlan_t2lm_api.h" +#include "wlan_mlo_link_force.h" +#include +#include + +static void cm_abort_connect_request_timers(struct wlan_objmgr_vdev *vdev) +{ + struct scheduler_msg msg; + QDF_STATUS status; + + qdf_mem_zero(&msg, sizeof(msg)); + msg.bodyval = wlan_vdev_get_id(vdev); + msg.type = CM_ABORT_CONN_TIMER; + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("msg CM_ABORT_CONN_TIMER post fail"); +} + +QDF_STATUS cm_disconnect_start_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_disconnect_req *req) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + bool user_disconnect; + + if (!vdev || !req) { + mlme_err("vdev or req is NULL"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("vdev_id: %d pdev not found", req->vdev_id); + return QDF_STATUS_E_INVAL; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err("vdev_id: %d psoc not found", req->vdev_id); + return QDF_STATUS_E_INVAL; + } + mlo_sta_stop_reconfig_timer(vdev); + if (req->source != CM_MLO_LINK_SWITCH_DISCONNECT) + ml_nlink_conn_change_notify( + psoc, wlan_vdev_get_id(vdev), + ml_nlink_disconnect_start_evt, NULL); + if (cm_csr_is_ss_wait_for_key(req->vdev_id)) { + mlme_debug("Stop Wait for key timer"); + cm_stop_wait_for_key_timer(psoc, req->vdev_id); + cm_csr_set_ss_none(req->vdev_id); + } + + user_disconnect = + (req->source == CM_OSIF_DISCONNECT || + req->source == CM_MLO_LINK_SWITCH_DISCONNECT) ? true : false; + if (user_disconnect) + wlan_p2p_cleanup_roc_by_vdev(vdev, false); + + /* + * For link switch disconnect avoid posting msg to PE to + * delete all the TDLS peers since pe_session can get deleted before + * TDLS msg is processed, causing the TDLS peers to be not deleted. + * The AID bitmap also gets cleared during pe_session deletion, + * so during subsequent disconnects also to not deleted the TDLS peers + * TODO: Move all TDLS peers deletion logic from IF_MGR to be symmetric + */ + if (req->source == CM_OSIF_DISCONNECT) + wlan_tdls_notify_sta_disconnect(req->vdev_id, false, + true, vdev); + + cm_abort_connect_request_timers(vdev); + + if (req->source != CM_MLO_ROAM_INTERNAL_DISCONNECT && + req->source != CM_MLO_LINK_SWITCH_DISCONNECT) { + mlme_debug("Free copied reassoc rsp"); + mlo_roam_free_copied_reassoc_rsp(vdev); + } + + wlan_t2lm_clear_all_tid_mapping(vdev); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_CHIPSET_STATS +static void +cm_cp_stats_cstats_disconn_req_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_discon_req *req) +{ + struct cstats_sta_disconnect_req stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_DISCONNECT_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sta_disconnect_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = req->req.vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.reason_code = req->req.reason_code; + stat.source = req->req.source; + stat.is_no_disassoc_disconnect = req->req.is_no_disassoc_disconnect; + CSTATS_MAC_COPY(stat.bssid, req->req.bssid.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_sta_disconnect_req), &stat); +} + +static void +cm_cp_stats_cstats_disconn_resp_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ + struct cstats_sta_disconnect_resp stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_DISCONNECT_DONE_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sta_disconnect_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.cm_id = rsp->req.cm_id; + stat.reason_code = rsp->req.req.reason_code; + stat.source = rsp->req.req.source; + CSTATS_MAC_COPY(stat.bssid, rsp->req.req.bssid.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_sta_disconnect_resp), + &stat); +} +#else +static inline void +cm_cp_stats_cstats_disconn_req_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_discon_req *req) +{ +} + +static inline void +cm_cp_stats_cstats_disconn_resp_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ +} +#endif /* WLAN_CHIPSET_STATS */ + +QDF_STATUS +cm_handle_disconnect_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_discon_req *req) +{ + struct wlan_cm_vdev_discon_req *discon_req; + struct scheduler_msg msg; + QDF_STATUS status; + enum QDF_OPMODE opmode; + struct wlan_objmgr_pdev *pdev; + uint8_t vdev_id; + struct rso_config *rso_cfg; + struct wlan_objmgr_psoc *psoc; + + if (!vdev || !req) + return QDF_STATUS_E_FAILURE; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "pdev not found", + CM_PREFIX_REF(req->req.vdev_id, req->cm_id)); + return QDF_STATUS_E_INVAL; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "psoc not found", + CM_PREFIX_REF(req->req.vdev_id, req->cm_id)); + return QDF_STATUS_E_INVAL; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_INVAL; + vdev_id = wlan_vdev_get_id(vdev); + + qdf_mem_zero(&msg, sizeof(msg)); + + discon_req = qdf_mem_malloc(sizeof(*discon_req)); + if (!discon_req) + return QDF_STATUS_E_NOMEM; + cm_cp_stats_cstats_disconn_req_event(vdev, req); + + cm_csr_handle_diconnect_req(vdev, req); + wlan_roam_reset_roam_params(vdev); + cm_roam_restore_default_config(pdev, vdev_id); + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode == QDF_STA_MODE && !wlan_vdev_mlme_is_link_sta_vdev(vdev)) + wlan_cm_roam_state_change(pdev, vdev_id, + WLAN_ROAM_DEINIT, + REASON_DISCONNECTED); + if (rso_cfg->roam_scan_freq_lst.freq_list) + qdf_mem_free(rso_cfg->roam_scan_freq_lst.freq_list); + rso_cfg->roam_scan_freq_lst.freq_list = NULL; + rso_cfg->roam_scan_freq_lst.num_chan = 0; + + qdf_mem_copy(discon_req, req, sizeof(*req)); + msg.bodyptr = discon_req; + msg.type = CM_DISCONNECT_REQ; + + status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err(CM_PREFIX_FMT "msg post fail", + CM_PREFIX_REF(req->req.vdev_id, req->cm_id)); + qdf_mem_free(discon_req); + } + return status; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void cm_disconnect_diag_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + WLAN_HOST_DIAG_EVENT_DEF(connect_status, + host_event_wlan_status_payload_type); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + qdf_mem_zero(&connect_status, + sizeof(host_event_wlan_status_payload_type)); + qdf_mem_copy(&connect_status, + &mlme_obj->cfg.sta.event_payload, + sizeof(host_event_wlan_status_payload_type)); + + connect_status.rssi = mlme_obj->cfg.sta.current_rssi; + connect_status.eventId = DIAG_WLAN_STATUS_DISCONNECT; + if (rsp->req.req.reason_code == REASON_MIC_FAILURE) { + connect_status.reason = DIAG_REASON_MIC_ERROR; + } else if (rsp->req.req.source == CM_PEER_DISCONNECT) { + switch (rsp->req.req.reason_code) { + case REASON_PREV_AUTH_NOT_VALID: + case REASON_CLASS2_FRAME_FROM_NON_AUTH_STA: + case REASON_DEAUTH_NETWORK_LEAVING: + connect_status.reason = DIAG_REASON_DEAUTH; + break; + default: + connect_status.reason = DIAG_REASON_DISASSOC; + break; + } + connect_status.reasonDisconnect = rsp->req.req.reason_code; + } else if (rsp->req.req.source == CM_SB_DISCONNECT) { + connect_status.reason = DIAG_REASON_DEAUTH; + connect_status.reasonDisconnect = rsp->req.req.reason_code; + } else { + connect_status.reason = DIAG_REASON_USER_REQUESTED; + } + + WLAN_HOST_DIAG_EVENT_REPORT(&connect_status, + EVENT_WLAN_STATUS_V2); +} +#else +static inline void cm_disconnect_diag_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{} +#endif + +QDF_STATUS +cm_disconnect_complete_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + enum QDF_OPMODE op_mode; + + if (!vdev || !rsp) { + mlme_err("vdev or rsp is NULL"); + return QDF_STATUS_E_INVAL; + } + cm_csr_disconnect_done_ind(vdev, rsp); + + vdev_id = wlan_vdev_get_id(vdev); + op_mode = wlan_vdev_mlme_get_opmode(vdev); + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err(CM_PREFIX_FMT "pdev not found", + CM_PREFIX_REF(vdev_id, rsp->req.cm_id)); + return QDF_STATUS_E_INVAL; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err(CM_PREFIX_FMT "psoc not found", + CM_PREFIX_REF(vdev_id, rsp->req.cm_id)); + return QDF_STATUS_E_INVAL; + } + cm_cp_stats_cstats_disconn_resp_event(vdev, rsp); + + cm_disconnect_diag_event(vdev, rsp); + wlan_tdls_notify_sta_disconnect(vdev_id, false, false, vdev); + policy_mgr_decr_session_set_pcl(psoc, op_mode, vdev_id); + if (rsp->req.req.source != CM_MLO_LINK_SWITCH_DISCONNECT) { + wlan_clear_mlo_sta_link_removed_flag(vdev); + ml_nlink_conn_change_notify( + psoc, vdev_id, ml_nlink_disconnect_completion_evt, + NULL); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_send_vdev_down_req(struct wlan_objmgr_vdev *vdev) +{ + struct del_bss_resp *resp; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) + return QDF_STATUS_E_NOMEM; + + resp->status = QDF_STATUS_SUCCESS; + resp->vdev_id = wlan_vdev_get_id(vdev); + return wlan_vdev_mlme_sm_deliver_evt(vdev, + WLAN_VDEV_SM_EV_MLME_DOWN_REQ, + sizeof(*resp), resp); +} + +QDF_STATUS cm_disconnect(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum wlan_cm_source source, + enum wlan_reason_code reason_code, + struct qdf_mac_addr *bssid) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev_id: %d: vdev not found", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wlan_cm_disconnect(vdev, source, reason_code, bssid); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +QDF_STATUS cm_send_sb_disconnect_req(struct scheduler_msg *msg) +{ + struct cm_vdev_discon_ind *ind; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + ind = msg->bodyptr; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(ind->psoc, + ind->disconnect_param.vdev_id, + WLAN_MLME_CM_ID); + + if (!vdev) { + mlme_err("vdev_id: %d: vdev not found", + ind->disconnect_param.vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wlan_mlo_mgr_link_switch_defer_disconnect_req(vdev, + ind->disconnect_param.source, + ind->disconnect_param.reason_code); + if (QDF_IS_STATUS_ERROR(status)) { + status = mlo_disconnect(vdev, ind->disconnect_param.source, + ind->disconnect_param.reason_code, + &ind->disconnect_param.bssid); + } + + qdf_mem_free(ind); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +static void cm_copy_peer_disconnect_ies(struct wlan_objmgr_vdev *vdev, + struct element_info *ap_ie) +{ + struct element_info *discon_ie; + + discon_ie = mlme_get_peer_disconnect_ies(vdev); + if (!discon_ie) + return; + + ap_ie->len = discon_ie->len; + ap_ie->ptr = discon_ie->ptr; +} + +#ifdef WLAN_FEATURE_HOST_ROAM +static inline +QDF_STATUS cm_fill_disconnect_resp(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *resp) +{ + struct wlan_cm_vdev_reassoc_req req; + + /* Fill from reassoc req for Handsoff disconnect */ + if (cm_get_active_reassoc_req(vdev, &req)) { + resp->req.cm_id = req.cm_id; + resp->req.req.vdev_id = req.vdev_id; + qdf_copy_macaddr(&resp->req.req.bssid, &req.prev_bssid); + resp->req.req.source = CM_ROAM_DISCONNECT; + } else if (!cm_get_active_disconnect_req(vdev, &resp->req)) { + /* If not reassoc then fill from disconnect active */ + return QDF_STATUS_E_FAILURE; + } + mlme_debug(CM_PREFIX_FMT "disconnect found source %d", + CM_PREFIX_REF(resp->req.req.vdev_id, resp->req.cm_id), + resp->req.req.source); + + return QDF_STATUS_SUCCESS; +} +#else +static inline +QDF_STATUS cm_fill_disconnect_resp(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *resp) +{ + if (!cm_get_active_disconnect_req(vdev, &resp->req)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS cm_handle_disconnect_resp(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct cm_vdev_disconnect_rsp *ind; + struct wlan_cm_discon_rsp resp; + struct wlan_objmgr_vdev *vdev; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + ind = msg->bodyptr; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(ind->psoc, ind->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev_id: %d : vdev not found", ind->vdev_id); + qdf_mem_free(ind); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_zero(&resp, sizeof(resp)); + status = cm_fill_disconnect_resp(vdev, &resp); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Active disconnect not found for vdev %d", + ind->vdev_id); + qdf_mem_free(ind); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_FAILURE; + } + + if (resp.req.req.source == CM_PEER_DISCONNECT) + cm_copy_peer_disconnect_ies(vdev, &resp.ap_discon_ie); + + status = wlan_cm_disconnect_rsp(vdev, &resp); + mlme_free_peer_disconnect_ies(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + qdf_mem_free(ind); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +wlan_cm_mlo_update_disconnecting_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id) +{ + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_objmgr_vdev *vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {NULL}; + uint16_t num_links = 0, i = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, *vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev_id: %d vdev not found", *vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + status = QDF_STATUS_SUCCESS; + goto done; + } + + /* + * During the link vdev disconnection the RSO stop vdev id will be of + * assoc vdev (changed during cm_handle_mlo_rso_state_change), So try + * to get the link vdev on which disconnect was actually happening i.e + * the one with active disconnecting state from the mlo links, so that + * continue disconnect is initiated on a proper vdev in connection + * manager. + */ + mlo_get_ml_vdev_list(vdev, &num_links, vdev_list); + if (!num_links) { + mlme_err("No VDEVs under vdev id: %d", *vdev_id); + status = QDF_STATUS_E_NULL_VALUE; + goto done; + } + + if (num_links > QDF_ARRAY_SIZE(vdev_list)) { + mlme_err("Invalid number of VDEVs num_links:%u", num_links); + status = QDF_STATUS_E_INVAL; + goto release_mlo_ref; + } + + for (i = 0; i < num_links; i++) { + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev_list[i]) && + (wlan_cm_is_vdev_disconnecting(vdev_list[i]) || + wlan_cm_is_vdev_connecting(vdev_list[i])) && + wlan_cm_get_active_req_type(vdev_list[i]) == + CM_DISCONNECT_ACTIVE) { + /* + * This is expected to match only once as per current + * design. + */ + *vdev_id = wlan_vdev_get_id(vdev_list[i]); + break; + } + } + +release_mlo_ref: + for (i = 0; i < num_links; i++) + mlo_release_vdev_ref(vdev_list[i]); + +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} +#else +static QDF_STATUS +wlan_cm_mlo_update_disconnecting_vdev_id(struct wlan_objmgr_psoc *psoc, + uint8_t *vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +QDF_STATUS +wlan_cm_rso_stop_continue_disconnect(struct wlan_objmgr_psoc *psoc, + uint8_t rso_stop_vdev_id, bool is_ho_fail) +{ + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_cm_vdev_discon_req *req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = rso_stop_vdev_id; + + wlan_cm_mlo_update_disconnecting_vdev_id(psoc, &vdev_id); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev_id: %d vdev not found", vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto done; + } + + if (!cm_get_active_disconnect_req(vdev, req)) { + mlme_err("vdev: %d: Active disconnect not found", vdev_id); + status = QDF_STATUS_E_EXISTS; + goto done; + } + + if (is_ho_fail) { + req->req.source = CM_MLME_DISCONNECT; + req->req.reason_code = REASON_FW_TRIGGERED_ROAM_FAILURE; + mlme_debug(CM_PREFIX_FMT "Updating source(%d) and reason code (%d) to RSO reason and source as ho fail is received in RSO stop", + CM_PREFIX_REF(req->req.vdev_id, req->cm_id), + req->req.source, req->req.reason_code); + } + wlan_cm_disc_cont_after_rso_stop(vdev, req); + +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + qdf_mem_free(req); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h new file mode 100644 index 0000000000..621aa16533 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_api.h @@ -0,0 +1,2323 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_api.h + * + * Implementation for the Common Roaming interfaces. + */ + +#ifndef WLAN_CM_ROAM_API_H__ +#define WLAN_CM_ROAM_API_H__ + +#include "wlan_mlme_dbg.h" +#include "../../core/src/wlan_cm_roam_offload.h" +#include "wlan_mlme_main.h" +#include "wlan_mlme_api.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_cm_tgt_if_tx_api.h" +#include "wlan_connectivity_logging.h" + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * wlan_cm_enable_roaming_on_connected_sta() - Enable roaming on other connected + * sta vdev + * @pdev: pointer to pdev object + * @vdev_id: vdev id on which roaming should not be enabled + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * wlan_cm_roam_send_rso_cmd() - send rso command + * @psoc: psoc pointer + * @vdev_id: vdev id + * @rso_command: roam command to send + * @reason: reason for changing roam state for the requested vdev id + * + * similar to csr_roam_offload_scan, will be used from many legacy + * process directly, generate a new function wlan_cm_roam_send_rso_cmd + * for external usage. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t rso_command, + uint8_t reason); + +/** + * wlan_cm_handle_sta_sta_roaming_enablement() - Handle roaming in case + * of STA + STA + * @psoc: psoc common object + * @vdev_id: Vdev id + * + * Wrapper function to cm_handle_sta_sta_roaming_enablement + * + * Return: none + */ +void wlan_cm_handle_sta_sta_roaming_enablement(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_roam_state_change() - Post roam state change to roam state machine + * @pdev: pdev pointer + * @vdev_id: vdev id + * @requested_state: roam state to be set + * @reason: reason for changing roam state for the requested vdev id + * + * This function posts roam state change to roam state machine handling + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_roam_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state requested_state, + uint8_t reason); + +/** + * wlan_roam_update_cfg() - Process RSO update cfg request + * @psoc: psoc context + * @vdev_id: vdev id + * @reason: reason for requesting RSO update cfg + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_roam_update_cfg(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason); + +/** + * wlan_cm_send_beacon_miss() - initiate beacon miss + * @vdev_id: vdev id + * @rssi: AP rssi + * + * Return: void + */ +void wlan_cm_send_beacon_miss(uint8_t vdev_id, int32_t rssi); + +#else +static inline +QDF_STATUS wlan_cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t rso_command, + uint8_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +wlan_cm_handle_sta_sta_roaming_enablement(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ +} + +static inline QDF_STATUS +wlan_roam_update_cfg(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS wlan_cm_roam_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state requested_state, + uint8_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_cm_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * cm_update_associated_ch_info() - to save channel info in mlme priv obj at + * the time of initial connection + * @vdev: Pointer to vdev + * @is_update: to distinguish whether update is during connection or + * disconnection + * + * Return: none + */ +void +cm_update_associated_ch_info(struct wlan_objmgr_vdev *vdev, bool is_update); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define wlan_is_roam_offload_enabled(lfr) \ + (lfr.lfr3_roaming_offload) +#else +#define wlan_is_roam_offload_enabled(lfr) false +#endif + +/** + * wlan_cm_host_roam_in_progress() -Check if STA is in the middle of + * roaming states + * @psoc: psoc + * @vdev_id: vdev id + * + * Return: True or False + */ +bool wlan_cm_host_roam_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * cm_roam_acquire_lock() - Wrapper for rso lock. + * @vdev: Pointer to vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_acquire_lock(struct wlan_objmgr_vdev *vdev); + +/** + * cm_roam_release_lock() - Wrapper for rso lock + * @vdev: Pointer to vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_release_lock(struct wlan_objmgr_vdev *vdev); + +/** + * cm_roam_get_requestor_string() - RSO control requestor to string api + * @requestor: Requestor of type enum wlan_cm_rso_control_requestor + * + * Return: Pointer to converted string + */ +char +*cm_roam_get_requestor_string(enum wlan_cm_rso_control_requestor requestor); + +/** + * wlan_cm_rso_set_roam_trigger() - Send roam trigger bitmap firmware + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @trigger_data: Carries pointer of the object containing vdev id and + * roam_trigger_bitmap. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct wlan_roam_triggers *trigger_data); + +/** + * wlan_cm_disable_rso() - Disable roam scan offload to firmware + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @requestor: RSO disable requestor + * @reason: Reason for RSO disable + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_disable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + enum wlan_cm_rso_control_requestor requestor, + uint8_t reason); + +/** + * wlan_cm_enable_rso() - Enable roam scan offload to firmware + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @requestor: RSO disable requestor + * @reason: Reason for RSO disable + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_enable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + enum wlan_cm_rso_control_requestor requestor, + uint8_t reason); + +/** + * wlan_cm_roaming_in_progress() - check if roaming is in progress + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: true or false + */ +bool +wlan_cm_roaming_in_progress(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * wlan_cm_roam_stop_req() - roam stop request handling + * @psoc: psoc pointer + * @vdev_id: vdev id + * @reason: reason for changing roam state for the requested vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason); + +/** + * wlan_cm_roam_cfg_get_value - Get RSO config value from mlme vdev private + * object + * @psoc: psoc pointer + * @vdev_id: vdev id + * @roam_cfg_type: Value needed + * @dst_config: Destination config + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_roam_cfg_get_value(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum roam_cfg_param roam_cfg_type, + struct cm_roam_values_copy *dst_config); + +static inline void +wlan_cm_flush_roam_channel_list(struct rso_chan_info *channel_info) +{ + cm_flush_roam_channel_list(channel_info); +} + +/** + * wlan_cm_roam_cfg_set_value - Set RSO config value + * @psoc: psoc pointer + * @vdev_id: vdev id + * @roam_cfg_type: Roam configuration type to set + * @src_config: Source config + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_roam_cfg_set_value(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_cfg_param roam_cfg_type, + struct cm_roam_values_copy *src_config); + + +struct rso_config *wlan_cm_get_rso_config_fl(struct wlan_objmgr_vdev *vdev, + const char *func, uint32_t line); + +struct rso_user_config * +wlan_cm_get_rso_user_config_fl(struct wlan_objmgr_vdev *vdev, + const char *func, uint32_t line); +/** + * wlan_cm_get_rso_config - get per vdev RSO config + * @vdev: vdev pointer + * + * Return: rso config pointer + */ +#define wlan_cm_get_rso_config(vdev) \ + wlan_cm_get_rso_config_fl(vdev, __func__, __LINE__) + +/** + * wlan_cm_get_rso_user_config - get per vdev RSO userspace config + * @vdev: vdev pointer + * + * Return: rso user space config pointer + */ +#define wlan_cm_get_rso_user_config(vdev) \ + wlan_cm_get_rso_user_config_fl(vdev, __func__, __LINE__) +/** + * wlan_cm_set_disable_hi_rssi - set disable hi rssi config + * @pdev: pdev pointer + * @vdev_id: vdev id + * @value: value to set + * + * Return: void + */ +void wlan_cm_set_disable_hi_rssi(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, bool value); + +/** + * wlan_cm_set_country_code - set country code to vdev rso config + * @pdev: pdev pointer + * @vdev_id: vdev id + * @cc: country code + * + * Return: void + */ +void wlan_cm_set_country_code(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *cc); + +/** + * wlan_cm_get_country_code - get country code from vdev rso config + * @pdev: pdev pointer + * @vdev_id: vdev id + * @cc: country code + * + * Return: qdf status + */ +QDF_STATUS wlan_cm_get_country_code(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *cc); + +#ifdef FEATURE_WLAN_ESE +/** + * wlan_cm_set_ese_assoc - set ese assoc + * @pdev: pdev pointer + * @vdev_id: vdev + * @value: value to set + * + * Return: void + */ +void wlan_cm_set_ese_assoc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, bool value); + +/** + * wlan_cm_get_ese_assoc - get ese assoc + * @pdev: pdev pointer + * @vdev_id: vdev + * + * Return: value + */ +bool wlan_cm_get_ese_assoc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); +void wlan_cm_ese_populate_additional_ies(struct wlan_objmgr_pdev *pdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + uint8_t vdev_id, + struct wlan_roam_scan_offload_params *rso_mode_cfg); +#else +static inline void wlan_cm_set_ese_assoc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, bool value) {} +static inline +bool wlan_cm_get_ese_assoc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + return false; +} +static inline void wlan_cm_ese_populate_additional_ies( + struct wlan_objmgr_pdev *pdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + uint8_t vdev_id, + struct wlan_roam_scan_offload_params *rso_mode_cfg) +{} +#endif + +/** + * wlan_roam_reset_roam_params - reset_roam params + * @vdev: vdev pointer + * + * Return: void + */ +void wlan_roam_reset_roam_params(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cm_rso_config_init - initialize RSO config + * @vdev: vdev pointer + * @rso_cfg: rso config to init + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_rso_config_init(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg); + +/** + * wlan_cm_rso_config_deinit - deinit RSO config + * @vdev: vdev pointer + * @rso_cfg: rso config to deinit + * + * Return: void + */ +void wlan_cm_rso_config_deinit(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg); + +/** + * wlan_cm_fill_crypto_filter_from_vdev() - fill scan filter crypto from vdev + * given vdev id + * @vdev: vdev + * @filter: filetr to fill + * + * Return: void + */ +void wlan_cm_fill_crypto_filter_from_vdev(struct wlan_objmgr_vdev *vdev, + struct scan_filter *filter); + +/** + * wlan_cm_init_occupied_ch_freq_list - init occupied chan freq list + * @pdev: pdev pointer + * @psoc: psoc + * @vdev_id: vdev_id of vdev for which init is required + * + * Return: void + */ +void wlan_cm_init_occupied_ch_freq_list(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +uint32_t cm_crypto_authmode_to_wmi_authmode(int32_t authmodeset, + int32_t akm, + int32_t ucastcipherset); +uint8_t *wlan_cm_get_rrm_cap_ie_data(void); + +/** + * wlan_cm_append_assoc_ies() - Append specific IE to assoc IE's buffer + * @rso_mode_cfg: Pointer to Roam offload scan request + * @ie_id: IE ID to be appended + * @ie_len: IE length to be appended + * @ie_data: IE data to be appended + * + * Return: None + */ +void wlan_cm_append_assoc_ies(struct wlan_roam_scan_offload_params *rso_mode_cfg, + uint8_t ie_id, uint8_t ie_len, + const uint8_t *ie_data); +/** + * wlan_add_supported_5Ghz_channels()- Add valid 5Ghz channels + * in Join req. + * @psoc: psoc ptr + * @pdev: pdev + * @chan_list: Pointer to channel list buffer to populate + * @num_chnl: Pointer to number of channels value to update + * @supp_chan_ie: Boolean to check if we need to populate as IE + * + * This function is called to update valid 5Ghz channels + * in Join req. If @supp_chan_ie is true, supported channels IE + * format[chan num 1, num of channels 1, chan num 2, num of + * channels 2, ..] is populated. Else, @chan_list would be a list + * of supported channels[chan num 1, chan num 2..] + * + * Return: void + */ +void wlan_add_supported_5Ghz_channels(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t *chan_list, + uint8_t *num_chnl, + bool supp_chan_ie); +#ifdef WLAN_ADAPTIVE_11R +/** + * wlan_get_adaptive_11r_enabled() - Function to check if adaptive 11r + * ini is enabled or disabled + * @lfr_cfg: LFR configuration + * + * Return: true if adaptive 11r is enabled + */ +static inline bool +wlan_get_adaptive_11r_enabled(struct wlan_mlme_lfr_cfg *lfr_cfg) +{ + return lfr_cfg->enable_adaptive_11r; +} +#else +static inline bool +wlan_get_adaptive_11r_enabled(struct wlan_mlme_lfr_cfg *lfr_cfg) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +/** + * wlan_cm_get_fils_connection_info - Copy fils connection information from + * mlme vdev private object + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +struct wlan_fils_connection_info *wlan_cm_get_fils_connection_info( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_update_mlme_fils_info - Update FILS connection info + * to mlme vdev private object + * @vdev: Pointer to pdev object + * @src_fils_info: Current profile FILS connection information + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_update_mlme_fils_info(struct wlan_objmgr_vdev *vdev, + struct wlan_fils_con_info *src_fils_info); + +/** + * wlan_cm_update_fils_ft - Update the FILS FT derived to mlme + * @psoc: Psoc pointer + * @vdev_id: vdev id + * @fils_ft: Pointer to FILS FT + * @fils_ft_len: FILS FT length + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_update_fils_ft(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *fils_ft, + uint8_t fils_ft_len); + +/** + * wlan_cm_update_hlp_info - API to save HLP IE + * @psoc: Pointer to psoc + * @gen_ie: IE buffer to store + * @len: length of the IE buffer @gen_ie + * @vdev_id: vdev id + * @flush: Flush the older saved HLP if any + * + * Return: None + */ +void wlan_cm_update_hlp_info(struct wlan_objmgr_psoc *psoc, + const uint8_t *gen_ie, uint16_t len, + uint8_t vdev_id, bool flush); +#else +static inline +struct wlan_fils_connection_info *wlan_cm_get_fils_connection_info( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return NULL; +} + +static inline void wlan_cm_update_hlp_info(struct wlan_objmgr_psoc *psoc, + const uint8_t *gen_ie, uint16_t len, + uint8_t vdev_id, bool flush) +{} +#endif + +static inline +bool wlan_cm_is_auth_type_11r(struct wlan_mlme_psoc_ext_obj *mlme_obj, + struct wlan_objmgr_vdev *vdev, + bool mdie_present) +{ + return cm_is_auth_type_11r(mlme_obj, vdev, mdie_present); +} + +static inline bool cm_is_open_mode(struct wlan_objmgr_vdev *vdev) +{ + return wlan_vdev_is_open_mode(vdev); +} + +#ifdef WLAN_FEATURE_SAE +/** + * cm_is_auth_type_sae() - is vdev SAE auth type + * @vdev: pointer to vdev + * + * Return: true if vdev is SAE auth type + */ +static inline bool cm_is_auth_type_sae(struct wlan_objmgr_vdev *vdev) +{ + return wlan_vdev_is_sae_auth_type(vdev); +} +#else +static inline bool cm_is_auth_type_sae(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif + +#ifdef FEATURE_WLAN_ESE +bool +cm_ese_open_present(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + bool ese_version_present); +bool +cm_is_ese_connection(struct wlan_objmgr_vdev *vdev, bool ese_version_present); +#else +static inline bool +cm_ese_open_present(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + bool ese_version_present) +{ + return false; +} +static inline bool +cm_is_ese_connection(struct wlan_objmgr_vdev *vdev, bool ese_version_present) +{ + return false; +} +#endif + +/** + * cm_roam_start_init_on_connect() - init roaming + * @pdev: pdev pointer + * @vdev_id: vdev_id + * + * Return: void + */ +void cm_roam_start_init_on_connect(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +void cm_update_session_assoc_ie(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct element_info *assoc_ie); + +/** + * wlan_cm_roam_invoke() - Validate and send Roam invoke req to CM + * @pdev: Pdev pointer + * @vdev_id: vdev_id + * @bssid: Target bssid + * @chan_freq: channel frequency on which reassoc should be send + * @source: source of roam + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct qdf_mac_addr *bssid, qdf_freq_t chan_freq, + enum wlan_cm_source source); + +/** + * cm_is_fast_roam_enabled() - check fast roam enabled or not + * @psoc: psoc pointer + * + * Return: true or false + */ +bool cm_is_fast_roam_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * cm_is_rsn_or_8021x_sha256_auth_type() - check whether auth type is rsn + * or 8021x_sha256 or not + * @vdev: vdev object pointer + * + * Return: true, if auth type is rsn/8021x_sha256, false otherwise + */ +bool cm_is_rsn_or_8021x_sha256_auth_type(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * wlan_cm_host_roam_start() - fw host roam start handler + * @msg: msg pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg); + +/** + * cm_mlme_roam_preauth_fail() - roam preauth fail + * @vdev: VDEV object + * @req: Connection manager roam request + * @reason: connection manager connect fail reason + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_mlme_roam_preauth_fail(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_roam_req *req, + enum wlan_cm_connect_fail_reason reason); + +/** + * cm_free_preauth_req() - free preauth request related memory + * @preauth_req: preauth request + * + * Return: void + */ +void cm_free_preauth_req(struct wlan_preauth_req *preauth_req); + +/** + * cm_handle_preauth_rsp() - Process vdev preauth rsp and send to CM + * @msg: scheduler message + * + * Process preauth rsp and send it to CM SM. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_handle_preauth_rsp(struct scheduler_msg *msg); + +/** + * cm_reassoc_timer_callback() - reassoc timer callback, gets called at time out + * @context: context + * + * Timer callback for the timer that is started between the preauth completion + * and reassoc request. In this interval, it is expected that the + * pre-auth response and RIC IEs are passed up to the WPA supplicant and + * received back the necessary FTIEs required to be sent in the reassoc request + * + * Return: None + */ +void cm_reassoc_timer_callback(void *context); +#else +static inline QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg) +{ + if (msg && msg->bodyptr) + qdf_mem_free(msg->bodyptr); + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_cm_get_associated_ch_info() - get associated channel info + * @psoc: psoc pointer + * @vdev_id: vdev id + * @scanned_ch_width: channel width as per scan response + * @assoc_chan_info: channel info to get + * + * Return: none + */ +void wlan_cm_get_associated_ch_info(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width scanned_ch_width, + struct assoc_channel_info *assoc_chan_info); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_cm_fw_roam_abort_req() - roam abort request handling + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_fw_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * wlan_cm_get_roam_band_value - Get roam band value from RSO config + * @psoc: psoc pointer + * @vdev: Pointer to vdev + * + * Return: Roam Band + */ +uint32_t wlan_cm_get_roam_band_value(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cm_roam_activate_pcl_per_vdev() - Set the PCL command to be sent per + * vdev instead of pdev. + * @psoc: PSOC pointer + * @vdev_id: VDEV id + * @pcl_per_vdev: Activate vdev PCL type. 1- VDEV PCL, 0- PDEV PCL + * + * pcl_per_vdev will be set when: + * STA + STA is connected in DBS mode and roaming init is done on + * the 2nd STA. + * + * pcl_per_vdev will be false when only 1 sta connection exists or + * when 2nd sta gets disconnected + * + * Return: None + */ +void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool pcl_per_vdev); + +/** + * wlan_cm_roam_is_pcl_per_vdev_active() - API to know if the pcl command needs + * to be sent per vdev or not + * @psoc: PSOC pointer + * @vdev_id: VDEV id + * + * Return: PCL level + */ +bool wlan_cm_roam_is_pcl_per_vdev_active(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_dual_sta_roam_update_connect_channels() - Fill the allowed channels + * for connection of the 2nd STA based on the 1st STA connected band if dual + * sta roaming is enabled. + * @psoc: Pointer to PSOC object + * @filter: Pointer to scan filter + * + * Return: None + */ +void +wlan_cm_dual_sta_roam_update_connect_channels(struct wlan_objmgr_psoc *psoc, + struct scan_filter *filter); +/** + * wlan_cm_roam_set_vendor_btm_params() - API to set vendor btm params + * @psoc: PSOC pointer + * @param: vendor configured roam trigger param + * + * Return: none + */ +void +wlan_cm_roam_set_vendor_btm_params(struct wlan_objmgr_psoc *psoc, + struct wlan_cm_roam_vendor_btm_params + *param); +/** + * wlan_cm_roam_get_vendor_btm_params() - API to get vendor btm param + * @psoc: PSOC pointer + * @param: vendor configured roam trigger param + * + * Return: none + */ +void wlan_cm_roam_get_vendor_btm_params( + struct wlan_objmgr_psoc *psoc, + struct wlan_cm_roam_vendor_btm_params *param); + +/** + * wlan_cm_roam_get_score_delta_params() - API to get roam score delta param + * @psoc: PSOC pointer + * @params: roam trigger param + * + * Return: none + */ +void +wlan_cm_roam_get_score_delta_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_triggers *params); + +/** + * wlan_cm_roam_get_min_rssi_params() - API to get roam trigger min rssi param + * @psoc: PSOC pointer + * @params: roam trigger param + * + * Return: none + */ +void +wlan_cm_roam_get_min_rssi_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_triggers *params); + +/** + * wlan_cm_update_roam_scan_scheme_bitmap() - Set roam scan scheme bitmap for + * each vdev + * @psoc: PSOC pointer + * @vdev_id: VDEV id + * @roam_scan_scheme_bitmap: bitmap of roam triggers for which partial roam + * scan needs to be enabled + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_update_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_scan_scheme_bitmap); + +/** + * wlan_cm_set_roam_band_bitmask() - Set roam band bitmask for vdev + * @psoc: psoc pointer + * @vdev_id: vdev id + * @roam_band_bitmask: bitmask of roam band for which roam scan needs to be + * enabled in fw + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_set_roam_band_bitmask(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_band_bitmask); + +/** + * wlan_cm_set_btm_config() - Set btm roaming disable flag for vdev + * @psoc: psoc pointer + * @vdev_id: vdev id + * @is_disable_btm: to check whether btm roaming is disabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_set_btm_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_disable_btm); + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * struct roam_link_speed_cfg - link speed state config + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @is_link_speed_good: true means link speed good, false means bad + */ +struct roam_link_speed_cfg { + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + uint8_t is_link_speed_good; +}; + +/** + * wlan_cm_send_roam_linkspeed_state() - Send link speed state to target + * @msg: Pointer to schedule message + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_send_roam_linkspeed_state(struct scheduler_msg *msg); + +/** + * wlan_cm_roam_link_speed_update() - Update link speed state for roaming + * @psoc: psoc pointer + * @vdev_id: vdev id + * @is_link_speed_good: true means link speed good, false means bad + * + * Return: None + */ +void wlan_cm_roam_link_speed_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good); + +/** + * wlan_cm_is_linkspeed_roam_trigger_supported() - Get roam linkspeed check + * @psoc: pointer to psoc object + * + * Return: bool, true: Linkspeed check for low rssi roaming supported + */ +bool wlan_cm_is_linkspeed_roam_trigger_supported(struct wlan_objmgr_psoc *psoc); +#endif + +/** + * wlan_cm_set_roam_band_update() - send rso update on set band + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_set_roam_band_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_get_roam_scan_scheme_bitmap() - Get roam scan scheme bitmap value + * @psoc: PSOC pointer + * @vdev_id: VDEV id + * + * Return: Roam scan scheme bitmap value + */ +uint32_t wlan_cm_get_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_update_roam_states() - Set roam states for the vdev + * @psoc: PSOC pointer + * @vdev_id: VDEV id + * @value: Value to update + * @states: type of value to update + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_update_roam_states(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t value, enum roam_fail_params states); + +/** + * wlan_cm_get_roam_states() - Get roam states value + * @psoc: PSOC pointer + * @vdev_id: VDEV id + * @states: For which action get roam states + * + * Return: Roam fail reason value + */ +uint32_t +wlan_cm_get_roam_states(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_fail_params states); + +void wlan_cm_set_psk_pmk(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t pmk_len); + +void wlan_cm_get_psk_pmk(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t *pmk_len); + +/** + * cm_akm_roam_allowed() - check if roam allowed for some akm type + * roaming using single pmk + * with same pmk or not + * @psoc: psoc + * @vdev: vdev pointer + * + * Return: QDF_STATUS: QDF_STATUS_SUCCESS is allowed + */ +QDF_STATUS +cm_akm_roam_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * cm_invalid_roam_reason_handler() - Handler for invalid roam reason + * @vdev_id: vdev id + * @notif: roam notification of type enum cm_roam_notif + * @reason: Notif param value from the roam event that carries trigger reason + * + * Return: QDF_STATUS + */ +void cm_invalid_roam_reason_handler(uint32_t vdev_id, enum cm_roam_notif notif, + uint32_t reason); + +/** + * cm_handle_roam_reason_ho_failed() - Handler for roam due to ho failure + * @vdev_id: vdev id + * @bssid: carries the BSSID mac address + * @hw_mode_trans_ind: hw_mode transition indication + * + * Return: None + */ +void +cm_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind); + +/** + * cm_handle_scan_ch_list_data() - Roam scan ch evt wrapper for wma + * @data: roam scan channel event data + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp *data); + +/** + * wlan_cm_free_roam_synch_frame_ind() - Free the bcn_probe_rsp, reassoc_req, + * reassoc_rsp received as part of the ROAM_SYNC_FRAME event + * + * @rso_cfg: RSO configuration to be freed + * + * This API is used to free the buffer allocated during the ROAM_SYNC_FRAME + * event + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_free_roam_synch_frame_ind(struct rso_config *rso_cfg); + +/** + * cm_roam_sync_event_handler() - CM handler for roam sync event + * + * @psoc: psoc objmgr ptr + * @event: event ptr + * @len: event buff length + * @sync_ind: sync indication data + * + * This API is used to handle the buffer allocated during the ROAM_SYNC_EVENT + * event + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_sync_event_handler(struct wlan_objmgr_psoc *psoc, + uint8_t *event, + uint32_t len, + struct roam_offload_synch_ind *sync_ind); + +/** + * cm_roam_sync_frame_event_handler() - CM handler for roam sync frame event + * + * @psoc: psoc objmgr ptr + * @frame_ind: ptr to roam sync frame struct + * + * This API is used to handle the buffer allocated during the ROAM_SYNC_FRAME + * event + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_sync_frame_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_synch_frame_ind *frame_ind); + +/** + * cm_roam_sync_event_handler_cb() - CM callback handler for roam + * sync event + * + * @vdev: vdev objmgr ptr + * @event: event ptr + * @len: event data len + * + * This API is used to handle the buffer allocated during the ROAM_SYNC + * event + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_sync_event_handler_cb(struct wlan_objmgr_vdev *vdev, + uint8_t *event, + uint32_t len); + +/** + * wlan_cm_update_roam_rt_stats() - Store roam event stats command params + * @psoc: PSOC pointer + * @value: Value to update + * @stats: type of value to update + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_update_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t value, enum roam_rt_stats_params stats); + +/** + * wlan_cm_get_roam_rt_stats() - Get roam event stats value + * @psoc: PSOC pointer + * @stats: Get roam event command param for specific attribute + * + * Return: Roam events stats param value + */ +uint8_t +wlan_cm_get_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + enum roam_rt_stats_params stats); + +/** + * cm_report_roam_rt_stats - Gathers/Sends the roam events stats + * @psoc: Pointer to psoc structure + * @vdev_id: Vdev ID + * @events: Event/Notif type from roam event/roam stats event + * @roam_info: Roam stats from the roam stats event + * @value: Notif param value from the roam event + * @idx: TLV index in roam stats event + * @reason: Notif param value from the roam event that carries trigger reason + * + * Gathers the roam stats from the roam event and the roam stats event and + * sends them to hdd for filling the vendor attributes. + * + * Return: none + */ +void cm_report_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum roam_rt_stats_type events, + struct roam_stats_event *roam_info, + uint32_t value, uint8_t idx, uint32_t reason); +/** + * cm_roam_candidate_event_handler() - CM callback to save roam + * candidate entry in scan db + * + * @psoc: psoc objmgr ptr + * @candidate: roam scan candidate info + */ +QDF_STATUS +cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate); + +/** + * wlan_cm_is_roam_sync_in_progress() - Check if the vdev is in roam sync + * substate + * @psoc: psoc pointer + * @vdev_id: vdev_id + * + * Return: bool + */ +bool wlan_cm_is_roam_sync_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_set_roam_offload_bssid() - Set the roam offload bssid of the sae + * roam candidate + * @vdev: pointer to vdev + * @bssid: bssid + * + * Return: None + */ +void +wlan_cm_set_roam_offload_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid); + +/** + * wlan_cm_get_roam_offload_bssid() - Get the roam offload bssid of the sae + * roam candidate + * @vdev: pointer to vdev + * @bssid: bssid + * + * Return: None + */ +void +wlan_cm_get_roam_offload_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid); + +/** + * wlan_cm_set_roam_offload_ssid() - Set the roam offload candidate ssid + * + * @vdev: pointer to vdev + * @ssid: ssid of candidate + * @len: length of ssid + * + * Return: None + */ +void +wlan_cm_set_roam_offload_ssid(struct wlan_objmgr_vdev *vdev, + uint8_t *ssid, uint8_t len); + +/** + * wlan_cm_get_roam_offload_ssid() - Get the roam offload candidate ssid + * + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @ssid: ssid of the candidate + * @len: length of the ssid + * + * Return: None + */ +void +wlan_cm_get_roam_offload_ssid(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t *ssid, uint8_t *len); + +/** + * wlan_cm_roam_set_ho_delay_config() - Set roam hand-off delay + * @psoc: PSOC pointer + * @roam_ho_delay: vendor configured roam HO delay value + * + * Return: none + */ +void +wlan_cm_roam_set_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint16_t roam_ho_delay); + +/** + * wlan_cm_roam_get_ho_delay_config() - Get roam hand-off delay + * @psoc: PSOC pointer + * + * Return: Roam HO delay value + */ +uint16_t +wlan_cm_roam_get_ho_delay_config(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_cm_set_exclude_rm_partial_scan_freq() - set value to include/exclude + * the partial scan channels in roam full scan. + * @psoc: PSOC pointer + * @exclude_rm_partial_scan_freq: Include/exclude the channels in roam full scan + * that are already scanned as part of partial scan. + * + * Return: none + */ +void +wlan_cm_set_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t exclude_rm_partial_scan_freq); + +/** + * wlan_cm_get_exclude_rm_partial_scan_freq() - Get value to include/exclude + * the partial scan channels in roam full scan. + * @psoc: PSOC pointer + * + * Return: value to include/exclude the partial scan channels in roam full scan + */ +uint8_t +wlan_cm_get_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_cm_roam_set_full_scan_6ghz_on_disc() - set value to include the 6 GHz + * channels in roam full scan only on prior discovery of any 6 GHz support in + * the environment. + * @psoc: PSOC pointer + * @roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full scan: + * 1 - Include only on prior discovery of any 6 GHz support in the environment + * 0 - Include all the supported 6 GHz channels by default + * + * Return: none + */ +void +wlan_cm_roam_set_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc, + uint8_t roam_full_scan_6ghz_on_disc); + +/** + * wlan_cm_roam_get_full_scan_6ghz_on_disc() - Get value to include the 6 GHz + * channels in roam full scan only on prior discovery of any 6 GHz support in + * the environment. + * @psoc: PSOC pointer + * + * Return: + * 1 - Include only on prior discovery of any 6 GHz support in the environment + * 0 - Include all the supported 6 GHz channels by default + */ +uint8_t wlan_cm_roam_get_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_cm_set_roam_scan_high_rssi_offset() - Set the delta change in high RSSI + * at which roam scan is triggered in 2.4/5 GHz. + * @psoc: PSOC pointer + * @roam_high_rssi_delta: Set the High RSSI delta for roam scan trigger + * * 1-16 - Set an offset value in this range + * * 0 - Disable + * + * Return: none + */ +void +wlan_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc, + uint8_t roam_high_rssi_delta); + +/** + * wlan_cm_get_roam_scan_high_rssi_offset() - Get the delta change in high RSSI + * at which roam scan is triggered in 2.4/5 GHz. + * @psoc: PSOC pointer + * + * Return: High RSSI delta for roam scan trigger + */ +uint8_t wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc); + +#ifdef WLAN_FEATURE_ROAM_INFO_STATS +/** + * mlme_cm_alloc_roam_stats_info() - alloc roam stats info buffer + * @vdev_mlme: MLME-private vdev context + * + * Return: None + */ +void mlme_cm_alloc_roam_stats_info(struct vdev_mlme_obj *vdev_mlme); + +/** + * mlme_cm_free_roam_stats_info() - free roam stats info buffer in + * struct mlme_legacy_priv + * @ext_hdl: mlme_legacy_priv pointer + * + * Return: None + */ +void mlme_cm_free_roam_stats_info(mlme_vdev_ext_t *ext_hdl); + +/** + * wlan_cm_roam_stats_info_get() - get vdev roam stats info + * + * @vdev: pointer to vdev + * @roam_info: pointer to buffer to copy roam stats info + * @roam_num: pointer to valid roam stats num + * + * Return: QDF_STATUS + */ + +QDF_STATUS +wlan_cm_roam_stats_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint32_t *roam_num); + +/** + * wlan_cm_roam_info_get() - get vdev roam info + * + * @vdev: pointer to vdev + * @roam_info: pointer to buffer to copy roam stats info + * @idx: index of roam stats cache buffer + * + * Return: QDF_STATUS + */ + +QDF_STATUS +wlan_cm_roam_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint8_t idx); + +#else +static inline +void mlme_cm_alloc_roam_stats_info(struct vdev_mlme_obj *vdev_mlme) +{ +} + +static inline +void mlme_cm_free_roam_stats_info(mlme_vdev_ext_t *ext_hdl) +{ +} +#endif + +/** + * wlan_cm_update_offload_ssid_from_candidate() - Set the roam offload ssid of + * the roam candidate into the mlme priv + * + * @pdev: pointer to pdev + * @vdev_id: vdev id + * @ap_bssid: roam candidate bssid + * + * Get the scan entry corresponding to the bssid and save the ssid + * in the mlme priv of the STA vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_update_offload_ssid_from_candidate(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *ap_bssid); + +/** + * wlan_cm_add_frame_to_scan_db() - Add the frame to scan db + * + * @psoc: PSOC pointer + * @frame: frame to be added to scan db + * + * Fetch the channel from frame and add the frame to scan db + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *frame); + +/** + * wlan_cm_add_all_link_probe_rsp_to_scan_db() - Parse and generate + * probe responses for each of the per-sta profile + * + * @psoc: psoc objmgr ptr + * @candidate: roam scan candidate info + */ +QDF_STATUS +wlan_cm_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate); + +/** + * wlan_cm_is_mbo_ap_without_pmf() - Check if the connected AP is MBO without + * PMF + * @psoc: PSOC pointer + * @vdev_id: vdev id + * + * Return: True if connected AP is MBO capable without PMF + */ +bool wlan_cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_roam_btm_block_event() - Send BTM block/drop logging event + * @vdev_id: vdev id + * @token: BTM token + * @reason: Reason for dropping the BTM frame + * + * This is wrapper for cm_roam_btm_block_event() + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_roam_btm_block_event(uint8_t vdev_id, uint8_t token, + enum wlan_diag_btm_block_reason reason); +#else +static inline +void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool pcl_per_vdev) +{} + +static inline +uint32_t wlan_cm_get_roam_band_value(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint32_t current_band; + + ucfg_reg_get_band(wlan_vdev_get_pdev(vdev), ¤t_band); + + return current_band; +} + +static inline +bool wlan_cm_roam_is_pcl_per_vdev_active(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline void +wlan_cm_dual_sta_roam_update_connect_channels(struct wlan_objmgr_psoc *psoc, + struct scan_filter *filter) +{} + +static inline QDF_STATUS +wlan_cm_roam_extract_btm_response(wmi_unified_t wmi, void *evt_buf, + struct roam_btm_response_data *dst, + uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_cm_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf, + struct roam_frame_info *dst, uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_cm_roam_extract_roam_initial_info(wmi_unified_t wmi, void *evt_buf, + struct roam_initial_data *dst, + uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_cm_roam_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf, + struct roam_msg_info *dst, uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +wlan_cm_roam_disable_vendor_btm(struct wlan_objmgr_psoc *psoc) +{} + +static inline void +wlan_cm_roam_set_vendor_btm_params(struct wlan_objmgr_psoc *psoc, + struct wlan_cm_roam_vendor_btm_params *param) +{} + +static inline void +wlan_cm_roam_get_score_delta_params(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct roam_trigger_score_delta *param) +{} + +static inline void +wlan_cm_roam_get_min_rssi_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_triggers *params) +{} + +static inline QDF_STATUS +wlan_cm_update_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_scan_scheme_bitmap) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_cm_set_roam_band_bitmask(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t roam_band_bitmask) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS wlan_cm_set_btm_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_disable_btm) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +uint32_t wlan_cm_get_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return 0; +} + +static inline QDF_STATUS +wlan_cm_update_roam_states(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t value, enum roam_fail_params states) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint32_t +wlan_cm_get_roam_states(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_fail_params states) +{ + return 0; +} + +static inline void wlan_cm_set_psk_pmk(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t pmk_len) +{} + +static inline QDF_STATUS +cm_akm_roam_allowed(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +cm_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind) +{} + +static inline QDF_STATUS +cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp *data) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_cm_update_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t value, enum roam_rt_stats_params stats) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t +wlan_cm_get_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + enum roam_rt_stats_params stats) +{ + return 0; +} + +static inline void +cm_report_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, enum roam_rt_stats_type events, + struct roam_stats_event *roam_info, + uint32_t value, uint8_t idx, uint32_t reason) +{} + +static inline QDF_STATUS +cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cm_roam_sync_event_handler(struct wlan_objmgr_psoc *psoc, + uint8_t *event, uint32_t len, + struct roam_offload_synch_ind *sync_ind) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +cm_roam_sync_frame_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_synch_frame_ind *frame_ind) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_cm_is_roam_sync_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline void +wlan_cm_set_roam_offload_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ +} + +static inline void +wlan_cm_get_roam_offload_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ +} + +static inline void +wlan_cm_set_roam_offload_ssid(struct wlan_objmgr_vdev *vdev, + uint8_t *ssid, uint8_t len) +{ +} + +static inline void +wlan_cm_get_roam_offload_ssid(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t *ssid, uint8_t *len) +{ +} + +static inline uint16_t +wlan_cm_roam_get_ho_delay_config(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint8_t +wlan_cm_get_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline uint8_t +wlan_cm_roam_get_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline +void mlme_cm_alloc_roam_stats_info(struct vdev_mlme_obj *vdev_mlme) +{ +} + +static inline +void mlme_cm_free_roam_stats_info(mlme_vdev_ext_t *ext_hdl) +{ +} + +static inline QDF_STATUS +wlan_cm_update_offload_ssid_from_candidate(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *ap_bssid) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *frame) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_cm_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t +wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline +bool wlan_cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline QDF_STATUS +wlan_cm_roam_btm_block_event(uint8_t vdev_id, uint8_t token, + enum wlan_diag_btm_block_reason reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * cm_roam_sync_key_event_handler() - Handle roam sync key event and + * store the keys in crypto module + * @psoc: Pointer to psoc object + * @keys: Pointer to the keys + * @num_keys: Number of links for which keys entries are available + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_sync_key_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_crypto_key_entry *keys, + uint8_t num_keys); +#else +static inline +QDF_STATUS cm_roam_sync_key_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_crypto_key_entry *keys, + uint8_t num_keys) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_FIPS +/** + * cm_roam_pmkid_req_ind() - Function to handle + * roam event from firmware for pmkid generation. + * @psoc: psoc pointer + * @vdev_id: Vdev id + * @bss_list: candidate AP bssid list + */ +QDF_STATUS +cm_roam_pmkid_req_ind(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct roam_pmkid_req_event *bss_list); +#else /* WLAN_FEATURE_FIPS */ +static inline QDF_STATUS +cm_roam_pmkid_req_ind(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct roam_pmkid_req_event *bss_list) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_FIPS */ + +/** + * wlan_get_chan_by_bssid_from_rnr: get chan from rnr through bssid + * @vdev: vdev + * @cm_id: connect manager id + * @link_addr: bssid of given link + * @chan: chan to get + * @op_class: operation class + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_get_chan_by_bssid_from_rnr(struct wlan_objmgr_vdev *vdev, + wlan_cm_id cm_id, + struct qdf_mac_addr *link_addr, + uint8_t *chan, uint8_t *op_class); + +/** + * wlan_get_chan_by_link_id_from_rnr: get chan from rnr through link id + * @vdev: vdev + * @cm_id: connect manager id + * @link_id: link id of given link + * @chan: chan to get + * @op_class: operation class + * + * Return: QDF_STATUS + */ +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS wlan_get_chan_by_link_id_from_rnr(struct wlan_objmgr_vdev *vdev, + wlan_cm_id cm_id, + uint8_t link_id, + uint8_t *chan, uint8_t *op_class); +#endif + +/** + * cm_rso_cmd_status_event_handler() - Handler for rso cmd status + * @vdev_id: vdev id + * @notif: roam notification of type enum cm_roam_notif + * + * Return: QDF_STATUS + */ +int cm_rso_cmd_status_event_handler(uint8_t vdev_id, enum cm_roam_notif notif); + +/** + * cm_handle_roam_reason_invoke_roam_fail() - Handler for roam invoke fail event + * @vdev_id: vdev id + * @notif_params: contains roam invoke fail reason from wmi_roam_invoke_error_t + * @trans_ind: hw_mode transition indication + * + * Return: None + */ +void +cm_handle_roam_reason_invoke_roam_fail(uint8_t vdev_id, uint32_t notif_params, + struct cm_hw_mode_trans_ind *trans_ind); + +/** + * cm_handle_roam_sync_update_hw_mode() - Handler for roam sync hw mode update + * @trans_ind: hw_mode transition indication + * + * Return: None + */ +void +cm_handle_roam_sync_update_hw_mode(struct cm_hw_mode_trans_ind *trans_ind); + +/** + * cm_handle_roam_reason_deauth() - Handler for roam due to deauth from AP + * @vdev_id: vdev id + * @notif_params: contains roam invoke fail reason from wmi_roam_invoke_error_t + * @deauth_disassoc_frame: Disassoc or deauth frame + * @frame_len: Contains the length of @deauth_disassoc_frame + * + * Return: None + */ +void cm_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params, + uint8_t *deauth_disassoc_frame, + uint32_t frame_len); + +/** + * cm_handle_roam_reason_btm() - Handler for roam due to btm from AP + * @vdev_id: vdev id + * + * Return: None + */ +void cm_handle_roam_reason_btm(uint8_t vdev_id); + +/** + * cm_handle_roam_reason_bmiss() - Handler for roam due to bmiss + * @vdev_id: vdev id + * @rssi: RSSI value + * + * Return: None + */ +void cm_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi); + +/** + * cm_handle_roam_reason_better_ap() - Handler for roam due to better AP + * @vdev_id: vdev id + * @rssi: RSSI value + * + * Return: None + */ +void cm_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi); + +/** + * cm_handle_roam_reason_suitable_ap() - Handler for roam due to suitable AP + * @vdev_id: vdev id + * @rssi: RSSI value + * + * Return: None + */ +void cm_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi); + +/** + * cm_roam_event_handler() - Carries extracted roam info + * @roam_event: data carried by roam event + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_event_handler(struct roam_offload_roam_event *roam_event); + +/** + * cm_btm_denylist_event_handler() - Deny list the given BSSID due to btm + * @psoc: PSOC pointer + * @list: Roam denylist info + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_btm_denylist_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_denylist_event *list); + +/** + * cm_vdev_disconnect_event_handler() - disconnect evt handler for target_if + * @data: disconnect event data + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_vdev_disconnect_event_handler(struct vdev_disconnect_event_data *data); + +/** + * cm_handle_disconnect_reason() - disconnect reason evt wrapper for wma + * @data: disconnect event data + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_disconnect_reason(struct vdev_disconnect_event_data *data); + +/** + * cm_roam_scan_ch_list_event_handler() - Roam scan ch evt handler for target_if + * @data: roam scan channel event data + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_scan_ch_list_event_handler(struct cm_roam_scan_ch_resp *data); + +/** + * cm_roam_stats_event_handler() - Carries extracted roam stats info + * @psoc: PSOC pointer + * @stats_info: stats data carried by roam_stats_event + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info); + +/** + * cm_handle_auth_offload() - auth offload evt wrapper for wma + * @auth_event: auth offload event data + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_handle_auth_offload(struct auth_offload_event *auth_event); + +/** + * cm_roam_auth_offload_event_handler() - Handler for auth offload event + * @auth_event: Authentication event + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_auth_offload_event_handler(struct auth_offload_event *auth_event); + +/* + * cm_roam_pmkid_request_handler() - Carries extracted pmkid list info + * @data: Pmkid event with entries + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_pmkid_request_handler(struct roam_pmkid_req_event *data); + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * cm_roam_vendor_handoff_event_handler() - vendor handoff event handler + * @psoc: psoc object + * @data: vendor handoff params + * + * Return: None + */ +void +cm_roam_vendor_handoff_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_vendor_handoff_params *data); +#endif + +/** + * cm_roam_update_vdev() - Update the STA and BSS + * @vdev: Pointer to the vdev object + * @sync_ind: Information needed for roam sync propagation + * + * This function will perform all the vdev related operations with + * respect to the self sta and the peer after roaming and completes + * the roam synch propagation with respect to WMA layer. + * + * Return: QDF_STATUS + */ +QDF_STATUS cm_roam_update_vdev(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind); + +/** + * cm_roam_pe_sync_callback() - Callback registered at pe, gets invoked when + * ROAM SYNCH event is received from firmware + * @sync_ind: Structure with roam synch parameters + * @vdev_id: vdev id + * @len: length for bss_description + * + * This is a PE level callback called from CM to complete the roam synch + * propagation at PE level and also fill the BSS descriptor which will be + * helpful further to complete the roam synch propagation. + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_roam_pe_sync_callback(struct roam_offload_synch_ind *sync_ind, + uint8_t vdev_id, uint16_t len); + +/** + * cm_update_phymode_on_roam() - Update new phymode after + * ROAM SYNCH event is received from firmware + * @vdev_id: roamed vdev id + * @sync_ind: Structure with roam synch parameters + * + * This api will update the phy mode after roam sync is received. + * + * Return: none + */ +void +cm_update_phymode_on_roam(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind); + +/** + * wlan_cm_fw_to_host_phymode() - Convert fw phymode to host + * @phymode: wmi phymode + * + * This api will convert the phy mode from fw to host type. + * + * Return: wlan phymode + */ +enum wlan_phymode +wlan_cm_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode); + +/** + * wlan_cm_sta_mlme_vdev_roam_notify() - STA mlme vdev roam notify + * @vdev_mlme: MLME-private vdev context + * @data_len: Length of @data + * @data: Roam data + * + * This function will handle the roam notify event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_sta_mlme_vdev_roam_notify(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wlan_cm_same_band_sta_allowed() - check if same band STA +STA is allowed + * + * @psoc: psoc ptr + * + * Return: true if same band STA+STA is allowed + */ +bool wlan_cm_same_band_sta_allowed(struct wlan_objmgr_psoc *psoc); + +/** + * cm_cleanup_mlo_link() - Cleanup the MLO link + * + * @vdev: MLO link vdev + * + * This posts the event WLAN_CM_SM_EV_ROAM_LINK_DOWN to CM to cleanup the + * resources allocated for MLO link e.g. vdev, pe_session, etc.. + * This gets called when MLO to non-MLO roaming happens + * + * Return: qdf_status + */ +QDF_STATUS cm_cleanup_mlo_link(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_is_roaming_enabled() - Check if Roaming is enabled + * + * @pdev: pointer to pdev object + * @vdev_id : Vdev id + * + * Check if the ROAM enable vdev param (WMI_VDEV_PARAM_ROAM_FW_OFFLOAD) + * is sent to firmware or not. + * + * Return: True if RSO state is not DEINIT, which indicates that vdev param + * WMI_VDEV_PARAM_ROAM_FW_OFFLOAD is sent to firmware. + */ +bool wlan_is_roaming_enabled(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * wlan_is_rso_enabled() - Check if RSO state is enabled + * + * @pdev: pointer to pdev object + * @vdev_id : Vdev id + * + * Check if the ROAM SCAN OFFLOAD enable is sent to firmware. Host driver tracks + * this through RSO state machine and the states can be WLAN_ROAM_RSO_ENABLED/ + * WLAN_ROAMING_IN_PROG/WLAN_ROAM_SYNCH_IN_PROG/WLAN_MLO_ROAM_SYNCH_IN_PROG. + * + * Return: True if RSO state is any of the above mentioned states. + */ +bool wlan_is_rso_enabled(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * wlan_cm_set_sae_auth_ta() - Set SAE auth tx address + * @pdev: pdev object + * @vdev_id : Vdev id + * @sae_auth_ta: SAE auth tx address + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_set_sae_auth_ta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr sae_auth_ta); + +/** + * wlan_cm_get_sae_auth_ta() - Get SAE auth tx address + * @pdev: pdev object + * @vdev_id: Vdev id + * @sae_auth_ta: SAE auth tx address + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_get_sae_auth_ta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *sae_auth_ta); + +/** + * wlan_cm_set_assoc_btm_cap() - Set the assoc BTM capability + * @vdev: pointer to vdev + * @val: BTM cap + * + * Return: None + */ +void +wlan_cm_set_assoc_btm_cap(struct wlan_objmgr_vdev *vdev, bool val); + +/** + * wlan_cm_get_assoc_btm_cap() - Get the assoc BTM capability + * @psoc: pointer to psoc + * @vdev_id: vdev id + * + * Return: BTM cap + */ +bool wlan_cm_get_assoc_btm_cap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id); + +/** + * wlan_cm_is_self_mld_roam_supported() - Is self mld roam supported + * @psoc: pointer to psoc object + * + * Return: bool, true: self mld roam supported + */ +bool wlan_cm_is_self_mld_roam_supported(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_cm_set_force_20mhz_in_24ghz() - Sets the config to (dis)allow + * the 40 MHz connection in 2.4 GHz + * + * @vdev: pointer to vdev + * @is_40mhz_cap: is 40 MHz supported + * + * Return: None + */ +void +wlan_cm_set_force_20mhz_in_24ghz(struct wlan_objmgr_vdev *vdev, + bool is_40mhz_cap); + +/** + * wlan_cm_get_force_20mhz_in_24ghz - Gets the 40 MHz (dis)allowed on 2.4 GHz + * config + * @vdev: pointer to vdev + * + * Return: 40 MHz allowed on 2.4 GHz + */ +bool +wlan_cm_get_force_20mhz_in_24ghz(struct wlan_objmgr_vdev *vdev); + +/** + * cm_send_ies_for_roam_invoke - Send IEs to firmware based on the reassoc + * req received from the userspace + * @vdev: vdev + * @dot11_mode: dot11 mode + * + * Return: QDF_STATUS + */ +QDF_STATUS +cm_send_ies_for_roam_invoke(struct wlan_objmgr_vdev *vdev, uint16_t dot11_mode); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_cm_is_sae_auth_addr_conversion_required() - check whether address + * conversion is required or not. + * @vdev: pointer to vdev + * + * This API checks the address conversion (mld to link and vice-versa) for sae + * auth frames for below listed scenarios when mlo sae auth external conversion + * is true. + * + * Connected AP Roam AP Connection Conversion + * (MLO vdev) + * non-ML non-ML initial FALSE + * non-ML ML initial FALSE + * non-ML non-ML roam FALSE + * non-ML ML roam TRUE + * ML non-ML initial TRUE + * ML ML initial TRUE + * ML non-ML roam FALSE + * ML ML roam TRUE + * + * Return: true if address conversion required, otherwise false. + */ +bool +wlan_cm_is_sae_auth_addr_conversion_required(struct wlan_objmgr_vdev *vdev); +#else +static inline bool +wlan_cm_is_sae_auth_addr_conversion_required(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * wlan_cm_store_mlo_roam_peer_address() - cache peer mld and link address + * while roaming + * @pdev: pdev object + * @auth_event: auth offload event data + * + * Return: void + */ +void +wlan_cm_store_mlo_roam_peer_address(struct wlan_objmgr_pdev *pdev, + struct auth_offload_event *auth_event); + +/** + * wlan_cm_roaming_get_peer_mld_addr() - retrieve the peer mld address for + * roaming. + * @vdev: vdev pointer + * + * Return: pointer to struct qdf_mac_addr + */ +struct qdf_mac_addr * +wlan_cm_roaming_get_peer_mld_addr(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cm_roaming_get_peer_link_addr() - get peer link address for roaming + * @vdev: vdev pointer + * + * Return: pointer to struct qdf_mac_addr + */ +struct qdf_mac_addr * +wlan_cm_roaming_get_peer_link_addr(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cm_roam_is_mlo_ap() - to check whether vdev will be roam to ml ap + * @vdev: object manager vdev + * + * this function check whether roaming vdev will be connected to ml ap or not. + * + * Return: true if roam ap is ml capable otherwise false + */ +bool +wlan_cm_roam_is_mlo_ap(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cm_link_switch_notif_cb() - MLME CM link switch notifier callback + * @vdev: object manager vdev + * @req: Link switch request + * @notify_reason: Notify reason + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_link_switch_notif_cb(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *req, + enum wlan_mlo_link_switch_notify_reason notify_reason); +#else +static inline void +wlan_cm_store_mlo_roam_peer_address(struct wlan_objmgr_pdev *pdev, + struct auth_offload_event *auth_event) +{ +} + +static inline struct qdf_mac_addr * +wlan_cm_roaming_get_mld_addr(struct wlan_objmgr_vdev *vdev) +{ + return NULL; +} + +static inline struct qdf_mac_addr * +wlan_cm_roaming_get_peer_link_addr(struct wlan_objmgr_vdev *vdev) +{ + return NULL; +} + +static inline bool +wlan_cm_roam_is_mlo_ap(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +QDF_STATUS wlan_cm_link_switch_notif_cb(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *req, + enum wlan_mlo_link_switch_notify_reason notify_reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_11BE_MLO && WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wlan_update_peer_phy_mode() - update phymode in peer object + * @des_chan: wlan_channel pointer contain new ch_freq + * @vdev: vdev pointer + * + * Return: QDF_STATUS_SUCCESS if peer object phymode is set otherwise + * QDF_STATUS_E_INVAL + */ +QDF_STATUS +wlan_update_peer_phy_mode(struct wlan_channel *des_chan, + struct wlan_objmgr_vdev *vdev); + +#endif /* WLAN_CM_ROAM_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h new file mode 100644 index 0000000000..912eb1708f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_public_struct.h @@ -0,0 +1,3009 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains definitions for MLME roaming offload. + */ + +#ifndef CM_ROAM_PUBLIC_STRUCT_H__ +#define CM_ROAM_PUBLIC_STRUCT_H__ + +#include "wlan_objmgr_cmn.h" +#include "reg_services_public_struct.h" +#include "wlan_cm_bss_score_param.h" +#include "wlan_dlm_public_struct.h" +#include "wmi_unified_param.h" +#include "wmi_unified_sta_param.h" +#include "wlan_cm_public_struct.h" +#include "wmi_unified.h" + +#define WLAN_ROAM_MAX_CACHED_AUTH_FRAMES 8 + +#define ROAM_SCAN_OFFLOAD_START 1 +#define ROAM_SCAN_OFFLOAD_STOP 2 +#define ROAM_SCAN_OFFLOAD_RESTART 3 +#define ROAM_SCAN_OFFLOAD_UPDATE_CFG 4 +#define ROAM_SCAN_OFFLOAD_ABORT_SCAN 5 + +#define REASON_CONNECT 1 +#define REASON_CHANNEL_LIST_CHANGED 2 +#define REASON_LOOKUP_THRESH_CHANGED 3 +#define REASON_DISCONNECTED 4 +#define REASON_RSSI_DIFF_CHANGED 5 +#define REASON_ESE_INI_CFG_CHANGED 6 +#define REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED 7 +#define REASON_VALID_CHANNEL_LIST_CHANGED 8 +#define REASON_FLUSH_CHANNEL_LIST 9 +#define REASON_EMPTY_SCAN_REF_PERIOD_CHANGED 10 +#define REASON_PREAUTH_FAILED_FOR_ALL 11 +#define REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW 12 +#define REASON_NPROBES_CHANGED 13 +#define REASON_HOME_AWAY_TIME_CHANGED 14 +#define REASON_OS_REQUESTED_ROAMING_NOW 15 +#define REASON_SCAN_CH_TIME_CHANGED 16 +#define REASON_SCAN_HOME_TIME_CHANGED 17 +#define REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED 18 +#define REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED 19 +#define REASON_ROAM_BMISS_FIRST_BCNT_CHANGED 20 +#define REASON_ROAM_BMISS_FINAL_BCNT_CHANGED 21 +#define REASON_ROAM_DFS_SCAN_MODE_CHANGED 23 +#define REASON_ROAM_ABORT_ROAM_SCAN 24 +#define REASON_ROAM_EXT_SCAN_PARAMS_CHANGED 25 +#define REASON_ROAM_SET_SSID_ALLOWED 26 +#define REASON_ROAM_SET_FAVORED_BSSID 27 +#define REASON_ROAM_GOOD_RSSI_CHANGED 28 +#define REASON_ROAM_SET_DENYLIST_BSSID 29 +#define REASON_ROAM_SCAN_HI_RSSI_MAXCOUNT_CHANGED 30 +#define REASON_ROAM_SCAN_HI_RSSI_DELTA_CHANGED 31 +#define REASON_ROAM_SCAN_HI_RSSI_DELAY_CHANGED 32 +#define REASON_ROAM_SCAN_HI_RSSI_UB_CHANGED 33 +#define REASON_CONNECT_IES_CHANGED 34 +#define REASON_ROAM_SCAN_STA_ROAM_POLICY_CHANGED 35 +#define REASON_ROAM_SYNCH_FAILED 36 +#define REASON_ROAM_PSK_PMK_CHANGED 37 +#define REASON_ROAM_STOP_ALL 38 +#define REASON_SUPPLICANT_DISABLED_ROAMING 39 +#define REASON_CTX_INIT 40 +#define REASON_FILS_PARAMS_CHANGED 41 +#define REASON_SME_ISSUED 42 +#define REASON_DRIVER_ENABLED 43 +#define REASON_ROAM_FULL_SCAN_PERIOD_CHANGED 44 +#define REASON_SCORING_CRITERIA_CHANGED 45 +#define REASON_SUPPLICANT_INIT_ROAMING 46 +#define REASON_SUPPLICANT_DE_INIT_ROAMING 47 +#define REASON_DRIVER_DISABLED 48 +#define REASON_ROAM_CONTROL_CONFIG_CHANGED 49 +#define REASON_ROAM_CONTROL_CONFIG_ENABLED 50 +#define REASON_ROAM_CANDIDATE_FOUND 51 +#define REASON_ROAM_HANDOFF_DONE 52 +#define REASON_ROAM_ABORT 53 +#define REASON_ROAM_SET_PRIMARY 54 +#define REASON_ROAM_LINK_SWITCH_ASSOC_VDEV_CHANGE 55 +#define REASON_VDEV_RESTART_FROM_HOST 56 + +#define FILS_MAX_KEYNAME_NAI_LENGTH WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH +#define WLAN_FILS_MAX_REALM_LEN WLAN_CM_FILS_MAX_REALM_LEN +#define WLAN_FILS_MAX_RRK_LENGTH WLAN_CM_FILS_MAX_RRK_LENGTH + +#define FILS_MAX_HLP_DATA_LEN 2048 + +#define WLAN_FILS_MAX_RIK_LENGTH WLAN_FILS_MAX_RRK_LENGTH +#define WLAN_FILS_FT_MAX_LEN 48 + +#define WLAN_MAX_PMK_DUMP_BYTES 2 +#define DEFAULT_ROAM_SCAN_SCHEME_BITMAP 0 +#define ROAM_MAX_CFG_VALUE 0xffffffff + +#define CFG_VALID_CHANNEL_LIST_LEN 100 +#define MAX_SSID_ALLOWED_LIST 8 +#define MAX_BSSID_AVOID_LIST 16 +#define MAX_BSSID_FAVORED 16 +#define WLAN_MAX_BTM_CANDIDATES 8 + +/* Default value of WTC reason code */ +#define DISABLE_VENDOR_BTM_CONFIG 2 + +#ifdef WLAN_FEATURE_HOST_ROAM +#define MAX_FTIE_SIZE CM_MAX_FTIE_SIZE +#else +#define MAX_FTIE_SIZE 384 +#endif + +#define ESE_MAX_TSPEC_IES 4 + +/* + * To get 4 LSB of roam reason of roam_synch_data + * received from firmware + */ +#define ROAM_REASON_MASK 0x0F + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define ROAM_R0KH_ID_MAX_LEN 48 +/* connected but not authenticated */ +#define ROAM_AUTH_STATUS_CONNECTED 0x1 +/* connected and authenticated */ +#define ROAM_AUTH_STATUS_AUTHENTICATED 0x2 + +#define IS_ROAM_REASON_STA_KICKOUT(reason) ((reason & 0xF) == \ + WMI_ROAM_TRIGGER_REASON_STA_KICKOUT) +#define IS_ROAM_REASON_DISCONNECTION(reason) ((reason & 0xF) == \ + WMI_ROAM_TRIGGER_REASON_DEAUTH) +#endif + +/* + * Neighbor Report Params Bitmask + */ +#define NEIGHBOR_REPORT_PARAMS_TIME_OFFSET 0x01 +#define NEIGHBOR_REPORT_PARAMS_LOW_RSSI_OFFSET 0x02 +#define NEIGHBOR_REPORT_PARAMS_BMISS_COUNT_TRIGGER 0x04 +#define NEIGHBOR_REPORT_PARAMS_PER_THRESHOLD_OFFSET 0x08 +#define NEIGHBOR_REPORT_PARAMS_CACHE_TIMEOUT 0x10 +#define NEIGHBOR_REPORT_PARAMS_MAX_REQ_CAP 0x20 +#define NEIGHBOR_REPORT_PARAMS_ALL 0x3F + +/* + * Neighbor report offload needs to send 0xFFFFFFFF if a particular + * parameter is disabled from the ini + */ +#define NEIGHBOR_REPORT_PARAM_INVALID (0xFFFFFFFFU) + +/* + * Currently roam score delta value is sent for 2 triggers and min rssi + * values are sent for 3 triggers + */ +#define NUM_OF_ROAM_TRIGGERS 2 +#define IDLE_ROAM_TRIGGER 0 +#define BTM_ROAM_TRIGGER 1 + +#define NUM_OF_ROAM_MIN_RSSI 3 +#define DEAUTH_MIN_RSSI 0 +#define BMISS_MIN_RSSI 1 +#define MIN_RSSI_2G_TO_5G_ROAM 2 +#define CM_CFG_VALID_CHANNEL_LIST_LEN 100 + +/** + * enum roam_trigger_sub_reason - Roam trigger sub reasons + * @ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER: Roam scan triggered due to + * periodic timer expiry + * @ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI: Roam scan triggered due + * to inactivity detection and connected AP RSSI falls below a certain threshold + * @ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER: Roam scan triggered due to BTM + * Disassoc Imminent timeout + * @ROAM_TRIGGER_SUB_REASON_FULL_SCAN: Roam scan triggered due to partial scan + * failure + * @ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC: Roam scan triggered due to Low + * rssi periodic timer + * @ROAM_TRIGGER_SUB_REASON_CU_PERIODIC: Roam scan triggered due to CU periodic + * timer + * @ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY: Roam scan + * triggered due to periodic timer after device inactivity after low rssi + * trigger + * @ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU: Roam scan + * triggered due to first periodic timer exiry when full scan count is not 0 + * and roam scan trigger is CU load + * @ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU: Roam scan triggered due to + * first periodic timer exiry when full scan count is 0 and roam scan trigger + * is CU load + */ +enum roam_trigger_sub_reason { + ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER = 1, + ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI, + ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER, + ROAM_TRIGGER_SUB_REASON_FULL_SCAN, + ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC, + ROAM_TRIGGER_SUB_REASON_CU_PERIODIC, + ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY, + ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU, + ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU, +}; + +/** + * enum roam_stats_scan_type - Roam scan type defines + * @ROAM_STATS_SCAN_TYPE_PARTIAL: Partial scan + * @ROAM_STATS_SCAN_TYPE_FULL: Full scan + * @ROAM_STATS_SCAN_TYPE_NO_SCAN: No roam scan was triggered. This is generally + * used in BTM events to indicate BTM frame exchange logs. + * @ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ: Higher band roam scan from 2 GHz + * to 5 GHz or 6 GHz + * @ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ: Higher band roam scan from 5 GHz to + * 6 GHz + */ +enum roam_stats_scan_type { + ROAM_STATS_SCAN_TYPE_PARTIAL = 0, + ROAM_STATS_SCAN_TYPE_FULL = 1, + ROAM_STATS_SCAN_TYPE_NO_SCAN = 2, + ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ = 3, + ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ = 4, +}; + +/** + * enum wlan_roam_frame_subtype - Roam frame subtypes + * @ROAM_FRAME_SUBTYPE_M1: EAPOL M1 Frame + * @ROAM_FRAME_SUBTYPE_M2: EAPOL M2 Frame + * @ROAM_FRAME_SUBTYPE_M3: EAPOL M3 Frame + * @ROAM_FRAME_SUBTYPE_M4: EAPOL M4 Frame + * @ROAM_FRAME_SUBTYPE_GTK_M1: GTK M1 Frame + * @ROAM_FRAME_SUBTYPE_GTK_M2: GTK M2 Frame + */ +enum wlan_roam_frame_subtype { + ROAM_FRAME_SUBTYPE_M1 = 1, + ROAM_FRAME_SUBTYPE_M2, + ROAM_FRAME_SUBTYPE_M3, + ROAM_FRAME_SUBTYPE_M4, + ROAM_FRAME_SUBTYPE_GTK_M1, + ROAM_FRAME_SUBTYPE_GTK_M2, +}; + +/** + * struct cm_roam_neighbor_report_offload_params - neighbor report offload + * parameters + * @offload_11k_enable_bitmask: neighbor report offload bitmask control + * @params_bitmask: bitmask to specify which of the below are enabled + * @time_offset: time offset after 11k offload command to trigger a neighbor + * report request (in seconds) + * @low_rssi_offset: Offset from rssi threshold to trigger neighbor + * report request (in dBm) + * @bmiss_count_trigger: Number of beacon miss events to trigger neighbor + * report request + * @per_threshold_offset: offset from PER threshold to trigger neighbor + * report request (in %) + * @neighbor_report_cache_timeout: timeout after which new trigger can enable + * sending of a neighbor report request (in seconds) + * @max_neighbor_report_req_cap: max number of neighbor report requests that + * can be sent to the peer in the current session + */ +struct cm_roam_neighbor_report_offload_params { + uint32_t offload_11k_enable_bitmask; + uint8_t params_bitmask; + uint32_t time_offset; + uint32_t low_rssi_offset; + uint32_t bmiss_count_trigger; + uint32_t per_threshold_offset; + uint32_t neighbor_report_cache_timeout; + uint32_t max_neighbor_report_req_cap; +}; + +/** + * struct rso_chan_info - chan info + * @num_chan: number of channels + * @freq_list: freq list + */ +struct rso_chan_info { + uint8_t num_chan; + qdf_freq_t *freq_list; +}; + +/** + * struct rso_cfg_params - per vdev rso cfg + * @neighbor_scan_period: + * @neighbor_scan_min_period: + * @specific_chan_info: + * @neighbor_lookup_threshold: + * @next_rssi_threshold: Next roam can trigger rssi threshold + * @rssi_thresh_offset_5g: + * @min_chan_scan_time: + * @max_chan_scan_time: + * @passive_max_chan_time: + * @neighbor_results_refresh_period: + * @empty_scan_refresh_period: + * @opportunistic_threshold_diff: + * @roam_rescan_rssi_diff: + * @roam_bmiss_first_bcn_cnt: + * @roam_bmiss_final_cnt: + * @hi_rssi_scan_max_count: + * @hi_rssi_scan_rssi_delta: + * @hi_rssi_scan_delay: + * @hi_rssi_scan_rssi_ub: + * @pref_chan_info: + * @full_roam_scan_period: + * @enable_scoring_for_roam: + * @roam_rssi_diff: + * @roam_rssi_diff_6ghz: + * @bg_rssi_threshold: + * @roam_scan_home_away_time: + * @roam_scan_n_probes: + * @roam_scan_inactivity_time: + * @roam_inactive_data_packet_count: + */ +struct rso_cfg_params { + uint32_t neighbor_scan_period; + uint32_t neighbor_scan_min_period; + struct rso_chan_info specific_chan_info; + uint8_t neighbor_lookup_threshold; + uint8_t next_rssi_threshold; + int8_t rssi_thresh_offset_5g; + uint32_t min_chan_scan_time; + uint32_t max_chan_scan_time; + uint32_t passive_max_chan_time; + uint16_t neighbor_results_refresh_period; + uint16_t empty_scan_refresh_period; + uint8_t opportunistic_threshold_diff; + uint8_t roam_rescan_rssi_diff; + uint8_t roam_bmiss_first_bcn_cnt; + uint8_t roam_bmiss_final_cnt; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + uint32_t hi_rssi_scan_delay; + int32_t hi_rssi_scan_rssi_ub; + struct rso_chan_info pref_chan_info; + uint32_t full_roam_scan_period; + bool enable_scoring_for_roam; + uint8_t roam_rssi_diff; + uint8_t roam_rssi_diff_6ghz; + uint8_t bg_rssi_threshold; + uint16_t roam_scan_home_away_time; + uint8_t roam_scan_n_probes; + uint32_t roam_scan_inactivity_time; + uint32_t roam_inactive_data_packet_count; +}; + +/** + * struct wlan_chan_list - channel list + * @num_chan: number of channels + * @freq_list: freq list + */ +struct wlan_chan_list { + uint8_t num_chan; + qdf_freq_t freq_list[CFG_VALID_CHANNEL_LIST_LEN]; +}; + +/** + * enum roam_fail_params: different types of params to set or get + * roam fail states for the vdev + * @ROAM_TRIGGER_REASON: Roam trigger reason(enum WMI_ROAM_TRIGGER_REASON_ID) + * @ROAM_INVOKE_FAIL_REASON: One of WMI_ROAM_FAIL_REASON_ID for roam failure + * in case of forced roam + * @ROAM_FAIL_REASON: One of WMI_ROAM_FAIL_REASON_ID for roam failure + */ +enum roam_fail_params { + ROAM_TRIGGER_REASON, + ROAM_INVOKE_FAIL_REASON, + ROAM_FAIL_REASON, +}; + +/** + * enum wlan_roam_failure_reason_code - Roaming failure reason codes + * @ROAM_FAIL_REASON_NO_SCAN_START: Scan start failed + * @ROAM_FAIL_REASON_NO_AP_FOUND: No roamable AP found + * @ROAM_FAIL_REASON_NO_CAND_AP_FOUND: No candidate AP found + * @ROAM_FAIL_REASON_HOST: Host aborted roaming due to vdev stop from + * host + * @ROAM_FAIL_REASON_AUTH_SEND: Auth TX failure + * @ROAM_FAIL_REASON_NO_AUTH_RESP: No Authentication response received + * @ROAM_FAIL_REASON_AUTH_RECV: Authentication response received with + * error status code + * @ROAM_FAIL_REASON_REASSOC_SEND: Reassoc request TX failed + * @ROAM_FAIL_REASON_REASSOC_RECV: Reassoc response frame received with failure + * status + * @ROAM_FAIL_REASON_NO_REASSOC_RESP: No reassociation response received + * @ROAM_FAIL_REASON_EAPOL_TIMEOUT: EAPoL timedout + * @ROAM_FAIL_REASON_MLME: MLME internal error + * @ROAM_FAIL_REASON_INTERNAL_ABORT: Abort due to internal firmware error + * @ROAM_FAIL_REASON_SCAN_START: Not able to start roam scan + * @ROAM_FAIL_REASON_AUTH_NO_ACK: No ack received for Auth request frame + * @ROAM_FAIL_REASON_AUTH_INTERNAL_DROP: Auth request dropped internally + * @ROAM_FAIL_REASON_REASSOC_NO_ACK: No ack received for reassoc request frame + * @ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP: Reassoc frame dropped internally + * at firmware + * @ROAM_FAIL_REASON_EAPOL_M2_SEND: EAPoL M2 send failed + * @ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP: EAPoL M2 frame dropped internally + * at firmware + * @ROAM_FAIL_REASON_EAPOL_M2_NO_ACK: No ack received for EAPoL M2 frame + * @ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT: EAPoL M3 not received from AP + * @ROAM_FAIL_REASON_EAPOL_M4_SEND: EAPoL M4 frame TX failed + * @ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP: EAPoL M4 frame dropped internally + * @ROAM_FAIL_REASON_EAPOL_M4_NO_ACK: No ack received for EAPoL M4 frame + * @ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS: Roam scan start failed for final + * bmiss case + * @ROAM_FAIL_REASON_DISCONNECT: Deauth/Disassoc frame received from AP during + * roaming + * @ROAM_FAIL_REASON_SYNC: Roam failure due to host wake-up during roaming in + * progress + * @ROAM_FAIL_REASON_SAE_INVALID_PMKID: Invalid PMKID during SAE roaming + * @ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: SAE roaming preauthentication + * timedout + * @ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: SAE preauthentication failure + * @ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO: Start handoff failed + * @ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT: No AP found after + * final BMISS + * @ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT: No Candidate AP + * found after final BMISS. + * @ROAM_FAIL_REASON_CURR_AP_STILL_OK: Background scan was abort, but + * current network condition is fine. + * @ROAM_FAIL_REASON_SCAN_CANCEL: Roam fail reason, scan cancelled + * @ROAM_FAIL_REASON_SCREEN_ACTIVITY: Roam fail reason screen activity happened + * @ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN: Roam fail due to other priority + * roam scan started. + * @ROAM_FAIL_REASON_UNKNOWN: Default reason + */ +enum wlan_roam_failure_reason_code { + ROAM_FAIL_REASON_NO_SCAN_START = 1, + ROAM_FAIL_REASON_NO_AP_FOUND, + ROAM_FAIL_REASON_NO_CAND_AP_FOUND, + + /* Failure reasons after roam scan is complete */ + ROAM_FAIL_REASON_HOST, + ROAM_FAIL_REASON_AUTH_SEND, + ROAM_FAIL_REASON_AUTH_RECV, + ROAM_FAIL_REASON_NO_AUTH_RESP, + ROAM_FAIL_REASON_REASSOC_SEND, + ROAM_FAIL_REASON_REASSOC_RECV, + ROAM_FAIL_REASON_NO_REASSOC_RESP, + ROAM_FAIL_REASON_EAPOL_TIMEOUT, + ROAM_FAIL_REASON_MLME, + ROAM_FAIL_REASON_INTERNAL_ABORT, + ROAM_FAIL_REASON_SCAN_START, + ROAM_FAIL_REASON_AUTH_NO_ACK, + ROAM_FAIL_REASON_AUTH_INTERNAL_DROP, + ROAM_FAIL_REASON_REASSOC_NO_ACK, + ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP, + ROAM_FAIL_REASON_EAPOL_M2_SEND, + ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP, + ROAM_FAIL_REASON_EAPOL_M2_NO_ACK, + ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT, + ROAM_FAIL_REASON_EAPOL_M4_SEND, + ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP, + ROAM_FAIL_REASON_EAPOL_M4_NO_ACK, + ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS, + ROAM_FAIL_REASON_DISCONNECT, + ROAM_FAIL_REASON_SYNC, + ROAM_FAIL_REASON_SAE_INVALID_PMKID, + ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT, + ROAM_FAIL_REASON_SAE_PREAUTH_FAIL, + ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO, + ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT, + ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT, + ROAM_FAIL_REASON_CURR_AP_STILL_OK, + ROAM_FAIL_REASON_SCAN_CANCEL, + ROAM_FAIL_REASON_SCREEN_ACTIVITY, + ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN, + ROAM_FAIL_REASON_UNKNOWN = 255, +}; + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * struct reassoc_timer_ctx - reassoc timer context + * @pdev: pdev object pointer + * @vdev_id: vdev id + * @cm_id: cm id to find cm_roam_req + */ +struct reassoc_timer_ctx { + struct wlan_objmgr_pdev *pdev; + uint8_t vdev_id; + wlan_cm_id cm_id; +}; +#endif + +/** + * struct roam_synch_frame_ind - Structure to hold the information on frames + * received during roam synch frame indication. + * @bcn_probe_rsp_len: Length of the beacon/probe response frame + * @bcn_probe_rsp: Beacon probe response frame pointer + * @is_beacon: Flag to indicate if received frame is beacon or probe response + * @link_bcn_probe_rsp_len: Length of the link beacon/probe response frame + * @link_bcn_probe_rsp: Link beacon probe response frame pointer + * @is_link_beacon: Flag to indicate if received frame is link beacon or probe + * response + * @reassoc_req_len: Reassoc request frame length + * @reassoc_req: Reassoc request frame pointer + * @reassoc_rsp_len: Reassoc response frame length + * @reassoc_rsp: Reassoc response frame pointer + * @vdev_id: Vdev id + * @rssi: RSSI of the frame + */ +struct roam_synch_frame_ind { + uint32_t bcn_probe_rsp_len; + uint8_t *bcn_probe_rsp; + uint8_t is_beacon; + uint32_t link_bcn_probe_rsp_len; + uint8_t *link_bcn_probe_rsp; + uint8_t is_link_beacon; + uint32_t reassoc_req_len; + uint8_t *reassoc_req; + uint32_t reassoc_rsp_len; + uint8_t *reassoc_rsp; + uint8_t vdev_id; + int8_t rssi; +}; + +/** + * struct owe_transition_mode_info - structure containing owe transition mode + * element info + * @is_owe_transition_conn: Current connection is in owe transition mode or not + * @ssid: ssid + */ +struct owe_transition_mode_info { + bool is_owe_transition_conn; + struct wlan_ssid ssid; +}; + +/** + * struct sae_roam_auth_map - map the peer address for the sae raom + * @is_mlo_ap: to check ap (to which roam) is mlo capable. + * @peer_mldaddr: peer MLD address + * @peer_linkaddr: peer link address + */ +struct sae_roam_auth_map { + bool is_mlo_ap; + struct qdf_mac_addr peer_mldaddr; + struct qdf_mac_addr peer_linkaddr; +}; + +/** + * struct rso_config - connect config to be used to send info in + * RSO. This is the info we dont have in VDEV or CM ctx + * @reassoc_timer: reassoc timer + * @ctx: reassoc timer context + * @cm_rso_lock: RSO lock + * @orig_sec_info: original security info coming from the connect req from + * supplicant, without intersection of the peer capability + * @country_code: country code from connected AP's beacon IE + * @disable_hi_rssi: disable high rssi + * @roam_control_enable: Flag used to cache the status of roam control + * configuration. This will be set only if the + * corresponding vendor command data is configured to + * driver/firmware successfully. The same shall be + * returned to userspace whenever queried for roam + * control config status. + * @rescan_rssi_delta: Roam scan rssi delta. Start new rssi triggered scan only + * if it changes by rescan_rssi_delta value. + * @beacon_rssi_weight: Number of beacons to be used to calculate the average + * rssi of the AP. + * @hi_rssi_scan_delay: Roam scan delay in ms for High RSSI roam trigger. + * @roam_scan_scheme_bitmap: Bitmap of roam triggers for which partial channel + * map scan scheme needs to be enabled. Each bit in the bitmap corresponds to + * the bit position in the order provided by the enum roam_trigger_reason + * Ex: roam_scan_scheme_bitmap - 0x00110 will enable partial scan for below + * triggers: + * ROAM_TRIGGER_REASON_PER, ROAM_TRIGGER_REASON_BMISS + * @cfg_param: per vdev config params + * @assoc_ie: assoc IE + * @prev_ap_bcn_ie: last connected AP ie + * @occupied_chan_lst: occupied channel list + * @roam_candidate_count: candidate count + * @uapsd_mask: UAPSD mask + * @is_ese_assoc: is ese assoc + * @krk: krk data + * @btk: btk data + * @psk_pmk: pmk + * @pmk_len: length of pmk + * @owe_info: owe ap profile info + * @mdid: mdid info + * @is_11r_assoc: is 11r assoc + * @is_adaptive_11r_connection: is adaptive 11r connection + * @hs_20_ap: Hotspot 2.0 AP + * @mbo_oce_enabled_ap: MBO/OCE enabled network + * @is_single_pmk: is single pmk + * @roam_scan_freq_lst: roam freq list + * @roam_fail_reason: One of WMI_ROAM_FAIL_REASON_ID + * @roam_trigger_reason: Roam trigger reason(enum WMI_ROAM_TRIGGER_REASON_ID) + * @roam_invoke_fail_reason: One of reason id from enum + * wmi_roam_invoke_status_error in case of forced roam + * @lost_link_rssi: lost link RSSI + * @roam_sync_frame_ind: roam sync frame ind + * @roam_band_bitmask: This allows the driver to roam within this band + * @sae_roam_auth: structure containing roam peer mld and link address. + * @roam_invoke_source: roam invoke source + * @roam_invoke_bssid: mac address used for roam invoke + * @is_forced_roaming: bool value indicating if its forced roaming + * @tried_candidate_freq_list: freq list on which connection tried + * @rso_rsn_caps: rsn caps with global user MFP which can be used for + * cross-AKM roaming + * @is_disable_btm: btm roaming disabled or not from userspace + */ +struct rso_config { +#ifdef WLAN_FEATURE_HOST_ROAM + qdf_mc_timer_t reassoc_timer; + struct reassoc_timer_ctx ctx; +#endif + qdf_mutex_t cm_rso_lock; + struct security_info orig_sec_info; + uint8_t country_code[REG_ALPHA2_LEN + 1]; + bool disable_hi_rssi; + bool roam_control_enable; + uint8_t rescan_rssi_delta; + uint8_t beacon_rssi_weight; + uint32_t hi_rssi_scan_delay; + uint32_t roam_scan_scheme_bitmap; + struct rso_cfg_params cfg_param; + struct element_info assoc_ie; + struct element_info prev_ap_bcn_ie; + struct wlan_chan_list occupied_chan_lst; + int8_t roam_candidate_count; + uint8_t uapsd_mask; +#ifdef FEATURE_WLAN_ESE + bool is_ese_assoc; + uint8_t krk[WMI_KRK_KEY_LEN]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t btk[WMI_BTK_KEY_LEN]; +#endif +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + uint8_t psk_pmk[MAX_PMK_LEN]; + uint8_t pmk_len; +#endif + struct owe_transition_mode_info owe_info; + struct mobility_domain_info mdid; + bool is_11r_assoc; + bool is_adaptive_11r_connection; + bool hs_20_ap; + bool is_single_pmk; + uint32_t mbo_oce_enabled_ap; + struct rso_chan_info roam_scan_freq_lst; + uint32_t roam_fail_reason; + uint32_t roam_trigger_reason; + uint32_t roam_invoke_fail_reason; + int32_t lost_link_rssi; + struct roam_synch_frame_ind roam_sync_frame_ind; + uint32_t roam_band_bitmask; +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) + struct sae_roam_auth_map sae_roam_auth; +#endif + enum wlan_cm_source roam_invoke_source; + struct qdf_mac_addr roam_invoke_bssid; + bool is_forced_roaming; + struct wlan_chan_list tried_candidate_freq_list; + uint16_t rso_rsn_caps; + bool is_disable_btm; +}; + +/** + * struct rso_user_config - userspace configured RSO related + * configs. + * @num_ssid_allowed_list: The number of SSID profiles that are + * in the allowlist. When roaming, we consider the BSSID's with + * this SSID also for roaming apart from the connected ones + * @ssid_allowed_list: Allowlist SSIDs + */ +struct rso_user_config { + uint8_t num_ssid_allowed_list; + struct wlan_ssid ssid_allowed_list[MAX_SSID_ALLOWED_LIST]; +}; + +/** + * enum sta_roam_policy_dfs_mode - state of DFS mode for STA ROME policy + * @STA_ROAM_POLICY_NONE: DFS mode attribute is not valid + * @STA_ROAM_POLICY_DFS_ENABLED: DFS mode is enabled + * @STA_ROAM_POLICY_DFS_DISABLED: DFS mode is disabled + * @STA_ROAM_POLICY_DFS_DEPRIORITIZE: Deprioritize DFS channels in scanning + */ +enum sta_roam_policy_dfs_mode { + STA_ROAM_POLICY_NONE, + STA_ROAM_POLICY_DFS_ENABLED, + STA_ROAM_POLICY_DFS_DISABLED, + STA_ROAM_POLICY_DFS_DEPRIORITIZE +}; + +/** + * struct rso_roam_policy_params - sta roam policy params for station + * @dfs_mode: tell is DFS channels needs to be skipped while scanning + * @skip_unsafe_channels: tells if unsafe channels needs to be skip in scanning + * @sap_operating_band: Operating band for SAP + */ +struct rso_roam_policy_params { + enum sta_roam_policy_dfs_mode dfs_mode; + bool skip_unsafe_channels; + uint8_t sap_operating_band; +}; + +#define DEFAULT_RSSI_DB_GAP 30 /* every 30 dbm for one category */ +#define ENABLE_FT_OVER_DS 1 /* enable ft_over_ds */ + +/** + * struct rso_config_params - global RSO params + * @num_bssid_favored: Number of BSSID's which have a preference over others + * @bssid_favored: Favorable BSSID's + * @bssid_favored_factor: RSSI to be added to this BSSID to prefer it + * @good_rssi_roam: Lazy Roam + * @alert_rssi_threshold: Alert RSSI + * @rssi_diff: rssi diff + * @raise_rssi_thresh_5g: The RSSI threshold below which the + * raise_factor_5g (boost factor) should be applied. + * @drop_rssi_thresh_5g: The RSSI threshold beyond which the + * drop_factor_5g (penalty factor) should be applied + * @raise_factor_5g: Boost factor + * @drop_factor_5g: Penalty factor + * @max_raise_rssi_5g: Maximum amount of Boost that can added + * @cat_rssi_offset: + * @is_fils_roaming_supported: fils roaming supported + * @policy_params: roam policy params + * @neighbor_report_offload: neighbor report offload params + */ +struct rso_config_params { + uint8_t num_bssid_favored; + struct qdf_mac_addr bssid_favored[MAX_BSSID_FAVORED]; + uint8_t bssid_favored_factor[MAX_BSSID_FAVORED]; + int good_rssi_roam; + int alert_rssi_threshold; + int rssi_diff; + int raise_rssi_thresh_5g; + int drop_rssi_thresh_5g; + uint8_t raise_factor_5g; + uint8_t drop_factor_5g; + int max_raise_rssi_5g; + uint8_t cat_rssi_offset; + bool is_fils_roaming_supported; + struct rso_roam_policy_params policy_params; + struct cm_roam_neighbor_report_offload_params neighbor_report_offload; +}; + +/** + * enum roam_cfg_param - Type values for roaming parameters used as index + * for get/set of roaming config values(pNeighborRoamInfo in legacy) + * @RSSI_CHANGE_THRESHOLD: Rssi change threshold + * @BEACON_RSSI_WEIGHT: Beacon Rssi weight parameter + * @HI_RSSI_DELAY_BTW_SCANS: High Rssi delay between scans + * @EMPTY_SCAN_REFRESH_PERIOD: empty scan refresh period + * @FULL_ROAM_SCAN_PERIOD: Full roam scan period + * @ENABLE_SCORING_FOR_ROAM: enable scoring + * @SCAN_MIN_CHAN_TIME: scan min chan time + * @SCAN_MAX_CHAN_TIME: scan max chan time + * @NEIGHBOR_SCAN_PERIOD: neighbour scan period + * @ROAM_CONFIG_ENABLE: Roam config enable + * @ROAM_PREFERRED_CHAN: preferred channel list + * @ROAM_SPECIFIC_CHAN: specific channel list + * @ROAM_RSSI_DIFF: rssi diff + * @NEIGHBOUR_LOOKUP_THRESHOLD: lookup threshold + * @NEXT_RSSI_THRESHOLD: Next roam can trigger rssi threshold + * @SCAN_N_PROBE: scan n probe + * @SCAN_HOME_AWAY: scan and away + * @NEIGHBOUR_SCAN_REFRESH_PERIOD: scan refresh + * @ROAM_CONTROL_ENABLE: roam control enable + * @UAPSD_MASK: uapsd mask + * @MOBILITY_DOMAIN: mobility domain + * @IS_11R_CONNECTION: is 11r connection + * @ADAPTIVE_11R_CONNECTION: adaptive 11r + * @HS_20_AP: Hotspot 2.0 AP + * @MBO_OCE_ENABLED_AP: MBO/OCE enabled network + * @IS_SINGLE_PMK: + * @LOST_LINK_RSSI: lost link RSSI + * @ROAM_BAND: Allowed band for roaming in FW + * @HI_RSSI_SCAN_RSSI_DELTA: + * @ROAM_RSSI_DIFF_6GHZ: roam rssi diff for 6 GHz AP + * @IS_DISABLE_BTM: disable btm roaming + */ +enum roam_cfg_param { + RSSI_CHANGE_THRESHOLD, + BEACON_RSSI_WEIGHT, + HI_RSSI_DELAY_BTW_SCANS, + EMPTY_SCAN_REFRESH_PERIOD, + FULL_ROAM_SCAN_PERIOD, + ENABLE_SCORING_FOR_ROAM, + SCAN_MIN_CHAN_TIME, + SCAN_MAX_CHAN_TIME, + NEIGHBOR_SCAN_PERIOD, + ROAM_CONFIG_ENABLE, + ROAM_PREFERRED_CHAN, + ROAM_SPECIFIC_CHAN, + ROAM_RSSI_DIFF, + NEIGHBOUR_LOOKUP_THRESHOLD, + NEXT_RSSI_THRESHOLD, + SCAN_N_PROBE, + SCAN_HOME_AWAY, + NEIGHBOUR_SCAN_REFRESH_PERIOD, + ROAM_CONTROL_ENABLE, + UAPSD_MASK, + MOBILITY_DOMAIN, + IS_11R_CONNECTION, + ADAPTIVE_11R_CONNECTION, + HS_20_AP, + MBO_OCE_ENABLED_AP, + IS_SINGLE_PMK, + LOST_LINK_RSSI, + ROAM_BAND, + HI_RSSI_SCAN_RSSI_DELTA, + ROAM_RSSI_DIFF_6GHZ, + IS_DISABLE_BTM, +}; + +/** + * enum roam_offload_init_flags - Flags sent in Roam offload initialization. + * @WLAN_ROAM_FW_OFFLOAD_ENABLE: Init roaming module at firmware + * @WLAN_ROAM_BMISS_FINAL_SCAN_ENABLE: Enable partial scan after final beacon + * miss event at firmware + * @WLAN_ROAM_SKIP_EAPOL_4WAY_HANDSHAKE: Disable 4 Way-HS offload to firmware + * Setting this flag will make the eapol packets reach to host every time + * and can cause frequent APPS wake-ups. And clearing this flag will make + * eapol offload to firmware except for SAE and OWE roam. + * @WLAN_ROAM_BMISS_FINAL_SCAN_TYPE: Set this flag to skip full scan on final + * bmiss and use the channel map to do the partial scan alone + * @WLAN_ROAM_SKIP_SAE_ROAM_4WAY_HANDSHAKE: Disable 4 Way-HS offload to firmware + * Setting this flag will make the eapol packets reach to host and clearing this + * flag will make eapol offload to firmware including for SAE roam. + */ +enum roam_offload_init_flags { + WLAN_ROAM_FW_OFFLOAD_ENABLE = BIT(1), + WLAN_ROAM_BMISS_FINAL_SCAN_ENABLE = BIT(2), + WLAN_ROAM_SKIP_EAPOL_4WAY_HANDSHAKE = BIT(3), + WLAN_ROAM_BMISS_FINAL_SCAN_TYPE = BIT(4), + WLAN_ROAM_SKIP_SAE_ROAM_4WAY_HANDSHAKE = BIT(5) +}; + +/** + * struct wlan_roam_offload_init_params - Firmware roam module initialization + * parameters. Used to fill + * @vdev_id: vdev for which the roaming has to be enabled/disabled + * @roam_offload_flag: flag to init/deinit roam module + */ +struct wlan_roam_offload_init_params { + uint8_t vdev_id; + uint32_t roam_offload_flag; +}; + +/** + * struct wlan_cm_roam_vendor_btm_params - vendor config roam control param + * @scan_freq_scheme: scan frequency scheme from enum + * qca_roam_scan_freq_scheme + * @connected_rssi_threshold: RSSI threshold of the current + * connected AP + * @candidate_rssi_threshold_2g: RSSI threshold of the + * candidate AP in 2.4Ghz band + * @candidate_rssi_threshold_5g: RSSI threshold of the candidate AP in 5Ghz + * band + * @candidate_rssi_threshold_6g: RSSI threshold of the candidate AP in 6Ghz + * band + * @user_roam_reason: Roam triggered reason code, value zero is for enable + * and non zero value is disable + */ +struct wlan_cm_roam_vendor_btm_params { + uint32_t scan_freq_scheme; + uint32_t connected_rssi_threshold; + uint32_t candidate_rssi_threshold_2g; + uint32_t candidate_rssi_threshold_5g; + uint32_t candidate_rssi_threshold_6g; + uint32_t user_roam_reason; +}; + +/** + * struct ap_profile - Structure ap profile to match candidate + * @flags: flags + * @rssi_threshold: the value of the the candidate AP should higher by this + * threshold than the rssi of the currently associated AP + * @ssid: ssid value to be matched + * @rsn_authmode: security params to be matched + * @rsn_ucastcipherset: unicast cipher set + * @rsn_mcastcipherset: mcast/group cipher set + * @rsn_mcastmgmtcipherset: mcast/group management frames cipher set + * @rssi_abs_thresh: the value of the candidate AP should higher than this + * absolute RSSI threshold. Zero means no absolute minimum + * RSSI is required. units are the offset from the noise + * floor in dB + * @bg_rssi_threshold: Value of rssi threshold to trigger roaming + * after background scan. + * @num_allowed_authmode: Number of allowerd authmode + * @allowed_authmode: List of allowed authmode other than connected + */ +struct ap_profile { + uint32_t flags; + uint32_t rssi_threshold; + struct wlan_ssid ssid; + uint32_t rsn_authmode; + uint32_t rsn_ucastcipherset; + uint32_t rsn_mcastcipherset; + uint32_t rsn_mcastmgmtcipherset; + uint32_t rssi_abs_thresh; + uint8_t bg_rssi_threshold; + uint32_t num_allowed_authmode; + uint32_t allowed_authmode[WLAN_CRYPTO_AUTH_MAX]; +}; + +/** + * struct scoring_param - scoring param to sortlist selected AP + * @disable_bitmap: Each bit will be either allow(0)/disallow(1) to + * considered the roam score param. + * @rssi_weightage: RSSI weightage out of total score in % + * @ht_weightage: HT weightage out of total score in %. + * @vht_weightage: VHT weightage out of total score in %. + * @he_weightage: 11ax weightage out of total score in %. + * @bw_weightage: Bandwidth weightage out of total score in %. + * @band_weightage: Band(2G/5G) weightage out of total score in %. + * @nss_weightage: NSS(1x1 / 2x2)weightage out of total score in %. + * @esp_qbss_weightage: ESP/QBSS weightage out of total score in %. + * @beamforming_weightage: Beamforming weightage out of total score in %. + * @pcl_weightage: PCL weightage out of total score in %. + * @oce_wan_weightage: OCE WAN metrics weightage out of total score in %. + * @oce_ap_tx_pwr_weightage: OCE AP TX power score in % + * @oce_subnet_id_weightage: OCE subnet id score in % + * @sae_pk_ap_weightage: SAE-PK AP score in % + * @bw_index_score: channel BW scoring percentage information. + * BITS 0-7 :- It contains scoring percentage of 20MHz BW + * BITS 8-15 :- It contains scoring percentage of 40MHz BW + * BITS 16-23 :- It contains scoring percentage of 80MHz BW + * BITS 24-31 :- It contains scoring percentage of 1600MHz BW + * The value of each index must be 0-100 + * @band_index_score: band scording percentage information. + * BITS 0-7 :- It contains scoring percentage of 2G + * BITS 8-15 :- It contains scoring percentage of 5G + * BITS 16-23 :- reserved + * BITS 24-31 :- reserved + * The value of each index must be 0-100 + * @nss_index_score: NSS scoring percentage information. + * BITS 0-7 :- It contains scoring percentage of 1x1 + * BITS 8-15 :- It contains scoring percentage of 2x2 + * BITS 16-23 :- It contains scoring percentage of 3x3 + * BITS 24-31 :- It contains scoring percentage of 4x4 + * The value of each index must be 0-100 + * @roam_score_delta: delta value expected over the roam score of the candidate + * ap over the roam score of the current ap + * @roam_trigger_bitmap: bitmap of roam triggers on which roam_score_delta + * will be applied + * @vendor_roam_score_algorithm: Preferred algorithm for roam candidate + * selection + * @cand_min_roam_score_delta: candidate min roam score delta value + * @rssi_scoring: RSSI scoring information. + * @esp_qbss_scoring: ESP/QBSS scoring percentage information + * @oce_wan_scoring: OCE WAN metrics percentage information + * @eht_caps_weightage: EHT caps weightage out of total score in % + * @mlo_weightage: MLO weightage out of total score in % + * @security_weightage: Security(WPA/WPA2/WPA3) weightage out of + * total score in % + * @security_index_score: Security scoring percentage information. + * BITS 0-7 :- It contains scoring percentage of WPA security + * BITS 8-15 :- It contains scoring percentage of WPA2 security + * BITS 16-23 :- It contains scoring percentage of WPA3 security + * BITS 24-31 :- reserved + * The value of each index must be 0-100 + */ +struct scoring_param { + uint32_t disable_bitmap; + int32_t rssi_weightage; + int32_t ht_weightage; + int32_t vht_weightage; + int32_t he_weightage; + int32_t bw_weightage; + int32_t band_weightage; + int32_t nss_weightage; + int32_t esp_qbss_weightage; + int32_t beamforming_weightage; + int32_t pcl_weightage; + int32_t oce_wan_weightage; + uint32_t oce_ap_tx_pwr_weightage; + uint32_t oce_subnet_id_weightage; + uint32_t sae_pk_ap_weightage; + uint32_t bw_index_score; + uint32_t band_index_score; + uint32_t nss_index_score; + uint32_t roam_score_delta; + uint32_t roam_trigger_bitmap; + uint32_t vendor_roam_score_algorithm; + uint32_t cand_min_roam_score_delta; + struct rssi_config_score rssi_scoring; + struct per_slot_score esp_qbss_scoring; + struct per_slot_score oce_wan_scoring; +#ifdef WLAN_FEATURE_11BE_MLO + uint8_t eht_caps_weightage; + uint8_t mlo_weightage; +#endif + int32_t security_weightage; + uint32_t security_index_score; +}; + +/** + * enum roam_invoke_reason - Roam invoke reason. + * + * @WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED: Default value when target + * invoke roam. + * @WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE: Neighbor unreachable + * detection failed when the roam trigger. + * @WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE: Invoke from user space. + */ +enum roam_invoke_reason { + WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED = 0, + WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE = 1, + WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE = 2, +}; + +/** + * enum roam_tx_failures_reason - Roam TX failures reason. + * + * @WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED: Default value when + * roam by kickout. + * @WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY: Excessive retry when roam + * trigger by kickout. + * @WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY: Station inactivity when + * roam trigger by kickout. + * @WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT: IBSS disconnect when + * roam trigger by kickout. + * @WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT: TDLS peer has + * disappeared, and all TX is failing when roam trigger by kickout. + * @WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT: SA query process + * timeout when roam trigger by kickout. + * @WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT: Directly connected + * peer has roamed to a repeater. + */ +enum roam_tx_failures_reason { + WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED = 0, + WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY = 1, + WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY = 2, + WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT = 3, + WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT = 4, + WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT = 5, + WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT = 6, +}; + +/** + * enum roam_abort_reason - Roam abort reason. + * + * @WLAN_ROAM_STATS_ABORT_UNSPECIFIED: Target did not specify the + * detailed reason for roam scan being aborted. + * @WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH: Roam scan is not + * started due to high data RSSI during LOW-RSSI roaming. + * @WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD: Roam scan is not + * started due to good link speed during LOW-RSSI roaming. + * @WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH: Roam scan is not started + * due to high data RSSI during background roaming. + * @WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD: Roam scan is not + * started due to high beacon RSSI during background roaming + */ +enum roam_abort_reason { + WLAN_ROAM_STATS_ABORT_UNSPECIFIED = 0, + WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH = 1, + WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD = 2, + WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH = 3, + WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD = 4, +}; + +/** + * enum roam_scan_dwell_type - Roam scan dwell type defines + * @WLAN_ROAM_DWELL_TYPE_UNSPECIFIED: Target did not specify the + * detailed roam scan type. + * @WLAN_ROAM_DWELL_ACTIVE_TYPE: active scan during roam + * @WLAN_ROAM_DWELL_PASSIVE_TYPE: passive scan during roam. + */ +enum roam_scan_dwell_type { + WLAN_ROAM_DWELL_TYPE_UNSPECIFIED = 0, + WLAN_ROAM_DWELL_ACTIVE_TYPE = 1, + WLAN_ROAM_DWELL_PASSIVE_TYPE = 2, +}; + +/** + * enum eroam_frame_subtype - Enhanced roam frame subtypes. + * + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_INVALID: Invalid subtype + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP: Authentication resp frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP: Reassociation resp frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1: EAPOL-Key M1 frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2: EAPOL-Key M2 frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3: EAPOL-Key M3 frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4: EAPOL-Key M4 frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1: EAPOL-Key GTK M1 frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2: EAPOL-Key GTK M2 frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ: Authentication req frame + * @WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ: Reassociation req frame + */ +enum eroam_frame_subtype { + WLAN_ROAM_STATS_FRAME_SUBTYPE_INVALID = 0, + WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP = 1, + WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP = 2, + WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1 = 3, + WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2 = 4, + WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3 = 5, + WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4 = 6, + WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1 = 7, + WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2 = 8, + WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ = 9, + WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ = 10, +}; + +/** + * enum eroam_frame_status - Specifies the valid values of roam frame status + * + * @WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS: indicates the roam frame was + * sent or received successfully. + * @WLAN_ROAM_STATS_FRAME_STATUS_FAIL: indicates the roam frame sending or + * receiving failed. + */ +enum eroam_frame_status { + WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS = 0, + WLAN_ROAM_STATS_FRAME_STATUS_FAIL = 1, +}; + +/** + * enum roam_trigger_reason - Reason for triggering roam + * @ROAM_TRIGGER_REASON_NONE: Roam trigger reason none + * @ROAM_TRIGGER_REASON_PER: Roam triggered due to packet error + * @ROAM_TRIGGER_REASON_BMISS: Roam triggered due to beacon miss + * @ROAM_TRIGGER_REASON_LOW_RSSI: Roam triggered due to low RSSI of current + * connected AP. + * @ROAM_TRIGGER_REASON_HIGH_RSSI: Roam triggered because sta is connected to + * a AP in 2.4GHz band and a better 5GHz AP is available + * @ROAM_TRIGGER_REASON_PERIODIC: Roam triggered as better AP was found during + * periodic roam scan. + * @ROAM_TRIGGER_REASON_MAWC: Motion Aided WiFi Connectivity triggered roam. + * @ROAM_TRIGGER_REASON_DENSE: Roaming triggered due to dense environment + * detected. + * @ROAM_TRIGGER_REASON_BACKGROUND: Roam triggered due to current AP having + * poor rssi and scan candidate found in scan results provided by other + * scan clients. + * @ROAM_TRIGGER_REASON_FORCED: Forced roam trigger. + * @ROAM_TRIGGER_REASON_BTM: Roam triggered due to AP sent BTM query with + * Disassoc imminent bit set. + * @ROAM_TRIGGER_REASON_UNIT_TEST: Roam triggered due to unit test command. + * @ROAM_TRIGGER_REASON_BSS_LOAD: Roam triggered due to high channel utilization + * in the current connected channel + * @ROAM_TRIGGER_REASON_DEAUTH: Roam triggered due to deauth received from the + * current connected AP. + * @ROAM_TRIGGER_REASON_IDLE: Roam triggered due to inactivity of the device. + * @ROAM_TRIGGER_REASON_STA_KICKOUT: Roam triggered due to sta kickout event. + * @ROAM_TRIGGER_REASON_ESS_RSSI: Roam triggered due to ess rssi + * @ROAM_TRIGGER_REASON_WTC_BTM: Roam triggered due to WTC BTM + * @ROAM_TRIGGER_REASON_PMK_TIMEOUT: Roam triggered due to PMK expiry + * @ROAM_TRIGGER_REASON_BTC: Roam triggered due to BT Coex + * @ROAM_TRIGGER_REASON_MAX: Maximum number of roam triggers + */ +enum roam_trigger_reason { + ROAM_TRIGGER_REASON_NONE = 0, + ROAM_TRIGGER_REASON_PER, + ROAM_TRIGGER_REASON_BMISS, + ROAM_TRIGGER_REASON_LOW_RSSI, + ROAM_TRIGGER_REASON_HIGH_RSSI, + ROAM_TRIGGER_REASON_PERIODIC, + ROAM_TRIGGER_REASON_MAWC, + ROAM_TRIGGER_REASON_DENSE, + ROAM_TRIGGER_REASON_BACKGROUND, + ROAM_TRIGGER_REASON_FORCED, + ROAM_TRIGGER_REASON_BTM, + ROAM_TRIGGER_REASON_UNIT_TEST, + ROAM_TRIGGER_REASON_BSS_LOAD, + ROAM_TRIGGER_REASON_DEAUTH, + ROAM_TRIGGER_REASON_IDLE, + ROAM_TRIGGER_REASON_STA_KICKOUT, + ROAM_TRIGGER_REASON_ESS_RSSI, + ROAM_TRIGGER_REASON_WTC_BTM, + ROAM_TRIGGER_REASON_PMK_TIMEOUT, + ROAM_TRIGGER_REASON_BTC, + ROAM_TRIGGER_REASON_MAX, +}; + +/** + * struct roam_trigger_min_rssi - structure to hold minimum rssi value of + * candidate APs for each roam trigger + * @min_rssi: minimum RSSI of candidate AP for the trigger reason specified in + * trigger_id + * @trigger_reason: Roam trigger reason + */ +struct roam_trigger_min_rssi { + int32_t min_rssi; + enum roam_trigger_reason trigger_reason; +}; + +/** + * struct roam_trigger_score_delta - structure to hold roam score delta value of + * candidate APs for each roam trigger + * @roam_score_delta: delta value in score of the candidate AP for the roam + * trigger mentioned in the trigger_id. + * @trigger_reason: Roam trigger reason + */ +struct roam_trigger_score_delta { + uint32_t roam_score_delta; + enum roam_trigger_reason trigger_reason; +}; + +/** + * struct wlan_roam_triggers - vendor configured roam triggers + * @vdev_id: vdev id + * @trigger_bitmap: vendor configured roam trigger bitmap as + * defined @enum roam_control_trigger_reason + * @roam_score_delta: Value of roam score delta + * percentage to trigger roam + * @roam_scan_scheme_bitmap: Bitmap of roam triggers as defined in + * enum roam_trigger_reason, for which the roam scan scheme should + * be partial scan + * @vendor_btm_param: roam trigger param + * @min_rssi_params: Min RSSI values for different roam triggers + * @score_delta_param: Roam score delta values for different triggers + */ +struct wlan_roam_triggers { + uint32_t vdev_id; + uint32_t trigger_bitmap; + uint32_t roam_score_delta; + uint32_t roam_scan_scheme_bitmap; + struct wlan_cm_roam_vendor_btm_params vendor_btm_param; + struct roam_trigger_min_rssi min_rssi_params[NUM_OF_ROAM_MIN_RSSI]; + struct roam_trigger_score_delta score_delta_param[NUM_OF_ROAM_TRIGGERS]; +}; + +/** + * struct ap_profile_params - ap profile params + * @vdev_id: vdev id + * @profile: ap profile to match candidate + * @param: scoring params to short candidate + * @min_rssi_params: Min RSSI values for different roam triggers + * @score_delta_param: Roam score delta values for different triggers + * @owe_ap_profile: owe ap profile info + */ +struct ap_profile_params { + uint8_t vdev_id; + struct ap_profile profile; + struct scoring_param param; + struct roam_trigger_min_rssi min_rssi_params[NUM_OF_ROAM_MIN_RSSI]; + struct roam_trigger_score_delta score_delta_param[NUM_OF_ROAM_TRIGGERS]; + struct owe_transition_mode_info owe_ap_profile; +}; + +/** + * struct wlan_roam_mawc_params - Motion Aided wireless connectivity params + * @vdev_id: VDEV on which the parameters should be applied + * @enable: MAWC roaming feature enable/disable + * @traffic_load_threshold: Traffic threshold in kBps for MAWC roaming + * @best_ap_rssi_threshold: AP RSSI Threshold for MAWC roaming + * @rssi_stationary_high_adjust: High RSSI adjustment value to suppress scan + * @rssi_stationary_low_adjust: Low RSSI adjustment value to suppress scan + */ +struct wlan_roam_mawc_params { + uint8_t vdev_id; + bool enable; + uint32_t traffic_load_threshold; + uint32_t best_ap_rssi_threshold; + uint8_t rssi_stationary_high_adjust; + uint8_t rssi_stationary_low_adjust; +}; + +/** + * struct roam_scan_filter_params - Structure holding roaming scan + * parameters + * @op_bitmap: bitmap to determine reason of roaming + * @vdev_id: vdev id + * @num_bssid_deny_list: The number of BSSID's that we should avoid + * connecting to. It is like a denylist of BSSID's. + * @num_ssid_allow_list: The number of SSID profiles that are in the + * Allowlist. When roaming, we consider the BSSID's with + * this SSID also for roaming apart from the connected + * one's + * @num_bssid_preferred_list: Number of BSSID's which have a preference over + * others + * @bssid_avoid_list: Denylist SSID's + * @ssid_allowed_list: Allowlist SSID's + * @bssid_favored: Favorable BSSID's + * @bssid_favored_factor: RSSI to be added to this BSSID to prefer it + * @lca_disallow_config_present: LCA [Last Connected AP] disallow config + * present + * @disallow_duration: How long LCA AP will be disallowed before it can be a + * roaming candidate again, in seconds + * @rssi_channel_penalization: How much RSSI will be penalized if candidate(s) + * are found in the same channel as disallowed + * AP's, in units of db + * @num_disallowed_aps: How many APs the target should maintain in its LCA + * list + * @num_rssi_rejection_ap: Number of entries in @rssi_rejection_ap + * @rssi_rejection_ap: APs rejected due to poor RSSI + * @delta_rssi: (dB units) when AB in RSSI denylist improved by at least + * delta_rssi,it will be removed from denylist + * + * This structure holds all the key parameters related to + * initial connection and roaming connections. + */ + +struct roam_scan_filter_params { + uint32_t op_bitmap; + uint8_t vdev_id; + uint32_t num_bssid_deny_list; + uint32_t num_ssid_allow_list; + uint32_t num_bssid_preferred_list; + struct qdf_mac_addr bssid_avoid_list[MAX_BSSID_AVOID_LIST]; + struct wlan_ssid ssid_allowed_list[MAX_SSID_ALLOWED_LIST]; + struct qdf_mac_addr bssid_favored[MAX_BSSID_FAVORED]; + uint8_t bssid_favored_factor[MAX_BSSID_FAVORED]; + uint8_t lca_disallow_config_present; + uint32_t disallow_duration; + uint32_t rssi_channel_penalization; + uint32_t num_disallowed_aps; + uint32_t num_rssi_rejection_ap; + struct reject_ap_config_params + rssi_rejection_ap[MAX_RSSI_AVOID_BSSID_LIST]; + uint32_t delta_rssi; +}; + +/** + * struct wlan_roam_scan_filter_params - structure containing parameters for + * roam scan offload filter + * @reason: reason for changing roam state for the requested vdev id + * @filter_params: roam scan filter parameters + */ +struct wlan_roam_scan_filter_params { + uint8_t reason; + struct roam_scan_filter_params filter_params; +}; + +/** + * struct wlan_roam_btm_config - BSS Transition Management offload params + * @vdev_id: VDEV on which the parameters should be applied + * @btm_offload_config: BTM config + * @btm_solicited_timeout: Timeout value for waiting BTM request + * @btm_max_attempt_cnt: Maximum attempt for sending BTM query to ESS + * @btm_sticky_time: Stick time after roaming to new AP by BTM + * @disassoc_timer_threshold: threshold value till which the firmware can + * wait before triggering the roam scan after receiving the disassoc imminent + * @btm_query_bitmask: bitmask to btm query with candidate list + * @btm_candidate_min_score: Minimum score of the AP to consider it as a + * candidate if the roam trigger is BTM kickout. + */ +struct wlan_roam_btm_config { + uint8_t vdev_id; + uint32_t btm_offload_config; + uint32_t btm_solicited_timeout; + uint32_t btm_max_attempt_cnt; + uint32_t btm_sticky_time; + uint32_t disassoc_timer_threshold; + uint32_t btm_query_bitmask; + uint32_t btm_candidate_min_score; +}; + +/** + * struct wlan_roam_neighbor_report_params -neighbour report params + * @time_offset: time offset after 11k offload command to trigger a neighbor + * report request (in seconds) + * @low_rssi_offset: Offset from rssi threshold to trigger a neighbor + * report request (in dBm) + * @bmiss_count_trigger: Number of beacon miss events to trigger neighbor + * report request + * @per_threshold_offset: offset from PER threshold to trigger neighbor + * report request (in %) + * @neighbor_report_cache_timeout: timeout after which new trigger can enable + * sending of a neighbor report request (in seconds) + * @max_neighbor_report_req_cap: max number of neighbor report requests that + * can be sent to the peer in the current session + * @ssid: Current connect SSID info + */ +struct wlan_roam_neighbor_report_params { + uint32_t time_offset; + uint32_t low_rssi_offset; + uint32_t bmiss_count_trigger; + uint32_t per_threshold_offset; + uint32_t neighbor_report_cache_timeout; + uint32_t max_neighbor_report_req_cap; + struct wlan_ssid ssid; +}; + +/** + * struct wlan_roam_11k_offload_params - offload 11k features to FW + * @vdev_id: vdev id + * @offload_11k_bitmask: bitmask to specify offloaded features + * B0: Neighbor Report Request offload + * B1-B31: Reserved + * @neighbor_report_params: neighbor report offload params + */ +struct wlan_roam_11k_offload_params { + uint32_t vdev_id; + uint32_t offload_11k_bitmask; + struct wlan_roam_neighbor_report_params neighbor_report_params; +}; + +/** + * struct wlan_roam_bss_load_config - BSS load trigger parameters + * @vdev_id: VDEV on which the parameters should be applied + * @bss_load_threshold: BSS load threshold after which roam scan should trigger + * @bss_load_sample_time: Time duration in milliseconds for which the bss load + * trigger needs to be enabled + * @rssi_threshold_6ghz: RSSI threshold of the current connected AP below which + * roam should be triggered if bss load threshold exceeds the configured value. + * This value is applicable only when we are connected in 6GHz band. + * @rssi_threshold_5ghz: RSSI threshold of the current connected AP below which + * roam should be triggered if bss load threshold exceeds the configured value. + * This value is applicable only when we are connected in 5GHz band. + * @rssi_threshold_24ghz: RSSI threshold of the current connected AP below which + * roam should be triggered if bss load threshold exceeds the configured value. + * This value is applicable only when we are connected in 2.4GHz band. + */ +struct wlan_roam_bss_load_config { + uint32_t vdev_id; + uint32_t bss_load_threshold; + uint32_t bss_load_sample_time; + int32_t rssi_threshold_6ghz; + int32_t rssi_threshold_5ghz; + int32_t rssi_threshold_24ghz; +}; + +/** + * struct roam_disable_cfg - Firmware roam module disable parameters + * @vdev_id: vdev for which the roaming has to be enabled/disabled + * @cfg: Config to enable/disable FW roam module + */ +struct roam_disable_cfg { + uint8_t vdev_id; + uint8_t cfg; +}; + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * struct vendor_handoff_cfg - vendor handoff command params + * @vdev_id: vdev for which host sends vendor handoff command + * @param_id: parameter id + */ +struct vendor_handoff_cfg { + uint32_t vdev_id; + uint32_t param_id; +}; +#endif + +/** + * struct wlan_roam_disconnect_params - Emergency deauth/disconnect roam params + * @vdev_id: VDEV on which the parameters should be applied + * @enable: Enable or disable disconnect roaming. + */ +struct wlan_roam_disconnect_params { + uint32_t vdev_id; + bool enable; +}; + +/** + * struct wlan_roam_idle_params - Idle roam trigger parameters + * @vdev_id: VDEV on which the parameters should be applied + * @enable: Enable/Disable Idle roaming + * @band: Connected AP band + * @conn_ap_rssi_delta: Rssi change of connected AP in dBm + * @conn_ap_min_rssi: If connected AP rssi is less than min rssi trigger roam + * @inactive_time: Connected AP idle time + * @data_pkt_count: Data packet count allowed during idle time + */ +struct wlan_roam_idle_params { + uint32_t vdev_id; + bool enable; + uint32_t band; + uint32_t conn_ap_rssi_delta; + int32_t conn_ap_min_rssi; + uint32_t inactive_time; + uint32_t data_pkt_count; +}; + +/** + * struct wlan_per_roam_config - per based roaming parameters + * @enable: if PER based roaming is enabled/disabled + * @tx_high_rate_thresh: high rate threshold at which PER based + * roam will stop in tx path + * @rx_high_rate_thresh: high rate threshold at which PER based + * roam will stop in rx path + * @tx_low_rate_thresh: rate below which traffic will be considered + * for PER based roaming in Tx path + * @rx_low_rate_thresh: rate below which traffic will be considered + * for PER based roaming in Tx path + * @tx_rate_thresh_percnt: % above which when traffic is below low_rate_thresh + * will be considered for PER based scan in tx path + * @rx_rate_thresh_percnt: % above which when traffic is below low_rate_thresh + * will be considered for PER based scan in rx path + * @per_rest_time: time for which PER based roam will wait once it + * issues a roam scan. + * @tx_per_mon_time: Minimum time required to be considered as valid scenario + * for PER based roam in tx path + * @rx_per_mon_time: Minimum time required to be considered as valid scenario + * for PER based roam in rx path + * @min_candidate_rssi: Minimum RSSI threshold for candidate AP to be used for + * PER based roaming + */ +struct wlan_per_roam_config { + uint32_t enable; + uint32_t tx_high_rate_thresh; + uint32_t rx_high_rate_thresh; + uint32_t tx_low_rate_thresh; + uint32_t rx_low_rate_thresh; + uint32_t tx_rate_thresh_percnt; + uint32_t rx_rate_thresh_percnt; + uint32_t per_rest_time; + uint32_t tx_per_mon_time; + uint32_t rx_per_mon_time; + uint32_t min_candidate_rssi; +}; + +/** + * struct wlan_per_roam_config_req: PER based roaming config request + * @vdev_id: vdev id on which config needs to be set + * @per_config: PER config + */ +struct wlan_per_roam_config_req { + uint8_t vdev_id; + struct wlan_per_roam_config per_config; +}; + +#define NOISE_FLOOR_DBM_DEFAULT (-96) +#define RSSI_MIN_VALUE (-128) +#define RSSI_MAX_VALUE (127) + +#ifdef WLAN_FEATURE_FILS_SK +#define WLAN_FILS_MAX_USERNAME_LENGTH 16 + +/** + * struct wlan_roam_fils_params - Roaming FILS params + * @next_erp_seq_num: next ERP sequence number + * @username: username + * @username_length: username length + * @rrk: RRK + * @rrk_length: length of @rrk + * @rik: RIK + * @rik_length: length of @rik + * @realm: realm + * @realm_len: length of @realm + * @fils_ft: xx_key for FT-FILS connection + * @fils_ft_len: length of FT-FILS + */ +struct wlan_roam_fils_params { + uint32_t next_erp_seq_num; + uint8_t username[WLAN_FILS_MAX_USERNAME_LENGTH]; + uint32_t username_length; + uint8_t rrk[WLAN_FILS_MAX_RRK_LENGTH]; + uint32_t rrk_length; + uint8_t rik[WLAN_FILS_MAX_RIK_LENGTH]; + uint32_t rik_length; + uint8_t realm[WLAN_FILS_MAX_REALM_LEN]; + uint32_t realm_len; + uint8_t fils_ft[WLAN_FILS_FT_MAX_LEN]; + uint8_t fils_ft_len; +}; +#endif + +/** + * struct wlan_roam_scan_params - Roaming scan parameters + * @vdev_id: vdev id + * @dwell_time_passive: dwell time in msec on passive channels + * @dwell_time_active: dwell time in msec on active channels + * @min_dwell_time_6ghz: minimum dwell time in msec for 6 GHz channel + * @burst_duration: Burst duration time in msec + * @min_rest_time: min time in msec on the BSS channel,only valid if atleast + * one VDEV is active + * @max_rest_time: max rest time in msec on the BSS channel,only valid if + * at least one VDEV is active + * @probe_spacing_time: time in msec between 2 consecutive probe requests with + * in a set + * @probe_delay: delay in msec before sending first probe request after + * switching to a channel + * @repeat_probe_time: time in msec between 2 consecutive probe requests within + * a set + * @max_scan_time: maximum time in msec allowed for scan + * @idle_time: data inactivity time in msec on bss channel that will be used by + * scanner for measuring the inactivity + * @n_probes: Max number of probes to be sent + * @scan_ctrl_flags: Scan control flags + * @scan_ctrl_flags_ext: Scan control flags extended + * @rso_adaptive_dwell_mode: Adaptive dwell mode + * @num_chan: number of channels + * @num_bssid: number of bssids in tlv bssid_list[] + * @ie_len: number of bytes in ie data. In the TLV ie_data[] + * @dwell_time_active_2g: dwell time in msec on active 2G channels. + * @dwell_time_active_6ghz: dwell time in msec when 6 GHz channel + * @dwell_time_passive_6ghz: Passive scan dwell time in msec for 6Ghz channel. + * @scan_start_offset: Offset time is in milliseconds per channel + */ +struct wlan_roam_scan_params { + uint32_t vdev_id; + uint32_t dwell_time_passive; + uint32_t dwell_time_active; + uint32_t min_dwell_time_6ghz; + uint32_t burst_duration; + uint32_t min_rest_time; + uint32_t max_rest_time; + uint32_t probe_spacing_time; + uint32_t probe_delay; + uint32_t repeat_probe_time; + uint32_t max_scan_time; + uint32_t idle_time; + uint32_t n_probes; + uint32_t scan_ctrl_flags; + uint32_t scan_ctrl_flags_ext; + enum scan_dwelltime_adaptive_mode rso_adaptive_dwell_mode; + uint32_t num_chan; + uint32_t num_bssid; + uint32_t ie_len; + uint32_t dwell_time_active_2g; + uint32_t dwell_time_active_6ghz; + uint32_t dwell_time_passive_6ghz; + uint32_t scan_start_offset; +}; + +/** + * struct wlan_roam_scan_mode_params - WMI_ROAM_SCAN_MODE command fixed_param + * wmi_roam_scan_mode_fixed_param related params + * @roam_scan_mode: Roam scan mode flags + * @min_delay_btw_scans: Minimum duration allowed between two consecutive roam + * scans in millisecs. + * @min_delay_roam_trigger_bitmask: Roaming triggers for which the min delay + * between roam scans is applicable(bitmask of enum WMI_ROAM_TRIGGER_REASON_ID) + */ +struct wlan_roam_scan_mode_params { + uint32_t roam_scan_mode; + uint32_t min_delay_btw_scans; + uint32_t min_delay_roam_trigger_bitmask; +}; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * struct wlan_rso_lfr3_params - LFR-3.0 roam offload params to be filled + * in the wmi_roam_offload_tlv_param TLV of WMI_ROAM_SCAN_MODE command. + * @roam_rssi_cat_gap: RSSI category gap + * @prefer_5ghz: Prefer 5G candidate AP + * @select_5ghz_margin: Prefer connecting to 5G AP even if its RSSI is lower by + * select_5g_margin dBm + * @reassoc_failure_timeout: reassociation response failure timeout + * @ho_delay_for_rx: Time in millisecs to delay hand-off by this duration to + * receive pending Rx frames from current BSS + * @roam_retry_count: maximum number of software retries for preauth and + * reassoc req + * @roam_preauth_no_ack_timeout: duration in millsecs to wait before another SW + * retry made if no ack seen for previous frame + * @disable_self_roam: Disable roaming to current connected BSS. + * @rct_validity_timer: duration value for which the entries in + * roam candidate table(rct) are valid + */ +struct wlan_rso_lfr3_params { + uint8_t roam_rssi_cat_gap; + uint8_t prefer_5ghz; + uint8_t select_5ghz_margin; + uint32_t reassoc_failure_timeout; + uint32_t ho_delay_for_rx; + uint32_t roam_retry_count; + uint32_t roam_preauth_no_ack_timeout; + bool disable_self_roam; + uint32_t rct_validity_timer; +}; + +#define WLAN_ROAM_OFFLOAD_NUM_MCS_SET (16) +/** + * struct wlan_rso_lfr3_caps - LFR3 Roaming offload parameters + * @capability: RSN capabilities + * @ht_caps_info: HT capabilities information + * @ampdu_param: AMPDU configs + * @ht_ext_cap: HT extended capabilities info + * @ht_txbf: HT Tx Beamform capabilities + * @asel_cap: Antena selection capabilities + * @qos_enabled: QoS enabled + * @qos_caps: QoS capabilities + * @wmm_caps: WMM capabilities + * @mcsset: MCS set + */ +struct wlan_rso_lfr3_caps { + uint32_t capability; + uint32_t ht_caps_info; + uint32_t ampdu_param; + uint32_t ht_ext_cap; + uint32_t ht_txbf; + uint32_t asel_cap; + uint32_t qos_enabled; + uint32_t qos_caps; + uint32_t wmm_caps; + /* since this is 4 byte aligned, we don't declare it as tlv array */ + uint32_t mcsset[WLAN_ROAM_OFFLOAD_NUM_MCS_SET >> 2]; +}; + +/** + * struct wlan_rso_11i_params - LFR-3.0 related parameters to be filled in + * wmi_roam_11i_offload_tlv_param TLV in the WMI_ROAM_SCAN_MODE command. + * @roam_key_mgmt_offload_enabled: Enable 4-way HS offload to firmware + * @fw_okc: use OKC in firmware + * @fw_pmksa_cache: use PMKSA cache in firmware + * @is_sae_same_pmk: Flag to indicate fw whether WLAN_SAE_SINGLE_PMK feature is + * enable or not + * @psk_pmk: pre shared key/pairwise master key + * @pmk_len: length of PMK + */ +struct wlan_rso_11i_params { + bool roam_key_mgmt_offload_enabled; + bool fw_okc; + bool fw_pmksa_cache; + bool is_sae_same_pmk; + uint8_t psk_pmk[MAX_PMK_LEN]; + uint8_t pmk_len; +}; + +/** + * struct wlan_rso_11r_params - LFR-3.0 parameters to fill + * wmi_roam_11r_offload_tlv_param TLV related info in WMI_ROAM_SCAN_MODE command + * @is_11r_assoc: + * @is_adaptive_11r: + * @enable_ft_im_roaming: Flag to enable/disable FT-IM roaming upon receiving + * deauth + * @psk_pmk: key material + * @pmk_len: length of key material + * @r0kh_id_length: r0kh id length + * @r0kh_id: r0kh id + * @mdid: mobility domain info + * @enable_ft_over_ds: Flag to enable/disable FT-over-DS + */ +struct wlan_rso_11r_params { + bool is_11r_assoc; + bool is_adaptive_11r; + bool enable_ft_im_roaming; + uint8_t psk_pmk[MAX_PMK_LEN]; + uint8_t pmk_len; + uint32_t r0kh_id_length; + uint8_t r0kh_id[WMI_ROAM_R0KH_ID_MAX_LEN]; + struct mobility_domain_info mdid; + bool enable_ft_over_ds; +}; + +/** + * struct wlan_rso_ese_params - LFR-3.0 parameters to fill the + * wmi_roam_ese_offload_tlv_param TLV related info in WMI_ROAM_SCAN_MODE command + * @is_ese_assoc: flag to determine ese assoc + * @krk: KRK + * @btk: BTK + */ +struct wlan_rso_ese_params { + bool is_ese_assoc; + uint8_t krk[WMI_KRK_KEY_LEN]; + uint8_t btk[WMI_BTK_KEY_LEN]; +}; + +/** + * struct wlan_rso_sae_offload_params - SAE authentication offload related + * parameters. + * @spmk_timeout: Single PMK timeout value in seconds. + */ +struct wlan_rso_sae_offload_params { + uint32_t spmk_timeout; +}; +#endif + +#define ROAM_SCAN_DWELL_TIME_ACTIVE_DEFAULT (100) +#define ROAM_SCAN_DWELL_TIME_PASSIVE_DEFAULT (110) +#define ROAM_SCAN_MIN_REST_TIME_DEFAULT (50) +#define ROAM_SCAN_MAX_REST_TIME_DEFAULT (500) +#define ROAM_SCAN_HW_DEF_SCAN_MAX_DURATION 30000 /* 30 secs */ +#define ROAM_SCAN_CHANNEL_SWITCH_TIME (4) + +/** + * struct wlan_roam_scan_offload_params - structure containing roaming offload + * scan parameters to be filled over WMI_ROAM_SCAN_MODE command. + * @vdev_id: vdev id + * @is_rso_stop: flag to tell whether roam req is valid or NULL + * @roaming_scan_policy: + * @rso_mode_info: Roam scan mode related parameters + * @rso_scan_params: Roam scan offload scan start params + * @scan_params: Roaming scan related parameters + * @assoc_ie_length: Assoc IE length + * @assoc_ie: Assoc IE buffer + * @roam_offload_enabled: flag for offload enable + * @add_fils_tlv: add FILS TLV boolean + * @akm: authentication key management mode + * @rso_lfr3_params: Candidate selection and other lfr-3.0 offload parameters + * @rso_lfr3_caps: Self capabilities + * @rso_11i_info: PMK, PMKSA, SAE single PMK related parameters + * @rso_11r_info: FT related parameters + * @rso_ese_info: ESE related parameters + * @fils_roam_config: roam fils params + * @sae_offload_params: SAE offload/single pmk related parameters + */ +struct wlan_roam_scan_offload_params { + uint32_t vdev_id; + uint8_t is_rso_stop; + /* Parameters common for LFR-3.0 and LFR-2.0 */ + bool roaming_scan_policy; + struct wlan_roam_scan_mode_params rso_mode_info; + struct wlan_roam_scan_params rso_scan_params; + uint32_t assoc_ie_length; + uint8_t assoc_ie[MAX_ASSOC_IE_LENGTH]; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + /* Parameters specific to LFR-3.0 */ + bool roam_offload_enabled; + bool add_fils_tlv; + int akm; + struct wlan_rso_lfr3_params rso_lfr3_params; + struct wlan_rso_lfr3_caps rso_lfr3_caps; + struct wlan_rso_11i_params rso_11i_info; + struct wlan_rso_11r_params rso_11r_info; + struct wlan_rso_ese_params rso_ese_info; +#ifdef WLAN_FEATURE_FILS_SK + struct wlan_roam_fils_params fils_roam_config; +#endif + struct wlan_rso_sae_offload_params sae_offload_params; +#endif +}; + +/** + * enum wlan_roam_offload_scan_rssi_flags - Flags for roam scan RSSI threshold + * params, this enums will be used in flags param of the structure + * wlan_roam_offload_scan_rssi_params + * @ROAM_SCAN_RSSI_THRESHOLD_INVALID_FLAG: invalid flag + * @ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G: enable high RSSI roam + * trigger support to roam from 5 GHz to 6 GHz band + */ +enum wlan_roam_offload_scan_rssi_flags { + ROAM_SCAN_RSSI_THRESHOLD_INVALID_FLAG, + ROAM_SCAN_RSSI_THRESHOLD_FLAG_ROAM_HI_RSSI_EN_ON_5G = BIT(0), +}; + +/** + * struct wlan_roam_offload_scan_rssi_params - structure containing + * parameters for roam offload scan based on RSSI + * @rssi_thresh: rssi threshold + * @rssi_thresh_diff: difference in rssi threshold + * @hi_rssi_scan_max_count: 5G scan max count + * @hi_rssi_scan_rssi_delta: 5G scan rssi change threshold value + * @hi_rssi_scan_rssi_ub: 5G scan upper bound + * @raise_rssi_thresh_5g: flag to determine penalty and boost thresholds + * @drop_rssi_thresh_5g: flag to determine penalty and boost thresholds + * @vdev_id: vdev id + * @penalty_threshold_5g: RSSI threshold below which 5GHz RSSI is penalized + * @boost_threshold_5g: RSSI threshold above which 5GHz RSSI is favored + * @raise_factor_5g: factor by which 5GHz RSSI is boosted + * @drop_factor_5g: factor by which 5GHz RSSI is penalized + * @max_raise_rssi_5g: maximum boost that can be applied to a 5GHz RSSI + * @max_drop_rssi_5g: maximum penalty that can be applied to a 5GHz RSSI + * @good_rssi_threshold: RSSI below which roam is kicked in by background + * scan although rssi is still good + * @early_stop_scan_enable: early stop scan enable + * @roam_earlystop_thres_min: Minimum RSSI threshold value for early stop, + * unit is dB above NF + * @roam_earlystop_thres_max: Maximum RSSI threshold value for early stop, + * unit is dB above NF + * @dense_rssi_thresh_offset: dense roam RSSI threshold difference + * @dense_min_aps_cnt: dense roam minimum APs + * @initial_dense_status: dense status detected by host + * @traffic_threshold: dense roam RSSI threshold + * @rssi_thresh_offset_5g: + * @bg_scan_bad_rssi_thresh: Bad RSSI threshold to perform bg scan + * @roam_bad_rssi_thresh_offset_2g: Offset from Bad RSSI threshold for 2G + * to 5G Roam + * @bg_scan_client_bitmap: Bitmap used to identify the client scans to snoop + * @roam_data_rssi_threshold_triggers: triggers of bad data RSSI threshold to + * roam + * @roam_data_rssi_threshold: Bad data RSSI threshold to roam + * @rx_data_inactivity_time: Rx duration to check data RSSI + * @flags: Flags for roam scan RSSI threshold params + */ +struct wlan_roam_offload_scan_rssi_params { + int8_t rssi_thresh; + uint8_t rssi_thresh_diff; + uint32_t hi_rssi_scan_max_count; + uint32_t hi_rssi_scan_rssi_delta; + int32_t hi_rssi_scan_rssi_ub; + int raise_rssi_thresh_5g; + int drop_rssi_thresh_5g; + uint8_t vdev_id; + uint32_t penalty_threshold_5g; + uint32_t boost_threshold_5g; + uint8_t raise_factor_5g; + uint8_t drop_factor_5g; + int max_raise_rssi_5g; + int max_drop_rssi_5g; + uint32_t good_rssi_threshold; + bool early_stop_scan_enable; + int32_t roam_earlystop_thres_min; + int32_t roam_earlystop_thres_max; + int dense_rssi_thresh_offset; + int dense_min_aps_cnt; + int initial_dense_status; + int traffic_threshold; + int32_t rssi_thresh_offset_5g; + int8_t bg_scan_bad_rssi_thresh; + uint8_t roam_bad_rssi_thresh_offset_2g; + uint32_t bg_scan_client_bitmap; + uint32_t roam_data_rssi_threshold_triggers; + int32_t roam_data_rssi_threshold; + uint32_t rx_data_inactivity_time; + uint32_t flags; +}; + +/** + * struct wlan_roam_beacon_miss_cnt - roam beacon miss count + * @vdev_id: vdev id + * @roam_bmiss_first_bcnt: First beacon miss count + * @roam_bmiss_final_bcnt: Final beacon miss count + */ +struct wlan_roam_beacon_miss_cnt { + uint32_t vdev_id; + uint8_t roam_bmiss_first_bcnt; + uint8_t roam_bmiss_final_bcnt; +}; + +/** + * struct wlan_roam_bmiss_timeout - roam beacon miss timeout + * @vdev_id: vdev id + * @bmiss_timeout_onwakeup : timeout on wakeup in seconds + * @bmiss_timeout_onsleep : timeout on sleep in seconds + */ +struct wlan_roam_bmiss_timeout { + uint32_t vdev_id; + uint8_t bmiss_timeout_onwakeup; + uint8_t bmiss_timeout_onsleep; +}; + +/** + * struct wlan_roam_reason_vsie_enable - roam reason vsie enable parameters + * @vdev_id: vdev id + * @enable_roam_reason_vsie: enable/disable inclusion of roam Reason + * in Re(association) frame + */ +struct wlan_roam_reason_vsie_enable { + uint32_t vdev_id; + uint8_t enable_roam_reason_vsie; +}; + +/** + * struct wlan_roam_scan_period_params - Roam scan period parameters + * @vdev_id: Vdev for which the scan period parameters are sent + * @empty_scan_refresh_period: empty scan refresh period + * @scan_period: Opportunistic scan runs on a timer for scan_period + * @scan_age: Duration after which the scan entries are to be aged out + * @roam_scan_inactivity_time: inactivity monitoring time in ms for which the + * device is considered to be inactive + * @roam_inactive_data_packet_count: Maximum allowed data packets count during + * roam_scan_inactivity_time. + * @full_scan_period: Full scan period is the idle period in seconds + * between two successive full channel roam scans. + */ +struct wlan_roam_scan_period_params { + uint32_t vdev_id; + uint32_t empty_scan_refresh_period; + uint32_t scan_period; + uint32_t scan_age; + uint32_t roam_scan_inactivity_time; + uint32_t roam_inactive_data_packet_count; + uint32_t full_scan_period; +}; + +/** + * struct wlan_roam_scan_channel_list - Roam Scan channel list related + * parameters + * @vdev_id: Vdev id + * @chan_count: Channel count + * @chan_freq_list: Frequency list pointer + * @chan_cache_type: Static or dynamic channel cache + */ +struct wlan_roam_scan_channel_list { + uint32_t vdev_id; + uint8_t chan_count; + uint32_t chan_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t chan_cache_type; +}; + +/** + * struct wlan_roam_rssi_change_params - RSSI change parameters to be sent over + * WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD command + * @vdev_id: vdev id + * only if current RSSI changes by rssi_change_thresh value. + * @bcn_rssi_weight: Beacon RSSI weightage + * @hirssi_delay_btw_scans: Delay between high RSSI scans + * @rssi_change_thresh: RSSI change threshold. Start new rssi triggered scan + */ +struct wlan_roam_rssi_change_params { + uint32_t vdev_id; + uint32_t bcn_rssi_weight; + uint32_t hirssi_delay_btw_scans; + int32_t rssi_change_thresh; +}; + +/** + * struct wlan_cm_roam_rt_stats - Roam events stats update + * @roam_stats_enabled: set 1 if roam stats feature is enabled from userspace + * @roam_stats_wow_sent: set 1 if roam stats wow event is sent to FW + */ +struct wlan_cm_roam_rt_stats { + uint8_t roam_stats_enabled; + uint8_t roam_stats_wow_sent; +}; + +/** + * enum roam_rt_stats_params: different types of params to set or get roam + * events stats for the vdev + * @ROAM_RT_STATS_ENABLE: Roam stats feature if enable/not + * @ROAM_RT_STATS_SUSPEND_MODE_ENABLE: Roam stats wow event if sent to FW/not + */ +enum roam_rt_stats_params { + ROAM_RT_STATS_ENABLE, + ROAM_RT_STATS_SUSPEND_MODE_ENABLE, +}; + +/** + * struct wlan_roam_mlo_config - Roam MLO config parameters + * @vdev_id: VDEV id + * @partner_link_addr: Assigned link address which can be used as self + * link addr when vdev is not created + * @support_link_num: Configure max number of link mlo connection supports. + * Invalid value or 0 will use max supported value by fw. + * @support_link_band: Configure the band bitmap of mlo connection supports + * The bits of the bitmap are defined by the enum reg_wifi_band + * @mlo_5gl_5gh_mlsr: 5GL+5GH MLSR support + */ +struct wlan_roam_mlo_config { + uint8_t vdev_id; + struct qdf_mac_addr partner_link_addr; + uint32_t support_link_num; + uint32_t support_link_band; + uint32_t mlo_5gl_5gh_mlsr; +}; + +/** + * struct wlan_roam_start_config - structure containing parameters for + * roam start config + * @rssi_params: roam scan rssi threshold parameters + * @beacon_miss_cnt: roam beacon miss count parameters + * @bmiss_timeout: roam consecutive beaconloss timeout parameters + * @reason_vsie_enable: roam reason vsie enable parameters + * @roam_triggers: roam triggers parameters + * @scan_period_params: roam scan period parameters + * @rso_config: roam scan offload configuration + * @rssi_change_params: Roam offload RSSI change parameters + * @profile_params: ap profile parameters + * @rso_chan_info: Roam scan channel list parameters + * @mawc_params: mawc parameters + * @scan_filter_params: roam scan filter parameters + * @btm_config: btm configuration + * @roam_11k_params: 11k params + * @bss_load_config: bss load config + * @disconnect_params: disconnect params + * @idle_params: idle params + * @wlan_roam_rt_stats_config: roam events stats config + * @roam_mlo_params: roam mlo config params + * @wlan_roam_ho_delay_config: roam HO delay value + * @wlan_exclude_rm_partial_scan_freq: Include/exclude the channels in roam full + * scan that are already scanned as part of partial scan. + * @wlan_roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full + * scan only on prior discovery of any 6 GHz support in the environment. + * @wlan_roam_rssi_diff_6ghz: This value is used as to how better the RSSI of + * the new/roamable 6GHz AP should be for roaming. + */ +struct wlan_roam_start_config { + struct wlan_roam_offload_scan_rssi_params rssi_params; + struct wlan_roam_beacon_miss_cnt beacon_miss_cnt; + struct wlan_roam_bmiss_timeout bmiss_timeout; + struct wlan_roam_reason_vsie_enable reason_vsie_enable; + struct wlan_roam_triggers roam_triggers; + struct wlan_roam_scan_period_params scan_period_params; + struct wlan_roam_scan_offload_params rso_config; + struct wlan_roam_rssi_change_params rssi_change_params; + struct ap_profile_params profile_params; + struct wlan_roam_scan_channel_list rso_chan_info; + struct wlan_roam_mawc_params mawc_params; + struct wlan_roam_scan_filter_params scan_filter_params; + struct wlan_roam_btm_config btm_config; + struct wlan_roam_11k_offload_params roam_11k_params; + struct wlan_roam_bss_load_config bss_load_config; + struct wlan_roam_disconnect_params disconnect_params; + struct wlan_roam_idle_params idle_params; + uint8_t wlan_roam_rt_stats_config; + struct wlan_roam_mlo_config roam_mlo_params; + uint16_t wlan_roam_ho_delay_config; + uint8_t wlan_exclude_rm_partial_scan_freq; + uint8_t wlan_roam_full_scan_6ghz_on_disc; + uint8_t wlan_roam_rssi_diff_6ghz; + /* other wmi cmd structures */ +}; + +/** + * struct wlan_roam_stop_config - structure containing parameters for + * roam stop + * @reason: roaming reason + * @middle_of_roaming: in the middle of roaming + * @rso_config: Roam scan mode config + * @roam_11k_params: 11k params + * @btm_config: btm configuration + * @scan_filter_params: roam scan filter parameters + * @disconnect_params: disconnect params + * @idle_params: idle params + * @roam_triggers: roam triggers parameters + * @rssi_params: roam scan rssi threshold parameters + * @send_rso_stop_resp: send rso stop response + * @start_rso_stop_timer: start rso stop timer + */ +struct wlan_roam_stop_config { + uint8_t reason; + uint8_t middle_of_roaming; + struct wlan_roam_scan_offload_params rso_config; + struct wlan_roam_11k_offload_params roam_11k_params; + struct wlan_roam_btm_config btm_config; + struct wlan_roam_scan_filter_params scan_filter_params; + struct wlan_roam_disconnect_params disconnect_params; + struct wlan_roam_idle_params idle_params; + struct wlan_roam_triggers roam_triggers; + struct wlan_roam_offload_scan_rssi_params rssi_params; + bool send_rso_stop_resp; + bool start_rso_stop_timer; +}; + +/** + * struct wlan_roam_update_config - structure containing parameters for + * roam update config + * @beacon_miss_cnt: roam beacon miss count parameters + * @bmiss_timeout: roam scan bmiss timeout parameters + * @scan_filter_params: roam scan filter parameters + * @scan_period_params: roam scan period parameters + * @rssi_change_params: roam scan rssi change parameters + * @rso_config: roam scan mode configurations + * @profile_params: ap profile parameters + * @rso_chan_info: Roam scan channel list parameters + * @rssi_params: roam scan rssi threshold parameters + * @disconnect_params: disconnect params + * @idle_params: idle params + * @roam_triggers: roam triggers parameters + * @wlan_roam_rt_stats_config: roam events stats config + * @wlan_roam_ho_delay_config: roam HO delay value + * @wlan_exclude_rm_partial_scan_freq: Include/exclude the channels in roam full + * scan that are already scanned as part of partial scan. + * @wlan_roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full + * scan only on prior discovery of any 6 GHz support in the environment. + * @wlan_roam_rssi_diff_6ghz: This value is used as to how better the RSSI of + * the new/roamable 6GHz AP should be for roaming. + */ +struct wlan_roam_update_config { + struct wlan_roam_beacon_miss_cnt beacon_miss_cnt; + struct wlan_roam_bmiss_timeout bmiss_timeout; + struct wlan_roam_scan_filter_params scan_filter_params; + struct wlan_roam_scan_period_params scan_period_params; + struct wlan_roam_rssi_change_params rssi_change_params; + struct wlan_roam_scan_offload_params rso_config; + struct ap_profile_params profile_params; + struct wlan_roam_scan_channel_list rso_chan_info; + struct wlan_roam_offload_scan_rssi_params rssi_params; + struct wlan_roam_disconnect_params disconnect_params; + struct wlan_roam_idle_params idle_params; + struct wlan_roam_triggers roam_triggers; + uint8_t wlan_roam_rt_stats_config; + uint16_t wlan_roam_ho_delay_config; + uint8_t wlan_exclude_rm_partial_scan_freq; + uint8_t wlan_roam_full_scan_6ghz_on_disc; + uint8_t wlan_roam_rssi_diff_6ghz; +}; + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * enum roam_offload_state - Roaming module state for each STA vdev. + * @WLAN_ROAM_DEINIT: Roaming module is not initialized at the + * firmware. + * @WLAN_ROAM_INIT: Roaming module initialized at the firmware. + * @WLAN_ROAM_RSO_ENABLED: RSO enabled, firmware can roam to different AP. + * @WLAN_ROAM_RSO_STOPPED: RSO stopped - roaming module is initialized at + * firmware, but firmware cannot do roaming due to supplicant disabled + * roaming/driver disabled roaming. + * @WLAN_ROAMING_IN_PROG: Roaming started at firmware. This state is + * transitioned after candidate selection is done at fw and preauth to + * the AP is started. + * @WLAN_ROAM_SYNCH_IN_PROG: Roaming handoff complete + * @WLAN_MLO_ROAM_SYNCH_IN_PROG: MLO Roam sync is ongoing, + * only used for ml links. + */ +enum roam_offload_state { + WLAN_ROAM_DEINIT, + WLAN_ROAM_INIT, + WLAN_ROAM_RSO_ENABLED, + WLAN_ROAM_RSO_STOPPED, + WLAN_ROAMING_IN_PROG, + WLAN_ROAM_SYNCH_IN_PROG, + WLAN_MLO_ROAM_SYNCH_IN_PROG, +}; + +#define WLAN_ROAM_SCAN_CANDIDATE_AP 0 +#define WLAN_ROAM_SCAN_CURRENT_AP 1 +#define WLAN_ROAM_SCAN_ROAMED_AP 2 + +/** + * struct roam_btm_response_data - BTM response related data + * @present: Flag to check if the roam btm_rsp tlv is present + * @btm_status: Btm request status + * @target_bssid: AP MAC address + * @vsie_reason: Vsie_reason value + * @timestamp: This timestamp indicates the time when btm rsp is sent + * @btm_resp_dialog_token: Dialog token + * @btm_delay: BTM bss termination delay + * @is_mlo: Flag to check if the current connection is a MLO connection + * @band: Band of the link that is involved in frame exchange + */ +struct roam_btm_response_data { + bool present; + uint32_t btm_status; + struct qdf_mac_addr target_bssid; + uint32_t vsie_reason; + uint32_t timestamp; + uint16_t btm_resp_dialog_token; + uint8_t btm_delay; + bool is_mlo; + uint8_t band; +}; + +/** + * struct roam_initial_data - Roam initial related data + * @present: Flag to check if the roam btm_rsp tlv is present + * @roam_full_scan_count: Roam full scan count + * @rssi_th: RSSI threshold + * @cu_th: Channel utilization threshold + * @fw_cancel_timer_bitmap: FW timers, which are getting cancelled + */ +struct roam_initial_data { + bool present; + uint32_t roam_full_scan_count; + uint32_t rssi_th; + uint32_t cu_th; + uint32_t fw_cancel_timer_bitmap; +}; + +/** + * struct roam_msg_info - Roam message related information + * @present: Flag to check if the roam msg info tlv is present + * @timestamp: Timestamp is the absolute time w.r.t host timer which is + * synchronized between the host and target + * @msg_id: Message ID from WMI_ROAM_MSG_ID + * @msg_param1: msg_param1, values is based on the host & FW + * understanding and depend on the msg ID + * @msg_param2: msg_param2 value is based on the host & FW understanding + * and depend on the msg ID + */ +struct roam_msg_info { + bool present; + uint32_t timestamp; + uint32_t msg_id; + uint32_t msg_param1; + uint32_t msg_param2; +}; + +/** + * struct roam_event_rt_info - Roam event related information + * @roam_scan_state: roam scan state notif value + * @roam_invoke_fail_reason: roam invoke fail reason + */ +struct roam_event_rt_info { + uint32_t roam_scan_state; + uint32_t roam_invoke_fail_reason; +}; + +/** + * enum roam_rt_stats_type: different types of params to get roam event stats + * for the vdev + * @ROAM_RT_STATS_TYPE_SCAN_STATE: Roam Scan Start/End + * @ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON: One of WMI_ROAM_FAIL_REASON_ID for + * roam failure in case of forced roam + * @ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO: Roam Trigger/Fail/Scan/AP Stats + */ +enum roam_rt_stats_type { + ROAM_RT_STATS_TYPE_SCAN_STATE, + ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON, + ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO, +}; + +/** + * struct roam_frame_info - Structure to hold the mgmt frame/eapol frame + * related info exchanged during roaming. + * @present: Flag to indicate if roam frame info TLV is present + * @bssid: BSSID of the candidate AP or roamed AP to which the + * frame exchange happened + * @timestamp: Fw timestamp at which the frame was Tx/Rx'ed + * @type: Frame Type + * @subtype: Frame subtype + * @is_rsp: True if frame is response frame else false + * @seq_num: Frame sequence number from the 802.11 header + * @status_code: Status code from 802.11 spec, section 9.4.1.9 + * @auth_algo: Authentication algorithm as defined in 802.11 spec, + * 9.4.1.1 Authentication Algorithm Number field + * @tx_status: Frame TX status defined by enum qdf_dp_tx_rx_status + * applicable only for tx frames + * @rssi: Frame rssi + * @retry_count: Frame retry count + * @assoc_id: Association id received in the association response/ + * reassociation response frame + * @band: Band on which the packet is transmitted or received. Refer + * enum wlan_diag_wifi_band + */ +struct roam_frame_info { + bool present; + struct qdf_mac_addr bssid; + uint32_t timestamp; + uint8_t type; + uint8_t subtype; + uint8_t is_rsp; + enum qdf_dp_tx_rx_status tx_status; + uint16_t seq_num; + uint8_t auth_algo; + uint16_t status_code; + int32_t rssi; + uint16_t retry_count; + uint16_t assoc_id; + uint8_t band; +}; + +/** + * enum wlan_cm_rso_control_requestor - Driver disabled roaming requestor that + * will request the roam module to disable roaming based on the mlme operation + * @RSO_INVALID_REQUESTOR: invalid requestor + * @RSO_START_BSS: disable roaming temporarily due to start bss + * @RSO_CHANNEL_SWITCH: disable roaming due to STA channel switch + * @RSO_CONNECT_START: disable roaming temporarily due to connect + * @RSO_SAP_CHANNEL_CHANGE: disable roaming due to SAP channel change + * @RSO_NDP_CON_ON_NDI: disable roaming due to NDP connection on NDI + * @RSO_SET_PCL: Disable roaming to set pcl to firmware + */ +enum wlan_cm_rso_control_requestor { + RSO_INVALID_REQUESTOR, + RSO_START_BSS = BIT(0), + RSO_CHANNEL_SWITCH = BIT(1), + RSO_CONNECT_START = BIT(2), + RSO_SAP_CHANNEL_CHANGE = BIT(3), + RSO_NDP_CON_ON_NDI = BIT(4), + RSO_SET_PCL = BIT(5), +}; +#endif + +/** + * struct set_pcl_req - Request message to set the PCL + * @vdev_id: Vdev id + * @band_mask: Supported band mask + * @clear_vdev_pcl: Clear the configured vdev pcl channels + * @chan_weights: PCL channel weights + */ +struct set_pcl_req { + uint8_t vdev_id; + uint32_t band_mask; + bool clear_vdev_pcl; + struct wmi_pcl_chan_weights chan_weights; +}; + +/** + * struct roam_invoke_req - roam invoke request + * @vdev_id: vdev for which the roaming has to be enabled/disabled + * @target_bssid: target mac address + * @ch_freq: channel frequency + * @frame_len: frame length, includs mac header, fixed params and ies + * @frame_buf: buffer containing probe response or beacon + * @is_same_bssid: flag to indicate if roaming is requested for same bssid + * @forced_roaming: Roam to any bssid in any ch (here bssid & ch is not given) + */ +struct roam_invoke_req { + uint8_t vdev_id; + struct qdf_mac_addr target_bssid; + uint32_t ch_freq; + uint32_t frame_len; + uint8_t *frame_buf; + uint8_t is_same_bssid; + bool forced_roaming; +}; + +/** + * enum cm_roam_notif: roaming notification + * @CM_ROAM_NOTIF_INVALID: invalid notification. Do not interpret notif field + * @CM_ROAM_NOTIF_ROAM_START: indicate that roaming is started. sent only in + * non WOW state + * @CM_ROAM_NOTIF_ROAM_ABORT: indicate that roaming is aborted. sent only in + * non WOW state + * @CM_ROAM_NOTIF_ROAM_REASSOC: indicate that reassociation is done. sent only + * in non WOW state + * @CM_ROAM_NOTIF_SCAN_MODE_SUCCESS: indicate that roaming scan mode is + * successful + * @CM_ROAM_NOTIF_SCAN_MODE_FAIL: indicate that roaming scan mode is failed due + * to internal roaming state + * @CM_ROAM_NOTIF_DISCONNECT: indicate that roaming not allowed due BTM req + * @CM_ROAM_NOTIF_SUBNET_CHANGED: indicate that subnet has changed + * @CM_ROAM_NOTIF_SCAN_START: indicate roam scan start, notif_params to be sent + * as WMI_ROAM_TRIGGER_REASON_ID + * @CM_ROAM_NOTIF_DEAUTH_RECV: indicate deauth received, notif_params to be sent + * as reason code, notif_params1 to be sent as + * frame length + * @CM_ROAM_NOTIF_DISASSOC_RECV: indicate disassoc received, notif_params to be + * sent as reason code, notif_params1 to be sent + * as frame length + * @CM_ROAM_NOTIF_HO_FAIL: indicates that roaming scan mode is successful but + * caused disconnection and subsequent + * WMI_ROAM_REASON_HO_FAILED is event expected + * @CM_ROAM_NOTIF_SCAN_END: indicate roam scan end, notif_params to be sent + * as WMI_ROAM_TRIGGER_REASON_ID + */ +enum cm_roam_notif { + CM_ROAM_NOTIF_INVALID = 0, + CM_ROAM_NOTIF_ROAM_START, + CM_ROAM_NOTIF_ROAM_ABORT, + CM_ROAM_NOTIF_ROAM_REASSOC, + CM_ROAM_NOTIF_SCAN_MODE_SUCCESS, + CM_ROAM_NOTIF_SCAN_MODE_FAIL, + CM_ROAM_NOTIF_DISCONNECT, + CM_ROAM_NOTIF_SUBNET_CHANGED, + CM_ROAM_NOTIF_SCAN_START, + CM_ROAM_NOTIF_DEAUTH_RECV, + CM_ROAM_NOTIF_DISASSOC_RECV, + CM_ROAM_NOTIF_HO_FAIL, + CM_ROAM_NOTIF_SCAN_END, +}; + +/** + * enum roam_reason: Roam reason + * @ROAM_REASON_INVALID: invalid reason. Do not interpret reason field + * @ROAM_REASON_BETTER_AP: found a better AP + * @ROAM_REASON_BMISS: beacon miss detected + * @ROAM_REASON_LOW_RSSI: connected AP's low rssi condition detected + * @ROAM_REASON_SUITABLE_AP: found another AP that matches SSID and Security + * profile in WMI_ROAM_AP_PROFILE, found during scan triggered upon FINAL_BMISS + * @ROAM_REASON_HO_FAILED: LFR3.0 roaming failed, indicate the disconnection + * to host + * @ROAM_REASON_INVOKE_ROAM_FAIL: Result code of WMI_ROAM_INVOKE_CMDID. Any + * roaming failure before reassociation will be indicated to host with this + * reason. Any roaming failure after reassociation will be indicated to host + * with WMI_ROAM_REASON_HO_FAILED no matter WMI_ROAM_INVOKE_CMDID is + * called or not. + * @ROAM_REASON_RSO_STATUS: + * @ROAM_REASON_BTM: Roaming because of BTM request received + * @ROAM_REASON_DEAUTH: deauth/disassoc received + */ +enum roam_reason { + ROAM_REASON_INVALID, + ROAM_REASON_BETTER_AP, + ROAM_REASON_BMISS, + ROAM_REASON_LOW_RSSI, + ROAM_REASON_SUITABLE_AP, + ROAM_REASON_HO_FAILED, + ROAM_REASON_INVOKE_ROAM_FAIL, + ROAM_REASON_RSO_STATUS, + ROAM_REASON_BTM, + ROAM_REASON_DEAUTH, +}; + +/* + * struct roam_denylist_timeout - BTM denylist entry + * @bssid: bssid that is to be denylisted + * @timeout: time duration for which the bssid is denylisted + * @received_time: boot timestamp at which the firmware event was received + * @rssi: rssi value for which the bssid is denylisted + * @reject_reason: reason to add the BSSID to DLM + * @original_timeout: original timeout sent by the AP + * @source: Source of adding the BSSID to DLM + */ +struct roam_denylist_timeout { + struct qdf_mac_addr bssid; + uint32_t timeout; + qdf_time_t received_time; + int32_t rssi; + enum dlm_reject_ap_reason reject_reason; + uint32_t original_timeout; + enum dlm_reject_ap_source source; +}; + +/** + * struct roam_denylist_event - Denylist event entries destination structure + * @vdev_id: vdev id + * @num_entries: total entries sent over the event + * @roam_denylist: denylist details + */ +struct roam_denylist_event { + uint8_t vdev_id; + uint32_t num_entries; + struct roam_denylist_timeout roam_denylist[]; +}; + +/** + * enum cm_vdev_disconnect_reason - Roam disconnect reason + * @CM_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT: Disconnect due to SA query + * timeout after moving to new channel due to CSA in OCV enabled case. + * @CM_DISCONNECT_REASON_MOVE_TO_CELLULAR: Disconnect from WiFi to move + * to cellular + */ +enum cm_vdev_disconnect_reason { + CM_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT = 1, + CM_DISCONNECT_REASON_MOVE_TO_CELLULAR, +}; + +/** + * struct vdev_disconnect_event_data - Roam disconnect event data + * @vdev_id: vdev id + * @psoc: psoc object + * @reason: roam reason of type @enum cm_vdev_disconnect_reason + */ +struct vdev_disconnect_event_data { + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + enum cm_vdev_disconnect_reason reason; +}; + +/** + * struct cm_roam_scan_ch_resp - roam scan chan list response to userspace + * @vdev_id: vdev id + * @num_channels: number of roam scan channels + * @command_resp: command response or async event + * @chan_list: list of roam scan channels + */ +struct cm_roam_scan_ch_resp { + uint16_t vdev_id; + uint16_t num_channels; + uint32_t command_resp; + uint32_t *chan_list; +}; + +/** + * enum roam_dispatcher_events - Roam events to post to scheduler thread + * @ROAM_EVENT_INVALID: Invalid event + * @ROAM_PMKID_REQ_EVENT: Roam pmkid request event + * @ROAM_VDEV_DISCONNECT_EVENT: Roam disconnect event + */ +enum roam_dispatcher_events { + ROAM_EVENT_INVALID, + ROAM_PMKID_REQ_EVENT, + ROAM_VDEV_DISCONNECT_EVENT, +}; + +/** + * struct roam_offload_roam_event: Data carried by roam event + * @vdev_id: vdev id + * @psoc: psoc object + * @reason: reason for roam event of type @enum roam_reason + * @rssi: associated AP's rssi calculated by FW when reason code + * is WMI_ROAM_REASON_LOW_RSSI + * @notif: roam notification + * @notif_params: Contains roam invoke fail reason from wmi_roam_invoke_error_t + * if reason is WMI_ROAM_REASON_INVOKE_ROAM_FAIL. + * @notif_params1: notif_params1 is exact frame length of deauth or disassoc if + * reason is WMI_ROAM_REASON_DEAUTH. + * @hw_mode_trans_ind: HW mode transition indication + * @deauth_disassoc_frame: Deauth/disassoc frame received from AP + * @rso_timer_stopped: RSO timer stopped + */ +struct roam_offload_roam_event { + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + enum roam_reason reason; + uint32_t rssi; + enum cm_roam_notif notif; + uint32_t notif_params; + uint32_t notif_params1; + struct cm_hw_mode_trans_ind *hw_mode_trans_ind; + uint8_t *deauth_disassoc_frame; + bool rso_timer_stopped; +}; + +/** + * struct roam_frame_stats - Roam frame stats + * @num_frame: number of frames + * @frame_info: Roam frame info + */ +struct roam_frame_stats { + uint8_t num_frame; + struct roam_frame_info frame_info[WLAN_ROAM_MAX_FRAME_INFO]; +}; + +/** + * struct roam_stats_event - Data carried by stats event + * @vdev_id: vdev id + * @num_tlv: Number of roam scans triggered + * @num_roam_msg_info: Number of roam_msg_info present in event + * @enhance_roam_rt_event: flag of whether we need send event for + * real time enhance roam stats info to user space + * @trigger: Roam trigger related details + * @scan: Roam scan event details + * @result: Roam result related info + * @frame_stats: Info on frame exchange during roaming + * @data_11kv: Neighbor report/BTM request related data + * @btm_rsp: BTM response related data + * @roam_init_info: Roam initial related data + * @roam_msg_info: Roam message related information + * @roam_event_param: Roam event notif params + */ +struct roam_stats_event { + uint8_t vdev_id; + uint8_t num_tlv; + uint8_t num_roam_msg_info; + bool enhance_roam_rt_event; + struct wmi_roam_trigger_info trigger[MAX_ROAM_SCAN_STATS_TLV]; + struct wmi_roam_scan_data scan[MAX_ROAM_SCAN_STATS_TLV]; + struct wmi_roam_result result[MAX_ROAM_SCAN_STATS_TLV]; + struct roam_frame_stats frame_stats[MAX_ROAM_SCAN_STATS_TLV]; + struct wmi_neighbor_report_data data_11kv[MAX_ROAM_SCAN_STATS_TLV]; + struct roam_btm_response_data btm_rsp[MAX_ROAM_SCAN_STATS_TLV]; + struct roam_initial_data roam_init_info[MAX_ROAM_SCAN_STATS_TLV]; + struct roam_msg_info *roam_msg_info; + struct roam_event_rt_info roam_event_param; +}; + +/** + * struct auth_offload_event - offload data carried by roam event + * @vdev_id: vdev id + * @ap_bssid: SAE authentication offload AP MAC Address + * @ta: SAE authentication offload Tx MAC Address + * @akm: SAE AKM type + */ +struct auth_offload_event { + uint8_t vdev_id; + struct qdf_mac_addr ap_bssid; + struct qdf_mac_addr ta; + uint32_t akm; +}; + +/** + * struct roam_pmkid_req_event - Pmkid event with entries destination structure + * @vdev_id: VDEV id + * @psoc: psoc object + * @num_entries: total entries sent over the event + * @ap_bssid: bssid list + */ +struct roam_pmkid_req_event { + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + uint32_t num_entries; + struct qdf_mac_addr ap_bssid[]; +}; + +/** + * struct wlan_cm_roam_tx_ops - structure of tx function pointers for + * roaming related commands + * @send_vdev_set_pcl_cmd: TX ops function pointer to send set vdev PCL + * command + * @send_roam_offload_init_req: TX Ops function pointer to send roam offload + * module initialize request + * @send_roam_start_req: TX ops function pointer to send roam start related + * commands + * @send_roam_stop_offload: + * @send_roam_update_config: + * @send_roam_abort: send roam abort + * @send_roam_per_config: + * @send_roam_triggers: + * @send_roam_disable_config: send roam disable config + * @send_roam_invoke_cmd: + * @send_roam_sync_complete_cmd: + * @send_roam_rt_stats_config: Send roam events vendor command param value to FW + * @send_roam_ho_delay_config: Send roam Hand-off delay value to FW + * @send_exclude_rm_partial_scan_freq: Include/exclude the channels in roam full + * scan that are already scanned as part of partial scan. + * @send_roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full + * scan only on prior discovery of any 6 GHz support in the environment. + * @send_roam_mcc_disallow: Send MCC disallow to FW + * @send_roam_linkspeed_state: Send roam link speed good/poor state to FW + * @send_roam_vendor_handoff_config: send vendor handoff config command to FW + * @send_roam_mlo_config: send MLO config to FW + * @send_roam_scan_offload_rssi_params: Set the RSSI parameters for roam + * offload scan + * @send_roam_frequencies: send roam frequencies to FW + */ +struct wlan_cm_roam_tx_ops { + QDF_STATUS (*send_vdev_set_pcl_cmd)(struct wlan_objmgr_vdev *vdev, + struct set_pcl_req *req); + QDF_STATUS (*send_roam_offload_init_req)( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_offload_init_params *params); + + QDF_STATUS (*send_roam_start_req)(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_start_config *req); + QDF_STATUS (*send_roam_stop_offload)(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_stop_config *req); + QDF_STATUS (*send_roam_update_config)( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_update_config *req); + QDF_STATUS (*send_roam_abort)(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id); + QDF_STATUS (*send_roam_per_config)( + struct wlan_objmgr_vdev *vdev, + struct wlan_per_roam_config_req *req); + QDF_STATUS (*send_roam_triggers)(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_triggers *req); + QDF_STATUS (*send_roam_disable_config)(struct wlan_objmgr_vdev *vdev, + struct roam_disable_cfg *req); + QDF_STATUS (*send_roam_invoke_cmd)(struct wlan_objmgr_vdev *vdev, + struct roam_invoke_req *req); + QDF_STATUS (*send_roam_sync_complete_cmd)(struct wlan_objmgr_vdev *vdev); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + QDF_STATUS (*send_roam_rt_stats_config)(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint8_t value); + QDF_STATUS (*send_roam_ho_delay_config)(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, + uint16_t value); + QDF_STATUS (*send_exclude_rm_partial_scan_freq)( + struct wlan_objmgr_vdev *vdev, + uint8_t value); + QDF_STATUS (*send_roam_full_scan_6ghz_on_disc)( + struct wlan_objmgr_vdev *vdev, + uint8_t value); + QDF_STATUS (*send_roam_mcc_disallow)(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint8_t value); + QDF_STATUS (*send_roam_scan_offload_rssi_params)( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params); +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER + QDF_STATUS (*send_roam_linkspeed_state)(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, bool value); +#endif +#endif +#ifdef WLAN_VENDOR_HANDOFF_CONTROL + QDF_STATUS (*send_roam_vendor_handoff_config)( + struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, uint32_t param_id); +#endif +#ifdef WLAN_FEATURE_11BE_MLO + QDF_STATUS (*send_roam_mlo_config)(struct wlan_objmgr_vdev *vdev, + struct wlan_roam_mlo_config *req); +#endif + QDF_STATUS (*send_roam_frequencies)( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_scan_channel_list *rso_ch_info); +}; + +/** + * enum roam_scan_freq_scheme - Scan mode for triggering roam + * @ROAM_SCAN_FREQ_SCHEME_NO_SCAN: Indicates the fw to not scan. + * @ROAM_SCAN_FREQ_SCHEME_PARTIAL_SCAN: Indicates the firmware to + * trigger partial frequency scans. + * @ROAM_SCAN_FREQ_SCHEME_FULL_SCAN: Indicates the firmware to + * trigger full frequency scans. + * @ROAM_SCAN_FREQ_SCHEME_NONE: Invalid scan mode + */ +enum roam_scan_freq_scheme { + ROAM_SCAN_FREQ_SCHEME_NO_SCAN = 0, + ROAM_SCAN_FREQ_SCHEME_PARTIAL_SCAN = 1, + ROAM_SCAN_FREQ_SCHEME_FULL_SCAN = 2, + ROAM_SCAN_FREQ_SCHEME_NONE = 3, +}; + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * struct wlan_cm_vendor_handoff_param - vendor handoff configuration + * structure + * @vendor_handoff_context: vendor handoff context + * @req_in_progress: to check whether vendor handoff request in progress or not + */ +struct wlan_cm_vendor_handoff_param { + void *vendor_handoff_context; + bool req_in_progress; +}; +#endif + +/** + * struct sae_offload_params - SAE roam auth offload related params + * @ssid: SSID of the roam candidate + * @bssid: BSSID of the roam candidate + */ +struct sae_offload_params { + struct wlan_ssid ssid; + struct qdf_mac_addr bssid; +}; + +/** + * struct wlan_cm_roam - Connection manager roam configs, state and roam + * data related structure + * @pcl_vdev_cmd_active: Flag to check if vdev level pcl command needs to be + * sent or PDEV level PCL command needs to be sent + * @vendor_handoff_param: vendor handoff params + * @sae_offload: SAE roam offload related params + */ +struct wlan_cm_roam { + bool pcl_vdev_cmd_active; +#ifdef WLAN_VENDOR_HANDOFF_CONTROL + struct wlan_cm_vendor_handoff_param vendor_handoff_param; +#endif + struct sae_offload_params sae_offload; +}; + +/** + * struct cm_roam_values_copy - Structure for values copy buffer + * @uint_value: Unsigned integer value to be copied + * @int_value: Integer value + * @bool_value: boolean value + * @chan_info: chan info + */ +struct cm_roam_values_copy { + uint32_t uint_value; + int32_t int_value; + bool bool_value; + struct rso_chan_info chan_info; +}; + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/* bit-4 and bit-5 indicate the subnet status */ +#define CM_GET_SUBNET_STATUS(roam_reason) (((roam_reason) & 0x30) >> 4) +#else +#define CM_GET_SUBNET_STATUS(roam_reason) (0) +#endif + +/* This should not be greater than MAX_NUMBER_OF_CONC_CONNECTIONS */ +#define MAX_VDEV_SUPPORTED 4 +#define MAX_PN_LEN 8 +#define MAX_KEY_LEN 32 + +/* MAX_FREQ_RANGE_NUM shouldn't exceed as only in case of SBS there will be 3 + * frequency ranges, For DBS, it will be 2. For SMM, it will be 1 + */ +#define MAX_FREQ_RANGE_NUM 3 + +/** + * struct cm_ho_fail_ind - ho fail indication to CM + * @vdev_id: vdev id + * @psoc: psoc object + * @bssid: bssid addr + */ +struct cm_ho_fail_ind { + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct qdf_mac_addr bssid; +}; + +/** + * struct policy_mgr_vdev_mac_map - vdev id-mac id map + * @vdev_id: VDEV id + * @mac_id: MAC id + */ +struct policy_mgr_vdev_mac_map { + uint32_t vdev_id; + uint32_t mac_id; +}; + +/** + * struct policy_mgr_pdev_mac_freq_map - vdev id-mac id map + * @mac_id: mac_id mapped to pdev id (macros starting with WMI_PDEV_ID_) + * @start_freq: Start Frequency in Mhz + * @end_freq: End Frequency in Mhz + */ +struct policy_mgr_pdev_mac_freq_map { + uint32_t mac_id; + qdf_freq_t start_freq; + qdf_freq_t end_freq; +}; + +/** + * struct cm_hw_mode_trans_ind - HW mode transition indication + * @old_hw_mode_index: Index of old HW mode + * @new_hw_mode_index: Index of new HW mode + * @num_vdev_mac_entries: Number of vdev-mac id entries + * @vdev_mac_map: vdev id-mac id map + * @num_freq_map: Number of frequency map entries + * @mac_freq_map: Frequency range map + */ +struct cm_hw_mode_trans_ind { + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + uint32_t num_vdev_mac_entries; + struct policy_mgr_vdev_mac_map vdev_mac_map[MAX_VDEV_SUPPORTED]; + uint32_t num_freq_map; + struct policy_mgr_pdev_mac_freq_map mac_freq_map[MAX_FREQ_RANGE_NUM]; +}; + +/* If link is disabled, during roam sync */ +#define CM_ROAM_LINK_FLAG_DISABLE 0x1 + +/** + * struct ml_setup_link_param - MLO setup link param + * @vdev_id: vdev id of the link + * @link_id: link id of the link + * @channel: wmi channel + * @flags: link flags + * @link_addr: link mac address + * @self_link_addr: VDEV link mac address + */ +struct ml_setup_link_param { + uint32_t vdev_id; + uint32_t link_id; + wmi_channel channel; + uint32_t flags; + struct qdf_mac_addr link_addr; + struct qdf_mac_addr self_link_addr; +}; + +/** + * struct ml_key_material_param - MLO key material param + * @link_id: key is for which link, when link_id is 0xf, + * means the key is used for all links, like PTK + * @key_idx: key idx + * @key_cipher: key cipher + * @pn: pn + * @key_buff: key buffer + */ +struct ml_key_material_param { + uint32_t link_id; + uint32_t key_idx; + uint32_t key_cipher; + uint8_t pn[MAX_PN_LEN]; + uint8_t key_buff[MAX_KEY_LEN]; +}; + +struct roam_offload_synch_ind { + uint16_t beacon_probe_resp_offset; + uint16_t beacon_probe_resp_length; + uint16_t reassoc_resp_offset; + uint16_t reassoc_resp_length; + uint16_t reassoc_req_offset; + uint16_t reassoc_req_length; + uint8_t is_beacon; + uint8_t roamed_vdev_id; + struct qdf_mac_addr bssid; + struct wlan_ssid ssid; + int8_t tx_mgmt_power; + uint32_t auth_status; + int8_t rssi; + uint8_t roam_reason; + uint32_t chan_freq; + uint8_t kck[MAX_KCK_LEN]; + uint8_t kck_len; + uint32_t kek_len; + uint8_t kek[MAX_KEK_LENGTH]; + uint32_t pmk_len; + uint8_t pmk[MAX_PMK_LEN]; + uint8_t pmkid[PMKID_LEN]; + bool update_erp_next_seq_num; + uint16_t next_erp_seq_num; + uint8_t replay_ctr[REPLAY_CTR_LEN]; + void *add_bss_params; + enum phy_ch_width chan_width; + uint32_t max_rate_flags; + uint32_t ric_data_len; +#ifdef FEATURE_WLAN_ESE + uint32_t tspec_len; +#endif + uint8_t *ric_tspec_data; + uint16_t aid; + bool hw_mode_trans_present; + struct cm_hw_mode_trans_ind hw_mode_trans_ind; + uint8_t nss; + struct qdf_mac_addr dst_mac; + struct qdf_mac_addr src_mac; + uint16_t hlp_data_len; + uint8_t hlp_data[FILS_MAX_HLP_DATA_LEN]; + bool is_ft_im_roam; + uint8_t is_assoc; + enum wlan_phymode phy_mode; /*phy mode sent by fw */ + wmi_channel chan; + uint16_t link_beacon_probe_resp_offset; + uint16_t link_beacon_probe_resp_length; + uint8_t is_link_beacon; +#ifdef WLAN_FEATURE_11BE_MLO + uint8_t num_setup_links; + struct ml_setup_link_param ml_link[WLAN_MAX_ML_BSS_LINKS]; + uint8_t num_ml_key_material; + struct ml_key_material_param ml_key[WLAN_MAX_ML_BSS_LINKS]; +#endif +}; + +/** + * struct roam_scan_candidate_frame Roam candidate scan entry + * @vdev_id : vdev id + * @frame_length : Length of the beacon/probe rsp frame + * @frame : Pointer to the frame + * @rssi: RSSI of the received frame, 0 if not available + * @roam_offload_candidate_frm: Is a roam offload candidate frame + */ +struct roam_scan_candidate_frame { + uint8_t vdev_id; + uint32_t frame_length; + uint8_t *frame; + int32_t rssi; + bool roam_offload_candidate_frm; +}; + +/** + * struct wlan_cm_roam_rx_ops - structure of rx function pointers for + * roaming related commands + * @roam_sync_event: RX ops function pointer for roam sync event + * @roam_sync_frame_event: Rx ops function pointer for roam sync frame event + * @roam_sync_key_event: Rx ops function pointer for roam sych key event + * @roam_event_rx: Rx ops function pointer for roam info event + * @btm_denylist_event: Rx ops function pointer for btm denylist event + * @vdev_disconnect_event: Rx ops function pointer for vdev disconnect event + * @roam_scan_chan_list_event: Rx ops function pointer for roam scan ch event + * @roam_stats_event_rx: Rx ops function pointer for roam stats event + * @roam_auth_offload_event: Rx ops function pointer for auth offload event + * @roam_pmkid_request_event_rx: Rx ops function pointer for roam pmkid event + * @roam_candidate_frame_event : Rx ops function pointer for roam frame event + * @roam_vendor_handoff_event: Rx ops function pointer for vendor handoff event + */ +struct wlan_cm_roam_rx_ops { + QDF_STATUS (*roam_sync_event)(struct wlan_objmgr_psoc *psoc, + uint8_t *event, + uint32_t len, + struct roam_offload_synch_ind *sync_ind); + QDF_STATUS (*roam_sync_frame_event)(struct wlan_objmgr_psoc *psoc, + struct roam_synch_frame_ind *frm); + QDF_STATUS (*roam_sync_key_event)(struct wlan_objmgr_psoc *psoc, + struct wlan_crypto_key_entry *keys, + uint8_t num_keys); + QDF_STATUS (*roam_event_rx)(struct roam_offload_roam_event *roam_event); + QDF_STATUS (*btm_denylist_event)(struct wlan_objmgr_psoc *psoc, + struct roam_denylist_event *list); + QDF_STATUS + (*vdev_disconnect_event)(struct vdev_disconnect_event_data *data); + QDF_STATUS + (*roam_scan_chan_list_event)(struct cm_roam_scan_ch_resp *data); + QDF_STATUS + (*roam_stats_event_rx)(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info); + QDF_STATUS + (*roam_auth_offload_event)(struct auth_offload_event *auth_event); + QDF_STATUS + (*roam_pmkid_request_event_rx)(struct roam_pmkid_req_event *list); + QDF_STATUS + (*roam_candidate_frame_event)(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *frame); +#ifdef WLAN_VENDOR_HANDOFF_CONTROL + void + (*roam_vendor_handoff_event)(struct wlan_objmgr_psoc *psoc, + struct roam_vendor_handoff_params *data); +#endif +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h new file mode 100644 index 0000000000..9b04161047 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_roam_ucfg_api.h @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_ucfg_api.h + * + * Implementation for roaming public ucfg API interfaces. + */ + +#ifndef _WLAN_CM_ROAM_UCFG_API_H_ +#define _WLAN_CM_ROAM_UCFG_API_H_ + +#include "wlan_cm_roam_api.h" + +/** + * ucfg_user_space_enable_disable_rso() - Enable/Disable Roam Scan offload + * to firmware. + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @is_fast_roam_enabled: Value provided by userspace. + * is_fast_roam_enabled - true: enable RSO if FastRoamEnabled ini is enabled + * false: disable RSO + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_user_space_enable_disable_rso(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + const bool is_fast_roam_enabled); + +/** + * ucfg_clear_user_disabled_roaming() - clear user/wpa_supplicant + * disabled_roaming flag in driver + * @psoc: Pointer to pdev + * @vdev_id: vdev id + * + * Return: void + */ +void +ucfg_clear_user_disabled_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_is_rso_enabled() - Check if rso is enabled + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * + * Return: Wrapper for wlan_is_rso_enabled. + */ +bool ucfg_is_rso_enabled(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/* + * ucfg_cm_abort_roam_scan() -abort current roam scan cycle by roam scan + * offload module. + * @pdev: Pointer to pdev + * vdev_id - vdev Identifier + * + * Return QDF_STATUS + */ +QDF_STATUS ucfg_cm_abort_roam_scan(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +#ifdef FEATURE_WLAN_ESE +/** + * ucfg_cm_set_ese_roam_scan_channel_list() - To set ese roam scan channel list + * @pdev: pdev pointer + * @vdev_id: vdev_id id + * @chan_freq_list: Output channel list + * @num_chan: Output number of channels + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_cm_set_ese_roam_scan_channel_list(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t *chan_freq_list, + uint8_t num_chan); +QDF_STATUS ucfg_cm_set_cckm_ie(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + const uint8_t *cck_ie, const uint8_t cck_ie_len); +#endif + +/** + * ucfg_cm_get_roam_band() - Get roam band from rso config + * @psoc: Pointer to psoc + * @vdev_id: vdev id + * @roam_band: Pointer of a buffer to fill the roam band + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_cm_get_roam_band(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t *roam_band); + +/** + * ucfg_cm_rso_set_roam_trigger() - Send roam trigger bitmap firmware + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @trigger: Carries pointer of the object containing vdev id and + * roam_trigger_bitmap. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct wlan_roam_triggers *trigger) +{ + return wlan_cm_rso_set_roam_trigger(pdev, vdev_id, trigger); +} + +/** + * ucfg_cm_update_session_assoc_ie() - Send assoc ie + * @psoc: Pointer to psoc + * @vdev_id: vdev id + * @assoc_ie: assoc ir to update. + * + * Return: QDF_STATUS + */ +static inline void +ucfg_cm_update_session_assoc_ie(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct element_info *assoc_ie) +{ + cm_update_session_assoc_ie(psoc, vdev_id, assoc_ie); +} + +static inline void +ucfg_cm_get_associated_ch_info(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum phy_ch_width scanned_ch_width, + struct assoc_channel_info *assoc_chan_info) +{ + wlan_cm_get_associated_ch_info(psoc, vdev_id, scanned_ch_width, + assoc_chan_info); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * ucfg_cm_roam_link_speed_update() - Update link speed state for roaming + * @psoc: psoc pointer + * @vdev_id: vdev id + * @is_link_speed_good: true means link speed good, false means bad + * + * Return: QDF_STATUS + */ +static inline +void ucfg_cm_roam_link_speed_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good) +{ + wlan_cm_roam_link_speed_update(psoc, + vdev_id, + is_link_speed_good); +} + +/** + * ucfg_cm_is_linkspeed_roam_trigger_supported() - Get roam linkspeed check + * @psoc: pointer to psoc object + * + * Return: bool, true: Linkspeed check for low rssi roaming supported + */ +static inline bool +ucfg_cm_is_linkspeed_roam_trigger_supported(struct wlan_objmgr_psoc *psoc) +{ + return wlan_cm_is_linkspeed_roam_trigger_supported(psoc); +} +#endif + +static inline QDF_STATUS +ucfg_cm_update_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_scan_scheme_bitmap) +{ + return wlan_cm_update_roam_scan_scheme_bitmap(psoc, vdev_id, + roam_scan_scheme_bitmap); +} + +static inline QDF_STATUS +ucfg_cm_set_roam_band_mask(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t roam_band_mask) +{ + return wlan_cm_set_roam_band_bitmask(psoc, vdev_id, roam_band_mask); +} + +/** + * ucfg_cm_set_btm_config() - Inline ucfg api to set btm roaming disable flag + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @is_disable_btm: btm config flag that needs to be set from the caller + * + * Return: QDF Status + */ +static inline QDF_STATUS ucfg_cm_set_btm_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_disable_btm) +{ + return wlan_cm_set_btm_config(psoc, vdev_id, is_disable_btm); +} + +static inline QDF_STATUS +ucfg_cm_set_roam_band_update(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return wlan_cm_set_roam_band_update(psoc, vdev_id); +} + +static inline bool +ucfg_cm_is_change_in_band_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t roam_band_mask) +{ + return cm_roam_is_change_in_band_allowed(psoc, vdev_id, roam_band_mask); +} + +static inline QDF_STATUS +ucfg_cm_update_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t value, enum roam_rt_stats_params stats) +{ + return wlan_cm_update_roam_rt_stats(psoc, value, stats); +} + +static inline uint8_t +ucfg_cm_get_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + enum roam_rt_stats_params stats) +{ + return wlan_cm_get_roam_rt_stats(psoc, stats); +} +#else +static inline QDF_STATUS +ucfg_cm_update_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_scan_scheme_bitmap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_cm_set_roam_band_mask(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t roam_band_mask) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_cm_set_btm_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_disable_btm) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_cm_set_roam_band_update(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ucfg_cm_is_change_in_band_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t roam_band_mask) +{ + return true; +} + +static inline QDF_STATUS +ucfg_cm_update_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t value, enum roam_rt_stats_params stats) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint8_t +ucfg_cm_get_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + enum roam_rt_stats_params stats) +{ + return 0; +} + +#endif + +/** + * ucfg_wlan_cm_roam_invoke() - Invokes Roam request + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @bssid: Pointer to bssid to look for in scan cache + * @ch_freq: channel on which reassoc should be send + * @source: source of roam + * + * Return: true or false + */ +QDF_STATUS +ucfg_wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct qdf_mac_addr *bssid, qdf_freq_t ch_freq, + enum wlan_cm_source source); + +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS +ucfg_cm_update_fils_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_fils_con_info *fils_info); +#else +static inline QDF_STATUS +ucfg_cm_update_fils_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_fils_con_info *fils_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_HOST_ROAM +void ucfg_cm_ft_reset(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_cm_set_ft_ies() - to set FT IEs + * @pdev: pdev ctx + * @vdev_id: vdev identifier + * @ft_ies: pointer to FT IEs + * @ft_ies_length: length of FT IEs + * + * Each time the supplicant sends down the FT IEs to the driver. This function + * is called in SME. This function packages and sends the FT IEs to PE. + * + * Return: none + */ +void ucfg_cm_set_ft_ies(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + const uint8_t *ft_ies, uint16_t ft_ies_length); + +/** + * ucfg_cm_check_ft_status() - Check for key wait status in FT mode + * @pdev: pdev ctx + * @vdev_id: vdev identifier + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_cm_check_ft_status(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); + +/** + * ucfg_cm_ft_key_ready_for_install() - API to check ft key ready for install + * @vdev: pdev handle + * + * It is only applicable for LFR2.0 enabled + * + * Return: true when ft key is ready otherwise false + */ +bool ucfg_cm_ft_key_ready_for_install(struct wlan_objmgr_vdev *vdev); +void ucfg_cm_set_ft_pre_auth_state(struct wlan_objmgr_vdev *vdev, bool state); + +#else /* WLAN_FEATURE_HOST_ROAM */ + +static inline void ucfg_cm_ft_reset(struct wlan_objmgr_vdev *vdev) {} +static inline +void ucfg_cm_set_ft_ies(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + const uint8_t *ft_ies, uint16_t ft_ies_length) {} + +static inline +QDF_STATUS ucfg_cm_check_ft_status(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline void ucfg_cm_set_ft_pre_auth_state(struct wlan_objmgr_vdev *vdev, + bool state) {} +#endif /* WLAN_FEATURE_HOST_ROAM */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * ucfg_cm_reset_key() -Reset key information + * @pdev: pdev handle + * @vdev_id: vdev identifier + * + * Return: None + */ +void ucfg_cm_reset_key(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id); + +/** + * ucfg_cm_roam_send_rt_stats_config() - Enable/Disable Roam event stats from FW + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @param_value: Value set based on the userspace attributes. + * param_value - 0: if configure attribute is 0 + * 1: if configure is 1 and suspend_state is not set + * 3: if configure is 1 and suspend_state is set + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_roam_send_rt_stats_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value); + +/** + * ucfg_cm_roam_send_ho_delay_config() - Send the HO delay value to Firmware + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @param_value: Value will be from range 20 to 1000 in msec. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_roam_send_ho_delay_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint16_t param_value); + +/** + * ucfg_cm_exclude_rm_partial_scan_freq() - Exclude the channels in roam full + * scan that are already scanned as part of partial scan. + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @param_value: Include/exclude the partial scan channel in roam full scan + * 1 - Exclude + * 0 - Include + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value); + +/** + * ucfg_cm_roam_full_scan_6ghz_on_disc() - Include the 6 GHz channels in roam + * full scan only on prior discovery of any 6 GHz support in the environment. + * @pdev: Pointer to pdev + * @vdev_id: vdev id + * @param_value: Include the 6 GHz channels in roam full scan: + * 1 - Include only on prior discovery of any 6 GHz support in the environment + * 0 - Include all the supported 6 GHz channels by default + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t param_value); + +/** + * ucfg_cm_set_roam_scan_high_rssi_offset() - Set the delta change in high RSSI + * at which roam scan is triggered in 2.4/5 GHz. + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * @param_value: Set the High RSSI delta for roam scan trigger + * 0 - Disable + * 1-16 - Set an offset value in this range + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + return cm_set_roam_scan_high_rssi_offset(psoc, vdev_id, param_value); +} +#else +static inline void +ucfg_cm_reset_key(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) {} + +static inline QDF_STATUS +ucfg_cm_roam_send_rt_stats_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_cm_roam_send_ho_delay_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint16_t param_value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t param_value) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * ucfg_cm_roam_send_vendor_handoff_param_req() - send vendor handoff params + * command request to FW + * @psoc: Pointer to psoc + * @vdev_id: vdev id + * @param_id: Vendor Control Param ID from + * enum WMI_ROAM_GET_VENDOR_CONTROL_PARAM_ID + * @vendor_handoff_context: + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_roam_send_vendor_handoff_param_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t param_id, + void *vendor_handoff_context); + +/** + * ucfg_cm_roam_is_vendor_handoff_control_enable() - check whether vendor + * handoff control feature is enable or not in driver + * @psoc: psoc pointer + * + * Return: true if feature supports + */ +bool +ucfg_cm_roam_is_vendor_handoff_control_enable(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_cm_roam_is_vendor_handoff_control_enable(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * ucfg_cm_get_sae_auth_ta() - Get SAE auth tx address + * @pdev: pointer to pdev object + * @vdev_id: Vdev id + * @sae_auth_ta: SAE auth tx address + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_cm_get_sae_auth_ta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *sae_auth_ta) +{ + return wlan_cm_get_sae_auth_ta(pdev, vdev_id, sae_auth_ta); +} + +/** + * ucfg_cm_get_roam_intra_band() - get Intra band roaming + * @psoc: pointer to psoc object + * @val: Infra band value + * + * Return: Success or failure + */ +QDF_STATUS +ucfg_cm_get_roam_intra_band(struct wlan_objmgr_psoc *psoc, uint16_t *val); + +/** + * ucfg_cm_get_roam_rescan_rssi_diff() - gets roam rescan rssi diff + * @psoc: pointer to psoc object + * @val: value for rescan rssi diff + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_roam_rescan_rssi_diff(struct wlan_objmgr_psoc *psoc, uint8_t *val); + +/** + * ucfg_cm_get_neighbor_lookup_rssi_threshold() - + * get neighbor lookup rssi threshold + * @psoc: pointer to psoc object + * @vdev_id: vdev identifier + * @lookup_threshold: Buffer to fill the neighbor lookup threshold. + * Valid only if the return status is success. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_neighbor_lookup_rssi_threshold(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t *lookup_threshold); + +/** + * ucfg_cm_get_empty_scan_refresh_period() - get empty scan refresh period + * @psoc: pointer to psoc object + * @vdev_id: Vdev id + * @refresh_threshold: Buffer to fill the empty scan refresh period. + * Valid only if the return status is success. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_empty_scan_refresh_period(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint16_t *refresh_threshold); + +/** + * ucfg_cm_get_neighbor_scan_min_chan_time() - + * get neighbor scan min channel time + * @psoc: pointer to psoc object + * @vdev_id: vdev_id + * + * Return: channel min time value + */ +uint16_t +ucfg_cm_get_neighbor_scan_min_chan_time(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_cm_get_roam_rssi_diff() - Get Roam rssi diff + * @psoc: pointer to psoc object + * @vdev_id: vdev identifier + * @rssi_diff: Buffer to fill the roam RSSI diff. + * Valid only if the return status is success. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_roam_rssi_diff(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t *rssi_diff); + +#ifdef FEATURE_WLAN_ESE +/** + * ucfg_cm_get_is_ese_feature_enabled() - Get ESE feature enabled or not + * This is a synchronous call + * @psoc: pointer to psoc object + * + * Return: true (1) - if the ESE feature is enabled + * false (0) - if feature is disabled (compile or runtime) + */ +bool +ucfg_cm_get_is_ese_feature_enabled(struct wlan_objmgr_psoc *psoc); +#else +static inline bool +ucfg_cm_get_is_ese_feature_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +/** + * ucfg_cm_get_neighbor_scan_max_chan_time() - get neighbor + * scan max channel time + * @psoc: pointer to psoc object + * @vdev_id: vdev identifier + * + * Return: channel max time value + */ +uint16_t +ucfg_cm_get_neighbor_scan_max_chan_time(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_cm_get_neighbor_scan_period() - get neighbor scan period + * @psoc: pointer to psoc object + * @vdev_id: vdev identifier + * + * Return: neighbor scan period + */ +uint16_t +ucfg_cm_get_neighbor_scan_period(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * ucfg_cm_get_wes_mode() - Get WES Mode + * This is a synchronous call + * @psoc: pointer to psoc object + * + * Return: WES Mode Enabled(1)/Disabled(0) + */ +bool ucfg_cm_get_wes_mode(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_cm_get_is_lfr_feature_enabled() - Get LFR feature enabled or not + * This is a synchronous call + * @psoc: pointer to psoc object + * + * Return: true (1) - if the feature is enabled + * false (0) - if feature is disabled (compile or runtime) + */ +bool ucfg_cm_get_is_lfr_feature_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_cm_get_is_ft_feature_enabled() - Get FT feature enabled or not + * This is a synchronous call + * @psoc: pointer to psoc object + * + * Return: true (1) - if the feature is enabled + * false (0) - if feature is disabled (compile or runtime) + */ +bool ucfg_cm_get_is_ft_feature_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_cm_get_roam_scan_home_away_time() - Get Roam scan home away time + * @psoc: Pointer to psoc + * @vdev_id: vdev identifier + * @roam_scan_home_away_time: Buffer to fill the roam scan home away time. + * Valid only if the return status is success. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_roam_scan_home_away_time(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint16_t *roam_scan_home_away_time); +/** + * ucfg_cm_get_roam_opportunistic_scan_threshold_diff() - + * get Opportunistic Scan threshold diff. + * This is a synchronous call + * @psoc: Pointer to psoc + * @val: Opportunistic Scan threshold diff. + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_roam_opportunistic_scan_threshold_diff( + struct wlan_objmgr_psoc *psoc, + int8_t *val); + +/** + * ucfg_cm_get_neighbor_scan_refresh_period() - Get neighbor scan results + * refresh period. + * This is a synchronous call + * @psoc: pointer to psoc object + * @value: value for scan results refresh period + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_neighbor_scan_refresh_period(struct wlan_objmgr_psoc *psoc, + uint16_t *value); + +/** + * ucfg_cm_get_empty_scan_refresh_period_global() - Get global scan + * refresh period + * @psoc: pointer to psoc object + * @roam_scan_period_global: value for empty scan refresh period + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_cm_get_empty_scan_refresh_period_global(struct wlan_objmgr_psoc *psoc, + uint16_t *roam_scan_period_global); + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_ROAM_INFO_STATS) +/** + * ucfg_cm_roam_stats_info_get() - get vdev roam stats info + * + * @vdev: pointer to vdev + * @roam_info: pointer to buffer to copy roam stats info + * @roam_num: pointer to valid roam stats num + * + * After use, roam_info must be released by using + * ucfg_cm_roam_stats_info_put() + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_cm_roam_stats_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint32_t *roam_num) +{ + return wlan_cm_roam_stats_info_get(vdev, roam_info, roam_num); +} + +/** + * ucfg_cm_roam_stats_info_put() - put vdev roam stats info + * + * @roam_info: pointer to buffer of roam stats info + * + * Return: QDF_STATUS + */ +static inline void +ucfg_cm_roam_stats_info_put(struct enhance_roam_info *roam_info) +{ + qdf_mem_free(roam_info); +} + +/** + * ucfg_cm_roam_info_get() - get vdev roam info + * + * @vdev: pointer to vdev + * @roam_info: pointer to buffer to copy roam stats info + * @idx: index of roam stats cache buffer + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +ucfg_cm_roam_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint8_t idx) +{ + return wlan_cm_roam_info_get(vdev, roam_info, idx); +} + +#else +static inline QDF_STATUS +ucfg_cm_roam_stats_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint32_t *roam_num) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +ucfg_cm_roam_stats_info_put(struct enhance_roam_info *roam_info) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * ucfg_cm_is_sae_auth_addr_conversion_required() - this api is wrapper for + * "wlan_cm_is_sae_auth_addr_conversion_required" function + * @vdev: pointer to vdev + * + * Return: true for address conversion otherwise false + */ +static inline bool +ucfg_cm_is_sae_auth_addr_conversion_required(struct wlan_objmgr_vdev *vdev) +{ + return wlan_cm_is_sae_auth_addr_conversion_required(vdev); +} +#else +static inline bool +ucfg_cm_is_sae_auth_addr_conversion_required(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +/** + * ucfg_cm_roaming_get_peer_mld_addr() - this api is wrapper for + * "wlan_cm_roaming_get_peer_mld_addr" function. + * @vdev: pointer to vdev + * + * Return: mld address of peer + */ +static inline struct qdf_mac_addr * +ucfg_cm_roaming_get_peer_mld_addr(struct wlan_objmgr_vdev *vdev) +{ + return wlan_cm_roaming_get_peer_mld_addr(vdev); +} +#else +static inline struct qdf_mac_addr * +ucfg_cm_roaming_get_peer_mld_addr(struct wlan_objmgr_vdev *vdev) +{ + return NULL; +} +#endif +#endif /* _WLAN_CM_ROAM_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_tgt_if_tx_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_tgt_if_tx_api.h new file mode 100644 index 0000000000..2e66792c75 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/inc/wlan_cm_tgt_if_tx_api.h @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cm_tgt_if_tx_api.h + * + * This file contains connection manager tx ops related functions + */ + +#ifndef CM_TGT_IF_TX_API_H__ +#define CM_TGT_IF_TX_API_H__ + +#include "wlan_cm_roam_public_struct.h" + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_cm_tgt_send_roam_mlo_config() - Send roam mlo config to firmware + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam mlo config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_mlo_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_mlo_config *req); +#else +static inline +QDF_STATUS wlan_cm_tgt_send_roam_mlo_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_mlo_config *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_cm_roam_send_set_vdev_pcl() - Send vdev set pcl command to firmware + * @psoc: PSOC pointer + * @pcl_req: Set pcl request structure pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_roam_send_set_vdev_pcl(struct wlan_objmgr_psoc *psoc, + struct set_pcl_req *pcl_req); + +/** + * wlan_cm_tgt_send_roam_rt_stats_config() - Send roam event stats config + * command to FW + * @psoc: psoc pointer + * @req: roam stats config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_rt_stats_config(struct wlan_objmgr_psoc *psoc, + struct roam_disable_cfg *req); + +/** + * wlan_cm_tgt_send_roam_ho_delay_config() - Send roam HO delay config command + * to FW + * @psoc: psoc pointer + * @vdev_id: vdev id + * @roam_ho_delay: roam hand-off delay value + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint16_t roam_ho_delay); + +/** + * wlan_cm_tgt_exclude_rm_partial_scan_freq() - Exclude the channels in roam + * full scan that are already scanned as part of partial scan. + * @psoc: psoc pointer + * @vdev_id: vdev id + * @exclude_rm_partial_scan_freq: Exclude the channels in roam full scan that + * are already scanned as part of partial scan. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_tgt_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t exclude_rm_partial_scan_freq); + +/** + * wlan_cm_tgt_send_roam_full_scan_6ghz_on_disc() - Include the 6 GHz channels + * in roam full scan only on prior discovery of any 6 GHz support in the + * environment. + * @psoc: PSOC pointer + * @vdev_id: vdev ID + * @roam_full_scan_6ghz_on_disc: Include the 6 GHz channels in roam full scan: + * 1 - Include only on prior discovery of any 6 GHz support in the environment + * 0 - Include all the supported 6 GHz channels by default + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_full_scan_6ghz_on_disc( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t roam_full_scan_6ghz_on_disc); + +/** + * wlan_cm_tgt_send_roam_scan_offload_rssi_params() - Set the RSSI parameters + * for roam offload scan + * @vdev: Pointer to vdev object + * @roam_rssi_params: structure containing parameters for roam offload scan + * based on RSSI + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_tgt_send_roam_scan_offload_rssi_params( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params); + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * wlan_cm_tgt_send_roam_linkspeed_state() - Send roam link speed state + * command to FW + * @psoc: psoc pointer + * @req: roam stats config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_linkspeed_state(struct wlan_objmgr_psoc *psoc, + struct roam_disable_cfg *req); +#endif +#else +static inline QDF_STATUS +wlan_cm_roam_send_set_vdev_pcl(struct wlan_objmgr_psoc *psoc, + struct set_pcl_req *pcl_req) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +wlan_cm_tgt_send_roam_rt_stats_config(struct wlan_objmgr_psoc *psoc, + struct roam_disable_cfg *req) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +QDF_STATUS wlan_cm_tgt_send_roam_mlo_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_mlo_config *req) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_cm_tgt_send_roam_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t roam_ho_delay) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +wlan_cm_tgt_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t exclude_rm_partial_scan_freq) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +wlan_cm_tgt_send_roam_full_scan_6ghz_on_disc( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t roam_full_scan_6ghz_on_disc) +{ + return QDF_STATUS_E_FAILURE; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * wlan_cm_tgt_send_roam_vendor_handoff_config() - Send vendor handoff config + * command to firmware + * @psoc: PSOC pointer + * @req: vendor handoff command params + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_tgt_send_roam_vendor_handoff_config(struct wlan_objmgr_psoc *psoc, + struct vendor_handoff_cfg *req); +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) + +#define CFG_DISABLE_4WAY_HS_OFFLOAD_DEFAULT BIT(0) + +/** + * wlan_cm_tgt_send_roam_offload_init() - Send wmi_vdev_param_roam_fw_offload + * to init/deinit roaming module at firmware + * @psoc: PSOC pointer + * @vdev_id: vdev id + * @is_init: true if roam module is to be initialized else false for deinit + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_offload_init(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_init); + +/** + * wlan_cm_tgt_send_roam_start_req() - Send roam start command to firmware + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam start config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_start_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_start_config *req); + +/** + * wlan_cm_tgt_send_roam_stop_req() - Send roam stop command to firmware + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam stop config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_stop_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_stop_config *req); + +/** + * wlan_cm_tgt_send_roam_update_req() - Send roam update command to firmware + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam update config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_update_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_update_config *req); +/** + * wlan_cm_tgt_send_roam_freqs() - Send roam frequencies to firmware + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam frequency list to be sent to fw + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_tgt_send_roam_freqs(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_scan_channel_list *req); + +/** + * wlan_cm_tgt_send_roam_abort_req() - Send roam abort command to firmware + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_abort_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_cm_tgt_send_roam_per_config() - Send roam per config command to FW + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: per roam config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_per_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_per_roam_config_req *req); + +/** + * wlan_cm_tgt_send_roam_triggers() - Send roam trigger command to FW + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam trigger parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_triggers(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_triggers *req); + +/** + * wlan_cm_tgt_send_roam_invoke_req() - Send roam trigger command to FW + * @psoc: psoc pointer + * @roam_invoke_req: roam invoke parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_tgt_send_roam_invoke_req(struct wlan_objmgr_psoc *psoc, + struct roam_invoke_req *roam_invoke_req); + +/** + * wlan_cm_tgt_send_roam_sync_complete_cmd() - Send roam sync command to FW + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_cm_tgt_send_roam_sync_complete_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#endif + +/** + * wlan_cm_tgt_send_roam_disable_config() - Send roam disable config command + * to FW + * @psoc: psoc pointer + * @vdev_id: vdev id + * @req: roam disable config parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cm_tgt_send_roam_disable_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct roam_disable_cfg *req); +#endif /* CM_TGT_IF_TX_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c new file mode 100644 index 0000000000..a2e7391731 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c @@ -0,0 +1,5884 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_api.c + * + * Implementation for the Common Roaming interfaces. + */ + +#include "wlan_cm_roam_api.h" +#include "wlan_vdev_mlme_api.h" +#include "wlan_mlme_main.h" +#include "wlan_policy_mgr_api.h" +#include +#include <../../core/src/wlan_cm_vdev_api.h> +#include "wlan_crypto_global_api.h" +#include +#include "connection_mgr/core/src/wlan_cm_roam.h" +#include "wlan_cm_roam_api.h" +#include "wlan_dlm_api.h" +#include <../../core/src/wlan_cm_roam_i.h> +#include "wlan_reg_ucfg_api.h" +#include "wlan_connectivity_logging.h" +#include "target_if.h" +#include "wlan_mlo_mgr_roam.h" +#include + +/* Support for "Fast roaming" (i.e., ESE, LFR, or 802.11r.) */ +#define BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN 15 +#define CM_MIN_RSSI 0 /* 0dbm */ + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS +wlan_cm_enable_roaming_on_connected_sta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + uint32_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t sta_vdev_id = WLAN_INVALID_VDEV_ID; + uint32_t count, idx; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + sta_vdev_id = policy_mgr_get_roam_enabled_sta_session_id(psoc, vdev_id); + if (sta_vdev_id != WLAN_UMAC_VDEV_ID_MAX) + return QDF_STATUS_E_FAILURE; + + count = policy_mgr_get_mode_specific_conn_info(psoc, + op_ch_freq_list, + vdev_id_list, + PM_STA_MODE); + if (!count) + return QDF_STATUS_E_FAILURE; + + /* + * Loop through all connected STA vdevs and roaming will be enabled + * on the STA that has a different vdev id from the one passed as + * input and has non zero roam trigger value. + */ + for (idx = 0; idx < count; idx++) { + if (vdev_id_list[idx] != vdev_id && + mlme_get_roam_trigger_bitmap(psoc, vdev_id_list[idx])) { + sta_vdev_id = vdev_id_list[idx]; + break; + } + } + + if (sta_vdev_id == WLAN_INVALID_VDEV_ID) + return QDF_STATUS_E_FAILURE; + + if (mlo_check_is_given_vdevs_on_same_mld(psoc, sta_vdev_id, vdev_id)) { + mlme_debug("RSO_CFG: vdev:%d , vdev:%d are on same MLD skip RSO enable", + sta_vdev_id, vdev_id); + + return QDF_STATUS_E_FAILURE; + } + + mlme_debug("ROAM: Enabling roaming on vdev[%d]", sta_vdev_id); + + return cm_roam_state_change(pdev, + sta_vdev_id, + WLAN_ROAM_RSO_ENABLED, + REASON_CTX_INIT, + NULL, false); +} + +QDF_STATUS wlan_cm_roam_state_change(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + enum roam_offload_state requested_state, + uint8_t reason) +{ + return cm_roam_state_change(pdev, vdev_id, requested_state, reason, + NULL, false); +} + +QDF_STATUS wlan_cm_roam_send_rso_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t rso_command, + uint8_t reason) +{ + return cm_roam_send_rso_cmd(psoc, vdev_id, rso_command, reason); +} + +void wlan_cm_handle_sta_sta_roaming_enablement(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return cm_handle_sta_sta_roaming_enablement(psoc, vdev_id); +} + +QDF_STATUS +wlan_roam_update_cfg(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + if (!MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + mlme_debug("Update cfg received while ROAM RSO not started"); + return QDF_STATUS_E_INVAL; + } + + return cm_roam_send_rso_cmd(psoc, vdev_id, ROAM_SCAN_OFFLOAD_UPDATE_CFG, + reason); +} + +#endif + +void +cm_update_associated_ch_info(struct wlan_objmgr_vdev *vdev, bool is_update) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_channel *des_chan; + struct assoc_channel_info *assoc_chan_info; + struct wlan_objmgr_pdev *pdev; + enum phy_ch_width ch_width; + QDF_STATUS status; + uint8_t band_mask; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("invalid pdev"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + assoc_chan_info = &mlme_priv->connect_info.assoc_chan_info; + if (!is_update) { + assoc_chan_info->assoc_ch_width = CH_WIDTH_INVALID; + return; + } + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) + return; + + /* If operating mode is STA / P2P-CLI then get the channel width + * from phymode. This is due the reason where actual operating + * channel width is configured as part of WMI_PEER_ASSOC_CMDID + * which could be downgraded while the peer associated. + * If there is a failure or operating mode is not STA / P2P-CLI + * then get channel width from wlan_channel. + */ + status = wlan_mlme_get_sta_ch_width(vdev, &ch_width); + if (QDF_IS_STATUS_ERROR(status)) + assoc_chan_info->assoc_ch_width = des_chan->ch_width; + else + assoc_chan_info->assoc_ch_width = ch_width; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(des_chan->ch_freq) && + des_chan->ch_width == CH_WIDTH_40MHZ) { + if (des_chan->ch_cfreq1 == des_chan->ch_freq + BW_10_MHZ) + assoc_chan_info->sec_2g_freq = + des_chan->ch_freq + BW_20_MHZ; + if (des_chan->ch_cfreq1 == des_chan->ch_freq - BW_10_MHZ) + assoc_chan_info->sec_2g_freq = + des_chan->ch_freq - BW_20_MHZ; + } else if (des_chan->ch_width == CH_WIDTH_320MHZ) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(des_chan->ch_freq)) + band_mask = BIT(REG_BAND_6G); + else + band_mask = BIT(REG_BAND_5G); + assoc_chan_info->cen320_freq = + wlan_reg_chan_band_to_freq(pdev, + des_chan->ch_freq_seg2, + band_mask); + + mlme_debug("ch_freq_seg2: %d, cen320_freq: %d", + des_chan->ch_freq_seg2, + assoc_chan_info->cen320_freq); + } + + mlme_debug("ch width :%d, ch_freq:%d, ch_cfreq1:%d, sec_2g_freq:%d", + assoc_chan_info->assoc_ch_width, des_chan->ch_freq, + des_chan->ch_cfreq1, assoc_chan_info->sec_2g_freq); +} + +char *cm_roam_get_requestor_string(enum wlan_cm_rso_control_requestor requestor) +{ + switch (requestor) { + case RSO_INVALID_REQUESTOR: + default: + return "No requestor"; + case RSO_START_BSS: + return "SAP start"; + case RSO_CHANNEL_SWITCH: + return "CSA"; + case RSO_CONNECT_START: + return "STA connection"; + case RSO_SAP_CHANNEL_CHANGE: + return "SAP Ch switch"; + case RSO_NDP_CON_ON_NDI: + return "NDP connection"; + case RSO_SET_PCL: + return "Set PCL"; + } +} + +QDF_STATUS +wlan_cm_rso_set_roam_trigger(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct wlan_roam_triggers *trigger) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto release_ref; + + status = cm_rso_set_roam_trigger(pdev, vdev_id, trigger); + + cm_roam_release_lock(vdev); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +QDF_STATUS wlan_cm_disable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + enum wlan_cm_rso_control_requestor requestor, + uint8_t reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + QDF_STATUS status; + uint8_t disable_reason = REASON_DRIVER_DISABLED; + + if (reason == REASON_DRIVER_DISABLED && requestor) + mlme_set_operations_bitmap(psoc, vdev_id, requestor, false); + + if (reason == REASON_VDEV_RESTART_FROM_HOST) + disable_reason = REASON_VDEV_RESTART_FROM_HOST; + + mlme_debug("ROAM_CONFIG: vdev[%d] Disable roaming - requestor:%s", + vdev_id, cm_roam_get_requestor_string(requestor)); + + status = cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_STOPPED, + disable_reason, NULL, false); + + return status; +} + +QDF_STATUS wlan_cm_enable_rso(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + enum wlan_cm_rso_control_requestor requestor, + uint8_t reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + QDF_STATUS status; + uint8_t enable_reason = REASON_DRIVER_ENABLED; + + if (reason == REASON_DRIVER_ENABLED && requestor) + mlme_set_operations_bitmap(psoc, vdev_id, requestor, true); + + if (reason == REASON_VDEV_RESTART_FROM_HOST) + enable_reason = REASON_VDEV_RESTART_FROM_HOST; + + mlme_debug("ROAM_CONFIG: vdev[%d] Enable roaming - requestor:%s", + vdev_id, cm_roam_get_requestor_string(requestor)); + + status = cm_roam_state_change(pdev, vdev_id, WLAN_ROAM_RSO_ENABLED, + enable_reason, NULL, false); + + return status; +} + +bool wlan_cm_host_roam_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool host_roam_in_progress = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return host_roam_in_progress; + } + + if (wlan_cm_is_vdev_roam_preauth_state(vdev) || + wlan_cm_is_vdev_roam_reassoc_state(vdev)) + host_roam_in_progress = true; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return host_roam_in_progress; +} + +bool wlan_cm_roaming_in_progress(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + bool roaming_in_progress = false; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return roaming_in_progress; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) + goto exit; + + roaming_in_progress = wlan_cm_is_vdev_roaming(vdev); + +exit: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return roaming_in_progress; +} + +QDF_STATUS wlan_cm_roam_stop_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + return cm_roam_stop_req(psoc, vdev_id, reason, NULL, false); +} + +bool wlan_cm_same_band_sta_allowed(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct dual_sta_policy *dual_sta_policy; + + if (!wlan_mlme_get_dual_sta_roaming_enabled(psoc)) + return true; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return true; + + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + if (dual_sta_policy->primary_vdev_id != WLAN_UMAC_VDEV_ID_MAX && + dual_sta_policy->concurrent_sta_policy == + QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY) + return true; + + return false; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +QDF_STATUS wlan_cm_send_roam_linkspeed_state(struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct roam_link_speed_cfg *link_speed_cfg; + struct roam_disable_cfg roam_link_speed_cfg; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + link_speed_cfg = msg->bodyptr; + roam_link_speed_cfg.vdev_id = link_speed_cfg->vdev_id; + roam_link_speed_cfg.cfg = link_speed_cfg->is_link_speed_good; + status = wlan_cm_tgt_send_roam_linkspeed_state(link_speed_cfg->psoc, + &roam_link_speed_cfg); + qdf_mem_free(link_speed_cfg); + + return status; +} + +void wlan_cm_roam_link_speed_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good) +{ + QDF_STATUS qdf_status; + struct scheduler_msg msg = {0}; + struct roam_link_speed_cfg *link_speed_cfg; + + link_speed_cfg = qdf_mem_malloc(sizeof(*link_speed_cfg)); + if (!link_speed_cfg) + return; + + link_speed_cfg->psoc = psoc; + link_speed_cfg->vdev_id = vdev_id; + link_speed_cfg->is_link_speed_good = is_link_speed_good; + + msg.bodyptr = link_speed_cfg; + msg.callback = wlan_cm_send_roam_linkspeed_state; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_MLME, + QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &msg); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + mlme_err("post msg failed"); + qdf_mem_free(link_speed_cfg); + } +} + +bool wlan_cm_is_linkspeed_roam_trigger_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + mlme_debug("Invalid WMI handle"); + return false; + } + + return wmi_service_enabled(wmi_handle, + wmi_service_linkspeed_roam_trigger_support); +} +#endif + +QDF_STATUS +wlan_cm_fw_roam_abort_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return cm_fw_roam_abort_req(psoc, vdev_id); +} + +uint32_t wlan_cm_get_roam_band_value(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct cm_roam_values_copy config; + uint32_t band_mask; + + wlan_cm_roam_cfg_get_value(psoc, wlan_vdev_get_id(vdev), ROAM_BAND, + &config); + + band_mask = config.uint_value; + mlme_debug("[ROAM BAND] band mask:%d", band_mask); + return band_mask; +} + +void wlan_cm_roam_activate_pcl_per_vdev(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool pcl_per_vdev) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + /* value - true (vdev pcl) false - pdev pcl */ + mlme_priv->cm_roam.pcl_vdev_cmd_active = pcl_per_vdev; + mlme_debug("CM_ROAM: vdev[%d] SET PCL cmd level - [%s]", vdev_id, + pcl_per_vdev ? "VDEV" : "PDEV"); +} + +bool wlan_cm_roam_is_pcl_per_vdev_active(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return false; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return false; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return mlme_priv->cm_roam.pcl_vdev_cmd_active; +} + +/** + * wlan_cm_dual_sta_is_freq_allowed() - This API is used to check if the + * provided frequency is allowed for the 2nd STA vdev for connection. + * @psoc: Pointer to PSOC object + * @freq: Frequency in the given frequency list for the STA that is about to + * connect + * @connected_sta_freq: 1st connected sta freq + * + * Make sure to validate the STA+STA condition before calling this + * + * Return: True if this channel is allowed for connection when dual sta roaming + * is enabled + */ +static bool +wlan_cm_dual_sta_is_freq_allowed(struct wlan_objmgr_psoc *psoc, + qdf_freq_t freq, qdf_freq_t connected_sta_freq) +{ + if (!connected_sta_freq) + return true; + + if (policy_mgr_2_freq_always_on_same_mac(psoc, freq, + connected_sta_freq)) + return false; + + return true; +} + +void +wlan_cm_dual_sta_roam_update_connect_channels(struct wlan_objmgr_psoc *psoc, + struct scan_filter *filter) +{ + uint32_t i, num_channels = 0; + uint32_t *channel_list; + bool is_ch_allowed; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_mlme_cfg *mlme_cfg; + struct dual_sta_policy *dual_sta_policy; + uint32_t buff_len; + char *chan_buff; + uint32_t len = 0; + uint32_t sta_count; + qdf_freq_t op_ch_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + + filter->num_of_channels = 0; + sta_count = policy_mgr_get_mode_specific_conn_info(psoc, op_ch_freq_list, + vdev_id_list, + PM_STA_MODE); + + /* No need to fill freq list, if no other STA is in connected state */ + if (!sta_count) + return; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + mlme_cfg = &mlme_obj->cfg; + + mlme_debug("sta_count %d, primary vdev is %d dual sta roaming enabled %d", + sta_count, dual_sta_policy->primary_vdev_id, + wlan_mlme_get_dual_sta_roaming_enabled(psoc)); + + if (!wlan_mlme_get_dual_sta_roaming_enabled(psoc)) + return; + + /* + * Check if primary iface is configured. If yes, + * then allow further STA connection to all + * available bands/channels irrespective of first + * STA connection band, which allow driver to + * connect with the best available AP present in + * environment, so that user can switch to second + * connection and mark it as primary. + */ + if (wlan_mlme_is_primary_interface_configured(psoc)) + return; + + /* + * If an ML STA exists with more than one link, allow further STA + * connection to all available bands/channels irrespective of existing + * STA connection/link band. Link that is causing MCC with the second + * STA can be disabled post connection. + * TODO: Check if disabling the MCC link is allowed or not. TID to + * link mapping restricts disabling the link. + * + * If only one ML link is present, allow the second STA only on other + * mac than this link mac. If second STA is allowed on the same mac + * also, it may result in MCC and the link can't be disabled + * post connection as only one link is present. + */ + if (policy_mgr_is_mlo_sta_present(psoc) && sta_count > 1) { + mlme_debug("Multi link mlo sta present"); + return; + } + + /* + * Get Reg domain valid channels and update to the scan filter + * if already 1st sta is in connected state. Don't allow channels + * on which the 1st STA is connected. + */ + num_channels = mlme_cfg->reg.valid_channel_list_num; + channel_list = mlme_cfg->reg.valid_channel_freq_list; + + /* + * Buffer of (num channel * 5) + 1 to consider the 4 char freq, + * 1 space after it for each channel and 1 to end the string + * with NULL. + */ + buff_len = (num_channels * 5) + 1; + chan_buff = qdf_mem_malloc(buff_len); + if (!chan_buff) + return; + + for (i = 0; i < num_channels; i++) { + is_ch_allowed = + wlan_cm_dual_sta_is_freq_allowed(psoc, channel_list[i], + op_ch_freq_list[0]); + if (!is_ch_allowed) + continue; + + filter->chan_freq_list[filter->num_of_channels] = + channel_list[i]; + filter->num_of_channels++; + + len += qdf_scnprintf(chan_buff + len, buff_len - len, + "%d ", channel_list[i]); + } + + if (filter->num_of_channels) + mlme_debug("Freq list (%d): %s", filter->num_of_channels, + chan_buff); + + qdf_mem_free(chan_buff); +} + +void +wlan_cm_roam_set_vendor_btm_params(struct wlan_objmgr_psoc *psoc, + struct wlan_cm_roam_vendor_btm_params *param) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + qdf_mem_copy(&mlme_obj->cfg.lfr.vendor_btm_param, param, + sizeof(struct wlan_cm_roam_vendor_btm_params)); +} + +void +wlan_cm_roam_get_vendor_btm_params(struct wlan_objmgr_psoc *psoc, + struct wlan_cm_roam_vendor_btm_params *param) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + qdf_mem_copy(param, &mlme_obj->cfg.lfr.vendor_btm_param, + sizeof(struct wlan_cm_roam_vendor_btm_params)); +} + +void wlan_cm_set_psk_pmk(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t pmk_len) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + qdf_mem_zero(rso_cfg->psk_pmk, sizeof(rso_cfg->psk_pmk)); + if (psk_pmk) + qdf_mem_copy(rso_cfg->psk_pmk, psk_pmk, pmk_len); + rso_cfg->pmk_len = pmk_len; + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_MLME, QDF_TRACE_LEVEL_DEBUG, + rso_cfg->psk_pmk, WLAN_MAX_PMK_DUMP_BYTES); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void wlan_cm_get_psk_pmk(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *psk_pmk, + uint8_t *pmk_len) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + if (!psk_pmk || !pmk_len) + return; + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + qdf_mem_copy(psk_pmk, rso_cfg->psk_pmk, rso_cfg->pmk_len); + *pmk_len = rso_cfg->pmk_len; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void +wlan_cm_roam_get_score_delta_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_triggers *params) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + params->score_delta_param[IDLE_ROAM_TRIGGER] = + mlme_obj->cfg.trig_score_delta[IDLE_ROAM_TRIGGER]; + params->score_delta_param[BTM_ROAM_TRIGGER] = + mlme_obj->cfg.trig_score_delta[BTM_ROAM_TRIGGER]; +} + +void +wlan_cm_roam_get_min_rssi_params(struct wlan_objmgr_psoc *psoc, + struct wlan_roam_triggers *params) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + params->min_rssi_params[DEAUTH_MIN_RSSI] = + mlme_obj->cfg.trig_min_rssi[DEAUTH_MIN_RSSI]; + params->min_rssi_params[BMISS_MIN_RSSI] = + mlme_obj->cfg.trig_min_rssi[BMISS_MIN_RSSI]; + params->min_rssi_params[MIN_RSSI_2G_TO_5G_ROAM] = + mlme_obj->cfg.trig_min_rssi[MIN_RSSI_2G_TO_5G_ROAM]; +} +#endif + +QDF_STATUS wlan_cm_roam_cfg_get_value(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum roam_cfg_param roam_cfg_type, + struct cm_roam_values_copy *dst_config) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct rso_config *rso_cfg; + struct rso_cfg_params *src_cfg; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + qdf_mem_zero(dst_config, sizeof(*dst_config)); + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + src_cfg = &rso_cfg->cfg_param; + switch (roam_cfg_type) { + case RSSI_CHANGE_THRESHOLD: + dst_config->int_value = rso_cfg->rescan_rssi_delta; + break; + case IS_DISABLE_BTM: + dst_config->bool_value = rso_cfg->is_disable_btm; + break; + case BEACON_RSSI_WEIGHT: + dst_config->uint_value = rso_cfg->beacon_rssi_weight; + break; + case HI_RSSI_DELAY_BTW_SCANS: + dst_config->uint_value = rso_cfg->hi_rssi_scan_delay; + break; + case EMPTY_SCAN_REFRESH_PERIOD: + dst_config->uint_value = src_cfg->empty_scan_refresh_period; + break; + case SCAN_MIN_CHAN_TIME: + dst_config->uint_value = src_cfg->min_chan_scan_time; + break; + case SCAN_MAX_CHAN_TIME: + dst_config->uint_value = src_cfg->max_chan_scan_time; + break; + case NEIGHBOR_SCAN_PERIOD: + dst_config->uint_value = src_cfg->neighbor_scan_period; + break; + case FULL_ROAM_SCAN_PERIOD: + dst_config->uint_value = src_cfg->full_roam_scan_period; + break; + case ROAM_RSSI_DIFF: + dst_config->uint_value = src_cfg->roam_rssi_diff; + break; + case ROAM_RSSI_DIFF_6GHZ: + dst_config->uint_value = src_cfg->roam_rssi_diff_6ghz; + break; + case NEIGHBOUR_LOOKUP_THRESHOLD: + dst_config->uint_value = src_cfg->neighbor_lookup_threshold; + break; + case NEXT_RSSI_THRESHOLD: + dst_config->uint_value = src_cfg->next_rssi_threshold; + break; + case SCAN_N_PROBE: + dst_config->uint_value = src_cfg->roam_scan_n_probes; + break; + case SCAN_HOME_AWAY: + dst_config->uint_value = src_cfg->roam_scan_home_away_time; + break; + case NEIGHBOUR_SCAN_REFRESH_PERIOD: + dst_config->uint_value = + src_cfg->neighbor_results_refresh_period; + break; + case ROAM_CONTROL_ENABLE: + dst_config->bool_value = rso_cfg->roam_control_enable; + break; + case UAPSD_MASK: + dst_config->uint_value = rso_cfg->uapsd_mask; + break; + case MOBILITY_DOMAIN: + dst_config->bool_value = rso_cfg->mdid.mdie_present; + dst_config->uint_value = rso_cfg->mdid.mobility_domain; + break; + case IS_11R_CONNECTION: + dst_config->bool_value = rso_cfg->is_11r_assoc; + break; + case ADAPTIVE_11R_CONNECTION: + dst_config->bool_value = rso_cfg->is_adaptive_11r_connection; + break; + case HS_20_AP: + dst_config->bool_value = rso_cfg->hs_20_ap; + break; + case MBO_OCE_ENABLED_AP: + dst_config->uint_value = rso_cfg->mbo_oce_enabled_ap; + break; + case IS_SINGLE_PMK: + dst_config->bool_value = rso_cfg->is_single_pmk; + break; + case LOST_LINK_RSSI: + dst_config->int_value = rso_cfg->lost_link_rssi; + break; + case ROAM_BAND: + dst_config->uint_value = rso_cfg->roam_band_bitmask; + break; + case HI_RSSI_SCAN_RSSI_DELTA: + dst_config->uint_value = src_cfg->hi_rssi_scan_rssi_delta; + break; + case ROAM_CONFIG_ENABLE: + dst_config->bool_value = rso_cfg->roam_control_enable; + break; + default: + mlme_err("Invalid roam config requested:%d", roam_cfg_type); + status = QDF_STATUS_E_FAILURE; + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +void wlan_cm_set_disable_hi_rssi(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, bool value) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + + rso_cfg->disable_hi_rssi = value; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void wlan_cm_set_country_code(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *cc) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg || !cc) + goto release_vdev_ref; + + mlme_debug("Country info from bcn IE:%c%c 0x%x", cc[0], cc[1], cc[2]); + + qdf_mem_copy(rso_cfg->country_code, cc, REG_ALPHA2_LEN + 1); + +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +QDF_STATUS wlan_cm_get_country_code(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t *cc) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg || !cc) { + status = QDF_STATUS_E_INVAL; + goto release_vdev_ref; + } + + qdf_mem_copy(cc, rso_cfg->country_code, REG_ALPHA2_LEN + 1); + +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return status; +} + +#ifdef FEATURE_WLAN_ESE +void wlan_cm_set_ese_assoc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, bool value) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + + rso_cfg->is_ese_assoc = value; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +bool wlan_cm_get_ese_assoc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + static struct rso_config *rso_cfg; + struct wlan_objmgr_vdev *vdev; + bool ese_assoc; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return false; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return false; + } + + ese_assoc = rso_cfg->is_ese_assoc; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return ese_assoc; +} +#endif + +static QDF_STATUS +cm_roam_update_cfg(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto release_ref; + if (!MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + mlme_debug("Update cfg received while ROAM RSO not started"); + cm_roam_release_lock(vdev); + status = QDF_STATUS_E_INVAL; + goto release_ref; + } + + status = cm_roam_send_rso_cmd(psoc, vdev_id, + ROAM_SCAN_OFFLOAD_UPDATE_CFG, reason); + cm_roam_release_lock(vdev); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +void cm_dump_freq_list(struct rso_chan_info *chan_info) +{ + uint8_t *channel_list; + uint8_t i = 0, j = 0; + uint32_t buflen = CFG_VALID_CHANNEL_LIST_LEN * 4; + + channel_list = qdf_mem_malloc(buflen); + if (!channel_list) + return; + + if (chan_info->freq_list) { + for (i = 0; i < chan_info->num_chan; i++) { + if (j < buflen) + j += qdf_scnprintf(channel_list + j, buflen - j, + "%d ", + chan_info->freq_list[i]); + else + break; + } + } + + mlme_debug("frequency list [%u]: %s", i, channel_list); + qdf_mem_free(channel_list); +} + +static uint8_t +cm_append_pref_chan_list(struct rso_chan_info *chan_info, qdf_freq_t *freq_list, + uint8_t num_chan) +{ + uint8_t i = 0, j = 0; + + for (i = 0; i < chan_info->num_chan; i++) { + for (j = 0; j < num_chan; j++) + if (chan_info->freq_list[i] == freq_list[j]) + break; + + if (j < num_chan) + continue; + if (num_chan == CFG_VALID_CHANNEL_LIST_LEN) + break; + freq_list[num_chan++] = chan_info->freq_list[i]; + } + + return num_chan; +} + +/** + * cm_modify_chan_list_based_on_band() - Modify RSO channel list based on band + * @freq_list: Channel list coming from user space + * @num_chan: Number of channel present in freq_list buffer + * @band_bitmap: On basis of this band host modify RSO channel list + * + * Return: valid number of channel as per bandmap + */ +static uint8_t +cm_modify_chan_list_based_on_band(qdf_freq_t *freq_list, uint8_t num_chan, + uint32_t band_bitmap) +{ + uint8_t i = 0, valid_chan_num = 0; + + if (!(band_bitmap & BIT(REG_BAND_2G))) { + mlme_debug("disabling 2G"); + for (i = 0; i < num_chan; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq_list[i])) + freq_list[i] = 0; + } + } + + if (!(band_bitmap & BIT(REG_BAND_5G))) { + mlme_debug("disabling 5G"); + for (i = 0; i < num_chan; i++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(freq_list[i])) + freq_list[i] = 0; + } + } + + if (!(band_bitmap & BIT(REG_BAND_6G))) { + mlme_debug("disabling 6G"); + for (i = 0; i < num_chan; i++) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq_list[i])) + freq_list[i] = 0; + } + } + + for (i = 0; i < num_chan; i++) { + if (freq_list[i]) + freq_list[valid_chan_num++] = freq_list[i]; + } + + return valid_chan_num; +} + +static QDF_STATUS cm_create_bg_scan_roam_channel_list(struct rso_chan_info *chan_info, + const qdf_freq_t *chan_freq_lst, + const uint8_t num_chan) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + + chan_info->freq_list = qdf_mem_malloc(sizeof(qdf_freq_t) * num_chan); + if (!chan_info->freq_list) + return QDF_STATUS_E_NOMEM; + + chan_info->num_chan = num_chan; + for (i = 0; i < num_chan; i++) + chan_info->freq_list[i] = chan_freq_lst[i]; + + return status; +} + +/** + * cm_remove_disabled_channels() - Remove disabled channels as per current + * connected band + * @vdev: vdev common object + * @freq_list: Channel list coming from user space + * @num_chan: Number of channel present in freq_list buffer + * + * Return: Number of channels as per SETBAND mask + */ +static uint32_t cm_remove_disabled_channels(struct wlan_objmgr_vdev *vdev, + qdf_freq_t *freq_list, + uint8_t num_chan) +{ + struct regulatory_channel *cur_chan_list; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + uint32_t valid_chan_num = 0; + enum channel_state state; + uint32_t freq, i, j; + QDF_STATUS status; + uint32_t filtered_lst[NUM_CHANNELS] = {0}; + + cur_chan_list = + qdf_mem_malloc(NUM_CHANNELS * sizeof(struct regulatory_channel)); + if (!cur_chan_list) + return 0; + + status = wlan_reg_get_current_chan_list(pdev, cur_chan_list); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(cur_chan_list); + return 0; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + freq = cur_chan_list[i].center_freq; + state = wlan_reg_get_channel_state_for_pwrmode( + pdev, freq, + REG_CURRENT_PWR_MODE); + if (state != CHANNEL_STATE_DISABLE && + state != CHANNEL_STATE_INVALID) { + for (j = 0; j < num_chan; j++) { + if (freq == freq_list[j]) { + filtered_lst[valid_chan_num++] = + freq_list[j]; + break; + } + } + } + } + + mlme_debug("[ROAM_BAND]: num channel :%d", valid_chan_num); + for (i = 0; i < valid_chan_num; i++) + freq_list[i] = filtered_lst[i]; + + qdf_mem_free(cur_chan_list); + + return valid_chan_num; +} + +/** + * cm_update_roam_scan_channel_list() - Update channel list as per RSO chan info + * band bitmask + * @psoc: Psoc common object + * @vdev: vdev common object + * @rso_cfg: connect config to be used to send info in RSO + * @vdev_id: vdev id + * @chan_info: hannel list already sent via RSO + * @freq_list: Channel list coming from user space + * @num_chan: Number of channel present in freq_list buffer + * @update_preferred_chan: Decide whether to update preferred chan list or not + * + * Return: QDF_STATUS + */ +static QDF_STATUS +cm_update_roam_scan_channel_list(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, uint8_t vdev_id, + struct rso_chan_info *chan_info, + qdf_freq_t *freq_list, uint8_t num_chan, + bool update_preferred_chan) +{ + uint16_t pref_chan_cnt = 0; + uint32_t valid_chan_num = 0; + struct cm_roam_values_copy config; + uint32_t current_band; + + if (chan_info->num_chan) { + mlme_debug("Current channel num: %d", chan_info->num_chan); + cm_dump_freq_list(chan_info); + } + + if (update_preferred_chan) { + pref_chan_cnt = cm_append_pref_chan_list(chan_info, freq_list, + num_chan); + num_chan = pref_chan_cnt; + } + + num_chan = cm_remove_disabled_channels(vdev, freq_list, num_chan); + if (!num_chan) + return QDF_STATUS_E_FAILURE; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_BAND, &config); + ucfg_reg_get_band(wlan_vdev_get_pdev(vdev), ¤t_band); + /* No need to modify channel list if all channel is allowed */ + if (config.uint_value != current_band) { + valid_chan_num = + cm_modify_chan_list_based_on_band(freq_list, num_chan, + config.uint_value); + if (!valid_chan_num) { + mlme_debug("No valid channels left to send to the fw"); + return QDF_STATUS_E_FAILURE; + } + num_chan = valid_chan_num; + } + + cm_flush_roam_channel_list(chan_info); + cm_create_bg_scan_roam_channel_list(chan_info, freq_list, num_chan); + + mlme_debug("New channel num: %d", num_chan); + cm_dump_freq_list(chan_info); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cm_roam_cfg_set_value(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_cfg_param roam_cfg_type, + struct cm_roam_values_copy *src_config) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct rso_config *rso_cfg; + struct rso_cfg_params *dst_cfg; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_roam_scan_channel_list chan_info = {0}; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + dst_cfg = &rso_cfg->cfg_param; + mlme_debug("roam_cfg_type %d, uint val %d int val %d bool val %d num chan %d", + roam_cfg_type, src_config->uint_value, src_config->int_value, + src_config->bool_value, src_config->chan_info.num_chan); + switch (roam_cfg_type) { + case RSSI_CHANGE_THRESHOLD: + rso_cfg->rescan_rssi_delta = src_config->uint_value; + break; + case IS_DISABLE_BTM: + rso_cfg->is_disable_btm = src_config->bool_value; + break; + case BEACON_RSSI_WEIGHT: + rso_cfg->beacon_rssi_weight = src_config->uint_value; + break; + case HI_RSSI_DELAY_BTW_SCANS: + rso_cfg->hi_rssi_scan_delay = src_config->uint_value; + break; + case EMPTY_SCAN_REFRESH_PERIOD: + dst_cfg->empty_scan_refresh_period = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_EMPTY_SCAN_REF_PERIOD_CHANGED); + break; + case FULL_ROAM_SCAN_PERIOD: + dst_cfg->full_roam_scan_period = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_ROAM_FULL_SCAN_PERIOD_CHANGED); + break; + case ENABLE_SCORING_FOR_ROAM: + dst_cfg->enable_scoring_for_roam = src_config->bool_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_SCORING_CRITERIA_CHANGED); + break; + case SCAN_MIN_CHAN_TIME: + mlme_obj->cfg.lfr.neighbor_scan_min_chan_time = + src_config->uint_value; + dst_cfg->min_chan_scan_time = src_config->uint_value; + break; + case SCAN_MAX_CHAN_TIME: + dst_cfg->max_chan_scan_time = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_SCAN_CH_TIME_CHANGED); + break; + case NEIGHBOR_SCAN_PERIOD: + dst_cfg->neighbor_scan_period = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_SCAN_HOME_TIME_CHANGED); + break; + case ROAM_CONFIG_ENABLE: + rso_cfg->roam_control_enable = src_config->bool_value; + if (!rso_cfg->roam_control_enable) + break; + dst_cfg->roam_inactive_data_packet_count = 0; + dst_cfg->roam_scan_inactivity_time = 0; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_ROAM_CONTROL_CONFIG_ENABLED); + break; + case ROAM_PREFERRED_CHAN: + /* + * In RSO update command, the specific channel list is + * given priority. So flush the Specific channel list if + * preferred channel list is received. Else the channel list + * type will be filled as static instead of dynamic. + */ + cm_flush_roam_channel_list(&dst_cfg->specific_chan_info); + status = cm_update_roam_scan_channel_list(psoc, vdev, rso_cfg, + vdev_id, &dst_cfg->pref_chan_info, + src_config->chan_info.freq_list, + src_config->chan_info.num_chan, true); + if (QDF_IS_STATUS_ERROR(status)) + break; + if (!mlme_obj->cfg.lfr.roam_scan_offload_enabled) + break; + + chan_info.vdev_id = vdev_id; + chan_info.chan_count = dst_cfg->pref_chan_info.num_chan; + qdf_mem_copy(chan_info.chan_freq_list, + dst_cfg->pref_chan_info.freq_list, + chan_info.chan_count * sizeof(uint32_t)); + chan_info.chan_cache_type = CHANNEL_LIST_DYNAMIC; + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + break; + if (!MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + mlme_debug("PREF_CHAN received while ROAM RSO not started"); + cm_roam_release_lock(vdev); + status = QDF_STATUS_E_INVAL; + break; + } + cm_fill_rso_channel_list(psoc, vdev, rso_cfg, + &chan_info, + REASON_CHANNEL_LIST_CHANGED); + wlan_cm_tgt_send_roam_freqs(psoc, vdev_id, &chan_info); + cm_roam_release_lock(vdev); + break; + case ROAM_SPECIFIC_CHAN: + status = cm_update_roam_scan_channel_list(psoc, vdev, rso_cfg, + vdev_id, &dst_cfg->specific_chan_info, + src_config->chan_info.freq_list, + src_config->chan_info.num_chan, + false); + if (QDF_IS_STATUS_ERROR(status)) + break; + if (!mlme_obj->cfg.lfr.roam_scan_offload_enabled) + break; + + chan_info.vdev_id = vdev_id; + chan_info.chan_count = dst_cfg->specific_chan_info.num_chan; + qdf_mem_copy(chan_info.chan_freq_list, + dst_cfg->specific_chan_info.freq_list, + chan_info.chan_count * sizeof(uint32_t)); + chan_info.chan_cache_type = CHANNEL_LIST_DYNAMIC; + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + break; + if (!MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + mlme_debug("SPECIFIC_CHAN received while ROAM RSO not started"); + cm_roam_release_lock(vdev); + status = QDF_STATUS_E_INVAL; + break; + } + cm_fill_rso_channel_list(psoc, vdev, rso_cfg, + &chan_info, + REASON_CHANNEL_LIST_CHANGED); + wlan_cm_tgt_send_roam_freqs(psoc, vdev_id, &chan_info); + cm_roam_release_lock(vdev); + break; + case ROAM_RSSI_DIFF: + dst_cfg->roam_rssi_diff = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_RSSI_DIFF_CHANGED); + break; + case ROAM_RSSI_DIFF_6GHZ: + dst_cfg->roam_rssi_diff_6ghz = src_config->uint_value; + break; + case NEIGHBOUR_LOOKUP_THRESHOLD: + dst_cfg->neighbor_lookup_threshold = src_config->uint_value; + fallthrough; + case NEXT_RSSI_THRESHOLD: + dst_cfg->next_rssi_threshold = src_config->uint_value; + break; + case SCAN_N_PROBE: + dst_cfg->roam_scan_n_probes = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_NPROBES_CHANGED); + break; + case SCAN_HOME_AWAY: + dst_cfg->roam_scan_home_away_time = src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled && + src_config->bool_value) + cm_roam_update_cfg(psoc, vdev_id, + REASON_HOME_AWAY_TIME_CHANGED); + break; + case NEIGHBOUR_SCAN_REFRESH_PERIOD: + dst_cfg->neighbor_results_refresh_period = + src_config->uint_value; + mlme_obj->cfg.lfr.neighbor_scan_results_refresh_period = + src_config->uint_value; + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + cm_roam_update_cfg(psoc, vdev_id, + REASON_NEIGHBOR_SCAN_REFRESH_PERIOD_CHANGED); + break; + case UAPSD_MASK: + rso_cfg->uapsd_mask = src_config->uint_value; + break; + case MOBILITY_DOMAIN: + rso_cfg->mdid.mdie_present = src_config->bool_value; + rso_cfg->mdid.mobility_domain = src_config->uint_value; + break; + case IS_11R_CONNECTION: + rso_cfg->is_11r_assoc = src_config->bool_value; + break; + case ADAPTIVE_11R_CONNECTION: + rso_cfg->is_adaptive_11r_connection = src_config->bool_value; + break; + case HS_20_AP: + rso_cfg->hs_20_ap = src_config->bool_value; + break; + case MBO_OCE_ENABLED_AP: + rso_cfg->mbo_oce_enabled_ap = src_config->uint_value; + break; + case IS_SINGLE_PMK: + rso_cfg->is_single_pmk = src_config->bool_value; + break; + case LOST_LINK_RSSI: + rso_cfg->lost_link_rssi = src_config->int_value; + break; + case ROAM_BAND: + rso_cfg->roam_band_bitmask = src_config->uint_value; + mlme_debug("[ROAM BAND] Set roam band:%d", + rso_cfg->roam_band_bitmask); + break; + default: + mlme_err("Invalid roam config requested:%d", roam_cfg_type); + status = QDF_STATUS_E_FAILURE; + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +void wlan_roam_reset_roam_params(struct wlan_objmgr_vdev *vdev) +{ + struct rso_user_config *rso_usr_cfg; + + rso_usr_cfg = wlan_cm_get_rso_user_config(vdev); + if (!rso_usr_cfg) + return; + + /* + * clear all the allowlist parameters and remaining + * needs to be retained across connections. + */ + rso_usr_cfg->num_ssid_allowed_list = 0; + qdf_mem_zero(&rso_usr_cfg->ssid_allowed_list, + sizeof(struct wlan_ssid) * MAX_SSID_ALLOWED_LIST); +} + +static void cm_rso_chan_to_freq_list(struct wlan_objmgr_pdev *pdev, + qdf_freq_t *freq_list, + const uint8_t *chan_list, + uint32_t chan_list_len) +{ + uint32_t count; + + for (count = 0; count < chan_list_len; count++) + freq_list[count] = + wlan_reg_legacy_chan_to_freq(pdev, chan_list[count]); +} + +#ifdef WLAN_FEATURE_HOST_ROAM +static QDF_STATUS cm_init_reassoc_timer(struct rso_config *rso_cfg) +{ + QDF_STATUS status; + + status = qdf_mc_timer_init(&rso_cfg->reassoc_timer, QDF_TIMER_TYPE_SW, + cm_reassoc_timer_callback, &rso_cfg->ctx); + + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("Preauth Reassoc interval Timer allocation failed"); + + return status; +} + +static void cm_deinit_reassoc_timer(struct rso_config *rso_cfg) +{ + /* check if the timer is running */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&rso_cfg->reassoc_timer)) + qdf_mc_timer_stop(&rso_cfg->reassoc_timer); + + qdf_mc_timer_destroy(&rso_cfg->reassoc_timer); +} +#else +static inline QDF_STATUS cm_init_reassoc_timer(struct rso_config *rso_cfg) +{ + return QDF_STATUS_SUCCESS; +} +static inline void cm_deinit_reassoc_timer(struct rso_config *rso_cfg) {} +#endif + +QDF_STATUS wlan_cm_rso_config_init(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct rso_chan_info *chan_info; + struct rso_cfg_params *cfg_params; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + uint32_t current_band = REG_BAND_MASK_ALL; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_INVAL; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + status = cm_init_reassoc_timer(rso_cfg); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + qdf_mutex_create(&rso_cfg->cm_rso_lock); + cfg_params = &rso_cfg->cfg_param; + cfg_params->max_chan_scan_time = + mlme_obj->cfg.lfr.neighbor_scan_max_chan_time; + cfg_params->passive_max_chan_time = + mlme_obj->cfg.lfr.passive_max_channel_time; + cfg_params->min_chan_scan_time = + mlme_obj->cfg.lfr.neighbor_scan_min_chan_time; + cfg_params->neighbor_lookup_threshold = + mlme_obj->cfg.lfr.neighbor_lookup_rssi_threshold; + cfg_params->next_rssi_threshold = + mlme_obj->cfg.lfr.neighbor_lookup_rssi_threshold; + cfg_params->rssi_thresh_offset_5g = + mlme_obj->cfg.lfr.rssi_threshold_offset_5g; + cfg_params->opportunistic_threshold_diff = + mlme_obj->cfg.lfr.opportunistic_scan_threshold_diff; + cfg_params->roam_rescan_rssi_diff = + mlme_obj->cfg.lfr.roam_rescan_rssi_diff; + + cfg_params->roam_bmiss_first_bcn_cnt = + mlme_obj->cfg.lfr.roam_bmiss_first_bcnt; + cfg_params->roam_bmiss_final_cnt = + mlme_obj->cfg.lfr.roam_bmiss_final_bcnt; + + cfg_params->neighbor_scan_period = + mlme_obj->cfg.lfr.neighbor_scan_timer_period; + cfg_params->neighbor_scan_min_period = + mlme_obj->cfg.lfr.neighbor_scan_min_timer_period; + cfg_params->neighbor_results_refresh_period = + mlme_obj->cfg.lfr.neighbor_scan_results_refresh_period; + cfg_params->empty_scan_refresh_period = + mlme_obj->cfg.lfr.empty_scan_refresh_period; + cfg_params->full_roam_scan_period = + mlme_obj->cfg.lfr.roam_full_scan_period; + cfg_params->enable_scoring_for_roam = + mlme_obj->cfg.roam_scoring.enable_scoring_for_roam; + cfg_params->roam_scan_n_probes = + mlme_obj->cfg.lfr.roam_scan_n_probes; + cfg_params->roam_scan_home_away_time = + mlme_obj->cfg.lfr.roam_scan_home_away_time; + cfg_params->roam_scan_inactivity_time = + mlme_obj->cfg.lfr.roam_scan_inactivity_time; + cfg_params->roam_inactive_data_packet_count = + mlme_obj->cfg.lfr.roam_inactive_data_packet_count; + + chan_info = &cfg_params->specific_chan_info; + chan_info->num_chan = + mlme_obj->cfg.lfr.neighbor_scan_channel_list_num; + mlme_debug("number of channels: %u", chan_info->num_chan); + if (chan_info->num_chan) { + chan_info->freq_list = + qdf_mem_malloc(sizeof(qdf_freq_t) * + chan_info->num_chan); + if (!chan_info->freq_list) { + chan_info->num_chan = 0; + return QDF_STATUS_E_NOMEM; + } + /* Update the roam global structure from CFG */ + cm_rso_chan_to_freq_list(pdev, chan_info->freq_list, + mlme_obj->cfg.lfr.neighbor_scan_channel_list, + mlme_obj->cfg.lfr.neighbor_scan_channel_list_num); + } else { + chan_info->freq_list = NULL; + } + + cfg_params->hi_rssi_scan_max_count = + mlme_obj->cfg.lfr.roam_scan_hi_rssi_maxcount; + cfg_params->hi_rssi_scan_rssi_delta = + mlme_obj->cfg.lfr.roam_scan_hi_rssi_delta; + + cfg_params->hi_rssi_scan_delay = + mlme_obj->cfg.lfr.roam_scan_hi_rssi_delay; + + cfg_params->hi_rssi_scan_rssi_ub = + mlme_obj->cfg.lfr.roam_scan_hi_rssi_ub; + cfg_params->roam_rssi_diff = + mlme_obj->cfg.lfr.roam_rssi_diff; + cfg_params->roam_rssi_diff_6ghz = + mlme_obj->cfg.lfr.roam_rssi_diff_6ghz; + cfg_params->bg_rssi_threshold = + mlme_obj->cfg.lfr.bg_rssi_threshold; + + ucfg_reg_get_band(wlan_vdev_get_pdev(vdev), ¤t_band); + rso_cfg->roam_band_bitmask = current_band; + rso_cfg->is_disable_btm = false; + + return status; +} + +void wlan_cm_rso_config_deinit(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg) +{ + struct rso_cfg_params *cfg_params; + + cfg_params = &rso_cfg->cfg_param; + if (rso_cfg->assoc_ie.ptr) { + qdf_mem_free(rso_cfg->assoc_ie.ptr); + rso_cfg->assoc_ie.ptr = NULL; + rso_cfg->assoc_ie.len = 0; + } + if (rso_cfg->prev_ap_bcn_ie.ptr) { + qdf_mem_free(rso_cfg->prev_ap_bcn_ie.ptr); + rso_cfg->prev_ap_bcn_ie.ptr = NULL; + rso_cfg->prev_ap_bcn_ie.len = 0; + } + if (rso_cfg->roam_scan_freq_lst.freq_list) + qdf_mem_free(rso_cfg->roam_scan_freq_lst.freq_list); + rso_cfg->roam_scan_freq_lst.freq_list = NULL; + rso_cfg->roam_scan_freq_lst.num_chan = 0; + + cm_flush_roam_channel_list(&cfg_params->specific_chan_info); + cm_flush_roam_channel_list(&cfg_params->pref_chan_info); + + qdf_mutex_destroy(&rso_cfg->cm_rso_lock); + rso_cfg->is_disable_btm = false; + + cm_deinit_reassoc_timer(rso_cfg); +} + +struct rso_config *wlan_cm_get_rso_config_fl(struct wlan_objmgr_vdev *vdev, + const char *func, uint32_t line) + +{ + struct cm_ext_obj *cm_ext_obj; + enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev); + + /* get only for CLI and STA */ + if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) + return NULL; + + cm_ext_obj = cm_get_ext_hdl_fl(vdev, func, line); + if (!cm_ext_obj) + return NULL; + + return &cm_ext_obj->rso_cfg; +} + +struct rso_user_config * +wlan_cm_get_rso_user_config_fl(struct wlan_objmgr_vdev *vdev, + const char *func, uint32_t line) +{ + struct cm_ext_obj *cm_ext_obj; + enum QDF_OPMODE op_mode = wlan_vdev_mlme_get_opmode(vdev); + + /* get only for CLI and STA */ + if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) + return NULL; + + cm_ext_obj = cm_get_ext_hdl_fl(vdev, func, line); + if (!cm_ext_obj) + return NULL; + + return &cm_ext_obj->rso_usr_cfg; +} + +QDF_STATUS cm_roam_acquire_lock(struct wlan_objmgr_vdev *vdev) +{ + static struct rso_config *rso_cfg; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_INVAL; + + return qdf_mutex_acquire(&rso_cfg->cm_rso_lock); +} + +QDF_STATUS cm_roam_release_lock(struct wlan_objmgr_vdev *vdev) +{ + static struct rso_config *rso_cfg; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return QDF_STATUS_E_INVAL; + + return qdf_mutex_release(&rso_cfg->cm_rso_lock); +} + +QDF_STATUS +wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct qdf_mac_addr *bssid, qdf_freq_t chan_freq, + enum wlan_cm_source source) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + mlme_err("Invalid psoc"); + return QDF_STATUS_E_FAILURE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + mlme_debug("vdev: %d source: %d freq: %d bssid: " QDF_MAC_ADDR_FMT, + vdev_id, source, chan_freq, QDF_MAC_ADDR_REF(bssid->bytes)); + + status = cm_start_roam_invoke(psoc, vdev, bssid, chan_freq, source); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +bool cm_is_fast_roam_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + if (!mlme_obj->cfg.lfr.lfr_enabled) + return false; + + if (mlme_obj->cfg.lfr.enable_fast_roam_in_concurrency) + return true; + /* return true if no concurrency */ + if (policy_mgr_get_connection_count(psoc) < 2) + return true; + + return false; +} + +bool cm_is_rsn_or_8021x_sha256_auth_type(struct wlan_objmgr_vdev *vdev) +{ + int32_t akm; + + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return true; + + return false; +} + +#ifdef WLAN_FEATURE_HOST_ROAM +QDF_STATUS wlan_cm_host_roam_start(struct scheduler_msg *msg) +{ + QDF_STATUS status; + struct cm_host_roam_start_ind *req; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_ZERO_INIT; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_FAILURE; + + req = msg->bodyptr; + status = wlan_cm_roam_invoke(req->pdev, req->vdev_id, &bssid, 0, + CM_ROAMING_FW); + qdf_mem_free(req); + + return status; +} + +QDF_STATUS cm_mlme_roam_preauth_fail(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_roam_req *req, + enum wlan_cm_connect_fail_reason reason) +{ + uint8_t vdev_id, roam_reason; + struct wlan_objmgr_pdev *pdev; + + if (!vdev || !req) { + mlme_err("vdev or req is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (reason == CM_NO_CANDIDATE_FOUND) + roam_reason = REASON_NO_CAND_FOUND_OR_NOT_ROAMING_NOW; + else + roam_reason = REASON_PREAUTH_FAILED_FOR_ALL; + + pdev = wlan_vdev_get_pdev(vdev); + vdev_id = wlan_vdev_get_id(vdev); + + if (req->source == CM_ROAMING_FW) + cm_roam_state_change(pdev, vdev_id, + ROAM_SCAN_OFFLOAD_RESTART, + roam_reason, NULL, false); + else + cm_roam_state_change(pdev, vdev_id, + ROAM_SCAN_OFFLOAD_START, + roam_reason, NULL, false); + return QDF_STATUS_SUCCESS; +} +#endif + +void wlan_cm_fill_crypto_filter_from_vdev(struct wlan_objmgr_vdev *vdev, + struct scan_filter *filter) +{ + struct rso_config *rso_cfg; + + filter->authmodeset = + wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_AUTH_MODE); + filter->mcastcipherset = + wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MCAST_CIPHER); + filter->ucastcipherset = + wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_UCAST_CIPHER); + filter->key_mgmt = + wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + filter->mgmtcipherset = + wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_MGMT_CIPHER); + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + + if (rso_cfg->orig_sec_info.rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_REQUIRED) + filter->pmf_cap = WLAN_PMF_REQUIRED; + else if (rso_cfg->orig_sec_info.rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) + filter->pmf_cap = WLAN_PMF_CAPABLE; +} + +static void cm_dump_occupied_chan_list(struct wlan_chan_list *occupied_ch) +{ + uint8_t idx; + uint32_t buff_len; + char *chan_buff; + uint32_t len = 0; + + buff_len = (occupied_ch->num_chan * 5) + 1; + chan_buff = qdf_mem_malloc(buff_len); + if (!chan_buff) + return; + + for (idx = 0; idx < occupied_ch->num_chan; idx++) + len += qdf_scnprintf(chan_buff + len, buff_len - len, " %d", + occupied_ch->freq_list[idx]); + + mlme_nofl_debug("Occupied chan list[%d]:%s", + occupied_ch->num_chan, chan_buff); + + qdf_mem_free(chan_buff); +} + +/** + * cm_should_add_to_occupied_channels() - validates bands of active_ch_freq and + * curr node freq before addition of curr node freq to occupied channels + * + * @active_ch_freq: active channel frequency + * @cur_node_chan_freq: curr channel frequency + * @dual_sta_roam_active: dual sta roam active + * + * Return: True if active_ch_freq and cur_node_chan_freq belongs to same + * bands else false + **/ +static bool cm_should_add_to_occupied_channels(qdf_freq_t active_ch_freq, + qdf_freq_t cur_node_chan_freq, + bool dual_sta_roam_active) +{ + /* all channels can be added if dual STA roam is not active */ + if (!dual_sta_roam_active) + return true; + + /* when dual STA roam is active, channels must be in the same band */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(active_ch_freq) && + WLAN_REG_IS_24GHZ_CH_FREQ(cur_node_chan_freq)) + return true; + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(active_ch_freq) && + !WLAN_REG_IS_24GHZ_CH_FREQ(cur_node_chan_freq)) + return true; + + /* not in same band */ + return false; +} + +static QDF_STATUS cm_add_to_freq_list_front(qdf_freq_t *ch_freq_lst, + int num_chan, qdf_freq_t chan_freq) +{ + int i = 0; + + /* Check for NULL pointer */ + if (!ch_freq_lst) + return QDF_STATUS_E_NULL_VALUE; + + /* Make room for the addition. (Start moving from the back.) */ + for (i = num_chan; i > 0; i--) + ch_freq_lst[i] = ch_freq_lst[i - 1]; + + /* Now add the NEW channel...at the front */ + ch_freq_lst[0] = chan_freq; + + return QDF_STATUS_SUCCESS; +} + +/* Add the channel to the occupied channels array */ +static void cm_add_to_occupied_channels(qdf_freq_t ch_freq, + struct rso_config *rso_cfg, + bool is_init_list) +{ + QDF_STATUS status; + uint8_t num_occupied_ch = rso_cfg->occupied_chan_lst.num_chan; + qdf_freq_t *occupied_ch_lst = rso_cfg->occupied_chan_lst.freq_list; + + if (is_init_list) + rso_cfg->roam_candidate_count++; + + if (wlan_is_channel_present_in_list(occupied_ch_lst, + num_occupied_ch, ch_freq)) + return; + + if (num_occupied_ch >= CFG_VALID_CHANNEL_LIST_LEN) + num_occupied_ch = CFG_VALID_CHANNEL_LIST_LEN - 1; + + status = cm_add_to_freq_list_front(occupied_ch_lst, + num_occupied_ch, ch_freq); + if (QDF_IS_STATUS_SUCCESS(status)) { + rso_cfg->occupied_chan_lst.num_chan++; + if (rso_cfg->occupied_chan_lst.num_chan > + BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN) + rso_cfg->occupied_chan_lst.num_chan = + BG_SCAN_OCCUPIED_CHANNEL_LIST_LEN; + } +} + +void wlan_cm_init_occupied_ch_freq_list(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + qdf_list_t *list = NULL; + qdf_list_node_t *cur_lst = NULL; + qdf_list_node_t *next_lst = NULL; + struct scan_cache_node *cur_node = NULL; + struct scan_filter *filter; + bool dual_sta_roam_active; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + struct wlan_ssid ssid; + qdf_freq_t op_freq, freq; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + goto rel_vdev_ref; + op_freq = wlan_get_operation_chan_freq(vdev); + if (!op_freq) { + mlme_debug("failed to get op freq"); + goto rel_vdev_ref; + } + status = wlan_vdev_mlme_get_ssid(vdev, ssid.ssid, &ssid.length); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("failed to find SSID for vdev %d", vdev_id); + goto rel_vdev_ref; + } + + cfg_params = &rso_cfg->cfg_param; + + if (cfg_params->specific_chan_info.num_chan) { + /* + * Ini file contains neighbor scan channel list, hence NO need + * to build occupied channel list" + */ + mlme_debug("Ini contains neighbor scan ch list"); + goto rel_vdev_ref; + } + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + goto rel_vdev_ref; + + wlan_cm_fill_crypto_filter_from_vdev(vdev, filter); + filter->num_of_ssid = 1; + qdf_mem_copy(&filter->ssid_list[0], &ssid, sizeof(ssid)); + + /* Empty occupied channels here */ + rso_cfg->occupied_chan_lst.num_chan = 0; + rso_cfg->roam_candidate_count = 0; + + cm_add_to_occupied_channels(op_freq, rso_cfg, true); + list = wlan_scan_get_result(pdev, filter); + qdf_mem_free(filter); + if (!list || (list && !qdf_list_size(list))) + goto err; + + dual_sta_roam_active = + wlan_mlme_get_dual_sta_roaming_enabled(psoc); + dual_sta_roam_active = dual_sta_roam_active && + policy_mgr_mode_specific_connection_count + (psoc, PM_STA_MODE, NULL) >= 2; + + qdf_list_peek_front(list, &cur_lst); + while (cur_lst) { + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, + node); + freq = cur_node->entry->channel.chan_freq; + if (cm_should_add_to_occupied_channels(op_freq, freq, + dual_sta_roam_active)) + cm_add_to_occupied_channels(freq, rso_cfg, true); + + qdf_list_peek_next(list, cur_lst, &next_lst); + cur_lst = next_lst; + next_lst = NULL; + } +err: + cm_dump_occupied_chan_list(&rso_cfg->occupied_chan_lst); + if (list) + wlan_scan_purge_results(list); +rel_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS +wlan_cm_update_mlme_fils_info(struct wlan_objmgr_vdev *vdev, + struct wlan_fils_con_info *src_fils_info) +{ + struct mlme_legacy_priv *mlme_priv; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_fils_connection_info *tgt_info; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL for vdev %d", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (!src_fils_info) { + mlme_debug("FILS: vdev:%d Clear fils info", vdev_id); + qdf_mem_free(mlme_priv->connect_info.fils_con_info); + mlme_priv->connect_info.fils_con_info = NULL; + return QDF_STATUS_SUCCESS; + } + + if (mlme_priv->connect_info.fils_con_info) + qdf_mem_free(mlme_priv->connect_info.fils_con_info); + + mlme_priv->connect_info.fils_con_info = + qdf_mem_malloc(sizeof(struct wlan_fils_connection_info)); + if (!mlme_priv->connect_info.fils_con_info) + return QDF_STATUS_E_NOMEM; + + tgt_info = mlme_priv->connect_info.fils_con_info; + mlme_debug("FILS: vdev:%d update fils info", vdev_id); + tgt_info->is_fils_connection = src_fils_info->is_fils_connection; + tgt_info->key_nai_length = src_fils_info->username_len; + qdf_mem_copy(tgt_info->keyname_nai, src_fils_info->username, + tgt_info->key_nai_length); + + tgt_info->realm_len = src_fils_info->realm_len; + qdf_mem_copy(tgt_info->realm, src_fils_info->realm, + tgt_info->realm_len); + + tgt_info->r_rk_length = src_fils_info->rrk_len; + qdf_mem_copy(tgt_info->r_rk, src_fils_info->rrk, + tgt_info->r_rk_length); + tgt_info->erp_sequence_number = src_fils_info->next_seq_num; + tgt_info->auth_type = src_fils_info->auth_type; + + return QDF_STATUS_SUCCESS; +} + +void wlan_cm_update_hlp_info(struct wlan_objmgr_psoc *psoc, + const uint8_t *gen_ie, uint16_t len, + uint8_t vdev_id, bool flush) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev_id %d", vdev_id); + return; + } + + cm_update_hlp_info(vdev, gen_ie, len, flush); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +} + +struct wlan_fils_connection_info *wlan_cm_get_fils_connection_info( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + struct wlan_fils_connection_info *fils_info; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return NULL; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return NULL; + } + + fils_info = mlme_priv->connect_info.fils_con_info; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return fils_info; +} + +QDF_STATUS wlan_cm_update_fils_ft(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *fils_ft, + uint8_t fils_ft_len) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + + if (!mlme_priv->connect_info.fils_con_info || !fils_ft || + !fils_ft_len || + !mlme_priv->connect_info.fils_con_info->is_fils_connection) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->connect_info.fils_con_info->fils_ft_len = fils_ft_len; + qdf_mem_copy(mlme_priv->connect_info.fils_con_info->fils_ft, fils_ft, + fils_ft_len); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static void +wlan_cm_get_mlo_associated_ch_info(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width scanned_ch_width, + struct assoc_channel_info *assoc_chan_info) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_channel *des_chan; + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx = NULL; + uint8_t i; + struct wlan_objmgr_vdev *mlo_vdev; + struct assoc_channel_info *temp_assoc_chan_info; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + mlme_err("vdev %d :mlo_dev_ctx is NULL", + vdev->vdev_objmgr.vdev_id); + return; + } + + sta_ctx = mlo_dev_ctx->sta_ctx; + if (!sta_ctx) { + mlme_err("vdev %d :mlo_dev_ctx is NULL", + vdev->vdev_objmgr.vdev_id); + return; + } + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + if (qdf_test_bit(i, sta_ctx->wlan_connected_links)) { + mlo_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + des_chan = wlan_vdev_mlme_get_des_chan(mlo_vdev); + if (!des_chan) { + mlme_debug("NULL des_chan"); + return; + } + + if (des_chan->ch_width == scanned_ch_width) { + mlme_priv = + wlan_vdev_mlme_get_ext_hdl(mlo_vdev); + if (!mlme_priv) { + mlme_legacy_err("mlme_priv is NULL"); + return; + } + temp_assoc_chan_info = + &mlme_priv->connect_info.assoc_chan_info; + assoc_chan_info->sec_2g_freq = + temp_assoc_chan_info->sec_2g_freq; + mlme_debug("vdev %d: assoc sec_2g_freq:%d", + mlo_vdev->vdev_objmgr.vdev_id, + assoc_chan_info->sec_2g_freq); + break; + } + } + } +} +#else +static void +wlan_cm_get_mlo_associated_ch_info(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width ch_width, + struct assoc_channel_info *chan_info) +{ +} +#endif + +void wlan_cm_get_associated_ch_info(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width scanned_ch_width, + struct assoc_channel_info *assoc_chan_info) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + assoc_chan_info->assoc_ch_width = CH_WIDTH_INVALID; + assoc_chan_info->sec_2g_freq = 0; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_legacy_err("vdev %d: vdev not found", vdev_id); + return; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + mlme_debug("vdev %d: get assoc chan info for mlo connection", + vdev_id); + wlan_cm_get_mlo_associated_ch_info(vdev, scanned_ch_width, + assoc_chan_info); + goto release; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("mlme_priv is NULL"); + goto release; + } + + assoc_chan_info->assoc_ch_width = + mlme_priv->connect_info.assoc_chan_info.assoc_ch_width; + assoc_chan_info->sec_2g_freq = + mlme_priv->connect_info.assoc_chan_info.sec_2g_freq; + + mlme_debug("vdev %d: associated_ch_width:%d, sec_2g_freq:%d", vdev_id, + assoc_chan_info->assoc_ch_width, + assoc_chan_info->sec_2g_freq); + +release: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +wlan_cm_update_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_scan_scheme_bitmap) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + rso_cfg->roam_scan_scheme_bitmap = roam_scan_scheme_bitmap; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cm_set_roam_band_bitmask(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t roam_band_bitmask) +{ + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = roam_band_bitmask; + return wlan_cm_roam_cfg_set_value(psoc, vdev_id, ROAM_BAND, + &src_config); +} + +QDF_STATUS wlan_cm_set_btm_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_disable_btm) +{ + struct cm_roam_values_copy src_config = {}; + + src_config.bool_value = is_disable_btm; + return wlan_cm_roam_cfg_set_value(psoc, vdev_id, IS_DISABLE_BTM, + &src_config); +} + +static QDF_STATUS +cm_roam_refine_channels(struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct wlan_roam_scan_channel_list *chan_info, + struct rso_chan_info *cached_chan_info) +{ + struct rso_chan_info temp_chan_info = {0}, computed_chan_info = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + temp_chan_info.num_chan = cached_chan_info->num_chan; + computed_chan_info.num_chan = cached_chan_info->num_chan; + temp_chan_info.freq_list = qdf_mem_malloc( + temp_chan_info.num_chan * sizeof(qdf_freq_t)); + if (!temp_chan_info.freq_list) + goto done; + computed_chan_info.freq_list = qdf_mem_malloc( + temp_chan_info.num_chan * sizeof(qdf_freq_t)); + if (!computed_chan_info.freq_list) + goto done; + for (i = 0; i < temp_chan_info.num_chan; i++) { + temp_chan_info.freq_list[i] = + cached_chan_info->freq_list[i]; + computed_chan_info.freq_list[i] = + cached_chan_info->freq_list[i]; + } + status = cm_update_roam_scan_channel_list(wlan_vdev_get_psoc(vdev), + vdev, rso_cfg, + wlan_vdev_get_id(vdev), + &computed_chan_info, + temp_chan_info.freq_list, + temp_chan_info.num_chan, + false); + if (QDF_IS_STATUS_ERROR(status)) + goto done; + chan_info->chan_count = computed_chan_info.num_chan; + for (i = 0; i < chan_info->chan_count; i++) + chan_info->chan_freq_list[i] = computed_chan_info.freq_list[i]; + +done: + qdf_mem_free(temp_chan_info.freq_list); + qdf_mem_free(computed_chan_info.freq_list); + + return status; +} + +QDF_STATUS wlan_cm_set_roam_band_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct rso_config *rso_cfg; + struct rso_cfg_params *dst_cfg; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_roam_scan_channel_list chan_info = {0}; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (!mlme_obj->cfg.lfr.roam_scan_offload_enabled) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + status = QDF_STATUS_E_FAILURE; + goto done; + } + dst_cfg = &rso_cfg->cfg_param; + + chan_info.vdev_id = vdev_id; + if (dst_cfg->specific_chan_info.num_chan) { + status = cm_roam_refine_channels(vdev, rso_cfg, + &chan_info, + &dst_cfg->specific_chan_info); + if (QDF_IS_STATUS_ERROR(status)) + goto done; + chan_info.chan_cache_type = CHANNEL_LIST_STATIC; + } else if (dst_cfg->pref_chan_info.num_chan) { + status = cm_roam_refine_channels(vdev, rso_cfg, + &chan_info, + &dst_cfg->pref_chan_info); + if (QDF_IS_STATUS_ERROR(status)) + goto done; + chan_info.chan_cache_type = CHANNEL_LIST_DYNAMIC; + } else { + goto done; + } + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto done; + if (!MLME_IS_ROAM_STATE_RSO_ENABLED(psoc, vdev_id)) { + mlme_debug("CHAN update received while ROAM RSO not started"); + cm_roam_release_lock(vdev); + status = QDF_STATUS_E_INVAL; + goto done; + } + wlan_cm_tgt_send_roam_freqs(psoc, vdev_id, &chan_info); + cm_roam_release_lock(vdev); + +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return status; +} + +uint32_t wlan_cm_get_roam_scan_scheme_bitmap(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t roam_scan_scheme_bitmap; + struct rso_config *rso_cfg; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", vdev_id); + return 0; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return 0; + } + + roam_scan_scheme_bitmap = rso_cfg->roam_scan_scheme_bitmap; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return roam_scan_scheme_bitmap; +} + +QDF_STATUS +wlan_cm_update_roam_states(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t value, enum roam_fail_params states) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + + switch (states) { + case ROAM_TRIGGER_REASON: + rso_cfg->roam_trigger_reason = value; + break; + case ROAM_INVOKE_FAIL_REASON: + rso_cfg->roam_invoke_fail_reason = value; + break; + case ROAM_FAIL_REASON: + rso_cfg->roam_fail_reason = value; + break; + default: + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return QDF_STATUS_SUCCESS; +} + +uint32_t wlan_cm_get_roam_states(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + enum roam_fail_params states) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t roam_states = 0; + struct rso_config *rso_cfg; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", vdev_id); + return 0; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return 0; + } + + switch (states) { + case ROAM_TRIGGER_REASON: + roam_states = rso_cfg->roam_trigger_reason; + break; + case ROAM_INVOKE_FAIL_REASON: + roam_states = rso_cfg->roam_invoke_fail_reason; + break; + case ROAM_FAIL_REASON: + roam_states = rso_cfg->roam_fail_reason; + break; + default: + break; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return roam_states; +} + +QDF_STATUS +wlan_cm_update_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t value, enum roam_rt_stats_params stats) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_cm_roam_rt_stats *roam_rt_stats; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + roam_rt_stats = &mlme_obj->cfg.lfr.roam_rt_stats; + + switch (stats) { + case ROAM_RT_STATS_ENABLE: + roam_rt_stats->roam_stats_enabled = value; + break; + case ROAM_RT_STATS_SUSPEND_MODE_ENABLE: + roam_rt_stats->roam_stats_wow_sent = value; + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +uint8_t wlan_cm_get_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + enum roam_rt_stats_params stats) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct wlan_cm_roam_rt_stats *roam_rt_stats; + uint8_t rstats_value = 0; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return QDF_STATUS_E_FAILURE; + } + + roam_rt_stats = &mlme_obj->cfg.lfr.roam_rt_stats; + switch (stats) { + case ROAM_RT_STATS_ENABLE: + rstats_value = roam_rt_stats->roam_stats_enabled; + break; + case ROAM_RT_STATS_SUSPEND_MODE_ENABLE: + rstats_value = roam_rt_stats->roam_stats_wow_sent; + break; + default: + break; + } + + return rstats_value; +} +#endif + +QDF_STATUS wlan_get_chan_by_bssid_from_rnr(struct wlan_objmgr_vdev *vdev, + wlan_cm_id cm_id, + struct qdf_mac_addr *link_addr, + uint8_t *chan, uint8_t *op_class) +{ + struct reduced_neighbor_report *rnr; + int i; + QDF_STATUS status; + + *chan = 0; + rnr = qdf_mem_malloc(sizeof(*rnr)); + if (!rnr) + return QDF_STATUS_E_NOMEM; + + status = wlan_cm_get_rnr(vdev, cm_id, rnr); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(rnr); + return status; + } + + for (i = 0; i < MAX_RNR_BSS; i++) { + if (!rnr->bss_info[i].channel_number) + continue; + if (qdf_is_macaddr_equal(link_addr, &rnr->bss_info[i].bssid)) { + *chan = rnr->bss_info[i].channel_number; + *op_class = rnr->bss_info[i].operating_class; + break; + } + } + qdf_mem_free(rnr); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * mlo_rnr_link_id_cmp() - compare given link id with link id in rnr + * @rnr_bss_info: rnr bss info + * @link_id: link id + * + * Return: true if given link id is the same with link id in rnr + */ +static bool mlo_rnr_link_id_cmp(struct rnr_bss_info *rnr_bss_info, + uint8_t link_id) +{ + if (rnr_bss_info) + return link_id == rnr_bss_info->mld_info.link_id; + + return false; +} + +QDF_STATUS wlan_get_chan_by_link_id_from_rnr(struct wlan_objmgr_vdev *vdev, + wlan_cm_id cm_id, + uint8_t link_id, + uint8_t *chan, uint8_t *op_class) +{ + struct reduced_neighbor_report *rnr; + int i; + QDF_STATUS status; + + *chan = 0; + rnr = qdf_mem_malloc(sizeof(*rnr)); + if (!rnr) + return QDF_STATUS_E_NOMEM; + + status = wlan_cm_get_rnr(vdev, cm_id, rnr); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(rnr); + return status; + } + + for (i = 0; i < MAX_RNR_BSS; i++) { + if (!rnr->bss_info[i].channel_number) + continue; + if (mlo_rnr_link_id_cmp(&rnr->bss_info[i], link_id)) { + *chan = rnr->bss_info[i].channel_number; + *op_class = rnr->bss_info[i].operating_class; + break; + } + } + qdf_mem_free(rnr); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wlan_cm_sta_mlme_vdev_roam_notify(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + status = cm_roam_sync_event_handler_cb(vdev_mlme->vdev, data, data_len); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("Failed to process roam synch event"); +#endif + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void +cm_handle_roam_offload_events(struct roam_offload_roam_event *roam_event) +{ + switch (roam_event->reason) { + case ROAM_REASON_HO_FAILED: { + struct qdf_mac_addr bssid; + + bssid.bytes[0] = roam_event->notif_params >> 0 & 0xFF; + bssid.bytes[1] = roam_event->notif_params >> 8 & 0xFF; + bssid.bytes[2] = roam_event->notif_params >> 16 & 0xFF; + bssid.bytes[3] = roam_event->notif_params >> 24 & 0xFF; + bssid.bytes[4] = roam_event->notif_params1 >> 0 & 0xFF; + bssid.bytes[5] = roam_event->notif_params1 >> 8 & 0xFF; + cm_handle_roam_reason_ho_failed(roam_event->vdev_id, bssid, + roam_event->hw_mode_trans_ind); + } + break; + case ROAM_REASON_INVALID: + cm_invalid_roam_reason_handler(roam_event->vdev_id, + roam_event->notif, + roam_event->notif_params); + break; + default: + break; + } +} + +QDF_STATUS +cm_vdev_disconnect_event_handler(struct vdev_disconnect_event_data *data) +{ + return cm_handle_disconnect_reason(data); +} + +QDF_STATUS +cm_roam_auth_offload_event_handler(struct auth_offload_event *auth_event) +{ + return cm_handle_auth_offload(auth_event); +} + +QDF_STATUS +cm_roam_pmkid_request_handler(struct roam_pmkid_req_event *data) +{ + QDF_STATUS status; + + status = cm_roam_pmkid_req_ind(data->psoc, data->vdev_id, data); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("Pmkid request failed"); + + return status; +} +#else +static void +cm_handle_roam_offload_events(struct roam_offload_roam_event *roam_event) +{ + mlme_debug("Unhandled roam event with reason 0x%x for vdev_id %u", + roam_event->reason, roam_event->vdev_id); +} + +QDF_STATUS +cm_vdev_disconnect_event_handler(struct vdev_disconnect_event_data *data) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_roam_auth_offload_event_handler(struct auth_offload_event *auth_event) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_roam_pmkid_request_handler(struct roam_pmkid_req_event *data) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +void +cm_roam_vendor_handoff_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_vendor_handoff_params *data) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + void *vendor_handoff_context; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, data->vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", data->vdev_id); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + vendor_handoff_context = + mlme_priv->cm_roam.vendor_handoff_param.vendor_handoff_context; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + status = mlme_cm_osif_get_vendor_handoff_params(psoc, + vendor_handoff_context); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_debug("Failed to free vendor handoff request"); + return; + } + + mlme_debug("Reset vendor handoff req in progress context"); + mlme_priv->cm_roam.vendor_handoff_param.req_in_progress = false; + mlme_priv->cm_roam.vendor_handoff_param.vendor_handoff_context = NULL; + + status = cm_roam_update_vendor_handoff_config(psoc, data); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("Failed to update params in rso_config struct"); +} +#endif + +QDF_STATUS +cm_roam_event_handler(struct roam_offload_roam_event *roam_event) +{ + switch (roam_event->reason) { + case ROAM_REASON_BTM: + cm_handle_roam_reason_btm(roam_event->vdev_id); + break; + case ROAM_REASON_BMISS: + cm_handle_roam_reason_bmiss(roam_event->vdev_id, + roam_event->rssi); + break; + case ROAM_REASON_BETTER_AP: + cm_handle_roam_reason_better_ap(roam_event->vdev_id, + roam_event->rssi); + break; + case ROAM_REASON_SUITABLE_AP: + cm_handle_roam_reason_suitable_ap(roam_event->vdev_id, + roam_event->rssi); + break; + case ROAM_REASON_HO_FAILED: + /* + * Continue disconnect only if RSO_STOP timer is running when + * this event is received and stopped as part of this. + * Otherwise it's a normal HO_FAIL event and handle it in + * legacy way. + */ + if (roam_event->rso_timer_stopped) + wlan_cm_rso_stop_continue_disconnect(roam_event->psoc, + roam_event->vdev_id, true); + fallthrough; + case ROAM_REASON_INVALID: + cm_handle_roam_offload_events(roam_event); + break; + case ROAM_REASON_RSO_STATUS: + /* + * roam_event->rso_timer_stopped is set to true in target_if + * only if RSO_STOP timer is running and it's stopped + * successfully + */ + if (roam_event->rso_timer_stopped && + (roam_event->notif == CM_ROAM_NOTIF_SCAN_MODE_SUCCESS || + roam_event->notif == CM_ROAM_NOTIF_SCAN_MODE_FAIL)) + wlan_cm_rso_stop_continue_disconnect(roam_event->psoc, + roam_event->vdev_id, false); + cm_rso_cmd_status_event_handler(roam_event->vdev_id, + roam_event->notif); + break; + case ROAM_REASON_INVOKE_ROAM_FAIL: + cm_handle_roam_reason_invoke_roam_fail(roam_event->vdev_id, + roam_event->notif_params, + roam_event->hw_mode_trans_ind); + break; + case ROAM_REASON_DEAUTH: + cm_handle_roam_reason_deauth(roam_event->vdev_id, + roam_event->notif_params, + roam_event->deauth_disassoc_frame, + roam_event->notif_params1); + break; + default: + mlme_debug("Unhandled roam event with reason 0x%x for vdev_id %u", + roam_event->reason, roam_event->vdev_id); + break; + } + + return QDF_STATUS_SUCCESS; +} + +static void +cm_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct sir_rssi_disallow_lst *entry) +{ + struct reject_ap_info ap_info; + + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + + ap_info.bssid = entry->bssid; + ap_info.reject_ap_type = DRIVER_RSSI_REJECT_TYPE; + ap_info.rssi_reject_params.expected_rssi = entry->expected_rssi; + ap_info.rssi_reject_params.retry_delay = entry->retry_delay; + ap_info.reject_reason = entry->reject_reason; + ap_info.source = entry->source; + ap_info.rssi_reject_params.received_time = entry->received_time; + ap_info.rssi_reject_params.original_timeout = entry->original_timeout; + /* Add this ap info to the rssi reject ap type in denylist manager */ + wlan_dlm_add_bssid_to_reject_list(pdev, &ap_info); +} + +QDF_STATUS +cm_btm_denylist_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_denylist_event *list) +{ + uint32_t i, pdev_id; + struct sir_rssi_disallow_lst entry; + struct roam_denylist_timeout *denylist; + struct wlan_objmgr_pdev *pdev; + + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, list->vdev_id, + WLAN_MLME_CM_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + mlme_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_MLME_CM_ID); + if (!pdev) { + mlme_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + mlme_debug("Received Denylist event from FW num entries %d", + list->num_entries); + denylist = &list->roam_denylist[0]; + for (i = 0; i < list->num_entries; i++) { + qdf_mem_zero(&entry, sizeof(struct sir_rssi_disallow_lst)); + entry.bssid = denylist->bssid; + entry.time_during_rejection = denylist->received_time; + entry.reject_reason = denylist->reject_reason; + entry.source = denylist->source ? denylist->source : + ADDED_BY_TARGET; + entry.original_timeout = denylist->original_timeout; + entry.received_time = denylist->received_time; + /* If timeout = 0 and rssi = 0 ignore the entry */ + if (!denylist->timeout && !denylist->rssi) { + continue; + } else if (denylist->timeout) { + entry.retry_delay = denylist->timeout; + /* set 0dbm as expected rssi */ + entry.expected_rssi = CM_MIN_RSSI; + } else { + /* denylist timeout as 0 */ + entry.retry_delay = denylist->timeout; + entry.expected_rssi = denylist->rssi; + } + + /* Add this bssid to the rssi reject ap type in denylist mgr */ + cm_add_bssid_to_reject_list(pdev, &entry); + denylist++; + } + wlan_objmgr_pdev_release_ref(pdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_roam_scan_ch_list_event_handler(struct cm_roam_scan_ch_resp *data) +{ + return cm_handle_scan_ch_list_data(data); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * cm_roam_stats_get_trigger_detail_str - Return roam trigger string from the + * enum roam_trigger_reason + * @neigh_rpt: Neighbor report/BTM request related data + * @ptr: Pointer to the roam trigger info + * @buf: Destination buffer to write the reason string + * @is_full_scan: Is roam scan partial scan or all channels scan + * @vdev_id: vdev id + * + * Return: None + */ +static void +cm_roam_stats_get_trigger_detail_str(struct wmi_neighbor_report_data *neigh_rpt, + struct wmi_roam_trigger_info *ptr, + char *buf, bool is_full_scan, + uint8_t vdev_id) +{ + uint16_t buf_cons, buf_left = MAX_ROAM_DEBUG_BUF_SIZE; + char *temp = buf; + + buf_cons = qdf_snprint(temp, buf_left, "Reason: \"%s\" ", + mlme_get_roam_trigger_str(ptr->trigger_reason)); + temp += buf_cons; + buf_left -= buf_cons; + + if (ptr->trigger_sub_reason) { + buf_cons = qdf_snprint(temp, buf_left, "Sub-Reason: %s", + mlme_get_sub_reason_str(ptr->trigger_sub_reason)); + temp += buf_cons; + buf_left -= buf_cons; + } + + switch (ptr->trigger_reason) { + case ROAM_TRIGGER_REASON_PER: + case ROAM_TRIGGER_REASON_BMISS: + case ROAM_TRIGGER_REASON_HIGH_RSSI: + case ROAM_TRIGGER_REASON_MAWC: + case ROAM_TRIGGER_REASON_DENSE: + case ROAM_TRIGGER_REASON_BACKGROUND: + case ROAM_TRIGGER_REASON_IDLE: + case ROAM_TRIGGER_REASON_FORCED: + case ROAM_TRIGGER_REASON_UNIT_TEST: + break; + case ROAM_TRIGGER_REASON_BTM: + cm_roam_btm_req_event(neigh_rpt, &ptr->btm_trig_data, ptr, + vdev_id, false); + buf_cons = qdf_snprint( + temp, buf_left, + "Req_mode: %d Disassoc_timer: %d", + ptr->btm_trig_data.btm_request_mode, + ptr->btm_trig_data.disassoc_timer / 1000); + temp += buf_cons; + buf_left -= buf_cons; + + buf_cons = qdf_snprint(temp, buf_left, + "validity_interval: %d candidate_list_cnt: %d resp_status: %d, bss_termination_timeout: %d, mbo_assoc_retry_timeout: %d", + ptr->btm_trig_data.validity_interval / 1000, + ptr->btm_trig_data.candidate_list_count, + ptr->btm_trig_data.btm_resp_status, + ptr->btm_trig_data.btm_bss_termination_timeout, + ptr->btm_trig_data.btm_mbo_assoc_retry_timeout); + buf_left -= buf_cons; + temp += buf_cons; + break; + case ROAM_TRIGGER_REASON_BSS_LOAD: + buf_cons = qdf_snprint(temp, buf_left, "CU: %d %% ", + ptr->cu_trig_data.cu_load); + temp += buf_cons; + buf_left -= buf_cons; + break; + case ROAM_TRIGGER_REASON_DEAUTH: + buf_cons = qdf_snprint(temp, buf_left, "Type: %d Reason: %d ", + ptr->deauth_trig_data.type, + ptr->deauth_trig_data.reason); + temp += buf_cons; + buf_left -= buf_cons; + break; + case ROAM_TRIGGER_REASON_LOW_RSSI: + case ROAM_TRIGGER_REASON_PERIODIC: + /* + * Use ptr->current_rssi get the RSSI of current AP after + * roam scan is triggered. This avoids discrepancy with the + * next rssi threshold value printed in roam scan details. + * ptr->rssi_trig_data.threshold gives the rssi threshold + * for the Low Rssi/Periodic scan trigger. + */ + if (ptr->common_roam) + buf_cons = qdf_snprint(temp, buf_left, + "Cur_Rssi threshold:%d Current AP RSSI: %d", + ptr->low_rssi_trig_data.roam_rssi_threshold, + ptr->low_rssi_trig_data.current_rssi); + else + buf_cons = qdf_snprint(temp, buf_left, + "Cur_Rssi threshold:%d Current AP RSSI: %d", + ptr->rssi_trig_data.threshold, + ptr->current_rssi); + temp += buf_cons; + buf_left -= buf_cons; + break; + case ROAM_TRIGGER_REASON_WTC_BTM: + cm_roam_btm_resp_event(ptr, NULL, vdev_id, true); + + if (ptr->wtc_btm_trig_data.wtc_candi_rssi_ext_present) { + buf_cons = qdf_snprint(temp, buf_left, + "Roaming Mode: %d, Trigger Reason: %d, Sub code:%d, wtc mode:%d, wtc scan mode:%d, wtc rssi th:%d, wtc candi rssi th_2g:%d, wtc_candi_rssi_th_5g:%d, wtc_candi_rssi_th_6g:%d", + ptr->wtc_btm_trig_data.roaming_mode, + ptr->wtc_btm_trig_data.vsie_trigger_reason, + ptr->wtc_btm_trig_data.sub_code, + ptr->wtc_btm_trig_data.wtc_mode, + ptr->wtc_btm_trig_data.wtc_scan_mode, + ptr->wtc_btm_trig_data.wtc_rssi_th, + ptr->wtc_btm_trig_data.wtc_candi_rssi_th, + ptr->wtc_btm_trig_data.wtc_candi_rssi_th_5g, + ptr->wtc_btm_trig_data.wtc_candi_rssi_th_6g); + } else { + buf_cons = qdf_snprint(temp, buf_left, + "Roaming Mode: %d, Trigger Reason: %d, Sub code:%d, wtc mode:%d, wtc scan mode:%d, wtc rssi th:%d, wtc candi rssi th:%d", + ptr->wtc_btm_trig_data.roaming_mode, + ptr->wtc_btm_trig_data.vsie_trigger_reason, + ptr->wtc_btm_trig_data.sub_code, + ptr->wtc_btm_trig_data.wtc_mode, + ptr->wtc_btm_trig_data.wtc_scan_mode, + ptr->wtc_btm_trig_data.wtc_rssi_th, + ptr->wtc_btm_trig_data.wtc_candi_rssi_th); + } + + temp += buf_cons; + buf_left -= buf_cons; + break; + default: + break; + } +} + +/** + * cm_roam_stats_print_trigger_info - Roam trigger related details + * @psoc: Pointer to PSOC object + * @neigh_rpt: Neighbor report/BTM request related data + * @data: Pointer to the roam trigger data + * @scan_data: Roam scan data pointer + * @vdev_id: Vdev ID + * @is_full_scan: Was a full scan performed + * + * Prints the vdev, roam trigger reason, time of the day at which roaming + * was triggered. + * + * Return: None + */ +static void +cm_roam_stats_print_trigger_info(struct wlan_objmgr_psoc *psoc, + struct wmi_neighbor_report_data *neigh_rpt, + struct wmi_roam_trigger_info *data, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id, bool is_full_scan) +{ + char *buf; + char time[TIME_STRING_LEN]; + QDF_STATUS status; + + buf = qdf_mem_malloc(MAX_ROAM_DEBUG_BUF_SIZE); + if (!buf) + return; + + cm_roam_stats_get_trigger_detail_str(neigh_rpt, data, buf, + is_full_scan, vdev_id); + mlme_get_converted_timestamp(data->timestamp, time); + + /* Update roam trigger info to userspace */ + cm_roam_trigger_info_event(data, scan_data, vdev_id, is_full_scan); + + mlme_nofl_info("%s [ROAM_TRIGGER]: VDEV[%d] %s", + time, vdev_id, buf); + qdf_mem_free(buf); + + status = wlan_cm_update_roam_states(psoc, vdev_id, data->trigger_reason, + ROAM_TRIGGER_REASON); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("failed to update rt stats trigger reason"); +} + +/** + * cm_roam_stats_print_btm_rsp_info - BTM RSP related details + * @trigger_info: Roam scan trigger reason + * @data: Pointer to the btm rsp data + * @vdev_id: vdev id + * @is_wtc: is WTC? + * + * Prints the vdev, btm status, target_bssid and vsie reason + * + * Return: None + */ +static void +cm_roam_stats_print_btm_rsp_info(struct wmi_roam_trigger_info *trigger_info, + struct roam_btm_response_data *data, + uint8_t vdev_id, bool is_wtc) +{ + char time[TIME_STRING_LEN]; + + mlme_get_converted_timestamp(data->timestamp, time); + mlme_nofl_info("%s [BTM RSP]:VDEV[%d], Status:%d, VSIE reason:%d, BSSID: " + QDF_MAC_ADDR_FMT, time, vdev_id, data->btm_status, + data->vsie_reason, + QDF_MAC_ADDR_REF(data->target_bssid.bytes)); + cm_roam_btm_resp_event(trigger_info, data, vdev_id, is_wtc); +} + +/** + * cm_roam_stats_print_roam_initial_info - Roaming related initial details + * @data: Pointer to the btm rsp data + * @vdev_id: vdev id + * + * Prints the vdev, roam_full_scan_count, channel and rssi + * utilization threshold and timer + * + * Return: None + */ +static void +cm_roam_stats_print_roam_initial_info(struct roam_initial_data *data, + uint8_t vdev_id) +{ + mlme_nofl_info("[ROAM INIT INFO]: VDEV[%d], roam_full_scan_count: %d, rssi_th: %d, cu_th: %d, fw_cancel_timer_bitmap: %d", + vdev_id, data->roam_full_scan_count, data->rssi_th, + data->cu_th, data->fw_cancel_timer_bitmap); +} + +/** + * cm_roam_update_next_rssi_threshold() - Update neighbor_lookup_threshold + * @psoc: Pointer to psoc object + * @next_rssi_threshold: value of next rssi threshold coming from FW + * @vdev_id: vdev id + * + * Host updates the configured RSSI threshold from INI + * "gNeighborLookupThreshold RoamRSSI_Trigger" over the + * GETROAMTRIGGER command. But this RSSI threshold is reduced by + * firmware in steps for reasons like candidate not found during + * roam scan. So, the expectation is to print the next RSSI + * threshold at which the roam scan will be triggered. This value + * is received from firmware via the WMI_ROAM_SCAN_STATS_EVENTID. + * + * Return: None + */ +static void +cm_roam_update_next_rssi_threshold(struct wlan_objmgr_psoc *psoc, + uint32_t next_rssi_threshold, + uint8_t vdev_id) +{ + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = next_rssi_threshold; + wlan_cm_roam_cfg_set_value(psoc, vdev_id, NEXT_RSSI_THRESHOLD, + &src_config); +} + +/** + * cm_roam_stats_process_roam_msg_info - Roaming related message details + * @psoc: Pointer to psoc object + * @data: Pointer to the btm rsp data + * @vdev_id: vdev id + * + * Prints the vdev, msg_id, msg_param1, msg_param2 and timer + * + * Return: None + */ +static void cm_roam_stats_process_roam_msg_info(struct wlan_objmgr_psoc *psoc, + struct roam_msg_info *data, + uint8_t vdev_id) +{ + char time[TIME_STRING_LEN]; + static const char msg_id1_str[] = "Roam RSSI TH Reset"; + + if (data->msg_id == WMI_ROAM_MSG_RSSI_RECOVERED || + data->msg_id == WMI_ROAM_MSG_CONNECTED_IN_POOR_RSSI) { + mlme_get_converted_timestamp(data->timestamp, time); + mlme_nofl_info("%s [ROAM MSG INFO]: VDEV[%d] %s, Current rssi: %d dbm, next_rssi_threshold: %d dbm", + time, vdev_id, msg_id1_str, data->msg_param1, + data->msg_param2); + cm_roam_update_next_rssi_threshold(psoc, data->msg_param2, + vdev_id); + } +} + +/** + * cm_stats_log_roam_scan_candidates - Print roam scan candidate AP info + * @ap: Pointer to the candidate AP list + * @num_entries: Number of candidate APs + * + * Print the RSSI, CU load, Cu score, RSSI score, total score, BSSID + * and time stamp at which the candidate was found details. + * + * Return: None + */ +static void +cm_stats_log_roam_scan_candidates(struct wmi_roam_candidate_info *ap, + uint8_t num_entries) +{ + uint16_t i; + char time[TIME_STRING_LEN], time2[TIME_STRING_LEN]; + + + mlme_nofl_info("%62s%62s", LINE_STR, LINE_STR); + mlme_nofl_info("%13s %16s %8s %4s %4s %5s/%3s %3s/%3s %7s %7s %6s %12s %20s", + "AP BSSID", "TSTAMP", "CH", "TY", "ETP", "RSSI", + "SCR", "CU%", "SCR", "TOT_SCR", "BL_RSN", "BL_SRC", + "BL_TSTAMP", "BL_TIMEOUT(ms)"); + mlme_nofl_info("%62s%62s", LINE_STR, LINE_STR); + + if (num_entries > MAX_ROAM_CANDIDATE_AP) + num_entries = MAX_ROAM_CANDIDATE_AP; + + for (i = 0; i < num_entries; i++) { + mlme_get_converted_timestamp(ap->timestamp, time); + mlme_get_converted_timestamp(ap->dl_timestamp, time2); + mlme_nofl_info(QDF_MAC_ADDR_FMT " %17s %4d %-4s %4d %3d/%-4d %2d/%-4d %5d %7d %7d %17s %9d", + QDF_MAC_ADDR_REF(ap->bssid.bytes), time, + ap->freq, + ((ap->type == 0) ? "C_AP" : + ((ap->type == 2) ? "R_AP" : "P_AP")), + ap->etp, ap->rssi, ap->rssi_score, ap->cu_load, + ap->cu_score, ap->total_score, ap->dl_reason, + ap->dl_source, time2, ap->dl_original_timeout); + /* Update roam candidates info to userspace */ + cm_roam_candidate_info_event(ap, i); + ap++; + } +} + +/** + * cm_get_roam_scan_type_str() - Get the string for roam scan type + * @roam_scan_type: roam scan type coming from fw via + * wmi_roam_scan_info tlv + * + * Return: Meaningful string for roam scan type + */ +static char *cm_get_roam_scan_type_str(uint32_t roam_scan_type) +{ + switch (roam_scan_type) { + case ROAM_STATS_SCAN_TYPE_PARTIAL: + return "PARTIAL"; + case ROAM_STATS_SCAN_TYPE_FULL: + return "FULL"; + case ROAM_STATS_SCAN_TYPE_NO_SCAN: + return "NO SCAN"; + case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ: + return "Higher Band: 5 GHz + 6 GHz"; + case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ: + return "Higher Band : 6 GHz"; + default: + return "UNKNOWN"; + } +} + +/** + * cm_roam_stats_print_scan_info - Print the roam scan details and candidate AP + * details + * @psoc: psoc common object + * @scan: Pointer to the received tlv after sanitization + * @vdev_id: Vdev ID + * @trigger: Roam scan trigger reason + * @timestamp: Host timestamp in millisecs + * + * Prinst the roam scan details with time of the day when the scan was + * triggered and roam candidate AP with score details + * + * Return: None + */ +static void +cm_roam_stats_print_scan_info(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_scan_data *scan, uint8_t vdev_id, + uint32_t trigger, uint32_t timestamp) +{ + uint16_t num_ch = scan->num_chan; + uint16_t buf_cons = 0, buf_left = ROAM_CHANNEL_BUF_SIZE; + uint8_t i; + char *buf, *buf1, *tmp; + char time[TIME_STRING_LEN]; + + /* Update roam scan info to userspace */ + cm_roam_scan_info_event(psoc, scan, vdev_id); + + buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE); + if (!buf) + return; + + tmp = buf; + /* For partial scans, print the channel info */ + if (scan->type == ROAM_STATS_SCAN_TYPE_PARTIAL) { + buf_cons = qdf_snprint(tmp, buf_left, "{"); + buf_left -= buf_cons; + tmp += buf_cons; + + for (i = 0; i < num_ch; i++) { + buf_cons = qdf_snprint(tmp, buf_left, "%d ", + scan->chan_freq[i]); + buf_left -= buf_cons; + tmp += buf_cons; + } + buf_cons = qdf_snprint(tmp, buf_left, "}"); + buf_left -= buf_cons; + tmp += buf_cons; + } + + buf1 = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE); + if (!buf1) { + qdf_mem_free(buf); + return; + } + + if (trigger == ROAM_TRIGGER_REASON_LOW_RSSI || + trigger == ROAM_TRIGGER_REASON_PERIODIC) + qdf_snprint(buf1, ROAM_FAILURE_BUF_SIZE, + "next_rssi_threshold: %d dBm", + scan->next_rssi_threshold); + + mlme_get_converted_timestamp(timestamp, time); + mlme_nofl_info("%s [ROAM_SCAN]: VDEV[%d] Scan_type: %s %s %s", + time, vdev_id, cm_get_roam_scan_type_str(scan->type), + buf1, buf); + cm_stats_log_roam_scan_candidates(scan->ap, scan->num_ap); + + qdf_mem_free(buf); + qdf_mem_free(buf1); +} + +/** + * cm_roam_stats_print_roam_result() - Print roam result related info + * @psoc: Pointer to psoc object + * @trigger: roam trigger information + * @res: Roam result structure pointer + * @scan_data: scan data + * @vdev_id: vdev id + * + * Print roam result and failure reason if roaming failed. + * + * Return: None + */ +static void +cm_roam_stats_print_roam_result(struct wlan_objmgr_psoc *psoc, + struct wmi_roam_trigger_info *trigger, + struct wmi_roam_result *res, + struct wmi_roam_scan_data *scan_data, + uint8_t vdev_id) +{ + char *buf; + char time[TIME_STRING_LEN]; + QDF_STATUS status; + + /* Update roam result info to userspace */ + cm_roam_result_info_event(psoc, trigger, res, scan_data, vdev_id); + + buf = qdf_mem_malloc(ROAM_FAILURE_BUF_SIZE); + if (!buf) + return; + + if (res->status == 1) + qdf_snprint(buf, ROAM_FAILURE_BUF_SIZE, "Reason: %s", + mlme_get_roam_fail_reason_str(res->fail_reason)); + + mlme_get_converted_timestamp(res->timestamp, time); + + if (res->fail_reason == ROAM_FAIL_REASON_CURR_AP_STILL_OK) + mlme_nofl_info("%s [ROAM_RESULT]: VDEV[%d] %s", + time, vdev_id, buf); + else + mlme_nofl_info("%s [ROAM_RESULT]: VDEV[%d] %s %s", + time, vdev_id, + mlme_get_roam_status_str(res->status), buf); + qdf_mem_free(buf); + + status = wlan_cm_update_roam_states(psoc, vdev_id, res->fail_reason, + ROAM_FAIL_REASON); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("failed to update rt stats roam fail reason"); +} + +#define WLAN_ROAM_11KV_REQ_TYPE_BTM 1 +#define WLAN_ROAM_11KV_REQ_TYPE_NEIGH_RPT 2 + +/** + * cm_roam_stats_print_11kv_info - Print neighbor report/BTM related data + * @psoc: Pointer to psoc object + * @neigh_rpt: Pointer to the extracted TLV structure + * @vdev_id: Vdev ID + * + * Print BTM/neighbor report info that is sent by firmware after + * connection/roaming to an AP. + * + * Return: none + */ +static void +cm_roam_stats_print_11kv_info(struct wlan_objmgr_psoc *psoc, + struct wmi_neighbor_report_data *neigh_rpt, + uint8_t vdev_id) +{ + char time[TIME_STRING_LEN], time1[TIME_STRING_LEN]; + char *buf, *tmp; + uint8_t type = neigh_rpt->req_type, i; + uint16_t buf_left = ROAM_CHANNEL_BUF_SIZE, buf_cons; + uint8_t num_ch = neigh_rpt->num_freq; + struct wlan_objmgr_vdev *vdev; + + if (!type) + return; + + buf = qdf_mem_malloc(ROAM_CHANNEL_BUF_SIZE); + if (!buf) + return; + + tmp = buf; + if (num_ch) { + buf_cons = qdf_snprint(tmp, buf_left, "{ "); + buf_left -= buf_cons; + tmp += buf_cons; + + for (i = 0; i < num_ch; i++) { + buf_cons = qdf_snprint(tmp, buf_left, "%d ", + neigh_rpt->freq[i]); + buf_left -= buf_cons; + tmp += buf_cons; + } + + buf_cons = qdf_snprint(tmp, buf_left, "}"); + buf_left -= buf_cons; + tmp += buf_cons; + } + + mlme_get_converted_timestamp(neigh_rpt->req_time, time); + mlme_nofl_info("%s [%s] VDEV[%d]", time, + (type == WLAN_ROAM_11KV_REQ_TYPE_BTM) ? + "BTM_QUERY" : "NEIGH_RPT_REQ", vdev_id); + + if (type == WLAN_ROAM_11KV_REQ_TYPE_BTM) + cm_roam_btm_query_event(neigh_rpt, vdev_id); + else if (type == WLAN_ROAM_11KV_REQ_TYPE_NEIGH_RPT) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_err("vdev pointer not found"); + goto out; + } + + cm_roam_neigh_rpt_req_event(neigh_rpt, vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + } + + if (neigh_rpt->resp_time) { + mlme_get_converted_timestamp(neigh_rpt->resp_time, time1); + mlme_nofl_info("%s [%s] VDEV[%d] %s", time1, + (type == WLAN_ROAM_11KV_REQ_TYPE_BTM) ? + "BTM_REQ" : "NEIGH_RPT_RSP", + vdev_id, + (num_ch > 0) ? buf : "NO Ch update"); + + if (type == WLAN_ROAM_11KV_REQ_TYPE_NEIGH_RPT) + cm_roam_neigh_rpt_resp_event(neigh_rpt, vdev_id); + + } else { + mlme_nofl_info("%s No response received from AP", + (type == WLAN_ROAM_11KV_REQ_TYPE_BTM) ? + "BTM" : "NEIGH_RPT"); + } +out: + qdf_mem_free(buf); +} + +static char * +cm_get_frame_subtype_str(enum mgmt_subtype frame_subtype) +{ + switch (frame_subtype) { + case MGMT_SUBTYPE_ASSOC_REQ: + return "ASSOC"; + case MGMT_SUBTYPE_ASSOC_RESP: + return "ASSOC"; + case MGMT_SUBTYPE_REASSOC_REQ: + return "REASSOC"; + case MGMT_SUBTYPE_REASSOC_RESP: + return "REASSOC"; + case MGMT_SUBTYPE_DISASSOC: + return "DISASSOC"; + case MGMT_SUBTYPE_AUTH: + return "AUTH"; + case MGMT_SUBTYPE_DEAUTH: + return "DEAUTH"; + default: + break; + } + + return "Invalid frm"; +} + +#define WLAN_SAE_AUTH_ALGO 3 +static void +cm_roam_print_frame_info(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct roam_frame_stats *frame_data, + struct wmi_roam_scan_data *scan_data, + struct wmi_roam_result *result) +{ + struct roam_frame_info *frame_info; + char time[TIME_STRING_LEN]; + uint8_t i, vdev_id, cached_vdev_id; + + if (!frame_data->num_frame) + return; + + vdev_id = wlan_vdev_get_id(vdev); + + for (i = 0; i < frame_data->num_frame; i++) { + cached_vdev_id = vdev_id; + frame_info = &frame_data->frame_info[i]; + /* + * For SAE auth frame, since host sends the authentication + * frames, its cached in the TX/RX path and the cached + * frames are printed from here. + */ + if (frame_info->auth_algo == WLAN_SAE_AUTH_ALGO && + wlan_is_sae_auth_log_present_for_bssid(psoc, + &frame_info->bssid, + &cached_vdev_id)) { + wlan_print_cached_sae_auth_logs(psoc, + &frame_info->bssid, + cached_vdev_id); + continue; + } + + qdf_mem_zero(time, TIME_STRING_LEN); + mlme_get_converted_timestamp(frame_info->timestamp, time); + + /* Log the auth & reassoc frames here to driver log */ + if (frame_info->type != ROAM_FRAME_INFO_FRAME_TYPE_EXT) + mlme_nofl_info("%s [%s%s] VDEV[%d] bssid: " QDF_MAC_ADDR_FMT " status:%d seq_num:%d", + time, + cm_get_frame_subtype_str(frame_info->subtype), + frame_info->subtype == MGMT_SUBTYPE_AUTH ? + (frame_info->is_rsp ? " RX" : " TX") : "", + vdev_id, + QDF_MAC_ADDR_REF(frame_info->bssid.bytes), + frame_info->status_code, + frame_info->seq_num); + + cm_roam_mgmt_frame_event(vdev, frame_info, scan_data, result); + } +} + +void cm_report_roam_rt_stats(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum roam_rt_stats_type events, + struct roam_stats_event *roam_info, + uint32_t value, uint8_t idx, uint32_t reason) +{ + struct roam_stats_event *roam_event = NULL; + + if (!wlan_cm_get_roam_rt_stats(psoc, ROAM_RT_STATS_ENABLE)) { + mlme_debug("Roam events stats is disabled"); + return; + } + + switch (events) { + case ROAM_RT_STATS_TYPE_SCAN_STATE: + roam_event = qdf_mem_malloc(sizeof(*roam_event)); + if (!roam_event) + return; + + if (value == WMI_ROAM_NOTIF_SCAN_START) { + roam_event->roam_event_param.roam_scan_state = + QCA_WLAN_VENDOR_ROAM_SCAN_STATE_START; + if (reason) { + roam_event->trigger[idx].present = true; + roam_event->trigger[idx].trigger_reason = + reason; + } + } else if (value == WMI_ROAM_NOTIF_SCAN_END) { + roam_event->roam_event_param.roam_scan_state = + QCA_WLAN_VENDOR_ROAM_SCAN_STATE_END; + } + + mlme_debug("Invoke HDD roam events callback for roam " + "scan notif"); + roam_event->vdev_id = vdev_id; + mlme_cm_osif_roam_rt_stats(roam_event, idx); + qdf_mem_free(roam_event); + break; + case ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON: + roam_event = qdf_mem_malloc(sizeof(*roam_event)); + if (!roam_event) + return; + + roam_event->roam_event_param.roam_invoke_fail_reason = value; + + mlme_debug("Invoke HDD roam events callback for roam " + "invoke fail"); + roam_event->vdev_id = vdev_id; + mlme_cm_osif_roam_rt_stats(roam_event, idx); + qdf_mem_free(roam_event); + break; + case ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO: + if (roam_info->scan[idx].present || + roam_info->trigger[idx].present || + (roam_info->result[idx].present && + roam_info->result[idx].fail_reason)) { + mlme_debug("Invoke HDD roam events callback for roam " + "stats event"); + roam_info->vdev_id = vdev_id; + mlme_cm_osif_roam_rt_stats(roam_info, idx); + } + break; + default: + break; + } +} + +/** + * cm_roam_handle_btm_stats() - Handle BTM related logging roam stats. + * @psoc: psoc pointer + * @stats_info: Pointer to the roam stats + * @i: TLV indev for BTM roam trigger + * @rem_tlv_len: Remaining TLV length + * + * Return: None + */ +static void +cm_roam_handle_btm_stats(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info, uint8_t i, + uint8_t *rem_tlv_len) +{ + bool log_btm_frames_only = false; + struct wlan_objmgr_vdev *vdev; + + if (stats_info->data_11kv[i].present) + cm_roam_stats_print_11kv_info(psoc, &stats_info->data_11kv[i], + stats_info->vdev_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + stats_info->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev: %d vdev not found", stats_info->vdev_id); + return; + } + + /* + * If roam trigger is BTM and roam scan type is no scan then + * the roam stats event is for BTM frames logging. + * So log the BTM frames alone and return. + */ + if (stats_info->scan[i].present && + stats_info->scan[i].type == ROAM_STATS_SCAN_TYPE_NO_SCAN) { + cm_roam_btm_req_event(&stats_info->data_11kv[i], + &stats_info->trigger[i].btm_trig_data, + &stats_info->trigger[i], + stats_info->vdev_id, false); + log_btm_frames_only = true; + goto log_btm_frames_only; + } + + if (stats_info->trigger[i].present) { + bool is_full_scan = stats_info->scan[i].present && + stats_info->scan[i].type; + + /* BTM request diag log event will be sent from inside below */ + cm_roam_stats_print_trigger_info(psoc, + &stats_info->data_11kv[i], + &stats_info->trigger[i], + &stats_info->scan[i], + stats_info->vdev_id, + is_full_scan); + + if (stats_info->scan[i].present) + cm_roam_stats_print_scan_info( + psoc, &stats_info->scan[i], + stats_info->vdev_id, + stats_info->trigger[i].trigger_reason, + stats_info->trigger[i].timestamp); + } + + if (stats_info->result[i].present) + cm_roam_stats_print_roam_result(psoc, + &stats_info->trigger[i], + &stats_info->result[i], + &stats_info->scan[i], + stats_info->vdev_id); + + if (stats_info->frame_stats[i].num_frame) + cm_roam_print_frame_info(psoc, vdev, + &stats_info->frame_stats[i], + &stats_info->scan[i], + &stats_info->result[i]); + +log_btm_frames_only: + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + /* + * Print BTM resp TLV info (wmi_roam_btm_response_info) only + * when trigger reason is BTM or WTC_BTM. As for other roam + * triggers this TLV contains zeros, so host should not print. + */ + if (stats_info->btm_rsp[i].present && stats_info->trigger[i].present && + (stats_info->trigger[i].trigger_reason == ROAM_TRIGGER_REASON_BTM || + stats_info->trigger[i].trigger_reason == + ROAM_TRIGGER_REASON_WTC_BTM)) + cm_roam_stats_print_btm_rsp_info(&stats_info->trigger[i], + &stats_info->btm_rsp[i], + stats_info->vdev_id, false); + + if (log_btm_frames_only) + return; + + if (stats_info->roam_init_info[i].present) + cm_roam_stats_print_roam_initial_info( + &stats_info->roam_init_info[i], + stats_info->vdev_id); + + if (stats_info->roam_msg_info && stats_info->roam_msg_info[i].present && + i < stats_info->num_roam_msg_info) { + *rem_tlv_len = *rem_tlv_len + 1; + cm_roam_stats_process_roam_msg_info(psoc, + &stats_info->roam_msg_info[i], + stats_info->vdev_id); + } + + cm_report_roam_rt_stats(psoc, stats_info->vdev_id, + ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO, + stats_info, 0, i, 0); +} + +#ifdef WLAN_FEATURE_ROAM_INFO_STATS +void mlme_cm_free_roam_stats_info(mlme_vdev_ext_t *ext_hdl) +{ + uint32_t roam_cache_num; + + roam_cache_num = ext_hdl->roam_cache_num; + + if (roam_cache_num == 0) { + mlme_debug("enhanced roam disable, no need free memory"); + return; + } + + qdf_mutex_destroy(&ext_hdl->roam_rd_wr_lock); + qdf_mem_free(ext_hdl->roam_info); + ext_hdl->roam_info = NULL; +} + +void +mlme_cm_alloc_roam_stats_info(struct vdev_mlme_obj *vdev_mlme) +{ + uint32_t cache_num; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + if (!vdev_mlme->ext_vdev_ptr) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev_mlme->vdev); + if (!psoc) { + mlme_err("Invalid PSOC"); + return; + } + status = wlan_mlme_get_roam_info_stats_num(psoc, &cache_num); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("failed to get groam_info_stats_num"); + return; + } + + if (cache_num == 0) { + mlme_err("groam_info_stats_num = 0, not support enhanced roam"); + return; + } + + if (vdev_mlme->ext_vdev_ptr->roam_info) { + mlme_debug("mlme_priv->enhance_roam_info already malloced"); + return; + } + + vdev_mlme->ext_vdev_ptr->roam_info = + qdf_mem_malloc(cache_num * sizeof(struct enhance_roam_info)); + if (!vdev_mlme->ext_vdev_ptr->roam_info) + return; + + vdev_mlme->ext_vdev_ptr->roam_cache_num = cache_num; + vdev_mlme->ext_vdev_ptr->roam_write_index = 0; + qdf_mutex_create(&vdev_mlme->ext_vdev_ptr->roam_rd_wr_lock); +} + +#ifdef WLAN_CHIPSET_STATS +static void +cm_cp_stats_cstats_log_deauth_evt(struct wlan_objmgr_vdev *vdev, + enum cstats_dir dir, uint16_t reason_code) +{ + struct cstats_deauth_mgmt_frm stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_DEAUTH_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_deauth_mgmt_frm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.reason = reason_code; + stat.direction = dir; + + wlan_cstats_host_stats(sizeof(struct cstats_deauth_mgmt_frm), &stat); +} + +static void +cm_cp_stats_cstats_log_disassoc_evt(struct wlan_objmgr_vdev *vdev, + enum cstats_dir dir, uint16_t reason_code) +{ + struct cstats_disassoc_mgmt_frm stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_DISASSOC_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_disassoc_mgmt_frm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.reason = reason_code; + stat.direction = dir; + + wlan_cstats_host_stats(sizeof(struct cstats_disassoc_mgmt_frm), &stat); +} +#else +static void +cm_cp_stats_cstats_log_deauth_evt(struct wlan_objmgr_vdev *vdev, + enum cstats_dir dir, uint16_t reason_code) +{ +} + +static void +cm_cp_stats_cstats_log_disassoc_evt(struct wlan_objmgr_vdev *vdev, + enum cstats_dir dir, uint16_t reason_code) +{ +} +#endif /* WLAN_CHIPSET_STATS */ + +/** + * wlan_cm_update_roam_trigger_info() - API to update roam trigger info + * @vdev: Pointer to vdev object + * @data: Data from target_if wmi event + * + * Get roam trigger info from target_if wmi event and save in vdev mlme ring + * buffer, it is required that the mlme_priv->roam_rd_wr_lock be held before + * this API is called + * + * Return: void + */ +static void +wlan_cm_update_roam_trigger_info(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_trigger_info *data) +{ + uint32_t trigger_reason; + uint32_t index; + struct enhance_roam_info *info; + struct mlme_legacy_priv *mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + + index = mlme_priv->roam_write_index; + info = &mlme_priv->roam_info[index]; + + info->trigger.timestamp = data->timestamp; + info->trigger.trigger_reason = data->trigger_reason; + trigger_reason = data->trigger_reason; + + mlme_debug("roam trigger info: timestamp:%llu, reason:%u,index:%u", + info->trigger.timestamp, + info->trigger.trigger_reason, index); + + switch (trigger_reason) { + case ROAM_TRIGGER_REASON_PER: + info->trigger.condition.roam_per.tx_rate_thresh_percent = + data->per_trig_data.tx_rate_thresh_percent; + info->trigger.condition.roam_per.tx_rate_thresh_percent = + data->per_trig_data.tx_rate_thresh_percent; + mlme_debug("roam per: rx:%u, tx:%u", + data->per_trig_data.rx_rate_thresh_percent, + data->per_trig_data.tx_rate_thresh_percent); + break; + case ROAM_TRIGGER_REASON_BMISS: + info->trigger.condition.roam_bmiss.final_bmiss_cnt = + data->bmiss_trig_data.final_bmiss_cnt; + info->trigger.condition.roam_bmiss.consecutive_bmiss_cnt = + data->bmiss_trig_data.consecutive_bmiss_cnt; + info->trigger.condition.roam_bmiss.qos_null_success = + data->bmiss_trig_data.qos_null_success; + mlme_debug("roam bmiss: final:%u, consecutive:%u, qos:%u", + data->bmiss_trig_data.final_bmiss_cnt, + data->bmiss_trig_data.consecutive_bmiss_cnt, + data->bmiss_trig_data.qos_null_success); + break; + case ROAM_TRIGGER_REASON_LOW_RSSI: + info->trigger.condition.roam_poor_rssi.current_rssi = + data->low_rssi_trig_data.current_rssi; + info->trigger.condition.roam_poor_rssi.roam_rssi_threshold = + data->low_rssi_trig_data.roam_rssi_threshold; + info->trigger.condition.roam_poor_rssi.rx_linkspeed_status = + data->low_rssi_trig_data.rx_linkspeed_status; + mlme_debug("roam low rssi: rssi:%d, rssi_th:%d, rx_linkspeed:%u", + data->low_rssi_trig_data.current_rssi, + data->low_rssi_trig_data.roam_rssi_threshold, + data->low_rssi_trig_data.rx_linkspeed_status); + break; + case ROAM_TRIGGER_REASON_HIGH_RSSI: + info->trigger.condition.roam_better_rssi.current_rssi = + data->hi_rssi_trig_data.current_rssi; + info->trigger.condition.roam_better_rssi.hi_rssi_threshold = + data->hi_rssi_trig_data.hirssi_threshold; + mlme_debug("roam better rssi: cu_rssi:%d, hi_rssi_th:%d", + data->hi_rssi_trig_data.current_rssi, + data->hi_rssi_trig_data.hirssi_threshold); + break; + case ROAM_TRIGGER_REASON_PERIODIC: + info->trigger.condition.roam_periodic.periodic_timer_ms = + data->periodic_trig_data.periodic_timer_ms; + mlme_debug("roam periodic: periodic_timer:%u", + data->periodic_trig_data.periodic_timer_ms); + break; + + case ROAM_TRIGGER_REASON_DENSE: + info->trigger.condition.roam_congestion.rx_tput = + data->congestion_trig_data.rx_tput; + info->trigger.condition.roam_congestion.tx_tput = + data->congestion_trig_data.tx_tput; + info->trigger.condition.roam_congestion.roamable_count = + data->congestion_trig_data.roamable_count; + mlme_debug("roam dense: rx_tput:%u, tx_tput:%u, roamable %u", + data->congestion_trig_data.rx_tput, + data->congestion_trig_data.tx_tput, + data->congestion_trig_data.roamable_count); + break; + case ROAM_TRIGGER_REASON_BACKGROUND: + info->trigger.condition.roam_background.current_rssi = + data->background_trig_data.current_rssi; + info->trigger.condition.roam_background.data_rssi = + data->background_trig_data.data_rssi; + info->trigger.condition.roam_background.data_rssi_threshold = + data->background_trig_data.data_rssi_threshold; + mlme_debug("roam background: rssi:%d, datarssi:%d, rssi_th %d", + data->background_trig_data.current_rssi, + data->background_trig_data.data_rssi, + data->background_trig_data.data_rssi_threshold); + break; + case ROAM_TRIGGER_REASON_FORCED: + info->trigger.condition.roam_user_trigger.invoke_reason = + data->user_trig_data.invoke_reason; + mlme_debug("roam force: invoke_reason:%u", + data->user_trig_data.invoke_reason); + break; + case ROAM_TRIGGER_REASON_BTM: + info->trigger.condition.roam_btm.btm_request_mode = + data->btm_trig_data.btm_request_mode; + info->trigger.condition.roam_btm.disassoc_imminent_timer = + data->btm_trig_data.disassoc_timer; + info->trigger.condition.roam_btm.validity_internal = + data->btm_trig_data.validity_interval; + info->trigger.condition.roam_btm.candidate_list_count = + data->btm_trig_data.candidate_list_count; + info->trigger.condition.roam_btm.btm_response_status_code = + data->btm_trig_data.btm_resp_status; + info->trigger.condition.roam_btm.btm_bss_termination_timeout = + data->btm_trig_data.btm_bss_termination_timeout; + info->trigger.condition.roam_btm.btm_mbo_assoc_retry_timeout = + data->btm_trig_data.btm_mbo_assoc_retry_timeout; + info->trigger.condition.roam_btm.btm_req_dialog_token = + (uint8_t)data->btm_trig_data.token; + mlme_debug("roam btm: %u %u %u %u %u %u %u %u", + data->btm_trig_data.btm_request_mode, + data->btm_trig_data.disassoc_timer, + data->btm_trig_data.validity_interval, + data->btm_trig_data.candidate_list_count, + data->btm_trig_data.btm_resp_status, + data->btm_trig_data.btm_bss_termination_timeout, + data->btm_trig_data.btm_mbo_assoc_retry_timeout, + data->btm_trig_data.token); + break; + case ROAM_TRIGGER_REASON_BSS_LOAD: + info->trigger.condition.roam_bss_load.cu_load = + (uint8_t)data->cu_trig_data.cu_load; + mlme_debug("roam bss_load: cu_load:%u", + data->cu_trig_data.cu_load); + break; + case ROAM_TRIGGER_REASON_DEAUTH: + info->trigger.condition.roam_disconnection.deauth_type = + (uint8_t)data->deauth_trig_data.type; + info->trigger.condition.roam_disconnection.deauth_reason = + (uint16_t)data->deauth_trig_data.reason; + mlme_debug("roam disconnection: type:%u reason:%u", + data->deauth_trig_data.type, + data->deauth_trig_data.reason); + if (data->deauth_trig_data.type == 1) { + cm_cp_stats_cstats_log_deauth_evt( + vdev, CSTATS_DIR_RX, + data->deauth_trig_data.reason); + } else if (data->deauth_trig_data.type == 2) { + cm_cp_stats_cstats_log_disassoc_evt( + vdev, CSTATS_DIR_RX, + data->deauth_trig_data.reason); + } + break; + case ROAM_TRIGGER_REASON_STA_KICKOUT: + info->trigger.condition.roam_tx_failures.kickout_threshold = + data->tx_failures_trig_data.kickout_threshold; + info->trigger.condition.roam_tx_failures.kickout_reason = + data->tx_failures_trig_data.kickout_reason; + mlme_debug("roam tx_failures: kickout_th:%u kickout_reason:%u", + data->tx_failures_trig_data.kickout_threshold, + data->tx_failures_trig_data.kickout_reason); + break; + case ROAM_TRIGGER_REASON_IDLE: + case ROAM_TRIGGER_REASON_UNIT_TEST: + case ROAM_TRIGGER_REASON_MAWC: + default: + break; + } + + info->trigger.roam_scan_type = data->scan_type; + info->trigger.roam_status = data->roam_status; + mlme_debug("roam trigger info: scan_type:%u,status:%u", + data->scan_type, data->roam_status); + + if (info->trigger.roam_status) { + info->trigger.roam_fail_reason = data->fail_reason; + + if (data->abort_reason.abort_reason_code) { + info->trigger.abort.abort_reason_code = + data->abort_reason.abort_reason_code; + info->trigger.abort.data_rssi = + data->abort_reason.data_rssi; + info->trigger.abort.data_rssi_threshold = + data->abort_reason.data_rssi_threshold; + info->trigger.abort.rx_linkspeed_status = + data->abort_reason.rx_linkspeed_status; + } + + mlme_debug("abort:reason:%u,rssi:%d,rssit:%d,status:%u,fail:%u", + info->trigger.abort.abort_reason_code, + info->trigger.abort.data_rssi, + info->trigger.abort.data_rssi_threshold, + info->trigger.abort.rx_linkspeed_status, + info->trigger.roam_fail_reason); + } +} + +static uint32_t +wlan_cm_get_roam_chn_dwell_time(struct wlan_objmgr_vdev *vdev, + uint16_t freq, + enum roam_scan_dwell_type dwell_type) +{ + struct wlan_scan_obj *scan_obj; + + scan_obj = wlan_vdev_get_scan_obj(vdev); + if (!scan_obj) { + mlme_err("scan_obj is NULL"); + return 0; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) { + return scan_obj->scan_def.active_dwell_2g; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ(freq)) { + if (dwell_type == WLAN_ROAM_DWELL_PASSIVE_TYPE) + return scan_obj->scan_def.passive_dwell; + else + return scan_obj->scan_def.active_dwell; + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(freq)) { + if (dwell_type == WLAN_ROAM_DWELL_PASSIVE_TYPE) + return scan_obj->scan_def.passive_dwell_6g; + else + return scan_obj->scan_def.active_dwell_6g; + } + + return 0; +} + +/** + * wlan_cm_update_roam_scan_info() - API to update roam scan info + * @vdev: Pointer to vdev + * @scan: Scan data from target_if wmi event + * + * Get roam scan info from target_if wmi event and save in vdev mlme ring + * buffer, it is required that the mlme_priv->roam_rd_wr_lock be held before + * this API is called + * + * Return: void + */ +static void +wlan_cm_update_roam_scan_info(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_scan_data *scan) +{ + struct mlme_legacy_priv *mlme_priv; + struct enhance_roam_info *info; + uint32_t freq; + uint32_t dwell_type; + uint32_t i, index; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + index = mlme_priv->roam_write_index; + info = &mlme_priv->roam_info[index]; + info->scan.num_channels = scan->num_chan; + + if (scan->num_chan) { + for (i = 0; i < scan->num_chan; i++) { + info->scan.roam_chn[i].chan_freq = + scan->chan_freq[i]; + info->scan.roam_chn[i].dwell_type = + scan->dwell_type[i]; + + freq = scan->chan_freq[i]; + dwell_type = scan->dwell_type[i]; + info->scan.roam_chn[i].max_dwell_time = + wlan_cm_get_roam_chn_dwell_time(vdev, freq, + dwell_type); + + mlme_debug("freq %u dwell_type %u dwell_time:%u", + freq, dwell_type, + info->scan.roam_chn[i].max_dwell_time); + } + + info->scan.total_scan_time = + scan->scan_complete_timestamp - + info->trigger.timestamp; + + mlme_debug("roam scan:chn_num:%u,com:%u,total_time:%u,index:%u", + info->scan.num_channels, + scan->scan_complete_timestamp, + info->scan.total_scan_time, index); + } +} + +/** + * wlan_cm_roam_frame_subtype() - Convert roam host enum + * @frame: Roam frame info + * @frame_type: roam frame type + * + * Return: Roam frame type defined in host driver + */ +static enum eroam_frame_subtype +wlan_cm_roam_frame_subtype(struct roam_frame_info *frame, uint8_t frame_type) +{ + switch (frame_type) { + case MGMT_SUBTYPE_AUTH: + if (frame->is_rsp) + return WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP; + else + return WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ; + case MGMT_SUBTYPE_REASSOC_REQ: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ; + case MGMT_SUBTYPE_REASSOC_RESP: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP; + case ROAM_FRAME_SUBTYPE_M1: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1; + case ROAM_FRAME_SUBTYPE_M2: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2; + case ROAM_FRAME_SUBTYPE_M3: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3; + case ROAM_FRAME_SUBTYPE_M4: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4; + case ROAM_FRAME_SUBTYPE_GTK_M1: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1; + case ROAM_FRAME_SUBTYPE_GTK_M2: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2; + default: + return WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ; + } +} + +static bool +wlan_cm_get_valid_frame_type(struct roam_frame_info *frame) +{ + if (frame->subtype == MGMT_SUBTYPE_AUTH || + frame->subtype == MGMT_SUBTYPE_REASSOC_REQ || + frame->subtype == MGMT_SUBTYPE_REASSOC_RESP || + frame->subtype == ROAM_FRAME_SUBTYPE_M1 || + frame->subtype == ROAM_FRAME_SUBTYPE_M2 || + frame->subtype == ROAM_FRAME_SUBTYPE_M3 || + frame->subtype == ROAM_FRAME_SUBTYPE_M4) + return true; + else + return false; +} + +/** + * wlan_cm_update_roam_frame_info() - API to update roam frame info + * @mlme_priv: Pointer to Pointer to vdev mlme legacy priv struct + * @frame_data: Frame data from target_if wmi event + * + * Get roam frame info from target_if wmi event and save in vdev mlme ring + * buffer, it is required that the mlme_priv->roam_rd_wr_lock be held before + * this API is called + * + * Return: void + */ +static void +wlan_cm_update_roam_frame_info(struct mlme_legacy_priv *mlme_priv, + struct roam_frame_stats *frame_data) +{ + struct enhance_roam_info *info; + uint32_t index, i, j = 0; + uint8_t subtype; + + index = mlme_priv->roam_write_index; + info = &mlme_priv->roam_info[index]; + + for (i = 0; i < frame_data->num_frame; i++) { + if (!wlan_cm_get_valid_frame_type(&frame_data->frame_info[i])) + continue; + + if (j >= WLAN_ROAM_MAX_FRAME_INFO) + break; + /* + * fill frame preauth req/rsp, reassoc req/rsp + * and EAPOL-M1/M2/M3/M4 into roam buffer + */ + subtype = frame_data->frame_info[i].subtype; + info->timestamp[j].frame_type = + wlan_cm_roam_frame_subtype(&frame_data->frame_info[i], + subtype); + info->timestamp[j].timestamp = + frame_data->frame_info[i].timestamp; + info->timestamp[j].status = + frame_data->frame_info[i].status_code; + + qdf_mem_copy(info->timestamp[j].bssid.bytes, + frame_data->frame_info[i].bssid.bytes, + QDF_MAC_ADDR_SIZE); + + mlme_debug("frame:idx:%u subtype:%x time:%llu status:%u AP BSSID" QDF_MAC_ADDR_FMT, + j, info->timestamp[j].frame_type, + info->timestamp[j].timestamp, + info->timestamp[j].status, + QDF_MAC_ADDR_REF(info->timestamp[j].bssid.bytes)); + j++; + } +} + +/** + * wlan_cm_clear_current_roam_stats_info() - API to clear roam stats buffer date + * @mlme_priv: Pointer to Pointer to vdev mlme legacy priv struct + * + * clear the roam stats buffer data before write + * + * Return: void + */ +static void +wlan_cm_clear_current_roam_stats_info(struct mlme_legacy_priv *mlme_priv) +{ + uint32_t index; + + index = mlme_priv->roam_write_index; + qdf_mem_set(&mlme_priv->roam_info[index], + sizeof(struct enhance_roam_info), 0); +} + +/** + * wlan_cm_update_roam_bssid() - API to get roam stats AP BSSID + * @mlme_priv: Pointer to Pointer to vdev mlme legacy priv struct + * @scan: Scan data from target_if wmi event + * + * get AP BSSID from roam stats info which keep in scan data. + * + * Return: void + */ +static void +wlan_cm_update_roam_bssid(struct mlme_legacy_priv *mlme_priv, + struct wmi_roam_scan_data *scan) +{ + struct enhance_roam_info *info; + int16_t i; + uint16_t index, scan_ap_idx; + struct wmi_roam_candidate_info *ap = NULL; + + if (scan->num_ap == 0) + return; + + scan_ap_idx = scan->num_ap - 1; + ap = &scan->ap[scan_ap_idx]; + + index = mlme_priv->roam_write_index; + info = &mlme_priv->roam_info[index]; + + /* For roam failed, we may get candidate ap list, and only + * fetch the last candidate AP bssid. + */ + + for (i = scan_ap_idx; i >= 0; i--) { + if (ap->type == WLAN_ROAM_SCAN_CURRENT_AP) + qdf_mem_copy(info->scan.original_bssid.bytes, + ap->bssid.bytes, + QDF_MAC_ADDR_SIZE); + else if (ap->type == WLAN_ROAM_SCAN_ROAMED_AP) + qdf_mem_copy(info->scan.roamed_bssid.bytes, + ap->bssid.bytes, + QDF_MAC_ADDR_SIZE); + else + mlme_debug("unknown type:%u of AP", ap->type); + ap--; + } +} + +/** + * wlan_cm_update_roam_stats_info() - API to update roam stats info + * @psoc: Pointer to psoc + * @stats_info: Roam stats event + * @index: TLV index in roam stats event + * + * Get roam stats info from target_if wmi event and save in vdev mlme ring + * buffer. + * + * Return: void + */ +static void +wlan_cm_update_roam_stats_info(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info, + uint8_t index) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, stats_info->vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev%d: vdev object is NULL", stats_info->vdev_id); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return; + } + + if (mlme_priv->roam_cache_num == 0) { + mlme_debug("Enhanced roam stats not supported"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return; + } + + if (!mlme_priv->roam_info) { + mlme_err("enhance_roam_info buffer is NULL"); + return; + } + + qdf_mutex_acquire(&mlme_priv->roam_rd_wr_lock); + + if (stats_info->trigger[index].present) { + wlan_cm_clear_current_roam_stats_info(mlme_priv); + wlan_cm_update_roam_trigger_info(vdev, + &stats_info->trigger[index]); + if (stats_info->scan[index].present) + wlan_cm_update_roam_scan_info(vdev, + &stats_info->scan[index]); + if (stats_info->frame_stats[index].num_frame) + wlan_cm_update_roam_frame_info(mlme_priv, + &stats_info->frame_stats[index]); + if (stats_info->scan[index].present) + wlan_cm_update_roam_bssid(mlme_priv, + &stats_info->scan[index]); + + stats_info->enhance_roam_rt_event = true; + mlme_cm_osif_roam_rt_stats(stats_info, + mlme_priv->roam_write_index); + + mlme_priv->roam_write_index += 1; + if (mlme_priv->roam_write_index == mlme_priv->roam_cache_num) + mlme_priv->roam_write_index = 0; + } + qdf_mutex_release(&mlme_priv->roam_rd_wr_lock); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +QDF_STATUS +wlan_cm_roam_stats_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint32_t *roam_num) +{ + struct mlme_legacy_priv *mlme_priv; + uint32_t i, src, dst; + uint32_t index = 0; + uint32_t valid_cache_num; + struct enhance_roam_info *eroam_info; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (mlme_priv->roam_cache_num == 0) { + mlme_debug("Enhanced roam stats not supported"); + return QDF_STATUS_E_NOSUPPORT; + } + + qdf_mutex_acquire(&mlme_priv->roam_rd_wr_lock); + + /* get all roam event info from oldest to + * latest by timestamp. + */ + valid_cache_num = mlme_priv->roam_cache_num; + for (i = 0; i < mlme_priv->roam_cache_num; i++) { + if (mlme_priv->roam_info[i].trigger.timestamp == 0) { + valid_cache_num--; + continue; + } + if (mlme_priv->roam_info[i].trigger.timestamp < + mlme_priv->roam_info[index].trigger.timestamp) + index = i; + } + mlme_debug("valid num: %d, start index:%u", valid_cache_num, index); + + if (valid_cache_num == 0) { + mlme_debug("Enhanced roam stats not existed"); + qdf_mutex_release(&mlme_priv->roam_rd_wr_lock); + return QDF_STATUS_E_INVAL; + } + + /* Send all driver cached roam info to user space one time, + * and don't flush them, since they will be cover by + * new roam event info. + */ + eroam_info = + qdf_mem_malloc(valid_cache_num * + sizeof(*eroam_info)); + if (!eroam_info) { + qdf_mutex_release(&mlme_priv->roam_rd_wr_lock); + return QDF_STATUS_E_NOMEM; + } + + dst = 0; + src = index; + while (dst < valid_cache_num) { + if (mlme_priv->roam_info[src].trigger.timestamp == 0) { + src++; + } else { + eroam_info[dst] = mlme_priv->roam_info[src]; + src++; + dst++; + } + if (src == mlme_priv->roam_cache_num) + src = 0; + } + + *roam_num = valid_cache_num; + *roam_info = eroam_info; + qdf_mutex_release(&mlme_priv->roam_rd_wr_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cm_roam_info_get(struct wlan_objmgr_vdev *vdev, + struct enhance_roam_info **roam_info, + uint8_t idx) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (mlme_priv->roam_cache_num == 0) { + mlme_debug("Enhanced roam stats not supported"); + return QDF_STATUS_E_NOSUPPORT; + } + *roam_info = &mlme_priv->roam_info[idx]; + return QDF_STATUS_SUCCESS; +} + +#else +static void +wlan_cm_update_roam_stats_info(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info, + uint8_t index) +{ +} +#endif + +#ifdef WLAN_CHIPSET_STATS +static void +cm_cp_stats_cstats_roam_scan_cancel(struct cstats_sta_roam_scan_cancel *stat, + struct wmi_roam_trigger_abort_reason *abort) +{ + stat->reason_code = abort->abort_reason_code; + stat->data_rssi = abort->data_rssi; + stat->data_rssi_threshold = abort->data_rssi_threshold; + stat->rx_linkspeed_status = abort->rx_linkspeed_status; +} + +static void +cm_cp_stats_cstats_roam_scan_start(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_trigger_info *event, + bool is_full_scan) +{ + struct cstats_sta_roam_scan_start stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_ROAM_SCAN_START_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sta_roam_scan_start) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.trigger_reason = event->trigger_reason; + stat.trigger_sub_reason = event->trigger_sub_reason; + stat.rssi = event->current_rssi; + stat.timestamp = event->timestamp; + stat.is_full_scan = is_full_scan; + cm_cp_stats_cstats_roam_scan_cancel(&stat.abort_roam, + &event->abort_reason); + + wlan_cstats_host_stats(sizeof(struct cstats_sta_roam_scan_start), + &stat); +} + +static void +cm_cp_stats_cstats_roam_scan_ap(struct cstats_sta_roam_scan_ap *stat, + struct wmi_roam_candidate_info *ap, + uint8_t num_ap) +{ + uint8_t i; + + if (num_ap > MAX_ROAM_CANDIDATE_AP) + num_ap = MAX_ROAM_CANDIDATE_AP; + + for (i = 0; i < num_ap; i++) { + CSTATS_MAC_COPY(stat->bssid, ap->bssid.bytes); + stat[i].total_score = ap->total_score; + stat[i].rssi = ap->rssi; + stat[i].etp = ap->etp; + stat[i].freq = ap->freq; + stat[i].cu_load = ap->cu_load; + stat[i].is_mlo = ap->is_mlo; + stat[i].type = ap->type; + } +} + +static void cm_cp_stats_cstats_roam_scan_done(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_scan_data *event, + bool is_full_scan) +{ + struct cstats_sta_roam_scan_done stat = {0}; + uint8_t i; + + if (event->num_ap >= MAX_ROAM_CANDIDATE_AP && + event->num_chan > MAX_ROAM_SCAN_CHAN) + return; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_ROAM_SCAN_DONE_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sta_roam_scan_done) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.cand_ap_count = event->num_ap; + stat.num_scanned_freq = event->num_chan; + stat.timestamp = event->scan_complete_timestamp; + + for (i = 0; i < event->num_chan; i++) + stat.scanned_freq[i] = event->chan_freq[i]; + + stat.is_full_scan = is_full_scan; + cm_cp_stats_cstats_roam_scan_ap(stat.ap, event->ap, stat.cand_ap_count); + + wlan_cstats_host_stats(sizeof(struct cstats_sta_roam_scan_done), &stat); +} + +static void cm_cp_stats_cstats_roam_result(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_result *event) +{ + struct cstats_sta_roam_result stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_ROAM_RESULT_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sta_roam_result) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.timestamp = event->timestamp; + stat.status = event->status; + stat.fail_reason = event->fail_reason; + stat.roam_cancel_reason = event->roam_abort_reason; + CSTATS_MAC_COPY(stat.bssid, event->fail_bssid.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_sta_roam_result), &stat); +} +#else +static inline void +cm_cp_stats_cstats_roam_scan_start(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_trigger_info *event, + bool is_full_scan) +{ +} + +static inline void +cm_cp_stats_cstats_roam_scan_done(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_scan_data *event, + bool is_full_scan) +{ +} + +static inline void +cm_cp_stats_cstats_roam_result(struct wlan_objmgr_vdev *vdev, + struct wmi_roam_result *event) +{ +} +#endif /* WLAN_CHIPSET_STATS */ + +QDF_STATUS +cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info) +{ + uint8_t i, rem_tlv = 0; + bool is_wtc = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + uint32_t trigger; + struct wmi_roam_scan_data *scan = NULL; + + if (!stats_info) + return QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, stats_info->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + for (i = 0; i < stats_info->num_tlv; i++) { + if (stats_info->trigger[i].present) { + bool is_full_scan = + stats_info->scan[i].present && + stats_info->scan[i].type; + + cm_cp_stats_cstats_roam_scan_start + (vdev, &stats_info->trigger[i], is_full_scan); + + if (stats_info->trigger[i].trigger_reason == + ROAM_TRIGGER_REASON_BTM) { + cm_roam_handle_btm_stats(psoc, stats_info, i, + &rem_tlv); + if (!stats_info->trigger[i].common_roam) + continue; + } + + cm_roam_stats_print_trigger_info( + psoc, &stats_info->data_11kv[i], + &stats_info->trigger[i], + &stats_info->scan[i], + stats_info->vdev_id, is_full_scan); + + if (stats_info->scan[i].present) { + cm_roam_stats_print_scan_info( + psoc, &stats_info->scan[i], + stats_info->vdev_id, + stats_info->trigger[i].trigger_reason, + stats_info->trigger[i].timestamp); + + cm_cp_stats_cstats_roam_scan_done + (vdev, &stats_info->scan[i], is_full_scan); + + trigger = stats_info->trigger[i].trigger_reason; + scan = &stats_info->scan[i]; + if (trigger == ROAM_TRIGGER_REASON_LOW_RSSI || + trigger == ROAM_TRIGGER_REASON_PERIODIC) { + cm_roam_update_next_rssi_threshold( + psoc, scan->next_rssi_threshold, + stats_info->vdev_id); + } + } + } + + if (stats_info->result[i].present) { + cm_roam_stats_print_roam_result(psoc, + &stats_info->trigger[i], + &stats_info->result[i], + &stats_info->scan[i], + stats_info->vdev_id); + cm_cp_stats_cstats_roam_result + (vdev, &stats_info->result[i]); + } + + if (stats_info->frame_stats[i].num_frame) + cm_roam_print_frame_info(psoc, + vdev, + &stats_info->frame_stats[i], + &stats_info->scan[i], + &stats_info->result[i]); + + wlan_cm_update_roam_stats_info(psoc, stats_info, i); + + /* + * Print BTM resp TLV info (wmi_roam_btm_response_info) only + * when trigger reason is BTM or WTC_BTM. As for other roam + * triggers this TLV contains zeros, so host should not print. + */ + if (stats_info->btm_rsp[i].present && + stats_info->trigger[i].present && + (stats_info->trigger[i].trigger_reason == + ROAM_TRIGGER_REASON_BTM || + stats_info->trigger[i].trigger_reason == + ROAM_TRIGGER_REASON_WTC_BTM)) + cm_roam_stats_print_btm_rsp_info( + &stats_info->trigger[i], + &stats_info->btm_rsp[i], + stats_info->vdev_id, false); + + if (stats_info->roam_init_info[i].present) + cm_roam_stats_print_roam_initial_info( + &stats_info->roam_init_info[i], + stats_info->vdev_id); + + if (stats_info->roam_msg_info && + i < stats_info->num_roam_msg_info && + stats_info->roam_msg_info[i].present) { + rem_tlv++; + cm_roam_stats_process_roam_msg_info(psoc, + &stats_info->roam_msg_info[i], + stats_info->vdev_id); + } + + cm_report_roam_rt_stats(psoc, stats_info->vdev_id, + ROAM_RT_STATS_TYPE_ROAM_SCAN_INFO, + stats_info, 0, i, 0); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + if (!stats_info->num_tlv) { + /* + * wmi_roam_trigger_reason TLV is sent only for userspace + * logging of BTM/WTC frame without roam scans. + */ + + if (stats_info->data_11kv[0].present) + cm_roam_stats_print_11kv_info(psoc, + &stats_info->data_11kv[0], + stats_info->vdev_id); + + if (stats_info->trigger[0].present && + (stats_info->trigger[0].trigger_reason == + ROAM_TRIGGER_REASON_BTM || + stats_info->trigger[0].trigger_reason == + ROAM_TRIGGER_REASON_WTC_BTM)) { + if (stats_info->trigger[0].trigger_reason == + ROAM_TRIGGER_REASON_WTC_BTM) + is_wtc = true; + + cm_roam_btm_req_event(&stats_info->data_11kv[0], + &stats_info->trigger[0].btm_trig_data, + &stats_info->trigger[0], + stats_info->vdev_id, is_wtc); + } + + if (stats_info->scan[0].present && + stats_info->trigger[0].present) + cm_roam_stats_print_scan_info(psoc, + &stats_info->scan[0], + stats_info->vdev_id, + stats_info->trigger[0].trigger_reason, + stats_info->trigger[0].timestamp); + + if (stats_info->btm_rsp[0].present) + cm_roam_stats_print_btm_rsp_info( + &stats_info->trigger[0], + &stats_info->btm_rsp[0], + stats_info->vdev_id, 0); + + /* + * WTC BTM response with reason code + * WTC print should be after the normal BTM + * response print + */ + if (stats_info->trigger[0].present && + stats_info->trigger[0].trigger_reason == + ROAM_TRIGGER_REASON_WTC_BTM) + cm_roam_btm_resp_event(&stats_info->trigger[0], NULL, + stats_info->vdev_id, true); + } + + if (stats_info->roam_msg_info && stats_info->num_roam_msg_info && + stats_info->num_roam_msg_info - rem_tlv) { + for (i = 0; i < (stats_info->num_roam_msg_info-rem_tlv); i++) { + if (stats_info->roam_msg_info[rem_tlv + i].present) + cm_roam_stats_process_roam_msg_info(psoc, + &stats_info->roam_msg_info[rem_tlv + i], + stats_info->vdev_id); + } + } + +out: + wlan_clear_sae_auth_logs_cache(psoc, stats_info->vdev_id); + qdf_mem_free(stats_info->roam_msg_info); + qdf_mem_free(stats_info); + + return status; +} + +bool wlan_cm_is_roam_sync_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + bool ret; + enum QDF_OPMODE opmode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + + if (!vdev) + return false; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + + if (opmode != QDF_STA_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return false; + } + + ret = cm_is_vdev_roam_sync_inprogress(vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return ret; +} + +void +wlan_cm_set_roam_offload_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ + struct mlme_legacy_priv *mlme_priv; + struct qdf_mac_addr *mlme_bssid; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + mlme_bssid = &(mlme_priv->cm_roam.sae_offload.bssid); + + if (!bssid || qdf_is_macaddr_zero(bssid)) { + mlme_err("NULL BSSID"); + return; + } + qdf_mem_copy(mlme_bssid->bytes, bssid->bytes, QDF_MAC_ADDR_SIZE); +} + +void +wlan_cm_get_roam_offload_bssid(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ + struct mlme_legacy_priv *mlme_priv; + struct qdf_mac_addr *mlme_bssid; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + mlme_bssid = &(mlme_priv->cm_roam.sae_offload.bssid); + + if (!bssid) + return; + qdf_mem_copy(bssid->bytes, mlme_bssid->bytes, QDF_MAC_ADDR_SIZE); +} + +void +wlan_cm_set_roam_offload_ssid(struct wlan_objmgr_vdev *vdev, + uint8_t *ssid, uint8_t len) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_ssid *mlme_ssid; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + return; + } + + mlme_ssid = &mlme_priv->cm_roam.sae_offload.ssid; + + if (len > WLAN_SSID_MAX_LEN) + len = WLAN_SSID_MAX_LEN; + + qdf_mem_zero(mlme_ssid, sizeof(struct wlan_ssid)); + qdf_mem_copy(&mlme_ssid->ssid[0], ssid, len); + mlme_ssid->length = len; + + mlme_debug("Set roam offload ssid: " QDF_SSID_FMT, + QDF_SSID_REF(mlme_ssid->length, + mlme_ssid->ssid)); +} + +void +wlan_cm_get_roam_offload_ssid(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t *ssid, uint8_t *len) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + struct wlan_ssid *mlme_ssid; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("VDEV is NULL"); + return; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("vdev legacy private object is NULL"); + goto ret; + } + + mlme_ssid = &mlme_priv->cm_roam.sae_offload.ssid; + + qdf_mem_copy(ssid, mlme_ssid->ssid, mlme_ssid->length); + *len = mlme_ssid->length; + +ret: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +void +wlan_cm_roam_set_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint16_t roam_ho_delay) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.lfr.roam_ho_delay_config = roam_ho_delay; +} + +uint16_t +wlan_cm_roam_get_ho_delay_config(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return 0; + } + + return mlme_obj->cfg.lfr.roam_ho_delay_config; +} + +void +wlan_cm_set_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t exclude_rm_partial_scan_freq) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.lfr.exclude_rm_partial_scan_freq = + exclude_rm_partial_scan_freq; +} + +uint8_t +wlan_cm_get_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return 0; + } + + return mlme_obj->cfg.lfr.exclude_rm_partial_scan_freq; +} + +void +wlan_cm_roam_set_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc, + uint8_t roam_full_scan_6ghz_on_disc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.lfr.roam_full_scan_6ghz_on_disc = + roam_full_scan_6ghz_on_disc; +} + +uint8_t wlan_cm_roam_get_full_scan_6ghz_on_disc(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) { + mlme_legacy_err("Failed to get MLME Obj"); + return 0; + } + + return mlme_obj->cfg.lfr.roam_full_scan_6ghz_on_disc; +} + +void +wlan_cm_set_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc, + uint8_t roam_high_rssi_delta) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return; + + mlme_obj->cfg.lfr.roam_high_rssi_delta = roam_high_rssi_delta; +} + +uint8_t +wlan_cm_get_roam_scan_high_rssi_offset(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return 0; + + return mlme_obj->cfg.lfr.roam_high_rssi_delta; +} + +bool wlan_cm_is_mbo_ap_without_pmf(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return cm_is_mbo_ap_without_pmf(psoc, vdev_id); +} + +QDF_STATUS +wlan_cm_roam_btm_block_event(uint8_t vdev_id, uint8_t token, + enum wlan_diag_btm_block_reason reason) +{ + return cm_roam_btm_block_event(vdev_id, token, reason); +} +#else +QDF_STATUS +cm_roam_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_stats_event *stats_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_FIPS +QDF_STATUS cm_roam_pmkid_req_ind(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct roam_pmkid_req_event *src_lst) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr *dst_list; + uint32_t num_entries, i; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + num_entries = src_lst->num_entries; + mlme_debug("Num entries %d", num_entries); + for (i = 0; i < num_entries; i++) { + dst_list = &src_lst->ap_bssid[i]; + status = mlme_cm_osif_pmksa_candidate_notify(vdev, dst_list, + 1, false); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Number %d Notify failed for " QDF_MAC_ADDR_FMT, + i, QDF_MAC_ADDR_REF(dst_list->bytes)); + goto rel_ref; + } + } + +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} +#endif /* WLAN_FEATURE_FIPS */ + +QDF_STATUS +cm_cleanup_mlo_link(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + /* Use MLO roam internal disconnect as this is for cleanup and + * no need to inform OSIF, and REASON_FW_TRIGGERED_ROAM_FAILURE will + * cleanup host without informing the FW + */ + status = wlan_cm_disconnect(vdev, + CM_MLO_ROAM_INTERNAL_DISCONNECT, + REASON_FW_TRIGGERED_ROAM_FAILURE, + NULL); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("Failed to post disconnect for link vdev"); + + return status; +} + +bool wlan_is_rso_enabled(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + enum roam_offload_state cur_state; + + cur_state = mlme_get_roam_state(psoc, vdev_id); + if (cur_state == WLAN_ROAM_RSO_ENABLED || + cur_state == WLAN_ROAMING_IN_PROG || + cur_state == WLAN_ROAM_SYNCH_IN_PROG || + cur_state == WLAN_MLO_ROAM_SYNCH_IN_PROG) + return true; + + return false; +} + +bool wlan_is_roaming_enabled(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (mlme_get_roam_state(psoc, vdev_id) == WLAN_ROAM_DEINIT) + return false; + + return true; +} + +QDF_STATUS +wlan_cm_set_sae_auth_ta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr sae_auth_ta) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_objmgr_vdev *vdev; + + if (!pdev) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(mlme_priv->mlme_roam.sae_auth_ta.bytes, sae_auth_ta.bytes, + QDF_MAC_ADDR_SIZE); + mlme_priv->mlme_roam.sae_auth_pending = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cm_get_sae_auth_ta(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *sae_auth_ta) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_objmgr_vdev *vdev; + + if (!pdev) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_INVAL; + } + + if (mlme_priv->mlme_roam.sae_auth_pending) { + qdf_mem_copy(sae_auth_ta->bytes, + mlme_priv->mlme_roam.sae_auth_ta.bytes, + QDF_MAC_ADDR_SIZE); + mlme_priv->mlme_roam.sae_auth_pending = false; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_SUCCESS; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_E_ALREADY; +} + +void +wlan_cm_set_assoc_btm_cap(struct wlan_objmgr_vdev *vdev, bool val) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + mlme_priv->connect_info.assoc_btm_cap = val; +} + +bool wlan_cm_get_assoc_btm_cap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct mlme_legacy_priv *mlme_priv; + struct wlan_objmgr_vdev *vdev; + bool assoc_btm_cap = true; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + mlme_err("vdev is NULL"); + return true; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_err("mlme_priv is NULL"); + goto release_ref; + } + + assoc_btm_cap = mlme_priv->connect_info.assoc_btm_cap; + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return assoc_btm_cap; +} + +bool wlan_cm_is_self_mld_roam_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + mlme_debug("Invalid WMI handle"); + return false; + } + + return wmi_service_enabled(wmi_handle, + wmi_service_self_mld_roam_between_dbs_and_hbs); +} + +void +wlan_cm_set_force_20mhz_in_24ghz(struct wlan_objmgr_vdev *vdev, + bool is_40mhz_cap) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct mlme_legacy_priv *mlme_priv; + uint16_t dot11_mode; + bool send_ie_to_fw = false; + + if (!vdev) + return; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj || !mlme_obj->cfg.obss_ht40.is_override_ht20_40_24g) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + /* + * Force the connection to 20 MHz in 2.4 GHz if the userspace + * connect req doesn't support 40 MHz in HT caps. + */ + if (mlme_priv->connect_info.force_20mhz_in_24ghz != !is_40mhz_cap) + send_ie_to_fw = true; + + mlme_priv->connect_info.force_20mhz_in_24ghz = !is_40mhz_cap; + + if (cm_is_vdev_connected(vdev) && send_ie_to_fw) { + dot11_mode = + cm_csr_get_vdev_dot11_mode(wlan_vdev_get_id(vdev)); + cm_send_ies_for_roam_invoke(vdev, dot11_mode); + } +} + +bool +wlan_cm_get_force_20mhz_in_24ghz(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!vdev) + return true; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return true; + + return mlme_priv->connect_info.force_20mhz_in_24ghz; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +wlan_cm_update_offload_ssid_from_candidate(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + struct qdf_mac_addr *ap_bssid) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + qdf_list_t *list = NULL; + struct scan_cache_node *first_node = NULL; + struct scan_filter *scan_filter; + struct scan_cache_entry *entry; + struct qdf_mac_addr cache_bssid; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + /* + * sae_offload ssid, bssid would have already been cached + * from the tx profile of the roam_candidate_frame from FW, + * but if the roam offload is received for a non-tx BSSID, + * then the ssid stored in mlme_priv would be incorrect. + * + * If the bssid cached in sae_offload_param doesn't match + * with the bssid received in roam_offload_event, then + * get the scan entry from scan table to save the proper + * ssid, bssid. + */ + wlan_cm_get_roam_offload_bssid(vdev, &cache_bssid); + if (!qdf_mem_cmp(cache_bssid.bytes, ap_bssid->bytes, QDF_MAC_ADDR_SIZE)) + goto end; + + mlme_debug("Update the roam offload ssid from scan cache"); + + scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); + if (!scan_filter) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + scan_filter->num_of_bssid = 1; + qdf_mem_copy(scan_filter->bssid_list[0].bytes, + ap_bssid, sizeof(struct qdf_mac_addr)); + + list = wlan_scan_get_result(pdev, scan_filter); + qdf_mem_free(scan_filter); + + if (!list || !qdf_list_size(list)) { + mlme_err("Scan result is empty, candidate entry not found"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_list_peek_front(list, (qdf_list_node_t **)&first_node); + if (first_node && first_node->entry) { + entry = first_node->entry; + wlan_cm_set_roam_offload_ssid(vdev, + &entry->ssid.ssid[0], + entry->ssid.length); + wlan_cm_set_roam_offload_bssid(vdev, ap_bssid); + } + +end: + if (list) + wlan_scan_purge_results(list); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return status; +} + +QDF_STATUS +wlan_cm_add_frame_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *frame) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct cnx_mgr *cm_ctx; + uint32_t ie_offset, ie_len; + uint8_t *ie_ptr = NULL; + uint8_t *extracted_ie = NULL; + uint8_t primary_channel, band; + qdf_freq_t op_freq; + struct wlan_frame_hdr *wh; + struct qdf_mac_addr bssid; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, frame->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev object is NULL"); + goto err; + } + + cm_ctx = cm_get_cm_ctx(vdev); + if (!cm_ctx) { + mlme_err("cm ctx is NULL"); + goto err; + } + + /* Fixed parameters offset */ + ie_offset = sizeof(struct wlan_frame_hdr) + MAC_B_PR_SSID_OFFSET; + + if (frame->frame_length <= ie_offset) { + mlme_err("Invalid frame length"); + goto err; + } + + ie_ptr = frame->frame + ie_offset; + ie_len = frame->frame_length - ie_offset; + + extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_SSID, + ie_ptr, ie_len); + /* + * Roam offload ssid/bssid needs to be set only for SAE roam offload + * candidate frames for supporting cross-ssid roaming. + * This update is not needed for probe/beacons received from the + * roam sync frame event. + */ + if (frame->roam_offload_candidate_frm && + extracted_ie && extracted_ie[0] == WLAN_ELEMID_SSID) { + wh = (struct wlan_frame_hdr *)frame->frame; + WLAN_ADDR_COPY(&bssid.bytes[0], wh->i_addr2); + + mlme_debug("SSID of the candidate is " QDF_SSID_FMT, + QDF_SSID_REF(extracted_ie[1], &extracted_ie[2])); + wlan_cm_set_roam_offload_ssid(vdev, &extracted_ie[2], + extracted_ie[1]); + wlan_cm_set_roam_offload_bssid(vdev, &bssid); + } + + /* For 2.4GHz,5GHz get channel from DS IE */ + extracted_ie = (uint8_t *)wlan_get_ie_ptr_from_eid(WLAN_ELEMID_DSPARMS, + ie_ptr, ie_len); + if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_DSPARMS && + extracted_ie[1] == WLAN_DS_PARAM_IE_MAX_LEN) { + band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + primary_channel = *(extracted_ie + 2); + mlme_debug("Extracted primary channel from DS : %d", + primary_channel); + goto update_beacon; + } + + /* For HT, VHT and non-6GHz HE, get channel from HTINFO IE */ + extracted_ie = (uint8_t *) + wlan_get_ie_ptr_from_eid(WLAN_ELEMID_HTINFO_ANA, + ie_ptr, ie_len); + if (extracted_ie && extracted_ie[0] == WLAN_ELEMID_HTINFO_ANA && + extracted_ie[1] == sizeof(struct wlan_ie_htinfo_cmn)) { + band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + primary_channel = + ((struct wlan_ie_htinfo *)extracted_ie)-> + hi_ie.hi_ctrlchannel; + mlme_debug("Extracted primary channel from HT INFO : %d", + primary_channel); + goto update_beacon; + } + /* For 6GHz, get channel from HE OP IE */ + extracted_ie = (uint8_t *) + wlan_get_ext_ie_ptr_from_ext_id(WLAN_HEOP_OUI_TYPE, + (uint8_t) + WLAN_HEOP_OUI_SIZE, + ie_ptr, ie_len); + if (extracted_ie && !qdf_mem_cmp(&extracted_ie[2], WLAN_HEOP_OUI_TYPE, + WLAN_HEOP_OUI_SIZE) && + extracted_ie[1] <= WLAN_MAX_HEOP_IE_LEN) { + band = BIT(REG_BAND_6G); + primary_channel = util_scan_get_6g_oper_channel(extracted_ie); + mlme_debug("Extracted primary channel from HE OP : %d", + primary_channel); + if (primary_channel) + goto update_beacon; + } + + mlme_err("Ignore beacon, Primary channel was not found in the candidate frame"); + goto err; + +update_beacon: + op_freq = wlan_reg_chan_band_to_freq(pdev, primary_channel, band); + cm_inform_bcn_probe(cm_ctx, frame->frame, frame->frame_length, + op_freq, + frame->rssi, + cm_ctx->active_cm_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_SUCCESS; +err: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_FAILURE; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +bool wlan_cm_is_sae_auth_addr_conversion_required(struct wlan_objmgr_vdev *vdev) +{ + if (!wlan_vdev_get_mlo_external_sae_auth_conversion(vdev)) + return false; + + if (wlan_cm_is_vdev_roaming(vdev)) { + if (!wlan_cm_roam_is_mlo_ap(vdev)) + return false; + } else if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + return false; + } + + return true; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +/** + * wlan_cm_reset_mlo_roam_peer_address() - this API reset the sae_roam_auth + * structure values to zero. + * @rso_config: pointer to struct rso_config + * + * Return: void + */ +static void wlan_cm_reset_mlo_roam_peer_address(struct rso_config *rso_config) +{ + qdf_mem_zero(&rso_config->sae_roam_auth.peer_mldaddr, + QDF_MAC_ADDR_SIZE); + qdf_mem_zero(&rso_config->sae_roam_auth.peer_linkaddr, + QDF_MAC_ADDR_SIZE); +} + +void wlan_cm_store_mlo_roam_peer_address(struct wlan_objmgr_pdev *pdev, + struct auth_offload_event *auth_event) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_config; + struct qdf_mac_addr mld_addr; + QDF_STATUS status; + + if (!pdev) { + mlme_err("pdev is NULL"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, auth_event->vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + mlme_err("vdev %d not found", auth_event->vdev_id); + return; + } + + if (!wlan_vdev_get_mlo_external_sae_auth_conversion(vdev)) + goto rel_ref; + + if (!wlan_cm_is_vdev_roaming(vdev)) + goto rel_ref; + + rso_config = wlan_cm_get_rso_config(vdev); + if (!rso_config) + goto rel_ref; + + if (qdf_is_macaddr_zero(&auth_event->ta)) { + /* ta have zero value for non-ML AP */ + rso_config->sae_roam_auth.is_mlo_ap = false; + wlan_cm_reset_mlo_roam_peer_address(rso_config); + goto rel_ref; + } + + status = scm_get_mld_addr_by_link_addr(pdev, &auth_event->ap_bssid, + &mld_addr); + + rso_config->sae_roam_auth.is_mlo_ap = true; + + if (QDF_IS_STATUS_ERROR(status)) { + wlan_cm_reset_mlo_roam_peer_address(rso_config); + goto rel_ref; + } + + qdf_mem_copy(rso_config->sae_roam_auth.peer_mldaddr.bytes, + mld_addr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(rso_config->sae_roam_auth.peer_linkaddr.bytes, + &auth_event->ap_bssid, QDF_MAC_ADDR_SIZE); + + mlme_debug("mld addr " QDF_MAC_ADDR_FMT "link addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(rso_config->sae_roam_auth.peer_mldaddr.bytes), + QDF_MAC_ADDR_REF(rso_config->sae_roam_auth.peer_linkaddr.bytes)); +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +struct qdf_mac_addr * +wlan_cm_roaming_get_peer_mld_addr(struct wlan_objmgr_vdev *vdev) +{ + struct rso_config *rso_config; + + rso_config = wlan_cm_get_rso_config(vdev); + if (!rso_config) + return NULL; + + if (qdf_is_macaddr_zero(&rso_config->sae_roam_auth.peer_mldaddr)) + return NULL; + + return &rso_config->sae_roam_auth.peer_mldaddr; +} + +struct qdf_mac_addr * +wlan_cm_roaming_get_peer_link_addr(struct wlan_objmgr_vdev *vdev) +{ + struct rso_config *rso_config; + + rso_config = wlan_cm_get_rso_config(vdev); + if (!rso_config) + return NULL; + + if (qdf_is_macaddr_zero(&rso_config->sae_roam_auth.peer_linkaddr)) + return NULL; + + return &rso_config->sae_roam_auth.peer_linkaddr; +} + +bool wlan_cm_roam_is_mlo_ap(struct wlan_objmgr_vdev *vdev) +{ + struct rso_config *rso_config; + + rso_config = wlan_cm_get_rso_config(vdev); + if (!rso_config) + return false; + + return rso_config->sae_roam_auth.is_mlo_ap; +} + +QDF_STATUS +cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate) +{ + return mlo_add_all_link_probe_rsp_to_scan_db(psoc, candidate); +} + +QDF_STATUS +wlan_cm_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate) +{ + return mlo_add_all_link_probe_rsp_to_scan_db(psoc, candidate); +} + +#elif defined(WLAN_FEATURE_ROAM_OFFLOAD) /* end WLAN_FEATURE_11BE_MLO */ +QDF_STATUS +cm_roam_candidate_event_handler(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate) +{ + return wlan_cm_add_frame_to_scan_db(psoc, candidate); +} + +QDF_STATUS +wlan_cm_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *candidate) +{ + return wlan_cm_add_frame_to_scan_db(psoc, candidate); +} + +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS wlan_cm_link_switch_notif_cb(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_link_switch_req *req, + enum wlan_mlo_link_switch_notify_reason notify_reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (notify_reason != MLO_LINK_SWITCH_NOTIFY_REASON_PRE_START_PRE_SER) + return status; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return status; + + /* Only send RSO stop for assoc vdev */ + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return status; + + status = cm_roam_state_change(wlan_vdev_get_pdev(vdev), + wlan_vdev_get_id(vdev), + WLAN_ROAM_RSO_STOPPED, + REASON_DISCONNECTED, NULL, false); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("vdev:%d switch to RSO Stop failed", + wlan_vdev_get_id(vdev)); + + return status; +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c new file mode 100644 index 0000000000..0a2ebafb4b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c @@ -0,0 +1,747 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_roam_ucfg_api.c + * + * Implementation for roaming ucfg public functionality. + */ + +#include "wlan_mlme_ucfg_api.h" +#include "wlan_cm_roam_ucfg_api.h" +#include "../../core/src/wlan_cm_roam_offload.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_mlo_mgr_sta.h" + +bool ucfg_is_rso_enabled(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + return wlan_is_rso_enabled(pdev, vdev_id); +} + +QDF_STATUS +ucfg_user_space_enable_disable_rso(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + const bool is_fast_roam_enabled) +{ + bool supplicant_disabled_roaming; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + QDF_STATUS status; + bool lfr_enabled; + enum roam_offload_state state; + uint32_t set_val = 0; + enum roam_offload_state cur_state; + + /* + * If the ini "FastRoamEnabled" is disabled, don't allow the + * userspace to enable roam offload + */ + ucfg_mlme_is_lfr_enabled(psoc, &lfr_enabled); + if (!lfr_enabled) { + mlme_debug("ROAM_CONFIG: Fast roam ini is disabled. is_fast_roam_enabled %d", + is_fast_roam_enabled); + if (!is_fast_roam_enabled) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; + } + + cur_state = mlme_get_roam_state(psoc, vdev_id); + if (cur_state == WLAN_ROAM_INIT) { + if (!is_fast_roam_enabled) + set_val = + WMI_VDEV_ROAM_11KV_CTRL_DISABLE_FW_TRIGGER_ROAMING; + + status = cm_roam_send_disable_config(psoc, vdev_id, set_val); + if (!QDF_IS_STATUS_SUCCESS(status)) + mlme_err("ROAM: update fast roaming failed, status: %d", + status); + } + wlan_mlme_set_usr_disabled_roaming(psoc, !is_fast_roam_enabled); + + /* + * Supplicant_disabled_roaming flag is only effective for current + * connection, it will be cleared during new connection. + * is_fast_roam_enabled: true - enable RSO if not disabled by driver + * false - Disable RSO. Send RSO stop if false + * is set. + */ + supplicant_disabled_roaming = + mlme_get_supplicant_disabled_roaming(psoc, vdev_id); + if (!is_fast_roam_enabled && supplicant_disabled_roaming) { + mlme_debug("ROAM_CONFIG: RSO already disabled by supplicant"); + return QDF_STATUS_E_ALREADY; + } + + mlme_set_supplicant_disabled_roaming(psoc, vdev_id, + !is_fast_roam_enabled); + + /* For mlo connection, before all links are up + * supplicant can enable roaming, to handle this + * drop the enable rso as host will enable roaming + * once all links are up + */ + if (mlo_is_ml_connection_in_progress(psoc, vdev_id)) { + mlme_debug("mlo connection in progress"); + return QDF_STATUS_SUCCESS; + } + + state = (is_fast_roam_enabled) ? + WLAN_ROAM_RSO_ENABLED : WLAN_ROAM_RSO_STOPPED; + status = cm_roam_state_change(pdev, vdev_id, state, + REASON_SUPPLICANT_DISABLED_ROAMING, + NULL, false); + + return status; +} + +void +ucfg_clear_user_disabled_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + wlan_mlme_set_usr_disabled_roaming(psoc, false); + mlme_set_supplicant_disabled_roaming(psoc, vdev_id, false); +} + +QDF_STATUS ucfg_cm_abort_roam_scan(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + bool roam_scan_offload_enabled; + + ucfg_mlme_is_roam_scan_offload_enabled(psoc, + &roam_scan_offload_enabled); + if (!roam_scan_offload_enabled) + return QDF_STATUS_SUCCESS; + + status = cm_roam_send_rso_cmd(psoc, vdev_id, + ROAM_SCAN_OFFLOAD_ABORT_SCAN, + REASON_ROAM_ABORT_ROAM_SCAN); + + return status; +} + +QDF_STATUS ucfg_cm_get_roam_band(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t *roam_band) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, ROAM_BAND, &temp); + + *roam_band = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS ucfg_cm_set_ese_roam_scan_channel_list(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + qdf_freq_t *chan_freq_list, + uint8_t num_chan) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum band_info band = -1; + uint32_t band_bitmap; + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto release_ref; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + status = QDF_STATUS_E_FAILURE; + goto error; + } + + mlme_debug("Chan list Before"); + cm_dump_freq_list(&rso_cfg->roam_scan_freq_lst); + ucfg_reg_get_band(pdev, &band_bitmap); + band = wlan_reg_band_bitmap_to_band_info(band_bitmap); + status = cm_create_roam_scan_channel_list(pdev, rso_cfg, num_chan, + chan_freq_list, num_chan, + band); + if (QDF_IS_STATUS_SUCCESS(status)) { + mlme_debug("Chan list After"); + cm_dump_freq_list(&rso_cfg->roam_scan_freq_lst); + } + + if (mlme_obj->cfg.lfr.roam_scan_offload_enabled) + wlan_roam_update_cfg(psoc, vdev_id, + REASON_CHANNEL_LIST_CHANGED); + + +error: + cm_roam_release_lock(vdev); +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +QDF_STATUS ucfg_cm_set_cckm_ie(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + const uint8_t *cck_ie, const uint8_t cck_ie_len) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_CM_ID); + + if (!vdev) { + mlme_err("vdev not found for id %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(mlme_priv->connect_info.cckm_ie, cck_ie, cck_ie_len); + mlme_priv->connect_info.cckm_ie_len = cck_ie_len; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return QDF_STATUS_SUCCESS; +} + +#endif + +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS +ucfg_cm_update_fils_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_fils_con_info *fils_info) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = wlan_cm_update_mlme_fils_info(vdev, fils_info); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} +#endif + +QDF_STATUS +ucfg_wlan_cm_roam_invoke(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + struct qdf_mac_addr *bssid, qdf_freq_t ch_freq, + enum wlan_cm_source source) +{ + return wlan_cm_roam_invoke(pdev, vdev_id, bssid, ch_freq, source); +} + +#ifdef WLAN_FEATURE_HOST_ROAM +void ucfg_cm_set_ft_pre_auth_state(struct wlan_objmgr_vdev *vdev, bool state) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + mlme_priv->connect_info.ft_info.set_ft_preauth_state = state; +} + +static bool ucfg_cm_get_ft_pre_auth_state(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return false; + + return mlme_priv->connect_info.ft_info.set_ft_preauth_state; +} + +void ucfg_cm_set_ft_ies(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + const uint8_t *ft_ies, uint16_t ft_ies_length) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + if (!ft_ies) { + mlme_err("ft ies is NULL"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + goto end; + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + mlme_debug("FT IEs Req is received in state %d", + mlme_priv->connect_info.ft_info.ft_state); + + /* Global Station FT State */ + switch (mlme_priv->connect_info.ft_info.ft_state) { + case FT_START_READY: + case FT_AUTH_REQ_READY: + mlme_debug("ft_ies_length: %d", ft_ies_length); + ft_ies_length = QDF_MIN(ft_ies_length, MAX_FTIE_SIZE); + mlme_priv->connect_info.ft_info.auth_ie_len = ft_ies_length; + qdf_mem_copy(mlme_priv->connect_info.ft_info.auth_ft_ie, + ft_ies, ft_ies_length); + mlme_priv->connect_info.ft_info.ft_state = FT_AUTH_REQ_READY; + break; + + case FT_REASSOC_REQ_WAIT: + /* + * We are done with pre-auth, hence now waiting for + * reassoc req. This is the new FT Roaming in place At + * this juncture we'r ready to start sending Reassoc req + */ + + ft_ies_length = QDF_MIN(ft_ies_length, MAX_FTIE_SIZE); + + mlme_debug("New Reassoc Req: %pK in state %d", + ft_ies, mlme_priv->connect_info.ft_info.ft_state); + mlme_priv->connect_info.ft_info.reassoc_ie_len = + ft_ies_length; + qdf_mem_copy(mlme_priv->connect_info.ft_info.reassoc_ft_ie, + ft_ies, ft_ies_length); + + mlme_priv->connect_info.ft_info.ft_state = FT_SET_KEY_WAIT; + mlme_debug("ft_ies_length: %d state: %d", ft_ies_length, + mlme_priv->connect_info.ft_info.ft_state); + break; + + default: + mlme_warn("Unhandled state: %d", + mlme_priv->connect_info.ft_info.ft_state); + break; + } + cm_roam_release_lock(vdev); +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); +} + +QDF_STATUS ucfg_cm_check_ft_status(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) + return status; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + goto end; + + status = cm_roam_acquire_lock(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + mlme_debug("FT update key is received in state %d", + mlme_priv->connect_info.ft_info.ft_state); + + /* Global Station FT State */ + switch (mlme_priv->connect_info.ft_info.ft_state) { + case FT_SET_KEY_WAIT: + if (ucfg_cm_get_ft_pre_auth_state(vdev)) { + mlme_priv->connect_info.ft_info.ft_state = FT_START_READY; + mlme_debug("state changed to %d", + mlme_priv->connect_info.ft_info.ft_state); + break; + } + fallthrough; + default: + mlme_debug("Unhandled state:%d", + mlme_priv->connect_info.ft_info.ft_state); + status = QDF_STATUS_E_FAILURE; + break; + } + cm_roam_release_lock(vdev); +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return status; +} + +bool ucfg_cm_ft_key_ready_for_install(struct wlan_objmgr_vdev *vdev) +{ + bool ret = false; + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return ret; + + if (ucfg_cm_get_ft_pre_auth_state(vdev) && + mlme_priv->connect_info.ft_info.ft_state == FT_START_READY) { + ret = true; + ucfg_cm_set_ft_pre_auth_state(vdev, false); + } + + return ret; +} + +void ucfg_cm_ft_reset(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + qdf_mem_zero(&mlme_priv->connect_info.ft_info, + sizeof(struct ft_context)); + + mlme_priv->connect_info.ft_info.ft_state = FT_START_READY; +} +#endif /* WLAN_FEATURE_HOST_ROAM */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef FEATURE_WLAN_ESE +static void +ucfg_cm_reset_esecckm_info(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + return; + } + + qdf_mem_zero(rso_cfg->krk, WMI_KRK_KEY_LEN); + qdf_mem_zero(rso_cfg->btk, WMI_BTK_KEY_LEN); + rso_cfg->is_ese_assoc = false; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + +} +#else +static inline +void ucfg_cm_reset_esecckm_info(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ +} +#endif + +void ucfg_cm_reset_key(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id) +{ + wlan_cm_set_psk_pmk(pdev, vdev_id, NULL, 0); + ucfg_cm_reset_esecckm_info(pdev, vdev_id); +} + +QDF_STATUS +ucfg_cm_roam_send_rt_stats_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + return cm_roam_send_rt_stats_config(psoc, vdev_id, param_value); +} + +QDF_STATUS +ucfg_cm_roam_send_ho_delay_config(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint16_t param_value) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + return cm_roam_send_ho_delay_config(psoc, vdev_id, param_value); +} + +QDF_STATUS +ucfg_cm_exclude_rm_partial_scan_freq(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint8_t param_value) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + return cm_exclude_rm_partial_scan_freq(psoc, vdev_id, param_value); +} + +QDF_STATUS ucfg_cm_roam_full_scan_6ghz_on_disc(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, + uint8_t param_value) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + return cm_roam_full_scan_6ghz_on_disc(psoc, vdev_id, param_value); +} +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +QDF_STATUS +ucfg_cm_roam_send_vendor_handoff_param_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t param_id, + void *vendor_handoff_context) +{ + return cm_roam_send_vendor_handoff_param_req(psoc, vdev_id, param_id, + vendor_handoff_context); +} + +bool +ucfg_cm_roam_is_vendor_handoff_control_enable(struct wlan_objmgr_psoc *psoc) +{ + return cm_roam_is_vendor_handoff_control_enable(psoc); +} + +#endif +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +QDF_STATUS +ucfg_cm_get_roam_intra_band(struct wlan_objmgr_psoc *psoc, uint16_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.lfr.roam_intra_band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_cm_get_roam_rescan_rssi_diff(struct wlan_objmgr_psoc *psoc, uint8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.lfr.roam_rescan_rssi_diff; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_cm_get_neighbor_lookup_rssi_threshold(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t *lookup_threshold) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, NEXT_RSSI_THRESHOLD, &temp); + *lookup_threshold = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_cm_get_empty_scan_refresh_period(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint16_t *refresh_threshold) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + EMPTY_SCAN_REFRESH_PERIOD, &temp); + *refresh_threshold = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +uint16_t +ucfg_cm_get_neighbor_scan_min_chan_time(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + SCAN_MIN_CHAN_TIME, &temp); + + return temp.uint_value; +} + +QDF_STATUS +ucfg_cm_get_roam_rssi_diff(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t *rssi_diff) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + ROAM_RSSI_DIFF, &temp); + *rssi_diff = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +bool ucfg_cm_get_is_ese_feature_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.lfr.ese_enabled; +} +#endif + +uint16_t +ucfg_cm_get_neighbor_scan_max_chan_time(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + SCAN_MAX_CHAN_TIME, &temp); + + return temp.uint_value; +} + +uint16_t +ucfg_cm_get_neighbor_scan_period(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, + NEIGHBOR_SCAN_PERIOD, &temp); + return temp.uint_value; +} + +bool ucfg_cm_get_wes_mode(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.lfr.wes_mode_enabled; +} + +bool ucfg_cm_get_is_lfr_feature_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.lfr.lfr_enabled; +} + +bool ucfg_cm_get_is_ft_feature_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return false; + + return mlme_obj->cfg.lfr.fast_transition_enabled; +} + +QDF_STATUS +ucfg_cm_get_roam_scan_home_away_time(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint16_t *roam_scan_home_away_time) +{ + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(psoc, vdev_id, SCAN_HOME_AWAY, &temp); + + *roam_scan_home_away_time = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_cm_get_roam_opportunistic_scan_threshold_diff( + struct wlan_objmgr_psoc *psoc, + int8_t *val) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *val = mlme_obj->cfg.lfr.opportunistic_scan_threshold_diff; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_cm_get_neighbor_scan_refresh_period(struct wlan_objmgr_psoc *psoc, + uint16_t *value) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *value = mlme_obj->cfg.lfr.neighbor_scan_results_refresh_period; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_cm_get_empty_scan_refresh_period_global(struct wlan_objmgr_psoc *psoc, + uint16_t *roam_scan_period_global) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + *roam_scan_period_global = + mlme_obj->cfg.lfr.empty_scan_refresh_period; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c new file mode 100644 index 0000000000..3212c986a1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c @@ -0,0 +1,804 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_cm_tgt_if_tx_api.c + * + * Implementation for the Common Roaming interfaces. + */ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_reg_services_api.h" +#include "wlan_cm_tgt_if_tx_api.h" +#include "wlan_mlme_public_struct.h" +#include "wma.h" + +static inline +struct wlan_cm_roam_tx_ops *wlan_cm_roam_get_tx_ops_from_vdev( + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlme_psoc_ext_obj *psoc_ext_priv; + struct wlan_cm_roam_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_legacy_err("psoc object is NULL"); + return NULL; + } + psoc_ext_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!psoc_ext_priv) { + mlme_legacy_err("psoc legacy private object is NULL"); + return NULL; + } + + tx_ops = &psoc_ext_priv->rso_tx_ops; + + return tx_ops; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +wlan_cm_roam_send_set_vdev_pcl(struct wlan_objmgr_psoc *psoc, + struct set_pcl_req *pcl_req) +{ + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct fw_scan_channels *freq_list; + struct wlan_objmgr_vdev *vdev; + struct wmi_pcl_chan_weights *weights; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t band_capability; + uint16_t i; + bool is_channel_allowed; + + /* + * If vdev_id is WLAN_UMAC_VDEV_ID_MAX, then PDEV pcl command + * needs to be sent + */ + if (!pcl_req || pcl_req->vdev_id == WLAN_UMAC_VDEV_ID_MAX) + return QDF_STATUS_E_FAILURE; + + status = ucfg_mlme_get_band_capability(psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + mlme_debug("RSO_CFG: band_capability:%d band_mask:%d for vdev[%d]", + band_capability, pcl_req->band_mask, pcl_req->vdev_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, pcl_req->vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + status = QDF_STATUS_E_FAILURE; + return status; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + mlme_err("pdev object is NULL"); + status = QDF_STATUS_E_FAILURE; + return status; + } + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_vdev_set_pcl_cmd) { + mlme_err("send_vdev_set_pcl_cmd is NULL"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + freq_list = qdf_mem_malloc(sizeof(*freq_list)); + if (!freq_list) { + status = QDF_STATUS_E_FAILURE; + goto end; + } + + mlme_get_fw_scan_channels(psoc, freq_list->freq, + &freq_list->num_channels); + + weights = &pcl_req->chan_weights; + for (i = 0; i < freq_list->num_channels; i++) + weights->saved_chan_list[i] = freq_list->freq[i]; + + weights->saved_num_chan = freq_list->num_channels; + if (pcl_req->clear_vdev_pcl) + weights->saved_num_chan = 0; + + status = policy_mgr_get_valid_chan_weights( + psoc, (struct policy_mgr_pcl_chan_weights *)weights, + PM_STA_MODE, vdev); + + qdf_mem_free(freq_list); + + for (i = 0; i < weights->saved_num_chan; i++) { + weights->weighed_valid_list[i] = + wma_map_pcl_weights(weights->weighed_valid_list[i]); + + /* Dont allow roaming on 2G when 5G_ONLY configured */ + if ((band_capability == BIT(REG_BAND_5G) || + band_capability == BIT(REG_BAND_6G) || + pcl_req->band_mask == BIT(REG_BAND_5G) || + pcl_req->band_mask == BIT(REG_BAND_6G)) && + WLAN_REG_IS_24GHZ_CH_FREQ(weights->saved_chan_list[i])) + weights->weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + + if ((band_capability == BIT(REG_BAND_2G) || + pcl_req->band_mask == BIT(REG_BAND_2G)) && + !WLAN_REG_IS_24GHZ_CH_FREQ(weights->saved_chan_list[i])) + weights->weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + + is_channel_allowed = + policy_mgr_is_sta_chan_valid_for_connect_and_roam( + pdev, weights->saved_chan_list[i]); + if (!is_channel_allowed) + weights->weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + } + + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Error in creating weighed pcl"); + goto end; + } + + mlme_debug("RSO_CFG: Dump Vdev PCL weights for vdev[%d]", + pcl_req->vdev_id); + policy_mgr_dump_channel_list(weights->saved_num_chan, + weights->saved_chan_list, + weights->weighed_valid_list); + + status = roam_tx_ops->send_vdev_set_pcl_cmd(vdev, pcl_req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("set vdev PCL failed"); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_rt_stats_config(struct wlan_objmgr_psoc *psoc, + struct roam_disable_cfg *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_rt_stats_config) { + mlme_err("vdev %d send_roam_rt_stats_config is NULL", + req->vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_rt_stats_config(vdev, + req->vdev_id, req->cfg); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to send roam rt stats config", + req->vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_ho_delay_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint16_t roam_ho_delay) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_ho_delay_config) { + mlme_err("vdev %d send_roam_ho_delay_config is NULL", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_ho_delay_config(vdev, vdev_id, + roam_ho_delay); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to send roam HO delay config", + vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS +wlan_cm_tgt_exclude_rm_partial_scan_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t exclude_rm_partial_scan_freq) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_exclude_rm_partial_scan_freq) { + mlme_err("vdev %d send_exclude_rm_partial_scan_freq is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_exclude_rm_partial_scan_freq( + vdev, exclude_rm_partial_scan_freq); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to exclude roam partial scan freq", + vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_full_scan_6ghz_on_disc( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t roam_full_scan_6ghz_on_disc) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_full_scan_6ghz_on_disc) { + mlme_err("vdev %d send_roam_full_scan_6ghz_on_disc is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_full_scan_6ghz_on_disc( + vdev, roam_full_scan_6ghz_on_disc); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to send inclusion of 6 GHz channels", + vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +QDF_STATUS wlan_cm_tgt_send_roam_linkspeed_state(struct wlan_objmgr_psoc *psoc, + struct roam_disable_cfg *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_linkspeed_state) { + mlme_err("vdev %d send_roam_linkspeed_state is NULL", + req->vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_linkspeed_state(vdev, + req->vdev_id, req->cfg); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to send roam linkspeed state", + req->vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} +#endif + +QDF_STATUS +wlan_cm_tgt_send_roam_scan_offload_rssi_params( + struct wlan_objmgr_vdev *vdev, + struct wlan_roam_offload_scan_rssi_params *roam_rssi_params) +{ + QDF_STATUS status; + uint8_t vdev_id; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + + vdev_id = wlan_vdev_get_id(vdev); + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_scan_offload_rssi_params) { + mlme_err("vdev %d send_roam_scan_offload_rssi_params is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_scan_offload_rssi_params( + vdev, roam_rssi_params); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to send roam scan offload RSSI params", + vdev_id); + + return status; +} +#endif + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +QDF_STATUS +wlan_cm_tgt_send_roam_vendor_handoff_config(struct wlan_objmgr_psoc *psoc, + struct vendor_handoff_cfg *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, req->vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_vendor_handoff_config) { + mlme_err("vdev %d send_roam_vendor_handoff_config is NULL", + req->vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_vendor_handoff_config(vdev, + req->vdev_id, + req->param_id); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("vdev %d fail to send roam vendor handoff config", + req->vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS wlan_cm_tgt_send_roam_offload_init(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool is_init) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + struct wlan_roam_offload_init_params init_msg = {0}; + uint32_t disable_4way_hs_offload; + bool bmiss_skip_full_scan; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_offload_init_req) { + mlme_err("CM_RSO: vdev%d send_roam_offload_init_req is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + init_msg.vdev_id = vdev_id; + if (is_init) { + init_msg.roam_offload_flag = WLAN_ROAM_FW_OFFLOAD_ENABLE | + WLAN_ROAM_BMISS_FINAL_SCAN_ENABLE; + + wlan_mlme_get_4way_hs_offload(psoc, &disable_4way_hs_offload); + if (!disable_4way_hs_offload) + init_msg.roam_offload_flag |= + WLAN_ROAM_SKIP_SAE_ROAM_4WAY_HANDSHAKE; + if (disable_4way_hs_offload & + CFG_DISABLE_4WAY_HS_OFFLOAD_DEFAULT) + init_msg.roam_offload_flag |= + (WLAN_ROAM_SKIP_EAPOL_4WAY_HANDSHAKE | + WLAN_ROAM_SKIP_SAE_ROAM_4WAY_HANDSHAKE); + + wlan_mlme_get_bmiss_skip_full_scan_value(psoc, + &bmiss_skip_full_scan); + if (bmiss_skip_full_scan) + init_msg.roam_offload_flag |= + WLAN_ROAM_BMISS_FINAL_SCAN_TYPE; + } + mlme_debug("vdev_id:%d, is_init:%d, flag:%d", vdev_id, is_init, + init_msg.roam_offload_flag); + + status = roam_tx_ops->send_roam_offload_init_req(vdev, &init_msg); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev%d fail to send rso init", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_start_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_start_config *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_start_req) { + mlme_err("CM_RSO: vdev %d send_roam_start_req is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_start_req(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roam start", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_stop_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_stop_config *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_stop_offload) { + mlme_err("CM_RSO: vdev %d send_roam_stop_offload is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_stop_offload(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roam stop", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_update_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_update_config *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_update_config) { + mlme_err("CM_RSO: vdev %d send_roam_update_config is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_update_config(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roam update", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS +wlan_cm_tgt_send_roam_freqs(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_scan_channel_list *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_frequencies) { + mlme_err("CM_RSO: vdev %d send_roam_frequencies is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_frequencies(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roam freqs", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_abort_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_abort) { + mlme_err("CM_RSO: vdev %d send_roam_abort is NULL", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_abort(vdev, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roam abort", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_per_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_per_roam_config_req *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_per_config) { + mlme_err("CM_RSO: vdev %d send_roam_per_config is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_per_config(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send per config", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS wlan_cm_tgt_send_roam_triggers(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_triggers *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_triggers) { + mlme_err("CM_RSO: vdev %d send_roam_triggers is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_triggers(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roamtrigger", vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS wlan_cm_tgt_send_roam_mlo_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_roam_mlo_config *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_mlo_config) { + mlme_err("CM_RSO: vdev %d send_roam_mlo_config is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_mlo_config(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("CM_RSO: vdev %d fail to send roam mlo config", + vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} +#endif + +QDF_STATUS wlan_cm_tgt_send_roam_disable_config(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct roam_disable_cfg *req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + if (!roam_tx_ops || !roam_tx_ops->send_roam_disable_config) { + mlme_err("CM_RSO: vdev %d send_roam_disable_config is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_disable_config(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("CM_RSO: vdev %d fail to send roam disable config", + vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS +wlan_cm_tgt_send_roam_invoke_req(struct wlan_objmgr_psoc *psoc, + struct roam_invoke_req *roam_invoke_req) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + roam_invoke_req->vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + + if (!roam_tx_ops || !roam_tx_ops->send_roam_invoke_cmd) { + mlme_err("CM_RSO: vdev %d send_roam_invoke_cmd is NULL", + roam_invoke_req->vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_invoke_cmd(vdev, roam_invoke_req); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("CM_RSO: vdev %d fail to send roam invoke cmd", + roam_invoke_req->vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} + +QDF_STATUS +wlan_cm_tgt_send_roam_sync_complete_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct wlan_cm_roam_tx_ops *roam_tx_ops; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + roam_tx_ops = wlan_cm_roam_get_tx_ops_from_vdev(vdev); + + if (!roam_tx_ops || !roam_tx_ops->send_roam_sync_complete_cmd) { + mlme_err("CM_RSO: vdev %d send_roam_sync_complete_cmd is NULL", + vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_INVAL; + } + + status = roam_tx_ops->send_roam_sync_complete_cmd(vdev); + if (QDF_IS_STATUS_ERROR(status)) + mlme_debug("CM_RSO: vdev %d fail to send roam sync complete cmd", + vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/utf/inc/cm_utf.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/utf/inc/cm_utf.h new file mode 100644 index 0000000000..a641f9ae8c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/utf/inc/cm_utf.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: Implements CM UTF related functionalities + */ + +#ifndef WLAN_MLME_CM_UTF_H +#define WLAN_MLME_CM_UTF_H + +#include +#include + +#ifdef FEATURE_CM_UTF_ENABLE +void cm_utf_set_mlme_ops(struct mlme_ext_ops *ext_ops); + +QDF_STATUS cm_utf_register_os_if_cb(void); + +void cm_utf_attach(struct wlan_objmgr_vdev *vdev); + +void cm_utf_detach(struct wlan_objmgr_vdev *vdev); +#else +static inline void cm_utf_set_mlme_ops(struct mlme_ext_ops *ext_ops) +{ +} + +static inline QDF_STATUS cm_utf_register_os_if_cb(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void cm_utf_attach(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void cm_utf_detach(struct wlan_objmgr_vdev *vdev) +{ +} +#endif +#endif //WLAN_MLME_CM_UTF_H diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/utf/src/cm_utf.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/utf/src/cm_utf.c new file mode 100644 index 0000000000..3ba30bed22 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/connection_mgr/utf/src/cm_utf.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: Implements CM UTF + */ + +#ifdef FEATURE_CM_UTF_ENABLE +#include +#include +#include + +void cm_utf_set_mlme_ops(struct mlme_ext_ops *ext_ops) +{ + ext_ops->mlme_cm_ext_connect_start_ind_cb = NULL; + ext_ops->mlme_cm_ext_bss_select_ind_cb = NULL; + ext_ops->mlme_cm_ext_bss_peer_create_req_cb = + wlan_cm_utf_bss_peer_create_req; + ext_ops->mlme_cm_ext_connect_req_cb = wlan_cm_utf_connect_req; + ext_ops->mlme_cm_ext_connect_complete_ind_cb = NULL; + ext_ops->mlme_cm_ext_disconnect_start_ind_cb = NULL; + ext_ops->mlme_cm_ext_disconnect_req_cb = wlan_cm_utf_disconnect_req; + ext_ops->mlme_cm_ext_bss_peer_delete_req_cb = + wlan_cm_utf_bss_peer_delete_req; + ext_ops->mlme_cm_ext_disconnect_complete_ind_cb = NULL; + ext_ops->mlme_cm_ext_vdev_down_req_cb = wlan_cm_utf_vdev_down; +} + +QDF_STATUS cm_utf_register_os_if_cb(void) +{ + return osif_cm_utf_register_cb(); +} + +void cm_utf_attach(struct wlan_objmgr_vdev *vdev) +{ + if (QDF_IS_STATUS_ERROR(wlan_cm_utf_attach(vdev))) + mlme_err("utf attach failed"); + else + mlme_debug("utf attach success"); +} + +void cm_utf_detach(struct wlan_objmgr_vdev *vdev) +{ + wlan_cm_utf_detach(vdev); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/dispatcher/inc/wlan_mlo_epcs_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/dispatcher/inc/wlan_mlo_epcs_ucfg_api.h new file mode 100644 index 0000000000..7167cd99aa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/dispatcher/inc/wlan_mlo_epcs_ucfg_api.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_mlo_epcs_ucfg_api.h + * + * Implementation for mlo epcs public ucfg API interfaces. + */ + +#ifndef _WLAN_MLO_EPCS_UCFG_API_H_ +#define _WLAN_MLO_EPCS_UCFG_API_H_ + +#include "wlan_epcs_api.h" + +/** + * ucfg_epcs_deliver_cmd() - Handler to deliver EPCS command + * @vdev: vdev pointer + * @event: EPCS event + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, + enum wlan_epcs_evt event); + +/** + * ucfg_epcs_set_config() - Set EPCS enable/disable config + * @vdev: vdev pointer + * @flag: EPCS flag + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_epcs_set_config(struct wlan_objmgr_vdev *vdev, uint8_t flag); + +#endif /* _WLAN_MLO_EPCS_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/dispatcher/src/wlan_mlo_epcs_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/dispatcher/src/wlan_mlo_epcs_ucfg_api.c new file mode 100644 index 0000000000..f2521723b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/dispatcher/src/wlan_mlo_epcs_ucfg_api.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_mlo_epcs_ucfg_api.c + * + * Implementation for mlo epcs public ucfg API interfaces. + */ +#include "wlan_epcs_api.h" +#include "wlan_mlo_epcs_ucfg_api.h" + +QDF_STATUS ucfg_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, + enum wlan_epcs_evt event) +{ + return wlan_epcs_deliver_cmd(vdev, event); +} + +QDF_STATUS ucfg_epcs_set_config(struct wlan_objmgr_vdev *vdev, uint8_t flag) +{ + return wlan_epcs_set_config(vdev, flag); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_epcs_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_epcs_api.h new file mode 100644 index 0000000000..b76a769cb9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_epcs_api.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains EPCS (Emergency Preparedness Communications Service) + * related functionality + */ +#ifndef _WLAN_EPCS_API_H_ +#define _WLAN_EPCS_API_H_ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_send_messages.h" + +#define RSVD_SHIFT_BIT 0x7 +#define ACI_SHIFT_BIT 0x5 +#define ACM_SHIFT_BIT 0x4 +#define AIFSN_SHIFT_BIT 0x0 +#define CWMAX_SHIFT_BIT 0x4 +#define CWMIN_SHIFT_BIT 0x0 + +#define RSVD_MASK 0x1 +#define ACI_MASK 0x3 +#define ACM_MASK 0x1 +#define AIFSN_MASK 0xf +#define CWMAX_MASK 0xf +#define CWMIN_MASK 0xf + +#define WMM_VENDOR_HEADER_LEN 7 + +/** + * enum wlan_epcs_evt: EPCS manager events + * @WLAN_EPCS_EV_ACTION_FRAME_RX_REQ:Handle EPCS request frame received from AP + * @WLAN_EPCS_EV_ACTION_FRAME_TX_RESP:Handle EPCS response frame sent to AP + * @WLAN_EPCS_EV_ACTION_FRAME_TX_REQ:Handle EPCS request frame sent by STA + * @WLAN_EPCS_EV_ACTION_FRAME_RX_RESP:Handle EPCS response frame received from AP + * @WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN:Handle received teardown frame event + * @WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN:Handle sending teardown frame event + * @WLAN_EPCS_EV_ACTION_FRAME_MAX: Maximum EPCS action frame event value + */ +enum wlan_epcs_evt { + WLAN_EPCS_EV_ACTION_FRAME_RX_REQ = 0, + WLAN_EPCS_EV_ACTION_FRAME_TX_RESP = 1, + WLAN_EPCS_EV_ACTION_FRAME_TX_REQ = 2, + WLAN_EPCS_EV_ACTION_FRAME_RX_RESP = 3, + WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN = 4, + WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN = 5, + WLAN_EPCS_EV_ACTION_FRAME_MAX = 6, +}; + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_epcs_deliver_event() - Handler to deliver EPCS event + * @vdev: vdev pointer + * @peer: pointer to peer + * @event: EPCS event + * @event_data: EPCS event data pointer + * @len: length of data + * + * This api will be called from lim layers, to process EPCS event + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_epcs_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_epcs_evt event, + void *event_data, uint32_t len); + +/** + * wlan_epcs_set_config() - Set EPCS enable flag + * @vdev: vdev pointer + * @flag: EPCS flag + * + * This api will be called from os_if layers, to set EPCS flag + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_epcs_set_config(struct wlan_objmgr_vdev *vdev, + uint8_t flag); + +/** + * wlan_epcs_get_config() - Get EPCS config + * @vdev: vdev pointer + * + * This api will be called from other module + * + * Return: bool + */ +bool wlan_epcs_get_config(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_epcs_deliver_cmd() - Handler to deliver EPCS command + * @vdev: vdev pointer + * @event: EPCS event + * + * This api will be called from os_if layers, to process EPCS command + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, + enum wlan_epcs_evt event); +#else +static inline +QDF_STATUS wlan_epcs_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_epcs_evt event, + void *event_data, uint32_t len) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_epcs_set_config(struct wlan_objmgr_vdev *vdev, uint8_t flag) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool wlan_epcs_get_config(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline +QDF_STATUS wlan_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, + enum wlan_epcs_evt event) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h new file mode 100644 index 0000000000..c20f862229 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_mlo_link_force.h @@ -0,0 +1,476 @@ +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains ML STA link force active/inactive public API + */ +#ifndef _WLAN_MLO_LINK_FORCE_H_ +#define _WLAN_MLO_LINK_FORCE_H_ + +#include +#include +#include + +/** + * enum ml_nlink_change_event_type - Ml link state change trigger event + * @ml_nlink_link_switch_start_evt: link switch start + * @ml_nlink_link_switch_pre_completion_evt: link switch pre-completion + * @ml_nlink_roam_sync_start_evt: roam sync start + * @ml_nlink_roam_sync_completion_evt: roam sync completion + * @ml_nlink_connect_start_evt: STA/CLI connect start + * @ml_nlink_connect_completion_evt: STA/CLI connect completion + * @ml_nlink_disconnect_start_evt: STA/CLI disconnect start + * @ml_nlink_disconnect_completion_evt: STA/CLI disconnect completion + * @ml_nlink_ap_started_evt: SAP/GO bss started + * @ml_nlink_ap_stopped_evt: SAP/GO bss stopped + * @ml_nlink_connection_updated_evt: connection home channel changed + * @ml_nlink_tdls_request_evt: tdls request link enable/disable + * @ml_nlink_vendor_cmd_request_evt: vendor command request + */ +enum ml_nlink_change_event_type { + ml_nlink_link_switch_start_evt, + ml_nlink_link_switch_pre_completion_evt, + ml_nlink_roam_sync_start_evt, + ml_nlink_roam_sync_completion_evt, + ml_nlink_connect_start_evt, + ml_nlink_connect_completion_evt, + ml_nlink_disconnect_start_evt, + ml_nlink_disconnect_completion_evt, + ml_nlink_ap_started_evt, + ml_nlink_ap_stopped_evt, + ml_nlink_connection_updated_evt, + ml_nlink_tdls_request_evt, + ml_nlink_vendor_cmd_request_evt, +}; + +/** + * enum link_control_modes - the types of MLO links state + * control modes. This enum is internal mapping of + * qca_wlan_vendor_link_state_control_modes. + * @LINK_CONTROL_MODE_DEFAULT: MLO links state controlled + * by the driver. + * @LINK_CONTROL_MODE_USER: MLO links state controlled by + * user space. + * @LINK_CONTROL_MODE_MIXED: User space provides the + * desired number of MLO links to operate in active state at any given time. + * The driver will choose which MLO links should operate in the active state. + * See enum qca_wlan_vendor_link_state for active state definition. + */ +enum link_control_modes { + LINK_CONTROL_MODE_DEFAULT = 0, + LINK_CONTROL_MODE_USER = 1, + LINK_CONTROL_MODE_MIXED = 2, +}; + +/** + * struct ml_nlink_change_event - connection change event data struct + * @evt: event parameters + * @link_switch: link switch start parameters + * @tdls: tdls parameters + * @vendor: vendor command set link parameters + */ +struct ml_nlink_change_event { + union { + struct { + uint8_t curr_ieee_link_id; + uint8_t new_ieee_link_id; + uint32_t new_primary_freq; + enum wlan_mlo_link_switch_reason reason; + } link_switch; + struct { + uint32_t link_bitmap; + uint8_t vdev_count; + uint8_t mlo_vdev_lst[WLAN_UMAC_MLO_MAX_VDEVS]; + enum mlo_link_force_mode mode; + enum mlo_link_force_reason reason; + } tdls; + struct { + enum link_control_modes link_ctrl_mode; + uint8_t link_num; + uint32_t link_bitmap; + uint32_t link_bitmap2; + enum mlo_link_force_mode mode; + enum mlo_link_force_reason reason; + } vendor; + } evt; +}; + +#ifdef WLAN_FEATURE_11BE_MLO +static inline const char *force_mode_to_string(uint32_t mode) +{ + switch (mode) { + CASE_RETURN_STRING(MLO_LINK_FORCE_MODE_ACTIVE); + CASE_RETURN_STRING(MLO_LINK_FORCE_MODE_INACTIVE); + CASE_RETURN_STRING(MLO_LINK_FORCE_MODE_ACTIVE_NUM); + CASE_RETURN_STRING(MLO_LINK_FORCE_MODE_INACTIVE_NUM); + CASE_RETURN_STRING(MLO_LINK_FORCE_MODE_NO_FORCE); + CASE_RETURN_STRING(MLO_LINK_FORCE_MODE_ACTIVE_INACTIVE); + default: + return "Unknown"; + } +}; + +#define ml_nlink_dump_force_state(_force_state, format, args...) \ + mlo_debug("inactive 0x%x active 0x%x inact num %d 0x%x act num %d 0x%x dyn 0x%x"format, \ + (_force_state)->force_inactive_bitmap, \ + (_force_state)->force_active_bitmap, \ + (_force_state)->force_inactive_num, \ + (_force_state)->force_inactive_num_bitmap, \ + (_force_state)->force_active_num, \ + (_force_state)->force_active_num_bitmap, \ + (_force_state)->curr_dynamic_inactive_bitmap, \ + ##args); + +static inline const char *link_evt_to_string(uint32_t evt) +{ + switch (evt) { + CASE_RETURN_STRING(ml_nlink_link_switch_start_evt); + CASE_RETURN_STRING(ml_nlink_link_switch_pre_completion_evt); + CASE_RETURN_STRING(ml_nlink_roam_sync_start_evt); + CASE_RETURN_STRING(ml_nlink_roam_sync_completion_evt); + CASE_RETURN_STRING(ml_nlink_connect_start_evt); + CASE_RETURN_STRING(ml_nlink_connect_completion_evt); + CASE_RETURN_STRING(ml_nlink_disconnect_start_evt); + CASE_RETURN_STRING(ml_nlink_disconnect_completion_evt); + CASE_RETURN_STRING(ml_nlink_ap_started_evt); + CASE_RETURN_STRING(ml_nlink_ap_stopped_evt); + CASE_RETURN_STRING(ml_nlink_connection_updated_evt); + CASE_RETURN_STRING(ml_nlink_tdls_request_evt); + CASE_RETURN_STRING(ml_nlink_vendor_cmd_request_evt); + default: + return "Unknown"; + } +}; + +/** + * ml_nlink_conn_change_notify() - Notify connection state + * change to force link module + * @psoc: pointer to pdev + * @vdev_id: vdev id + * @evt: event type + * @data: event data + * + * Return: QDF_STATUS_SUCCESS in the case of success + */ +QDF_STATUS +ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data); + +#define MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT (sizeof(uint32_t) * 8) + +/** + * ml_nlink_convert_linkid_bitmap_to_vdev_bitmap() - convert link + * id bitmap to vdev id bitmap + * state + * @psoc: psoc object + * @vdev: vdev object + * @link_bitmap: link id bitmap + * @associated_bitmap: all associated the link id bitmap + * @vdev_id_bitmap_sz: number vdev id bitamp in vdev_id_bitmap + * @vdev_id_bitmap: array to return the vdev id bitmaps + * @vdev_id_num: total vdev id number in vdev_ids + * @vdev_ids: vdev id array + * + * Return: None + */ +void +ml_nlink_convert_linkid_bitmap_to_vdev_bitmap( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t link_bitmap, + uint32_t *associated_bitmap, + uint32_t *vdev_id_bitmap_sz, + uint32_t vdev_id_bitmap[MLO_VDEV_BITMAP_SZ], + uint8_t *vdev_id_num, + uint8_t vdev_ids[WLAN_MLO_MAX_VDEVS]); + +/** + * ml_nlink_convert_vdev_bitmap_to_linkid_bitmap() - convert vdev + * id bitmap to link id bitmap + * state + * @psoc: psoc object + * @vdev: vdev object + * @vdev_id_bitmap_sz: array size of vdev_id_bitmap + * @vdev_id_bitmap: vdev bitmap array + * @link_bitmap: link id bitamp converted from vdev id bitmap + * @associated_bitmap: all associated the link id bitmap + * + * Return: None + */ +void +ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t vdev_id_bitmap_sz, + uint32_t *vdev_id_bitmap, + uint32_t *link_bitmap, + uint32_t *associated_bitmap); + +/** + * convert_link_bitmap_to_link_ids() - Convert link bitmap to link ids + * @link_bitmap: PSOC object information + * @link_id_sz: link_ids array size + * @link_ids: link id array + * + * Return: num of link id in link_ids array converted from link bitmap + */ +uint32_t +convert_link_bitmap_to_link_ids(uint32_t link_bitmap, + uint8_t link_id_sz, + uint8_t *link_ids); + +/** + * ml_nlink_convert_link_bitmap_to_ids() - convert link bitmap + * to link ids + * @link_bitmap: link bitmap + * @link_id_sz: array size of link_ids + * @link_ids: link id array + * + * Return: number of link ids + */ +uint32_t +ml_nlink_convert_link_bitmap_to_ids(uint32_t link_bitmap, + uint8_t link_id_sz, + uint8_t *link_ids); + +/** + * enum set_curr_control - control flag to update current force bitmap + * @LINK_OVERWRITE: use bitmap to overwrite existing force bitmap + * @LINK_CLR: clr the input bitmap from existing force bitmap + * @LINK_ADD: append the input bitmap to existing force bitamp + * + * This control value will be used in ml_nlink_set_* API to indicate + * how to update input link_bitmap to current bitmap + */ +enum set_curr_control { + LINK_OVERWRITE = 0x0, + LINK_CLR = 0x1, + LINK_ADD = 0x2, +}; + +/** + * ml_nlink_set_curr_force_active_state() - set link force active + * state + * @psoc: psoc object + * @vdev: vdev object + * @link_bitmap: force active link id bitmap + * @ctrl: control value to indicate how to update link_bitmap to current + * bitmap + * + * Return: None + */ +void +ml_nlink_set_curr_force_active_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t link_bitmap, + enum set_curr_control ctrl); + +/** + * ml_nlink_set_curr_force_inactive_state() - set link force inactive + * state + * @psoc: psoc object + * @vdev: vdev object + * @link_bitmap: force inactive link id bitmap + * @ctrl: control value to indicate how to update link_bitmap to current + * bitmap + * + * Return: None + */ +void +ml_nlink_set_curr_force_inactive_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t link_bitmap, + enum set_curr_control ctrl); + +/** + * ml_nlink_set_curr_force_active_num_state() - set link force active + * number state + * @psoc: psoc object + * @vdev: vdev object + * @link_num: force active num + * @link_bitmap: force active num link id bitmap + * + * Return: None + */ +void +ml_nlink_set_curr_force_active_num_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t link_num, + uint16_t link_bitmap); + +/** + * ml_nlink_set_curr_force_inactive_num_state() - set link force inactive + * number state + * @psoc: psoc object + * @vdev: vdev object + * @link_num: force inactive num + * @link_bitmap: force inactive num link id bitmap + * + * Return: None + */ +void +ml_nlink_set_curr_force_inactive_num_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t link_num, + uint16_t link_bitmap); + +/** + * ml_nlink_set_dynamic_inactive_links() - set link dynamic inactive + * link bitmap + * @psoc: psoc object + * @vdev: vdev object + * @dynamic_link_bitmap: dynamic inactive bitmap + * + * Return: None + */ +void +ml_nlink_set_dynamic_inactive_links(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t dynamic_link_bitmap); + +/** + * ml_nlink_get_dynamic_inactive_links() - get link dynamic inactive + * link bitmap + * @psoc: psoc object + * @vdev: vdev object + * @dynamic_link_bitmap: dynamic inactive bitmap + * @force_link_bitmap: forced inactive bitmap + * + * Return: None + */ +void +ml_nlink_get_dynamic_inactive_links(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t *dynamic_link_bitmap, + uint16_t *force_link_bitmap); + +/** + * ml_nlink_init_concurrency_link_request() - Init concurrency force + * link request + * link bitmap + * @psoc: psoc object + * @vdev: vdev object + * + * When ML STA associated or Roam, initialize the concurrency + * force link request based on "current" force link state + * + * Return: None + */ +void ml_nlink_init_concurrency_link_request( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * ml_nlink_get_force_link_request() - get link request of source + * link bitmap + * @psoc: psoc object + * @vdev: vdev object + * @req: set link request + * @source: the source to query + * + * Return: None + */ +void +ml_nlink_get_force_link_request(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct set_link_req *req, + enum set_link_source source); + +/** + * ml_nlink_get_curr_force_state() - get link force state + * @psoc: psoc object + * @vdev: vdev object + * @force_cmd: current force state + * + * Return: None + */ +void +ml_nlink_get_curr_force_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd); + +/** + * ml_nlink_clr_force_state() - clear all link force state + * @psoc: psoc object + * @vdev: vdev object + * + * Return: None + */ +void +ml_nlink_clr_force_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * ml_nlink_vendor_command_set_link() - Update vendor command + * set link parameters + * @psoc: psoc object + * @vdev_id: vdev id + * @link_control_mode: link control mode: default, user, mix + * @reason: reason to set + * @mode: mode to set + * @link_num: number of link, valid for mode: + * @link_bitmap: link bitmap, valid for mode: + * @link_bitmap2: inactive link bitmap, only valid for mode + * + * Return: void + */ +void +ml_nlink_vendor_command_set_link(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum link_control_modes link_control_mode, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t link_num, + uint16_t link_bitmap, + uint16_t link_bitmap2); + +/** + * ml_is_nlink_service_supported() - support nlink or not + * @psoc: psoc object + * + * Return: true if supported + */ +bool ml_is_nlink_service_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ml_nlink_get_standby_link_bitmap() - Get standby link info + * @psoc: psoc + * @vdev: vdev object + * + * Return: standby link bitmap + */ +uint32_t +ml_nlink_get_standby_link_bitmap(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +ml_is_nlink_service_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h new file mode 100644 index 0000000000..9ac66f187e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_mlo_mgr_roam.h @@ -0,0 +1,703 @@ +/* + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains MLO manager public file containing roaming functionality + */ +#ifndef _WLAN_MLO_MGR_ROAM_H_ +#define _WLAN_MLO_MGR_ROAM_H_ + +#include +#include +#include +#include <../../core/src/wlan_cm_roam_i.h> + +#ifdef WLAN_FEATURE_11BE_MLO + +/** + * mlo_fw_roam_sync_req - Handler for roam sync event handling + * + * @psoc: psoc pointer + * @vdev_id: vdev id + * @event: event ptr + * @event_data_len: event data len + * + * This api will be called from target_if layer to mlo mgr, + * handles mlo roaming and posts roam sync propagation to + * connection manager state machine. + * + * Return: qdf status + */ +QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, void *event, + uint32_t event_data_len); + +/** + * mlo_fw_ho_fail_req - Handler for HO fail event handling + * + * @psoc: psoc pointer + * @vdev_id: vdev id + * @bssid: bssid mac addr + * + * This api will be called from target_if layer to mlo mgr, + * handles mlo ho fail req and posts to connection manager + * state machine. + * + * Return: void + */ +void +mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct qdf_mac_addr bssid); + +/** + * mlo_get_sta_link_mac_addr - get sta link mac addr + * + * @vdev_id: vdev id + * @sync_ind: roam sync ind pointer + * @link_mac_addr: link mac addr pointer + * + * This api will be called to get the link specific mac address. + * + * Return: qdf status + */ +QDF_STATUS +mlo_get_sta_link_mac_addr(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + struct qdf_mac_addr *link_mac_addr); + +/** + * mlo_roam_get_chan_freq - get channel frequency + * + * @vdev_id: vdev id + * @sync_ind: roam sync ind pointer + * + * This api will be called to get the link channel frequency. + * + * Return: channel frequency + */ +uint32_t +mlo_roam_get_chan_freq(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind); + +/** + * mlo_roam_get_link_freq_from_mac_addr - get given link frequency + * @sync_ind: roam sync ind pointer + * @link_mac_addr: Link mac address + * + * This api will be called to get the link frequency. + * + * Return: channel frequency + */ +uint32_t +mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind, + uint8_t *link_mac_addr); + +/** + * mlo_roam_get_link_id_from_mac_addr - get link id of given link addr + * @sync_ind: roam sync ind pointer + * @link_mac_addr: Link mac address + * @link_id: Buffer to fill link corresponds to link mac address + * + * This api will be called to get the link id + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind, + uint8_t *link_mac_addr, uint32_t *link_id); +/** + * mlo_roam_get_link_id - get link id + * + * @vdev_id: vdev id + * @sync_ind: roam sync ind pointer + * + * This api will be called to get the link id information. + * + * Return: link id + */ +uint32_t +mlo_roam_get_link_id(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind); + +/** + * is_multi_link_roam - check if MLO roaming + * + * @sync_ind: roam sync ind pointer + * + * This api will be called to check if MLO roaming. + * + * Return: true/false + */ +bool +is_multi_link_roam(struct roam_offload_synch_ind *sync_ind); + +/** + * mlo_roam_get_num_of_setup_links - get number of setup links + * @sync_ind: roam sync ind pointer + * + * This api will be called to get number of setup links after roaming + * + * Return: true/false + */ +uint8_t +mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind); + +/** + * mlo_enable_rso - Enable rso on assoc vdev + * + * @pdev: pdev pointer + * @vdev: assoc vdev pointer + * @rsp: cm connect rsp + * + * This api will be called to enable RSO for MLO connection. + * + * Return: qdf_status success or fail + */ +QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); + +/** + * mlo_roam_copy_partner_info - copy partner link info to connect response + * + * @partner_info: Destination buffer to fill partner info from roam sync ind + * @sync_ind: roam sync ind pointer + * @skip_vdev_id: Skip to copy the link info corresponds to this vdev_id + * @fill_all_links: Fill all the links for connect response to userspace + * + * This api will be called to copy partner link info to connect response. + * + * Return: none + */ +void mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info, + struct roam_offload_synch_ind *sync_ind, + uint8_t skip_vdev_id, bool fill_all_links); + +/** + * mlo_roam_init_cu_bpcc() - init cu bpcc per roam sync data + * @vdev: vdev object + * @sync_ind: roam sync ind pointer + * + * This api will be called to init cu bpcc from connect response. + * + * Return: none + */ +void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind); + +/** + * mlo_roam_update_connected_links - update connected links bitmap after roaming + * + * @vdev: vdev pointer + * @connect_rsp: connect resp structure pointer + * + * This api will be called to copy partner link info to connect response. + * + * Return: none + */ +void mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *connect_rsp); + +/** + * mlo_set_single_link_ml_roaming - set single link mlo roaming + * + * @psoc: psoc pointer + * @vdev_id: vdev id + * @is_single_link_ml_roaming: boolean flag + * + * This api will be called to set single link mlo roaming flag. + * + * Return: none + */ +void +mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_single_link_ml_roaming); + +/** + * mlo_get_single_link_ml_roaming - check if single link mlo roaming + * + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This api will be called to check if single link mlo roaming is true or false. + * + * Return: boolean value + */ +bool +mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlo_roam_get_bssid_chan_for_link - get link mac addr and channel info + * + * @vdev_id: vdev id + * @sync_ind: roam sync ind pointer + * @bssid: link mac addr pointer + * @chan: link wmi channel pointer + * + * This api will be called to get link mac addr and channel info. + * + * Return: qdf status + */ +QDF_STATUS +mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + struct qdf_mac_addr *bssid, + wmi_channel *chan); + +/** + * mlo_get_link_mac_addr_from_reassoc_rsp - get link mac addr from reassoc rsp + * @vdev: vdev pointer + * @link_mac_addr: link mac address + * + * This api will be called to get link mac addr from stored reassoc rsp + * after roaming and vdev id. + * + * Return: qdf status + */ +QDF_STATUS +mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *link_mac_addr); + +/** + * mlo_roam_copy_reassoc_rsp - Copy cm vdev join rsp + * + * @vdev: vdev pointer + * @reassoc_rsp: cm vdev reassoc rsp pointer + * + * This api will be called to copy cm vdev reassoc rsp which will + * be used to later bring up link vdev/s. + * + * Return: qdf_status success or fail + */ +QDF_STATUS +mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *reassoc_rsp); + +/** + * mlo_roam_link_connect_notify - Send connect req + * on link + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This api will be called to send connect req for link vdev. + * + * Return: qdf_status success or fail + */ +QDF_STATUS +mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlo_roam_is_auth_status_connected - api to check roam auth status + * on link + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This api will be called to check if roam auth status is connected + * + * Return: boolean true or false + */ +bool +mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlo_roam_connect_complete - roam connect complete api + * @vdev: vdev pointer + * + * This api will be called after connect complete for roam 1x case. + * + * Return: none + */ +void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev); + +/** + * mlo_roam_free_copied_reassoc_rsp - roam free copied reassoc rsp + * @vdev: vdev pointer + * + * This api will be called to free copied reassoc rsp. + * + * Return: none + */ +void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * mlo_mgr_roam_update_ap_link_info() - Update AP links information + * @vdev: Object Manager vdev + * @src_link_info: Source link setup information + * @channel: Channel information + * + * Update AP link information for each link of AP MLD + * + * Return: None + */ +void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev, + struct ml_setup_link_param *src_link_info, + struct wlan_channel *channel); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * mlo_mgr_num_roam_links() - Get number of roaming links + * @vdev: VDEV object manager pointer + * + * Returns the num of links device roamed via FW roam sync event, + * for non-MLO VDEV the number of links is one. + */ +uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev); +#else +static inline uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} +#endif + +/** + * mlo_cm_roam_sync_cb - Callback function from CM to MLO mgr + * + * @vdev: vdev pointer + * @event: event ptr + * @event_data_len: event data len + * + * This api will be called from connection manager to mlo + * manager to start roam sync request on link vdev's. + * + * Return: qdf status + */ +QDF_STATUS +mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev, + void *event, uint32_t event_data_len); +#endif /* WLAN_FEATURE_11BE_MLO_ADV_FEATURE */ + +/** + * wlan_mlo_roam_abort_on_link - Abort roam on link + * + * @psoc: psoc pointer + * @event: Roam sync indication event pointer + * @vdev_id: vdev id value + * + * Abort roaming on all the links except the vdev id passed. + * Roam abort on vdev id link would be taken care in legacy path. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc, + uint8_t *event, uint8_t vdev_id); + +/** + * mlo_check_if_all_links_up - Check if all links are up + * @vdev: vdev pointer + * + * This api will check if all the requested links are in CM connected + * state. + * + * Return: bool, true: all links of mld connected + */ +bool +mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev); + +/** + * mlo_check_if_all_vdev_up - Check if all vdev are up + * @vdev: vdev pointer + * + * This api will check if all the requested vdev are in up + * state. + * + * Return: bool, true: all assoc/link vdevs of mld in UP state + */ +bool +mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev); + +/** + * mlo_roam_set_link_id - set link id post roaming + * + * @vdev: vdev pointer + * @sync_ind: roam sync indication pointer + * + * This api will be called to set link id post roaming + * + * Return: none + */ +void +mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind); + +/** + * mlo_is_roaming_in_progress - check if roaming is in progress + * @psoc: psoc pointer + * @vdev_id: vdev id + * + * This api will be called to check if roaming in progress on any + * of the mlo links. + * + * Return: boolean (true or false) + */ +bool +mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * mlo_add_all_link_probe_rsp_to_scan_db - Extract and add all ML link probe + * rsps to scan db + * @psoc: psoc pointer + * @rcvd_frame: Received frame from firmware + * + * This api will be called to generate ML probe responses corresponds to each + * link from the received probe response and add them to scan db + * + * Return: QDF_STATUS + */ +QDF_STATUS +mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *rcvd_frame); + +/** + * mlo_is_enable_roaming_on_connected_sta_allowed() - whether connected STA is + * allowed to enable roaming if link vdev disconnects + * @vdev: vdev object + * + * Return: true if connected STA is allowed to enable roaming, false otherwise. + */ +bool +mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev); + +/** + * mlo_check_is_given_vdevs_on_same_mld() - check if the 2 given vdev's are on + * same MLD + * @psoc: PSOC object + * @vdev_id_1: Current connected station vdev id on which roaming is to be + * enabled + * @vdev_id_2: vdev id on which disconnection is happening + * + * Return: true if both vdev ids are on same MLD, false otherwise. + */ +bool +mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id_1, uint8_t vdev_id_2); +#else /* WLAN_FEATURE_11BE_MLO */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline +QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, void *event, + uint32_t event_data_len) +{ + return cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len); +} +#endif +static inline QDF_STATUS +mlo_get_sta_link_mac_addr(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + struct qdf_mac_addr *link_mac_addr) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline uint32_t +mlo_roam_get_chan_freq(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + return 0; +} + +static inline uint32_t +mlo_roam_get_link_id(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + return 0; +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * mlo_cm_roam_sync_cb() - MLO callback to handle roam synch event + * for MLO vdev + * @vdev: Pointer to objmgr vdev + * @event: Pointer to event + * @event_data_len: event data length + */ +QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev, + void *event, uint32_t event_data_len); +#else +static inline QDF_STATUS +mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev, + void *event, uint32_t event_data_len) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static inline bool +is_multi_link_roam(struct roam_offload_synch_ind *sync_ind) +{ + return false; +} + +static inline uint8_t +mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind) +{ + return 0; +} + +static inline +QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info, + struct roam_offload_synch_ind *sync_ind, + uint8_t skip_vdev_id, bool fill_all_links) +{} + +static inline +void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind) +{} + +static inline void +mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *connect_rsp) +{} + +static inline QDF_STATUS +wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc, + uint8_t *event, uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_single_link_ml_roaming) +{} + +static inline bool +mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline QDF_STATUS +mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + struct qdf_mac_addr *bssid, + wmi_channel *chan) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline bool +mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline void +mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind) +{} + +static inline QDF_STATUS +mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *reassoc_rsp) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline void +mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev) +{} + +static inline void +mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev) +{} + +static inline QDF_STATUS +mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *link_mac_addr) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev, + struct ml_setup_link_param *src_info, + struct wlan_channel *channel) +{} + +static inline uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev) +{ + return 1; +} + +static inline uint32_t +mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind, + uint8_t *link_mac_addr) +{ + if (sync_ind) + return sync_ind->chan_freq; + + return 0; +} + +static inline bool +mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} + +static inline bool +mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev) +{ + return true; +} + +static inline bool +mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id_1, uint8_t vdev_id_2) +{ + return false; +} + +#endif /* WLAN_FEATURE_11BE_MLO */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h new file mode 100644 index 0000000000..87bbe0399e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/inc/wlan_t2lm_api.h @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains TID to Link mapping related functionality + */ +#ifndef _WLAN_T2LM_API_H_ +#define _WLAN_T2LM_API_H_ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_send_messages.h" + +/* T2LM IE Length = + * Size of header (2 bytes) + + * Length (1 bytes) + t2lm mapping control (2 bytes) + + * mapping switch time (2 bytes) + expected duration (3 bytes) + + * link mapping of tids (16 bytes) + */ +#define T2LM_IE_ACTION_FRAME_MAX_LEN 26 + +/** + * struct t2lm_event_data - TID to Link mapping event data + * @status: qdf status used to indicate if t2lm action frame status + * @data: event data + */ +struct t2lm_event_data { + QDF_STATUS status; + void *data; +}; + +/** + * enum wlan_t2lm_evt: T2LM manager events + * @WLAN_T2LM_EV_ACTION_FRAME_RX_REQ:Handle T2LM request frame received from AP + * @WLAN_T2LM_EV_ACTION_FRAME_TX_RESP:Handle T2LM response frame sent to AP + * @WLAN_T2LM_EV_ACTION_FRAME_TX_REQ:Handle T2LM request frame sent by STA + * @WLAN_T2LM_EV_ACTION_FRAME_RX_RESP:Handle T2LM response frame received from AP + * @WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN:Handle received teardown frame event + * @WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN:Handle sending teardown frame event + * @WLAN_T2LM_EV_ACTION_FRAME_MAX: Maximum T2LM action frame event value + */ +enum wlan_t2lm_evt { + WLAN_T2LM_EV_ACTION_FRAME_RX_REQ = 0, + WLAN_T2LM_EV_ACTION_FRAME_TX_RESP = 1, + WLAN_T2LM_EV_ACTION_FRAME_TX_REQ = 2, + WLAN_T2LM_EV_ACTION_FRAME_RX_RESP = 3, + WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN = 4, + WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN = 5, + WLAN_T2LM_EV_ACTION_FRAME_MAX = 6, +}; + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * t2lm_deliver_event - Handler to deliver T2LM event + * @vdev: vdev pointer + * @peer: pointer to peer + * @event: T2LM event + * @event_data: T2LM event data pointer + * @frame_len: Received T2LM Frame length + * @dialog_token: Dialog token + * + * This api will be called from lim layers, to process T2LM event + * + * Return: qdf_status + */ +QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_t2lm_evt event, + void *event_data, + uint32_t frame_len, + uint8_t *dialog_token); + +/** + * t2lm_handle_rx_req - Handler for parsing T2LM action frame + * @vdev: vdev pointer + * @peer: pointer to peer + * @event_data: T2LM event data pointer + * @frame_len: Received Frame length + * @token: Dialog token + * + * This api will be called from lim layers, after T2LM action frame + * is received, the api will parse the T2LM request frame. + * + * Return: qdf_status + */ +QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t frame_len, + uint8_t *token); + +/** + * t2lm_handle_tx_resp - Handler for populating T2LM action frame + * @vdev: vdev pointer + * @event_data: T2LM event data pointer + * @token: Dialog token + * + * This api will be called to populate T2LM response action frame. + * + * Return: qdf_status + */ +QDF_STATUS t2lm_handle_tx_resp(struct wlan_objmgr_vdev *vdev, + void *event_data, uint8_t *token); + +/** + * t2lm_handle_tx_req - Handler for populating T2LM action frame + * @vdev: vdev pointer + * @peer: pointer to peer + * @event_data: T2LM event data pointer + * @token: Dialog token + * + * This api will be called to populate T2LM request action frame. + * + * Return: qdf_status + */ +QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint8_t *token); + +/** + * t2lm_handle_rx_resp - Handler for parsing T2LM action frame + * @vdev: vdev pointer + * @peer: peer pointer + * @event_data: T2LM event data pointer + * @frame_len: Frame length + * @token: Dialog token + * + * This api will be called to parsing T2LM response action frame. + * + * Return: qdf_status + */ +QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t frame_len, + uint8_t *token); + +/** + * t2lm_handle_rx_teardown - Handler for parsing T2LM action frame + * @vdev: vdev pointer + * @peer: peer pointer + * @event_data: T2LM event data pointer + * + * This api will be called to parsing T2LM teardown action frame. + * + * Return: qdf_status + */ +QDF_STATUS t2lm_handle_rx_teardown(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data); + +/** + * t2lm_handle_tx_teardown - Handler for populating T2LM action frame + * @vdev: vdev pointer + * @event_data: T2LM event data pointer + * + * This api will be called to populate T2LM teardown action frame. + * + * Return: qdf_status + */ +QDF_STATUS t2lm_handle_tx_teardown(struct wlan_objmgr_vdev *vdev, + void *event_data); + +/** + * wlan_t2lm_validate_candidate - Validate candidate based on T2LM IE + * @cm_ctx: connection manager context pointer + * @scan_entry: scan entry pointer + * + * This api will be called to validate candidate based on T2LM IE received + * in beacon or probe response + * + * Return: qdf_status + */ + +QDF_STATUS +wlan_t2lm_validate_candidate(struct cnx_mgr *cm_ctx, + struct scan_cache_entry *scan_entry); +/** + * wlan_t2lm_deliver_event() - TID-to-link-mapping event handler + * @vdev: vdev object + * @peer: pointer to peer + * @event: T2LM event + * @event_data: T2LM event data + * @frame_len: received T2LM frame len + * @dialog_token: Dialog token + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_t2lm_evt event, + void *event_data, + uint32_t frame_len, + uint8_t *dialog_token); + +/** + * wlan_t2lm_clear_ongoing_negotiation - Clear ongoing + * negotiation peer level TID-to-link-mapping. + * @peer: pointer to peer + * + * Return: none + */ +void +wlan_t2lm_clear_ongoing_negotiation(struct wlan_objmgr_peer *peer); + +/** + * wlan_t2lm_clear_peer_negotiation - Clear previously + * negotiated peer level TID-to-link-mapping. + * @peer: pointer to peer + * + * Return: none + */ +void +wlan_t2lm_clear_peer_negotiation(struct wlan_objmgr_peer *peer); + +/** + * wlan_t2lm_clear_all_tid_mapping - Clear all tid mapping + * @vdev: pointer to vdev + * + * This api will clear peer level and beacon t2lm mapping. + * Return: none + */ +void +wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_populate_link_disable_t2lm_frame - Populate link disable t2lm frame + * @vdev: pointer to vdev + * @params: link disable params + * + * Return: none + */ +QDF_STATUS +wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev, + struct mlo_link_disable_request_evt_params *params); + +/** + * wlan_update_t2lm_mapping - Update t2lm mapping to fw + * @vdev: pointer to vdev + * @rx_t2lm: received t2lm mapping from beacon + * @tsf: timing sync function value + * + * Return: qdf status + */ +QDF_STATUS wlan_update_t2lm_mapping( + struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_context *rx_t2lm, + uint64_t tsf); + +/** + * wlan_t2lm_init_default_mapping - Initialize t2lm to default mapping + * @t2lm_ctx: t2lm ctx stored in ml dev ctx + * + * Return: qdf status + */ +QDF_STATUS +wlan_t2lm_init_default_mapping(struct wlan_t2lm_context *t2lm_ctx); + +#else +static inline QDF_STATUS +wlan_t2lm_init_default_mapping(struct wlan_t2lm_context *t2lm_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS wlan_update_t2lm_mapping( + struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_context *rx_t2lm, + uint64_t tsf) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev, + struct mlo_link_disable_request_evt_params *params) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t frame_len, uint8_t *token) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +t2lm_handle_tx_resp(struct wlan_objmgr_vdev *vdev, + void *event_data, uint8_t *token) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint8_t *token) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t frame_len, uint8_t *token) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +t2lm_handle_rx_teardown(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +t2lm_handle_tx_teardown(struct wlan_objmgr_vdev *vdev, + void *event_data) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_t2lm_validate_candidate(struct cnx_mgr *cm_ctx, + struct scan_cache_entry *scan_entry) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void +wlan_t2lm_clear_ongoing_negotiation(struct wlan_objmgr_peer *peer) +{} + +static inline void +wlan_t2lm_clear_peer_negotiation(struct wlan_objmgr_peer *peer) +{} + +static inline void +wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev) +{} + +static inline +QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_t2lm_evt event, + void *event_data, + uint32_t frame_len, + uint8_t *dialog_token) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_epcs_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_epcs_api.c new file mode 100644 index 0000000000..6ea32353c7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_epcs_api.c @@ -0,0 +1,688 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains EPCS (Emergency Preparedness Communications Service) + * related functionality + */ +#include +#include +#include "wlan_epcs_api.h" +#include +#include "wlan_cm_api.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_cmn_ieee80211.h" +#include "dot11f.h" + +#define EPCS_MIN_DIALOG_TOKEN 1 +#define EPCS_MAX_DIALOG_TOKEN 0xFF + +static struct ac_param_record default_epcs_edca[] = { +#ifndef ANI_LITTLE_BIT_ENDIAN + /* The txop is multiple of 32us units */ + {0x07, 0x95, 79 /* 2.528ms */}, + {0x03, 0x95, 79 /* 2.528ms */}, + {0x02, 0x54, 128 /* 4.096ms */}, + {0x02, 0x43, 65 /* 2.080ms */} +#else + {0x70, 0x59, 79 /* 2.528ms */}, + {0x30, 0x59, 79 /* 2.528ms */}, + {0x20, 0x45, 128 /* 4.096ms */}, + {0x20, 0x34, 65 /* 2.080ms */} +#endif +}; + +static +const char *epcs_get_event_str(enum wlan_epcs_evt event) +{ + if (event > WLAN_EPCS_EV_ACTION_FRAME_MAX) + return ""; + + switch (event) { + CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_REQ); + CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_RESP); + CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_REQ); + CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_RESP); + CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN); + CASE_RETURN_STRING(WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN); + default: + return "Unknown"; + } +} + +static uint8_t +epcs_gen_dialog_token(struct wlan_mlo_peer_epcs_info *epcs_info) +{ + if (!epcs_info) + return 0; + + if (epcs_info->self_gen_dialog_token == EPCS_MAX_DIALOG_TOKEN) + /* wrap is ok */ + epcs_info->self_gen_dialog_token = EPCS_MIN_DIALOG_TOKEN; + else + epcs_info->self_gen_dialog_token += 1; + + mlme_debug("gen dialog token %d", epcs_info->self_gen_dialog_token); + return epcs_info->self_gen_dialog_token; +} + +static void epcs_update_ac_value(tSirMacEdcaParamRecord *edca, + struct ac_param_record *epcs) +{ + edca->aci.rsvd = epcs->aci_aifsn >> RSVD_SHIFT_BIT & RSVD_MASK; + edca->aci.aci = epcs->aci_aifsn >> ACI_SHIFT_BIT & ACI_MASK; + edca->aci.acm = epcs->aci_aifsn >> ACM_SHIFT_BIT & ACM_MASK; + edca->aci.aifsn = epcs->aci_aifsn >> AIFSN_SHIFT_BIT & AIFSN_MASK; + + edca->cw.max = epcs->ecw_min_max >> CWMAX_SHIFT_BIT & CWMAX_MASK; + edca->cw.min = epcs->ecw_min_max >> CWMIN_SHIFT_BIT & CWMIN_MASK; + + edca->txoplimit = epcs->txop_limit; + mlme_debug("edca rsvd %d, aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", + edca->aci.rsvd, edca->aci.aci, edca->aci.acm, + edca->aci.aifsn, edca->cw.max, edca->cw.min); +} + +static void epcs_update_mu_ac_value(tSirMacEdcaParamRecord *edca, + struct muac_param_record *epcs) +{ + edca->aci.rsvd = epcs->aci_aifsn >> RSVD_SHIFT_BIT & RSVD_MASK; + edca->aci.aci = epcs->aci_aifsn >> ACI_SHIFT_BIT & ACI_MASK; + edca->aci.acm = epcs->aci_aifsn >> ACM_SHIFT_BIT & ACM_MASK; + edca->aci.aifsn = epcs->aci_aifsn >> AIFSN_SHIFT_BIT & AIFSN_MASK; + + edca->cw.max = epcs->ecw_min_max >> CWMAX_SHIFT_BIT & CWMAX_MASK; + edca->cw.min = epcs->ecw_min_max >> CWMIN_SHIFT_BIT & CWMIN_MASK; + + edca->txoplimit = epcs->mu_edca_timer; + mlme_debug("muac rsvd %d, aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", + edca->aci.rsvd, edca->aci.aci, edca->aci.acm, + edca->aci.aifsn, edca->cw.max, edca->cw.min); +} + +static QDF_STATUS +epcs_update_def_edca_param(struct wlan_objmgr_vdev *vdev) +{ + int i; + struct mac_context *mac_ctx; + tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + epcs_update_ac_value(&edca[i], &default_epcs_edca[i]); + edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i]; + } + + mlme_debug("using default edca info"); + return lim_send_epcs_update_edca_params(vdev, edca, false); +} + +static QDF_STATUS +epcs_update_edca_param(struct wlan_objmgr_vdev *vdev, + struct edca_ie *edca_ie) +{ + struct mac_context *mac_ctx; + struct ac_param_record *ac_record; + tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; + int i; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + if (edca_ie->ie != DOT11F_EID_EDCAPARAMSET || + edca_ie->len != DOT11F_IE_EDCAPARAMSET_MIN_LEN) { + mlme_debug("edca info is not valid or not exist"); + return QDF_STATUS_E_INVAL; + } + + ac_record = edca_ie->ac_record; + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + epcs_update_ac_value(&edca[i], &ac_record[i]); + edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i]; + } + + return lim_send_epcs_update_edca_params(vdev, edca, false); +} + +static QDF_STATUS +epcs_update_ven_wmm_param(struct wlan_objmgr_vdev *vdev, uint8_t *ven_wme_ie) +{ + struct mac_context *mac_ctx; + tDot11fIEWMMParams wmm_para = {0}; + tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; + uint32_t status; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + status = dot11f_unpack_ie_wmm_params(mac_ctx, + ven_wme_ie + WMM_VENDOR_HEADER_LEN, + DOT11F_IE_WMMPARAMS_MIN_LEN, + &wmm_para, false); + if (status != DOT11F_PARSE_SUCCESS) { + mlme_debug("EPCS parsing wmm ie error"); + return QDF_STATUS_E_INVAL; + } + + edca[QCA_WLAN_AC_BE].aci.rsvd = wmm_para.unused1; + edca[QCA_WLAN_AC_BE].aci.aci = wmm_para.acbe_aci; + edca[QCA_WLAN_AC_BE].aci.acm = wmm_para.acbe_acm; + edca[QCA_WLAN_AC_BE].aci.aifsn = wmm_para.acbe_aifsn; + edca[QCA_WLAN_AC_BE].cw.max = wmm_para.acbe_acwmax; + edca[QCA_WLAN_AC_BE].cw.min = wmm_para.acbe_acwmin; + edca[QCA_WLAN_AC_BE].txoplimit = wmm_para.acbe_txoplimit; + edca[QCA_WLAN_AC_BE].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BE]; + mlme_debug("WMM BE aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", + edca[QCA_WLAN_AC_BE].aci.aci, + edca[QCA_WLAN_AC_BE].aci.acm, + edca[QCA_WLAN_AC_BE].aci.aifsn, + edca[QCA_WLAN_AC_BE].cw.max, + edca[QCA_WLAN_AC_BE].cw.min); + + edca[QCA_WLAN_AC_BK].aci.rsvd = wmm_para.unused2; + edca[QCA_WLAN_AC_BK].aci.aci = wmm_para.acbk_aci; + edca[QCA_WLAN_AC_BK].aci.acm = wmm_para.acbk_acm; + edca[QCA_WLAN_AC_BK].aci.aifsn = wmm_para.acbk_aifsn; + edca[QCA_WLAN_AC_BK].cw.max = wmm_para.acbk_acwmax; + edca[QCA_WLAN_AC_BK].cw.min = wmm_para.acbk_acwmin; + edca[QCA_WLAN_AC_BK].txoplimit = wmm_para.acbk_txoplimit; + edca[QCA_WLAN_AC_BK].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BK]; + mlme_debug("WMM BK aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", + edca[QCA_WLAN_AC_BK].aci.aci, + edca[QCA_WLAN_AC_BK].aci.acm, + edca[QCA_WLAN_AC_BK].aci.aifsn, + edca[QCA_WLAN_AC_BK].cw.max, + edca[QCA_WLAN_AC_BK].cw.min); + + edca[QCA_WLAN_AC_VI].aci.rsvd = wmm_para.unused3; + edca[QCA_WLAN_AC_VI].aci.aci = wmm_para.acvi_aci; + edca[QCA_WLAN_AC_VI].aci.acm = wmm_para.acvi_acm; + edca[QCA_WLAN_AC_VI].aci.aifsn = wmm_para.acvi_aifsn; + edca[QCA_WLAN_AC_VI].cw.max = wmm_para.acvi_acwmax; + edca[QCA_WLAN_AC_VI].cw.min = wmm_para.acvi_acwmin; + edca[QCA_WLAN_AC_VI].txoplimit = wmm_para.acvi_txoplimit; + edca[QCA_WLAN_AC_VI].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VI]; + mlme_debug("WMM VI aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", + edca[QCA_WLAN_AC_VI].aci.aci, + edca[QCA_WLAN_AC_VI].aci.acm, + edca[QCA_WLAN_AC_VI].aci.aifsn, + edca[QCA_WLAN_AC_VI].cw.max, + edca[QCA_WLAN_AC_VI].cw.min); + + edca[QCA_WLAN_AC_VO].aci.rsvd = wmm_para.unused4; + edca[QCA_WLAN_AC_VO].aci.aci = wmm_para.acvo_aci; + edca[QCA_WLAN_AC_VO].aci.acm = wmm_para.acvo_acm; + edca[QCA_WLAN_AC_VO].aci.aifsn = wmm_para.acvo_aifsn; + edca[QCA_WLAN_AC_VO].cw.max = wmm_para.acvo_acwmax; + edca[QCA_WLAN_AC_VO].cw.min = wmm_para.acvo_acwmin; + edca[QCA_WLAN_AC_VO].txoplimit = wmm_para.acvo_txoplimit; + edca[QCA_WLAN_AC_VO].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VO]; + mlme_debug("WMM VO aci %d, acm %d, aifsn %d, cwmax %d, cwmin %d", + edca[QCA_WLAN_AC_VO].aci.aci, + edca[QCA_WLAN_AC_VO].aci.acm, + edca[QCA_WLAN_AC_VO].aci.aifsn, + edca[QCA_WLAN_AC_VO].cw.max, + edca[QCA_WLAN_AC_VO].cw.min); + + return lim_send_epcs_update_edca_params(vdev, edca, false); +} + +static QDF_STATUS +epcs_update_mu_edca_param(struct wlan_objmgr_vdev *vdev, + struct muedca_ie *muedca) +{ + struct mac_context *mac_ctx; + struct muac_param_record *mu_record; + tSirMacEdcaParamRecord edca[QCA_WLAN_AC_ALL] = {0}; + int i; + + if (muedca->elem_id != DOT11F_EID_MU_EDCA_PARAM_SET || + muedca->elem_len != (DOT11F_IE_MU_EDCA_PARAM_SET_MIN_LEN + 1)) { + mlme_debug("mu edca info for epcs is not valid or not exist"); + return QDF_STATUS_SUCCESS; + } + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + mu_record = muedca->mu_record; + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + epcs_update_mu_ac_value(&edca[i], &mu_record[i]); + edca[i].no_ack = mac_ctx->no_ack_policy_cfg[i]; + } + + return lim_send_epcs_update_edca_params(vdev, edca, true); +} + +static QDF_STATUS +epcs_restore_edca_param(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_vdev *link_vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + int i; + + if (!vdev) + return QDF_STATUS_E_INVAL; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) + return QDF_STATUS_E_INVAL; + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + link_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!link_vdev) + continue; + lim_send_epcs_restore_edca_params(link_vdev); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS epcs_handle_rx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t len) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_mlo_peer_epcs_info *epcs_info; + struct wlan_epcs_info epcs_req = {0}; + struct wlan_action_frame_args args; + struct ml_pa_info *edca_info; + struct ml_pa_partner_link_info *link; + struct wlan_objmgr_vdev *link_vdev; + uint32_t i; + QDF_STATUS status; + + if (!vdev || !peer) + return QDF_STATUS_E_INVAL; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) + return QDF_STATUS_E_FAILURE; + + epcs_info = &ml_peer->epcs_info; + if (epcs_info->state == EPCS_ENABLE) { + mlme_err("EPCS has been enable, ignore the req."); + return QDF_STATUS_E_ALREADY; + } + + status = wlan_mlo_parse_epcs_action_frame(&epcs_req, event_data, len); + if (status != QDF_STATUS_SUCCESS) { + mlme_err("Unable to parse EPCS request action frame"); + return QDF_STATUS_E_FAILURE; + } + + epcs_info->self_gen_dialog_token = epcs_req.dialog_token; + edca_info = &epcs_req.pa_info; + for (i = 0; i < edca_info->num_links; i++) { + link = &edca_info->link_info[i]; + link_vdev = mlo_get_vdev_by_link_id(vdev, link->link_id, + WLAN_MLO_MGR_ID); + if (!link_vdev) + continue; + + if (link->edca_ie_present) + epcs_update_edca_param(link_vdev, &link->edca); + else if (link->ven_wme_ie_present) + epcs_update_ven_wmm_param(link_vdev, + &link->ven_wme_ie_bytes[0]); + else + epcs_update_def_edca_param(link_vdev); + + if (link->muedca_ie_present) + epcs_update_mu_edca_param(link_vdev, &link->muedca); + + wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLO_MGR_ID); + } + + args.category = ACTION_CATEGORY_PROTECTED_EHT; + args.action = EHT_EPCS_RESPONSE; + args.arg1 = epcs_info->self_gen_dialog_token; + args.arg2 = QDF_STATUS_SUCCESS; + + status = lim_send_epcs_action_rsp_frame(vdev, + wlan_peer_get_macaddr(peer), + &args); + if (status != QDF_STATUS_SUCCESS) { + mlme_err("Send EPCS response frame error"); + epcs_restore_edca_param(vdev); + } else { + epcs_info->state = EPCS_ENABLE; + mlme_debug("EPCS (responder) state: Teardown -> Enable"); + } + + return status; +} + +static QDF_STATUS epcs_handle_rx_resp(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t len) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_mlo_peer_epcs_info *epcs_info; + struct wlan_epcs_info epcs_rsp = {0}; + struct ml_pa_info *edca_info; + struct ml_pa_partner_link_info *link; + struct wlan_objmgr_vdev *link_vdev; + uint32_t i; + QDF_STATUS status; + + if (!vdev || !peer) + return QDF_STATUS_E_NULL_VALUE; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) + return QDF_STATUS_E_NULL_VALUE; + + epcs_info = &ml_peer->epcs_info; + if (epcs_info->state == EPCS_ENABLE) { + mlme_err("EPCS has been enable, ignore the rsp."); + return QDF_STATUS_E_ALREADY; + } + + status = wlan_mlo_parse_epcs_action_frame(&epcs_rsp, event_data, len); + if (status != QDF_STATUS_SUCCESS) { + mlme_err("Unable to parse EPCS response action frame"); + return QDF_STATUS_E_FAILURE; + } + + if (epcs_info->self_gen_dialog_token != epcs_rsp.dialog_token) { + mlme_err("epcs rsp dialog token %d does not match", + epcs_rsp.dialog_token); + return QDF_STATUS_E_FAILURE; + } + + if (epcs_rsp.status) { + mlme_err("epcs rsp status error %d", epcs_rsp.status); + return QDF_STATUS_E_FAILURE; + } + + edca_info = &epcs_rsp.pa_info; + for (i = 0; i < edca_info->num_links; i++) { + link = &edca_info->link_info[i]; + link_vdev = mlo_get_vdev_by_link_id(vdev, link->link_id, + WLAN_MLO_MGR_ID); + if (!link_vdev) + continue; + + if (link->edca_ie_present) + epcs_update_edca_param(link_vdev, &link->edca); + else if (link->ven_wme_ie_present) + epcs_update_ven_wmm_param(link_vdev, + &link->ven_wme_ie_bytes[0]); + else + epcs_update_def_edca_param(link_vdev); + + if (link->muedca_ie_present) + epcs_update_mu_edca_param(link_vdev, &link->muedca); + + wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLO_MGR_ID); + } + + epcs_info->state = EPCS_ENABLE; + mlme_debug("EPCS (initiator) state: Teardown -> Enable"); + + return status; +} + +static QDF_STATUS epcs_handle_rx_teardown(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t len) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_mlo_peer_epcs_info *epcs_info; + struct wlan_epcs_info epcs_req = {0}; + struct mac_context *mac_ctx; + QDF_STATUS status; + + if (!vdev || !peer) + return QDF_STATUS_E_INVAL; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) + return QDF_STATUS_E_FAILURE; + + epcs_info = &ml_peer->epcs_info; + if (epcs_info->state == EPCS_DOWN) { + mlme_err("EPCS has been down, ignore the teardown req."); + return QDF_STATUS_E_ALREADY; + } + + status = wlan_mlo_parse_epcs_action_frame(&epcs_req, event_data, len); + if (status != QDF_STATUS_SUCCESS) { + mlme_err("Unable to parse EPCS teardown action frame"); + return QDF_STATUS_E_FAILURE; + } + + epcs_restore_edca_param(vdev); + + epcs_info->state = EPCS_DOWN; + mlme_debug("EPCS state: Enale -> Teardown."); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS epcs_handle_tx_req(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_objmgr_peer *peer; + struct wlan_action_frame_args args; + struct wlan_mlo_peer_epcs_info *epcs_info; + QDF_STATUS status; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID); + if (!peer) + return QDF_STATUS_E_NULL_VALUE; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) { + status = QDF_STATUS_E_NULL_VALUE; + goto release_peer; + } + + epcs_info = &ml_peer->epcs_info; + if (epcs_info->state == EPCS_ENABLE) { + mlme_err("EPCS has been enable, ignore the req cmd."); + status = QDF_STATUS_E_ALREADY; + goto release_peer; + } + + args.category = ACTION_CATEGORY_PROTECTED_EHT; + args.action = EHT_EPCS_REQUEST; + args.arg1 = epcs_gen_dialog_token(epcs_info); + + status = lim_send_epcs_action_req_frame(vdev, + wlan_peer_get_macaddr(peer), + &args); + if (QDF_IS_STATUS_ERROR(status)) + mlme_err("Failed to send EPCS action request frame"); + +release_peer: + wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); + + return status; +} + +static QDF_STATUS epcs_handle_tx_teardown(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_objmgr_peer *peer; + struct wlan_action_frame_args args; + struct wlan_mlo_peer_epcs_info *epcs_info; + QDF_STATUS status; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_MLO_MGR_ID); + if (!peer) + return QDF_STATUS_E_NULL_VALUE; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) { + status = QDF_STATUS_E_NULL_VALUE; + goto release_peer; + } + + epcs_info = &ml_peer->epcs_info; + if (epcs_info->state == EPCS_DOWN) { + mlme_err("EPCS has been down, ignore the teardwon cmd."); + status = QDF_STATUS_E_ALREADY; + goto release_peer; + } + + args.category = ACTION_CATEGORY_PROTECTED_EHT; + args.action = EHT_EPCS_TEARDOWN; + + status = + lim_send_epcs_action_teardown_frame(vdev, + wlan_peer_get_macaddr(peer), + &args); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Failed to send EPCS tear down frame"); + } else { + epcs_restore_edca_param(vdev); + epcs_info->state = EPCS_DOWN; + mlme_debug("EPCS state: Enale -> Teardown."); + } + +release_peer: + wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); + + return status; +} + +static QDF_STATUS epcs_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_epcs_evt event, + void *event_data, uint32_t len) +{ + QDF_STATUS status; + + mlme_debug("EPCS event received: %s(%d)", + epcs_get_event_str(event), event); + + switch (event) { + case WLAN_EPCS_EV_ACTION_FRAME_RX_REQ: + status = epcs_handle_rx_req(vdev, peer, event_data, len); + break; + case WLAN_EPCS_EV_ACTION_FRAME_RX_RESP: + status = epcs_handle_rx_resp(vdev, peer, event_data, len); + break; + case WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN: + status = epcs_handle_rx_teardown(vdev, peer, event_data, len); + break; + default: + status = QDF_STATUS_E_FAILURE; + mlme_err("Unhandled EPCS event"); + } + + return status; +} + +QDF_STATUS wlan_epcs_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_epcs_evt event, + void *event_data, uint32_t len) +{ + return epcs_deliver_event(vdev, peer, event, event_data, len); +} + +static QDF_STATUS epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, + enum wlan_epcs_evt event) +{ + QDF_STATUS status; + + mlme_debug("EPCS cmd received: %s(%d)", + epcs_get_event_str(event), event); + + switch (event) { + case WLAN_EPCS_EV_ACTION_FRAME_TX_REQ: + status = epcs_handle_tx_req(vdev); + break; + case WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN: + status = epcs_handle_tx_teardown(vdev); + break; + default: + status = QDF_STATUS_E_FAILURE; + mlme_err("Unhandled EPCS cmd"); + } + + return status; +} + +QDF_STATUS wlan_epcs_deliver_cmd(struct wlan_objmgr_vdev *vdev, + enum wlan_epcs_evt event) +{ + if (!vdev) + return QDF_STATUS_E_FAILURE; + + if (!wlan_mlme_get_epcs_capability(wlan_vdev_get_psoc(vdev))) { + mlme_info("EPCS has been disabled"); + return QDF_STATUS_E_FAILURE; + } + + return epcs_deliver_cmd(vdev, event); +} + +QDF_STATUS wlan_epcs_set_config(struct wlan_objmgr_vdev *vdev, uint8_t flag) +{ + struct mac_context *mac_ctx; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + if (!vdev) + return QDF_STATUS_E_FAILURE; + + if (flag) + wlan_mlme_set_epcs_capability(wlan_vdev_get_psoc(vdev), true); + else + wlan_mlme_set_epcs_capability(wlan_vdev_get_psoc(vdev), false); + + return lim_send_eht_caps_ie(mac_ctx, QDF_STA_MODE, + wlan_vdev_get_id(vdev)); +} + +bool wlan_epcs_get_config(struct wlan_objmgr_vdev *vdev) +{ + bool epcs_flag; + + if (!vdev) + return false; + + epcs_flag = wlan_mlme_get_epcs_capability(wlan_vdev_get_psoc(vdev)); + mlme_debug("EPCS %s", epcs_flag ? "Enabled" : "Disabled"); + + return epcs_flag; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c new file mode 100644 index 0000000000..9fd3036890 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c @@ -0,0 +1,2443 @@ +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains ML STA link force active/inactive related functionality + */ +#include "wlan_mlo_link_force.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_mlme_main.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "target_if.h" + +void +ml_nlink_convert_linkid_bitmap_to_vdev_bitmap( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t link_bitmap, + uint32_t *associated_bitmap, + uint32_t *vdev_id_bitmap_sz, + uint32_t vdev_id_bitmap[MLO_VDEV_BITMAP_SZ], + uint8_t *vdev_id_num, + uint8_t vdev_ids[WLAN_MLO_MAX_VDEVS]) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + uint8_t i, j, bitmap_sz = 0, num_vdev = 0; + uint16_t link_id; + uint8_t vdev_id; + uint32_t associated_link_bitmap = 0; + uint8_t vdev_per_bitmap = MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT; + + *vdev_id_bitmap_sz = 0; + *vdev_id_num = 0; + qdf_mem_zero(vdev_id_bitmap, + sizeof(vdev_id_bitmap[0]) * MLO_VDEV_BITMAP_SZ); + qdf_mem_zero(vdev_ids, + sizeof(vdev_ids[0]) * WLAN_MLO_MAX_VDEVS); + if (associated_bitmap) + *associated_bitmap = 0; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + sta_ctx = mlo_dev_ctx->sta_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + /*todo: add standby link */ + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) { + mlo_debug("vdev %d is not connected", vdev_id); + continue; + } + + link_id = wlan_vdev_get_link_id( + mlo_dev_ctx->wlan_vdev_list[i]); + if (link_id >= MAX_MLO_LINK_ID) { + mlo_err("invalid link id %d", link_id); + continue; + } + associated_link_bitmap |= 1 << link_id; + /* If the link_id is not interested one which is specified + * in "link_bitmap", continue the search. + */ + if (!(link_bitmap & (1 << link_id))) + continue; + j = vdev_id / vdev_per_bitmap; + if (j >= MLO_VDEV_BITMAP_SZ) + break; + vdev_id_bitmap[j] |= 1 << (vdev_id % vdev_per_bitmap); + if (j + 1 > bitmap_sz) + bitmap_sz = j + 1; + + if (num_vdev >= WLAN_MLO_MAX_VDEVS) + break; + vdev_ids[num_vdev++] = vdev_id; + } + mlo_dev_lock_release(mlo_dev_ctx); + + *vdev_id_bitmap_sz = bitmap_sz; + *vdev_id_num = num_vdev; + if (associated_bitmap) + *associated_bitmap = associated_link_bitmap; + + mlo_debug("vdev %d link bitmap 0x%x vdev_bitmap 0x%x sz %d num %d assoc 0x%x for bitmap 0x%x", + wlan_vdev_get_id(vdev), link_bitmap & associated_link_bitmap, + vdev_id_bitmap[0], *vdev_id_bitmap_sz, num_vdev, + associated_link_bitmap, link_bitmap); +} + +void +ml_nlink_convert_vdev_bitmap_to_linkid_bitmap( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t vdev_id_bitmap_sz, + uint32_t *vdev_id_bitmap, + uint32_t *link_bitmap, + uint32_t *associated_bitmap) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + uint8_t i, j; + uint16_t link_id; + uint8_t vdev_id; + uint32_t associated_link_bitmap = 0; + uint8_t vdev_per_bitmap = MLO_MAX_VDEV_COUNT_PER_BIMTAP_ELEMENT; + + *link_bitmap = 0; + if (associated_bitmap) + *associated_bitmap = 0; + if (!vdev_id_bitmap_sz) { + mlo_debug("vdev_id_bitmap_sz 0"); + return; + } + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + sta_ctx = mlo_dev_ctx->sta_ctx; + mlo_dev_lock_acquire(mlo_dev_ctx); + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) { + mlo_debug("vdev %d is not connected", vdev_id); + continue; + } + + link_id = wlan_vdev_get_link_id( + mlo_dev_ctx->wlan_vdev_list[i]); + if (link_id >= MAX_MLO_LINK_ID) { + mlo_err("invalid link id %d", link_id); + continue; + } + associated_link_bitmap |= 1 << link_id; + j = vdev_id / vdev_per_bitmap; + if (j >= vdev_id_bitmap_sz) { + mlo_err("invalid vdev id %d", vdev_id); + continue; + } + /* If the vdev_id is not interested one which is specified + * in "vdev_id_bitmap", continue the search. + */ + if (!(vdev_id_bitmap[j] & (1 << (vdev_id % vdev_per_bitmap)))) + continue; + + *link_bitmap |= 1 << link_id; + } + mlo_dev_lock_release(mlo_dev_ctx); + + if (associated_bitmap) + *associated_bitmap = associated_link_bitmap; + mlo_debug("vdev %d link bitmap 0x%x vdev_bitmap 0x%x sz %d assoc 0x%x", + wlan_vdev_get_id(vdev), *link_bitmap, vdev_id_bitmap[0], + vdev_id_bitmap_sz, associated_link_bitmap); +} + +void +ml_nlink_get_curr_force_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + qdf_mem_copy(force_cmd, + &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state, + sizeof(*force_cmd)); + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_clr_force_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) + return; + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + qdf_mem_zero(force_state, sizeof(*force_state)); + ml_nlink_dump_force_state(force_state, ""); + qdf_mem_zero(mlo_dev_ctx->sta_ctx->link_force_ctx.reqs, + sizeof(mlo_dev_ctx->sta_ctx->link_force_ctx.reqs)); + mlo_dev_lock_release(mlo_dev_ctx); +} + +static void +ml_nlink_update_link_bitmap(uint16_t *curr_link_bitmap, + uint16_t link_bitmap, + enum set_curr_control ctrl) +{ + switch (ctrl) { + case LINK_OVERWRITE: + *curr_link_bitmap = link_bitmap; + break; + case LINK_CLR: + *curr_link_bitmap &= ~link_bitmap; + break; + case LINK_ADD: + *curr_link_bitmap |= link_bitmap; + break; + default: + mlo_err("unknown update ctrl %d", ctrl); + return; + } +} + +void +ml_nlink_set_curr_force_active_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t link_bitmap, + enum set_curr_control ctrl) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + ml_nlink_update_link_bitmap(&force_state->force_active_bitmap, + link_bitmap, ctrl); + ml_nlink_dump_force_state(force_state, ":ctrl %d bitmap 0x%x", + ctrl, link_bitmap); + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_set_curr_force_inactive_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t link_bitmap, + enum set_curr_control ctrl) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + ml_nlink_update_link_bitmap(&force_state->force_inactive_bitmap, + link_bitmap, ctrl); + ml_nlink_dump_force_state(force_state, ":ctrl %d bitmap 0x%x", ctrl, + link_bitmap); + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_set_curr_force_active_num_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t link_num, + uint16_t link_bitmap) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + force_state->force_active_num = link_num; + force_state->force_active_num_bitmap = link_bitmap; + ml_nlink_dump_force_state(force_state, ":num %d bitmap 0x%x", + link_num, link_bitmap); + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_set_curr_force_inactive_num_state(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t link_num, + uint16_t link_bitmap) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + force_state->force_inactive_num = link_num; + force_state->force_inactive_num_bitmap = link_bitmap; + ml_nlink_dump_force_state(force_state, ":num %d bitmap 0x%x", + link_num, link_bitmap); + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_set_dynamic_inactive_links(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t dynamic_link_bitmap) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + force_state->curr_dynamic_inactive_bitmap = dynamic_link_bitmap; + ml_nlink_dump_force_state(force_state, ":dynamic bitmap 0x%x", + dynamic_link_bitmap); + mlo_dev_lock_release(mlo_dev_ctx); +} + +static void +ml_nlink_update_force_link_request(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct set_link_req *req, + enum set_link_source source) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct set_link_req *old; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + if (source >= SET_LINK_SOURCE_MAX || source < 0) { + mlo_err("invalid source %d", source); + return; + } + mlo_dev_lock_acquire(mlo_dev_ctx); + old = &mlo_dev_ctx->sta_ctx->link_force_ctx.reqs[source]; + *old = *req; + mlo_dev_lock_release(mlo_dev_ctx); +} + +static void +ml_nlink_update_concurrency_link_request( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_state, + enum mlo_link_force_reason reason) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct set_link_req *req; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + mlo_dev_lock_acquire(mlo_dev_ctx); + req = + &mlo_dev_ctx->sta_ctx->link_force_ctx.reqs[SET_LINK_FROM_CONCURRENCY]; + req->reason = reason; + req->force_active_bitmap = force_state->force_active_bitmap; + req->force_inactive_bitmap = force_state->force_inactive_bitmap; + req->force_active_num = force_state->force_active_num; + req->force_inactive_num = force_state->force_inactive_num; + req->force_inactive_num_bitmap = + force_state->force_inactive_num_bitmap; + mlo_dev_lock_release(mlo_dev_ctx); +} + +void ml_nlink_init_concurrency_link_request( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct set_link_req *req; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + req = + &mlo_dev_ctx->sta_ctx->link_force_ctx.reqs[SET_LINK_FROM_CONCURRENCY]; + req->reason = MLO_LINK_FORCE_REASON_CONNECT; + req->force_active_bitmap = force_state->force_active_bitmap; + req->force_inactive_bitmap = force_state->force_inactive_bitmap; + req->force_active_num = force_state->force_active_num; + req->force_inactive_num = force_state->force_inactive_num; + req->force_inactive_num_bitmap = + force_state->force_inactive_num_bitmap; + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_get_force_link_request(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct set_link_req *req, + enum set_link_source source) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct set_link_req *old; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + if (source >= SET_LINK_SOURCE_MAX || source < 0) { + mlo_err("invalid source %d", source); + return; + } + mlo_dev_lock_acquire(mlo_dev_ctx); + old = &mlo_dev_ctx->sta_ctx->link_force_ctx.reqs[source]; + *req = *old; + mlo_dev_lock_release(mlo_dev_ctx); +} + +static void +ml_nlink_clr_force_link_request(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum set_link_source source) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct set_link_req *req; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + if (source >= SET_LINK_SOURCE_MAX || source < 0) { + mlo_err("invalid source %d", source); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + req = &mlo_dev_ctx->sta_ctx->link_force_ctx.reqs[source]; + qdf_mem_zero(req, sizeof(*req)); + mlo_dev_lock_release(mlo_dev_ctx); +} + +void +ml_nlink_get_dynamic_inactive_links(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t *dynamic_link_bitmap, + uint16_t *force_link_bitmap) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct ml_link_force_state *force_state; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + force_state = &mlo_dev_ctx->sta_ctx->link_force_ctx.force_state; + *dynamic_link_bitmap = force_state->curr_dynamic_inactive_bitmap; + *force_link_bitmap = force_state->force_inactive_bitmap; + mlo_dev_lock_release(mlo_dev_ctx); +} + +/** + * ml_nlink_get_affect_ml_sta() - Get ML STA whose link can be + * force inactive + * @psoc: PSOC object information + * + * At present we only support one ML STA. so ml_nlink_get_affect_ml_sta + * is invoked to get one ML STA vdev from policy mgr table. + * In future if ML STA+ML STA supported, we may need to extend it + * to find one ML STA which is required to force inactve/active. + * + * Return: vdev object + */ +static struct wlan_objmgr_vdev * +ml_nlink_get_affect_ml_sta(struct wlan_objmgr_psoc *psoc) +{ + uint8_t num_ml_sta = 0, num_disabled_ml_sta = 0; + uint8_t ml_sta_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + struct wlan_objmgr_vdev *vdev; + + policy_mgr_get_ml_sta_info_psoc(psoc, &num_ml_sta, + &num_disabled_ml_sta, + ml_sta_vdev_lst, ml_freq_lst, NULL, + NULL, NULL); + if (!num_ml_sta || num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) + return NULL; + + if (num_ml_sta > MAX_NUMBER_OF_CONC_CONNECTIONS) { + mlo_debug("unexpected num_ml_sta %d", num_ml_sta); + return NULL; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, ml_sta_vdev_lst[0], + WLAN_MLO_MGR_ID); + if (!vdev) { + mlo_err("invalid vdev for id %d", ml_sta_vdev_lst[0]); + return NULL; + } + + return vdev; +} + +bool ml_is_nlink_service_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + mlo_err("Invalid WMI handle"); + return false; + } + return wmi_service_enabled( + wmi_handle, + wmi_service_n_link_mlo_support); +} + +/* Exclude AP removed link */ +#define NLINK_EXCLUDE_REMOVED_LINK 0x01 +/* Include AP removed link only, can't work with other flags */ +#define NLINK_INCLUDE_REMOVED_LINK_ONLY 0x02 +/* Exclude QUITE link */ +#define NLINK_EXCLUDE_QUIET_LINK 0x04 +/* Exclude standby link information */ +#define NLINK_EXCLUDE_STANDBY_LINK 0x08 +/* Dump link information */ +#define NLINK_DUMP_LINK 0x10 + +static void +ml_nlink_get_standby_link_info(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t flag, + uint8_t ml_num_link_sz, + struct ml_link_info *ml_link_info, + qdf_freq_t *ml_freq_lst, + uint8_t *ml_vdev_lst, + uint8_t *ml_linkid_lst, + uint8_t *ml_num_link, + uint32_t *ml_link_bitmap) +{ + struct mlo_link_info *link_info; + uint8_t link_info_iter; + + link_info = mlo_mgr_get_ap_link(vdev); + if (!link_info) + return; + + for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; + link_info_iter++) { + if (qdf_is_macaddr_zero(&link_info->ap_link_addr)) + break; + + if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) { + if (*ml_num_link >= ml_num_link_sz) { + mlo_debug("link lst overflow"); + break; + } + if (!link_info->link_chan_info->ch_freq) { + mlo_debug("link freq 0!"); + break; + } + if (*ml_link_bitmap & (1 << link_info->link_id)) { + mlo_debug("unexpected standby linkid %d", + link_info->link_id); + break; + } + if (link_info->link_id >= MAX_MLO_LINK_ID) { + mlo_debug("invalid standby link id %d", + link_info->link_id); + break; + } + + if ((flag & NLINK_EXCLUDE_REMOVED_LINK) && + qdf_atomic_test_bit( + LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags)) { + mlo_debug("standby link %d is removed", + link_info->link_id); + continue; + } + if ((flag & NLINK_INCLUDE_REMOVED_LINK_ONLY) && + !qdf_atomic_test_bit( + LS_F_AP_REMOVAL_BIT, + &link_info->link_status_flags)) { + continue; + } + + ml_freq_lst[*ml_num_link] = + link_info->link_chan_info->ch_freq; + ml_vdev_lst[*ml_num_link] = WLAN_INVALID_VDEV_ID; + ml_linkid_lst[*ml_num_link] = link_info->link_id; + *ml_link_bitmap |= 1 << link_info->link_id; + if (flag & NLINK_DUMP_LINK) + mlo_debug("vdev %d link %d freq %d bitmap 0x%x flag 0x%x", + ml_vdev_lst[*ml_num_link], + ml_linkid_lst[*ml_num_link], + ml_freq_lst[*ml_num_link], + *ml_link_bitmap, flag); + (*ml_num_link)++; + } + + link_info++; + } +} + +uint32_t +ml_nlink_get_standby_link_bitmap(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t ml_num_link = 0; + uint32_t standby_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + ml_nlink_get_standby_link_info(psoc, vdev, NLINK_DUMP_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &standby_link_bitmap); + + return standby_link_bitmap; +} + +/** + * ml_nlink_get_link_info() - Get ML STA link info + * @psoc: PSOC object information + * @vdev: ml sta vdev object + * @flag: flag NLINK_* to specify what links should be returned + * @ml_num_link_sz: input array size of ml_link_info and + * other parameters. + * @ml_link_info: ml link info array + * @ml_freq_lst: channel frequency list + * @ml_vdev_lst: vdev id list + * @ml_linkid_lst: link id list + * @ml_num_link: num of links + * @ml_link_bitmap: link bitmaps. + * + * Return: void + */ +static void ml_nlink_get_link_info(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint8_t flag, + uint8_t ml_num_link_sz, + struct ml_link_info *ml_link_info, + qdf_freq_t *ml_freq_lst, + uint8_t *ml_vdev_lst, + uint8_t *ml_linkid_lst, + uint8_t *ml_num_link, + uint32_t *ml_link_bitmap) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + uint8_t i, num_link = 0; + uint32_t link_bitmap = 0; + uint16_t link_id; + uint8_t vdev_id; + bool connected = false; + + *ml_num_link = 0; + *ml_link_bitmap = 0; + qdf_mem_zero(ml_link_info, sizeof(*ml_link_info) * ml_num_link_sz); + qdf_mem_zero(ml_freq_lst, sizeof(*ml_freq_lst) * ml_num_link_sz); + qdf_mem_zero(ml_linkid_lst, sizeof(*ml_linkid_lst) * ml_num_link_sz); + qdf_mem_zero(ml_vdev_lst, sizeof(*ml_vdev_lst) * ml_num_link_sz); + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx || !mlo_dev_ctx->sta_ctx) { + mlo_err("mlo_ctx or sta_ctx null"); + return; + } + + mlo_dev_lock_acquire(mlo_dev_ctx); + sta_ctx = mlo_dev_ctx->sta_ctx; + + link_bitmap = 0; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + if (!qdf_test_bit(i, sta_ctx->wlan_connected_links)) + continue; + + if (!wlan_cm_is_vdev_connected( + mlo_dev_ctx->wlan_vdev_list[i])) { + mlo_debug("Vdev id %d is not in connected state", + wlan_vdev_get_id( + mlo_dev_ctx->wlan_vdev_list[i])); + continue; + } + connected = true; + + vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + link_id = wlan_vdev_get_link_id( + mlo_dev_ctx->wlan_vdev_list[i]); + if (link_id >= MAX_MLO_LINK_ID) { + mlo_debug("invalid link id %x for vdev %d", + link_id, vdev_id); + continue; + } + + if ((flag & NLINK_EXCLUDE_REMOVED_LINK) && + wlan_get_vdev_link_removed_flag_by_vdev_id( + psoc, vdev_id)) { + mlo_debug("vdev id %d link %d is removed", + vdev_id, link_id); + continue; + } + if ((flag & NLINK_INCLUDE_REMOVED_LINK_ONLY) && + !wlan_get_vdev_link_removed_flag_by_vdev_id( + psoc, vdev_id)) { + continue; + } + if ((flag & NLINK_EXCLUDE_QUIET_LINK) && + mlo_is_sta_in_quiet_status(mlo_dev_ctx, link_id)) { + mlo_debug("vdev id %d link %d is quiet", + vdev_id, link_id); + continue; + } + + if (num_link >= ml_num_link_sz) + break; + ml_freq_lst[num_link] = wlan_get_operation_chan_freq( + mlo_dev_ctx->wlan_vdev_list[i]); + ml_vdev_lst[num_link] = vdev_id; + ml_linkid_lst[num_link] = link_id; + link_bitmap |= 1 << link_id; + if (flag & NLINK_DUMP_LINK) + mlo_debug("vdev %d link %d freq %d bitmap 0x%x flag 0x%x", + ml_vdev_lst[num_link], + ml_linkid_lst[num_link], + ml_freq_lst[num_link], link_bitmap, flag); + num_link++; + } + /* Add standby link only if mlo sta is connected */ + if (connected && !(flag & NLINK_EXCLUDE_STANDBY_LINK)) + ml_nlink_get_standby_link_info(psoc, vdev, flag, + ml_num_link_sz, + ml_link_info, + ml_freq_lst, + ml_vdev_lst, + ml_linkid_lst, + &num_link, + &link_bitmap); + + mlo_dev_lock_release(mlo_dev_ctx); + *ml_num_link = num_link; + *ml_link_bitmap = link_bitmap; +} + +uint32_t +convert_link_bitmap_to_link_ids(uint32_t link_bitmap, + uint8_t link_id_sz, + uint8_t *link_ids) +{ + uint32_t i = 0; + uint8_t id = 0; + + while (link_bitmap) { + if (link_bitmap & 1) { + if (id >= 15) { + /* warning */ + mlo_err("linkid invalid %d 0x%x", + id, link_bitmap); + break; + } + if (link_ids) { + if (i >= link_id_sz) { + /* warning */ + mlo_err("linkid buff overflow 0x%x", + link_bitmap); + break; + } + link_ids[i] = id; + } + i++; + } + link_bitmap >>= 1; + id++; + } + + return i; +} + +uint32_t +ml_nlink_convert_link_bitmap_to_ids(uint32_t link_bitmap, + uint8_t link_id_sz, + uint8_t *link_ids) +{ + return convert_link_bitmap_to_link_ids(link_bitmap, link_id_sz, + link_ids); +} + +/** + * ml_nlink_handle_mcc_links() - Check force inactive needed + * if ML STA links are in MCC channels + * @psoc: PSOC object information + * @vdev: vdev object + * @force_cmd: force command to be returned + * + * This API will return force inactive number 1 in force_cmd + * if STA links are in MCC channels with the link bitmap including + * the MCC links id. + * If the link is marked removed by AP MLD, return force inactive + * bitmap with removed link id bitmap as well. + * + * Return: void + */ +static void +ml_nlink_handle_mcc_links(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0, affected_link_bitmap = 0; + uint32_t force_inactive_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + ml_nlink_get_link_info(psoc, vdev, NLINK_INCLUDE_REMOVED_LINK_ONLY | + NLINK_DUMP_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &force_inactive_link_bitmap); + if (force_inactive_link_bitmap) { + /* AP removed link will be force inactive always */ + force_cmd->force_inactive_bitmap = force_inactive_link_bitmap; + mlo_debug("AP removed link 0x%x", force_inactive_link_bitmap); + } + + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK | + NLINK_DUMP_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + + policy_mgr_is_ml_sta_links_in_mcc(psoc, ml_freq_lst, + ml_vdev_lst, + ml_linkid_lst, + ml_num_link, + &affected_link_bitmap); + if (affected_link_bitmap) { + force_cmd->force_inactive_num = + convert_link_bitmap_to_link_ids( + affected_link_bitmap, 0, NULL); + if (force_cmd->force_inactive_num > 1) { + force_cmd->force_inactive_num--; + force_cmd->force_inactive_num_bitmap = + affected_link_bitmap; + } else { + force_cmd->force_inactive_num = 0; + } + } + if (force_inactive_link_bitmap || affected_link_bitmap) + ml_nlink_dump_force_state(force_cmd, ""); +} + +/** + * ml_nlink_handle_legacy_sta_intf() - Check force inactive needed + * with legacy STA + * @psoc: PSOC object information + * @vdev: vdev object + * @force_cmd: force command to be returned + * @sta_vdev_id: legacy STA vdev id + * @non_ml_sta_freq: legacy STA channel frequency + * + * If legacy STA is MCC with any link of MLO STA, the mlo link + * will be forced inactive. And if 3 link MLO case, the left + * 2 links have to be force inactive with num 1. For example, + * ML STA 2+5+6, legacy STA on MCC channel of 5G link, then + * 5G will be force inactive, and left 2+6 link will be force + * inactive by inactive link num = 1 (with link bitmap 2+6). + * + * Return: void + */ +static void +ml_nlink_handle_legacy_sta_intf(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd, + uint8_t sta_vdev_id, + qdf_freq_t non_ml_sta_freq) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0, affected_link_bitmap = 0; + uint32_t force_inactive_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t i = 0; + uint32_t scc_link_bitmap = 0; + + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + + for (i = 0; i < ml_num_link; i++) { + /*todo add removed link to force_inactive_link_bitmap*/ + if (ml_freq_lst[i] == non_ml_sta_freq) { + scc_link_bitmap = 1 << ml_linkid_lst[i]; + } else if (policy_mgr_2_freq_always_on_same_mac( + psoc, ml_freq_lst[i], non_ml_sta_freq)) { + force_inactive_link_bitmap |= 1 << ml_linkid_lst[i]; + } else if (!wlan_cm_same_band_sta_allowed(psoc) && + (wlan_reg_is_24ghz_ch_freq(ml_freq_lst[i]) == + wlan_reg_is_24ghz_ch_freq(non_ml_sta_freq)) && + !policy_mgr_are_sbs_chan(psoc, ml_freq_lst[i], + non_ml_sta_freq)) { + force_inactive_link_bitmap |= 1 << ml_linkid_lst[i]; + } + } + + /* If no left active link, don't send the force inactive command for + * concurrency purpose. + */ + if (!(ml_link_bitmap & ~force_inactive_link_bitmap)) { + mlo_debug("unexpected ML conc with legacy STA freq %d", + non_ml_sta_freq); + return; + } + + if (force_inactive_link_bitmap) { + /* for example SBS rd, ML 2G+5G high, Legacy intf on 5G high, + * set force inactive with bitmap of 5g link. + * + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 2G. + * set force inactive with bitmap 2G link, + * and set force inactive link num to 1 for left 5g and 6g + * link. + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 5G low. + * set force inactive with bitmap 5G low link, + * and set force inactive link num to 1 for left 2g and 6g + * link. + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 5G high. + * set force inactive with bitmap 6G link, + * and set force inactive link num to 1 for left 2g and 5g + * link. + * In above 3 link cases, if legacy intf is SCC with ml link + * don't force inactive by bitmap, only send force inactive + * num with bitmap + */ + force_cmd->force_inactive_bitmap = force_inactive_link_bitmap; + + affected_link_bitmap = + ml_link_bitmap & ~force_inactive_link_bitmap; + affected_link_bitmap &= ~scc_link_bitmap; + force_cmd->force_inactive_num = + convert_link_bitmap_to_link_ids( + affected_link_bitmap, 0, NULL); + if (force_cmd->force_inactive_num > 1) { + force_cmd->force_inactive_num--; + force_cmd->force_inactive_num_bitmap = + affected_link_bitmap; + + } else { + force_cmd->force_inactive_num = 0; + } + } else { + /* for example SBS rd, ML 2G+5G high, Legacy intf on 5G low, + * set force inactive num to 1 with bitmap of 2g+5g link. + * + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 5G low SCC. + * set force inactive link num to 1 for left 2g and 6g + * link. + */ + affected_link_bitmap = ml_link_bitmap; + affected_link_bitmap &= ~scc_link_bitmap; + + force_cmd->force_inactive_num = + convert_link_bitmap_to_link_ids( + affected_link_bitmap, 0, NULL); + if (force_cmd->force_inactive_num > 1) { + force_cmd->force_inactive_num--; + force_cmd->force_inactive_num_bitmap = + affected_link_bitmap; + } else { + force_cmd->force_inactive_num = 0; + } + } +} + +/** + * ml_nlink_handle_legacy_sap_intf() - Check force inactive needed + * with legacy SAP + * @psoc: PSOC object information + * @vdev: vdev object + * @force_cmd: force command to be returned + * @sap_vdev_id: legacy SAP vdev id + * @sap_freq: legacy SAP channel frequency + * + * If legacy SAP is 2g only SAP and MLO STA is 5+6, + * 2 links have to be force inactive with num 1. + * + * Return: void + */ +static void +ml_nlink_handle_legacy_sap_intf(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd, + uint8_t sap_vdev_id, + qdf_freq_t sap_freq) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0, affected_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t i = 0; + bool sap_2g_only = false; + + /* SAP MCC with MLO STA link is not preferred. + * If SAP is 2Ghz only by ACS and two ML link are + * 5/6 band, then force SCC may not happen. In such + * case inactive one link. + */ + if (policy_mgr_check_2ghz_only_sap_affected_link( + psoc, sap_vdev_id, sap_freq, + ml_num_link, ml_freq_lst)) { + mlo_debug("2G only SAP vdev %d ch freq %d is not SCC with any MLO STA link", + sap_vdev_id, sap_freq); + sap_2g_only = true; + } + /* + * If SAP is on 5G or 6G, SAP can always force SCC to 5G/6G ML STA or + * 2G ML STA, no need force SCC link. + */ + if (!sap_2g_only) + return; + + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + + for (i = 0; i < ml_num_link; i++) { + if (!wlan_reg_is_24ghz_ch_freq(ml_freq_lst[i])) + affected_link_bitmap |= 1 << ml_linkid_lst[i]; + } + + if (affected_link_bitmap) { + /* for SBS rd, ML 2G + 5G low, Legacy SAP on 2G. + * no force any link + * for SBS rd, ML 5G low + 5G high/6G, Legacy SAP on 2G. + * set force inactive num 1 with bitmap 5g and 6g. + * + * for SBS rd, ML 2G + 5G low + 6G, Legacy SAP on 2G. + * set force inactive link num to 1 for 5g and 6g + * link. + */ + force_cmd->force_inactive_num = + convert_link_bitmap_to_link_ids( + affected_link_bitmap, 0, NULL); + if (force_cmd->force_inactive_num > 1) { + force_cmd->force_inactive_num--; + force_cmd->force_inactive_num_bitmap = + affected_link_bitmap; + } else { + force_cmd->force_inactive_num = 0; + } + } +} + +/** + * ml_nlink_handle_legacy_p2p_intf() - Check force inactive needed + * with p2p + * @psoc: PSOC object information + * @vdev: vdev object + * @force_cmd: force command to be returned + * @p2p_vdev_id: p2p vdev id + * @p2p_freq: p2p channel frequency + * + * If P2P has low latency flag and MCC with any link of MLO STA, the mlo link + * will be forced inactive. And if 3 link MLO case, the left 2 links have to + * be force inactive with num 1. + * + * Return: void + */ +static void +ml_nlink_handle_legacy_p2p_intf(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd, + uint8_t p2p_vdev_id, + qdf_freq_t p2p_freq) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0, affected_link_bitmap = 0; + uint32_t force_inactive_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t i = 0; + uint32_t scc_link_bitmap = 0; + + /* If high tput or low latency is not set, mcc is allowed for p2p */ + if (!policy_mgr_is_vdev_high_tput_or_low_latency( + psoc, p2p_vdev_id)) + return; + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + + for (i = 0; i < ml_num_link; i++) { + if (ml_freq_lst[i] == p2p_freq) { + scc_link_bitmap = 1 << ml_linkid_lst[i]; + } else if (policy_mgr_2_freq_always_on_same_mac( + psoc, ml_freq_lst[i], p2p_freq)) { + force_inactive_link_bitmap |= 1 << ml_linkid_lst[i]; + } + } + /* If no left active link, don't send the force inactive command for + * concurrency purpose. + */ + if (!(ml_link_bitmap & ~force_inactive_link_bitmap)) { + mlo_debug("unexpected ML conc with legacy P2P freq %d", + p2p_freq); + return; + } + + if (force_inactive_link_bitmap) { + /* for example SBS rd, ML 2G+5G high, Legacy intf on 5G high, + * set force inactive with bitmap of 5g link. + * + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 2G. + * set force inactive with bitmap 2G link, + * and set force inactive link num to 1 for left 5g and 6g + * link. + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 5G low. + * set force inactive with bitmap 5G low link, + * and set force inactive link num to 1 for left 2g and 6g + * link. + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 5G high.. + * set force inactive with bitmap 6G low link, + * and set force inactive link num to 1 for left 2g and 5g + * link. + */ + force_cmd->force_inactive_bitmap = force_inactive_link_bitmap; + + affected_link_bitmap = + ml_link_bitmap & ~force_inactive_link_bitmap; + affected_link_bitmap &= ~scc_link_bitmap; + force_cmd->force_inactive_num = + convert_link_bitmap_to_link_ids( + affected_link_bitmap, 0, NULL); + if (force_cmd->force_inactive_num > 1) { + force_cmd->force_inactive_num--; + force_cmd->force_inactive_num_bitmap = + affected_link_bitmap; + + } else { + force_cmd->force_inactive_num = 0; + } + } else { + /* for example SBS rd, ML 2G+5G high, Legacy intf on 5G low, + * set force inactive num to 1 with bitmap of 2g+5g link. + * + * for SBS rd, ML 2G + 5G low + 6G, Legacy intf on 5G low SCC. + * set force inactive link num to 1 for left 2g and 6g + * link. + */ + affected_link_bitmap = ml_link_bitmap; + affected_link_bitmap &= ~scc_link_bitmap; + + force_cmd->force_inactive_num = + convert_link_bitmap_to_link_ids( + affected_link_bitmap, 0, NULL); + if (force_cmd->force_inactive_num > 1) { + force_cmd->force_inactive_num--; + force_cmd->force_inactive_num_bitmap = + affected_link_bitmap; + } else { + force_cmd->force_inactive_num = 0; + } + } +} + +/** + * ml_nlink_handle_3_port_specific_scenario() - Check some specific corner + * case that can't be handled general logic in + * ml_nlink_handle_legacy_intf_3_ports. + * @psoc: PSOC object information + * @legacy_intf_freq1: legacy interface 1 channel frequency + * @legacy_intf_freq2: legacy interface 2 channel frequency + * @ml_num_link: number of ML STA links + * @ml_freq_lst: ML STA link channel frequency list + * @ml_linkid_lst: ML STA link ids + * + * Return: link force inactive bitmap + */ +static uint32_t +ml_nlink_handle_3_port_specific_scenario(struct wlan_objmgr_psoc *psoc, + qdf_freq_t legacy_intf_freq1, + qdf_freq_t legacy_intf_freq2, + uint8_t ml_num_link, + qdf_freq_t *ml_freq_lst, + uint8_t *ml_linkid_lst) +{ + uint32_t force_inactive_link_bitmap = 0; + + if (ml_num_link < 2) + return 0; + + /* special case handling: + * LL P2P on 2.4G, ML STA 5G+6G, SAP on 6G, then + * inactive 5G link. + * LL P2P on 2.4G, ML STA 5G+6G, SAP on 5G, then + * inactive 6G link. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(legacy_intf_freq1) && + !WLAN_REG_IS_24GHZ_CH_FREQ(ml_freq_lst[0]) && + policy_mgr_are_sbs_chan(psoc, ml_freq_lst[0], ml_freq_lst[1]) && + policy_mgr_2_freq_always_on_same_mac(psoc, ml_freq_lst[0], + legacy_intf_freq2)) + force_inactive_link_bitmap |= 1 << ml_linkid_lst[1]; + else if (WLAN_REG_IS_24GHZ_CH_FREQ(legacy_intf_freq1) && + !WLAN_REG_IS_24GHZ_CH_FREQ(ml_freq_lst[1]) && + policy_mgr_are_sbs_chan(psoc, ml_freq_lst[0], + ml_freq_lst[1]) && + policy_mgr_2_freq_always_on_same_mac(psoc, ml_freq_lst[1], + legacy_intf_freq2)) + force_inactive_link_bitmap |= 1 << ml_linkid_lst[0]; + + if (force_inactive_link_bitmap) + mlo_debug("force inactive 0x%x", force_inactive_link_bitmap); + + return force_inactive_link_bitmap; +} + +/** + * ml_nlink_handle_legacy_intf_3_ports() - Check force inactive needed + * with 2 legacy interfaces + * @psoc: PSOC object information + * @vdev: vdev object + * @force_cmd: force command to be returned + * @legacy_intf_freq1: legacy interface frequency + * @legacy_intf_freq2: legacy interface frequency + * + * If legacy interface 1 (which channel frequency legacy_intf_freq1) is + * mcc with any link based on current hw mode, then force inactive the link. + * And if standby link is mcc with legacy interface, then disable standby + * link as well. + * In 3 Port case, at present only legacy interface 1(which channel frequency + * legacy_intf_freq1) MCC avoidance requirement can be met. The assignment of + * legacy_intf_freq1 and legacy_intf_freq2 is based on priority of Port type, + * check policy_mgr_get_legacy_conn_info for detail. + * Cornor cases will be handled in ml_nlink_handle_3_port_specific_scenario. + * + * Return: void + */ +static void +ml_nlink_handle_legacy_intf_3_ports(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd, + qdf_freq_t legacy_intf_freq1, + qdf_freq_t legacy_intf_freq2) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0; + uint32_t force_inactive_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t i = 0; + uint32_t scc_link_bitmap = 0; + + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + + for (i = 0; i < ml_num_link; i++) { + if (ml_vdev_lst[i] == WLAN_INVALID_VDEV_ID) { + /*standby link will be handled later. */ + continue; + } + if (ml_freq_lst[i] == legacy_intf_freq1) { + scc_link_bitmap = 1 << ml_linkid_lst[i]; + if (ml_freq_lst[i] == legacy_intf_freq2) { + mlo_debug("3 vdev scc no-op"); + return; + } + } else if (policy_mgr_are_2_freq_on_same_mac( + psoc, ml_freq_lst[i], legacy_intf_freq1)) { + force_inactive_link_bitmap |= 1 << ml_linkid_lst[i]; + } else if (i == 1) { + force_inactive_link_bitmap |= + ml_nlink_handle_3_port_specific_scenario( + psoc, + legacy_intf_freq1, + legacy_intf_freq2, + ml_num_link, + ml_freq_lst, + ml_linkid_lst); + } + } + /* usually it can't happen in 3 Port */ + if (!force_inactive_link_bitmap && !scc_link_bitmap) { + mlo_debug("legacy vdev freq %d standalone on dedicated mac", + legacy_intf_freq1); + return; + } + + if (force_inactive_link_bitmap) + force_cmd->force_inactive_bitmap = force_inactive_link_bitmap; +} + +static void +ml_nlink_handle_standby_link_3_ports( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd, + uint8_t num_legacy_vdev, + uint8_t *vdev_lst, + qdf_freq_t *freq_lst, + enum policy_mgr_con_mode *mode_lst) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0; + uint32_t force_inactive_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t i, j; + + if (num_legacy_vdev < 2) + return; + + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + for (i = 0; i < ml_num_link; i++) { + if (ml_vdev_lst[i] != WLAN_INVALID_VDEV_ID) + continue; + /* standby link will be forced inactive if mcc with + * legacy interface + */ + for (j = 0; j < num_legacy_vdev; j++) { + if (ml_freq_lst[i] != freq_lst[j] && + policy_mgr_are_2_freq_on_same_mac( + psoc, ml_freq_lst[i], freq_lst[j])) + force_inactive_link_bitmap |= + 1 << ml_linkid_lst[i]; + } + } + + if (force_inactive_link_bitmap) + force_cmd->force_inactive_bitmap |= force_inactive_link_bitmap; +} + +/** + * ml_nlink_handle_legacy_intf() - Check force inactive needed + * with legacy interface + * @psoc: PSOC object information + * @vdev: vdev object + * @force_cmd: force command to be returned + * + * Return: void + */ +static void +ml_nlink_handle_legacy_intf(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *force_cmd) +{ + uint8_t vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + enum policy_mgr_con_mode mode_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t num_legacy_vdev; + + num_legacy_vdev = policy_mgr_get_legacy_conn_info( + psoc, vdev_lst, + freq_lst, mode_lst, + QDF_ARRAY_SIZE(vdev_lst)); + if (!num_legacy_vdev) + return; + /* 2 port case with 2 ml sta links or + * 2 port case with 3 ml sta links + */ + if (num_legacy_vdev == 1) { + switch (mode_lst[0]) { + case PM_STA_MODE: + ml_nlink_handle_legacy_sta_intf( + psoc, vdev, force_cmd, vdev_lst[0], + freq_lst[0]); + break; + case PM_SAP_MODE: + ml_nlink_handle_legacy_sap_intf( + psoc, vdev, force_cmd, vdev_lst[0], + freq_lst[0]); + break; + case PM_P2P_CLIENT_MODE: + case PM_P2P_GO_MODE: + ml_nlink_handle_legacy_p2p_intf( + psoc, vdev, force_cmd, vdev_lst[0], + freq_lst[0]); + break; + default: + /* unexpected legacy connection count */ + mlo_debug("unexpected legacy intf mode %d", + mode_lst[0]); + return; + } + ml_nlink_dump_force_state(force_cmd, ""); + return; + } + /* 3 ports case with ml sta 2 or 3 links, suppose port 3 vdev is + * low latency legacy vdev: + * 6G: ML Link + Port2 + Port3 | 5G: ML Link + * => no op + * 6G: ML Link + Port2 | 5G: ML Link + Port3 + * => disable 5G link if 5G mcc + * 6G: ML Link + Port3 | 5G: ML Link + Port2 + * => disable 6G link if 6G mcc + * 6G: ML Link | 5G: ML Link + Port3 | 2G: Port2 + * => disable 5G link if 5G mcc. + * 6G: ML Link | 5G: ML Link + Port2 | 2G: Port3 + * => disable 6g link. + * 6G: ML Link + Port3 | 5G: ML Link | 2G: Port2 + * => disable 6G link if 6G mcc. + * 6G: ML Link + Port2 | 5G: ML Link | 2G: Port3 + * => disable 6g link. + * 6G: ML Link + Port2 + Port3 | 2G: ML Link + * => no op + * 6G: ML Link + Port2 | 2G: ML Link + Port3 + * => disable 2G link if 2G mcc + * 6G: ML Link + Port3 | 2G: ML Link + Port2 + * => disable 6G link if 6G mcc + * 6G: ML Link | 2G: ML Link + Port3 | 5G: Port2 + * => disable 2G link if 2G mcc. + * 6G: ML Link | 2G: ML Link + Port2 | 5GL: Port3 + * => disable 6G link + * 6G: ML Link + Port3 | 2G: ML Link | 5G: Port2 + * => disable 6G link if 6G mcc. + * 6G: ML Link + Port2 | 2G: ML Link | 5GL: Port3 + * => disable 2G link + * general rule: + * If Port3 is mcc with any link based on current hw mode, then + * force inactive the link. + * And if standby link is mcc with Port3, then disable standby + * link as well. + */ + switch (mode_lst[0]) { + case PM_P2P_CLIENT_MODE: + case PM_P2P_GO_MODE: + if (!policy_mgr_is_vdev_high_tput_or_low_latency( + psoc, vdev_lst[0])) + break; + fallthrough; + case PM_STA_MODE: + ml_nlink_handle_legacy_intf_3_ports( + psoc, vdev, force_cmd, freq_lst[0], freq_lst[1]); + break; + case PM_SAP_MODE: + /* if 2g only sap present, force inactive num to fw. */ + ml_nlink_handle_legacy_sap_intf( + psoc, vdev, force_cmd, vdev_lst[0], freq_lst[0]); + break; + default: + /* unexpected legacy connection count */ + mlo_debug("unexpected legacy intf mode %d", mode_lst[0]); + return; + } + ml_nlink_handle_standby_link_3_ports(psoc, vdev, force_cmd, + num_legacy_vdev, + vdev_lst, + freq_lst, + mode_lst); + ml_nlink_dump_force_state(force_cmd, ""); +} + +/** + * ml_nlink_handle_dynamic_inactive() - Handle dynamic force inactive num + * with legacy SAP + * @psoc: PSOC object information + * @vdev: vdev object + * @curr: current force command state + * @new: new force command + * + * If ML STA 2 or 3 links are present and force inactive num = 1 with dynamic + * flag enabled for some reason, FW will report the current inactive links, + * host will select one and save to curr_dynamic_inactive_bitmap. + * If SAP starting on channel which is same mac as links in + * the curr_dynamic_inactive_bitmap, host will force inactive the links in + * curr_dynamic_inactive_bitmap to avoid FW link switch between the dynamic + * inactive links. + * + * Return: void + */ +static void +ml_nlink_handle_dynamic_inactive(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *curr, + struct ml_link_force_state *new) +{ + uint8_t vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + enum policy_mgr_con_mode mode_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t num; + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap; + uint32_t force_inactive_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t i, j; + + /* If force inactive num wasn't sent to fw, no need to handle + * dynamic inactive links. + */ + if (!curr->force_inactive_num || + !curr->force_inactive_num_bitmap || + !curr->curr_dynamic_inactive_bitmap) + return; + if (curr->force_inactive_num != new->force_inactive_num || + curr->force_inactive_num_bitmap != + new->force_inactive_num_bitmap) + return; + /* If links have been forced inactive by bitmap, no need to force + * again. + */ + if ((new->force_inactive_bitmap & + curr->curr_dynamic_inactive_bitmap) == + curr->curr_dynamic_inactive_bitmap) + return; + + num = policy_mgr_get_legacy_conn_info( + psoc, vdev_lst, + freq_lst, mode_lst, + QDF_ARRAY_SIZE(vdev_lst)); + if (!num) + return; + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_REMOVED_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return; + for (i = 0; i < ml_num_link; i++) { + if (!((1 << ml_linkid_lst[i]) & + curr->curr_dynamic_inactive_bitmap)) + continue; + for (j = 0; j < num; j++) { + if (mode_lst[j] != PM_SAP_MODE) + continue; + if (policy_mgr_2_freq_always_on_same_mac( + psoc, freq_lst[j], ml_freq_lst[i])) { + force_inactive_link_bitmap |= + 1 << ml_linkid_lst[i]; + mlo_debug("force dynamic inactive link id %d freq %d for sap freq %d", + ml_linkid_lst[i], ml_freq_lst[i], + freq_lst[j]); + } else if (num > 1 && + policy_mgr_are_2_freq_on_same_mac( + psoc, freq_lst[j], ml_freq_lst[i])) { + force_inactive_link_bitmap |= + 1 << ml_linkid_lst[i]; + mlo_debug("force dynamic inactive link id %d freq %d for sap freq %d", + ml_linkid_lst[i], ml_freq_lst[i], + freq_lst[j]); + } + } + } + if (force_inactive_link_bitmap) { + new->force_inactive_bitmap |= force_inactive_link_bitmap; + ml_nlink_dump_force_state(new, ""); + } +} + +/** + * ml_nlink_sta_inactivity_allowed_with_quiet() - Check force inactive allowed + * for links in bitmap + * @psoc: PSOC object information + * @vdev: vdev object + * @force_inactive_bitmap: force inactive link bimap + * + * If left links (exclude removed link and QUITE link) are zero, the force + * inactive bitmap is not allowed. + * + * Return: true if allow to force inactive links in force_inactive_bitmap + */ +static bool ml_nlink_sta_inactivity_allowed_with_quiet( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t force_inactive_bitmap) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + ml_nlink_get_link_info(psoc, vdev, (NLINK_EXCLUDE_REMOVED_LINK | + NLINK_EXCLUDE_QUIET_LINK | + NLINK_EXCLUDE_STANDBY_LINK), + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + ml_link_bitmap &= ~force_inactive_bitmap; + if (!ml_link_bitmap) { + mlo_debug("not allow - no active link after force inactive 0x%x", + force_inactive_bitmap); + return false; + } + + return true; +} + +/** + * ml_nlink_allow_conc() - Check force inactive allowed for links in bitmap + * @psoc: PSOC object information + * @vdev: vdev object + * @no_forced_bitmap: no force link bitmap + * @force_inactive_bitmap: force inactive link bimap + * + * Check the no force bitmap and force inactive bitmap are allowed to send + * to firmware + * + * Return: true if allow to "no force" and force inactive links. + */ +static bool +ml_nlink_allow_conc(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint16_t no_forced_bitmap, + uint16_t force_inactive_bitmap) +{ + uint8_t vdev_id_num = 0; + uint8_t vdev_ids[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t vdev_id_bitmap_sz; + uint32_t vdev_id_bitmap[MLO_VDEV_BITMAP_SZ]; + uint32_t i; + union conc_ext_flag conc_ext_flags; + struct wlan_objmgr_vdev *ml_vdev; + bool allow = true; + qdf_freq_t freq = 0; + struct wlan_channel *bss_chan; + + if (!ml_nlink_sta_inactivity_allowed_with_quiet( + psoc, vdev, force_inactive_bitmap)) + return false; + + ml_nlink_convert_linkid_bitmap_to_vdev_bitmap( + psoc, vdev, no_forced_bitmap, NULL, &vdev_id_bitmap_sz, + vdev_id_bitmap, &vdev_id_num, vdev_ids); + + for (i = 0; i < vdev_id_num; i++) { + ml_vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_ids[i], + WLAN_MLO_MGR_ID); + if (!ml_vdev) { + mlo_err("invalid vdev id %d ", vdev_ids[i]); + continue; + } + + /* If link is active, no need to check allow conc */ + if (!policy_mgr_vdev_is_force_inactive(psoc, vdev_ids[i])) { + wlan_objmgr_vdev_release_ref(ml_vdev, + WLAN_MLO_MGR_ID); + continue; + } + + conc_ext_flags.value = + policy_mgr_get_conc_ext_flags(ml_vdev, true); + + bss_chan = wlan_vdev_mlme_get_bss_chan(ml_vdev); + if (bss_chan) + freq = bss_chan->ch_freq; + + if (!policy_mgr_is_concurrency_allowed(psoc, PM_STA_MODE, + freq, + HW_MODE_20_MHZ, + conc_ext_flags.value, + NULL)) { + wlan_objmgr_vdev_release_ref(ml_vdev, + WLAN_MLO_MGR_ID); + break; + } + + wlan_objmgr_vdev_release_ref(ml_vdev, WLAN_MLO_MGR_ID); + } + + if (i < vdev_id_num) { + mlo_err("not allow - vdev %d freq %d active due to conc", + vdev_ids[i], freq); + allow = false; + } + + return allow; +} + +static QDF_STATUS +ml_nlink_update_no_force_for_all(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *curr, + struct ml_link_force_state *new, + enum mlo_link_force_reason reason) +{ + uint16_t no_force_links; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* Special handling for clear all force mode in target. + * send MLO_LINK_FORCE_MODE_NO_FORCE to clear "all" + * to target + */ + if (!new->force_inactive_bitmap && + !new->force_inactive_num && + !new->force_active_bitmap && + !new->force_active_num && + (curr->force_inactive_bitmap || + curr->force_inactive_num || + curr->force_active_bitmap || + curr->force_active_num)) { + /* If link is force inactive already, but new command will + * mark it non-force, need to check conc allow or not. + */ + no_force_links = curr->force_inactive_bitmap; + /* Check non forced links allowed by conc */ + if (!ml_nlink_allow_conc(psoc, vdev, no_force_links, 0)) { + status = QDF_STATUS_E_INVAL; + goto end; + } + + status = policy_mgr_mlo_sta_set_nlink( + psoc, wlan_vdev_get_id(vdev), + reason, + MLO_LINK_FORCE_MODE_NO_FORCE, + 0, 0, 0, 0); + } + +end: + return status; +} + +static QDF_STATUS +ml_nlink_update_force_inactive(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *curr, + struct ml_link_force_state *new, + enum mlo_link_force_reason reason) +{ + uint16_t no_force_links; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (new->force_inactive_bitmap != curr->force_inactive_bitmap) { + /* If link is force inactive already, but new command will + * mark it non-force, need to check conc allow or not. + */ + no_force_links = curr->force_inactive_bitmap & + new->force_inactive_bitmap; + no_force_links ^= curr->force_inactive_bitmap; + + /* Check non forced links allowed by conc */ + if (!ml_nlink_allow_conc(psoc, vdev, no_force_links, + new->force_inactive_bitmap)) { + status = QDF_STATUS_E_NOSUPPORT; + goto end; + } + status = policy_mgr_mlo_sta_set_nlink( + psoc, wlan_vdev_get_id(vdev), reason, + MLO_LINK_FORCE_MODE_INACTIVE, + 0, + new->force_inactive_bitmap, + 0, + link_ctrl_f_overwrite_inactive_bitmap | + link_ctrl_f_post_re_evaluate); + } + +end: + return status; +} + +static QDF_STATUS +ml_nlink_update_force_inactive_num(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *curr, + struct ml_link_force_state *new, + enum mlo_link_force_reason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (new->force_inactive_num != + curr->force_inactive_num || + new->force_inactive_num_bitmap != + curr->force_inactive_num_bitmap) { + status = policy_mgr_mlo_sta_set_nlink( + psoc, wlan_vdev_get_id(vdev), reason, + MLO_LINK_FORCE_MODE_INACTIVE_NUM, + new->force_inactive_num, + new->force_inactive_num_bitmap, + 0, + link_ctrl_f_dynamic_force_link_num | + link_ctrl_f_post_re_evaluate); + } + + return status; +} + +static QDF_STATUS +ml_nlink_update_force_active(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *curr, + struct ml_link_force_state *new, + enum mlo_link_force_reason reason) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +ml_nlink_update_force_active_num(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct ml_link_force_state *curr, + struct ml_link_force_state *new, + enum mlo_link_force_reason reason) +{ + return QDF_STATUS_SUCCESS; +} + +static bool +ml_nlink_all_links_ready_for_state_change(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum ml_nlink_change_event_type evt) +{ + uint8_t ml_num_link = 0; + uint32_t ml_link_bitmap = 0; + uint8_t ml_vdev_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t ml_freq_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t ml_linkid_lst[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct ml_link_info ml_link_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + if (!mlo_check_if_all_links_up(vdev)) + return false; + + if (mlo_mgr_is_link_switch_in_progress(vdev) && + evt != ml_nlink_connect_completion_evt) { + mlo_debug("mlo vdev %d link switch in progress!", + wlan_vdev_get_id(vdev)); + return false; + } + /* For initial connecting to 2 or 3 links ML ap, assoc link and + * non assoc link connected one by one, avoid changing link state + * before link vdev connect completion, to check connected link count. + * If < 2, means non assoc link connect is not completed, disallow + * link state change. + */ + if (!mlo_mgr_is_link_switch_in_progress(vdev) && + evt == ml_nlink_connect_completion_evt) { + ml_nlink_get_link_info(psoc, vdev, NLINK_EXCLUDE_STANDBY_LINK, + QDF_ARRAY_SIZE(ml_linkid_lst), + ml_link_info, ml_freq_lst, ml_vdev_lst, + ml_linkid_lst, &ml_num_link, + &ml_link_bitmap); + if (ml_num_link < 2) + return false; + } + + return true; +} + +/** + * ml_nlink_state_change() - Handle ML STA link force + * with concurrency internal function + * @psoc: PSOC object information + * @reason: reason code of trigger force mode change. + * @evt: event type + * @data: event data + * + * This API handle link force for connected ML STA. + * At present we only support one ML STA. so ml_nlink_get_affect_ml_sta + * is invoked to get one ML STA vdev from policy mgr table. + * + * The flow is to get current force command which has been sent to target + * and compute a new force command based on current connection table. + * If any difference between "current" and "new", driver sends update + * command to target. Driver will update the current force command + * record after get successful respone from target. + * + * Return: QDF_STATUS_SUCCESS if no new command updated to target. + * QDF_STATUS_E_PENDING if new command is sent to target. + * otherwise QDF_STATUS error code + */ +static QDF_STATUS ml_nlink_state_change(struct wlan_objmgr_psoc *psoc, + enum mlo_link_force_reason reason, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data) +{ + struct ml_link_force_state force_state = {0}; + struct ml_link_force_state legacy_intf_force_state = {0}; + struct ml_link_force_state curr_force_state = {0}; + struct wlan_objmgr_vdev *vdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* + * eMLSR is allowed in MCC mode also. So, don't disable any links + * if current connection happens in eMLSR mode. + * eMLSR is handled by wlan_handle_emlsr_sta_concurrency + */ + if (policy_mgr_is_mlo_in_mode_emlsr(psoc, NULL, NULL)) { + mlo_debug("Don't disable eMLSR links"); + goto end; + } + + vdev = ml_nlink_get_affect_ml_sta(psoc); + if (!vdev) + goto end; + if (!ml_nlink_all_links_ready_for_state_change(psoc, vdev, evt)) + goto end; + + ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state); + + ml_nlink_handle_mcc_links(psoc, vdev, &force_state); + + ml_nlink_handle_legacy_intf(psoc, vdev, &legacy_intf_force_state); + + force_state.force_inactive_bitmap |= + legacy_intf_force_state.force_inactive_bitmap; + + if (legacy_intf_force_state.force_inactive_num && + legacy_intf_force_state.force_inactive_num >= + force_state.force_inactive_num) { + force_state.force_inactive_num = + legacy_intf_force_state.force_inactive_num; + force_state.force_inactive_num_bitmap = + legacy_intf_force_state.force_inactive_num_bitmap; + } + + ml_nlink_handle_dynamic_inactive(psoc, vdev, &curr_force_state, + &force_state); + + ml_nlink_update_concurrency_link_request(psoc, vdev, + &force_state, + reason); + + status = ml_nlink_update_no_force_for_all(psoc, vdev, + &curr_force_state, + &force_state, + reason); + if (status == QDF_STATUS_E_PENDING || status != QDF_STATUS_SUCCESS) + goto end; + + status = ml_nlink_update_force_inactive(psoc, vdev, + &curr_force_state, + &force_state, + reason); + if (status == QDF_STATUS_E_PENDING || + (status != QDF_STATUS_SUCCESS && status != QDF_STATUS_E_NOSUPPORT)) + goto end; + + status = ml_nlink_update_force_inactive_num(psoc, vdev, + &curr_force_state, + &force_state, + reason); + if (status == QDF_STATUS_E_PENDING || status != QDF_STATUS_SUCCESS) + goto end; + + /* At present, only force inactive/inactive num mode have been used + * to avoid MCC, force active/active num APIs are no-op for now. + */ + status = ml_nlink_update_force_active(psoc, vdev, + &curr_force_state, + &force_state, + reason); + if (status == QDF_STATUS_E_PENDING || status != QDF_STATUS_SUCCESS) + goto end; + + status = ml_nlink_update_force_active_num(psoc, vdev, + &curr_force_state, + &force_state, + reason); +end: + if (vdev) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); + + if (status == QDF_STATUS_SUCCESS) + mlo_debug("exit no force state change"); + else if (status == QDF_STATUS_E_PENDING) + mlo_debug("exit pending force state change"); + else + mlo_err("exit err %d state change", status); + } + + return status; +} + +/** + * ml_nlink_state_change_handler() - Handle ML STA link force + * with concurrency + * @psoc: PSOC object information + * @vdev: ml sta vdev object + * @reason: reason code of trigger force mode change. + * @evt: event type + * @data: event data + * + * Return: QDF_STATUS_SUCCESS if successfully + */ +static QDF_STATUS +ml_nlink_state_change_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum mlo_link_force_reason reason, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data) +{ + enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev); + uint8_t vdev_id = wlan_vdev_get_id(vdev); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* If WMI_SERVICE_N_LINK_MLO_SUPPORT = 381 is enabled, + * indicate FW support N MLO link & vdev re-purpose between links, + * host will use linkid bitmap to force inactive/active links + * by API ml_nlink_state_change. + * Otherwise, use legacy policy mgr API to inactive/active based + * on vdev id bitmap. + */ + if (ml_is_nlink_service_supported(psoc)) + status = ml_nlink_state_change(psoc, reason, evt, data); + else if (reason == MLO_LINK_FORCE_REASON_CONNECT) + policy_mgr_handle_ml_sta_links_on_vdev_up_csa(psoc, mode, + vdev_id); + else + policy_mgr_handle_ml_sta_links_on_vdev_down(psoc, mode, + vdev_id); + + return status; +} + +static QDF_STATUS +ml_nlink_tdls_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data) +{ + struct ml_link_force_state curr_force_state = {0}; + QDF_STATUS status; + struct set_link_req vendor_req = {0}; + + ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state); + + switch (data->evt.tdls.mode) { + case MLO_LINK_FORCE_MODE_ACTIVE: + if ((data->evt.tdls.link_bitmap & + curr_force_state.force_active_bitmap) == + data->evt.tdls.link_bitmap) { + mlo_debug("link_bitmap 0x%x already active, 0x%x", + data->evt.tdls.link_bitmap, + curr_force_state.force_active_bitmap); + return QDF_STATUS_SUCCESS; + } + if (data->evt.tdls.link_bitmap & + (curr_force_state.force_inactive_bitmap | + curr_force_state.curr_dynamic_inactive_bitmap)) { + mlo_debug("link_bitmap 0x%x can't be active due to concurrency, 0x%x 0x%x", + data->evt.tdls.link_bitmap, + curr_force_state.force_inactive_bitmap, + curr_force_state. + curr_dynamic_inactive_bitmap); + return QDF_STATUS_E_INVAL; + } + break; + case MLO_LINK_FORCE_MODE_NO_FORCE: + if (data->evt.tdls.link_bitmap & + curr_force_state.force_inactive_bitmap) { + mlo_debug("link_bitmap 0x%x can't be no_force due to concurrency, 0x%x", + data->evt.tdls.link_bitmap, + curr_force_state.force_inactive_bitmap); + return QDF_STATUS_E_INVAL; + } + if (!(data->evt.tdls.link_bitmap & + curr_force_state.force_active_bitmap)) { + mlo_debug("link_bitmap 0x%x already no force, 0x%x", + data->evt.tdls.link_bitmap, + curr_force_state.force_active_bitmap); + return QDF_STATUS_SUCCESS; + } + ml_nlink_get_force_link_request(psoc, vdev, &vendor_req, + SET_LINK_FROM_VENDOR_CMD); + if (data->evt.tdls.link_bitmap & + vendor_req.force_active_bitmap) { + mlo_debug("link_bitmap 0x%x active hold by vendor cmd, 0x%x", + data->evt.tdls.link_bitmap, + vendor_req.force_active_bitmap); + return QDF_STATUS_SUCCESS; + } + break; + default: + mlo_err("unhandled for tdls force mode %d", + data->evt.tdls.mode); + return QDF_STATUS_E_INVAL; + } + + if (ml_is_nlink_service_supported(psoc)) + status = policy_mgr_mlo_sta_set_nlink( + psoc, wlan_vdev_get_id(vdev), + data->evt.tdls.reason, + data->evt.tdls.mode, + 0, + data->evt.tdls.link_bitmap, + 0, + 0); + else + status = + policy_mgr_mlo_sta_set_link(psoc, + data->evt.tdls.reason, + data->evt.tdls.mode, + data->evt.tdls.vdev_count, + data->evt.tdls.mlo_vdev_lst); + + return status; +} + +static QDF_STATUS +ml_nlink_vendor_cmd_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data) +{ + struct set_link_req req = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + mlo_debug("link ctrl %d mode %d reason %d num %d 0x%x 0x%x", + data->evt.vendor.link_ctrl_mode, + data->evt.vendor.mode, + data->evt.vendor.reason, + data->evt.vendor.link_num, + data->evt.vendor.link_bitmap, + data->evt.vendor.link_bitmap2); + switch (data->evt.vendor.link_ctrl_mode) { + case LINK_CONTROL_MODE_DEFAULT: + ml_nlink_clr_force_link_request(psoc, vdev, + SET_LINK_FROM_VENDOR_CMD); + break; + case LINK_CONTROL_MODE_USER: + req.mode = data->evt.vendor.mode; + req.reason = data->evt.vendor.reason; + req.force_active_bitmap = data->evt.vendor.link_bitmap; + req.force_inactive_bitmap = data->evt.vendor.link_bitmap2; + ml_nlink_update_force_link_request(psoc, vdev, &req, + SET_LINK_FROM_VENDOR_CMD); + break; + case LINK_CONTROL_MODE_MIXED: + req.mode = data->evt.vendor.mode; + req.reason = data->evt.vendor.reason; + req.force_active_num = data->evt.vendor.link_num; + req.force_active_num_bitmap = data->evt.vendor.link_bitmap; + ml_nlink_update_force_link_request(psoc, vdev, &req, + SET_LINK_FROM_VENDOR_CMD); + break; + default: + status = QDF_STATUS_E_INVAL; + } + + return status; +} + +static QDF_STATUS +ml_nlink_swtich_dynamic_inactive_link(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t link_id; + uint32_t standby_link_bitmap, dynamic_inactive_bitmap; + struct ml_link_force_state curr_force_state = {0}; + uint8_t link_ids[MAX_MLO_LINK_ID]; + uint8_t num_ids; + + link_id = wlan_vdev_get_link_id(vdev); + if (link_id >= MAX_MLO_LINK_ID) { + mlo_err("invalid link id %d", link_id); + return QDF_STATUS_E_INVAL; + } + + ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state); + standby_link_bitmap = ml_nlink_get_standby_link_bitmap(psoc, vdev); + standby_link_bitmap &= curr_force_state.force_inactive_num_bitmap & + ~(1 << link_id); + /* In DBS RD, ML STA 2+5+6(standby link), force inactive num = 1 and + * force inactive bitmap with 5 + 6 links will be sent to FW, host + * will select 6G as dynamic inactive link, 5G vdev will be kept in + * policy mgr active connection table. + * If FW link switch and repurpose 5G vdev to 6G, host will need to + * select 5G standby link as dynamic inactive. + * Then 6G vdev can be moved to policy mgr active connection table. + */ + if (((1 << link_id) & curr_force_state.curr_dynamic_inactive_bitmap) && + ((1 << link_id) & curr_force_state.force_inactive_num_bitmap) && + !(standby_link_bitmap & + curr_force_state.curr_dynamic_inactive_bitmap) && + (standby_link_bitmap & + curr_force_state.force_inactive_num_bitmap)) { + num_ids = convert_link_bitmap_to_link_ids( + standby_link_bitmap, + QDF_ARRAY_SIZE(link_ids), + link_ids); + if (!num_ids) { + mlo_err("unexpected 0 link ids for bitmap 0x%x", + standby_link_bitmap); + return QDF_STATUS_E_INVAL; + } + /* Remove the link from dynamic inactive bitmap, + * add the standby link to dynamic inactive bitmap. + */ + dynamic_inactive_bitmap = + curr_force_state.curr_dynamic_inactive_bitmap & + ~(1 << link_id); + dynamic_inactive_bitmap |= 1 << link_ids[0]; + mlo_debug("move out vdev %d link id %d from dynamic inactive, add standby link id %d", + wlan_vdev_get_id(vdev), link_id, link_ids[0]); + ml_nlink_set_dynamic_inactive_links(psoc, vdev, + dynamic_inactive_bitmap); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ml_nlink_conn_change_notify(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum ml_nlink_change_event_type evt, + struct ml_nlink_change_event *data) +{ + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE mode; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ml_link_force_state curr_force_state = {0}; + bool is_set_link_in_progress = policy_mgr_is_set_link_in_progress(psoc); + bool is_host_force; + + mlo_debug("vdev %d %s(%d)", vdev_id, link_evt_to_string(evt), + evt); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLO_MGR_ID); + if (!vdev) { + mlo_err("invalid vdev id %d ", vdev_id); + return QDF_STATUS_E_INVAL; + } + mode = wlan_vdev_mlme_get_opmode(vdev); + + switch (evt) { + case ml_nlink_link_switch_start_evt: + if (data->evt.link_switch.reason == + MLO_LINK_SWITCH_REASON_HOST_FORCE) { + is_host_force = true; + } else { + is_host_force = false; + } + + mlo_debug("set_link_in_prog %d reason %d", + is_set_link_in_progress, + data->evt.link_switch.reason); + + if (is_set_link_in_progress) { + /* If set active is in progress then only accept host + * force link switch requests from FW + */ + if (is_host_force) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_INVAL; + break; + } else if (is_host_force) { + /* If set active is not in progress but FW sent host + * force then reject the link switch + */ + status = QDF_STATUS_E_INVAL; + break; + } + + ml_nlink_get_curr_force_state(psoc, vdev, &curr_force_state); + if ((1 << data->evt.link_switch.new_ieee_link_id) & + curr_force_state.force_inactive_bitmap) { + mlo_debug("target link %d is force inactive, don't switch to it", + data->evt.link_switch.new_ieee_link_id); + status = QDF_STATUS_E_INVAL; + } + break; + case ml_nlink_link_switch_pre_completion_evt: + status = ml_nlink_swtich_dynamic_inactive_link( + psoc, vdev); + break; + case ml_nlink_roam_sync_start_evt: + ml_nlink_clr_force_state(psoc, vdev); + break; + case ml_nlink_roam_sync_completion_evt: + status = ml_nlink_state_change_handler( + psoc, vdev, MLO_LINK_FORCE_REASON_CONNECT, + evt, data); + break; + case ml_nlink_connect_start_evt: + ml_nlink_clr_force_state(psoc, vdev); + break; + case ml_nlink_connect_completion_evt: + status = ml_nlink_state_change_handler( + psoc, vdev, MLO_LINK_FORCE_REASON_CONNECT, + evt, data); + break; + case ml_nlink_disconnect_start_evt: + ml_nlink_clr_force_state(psoc, vdev); + break; + case ml_nlink_disconnect_completion_evt: + status = ml_nlink_state_change_handler( + psoc, vdev, MLO_LINK_FORCE_REASON_DISCONNECT, + evt, data); + break; + case ml_nlink_ap_started_evt: + status = ml_nlink_state_change_handler( + psoc, vdev, MLO_LINK_FORCE_REASON_CONNECT, + evt, data); + break; + case ml_nlink_ap_stopped_evt: + status = ml_nlink_state_change_handler( + psoc, vdev, MLO_LINK_FORCE_REASON_DISCONNECT, + evt, data); + break; + case ml_nlink_connection_updated_evt: + if (mode == QDF_STA_MODE && + (MLME_IS_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) || + MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id))) { + mlo_debug("vdev id %d in roam sync", vdev_id); + break; + } + status = ml_nlink_state_change_handler( + psoc, vdev, MLO_LINK_FORCE_REASON_CONNECT, + evt, data); + break; + case ml_nlink_tdls_request_evt: + status = ml_nlink_tdls_event_handler( + psoc, vdev, evt, data); + break; + case ml_nlink_vendor_cmd_request_evt: + status = ml_nlink_vendor_cmd_handler( + psoc, vdev, evt, data); + break; + default: + break; + } + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); + + return status; +} + +void +ml_nlink_vendor_command_set_link(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum link_control_modes link_control_mode, + enum mlo_link_force_reason reason, + enum mlo_link_force_mode mode, + uint8_t link_num, + uint16_t link_bitmap, + uint16_t link_bitmap2) +{ + struct ml_nlink_change_event data; + + qdf_mem_zero(&data, sizeof(data)); + data.evt.vendor.link_ctrl_mode = link_control_mode; + data.evt.vendor.mode = mode; + data.evt.vendor.reason = reason; + data.evt.vendor.link_num = link_num; + data.evt.vendor.link_bitmap = link_bitmap; + data.evt.vendor.link_bitmap2 = link_bitmap2; + + ml_nlink_conn_change_notify( + psoc, vdev_id, + ml_nlink_vendor_cmd_request_evt, &data); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c new file mode 100644 index 0000000000..42ea2dc152 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c @@ -0,0 +1,1687 @@ +/* + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains MLO manager roaming related functionality + */ +#include +#include +#include +#include "wlan_mlo_mgr_cmn.h" +#include "wlan_mlo_mgr_main.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_mlo_mgr_public_structs.h" +#include "wlan_mlo_mgr_sta.h" +#include <../../core/src/wlan_cm_roam_i.h> +#include "wlan_cm_roam_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include +#include +#include +#include +#include "wlan_mlo_link_force.h" + +#ifdef WLAN_FEATURE_11BE_MLO +static bool +mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx = vdev->mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + uint8_t i = 0; + + if (!mlo_dev_ctx) + return false; + + sta_ctx = mlo_dev_ctx->sta_ctx; + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + if (vdev == mlo_dev_ctx->wlan_vdev_list[i]) + return qdf_test_bit(i, sta_ctx->wlan_connect_req_links); + } + + mlo_err("vdev:%d not found in ml dev ctx list", wlan_vdev_get_id(vdev)); + + return false; +} + +static void +mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t ml_link_vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + ml_link_vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlo_err("VDEV is null"); + return; + } + + if (vdev_id == ml_link_vdev_id) { + wlan_vdev_mlme_set_mlo_vdev(vdev); + goto end; + } + + wlan_vdev_mlme_set_mlo_vdev(vdev); + wlan_vdev_mlme_set_mlo_link_vdev(vdev); + + mlo_update_connect_req_links(vdev, true); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +static void +mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links) +{ + /* + * Cleanup the non-assoc link link in below cases, + * 1. Roamed to single link-MLO AP + * 2. Roamed to an MLO AP but 4-way handshake is offloaded to + * userspace, i.e.auth_status = ROAM_AUTH_STATUS_CONNECTED + * 3. Roamed to non-MLO AP(num_setup_links = 0) + * This covers all supported combinations. So cleanup the link always. + */ + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + cm_cleanup_mlo_link(vdev); + /* + * Clear the MLO vdev flag when roam to a non-MLO AP to prepare the + * roam done indication to userspace in non-MLO format + * i.e. without MLD/link info + */ + else if (wlan_vdev_mlme_is_mlo_vdev(vdev) && !num_setup_links) + wlan_vdev_mlme_clear_mlo_vdev(vdev); +} + +static void +mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t num_setup_links) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint8_t i; + struct wlan_objmgr_vdev *vdev, *tmp_vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlo_err("VDEV:%d is null", vdev_id); + return; + } + + if (!vdev->mlo_dev_ctx) + goto end; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + tmp_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + mlo_cleanup_link(tmp_vdev, num_setup_links); + } + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +static void +mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlo_err("VDEV is null"); + return; + } + + mlo_clear_connect_req_links_bmap(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +static QDF_STATUS +mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc, + uint8_t *event, uint8_t vdev_id) +{ + struct roam_offload_synch_ind *sync_ind = NULL; + + sync_ind = (struct roam_offload_synch_ind *)event; + + if (!sync_ind) { + mlme_err("Roam Sync ind ptr is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_mlo_roam_abort_on_link(psoc, event, sync_ind->roamed_vdev_id); + + return QDF_STATUS_SUCCESS; +} +#else +static inline void +mlo_clear_link_bmap(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{} + +static inline void +mlo_update_vdev_after_roam(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t num_setup_links) +{} + +static inline void +mlo_cleanup_link(struct wlan_objmgr_vdev *vdev, uint8_t num_setup_links) +{} + +static inline void +mlo_update_for_multi_link_roam(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t ml_link_vdev_id) +{} + +static inline bool +mlo_check_connect_req_bmap(struct wlan_objmgr_vdev *vdev) +{ + return false; +} + +static inline QDF_STATUS +mlo_roam_abort_req(struct wlan_objmgr_psoc *psoc, + uint8_t *event, uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +static void mlo_roam_update_vdev_macaddr(struct wlan_objmgr_psoc *psoc, + struct roam_offload_synch_ind *sync_ind, + uint8_t vdev_id, + bool is_non_ml_connection) +{ + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr *mld_mac; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLO_MGR_ID); + if (!vdev) { + mlo_err("VDEV is null"); + return; + } + + if (is_non_ml_connection) { + mld_mac = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + if (!qdf_is_macaddr_zero(mld_mac)) + wlan_vdev_mlme_set_macaddr(vdev, mld_mac->bytes); + } else { + struct qdf_mac_addr *vdev_link_addr; + uint8_t i; + + wlan_vdev_mlme_set_macaddr(vdev, + wlan_vdev_mlme_get_linkaddr(vdev)); + /* Update the link address received from fw to assoc vdev */ + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (vdev_id != sync_ind->ml_link[i].vdev_id) + continue; + + vdev_link_addr = &sync_ind->ml_link[i].self_link_addr; + if (qdf_is_macaddr_zero(vdev_link_addr) || + qdf_is_macaddr_broadcast(vdev_link_addr)) + continue; + + wlan_vdev_mlme_set_macaddr(vdev, vdev_link_addr->bytes); + wlan_vdev_mlme_set_linkaddr(vdev, + vdev_link_addr->bytes); + } + } + + mlme_debug("vdev_id %d self mac " QDF_MAC_ADDR_FMT, + vdev_id, + QDF_MAC_ADDR_REF(wlan_vdev_mlme_get_macaddr(vdev))); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); +} + +QDF_STATUS mlo_fw_roam_sync_req(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + void *event, uint32_t event_data_len) +{ + struct roam_offload_synch_ind *sync_ind; + QDF_STATUS status; + uint8_t i; + bool is_non_mlo_ap = false; + + sync_ind = (struct roam_offload_synch_ind *)event; + if (!sync_ind) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < sync_ind->num_setup_links; i++) + mlo_update_for_multi_link_roam(psoc, vdev_id, + sync_ind->ml_link[i].vdev_id); + + if (!sync_ind->num_setup_links) { + mlo_debug("MLO_ROAM: Roamed to Legacy"); + is_non_mlo_ap = true; + mlo_set_single_link_ml_roaming(psoc, vdev_id, false); + } else if (sync_ind->num_setup_links == 1 || + sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) { + mlo_debug("MLO_ROAM: Roamed to single link MLO"); + mlo_set_single_link_ml_roaming(psoc, vdev_id, true); + } else { + mlo_debug("MLO_ROAM: Roamed to MLO with %d links", + sync_ind->num_setup_links); + mlo_set_single_link_ml_roaming(psoc, vdev_id, false); + } + + mlo_roam_update_vdev_macaddr(psoc, sync_ind, vdev_id, is_non_mlo_ap); + ml_nlink_conn_change_notify( + psoc, vdev_id, ml_nlink_roam_sync_start_evt, NULL); + + status = cm_fw_roam_sync_req(psoc, vdev_id, event, event_data_len); + + if (QDF_IS_STATUS_ERROR(status)) + mlo_clear_link_bmap(psoc, vdev_id); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static struct mlo_link_info * +mlo_mgr_get_link_info_by_self_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *self_addr) +{ + uint8_t iter; + struct mlo_link_info *mlo_link; + + if (!vdev || !vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->link_ctx || + !self_addr || qdf_is_macaddr_zero(self_addr)) + return NULL; + + for (iter = 0; iter < WLAN_MAX_ML_BSS_LINKS; iter++) { + mlo_link = &vdev->mlo_dev_ctx->link_ctx->links_info[iter]; + + if (qdf_is_macaddr_equal(&mlo_link->link_addr, self_addr)) + return mlo_link; + } + + return NULL; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +uint8_t mlo_mgr_num_roam_links(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_cm_connect_resp *reassoc_rsp; + + if (!vdev->mlo_dev_ctx) + return 1; + + if (!vdev->mlo_dev_ctx->sta_ctx) + return 0; + + reassoc_rsp = vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp; + if (!reassoc_rsp || !reassoc_rsp->roaming_info) + return 0; + + return reassoc_rsp->roaming_info->num_setup_links; +} +#endif + +void mlo_mgr_roam_update_ap_link_info(struct wlan_objmgr_vdev *vdev, + struct ml_setup_link_param *src_link_info, + struct wlan_channel *channel) +{ + struct mlo_link_info *link_info; + + if (!src_link_info) + return; + + link_info = mlo_mgr_get_link_info_by_self_addr(vdev, + &src_link_info->self_link_addr); + if (!link_info) { + mlo_err("No link info found for vdev %d with " QDF_MAC_ADDR_FMT, + src_link_info->vdev_id, + QDF_MAC_ADDR_REF(src_link_info->self_link_addr.bytes)); + QDF_BUG(0); + return; + } + + if (link_info->vdev_id != src_link_info->vdev_id) { + mlo_err("Host(%d)-FW(%d) VDEV-MAC addr mismatch", + link_info->vdev_id, src_link_info->vdev_id); + QDF_BUG(0); + return; + } + + link_info->link_id = src_link_info->link_id; + qdf_copy_macaddr(&link_info->ap_link_addr, &src_link_info->link_addr); + qdf_mem_copy(link_info->link_chan_info, channel, sizeof(*channel)); + + mlo_debug("link_id: %d, vdev_id:%d freq:%d ap_link_addr: "QDF_MAC_ADDR_FMT", self_link_addr: "QDF_MAC_ADDR_FMT, + link_info->link_id, link_info->vdev_id, + link_info->link_chan_info->ch_freq, + QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes), + QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); +} + +QDF_STATUS mlo_cm_roam_sync_cb(struct wlan_objmgr_vdev *vdev, + void *event, uint32_t event_data_len) +{ + QDF_STATUS status; + struct roam_offload_synch_ind *sync_ind; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *link_vdev = NULL; + uint8_t i; + uint8_t vdev_id; + + sync_ind = (struct roam_offload_synch_ind *)event; + vdev_id = wlan_vdev_get_id(vdev); + psoc = wlan_vdev_get_psoc(vdev); + + /* Clean up link vdev in following cases + * 1. When roamed to legacy, num_setup_links = 0 + * 2. When roamed to single link, num_setup_links = 1 + * 3. Roamed to AP with auth_status = ROAMED_AUTH_STATUS_CONNECTED + */ + if (sync_ind->num_setup_links < 2 || + sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) { + mlme_debug("Roam auth status %d", sync_ind->auth_status); + mlo_update_vdev_after_roam(psoc, vdev_id, + sync_ind->num_setup_links); + } + + /* If EAPOL is offloaded to supplicant, link vdev/s are not up + * at FW, in that case complete roam sync on assoc vdev + * link vdev will be initialized after set key is complete. + */ + if (sync_ind->auth_status == ROAM_AUTH_STATUS_CONNECTED) + return QDF_STATUS_SUCCESS; + + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (vdev_id == sync_ind->ml_link[i].vdev_id) + continue; + + /* Standby Link */ + if (sync_ind->ml_link[i].vdev_id == WLAN_INVALID_VDEV_ID) + continue; + + link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + sync_ind->ml_link[i].vdev_id, + WLAN_MLME_SB_ID); + if (!link_vdev) { + mlo_err("Link vdev:%d is null", + sync_ind->ml_link[i].vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (mlo_check_connect_req_bmap(link_vdev)) { + struct qdf_mac_addr *vdev_link_addr; + + mlo_update_connect_req_links(link_vdev, false); + + vdev_link_addr = &sync_ind->ml_link[i].self_link_addr; + if (!qdf_is_macaddr_zero(vdev_link_addr) && + !qdf_is_macaddr_broadcast(vdev_link_addr)) { + wlan_vdev_mlme_set_macaddr(link_vdev, + vdev_link_addr->bytes); + wlan_vdev_mlme_set_linkaddr(link_vdev, + vdev_link_addr->bytes); + } + + status = cm_fw_roam_sync_req(psoc, + sync_ind->ml_link[i].vdev_id, + event, event_data_len); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_clear_connect_req_links_bmap(link_vdev); + mlo_roam_abort_req(psoc, event, + sync_ind->ml_link[i].vdev_id); + wlan_objmgr_vdev_release_ref(link_vdev, + WLAN_MLME_SB_ID); + return QDF_STATUS_E_FAILURE; + } + } + wlan_objmgr_vdev_release_ref(link_vdev, + WLAN_MLME_SB_ID); + } + + return QDF_STATUS_SUCCESS; +} +#endif + +void +mlo_fw_ho_fail_req(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct qdf_mac_addr bssid) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint8_t i; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + + if (!vdev) { + mlo_err("vdev is null"); + return; + } + + if (!vdev->mlo_dev_ctx) + goto end; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i] || + mlo_dev_ctx->wlan_vdev_list[i] == vdev) + continue; + cm_fw_ho_fail_req(psoc, + wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]), + bssid); + } + +end: + cm_fw_ho_fail_req(psoc, vdev_id, bssid); + wlan_objmgr_vdev_release_ref(vdev, + WLAN_MLME_SB_ID); +} + +QDF_STATUS +mlo_get_sta_link_mac_addr(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + struct qdf_mac_addr *link_mac_addr) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + + if (!sync_ind || !sync_ind->num_setup_links) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (sync_ind->ml_link[i].vdev_id == vdev_id) { + qdf_copy_macaddr(link_mac_addr, + &sync_ind->ml_link[i].link_addr); + return status; + } + } + + if (i == sync_ind->num_setup_links) { + mlo_err("Link mac addr not found"); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +uint32_t +mlo_roam_get_chan_freq(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + uint8_t i; + + if (!sync_ind || !sync_ind->num_setup_links) + return 0; + + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (sync_ind->ml_link[i].vdev_id == vdev_id) + return sync_ind->ml_link[i].channel.mhz; + } + + return 0; +} + +uint32_t +mlo_roam_get_link_id(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + uint8_t i; + + if (!sync_ind || !sync_ind->num_setup_links) + return 0; + + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (sync_ind->ml_link[i].vdev_id == vdev_id) + return sync_ind->ml_link[i].link_id; + } + + return 0; +} + +bool is_multi_link_roam(struct roam_offload_synch_ind *sync_ind) +{ + if (!sync_ind) + return false; + + if (sync_ind->num_setup_links) + return true; + + return false; +} + +uint8_t +mlo_roam_get_num_of_setup_links(struct roam_offload_synch_ind *sync_ind) +{ + if (!sync_ind) { + mlo_err("Roam Sync ind is null"); + return WLAN_INVALID_VDEV_ID; + } + + return sync_ind->num_setup_links; +} + +uint32_t +mlo_roam_get_link_freq_from_mac_addr(struct roam_offload_synch_ind *sync_ind, + uint8_t *link_mac_addr) +{ + uint8_t i; + + if (!sync_ind) + return 0; + + /* Non-MLO roaming */ + if (!sync_ind->num_setup_links) + return sync_ind->chan_freq; + + if (!link_mac_addr) { + mlo_debug("link_mac_addr is NULL"); + return 0; + } + + for (i = 0; i < sync_ind->num_setup_links; i++) + if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes, + link_mac_addr, + QDF_MAC_ADDR_SIZE)) + return sync_ind->ml_link[i].channel.mhz; + + mlo_debug("Mac address not found in ml_link info" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(link_mac_addr)); + + return 0; +} + +QDF_STATUS +mlo_roam_get_link_id_from_mac_addr(struct roam_offload_synch_ind *sync_ind, + uint8_t *link_mac_addr, uint32_t *link_id) +{ + uint8_t i; + + if (!sync_ind || !sync_ind->num_setup_links || !link_mac_addr) + return QDF_STATUS_E_INVAL; + + for (i = 0; i < sync_ind->num_setup_links; i++) + if (!qdf_mem_cmp(sync_ind->ml_link[i].link_addr.bytes, + link_mac_addr, + QDF_MAC_ADDR_SIZE)) { + *link_id = sync_ind->ml_link[i].link_id; + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS mlo_enable_rso(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct wlan_objmgr_vdev *assoc_vdev; + uint8_t num_partner_links; + + if (!rsp) { + mlo_err("Connect resp is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + num_partner_links = rsp->ml_parnter_info.num_partner_links; + + if (num_partner_links && + (!wlan_vdev_mlme_is_mlo_link_vdev(vdev) || + !mlo_check_if_all_links_up(vdev))) + return QDF_STATUS_SUCCESS; + + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + if (!assoc_vdev) { + mlo_err("Assoc vdev is null"); + return QDF_STATUS_E_NULL_VALUE; + } + cm_roam_start_init_on_connect(pdev, wlan_vdev_get_id(assoc_vdev)); + + return QDF_STATUS_SUCCESS; +} + +void +mlo_roam_copy_partner_info(struct mlo_partner_info *partner_info, + struct roam_offload_synch_ind *sync_ind, + uint8_t skip_vdev_id, bool fill_all_links) +{ + uint8_t i, j; + struct mlo_link_info *link; + + if (!sync_ind) + return; + + for (i = 0, j = 0; i < sync_ind->num_setup_links; i++) { + if (!fill_all_links && + sync_ind->ml_link[i].vdev_id == skip_vdev_id) + continue; + + link = &partner_info->partner_link_info[j]; + link->link_id = sync_ind->ml_link[i].link_id; + link->vdev_id = sync_ind->ml_link[i].vdev_id; + + qdf_copy_macaddr(&link->link_addr, + &sync_ind->ml_link[i].link_addr); + link->chan_freq = sync_ind->ml_link[i].channel.mhz; + mlo_debug("vdev_id %d link_id %d freq %d bssid" QDF_MAC_ADDR_FMT, + link->vdev_id, link->link_id, link->chan_freq, + QDF_MAC_ADDR_REF(link->link_addr.bytes)); + j++; + } + partner_info->num_partner_links = j; + mlo_debug("vdev_to_skip:%d num_setup_links %d fill_all_links:%d", + skip_vdev_id, partner_info->num_partner_links, + fill_all_links); +} + +void mlo_roam_init_cu_bpcc(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind) +{ + uint8_t i; + struct wlan_mlo_dev_context *mlo_dev_ctx; + + if (!vdev) { + mlo_err("vdev is NULL"); + return; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + mlo_err("ML dev ctx is NULL"); + return; + } + + mlo_clear_cu_bpcc(vdev); + for (i = 0; i < sync_ind->num_setup_links; i++) + mlo_init_cu_bpcc(mlo_dev_ctx, sync_ind->ml_link[i].vdev_id); + + mlo_debug("update cu info from roam sync"); +} + +void +mlo_roam_update_connected_links(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *connect_rsp) +{ + mlo_clear_connected_links_bmap(vdev); + if (mlo_get_single_link_ml_roaming(wlan_vdev_get_psoc(vdev), + wlan_vdev_get_id(vdev))) + mlo_update_connected_links(vdev, 1); + else + mlo_update_connected_links_bmap(vdev->mlo_dev_ctx, + connect_rsp->ml_parnter_info); +} + +QDF_STATUS +wlan_mlo_roam_abort_on_link(struct wlan_objmgr_psoc *psoc, + uint8_t *event, uint8_t vdev_id) +{ + uint8_t i; + QDF_STATUS status; + struct roam_offload_synch_ind *sync_ind = NULL; + + sync_ind = (struct roam_offload_synch_ind *)event; + + if (!sync_ind) { + mlo_err("Roam Sync ind ptr is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (sync_ind->ml_link[i].vdev_id != vdev_id) { + status = cm_fw_roam_abort_req(psoc, + sync_ind->ml_link[i].vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_err("LFR3: Fail to abort roam on vdev: %u", + sync_ind->ml_link[i].vdev_id); + } + } + } + + return QDF_STATUS_SUCCESS; +} + +void +mlo_set_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_single_link_ml_roaming) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlo_err("VDEV is null"); + return; + } + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + mlme_set_single_link_mlo_roaming(vdev, + is_single_link_ml_roaming); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +bool +mlo_get_single_link_ml_roaming(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + bool is_single_link_ml_roaming = false; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + mlo_err("VDEV is null"); + return is_single_link_ml_roaming; + } + + is_single_link_ml_roaming = mlme_get_single_link_mlo_roaming(vdev); + mlo_debug("MLO:is_single_link_ml_roaming %d", + is_single_link_ml_roaming); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + + return is_single_link_ml_roaming; +} + +QDF_STATUS +mlo_roam_get_bssid_chan_for_link(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + struct qdf_mac_addr *bssid, + wmi_channel *chan) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + + if (!sync_ind || !sync_ind->num_setup_links) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < sync_ind->num_setup_links; i++) { + if (vdev_id == sync_ind->ml_link[i].vdev_id) { + qdf_mem_copy(chan, &sync_ind->ml_link[i].channel, + sizeof(wmi_channel)); + qdf_copy_macaddr(bssid, + &sync_ind->ml_link[i].link_addr); + return status; + } + } + + if (i == sync_ind->num_setup_links) { + mlo_err("roam sync info not found for vdev id %d", vdev_id); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +bool +mlo_check_if_all_links_up(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + uint8_t i; + + if (!vdev || !vdev->mlo_dev_ctx) { + mlo_err("Vdev is null"); + return false; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx->sta_ctx) { + mlo_err("mlo sta ctx is null"); + return false; + } + + sta_ctx = mlo_dev_ctx->sta_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + if (qdf_test_bit(i, sta_ctx->wlan_connected_links) && + !wlan_cm_is_vdev_connected(mlo_dev_ctx->wlan_vdev_list[i])) { + mlo_debug("Vdev id %d is not in connected state", + wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i])); + return false; + } + } + + if (i == WLAN_UMAC_MLO_MAX_VDEVS) { + mlo_debug("all links are up"); + return true; + } + + return false; +} + +bool +mlo_check_if_all_vdev_up(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + uint8_t i; + + if (!vdev || !vdev->mlo_dev_ctx) { + mlo_err("Vdev is null"); + return false; + } + + if (QDF_IS_STATUS_ERROR(wlan_vdev_is_up(vdev))) { + mlo_debug("Vdev id %d is not in up state", + wlan_vdev_get_id(vdev)); + return false; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx->sta_ctx) { + mlo_err("mlo sta ctx is null"); + return false; + } + sta_ctx = mlo_dev_ctx->sta_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + if ((qdf_test_bit(i, sta_ctx->wlan_connected_links) || + qdf_test_bit(i, sta_ctx->wlan_connect_req_links)) && + !QDF_IS_STATUS_SUCCESS(wlan_vdev_is_up(mlo_dev_ctx->wlan_vdev_list[i]))) { + mlo_debug("Vdev id %d is not in up state", + wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i])); + return false; + } + } + + if (i == WLAN_UMAC_MLO_MAX_VDEVS) { + mlo_debug("all links are up"); + return true; + } + + return false; +} + +void +mlo_roam_set_link_id(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind) +{ + uint8_t i; + uint8_t j; + struct wlan_mlo_dev_context *mlo_dev_ctx; + + if (!vdev || !sync_ind || !vdev->mlo_dev_ctx) { + mlo_debug("Invalid input"); + return; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!vdev) + continue; + + wlan_vdev_set_link_id(vdev, WLAN_LINK_ID_INVALID); + for (j = 0; j < sync_ind->num_setup_links; j++) { + if (sync_ind->ml_link[j].vdev_id == + wlan_vdev_get_id(vdev)) { + wlan_vdev_set_link_id( + vdev, sync_ind->ml_link[j].link_id); + mlme_debug("Set link for vdev id %d link id %d", + wlan_vdev_get_id(vdev), + sync_ind->ml_link[j].link_id); + } + } + } +} + +QDF_STATUS +mlo_get_link_mac_addr_from_reassoc_rsp(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *link_mac_addr) +{ + uint8_t i; + struct wlan_mlo_sta *sta_ctx; + struct wlan_cm_connect_resp *rsp; + struct mlo_partner_info parnter_info; + uint8_t vdev_id; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + vdev_id = wlan_vdev_get_id(vdev); + + if (!vdev->mlo_dev_ctx) { + mlo_err("mlo dev ctx is null, vdev id %d", vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || + !sta_ctx->copied_reassoc_rsp->roaming_info) { + mlo_debug("sta ctx or copied reassoc rsp is null for vdev id %d", vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + rsp = sta_ctx->copied_reassoc_rsp; + if (rsp->roaming_info->auth_status != ROAM_AUTH_STATUS_CONNECTED) { + mlo_debug("Roam auth status is not connected"); + return QDF_STATUS_E_FAILURE; + } + + parnter_info = rsp->ml_parnter_info; + for (i = 0; i < parnter_info.num_partner_links; i++) { + if (parnter_info.partner_link_info[i].vdev_id == vdev_id) { + qdf_copy_macaddr(link_mac_addr, + &parnter_info.partner_link_info[i].link_addr); + return QDF_STATUS_SUCCESS; + } + } + + if (i == parnter_info.num_partner_links) { + mlo_debug("Link mac addr not found"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +mlo_roam_copy_reassoc_rsp(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *reassoc_rsp) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + struct wlan_connect_rsp_ies *connect_ies; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + if (!reassoc_rsp) + return QDF_STATUS_E_NULL_VALUE; + + /* Store reassoc rsp only if roamed to 2 link AP */ + if (reassoc_rsp->ml_parnter_info.num_partner_links < 2) + return QDF_STATUS_E_INVAL; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) + return QDF_STATUS_E_NULL_VALUE; + + sta_ctx = mlo_dev_ctx->sta_ctx; + if (!sta_ctx) + return QDF_STATUS_E_NULL_VALUE; + + wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); + /* Free assoc rsp, so that reassoc rsp can be used during + * reassociation. + */ + if (sta_ctx->assoc_rsp.ptr) { + qdf_mem_free(sta_ctx->assoc_rsp.ptr); + sta_ctx->assoc_rsp.ptr = NULL; + sta_ctx->assoc_rsp.len = 0; + } + + sta_ctx->ml_partner_info = reassoc_rsp->ml_parnter_info; + + sta_ctx->copied_reassoc_rsp = qdf_mem_malloc( + sizeof(struct wlan_cm_connect_resp)); + if (!sta_ctx->copied_reassoc_rsp) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(sta_ctx->copied_reassoc_rsp, reassoc_rsp, + sizeof(struct wlan_cm_connect_resp)); + + sta_ctx->copied_reassoc_rsp->roaming_info = qdf_mem_malloc( + sizeof(struct wlan_roam_sync_info)); + + if (!sta_ctx->copied_reassoc_rsp->roaming_info) { + qdf_mem_free(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(sta_ctx->copied_reassoc_rsp->roaming_info, + reassoc_rsp->roaming_info, + sizeof(struct wlan_roam_sync_info)); + + connect_ies = &sta_ctx->copied_reassoc_rsp->connect_ies; + + connect_ies->assoc_rsp.len = + reassoc_rsp->connect_ies.assoc_rsp.len; + + connect_ies->assoc_rsp.ptr = qdf_mem_malloc( + connect_ies->assoc_rsp.len); + + if (!connect_ies->assoc_rsp.ptr) { + qdf_mem_free(sta_ctx->copied_reassoc_rsp->roaming_info); + sta_ctx->copied_reassoc_rsp->roaming_info = NULL; + qdf_mem_free(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(connect_ies->assoc_rsp.ptr, + reassoc_rsp->connect_ies.assoc_rsp.ptr, + reassoc_rsp->connect_ies.assoc_rsp.len); + + connect_ies->assoc_req.len = 0; + connect_ies->assoc_req.ptr = NULL; + connect_ies->bcn_probe_rsp.len = 0; + connect_ies->bcn_probe_rsp.ptr = NULL; + connect_ies->link_bcn_probe_rsp.len = 0; + connect_ies->link_bcn_probe_rsp.ptr = NULL; + connect_ies->fils_ie = NULL; + + mlo_debug("Copied reassoc response for vdev: %d len: %d", + wlan_vdev_get_id(vdev), connect_ies->assoc_rsp.len); + + return QDF_STATUS_SUCCESS; +} + +static bool +mlo_roam_is_internal_disconnect(struct wlan_objmgr_vdev *link_vdev) +{ + struct wlan_cm_vdev_discon_req *disconn_req; + + if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && + wlan_cm_is_vdev_disconnecting(link_vdev)) { + mlo_debug("Disconnect is ongoing on vdev %d", + wlan_vdev_get_id(link_vdev)); + + disconn_req = qdf_mem_malloc(sizeof(*disconn_req)); + if (!disconn_req) { + mlme_err("Malloc failed for disconnect req"); + return false; + } + + if (!wlan_cm_get_active_disconnect_req(link_vdev, + disconn_req)) { + mlme_err("vdev: %d: Active disconnect not found", + wlan_vdev_get_id(link_vdev)); + qdf_mem_free(disconn_req); + return false; + } + + mlo_debug("Disconnect source %d", disconn_req->req.source); + + if (disconn_req->req.source == CM_MLO_ROAM_INTERNAL_DISCONNECT) { + qdf_mem_free(disconn_req); + return true; + } + + qdf_mem_free(disconn_req); + } + /* Disconnect is not ongoing */ + return true; +} + +static QDF_STATUS +mlo_roam_validate_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_vdev *link_vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + + if (!vdev) { + mlo_debug_rl("vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + mlo_debug_rl("mlo_dev_ctx is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + sta_ctx = mlo_dev_ctx->sta_ctx; + if (sta_ctx && sta_ctx->disconn_req) { + mlo_debug("Handle pending disconnect for vdev %d", + wlan_vdev_get_id(vdev)); + mlo_handle_pending_disconnect(vdev); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_cm_is_vdev_disconnected(vdev) || + (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && + (wlan_cm_is_vdev_connecting(link_vdev) || + !mlo_roam_is_internal_disconnect(link_vdev)))) { + if (sta_ctx) { + if (sta_ctx->copied_reassoc_rsp) { + wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; + } + copied_conn_req_lock_acquire(sta_ctx); + if (sta_ctx->copied_conn_req) { + wlan_cm_free_connect_req(sta_ctx->copied_conn_req); + sta_ctx->copied_conn_req = NULL; + } + copied_conn_req_lock_release(sta_ctx); + } + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) { + mlo_debug("Vdev: %d", wlan_vdev_get_id(vdev)); + if (wlan_cm_is_vdev_disconnected(vdev)) { + mlo_handle_sta_link_connect_failure(vdev, rsp); + return QDF_STATUS_E_FAILURE; + } else if (!wlan_cm_is_vdev_connected(vdev)) { + /* If vdev is not in disconnected or connected state, + * then the event is received due to connect req being + * flushed. Hence, ignore this event + */ + if (sta_ctx && sta_ctx->copied_reassoc_rsp) { + wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; + } + return QDF_STATUS_E_FAILURE; + } + } + + if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && + (wlan_cm_is_vdev_connecting(link_vdev) || + !mlo_roam_is_internal_disconnect(link_vdev))) { + return QDF_STATUS_E_FAILURE; + } + + if (sta_ctx && !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { + if (sta_ctx->assoc_rsp.ptr) { + qdf_mem_free(sta_ctx->assoc_rsp.ptr); + sta_ctx->assoc_rsp.ptr = NULL; + } + sta_ctx->assoc_rsp.len = rsp->connect_ies.assoc_rsp.len; + sta_ctx->assoc_rsp.ptr = + qdf_mem_malloc(rsp->connect_ies.assoc_rsp.len); + if (!sta_ctx->assoc_rsp.ptr) + return QDF_STATUS_E_FAILURE; + if (rsp->connect_ies.assoc_rsp.ptr) + qdf_mem_copy(sta_ctx->assoc_rsp.ptr, + rsp->connect_ies.assoc_rsp.ptr, + rsp->connect_ies.assoc_rsp.len); + /* Update connected_links_bmap for all vdev taking + * part in association + */ + mlo_update_connected_links(vdev, 1); + mlo_update_connected_links_bmap(mlo_dev_ctx, + rsp->ml_parnter_info); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +mlo_roam_prepare_and_send_link_connect_req(struct wlan_objmgr_vdev *assoc_vdev, + struct wlan_objmgr_vdev *link_vdev, + struct wlan_cm_connect_resp *rsp, + struct mlo_link_info *link_info) +{ + struct wlan_mlo_sta *sta_ctx; + struct wlan_cm_connect_req req = {0}; + struct wlan_ssid ssid = {0}; + struct rso_config *rso_cfg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!assoc_vdev->mlo_dev_ctx || !assoc_vdev->mlo_dev_ctx->sta_ctx) + return QDF_STATUS_E_FAILURE; + + sta_ctx = assoc_vdev->mlo_dev_ctx->sta_ctx; + + wlan_vdev_mlme_get_ssid(assoc_vdev, ssid.ssid, + &ssid.length); + + req.vdev_id = wlan_vdev_get_id(link_vdev); + req.source = CM_MLO_LINK_VDEV_CONNECT; + req.chan_freq = link_info->chan_freq; + req.link_id = link_info->link_id; + qdf_copy_macaddr(&req.bssid, &link_info->link_addr); + + req.ssid.length = ssid.length; + qdf_mem_copy(&req.ssid.ssid, &ssid.ssid, ssid.length); + qdf_copy_macaddr(&req.mld_addr, &rsp->mld_addr); + + req.ml_parnter_info = rsp->ml_parnter_info; + + rso_cfg = wlan_cm_get_rso_config(assoc_vdev); + if (rso_cfg) { + req.crypto.rsn_caps = rso_cfg->orig_sec_info.rsn_caps; + req.crypto.auth_type = rso_cfg->orig_sec_info.authmodeset; + req.crypto.ciphers_pairwise = + rso_cfg->orig_sec_info.ucastcipherset; + req.crypto.group_cipher = rso_cfg->orig_sec_info.mcastcipherset; + req.crypto.mgmt_ciphers = rso_cfg->orig_sec_info.mgmtcipherset; + req.crypto.akm_suites = rso_cfg->orig_sec_info.key_mgmt; + req.assoc_ie.len = rso_cfg->assoc_ie.len; + + req.assoc_ie.ptr = qdf_mem_malloc(req.assoc_ie.len); + if (!req.assoc_ie.ptr) + return QDF_STATUS_E_NOMEM; + + if (rso_cfg->assoc_ie.len) + qdf_mem_copy(req.assoc_ie.ptr, rso_cfg->assoc_ie.ptr, + rso_cfg->assoc_ie.len); + } + + mlme_cm_osif_roam_get_scan_params(assoc_vdev, &req.scan_ie, + &req.dot11mode_filter); + + mlme_info("vdev:%d Connecting to " QDF_SSID_FMT " link_addr: " QDF_MAC_ADDR_FMT " freq %d rsn_caps:0x%x auth_type:0x%x pairwise:0x%x grp:0x%x mcast:0x%x akms:0x%x assoc_ie_len:%d f_rsne:%d is_wps:%d dot11_filter:%d", + req.vdev_id, QDF_SSID_REF(req.ssid.length, req.ssid.ssid), + QDF_MAC_ADDR_REF(link_info->link_addr.bytes), + req.chan_freq, req.crypto.rsn_caps, req.crypto.auth_type, + req.crypto.ciphers_pairwise, req.crypto.group_cipher, + req.crypto.mgmt_ciphers, req.crypto.akm_suites, + req.assoc_ie.len, req.force_rsne_override, + req.is_wps_connection, req.dot11mode_filter); + + copied_conn_req_lock_acquire(sta_ctx); + if (!sta_ctx->copied_conn_req) + sta_ctx->copied_conn_req = + qdf_mem_malloc(sizeof(struct wlan_cm_connect_req)); + else + wlan_cm_free_connect_req_param(sta_ctx->copied_conn_req); + + if (!sta_ctx->copied_conn_req) { + mlo_err("MLO_ROAM: vdev:%d Failed to allocate connect req", + req.vdev_id); + copied_conn_req_lock_release(sta_ctx); + status = QDF_STATUS_E_NOMEM; + goto err; + } + + qdf_mem_copy(sta_ctx->copied_conn_req, &req, + sizeof(struct wlan_cm_connect_req)); + mlo_allocate_and_copy_ies(sta_ctx->copied_conn_req, &req); + copied_conn_req_lock_release(sta_ctx); + + status = mlo_roam_validate_req(assoc_vdev, link_vdev, rsp); + if (QDF_IS_STATUS_ERROR(status)) + goto err; + + status = wlan_cm_start_connect(link_vdev, &req); + if (QDF_IS_STATUS_ERROR(status)) + goto err; + + mlo_update_connected_links(link_vdev, 1); +err: + qdf_mem_free(req.assoc_ie.ptr); + + return status; +} + +void mlo_roam_free_copied_reassoc_rsp(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_sta *sta_ctx; + + if (!vdev) + return; + + if (!vdev->mlo_dev_ctx) + return; + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || + !sta_ctx->copied_reassoc_rsp->roaming_info) + return; + + wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; +} + +void mlo_roam_connect_complete(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlo_sta *sta_ctx; + uint8_t auth_status; + + if (!vdev) + return; + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return; + + if (!vdev->mlo_dev_ctx) + return; + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || + !sta_ctx->copied_reassoc_rsp->roaming_info) + return; + + auth_status = sta_ctx->copied_reassoc_rsp->roaming_info->auth_status; + if (!mlo_check_connect_req_bmap(vdev) && + auth_status == ROAM_AUTH_STATUS_CONNECTED) { + wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; + } +} + +bool +mlo_roam_is_auth_status_connected(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + bool status = false; + struct wlan_mlo_sta *sta_ctx; + struct wlan_cm_connect_resp *rsp; + struct wlan_objmgr_vdev *vdev; + + if (!psoc) + return status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) + return status; + + if (!vdev->mlo_dev_ctx) + goto end; + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!sta_ctx || !sta_ctx->copied_reassoc_rsp || + !sta_ctx->copied_reassoc_rsp->roaming_info) + goto end; + + rsp = sta_ctx->copied_reassoc_rsp; + if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_CONNECTED) + status = true; + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return status; +} + +QDF_STATUS +mlo_roam_link_connect_notify(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_mlo_sta *sta_ctx = NULL; + struct wlan_cm_connect_resp *rsp; + struct wlan_objmgr_vdev *assoc_vdev; + struct wlan_objmgr_vdev *link_vdev = NULL; + struct wlan_objmgr_vdev *vdev; + struct mlo_partner_info partner_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + uint8_t assoc_vdev_id; + uint8_t link_vdev_id; + + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + if (!vdev->mlo_dev_ctx) { + mlo_err("mlo dev ctx is null"); + status = QDF_STATUS_E_FAILURE; + goto err; + } + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + mlo_debug("MLO_ROAM: Ignore if not mlo vdev"); + status = QDF_STATUS_E_FAILURE; + goto err; + } + + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + if (!assoc_vdev) { + status = QDF_STATUS_E_NULL_VALUE; + goto err; + } + + assoc_vdev_id = wlan_vdev_get_id(assoc_vdev); + if (!sta_ctx || !sta_ctx->copied_reassoc_rsp) { + status = QDF_STATUS_E_NULL_VALUE; + goto err; + } + + rsp = sta_ctx->copied_reassoc_rsp; + partner_info = rsp->ml_parnter_info; + mlo_debug("partner links %d", partner_info.num_partner_links); + + for (i = 0; i < partner_info.num_partner_links; i++) { + link_vdev_id = partner_info.partner_link_info[i].vdev_id; + if (assoc_vdev_id == link_vdev_id) + continue; + link_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + link_vdev_id, + WLAN_MLME_SB_ID); + if (!link_vdev) { + mlo_err("Link vdev is null"); + status = QDF_STATUS_E_NULL_VALUE; + goto err; + } + + if (mlo_check_connect_req_bmap(link_vdev)) { + status = mlo_roam_prepare_and_send_link_connect_req(assoc_vdev, + link_vdev, rsp, + &partner_info.partner_link_info[i]); + if (QDF_IS_STATUS_ERROR(status)) + goto err; + else { + mlo_update_connect_req_links(link_vdev, false); + goto end; + } + } + } +err: + if (link_vdev) + mlo_clear_connect_req_links_bmap(link_vdev); + if (sta_ctx && sta_ctx->copied_reassoc_rsp) { + wlan_cm_free_connect_resp(sta_ctx->copied_reassoc_rsp); + sta_ctx->copied_reassoc_rsp = NULL; + } +end: + if (link_vdev) + wlan_objmgr_vdev_release_ref(link_vdev, WLAN_MLME_SB_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return status; +} + +bool +mlo_is_roaming_in_progress(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + bool is_roaming_in_progress = false; + uint8_t link_vdev_id; + uint8_t i; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return false; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id); + goto end; + } + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + if (link_vdev_id == WLAN_INVALID_VDEV_ID) { + mlme_err("invalid vdev id"); + goto end; + } + + if (wlan_cm_is_roam_sync_in_progress(psoc, link_vdev_id)) { + is_roaming_in_progress = true; + goto end; + } + } + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return is_roaming_in_progress; +} + +QDF_STATUS +mlo_add_all_link_probe_rsp_to_scan_db(struct wlan_objmgr_psoc *psoc, + struct roam_scan_candidate_frame *rcvd_frame) +{ + uint8_t *ml_ie, link_id, idx, ies_offset; + qdf_size_t ml_ie_total_len, gen_frame_len; + QDF_STATUS status; + struct mlo_partner_info ml_partner_info = {0}; + struct element_info rcvd_probe_rsp, gen_probe_rsp = {0, NULL}; + struct roam_scan_candidate_frame entry = {0}; + struct qdf_mac_addr self_link_addr; + struct wlan_objmgr_vdev *vdev; + + /* Add the received scan entry as it is */ + wlan_cm_add_frame_to_scan_db(psoc, rcvd_frame); + + ies_offset = WLAN_MAC_HDR_LEN_3A + WLAN_PROBE_RESP_IES_OFFSET; + if (rcvd_frame->frame_length < ies_offset) { + mlme_err("No IEs in probe rsp"); + return QDF_STATUS_E_FAILURE; + } + + status = util_find_mlie(rcvd_frame->frame + ies_offset, + rcvd_frame->frame_length - ies_offset, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_SUCCESS; + + status = util_get_bvmlie_persta_partner_info(ml_ie, + ml_ie_total_len, + &ml_partner_info); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("Per STA profile parsing failed"); + return status; + } + + gen_frame_len = MAX_MGMT_MPDU_LEN; + + gen_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len); + if (!gen_probe_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, rcvd_frame->vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + mlme_err("vdev object is NULL"); + status = QDF_STATUS_E_NULL_VALUE; + goto done; + } + qdf_mem_copy(self_link_addr.bytes, + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + rcvd_probe_rsp.ptr = rcvd_frame->frame + WLAN_MAC_HDR_LEN_3A; + rcvd_probe_rsp.len = rcvd_frame->frame_length - WLAN_MAC_HDR_LEN_3A; + + for (idx = 0; idx < ml_partner_info.num_partner_links; idx++) { + link_id = ml_partner_info.partner_link_info[idx].link_id; + status = util_gen_link_probe_rsp(rcvd_probe_rsp.ptr, + rcvd_probe_rsp.len, + link_id, + self_link_addr, + gen_probe_rsp.ptr, + gen_frame_len, + (qdf_size_t *)&gen_probe_rsp.len); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("MLO: Link %d probe resp gen failed %d", + link_id, status); + status = QDF_STATUS_E_FAILURE; + goto done; + } + + mlme_debug("MLO: link probe rsp size:%u orig probe rsp :%u", + gen_probe_rsp.len, rcvd_probe_rsp.len); + + entry.vdev_id = rcvd_frame->vdev_id; + entry.frame = gen_probe_rsp.ptr; + entry.frame_length = gen_probe_rsp.len; + entry.rssi = rcvd_frame->rssi; + + wlan_cm_add_frame_to_scan_db(psoc, &entry); + } +done: + qdf_mem_free(gen_probe_rsp.ptr); + + return status; +} + +bool +mlo_is_enable_roaming_on_connected_sta_allowed(struct wlan_objmgr_vdev *vdev) +{ + struct mlo_partner_info *partner_info; + + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return true; + + if (!vdev->mlo_dev_ctx || !vdev->mlo_dev_ctx->sta_ctx || + !vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp) + return true; + + partner_info = + &vdev->mlo_dev_ctx->sta_ctx->copied_reassoc_rsp->ml_parnter_info; + if (partner_info->num_partner_links <= 1) + return true; + + /* Roamed to MLO AP, do nothing if link vdev is disconnected */ + return false; +} + +bool +mlo_check_is_given_vdevs_on_same_mld(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id_1, uint8_t vdev_id_2) +{ + struct wlan_objmgr_vdev *vdev1; + struct wlan_mlo_dev_context *ml_dev_ctx1; + struct wlan_objmgr_vdev **vdev_list; + bool is_same_mld = false; + uint8_t i; + + vdev1 = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id_1, + WLAN_MLME_CM_ID); + if (!vdev1) + return false; + + ml_dev_ctx1 = vdev1->mlo_dev_ctx; + if (!ml_dev_ctx1) + goto end; + + vdev_list = ml_dev_ctx1->wlan_vdev_list; + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!vdev_list[i]) + continue; + + if (wlan_vdev_get_id(vdev_list[i]) == vdev_id_2) { + is_same_mld = true; + goto end; + } + } + +end: + if (vdev1) + wlan_objmgr_vdev_release_ref(vdev1, WLAN_MLME_CM_ID); + + return is_same_mld; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c new file mode 100644 index 0000000000..acbe9d00b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c @@ -0,0 +1,978 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: contains TID to Link mapping related functionality + */ +#include +#include +#include "wlan_t2lm_api.h" +#include +#include "wlan_cm_api.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_connectivity_logging.h" + +#define T2LM_MIN_DIALOG_TOKEN 1 +#define T2LM_MAX_DIALOG_TOKEN 0xFF + +static +const char *t2lm_get_event_str(enum wlan_t2lm_evt event) +{ + if (event > WLAN_T2LM_EV_ACTION_FRAME_MAX) + return ""; + + switch (event) { + CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_REQ); + CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_RESP); + CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_REQ); + CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_RESP); + CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN); + CASE_RETURN_STRING(WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN); + default: + return "Unknown"; + } +} + +static +uint16_t t2lm_get_connected_link_id(struct wlan_objmgr_vdev *vdev) +{ + uint16_t ieee_link_mask = 0; + uint8_t i, link_id; + struct mlo_link_info *link_info = NULL; + + if (!vdev->mlo_dev_ctx) { + t2lm_err("MLO dev context failed"); + return false; + } + + link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; + + for (i = 0; i < WLAN_MAX_ML_BSS_LINKS; i++) { + link_id = link_info[i].link_id; + if (link_id == WLAN_INVALID_LINK_ID) + continue; + + ieee_link_mask |= BIT(link_id); + } + + return ieee_link_mask; +} + +static +bool t2lm_is_valid_t2lm_link_map(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_onging_negotiation_info *t2lm, + enum wlan_t2lm_direction *valid_dir) +{ + uint8_t i, tid = 0; + enum wlan_t2lm_direction dir = WLAN_T2LM_INVALID_DIRECTION; + uint16_t ieee_link_mask = 0; + uint16_t provisioned_links = 0; + bool is_valid_link_mask = false; + + ieee_link_mask = t2lm_get_connected_link_id(vdev); + + /* Check if the configured hw_link_id map is valid */ + for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { + if (t2lm->t2lm_info[dir].direction == + WLAN_T2LM_INVALID_DIRECTION) + continue; + + if (t2lm->t2lm_info[dir].default_link_mapping && + t2lm->t2lm_info[dir].direction == WLAN_T2LM_BIDI_DIRECTION) { + is_valid_link_mask = true; + *valid_dir = dir; + continue; + } + + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { + provisioned_links = + t2lm->t2lm_info[dir].ieee_link_map_tid[tid]; + + for (i = 0; i < WLAN_T2LM_MAX_NUM_LINKS; i++) { + if (!(provisioned_links & BIT(i))) + continue; + + if (ieee_link_mask & BIT(i)) { + is_valid_link_mask = true; + *valid_dir = dir; + continue; + } else { + return false; + } + } + } + } + + return is_valid_link_mask; +} + +static uint8_t +t2lm_gen_dialog_token(struct wlan_mlo_peer_t2lm_policy *t2lm_policy) +{ + if (!t2lm_policy) + return 0; + + if (t2lm_policy->self_gen_dialog_token == T2LM_MAX_DIALOG_TOKEN) + /* wrap is ok */ + t2lm_policy->self_gen_dialog_token = T2LM_MIN_DIALOG_TOKEN; + else + t2lm_policy->self_gen_dialog_token += 1; + + t2lm_debug("gen dialog token %d", t2lm_policy->self_gen_dialog_token); + return t2lm_policy->self_gen_dialog_token; +} + +QDF_STATUS t2lm_handle_rx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t frame_len, + uint8_t *token) +{ + struct wlan_t2lm_onging_negotiation_info t2lm_req = {0}; + struct wlan_t2lm_info *t2lm_info; + enum wlan_t2lm_direction dir = WLAN_T2LM_MAX_DIRECTION; + bool valid_map = false; + QDF_STATUS status; + struct wlan_mlo_peer_context *ml_peer; + struct wlan_objmgr_psoc *psoc; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + if (!wlan_mlme_get_t2lm_negotiation_supported(psoc)) { + mlme_rl_debug("T2LM negotiation not supported"); + return QDF_STATUS_E_NOSUPPORT; + } + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) + return QDF_STATUS_E_FAILURE; + + status = wlan_mlo_parse_t2lm_action_frame(&t2lm_req, event_data, + frame_len, + WLAN_T2LM_CATEGORY_REQUEST); + if (status != QDF_STATUS_SUCCESS) { + mlme_err("Unable to parse T2LM request action frame"); + return QDF_STATUS_E_FAILURE; + } + + /* + * Check if ML vdevs are connected and link id matches with T2LM + * negotiation action request link id + */ + valid_map = t2lm_is_valid_t2lm_link_map(vdev, &t2lm_req, &dir); + if (valid_map) { + mlme_debug("Link match found,accept t2lm conf"); + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_FAILURE; + mlme_err("reject t2lm conf"); + } + + if (dir >= WLAN_T2LM_MAX_DIRECTION) { + mlme_err("Received T2LM IE has invalid direction"); + status = QDF_STATUS_E_INVAL; + } + + if (QDF_IS_STATUS_SUCCESS(status) && + t2lm_req.t2lm_info[dir].direction != WLAN_T2LM_INVALID_DIRECTION) { + wlan_t2lm_clear_peer_negotiation(peer); + /* Apply T2LM config to peer T2LM ctx */ + t2lm_info = &ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info[dir]; + qdf_mem_copy(t2lm_info, &t2lm_req.t2lm_info[dir], + sizeof(struct wlan_t2lm_info)); + } + + *token = t2lm_req.dialog_token; + wlan_connectivity_t2lm_req_resp_event( + vdev, *token, 0, 0, + wlan_vdev_mlme_get_bss_chan(vdev)->ch_freq, + true, WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT); + + return status; +} + +QDF_STATUS t2lm_handle_tx_resp(struct wlan_objmgr_vdev *vdev, + void *event_data, uint8_t *token) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS t2lm_handle_tx_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint8_t *token) +{ + struct wlan_t2lm_onging_negotiation_info *t2lm_neg; + struct wlan_action_frame_args args; + QDF_STATUS status; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + if (!event_data) { + t2lm_err("Null event data ptr"); + return QDF_STATUS_E_NULL_VALUE; + } + + t2lm_neg = (struct wlan_t2lm_onging_negotiation_info *)event_data; + args.category = ACTION_CATEGORY_PROTECTED_EHT; + args.action = EHT_T2LM_REQUEST; + args.arg1 = *token; + + status = lim_send_t2lm_action_req_frame(vdev, + wlan_peer_get_macaddr(peer), + &args, t2lm_neg, + *token); + + if (QDF_IS_STATUS_ERROR(status)) { + t2lm_err("Failed to send T2LM action request frame"); + } else { + t2lm_debug("Copy the ongoing neg to peer"); + qdf_mem_copy(&peer->mlo_peer_ctx->t2lm_policy.ongoing_tid_to_link_mapping, + t2lm_neg, sizeof(struct wlan_t2lm_onging_negotiation_info)); + } + + return status; +} + +QDF_STATUS t2lm_handle_rx_resp(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data, uint32_t frame_len, + uint8_t *token) +{ + struct wlan_t2lm_onging_negotiation_info t2lm_rsp = {0}; + struct wlan_t2lm_onging_negotiation_info *t2lm_req; + QDF_STATUS status; + struct wlan_mlo_peer_context *ml_peer; + struct wlan_t2lm_info *t2lm_info; + uint8_t dir; + struct wlan_channel *channel; + + if (!peer) { + t2lm_err("peer is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) { + t2lm_err("ml peer is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* ignore the frame if all links are not connected */ + if (!mlo_check_if_all_links_up(vdev)) + return QDF_STATUS_SUCCESS; + + status = wlan_mlo_parse_t2lm_action_frame(&t2lm_rsp, event_data, + frame_len, + WLAN_T2LM_CATEGORY_RESPONSE); + if (status != QDF_STATUS_SUCCESS) { + mlme_err("Unable to parse T2LM request action frame"); + return QDF_STATUS_E_FAILURE; + } + + mlme_debug("t2lm rsp dialog token %d", t2lm_rsp.dialog_token); + mlme_debug("t2lm rsp is %d", t2lm_rsp.t2lm_resp_type); + t2lm_req = &ml_peer->t2lm_policy.ongoing_tid_to_link_mapping; + if (!t2lm_req) { + t2lm_err("Ongoing tid neg is null"); + return QDF_STATUS_E_FAILURE; + } + + for (dir = 0; dir < WLAN_T2LM_MAX_DIRECTION; dir++) { + t2lm_info = &t2lm_req->t2lm_info[dir]; + if (t2lm_info && + t2lm_info->direction != WLAN_T2LM_INVALID_DIRECTION) { + if (t2lm_rsp.dialog_token == t2lm_req->dialog_token && + t2lm_rsp.t2lm_resp_type == WLAN_T2LM_RESP_TYPE_SUCCESS) { + status = wlan_send_tid_to_link_mapping(vdev, + t2lm_info); + if (QDF_IS_STATUS_ERROR(status)) { + t2lm_err("sending t2lm wmi failed"); + break; + } + } else if (t2lm_rsp.dialog_token == t2lm_req->dialog_token && + t2lm_rsp.t2lm_resp_type != WLAN_T2LM_RESP_TYPE_PREFERRED_TID_TO_LINK_MAPPING) { + t2lm_debug("T2LM rsp status denied, clear ongoing tid mapping"); + wlan_t2lm_clear_ongoing_negotiation(peer); + } + } + } + + channel = wlan_vdev_mlme_get_bss_chan(vdev); + if (!channel) { + t2lm_err("vdev: %d channel infio not found", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_FAILURE; + } + + wlan_connectivity_t2lm_req_resp_event(vdev, t2lm_rsp.dialog_token, 0, + false, + channel->ch_freq, + true, + WLAN_CONN_DIAG_MLO_T2LM_RESP_EVENT); + + return status; +} + +QDF_STATUS t2lm_handle_rx_teardown(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + void *event_data) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_t2lm_context *t2lm_ctx; + + if (!peer) { + t2lm_err("peer is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!vdev) { + t2lm_err("vdev is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + t2lm_err("mlo dev ctx is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + t2lm_ctx = &mlo_dev_ctx->t2lm_ctx; + if (!t2lm_ctx) { + t2lm_err("t2lm ctx is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + wlan_t2lm_clear_peer_negotiation(peer); + + /* Notify the registered caller about the link update*/ + wlan_mlo_dev_t2lm_notify_link_update(vdev, + &t2lm_ctx->established_t2lm.t2lm); + wlan_send_tid_to_link_mapping(vdev, + &t2lm_ctx->established_t2lm.t2lm); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS t2lm_handle_tx_teardown(struct wlan_objmgr_vdev *vdev, + void *event_data) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_t2lm_evt event, + void *event_data, uint32_t frame_len, + uint8_t *token) +{ + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + mlme_debug("T2LM event received: %s(%d)", + t2lm_get_event_str(event), event); + + switch (event) { + case WLAN_T2LM_EV_ACTION_FRAME_RX_REQ: + status = t2lm_handle_rx_req(vdev, peer, event_data, + frame_len, token); + break; + case WLAN_T2LM_EV_ACTION_FRAME_TX_RESP: + status = t2lm_handle_tx_resp(vdev, event_data, token); + break; + case WLAN_T2LM_EV_ACTION_FRAME_TX_REQ: + status = t2lm_handle_tx_req(vdev, peer, event_data, token); + break; + case WLAN_T2LM_EV_ACTION_FRAME_RX_RESP: + status = t2lm_handle_rx_resp(vdev, peer, event_data, + frame_len, token); + break; + case WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN: + status = t2lm_handle_rx_teardown(vdev, peer, event_data); + break; + case WLAN_T2LM_EV_ACTION_FRAME_TX_TEARDOWN: + status = t2lm_handle_tx_teardown(vdev, event_data); + break; + default: + status = QDF_STATUS_E_FAILURE; + mlme_err("Unhandled T2LM event"); + } + + return status; +} + +static uint16_t +t2lm_get_tids_mapped_link_id(uint16_t link_map_tid) +{ + uint16_t all_tids_mapped_link_id = 0; + uint8_t i; + uint8_t bit_mask = 1; + + for (i = 0; i < WLAN_T2LM_MAX_NUM_LINKS; i++) { + if (link_map_tid & bit_mask) + all_tids_mapped_link_id = i; + bit_mask = bit_mask << 1; + } + + return all_tids_mapped_link_id; +} + +static QDF_STATUS +t2lm_find_tid_mapped_link_id(struct wlan_t2lm_info *t2lm_info, + uint16_t *tid_mapped_link_id) +{ + uint16_t link_map_tid; + uint8_t tid; + + if (!t2lm_info) + return QDF_STATUS_E_NULL_VALUE; + + if (t2lm_info->default_link_mapping) { + t2lm_debug("T2LM ie has default link mapping"); + *tid_mapped_link_id = 0xFFFF; + return QDF_STATUS_SUCCESS; + } + + link_map_tid = t2lm_info->ieee_link_map_tid[0]; + for (tid = 1; tid < T2LM_MAX_NUM_TIDS; tid++) { + if (link_map_tid != t2lm_info->ieee_link_map_tid[tid]) { + mlme_debug("all tids are not mapped to same link set"); + return QDF_STATUS_E_FAILURE; + } + } + + *tid_mapped_link_id = t2lm_get_tids_mapped_link_id(link_map_tid); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_t2lm_validate_candidate(struct cnx_mgr *cm_ctx, + struct scan_cache_entry *scan_entry) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + struct wlan_t2lm_context t2lm_ctx; + uint16_t tid_map_link_id; + uint16_t established_tid_mapped_link_id = 0; + uint16_t upcoming_tid_mapped_link_id = 0; + struct wlan_objmgr_psoc *psoc; + + if (!scan_entry || !cm_ctx || !cm_ctx->vdev) + return QDF_STATUS_E_NULL_VALUE; + + vdev = cm_ctx->vdev; + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_NULL_VALUE; + + if (!wlan_mlme_get_t2lm_negotiation_supported(psoc)) { + mlme_rl_debug("T2LM negotiation not supported"); + return QDF_STATUS_SUCCESS; + } + + /* + * Skip T2LM validation for following cases: + * - Is link VDEV + * - Is not STA VDEV + * - T2LM IE not present in scan entry + */ + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) || + wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE || + !scan_entry->ie_list.t2lm[0]) { + return QDF_STATUS_SUCCESS; + } + + status = wlan_mlo_parse_bcn_prbresp_t2lm_ie(&t2lm_ctx, + util_scan_entry_t2lm(scan_entry), + util_scan_entry_t2lm_len(scan_entry)); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + status = t2lm_find_tid_mapped_link_id(&t2lm_ctx.established_t2lm.t2lm, + &established_tid_mapped_link_id); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + status = t2lm_find_tid_mapped_link_id(&t2lm_ctx.upcoming_t2lm.t2lm, + &upcoming_tid_mapped_link_id); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + t2lm_debug("self link id %d established_tid_mapped_link_id %x upcoming_tid_mapped_link_id %x", + scan_entry->ml_info.self_link_id, + established_tid_mapped_link_id, upcoming_tid_mapped_link_id); + + tid_map_link_id = + established_tid_mapped_link_id & upcoming_tid_mapped_link_id; + + if (!tid_map_link_id) + tid_map_link_id = established_tid_mapped_link_id; + + if (tid_map_link_id == scan_entry->ml_info.self_link_id) + status = QDF_STATUS_SUCCESS; + else + status = QDF_STATUS_E_FAILURE; + +end: + return status; +} + +void +wlan_t2lm_clear_ongoing_negotiation(struct wlan_objmgr_peer *peer) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_t2lm_onging_negotiation_info *ongoing_tid_to_link_mapping; + uint8_t i; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) { + t2lm_err("ml peer is null"); + return; + } + + ongoing_tid_to_link_mapping = &ml_peer->t2lm_policy.ongoing_tid_to_link_mapping; + if (!ongoing_tid_to_link_mapping) { + t2lm_err("ongoing tid mapping is null"); + return; + } + + qdf_mem_zero(&ongoing_tid_to_link_mapping->t2lm_info, + sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION); + + ongoing_tid_to_link_mapping->dialog_token = 0; + ongoing_tid_to_link_mapping->category = WLAN_T2LM_CATEGORY_NONE; + ongoing_tid_to_link_mapping->t2lm_resp_type = WLAN_T2LM_RESP_TYPE_INVALID; + ongoing_tid_to_link_mapping->t2lm_tx_status = WLAN_T2LM_TX_STATUS_NONE; + + for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++) + ongoing_tid_to_link_mapping->t2lm_info[i].direction = + WLAN_T2LM_INVALID_DIRECTION; +} + +void +wlan_t2lm_clear_peer_negotiation(struct wlan_objmgr_peer *peer) +{ + struct wlan_mlo_peer_context *ml_peer; + struct wlan_prev_t2lm_negotiated_info *t2lm_negotiated_info; + uint8_t i; + + ml_peer = peer->mlo_peer_ctx; + if (!ml_peer) { + t2lm_err("ml peer is null"); + return; + } + + qdf_mem_zero(&ml_peer->t2lm_policy.t2lm_negotiated_info.t2lm_info, + sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION); + + ml_peer->t2lm_policy.t2lm_negotiated_info.dialog_token = 0; + t2lm_negotiated_info = &ml_peer->t2lm_policy.t2lm_negotiated_info; + for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++) + t2lm_negotiated_info->t2lm_info[i].direction = + WLAN_T2LM_INVALID_DIRECTION; +} + +void +wlan_t2lm_clear_all_tid_mapping(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *peer; + struct wlan_t2lm_context *t2lm_ctx; + + if (!vdev) { + t2lm_err("Vdev is null"); + return; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + if (!vdev->mlo_dev_ctx) { + t2lm_err("mlo dev ctx is null"); + return; + } + + t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, + WLAN_MLO_MGR_ID); + if (!peer) { + t2lm_err("peer is null"); + return; + } + qdf_mem_zero(&t2lm_ctx->established_t2lm, + sizeof(struct wlan_mlo_t2lm_ie)); + t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION; + t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1; + t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0; + + qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, + sizeof(struct wlan_mlo_t2lm_ie)); + t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + t2lm_debug("Clear the T2LM info received in assoc rsp"); + t2lm_ctx = &vdev->mlo_dev_ctx->sta_ctx->copied_t2lm_ie_assoc_rsp; + + qdf_mem_zero(&t2lm_ctx->established_t2lm, + sizeof(struct wlan_mlo_t2lm_ie)); + t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, + sizeof(struct wlan_mlo_t2lm_ie)); + t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + wlan_t2lm_clear_peer_negotiation(peer); + wlan_t2lm_clear_ongoing_negotiation(peer); + wlan_mlo_t2lm_timer_stop(vdev); + wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); +} + +static bool +wlan_is_ml_link_disabled(uint32_t link_id_bitmap, + uint8_t ml_link_id) +{ + uint8_t link; + + if (!link_id_bitmap) { + t2lm_err("Link id bitmap is 0"); + return false; + } + + for (link = 0; link < WLAN_T2LM_MAX_NUM_LINKS; link++) { + if ((link == ml_link_id) && + (link_id_bitmap & BIT(link))) { + return true; + } + } + + return false; +} + +static void +wlan_t2lm_set_link_mapping_of_tids(uint8_t link_id, + struct wlan_t2lm_info *t2lm_info, + bool set) +{ + uint8_t tid_num; + + if (link_id >= WLAN_T2LM_MAX_NUM_LINKS) { + t2lm_err("Max 16 t2lm links are supported"); + return; + } + + for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { + if (set) + t2lm_info->ieee_link_map_tid[tid_num] |= BIT(link_id); + else + t2lm_info->ieee_link_map_tid[tid_num] &= ~BIT(link_id); + } +} + +QDF_STATUS +wlan_populate_link_disable_t2lm_frame(struct wlan_objmgr_vdev *vdev, + struct mlo_link_disable_request_evt_params *params) +{ + struct wlan_objmgr_peer *peer; + struct wlan_mlo_dev_context *ml_dev_ctx; + struct wlan_mlo_peer_t2lm_policy *t2lm_policy; + struct wlan_objmgr_vdev *tmp_vdev; + struct wlan_t2lm_onging_negotiation_info t2lm_neg = {0}; + uint8_t dir = WLAN_T2LM_BIDI_DIRECTION; + uint8_t i = 0; + QDF_STATUS status; + uint8_t link_id; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, + WLAN_MLO_MGR_ID); + + if (!peer) { + t2lm_err("peer is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!vdev->mlo_dev_ctx) + return QDF_STATUS_E_NULL_VALUE; + + t2lm_policy = &peer->mlo_peer_ctx->t2lm_policy; + t2lm_neg = t2lm_policy->ongoing_tid_to_link_mapping; + + t2lm_neg.category = WLAN_T2LM_CATEGORY_REQUEST; + t2lm_neg.dialog_token = t2lm_gen_dialog_token(t2lm_policy); + qdf_mem_zero(&t2lm_neg.t2lm_info, + sizeof(struct wlan_t2lm_info) * WLAN_T2LM_MAX_DIRECTION); + for (i = 0; i < WLAN_T2LM_MAX_DIRECTION; i++) + t2lm_neg.t2lm_info[i].direction = WLAN_T2LM_INVALID_DIRECTION; + + t2lm_neg.t2lm_info[dir].default_link_mapping = 0; + t2lm_neg.t2lm_info[dir].direction = WLAN_T2LM_BIDI_DIRECTION; + t2lm_neg.t2lm_info[dir].mapping_switch_time_present = 0; + t2lm_neg.t2lm_info[dir].expected_duration_present = 0; + t2lm_neg.t2lm_info[dir].link_mapping_size = 1; + + t2lm_debug("dir %d", t2lm_neg.t2lm_info[dir].direction); + ml_dev_ctx = vdev->mlo_dev_ctx; + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!ml_dev_ctx->wlan_vdev_list[i]) + continue; + + tmp_vdev = ml_dev_ctx->wlan_vdev_list[i]; + link_id = wlan_vdev_get_link_id(tmp_vdev); + + /* if link id matches disabled link id bitmap + * set that bit as 0. + */ + if (wlan_is_ml_link_disabled(params->link_id_bitmap, + link_id)) { + wlan_t2lm_set_link_mapping_of_tids(link_id, + &t2lm_neg.t2lm_info[dir], + 0); + t2lm_debug("Disabled link id %d", link_id); + } else { + wlan_t2lm_set_link_mapping_of_tids(link_id, + &t2lm_neg.t2lm_info[dir], + 1); + t2lm_debug("Enabled link id %d", link_id); + } + } + + status = t2lm_deliver_event(vdev, peer, + WLAN_T2LM_EV_ACTION_FRAME_TX_REQ, + &t2lm_neg, + 0, + &t2lm_neg.dialog_token); + + wlan_objmgr_peer_release_ref(peer, WLAN_MLO_MGR_ID); + return status; +} + +QDF_STATUS wlan_t2lm_deliver_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum wlan_t2lm_evt event, + void *event_data, + uint32_t frame_len, + uint8_t *dialog_token) +{ + return t2lm_deliver_event(vdev, peer, event, event_data, + frame_len, dialog_token); +} + +QDF_STATUS +wlan_t2lm_init_default_mapping(struct wlan_t2lm_context *t2lm_ctx) +{ + if (!t2lm_ctx) + return QDF_STATUS_E_NULL_VALUE; + + qdf_mem_zero(t2lm_ctx, sizeof(struct wlan_t2lm_context)); + + t2lm_ctx->established_t2lm.t2lm.default_link_mapping = 1; + t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_BIDI_DIRECTION; + t2lm_ctx->established_t2lm.t2lm.link_mapping_size = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_update_t2lm_mapping(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_context *rx_t2lm, uint64_t tsf) +{ + struct wlan_t2lm_context *t2lm_ctx; + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint64_t mst_start_tsf; + uint64_t mst_end_tsf; + uint64_t rx_bcn_tsf_exp_dur; + uint64_t mst_end_tsf_low; + uint64_t mst_end_tsf_high; + uint16_t mst; + uint32_t exp_dur; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx) + return QDF_STATUS_E_NULL_VALUE; + + t2lm_ctx = &mlo_dev_ctx->t2lm_ctx; + if (rx_t2lm->upcoming_t2lm.t2lm.direction == WLAN_T2LM_INVALID_DIRECTION && + rx_t2lm->established_t2lm.t2lm.direction == WLAN_T2LM_INVALID_DIRECTION) { + if (!t2lm_ctx->established_t2lm.t2lm.default_link_mapping) { + wlan_t2lm_init_default_mapping(t2lm_ctx); + t2lm_debug("initialize to default T2LM mapping"); + } + return QDF_STATUS_SUCCESS; + } + + if (rx_t2lm->established_t2lm.t2lm.expected_duration && + !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present && + rx_t2lm->upcoming_t2lm.t2lm.expected_duration && + rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) { + if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, + rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid, + sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { + t2lm_debug("T2LM mapping is already configured"); + return QDF_STATUS_E_ALREADY; + } + + qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, + &rx_t2lm->established_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + + t2lm_ctx->established_t2lm.t2lm.expected_duration = 0; + t2lm_ctx->established_t2lm.t2lm.expected_duration_present = 0; + t2lm_ctx->established_t2lm.t2lm.mapping_switch_time = 0; + t2lm_ctx->established_t2lm.t2lm.mapping_switch_time_present = 0; + + wlan_mlo_dev_t2lm_notify_link_update(vdev, + &t2lm_ctx->established_t2lm.t2lm); + wlan_clear_peer_level_tid_to_link_mapping(vdev); + t2lm_debug("Update T2LM established mapping to FW"); + wlan_send_tid_to_link_mapping( + vdev, &t2lm_ctx->established_t2lm.t2lm); + + if (!qdf_mem_cmp(t2lm_ctx->upcoming_t2lm.t2lm.ieee_link_map_tid, + rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid, + sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { + t2lm_debug("Ongoing mapping is already established"); + return QDF_STATUS_E_ALREADY; + } + qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, + &rx_t2lm->upcoming_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_debug("Update T2LM upcoming mapping to FW"); + wlan_send_tid_to_link_mapping( + vdev, &t2lm_ctx->upcoming_t2lm.t2lm); + } + + if (t2lm_ctx->established_t2lm.t2lm.expected_duration_present && + rx_t2lm->established_t2lm.t2lm.expected_duration_present) { + /* Established T2LM is already saved in the T2LM context. + * T2LM IE in the beacon/probe response frame has the updated + * expected duration. + */ + if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, + rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid, + sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { + if (!t2lm_ctx->mst_start_tsf) { + t2lm_ctx->mst_end_tsf = tsf + (rx_t2lm->established_t2lm.t2lm.expected_duration << 10); + t2lm_ctx->mst_start_tsf = tsf; + } + + /* Check if AP has updated expected duration value + * more than expected delta between 2 beacons, + * calculation as following: + * 1.when receive a beacon with mapping switch + * time set, calculate the mapping switch start TSF + * by replacing bit25~bit10 in the bcn TSF + * mst_start_tsf = (bcn_tsf & (~mst_mask)) | (mst << 10); + * 2.based on the expected duration, + * calculate the mapping end time tsf + * mst_end_tsf = mst_start_tsf + expected_duration; + * 3.then after the TSF become established mapping, + * whenever host receive a beacon, + * check if the new expected duration based + * on current beacon TSF has a big drift to the old one. + * mst_end_tsf - (200 << 10) < rx_bcn_tsf_exp_dur + + * rx_bcn_tsf_exp_dur < mst_end_tsf + (200 << 10) + */ + rx_bcn_tsf_exp_dur = tsf + (rx_t2lm->established_t2lm.t2lm.expected_duration << 10); + mst_end_tsf_low = t2lm_ctx->mst_end_tsf - (200 << 10); + mst_end_tsf_high = t2lm_ctx->mst_end_tsf + (200 << 10); + if (t2lm_ctx->mst_end_tsf && (rx_bcn_tsf_exp_dur < mst_end_tsf_low) && + (rx_bcn_tsf_exp_dur > mst_end_tsf_high)) { + t2lm_ctx->established_t2lm.t2lm.expected_duration = + rx_t2lm->established_t2lm.t2lm.expected_duration; + wlan_send_tid_to_link_mapping( + vdev, &t2lm_ctx->established_t2lm.t2lm); + } else { + t2lm_debug("T2LM exp duration in range"); + } + } + } else if (rx_t2lm->established_t2lm.t2lm.expected_duration_present && + !rx_t2lm->established_t2lm.t2lm.mapping_switch_time_present) { + if (!qdf_mem_cmp(t2lm_ctx->established_t2lm.t2lm.ieee_link_map_tid, + rx_t2lm->established_t2lm.t2lm.ieee_link_map_tid, + sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { + t2lm_debug("T2LM mapping is already configured"); + return QDF_STATUS_E_ALREADY; + } + + mst_start_tsf = tsf; + t2lm_ctx->mst_start_tsf = mst_start_tsf; + mst_end_tsf = mst_start_tsf + (rx_t2lm->established_t2lm.t2lm.expected_duration << 10); + t2lm_ctx->mst_end_tsf = mst_end_tsf; + + /* Mapping switch time is already expired when STA receives the + * T2LM IE from beacon/probe response frame. + */ + qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, + &rx_t2lm->established_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + + /* Notify the registered caller about the link update*/ + wlan_mlo_dev_t2lm_notify_link_update(vdev, + &t2lm_ctx->established_t2lm.t2lm); + wlan_clear_peer_level_tid_to_link_mapping(vdev); + t2lm_debug("MST expired, update established T2LM mapping to FW"); + wlan_send_tid_to_link_mapping( + vdev, &t2lm_ctx->established_t2lm.t2lm); + } + + if (rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time_present) { + if (!qdf_mem_cmp(t2lm_ctx->upcoming_t2lm.t2lm.ieee_link_map_tid, + rx_t2lm->upcoming_t2lm.t2lm.ieee_link_map_tid, + sizeof(uint16_t) * T2LM_MAX_NUM_TIDS)) { + t2lm_debug("Ongoing mapping is already established"); + return QDF_STATUS_E_ALREADY; + } + + mst = rx_t2lm->upcoming_t2lm.t2lm.mapping_switch_time; + exp_dur = rx_t2lm->upcoming_t2lm.t2lm.expected_duration; + if (mst) { + mst_start_tsf = (tsf & (~WLAN_T2LM_MAPPING_SWITCH_TSF_BITS)) | (mst << 10); + mst_end_tsf = mst_start_tsf + exp_dur; + t2lm_ctx->mst_start_tsf = mst_start_tsf; + t2lm_ctx->mst_end_tsf = mst_end_tsf; + } + + qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, + &rx_t2lm->upcoming_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_debug("Update T2LM upcoming mapping to FW"); + wlan_send_tid_to_link_mapping( + vdev, &t2lm_ctx->upcoming_t2lm.t2lm); + } else { + if (t2lm_ctx->established_t2lm.t2lm.direction == WLAN_T2LM_INVALID_DIRECTION && + t2lm_ctx->upcoming_t2lm.t2lm.direction != WLAN_T2LM_INVALID_DIRECTION) { + t2lm_debug("Copy upcoming T2LM mapping to expected T2LM"); + qdf_mem_copy(&t2lm_ctx->established_t2lm, + &t2lm_ctx->upcoming_t2lm, + sizeof(struct wlan_mlo_t2lm_ie)); + } + /* Upcoming mapping should be cleared as mapping switch time has expired */ + qdf_mem_zero(&t2lm_ctx->upcoming_t2lm, + sizeof(struct wlan_mlo_t2lm_ie)); + t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + } + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c new file mode 100644 index 0000000000..fe429af4b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c @@ -0,0 +1,1798 @@ +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_ll_sap_main.h" +#include "wlan_ll_lt_sap_bearer_switch.h" +#include "wlan_sm_engine.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_policy_mgr_ll_sap.h" + +#define BEARER_SWITCH_TIMEOUT 5000 +#define BS_PREFIX_FMT "BS_SM vdev %d req_id 0x%x: " +#define BS_PREFIX_REF(vdev_id, req_id) (vdev_id), (req_id) + + +wlan_bs_req_id ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc) +{ + wlan_bs_req_id request_id = BS_REQ_ID_INVALID; + struct ll_sap_vdev_priv_obj *ll_sap_obj; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + + vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc); + if (vdev_id == WLAN_INVALID_VDEV_ID) + return request_id; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LL_SAP_ID); + if (!vdev) { + ll_sap_err(BS_PREFIX_FMT "Vdev is NULL", + BS_PREFIX_REF(vdev_id, request_id)); + return request_id; + } + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + if (!ll_sap_obj) { + ll_sap_err(BS_PREFIX_FMT "ll sap obj is NULL", + BS_PREFIX_REF(vdev_id, request_id)); + + goto rel_ref; + } + + request_id = qdf_atomic_inc_return( + &ll_sap_obj->bearer_switch_ctx->request_id); + + ll_sap_nofl_debug(BS_PREFIX_FMT, BS_PREFIX_REF(vdev_id, request_id)); +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); + + return request_id; +} + +bool __ll_lt_sap_is_bs_ctx_valid(struct bearer_switch_info *bs_ctx, + const char *func) +{ + if (!bs_ctx) { + ll_sap_nofl_err("BS_SM context is null (via %s)", func); + return false; + } + return true; +} + +bool __ll_lt_sap_is_bs_req_valid(struct wlan_bearer_switch_request *bs_req, + const char *func) +{ + if (!bs_req) { + ll_sap_nofl_err("BS_SM request is null (via %s)", func); + return false; + } + + if (bs_req->vdev_id >= WLAN_UMAC_PSOC_MAX_VDEVS) { + ll_sap_nofl_err("Invalid vdev id %d in BS_SM request", + bs_req->vdev_id); + return false; + } + + return true; +} + +/** + * ll_lt_sap_deliver_audio_transport_switch_resp_to_fw() - Deliver audio + * transport switch response to FW + * @vdev: Vdev on which the request is received + * @req_type: Transport switch type for which the response is received + * @status: Status of the response + * + * Return: None + */ +static void +ll_lt_sap_deliver_audio_transport_switch_resp_to_fw( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ + struct wlan_objmgr_psoc *psoc; + struct ll_sap_psoc_priv_obj *psoc_ll_sap_obj; + struct wlan_ll_sap_tx_ops *tx_ops; + + psoc = wlan_vdev_get_psoc(vdev); + + psoc_ll_sap_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, + WLAN_UMAC_COMP_LL_SAP); + + if (!psoc_ll_sap_obj) { + ll_sap_err("psoc_ll_sap_obj is null"); + return; + } + + tx_ops = &psoc_ll_sap_obj->tx_ops; + + if (!tx_ops->send_audio_transport_switch_resp) { + ll_sap_err("deliver_audio_transport_switch_resp op is NULL"); + return; + } + + tx_ops->send_audio_transport_switch_resp(psoc, req_type, status); +} + +/** + * bs_req_timeout_cb() - Callback which will be invoked on bearer switch req + * timeout + * @user_data: Bearer switch context + * + * API to handle the timeout for the bearer switch requests + * + * Return: None + */ + +static void bs_req_timeout_cb(void *user_data) +{ + struct bearer_switch_info *bs_ctx = user_data; + struct wlan_bearer_switch_request *bs_req = NULL; + uint8_t i; + enum wlan_bearer_switch_sm_evt event; + + for (i = 0; i < MAX_BEARER_SWITCH_REQUESTERS; i++) { + if (!bs_ctx->requests[i].requester_cb) + continue; + + /* + * It is always the first cached request for which the request + * to switch the bearer is sent (other requests for bearer + * switch are just cached) and for the same this timeout has + * happened + */ + bs_req = &bs_ctx->requests[i]; + break; + } + if (!bs_req) { + ll_sap_err("BS_SM No request pending"); + return; + } + + if (bs_req->req_type == WLAN_BS_REQ_TO_WLAN) + event = WLAN_BS_SM_EV_SWITCH_TO_WLAN_TIMEOUT; + else + event = WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_TIMEOUT; + bs_sm_deliver_event(wlan_vdev_get_psoc(bs_ctx->vdev), event, + sizeof(*bs_req), bs_req); +} + +void bs_req_timer_init(struct bearer_switch_info *bs_ctx) +{ + qdf_mc_timer_init(&bs_ctx->bs_request_timer, QDF_TIMER_TYPE_SW, + bs_req_timeout_cb, bs_ctx); +} + +void bs_req_timer_deinit(struct bearer_switch_info *bs_ctx) +{ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&bs_ctx->bs_request_timer)) + qdf_mc_timer_stop(&bs_ctx->bs_request_timer); + + qdf_mc_timer_destroy(&bs_ctx->bs_request_timer); +} + +/** + * ll_lt_sap_stop_bs_timer() - Stop bearer switch timer + * @bs_ctx: Bearer switch context + * @req_id: Request id for which timer needs to be stopped + * + * API to stop bearer switch request timer + * + * Return: None + */ +static void ll_lt_sap_stop_bs_timer(struct bearer_switch_info *bs_ctx, + uint32_t req_id) +{ + QDF_STATUS status; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&bs_ctx->bs_request_timer)) { + status = qdf_mc_timer_stop(&bs_ctx->bs_request_timer); + if (QDF_IS_STATUS_ERROR(status)) + ll_sap_err(BS_PREFIX_FMT "failed to stop timer", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + req_id)); + } else { + ll_sap_err(BS_PREFIX_FMT "timer is not running", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + req_id)); + } +} + +/** + * bs_set_state() - Set bearer switch state in the bearer switch state machine + * @bs_ctx: Bearer switch context + * @state: State which needs to be set + * + * API to Set the bearer switch state + * + * Return: None + */ +static void bs_set_state(struct bearer_switch_info *bs_ctx, + enum wlan_bearer_switch_sm_state state) +{ + if (state < BEARER_SWITCH_MAX) + bs_ctx->sm.bs_state = state; + else + ll_sap_err("BS_SM vdev %d state (%d) is invalid", + wlan_vdev_get_id(bs_ctx->vdev), state); +} + +/** + * bs_sm_state_update() - Update the bearer switch state in the bearer switch + * state machine + * @bs_ctx: Bearer switch context + * @state: State which needs to be set + * + * API to update the bearer switch state + * + * Return: None + */ +static void bs_sm_state_update(struct bearer_switch_info *bs_ctx, + enum wlan_bearer_switch_sm_state state) +{ + if (!ll_lt_sap_is_bs_ctx_valid(bs_ctx)) + return; + + bs_set_state(bs_ctx, state); +} + +static void +ll_lt_sap_invoke_req_callback_f(struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req, + QDF_STATUS status, const char *func) +{ + if (!bs_req->requester_cb) { + ll_sap_err("%s BS_SM vdev %d NULL cbk, req_vdev %d src %d req %d arg val %d", + func, wlan_vdev_get_id(bs_ctx->vdev), bs_req->vdev_id, + bs_req->source, bs_req->request_id, + bs_req->arg_value); + return; + } + + /* Invoke the requester callback without waiting for the response */ + bs_req->requester_cb(wlan_vdev_get_psoc(bs_ctx->vdev), bs_req->vdev_id, + bs_req->request_id, status, bs_req->arg_value, + bs_req->arg); +} + +#define ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, status) \ + ll_lt_sap_invoke_req_callback_f(bs_ctx, bs_req, status, __func__) + +/** + * ll_lt_sap_bs_increament_ref_count() - Increment the bearer switch ref count + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request corresponding to which the ref count needs to + * be incremented + * + * API to increment the bearer switch ref count + * + * Return: None + */ +static inline void +ll_lt_sap_bs_increament_ref_count(struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + uint32_t ref_count; + uint32_t total_ref_count; + + total_ref_count = qdf_atomic_inc_return(&bs_ctx->total_ref_count); + if (bs_req->source == BEARER_SWITCH_REQ_FW) + ref_count = qdf_atomic_inc_return(&bs_ctx->fw_ref_count); + else + ref_count = qdf_atomic_inc_return( + &bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]); + + ll_sap_nofl_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count %d Total ref count %d", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id), + bs_req->vdev_id, bs_req->source, ref_count, + total_ref_count); +} + +/** + * ll_lt_sap_bs_decreament_ref_count() - Decreament the bearer switch ref count + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request corresponding to which the ref count needs to + * be decremented + * + * API to decreament the bearer switch ref count + * + * Return: None + */ +static inline QDF_STATUS +ll_lt_sap_bs_decreament_ref_count(struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + uint32_t ref_count; + uint32_t total_ref_count; + + /* + * If the ref count is 0 for the requested module, it means that this + * module did not requested for wlan to non wlan transition earlier, so + * reject this operation. + */ + if (bs_req->source == BEARER_SWITCH_REQ_FW) { + if (!qdf_atomic_read(&bs_ctx->fw_ref_count)) { + ll_sap_debug(BS_PREFIX_FMT "ref_count is zero for FW", + BS_PREFIX_REF( + wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id)); + return QDF_STATUS_E_INVAL; + } + ref_count = qdf_atomic_dec_return(&bs_ctx->fw_ref_count); + } else if (!qdf_atomic_read( + &bs_ctx->ref_count[bs_req->vdev_id][bs_req->source])) { + ll_sap_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count is zero", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id), + bs_req->vdev_id, bs_req->source); + return QDF_STATUS_E_INVAL; + } else { + ref_count = qdf_atomic_dec_return( + &bs_ctx->ref_count[bs_req->vdev_id][bs_req->source]); + } + total_ref_count = qdf_atomic_dec_return(&bs_ctx->total_ref_count); + ll_sap_nofl_debug(BS_PREFIX_FMT "req_vdev %d src %d ref_count %d Total ref count %d", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id), + bs_req->vdev_id, bs_req->source, + ref_count, total_ref_count); + + return QDF_STATUS_SUCCESS; +} + +/** + * ll_lt_sap_cache_bs_request() - Cache the bearer switch request + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request which needs to be cached + * + * API to cache the bearer switch request in the bearer switch context + * + * Return: None + */ +static void +ll_lt_sap_cache_bs_request(struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + uint8_t i; + + for (i = 0; i < MAX_BEARER_SWITCH_REQUESTERS; i++) { + /* + * Find the empty slot in the requests array to cache the + * current request + */ + if (bs_ctx->requests[i].requester_cb) + continue; + ll_sap_debug(BS_PREFIX_FMT "req_vdev %d cache %d request at %d", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id), + bs_req->vdev_id, bs_req->req_type, i); + bs_ctx->requests[i].vdev_id = bs_req->vdev_id; + bs_ctx->requests[i].request_id = bs_req->request_id; + bs_ctx->requests[i].req_type = bs_req->req_type; + bs_ctx->requests[i].source = bs_req->source; + bs_ctx->requests[i].requester_cb = bs_req->requester_cb; + bs_ctx->requests[i].arg_value = bs_req->arg_value; + bs_ctx->requests[i].arg = bs_req->arg; + break; + } + if (i >= MAX_BEARER_SWITCH_REQUESTERS) + ll_sap_err(BS_PREFIX_FMT "Max number of requests reached", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id)); +} + +/* + * ll_lt_sap_invoke_bs_requester_cbks() - Invoke callbacks of all the cached + * requests + * @bs_ctx: Bearer switch context + * @Status: Status with which the callbacks needs to be invoked + * + * API to invoke the callbacks of the cached requests + * + * Return: None + */ +static void +ll_lt_sap_invoke_bs_requester_cbks(struct bearer_switch_info *bs_ctx, + QDF_STATUS status) +{ + struct wlan_objmgr_psoc *psoc; + uint8_t i; + + psoc = wlan_vdev_get_psoc(bs_ctx->vdev); + + if (!psoc) { + ll_sap_err("BS_SM invalid psoc"); + return; + } + + for (i = 0; i < MAX_BEARER_SWITCH_REQUESTERS; i++) { + if (!bs_ctx->requests[i].requester_cb) + continue; + + bs_ctx->requests[i].requester_cb(psoc, + bs_ctx->requests[i].vdev_id, + bs_ctx->requests[i].request_id, + status, + bs_ctx->requests[i].arg_value, + bs_ctx->requests[i].arg); + bs_ctx->requests[i].requester_cb = NULL; + bs_ctx->requests[i].arg = NULL; + bs_ctx->requests[i].arg_value = 0; + } +} + +/* + * ll_lt_sap_find_first_valid_bs_wlan_req() - Find first valid wlan switch + * request from the cached requests + * @bs_ctx: Bearer switch context + * + * API to find first valid wlan switch request from the cached requests + * + * Return: If found return bearer switch request, else return NULL + */ +static struct wlan_bearer_switch_request * +ll_lt_sap_find_first_valid_bs_wlan_req(struct bearer_switch_info *bs_ctx) +{ + uint8_t i; + + for (i = 0; i < MAX_BEARER_SWITCH_REQUESTERS; i++) { + if (bs_ctx->requests[i].requester_cb && + bs_ctx->requests[i].req_type == WLAN_BS_REQ_TO_WLAN) + return &bs_ctx->requests[i]; + } + return NULL; +} + +/* + * ll_lt_sap_find_first_valid_bs_non_wlan_req() - Find first valid non-wlan + * switch request from the cached requests + * @bs_ctx: Bearer switch context + * + * API to find first valid non-wlan switch request from the cached requests + * + * Return: If found return bearer switch request, else return NULL + */ +static struct wlan_bearer_switch_request * +ll_lt_sap_find_first_valid_bs_non_wlan_req(struct bearer_switch_info *bs_ctx) +{ + uint8_t i; + + for (i = 0; i < MAX_BEARER_SWITCH_REQUESTERS; i++) { + if (bs_ctx->requests[i].requester_cb && + bs_ctx->requests[i].req_type == WLAN_BS_REQ_TO_NON_WLAN) + return &bs_ctx->requests[i]; + } + return NULL; +} + +/* + * ll_lt_sap_send_bs_req_to_userspace() - Send bearer switch request to user + * space + * @vdev: ll_lt sap vdev + * + * API to send bearer switch request to userspace + * + * Return: None + */ +static void +ll_lt_sap_send_bs_req_to_userspace(struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type) +{ + struct ll_sap_ops *osif_cbk; + + osif_cbk = ll_sap_get_osif_cbk(); + if (osif_cbk && osif_cbk->ll_sap_send_audio_transport_switch_req_cb) + osif_cbk->ll_sap_send_audio_transport_switch_req_cb(vdev, + req_type); +} +/** + * ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state() - API to handle bearer switch + * to wlan in non-wlan state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * If total_ref_count is non-zero, means non-wlan bearer should be there and + * no further action is required, just invoke the callback of the requester + * with status as success. + * If total_ref_count is zero, means none of the module wants to be in the + * non-wlan bearer, cache the request and send the wlan bearer switch request + * to userspace. + * If the last_status is not QDF_STATUS_SUCCESS, means the last request to + * switch the bearer to non-wlan was failed/timedout and the state is moved to + * non-wlan, irrespective of the last status follow the same flow and send the + * request to switch the bearer to wlan + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + QDF_STATUS status; + + status = ll_lt_sap_bs_decreament_ref_count(bs_ctx, bs_req); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (qdf_atomic_read(&bs_ctx->total_ref_count)) + goto invoke_requester_cb; + + ll_lt_sap_cache_bs_request(bs_ctx, bs_req); + + ll_lt_sap_send_bs_req_to_userspace(bs_ctx->vdev, bs_req->req_type); + + status = qdf_mc_timer_start(&bs_ctx->bs_request_timer, + BEARER_SWITCH_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + ll_sap_err(BS_PREFIX_FMT "Failed to start timer", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id)); + + bs_sm_transition_to(bs_ctx, BEARER_WLAN_REQUESTED); + +invoke_requester_cb: + ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, status); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_completed_wlan_in_non_wlan_state() - API to + * handle bearer switch to wlan completed event in non-wlan state. + * @bs_ctx: Bearer switch context + * + * This event is possible only if current bearer is non-wlan and user space + * switches the bearer to wlan first time after bringing up the LL_LT_SAP. + * Since host driver did not request for the bearer switch so there will not + * be any valid bearer switch request. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_completed_wlan_in_non_wlan_state( + struct bearer_switch_info *bs_ctx) +{ + bs_sm_transition_to(bs_ctx, BEARER_WLAN); +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state() - API to handle bearer + * switch to non-wlan in non-wlan state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Increment the ref_count. check last_status, if last status is + * QDF_STATUS_SUCCESS, then just invoke the requester callback with success, no + * need to cache the request. + * If last status is not QDF_STATUS_SUCCESS, it means last request was not + * success, so cache this request and send a non-wlan bearer switch request to + * userspace. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + QDF_STATUS status; + + ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req); + + if (QDF_IS_STATUS_SUCCESS(bs_ctx->last_status)) + return ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, + QDF_STATUS_E_ALREADY); + + ll_lt_sap_send_bs_req_to_userspace(bs_ctx->vdev, bs_req->req_type); + + status = qdf_mc_timer_start(&bs_ctx->bs_request_timer, + BEARER_SWITCH_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + ll_sap_err(BS_PREFIX_FMT "Failed to start timer", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id)); + + bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN_REQUESTED); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_in_non_wlan_requested_state() - API to handle + * bearer switch to wlan in non-wlan requested state + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Decreament the ref_count. + * 1) If total_ref_count is non-zero, it means there is some module + * which wants to be in the non-wlan state, invoke the caller of current + * requester with success and let the ongoing request for non wlan bearer + * switch get complete. + * 2) If total_ref_count is zero, it means no other module wants to be + * in non-wlan state, cache this wlan bearer switch request and invoke the + * callback of the caller with status as success, once the response of + * ongoign request of the non-wlan switch is received then check the + * total_ref_count and if it is 0, then send the request to switch to + * wlan in ll_lt_sap_handle_bs_to_non_wlan_completed, + * ll_lt_sap_handle_bs_to_non_wlan_failure or in + * ll_lt_sap_handle_bs_to_non_wlan_timeout. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_in_non_wlan_requested_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + QDF_STATUS status; + + status = ll_lt_sap_bs_decreament_ref_count(bs_ctx, bs_req); + + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (!bs_req->requester_cb) { + ll_sap_err(BS_PREFIX_FMT "NULL cbk, req_vdev %d src %d arg val %d", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id), + bs_req->vdev_id, bs_req->source, + bs_req->arg_value); + return; + } + + ll_lt_sap_cache_bs_request(bs_ctx, bs_req); + ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, status); +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_requested_state() - API to handle + * bearer switch to non wlan in non-wlan requested state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Increment the ref_count. + * Request to switch the bearer to non-wlan is already sent, cache this request + * and on receiving the response of the current non-wlan request invoke the + * callbacks of all the requesters in ll_lt_sap_handle_bs_to_non_wlan_completed, + * ll_lt_sap_handle_bs_to_non_wlan_failure, + * ll_lt_sap_handle_bs_to_non_wlan_timeout + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_requested_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req); + + ll_lt_sap_cache_bs_request(bs_ctx, bs_req); +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_timeout() - API to handle bearer switch + * to non-wlan timeout event. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Move the bearer state to BEARER_NON_WLAN, even if this request is timedout as + * requester of this request needs to invoke the bearer switch to wlan again + * to reset the ref counts and in that path the state will be moved to + * BEARER_WLAN and the request to switch the bearer to userspace will still be + * sent irrespective of last_status and userspace should return success as + * the bearer is already wlan + * If total_ref_count is non-zero, means non-wlan bearer should be there and + * no further action is required. + * If total_ref_count is zero, means none of the module wants to be in the + * non-wlan bearer and the current module which has requested for non-wlan + * bearer also requested for the wlan bearer before this event/response is + * received(switch to wlan in non-wlan requested state) and this request for + * wlan bearer switch should have been cached get that request and deliver the + * event to switch the bearer to wlan. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_timeout( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + struct wlan_bearer_switch_request *first_bs_req; + + bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN); + + bs_ctx->last_status = QDF_STATUS_E_TIMEOUT; + ll_lt_sap_invoke_bs_requester_cbks(bs_ctx, QDF_STATUS_E_TIMEOUT); + + /* + * If total_ref_count is non-zero, means non-wlan bearer should be + * there, so no further action is required + */ + if (qdf_atomic_read(&bs_ctx->total_ref_count)) + return; + + first_bs_req = ll_lt_sap_find_first_valid_bs_wlan_req(bs_ctx); + + if (!ll_lt_sap_is_bs_req_valid(first_bs_req)) { + ll_sap_err("BS_SM vdev %d Invalid total ref count %d", + wlan_vdev_get_id(bs_ctx->vdev), + qdf_atomic_read(&bs_ctx->total_ref_count)); + QDF_BUG(0); + } + + bs_sm_deliver_event(wlan_vdev_get_psoc(bs_ctx->vdev), + WLAN_BS_SM_EV_SWITCH_TO_WLAN, + sizeof(*first_bs_req), first_bs_req); +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_completed() - API to handle bearer switch + * to non-wlan complete event. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * If total_ref_count is non-zero, means non-wlan bearer should be there and + * no further action is required. + * If total_ref_count is zero, means none of the module wants to be in the + * non-wlan bearer and the current module which has requested for non-wlan + * bearer also requested for the wlan bearer before this event/response is + * received(switch to wlan in non-wlan requested state) and this request for + * wlan bearer switch should have been cached get that request and deliver the + * event to switch the bearer to wlan. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_completed( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + struct wlan_bearer_switch_request *first_bs_req; + + ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id); + + bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN); + + bs_ctx->last_status = QDF_STATUS_SUCCESS; + + ll_lt_sap_invoke_bs_requester_cbks(bs_ctx, QDF_STATUS_SUCCESS); + + /* + * If total_ref_count is non-zero, means non-wlan bearer should be + * there, so no further action is required + */ + if (qdf_atomic_read(&bs_ctx->total_ref_count)) + return; + + first_bs_req = ll_lt_sap_find_first_valid_bs_wlan_req(bs_ctx); + + if (!ll_lt_sap_is_bs_req_valid(first_bs_req)) { + ll_sap_err("BS_SM vdev %d Invalid total ref count %d", + wlan_vdev_get_id(bs_ctx->vdev), + qdf_atomic_read(&bs_ctx->total_ref_count)); + QDF_BUG(0); + } + + bs_sm_deliver_event(wlan_vdev_get_psoc(bs_ctx->vdev), + WLAN_BS_SM_EV_SWITCH_TO_WLAN, + sizeof(*first_bs_req), first_bs_req); +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_failure() - API to handle bearer switch + * to non-wlan failure event. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Move the bearer state to BEARER_NON_WLAN, even if this request is failed as + * requester of this request needs to invoke the bearer switch to wlan again + * to reset the ref counts and in that path the state will be moved to + * BEARER_WLAN and the request to switch the bearer to userspace will still be + * sent irrespective of last_status and userspace should return success as + * the bearer is already wlan + * If total_ref_count is non-zero, means non-wlan bearer should be there and + * no further action is required. + * If total_ref_count is zero, means none of the module wants to be in the + * non-wlan bearer and the current module which has requested for non-wlan + * bearer also requested for the wlan bearer before this event/response is + * received(switch to wlan in non-wlan requested state) and this request for + * wlan bearer switch should have been cached get that request and deliver the + * event to switch the bearer to wlan. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_failure( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + struct wlan_bearer_switch_request *first_bs_req; + + ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id); + + bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN); + + bs_ctx->last_status = QDF_STATUS_E_FAILURE; + + ll_lt_sap_invoke_bs_requester_cbks(bs_ctx, QDF_STATUS_E_FAILURE); + + /* + * If total_ref_count is non-zero, means non-wlan bearer should be + * there, so no further action is required + */ + if (qdf_atomic_read(&bs_ctx->total_ref_count)) + return; + + first_bs_req = ll_lt_sap_find_first_valid_bs_wlan_req(bs_ctx); + + if (!ll_lt_sap_is_bs_req_valid(first_bs_req)) { + ll_sap_err("BS_SM vdev %d Invalid total ref count %d", + wlan_vdev_get_id(bs_ctx->vdev), + qdf_atomic_read(&bs_ctx->total_ref_count)); + QDF_BUG(0); + } + + bs_sm_deliver_event(wlan_vdev_get_psoc(bs_ctx->vdev), + WLAN_BS_SM_EV_SWITCH_TO_WLAN, + sizeof(*first_bs_req), first_bs_req); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_in_wlan_state() - API to handle bearer switch + * to wlan in wlan state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Ideally this scenario should not occur, but in any case if this happens then + * simply invoke the requester callback with QDF_STATUS_E_ALREADY status + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_in_wlan_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + ll_lt_sap_invoke_req_callback(bs_ctx, bs_req, QDF_STATUS_E_ALREADY); +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state() - API to handle bearer switch + * to non-wlan in wlan state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Increment the ref count, cache the request, send the non-wlan bearer switch + * request to userspace and transition thestate to BEARER_NON_WLAN_REQUESTED + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + QDF_STATUS status; + + if (!bs_req->requester_cb) { + ll_sap_err(BS_PREFIX_FMT "NULL cbk, req_vdev %d src %d arg val %d", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id), + bs_req->vdev_id, bs_req->source, + bs_req->arg_value); + return; + } + + ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req); + + ll_lt_sap_cache_bs_request(bs_ctx, bs_req); + + /* + * Todo, Send bearer switch request to userspace + */ + + bs_sm_transition_to(bs_ctx, BEARER_NON_WLAN_REQUESTED); + + status = qdf_mc_timer_start(&bs_ctx->bs_request_timer, + BEARER_SWITCH_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + ll_sap_err(BS_PREFIX_FMT "Failed to start timer", + BS_PREFIX_REF(wlan_vdev_get_id(bs_ctx->vdev), + bs_req->request_id)); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_in_wlan_req_state() - API to handle bearer switch + * to wlan in wlan requested state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * This scenario is not possible as if already switch to wlan is + * requested it means total_ref_count is already zero, so no other + * module should request for the bearer to switch to wlan. Hence drop + * this request. + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_in_wlan_req_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ +} + +/** + * ll_lt_sap_handle_bs_to_non_wlan_in_wlan_req_state() - API to handle bearer + * switch to non-wlan in wlan requested state. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Increment the reference count and cache the request so that on + * receiving the response of the ongoing wlan switch request, switch + * to non-wlan can be issued from ll_lt_sap_handle_bs_to_wlan_completed, + * ll_lt_sap_handle_bs_to_wlan_timeout or from + * ll_lt_sap_handle_bs_to_wlan_failure + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_non_wlan_in_wlan_req_state( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + ll_lt_sap_bs_increament_ref_count(bs_ctx, bs_req); + + ll_lt_sap_cache_bs_request(bs_ctx, bs_req); +} + +/** + * ll_lt_sap_switch_to_non_wlan_from_wlan() - API to issue bearer switch + * request to non-wlan bearer from wlan-requested state response + * @bs_ctx: Bearer switch info + * + * This function handles the case when someone requested for non-wlan + * bearer-switch in between of ongoing non-wlan to wlan bearer switch request. + * check if any non-wlan bearer switch request is issued before receiving this + * response then switch to non-wlan bearer + * + * Return: None + */ +static void +ll_lt_sap_switch_to_non_wlan_from_wlan(struct bearer_switch_info *bs_ctx) +{ + struct wlan_bearer_switch_request *bs_req; + + /* no request for wlan to no-wlan bearer switch */ + if (!qdf_atomic_read(&bs_ctx->total_ref_count)) + return; + + bs_req = ll_lt_sap_find_first_valid_bs_non_wlan_req(bs_ctx); + + if (!ll_lt_sap_is_bs_req_valid(bs_req)) { + ll_sap_err("BS_SM vdev %d Invalid total ref count %d", + wlan_vdev_get_id(bs_ctx->vdev), + qdf_atomic_read(&bs_ctx->total_ref_count)); + QDF_BUG(0); + } + + bs_sm_deliver_event(wlan_vdev_get_psoc(bs_ctx->vdev), + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN, + sizeof(*bs_req), bs_req); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_timeout() - API to handle bearer switch + * to wlan timeout event. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * Transition the state to wlan even in case of timeout as well, because from + * the wlan point of view total_ref_count is 0 which means it is ready for + * wlan bear Update last_status as QDF_STATUS_E_FAILURE and check if any + * non-wlan bearer switch request is issued before receiving this response + * then switch to non-wlan bearer + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_timeout( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + bs_sm_transition_to(bs_ctx, BEARER_WLAN); + + if (bs_req->source == BEARER_SWITCH_REQ_FW) + ll_lt_sap_deliver_audio_transport_switch_resp_to_fw( + bs_ctx->vdev, + bs_req->req_type, + WLAN_BS_STATUS_TIMEOUT); + + bs_ctx->last_status = QDF_STATUS_E_TIMEOUT; + + ll_lt_sap_switch_to_non_wlan_from_wlan(bs_ctx); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_completed() - API to handle bearer switch + * to wlan complete event. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * This event will be delivered by vendor command in the wlan requested state. + * Stop the bearer switch timer, move the state to BEARER_WLAN and update the + * last_status as QDF_STATUS_SUCCESS and check if any non-wlan bearer switch + * request is issued before receiving this response then switch to non-wlan + * bearer + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_completed( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id); + + bs_sm_transition_to(bs_ctx, BEARER_WLAN); + + bs_ctx->last_status = QDF_STATUS_SUCCESS; + + ll_lt_sap_switch_to_non_wlan_from_wlan(bs_ctx); +} + +/** + * ll_lt_sap_handle_bs_to_wlan_failure() - API to handle bearer switch + * to wlan failure event. + * @bs_ctx: Bearer switch context + * @bs_req: Bearer switch request + * + * This event will be delivered by vendor command in the wlan requested state + * Stop the bearer switch timer,transition the state to wlan even in case of + * failure as well, because from the wlan point of view total_ref_count is 0 + * which means it is ready for wlan bearer + * Update last_status as QDF_STATUS_E_FAILURE and check if any non-wlan bearer + * switch request is issued before receiving this response then switch to + * non-wlan bearer + * + * Return: None + */ +static void +ll_lt_sap_handle_bs_to_wlan_failure( + struct bearer_switch_info *bs_ctx, + struct wlan_bearer_switch_request *bs_req) +{ + ll_lt_sap_stop_bs_timer(bs_ctx, bs_req->request_id); + + bs_sm_transition_to(bs_ctx, BEARER_WLAN); + + bs_ctx->last_status = QDF_STATUS_E_FAILURE; + + ll_lt_sap_switch_to_non_wlan_from_wlan(bs_ctx); +} + +/** + * bs_state_non_wlan_entry() - Entry API for non wlan state for bearer switch + * state machine + * @ctx: Bearer switch context + * + * API to perform operations on moving to non-wlan state + * + * Return: void + */ +static void bs_state_non_wlan_entry(void *ctx) +{ + struct bearer_switch_info *bs_ctx = ctx; + + bs_sm_state_update(bs_ctx, BEARER_NON_WLAN); +} + +/** + * bs_state_non_wlan_exit() - Exit API for non wlan state for bearer switch + * state machine + * @ctx: Bearer switch context + * + * API to perform operations on exiting from non-wlan state + * + * Return: void + */ +static void bs_state_non_wlan_exit(void *ctx) +{ +} + +/** + * bs_state_non_wlan_event() - Non-wlan State event handler for bearer switch + * state machine + * @ctx: Bearer switch context + * @event: event + * @data_len: length of @data + * @data: event data + * + * API to handle events in Non-wlan state + * + * Return: bool + */ +static bool bs_state_non_wlan_event(void *ctx, uint16_t event, + uint16_t data_len, void *data) +{ + bool event_handled = true; + struct bearer_switch_info *bs_ctx = ctx; + struct wlan_bearer_switch_request *bs_req = data; + + if (event != WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED && + !ll_lt_sap_is_bs_req_valid(bs_req)) + return false; + if (!ll_lt_sap_is_bs_ctx_valid(bs_ctx)) + return false; + + switch (event) { + case WLAN_BS_SM_EV_SWITCH_TO_WLAN: + ll_lt_sap_handle_bs_to_wlan_in_non_wlan_state(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN: + ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_state(bs_ctx, + bs_req); + break; + /* + * This event is possible when userspace first time sends the request + * to switch the bearer. + */ + case WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED: + ll_lt_sap_handle_bs_to_wlan_completed_wlan_in_non_wlan_state( + bs_ctx); + break; + default: + event_handled = false; + break; + } + + return event_handled; +} + +/** + * bs_state_non_wlan_req_entry() - Entry API for non wlan requested state for + * bearer switch state machine + * @ctx: Bearer switch context + * + * API to perform operations on moving to non-wlan requested state + * + * Return: void + */ +static void bs_state_non_wlan_req_entry(void *ctx) +{ + struct bearer_switch_info *bs_ctx = ctx; + + bs_sm_state_update(bs_ctx, BEARER_NON_WLAN_REQUESTED); +} + +/** + * bs_state_non_wlan_req_exit() - Exit API for non wlan requested state for + * bearer switch state machine + * @ctx: Bearer switch context + * + * API to perform operations on exiting from non-wlan requested state + * + * Return: void + */ +static void bs_state_non_wlan_req_exit(void *ctx) +{ +} + +/** + * bs_state_non_wlan_req_event() - Non-wlan requested State event handler for + * bearer switch state machine + * @ctx: Bearer switch context + * @event: event + * @data_len: length of @data + * @data: event data + * + * API to handle events in Non-wlan requested state + * + * Return: bool + */ +static bool bs_state_non_wlan_req_event(void *ctx, uint16_t event, + uint16_t data_len, void *data) +{ + bool event_handled = true; + struct bearer_switch_info *bs_ctx = ctx; + struct wlan_bearer_switch_request *bs_req = data; + + if (!ll_lt_sap_is_bs_req_valid(bs_req)) + return false; + if (!ll_lt_sap_is_bs_ctx_valid(bs_ctx)) + return false; + + switch (event) { + case WLAN_BS_SM_EV_SWITCH_TO_WLAN: + ll_lt_sap_handle_bs_to_wlan_in_non_wlan_requested_state(bs_ctx, + bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN: + ll_lt_sap_handle_bs_to_non_wlan_in_non_wlan_requested_state( + bs_ctx, + bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_TIMEOUT: + ll_lt_sap_handle_bs_to_non_wlan_timeout(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED: + ll_lt_sap_handle_bs_to_non_wlan_completed(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_FAILURE: + ll_lt_sap_handle_bs_to_non_wlan_failure(bs_ctx, bs_req); + break; + default: + event_handled = false; + break; + } + + return event_handled; +} + +/** + * bs_state_wlan_entry() - Entry API for wlan state for bearer switch + * state machine + * @ctx: Bearer switch context + * + * API to perform operations on moving to wlan state + * + * Return: void + */ +static void bs_state_wlan_entry(void *ctx) +{ + struct bearer_switch_info *bs_ctx = ctx; + + bs_sm_state_update(bs_ctx, BEARER_WLAN); +} + +/** + * bs_state_wlan_exit() - Exit API for wlan state for bearer switch + * state machine + * @ctx: Bearer switch context + * + * API to perform operations on exiting from wlan state + * + * Return: void + */ +static void bs_state_wlan_exit(void *ctx) +{ +} + +/** + * bs_state_wlan_event() - Wlan State event handler for bearer switch + * state machine + * @ctx: Bearer switch context + * @event: event + * @data_len: length of @data + * @data: event data + * + * API to handle events in Wlan state + * + * Return: bool + */ +static bool bs_state_wlan_event(void *ctx, uint16_t event, + uint16_t data_len, void *data) +{ + bool event_handled = true; + struct bearer_switch_info *bs_ctx = ctx; + struct wlan_bearer_switch_request *bs_req = data; + + if (!ll_lt_sap_is_bs_req_valid(bs_req)) + return false; + if (!ll_lt_sap_is_bs_ctx_valid(bs_ctx)) + return false; + + switch (event) { + case WLAN_BS_SM_EV_SWITCH_TO_WLAN: + ll_lt_sap_handle_bs_to_wlan_in_wlan_state(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN: + ll_lt_sap_handle_bs_to_non_wlan_in_wlan_state(bs_ctx, bs_req); + break; + default: + event_handled = false; + break; + } + + return event_handled; +} + +/** + * bs_state_wlan_req_entry() - Entry API for Wlan requested state for + *bearer switch state machine + * @ctx: Bearer switch context + * + * API to perform operations on moving to Wlan requested state + * + * Return: void + */ +static void bs_state_wlan_req_entry(void *ctx) +{ +} + +/** + * bs_state_wlan_req_exit() - Exit API for Wlan requested state for + * bearer switch state machine + * @ctx: Bearer switch context + * + * API to perform operations on exiting from Wlan requested state + * + * Return: void + */ +static void bs_state_wlan_req_exit(void *ctx) +{ + struct bearer_switch_info *bs_ctx = ctx; + + bs_sm_state_update(bs_ctx, BEARER_WLAN_REQUESTED); +} + +/** + * bs_state_wlan_req_event() - Wlan requested State event handler for + * bearer switch state machine + * @ctx: Bearer switch context + * @event: event + * @data_len: length of @data + * @data: event data + * + * API to handle events in Wlan state + * + * Return: bool + */ +static bool bs_state_wlan_req_event(void *ctx, uint16_t event, + uint16_t data_len, void *data) +{ + bool event_handled = true; + struct bearer_switch_info *bs_ctx = ctx; + struct wlan_bearer_switch_request *bs_req = data; + + if (!ll_lt_sap_is_bs_req_valid(bs_req)) + return false; + if (!ll_lt_sap_is_bs_ctx_valid(bs_ctx)) + return false; + + switch (event) { + case WLAN_BS_SM_EV_SWITCH_TO_WLAN: + ll_lt_sap_handle_bs_to_wlan_in_wlan_req_state(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN: + ll_lt_sap_handle_bs_to_non_wlan_in_wlan_req_state(bs_ctx, + bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_WLAN_TIMEOUT: + ll_lt_sap_handle_bs_to_wlan_timeout(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE: + ll_lt_sap_handle_bs_to_wlan_failure(bs_ctx, bs_req); + break; + case WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED: + ll_lt_sap_handle_bs_to_wlan_completed(bs_ctx, bs_req); + break; + default: + event_handled = false; + break; + } + + return event_handled; +} + +struct wlan_sm_state_info bs_sm_info[] = { + { + (uint8_t)BEARER_NON_WLAN, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + false, + "NON_WLAN", + bs_state_non_wlan_entry, + bs_state_non_wlan_exit, + bs_state_non_wlan_event + }, + { + (uint8_t)BEARER_NON_WLAN_REQUESTED, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + false, + "NON_WLAN_REQUESTED", + bs_state_non_wlan_req_entry, + bs_state_non_wlan_req_exit, + bs_state_non_wlan_req_event + }, + { + (uint8_t)BEARER_WLAN_REQUESTED, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + false, + "WLAN_REQUESTED", + bs_state_wlan_req_entry, + bs_state_wlan_req_exit, + bs_state_wlan_req_event + }, + { + (uint8_t)BEARER_WLAN, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + false, + "WLAN", + bs_state_wlan_entry, + bs_state_wlan_exit, + bs_state_wlan_event + }, + { + (uint8_t)BEARER_SWITCH_MAX, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + (uint8_t)WLAN_SM_ENGINE_STATE_NONE, + false, + "INVALID", + NULL, + NULL, + NULL + }, +}; + +static const char *bs_sm_event_names[] = { + "EV_SW_TO_WLAN", + "EV_SW_TO_NON_WLAN", + "EV_SW_TO_WLAN_TIMEOUT", + "EV_SW_TO_NON_WLAN_TIMEOUT", + "EV_SW_TO_WLAN_COMPLETED", + "EV_SW_TO_NON_WLAN_COMPLETED", + "EV_SW_TO_WLAN_FAILURE", + "EV_SW_TO_NON_WLAN_FAILURE", +}; + +QDF_STATUS bs_sm_create(struct bearer_switch_info *bs_ctx) +{ + struct wlan_sm *sm; + uint8_t name[WLAN_SM_ENGINE_MAX_NAME]; + + qdf_scnprintf(name, sizeof(name), "BS_%d", + wlan_vdev_get_id(bs_ctx->vdev)); + sm = wlan_sm_create(name, bs_ctx, + BEARER_NON_WLAN, + bs_sm_info, + QDF_ARRAY_SIZE(bs_sm_info), + bs_sm_event_names, + QDF_ARRAY_SIZE(bs_sm_event_names)); + if (!sm) { + ll_sap_err("Vdev %d BS_SM State Machine creation failed", + wlan_vdev_get_id(bs_ctx->vdev)); + return QDF_STATUS_E_NOMEM; + } + bs_ctx->sm.sm_hdl = sm; + + bs_lock_create(bs_ctx); + + bs_req_timer_init(bs_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bs_sm_destroy(struct bearer_switch_info *bs_ctx) +{ + bs_lock_destroy(bs_ctx); + bs_req_timer_deinit(bs_ctx); + wlan_sm_delete(bs_ctx->sm.sm_hdl); + + return QDF_STATUS_SUCCESS; +} + +/** + * bs_get_state() - Get current state of the bearer switch state machine + * @bearer_switch_ctx: lBearer switch context + * + * Return: Current state of the bearer switch state machine + */ +static enum wlan_bearer_switch_sm_state +bs_get_state(struct bearer_switch_info *bearer_switch_ctx) +{ + if (!bearer_switch_ctx || !bearer_switch_ctx->vdev) + return BEARER_SWITCH_MAX; + + return bearer_switch_ctx->sm.bs_state; +} + +/** + * bs_sm_print_state_event() - Print BS_SM state and event + * @bearer_switch_ctx: lBearer switch context + * @event: Event which needs to be printed + * + * Return: None + */ +static void +bs_sm_print_state_event(struct bearer_switch_info *bearer_switch_ctx, + enum wlan_bearer_switch_sm_evt event) +{ + enum wlan_bearer_switch_sm_state state; + + state = bs_get_state(bearer_switch_ctx); + + ll_sap_debug("[%s]%s, %s", bearer_switch_ctx->sm.sm_hdl->name, + bs_sm_info[state].name, bs_sm_event_names[event]); +} + +/** + * bs_sm_print_state() - Print BS_SM state + * @bearer_switch_ctx: lBearer switch context + * + * Return: None + */ +static void +bs_sm_print_state(struct bearer_switch_info *bearer_switch_ctx) +{ + enum wlan_bearer_switch_sm_state state; + + state = bs_get_state(bearer_switch_ctx); + + ll_sap_debug("[%s]%s", bearer_switch_ctx->sm.sm_hdl->name, + bs_sm_info[state].name); +} + +QDF_STATUS bs_sm_deliver_event(struct wlan_objmgr_psoc *psoc, + enum wlan_bearer_switch_sm_evt event, + uint16_t data_len, void *data) +{ + QDF_STATUS status; + enum wlan_bearer_switch_sm_state state_entry, state_exit; + struct bearer_switch_info *bearer_switch_ctx; + struct wlan_objmgr_vdev *vdev; + struct ll_sap_vdev_priv_obj *ll_sap_obj; + uint8_t vdev_id; + + vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc); + if (vdev_id == WLAN_INVALID_VDEV_ID) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LL_SAP_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("BS_SM vdev %d ll_sap obj null", + wlan_vdev_get_id(vdev)); + status = QDF_STATUS_E_INVAL; + goto rel_ref; + } + + bearer_switch_ctx = ll_sap_obj->bearer_switch_ctx; + if (!bearer_switch_ctx) { + status = QDF_STATUS_E_FAILURE; + goto rel_ref; + } + + bs_lock_acquire(bearer_switch_ctx); + + /* store entry state and sub state for prints */ + state_entry = bs_get_state(bearer_switch_ctx); + bs_sm_print_state_event(bearer_switch_ctx, event); + + status = wlan_sm_dispatch(bearer_switch_ctx->sm.sm_hdl, + event, data_len, data); + /* Take exit state, exit substate for prints */ + state_exit = bs_get_state(bearer_switch_ctx); + + /* If no state change, don't print */ + if (!(state_entry == state_exit)) + bs_sm_print_state(bearer_switch_ctx); + bs_lock_release(bearer_switch_ctx); + +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); + + return status; +} + +QDF_STATUS +ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request) +{ + return bs_sm_deliver_event(psoc, WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN, + sizeof(*bs_request), bs_request); +} + +QDF_STATUS +ll_lt_sap_switch_bearer_to_wlan(struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request) +{ + return bs_sm_deliver_event(psoc, WLAN_BS_SM_EV_SWITCH_TO_WLAN, + sizeof(*bs_request), bs_request); +} + +QDF_STATUS +ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type) +{ + struct ll_sap_vdev_priv_obj *ll_sap_obj; + struct bearer_switch_info *bearer_switch_ctx; + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("BS_SM vdev %d ll_sap obj null", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + bearer_switch_ctx = ll_sap_obj->bearer_switch_ctx; + if (!bearer_switch_ctx) + return QDF_STATUS_E_INVAL; + + /* + * Request to switch to non-wlan can always be accepted so, + * always return success + */ + if (req_type == WLAN_BS_REQ_TO_NON_WLAN) { + ll_sap_debug("BS_SM vdev %d WLAN_BS_REQ_TO_NON_WLAN accepted", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_SUCCESS; + } else if (req_type == WLAN_BS_REQ_TO_WLAN) { + /* + * Total_ref_count zero indicates that no module wants to stay + * in non-wlan mode so this request can be accepted + */ + if (!qdf_atomic_read(&bearer_switch_ctx->total_ref_count)) { + ll_sap_debug("BS_SM vdev %d WLAN_BS_REQ_TO_WLAN accepted", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_SUCCESS; + } + ll_sap_debug("BS_SM vdev %d WLAN_BS_REQ_TO_WLAN rejected", + wlan_vdev_get_id(vdev)); + + return QDF_STATUS_E_FAILURE; + } + ll_sap_err("BS_SM vdev %d Invalid audio transport type %d", + wlan_vdev_get_id(vdev), req_type); + + return QDF_STATUS_E_INVAL; +} + +/** + * ll_lt_sap_deliver_wlan_audio_transport_switch_resp() - Deliver wlan + * audio transport switch response to BS_SM + * @vdev: ll_lt sap vdev + * @status: Status of the request + * + * Return: None + */ +static void ll_lt_sap_deliver_wlan_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_status status) +{ + struct wlan_bearer_switch_request *bs_request; + struct ll_sap_vdev_priv_obj *ll_sap_obj; + struct bearer_switch_info *bs_ctx; + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("BS_SM vdev %d ll_sap obj null", + wlan_vdev_get_id(vdev)); + return; + } + + bs_ctx = ll_sap_obj->bearer_switch_ctx; + if (!bs_ctx) + return; + + bs_request = ll_lt_sap_find_first_valid_bs_wlan_req(bs_ctx); + + /* + * If bs_request is cached in the BS_SM, it means this is a response + * to the host driver's request of bearer switch so deliver the event + * to the BS_SM + * If there is no cached request in BS_SM, it means that some other + * module (other than wlan) has performed the bearer switch and it is + * not a response of the wlan module's bearer switch request. + */ + if (status == WLAN_BS_STATUS_COMPLETED) + bs_sm_deliver_event(wlan_vdev_get_psoc(vdev), + WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED, + sizeof(*bs_request), bs_request); + else if (status == WLAN_BS_STATUS_REJECTED) + bs_sm_deliver_event(wlan_vdev_get_psoc(vdev), + WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE, + sizeof(*bs_request), bs_request); + else + ll_sap_err("BS_SM vdev %d Invalid BS status %d", + wlan_vdev_get_id(vdev), status); +} + +/** + * ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp() - Deliver non wlan + * audio transport switch response to BS_SM + * @vdev: ll_lt sap vdev + * @status: Status of the request + * + * Return: None + */ +static void ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_status status) +{ + struct wlan_bearer_switch_request *bs_request; + struct ll_sap_vdev_priv_obj *ll_sap_obj; + struct bearer_switch_info *bs_ctx; + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("BS_SM vdev %d ll_sap obj null", + wlan_vdev_get_id(vdev)); + return; + } + + bs_ctx = ll_sap_obj->bearer_switch_ctx; + if (!bs_ctx) + return; + + bs_request = ll_lt_sap_find_first_valid_bs_non_wlan_req(bs_ctx); + + /* + * If bs_request is cached in the BS_SM, it means this is a response + * to the host driver's request of bearer switch so deliver the event + * to the BS_SM + */ + if (bs_request) { + if (status == WLAN_BS_STATUS_COMPLETED) + bs_sm_deliver_event( + wlan_vdev_get_psoc(vdev), + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED, + sizeof(*bs_request), bs_request); + else if (status == WLAN_BS_STATUS_REJECTED) + bs_sm_deliver_event( + wlan_vdev_get_psoc(vdev), + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_FAILURE, + sizeof(*bs_request), bs_request); + else + ll_sap_err(BS_PREFIX_FMT "Invalid BS status %d", + BS_PREFIX_REF(wlan_vdev_get_id(vdev), + bs_request->request_id), + status); + + return; + } + + /* + * If there is no cached request in BS_SM, it means that some other + * module has performed the bearer switch and it is not a response of + * the wlan bearer switch request, so just update the current state of + * the state machine + */ + bs_sm_state_update(bs_ctx, BEARER_NON_WLAN); +} + +void +ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ + ll_lt_sap_deliver_audio_transport_switch_resp_to_fw(vdev, req_type, + status); + + if (req_type == WLAN_BS_REQ_TO_NON_WLAN) + ll_lt_sap_deliver_non_wlan_audio_transport_switch_resp( + vdev, + status); + + else if (req_type == WLAN_BS_REQ_TO_WLAN) + ll_lt_sap_deliver_wlan_audio_transport_switch_resp( + vdev, + status); + else + ll_sap_err("Vdev %d Invalid req_type %d ", + wlan_vdev_get_id(vdev), req_type); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.h new file mode 100644 index 0000000000..c74506d188 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.h @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_lt_sap declarations specific to the bearer + * switch functionalities + */ + +#ifndef _WLAN_LL_LT_SAP_BEARER_SWITCH_H_ +#define _WLAN_LL_LT_SAP_BEARER_SWITCH_H_ + +#include "wlan_ll_sap_public_structs.h" +#include +#include "wlan_cmn.h" +#include "wlan_ll_sap_main.h" +#include "wlan_sm_engine.h" + +/** + * enum wlan_bearer_switch_sm_state - Bearer switch states + * @BEARER_NON_WLAN: Default state, Bearer non wlan state + * @BEARER_NON_WLAN_REQUESTED: State when bearer switch requested to non-wlan + * @BEARER_WLAN_REQUESTED: State when bearer switch requested to wlan + * @BEARER_WLAN: Bearer non wlan state + * @BEARER_SWITCH_MAX: Max state + */ +enum wlan_bearer_switch_sm_state { + BEARER_NON_WLAN = 0, + BEARER_NON_WLAN_REQUESTED = 1, + BEARER_WLAN_REQUESTED = 2, + BEARER_WLAN = 3, + BEARER_SWITCH_MAX = 4, +}; + +/** + * enum wlan_bearer_switch_sm_evt - Bearer switch related events, if any new + * enum is added to this enum, then please update bs_sm_event_names + * @WLAN_BS_SM_EV_SWITCH_TO_WLAN: Bearer switch request to WLAN + * @WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN: Bearer switch request to NON WLAN + * @WLAN_BS_SM_EV_SWITCH_TO_WLAN_TIMEOUT: Bearer switch request to WLA + * timeout + * @WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_TIMEOUT: Bearer switch request to NON-WLAN + * timeout + * @WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED: Bearer switch request to WLAN + * completed + * @WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED: Bearer switch request to + * NON-WLAN completed + * @WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE: Bearer switch request to WLAN + * failure + * @WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_FAILURE: Bearer switch request to NON-WLAN + * failure + */ +enum wlan_bearer_switch_sm_evt { + WLAN_BS_SM_EV_SWITCH_TO_WLAN = 0, + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN = 1, + WLAN_BS_SM_EV_SWITCH_TO_WLAN_TIMEOUT = 2, + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_TIMEOUT = 3, + WLAN_BS_SM_EV_SWITCH_TO_WLAN_COMPLETED = 4, + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_COMPLETED = 5, + WLAN_BS_SM_EV_SWITCH_TO_WLAN_FAILURE = 6, + WLAN_BS_SM_EV_SWITCH_TO_NON_WLAN_FAILURE = 7, +}; + +/** + * struct bs_state_sm - Bearer switch state machine + * @bs_sm_lock: sm lock + * @sm_hdl: sm handlers + * @bs_state: bearer switch state + */ +struct bs_state_sm { + qdf_mutex_t bs_sm_lock; + struct wlan_sm *sm_hdl; + enum wlan_bearer_switch_sm_state bs_state; +}; + +/** + * struct bearer_switch_info - Data structure to store the bearer switch + * requests and related information + * @vdev: Pointer to the ll lt sap vdev + * @request_id: Last allocated request id + * @sm: state machine context + * @ref_count: Reference count corresponding to each vdev and requester + * @fw_ref_count: Reference counts for the firmware requests + * @total_ref_count: Total reference counts + * @last_status:status of the last bearer switch request + * @requests: Array of bearer_switch_requests to cache the request information + * @bs_request_timer: Bearer switch request timer + */ +struct bearer_switch_info { + struct wlan_objmgr_vdev *vdev; + qdf_atomic_t request_id; + struct bs_state_sm sm; + qdf_atomic_t ref_count[WLAN_UMAC_PSOC_MAX_VDEVS][BEARER_SWITCH_REQ_MAX]; + qdf_atomic_t fw_ref_count; + qdf_atomic_t total_ref_count; + QDF_STATUS last_status; + struct wlan_bearer_switch_request requests[MAX_BEARER_SWITCH_REQUESTERS]; + qdf_mc_timer_t bs_request_timer; +}; + +/** + * ll_lt_sap_bearer_switch_get_id() - Get the request id for bearer switch + * request + * @psoc: Pointer to psoc + * Return: Bearer switch request id + */ +wlan_bs_req_id ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc); + +/** + * bs_sm_create() - Invoke SM creation for bearer switch + * @bs_ctx: Bearer switch context + * + * Return: SUCCESS on successful creation + * FAILURE, if creation fails + */ +QDF_STATUS bs_sm_create(struct bearer_switch_info *bs_ctx); + +/** + * bs_sm_destroy() - Invoke SM deletion for bearer switch + * @bs_ctx: Bearer switch context + * + * Return: SUCCESS on successful deletion + * FAILURE, if deletion fails + */ +QDF_STATUS bs_sm_destroy(struct bearer_switch_info *bs_ctx); + +/** + * bs_lock_create() - Create BS SM mutex + * @bs_ctx: Bearer switch ctx + * + * Creates Bearer switch state machine mutex + * + * Return: void + */ +static inline void bs_lock_create(struct bearer_switch_info *bs_ctx) +{ + qdf_mutex_create(&bs_ctx->sm.bs_sm_lock); +} + +/** + * bs_lock_destroy() - Create BS SM mutex + * @bs_ctx: Bearer switch ctx + * + * Deatroys Bearer switch state machine mutex + * + * Return: void + */ +static inline void bs_lock_destroy(struct bearer_switch_info *bs_ctx) +{ + qdf_mutex_destroy(&bs_ctx->sm.bs_sm_lock); +} + +/** + * bs_lock_acquire() - Acquires BS SM mutex + * @bs_ctx: Bearer switch ctx + * + * Acquire Bearer switch state machine mutex + * + * Return: void + */ +static inline void bs_lock_acquire(struct bearer_switch_info *bs_ctx) +{ + qdf_mutex_acquire(&bs_ctx->sm.bs_sm_lock); +} + +/** + * bs_lock_release() - Release BS SM mutex + * @bs_ctx: Bearer switch ctx + * + * Releases Bearer switch state machine mutex + * + * Return: void + */ +static inline void bs_lock_release(struct bearer_switch_info *bs_ctx) +{ + qdf_mutex_release(&bs_ctx->sm.bs_sm_lock); +} + +/** + * bs_sm_transition_to() - invokes state transition + * @bs_ctx: Bearer switch ctx + * @state: new cm state + * + * API to invoke SM API to move to new state + * + * Return: void + */ +static inline void bs_sm_transition_to(struct bearer_switch_info *bs_ctx, + enum wlan_bearer_switch_sm_state state) +{ + wlan_sm_transition_to(bs_ctx->sm.sm_hdl, state); +} + +/** + * bs_sm_deliver_event() - Delivers event to Bearer switch SM + * @psoc: Pointer to psoc + * @event: BS event + * @data_len: data size + * @data: event data + * + * API to dispatch event to Bearer switch state machine. To be used while + * posting events from API called from public API. + * + * Return: SUCCESS: on handling event + * FAILURE: If event not handled + */ +QDF_STATUS bs_sm_deliver_event(struct wlan_objmgr_psoc *psoc, + enum wlan_bearer_switch_sm_evt event, + uint16_t data_len, void *data); + +/** + * bs_req_timer_init() - Initialize Bearer switch request timer + * @bs_ctx: Bearer switch context + * + * Return: None + */ +void bs_req_timer_init(struct bearer_switch_info *bs_ctx); + +/** + * bs_req_timer_deinit() - De-initialize Bearer switch request timer + * @bs_ctx: Bearer switch context + * + * Return: None + */ +void bs_req_timer_deinit(struct bearer_switch_info *bs_ctx); + +/** + * ll_lt_sap_is_bs_ctx_valid() - Check if bearer switch context is valid or not + * @bs_ctx: Bearer switch context + * + * Return: True if bearer switch context is valid else return false + */ +#define ll_lt_sap_is_bs_ctx_valid(bs_ctx) \ + __ll_lt_sap_is_bs_ctx_valid(bs_ctx, __func__) + +bool __ll_lt_sap_is_bs_ctx_valid(struct bearer_switch_info *bs_ctx, + const char *func); + +/** + * ll_lt_sap_is_bs_req_valid() - Check if bearer switch request is valid or not + * @bs_req: Bearer switch request + * + * Return: True if bearer switch request is valid else return false + */ +#define ll_lt_sap_is_bs_req_valid(bs_req) \ + __ll_lt_sap_is_bs_req_valid(bs_req, __func__) + +bool __ll_lt_sap_is_bs_req_valid(struct wlan_bearer_switch_request *bs_req, + const char *func); + +/** + * ll_lt_sap_switch_bearer_to_ble() - Switch audio transport to BLE + * @psoc: Pointer to psoc + * @bs_request: Pointer to bearer switch request + * Return: QDF_STATUS_SUCCESS on successful bearer switch else failure + */ +QDF_STATUS +ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request); + +/** + * ll_lt_sap_switch_bearer_to_wlan() - Switch audio transport to BLE + * @psoc: Pointer to psoc + * @bs_request: Pointer to bearer switch request + * Return: QDF_STATUS_SUCCESS on successful bearer switch else failure + */ +QDF_STATUS +ll_lt_sap_switch_bearer_to_wlan(struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request); + +/** + * ll_lt_sap_request_for_audio_transport_switch() - Handls audio transport + * switch request from userspace + * @vdev: Vdev on which the request is received + * @req_type: requested transport switch type + * + * Return: True/False + */ +QDF_STATUS +ll_lt_sap_request_for_audio_transport_switch(struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type); + +/** + * ll_lt_sap_deliver_audio_transport_switch_resp() - Deliver audio + * transport switch response + * @vdev: Vdev on which the request is received + * @req_type: Transport switch type for which the response is received + * @status: Status of the response + * + * Return: None + */ +void +ll_lt_sap_deliver_audio_transport_switch_resp(struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status); + +#endif /* _WLAN_LL_LT_SAP_BEARER_SWITCH_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c new file mode 100644 index 0000000000..62d2d14411 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c @@ -0,0 +1,456 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_ll_lt_sap_main.h" +#include "wlan_reg_services_api.h" +#include "wlan_ll_sap_public_structs.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_ll_sap_main.h" +#include "wlan_ll_lt_sap_bearer_switch.h" +#include "wlan_scan_api.h" +#include "target_if.h" + +bool ll_lt_sap_is_supported(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + ll_sap_err("Invalid WMI handle"); + return false; + } + + return wmi_service_enabled(wmi_handle, wmi_service_xpan_support); +} + +/** + * ll_lt_sap_get_sorted_user_config_acs_ch_list() - API to get sorted user + * configured ACS channel list + * @psoc: Pointer to psoc object + * @vdev_id: Vdev Id + * @ch_info: Pointer to ch_info + * + * Return: None + */ +static +QDF_STATUS ll_lt_sap_get_sorted_user_config_acs_ch_list( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct sap_sel_ch_info *ch_info) +{ + struct scan_filter *filter; + qdf_list_t *list = NULL; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LL_SAP_ID); + + if (!vdev) { + ll_sap_err("Invalid vdev for vdev_id %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + pdev = wlan_vdev_get_pdev(vdev); + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + goto rel_ref; + + wlan_sap_get_user_config_acs_ch_list(vdev_id, filter); + + list = wlan_scan_get_result(pdev, filter); + + qdf_mem_free(filter); + + if (!list) + goto rel_ref; + + status = wlan_ll_sap_sort_channel_list(vdev_id, list, ch_info); + + wlan_scan_purge_results(list); + +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); + + return status; +} + +QDF_STATUS ll_lt_sap_init(struct wlan_objmgr_vdev *vdev) +{ + struct ll_sap_vdev_priv_obj *ll_sap_obj; + QDF_STATUS status; + uint8_t i, j; + struct bearer_switch_info *bs_ctx; + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("vdev %d ll_sap obj null", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + bs_ctx = qdf_mem_malloc(sizeof(struct bearer_switch_info)); + if (!bs_ctx) + return QDF_STATUS_E_NOMEM; + + ll_sap_obj->bearer_switch_ctx = bs_ctx; + + qdf_atomic_init(&bs_ctx->request_id); + + for (i = 0; i < WLAN_UMAC_PSOC_MAX_VDEVS; i++) + for (j = 0; j < BEARER_SWITCH_REQ_MAX; j++) + qdf_atomic_init(&bs_ctx->ref_count[i][j]); + + qdf_atomic_init(&bs_ctx->fw_ref_count); + qdf_atomic_init(&bs_ctx->total_ref_count); + + bs_ctx->vdev = vdev; + + status = bs_sm_create(bs_ctx); + + if (QDF_IS_STATUS_ERROR(status)) + goto bs_sm_failed; + + ll_sap_debug("vdev %d", wlan_vdev_get_id(vdev)); + + return QDF_STATUS_SUCCESS; + +bs_sm_failed: + qdf_mem_free(ll_sap_obj->bearer_switch_ctx); + ll_sap_obj->bearer_switch_ctx = NULL; + return status; +} + +QDF_STATUS ll_lt_sap_deinit(struct wlan_objmgr_vdev *vdev) +{ + struct ll_sap_vdev_priv_obj *ll_sap_obj; + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("vdev %d ll_sap obj null", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + if (!ll_sap_obj->bearer_switch_ctx) { + ll_sap_debug("vdev %d Bearer switch context is NULL", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + bs_sm_destroy(ll_sap_obj->bearer_switch_ctx); + qdf_mem_free(ll_sap_obj->bearer_switch_ctx); + ll_sap_obj->bearer_switch_ctx = NULL; + + ll_sap_debug("vdev %d", wlan_vdev_get_id(vdev)); + + return QDF_STATUS_SUCCESS; +} + +static +void ll_lt_sap_update_mac_freq(struct wlan_ll_lt_sap_mac_freq *freq_list, + qdf_freq_t sbs_cut_off_freq, + qdf_freq_t given_freq, uint32_t given_weight) +{ + if (WLAN_REG_IS_5GHZ_CH_FREQ(given_freq) && + ((sbs_cut_off_freq && given_freq < sbs_cut_off_freq) || + !sbs_cut_off_freq) && !freq_list->freq_5GHz_low) { + freq_list->freq_5GHz_low = given_freq; + freq_list->weight_5GHz_low = given_weight; + + /* + * Update same freq in 5GHz high freq if sbs_cut_off_freq + * is not present + */ + if (!sbs_cut_off_freq) { + freq_list->freq_5GHz_high = given_freq; + freq_list->weight_5GHz_high = given_weight; + } + } else if (WLAN_REG_IS_5GHZ_CH_FREQ(given_freq) && + ((sbs_cut_off_freq && given_freq > sbs_cut_off_freq) || + !sbs_cut_off_freq) && !freq_list->freq_5GHz_high) { + freq_list->freq_5GHz_high = given_freq; + freq_list->weight_5GHz_high = given_weight; + + /* + * Update same freq for 5GHz low freq if sbs_cut_off_freq + * is not present + */ + if (!sbs_cut_off_freq) { + freq_list->freq_5GHz_low = given_freq; + freq_list->weight_5GHz_low = given_weight; + } + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(given_freq) && + !freq_list->freq_6GHz) { + freq_list->freq_6GHz = given_freq; + freq_list->weight_6GHz = given_weight; + } +} + +/* Threshold value of channel weight */ +#define CHANNEL_WEIGHT_THRESHOLD_VALUE 20000 +static +void ll_lt_sap_update_freq_list(struct wlan_objmgr_psoc *psoc, + struct sap_sel_ch_info *ch_param, + struct wlan_ll_lt_sap_freq_list *freq_list, + struct policy_mgr_pcl_list *pcl, + struct connection_info *info, + uint8_t connection_count, + uint8_t vdev_id) +{ + qdf_freq_t freq, sbs_cut_off_freq; + qdf_freq_t same_mac_freq, standalone_mac_freq; + uint8_t i = 0, count; + uint32_t weight; + enum policy_mgr_con_mode con_mode = PM_MAX_NUM_OF_MODE; + + sbs_cut_off_freq = policy_mgr_get_sbs_cut_off_freq(psoc); + + for (i = 0; i < ch_param->num_ch; i++) { + if (!ch_param->ch_info[i].valid) + continue; + + freq = ch_param->ch_info[i].chan_freq; + weight = ch_param->ch_info[i].weight; + + /* + * Do not select same channel where LL_LT_SAP was + * present earlier + */ + if (freq_list->prev_freq == freq) + continue; + + /* Check if channel is present in PCL or not */ + if (!wlan_ll_sap_freq_present_in_pcl(pcl, freq)) + continue; + + /* + * Store first valid best channel from ACS final list + * This will be used if there is no valid freq present + * within threshold value or no concurrency present + */ + if (!freq_list->best_freq) { + freq_list->best_freq = freq; + freq_list->weight_best_freq = weight; + } + + if (!connection_count) + break; + + /* + * Instead of selecting random channel, select those + * channel whose weight is less than + * CHANNEL_WEIGHT_THRESHOLD_VALUE value. This will help + * to get the best channel compartively and avoid multiple + * times of channel switch. + */ + if (weight > CHANNEL_WEIGHT_THRESHOLD_VALUE) + continue; + + same_mac_freq = 0; + standalone_mac_freq = 0; + + /* + * Loop through all existing connections before updating + * channels for LL_LT_SAP. + */ + for (count = 0; count < connection_count; count++) { + /* Do not select SCC channel to update freq_list */ + if (freq == info[count].ch_freq) { + same_mac_freq = 0; + standalone_mac_freq = 0; + break; + } + /* + * Check whether ch_param frequency is in same mac + * or not. + */ + if (policy_mgr_2_freq_always_on_same_mac( + psoc, freq, + info[count].ch_freq)) { + con_mode = policy_mgr_get_mode_by_vdev_id( + psoc, info[count].vdev_id); + /* + * Check whether SAP is present in same mac or + * not. If yes then do not select that frequency + * because two beacon entity can't be in same + * mac. + * Also, do not fill same_mac_freq if it's + * already filled i.e two existing connection + * are present on same mac. + */ + if (con_mode == PM_SAP_MODE || same_mac_freq) { + same_mac_freq = 0; + standalone_mac_freq = 0; + break; + } + same_mac_freq = freq; + } else if (!standalone_mac_freq) { + /* + * Fill standalone_mac_freq only if it's not + * filled + */ + standalone_mac_freq = freq; + } + } + + /* + * Scenario: Let say two concurrent connection(other than + * LL_LT_SAP) are present in both mac and one channel from + * ch_param structure needs to select to fill in freq_list for + * LL_LT_SAP. + * Since, there is an existing connection present in both mac + * then there is chance that channel from ch_param structure + * may get select for both same_mac_freq and standalone_mac_freq + * + * But ideally standalone_mac_freq is not free, some existing + * connection is already present in it. + * So, instead of giving priority to fill standalone_mac_freq + * first, fill same_mac_freq first. + * + * Example: Let say 2 concurrent interface present in channel + * 36 and 149. Now channel 48 from ch_param structure needs to + * be validate and fill based on existing interface. + * With respect to channel 36, it will fit to same_mac_freq + * and with respect to channel 149, it will fit to + * standalone_mac_freq. But in standalone_mac_freq, there is + * already existing interface present. So, give priority to + * same_mac_freq to fill the freq list. + */ + if (same_mac_freq) + ll_lt_sap_update_mac_freq(&freq_list->shared_mac, + sbs_cut_off_freq, + same_mac_freq, + weight); + else if (standalone_mac_freq) + ll_lt_sap_update_mac_freq(&freq_list->standalone_mac, + sbs_cut_off_freq, + standalone_mac_freq, + weight); + + if (freq_list->shared_mac.freq_5GHz_low && + freq_list->shared_mac.freq_5GHz_high && + freq_list->shared_mac.freq_6GHz && + freq_list->standalone_mac.freq_5GHz_low && + freq_list->standalone_mac.freq_5GHz_high && + freq_list->standalone_mac.freq_6GHz) + break; + } + + ll_sap_debug("vdev %d, best %d[%d] Shared: low %d[%d] high %d[%d] 6Ghz %d[%d], Standalone: low %d[%d] high %d[%d] 6Ghz %d[%d], prev %d, existing connection cnt %d", + vdev_id, freq_list->best_freq, + freq_list->weight_best_freq, + freq_list->shared_mac.freq_5GHz_low, + freq_list->shared_mac.weight_5GHz_low, + freq_list->shared_mac.freq_5GHz_high, + freq_list->shared_mac.weight_5GHz_high, + freq_list->shared_mac.freq_6GHz, + freq_list->shared_mac.weight_6GHz, + freq_list->standalone_mac.freq_5GHz_low, + freq_list->standalone_mac.weight_5GHz_low, + freq_list->standalone_mac.freq_5GHz_high, + freq_list->standalone_mac.weight_5GHz_high, + freq_list->standalone_mac.freq_6GHz, + freq_list->standalone_mac.weight_6GHz, + freq_list->prev_freq, connection_count); +} + +static +QDF_STATUS ll_lt_sap_get_allowed_freq_list( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct sap_sel_ch_info *ch_param, + struct wlan_ll_lt_sap_freq_list *freq_list) +{ + struct connection_info conn_info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t count; + struct policy_mgr_pcl_list *pcl; + QDF_STATUS status; + + pcl = qdf_mem_malloc(sizeof(*pcl)); + if (!pcl) + return QDF_STATUS_E_FAILURE; + + status = policy_mgr_get_pcl_ch_list_for_ll_sap(psoc, pcl, vdev_id, + conn_info, &count); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + ll_lt_sap_update_freq_list(psoc, ch_param, freq_list, pcl, + conn_info, count, vdev_id); + + status = QDF_STATUS_SUCCESS; +end: + qdf_mem_free(pcl); + return status; +} + +QDF_STATUS ll_lt_sap_get_freq_list(struct wlan_objmgr_psoc *psoc, + struct wlan_ll_lt_sap_freq_list *freq_list, + uint8_t vdev_id) +{ + struct sap_sel_ch_info ch_param = { NULL, 0 }; + QDF_STATUS status; + + /* + * This memory will be allocated in sap_chan_sel_init() as part + * of sap_sort_channel_list(). But the caller has to free up the + * allocated memory + */ + + status = ll_lt_sap_get_sorted_user_config_acs_ch_list(psoc, vdev_id, + &ch_param); + + if (!ch_param.num_ch || QDF_IS_STATUS_ERROR(status)) + goto release_mem; + + status = ll_lt_sap_get_allowed_freq_list(psoc, vdev_id, &ch_param, + freq_list); + +release_mem: + wlan_ll_sap_free_chan_info(&ch_param); + return status; +} + +qdf_freq_t ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_ll_lt_sap_freq_list freq_list; + + qdf_mem_zero(&freq_list, sizeof(freq_list)); + + ll_lt_sap_get_freq_list(psoc, &freq_list, vdev_id); + + if (freq_list.standalone_mac.freq_5GHz_low) + return freq_list.standalone_mac.freq_5GHz_low; + if (freq_list.shared_mac.freq_5GHz_low) + return freq_list.shared_mac.freq_5GHz_low; + if (freq_list.standalone_mac.freq_6GHz) + return freq_list.standalone_mac.freq_6GHz; + if (freq_list.standalone_mac.freq_5GHz_high) + return freq_list.standalone_mac.freq_5GHz_high; + if (freq_list.shared_mac.freq_6GHz) + return freq_list.shared_mac.freq_6GHz; + if (freq_list.shared_mac.freq_5GHz_high) + return freq_list.shared_mac.freq_5GHz_high; + + return freq_list.best_freq; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.h new file mode 100644 index 0000000000..574e88f372 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_sap_definitions specific to the ll_sap module + */ + +#ifndef _WLAN_LL_LT_SAP_MAIN_H_ +#define _WLAN_LL_LT_SAP_MAIN_H_ + +#include "wlan_ll_sap_main.h" +#include "wlan_mlme_public_struct.h" +#include +#include +#include "wlan_ll_sap_main.h" +#include "wlan_ll_sap_public_structs.h" + +/** + * ll_lt_sap_is_supported() - Check if ll_lt_sap is supported or not + * @psoc: Pointer to psoc object + * Return: True/False + */ +bool ll_lt_sap_is_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ll_lt_sap_get_freq_list() - API to get frequency list for LL_LT_SAP + * @psoc: Pointer to psoc object + * @freq_list: Pointer to wlan_ll_lt_sap_freq_list structure + * @vdev_id: Vdev Id + * + * Return: QDF_STATUS + */ +QDF_STATUS ll_lt_sap_get_freq_list(struct wlan_objmgr_psoc *psoc, + struct wlan_ll_lt_sap_freq_list *freq_list, + uint8_t vdev_id); + +/** + * ll_lt_sap_get_valid_freq() - API to get valid frequency for LL_LT_SAP + * @psoc: Pointer to psoc object + * @vdev_id: Vdev Id of ll_lt_sap + * + * Return: QDF_STATUS + */ +QDF_STATUS ll_lt_sap_get_valid_freq(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/* + * ll_lt_sap_init() - Initialize ll_lt_sap infrastructure + * @vdev: Pointer to vdev + * + * Return: QDF_STATUS_SUCCESS if ll_lt_sap infra initialized successfully else + * error code + */ +QDF_STATUS ll_lt_sap_init(struct wlan_objmgr_vdev *vdev); + +/** + * ll_lt_sap_deinit() - De-initialize ll_lt_sap infrastructure + * @vdev: Pointer to vdev + * + * Return: QDF_STATUS_SUCCESS if ll_lt_sap infra de-initialized successfully + * else error code + */ +QDF_STATUS ll_lt_sap_deinit(struct wlan_objmgr_vdev *vdev); +#endif /* _WLAN_LL_SAP_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c new file mode 100644 index 0000000000..006d2f4791 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_ll_sap_main.h" +#include +#include "qca_vendor.h" +#include "wlan_ll_lt_sap_main.h" +#include "target_if_ll_sap.h" + +struct ll_sap_ops *global_ll_sap_ops; + +static QDF_STATUS ll_sap_psoc_obj_created_notification(struct wlan_objmgr_psoc *psoc, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ll_sap_psoc_priv_obj *ll_sap_psoc_obj; + + ll_sap_psoc_obj = qdf_mem_malloc(sizeof(*ll_sap_psoc_obj)); + if (!ll_sap_psoc_obj) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("ll_sap obj attach with psoc failed"); + goto ll_sap_psoc_obj_fail; + } + + target_if_ll_sap_register_tx_ops(&ll_sap_psoc_obj->tx_ops); + target_if_ll_sap_register_rx_ops(&ll_sap_psoc_obj->rx_ops); + + ll_sap_debug("ll sap psoc object created"); + + return status; + +ll_sap_psoc_obj_fail: + qdf_mem_free(ll_sap_psoc_obj); + + return status; +} + +static QDF_STATUS ll_sap_psoc_obj_destroyed_notification(struct wlan_objmgr_psoc *psoc, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ll_sap_psoc_priv_obj *ll_sap_psoc_obj; + + ll_sap_psoc_obj = + wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_LL_SAP); + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj); + if (QDF_IS_STATUS_ERROR(status)) + ll_sap_err("ll_sap detach failed"); + + qdf_mem_free(ll_sap_psoc_obj); + + ll_sap_debug("ll sap psoc object destroyed"); + + return status; +} + +static QDF_STATUS ll_sap_vdev_obj_created_notification( + struct wlan_objmgr_vdev *vdev, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ll_sap_vdev_priv_obj *ll_sap_obj; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE) + return QDF_STATUS_SUCCESS; + + ll_sap_obj = qdf_mem_malloc(sizeof(*ll_sap_obj)); + if (!ll_sap_obj) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_vdev_component_obj_attach( + vdev, + WLAN_UMAC_COMP_LL_SAP, + (void *)ll_sap_obj, + QDF_STATUS_SUCCESS); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("vdev %d obj attach failed", wlan_vdev_get_id(vdev)); + goto ll_sap_vdev_attach_failed; + } + + status = ll_lt_sap_init(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto ll_sap_init_failed; + + return status; + +ll_sap_init_failed: + wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_LL_SAP, + ll_sap_obj); + +ll_sap_vdev_attach_failed: + qdf_mem_free(ll_sap_obj); + return status; +} + +static QDF_STATUS ll_sap_vdev_obj_destroyed_notification( + struct wlan_objmgr_vdev *vdev, void *arg_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct ll_sap_vdev_priv_obj *ll_sap_obj; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE) + return QDF_STATUS_SUCCESS; + + ll_lt_sap_deinit(vdev); + + ll_sap_obj = ll_sap_get_vdev_priv_obj(vdev); + + if (!ll_sap_obj) { + ll_sap_err("vdev %d ll sap obj null", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + status = wlan_objmgr_vdev_component_obj_detach(vdev, + WLAN_UMAC_COMP_LL_SAP, + ll_sap_obj); + if (QDF_IS_STATUS_ERROR(status)) + ll_sap_err("vdev %d ll sap obj detach failed, status %d", + wlan_vdev_get_id(vdev), status); + + qdf_mem_free(ll_sap_obj); + + return status; +} + +QDF_STATUS ll_sap_init(void) +{ + QDF_STATUS status; + + /* register psoc create handler functions. */ + status = wlan_objmgr_register_psoc_create_handler(WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_register_psoc_create_handler failed"); + return status; + } + + /* register psoc delete handler functions. */ + status = wlan_objmgr_register_psoc_destroy_handler(WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_register_psoc_destroy_handler failed"); + goto err_psoc_destroy_reg; + } + + /* register vdev create handler functions. */ + status = wlan_objmgr_register_vdev_create_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_vdev_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_register_vdev_create_handler failed"); + goto err_vdev_create_reg; + } + + /* register vdev delete handler functions. */ + status = wlan_objmgr_register_vdev_destroy_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_vdev_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_register_vdev_destroy_handler failed"); + goto err_vdev_destroy_reg; + } + + return status; +err_vdev_destroy_reg: + wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_vdev_obj_created_notification, + NULL); + +err_vdev_create_reg: + wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj_destroyed_notification, + NULL); + +err_psoc_destroy_reg: + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj_created_notification, + NULL); + + return status; +} + +QDF_STATUS ll_sap_deinit(void) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS, status; + + /* de-register vdev delete handler functions. */ + status = wlan_objmgr_unregister_vdev_destroy_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_vdev_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_unregister_vdev_destroy_handler failed"); + ret = status; + } + + /* de-register vdev create handler functions. */ + status = wlan_objmgr_unregister_vdev_create_handler( + WLAN_UMAC_COMP_LL_SAP, + ll_sap_vdev_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_unregister_vdev_create_handler failed"); + ret = status; + } + + /* unregister psoc destroy handler functions. */ + status = wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj_destroyed_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_deregister_psoc_destroy_handler failed"); + ret = status; + } + + /* unregister psoc create handler functions. */ + status = wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_LL_SAP, + ll_sap_psoc_obj_created_notification, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + ll_sap_err("objmgr_unregister_psoc_create_handler failed"); + ret = status; + } + + return ret; +} + +void ll_sap_register_os_if_cb(struct ll_sap_ops *ll_sap_global_ops) +{ + global_ll_sap_ops = ll_sap_global_ops; +} + +void ll_sap_unregister_os_if_cb(void) +{ + global_ll_sap_ops = NULL; +} + +struct ll_sap_ops *ll_sap_get_osif_cbk(void) +{ + return global_ll_sap_ops; +} + +QDF_STATUS ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return target_if_ll_sap_register_events(psoc); +} + +QDF_STATUS ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return target_if_ll_sap_deregister_events(psoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h new file mode 100644 index 0000000000..0320a4b317 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_sap_definitions specific to the ll_sap module + */ + +#ifndef _WLAN_LL_SAP_MAIN_H_ +#define _WLAN_LL_SAP_MAIN_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_ll_sap_public_structs.h" + +#define ll_sap_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_LL_SAP, params) +#define ll_sap_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_LL_SAP, params) +#define ll_sap_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_LL_SAP, params) + +#define ll_sap_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_LL_SAP, params) +#define ll_sap_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_LL_SAP, params) +#define ll_sap_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_LL_SAP, params) + +/** + * struct ll_sap_psoc_priv_obj - ll_sap private psoc obj + * @tx_ops: Tx ops registered with Target IF interface + * @rx_ops: Rx ops registered with Target IF interface + */ +struct ll_sap_psoc_priv_obj { + struct wlan_ll_sap_tx_ops tx_ops; + struct wlan_ll_sap_rx_ops rx_ops; +}; + +/** + * struct ll_sap_vdev_priv_obj - ll sap private vdev obj + * @bearer_switch_ctx: Bearer switch context + */ +struct ll_sap_vdev_priv_obj { + struct bearer_switch_info *bearer_switch_ctx; +}; + +/** + * ll_sap_get_vdev_priv_obj: get ll_sap priv object from vdev object + * @vdev: pointer to vdev object + * + * Return: pointer to ll_sap vdev private object + */ +static inline +struct ll_sap_vdev_priv_obj *ll_sap_get_vdev_priv_obj( + struct wlan_objmgr_vdev *vdev) +{ + struct ll_sap_vdev_priv_obj *obj; + + if (!vdev) { + ll_sap_err("vdev is null"); + return NULL; + } + obj = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_LL_SAP); + + return obj; +} + +/** + * ll_sap_init() - initializes ll_sap component + * + * Return: QDF status + */ +QDF_STATUS ll_sap_init(void); + +/** + * ll_sap_deinit() - De-initializes ll_sap component + * + * Return: QDF status + */ +QDF_STATUS ll_sap_deinit(void); + +/** + * ll_sap_register_os_if_cb() - Register ll_sap osif callbacks + * @ll_sap_global_ops: Ops which needs to be registered + * + * Return: None + */ +void ll_sap_register_os_if_cb(struct ll_sap_ops *ll_sap_global_ops); + +/** + * ll_sap_unregister_os_if_cb() - Un-register ll_sap osif callbacks + * + * Return: None + */ +void ll_sap_unregister_os_if_cb(void); + +/** + * ll_sap_get_osif_cbk() - API to get ll_sap osif callbacks + * + * Return: global ll_sap osif callback + */ +struct ll_sap_ops *ll_sap_get_osif_cbk(void); + +/** + * ll_sap_psoc_enable() - Enable ll_lt_sap psoc + * @psoc: objmgr psoc pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ll_sap_psoc_disable() - Disable ll_lt_sap psoc + * @psoc: objmgr psoc pointer + * + * Return: None + */ +QDF_STATUS ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc); + +#endif /* _WLAN_LL_SAP_MAIN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_api.h new file mode 100644 index 0000000000..6f047324b5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_api.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_lt_sap API definitions specific to the bearer + * switch, channel selection functionalities + */ + +#ifndef _WLAN_LL_LT_SAP_API_H_ +#define _WLAN_LL_LT_SAP_API_H_ + +#include +#include +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_ll_sap_public_structs.h" +#include "wlan_cm_public_struct.h" +#include "wlan_policy_mgr_public_struct.h" + +#ifdef WLAN_FEATURE_LL_LT_SAP +#ifdef WLAN_FEATURE_BEARER_SWITCH +/** + * wlan_ll_lt_sap_bearer_switch_get_id() - Get the request id for bearer switch + * request + * @psoc: Pointer to psoc + * Return: Bearer switch request id + */ +wlan_bs_req_id +wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_ll_lt_sap_switch_bearer_to_ble() - Switch audio transport to BLE + * @psoc: Pointer to psoc + * @bs_request: Pointer to bearer switch request + * Return: QDF_STATUS_SUCCESS on successful bearer switch else failure + */ +QDF_STATUS wlan_ll_lt_sap_switch_bearer_to_ble( + struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request); + +/** + * wlan_ll_sap_switch_bearer_on_sta_connect_start() - Switch bearer during + * station connection start + * @psoc: Pointer to psoc + * @scan_list: Pointer to the candidate list + * @vdev_id: Vdev id of the requesting vdev + * @cm_id: connection manager id of the current connect request + * Return: QDF_STATUS_SUCCESS on successful bearer switch + * QDF_STATUS_E_ALREADY, if bearer switch is not required + * else failure + */ +QDF_STATUS wlan_ll_sap_switch_bearer_on_sta_connect_start( + struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, + uint8_t vdev_id, + wlan_cm_id cm_id); +#else +static inline wlan_bs_req_id +wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline QDF_STATUS +wlan_ll_lt_sap_switch_bearer_to_ble( + struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +wlan_ll_sap_switch_bearer_on_sta_connect_start(struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, + uint8_t vdev_id, + wlan_cm_id cm_id) + +{ + return QDF_STATUS_E_ALREADY; +} + +static inline QDF_STATUS +wlan_ll_sap_switch_bearer_on_sta_connect_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_ll_sap_switch_bearer_on_sta_connect_complete() - Switch bearer during + * station connection complete + * @psoc: Pointer to psoc + * @vdev_id: Vdev id of the requesting vdev + * Return: QDF_STATUS_SUCCESS on successful bearer switch + * QDF_STATUS_E_ALREADY, if bearer switch is not required + * else failure + */ +QDF_STATUS wlan_ll_sap_switch_bearer_on_sta_connect_complete( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wlan_ll_lt_sap_get_freq_list() - Get frequency list for LL_LT_SAP + * @psoc: Pointer to psoc object + * @freq_list: Pointer to wlan_ll_lt_sap_freq_list structure + * @vdev_id: Vdev Id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_ll_lt_sap_get_freq_list( + struct wlan_objmgr_psoc *psoc, + struct wlan_ll_lt_sap_freq_list *freq_list, + uint8_t vdev_id); + +/** + * wlan_ll_lt_sap_override_freq() - Return frequency on which LL_LT_SAP can + * be started + * @psoc: Pointer to psoc object + * @vdev_id: Vdev Id of LL_LT_SAP + * @chan_freq: current frequency of ll_lt_sap + * + * This function checks if ll_lt_sap can come up on the given frequency, if it + * can come up on given frequency then return same frequency else return a + * different frequency on which ll_lt_sap can come up + * + * Return: valid ll_lt_sap frequency + */ +qdf_freq_t wlan_ll_lt_sap_override_freq(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + qdf_freq_t chan_freq); + +/** + * wlan_get_ll_lt_sap_restart_freq() - Get restart frequency on which LL_LT_SAP + * can be re-started + * @pdev: Pointer to pdev object + * @chan_freq: current frequency of ll_lt_sap + * @vdev_id: Vdev Id of LL_LT_SAP + * @csa_reason: Reason for the CSA + * + * This function checks if ll_lt_sap needs to be restarted, if yes, it returns + * new valid frequency on which ll_lt_sap can be restarted else return same + * frequency. + * + * Return: valid ll_lt_sap frequency + */ +qdf_freq_t +wlan_get_ll_lt_sap_restart_freq(struct wlan_objmgr_pdev *pdev, + qdf_freq_t chan_freq, + uint8_t vdev_id, + enum sap_csa_reason_code *csa_reason); + +/** + * wlan_ll_sap_fw_bearer_switch_req() - FW bearer switch request + * @psoc: Pointer to psoc object + * @req_type: Bearer switch request type + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_ll_sap_fw_bearer_switch_req(struct wlan_objmgr_psoc *psoc, + enum bearer_switch_req_type req_type); +#else +static inline wlan_bs_req_id +wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline QDF_STATUS +wlan_ll_lt_sap_switch_bearer_to_ble( + struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +wlan_ll_sap_switch_bearer_on_sta_connect_start(struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, + uint8_t vdev_id, + wlan_cm_id cm_id) + +{ + return QDF_STATUS_E_ALREADY; +} + +static inline QDF_STATUS +wlan_ll_sap_switch_bearer_on_sta_connect_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS wlan_ll_lt_sap_get_freq_list( + struct wlan_objmgr_psoc *psoc, + struct wlan_ll_lt_sap_freq_list *freq_list, + uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +qdf_freq_t wlan_ll_lt_sap_override_freq(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + qdf_freq_t chan_freq) +{ + return chan_freq; +} + +static inline +qdf_freq_t wlan_get_ll_lt_sap_restart_freq(struct wlan_objmgr_pdev *pdev, + qdf_freq_t chan_freq, + uint8_t vdev_id, + enum sap_csa_reason_code *csa_reason) +{ + return 0; +} +#endif /* WLAN_FEATURE_LL_LT_SAP */ +#endif /* _WLAN_LL_LT_SAP_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h new file mode 100644 index 0000000000..1832191617 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_public_structs.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_lt_sap structure definitions specific to the bearer + * switch and channel selection functionalities + */ + +#ifndef _WLAN_LL_SAP_PUBLIC_STRUCTS_H_ +#define _WLAN_LL_SAP_PUBLIC_STRUCTS_H_ + +#include "wlan_objmgr_psoc_obj.h" +#include + +/* Indicates MAX bearer switch requesters at a time */ +#define MAX_BEARER_SWITCH_REQUESTERS 5 +#define BS_REQ_ID_INVALID 0xFFFFFFFF +typedef uint32_t wlan_bs_req_id; + +/** + * enum bearer_switch_req_type: Bearer switch request type + * @WLAN_BS_REQ_TO_NON_WLAN: Bearer switch request to non-wlan + * @WLAN_BS_REQ_TO_WLAN: Bearer switch request to wlan + * @WLAN_BS_REQ_INVALID: Invalid bearer switch request + */ +enum bearer_switch_req_type { + WLAN_BS_REQ_TO_NON_WLAN = 0, + WLAN_BS_REQ_TO_WLAN = 1, + WLAN_BS_REQ_INVALID, +}; + +/** + * enum bearer_switch_status: Bearer switch status + * @WLAN_BS_STATUS_REJECTED: Bearer switch request rejected + * @WLAN_BS_STATUS_COMPLETED: Bearer switch request completed + * @WLAN_BS_STATUS_INVALID: Invalid bearer switch request + * @WLAN_BS_STATUS_TIMEOUT: Bearer switch request timedout + */ +enum bearer_switch_status { + WLAN_BS_STATUS_REJECTED = 0, + WLAN_BS_STATUS_COMPLETED = 1, + WLAN_BS_STATUS_TIMEOUT = 2, + WLAN_BS_STATUS_INVALID, +}; + +/** + * enum bearer_switch_req_source: Bearer switch requester source + * @BEARER_SWITCH_REQ_CONNECT: Bearer switch requester is connect + * @BEARER_SWITCH_REQ_CSA: Bearer switch requester is CSA + * @BEARER_SWITCH_REQ_FW: Bearer switch requester is FW + * @BEARER_SWITCH_REQ_MAX: Indicates MAX bearer switch requester + */ +enum bearer_switch_req_source { + BEARER_SWITCH_REQ_CONNECT, + BEARER_SWITCH_REQ_CSA, + BEARER_SWITCH_REQ_FW, + BEARER_SWITCH_REQ_MAX, +}; + +/** + * struct wlan_ll_lt_sap_mac_freq: LL_LT_SAP mac frequency + * @freq_5GHz_low: Low 5GHz frequency + * @freq_5GHz_high: High 5GHz frequency + * @freq_6GHz: 6GHz frequency + * @weight_5GHz_low: Weight of 5GHz low frequency + * @weight_5GHz_high: Weight of 5GHz high frequency + * @weight_6GHz: Weight of 6GHz frequency + */ +struct wlan_ll_lt_sap_mac_freq { + qdf_freq_t freq_5GHz_low; + qdf_freq_t freq_5GHz_high; + qdf_freq_t freq_6GHz; + uint32_t weight_5GHz_low; + uint32_t weight_5GHz_high; + uint32_t weight_6GHz; +}; + +/** + * struct wlan_ll_lt_sap_freq_list: LL_LT_SAP frequency list structure + * @standalone_mac: Select frequency from mac which doesn't have any + * concurrent interface present. + * @shared_mac: Select frequency from mac which has one concurrent + * interface present. + * @best_freq: Best freq present in ACS final list. This freq can be + * use to bring LL_LT_SAP if none of the above channels are present + * @prev_freq: Previous/current freq on which LL_LT_SAP is present. + * This will be use to avoid SCC channel selection while updating this + * list. This freq should be filled by user. + * @weight_best_freq: Weight of best frequency + */ +struct wlan_ll_lt_sap_freq_list { + struct wlan_ll_lt_sap_mac_freq standalone_mac; + struct wlan_ll_lt_sap_mac_freq shared_mac; + qdf_freq_t best_freq; + qdf_freq_t prev_freq; + uint32_t weight_best_freq; +}; + +/** + * typedef bearer_switch_requester_cb() - Callback function, which will + * be invoked with the bearer switch request status. + * @psoc: Psoc pointer + * @vdev_id: vdev id of the requester + * @request_id: Request ID + * @status: Status of the bearer switch request + * @req_value: Request value for the bearer switch request + * @request_params: Request params for the bearer switch request + * + * Return: None + */ +typedef void (*bearer_switch_requester_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + wlan_bs_req_id request_id, + QDF_STATUS status, + uint32_t req_value, + void *request_params); + +/** + * struct wlan_bearer_switch_request - Data structure to store the bearer switch + * request + * @vdev_id: Vdev id of the requester + * @request_id: Unique value to identify the request + * @req_type: Type of the request, bearer switch to wlan or bearer switch + * to non-wlan + * @source: Bearer switch request source + * @requester_cb: Callback which needs to be invoked to indicate the status of + * the request to the requester, this callback will be passed by the requester + * when requester will send the request. + * @arg_value: argument value passed by requester, this will be returned back + * in the callback + * @arg: Argument passed by requester, this will be returned back in the + * callback + */ +struct wlan_bearer_switch_request { + uint8_t vdev_id; + wlan_bs_req_id request_id; + enum bearer_switch_req_type req_type; + enum bearer_switch_req_source source; + bearer_switch_requester_cb requester_cb; + uint32_t arg_value; + void *arg; +}; + +/** + * struct wlan_ll_sap_tx_ops - defines southbound tx callbacks for + * LL_SAP (low latency sap) component + * @send_audio_transport_switch_resp: function pointer to indicate audio + * transport switch response to FW + */ +struct wlan_ll_sap_tx_ops { + QDF_STATUS (*send_audio_transport_switch_resp)( + struct wlan_objmgr_psoc *psoc, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status); +}; + +/** + * struct wlan_ll_sap_rx_ops - defines southbound rx callbacks for + * LL_SAP (low latency SAP) component + * @audio_transport_switch_req: function pointer to indicate audio + * transport switch request from FW + */ +struct wlan_ll_sap_rx_ops { + QDF_STATUS (*audio_transport_switch_req)( + struct wlan_objmgr_psoc *psoc, + enum bearer_switch_req_type req_type); +}; + +/** + * struct ll_sap_ops - ll_sap osif callbacks + * @ll_sap_send_audio_transport_switch_req_cb: Send audio transport request to + * userspace + */ +struct ll_sap_ops { + void (*ll_sap_send_audio_transport_switch_req_cb)( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type); +}; +#endif /* _WLAN_LL_SAP_PUBLIC_STRUCTS_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h new file mode 100644 index 0000000000..c7c91a6670 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/inc/wlan_ll_sap_ucfg_api.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains ll_sap north bound interface declarations + */ + +#ifndef _WLAN_LL_SAP_UCFG_API_H_ +#define _WLAN_LL_SAP_UCFG_API_H_ +#include "wlan_ll_sap_public_structs.h" + +#ifdef WLAN_FEATURE_LL_LT_SAP + +/** + * ucfg_ll_sap_init() - initializes ll_sap component + * + * Return: QDF status + */ +QDF_STATUS ucfg_ll_sap_init(void); + +/** + * ucfg_ll_sap_deinit() - De-initializes ll_sap component + * + * Return: QDF status + */ +QDF_STATUS ucfg_ll_sap_deinit(void); + +/** + * ucfg_is_ll_lt_sap_supported() - Check if ll_lt_sap is supported or not + *@psoc: Psoc pointer + * + * Return: True/False + */ +bool ucfg_is_ll_lt_sap_supported(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_ll_lt_sap_request_for_audio_transport_switch() - Request to switch the + * audio transport medium + * @vdev: Vdev on which the request is received + * @req_type: Requested transport switch type + * + * Return: Accepted/Rejected + */ +QDF_STATUS ucfg_ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type); + +/** + * ucfg_ll_lt_sap_deliver_audio_transport_switch_resp() - Deliver audio + * transport switch response + * @vdev: Vdev on which the request is received + * @req_type: Transport switch type for which the response is received + * @status: Status of the response + * + * Return: None + */ +void ucfg_ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status); + +/** + * ucfg_ll_sap_register_cb() - Register ll_sap osif callbacks + * @ll_sap_global_ops: Ops which needs to be registered + * + * Return: None + */ +void ucfg_ll_sap_register_cb(struct ll_sap_ops *ll_sap_global_ops); + +/** + * ucfg_ll_sap_unregister_cb() - Un-register ll_sap osif callbacks + * + * Return: None + */ +void ucfg_ll_sap_unregister_cb(void); + +/** + * ucfg_ll_sap_psoc_enable() - Enable ll_lt_sap psoc + * @psoc: objmgr psoc pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_ll_sap_psoc_disable() - Disable ll_lt_sap psoc + * @psoc: objmgr psoc pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc); + +#else +static inline QDF_STATUS ucfg_ll_sap_init(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_ll_sap_deinit(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool ucfg_is_ll_lt_sap_supported(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline QDF_STATUS +ucfg_ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type) +{ + return QDF_STATUS_E_INVAL; +} + +static inline void +ucfg_ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ +} + +static inline void ucfg_ll_sap_register_cb(struct ll_sap_ops *ll_sap_global_ops) +{ +} + +static inline void ucfg_ll_sap_unregister_cb(void) +{ +} + +static inline QDF_STATUS ucfg_ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS ucfg_ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_FEATURE_LL_LT_SAP */ +#endif /* _WLAN_LL_SAP_UCFG_API_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c new file mode 100644 index 0000000000..a712fa8cde --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_ll_sap_api.h" +#include <../../core/src/wlan_ll_lt_sap_bearer_switch.h> +#include <../../core/src/wlan_ll_lt_sap_main.h> +#include "wlan_cm_api.h" +#include "wlan_policy_mgr_ll_sap.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_reg_services_api.h" +#include "wlan_dfs_utils_api.h" +#include "wlan_mlme_main.h" + +#ifdef WLAN_FEATURE_BEARER_SWITCH +wlan_bs_req_id +wlan_ll_lt_sap_bearer_switch_get_id(struct wlan_objmgr_psoc *psoc) +{ + return ll_lt_sap_bearer_switch_get_id(psoc); +} + +QDF_STATUS +wlan_ll_lt_sap_switch_bearer_to_ble(struct wlan_objmgr_psoc *psoc, + struct wlan_bearer_switch_request *bs_request) +{ + return ll_lt_sap_switch_bearer_to_ble(psoc, bs_request); +} + +static void +connect_start_bearer_switch_requester_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + wlan_bs_req_id request_id, + QDF_STATUS status, uint32_t req_value, + void *request_params) +{ + wlan_cm_id cm_id = req_value; + + wlan_cm_bearer_switch_resp(psoc, vdev_id, cm_id, status); +} + +QDF_STATUS +wlan_ll_sap_switch_bearer_on_sta_connect_start(struct wlan_objmgr_psoc *psoc, + qdf_list_t *scan_list, + uint8_t vdev_id, + wlan_cm_id cm_id) +{ + struct scan_cache_node *scan_node = NULL; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + uint32_t ch_freq = 0; + struct scan_cache_entry *entry; + struct wlan_objmgr_vdev *vdev; + struct wlan_bearer_switch_request bs_request = {0}; + qdf_freq_t ll_lt_sap_freq; + bool is_bearer_switch_required = false; + QDF_STATUS status = QDF_STATUS_E_ALREADY; + uint8_t ll_lt_sap_vdev_id; + + ll_lt_sap_vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc); + /* LL_LT SAP is not present, bearer switch is not required */ + if (ll_lt_sap_vdev_id == WLAN_INVALID_VDEV_ID) + return status; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, ll_lt_sap_vdev_id, + WLAN_LL_SAP_ID); + if (!vdev) + return status; + + if (!scan_list || !qdf_list_size(scan_list)) + goto rel_ref; + + ll_lt_sap_freq = policy_mgr_get_ll_lt_sap_freq(psoc); + qdf_list_peek_front(scan_list, &cur_node); + + while (cur_node) { + qdf_list_peek_next(scan_list, cur_node, &next_node); + + scan_node = qdf_container_of(cur_node, struct scan_cache_node, + node); + entry = scan_node->entry; + ch_freq = entry->channel.chan_freq; + + /* + * Switch the bearer in case of SCC/MCC for LL_LT SAP + */ + if (policy_mgr_2_freq_always_on_same_mac(psoc, ch_freq, + ll_lt_sap_freq)) { + ll_sap_debug("Scan list has BSS of freq %d on same mac with ll_lt sap %d", + ch_freq, ll_lt_sap_freq); + is_bearer_switch_required = true; + break; + } + + ch_freq = 0; + cur_node = next_node; + next_node = NULL; + } + + if (!is_bearer_switch_required) + goto rel_ref; + + bs_request.vdev_id = vdev_id; + bs_request.request_id = ll_lt_sap_bearer_switch_get_id(psoc); + bs_request.req_type = WLAN_BS_REQ_TO_NON_WLAN; + bs_request.source = BEARER_SWITCH_REQ_CONNECT; + bs_request.requester_cb = connect_start_bearer_switch_requester_cb; + bs_request.arg_value = cm_id; + + status = ll_lt_sap_switch_bearer_to_ble(psoc, &bs_request); + + if (QDF_IS_STATUS_ERROR(status)) + status = QDF_STATUS_E_ALREADY; +rel_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); + + return status; +} + +static void connect_complete_bearer_switch_requester_cb( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + wlan_bs_req_id request_id, + QDF_STATUS status, + uint32_t req_value, + void *request_params) +{ + /* Drop this response as no action is required */ +} + +QDF_STATUS wlan_ll_sap_switch_bearer_on_sta_connect_complete( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_bearer_switch_request bs_request = {0}; + QDF_STATUS status; + + bs_request.vdev_id = vdev_id; + bs_request.request_id = ll_lt_sap_bearer_switch_get_id(psoc); + bs_request.req_type = WLAN_BS_REQ_TO_WLAN; + bs_request.source = BEARER_SWITCH_REQ_CONNECT; + bs_request.requester_cb = connect_complete_bearer_switch_requester_cb; + + status = ll_lt_sap_switch_bearer_to_wlan(psoc, &bs_request); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_ALREADY; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wlan_ll_lt_sap_get_freq_list( + struct wlan_objmgr_psoc *psoc, + struct wlan_ll_lt_sap_freq_list *freq_list, + uint8_t vdev_id) +{ + return ll_lt_sap_get_freq_list(psoc, freq_list, vdev_id); +} + +qdf_freq_t wlan_ll_lt_sap_override_freq(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + qdf_freq_t chan_freq) +{ + qdf_freq_t freq; + + if (!policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) + return chan_freq; + + /* + * If already any concurrent interface is present on this frequency, + * select a different frequency to start ll_lt_sap + */ + if (!policy_mgr_get_connection_count_with_ch_freq(chan_freq)) + return chan_freq; + + freq = ll_lt_sap_get_valid_freq(psoc, vdev_id); + + ll_sap_debug("Vdev %d ll_lt_sap old freq %d new freq %d", vdev_id, + chan_freq, freq); + + return freq; +} + +qdf_freq_t wlan_get_ll_lt_sap_restart_freq(struct wlan_objmgr_pdev *pdev, + qdf_freq_t chan_freq, + uint8_t vdev_id, + enum sap_csa_reason_code *csa_reason) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + qdf_freq_t restart_freq; + + if (wlan_reg_is_disable_in_secondary_list_for_freq(pdev, chan_freq) && + !utils_dfs_is_freq_in_nol(pdev, chan_freq)) { + *csa_reason = CSA_REASON_CHAN_DISABLED; + goto get_new_ll_lt_sap_freq; + } else if (wlan_reg_is_passive_for_freq(pdev, chan_freq)) { + *csa_reason = CSA_REASON_CHAN_PASSIVE; + goto get_new_ll_lt_sap_freq; + } else if (!policy_mgr_is_sap_freq_allowed(psoc, + wlan_get_opmode_from_vdev_id(pdev, vdev_id), + chan_freq)) { + *csa_reason = CSA_REASON_UNSAFE_CHANNEL; + goto get_new_ll_lt_sap_freq; + } else if (policy_mgr_is_ll_lt_sap_restart_required(psoc)) { + *csa_reason = CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL; + goto get_new_ll_lt_sap_freq; + } + + return chan_freq; + +get_new_ll_lt_sap_freq: + restart_freq = ll_lt_sap_get_valid_freq(psoc, vdev_id); + + ll_sap_debug("vdev %d old freq %d restart freq %d CSA reason %d ", + vdev_id, chan_freq, restart_freq, *csa_reason); + return restart_freq; +} + +static void fw_bearer_switch_requester_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + wlan_bs_req_id request_id, + QDF_STATUS status, + uint32_t req_value, + void *request_params) +{ + /* + * Drop this response as all the responses to the FW is always + * forwarded + */ +} + +QDF_STATUS +wlan_ll_sap_fw_bearer_switch_req(struct wlan_objmgr_psoc *psoc, + enum bearer_switch_req_type req_type) +{ + struct wlan_bearer_switch_request bs_request = {0}; + QDF_STATUS status; + uint8_t ll_lt_sap_vdev_id; + + ll_lt_sap_vdev_id = wlan_policy_mgr_get_ll_lt_sap_vdev_id(psoc); + + bs_request.vdev_id = ll_lt_sap_vdev_id; + bs_request.request_id = ll_lt_sap_bearer_switch_get_id(psoc); + bs_request.req_type = req_type; + bs_request.source = BEARER_SWITCH_REQ_FW; + bs_request.requester_cb = fw_bearer_switch_requester_cb; + + if (req_type == WLAN_BS_REQ_TO_WLAN) + status = ll_lt_sap_switch_bearer_to_wlan(psoc, &bs_request); + + else + status = ll_lt_sap_switch_bearer_to_ble(psoc, &bs_request); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_ALREADY; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c new file mode 100644 index 0000000000..e0c232e048 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains ll_sap north bound interface definitions + */ +#include "../../core/src/wlan_ll_sap_main.h" +#include "../../core/src/wlan_ll_lt_sap_main.h" +#include "../../core/src/wlan_ll_lt_sap_bearer_switch.h" +#include + +QDF_STATUS ucfg_ll_sap_init(void) +{ + return ll_sap_init(); +} + +QDF_STATUS ucfg_ll_sap_deinit(void) +{ + return ll_sap_deinit(); +} + +bool ucfg_is_ll_lt_sap_supported(struct wlan_objmgr_psoc *psoc) +{ + return ll_lt_sap_is_supported(psoc); +} + +QDF_STATUS ucfg_ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type) +{ + return ll_lt_sap_request_for_audio_transport_switch(vdev, req_type); +} + +void ucfg_ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ + ll_lt_sap_deliver_audio_transport_switch_resp(vdev, req_type, + status); +} + +void ucfg_ll_sap_register_cb(struct ll_sap_ops *ll_sap_global_ops) +{ + ll_sap_register_os_if_cb(ll_sap_global_ops); +} + +void ucfg_ll_sap_unregister_cb(void) +{ + ll_sap_unregister_os_if_cb(); +} + +QDF_STATUS ucfg_ll_sap_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return ll_sap_psoc_enable(psoc); +} + +QDF_STATUS ucfg_ll_sap_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return ll_sap_psoc_disable(psoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_config_public_struct.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_config_public_struct.h new file mode 100644 index 0000000000..8614afe5d2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_config_public_struct.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Declare structs and macros which can be accessed by various + * components and modules. + */ + +#ifndef _WLAN_WFA_CONFIG_PUBLIC_STRUCT_H_ +#define _WLAN_WFA_CONFIG_PUBLIC_STRUCT_H_ + +#include +#include +#include + +/** + * struct wlan_wfa_cmd_tx_ops - structure of tx function pointers for wfa + * test cmds + * @send_wfa_test_cmd: TX ops function pointer to send WFA test command + */ +struct wlan_wfa_cmd_tx_ops { + QDF_STATUS (*send_wfa_test_cmd)(struct wlan_objmgr_vdev *vdev, + struct set_wfatest_params *wfa_test); +}; + +/** + * enum wlan_wfa_test_feature_flags - WFA test feature flags + * @WFA_TEST_IGNORE_RSNXE: Ignore the H2E RSNXE mismatch for 6g connection when + * this flag is set + */ +enum wlan_wfa_test_feature_flags { + WFA_TEST_IGNORE_RSNXE = 0x1, +}; + +/** + * struct wlan_mlme_wfa_cmd - WFA test command tx ops + * @tx_ops: WFA test command Tx ops to send commands to firmware + * @flags: WFA test feature flags to do feature specific operations + */ +struct wlan_mlme_wfa_cmd { + struct wlan_wfa_cmd_tx_ops tx_ops; + enum wlan_wfa_test_feature_flags flags; +}; + +#endif /* _WLAN_WFA_CONFIG_PUBLIC_STRUCT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_tgt_if_tx_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_tgt_if_tx_api.h new file mode 100644 index 0000000000..d5496d5345 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_tgt_if_tx_api.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_wfa_tgt_if_tx_api.h + * + * This file contains connection manager tx ops related functions + */ + +#ifndef WFA_TGT_IF_TX_API_H__ +#define WFA_TGT_IF_TX_API_H__ + +#include "wlan_wfa_config_public_struct.h" + +/** + * wlan_send_wfatest_cmd() - Send WFA test command to firmware + * @vdev: VDEV pointer + * @wmi_wfatest: wfa test command pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_send_wfatest_cmd(struct wlan_objmgr_vdev *vdev, + struct set_wfatest_params *wmi_wfatest); + +/** + * wlan_wfa_get_test_feature_flags() - Check if the given WFA test flag is set + * @psoc: psoc pointer + * @feature: wfa test feature bit to be checked + * + * Return: True if the specific feature is configured + */ +bool wlan_wfa_get_test_feature_flags(struct wlan_objmgr_psoc *psoc, + enum wlan_wfa_test_feature_flags feature); +#endif /* WFA_TGT_IF_TX_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_ucfg_api.h new file mode 100644 index 0000000000..d9f3417e83 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/inc/wlan_wfa_ucfg_api.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_wfa_ucfg_api.h + * + * Implementation for the Common WFA test config interfaces. + */ + +#ifndef WLAN_WFA_CONFIG_API_H__ +#define WLAN_WFA_CONFIG_API_H__ + +#include "wlan_mlme_dbg.h" +#include "wlan_mlme_api.h" +#include "wlan_wfa_tgt_if_tx_api.h" + +/** + * ucfg_send_wfatest_cmd() - Send WFA test command to firmware + * @vdev: Pointer to vdev + * @wmi_wfatest: Pointer to WFA test config params + * + * Return: QDF_STATUS + */ +static inline +QDF_STATUS ucfg_send_wfatest_cmd(struct wlan_objmgr_vdev *vdev, + struct set_wfatest_params *wmi_wfatest) +{ + return wlan_send_wfatest_cmd(vdev, wmi_wfatest); +} +#endif /* WLAN_WFA_CONFIG_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/src/wlan_wfa_tgt_if_tx_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/src/wlan_wfa_tgt_if_tx_api.c new file mode 100644 index 0000000000..28f1eeca41 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/mlme/wfa_config/dispatcher/src/wlan_wfa_tgt_if_tx_api.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_wfa_tgt_if_tx_api.c + * + * Implementation for the Common WFA config interfaces. + */ + +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_wfa_tgt_if_tx_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_vdev_mgr_tgt_if_tx_api.h" +#include "wma.h" + +static inline struct wlan_wfa_cmd_tx_ops * +wlan_wfatest_get_tx_ops_from_vdev(struct wlan_objmgr_vdev *vdev) +{ + mlme_psoc_ext_t *mlme_priv; + struct wlan_wfa_cmd_tx_ops *tx_ops; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + mlme_legacy_err("psoc object is NULL"); + return NULL; + } + + mlme_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return NULL; + } + + tx_ops = &mlme_priv->wfa_testcmd.tx_ops; + + return tx_ops; +} + +static QDF_STATUS +wlan_wfa_set_test_feature_flags(struct wlan_objmgr_psoc *psoc, + enum wlan_wfa_test_feature_flags feature, + uint8_t value) +{ + mlme_psoc_ext_t *mlme_priv; + + if (!psoc) { + mlme_legacy_err("psoc object is NULL"); + return QDF_STATUS_E_INVAL; + } + + mlme_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + switch (feature) { + case WFA_TEST_IGNORE_RSNXE: + if (value) + mlme_priv->wfa_testcmd.flags |= WFA_TEST_IGNORE_RSNXE; + else + mlme_priv->wfa_testcmd.flags &= ~WFA_TEST_IGNORE_RSNXE; + break; + default: + mlme_legacy_debug("Invalid feature flag: 0x%x", feature); + break; + } + + return QDF_STATUS_SUCCESS; +} + +bool wlan_wfa_get_test_feature_flags(struct wlan_objmgr_psoc *psoc, + enum wlan_wfa_test_feature_flags feature) +{ + mlme_psoc_ext_t *mlme_priv; + bool set = false; + + if (!psoc) { + mlme_legacy_err("psoc object is NULL"); + return set; + } + + mlme_priv = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!mlme_priv) { + mlme_legacy_err("psoc legacy private object is NULL"); + return set; + } + + switch (feature) { + case WFA_TEST_IGNORE_RSNXE: + set = !!(mlme_priv->wfa_testcmd.flags & WFA_TEST_IGNORE_RSNXE); + if (set) + mlme_legacy_debug("IGNORE_RSNXE is set"); + break; + default: + mlme_legacy_debug("Invalid feature flag: 0x%x", feature); + break; + } + + return set; +} + +QDF_STATUS +wlan_send_wfatest_cmd(struct wlan_objmgr_vdev *vdev, + struct set_wfatest_params *wmi_wfatest) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_wfa_cmd_tx_ops *tx_ops; + struct vdev_mlme_obj *mlme_obj; + struct config_fils_params param = {0}; + + if (!vdev || !wmi_wfatest) { + mlme_legacy_err("vdev or test params is NULL"); + return status; + } + + if (wmi_wfatest->cmd == WFA_FILS_DISCV_FRAMES) { + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("failed to get mlme_obj"); + return QDF_STATUS_E_INVAL; + } + + param.vdev_id = wmi_wfatest->vdev_id; + if (wmi_wfatest->value) + param.fd_period = DEFAULT_FILS_DISCOVERY_PERIOD; + + return tgt_vdev_mgr_fils_enable_send(mlme_obj, ¶m); + } else if (wmi_wfatest->cmd == WFA_IGNORE_H2E_RSNXE) { + return wlan_wfa_set_test_feature_flags(wlan_vdev_get_psoc(vdev), + WFA_TEST_IGNORE_RSNXE, + wmi_wfatest->value); + } + + tx_ops = wlan_wfatest_get_tx_ops_from_vdev(vdev); + if (!tx_ops || !tx_ops->send_wfa_test_cmd) { + mlme_legacy_err("Failed to send WFA test cmd"); + return QDF_STATUS_E_FAILURE; + } + + return tx_ops->send_wfa_test_cmd(vdev, wmi_wfatest); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_cfg.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_cfg.c new file mode 100644 index 0000000000..13e3e975c1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_cfg.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include "wlan_twt_cfg.h" +#include "twt/core/src/wlan_twt_priv.h" + +QDF_STATUS wlan_twt_cfg_init(struct wlan_objmgr_psoc *psoc) +{ + struct twt_psoc_priv_obj *twt_psoc; + psoc_twt_ext_cfg_params_t *twt_cfg; + uint32_t bcast_conf; + uint32_t rtwt_conf; + + if (!psoc) { + twt_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + + twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TWT); + if (!twt_psoc) { + twt_err("null twt psoc priv obj"); + return QDF_STATUS_E_FAILURE; + } + + twt_cfg = &twt_psoc->cfg_params; + bcast_conf = cfg_get(psoc, CFG_BCAST_TWT_REQ_RESP); + rtwt_conf = cfg_get(psoc, CFG_RTWT_REQ_RESP); + + + twt_cfg->enable_twt = cfg_get(psoc, CFG_ENABLE_TWT); + twt_cfg->twt_requestor = cfg_get(psoc, CFG_TWT_REQUESTOR); + twt_cfg->twt_responder = cfg_get(psoc, CFG_TWT_RESPONDER); + twt_cfg->twt_congestion_timeout = + cfg_get(psoc, CFG_TWT_CONGESTION_TIMEOUT); + twt_cfg->bcast_requestor_enabled = CFG_TWT_GET_BCAST_REQ(bcast_conf); + twt_cfg->bcast_responder_enabled = CFG_TWT_GET_BCAST_RES(bcast_conf); + twt_cfg->enable_twt_24ghz = cfg_get(psoc, CFG_ENABLE_TWT_24GHZ); + twt_cfg->flex_twt_sched = cfg_default(CFG_HE_FLEX_TWT_SCHED); + twt_cfg->is_twt_enabled_in_11n = cfg_get(psoc, CFG_TWT_ENABLE_IN_11N); + twt_cfg->req_flag = false; + twt_cfg->res_flag = false; + twt_cfg->rtwt_requestor_enabled = CFG_GET_RTWT_REQ(rtwt_conf); + twt_cfg->rtwt_responder_enabled = CFG_GET_RTWT_RES(rtwt_conf); + + twt_debug("req: %d resp: %d", twt_cfg->twt_requestor, + twt_cfg->twt_responder); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_twt_cfg_deinit(struct wlan_objmgr_psoc *psoc) +{ + struct twt_psoc_priv_obj *twt_psoc; + + if (!psoc) { + twt_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + + twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TWT); + if (!twt_psoc) { + twt_err("null twt psoc priv obj"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&twt_psoc->cfg_params, sizeof(twt_psoc->cfg_params)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_twt_cfg_update(struct wlan_objmgr_psoc *psoc) +{ + struct twt_psoc_priv_obj *twt_psoc; + psoc_twt_ext_cfg_params_t *twt_cfg; + struct twt_tgt_caps *tgt_caps; + bool enable_twt; + + if (!psoc) { + twt_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + + twt_psoc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_TWT); + if (!twt_psoc) { + twt_err("null twt psoc priv obj"); + return QDF_STATUS_E_FAILURE; + } + + twt_cfg = &twt_psoc->cfg_params; + tgt_caps = &twt_psoc->twt_caps; + enable_twt = twt_cfg->enable_twt; + + twt_cfg->twt_requestor = QDF_MIN(tgt_caps->twt_requestor, + (enable_twt && twt_cfg->twt_requestor)); + twt_cfg->twt_responder = QDF_MIN(tgt_caps->twt_responder, + (enable_twt && twt_cfg->twt_responder)); + twt_cfg->bcast_requestor_enabled = + QDF_MIN((tgt_caps->twt_bcast_req_support || + tgt_caps->legacy_bcast_twt_support), + (enable_twt && + twt_cfg->bcast_requestor_enabled)); + twt_cfg->bcast_responder_enabled = + QDF_MIN((tgt_caps->twt_bcast_res_support || + tgt_caps->legacy_bcast_twt_support), + (enable_twt && + twt_cfg->bcast_responder_enabled)); + twt_debug("req: %d resp: %d bcast_req: %d bcast_resp: %d", + twt_cfg->twt_requestor, twt_cfg->twt_responder, + twt_cfg->bcast_requestor_enabled, + twt_cfg->bcast_responder_enabled); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_TWT_REQUESTOR); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.twt_requestor; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_TWT_RESPONDER); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.twt_responder; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) + return QDF_STATUS_E_INVAL; + + twt_psoc_obj->cfg_params.twt_responder = val; + + return QDF_STATUS_SUCCESS; +} + +bool wlan_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) + return false; + + return twt_psoc_obj->cfg_params.enable_twt; +} + +QDF_STATUS +wlan_twt_cfg_get_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_TWT_CONGESTION_TIMEOUT); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.twt_congestion_timeout; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_set_congestion_timeout(struct wlan_objmgr_psoc *psoc, uint32_t val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) + return QDF_STATUS_E_INVAL; + + twt_psoc_obj->cfg_params.twt_congestion_timeout = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_requestor_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = false; + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.req_flag; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_set_requestor_flag(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) + return QDF_STATUS_E_INVAL; + + twt_psoc_obj->cfg_params.req_flag = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_responder_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) + return QDF_STATUS_E_INVAL; + + *val = twt_psoc_obj->cfg_params.res_flag; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_set_responder_flag(struct wlan_objmgr_psoc *psoc, bool val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) + return QDF_STATUS_E_INVAL; + + twt_psoc_obj->cfg_params.res_flag = val; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_flex_sched(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_HE_FLEX_TWT_SCHED); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.flex_twt_sched; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_24ghz_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_ENABLE_TWT_24GHZ); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.enable_twt_24ghz; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_bcast_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + uint32_t b_req_res; + + b_req_res = cfg_default(CFG_BCAST_TWT_REQ_RESP); + *val = CFG_TWT_GET_BCAST_REQ(b_req_res); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.bcast_requestor_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_bcast_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + uint32_t b_req_res; + + b_req_res = cfg_default(CFG_BCAST_TWT_REQ_RESP); + *val = CFG_TWT_GET_BCAST_RES(b_req_res); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.bcast_responder_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_rtwt_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + uint32_t rtwt_req_res; + + rtwt_req_res = cfg_default(CFG_RTWT_REQ_RESP); + *val = CFG_GET_RTWT_REQ(rtwt_req_res); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.rtwt_requestor_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_rtwt_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + uint32_t rtwt_req_res; + + rtwt_req_res = cfg_default(CFG_RTWT_REQ_RESP); + *val = CFG_GET_RTWT_RES(rtwt_req_res); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.rtwt_responder_enabled; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_cfg_get_support_in_11n_mode(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + psoc_twt_ext_cfg_params_t *twt_cfg; + struct twt_tgt_caps *tgt_caps; + bool enable_twt; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_TWT_ENABLE_IN_11N); + return QDF_STATUS_E_INVAL; + } + + *val = twt_psoc_obj->cfg_params.is_twt_enabled_in_11n; + twt_cfg = &twt_psoc_obj->cfg_params; + tgt_caps = &twt_psoc_obj->twt_caps; + enable_twt = twt_cfg->enable_twt; + + *val = QDF_MIN(tgt_caps->twt_requestor, + (enable_twt && twt_cfg->twt_requestor && *val)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_get_restricted_support(struct wlan_objmgr_psoc *psoc, bool *val) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + psoc_twt_ext_cfg_params_t *twt_cfg; + struct twt_tgt_caps *tgt_caps; + bool enable_twt; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + if (!twt_psoc_obj) { + *val = cfg_default(CFG_RTWT_REQ_RESP); + return QDF_STATUS_E_INVAL; + } + + twt_cfg = &twt_psoc_obj->cfg_params; + tgt_caps = &twt_psoc_obj->twt_caps; + enable_twt = twt_cfg->enable_twt; + + *val = QDF_MIN(tgt_caps->twt_bcast_req_support && + tgt_caps->restricted_twt_support, + twt_cfg->bcast_requestor_enabled && + twt_cfg->rtwt_requestor_enabled && + enable_twt); + + return QDF_STATUS_SUCCESS; +} + +bool +wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc) +{ + struct twt_psoc_priv_obj *twt_psoc_obj; + + twt_psoc_obj = wlan_twt_psoc_get_comp_private_obj(psoc); + + if (!twt_psoc_obj || twt_psoc_obj->twt_pmo_disabled) + return false; + + return true; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_cfg.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_cfg.h new file mode 100644 index 0000000000..f0e83561e9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_cfg.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_TWT_CFG_H +#define _WLAN_TWT_CFG_H + +#include + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/** + * wlan_twt_cfg_init() - Initialize twt config params + * @psoc: Pointer to global psoc + * + * This function initializes the twt private cfg params + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_twt_cfg_init(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_twt_cfg_deinit() - De-initialize twt config params + * @psoc: Pointer to global psoc + * + * This function de-initializes the twt private cfg params + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_twt_cfg_deinit(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_twt_cfg_update() - Update twt config params + * @psoc: Pointer to global psoc + * + * This function updates the cfg param structure based on the + * intersection of target capabilities and other cfg params + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_twt_cfg_update(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_twt_cfg_get_requestor() - get cfg requestor + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_requestor(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_responder() - get cfg responder + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_responder(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_set_responder() - set cfg responder + * @psoc: Pointer to global psoc + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * wlan_twt_cfg_is_twt_enabled() - API to check if TWT is enabled + * @psoc: Pointer to PSOC object + * + * Return: True if TWT is enabled else false + */ +bool wlan_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_twt_cfg_get_congestion_timeout() - get congestion timeout + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val); + +/** + * wlan_twt_cfg_set_congestion_timeout() - set congestion timeout + * @psoc: Pointer to global psoc + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_set_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t val); + +/** + * wlan_twt_cfg_get_requestor_flag() - get requestor flag + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_requestor_flag(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_set_requestor_flag() - set requestor flag + * @psoc: Pointer to global psoc + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_set_requestor_flag(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * wlan_twt_cfg_get_responder_flag() - get responder flag + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_responder_flag(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_set_responder_flag() - set responder flag + * @psoc: Pointer to global psoc + * @val: value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_set_responder_flag(struct wlan_objmgr_psoc *psoc, bool val); + +/** + * wlan_twt_cfg_get_flex_sched() - get flex scheduling + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_flex_sched(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_24ghz_enabled() - get 24ghz enable + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_24ghz_enabled(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_bcast_requestor() - get bcast requestor + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_bcast_requestor(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_bcast_responder() - get bcast responder + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_bcast_responder(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_rtwt_requestor() - get rtwt requestor + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_rtwt_requestor(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_rtwt_responder() - get rtwt responder + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_rtwt_responder(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_support_in_11n_mode() - Get TWT support in 11n mode + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_cfg_get_support_in_11n_mode(struct wlan_objmgr_psoc *psoc, + bool *val); +/** + * wlan_twt_get_restricted_support() - Get rTWT support + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_get_restricted_support(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_get_pmo_allowed() - Get pmo allowed + * @psoc: psoc handler + * + * Return: True if twt pmo is allowed otherwise false + */ +bool +wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc); +#else + +static inline QDF_STATUS wlan_twt_cfg_init(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlan_twt_cfg_deinit(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlan_twt_cfg_update(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_set_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_requestor_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_set_requestor_flag(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_responder_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_set_responder_flag(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_flex_sched(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_24ghz_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_bcast_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_bcast_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_support_in_11n_mode(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_get_restricted_support(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc) +{ + return true; +} +#endif + +#endif /* End of _WLAN_TWT_CFG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_main.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_main.c new file mode 100644 index 0000000000..8f1f64c8fd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_main.c @@ -0,0 +1,2331 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include "include/wlan_mlme_cmn.h" +#include +#include +#include +#include +#include +#include +#include "twt/core/src/wlan_twt_priv.h" +#include "twt/core/src/wlan_twt_common.h" +#include +#include +#include "wlan_twt_main.h" + +/** + * wlan_twt_add_session() - Add TWT session entry in the TWT context + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * @context: request context + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_add_session(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + void *context) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer twt component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == + TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].dialog_id = dialog_id; + peer_priv->session_info[i].twt_ack_ctx = context; + break; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_set_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + struct wlan_objmgr_peer *peer; + struct twt_peer_priv_obj *peer_priv; + uint8_t i = 0; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].active_cmd = cmd; + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) + break; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_init_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer twt component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + peer_priv->num_twt_sessions = WLAN_MAX_TWT_SESSIONS_PER_PEER; + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].setup_done = false; + peer_priv->session_info[i].dialog_id = + TWT_ALL_SESSIONS_DIALOG_ID; + peer_priv->session_info[i].active_cmd = + WLAN_TWT_NONE; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + twt_debug("init done"); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_is_twt_notify_in_progress() - is TWT notify in progress + * @psoc: Pointer to psoc object + * @vdev_id: VDEV identifier + * + * Return: True if twt_notify is in progress. + */ +static bool +wlan_is_twt_notify_in_progress(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct twt_vdev_priv_obj *twt_vdev_priv; + bool is_twt_notify_in_progress; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + twt_err("vdev object not found"); + return false; + } + + twt_vdev_priv = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TWT); + if (!twt_vdev_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + twt_err("twt vdev private object is NULL"); + return false; + } + + is_twt_notify_in_progress = twt_vdev_priv->twt_wait_for_notify; + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + + twt_debug("is_twt_notify_in_progress: %d", is_twt_notify_in_progress); + return is_twt_notify_in_progress; +} + +/** + * wlan_twt_set_wait_for_notify() - Set wait for notify flag + * @psoc: Pointer to psoc object + * @vdev_id: VDEV identifier + * @is_set: Set or clear notify flag + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_set_wait_for_notify(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id, + bool is_set) +{ + struct wlan_objmgr_vdev *vdev; + struct twt_vdev_priv_obj *twt_vdev_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + twt_err("vdev object not found"); + return QDF_STATUS_E_INVAL; + } + + twt_vdev_priv = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_TWT); + if (!twt_vdev_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + twt_err("twt vdev private object is NULL"); + return QDF_STATUS_E_INVAL; + } + + twt_vdev_priv->twt_wait_for_notify = is_set; + twt_debug("twt_wait_for_notify: %d", is_set); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +wlan_twt_update_peer_twt_required_bit(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event) +{ + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr peer_mac; + uint8_t peer_cap = 0; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, + WLAN_TWT_ID); + + if (!vdev) { + twt_err("vdev object not found"); + return QDF_STATUS_E_INVAL; + } + + status = wlan_vdev_get_bss_peer_mac(vdev, &peer_mac); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("Failed to get bssid"); + goto exit; + } + + status = wlan_twt_get_peer_capabilities(psoc, &peer_mac, &peer_cap); + + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("twt failed to get peer capabilities"); + goto exit; + } + + if ((peer_cap & WLAN_TWT_CAPA_REQUIRED) && + event->status == HOST_TWT_NOTIFY_EVENT_AP_TWT_REQ_BIT_CLEAR) { + /* set TWT required bit as 0 */ + peer_cap &= ~WLAN_TWT_CAPA_REQUIRED; + } else if (!(peer_cap & WLAN_TWT_CAPA_REQUIRED) && + event->status == HOST_TWT_NOTIFY_EVENT_AP_TWT_REQ_BIT_SET) { + /* set TWT required bit as 1 */ + peer_cap |= WLAN_TWT_CAPA_REQUIRED; + } + + status = wlan_twt_set_peer_capabilities(psoc, &peer_mac, peer_cap); + twt_debug("Update Peer TWT capabilities: %d", peer_cap); + +exit: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + + return status; +} + +/** + * wlan_twt_util_cmd_in_progress() - for a given peer_priv, check if the + * given command is in progress + * @peer_priv: peer priv object + * @dialog_id: Dialog id + * @cmd: command + * + * Return: true if command is in progress, false otherwise + */ +static bool +wlan_twt_util_cmd_in_progress(struct twt_peer_priv_obj *peer_priv, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + bool cmd_in_progress = false; + uint8_t i; + uint8_t num_sessions = peer_priv->num_twt_sessions; + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < num_sessions; i++) { + enum wlan_twt_commands active_cmd; + uint8_t existing_dialog_id; + + active_cmd = peer_priv->session_info[i].active_cmd; + existing_dialog_id = peer_priv->session_info[i].dialog_id; + + if (existing_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + cmd_in_progress = (active_cmd == cmd); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + cmd_in_progress) { + qdf_mutex_release(&peer_priv->twt_peer_lock); + return cmd_in_progress; + } + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + return cmd_in_progress; +} + +/** + * wlan_twt_any_peer_cmd_in_progress() - Iterate through the list of peers + * and check if the given command is in progress + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @dialog_id: Dialog id + * @cmd: command + * + * This API is used to check for the given @dialog_id if the + * @cmd command is in progress for any of the peers. + * + * Return: true if command is in progress, false otherwise + */ +static bool +wlan_twt_any_peer_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct twt_peer_priv_obj *peer_priv; + bool cmd_in_progress = false; + + if (!psoc) { + twt_err("psoc is NULL, dialog_id: %d", dialog_id); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + twt_err("vdev is NULL, vdev_id: %d dialog_id: %d", + vdev_id, dialog_id); + return false; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + twt_err("Peer list for vdev obj is NULL"); + return false; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_TWT_ID); + while (peer) { + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (peer_priv) { + cmd_in_progress = + wlan_twt_util_cmd_in_progress(peer_priv, + dialog_id, cmd); + + if (cmd_in_progress) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return cmd_in_progress; + } + } + + peer_next = + wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_TWT_ID); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + peer = peer_next; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return cmd_in_progress; +} + +/** + * wlan_twt_sap_peer_is_cmd_in_progress() - For a given peer_mac check if + * the given command is in progress + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * + * Return: True if given command is in progress. + */ +static bool +wlan_twt_sap_peer_is_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + struct wlan_objmgr_peer *peer; + struct twt_peer_priv_obj *peer_priv; + uint8_t i; + bool cmd_in_progress = false; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("twt peer component object is NULL"); + return false; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + enum wlan_twt_commands active_cmd; + uint8_t existing_dialog_id; + + active_cmd = + peer_priv->session_info[i].active_cmd; + existing_dialog_id = + peer_priv->session_info[i].dialog_id; + + if (existing_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID || + existing_dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + cmd_in_progress = (active_cmd == cmd); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + cmd_in_progress) { + break; + } + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return cmd_in_progress; +} + +/** + * wlan_twt_sap_is_command_in_progress() - Based on the input peer mac address + * invoke the appropriate function to check if the given command is in progress + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * @cmd: command + * + * If the input @peer_mac is a broadcast MAC address then the expectation is + * to iterate through the list of all peers and check for any given @dialog_id + * if the command @cmd is in progress. + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * For ex: If TWT teardown command is issued on a particular @dialog_id and + * non-broadcast peer mac and FW response is not yet received then for that + * particular @dialog_id and @peer_mac, TWT teardown is the active command, + * then if the driver receives another TWT teardown request with broadcast + * peer mac, then API wlan_twt_any_peer_cmd_in_progress() shall iterate + * through the list of all peers and returns command in progress as true. + * + * If the input @peer_mac is a non-broadcast MAC address then + * wlan_twt_sap_peer_is_cmd_in_progress() shall check only for that + * particular @peer_mac and @dialog_id. + * + * Return: true if command is in progress, false otherwise + */ +static bool +wlan_twt_sap_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + if (qdf_is_macaddr_broadcast(peer_mac)) { + return wlan_twt_any_peer_cmd_in_progress(psoc, vdev_id, + dialog_id, cmd); + } else { + return wlan_twt_sap_peer_is_cmd_in_progress(psoc, peer_mac, + dialog_id, cmd); + } +} + +/** + * wlan_twt_sap_add_session() - Based on the input peer mac address + * invoke the appropriate function to add dialog_id to the TWT session context + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * + * If the input @peer_mac is a broadcast MAC address then there is nothing + * to do, because the initialized structure is already in the expected format + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * + * If the input @peer_mac is a non-broadcast MAC address then + * wlan_twt_add_session() shall add the @dialog_id to the @peer_mac + * TWT session context. + * + * Return: None + */ +static void +wlan_twt_sap_add_session(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + if (!qdf_is_macaddr_broadcast(peer_mac)) + wlan_twt_add_session(psoc, peer_mac, dialog_id, NULL); +} + +/** + * wlan_twt_sap_set_all_peers_cmd_in_progress() - Iterate through the list + * of peers and set the command in the TWT session entry in the TWT context + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @dialog_id: Dialog ID + * @cmd: Command + * + * This API iterates through the list of peers and updates the active + * command to @cmd for the given dialog_id. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_sap_set_all_peers_cmd_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct twt_peer_priv_obj *peer_priv; + + if (!psoc) { + twt_err("psoc is NULL, dialog_id: %d", dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + twt_err("vdev is NULL, vdev_id: %d dialog_id: %d", + vdev_id, dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + twt_err("Peer list for vdev obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_TWT_ID); + while (peer) { + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (peer_priv) { + uint8_t i; + uint8_t num_sessions = peer_priv->num_twt_sessions; + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < num_sessions; i++) { + uint8_t eid = + peer_priv->session_info[i].dialog_id; + + if (eid == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].active_cmd = + cmd; + + if (dialog_id != + TWT_ALL_SESSIONS_DIALOG_ID) { + break; + } + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + } + + peer_next = + wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_TWT_ID); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + peer = peer_next; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_twt_sap_set_command_in_progress() - Based on the input peer mac address + * invoke the appropriate function to set the command is in progress + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * @cmd: command + * + * If the input @peer_mac is a broadcast MAC address then the expectation is + * to iterate through the list of all peers and set the active command to @cmd + * for the given @dialog_id + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * For ex: If TWT teardown command is issued on broadcast @peer_mac, then + * it is same as issuing TWT teardown for all the peers (all TWT sessions). + * Invoking wlan_twt_sap_set_all_peers_cmd_in_progress() shall iterate through + * all the peers and set the active command to @cmd. + * + * If the input @peer_mac is a non-broadcast MAC address then + * wlan_twt_set_command_in_progress() shall set the active command to @cmd + * only for that particular @peer_mac and @dialog_id. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_sap_set_command_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + if (qdf_is_macaddr_broadcast(peer_mac)) { + return wlan_twt_sap_set_all_peers_cmd_in_progress(psoc, + vdev_id, + dialog_id, + cmd); + } else { + return wlan_twt_set_command_in_progress(psoc, peer_mac, + dialog_id, cmd); + } +} + +/** + * wlan_twt_init_all_peers_context() - Iterate through the list + * of peers and initialize the TWT context structure + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @dialog_id: Dialog ID + * + * This API iterates through the list of peers and initializes + * the TWT context structure + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_init_all_peers_context(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint8_t dialog_id) +{ + qdf_list_t *peer_list; + struct wlan_objmgr_peer *peer, *peer_next; + struct wlan_objmgr_vdev *vdev; + struct twt_peer_priv_obj *peer_priv; + + if (!psoc) { + twt_err("psoc is NULL, dialog_id: %d", dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + twt_err("vdev is NULL, vdev_id: %d dialog_id: %d", + vdev_id, dialog_id); + return QDF_STATUS_E_NULL_VALUE; + } + + peer_list = &vdev->vdev_objmgr.wlan_peer_list; + if (!peer_list) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + twt_err("Peer list for vdev obj is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + peer = wlan_vdev_peer_list_peek_active_head(vdev, peer_list, + WLAN_TWT_ID); + while (peer) { + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (peer_priv) { + uint8_t i = 0; + uint8_t num_sessions = WLAN_MAX_TWT_SESSIONS_PER_PEER; + + peer_priv->num_twt_sessions = num_sessions; + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < num_sessions; i++) { + uint8_t eid = + peer_priv->session_info[i].dialog_id; + + if (eid == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].setup_done = + false; + peer_priv->session_info[i].dialog_id = + TWT_ALL_SESSIONS_DIALOG_ID; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + } + + peer_next = + wlan_peer_get_next_active_peer_of_vdev(vdev, + peer_list, + peer, + WLAN_TWT_ID); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + peer = peer_next; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + twt_debug("init done"); + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_twt_sap_init_context() - Based on the input peer mac address + * invoke the appropriate function to initialize the TWT session context + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * + * If the input @peer_mac is a broadcast MAC address then the expectation is + * to iterate through the list of all peers and initialize the TWT session + * context + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * For ex: If TWT teardown command is issued on broadcast @peer_mac, then + * it is same as issuing TWT teardown for all the peers (all TWT sessions). + * Then active command for all the peers is set to @WLAN_TWT_TERMINATE. + * Upon receiving the TWT teardown WMI event, wlan_twt_init_all_peers_context() + * shall iterate through the list of all peers and initializes the TWT session + * context back to its initial state. + * + * If the input @peer_mac is a non-broadcast MAC address then + * wlan_twt_init_context() shall initialize the TWT session context + * only for that particular @peer_mac and @dialog_id. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_sap_init_context(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + if (!qdf_is_macaddr_broadcast(peer_mac)) + return wlan_twt_init_context(psoc, peer_mac, dialog_id); + + return wlan_twt_init_all_peers_context(psoc, vdev_id, dialog_id); +} + +/** + * wlan_is_vdev_connected_to_peer() - find if peer exists in the vdev peer list + * @psoc: Pointer to global psoc object + * @vdev_id: Vdev id + * @peer_macaddr: peer mac address + * + * This API finds if for the given vdev there exists a peer with the given + * @peer_macaddr + * + * Return: true if exists, false otherwise + */ +static bool +wlan_is_vdev_connected_to_peer(struct wlan_objmgr_psoc *psoc, uint32_t vdev_id, + struct qdf_mac_addr *peer_macaddr) +{ + uint8_t pdev_id; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + bool connection_exists = false; + + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, + WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return connection_exists; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return connection_exists; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + twt_err("vdev object is NULL"); + goto end; + } + + peer = wlan_objmgr_vdev_find_peer_by_mac(vdev, peer_macaddr->bytes, + WLAN_TWT_ID); + if (peer) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + connection_exists = true; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); +end: + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return connection_exists; +} + +/** + * wlan_twt_is_setup_done() - Get if TWT session is established for given + * dialog id. + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: Return true if TWT session exists for given dialog ID. + */ +bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + bool is_setup_done = false; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer mlme component object is NULL"); + return false; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + is_setup_done = peer_priv->session_info[i].setup_done; + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + is_setup_done) + break; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return is_setup_done; +} + +bool wlan_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i, num_twt_sessions = 0, max_twt_sessions; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return true; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer twt component object is NULL"); + return true; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + max_twt_sessions = peer_priv->num_twt_sessions; + for (i = 0; i < max_twt_sessions; i++) { + uint8_t existing_session_dialog_id = + peer_priv->session_info[i].dialog_id; + + if (existing_session_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + existing_session_dialog_id != dialog_id) + num_twt_sessions++; + } + + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + twt_debug("num_twt_sessions:%d max_twt_sessions:%d", + num_twt_sessions, max_twt_sessions); + return num_twt_sessions == max_twt_sessions; +} + +bool wlan_twt_is_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer twt component object is NULL"); + return false; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + bool setup_done = peer_priv->session_info[i].setup_done; + uint8_t existing_session_dialog_id; + + existing_session_dialog_id = + peer_priv->session_info[i].dialog_id; + if (existing_session_dialog_id == dialog_id && + existing_session_dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + !setup_done) { + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return true; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return false; +} + +/** + * wlan_twt_set_ack_context() - set twt ack context + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * @context: TWT context + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_set_ack_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + void *context) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer twt component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + uint8_t existing_session_dialog_id; + + existing_session_dialog_id = + peer_priv->session_info[i].dialog_id; + if (existing_session_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].twt_ack_ctx = context; + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) + break; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_twt_get_ack_context() - get twt ack context + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * @context: TWT context + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_twt_get_ack_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + void **context) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + goto err; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err("peer twt component object is NULL"); + goto err; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + uint8_t existing_session_dialog_id; + + existing_session_dialog_id = + peer_priv->session_info[i].dialog_id; + if (existing_session_dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + *context = peer_priv->session_info[i].twt_ack_ctx; + break; + } + } + + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return QDF_STATUS_SUCCESS; + +err: + *context = NULL; + return QDF_STATUS_E_FAILURE; +} + +bool wlan_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd) +{ + struct wlan_objmgr_peer *peer; + struct twt_peer_priv_obj *peer_priv; + enum wlan_twt_commands active_cmd; + uint8_t i = 0; + bool is_command_in_progress = false; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return false; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return false; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + active_cmd = peer_priv->session_info[i].active_cmd; + + if (pactive_cmd) + *pactive_cmd = active_cmd; + + if (peer_priv->session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + if (cmd == WLAN_TWT_ANY) { + is_command_in_progress = + (active_cmd != WLAN_TWT_NONE); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + is_command_in_progress) + break; + } else { + is_command_in_progress = (active_cmd == cmd); + + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID || + is_command_in_progress) + break; + } + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return is_command_in_progress; +} + +QDF_STATUS wlan_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *req, + void *context) +{ + QDF_STATUS status; + bool cmd_in_progress, notify_in_progress; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + if (wlan_twt_is_max_sessions_reached(psoc, &req->peer_macaddr, + req->dialog_id)) { + twt_err("TWT add failed(dialog_id:%d), another TWT already exists (max reached)", + req->dialog_id); + return QDF_STATUS_E_AGAIN; + } + + if (wlan_twt_is_setup_in_progress(psoc, &req->peer_macaddr, + req->dialog_id)) { + twt_err("TWT setup is in progress for dialog_id:%d", + req->dialog_id); + return QDF_STATUS_E_ALREADY; + } + + if (!mlme_get_user_ps(psoc, req->vdev_id)) { + twt_warn("Power save mode disable"); + return QDF_STATUS_E_AGAIN; + } + + notify_in_progress = wlan_is_twt_notify_in_progress(psoc, req->vdev_id); + if (notify_in_progress) { + twt_warn("Waiting for TWT Notify"); + return QDF_STATUS_E_BUSY; + } + + cmd_in_progress = wlan_twt_is_command_in_progress( + psoc, &req->peer_macaddr, req->dialog_id, + WLAN_TWT_ANY, &active_cmd); + if (cmd_in_progress) { + twt_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + /* + * Add the dialog id to TWT context to drop back to back + * commands + */ + wlan_twt_add_session(psoc, &req->peer_macaddr, req->dialog_id, context); + wlan_twt_set_ack_context(psoc, &req->peer_macaddr, req->dialog_id, + context); + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_SETUP); + + status = tgt_twt_setup_req_send(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("tgt_twt_setup_req_send failed (status=%d)", status); + wlan_twt_init_context(psoc, &req->peer_macaddr, req->dialog_id); + } + + return status; +} + +/** + * wlan_twt_sta_teardown_req() - station TWT teardown request + * @psoc: Pointer to psoc object + * @req: TWT del dialog parameters + * @context: TWT context + * + * Return: QDF Status + */ +static QDF_STATUS +wlan_twt_sta_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req, + void *context) +{ + bool cmd_in_progress; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + QDF_STATUS status; + + if (!wlan_twt_is_setup_done(psoc, &req->peer_macaddr, req->dialog_id)) { + twt_err("vdev%d: TWT session %d setup incomplete", + req->vdev_id, req->dialog_id); + return QDF_STATUS_E_AGAIN; + } + + cmd_in_progress = + wlan_twt_is_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_SETUP, &active_cmd) || + wlan_twt_is_command_in_progress( + psoc, &req->peer_macaddr, req->dialog_id, + WLAN_TWT_TERMINATE, &active_cmd); + if (cmd_in_progress) { + twt_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wlan_twt_set_ack_context(psoc, &req->peer_macaddr, + req->dialog_id, context); + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_TERMINATE); + + status = tgt_twt_teardown_req_send(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("tgt_twt_teardown_req_send failed (status=%d)", status); + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_NONE); + } + + return status; +} + +QDF_STATUS wlan_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *req, + void *context) +{ + QDF_STATUS status; + bool cmd_in_progress; + bool is_twt_setup_done; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + status = wlan_twt_check_all_twt_support(psoc, req->dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("All TWT sessions not supported by target"); + return status; + } + + is_twt_setup_done = wlan_twt_is_setup_done(psoc, &req->peer_macaddr, + req->dialog_id); + if (!is_twt_setup_done) { + twt_err("TWT setup is not complete for dialog_id:%d", + req->dialog_id); + return QDF_STATUS_E_AGAIN; + } + + cmd_in_progress = wlan_twt_is_command_in_progress(psoc, + &req->peer_macaddr, req->dialog_id, + WLAN_TWT_ANY, &active_cmd); + if (cmd_in_progress) { + twt_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_SUSPEND); + wlan_twt_set_ack_context(psoc, &req->peer_macaddr, + req->dialog_id, context); + + status = tgt_twt_pause_req_send(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("tgt_twt_pause_req_send failed (status=%d)", status); + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_NONE); + } + + return status; +} + +QDF_STATUS wlan_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *req, + void *context) +{ + QDF_STATUS status; + bool cmd_in_progress; + bool is_twt_setup_done; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + status = wlan_twt_check_all_twt_support(psoc, req->dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("All TWT sessions not supported by target"); + return status; + } + + is_twt_setup_done = wlan_twt_is_setup_done(psoc, &req->peer_macaddr, + req->dialog_id); + if (!is_twt_setup_done) { + twt_err("TWT setup is not complete for dialog_id:%d", + req->dialog_id); + return QDF_STATUS_E_AGAIN; + } + + cmd_in_progress = wlan_twt_is_command_in_progress(psoc, + &req->peer_macaddr, + req->dialog_id, WLAN_TWT_ANY, + &active_cmd); + if (cmd_in_progress) { + twt_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_RESUME); + wlan_twt_set_ack_context(psoc, &req->peer_macaddr, + req->dialog_id, context); + + status = tgt_twt_resume_req_send(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("tgt_twt_resume_req_send failed (status=%d)", status); + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_NONE); + } + + return status; +} + +QDF_STATUS wlan_twt_nudge_req(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *req, + void *context) +{ + QDF_STATUS status; + bool cmd_in_progress; + bool setup_done; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + status = wlan_twt_check_all_twt_support(psoc, req->dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("All TWT sessions not supported by target"); + return status; + } + + setup_done = wlan_twt_is_setup_done(psoc, &req->peer_macaddr, + req->dialog_id); + if (!setup_done) { + twt_err("TWT setup is not complete for dialog_id:%d", + req->dialog_id); + return QDF_STATUS_E_AGAIN; + } + + cmd_in_progress = wlan_twt_is_command_in_progress(psoc, + &req->peer_macaddr, req->dialog_id, + WLAN_TWT_ANY, &active_cmd); + if (cmd_in_progress) { + twt_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_NUDGE); + wlan_twt_set_ack_context(psoc, &req->peer_macaddr, req->dialog_id, + context); + + status = tgt_twt_nudge_req_send(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("tgt_twt_nudge_req_send failed (status=%d)", status); + wlan_twt_set_command_in_progress(psoc, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_NONE); + } + + return status; +} + +QDF_STATUS wlan_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac) +{ + QDF_STATUS status; + + status = tgt_twt_ac_pdev_param_send(psoc, twt_ac); + if (QDF_IS_STATUS_ERROR(status)) + twt_err("failed (status=%d)", status); + + return status; +} + +/** + * wlan_twt_sap_teardown_req() - sap TWT teardown request + * @psoc: Pointer to psoc object + * @req: TWT del dialog parameters + * + * Return: QDF Status + */ +static QDF_STATUS +wlan_twt_sap_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req) +{ + bool is_twt_cmd_in_progress; + QDF_STATUS status; + bool connection_exists; + + if (!qdf_is_macaddr_broadcast(&req->peer_macaddr)) { + connection_exists = wlan_is_vdev_connected_to_peer(psoc, + req->vdev_id, + &req->peer_macaddr); + if (!connection_exists) { + twt_warn("SAP doesn't have connection with this peer("QDF_MAC_ADDR_FMT")", + QDF_MAC_ADDR_REF(req->peer_macaddr.bytes)); + /* + * Return success, since STA is not associated and + * there is no TWT session. + */ + return QDF_STATUS_SUCCESS; + } + } + + is_twt_cmd_in_progress = + wlan_twt_sap_is_command_in_progress( + psoc, req->vdev_id, &req->peer_macaddr, + req->dialog_id, WLAN_TWT_TERMINATE); + if (is_twt_cmd_in_progress) { + twt_debug("Already TWT teardown command is in progress"); + return QDF_STATUS_E_PENDING; + } + + /* + * Add the dialog id to TWT context to drop back to back + * commands + */ + wlan_twt_sap_add_session(psoc, req->vdev_id, &req->peer_macaddr, + req->dialog_id); + + wlan_twt_sap_set_command_in_progress(psoc, req->vdev_id, + &req->peer_macaddr, req->dialog_id, + WLAN_TWT_TERMINATE); + + status = tgt_twt_teardown_req_send(psoc, req); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("tgt_twt_teardown_req_send failed (status=%d)", status); + wlan_twt_sap_set_command_in_progress(psoc, req->vdev_id, + &req->peer_macaddr, req->dialog_id, + WLAN_TWT_NONE); + wlan_twt_sap_init_context(psoc, req->vdev_id, + &req->peer_macaddr, req->dialog_id); + } + + return status; +} + +QDF_STATUS +wlan_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req, + void *context) +{ + enum QDF_OPMODE opmode; + uint32_t pdev_id; + struct wlan_objmgr_pdev *pdev; + QDF_STATUS status; + + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, req->vdev_id, + WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + status = wlan_twt_check_all_twt_support(psoc, req->dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("All TWT sessions not supported by target"); + return status; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, req->vdev_id); + + switch (opmode) { + case QDF_SAP_MODE: + status = wlan_twt_sap_teardown_req(psoc, req); + break; + case QDF_STA_MODE: + status = wlan_twt_sta_teardown_req(psoc, req, context); + break; + default: + twt_err("TWT teardown not supported in mode: %d", opmode); + status = QDF_STATUS_E_INVAL; + break; + } + + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return status; +} + +QDF_STATUS +wlan_twt_ack_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *event) +{ + void *ack_context = NULL; + QDF_STATUS qdf_status; + + twt_debug("TWT ack status: %d", event->status); + /* If the ack status is other than 0 (SUCCESS) then its a error. + * that means there won't be following TWT add/del/pause/resume/nudge + * event, hence clear the command in progress to NONE + */ + if (event->status) { + qdf_status = wlan_twt_set_command_in_progress(psoc, + &event->peer_macaddr, + event->dialog_id, WLAN_TWT_NONE); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + } + qdf_status = wlan_twt_get_ack_context(psoc, &event->peer_macaddr, + event->dialog_id, &ack_context); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + qdf_status = mlme_twt_osif_ack_complete_ind(psoc, event, ack_context); + + return qdf_status; +} + +/** + * wlan_twt_set_setup_done() - Set TWT setup complete for given dialog ID + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @is_set: Set or clear the setup done flag + * + * Return: None + */ +static void +wlan_twt_set_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, bool is_set) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id) { + peer_priv->session_info[i].setup_done = is_set; + twt_debug("setup done:%d dialog:%d", is_set, dialog_id); + break; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); +} + +/** + * wlan_twt_set_session_state() - Set the TWT session state for the given dialog + * id in TWT context + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @state: TWT session state + * + * Return: None + */ +static void +wlan_twt_set_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_session_state state) +{ + struct wlan_objmgr_peer *peer; + struct twt_peer_priv_obj *peer_priv; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return; + } + + twt_debug("set_state:%d for dialog_id:%d", state, dialog_id); + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id || + dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].state = state; + break; + } + } + qdf_mutex_release(&peer_priv->twt_peer_lock); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); +} + +enum wlan_twt_session_state +wlan_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + struct wlan_objmgr_peer *peer; + struct twt_peer_priv_obj *peer_priv; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id && + dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return peer_priv->session_info[i].state; + } + } + + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + +/** + * wlan_twt_process_renego_failure() - Process TWT re-negotiation failure + * @psoc: psoc + * @event: pointer to event buf containing twt response parameters + * + * Return: None + */ +static void +wlan_twt_process_renego_failure(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + /* Reset the active TWT command to none */ + wlan_twt_set_command_in_progress(psoc, + &event->params.peer_macaddr, + event->params.dialog_id, + WLAN_TWT_NONE); + + mlme_twt_osif_setup_complete_ind(psoc, event, true); +} + +/** + * wlan_twt_process_add_initial_nego() - Process initial TWT setup or + * re-negotiation successful setup + * @psoc: psoc + * @event: pointer to event buf containing twt response parameters + * + * Return: None + */ +static void +wlan_twt_process_add_initial_nego(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + mlme_twt_osif_setup_complete_ind(psoc, event, false); + + /* Reset the active TWT command to none */ + wlan_twt_set_command_in_progress(psoc, + &event->params.peer_macaddr, + event->params.dialog_id, + WLAN_TWT_NONE); + + if (event->params.status) { + /* Clear the stored TWT dialog ID as TWT setup failed */ + wlan_twt_init_context(psoc, &event->params.peer_macaddr, + event->params.dialog_id); + return; + } + + wlan_twt_set_setup_done(psoc, &event->params.peer_macaddr, + event->params.dialog_id, true); + + wlan_twt_set_session_state(psoc, &event->params.peer_macaddr, + event->params.dialog_id, + WLAN_TWT_SETUP_STATE_ACTIVE); +} + +/* + * wlan_twt_clear_wake_dur_and_interval() - Clear cached TWT wake duration and + * wake interval of peer. + * @psoc: Pointer to psoc object + * @vdev_id: Vdev Id + * @peer_mac: Peer mac address + * @dialog_id: Dialog Id + * + * Return: QDF_STATUS + */ +static void +wlan_twt_clear_wake_dur_and_interval(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id) { + peer_priv->session_info[i].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + peer_priv->session_info[i].wake_dur = 0; + peer_priv->session_info[i].wake_interval = 0; + break; + } + } + + twt_debug("vdev:%d peer:" QDF_MAC_ADDR_FMT " dialog_id:%d wake_dur:%d wake_interval:%d", + vdev_id, + QDF_MAC_ADDR_REF(peer_mac->bytes), + peer_priv->session_info[i].dialog_id, + peer_priv->session_info[i].wake_dur, + peer_priv->session_info[i].wake_interval); + + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); +} + +/* + * wlan_twt_set_wake_dur_and_interval() - Set TWT wake duration and wake + * interval of peer. + * @psoc: Pointer to psoc object + * @vdev_id: Vdev Id + * @peer_mac: Peer mac address + * @dialog_id: Dialog Id + * @wake_dur: TWT wake duration + * @wake_interval: TWT wake interval + * + * Return: QDF_STATUS + */ +static void +wlan_twt_set_wake_dur_and_interval(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + uint32_t wake_dur, + uint32_t wake_interval) +{ + struct twt_peer_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + uint8_t i; + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac->bytes, + WLAN_TWT_ID); + if (!peer) { + twt_err("Peer object not found "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + return; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_TWT); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + twt_err(" peer twt component object is NULL"); + return; + } + + qdf_mutex_acquire(&peer_priv->twt_peer_lock); + + for (i = 0; i < peer_priv->num_twt_sessions; i++) { + if (peer_priv->session_info[i].dialog_id == dialog_id) { + peer_priv->session_info[i].wake_dur = wake_dur; + peer_priv->session_info[i].wake_interval = wake_interval; + break; + } else { + if (peer_priv->session_info[i].dialog_id == TWT_ALL_SESSIONS_DIALOG_ID) { + peer_priv->session_info[i].dialog_id = dialog_id; + peer_priv->session_info[i].wake_dur = wake_dur; + peer_priv->session_info[i].wake_interval = wake_interval; + break; + } + } + } + + twt_debug("vdev:%d peer:" QDF_MAC_ADDR_FMT " dialog_id:%d wake_dur:%d wake_interval:%d", + vdev_id, + QDF_MAC_ADDR_REF(peer_mac->bytes), + peer_priv->session_info[i].dialog_id, + peer_priv->session_info[i].wake_dur, + peer_priv->session_info[i].wake_interval); + + qdf_mutex_release(&peer_priv->twt_peer_lock); + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); +} + +QDF_STATUS +wlan_twt_setup_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + bool is_evt_allowed; + bool setup_done; + enum HOST_TWT_ADD_STATUS status = event->params.status; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t pdev_id, vdev_id; + struct wlan_objmgr_pdev *pdev; + + vdev_id = event->params.vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + + switch (opmode) { + case QDF_SAP_MODE: + wlan_twt_set_wake_dur_and_interval( + psoc, vdev_id, + &event->params.peer_macaddr, + event->params.dialog_id, + event->additional_params.wake_dur_us, + event->additional_params.wake_intvl_us); + qdf_status = mlme_twt_osif_setup_complete_ind(psoc, event, + false); + break; + case QDF_STA_MODE: + is_evt_allowed = wlan_twt_is_command_in_progress( + psoc, + &event->params.peer_macaddr, + event->params.dialog_id, + WLAN_TWT_SETUP, &active_cmd); + + if (!is_evt_allowed) { + twt_debug("Drop TWT add dialog event for dialog_id:%d status:%d active_cmd:%d", + event->params.dialog_id, status, + active_cmd); + qdf_status = QDF_STATUS_E_INVAL; + goto cleanup; + } + + setup_done = wlan_twt_is_setup_done(psoc, + &event->params.peer_macaddr, + event->params.dialog_id); + twt_debug("setup_done:%d status:%d", setup_done, status); + + if (setup_done && status) { + /*This is re-negotiation failure case */ + wlan_twt_process_renego_failure(psoc, event); + } else { + wlan_twt_process_add_initial_nego(psoc, event); + } + + qdf_status = QDF_STATUS_SUCCESS; + break; + default: + twt_debug("TWT Setup is not supported on %s", + qdf_opmode_str(opmode)); + break; + } + +cleanup: + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return qdf_status; +} + +static bool +wlan_is_twt_teardown_failed(enum HOST_TWT_DEL_STATUS teardown_status) +{ + switch (teardown_status) { + case HOST_TWT_DEL_STATUS_DIALOG_ID_NOT_EXIST: + case HOST_TWT_DEL_STATUS_INVALID_PARAM: + case HOST_TWT_DEL_STATUS_DIALOG_ID_BUSY: + case HOST_TWT_DEL_STATUS_NO_RESOURCE: + case HOST_TWT_DEL_STATUS_NO_ACK: + case HOST_TWT_DEL_STATUS_UNKNOWN_ERROR: + return true; + default: + return false; + } + + return false; +} + +static void +wlan_twt_handle_sta_del_dialog_event(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + bool is_evt_allowed, usr_cfg_ps_enable; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + is_evt_allowed = wlan_twt_is_command_in_progress( + psoc, &event->peer_macaddr, + event->dialog_id, + WLAN_TWT_TERMINATE, &active_cmd); + if (!is_evt_allowed && + event->dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + event->status != HOST_TWT_DEL_STATUS_ROAMING && + event->status != HOST_TWT_DEL_STATUS_PEER_INIT_TEARDOWN && + event->status != HOST_TWT_DEL_STATUS_CONCURRENCY) { + twt_err("Drop TWT Del dialog event for dialog_id:%d status:%d active_cmd:%d", + event->dialog_id, event->status, active_cmd); + + return; + } + + usr_cfg_ps_enable = mlme_get_user_ps(psoc, event->vdev_id); + if (!usr_cfg_ps_enable && + event->status == HOST_TWT_DEL_STATUS_OK) + event->status = HOST_TWT_DEL_STATUS_PS_DISABLE_TEARDOWN; + + mlme_twt_osif_teardown_complete_ind(psoc, event); + + if (event->status == HOST_TWT_DEL_STATUS_ROAMING || + event->status == HOST_TWT_DEL_STATUS_CONCURRENCY) + wlan_twt_set_wait_for_notify(psoc, event->vdev_id, true); + + wlan_twt_set_command_in_progress(psoc, &event->peer_macaddr, + event->dialog_id, WLAN_TWT_NONE); + + if (wlan_is_twt_teardown_failed(event->status)) + return; + + wlan_twt_set_setup_done(psoc, &event->peer_macaddr, + event->dialog_id, false); + wlan_twt_set_session_state(psoc, &event->peer_macaddr, event->dialog_id, + WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED); + wlan_twt_init_context(psoc, &event->peer_macaddr, event->dialog_id); +} + +QDF_STATUS +wlan_twt_teardown_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + enum QDF_OPMODE opmode; + uint32_t pdev_id, vdev_id; + struct wlan_objmgr_pdev *pdev; + + vdev_id = event->vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + + switch (opmode) { + case QDF_SAP_MODE: + mlme_twt_osif_teardown_complete_ind(psoc, event); + + wlan_twt_clear_wake_dur_and_interval(psoc, vdev_id, + &event->peer_macaddr, + event->dialog_id); + + /* + * If this is an unsolicited TWT del event initiated from the + * peer, then no need to clear the active command in progress + */ + if (event->status != HOST_TWT_DEL_STATUS_PEER_INIT_TEARDOWN) { + /* Reset the active TWT command to none */ + wlan_twt_sap_set_command_in_progress(psoc, + event->vdev_id, &event->peer_macaddr, + event->dialog_id, WLAN_TWT_NONE); + wlan_twt_sap_init_context(psoc, event->vdev_id, + &event->peer_macaddr, event->dialog_id); + } + break; + case QDF_STA_MODE: + wlan_twt_handle_sta_del_dialog_event(psoc, event); + break; + default: + twt_debug("TWT Teardown is not supported on %s", + qdf_opmode_str(opmode)); + break; + } + + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_twt_pause_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event) +{ + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t pdev_id, vdev_id; + struct wlan_objmgr_pdev *pdev; + + vdev_id = event->vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + + switch (opmode) { + case QDF_SAP_MODE: + qdf_status = mlme_twt_osif_pause_complete_ind(psoc, event); + break; + case QDF_STA_MODE: + qdf_status = mlme_twt_osif_pause_complete_ind(psoc, event); + + wlan_twt_set_session_state(psoc, &event->peer_macaddr, + event->dialog_id, + WLAN_TWT_SETUP_STATE_SUSPEND); + + qdf_status = wlan_twt_set_command_in_progress(psoc, + &event->peer_macaddr, + event->dialog_id, WLAN_TWT_NONE); + break; + default: + twt_debug("TWT Pause is not supported on %s", + qdf_opmode_str(opmode)); + break; + } + + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return qdf_status; +} + +QDF_STATUS +wlan_twt_resume_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event) +{ + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t pdev_id, vdev_id; + struct wlan_objmgr_pdev *pdev; + + vdev_id = event->vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + + switch (opmode) { + case QDF_SAP_MODE: + qdf_status = mlme_twt_osif_resume_complete_ind(psoc, event); + break; + case QDF_STA_MODE: + qdf_status = mlme_twt_osif_resume_complete_ind(psoc, event); + + wlan_twt_set_session_state(psoc, &event->peer_macaddr, + event->dialog_id, + WLAN_TWT_SETUP_STATE_ACTIVE); + + qdf_status = wlan_twt_set_command_in_progress(psoc, + &event->peer_macaddr, + event->dialog_id, + WLAN_TWT_NONE); + break; + default: + twt_debug("TWT Resume is not supported on %s", + qdf_opmode_str(opmode)); + break; + } + + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return qdf_status; +} + +QDF_STATUS +wlan_twt_nudge_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event) +{ + bool is_evt_allowed; + enum HOST_TWT_NUDGE_STATUS status = event->status; + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + uint32_t pdev_id, vdev_id; + struct wlan_objmgr_pdev *pdev; + + vdev_id = event->vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + twt_err("Invalid pdev id"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + twt_err("Invalid pdev"); + return QDF_STATUS_E_INVAL; + } + + opmode = wlan_get_opmode_from_vdev_id(pdev, vdev_id); + + switch (opmode) { + case QDF_SAP_MODE: + qdf_status = mlme_twt_osif_nudge_complete_ind(psoc, event); + break; + case QDF_STA_MODE: + is_evt_allowed = wlan_twt_is_command_in_progress( + psoc, + &event->peer_macaddr, + event->dialog_id, + WLAN_TWT_NUDGE, &active_cmd); + + if (!is_evt_allowed && + event->dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + twt_debug("Drop TWT nudge dialog event for dialog_id:%d status:%d active_cmd:%d", + event->dialog_id, status, + active_cmd); + qdf_status = QDF_STATUS_E_INVAL; + goto fail; + } + + mlme_twt_osif_nudge_complete_ind(psoc, event); + qdf_status = wlan_twt_set_command_in_progress(psoc, + &event->peer_macaddr, + event->dialog_id, WLAN_TWT_NONE); + break; + default: + twt_debug("TWT nudge is not supported on %s", + qdf_opmode_str(opmode)); + break; + } + +fail: + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); + return qdf_status; +} + +QDF_STATUS +wlan_twt_notify_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event) +{ + QDF_STATUS status; + + if (event->status == HOST_TWT_NOTIFY_EVENT_READY) + status = wlan_twt_set_wait_for_notify(psoc, event->vdev_id, + false); + else + status = wlan_twt_update_peer_twt_required_bit(psoc, event); + + if (QDF_IS_STATUS_ERROR(status)) { + twt_err("failed to get status"); + return status; + } + + mlme_twt_osif_notify_complete_ind(psoc, event); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_twt_update_beacon_template(void) +{ + struct scheduler_msg msg = { 0 }; + QDF_STATUS status; + + msg.type = SIR_LIM_UPDATE_BEACON; + status = scheduler_post_message(QDF_MODULE_ID_TWT, QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) + twt_err("scheduler_post_message failed, status = %u", status); + + return status; +} + +void wlan_twt_set_work_params( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + bool is_ps_disabled, + uint32_t twt_next_action) +{ + struct twt_vdev_priv_obj *twt_vdev_priv; + + twt_vdev_priv = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_TWT); + + if (!twt_vdev_priv) { + twt_err("twt vdev private obj is null"); + return; + } + + qdf_copy_macaddr(&twt_vdev_priv->peer_macaddr, peer_mac); + twt_vdev_priv->dialog_id = dialog_id; + twt_vdev_priv->is_ps_disabled = is_ps_disabled; + twt_vdev_priv->next_action = twt_next_action; + + twt_debug("TWT terminate: dialog_id:%d is_ps_disabled:%d next_action:%d peer mac_addr " + QDF_MAC_ADDR_FMT, twt_vdev_priv->dialog_id, + twt_vdev_priv->is_ps_disabled, + twt_vdev_priv->next_action, + QDF_MAC_ADDR_REF(twt_vdev_priv->peer_macaddr.bytes)); +} + +void wlan_twt_get_work_params(struct wlan_objmgr_vdev *vdev, + struct twt_work_params *params, + uint32_t *next_action) +{ + struct twt_vdev_priv_obj *twt_vdev_priv; + + twt_vdev_priv = wlan_objmgr_vdev_get_comp_private_obj( + vdev, WLAN_UMAC_COMP_TWT); + if (!twt_vdev_priv) { + twt_err("twt vdev private obj is null"); + return; + } + + qdf_copy_macaddr(¶ms->peer_macaddr, &twt_vdev_priv->peer_macaddr); + params->dialog_id = twt_vdev_priv->dialog_id; + params->is_ps_disabled = twt_vdev_priv->is_ps_disabled; + *next_action = twt_vdev_priv->next_action; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_main.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_main.h new file mode 100644 index 0000000000..a469764cff --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/core/src/wlan_twt_main.h @@ -0,0 +1,497 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if defined(WLAN_SUPPORT_TWT) + +/** + * wlan_twt_is_max_sessions_reached() - Check if the maximum number of + * TWT sessions reached or not excluding the given dialog_id + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: dialog id + * + * Check if the number of active TWT sessions is equal to the maximum number + * of TWT sessions supported. Only count the TWT session slot if it not + * TWT_ALL_SESSIONS_DIALOG_ID and dialog id is different from input dialog_id, + * because if same dialog_id already exists in the TWT sessions, we should + * return false since re-negotiation is supported on existing dialog_id. + * + * Return: True if slot is available for dialog_id, false otherwise + */ +bool +wlan_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * wlan_twt_set_command_in_progress() - Set TWT command is in progress + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_set_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd); + +/** + * wlan_twt_setup_req() - twt setup request + * @psoc: Pointer to psoc object + * @req: TWT setup request + * @context: context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *req, + void *context); + +/** + * wlan_twt_teardown_req() - twt teardown request + * @psoc: Pointer to psoc object + * @req: TWT setup request + * @context: context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req, + void *context); + +/** + * wlan_twt_pause_req() - Process TWT pause req + * @psoc: psoc + * @req: pause dialog cmd param + * @context: context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *req, + void *context); + +/** + * wlan_twt_resume_req() - Process TWT resume req + * @psoc: psoc + * @req: resume dialog cmd param + * @context: context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *req, + void *context); + +/** + * wlan_twt_nudge_req() - Process TWT nudge req + * @psoc: psoc + * @req: nudge dialog cmd param + * @context: context + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_nudge_req(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *req, + void *context); + +/** + * wlan_twt_ac_pdev_param_send() - pdev TWT param send + * @psoc: Pointer to psoc object + * @twt_ac: TWT access category + * + * Return: QDF Status + */ +QDF_STATUS wlan_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac); + +/** + * wlan_twt_is_setup_in_progress() - Get if TWT setup command is in progress + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: True if Setup is in progress + */ +bool +wlan_twt_is_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * wlan_twt_setup_complete_event_handler() - twt setup complete event handler + * @psoc: Pointer to global psoc object + * @event: add dialog event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_setup_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event); + +/** + * wlan_twt_ack_event_handler() - ack complete event handler + * @psoc: Pointer to global psoc object + * @event: ack complete event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_ack_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *event); + +/** + * wlan_twt_teardown_complete_event_handler() - teardown complete event handler + * @psoc: Pointer to global psoc object + * @event: del complete event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_teardown_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event); + +/** + * wlan_twt_pause_complete_event_handler() - pause complete event handler + * @psoc: Pointer to global psoc object + * @event: pause complete event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_pause_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event); + +/** + * wlan_twt_resume_complete_event_handler() - resume complete event handler + * @psoc: Pointer to global psoc object + * @event: resume complete event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_resume_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event); + +/** + * wlan_twt_nudge_complete_event_handler() - nudge complete event handler + * @psoc: Pointer to global psoc object + * @event: nudge complete event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_nudge_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event); + +/** + * wlan_twt_notify_event_handler() - notify event handler + * @psoc: Pointer to global psoc object + * @event: notify complete event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_notify_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event); + +/** + * wlan_twt_init_context() - Initialize TWT context structure + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_init_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * wlan_twt_update_beacon_template() - update beacon template + * + * SoftAP (SAP) is the beaconing entity, as per current requirement + * during Single Channel Concurrency (SCC) or Multi-Channel Concurrency (MCC) + * TWT is not supported on STA as well as SAP. + * + * Whenever SAP is forming SCC/MCC, this function shall be called to update the + * beacon, underlying LIM layer based the TWT responder flag, it disables the + * TWT responder advertisement bit in the beacon. + * + * When SAP moves from SCC/MCC to Standalone, this function shall be called + * to update the beacon, underlying LIM layer based the TWT responder flag, + * it enables the TWT responder advertisement bit in the beacon. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_twt_update_beacon_template(void); + +/** + * wlan_twt_is_setup_done() - Check if TWT setup exists for a given dialog id + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: true if TWT setup exists, false otherwise + */ +bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); + +/** + * wlan_twt_get_session_state() - Get TWT session state + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: enum wlan_twt_session_state + */ +enum wlan_twt_session_state +wlan_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); + +/** + * wlan_twt_is_command_in_progress() - Check if given command is in progress + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * @pactive_cmd: Fill the active command in this output parameter + * + * Return: True if given command is in progress. + */ +bool wlan_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd); + +/** + * wlan_twt_set_work_params() - Set TWT work params + * @vdev: vdev pointer + * @peer_mac: mac address of peer + * @dialog_id: dialog_id of TWT session + * @is_ps_disabled: Whether power save is disabled or not + * @twt_next_action: Set next action to do before work scheduled + * + * Return: None + */ +void wlan_twt_set_work_params( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + bool is_ps_disabled, + uint32_t twt_next_action); + +/** + * wlan_twt_get_work_params() - Get TWT work params + * @vdev: vdev pointer + * @params: pointer to TWT work params + * @next_action: Get next action to do after work scheduled + * + * Return: None + */ +void wlan_twt_get_work_params(struct wlan_objmgr_vdev *vdev, + struct twt_work_params *params, + uint32_t *next_action); +#else + +static inline bool +wlan_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return true; +} + +static inline QDF_STATUS +wlan_twt_set_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *req, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *req, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *req, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_nudge_req(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *req, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_twt_is_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return true; +} + +static inline QDF_STATUS +wlan_twt_setup_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_ack_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_teardown_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_pause_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_resume_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_nudge_complete_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_notify_event_handler(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_init_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS wlan_twt_update_beacon_template(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool wlan_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return true; +} + +static inline +enum wlan_twt_session_state +wlan_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + +static inline +bool wlan_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd) +{ + return true; +} + +static inline +void wlan_twt_set_work_params( + struct wlan_objmgr_vdev *vdev, + struct twt_add_dialog_complete_event_param *params, + uint32_t twt_next_action) +{ +} + +static inline +void wlan_twt_get_work_params(struct wlan_objmgr_vdev *vdev, + struct twt_work_params *params, + uint32_t *next_action) +{ +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/cfg_twt.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/cfg_twt.h new file mode 100644 index 0000000000..d7f2235d10 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/cfg_twt.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains TWT config related definitions + */ + +#ifndef __CFG_TWT_H_ +#define __CFG_TWT_H_ + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/* + * + * twt_requestor - twt requestor. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This cfg is used to store twt requestor config. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal + * + * + */ +#define CFG_TWT_REQUESTOR CFG_INI_BOOL( \ + "twt_requestor", \ + 1, \ + "TWT requestor") +/* + * + * twt_responder - twt responder. + * @Min: 0 + * @Max: 1 + * @Default: false + * + * This cfg is used to store twt responder config. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: Internal + * + * + */ +#define CFG_TWT_RESPONDER CFG_INI_BOOL( \ + "twt_responder", \ + false, \ + "TWT responder") + +/* + * + * enable_twt - Enable Target Wake Time support. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable or disable TWT support. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_ENABLE_TWT CFG_INI_BOOL( \ + "enable_twt", \ + 1, \ + "TWT support") + +/* + * + * twt_congestion_timeout - Target wake time congestion timeout. + * @Min: 0 + * @Max: 10000 + * @Default: 100 + * + * STA uses this timer to continuously monitor channel congestion levels to + * decide whether to start or stop TWT. This ini is used to configure the + * target wake time congestion timeout value in the units of milliseconds. + * A value of Zero indicates that this is a host triggered TWT and all the + * necessary configuration for TWT will be directed from the host. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_TWT_CONGESTION_TIMEOUT CFG_INI_UINT( \ + "twt_congestion_timeout", \ + 0, \ + 10000, \ + 100, \ + CFG_VALUE_OR_DEFAULT, \ + "twt congestion timeout") +/* + * + * twt_bcast_req_resp_config - To enable broadcast twt requestor and responder. + * @Min: 0 Disable the extended twt capability + * @Max: 3 + * @Default: 1 + * + * This cfg is used to configure the broadcast TWT requestor and responder. + * Bitmap for enabling the broadcast twt requestor and responder. + * BIT 0: Enable/Disable broadcast twt requestor. + * BIT 1: Enable/Disable broadcast twt responder. + * BIT 2-31: Reserved + * + * Related: CFG_ENABLE_TWT + * Related: CFG_TWT_RESPONDER + * Related: CFG_TWT_REQUESTOR + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +/* defines to extract the requestor/responder capabilities from cfg */ +#define TWT_BCAST_REQ_INDEX 0 +#define TWT_BCAST_REQ_BITS 1 +#define TWT_BCAST_RES_INDEX 1 +#define TWT_BCAST_RES_BITS 1 + +#define CFG_BCAST_TWT_REQ_RESP CFG_INI_UINT( \ + "twt_bcast_req_resp_config", \ + 0, \ + 3, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "BROADCAST TWT CAPABILITY") + +#define CFG_TWT_GET_BCAST_REQ(_bcast_conf) \ + QDF_GET_BITS(_bcast_conf, \ + TWT_BCAST_REQ_INDEX, \ + TWT_BCAST_REQ_BITS) + +#define CFG_TWT_GET_BCAST_RES(_bcast_conf) \ + QDF_GET_BITS(_bcast_conf, \ + TWT_BCAST_RES_INDEX, \ + TWT_BCAST_RES_BITS) + +/* + * + * rtwt_req_resp_config - To enable restricted twt requestor and responder. + * @Min: 0 Disable the extended twt capability + * @Max: 3 + * @Default: 0 + * + * This cfg is used to configure the restricted TWT requestor and responder. + * Bitmap for enabling the restricted twt requestor and responder. + * BIT 0: Enable/Disable restricted twt requestor. + * BIT 1: Enable/Disable restricted twt responder. + * BIT 2-31: Reserved + * + * Related: CFG_ENABLE_TWT + * Related: CFG_TWT_RESPONDER + * Related: CFG_TWT_REQUESTOR + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +/* defines to extract the requestor/responder capabilities from cfg */ +#define RTWT_REQ_INDEX 0 +#define RTWT_REQ_BITS 1 +#define RTWT_RES_INDEX 1 +#define RTWT_RES_BITS 1 + +#define CFG_RTWT_REQ_RESP CFG_INI_UINT( \ + "rtwt_req_resp_config", \ + 0, \ + 3, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "RESTRICTED TWT CAPABILITY") + +#define CFG_GET_RTWT_REQ(_rtwt_conf) \ + QDF_GET_BITS(_rtwt_conf, \ + RTWT_REQ_INDEX, \ + RTWT_REQ_BITS) + +#define CFG_GET_RTWT_RES(_rtwt_conf) \ + QDF_GET_BITS(_rtwt_conf, \ + RTWT_RES_INDEX, \ + RTWT_RES_BITS) + +/* + * + * enable_twt_24ghz - Enable Target wake time when STA is connected on 2.4Ghz + * band. + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable/disable the host TWT when STA is connected to AP + * in 2.4Ghz band. + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_ENABLE_TWT_24GHZ CFG_INI_BOOL( \ + "enable_twt_24ghz", \ + true, \ + "enable twt in 2.4Ghz band") +/* + * + * twt_disable_info - Enable/Disable TWT info frame. + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable TWT Info frame + * + * Related: NA + * + * Supported Feature: 11AX + * + * Usage: External + * + * + */ +#define CFG_DISABLE_TWT_INFO_FRAME CFG_INI_BOOL( \ + "twt_disable_info", \ + false, \ + "disable twt info frame") + +#define CFG_HE_FLEX_TWT_SCHED CFG_BOOL( \ + "he_flex_twt_sched", \ + 0, \ + "HE Flex Twt Sched") + +/* + * + * enable_twt_in_11n - Enable TWT support in 11n mode + * @MIN: 0 + * @MAX: 1 + * @Default: 0 + * + * This ini is used to enable/disable TWT support 11n mode. + * Generally by default TWT support present from HE capable + * devices but if this ini is enabled then it will support + * partially from 11n mode itself. + * + * Related: NA + * + * Usage: External + * + * + */ +#define CFG_TWT_ENABLE_IN_11N CFG_INI_BOOL( \ + "enable_twt_in_11n", \ + false, \ + "enable twt support in 11n mode") + +#define CFG_TWT_ALL \ + CFG(CFG_ENABLE_TWT) \ + CFG(CFG_TWT_REQUESTOR) \ + CFG(CFG_TWT_RESPONDER) \ + CFG(CFG_TWT_CONGESTION_TIMEOUT) \ + CFG(CFG_BCAST_TWT_REQ_RESP) \ + CFG(CFG_ENABLE_TWT_24GHZ) \ + CFG(CFG_DISABLE_TWT_INFO_FRAME) \ + CFG(CFG_TWT_ENABLE_IN_11N) \ + CFG(CFG_RTWT_REQ_RESP) +#elif !defined(WLAN_SUPPORT_TWT) && !defined(WLAN_TWT_CONV_SUPPORTED) +#define CFG_TWT_ALL +#endif +#endif /* __CFG_TWT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_cfg_ext_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_cfg_ext_api.h new file mode 100644 index 0000000000..8a2491a61c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_cfg_ext_api.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_TWT_CFG_EXT_API_H +#define _WLAN_TWT_CFG_EXT_API_H + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +#include +#include +#include + +/** + * wlan_twt_cfg_get_req_flag() - Get TWT requestor flag + * @psoc: Pointer to global psoc object + * @val: pointer to output variable + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS +wlan_twt_cfg_get_req_flag(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_res_flag() - Get TWT responder flag + * @psoc: Pointer to global psoc object + * @val: pointer to output variable + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS +wlan_twt_cfg_get_res_flag(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_cfg_get_support_in_11n() - Get TWT support on HT cap + * @psoc: Pointer to global psoc object + * @val: pointer to output variable + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS +wlan_twt_cfg_get_support_in_11n(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * wlan_twt_cfg_get_support_requestor() - Get TWT support of requestor + * @psoc: Pointer to global psoc object + * @val: pointer to output variable + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS +wlan_twt_cfg_get_support_requestor(struct wlan_objmgr_psoc *psoc, + bool *val); + +/** + * wlan_twt_get_requestor_cfg() - Get requestor TWT configuration + * @psoc: Pointer to psoc object + * @val: Pointer to value + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_get_requestor_cfg(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_get_responder_cfg() - Get TWT responder configuration + * @psoc: Pointer to PSOC object + * @val: Pointer to value + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_get_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_get_rtwt_support() - Get rTWT support + * @psoc: Pointer to global psoc + * @val: pointer to output variable + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_get_rtwt_support(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_get_bcast_requestor_cfg() - Get requestor broadcast TWT + * configuration + * @psoc: Pointer to psoc object + * @val: Pointer to value + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_twt_get_bcast_requestor_cfg(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_twt_get_bcast_responder_cfg() - Get responder broadcast TWT + * configuration + * @psoc: Pointer to psoc object + * @val: Pointer to value + * + * Return: QDF_STATUS + */ + +QDF_STATUS +wlan_twt_get_bcast_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val); + +#ifdef FEATURE_SET +/** + * wlan_twt_get_feature_info() - Get TWT feature set information + * @psoc: Pointer to global psoc object + * @twt_feature_set: pointer to output twt feature set structure + * + * Return: None + */ +void wlan_twt_get_feature_info(struct wlan_objmgr_psoc *psoc, + struct wlan_twt_features *twt_feature_set); +#endif + +#else +static inline QDF_STATUS +wlan_twt_cfg_get_res_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_req_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_support_in_11n(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_cfg_get_support_requestor(struct wlan_objmgr_psoc *psoc, + bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_get_requestor_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_get_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_get_bcast_requestor_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wlan_twt_get_bcast_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_SET +static inline void +wlan_twt_get_feature_info(struct wlan_objmgr_psoc *psoc, + struct wlan_twt_features *twt_feature_set) +{ +} +#endif +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ext_defs.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ext_defs.h new file mode 100644 index 0000000000..af82e5906d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ext_defs.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_twt_ext_defs.h + * + * This file provide definition for structure/enums/defines related to + * twt component + */ + +#ifndef __WLAN_TWT_EXT_DEFS_H__ +#define __WLAN_TWT_EXT_DEFS_H__ + +/* + * struct twt_mc_cfg_params - All twt related cfg items + * @enable_twt: global twt configuration + * @twt_responder: twt responder enable/disable + * @twt_requestor: twt requestor enable/disable + * @twt_congestion_timeout: congestion timeout value + * @bcast_requestor_enabled: bcast requestor enable/disable + * @bcast_responder_enabled: bcast responder enable/disable + * @enable_twt_24ghz: Enable/disable host TWT when STA is connected in + * 2.4Ghz + * @flex_twt_sched: flex twt scheduling enable/disable + * @req_flag: requestor flag enable/disable + * @res_flag: responder flag enable/disable + * @is_twt_enabled_in_11n: Enable TWT support in 11n mode + * @rtwt_requestor_enabled: Restricted TWT requestor enable or disable + * @rtwt_responder_enabled: Restricted TWT responder enable or disable + */ +struct twt_mc_cfg_params { + bool enable_twt; + bool twt_responder; + bool twt_requestor; + uint32_t twt_congestion_timeout; + bool bcast_requestor_enabled; + bool bcast_responder_enabled; + bool enable_twt_24ghz; + bool flex_twt_sched; + bool req_flag; + bool res_flag; + bool is_twt_enabled_in_11n; + bool rtwt_requestor_enabled; + bool rtwt_responder_enabled; +}; + +#endif /* __WLAN_TWT_EXT_DEFS_H__ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ext_type.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ext_type.h new file mode 100644 index 0000000000..3379b7f4b6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ext_type.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_twt_ext_type.h + * + * This header file is included by the converged twt + * component to map legacy structures to the external + * (ext)typedefs used by the converged code. + */ + +#ifndef __WLAN_TWT_EXT_TYPE_H__ +#define __WLAN_TWT_EXT_TYPE_H__ + +/** + * typedef psoc_twt_ext_cfg_params_t - Definition of psoc twt cfg params + * Define twt cfg params from external umac/twt component point to this type + */ +typedef struct twt_mc_cfg_params psoc_twt_ext_cfg_params_t; + +#endif /* __WLAN_TWT_EXT_TYPE_H__ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_tgt_if_ext_tx_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_tgt_if_ext_tx_api.h new file mode 100644 index 0000000000..56742e8557 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_tgt_if_ext_tx_api.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_twt_tgt_if_ext_tx_api.h + * + * API declarations to send WMI command using Tx Ops + */ +#ifndef _WLAN_TWT_TGT_IF_EXT_TX_API_H_ +#define _WLAN_TWT_TGT_IF_EXT_TX_API_H_ + +/** + * tgt_twt_setup_req_send() - Send twt setup request + * @psoc: Pointer to psoc object + * @req: TWT setup request + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_twt_setup_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *req); + +/** + * tgt_twt_teardown_req_send() - Send twt teardown request + * @psoc: Pointer to psoc object + * @req: TWT setup request + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_twt_teardown_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req); + +/** + * tgt_twt_pause_req_send() - Send twt pause request + * @psoc: Pointer to psoc object + * @req: TWT pause request + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_twt_pause_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *req); + +/** + * tgt_twt_resume_req_send() - Send twt resume request + * @psoc: Pointer to psoc object + * @req: TWT resume request + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_twt_resume_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *req); + +/** + * tgt_twt_nudge_req_send() - Send twt nudge request + * @psoc: Pointer to psoc object + * @req: TWT nudge request + * + * Return: QDF_STATUS + */ +QDF_STATUS +tgt_twt_nudge_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *req); + +/** + * tgt_twt_ac_pdev_param_send() - pdev TWT param send + * @psoc: Pointer to psoc object + * @twt_ac: TWT access category + * + * Return: QDF Status + */ +QDF_STATUS +tgt_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h new file mode 100644 index 0000000000..059d7ae7f6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/inc/wlan_twt_ucfg_ext_api.h @@ -0,0 +1,452 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_TWT_UCFG_EXT_API_H +#define _WLAN_TWT_UCFG_EXT_API_H + + +#include +#include +#include + +/* dialog_id used to get all peer's twt session parameters */ +#define TWT_GET_ALL_PEER_PARAMS_DIALOG_ID (0xFF) + +/* Valid dialog_id 0 to (0xFF - 1) */ +#define TWT_MAX_DIALOG_ID (TWT_GET_ALL_PEER_PARAMS_DIALOG_ID - 1) + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/** + * ucfg_twt_psoc_open() - TWT psoc open + * @psoc: Pointer to global PSOC object + * + * Upon psoc open, this function initializes the twt config params + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ucfg_twt_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_twt_psoc_close() - TWT psoc close + * @psoc: Pointer to global PSOC object + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ucfg_twt_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_twt_update_psoc_config() - TWT update config + * @psoc: Pointer to global PSOC object + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ucfg_twt_update_psoc_config(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_twt_setup_req() - TWT setup + * @psoc: Pointer to global PSOC object + * @params: add dialog params + * @context: twt context + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ucfg_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *params, + void *context); + +/** + * ucfg_twt_teardown_req() - TWT teardown + * @psoc: Pointer to global PSOC object + * @params: delete dialog params + * @context: twt context + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ucfg_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *params, + void *context); + +/** + * ucfg_twt_pause_req() - Process TWT pause req + * @psoc: psoc + * @params: pause dialog cmd param + * @context: context + * + * Perform validations and set WLAN_TWT_SUSPEND + * in progress + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *params, + void *context); + +/** + * ucfg_twt_resume_req() - Process TWT resume req + * @psoc: psoc + * @params: resume dialog cmd param + * @context: context + * + * Perform validations and set WLAN_TWT_RESUME + * in progress + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *params, + void *context); + +/** + * ucfg_twt_nudge_req() - Process TWT nudge req + * @psoc: psoc + * @params: nudge dialog cmd param + * @context: context + * + * Perform validations and set WLAN_TWT_NUDGE + * in progress + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_twt_nudge_req(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *params, + void *context); + +/** + * ucfg_twt_ac_pdev_param_send() - pdev TWT param send + * @psoc: Pointer to psoc object + * @twt_ac: TWT access category + * + * Return: QDF Status + */ +QDF_STATUS +ucfg_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac); + +/** + * ucfg_twt_is_max_sessions_reached() - Check if the maximum number of + * TWT sessions reached or not excluding the given dialog_id + * @psoc: Pointer to global PSOC object + * @peer_mac: Global peer mac address + * @dialog_id: dialog id + * + * Check if the number of active TWT sessions is equal to the maximum number + * of TWT sessions supported. Only count the TWT session slot if it not + * TWT_ALL_SESSIONS_DIALOG_ID and dialog id is different from input dialog_id, + * because if same dialog_id already exists in the TWT sessions, we should + * return false since re-negotiation is supported on existing dialog_id. + * + * Return: True if slot is available for dialog_id, false otherwise + */ +bool ucfg_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_twt_is_setup_in_progress() - Get if TWT setup command is in progress + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: True if Setup is in progress + */ +bool ucfg_twt_is_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_twt_cfg_is_twt_enabled() - Get if TWT is enabled + * @psoc: PSOC pointer + * + * Return: True if TWT is enabled + */ +bool ucfg_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_twt_set_command_in_progress() - Set TWT command is in progress + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * @cmd: TWT command + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_twt_set_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd); + +/** + * ucfg_twt_reset_active_command() - Reset active command to WLAN_TWT_NONE + * @psoc: Pointer to psoc object + * @peer_mac: Pointer to peer mac address + * @dialog_id: Dialog id + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_twt_reset_active_command(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_twt_init_context() - Initialize TWT context + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS +ucfg_twt_init_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_twt_set_osif_cb() - Set TWT osif callbacks + * @osif_twt_ops: pointer to global osif ops + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS +ucfg_twt_set_osif_cb(osif_twt_get_global_ops_cb osif_twt_ops); + +/** + * ucfg_twt_update_beacon_template() - update beacon template + * + * SoftAP (SAP) is the beaconing entity, as per current requirement + * during Single Channel Concurrency (SCC) or Multi-Channel Concurrency (MCC) + * TWT is not supported on STA as well as SAP. + * + * Whenever SAP is forming SCC/MCC, this function shall be called to update the + * beacon, underlying LIM layer based the TWT responder flag, it disables the + * TWT responder advertisement bit in the beacon. + * + * When SAP moves from SCC/MCC to Standalone, this function shall be called + * to update the beacon, underlying LIM layer based the TWT responder flag, + * it enables the TWT responder advertisement bit in the beacon. + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS ucfg_twt_update_beacon_template(void); + +/** + * ucfg_twt_is_setup_done() - check if TWT setup is done or not + * for given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: True if Setup is done, false otherwise + */ +bool +ucfg_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id); + +/** + * ucfg_twt_get_session_state() - get TWT session state for a given dialog id + * @psoc: Pointer to global psoc object + * @peer_mac: Global peer mac address + * @dialog_id: Dialog ID + * + * Return: TWT session state + */ +enum wlan_twt_session_state +ucfg_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id); + +bool ucfg_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd); + +/** + * ucfg_twt_set_work_params() - Set TWT work params + * @vdev: Vdev pointer + * @peer_mac: peer mac address + * @dialog_id: dialog_id + * @is_ps_disabled: Whether Power saave is disabled or not + * @twt_next_action: Set TWT next action to do before work schedule + * + * Return: None + */ +void ucfg_twt_set_work_params( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + bool is_ps_disabled, + uint32_t twt_next_action); + +/** + * ucfg_twt_get_work_params() - Get TWT work params + * @vdev: vdev pointer + * @params: TWT work params + * @next_action: Get TWT next action to do after work scheduled + * + * Return: None + */ +void ucfg_twt_get_work_params(struct wlan_objmgr_vdev *vdev, + struct twt_work_params *params, + uint32_t *next_action); + +/** + * ucfg_twt_cfg_set_responder() - Set TWT responder capability + * @psoc: Pointer to global PSOC object + * @val: pointer to value to be set + * + * Return: QDF_STATUS + */ +QDF_STATUS ucfg_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val); +/** + * ucfg_twt_get_pmo_allowed() - Get twt allowed + * @psoc: psoc handler + * + * Return: QDF_STATUS_SUCCESS + */ +bool ucfg_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc); +#else +static inline +QDF_STATUS ucfg_twt_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_twt_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_twt_update_psoc_config(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *params, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *params, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *params, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS ucfg_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *params, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_twt_init_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +ucfg_twt_set_osif_cb(osif_twt_get_global_ops_cb osif_twt_ops) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool +ucfg_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return false; +} + +static inline enum wlan_twt_session_state +ucfg_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; +} + +static inline bool +ucfg_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd) +{ + return false; +} + +static inline void +ucfg_twt_set_work_params( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + bool is_ps_disabled, + uint32_t twt_next_action) +{ +} + +static inline void +ucfg_twt_get_work_params( + struct wlan_objmgr_vdev *vdev, + struct twt_work_params *params, + uint32_t *next_action) +{ +} + +static inline +QDF_STATUS ucfg_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool ucfg_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +static inline +bool ucfg_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} + +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_cfg_ext_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_cfg_ext_api.c new file mode 100644 index 0000000000..42f58e1770 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_cfg_ext_api.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include "twt/core/src/wlan_twt_cfg.h" +#include "wlan_mlme_api.h" + +QDF_STATUS +wlan_twt_cfg_get_req_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_requestor_flag(psoc, val); +} + +QDF_STATUS +wlan_twt_cfg_get_res_flag(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_responder_flag(psoc, val); +} + +QDF_STATUS +wlan_twt_cfg_get_support_in_11n(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_support_in_11n_mode(psoc, val); +} + +QDF_STATUS +wlan_twt_get_requestor_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_requestor(psoc, val); +} + +QDF_STATUS +wlan_twt_get_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_responder(psoc, val); +} + +QDF_STATUS +wlan_twt_cfg_get_support_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_requestor(psoc, val); +} + +QDF_STATUS +wlan_twt_get_rtwt_support(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_get_restricted_support(psoc, val); +} + +QDF_STATUS +wlan_twt_get_bcast_requestor_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_bcast_requestor(psoc, val); +} + +QDF_STATUS +wlan_twt_get_bcast_responder_cfg(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_bcast_responder(psoc, val); +} + +#ifdef FEATURE_SET +void wlan_twt_get_feature_info(struct wlan_objmgr_psoc *psoc, + struct wlan_twt_features *twt_feature_set) +{ + twt_feature_set->enable_twt = wlan_twt_cfg_is_twt_enabled(psoc); + if (twt_feature_set->enable_twt) { + wlan_twt_cfg_get_bcast_requestor( + psoc, + &twt_feature_set->enable_twt_broadcast); + wlan_twt_cfg_get_requestor( + psoc, + &twt_feature_set->enable_twt_requester); + twt_feature_set->enable_twt_flexible = true; + } +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_rx_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_rx_api.c new file mode 100644 index 0000000000..889b6e18e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_rx_api.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_twt_tgt_if_ext_rx_api.c + * + * This file provide definition for APIs registered for LMAC TWT Rx Ops + */ +#include +#include +#include +#include +#include "twt/core/src/wlan_twt_main.h" + +static QDF_STATUS +tgt_twt_setup_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + return wlan_twt_setup_complete_event_handler(psoc, event); +} + +static QDF_STATUS +tgt_twt_teardown_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + return wlan_twt_teardown_complete_event_handler(psoc, event); +} + +static QDF_STATUS +tgt_twt_pause_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event) +{ + return wlan_twt_pause_complete_event_handler(psoc, event); +} + +static QDF_STATUS +tgt_twt_resume_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event) +{ + return wlan_twt_resume_complete_event_handler(psoc, event); +} + +static QDF_STATUS +tgt_twt_nudge_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event) +{ + return wlan_twt_nudge_complete_event_handler(psoc, event); +} + +static QDF_STATUS +tgt_twt_notify_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event) +{ + return wlan_twt_notify_event_handler(psoc, event); +} + +static QDF_STATUS +tgt_twt_ack_complete_resp_handler(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *event) +{ + return wlan_twt_ack_event_handler(psoc, event); +} + +void tgt_twt_register_ext_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops) +{ + struct wlan_lmac_if_twt_rx_ops *twt_rx_ops = &rx_ops->twt_rx_ops; + + twt_rx_ops->twt_setup_comp_cb = tgt_twt_setup_complete_resp_handler; + twt_rx_ops->twt_teardown_comp_cb = + tgt_twt_teardown_complete_resp_handler; + twt_rx_ops->twt_pause_comp_cb = tgt_twt_pause_complete_resp_handler; + twt_rx_ops->twt_resume_comp_cb = tgt_twt_resume_complete_resp_handler; + twt_rx_ops->twt_nudge_comp_cb = tgt_twt_nudge_complete_resp_handler; + twt_rx_ops->twt_notify_comp_cb = tgt_twt_notify_complete_resp_handler; + twt_rx_ops->twt_ack_comp_cb = tgt_twt_ack_complete_resp_handler; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_tx_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_tx_api.c new file mode 100644 index 0000000000..1a00857577 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_tx_api.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_twt_tgt_if_ext_tx_api.c + * + * This file provides definitions for twt tgt_if APIs, which will + * further call target_if component using LMAC TWT txops + */ +#include +#include +#include +#include +#include +#include + +QDF_STATUS +tgt_twt_setup_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *req) +{ + struct wlan_lmac_if_twt_tx_ops *tx_ops; + QDF_STATUS status; + + if (!psoc) { + twt_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + if (!req) { + twt_err("Invalid input"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_twt_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->setup_req) { + twt_err("setup_req tx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = tx_ops->setup_req(psoc, req); + + return status; +} + +QDF_STATUS +tgt_twt_teardown_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *req) +{ + struct wlan_lmac_if_twt_tx_ops *tx_ops; + QDF_STATUS status; + + if (!psoc) { + twt_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + if (!req) { + twt_err("Invalid input"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_twt_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->teardown_req) { + twt_err("teardown_req tx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = tx_ops->teardown_req(psoc, req); + + return status; +} + +QDF_STATUS +tgt_twt_pause_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *req) +{ + struct wlan_lmac_if_twt_tx_ops *tx_ops; + QDF_STATUS status; + + if (!psoc) { + twt_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + if (!req) { + twt_err("Invalid input"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_twt_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->pause_req) { + twt_err("pause tx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = tx_ops->pause_req(psoc, req); + + return status; +} + +QDF_STATUS +tgt_twt_resume_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *req) +{ + struct wlan_lmac_if_twt_tx_ops *tx_ops; + QDF_STATUS status; + + if (!psoc) { + twt_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + if (!req) { + twt_err("Invalid input"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_twt_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->resume_req) { + twt_err("resume tx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = tx_ops->resume_req(psoc, req); + + return status; +} + +QDF_STATUS +tgt_twt_nudge_req_send(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *req) +{ + struct wlan_lmac_if_twt_tx_ops *tx_ops; + QDF_STATUS status; + + if (!psoc) { + twt_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + if (!req) { + twt_err("Invalid input"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_twt_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->nudge_req) { + twt_err("nudge tx_ops is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = tx_ops->nudge_req(psoc, req); + + return status; +} + +QDF_STATUS +tgt_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac) +{ + struct wlan_lmac_if_twt_tx_ops *tx_ops; + QDF_STATUS status; + + if (!psoc) { + twt_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + tx_ops = wlan_twt_get_tx_ops(psoc); + if (!tx_ops || !tx_ops->set_ac_param) { + twt_err("set_ac_param is null"); + status = QDF_STATUS_E_NULL_VALUE; + return status; + } + + status = tx_ops->set_ac_param(psoc, twt_ac, 0); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c new file mode 100644 index 0000000000..63a271958b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include "twt/core/src/wlan_twt_cfg.h" +#include "twt/core/src/wlan_twt_main.h" + +QDF_STATUS ucfg_twt_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return wlan_twt_cfg_init(psoc); +} + +QDF_STATUS ucfg_twt_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return wlan_twt_cfg_deinit(psoc); +} + +QDF_STATUS ucfg_twt_update_psoc_config(struct wlan_objmgr_psoc *psoc) +{ + return wlan_twt_cfg_update(psoc); +} + +QDF_STATUS +ucfg_twt_cfg_get_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_requestor(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_get_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_responder(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_set_responder(struct wlan_objmgr_psoc *psoc, bool val) +{ + return wlan_twt_cfg_set_responder(psoc, val); +} + +QDF_STATUS +ucfg_twt_setup_req(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *params, + void *context) +{ + return wlan_twt_setup_req(psoc, params, context); +} + +QDF_STATUS ucfg_twt_teardown_req(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *params, + void *context) +{ + return wlan_twt_teardown_req(psoc, params, context); +} + +QDF_STATUS +ucfg_twt_pause_req(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *params, + void *context) +{ + return wlan_twt_pause_req(psoc, params, context); +} + +QDF_STATUS +ucfg_twt_resume_req(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *params, + void *context) +{ + return wlan_twt_resume_req(psoc, params, context); +} + +QDF_STATUS +ucfg_twt_nudge_req(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *params, + void *context) +{ + return wlan_twt_nudge_req(psoc, params, context); +} + +QDF_STATUS +ucfg_twt_ac_pdev_param_send(struct wlan_objmgr_psoc *psoc, + enum twt_traffic_ac twt_ac) +{ + return wlan_twt_ac_pdev_param_send(psoc, twt_ac); +} + +bool ucfg_twt_is_max_sessions_reached(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return wlan_twt_is_max_sessions_reached(psoc, peer_mac, dialog_id); +} + +bool ucfg_twt_is_setup_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return wlan_twt_is_setup_in_progress(psoc, peer_mac, dialog_id); +} + +bool ucfg_twt_cfg_is_twt_enabled(struct wlan_objmgr_psoc *psoc) +{ + return wlan_twt_cfg_is_twt_enabled(psoc); +} + +QDF_STATUS +ucfg_twt_cfg_get_congestion_timeout(struct wlan_objmgr_psoc *psoc, + uint32_t *val) +{ + return wlan_twt_cfg_get_congestion_timeout(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_set_congestion_timeout(struct wlan_objmgr_psoc *psoc, uint32_t val) +{ + return wlan_twt_cfg_set_congestion_timeout(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_get_24ghz_enabled(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_24ghz_enabled(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_get_bcast_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_bcast_requestor(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_get_bcast_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_bcast_responder(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_get_rtwt_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_rtwt_requestor(psoc, val); +} + +QDF_STATUS +ucfg_twt_cfg_get_flex_sched(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return wlan_twt_cfg_get_flex_sched(psoc, val); +} + +QDF_STATUS +ucfg_twt_init_context(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return wlan_twt_init_context(psoc, peer_mac, dialog_id); +} + +QDF_STATUS +ucfg_twt_set_osif_cb(osif_twt_get_global_ops_cb osif_twt_ops) +{ + mlme_set_osif_twt_cb(osif_twt_ops); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ucfg_twt_set_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + return wlan_twt_set_command_in_progress(psoc, peer_mac, + dialog_id, cmd); +} + +QDF_STATUS +ucfg_twt_reset_active_command(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + return wlan_twt_set_command_in_progress(psoc, peer_mac, dialog_id, + WLAN_TWT_NONE); +} + +QDF_STATUS ucfg_twt_update_beacon_template(void) +{ + return wlan_twt_update_beacon_template(); +} + +bool +ucfg_twt_is_setup_done(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return wlan_twt_is_setup_done(psoc, peer_mac, dialog_id); +} + +enum wlan_twt_session_state +ucfg_twt_get_session_state(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id) +{ + return wlan_twt_get_session_state(psoc, peer_mac, dialog_id); +} + +bool ucfg_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd, + enum wlan_twt_commands *pactive_cmd) +{ + return wlan_twt_is_command_in_progress(psoc, peer_mac, dialog_id, cmd, + pactive_cmd); +} + +void ucfg_twt_set_work_params( + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + bool is_ps_disabled, + uint32_t twt_next_action) +{ + return wlan_twt_set_work_params(vdev, peer_mac, dialog_id, + is_ps_disabled, twt_next_action); +} + +void ucfg_twt_get_work_params( + struct wlan_objmgr_vdev *vdev, + struct twt_work_params *params, + uint32_t *next_action) +{ + return wlan_twt_get_work_params(vdev, params, next_action); +} + +bool ucfg_twt_get_pmo_allowed(struct wlan_objmgr_psoc *psoc) +{ + return wlan_twt_get_pmo_allowed(psoc); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/core/inc/wlan_wifi_pos_interface.h b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/core/inc/wlan_wifi_pos_interface.h new file mode 100644 index 0000000000..014d81cbfc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/core/inc/wlan_wifi_pos_interface.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare WIFI POS interface APIs exposed by the mlme component + */ + +#ifndef _WLAN_WIFI_POS_IFACE_API_H_ +#define _WLAN_WIFI_POS_IFACE_API_H_ + +#include +#include "lim_types.h" +#include "wifi_pos_pasn_api.h" + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +/** + * wlan_wifi_pos_pasn_peer_delete_all - Delete all pasn peer callback + * @psoc: Psoc pointer + * @vdev_id: vdev for which PASN peers are to be deleted + * + * Return: True if PASN peer delete all is required + */ +bool wlan_wifi_pos_pasn_peer_delete_all(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * wifi_pos_register_legacy_ops() - Register wifi pos legacy callbacks + * @psoc: Psoc pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wifi_pos_register_legacy_ops(struct wlan_objmgr_psoc *psoc); + +/** + * wifi_pos_deregister_legacy_ops() - Deregister wifi pos legacy callbacks + * @psoc: Psoc pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wifi_pos_deregister_legacy_ops(struct wlan_objmgr_psoc *psoc); +#else +static inline QDF_STATUS +wifi_pos_register_legacy_ops(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wifi_pos_deregister_legacy_ops(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool +wlan_wifi_pos_pasn_peer_delete_all(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return false; +} +#endif +#endif /* _WLAN_WIFI_POS_IFACE_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/core/src/wlan_wifi_pos_interface.c b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/core/src/wlan_wifi_pos_interface.c new file mode 100644 index 0000000000..6fff520bd7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/core/src/wlan_wifi_pos_interface.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: define internal APIs related to the mlme component, legacy APIs are + * called for the time being, but will be cleaned up after convergence + */ +#include "wifi_pos_api.h" +#include "wlan_wifi_pos_interface.h" +#include "wma_pasn_peer_api.h" + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +/** + * wlan_wifi_pos_pasn_peer_create() - Callback to create ranging peer + * @psoc: Pointer to PSOC + * @peer_addr: Address of the peer for which PASN peer is to be created + * @vdev_id: Vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_wifi_pos_pasn_peer_create(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id) +{ + return wma_pasn_peer_create(psoc, peer_addr, vdev_id); +} + +/** + * wlan_wifi_pos_pasn_peer_delete() - Callback to delete ranging peer + * @psoc: Pointer to PSOC + * @peer_addr: Address of the peer for which PASN peer is to be deleted + * @vdev_id: Vdev id + * @no_fw_peer_delete: if true do not seend peer delete to firmware + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_wifi_pos_pasn_peer_delete(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id, + bool no_fw_peer_delete) +{ + return wma_pasn_peer_remove(psoc, peer_addr, vdev_id, + no_fw_peer_delete); +} + +/** + * wlan_wifi_pos_vdev_delete_resume() - Resume vdev delete operation + * after deleting all pasn peers + * @vdev: Pointer to objmgr vdev + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_wifi_pos_vdev_delete_resume(struct wlan_objmgr_vdev *vdev) +{ + return wma_pasn_peer_delete_all_complete(vdev); +} + +bool +wlan_wifi_pos_pasn_peer_delete_all(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct pasn_peer_delete_msg *req; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_WIFI_POS_TGT_IF_ID); + if (!vdev) { + mlme_err("Vdev is not found for id:%d", vdev_id); + return false; + } + + if (!(vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE || + vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_TGT_IF_ID); + return false; + } + + if (!wifi_pos_get_pasn_peer_count(vdev) || + wifi_pos_is_delete_all_peer_in_progress(vdev)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_TGT_IF_ID); + return false; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_TGT_IF_ID); + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return false; + + req->vdev_id = vdev_id; + + msg.type = WIFI_POS_PASN_PEER_DELETE_ALL; + msg.bodyptr = req; + + status = scheduler_post_message(QDF_MODULE_ID_WIFIPOS, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(req); + mlme_err("Delete all pasn peers failed"); + return false; + } + + return true; +} + +static struct wifi_pos_legacy_ops wifi_pos_ops = { + .pasn_peer_create_cb = wlan_wifi_pos_pasn_peer_create, + .pasn_peer_delete_cb = wlan_wifi_pos_pasn_peer_delete, + .pasn_vdev_delete_resume_cb = wlan_wifi_pos_vdev_delete_resume, +}; + +QDF_STATUS +wifi_pos_register_legacy_ops(struct wlan_objmgr_psoc *psoc) +{ + return wifi_pos_set_legacy_ops(psoc, &wifi_pos_ops); +} + +QDF_STATUS +wifi_pos_deregister_legacy_ops(struct wlan_objmgr_psoc *psoc) +{ + return wifi_pos_set_legacy_ops(psoc, NULL); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/dispatcher/inc/wifi_pos_ucfg_api.h b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/dispatcher/inc/wifi_pos_ucfg_api.h new file mode 100644 index 0000000000..109e782519 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/dispatcher/inc/wifi_pos_ucfg_api.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare WIFI POS ucfg APIs exposed by the mlme component + */ + +#ifndef _WLAN_WIFI_POS_UCFG_API_H_ +#define _WLAN_WIFI_POS_UCFG_API_H_ + +#include +#include "wma_if.h" +#include "wlan_wifi_pos_interface.h" +#include "os_if_wifi_pos_utils.h" + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +/** + * ucfg_wifi_pos_psoc_open - Wifi pos module PSOC open api + * @psoc: Pointer to PSOC object + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_wifi_pos_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * ucfg_wifi_pos_psoc_close - Wifi pos module PSOC close api + * @psoc: Pointer to PSOC object + * + * Return: QDF_STATUS + */ +QDF_STATUS +ucfg_wifi_pos_psoc_close(struct wlan_objmgr_psoc *psoc); +# +#else +static inline QDF_STATUS +ucfg_wifi_pos_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +ucfg_wifi_pos_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WIFI_POS_CONVERGED && WLAN_FEATURE_RTT_11AZ_SUPPORT */ +#endif /* _WLAN_WIFI_POS_UCFG_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/dispatcher/src/wifi_pos_ucfg_api.c b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/dispatcher/src/wifi_pos_ucfg_api.c new file mode 100644 index 0000000000..7c8cf2d423 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wifi_pos/dispatcher/src/wifi_pos_ucfg_api.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: declare WIFI POS ucfg APIs exposed by the mlme component + */ + +#include "wifi_pos_ucfg_api.h" +#include "wifi_pos_utils_i.h" +#include "os_if_wifi_pos_utils.h" + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +QDF_STATUS +ucfg_wifi_pos_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = osif_wifi_pos_register_ops(psoc); + if (QDF_IS_STATUS_ERROR(status)) + wifi_pos_err("Register OSIF ops failed"); + + status = wifi_pos_register_legacy_ops(psoc); + if (QDF_IS_STATUS_ERROR(status)) + wifi_pos_err("Set legacy ops failed"); + + return status; +} + +QDF_STATUS +ucfg_wifi_pos_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = wifi_pos_deregister_legacy_ops(psoc); + if (QDF_IS_STATUS_ERROR(status)) + wifi_pos_err("Set legacy ops failed"); + + status = osif_wifi_pos_deregister_ops(psoc); + if (QDF_IS_STATUS_ERROR(status)) + wifi_pos_err("Register OSIF ops failed"); + + return status; +} +#endif /* WIFI_POS_CONVERGED && WLAN_FEATURE_RTT_11AZ_SUPPORT */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_coap_api.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_coap_api.h new file mode 100644 index 0000000000..409061e937 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_coap_api.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to CoAP component. + */ + +#ifndef _WMI_UNIFIED_COAP_API_H_ +#define _WMI_UNIFIED_COAP_API_H_ + +#include + +#ifdef WLAN_FEATURE_COAP +/** + * wmi_unified_coap_add_pattern_cmd() - Add pattern for CoAP offload reply + * @wmi_handle: wmi handle + * @param: parameters for CoAP offload reply + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_add_pattern_cmd(wmi_unified_t wmi_handle, + struct coap_offload_reply_param *param) +{ + if (wmi_handle->ops->send_coap_add_pattern_cmd) + return wmi_handle->ops->send_coap_add_pattern_cmd(wmi_handle, + param); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_del_pattern_cmd() - Delete pattern for CoAP offload reply + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_del_pattern_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + if (wmi_handle->ops->send_coap_del_pattern_cmd) + return wmi_handle->ops->send_coap_del_pattern_cmd(wmi_handle, + vdev_id, pattern_id); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_add_keepalive_pattern_cmd() - Add pattern for CoAP offload + * periodic transmitting + * @wmi_handle: wmi handle + * @param: parameters for CoAP offload periodic transmitting + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_add_keepalive_pattern_cmd(wmi_unified_t wmi_handle, + struct coap_offload_periodic_tx_param *param) +{ + if (wmi_handle->ops->send_coap_add_keepalive_pattern_cmd) + return wmi_handle->ops->send_coap_add_keepalive_pattern_cmd( + wmi_handle, param); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_del_keepalive_pattern_cmd() - Delete pattern for CoAP + * offload periodic transmitting + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_del_keepalive_pattern_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint32_t pattern_id) +{ + if (wmi_handle->ops->send_coap_del_keepalive_pattern_cmd) + return wmi_handle->ops->send_coap_del_keepalive_pattern_cmd( + wmi_handle, vdev_id, pattern_id); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_cache_get() - Get cached CoAP messages + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_cache_get(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + if (wmi_handle->ops->send_coap_cache_get_cmd) + return wmi_handle->ops->send_coap_cache_get_cmd(wmi_handle, + vdev_id, pattern_id); + + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wmi_unified_coap_extract_buf_info() - extract CoAP buf info from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @info: Pointer to hold CoAP buf info + * + * The caller needs to free any possible nodes in info->info_list + * regardless of failure or success. + * + * Return: status of operation + */ +static inline QDF_STATUS +wmi_unified_coap_extract_buf_info(wmi_unified_t wmi_handle, void *evt_buf, + struct coap_buf_info *info) +{ + if (wmi_handle->ops->extract_coap_buf_info) { + return wmi_handle->ops->extract_coap_buf_info(wmi_handle, + evt_buf, + info); + } + + return QDF_STATUS_E_NOSUPPORT; +} +#endif +#endif /* _WMI_UNIFIED_ROAM_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_ll_sap_api.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_ll_sap_api.h new file mode 100644 index 0000000000..2eb116ed04 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_ll_sap_api.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_status.h" +#include "wlan_ll_sap_public_structs.h" +#include "wmi_unified_param.h" + +#ifdef WLAN_FEATURE_LL_LT_SAP +/** + * wmi_unified_audio_transport_switch_resp_send() - Send audio transport switch + * response to fw + * @wmi_hdl: WMI handle + * @req_type: Bearer switch request type + * @status: Status of the bearer switch request + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_audio_transport_switch_resp_send( + wmi_unified_t wmi_hdl, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status); + +/** + * wmi_extract_audio_transport_switch_req_event() - Extract audio transport + * switch request from fw + * @wmi_handle: WMI handle + * @event: WMI event from fw + * @len: Length of the event + * @req_type: Type of the bearer switch request from fw + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_audio_transport_switch_req_event( + wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + enum bearer_switch_req_type *req_type); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_mc_cp_stats_api.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_mc_cp_stats_api.h new file mode 100644 index 0000000000..9ba7e33500 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_mc_cp_stats_api.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implement API's specific to control path stats component. + */ + +#ifndef _WMI_UNIFIED_MC_CP_STATS_API_H_ +#define _WMI_UNIFIED_MC_CP_STATS_API_H_ + +#include + +/** + * wmi_extract_per_chain_rssi_stats() - extract rssi stats from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into rssi stats + * @rssi_stats: Pointer to hold rssi stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_per_chain_rssi_stats(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + struct wmi_host_per_chain_rssi_stats *rssi_stats); + +/** + * wmi_extract_peer_adv_stats() - extract advance (extd2) peer stats from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @peer_adv_stats: Pointer to hold extended peer stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_adv_stats(wmi_unified_t wmi_handle, void *evt_buf, + struct wmi_host_peer_adv_stats *peer_adv_stats); + +#ifdef WLAN_FEATURE_MIB_STATS +/** + * wmi_extract_mib_stats() - extract mib stats from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @mib_stats: pointer to hold mib stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_mib_stats(wmi_unified_t wmi_handle, void *evt_buf, + struct mib_stats_metrics *mib_stats); +#endif + +/** + * wmi_unified_peer_stats_request_send() - send peer stats request to fw + * @wmi_handle: wmi handle + * @param: pointer to peer stats request parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_peer_stats_request_send(wmi_unified_t wmi_handle, + struct peer_stats_request_params *param); + +/** + * wmi_extract_peer_stats_param() - extract all stats count from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @stats_param: Pointer to hold stats count + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_stats_param(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_stats_event *stats_param); + +/** + * wmi_extract_peer_stats_info() - extract peer stats info from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into beacon stats + * @peer_stats_info: Pointer to hold peer stats info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_stats_info(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info); + +/** + * wmi_extract_peer_tx_pkt_per_mcs() - extract peer tx packets per MCS + * from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index to tx packets per MCS for current peer + * @peer_stats_info: Pointer to hold peer stats info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_tx_pkt_per_mcs(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info); + +/** + * wmi_extract_peer_rx_pkt_per_mcs() - extract peer rx packets per MCS + * from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index to tx rate count for current peer + * @peer_stats_info: Pointer to hold peer stats info + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_peer_rx_pkt_per_mcs(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info); + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/** + * wmi_extract_big_data_stats_param() - extract big data statsfrom event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @stats_param: Pointer to hold stats + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_big_data_stats_param(wmi_unified_t wmi_handle, void *evt_buf, + struct big_data_stats_event *stats_param); +#endif + +#endif /* _WMI_UNIFIED_MC_CP_STATS_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_mlme_api.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_mlme_api.h new file mode 100644 index 0000000000..623b681d4e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_mlme_api.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/** + * DOC: contains wmi mlme declarations + */ + +#ifndef _WLAN_UNIFIED_MLME_API_H_ +#define _WLAN_UNIFIED_MLME_API_H_ + +/* + * struct csa_event_status_ind - structure for csa event status ind + * @vdev_id: vdev id + * @status: accept: 1 reject : 0 + */ +struct csa_event_status_ind { + uint8_t vdev_id; + uint8_t status; +}; + +/** + * wmi_send_csa_event_status_ind + * @wmi_hdl: wmi handle + * @params: csa params + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wmi_send_csa_event_status_ind( + wmi_unified_t wmi_hdl, + struct csa_event_status_ind params); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_roam_api.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_roam_api.h new file mode 100644 index 0000000000..aa617abc28 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_roam_api.h @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to ROAMING component. + */ + +#ifndef _WMI_UNIFIED_ROAM_API_H_ +#define _WMI_UNIFIED_ROAM_API_H_ + +#include +#include "wlan_cm_roam_public_struct.h" +#include "wlan_crypto_def_i.h" + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * wmi_unified_set_gateway_params_cmd() - set gateway parameters + * @wmi_handle: wmi handle + * @req: gateway parameter update request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and sends down the gateway configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures; + * error number otherwise + */ +QDF_STATUS +wmi_unified_set_gateway_params_cmd(wmi_unified_t wmi_handle, + struct gateway_update_req_param *req); +#endif + +#ifdef FEATURE_RSSI_MONITOR +/** + * wmi_unified_set_rssi_monitoring_cmd() - set rssi monitoring + * @wmi_handle: wmi handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failures; + * error number otherwise + */ +QDF_STATUS +wmi_unified_set_rssi_monitoring_cmd(wmi_unified_t wmi_handle, + struct rssi_monitor_param *req); +#endif + +/** + * wmi_unified_roam_scan_offload_rssi_thresh_cmd() - set roam scan rssi + * parameters + * @wmi_handle: wmi handle + * @roam_req: roam rssi related parameters + * + * This function reads the incoming @roam_req and fill in the destination + * WMI structure and send down the roam scan rssi configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_rssi_thresh_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *roam_req); + +/** + * wmi_unified_roam_scan_offload_scan_period() - set roam offload scan period + * @wmi_handle: wmi handle + * @param: pointer to roam scan period params to be sent to fw + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_scan_period( + wmi_unified_t wmi_handle, struct wlan_roam_scan_period_params *param); + +/** + * wmi_unified_roam_mawc_params_cmd() - configure roaming MAWC parameters + * @wmi_handle: wmi handle + * @params: Parameters to be configured + * + * Pass the MAWC(Motion Aided wireless connectivity) related roaming + * parameters from the host to the target + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_roam_mawc_params_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_mawc_params *params); + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * wmi_extract_roam_vendor_control_param_event() - extract vendor handoff param + * event coming from fw + * @wmi_handle: wmi handle + * @event: vendor handoff param event pointer + * @len: event len + * @data: vendor handoff related parameters + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ + +QDF_STATUS +wmi_extract_roam_vendor_control_param_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + struct roam_vendor_handoff_params **data); + +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +/** + * wmi_extract_roam_synch_key_event() - extract roam synch key event + * @wmi_handle: wmi handle + * @event: roam synch key event buffer pointer + * @len: event len + * @keys: destination buffer to copy keys + * @num_keys: Number of keys + * @mld_addr: MLD address pointer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct wlan_crypto_key_entry **keys, + uint8_t *num_keys, + struct qdf_mac_addr *mld_addr); +#else +static inline QDF_STATUS +wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct wlan_crypto_key_entry **keys, + uint8_t *num_keys, + struct qdf_mac_addr *mld_addr) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * wmi_unified_roam_scan_filter_cmd() - send roam scan allowlist, + * denylist and preferred list + * @wmi_handle: wmi handle + * @roam_req: roam scan lists related parameters + * + * This function reads the incoming @roam_req and fill in the destination + * WMI structure and send down the different roam scan lists down to the fw + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_roam_scan_filter_cmd(wmi_unified_t wmi_handle, + struct roam_scan_filter_params *roam_req); + +#ifdef FEATURE_WLAN_ESE +/** + * wmi_unified_plm_stop_cmd() - plm stop request + * @wmi_handle: wmi handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_plm_stop_cmd(wmi_unified_t wmi_handle, + const struct plm_req_params *plm); + +/** + * wmi_unified_plm_start_cmd() - plm start request + * @wmi_handle: wmi handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_plm_start_cmd(wmi_unified_t wmi_handle, + const struct plm_req_params *plm); +#endif /* FEATURE_WLAN_ESE */ + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * wmi_extract_roam_event - Extract roam event + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @roam_event: Extract the event and fill in roam_event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t data_len, + struct roam_offload_roam_event *roam_event); +#endif /* WLAN_FEATURE_HOST_ROAM || WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* wmi_unified_set_ric_req_cmd() - set ric request element + * @wmi_handle: wmi handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_ric_req_cmd(wmi_unified_t wmi_handle, void *msg, + uint8_t is_add_ts); + +/** + * wmi_unified_roam_synch_complete_cmd() - roam synch complete command to fw. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * This function sends roam synch complete event to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_synch_complete_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +/** + * wmi_unified_roam_invoke_cmd() - send roam invoke command to fw. + * @wmi_handle: wmi handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_roam_invoke_cmd(wmi_unified_t wmi_handle, + struct roam_invoke_req *roaminvoke); + +/** + * wmi_unified_set_roam_triggers() - send roam trigger bitmap + * @wmi_handle: wmi handle + * @triggers: Roam trigger bitmap params as defined @roam_control_trigger_reason + * + * This function passes the roam trigger bitmap to fw + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_set_roam_triggers(wmi_unified_t wmi_handle, + struct wlan_roam_triggers *triggers); + +/** + * wmi_unified_send_disconnect_roam_params() - Send disconnect roam trigger + * parameters to firmware + * @wmi_handle: wmi handle + * @req: pointer to wlan_roam_disconnect_params + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_send_disconnect_roam_params(wmi_unified_t wmi_handle, + struct wlan_roam_disconnect_params *req); + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * wmi_unified_roam_vendor_handoff_req_cmd() - Send vendor handoff request + * command to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param_id: Vendor Control Param ID from enum + * WMI_ROAM_GET_VENDOR_CONTROL_PARAM_ID + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_roam_vendor_handoff_req_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint32_t param_id); +#endif + +/** + * wmi_unified_send_idle_roam_params() - Send idle roam trigger params to fw + * @wmi_handle: wmi handle + * @req: pointer to wlan_roam_idle_params + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_send_idle_roam_params(wmi_unified_t wmi_handle, + struct wlan_roam_idle_params *req); + +/** + * wmi_unified_send_roam_preauth_status() - Send roam preauthentication status + * to target. + * @wmi_handle: wmi handle + * @param: Roam auth status params + * + * This function passes preauth status of WPA3 SAE auth to firmware. It is + * called when external_auth_status event is received from userspace. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_send_roam_preauth_status(wmi_unified_t wmi_handle, + struct wmi_roam_auth_status_params *param); + +/** + * wmi_unified_vdev_set_pcl_cmd - Send Vdev PCL command to fw + * @wmi_handle: WMI handle + * @params: Set VDEV pcl parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_vdev_set_pcl_cmd(wmi_unified_t wmi_handle, + struct set_pcl_cmd_params *params); + +/** + * wmi_extract_roam_sync_event - Extract roam sync event + * @wmi_handle: WMI handle + * @evt_buf: Event buffer + * @len: evt buffer data len + * @sync_ind: roam sync ptr + * + * This api will allocate memory for roam sync info, extract + * the information sent by FW and pass to CM.The memory will be + * freed by target_if_cm_roam_sync_event. + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_sync_event(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t len, + struct roam_offload_synch_ind **sync_ind); + +/** + * wmi_extract_roam_sync_frame_event - Extract roam sync frame event + * @wmi_handle: WMI handle + * @event: Event buffer + * @len: evt buffer data len + * @frame_ptr: roam sync frame ptr + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_sync_frame_event(wmi_unified_t wmi_handle, void *event, + uint32_t len, + struct roam_synch_frame_ind *frame_ptr); + +/** + * wmi_extract_btm_denylist_event - Extract btm denylist event + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @dst_list: Extract the event and fill in dst_list + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_btm_denylist_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct roam_denylist_event **dst_list); + +/** + * wmi_extract_vdev_disconnect_event - Extract disconnect event data + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @data: Extract the event and fill in data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_vdev_disconnect_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct vdev_disconnect_event_data *data); + +/** + * wmi_extract_roam_scan_chan_list - Extract roam scan chan list + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @data: Extract the event and fill in data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_scan_chan_list(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct cm_roam_scan_ch_resp **data); + +/** + * wmi_unified_extract_roam_btm_response() - Extract BTM response + * @wmi: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: TLV id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_extract_roam_btm_response(wmi_unified_t wmi, void *evt_buf, + struct roam_btm_response_data *dst, + uint8_t idx); + +/** + * wmi_unified_extract_roam_initial_info() - Extract initial info + * @wmi: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: TLV id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_extract_roam_initial_info(wmi_unified_t wmi, void *evt_buf, + struct roam_initial_data *dst, + uint8_t idx); + +/** + * wmi_unified_extract_roam_msg_info() - Extract roam msg info + * @wmi: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: TLV id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf, + struct roam_msg_info *dst, uint8_t idx); + +/** + * wmi_extract_roam_stats_event - Extract roam stats event + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @stats_info: Extract the event and fill in stats_info + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_stats_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct roam_stats_event **stats_info); + +/** + * wmi_unified_extract_roam_extract_frame_info() - Extract the roam frame + * info TLV from roam stats event + * @wmi: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: Index of the TLV to read + * @num_frames: Number of TLV to read + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_extract_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf, + struct roam_frame_stats *dst, + uint8_t idx, uint8_t num_frames); + +/** + * wmi_extract_auth_offload_event - Extract auth offload event + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @auth_event: Extract the event and fill in auth_event + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_auth_offload_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct auth_offload_event *auth_event); + +/** + * wmi_extract_roam_pmkid_request - Extract roam pmkid list + * @wmi_handle: WMI handle + * @event: Event data received from firmware + * @data_len: Event data length received from firmware + * @data: Extract the event and fill in data + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_extract_roam_pmkid_request(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct roam_pmkid_req_event **data); + +/** + * wmi_extract_roam_candidate_frame_event() - Extract the roam candidate + * scan entry and update the scan db + * @wmi_handle: wmi handle + * @event: Event data received from firmware + * @len: Event data length received from firmware + * @data: Extract the event and fill in data + */ +QDF_STATUS +wmi_extract_roam_candidate_frame_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct roam_scan_candidate_frame *data); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +wmi_unified_roam_mlo_config_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_mlo_config *req); +#else +static inline QDF_STATUS +wmi_unified_roam_mlo_config_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_mlo_config *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wmi_unified_roam_scan_offload_mode_cmd() - set roam scan parameters + * @wmi_handle: wmi handle + * @rso_cfg: roam scan offload parameters + * + * This function reads the incoming @rso_cfg and fill in the destination + * WMI structure and send down the roam scan configs down to the firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_mode_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_offload_params *rso_cfg); + +/** + * wmi_unified_send_roam_scan_offload_ap_cmd() - set roam ap profile in fw + * @wmi_handle: wmi handle + * @ap_profile: ap profile params + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_send_roam_scan_offload_ap_cmd( + wmi_unified_t wmi_handle, + struct ap_profile_params *ap_profile); + +/** + * wmi_unified_roam_scan_offload_cmd() - set roam offload command + * @wmi_handle: wmi handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_scan_offload_cmd(wmi_unified_t wmi_handle, + uint32_t command, + uint32_t vdev_id); + +/** + * wmi_unified_roam_scan_offload_chan_list_cmd - Roam scan offload channel + * list command + * @wmi_handle: wmi handle + * @rso_ch_info: roam scan offload channel info + * + * Return: QDF_STATUS + */ +QDF_STATUS +wmi_unified_roam_scan_offload_chan_list_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_scan_channel_list *rso_ch_info); + +/** + * wmi_unified_roam_scan_offload_rssi_change_cmd() - set roam offload RSSI + * threshold + * @wmi_handle: wmi handle + * @params: RSSI change params + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_roam_scan_offload_rssi_change_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_rssi_change_params *params); + +/** + * wmi_unified_set_per_roam_config() - set PER roam config in FW + * @wmi_handle: wmi handle + * @req_buf: per roam config request buffer + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_set_per_roam_config(wmi_unified_t wmi_handle, + struct wlan_per_roam_config_req *req_buf); + +/** + * wmi_unified_send_limit_off_chan_cmd() - send wmi cmd of limit off channel + * configuration params + * @wmi_handle: wmi handler + * @wmi_param: pointer to wmi_limit_off_chan_param + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code on failure + */ +QDF_STATUS wmi_unified_send_limit_off_chan_cmd( + wmi_unified_t wmi_handle, + struct wmi_limit_off_chan_param *wmi_param); + +#ifdef WLAN_FEATURE_FILS_SK +/* + * wmi_unified_roam_send_hlp_cmd() -send HLP command info + * @wmi_handle: wma handle + * @req_buf: Pointer to HLP params + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_roam_send_hlp_cmd(wmi_unified_t wmi_handle, + struct hlp_params *req_buf); +#endif /* WLAN_FEATURE_FILS_SK */ + +/** + * wmi_unified_send_btm_config() - Send BTM config to fw + * @wmi_handle: wmi handle + * @params: pointer to wlan_roam_btm_config + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_send_btm_config(wmi_unified_t wmi_handle, + struct wlan_roam_btm_config *params); + +/** + * wmi_unified_send_bss_load_config() - Send bss load trigger params to fw + * @wmi_handle: wmi handle + * @params: pointer to wlan_roam_bss_load_config + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_unified_send_bss_load_config( + wmi_unified_t wmi_handle, + struct wlan_roam_bss_load_config *params); + +/** + * wmi_unified_offload_11k_cmd() - send 11k offload command + * @wmi_handle: wmi handle + * @params: 11k offload params + * + * This function passes the 11k offload command params to FW + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS +wmi_unified_offload_11k_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_11k_offload_params *params); +/** + * wmi_unified_invoke_neighbor_report_cmd() - send invoke neighbor report cmd + * @wmi_handle: wmi handle + * @params: invoke neighbor report params + * + * This function passes the invoke neighbor report command to fw + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_invoke_neighbor_report_cmd( + wmi_unified_t wmi_handle, + struct wmi_invoke_neighbor_report_params *params); + +/** + * wmi_unified_get_roam_scan_ch_list() - send roam scan channel list get cmd + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * This function sends roam scan channel list get command to firmware. + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_unified_get_roam_scan_ch_list(wmi_unified_t wmi_handle, + uint8_t vdev_id); + +#endif /* _WMI_UNIFIED_ROAM_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_roam_param.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_roam_param.h new file mode 100644 index 0000000000..ef4f3f33fd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/inc/wmi_unified_roam_param.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file contains the API definitions for the ROAMING WMI APIs. + */ + +#ifndef _WMI_UNIFIED_ROAM_PARAM_H_ +#define _WMI_UNIFIED_ROAM_PARAM_H_ + +#include +#include + +/** + * struct gateway_update_req_param - gateway parameter update request + * @request_id: request id + * @vdev_id: vdev id + * @max_retries: Max ARP/NS retry attempts + * @timeout: Retry interval + * @ipv4_addr_type: on ipv4 network + * @ipv6_addr_type: on ipv6 network + * @gw_mac_addr: gateway mac addr + * @ipv4_addr: ipv4 addr + * @ipv6_addr: ipv6 addr + */ +struct gateway_update_req_param { + uint32_t request_id; + uint32_t vdev_id; + uint32_t max_retries; + uint32_t timeout; + uint32_t ipv4_addr_type; + uint32_t ipv6_addr_type; + struct qdf_mac_addr gw_mac_addr; + uint8_t ipv4_addr[QDF_IPV4_ADDR_SIZE]; + uint8_t ipv6_addr[QDF_IPV6_ADDR_SIZE]; +}; + +/** + * struct rssi_monitor_param - rssi monitoring + * @request_id: request id + * @vdev_id: vdev id + * @min_rssi: minimum rssi + * @max_rssi: maximum rssi + * @control: flag to indicate start or stop + */ +struct rssi_monitor_param { + uint32_t request_id; + uint32_t vdev_id; + int8_t min_rssi; + int8_t max_rssi; + bool control; +}; + +#define WMI_CFG_VALID_CHANNEL_LIST_LEN 100 +/* Occupied channel list remains static */ +#define WMI_CHANNEL_LIST_STATIC 1 +/* Occupied channel list can be learnt after init */ +#define WMI_CHANNEL_LIST_DYNAMIC_INIT 2 +/* Occupied channel list can be learnt after flush */ +#define WMI_CHANNEL_LIST_DYNAMIC_FLUSH 3 +/* Occupied channel list can be learnt after update */ +#define WMI_CHANNEL_LIST_DYNAMIC_UPDATE 4 + +/** + * struct plm_req_params - plm req parameter + * @diag_token: Dialog token + * @meas_token: measurement token + * @num_bursts: total number of bursts + * @burst_int: burst interval in seconds + * @meas_duration:in TU's,STA goes off-ch + * @burst_len: no of times the STA should cycle through PLM ch list + * @desired_tx_pwr: desired tx power + * @mac_addr: MC dest addr + * @plm_num_ch: channel numbers + * @plm_ch_freq_list: channel frequency list + * @vdev_id: vdev id + * @enable: enable/disable + */ +struct plm_req_params { + uint16_t diag_token; + uint16_t meas_token; + uint16_t num_bursts; + uint16_t burst_int; + uint16_t meas_duration; + /* no of times the STA should cycle through PLM ch list */ + uint8_t burst_len; + int8_t desired_tx_pwr; + struct qdf_mac_addr mac_addr; + /* no of channels */ + uint8_t plm_num_ch; + /* channel frequency list */ + uint32_t plm_ch_freq_list[WMI_CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t vdev_id; + bool enable; +}; + +/** + * struct wmi_limit_off_chan_param - limit off channel parameters + * @vdev_id: vdev id + * @status: status of the command (enable/disable) + * @max_offchan_time: max off channel time + * @rest_time: home channel time + * @skip_dfs_chans: skip dfs channels during scan + */ +struct wmi_limit_off_chan_param { + uint32_t vdev_id; + bool status; + uint32_t max_offchan_time; + uint32_t rest_time; + bool skip_dfs_chans; +}; + +#define WMI_MAX_HLP_IE_LEN 2048 +/** + * struct hlp_params - HLP info params + * @vdev_id: vdev id + * @hlp_ie_len: HLP IE length + * @hlp_ie: HLP IE + */ +struct hlp_params { + uint8_t vdev_id; + uint32_t hlp_ie_len; + uint8_t hlp_ie[WMI_MAX_HLP_IE_LEN]; +}; + +/** + * struct wmi_roam_auth_status_params - WPA3 roam auth response status + * parameters + * @vdev_id: Vdev on which roam preauth is happening + * @preauth_status: Status of the Auth response. + * IEEE80211_STATUS_SUCCESS(0) for success. Corresponding + * IEEE80211 failure status code for failure. + * + * @bssid: Candidate BSSID + * @pmkid: PMKID derived for the auth + */ +struct wmi_roam_auth_status_params { + uint32_t vdev_id; + uint32_t preauth_status; + struct qdf_mac_addr bssid; + uint8_t pmkid[PMKID_LEN]; +}; + +/** + * struct wmi_invoke_neighbor_report_params - Invoke neighbor report request + * from IW to FW + * @vdev_id: vdev id + * @send_resp_to_host: bool to send response to host or not + * @ssid: ssid given from the IW command + */ +struct wmi_invoke_neighbor_report_params { + uint32_t vdev_id; + uint32_t send_resp_to_host; + struct wlan_ssid ssid; +}; + +/** + * struct set_pcl_cmd_params - Set PCL command params + * @vdev_id: Vdev id + * @weights: PCL weights + */ +struct set_pcl_cmd_params { + uint8_t vdev_id; + struct wmi_pcl_chan_weights *weights; +}; +#endif /* _WMI_UNIFIED_ROAM_PARAM_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_coap_tlv.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_coap_tlv.c new file mode 100644 index 0000000000..ae2529c925 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_coap_tlv.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to CoAP component. + */ + +#include +#include "wmi.h" +#include "ol_defines.h" + +/* + * send_coap_add_pattern_cmd_tlv() - Send wmi cmd for adding CoAP pattern + * @wmi_handle: wmi handle + * @param: parameter for CoAP add pattern + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_add_pattern_cmd_tlv(wmi_unified_t wmi_handle, + struct coap_offload_reply_param *param) +{ + WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len, coapmsg_len_align, verify_len_align; + + wmi_debug("vdev id %d pattern id %d timeout %d src ip 0x%x:%d coap msg len %d", + param->vdev_id, param->pattern_id, param->cache_timeout, + param->src_ip_v4, param->src_udp_port, + param->coapmsg_len); + + wmi_debug("filter: dest ip 0x%x:%d is bc %d verify offset %d len %d", + param->dest_ip_v4, param->dest_udp_port, + param->dest_ip_v4_is_bc, param->verify_offset, + param->verify_len); + + if (!param->verify || !param->verify_len || + !param->coapmsg || !param->coapmsg_len) { + wmi_err("invalid param"); + return QDF_STATUS_E_INVAL; + } + + coapmsg_len_align = qdf_align(param->coapmsg_len, 4); + verify_len_align = qdf_align(param->verify_len, 4); + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + coapmsg_len_align + + WMI_TLV_HDR_SIZE + verify_len_align; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = wmi_buf_data(buf); + cmd = (WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_ADD_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = param->vdev_id; + cmd->pattern_id = param->pattern_id; + cmd->timeout = param->cache_timeout; + WMI_COAP_IPV6_SET(cmd->pattern_type, 0); + WMI_COAP_ADDR_TYPE_SET(cmd->pattern_type, + param->dest_ip_v4_is_bc ? 1 : 0); + qdf_mem_copy(cmd->match_udp_ip.ipv4_addr, ¶m->dest_ip_v4, + sizeof(param->dest_ip_v4)); + cmd->match_udp_port = param->dest_udp_port; + qdf_mem_copy(cmd->udp_local_ip.ipv4_addr, ¶m->src_ip_v4, + sizeof(param->src_ip_v4)); + cmd->udp_local_port = param->src_udp_port; + cmd->verify_offset = param->verify_offset; + cmd->verify_len = param->verify_len; + cmd->coapmsg_len = param->coapmsg_len; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, verify_len_align); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->verify, param->verify_len); + + buf_ptr += verify_len_align; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, coapmsg_len_align); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->coapmsg, param->coapmsg_len); + buf_ptr += coapmsg_len_align; + + wmi_mtrace(WMI_WOW_COAP_ADD_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_ADD_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap add pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_del_pattern_cmd_tlv() - Send wmi cmd for deleting CoAP pattern + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_del_pattern_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint32_t len = sizeof(*cmd); + + wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + wmi_mtrace(WMI_WOW_COAP_DEL_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_DEL_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap del pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_add_pattern_cmd_tlv() - Send wmi cmd for adding CoAP keepalive + * pattern + * @wmi_handle: wmi handle + * @param: parameter for CoAP add pattern + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_add_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle, + struct coap_offload_periodic_tx_param *param) +{ + WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len, coapmsg_len_align; + + wmi_debug("vdev id %d pattern id %d ip src 0x%x:%d dest 0x%x:%d bc %d timeout %d", + param->vdev_id, param->pattern_id, param->src_ip_v4, + param->src_udp_port, param->dest_ip_v4, + param->dest_udp_port, param->dest_ip_v4_is_bc, + param->timeout); + + if (!param->coapmsg || !param->coapmsg_len) { + wmi_err("invalid CoAP message"); + return QDF_STATUS_E_INVAL; + } + + coapmsg_len_align = qdf_align(param->coapmsg_len, 4); + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + coapmsg_len_align; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = wmi_buf_data(buf); + cmd = (WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = param->vdev_id; + cmd->pattern_id = param->pattern_id; + + /* only support IPv4 in current stage */ + WMI_COAP_IPV6_SET(cmd->pattern_type, 0); + WMI_COAP_ADDR_TYPE_SET(cmd->pattern_type, + param->dest_ip_v4_is_bc ? 1 : 0); + qdf_mem_copy(cmd->udp_remote_ip.ipv4_addr, ¶m->dest_ip_v4, + sizeof(param->dest_ip_v4)); + cmd->udp_remote_port = param->dest_udp_port; + qdf_mem_copy(cmd->udp_local_ip.ipv4_addr, ¶m->src_ip_v4, + sizeof(param->src_ip_v4)); + cmd->udp_local_port = param->src_udp_port; + cmd->timeout = param->timeout; + cmd->coapmsg_len = param->coapmsg_len; + + buf_ptr += sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, coapmsg_len_align); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, param->coapmsg, param->coapmsg_len); + buf_ptr += coapmsg_len_align; + + wmi_mtrace(WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_ADD_KEEPALIVE_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap add keepalive pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_del_pattern_cmd_tlv() - Send wmi cmd for deleting CoAP + * keepalive pattern + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_del_keepalive_pattern_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len = sizeof(*cmd); + + wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = wmi_buf_data(buf); + cmd = (WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_DEL_PATTERN_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + wmi_mtrace(WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_DEL_KEEPALIVE_PATTERN_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap del keepalive pattern command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/* + * send_coap_cache_get_cmd_tlv() - Send wmi cmd for getting cached CoAP + * messages + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @pattern_id: pattern id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_coap_cache_get_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t pattern_id) +{ + WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint32_t len = sizeof(*cmd); + + wmi_debug("vdev id %d pattern id %d", vdev_id, pattern_id); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_COAP_GET_BUF_INFO_CMD_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->pattern_id = pattern_id; + wmi_mtrace(WMI_WOW_COAP_GET_BUF_INFO_CMDID, + cmd->vdev_id, cmd->pattern_id); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_WOW_COAP_GET_BUF_INFO_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send wow coap get buf info command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * coap_extract_buf_info_tlv() - Extract CoAP buf info event + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @info: pointer to CoAP buf info + * + * The caller needs to free any possible nodes in info->info_list + * regardless of failure or success. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +coap_extract_buf_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct coap_buf_info *info) +{ + WMI_WOW_COAP_BUF_INFO_EVENT_fixed_param *buf_info_ev; + WMI_WOW_COAP_BUF_INFO_EVENTID_param_tlvs *param_buf = evt_buf; + wmi_coap_tuple *tuple; + uint8_t *payload; + uint32_t num_tuple, num_payload; + struct coap_buf_node *buf_node; + int i, j; + + buf_info_ev = param_buf->fixed_param; + if (!buf_info_ev) { + wmi_debug("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + if (buf_info_ev->vdev_id > WLAN_MAX_VDEVS) { + wmi_debug("received invalid vdev_id %d", + buf_info_ev->vdev_id); + return QDF_STATUS_E_INVAL; + } + + info->vdev_id = buf_info_ev->vdev_id; + info->req_id = buf_info_ev->pattern_id; + info->more_info = buf_info_ev->more_tuples; + + num_tuple = param_buf->num_coap_tuple; + num_payload = param_buf->num_payloads; + for (i = 0, j = 0; i < num_tuple && j < num_payload; i++) { + tuple = ¶m_buf->coap_tuple[i]; + if (!tuple->payload_len) { + wmi_err("idx %d: invalid payload len 0", i); + continue; + } + + payload = ¶m_buf->payloads[j]; + j += qdf_align(tuple->payload_len, 4); + if (j > num_payload) { + wmi_err("idx %d: payload len overflow, pos %d - total %d", + i, j, num_payload); + return QDF_STATUS_E_INVAL; + } + + buf_node = qdf_mem_malloc(sizeof(*buf_node)); + if (!buf_node) + return QDF_STATUS_E_NOMEM; + + buf_node->payload = qdf_mem_malloc(tuple->payload_len); + if (!buf_node->payload) { + qdf_mem_free(buf_node); + return QDF_STATUS_E_NOMEM; + } + + buf_node->tsf = tuple->tsf; + qdf_mem_copy(&buf_node->src_ip, tuple->src_ip.ipv4_addr, + sizeof(buf_node->src_ip)); + buf_node->len = tuple->payload_len; + qdf_mem_copy(buf_node->payload, payload, buf_node->len); + qdf_list_insert_back(&info->info_list, &buf_node->node); + + wmi_debug("idx %d: src ip 0x%x tsf 0x%llx payload len %d", + i, buf_node->src_ip, buf_node->tsf, buf_node->len); + } + + wmi_debug("vdev_id %d req_id %d num_tuple %d payload len %d more info %d", + info->vdev_id, info->req_id, num_tuple, + num_payload, info->more_info); + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_coap_attach_tlv() - attach CoAP tlv handlers + * @wmi_handle: wmi handle + * + * Return: void + */ +void wmi_coap_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_coap_add_pattern_cmd = send_coap_add_pattern_cmd_tlv; + ops->send_coap_del_pattern_cmd = send_coap_del_pattern_cmd_tlv; + ops->send_coap_add_keepalive_pattern_cmd = + send_coap_add_keepalive_pattern_cmd_tlv; + ops->send_coap_del_keepalive_pattern_cmd = + send_coap_del_keepalive_pattern_cmd_tlv; + ops->send_coap_cache_get_cmd = send_coap_cache_get_cmd_tlv; + ops->extract_coap_buf_info = coap_extract_buf_info_tlv; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_api.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_api.c new file mode 100644 index 0000000000..1eb469c1ec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_api.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "wmi_unified_ll_sap_api.h" +#include "wmi_unified_param.h" + +QDF_STATUS wmi_unified_audio_transport_switch_resp_send( + wmi_unified_t wmi_hdl, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ + if (wmi_hdl->ops->send_audio_transport_switch_resp) + return wmi_hdl->ops->send_audio_transport_switch_resp(wmi_hdl, + req_type, + status); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_audio_transport_switch_req_event( + wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + enum bearer_switch_req_type *req_type) +{ + if (wmi_handle->ops->extract_audio_transport_switch_req_event) + return wmi_handle->ops->extract_audio_transport_switch_req_event( + wmi_handle, event, len, req_type); + return QDF_STATUS_E_FAILURE; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_tlv.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_tlv.c new file mode 100644 index 0000000000..39577d6b62 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_tlv.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wmi_unified.h" +#include "wmi_unified_param.h" +#include +#include +#include "wmi_unified_ll_sap_tlv.h" + +static WMI_AUDIO_TRANSPORT_SWITCH_RESPONSE_STATUS +wmi_convert_host_to_target_audio_switch_status(enum bearer_switch_status status) +{ + if (status == WLAN_BS_STATUS_COMPLETED) + return WMI_AUDIO_TRANSPORT_SWITCH_STATUS_SUCCESS; + else if (status == WLAN_BS_STATUS_REJECTED) + return WMI_AUDIO_TRANSPORT_SWITCH_STATUS_FAIL; + else + return WMI_AUDIO_TRANSPORT_SWITCH_STATUS_TIMEOUT; +} + +static WMI_AUDIO_TRANSPORT_SWITCH_TYPE +wmi_convert_host_to_target_audio_switch_type( + enum bearer_switch_req_type req_type) +{ + if (req_type == WLAN_BS_REQ_TO_NON_WLAN) + return WMI_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN; + else + return WMI_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN; +} + +static enum bearer_switch_req_type +wmi_convert_target_to_host_audio_switch_type(uint32_t req_type) +{ + if (req_type == WMI_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN) + return WLAN_BS_REQ_TO_NON_WLAN; + else if (req_type == WMI_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN) + return WLAN_BS_REQ_TO_WLAN; + else + return WLAN_BS_REQ_INVALID; +} + +QDF_STATUS audio_transport_switch_resp_tlv( + wmi_unified_t wmi_hdl, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status) +{ + wmi_audio_transport_switch_resp_status_cmd_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS qdf_status; + + buf = wmi_buf_alloc(wmi_hdl, sizeof(*cmd)); + if (!buf) + return QDF_STATUS_E_FAILURE; + + cmd = (wmi_audio_transport_switch_resp_status_cmd_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_audio_transport_switch_resp_status_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_audio_transport_switch_resp_status_cmd_fixed_param)); + + cmd->switch_type = wmi_convert_host_to_target_audio_switch_type( + req_type); + cmd->switch_response_status = + wmi_convert_host_to_target_audio_switch_status(status); + + wmi_nofl_debug("LL_LT_SAP Audio switch type %d status %d", + cmd->switch_type, cmd->switch_response_status); + + qdf_status = wmi_unified_cmd_send( + wmi_hdl, buf, sizeof(*cmd), + WMI_AUDIO_TRANSPORT_SWITCH_RESP_STATUS_CMDID); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + wmi_buf_free(buf); + + return qdf_status; +} + +QDF_STATUS +extract_audio_transport_switch_req_event_tlv( + wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + enum bearer_switch_req_type *req_type) +{ + WMI_AUDIO_TRANSPORT_SWITCH_TYPE_EVENTID_param_tlvs *param_buf = NULL; + wmi_audio_transport_switch_type_event_fixed_param *fixed_param = NULL; + + if (!event || !len) { + wmi_debug("Empty transport switch request event"); + return QDF_STATUS_E_FAILURE; + } + + param_buf = (WMI_AUDIO_TRANSPORT_SWITCH_TYPE_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err("received null buf from target"); + return QDF_STATUS_E_INVAL; + } + + fixed_param = (wmi_audio_transport_switch_type_event_fixed_param *) + param_buf->fixed_param; + if (!fixed_param) { + wmi_err("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + *req_type = wmi_convert_target_to_host_audio_switch_type( + fixed_param->switch_type); + + wmi_nofl_debug("LL_LT_SAP FW requested bearer switch to %d", *req_type); + + if (*req_type == WLAN_BS_REQ_TO_WLAN) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_tlv.h b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_tlv.h new file mode 100644 index 0000000000..6f37502568 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_ll_sap_tlv.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_status.h" +#include "wlan_ll_sap_public_structs.h" +#include "wmi_unified_param.h" + +#ifdef WLAN_FEATURE_LL_LT_SAP +/** + * audio_transport_switch_resp_tlv() - AUdio transport switch response tlv + * @wmi_hdl: WMI handle + * @req_type: Bearer switch request type + * @status: Bearer switch status + * + * Return: QDF_STATUS + */ +QDF_STATUS +audio_transport_switch_resp_tlv(wmi_unified_t wmi_hdl, + enum bearer_switch_req_type req_type, + enum bearer_switch_status status); + +/** + * extract_audio_transport_switch_req_event_tlv() - AUdio transport switch + * request tlv + * @wmi_handle: WMI handle + * @event: Event received from the FW + * @len: Length of the event + * @req_type: Bearer switch request type + * + * Return: QDF_STATUS + */ +QDF_STATUS +extract_audio_transport_switch_req_event_tlv( + wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + enum bearer_switch_req_type *req_type); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mc_cp_stats_api.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mc_cp_stats_api.c new file mode 100644 index 0000000000..9893f71c90 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mc_cp_stats_api.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: Implement API's specific to cp stats component. + */ + +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" +#include "wmi_unified_mc_cp_stats_api.h" + +QDF_STATUS +wmi_extract_per_chain_rssi_stats(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + struct wmi_host_per_chain_rssi_stats *rssi_stats) +{ + if (wmi_handle->ops->extract_per_chain_rssi_stats) + return wmi_handle->ops->extract_per_chain_rssi_stats(wmi_handle, + evt_buf, index, rssi_stats); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_adv_stats(wmi_unified_t wmi_handle, void *evt_buf, + struct wmi_host_peer_adv_stats *peer_adv_stats) +{ + if (wmi_handle->ops->extract_peer_adv_stats) + return wmi_handle->ops->extract_peer_adv_stats(wmi_handle, + evt_buf, peer_adv_stats); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_FEATURE_MIB_STATS +QDF_STATUS wmi_extract_mib_stats(wmi_unified_t wmi_handle, void *evt_buf, + struct mib_stats_metrics *mib_stats) +{ + if (wmi_handle->ops->extract_mib_stats) + return wmi_handle->ops->extract_mib_stats(wmi_handle, + evt_buf, + mib_stats); + + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS +wmi_unified_peer_stats_request_send(wmi_unified_t wmi_handle, + struct peer_stats_request_params *param) +{ + if (wmi_handle->ops->send_request_peer_stats_info_cmd) + return wmi_handle->ops->send_request_peer_stats_info_cmd( + wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_stats_param(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_stats_event *stats_param) +{ + if (wmi_handle->ops->extract_peer_stats_count) + return wmi_handle->ops->extract_peer_stats_count(wmi_handle, + evt_buf, stats_param); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_tx_pkt_per_mcs(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info) +{ + if (wmi_handle->ops->extract_peer_tx_pkt_per_mcs) + return wmi_handle->ops->extract_peer_tx_pkt_per_mcs(wmi_handle, + evt_buf, index, peer_stats_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_rx_pkt_per_mcs(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info) +{ + if (wmi_handle->ops->extract_peer_rx_pkt_per_mcs) + return wmi_handle->ops->extract_peer_rx_pkt_per_mcs(wmi_handle, + evt_buf, index, peer_stats_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_peer_stats_info(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info) +{ + if (wmi_handle->ops->extract_peer_stats_info) + return wmi_handle->ops->extract_peer_stats_info(wmi_handle, + evt_buf, index, peer_stats_info); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +QDF_STATUS +wmi_extract_big_data_stats_param(wmi_unified_t wmi_handle, void *evt_buf, + struct big_data_stats_event *stats_param) +{ + if (wmi_handle->ops->extract_big_data_stats) + return wmi_handle->ops->extract_big_data_stats(wmi_handle, + evt_buf, stats_param); + + return QDF_STATUS_E_FAILURE; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mc_cp_stats_tlv.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mc_cp_stats_tlv.c new file mode 100644 index 0000000000..a3bd426600 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mc_cp_stats_tlv.c @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "osdep.h" +#include "wmi.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_param.h" + +/** + * extract_per_chain_rssi_stats_tlv() - api to extract rssi stats from event + * buffer + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into vdev stats + * @rssi_stats: Pointer to hold rssi stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +extract_per_chain_rssi_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + struct wmi_host_per_chain_rssi_stats *rssi_stats) +{ + uint8_t *data; + wmi_rssi_stats *fw_rssi_stats; + wmi_per_chain_rssi_stats *rssi_event; + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + + if (!evt_buf) { + wmi_err("evt_buf is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *) evt_buf; + rssi_event = param_buf->chain_stats; + + if (index >= rssi_event->num_per_chain_rssi_stats) { + wmi_err("Invalid index: %u", index); + return QDF_STATUS_E_INVAL; + } + + data = ((uint8_t *)(&rssi_event[1])) + WMI_TLV_HDR_SIZE; + fw_rssi_stats = &((wmi_rssi_stats *)data)[index]; + if (fw_rssi_stats->vdev_id >= WLAN_UMAC_PDEV_MAX_VDEVS) + return QDF_STATUS_E_INVAL; + + rssi_stats->vdev_id = fw_rssi_stats->vdev_id; + qdf_mem_copy(rssi_stats->rssi_avg_beacon, + fw_rssi_stats->rssi_avg_beacon, + sizeof(fw_rssi_stats->rssi_avg_beacon)); + qdf_mem_copy(rssi_stats->rssi_avg_data, + fw_rssi_stats->rssi_avg_data, + sizeof(fw_rssi_stats->rssi_avg_data)); + qdf_mem_copy(&rssi_stats->peer_macaddr, + &fw_rssi_stats->peer_macaddr, + sizeof(fw_rssi_stats->peer_macaddr)); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_adv_stats_tlv() - extract adv peer stats from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @peer_adv_stats: Pointer to hold adv peer stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_peer_adv_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + struct wmi_host_peer_adv_stats + *peer_adv_stats) +{ + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_peer_extd2_stats *adv_stats; + int i; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf; + + adv_stats = param_buf->peer_extd2_stats; + if (!adv_stats) { + wmi_debug("no peer_adv stats in event buffer"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < param_buf->num_peer_extd2_stats; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&adv_stats[i].peer_macaddr, + peer_adv_stats[i].peer_macaddr); + peer_adv_stats[i].fcs_count = adv_stats[i].rx_fcs_err; + peer_adv_stats[i].rx_bytes = + (uint64_t)adv_stats[i].rx_bytes_u32 << + WMI_LOWER_BITS_SHIFT_32 | + adv_stats[i].rx_bytes_l32; + peer_adv_stats[i].rx_count = adv_stats[i].rx_mpdus; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_MIB_STATS +/** + * extract_mib_stats_tlv() - extract mib stats from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @mib_stats: pointer to hold mib stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS extract_mib_stats_tlv(wmi_unified_t wmi_handle, + void *evt_buf, + struct mib_stats_metrics + *mib_stats) +{ + WMI_UPDATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_stats_event_fixed_param *ev_param; + uint8_t *data; + wmi_mib_stats *ev; + wmi_mib_extd_stats *ev_extd; + + param_buf = (WMI_UPDATE_STATS_EVENTID_param_tlvs *)evt_buf; + ev_param = (wmi_stats_event_fixed_param *)param_buf->fixed_param; + data = (uint8_t *)param_buf->data; + + ev = (wmi_mib_stats *)(data + + ev_param->num_pdev_stats * sizeof(wmi_pdev_stats) + + ev_param->num_vdev_stats * sizeof(wmi_vdev_stats) + + ev_param->num_peer_stats * sizeof(wmi_peer_stats) + + ev_param->num_bcnflt_stats * + sizeof(wmi_bcnfilter_stats_t) + + ev_param->num_chan_stats * sizeof(wmi_chan_stats)); + + qdf_mem_zero(mib_stats, sizeof(*mib_stats)); + + mib_stats->mib_counters.tx_frags = + ev->tx_mpdu_grp_frag_cnt; + mib_stats->mib_counters.group_tx_frames = + ev->tx_msdu_grp_frm_cnt; + mib_stats->mib_counters.failed_cnt = ev->tx_msdu_fail_cnt; + mib_stats->mib_counters.rx_frags = ev->rx_mpdu_frag_cnt; + mib_stats->mib_counters.group_rx_frames = + ev->rx_msdu_grp_frm_cnt; + mib_stats->mib_counters.fcs_error_cnt = + ev->rx_mpdu_fcs_err; + mib_stats->mib_counters.tx_frames = + ev->tx_msdu_frm_cnt; + mib_stats->mib_mac_statistics.retry_cnt = + ev->tx_msdu_retry_cnt; + mib_stats->mib_mac_statistics.frame_dup_cnt = + ev->rx_frm_dup_cnt; + mib_stats->mib_mac_statistics.rts_success_cnt = + ev->tx_rts_success_cnt; + mib_stats->mib_mac_statistics.rts_fail_cnt = + ev->tx_rts_fail_cnt; + + mib_stats->mib_qos_counters.qos_tx_frag_cnt = + ev->tx_Qos_mpdu_grp_frag_cnt; + mib_stats->mib_qos_counters.qos_retry_cnt = + ev->tx_Qos_msdu_retry_UP; + mib_stats->mib_qos_counters.qos_failed_cnt = + ev->tx_Qos_msdu_fail_UP; + mib_stats->mib_qos_counters.qos_frame_dup_cnt = + ev->rx_Qos_frm_dup_cnt_UP; + mib_stats->mib_qos_counters.qos_rts_success_cnt = + ev->tx_Qos_rts_success_cnt_UP; + mib_stats->mib_qos_counters.qos_rts_fail_cnt = + ev->tx_Qos_rts_fail_cnt_UP; + mib_stats->mib_qos_counters.qos_rx_frag_cnt = + ev->rx_Qos_mpdu_frag_cnt_UP; + mib_stats->mib_qos_counters.qos_tx_frame_cnt = + ev->tx_Qos_msdu_frm_cnt_UP; + mib_stats->mib_qos_counters.qos_discarded_frame_cnt = + ev->rx_Qos_msdu_discard_cnt_UP; + mib_stats->mib_qos_counters.qos_mpdu_rx_cnt = + ev->rx_Qos_mpdu_cnt; + mib_stats->mib_qos_counters.qos_retries_rx_cnt = + ev->rx_Qos_mpdu_retryBit_cnt; + + mib_stats->mib_rsna_stats.tkip_icv_err = + ev->rsna_TKIP_icv_err_cnt; + mib_stats->mib_rsna_stats.tkip_replays = + ev->rsna_TKIP_replay_err_cnt; + mib_stats->mib_rsna_stats.ccmp_decrypt_err = + ev->rsna_CCMP_decrypt_err_cnt; + mib_stats->mib_rsna_stats.ccmp_replays = + ev->rsna_CCMP_replay_err_cnt; + + mib_stats->mib_counters_group3.tx_ampdu_cnt = + ev->tx_ampdu_cnt; + mib_stats->mib_counters_group3.tx_mpdus_in_ampdu_cnt = + ev->tx_mpdu_cnt_in_ampdu; + mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt = + ev->tx_octets_in_ampdu.upload.high; + mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt = + mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt << 32; + mib_stats->mib_counters_group3.tx_octets_in_ampdu_cnt += + ev->tx_octets_in_ampdu.upload.low; + + mib_stats->mib_counters_group3.ampdu_rx_cnt = + ev->rx_ampdu_cnt; + mib_stats->mib_counters_group3.mpdu_in_rx_ampdu_cnt = + ev->rx_mpdu_cnt_in_ampdu; + mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt = + ev->rx_octets_in_ampdu.upload.rx_octets_in_ampdu_high; + mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt = + mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt << 32; + mib_stats->mib_counters_group3.rx_octets_in_ampdu_cnt += + ev->rx_octets_in_ampdu.upload.rx_octets_in_ampdu_low; + + if (ev_param->num_mib_extd_stats) { + ev_extd = (wmi_mib_extd_stats *)((uint8_t *)ev + + ev_param->num_mib_stats * sizeof(wmi_mib_stats) + + ev_param->num_bcn_stats * sizeof(wmi_bcn_stats) + + ev_param->num_peer_extd_stats * + sizeof(wmi_peer_extd_stats)); + mib_stats->mib_mac_statistics.multi_retry_cnt = + ev_extd->tx_msdu_multi_retry_cnt; + mib_stats->mib_mac_statistics.tx_ack_fail_cnt = + ev_extd->tx_ack_fail_cnt; + + mib_stats->mib_qos_counters.qos_multi_retry_cnt = + ev_extd->tx_qos_msdu_multi_retry_up; + mib_stats->mib_qos_counters.tx_qos_ack_fail_cnt_up = + ev_extd->tx_qos_ack_fail_cnt_up; + + mib_stats->mib_rsna_stats.cmac_icv_err = + ev_extd->rsna_cmac_icv_err_cnt; + mib_stats->mib_rsna_stats.cmac_replays = + ev_extd->rsna_cmac_replay_err_cnt; + + mib_stats->mib_counters_group3.rx_ampdu_deli_crc_err_cnt = + ev_extd->rx_ampdu_deli_crc_err_cnt; + } + + return QDF_STATUS_SUCCESS; +} + +static void wmi_cp_stats_attach_mib_stats_tlv(struct wmi_ops *ops) +{ + ops->extract_mib_stats = extract_mib_stats_tlv; +} +#else +static void wmi_cp_stats_attach_mib_stats_tlv(struct wmi_ops *ops) +{ +} +#endif /* WLAN_FEATURE_MIB_STATS */ + +/** + * send_request_peer_stats_info_cmd_tlv() - WMI request peer stats function + * @wmi_handle: handle to WMI. + * @param: pointer to hold peer stats request parameter + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_request_peer_stats_info_cmd_tlv(wmi_unified_t wmi_handle, + struct peer_stats_request_params *param) +{ + int32_t ret; + wmi_request_peer_stats_info_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(wmi_request_peer_stats_info_cmd_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_request_peer_stats_info_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_request_peer_stats_info_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_request_peer_stats_info_cmd_fixed_param)); + cmd->request_type = param->request_type; + cmd->vdev_id = param->vdev_id; + WMI_CHAR_ARRAY_TO_MAC_ADDR(param->peer_mac_addr, &cmd->peer_macaddr); + cmd->reset_after_request = param->reset_after_request; + + wmi_debug("PEER STATS REQ VDEV_ID:%d PEER:"QDF_MAC_ADDR_FMT" TYPE:%d RESET:%d", + cmd->vdev_id, QDF_MAC_ADDR_REF(param->peer_mac_addr), + cmd->request_type, + cmd->reset_after_request); + + wmi_mtrace(WMI_REQUEST_PEER_STATS_INFO_CMDID, cmd->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_PEER_STATS_INFO_CMDID); + if (ret) { + wmi_err("Failed to send peer stats request to fw =%d", ret); + wmi_buf_free(buf); + } + + return qdf_status_from_os_return(ret); +} + +/** + * extract_peer_stats_count_tlv() - extract peer stats count from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @stats_param: Pointer to hold stats count + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +extract_peer_stats_count_tlv(wmi_unified_t wmi_handle, void *evt_buf, + wmi_host_stats_event *stats_param) +{ + WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf; + wmi_peer_stats_info_event_fixed_param *ev_param; + + param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) + return QDF_STATUS_E_FAILURE; + + ev_param = param_buf->fixed_param; + if (!ev_param) + return QDF_STATUS_E_FAILURE; + + if (!param_buf->num_peer_stats_info || + param_buf->num_peer_stats_info < ev_param->num_peers) { + wmi_err_rl("actual num of peers stats info: %d is less than provided peers: %d", + param_buf->num_peer_stats_info, ev_param->num_peers); + return QDF_STATUS_E_FAULT; + } + + if (!stats_param) + return QDF_STATUS_E_FAILURE; + + stats_param->num_peer_stats_info_ext = ev_param->num_peers; + + return QDF_STATUS_SUCCESS; +} + +static void dump_peer_stats_info(wmi_peer_stats_info *stats) +{ + u_int8_t mac[6]; + int i; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&stats->peer_macaddr, mac); + wmi_debug("mac "QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac)); + wmi_debug("tx_bytes %d %d tx_packets %d %d tx_retries %d tx_failed %d", + stats->tx_bytes.low_32, + stats->tx_bytes.high_32, + stats->tx_packets.low_32, + stats->tx_packets.high_32, + stats->tx_retries, stats->tx_failed); + wmi_debug("rx_bytes %d %d rx_packets %d %d", + stats->rx_bytes.low_32, + stats->rx_bytes.high_32, + stats->rx_packets.low_32, + stats->rx_packets.high_32); + wmi_debug("tx_rate_code %x rx_rate_code %x tx_rate %x rx_rate %x peer_rssi %d tx_succeed %d", + stats->last_tx_rate_code, + stats->last_rx_rate_code, + stats->last_tx_bitrate_kbps, + stats->last_rx_bitrate_kbps, + stats->peer_rssi, stats->tx_succeed); + for (i = 0; i < WMI_MAX_CHAINS; i++) + wmi_debug("chain%d_rssi %d", i, stats->peer_rssi_per_chain[i]); +} + +/** + * extract_peer_tx_pkt_per_mcs_tlv() - extract peer tx packets per MCS + * from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into vdev stats + * @peer_stats_info: Pointer to hold peer stats info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +extract_peer_tx_pkt_per_mcs_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info) +{ + WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf; + int i, j; + + param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf; + + if (index + peer_stats_info->num_tx_rate_counts <= + param_buf->num_tx_rate_counts) { + peer_stats_info->tx_pkt_per_mcs = + qdf_mem_malloc( + peer_stats_info->num_tx_rate_counts * sizeof(uint32_t)); + + if (!peer_stats_info->tx_pkt_per_mcs) + return QDF_STATUS_E_NOMEM; + wmi_debug("Tx rate counts"); + for (j = 0, i = index; j < peer_stats_info->num_tx_rate_counts; + j++, i++) { + peer_stats_info->tx_pkt_per_mcs[j] = + param_buf->tx_rate_counts[i]; + wmi_nofl_debug("MCS [%d] %d", j, + peer_stats_info->tx_pkt_per_mcs[j]); + } + } else { + wmi_err("invalid idx %d curr peer tx_rate_counts %d total tx_rate_count %d", + index, peer_stats_info->num_tx_rate_counts, + param_buf->num_tx_rate_counts); + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_rx_pkt_per_mcs_tlv() - extract peer rx rpackets per MCS + * from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into vdev stats + * @peer_stats_info: Pointer to hold peer stats info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +extract_peer_rx_pkt_per_mcs_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info) +{ + WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf; + int i, j; + + param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf; + + if (index + peer_stats_info->num_rx_rate_counts <= + param_buf->num_rx_rate_counts) { + peer_stats_info->rx_pkt_per_mcs = + qdf_mem_malloc( + peer_stats_info->num_rx_rate_counts * sizeof(uint32_t)); + + if (!peer_stats_info->rx_pkt_per_mcs) + return QDF_STATUS_E_NOMEM; + wmi_debug("Rx rate counts"); + for (j = 0, i = index; j < peer_stats_info->num_rx_rate_counts; + j++, i++) { + peer_stats_info->rx_pkt_per_mcs[j] = + param_buf->rx_rate_counts[i]; + wmi_nofl_debug("MCS [%d] %d", j, + peer_stats_info->rx_pkt_per_mcs[j]); + } + } else { + wmi_err("invalid idx %d curr peer rx_rate_counts %d total rx_rate_count %d", + index, peer_stats_info->num_rx_rate_counts, + param_buf->num_rx_rate_counts); + } + return QDF_STATUS_SUCCESS; +} + +/** + * extract_peer_stats_info_tlv() - extract peer stats info from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @index: Index into vdev stats + * @peer_stats_info: Pointer to hold peer stats info + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +extract_peer_stats_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t index, + wmi_host_peer_stats_info *peer_stats_info) +{ + WMI_PEER_STATS_INFO_EVENTID_param_tlvs *param_buf; + wmi_peer_stats_info_event_fixed_param *ev_param; + + param_buf = (WMI_PEER_STATS_INFO_EVENTID_param_tlvs *)evt_buf; + ev_param = param_buf->fixed_param; + + if (index < ev_param->num_peers) { + wmi_peer_stats_info *ev = ¶m_buf->peer_stats_info[index]; + int i; + + dump_peer_stats_info(ev); + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->peer_macaddr, + peer_stats_info->peer_macaddr.bytes); + peer_stats_info->tx_packets = ev->tx_packets.low_32; + peer_stats_info->tx_bytes = ev->tx_bytes.high_32; + peer_stats_info->tx_bytes <<= 32; + peer_stats_info->tx_bytes += ev->tx_bytes.low_32; + peer_stats_info->rx_packets = ev->rx_packets.low_32; + peer_stats_info->rx_bytes = ev->rx_bytes.high_32; + peer_stats_info->rx_bytes <<= 32; + peer_stats_info->rx_bytes += ev->rx_bytes.low_32; + peer_stats_info->tx_retries = ev->tx_retries; + peer_stats_info->tx_failed = ev->tx_failed; + peer_stats_info->tx_succeed = ev->tx_succeed; + peer_stats_info->peer_rssi = ev->peer_rssi; + peer_stats_info->last_tx_bitrate_kbps = + ev->last_tx_bitrate_kbps; + peer_stats_info->last_tx_rate_code = ev->last_tx_rate_code; + peer_stats_info->last_rx_bitrate_kbps = + ev->last_rx_bitrate_kbps; + peer_stats_info->last_rx_rate_code = ev->last_rx_rate_code; + for (i = 0; i < WMI_MAX_CHAINS; i++) + peer_stats_info->peer_rssi_per_chain[i] = + ev->peer_rssi_per_chain[i]; + peer_stats_info->num_tx_rate_counts = ev->num_tx_rate_counts; + peer_stats_info->num_rx_rate_counts = ev->num_rx_rate_counts; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/** + * extract_big_data_stats_tlv() - extract big data from event + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @stats: Pointer to hold big data stats + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +extract_big_data_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct big_data_stats_event *stats) +{ + WMI_VDEV_SEND_BIG_DATA_P2_EVENTID_param_tlvs *param_buf; + wmi_vdev_send_big_data_p2_event_fixed_param *event; + wmi_big_data_dp_stats_tlv_param *dp_stats_param_buf; + + param_buf = (WMI_VDEV_SEND_BIG_DATA_P2_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + wmi_err("invalid buffer"); + return QDF_STATUS_E_FAILURE; + } + + event = param_buf->fixed_param; + if (!event) { + wmi_err("invalid fixed param"); + return QDF_STATUS_E_FAILURE; + } + + dp_stats_param_buf = param_buf->big_data_dp_stats; + if (!dp_stats_param_buf) { + wmi_err("invalid dp stats param"); + return QDF_STATUS_E_FAILURE; + } + + stats->vdev_id = event->vdev_id; + stats->ani_level = event->ani_level; + stats->tsf_out_of_sync = event->tsf_out_of_sync; + + stats->last_data_tx_pwr = dp_stats_param_buf->last_data_tx_pwr; + stats->target_power_dsss = dp_stats_param_buf->target_power_dsss; + stats->target_power_ofdm = dp_stats_param_buf->target_power_ofdm; + stats->last_tx_data_rix = dp_stats_param_buf->last_tx_data_rix; + stats->last_tx_data_rate_kbps = + dp_stats_param_buf->last_tx_data_rate_kbps; + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +static void +wmi_attach_big_data_stats_handler(struct wmi_ops *ops) +{ + ops->extract_big_data_stats = extract_big_data_stats_tlv; +} +#else +static void +wmi_attach_big_data_stats_handler(struct wmi_ops *ops) +{} +#endif + +void wmi_mc_cp_stats_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->extract_per_chain_rssi_stats = extract_per_chain_rssi_stats_tlv; + ops->extract_peer_adv_stats = extract_peer_adv_stats_tlv; + wmi_cp_stats_attach_mib_stats_tlv(ops); + ops->send_request_peer_stats_info_cmd = + send_request_peer_stats_info_cmd_tlv; + ops->extract_peer_stats_count = extract_peer_stats_count_tlv; + ops->extract_peer_stats_info = extract_peer_stats_info_tlv; + wmi_handle->ops->extract_peer_tx_pkt_per_mcs = + extract_peer_tx_pkt_per_mcs_tlv; + wmi_handle->ops->extract_peer_rx_pkt_per_mcs = + extract_peer_rx_pkt_per_mcs_tlv; + wmi_attach_big_data_stats_handler(ops); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mlme_api.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mlme_api.c new file mode 100644 index 0000000000..8ebeb29122 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mlme_api.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/** + * DOC: contains wmi mlme declarations + */ + +#include +#include +#include +#include + +QDF_STATUS wmi_send_csa_event_status_ind( + wmi_unified_t wmi_hdl, + struct csa_event_status_ind params) +{ + if (wmi_hdl->ops->send_csa_event_status_ind) + return wmi_hdl->ops->send_csa_event_status_ind(wmi_hdl, params); + + return QDF_STATUS_E_FAILURE; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mlme_tlv.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mlme_tlv.c new file mode 100644 index 0000000000..13072230e5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_mlme_tlv.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +/** + * DOC: contains wmi mlme declarations + */ + +#include +#include "wmi.h" +#include "wlan_mlme_api.h" +#include "wmi_unified_ll_sap_tlv.h" + +static QDF_STATUS csa_event_status_ind_tlv(wmi_unified_t wmi_handle, + struct csa_event_status_ind params) +{ + wmi_csa_event_status_ind_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + + buf = wmi_buf_alloc(wmi_handle, sizeof(*cmd)); + if (!buf) + return QDF_STATUS_E_FAILURE; + + cmd = (wmi_csa_event_status_ind_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_csa_event_status_ind_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_csa_event_status_ind_fixed_param)); + + cmd->vdev_id = params.vdev_id; + cmd->status = params.status; + + wmi_debug("vdev_id: %d status: %d ", cmd->vdev_id, cmd->status); + + status = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), + WMI_CSA_EVENT_STATUS_INDICATION_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +#ifdef WLAN_FEATURE_LL_LT_SAP +/** + * wmi_mlme_attach_ll_lt_sap_tlv() - attach ll_lt_sap tlv handlers + * @ops: wmi ops + * + * Return: void + */ +static void wmi_mlme_attach_ll_lt_sap_tlv(struct wmi_ops *ops) +{ + ops->send_audio_transport_switch_resp = audio_transport_switch_resp_tlv; + ops->extract_audio_transport_switch_req_event = + extract_audio_transport_switch_req_event_tlv; +} +#else +static inline void wmi_mlme_attach_ll_lt_sap_tlv(struct wmi_ops *ops) +{ +} +#endif + +/** + * wmi_mlme_attach_tlv() - attach MLME tlv handlers + * @wmi_handle: wmi handle + * + * Return: void + */ +void wmi_mlme_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_csa_event_status_ind = csa_event_status_ind_tlv; + wmi_mlme_attach_ll_lt_sap_tlv(ops); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_roam_api.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_roam_api.c new file mode 100644 index 0000000000..f813cdabc2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_roam_api.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS +wmi_unified_set_gateway_params_cmd(wmi_unified_t wmi_handle, + struct gateway_update_req_param *req) +{ + if (wmi_handle->ops->send_set_gateway_params_cmd) + return wmi_handle->ops->send_set_gateway_params_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +#ifdef FEATURE_RSSI_MONITOR +QDF_STATUS +wmi_unified_set_rssi_monitoring_cmd(wmi_unified_t wmi_handle, + struct rssi_monitor_param *req) +{ + if (wmi_handle->ops->send_set_rssi_monitoring_cmd) + return wmi_handle->ops->send_set_rssi_monitoring_cmd(wmi_handle, + req); + + return QDF_STATUS_E_FAILURE; +} +#endif /* FEATURE_RSSI_MONITOR */ + +QDF_STATUS wmi_unified_roam_scan_offload_rssi_thresh_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *roam_req) +{ + if (wmi_handle->ops->send_roam_scan_offload_rssi_thresh_cmd) + return wmi_handle->ops->send_roam_scan_offload_rssi_thresh_cmd( + wmi_handle, roam_req); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_roam_scan_offload_scan_period( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_period_params *param) +{ + if (wmi_handle->ops->send_roam_scan_offload_scan_period_cmd) + return wmi_handle->ops->send_roam_scan_offload_scan_period_cmd( + wmi_handle, param); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_roam_mawc_params_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_mawc_params *params) +{ + if (wmi_handle->ops->send_roam_mawc_params_cmd) + return wmi_handle->ops->send_roam_mawc_params_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_roam_scan_filter_cmd(wmi_unified_t wmi_handle, + struct roam_scan_filter_params *roam_req) +{ + if (wmi_handle->ops->send_roam_scan_filter_cmd) + return wmi_handle->ops->send_roam_scan_filter_cmd(wmi_handle, + roam_req); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS wmi_unified_plm_stop_cmd(wmi_unified_t wmi_handle, + const struct plm_req_params *plm) +{ + if (wmi_handle->ops->send_plm_stop_cmd) + return wmi_handle->ops->send_plm_stop_cmd(wmi_handle, plm); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_plm_start_cmd(wmi_unified_t wmi_handle, + const struct plm_req_params *plm) +{ + if (wmi_handle->ops->send_plm_start_cmd) + return wmi_handle->ops->send_plm_start_cmd(wmi_handle, plm); + + return QDF_STATUS_E_FAILURE; +} +#endif /* FEATURE_WLAN_ESE */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wmi_unified_set_ric_req_cmd(wmi_unified_t wmi_handle, void *msg, + uint8_t is_add_ts) +{ + if (wmi_handle->ops->send_set_ric_req_cmd) + return wmi_handle->ops->send_set_ric_req_cmd(wmi_handle, msg, + is_add_ts); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_roam_synch_complete_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + if (wmi_handle->ops->send_process_roam_synch_complete_cmd) + return wmi_handle->ops->send_process_roam_synch_complete_cmd( + wmi_handle, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +QDF_STATUS +wmi_unified_roam_vendor_handoff_req_cmd(wmi_unified_t wmi_handle, + uint8_t vdev_id, uint32_t param_id) +{ + if (wmi_handle->ops->send_process_roam_vendor_handoff_req_cmd) + return wmi_handle->ops->send_process_roam_vendor_handoff_req_cmd( + wmi_handle, vdev_id, param_id); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_vendor_control_param_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + struct roam_vendor_handoff_params **data) +{ + if (wmi_handle->ops->extract_roam_vendor_control_param_event) + return wmi_handle->ops->extract_roam_vendor_control_param_event( + wmi_handle, event, len, data); + return QDF_STATUS_E_FAILURE; +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +QDF_STATUS +wmi_extract_roam_synch_key_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct wlan_crypto_key_entry **keys, + uint8_t *num_keys, + struct qdf_mac_addr *mld_addr) +{ + if (wmi_handle->ops->extract_roam_synch_key_event) + return wmi_handle->ops->extract_roam_synch_key_event( + wmi_handle, event, + len, keys, num_keys, + mld_addr); + + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS wmi_unified_roam_invoke_cmd(wmi_unified_t wmi_handle, + struct roam_invoke_req *roaminvoke) +{ + if (wmi_handle->ops->send_roam_invoke_cmd) + return wmi_handle->ops->send_roam_invoke_cmd(wmi_handle, + roaminvoke); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_send_disconnect_roam_params(wmi_unified_t wmi_handle, + struct wlan_roam_disconnect_params *req) +{ + if (wmi_handle->ops->send_disconnect_roam_params) + return wmi_handle->ops->send_disconnect_roam_params(wmi_handle, + req); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_send_idle_roam_params(wmi_unified_t wmi_handle, + struct wlan_roam_idle_params *req) +{ + if (wmi_handle->ops->send_idle_roam_params) + return wmi_handle->ops->send_idle_roam_params(wmi_handle, + req); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_send_roam_preauth_status(wmi_unified_t wmi_handle, + struct wmi_roam_auth_status_params *params) +{ + if (wmi_handle->ops->send_roam_preauth_status) + return wmi_handle->ops->send_roam_preauth_status(wmi_handle, + params); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_vdev_set_pcl_cmd(wmi_unified_t wmi_handle, + struct set_pcl_cmd_params *params) +{ + if (wmi_handle->ops->send_vdev_set_pcl_cmd) + return wmi_handle->ops->send_vdev_set_pcl_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +wmi_unified_roam_mlo_config_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_mlo_config *req) +{ + if (wmi_handle->ops->send_roam_mlo_config) + return wmi_handle->ops->send_roam_mlo_config(wmi_handle, + req); + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS wmi_unified_roam_scan_offload_mode_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_offload_params *rso_cfg) +{ + if (wmi_handle->ops->send_roam_scan_offload_mode_cmd) + return wmi_handle->ops->send_roam_scan_offload_mode_cmd( + wmi_handle, rso_cfg); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_send_roam_scan_offload_ap_cmd( + wmi_unified_t wmi_handle, + struct ap_profile_params *ap_profile) +{ + if (wmi_handle->ops->send_roam_scan_offload_ap_profile_cmd) + return wmi_handle->ops->send_roam_scan_offload_ap_profile_cmd( + wmi_handle, ap_profile); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_roam_scan_offload_cmd(wmi_unified_t wmi_handle, + uint32_t command, + uint32_t vdev_id) +{ + if (wmi_handle->ops->send_roam_scan_offload_cmd) + return wmi_handle->ops->send_roam_scan_offload_cmd(wmi_handle, + command, + vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_roam_scan_offload_chan_list_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_channel_list *rso_ch_info) +{ + if (wmi_handle->ops->send_roam_scan_offload_chan_list_cmd) + return wmi_handle->ops->send_roam_scan_offload_chan_list_cmd( + wmi_handle, rso_ch_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_roam_scan_offload_rssi_change_cmd( + wmi_unified_t wmi_handle, + struct wlan_roam_rssi_change_params *params) +{ + if (wmi_handle->ops->send_roam_scan_offload_rssi_change_cmd) + return wmi_handle->ops->send_roam_scan_offload_rssi_change_cmd( + wmi_handle, params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_set_per_roam_config(wmi_unified_t wmi_handle, + struct wlan_per_roam_config_req *req_buf) +{ + if (wmi_handle->ops->send_per_roam_config_cmd) + return wmi_handle->ops->send_per_roam_config_cmd(wmi_handle, + req_buf); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_send_limit_off_chan_cmd( + wmi_unified_t wmi_handle, + struct wmi_limit_off_chan_param *limit_off_chan_param) +{ + if (wmi_handle->ops->send_limit_off_chan_cmd) + return wmi_handle->ops->send_limit_off_chan_cmd(wmi_handle, + limit_off_chan_param); + + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS wmi_unified_roam_send_hlp_cmd(wmi_unified_t wmi_handle, + struct hlp_params *req_buf) +{ + if (wmi_handle->ops->send_roam_scan_hlp_cmd) + return wmi_handle->ops->send_roam_scan_hlp_cmd(wmi_handle, + req_buf); + + return QDF_STATUS_E_FAILURE; +} +#endif /* WLAN_FEATURE_FILS_SK */ + +QDF_STATUS wmi_unified_send_btm_config(wmi_unified_t wmi_handle, + struct wlan_roam_btm_config *params) +{ + if (wmi_handle->ops->send_btm_config) + return wmi_handle->ops->send_btm_config(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_send_bss_load_config( + wmi_unified_t wmi_handle, + struct wlan_roam_bss_load_config *params) +{ + if (wmi_handle->ops->send_roam_bss_load_config) + return wmi_handle->ops->send_roam_bss_load_config(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_offload_11k_cmd(wmi_unified_t wmi_handle, + struct wlan_roam_11k_offload_params *params) +{ + if (wmi_handle->ops->send_offload_11k_cmd) + return wmi_handle->ops->send_offload_11k_cmd(wmi_handle, + params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_invoke_neighbor_report_cmd( + wmi_unified_t wmi_handle, + struct wmi_invoke_neighbor_report_params *params) +{ + if (wmi_handle->ops->send_invoke_neighbor_report_cmd) + return wmi_handle->ops->send_invoke_neighbor_report_cmd( + wmi_handle, params); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_unified_get_roam_scan_ch_list(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + if (wmi_handle->ops->send_roam_scan_ch_list_req_cmd) + return wmi_handle->ops->send_roam_scan_ch_list_req_cmd( + wmi_handle, vdev_id); + + return QDF_STATUS_E_FAILURE; +} + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS +wmi_extract_roam_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t data_len, + struct roam_offload_roam_event *roam_event) +{ + if (wmi_handle->ops->extract_roam_event) + return wmi_handle->ops->extract_roam_event(wmi_handle, event, + data_len, + roam_event); + + return QDF_STATUS_E_FAILURE; +} +#endif /* WLAN_FEATURE_HOST_ROAM || WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wmi_unified_set_roam_triggers(wmi_unified_t wmi_handle, + struct wlan_roam_triggers *triggers) +{ + if (wmi_handle->ops->send_set_roam_trigger_cmd) + return wmi_handle->ops->send_set_roam_trigger_cmd(wmi_handle, + triggers); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_extract_roam_sync_event(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t len, + struct roam_offload_synch_ind **sync_ind) +{ + if (wmi_handle->ops->extract_roam_sync_event) + return wmi_handle->ops->extract_roam_sync_event(wmi_handle, + evt_buf, + len, + sync_ind); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_sync_frame_event(wmi_unified_t wmi_handle, void *event, + uint32_t len, + struct roam_synch_frame_ind *frame_ptr) +{ + if (wmi_handle->ops->extract_roam_sync_frame_event) + return wmi_handle->ops->extract_roam_sync_frame_event(wmi_handle, + event, + len, + frame_ptr); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_btm_denylist_event(wmi_unified_t wmi_handle, + uint8_t *event, + uint32_t data_len, + struct roam_denylist_event **dst_list) +{ + if (wmi_handle->ops->extract_btm_dl_event) + return wmi_handle->ops->extract_btm_dl_event(wmi_handle, + event, + data_len, + dst_list); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_vdev_disconnect_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct vdev_disconnect_event_data *data) +{ + if (wmi_handle->ops->extract_vdev_disconnect_event) + return wmi_handle->ops->extract_vdev_disconnect_event( + wmi_handle, event, data_len, data); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_scan_chan_list(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct cm_roam_scan_ch_resp **data) +{ + if (wmi_handle->ops->extract_roam_scan_chan_list) + return wmi_handle->ops->extract_roam_scan_chan_list( + wmi_handle, event, data_len, data); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_extract_roam_btm_response(wmi_unified_t wmi, void *evt_buf, + struct roam_btm_response_data *dst, + uint8_t idx) +{ + if (wmi->ops->extract_roam_btm_response_stats) + return wmi->ops->extract_roam_btm_response_stats(wmi, evt_buf, + dst, idx); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_extract_roam_initial_info(wmi_unified_t wmi, void *evt_buf, + struct roam_initial_data *dst, + uint8_t idx) +{ + if (wmi->ops->extract_roam_initial_info) + return wmi->ops->extract_roam_initial_info(wmi, evt_buf, + dst, idx); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_extract_roam_msg_info(wmi_unified_t wmi, void *evt_buf, + struct roam_msg_info *dst, uint8_t idx) +{ + if (wmi->ops->extract_roam_msg_info) + return wmi->ops->extract_roam_msg_info(wmi, evt_buf, dst, idx); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_unified_extract_roam_extract_frame_info(wmi_unified_t wmi, void *evt_buf, + struct roam_frame_stats *dst, + uint8_t idx, uint8_t num_frames) +{ + if (wmi->ops->extract_roam_frame_info) + return wmi->ops->extract_roam_frame_info(wmi, evt_buf, + dst, idx, num_frames); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_stats_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct roam_stats_event **stats_info) +{ + if (wmi_handle->ops->extract_roam_stats_event) + return wmi_handle->ops->extract_roam_stats_event(wmi_handle, + event, + data_len, + stats_info); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_auth_offload_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct auth_offload_event *auth_event) +{ + if (wmi_handle->ops->extract_auth_offload_event) + return wmi_handle->ops->extract_auth_offload_event(wmi_handle, + event, + data_len, + auth_event); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_pmkid_request(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct roam_pmkid_req_event **list) +{ + if (wmi_handle->ops->extract_roam_pmkid_request) + return wmi_handle->ops->extract_roam_pmkid_request(wmi_handle, + event, + data_len, + list); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS +wmi_extract_roam_candidate_frame_event(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct roam_scan_candidate_frame *data) +{ + if (wmi_handle->ops->extract_roam_candidate_frame) + return wmi_handle->ops->extract_roam_candidate_frame( + wmi_handle, + event, + len, data); + return QDF_STATUS_E_FAILURE; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_roam_tlv.c b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_roam_tlv.c new file mode 100644 index 0000000000..39203a7292 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/components/wmi/src/wmi_unified_roam_tlv.c @@ -0,0 +1,6394 @@ +/* + * Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to roaming component. + */ + +#include +#include +#include +#include "wmi.h" +#include "wlan_roam_debug.h" +#include "ol_defines.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlme_api.h" +#include "wlan_crypto_global_api.h" + +#define WMI_MAC_TO_PDEV_MAP(x) ((x) + (1)) +#define WMI_PDEV_TO_MAC_MAP(x) ((x) - (1)) + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * send_set_gateway_params_cmd_tlv() - set gateway parameters + * @wmi_handle: wmi handle + * @req: gateway parameter update request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and sends down the gateway configs down to the firmware + * + * Return: QDF_STATUS + */ +static QDF_STATUS send_set_gateway_params_cmd_tlv(wmi_unified_t wmi_handle, + struct gateway_update_req_param *req) +{ + wmi_roam_subnet_change_config_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS ret; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_subnet_change_config_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_subnet_change_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_roam_subnet_change_config_fixed_param)); + + cmd->vdev_id = req->vdev_id; + qdf_mem_copy(&cmd->inet_gw_ip_v4_addr, req->ipv4_addr, + QDF_IPV4_ADDR_SIZE); + qdf_mem_copy(&cmd->inet_gw_ip_v6_addr, req->ipv6_addr, + QDF_IPV6_ADDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(req->gw_mac_addr.bytes, + &cmd->inet_gw_mac_addr); + cmd->max_retries = req->max_retries; + cmd->timeout = req->timeout; + cmd->num_skip_subnet_change_detection_bssid_list = 0; + cmd->flag = 0; + if (req->ipv4_addr_type) + WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP4_ENABLED(cmd->flag); + + if (req->ipv6_addr_type) + WMI_SET_ROAM_SUBNET_CHANGE_FLAG_IP6_ENABLED(cmd->flag); + + wmi_mtrace(WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID, cmd->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_SUBNET_CHANGE_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + wmi_err("Failed to send gw config parameter to fw, ret: %d", + ret); + wmi_buf_free(buf); + } + + return ret; +} + +void wmi_lfr_subnet_detection_attach_tlv(struct wmi_unified *wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_set_gateway_params_cmd = send_set_gateway_params_cmd_tlv; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +#ifdef FEATURE_RSSI_MONITOR +/** + * send_set_rssi_monitoring_cmd_tlv() - set rssi monitoring + * @wmi_handle: wmi handle + * @req: rssi monitoring request structure + * + * This function reads the incoming @req and fill in the destination + * WMI structure and send down the rssi monitoring configs down to the firmware + * + * Return: 0 on success; error number otherwise + */ +static QDF_STATUS send_set_rssi_monitoring_cmd_tlv(wmi_unified_t wmi_handle, + struct rssi_monitor_param *req) +{ + wmi_rssi_breach_monitor_config_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS ret; + uint32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_rssi_breach_monitor_config_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rssi_breach_monitor_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_rssi_breach_monitor_config_fixed_param)); + + cmd->vdev_id = req->vdev_id; + cmd->request_id = req->request_id; + cmd->lo_rssi_reenable_hysteresis = 0; + cmd->hi_rssi_reenable_histeresis = 0; + cmd->min_report_interval = 0; + cmd->max_num_report = 1; + if (req->control) { + /* enable one threshold for each min/max */ + cmd->enabled_bitmap = 0x09; + cmd->low_rssi_breach_threshold[0] = req->min_rssi; + cmd->hi_rssi_breach_threshold[0] = req->max_rssi; + } else { + cmd->enabled_bitmap = 0; + cmd->low_rssi_breach_threshold[0] = 0; + cmd->hi_rssi_breach_threshold[0] = 0; + } + + wmi_mtrace(WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID, cmd->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + wmi_err("Failed to send WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID"); + wmi_buf_free(buf); + } + + wmi_debug("Sent WMI_RSSI_BREACH_MONITOR_CONFIG_CMDID to FW"); + + return ret; +} + +void wmi_rssi_monitor_attach_tlv(struct wmi_unified *wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_set_rssi_monitoring_cmd = send_set_rssi_monitoring_cmd_tlv; +} +#endif /* FEATURE_RSSI_MONITOR */ + +/** + * send_roam_scan_offload_rssi_thresh_cmd_tlv() - set scan offload + * rssi threshold + * @wmi_handle: wmi handle + * @roam_req: Roaming request buffer + * + * Send WMI_ROAM_SCAN_RSSI_THRESHOLD TLV to firmware + * + * Return: QDF status + */ +static QDF_STATUS send_roam_scan_offload_rssi_thresh_cmd_tlv( + wmi_unified_t wmi_handle, + struct wlan_roam_offload_scan_rssi_params *roam_req) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_rssi_threshold_fixed_param *rssi_threshold_fp; + wmi_roam_scan_extended_threshold_param *ext_thresholds = NULL; + wmi_roam_earlystop_rssi_thres_param *early_stop_thresholds = NULL; + wmi_roam_dense_thres_param *dense_thresholds = NULL; + wmi_roam_bg_scan_roaming_param *bg_scan_params = NULL; + wmi_roam_data_rssi_roaming_param *data_rssi_param = NULL; + + len = sizeof(wmi_roam_scan_rssi_threshold_fixed_param); + len += WMI_TLV_HDR_SIZE; /* TLV for ext_thresholds*/ + len += sizeof(wmi_roam_scan_extended_threshold_param); + len += WMI_TLV_HDR_SIZE; + len += sizeof(wmi_roam_earlystop_rssi_thres_param); + len += WMI_TLV_HDR_SIZE; /* TLV for dense thresholds*/ + len += sizeof(wmi_roam_dense_thres_param); + len += WMI_TLV_HDR_SIZE; /* TLV for BG Scan*/ + len += sizeof(wmi_roam_bg_scan_roaming_param); + len += WMI_TLV_HDR_SIZE; /* TLV for data RSSI*/ + len += sizeof(wmi_roam_data_rssi_roaming_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + rssi_threshold_fp = + (wmi_roam_scan_rssi_threshold_fixed_param *)buf_ptr; + WMITLV_SET_HDR( + &rssi_threshold_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_threshold_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_rssi_threshold_fixed_param)); + /* fill in threshold values */ + rssi_threshold_fp->vdev_id = roam_req->vdev_id; + rssi_threshold_fp->roam_scan_rssi_thresh = roam_req->rssi_thresh; + rssi_threshold_fp->roam_rssi_thresh_diff = roam_req->rssi_thresh_diff; + rssi_threshold_fp->hirssi_scan_max_count = + roam_req->hi_rssi_scan_max_count; + rssi_threshold_fp->hirssi_scan_delta = + roam_req->hi_rssi_scan_rssi_delta; + rssi_threshold_fp->hirssi_upper_bound = roam_req->hi_rssi_scan_rssi_ub; + rssi_threshold_fp->rssi_thresh_offset_5g = + roam_req->rssi_thresh_offset_5g; + rssi_threshold_fp->flags = roam_req->flags; + + buf_ptr += sizeof(wmi_roam_scan_rssi_threshold_fixed_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_scan_extended_threshold_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + ext_thresholds = (wmi_roam_scan_extended_threshold_param *)buf_ptr; + + ext_thresholds->penalty_threshold_5g = roam_req->penalty_threshold_5g; + if (roam_req->raise_rssi_thresh_5g >= WMI_NOISE_FLOOR_DBM_DEFAULT) + ext_thresholds->boost_threshold_5g = + roam_req->boost_threshold_5g; + + ext_thresholds->boost_algorithm_5g = + WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR; + ext_thresholds->boost_factor_5g = roam_req->raise_factor_5g; + ext_thresholds->penalty_algorithm_5g = + WMI_ROAM_5G_BOOST_PENALIZE_ALGO_LINEAR; + ext_thresholds->penalty_factor_5g = roam_req->drop_factor_5g; + ext_thresholds->max_boost_5g = roam_req->max_raise_rssi_5g; + ext_thresholds->max_penalty_5g = roam_req->max_drop_rssi_5g; + ext_thresholds->good_rssi_threshold = roam_req->good_rssi_threshold; + + WMITLV_SET_HDR(&ext_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_extended_threshold_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_extended_threshold_param)); + buf_ptr += sizeof(wmi_roam_scan_extended_threshold_param); + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_earlystop_rssi_thres_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + early_stop_thresholds = (wmi_roam_earlystop_rssi_thres_param *)buf_ptr; + early_stop_thresholds->roam_earlystop_thres_min = + roam_req->roam_earlystop_thres_min; + early_stop_thresholds->roam_earlystop_thres_max = + roam_req->roam_earlystop_thres_max; + WMITLV_SET_HDR(&early_stop_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_earlystop_rssi_thres_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_earlystop_rssi_thres_param)); + + buf_ptr += sizeof(wmi_roam_earlystop_rssi_thres_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_dense_thres_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + dense_thresholds = (wmi_roam_dense_thres_param *)buf_ptr; + dense_thresholds->roam_dense_rssi_thres_offset = + roam_req->dense_rssi_thresh_offset; + dense_thresholds->roam_dense_min_aps = roam_req->dense_min_aps_cnt; + dense_thresholds->roam_dense_traffic_thres = + roam_req->traffic_threshold; + dense_thresholds->roam_dense_status = roam_req->initial_dense_status; + WMITLV_SET_HDR(&dense_thresholds->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_dense_thres_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_dense_thres_param)); + + buf_ptr += sizeof(wmi_roam_dense_thres_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_bg_scan_roaming_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + bg_scan_params = (wmi_roam_bg_scan_roaming_param *)buf_ptr; + bg_scan_params->roam_bg_scan_bad_rssi_thresh = + roam_req->bg_scan_bad_rssi_thresh; + bg_scan_params->roam_bg_scan_client_bitmap = + roam_req->bg_scan_client_bitmap; + bg_scan_params->bad_rssi_thresh_offset_2g = + roam_req->roam_bad_rssi_thresh_offset_2g; + + bg_scan_params->flags = 0; + if (roam_req->roam_bad_rssi_thresh_offset_2g) + bg_scan_params->flags |= WMI_ROAM_BG_SCAN_FLAGS_2G_TO_5G_ONLY; + WMITLV_SET_HDR(&bg_scan_params->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_bg_scan_roaming_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_bg_scan_roaming_param)); + + buf_ptr += sizeof(wmi_roam_bg_scan_roaming_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_data_rssi_roaming_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + data_rssi_param = (wmi_roam_data_rssi_roaming_param *)buf_ptr; + data_rssi_param->flags = + roam_req->roam_data_rssi_threshold_triggers; + data_rssi_param->roam_data_rssi_thres = + roam_req->roam_data_rssi_threshold; + data_rssi_param->rx_inactivity_ms = + roam_req->rx_data_inactivity_time; + WMITLV_SET_HDR(&data_rssi_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_data_rssi_roaming_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_data_rssi_roaming_param)); + wmi_debug("vdev %d Data rssi threshold: %d, triggers: 0x%x, rx time: %d, rssi_thresh:%d", + rssi_threshold_fp->vdev_id, + data_rssi_param->roam_data_rssi_thres, + data_rssi_param->flags, + data_rssi_param->rx_inactivity_ms, + rssi_threshold_fp->roam_scan_rssi_thresh); + + wmi_mtrace(WMI_ROAM_SCAN_RSSI_THRESHOLD, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_RSSI_THRESHOLD); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("cmd WMI_ROAM_SCAN_RSSI_THRESHOLD returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_roam_scan_offload_scan_period_cmd_tlv() - set roam offload scan period + * @wmi_handle: wmi handle + * @param: roam scan parameters to be sent to firmware + * + * Send WMI_ROAM_SCAN_PERIOD parameters to fw. + * + * Return: QDF status + */ +static QDF_STATUS +send_roam_scan_offload_scan_period_cmd_tlv( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_period_params *param) +{ + QDF_STATUS status; + wmi_buf_t buf = NULL; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_period_fixed_param *scan_period_fp; + + /* Send scan period values */ + len = sizeof(wmi_roam_scan_period_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + scan_period_fp = (wmi_roam_scan_period_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&scan_period_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_period_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_period_fixed_param)); + /* fill in scan period values */ + scan_period_fp->vdev_id = param->vdev_id; + scan_period_fp->roam_scan_period = param->scan_period; + scan_period_fp->roam_scan_age = param->scan_age; + scan_period_fp->inactivity_time_period = + param->roam_scan_inactivity_time; + scan_period_fp->roam_inactive_count = + param->roam_inactive_data_packet_count; + /* Firmware expects the full scan period in msec whereas host + * provides the same in seconds. + * Convert it to msec and send to firmware + */ + scan_period_fp->roam_full_scan_period = param->full_scan_period * 1000; + + wmi_debug("roam_scan_period=%d, roam_scan_age=%d, full_scan_period= %u", + scan_period_fp->roam_scan_period, + scan_period_fp->roam_scan_age, + scan_period_fp->roam_full_scan_period); + + wmi_debug("inactiviy time:%d inactive cnt:%d", + scan_period_fp->inactivity_time_period, + scan_period_fp->roam_inactive_count); + + wmi_mtrace(WMI_ROAM_SCAN_PERIOD, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_SCAN_PERIOD); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_buf_free(buf); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS send_roam_mawc_params_cmd_tlv( + wmi_unified_t wmi_handle, + struct wlan_roam_mawc_params *params) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_configure_mawc_cmd_fixed_param *wmi_roam_mawc_params; + + len = sizeof(*wmi_roam_mawc_params); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + wmi_roam_mawc_params = + (wmi_roam_configure_mawc_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&wmi_roam_mawc_params->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_configure_mawc_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_configure_mawc_cmd_fixed_param)); + wmi_roam_mawc_params->vdev_id = params->vdev_id; + if (params->enable) + wmi_roam_mawc_params->enable = 1; + else + wmi_roam_mawc_params->enable = 0; + wmi_roam_mawc_params->traffic_load_threshold = + params->traffic_load_threshold; + wmi_roam_mawc_params->best_ap_rssi_threshold = + params->best_ap_rssi_threshold; + wmi_roam_mawc_params->rssi_stationary_high_adjust = + params->rssi_stationary_high_adjust; + wmi_roam_mawc_params->rssi_stationary_low_adjust = + params->rssi_stationary_low_adjust; + wmi_debug("MAWC roam en=%d, vdev=%d, tr=%d, ap=%d, high=%d, low=%d", + wmi_roam_mawc_params->enable, wmi_roam_mawc_params->vdev_id, + wmi_roam_mawc_params->traffic_load_threshold, + wmi_roam_mawc_params->best_ap_rssi_threshold, + wmi_roam_mawc_params->rssi_stationary_high_adjust, + wmi_roam_mawc_params->rssi_stationary_low_adjust); + + wmi_mtrace(WMI_ROAM_CONFIGURE_MAWC_CMDID, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_CONFIGURE_MAWC_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("WMI_ROAM_CONFIGURE_MAWC_CMDID failed, Error %d", + status); + wmi_buf_free(buf); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_scan_filter_cmd_tlv() - Filter to be applied while roaming + * @wmi_handle: wmi handle + * @roam_req: Request which contains the filters + * + * There are filters such as allowlist, denylist and preferred + * list that need to be applied to the scan results to form the + * probable candidates for roaming. + * + * Return: Return success upon successfully passing the + * parameters to the firmware, otherwise failure. + */ +static QDF_STATUS send_roam_scan_filter_cmd_tlv(wmi_unified_t wmi_handle, + struct roam_scan_filter_params *roam_req) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + uint32_t i; + uint32_t len, blist_len = 0; + uint8_t *buf_ptr; + wmi_roam_filter_fixed_param *roam_filter; + uint8_t *bssid_src_ptr = NULL; + wmi_mac_addr *bssid_dst_ptr = NULL; + wmi_ssid *ssid_ptr = NULL; + uint32_t *bssid_preferred_factor_ptr = NULL; + wmi_roam_lca_disallow_config_tlv_param *blist_param; + wmi_roam_rssi_rejection_oce_config_param *rssi_rej; + + len = sizeof(wmi_roam_filter_fixed_param); + + len += WMI_TLV_HDR_SIZE; + if (roam_req->num_bssid_deny_list) + len += roam_req->num_bssid_deny_list * sizeof(wmi_mac_addr); + len += WMI_TLV_HDR_SIZE; + if (roam_req->num_ssid_allow_list) + len += roam_req->num_ssid_allow_list * sizeof(wmi_ssid); + len += 2 * WMI_TLV_HDR_SIZE; + if (roam_req->num_bssid_preferred_list) { + len += (roam_req->num_bssid_preferred_list * + sizeof(wmi_mac_addr)); + len += roam_req->num_bssid_preferred_list * sizeof(uint32_t); + } + len += WMI_TLV_HDR_SIZE; + if (roam_req->lca_disallow_config_present) { + len += sizeof(*blist_param); + blist_len = sizeof(*blist_param); + } + + len += WMI_TLV_HDR_SIZE; + if (roam_req->num_rssi_rejection_ap) + len += roam_req->num_rssi_rejection_ap * sizeof(*rssi_rej); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *)wmi_buf_data(buf); + roam_filter = (wmi_roam_filter_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&roam_filter->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_filter_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_filter_fixed_param)); + /* fill in fixed values */ + roam_filter->vdev_id = roam_req->vdev_id; + roam_filter->flags = 0; + roam_filter->op_bitmap = roam_req->op_bitmap; + roam_filter->num_bssid_black_list = roam_req->num_bssid_deny_list; + roam_filter->num_ssid_white_list = roam_req->num_ssid_allow_list; + roam_filter->num_bssid_preferred_list = + roam_req->num_bssid_preferred_list; + roam_filter->num_rssi_rejection_ap = + roam_req->num_rssi_rejection_ap; + roam_filter->delta_rssi = roam_req->delta_rssi; + buf_ptr += sizeof(wmi_roam_filter_fixed_param); + + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (roam_req->num_bssid_deny_list * sizeof(wmi_mac_addr))); + bssid_src_ptr = (uint8_t *)&roam_req->bssid_avoid_list; + bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_bssid_deny_list; i++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, bssid_dst_ptr); + bssid_src_ptr += ATH_MAC_LEN; + bssid_dst_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (roam_req->num_bssid_deny_list * sizeof(wmi_mac_addr)); + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (roam_req->num_ssid_allow_list * sizeof(wmi_ssid))); + ssid_ptr = (wmi_ssid *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_ssid_allow_list; i++) { + qdf_mem_copy(&ssid_ptr->ssid, + &roam_req->ssid_allowed_list[i].ssid, + roam_req->ssid_allowed_list[i].length); + ssid_ptr->ssid_len = roam_req->ssid_allowed_list[i].length; + ssid_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + (roam_req->num_ssid_allow_list * + sizeof(wmi_ssid)); + WMITLV_SET_HDR((buf_ptr), + WMITLV_TAG_ARRAY_FIXED_STRUC, + (roam_req->num_bssid_preferred_list * sizeof(wmi_mac_addr))); + bssid_src_ptr = (uint8_t *)&roam_req->bssid_favored; + bssid_dst_ptr = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_bssid_preferred_list; i++) { + WMI_CHAR_ARRAY_TO_MAC_ADDR(bssid_src_ptr, + (wmi_mac_addr *)bssid_dst_ptr); + bssid_src_ptr += ATH_MAC_LEN; + bssid_dst_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (roam_req->num_bssid_preferred_list * sizeof(wmi_mac_addr)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (roam_req->num_bssid_preferred_list * sizeof(uint32_t))); + bssid_preferred_factor_ptr = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < roam_req->num_bssid_preferred_list; i++) { + *bssid_preferred_factor_ptr = + roam_req->bssid_favored_factor[i]; + bssid_preferred_factor_ptr++; + } + buf_ptr += WMI_TLV_HDR_SIZE + + (roam_req->num_bssid_preferred_list * sizeof(uint32_t)); + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, blist_len); + buf_ptr += WMI_TLV_HDR_SIZE; + if (roam_req->lca_disallow_config_present) { + blist_param = + (wmi_roam_lca_disallow_config_tlv_param *)buf_ptr; + WMITLV_SET_HDR(&blist_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_lca_disallow_config_tlv_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_roam_lca_disallow_config_tlv_param)); + + blist_param->disallow_duration = roam_req->disallow_duration; + blist_param->rssi_channel_penalization = + roam_req->rssi_channel_penalization; + blist_param->num_disallowed_aps = roam_req->num_disallowed_aps; + blist_param->disallow_lca_enable_source_bitmap = + (WMI_ROAM_LCA_DISALLOW_SOURCE_PER | + WMI_ROAM_LCA_DISALLOW_SOURCE_BACKGROUND); + buf_ptr += (sizeof(wmi_roam_lca_disallow_config_tlv_param)); + } + + WMITLV_SET_HDR(buf_ptr, + WMITLV_TAG_ARRAY_STRUC, + (roam_req->num_rssi_rejection_ap * sizeof(*rssi_rej))); + buf_ptr += WMI_TLV_HDR_SIZE; + for (i = 0; i < roam_req->num_rssi_rejection_ap; i++) { + rssi_rej = + (wmi_roam_rssi_rejection_oce_config_param *)buf_ptr; + + WMITLV_SET_HDR(&rssi_rej->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_rssi_rejection_oce_config_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_rssi_rejection_oce_config_param)); + + WMI_CHAR_ARRAY_TO_MAC_ADDR( + roam_req->rssi_rejection_ap[i].bssid.bytes, + &rssi_rej->bssid); + rssi_rej->remaining_disallow_duration = + roam_req->rssi_rejection_ap[i].reject_duration; + rssi_rej->requested_rssi = + (int32_t)roam_req->rssi_rejection_ap[i].expected_rssi; + buf_ptr += + (sizeof(wmi_roam_rssi_rejection_oce_config_param)); + } + + wmi_mtrace(WMI_ROAM_FILTER_CMDID, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_FILTER_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("cmd WMI_ROAM_FILTER_CMDID returned Error %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +#ifdef FEATURE_WLAN_ESE +/** + * send_plm_stop_cmd_tlv() - plm stop request + * @wmi_handle: wmi handle + * @plm: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: CDF status + */ +static QDF_STATUS send_plm_stop_cmd_tlv(wmi_unified_t wmi_handle, + const struct plm_req_params *plm) +{ + wmi_vdev_plmreq_stop_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_vdev_plmreq_stop_cmd_fixed_param *)wmi_buf_data(buf); + + buf_ptr = (uint8_t *)cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_plmreq_stop_cmd_fixed_param)); + + cmd->vdev_id = plm->vdev_id; + + cmd->meas_token = plm->meas_token; + wmi_debug("vdev %d meas token %d", cmd->vdev_id, cmd->meas_token); + + wmi_mtrace(WMI_VDEV_PLMREQ_STOP_CMDID, cmd->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_PLMREQ_STOP_CMDID); + if (ret) { + wmi_err("Failed to send plm stop wmi cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_plm_start_cmd_tlv() - plm start request + * @wmi_handle: wmi handle + * @plm: plm request parameters + * + * This function request FW to start PLM. + * + * Return: CDF status + */ +static QDF_STATUS send_plm_start_cmd_tlv(wmi_unified_t wmi_handle, + const struct plm_req_params *plm) +{ + wmi_vdev_plmreq_start_cmd_fixed_param *cmd; + uint32_t *channel_list; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint8_t count; + int ret; + + /* TLV place holder for channel_list */ + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + len += sizeof(uint32_t) * plm->plm_num_ch; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_vdev_plmreq_start_cmd_fixed_param *)wmi_buf_data(buf); + + buf_ptr = (uint8_t *)cmd; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_plmreq_start_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_vdev_plmreq_start_cmd_fixed_param)); + + cmd->vdev_id = plm->vdev_id; + + cmd->meas_token = plm->meas_token; + cmd->dialog_token = plm->diag_token; + cmd->number_bursts = plm->num_bursts; + cmd->burst_interval = WMI_SEC_TO_MSEC(plm->burst_int); + cmd->off_duration = plm->meas_duration; + cmd->burst_cycle = plm->burst_len; + cmd->tx_power = plm->desired_tx_pwr; + WMI_CHAR_ARRAY_TO_MAC_ADDR(plm->mac_addr.bytes, &cmd->dest_mac); + cmd->num_chans = plm->plm_num_ch; + + buf_ptr += sizeof(wmi_vdev_plmreq_start_cmd_fixed_param); + + wmi_debug("vdev: %d measu token: %d dialog_token: %d number_bursts: %d burst_interval: %d off_duration: %d burst_cycle: %d tx_power: %d Number of channels: %d", + cmd->vdev_id, cmd->meas_token, cmd->dialog_token, + cmd->number_bursts, cmd->burst_interval, cmd->off_duration, + cmd->burst_cycle, cmd->tx_power, cmd->num_chans); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (cmd->num_chans * sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + if (cmd->num_chans) { + channel_list = (uint32_t *)buf_ptr; + for (count = 0; count < cmd->num_chans; count++) { + channel_list[count] = plm->plm_ch_freq_list[count]; + wmi_debug("Ch[%d]: %d MHz", count, channel_list[count]); + } + buf_ptr += cmd->num_chans * sizeof(uint32_t); + } + + wmi_mtrace(WMI_VDEV_PLMREQ_START_CMDID, cmd->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_PLMREQ_START_CMDID); + if (ret) { + wmi_err("Failed to send plm start wmi cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void wmi_ese_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_plm_stop_cmd = send_plm_stop_cmd_tlv; + ops->send_plm_start_cmd = send_plm_start_cmd_tlv; +} +#endif /* FEATURE_WLAN_ESE */ + +/** + * convert_roam_trigger_reason() - Function to convert unified Roam trigger + * enum to TLV specific WMI_ROAM_TRIGGER_REASON_ID + * @trigger_reason: Roam trigger reason + * + * Return: WMI roam trigger reason + */ +static uint32_t +convert_roam_trigger_reason(enum roam_trigger_reason trigger_reason) +{ + switch (trigger_reason) { + case ROAM_TRIGGER_REASON_NONE: + return WMI_ROAM_TRIGGER_REASON_NONE; + case ROAM_TRIGGER_REASON_PER: + return WMI_ROAM_TRIGGER_REASON_PER; + case ROAM_TRIGGER_REASON_BMISS: + return WMI_ROAM_TRIGGER_REASON_BMISS; + case ROAM_TRIGGER_REASON_LOW_RSSI: + return WMI_ROAM_TRIGGER_REASON_LOW_RSSI; + case ROAM_TRIGGER_REASON_HIGH_RSSI: + return WMI_ROAM_TRIGGER_REASON_HIGH_RSSI; + case ROAM_TRIGGER_REASON_PERIODIC: + return WMI_ROAM_TRIGGER_REASON_PERIODIC; + case ROAM_TRIGGER_REASON_MAWC: + return WMI_ROAM_TRIGGER_REASON_MAWC; + case ROAM_TRIGGER_REASON_DENSE: + return WMI_ROAM_TRIGGER_REASON_DENSE; + case ROAM_TRIGGER_REASON_BACKGROUND: + return WMI_ROAM_TRIGGER_REASON_BACKGROUND; + case ROAM_TRIGGER_REASON_FORCED: + return WMI_ROAM_TRIGGER_REASON_FORCED; + case ROAM_TRIGGER_REASON_BTM: + return WMI_ROAM_TRIGGER_REASON_BTM; + case ROAM_TRIGGER_REASON_UNIT_TEST: + return WMI_ROAM_TRIGGER_REASON_UNIT_TEST; + case ROAM_TRIGGER_REASON_BSS_LOAD: + return WMI_ROAM_TRIGGER_REASON_BSS_LOAD; + case ROAM_TRIGGER_REASON_DEAUTH: + return WMI_ROAM_TRIGGER_REASON_DEAUTH; + case ROAM_TRIGGER_REASON_IDLE: + return WMI_ROAM_TRIGGER_REASON_IDLE; + case ROAM_TRIGGER_REASON_STA_KICKOUT: + return WMI_ROAM_TRIGGER_REASON_STA_KICKOUT; + case ROAM_TRIGGER_REASON_ESS_RSSI: + return WMI_ROAM_TRIGGER_REASON_ESS_RSSI; + case ROAM_TRIGGER_REASON_WTC_BTM: + return WMI_ROAM_TRIGGER_REASON_WTC_BTM; + case ROAM_TRIGGER_REASON_PMK_TIMEOUT: + return WMI_ROAM_TRIGGER_REASON_PMK_TIMEOUT; + case ROAM_TRIGGER_REASON_BTC: + return WMI_ROAM_TRIGGER_REASON_BTC; + case ROAM_TRIGGER_REASON_MAX: + return WMI_ROAM_TRIGGER_REASON_MAX; + default: + return WMI_ROAM_TRIGGER_REASON_NONE; + } +} + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +static char *wmi_get_roam_event_reason_string(uint32_t reason) +{ + switch (reason) { + case WMI_ROAM_REASON_INVALID: + return "Default"; + case WMI_ROAM_REASON_BETTER_AP: + return "Better AP"; + case WMI_ROAM_REASON_BMISS: + return "BMISS"; + case WMI_ROAM_REASON_LOW_RSSI: + return "Low Rssi"; + case WMI_ROAM_REASON_SUITABLE_AP: + return "Suitable AP"; + case WMI_ROAM_REASON_HO_FAILED: + return "Hand-off Failed"; + case WMI_ROAM_REASON_INVOKE_ROAM_FAIL: + return "Roam Invoke failed"; + case WMI_ROAM_REASON_RSO_STATUS: + return "RSO status"; + case WMI_ROAM_REASON_BTM: + return "BTM"; + case WMI_ROAM_REASON_DEAUTH: + return "Deauth"; + default: + return "Invalid"; + } + + return "Invalid"; +} + +static enum roam_reason +wmi_convert_fw_reason_to_cm_reason(uint32_t reason) +{ + switch (reason) { + case WMI_ROAM_REASON_INVALID: + return ROAM_REASON_INVALID; + case WMI_ROAM_REASON_BETTER_AP: + return ROAM_REASON_BETTER_AP; + case WMI_ROAM_REASON_BMISS: + return ROAM_REASON_BMISS; + case WMI_ROAM_REASON_LOW_RSSI: + return ROAM_REASON_LOW_RSSI; + case WMI_ROAM_REASON_SUITABLE_AP: + return ROAM_REASON_SUITABLE_AP; + case WMI_ROAM_REASON_HO_FAILED: + return ROAM_REASON_HO_FAILED; + case WMI_ROAM_REASON_INVOKE_ROAM_FAIL: + return ROAM_REASON_INVOKE_ROAM_FAIL; + case WMI_ROAM_REASON_RSO_STATUS: + return ROAM_REASON_RSO_STATUS; + case WMI_ROAM_REASON_BTM: + return ROAM_REASON_BTM; + case WMI_ROAM_REASON_DEAUTH: + return ROAM_REASON_DEAUTH; + default: + return ROAM_REASON_INVALID; + } + + return ROAM_REASON_INVALID; +} + +static enum cm_roam_notif +wmi_convert_fw_notif_to_cm_notif(uint32_t fw_notif) +{ + switch (fw_notif) { + case WMI_ROAM_NOTIF_ROAM_START: + return CM_ROAM_NOTIF_ROAM_START; + case WMI_ROAM_NOTIF_ROAM_ABORT: + return CM_ROAM_NOTIF_ROAM_ABORT; + case WMI_ROAM_NOTIF_ROAM_REASSOC: + return CM_ROAM_NOTIF_ROAM_REASSOC; + case WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS: + return CM_ROAM_NOTIF_SCAN_MODE_SUCCESS; + case WMI_ROAM_NOTIF_SCAN_MODE_FAIL: + return CM_ROAM_NOTIF_SCAN_MODE_FAIL; + case WMI_ROAM_NOTIF_DISCONNECT: + return CM_ROAM_NOTIF_DISCONNECT; + case WMI_ROAM_NOTIF_SUBNET_CHANGED: + return CM_ROAM_NOTIF_SUBNET_CHANGED; + case WMI_ROAM_NOTIF_SCAN_START: + return CM_ROAM_NOTIF_SCAN_START; + case WMI_ROAM_NOTIF_DEAUTH_RECV: + return CM_ROAM_NOTIF_DEAUTH_RECV; + case WMI_ROAM_NOTIF_DISASSOC_RECV: + return CM_ROAM_NOTIF_DISASSOC_RECV; + case WMI_ROAM_NOTIF_SCAN_MODE_SUCCESS_WITH_HO_FAIL: + return CM_ROAM_NOTIF_HO_FAIL; + case WMI_ROAM_NOTIF_SCAN_END: + return CM_ROAM_NOTIF_SCAN_END; + default: + return CM_ROAM_NOTIF_INVALID; + } + + return CM_ROAM_NOTIF_INVALID; +} + +static void +wmi_extract_pdev_hw_mode_trans_ind( + wmi_pdev_hw_mode_transition_event_fixed_param *fixed_param, + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind) +{ + uint32_t i; + + if (fixed_param->num_vdev_mac_entries > MAX_VDEV_SUPPORTED) { + wmi_err("Number of Vdev mac entries %d exceeded max vdev supported %d", + fixed_param->num_vdev_mac_entries, + MAX_VDEV_SUPPORTED); + return; + } + hw_mode_trans_ind->old_hw_mode_index = fixed_param->old_hw_mode_index; + hw_mode_trans_ind->new_hw_mode_index = fixed_param->new_hw_mode_index; + hw_mode_trans_ind->num_vdev_mac_entries = + fixed_param->num_vdev_mac_entries; + wmi_debug("old_hw_mode_index:%d new_hw_mode_index:%d entries=%d", + fixed_param->old_hw_mode_index, + fixed_param->new_hw_mode_index, + fixed_param->num_vdev_mac_entries); + + if (!vdev_mac_entry) { + wmi_err("Invalid vdev_mac_entry"); + return; + } + + /* Store the vdev-mac map in WMA and send to policy manager */ + for (i = 0; i < fixed_param->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id, pdev_id; + + vdev_id = vdev_mac_entry[i].vdev_id; + pdev_id = vdev_mac_entry[i].pdev_id; + + if (pdev_id == OL_TXRX_PDEV_ID) { + wmi_err("soc level id received for mac id"); + return; + } + if (vdev_id >= WLAN_MAX_VDEVS) { + wmi_err("vdev_id: %d is invalid, max_bssid: %d", + vdev_id, WLAN_MAX_VDEVS); + return; + } + + mac_id = WMI_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + + hw_mode_trans_ind->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_trans_ind->vdev_mac_map[i].mac_id = mac_id; + + wmi_debug("vdev_id:%d mac_id:%d", vdev_id, mac_id); + } +} + +/** + * extract_roam_event_tlv() - Extract the roam event + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @len: Data length + * @roam_event: Roam event data + */ +static QDF_STATUS +extract_roam_event_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t len, + struct roam_offload_roam_event *roam_event) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_roam_event_fixed_param *wmi_event = NULL; + WMI_ROAM_EVENTID_param_tlvs *param_buf = NULL; + struct cm_hw_mode_trans_ind *hw_mode_trans_ind; + wmi_pdev_hw_mode_transition_event_fixed_param *hw_mode_trans_param; + + if (!evt_buf) { + wmi_debug("Empty roam_sync_event param buf"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + param_buf = (WMI_ROAM_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + wmi_debug("received null buf from target"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + wmi_event = param_buf->fixed_param; + if (!wmi_event) { + wmi_debug("received null event data from target"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + roam_event->vdev_id = wmi_event->vdev_id; + + if (roam_event->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err("Invalid vdev id from firmware: %u", + roam_event->vdev_id); + return -EINVAL; + } + hw_mode_trans_param = param_buf->hw_mode_transition_fixed_param; + if (hw_mode_trans_param && + hw_mode_trans_param->num_vdev_mac_entries > + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping) { + wmi_debug("invalid vdev mac entries %d %d", + hw_mode_trans_param->num_vdev_mac_entries, + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping); + return QDF_STATUS_E_FAILURE; + } + + roam_event->reason = + wmi_convert_fw_reason_to_cm_reason(wmi_event->reason); + roam_event->rssi = wmi_event->rssi; + roam_event->notif = wmi_convert_fw_notif_to_cm_notif(wmi_event->notif); + roam_event->notif_params = wmi_event->notif_params; + roam_event->notif_params1 = wmi_event->notif_params1; + + wlan_roam_debug_log(roam_event->vdev_id, DEBUG_ROAM_EVENT, + DEBUG_INVALID_PEER_ID, NULL, NULL, + roam_event->reason, + (roam_event->reason == WMI_ROAM_REASON_INVALID) ? + roam_event->notif : roam_event->rssi); + + DPTRACE(qdf_dp_trace_record_event(QDF_DP_TRACE_EVENT_RECORD, + roam_event->vdev_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_EVENT, + QDF_ROAM_EVENTID)); + + wmi_debug("FW_ROAM_EVT: Reason:%s[%d], Notif %x for vdevid %x, rssi %d, params %d, params1 %d", + wmi_get_roam_event_reason_string(roam_event->reason), + roam_event->reason, + roam_event->notif, roam_event->vdev_id, roam_event->rssi, + roam_event->notif_params, roam_event->notif_params1); + + if (param_buf->hw_mode_transition_fixed_param) { + hw_mode_trans_ind = qdf_mem_malloc(sizeof(*hw_mode_trans_ind)); + if (!hw_mode_trans_ind) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + wmi_extract_pdev_hw_mode_trans_ind( + param_buf->hw_mode_transition_fixed_param, + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping, + hw_mode_trans_ind); + roam_event->hw_mode_trans_ind = hw_mode_trans_ind; + } + + if (wmi_event->notif_params1) + roam_event->deauth_disassoc_frame = + param_buf->deauth_disassoc_frame; +end: + return status; +} +#endif /* WLAN_FEATURE_HOST_ROAM || WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* send_set_ric_req_cmd_tlv() - set ric request element + * @wmi_handle: wmi handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: CDF status + */ +static QDF_STATUS send_set_ric_req_cmd_tlv(wmi_unified_t wmi_handle, + void *msg, uint8_t is_add_ts) +{ + wmi_ric_request_fixed_param *cmd; + wmi_ric_tspec *tspec_param; + wmi_buf_t buf; + uint8_t *buf_ptr; + struct mac_tspec_ie *tspec_ie = NULL; + int32_t len = sizeof(wmi_ric_request_fixed_param) + + WMI_TLV_HDR_SIZE + sizeof(wmi_ric_tspec); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd = (wmi_ric_request_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_ric_request_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_ric_request_fixed_param)); + if (is_add_ts) + cmd->vdev_id = ((struct add_ts_param *)msg)->vdev_id; + else + cmd->vdev_id = ((struct del_ts_params *)msg)->sessionId; + cmd->num_ric_request = 1; + cmd->is_add_ric = is_add_ts; + + buf_ptr += sizeof(wmi_ric_request_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, sizeof(wmi_ric_tspec)); + + buf_ptr += WMI_TLV_HDR_SIZE; + tspec_param = (wmi_ric_tspec *)buf_ptr; + WMITLV_SET_HDR(&tspec_param->tlv_header, + WMITLV_TAG_STRUC_wmi_ric_tspec, + WMITLV_GET_STRUCT_TLVLEN(wmi_ric_tspec)); + + if (is_add_ts) + tspec_ie = &(((struct add_ts_param *)msg)->tspec); + else + tspec_ie = &(((struct del_ts_params *)msg)->delTsInfo.tspec); + if (tspec_ie) { + /* Fill the tsinfo in the format expected by firmware */ +#ifndef ANI_LITTLE_BIT_ENDIAN + qdf_mem_copy(((uint8_t *)&tspec_param->ts_info) + 1, + ((uint8_t *)&tspec_ie->tsinfo) + 1, 2); +#else + qdf_mem_copy(((uint8_t *)&tspec_param->ts_info), + ((uint8_t *)&tspec_ie->tsinfo) + 1, 2); +#endif /* ANI_LITTLE_BIT_ENDIAN */ + + tspec_param->nominal_msdu_size = tspec_ie->nomMsduSz; + tspec_param->maximum_msdu_size = tspec_ie->maxMsduSz; + tspec_param->min_service_interval = tspec_ie->minSvcInterval; + tspec_param->max_service_interval = tspec_ie->maxSvcInterval; + tspec_param->inactivity_interval = tspec_ie->inactInterval; + tspec_param->suspension_interval = tspec_ie->suspendInterval; + tspec_param->svc_start_time = tspec_ie->svcStartTime; + tspec_param->min_data_rate = tspec_ie->minDataRate; + tspec_param->mean_data_rate = tspec_ie->meanDataRate; + tspec_param->peak_data_rate = tspec_ie->peakDataRate; + tspec_param->max_burst_size = tspec_ie->maxBurstSz; + tspec_param->delay_bound = tspec_ie->delayBound; + tspec_param->min_phy_rate = tspec_ie->minPhyRate; + tspec_param->surplus_bw_allowance = tspec_ie->surplusBw; + tspec_param->medium_time = 0; + } + wmi_debug("Set RIC Req is_add_ts: %d", is_add_ts); + + wmi_mtrace(WMI_ROAM_SET_RIC_REQUEST_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_SET_RIC_REQUEST_CMDID)) { + wmi_err("Failed to send vdev Set RIC Req command"); + if (is_add_ts) + ((struct add_ts_param *)msg)->status = + QDF_STATUS_E_FAILURE; + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_roam_synch_complete_cmd_tlv() - roam synch complete command to + * fw. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * + * This function sends roam synch complete event to fw. + * + * Return: QDF STATUS + */ +static QDF_STATUS +send_process_roam_synch_complete_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + wmi_roam_synch_complete_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint16_t len; + len = sizeof(wmi_roam_synch_complete_fixed_param); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_synch_complete_fixed_param *)wmi_buf_data(wmi_buf); + buf_ptr = (uint8_t *)cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_synch_complete_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_synch_complete_fixed_param)); + cmd->vdev_id = vdev_id; + wmi_mtrace(WMI_ROAM_SYNCH_COMPLETE, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ROAM_SYNCH_COMPLETE)) { + wmi_err("Failed to send roam synch confirmation"); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_invoke_cmd_tlv() - send roam invoke command to fw. + * @wmi_handle: wma handle + * @roaminvoke: roam invoke command + * + * Send roam invoke command to fw for fastreassoc. + * + * Return: CDF STATUS + */ +static QDF_STATUS send_roam_invoke_cmd_tlv(wmi_unified_t wmi_handle, + struct roam_invoke_req *roaminvoke) +{ + wmi_roam_invoke_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + u_int8_t *buf_ptr; + u_int16_t len, args_tlv_len; + uint32_t *channel_list; + wmi_mac_addr *bssid_list; + wmi_tlv_buf_len_param *buf_len_tlv; + + args_tlv_len = (4 * WMI_TLV_HDR_SIZE) + sizeof(uint32_t) + + sizeof(wmi_mac_addr) + sizeof(wmi_tlv_buf_len_param) + + roundup(roaminvoke->frame_len, sizeof(uint32_t)); + len = sizeof(wmi_roam_invoke_cmd_fixed_param) + args_tlv_len; + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_invoke_cmd_fixed_param *)wmi_buf_data(wmi_buf); + buf_ptr = (u_int8_t *)cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_invoke_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_invoke_cmd_fixed_param)); + cmd->vdev_id = roaminvoke->vdev_id; + cmd->flags |= (1 << WMI_ROAM_INVOKE_FLAG_REPORT_FAILURE); + if (roaminvoke->is_same_bssid) + cmd->flags |= (1 << WMI_ROAM_INVOKE_FLAG_NO_NULL_FRAME_TO_AP); + + if (roaminvoke->frame_len) { + cmd->roam_scan_mode = WMI_ROAM_INVOKE_SCAN_MODE_SKIP; + /* packing 1 beacon/probe_rsp frame with WMI cmd */ + cmd->num_buf = 1; + } else { + cmd->roam_scan_mode = WMI_ROAM_INVOKE_SCAN_MODE_FIXED_CH; + cmd->num_buf = 0; + } + + cmd->roam_ap_sel_mode = 0; + cmd->roam_delay = 0; + cmd->num_chan = 1; + cmd->num_bssid = 1; + + if (roaminvoke->forced_roaming) { + cmd->num_chan = 0; + cmd->num_bssid = 0; + cmd->roam_scan_mode = WMI_ROAM_INVOKE_SCAN_MODE_CACHE_MAP; + cmd->flags |= + (1 << WMI_ROAM_INVOKE_FLAG_FULL_SCAN_IF_NO_CANDIDATE); + cmd->reason = ROAM_INVOKE_REASON_NUD_FAILURE; + } else if (qdf_is_macaddr_broadcast(&roaminvoke->target_bssid)) { + cmd->num_chan = 0; + cmd->num_bssid = 0; + cmd->roam_scan_mode = WMI_ROAM_INVOKE_SCAN_MODE_CACHE_MAP; + cmd->flags |= + (1 << WMI_ROAM_INVOKE_FLAG_FULL_SCAN_IF_NO_CANDIDATE) | + (1 << WMI_ROAM_INVOKE_FLAG_SELECT_CANDIDATE_CONSIDER_SCORE); + cmd->reason = ROAM_INVOKE_REASON_USER_SPACE; + } else { + cmd->reason = ROAM_INVOKE_REASON_USER_SPACE; + } + + buf_ptr += sizeof(wmi_roam_invoke_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (sizeof(u_int32_t))); + channel_list = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); + *channel_list = roaminvoke->ch_freq; + buf_ptr += sizeof(uint32_t) + WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + (sizeof(wmi_mac_addr))); + bssid_list = (wmi_mac_addr *)(buf_ptr + WMI_TLV_HDR_SIZE); + WMI_CHAR_ARRAY_TO_MAC_ADDR(roaminvoke->target_bssid.bytes, bssid_list); + + /* move to next tlv i.e. bcn_prb_buf_list */ + buf_ptr += WMI_TLV_HDR_SIZE + sizeof(wmi_mac_addr); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_FIXED_STRUC, + sizeof(wmi_tlv_buf_len_param)); + + buf_len_tlv = (wmi_tlv_buf_len_param *)(buf_ptr + WMI_TLV_HDR_SIZE); + WMITLV_SET_HDR(&buf_len_tlv->tlv_header, + WMITLV_TAG_STRUC_wmi_tlv_buf_len_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_tlv_buf_len_param)); + buf_len_tlv->buf_len = roaminvoke->frame_len; + + /* move to next tlv i.e. bcn_prb_frm */ + buf_ptr += WMI_TLV_HDR_SIZE + sizeof(wmi_tlv_buf_len_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + roundup(roaminvoke->frame_len, sizeof(uint32_t))); + + /* copy frame after the header */ + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + roaminvoke->frame_buf, + roaminvoke->frame_len); + + wmi_debug("flag:%d, MODE:%d, ap:%d, dly:%d, n_ch:%d, n_bssid:%d, ch_freq:%d, is_same_bss:%d", + cmd->flags, cmd->roam_scan_mode, + cmd->roam_ap_sel_mode, cmd->roam_delay, + cmd->num_chan, cmd->num_bssid, roaminvoke->ch_freq, + roaminvoke->is_same_bssid); + + wmi_mtrace(WMI_ROAM_INVOKE_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ROAM_INVOKE_CMDID)) { + wmi_err("Failed to send roam invoke command"); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * convert_control_roam_trigger_reason_bitmap() - Convert roam trigger bitmap + * + * @trigger_reason_bitmap: Roam trigger reason bitmap received from upper layers + * + * Converts the controlled roam trigger reason bitmap of + * type @roam_control_trigger_reason to firmware trigger + * reason bitmap as defined in + * trigger_reason_bitmask @wmi_roam_enable_disable_trigger_reason_fixed_param + * + * Return: trigger_reason_bitmask as defined in + * wmi_roam_enable_disable_trigger_reason_fixed_param + */ +static uint32_t +convert_control_roam_trigger_reason_bitmap(uint32_t trigger_reason_bitmap) +{ + uint32_t fw_trigger_bitmap = 0, all_bitmap; + + /* Enable the complete trigger bitmap when all bits are set in + * the control config bitmap + */ + all_bitmap = BIT(ROAM_TRIGGER_REASON_MAX) - 1; + if (trigger_reason_bitmap == all_bitmap) + return BIT(WMI_ROAM_TRIGGER_EXT_REASON_MAX) - 1; + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_NONE)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_NONE); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_PER)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_PER); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_BMISS)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_BMISS); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_LOW_RSSI)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_LOW_RSSI); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_HIGH_RSSI)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_HIGH_RSSI); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_PERIODIC)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_PERIODIC); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_MAWC)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_MAWC); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_DENSE)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_DENSE); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_BACKGROUND)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_BACKGROUND); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_FORCED)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_FORCED); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_BTM)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_BTM); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_UNIT_TEST)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_UNIT_TEST); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_BSS_LOAD)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_BSS_LOAD); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_DEAUTH)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_DEAUTH); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_IDLE)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_IDLE); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_STA_KICKOUT)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_STA_KICKOUT); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_ESS_RSSI)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_ESS_RSSI); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_WTC_BTM)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_WTC_BTM); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_PMK_TIMEOUT)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_PMK_TIMEOUT); + + if (trigger_reason_bitmap & BIT(ROAM_TRIGGER_REASON_BTC)) + fw_trigger_bitmap |= BIT(WMI_ROAM_TRIGGER_REASON_BTC); + + return fw_trigger_bitmap; +} + +/** + * get_internal_mandatory_roam_triggers() - Internal triggers to be added + * + * Return: the bitmap of mandatory triggers to be sent to firmware but not given + * by user. + */ +static uint32_t +get_internal_mandatory_roam_triggers(void) +{ + return BIT(WMI_ROAM_TRIGGER_REASON_FORCED); +} + +/** + * convert_roam_trigger_scan_mode() - Function to convert unified Roam trigger + * scan mode enum to TLV specific ROAM_TRIGGER_SCAN_MODE + * @scan_freq_scheme: scan freq scheme coming from userspace + * + * Return: ROAM_TRIGGER_SCAN_MODE + */ +static WMI_ROAM_TRIGGER_SCAN_MODE +convert_roam_trigger_scan_mode(enum roam_scan_freq_scheme scan_freq_scheme) +{ + switch (scan_freq_scheme) { + case ROAM_SCAN_FREQ_SCHEME_NO_SCAN: + return ROAM_TRIGGER_SCAN_MODE_NO_SCAN_DISCONNECTION; + case ROAM_SCAN_FREQ_SCHEME_PARTIAL_SCAN: + return ROAM_TRIGGER_SCAN_MODE_PARTIAL; + case ROAM_SCAN_FREQ_SCHEME_FULL_SCAN: + return ROAM_TRIGGER_SCAN_MODE_FULL; + default: + return ROAM_TRIGGER_SCAN_MODE_NONE; + } +} + +/** + * wmi_fill_default_roam_trigger_parameters() - Fill the default parameters + * for wmi_configure_roam_trigger_parameters tlv. + * @roam_trigger_params: pointer to wmi_configure_roam_trigger_parameters tlv + * to be filled. + * @roam_trigger: Roam trigger reason + * + * Return: None + */ +static void wmi_fill_default_roam_trigger_parameters( + wmi_configure_roam_trigger_parameters *roam_trigger_params, + uint32_t roam_trigger) +{ + WMITLV_SET_HDR(&roam_trigger_params->tlv_header, + WMITLV_TAG_STRUC_wmi_configure_roam_trigger_parameters, + WMITLV_GET_STRUCT_TLVLEN(wmi_configure_roam_trigger_parameters)); + + roam_trigger_params->trigger_reason = roam_trigger; + roam_trigger_params->enable = 1; + roam_trigger_params->scan_mode = ROAM_TRIGGER_SCAN_MODE_NONE; + roam_trigger_params->trigger_rssi_threshold = + ROAM_MAX_CFG_VALUE; + roam_trigger_params->cand_ap_min_rssi_threshold = + ROAM_MAX_CFG_VALUE; + roam_trigger_params->cand_ap_min_rssi_threshold_5g = + ROAM_MAX_CFG_VALUE; + roam_trigger_params->cand_ap_min_rssi_threshold_6g = + ROAM_MAX_CFG_VALUE; + roam_trigger_params->roam_score_delta_percentage = + ROAM_MAX_CFG_VALUE; + roam_trigger_params->reason_code = ROAM_MAX_CFG_VALUE; +} + +static void wmi_fill_score_delta_params( + wmi_configure_roam_trigger_parameters *roam_trigger_params, + struct wlan_roam_triggers *triggers, + uint8_t trig_index) +{ + enum roam_trigger_reason trig_reason; + + if (trig_index >= NUM_OF_ROAM_TRIGGERS) + return; + + trig_reason = + triggers->score_delta_param[trig_index].trigger_reason; + wmi_fill_default_roam_trigger_parameters( + roam_trigger_params, + convert_roam_trigger_reason(trig_reason)); + roam_trigger_params->roam_score_delta_percentage = + triggers->score_delta_param[trig_index].roam_score_delta; + + wmi_debug("RSO_CFG: Score delta per: %d converted trig_reason: %d", + roam_trigger_params->roam_score_delta_percentage, + convert_roam_trigger_reason(trig_reason)); + +} + +static void wmi_fill_min_rssi_params( + wmi_configure_roam_trigger_parameters *roam_trigger_params, + struct wlan_roam_triggers *triggers, + uint8_t trig_index) +{ + enum roam_trigger_reason trig_reason; + + if (trig_index >= NUM_OF_ROAM_MIN_RSSI) + return; + + trig_reason = + triggers->min_rssi_params[trig_index].trigger_reason; + wmi_fill_default_roam_trigger_parameters( + roam_trigger_params, + convert_roam_trigger_reason(trig_reason)); + roam_trigger_params->cand_ap_min_rssi_threshold = + triggers->min_rssi_params[trig_index].min_rssi; + roam_trigger_params->cand_ap_min_rssi_threshold_5g = + triggers->min_rssi_params[trig_index].min_rssi; + roam_trigger_params->cand_ap_min_rssi_threshold_6g = + triggers->min_rssi_params[trig_index].min_rssi; + + wmi_debug("RSO_CFG: Min rssi thresh: %d converted trig_reason: %d", + roam_trigger_params->cand_ap_min_rssi_threshold, + convert_roam_trigger_reason(trig_reason)); +} + +/** + * send_set_roam_trigger_cmd_tlv() - send set roam triggers to fw + * @wmi_handle: wmi handle + * @triggers: roam trigger bitmap to be enabled + * + * Send WMI_ROAM_ENABLE_DISABLE_TRIGGER_REASON_CMDID to fw. + * + * Return: QDF_STATUS + */ +static QDF_STATUS send_set_roam_trigger_cmd_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_triggers *triggers) +{ + wmi_buf_t buf; + wmi_roam_enable_disable_trigger_reason_fixed_param *cmd; + uint32_t len = sizeof(*cmd); + int ret; + uint8_t *buf_ptr; + wmi_configure_roam_trigger_parameters + *roam_trigger_parameters; + uint32_t num_triggers_enabled = 0; + uint32_t roam_scan_scheme_bitmap = triggers->roam_scan_scheme_bitmap; + uint32_t total_tlv_len = 0; + + if (BIT(ROAM_TRIGGER_REASON_PER) & roam_scan_scheme_bitmap) + num_triggers_enabled++; + + if (BIT(ROAM_TRIGGER_REASON_BTC) & roam_scan_scheme_bitmap) + num_triggers_enabled++; + + if (BIT(ROAM_TRIGGER_REASON_BMISS) & roam_scan_scheme_bitmap) + num_triggers_enabled++; + + if (BIT(ROAM_TRIGGER_REASON_LOW_RSSI) & roam_scan_scheme_bitmap) + num_triggers_enabled++; + + if (BIT(ROAM_TRIGGER_REASON_BTM) & roam_scan_scheme_bitmap) + num_triggers_enabled++; + + if (BIT(ROAM_TRIGGER_REASON_BSS_LOAD) & roam_scan_scheme_bitmap) + num_triggers_enabled++; + + if (wmi_service_enabled(wmi_handle, + wmi_service_configure_roam_trigger_param_support)) + total_tlv_len += (NUM_OF_ROAM_TRIGGERS + NUM_OF_ROAM_MIN_RSSI) * + sizeof(wmi_configure_roam_trigger_parameters); + + total_tlv_len += 2 * sizeof(wmi_configure_roam_trigger_parameters) + + num_triggers_enabled * + sizeof(wmi_configure_roam_trigger_parameters); + len += WMI_TLV_HDR_SIZE + total_tlv_len; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + wmi_err("Failed to allocate wmi buffer"); + return QDF_STATUS_E_NOMEM; + } + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd = (wmi_roam_enable_disable_trigger_reason_fixed_param *) + wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_enable_disable_trigger_reason_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_enable_disable_trigger_reason_fixed_param)); + + cmd->vdev_id = triggers->vdev_id; + cmd->trigger_reason_bitmask = + convert_control_roam_trigger_reason_bitmap(triggers->trigger_bitmap); + wmi_debug("RSO_CFG: Received trigger bitmap: 0x%x converted trigger_bitmap: 0x%x", + triggers->trigger_bitmap, cmd->trigger_reason_bitmask); + cmd->trigger_reason_bitmask |= get_internal_mandatory_roam_triggers(); + wmi_debug("RSO_CFG: vdev id: %d final trigger_bitmap: 0x%x roam_scan_scheme:0x%x num_triggers_enabled:%d", + cmd->vdev_id, cmd->trigger_reason_bitmask, + roam_scan_scheme_bitmap, num_triggers_enabled); + + buf_ptr += sizeof(wmi_roam_enable_disable_trigger_reason_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, total_tlv_len); + buf_ptr += WMI_TLV_HDR_SIZE; + + roam_trigger_parameters = + (wmi_configure_roam_trigger_parameters *)buf_ptr; + + WMITLV_SET_HDR(&roam_trigger_parameters->tlv_header, + WMITLV_TAG_STRUC_wmi_configure_roam_trigger_parameters, + WMITLV_GET_STRUCT_TLVLEN( + wmi_configure_roam_trigger_parameters)); + roam_trigger_parameters->trigger_reason = + WMI_ROAM_TRIGGER_REASON_WTC_BTM; + if (triggers->vendor_btm_param.user_roam_reason == 0) + roam_trigger_parameters->enable = 1; + roam_trigger_parameters->scan_mode = convert_roam_trigger_scan_mode( + triggers->vendor_btm_param.scan_freq_scheme); + roam_trigger_parameters->trigger_rssi_threshold = + triggers->vendor_btm_param.connected_rssi_threshold; + roam_trigger_parameters->cand_ap_min_rssi_threshold = + triggers->vendor_btm_param.candidate_rssi_threshold_2g; + roam_trigger_parameters->cand_ap_min_rssi_threshold_5g = + triggers->vendor_btm_param.candidate_rssi_threshold_5g; + roam_trigger_parameters->cand_ap_min_rssi_threshold_6g = + triggers->vendor_btm_param.candidate_rssi_threshold_6g; + roam_trigger_parameters->roam_score_delta_percentage = + triggers->roam_score_delta; + roam_trigger_parameters->reason_code = + triggers->vendor_btm_param.user_roam_reason; + + roam_trigger_parameters++; + + if (wmi_service_enabled(wmi_handle, + wmi_service_configure_roam_trigger_param_support)) { + wmi_fill_score_delta_params(roam_trigger_parameters, + triggers, + IDLE_ROAM_TRIGGER); + if (cmd->trigger_reason_bitmask & + BIT(WMI_ROAM_TRIGGER_REASON_IDLE)) + roam_trigger_parameters->enable = 1; + else + roam_trigger_parameters->enable = 0; + + roam_trigger_parameters++; + + wmi_fill_score_delta_params(roam_trigger_parameters, + triggers, + BTM_ROAM_TRIGGER); + roam_trigger_parameters++; + + wmi_fill_min_rssi_params(roam_trigger_parameters, + triggers, + DEAUTH_MIN_RSSI); + roam_trigger_parameters++; + + wmi_fill_min_rssi_params(roam_trigger_parameters, + triggers, + BMISS_MIN_RSSI); + roam_trigger_parameters++; + + wmi_fill_min_rssi_params(roam_trigger_parameters, + triggers, + MIN_RSSI_2G_TO_5G_ROAM); + roam_trigger_parameters++; + } + + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_PMK_TIMEOUT); + + if (cmd->trigger_reason_bitmask & + BIT(WMI_ROAM_TRIGGER_REASON_PMK_TIMEOUT)) + roam_trigger_parameters->enable = 1; + else + roam_trigger_parameters->enable = 0; + + roam_trigger_parameters->roam_score_delta_percentage = 0; + roam_trigger_parameters++; + + if (num_triggers_enabled == 0) + goto send; + + if (BIT(ROAM_TRIGGER_REASON_PER) & roam_scan_scheme_bitmap) { + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_PER); + roam_trigger_parameters->scan_mode = + ROAM_TRIGGER_SCAN_MODE_PARTIAL; + + roam_trigger_parameters++; + } + + if (BIT(ROAM_TRIGGER_REASON_BTC) & roam_scan_scheme_bitmap) { + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_BTC); + roam_trigger_parameters->scan_mode = + ROAM_TRIGGER_SCAN_MODE_PARTIAL; + + roam_trigger_parameters++; + } + + if (BIT(ROAM_TRIGGER_REASON_BMISS) & roam_scan_scheme_bitmap) { + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_BMISS); + roam_trigger_parameters->scan_mode = + ROAM_TRIGGER_SCAN_MODE_PARTIAL; + + roam_trigger_parameters++; + } + + if (BIT(ROAM_TRIGGER_REASON_LOW_RSSI) & roam_scan_scheme_bitmap) { + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_LOW_RSSI); + roam_trigger_parameters->scan_mode = + ROAM_TRIGGER_SCAN_MODE_PARTIAL; + + roam_trigger_parameters++; + } + + if (BIT(ROAM_TRIGGER_REASON_BTM) & roam_scan_scheme_bitmap) { + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_BTM); + roam_trigger_parameters->scan_mode = + ROAM_TRIGGER_SCAN_MODE_PARTIAL; + + roam_trigger_parameters++; + } + + if (BIT(ROAM_TRIGGER_REASON_BSS_LOAD) & roam_scan_scheme_bitmap) { + wmi_fill_default_roam_trigger_parameters( + roam_trigger_parameters, + WMI_ROAM_TRIGGER_REASON_BSS_LOAD); + roam_trigger_parameters->scan_mode = + ROAM_TRIGGER_SCAN_MODE_PARTIAL; + + roam_trigger_parameters++; + } + +send: + wmi_mtrace(WMI_ROAM_ENABLE_DISABLE_TRIGGER_REASON_CMDID, + triggers->vdev_id, 0); + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_ENABLE_DISABLE_TRIGGER_REASON_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + wmi_err("Failed to send set roam triggers command ret = %d", + ret); + wmi_buf_free(buf); + } + return ret; +} + +/** + * send_vdev_set_pcl_cmd_tlv() - Send WMI_VDEV_SET_PCL_CMDID to FW + * @wmi_handle: wmi handle + * @params: Set VDEV PCL params + * + * WMI_VDEV_SET_PCL_CMDID provides the Preferred Channel List (PCL) to WLAN + * firmware. The roaming module is the consumer of this information + * in the WLAN firmware. The channel list will be used when a VDEV needs + * to migrate to a new channel without host driver involvement. An example of + * this behavior is Legacy Fast Roaming (LFR 3.0). + * + * WMI_VDEV_SET_PCL_CMDID will carry only the weight list and not the actual + * channel list. The weights corresponds to the channels sent in + * WMI_SCAN_CHAN_LIST_CMDID. The channels from PCL would be having a higher + * weightage compared to the non PCL channels. + * + * When roaming is enabled on STA 1, PDEV pcl will be sent. When STA2 is + * up, VDEV pcl will be sent on STA 1 after calculating pcl again applying + * the bandmask and VDEV pcl will be sent for STA2. When one of the STA + * is disconnected, PDEV pcl will be sent on the other STA again. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +static QDF_STATUS +send_vdev_set_pcl_cmd_tlv(wmi_unified_t wmi_handle, + struct set_pcl_cmd_params *params) +{ + wmi_vdev_set_pcl_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint8_t *buf_ptr; + uint32_t *ch_weight, i; + size_t len; + uint32_t chan_len; + + chan_len = params->weights->saved_num_chan; + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + (chan_len * sizeof(uint32_t)); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_vdev_set_pcl_cmd_fixed_param *)wmi_buf_data(buf); + buf_ptr = (uint8_t *)cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_pcl_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_vdev_set_pcl_cmd_fixed_param)); + cmd->vdev_id = params->vdev_id; + buf_ptr += sizeof(wmi_vdev_set_pcl_cmd_fixed_param); + + /* Channel weights uint32 Array TLV */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (chan_len * sizeof(uint32_t))); + ch_weight = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; i < chan_len; i++) + ch_weight[i] = params->weights->weighed_valid_list[i]; + + wmi_mtrace(WMI_VDEV_SET_PCL_CMDID, params->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_SET_PCL_CMDID)) { + wmi_err("Failed to send WMI_VDEV_SET_PCL_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_btm_response_stats_tlv() - Extract the btm rsp stats + * from the WMI_ROAM_STATS_EVENTID + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: TLV id + */ +static QDF_STATUS +extract_roam_btm_response_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_btm_response_data *dst, + uint8_t idx) +{ + WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf; + wmi_roam_btm_response_info *src_data = NULL; + + param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf; + + if (!param_buf || !param_buf->roam_btm_response_info || + !param_buf->num_roam_btm_response_info || + idx >= param_buf->num_roam_btm_response_info) { + wmi_debug("Empty btm response param buf"); + return QDF_STATUS_SUCCESS; + } + + src_data = ¶m_buf->roam_btm_response_info[idx]; + if (!src_data->timestamp) + return QDF_STATUS_SUCCESS; + + dst->present = true; + dst->btm_status = src_data->btm_status; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_data->target_bssid, + dst->target_bssid.bytes); + dst->vsie_reason = src_data->vsie_reason; + dst->timestamp = src_data->timestamp; + dst->btm_resp_dialog_token = src_data->btm_resp_dialog_token; + dst->btm_delay = src_data->btm_resp_bss_termination_delay; + dst->band = WMI_ROAM_BTM_RESP_MLO_BAND_INFO_GET(src_data->info); + if (dst->band != WMI_MLO_BAND_NO_MLO) + dst->is_mlo = true; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_initial_info_tlv() - Extract the roam initial info + * from the WMI_ROAM_STATS_EVENTID + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: TLV id + */ +static QDF_STATUS +extract_roam_initial_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_initial_data *dst, uint8_t idx) +{ + WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf; + wmi_roam_initial_info *src_data = NULL; + + param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf; + + if (!param_buf || !param_buf->roam_initial_info || + !param_buf->num_roam_initial_info || + idx >= param_buf->num_roam_initial_info) { + wmi_debug("Empty roam_initial_info param buf"); + return QDF_STATUS_SUCCESS; + } + + src_data = ¶m_buf->roam_initial_info[idx]; + + dst->present = true; + dst->roam_full_scan_count = src_data->roam_full_scan_count; + dst->rssi_th = src_data->rssi_th; + dst->cu_th = src_data->cu_th; + dst->fw_cancel_timer_bitmap = src_data->timer_canceled; + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_msg_info_tlv() - Extract the roam message info + * from the WMI_ROAM_STATS_EVENTID + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @idx: TLV id + */ +static QDF_STATUS +extract_roam_msg_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_msg_info *dst, uint8_t idx) +{ + WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf; + wmi_roam_msg_info *src_data = NULL; + + param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf; + + if (!param_buf || !param_buf->roam_msg_info || + !param_buf->num_roam_msg_info || + idx >= param_buf->num_roam_msg_info) + return QDF_STATUS_SUCCESS; + + src_data = ¶m_buf->roam_msg_info[idx]; + + dst->present = true; + dst->timestamp = src_data->timestamp; + dst->msg_id = src_data->msg_id; + dst->msg_param1 = src_data->msg_param1; + dst->msg_param2 = src_data->msg_param2; + + return QDF_STATUS_SUCCESS; +} + +static enum wlan_roam_frame_subtype +wmi_get_converted_roam_eapol_subtype( + WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE eapol_subtype) +{ + switch (eapol_subtype) { + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M1: + return ROAM_FRAME_SUBTYPE_M1; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M2: + return ROAM_FRAME_SUBTYPE_M2; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M3: + return ROAM_FRAME_SUBTYPE_M3; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_M4: + return ROAM_FRAME_SUBTYPE_M4; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_GTK_M1: + return ROAM_FRAME_SUBTYPE_GTK_M1; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_SUBTYPE_GTK_M2: + return ROAM_FRAME_SUBTYPE_GTK_M2; + default: + break; + } + + return 0; +} + +static enum qdf_dp_tx_rx_status +wmi_get_converted_tx_status( + WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS roam_tx_status) +{ + switch (roam_tx_status) { + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS_ACK: + return QDF_TX_RX_STATUS_OK; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS_NO_ACK: + return QDF_TX_RX_STATUS_NO_ACK; + case WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT_STATUS_TX_FAIL: + return QDF_TX_RX_STATUS_DROP; + default: + break; + } + + return QDF_TX_RX_STATUS_INVALID; +} + +#define WLAN_FC0_SUBTYPE_SHIFT 4 +#define WLAN_FRAME_INFO_TYPE_OFFSET 0 +#define WLAN_FRAME_INFO_SUBTYPE_OFFSET 2 +#define WLAN_FRAME_INFO_RESP_OFFSET 6 +#define WLAN_FRAME_INFO_AUTH_ALG_OFFSET 7 +#define WLAN_FRAME_INFO_SEQ_NUM_OFFSET 16 + +/** + * extract_roam_frame_info_tlv() - Extract the frame exchanges during roaming + * info from the WMI_ROAM_STATS_EVENTID + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @dst: Pointer to destination structure to fill data + * @frame_idx: TLV id + * @num_frames: Number of Frame TLVs to be extracted + */ +static QDF_STATUS +extract_roam_frame_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_frame_stats *dst, uint8_t frame_idx, + uint8_t num_frames) +{ + WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf; + wmi_roam_frame_info *src_data = NULL; + struct roam_frame_info *dst_buf; + uint8_t i, subtype; + + param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf; + + if (!param_buf || !param_buf->roam_frame_info || + !param_buf->num_roam_frame_info || + (frame_idx + num_frames) > param_buf->num_roam_frame_info) { + wmi_err("Empty roam_frame_info param buf frame_idx:%d num_frames:%d", + frame_idx, num_frames); + return QDF_STATUS_SUCCESS; + } + + src_data = ¶m_buf->roam_frame_info[frame_idx]; + + if (num_frames > WLAN_ROAM_MAX_FRAME_INFO) + num_frames = WLAN_ROAM_MAX_FRAME_INFO; + + dst->num_frame = num_frames; + dst_buf = dst->frame_info; + for (i = 0; i < num_frames; i++) { + dst_buf->timestamp = src_data->timestamp; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_data->bssid, + dst_buf->bssid.bytes); + dst_buf->type = WMI_GET_BITS(src_data->frame_info, + WLAN_FRAME_INFO_TYPE_OFFSET, 2); + + subtype = WMI_GET_BITS(src_data->frame_info, + WLAN_FRAME_INFO_SUBTYPE_OFFSET, 4); + if (dst_buf->type == WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT) { + dst_buf->type = ROAM_FRAME_INFO_FRAME_TYPE_EXT; + dst_buf->subtype = + wmi_get_converted_roam_eapol_subtype(subtype); + } else { + dst_buf->subtype = subtype << WLAN_FC0_SUBTYPE_SHIFT; + } + + dst_buf->is_rsp = WMI_GET_BITS(src_data->frame_info, + WLAN_FRAME_INFO_RESP_OFFSET, 1); + dst_buf->seq_num = WMI_GET_BITS(src_data->frame_info, + WLAN_FRAME_INFO_SEQ_NUM_OFFSET, + 16); + dst_buf->status_code = src_data->status_code; + if (dst_buf->type != WMI_ROAM_FRAME_INFO_FRAME_TYPE_EXT && + dst_buf->subtype == MGMT_SUBTYPE_AUTH) + dst_buf->auth_algo = + WMI_GET_BITS(src_data->frame_info, + WLAN_FRAME_INFO_AUTH_ALG_OFFSET, + 4); + /* + * src_data->status_code is treated as tx status under + * following condition: + * 1. if the frame is an authentication frame and req_resp bit + * is set to '0' + * 2. If the Frame is Association Request frame + * 3. If the Frame is Re-Association Request Frame + */ + + if ((!dst_buf->is_rsp && + dst_buf->subtype == MGMT_SUBTYPE_AUTH) || + dst_buf->subtype == MGMT_SUBTYPE_ASSOC_REQ || + dst_buf->subtype == MGMT_SUBTYPE_REASSOC_REQ) { + dst_buf->tx_status = wmi_get_converted_tx_status( + src_data->status_code); + dst_buf->status_code = 0; + } + + dst_buf->retry_count = src_data->retry_count; + dst_buf->rssi = (-1) * src_data->rssi_dbm_abs; + dst_buf->assoc_id = + WMI_GET_ASSOC_ID(src_data->frame_info_ext); + + dst_buf->band = + WMI_GET_MLO_BITMAP_BAND_INFO(src_data->frame_info_ext); + + dst_buf++; + src_data++; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_fill_data_synch_frame_event() - Fill the the roam sync data buffer using + * synch frame event data + * @rso_cfg: Source buffer + * @roam_sync_ind: Buffer to be filled + * + * Firmware sends all the required information required for roam + * synch propagation as TLV's and stored in param_buf. These + * parameters are parsed and filled into the roam synch indication + * buffer which will be used at different layers for propagation. + * + * Return: None + */ +static void +wmi_fill_data_synch_frame_event(struct rso_config *rso_cfg, + struct roam_offload_synch_ind *roam_sync_ind) +{ + uint8_t *bcn_probersp_ptr, *link_bcn_probersp_ptr; + uint8_t *reassoc_rsp_ptr; + uint8_t *reassoc_req_ptr; + + /* Beacon/Probe Rsp data */ + roam_sync_ind->beacon_probe_resp_offset = + sizeof(struct roam_offload_synch_ind); + bcn_probersp_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->beacon_probe_resp_offset; + roam_sync_ind->beacon_probe_resp_length = + rso_cfg->roam_sync_frame_ind.bcn_probe_rsp_len; + qdf_mem_copy(bcn_probersp_ptr, + rso_cfg->roam_sync_frame_ind.bcn_probe_rsp, + roam_sync_ind->beacon_probe_resp_length); + qdf_mem_free(rso_cfg->roam_sync_frame_ind.bcn_probe_rsp); + rso_cfg->roam_sync_frame_ind.bcn_probe_rsp = NULL; + + /* Link beacon/probe rsp data */ + if (rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp) { + roam_sync_ind->link_beacon_probe_resp_offset = + sizeof(struct roam_offload_synch_ind) + + roam_sync_ind->beacon_probe_resp_length; + roam_sync_ind->link_beacon_probe_resp_length = + rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp_len; + roam_sync_ind->is_link_beacon = + rso_cfg->roam_sync_frame_ind.is_link_beacon; + link_bcn_probersp_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->link_beacon_probe_resp_offset; + qdf_mem_copy(link_bcn_probersp_ptr, + rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp, + roam_sync_ind->link_beacon_probe_resp_length); + qdf_mem_free(rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp); + rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp = NULL; + } + + /* ReAssoc Rsp data */ + roam_sync_ind->reassoc_resp_offset = + sizeof(struct roam_offload_synch_ind) + + roam_sync_ind->beacon_probe_resp_length + + roam_sync_ind->link_beacon_probe_resp_length; + roam_sync_ind->reassoc_resp_length = + rso_cfg->roam_sync_frame_ind.reassoc_rsp_len; + reassoc_rsp_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->reassoc_resp_offset; + qdf_mem_copy(reassoc_rsp_ptr, + rso_cfg->roam_sync_frame_ind.reassoc_rsp, + roam_sync_ind->reassoc_resp_length); + qdf_mem_free(rso_cfg->roam_sync_frame_ind.reassoc_rsp); + rso_cfg->roam_sync_frame_ind.reassoc_rsp = NULL; + + /* ReAssoc Req data */ + roam_sync_ind->reassoc_req_offset = + sizeof(struct roam_offload_synch_ind) + + roam_sync_ind->beacon_probe_resp_length + + roam_sync_ind->link_beacon_probe_resp_length + + roam_sync_ind->reassoc_resp_length; + roam_sync_ind->reassoc_req_length = + rso_cfg->roam_sync_frame_ind.reassoc_req_len; + reassoc_req_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->reassoc_req_offset; + qdf_mem_copy(reassoc_req_ptr, + rso_cfg->roam_sync_frame_ind.reassoc_req, + roam_sync_ind->reassoc_req_length); + qdf_mem_free(rso_cfg->roam_sync_frame_ind.reassoc_req); + rso_cfg->roam_sync_frame_ind.reassoc_req = NULL; +} + +/** + * wmi_fill_data_synch_event() - Fill the the roam sync data buffer + * using synch event data + * @roam_sync_ind: Buffer to be filled + * @param_buf: Source buffer + * + * Firmware sends all the required information required for roam + * synch propagation as TLV's and stored in param_buf. These + * parameters are parsed and filled into the roam synch indication + * buffer which will be used at different layers for propagation. + * + * Return: None + */ +static void +wmi_fill_data_synch_event(struct roam_offload_synch_ind *roam_sync_ind, + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf) +{ + uint8_t *bcn_probersp_ptr; + uint8_t *reassoc_rsp_ptr; + uint8_t *reassoc_req_ptr; + wmi_roam_synch_event_fixed_param *synch_event; + + synch_event = param_buf->fixed_param; + + /* Beacon/Probe Rsp data */ + roam_sync_ind->beacon_probe_resp_offset = + sizeof(struct roam_offload_synch_ind); + bcn_probersp_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->beacon_probe_resp_offset; + roam_sync_ind->beacon_probe_resp_length = + synch_event->bcn_probe_rsp_len; + qdf_mem_copy(bcn_probersp_ptr, param_buf->bcn_probe_rsp_frame, + roam_sync_ind->beacon_probe_resp_length); + /* + * Firmware doesn't support link beacon/Probe Rsp data in roam sync + * event. It's always sent in sync_frame event + */ + /* ReAssoc Rsp data */ + roam_sync_ind->reassoc_resp_offset = + sizeof(struct roam_offload_synch_ind) + + roam_sync_ind->beacon_probe_resp_length; + roam_sync_ind->reassoc_resp_length = synch_event->reassoc_rsp_len; + reassoc_rsp_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->reassoc_resp_offset; + qdf_mem_copy(reassoc_rsp_ptr, + param_buf->reassoc_rsp_frame, + roam_sync_ind->reassoc_resp_length); + + /* ReAssoc Req data */ + roam_sync_ind->reassoc_req_offset = + sizeof(struct roam_offload_synch_ind) + + roam_sync_ind->beacon_probe_resp_length + + roam_sync_ind->reassoc_resp_length; + roam_sync_ind->reassoc_req_length = synch_event->reassoc_req_len; + reassoc_req_ptr = (uint8_t *)roam_sync_ind + + roam_sync_ind->reassoc_req_offset; + qdf_mem_copy(reassoc_req_ptr, param_buf->reassoc_req_frame, + roam_sync_ind->reassoc_req_length); +} + +#ifdef WLAN_FEATURE_11BE_MLO +#define STANDBY_VDEV_ID (0xFFFFFFFF) +static QDF_STATUS +wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle, + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf, + struct roam_offload_synch_ind *roam_sync_ind) +{ + uint8_t i, mlo_max_allowed_links; + wmi_roam_ml_setup_links_param *setup_links; + wmi_roam_ml_key_material_param *ml_key_param; + struct ml_setup_link_param *link; + struct ml_key_material_param *key; + + mlo_max_allowed_links = + wlan_mlme_get_sta_mlo_conn_max_num(wmi_handle->soc->wmi_psoc); + if (param_buf->num_setup_links_param) { + if (param_buf->num_setup_links_param > mlo_max_allowed_links || + param_buf->num_setup_links_param > WLAN_MAX_ML_BSS_LINKS) { + wmi_err("Number of links %d exceeded max vdev supported %d", + param_buf->num_setup_links_param, + mlo_max_allowed_links); + return QDF_STATUS_E_INVAL; + } + + roam_sync_ind->num_setup_links = + param_buf->num_setup_links_param; + setup_links = param_buf->setup_links_param; + + for (i = 0; i < roam_sync_ind->num_setup_links; i++) { + link = &roam_sync_ind->ml_link[i]; + link->link_id = setup_links->link_id; + + /* + * setup_links->vdev_id == UINT32_MAX for standby link + */ + link->vdev_id = WLAN_INVALID_VDEV_ID; + if (setup_links->vdev_id != STANDBY_VDEV_ID) + link->vdev_id = setup_links->vdev_id; + + link->channel = setup_links->channel; + link->flags = setup_links->flags; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&setup_links->link_addr, + link->link_addr.bytes); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&setup_links->self_link_addr, + link->self_link_addr.bytes); + wmi_debug("link_id: %u vdev_id: %u flags: 0x%x addr: " QDF_MAC_ADDR_FMT " self_addr:" QDF_MAC_ADDR_FMT, + link->link_id, link->vdev_id, + link->flags, + QDF_MAC_ADDR_REF(link->link_addr.bytes), + QDF_MAC_ADDR_REF(link->self_link_addr.bytes)); + wmi_debug("channel: %u mhz center_freq1: %u center_freq2: %u", + link->channel.mhz, + link->channel.band_center_freq1, + link->channel.band_center_freq2); + setup_links++; + } + } + + if (!param_buf->num_ml_key_material) + return QDF_STATUS_SUCCESS; + + if (param_buf->num_ml_key_material > WLAN_MAX_ML_BSS_LINKS) + param_buf->num_ml_key_material = WLAN_MAX_ML_BSS_LINKS; + + roam_sync_ind->num_ml_key_material = param_buf->num_ml_key_material; + ml_key_param = param_buf->ml_key_material; + + for (i = 0; i < roam_sync_ind->num_ml_key_material; i++) { + key = &roam_sync_ind->ml_key[i]; + key->link_id = ml_key_param->link_id; + key->key_idx = ml_key_param->key_ix; + key->key_cipher = ml_key_param->key_cipher; + qdf_mem_copy(key->pn, ml_key_param->pn, + WMI_MAX_PN_LEN); + qdf_mem_copy(key->key_buff, ml_key_param->key_buff, + WMI_MAX_KEY_LEN); + wmi_debug("link_id: %u key_idx: %u key_cipher: %u", + key->link_id, key->key_idx, key->key_cipher); + ml_key_param++; + } + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +wmi_fill_roam_mlo_info(wmi_unified_t wmi_handle, + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf, + struct roam_offload_synch_ind *roam_sync_ind) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS +wmi_fill_roam_sync_buffer(wmi_unified_t wmi_handle, + struct wlan_objmgr_vdev *vdev, + struct rso_config *rso_cfg, + struct roam_offload_synch_ind *roam_sync_ind, + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf) +{ + wmi_roam_synch_event_fixed_param *synch_event; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + wmi_channel *chan = NULL; + wmi_key_material *key; + wmi_key_material_ext *key_ext; + wmi_roam_fils_synch_tlv_param *fils_info; + wmi_roam_pmk_cache_synch_tlv_param *pmk_cache_info; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t kck_len; + uint8_t kek_len; + struct roam_scan_candidate_frame roam_candidate = {0}; + + synch_event = param_buf->fixed_param; + roam_sync_ind->roamed_vdev_id = synch_event->vdev_id; + roam_sync_ind->auth_status = synch_event->auth_status; + roam_sync_ind->roam_reason = synch_event->roam_reason; + roam_sync_ind->rssi = -1 * synch_event->rssi; + roam_sync_ind->is_beacon = synch_event->is_beacon; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&synch_event->bssid, + roam_sync_ind->bssid.bytes); + wmi_debug("roamed_vdev_id %d auth_status %d roam_reason %d rssi %d is_beacon %d", + roam_sync_ind->roamed_vdev_id, + roam_sync_ind->auth_status, + roam_sync_ind->roam_reason, + roam_sync_ind->rssi, + roam_sync_ind->is_beacon); + + cdp_update_roaming_peer_in_vdev(soc, synch_event->vdev_id, + roam_sync_ind->bssid.bytes, + synch_event->auth_status); + /* + * If lengths of bcn_probe_rsp, reassoc_req and reassoc_rsp are zero in + * synch_event driver would have received bcn_probe_rsp, reassoc_req + * and reassoc_rsp via the event WMI_ROAM_SYNCH_FRAME_EVENTID + */ + if ((!synch_event->bcn_probe_rsp_len) && + (!synch_event->reassoc_req_len) && + (!synch_event->reassoc_rsp_len)) { + if (!rso_cfg->roam_sync_frame_ind.bcn_probe_rsp) { + wmi_err("LFR3: bcn_probe_rsp is NULL"); + QDF_ASSERT(rso_cfg->roam_sync_frame_ind.bcn_probe_rsp); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return status; + } + + if (!rso_cfg->roam_sync_frame_ind.reassoc_rsp) { + wmi_err("LFR3: reassoc_rsp is NULL"); + QDF_ASSERT(rso_cfg->roam_sync_frame_ind.reassoc_rsp); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return status; + } + if (!rso_cfg->roam_sync_frame_ind.reassoc_req) { + wmi_err("LFR3: reassoc_req is NULL"); + QDF_ASSERT(rso_cfg->roam_sync_frame_ind.reassoc_req); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return status; + } + wmi_fill_data_synch_frame_event(rso_cfg, roam_sync_ind); + } else { + wmi_fill_data_synch_event(roam_sync_ind, param_buf); + + roam_candidate.vdev_id = roam_sync_ind->roamed_vdev_id; + roam_candidate.frame_length = + roam_sync_ind->beacon_probe_resp_length; + roam_candidate.frame = (uint8_t *)roam_sync_ind + + roam_sync_ind->beacon_probe_resp_offset; + roam_candidate.rssi = roam_sync_ind->rssi; + roam_candidate.roam_offload_candidate_frm = false; + wlan_cm_add_all_link_probe_rsp_to_scan_db(wlan_vdev_get_psoc(vdev), + &roam_candidate); + } + chan = param_buf->chan; + if (chan) { + roam_sync_ind->chan_freq = chan->mhz; + roam_sync_ind->phy_mode = + wlan_cm_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan)); + roam_sync_ind->chan = *chan; + } else { + roam_sync_ind->phy_mode = WLAN_PHYMODE_AUTO; + } + + key = param_buf->key; + key_ext = param_buf->key_ext; + if (key) { + roam_sync_ind->kck_len = KCK_KEY_LEN; + qdf_mem_copy(roam_sync_ind->kck, key->kck, + KCK_KEY_LEN); + roam_sync_ind->kek_len = KEK_KEY_LEN; + qdf_mem_copy(roam_sync_ind->kek, key->kek, + KEK_KEY_LEN); + qdf_mem_copy(roam_sync_ind->replay_ctr, + key->replay_counter, REPLAY_CTR_LEN); + } else if (key_ext) { + /* + * key_ext carries key materials whose size + * is greater than conventional 16bytes. + */ + kck_len = key_ext->kck_len ? + key_ext->kck_len : KCK_192BIT_KEY_LEN; + kek_len = key_ext->kek_len ? + key_ext->kek_len : KEK_256BIT_KEY_LEN; + + roam_sync_ind->kck_len = kck_len; + qdf_mem_copy(roam_sync_ind->kck, + key_ext->key_buffer, kck_len); + + roam_sync_ind->kek_len = kek_len; + qdf_mem_copy(roam_sync_ind->kek, + (key_ext->key_buffer + kck_len), + kek_len); + + qdf_mem_copy(roam_sync_ind->replay_ctr, + (key_ext->key_buffer + kek_len + kck_len), + REPLAY_CTR_LEN); + } + + wmi_debug("ROAM_SYNC kek_len %d kck_len %d", + roam_sync_ind->kek_len, + roam_sync_ind->kck_len); + + if (param_buf->hw_mode_transition_fixed_param) { + wmi_extract_pdev_hw_mode_trans_ind( + param_buf->hw_mode_transition_fixed_param, + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping, + &roam_sync_ind->hw_mode_trans_ind); + roam_sync_ind->hw_mode_trans_present = true; + } else { + wmi_debug("hw_mode transition fixed param is NULL"); + } + + fils_info = param_buf->roam_fils_synch_info; + if (fils_info) { + if ((fils_info->kek_len > MAX_KEK_LENGTH) || + (fils_info->pmk_len > MAX_PMK_LEN)) { + wmi_err("Invalid kek_len %d or pmk_len %d", + fils_info->kek_len, + fils_info->pmk_len); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return status; + } + + roam_sync_ind->kek_len = fils_info->kek_len; + qdf_mem_copy(roam_sync_ind->kek, fils_info->kek, + fils_info->kek_len); + + roam_sync_ind->pmk_len = fils_info->pmk_len; + qdf_mem_copy(roam_sync_ind->pmk, fils_info->pmk, + fils_info->pmk_len); + + qdf_mem_copy(roam_sync_ind->pmkid, fils_info->pmkid, + PMKID_LEN); + + roam_sync_ind->update_erp_next_seq_num = + fils_info->update_erp_next_seq_num; + roam_sync_ind->next_erp_seq_num = + fils_info->next_erp_seq_num; + + wmi_debug("Update ERP Seq Num %d, Next ERP Seq Num %d KEK len %d", + roam_sync_ind->update_erp_next_seq_num, + roam_sync_ind->next_erp_seq_num, + roam_sync_ind->kek_len); + } + + pmk_cache_info = param_buf->roam_pmk_cache_synch_info; + if (pmk_cache_info && (pmk_cache_info->pmk_len)) { + if (pmk_cache_info->pmk_len > MAX_PMK_LEN) { + wmi_err("Invalid pmk_len %d", + pmk_cache_info->pmk_len); + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return status; + } + + roam_sync_ind->pmk_len = pmk_cache_info->pmk_len; + qdf_mem_copy(roam_sync_ind->pmk, + pmk_cache_info->pmk, pmk_cache_info->pmk_len); + qdf_mem_copy(roam_sync_ind->pmkid, + pmk_cache_info->pmkid, PMKID_LEN); + } + + status = wmi_fill_roam_mlo_info(wmi_handle, param_buf, roam_sync_ind); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("Failed to fill roam mlo info"); + return status; + } + wlan_cm_free_roam_synch_frame_ind(rso_cfg); + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_sync_event_tlv() - Extract the roam sync event + * from the wmi_roam_synch_event_id + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @len: Data length + * @roam_sync_ind: Ptr to roam offload sync struct + */ +static QDF_STATUS +extract_roam_sync_event_tlv(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t len, + struct roam_offload_synch_ind **roam_sync_ind) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_roam_synch_event_fixed_param *synch_event = NULL; + WMI_ROAM_SYNCH_EVENTID_param_tlvs *param_buf = NULL; + struct roam_offload_synch_ind *roam_sync = NULL; + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_objmgr_psoc *psoc = NULL; + struct rso_config *rso_cfg; + uint32_t roam_synch_data_len; + uint32_t bcn_probe_rsp_len, link_bcn_probe_rsp_len; + uint32_t reassoc_rsp_len; + uint32_t reassoc_req_len; + wmi_pdev_hw_mode_transition_event_fixed_param *hw_mode_trans_param; + + if (!evt_buf) { + wmi_debug("Empty roam_sync_event param buf"); + return QDF_STATUS_E_FAILURE; + } + + param_buf = (WMI_ROAM_SYNCH_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + wmi_debug("received null buf from target"); + return QDF_STATUS_E_FAILURE; + } + + synch_event = param_buf->fixed_param; + if (!synch_event) { + wmi_debug("received null event data from target"); + return QDF_STATUS_E_FAILURE; + } + hw_mode_trans_param = param_buf->hw_mode_transition_fixed_param; + if (hw_mode_trans_param && + hw_mode_trans_param->num_vdev_mac_entries > + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping) { + wmi_debug("invalid vdev mac entries %d %d in roam sync", + hw_mode_trans_param->num_vdev_mac_entries, + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping); + return QDF_STATUS_E_FAILURE; + } + + if (synch_event->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err("received invalid vdev_id %d", + synch_event->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + psoc = wmi_handle->soc->wmi_psoc; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, synch_event->vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + wmi_err("For vdev:%d object is NULL", synch_event->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (synch_event->bcn_probe_rsp_len > + param_buf->num_bcn_probe_rsp_frame || + synch_event->reassoc_req_len > + param_buf->num_reassoc_req_frame || + synch_event->reassoc_rsp_len > + param_buf->num_reassoc_rsp_frame) { + wmi_debug("Invalid sync payload: LEN bcn:%d, req:%d, rsp:%d, vdev:%d", + synch_event->bcn_probe_rsp_len, + synch_event->reassoc_req_len, + synch_event->reassoc_rsp_len, + synch_event->vdev_id); + status = QDF_STATUS_E_FAILURE; + goto abort_roam; + } + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + status = QDF_STATUS_E_FAILURE; + goto abort_roam; + } + + /* + * All below length fields are unsigned and hence positive numbers. + * Maximum number during the addition would be (3 * MAX_LIMIT(UINT32) + + * few fixed fields). + */ + wmi_debug("synch payload: LEN bcn:%d, req:%d, rsp:%d", + synch_event->bcn_probe_rsp_len, + synch_event->reassoc_req_len, + synch_event->reassoc_rsp_len); + + /* + * If lengths of bcn_probe_rsp, reassoc_req and reassoc_rsp are zero in + * synch_event driver would have received bcn_probe_rsp, reassoc_req + * and reassoc_rsp via the event WMI_ROAM_SYNCH_FRAME_EVENTID + */ + if ((!synch_event->bcn_probe_rsp_len) && + (!synch_event->reassoc_req_len) && + (!synch_event->reassoc_rsp_len)) { + bcn_probe_rsp_len = + rso_cfg->roam_sync_frame_ind.bcn_probe_rsp_len; + link_bcn_probe_rsp_len = + rso_cfg->roam_sync_frame_ind.link_bcn_probe_rsp_len; + reassoc_req_len = rso_cfg->roam_sync_frame_ind.reassoc_req_len; + reassoc_rsp_len = rso_cfg->roam_sync_frame_ind.reassoc_rsp_len; + + roam_synch_data_len = + bcn_probe_rsp_len + link_bcn_probe_rsp_len + + reassoc_rsp_len + reassoc_req_len + + sizeof(struct roam_offload_synch_ind); + + wmi_debug("Updated synch payload: LEN bcn:%d, link bcn: %d req:%d, rsp:%d", + bcn_probe_rsp_len, + link_bcn_probe_rsp_len, + reassoc_req_len, + reassoc_rsp_len); + } else { + bcn_probe_rsp_len = synch_event->bcn_probe_rsp_len; + reassoc_req_len = synch_event->reassoc_req_len; + reassoc_rsp_len = synch_event->reassoc_rsp_len; + + roam_synch_data_len = bcn_probe_rsp_len + + reassoc_rsp_len + reassoc_req_len; + roam_synch_data_len += sizeof(struct roam_offload_synch_ind); + } + + roam_sync = qdf_mem_malloc(roam_synch_data_len); + if (!roam_sync) { + QDF_ASSERT(roam_sync); + status = QDF_STATUS_E_NOMEM; + goto abort_roam; + } + + *roam_sync_ind = roam_sync; + status = wmi_fill_roam_sync_buffer(wmi_handle, vdev, rso_cfg, + roam_sync, param_buf); + +abort_roam: + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("%d Failed to extract roam sync ind", status); + wlan_cm_roam_state_change(wlan_vdev_get_pdev(vdev), + synch_event->vdev_id, + WLAN_ROAM_RSO_STOPPED, + REASON_ROAM_SYNCH_FAILED); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return status; +} + +/** + * extract_roam_sync_frame_event_tlv() - Extract the roam sync frame event + * from the wmi_roam_synch_event_id + * @wmi_handle: wmi handle + * @event: Pointer to the event buffer + * @len: event buffer length + * @frame_ptr: wmi sync frame event ptr + */ +static QDF_STATUS +extract_roam_sync_frame_event_tlv(wmi_unified_t wmi_handle, void *event, + uint32_t len, + struct roam_synch_frame_ind *frame_ptr) +{ + WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *param_buf = NULL; + struct roam_synch_frame_ind *frame_ind; + wmi_roam_synch_frame_event_fixed_param *frame_evt; + + if (!event) { + wmi_err("Event param null"); + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_ROAM_SYNCH_FRAME_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err("received null buf from target"); + return QDF_STATUS_E_NULL_VALUE; + } + + frame_evt = param_buf->fixed_param; + if (!frame_evt) { + wmi_err("received null event data from target"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (frame_evt->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err("received invalid vdev_id %d", frame_evt->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* + * Firmware can send more than one roam synch frame event to host + * driver. So Bcn_prb_rsp_len/reassoc_req_len/reassoc_rsp_len can be 0 + * in some of the events. + */ + if (frame_evt->bcn_probe_rsp_len > param_buf->num_bcn_probe_rsp_frame || + frame_evt->reassoc_req_len > param_buf->num_reassoc_req_frame || + frame_evt->reassoc_rsp_len > param_buf->num_reassoc_rsp_frame || + (frame_evt->bcn_probe_rsp_len && + frame_evt->bcn_probe_rsp_len < sizeof(struct wlan_frame_hdr)) || + (frame_evt->reassoc_req_len && + frame_evt->reassoc_req_len < sizeof(struct wlan_frame_hdr)) || + (frame_evt->reassoc_rsp_len && + frame_evt->reassoc_rsp_len < sizeof(struct wlan_frame_hdr))) { + wmi_err("fixed/actual len err: bcn:%d/%d req:%d/%d rsp:%d/%d", + frame_evt->bcn_probe_rsp_len, + param_buf->num_bcn_probe_rsp_frame, + frame_evt->reassoc_req_len, + param_buf->num_reassoc_req_frame, + frame_evt->reassoc_rsp_len, + param_buf->num_reassoc_rsp_frame); + return QDF_STATUS_E_FAILURE; + } + + frame_ind = frame_ptr; + frame_ind->vdev_id = frame_evt->vdev_id; + + wmi_debug("synch frame payload: LEN %s bcn:%d, req:%d, rsp:%d", + frame_evt->reassoc_rsp_len ? "Assoc" : "Link", + frame_evt->bcn_probe_rsp_len, + frame_evt->reassoc_req_len, + frame_evt->reassoc_rsp_len); + + if (frame_evt->bcn_probe_rsp_len && + frame_evt->reassoc_rsp_len) { + frame_ind->bcn_probe_rsp_len = frame_evt->bcn_probe_rsp_len; + + frame_ind->is_beacon = frame_evt->is_beacon; + + frame_ind->bcn_probe_rsp = + qdf_mem_malloc(frame_ind->bcn_probe_rsp_len); + if (!frame_ind->bcn_probe_rsp) { + QDF_ASSERT(frame_ind->bcn_probe_rsp); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(frame_ind->bcn_probe_rsp, + param_buf->bcn_probe_rsp_frame, + frame_ind->bcn_probe_rsp_len); + } else if (frame_evt->bcn_probe_rsp_len) { + frame_ind->link_bcn_probe_rsp_len = + frame_evt->bcn_probe_rsp_len; + + frame_ind->is_link_beacon = frame_evt->is_beacon; + + if (frame_ind->link_bcn_probe_rsp) + qdf_mem_free(frame_ind->bcn_probe_rsp); + + frame_ind->link_bcn_probe_rsp = + qdf_mem_malloc(frame_ind->link_bcn_probe_rsp_len); + if (!frame_ind->link_bcn_probe_rsp) { + QDF_ASSERT(frame_ind->link_bcn_probe_rsp); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(frame_ind->link_bcn_probe_rsp, + param_buf->bcn_probe_rsp_frame, + frame_ind->link_bcn_probe_rsp_len); + } + + if (frame_evt->reassoc_req_len) { + frame_ind->reassoc_req_len = frame_evt->reassoc_req_len; + + frame_ind->reassoc_req = + qdf_mem_malloc(frame_ind->reassoc_req_len); + if (!frame_ind->reassoc_req) { + QDF_ASSERT(frame_ind->reassoc_req); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(frame_ind->reassoc_req, + param_buf->reassoc_req_frame, + frame_ind->reassoc_req_len); + } + + if (frame_evt->reassoc_rsp_len) { + frame_ind->reassoc_rsp_len = frame_evt->reassoc_rsp_len; + + frame_ind->reassoc_rsp = + qdf_mem_malloc(frame_ind->reassoc_rsp_len); + if (!frame_ind->reassoc_rsp) { + QDF_ASSERT(frame_ind->reassoc_rsp); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(frame_ind->reassoc_rsp, + param_buf->reassoc_rsp_frame, + frame_ind->reassoc_rsp_len); + } + + return QDF_STATUS_SUCCESS; +} + +static enum dlm_reject_ap_reason wmi_get_reject_reason(uint32_t reason) +{ + switch (reason) { + case WMI_BL_REASON_NUD_FAILURE: + return REASON_NUD_FAILURE; + case WMI_BL_REASON_STA_KICKOUT: + return REASON_STA_KICKOUT; + case WMI_BL_REASON_ROAM_HO_FAILURE: + return REASON_ROAM_HO_FAILURE; + case WMI_BL_REASON_ASSOC_REJECT_POOR_RSSI: + return REASON_ASSOC_REJECT_POOR_RSSI; + case WMI_BL_REASON_ASSOC_REJECT_OCE: + return REASON_ASSOC_REJECT_OCE; + case WMI_BL_REASON_USERSPACE_BL: + return REASON_USERSPACE_BL; + case WMI_BL_REASON_USERSPACE_AVOID_LIST: + return REASON_USERSPACE_AVOID_LIST; + case WMI_BL_REASON_BTM_DIASSOC_IMMINENT: + return REASON_BTM_DISASSOC_IMMINENT; + case WMI_BL_REASON_BTM_BSS_TERMINATION: + return REASON_BTM_BSS_TERMINATION; + case WMI_BL_REASON_BTM_MBO_RETRY: + return REASON_BTM_MBO_RETRY; + case WMI_BL_REASON_REASSOC_RSSI_REJECT: + return REASON_REASSOC_RSSI_REJECT; + case WMI_BL_REASON_REASSOC_NO_MORE_STAS: + return REASON_REASSOC_NO_MORE_STAS; + default: + return REASON_UNKNOWN; + } +} + +static QDF_STATUS +extract_btm_denylist_event(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + struct roam_denylist_event **list) +{ + WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *param_buf; + wmi_roam_blacklist_event_fixed_param *resp_event; + wmi_roam_blacklist_with_timeout_tlv_param *src_list; + struct roam_denylist_timeout *roam_denylist; + struct roam_denylist_event *dst_list; + uint32_t num_entries, i; + + param_buf = (WMI_ROAM_BLACKLIST_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err("Invalid event buffer"); + return QDF_STATUS_E_INVAL; + } + + resp_event = param_buf->fixed_param; + if (!resp_event) { + wmi_err("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + if (resp_event->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err("received invalid vdev_id %d", resp_event->vdev_id); + return QDF_STATUS_E_INVAL; + } + + num_entries = param_buf->num_blacklist_with_timeout; + if (num_entries == 0) + return QDF_STATUS_SUCCESS; + + if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) { + wmi_err("num blacklist entries:%d exceeds maximum value", + num_entries); + return QDF_STATUS_E_INVAL; + } + + src_list = param_buf->blacklist_with_timeout; + if (len < (sizeof(*resp_event) + (num_entries * sizeof(*src_list)))) { + wmi_err("Invalid length:%d", len); + return QDF_STATUS_E_INVAL; + } + + dst_list = qdf_mem_malloc(sizeof(struct roam_denylist_event) + + (sizeof(struct roam_denylist_timeout) * + num_entries)); + if (!dst_list) + return QDF_STATUS_E_NOMEM; + + dst_list->vdev_id = resp_event->vdev_id; + roam_denylist = &dst_list->roam_denylist[0]; + for (i = 0; i < num_entries; i++) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid, + roam_denylist->bssid.bytes); + roam_denylist->timeout = src_list->timeout; + roam_denylist->received_time = src_list->timestamp; + roam_denylist->original_timeout = src_list->original_timeout; + roam_denylist->reject_reason = + wmi_get_reject_reason(src_list->reason); + roam_denylist->source = src_list->source; + roam_denylist++; + src_list++; + } + + dst_list->num_entries = num_entries; + *list = dst_list; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +extract_vdev_disconnect_event_tlv(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct vdev_disconnect_event_data *data) +{ + WMI_VDEV_DISCONNECT_EVENTID_param_tlvs *param_buf; + wmi_vdev_disconnect_event_fixed_param *roam_vdev_disc_ev; + + param_buf = (WMI_VDEV_DISCONNECT_EVENTID_param_tlvs *)event; + + roam_vdev_disc_ev = param_buf->fixed_param; + if (!roam_vdev_disc_ev) { + wmi_err("roam cap event is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (roam_vdev_disc_ev->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err("Invalid vdev id %d", roam_vdev_disc_ev->vdev_id); + return QDF_STATUS_E_INVAL; + } + data->vdev_id = roam_vdev_disc_ev->vdev_id; + data->reason = roam_vdev_disc_ev->reason; + + wmi_debug("Received disconnect roam event on vdev_id : %d, reason:%d", + data->vdev_id, data->reason); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +extract_roam_scan_chan_list_tlv(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct cm_roam_scan_ch_resp **list) +{ + WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *param_buf; + wmi_roam_scan_channel_list_event_fixed_param *fixed_param; + struct cm_roam_scan_ch_resp *data; + uint8_t i = 0, num_ch = 0; + + param_buf = (WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err_rl("NULL event received from target"); + return -EINVAL; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + wmi_err_rl(" NULL fixed param"); + return -EINVAL; + } + + if (fixed_param->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err_rl("Invalid vdev_id %d", fixed_param->vdev_id); + return -EINVAL; + } + + num_ch = (param_buf->num_channel_list < CM_CFG_VALID_CHANNEL_LIST_LEN) ? + param_buf->num_channel_list : CM_CFG_VALID_CHANNEL_LIST_LEN; + + data = qdf_mem_malloc(sizeof(struct cm_roam_scan_ch_resp) + + num_ch * sizeof(param_buf->channel_list[0])); + if (!data) + return -EINVAL; + + data->chan_list = (uint32_t *)(data + 1); + data->vdev_id = fixed_param->vdev_id; + data->command_resp = fixed_param->command_response; + data->num_channels = param_buf->num_channel_list; + + for (i = 0; i < num_ch; i++) + data->chan_list[i] = param_buf->channel_list[i]; + + *list = data; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +extract_roam_stats_with_single_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf, + struct roam_stats_event *stats_info) +{ + QDF_STATUS status; + uint8_t vdev_id = stats_info->vdev_id; + + status = wmi_unified_extract_roam_scan_stats( + wmi_handle, evt_buf, &stats_info->scan[0], 0, 0, 0); + if (QDF_IS_STATUS_ERROR(status)) + wmi_debug("Roam scan stats extract failed vdev %d", vdev_id); + + status = wmi_unified_extract_roam_11kv_stats( + wmi_handle, evt_buf, &stats_info->data_11kv[0], 0, 0); + if (QDF_IS_STATUS_ERROR(status)) + wmi_debug("Roam 11kv stats extract failed vdev %d", vdev_id); + + status = wmi_unified_extract_roam_trigger_stats( + wmi_handle, evt_buf, &stats_info->trigger[0], 0, 0); + if (QDF_IS_STATUS_ERROR(status)) + wmi_debug("Extract roamtrigger stats failed vdev %d", + vdev_id); + + status = wmi_unified_extract_roam_btm_response( + wmi_handle, evt_buf, &stats_info->btm_rsp[0], 0); + if (QDF_IS_STATUS_ERROR(status)) + wmi_debug("Roam btm rsp stats extract fail vdev %d", + vdev_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_stats_event_tlv() - Extract the roam stats event + * from the wmi_roam_stats_event_id + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @len: Data length + * @data: Double pointer to roam stats data + */ +static QDF_STATUS +extract_roam_stats_event_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf, + uint32_t len, + struct roam_stats_event **data) +{ + WMI_ROAM_STATS_EVENTID_param_tlvs *param_buf; + wmi_roam_stats_event_fixed_param *fixed_param; + struct roam_stats_event *stats_info; + struct roam_msg_info *roam_msg_info = NULL; + uint8_t vdev_id, i, num_btm = 0, num_frames = 0; + uint8_t num_tlv = 0, num_chan = 0, num_ap = 0, num_rpt = 0; + uint8_t num_trigger_reason = 0; + uint32_t rem_len; + QDF_STATUS status; + + param_buf = (WMI_ROAM_STATS_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + wmi_err_rl("NULL event received from target"); + return QDF_STATUS_E_INVAL; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + wmi_err_rl(" NULL fixed param"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = fixed_param->vdev_id; + + if (vdev_id >= WLAN_MAX_VDEVS) { + wmi_err_rl("Invalid vdev_id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + num_tlv = fixed_param->roam_scan_trigger_count; + if (num_tlv > MAX_ROAM_SCAN_STATS_TLV) { + wmi_err_rl("Limiting roam triggers to 5"); + num_tlv = MAX_ROAM_SCAN_STATS_TLV; + } + + if (param_buf->roam_trigger_reason) + num_trigger_reason = num_tlv; + else + num_trigger_reason = 0; + + rem_len = len - sizeof(*fixed_param); + if (rem_len < num_trigger_reason * sizeof(wmi_roam_trigger_reason)) { + wmi_err_rl("Invalid roam trigger data"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= num_trigger_reason * sizeof(wmi_roam_trigger_reason); + if (rem_len < num_tlv * sizeof(wmi_roam_scan_info)) { + wmi_err_rl("Invalid roam scan data"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= num_tlv * sizeof(wmi_roam_scan_info); + if (rem_len < num_tlv * sizeof(wmi_roam_result)) { + wmi_err_rl("Invalid roam result data"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= num_tlv * sizeof(wmi_roam_result); + if (rem_len < (num_tlv * sizeof(wmi_roam_neighbor_report_info))) { + wmi_err_rl("Invalid roam neighbor report data"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= num_tlv * sizeof(wmi_roam_neighbor_report_info); + if (rem_len < (param_buf->num_roam_scan_chan_info * + sizeof(wmi_roam_scan_channel_info))) { + wmi_err_rl("Invalid roam chan data num_tlv:%d", + param_buf->num_roam_scan_chan_info); + return QDF_STATUS_E_INVAL; + } + + rem_len -= param_buf->num_roam_scan_chan_info * + sizeof(wmi_roam_scan_channel_info); + + if (rem_len < (param_buf->num_roam_ap_info * + sizeof(wmi_roam_ap_info))) { + wmi_err_rl("Invalid roam ap data num_tlv:%d", + param_buf->num_roam_ap_info); + return QDF_STATUS_E_INVAL; + } + + rem_len -= param_buf->num_roam_ap_info * sizeof(wmi_roam_ap_info); + if (rem_len < (param_buf->num_roam_neighbor_report_chan_info * + sizeof(wmi_roam_neighbor_report_channel_info))) { + wmi_err_rl("Invalid roam neigb rpt chan data num_tlv:%d", + param_buf->num_roam_neighbor_report_chan_info); + return QDF_STATUS_E_INVAL; + } + + rem_len -= param_buf->num_roam_neighbor_report_chan_info * + sizeof(wmi_roam_neighbor_report_channel_info); + if (rem_len < param_buf->num_roam_btm_response_info * + sizeof(wmi_roam_btm_response_info)) { + wmi_err_rl("Invalid btm rsp data"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= param_buf->num_roam_btm_response_info * + sizeof(wmi_roam_btm_response_info); + if (rem_len < param_buf->num_roam_initial_info * + sizeof(wmi_roam_initial_info)) { + wmi_err_rl("Invalid Initial roam info"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= param_buf->num_roam_initial_info * + sizeof(wmi_roam_initial_info); + if (rem_len < param_buf->num_roam_msg_info * + sizeof(wmi_roam_msg_info)) { + wmi_err_rl("Invalid roam msg info"); + return QDF_STATUS_E_INVAL; + } + + rem_len -= param_buf->num_roam_msg_info * sizeof(wmi_roam_msg_info); + if (rem_len < + param_buf->num_roam_frame_info * sizeof(wmi_roam_frame_info)) { + wmi_err_rl("Invalid roam frame info"); + return QDF_STATUS_E_INVAL; + } + + stats_info = qdf_mem_malloc(sizeof(struct roam_stats_event)); + if (!stats_info) { + status = QDF_STATUS_E_NOMEM; + goto err; + } + *data = stats_info; + qdf_mem_set(stats_info, sizeof(struct roam_stats_event), 0); + stats_info->vdev_id = vdev_id; + stats_info->num_roam_msg_info = param_buf->num_roam_msg_info; + stats_info->num_tlv = num_tlv; + + if (!num_tlv) + extract_roam_stats_with_single_tlv(wmi_handle, evt_buf, + stats_info); + + for (i = 0; i < num_tlv; i++) { + /* + * Roam Trigger id and that specific roam trigger related + * details. + */ + status = wmi_unified_extract_roam_trigger_stats(wmi_handle, + evt_buf, + &stats_info->trigger[i], i, + num_btm); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_debug_rl("Extract roam trigger stats failed vdev %d at %d iteration", + vdev_id, i); + status = QDF_STATUS_E_INVAL; + goto err; + } + + if (stats_info->trigger[i].trigger_reason == + WMI_ROAM_TRIGGER_REASON_BTM) + num_btm += stats_info->trigger[i].btm_trig_data.candidate_list_count; + + /* Roam scan related details - Scan channel, scan type .. */ + status = wmi_unified_extract_roam_scan_stats(wmi_handle, + evt_buf, + &stats_info->scan[i], i, + num_chan, num_ap); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_debug_rl("Roam scan stats extract failed vdev %d at %d iteration", + vdev_id, i); + status = QDF_STATUS_E_INVAL; + goto err; + } + num_chan += stats_info->scan[i].num_chan; + num_ap += stats_info->scan[i].num_ap; + num_frames = stats_info->scan[i].frame_info_count; + + /* Roam result - Success/Failure status, failure reason */ + status = wmi_unified_extract_roam_result_stats(wmi_handle, + evt_buf, + &stats_info->result[i], i); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_debug_rl("Roam result stats extract failed vdev %d at %d iteration", + vdev_id, i); + status = QDF_STATUS_E_INVAL; + goto err; + } + + if (num_frames) { + status = wmi_unified_extract_roam_extract_frame_info( + wmi_handle, evt_buf, + &stats_info->frame_stats[i], i, + num_frames); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_debug_rl("Roam frame stats extract failed vdev %d at %d iteration", + vdev_id, i); + status = QDF_STATUS_E_INVAL; + goto err; + } + } + + /* BTM req/resp or Neighbor report/response info */ + status = wmi_unified_extract_roam_11kv_stats( + wmi_handle, + evt_buf, + &stats_info->data_11kv[i], + i, num_rpt); + if (QDF_IS_STATUS_ERROR(status)) + wmi_debug_rl("Roam 11kv stats extract fail vdev %d iter %d", + vdev_id, i); + + if (stats_info->data_11kv[i].present) + num_rpt += stats_info->data_11kv[i].num_freq; + + /* BTM resp info */ + status = wmi_unified_extract_roam_btm_response(wmi_handle, + evt_buf, + &stats_info->btm_rsp[i], + i); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_debug_rl("Roam btm rsp stats extract fail vdev %d at %d iteration", + vdev_id, i); + status = QDF_STATUS_E_INVAL; + goto err; + } + + /* Initial Roam info */ + status = wmi_unified_extract_roam_initial_info(wmi_handle, + evt_buf, + &stats_info->roam_init_info[i], i); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_debug_rl("Initial roam stats extract fail vdev %d at %d iteration", + vdev_id, i); + status = QDF_STATUS_E_INVAL; + goto err; + } + } + + if (param_buf->roam_msg_info && param_buf->num_roam_msg_info) { + roam_msg_info = qdf_mem_malloc(param_buf->num_roam_msg_info * + sizeof(*roam_msg_info)); + if (!roam_msg_info) { + status = QDF_STATUS_E_NOMEM; + goto err; + } + stats_info->roam_msg_info = roam_msg_info; + for (i = 0; i < param_buf->num_roam_msg_info; i++) { + status = wmi_unified_extract_roam_msg_info(wmi_handle, + evt_buf, + &roam_msg_info[i], i); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("roam msg stats extract fail vdev %d", + vdev_id); + status = QDF_STATUS_E_INVAL; + goto err; + } + } + } + return QDF_STATUS_SUCCESS; +err: + if (stats_info) { + if (roam_msg_info) + qdf_mem_free(roam_msg_info); + qdf_mem_free(stats_info); + } + return status; +} + +static QDF_STATUS +extract_auth_offload_event_tlv(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + struct auth_offload_event *auth_event) +{ + wmi_roam_preauth_start_event_fixed_param *rso_auth_start_ev; + WMI_ROAM_PREAUTH_START_EVENTID_param_tlvs *param_buf; + + param_buf = (WMI_ROAM_PREAUTH_START_EVENTID_param_tlvs *) event; + + rso_auth_start_ev = param_buf->fixed_param; + if (!rso_auth_start_ev) { + wmi_debug("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + if (rso_auth_start_ev->vdev_id > WLAN_MAX_VDEVS) { + wmi_debug("received invalid vdev_id %d", + rso_auth_start_ev->vdev_id); + return QDF_STATUS_E_INVAL; + } + + auth_event->vdev_id = rso_auth_start_ev->vdev_id; + auth_event->akm = rso_auth_start_ev->akm_suite_type; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&rso_auth_start_ev->candidate_ap_bssid, + auth_event->ap_bssid.bytes); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&rso_auth_start_ev->transmit_addr, + auth_event->ta.bytes); + if (qdf_is_macaddr_zero(&auth_event->ap_bssid) || + qdf_is_macaddr_broadcast(&auth_event->ap_bssid) || + qdf_is_macaddr_group(&auth_event->ap_bssid)) { + wmi_debug("Invalid bssid"); + return -EINVAL; + } + + wmi_debug("Received Roam auth offload event for bss:" + QDF_MAC_ADDR_FMT " ta:" QDF_MAC_ADDR_FMT " vdev_id: %d akm: %d", + QDF_MAC_ADDR_REF(auth_event->ap_bssid.bytes), + QDF_MAC_ADDR_REF(auth_event->ta.bytes), + auth_event->vdev_id, auth_event->akm); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_roam_pmkid_request_tlv() - Extract the roam pmkid request event + * @wmi_handle: wmi handle + * @evt_buf: Pointer to the event buffer + * @len: Data length + * @list: Extract the data and fill in list + */ +static QDF_STATUS +extract_roam_pmkid_request_tlv(wmi_unified_t wmi_handle, uint8_t *evt_buf, + uint32_t len, + struct roam_pmkid_req_event **list) +{ + WMI_ROAM_PMKID_REQUEST_EVENTID_param_tlvs *param_buf; + wmi_roam_pmkid_request_event_fixed_param *roam_pmkid_req_ev; + wmi_roam_pmkid_request_tlv_param *src_list; + struct qdf_mac_addr *roam_bsslist; + uint32_t num_entries, i; + struct roam_pmkid_req_event *dst_list; + + if (!evt_buf || !len) { + wmi_err("received null event from target"); + return QDF_STATUS_E_INVAL; + } + + param_buf = (WMI_ROAM_PMKID_REQUEST_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + wmi_err("received null buf from target"); + return QDF_STATUS_E_INVAL; + } + + roam_pmkid_req_ev = param_buf->fixed_param; + if (!roam_pmkid_req_ev) { + wmi_err("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + if (roam_pmkid_req_ev->vdev_id >= WLAN_MAX_VDEVS) { + wmi_err_rl("Invalid vdev_id %d", roam_pmkid_req_ev->vdev_id); + return QDF_STATUS_E_INVAL; + } + + num_entries = param_buf->num_pmkid_request; + if (num_entries > MAX_RSSI_AVOID_BSSID_LIST) { + wmi_err("num bssid entries:%d exceeds maximum value", + num_entries); + return QDF_STATUS_E_INVAL; + } + + src_list = param_buf->pmkid_request; + if (len < (sizeof(*roam_pmkid_req_ev) + + (num_entries * sizeof(*src_list)))) { + wmi_err("Invalid length: %d", len); + return QDF_STATUS_E_INVAL; + } + + dst_list = qdf_mem_malloc(sizeof(struct roam_pmkid_req_event) + + (sizeof(struct qdf_mac_addr) * num_entries)); + if (!dst_list) + return QDF_STATUS_E_NOMEM; + + dst_list->vdev_id = roam_pmkid_req_ev->vdev_id; + + for (i = 0; i < num_entries; i++) { + roam_bsslist = &dst_list->ap_bssid[i]; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_list->bssid, + roam_bsslist->bytes); + if (qdf_is_macaddr_zero(roam_bsslist) || + qdf_is_macaddr_broadcast(roam_bsslist) || + qdf_is_macaddr_group(roam_bsslist)) { + wmi_err("Invalid bssid"); + qdf_mem_free(dst_list); + return QDF_STATUS_E_INVAL; + } + wmi_debug("Received pmkid fallback for bssid: " QDF_MAC_ADDR_FMT" vdev_id:%d", + QDF_MAC_ADDR_REF(roam_bsslist->bytes), + roam_pmkid_req_ev->vdev_id); + src_list++; + } + dst_list->num_entries = num_entries; + *list = dst_list; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +extract_roam_candidate_frame_tlv(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct roam_scan_candidate_frame *data) +{ + WMI_ROAM_FRAME_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_frame_event_fixed_param *frame_params = NULL; + + if (!event || !len) { + wmi_debug("Empty roam candidate frame event"); + return QDF_STATUS_E_FAILURE; + } + + param_buf = (WMI_ROAM_FRAME_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err("received null buf from target"); + return -EINVAL; + } + + frame_params = + (wmi_roam_frame_event_fixed_param *)param_buf->fixed_param; + + if (frame_params->vdev_id >= WLAN_MAX_VDEVS) { + wmi_debug("Invalid VDEV id %d", frame_params->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (frame_params->frame_length > param_buf->num_frame) { + wmi_debug("Invalid frame length %d expected : %d", + frame_params->frame_length, + param_buf->num_frame); + return QDF_STATUS_E_FAILURE; + } + + if (!param_buf->frame) { + wmi_debug("Frame pointer is Null"); + return QDF_STATUS_E_FAILURE; + } + + data->vdev_id = frame_params->vdev_id; + data->frame_length = frame_params->frame_length; + data->frame = (uint8_t *)param_buf->frame; + data->roam_offload_candidate_frm = true; + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, + data->frame, data->frame_length); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static QDF_STATUS +extract_peer_oper_mode_event_tlv(wmi_unified_t wmi_handle, uint8_t *event, + uint32_t len, + struct peer_oper_mode_event *data) +{ + WMI_PEER_OPER_MODE_CHANGE_EVENTID_param_tlvs *param_buf = NULL; + wmi_peer_oper_mode_change_event_fixed_param *params = NULL; + + if (!event || !len) { + wmi_debug("Empty operating mode change event"); + return QDF_STATUS_E_FAILURE; + } + + param_buf = (WMI_PEER_OPER_MODE_CHANGE_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err("Received null buf from target"); + return -EINVAL; + } + + params = + (wmi_peer_oper_mode_change_event_fixed_param *)param_buf->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(¶ms->peer_mac_address, + data->peer_mac_address.bytes); + data->ind_type = params->ind_type; + data->new_rxnss = params->new_rxnss; + data->new_bw = params->new_bw; + data->new_txnss = params->new_txnss; + data->new_disablemu = params->new_disablemu; + + wmi_debug("peer_mac_addr: " QDF_MAC_ADDR_FMT " ind_type: %d new_rxnss: %d new_bw: %d new_txnss: %d new_disablemu: %d", + QDF_MAC_ADDR_REF(data->peer_mac_address.bytes), + data->ind_type, + data->new_rxnss, + data->new_bw, + data->new_txnss, + data->new_disablemu); + + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * convert_roam_vendor_control_param() - Function to convert + * vendor_control_roam_param enum to TLV specific + * WMI_ROAM_GET_VENDOR_CONTROL_PARAM_ID + * @param_id: Roam vendor control param id + * + * Return: wmi roam vendor control param id + */ +static WMI_ROAM_GET_VENDOR_CONTROL_PARAM_ID +convert_roam_vendor_control_param(enum vendor_control_roam_param param_id) +{ + switch (param_id) { + case VENDOR_CONTROL_PARAM_ROAM_TRIGGER: + return ROAM_VENDOR_CONTROL_PARAM_TRIGGER; + case VENDOR_CONTROL_PARAM_ROAM_DELTA: + return ROAM_VENDOR_CONTROL_PARAM_DELTA; + case VENDOR_CONTROL_PARAM_ROAM_FULL_SCANPERIOD: + return ROAM_VENDOR_CONTROL_PARAM_FULL_SCANPERIOD; + case VENDOR_CONTROL_PARAM_ROAM_PARTIAL_SCANPERIOD: + return ROAM_VENDOR_CONTROL_PARAM_PARTIAL_SCANPERIOD; + case VENDOR_CONTROL_PARAM_ROAM_ACTIVE_CH_DWELLTIME: + return ROAM_VENDOR_CONTROL_PARAM_ACTIVE_CH_DWELLTIME; + case VENDOR_CONTROL_PARAM_ROAM_PASSIVE_CH_DWELLTIME: + return ROAM_VENDOR_CONTROL_PARAM_PASSIVE_CH_DWELLTIME; + case VENDOR_CONTROL_PARAM_ROAM_HOME_CH_TIME: + return ROAM_VENDOR_CONTROL_PARAM_HOME_CH_TIME; + case VENDOR_CONTROL_PARAM_ROAM_AWAY_TIME: + return ROAM_VENDOR_CONTROL_PARAM_AWAY_TIME; + case VENDOR_CONTROL_PARAM_ROAM_ALL: + return ROAM_VENDOR_CONTROL_PARAM_ALL; + default: + wmi_debug("Invalid param id"); + return 0; + } +} + +/** + * convert_wmi_roam_vendor_control_param() - Function to convert TLV specific + * WMI_ROAM_GET_VENDOR_CONTROL_PARAM_ID to vendor_control_roam_param + * @param_id: wmi vendor control param id + * + * Return: roam vendor control param id + */ +static enum vendor_control_roam_param convert_wmi_roam_vendor_control_param( + WMI_ROAM_GET_VENDOR_CONTROL_PARAM_ID param_id) +{ + switch (param_id) { + case ROAM_VENDOR_CONTROL_PARAM_TRIGGER: + return VENDOR_CONTROL_PARAM_ROAM_TRIGGER; + case ROAM_VENDOR_CONTROL_PARAM_DELTA: + return VENDOR_CONTROL_PARAM_ROAM_DELTA; + case ROAM_VENDOR_CONTROL_PARAM_FULL_SCANPERIOD: + return VENDOR_CONTROL_PARAM_ROAM_FULL_SCANPERIOD; + case ROAM_VENDOR_CONTROL_PARAM_PARTIAL_SCANPERIOD: + return VENDOR_CONTROL_PARAM_ROAM_PARTIAL_SCANPERIOD; + case ROAM_VENDOR_CONTROL_PARAM_ACTIVE_CH_DWELLTIME: + return VENDOR_CONTROL_PARAM_ROAM_ACTIVE_CH_DWELLTIME; + case ROAM_VENDOR_CONTROL_PARAM_PASSIVE_CH_DWELLTIME: + return VENDOR_CONTROL_PARAM_ROAM_PASSIVE_CH_DWELLTIME; + case ROAM_VENDOR_CONTROL_PARAM_HOME_CH_TIME: + return VENDOR_CONTROL_PARAM_ROAM_HOME_CH_TIME; + case ROAM_VENDOR_CONTROL_PARAM_AWAY_TIME: + return VENDOR_CONTROL_PARAM_ROAM_AWAY_TIME; + case ROAM_VENDOR_CONTROL_PARAM_ALL: + return VENDOR_CONTROL_PARAM_ROAM_ALL; + default: + wmi_debug("Invalid param id"); + return 0; + } +} + +static QDF_STATUS +extract_roam_vendor_control_param_event_tlv(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t len, + struct roam_vendor_handoff_params **list) +{ + WMI_ROAM_GET_VENDOR_CONTROL_PARAM_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_get_vendor_control_param_event_fixed_param *fixed_param = NULL; + uint32_t num_entries, i; + wmi_vendor_control_param *src_list; + struct roam_vendor_handoff_params *dst_list; + struct roam_param_info *param_info; + + if (!event || !len) { + wmi_debug("Empty roam vendor control param event"); + return QDF_STATUS_E_FAILURE; + } + + param_buf = + (WMI_ROAM_GET_VENDOR_CONTROL_PARAM_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err("received null buf from target"); + return QDF_STATUS_E_INVAL; + } + + fixed_param = (wmi_roam_get_vendor_control_param_event_fixed_param *) + param_buf->fixed_param; + if (!fixed_param) { + wmi_err("received null event data from target"); + return QDF_STATUS_E_INVAL; + } + + if (fixed_param->vdev_id >= WLAN_MAX_VDEVS) { + wmi_debug("Invalid VDEV id %d", fixed_param->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + num_entries = param_buf->num_vendor_control_param; + src_list = param_buf->vendor_control_param; + + if (len < (sizeof(*fixed_param) + (num_entries * sizeof(*src_list)))) { + wmi_err("Invalid length: %d", len); + return QDF_STATUS_E_FAILURE; + } + + dst_list = qdf_mem_malloc(sizeof(struct roam_vendor_handoff_params)); + if (!dst_list) + return QDF_STATUS_E_FAILURE; + + dst_list->vdev_id = fixed_param->vdev_id; + wmi_debug("vdev_id:%d, num_tlv:%d", dst_list->vdev_id, num_entries); + + param_info = &dst_list->param_info[0]; + for (i = 0; i < num_entries; i++) { + param_info->param_id = + convert_wmi_roam_vendor_control_param(src_list->param_id); + param_info->param_value = src_list->param_value; + wmi_debug("param_info->param_id:%d, param_info->param_value:%d", + param_info->param_id, param_info->param_value); + param_info++; + src_list++; + } + + dst_list->num_entries = num_entries; + *list = dst_list; + + return QDF_STATUS_SUCCESS; +} + +/** + * send_process_roam_vendor_handoff_req_cmd_tlv() - Send vendor handoff command + * to fw. + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param_id: parameter ID to set + * + * Return: QDF STATUS + */ +static QDF_STATUS +send_process_roam_vendor_handoff_req_cmd_tlv(wmi_unified_t wmi_handle, + uint8_t vdev_id, + uint32_t param_id) +{ + wmi_roam_get_vendor_control_param_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint16_t len; + + len = sizeof(wmi_roam_get_vendor_control_param_cmd_fixed_param); + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_get_vendor_control_param_cmd_fixed_param *)wmi_buf_data( + wmi_buf); + buf_ptr = (uint8_t *)cmd; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_get_vendor_control_param_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_get_vendor_control_param_cmd_fixed_param)); + cmd->vdev_id = vdev_id; + cmd->param_id = convert_roam_vendor_control_param(param_id); + wmi_debug("Send GET_VENDOR_CONTROL_PARAM cmd vdev_id:%d, param_id:0x%x", + cmd->vdev_id, cmd->param_id); + wmi_mtrace(WMI_ROAM_GET_VENDOR_CONTROL_PARAM_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ROAM_GET_VENDOR_CONTROL_PARAM_CMDID)) { + wmi_err("Failed to send get vendor control param command"); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wmi_roam_offload_attach_vendor_handoff_tlv() - register wmi ops for vendor + * handoff related command and event + * @ops: wmi ops + * + * Return: none + */ +static inline void +wmi_roam_offload_attach_vendor_handoff_tlv(struct wmi_ops *ops) +{ + ops->extract_roam_vendor_control_param_event = + extract_roam_vendor_control_param_event_tlv; + ops->send_process_roam_vendor_handoff_req_cmd = + send_process_roam_vendor_handoff_req_cmd_tlv; +} +#else +static inline void +wmi_roam_offload_attach_vendor_handoff_tlv(struct wmi_ops *ops) +{ +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +static inline +enum wlan_crypto_cipher_type wlan_wmi_cipher_to_crypto(uint8_t cipher) +{ + switch (cipher) { + case WMI_CIPHER_NONE: + return WLAN_CRYPTO_CIPHER_NONE; + case WMI_CIPHER_WEP: + return WLAN_CRYPTO_CIPHER_WEP; + case WMI_CIPHER_TKIP: + return WLAN_CRYPTO_CIPHER_TKIP; + case WMI_CIPHER_AES_OCB: + return WLAN_CRYPTO_CIPHER_AES_OCB; + case WMI_CIPHER_AES_CCM: + return WLAN_CRYPTO_CIPHER_AES_CCM; + case WMI_CIPHER_WAPI: + return WLAN_CRYPTO_CIPHER_WAPI_SMS4; + case WMI_CIPHER_CKIP: + return WLAN_CRYPTO_CIPHER_CKIP; + case WMI_CIPHER_AES_CMAC: + return WLAN_CRYPTO_CIPHER_AES_CMAC; + case WMI_CIPHER_AES_GCM: + return WLAN_CRYPTO_CIPHER_AES_GCM; + case WMI_CIPHER_AES_GMAC: + return WLAN_CRYPTO_CIPHER_AES_GMAC; + case WMI_CIPHER_WAPI_GCM_SM4: + return WLAN_CRYPTO_CIPHER_WAPI_GCM4; + case WMI_CIPHER_BIP_CMAC_128: + return WLAN_CRYPTO_CIPHER_AES_CMAC; + case WMI_CIPHER_BIP_CMAC_256: + return WLAN_CRYPTO_CIPHER_AES_CMAC_256; + case WMI_CIPHER_BIP_GMAC_128: + return WLAN_CRYPTO_CIPHER_AES_GMAC; + case WMI_CIPHER_BIP_GMAC_256: + return WLAN_CRYPTO_CIPHER_AES_GMAC_256; + + default: + return 0; + } +} +#define MLO_PAIRWISE_LINKID 0xF +/** + * wmi_fill_keys_from_tlv - Fill the destination key buffer from the WMI TLV + * @ml_keys: ML Keys TLV pointer + * @dst_key: Destination keys + * @dst_key_len: Destination keys length + * @count: TLV count + * @max_num_tlv: Total number of TLVs + * + * Return: None + */ +static void +wmi_fill_keys_from_tlv(wmi_roam_ml_key_material_param **ml_keys, + uint8_t *dst_key, uint8_t *dst_key_len, uint8_t *count, + uint8_t max_num_tlv) +{ + uint8_t rem_key_len, bytes_filled, key_len, total_key_len; + uint8_t max_key_len = WLAN_CRYPTO_KEYBUF_SIZE + WLAN_CRYPTO_MICBUF_SIZE; + + *dst_key_len = (*ml_keys)->key_len; + if (*dst_key_len > max_key_len) + *dst_key_len = max_key_len; + + total_key_len = *dst_key_len; + rem_key_len = *dst_key_len; + + while (rem_key_len) { + if (!(*ml_keys)) { + wmi_err_rl("ml_keys is NULL. rem_key_len:%d", + rem_key_len); + return; + } + + if (*count >= max_num_tlv) { + wmi_debug("Read all TLVs count:%d", *count); + return; + } + + if (rem_key_len < WMI_MAX_KEY_LEN) + key_len = rem_key_len; + else + key_len = WMI_MAX_KEY_LEN; + + bytes_filled = total_key_len - rem_key_len; + qdf_mem_copy(dst_key + bytes_filled, (*ml_keys)->key_buff, + key_len); + (*ml_keys)++; + (*count)++; + + rem_key_len -= key_len; + } +} + +#define WMI_NUM_KEYS_ALLOCATED (WLAN_MAX_ML_BSS_LINKS * 4) +static QDF_STATUS +extract_roam_synch_key_event_tlv(wmi_unified_t wmi_handle, + uint8_t *event, uint32_t data_len, + struct wlan_crypto_key_entry **entries, + uint8_t *num_entries, + struct qdf_mac_addr *mld_addr) +{ + WMI_ROAM_SYNCH_KEY_EVENTID_param_tlvs *param_buf = NULL; + wmi_roam_ml_key_material_param *ml_keys = NULL; + struct wlan_crypto_key_entry *key_entry; + struct wlan_crypto_keys *all_keys; + struct wlan_crypto_key *dst_key, *pairwise; + struct wlan_crypto_key *key_alloc_buf[WMI_NUM_KEYS_ALLOCATED]; + bool flush_keybuf; + uint8_t total_num_tlv, j = 0, k = 0; + uint8_t count = 0, total_links = 0, dst_key_count = 0; + uint8_t igtk_idx = 0, bigtk_idx = 0; + bool slot_found; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + param_buf = (WMI_ROAM_SYNCH_KEY_EVENTID_param_tlvs *)event; + if (!param_buf) { + wmi_err_rl("received null buf from target"); + return QDF_STATUS_E_INVAL; + } + + total_num_tlv = param_buf->num_ml_key_material; + ml_keys = (wmi_roam_ml_key_material_param *)param_buf->ml_key_material; + if (!ml_keys) { + wmi_err_rl("received ml keys param is null"); + return QDF_STATUS_E_INVAL; + } + + *entries = qdf_mem_malloc(WLAN_MAX_ML_BSS_LINKS * sizeof(*key_entry)); + if (!*entries) + return QDF_STATUS_E_NOMEM; + + /* + * Allocate memory for each PTK, GTK, IGTK, BIGTK keys. + * So total WLAN_MAX_ML_BSS_LINKS * 4 keys are needed + */ + for (k = 0; k < WMI_NUM_KEYS_ALLOCATED; k++) { + key_alloc_buf[k] = qdf_mem_malloc(sizeof(*dst_key)); + if (!key_alloc_buf[k]) { + flush_keybuf = true; + status = QDF_STATUS_E_NOMEM; + goto free_entries; + } + } + + /* + * key_entry is the master structure that is given directly to the + * crypto module and stored for each link. + * key_entry -> keys ->key filled from dst_key has the PTK & GTK indexed + * with corresponding key index + * + * key_entry -> keys -> iGTK holds the iGTK key + * key_entry -> keys -> BIGTK holds the BIGTK key + */ + key_entry = *entries; + + /* + * Initialize all the Key Entry structures with invalid Link + * ID to identify empty links allocated and will be freed + * at the end. + */ + for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) + key_entry[j].link_id = MLO_INVALID_LINK_IDX; + + /* + * TLV Format to parse: + * 1. wmi_roam_ml_key_material_param -> For PTK with Link ID = 0xF + * Copy this PTK to all the key entry of all the links. + * + * 2. wmi_roam_ml_key_material_param -> GTK for a valid Link. + * Get available entry, and fill the GTK to that entry + * + * 3. wmi_roam_ml_key_material_param -> IGTK for a valid link + * + * 4. wmi_roam_ml_key_material_param -> BIGTK for a valid link + * + * 5. wmi_roam_ml_key_material_param -> For LTF Keyseed with Link ID = + * 0xF and flags has LTF_USAGE set. + * + * If any of the key length is > WMI_MAX_KEY_LEN, then multiple + * wmi_roam_ml_key_material_param TLVs follow to get the entire key + */ + while (ml_keys && count < total_num_tlv && + dst_key_count < WMI_NUM_KEYS_ALLOCATED) { + /* + * Track individual keys with key_alloc_buf[dst_key_count] array + * pointer to avoid mem leaks if parsing/validating any of the + * keys fail. + * Freeing the allocated keys it done at the end of this + * function + */ + dst_key = key_alloc_buf[dst_key_count]; + wmi_debug("link_id:%d key_ix:%d key_cipher:%d key_len:%d key_flags:%d", + ml_keys->link_id, ml_keys->key_ix, + ml_keys->key_cipher, + ml_keys->key_len, ml_keys->key_flags); + + if (!is_valid_keyix(ml_keys->key_ix)) { + wmi_err_rl("invalid key index:%d", ml_keys->key_ix); + status = QDF_STATUS_E_INVAL; + flush_keybuf = true; + goto free_entries; + } + + /* Copy pairwise keys to all the entries */ + if (ml_keys->link_id == MLO_PAIRWISE_LINKID) { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ml_keys->mac_addr, + mld_addr->bytes); + if (!ml_keys->key_len) { + wmi_err_rl("Received key_len as 0 for tlv:%d", + count); + status = QDF_STATUS_E_INVAL; + flush_keybuf = true; + goto free_entries; + } + + if (ml_keys->key_flags & LTF_USAGE) { + struct wlan_crypto_ltf_keyseed_data key_seed; + uint8_t key_seed_len; + + if (ml_keys->key_len > + WLAN_MAX_SECURE_LTF_KEYSEED_LEN) + ml_keys->key_len = + WLAN_MAX_SECURE_LTF_KEYSEED_LEN; + + /* + * Filling the keys from multiple TLVs is + * handled by below API and ml_keys ptr gets + * incremented accordingly inside + */ + wmi_fill_keys_from_tlv(&ml_keys, + key_seed.key_seed, + &key_seed_len, &count, + total_num_tlv); + key_seed.key_seed_len = key_seed_len; + wmi_debug("ML_KEY: Got LTF keyseed key for MLD: " + QDF_MAC_ADDR_FMT " key_seed_len:%d", + QDF_MAC_ADDR_REF(mld_addr->bytes), + key_seed.key_seed_len); + + for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) + key_entry[j].keys.ltf_key_seed = + key_seed; + + continue; + } + + dst_key->valid = true; + dst_key->keylen = ml_keys->key_len; + dst_key->flags = ml_keys->key_flags; + dst_key->keyix = ml_keys->key_ix; + dst_key->key_type = + WLAN_CRYPTO_KEY_TYPE_UNICAST; + dst_key->cipher_type = + wlan_wmi_cipher_to_crypto(ml_keys->key_cipher); + dst_key->keylen = ml_keys->key_len; + + wmi_fill_keys_from_tlv(&ml_keys, dst_key->keyval, + &dst_key->keylen, &count, + total_num_tlv); + wmi_err_rl("ML_KEY: Got Pairwise key for MLD: " + QDF_MAC_ADDR_FMT " rem_len:%d", + QDF_MAC_ADDR_REF(mld_addr->bytes), + dst_key->keylen); + + pairwise = dst_key; + /* + * Pairwise keys will be sent only once. Copy that for + * all the link entries + */ + for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) { + dst_key = key_alloc_buf[dst_key_count]; + *dst_key = *pairwise; + key_entry[j].keys.key[dst_key->keyix] = dst_key; + dst_key_count++; + } + + continue; + } + + slot_found = false; + for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) { + if (ml_keys->link_id == MLO_INVALID_LINK_IDX) + break; + + if (key_entry[j].link_id == MLO_INVALID_LINK_IDX || + key_entry[j].link_id == ml_keys->link_id) { + slot_found = true; + break; + } + } + + if (!slot_found) { + wmi_err_rl("Not able to find a entry for link:%d j=%d", + ml_keys->link_id, j); + break; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ml_keys->mac_addr, + dst_key->macaddr); + key_entry[j].link_id = ml_keys->link_id; + qdf_copy_macaddr((struct qdf_mac_addr *)key_entry[j].mac_addr.raw, + (struct qdf_mac_addr *)dst_key->macaddr); + all_keys = &key_entry[j].keys; + + dst_key->valid = true; + dst_key->keyix = ml_keys->key_ix; + dst_key->cipher_type = + wlan_wmi_cipher_to_crypto(ml_keys->key_cipher); + + qdf_mem_copy(dst_key->keyrsc, ml_keys->pn, WMI_MAX_PN_LEN); + + /* + * For LTF keyseed or FILS SHA 384, FILS SHA 512 cases, the key + * size will go beyond WMI_MAX_KEY_LEN(32). So extract first 32 + * bytes from 1st TLV and extract the rest of the bytes from + * the following TLVs + */ + dst_key->keylen = ml_keys->key_len; + wmi_fill_keys_from_tlv(&ml_keys, dst_key->keyval, + &dst_key->keylen, &count, total_num_tlv); + + if (is_igtk(dst_key->keyix)) { + dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP; + + igtk_idx = dst_key->keyix - WLAN_CRYPTO_MAXKEYIDX; + bigtk_idx = igtk_idx - WLAN_CRYPTO_MAXIGTKKEYIDX; + + wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT "Key is IGTK key_ix:%d igtk_idx:%d bigtk:%d", + j, key_entry[j].link_id, + QDF_MAC_ADDR_REF(dst_key->macaddr), + dst_key->keyix, igtk_idx, bigtk_idx); + all_keys->igtk_key[igtk_idx] = dst_key; + all_keys->def_igtk_tx_keyid = igtk_idx; + + bigtk_idx = 0; + igtk_idx = 0; + } else if (is_bigtk(dst_key->keyix)) { + dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP; + + igtk_idx = dst_key->keyix - WLAN_CRYPTO_MAXKEYIDX; + bigtk_idx = igtk_idx - WLAN_CRYPTO_MAXIGTKKEYIDX; + + wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT "Key is BIGTK key_ix:%d igtk_idx:%d bigtk:%d", + j, key_entry[j].link_id, + QDF_MAC_ADDR_REF(dst_key->macaddr), + dst_key->keyix, igtk_idx, bigtk_idx); + all_keys->bigtk_key[bigtk_idx] = dst_key; + all_keys->def_bigtk_tx_keyid = bigtk_idx; + + bigtk_idx = 0; + igtk_idx = 0; + } else if (is_gtk(dst_key->keyix)) { + wmi_debug("ML_KEY: Slot:%d link_id:%d addr: " QDF_MAC_ADDR_FMT " Key is GTK key_ix:%d", + j, key_entry[j].link_id, + QDF_MAC_ADDR_REF(dst_key->macaddr), + dst_key->keyix); + dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_GROUP; + all_keys->key[dst_key->keyix] = dst_key; + } else { + wmi_debug("Key is Pairwise. Shouldn't reach here"); + /* Pairwise key */ + dst_key->key_type = WLAN_CRYPTO_KEY_TYPE_UNICAST; + all_keys->key[dst_key->keyix] = dst_key; + } + + dst_key_count++; + } + + for (j = 0; j < WLAN_MAX_ML_BSS_LINKS; j++) { + /* + * Pairwise keys maybe copied for all the WLAN_MAX_ML_BSS_LINKS + * but firmware might have roamed to AP with number of links + * less than WLAN_MAX_ML_BSS_LINKS. So free the memory for those + * links + */ + if (key_entry[j].link_id != MLO_INVALID_LINK_IDX) { + total_links++; + } else { + wmi_err_rl("Free keys for invalid entry at index:%d", + j); + wlan_crypto_free_key(&key_entry[j].keys); + } + } + + *num_entries = total_links; + /* Free the invalid dst_keys allocated */ + if (!*num_entries) + goto free_entries; + + /* + * This is to free the unfilled key_alloc_buf that + * was allocated initially + */ + flush_keybuf = false; + + wmi_err_rl("ML_KEYS: total_entries filled:%d total_num_tlv:%d dst_key_count:%d", + *num_entries, total_num_tlv, dst_key_count); + goto free_keys; + +free_entries: + qdf_mem_zero(*entries, + WLAN_MAX_ML_BSS_LINKS * sizeof(**entries)); + qdf_mem_free(*entries); + +free_keys: + for (k = 0; k < WMI_NUM_KEYS_ALLOCATED; k++) { + if (!key_alloc_buf[k]) + continue; + + wmi_err_rl("flush keybuf :%d, key is valid", flush_keybuf, + key_alloc_buf[k]->valid); + if (!flush_keybuf && key_alloc_buf[k]->valid) + continue; + + wmi_err("Free key allocated at idx:%d", k); + qdf_mem_zero(key_alloc_buf[k], sizeof(*key_alloc_buf[k])); + qdf_mem_free(key_alloc_buf[k]); + } + + return status; +} + +static void +wmi_roam_offload_attach_mlo_tlv(struct wmi_ops *ops) +{ + ops->extract_roam_synch_key_event = extract_roam_synch_key_event_tlv; +} +#else +static inline void +wmi_roam_offload_attach_mlo_tlv(struct wmi_ops *ops) +{} +#endif + +void wmi_roam_offload_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->extract_roam_btm_response_stats = + extract_roam_btm_response_stats_tlv; + ops->extract_roam_initial_info = extract_roam_initial_info_tlv; + ops->extract_roam_msg_info = extract_roam_msg_info_tlv; + ops->extract_roam_frame_info = extract_roam_frame_info_tlv; + ops->extract_roam_sync_event = extract_roam_sync_event_tlv; + ops->extract_roam_sync_frame_event = extract_roam_sync_frame_event_tlv; + ops->extract_roam_event = extract_roam_event_tlv; + ops->extract_btm_dl_event = extract_btm_denylist_event; + ops->extract_vdev_disconnect_event = extract_vdev_disconnect_event_tlv; + ops->extract_roam_scan_chan_list = extract_roam_scan_chan_list_tlv; + ops->extract_roam_stats_event = extract_roam_stats_event_tlv; + ops->extract_auth_offload_event = extract_auth_offload_event_tlv; + ops->extract_roam_pmkid_request = extract_roam_pmkid_request_tlv; + ops->send_set_ric_req_cmd = send_set_ric_req_cmd_tlv; + ops->send_process_roam_synch_complete_cmd = + send_process_roam_synch_complete_cmd_tlv; + ops->send_roam_invoke_cmd = send_roam_invoke_cmd_tlv; + ops->send_vdev_set_pcl_cmd = send_vdev_set_pcl_cmd_tlv; + ops->send_set_roam_trigger_cmd = send_set_roam_trigger_cmd_tlv; + ops->extract_roam_candidate_frame = extract_roam_candidate_frame_tlv; + ops->extract_peer_oper_mode_event = extract_peer_oper_mode_event_tlv; + wmi_roam_offload_attach_vendor_handoff_tlv(ops); + wmi_roam_offload_attach_mlo_tlv(ops); +} +#else +static inline QDF_STATUS +extract_roam_btm_response_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_btm_response_data *dst, + uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +extract_roam_initial_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_initial_data *dst, uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +extract_roam_msg_info_tlv(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_msg_info *dst, uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +extract_roam_sync_event(wmi_unified_t wmi_handle, void *evt_buf, + uint32_t len, + struct roam_offload_synch_ind **roam_sync_ind) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +extract_roam_sync_frame_event(wmi_unified_t wmi_handle, void *evt_buf, + struct roam_msg_info *dst, uint8_t idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +extract_roam_event(wmi_unified_t wmi_handle, void *evt_buf, uint32_t len, + struct roam_offload_roam_event *roam_event) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wmi_fill_roam_offload_11r_params() - Fill roam scan params to send it to fw + * @akm: Authentication key management type + * @roam_offload_11r: TLV to be filled with 11r params + * @roam_req: roam request param + */ +static void wmi_fill_roam_offload_11r_params( + uint32_t akm, + wmi_roam_11r_offload_tlv_param *roam_offload_11r, + struct wlan_roam_scan_offload_params *roam_req) +{ + struct wlan_rso_11r_params *src_11r_params; + uint8_t *psk_msk, len; + + src_11r_params = &roam_req->rso_11r_info; + + if ((akm == WMI_AUTH_FT_RSNA_FILS_SHA256 || + akm == WMI_AUTH_FT_RSNA_FILS_SHA384) && + roam_req->fils_roam_config.fils_ft_len) { + wmi_debug("Update the FILS FT key to Firmware"); + psk_msk = roam_req->fils_roam_config.fils_ft; + len = roam_req->fils_roam_config.fils_ft_len; + } else { + psk_msk = src_11r_params->psk_pmk; + len = src_11r_params->pmk_len; + } + + /* + * For SHA384 based akm, the pmk length is 48 bytes. So fill + * first 32 bytes in roam_offload_11r->psk_msk and the remaining + * bytes in roam_offload_11r->psk_msk_ext buffer + */ + roam_offload_11r->psk_msk_len = len > ROAM_OFFLOAD_PSK_MSK_BYTES ? + ROAM_OFFLOAD_PSK_MSK_BYTES : len; + qdf_mem_copy(roam_offload_11r->psk_msk, psk_msk, + roam_offload_11r->psk_msk_len); + roam_offload_11r->psk_msk_ext_len = 0; + + if (len > ROAM_OFFLOAD_PSK_MSK_BYTES) { + roam_offload_11r->psk_msk_ext_len = + len - roam_offload_11r->psk_msk_len; + qdf_mem_copy(roam_offload_11r->psk_msk_ext, + &psk_msk[roam_offload_11r->psk_msk_len], + roam_offload_11r->psk_msk_ext_len); + } +} + +/** + * wmi_is_ft_akm() - Check if the akm is FT akm. Based on the AKM 11r params + * will be sent for lfr-3.0 roaming offload + * @akm: AKM negotiated for the connection + * @roam_req: roam request sent to firmware + * + * Return: true if the akm is 11r based + */ +static bool wmi_is_ft_akm(int akm, + struct wlan_roam_scan_offload_params *roam_req) +{ + switch (akm) { + case WMI_AUTH_FT_RSNA: + case WMI_AUTH_FT_RSNA_PSK: + case WMI_AUTH_FT_RSNA_SAE: + case WMI_AUTH_FT_RSNA_SUITE_B_8021X_SHA384: + case WMI_AUTH_FT_RSNA_FILS_SHA256: + case WMI_AUTH_FT_RSNA_FILS_SHA384: + case WMI_AUTH_FT_RSNA_SAE_SHA384: + return true; + case WMI_AUTH_OPEN: + if (roam_req->rso_11r_info.mdid.mdie_present && + roam_req->rso_11r_info.is_11r_assoc) + return true; + + break; + default: + return false; + } + + return false; +} + +/** + * wmi_get_rso_buf_len() - calculate the length needed to allocate buffer + * for RSO mode command + * @roam_req: roam request parameters + */ +static uint32_t +wmi_get_rso_buf_len(struct wlan_roam_scan_offload_params *roam_req) +{ + wmi_tlv_buf_len_param *assoc_ies; + uint32_t buf_len; + uint32_t fils_tlv_len = 0; + int akm = roam_req->akm; + + /* + * Allocate room for wmi_roam_offload_tlv_param and + * 11i or 11r or ese roam offload tlv param + * Todo: Test if below headroom of 2 TLV header is needed + */ + buf_len = (2 * WMI_TLV_HDR_SIZE); + + if (roam_req->is_rso_stop || + !roam_req->roam_offload_enabled) { + buf_len += (4 * WMI_TLV_HDR_SIZE); + + if (!roam_req->is_rso_stop) + wmi_debug("vdev[%d]: %s roam offload: %d", + roam_req->vdev_id, + roam_req->is_rso_stop ? "RSO stop cmd." : "", + roam_req->roam_offload_enabled); + + return buf_len; + } + + wmi_debug("wmi akm = %d", akm); + + buf_len += sizeof(wmi_roam_offload_tlv_param); + buf_len += 2 * WMI_TLV_HDR_SIZE; + + if ((akm != WMI_AUTH_OPEN || roam_req->rso_ese_info.is_ese_assoc || + wmi_is_ft_akm(akm, roam_req)) && akm != WMI_AUTH_NONE) { + if (roam_req->rso_ese_info.is_ese_assoc) + buf_len += sizeof(wmi_roam_ese_offload_tlv_param); + else if (wmi_is_ft_akm(akm, roam_req)) + buf_len += sizeof(wmi_roam_11r_offload_tlv_param); + else + buf_len += sizeof(wmi_roam_11i_offload_tlv_param); + } + + buf_len += (sizeof(*assoc_ies) + (2 * WMI_TLV_HDR_SIZE) + + roundup(roam_req->assoc_ie_length, sizeof(uint32_t))); + + /* Fils TLV */ + buf_len += WMI_TLV_HDR_SIZE; + if (roam_req->add_fils_tlv) { + fils_tlv_len = sizeof(wmi_roam_fils_offload_tlv_param); + buf_len += fils_tlv_len; + } + + if (roam_req->rso_11i_info.is_sae_same_pmk) + buf_len += WMI_TLV_HDR_SIZE + + sizeof(wmi_roam_sae_offload_tlv_param); + + roam_req->rso_mode_info.roam_scan_mode |= + WMI_ROAM_SCAN_MODE_ROAMOFFLOAD; + + return buf_len; +} + +#if defined(WLAN_FEATURE_FILS_SK) +/** + * wmi_add_fils_tlv() - Add FILS TLV to roam scan offload command + * @wmi_handle: wmi handle + * @roam_req: Roam scan offload params + * @buf_ptr: command buffer to send + * @fils_tlv_len: fils tlv length + * + * Return: Updated buffer pointer + */ +static uint8_t *wmi_add_fils_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_scan_offload_params *roam_req, + uint8_t *buf_ptr, uint32_t fils_tlv_len) +{ + wmi_roam_fils_offload_tlv_param *fils_tlv; + wmi_erp_info *erp_info; + struct wlan_roam_fils_params *roam_fils_params; + + if (!roam_req->add_fils_tlv) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, 0); + buf_ptr += WMI_TLV_HDR_SIZE; + return buf_ptr; + } + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(*fils_tlv)); + buf_ptr += WMI_TLV_HDR_SIZE; + + fils_tlv = (wmi_roam_fils_offload_tlv_param *)buf_ptr; + WMITLV_SET_HDR(&fils_tlv->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_fils_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_fils_offload_tlv_param)); + + roam_fils_params = &roam_req->fils_roam_config; + erp_info = (wmi_erp_info *)(&fils_tlv->vdev_erp_info); + + erp_info->username_length = roam_fils_params->username_length; + qdf_mem_copy(erp_info->username, roam_fils_params->username, + erp_info->username_length); + + erp_info->next_erp_seq_num = roam_fils_params->next_erp_seq_num; + + erp_info->rRk_length = roam_fils_params->rrk_length; + qdf_mem_copy(erp_info->rRk, roam_fils_params->rrk, + erp_info->rRk_length); + + erp_info->rIk_length = roam_fils_params->rik_length; + qdf_mem_copy(erp_info->rIk, roam_fils_params->rik, + erp_info->rIk_length); + + erp_info->realm_len = roam_fils_params->realm_len; + qdf_mem_copy(erp_info->realm, roam_fils_params->realm, + erp_info->realm_len); + + buf_ptr += sizeof(*fils_tlv); + wmi_debug("RSO_CFG: ERP: usrname_len:%d next_erp_seq_num:%d rRk_len:%d rIk_len:%d realm_len:%d", + erp_info->username_length, erp_info->next_erp_seq_num, + erp_info->rRk_length, erp_info->rIk_length, + erp_info->realm_len); + return buf_ptr; +} +#else +static inline +uint8_t *wmi_add_fils_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_scan_offload_params *roam_req, + uint8_t *buf_ptr, uint32_t fils_tlv_len) +{ + return buf_ptr; +} +#endif + +#ifdef WLAN_SAE_SINGLE_PMK +static inline void +wmi_fill_sae_single_pmk_param(struct wlan_rso_11i_params *src_11i, + wmi_roam_11i_offload_tlv_param *roam_offload_11i) +{ + if (src_11i->is_sae_same_pmk) + roam_offload_11i->flags |= + 1 << WMI_ROAM_OFFLOAD_FLAG_SAE_SAME_PMKID; +} + +static uint8_t *wmi_fill_sae_single_pmk_tlv( + struct wlan_roam_scan_offload_params *roam_req, uint8_t *buf_ptr) +{ + wmi_roam_sae_offload_tlv_param *sae_offload_param; + + if (!roam_req->rso_11i_info.is_sae_same_pmk) + return buf_ptr; + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_sae_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + + sae_offload_param = (wmi_roam_sae_offload_tlv_param *)buf_ptr; + WMITLV_SET_HDR(&sae_offload_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_sae_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_sae_offload_tlv_param)); + + sae_offload_param->spmk_timeout = + roam_req->sae_offload_params.spmk_timeout; + wmi_debug("spmk_timeout:%d seconds", sae_offload_param->spmk_timeout); + + buf_ptr += sizeof(*sae_offload_param); + + return buf_ptr; +} +#else +static inline void +wmi_fill_sae_single_pmk_param(struct wlan_rso_11i_params *src_11i, + wmi_roam_11i_offload_tlv_param *roam_offload_11i) +{} + +static inline uint8_t *wmi_fill_sae_single_pmk_tlv( + struct wlan_roam_scan_offload_params *roam_req, + uint8_t *buf_ptr) +{ + return buf_ptr; +} + +#endif + +static QDF_STATUS +wmi_fill_rso_tlvs(wmi_unified_t wmi_handle, uint8_t *buf, + struct wlan_roam_scan_offload_params *roam_req) +{ + wmi_roam_offload_tlv_param *roam_offload_params; + wmi_roam_11i_offload_tlv_param *roam_offload_11i; + wmi_roam_11r_offload_tlv_param *roam_offload_11r; + wmi_roam_ese_offload_tlv_param *roam_offload_ese; + wmi_tlv_buf_len_param *assoc_ies; + uint32_t fils_tlv_len = 0; + int akm = roam_req->akm; + struct wlan_rso_lfr3_params *src_lfr3_params = + &roam_req->rso_lfr3_params; + struct wlan_rso_lfr3_caps *src_lfr3_caps = + &roam_req->rso_lfr3_caps; + struct wlan_rso_11i_params *src_11i_info = + &roam_req->rso_11i_info; + struct wlan_rso_ese_params *src_ese_info = + &roam_req->rso_ese_info; + struct wlan_rso_11r_params *src_11r_info = + &roam_req->rso_11r_info; + + /* For RSO stop command, dont fill 11i, 11r or ese tlv */ + if (roam_req->is_rso_stop || !roam_req->roam_offload_enabled) { + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf += WMI_TLV_HDR_SIZE; + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_BYTE, + WMITLV_GET_STRUCT_TLVLEN(0)); + + return QDF_STATUS_SUCCESS; + } + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_offload_tlv_param)); + + buf += WMI_TLV_HDR_SIZE; + roam_offload_params = (wmi_roam_offload_tlv_param *)buf; + WMITLV_SET_HDR(buf, + WMITLV_TAG_STRUC_wmi_roam_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_offload_tlv_param)); + + roam_offload_params->prefer_5g = src_lfr3_params->prefer_5ghz; + roam_offload_params->rssi_cat_gap = src_lfr3_params->roam_rssi_cat_gap; + roam_offload_params->select_5g_margin = + src_lfr3_params->select_5ghz_margin; + roam_offload_params->handoff_delay_for_rx = + src_lfr3_params->ho_delay_for_rx; + roam_offload_params->max_mlme_sw_retries = + src_lfr3_params->roam_retry_count; + roam_offload_params->no_ack_timeout = + src_lfr3_params->roam_preauth_no_ack_timeout; + roam_offload_params->reassoc_failure_timeout = + src_lfr3_params->reassoc_failure_timeout; + roam_offload_params->roam_candidate_validity_time = + src_lfr3_params->rct_validity_timer; + roam_offload_params->roam_to_current_bss_disable = + src_lfr3_params->disable_self_roam; + wmi_debug("RSO_CFG: prefer_5g:%d rssi_cat_gap:%d select_5g_margin:%d ho_delay:%d max_sw_retry:%d no_ack_timeout:%d", + roam_offload_params->prefer_5g, + roam_offload_params->rssi_cat_gap, + roam_offload_params->select_5g_margin, + roam_offload_params->handoff_delay_for_rx, + roam_offload_params->max_mlme_sw_retries, + roam_offload_params->no_ack_timeout); + wmi_debug("RSO_CFG: reassoc_fail_timeout:%d rct_validity_time:%d disable_self_roam:%d", + roam_offload_params->reassoc_failure_timeout, + roam_offload_params->roam_candidate_validity_time, + roam_offload_params->roam_to_current_bss_disable); + + /* Fill the capabilities */ + roam_offload_params->capability = src_lfr3_caps->capability; + roam_offload_params->ht_caps_info = src_lfr3_caps->ht_caps_info; + roam_offload_params->ampdu_param = src_lfr3_caps->ampdu_param; + roam_offload_params->ht_ext_cap = src_lfr3_caps->ht_ext_cap; + roam_offload_params->ht_txbf = src_lfr3_caps->ht_txbf; + roam_offload_params->asel_cap = src_lfr3_caps->asel_cap; + roam_offload_params->qos_caps = src_lfr3_caps->qos_caps; + roam_offload_params->qos_enabled = src_lfr3_caps->qos_enabled; + roam_offload_params->wmm_caps = src_lfr3_caps->wmm_caps; + qdf_mem_copy((uint8_t *)roam_offload_params->mcsset, + (uint8_t *)src_lfr3_caps->mcsset, + ROAM_OFFLOAD_NUM_MCS_SET); + wmi_debug("RSO_CFG: capability:0x%x ht_caps:0x%x ampdu_param:0%x ht_ext_cap:0x%x ht_txbf:0x%x asel_cap:0x%x qos_caps:0x%x qos_en:%d wmm_caps:0x%x", + roam_offload_params->capability, + roam_offload_params->ht_caps_info, + roam_offload_params->ampdu_param, + roam_offload_params->ht_ext_cap, + roam_offload_params->ht_txbf, roam_offload_params->asel_cap, + roam_offload_params->qos_caps, + roam_offload_params->qos_enabled, + roam_offload_params->wmm_caps); + + buf += sizeof(wmi_roam_offload_tlv_param); + /* + * The TLV's are in the order of 11i, 11R, ESE. Hence, + * they are filled in the same order.Depending on the + * authentication type, the other mode TLV's are nullified + * and only headers are filled. + */ + if ((akm != WMI_AUTH_OPEN || roam_req->rso_ese_info.is_ese_assoc || + wmi_is_ft_akm(akm, roam_req)) && akm != WMI_AUTH_NONE) { + if (roam_req->rso_ese_info.is_ese_assoc) { + /* Fill the length of 11i, 11r TLV as 0 */ + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + /* Start filling the ESE TLV */ + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_ese_offload_tlv_param)); + buf += WMI_TLV_HDR_SIZE; + roam_offload_ese = + (wmi_roam_ese_offload_tlv_param *)buf; + qdf_mem_copy(roam_offload_ese->krk, src_ese_info->krk, + sizeof(src_ese_info->krk)); + qdf_mem_copy(roam_offload_ese->btk, src_ese_info->btk, + sizeof(src_ese_info->btk)); + + WMITLV_SET_HDR(&roam_offload_ese->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_ese_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_ese_offload_tlv_param)); + + buf += sizeof(wmi_roam_ese_offload_tlv_param); + } else if (wmi_is_ft_akm(akm, roam_req)) { + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_11r_offload_tlv_param)); + buf += WMI_TLV_HDR_SIZE; + + roam_offload_11r = + (wmi_roam_11r_offload_tlv_param *)buf; + + roam_offload_11r->r0kh_id_len = + src_11r_info->r0kh_id_length; + qdf_mem_copy(roam_offload_11r->r0kh_id, + src_11r_info->r0kh_id, + src_11r_info->r0kh_id_length); + + wmi_fill_roam_offload_11r_params(akm, roam_offload_11r, + roam_req); + + roam_offload_11r->mdie_present = + src_11r_info->mdid.mdie_present; + roam_offload_11r->mdid = + src_11r_info->mdid.mobility_domain; + roam_offload_11r->adaptive_11r = + src_11r_info->is_adaptive_11r; + roam_offload_11r->ft_im_for_deauth = + src_11r_info->enable_ft_im_roaming; + roam_offload_11r->ft_over_ds_enable = + src_11r_info->enable_ft_over_ds; + + if (akm == WMI_AUTH_OPEN) { + /* + * If FT-Open ensure pmk length + * and r0khid len are zero + */ + roam_offload_11r->r0kh_id_len = 0; + roam_offload_11r->psk_msk_len = 0; + } + + WMITLV_SET_HDR(&roam_offload_11r->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_11r_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_11r_offload_tlv_param)); + + buf += sizeof(wmi_roam_11r_offload_tlv_param); + /* Set ESE TLV len to 0*/ + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + wmi_debug("RSO_CFG: vdev[%d] 11r TLV psk_msk_len = %d psk_msk_ext:%d md:0x%x", + roam_req->vdev_id, + roam_offload_11r->psk_msk_len, + roam_offload_11r->psk_msk_ext_len, + roam_offload_11r->mdid); + if (roam_offload_11r->psk_msk_len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, + QDF_TRACE_LEVEL_DEBUG, + roam_offload_11r->psk_msk, + WLAN_MAX_PMK_DUMP_BYTES); + } else { + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_roam_11i_offload_tlv_param)); + buf += WMI_TLV_HDR_SIZE; + + roam_offload_11i = + (wmi_roam_11i_offload_tlv_param *)buf; + + if (src_11i_info->roam_key_mgmt_offload_enabled && + src_11i_info->fw_okc) + WMI_SET_ROAM_OFFLOAD_OKC_ENABLED( + roam_offload_11i->flags); + else + WMI_SET_ROAM_OFFLOAD_OKC_DISABLED( + roam_offload_11i->flags); + + if (src_11i_info->roam_key_mgmt_offload_enabled && + src_11i_info->fw_pmksa_cache) + WMI_SET_ROAM_OFFLOAD_PMK_CACHE_ENABLED( + roam_offload_11i->flags); + else + WMI_SET_ROAM_OFFLOAD_PMK_CACHE_DISABLED( + roam_offload_11i->flags); + + wmi_fill_sae_single_pmk_param(src_11i_info, + roam_offload_11i); + + roam_offload_11i->pmk_len = + src_11i_info->pmk_len > ROAM_OFFLOAD_PMK_BYTES ? + ROAM_OFFLOAD_PMK_BYTES : src_11i_info->pmk_len; + qdf_mem_copy(roam_offload_11i->pmk, + src_11i_info->psk_pmk, + roam_offload_11i->pmk_len); + + roam_offload_11i->pmk_ext_len = 0; + if (src_11i_info->pmk_len > ROAM_OFFLOAD_PMK_BYTES) { + roam_offload_11i->pmk_ext_len = + QDF_MIN(src_11i_info->pmk_len - + ROAM_OFFLOAD_PMK_BYTES, + ROAM_OFFLOAD_PMK_BYTES); + } + qdf_mem_copy( + roam_offload_11i->pmk_ext, + &src_11i_info->psk_pmk[ROAM_OFFLOAD_PMK_BYTES], + roam_offload_11i->pmk_ext_len); + + WMITLV_SET_HDR(&roam_offload_11i->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_11i_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_11i_offload_tlv_param)); + + buf += sizeof(wmi_roam_11i_offload_tlv_param); + + /* + * Set 11r TLV len to 0, since security profile is not + * FT + */ + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + /* + * Set ESE TLV len to 0 since security profile is not + * ESE + */ + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + wmi_info("RSO_CFG: vdev:%d pmk_len = %d pmksa caching:%d OKC:%d sae_same_pmk:%d key_mgmt_offload:%d", + roam_req->vdev_id, roam_offload_11i->pmk_len, + src_11i_info->fw_pmksa_cache, + src_11i_info->fw_okc, + src_11i_info->is_sae_same_pmk, + src_11i_info->roam_key_mgmt_offload_enabled); + if (roam_offload_11i->pmk_len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, + QDF_TRACE_LEVEL_DEBUG, + roam_offload_11i->pmk, + WLAN_MAX_PMK_DUMP_BYTES); + if (roam_offload_11i->pmk_ext_len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, + QDF_TRACE_LEVEL_DEBUG, + roam_offload_11i->pmk_ext, + WLAN_MAX_PMK_DUMP_BYTES); + } + } else { + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, 0); + buf += WMI_TLV_HDR_SIZE; + } + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_STRUC, sizeof(*assoc_ies)); + buf += WMI_TLV_HDR_SIZE; + + assoc_ies = (wmi_tlv_buf_len_param *)buf; + WMITLV_SET_HDR(&assoc_ies->tlv_header, + WMITLV_TAG_STRUC_wmi_tlv_buf_len_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_tlv_buf_len_param)); + assoc_ies->buf_len = roam_req->assoc_ie_length; + + buf += sizeof(*assoc_ies); + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_BYTE, + roundup(assoc_ies->buf_len, sizeof(uint32_t))); + buf += WMI_TLV_HDR_SIZE; + + wmi_debug("RSO_CFG: akm:%d assoc_ies len:%d", akm, assoc_ies->buf_len); + if (assoc_ies->buf_len) + qdf_mem_copy(buf, roam_req->assoc_ie, assoc_ies->buf_len); + + buf += qdf_roundup(assoc_ies->buf_len, sizeof(uint32_t)); + buf = wmi_add_fils_tlv(wmi_handle, roam_req, buf, fils_tlv_len); + + buf = wmi_fill_sae_single_pmk_tlv(roam_req, buf); + + return QDF_STATUS_SUCCESS; +} +#else +static inline +uint32_t wmi_get_rso_buf_len(struct wlan_roam_scan_offload_params *roam_req) +{ + return 0; +} + +static inline QDF_STATUS +wmi_fill_rso_tlvs(wmi_unified_t wmi_handle, uint8_t *buf_ptr, + struct wlan_roam_scan_offload_params *roam_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS +wmi_fill_rso_start_scan_tlv(struct wlan_roam_scan_offload_params *rso_req, + wmi_start_scan_cmd_fixed_param *scan_tlv) +{ + struct wlan_roam_scan_params *src_scan_params; + + src_scan_params = &rso_req->rso_scan_params; + scan_tlv->scan_ctrl_flags = WMI_SCAN_ADD_CCK_RATES | + WMI_SCAN_ADD_OFDM_RATES | + WMI_SCAN_ADD_DS_IE_IN_PROBE_REQ | + WMI_SCAN_FILTER_PROBE_REQ; + if (rso_req->is_rso_stop) { + scan_tlv->dwell_time_active = + ROAM_SCAN_DWELL_TIME_ACTIVE_DEFAULT; + scan_tlv->dwell_time_passive = + ROAM_SCAN_DWELL_TIME_PASSIVE_DEFAULT; + scan_tlv->min_rest_time = ROAM_SCAN_MIN_REST_TIME_DEFAULT; + scan_tlv->max_rest_time = ROAM_SCAN_MAX_REST_TIME_DEFAULT; + scan_tlv->repeat_probe_time = 0; + scan_tlv->probe_spacing_time = 0; + scan_tlv->probe_delay = 0; + scan_tlv->max_scan_time = ROAM_SCAN_HW_DEF_SCAN_MAX_DURATION; + scan_tlv->idle_time = src_scan_params->min_rest_time; + scan_tlv->burst_duration = 0; + + return QDF_STATUS_SUCCESS; + } + + scan_tlv->dwell_time_active = src_scan_params->dwell_time_active; + scan_tlv->dwell_time_passive = src_scan_params->dwell_time_passive; + scan_tlv->min_dwell_time_6ghz = src_scan_params->min_dwell_time_6ghz; + scan_tlv->burst_duration = src_scan_params->burst_duration; + scan_tlv->min_rest_time = src_scan_params->min_rest_time; + scan_tlv->max_rest_time = src_scan_params->max_rest_time; + scan_tlv->repeat_probe_time = src_scan_params->repeat_probe_time; + scan_tlv->probe_spacing_time = src_scan_params->probe_spacing_time; + scan_tlv->probe_delay = src_scan_params->probe_delay; + scan_tlv->max_scan_time = ROAM_SCAN_HW_DEF_SCAN_MAX_DURATION; + scan_tlv->idle_time = src_scan_params->idle_time; + scan_tlv->n_probes = src_scan_params->n_probes; + scan_tlv->scan_ctrl_flags |= src_scan_params->scan_ctrl_flags; + scan_tlv->dwell_time_active_6ghz = + src_scan_params->dwell_time_active_6ghz; + scan_tlv->dwell_time_passive_6ghz = + src_scan_params->dwell_time_passive_6ghz; + + WMI_SCAN_SET_DWELL_MODE(scan_tlv->scan_ctrl_flags, + src_scan_params->rso_adaptive_dwell_mode); + + /* Configure roaming scan behavior (DBS/Non-DBS scan) */ + if (rso_req->roaming_scan_policy) + scan_tlv->scan_ctrl_flags_ext |= + WMI_SCAN_DBS_POLICY_FORCE_NONDBS; + else + scan_tlv->scan_ctrl_flags_ext |= + WMI_SCAN_DBS_POLICY_DEFAULT; + + wmi_debug("RSO_CFG: dwell time: active %d passive %d, burst_duration:%d, active 6g %d passive 6g %d, min_rest_time %d max rest %d repeat probe time %d probe_spacing:%d", + scan_tlv->dwell_time_active, scan_tlv->dwell_time_passive, + scan_tlv->burst_duration, + scan_tlv->dwell_time_active_6ghz, + scan_tlv->dwell_time_passive_6ghz, + scan_tlv->min_rest_time, scan_tlv->max_rest_time, + scan_tlv->repeat_probe_time, scan_tlv->probe_spacing_time); + wmi_debug("RSO_CFG: ctrl_flags:0x%x probe_delay:%d max_scan_time:%d idle_time:%d n_probes:%d", + scan_tlv->scan_ctrl_flags_ext, scan_tlv->probe_delay, + scan_tlv->max_scan_time, scan_tlv->idle_time, + scan_tlv->n_probes); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +wmi_set_rso_stop_report_status(wmi_roam_scan_mode_fixed_param *rso_fp) +{ + /** + * Set the REPORT status flag always, so that firmware sends RSO stop + * status always + */ + rso_fp->flags |= WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS; +} +#else +static void +wmi_set_rso_stop_report_status(wmi_roam_scan_mode_fixed_param *rso_fp) +{ +} +#endif + +/** + * send_roam_scan_offload_mode_cmd_tlv() - send roam scan mode request to fw + * @wmi_handle: wmi handle + * @rso_req: roam request param + * + * send WMI_ROAM_SCAN_MODE TLV to firmware. It has a piggyback + * of WMI_ROAM_SCAN_MODE. + * + * Return: QDF status + */ +static QDF_STATUS +send_roam_scan_offload_mode_cmd_tlv( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_offload_params *rso_req) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + size_t len; + uint8_t *buf_ptr; + wmi_roam_scan_mode_fixed_param *roam_scan_mode_fp; + wmi_start_scan_cmd_fixed_param *scan_cmd_fp; + struct wlan_roam_scan_mode_params *src_rso_mode_info = NULL; + + /* + * Need to create a buf with roam_scan command at + * front and piggyback with scan command + */ + len = sizeof(wmi_roam_scan_mode_fixed_param) + + sizeof(wmi_start_scan_cmd_fixed_param); + len += wmi_get_rso_buf_len(rso_req); + + if (rso_req->rso_mode_info.roam_scan_mode == + (WMI_ROAM_SCAN_MODE_NONE | WMI_ROAM_SCAN_MODE_ROAMOFFLOAD)) + len = sizeof(wmi_roam_scan_mode_fixed_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + src_rso_mode_info = &rso_req->rso_mode_info; + roam_scan_mode_fp = (wmi_roam_scan_mode_fixed_param *)buf_ptr; + WMITLV_SET_HDR( + &roam_scan_mode_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_mode_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_scan_mode_fixed_param)); + + roam_scan_mode_fp->min_delay_roam_trigger_reason_bitmask = + src_rso_mode_info->min_delay_roam_trigger_bitmask; + roam_scan_mode_fp->min_delay_btw_scans = + WMI_SEC_TO_MSEC(src_rso_mode_info->min_delay_btw_scans); + roam_scan_mode_fp->roam_scan_mode = src_rso_mode_info->roam_scan_mode; + roam_scan_mode_fp->vdev_id = rso_req->vdev_id; + wmi_debug("RSO_CFG: vdev_id:%d roam scan mode:0x%x min_delay_bitmap:0x%x min_delay_btw_scans:%d", + rso_req->vdev_id, + roam_scan_mode_fp->roam_scan_mode, + roam_scan_mode_fp->min_delay_roam_trigger_reason_bitmask, + roam_scan_mode_fp->min_delay_btw_scans); + /* + * For supplicant disabled roaming, all other roam triggers are disabled + * so send only roam scan mode Fixed param in the command + */ + if (src_rso_mode_info->roam_scan_mode == + (WMI_ROAM_SCAN_MODE_NONE | WMI_ROAM_SCAN_MODE_ROAMOFFLOAD)) { + roam_scan_mode_fp->flags |= + WMI_ROAM_SCAN_MODE_FLAG_REPORT_STATUS; + goto send_roam_scan_mode_cmd; + } else { + wmi_set_rso_stop_report_status(roam_scan_mode_fp); + } + + /* Fill in scan parameters suitable for roaming scan */ + buf_ptr += sizeof(wmi_roam_scan_mode_fixed_param); + WMITLV_SET_HDR( + buf_ptr, + WMITLV_TAG_STRUC_wmi_start_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_start_scan_cmd_fixed_param)); + scan_cmd_fp = (wmi_start_scan_cmd_fixed_param *)buf_ptr; + wmi_fill_rso_start_scan_tlv(rso_req, scan_cmd_fp); + + /* Ensure there is no additional IEs */ + scan_cmd_fp->ie_len = 0; + buf_ptr += sizeof(wmi_start_scan_cmd_fixed_param); + + status = wmi_fill_rso_tlvs(wmi_handle, buf_ptr, rso_req); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_buf_free(buf); + return status; + } + +send_roam_scan_mode_cmd: + wmi_mtrace(WMI_ROAM_SCAN_MODE, rso_req->vdev_id, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_MODE); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +send_update_mlo_roam_params(wmi_roam_cnd_scoring_param *score_param, + struct ap_profile_params *ap_profile) +{ + score_param->eht_weightage_pcnt = + ap_profile->param.eht_caps_weightage; + score_param->mlo_weightage_pcnt = + ap_profile->param.mlo_weightage; + wmi_debug("11be score params weightage: EHT %d MLO %d", + score_param->eht_weightage_pcnt, + score_param->mlo_weightage_pcnt); +} + +static uint32_t convert_support_link_band_to_wmi(uint32_t bands) +{ + uint32_t target_bands = 0; + + if (bands & BIT(REG_BAND_2G)) + target_bands |= BIT(0); + if (bands & BIT(REG_BAND_5G)) + target_bands |= BIT(1); + if (bands & BIT(REG_BAND_6G)) + target_bands |= BIT(2); + + return target_bands; +} + +/** + * send_roam_mlo_config_tlv() - send roam mlo config parameters + * @wmi_handle: wmi handle + * @req: pointer to wlan roam mlo config parameters + * + * This function sends the roam mlo config parameters to fw. + * + * Return: QDF status + */ +static QDF_STATUS +send_roam_mlo_config_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_mlo_config *req) +{ + wmi_roam_mlo_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_mlo_config_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_mlo_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_mlo_config_cmd_fixed_param)); + + cmd->vdev_id = req->vdev_id; + cmd->support_link_num = req->support_link_num; + cmd->support_link_band = convert_support_link_band_to_wmi( + req->support_link_band); + if (!req->mlo_5gl_5gh_mlsr) + cmd->disallow_connect_modes |= WMI_ROAM_MLO_CONNECTION_MODE_5GL_5GH_MLSR; + + WMI_CHAR_ARRAY_TO_MAC_ADDR(req->partner_link_addr.bytes, + &cmd->partner_link_addr); + + wmi_debug("RSO_CFG MLO: vdev_id:%d support_link_num:%d support_link_band:0x%0x disallow_connect_mode %d link addr:"QDF_MAC_ADDR_FMT, + cmd->vdev_id, cmd->support_link_num, + cmd->support_link_band, + cmd->disallow_connect_modes, + QDF_MAC_ADDR_REF(req->partner_link_addr.bytes)); + + wmi_mtrace(WMI_ROAM_MLO_CONFIG_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_MLO_CONFIG_CMDID)) { + wmi_err("Failed to send WMI_ROAM_MLO_CONFIG_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static void wmi_roam_mlo_attach_tlv(struct wmi_unified *wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_roam_mlo_config = send_roam_mlo_config_tlv; +} + +#else +static void +send_update_mlo_roam_params(wmi_roam_cnd_scoring_param *score_param, + struct ap_profile_params *ap_profile) +{ +} + +static void wmi_roam_mlo_attach_tlv(struct wmi_unified *wmi_handle) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * update_mlo_prefer_percentage() - Update mlo preference with configured value + * @psoc: psoc object + * @mlo_prefer_percentage: pointer to hold mlo preference percentage + * + * Return: None + */ +static void update_mlo_prefer_percentage(struct wlan_objmgr_psoc *psoc, + int8_t *mlo_prefer_percentage) +{ + wlan_mlme_get_mlo_prefer_percentage(psoc, mlo_prefer_percentage); + /* host will deliver actual weighted number based on 100. + * For example: + * If percentage value in INI is 20, then host will give 120 (100 + 20) + * i.e (100 * 1.2) as mlo_etp_weightage_pcnt. + * If percentage value in INI is -20, then host will give 80 (100 - 20) + * i.e (100 * 0.8) as mlo_etp_weightage_pcnt. + */ + *mlo_prefer_percentage += 100; +} +#else +static inline +void update_mlo_prefer_percentage(struct wlan_objmgr_psoc *psoc, + int8_t *mlo_preference_pctn) +{} +#endif + +/** + * send_roam_scan_offload_ap_profile_cmd_tlv() - set roam ap profile in fw + * @wmi_handle: wmi handle + * @ap_profile: ap profile + * + * Send WMI_ROAM_AP_PROFILE to firmware + * + * Return: CDF status + */ +static QDF_STATUS +send_roam_scan_offload_ap_profile_cmd_tlv(wmi_unified_t wmi_handle, + struct ap_profile_params *ap_profile) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + size_t len; + uint8_t *buf_ptr; + wmi_roam_ap_profile_fixed_param *roam_ap_profile_fp; + wmi_roam_cnd_scoring_param *score_param; + wmi_ap_profile *profile; + wmi_roam_score_delta_param *score_delta_param; + wmi_roam_cnd_min_rssi_param *min_rssi_param; + wmi_owe_ap_profile *owe_ap_profile; + enum roam_trigger_reason trig_reason; + uint32_t *authmode_list; + int8_t mlo_prefer_percentage = 0; + wmi_ssid *ssid; + int i; + + len = sizeof(wmi_roam_ap_profile_fixed_param) + sizeof(wmi_ap_profile); + len += sizeof(*score_param) + WMI_TLV_HDR_SIZE; + + if (!wmi_service_enabled(wmi_handle, + wmi_service_configure_roam_trigger_param_support)) { + len += WMI_TLV_HDR_SIZE; + len += NUM_OF_ROAM_TRIGGERS * sizeof(*score_delta_param); + len += WMI_TLV_HDR_SIZE; + len += NUM_OF_ROAM_MIN_RSSI * sizeof(*min_rssi_param); + } else { + len += 2 * WMI_TLV_HDR_SIZE; + } + + if (ap_profile->owe_ap_profile.is_owe_transition_conn) { + len += WMI_TLV_HDR_SIZE; + len += sizeof(*owe_ap_profile); + } else { + len += WMI_TLV_HDR_SIZE; + } + + if (ap_profile->profile.num_allowed_authmode) { + len += WMI_TLV_HDR_SIZE; + len += ap_profile->profile.num_allowed_authmode * + sizeof(uint32_t); + } else { + len += WMI_TLV_HDR_SIZE; + } + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + roam_ap_profile_fp = (wmi_roam_ap_profile_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&roam_ap_profile_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_ap_profile_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_ap_profile_fixed_param)); + /* fill in threshold values */ + roam_ap_profile_fp->vdev_id = ap_profile->vdev_id; + roam_ap_profile_fp->id = 0; + buf_ptr += sizeof(wmi_roam_ap_profile_fixed_param); + + profile = (wmi_ap_profile *)buf_ptr; + WMITLV_SET_HDR(&profile->tlv_header, + WMITLV_TAG_STRUC_wmi_ap_profile, + WMITLV_GET_STRUCT_TLVLEN(wmi_ap_profile)); + profile->flags = ap_profile->profile.flags; + profile->rssi_threshold = ap_profile->profile.rssi_threshold; + profile->bg_rssi_threshold = ap_profile->profile.bg_rssi_threshold; + profile->ssid.ssid_len = ap_profile->profile.ssid.length; + qdf_mem_copy(profile->ssid.ssid, ap_profile->profile.ssid.ssid, + profile->ssid.ssid_len); + profile->rsn_authmode = ap_profile->profile.rsn_authmode; + profile->rsn_ucastcipherset = ap_profile->profile.rsn_ucastcipherset; + profile->rsn_mcastcipherset = ap_profile->profile.rsn_mcastcipherset; + profile->rsn_mcastmgmtcipherset = + ap_profile->profile.rsn_mcastmgmtcipherset; + profile->rssi_abs_thresh = ap_profile->profile.rssi_abs_thresh; + + wmi_debug("vdev %d AP PROFILE: flags:%x rssi_thres:%d bg_rssi_thres:%d ssid:" QDF_SSID_FMT " authmode:%d uc cipher:%d mc cipher:%d mc mgmt cipher:%d rssi abs thresh:%d", + roam_ap_profile_fp->vdev_id, + profile->flags, profile->rssi_threshold, + profile->bg_rssi_threshold, + QDF_SSID_REF(profile->ssid.ssid_len, + ap_profile->profile.ssid.ssid), + profile->rsn_authmode, profile->rsn_ucastcipherset, + profile->rsn_mcastcipherset, profile->rsn_mcastmgmtcipherset, + profile->rssi_abs_thresh); + + buf_ptr += sizeof(wmi_ap_profile); + + score_param = (wmi_roam_cnd_scoring_param *)buf_ptr; + WMITLV_SET_HDR(&score_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_cnd_scoring_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_cnd_scoring_param)); + score_param->disable_bitmap = ap_profile->param.disable_bitmap; + score_param->rssi_weightage_pcnt = + ap_profile->param.rssi_weightage; + score_param->ht_weightage_pcnt = ap_profile->param.ht_weightage; + score_param->vht_weightage_pcnt = ap_profile->param.vht_weightage; + score_param->he_weightage_pcnt = ap_profile->param.he_weightage; + score_param->bw_weightage_pcnt = ap_profile->param.bw_weightage; + score_param->band_weightage_pcnt = ap_profile->param.band_weightage; + score_param->nss_weightage_pcnt = ap_profile->param.nss_weightage; + score_param->security_weightage_pcnt = + ap_profile->param.security_weightage; + score_param->esp_qbss_weightage_pcnt = + ap_profile->param.esp_qbss_weightage; + score_param->beamforming_weightage_pcnt = + ap_profile->param.beamforming_weightage; + score_param->pcl_weightage_pcnt = ap_profile->param.pcl_weightage; + score_param->oce_wan_weightage_pcnt = + ap_profile->param.oce_wan_weightage; + score_param->oce_ap_tx_pwr_weightage_pcnt = + ap_profile->param.oce_ap_tx_pwr_weightage; + score_param->oce_ap_subnet_id_weightage_pcnt = + ap_profile->param.oce_subnet_id_weightage; + score_param->vendor_roam_score_algorithm_id = + ap_profile->param.vendor_roam_score_algorithm; + score_param->sae_pk_ap_weightage_pcnt = + ap_profile->param.sae_pk_ap_weightage; + update_mlo_prefer_percentage(wmi_handle->soc->wmi_psoc, + &mlo_prefer_percentage); + score_param->mlo_etp_weightage_pcnt = mlo_prefer_percentage; + send_update_mlo_roam_params(score_param, ap_profile); + wmi_debug("Score params weightage: disable_bitmap %x rssi %d ht %d vht %d he %d BW %d band %d NSS %d ESP %d BF %d PCL %d OCE WAN %d APTX %d roam score algo %d subnet id %d sae-pk %d security %d mlo_etp_weight_pct %d", + score_param->disable_bitmap, score_param->rssi_weightage_pcnt, + score_param->ht_weightage_pcnt, + score_param->vht_weightage_pcnt, + score_param->he_weightage_pcnt, + score_param->bw_weightage_pcnt, + score_param->band_weightage_pcnt, + score_param->nss_weightage_pcnt, + score_param->esp_qbss_weightage_pcnt, + score_param->beamforming_weightage_pcnt, + score_param->pcl_weightage_pcnt, + score_param->oce_wan_weightage_pcnt, + score_param->oce_ap_tx_pwr_weightage_pcnt, + score_param->vendor_roam_score_algorithm_id, + score_param->oce_ap_subnet_id_weightage_pcnt, + score_param->sae_pk_ap_weightage_pcnt, + score_param->security_weightage_pcnt, + score_param->mlo_etp_weightage_pcnt); + + score_param->bw_scoring.score_pcnt = ap_profile->param.bw_index_score; + score_param->band_scoring.score_pcnt = + ap_profile->param.band_index_score; + score_param->nss_scoring.score_pcnt = + ap_profile->param.nss_index_score; + score_param->security_scoring.score_pcnt = + ap_profile->param.security_index_score; + + wmi_debug("bw_index_score %x band_index_score %x nss_index_score %x security_index_score %x", + score_param->bw_scoring.score_pcnt, + score_param->band_scoring.score_pcnt, + score_param->nss_scoring.score_pcnt, + score_param->security_scoring.score_pcnt); + + score_param->rssi_scoring.best_rssi_threshold = + (-1) * ap_profile->param.rssi_scoring.best_rssi_threshold; + score_param->rssi_scoring.good_rssi_threshold = + (-1) * ap_profile->param.rssi_scoring.good_rssi_threshold; + score_param->rssi_scoring.bad_rssi_threshold = + (-1) * ap_profile->param.rssi_scoring.bad_rssi_threshold; + score_param->rssi_scoring.good_rssi_pcnt = + ap_profile->param.rssi_scoring.good_rssi_pcnt; + score_param->rssi_scoring.bad_rssi_pcnt = + ap_profile->param.rssi_scoring.bad_rssi_pcnt; + score_param->rssi_scoring.good_bucket_size = + ap_profile->param.rssi_scoring.good_rssi_bucket_size; + score_param->rssi_scoring.bad_bucket_size = + ap_profile->param.rssi_scoring.bad_rssi_bucket_size; + score_param->rssi_scoring.rssi_pref_5g_rssi_thresh = + (-1) * ap_profile->param.rssi_scoring.rssi_pref_5g_rssi_thresh; + + wmi_debug("Rssi scoring threshold: best RSSI %d good RSSI %d bad RSSI %d prefer 5g threshold %d", + score_param->rssi_scoring.best_rssi_threshold, + score_param->rssi_scoring.good_rssi_threshold, + score_param->rssi_scoring.bad_rssi_threshold, + score_param->rssi_scoring.rssi_pref_5g_rssi_thresh); + wmi_debug("Good RSSI score for each slot %d bad RSSI score for each slot %d good bucket %d bad bucket %d", + score_param->rssi_scoring.good_rssi_pcnt, + score_param->rssi_scoring.bad_rssi_pcnt, + score_param->rssi_scoring.good_bucket_size, + score_param->rssi_scoring.bad_bucket_size); + + score_param->esp_qbss_scoring.num_slot = + ap_profile->param.esp_qbss_scoring.num_slot; + score_param->esp_qbss_scoring.score_pcnt3_to_0 = + ap_profile->param.esp_qbss_scoring.score_pcnt3_to_0; + score_param->esp_qbss_scoring.score_pcnt7_to_4 = + ap_profile->param.esp_qbss_scoring.score_pcnt7_to_4; + score_param->esp_qbss_scoring.score_pcnt11_to_8 = + ap_profile->param.esp_qbss_scoring.score_pcnt11_to_8; + score_param->esp_qbss_scoring.score_pcnt15_to_12 = + ap_profile->param.esp_qbss_scoring.score_pcnt15_to_12; + + wmi_debug("ESP QBSS index weight: slots %d weight 0to3 %x weight 4to7 %x weight 8to11 %x weight 12to15 %x", + score_param->esp_qbss_scoring.num_slot, + score_param->esp_qbss_scoring.score_pcnt3_to_0, + score_param->esp_qbss_scoring.score_pcnt7_to_4, + score_param->esp_qbss_scoring.score_pcnt11_to_8, + score_param->esp_qbss_scoring.score_pcnt15_to_12); + + score_param->oce_wan_scoring.num_slot = + ap_profile->param.oce_wan_scoring.num_slot; + score_param->oce_wan_scoring.score_pcnt3_to_0 = + ap_profile->param.oce_wan_scoring.score_pcnt3_to_0; + score_param->oce_wan_scoring.score_pcnt7_to_4 = + ap_profile->param.oce_wan_scoring.score_pcnt7_to_4; + score_param->oce_wan_scoring.score_pcnt11_to_8 = + ap_profile->param.oce_wan_scoring.score_pcnt11_to_8; + score_param->oce_wan_scoring.score_pcnt15_to_12 = + ap_profile->param.oce_wan_scoring.score_pcnt15_to_12; + + wmi_debug("OCE WAN index weight: slots %d weight 0to3 %x weight 4to7 %x weight 8to11 %x weight 12to15 %x", + score_param->oce_wan_scoring.num_slot, + score_param->oce_wan_scoring.score_pcnt3_to_0, + score_param->oce_wan_scoring.score_pcnt7_to_4, + score_param->oce_wan_scoring.score_pcnt11_to_8, + score_param->oce_wan_scoring.score_pcnt15_to_12); + + score_param->roam_score_delta_pcnt = ap_profile->param.roam_score_delta; + score_param->roam_score_delta_mask = + ap_profile->param.roam_trigger_bitmap; + score_param->candidate_min_roam_score_delta = + ap_profile->param.cand_min_roam_score_delta; + wmi_debug("Roam score delta:%d Roam_trigger_bitmap:%x cand min score delta = %d", + score_param->roam_score_delta_pcnt, + score_param->roam_score_delta_mask, + score_param->candidate_min_roam_score_delta); + + buf_ptr += sizeof(*score_param); + + if (!wmi_service_enabled(wmi_handle, + wmi_service_configure_roam_trigger_param_support)) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (NUM_OF_ROAM_TRIGGERS * sizeof(*score_delta_param))); + buf_ptr += WMI_TLV_HDR_SIZE; + + score_delta_param = (wmi_roam_score_delta_param *)buf_ptr; + WMITLV_SET_HDR(&score_delta_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_score_delta_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_score_delta_param)); + trig_reason = + ap_profile->score_delta_param[IDLE_ROAM_TRIGGER].trigger_reason; + score_delta_param->roam_trigger_reason = + convert_roam_trigger_reason(trig_reason); + score_delta_param->roam_score_delta = + ap_profile->score_delta_param[IDLE_ROAM_TRIGGER].roam_score_delta; + + buf_ptr += sizeof(*score_delta_param); + score_delta_param = (wmi_roam_score_delta_param *)buf_ptr; + WMITLV_SET_HDR(&score_delta_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_score_delta_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_score_delta_param)); + trig_reason = + ap_profile->score_delta_param[BTM_ROAM_TRIGGER].trigger_reason; + score_delta_param->roam_trigger_reason = + convert_roam_trigger_reason(trig_reason); + score_delta_param->roam_score_delta = + ap_profile->score_delta_param[BTM_ROAM_TRIGGER].roam_score_delta; + + buf_ptr += sizeof(*score_delta_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + (NUM_OF_ROAM_MIN_RSSI * sizeof(*min_rssi_param))); + buf_ptr += WMI_TLV_HDR_SIZE; + + min_rssi_param = (wmi_roam_cnd_min_rssi_param *)buf_ptr; + WMITLV_SET_HDR(&min_rssi_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_cnd_min_rssi_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_cnd_min_rssi_param)); + trig_reason = + ap_profile->min_rssi_params[DEAUTH_MIN_RSSI].trigger_reason; + min_rssi_param->roam_trigger_reason = + convert_roam_trigger_reason(trig_reason); + min_rssi_param->candidate_min_rssi = + ap_profile->min_rssi_params[DEAUTH_MIN_RSSI].min_rssi; + + buf_ptr += sizeof(*min_rssi_param); + min_rssi_param = (wmi_roam_cnd_min_rssi_param *)buf_ptr; + WMITLV_SET_HDR(&min_rssi_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_cnd_min_rssi_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_cnd_min_rssi_param)); + trig_reason = + ap_profile->min_rssi_params[BMISS_MIN_RSSI].trigger_reason; + min_rssi_param->roam_trigger_reason = + convert_roam_trigger_reason(trig_reason); + min_rssi_param->candidate_min_rssi = + ap_profile->min_rssi_params[BMISS_MIN_RSSI].min_rssi; + + buf_ptr += sizeof(*min_rssi_param); + min_rssi_param = (wmi_roam_cnd_min_rssi_param *)buf_ptr; + WMITLV_SET_HDR(&min_rssi_param->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_cnd_min_rssi_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_cnd_min_rssi_param)); + trig_reason = + ap_profile->min_rssi_params[MIN_RSSI_2G_TO_5G_ROAM].trigger_reason; + min_rssi_param->roam_trigger_reason = + convert_roam_trigger_reason(trig_reason); + min_rssi_param->candidate_min_rssi = + ap_profile->min_rssi_params[MIN_RSSI_2G_TO_5G_ROAM].min_rssi; + + buf_ptr += sizeof(*min_rssi_param); + } else { + /* set zero TLV's for roam_score_delta_param_list */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + + /* set zero TLV's for roam_cnd_min_rssi_param_list */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + } + + /* set zero TLV's for roam_cnd_vendor_scoring_param */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + + if (ap_profile->owe_ap_profile.is_owe_transition_conn) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(*owe_ap_profile)); + buf_ptr += WMI_TLV_HDR_SIZE; + + owe_ap_profile = (wmi_owe_ap_profile *)buf_ptr; + ssid = &owe_ap_profile->open_ssid_for_owe_transition; + WMITLV_SET_HDR(&owe_ap_profile->tlv_header, + WMITLV_TAG_STRUC_wmi_owe_ap_profile, + WMITLV_GET_STRUCT_TLVLEN(wmi_owe_ap_profile)); + + ssid->ssid_len = ap_profile->owe_ap_profile.ssid.length; + qdf_mem_copy(ssid->ssid, + ap_profile->owe_ap_profile.ssid.ssid, + ap_profile->owe_ap_profile.ssid.length); + wmi_debug("[OWE_TRANSITION]: open ssid:" QDF_SSID_FMT, + QDF_SSID_REF(ssid->ssid_len, (char *)ssid->ssid)); + + buf_ptr += sizeof(*owe_ap_profile); + } else { + /* set zero TLV's for owe_ap_profile */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + } + + /* List of Allowed authmode other than the connected akm */ + if (ap_profile->profile.num_allowed_authmode) { + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (ap_profile->profile.num_allowed_authmode * + sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + + authmode_list = (uint32_t *)buf_ptr; + for (i = 0; i < ap_profile->profile.num_allowed_authmode; i++) + authmode_list[i] = + ap_profile->profile.allowed_authmode[i]; + + wmi_debug("[Allowed Authmode]: num_allowed_authmode: %d", + ap_profile->profile.num_allowed_authmode); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, + authmode_list, + ap_profile->profile.num_allowed_authmode * + sizeof(uint32_t)); + } else { + /* set zero TLV's for allowed_authmode */ + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + WMITLV_GET_STRUCT_TLVLEN(0)); + buf_ptr += WMI_TLV_HDR_SIZE; + } + + wmi_mtrace(WMI_ROAM_AP_PROFILE, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_AP_PROFILE); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * send_roam_scan_offload_cmd_tlv() - set roam offload command + * @wmi_handle: wmi handle + * @command: command + * @vdev_id: vdev id + * + * This function set roam offload command to fw. + * + * Return: QDF status + */ +static QDF_STATUS +send_roam_scan_offload_cmd_tlv(wmi_unified_t wmi_handle, + uint32_t command, uint32_t vdev_id) +{ + QDF_STATUS status; + wmi_roam_scan_cmd_fixed_param *cmd_fp; + wmi_buf_t buf = NULL; + int len; + uint8_t *buf_ptr; + + len = sizeof(wmi_roam_scan_cmd_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + + cmd_fp = (wmi_roam_scan_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_scan_cmd_fixed_param)); + cmd_fp->vdev_id = vdev_id; + cmd_fp->command_arg = command; + + wmi_mtrace(WMI_ROAM_SCAN_CMD, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_SCAN_CMD); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + wmi_info("WMI --> WMI_ROAM_SCAN_CMD"); + return QDF_STATUS_SUCCESS; + +error: + wmi_buf_free(buf); + + return status; +} + +/** + * send_roam_scan_offload_chan_list_cmd_tlv() - set roam offload channel list + * @wmi_handle: wmi handle + * @rso_ch_info: Roam offload channel information + * + * Set roam offload channel list. + * + * Return: QDF status + */ +static QDF_STATUS send_roam_scan_offload_chan_list_cmd_tlv( + wmi_unified_t wmi_handle, + struct wlan_roam_scan_channel_list *rso_ch_info) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len, list_tlv_len; + int i; + uint8_t *buf_ptr; + wmi_roam_chan_list_fixed_param *chan_list_fp; + uint32_t *roam_chan_list_array; + uint8_t chan_count = rso_ch_info->chan_count; + uint32_t *chan_list = rso_ch_info->chan_freq_list; + + /* Channel list is a table of 2 TLV's */ + list_tlv_len = WMI_TLV_HDR_SIZE + chan_count * sizeof(uint32_t); + len = sizeof(wmi_roam_chan_list_fixed_param) + list_tlv_len; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + chan_list_fp = (wmi_roam_chan_list_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&chan_list_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_chan_list_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_chan_list_fixed_param)); + chan_list_fp->vdev_id = rso_ch_info->vdev_id; + chan_list_fp->num_chan = chan_count; + if (rso_ch_info->chan_cache_type == WMI_CHANNEL_LIST_STATIC) + /* external app is controlling channel list */ + chan_list_fp->chan_list_type = + WMI_ROAM_SCAN_CHAN_LIST_TYPE_STATIC; + else + /* umac supplied occupied channel list in LFR */ + chan_list_fp->chan_list_type = + WMI_ROAM_SCAN_CHAN_LIST_TYPE_DYNAMIC; + + buf_ptr += sizeof(wmi_roam_chan_list_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + (chan_list_fp->num_chan * sizeof(uint32_t))); + roam_chan_list_array = (uint32_t *)(buf_ptr + WMI_TLV_HDR_SIZE); + for (i = 0; ((i < chan_list_fp->num_chan) && + (i < WMI_ROAM_MAX_CHANNELS)); i++) + roam_chan_list_array[i] = chan_list[i]; + + wmi_debug("RSO_CFG: vdev:%d num_chan:%d cache_type:%d", + chan_list_fp->vdev_id, chan_list_fp->num_chan, + rso_ch_info->chan_cache_type); + wmi_mtrace(WMI_ROAM_CHAN_LIST, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_CHAN_LIST); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +/** + * send_roam_scan_offload_rssi_change_cmd_tlv() - set roam offload RSSI th + * @wmi_handle: wmi handle + * @params: RSSI change parameters + * + * Send WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD parameters to fw. + * + * Return: CDF status + */ +static QDF_STATUS send_roam_scan_offload_rssi_change_cmd_tlv( + wmi_unified_t wmi_handle, + struct wlan_roam_rssi_change_params *params) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_scan_rssi_change_threshold_fixed_param *rssi_change_fp; + + /* Send rssi change parameters */ + len = sizeof(wmi_roam_scan_rssi_change_threshold_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + rssi_change_fp = + (wmi_roam_scan_rssi_change_threshold_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&rssi_change_fp->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_scan_rssi_change_threshold_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_scan_rssi_change_threshold_fixed_param)); + /* fill in rssi change threshold (hysteresis) values */ + rssi_change_fp->vdev_id = params->vdev_id; + rssi_change_fp->roam_scan_rssi_change_thresh = + params->rssi_change_thresh; + rssi_change_fp->bcn_rssi_weight = params->bcn_rssi_weight; + rssi_change_fp->hirssi_delay_btw_scans = params->hirssi_delay_btw_scans; + + wmi_nofl_debug("RSO_CFG: vdev %d rssi_change_thresh:%d bcn_rssi_weight:%d hirssi_delay_btw_scans:%d", + rssi_change_fp->vdev_id, + rssi_change_fp->roam_scan_rssi_change_thresh, + rssi_change_fp->bcn_rssi_weight, + rssi_change_fp->hirssi_delay_btw_scans); + + wmi_mtrace(WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + rssi_change_fp->vdev_id, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_SCAN_RSSI_CHANGE_THRESHOLD); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + return QDF_STATUS_SUCCESS; +error: + wmi_buf_free(buf); + + return status; +} + +/** + * send_per_roam_config_cmd_tlv() - set per roaming config to FW + * @wmi_handle: wmi handle + * @req_buf: per roam config buffer + * + * Return: QDF status + */ +static QDF_STATUS +send_per_roam_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wlan_per_roam_config_req *req_buf) +{ + wmi_buf_t buf = NULL; + QDF_STATUS status; + int len; + uint8_t *buf_ptr; + wmi_roam_per_config_fixed_param *wmi_per_config; + + len = sizeof(wmi_roam_per_config_fixed_param); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + wmi_per_config = + (wmi_roam_per_config_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&wmi_per_config->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_per_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_roam_per_config_fixed_param)); + + /* fill in per roam config values */ + wmi_per_config->vdev_id = req_buf->vdev_id; + + wmi_per_config->enable = req_buf->per_config.enable; + wmi_per_config->high_rate_thresh = + (req_buf->per_config.tx_high_rate_thresh << 16) | + (req_buf->per_config.rx_high_rate_thresh & 0x0000ffff); + wmi_per_config->low_rate_thresh = + (req_buf->per_config.tx_low_rate_thresh << 16) | + (req_buf->per_config.rx_low_rate_thresh & 0x0000ffff); + wmi_per_config->pkt_err_rate_thresh_pct = + (req_buf->per_config.tx_rate_thresh_percnt << 16) | + (req_buf->per_config.rx_rate_thresh_percnt & 0x0000ffff); + wmi_per_config->per_rest_time = req_buf->per_config.per_rest_time; + wmi_per_config->pkt_err_rate_mon_time = + (req_buf->per_config.tx_per_mon_time << 16) | + (req_buf->per_config.rx_per_mon_time & 0x0000ffff); + wmi_per_config->min_candidate_rssi = + req_buf->per_config.min_candidate_rssi; + + /* Send per roam config parameters */ + wmi_mtrace(WMI_ROAM_PER_CONFIG_CMDID, NO_SESSION, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_ROAM_PER_CONFIG_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_err("WMI_ROAM_PER_CONFIG_CMDID failed, Error %d", status); + wmi_buf_free(buf); + return status; + } + wmi_debug("per roam enable=%d, vdev=%d", + req_buf->per_config.enable, req_buf->vdev_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * send_limit_off_chan_cmd_tlv() - send wmi cmd of limit off chan + * configuration params + * @wmi_handle: wmi handler + * @limit_off_chan_param: pointer to wmi_off_chan_param + * + * Return: 0 for success and non zero for failure + */ +static QDF_STATUS send_limit_off_chan_cmd_tlv( + wmi_unified_t wmi_handle, + struct wmi_limit_off_chan_param *limit_off_chan_param) +{ + wmi_vdev_limit_offchan_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len = sizeof(*cmd); + int err; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_vdev_limit_offchan_cmd_fixed_param *)wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_limit_offchan_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_limit_offchan_cmd_fixed_param)); + + cmd->vdev_id = limit_off_chan_param->vdev_id; + + cmd->flags &= 0; + if (limit_off_chan_param->status) + cmd->flags |= WMI_VDEV_LIMIT_OFFCHAN_ENABLE; + if (limit_off_chan_param->skip_dfs_chans) + cmd->flags |= WMI_VDEV_LIMIT_OFFCHAN_SKIP_DFS; + + cmd->max_offchan_time = limit_off_chan_param->max_offchan_time; + cmd->rest_time = limit_off_chan_param->rest_time; + + wmi_debug("vdev_id=%d, flags =%x, max_offchan_time=%d, rest_time=%d", + cmd->vdev_id, cmd->flags, cmd->max_offchan_time, + cmd->rest_time); + + wmi_mtrace(WMI_VDEV_LIMIT_OFFCHAN_CMDID, cmd->vdev_id, 0); + err = wmi_unified_cmd_send(wmi_handle, buf, + len, WMI_VDEV_LIMIT_OFFCHAN_CMDID); + if (QDF_IS_STATUS_ERROR(err)) { + wmi_err("Failed to send limit off chan cmd err=%d", err); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FILS_SK +static QDF_STATUS send_roam_scan_send_hlp_cmd_tlv(wmi_unified_t wmi_handle, + struct hlp_params *params) +{ + uint32_t len; + uint8_t *buf_ptr; + wmi_buf_t buf = NULL; + wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param *hlp_params; + + len = sizeof(wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param); + len += WMI_TLV_HDR_SIZE; + len += qdf_roundup(params->hlp_ie_len, sizeof(uint32_t)); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + hlp_params = (wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&hlp_params->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_update_fils_hlp_pkt_cmd_fixed_param)); + + hlp_params->vdev_id = params->vdev_id; + hlp_params->size = params->hlp_ie_len; + hlp_params->pkt_type = WMI_FILS_HLP_PKT_TYPE_DHCP_DISCOVER; + + buf_ptr += sizeof(*hlp_params); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + round_up(params->hlp_ie_len, sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, params->hlp_ie, params->hlp_ie_len); + + wmi_debug("send FILS HLP pkt vdev %d len %d", + hlp_params->vdev_id, hlp_params->size); + wmi_mtrace(WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID, NO_SESSION, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_PDEV_UPDATE_FILS_HLP_PKT_CMDID)) { + wmi_err("Failed to send FILS HLP pkt cmd"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void wmi_fils_sk_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_roam_scan_hlp_cmd = send_roam_scan_send_hlp_cmd_tlv; +} +#endif /* WLAN_FEATURE_FILS_SK */ + +/* + * send_btm_config_cmd_tlv() - Send wmi cmd for BTM config + * @wmi_handle: wmi handle + * @params: pointer to wlan_roam_btm_config + * + * Return: QDF_STATUS + */ +static QDF_STATUS send_btm_config_cmd_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_btm_config *params) +{ + wmi_btm_config_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_btm_config_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_btm_config_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_btm_config_fixed_param)); + cmd->vdev_id = params->vdev_id; + cmd->flags = params->btm_offload_config; + cmd->max_attempt_cnt = params->btm_max_attempt_cnt; + cmd->solicited_timeout_ms = params->btm_solicited_timeout; + cmd->stick_time_seconds = params->btm_sticky_time; + cmd->disassoc_timer_threshold = params->disassoc_timer_threshold; + cmd->btm_bitmap = params->btm_query_bitmask; + cmd->btm_candidate_min_score = params->btm_candidate_min_score; + + wmi_debug("RSO_CFG: vdev_id:%u btm_offload:%u btm_query_bitmask:%u btm_candidate_min_score:%u", + cmd->vdev_id, cmd->flags, cmd->btm_bitmap, + cmd->btm_candidate_min_score); + wmi_debug("RSO_CFG: btm_solicited_timeout:%u btm_max_attempt_cnt:%u btm_sticky_time:%u disassoc_timer_threshold:%u", + cmd->solicited_timeout_ms, cmd->max_attempt_cnt, + cmd->stick_time_seconds, cmd->disassoc_timer_threshold); + + wmi_mtrace(WMI_ROAM_BTM_CONFIG_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_BTM_CONFIG_CMDID)) { + wmi_err("Failed to send WMI_ROAM_BTM_CONFIG_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_bss_load_config_tlv() - send roam load bss trigger configuration + * @wmi_handle: wmi handle + * @params: pointer to wlan_roam_bss_load_config + * + * This function sends the roam load bss trigger configuration to fw. + * the bss_load_threshold parameter is used to configure the maximum + * bss load percentage, above which the firmware should trigger roaming + * + * Return: QDF status + */ +static QDF_STATUS +send_roam_bss_load_config_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_bss_load_config *params) +{ + wmi_roam_bss_load_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_bss_load_config_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_bss_load_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_bss_load_config_cmd_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->bss_load_threshold = params->bss_load_threshold; + cmd->monitor_time_window = params->bss_load_sample_time; + cmd->rssi_2g_threshold = params->rssi_threshold_24ghz; + cmd->rssi_5g_threshold = params->rssi_threshold_5ghz; + cmd->rssi_6g_threshold = params->rssi_threshold_6ghz; + + wmi_debug("RSO_CFG: vdev:%d bss_load_thres:%d monitor_time:%d rssi_2g:%d rssi_5g:%d, rssi_6g:%d", + cmd->vdev_id, cmd->bss_load_threshold, + cmd->monitor_time_window, cmd->rssi_2g_threshold, + cmd->rssi_5g_threshold, cmd->rssi_6g_threshold); + + wmi_mtrace(WMI_ROAM_BSS_LOAD_CONFIG_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_BSS_LOAD_CONFIG_CMDID)) { + wmi_err("Failed to send WMI_ROAM_BSS_LOAD_CONFIG_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * send_disconnect_roam_params_tlv() - send disconnect roam trigger parameters + * @wmi_handle: wmi handle + * @req: pointer to wlan_roam_disconnect_params which carries the + * disconnect_roam_trigger parameters + * + * This function sends the disconnect roam trigger parameters to fw. + * + * Return: QDF status + */ +static QDF_STATUS +send_disconnect_roam_params_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_disconnect_params *req) +{ + wmi_roam_deauth_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_deauth_config_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_deauth_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_deauth_config_cmd_fixed_param)); + + cmd->vdev_id = req->vdev_id; + cmd->enable = req->enable; + wmi_debug("RSO_CFG: vdev_id:%d enable:%d", cmd->vdev_id, cmd->enable); + + wmi_mtrace(WMI_ROAM_DEAUTH_CONFIG_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_DEAUTH_CONFIG_CMDID)) { + wmi_err("Failed to send WMI_ROAM_DEAUTH_CONFIG_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#define WLAN_TIME_IN_MS 1000 +/** + * send_idle_roam_params_tlv() - send idle roam trigger parameters + * @wmi_handle: wmi handle + * @idle_roam_params: pointer to wlan_roam_idle_params which carries the + * idle roam parameters from CSR + * + * This function sends the idle roam trigger parameters to fw. + * + * Return: QDF status + */ +static QDF_STATUS +send_idle_roam_params_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_idle_params *idle_roam_params) +{ + wmi_roam_idle_config_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_roam_idle_config_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_idle_config_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_idle_config_cmd_fixed_param)); + + cmd->vdev_id = idle_roam_params->vdev_id; + cmd->enable = idle_roam_params->enable; + cmd->band = idle_roam_params->band; + cmd->rssi_delta = idle_roam_params->conn_ap_rssi_delta; + cmd->min_rssi = idle_roam_params->conn_ap_min_rssi; + cmd->idle_time = idle_roam_params->inactive_time / WLAN_TIME_IN_MS; + cmd->data_packet_count = idle_roam_params->data_pkt_count; + wmi_debug("RSO_CFG: vdev_id:%d enable:%d band:%d rssi_delta:%d min_rssi:%d idle_time:%d data_pkt:%d", + cmd->vdev_id, cmd->enable, + cmd->band, cmd->rssi_delta, cmd->min_rssi, + cmd->idle_time, cmd->data_packet_count); + + wmi_mtrace(WMI_ROAM_IDLE_CONFIG_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_IDLE_CONFIG_CMDID)) { + wmi_err("Failed to send WMI_ROAM_IDLE_CONFIG_CMDID"); + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * send_roam_preauth_status_tlv() - send roam pre-authentication status + * @wmi_handle: wmi handle + * @params: pre-auth status params + * + * This function sends the roam pre-authentication status for WPA3 SAE + * pre-auth to target. + * + * Return: QDF status + */ +static QDF_STATUS +send_roam_preauth_status_tlv(wmi_unified_t wmi_handle, + struct wmi_roam_auth_status_params *params) +{ + wmi_roam_preauth_status_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE + PMKID_LEN; + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_roam_preauth_status_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_roam_preauth_status_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_roam_preauth_status_cmd_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->preauth_status = params->preauth_status; + WMI_CHAR_ARRAY_TO_MAC_ADDR(params->bssid.bytes, + &cmd->candidate_ap_bssid); + + buf_ptr += sizeof(wmi_roam_preauth_status_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, PMKID_LEN); + buf_ptr += WMI_TLV_HDR_SIZE; + + qdf_mem_copy(buf_ptr, params->pmkid, PMKID_LEN); + wmi_debug("vdev_id:%d status:%d bssid:"QDF_MAC_ADDR_FMT, + cmd->vdev_id, cmd->preauth_status, + QDF_MAC_ADDR_REF(params->bssid.bytes)); + + wmi_mtrace(WMI_ROAM_PREAUTH_STATUS_CMDID, cmd->vdev_id, 0); + if (wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_ROAM_PREAUTH_STATUS_CMDID)) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +send_disconnect_roam_params_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_disconnect_params *req) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +send_idle_roam_params_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_idle_params *idle_roam_params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +send_roam_preauth_status_tlv(wmi_unified_t wmi_handle, + struct wmi_roam_auth_status_params *params) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * send_offload_11k_cmd_tlv() - send wmi cmd with 11k offload params + * @wmi_handle: wmi handler + * @params: pointer to 11k offload params + * + * Return: 0 for success and non zero for failure + */ +static QDF_STATUS +send_offload_11k_cmd_tlv(wmi_unified_t wmi_handle, + struct wlan_roam_11k_offload_params *params) +{ + wmi_11k_offload_report_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + wmi_neighbor_report_11k_offload_tlv_param + *neighbor_report_offload_params; + wmi_neighbor_report_offload *neighbor_report_offload; + uint32_t len = sizeof(*cmd); + + if (params->offload_11k_bitmask & + WMI_11K_OFFLOAD_BITMAP_NEIGHBOR_REPORT_REQ) + len += WMI_TLV_HDR_SIZE + + sizeof(wmi_neighbor_report_11k_offload_tlv_param); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_11k_offload_report_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_offload_11k_report_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_11k_offload_report_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->offload_11k = params->offload_11k_bitmask; + + if (params->offload_11k_bitmask & + WMI_11K_OFFLOAD_BITMAP_NEIGHBOR_REPORT_REQ) { + buf_ptr += sizeof(wmi_11k_offload_report_fixed_param); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_STRUC, + sizeof(wmi_neighbor_report_11k_offload_tlv_param)); + buf_ptr += WMI_TLV_HDR_SIZE; + + neighbor_report_offload_params = + (wmi_neighbor_report_11k_offload_tlv_param *)buf_ptr; + WMITLV_SET_HDR(&neighbor_report_offload_params->tlv_header, + WMITLV_TAG_STRUC_wmi_neighbor_report_offload_tlv_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_neighbor_report_11k_offload_tlv_param)); + + neighbor_report_offload = &neighbor_report_offload_params-> + neighbor_rep_ofld_params; + + neighbor_report_offload->time_offset = + params->neighbor_report_params.time_offset; + neighbor_report_offload->low_rssi_offset = + params->neighbor_report_params.low_rssi_offset; + neighbor_report_offload->bmiss_count_trigger = + params->neighbor_report_params.bmiss_count_trigger; + neighbor_report_offload->per_threshold_offset = + params->neighbor_report_params.per_threshold_offset; + neighbor_report_offload->neighbor_report_cache_timeout = + params->neighbor_report_params. + neighbor_report_cache_timeout; + neighbor_report_offload->max_neighbor_report_req_cap = + params->neighbor_report_params. + max_neighbor_report_req_cap; + neighbor_report_offload->ssid.ssid_len = + params->neighbor_report_params.ssid.length; + qdf_mem_copy(neighbor_report_offload->ssid.ssid, + ¶ms->neighbor_report_params.ssid.ssid, + neighbor_report_offload->ssid.ssid_len); + } + + wmi_debug("RSO_CFG: vdev %d 11k_bitmask:%u time_offset:%u low_rssi_offset:%u bmiss_count_trigger:%u per_threshold_offset%u", + cmd->vdev_id, params->offload_11k_bitmask, + params->neighbor_report_params.time_offset, + params->neighbor_report_params.low_rssi_offset, + params->neighbor_report_params.bmiss_count_trigger, + params->neighbor_report_params.per_threshold_offset); + wmi_debug("RSO_CFG: neighbor_report_cache_timeout:%u max_neighbor_report_req_cap:%u SSID:" QDF_SSID_FMT, + params->neighbor_report_params.neighbor_report_cache_timeout, + params->neighbor_report_params.max_neighbor_report_req_cap, + QDF_SSID_REF(params->neighbor_report_params.ssid.length, + params->neighbor_report_params.ssid.ssid)); + + wmi_mtrace(WMI_11K_OFFLOAD_REPORT_CMDID, cmd->vdev_id, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_11K_OFFLOAD_REPORT_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send 11k offload command %d", status); + wmi_buf_free(buf); + } + + return status; +} + +/** + * send_invoke_neighbor_report_cmd_tlv() - send invoke 11k neighbor report + * command + * @wmi_handle: wmi handler + * @params: pointer to neighbor report invoke params + * + * Return: 0 for success and non zero for failure + */ +static QDF_STATUS send_invoke_neighbor_report_cmd_tlv( + wmi_unified_t wmi_handle, + struct wmi_invoke_neighbor_report_params *params) +{ + wmi_11k_offload_invoke_neighbor_report_fixed_param *cmd; + wmi_buf_t buf; + QDF_STATUS status; + uint8_t *buf_ptr; + uint32_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_11k_offload_invoke_neighbor_report_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_invoke_neighbor_report_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_11k_offload_invoke_neighbor_report_fixed_param)); + + cmd->vdev_id = params->vdev_id; + cmd->flags = params->send_resp_to_host; + + cmd->ssid.ssid_len = params->ssid.length; + qdf_mem_copy(cmd->ssid.ssid, ¶ms->ssid.ssid, cmd->ssid.ssid_len); + + wmi_mtrace(WMI_11K_INVOKE_NEIGHBOR_REPORT_CMDID, cmd->vdev_id, 0); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_11K_INVOKE_NEIGHBOR_REPORT_CMDID); + if (status != QDF_STATUS_SUCCESS) { + wmi_err("Failed to send invoke neighbor report command %d", + status); + wmi_buf_free(buf); + } + + return status; +} + +void wmi_roam_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->send_roam_scan_offload_rssi_thresh_cmd = + send_roam_scan_offload_rssi_thresh_cmd_tlv; + ops->send_roam_mawc_params_cmd = send_roam_mawc_params_cmd_tlv; + ops->send_roam_scan_filter_cmd = + send_roam_scan_filter_cmd_tlv; + ops->send_roam_scan_offload_mode_cmd = + send_roam_scan_offload_mode_cmd_tlv; + ops->send_roam_scan_offload_ap_profile_cmd = + send_roam_scan_offload_ap_profile_cmd_tlv; + ops->send_roam_scan_offload_cmd = send_roam_scan_offload_cmd_tlv; + ops->send_roam_scan_offload_scan_period_cmd = + send_roam_scan_offload_scan_period_cmd_tlv; + ops->send_roam_scan_offload_chan_list_cmd = + send_roam_scan_offload_chan_list_cmd_tlv; + ops->send_roam_scan_offload_rssi_change_cmd = + send_roam_scan_offload_rssi_change_cmd_tlv; + ops->send_per_roam_config_cmd = send_per_roam_config_cmd_tlv; + ops->send_limit_off_chan_cmd = send_limit_off_chan_cmd_tlv; + ops->send_btm_config = send_btm_config_cmd_tlv; + ops->send_offload_11k_cmd = send_offload_11k_cmd_tlv; + ops->send_invoke_neighbor_report_cmd = + send_invoke_neighbor_report_cmd_tlv; + ops->send_roam_bss_load_config = send_roam_bss_load_config_tlv; + ops->send_idle_roam_params = send_idle_roam_params_tlv; + ops->send_disconnect_roam_params = send_disconnect_roam_params_tlv; + ops->send_roam_preauth_status = send_roam_preauth_status_tlv; + ops->extract_roam_event = extract_roam_event_tlv; + + wmi_roam_mlo_attach_tlv(wmi_handle); + wmi_lfr_subnet_detection_attach_tlv(wmi_handle); + wmi_rssi_monitor_attach_tlv(wmi_handle); + wmi_ese_attach_tlv(wmi_handle); + wmi_roam_offload_attach_tlv(wmi_handle); + wmi_fils_sk_attach_tlv(wmi_handle); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/adrastea_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/adrastea_defconfig new file mode 100644 index 0000000000..6e0e3c209e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/adrastea_defconfig @@ -0,0 +1 @@ +include $(WLAN_ROOT)/configs/default_defconfig diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/config_to_feature.h b/qcom/opensource/wlan/qcacld-3.0/configs/config_to_feature.h new file mode 100644 index 0000000000..aba4654fb6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/config_to_feature.h @@ -0,0 +1,3002 @@ +/* + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CONFIG_TO_FEATURE_H +#define CONFIG_TO_FEATURE_H + +#ifdef CONFIG_CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +#define CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT (1) +#endif + +#ifdef CONFIG_CFG80211_MLO_KEY_OPERATION_SUPPORT +#define CFG80211_MLO_KEY_OPERATION_SUPPORT (1) +#endif + +#ifdef CONFIG_CFG80211_LINK_STA_PARAMS_PRESENT +#define CFG80211_LINK_STA_PARAMS_PRESENT (1) +#endif + +#ifdef CONFIG_CFG80211_RU_PUNCT_SUPPORT +#define CFG80211_RU_PUNCT_SUPPORT (1) +#endif + +#ifdef CONFIG_CFG80211_RU_PUNCT_NOTIFY +#define CFG80211_RU_PUNCT_NOTIFY (1) +#endif + +#ifdef CONFIG_CFG80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA +#define CFG80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA (1) +#endif + +#ifdef CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT +#define CFG80211_EXTERNAL_AUTH_MLO_SUPPORT (1) +#endif + +#ifdef CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN +#define CFG80211_EXT_FEATURE_SECURE_NAN (1) +#endif + +#ifdef CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT +#define CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT (1) +#endif + +#ifdef CONFIG_CFG80211_SET_KEY_WITH_SRC_MAC +#define CFG80211_SET_KEY_WITH_SRC_MAC (1) +#endif + +#ifdef CONFIG_CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +#define CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV (1) +#endif + +#ifdef CONFIG_ONE_MSI_VECTOR +#define WLAN_ONE_MSI_VECTOR (1) +#endif + +#ifdef CONFIG_DSC_DEBUG +#define WLAN_DSC_DEBUG (1) +#endif + +#ifdef CONFIG_DSC_TEST +#define WLAN_DSC_TEST (1) +#endif + +#ifdef CONFIG_BERYLLIUM +#define DP_OFFLOAD_FRAME_WITH_SW_EXCEPTION (1) +#endif + +#ifdef CONFIG_TALLOC_DEBUG +#define WLAN_TALLOC_DEBUG (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_DELAYED_WORK_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_HASHTABLE_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_PERIODIC_WORK_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_PTR_HASH_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_SLIST_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_TALLOC_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_TRACKER_TEST (1) +#endif + +#ifdef CONFIG_QDF_TEST +#define WLAN_TYPES_TEST (1) +#endif + +#ifdef CONFIG_WLAN_HANG_EVENT +#define WLAN_HANG_EVENT (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_PRE_CAC +#define PRE_CAC_SUPPORT (1) +#endif + +#ifdef CONFIG_WIFI_POS_PASN +#define WLAN_FEATURE_RTT_11AZ_SUPPORT (1) +#endif + +#ifdef CONFIG_DIRECT_BUF_RX_ENABLE +#ifdef CONFIG_DBR_HOLD_LARGE_MEM +#define DBR_HOLD_LARGE_MEM (1) +#endif +#endif +#ifdef CONFIG_DP_TRAFFIC_END_INDICATION +#define DP_TRAFFIC_END_INDICATION (1) +#endif + +#ifdef CONFIG_THERMAL_STATS_SUPPORT +#define THERMAL_STATS_SUPPORT (1) +#endif + +#ifdef CONFIG_PTT_SOCK_SVC_ENABLE +#define PTT_SOCK_SVC_ENABLE (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_WAPI +#define FEATURE_WLAN_WAPI (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_WAPI +#define ATH_SUPPORT_WAPI (1) +#endif + +#ifdef CONFIG_SOFTAP_CHANNEL_RANGE +#define SOFTAP_CHANNEL_RANGE (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_SCAN_PNO +#define FEATURE_WLAN_SCAN_PNO (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_PACKET_FILTERING +#define WLAN_FEATURE_PACKET_FILTERING (1) +#endif + +#ifdef CONFIG_DHCP_SERVER_OFFLOAD +#define DHCP_SERVER_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_NS_OFFLOAD +#define WLAN_NS_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_DYNAMIC_ARP_NS_OFFLOAD +#define FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_ICMP_OFFLOAD +#define WLAN_FEATURE_ICMP_OFFLOAD (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_RA_FILTERING +#define FEATURE_WLAN_RA_FILTERING (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_LPHB +#define FEATURE_WLAN_LPHB (1) +#endif + +#ifdef CONFIG_QCA_SUPPORT_TX_THROTTLE +#define QCA_SUPPORT_TX_THROTTLE (1) +#endif + +#ifdef CONFIG_WMI_INTERFACE_EVENT_LOGGING +#define WMI_INTERFACE_EVENT_LOGGING (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_LINK_LAYER_STATS +#define WLAN_FEATURE_LINK_LAYER_STATS (1) +#endif + +#ifdef CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION +#define FEATURE_CLUB_LL_STATS_AND_GET_STATION (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_MIB_STATS +#define WLAN_FEATURE_MIB_STATS (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_EXTSCAN +#define FEATURE_WLAN_EXTSCAN (1) +#endif + +#ifdef CONFIG_WLAN_PMO_ENABLE +#define WLAN_PMO_ENABLE (1) +#endif + +#ifdef CONFIG_CONVERGED_P2P_ENABLE +#define CONVERGED_P2P_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_POLICY_MGR_ENABLE +#define WLAN_POLICY_MGR_ENABLE (1) +#endif + +#ifdef CONFIG_FEATURE_DENYLIST_MGR +#define FEATURE_DENYLIST_MGR (1) +#endif + +#ifdef CONFIG_WAPI_BIG_ENDIAN +#define FEATURE_WAPI_BIG_ENDIAN (1) +#endif + +#ifdef CONFIG_SUPPORT_11AX +#define SUPPORT_11AX (1) +#endif + +#ifdef CONFIG_WLAN_CONV_SPECTRAL_ENABLE +#define WLAN_CONV_SPECTRAL_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_CFR_ENABLE +#define WLAN_CFR_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_ENH_CFR_ENABLE +#define WLAN_ENH_CFR_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_ENH_CFR_ENABLE +#define WLAN_CFR_PM (1) +#endif + +#ifdef CONFIG_WLAN_CFR_ADRASTEA +#define WLAN_CFR_ADRASTEA (1) +#endif + +#ifdef CONFIG_WLAN_CFR_DBR +#define WLAN_CFR_DBR (1) +#endif + +#ifdef CONFIG_WLAN_CFR_ENABLE +#define CFR_USE_FIXED_FOLDER (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_MEDIUM_ASSESS +#define WLAN_FEATURE_MEDIUM_ASSESS (1) +#endif + +#ifdef CONFIG_FEATURE_RADAR_HISTORY +#define FEATURE_RADAR_HISTORY (1) +#endif + +#ifdef CONFIG_DIRECT_BUF_RX_ENABLE +#define DIRECT_BUF_RX_ENABLE (1) +#endif + +#ifdef CONFIG_WMI_DBR_SUPPORT +#define WMI_DBR_SUPPORT (1) +#endif + +#if !defined(CONFIG_CNSS_QCA6750) && !defined(CONFIG_CNSS_WCN6450) +#ifdef CONFIG_DIRECT_BUF_RX_ENABLE +#define DBR_MULTI_SRNG_ENABLE (1) +#endif +#endif + +#ifdef CONFIG_WMI_CMD_STRINGS +#define WMI_CMD_STRINGS (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_TWT +#define WLAN_SUPPORT_TWT (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#ifdef CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH +#define DP_USE_REDUCED_PEER_ID_FIELD_WIDTH (1) +#endif +#endif + +#ifdef CONFIG_WLAN_TWT_SAP_STA_COUNT +#define WLAN_TWT_SAP_STA_COUNT (32) +#endif + +#ifdef CONFIG_WLAN_TWT_SAP_PDEV_COUNT +#define WLAN_TWT_AP_PDEV_COUNT_NUM_PHY (1) +#endif + +#ifdef CONFIG_WLAN_DISABLE_EXPORT_SYMBOL +#define WLAN_DISABLE_EXPORT_SYMBOL (1) +#endif + +#ifdef CONFIG_WIFI_POS_CONVERGED +#define WIFI_POS_CONVERGED (1) +#endif + +#ifdef CONFIG_WLAN_TWT_CONVERGED +#define WLAN_TWT_CONV_SUPPORTED (1) +#endif + +#ifdef CONFIG_WIFI_POS_LEGACY +#define FEATURE_OEM_DATA_SUPPORT (1) +#endif + +#ifdef CONFIG_FEATURE_HTC_CREDIT_HISTORY +#define FEATURE_HTC_CREDIT_HISTORY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_P2P_DEBUG +#define WLAN_FEATURE_P2P_DEBUG (1) +#endif + +#ifdef CONFIG_WLAN_WEXT_SUPPORT_ENABLE +#define WLAN_WEXT_SUPPORT_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_LOGGING_SOCK_SVC +#define WLAN_LOGGING_SOCK_SVC_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY +#define WLAN_LOGGING_BUFFERS_DYNAMICALLY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_FILS +#define WLAN_FEATURE_FILS_SK (1) +#endif + +#ifdef CONFIG_CP_STATS +#define WLAN_SUPPORT_INFRA_CTRL_PATH_STATS (1) +#endif + +#ifdef CONFIG_QCA_TARGET_IF_MLME +#define QCA_TARGET_IF_MLME +#endif + +#ifdef CONFIG_CP_STATS +#define QCA_SUPPORT_CP_STATS (1) +#endif + +#ifdef CONFIG_CP_STATS +#define QCA_SUPPORT_MC_CP_STATS (1) +#endif + +#ifdef CONFIG_CP_STATS +#define WLAN_SUPPORT_LEGACY_CP_STATS_HANDLERS (1) +#endif + +#ifdef CONFIG_DCS +#define DCS_INTERFERENCE_DETECTION (1) +#endif + +#ifdef CONFIG_FEATURE_INTEROP_ISSUES_AP +#define WLAN_FEATURE_INTEROP_ISSUES_AP (1) +#endif + +#ifdef CONFIG_FEATURE_MEMDUMP_ENABLE +#define WLAN_FEATURE_MEMDUMP_ENABLE (1) +#endif + +#ifdef CONFIG_FEATURE_FW_LOG_PARSING +#define FEATURE_FW_LOG_PARSING (1) +#endif + +#ifdef CONFIG_FEATURE_OEM_DATA +#define FEATURE_OEM_DATA (1) +#endif + +#ifdef CONFIG_FEATURE_MOTION_DETECTION +#define WLAN_FEATURE_MOTION_DETECTION (1) +#endif + +#ifdef CONFIG_WLAN_FW_OFFLOAD +#define WLAN_FW_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_ELNA +#define WLAN_FEATURE_ELNA (1) +#endif + +#ifdef CONFIG_FEATURE_COEX +#define FEATURE_COEX (1) +#endif + +#ifdef CONFIG_HOST_WAKEUP_OVER_QMI +#define HOST_WAKEUP_OVER_QMI (1) +#endif + +#ifdef CONFIG_DISABLE_STATUS_RING_TIMER_WAR +#define WLAN_DISABLE_STATUS_RING_TIMER_WAR (1) +#endif + +#ifdef CONFIG_CE_DISABLE_SRNG_TIMER_IRQ +#define WLAN_WAR_CE_DISABLE_SRNG_TIMER_IRQ (1) +#endif + +#ifdef CONFIG_PLD_IPCI_ICNSS_FLAG +#define CONFIG_PLD_IPCI_ICNSS (1) +#endif + +#ifdef CONFIG_PLD_SDIO_CNSS_FLAG +#define CONFIG_PLD_SDIO_CNSS (1) +#endif + +#ifdef CONFIG_WLAN_RESIDENT_DRIVER +#define FEATURE_WLAN_RESIDENT_DRIVER (1) +#endif + +#ifdef CONFIG_FEATURE_GPIO_CFG +#define WLAN_FEATURE_GPIO_CFG (1) +#endif + +#ifdef CONFIG_FEATURE_BUS_BANDWIDTH_MGR +#define FEATURE_BUS_BANDWIDTH_MGR (1) +#endif + +#ifdef CONFIG_DP_BE_WAR +#define DP_BE_WAR (1) +#endif + +#ifdef CONFIG_IPCIE_FW_SIM +#define CONFIG_PLD_IPCIE_FW_SIM (1) +#endif + +#ifdef CONFIG_PLD_PCIE_CNSS_FLAG +#ifdef CONFIG_PCIE_FW_SIM +#define CONFIG_PLD_PCIE_FW_SIM (1) +#else +#define CONFIG_PLD_PCIE_CNSS (1) +#endif +#endif +#ifdef CONFIG_PLD_PCIE_INIT_FLAG +#define CONFIG_PLD_PCIE_INIT (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_RX_THREADS +#define FEATURE_WLAN_DP_RX_THREADS (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT +#define WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT (1) +#endif + +#ifdef CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE +#define HIF_LATENCY_PROFILE_ENABLE (1) +#endif + +#ifdef CONFIG_FEATURE_HAL_DELAYED_REG_WRITE +#define FEATURE_HAL_DELAYED_REG_WRITE (1) +#endif + +#ifdef CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE +#define FEATURE_HAL_RECORD_SUSPEND_WRITE (1) +#endif + +#ifdef CONFIG_QCA_OL_DP_SRNG_LOCK_LESS_ACCESS +#define QCA_OL_DP_SRNG_LOCK_LESS_ACCESS (1) +#endif + +#ifdef CONFIG_SHADOW_WRITE_DELAY +#define SHADOW_WRITE_DELAY (1) +#endif + +#ifdef CONFIG_WLAN_RECORD_RX_PADDR +#define HIF_RECORD_RX_PADDR (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_TIME_SYNC_FTM +#define FEATURE_WLAN_TIME_SYNC_FTM (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB +#define WLAN_FEATURE_LRO_CTX_IN_CB (1) +#endif + +#ifdef CONFIG_FEATURE_MONITOR_MODE_SUPPORT +#define FEATURE_MONITOR_MODE_SUPPORT (1) +#ifdef CONFIG_DP_CON_MON_MSI_ENABLED +#define DP_CON_MON_MSI_ENABLED (1) +#endif +#ifdef CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO +#define WLAN_RX_MON_PARSE_CMN_USER_INFO (1) +#endif +#ifdef CONFIG_DP_CON_MON_MSI_SKIP_SET +#define DP_CON_MON_MSI_SKIP_SET (1) +#endif +#ifdef CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT +#define QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT (1) +#endif +#else +#define DISABLE_MON_CONFIG (1) +#endif + +#ifdef CONFIG_NL80211_TESTMODE +#define WLAN_NL80211_TESTMODE (1) +#endif + +#ifdef CONFIG_BUS_AUTO_SUSPEND +#define FEATURE_RUNTIME_PM (1) +#endif + +#if defined(CONFIG_ICNSS) || defined(CONFIG_ICNSS_MODULE) +#ifdef CONFIG_SNOC_FW_SIM +#define CONFIG_PLD_SNOC_FW_SIM (1) +#else +#define CONFIG_PLD_SNOC_ICNSS (1) +#endif +#endif + +#ifdef CONFIG_PLD_SNOC_ICNSS_FLAG +#define CONFIG_PLD_SNOC_ICNSS (1) +#endif + +#ifdef CONFIG_ICNSS2_HELIUM +#define CONFIG_PLD_SNOC_ICNSS2 (1) +#endif + +#ifdef CONFIG_WIFI_3_0_ADRASTEA +#define QCA_WIFI_3_0_ADRASTEA (1) +#endif + +#ifdef CONFIG_WIFI_3_0_ADRASTEA +#define QCA_WIFI_3_0 (1) +#endif + +#ifdef CONFIG_ADRASTEA_SHADOW_REGISTERS +#define ADRASTEA_SHADOW_REGISTERS (1) +#endif + +#ifdef CONFIG_ADRASTEA_RRI_ON_DDR +#define ADRASTEA_RRI_ON_DDR (1) +#endif + +#ifndef CONFIG_QMI_SUPPORT +#define CONFIG_BYPASS_QMI (1) +#endif + +#ifdef CONFIG_WLAN_FASTPATH +#define WLAN_FEATURE_FASTPATH (1) +#endif + +#ifdef CONFIG_FEATURE_PKTLOG +#define FEATURE_PKTLOG (1) +#endif + +#ifdef CONFIG_CONNECTIVITY_PKTLOG +#define CONNECTIVITY_PKTLOG (1) +#endif + +#ifdef CONFIG_WLAN_NAPI +#define FEATURE_NAPI (1) +#define HIF_IRQ_AFFINITY (1) +#ifdef CONFIG_WLAN_NAPI_DEBUG +#define FEATURE_NAPI_DEBUG (1) +#endif +#endif + +#if defined(CONFIG_ARCH_MSM) || defined(CONFIG_ARCH_QCOM) +#define MSM_PLATFORM (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH +#define WLAN_FEATURE_DP_BUS_BANDWIDTH (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS +#define WLAN_FEATURE_PERIODIC_STA_STATS (1) +#endif + +#if defined(CONFIG_WLAN_TX_FLOW_CONTROL_V2) || \ + defined(CONFIG_WLAN_TX_FLOW_CONTROL_V2_HL) +#define QCA_LL_TX_FLOW_CONTROL_V2 (1) +#endif + +#if defined(CONFIG_WLAN_TX_FLOW_CONTROL_V2) || \ + defined(CONFIG_WLAN_TX_FLOW_CONTROL_V2_HL) +#define QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL (1) +#endif + +#ifdef CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY +#define QCA_LL_LEGACY_TX_FLOW_CONTROL (1) +#endif + +#ifdef CONFIG_WLAN_PDEV_TX_FLOW_CONTROL +#define QCA_LL_PDEV_TX_FLOW_CONTROL (1) +#endif + +#ifdef CONFIG_WLAN_DEBUG_VERSION +#define WLAN_DEBUG (1) +#ifdef CONFIG_TRACE_RECORD_FEATURE +#define TRACE_RECORD (1) +#define LIM_TRACE_RECORD (1) +#define SME_TRACE_RECORD (1) +#define HDD_TRACE_RECORD (1) + +#endif +#endif +#ifdef CONFIG_UNIT_TEST +#define WLAN_UNIT_TEST (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_RTS_CTS +#define WLAN_SYSFS_RTS_CTS (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_DP_TRACE +#define WLAN_SYSFS_DP_TRACE (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_STATS +#define WLAN_SYSFS_STATS (1) +#endif +#ifdef CONFIG_FEATURE_UNIT_TEST_SUSPEND +#define WLAN_SUSPEND_RESUME_TEST (1) +#endif +#ifdef CONFIG_FEATURE_WLM_STATS +#define FEATURE_WLM_STATS (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_DCM +#define WLAN_SYSFS_DCM (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_HE_BSS_COLOR +#define WLAN_SYSFS_HE_BSS_COLOR (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_STA_INFO +#define WLAN_SYSFS_STA_INFO (1) +#endif +#ifdef CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT +#define FEATURE_WPSS_THERMAL_MITIGATION (1) +#endif +#ifdef CONFIG_WLAN_SYSFS_DP_STATS +#define WLAN_SYSFS_DP_STATS (1) +#endif +#ifdef CONFIG_WIFI_MONITOR_SUPPORT +#define WIFI_MONITOR_SUPPORT (1) +#endif + +#ifdef CONFIG_QCA_MONITOR_PKT_SUPPORT +#define QCA_MONITOR_PKT_SUPPORT (1) +#endif + +#ifdef CONFIG_MONITOR_MODULARIZED_ENABLE +#define MONITOR_MODULARIZED_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM +#define WLAN_PDEV_VDEV_SEND_MULTI_PARAM (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_LOG_BUFFER +#define FEATURE_SYSFS_LOG_BUFFER (1) +#endif + +#ifdef CONFIG_ENABLE_VALLOC_REPLACE_MALLOC +#define ENABLE_VALLOC_REPLACE_MALLOC (1) +#endif + +#ifdef CONFIG_LEAK_DETECTION +#define CONFIG_HALT_KMEMLEAK (1) +#define MEMORY_DEBUG (1) +#define NBUF_MEMORY_DEBUG (1) +#define NBUF_MAP_UNMAP_DEBUG (1) +#define TIMER_MANAGER (1) +#define WLAN_DELAYED_WORK_DEBUG (1) +#define WLAN_WAKE_LOCK_DEBUG (1) +#define WLAN_PERIODIC_WORK_DEBUG (1) + +#endif + +#ifdef CONFIG_QCOM_VOWIFI_11R +#define KERNEL_SUPPORT_11R_CFG80211 (1) +#define USE_80211_WMMTSPEC_FOR_RIC (1) +#endif + +#ifdef CONFIG_QCOM_ESE +#define FEATURE_WLAN_ESE (1) +#endif + +#ifdef CONFIG_QCOM_TDLS +#define FEATURE_WLAN_TDLS (1) +#endif + +#ifdef CONFIG_QCOM_TDLS +#define WLAN_FEATURE_TDLS_CONCURRENCIES (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_TDLS_PEERS +#define WLAN_SYSFS_TDLS_PEERS (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_RANGE_EXT +#define WLAN_SYSFS_RANGE_EXT (1) +#endif + +#ifdef CONFIG_QCACLD_WLAN_LFR2 +#define WLAN_FEATURE_PREAUTH_ENABLE (1) +#endif + +#ifdef CONFIG_CM_UTF_ENABLE +#define FEATURE_CM_UTF_ENABLE (1) +#endif + +#ifdef CONFIG_QCACLD_WLAN_LFR3 +#define WLAN_FEATURE_ROAM_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_ROAM_INFO_STATS +#define WLAN_FEATURE_ROAM_INFO_STATS (1) +#endif + +#ifdef CONFIG_QCACLD_WLAN_CONNECTIVITY_LOGGING +#define WLAN_FEATURE_CONNECTIVITY_LOGGING (1) +#endif + +#ifdef CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT +#define CONNECTIVITY_DIAG_EVENT (1) +#endif + +#ifdef CONFIG_OFDM_SCRAMBLER_SEED +#define WLAN_FEATURE_OFDM_SCRAMBLER_SEED (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_MBSSID +#define WLAN_FEATURE_MBSSID (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_P2P_P2P_STA +#define WLAN_FEATURE_P2P_P2P_STA (1) +#endif + +#if defined(CONFIG_CNSS_GENL) || defined(CONFIG_CNSS_GENL_MODULE) +#define CNSS_GENL (1) +#endif + +#if defined(CONFIG_CNSS_UTILS) || defined(CONFIG_CNSS_UTILS_MODULE) +#define CNSS_UTILS (1) +#endif + +#if defined(CONFIG_WCNSS_MEM_PRE_ALLOC) || defined(CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE) +#define CNSS_MEM_PRE_ALLOC (1) +#endif + +#ifdef CONFIG_QCACLD_WLAN_LFR2 +#define WLAN_FEATURE_HOST_ROAM (1) +#endif + +#ifdef CONFIG_FEATURE_ROAM_DEBUG +#define FEATURE_ROAM_DEBUG (1) +#endif + +#ifdef CONFIG_WLAN_POWER_DEBUG +#define WLAN_POWER_DEBUG (1) +#endif + +#ifdef CONFIG_WLAN_MWS_INFO_DEBUGFS +#define WLAN_MWS_INFO_DEBUGFS (1) +#endif + +#ifdef CONFIG_WLAN_DEBUG_LINK_VOTE +#define WLAN_DEBUG_LINK_VOTE (1) +#endif + +#ifdef CONFIG_WLAN_OBJMGR_DEBUG +#define WLAN_OBJMGR_DEBUG (1) +#endif + +#ifdef CONFIG_WLAN_OBJMGR_DEBUG +#define WLAN_OBJMGR_REF_ID_DEBUG (1) +#endif + +#ifdef CONFIG_WLAN_OBJMGR_REF_ID_TRACE +#define WLAN_OBJMGR_REF_ID_TRACE (1) +#endif + +#ifdef CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY +#define FEATURE_DELAYED_PEER_OBJ_DESTROY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_SAE +#define WLAN_FEATURE_SAE (1) +#endif + +#ifdef CONFIG_WLAN_DIAG_VERSION +#define FEATURE_WLAN_DIAG_SUPPORT (1) +#define FEATURE_WLAN_DIAG_SUPPORT_CSR (1) +#define FEATURE_WLAN_DIAG_SUPPORT_LIM (1) +#ifdef CONFIG_HIF_PCI +#define CONFIG_ATH_PROCFS_DIAG_SUPPORT (1) +#endif +#ifdef CONFIG_HIF_IPCI +#define CONFIG_ATH_PROCFS_DIAG_SUPPORT (1) +#endif +#endif +#ifdef CONFIG_HIF_USB +#define CONFIG_ATH_PROCFS_DIAG_SUPPORT (1) +#define QCA_SUPPORT_OL_RX_REORDER_TIMEOUT (1) +#define CONFIG_ATH_PCIE_MAX_PERF (0) +#define CONFIG_ATH_PCIE_AWAKE_WHILE_DRIVER_LOAD (0) +#define CONFIG_DISABLE_CDC_MAX_PERF_WAR (0) +#endif + +#ifdef CONFIG_QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +#define QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK (1) +#endif + +#ifdef CONFIG_QCA_TXDESC_SANITY_CHECKS +#define QCA_SUPPORT_TXDESC_SANITY_CHECKS (1) +#endif + +#ifdef CONFIG_QCOM_LTE_COEX +#define FEATURE_WLAN_CH_AVOID (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_LPSS +#define WLAN_FEATURE_LPSS (1) +#endif + +#ifdef CONFIG_DESC_DUP_DETECT_DEBUG +#define DESC_DUP_DETECT_DEBUG (1) +#endif + +#ifdef CONFIG_DEBUG_RX_RING_BUFFER +#define DEBUG_RX_RING_BUFFER (1) +#endif + +#ifdef CONFIG_DESC_TIMESTAMP_DEBUG_INFO +#define DESC_TIMESTAMP_DEBUG_INFO (1) +#endif + +#ifdef CONFIG_POWER_MANAGEMENT_OFFLOAD +#define WLAN_POWER_MANAGEMENT_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_LOG_FATAL +#define WLAN_LOG_FATAL (1) +#endif + +#ifdef CONFIG_WLAN_LOG_ERROR +#define WLAN_LOG_ERROR (1) +#endif + +#ifdef CONFIG_WLAN_LOG_WARN +#define WLAN_LOG_WARN (1) +#endif + +#ifdef CONFIG_WLAN_LOG_INFO +#define WLAN_LOG_INFO (1) +#endif + +#ifdef CONFIG_WLAN_LOG_DEBUG +#define WLAN_LOG_DEBUG (1) +#endif + +#ifdef CONFIG_WLAN_LOG_ENTER +#define WLAN_LOG_ENTER (1) +#endif + +#ifdef CONFIG_WLAN_LOG_EXIT +#define WLAN_LOG_EXIT (1) +#endif + +#ifdef CONFIG_FEATURE_STATS_EXT +#define WLAN_FEATURE_STATS_EXT (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_NAN +#define WLAN_FEATURE_NAN (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_SON +#define WLAN_FEATURE_SON (1) +#endif + +#ifdef CONFIG_NDP_SAP_CONCURRENCY_ENABLE +#define NDP_SAP_CONCURRENCY_ENABLE (1) +#endif + +#ifdef CONFIG_DFS_FCC_TYPE4_DURATION_CHECK +#define DFS_FCC_TYPE4_DURATION_CHECK (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS +#define WLAN_SYSFS (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_CHANNEL +#define WLAN_SYSFS_CHANNEL (1) +#endif + +#ifdef CONFIG_FEATURE_BECN_STATS +#define WLAN_FEATURE_BEACON_RECEPTION_STATS (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_CONNECT_INFO +#define WLAN_SYSFS_CONNECT_INFO (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_EHT_RATE +#define WLAN_SYSFS_EHT_RATE (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_WDS_MODE +#define FEATURE_SYSFS_WDS_MODE (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP +#define FEATURE_SYSFS_ROAM_TRIGGER_BITMAP (1) +#endif + +#ifdef CONFIG_WLAN_SYSFS_RF_TEST_MODE +#define FEATURE_SYSFS_RF_TEST_MODE (1) +#endif + +#ifdef CONFIG_RX_PERFORMANCE +#define RX_PERFORMANCE (1) +#endif + +#ifdef CONFIG_MULTI_IF_LOG +#define MULTI_IF_LOG (1) +#endif + +#ifdef CONFIG_SLUB_MEM_OPTIMIZE +#define SLUB_MEM_OPTIMIZE (1) +#endif + +#ifdef CONFIG_ARCH_SDXBAAGHA +#ifdef CONFIG_WLAN_MEMORY_OPT +#define WLAN_MEMORY_OPT (1) +#endif +#endif + +#ifdef CONFIG_DFS_PRI_MULTIPLIER +#define DFS_PRI_MULTIPLIER (1) +#endif + +#ifdef CONFIG_DFS_OVERRIDE_RF_THRESHOLD +#define DFS_OVERRIDE_RF_THRESHOLD (1) +#endif + +#ifdef CONFIG_ATH_PERF_PWR_OFFLOAD +#define ATH_PERF_PWR_OFFLOAD (1) +#endif + +#ifdef CONFIG_REMOVE_PKT_LOG +#define REMOVE_PKT_LOG (1) +#endif + +#ifdef CONFIG_ATH_11AC_TXCOMPACT +#define ATH_11AC_TXCOMPACT (1) +#endif + +#ifdef CONFIG_HIF_PCI +#define HIF_PCI (1) +#endif + +#ifdef CONFIG_HIF_IPCI +#define HIF_IPCI (1) +#endif + +#ifdef CONFIG_HIF_SNOC +#define HIF_SNOC (1) +#endif + +#ifdef CONFIG_HL_DP_SUPPORT +#define CONFIG_HL_SUPPORT (1) +#endif + +#ifdef CONFIG_HL_DP_SUPPORT +#define WLAN_PARTIAL_REORDER_OFFLOAD (1) +#endif + +#ifdef CONFIG_HL_DP_SUPPORT +#define QCA_COMPUTE_TX_DELAY (1) +#endif + +#ifdef CONFIG_HL_DP_SUPPORT +#define QCA_COMPUTE_TX_DELAY_PER_TID (1) +#endif + +#ifdef CONFIG_LL_DP_SUPPORT +#define WLAN_FULL_REORDER_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_BIG_DATA_STATS +#define WLAN_FEATURE_BIG_DATA_STATS (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11AX +#ifdef CONFIG_WLAN_FEATURE_SR +#define WLAN_FEATURE_SR (1) +#endif +#ifdef CONFIG_OBSS_PD +#define OBSS_PD (1) +#endif +#endif + +#ifdef CONFIG_WLAN_FEATURE_IGMP_OFFLOAD +#define WLAN_FEATURE_IGMP_OFFLOAD (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST +#define WLAN_FEATURE_GET_USABLE_CHAN_LIST (1) +#endif + +#ifdef CONFIG_PCIE_GEN_SWITCH +#define PCIE_GEN_SWITCH (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_WOW_PULSE +#define WLAN_FEATURE_WOW_PULSE (1) +#endif + +#ifdef CONFIG_QCA_WIFI_SDIO +#define CONFIG_AR6320_SUPPORT (1) +#define SDIO_3_0 (1) +#define HIF_SDIO (1) +#define CONFIG_DISABLE_CDC_MAX_PERF_WAR (0) +#define CONFIG_ATH_PROCFS_DIAG_SUPPORT (1) +#define HIF_MBOX_SLEEP_WAR (1) +#define DEBUG_HL_LOGGING (1) +#define QCA_BAD_PEER_TX_FLOW_CL (1) +#define CONFIG_SDIO (1) +#define FEATURE_WLAN_FORCE_SAP_SCC (1) + +#ifdef CONFIG_SDIO_TRANSFER +#define CONFIG_SDIO_TRANSFER_ADMA (1) +#else +#define CONFIG_SDIO_TRANSFER_MAILBOX (1) +#endif +#endif +#ifdef CONFIG_WLAN_FEATURE_DSRC +#define WLAN_FEATURE_DSRC (1) +#ifdef CONFIG_OCB_UT_FRAMEWORK +#define WLAN_OCB_UT (1) +#endif +#elif defined CONFIG_WLAN_REG_AUTO +#define WLAN_REG_AUTO (1) +#endif + +#ifdef CONFIG_FEATURE_SKB_PRE_ALLOC +#define FEATURE_SKB_PRE_ALLOC (1) +#endif + +#ifdef CONFIG_HIF_USB +#define HIF_USB (1) +#define DEBUG_HL_LOGGING (1) + +#endif + +#ifdef CONFIG_QCA_HL_NETDEV_FLOW_CONTROL +#define QCA_HL_NETDEV_FLOW_CONTROL (1) +#endif + +#ifdef CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL +#define FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL (1) +#endif + +#ifdef CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING +#define FEATURE_HL_DBS_GROUP_CREDIT_SHARING (1) +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF_TIMER +#define WLAN_FEATURE_TSF_TIMER_SYNC (1) +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF_PTP +#define WLAN_FEATURE_TSF_PTP (1) +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ +#define WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ (1) +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_SYNC +#define WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC (1) +#endif + +#ifdef CONFIG_ATH_BUS_PM +#define ATH_BUS_PM (1) +#endif + +#ifdef CONFIG_ATH_SUPPORT_FLOWMAC_MODULE +#define ATH_SUPPORT_FLOWMAC_MODULE (1) +#endif + +#ifdef CONFIG_ATH_SUPPORT_SPECTRAL +#define ATH_SUPPORT_SPECTRAL (1) +#endif + +#ifdef CONFIG_PKTLOG_LEGACY +#define PKTLOG_LEGACY (1) +#endif + +#ifdef CONFIG_WDI_EVENT_ENABLE +#define WDI_EVENT_ENABLE (1) +#endif + +#ifdef CONFIG_PKTLOG_HAS_SPECIFIC_DATA +#define PKTLOG_HAS_SPECIFIC_DATA (1) +#endif + +#ifdef CONFIG_LITTLE_ENDIAN +#define ANI_LITTLE_BYTE_ENDIAN (1) +#define ANI_LITTLE_BIT_ENDIAN (1) +#define DOT11F_LITTLE_ENDIAN_HOST (1) +#else +#define ANI_BIG_BYTE_ENDIAN (1) +#define BIG_ENDIAN_HOST (1) +#endif + +#ifdef CONFIG_TX_CREDIT_RECLAIM_SUPPORT +#define TX_CREDIT_RECLAIM_SUPPORT (1) +#endif + +#ifdef CONFIG_QCA_WIFI_FTM +#define QCA_WIFI_FTM (1) +#endif + +#ifdef CONFIG_NL80211_TESTMODE +#define QCA_WIFI_FTM_NL80211 (1) +#endif + +#ifdef CONFIG_LINUX_QCMBR +#define LINUX_QCMBR (1) +#define QCA_WIFI_FTM_IOCTL (1) +#endif + +#ifdef CONFIG_CHECKSUM_OFFLOAD +#define CHECKSUM_OFFLOAD (1) +#endif + +#ifdef CONFIG_IPA_OFFLOAD +#define IPA_OFFLOAD (1) +#endif + +#ifdef CONFIG_IPA_OPT_WIFI_DP +#ifdef CONFIG_IPA_OFFLOAD +#define IPA_OPT_WIFI_DP (1) +#endif +#endif +#ifdef CONFIG_WDI3_IPA_OVER_GSI +#define IPA_WDI3_GSI (1) +#endif + +#ifdef CONFIG_WDI2_IPA_OVER_GSI +#define IPA_WDI2_GSI (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7 +#define WLAN_FEATURE_WMI_DIAG_OVER_CE7 (1) +#endif + +#ifdef CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY +#define WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY (1) +#endif + +#ifdef CONFIG_ARCH_SDX20 +#define SYNC_IPA_READY (1) +#endif + +#ifdef CONFIG_FEATURE_SG +#define FEATURE_SG (1) +#endif + +#ifdef CONFIG_RX_THREAD_PRIORITY +#define RX_THREAD_PRIORITY (1) +#endif + +#ifdef CONFIG_SUPPORT_P2P_BY_ONE_INTF_WLAN +#define SUPPORT_P2P_BY_ONE_INTF_WLAN (1) +#else +#ifdef CONFIG_WLAN_OPEN_P2P_INTERFACE +#define WLAN_OPEN_P2P_INTERFACE (1) +#endif +#endif + +#ifdef CONFIG_WMI_BCN_OFFLOAD +#define WLAN_WMI_BCN (1) +#endif + +#ifdef CONFIG_WLAN_WBUFF +#define WLAN_FEATURE_WBUFF (1) +#endif + +#ifdef CONFIG_GTK_OFFLOAD +#define WLAN_FEATURE_GTK_OFFLOAD (1) +#endif + +#ifdef CONFIG_EXT_WOW +#define WLAN_FEATURE_EXTWOW_SUPPORT (1) +#endif + +#ifdef CONFIG_SMP +#define QCA_CONFIG_SMP (1) +#endif + +#ifdef CONFIG_RPS +#define QCA_CONFIG_RPS (1) +#endif + +#ifdef CONFIG_CHNL_MATRIX_RESTRICTION +#define WLAN_ENABLE_CHNL_MATRIX_RESTRICTION (1) +#endif + +#ifdef CONFIG_ICMP_DISABLE_PS +#define WLAN_ICMP_DISABLE_PS (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH +#define FEATURE_WLAN_MCC_TO_SCC_SWITCH (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN +#define FEATURE_WLAN_AUTO_SHUTDOWN (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +#define FEATURE_WLAN_AP_AP_ACS_OPTIMIZE (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME +#define FEATURE_WLAN_STA_4ADDR_SCHEME (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_GC_SKIP_JOIN +#define FEATURE_WLAN_GC_SKIP_JOIN (1) +#endif + +#ifdef CONFIG_MDM_PLATFORM +#define MDM_PLATFORM (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE +#define FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE (1) +#endif + +#ifdef CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY +#define WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_GREEN_AP +#define WLAN_SUPPORT_GREEN_AP (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE +#define WLAN_SUPPORT_GAP_LL_PS_MODE (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_APF +#define FEATURE_WLAN_APF (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 +#define WLAN_FEATURE_SARV1_TO_SARV2 (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_FT_IEEE8021X +#define FEATURE_WLAN_FT_IEEE8021X (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_FT_PSK +#define FEATURE_WLAN_FT_PSK (1) +#endif + +#ifdef CONFIG_HOST_11D_SCAN +#define HOST_11D_SCAN (1) +#endif + +#ifdef CONFIG_IPA_OFFLOAD +#ifdef CONFIG_QCACLD_FEATURE_METERING +#define FEATURE_METERING (1) +#endif +#endif +#ifdef CONFIG_IPA_OFFLOAD +#ifdef CONFIG_NUM_IPA_IFACE +#define MAX_IPA_IFACE (CONFIG_NUM_IPA_IFACE) +#else +#ifndef NUM_IPA_IFACE +#define NUM_IPA_IFACE (3) +#endif +#define MAX_IPA_IFACE (NUM_IPA_IFACE) +#endif +#endif +#ifdef CONFIG_CHANNEL_HOPPING_ALL_BANDS +#define CHANNEL_HOPPING_ALL_BANDS (1) +#endif + +#ifdef CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT +#define QCA_SIGNED_SPLIT_BINARY_SUPPORT (1) +#endif + +#ifdef CONFIG_QCA_SINGLE_BINARY_SUPPORT +#define QCA_SINGLE_BINARY_SUPPORT (1) +#endif + +#ifdef CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC +#define TARGET_RAMDUMP_AFTER_KERNEL_PANIC (1) +#endif + +#ifdef CONFIG_FEATURE_SECURE_FIRMWARE +#define FEATURE_SECURE_FIRMWARE (1) +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF +#define WLAN_FEATURE_TSF (1) +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF_PLUS +#define WLAN_FEATURE_TSF_PLUS (1) +#ifdef CONFIG_WLAN_SYNC_TSF_ACCURACY +#define WLAN_FEATURE_TSF_ACCURACY (1) +#endif +#ifndef CONFIG_WLAN_SYNC_TSF_PLUS_DISABLE_SOCK_TS +#define WLAN_FEATURE_TSF_PLUS_SOCK_TS (1) +#endif +#endif + +#ifdef CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ +#define WLAN_FEATURE_TSF_PLUS_NOIRQ (1) +#endif + +#ifdef CONFIG_WLAN_TSF_AUTO_REPORT +#define WLAN_FEATURE_TSF_AUTO_REPORT (1) +#endif + +#ifdef CONFIG_WLAN_TX_LATENCY_STATS +#define WLAN_FEATURE_TX_LATENCY_STATS (1) +#endif + +#ifdef CONFIG_WLAN_TSF_UPLINK_DELAY +#define WLAN_FEATURE_TSF_UPLINK_DELAY (1) +#endif + +#ifdef CONFIG_HELIUMPLUS +#define HELIUMPLUS (1) +#endif + +#ifdef CONFIG_RX_OL +#define RECEIVE_OFFLOAD (1) +#endif + +#ifdef CONFIG_TX_TID_OVERRIDE +#define ATH_TX_PRI_OVERRIDE (1) +#endif + +#ifdef CONFIG_AR900B +#define AR900B (1) +#endif + +#ifdef CONFIG_HTT_PADDR64 +#define HTT_PADDR64 (1) +#endif + +#ifdef CONFIG_OL_RX_INDICATION_RECORD +#define OL_RX_INDICATION_RECORD (1) +#endif + +#ifdef CONFIG_TSOSEG_DEBUG +#define TSOSEG_DEBUG (1) +#endif + +#ifdef CONFIG_ALLOW_PKT_DROPPING +#define FEATURE_ALLOW_PKT_DROPPING (1) +#endif + +#ifdef CONFIG_ATH_DIAG_EXT_DIRECT +#define ATH_DIAG_EXT_DIRECT (1) +#endif + +#ifdef CONFIG_ENABLE_DEBUG_ADDRESS_MARKING +#define ENABLE_DEBUG_ADDRESS_MARKING (1) +#endif + +#ifdef CONFIG_FEATURE_TSO +#define FEATURE_TSO (1) +#endif + +#ifdef CONFIG_FEATURE_TSO_DEBUG +#define FEATURE_TSO_DEBUG (1) +#endif + +#ifdef CONFIG_FEATURE_TSO_STATS +#define FEATURE_TSO_STATS (1) +#endif + +#ifdef CONFIG_FEATURE_FORCE_WAKE +#define FORCE_WAKE (1) +#endif + +#ifdef CONFIG_WLAN_LRO +#define FEATURE_LRO (1) +#endif + +#ifdef CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE +#define FEATURE_AP_MCC_CH_AVOIDANCE (1) +#endif + +#ifdef CONFIG_FEATURE_EPPING +#define WLAN_FEATURE_EPPING (1) +#endif + +#ifdef CONFIG_WLAN_OFFLOAD_PACKETS +#define WLAN_FEATURE_OFFLOAD_PACKETS (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DISA +#define WLAN_FEATURE_DISA (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_ACTION_OUI +#define WLAN_FEATURE_ACTION_OUI (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_FIPS +#define WLAN_FEATURE_FIPS (1) +#endif + +#ifdef CONFIG_LFR_SUBNET_DETECTION +#define FEATURE_LFR_SUBNET_DETECTION (1) +#endif + +#ifdef CONFIG_MCC_TO_SCC_SWITCH +#define FEATURE_WLAN_MCC_TO_SCC_SWITCH (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_D0WOW +#define FEATURE_WLAN_D0WOW (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_PKT_CAPTURE +#define WLAN_FEATURE_PKT_CAPTURE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_PKT_CAPTURE_V2 +#define WLAN_FEATURE_PKT_CAPTURE_V2 (1) +#endif + +#ifdef CONFIG_DP_RX_UDP_OVER_PEER_ROAM +#define DP_RX_UDP_OVER_PEER_ROAM (1) +#endif + +#ifdef CONFIG_QCA_WIFI_EMULATION +#define QCA_WIFI_EMULATION (1) +#endif + +#ifdef CONFIG_SAP_MULTI_LINK_EMULATION +#define SAP_MULTI_LINK_EMULATION (1) +#endif + +#ifdef CONFIG_QCA6290_HEADERS_DEF +#define QCA6290_HEADERS_DEF (1) +#endif + +#ifdef CONFIG_QCA_WIFI_QCA6290 +#define QCA_WIFI_QCA6290 (1) +#endif + +#ifdef CONFIG_QCA6390_HEADERS_DEF +#define QCA6390_HEADERS_DEF (1) +#endif + +#ifdef CONFIG_QCA6750_HEADERS_DEF +#define QCA6750_HEADERS_DEF (1) +#endif + +#ifdef CONFIG_QCA_WIFI_QCA6390 +#define QCA_WIFI_QCA6390 (1) +#endif + +#ifdef CONFIG_QCA6490_HEADERS_DEF +#define QCA6490_HEADERS_DEF (1) +#endif + +#ifdef CONFIG_KIWI_HEADERS_DEF +#define KIWI_HEADERS_DEF (1) +#endif + +#ifdef CONFIG_WCN6450_HEADERS_DEF +#define WCN6450_HEADERS_DEF (1) +#endif + +#ifdef CONFIG_QCA_WIFI_QCA6490 +#define QCA_WIFI_QCA6490 (1) +#endif + +#ifdef CONFIG_QCA_WIFI_QCA6750 +#define QCA_WIFI_QCA6750 (1) +#endif + +#ifdef CONFIG_QCA_WIFI_KIWI +#define QCA_WIFI_KIWI (1) +#endif + +#ifdef CONFIG_QCA_WIFI_WCN6450 +#define QCA_WIFI_WCN6450 (1) +#endif + +#ifdef CONFIG_QCA_WIFI_WCN6450 +#define WLAN_40BIT_ADDRESSING_SUPPORT (1) +#endif + +#ifdef CONFIG_QCA_WIFI_WCN6450 +#define WLAN_64BIT_DATA_SUPPORT (1) +#endif + +#ifdef CONFIG_CE_LEGACY_MSI_SUPPORT +#define CE_LEGACY_MSI_SUPPORT (1) +#endif + +#ifdef CONFIG_HIF_HAL_REG_ACCESS_SUPPORT +#define HIF_HAL_REG_ACCESS_SUPPORT (1) +#endif + +#ifdef CONFIG_CNSS_KIWI_V2 +#define QCA_WIFI_KIWI_V2 (1) +#endif + +#ifdef CONFIG_CNSS_MANGO +#define QCA_WIFI_MANGO (1) +#endif + +#ifdef CONFIG_CNSS_PEACH +#define QCA_WIFI_PEACH (1) +#endif + +#ifdef CONFIG_CNSS_PEACH_V2 +#define QCA_WIFI_PEACH_V2 (1) +#endif + +#ifdef CONFIG_INCLUDE_HAL_KIWI +#define INCLUDE_HAL_KIWI (1) +#endif + +#ifdef CONFIG_INCLUDE_HAL_PEACH +#define INCLUDE_HAL_PEACH (1) +#endif + +#ifdef CONFIG_QCA_WIFI_QCA8074 +#define QCA_WIFI_QCA8074 (1) +#endif + +#ifdef CONFIG_SCALE_INCLUDES +#define SCALE_INCLUDES (1) +#endif + +#ifdef CONFIG_QCA_WIFI_QCA8074_VP +#define QCA_WIFI_QCA8074_VP (1) +#endif + +#ifdef CONFIG_DP_INTR_POLL_BASED +#define DP_INTR_POLL_BASED (1) +#endif + +#ifdef CONFIG_TX_PER_PDEV_DESC_POOL +#define TX_PER_PDEV_DESC_POOL (1) +#endif + +#ifdef CONFIG_FEATURE_TSO +#define FEATURE_TSO (1) +#endif + +#ifdef CONFIG_TSO_DEBUG_LOG_ENABLE +#define TSO_DEBUG_LOG_ENABLE (1) +#endif + +#ifdef CONFIG_DP_LFR +#define DP_LFR (1) +#endif + +#ifdef CONFIG_DUP_RX_DESC_WAR +#define DUP_RX_DESC_WAR (1) +#endif + +#ifdef CONFIG_DP_MEM_PRE_ALLOC +#define DP_MEM_PRE_ALLOC (1) +#endif + +#ifdef CONFIG_DP_TXRX_SOC_ATTACH +#define DP_TXRX_SOC_ATTACH (1) +#endif + +#ifdef CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT +#define QCA_TX_PADDING_CREDIT_SUPPORT (1) +#endif + +#ifdef CONFIG_QCN7605_SUPPORT +#define QCN7605_SUPPORT (1) +#define PLATFORM_GENOA (1) +#endif + +#ifdef CONFIG_HIF_REG_WINDOW_SUPPORT +#define HIF_REG_WINDOW_SUPPORT (1) +#endif + +#ifdef CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +#define WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY (1) +#endif + +#ifdef CONFIG_HIF_CE_DEBUG_DATA_BUF +#define HIF_CE_DEBUG_DATA_BUF (1) +#endif + +#ifdef CONFIG_IPA_DISABLE_OVERRIDE +#define IPA_DISABLE_OVERRIDE (1) +#endif + +#ifdef CONFIG_QCA_LL_TX_FLOW_CONTROL_RESIZE +#define QCA_LL_TX_FLOW_CONTROL_RESIZE (1) +#endif + +#ifdef CONFIG_HIF_PCI +#define CE_SVC_CMN_INIT (1) +#endif + +#ifdef CONFIG_HIF_IPCI +#define CE_SVC_CMN_INIT (1) +#endif + +#ifdef CONFIG_HIF_SNOC +#define CE_SVC_CMN_INIT (1) +#endif + +#ifdef CONFIG_RX_DESC_SANITY_WAR +#define RX_DESC_SANITY_WAR (1) +#endif + +#ifdef CONFIG_WBM_IDLE_LSB_WR_CNF_WAR +#define WBM_IDLE_LSB_WRITE_CONFIRM_WAR (1) +#endif + +#ifdef CONFIG_DYNAMIC_RX_AGGREGATION +#define WLAN_FEATURE_DYNAMIC_RX_AGGREGATION (1) +#endif + +#ifdef CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION +#define DP_FEATURE_HW_COOKIE_CONVERSION (1) +#endif + +#ifdef CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION +#define DP_HW_COOKIE_CONVERT_EXCEPTION (1) +#endif + +#ifdef CONFIG_TX_ADDR_INDEX_SEARCH +#define TX_ADDR_INDEX_SEARCH (1) +#endif + +#ifdef CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES +#define QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES (1) +#endif + +#ifdef CONFIG_QCA_GET_TSF_VIA_REG +#define QCA_GET_TSF_VIA_REG (1) +#endif + +#ifdef CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK +#define DP_TX_COMP_RING_DESC_SANITY_CHECK (1) +#endif + +#ifdef CONFIG_HAL_SRNG_REG_HIS_DEBUG +#define HAL_SRNG_REG_HIS_DEBUG (1) +#endif + +#ifdef CONFIG_RX_HASH_DEBUG +#define RX_HASH_DEBUG (1) +#endif + +#ifdef CONFIG_DP_PKT_STATS_PER_LMAC +#define DP_PKT_STATS_PER_LMAC (1) +#endif + +#ifdef CONFIG_NO_RX_PKT_HDR_TLV +#define NO_RX_PKT_HDR_TLV (1) +#endif + +#ifdef CONFIG_QCA6290_11AX +#define QCA_WIFI_QCA6290_11AX (1) +#define QCA_WIFI_QCA6290_11AX_MU_UL (1) +#endif + +#if defined(CONFIG_WLAN_TX_FLOW_CONTROL_V2) || \ + defined(CONFIG_WLAN_TX_FLOW_CONTROL_V2_HL) +#define QCA_AC_BASED_FLOW_CONTROL (1) +#endif + +#ifdef CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT +#define FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT (1) +#endif + +#ifdef CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR +#define HAL_DISABLE_NON_BA_2K_JUMP_ERROR (1) +#endif + +#ifdef CONFIG_ENABLE_HAL_SOC_STATS +#define ENABLE_HAL_SOC_STATS (1) +#endif + +#ifdef CONFIG_DP_RX_DESC_COOKIE_INVALIDATE +#define DP_RX_DESC_COOKIE_INVALIDATE (1) +#endif + +#ifdef CONFIG_MON_ENABLE_DROP_FOR_MAC +#define MON_ENABLE_DROP_FOR_MAC (1) +#endif + +#ifdef CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC +#define MON_ENABLE_DROP_FOR_NON_MON_PMAC (1) +#endif + +#ifdef CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG +#define DP_WAR_INVALID_FIRST_MSDU_FLAG (1) +#endif + +#ifdef CONFIG_LITHIUM +#define DISABLE_MON_RING_MSI_CFG (1) +#endif + +#ifdef CONFIG_LITHIUM +#define FEATURE_IRQ_AFFINITY (1) +#endif + +#ifdef CONFIG_RHINE +#define DISABLE_MON_RING_MSI_CFG (1) +#endif + +#ifdef CONFIG_RHINE +#define FEATURE_IRQ_AFFINITY (1) +#endif + +#ifdef CONFIG_RHINE +#define WLAN_SOFTUMAC_SUPPORT (1) +#endif + +#ifdef CONFIG_BERYLLIUM +#define FEATURE_IRQ_AFFINITY (1) +#endif + +#ifdef CONFIG_TX_MULTIQ_PER_AC +#define TX_MULTIQ_PER_AC (1) +#endif + +#ifdef CONFIG_PCI_LINK_STATUS_SANITY +#define PCI_LINK_STATUS_SANITY (1) +#endif + +#ifdef CONFIG_DDP_MON_RSSI_IN_DBM +#define DP_MON_RSSI_IN_DBM (1) +#endif + +#ifdef CONFIG_SYSTEM_PM_CHECK +#define SYSTEM_PM_CHECK (1) +#endif + +#ifdef CONFIG_DISABLE_EAPOL_INTRABSS_FWD +#define DISABLE_EAPOL_INTRABSS_FWD (1) +#endif + +#ifdef CONFIG_TX_AGGREGATION_SIZE_ENABLE +#define TX_AGGREGATION_SIZE_ENABLE (1) +#endif + +#ifdef CONFIG_TX_MULTI_TCL +#define TX_MULTI_TCL (1) +#endif + +#ifdef CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG +#define WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG (1) +#endif + +#ifdef CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG +#define WLAN_DP_DISABLE_TCL_STATUS_SRNG (1) +#endif + +#ifdef CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE +#define DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE (1) +#endif + +#ifdef CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING +#define WLAN_DP_SRNG_USAGE_WM_TRACKING (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY +#define WLAN_FEATURE_DP_CFG_EVENT_HISTORY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_LL_MODE +#define WLAN_FEATURE_LL_MODE (1) +#endif + +#ifdef CONFIG_WLAN_CLD_PM_QOS +#define CLD_PM_QOS (1) +#endif + +#ifdef CONFIG_WLAN_CLD_DEV_PM_QOS +#define CLD_DEV_PM_QOS (1) +#endif + +#ifdef CONFIG_REO_DESC_DEFER_FREE +#define REO_DESC_DEFER_FREE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11AX +#define WLAN_FEATURE_11AX (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11AX +#define WLAN_FEATURE_11AX_BSS_COLOR (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11AX +#define SUPPORT_11AX_D3 (1) +#endif + +#ifdef CONFIG_RXDMA_ERR_PKT_DROP +#define RXDMA_ERR_PKT_DROP (1) +#endif + +#ifdef CONFIG_MAX_ALLOC_PAGE_SIZE +#define MAX_ALLOC_PAGE_SIZE (1) +#endif + +#ifdef CONFIG_DELIVERY_TO_STACK_STATUS_CHECK +#define DELIVERY_TO_STACK_STATUS_CHECK (1) +#endif + +#ifdef CONFIG_WLAN_TRACE_HIDE_SSID +#define WLAN_TRACE_HIDE_SSID (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE +#define WLAN_FEATURE_11BE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#define WLAN_FEATURE_11BE_MLO (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#define WLAN_FEATURE_11BE_MLO_ADV_FEATURE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#define WLAN_SUPPORT_11BE_D3_0 (1) +#endif + +#ifdef CONFIG_FIX_TXDMA_LIMITATION +#define FIX_TXDMA_LIMITATION (1) +#endif + +#ifdef CONFIG_FEATURE_AST +#define FEATURE_AST (1) +#endif + +#ifdef CONFIG_PEER_PROTECTED_ACCESS +#define PEER_PROTECTED_ACCESS (1) +#endif + +#ifdef CONFIG_SERIALIZE_QUEUE_SETUP +#define SERIALIZE_QUEUE_SETUP (1) +#endif + +#ifdef CONFIG_DP_RX_PKT_NO_PEER_DELIVER +#define DP_RX_PKT_NO_PEER_DELIVER (1) +#endif + +#ifdef CONFIG_DP_RX_DROP_RAW_FRM +#define DP_RX_DROP_RAW_FRM (1) +#endif + +#ifdef CONFIG_FEATURE_ALIGN_STATS_FROM_DP +#define FEATURE_ALIGN_STATS_FROM_DP (1) +#endif + +#ifdef CONFIG_DP_RX_SPECIAL_FRAME_NEED +#define DP_RX_SPECIAL_FRAME_NEED (1) +#endif + +#ifdef CONFIG_FEATURE_STATS_EXT_V2 +#define FEATURE_STATS_EXT_V2 (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER +#define WLAN_FEATURE_CAL_FAILURE_TRIGGER (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +#define WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE +#define WLAN_FEATURE_SAP_ACS_OPTIMIZE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_NO_STA_SAP_CONCURRENCY +#define WLAN_FEATURE_NO_STA_SAP_CONCURRENCY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_NO_STA_NAN_CONCURRENCY +#define WLAN_FEATURE_NO_STA_NAN_CONCURRENCY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_NO_P2P_CONCURRENCY +#define WLAN_FEATURE_NO_P2P_CONCURRENCY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY +#define WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY (1) +#endif + +#ifdef CONFIG_VERBOSE_DEBUG +#define ENABLE_VERBOSE_DEBUG (1) +#endif + +#ifdef CONFIG_RX_DESC_DEBUG_CHECK +#define RX_DESC_DEBUG_CHECK (1) +#endif + +#ifdef CONFIG_REGISTER_OP_DEBUG +#define HAL_REGISTER_WRITE_DEBUG (1) +#endif + +#ifdef CONFIG_ENABLE_QDF_PTR_HASH_DEBUG +#define ENABLE_QDF_PTR_HASH_DEBUG (1) +#endif + +#ifdef CONFIG_SM_ENG_HIST +#define SM_ENG_HIST_ENABLE (1) +#endif + +#ifdef CONFIG_FEATURE_VDEV_OPS_WAKELOCK +#define FEATURE_VDEV_OPS_WAKELOCK (1) +#endif + +#ifdef CONFIG_FEATURE_RSSI_MONITOR +#define FEATURE_RSSI_MONITOR (1) +#endif + +#ifdef CONFIG_FEATURE_BSS_TRANSITION +#define FEATURE_BSS_TRANSITION (1) +#endif + +#ifdef CONFIG_FEATURE_STATION_INFO +#define FEATURE_STATION_INFO (1) +#endif + +#ifdef CONFIG_FEATURE_TX_POWER +#define FEATURE_TX_POWER (1) +#endif + +#ifdef CONFIG_FEATURE_OTA_TEST +#define FEATURE_OTA_TEST (1) +#endif + +#ifdef CONFIG_FEATURE_ACTIVE_TOS +#define FEATURE_ACTIVE_TOS (1) +#endif + +#ifdef CONFIG_FEATURE_SAR_LIMITS +#define FEATURE_SAR_LIMITS (1) +#endif + +#ifdef CONFIG_FEATURE_CONCURRENCY_MATRIX +#define FEATURE_CONCURRENCY_MATRIX (1) +#endif + +#ifdef CONFIG_FEATURE_SAP_COND_CHAN_SWITCH +#define FEATURE_SAP_COND_CHAN_SWITCH (1) +#endif + +#ifdef CONFIG_FEATURE_WLAN_CH_AVOID_EXT +#define FEATURE_WLAN_CH_AVOID_EXT (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_MDNS_OFFLOAD +#define WLAN_FEATURE_MDNS_OFFLOAD (1) +#endif + +#ifdef CONFIG_CONVERGED_P2P_ENABLE +#ifdef CONFIG_FEATURE_P2P_LISTEN_OFFLOAD +#define FEATURE_P2P_LISTEN_OFFLOAD (1) +#endif +#endif + +#ifdef CONFIG_ANI_LEVEL_REQUEST +#define FEATURE_ANI_LEVEL_REQUEST (1) +#endif + +#ifdef CONFIG_WMI_ROAM_SUPPORT +#define WMI_ROAM_SUPPORT (1) +#endif + +#ifdef CONFIG_WMI_CONCURRENCY_SUPPORT +#define WMI_CONCURRENCY_SUPPORT (1) +#endif + +#ifdef CONFIG_WMI_STA_SUPPORT +#define WMI_STA_SUPPORT (1) +#endif + +#ifdef CONFIG_HIF_LARGE_CE_RING_HISTORY +#define HIF_CE_HISTORY_MAX (CONFIG_HIF_LARGE_CE_RING_HISTORY) +#endif + +#ifdef CONFIG_WLAN_HANG_EVENT +#define HIF_CE_LOG_INFO (1) +#endif + +#ifdef CONFIG_WLAN_HANG_EVENT +#define HIF_BUS_LOG_INFO (1) +#endif + +#ifdef CONFIG_WLAN_HANG_EVENT +#define DP_SUPPORT_RECOVERY_NOTIFY (1) +#endif + +#ifdef CONFIG_WLAN_DFS_STATIC_MEM_ALLOC +#define WLAN_DFS_STATIC_MEM_ALLOC (1) +#endif + +#ifdef CONFIG_WLAN_DFS_MASTER_ENABLE +#define MOBILE_DFS_SUPPORT (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DFS_OFFLOAD +#ifdef CONFIG_WLAN_DFS_MASTER_ENABLE +#define WLAN_DFS_FULL_OFFLOAD (1) +#endif +#else +#ifdef CONFIG_WLAN_DFS_MASTER_ENABLE +#define WLAN_DFS_PARTIAL_OFFLOAD (1) +#endif +#endif + +#ifdef CONFIG_WLAN_DFS_MASTER_ENABLE +#define DFS_COMPONENT_ENABLE (1) +#endif + +#ifdef CONFIG_WLAN_DFS_MASTER_ENABLE +#define QCA_DFS_USE_POLICY_MANAGER (1) +#endif + +#ifdef CONFIG_WLAN_DFS_MASTER_ENABLE +#define QCA_DFS_NOL_PLATFORM_DRV_SUPPORT (1) +#endif + +#ifdef CONFIG_QCA_DFS_BW_PUNCTURE +#define QCA_DFS_BW_PUNCTURE (1) +#endif + +#ifdef CONFIG_WLAN_DEBUGFS +#define WLAN_DEBUGFS (1) +#endif + +#ifdef CONFIG_WLAN_DEBUGFS +#define WLAN_DBGLOG_DEBUGFS (1) +#endif + +#ifdef CONFIG_WLAN_STREAMFS +#define WLAN_STREAMFS (1) +#endif + +#ifdef CONFIG_DYNAMIC_DEBUG +#define FEATURE_MULTICAST_HOST_FW_MSGS (1) +#endif + +#ifdef CONFIG_WLAN_CHIPSET_STATS +#define WLAN_CHIPSET_STATS (1) +#endif + +#ifdef CONFIG_ENABLE_SMMU_S1_TRANSLATION +#define ENABLE_SMMU_S1_TRANSLATION (1) +#endif + +#ifdef CONFIG_LOG_LINE_NUMBER +#define LOG_LINE_NUMBER (1) +#endif + +#ifdef CONFIG_ENABLE_MTRACE_LOG +#define ENABLE_MTRACE_LOG (1) +#endif + +#ifdef CONFIG_FUNC_CALL_MAP +#define FUNC_CALL_MAP (1) +#endif + +#ifdef CONFIG_ADAPTIVE_11R +#define WLAN_ADAPTIVE_11R (1) +#endif + +#ifdef CONFIG_SAE_SINGLE_PMK +#define WLAN_SAE_SINGLE_PMK (1) +#endif + +#ifdef CONFIG_MULTI_CLIENT_LL_SUPPORT +#define MULTI_CLIENT_LL_SUPPORT (1) +#endif + +#ifdef CONFIG_WLAN_VENDOR_HANDOFF_CONTROL +#define WLAN_VENDOR_HANDOFF_CONTROL (1) +#endif + +#ifdef CONFIG_FEATURE_MSCS +#define WLAN_FEATURE_MSCS (1) +#endif + +#ifdef CONFIG_WLAN_NUD_TRACKING +#define WLAN_NUD_TRACKING (1) +#endif + +#ifdef CONFIG_DISABLE_CHANNEL_LIST +#define DISABLE_CHANNEL_LIST (1) +#endif + +#ifdef CONFIG_WLAN_BCN_RECV_FEATURE +#define WLAN_BCN_RECV_FEATURE (1) +#endif + +#ifdef CONFIG_FW_THERMAL_THROTTLE +#define FW_THERMAL_THROTTLE (1) +#endif + +#ifdef CONFIG_LTE_COEX +#define LTE_COEX (1) +#endif + +#ifdef CONFIG_HOST_OPCLASS +#define HOST_OPCLASS (1) +#endif + +#ifdef CONFIG_HOST_OPCLASS +#define HOST_OPCLASS_EXT (1) +#endif + +#ifdef CONFIG_TARGET_11D_SCAN +#define TARGET_11D_SCAN (1) +#endif + +#ifdef CONFIG_SAP_AVOID_ACS_FREQ_LIST +#define SAP_AVOID_ACS_FREQ_LIST (1) +#endif + +#ifdef CONFIG_WLAN_DYNAMIC_CVM +#define FEATURE_WLAN_DYNAMIC_CVM (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_FW_STATE +#define FEATURE_FW_STATE (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_COEX_CONFIG +#define FEATURE_COEX_CONFIG (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_MPTA_HELPER +#define FEATURE_MPTA_HELPER (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_HW_CAPABILITY +#define FEATURE_HW_CAPABILITY (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_BTC_CHAIN_MODE +#define FEATURE_BTC_CHAIN_MODE (1) +#endif + +#ifdef CONFIG_DATA_CE_SW_INDEX_NO_INLINE_UPDATE +#define DATA_CE_SW_INDEX_NO_INLINE_UPDATE (1) +#endif + +#ifdef CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC +#define RX_DESC_MULTI_PAGE_ALLOC (1) +#endif + +#ifdef CONFIG_SAR_SAFETY_FEATURE +#define SAR_SAFETY_FEATURE (1) +#endif + +#ifdef CONFIG_CONNECTION_ROAMING_CFG +#define CONNECTION_ROAMING_CFG (1) +#endif + +#ifdef CONFIG_FEATURE_SET +#define FEATURE_SET (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ +#define WLAN_FEATURE_NEAR_FULL_IRQ (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY +#define WLAN_FEATURE_DP_EVENT_HISTORY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY +#define WLAN_FEATURE_DP_RX_RING_HISTORY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY +#define WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY +#define WLAN_FEATURE_DP_TX_DESC_HISTORY (1) +#endif + +#ifdef CONFIG_REO_QDESC_HISTORY +#define REO_QDESC_HISTORY (1) +#endif + +#ifdef CONFIG_DP_TX_HW_DESC_HISTORY +#define DP_TX_HW_DESC_HISTORY (1) +#endif + +#ifdef CONFIG_QDF_NBUF_HISTORY_SIZE +#define QDF_NBUF_HISTORY_SIZE (CONFIG_QDF_NBUF_HISTORY_SIZE) +#endif + +#ifdef CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG +#define WLAN_DP_PER_RING_TYPE_CONFIG (1) +#endif + +#ifdef CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG +#define WLAN_CE_INTERRUPT_THRESHOLD_CONFIG (1) +#endif + +#ifdef CONFIG_SAP_DHCP_FW_IND +#define SAP_DHCP_FW_IND (1) +#endif + +#ifdef CONFIG_WLAN_DP_PENDING_MEM_FLUSH +#define WLAN_DP_PENDING_MEM_FLUSH (1) +#endif + +#ifdef CONFIG_WLAN_SUPPORT_DATA_STALL +#define WLAN_SUPPORT_DATA_STALL (1) +#endif + +#ifdef CONFIG_WLAN_SUPPORT_TXRX_HL_BUNDLE +#define WLAN_SUPPORT_TXRX_HL_BUNDLE (1) +#endif + +#ifdef CONFIG_QCN7605_PCIE_SHADOW_REG_SUPPORT +#define QCN7605_PCIE_SHADOW_REG_SUPPORT (1) +#endif + +#ifdef CONFIG_QCN7605_PCIE_GOLBAL_RESET_SUPPORT +#define QCN7605_PCIE_GOLBAL_RESET_SUPPORT (1) +#endif + +#ifdef CONFIG_MARK_ICMP_REQ_TO_FW +#define WLAN_DP_FEATURE_MARK_ICMP_REQ_TO_FW (1) +#endif + +#ifdef CONFIG_EMULATION_2_0 +#define CONFIG_KIWI_EMULATION_2_0 (1) +#endif + +#ifdef CONFIG_WLAN_SKIP_BAR_UPDATE +#define WLAN_SKIP_BAR_UPDATE (1) +#endif + +#ifdef CONFIG_WLAN_TRACEPOINTS +#define WLAN_TRACEPOINTS (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_SON +#define FEATURE_PERPKT_INFO (1) +#endif + +#ifdef CONFIG_QCACLD_FEATURE_SON +#define QCA_ENHANCED_STATS_SUPPORT (1) +#endif + +#ifdef CONFIG_QMI_COMPONENT_ENABLE +#define QMI_COMPONENT_ENABLE (1) +#ifdef CONFIG_QMI_WFDS +#define QMI_WFDS (1) +#endif +#endif +#if defined(CONFIG_MAX_LOGS_PER_SEC) && defined(CONFIG_ENABLE_MAX_LOGS_PER_SEC) +#define WLAN_MAX_LOGS_PER_SEC (CONFIG_MAX_LOGS_PER_SEC) +#endif + +#ifdef CONFIG_NON_QC_PLATFORM +#define WLAN_DUMP_LOG_BUF_CNT (CONFIG_DUMP_LOG_BUF_CNT) +#endif + +#if defined(CONFIG_SCHED_HISTORY_SIZE) && \ + defined(CONFIG_ENABLE_SCHED_HISTORY_SIZE) +#define WLAN_SCHED_HISTORY_SIZE (CONFIG_SCHED_HISTORY_SIZE) +#endif + +#ifdef CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE +#define DP_LEGACY_MODE_CSM_DEFAULT_DISABLE (CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE) +#endif + +#ifdef CONFIG_HANDLE_RX_REROUTE_ERR +#define HANDLE_RX_REROUTE_ERR (1) +#endif + +#ifdef CONFIG_CFG_NUM_DP_TRACE_RECORD +#define MAX_QDF_DP_TRACE_RECORDS (CONFIG_CFG_NUM_DP_TRACE_RECORD) +#endif + +#ifdef CONFIG_CFG_NUM_HTC_CREDIT_HISTORY +#define HTC_CREDIT_HISTORY_MAX (CONFIG_CFG_NUM_HTC_CREDIT_HISTORY) +#endif + +#ifdef CONFIG_CFG_NUM_WMI_EVENT_HISTORY +#define WMI_EVENT_DEBUG_MAX_ENTRY (CONFIG_CFG_NUM_WMI_EVENT_HISTORY) +#endif + +#ifdef CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY +#define WMI_MGMT_EVENT_DEBUG_MAX_ENTRY (CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY) +#endif + +#ifdef CONFIG_CFG_NUM_TX_RX_HISTOGRAM +#define NUM_TX_RX_HISTOGRAM (CONFIG_CFG_NUM_TX_RX_HISTOGRAM) +#endif + +#ifdef CONFIG_CFG_NUM_RX_IND_RECORD +#define OL_RX_INDICATION_MAX_RECORDS (CONFIG_CFG_NUM_RX_IND_RECORD) +#endif + +#ifdef CONFIG_CFG_NUM_ROAM_DEBUG_RECORD +#define WLAN_ROAM_DEBUG_MAX_REC (CONFIG_CFG_NUM_ROAM_DEBUG_RECORD) +#endif + +#ifdef CONFIG_CFG_PMO_WOW_FILTERS_MAX +#define PMO_WOW_FILTERS_MAX (CONFIG_CFG_PMO_WOW_FILTERS_MAX) +#endif + +#ifdef CONFIG_CFG_GTK_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV (CONFIG_CFG_GTK_OFFLOAD_MAX_VDEV) +#endif + +#ifdef CONFIG_TGT_NUM_MSDU_DESC +#define CFG_TGT_NUM_MSDU_DESC (CONFIG_TGT_NUM_MSDU_DESC) +#endif + +#ifdef CONFIG_HTC_MAX_MSG_PER_BUNDLE_TX +#define CFG_HTC_MAX_MSG_PER_BUNDLE_TX (CONFIG_HTC_MAX_MSG_PER_BUNDLE_TX) +#endif + +#ifdef CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV (CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV) +#endif + +#ifdef CONFIG_WLAN_UMAC_MLO_MAX_DEV +#define WLAN_UMAC_MLO_MAX_DEV (CONFIG_WLAN_UMAC_MLO_MAX_DEV) +#endif + +#ifdef CONFIG_CFG_ROAM_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV (CONFIG_CFG_ROAM_OFFLOAD_MAX_VDEV) +#endif + +#ifdef CONFIG_CFG_MAX_PERIODIC_TX_PTRNS +#define MAXNUM_PERIODIC_TX_PTRNS (CONFIG_CFG_MAX_PERIODIC_TX_PTRNS) +#endif + +#ifdef CONFIG_CFG_MAX_STA_VDEVS +#define CFG_TGT_DEFAULT_MAX_STA_VDEVS (CONFIG_CFG_MAX_STA_VDEVS) +#endif + +#ifdef CONFIG_CFG_NUM_OF_ADDITIONAL_FW_PEERS +#define NUM_OF_ADDITIONAL_FW_PEERS (CONFIG_CFG_NUM_OF_ADDITIONAL_FW_PEERS) +#endif + +#ifdef CONFIG_CFG_NUM_OF_TDLS_CONN_TABLE_ENTRIES +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES (CONFIG_CFG_NUM_OF_TDLS_CONN_TABLE_ENTRIES) +#endif + +#ifdef CONFIG_CFG_TGT_AST_SKID_LIMIT +#define CFG_TGT_AST_SKID_LIMIT (CONFIG_CFG_TGT_AST_SKID_LIMIT) +#endif + +#ifdef CONFIG_TX_RESOURCE_HIGH_TH_IN_PER +#define TX_RESOURCE_HIGH_TH_IN_PER (CONFIG_TX_RESOURCE_HIGH_TH_IN_PER) +#endif + +#ifdef CONFIG_TX_RESOURCE_LOW_TH_IN_PER +#define TX_RESOURCE_LOW_TH_IN_PER (CONFIG_TX_RESOURCE_LOW_TH_IN_PER) +#endif + +#ifndef CONFIG_WLAN_MAX_PSOCS +#define CONFIG_WLAN_MAX_PSOCS (1) +#endif +#define WLAN_MAX_PSOCS (CONFIG_WLAN_MAX_PSOCS) + +#ifndef CONFIG_WLAN_MAX_PDEVS +#define CONFIG_WLAN_MAX_PDEVS (1) +#endif +#define WLAN_MAX_PDEVS (CONFIG_WLAN_MAX_PDEVS) + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#ifndef CONFIG_WLAN_MAX_ML_VDEVS +#define CONFIG_WLAN_MAX_ML_VDEVS (3) +#endif +#else +#ifndef CONFIG_WLAN_MAX_ML_VDEVS +#define CONFIG_WLAN_MAX_ML_VDEVS (0) +#endif +#endif + +#define WLAN_MAX_ML_VDEVS (CONFIG_WLAN_MAX_ML_VDEVS) + +#ifndef CONFIG_WLAN_MAX_VDEVS +#define CONFIG_WLAN_MAX_VDEVS (6) +#endif +#define WLAN_MAX_VDEVS (CONFIG_WLAN_MAX_VDEVS) + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#ifndef CONFIG_WLAN_MAX_MLD +#define CONFIG_WLAN_MAX_MLD (2) +#endif +#else +#ifndef CONFIG_WLAN_MAX_MLD +#define CONFIG_WLAN_MAX_MLD (1) +#endif +#endif + +#define WLAN_MAX_MLD (CONFIG_WLAN_MAX_MLD) + +#ifdef CONFIG_SIR_SAP_MAX_NUM_PEERS +#ifndef CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP +#define CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP (CONFIG_SIR_SAP_MAX_NUM_PEERS) +#endif +#else +#ifndef CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP +#define CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP (32) +#endif +#endif + +#ifndef WLAN_SER_MAX_PENDING_CMDS_AP +#define WLAN_SER_MAX_PENDING_CMDS_AP (CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP + 3) +#endif + +#ifndef CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA +#define CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA (4) +#endif +#define WLAN_SER_MAX_PENDING_CMDS_STA (CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA) + +#ifndef CONFIG_WLAN_MAX_PENDING_CMDS +#define CONFIG_WLAN_MAX_PENDING_CMDS (CONFIG_WLAN_SER_MAX_PENDING_CMDS_AP * 3 + CONFIG_WLAN_SER_MAX_PENDING_CMDS_STA * 2) +#endif +#define WLAN_SER_MAX_PENDING_CMDS (CONFIG_WLAN_MAX_PENDING_CMDS) + +#ifndef CONFIG_WLAN_PDEV_MAX_VDEVS +#define CONFIG_WLAN_PDEV_MAX_VDEVS (CONFIG_WLAN_MAX_VDEVS) +#endif +#define WLAN_PDEV_MAX_VDEVS (CONFIG_WLAN_PDEV_MAX_VDEVS) + +#ifndef CONFIG_WLAN_PSOC_MAX_VDEVS +#define CONFIG_WLAN_PSOC_MAX_VDEVS (CONFIG_WLAN_MAX_VDEVS) +#endif +#define WLAN_PSOC_MAX_VDEVS (CONFIG_WLAN_PSOC_MAX_VDEVS) + +#ifndef CONFIG_MAX_SCAN_CACHE_SIZE +#define CONFIG_MAX_SCAN_CACHE_SIZE (500) +#endif +#define MAX_SCAN_CACHE_SIZE (CONFIG_MAX_SCAN_CACHE_SIZE) + +#ifndef CONFIG_SCAN_MAX_REST_TIME +#define CONFIG_SCAN_MAX_REST_TIME (0) +#endif +#define SCAN_MAX_REST_TIME (CONFIG_SCAN_MAX_REST_TIME) + +#ifndef CONFIG_SCAN_MIN_REST_TIME +#define CONFIG_SCAN_MIN_REST_TIME (0) +#endif +#define SCAN_MIN_REST_TIME (CONFIG_SCAN_MIN_REST_TIME) + +#ifndef CONFIG_SCAN_BURST_DURATION +#define CONFIG_SCAN_BURST_DURATION (0) +#endif +#define SCAN_BURST_DURATION (CONFIG_SCAN_BURST_DURATION) + +#ifndef CONFIG_SCAN_PROBE_SPACING_TIME +#define CONFIG_SCAN_PROBE_SPACING_TIME (0) +#endif +#define SCAN_PROBE_SPACING_TIME (CONFIG_SCAN_PROBE_SPACING_TIME) + +#ifndef CONFIG_SCAN_PROBE_DELAY +#define CONFIG_SCAN_PROBE_DELAY (0) +#endif +#define SCAN_PROBE_DELAY (CONFIG_SCAN_PROBE_DELAY) + +#ifndef CONFIG_SCAN_MAX_SCAN_TIME +#define CONFIG_SCAN_MAX_SCAN_TIME (30000) +#endif +#define SCAN_MAX_SCAN_TIME (CONFIG_SCAN_MAX_SCAN_TIME) + +#ifndef CONFIG_SCAN_NETWORK_IDLE_TIMEOUT +#define CONFIG_SCAN_NETWORK_IDLE_TIMEOUT (0) +#endif +#define SCAN_NETWORK_IDLE_TIMEOUT (CONFIG_SCAN_NETWORK_IDLE_TIMEOUT) + +#ifndef CONFIG_HIDDEN_SSID_TIME +#define CONFIG_HIDDEN_SSID_TIME (0xFFFFFFFF) +#endif +#define HIDDEN_SSID_TIME (CONFIG_HIDDEN_SSID_TIME) + +#ifndef CONFIG_SCAN_CHAN_STATS_EVENT_ENAB +#define CONFIG_SCAN_CHAN_STATS_EVENT_ENAB (false) +#endif +#define SCAN_CHAN_STATS_EVENT_ENAB (CONFIG_SCAN_CHAN_STATS_EVENT_ENAB) + +#ifndef CONFIG_MAX_BCN_PROBE_IN_SCAN_QUEUE +#define CONFIG_MAX_BCN_PROBE_IN_SCAN_QUEUE (150) +#endif +#define MAX_BCN_PROBE_IN_SCAN_QUEUE (CONFIG_MAX_BCN_PROBE_IN_SCAN_QUEUE) + +#ifndef CONFIG_RX_DIAG_WQ_MAX_SIZE +#define CONFIG_RX_DIAG_WQ_MAX_SIZE (1000) +#endif +#define RX_DIAG_WQ_MAX_SIZE (CONFIG_RX_DIAG_WQ_MAX_SIZE) + +#ifndef CONFIG_MGMT_DESC_POOL_MAX +#define CONFIG_MGMT_DESC_POOL_MAX (64) +#endif +#define MGMT_DESC_POOL_MAX (CONFIG_MGMT_DESC_POOL_MAX) + +#ifdef CONFIG_SIR_SAP_MAX_NUM_PEERS +#define SIR_SAP_MAX_NUM_PEERS (CONFIG_SIR_SAP_MAX_NUM_PEERS) +#endif + +#ifdef CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV (CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV) +#endif + +#ifdef CONFIG_LIMIT_IPA_TX_BUFFER +#define LIMIT_IPA_TX_BUFFER (CONFIG_LIMIT_IPA_TX_BUFFER) +#endif + +#ifdef CONFIG_LOCK_STATS_ON +#define QDF_LOCK_STATS (1) +#define QDF_LOCK_STATS_DESTROY_PRINT (0) +#ifndef CONFIG_ARCH_SDXPRAIRIE +#define QDF_LOCK_STATS_BUG_ON (1) +#endif +#ifdef CONFIG_VCPU_TIMESTOLEN +#define VCPU_TIMESTOLEN (1) +#endif +#define QDF_LOCK_STATS_LIST (1) +#define QDF_LOCK_STATS_LIST_SIZE (256) +#endif +#ifdef CONFIG_FW_THERMAL_THROTTLE +#define FW_THERMAL_THROTTLE_SUPPORT (1) +#endif + +#ifdef CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER +#define FEATURE_RX_LINKSPEED_ROAM_TRIGGER (1) +#endif + +#ifdef CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER +#define DP_RATETABLE_SUPPORT (1) +#endif + +#ifdef CONFIG_6G_SCAN_CHAN_SORT_ALGO +#define FEATURE_6G_SCAN_CHAN_SORT_ALGO (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE +#define WLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE (1) +#endif + +#ifdef CONFIG_RX_FISA +#define WLAN_SUPPORT_RX_FISA (1) +#endif + +#ifdef CONFIG_RX_FISA_HISTORY +#define WLAN_SUPPORT_RX_FISA_HIST (1) +#endif + +#ifdef CONFIG_DP_SWLM +#define WLAN_DP_FEATURE_SW_LATENCY_MGR (1) +#endif + +#ifdef CONFIG_RX_DEFRAG_DO_NOT_REINJECT +#define RX_DEFRAG_DO_NOT_REINJECT (1) +#endif + +#ifdef CONFIG_HANDLE_BC_EAP_TX_FRM +#define HANDLE_BROADCAST_EAPOL_TX_FRAME (1) +#endif + +#ifdef CONFIG_HASTINGS_BT_WAR +#define HASTINGS_BT_WAR (1) +#endif + +#ifdef CONFIG_HIF_DEBUG +#define HIF_CONFIG_SLUB_DEBUG_ON (1) +#endif + +#ifdef CONFIG_HAL_DEBUG +#define HAL_CONFIG_SLUB_DEBUG_ON (1) +#endif + +#ifdef CONFIG_FOURTH_CONNECTION +#define FEATURE_FOURTH_CONNECTION (1) +#endif + +#ifdef CONFIG_FOURTH_CONNECTION_AUTO +#define FOURTH_CONNECTION_AUTO (1) +#endif + +#ifdef CONFIG_WMI_SEND_RECV_QMI +#define WLAN_FEATURE_WMI_SEND_RECV_QMI (1) +#endif + +#ifdef CONFIG_WDI3_STATS_UPDATE +#define WDI3_STATS_UPDATE (1) +#endif + +#ifdef CONFIG_WDI3_STATS_BW_MONITOR +#define WDI3_STATS_BW_MONITOR (1) +#endif + +#ifdef CONFIG_IPA_P2P_SUPPORT +#define IPA_P2P_SUPPORT (1) +#endif + +#ifdef CONFIG_WLAN_CUSTOM_DSCP_UP_MAP +#define WLAN_CUSTOM_DSCP_UP_MAP (1) +#endif + +#ifdef CONFIG_WLAN_SEND_DSCP_UP_MAP_TO_FW +#define WLAN_SEND_DSCP_UP_MAP_TO_FW (1) +#endif + +#ifdef CONFIG_HIF_CPU_PERF_AFFINE_MASK +#define HIF_CPU_PERF_AFFINE_MASK (1) +#endif + +#ifdef CONFIG_HIF_CPU_CLEAR_AFFINITY +#define HIF_CPU_CLEAR_AFFINITY (1) +#endif + +#ifdef CONFIG_GENERIC_SHADOW_REGISTER_ACCESS_ENABLE +#define GENERIC_SHADOW_REGISTER_ACCESS_ENABLE (1) +#endif + +#ifdef CONFIG_IPA_SET_RESET_TX_DB_PA +#define IPA_SET_RESET_TX_DB_PA (1) +#endif + +#ifdef CONFIG_DEVICE_FORCE_WAKE_ENABLE +#define DEVICE_FORCE_WAKE_ENABLE (1) +#endif + +#ifdef CONFIG_WINDOW_REG_PLD_LOCK_ENABLE +#define WINDOW_REG_PLD_LOCK_ENABLE (1) +#endif + +#ifdef CONFIG_DUMP_REO_QUEUE_INFO_IN_DDR +#define DUMP_REO_QUEUE_INFO_IN_DDR (1) +#endif + +#ifdef CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK +#define DP_RX_REFILL_CPU_PERF_AFFINE_MASK (1) +#endif + +#ifdef CONFIG_MAX_CLIENTS_ALLOWED +#define WLAN_MAX_CLIENTS_ALLOWED (CONFIG_MAX_CLIENTS_ALLOWED) +#endif + +#ifdef CONFIG_WLAN_FEATURE_RX_BUFFER_POOL +#define WLAN_FEATURE_RX_PREALLOC_BUFFER_POOL (1) +#ifdef CONFIG_DP_RX_BUFFER_POOL_SIZE +#define DP_RX_BUFFER_POOL_SIZE (CONFIG_DP_RX_BUFFER_POOL_SIZE) +#endif +#ifdef CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES +#define DP_RX_BUFFER_POOL_ALLOC_THRES (CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES) +#endif +#ifdef CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE +#define DP_RX_REFILL_BUFF_POOL_SIZE (CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE) +#endif +#ifdef CONFIG_DP_RX_REFILL_THRD_THRESHOLD +#define DP_RX_REFILL_THRD_THRESHOLD (CONFIG_DP_RX_REFILL_THRD_THRESHOLD) +#endif +#endif +#ifdef CONFIG_DP_FT_LOCK_HISTORY +#define DP_FT_LOCK_HISTORY (1) +#endif + +#ifdef CONFIG_INTRA_BSS_FWD_OFFLOAD +#define INTRA_BSS_FWD_OFFLOAD (1) +#endif + +#ifdef CONFIG_GET_DRIVER_MODE +#define FEATURE_GET_DRIVER_MODE (1) +#endif + +#ifdef CONFIG_FEATURE_IPA_PIPE_CHANGE_WDI1 +#define FEATURE_IPA_PIPE_CHANGE_WD (1) +#endif + +#ifdef CONFIG_WLAN_BOOTUP_MARKER +#define WLAN_BOOTUP_MARKER (1) +#endif + +#ifdef CONFIG_WLAN_PLACEMARKER_PREFIX +#define WLAN_PLACEMARKER_PREFIX (CONFIG_WLAN_PLACEMARKER_PREFIX) +#endif + +#ifdef CONFIG_FEATURE_STA_MODE_VOTE_LINK +#define FEATURE_STA_MODE_VOTE_LINK (1) +#endif + +#ifdef CONFIG_WLAN_ENABLE_GPIO_WAKEUP +#define WLAN_ENABLE_GPIO_WAKEUP (1) +#endif + +#ifdef CONFIG_WLAN_MAC_ADDR_UPDATE_DISABLE +#define WLAN_MAC_ADDR_UPDATE_DISABLE (1) +#endif + +#ifdef CONFIG_SMP +#ifdef CONFIG_HIF_DETECTION_LATENCY_ENABLE +#define HIF_DETECTION_LATENCY_ENABLE (1) +#define DETECTION_TIMER_TIMEOUT (4000) +#define DETECTION_LATENCY_THRESHOLD (3900) +#endif +#endif +#ifdef CONFIG_FEATURE_WDS +#define FEATURE_WDS (1) +#endif + +#ifdef CONFIG_FEATURE_MEC +#define FEATURE_MEC (1) +#endif + +#ifdef CONFIG_FEATURE_MCL_REPEATER +#define FEATURE_MCL_REPEATER (1) +#endif + +#ifdef CONFIG_WDS_CONV_TARGET_IF_OPS_ENABLE +#define WDS_CONV_TARGET_IF_OPS_ENABLE (1) +#endif + +#ifdef CONFIG_BYPASS_WDS_OL_OPS +#define BYPASS_OL_OPS (1) +#endif + +#ifdef CONFIG_IPA_WDI3_TX_TWO_PIPES +#define IPA_WDI3_TX_TWO_PIPES (1) +#endif + +#ifdef CONFIG_DP_TX_TRACKING +#define DP_TX_TRACKING (1) +#endif + +#ifdef CONFIG_CHIP_VERSION +#define CHIP_VERSION (CONFIG_CHIP_VERSION) +#endif + +#ifdef CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET +#define WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET (1) +#endif + +#ifdef CONFIG_SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND +#define SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_MCC_QUOTA +#define WLAN_FEATURE_MCC_QUOTA (1) +#ifdef CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA +#define WLAN_MCC_MIN_CHANNEL_QUOTA (CONFIG_WLAN_MCC_MIN_CHANNEL_QUOTA) +#endif +#endif +#ifdef CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +#define WLAN_FEATURE_PEER_TXQ_FLUSH_CONF (1) +#endif + +#ifdef CONFIG_DP_HW_TX_DELAY_STATS_ENABLE +#define HW_TX_DELAY_STATS_ENABLE (1) +#endif + +#ifdef CONFIG_CNSS_HW_SECURE_DISABLE +#define FEATURE_CNSS_HW_SECURE_DISABLE (1) +#endif + +#ifdef CONFIG_FEATURE_COEX +#ifdef CONFIG_WLAN_FEATURE_COEX_DBAM +#define WLAN_FEATURE_DBAM_CONFIG (1) +#endif +#endif + +#ifdef CONFIG_WLAN_FEATURE_COAP +#define WLAN_FEATURE_COAP (1) +#endif + +#ifdef CONFIG_CNSS2_SSR_DRIVER_DUMP +#define WLAN_FEATURE_SSR_DRIVER_DUMP (1) +#endif + +#ifdef CONFIG_WLAN_CTRL_NAME +#define WLAN_CTRL_NAME (CONFIG_WLAN_CTRL_NAME) +#endif + +#ifdef CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST +#define ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST +#endif + +#if defined(CONFIG_LITHIUM) || defined(CONFIG_BERYLLIUM) +#ifdef CONFIG_QCOM_TDLS +#define TDLS_WOW_ENABLED (1) +#endif +#endif + +#ifdef CONFIG_MORE_TX_DESC +#define TX_TO_NPEERS_INC_TX_DESCS +#endif + +#ifdef CONFIG_WLAN_HOST_ARCH_ARM +#define WLAN_HOST_ARCH_ARM (1) +#else +#define WLAN_HOST_ARCH_ARM (0) +#endif + +#ifdef CONFIG_PANIC_ON_BUG +#define PANIC_ON_BUG (1) +#endif + +#ifdef CONFIG_WLAN_WARN_ON_ASSERT +#define WLAN_WARN_ON_ASSERT (1) +#endif + +#ifdef CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE +#define WLAN_FEATURE_LOCAL_PKT_CAPTURE (1) +#endif + +#ifdef CONFIG_WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0 +#define WLAN_PKT_CAPTURE_TX_2_0 (1) +#define WLAN_TX_PKT_CAPTURE_ENH_BE (1) +#define QDF_FRAG_CACHE_SUPPORT (1) +#endif + +#ifdef CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP +#define DP_TX_PACKET_INSPECT_FOR_ILP (1) +#endif + +#ifdef CONFIG_NUM_SOC_PERF_CLUSTER +#define NUM_SOC_PERF_CLUSTER (CONFIG_NUM_SOC_PERF_CLUSTER) +#endif + +#ifdef CONFIG_WLAN_OPEN_SOURCE +#define WLAN_OPEN_SOURCE (1) +#endif + +#ifdef CONFIG_DP_MULTIPASS_SUPPORT +#define QCA_MULTIPASS_SUPPORT (1) +#define WLAN_REPEATER_NOT_SUPPORTED (1) +#define QCA_SUPPORT_PEER_ISOLATION (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_LL_LT_SAP +#define WLAN_FEATURE_LL_LT_SAP (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_AFFINITY_MGR +#define WLAN_FEATURE_AFFINITY_MGR (1) +#endif + +#ifdef CONFIG_WLAN_DP_VDEV_NO_SELF_PEER +#define WLAN_DP_VDEV_NO_SELF_PEER (1) +#endif + +#ifdef CONFIG_NL80211_EXT_FEATURE_PUNCT_SUPPORT +#define NL80211_EXT_FEATURE_PUNCT_SUPPORT (1) +#endif + +#ifdef CONFIG_DP_MLO_LINK_STATS_SUPPORT +#define DP_MLO_LINK_STATS_SUPPORT (1) +#endif + +#ifdef CONFIG_MULTI_IF_NAME +#define MULTI_IF_NAME CONFIG_MULTI_IF_NAME +#endif + +#ifdef CONFIG_FEATURE_HIF_DELAYED_REG_WRITE +#define FEATURE_HIF_DELAYED_REG_WRITE (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#ifndef CONFIG_WLAN_MAX_ML_DEFAULT_LINK +#define CONFIG_WLAN_MAX_ML_DEFAULT_LINK (2) +#endif +#else +#ifndef CONFIG_WLAN_MAX_ML_DEFAULT_LINK +#define CONFIG_WLAN_MAX_ML_DEFAULT_LINK (1) +#endif +#endif + +#ifdef CONFIG_WLAN_MAX_ML_DEFAULT_LINK +#define WLAN_MAX_ML_DEFAULT_LINK CONFIG_WLAN_MAX_ML_DEFAULT_LINK +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#ifndef CONFIG_WLAN_DEFAULT_REC_LINK_VALUE +#define CONFIG_WLAN_DEFAULT_REC_LINK_VALUE (2) +#endif +#else +#ifndef CONFIG_WLAN_DEFAULT_REC_LINK_VALUE +#define CONFIG_WLAN_DEFAULT_REC_LINK_VALUE (2) +#endif +#endif + +#ifdef CONFIG_WLAN_DEFAULT_REC_LINK_VALUE +#define WLAN_DEFAULT_REC_LINK_VALUE CONFIG_WLAN_DEFAULT_REC_LINK_VALUE +#endif + +#ifdef CONFIG_WLAN_FEATURE_11BE_MLO +#ifndef CONFIG_WLAN_MAX_ML_BSS_LINKS +#define CONFIG_WLAN_MAX_ML_BSS_LINKS (3) +#endif +#else +#ifndef CONFIG_WLAN_MAX_ML_BSS_LINKS +#define CONFIG_WLAN_MAX_ML_BSS_LINKS (1) +#endif +#endif + +#ifdef CONFIG_WLAN_MAX_ML_BSS_LINKS +#define WLAN_MAX_ML_BSS_LINKS CONFIG_WLAN_MAX_ML_BSS_LINKS +#endif + +#if defined(CONFIG_WLAN_FEATURE_11BE_MLO) && defined(CONFIG_WLAN_FEATURE_EMLSR) +#ifndef CONFIG_WLAN_EMLSR_ENABLE +#define CONFIG_WLAN_EMLSR_ENABLE (1) +#endif +#else +#ifndef CONFIG_WLAN_EMLSR_ENABLE +#define CONFIG_WLAN_EMLSR_ENABLE (0) +#endif +#endif + +#ifdef CONFIG_WLAN_EMLSR_ENABLE +#define WLAN_EMLSR_ENABLE CONFIG_WLAN_EMLSR_ENABLE +#endif + +#ifdef CONFIG_WALT_GET_CPU_TAKEN_SUPPORT +#define WALT_GET_CPU_TAKEN_SUPPORT (1) +#endif + +#ifdef CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +#define WLAN_HDD_MULTI_VDEV_SINGLE_NDEV (1) +#endif + +#ifdef CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE +#define WLAN_FEATURE_CE_RX_BUFFER_REUSE (1) +#endif + +#ifndef CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE +#define WLAN_TRACE_HIDE_MAC_ADDRESS (1) +#endif + +#ifdef CONFIG_ENABLE_HAL_REG_WR_HISTORY +#define ENABLE_HAL_REG_WR_HISTORY (1) +#endif + +#ifdef CONFIG_BCN_RATECODE_ENABLE +#define WLAN_BCN_RATECODE_ENABLE (1) +#endif + +#ifdef CONFIG_QDF_TIMER_MULTIPLIER_FRAC_ENABLE +#ifdef CONFIG_QDF_TIMER_MULTIPLIER_FRAC +#define QDF_TIMER_MULTIPLIER_FRAC CONFIG_QDF_TIMER_MULTIPLIER_FRAC +#endif +#endif + +#ifdef CONFIG_DP_RX_MSDU_DONE_FAIL_HISTORY +#define DP_RX_MSDU_DONE_FAIL_HISTORY (1) +#endif + +#ifdef CONFIG_DP_RX_PEEK_MSDU_DONE_WAR +#define DP_RX_PEEK_MSDU_DONE_WAR (1) +#endif + +#ifdef CONFIG_QDF_MAX_NO_OF_SAP_MODE +#define QDF_MAX_NO_OF_SAP_MODE CONFIG_QDF_MAX_NO_OF_SAP_MODE +#endif + +#ifdef CONFIG_LL_DP_SUPPORT_LEGACY +#define LL_DP_SUPPORT_LEGACY (1) +#endif +#endif /* CONFIG_TO_FEATURE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/default_config.h b/qcom/opensource/wlan/qcacld-3.0/configs/default_config.h new file mode 100644 index 0000000000..042dad5602 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/default_config.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define ALL_POSSIBLE_RATES_SUPPORTED 1 +#define ANI_OS_TYPE_ANDROID 6 +#define ATH_SUPPORT_WRAP 0 +#define CHECK_REG_PHYMODE 1 +#define CONFIG_CHAN_FREQ_API 1 +#define CONFIG_CHAN_NUM_API 1 +#define CONFIG_FW_LOGS_BASED_ON_INI 1 +#define CONFIG_REG_6G_PWRMODE 1 +#define CONN_MGR_ADV_FEATURE 1 +#define CRYPTO_SET_KEY_CONVERGED 1 +#define DP_CON_MON 1 +#define DP_FLOW_CTL 1 +#define DP_INTR_POLL_BOTH 1 +#define DP_INVALID_PEER_ASSERT 1 +#define DP_MOB_DEFS 1 +#define DP_PEER_EXTENDED_API 1 +#define DP_POWER_SAVE 1 +#define DP_PRINT_ENABLE 0 +#define DP_PRINT_NO_CONSOLE 1 +#define FEATURE_NBUFF_REPLENISH_TIMER 1 +#define IRQ_DISABLED_MAX_DURATION_NS 100000000 +#define LOG_DEL_OBJ_DESTROY_DURATION_SEC 4 +#define LOG_DEL_OBJ_TIMEOUT_VALUE_MSEC 4000 +#define MWS_COEX 1 +#define PCIE_REG_WINDOW_LOCAL_NO_CACHE 1 +#define PEER_CACHE_RX_PKTS 1 +#define QCA_HOST2FW_RXBUF_RING 1 +#define QCA_HT_2040_COEX 1 +#define QCA_SUPPORT_TXRX_LOCAL_PEER_ID 1 +#define SCHEDULER_CORE_MAX_MESSAGES 1000 +#define SERIALIZE_VDEV_RESP 1 +#define SERIALIZE_WMI_RX_EXECUTION_CTX 1 +#define TGT_IF_VDEV_MGR_CONV 1 +#define WLAN_CONV_CRYPTO_SUPPORTED 1 +#define WLAN_CRYPTO_CCMP_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_FILS_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_GCMP_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_GCM_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_OMAC1_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_TKIP_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_WAPI_OS_DERIVATIVE 1 +#define WLAN_CRYPTO_WEP_OS_DERIVATIVE 1 +#define WLAN_FEATURE_INTERFACE_MGR 1 +#define WLAN_FEATURE_P2P 1 +#define WLAN_FEATURE_WFD 1 +#define WLAN_OBJMGR_RATELIMIT_THRESH 0 +#define WLAN_REG_PARTIAL_OFFLOAD 1 +#define WLAN_SCHED_REDUCTION_LIMIT 0 +#define WMI_MULTI_MAC_SVC 1 +#define __linux__ 1 diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/default_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/default_defconfig new file mode 100644 index 0000000000..cb74e17499 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/default_defconfig @@ -0,0 +1,1684 @@ +CONFIG_HANDLE_RX_REROUTE_ERR := y + +#Enable DP Bus Vote +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y + +ifeq ($(CONFIG_CNSS_QCA6290), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_QCA6290_11AX := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y +endif + +ifeq ($(CONFIG_CNSS_QCA6390), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI :=y + CONFIG_DIRECT_BUF_RX_ENABLE := y + CONFIG_WMI_DBR_SUPPORT := y + CONFIG_MORE_TX_DESC := y + CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y + CONFIG_WINDOW_REG_PLD_LOCK_ENABLE := y +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) + CONFIG_DIRECT_BUF_RX_ENABLE := y + CONFIG_DBR_HOLD_LARGE_MEM := y + CONFIG_WMI_DBR_SUPPORT := y + CONFIG_WLAN_CFR_ENABLE := y + CONFIG_WLAN_ENH_CFR_ENABLE := y + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_SR := y + CONFIG_OBSS_PD := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI :=y + CONFIG_PCIE_GEN_SWITCH := y + CONFIG_WLAN_TWT_SAP_STA_COUNT := y + CONFIG_WLAN_TWT_SAP_PDEV_COUNT := y + CONFIG_DEVICE_FORCE_WAKE_ENABLE :=y + CONFIG_HIF_REG_WINDOW_SUPPORT :=y + CONFIG_WINDOW_REG_PLD_LOCK_ENABLE := y + CONFIG_DUMP_REO_QUEUE_INFO_IN_DDR :=y + CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y + CONFIG_DCS := y + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_TIMER := y + CONFIG_TX_MULTI_TCL := y + CONFIG_OFDM_SCRAMBLER_SEED := y + CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET := y + ifeq ($(CONFIG_ARCH_LAHAINA), y) + CONFIG_WLAN_TSF_UPLINK_DELAY := y + endif + CONFIG_DP_TRAFFIC_END_INDICATION := y + CONFIG_WLAN_FEATURE_MCC_QUOTA := y + CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF := y + CONFIG_DP_MULTIPASS_SUPPORT := y + CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY := y +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_DIRECT_BUF_RX_ENABLE := y + CONFIG_WLAN_CFR_ENABLE := y + CONFIG_WLAN_FEATURE_SR := y + CONFIG_WMI_DBR_SUPPORT := y + CONFIG_WLAN_ENH_CFR_ENABLE := y + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI :=y + CONFIG_HOST_WAKEUP_OVER_QMI := y + CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7 := y + CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY := y + CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y + CONFIG_TX_MULTI_TCL := y + ifeq ($(CONFIG_ARCH_LAHAINA), y) + CONFIG_WLAN_TSF_UPLINK_DELAY := y + endif + CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF := y + CONFIG_DP_TRAFFIC_END_INDICATION := y + CONFIG_WLAN_DP_PROFILE_SUPPORT := y +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS_KIWI) $(CONFIG_CNSS_KIWI_V2))) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y + endif + CONFIG_EMULATION_2_0 := y + CONFIG_DIRECT_BUF_RX_ENABLE := y + CONFIG_WMI_DBR_SUPPORT := y + CONFIG_WLAN_CFR_ENABLE := y + CONFIG_WLAN_ENH_CFR_ENABLE := y + CONFIG_BERYLLIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_SR := y + CONFIG_OBSS_PD := y + CONFIG_DCS := y + CONFIG_WLAN_TWT_SAP_STA_COUNT := y + CONFIG_WLAN_TWT_SAP_PDEV_COUNT := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_DP_BE_WAR := y + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI := y + CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y + CONFIG_PCIE_GEN_SWITCH := y + CONFIG_ATH_SUPPORT_SPECTRAL := n + CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION := y + CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION := y + CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ := y + CONFIG_WLAN_SYSFS_DP_STATS := y + CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH := y + CONFIG_DISABLE_STATUS_RING_TIMER_WAR := y + CONFIG_CE_DISABLE_SRNG_TIMER_IRQ := y + CONFIG_TX_ADDR_INDEX_SEARCH := y + CONFIG_DP_CON_MON_MSI_ENABLED := y + CONFIG_DEVICE_FORCE_WAKE_ENABLE :=y + CONFIG_HIF_REG_WINDOW_SUPPORT :=y + CONFIG_WINDOW_REG_PLD_LOCK_ENABLE := y + CONFIG_TX_MULTI_TCL := y + CONFIG_OFDM_SCRAMBLER_SEED := y + CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO := y + CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7 := y + CONFIG_WLAN_TSF_UPLINK_DELAY := y + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_TIMER := y + CONFIG_WIFI_POS_PASN := y + CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING := y + CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF := y + CONFIG_DP_PKT_STATS_PER_LMAC := y + CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y + CONFIG_DP_RX_BUFFER_POOL_SIZE := 128 + CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES := 5 + CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 2048 + CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 512 + CONFIG_NO_RX_PKT_HDR_TLV := y +ifeq ($(CONFIG_DP_CON_MON_MSI_ENABLED), y) + CONFIG_DP_CON_MON_MSI_SKIP_SET := y +endif + CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT := y + CONFIG_WLAN_FEATURE_MCC_QUOTA := y + CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE := y + CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC := y + CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG := y + CONFIG_DP_MULTIPASS_SUPPORT := y + CONFIG_WLAN_DP_VDEV_NO_SELF_PEER := y + CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY := y + CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET := y + CONFIG_DP_RX_MSDU_DONE_FAIL_HISTORY := y + CONFIG_DP_RX_PEEK_MSDU_DONE_WAR := y +endif + +ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) + CONFIG_FIX_TXDMA_LIMITATION := y + CONFIG_PEER_PROTECTED_ACCESS := y + CONFIG_SERIALIZE_QUEUE_SETUP := y + CONFIG_DP_RX_PKT_NO_PEER_DELIVER := y + CONFIG_DP_RX_DROP_RAW_FRM := y + CONFIG_FEATURE_ALIGN_STATS_FROM_DP := y + CONFIG_DP_RX_SPECIAL_FRAME_NEED := y + CONFIG_FEATURE_STATS_EXT_V2 := y + CONFIG_WLAN_FEATURE_DP_RX_THREADS := y + CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT := y + CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT := y + CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR := y + CONFIG_ENABLE_HAL_SOC_STATS := y + CONFIG_ENABLE_HAL_REG_WR_HISTORY := y + CONFIG_MON_ENABLE_DROP_FOR_MAC := y + CONFIG_PCI_LINK_STATUS_SANITY := y + CONFIG_DDP_MON_RSSI_IN_DBM := y + CONFIG_SYSTEM_PM_CHECK := y + CONFIG_DISABLE_EAPOL_INTRABSS_FWD := y + CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER := y + CONFIG_BCN_RATECODE_ENABLE := y +endif + +ifeq ($(CONFIG_LITHIUM), y) + CONFIG_FEATURE_AST := y +endif + +ifeq ($(CONFIG_BERYLLIUM), y) + CONFIG_FEATURE_AST := n + CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP := y +endif + +ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) + CONFIG_QCA_WIFI_SDIO := y +ifndef CONFIG_SDIO_TRANSFER + CONFIG_SDIO_TRANSFER = mailbox +endif +endif + +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) + CONFIG_ROME_IF = sdio +endif + +ifeq ($(CONFIG_ICNSS), m) + CONFIG_ICNSS_MODULE := y +endif +ifeq ($(CONFIG_CNSS), m) + CONFIG_CNSS_MODULE := y +endif +ifeq ($(CONFIG_CNSS2), m) + CONFIG_CNSS2_MODULE := y +endif +ifeq ($(CONFIG_ICNSS2), m) + CONFIG_ICNSS2_MODULE := y +endif +ifeq ($(CONFIG_CNSS_GENL), m) + CONFIG_CNSS_GENL_MODULE := y +endif +ifeq ($(CONFIG_CNSS_UTILS), m) + CONFIG_CNSS_UTILS_MODULE := y +endif +ifeq ($(CONFIG_WCNSS_MEM_PRE_ALLOC), m) + CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE := y +endif + +ifeq (y,$(findstring y,$(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE))) + CONFIG_ROME_IF = snoc + CONFIG_QCA_WIFI_SDIO := n + CONFIG_PLD_SNOC_ICNSS_FLAG := y +endif + +ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +ifeq ($(CONFIG_CNSS_QCA6750), y) + CONFIG_ROME_IF = ipci + CONFIG_PLD_IPCI_ICNSS_FLAG := y +endif +else ifeq (y,$(findstring y,$(CONFIG_ICNSS2) $(CONFIG_ICNSS2_MODULE))) + CONFIG_ROME_IF = snoc + CONFIG_QCA_WIFI_SDIO := n + CONFIG_ICNSS2_HELIUM := y + CONFIG_PLD_SNOC_ICNSS_FLAG := y +endif + +ifdef CONFIG_IPCIE_FW_SIM + CONFIG_ROME_IF = ipci + CONFIG_PLD_IPCI_ICNSS_FLAG := n +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS_MODULE) $(CONFIG_CNSS2) $(CONFIG_CNSS2_MODULE))) +ifndef CONFIG_ROME_IF + #use pci as default interface +ifndef CONFIG_IPCIE_FW_SIM + CONFIG_ROME_IF = pci +endif +endif +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := y + +ifeq (y,$(findstring y,$(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE) $(CONFIG_ICNSS2_HELIUM))) + CONFIG_HELIUMPLUS := y + CONFIG_64BIT_PADDR := y + CONFIG_FEATURE_TSO := y + CONFIG_FEATURE_TSO_DEBUG := y + ifeq ($(CONFIG_INET_LRO), y) + CONFIG_WLAN_LRO := y + else + CONFIG_WLAN_LRO := n + endif +endif + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +CONFIG_NUM_SOC_PERF_CLUSTER := 2 +endif + +ifeq ($(CONFIG_ARCH_SDXLEMUR), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_SDXBAAGHA), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MDM9630), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MDM9640), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515) $(CONFIG_ARCH_SA515M) $(CONFIG_ARCH_SDXPOORWILLS))) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MSM8917), y) + ifeq ($(CONFIG_ROME_IF), sdio) + CONFIG_WLAN_SYNC_TSF_PLUS := y + endif +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_QCS405) $(CONFIG_ARCH_QCS403))) + CONFIG_ARCH_QCS40X := y +endif + +ifeq ($(CONFIG_ARCH_QCS40X), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ := y + CONFIG_RX_PERFORMANCE := y + CONFIG_TGT_NUM_MSDU_DESC := 900 + CONFIG_MULTI_IF_LOG := y + CONFIG_DFS_PRI_MULTIPLIER := y + CONFIG_DFS_OVERRIDE_RF_THRESHOLD := y + CONFIG_WLAN_FEATURE_LL_MODE := y +ifeq ($(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH), y) + CONFIG_WLAN_CLD_PM_QOS := y + CONFIG_WLAN_CLD_DEV_PM_QOS := y +endif +endif +CONFIG_WLAN_FEATURE_MBSSID := y +CONFIG_WLAN_FEATURE_P2P_P2P_STA := y + +#Flag to enable Legacy Fast Roaming3(LFR3) +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) + CONFIG_QCACLD_WLAN_LFR3 := y +else + CONFIG_QCACLD_WLAN_LFR2 := y +endif + +#Flag to enable Roam stats feature +ifeq ($(CONFIG_BERYLLIUM), y) +ifeq (y,$(filter y,$(CONFIG_QCACLD_WLAN_LFR3))) + CONFIG_WLAN_FEATURE_ROAM_INFO_STATS := y +endif +endif + +#Flag to enable Dynamic MAC address update +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE := y + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_QCA_MONITOR_PKT_SUPPORT := y +CONFIG_MONITOR_MODULARIZED_ENABLE := n +endif + +ifeq (y,$(filter y,$(CONFIG_ARCH_SDXLEMUR) $(CONFIG_ARCH_SDXBAAGHA))) +CONFIG_WIFI_MONITOR_SUPPORT := n +CONFIG_QCA_MONITOR_PKT_SUPPORT := n +CONFIG_MONITOR_MODULARIZED_ENABLE := y +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Flag to enable TDLS feature +CONFIG_QCOM_TDLS := y + +CONFIG_WLAN_SYSFS := y + +CONFIG_THERMAL_STATS_SUPPORT := y + +ifeq ($(CONFIG_WLAN_SYSFS), y) + CONFIG_WLAN_SYSFS_STA_INFO := y + CONFIG_WLAN_SYSFS_CHANNEL := y + CONFIG_WLAN_SYSFS_FW_MODE_CFG := y + CONFIG_WLAN_SYSFS_MEM_STATS := y + CONFIG_WLAN_REASSOC := y + CONFIG_WLAN_SYSFS_CONNECT_INFO := y + CONFIG_WLAN_SCAN_DISABLE := y + CONFIG_WLAN_SYSFS_DCM := y + CONFIG_WLAN_WOW_ITO := y + CONFIG_WLAN_WOWL_ADD_PTRN := y + CONFIG_WLAN_WOWL_DEL_PTRN := y + CONFIG_WLAN_SYSFS_TX_STBC := y + CONFIG_WLAN_SYSFS_WLAN_DBG := y + CONFIG_WLAN_TXRX_FW_ST_RST := y + CONFIG_WLAN_GTX_BW_MASK := y + CONFIG_WLAN_SYSFS_SCAN_CFG := y + CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL := y + CONFIG_WLAN_SYSFS_RADAR := y + CONFIG_WLAN_SYSFS_RTS_CTS := y + CONFIG_WLAN_SYSFS_HE_BSS_COLOR := y + CONFIG_WLAN_TXRX_FW_STATS := y + CONFIG_WLAN_TXRX_STATS := y + CONFIG_WLAN_SYSFS_DP_TRACE := y + CONFIG_WLAN_SYSFS_STATS := y +ifeq ($(CONFIG_QCOM_TDLS), y) + CONFIG_WLAN_SYSFS_TDLS_PEERS := y +endif + CONFIG_WLAN_SYSFS_TEMPERATURE := y + CONFIG_WLAN_THERMAL_CFG := y + CONFIG_WLAN_DL_MODES := y + CONFIG_WLAN_DUMP_IN_PROGRESS := n + CONFIG_WLAN_BMISS := y + CONFIG_WLAN_FREQ_LIST := y + CONFIG_DP_PKT_ADD_TIMESTAMP := y + CONFIG_WLAN_SYSFS_LOG_BUFFER := y + CONFIG_WLAN_SYSFS_DFSNOL := y + CONFIG_WLAN_SYSFS_WDS_MODE := y + CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP := y + CONFIG_WLAN_SYSFS_RF_TEST_MODE := y +endif +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM := y +CONFIG_WLAN_POWER_DEBUG := y +#Enable Beacon Reception Stats +CONFIG_FEATURE_BECN_STATS := y +endif + +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y + +#Disable the Export Symbol config +ifeq ($(CONFIG_WLAN_MULTI_CHIP_SUPPORT), y) +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y +else +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n +endif + +CONFIG_QCACLD_FEATURE_GREEN_AP := y + +#Flag to enable pre cac feature +CONFIG_FEATURE_WLAN_PRE_CAC := y + +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := y + +#Flag to enable get firmware state +CONFIG_QCACLD_FEATURE_FW_STATE := y + +#Flag to enable set coex configuration +CONFIG_QCACLD_FEATURE_COEX_CONFIG := n + +#Flag to enable get hw capability +ifeq ($(CONFIG_ARCH_QCS40X), y) +CONFIG_QCACLD_FEATURE_HW_CAPABILITY := y +endif + +ifeq ($(CONFIG_ARCH_MSM8998), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +CONFIG_QCACLD_FEATURE_METERING := y +CONFIG_WDI3_STATS_UPDATE := y +ifeq ($(CONFIG_WDI3_STATS_UPDATE), y) +CONFIG_WDI3_STATS_BW_MONITOR := y +endif +CONFIG_WLAN_SYNC_TSF_TIMER := y +endif + +ifeq ($(CONFIG_ARCH_LAHAINA), y) +CONFIG_QCACLD_FEATURE_METERING := y +CONFIG_WDI3_STATS_UPDATE := y +ifeq ($(CONFIG_CNSS_QCA6490), y) +CONFIG_WBM_IDLE_LSB_WR_CNF_WAR := y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y +CONFIG_DP_RX_BUFFER_POOL_SIZE := 128 +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES := 5 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 512 +ifeq ($(CONFIG_WDI3_STATS_UPDATE), y) +CONFIG_WDI3_STATS_BW_MONITOR := y +endif +endif +endif + +#Flag to enable Fast Transition (11r) feature +CONFIG_QCOM_VOWIFI_11R := y + +#Flag to enable disable ACTION OUI feature +CONFIG_WLAN_FEATURE_ACTION_OUI := y + +#Flag to enable Adaptive 11r feature +CONFIG_ADAPTIVE_11R := y + +#Flag to enable sae single pmk feature +CONFIG_SAE_SINGLE_PMK := y + +#Flag to enable/disable multi client low latency feature support +CONFIG_MULTI_CLIENT_LL_SUPPORT := y + +#Flag to enable/disable vendor handoff feature support +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL := y + +#Flag to enable mscs feature +CONFIG_FEATURE_MSCS := y + +#Flag to enable FILS Feature (11ai) +CONFIG_WLAN_FEATURE_FILS := y +ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS_MODULE) $(CONFIG_CNSS2) \ + $(CONFIG_CNSS2_MODULE) $(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE) \ + $(CONFIG_ICNSS2) $(CONFIG_ICNSS2_MODULE))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + CONFIG_WLAN_FEATURE_LPSS := y + endif + ifeq ($(CONFIG_ARCH_SDXLEMUR), y) + CONFIG_WLAN_FEATURE_LPSS := y + endif + ifeq ($(CONFIG_ARCH_SDXBAAGHA), y) + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + +endif + +#Flag to enable the tx desc sanity check +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_QCA_TXDESC_SANITY_CHECKS := y +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN + CONFIG_QCACLD_FEATURE_NAN := y +endif + +#Flag to enable Linux QCMBR feature as default feature +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y +endif + + +CONFIG_FEATURE_EPPING := y + +#Flag to enable offload packets feature +CONFIG_WLAN_OFFLOAD_PACKETS := y + +#enable TSF get feature +CONFIG_WLAN_SYNC_TSF := y +#Enable DSRC feature +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +CONFIG_WLAN_FEATURE_DSRC := y +endif + +ifneq ($(CONFIG_ROME_IF),usb) + #Flag to enable SAE + CONFIG_WLAN_FEATURE_SAE := y + +ifneq ($(CONFIG_ROME_IF),sdio) + #Flag to enable DISA + CONFIG_WLAN_FEATURE_DISA := y + + #Flag to enable FIPS + CONFIG_WLAN_FEATURE_FIPS := y + + #Flag to enable Fast Path feature + ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) + CONFIG_WLAN_FASTPATH := y + endif + + # Flag to enable NAPI + CONFIG_WLAN_NAPI := y + CONFIG_WLAN_NAPI_DEBUG := n + + # Flag to enable FW based TX Flow control + ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y + else + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n + endif + +endif +endif + +CONFIG_POWER_MANAGEMENT_OFFLOAD := y + +ifeq ($(CONFIG_ROME_IF), snoc) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +endif + +ifeq ($(CONFIG_ARCH_QCS40X), y) +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n +# Flag to improve TCP TX throughput for both +# CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY and CONFIG_WLAN_TX_FLOW_CONTROL_V2 +# disabled platform, avoid frame drop in driver +CONFIG_WLAN_PDEV_TX_FLOW_CONTROL := y +endif + +# Flag to enable LFR Subnet Detection +CONFIG_LFR_SUBNET_DETECTION := y + +# Flag to enable MCC to SCC switch feature +CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + # Enable Obj Mgr Degug services if slub build + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_LOCK_STATS_ON:= y + CONFIG_WLAN_OBJMGR_REF_ID_TRACE := y +endif + +ifeq ($(CONFIG_WLAN_SYSFS), y) + CONFIG_WLAN_SYSFS_RANGE_EXT := y +endif + +ifeq (y,$(findstring y,$(CONFIG_QCA_WIFI_SDIO) $(CONFIG_HIF_USB))) +CONFIG_HL_DP_SUPPORT := y +else +CONFIG_LL_DP_SUPPORT := y +endif + +ifeq ($(CONFIG_ROME_IF),pci) +ifneq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +endif +endif +endif + +#Whether have QMI support +CONFIG_QMI_SUPPORT := y + +ifeq (y,$(findstring y,$(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE) $(CONFIG_ICNSS2_HELIUM))) +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +# Enable athdiag procfs debug support for adrastea +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +# Enable 11AC TX compact feature for adrastea +CONFIG_ATH_11AC_TXCOMPACT := y +ifeq ($(CONFIG_QMI_SUPPORT), y) +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +endif +endif + +# Enable fw stats version 2 +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_AR900B := y +endif + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq ($(CONFIG_HELIUMPLUS), y) + +ifeq ($(CONFIG_64BIT_PADDR), y) +CONFIG_HTT_PADDR64 := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +CONFIG_HIF_LARGE_CE_RING_HISTORY := 8192 +endif + +ifeq ($(CONFIG_CNSS2_DEBUG), y) +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +CONFIG_HIF_LARGE_CE_RING_HISTORY := 8192 +endif +CONFIG_FEATURE_ENABLE_CE_DP_IRQ_AFFINE := y +endif #CONFIG_HELIUMPLUS + +ifeq ($(CONFIG_LITHIUM), y) +# +# Enable Shadow V2 for all lithium platform +# +CONFIG_SHADOW_V2 := y + +# Enable sw_cookie sanity WAR for all Lithium platforms +CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE := y +endif + +ifeq ($(CONFIG_BERYLLIUM), y) +# +# Enable Shadow V3 for all Beryllium platform +# +CONFIG_SHADOW_V3 := y +endif + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_RX_DEFRAG_DO_NOT_REINJECT := y +CONFIG_MARK_ICMP_REQ_TO_FW := y +CONFIG_IPA_SET_RESET_TX_DB_PA := y +# +# Enable VERBOSE debug INI mechanism +# +CONFIG_VERBOSE_DEBUG := y +CONFIG_RX_DESC_SANITY_WAR := y +ifeq ($(CONFIG_PCI_MSM), $(filter $(CONFIG_PCI_MSM), m y)) + CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := y +ifeq ($(CONFIG_CNSS_QCA6390), y) + CONFIG_SHADOW_WRITE_DELAY := y +endif +endif + +ifeq ($(CONFIG_CNSS_QCA6290), y) + CONFIG_QCA6290_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6290 := y +endif +ifeq ($(CONFIG_CNSS_QCA6390), y) + CONFIG_QCA6390_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6390 := y +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) + CONFIG_QCA6490_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6490 := y + CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := y +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) + CONFIG_QCA6750_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6750 := y + CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := y + CONFIG_IPA_SET_RESET_TX_DB_PA := y + ifeq ($(CONFIG_WDI3_STATS_UPDATE), y) + CONFIG_WDI3_STATS_BW_MONITOR := y + endif +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) + CONFIG_BUS_AUTO_SUSPEND := y +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS_KIWI) $(CONFIG_CNSS_KIWI_V2))) + CONFIG_KIWI_HEADERS_DEF := y + CONFIG_QCA_WIFI_KIWI := y +endif + +CONFIG_QCA_WIFI_QCA8074 := y +CONFIG_QCA_WIFI_QCA8074_VP := y +CONFIG_DP_INTR_POLL_BASED := y +CONFIG_TX_PER_PDEV_DESC_POOL := y +CONFIG_DP_TRACE := y +CONFIG_FEATURE_TSO := y +CONFIG_FEATURE_FORCE_WAKE := y +CONFIG_DP_LFR := y +CONFIG_DUP_RX_DESC_WAR := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y +CONFIG_TX_TID_OVERRIDE := y +CONFIG_DP_TXRX_SOC_ATTACH := y +ifeq ($(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH), y) +CONFIG_WLAN_CLD_PM_QOS := y +endif +CONFIG_WLAN_CLD_DEV_PM_QOS := y +CONFIG_DISABLE_DP_STATS := n +CONFIG_MAX_ALLOC_PAGE_SIZE := y +CONFIG_REO_DESC_DEFER_FREE := y +CONFIG_RXDMA_ERR_PKT_DROP := y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK := y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS := y +CONFIG_WLAN_TRACE_HIDE_SSID := n +CONFIG_DP_MEM_PRE_ALLOC := y +CONFIG_FEATURE_GPIO_CFG := y + +ifeq ($(CONFIG_FEATURE_TSO), y) + CONFIG_FEATURE_TSO_STATS := y + CONFIG_TSO_DEBUG_LOG_ENABLE := y +endif + +ifeq ($(CONFIG_DISABLE_DP_STATS), y) + CONFIG_FEATURE_TSO_STATS := n +endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG=y + +# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QCOMs internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. +ifneq ($(TARGET_BUILD_VARIANT),user) + CONFIG_FEATURE_PKTLOG := y + CONFIG_WLAN_DEBUG_CRASH_INJECT := y +endif + +#Disable pktlog feature for lithium based target +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) + CONFIG_FEATURE_PKTLOG := n +endif + +#Enable WLAN/Power debugfs feature only if debug_fs is enabled +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y + + # Flag to enable streamfs. Depends on CONFIG_DEBUG_FS and + # CONFIG_RELAY in kernel configuration. +ifeq ($(CONFIG_RELAY), y) + CONFIG_WLAN_STREAMFS := y +endif +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) + CONFIG_WLAN_MWS_INFO_DEBUGFS := y + CONFIG_WLAN_FEATURE_MIB_STATS := y +endif + +#Whether to build debug version +CONFIG_WLAN_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +CONFIG_WLAN_DIAG_VERSION := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +# Compile all log levels by default +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := y + +#Disable packet log +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_REMOVE_PKT_LOG := y +else +CONFIG_REMOVE_PKT_LOG := n +endif + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +ifeq ($(CONFIG_ROME_IF),ipci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_ATH_11AC_TXCOMPACT := n +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := y +endif + +ifeq ($(CONFIG_ROME_IF),ipci) + CONFIG_HIF_IPCI := y +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_HIF_USB := y +endif + +#Enable SDIO specific APIS +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_HIF_SDIO := y + CONFIG_TX_DESC_HI_PRIO_RESERVE := y + CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y + CONFIG_TGT_NUM_MSDU_DESC := 0 +endif + +ifeq ($(CONFIG_ROME_IF),snoc) + CONFIG_HIF_SNOC:= y +endif + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := n +ifneq ($(CONFIG_ARCH_SDXPRAIRIE), y) +ifneq ($(CONFIG_ARCH_SA515), y) +ifneq ($(CONFIG_ARCH_SDXLEMUR), y) +ifneq ($(CONFIG_ARCH_SDXBAAGHA), y) +ifneq ($(CONFIG_ARCH_SDXPINN), y) +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +endif # CONFIG_ARCH_SDXPINN +endif +endif +endif +endif +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +CONFIG_FEATURE_STA_MODE_VOTE_LINK := y +else +CONFIG_QCOM_ESE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +#enable 4addr support for QCS40X +ifeq ($(CONFIG_ARCH_QCS40X), y) +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := y + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := n + +#Define the legacy pktlog +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), sdio) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), pci) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), usb) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), snoc) +CONFIG_PKTLOG_LEGACY := y +endif +endif + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_PKTLOG_LEGACY := n +endif + +#Customize DSCP_to-UP map based on RFC8325 +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y +CONFIG_WLAN_SEND_DSCP_UP_MAP_TO_FW := y +endif + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +CONFIG_SMMU_S1_UNMAP := y +endif + +ifeq ($(CONFIG_ICNSS2_HELIUM), y) +CONFIG_SMMU_S1_UNMAP := y +endif + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_WAPI_BIG_ENDIAN := y +else +CONFIG_WAPI_BIG_ENDIAN := n +endif + +#Enable WDI Event support +CONFIG_WDI_EVENT_ENABLE := y +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +ifeq ($(CONFIG_WLAN_ENH_CFR_ENABLE), n) +CONFIG_WDI_EVENT_ENABLE := n +endif +endif + +#Enable the type_specific_data in the ath_pktlog_arg +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif + +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif +endif + +#Endianness selection +CONFIG_LITTLE_ENDIAN := y + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := y + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := y + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := y + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := n + +#Enable IPA offload for MDM platforms +ifeq ($(CONFIG_MDM_PLATFORM), y) +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), m) +CONFIG_IPA_OFFLOAD := y +endif +else +CONFIG_IPA_OFFLOAD := n +CONFIG_IPA_OPT_WIFI_DP := n +endif + +#Flag to enable SMMU S1 support +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SA515M), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_IPA_P2P_SUPPORT := y +endif +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif +endif + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515))) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +CONFIG_IPA_WDI3_TX_TWO_PIPES := y +endif +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +endif +endif + +ifeq ($(CONFIG_ARCH_LAHAINA), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +endif +endif + +ifeq (y,$(filter y,$(CONFIG_ARCH_SDXLEMUR) $(CONFIG_ARCH_SDXBAAGHA))) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +CONFIG_IPA_WDI3_TX_TWO_PIPES := y +endif +endif + +ifeq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_ARCH_SDM630), y) +ifneq ($(CONFIG_ARCH_SDM660), y) +ifneq ($(CONFIG_ARCH_MSM8998), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif +endif +endif +endif + +ifeq ($(CONFIG_ARCH_WAIPIO), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +endif +CONFIG_WLAN_TSF_UPLINK_DELAY := y +endif + +ifeq ($(CONFIG_ARCH_KALAMA), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +endif +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +ifeq ($(CONFIG_WCNSS_SKB_PRE_ALLOC), y) +CONFIG_FEATURE_SKB_PRE_ALLOC := y +endif +endif +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ifneq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_HIF_CPU_CLEAR_AFFINITY := y +endif +endif +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := n + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := y + +#Flag to allocate memory dynamically for different buffers +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +#Flag to enable HTC credit history feature +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y + +#Flag to enable MTRACE feature +CONFIG_TRACE_RECORD_FEATURE := y + +#Flag to enable p2p debug feature +CONFIG_WLAN_FEATURE_P2P_DEBUG := y + +#Flag to enable roam debug log +CONFIG_FEATURE_ROAM_DEBUG := y + +#Flag to enable DFS Master feature +CONFIG_WLAN_DFS_MASTER_ENABLE := y + +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +#Flag to enable WEXT support for STA/AP/P2P interfaces +ifeq ($(CONFIG_CFG80211_WEXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif +else +ifeq ($(CONFIG_WIRELESS_EXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif +endif + +#Flag to enable/disable MTRACE feature +CONFIG_ENABLE_MTRACE_LOG := y + +#Flag to enable nud tracking feature +CONFIG_WLAN_NUD_TRACKING := y + +#Flag to enable/Disable Function call trace +CONFIG_FUNC_CALL_MAP := n + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := y + +#Flag to enable set and get disable channel list feature +CONFIG_DISABLE_CHANNEL_LIST :=y + +#Flag to enable beacon receive feature +CONFIG_WLAN_BCN_RECV_FEATURE := y + +#Flag to enable LTE COEX feature +CONFIG_LTE_COEX := y + +#Flag to enable delayed peer obj free +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY := y + +#Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +#Flag to enable/disable Avoid acs freq feature +CONFIG_SAP_AVOID_ACS_FREQ_LIST := y + +#Flag to enable HOST OPCLASS feature +CONFIG_HOST_OPCLASS := y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +#Flag to enable SAR Safety Feature +CONFIG_SAR_SAFETY_FEATURE := y + +CONFIG_CONNECTION_ROAMING_CFG := n + +CONFIG_FEATURE_SET := y + +CONFIG_WLAN_FEATURE_LL_LT_SAP := y + +CONFIG_WIFI_POS_CONVERGED := y +CONFIG_WLAN_TWT_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_QCA_TARGET_IF_MLME := y + +CONFIG_CP_STATS := y +CONFIG_FEATURE_INTEROP_ISSUES_AP := y + +CONFIG_FEATURE_WLAN_WAPI := y + +#Flag to enable FW log parsing support feature +CONFIG_FEATURE_FW_LOG_PARSING := y + +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_WMI_BCN_OFFLOAD := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_FEATURE_DENYLIST_MGR := y +CONFIG_FOURTH_CONNECTION := y +CONFIG_SUPPORT_11AX := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y + +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y + +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_FEATURE_TWT := y +CONFIG_FW_THERMAL_THROTTLE := y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS := y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD := y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y +CONFIG_FEATURE_RADAR_HISTORY := y + +ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE) $(CONFIG_ICNSS2_HELIUM))) +CONFIG_WLAN_FEATURE_BMI := n +else +CONFIG_WLAN_FEATURE_BMI := y +endif + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y +CONFIG_QCACLD_FEATURE_MPTA_HELPER := n +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC := y + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +CONFIG_DP_TRACE := y + +ifeq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif +CONFIG_RX_OL := y +endif + +ifeq ($(CONFIG_CNSS_EMULATION), y) +#on emulation platform, increase host timeouts by 1000 times +CONFIG_QDF_TIMER_MULTIPLIER_FRAC := 1000 +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y + CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS := n +ifndef CONFIG_MAX_LOGS_PER_SEC + CONFIG_MAX_LOGS_PER_SEC := 500 +endif + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_REGISTER_OP_DEBUG := y + CONFIG_ENABLE_QDF_PTR_HASH_DEBUG := y + CONFIG_HAL_DEBUG := y + CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE := y + +ifneq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_HIF_DETECTION_LATENCY_ENABLE := y +endif +endif +endif + +ifeq ($(CONFIG_CNSS2_DEBUG), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y + CONFIG_MAX_LOGS_PER_SEC := 500 + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_REGISTER_OP_DEBUG := y + CONFIG_ENABLE_QDF_PTR_HASH_DEBUG := y + CONFIG_HAL_DEBUG := y + CONFIG_ATH_DIAG_EXT_DIRECT := y + CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS := n +endif + + CONFIG_HIF_DEBUG := y + +ifeq ($(CONFIG_UNIT_TEST), y) + CONFIG_DSC_TEST := y + CONFIG_QDF_TEST := y + CONFIG_FEATURE_WLM_STATS := y +endif + +ifeq ($(CONFIG_LITHIUM), y) + CONFIG_RX_DESC_DEBUG_CHECK:= y + CONFIG_ALLOW_PKT_DROPPING := y +endif + +ifeq ($(CONFIG_BERYLLIUM), y) + ifeq (y,$(filter y,$(CONFIG_CNSS2_DEBUG) $(CONFIG_SLUB_DEBUG_ON))) + CONFIG_RX_DESC_DEBUG_CHECK:= y + CONFIG_ALLOW_PKT_DROPPING := y + CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY := y + CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK := y + CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY := y + endif +endif + +ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) + ifeq (y,$(filter y,$(CONFIG_CNSS2_DEBUG) $(CONFIG_SLUB_DEBUG_ON))) + CONFIG_HIF_CE_DEBUG_DATA_BUF := y + CONFIG_WLAN_RECORD_RX_PADDR := y + CONFIG_HIF_CPU_PERF_AFFINE_MASK := y + CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY := y + CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY := y + CONFIG_REO_QDESC_HISTORY := y + CONFIG_DP_TX_HW_DESC_HISTORY := y + CONFIG_QDF_NBUF_HISTORY_SIZE := 16384 + CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK := y + CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE := y + endif + CONFIG_DP_HW_TX_DELAY_STATS_ENABLE := y + CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY := y + CONFIG_DYNAMIC_RX_AGGREGATION := y + CONFIG_WLAN_SUPPORT_DATA_STALL := y + CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG := y + CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG := y + #Enable WMI TX/RX over QMI + CONFIG_WMI_SEND_RECV_QMI := y + CONFIG_WLAN_DP_PENDING_MEM_FLUSH := y + CONFIG_WLAN_SKIP_BAR_UPDATE := y + CONFIG_TX_MULTIQ_PER_AC := y + CONFIG_WLAN_TRACEPOINTS := y + ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST := y +endif + +#Flag to enable ref ID print +CONFIG_WLAN_OBJMGR_DEBUG:= y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE := y + +#Flag to enable hdd memory dump feature +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +#Flag to enable/disable WLAN D0-WOW +ifeq ($(CONFIG_PCI_MSM), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif +endif + +ifeq ($(CONFIG_ARCH_MDM9607), y) +CONFIG_TUFELLO_DUAL_FW_SUPPORT := y +endif + +CONFIG_CHANNEL_HOPPING_ALL_BANDS := y + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515))) + ifneq ($(CONFIG_SLUB_DEBUG), y) + CONFIG_DP_TRACE := n + endif + + CONFIG_DIRECT_BUF_RX_ENABLE := n + CONFIG_WMI_DBR_SUPPORT := n + CONFIG_MAX_CLIENTS_ALLOWED := 64 +endif + +ifneq ($(CONFIG_HIF_USB), y) +CONFIG_WLAN_LOGGING_SOCK_SVC := y +endif + +CONFIG_CONNECTIVITY_PKTLOG := y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y + +ifneq ($(TARGET_BUILD_VARIANT),user) +CONFIG_DESC_DUP_DETECT_DEBUG := y +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS_MODULE))) +ifeq ($(CONFIG_CNSS_SDIO), y) +CONFIG_PLD_SDIO_CNSS_FLAG := y +endif +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR := y +endif +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS2) $(CONFIG_CNSS2_MODULE))) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_BUS_BANDWIDTH_MGR := y +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +#Enable OEM DATA feature +CONFIG_FEATURE_OEM_DATA := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +#Enable eLNA bypass feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_ELNA := y +endif + +#Enable mDNS feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD := y +endif + +#Enable ICMP feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD := y +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y +CONFIG_RX_FISA := y +CONFIG_MORE_TX_DESC := y + ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DP_FT_LOCK_HISTORY := y + endif +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) + +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y +CONFIG_RX_FISA := y +CONFIG_MORE_TX_DESC := y + +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS_KIWI) $(CONFIG_CNSS_KIWI_V2))) +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y +CONFIG_RX_FISA := y +CONFIG_MORE_TX_DESC := y +endif + +CONFIG_HANDLE_BC_EAP_TX_FRM := y + +ifeq ($(CONFIG_BAND_6GHZ), y) + +CONFIG_6G_SCAN_CHAN_SORT_ALGO := y + +endif + +CONFIG_SAP_DHCP_FW_IND := y + +#Enable support to get ANI level +CONFIG_ANI_LEVEL_REQUEST := y + +ifeq ($(CONFIG_ARCH_QCS405), y) +CONFIG_FEATURE_WLAN_TIME_SYNC_FTM := y +endif + +ifeq ($(CONFIG_ARCH_SDM660), y) +CONFIG_WLAN_FEATURE_PKT_CAPTURE := y +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) +ifneq (, $(filter y, $(CONFIG_ARCH_LAHAINA) $(CONFIG_ARCH_PARROT))) +CONFIG_WLAN_FEATURE_PKT_CAPTURE := y +CONFIG_WLAN_FEATURE_PKT_CAPTURE_V2 := y +CONFIG_DP_RX_UDP_OVER_PEER_ROAM := y +CONFIG_WLAN_BOOST_CPU_FREQ_IN_ROAM := y +endif +endif + +#Enable RX RING buffers debug +CONFIG_DEBUG_RX_RING_BUFFER := y + +#Enable Hash debug +CONFIG_RX_HASH_DEBUG := y + +#Enable VDEV OPS wakelock feature +CONFIG_FEATURE_VDEV_OPS_WAKELOCK := y + +# Enable RX buffer pool support +ifeq ($(CONFIG_CNSS_QCA6750), y) +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y +CONFIG_DP_RX_BUFFER_POOL_SIZE := 128 +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES := 5 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 512 +CONFIG_DP_SWLM := y +CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE := y +endif + +ifeq ($(CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE), y) +CONFIG_WLAN_WBUFF := y +endif + +ifeq (y,$(filter y,$(CONFIG_ARCH_SDXLEMUR) $(CONFIG_ARCH_SDXBAAGHA))) +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y +CONFIG_DP_RX_BUFFER_POOL_SIZE := 128 +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES := 5 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 512 +CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV := 4 +CONFIG_NUM_IPA_IFACE := 4 +CONFIG_MAX_CLIENTS_ALLOWED := 64 +ifneq ($(CONFIG_SLUB_DEBUG), y) +CONFIG_DP_TRACE := n +endif +CONFIG_DIRECT_BUF_RX_ENABLE := n +CONFIG_WMI_DBR_SUPPORT := n +CONFIG_WLAN_CFR_ENABLE := n +CONFIG_WLAN_ENH_CFR_ENABLE := n +CONFIG_QCACLD_FEATURE_APF := n +CONFIG_QCACLD_FEATURE_NAN := n +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := n +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := n +CONFIG_FEATURE_RSSI_MONITOR := n +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := n +CONFIG_FEATURE_OEM_DATA := n +CONFIG_MORE_TX_DESC := n +CONFIG_AFC_SUPPORT := y +CONFIG_WLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE := y +endif + +#Enable Hang Event +CONFIG_WLAN_HANG_EVENT := y + +ifeq ($(CONFIG_FW_THERMAL_THROTTLE), y) +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT := y +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE := 1 +CONFIG_DP_RX_DESC_COOKIE_INVALIDATE := y +else +CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE := 0 +endif +endif + +CONFIG_WLAN_DEBUG_LINK_VOTE := y + +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT := y + +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER := y + +CONFIG_WLAN_FEATURE_NO_STA_SAP_CONCURRENCY := n +CONFIG_WLAN_FEATURE_NO_STA_NAN_CONCURRENCY := n +CONFIG_WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY := n +CONFIG_WLAN_FEATURE_NO_P2P_CONCURRENCY := n + +ifeq (y,$(findstring y,$(CONFIG_CNSS_QCA6490) $(CONFIG_CNSS_KIWI) $(CONFIG_CNSS_KIWI_V2))) +CONFIG_FEATURE_WLAN_CH_AVOID_EXT := y +endif + +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_DP_TX_TRACKING := y +endif + +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +CONFIG_WDI_EVENT_ENABLE := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_DCS := y +CONFIG_FEATURE_WDS := y +endif + +ifeq ($(CONFIG_FEATURE_WDS), y) +CONFIG_FEATURE_MEC := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_FEATURE_MCL_REPEATER := y +CONFIG_BYPASS_WDS_OL_OPS := y +CONFIG_WDS_CONV_TARGET_IF_OPS_ENABLE := y +endif + +ifeq ($(CONFIG_CNSS_SM6150), y) +CONFIG_ENABLE_LOW_POWER_MODE := y +endif + +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.common b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.common new file mode 100644 index 0000000000..887cef73e3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.common @@ -0,0 +1,260 @@ +# Protocol specific features + +#features not required for GENOA IOT, compilation errors are there. +CONFIG_TX_AGGREGATION_SIZE_ENABLE := y +CONFIG_SUPPORT_11AX := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_FEATURE_STATS_EXT := n +CONFIG_FEATURE_WLAN_FT_IEEE8021X := y +CONFIG_FEATURE_WLAN_FT_PSK := y + +#required features +CONFIG_QCACLD_WLAN_LFR2 := y +CONFIG_QCACLD_WLAN_LFR3 := n +CONFIG_QCOM_TDLS := y +CONFIG_QCACLD_FEATURE_GREEN_AP := n +CONFIG_QCOM_VOWIFI_11R := y +CONFIG_WLAN_FEATURE_FILS := y +CONFIG_QCOM_LTE_COEX := n +CONFIG_WLAN_FEATURE_LPSS := n +CONFIG_QCACLD_FEATURE_NAN := y +CONFIG_POWER_MANAGEMENT_OFFLOAD := y +CONFIG_LFR_SUBNET_DETECTION := y +CONFIG_MCC_TO_SCC_SWITCH := y +CONFIG_QCOM_ESE := n +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := n +CONFIG_WLAN_DFS_MASTER_ENABLE := y +CONFIG_WIFI_POS_CONVERGED := y +CONFIG_WIFI_POS_LEGACY := n +CONFIG_FEATURE_WLAN_WAPI := y +CONFIG_AGEIE_ON_SCAN_RESULTS := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_FEATURE_TWT := n +CONFIG_WMI_CMD_STRINGS := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_DSRC := n +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := n +CONFIG_DP_TRACE := y +CONFIG_QCACLD_FEATURE_METERING := n + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := n + +#We might need to disable WEXT support in perf builds in future +ifeq ($(CONFIG_WIRELESS_EXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif +CONFIG_HOST_11D_SCAN := y + +#Flag to enable/disable Avoid acs freq feature +CONFIG_SAP_AVOID_ACS_FREQ_LIST := n + +ifeq ($(CONFIG_ARCH_MSM8996), y) +CONFIG_CHANNEL_HOPPING_ALL_BANDS := y +endif + +# Debug specific features +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := y +CONFIG_WLAN_DEBUG_VERSION := y +CONFIG_WLAN_DIAG_VERSION := n + +CONFIG_REMOVE_PKT_LOG := y +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y +CONFIG_TRACE_RECORD_FEATURE := y +CONFIG_WLAN_NUD_TRACKING := n +CONFIG_CP_STATS := y +CONFIG_QCA_TARGET_IF_MLME := y +CONFIG_FEATURE_FW_LOG_PARSING := y +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_FEATURE_ROAM_DEBUG := y + +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y + +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +CONFIG_WDI_EVENT_ENABLE := n +else +CONFIG_WDI_EVENT_ENABLE := y +endif + +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +CONFIG_PKTLOG_LEGACY := y +endif + +#Enable the type_specific_data in the ath_pktlog_arg +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +CONFIG_WLAN_LOGGING_SOCK_SVC := y + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := n + +# other features +WLAN_OPEN_SOURCE := y +CONFIG_ATH_PERF_PWR_OFFLOAD := y +CONFIG_ATH_BUS_PM := n +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n +CONFIG_ATH_SUPPORT_SPECTRAL := n +CONFIG_LITTLE_ENDIAN := y +CONFIG_ATH_PCIE_ACCESS_DEBUG := n +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y +CONFIG_FEATURE_SECURE_FIRMWARE := n +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +CONFIG_FEATURE_WLAN_LPHB := y +endif +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_REG_CLIENT := y +CONFIG_WLAN_OFFLOAD_PACKETS := y +CONFIG_WLAN_SYNC_TSF := y +CONFIG_WLAN_FEATURE_DISA := n +CONFIG_WLAN_FEATURE_FIPS := y +CONFIG_WLAN_FEATURE_SAE := y +CONFIG_CHNL_MATRIX_RESTRICTION := n +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := y +CONFIG_WLAN_FEATURE_BMI := n +# Enable FW stats version 2 +CONFIG_AR900B := y + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := n +CONFIG_FEATURE_BSS_TRANSITION := n +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := n +CONFIG_FEATURE_OTA_TEST := n +CONFIG_FEATURE_ACTIVE_TOS := n +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := n +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := n +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := n + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +#Data Path specific features +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n +CONFIG_CHECKSUM_OFFLOAD := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y + +ifeq ($(CONFIG_POWER_MANAGEMENT_OFFLOAD), y) +CONFIG_GTK_OFFLOAD := y +endif +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := n + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +# Use static allocation for DFS +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +# WoW filer configs +CONFIG_CFG_PMO_WOW_FILTERS_MAX := 16 + +# Offload configs +CONFIG_CFG_GTK_OFFLOAD_MAX_VDEV := 2 +CONFIG_CFG_ROAM_OFFLOAD_MAX_VDEV := 1 + +# Max Periodic Tx Pattern Config +CONFIG_CFG_MAX_PERIODIC_TX_PTRNS := 3 + +# Max Sta Vdev Config +CONFIG_CFG_MAX_STA_VDEVS := 2 + +# Additional peers sent to firmware +CONFIG_CFG_NUM_OF_ADDITIONAL_FW_PEERS := 0 + +# Number of TDLS peers that each Tdls vdev can track +CONFIG_CFG_NUM_OF_TDLS_CONN_TABLE_ENTRIES := 4 + +# Number of vdevs supported at one time, used for allocating memory +CONFIG_WLAN_MAX_VDEVS := 3 + +#Number of STA sessions max connected to our SAP, used for allocating memory +#should never be less then number of max peers - INI +CONFIG_SIR_SAP_MAX_NUM_PEERS := 10 + +#Max no of offloaded beaconing entities supported +CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV := 3 + +#Beacon offload config +CONFIG_WMI_BCN_OFFLOAD := y + +#Flag to enable Supported Operating class +CONFIG_HOST_OPCLASS := y + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM) $(CONFIG_QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK))) +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y +endif + +CONFIG_SAP_DHCP_FW_IND := n + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +#Enable PCIe Shadow Register +CONFIG_QCN7605_PCIE_SHADOW_REG_SUPPORT := y + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515) $(CONFIG_ARCH_SDXPOORWILLS) $(CONFIG_ARCH_SA515M))) +CONFIG_MOBILE_ROUTER := y +endif + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := n +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := n +else +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +CONFIG_WLAN_SYSFS_MEM_STATS := y +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.pci.debug_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.pci.debug_defconfig new file mode 100644 index 0000000000..c25c05a77d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.pci.debug_defconfig @@ -0,0 +1,136 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +CONFIG_ROME_PCIE := n + +# Interface specific features +CONFIG_ROME_IF = pci +CONFIG_QMI_SUPPORT := y +CONFIG_HIF_PCI := y + +ifeq ($(CONFIG_PCI_MSM), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif + +# Data Path specific features +CONFIG_WLAN_FASTPATH := y +CONFIG_WLAN_NAPI := y +CONFIG_ATH_11AC_TXCOMPACT := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_QCA_LL_TX_FLOW_CONTROL_RESIZE := y +CONFIG_LL_DP_SUPPORT := y +CONFIG_DATA_CE_SW_INDEX_NO_INLINE_UPDATE := n + +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +else +CONFIG_IPA_DISABLE_OVERRIDE=y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +else +CONFIG_IPA_DISABLE_OVERRIDE=y +endif + +# Debug specific features +CONFIG_FEATURE_EPPING := y +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +# Features gets enabled on slub debug +CONFIG_FEATURE_PKTLOG := y +CONFIG_WLAN_DEBUG_CRASH_INJECT := y +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := y + CONFIG_WLAN_POWER_DEBUGFS := y +endif + +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PTP := y + CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) + CONFIG_WLAN_FEATURE_MIB_STATS := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_DESC_DUP_DETECT_DEBUG := y +CONFIG_DEBUG_RX_RING_BUFFER := y +CONFIG_WLAN_OBJMGR_DEBUG:= y +CONFIG_FEATURE_UNIT_TEST_SUSPEND := y +CONFIG_LEAK_DETECTION := y +CONFIG_HIF_DEBUG := y +CONFIG_HIF_LARGE_CE_RING_HISTORY := 8192 +endif +CONFIG_RX_PERFORMANCE := y + +# Genoa features vs Rome PCIe +ifeq ($(CONFIG_ROME_PCIE), y) +CONFIG_CHNL_MATRIX_RESTRICTION := y +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +else +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +CONFIG_FEATURE_TSO_DEBUG := y +CONFIG_FEATURE_TSO := y +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y + +CONFIG_QCN7605_SUPPORT := y +CONFIG_HIF_REG_WINDOW_SUPPORT := y + +ifneq ($(CONFIG_X86), y) +ifeq ($(CONFIG_INET_LRO), y) +CONFIG_WLAN_LRO := y +else +CONFIG_WLAN_LRO := n +endif +endif + +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif + +endif # CONFIG_ROME_PCIE + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), m) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +CONFIG_QCA_WIFI_FTM := y +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif +CONFIG_LINUX_QCMBR :=y +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.pci.perf_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.pci.perf_defconfig new file mode 100644 index 0000000000..66961d7efd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.pci.perf_defconfig @@ -0,0 +1,135 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +CONFIG_ROME_PCIE := n + +# Interface specific features +CONFIG_ROME_IF = pci +CONFIG_QMI_SUPPORT := y +CONFIG_HIF_PCI := y + +ifeq ($(CONFIG_PCI_MSM), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif + +# Data Path specific features +CONFIG_WLAN_FASTPATH := y +CONFIG_WLAN_NAPI := y +CONFIG_ATH_11AC_TXCOMPACT := y +CONFIG_QCA_LL_TX_FLOW_CONTROL_RESIZE := y +CONFIG_LL_DP_SUPPORT := y +CONFIG_DATA_CE_SW_INDEX_NO_INLINE_UPDATE := n + +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif + +# Debug specific features +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_WLAN_LOG_ENTER := n +CONFIG_WLAN_LOG_EXIT := n + +# Features gets enabled on slub debug +CONFIG_FEATURE_PKTLOG := y +CONFIG_WLAN_DEBUG_CRASH_INJECT := n +CONFIG_FEATURE_MEMDUMP_ENABLE := n + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := n + CONFIG_WLAN_POWER_DEBUGFS := n +endif + +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PTP := y + CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_IRQ := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_DESC_DUP_DETECT_DEBUG := n +CONFIG_DEBUG_RX_RING_BUFFER := n +CONFIG_WLAN_OBJMGR_DEBUG:= n +CONFIG_FEATURE_UNIT_TEST_SUSPEND := n +CONFIG_LEAK_DETECTION := n +endif + +# Genoa features vs Rome PCIe +ifeq ($(CONFIG_ROME_PCIE), y) +CONFIG_CHNL_MATRIX_RESTRICTION := y +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +else +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := n +CONFIG_FEATURE_TSO_DEBUG := n +CONFIG_FEATURE_TSO := y +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y + +CONFIG_QCN7605_SUPPORT := y +CONFIG_HIF_REG_WINDOW_SUPPORT := y + +ifneq ($(CONFIG_X86), y) +ifeq ($(CONFIG_INET_LRO), y) +CONFIG_WLAN_LRO := y +else +CONFIG_WLAN_LRO := n +endif +endif + +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif + +endif # CONFIG_ROME_PCIE + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), m) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +CONFIG_QCA_WIFI_FTM := n +QCA_WIFI_FTM_NL80211 := n +CONFIG_LINUX_QCMBR := n + +################################### +CONFIG_ENABLE_SIZE_OPTIMIZE := y + +# configure log buffer size +CONFIG_CFG_NUM_DP_TRACE_RECORD := 1000 +CONFIG_CFG_NUM_HTC_CREDIT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_TX_RX_HISTOGRAM := 16 +CONFIG_CFG_NUM_RX_IND_RECORD := 1024 + +ifeq ($(CONFIG_FEATURE_ROAM_DEBUG), y) +CONFIG_CFG_NUM_ROAM_DEBUG_RECORD := 64 +endif +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.sdio.debug_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.sdio.debug_defconfig new file mode 100644 index 0000000000..2ffe212fc8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.sdio.debug_defconfig @@ -0,0 +1,59 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +# Interface specific features +CONFIG_CLD_HL_SDIO_CORE := y +CONFIG_QCA_WIFI_SDIO := y +CONFIG_ROME_IF = sdio +CONFIG_HIF_SDIO := y +CONFIG_LINUX_QCMBR := y +CONFIG_SDIO_TRANSFER = adma +CONFIG_PLD_SDIO_CNSS2 := y + +# Data Path specific features +CONFIG_ATH_11AC_TXCOMPACT := n +CONFIG_QCA_HL_NETDEV_FLOW_CONTROL := y +CONFIG_TX_RESOURCE_HIGH_TH_IN_PER := 8 +CONFIG_TX_RESOURCE_LOW_TH_IN_PER := 2 +CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y +CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING := y +CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE := y +CONFIG_HL_DP_SUPPORT := y + +# Debug specific features +CONFIG_FEATURE_EPPING := y +CONFIG_WLAN_FEATURE_P2P_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := y + CONFIG_WLAN_POWER_DEBUGFS := y +endif + +# Features gets enabled on slub debug +CONFIG_FEATURE_PKTLOG := y +CONFIG_WLAN_DEBUG_CRASH_INJECT := y +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_WLAN_OBJMGR_DEBUG:= y +CONFIG_FEATURE_UNIT_TEST_SUSPEND := y +CONFIG_LEAK_DETECTION := y +endif + +# Genoa features vs Rome +CONFIG_HTT_PADDR64 := y + +CONFIG_QCA_WIFI_FTM := y +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif +CONFIG_LINUX_QCMBR :=y +CONFIG_TGT_NUM_MSDU_DESC := 0 +CONFIG_QCN7605_SUPPORT := y +CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT := y +CONFIG_CFG_TGT_AST_SKID_LIMIT := 16 +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.sdio.perf_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.sdio.perf_defconfig new file mode 100644 index 0000000000..69ef6662bf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.sdio.perf_defconfig @@ -0,0 +1,64 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +# Interface specific features +CONFIG_CLD_HL_SDIO_CORE := y +CONFIG_QCA_WIFI_SDIO := y +CONFIG_ROME_IF = sdio +CONFIG_HIF_SDIO := y +CONFIG_LINUX_QCMBR := y +CONFIG_SDIO_TRANSFER = adma +CONFIG_PLD_SDIO_CNSS2 := y + +# Data Path specific features +CONFIG_ATH_11AC_TXCOMPACT := n +CONFIG_QCA_HL_NETDEV_FLOW_CONTROL := y +CONFIG_TX_RESOURCE_HIGH_TH_IN_PER := 8 +CONFIG_TX_RESOURCE_LOW_TH_IN_PER := 2 +CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y +CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING := y +CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE := y +CONFIG_HL_DP_SUPPORT := y + +# Debug specific features +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_WLAN_LOG_ENTER := n +CONFIG_WLAN_LOG_EXIT := n + +# Features gets enabled on slub debug +CONFIG_FEATURE_PKTLOG := y +CONFIG_WLAN_DEBUG_CRASH_INJECT := n +CONFIG_FEATURE_MEMDUMP_ENABLE := n + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_WLAN_OBJMGR_DEBUG:= n +CONFIG_FEATURE_UNIT_TEST_SUSPEND := n +CONFIG_LEAK_DETECTION := n +endif + +# Genoa features vs Rome +CONFIG_HTT_PADDR64 := y + +CONFIG_ENABLE_SIZE_OPTIMIZE := y + +# configure log buffer size +CONFIG_CFG_NUM_DP_TRACE_RECORD := 1000 +CONFIG_CFG_NUM_HTC_CREDIT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_TX_RX_HISTOGRAM := 16 +CONFIG_CFG_NUM_RX_IND_RECORD := 1024 + +ifeq ($(CONFIG_FEATURE_ROAM_DEBUG), y) +CONFIG_CFG_NUM_ROAM_DEBUG_RECORD := 64 +endif + +CONFIG_QCA_WIFI_FTM := n +QCA_WIFI_FTM_NL80211 := n +CONFIG_LINUX_QCMBR := n +CONFIG_TGT_NUM_MSDU_DESC := 0 +CONFIG_QCN7605_SUPPORT := y +CONFIG_QCA_TX_PADDING_CREDIT_SUPPORT := y +CONFIG_CFG_TGT_AST_SKID_LIMIT := 16 +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.snoc.debug_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.snoc.debug_defconfig new file mode 100644 index 0000000000..aca99dc7b9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.snoc.debug_defconfig @@ -0,0 +1,87 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +# Interface specific features +CONFIG_ROME_IF = snoc +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_QMI_SUPPORT := y +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +CONFIG_HTT_PADDR64 := y +CONFIG_HIF_SNOC:= y + +# Genoa specific features +CONFIG_QCA_LL_TX_FLOW_CONTROL_RESIZE := y + +# Data Path specific features +CONFIG_WLAN_FASTPATH := y +CONFIG_FEATURE_TSO := y +CONFIG_WLAN_NAPI := y +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +CONFIG_ATH_11AC_TXCOMPACT := y +CONFIG_RX_OL := y +CONFIG_DESC_DUP_DETECT_DEBUG := y +CONFIG_DEBUG_RX_RING_BUFFER := y +CONFIG_LL_DP_SUPPORT := y + +ifeq ($(CONFIG_INET_LRO), y) +CONFIG_WLAN_LRO := y +else +CONFIG_WLAN_LRO := n +endif + +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif + +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif + +# Debug specific features +CONFIG_FEATURE_TSO_DEBUG := y +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := y +CONFIG_FEATURE_EPPING := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +# Features gets enabled on slub debug +CONFIG_WLAN_OBJMGR_DEBUG:= y +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +CONFIG_FEATURE_PKTLOG := y +CONFIG_WLAN_DEBUG_CRASH_INJECT := y +CONFIG_FEATURE_MEMDUMP_ENABLE := y +CONFIG_FEATURE_UNIT_TEST_SUSPEND := y +CONFIG_LEAK_DETECTION := y + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := y + CONFIG_WLAN_POWER_DEBUGFS := y +endif + +# other features +CONFIG_QCA_WIFI_FTM := y +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif +CONFIG_LINUX_QCMBR :=y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.snoc.perf_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.snoc.perf_defconfig new file mode 100644 index 0000000000..35836037df --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.snoc.perf_defconfig @@ -0,0 +1,96 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +# Interface specific features +CONFIG_ROME_IF = snoc +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_QMI_SUPPORT := y +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +CONFIG_HTT_PADDR64 := y +CONFIG_HIF_SNOC:= y + +# Genoa specific features +CONFIG_QCA_LL_TX_FLOW_CONTROL_RESIZE := y + +# Data Path specific features +CONFIG_WLAN_FASTPATH := y +CONFIG_FEATURE_TSO := y +CONFIG_WLAN_NAPI := y +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +CONFIG_ATH_11AC_TXCOMPACT := y +CONFIG_RX_OL := y +CONFIG_DESC_DUP_DETECT_DEBUG := n +CONFIG_DEBUG_RX_RING_BUFFER := n +CONFIG_LL_DP_SUPPORT := y + +ifeq ($(CONFIG_INET_LRO), y) +CONFIG_WLAN_LRO := y +else +CONFIG_WLAN_LRO := n +endif + +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif + +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif + +CONFIG_FEATURE_TSO_DEBUG := n +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_LOG_ENTER := n +CONFIG_WLAN_LOG_EXIT := n + +CONFIG_QCA_WIFI_FTM := n +QCA_WIFI_FTM_NL80211 := n +CONFIG_LINUX_QCMBR := n + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +# Features gets enabled on slub debug +CONFIG_WLAN_OBJMGR_DEBUG:= n +CONFIG_FEATURE_MEMDUMP_ENABLE := n +CONFIG_FEATURE_UNIT_TEST_SUSPEND := n +CONFIG_OL_RX_INDICATION_RECORD := n +CONFIG_TSOSEG_DEBUG := n +CONFIG_FEATURE_PKTLOG := n +CONFIG_WLAN_DEBUG_CRASH_INJECT := n +CONFIG_LEAK_DETECTION := n + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := n + CONFIG_WLAN_POWER_DEBUGFS := n +endif + +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +CONFIG_ENABLE_SIZE_OPTIMIZE := y + +# configure log buffer size +CONFIG_CFG_NUM_DP_TRACE_RECORD := 1000 +CONFIG_CFG_NUM_HTC_CREDIT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_TX_RX_HISTOGRAM := 16 +CONFIG_CFG_NUM_RX_IND_RECORD := 1024 + +ifeq ($(CONFIG_FEATURE_ROAM_DEBUG), y) +CONFIG_CFG_NUM_ROAM_DEBUG_RECORD := 64 +endif +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.usb.debug_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.usb.debug_defconfig new file mode 100644 index 0000000000..756055ba29 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.usb.debug_defconfig @@ -0,0 +1,68 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +# Interface specific features +CONFIG_ROME_IF := usb +CONFIG_HIF_USB := y +CONFIG_LINUX_QCMBR := y +CONFIG_PLD_USB_CNSS := y + +# Data Path specific features +CONFIG_ATH_11AC_TXCOMPACT := n +CONFIG_QCA_HL_NETDEV_FLOW_CONTROL := y +CONFIG_TX_RESOURCE_HIGH_TH_IN_PER := 8 +CONFIG_TX_RESOURCE_LOW_TH_IN_PER := 2 +CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y +CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING := y +CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE := y +CONFIG_WLAN_SUPPORT_TXRX_HL_BUNDLE := y +CONFIG_HL_DP_SUPPORT := y + +# Enable Motion Detection Feature +CONFIG_FEATURE_MOTION_DETECTION := y + +# Debug specific features +CONFIG_FEATURE_EPPING := y +CONFIG_WLAN_FEATURE_P2P_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := y + CONFIG_WLAN_POWER_DEBUGFS := y +endif + +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PTP := y +endif + +CONFIG_WLAN_SYNC_TSF_PLUS := y +CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_SYNC := y + +# Features gets enabled on slub debug +CONFIG_WLAN_DEBUG_CRASH_INJECT := y +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_WLAN_OBJMGR_DEBUG:= y +CONFIG_FEATURE_UNIT_TEST_SUSPEND := y +CONFIG_LEAK_DETECTION := y +endif + +# Genoa features vs Rome +CONFIG_HTT_PADDR64 := y + +CONFIG_QCA_WIFI_FTM := y +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif +CONFIG_LINUX_QCMBR :=y +CONFIG_QCN7605_SUPPORT := y +CONFIG_TGT_NUM_MSDU_DESC := 0 +# For OOB wakeup +CONFIG_WLAN_FEATURE_WOW_PULSE := y +CONFIG_HTC_MAX_MSG_PER_BUNDLE_TX := 48 +CONFIG_CFG_TGT_AST_SKID_LIMIT := 16 +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/genoa.usb.perf_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.usb.perf_defconfig new file mode 100644 index 0000000000..583f29a807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/genoa.usb.perf_defconfig @@ -0,0 +1,78 @@ + +include $(WLAN_ROOT)/configs/genoa.common + +# Interface specific features +CONFIG_ROME_IF := usb +CONFIG_HIF_USB := y +CONFIG_LINUX_QCMBR := y +CONFIG_PLD_USB_CNSS := y + +# Data Path specific features +CONFIG_ATH_11AC_TXCOMPACT := n +CONFIG_QCA_HL_NETDEV_FLOW_CONTROL := y +CONFIG_TX_RESOURCE_HIGH_TH_IN_PER := 8 +CONFIG_TX_RESOURCE_LOW_TH_IN_PER := 2 +CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y +CONFIG_FEATURE_HL_DBS_GROUP_CREDIT_SHARING := y +CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE := y +CONFIG_WLAN_SUPPORT_TXRX_HL_BUNDLE := y +CONFIG_HL_DP_SUPPORT := y + +# Enable Motion Detection Feature +CONFIG_FEATURE_MOTION_DETECTION := y + +# Debug specific features +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_WLAN_LOG_ENTER := n +CONFIG_WLAN_LOG_EXIT := n + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := y + CONFIG_WLAN_POWER_DEBUGFS := y +endif + +# Features gets enabled on slub debug +CONFIG_WLAN_DEBUG_CRASH_INJECT := n +CONFIG_FEATURE_MEMDUMP_ENABLE := n + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_WLAN_OBJMGR_DEBUG:= n +CONFIG_FEATURE_UNIT_TEST_SUSPEND := n +CONFIG_LEAK_DETECTION := n +endif + +ifeq ($(CONFIG_NETWORK_PHY_TIMESTAMPING), y) + CONFIG_WLAN_SYNC_TSF_PTP := y +endif + +CONFIG_WLAN_SYNC_TSF_PLUS := y +CONFIG_WLAN_SYNC_TSF_PLUS_EXT_GPIO_SYNC := y + +CONFIG_ENABLE_SIZE_OPTIMIZE := y + +# configure log buffer size +CONFIG_CFG_NUM_DP_TRACE_RECORD := 1000 +CONFIG_CFG_NUM_HTC_CREDIT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_TX_RX_HISTOGRAM := 16 +CONFIG_CFG_NUM_RX_IND_RECORD := 1024 + +ifeq ($(CONFIG_FEATURE_ROAM_DEBUG), y) +CONFIG_CFG_NUM_ROAM_DEBUG_RECORD := 64 +endif + +# Genoa features vs Rome +CONFIG_HTT_PADDR64 := y + +CONFIG_QCA_WIFI_FTM := n +QCA_WIFI_FTM_NL80211 := n +CONFIG_LINUX_QCMBR := n +CONFIG_QCN7605_SUPPORT := y +CONFIG_TGT_NUM_MSDU_DESC := 0 +# For OOB wakeup +CONFIG_WLAN_FEATURE_WOW_PULSE := y +CONFIG_HTC_MAX_MSG_PER_BUNDLE_TX := 48 +CONFIG_CFG_TGT_AST_SKID_LIMIT := 16 +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/kiwi_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/kiwi_defconfig new file mode 100644 index 0000000000..457d016d9a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/kiwi_defconfig @@ -0,0 +1,32 @@ +CONFIG_CNSS_KIWI := y +CONFIG_INCLUDE_HAL_KIWI := y + +include $(WLAN_ROOT)/configs/default_defconfig + +#Enable 11BE EHT +CONFIG_WLAN_FEATURE_11BE := y + +# Enable EHT rate sysfs entry +ifeq ($(CONFIG_WLAN_SYSFS), y) +CONFIG_WLAN_SYSFS_EHT_RATE := y +endif + +# Max Sta Vdev Config +CONFIG_CFG_MAX_STA_VDEVS := 4 + +#Enable 11BE MLO +CONFIG_WLAN_FEATURE_11BE_MLO := y + +#BMISS offload max vdev config +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV := 4 + +#Chip version +CONFIG_CHIP_VERSION := 1 + +#DP configs +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG := y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG := y + +ifeq ($(CONFIG_CNSS_KIWI_V2), y) + CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES := y +endif diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/kiwi_v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/kiwi_v2_defconfig new file mode 100644 index 0000000000..11ade73d3b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/kiwi_v2_defconfig @@ -0,0 +1,122 @@ +CONFIG_CNSS_KIWI := y +CONFIG_CNSS_KIWI_V2 := y +CONFIG_INCLUDE_HAL_KIWI := y + +ifeq ($(CONFIG_ARCH_SDXPINN), y) +CONFIG_MOBILE_ROUTER := y +CONFIG_WLAN_SYSFS := y +endif + +include $(WLAN_ROOT)/configs/default_defconfig + +#Enable 11BE EHT +CONFIG_WLAN_FEATURE_11BE := y + +#Enable IPA Optional wifi datapath feature +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +CONFIG_IPA_OPT_WIFI_DP := y +CONFIG_IPA_OFFLOAD := y +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +endif + +# Enable EHT rate sysfs entry +ifeq ($(CONFIG_WLAN_SYSFS), y) +CONFIG_WLAN_SYSFS_EHT_RATE := y +endif + +# Max Sta Vdev Config +CONFIG_CFG_MAX_STA_VDEVS := 4 + +#Enable 11BE MLO +CONFIG_WLAN_FEATURE_11BE_MLO := y + +#Enable Single NDEV Multi VDEV +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV := y + +#BMISS offload max vdev config +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV := 4 + +#Max MLD dev context +CONFIG_WLAN_UMAC_MLO_MAX_DEV := 3 + +#Chip version +CONFIG_CHIP_VERSION := 2 + +#DP configs +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG := y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG := y + +# Enable separate FW image +CONFIG_GET_DRIVER_MODE := y + +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES := y + +#Enable COEX feature +CONFIG_FEATURE_COEX := y + +#Enable DBAM feature +ifeq ($(CONFIG_FEATURE_COEX), y) +CONFIG_WLAN_FEATURE_COEX_DBAM := y +endif + +CONFIG_DP_TRAFFIC_END_INDICATION := y + +#Enable Constrained Application Protocol feature +CONFIG_WLAN_FEATURE_COAP := y + +#Enable TSF read using scratch register +CONFIG_QCA_GET_TSF_VIA_REG := y + +CONFIG_WLAN_FEATURE_AFFINITY_MGR := y + +#Enable per link stats support +CONFIG_DP_MLO_LINK_STATS_SUPPORT := y + +CONFIG_QCA_DFS_BW_PUNCTURE := y + +ifeq ($(CONFIG_ARCH_SDXPINN), y) +CONFIG_WLAN_UMAC_MLO_MAX_DEV := 4 + +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION := n +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION := n +CONFIG_DP_MEM_PRE_ALLOC := n +CONFIG_MORE_TX_DESC := n + +CONFIG_WIFI_MONITOR_SUPPORT := n +CONFIG_QCA_MONITOR_PKT_SUPPORT := n +CONFIG_MONITOR_MODULARIZED_ENABLE := y + +CONFIG_QCACLD_FEATURE_NAN := n +CONFIG_FEATURE_EPPING := n +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := n +CONFIG_WLAN_CFR_ENABLE := n + +CONFIG_BEACON_TX_OFFLOAD_MAX_VDEV := 4 +CONFIG_NUM_IPA_IFACE := 4 +CONFIG_MAX_CLIENTS_ALLOWED := 64 + +CONFIG_QDF_MAX_NO_OF_SAP_MODE := 4 + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +CONFIG_IPA_WDI3_TX_TWO_PIPES := y +endif # IPA_OFFLOAD + +CONFIG_WLAN_SYSFS_RANGE_EXT := n + +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 256 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 128 + +CONFIG_WLAN_FEATURE_COAP := n + +endif # ARCH_SDXPINN + +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +CONFIG_WLAN_TX_MON_2_0 := y +CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE := y +endif + +CONFIG_WLAN_FEATURE_LL_LT_SAP := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/mango_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/mango_defconfig new file mode 100644 index 0000000000..291d75aa6d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/mango_defconfig @@ -0,0 +1,45 @@ +CONFIG_CNSS_KIWI := y +CONFIG_CNSS_KIWI_V2 := y +CONFIG_CNSS_MANGO := y +CONFIG_INCLUDE_HAL_KIWI := y + +include $(WLAN_ROOT)/configs/default_defconfig + +#Enable 11BE EHT +CONFIG_WLAN_FEATURE_11BE := y + +# Enable EHT rate sysfs entry +ifeq ($(CONFIG_WLAN_SYSFS), y) +CONFIG_WLAN_SYSFS_EHT_RATE := y +endif + +# Max Sta Vdev Config +CONFIG_CFG_MAX_STA_VDEVS := 4 + +#Enable 11BE MLO +CONFIG_WLAN_FEATURE_11BE_MLO := y + +#BMISS offload max vdev config +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV := 4 + +#DP configs +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG := y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG := y + +# Enable separate FW image +CONFIG_GET_DRIVER_MODE := y + +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES := y + +#Enable COEX feature +CONFIG_FEATURE_COEX := y + +#Enable DBAM feature +ifeq ($(CONFIG_FEATURE_COEX), y) +CONFIG_WLAN_FEATURE_COEX_DBAM := y +endif + +CONFIG_DP_TRAFFIC_END_INDICATION := y + +#Enable Constrained Application Protocol feature +CONFIG_WLAN_FEATURE_COAP := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/niobe_consolidate_kiwi-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/niobe_consolidate_kiwi-v2_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/niobe_consolidate_kiwi-v2_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/niobe_gki_kiwi-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/niobe_gki_kiwi-v2_defconfig new file mode 100644 index 0000000000..ccae3b1c33 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/niobe_gki_kiwi-v2_defconfig @@ -0,0 +1,391 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=2 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_INCLUDE_HAL_KIWI=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="kiwi_v2" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_WLAN_TX_MON_2_0_Y_WLAN_DP_LOCAL_PKT_CAPTURE=y +CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0=y +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/parrot_consolidate_adrastea_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_consolidate_adrastea_defconfig new file mode 100644 index 0000000000..ea96d9cbbd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_consolidate_adrastea_defconfig @@ -0,0 +1,19 @@ +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE=y +CONFIG_QDF_NBUF_HISTORY_SIZE=4096 +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_QDF_TEST=y +CONFIG_FEATURE_WLM_STATS=y + diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/parrot_consolidate_qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_consolidate_qca6750_defconfig new file mode 100644 index 0000000000..c810b0a047 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_consolidate_qca6750_defconfig @@ -0,0 +1,28 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_FEATURE_WLM_STATS=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/parrot_gki_adrastea_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_gki_adrastea_defconfig new file mode 100644 index 0000000000..8f227cdfe5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_gki_adrastea_defconfig @@ -0,0 +1,251 @@ +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="adrastea" +CONFIG_CNSS_ADRASTEA=y +CONFIG_QCA_CLD_WLAN=y +CONFIG_ARCH_MSM=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_ROME_IF="snoc" +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_HELIUMPLUS=y +CONFIG_64BIT_PADDR=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_DEBUG=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_BUILD_TAG=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL=y +CONFIG_QCOM_TDLS=y +CONFIG_WLAN_SYSFS=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_DUMP_IN_PROGRESS=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_BMISS=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_PANIC_ON_BUG=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_WDS_MODE=y +CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_METERING=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_ADAPTIVE_11R=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_FEATURE_MSCS=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_FEATURE_EPPING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FASTPATH=y +CONFIG_WLAN_FASTPATH_LEGACY=y +CONFIG_QCA_SUPPORT_TX_THROTTLE_LEGACY=y +CONFIG_WLAN_NAPI=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2_HL=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LL_DP_SUPPORT_LEGACY=y +CONFIG_QMI_SUPPORT=y +CONFIG_WIFI_3_0_ADRASTEA=y +CONFIG_ADRASTEA_RRI_ON_DDR=y +CONFIG_ATH_PROCFS_DIAG_SUPPORT=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ADRASTEA_SHADOW_REGISTERS=y +CONFIG_AR900B=y +CONFIG_HTT_PADDR64=y +CONFIG_FEATURE_ENABLE_CE_DP_IRQ_AFFINE=y +CONFIG_FEATURE_PKTLOG=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_HIF_SNOC=y +CONFIG_PLD_SNOC_ICNSS_FLAG=y +CONFIG_ICNSS2_HELIUM=y +CONFIG_QCOM_ESE=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_ATH_BUS_PM=y +CONFIG_PKTLOG_LEGACY=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_SEND_DSCP_UP_MAP_TO_FW=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_LINUX_QCMBR=y +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_GTK_OFFLOAD=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_WEXT_SUPPORT_ENABLE=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_WBUFF=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_LTE_COEX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_HOST_OPCLASS=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_FEATURE_SET=y +CONFIG_WLAN_FEATURE_LL_LT_SAP=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_CP_STATS=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_SUPPORT_11AX=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_SPECTRAL_ENABLE=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_DP_TRACE=y +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING=y +CONFIG_RX_OL=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_CHANNEL_HOPPING_ALL_BANDS=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_PKT_LOG=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y + diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/parrot_gki_qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_gki_qca6750_defconfig new file mode 100644 index 0000000000..f01356e9b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/parrot_gki_qca6750_defconfig @@ -0,0 +1,331 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CNSS2_MODULE=y +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE=1 +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_SWLM=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_TX_TRACKING=y +CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_AST=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_PKTLOG=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_DEBUG=y +CONFIG_HIF_IPCI=y +CONFIG_HOST_OPCLASS=y +CONFIG_HOST_WAKEUP_OVER_QMI=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITHIUM=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_PANIC_ON_BUG=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA6750_HEADERS_DEF=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_QCA_WIFI_QCA6750=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_ROME_IF="ipci" +CONFIG_PLD_IPCI_ICNSS_FLAG=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V2=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_PROFILE_SUPPORT=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SPECTRAL_ENABLE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WDS_MODE=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_MULTI_IF_NAME="qca6750" +CONFIG_CNSS_QCA6750=y +CONFIG_BUILD_TAG=y +CONFIG_DP_RX_DESC_COOKIE_INVALIDATE=y +CONFIG_FEATURE_COEX=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/peach_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/peach_defconfig new file mode 100644 index 0000000000..00f68be83e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/peach_defconfig @@ -0,0 +1,938 @@ +CONFIG_CNSS_PEACH := y +CONFIG_CNSS_KIWI := y +CONFIG_CNSS_KIWI_V2 := y +CONFIG_INCLUDE_HAL_PEACH := y + +#Enable 11BE EHT +CONFIG_WLAN_FEATURE_11BE := y + +# Max Sta Vdev Config +CONFIG_CFG_MAX_STA_VDEVS := 4 + +#Enable 11BE MLO +CONFIG_WLAN_FEATURE_11BE_MLO := y + +#BMISS offload max vdev config +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV := 4 + +#Max MLD dev context +CONFIG_WLAN_UMAC_MLO_MAX_DEV := 3 + +#Chip version +CONFIG_CHIP_VERSION := 1 + +#DP configs +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG := y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG := y + +# Enable separate FW image +CONFIG_GET_DRIVER_MODE := y + +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES := y + +#Enable COEX feature +CONFIG_FEATURE_COEX := y + +#Enable DBAM feature +CONFIG_WLAN_FEATURE_COEX_DBAM := y + +CONFIG_DP_TRAFFIC_END_INDICATION := y + +#Enable Constrained Application Protocol feature +CONFIG_WLAN_FEATURE_COAP := y + +#Enable TSF read using scratch register +CONFIG_QCA_GET_TSF_VIA_REG := y + +CONFIG_HANDLE_RX_REROUTE_ERR := y + +#Enable DP Bus Vote +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y + +#Enable KIWI based Configs +ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y + CONFIG_SAP_MULTI_LINK_EMULATION := y +endif +CONFIG_EMULATION_2_0 := y +CONFIG_DIRECT_BUF_RX_ENABLE := y +CONFIG_WMI_DBR_SUPPORT := y +CONFIG_WLAN_CFR_ENABLE := y +CONFIG_WLAN_ENH_CFR_ENABLE := y +CONFIG_BERYLLIUM := y +CONFIG_WLAN_FEATURE_11AX := y +CONFIG_WLAN_FEATURE_SR := y +CONFIG_OBSS_PD := y +CONFIG_WLAN_TWT_SAP_STA_COUNT := y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT := y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y +CONFIG_DP_BE_WAR := y +CONFIG_SCALE_INCLUDES := y +CONFIG_HASTINGS_BT_WAR := y +CONFIG_WDI3_IPA_OVER_GSI := y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y +CONFIG_PCIE_GEN_SWITCH := y +CONFIG_ATH_SUPPORT_SPECTRAL := n +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION := y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION := y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ := y +CONFIG_WLAN_SYSFS_DP_STATS := y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH := y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR := y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ := y +CONFIG_TX_ADDR_INDEX_SEARCH := y +CONFIG_DP_CON_MON_MSI_ENABLED := y +CONFIG_DEVICE_FORCE_WAKE_ENABLE :=y +CONFIG_HIF_REG_WINDOW_SUPPORT :=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE := y +CONFIG_TX_MULTI_TCL := y +CONFIG_OFDM_SCRAMBLER_SEED := y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO := y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7 := y +CONFIG_WLAN_TSF_UPLINK_DELAY := y +CONFIG_WLAN_SYNC_TSF_PLUS := y +CONFIG_WLAN_SYNC_TSF_TIMER := y +CONFIG_WIFI_POS_PASN := y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING := y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF := y +CONFIG_DP_PKT_STATS_PER_LMAC := y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y +CONFIG_DP_RX_BUFFER_POOL_SIZE := 128 +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES := 5 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 512 +CONFIG_NO_RX_PKT_HDR_TLV := y +ifeq ($(CONFIG_DP_CON_MON_MSI_ENABLED), y) + CONFIG_DP_CON_MON_MSI_SKIP_SET := y +endif +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT := y +CONFIG_WLAN_FEATURE_MCC_QUOTA := y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE := y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC := y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG := y +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y +CONFIG_RX_FISA := y +CONFIG_MORE_TX_DESC := y + +#Enable Berrylium based Configs +CONFIG_FIX_TXDMA_LIMITATION := y +CONFIG_PEER_PROTECTED_ACCESS := y +CONFIG_SERIALIZE_QUEUE_SETUP := y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER := y +CONFIG_DP_RX_DROP_RAW_FRM := y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP := y +CONFIG_DP_RX_SPECIAL_FRAME_NEED := y +CONFIG_FEATURE_STATS_EXT_V2 := y +CONFIG_WLAN_FEATURE_DP_RX_THREADS := y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT := y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT := y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR := y +CONFIG_ENABLE_HAL_SOC_STATS := y +CONFIG_ENABLE_HAL_REG_WR_HISTORY := y +CONFIG_MON_ENABLE_DROP_FOR_MAC := y +CONFIG_PCI_LINK_STATUS_SANITY := y +CONFIG_DDP_MON_RSSI_IN_DBM := y +CONFIG_SYSTEM_PM_CHECK := y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD := y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER := y +CONFIG_FEATURE_AST := n +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_QCA_MONITOR_PKT_SUPPORT := y +CONFIG_MONITOR_MODULARIZED_ENABLE := n +#Flag to enable Legacy Fast Roaming3(LFR3) +CONFIG_QCACLD_WLAN_LFR3 := y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE := y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY := y +CONFIG_DYNAMIC_RX_AGGREGATION := y +CONFIG_WLAN_SUPPORT_DATA_STALL := y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG := y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG := y +#Enable WMI TX/RX over QMI +CONFIG_WMI_SEND_RECV_QMI := y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH := y +CONFIG_WLAN_SKIP_BAR_UPDATE := y +CONFIG_TX_MULTIQ_PER_AC := y +CONFIG_WLAN_TRACEPOINTS := y +ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST := y +# Flag to enable FW based TX Flow control +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT := y +CONFIG_MARK_ICMP_REQ_TO_FW := y +CONFIG_IPA_SET_RESET_TX_DB_PA := y +# Enable fw stats version 2 +CONFIG_AR900B := y +# Enable Shadow V3 for all Beryllium platform +CONFIG_SHADOW_V3 := y +#Disable pktlog feature for Beryllium based target +CONFIG_FEATURE_PKTLOG := n +#Disable packet log +CONFIG_REMOVE_PKT_LOG := y +#Customize DSCP_to-UP map based on RFC8325 +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y +CONFIG_WAPI_BIG_ENDIAN := y +CONFIG_WLAN_FEATURE_BMI := n +CONFIG_LL_DP_SUPPORT := y +CONFIG_LL_DP_SUPPORT := y +#Define the legacy pktlog +CONFIG_PKTLOG_LEGACY := n +# Enable VERBOSE debug INI mechanism +CONFIG_VERBOSE_DEBUG := y +CONFIG_RX_DESC_SANITY_WAR := y +ifeq ($(CONFIG_PCI_MSM), $(filter $(CONFIG_PCI_MSM), m y)) + CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := y +endif + +CONFIG_KIWI_HEADERS_DEF := y +CONFIG_QCA_WIFI_KIWI := y + +CONFIG_QCA_WIFI_QCA8074 := y +CONFIG_QCA_WIFI_QCA8074_VP := y +CONFIG_DP_INTR_POLL_BASED := y +CONFIG_TX_PER_PDEV_DESC_POOL := y +CONFIG_DP_TRACE := y +CONFIG_FEATURE_TSO := y +CONFIG_FEATURE_FORCE_WAKE := y +CONFIG_DP_LFR := y +CONFIG_DUP_RX_DESC_WAR := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y +CONFIG_TX_TID_OVERRIDE := y +CONFIG_DP_TXRX_SOC_ATTACH := y +ifeq ($(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH), y) + CONFIG_WLAN_CLD_PM_QOS := y +endif +CONFIG_WLAN_CLD_DEV_PM_QOS := y +CONFIG_DISABLE_DP_STATS := n +CONFIG_MAX_ALLOC_PAGE_SIZE := y +CONFIG_REO_DESC_DEFER_FREE := y +CONFIG_RXDMA_ERR_PKT_DROP := y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK := y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS := n +CONFIG_WLAN_TRACE_HIDE_SSID := n +CONFIG_DP_MEM_PRE_ALLOC := y +CONFIG_FEATURE_GPIO_CFG := y +ifeq ($(CONFIG_FEATURE_TSO), y) + CONFIG_FEATURE_TSO_STATS := y + CONFIG_TSO_DEBUG_LOG_ENABLE := y +endif +ifeq ($(CONFIG_DISABLE_DP_STATS), y) + CONFIG_FEATURE_TSO_STATS := n +endif + +ifeq ($(CONFIG_CNSS2), m) + CONFIG_CNSS2_MODULE := y +endif +ifeq ($(CONFIG_CNSS_GENL), m) + CONFIG_CNSS_GENL_MODULE := y +endif +ifeq ($(CONFIG_CNSS_UTILS), m) + CONFIG_CNSS_UTILS_MODULE := y +endif +ifeq ($(CONFIG_WCNSS_MEM_PRE_ALLOC), m) + CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE := y +endif + +ifdef CONFIG_IPCIE_FW_SIM + CONFIG_ROME_IF = ipci + CONFIG_PLD_IPCI_ICNSS_FLAG := n +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS_MODULE) $(CONFIG_CNSS2) $(CONFIG_CNSS2_MODULE))) +ifndef CONFIG_ROME_IF + #use pci as default interface +ifndef CONFIG_IPCIE_FW_SIM + CONFIG_ROME_IF = pci +endif +endif +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := y + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +CONFIG_WLAN_FEATURE_MBSSID := y +CONFIG_WLAN_FEATURE_P2P_P2P_STA := y + +#Flag to enable Dynamic MAC address update +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE := y + +#Flag to enable hdd memory dump feature +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +#Flag to enable/disable WLAN D0-WOW +ifeq ($(CONFIG_PCI_MSM), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Flag to enable TDLS feature +CONFIG_QCOM_TDLS := y + +CONFIG_WLAN_SYSFS := y + +CONFIG_THERMAL_STATS_SUPPORT := y + +ifeq ($(CONFIG_WLAN_SYSFS), y) + CONFIG_WLAN_SYSFS_STA_INFO := y + CONFIG_WLAN_SYSFS_CHANNEL := y + CONFIG_WLAN_SYSFS_FW_MODE_CFG := y + CONFIG_WLAN_SYSFS_MEM_STATS := y + CONFIG_WLAN_REASSOC := y + CONFIG_WLAN_SYSFS_CONNECT_INFO := y + CONFIG_WLAN_SCAN_DISABLE := y + CONFIG_WLAN_SYSFS_DCM := y + CONFIG_WLAN_WOW_ITO := y + CONFIG_WLAN_WOWL_ADD_PTRN := y + CONFIG_WLAN_WOWL_DEL_PTRN := y + CONFIG_WLAN_SYSFS_TX_STBC := y + CONFIG_WLAN_SYSFS_WLAN_DBG := y + CONFIG_WLAN_TXRX_FW_ST_RST := y + CONFIG_WLAN_GTX_BW_MASK := y + CONFIG_WLAN_SYSFS_SCAN_CFG := y + CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL := y + CONFIG_WLAN_SYSFS_RADAR := y + CONFIG_WLAN_SYSFS_RTS_CTS := y + CONFIG_WLAN_SYSFS_HE_BSS_COLOR := y + CONFIG_WLAN_TXRX_FW_STATS := y + CONFIG_WLAN_TXRX_STATS := y + CONFIG_WLAN_SYSFS_DP_TRACE := y + CONFIG_WLAN_SYSFS_STATS := y +ifeq ($(CONFIG_QCOM_TDLS), y) + CONFIG_WLAN_SYSFS_TDLS_PEERS := y +endif + CONFIG_WLAN_SYSFS_TEMPERATURE := y + CONFIG_WLAN_THERMAL_CFG := y + CONFIG_WLAN_DL_MODES := y + CONFIG_WLAN_DUMP_IN_PROGRESS := n + CONFIG_WLAN_BMISS := y + CONFIG_WLAN_FREQ_LIST := y + CONFIG_DP_PKT_ADD_TIMESTAMP := y + CONFIG_WLAN_SYSFS_RANGE_EXT := y + # Enable EHT rate sysfs entry + CONFIG_WLAN_SYSFS_EHT_RATE := y + CONFIG_WLAN_SYSFS_LOG_BUFFER := y +endif +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM := y +CONFIG_WLAN_POWER_DEBUG := y +#Enable Beacon Reception Stats +CONFIG_FEATURE_BECN_STATS := y +#Flag to enable NAN +CONFIG_QCACLD_FEATURE_NAN := y +endif + +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y + +CONFIG_QCACLD_FEATURE_GREEN_AP := y + +#Flag to enable pre cac feature +CONFIG_FEATURE_WLAN_PRE_CAC := y + +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := y + +#Flag to enable get firmware state +CONFIG_QCACLD_FEATURE_FW_STATE := y + +#Flag to enable set coex configuration +CONFIG_QCACLD_FEATURE_COEX_CONFIG := n + +#Flag to enable Fast Transition (11r) feature +CONFIG_QCOM_VOWIFI_11R := y + +#Flag to enable disable ACTION OUI feature +CONFIG_WLAN_FEATURE_ACTION_OUI := y + +#Flag to enable Adaptive 11r feature +CONFIG_ADAPTIVE_11R := y + +#Flag to enable sae single pmk feature +CONFIG_SAE_SINGLE_PMK := y + +#Flag to enable/disable multi client low latency feature support +CONFIG_MULTI_CLIENT_LL_SUPPORT := y + +#Flag to enable/disable vendor handoff feature support +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL := y + +#Flag to enable mscs feature +CONFIG_FEATURE_MSCS := y + +#Flag to enable FILS Feature (11ai) +CONFIG_WLAN_FEATURE_FILS := y +ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS_MODULE) $(CONFIG_CNSS2) \ + $(CONFIG_CNSS2_MODULE) $(CONFIG_ICNSS) $(CONFIG_ICNSS_MODULE) \ + $(CONFIG_ICNSS2) $(CONFIG_ICNSS2_MODULE))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif +endif + +CONFIG_FEATURE_EPPING := y + +#Flag to enable offload packets feature +CONFIG_WLAN_OFFLOAD_PACKETS := y + +#enable TSF get feature +CONFIG_WLAN_SYNC_TSF := y + +#Flag to enable SAE +CONFIG_WLAN_FEATURE_SAE := y + +#Flag to enable DISA +CONFIG_WLAN_FEATURE_DISA := y + +#Flag to enable FIPS +CONFIG_WLAN_FEATURE_FIPS := y + +# Flag to enable NAPI +CONFIG_WLAN_NAPI := y +CONFIG_WLAN_NAPI_DEBUG := n + +CONFIG_POWER_MANAGEMENT_OFFLOAD := y + +# Flag to enable LFR Subnet Detection +CONFIG_LFR_SUBNET_DETECTION := y + +# Flag to enable MCC to SCC switch feature +CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + # Enable Obj Mgr Degug services if slub build + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_LOCK_STATS_ON:= y + CONFIG_WLAN_OBJMGR_REF_ID_TRACE := y +endif + + +ifeq ($(CONFIG_ROME_IF),pci) +ifneq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM))) +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +endif +endif +endif + +#Whether have QMI support +CONFIG_QMI_SUPPORT := y + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG=y + +# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QCOMs internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. +ifneq ($(TARGET_BUILD_VARIANT),user) + CONFIG_FEATURE_PKTLOG := y + CONFIG_WLAN_DEBUG_CRASH_INJECT := y +endif + +#Enable WLAN/Power debugfs feature only if debug_fs is enabled +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y + + # Flag to enable streamfs. Depends on CONFIG_DEBUG_FS and + # CONFIG_RELAY in kernel configuration. +ifeq ($(CONFIG_RELAY), y) + CONFIG_WLAN_STREAMFS := y +endif +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) + CONFIG_WLAN_MWS_INFO_DEBUGFS := y + CONFIG_WLAN_FEATURE_MIB_STATS := y +endif + +#Whether to build debug version +CONFIG_WLAN_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +CONFIG_WLAN_DIAG_VERSION := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +# Compile all log levels by default +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := y + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := y +endif + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := n +ifneq ($(CONFIG_ARCH_SDXPRAIRIE), y) +ifneq ($(CONFIG_ARCH_SA515), y) +ifneq ($(CONFIG_ARCH_SDXLEMUR), y) +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +endif +endif +endif +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +CONFIG_FEATURE_STA_MODE_VOTE_LINK := y +else +CONFIG_QCOM_ESE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := y + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := n + +#Enable WDI Event support +CONFIG_WDI_EVENT_ENABLE := y +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +ifeq ($(CONFIG_WLAN_ENH_CFR_ENABLE), n) +CONFIG_WDI_EVENT_ENABLE := n +endif +endif + +#Enable the type_specific_data in the ath_pktlog_arg +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +ifeq ($(CONFIG_BERYLLIUM), y) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif +endif + +#Endianness selection +CONFIG_LITTLE_ENDIAN := y + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := y + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := y + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := y + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := n + +#Enable IPA offload for MDM platforms +ifeq ($(CONFIG_MDM_PLATFORM), y) +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), m) +CONFIG_IPA_OFFLOAD := y +endif +else +CONFIG_IPA_OFFLOAD := n +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := n + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := y + +#Flag to allocate memory dynamically for different buffers +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +#Flag to enable HTC credit history feature +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y + +#Flag to enable MTRACE feature +CONFIG_TRACE_RECORD_FEATURE := y + +#Flag to enable p2p debug feature +CONFIG_WLAN_FEATURE_P2P_DEBUG := y + +#Flag to enable roam debug log +CONFIG_FEATURE_ROAM_DEBUG := y + +#Flag to enable DFS Master feature +CONFIG_WLAN_DFS_MASTER_ENABLE := y + +#Flag to enable WEXT support for STA/AP/P2P interfaces +ifeq ($(CONFIG_WIRELESS_EXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif + +#Flag to enable/disable MTRACE feature +CONFIG_ENABLE_MTRACE_LOG := y + +#Flag to enable nud tracking feature +CONFIG_WLAN_NUD_TRACKING := y + +#Flag to enable/Disable Function call trace +CONFIG_FUNC_CALL_MAP := n + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := y + +#Flag to enable set and get disable channel list feature +CONFIG_DISABLE_CHANNEL_LIST :=y + +#Flag to enable beacon receive feature +CONFIG_WLAN_BCN_RECV_FEATURE := y + +#Flag to enable LTE COEX feature +CONFIG_LTE_COEX := y + +#Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +#Flag to enable/disable Avoid acs freq feature +CONFIG_SAP_AVOID_ACS_FREQ_LIST := y + +#Flag to enable HOST OPCLASS feature +CONFIG_HOST_OPCLASS := y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +#Flag to enable SAR Safety Feature +CONFIG_SAR_SAFETY_FEATURE := y + +CONFIG_CONNECTION_ROAMING_CFG := n + +CONFIG_FEATURE_SET := y + +CONFIG_WIFI_POS_CONVERGED := y +CONFIG_WLAN_TWT_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_CP_STATS := y + +CONFIG_QCA_TARGET_IF_MLME := y + +CONFIG_FEATURE_INTEROP_ISSUES_AP := y + +CONFIG_FEATURE_WLAN_WAPI := y + +CONFIG_AGEIE_ON_SCAN_RESULTS := y + +#Flag to enable FW log parsing support feature +CONFIG_FEATURE_FW_LOG_PARSING := y + +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_WMI_BCN_OFFLOAD := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_FEATURE_DENYLIST_MGR := y +CONFIG_FOURTH_CONNECTION := y +CONFIG_SUPPORT_11AX := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y + +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_FEATURE_TWT := y +CONFIG_FW_THERMAL_THROTTLE := y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS := y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD := y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y +CONFIG_FEATURE_RADAR_HISTORY := y + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y +CONFIG_QCACLD_FEATURE_MPTA_HELPER := n +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC := y + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +CONFIG_DP_TRACE := y + +ifeq ($(CONFIG_CNSS_EMULATION), y) +#on emulation platform, increase host timeouts by 1000 times +CONFIG_QDF_TIMER_MULTIPLIER_FRAC := 1000 +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y +ifndef CONFIG_MAX_LOGS_PER_SEC + CONFIG_MAX_LOGS_PER_SEC := 500 +endif + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_REGISTER_OP_DEBUG := y + CONFIG_ENABLE_QDF_PTR_HASH_DEBUG := y + CONFIG_HAL_DEBUG := y + CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE := y + +ifneq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_HIF_DETECTION_LATENCY_ENABLE := y +endif +endif +endif + +ifeq ($(CONFIG_CNSS2_DEBUG), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y + CONFIG_MAX_LOGS_PER_SEC := 500 + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_REGISTER_OP_DEBUG := y + CONFIG_ENABLE_QDF_PTR_HASH_DEBUG := y + CONFIG_HAL_DEBUG := y + CONFIG_ATH_DIAG_EXT_DIRECT := y + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_WLAN_OBJMGR_REF_ID_TRACE := y +endif + + CONFIG_HIF_DEBUG := y + +ifeq ($(CONFIG_UNIT_TEST), y) + CONFIG_DSC_TEST := y + CONFIG_QDF_TEST := y + CONFIG_FEATURE_WLM_STATS := y +endif + +ifeq (y,$(filter y,$(CONFIG_CNSS2_DEBUG) $(CONFIG_SLUB_DEBUG_ON))) + CONFIG_RX_DESC_DEBUG_CHECK:= y + CONFIG_ALLOW_PKT_DROPPING := y + CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY := y + CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK := y + CONFIG_HIF_CE_DEBUG_DATA_BUF := y + CONFIG_WLAN_RECORD_RX_PADDR := y + CONFIG_HIF_CPU_PERF_AFFINE_MASK := y + CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY := y + CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY := y + CONFIG_REO_QDESC_HISTORY := y + CONFIG_DP_TX_HW_DESC_HISTORY := y + CONFIG_QDF_NBUF_HISTORY_SIZE := 8192 + CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK := y + CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE := y +endif + +ifneq ($(CONFIG_HIF_USB), y) +CONFIG_WLAN_LOGGING_SOCK_SVC := y +endif + +CONFIG_CONNECTIVITY_PKTLOG := y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y + +ifneq ($(TARGET_BUILD_VARIANT),user) +CONFIG_DESC_DUP_DETECT_DEBUG := y +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS_MODULE))) +ifeq ($(CONFIG_CNSS_SDIO), y) +CONFIG_PLD_SDIO_CNSS_FLAG := y +endif +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR := y +endif +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS2) $(CONFIG_CNSS2_MODULE))) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_BUS_BANDWIDTH_MGR := y +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +#Enable OEM DATA feature +CONFIG_FEATURE_OEM_DATA := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +#Enable eLNA bypass feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_ELNA := y +endif + +#Enable mDNS and ICMP offload feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD := y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD := y +endif + + +CONFIG_HANDLE_BC_EAP_TX_FRM := y + +ifeq ($(CONFIG_BAND_6GHZ), y) + +CONFIG_6G_SCAN_CHAN_SORT_ALGO := y + +endif + +CONFIG_SAP_DHCP_FW_IND := y + +#Enable support to get ANI level +CONFIG_ANI_LEVEL_REQUEST := y + +#Enable RX RING buffers debug +CONFIG_DEBUG_RX_RING_BUFFER := y + +#Enable Hash debug +CONFIG_RX_HASH_DEBUG := y + +#Enable VDEV OPS wakelock feature +CONFIG_FEATURE_VDEV_OPS_WAKELOCK := y + +#Enable Hang Event +CONFIG_WLAN_HANG_EVENT := y + +ifeq ($(CONFIG_FW_THERMAL_THROTTLE), y) +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT := y +endif + +CONFIG_WLAN_DEBUG_LINK_VOTE := y + +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT := y + +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER := y + +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +CONFIG_WDI_EVENT_ENABLE := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_DCS := y +CONFIG_FEATURE_WDS := y +#Disable the Export Symbol config +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n +else +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y +endif + +ifeq ($(CONFIG_FEATURE_WDS), y) +CONFIG_FEATURE_MEC := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_FEATURE_MCL_REPEATER := y +CONFIG_BYPASS_WDS_OL_OPS := y +CONFIG_WDS_CONV_TARGET_IF_OPS_ENABLE := y +endif + +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE := y +CONFIG_4_BYTES_TLV_TAG := y + +#Enable Single NDEV Multi VDEV +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_kiwi-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_kiwi-v2_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_kiwi-v2_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_peach-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_peach-v2_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_peach-v2_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_peach_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_peach_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_peach_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_qca6750_defconfig new file mode 100644 index 0000000000..c810b0a047 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_consolidate_qca6750_defconfig @@ -0,0 +1,28 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_FEATURE_WLM_STATS=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_kiwi-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_kiwi-v2_defconfig new file mode 100644 index 0000000000..db4fe0e83e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_kiwi-v2_defconfig @@ -0,0 +1,402 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=2 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_INCLUDE_HAL_KIWI=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="kiwi_v2" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_WLAN_TX_MON_2_0_Y_WLAN_DP_LOCAL_PKT_CAPTURE=y +CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0=y +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y +CONFIG_WLAN_FEATURE_LL_LT_SAP=y +CONFIG_DP_RX_MSDU_DONE_FAIL_HISTORY=y +CONFIG_DP_RX_PEEK_MSDU_DONE_WAR=y +CONFIG_WLAN_CHIPSET_STATS=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_peach-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_peach-v2_defconfig new file mode 100644 index 0000000000..b0c58a9a6a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_peach-v2_defconfig @@ -0,0 +1,399 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=2 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_CNSS_PEACH=y +CONFIG_CNSS_PEACH_V2=y +CONFIG_INCLUDE_HAL_PEACH=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="peach_v2" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_4_BYTES_TLV_TAG=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y +CONFIG_WLAN_FEATURE_EMLSR=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_peach_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_peach_defconfig new file mode 100644 index 0000000000..8bf7553f57 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_peach_defconfig @@ -0,0 +1,398 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=1 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_CNSS_PEACH=y +CONFIG_INCLUDE_HAL_PEACH=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="peach" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_4_BYTES_TLV_TAG=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y +CONFIG_WLAN_FEATURE_EMLSR=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_qca6750_defconfig new file mode 100644 index 0000000000..f01356e9b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/pineapple_gki_qca6750_defconfig @@ -0,0 +1,331 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CNSS2_MODULE=y +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE=1 +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_SWLM=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_TX_TRACKING=y +CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_AST=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_PKTLOG=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_DEBUG=y +CONFIG_HIF_IPCI=y +CONFIG_HOST_OPCLASS=y +CONFIG_HOST_WAKEUP_OVER_QMI=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITHIUM=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_PANIC_ON_BUG=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA6750_HEADERS_DEF=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_QCA_WIFI_QCA6750=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_ROME_IF="ipci" +CONFIG_PLD_IPCI_ICNSS_FLAG=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V2=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_PROFILE_SUPPORT=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SPECTRAL_ENABLE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WDS_MODE=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_MULTI_IF_NAME="qca6750" +CONFIG_CNSS_QCA6750=y +CONFIG_BUILD_TAG=y +CONFIG_DP_RX_DESC_COOKIE_INVALIDATE=y +CONFIG_FEATURE_COEX=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/qca6174_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/qca6174_defconfig new file mode 100644 index 0000000000..fa02d93a44 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/qca6174_defconfig @@ -0,0 +1,764 @@ +CONFIG_TX_AGGREGATION_SIZE_ENABLE := y +CONFIG_RX_PERFORMANCE := y + +CONFIG_AR6320_SUPPORT := y +ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) + CONFIG_QCA_WIFI_SDIO := y +ifndef CONFIG_SDIO_TRANSFER + CONFIG_SDIO_TRANSFER = mailbox +endif +endif + +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) + CONFIG_ROME_IF = sdio +endif + +ifdef CONFIG_ICNSS + CONFIG_ROME_IF = snoc +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2))) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +ifeq (m,$(findstring m,$(CONFIG_CNSS) $(CONFIG_CNSS2))) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +# Enable FCC TYPE4 DURATION CHECK +CONFIG_DFS_FCC_TYPE4_DURATION_CHECK := y + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := y + +ifeq ($(CONFIG_ICNSS), y) + CONFIG_HELIUMPLUS := y + CONFIG_64BIT_PADDR := y + CONFIG_FEATURE_TSO := y + CONFIG_FEATURE_TSO_DEBUG := y + ifeq ($(CONFIG_INET_LRO), y) + CONFIG_WLAN_LRO := y + else + CONFIG_WLAN_LRO := n + endif +endif + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +ifeq ($(CONFIG_ARCH_MDM9630), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MDM9640), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515) $(CONFIG_ARCH_SDXPOORWILLS) $(CONFIG_ARCH_SA515M))) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MSM8917), y) + ifeq ($(CONFIG_ROME_IF), sdio) + CONFIG_WLAN_SYNC_TSF_PLUS := y + endif +endif + +ifeq ($(CONFIG_ARCH_QCS405), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ := y +endif + +#Flag to enable Legacy Fast Roaming3(LFR3) +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM))) + CONFIG_QCACLD_WLAN_LFR3 := y +else + CONFIG_QCACLD_WLAN_LFR2 := y +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Flag to enable TDLS feature +CONFIG_QCOM_TDLS := y + +CONFIG_WLAN_SYSFS := y +endif + +CONFIG_QCACLD_FEATURE_GREEN_AP := y +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := n + +ifeq ($(CONFIG_ARCH_MSM8998), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM660), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM630), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM670), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SM6150), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +#Flag to enable Fast Transition (11r) feature +CONFIG_QCOM_VOWIFI_11R := y + +#Flag to enable disable ACTION OUI feature +CONFIG_WLAN_FEATURE_ACTION_OUI := y + +#Flag to enable FILS Feature (11ai) +CONFIG_WLAN_FEATURE_FILS := y +ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2) $(CONFIG_ICNSS))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + + ifeq (m,$(findstring m,$(CONFIG_CNSS2))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif +endif + +#Flag to enable the tx desc sanity check +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_QCA_TXDESC_SANITY_CHECKS := y +endif + +#Flag to disable NAN +CONFIG_QCACLD_FEATURE_NAN := n + +#Flag to enable Linux QCMBR feature as default feature +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y +endif + + +CONFIG_FEATURE_EPPING := y + +#Flag to enable offload packets feature +CONFIG_WLAN_OFFLOAD_PACKETS := y + +#enable TSF get feature +CONFIG_WLAN_SYNC_TSF := y +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) + #Enable DSRC feature + CONFIG_WLAN_FEATURE_DSRC := y +else + CONFIG_WLAN_REG_AUTO := y +endif + +ifneq ($(CONFIG_ROME_IF),usb) + #Flag to enable SAE + CONFIG_WLAN_FEATURE_SAE := y + +ifneq ($(CONFIG_ROME_IF),sdio) + #Flag to enable DISA + CONFIG_WLAN_FEATURE_DISA := y + + #Flag to enable FIPS + CONFIG_WLAN_FEATURE_FIPS := y + + # Flag to enable NAPI + CONFIG_WLAN_NAPI := y + CONFIG_WLAN_NAPI_DEBUG := n + + # Flag to enable FW based TX Flow control + ifeq ($(CONFIG_LITHIUM), y) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y + else + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n + endif + +endif +endif + +CONFIG_POWER_MANAGEMENT_OFFLOAD := y + +ifeq ($(CONFIG_ROME_IF), snoc) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +endif + +# Flag to enable LFR Subnet Detection +CONFIG_LFR_SUBNET_DETECTION := y + +# Flag to enable MCC to SCC switch feature +CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + # Enable Obj Mgr Degug services if slub build + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_LOCK_STATS_ON:= y +endif + +ifeq (y,$(findstring y,$(CONFIG_QCA_WIFI_SDIO) $(CONFIG_HIF_USB))) +CONFIG_HL_DP_SUPPORT := y +else +CONFIG_LL_DP_SUPPORT := y +endif + +ifeq ($(CONFIG_ROME_IF),pci) +ifneq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +ifneq ($(CONFIG_LITHIUM), y) +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +endif +endif +endif + +#Whether have QMI support +CONFIG_QMI_SUPPORT := y + +ifeq ($(CONFIG_ICNSS), y) +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +# Enable athdiag procfs debug support for adrastea +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +# Enable 11AC TX compact feature for adrastea +CONFIG_ATH_11AC_TXCOMPACT := y +ifeq ($(CONFIG_QMI_SUPPORT), y) +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +endif +endif + +# Enable fw stats version 2 +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM))) +CONFIG_AR900B := y +endif + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq ($(CONFIG_HELIUMPLUS), y) + +ifeq ($(CONFIG_64BIT_PADDR), y) +CONFIG_HTT_PADDR64 := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +endif + +endif #CONFIG_HELIUMPLUS + +ifeq ($(CONFIG_LITHIUM), y) +# +# Enable Shadow V2 for all lithium platform +# +CONFIG_SHADOW_V2 := y + +CONFIG_QCA_WIFI_QCA8074 := y +CONFIG_QCA_WIFI_QCA8074_VP := y +CONFIG_DP_INTR_POLL_BASED := y +CONFIG_TX_PER_PDEV_DESC_POOL := y +CONFIG_DP_TRACE := y +CONFIG_FEATURE_TSO := y +CONFIG_TSO_DEBUG_LOG_ENABLE := y +CONFIG_DP_LFR := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y +CONFIG_TX_TID_OVERRIDE := y +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG=y + +# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QCOMs internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. +ifneq ($(TARGET_BUILD_VARIANT),user) + ifeq ($(CONFIG_LITHIUM), y) + CONFIG_FEATURE_PKTLOG := n + else + CONFIG_FEATURE_PKTLOG := y + endif + CONFIG_WLAN_DEBUG_CRASH_INJECT := y +endif + +#Enable WLAN/Power debugfs feature only if debug_fs is enabled +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y + + CONFIG_WLAN_POWER_DEBUGFS := y +endif + +#Whether to build debug version +CONFIG_WLAN_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +CONFIG_WLAN_DIAG_VERSION := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +# Compile all log levels by default +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := y + +#Disable packet log +CONFIG_REMOVE_PKT_LOG := n + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_ATH_11AC_TXCOMPACT := n +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := y +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_HIF_USB := y +endif + +#Enable SDIO specific APIS +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_HIF_SDIO := y + CONFIG_TX_DESC_HI_PRIO_RESERVE := y + CONFIG_PER_VDEV_TX_DESC_POOL := y + CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y +endif + +ifeq ($(CONFIG_ROME_IF),snoc) + CONFIG_HIF_SNOC:= y +endif + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +else +CONFIG_QCOM_ESE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +#enable 4addr support for QCS405 +ifeq ($(CONFIG_ARCH_QCS405), y) +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := y + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := n + +#Enable WDI Event support +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +CONFIG_WDI_EVENT_ENABLE := n +else +CONFIG_WDI_EVENT_ENABLE := y +endif + +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +CONFIG_PKTLOG_LEGACY := y +endif + +#Endianness selection +CONFIG_LITTLE_ENDIAN := y + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := y + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := y + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := y + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := n + +#Enable IPA offload +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif + +#Set MAX IPA Offload Interface +ifeq ($(CONFIG_ARCH_SDXPOORWILLS), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_NUM_IPA_IFACE := 2 +endif +endif + +#Flag to enable SMMU S1 support +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SDXPOORWILLS), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +ifeq ($(CONFIG_WCNSS_SKB_PRE_ALLOC), y) +CONFIG_FEATURE_SKB_PRE_ALLOC := y +endif +endif +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := n + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := y + +#Flag to allocate memory dynamically for different buffers +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +#Flag to enable HTC credit history feature +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y + +#Flag to enable MTRACE feature +CONFIG_TRACE_RECORD_FEATURE := y + +#Flag to enable p2p debug feature +CONFIG_WLAN_FEATURE_P2P_DEBUG := y + +#Flag to enable roam debug log +CONFIG_FEATURE_ROAM_DEBUG := y + +#Flag to enable DFS Master feature +CONFIG_WLAN_DFS_MASTER_ENABLE := y + +#Flag to enable WEXT support for STA/AP/P2P interfaces +ifeq ($(CONFIG_WIRELESS_EXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif + +#Flag to enable/disable MTRACE feature +CONFIG_ENABLE_MTRACE_LOG := y + +#Flag to enable nud tracking feature +CONFIG_WLAN_NUD_TRACKING := y + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := y + +#Flag to enable set and get disable channel list feature +CONFIG_DISABLE_CHANNEL_LIST :=y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +CONFIG_WIFI_POS_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_CP_STATS := y + +CONFIG_QCA_TARGET_IF_MLME := y + +CONFIG_FEATURE_WLAN_WAPI := y + +CONFIG_AGEIE_ON_SCAN_RESULTS := y + +#Flag to enable FW log parsing support feature +CONFIG_FEATURE_FW_LOG_PARSING := y + +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_WMI_BCN_OFFLOAD := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_SUPPORT_11AX := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_FEATURE_TWT := y +CONFIG_WLAN_FEATURE_BMI := y + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +#Flag to enable LTE COEX feature +CONFIG_LTE_COEX := y + +#Flag to enable delayed peer obj free +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY := y + +#Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +#Flag to enable HOST OPCLASS feature +CONFIG_HOST_OPCLASS := y + +ifeq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif +CONFIG_RX_OL := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y +ifndef CONFIG_MAX_LOGS_PER_SEC + CONFIG_MAX_LOGS_PER_SEC := 500 +endif + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y +endif + +ifeq ($(CONFIG_UNIT_TEST), y) + CONFIG_DSC_TEST := y + CONFIG_QDF_TEST := y +endif + +# enable unit-test suspend for napier builds +ifeq ($(CONFIG_LITHIUM), y) + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y +endif + +#Flag to enable hdd memory dump feature +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +#Flag to enable/disable WLAN D0-WOW +ifeq ($(CONFIG_PCI_MSM), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif +endif + +#Enable Channel Matrix restriction for all Rome only targets +ifneq ($(CONFIG_ICNSS), y) +CONFIG_CHNL_MATRIX_RESTRICTION := y +endif + +ifeq ($(CONFIG_ARCH_MDM9607), y) +CONFIG_TUFELLO_DUAL_FW_SUPPORT := y +endif + +ifeq ($(CONFIG_ARCH_MSM8996), y) +CONFIG_CHANNEL_HOPPING_ALL_BANDS := y +endif + +ifneq ($(CONFIG_HIF_USB), y) +CONFIG_WLAN_LOGGING_SOCK_SVC := y +endif + +ifneq ($(TARGET_BUILD_VARIANT),user) +CONFIG_DESC_DUP_DETECT_DEBUG := y +CONFIG_DEBUG_RX_RING_BUFFER := y +endif + +CONFIG_DP_TRACE := y + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_CNSS_SDIO), y) +CONFIG_PLD_SDIO_CNSS_FLAG := y +endif +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), m) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +#Enable Beacon Reception Stats +ifeq ($(CONFIG_WLAN_SYSFS), y) +CONFIG_FEATURE_BECN_STATS := y +CONFIG_WLAN_WOWL_ADD_PTRN := y +CONFIG_WLAN_WOWL_DEL_PTRN := y +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM))) +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y +endif + +CONFIG_SAP_DHCP_FW_IND := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +CONFIG_FEATURE_SG := y + +CONFIG_WLAN_SYSFS_MEM_STATS := y + +#Enable PCI low power interrupt register mask configuration +CONFIG_PCI_LOW_POWER_INT_REG := y + +#Enable Usable channel feature +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y + +ifeq ($(CONFIG_CNSS_GENL), m) +CONFIG_CNSS_GENL_MODULE := y +endif + +ifeq ($(CONFIG_CNSS_UTILS), m) +CONFIG_CNSS_UTILS_MODULE := y +endif + +#Enable thermal throttle +CONFIG_FW_THERMAL_THROTTLE := y + +CONFIG_ALLOC_CONTIGUOUS_MULTI_PAGE := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/qca6390_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/qca6390_defconfig new file mode 100644 index 0000000000..58b85fff15 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/qca6390_defconfig @@ -0,0 +1,867 @@ +CONFIG_CNSS_QCA6390 := y +CONFIG_BUS_AUTO_SUSPEND := y +CONFIG_DIRECT_BUF_RX_ENABLE := y +CONFIG_WMI_DBR_SUPPORT := y +CONFIG_TX_AGGREGATION_SIZE_ENABLE := y +CONFIG_RX_PERFORMANCE := y +#Flag to enable pre cac feature +CONFIG_FEATURE_WLAN_PRE_CAC := y + +ifeq ($(CONFIG_CNSS_QCA6390), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_NAPIER_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_SCALE_INCLUDES := y + CONFIG_MORE_TX_DESC := y + CONFIG_FW_THERMAL_THROTTLE := y + CONFIG_WLAN_FEATURE_MBSSID := y +endif + +ifeq ($(CONFIG_ENABLE_IPA), y) + CONFIG_IPA3 := y + CONFIG_WDI3_IPA_OVER_GSI := y +else + ifeq ($(CONFIG_ENABLE_IPA), n) + CONFIG_IPA3 := n + endif +endif + +ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) + CONFIG_QCA_WIFI_SDIO := y +ifndef CONFIG_SDIO_TRANSFER + CONFIG_SDIO_TRANSFER = mailbox +endif +endif + +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) + CONFIG_ROME_IF = sdio +endif + +ifdef CONFIG_ICNSS + CONFIG_ROME_IF = snoc +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2))) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +ifeq (m,$(findstring m,$(CONFIG_CNSS) $(CONFIG_CNSS2))) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := y + +ifeq ($(CONFIG_ICNSS), y) + CONFIG_HELIUMPLUS := y + CONFIG_64BIT_PADDR := y + CONFIG_FEATURE_TSO := y + CONFIG_FEATURE_TSO_DEBUG := y + ifeq ($(CONFIG_INET_LRO), y) + CONFIG_WLAN_LRO := y + else + CONFIG_WLAN_LRO := n + endif +endif + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +ifeq ($(CONFIG_ARCH_MDM9630), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MDM9640), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515) $(CONFIG_ARCH_SDXPOORWILLS))) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MSM8917), y) + ifeq ($(CONFIG_ROME_IF), sdio) + CONFIG_WLAN_SYNC_TSF_PLUS := y + endif +endif + +ifeq ($(CONFIG_ARCH_QCS405), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ := y +endif + +#Flag to enable Legacy Fast Roaming3(LFR3) +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM))) + CONFIG_QCACLD_WLAN_LFR3 := y +else + CONFIG_QCACLD_WLAN_LFR2 := y +endif + +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_QCA_MONITOR_PKT_SUPPORT := y +CONFIG_MONITOR_MODULARIZED_ENABLE := n +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Flag to enable TDLS feature +CONFIG_QCOM_TDLS := y + +CONFIG_WLAN_SYSFS := y +endif + +CONFIG_QCACLD_FEATURE_GREEN_AP := y +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := n + +ifeq ($(CONFIG_ARCH_MSM8998), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM660), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM630), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM670), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SM6150), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +#Flag to enable Fast Transition (11r) feature +CONFIG_QCOM_VOWIFI_11R := y + +#Flag to enable disable ACTION OUI feature +CONFIG_WLAN_FEATURE_ACTION_OUI := y + +#Flag to enable FILS Feature (11ai) +CONFIG_WLAN_FEATURE_FILS := y +ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2) $(CONFIG_ICNSS))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + + ifeq (m,$(findstring m,$(CONFIG_CNSS2))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif +endif + +#Flag to enable the tx desc sanity check +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_QCA_TXDESC_SANITY_CHECKS := y +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN + CONFIG_QCACLD_FEATURE_NAN := y + CONFIG_NDP_SAP_CONCURRENCY_ENABLE := y +endif + +#Flag to enable Linux QCMBR feature as default feature +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y +endif + + +CONFIG_FEATURE_EPPING := y + +#Flag to enable offload packets feature +CONFIG_WLAN_OFFLOAD_PACKETS := y + +#enable TSF get feature +CONFIG_WLAN_SYNC_TSF := y +#Enable DSRC feature +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) + #Enable DSRC feature + CONFIG_WLAN_FEATURE_DSRC := y +else + CONFIG_WLAN_REG_AUTO := y +endif + +ifneq ($(CONFIG_ROME_IF),usb) + #Flag to enable SAE + CONFIG_WLAN_FEATURE_SAE := y + +ifneq ($(CONFIG_ROME_IF),sdio) + #Flag to enable DISA + CONFIG_WLAN_FEATURE_DISA := y + + #Flag to enable FIPS + CONFIG_WLAN_FEATURE_FIPS := y + + #Flag to enable Fast Path feature + ifneq ($(CONFIG_LITHIUM), y) + CONFIG_WLAN_FASTPATH := y + endif + + # Flag to enable NAPI + CONFIG_WLAN_NAPI := y + CONFIG_WLAN_NAPI_DEBUG := n + + # Flag to enable FW based TX Flow control + ifeq ($(CONFIG_LITHIUM), y) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y + else + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n + endif + +endif +endif + +CONFIG_POWER_MANAGEMENT_OFFLOAD := y + +ifeq ($(CONFIG_ROME_IF), snoc) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +endif + +# Flag to enable LFR Subnet Detection +CONFIG_LFR_SUBNET_DETECTION := y + +# Flag to enable MCC to SCC switch feature +CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + # Enable Obj Mgr Degug services if slub build + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_LOCK_STATS_ON:= y +endif + +ifeq (y,$(findstring y,$(CONFIG_QCA_WIFI_SDIO) $(CONFIG_HIF_USB))) +CONFIG_HL_DP_SUPPORT := y +else +CONFIG_LL_DP_SUPPORT := y +endif + +ifeq ($(CONFIG_ROME_IF),pci) +ifneq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +ifneq ($(CONFIG_LITHIUM), y) +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +endif +endif +endif + +#Whether have QMI support +CONFIG_QMI_SUPPORT := y + +ifeq ($(CONFIG_ICNSS), y) +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +# Enable athdiag procfs debug support for adrastea +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +# Enable 11AC TX compact feature for adrastea +CONFIG_ATH_11AC_TXCOMPACT := y +ifeq ($(CONFIG_QMI_SUPPORT), y) +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +endif +endif + +# Enable fw stats version 2 +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM))) +CONFIG_AR900B := y +endif + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq ($(CONFIG_HELIUMPLUS), y) + +ifeq ($(CONFIG_64BIT_PADDR), y) +CONFIG_HTT_PADDR64 := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +endif + +endif #CONFIG_HELIUMPLUS + +ifeq ($(CONFIG_LITHIUM), y) +# +# Enable Shadow V2 for all lithium platform +# +CONFIG_SHADOW_V2 := y + +ifeq ($(CONFIG_CNSS_QCA6390), y) + CONFIG_QCA6390_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6390 := y +endif + +ifeq ($(CONFIG_PCI_MSM), $(filter $(CONFIG_PCI_MSM), m y)) + CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := y +ifeq ($(CONFIG_CNSS_QCA6390), y) + CONFIG_SHADOW_WRITE_DELAY := y +endif +endif + +CONFIG_DEVICE_FORCE_WAKE_ENABLE :=y +CONFIG_HIF_REG_WINDOW_SUPPORT :=y +CONFIG_FEATURE_FORCE_WAKE := y + +CONFIG_QCA_WIFI_QCA8074 := y +CONFIG_QCA_WIFI_QCA8074_VP := y +CONFIG_DP_INTR_POLL_BASED := y +CONFIG_TX_PER_PDEV_DESC_POOL := y +CONFIG_DP_TRACE := y +CONFIG_FEATURE_TSO := y +CONFIG_TSO_DEBUG_LOG_ENABLE := y +CONFIG_DP_LFR := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y +CONFIG_TX_TID_OVERRIDE := y +CONFIG_DP_TXRX_SOC_ATTACH := y +CONFIG_REO_DESC_DEFER_FREE := y +endif #CONFIG_LITHIUM + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG=y + +# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QCOMs internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. +ifneq ($(TARGET_BUILD_VARIANT),user) + ifeq ($(CONFIG_LITHIUM), y) + CONFIG_FEATURE_PKTLOG := n + else + CONFIG_FEATURE_PKTLOG := y + endif + CONFIG_WLAN_DEBUG_CRASH_INJECT := y +endif + +#Enable WLAN/Power debugfs feature only if debug_fs is enabled +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y + + CONFIG_WLAN_POWER_DEBUGFS := y +ifeq ($(CONFIG_RELAY), y) + CONFIG_WLAN_STREAMFS := y +endif +endif + +#Whether to build debug version +CONFIG_WLAN_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +CONFIG_WLAN_DIAG_VERSION := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +# Compile all log levels by default +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := y + +#Disable packet log +CONFIG_REMOVE_PKT_LOG := n + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_ATH_11AC_TXCOMPACT := n +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := y +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_HIF_USB := y +endif + +#Enable SDIO specific APIS +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_HIF_SDIO := y + CONFIG_TX_DESC_HI_PRIO_RESERVE := y + CONFIG_PER_VDEV_TX_DESC_POOL := y + CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y +endif + +ifeq ($(CONFIG_ROME_IF),snoc) + CONFIG_HIF_SNOC:= y +endif + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +else +CONFIG_QCOM_ESE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +#enable 4addr support for QCS405 +ifeq ($(CONFIG_ARCH_QCS405), y) +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := y + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := n + +#Enable WDI Event support +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +CONFIG_WDI_EVENT_ENABLE := n +else +CONFIG_WDI_EVENT_ENABLE := y +endif + +#Enable the type_specific_data in the ath_pktlog_arg +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif + +#Endianness selection +CONFIG_LITTLE_ENDIAN := y + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := y + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := y + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := y + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := n + +#Enable IPA offload +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_SMMU_S1_UNMAP := y +endif + +#Flag to enable SMMU S1 support +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +#Flag to enable SMMU S1 support +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515))) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_IPA_P2P_SUPPORT := y +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +ifeq ($(CONFIG_WCNSS_SKB_PRE_ALLOC), y) +CONFIG_FEATURE_SKB_PRE_ALLOC := y +endif +endif +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := n + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := y + +#Flag to allocate memory dynamically for different buffers +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +#Flag to enable HTC credit history feature +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y + +#Flag to enable MTRACE feature +CONFIG_TRACE_RECORD_FEATURE := y + +#Flag to enable p2p debug feature +CONFIG_WLAN_FEATURE_P2P_DEBUG := y + +#Flag to enable roam debug log +CONFIG_FEATURE_ROAM_DEBUG := y + +#Flag to enable DFS Master feature +CONFIG_WLAN_DFS_MASTER_ENABLE := y + +#Flag to enable WEXT support for STA/AP/P2P interfaces +ifeq ($(CONFIG_WIRELESS_EXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif + +#Flag to enable/disable MTRACE feature +CONFIG_ENABLE_MTRACE_LOG := y + +#Flag to enable nud tracking feature +CONFIG_WLAN_NUD_TRACKING := y + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := y + +#Flag to enable set and get disable channel list feature +CONFIG_DISABLE_CHANNEL_LIST :=y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +CONFIG_FEATURE_SET := y + +CONFIG_WIFI_POS_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_CP_STATS := y +CONFIG_QCA_TARGET_IF_MLME := y + +#Flag to enable compilation of DCS module +CONFIG_DCS := y + +CONFIG_FEATURE_WLAN_WAPI := y + +CONFIG_AGEIE_ON_SCAN_RESULTS := y + +#Flag to enable FW log parsing support feature +CONFIG_FEATURE_FW_LOG_PARSING := y + +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_WMI_BCN_OFFLOAD := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_FEATURE_DENYLIST_MGR := y +CONFIG_SUPPORT_11AX := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_FEATURE_TWT := y + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) + CONFIG_WLAN_FEATURE_MIB_STATS := y +endif + +ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_ICNSS))) +CONFIG_WLAN_FEATURE_BMI := n +else +CONFIG_WLAN_FEATURE_BMI := y +endif + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC := y + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +#Flag to enable LTE COEX feature +CONFIG_LTE_COEX := y + +#Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +#Flag to enable HOST OPCLASS feature +CONFIG_HOST_OPCLASS := y + +ifeq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif +CONFIG_RX_OL := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y +ifndef CONFIG_MAX_LOGS_PER_SEC + CONFIG_MAX_LOGS_PER_SEC := 500 +endif + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_HAL_DEBUG := y + CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE := y + CONFIG_HIF_DEBUG := y +endif + +ifeq ($(CONFIG_UNIT_TEST), y) + CONFIG_DSC_TEST := y + CONFIG_QDF_TEST := y +endif + +# enable unit-test suspend for napier builds +ifeq ($(CONFIG_LITHIUM), y) + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_FIX_TXDMA_LIMITATION := y + CONFIG_FEATURE_AST := y + CONFIG_PEER_PROTECTED_ACCESS := y + CONFIG_SERIALIZE_QUEUE_SETUP := y + CONFIG_DP_RX_PKT_NO_PEER_DELIVER := y + CONFIG_DP_RX_DROP_RAW_FRM := y + CONFIG_FEATURE_ALIGN_STATS_FROM_DP := y + CONFIG_DP_RX_SPECIAL_FRAME_NEED := y + CONFIG_FEATURE_STATS_EXT_V2 := y + CONFIG_WLAN_FEATURE_DP_RX_THREADS := y + CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT := y + CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT := y + CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR := y + CONFIG_ENABLE_HAL_SOC_STATS := y + CONFIG_ENABLE_HAL_REG_WR_HISTORY := y + CONFIG_MON_ENABLE_DROP_FOR_MAC := y + CONFIG_PCI_LINK_STATUS_SANITY := y + CONFIG_DDP_MON_RSSI_IN_DBM := y + CONFIG_SYSTEM_PM_CHECK := y + CONFIG_DISABLE_EAPOL_INTRABSS_FWD := y +endif + +#Flag to enable hdd memory dump feature +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +#Flag to enable/disable WLAN D0-WOW +ifeq ($(CONFIG_PCI_MSM), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif +endif + +ifeq ($(CONFIG_ARCH_MDM9607), y) +CONFIG_TUFELLO_DUAL_FW_SUPPORT := y +endif + +ifeq ($(CONFIG_ARCH_MSM8996), y) +CONFIG_CHANNEL_HOPPING_ALL_BANDS := y +endif + +ifeq (y, $(filter y, $(CONFIG_ARCH_SDXPRAIRIE) $(CONFIG_ARCH_SA515))) + CONFIG_FEATURE_MONITOR_MODE_SUPPORT := n + ifneq ($(CONFIG_SLUB_DEBUG), y) + CONFIG_DP_TRACE := n + endif +endif + +ifneq ($(CONFIG_HIF_USB), y) +CONFIG_WLAN_LOGGING_SOCK_SVC := y +endif + +ifneq ($(TARGET_BUILD_VARIANT),user) +CONFIG_DESC_DUP_DETECT_DEBUG := y +CONFIG_DEBUG_RX_RING_BUFFER := y +endif + + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_CNSS_SDIO), y) +CONFIG_PLD_SDIO_CNSS_FLAG := y +endif +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), m) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +ifeq ($(CONFIG_WLAN_SYSFS), y) +#Enable Beacon Reception Stats +CONFIG_FEATURE_BECN_STATS := y +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_MSM) $(CONFIG_ARCH_QCOM))) +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y +endif + +CONFIG_FOURTH_CONNECTION := y +CONFIG_FOURTH_CONNECTION_AUTO := y +CONFIG_SAP_DHCP_FW_IND := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y + +#Enable Usable channel feature +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y + +ifeq ($(CONFIG_MSM_BOOT_TIME_MARKER), y) +CONFIG_WLAN_BOOTUP_MARKER := y +endif + +CONFIG_WLAN_SYSFS_MEM_STATS := y + +CONFIG_WLAN_DP_PENDING_MEM_FLUSH := y + +CONFIG_WLAN_TRACEPOINTS := y + +ifeq ($(CONFIG_CNSS2), m) +CONFIG_CNSS2_MODULE := y +endif + +ifeq ($(CONFIG_CNSS_GENL), m) +CONFIG_CNSS_GENL_MODULE := y +endif + +ifeq ($(CONFIG_CNSS_UTILS), m) +CONFIG_CNSS_UTILS_MODULE := y +endif diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/qca6490_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/qca6490_defconfig new file mode 100644 index 0000000000..91dd00dc37 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/qca6490_defconfig @@ -0,0 +1,2 @@ +CONFIG_CNSS_QCA6490 := y +include $(WLAN_ROOT)/configs/default_defconfig diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/qca6750_defconfig new file mode 100644 index 0000000000..4afabfde73 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/qca6750_defconfig @@ -0,0 +1,3 @@ +CONFIG_CNSS_QCA6750 := y +$(warning "### DBG CONFIG_CNSS_QCA6750") +include $(WLAN_ROOT)/configs/default_defconfig diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/qcn7605_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/qcn7605_defconfig new file mode 100644 index 0000000000..adc0e901cb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/qcn7605_defconfig @@ -0,0 +1,28 @@ +include $(WLAN_ROOT)/configs/genoa.pci.debug_defconfig + +# Number of vdevs supported at one time, used for allocating memory +CONFIG_WLAN_MAX_VDEVS := 5 + +# Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +# Enable DENYLIST_MGR +CONFIG_FEATURE_DENYLIST_MGR := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y + +# Enable Thermal throttle +CONFIG_FW_THERMAL_THROTTLE := y + +# Enable AUTO specific regdoamin table +CONFIG_WLAN_REG_AUTO := y + +# Enable Usable channel feature +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y + +ifeq ($(CONFIG_CNSS_GENL), m) +CONFIG_CNSS_GENL_MODULE := y +endif + +ifeq ($(CONFIG_CNSS_UTILS), m) +CONFIG_CNSS_UTILS_MODULE := y +endif diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/qcs40x.snoc.perf_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/qcs40x.snoc.perf_defconfig new file mode 100644 index 0000000000..f168074489 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/qcs40x.snoc.perf_defconfig @@ -0,0 +1,211 @@ +# Protocol specific features +CONFIG_QCACLD_WLAN_LFR2 := y +CONFIG_QCACLD_WLAN_LFR3 := y +CONFIG_QCOM_TDLS := y +CONFIG_QCACLD_FEATURE_GREEN_AP := y +CONFIG_QCOM_VOWIFI_11R := y +CONFIG_WLAN_FEATURE_FILS := y +CONFIG_QCOM_LTE_COEX := n +CONFIG_WLAN_FEATURE_LPSS := n +CONFIG_QCACLD_FEATURE_NAN := n +CONFIG_POWER_MANAGEMENT_OFFLOAD := y +CONFIG_LFR_SUBNET_DETECTION := y +CONFIG_MCC_TO_SCC_SWITCH := y +CONFIG_QCOM_ESE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +CONFIG_WLAN_DFS_MASTER_ENABLE := y +CONFIG_WIFI_POS_CONVERGED := y +CONFIG_WIFI_POS_LEGACY := n +CONFIG_FEATURE_WLAN_WAPI := y +CONFIG_AGEIE_ON_SCAN_RESULTS := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_SUPPORT_11AX := n +CONFIG_HOST_OPCLASS := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := n +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_DFS_PRI_MULTIPLIER := y +CONFIG_DFS_OVERRIDE_RF_THRESHOLD := y + +# Interface specific features +CONFIG_ROME_IF = snoc +CONFIG_HELIUMPLUS := y +CONFIG_64BIT_PADDR := y +CONFIG_QMI_SUPPORT := y +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +CONFIG_HTT_PADDR64 := y +CONFIG_AR900B := y +CONFIG_HIF_SNOC:= y + +# Data Path specific features +CONFIG_WLAN_FASTPATH := y +CONFIG_FEATURE_TSO := y +CONFIG_WLAN_NAPI := y +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n +CONFIG_ATH_11AC_TXCOMPACT := y +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n +CONFIG_CHECKSUM_OFFLOAD := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_RX_OL := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := n +CONFIG_DESC_DUP_DETECT_DEBUG := n +CONFIG_DEBUG_RX_RING_BUFFER := n +CONFIG_RX_PERFORMANCE := y +CONFIG_SLUB_MEM_OPTIMIZE := y +CONFIG_TGT_NUM_MSDU_DESC := 900 +CONFIG_WLAN_PDEV_TX_FLOW_CONTROL := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y + +ifeq ($(CONFIG_INET_LRO), y) +CONFIG_WLAN_LRO := y +else +CONFIG_WLAN_LRO := n +endif + +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif + +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif + +# Debug specific features +CONFIG_WLAN_DEBUG_VERSION := n +CONFIG_WLAN_DIAG_VERSION := y +CONFIG_FEATURE_TSO_DEBUG := y +CONFIG_FEATURE_EPPING := n +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_REMOVE_PKT_LOG := y +CONFIG_FEATURE_STATS_EXT := y +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y +CONFIG_TRACE_RECORD_FEATURE := y +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_WLAN_NUD_TRACKING := n +CONFIG_CP_STATS := n +CONFIG_QCA_TARGET_IF_MLME := y +CONFIG_FEATURE_FW_LOG_PARSING := y +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_DP_TRACE := n +CONFIG_QCACLD_FEATURE_HW_CAPABILITY := y + +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y + +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +CONFIG_WDI_EVENT_ENABLE := n +else +CONFIG_WDI_EVENT_ENABLE := y +endif + +# Features gets enabled on slub debug +CONFIG_WLAN_OBJMGR_DEBUG:= n +CONFIG_OL_RX_INDICATION_RECORD := n +CONFIG_TSOSEG_DEBUG := n +CONFIG_FEATURE_PKTLOG := n +CONFIG_WLAN_DEBUG_CRASH_INJECT := n +PANIC_ON_BUG := y +WLAN_WARN_ON_ASSERT := y +CONFIG_FEATURE_MEMDUMP_ENABLE := n +CONFIG_WLAN_LOGGING_SOCK_SVC := n +CONFIG_FEATURE_UNIT_TEST_SUSPEND := n +CONFIG_LEAK_DETECTION := n + +ifeq ($(CONFIG_DEBUG_FS), y) + CONFIG_WLAN_DEBUGFS := n + CONFIG_WLAN_POWER_DEBUGFS := n +endif + +# other features +WLAN_OPEN_SOURCE := y +CONFIG_ATH_PERF_PWR_OFFLOAD := y +CONFIG_ATH_BUS_PM := y +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n +CONFIG_ATH_SUPPORT_SPECTRAL := n +CONFIG_LITTLE_ENDIAN := y +CONFIG_QCA_WIFI_FTM := y +CONFIG_ATH_PCIE_ACCESS_DEBUG := n +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y +CONFIG_FEATURE_SECURE_FIRMWARE := n +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_160MHZ_SUPPORT := y +CONFIG_WLAN_OFFLOAD_PACKETS := y +CONFIG_WLAN_SYNC_TSF := y +CONFIG_WLAN_SYNC_TSF_PLUS := y +CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ := y +CONFIG_WLAN_FEATURE_DISA := n +CONFIG_WLAN_FEATURE_FIPS := n +CONFIG_WLAN_FEATURE_SAE := y +CONFIG_GTK_OFFLOAD := y +CONFIG_QCACLD_FEATURE_COEX_CONFIG := y +CONFIG_QCACLD_FEATURE_MPTA_HELPER := y +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_LL_DP_SUPPORT := y +CONFIG_WLAN_FEATURE_LL_MODE := y + +ifeq ($(CONFIG_WLAN_FEATURE_LL_MODE), y) + CONFIG_WLAN_CLD_PM_QOS := y +endif + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +CONFIG_ENABLE_SIZE_OPTIMIZE := y +CONFIG_FEATURE_WLAN_TIME_SYNC_FTM := y + +# configure log buffer size +CONFIG_CFG_NUM_DP_TRACE_RECORD := 1000 +CONFIG_CFG_NUM_HTC_CREDIT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_WMI_MGMT_EVENT_HISTORY := 16 +CONFIG_CFG_NUM_TX_RX_HISTOGRAM := 16 +# CONFIG_CFG_NUM_RX_IND_RECORD := 1024 + +CONFIG_SAP_DHCP_FW_IND := y +################################### diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_kiwi-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_kiwi-v2_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_kiwi-v2_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_peach-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_peach-v2_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_peach-v2_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_peach_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_peach_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/sun_consolidate_peach_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_kiwi-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_kiwi-v2_defconfig new file mode 100644 index 0000000000..a8a4001114 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_kiwi-v2_defconfig @@ -0,0 +1,400 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=2 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_INCLUDE_HAL_KIWI=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="kiwi_v2" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_WLAN_TX_MON_2_0_Y_WLAN_DP_LOCAL_PKT_CAPTURE=y +CONFIG_WLAN_DP_LOCAL_PKT_CAPTURE=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0=y +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y +CONFIG_DP_RX_MSDU_DONE_FAIL_HISTORY=y +CONFIG_DP_RX_PEEK_MSDU_DONE_WAR=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_peach-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_peach-v2_defconfig new file mode 100644 index 0000000000..7e669d1448 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_peach-v2_defconfig @@ -0,0 +1,398 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=2 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_CNSS_PEACH=y +CONFIG_CNSS_PEACH_V2=y +CONFIG_INCLUDE_HAL_PEACH=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="peach_v2" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_4_BYTES_TLV_TAG=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_peach_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_peach_defconfig new file mode 100644 index 0000000000..6ff312e94a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/sun_gki_peach_defconfig @@ -0,0 +1,397 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=1 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_CNSS_PEACH=y +CONFIG_INCLUDE_HAL_PEACH=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="peach" +CONFIG_NL80211_TESTMODE=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_4_BYTES_TLV_TAG=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/volcano_consolidate_peach-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_consolidate_peach-v2_defconfig new file mode 100644 index 0000000000..58e3d95807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_consolidate_peach-v2_defconfig @@ -0,0 +1,34 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_COMP_RING_DESC_SANITY_CHECK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_ENABLE_SCHED_HISTORY_SIZE=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_CFG_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_MON_STATUS_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_FEATURE_WLM_STATS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS_DISABLE=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/volcano_consolidate_qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_consolidate_qca6750_defconfig new file mode 100644 index 0000000000..c810b0a047 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_consolidate_qca6750_defconfig @@ -0,0 +1,28 @@ +CONFIG_ALLOW_PKT_DROPPING=y +CONFIG_ATH_DIAG_EXT_DIRECT=y +CONFIG_DESC_TIMESTAMP_DEBUG_INFO=y +CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK=y +CONFIG_DP_TX_HW_DESC_HISTORY=y +CONFIG_DSC_DEBUG=y +CONFIG_DSC_TEST=y +CONFIG_ENABLE_QDF_PTR_HASH_DEBUG=y +CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE=y +CONFIG_FEATURE_UNIT_TEST_SUSPEND=y +CONFIG_HAL_DEBUG=y +CONFIG_HIF_CE_DEBUG_DATA_BUF=y +CONFIG_HIF_CPU_PERF_AFFINE_MASK=y +CONFIG_LEAK_DETECTION=y +CONFIG_MAX_LOGS_PER_SEC=500 +CONFIG_ENABLE_MAX_LOGS_PER_SEC=y +CONFIG_QDF_NBUF_HISTORY_SIZE=16384 +CONFIG_SCHED_HISTORY_SIZE=256 +CONFIG_REGISTER_OP_DEBUG=y +CONFIG_REO_QDESC_HISTORY=y +CONFIG_RX_DESC_DEBUG_CHECK=y +CONFIG_TALLOC_DEBUG=y +CONFIG_UNIT_TEST=y +CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY=y +CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY=y +CONFIG_WLAN_RECORD_RX_PADDR=y +CONFIG_QDF_TEST=y +CONFIG_FEATURE_WLM_STATS=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/volcano_gki_peach-v2_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_gki_peach-v2_defconfig new file mode 100644 index 0000000000..6eeb53a52f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_gki_peach-v2_defconfig @@ -0,0 +1,414 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BERYLLIUM=y +CONFIG_CE_DISABLE_SRNG_TIMER_IRQ=y +CONFIG_CFG_BMISS_OFFLOAD_MAX_VDEV=4 +CONFIG_CFG_MAX_STA_VDEVS=4 +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CHIP_VERSION=2 +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_KIWI=y +CONFIG_CNSS_KIWI_V2=y +CONFIG_CNSS_PEACH=y +CONFIG_CNSS_PEACH_V2=y +CONFIG_INCLUDE_HAL_PEACH=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CNSS_UTILS=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_DCS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DEVICE_FORCE_WAKE_ENABLE=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DISABLE_STATUS_RING_TIMER_WAR=y +CONFIG_DP_BE_WAR=y +CONFIG_DP_CON_MON_MSI_ENABLED=y +CONFIG_DP_CON_MON_MSI_SKIP_SET=y +CONFIG_DP_FEATURE_HW_COOKIE_CONVERSION=y +CONFIG_DP_HW_COOKIE_CONVERT_EXCEPTION=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_PKT_STATS_PER_LMAC=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_TX_NSS_STATS_SUPPORT=y +CONFIG_DP_USE_REDUCED_PEER_ID_FIELD_WIDTH=y +CONFIG_DP_WAR_INVALID_FIRST_MSDU_FLAG=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_EMULATION_2_0=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_ENABLE_SMMU_S1_TRANSLATION=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_BUS_BANDWIDTH_MGR=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_COEX=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FIFTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GET_DRIVER_MODE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_PCI=y +CONFIG_HIF_REG_WINDOW_SUPPORT=y +CONFIG_HOST_OPCLASS=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_OFFLOAD=y +CONFIG_IPA_OPT_WIFI_DP=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_KIWI_HEADERS_DEF=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MON_ENABLE_DROP_FOR_NON_MON_PMAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_NO_RX_PKT_HDR_TLV=y +CONFIG_WORD_BASED_TLV=y +CONFIG_DP_RX_BUFFER_OPTIMIZATION=y +CONFIG_OBSS_PD=y +CONFIG_OFDM_SCRAMBLER_SEED=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PCIE_GEN_SWITCH=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_PLD_PCIE_CNSS_FLAG=y +CONFIG_PLD_PCIE_INIT_FLAG=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA_DFS_BW_PUNCTURE=y +CONFIG_QCA_GET_TSF_VIA_REG=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_KIWI=y +CONFIG_QCA_WIFI_MONITOR_MODE_NO_MSDU_START_TLV_SUPPORT=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GAP_LL_PS_MODE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V3=y +CONFIG_SMMU_S1_UNMAP=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_ADDR_INDEX_SEARCH=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WIFI_POS_PASN=y +CONFIG_WINDOW_REG_PLD_LOCK_ENABLE=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG=y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_SRNG_USAGE_WM_TRACKING=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_11BE=y +CONFIG_WLAN_FEATURE_11BE_MLO=y +CONFIG_WLAN_HDD_MULTI_VDEV_SINGLE_NDEV=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_COAP=y +CONFIG_WLAN_FEATURE_COEX_DBAM=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MCC_QUOTA=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_NEAR_FULL_IRQ=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_ROAM_INFO_STATS=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_RX_MON_PARSE_CMN_USER_INFO=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYNC_TSF_PLUS=y +CONFIG_WLAN_SYNC_TSF_TIMER=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_STATS=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_EHT_RATE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_SYSFS_BITRATES=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TSF_AUTO_REPORT=y +CONFIG_WLAN_TSF_UPLINK_DELAY=y +CONFIG_WLAN_TX_LATENCY_STATS=y +CONFIG_WLAN_FEATURE_UL_JITTER=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TWT_SAP_PDEV_COUNT=y +CONFIG_WLAN_TWT_SAP_STA_COUNT=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_UMAC_MLO_MAX_DEV=3 +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_CFG80211_EXTERNAL_AUTH_MLO_SUPPORT=y +CONFIG_CFG80211_EXT_FEATURE_SECURE_NAN=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_MULTI_IF_NAME="peach_v2" +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_WLAN_HOST_ARCH_ARM=y +CONFIG_ARCH_MSM=y +CONFIG_DP_TX_PACKET_INSPECT_FOR_ILP=y +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y +CONFIG_DP_MULTIPASS_SUPPORT=y +CONFIG_WLAN_DP_VDEV_NO_SELF_PEER=y +CONFIG_WLAN_FEATURE_AFFINITY_MGR=y +CONFIG_WALT_GET_CPU_TAKEN_SUPPORT=y +CONFIG_DP_MLO_LINK_STATS_SUPPORT=y +CONFIG_WLAN_FEATURE_LL_LT_SAP=y +CONFIG_WLAN_FEATURE_VDEV_DCS=y +CONFIG_HIF_DEBUG=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_PANIC_ON_BUG=y +CONFIG_FEATURE_WLAN_CH_AVOID_EXT=y +CONFIG_CNSS2_SSR_DRIVER_DUMP=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CNSS_OUT_OF_TREE=y +CONFIG_SMP=y +CONFIG_RPS=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_4_BYTES_TLV_TAG=y +CONFIG_WLAN_FEATURE_MARK_FIRST_WAKEUP_PACKET=y +CONFIG_WLAN_MULTI_CHIP_SUPPORT=y +CONFIG_FEATURE_SMEM_MAILBOX=y +CONFIG_QMI_COMPONENT_ENABLE=y +CONFIG_QMI_WFDS=y +CONFIG_WLAN_DP_FEATURE_STC=y +CONFIG_WLAN_FEATURE_EMLSR=y +CONFIG_FEATURE_DIRECT_LINK=y +CONFIG_DP_SWLM=y +CONFIG_FEATURE_EPM=y +CONFIG_WLAN_FEATURE_LATENCY_SENSITIVE_REO=y +CONFIG_IPA_OPT_WIFI_DP_CTRL=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/volcano_gki_qca6750_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_gki_qca6750_defconfig new file mode 100644 index 0000000000..4c6c9a06e3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/volcano_gki_qca6750_defconfig @@ -0,0 +1,329 @@ +CONFIG_QCA_CLD_WLAN=y +CONFIG_160MHZ_SUPPORT=y +CONFIG_6G_SCAN_CHAN_SORT_ALGO=y +CONFIG_ADAPTIVE_11R=y +CONFIG_ANI_LEVEL_REQUEST=y +CONFIG_AR900B=y +CONFIG_ATH_11AC_TXCOMPACT=y +CONFIG_ATH_BUS_PM=y +CONFIG_ATH_PERF_PWR_OFFLOAD=y +CONFIG_BAND_6GHZ=y +CONFIG_BCN_RATECODE_ENABLE=y +CONFIG_BUS_AUTO_SUSPEND=y +CONFIG_CHECKSUM_OFFLOAD=y +CONFIG_CNSS2_MODULE=y +CONFIG_CNSS_GENL_MODULE=y +CONFIG_CNSS_UTILS_MODULE=y +CONFIG_CONNECTIVITY_PKTLOG=y +CONFIG_CONVERGED_P2P_ENABLE=y +CONFIG_CP_STATS=y +CONFIG_DDP_MON_RSSI_IN_DBM=y +CONFIG_DEBUG_RX_RING_BUFFER=y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK=y +CONFIG_DESC_DUP_DETECT_DEBUG=y +CONFIG_DIRECT_BUF_RX_ENABLE=y +CONFIG_DISABLE_CHANNEL_LIST=y +CONFIG_WLAN_BCN_RECV_FEATURE=y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD=y +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE=y +CONFIG_DP_INTR_POLL_BASED=y +CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE=1 +CONFIG_DP_LFR=y +CONFIG_DP_MEM_PRE_ALLOC=y +CONFIG_DP_PKT_ADD_TIMESTAMP=y +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES=5 +CONFIG_DP_RX_BUFFER_POOL_SIZE=128 +CONFIG_DP_RX_DROP_RAW_FRM=y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER=y +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE=2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD=512 +CONFIG_DP_RX_SPECIAL_FRAME_NEED=y +CONFIG_DP_SWLM=y +CONFIG_DP_TRACE=y +CONFIG_DP_TRAFFIC_END_INDICATION=y +CONFIG_DP_TXRX_SOC_ATTACH=y +CONFIG_DP_TX_TRACKING=y +CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE=y +CONFIG_DUP_RX_DESC_WAR=y +CONFIG_DYNAMIC_RX_AGGREGATION=y +CONFIG_ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST=y +CONFIG_ENABLE_HAL_REG_WR_HISTORY=y +CONFIG_ENABLE_HAL_SOC_STATS=y +CONFIG_ENABLE_MTRACE_LOG=y +CONFIG_FEATURE_ACTIVE_TOS=y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP=y +CONFIG_FEATURE_AST=y +CONFIG_FEATURE_BECN_STATS=y +CONFIG_FEATURE_BSS_TRANSITION=y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION=y +CONFIG_FEATURE_CONCURRENCY_MATRIX=y +CONFIG_FEATURE_DELAYED_PEER_OBJ_DESTROY=y +CONFIG_FEATURE_DENYLIST_MGR=y +CONFIG_FEATURE_EPPING=y +CONFIG_FEATURE_FORCE_WAKE=y +CONFIG_FEATURE_FW_LOG_PARSING=y +CONFIG_FEATURE_GPIO_CFG=y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE=y +CONFIG_FEATURE_HTC_CREDIT_HISTORY=y +CONFIG_FEATURE_INTEROP_ISSUES_AP=y +CONFIG_FEATURE_MEMDUMP_ENABLE=y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT=y +CONFIG_FEATURE_MSCS=y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT=y +CONFIG_FEATURE_OEM_DATA=y +CONFIG_FEATURE_OTA_TEST=y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD=y +CONFIG_FEATURE_PKTLOG=y +CONFIG_FEATURE_RADAR_HISTORY=y +CONFIG_FEATURE_ROAM_DEBUG=y +CONFIG_FEATURE_RSSI_MONITOR=y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER=y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH=y +CONFIG_FEATURE_SAR_LIMITS=y +CONFIG_FEATURE_SET=y +CONFIG_FEATURE_STATION_INFO=y +CONFIG_FEATURE_STATS_EXT=y +CONFIG_FEATURE_STATS_EXT_V2=y +CONFIG_FEATURE_TSO=y +CONFIG_FEATURE_TSO_STATS=y +CONFIG_FEATURE_TX_POWER=y +CONFIG_FEATURE_VDEV_OPS_WAKELOCK=y +CONFIG_FEATURE_WLAN_LPHB=y +CONFIG_FEATURE_WLAN_PRE_CAC=y +CONFIG_FEATURE_WLAN_RA_FILTERING=y +CONFIG_FEATURE_WLAN_SCAN_PNO=y +CONFIG_FEATURE_WLAN_WAPI=y +CONFIG_FIX_TXDMA_LIMITATION=y +CONFIG_FOURTH_CONNECTION=y +CONFIG_FW_THERMAL_THROTTLE=y +CONFIG_GTK_OFFLOAD=y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR=y +CONFIG_HANDLE_BC_EAP_TX_FRM=y +CONFIG_HANDLE_RX_REROUTE_ERR=y +CONFIG_HASTINGS_BT_WAR=y +CONFIG_HDD_INIT_WITH_RTNL_LOCK=y +CONFIG_HIF_DEBUG=y +CONFIG_HIF_IPCI=y +CONFIG_HOST_OPCLASS=y +CONFIG_HOST_WAKEUP_OVER_QMI=y +CONFIG_HTT_PADDR64=y +CONFIG_IPA_SET_RESET_TX_DB_PA=y +CONFIG_LFR_SUBNET_DETECTION=y +CONFIG_LINUX_QCMBR=y +CONFIG_LITHIUM=y +CONFIG_LITTLE_ENDIAN=y +CONFIG_LL_DP_SUPPORT=y +CONFIG_LTE_COEX=y +CONFIG_MARK_ICMP_REQ_TO_FW=y +CONFIG_MAX_ALLOC_PAGE_SIZE=y +CONFIG_MCC_TO_SCC_SWITCH=y +CONFIG_MON_ENABLE_DROP_FOR_MAC=y +CONFIG_MORE_TX_DESC=y +CONFIG_MULTI_CLIENT_LL_SUPPORT=y +CONFIG_PANIC_ON_BUG=y +CONFIG_PCI_LINK_STATUS_SANITY=y +CONFIG_PEER_PROTECTED_ACCESS=y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA=y +CONFIG_POWER_MANAGEMENT_OFFLOAD=y +CONFIG_PTT_SOCK_SVC_ENABLE=y +CONFIG_QCA6750_HEADERS_DEF=y +CONFIG_QCACLD_FEATURE_APF=y +CONFIG_QCACLD_FEATURE_FW_STATE=y +CONFIG_QCACLD_FEATURE_GREEN_AP=y +CONFIG_QCACLD_FEATURE_NAN=y +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC=y +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT=y +CONFIG_QCACLD_WLAN_LFR3=y +CONFIG_QCA_MONITOR_PKT_SUPPORT=y +CONFIG_QCA_SUPPORT_TX_THROTTLE=y +CONFIG_QCA_TARGET_IF_MLME=y +CONFIG_QCA_WIFI_FTM=y +CONFIG_QCA_WIFI_FTM_NL80211=y +CONFIG_QCA_WIFI_QCA6750=y +CONFIG_QCA_WIFI_QCA8074=y +CONFIG_QCA_WIFI_QCA8074_VP=y +CONFIG_QCOM_ESE=y +CONFIG_QCOM_LTE_COEX=y +CONFIG_QCOM_TDLS=y +CONFIG_QCOM_VOWIFI_11R=y +CONFIG_QMI_SUPPORT=y +CONFIG_REG_CLIENT=y +CONFIG_REMOVE_PKT_LOG=y +CONFIG_REO_DESC_DEFER_FREE=y +CONFIG_ROME_IF="ipci" +CONFIG_PLD_IPCI_ICNSS_FLAG=y +CONFIG_RXDMA_ERR_PKT_DROP=y +CONFIG_RX_DEFRAG_DO_NOT_REINJECT=y +CONFIG_RX_DESC_SANITY_WAR=y +CONFIG_RX_FISA=y +CONFIG_RX_HASH_DEBUG=y +CONFIG_RX_OL=y +CONFIG_SAE_SINGLE_PMK=y +CONFIG_SAP_AVOID_ACS_FREQ_LIST=y +CONFIG_SAP_DHCP_FW_IND=y +CONFIG_SAR_SAFETY_FEATURE=y +CONFIG_SCALE_INCLUDES=y +CONFIG_SERIALIZE_QUEUE_SETUP=y +CONFIG_SHADOW_V2=y +CONFIG_SOFTAP_CHANNEL_RANGE=y +CONFIG_SUPPORT_11AX=y +CONFIG_SYSTEM_PM_CHECK=y +CONFIG_TARGET_11D_SCAN=y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC=y +CONFIG_THERMAL_STATS_SUPPORT=y +CONFIG_TRACE_RECORD_FEATURE=y +CONFIG_TSO_DEBUG_LOG_ENABLE=y +CONFIG_TX_MULTIQ_PER_AC=y +CONFIG_TX_MULTI_TCL=y +CONFIG_TX_PER_PDEV_DESC_POOL=y +CONFIG_TX_TID_OVERRIDE=y +CONFIG_VERBOSE_DEBUG=y +CONFIG_WAPI_BIG_ENDIAN=y +CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE=y +CONFIG_WDI3_IPA_OVER_GSI=y +CONFIG_WDI_EVENT_ENABLE=y +CONFIG_WIFI_MONITOR_SUPPORT=y +CONFIG_WIFI_POS_CONVERGED=y +CONFIG_WLAN_BMISS=y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG=y +CONFIG_WLAN_CFR_ENABLE=y +CONFIG_WLAN_CLD_DEV_PM_QOS=y +CONFIG_WLAN_CLD_PM_QOS=y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE=y +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP=y +CONFIG_WLAN_DEBUGFS=y +CONFIG_WLAN_DEBUG_CRASH_INJECT=y +CONFIG_WLAN_DEBUG_LINK_VOTE=y +CONFIG_WLAN_DEBUG_VERSION=y +CONFIG_WLAN_DFS_MASTER_ENABLE=y +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC=y +CONFIG_WLAN_DIAG_VERSION=y +CONFIG_WLAN_DL_MODES=y +CONFIG_WLAN_DP_FEATURE_DEFERRED_REO_QDESC_DESTROY=y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH=y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG=y +CONFIG_WLAN_DP_PROFILE_SUPPORT=y +CONFIG_WLAN_DYNAMIC_CVM=y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY=y +CONFIG_WLAN_ENH_CFR_ENABLE=y +CONFIG_WLAN_FEATURE_11AX=y +CONFIG_WLAN_FEATURE_ACTION_OUI=y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS=y +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER=y +CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE=y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD=y +CONFIG_WLAN_FEATURE_DISA=y +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH=y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY=y +CONFIG_WLAN_FEATURE_DP_RX_THREADS=y +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE=y +CONFIG_WLAN_FEATURE_ELNA=y +CONFIG_WLAN_FEATURE_FILS=y +CONFIG_WLAN_FEATURE_FIPS=y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST=y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD=y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS=y +CONFIG_WLAN_FEATURE_LPSS=y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB=y +CONFIG_WLAN_FEATURE_MBSSID=y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD=y +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS=y +CONFIG_WLAN_FEATURE_MIB_STATS=y +CONFIG_WLAN_FEATURE_P2P_DEBUG=y +CONFIG_WLAN_FEATURE_P2P_P2P_STA=y +CONFIG_WLAN_FEATURE_PACKET_FILTERING=y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF=y +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL=y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT=y +CONFIG_WLAN_FEATURE_SAE=y +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE=y +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2=y +CONFIG_WLAN_FEATURE_SR=y +CONFIG_WLAN_FEATURE_TWT=y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7=y +CONFIG_WLAN_FREQ_LIST=y +CONFIG_WLAN_FW_OFFLOAD=y +CONFIG_WLAN_GTX_BW_MASK=y +CONFIG_WLAN_HANG_EVENT=y +CONFIG_WLAN_LOGGING_SOCK_SVC=y +CONFIG_WLAN_LOG_DEBUG=y +CONFIG_WLAN_LOG_ENTER=y +CONFIG_WLAN_LOG_ERROR=y +CONFIG_WLAN_LOG_EXIT=y +CONFIG_WLAN_LOG_FATAL=y +CONFIG_WLAN_LOG_INFO=y +CONFIG_WLAN_LOG_WARN=y +CONFIG_WLAN_MWS_INFO_DEBUGFS=y +CONFIG_WLAN_NAPI=y +CONFIG_WLAN_NS_OFFLOAD=y +CONFIG_WLAN_NUD_TRACKING=y +CONFIG_WLAN_OBJMGR_DEBUG=y +CONFIG_WLAN_OBJMGR_REF_ID_TRACE=y +CONFIG_WLAN_OFFLOAD_PACKETS=y +CONFIG_WLAN_OPEN_P2P_INTERFACE=y +CONFIG_WLAN_OPEN_SOURCE=y +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM=y +CONFIG_WLAN_PMO_ENABLE=y +CONFIG_WLAN_POLICY_MGR_ENABLE=y +CONFIG_WLAN_POWER_DEBUG=y +CONFIG_WLAN_REASSOC=y +CONFIG_WLAN_SCAN_DISABLE=y +CONFIG_WLAN_SKIP_BAR_UPDATE=y +CONFIG_WLAN_SPECTRAL_ENABLE=y +CONFIG_WLAN_SUPPORT_DATA_STALL=y +CONFIG_WLAN_SYNC_TSF=y +CONFIG_WLAN_SYSFS=y +CONFIG_WLAN_SYSFS_CHANNEL=y +CONFIG_WLAN_SYSFS_CONNECT_INFO=y +CONFIG_WLAN_SYSFS_DCM=y +CONFIG_WLAN_SYSFS_DFSNOL=y +CONFIG_WLAN_SYSFS_DP_TRACE=y +CONFIG_WLAN_SYSFS_FW_MODE_CFG=y +CONFIG_WLAN_SYSFS_HE_BSS_COLOR=y +CONFIG_WLAN_SYSFS_LOG_BUFFER=y +CONFIG_WLAN_SYSFS_MEM_STATS=y +CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL=y +CONFIG_WLAN_SYSFS_RADAR=y +CONFIG_WLAN_SYSFS_RANGE_EXT=y +CONFIG_WLAN_SYSFS_RF_TEST_MODE=y +CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP=y +CONFIG_WLAN_SYSFS_RTS_CTS=y +CONFIG_WLAN_SYSFS_SCAN_CFG=y +CONFIG_WLAN_SYSFS_STATS=y +CONFIG_WLAN_SYSFS_STA_INFO=y +CONFIG_WLAN_SYSFS_TDLS_PEERS=y +CONFIG_WLAN_SYSFS_TEMPERATURE=y +CONFIG_WLAN_SYSFS_TX_STBC=y +CONFIG_WLAN_SYSFS_WDS_MODE=y +CONFIG_WLAN_SYSFS_WLAN_DBG=y +CONFIG_WLAN_THERMAL_CFG=y +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT=y +CONFIG_WLAN_TRACEPOINTS=y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS=y +CONFIG_WLAN_TWT_CONVERGED=y +CONFIG_WLAN_TXRX_FW_STATS=y +CONFIG_WLAN_TXRX_FW_ST_RST=y +CONFIG_WLAN_TXRX_STATS=y +CONFIG_WLAN_TX_FLOW_CONTROL_V2=y +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL=y +CONFIG_WLAN_WARN_ON_ASSERT=y +CONFIG_WLAN_WBUFF=y +CONFIG_WLAN_WOWL_ADD_PTRN=y +CONFIG_WLAN_WOWL_DEL_PTRN=y +CONFIG_WLAN_WOW_ITO=y +CONFIG_WMI_BCN_OFFLOAD=y +CONFIG_WMI_CMD_STRINGS=y +CONFIG_WMI_CONCURRENCY_SUPPORT=y +CONFIG_WMI_DBR_SUPPORT=y +CONFIG_WMI_INTERFACE_EVENT_LOGGING=y +CONFIG_WMI_ROAM_SUPPORT=y +CONFIG_WMI_SEND_RECV_QMI=y +CONFIG_WMI_STA_SUPPORT=y +CONFIG_WLAN_CTRL_NAME="wlan" +CONFIG_NUM_SOC_PERF_CLUSTER=2 +CONFIG_MULTI_IF_NAME="qca6750" +CONFIG_CNSS_QCA6750=y +CONFIG_BUILD_TAG=y +CONFIG_DP_RX_DESC_COOKIE_INVALIDATE=y +CONFIG_CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT=y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/wcn6450_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/wcn6450_defconfig new file mode 100644 index 0000000000..f1d8c3227f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/wcn6450_defconfig @@ -0,0 +1,816 @@ +CONFIG_CNSS_WCN6450 := y + +#DP configs +CONFIG_WLAN_DP_DISABLE_TCL_CMD_CRED_SRNG := y +CONFIG_WLAN_DP_DISABLE_TCL_STATUS_SRNG := y +CONFIG_REO_DESC_DEFER_FREE := n + +CONFIG_HANDLE_RX_REROUTE_ERR := y + +#Enable DP Bus Vote +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y + +ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_EMULATION := y +endif +CONFIG_RHINE := y +CONFIG_WLAN_FEATURE_11AX := y +CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y +CONFIG_DIRECT_BUF_RX_ENABLE := y +CONFIG_WLAN_CFR_ENABLE := y +CONFIG_WMI_DBR_SUPPORT := y +CONFIG_WLAN_ENH_CFR_ENABLE := y +CONFIG_SCALE_INCLUDES := y +CONFIG_HASTINGS_BT_WAR := y +CONFIG_WDI3_IPA_OVER_GSI :=y +CONFIG_HOST_WAKEUP_OVER_QMI := y +CONFIG_WLAN_FEATURE_WMI_DIAG_OVER_CE7 := y +CONFIG_WLAN_FEATURE_LRO_CTX_IN_CB := y +CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF := y + +#Enable RHINE based Configs +CONFIG_FIX_TXDMA_LIMITATION := y +CONFIG_FEATURE_AST := y +CONFIG_PEER_PROTECTED_ACCESS := y +CONFIG_SERIALIZE_QUEUE_SETUP := y +CONFIG_DP_RX_PKT_NO_PEER_DELIVER := y +CONFIG_DP_RX_DROP_RAW_FRM := y +CONFIG_FEATURE_ALIGN_STATS_FROM_DP := y +CONFIG_FEATURE_STATS_EXT_V2 := y +CONFIG_WLAN_FEATURE_DP_RX_THREADS := y +CONFIG_WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT := y +CONFIG_FEATURE_NO_DBS_INTRABAND_MCC_SUPPORT := y +CONFIG_HAL_DISABLE_NON_BA_2K_JUMP_ERROR := y +CONFIG_ENABLE_HAL_SOC_STATS := y +CONFIG_ENABLE_HAL_REG_WR_HISTORY := y +CONFIG_MON_ENABLE_DROP_FOR_MAC := y +CONFIG_PCI_LINK_STATUS_SANITY := y +CONFIG_DDP_MON_RSSI_IN_DBM := y +CONFIG_SYSTEM_PM_CHECK := y +CONFIG_DISABLE_EAPOL_INTRABSS_FWD := y +CONFIG_FEATURE_RX_LINKSPEED_ROAM_TRIGGER := y +CONFIG_DP_TRAFFIC_END_INDICATION := y + +ifeq ($(CONFIG_ICNSS2), m) + CONFIG_ICNSS2_MODULE := y +endif +ifeq ($(CONFIG_CNSS_GENL), m) + CONFIG_CNSS_GENL_MODULE := y +endif +ifeq ($(CONFIG_CNSS_UTILS), m) + CONFIG_CNSS_UTILS_MODULE := y +endif +ifeq ($(CONFIG_WCNSS_MEM_PRE_ALLOC), m) + CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE := y +endif + +CONFIG_ROME_IF = ipci +CONFIG_PLD_IPCI_ICNSS_FLAG := y + +ifdef CONFIG_IPCIE_FW_SIM + CONFIG_ROME_IF = ipci + CONFIG_PLD_IPCI_ICNSS_FLAG := n +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := y + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +CONFIG_WLAN_FEATURE_MBSSID := y +CONFIG_WLAN_FEATURE_P2P_P2P_STA := y + +#Flag to enable Legacy Fast Roaming3(LFR3) +CONFIG_QCACLD_WLAN_LFR3 := y + +#Flag to enable Dynamic MAC address update +CONFIG_WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE := y + +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_QCA_MONITOR_PKT_SUPPORT := y +CONFIG_MONITOR_MODULARIZED_ENABLE := n +CONFIG_DP_CON_MON_MSI_ENABLED := y + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Flag to enable TDLS feature +CONFIG_QCOM_TDLS := y + +CONFIG_WLAN_SYSFS := y + +CONFIG_THERMAL_STATS_SUPPORT := y + +#Flag to enable pre cac feature +CONFIG_FEATURE_WLAN_PRE_CAC := y + +ifeq ($(CONFIG_WLAN_SYSFS), y) + CONFIG_WLAN_SYSFS_STA_INFO := y + CONFIG_WLAN_SYSFS_CHANNEL := y + CONFIG_WLAN_SYSFS_FW_MODE_CFG := y + CONFIG_WLAN_SYSFS_MEM_STATS := y + CONFIG_WLAN_REASSOC := y + CONFIG_WLAN_SYSFS_CONNECT_INFO := y + CONFIG_WLAN_SCAN_DISABLE := y + CONFIG_WLAN_SYSFS_DCM := y + CONFIG_WLAN_WOW_ITO := y + CONFIG_WLAN_WOWL_ADD_PTRN := y + CONFIG_WLAN_WOWL_DEL_PTRN := y + CONFIG_WLAN_SYSFS_TX_STBC := y + CONFIG_WLAN_SYSFS_WLAN_DBG := y + CONFIG_WLAN_TXRX_FW_ST_RST := y + CONFIG_WLAN_GTX_BW_MASK := y + CONFIG_WLAN_SYSFS_SCAN_CFG := y + CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL := y + CONFIG_WLAN_SYSFS_RADAR := y + CONFIG_WLAN_SYSFS_RTS_CTS := y + CONFIG_WLAN_SYSFS_HE_BSS_COLOR := y + CONFIG_WLAN_TXRX_FW_STATS := y + CONFIG_WLAN_TXRX_STATS := y + CONFIG_WLAN_SYSFS_DP_TRACE := y + CONFIG_WLAN_SYSFS_STATS := y +ifeq ($(CONFIG_QCOM_TDLS), y) + CONFIG_WLAN_SYSFS_TDLS_PEERS := y +endif + CONFIG_WLAN_SYSFS_TEMPERATURE := y + CONFIG_WLAN_THERMAL_CFG := y + CONFIG_WLAN_DL_MODES := y + CONFIG_WLAN_DUMP_IN_PROGRESS := n + CONFIG_WLAN_BMISS := y + CONFIG_WLAN_FREQ_LIST := y + CONFIG_DP_PKT_ADD_TIMESTAMP := y +endif +CONFIG_WLAN_PDEV_VDEV_SEND_MULTI_PARAM := y +CONFIG_WLAN_POWER_DEBUG := y +#Enable Beacon Reception Stats +CONFIG_FEATURE_BECN_STATS := y +#Flag to enable NAN +CONFIG_QCACLD_FEATURE_NAN := y +endif + +CONFIG_WLAN_FEATURE_MEDIUM_ASSESS := y + +#Disable the Export Symbol config +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := n +else +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y +endif + +CONFIG_QCACLD_FEATURE_GREEN_AP := y + +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := y + +#Flag to enable get firmware state +CONFIG_QCACLD_FEATURE_FW_STATE := y + +#Flag to enable set coex configuration +CONFIG_QCACLD_FEATURE_COEX_CONFIG := n + +#Flag to enable Fast Transition (11r) feature +CONFIG_QCOM_VOWIFI_11R := y + +#Flag to enable disable ACTION OUI feature +CONFIG_WLAN_FEATURE_ACTION_OUI := y + +#Flag to enable Adaptive 11r feature +CONFIG_ADAPTIVE_11R := y + +#Flag to enable sae single pmk feature +CONFIG_SAE_SINGLE_PMK := y + +#Flag to enable/disable multi client low latency feature support +CONFIG_MULTI_CLIENT_LL_SUPPORT := y + +#Flag to enable/disable vendor handoff feature support +CONFIG_WLAN_VENDOR_HANDOFF_CONTROL := y + +#Flag to enable mscs feature +CONFIG_FEATURE_MSCS := y + +#Flag to enable FILS Feature (11ai) +CONFIG_WLAN_FEATURE_FILS := y +ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_ICNSS2) $(CONFIG_ICNSS2_MODULE))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + +endif + +CONFIG_FEATURE_EPPING := y + +#Flag to enable offload packets feature +CONFIG_WLAN_OFFLOAD_PACKETS := y + +#enable TSF get feature +CONFIG_WLAN_SYNC_TSF := y + +#Flag to enable SAE +CONFIG_WLAN_FEATURE_SAE := y + +#Flag to enable DISA +CONFIG_WLAN_FEATURE_DISA := y + +#Flag to enable FIPS +CONFIG_WLAN_FEATURE_FIPS := y + +#Flag to enable Fast Path feature +CONFIG_WLAN_FASTPATH := y + +# Flag to enable NAPI +CONFIG_WLAN_NAPI := y +CONFIG_WLAN_NAPI_DEBUG := n + +# Flag to enable FW based TX Flow control +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y + +CONFIG_POWER_MANAGEMENT_OFFLOAD := y + +# Flag to enable LFR Subnet Detection +CONFIG_LFR_SUBNET_DETECTION := y + +# Flag to enable MCC to SCC switch feature +CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + # Enable Obj Mgr Degug services if slub build + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_LOCK_STATS_ON:= y + CONFIG_WLAN_OBJMGR_REF_ID_TRACE := y +endif + +ifeq ($(CONFIG_WLAN_SYSFS), y) + CONFIG_WLAN_SYSFS_RANGE_EXT := y +endif + +#Whether have QMI support +CONFIG_QMI_SUPPORT := y + +# Enable fw stats version 2 +CONFIG_AR900B := y + +# Enable sw_cookie sanity WAR for all Rhine platforms +CONFIG_DP_WAR_VALIDATE_RX_ERR_MSDU_COOKIE := y + +# +# Enable Shadow V3 for all Beryllium platform +# +CONFIG_SHADOW_V3 := y + +CONFIG_RX_DEFRAG_DO_NOT_REINJECT := y +CONFIG_MARK_ICMP_REQ_TO_FW := y +CONFIG_IPA_SET_RESET_TX_DB_PA := y +# +# Enable VERBOSE debug INI mechanism +# +CONFIG_VERBOSE_DEBUG := y +CONFIG_RX_DESC_SANITY_WAR := y + +CONFIG_WCN6450_HEADERS_DEF := y +CONFIG_QCA_WIFI_WCN6450 := y +CONFIG_IPA_SET_RESET_TX_DB_PA := y +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +CONFIG_HIF_HAL_REG_ACCESS_SUPPORT := y +CONFIG_CE_LEGACY_MSI_SUPPORT := y +CONFIG_FEATURE_HIF_DELAYED_REG_WRITE := y + +CONFIG_BUS_AUTO_SUSPEND := y + +CONFIG_QCA_WIFI_QCA8074 := y +CONFIG_QCA_WIFI_QCA8074_VP := y +CONFIG_DP_INTR_POLL_BASED := y +CONFIG_TX_PER_PDEV_DESC_POOL := y +CONFIG_DP_TRACE := y +CONFIG_FEATURE_TSO := y +CONFIG_FEATURE_FORCE_WAKE := y +CONFIG_DP_LFR := y +CONFIG_DUP_RX_DESC_WAR := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y +CONFIG_TX_TID_OVERRIDE := y +CONFIG_DP_TXRX_SOC_ATTACH := y +ifeq ($(CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH), y) +CONFIG_WLAN_CLD_PM_QOS := y +endif +CONFIG_WLAN_CLD_DEV_PM_QOS := y +CONFIG_DISABLE_DP_STATS := n +CONFIG_MAX_ALLOC_PAGE_SIZE := y +CONFIG_REO_DESC_DEFER_FREE := y +CONFIG_RXDMA_ERR_PKT_DROP := y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK := y +CONFIG_WLAN_TRACE_HIDE_MAC_ADDRESS := n +CONFIG_WLAN_TRACE_HIDE_SSID := n +CONFIG_DP_MEM_PRE_ALLOC := y +CONFIG_FEATURE_GPIO_CFG := y + +ifeq ($(CONFIG_FEATURE_TSO), y) + CONFIG_FEATURE_TSO_STATS := y + CONFIG_TSO_DEBUG_LOG_ENABLE := y +endif + +ifeq ($(CONFIG_DISABLE_DP_STATS), y) + CONFIG_FEATURE_TSO_STATS := n +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG=y + +# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QCOMs internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. +ifneq ($(TARGET_BUILD_VARIANT),user) + CONFIG_WLAN_DEBUG_CRASH_INJECT := y +endif + +#Disable pktlog feature for Rhine based target +CONFIG_FEATURE_PKTLOG := n + +#Enable WLAN/Power debugfs feature only if debug_fs is enabled +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y + + # Flag to enable streamfs. Depends on CONFIG_DEBUG_FS and + # CONFIG_RELAY in kernel configuration. +ifeq ($(CONFIG_RELAY), y) + CONFIG_WLAN_STREAMFS := y +endif +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) + CONFIG_WLAN_MWS_INFO_DEBUGFS := y + CONFIG_WLAN_FEATURE_MIB_STATS := y +endif + +#Whether to build debug version +CONFIG_WLAN_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +CONFIG_WLAN_DIAG_VERSION := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +# Compile all log levels by default +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := y + +#Disable packet log +CONFIG_REMOVE_PKT_LOG := y + +#Enable 11AC TX +CONFIG_ATH_11AC_TXCOMPACT := y + +#Enable PCI specific APIS (dma, etc) +CONFIG_HIF_IPCI := y + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := n +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +CONFIG_FEATURE_STA_MODE_VOTE_LINK := y +else +CONFIG_QCOM_ESE := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := y + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := n + +CONFIG_PKTLOG_LEGACY := n +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y + +CONFIG_WAPI_BIG_ENDIAN := y + +#Enable WDI Event support +CONFIG_WDI_EVENT_ENABLE := y +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +ifeq ($(CONFIG_WLAN_ENH_CFR_ENABLE), n) +CONFIG_WDI_EVENT_ENABLE := n +endif +endif + +#Enable the type_specific_data in the ath_pktlog_arg +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif + +#Endianness selection +CONFIG_LITTLE_ENDIAN := y + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := y + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := y + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := y + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := n + +#Enable IPA offload for MDM platforms +ifeq ($(CONFIG_MDM_PLATFORM), y) +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := y +endif +ifeq ($(CONFIG_IPA3), m) +CONFIG_IPA_OFFLOAD := y +endif +else +CONFIG_IPA_OFFLOAD := n +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := n + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := y + +#Flag to allocate memory dynamically for different buffers +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +#Flag to enable HTC credit history feature +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y + +#Flag to enable MTRACE feature +CONFIG_TRACE_RECORD_FEATURE := y + +#Flag to enable p2p debug feature +CONFIG_WLAN_FEATURE_P2P_DEBUG := y + +#Flag to enable roam debug log +CONFIG_FEATURE_ROAM_DEBUG := y + +#Flag to enable DFS Master feature +CONFIG_WLAN_DFS_MASTER_ENABLE := y + +#Flag to enable WEXT support for STA/AP/P2P interfaces +ifeq ($(CONFIG_WIRELESS_EXT), y) +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y +endif + +#Flag to enable/disable MTRACE feature +CONFIG_ENABLE_MTRACE_LOG := y + +#Flag to enable nud tracking feature +CONFIG_WLAN_NUD_TRACKING := y + +#Flag to enable/Disable Function call trace +CONFIG_FUNC_CALL_MAP := n + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := y + +#Flag to enable set and get disable channel list feature +CONFIG_DISABLE_CHANNEL_LIST :=y + +#Flag to enable beacon receive feature +CONFIG_WLAN_BCN_RECV_FEATURE := y + +#Flag to enable LTE COEX feature +CONFIG_LTE_COEX := y + +#Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +#Flag to enable/disable Avoid acs freq feature +CONFIG_SAP_AVOID_ACS_FREQ_LIST := y + +#Flag to enable HOST OPCLASS feature +CONFIG_HOST_OPCLASS := y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +#Flag to enable SAR Safety Feature +CONFIG_SAR_SAFETY_FEATURE := y + +CONFIG_CONNECTION_ROAMING_CFG := n + +CONFIG_FEATURE_SET := y + +CONFIG_WIFI_POS_CONVERGED := y +CONFIG_WLAN_TWT_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_CP_STATS := y + +CONFIG_QCA_TARGET_IF_MLME := y + +CONFIG_FEATURE_INTEROP_ISSUES_AP := y + +CONFIG_FEATURE_WLAN_WAPI := y + +CONFIG_AGEIE_ON_SCAN_RESULTS := y + +#Flag to enable FW log parsing support feature +CONFIG_FEATURE_FW_LOG_PARSING := y + +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_FEATURE_CLUB_LL_STATS_AND_GET_STATION := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_WMI_BCN_OFFLOAD := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_FEATURE_DENYLIST_MGR := y +CONFIG_FOURTH_CONNECTION := y +CONFIG_SUPPORT_11AX := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y + +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y + +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_FEATURE_TWT := y +CONFIG_FW_THERMAL_THROTTLE := y +CONFIG_WLAN_FEATURE_BIG_DATA_STATS := y +CONFIG_WLAN_FEATURE_IGMP_OFFLOAD := y +CONFIG_WLAN_FEATURE_GET_USABLE_CHAN_LIST := y +CONFIG_FEATURE_RADAR_HISTORY := y + +CONFIG_WLAN_FEATURE_BMI := n + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y +CONFIG_QCACLD_FEATURE_MPTA_HELPER := n +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC := y + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +CONFIG_DP_TRACE := y + +ifeq ($(CONFIG_CNSS_EMULATION), y) +#on emulation platform, increase host timeouts by 1000 times +CONFIG_QDF_TIMER_MULTIPLIER_FRAC := 1000 +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y +ifndef CONFIG_MAX_LOGS_PER_SEC + CONFIG_MAX_LOGS_PER_SEC := 500 +endif + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_REGISTER_OP_DEBUG := y + CONFIG_ENABLE_QDF_PTR_HASH_DEBUG := y + CONFIG_HAL_DEBUG := y + CONFIG_FEATURE_HAL_RECORD_SUSPEND_WRITE := y + + CONFIG_HIF_CE_DEBUG_DATA_BUF := y + CONFIG_WLAN_RECORD_RX_PADDR := y + CONFIG_HIF_CPU_PERF_AFFINE_MASK := y + CONFIG_QDF_NBUF_HISTORY_SIZE := 8192 + CONFIG_DP_RX_REFILL_CPU_PERF_AFFINE_MASK := y + CONFIG_FEATURE_HIF_LATENCY_PROFILE_ENABLE := y + CONFIG_DP_TX_HW_DESC_HISTORY := y + CONFIG_WLAN_FEATURE_DP_TX_DESC_HISTORY := y + +ifneq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_HIF_DETECTION_LATENCY_ENABLE := y +endif +endif + + CONFIG_HIF_DEBUG := y + +ifeq ($(CONFIG_UNIT_TEST), y) + CONFIG_DSC_TEST := y + CONFIG_QDF_TEST := y + CONFIG_FEATURE_WLM_STATS := y +endif + +CONFIG_RX_DESC_DEBUG_CHECK:= y +CONFIG_ALLOW_PKT_DROPPING := y + +CONFIG_DP_HW_TX_DELAY_STATS_ENABLE := y +CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY := y +CONFIG_DYNAMIC_RX_AGGREGATION := y +CONFIG_WLAN_SUPPORT_DATA_STALL := y +CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG := y +CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG := y +#Enable WMI TX/RX over QMI +CONFIG_WMI_SEND_RECV_QMI := y +CONFIG_WLAN_DP_PENDING_MEM_FLUSH := y +CONFIG_WLAN_SKIP_BAR_UPDATE := y +CONFIG_TX_MULTIQ_PER_AC := y +CONFIG_WLAN_TRACEPOINTS := y +ENABLE_CE4_COMP_DISABLE_HTT_HTC_MISC_LIST := y + +#Flag to enable hdd memory dump feature +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +CONFIG_WLAN_LOGGING_SOCK_SVC := y + +CONFIG_CONNECTIVITY_PKTLOG := y +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y + +ifneq ($(TARGET_BUILD_VARIANT),user) +CONFIG_DESC_DUP_DETECT_DEBUG := y +endif + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +#Enable OEM DATA feature +CONFIG_FEATURE_OEM_DATA := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +#Enable eLNA mDNS and ICMP feature +CONFIG_WLAN_FEATURE_ELNA := y +CONFIG_WLAN_FEATURE_MDNS_OFFLOAD := y +CONFIG_WLAN_FEATURE_ICMP_OFFLOAD := y + +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y +CONFIG_RX_FISA := y +CONFIG_MORE_TX_DESC := y +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DP_FT_LOCK_HISTORY := y +endif + +CONFIG_HANDLE_BC_EAP_TX_FRM := y + +CONFIG_6G_SCAN_CHAN_SORT_ALGO := y + +CONFIG_SAP_DHCP_FW_IND := y + +#Enable support to get ANI level +CONFIG_ANI_LEVEL_REQUEST := y + +#Enable RX RING buffers debug +CONFIG_DEBUG_RX_RING_BUFFER := y + +#Enable Hash debug +CONFIG_RX_HASH_DEBUG := y + +#Enable VDEV OPS wakelock feature +CONFIG_FEATURE_VDEV_OPS_WAKELOCK := y + +# Enable RX buffer pool support +CONFIG_WLAN_FEATURE_RX_BUFFER_POOL := y +CONFIG_DP_RX_BUFFER_POOL_SIZE := 128 +CONFIG_DP_RX_BUFFER_POOL_ALLOC_THRES := 5 +CONFIG_DP_RX_REFILL_BUFF_POOL_SIZE := 2048 +CONFIG_DP_RX_REFILL_THRD_THRESHOLD := 512 +CONFIG_DP_SWLM := y + +CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE := y + +#Enable Hang Event +CONFIG_WLAN_HANG_EVENT := y + +CONFIG_WLAN_THERMAL_MULTI_CLIENT_SUPPORT := y + +CONFIG_DP_LEGACY_MODE_CSM_DEFAULT_DISABLE := 1 +CONFIG_DP_RX_DESC_COOKIE_INVALIDATE := y + +CONFIG_WLAN_DEBUG_LINK_VOTE := y + +CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT := y + +CONFIG_WLAN_FEATURE_CAL_FAILURE_TRIGGER := y + +CONFIG_DP_TX_TRACKING := y + +ifeq ($(CONFIG_QCACLD_FEATURE_SON), y) +CONFIG_WDI_EVENT_ENABLE := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WIFI_MONITOR_SUPPORT := y +CONFIG_DCS := y +CONFIG_FEATURE_WDS := y +endif + +ifeq ($(CONFIG_FEATURE_WDS), y) +CONFIG_FEATURE_MEC := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_FEATURE_MCL_REPEATER := y +CONFIG_BYPASS_WDS_OL_OPS := y +CONFIG_WDS_CONV_TARGET_IF_OPS_ENABLE := y +endif + +ifeq ($(CONFIG_WLAN_FEATURE_CE_RX_BUFFER_REUSE), y) +CONFIG_WLAN_WBUFF := y +endif + +CONFIG_WLAN_FEATURE_SAP_ACS_OPTIMIZE := y + +# Enable sending DSCP-TID map config to firmware +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y +CONFIG_WLAN_SEND_DSCP_UP_MAP_TO_FW := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/wear_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/wear_defconfig new file mode 100644 index 0000000000..0d09a532fd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/wear_defconfig @@ -0,0 +1,1063 @@ +ifeq ($(CONFIG_CNSS_QCA6290), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_NAPIER_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_QCA6290_11AX := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + CONFIG_IPA3 := n +endif + +ifeq ($(CONFIG_CNSS_QCA6390), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_NAPIER_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + ifeq ($(CONFIG_ARCH_SDM845), y) + CONFIG_IPA3 := n + endif + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI :=y + CONFIG_DIRECT_BUF_RX_ENABLE := y + CONFIG_WMI_DBR_SUPPORT := y + CONFIG_MORE_TX_DESC := y + CONFIG_FIX_TXDMA_ALIGNMENT := y +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) + CONFIG_DIRECT_BUF_RX_ENABLE := y + CONFIG_WMI_DBR_SUPPORT := y + CONFIG_WLAN_CFR_ENABLE := y + CONFIG_WLAN_ENH_CFR_ENABLE := y + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_NAPIER_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + ifeq ($(CONFIG_ARCH_SDM845), y) + CONFIG_IPA3 := n + endif + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI :=y + CONFIG_GENERIC_SHADOW_REGISTER_ACCESS_ENABLE :=y +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) + ifeq ($(CONFIG_CNSS_EMULATION), y) + CONFIG_QCA_WIFI_NAPIER_EMULATION := y + endif + CONFIG_LITHIUM := y + CONFIG_WLAN_FEATURE_11AX := y + CONFIG_WLAN_FEATURE_DFS_OFFLOAD := y + ifeq ($(CONFIG_ARCH_SDM845), y) + CONFIG_IPA3 := n + endif + CONFIG_SCALE_INCLUDES := y + CONFIG_HASTINGS_BT_WAR := y + CONFIG_WDI3_IPA_OVER_GSI :=y +endif + +ifeq ($(CONFIG_CLD_HL_SDIO_CORE), y) + CONFIG_QCA_WIFI_SDIO := y +ifndef CONFIG_SDIO_TRANSFER + CONFIG_SDIO_TRANSFER = mailbox +endif +endif + +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) + CONFIG_ROME_IF = sdio +endif + +ifeq ($(CONFIG_CNSS_UTILS), m) + CONFIG_CNSS_UTILS_MODULE := y +endif +ifeq ($(CONFIG_WCNSS_MEM_PRE_ALLOC), m) + CONFIG_WCNSS_MEM_PRE_ALLOC_MODULE := y +endif + +ifdef CONFIG_ICNSS + CONFIG_ROME_IF = snoc +endif + +ifdef CONFIG_ICNSS2 + CONFIG_ROME_IF = ipci +endif + +ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2))) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +ifeq (m,$(findstring m,$(CONFIG_CNSS2))) +ifndef CONFIG_ROME_IF + #use pci as default interface + CONFIG_ROME_IF = pci +endif +endif + +# Make WLAN as open-source driver by default +WLAN_OPEN_SOURCE := y + +ifeq ($(CONFIG_ICNSS), y) + CONFIG_HELIUMPLUS := y + CONFIG_64BIT_PADDR := y + CONFIG_FEATURE_TSO := y + CONFIG_FEATURE_TSO_DEBUG := y + ifeq ($(CONFIG_INET_LRO), y) + CONFIG_WLAN_LRO := y + else + CONFIG_WLAN_LRO := n + endif +endif + +ifneq ($(DEVELOPER_DISABLE_BUILD_TIMESTAMP), y) +ifneq ($(WLAN_DISABLE_BUILD_TAG), y) +CONFIG_BUILD_TAG := y +endif +endif + +ifeq ($(CONFIG_ARCH_MDM9630), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MDM9640), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_SDXPRAIRIE), y) +CONFIG_MOBILE_ROUTER := y +endif + +ifeq ($(CONFIG_ARCH_MSM8917), y) + ifeq ($(CONFIG_ROME_IF), sdio) + CONFIG_WLAN_SYNC_TSF_PLUS := y + endif +endif + +ifeq (y,$(findstring y,$(CONFIG_ARCH_QCS405) $(CONFIG_ARCH_QCS403))) + CONFIG_ARCH_QCS40X := y +endif + +ifeq ($(CONFIG_ARCH_QCS40X), y) + CONFIG_WLAN_SYNC_TSF_PLUS := y + CONFIG_WLAN_SYNC_TSF_PLUS_NOIRQ := y + CONFIG_RX_PERFORMANCE := y + CONFIG_TGT_NUM_MSDU_DESC := 900 + CONFIG_MULTI_IF_LOG := y + CONFIG_DFS_PRI_MULTIPLIER := y + CONFIG_DFS_OVERRIDE_RF_THRESHOLD := y +endif +CONFIG_WLAN_FEATURE_MBSSID := y + +#Flag to enable Legacy Fast Roaming3(LFR3) +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM))) + CONFIG_QCACLD_WLAN_LFR3 := y +else + CONFIG_QCACLD_WLAN_LFR2 := y +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) +#Flag to enable TDLS feature +CONFIG_QCOM_TDLS := y + +CONFIG_WLAN_SYSFS := y +CONFIG_WLAN_POWER_DEBUG := y +#Enable Beacon Reception Stats +CONFIG_FEATURE_BECN_STATS := y +endif + +#Disable the Export Symbol config +CONFIG_WLAN_DISABLE_EXPORT_SYMBOL := y + +CONFIG_QCACLD_FEATURE_GREEN_AP := y +#Flag to enable Android Packet Filtering +CONFIG_QCACLD_FEATURE_APF := y + +#Flag to enable SARv1 -> SARv2 conversion +CONFIG_WLAN_FEATURE_SARV1_TO_SARV2 := n + +#Flag to enable get firmware state +CONFIG_QCACLD_FEATURE_FW_STATE := y + +#Flag to enable set coex configuration +CONFIG_QCACLD_FEATURE_COEX_CONFIG := n + +#Flag to enable get hw capability +ifeq ($(CONFIG_ARCH_QCS40X), y) +CONFIG_QCACLD_FEATURE_HW_CAPABILITY := y +endif + +ifeq ($(CONFIG_ARCH_MSM8998), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SDM845), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_QCACLD_FEATURE_METERING := y +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +CONFIG_QCACLD_FEATURE_METERING := y +CONFIG_WDI3_STATS_UPDATE := y +CONFIG_WLAN_SYNC_TSF_TIMER := y +endif + +#Flag to enable Fast Transition (11r) feature +CONFIG_QCOM_VOWIFI_11R := y + +#Flag to enable disable ACTION OUI feature +CONFIG_WLAN_FEATURE_ACTION_OUI := y + +#Flag to enable Adaptive 11r feature +CONFIG_ADAPTIVE_11R := y + +#Flag to enable sae single pmk feature +CONFIG_SAE_SINGLE_PMK := y + +#Flag to enable FILS Feature (11ai) +CONFIG_WLAN_FEATURE_FILS := y +ifneq ($(CONFIG_QCA_CLD_WLAN),) + ifeq (y,$(findstring y,$(CONFIG_CNSS) $(CONFIG_CNSS2) $(CONFIG_ICNSS)$(CONFIG_ICNSS2))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif + + ifeq (m,$(findstring m,$(CONFIG_CNSS2) $(CONFIG_ICNSS2))) + #Flag to enable LTE CoEx feature + CONFIG_QCOM_LTE_COEX := y + ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable LPSS feature + CONFIG_WLAN_FEATURE_LPSS := y + endif + endif +endif + +#Flag to enable the tx desc sanity check +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_QCA_TXDESC_SANITY_CHECKS := y +endif + +ifneq ($(CONFIG_MOBILE_ROUTER), y) + #Flag to enable NAN + CONFIG_QCACLD_FEATURE_NAN := y +endif + +#Flag to enable Linux QCMBR feature as default feature +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_LINUX_QCMBR :=y +endif + + +CONFIG_FEATURE_EPPING := y + +#Flag to enable offload packets feature +CONFIG_WLAN_OFFLOAD_PACKETS := y + +#enable TSF get feature +CONFIG_WLAN_SYNC_TSF := y +#Enable DSRC feature +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +CONFIG_WLAN_FEATURE_DSRC := y +endif + +ifneq ($(CONFIG_ROME_IF),usb) + #Flag to enable SAE + CONFIG_WLAN_FEATURE_SAE := y + +ifneq ($(CONFIG_ROME_IF),sdio) + #Flag to enable DISA + CONFIG_WLAN_FEATURE_DISA := y + + #Flag to enable FIPS + CONFIG_WLAN_FEATURE_FIPS := y + + #Flag to enable Fast Path feature + ifneq ($(CONFIG_LITHIUM), y) + CONFIG_WLAN_FASTPATH := y + endif + + # Flag to enable NAPI + CONFIG_WLAN_NAPI := y + CONFIG_WLAN_NAPI_DEBUG := n + + # Flag to enable FW based TX Flow control + ifeq ($(CONFIG_LITHIUM), y) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y + else + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n + endif + +endif +endif + +CONFIG_POWER_MANAGEMENT_OFFLOAD := y + +ifeq ($(CONFIG_ROME_IF), snoc) + CONFIG_WLAN_TX_FLOW_CONTROL_V2 := y +endif + +ifeq ($(CONFIG_ARCH_QCS40X), y) +CONFIG_WLAN_TX_FLOW_CONTROL_V2 := n +# Flag to improve TCP TX throughput for both +# CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY and CONFIG_WLAN_TX_FLOW_CONTROL_V2 +# disabled platform, avoid frame drop in driver +CONFIG_WLAN_PDEV_TX_FLOW_CONTROL := y +endif + +# Flag to enable LFR Subnet Detection +CONFIG_LFR_SUBNET_DETECTION := y + +# Flag to enable MCC to SCC switch feature +CONFIG_MCC_TO_SCC_SWITCH := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + # Enable Obj Mgr Degug services if slub build + CONFIG_WLAN_OBJMGR_DEBUG:= y + CONFIG_LOCK_STATS_ON:= y +endif + +ifeq (y,$(findstring y,$(CONFIG_QCA_WIFI_SDIO) $(CONFIG_HIF_USB))) +CONFIG_HL_DP_SUPPORT := y +else +CONFIG_LL_DP_SUPPORT := y +endif + +ifeq ($(CONFIG_ROME_IF),pci) +ifneq ($(CONFIG_WLAN_TX_FLOW_CONTROL_V2), y) +ifneq ($(CONFIG_LITHIUM), y) +CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY := y +endif +endif +endif + +#Whether have QMI support +CONFIG_QMI_SUPPORT := y + +ifeq ($(CONFIG_ICNSS), y) +CONFIG_WIFI_3_0_ADRASTEA := y +CONFIG_ADRASTEA_RRI_ON_DDR := y +# Enable athdiag procfs debug support for adrastea +CONFIG_ATH_PROCFS_DIAG_SUPPORT := y +# Enable 11AC TX compact feature for adrastea +CONFIG_ATH_11AC_TXCOMPACT := y +ifeq ($(CONFIG_QMI_SUPPORT), y) +CONFIG_ADRASTEA_SHADOW_REGISTERS := y +endif +endif + +# Enable fw stats version 2 +ifeq (y,$(findstring y,$(CONFIG_HELIUMPLUS) $(CONFIG_LITHIUM))) +CONFIG_AR900B := y +endif + +# NOTE: CONFIG_64BIT_PADDR requires CONFIG_HELIUMPLUS +ifeq ($(CONFIG_HELIUMPLUS), y) + +ifeq ($(CONFIG_64BIT_PADDR), y) +CONFIG_HTT_PADDR64 := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) +CONFIG_OL_RX_INDICATION_RECORD := y +CONFIG_TSOSEG_DEBUG := y +CONFIG_HIF_LARGE_CE_RING_HISTORY := 8192 +endif + +endif #CONFIG_HELIUMPLUS + +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_RX_DEFRAG_DO_NOT_REINJECT := y +# +# Enable Shadow V2 for all lithium platform +# +CONFIG_SHADOW_V2 := y + +ifeq ($(CONFIG_CNSS_QCA6290), y) + CONFIG_QCA6290_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6290 := y +endif +ifeq ($(CONFIG_CNSS_QCA6390), y) + CONFIG_QCA6390_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6390 := y +endif + +ifeq ($(CONFIG_CNSS_QCA6490), y) + CONFIG_QCA6490_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6490 := y +endif + +ifeq ($(CONFIG_CNSS_QCA6750), y) + CONFIG_QCA6750_HEADERS_DEF := y + CONFIG_QCA_WIFI_QCA6750 := y +endif + +ifeq ($(CONFIG_LITHIUM), y) +# +# Enable VERBOSE debug INI mechanism +# +CONFIG_VERBOSE_DEBUG := y +CONFIG_RX_DESC_SANITY_WAR := y +ifeq ($(CONFIG_PCI_MSM), y) + CONFIG_FEATURE_HAL_DELAYED_REG_WRITE := y +endif +endif + +CONFIG_QCA_WIFI_QCA8074 := y +CONFIG_QCA_WIFI_QCA8074_VP := y +CONFIG_DP_INTR_POLL_BASED := y +CONFIG_TX_PER_PDEV_DESC_POOL := y +CONFIG_DP_TRACE := y +CONFIG_FEATURE_TSO := y +CONFIG_FEATURE_FORCE_WAKE := y +CONFIG_DP_LFR := y +CONFIG_DUP_RX_DESC_WAR := y +CONFIG_HTT_PADDR64 := y +CONFIG_RX_OL := y +CONFIG_TX_TID_OVERRIDE := y +CONFIG_DP_TXRX_SOC_ATTACH := y +CONFIG_WLAN_CLD_PM_QOS := y +CONFIG_DISABLE_DP_STATS := n +CONFIG_MAX_ALLOC_PAGE_SIZE := y +CONFIG_REO_DESC_DEFER_FREE := y +CONFIG_RXDMA_ERR_PKT_DROP := y +CONFIG_DELIVERY_TO_STACK_STATUS_CHECK := y + +ifeq ($(CONFIG_FEATURE_TSO), y) + CONFIG_FEATURE_TSO_STATS := y + CONFIG_TSO_DEBUG_LOG_ENABLE := y +endif + +ifeq ($(CONFIG_DISABLE_DP_STATS), y) + CONFIG_FEATURE_TSO_STATS := n +endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG=y + +# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QCOMs internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. +ifneq ($(TARGET_BUILD_VARIANT),user) + ifeq ($(CONFIG_LITHIUM), y) + CONFIG_FEATURE_PKTLOG := n + else + CONFIG_FEATURE_PKTLOG := y + endif + CONFIG_WLAN_DEBUG_CRASH_INJECT := y +endif + +#Enable WLAN/Power debugfs feature only if debug_fs is enabled +ifeq ($(CONFIG_DEBUG_FS), y) + # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel + # configuration. + CONFIG_WLAN_DEBUGFS := y + + # Flag to enable streamfs. Depends on CONFIG_DEBUG_FS and + # CONFIG_RELAY in kernel configuration. +ifeq ($(CONFIG_RELAY), y) + CONFIG_WLAN_STREAMFS := y +endif +endif + +ifeq ($(CONFIG_WLAN_DEBUGFS), y) + CONFIG_WLAN_MWS_INFO_DEBUGFS := y + CONFIG_WLAN_FEATURE_MIB_STATS := y +else + CONFIG_WLAN_MWS_INFO_DEBUGFS := n + CONFIG_WLAN_FEATURE_MIB_STATS := n +endif + +#Whether to build debug version +CONFIG_WLAN_DEBUG_VERSION := y + +#Enable this flag to build driver in diag version +CONFIG_WLAN_DIAG_VERSION := y + +ifeq ($(CONFIG_SLUB_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else ifeq ($(CONFIG_PERF_DEBUG), y) + PANIC_ON_BUG := y + WLAN_WARN_ON_ASSERT := y +else + PANIC_ON_BUG := n + WLAN_WARN_ON_ASSERT := n +endif + +# Compile all log levels by default +CONFIG_WLAN_LOG_FATAL := y +CONFIG_WLAN_LOG_ERROR := y +CONFIG_WLAN_LOG_WARN := y +CONFIG_WLAN_LOG_INFO := y +CONFIG_WLAN_LOG_DEBUG := y +CONFIG_WLAN_LOG_ENTER := y +CONFIG_WLAN_LOG_EXIT := y + +#Enable OL debug and wmi unified functions +CONFIG_ATH_PERF_PWR_OFFLOAD := y + +#Disable packet log +CONFIG_REMOVE_PKT_LOG := n + +#Enable 11AC TX +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +ifeq ($(CONFIG_ROME_IF),ipci) + CONFIG_ATH_11AC_TXCOMPACT := y +endif + +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_ATH_11AC_TXCOMPACT := n +endif + +#Enable PCI specific APIS (dma, etc) +ifeq ($(CONFIG_ROME_IF),pci) + CONFIG_HIF_PCI := y +endif + +ifeq ($(CONFIG_ROME_IF),ipci) + CONFIG_HIF_IPCI := y +endif + +#Enable USB specific APIS +ifeq ($(CONFIG_ROME_IF),usb) + CONFIG_HIF_USB := y +endif + +#Enable SDIO specific APIS +ifeq ($(CONFIG_ROME_IF),sdio) + CONFIG_HIF_SDIO := y + CONFIG_TX_DESC_HI_PRIO_RESERVE := y + CONFIG_FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL := y + CONFIG_TGT_NUM_MSDU_DESC := 0 +endif + +ifeq ($(CONFIG_ROME_IF),snoc) + CONFIG_HIF_SNOC:= y +endif + +# enable/disable feature flags based upon mobile router profile +ifeq ($(CONFIG_MOBILE_ROUTER), y) +CONFIG_FEATURE_WLAN_MCC_TO_SCC_SWITCH := y +CONFIG_FEATURE_WLAN_AUTO_SHUTDOWN := y +CONFIG_FEATURE_WLAN_AP_AP_ACS_OPTIMIZE := y +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +CONFIG_MDM_PLATFORM := y +ifneq ($(CONFIG_ARCH_SDXPRAIRIE), y) +CONFIG_FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE := y +endif +CONFIG_FEATURE_AP_MCC_CH_AVOIDANCE := y +else +CONFIG_QCOM_ESE := y +CONFIG_FEATURE_WLAN_RMC := y +CONFIG_WLAN_OPEN_P2P_INTERFACE := y +CONFIG_WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY := y +endif + +#enable 4addr support for QCS40X +ifeq ($(CONFIG_ARCH_QCS40X), y) +CONFIG_FEATURE_WLAN_STA_4ADDR_SCHEME := y +endif + +#Enable power management suspend/resume functionality to PCI +CONFIG_ATH_BUS_PM := y + +#Enable FLOWMAC module support +CONFIG_ATH_SUPPORT_FLOWMAC_MODULE := n + +#Enable spectral support +CONFIG_ATH_SUPPORT_SPECTRAL := n + +#Define the legacy pktlog +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_PKTLOG_LEGACY := y +endif + +#Customize DSCP_to-UP map based on RFC8325 +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y +CONFIG_WLAN_SEND_DSCP_UP_MAP_TO_FW := y +endif +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_WLAN_CUSTOM_DSCP_UP_MAP := y +endif + +ifeq ($(CONFIG_ARCH_BENGAL), y) +CONFIG_SMMU_S1_UNMAP := y +endif + +ifeq ($(CONFIG_ROME_IF), sdio) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), pci) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), usb) +CONFIG_PKTLOG_LEGACY := y +endif + +ifeq ($(CONFIG_ROME_IF), snoc) +CONFIG_PKTLOG_LEGACY := y +endif +endif + +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_PKTLOG_LEGACY := n +endif + +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_WAPI_BIG_ENDIAN := y +else +CONFIG_WAPI_BIG_ENDIAN := n +endif + +#Enable WDI Event support +ifeq ($(CONFIG_REMOVE_PKT_LOG), y) +CONFIG_WDI_EVENT_ENABLE := n +else +CONFIG_WDI_EVENT_ENABLE := y +endif + +#Enable the type_specific_data in the ath_pktlog_arg +ifeq ($(CONFIG_REMOVE_PKT_LOG), n) +ifeq ($(CONFIG_LITHIUM), y) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif + +ifeq ($(CONFIG_HELIUMPLUS), y) +CONFIG_PKTLOG_HAS_SPECIFIC_DATA := y +endif +endif + +#Endianness selection +CONFIG_LITTLE_ENDIAN := y + +#Enable TX reclaim support +CONFIG_TX_CREDIT_RECLAIM_SUPPORT := n + +#Enable FTM support +CONFIG_QCA_WIFI_FTM := y + +ifeq ($(CONFIG_QCA_WIFI_FTM), y) + +ifeq ($(CONFIG_NL80211_TESTMODE), y) + QCA_WIFI_FTM_NL80211 :=y +else + QCA_WIFI_FTM_NL80211 :=n +endif + CONFIG_LINUX_QCMBR :=y + +else + QCA_WIFI_FTM_NL80211 :=n + CONFIG_LINUX_QCMBR :=n +endif + + +#Enable Checksum Offload +CONFIG_CHECKSUM_OFFLOAD := y + +#Enable GTK offload +CONFIG_GTK_OFFLOAD := y + +#Enable EXT WOW +ifeq ($(CONFIG_HIF_PCI), y) + CONFIG_EXT_WOW := y +endif + +#Set this to 1 to catch erroneous Target accesses during debug. +CONFIG_ATH_PCIE_ACCESS_DEBUG := n + +#Enable IPA offload +ifeq ($(CONFIG_IPA), y) +CONFIG_IPA_OFFLOAD := n +endif +ifeq ($(CONFIG_IPA3), y) +CONFIG_IPA_OFFLOAD := n +endif + +#Flag to enable SMMU S1 support +ifeq ($(CONFIG_ARCH_SDM845), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_SM8150), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +ifneq ($(CONFIG_LITHIUM), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif +endif + +ifeq ($(CONFIG_ARCH_SDXPRAIRIE), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif + +ifeq ($(CONFIG_ARCH_KONA), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +CONFIG_SMMU_S1_UNMAP := y +endif +endif + +ifeq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_ARCH_SDM630), y) +ifneq ($(CONFIG_ARCH_SDM660), y) +ifneq ($(CONFIG_ARCH_MSM8998), y) +ifeq ($(CONFIG_IPA_OFFLOAD), y) +CONFIG_ENABLE_SMMU_S1_TRANSLATION := y +endif +endif +endif +endif +endif + +ifeq ($(CONFIG_ARCH_SDX20), y) +ifeq ($(CONFIG_QCA_WIFI_SDIO), y) +ifeq ($(CONFIG_WCNSS_SKB_PRE_ALLOC), y) +CONFIG_FEATURE_SKB_PRE_ALLOC := y +endif +endif +endif + +#Enable Signed firmware support for split binary format +CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n + +#Enable single firmware binary format +CONFIG_QCA_SINGLE_BINARY_SUPPORT := n + +#Enable collecting target RAM dump after kernel panic +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y + +#Flag to enable/disable secure firmware feature +CONFIG_FEATURE_SECURE_FIRMWARE := n + +#Flag to enable Stats Ext implementation +CONFIG_FEATURE_STATS_EXT := y + +#Flag to allocate memory dynamically for different buffers +CONFIG_WLAN_LOGGING_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_DFS_STATIC_MEM_ALLOC := y + +#Flag to enable HTC credit history feature +CONFIG_FEATURE_HTC_CREDIT_HISTORY := y + +#Flag to enable MTRACE feature +CONFIG_TRACE_RECORD_FEATURE := y + +#Flag to enable p2p debug feature +CONFIG_WLAN_FEATURE_P2P_DEBUG := y + +#Flag to enable roam debug log +CONFIG_FEATURE_ROAM_DEBUG := y + +#Flag to enable DFS Master feature +CONFIG_WLAN_DFS_MASTER_ENABLE := y + +#Flag to enable WEXT support for STA/AP/P2P interfaces +CONFIG_WLAN_WEXT_SUPPORT_ENABLE := y + +#Flag to enable/disable MTRACE feature +CONFIG_ENABLE_MTRACE_LOG := y + +#Flag to enable nud tracking feature +CONFIG_WLAN_NUD_TRACKING := y + +#Flag to enable wbuff feature +CONFIG_WLAN_WBUFF := y + +#Flag to enable set and get disable channel list feature +CONFIG_DISABLE_CHANNEL_LIST :=y + +#Flag to enable beacon receive feature +CONFIG_WLAN_BCN_RECV_FEATURE := y + +#Flag to enable LTE COEX feature +CONFIG_LTE_COEX := y + +#Flag to enable/disable TARGET 11d scan +CONFIG_TARGET_11D_SCAN := y + +#Flag to enable/disable Avoid acs freq feature +CONFIG_SAP_AVOID_ACS_FREQ_LIST := y + +#Flag to enable HOST OPCLASS feature +CONFIG_HOST_OPCLASS := y + +#Flag to enable Dynamic Voltage WDCVS (Config Voltage Mode) +CONFIG_WLAN_DYNAMIC_CVM := y + +#Flag to enable SAR Safety Feature +CONFIG_SAR_SAFETY_FEATURE := y + +CONFIG_WIFI_POS_CONVERGED := y +ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) +CONFIG_WIFI_POS_LEGACY := y +endif + +CONFIG_CP_STATS := y +CONFIG_QCA_TARGET_IF_MLME := y +CONFIG_FEATURE_INTEROP_ISSUES_AP := y + +CONFIG_FEATURE_WLAN_WAPI := y + +CONFIG_AGEIE_ON_SCAN_RESULTS := y + +#Flag to enable FW log parsing support feature +CONFIG_FEATURE_FW_LOG_PARSING := y + +CONFIG_PTT_SOCK_SVC_ENABLE := y +CONFIG_SOFTAP_CHANNEL_RANGE := y +CONFIG_FEATURE_WLAN_SCAN_PNO := y +CONFIG_WLAN_FEATURE_PACKET_FILTERING := y +CONFIG_WLAN_NS_OFFLOAD := y +CONFIG_FEATURE_WLAN_RA_FILTERING:= y +CONFIG_FEATURE_WLAN_LPHB := y +CONFIG_QCA_SUPPORT_TX_THROTTLE := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_FEATURE_WLAN_EXTSCAN := n +CONFIG_WMI_BCN_OFFLOAD := y +CONFIG_160MHZ_SUPPORT := y +CONFIG_REG_CLIENT := y +CONFIG_WLAN_PMO_ENABLE := y +CONFIG_CONVERGED_P2P_ENABLE := y +CONFIG_WLAN_POLICY_MGR_ENABLE := y +CONFIG_FEATURE_DENYLIST_MGR := y +CONFIG_FOURTH_CONNECTION := y +CONFIG_SUPPORT_11AX := y +CONFIG_HDD_INIT_WITH_RTNL_LOCK := y +CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y +CONFIG_WLAN_SPECTRAL_ENABLE := y +CONFIG_WMI_CMD_STRINGS := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY := n +CONFIG_WLAN_FEATURE_TWT := y +CONFIG_FW_THERMAL_THROTTLE := y + +ifeq (y,$(findstring y,$(CONFIG_LITHIUM) $(CONFIG_ICNSS))) +CONFIG_WLAN_FEATURE_BMI := n +else +CONFIG_WLAN_FEATURE_BMI := y +endif + +#Flags to enable/disable vendor commands +CONFIG_FEATURE_RSSI_MONITOR := y +CONFIG_FEATURE_BSS_TRANSITION := y +CONFIG_FEATURE_STATION_INFO := y +CONFIG_FEATURE_TX_POWER := y +CONFIG_FEATURE_OTA_TEST := y +CONFIG_FEATURE_ACTIVE_TOS := y +CONFIG_FEATURE_SAR_LIMITS := y +CONFIG_FEATURE_CONCURRENCY_MATRIX := y +CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y +CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y +CONFIG_QCACLD_FEATURE_MPTA_HELPER := n +CONFIG_QCACLD_RX_DESC_MULTI_PAGE_ALLOC := y + +#Flags to enable/disable WMI APIs +CONFIG_WMI_ROAM_SUPPORT := y +CONFIG_WMI_CONCURRENCY_SUPPORT := y +CONFIG_WMI_STA_SUPPORT := y + +CONFIG_DP_TRACE := y + +ifeq ($(CONFIG_HELIUMPLUS), y) +ifneq ($(CONFIG_FORCE_ALLOC_FROM_DMA_ZONE), y) +CONFIG_ENABLE_DEBUG_ADDRESS_MARKING := y +endif +CONFIG_RX_OL := y +endif + +ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_DSC_DEBUG := y + CONFIG_DESC_TIMESTAMP_DEBUG_INFO := y + CONFIG_FEATURE_UNIT_TEST_SUSPEND := y + CONFIG_LEAK_DETECTION := y + CONFIG_MAX_LOGS_PER_SEC := 500 + CONFIG_SCHED_HISTORY_SIZE := 256 + CONFIG_TALLOC_DEBUG := y + CONFIG_UNIT_TEST := y + CONFIG_REGISTER_OP_DEBUG := y + CONFIG_ENABLE_QDF_PTR_HASH_DEBUG := y +endif + +ifeq ($(CONFIG_UNIT_TEST), y) + CONFIG_DSC_TEST := y + CONFIG_QDF_TEST := y + CONFIG_FEATURE_WLM_STATS := y +endif + +ifeq ($(CONFIG_LITHIUM), y) + ifeq ($(CONFIG_SLUB_DEBUG_ON), y) + CONFIG_WLAN_FEATURE_DP_EVENT_HISTORY := y + CONFIG_HIF_CE_DEBUG_DATA_BUF := y + CONFIG_WLAN_RECORD_RX_PADDR := y + CONFIG_HIF_CPU_PERF_AFFINE_MASK := y + CONFIG_WLAN_FEATURE_DP_RX_RING_HISTORY := y + CONFIG_ALLOW_PKT_DROPPING := y + endif + CONFIG_DYNAMIC_RX_AGGREGATION := y + CONFIG_RX_DESC_DEBUG_CHECK:= y + CONFIG_WLAN_SUPPORT_DATA_STALL := y + CONFIG_WLAN_DP_PER_RING_TYPE_CONFIG := y + CONFIG_WLAN_CE_INTERRUPT_THRESHOLD_CONFIG := y + #Enable WMI TX/RX over QMI + CONFIG_WMI_SEND_RECV_QMI := y + CONFIG_WLAN_DP_PENDING_MEM_FLUSH := y +endif + +#Flag to enable hdd memory dump feature +CONFIG_FEATURE_MEMDUMP_ENABLE := y + +#Flag to enable/disable WLAN D0-WOW +ifeq ($(CONFIG_PCI_MSM), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_FEATURE_WLAN_D0WOW := y +endif +endif + +ifeq ($(CONFIG_ARCH_MDM9607), y) +CONFIG_TUFELLO_DUAL_FW_SUPPORT := y +endif + +ifeq ($(CONFIG_ARCH_MSM8996), y) +CONFIG_CHANNEL_HOPPING_ALL_BANDS := y +endif + +ifeq ($(CONFIG_ARCH_SDXPRAIRIE), y) + ifneq ($(CONFIG_SLUB_DEBUG), y) + CONFIG_DP_TRACE := n + endif + + CONFIG_DIRECT_BUF_RX_ENABLE := n + CONFIG_WMI_DBR_SUPPORT := n +endif + +ifneq ($(CONFIG_HIF_USB), y) +CONFIG_WLAN_LOGGING_SOCK_SVC := y +endif + +ifneq ($(TARGET_BUILD_VARIANT),user) +CONFIG_DESC_DUP_DETECT_DEBUG := y +CONFIG_DEBUG_RX_RING_BUFFER := y +endif + +ifeq ($(CONFIG_CNSS), y) +ifeq ($(CONFIG_CNSS_SDIO), y) +CONFIG_PLD_SDIO_CNSS_FLAG := y +endif +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +endif +endif + +ifeq ($(CONFIG_ICNSS2), y) +CONFIG_PLD_IPCI_ICNSS_FLAG := y +endif + +ifeq ($(CONFIG_CNSS2), y) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +ifeq ($(CONFIG_CNSS2), m) +ifeq ($(CONFIG_HIF_PCI), y) +CONFIG_PLD_PCIE_CNSS_FLAG := y +CONFIG_PLD_PCIE_INIT_FLAG := y +endif +endif + +#Enable STATE MACHINE HISTORY +CONFIG_SM_ENG_HIST := n + +#Enable OEM DATA feature +CONFIG_FEATURE_OEM_DATA := y + +#Enable FW Offload +CONFIG_WLAN_FW_OFFLOAD := y + +#Enable eLNA bypass feature +ifeq ($(CONFIG_WLAN_FW_OFFLOAD), y) +CONFIG_WLAN_FEATURE_ELNA := y +endif + +#Enable DP Bus Vote +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y + +ifeq ($(CONFIG_CNSS_QCA6490), y) + +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y +CONFIG_RX_FISA := y +CONFIG_MORE_TX_DESC := y + +endif + +CONFIG_HANDLE_BC_EAP_TX_FRM := y + +ifeq ($(CONFIG_BAND_6GHZ), y) + +CONFIG_6G_SCAN_CHAN_SORT_ALGO := y + +endif + +CONFIG_SAP_DHCP_FW_IND := y + +#Enable support to get ANI level +CONFIG_ANI_LEVEL_REQUEST := y + +ifeq ($(CONFIG_ARCH_QCS405), y) +CONFIG_FEATURE_WLAN_TIME_SYNC_FTM := y +endif + +CONFIG_WLAN_HANG_EVENT := y + +#Enable VDEV Response wakelock feature +CONFIG_FEATURE_VDEV_RSP_WAKELOCK := y + +#Enable Low Power Modes: Deep Sleep/Hibernate +CONFIG_ENABLE_LOW_POWER_MODE := y diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/whunt_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/whunt_defconfig new file mode 100644 index 0000000000..80f896793a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/whunt_defconfig @@ -0,0 +1,13 @@ +#Enable 6 GHz Band +CONFIG_BAND_6GHZ := y + +#Enable 11AX Feature +CONFIG_WLAN_FEATURE_11AX := y + +include $(WLAN_ROOT)/configs/default_defconfig + +#Enable BUS bandwidth Feature +CONFIG_WLAN_FEATURE_DP_BUS_BANDWIDTH := y + +#Disable PM_QOS not supported in WHUNT +CONFIG_WLAN_CLD_PM_QOS := n diff --git a/qcom/opensource/wlan/qcacld-3.0/configs/wlan_defconfig b/qcom/opensource/wlan/qcacld-3.0/configs/wlan_defconfig new file mode 100644 index 0000000000..6e0e3c209e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/configs/wlan_defconfig @@ -0,0 +1 @@ +include $(WLAN_ROOT)/configs/default_defconfig diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/bmi.h b/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/bmi.h new file mode 100644 index 0000000000..722f5b42ed --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/bmi.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* ================================================================ */ +/* BMI declarations and prototypes */ +/* */ +/* ================================================================= */ + +#ifndef _BMI_H_ +#define _BMI_H_ +#include "bmi_msg.h" +#include "qdf_trace.h" +#include "ol_if_athvar.h" +#include "hif.h" + +struct ol_context; + +/** + * struct ol_config_info - Place Holder for offload configuration + * @enable_uart_print: UART Print + * @enable_self_recovery: Self Recovery + * @enable_fw_log: To Enable FW LOG + * @enable_lpass_support: LPASS support + * @enable_ramdump_collection: Ramdump Collection + * + * Structure for holding ini parameters. + */ + +struct ol_config_info { + bool enable_uart_print; + bool enable_self_recovery; + uint8_t enable_fw_log; + bool enable_lpass_support; + bool enable_ramdump_collection; +}; + +#ifdef WLAN_FEATURE_BMI +QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx); +void ol_cds_free(void); +void ol_init_ini_config(struct ol_context *ol_ctx, + struct ol_config_info *cfg); +/** + * ol_set_fw_crashed_cb() - set firmware crashed callback + * @ol_ctx: ol context + * @callback_fn: fw crashed callback function + * + * Return: None + */ +void ol_set_fw_crashed_cb(struct ol_context *ol_ctx, + void (*callback_fn)(void)); +void bmi_cleanup(struct ol_context *scn); +QDF_STATUS bmi_done(struct ol_context *ol_ctx); +void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx); +QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx); + +#else /* WLAN_FEATURE_BMI */ + +static inline QDF_STATUS +ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void ol_cds_free(void) +{ +} + +static inline void +ol_init_ini_config(struct ol_context *ol_ctx, struct ol_config_info *cfg) +{ +} + +static inline void +ol_set_fw_crashed_cb(struct ol_context *ol_ctx, void (*callback_fn)(void)) +{ +} + +static inline void bmi_cleanup(struct ol_context *scn) +{ +} + +static inline QDF_STATUS bmi_done(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx) +{ +} + +static inline QDF_STATUS +bmi_download_firmware(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_BMI */ + +#endif /* _BMI_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/ol_fw.h b/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/ol_fw.h new file mode 100644 index 0000000000..13d4cd65a7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/ol_fw.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_FW_H_ +#define _OL_FW_H_ + +#include "qdf_types.h" +#include "hif.h" +#include "hif_hw_version.h" +#include "bmi.h" + +#define AR6320_REV2_VERSION AR6320_REV1_1_VERSION +#define AR6320_REV4_VERSION AR6320_REV2_1_VERSION +#define SIGN_HEADER_MAGIC 0x454D4F52 +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET (1 << 0) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET (1 << 1) +#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2) + +#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK (1 << 16) +#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17) + +#ifdef WLAN_FEATURE_BMI +void ol_target_failure(void *instance, QDF_STATUS status); + +void ol_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx); +QDF_STATUS ol_extra_initialization(struct ol_context *ol_ctx); +#else /* WLAN_FEATURE_BMI */ +static inline void ol_target_failure(void *instance, QDF_STATUS status) {} +#endif /* WLAN_FEATURE_BMI */ +#endif /* _OL_FW_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/ol_if_athvar.h b/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/ol_if_athvar.h new file mode 100644 index 0000000000..dc2e0009b5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/inc/ol_if_athvar.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014-2016, 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Definitions for the Atheros Wireless LAN controller driver. + */ +#ifndef _DEV_OL_ATH_ATHVAR_H +#define _DEV_OL_ATH_ATHVAR_H + +#include "htc_api.h" +#include "bmi_msg.h" + +#endif /* _DEV_OL_ATH_ATHVAR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/bmi.c b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/bmi.c new file mode 100644 index 0000000000..e837659273 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/bmi.c @@ -0,0 +1,582 @@ +/* + * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "i_bmi.h" +#include "cds_api.h" + +/* APIs visible to the driver */ + +QDF_STATUS bmi_init(struct ol_context *ol_ctx) +{ + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + struct hif_opaque_softc *scn = ol_ctx->scn; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + if (!scn) { + BMI_ERR("Invalid scn Context"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + if (!qdf_dev->dev) { + BMI_ERR("%s: Invalid Device Pointer", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + info->bmi_done = false; + + if (!info->bmi_cmd_buff) { + info->bmi_cmd_buff = + qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + &info->bmi_cmd_da); + if (!info->bmi_cmd_buff) { + BMI_ERR("No Memory for BMI Command"); + return QDF_STATUS_E_NOMEM; + } + } + + if (!info->bmi_rsp_buff) { + info->bmi_rsp_buff = + qdf_mem_alloc_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + &info->bmi_rsp_da); + if (!info->bmi_rsp_buff) { + BMI_ERR("No Memory for BMI Response"); + goto end; + } + } + return QDF_STATUS_SUCCESS; +end: + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, MAX_BMI_CMDBUF_SZ, + info->bmi_cmd_buff, info->bmi_cmd_da, 0); + info->bmi_cmd_buff = NULL; + return QDF_STATUS_E_NOMEM; +} + +void bmi_cleanup(struct ol_context *ol_ctx) +{ + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + qdf_device_t qdf_dev; + + if (!info || !ol_ctx) { + BMI_WARN("%s: no bmi to cleanup", __func__); + return; + } + + qdf_dev = ol_ctx->qdf_dev; + if (!qdf_dev || !qdf_dev->dev) { + BMI_ERR("%s: Invalid Device Pointer", __func__); + return; + } + + if (info->bmi_cmd_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_cmd_buff, info->bmi_cmd_da, 0); + info->bmi_cmd_buff = NULL; + info->bmi_cmd_da = 0; + } + + if (info->bmi_rsp_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_rsp_buff, info->bmi_rsp_da, 0); + info->bmi_rsp_buff = NULL; + info->bmi_rsp_da = 0; + } +} + +/** + * bmi_done() - finish the bmi operation + * @ol_ctx: the bmi context + * + * does some sanity checking. + * exchanges one last message with firmware. + * frees some buffers. + * + * Return: QDF_STATUS_SUCCESS if bmi isn't needed. + * QDF_STATUS_SUCCESS if bmi finishes. + * otherwise returns failure. + */ +QDF_STATUS bmi_done(struct ol_context *ol_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NO_BMI) + return QDF_STATUS_SUCCESS; + + if (!ol_ctx) { + BMI_ERR("%s: null context", __func__); + return QDF_STATUS_E_NOMEM; + } + hif_claim_device(ol_ctx->scn); + + if (!hif_needs_bmi(ol_ctx->scn)) + return QDF_STATUS_SUCCESS; + + status = bmi_done_local(ol_ctx); + if (status != QDF_STATUS_SUCCESS) + BMI_ERR("BMI_DONE Failed status:%d", status); + + return status; +} + +void bmi_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx) +{ + ol_target_ready(scn, cfg_ctx); +} + +static QDF_STATUS +bmi_get_target_info_message_based(struct bmi_target_info *targ_info, + struct ol_context *ol_ctx) +{ + int status = 0; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + uint32_t cid, length; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + cid = BMI_GET_TARGET_INFO; + + qdf_mem_copy(bmi_cmd_buff, &cid, sizeof(cid)); + length = sizeof(struct bmi_target_info); + + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, sizeof(cid), + (uint8_t *)bmi_rsp_buff, &length, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Failed to target info: status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(targ_info, bmi_rsp_buff, length); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_get_target_info(struct bmi_target_info *targ_info, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + QDF_STATUS status; + + if (info->bmi_done) { + BMI_ERR("BMI Phase is Already Done"); + return QDF_STATUS_E_PERM; + } + + switch (hif_get_bus_type(scn)) { + case QDF_BUS_TYPE_PCI: + case QDF_BUS_TYPE_SNOC: + case QDF_BUS_TYPE_USB: + status = bmi_get_target_info_message_based(targ_info, ol_ctx); + break; +#ifdef HIF_SDIO + case QDF_BUS_TYPE_SDIO: + status = hif_reg_based_get_target_info(scn, targ_info); + break; +#endif + default: + status = QDF_STATUS_E_FAILURE; + break; + } + return status; +} + +QDF_STATUS bmi_download_firmware(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn; + + if (!ol_ctx) { + if (NO_BMI) { + /* ol_ctx is not allocated in NO_BMI case */ + return QDF_STATUS_SUCCESS; + } + + BMI_ERR("ol_ctx is NULL"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + scn = ol_ctx->scn; + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + if (!hif_needs_bmi(scn)) + return QDF_STATUS_SUCCESS; + else + hif_register_bmi_callbacks(scn); + + return bmi_firmware_download(ol_ctx); +} + +QDF_STATUS bmi_read_soc_register(uint32_t address, uint32_t *param, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset, param_len; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + qdf_mem_zero(bmi_cmd_buff, sizeof(cid) + sizeof(address)); + qdf_mem_zero(bmi_rsp_buff, sizeof(cid) + sizeof(address)); + + if (info->bmi_done) { + BMI_DBG("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Read SOC Register:device: 0x%pK, address: 0x%x", + scn, address); + + cid = BMI_READ_SOC_REGISTER; + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + param_len = sizeof(*param); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + bmi_rsp_buff, ¶m_len, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_DBG("Unable to read from the device; status:%d", status); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param)); + + BMI_DBG("BMI Read SOC Register: Exit value: %d", *param); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param); + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(size)); + qdf_mem_zero(bmi_cmd_buff, size); + + if (info->bmi_done) { + BMI_DBG("Command disallowed"); + return QDF_STATUS_E_FAILURE; + } + + BMI_DBG("SOC Register Write:device:0x%pK, addr:0x%x, param:%d", + scn, address, param); + + cid = BMI_WRITE_SOC_REGISTER; + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), ¶m, sizeof(param)); + offset += sizeof(param); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Unable to write to the device: status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + BMI_DBG("BMI Read SOC Register: Exit"); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +bmilz_data(uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx) +{ + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(length); + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + header); + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + BMI_DBG("BMI Send LZ Data: device: 0x%pK, length: %d", + scn, length); + + cid = BMI_LZ_DATA; + + remaining = length; + while (remaining) { + txlen = (remaining < (BMI_DATASZ_MAX - header)) ? + remaining : (BMI_DATASZ_MAX - header); + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + qdf_mem_copy(&(bmi_cmd_buff[offset]), + &buffer[length - remaining], txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, cmd, rsp, + bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Failed to write to the device: status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + remaining -= txlen; + } + + BMI_DBG("BMI LZ Data: Exit"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_context *ol_ctx) +{ + uint32_t cid; + int status; + uint32_t offset; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buf[BMI_DATASZ_MAX + 4]; + uint8_t *src; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint32_t remaining, txlen; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + header); + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + BMI_ERR("Sign Stream start:device:0x%pK, addr:0x%x, length:%d", + scn, address, length); + + cid = BMI_SIGN_STREAM_START; + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 0x3) { + memcpy(aligned_buf, src, remaining); + remaining = remaining + (4 - (remaining & 0x3)); + src = aligned_buf; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(offset); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, cmd, rsp, + bmi_cmd_buff, offset, NULL, + NULL, BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to write to the device: status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + remaining -= txlen; + } + BMI_DBG("BMI SIGN Stream Start: Exit"); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +bmilz_stream_start(uint32_t address, struct ol_context *ol_ctx) +{ + uint32_t cid; + int status; + uint32_t offset; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + bmi_assert(BMI_COMMAND_FITS(sizeof(cid) + sizeof(address))); + qdf_mem_zero(bmi_cmd_buff, sizeof(cid) + sizeof(address)); + + if (info->bmi_done) { + BMI_DBG("Command disallowed"); + return QDF_STATUS_E_PERM; + } + BMI_DBG("BMI LZ Stream Start: (device: 0x%pK, address: 0x%x)", + scn, address); + + cid = BMI_LZ_STREAM_START; + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + NULL, NULL, 0); + if (status) { + BMI_ERR("Unable to Start LZ Stream to the device status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + BMI_DBG("BMI LZ Stream: Exit"); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_fast_download(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_context *ol_ctx) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t last_word = 0; + uint32_t last_word_offset = length & ~0x3; + uint32_t unaligned_bytes = length & 0x3; + + status = bmilz_stream_start(address, ol_ctx); + if (status != QDF_STATUS_SUCCESS) + goto end; + + /* copy the last word into a zero padded buffer */ + if (unaligned_bytes) + qdf_mem_copy(&last_word, &buffer[last_word_offset], + unaligned_bytes); + + status = bmilz_data(buffer, last_word_offset, ol_ctx); + + if (status != QDF_STATUS_SUCCESS) + goto end; + + if (unaligned_bytes) + status = bmilz_data((uint8_t *) &last_word, 4, ol_ctx); + + if (status != QDF_STATUS_SUCCESS) + /* + * Close compressed stream and open a new (fake) one. + * This serves mainly to flush Target caches. + */ + status = bmilz_stream_start(0x00, ol_ctx); +end: + return status; +} + +/** + * ol_cds_init() - API to initialize global CDS OL Context + * @qdf_dev: QDF Device + * @hif_ctx: HIF Context + * + * Return: Success/Failure + */ +QDF_STATUS ol_cds_init(qdf_device_t qdf_dev, void *hif_ctx) +{ + struct ol_context *ol_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (NO_BMI) + return QDF_STATUS_SUCCESS; /* no BMI for Q6 bring up */ + + status = cds_alloc_context(QDF_MODULE_ID_BMI, + (void **)&ol_info, sizeof(*ol_info)); + + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("%s: CDS Allocation failed for ol_bmi context", + __func__); + return status; + } + + ol_info->qdf_dev = qdf_dev; + ol_info->scn = hif_ctx; + ol_info->tgt_def.targetdef = hif_get_targetdef(hif_ctx); + + qdf_create_work(qdf_dev, &ol_info->ramdump_work, + ramdump_work_handler, ol_info); + qdf_create_work(qdf_dev, &ol_info->fw_indication_work, + fw_indication_work_handler, ol_info); + + qdf_wake_lock_create(&ol_info->fw_dl_wakelock, + "fw_download_wakelock"); + + return status; +} + +/** + * ol_cds_free() - API to free the global CDS OL Context + * + * Return: void + */ +void ol_cds_free(void) +{ + struct ol_context *ol_info = cds_get_context(QDF_MODULE_ID_BMI); + + if (NO_BMI) + return; + + qdf_wake_lock_destroy(&ol_info->fw_dl_wakelock); + cds_free_context(QDF_MODULE_ID_BMI, ol_info); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/bmi_1.c b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/bmi_1.c new file mode 100644 index 0000000000..b24225e6c7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/bmi_1.c @@ -0,0 +1,332 @@ +/* + * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "i_bmi.h" +#include "cds_api.h" + +/* APIs visible to the driver */ + +QDF_STATUS +bmi_read_memory(uint32_t address, + uint8_t *buffer, uint32_t length, struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, rxlen; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + uint32_t align; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (info->bmi_done) { + BMI_DBG("command disallowed"); + return QDF_STATUS_E_PERM; + } + + if (!info->bmi_cmd_buff || !info->bmi_rsp_buff) { + BMI_ERR("BMI Initialization hasn't done"); + return QDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length))); + qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length)); + qdf_mem_zero(bmi_rsp_buff, BMI_DATASZ_MAX + sizeof(cid) + + sizeof(address) + sizeof(length)); + + cid = BMI_READ_MEMORY; + align = 0; + remaining = length; + + while (remaining) { + rxlen = (remaining < BMI_DATASZ_MAX) ? + remaining : BMI_DATASZ_MAX; + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &rxlen, sizeof(rxlen)); + offset += sizeof(length); + + /* note we reuse the same buffer to receive on */ + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, + offset, bmi_rsp_buff, &rxlen, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to read from the device"); + return QDF_STATUS_E_FAILURE; + } + if (remaining == rxlen) { + qdf_mem_copy(&buffer[length - remaining + align], + bmi_rsp_buff, rxlen - align); + /* last align bytes are invalid */ + } else { + qdf_mem_copy(&buffer[length - remaining + align], + bmi_rsp_buff, rxlen); + } + remaining -= rxlen; + address += rxlen; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + uint32_t remaining, txlen; + const uint32_t header = sizeof(cid) + sizeof(address) + sizeof(length); + uint8_t aligned_buffer[BMI_DATASZ_MAX]; + uint8_t *src; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff) { + BMI_ERR("BMI initialization hasn't done"); + return QDF_STATUS_E_PERM; + } + + bmi_assert(BMI_COMMAND_FITS(BMI_DATASZ_MAX + header)); + qdf_mem_zero(bmi_cmd_buff, BMI_DATASZ_MAX + header); + + cid = BMI_WRITE_MEMORY; + + remaining = length; + while (remaining) { + src = &buffer[length - remaining]; + if (remaining < (BMI_DATASZ_MAX - header)) { + if (remaining & 3) { + /* align it with 4 bytes */ + remaining = remaining + (4 - (remaining & 3)); + memcpy(aligned_buffer, src, remaining); + src = aligned_buffer; + } + txlen = remaining; + } else { + txlen = (BMI_DATASZ_MAX - header); + } + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, + sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &txlen, sizeof(txlen)); + offset += sizeof(txlen); + qdf_mem_copy(&(bmi_cmd_buff[offset]), src, txlen); + offset += txlen; + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, + offset, NULL, NULL, + BMI_EXCHANGE_TIMEOUT_MS); + if (status) { + BMI_ERR("Unable to write to the device; status:%d", + status); + return QDF_STATUS_E_FAILURE; + } + remaining -= txlen; + address += txlen; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_execute(uint32_t address, A_UINT32 *param, struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t cid; + int status; + uint32_t offset; + uint32_t param_len; + struct bmi_info *info = GET_BMI_CONTEXT(ol_ctx); + uint8_t *bmi_cmd_buff = info->bmi_cmd_buff; + uint8_t *bmi_rsp_buff = info->bmi_rsp_buff; + uint32_t size = sizeof(cid) + sizeof(address) + sizeof(param); + qdf_dma_addr_t cmd = info->bmi_cmd_da; + qdf_dma_addr_t rsp = info->bmi_rsp_da; + + if (info->bmi_done) { + BMI_ERR("Command disallowed"); + return QDF_STATUS_E_PERM; + } + + if (!bmi_cmd_buff || !bmi_rsp_buff) { + BMI_ERR("%s:BMI CMD/RSP Buffer is NULL", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + bmi_assert(BMI_COMMAND_FITS(size)); + qdf_mem_zero(bmi_cmd_buff, size); + qdf_mem_zero(bmi_rsp_buff, size); + + + BMI_DBG("BMI Execute: device: 0x%pK, address: 0x%x, param: %d", + scn, address, *param); + + cid = BMI_EXECUTE; + + offset = 0; + qdf_mem_copy(&(bmi_cmd_buff[offset]), &cid, sizeof(cid)); + offset += sizeof(cid); + qdf_mem_copy(&(bmi_cmd_buff[offset]), &address, sizeof(address)); + offset += sizeof(address); + qdf_mem_copy(&(bmi_cmd_buff[offset]), param, sizeof(*param)); + offset += sizeof(*param); + param_len = sizeof(*param); + status = hif_exchange_bmi_msg(scn, cmd, rsp, bmi_cmd_buff, offset, + bmi_rsp_buff, ¶m_len, 0); + if (status) { + BMI_ERR("Unable to read from the device status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(param, bmi_rsp_buff, sizeof(*param)); + + BMI_DBG("BMI Execute: Exit (param: %d)", *param); + return QDF_STATUS_SUCCESS; +} + +inline QDF_STATUS +bmi_no_command(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +bmi_firmware_download(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + QDF_STATUS status; + struct bmi_target_info targ_info; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + + qdf_mem_zero(&targ_info, sizeof(targ_info)); + /* Initialize BMI */ + status = bmi_init(ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI Initialization Failed err:%d", status); + return status; + } + + /* Get target information */ + status = bmi_get_target_info(&targ_info, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI Target Info get failed: status:%d", status); + return status; + } + + tgt_info->target_type = targ_info.target_type; + tgt_info->target_version = targ_info.target_ver; + /* Configure target */ + status = ol_configure_target(ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI Configure Target Failed status:%d", status); + return status; + } + status = ol_download_firmware(ol_ctx); + if (status != QDF_STATUS_SUCCESS) + BMI_ERR("BMI Download Firmware Failed Status:%d", status); + + return status; +} + +QDF_STATUS bmi_done_local(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + int status; + uint32_t cid; + struct bmi_info *info; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + qdf_dma_addr_t cmd, rsp; + + if (!scn) { + BMI_ERR("Invalid scn context"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + if (!qdf_dev->dev) { + BMI_ERR("%s: Invalid device pointer", __func__); + return QDF_STATUS_NOT_INITIALIZED; + } + + info = GET_BMI_CONTEXT(ol_ctx); + if (info->bmi_done) { + BMI_DBG(FL("skipped")); + return QDF_STATUS_E_PERM; + } + + cmd = info->bmi_cmd_da; + rsp = info->bmi_rsp_da; + + BMI_DBG("BMI Done: Enter (device: 0x%pK)", scn); + + info->bmi_done = true; + cid = BMI_DONE; + + if (!info->bmi_cmd_buff) { + BMI_ERR("Invalid scn BMICmdBuff"); + bmi_assert(0); + return QDF_STATUS_NOT_INITIALIZED; + } + + qdf_mem_copy(info->bmi_cmd_buff, &cid, sizeof(cid)); + + status = hif_exchange_bmi_msg(scn, cmd, rsp, info->bmi_cmd_buff, + sizeof(cid), NULL, NULL, 0); + if (status) { + BMI_ERR("Failed to write to the device; status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + if (info->bmi_cmd_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_cmd_buff, info->bmi_cmd_da, 0); + info->bmi_cmd_buff = NULL; + info->bmi_cmd_da = 0; + } + + if (info->bmi_rsp_buff) { + qdf_mem_free_consistent(qdf_dev, qdf_dev->dev, + MAX_BMI_CMDBUF_SZ, + info->bmi_rsp_buff, info->bmi_rsp_da, 0); + info->bmi_rsp_buff = NULL; + info->bmi_rsp_da = 0; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h new file mode 100644 index 0000000000..4bad505a2b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/i_ar6320v2_regtable.h @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _AR6320V2_DBG_REGTABLE_H_ +#define _AR6320V2_DBG_REGTABLE_H_ + +#include "regtable.h" + +#define AR6320_REV2_1_REG_SIZE 0x0007F820 +#define AR6320_REV3_REG_SIZE 0x0007F820 + +/* + * Redefine the register list. To minimize the size of the array, the list must + * obey the below format. {start0, end0}, {start1, end1}, {start2, end2}....... + * The value below must obey to "start0 < end0 < start1 < end1 < start2 < ...", + * otherwise we may encounter error in the dump processing. + */ + +static const struct tgt_reg_section ar6320v2_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A064}, + + /* DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skipped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; + +#ifdef HIF_SDIO +static const struct tgt_reg_section ar6320v3_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8010, 0x8060}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80ec}, + {0x8110, 0x8128}, + {0x9000, 0x9004}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A074}, + + /* + * DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skipped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; +#else +static const struct tgt_reg_section ar6320v3_reg_table[] = { + {0x800, 0x810}, + {0x820, 0x82C}, + {0x830, 0x8F4}, + {0x90C, 0x91C}, + {0xA14, 0xA18}, + {0xA84, 0xA94}, + {0xAA8, 0xAD4}, + {0xADC, 0xB40}, + {0x1000, 0x10A4}, + {0x10BC, 0x111C}, + {0x1134, 0x1138}, + {0x1144, 0x114C}, + {0x1150, 0x115C}, + {0x1160, 0x1178}, + {0x1240, 0x1260}, + {0x2000, 0x207C}, + {0x3000, 0x3014}, + {0x4000, 0x4014}, + {0x5000, 0x5124}, + {0x6000, 0x6040}, + {0x6080, 0x60CC}, + {0x6100, 0x611C}, + {0x6140, 0x61D8}, + {0x6200, 0x6238}, + {0x6240, 0x628C}, + {0x62C0, 0x62EC}, + {0x6380, 0x63E8}, + {0x6400, 0x6440}, + {0x6480, 0x64CC}, + {0x6500, 0x651C}, + {0x6540, 0x6580}, + {0x6600, 0x6638}, + {0x6640, 0x668C}, + {0x66C0, 0x66EC}, + {0x6780, 0x67E8}, + {0x7080, 0x708C}, + {0x70C0, 0x70C8}, + {0x7400, 0x741C}, + {0x7440, 0x7454}, + {0x7800, 0x7818}, + {0x8000, 0x8004}, + {0x8010, 0x8064}, + {0x8080, 0x8084}, + {0x80A0, 0x80A4}, + {0x80C0, 0x80C4}, + {0x80E0, 0x80F4}, + {0x8100, 0x8104}, + {0x8110, 0x812C}, + {0x9000, 0x9004}, + {0x9800, 0x982C}, + {0x9830, 0x9838}, + {0x9840, 0x986C}, + {0x9870, 0x9898}, + {0x9A00, 0x9C00}, + {0xD580, 0xD59C}, + {0xF000, 0xF0E0}, + {0xF140, 0xF190}, + {0xF250, 0xF25C}, + {0xF260, 0xF268}, + {0xF26C, 0xF2A8}, + {0x10008, 0x1000C}, + {0x10014, 0x10018}, + {0x1001C, 0x10020}, + {0x10024, 0x10028}, + {0x10030, 0x10034}, + {0x10040, 0x10054}, + {0x10058, 0x1007C}, + {0x10080, 0x100C4}, + {0x100C8, 0x10114}, + {0x1012C, 0x10130}, + {0x10138, 0x10144}, + {0x10200, 0x10220}, + {0x10230, 0x10250}, + {0x10260, 0x10280}, + {0x10290, 0x102B0}, + {0x102C0, 0x102DC}, + {0x102E0, 0x102F4}, + {0x102FC, 0x1037C}, + {0x10380, 0x10390}, + {0x10800, 0x10828}, + {0x10840, 0x10844}, + {0x10880, 0x10884}, + {0x108C0, 0x108E8}, + {0x10900, 0x10928}, + {0x10940, 0x10944}, + {0x10980, 0x10984}, + {0x109C0, 0x109E8}, + {0x10A00, 0x10A28}, + {0x10A40, 0x10A50}, + {0x11000, 0x11028}, + {0x11030, 0x11034}, + {0x11038, 0x11068}, + {0x11070, 0x11074}, + {0x11078, 0x110A8}, + {0x110B0, 0x110B4}, + {0x110B8, 0x110E8}, + {0x110F0, 0x110F4}, + {0x110F8, 0x11128}, + {0x11138, 0x11144}, + {0x11178, 0x11180}, + {0x111B8, 0x111C0}, + {0x111F8, 0x11200}, + {0x11238, 0x1123C}, + {0x11270, 0x11274}, + {0x11278, 0x1127C}, + {0x112B0, 0x112B4}, + {0x112B8, 0x112BC}, + {0x112F0, 0x112F4}, + {0x112F8, 0x112FC}, + {0x11338, 0x1133C}, + {0x11378, 0x1137C}, + {0x113B8, 0x113BC}, + {0x113F8, 0x113FC}, + {0x11438, 0x11440}, + {0x11478, 0x11480}, + {0x114B8, 0x114BC}, + {0x114F8, 0x114FC}, + {0x11538, 0x1153C}, + {0x11578, 0x1157C}, + {0x115B8, 0x115BC}, + {0x115F8, 0x115FC}, + {0x11638, 0x1163C}, + {0x11678, 0x1167C}, + {0x116B8, 0x116BC}, + {0x116F8, 0x116FC}, + {0x11738, 0x1173C}, + {0x11778, 0x1177C}, + {0x117B8, 0x117BC}, + {0x117F8, 0x117FC}, + {0x17000, 0x1701C}, + {0x17020, 0x170AC}, + {0x18000, 0x18050}, + {0x18054, 0x18074}, + {0x18080, 0x180D4}, + {0x180DC, 0x18104}, + {0x18108, 0x1813C}, + {0x18144, 0x18148}, + {0x18168, 0x18174}, + {0x18178, 0x18180}, + {0x181C8, 0x181E0}, + {0x181E4, 0x181E8}, + {0x181EC, 0x1820C}, + {0x1825C, 0x18280}, + {0x18284, 0x18290}, + {0x18294, 0x182A0}, + {0x18300, 0x18304}, + {0x18314, 0x18320}, + {0x18328, 0x18350}, + {0x1835C, 0x1836C}, + {0x18370, 0x18390}, + {0x18398, 0x183AC}, + {0x183BC, 0x183D8}, + {0x183DC, 0x183F4}, + {0x18400, 0x186F4}, + {0x186F8, 0x1871C}, + {0x18720, 0x18790}, + {0x19800, 0x19830}, + {0x19834, 0x19840}, + {0x19880, 0x1989C}, + {0x198A4, 0x198B0}, + {0x198BC, 0x19900}, + {0x19C00, 0x19C88}, + {0x19D00, 0x19D20}, + {0x19E00, 0x19E7C}, + {0x19E80, 0x19E94}, + {0x19E98, 0x19EAC}, + {0x19EB0, 0x19EBC}, + {0x19F70, 0x19F74}, + {0x19F80, 0x19F8C}, + {0x19FA0, 0x19FB4}, + {0x19FC0, 0x19FD8}, + {0x1A000, 0x1A200}, + {0x1A204, 0x1A210}, + {0x1A228, 0x1A22C}, + {0x1A230, 0x1A248}, + {0x1A250, 0x1A270}, + {0x1A280, 0x1A290}, + {0x1A2A0, 0x1A2A4}, + {0x1A2C0, 0x1A2EC}, + {0x1A300, 0x1A3BC}, + {0x1A3F0, 0x1A3F4}, + {0x1A3F8, 0x1A434}, + {0x1A438, 0x1A444}, + {0x1A448, 0x1A468}, + {0x1A580, 0x1A58C}, + {0x1A644, 0x1A654}, + {0x1A670, 0x1A698}, + {0x1A6AC, 0x1A6B0}, + {0x1A6D0, 0x1A6D4}, + {0x1A6EC, 0x1A70C}, + {0x1A710, 0x1A738}, + {0x1A7C0, 0x1A7D0}, + {0x1A7D4, 0x1A7D8}, + {0x1A7DC, 0x1A7E4}, + {0x1A7F0, 0x1A7F8}, + {0x1A888, 0x1A89C}, + {0x1A8A8, 0x1A8AC}, + {0x1A8C0, 0x1A8DC}, + {0x1A8F0, 0x1A8FC}, + {0x1AE04, 0x1AE08}, + {0x1AE18, 0x1AE24}, + {0x1AF80, 0x1AF8C}, + {0x1AFA0, 0x1AFB4}, + {0x1B000, 0x1B200}, + {0x1B284, 0x1B288}, + {0x1B2D0, 0x1B2D8}, + {0x1B2DC, 0x1B2EC}, + {0x1B300, 0x1B340}, + {0x1B374, 0x1B378}, + {0x1B380, 0x1B384}, + {0x1B388, 0x1B38C}, + {0x1B404, 0x1B408}, + {0x1B420, 0x1B428}, + {0x1B440, 0x1B444}, + {0x1B448, 0x1B44C}, + {0x1B450, 0x1B458}, + {0x1B45C, 0x1B468}, + {0x1B584, 0x1B58C}, + {0x1B68C, 0x1B690}, + {0x1B6AC, 0x1B6B0}, + {0x1B7F0, 0x1B7F8}, + {0x1C800, 0x1CC00}, + {0x1CE00, 0x1CE04}, + {0x1CF80, 0x1CF84}, + {0x1D200, 0x1D800}, + {0x1E000, 0x20014}, + {0x20100, 0x20124}, + {0x21400, 0x217A8}, + {0x21800, 0x21BA8}, + {0x21C00, 0x21FA8}, + {0x22000, 0x223A8}, + {0x22400, 0x227A8}, + {0x22800, 0x22BA8}, + {0x22C00, 0x22FA8}, + {0x23000, 0x233A8}, + {0x24000, 0x24034}, + + /* + * EFUSE0,1,2 is disabled here + * because it's state may be reset + * + * {0x24800, 0x24804}, + * {0x25000, 0x25004}, + * {0x25800, 0x25804}, + */ + + {0x26000, 0x26064}, + {0x27000, 0x27024}, + {0x34000, 0x3400C}, + {0x34400, 0x3445C}, + {0x34800, 0x3485C}, + {0x34C00, 0x34C5C}, + {0x35000, 0x3505C}, + {0x35400, 0x3545C}, + {0x35800, 0x3585C}, + {0x35C00, 0x35C5C}, + {0x36000, 0x3605C}, + {0x38000, 0x38064}, + {0x38070, 0x380E0}, + {0x3A000, 0x3A074}, + + /* + * DBI windows is skipped here, it can be only accessed when pcie + * is active (not in reset) and CORE_CTRL_PCIE_LTSSM_EN = 0 && + * PCIE_CTRL_APP_LTSSM_ENALBE=0. + * {0x3C000 , 0x3C004}, + */ + + {0x40000, 0x400A4}, + + /* + * SI register is skipped here. + * Because it will cause bus hang + * + * {0x50000, 0x50018}, + */ + + {0x80000, 0x8000C}, + {0x80010, 0x80020}, +}; +#endif +#endif /* #ifndef _AR6320V2_DBG_REGTABLE_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/i_bmi.h b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/i_bmi.h new file mode 100644 index 0000000000..07c51204a7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/i_bmi.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* =================================================================== + * Internal BMI Header File + */ + +#ifndef _I_BMI_H_ +#define _I_BMI_H_ + +#include "qdf_types.h" +#include "qdf_defer.h" +#include "hif.h" +#include "bmi_msg.h" +#include "bmi.h" +#include "ol_fw.h" +#include "pld_common.h" + +/* + * Note that not all the register locations are accessible. + * A list of accessible target registers are specified with + * their start and end addresses in a table for given target + * version. We should NOT access other locations as either + * they are invalid locations or host does not have read + * access to it or the value of the particular register + * read might change + */ +#define REGISTER_LOCATION 0x00000800 + +#define DRAM_LOCATION 0x00400000 +#ifdef HIF_PCI +#define DRAM_SIZE 0x000a8000 +#else +#define DRAM_SIZE 0x00098000 +#endif +/* The local base addr is used to read the target dump using pcie I/O reads */ +#define DRAM_LOCAL_BASE_ADDR (0x100000) + +/* Target IRAM config */ +#define FW_RAM_CONFIG_ADDRESS 0x0018 +#define IRAM1_LOCATION 0x00980000 +#define IRAM1_SIZE 0x00080000 +#define IRAM2_LOCATION 0x00a00000 +#define IRAM2_SIZE 0x00040000 +#ifdef HIF_SDIO +#define IRAM_LOCATION 0x00980000 +#define IRAM_SIZE 0x000C0000 +#else +#define IRAM_LOCATION 0x00980000 +#define IRAM_SIZE 0x00038000 +#endif + +#define AXI_LOCATION 0x000a0000 +#ifdef HIF_PCI +#define AXI_SIZE 0x00018000 +#else +#define AXI_SIZE 0x00020000 +#endif + +#define PCIE_READ_LIMIT 0x00040000 + +#define SHA256_DIGEST_SIZE 32 + +/* BMI LOGGING WRAPPERS */ + +#define BMI_LOG(level, args...) QDF_TRACE(QDF_MODULE_ID_BMI, \ + level, ##args) +#define BMI_ERR(args ...) BMI_LOG(QDF_TRACE_LEVEL_ERROR, args) +#define BMI_DBG(args ...) BMI_LOG(QDF_TRACE_LEVEL_DEBUG, args) +#define BMI_WARN(args ...) BMI_LOG(QDF_TRACE_LEVEL_WARN, args) +#define BMI_INFO(args ...) BMI_LOG(QDF_TRACE_LEVEL_INFO, args) +/* End of BMI Logging Wrappers */ + +/* BMI Assert Wrappers */ +#define bmi_assert QDF_BUG +/* + * Although we had envisioned BMI to run on top of HTC, this is not how the + * final implementation ended up. On the Target side, BMI is a part of the BSP + * and does not use the HTC protocol nor even DMA -- it is intentionally kept + * very simple. + */ + +#define MAX_BMI_CMDBUF_SZ (BMI_DATASZ_MAX + \ + sizeof(uint32_t) /* cmd */ + \ + sizeof(uint32_t) /* addr */ + \ + sizeof(uint32_t)) /* length */ +#define BMI_COMMAND_FITS(sz) ((sz) <= MAX_BMI_CMDBUF_SZ) +#define BMI_EXCHANGE_TIMEOUT_MS 1000 + +struct hash_fw { + u8 qwlan[SHA256_DIGEST_SIZE]; + u8 otp[SHA256_DIGEST_SIZE]; + u8 bdwlan[SHA256_DIGEST_SIZE]; + u8 utf[SHA256_DIGEST_SIZE]; +}; + +enum ATH_BIN_FILE { + ATH_OTP_FILE, + ATH_FIRMWARE_FILE, + ATH_PATCH_FILE, + ATH_BOARD_DATA_FILE, + ATH_FLASH_FILE, + ATH_SETUP_FILE, +}; + +#if defined(QCA_WIFI_3_0_ADRASTEA) +#define NO_BMI 1 +#else +#define NO_BMI 0 +#endif + +/** + * struct bmi_info - Structure to hold BMI Specific information + * @bmi_cmd_buff: BMI Command Buffer + * @bmi_rsp_buff: BMI Response Buffer + * @bmi_cmd_da: BMI Command Physical address + * @bmi_rsp_da: BMI Response Physical address + * @bmi_done: Flag to check if BMI Phase is complete + * @board_id: board ID + * @fw_files: FW files + * + */ +struct bmi_info { + uint8_t *bmi_cmd_buff; + uint8_t *bmi_rsp_buff; + dma_addr_t bmi_cmd_da; + dma_addr_t bmi_rsp_da; + bool bmi_done; + uint16_t board_id; + struct pld_fw_files fw_files; +}; + +/** + * struct ol_context - Structure to hold OL context + * @bmi: BMI info + * @cfg_info: OL config info + * @cal_in_flash: For Firmware Flash Download + * @qdf_dev: QDF Device + * @ramdump_work: Work for Ramdump collection + * @fw_indication_work: Work for Fw indication + * @fw_dl_wakelock: Firmware download wakelock + * @scn: HIF Context + * @tgt_def: Target Defnition pointer + * @fw_crashed_cb: Callback for firmware crashed ind + * + * Structure to hold all ol BMI/Ramdump info + */ +struct ol_context { + struct bmi_info bmi; + struct ol_config_info cfg_info; + uint8_t *cal_in_flash; + qdf_device_t qdf_dev; + qdf_work_t ramdump_work; + qdf_work_t fw_indication_work; + qdf_wake_lock_t fw_dl_wakelock; + struct hif_opaque_softc *scn; + struct targetdef_t { + struct targetdef_s *targetdef; + } tgt_def; + void (*fw_crashed_cb)(void); +}; + +#define GET_BMI_CONTEXT(ol_ctx) ((struct bmi_info *)ol_ctx) + +QDF_STATUS bmi_execute(uint32_t address, uint32_t *param, + struct ol_context *ol_ctx); +QDF_STATUS bmi_init(struct ol_context *ol_ctx); +QDF_STATUS bmi_no_command(struct ol_context *ol_ctx); +QDF_STATUS bmi_read_memory(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx); +QDF_STATUS bmi_write_memory(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx); +QDF_STATUS bmi_fast_download(uint32_t address, uint8_t *buffer, uint32_t length, + struct ol_context *ol_ctx); +QDF_STATUS bmi_read_soc_register(uint32_t address, + uint32_t *param, struct ol_context *ol_ctx); +QDF_STATUS bmi_write_soc_register(uint32_t address, uint32_t param, + struct ol_context *ol_ctx); +QDF_STATUS bmi_get_target_info(struct bmi_target_info *targ_info, + struct ol_context *ol_ctx); +QDF_STATUS bmi_firmware_download(struct ol_context *ol_ctx); +QDF_STATUS bmi_done_local(struct ol_context *ol_ctx); +QDF_STATUS ol_download_firmware(struct ol_context *ol_ctx); +QDF_STATUS ol_configure_target(struct ol_context *ol_ctx); +QDF_STATUS bmi_sign_stream_start(uint32_t address, uint8_t *buffer, + uint32_t length, struct ol_context *ol_ctx); +void ramdump_work_handler(void *arg); +void fw_indication_work_handler(void *arg); +struct ol_config_info *ol_get_ini_handle(struct ol_context *ol_ctx); + +#ifdef HIF_SDIO +QDF_STATUS hif_reg_based_get_target_info(struct hif_opaque_softc *hif_ctx, + struct bmi_target_info *targ_info); +#endif +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) || defined(HIF_USB) +static inline QDF_STATUS +hif_reg_based_get_target_info(struct hif_opaque_softc *hif_ctx, + struct bmi_target_info *targ_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/ol_fw.c b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/ol_fw.c new file mode 100644 index 0000000000..414bcbfffa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/ol_fw.c @@ -0,0 +1,1964 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "ol_if_athvar.h" +#include "qdf_time.h" +#include "targaddrs.h" +#include "ol_cfg.h" +#include "cds_api.h" +#include "wma_api.h" +#include "wma.h" +#include "bin_sig.h" +#include "i_ar6320v2_regtable.h" +#include "epping_main.h" +#ifdef HIF_PCI +#include "ce_reg.h" +#endif +#if defined(HIF_SDIO) +#include "if_sdio.h" +#include "regtable_sdio.h" +#endif +#if defined(HIF_USB) +#include "if_usb.h" +#include "regtable_usb.h" +#endif +#include "pld_common.h" +#include "hif_main.h" + +#include "i_bmi.h" +#include "qwlan_version.h" +#include "wlan_policy_mgr_api.h" +#include "dbglog_host.h" + +#ifdef FEATURE_SECURE_FIRMWARE +static struct hash_fw fw_hash; +#endif + +static uint32_t refclk_speed_to_hz[] = { + 48000000, /* SOC_REFCLK_48_MHZ */ + 19200000, /* SOC_REFCLK_19_2_MHZ */ + 24000000, /* SOC_REFCLK_24_MHZ */ + 26000000, /* SOC_REFCLK_26_MHZ */ + 37400000, /* SOC_REFCLK_37_4_MHZ */ + 38400000, /* SOC_REFCLK_38_4_MHZ */ + 40000000, /* SOC_REFCLK_40_MHZ */ + 52000000, /* SOC_REFCLK_52_MHZ */ +}; + +static int ol_target_coredump(void *inst, void *memory_block, + uint32_t block_len); + +#ifdef FEATURE_SECURE_FIRMWARE +static int ol_check_fw_hash(struct device *dev, const u8 *data, + u32 fw_size, enum ATH_BIN_FILE file) +{ + u8 *hash = NULL; + u8 *fw_mem = NULL; + u8 digest[SHA256_DIGEST_SIZE]; + u8 temp[SHA256_DIGEST_SIZE] = { }; + int ret = 0; + + switch (file) { + case ATH_BOARD_DATA_FILE: + hash = fw_hash.bdwlan; + break; + case ATH_OTP_FILE: + hash = fw_hash.otp; + break; + case ATH_FIRMWARE_FILE: +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hash = fw_hash.utf; + break; + } +#endif + hash = fw_hash.qwlan; + default: + break; + } + + if (!hash) { + BMI_INFO("No entry for file:%d Download FW in non-secure mode", + file); + goto end; + } + + if (qdf_mem_cmp(hash, temp, SHA256_DIGEST_SIZE)) { + BMI_INFO("Download FW in non-secure mode:%d", file); + goto end; + } + + fw_mem = pld_get_fw_ptr(dev); + if (!fw_mem || (fw_size > MAX_FIRMWARE_SIZE)) { + BMI_ERR("No Memory to copy FW data"); + ret = -1; + goto end; + } + qdf_mem_copy(fw_mem, data, fw_size); + + ret = pld_get_sha_hash(dev, fw_mem, fw_size, "sha256", digest); + + if (ret) { + BMI_ERR("Sha256 Hash computation failed err:%d", ret); + goto end; + } + + if (qdf_mem_cmp(hash, digest, SHA256_DIGEST_SIZE)) { + BMI_ERR("Hash Mismatch"); + qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + digest, SHA256_DIGEST_SIZE); + qdf_trace_hex_dump(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, + hash, SHA256_DIGEST_SIZE); + ret = QDF_STATUS_E_FAILURE; + } +end: + return ret; +} +#endif + +/** + * ol_board_id_to_filename() - Auto BDF board_id to filename conversion + * @old_name: name of the default board data file + * @board_id: board ID + * + * The API return board filename based on the board_id and chip_id. + * eg: input = "bdwlan30.bin", board_id = 0x01, board_file = "bdwlan30.b01" + * Return: The buffer with the formatted board filename. + */ +static char *ol_board_id_to_filename(const char *old_name, + uint16_t board_id) +{ + int name_len; + char *new_name; + + name_len = strlen(old_name); + new_name = qdf_mem_malloc(name_len + 1); + + if (!new_name) + goto out; + + if (board_id > 0xFF) + board_id = 0x0; + + qdf_mem_copy(new_name, old_name, name_len); + snprintf(&new_name[name_len - 2], 3, "%.2x", board_id); +out: + return new_name; +} + +#ifdef QCA_SIGNED_SPLIT_BINARY_SUPPORT +#define SIGNED_SPLIT_BINARY_VALUE true +#else +#define SIGNED_SPLIT_BINARY_VALUE false +#endif + +static int +__ol_transfer_bin_file(struct ol_context *ol_ctx, enum ATH_BIN_FILE file, + uint32_t address, bool compressed) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + int status = 0; + const char *filename; + const struct firmware *fw_entry; + uint32_t fw_entry_size; + uint8_t *temp_eeprom; + uint32_t board_data_size; + bool bin_sign = false; + int bin_off, bin_len; + SIGN_HEADER_T *sign_header; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + struct bmi_info *bmi_ctx = GET_BMI_CONTEXT(ol_ctx); + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + int i; + + /* + * If there is no board data file bases on board id, the default + * board data file should be used. + * For factory mode, the sequence for file selection should be + * utfbd.board_id -> utfbd.bin -> bd.board_id -> bd.bin. So we + * need to cache 4 file names. + */ + uint32_t bd_files = 1; + char *bd_id_filename[2] = {NULL, NULL}; + const char *bd_filename[2] = {NULL, NULL}; + + switch (file) { + default: + BMI_ERR("%s: Unknown file type", __func__); + return -EINVAL; + case ATH_OTP_FILE: + filename = bmi_ctx->fw_files.otp_data; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + + break; + case ATH_FIRMWARE_FILE: + if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + filename = bmi_ctx->fw_files.epping_file; + BMI_INFO("%s: Loading epping firmware file %s", + __func__, filename); + break; + } +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + filename = bmi_ctx->fw_files.utf_file; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + BMI_INFO("%s: Loading firmware file %s", + __func__, filename); + break; + } +#endif + if (cds_get_conparam() == QDF_GLOBAL_IBSS_MODE && + (bmi_ctx->fw_files.ibss_image_file[0] != '\0')) { + filename = bmi_ctx->fw_files.ibss_image_file; + } else { + filename = bmi_ctx->fw_files.image_file; + } + + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + break; + case ATH_PATCH_FILE: + BMI_INFO("%s: no Patch file defined", __func__); + return 0; + case ATH_BOARD_DATA_FILE: + filename = bmi_ctx->fw_files.board_data; +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + filename = bmi_ctx->fw_files.utf_board_data; + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + + BMI_INFO("%s: Loading board data file %s", + __func__, filename); + + /* + * In FTM mode, if utf files do not exit. + * bdwlan should be used. + */ + bd_files = 2; + } +#endif /* QCA_WIFI_FTM */ + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = false; + + bd_filename[0] = filename; + + /* + * For factory mode, we should cache 2 group of file names. + * For mission mode, bd_files==1, only one group of file names. + */ + bd_filename[bd_files - 1] = + bmi_ctx->fw_files.board_data; + for (i = 0; i < bd_files; i++) { + bd_id_filename[i] = + ol_board_id_to_filename(bd_filename[i], + bmi_ctx->board_id); + if (bd_id_filename[i]) { + BMI_INFO("%s: board data file is %s", + __func__, bd_id_filename[i]); + } else { + BMI_ERR("%s: Fail to allocate board filename", + __func__); + } + } + break; + case ATH_SETUP_FILE: + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + filename = bmi_ctx->fw_files.setup_file; + if (filename[0] == 0) { + BMI_INFO("%s: no Setup file defined", __func__); + return -EPERM; + } + + if (SIGNED_SPLIT_BINARY_VALUE) + bin_sign = true; + + BMI_INFO("%s: Loading setup file %s", + __func__, filename); + } else { + BMI_INFO("%s: no Setup file needed", __func__); + return -EPERM; + } + break; + } + + /* For FTM mode. bd.bin is used if there is no utf.bin */ + if (file == ATH_BOARD_DATA_FILE) { + for (i = 0; i < bd_files; i++) { + if (bd_id_filename[i]) { + BMI_DBG("%s: Trying to load %s", + __func__, bd_id_filename[i]); + status = request_firmware(&fw_entry, + bd_id_filename[i], + qdf_dev->dev); + if (!status) + break; + BMI_ERR("%s: Failed to get %s:%d", + __func__, bd_id_filename[i], + status); + } + + /* bd.board_id not exits, using bd.bin */ + BMI_DBG("%s: Trying to load default %s", + __func__, bd_filename[i]); + status = request_firmware(&fw_entry, bd_filename[i], + qdf_dev->dev); + if (!status) + break; + BMI_ERR("%s: Failed to get default %s:%d", + __func__, bd_filename[i], status); + } + } else { + status = request_firmware(&fw_entry, filename, qdf_dev->dev); + } + + if (status) { + BMI_ERR("%s: Failed to get %s", __func__, filename); + status = -ENOENT; + goto release_fw; + } + + if (!fw_entry || !fw_entry->data) { + BMI_ERR("Invalid fw_entries"); + status = -ENOENT; + goto release_fw; + } + + fw_entry_size = fw_entry->size; + temp_eeprom = NULL; + +#ifdef FEATURE_SECURE_FIRMWARE + if (ol_check_fw_hash(qdf_dev->dev, fw_entry->data, + fw_entry_size, file)) { + BMI_ERR("Hash Check failed for file:%s", filename); + status = -EINVAL; + goto end; + } +#endif + + if (file == ATH_BOARD_DATA_FILE) { + uint32_t board_ext_address = 0; + int32_t board_ext_data_size; + + temp_eeprom = qdf_mem_malloc(fw_entry_size); + if (!temp_eeprom) { + status = -ENOMEM; + goto release_fw; + } + + qdf_mem_copy(temp_eeprom, (uint8_t *) fw_entry->data, + fw_entry_size); + + switch (target_type) { + case TARGET_TYPE_AR6004: + board_data_size = AR6004_BOARD_DATA_SZ; + board_ext_data_size = AR6004_BOARD_EXT_DATA_SZ; + break; + case TARGET_TYPE_AR9888: + board_data_size = AR9888_BOARD_DATA_SZ; + board_ext_data_size = AR9888_BOARD_EXT_DATA_SZ; + break; + default: + board_data_size = 0; + board_ext_data_size = 0; + break; + } + + /* Determine where in Target RAM to write Board Data */ + bmi_read_memory(HOST_INTEREST_ITEM_ADDRESS(target_type, + hi_board_ext_data), + (uint8_t *) &board_ext_address, 4, ol_ctx); + BMI_INFO("Board extended Data download address: 0x%x", + board_ext_address); + + /* Check whether the target has allocated memory for extended + * board data and file contains extended board data + */ + + if ((board_ext_address) + && (fw_entry_size == + (board_data_size + board_ext_data_size))) { + uint32_t param; + + status = bmi_write_memory(board_ext_address, + (uint8_t *)(temp_eeprom + + board_data_size), + board_ext_data_size, ol_ctx); + + if (status) + goto end; + + /* Record extended board Data initialized */ + param = (board_ext_data_size << 16) | 1; + bmi_write_memory( + HOST_INTEREST_ITEM_ADDRESS(target_type, + hi_board_ext_data_config), + (uint8_t *)¶m, 4, ol_ctx); + + fw_entry_size = board_data_size; + } + } + + if (bin_sign && SIGNED_SPLIT_BINARY_VALUE) { + uint32_t chip_id; + + if (fw_entry_size < sizeof(SIGN_HEADER_T)) { + BMI_ERR("Invalid binary size %d", fw_entry_size); + status = -EINVAL; + goto end; + } + + sign_header = (SIGN_HEADER_T *) fw_entry->data; + chip_id = cpu_to_le32(sign_header->product_id); + if (sign_header->magic_num == SIGN_HEADER_MAGIC + && (chip_id == AR6320_REV1_1_VERSION + || chip_id == AR6320_REV1_3_VERSION + || chip_id == AR6320_REV2_1_VERSION)) { + + bin_off = sizeof(SIGN_HEADER_T); + status = bmi_sign_stream_start(address, + (uint8_t *)fw_entry->data, + bin_off, ol_ctx); + if (status) { + BMI_ERR("unable to start sign stream"); + status = -EINVAL; + goto end; + } + + bin_len = sign_header->rampatch_len - bin_off; + if (bin_len <= 0 || bin_len > fw_entry_size - bin_off) { + BMI_ERR("Invalid sign header"); + status = -EINVAL; + goto end; + } + } else { + bin_sign = false; + bin_off = 0; + bin_len = fw_entry_size; + } + } else { + bin_len = fw_entry_size; + bin_off = 0; + } + + if (compressed) { + status = bmi_fast_download(address, + (uint8_t *) fw_entry->data + bin_off, + bin_len, ol_ctx); + } else { + if (file == ATH_BOARD_DATA_FILE && fw_entry->data) { + status = bmi_write_memory(address, + (uint8_t *) temp_eeprom, + fw_entry_size, ol_ctx); + } else { + status = bmi_write_memory(address, + (uint8_t *) fw_entry->data + + bin_off, bin_len, ol_ctx); + } + } + + if (bin_sign && SIGNED_SPLIT_BINARY_VALUE) { + bin_off += bin_len; + bin_len = sign_header->total_len - sign_header->rampatch_len; + + if (bin_len > 0 && bin_len <= fw_entry_size - bin_off) { + status = bmi_sign_stream_start(0, + (uint8_t *)fw_entry->data + + bin_off, bin_len, ol_ctx); + if (status) + BMI_ERR("sign stream error"); + } + } + +end: + if (temp_eeprom) + qdf_mem_free(temp_eeprom); + +release_fw: + if (fw_entry) + release_firmware(fw_entry); + + for (i = 0; i < bd_files; i++) { + if (bd_id_filename[i]) { + qdf_mem_free(bd_id_filename[i]); + bd_id_filename[i] = NULL; + } + } + + if (status) + BMI_ERR("%s, BMI operation failed: %d", __func__, __LINE__); + else + BMI_INFO("transferring file: %s size %d bytes done!", + (filename) ? filename : " ", fw_entry_size); + return status; +} + +static int +ol_transfer_bin_file(struct ol_context *ol_ctx, enum ATH_BIN_FILE file, + uint32_t address, bool compressed) +{ +#define MAX_WAKELOCK_FOR_FW_DOWNLOAD 1000 //1s + int ret; + + qdf_wake_lock_timeout_acquire(&ol_ctx->fw_dl_wakelock, + MAX_WAKELOCK_FOR_FW_DOWNLOAD); + + ret = __ol_transfer_bin_file(ol_ctx, file, address, compressed); + + qdf_wake_lock_release(&ol_ctx->fw_dl_wakelock, 0); + + return ret; +} + +/** + * struct ramdump_info: Structure to hold ramdump information + * @base: Base address for Ramdump collection + * @size: Size of the dump + * + * Ramdump information. + */ +struct ramdump_info { + void *base; + unsigned long size; +}; + +/* + * if have platform driver support, reinit will be called by CNSS. + * recovery flag will be cleaned and CRASHED indication will be sent + * to user space by reinit function. If not support, clean recovery + * flag and send CRASHED indication in CLD driver. + */ +static inline void ol_check_clean_recovery_flag(struct ol_context *ol_ctx) +{ + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + if (!pld_have_platform_driver_support(qdf_dev->dev)) { + if (ol_ctx->fw_crashed_cb) + ol_ctx->fw_crashed_cb(); + } +} + +#if !defined(QCA_WIFI_3_0) +static inline void ol_get_ramdump_mem(struct device *dev, + struct ramdump_info *info) +{ + info->base = pld_get_virt_ramdump_mem(dev, &info->size); +} + +static inline void ol_release_ramdump_mem(struct device *dev, + struct ramdump_info *info) +{ + pld_release_virt_ramdump_mem(dev, info->base); +} +#else +static inline void ol_get_ramdump_mem(struct device *dev, + struct ramdump_info *info) { } +static inline void ol_release_ramdump_mem(struct device *dev, + struct ramdump_info *info) { } +#endif + +int ol_copy_ramdump(struct hif_opaque_softc *scn) +{ + int ret = -1; + struct ramdump_info *info; + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) + return -EINVAL; + + if (pld_is_fw_dump_skipped(qdf_dev->dev)) { + BMI_INFO("%s ssr enabled, skip ramdump", __func__); + return 0; + } + info = qdf_mem_malloc(sizeof(struct ramdump_info)); + if (!info) + return -ENOMEM; + + ol_get_ramdump_mem(qdf_dev->dev, info); + + if (!info->base || !info->size) { + BMI_ERR("%s:ramdump collection fail", __func__); + qdf_mem_free(info); + return -EACCES; + } + + ret = ol_target_coredump(scn, info->base, info->size); + + ol_release_ramdump_mem(qdf_dev->dev, info); + qdf_mem_free(info); + return ret; +} + +static void __ramdump_work_handler(void *data) +{ + int ret; + uint32_t host_interest_address; + uint32_t dram_dump_values[4]; + uint32_t target_type; + struct hif_target_info *tgt_info; + struct ol_context *ol_ctx = data; + struct hif_opaque_softc *ramdump_scn = ol_ctx->scn; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!ramdump_scn) { + BMI_ERR("%s:Ramdump_scn is null:", __func__); + goto out_fail; + } + tgt_info = hif_get_target_info_handle(ramdump_scn); + target_type = tgt_info->target_type; +#ifdef WLAN_DEBUG + ret = hif_check_soc_status(ramdump_scn); + if (ret) + goto out_fail; + + ret = hif_dump_registers(ramdump_scn); + if (ret) + goto out_fail; + +#endif + + if (hif_diag_read_mem(ramdump_scn, + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_failure_state)), + (uint8_t *)&host_interest_address, + sizeof(uint32_t)) != QDF_STATUS_SUCCESS) { + BMI_ERR("HifDiagReadiMem FW Dump Area Pointer failed!"); + ol_copy_ramdump(ramdump_scn); + pld_device_crashed(qdf_dev->dev); + ol_check_clean_recovery_flag(ol_ctx); + + return; + } + + BMI_ERR("Host interest item address: 0x%08x", host_interest_address); + + if (hif_diag_read_mem(ramdump_scn, host_interest_address, + (uint8_t *) &dram_dump_values[0], + 4 * sizeof(uint32_t)) != QDF_STATUS_SUCCESS) { + BMI_ERR("HifDiagReadiMem FW Dump Area failed!"); + goto out_fail; + } + BMI_ERR("FW Assertion at PC: 0x%08x BadVA: 0x%08x TargetID: 0x%08x", + dram_dump_values[2], dram_dump_values[3], dram_dump_values[0]); + + if (ol_copy_ramdump(ramdump_scn)) + goto out_fail; + + BMI_ERR("%s: RAM dump collecting completed!", __func__); + qdf_event_set(&wma->recovery_event); + + /* + * if unloading is in progress, then skip SSR, + * otherwise notify SSR framework the target has crashed. + */ + if (cds_is_load_or_unload_in_progress()) + cds_set_recovery_in_progress(false); + else { + pld_device_crashed(qdf_dev->dev); + ol_check_clean_recovery_flag(ol_ctx); + } + return; + +out_fail: + qdf_event_set(&wma->recovery_event); + /* Silent SSR on dump failure */ + if (ini_cfg->enable_self_recovery) + pld_device_self_recovery(qdf_dev->dev, + PLD_REASON_DEFAULT); + else + pld_device_crashed(qdf_dev->dev); + + ol_check_clean_recovery_flag(ol_ctx); +} + +void ramdump_work_handler(void *data) +{ + struct qdf_op_sync *op_sync; + + if (qdf_op_protect(&op_sync)) + return; + + __ramdump_work_handler(data); + + qdf_op_unprotect(op_sync); +} + +void fw_indication_work_handler(void *data) +{ + struct ol_context *ol_ctx = data; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + pld_device_self_recovery(qdf_dev->dev, + PLD_REASON_DEFAULT); + + ol_check_clean_recovery_flag(ol_ctx); +} + +void ol_target_failure(void *instance, QDF_STATUS status) +{ + struct ol_context *ol_ctx = instance; + struct hif_opaque_softc *scn = ol_ctx->scn; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + int ret; + bool skip_recovering_check = false; + enum hif_target_status target_status = hif_get_target_status(scn); + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SNOC) { + BMI_ERR("SNOC doesn't support this code path!"); + return; + } + + /* If Host driver trigger target failure, skip recovering check */ + if (cds_is_target_asserting()) + skip_recovering_check = true; + + if (TARGET_STATUS_RESET == target_status) { + BMI_ERR("Target is already asserted, ignore!"); + goto out; + } + + hif_set_target_status(scn, TARGET_STATUS_RESET); + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) { + if (status == QDF_STATUS_E_USB_ERROR) + hif_ramdump_handler(scn); + goto out; + } + + if (!skip_recovering_check && cds_is_driver_recovering()) { + BMI_ERR("%s: Recovery in progress, ignore!\n", __func__); + return; + } + + if (cds_is_driver_in_bad_state()) { + BMI_ERR("%s: Driver in bad state, ignore!\n", __func__); + goto out; + } + + if (cds_is_load_or_unload_in_progress()) { + BMI_ERR("%s: Loading/Unloading is in progress, ignore!", + __func__); + goto out; + } + cds_set_target_ready(false); + cds_set_recovery_in_progress(true); + + ret = hif_check_fw_reg(scn); + if (0 == ret) { + if (ini_cfg->enable_self_recovery) { + qdf_sched_work(0, &ol_ctx->fw_indication_work); + goto out; + } + } else if (-1 == ret) { + goto out; + } + + BMI_ERR("XXX TARGET ASSERTED XXX"); + + cds_svc_fw_shutdown_ind(qdf_dev->dev); + /* Collect the RAM dump through a workqueue */ + if (ini_cfg->enable_ramdump_collection) { + qdf_sched_work(0, &ol_ctx->ramdump_work); + } else { + pr_debug("%s: athdiag read for target reg\n", __func__); + qdf_event_set(&wma->recovery_event); + } + + return; +out: + qdf_event_set(&wma->recovery_event); + return; +} + +#ifdef CONFIG_DISABLE_CDC_MAX_PERF_WAR +static QDF_STATUS ol_disable_cdc_max_perf(struct ol_context *ol_ctx) +{ + uint32_t param; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + + /* set the firmware to disable CDC max perf WAR */ + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ for setting cdc max perf failed"); + return QDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_DISABLE_CDC_MAX_PERF_WAR; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("setting cdc max perf failed"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#else +static QDF_STATUS ol_disable_cdc_max_perf(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + +#ifdef WLAN_FEATURE_LPSS +static QDF_STATUS ol_set_lpass_support(struct ol_context *ol_ctx) +{ + uint32_t param; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + uint32_t target_type = tgt_info->target_type; + + if (ini_cfg->enable_lpass_support) { + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ:Setting LPASS Support failed"); + return QDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_DBUART_SUPPORT; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI_READ for setting LPASS Support fail"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +#else +static QDF_STATUS ol_set_lpass_support(struct ol_context *ol_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + + +QDF_STATUS ol_configure_target(struct ol_context *ol_ctx) +{ + uint32_t param; + struct pld_platform_cap cap = {0}; + int ret; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + /* Tell target which HTC version it is used */ + param = HTC_PROTOCOL_VERSION; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_app_host_interest)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("bmi_write_memory for htc version failed"); + return QDF_STATUS_E_FAILURE; + } + + /* set the firmware mode to STA/IBSS/AP */ + { + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("bmi_read_memory for setting fwmode failed"); + return QDF_STATUS_E_FAILURE; + } + + /* TODO following parameters need to be re-visited. */ + param |= (1 << HI_OPTION_NUM_DEV_SHIFT); /* num_device */ + /* Firmware mode ?? */ + param |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT); + /* mac_addr_method */ + param |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT); + /* firmware_bridge */ + param |= (0 << HI_OPTION_FW_BRIDGE_SHIFT); + /* fwsubmode */ + param |= (0 << HI_OPTION_FW_SUBMODE_SHIFT); + + BMI_INFO("NUM_DEV=%d FWMODE=0x%x FWSUBMODE=0x%x FWBR_BUF %d", + 1, HI_OPTION_FW_MODE_AP, 0, 0); + + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE for setting fwmode failed"); + return QDF_STATUS_E_FAILURE; + } + } + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_PCI) { + if (ol_disable_cdc_max_perf(ol_ctx)) + return QDF_STATUS_E_FAILURE; + + qdf_mem_zero(&cap, sizeof(cap)); + + ret = pld_get_platform_cap(qdf_dev->dev, &cap); + if (ret) + BMI_ERR("platform capability info not available"); + + if (!ret && cap.cap_flag & PLD_HAS_EXTERNAL_SWREG) { + if (bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != + QDF_STATUS_SUCCESS) { + BMI_ERR("BMI READ failed for external SWREG"); + return QDF_STATUS_E_FAILURE; + } + + param |= HI_OPTION_USE_EXT_LDO; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_option_flag2)), + (uint8_t *)¶m, 4, ol_ctx) != + QDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE failed for external SWREG"); + return QDF_STATUS_E_FAILURE; + } + } + + if (ol_set_lpass_support(ol_ctx)) + return QDF_STATUS_E_FAILURE; + } + + /* If host is running on a BE CPU, set the host interest area */ + { +#ifdef BIG_ENDIAN_HOST + param = 1; +#else + param = 0; +#endif + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_be)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("setting host CPU BE mode failed"); + return QDF_STATUS_E_FAILURE; + } + } + + /* FW descriptor/Data swap flags */ + param = 0; + if (bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_fw_swap)), + (uint8_t *) ¶m, 4, ol_ctx) != QDF_STATUS_SUCCESS) { + BMI_ERR("BMI WRITE failed setting FW data/desc swap flags"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static int +ol_check_dataset_patch(struct hif_opaque_softc *scn, uint32_t *address) +{ + /* Check if patch file needed for this target type/version. */ + return 0; +} + +static QDF_STATUS ol_fw_populate_clk_settings(enum a_refclk_speed_t refclk, + struct cmnos_clock_s *clock_s) +{ + if (!clock_s) + return QDF_STATUS_E_FAILURE; + + switch (refclk) { + case SOC_REFCLK_48_MHZ: + clock_s->wlan_pll.div = 0xE; + clock_s->wlan_pll.rnfrac = 0x2AAA8; + clock_s->pll_settling_time = 2400; + break; + case SOC_REFCLK_19_2_MHZ: + clock_s->wlan_pll.div = 0x24; + clock_s->wlan_pll.rnfrac = 0x2AAA8; + clock_s->pll_settling_time = 960; + break; + case SOC_REFCLK_24_MHZ: + clock_s->wlan_pll.div = 0x1D; + clock_s->wlan_pll.rnfrac = 0x15551; + clock_s->pll_settling_time = 1200; + break; + case SOC_REFCLK_26_MHZ: + clock_s->wlan_pll.div = 0x1B; + clock_s->wlan_pll.rnfrac = 0x4EC4; + clock_s->pll_settling_time = 1300; + break; + case SOC_REFCLK_37_4_MHZ: + clock_s->wlan_pll.div = 0x12; + clock_s->wlan_pll.rnfrac = 0x34B49; + clock_s->pll_settling_time = 1870; + break; + case SOC_REFCLK_38_4_MHZ: + clock_s->wlan_pll.div = 0x12; + clock_s->wlan_pll.rnfrac = 0x15551; + clock_s->pll_settling_time = 1920; + break; + case SOC_REFCLK_40_MHZ: + clock_s->wlan_pll.div = 0x11; + clock_s->wlan_pll.rnfrac = 0x26665; + clock_s->pll_settling_time = 2000; + break; + case SOC_REFCLK_52_MHZ: + clock_s->wlan_pll.div = 0x1B; + clock_s->wlan_pll.rnfrac = 0x4EC4; + clock_s->pll_settling_time = 2600; + break; + case SOC_REFCLK_UNKNOWN: + clock_s->wlan_pll.refdiv = 0; + clock_s->wlan_pll.div = 0; + clock_s->wlan_pll.rnfrac = 0; + clock_s->wlan_pll.outdiv = 0; + clock_s->pll_settling_time = 1024; + clock_s->refclk_hz = 0; + fallthrough; + default: + return QDF_STATUS_E_FAILURE; + } + + clock_s->refclk_hz = refclk_speed_to_hz[refclk]; + clock_s->wlan_pll.refdiv = 0; + clock_s->wlan_pll.outdiv = 1; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS ol_patch_pll_switch(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *hif = ol_ctx->scn; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t addr = 0; + uint32_t reg_val = 0; + uint32_t mem_val = 0; + struct cmnos_clock_s clock_s; + uint32_t cmnos_core_clk_div_addr = 0; + uint32_t cmnos_cpu_pll_init_done_addr = 0; + uint32_t cmnos_cpu_speed_addr = 0; + struct hif_target_info *tgt_info = hif_get_target_info_handle(hif); + uint32_t target_version = tgt_info->target_version; + struct targetdef_t *scn = &ol_ctx->tgt_def; + + switch (target_version) { + case AR6320_REV1_1_VERSION: + cmnos_core_clk_div_addr = AR6320_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320_CPU_SPEED_ADDR; + break; + case AR6320_REV1_3_VERSION: + case AR6320_REV2_1_VERSION: + cmnos_core_clk_div_addr = AR6320V2_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320V2_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320V2_CPU_SPEED_ADDR; + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case QCA9379_REV1_VERSION: + case QCA9377_REV1_1_VERSION: + cmnos_core_clk_div_addr = AR6320V3_CORE_CLK_DIV_ADDR; + cmnos_cpu_pll_init_done_addr = AR6320V3_CPU_PLL_INIT_DONE_ADDR; + cmnos_cpu_speed_addr = AR6320V3_CPU_SPEED_ADDR; + break; + default: + BMI_ERR("%s: Unsupported target version %x", __func__, + target_version); + goto end; + } + + addr = (RTC_SOC_BASE_ADDRESS | EFUSE_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read EFUSE Addr"); + goto end; + } + + status = ol_fw_populate_clk_settings(EFUSE_XTAL_SEL_GET(reg_val), + &clock_s); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to set clock settings"); + goto end; + } + BMI_DBG("crystal_freq: %dHz", clock_s.refclk_hz); + + /* ------Step 1---- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | BB_PLL_CONFIG_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CONFIG Addr"); + goto end; + } + BMI_DBG("Step 1a: %8X", reg_val); + + reg_val &= ~(BB_PLL_CONFIG_FRAC_MASK | BB_PLL_CONFIG_OUTDIV_MASK); + reg_val |= (BB_PLL_CONFIG_FRAC_SET(clock_s.wlan_pll.rnfrac) | + BB_PLL_CONFIG_OUTDIV_SET(clock_s.wlan_pll.outdiv)); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CONFIG Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CONFIG Addr"); + goto end; + } + BMI_DBG("Step 1b: %8X", reg_val); + + /* ------Step 2---- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_SETTLE_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_SETTLE Addr"); + goto end; + } + BMI_DBG("Step 2a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_SETTLE_TIME_MASK; + reg_val |= WLAN_PLL_SETTLE_TIME_SET(clock_s.pll_settling_time); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_SETTLE Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_SETTLE Addr"); + goto end; + } + BMI_DBG("Step 2b: %8X", reg_val); + + /* ------Step 3---- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | SOC_CORE_CLK_CTRL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read CLK_CTRL Addr"); + goto end; + } + BMI_DBG("Step 3a: %8X", reg_val); + + reg_val &= ~SOC_CORE_CLK_CTRL_DIV_MASK; + reg_val |= SOC_CORE_CLK_CTRL_DIV_SET(1); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CLK_CTRL Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back CLK_CTRL Addr"); + goto end; + } + BMI_DBG("Step 3b: %8X", reg_val); + + /* ------Step 4----- */ + mem_val = 1; + status = bmi_write_memory(cmnos_core_clk_div_addr, + (uint8_t *) &mem_val, 4, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CLK_DIV Addr"); + goto end; + } + + /* ------Step 5----- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr"); + goto end; + } + BMI_DBG("Step 5a: %8X", reg_val); + + reg_val &= ~(WLAN_PLL_CONTROL_REFDIV_MASK | WLAN_PLL_CONTROL_DIV_MASK | + WLAN_PLL_CONTROL_NOPWD_MASK); + reg_val |= (WLAN_PLL_CONTROL_REFDIV_SET(clock_s.wlan_pll.refdiv) | + WLAN_PLL_CONTROL_DIV_SET(clock_s.wlan_pll.div) | + WLAN_PLL_CONTROL_NOPWD_SET(1)); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr"); + goto end; + } + qdf_udelay(100); + BMI_DBG("Step 5b: %8X", reg_val); + + /* ------Step 6------- */ + do { + reg_val = 0; + status = bmi_read_soc_register((RTC_WMAC_BASE_ADDRESS | + RTC_SYNC_STATUS_OFFSET), ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read RTC_SYNC_STATUS Addr"); + goto end; + } + } while (RTC_SYNC_STATUS_PLL_CHANGING_GET(reg_val)); + + /* ------Step 7------- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + BMI_DBG("Step 7a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_CONTROL_BYPASS_MASK; + reg_val |= WLAN_PLL_CONTROL_BYPASS_SET(0); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr for CTRL_BYPASS"); + goto end; + } + BMI_DBG("Step 7b: %8X", reg_val); + + /* ------Step 8-------- */ + do { + reg_val = 0; + status = bmi_read_soc_register((RTC_WMAC_BASE_ADDRESS | + RTC_SYNC_STATUS_OFFSET), ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read SYNC_STATUS Addr"); + goto end; + } + } while (RTC_SYNC_STATUS_PLL_CHANGING_GET(reg_val)); + + /* ------Step 9-------- */ + reg_val = 0; + addr = (RTC_SOC_BASE_ADDRESS | SOC_CPU_CLOCK_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read CPU_CLK Addr"); + goto end; + } + BMI_DBG("Step 9a: %8X", reg_val); + + reg_val &= ~SOC_CPU_CLOCK_STANDARD_MASK; + reg_val |= SOC_CPU_CLOCK_STANDARD_SET(1); + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CPU_CLK Addr"); + goto end; + } + + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back CPU_CLK Addr"); + goto end; + } + BMI_DBG("Step 9b: %8X", reg_val); + + /* ------Step 10------- */ + reg_val = 0; + addr = (RTC_WMAC_BASE_ADDRESS | WLAN_PLL_CONTROL_OFFSET); + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read PLL_CTRL Addr for NOPWD"); + goto end; + } + BMI_DBG("Step 10a: %8X", reg_val); + + reg_val &= ~WLAN_PLL_CONTROL_NOPWD_MASK; + status = bmi_write_soc_register(addr, reg_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_CTRL Addr for NOPWD"); + goto end; + } + reg_val = 0; + status = bmi_read_soc_register(addr, ®_val, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to read back PLL_CTRL Addr for NOPWD"); + goto end; + } + BMI_DBG("Step 10b: %8X", reg_val); + + /* ------Step 11------- */ + mem_val = 1; + status = bmi_write_memory(cmnos_cpu_pll_init_done_addr, + (uint8_t *) &mem_val, 4, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write PLL_INIT Addr"); + goto end; + } + + mem_val = TARGET_CPU_FREQ; + status = bmi_write_memory(cmnos_cpu_speed_addr, + (uint8_t *) &mem_val, 4, ol_ctx); + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("Failed to write CPU_SPEED Addr"); + goto end; + } + +end: + return status; +} + +QDF_STATUS ol_download_firmware(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + uint32_t param, address = 0; + QDF_STATUS status = !QDF_STATUS_SUCCESS; + QDF_STATUS ret; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + struct ol_config_info *ini_cfg = ol_get_ini_handle(ol_ctx); + uint32_t target_type = tgt_info->target_type; + uint32_t target_version = tgt_info->target_version; + struct bmi_info *bmi_ctx = GET_BMI_CONTEXT(ol_ctx); + qdf_device_t qdf_dev = ol_ctx->qdf_dev; + + if (0 != pld_get_fw_files_for_target(qdf_dev->dev, + &bmi_ctx->fw_files, + target_type, + target_version)) { + BMI_ERR("%s: No FW files from platform driver", __func__); + return QDF_STATUS_E_FAILURE; + } + + /* Transfer Board Data from Target EEPROM to Target RAM */ + /* Determine where in Target RAM to write Board Data */ + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_board_data)), + (uint8_t *)&address, 4, ol_ctx); + + if (!address) { + address = AR6004_REV5_BOARD_DATA_ADDRESS; + BMI_DBG("%s: Target address not known! Using 0x%x", + __func__, address); + } + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_USB) { + ret = ol_patch_pll_switch(ol_ctx); + if (ret != QDF_STATUS_SUCCESS) { + BMI_ERR("pll switch failed. status %d", ret); + return ret; + } + } + + if (ol_ctx->cal_in_flash) { + /* Write EEPROM or Flash data to Target RAM */ + status = ol_transfer_bin_file(ol_ctx, ATH_FLASH_FILE, + address, false); + } + + if (!status) { + /* Record the fact that Board Data is initialized */ + param = 1; + bmi_write_memory( + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_board_data_initialized)), + (uint8_t *) ¶m, 4, ol_ctx); + } else { + /* Transfer One Time Programmable data */ + address = BMI_SEGMENTED_WRITE_ADDR; + BMI_INFO("%s: Using 0x%x for the remainder of init", + __func__, address); + + status = ol_transfer_bin_file(ol_ctx, ATH_OTP_FILE, + address, true); + /* Execute the OTP code only if entry found and downloaded */ + if (!status) { + uint16_t board_id = 0xffff; + /* get board id */ + param = 0x10; + bmi_execute(address, ¶m, ol_ctx); + if (!(param & 0xff)) + board_id = (param >> 8) & 0xffff; + BMI_INFO("%s: board ID is 0x%0x", __func__, board_id); + bmi_ctx->board_id = board_id; + } else if (status < 0) { + return status; + } + + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_board_data)), + (uint8_t *)&address, 4, ol_ctx); + + if (!address) { + address = AR6004_REV5_BOARD_DATA_ADDRESS; + pr_err("%s: Target address not known! Using 0x%x\n", + __func__, address); + } + + /* Flash is either not available or invalid */ + if (ol_transfer_bin_file(ol_ctx, ATH_BOARD_DATA_FILE, + address, false)) { + return QDF_STATUS_E_FAILURE; + } + + /* Record the fact that Board Data is initialized */ + param = 1; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_board_data_initialized)), + (uint8_t *) ¶m, 4, ol_ctx); + address = BMI_SEGMENTED_WRITE_ADDR; + param = 0; + bmi_execute(address, ¶m, ol_ctx); + } + + if (!ol_transfer_bin_file(ol_ctx, ATH_SETUP_FILE, + BMI_SEGMENTED_WRITE_ADDR, true)) { + param = 0; + bmi_execute(address, ¶m, ol_ctx); + } + + /* Download Target firmware + * TODO point to target specific files in runtime + */ + address = BMI_SEGMENTED_WRITE_ADDR; + if (ol_transfer_bin_file(ol_ctx, ATH_FIRMWARE_FILE, + address, true)) { + return QDF_STATUS_E_FAILURE; + } + + /* Apply the patches */ + if (ol_check_dataset_patch(scn, &address)) { + if (ol_transfer_bin_file(ol_ctx, ATH_PATCH_FILE, address, + false)) { + return QDF_STATUS_E_FAILURE; + } + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_dset_list_head)), + (uint8_t *) &address, 4, ol_ctx); + } + + switch (target_version) { + case AR6004_VERSION_REV1_3: + param = 11; + break; + case AR6320_REV1_VERSION: + case AR6320_REV2_VERSION: + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case QCA9377_REV1_1_VERSION: + case QCA9379_REV1_VERSION: + case AR6320_REV4_VERSION: + case AR6320_DEV_VERSION: + /* + * In sdio interface chip, both sdio_data2 and uart_tx pin + * will use GPIO6. It is set by fw rom code, which will cause + * sdio CRC error when there is sdio transaction. + * Override uart tx pin to avoid side effect to sdio pin. + */ + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO) + param = 19; + else + param = 6; + break; + default: + /* Configure GPIO AR9888 UART */ + param = 7; + } + + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_dbg_uart_txpin)), + (uint8_t *)¶m, 4, ol_ctx); + + if (ini_cfg->enable_uart_print) { + param = 1; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_serial_enable)), + (uint8_t *)¶m, 4, ol_ctx); + } else { + /* + * Explicitly setting UART prints to zero as target turns it on + * based on scratch registers. + */ + param = 0; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_serial_enable)), + (uint8_t *)¶m, 4, ol_ctx); + } + + if (ini_cfg->enable_fw_log) { + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx); + + param &= ~(HI_OPTION_DISABLE_DBGLOG); + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx); + } else { + /* + * Explicitly setting fwlog prints to zero as target turns it on + * based on scratch registers. + */ + bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *)¶m, 4, ol_ctx); + + param |= HI_OPTION_DISABLE_DBGLOG; + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_option_flag)), + (uint8_t *) ¶m, 4, ol_ctx); + } + status = ol_extra_initialization(ol_ctx); + + return status; +} + +static int ol_diag_read(struct hif_opaque_softc *scn, uint8_t *buffer, + uint32_t pos, size_t count) +{ + int result = 0; + + if ((4 == count) && ((pos & 3) == 0)) { + result = hif_diag_read_access(scn, pos, + (uint32_t *) buffer); + } else { + size_t amount_read = 0; + size_t readSize = PCIE_READ_LIMIT; + size_t remainder = 0; + + if (count > PCIE_READ_LIMIT) { + while ((amount_read < count) && (0 == result)) { + result = hif_diag_read_mem(scn, pos, + buffer, readSize); + if (0 == result) { + buffer += readSize; + pos += readSize; + amount_read += readSize; + remainder = count - amount_read; + if (remainder < PCIE_READ_LIMIT) + readSize = remainder; + } + } + } else { + result = hif_diag_read_mem(scn, pos, + buffer, count); + } + } + + if (!result) + return count; + else + return -EIO; +} + +static int ol_ath_get_reg_table(struct hif_opaque_softc *scn, + uint32_t target_version, + struct tgt_reg_table *reg_table) +{ + int section_len = 0; + + if (!reg_table) { + qdf_assert(0); + return section_len; + } + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_PCI && + hif_get_bus_type(scn) != QDF_BUS_TYPE_SDIO) + return section_len; + + switch (target_version) { + case AR6320_REV2_1_VERSION: + reg_table->section = ar6320v2_reg_table; + reg_table->section_size = ARRAY_SIZE(ar6320v2_reg_table); + section_len = AR6320_REV2_1_REG_SIZE; + break; + case AR6320_REV3_VERSION: + case AR6320_REV3_2_VERSION: + case QCA9379_REV1_VERSION: + case QCA9377_REV1_1_VERSION: + reg_table->section = ar6320v3_reg_table; + reg_table->section_size = ARRAY_SIZE(ar6320v3_reg_table); + section_len = AR6320_REV3_REG_SIZE; + break; + default: + reg_table->section = NULL; + reg_table->section_size = 0; + section_len = 0; + } + + return section_len; +} + +static int ol_diag_read_reg_loc(struct hif_opaque_softc *scn, uint8_t *buffer, + uint32_t buffer_len) +{ + int i, len, section_len, fill_len; + int dump_len, result = 0; + struct tgt_reg_table reg_table; + const struct tgt_reg_section *curr_sec, *next_sec; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_version = tgt_info->target_version; + + reg_table.section = NULL; + reg_table.section_size = 0; + + section_len = ol_ath_get_reg_table(scn, target_version, ®_table); + + if (!reg_table.section || !reg_table.section_size || !section_len) { + BMI_ERR("%s: failed to get reg table", __func__); + result = -EIO; + goto out; + } + + curr_sec = reg_table.section; + for (i = 0; i < reg_table.section_size; i++) { + + dump_len = curr_sec->end_addr - curr_sec->start_addr; + + if ((buffer_len - result) < dump_len) { + BMI_ERR("No buffer to dump regs:%d: 0x%08x-0x%08x", + i, curr_sec->start_addr, curr_sec->end_addr); + goto out; + } + + len = ol_diag_read(scn, buffer, curr_sec->start_addr, dump_len); + + if (len != -EIO) { + buffer += len; + result += len; + } else { + BMI_ERR("%s: can't read reg 0x%08x len = %d", + __func__, curr_sec->start_addr, dump_len); + result = -EIO; + goto out; + } + + if (result < section_len) { + next_sec = (struct tgt_reg_section *) ((uint8_t *) + curr_sec + sizeof(*curr_sec)); + fill_len = next_sec->start_addr - curr_sec->end_addr; + if ((buffer_len - result) < fill_len) { + BMI_ERR("No buf to fill regs:%d: 0x%08x-0x%08x", + i, curr_sec->end_addr, + next_sec->start_addr); + goto out; + } + + if (fill_len) { + buffer += fill_len; + result += fill_len; + } + } + curr_sec++; + } + +out: + return result; +} + +static +void ol_dump_target_memory(struct hif_opaque_softc *scn, void *memory_block) +{ + char *buffer_loc = memory_block; + u_int32_t section_count = 0; + u_int32_t address = 0; + u_int32_t size = 0; + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO || + hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) + return; + + for (; section_count < 2; section_count++) { + switch (section_count) { + case 0: + address = DRAM_LOCAL_BASE_ADDR; + size = DRAM_SIZE; + break; + case 1: + address = AXI_LOCATION; + size = AXI_SIZE; + break; + default: + break; + } + hif_dump_target_memory(scn, buffer_loc, address, size); + buffer_loc += size; + } +} + +static int +ol_dump_ce_register(struct hif_opaque_softc *scn, void *memory_block) +{ + int ret; + + BMI_ERR("Could not read dump section!"); + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO || + hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) + return 0; + + if (hif_dump_registers(scn)) + BMI_ERR("Failed to dump bus registers"); + + ol_dump_target_memory(scn, memory_block); + ret = -EACCES; + + return ret; +} + +static inline uint32_t +ol_get_max_section_count(struct hif_opaque_softc *scn) +{ + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_PCI) + return 5; + else + return 4; +} + +/** + * ol_set_ram_config_reg() - set target RAM configuration register + * @scn: pointer of hif_softc context + * @config: value to be written to the register + * + * This function will write the given value to target RAM configuration + * register which is bit[23-20] of target CPU inbound address in order to + * provide correct address mapping. + * + * Return: 0 for success or reasons for failure + */ +static int ol_set_ram_config_reg(struct hif_opaque_softc *scn, uint32_t config) +{ + QDF_STATUS status; + uint32_t val; + struct targetdef_s *targetdef = + (struct targetdef_s *)hif_get_targetdef(scn); + uint32_t ram_config_addr = + targetdef->d_SOC_CORE_BASE_ADDRESS + FW_RAM_CONFIG_ADDRESS; + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_PCI) + return -EACCES; + + status = hif_diag_write_access(scn, ram_config_addr, config); + if (QDF_IS_STATUS_ERROR(status)) { + return -EACCES; + } + status = hif_diag_read_access(scn, ram_config_addr, &val); + if (QDF_IS_STATUS_ERROR(status)) { + return -EACCES; + } + if (val != config) { + BMI_ERR("%s: Failed to set RAM config reg from 0x%x to 0x%x", + __func__, val, config); + return -EACCES; + } + return 0; +} + +static int +ol_get_iram_len_and_pos(struct hif_opaque_softc *scn, uint32_t *pos, + uint32_t *len, uint32_t section) +{ + enum hif_target_status status; + uint32_t iram_addr, iram_size; + int ret; + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_PCI) { + *pos = IRAM_LOCATION; + *len = IRAM_SIZE; + BMI_ERR("%s: Dumping IRAM Section", __func__); + return 0; + } + + status = hif_get_target_status(scn); + if (status != TARGET_STATUS_RESET) { + BMI_ERR("%s: Target status invalid: %d", __func__, status); + return -EBUSY; + } + + switch (section) { + case 3: + BMI_ERR("%s: Dumping IRAM1 section", __func__); + iram_addr = IRAM1_LOCATION; + iram_size = IRAM1_SIZE; + break; + case 4: + BMI_ERR("%s: Dumping IRAM2 section", __func__); + iram_addr = IRAM2_LOCATION; + iram_size = IRAM2_SIZE; + break; + default: + BMI_ERR("%s: Invalid input iram section %d", + __func__, section); + return A_EINVAL; + } + + ret = ol_set_ram_config_reg(scn, iram_addr >> 20); + if (ret) { + BMI_ERR("%s: Skip IRAM1 ret:%d", __func__, ret); + return -EBUSY; + } + + *pos = iram_addr; + *len = iram_size; + return 0; +} + +/** + * ol_target_coredump() - API to collect target ramdump + * @inst: private context + * @memory_block: non-NULL reserved memory location + * @block_len: size of the dump to collect + * + * Function to perform core dump for the target. + * + * Return: int + */ +static int ol_target_coredump(void *inst, void *memory_block, + uint32_t block_len) +{ + struct hif_opaque_softc *scn = (struct hif_opaque_softc *)inst; + int8_t *buffer_loc = memory_block; + int result = 0; + int ret = 0; + uint32_t amount_read = 0; + uint32_t section_count = 0; + uint32_t pos = 0; + uint32_t read_len = 0; + uint32_t max_count = ol_get_max_section_count(scn); + + while ((section_count < max_count) && (amount_read < block_len)) { + switch (section_count) { + case 0: + pos = DRAM_LOCATION; + read_len = DRAM_SIZE; + BMI_ERR("%s: Dumping DRAM section...", __func__); + break; + case 1: + pos = AXI_LOCATION; + read_len = AXI_SIZE; + BMI_ERR("%s: Dumping AXI section...", __func__); + break; + case 2: + pos = REGISTER_LOCATION; + /* ol_diag_read_reg_loc checks for buffer overrun */ + read_len = 0; + BMI_ERR("%s: Dumping Register section...", __func__); + break; + case 3: + case 4: + ret = ol_get_iram_len_and_pos(scn, &pos, &read_len, + section_count); + if (ret) { + BMI_ERR("%s: Fail to Dump IRAM Section " + "ret:%d", __func__, ret); + return ret; + } + break; + default: + BMI_ERR("%s: INVALID SECTION_:%d", __func__, + section_count); + return 0; + } + + if (block_len - amount_read < read_len) { + BMI_ERR("%s: No memory to dump section:%d buffer!", + __func__, section_count); + return -ENOMEM; + } + + if (((hif_get_bus_type(scn) == QDF_BUS_TYPE_PCI) || + (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO)) && + pos == REGISTER_LOCATION) + result = ol_diag_read_reg_loc(scn, buffer_loc, + block_len - amount_read); + else + result = ol_diag_read(scn, buffer_loc, pos, read_len); + + if (result == -EIO) + return ol_dump_ce_register(scn, memory_block); + + BMI_INFO("%s: Section:%d Bytes Read:%0x", __func__, + section_count, result); + + amount_read += result; + buffer_loc += result; + section_count++; + } + return ret; +} + +/** + * ol_get_ini_handle() - API to get Ol INI configuration + * @ol_ctx: OL Context + * + * Return: pointer to OL configuration + */ +struct ol_config_info *ol_get_ini_handle(struct ol_context *ol_ctx) +{ + return &ol_ctx->cfg_info; +} + +/** + * ol_init_ini_config() - API to initialize INI configuration + * @ol_ctx: OL Context + * @cfg: OL ini configuration + * + * Return: void + */ +void ol_init_ini_config(struct ol_context *ol_ctx, + struct ol_config_info *cfg) +{ + qdf_mem_copy(&ol_ctx->cfg_info, cfg, sizeof(struct ol_config_info)); +} + +void ol_set_fw_crashed_cb(struct ol_context *ol_ctx, + void (*callback_fn)(void)) +{ + ol_ctx->fw_crashed_cb = callback_fn; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/ol_fw_common.c b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/ol_fw_common.c new file mode 100644 index 0000000000..da353dfdbe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/bmi/src/ol_fw_common.c @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ol_if_athvar.h" +#include "targaddrs.h" +#include "ol_cfg.h" +#include "i_ar6320v2_regtable.h" +#include "ol_fw.h" +#ifdef HIF_PCI +#include "ce_reg.h" +#endif +#if defined(HIF_SDIO) +#include "regtable_sdio.h" +#endif +#if defined(HIF_USB) +#include "regtable_usb.h" +#endif +#include "i_bmi.h" +#include "cds_api.h" + +#ifdef CONFIG_DISABLE_SLEEP_BMI_OPTION +static inline void ol_sdio_disable_sleep(struct ol_context *ol_ctx) +{ + uint32_t value; + + BMI_ERR("prevent ROME from sleeping"); + bmi_read_soc_register(MBOX_BASE_ADDRESS + LOCAL_SCRATCH_OFFSET, + /* this address should be 0x80C0 for ROME*/ + &value, + ol_ctx); + + value |= SOC_OPTION_SLEEP_DISABLE; + + bmi_write_soc_register(MBOX_BASE_ADDRESS + LOCAL_SCRATCH_OFFSET, + value, + ol_ctx); +} + +#else +static inline void ol_sdio_disable_sleep(struct ol_context *ol_ctx) +{ +} + +#endif + +/** + * ol_usb_extra_initialization() - USB extra initialization + * @ol_ctx: pointer to ol_context + * + * USB specific initialization after firmware download + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +static QDF_STATUS +ol_usb_extra_initialization(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = + hif_get_target_info_handle(scn); + QDF_STATUS status = !QDF_STATUS_SUCCESS; + u_int32_t param = 0; + + param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; + status = bmi_write_memory( + hif_hia_item_address(tgt_info->target_type, + offsetof(struct host_interest_s, + hi_acs_flags)), + (u_int8_t *)¶m, 4, ol_ctx); + + return status; +} + +/*Setting SDIO block size, mbox ISR yield limit for SDIO based HIF*/ +static +QDF_STATUS ol_sdio_extra_initialization(struct ol_context *ol_ctx) +{ + + QDF_STATUS status; + uint32_t param; + uint32_t blocksizes[HTC_MAILBOX_NUM_MAX]; + uint32_t MboxIsrYieldValue = 99; + struct hif_opaque_softc *scn = ol_ctx->scn; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + + /* get the block sizes */ + status = hif_get_config_item(scn, + HIF_DEVICE_GET_BLOCK_SIZE, + blocksizes, sizeof(blocksizes)); + if (status) { + BMI_ERR("Failed to get block size info from HIF layer"); + goto exit; + } + /* note: we actually get the block size for mailbox 1, + * for SDIO the block size on mailbox 0 is artificially + * set to 1 must be a power of 2 + */ + qdf_assert((blocksizes[1] & (blocksizes[1] - 1)) == 0); + + /* set the host interest area for the block size */ + status = bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_mbox_io_block_sz)), + (uint8_t *)&blocksizes[1], + 4, + ol_ctx); + + if (status) { + BMI_ERR("BMIWriteMemory for IO block size failed"); + goto exit; + } + + if (MboxIsrYieldValue != 0) { + /* set the host for the mbox ISR yield limit */ + status = + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_mbox_isr_yield_limit)), + (uint8_t *)&MboxIsrYieldValue, + 4, + ol_ctx); + + if (status) { + BMI_ERR("BMI write for yield limit failed\n"); + goto exit; + } + } + ol_sdio_disable_sleep(ol_ctx); + status = bmi_read_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_acs_flags)), + (uint8_t *)¶m, + 4, + ol_ctx); + if (status) { + BMI_ERR("BMIReadMemory for hi_acs_flags failed"); + goto exit; + } + + param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; + + /* disable swap mailbox for FTM */ + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) + param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET; + + if (!cds_is_ptp_tx_opt_enabled()) + param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET; + + /* enable TX completion to collect tx_desc for pktlog */ + if (cds_is_packet_log_enabled()) + param &= ~HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET; + + bmi_write_memory(hif_hia_item_address(target_type, + offsetof(struct host_interest_s, + hi_acs_flags)), + (uint8_t *)¶m, 4, ol_ctx); +exit: + return status; +} + +/** + * ol_extra_initialization() - OL extra initialization + * @ol_ctx: pointer to ol_context + * + * Bus specific initialization after firmware download + * + * Return: QDF_STATUS_SUCCESS on success and error QDF status on failure + */ +QDF_STATUS ol_extra_initialization(struct ol_context *ol_ctx) +{ + struct hif_opaque_softc *scn = ol_ctx->scn; + + if (hif_get_bus_type(scn) == QDF_BUS_TYPE_SDIO) + return ol_sdio_extra_initialization(ol_ctx); + else if (hif_get_bus_type(scn) == QDF_BUS_TYPE_USB) + return ol_usb_extra_initialization(ol_ctx); + + return QDF_STATUS_SUCCESS; +} + +void ol_target_ready(struct hif_opaque_softc *scn, void *cfg_ctx) +{ + uint32_t value = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hif_target_info *tgt_info = hif_get_target_info_handle(scn); + uint32_t target_type = tgt_info->target_type; + + if (hif_get_bus_type(scn) != QDF_BUS_TYPE_SDIO) + return; + status = hif_diag_read_mem(scn, + hif_hia_item_address(target_type, + offsetof(struct host_interest_s, hi_acs_flags)), + (uint8_t *)&value, sizeof(u_int32_t)); + + if (status != QDF_STATUS_SUCCESS) { + BMI_ERR("HIFDiagReadMem failed"); + return; + } + + if (value & HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK) { + BMI_ERR("MAILBOX SWAP Service is enabled!"); + hif_set_mailbox_swap(scn); + } + + if (value & HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK) { + BMI_ERR("Reduced Tx Complete service is enabled!"); + ol_cfg_set_tx_free_at_download(cfg_ctx); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_api.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_api.h new file mode 100644 index 0000000000..1cd479b251 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_api.h @@ -0,0 +1,653 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__CDS_API_H) +#define __CDS_API_H + +/** + * DOC: cds_api.h + * + * Connectivity driver services public API + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "qdf_platform.h" +#include "qdf_cpuhp.h" +#include +#include "reg_services_public_struct.h" +#include +#include +#include +#include +#include +#include +#include + +/* The ini gReorderOffloadSupported is deprecated. So, defining a new macro + * DP_REORDER_OFFLOAD_SUPPORT with the ini's default value. + */ +#define DP_REORDER_OFFLOAD_SUPPORT (1) + +/* Amount of time to wait for WMA to perform an asynchronous activity. + * This value should be larger than the timeout used by WMI to wait for + * a response from target + */ +#define CDS_WMA_TIMEOUT (15000) + +/** + * enum cds_driver_state - Driver state + * @CDS_DRIVER_STATE_UNINITIALIZED: Driver is in uninitialized state. + * @CDS_DRIVER_STATE_LOADED: Driver is loaded and functional. + * @CDS_DRIVER_STATE_LOADING: Driver probe is in progress. + * @CDS_DRIVER_STATE_UNLOADING: Driver remove is in progress. + * @CDS_DRIVER_STATE_RECOVERING: Recovery in progress. + * @CDS_DRIVER_STATE_BAD: Driver in bad state. + * @CDS_DRIVER_STATE_FW_READY: Driver Firmware ready + * @CDS_DRIVER_STATE_MODULE_STOP: Module stop in progress or done. + * @CDS_DRIVER_STATE_ASSERTING_TARGET: Driver assert target in progress. + * @CDS_DRIVER_STATE_SYS_REBOOTING: System reboot in progress. + */ +enum cds_driver_state { + CDS_DRIVER_STATE_UNINITIALIZED = 0, + CDS_DRIVER_STATE_LOADED = BIT(0), + CDS_DRIVER_STATE_LOADING = BIT(1), + CDS_DRIVER_STATE_UNLOADING = BIT(2), + CDS_DRIVER_STATE_RECOVERING = BIT(3), + CDS_DRIVER_STATE_BAD = BIT(4), + CDS_DRIVER_STATE_FW_READY = BIT(5), + CDS_DRIVER_STATE_MODULE_STOP = BIT(6), + CDS_DRIVER_STATE_ASSERTING_TARGET = BIT(7), + CDS_DRIVER_STATE_SYS_REBOOTING = BIT(8), +}; + +/** + * struct cds_vdev_dp_stats - vdev stats populated from DP + * @tx_retries: packet number of successfully transmitted after more + * than one retransmission attempt + * @tx_retries_mpdu: mpdu number of successfully transmitted after more + * than one retransmission attempt + * @tx_mpdu_success_with_retries: Number of MPDU transmission retries done + * in case of successful transmission. + */ +struct cds_vdev_dp_stats { + uint32_t tx_retries; + uint32_t tx_retries_mpdu; + uint32_t tx_mpdu_success_with_retries; +}; + +#define __CDS_IS_DRIVER_STATE(_state, _mask) (((_state) & (_mask)) == (_mask)) + +void cds_set_driver_state(enum cds_driver_state); +void cds_clear_driver_state(enum cds_driver_state); +enum cds_driver_state cds_get_driver_state(void); + +/** + * cds_is_driver_loading() - Is driver load in progress + * + * Return: true if driver is loading and false otherwise. + */ +static inline bool cds_is_driver_loading(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADING); +} + +/** + * cds_is_driver_unloading() - Is driver unload in progress + * + * Return: true if driver is unloading and false otherwise. + */ +static inline bool cds_is_driver_unloading(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_UNLOADING); +} + +/** + * cds_is_driver_recovering() - Is recovery in progress + * + * Return: true if recovery in progress and false otherwise. + */ +static inline bool cds_is_driver_recovering(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_RECOVERING); +} + +/** + * cds_is_driver_in_bad_state() - is driver in bad state + * + * Return: true if driver is in bad state and false otherwise. + */ +static inline bool cds_is_driver_in_bad_state(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_BAD); +} + +/** + * cds_is_load_or_unload_in_progress() - Is driver load OR unload in progress + * + * Return: true if driver is loading OR unloading and false otherwise. + */ +static inline bool cds_is_load_or_unload_in_progress(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADING) || + __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_UNLOADING); +} + +/** + * cds_is_target_ready() - Is target is in ready state + * + * Return: true if target is in ready state and false otherwise. + */ +static inline bool cds_is_target_ready(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_FW_READY); +} + +/** + * cds_is_driver_state_module_stop - Is module stop is in-progress or done + * + * Return: true if driver state is module stop and false otherwise. + */ +static inline bool cds_is_driver_state_module_stop(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_MODULE_STOP); +} + +/** + * cds_set_recovery_in_progress() - Set recovery in progress + * @value: value to set + * + * Return: none + */ +static inline void cds_set_recovery_in_progress(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_RECOVERING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_RECOVERING); +} + +/** + * cds_set_driver_in_bad_state() - Set driver state + * @value: value to set + * + * Return: none + */ +static inline void cds_set_driver_in_bad_state(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_BAD); + else + cds_clear_driver_state(CDS_DRIVER_STATE_BAD); +} + +/** + * cds_set_target_ready() - Set target ready state + * @value: value to set + * + * Return: none + */ +static inline void cds_set_target_ready(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_FW_READY); + else + cds_clear_driver_state(CDS_DRIVER_STATE_FW_READY); +} + +/** + * cds_set_load_in_progress() - Set load in progress + * @value: value to set + * + * Return: none + */ +static inline void cds_set_load_in_progress(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_LOADING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_LOADING); +} + +/** + * cds_set_driver_loaded() - Set load completed + * @value: value to set + * + * Return: none + */ +static inline void cds_set_driver_loaded(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_LOADED); + else + cds_clear_driver_state(CDS_DRIVER_STATE_LOADED); +} + +/** + * cds_set_unload_in_progress() - Set unload in progress + * @value: value to set + * + * Return: none + */ +static inline void cds_set_unload_in_progress(uint8_t value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_UNLOADING); + else + cds_clear_driver_state(CDS_DRIVER_STATE_UNLOADING); +} + +/** + * cds_set_driver_state_module_stop() - Setting module stop in progress or done + * + * @value: value to set + * + * Return: none + */ +static inline void cds_set_driver_state_module_stop(bool value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_MODULE_STOP); + else + cds_clear_driver_state(CDS_DRIVER_STATE_MODULE_STOP); +} + +/** + * cds_is_driver_loaded() - Is driver loaded + * + * Return: true if driver is loaded or false otherwise. + */ +static inline bool cds_is_driver_loaded(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADED); +} + +/** + * cds_set_assert_target_in_progress() - Setting assert target in progress + * + * @value: value to set + * + * Return: none + */ +static inline void cds_set_assert_target_in_progress(bool value) +{ + if (value) + cds_set_driver_state(CDS_DRIVER_STATE_ASSERTING_TARGET); + else + cds_clear_driver_state(CDS_DRIVER_STATE_ASSERTING_TARGET); +} + +/** + * cds_is_target_asserting() - Is driver asserting target + * + * Return: true if driver is asserting target + */ +static inline bool cds_is_target_asserting(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_ASSERTING_TARGET); +} + +/** + * cds_set_sys_rebooting() - Set system reboot in progress + * + * Return: none + */ +void cds_set_sys_rebooting(void); + +/** + * cds_sys_reboot_protect() - Require the lock for system reboot and get + * system rebooting state + * + * cds_sys_reboot_protect() and cds_sys_reboot_unprotect() MUST be used + * in pair. + * + * Return: true if system is rebooting, false otherwise + */ +bool cds_sys_reboot_protect(void); + +/** + * cds_sys_reboot_unprotect() - Release the lock for system reboot + * + * Return: none + */ +void cds_sys_reboot_unprotect(void); + +/** + * cds_init() - Initialize CDS + * + * This function allocates the resource required for CDS, but does not + * initialize all the members. This overall initialization will happen at + * cds_open(). + * + * Return: QDF_STATUS_SUCCESS if CDS was initialized and an error on failure + */ +QDF_STATUS cds_init(void); + +void cds_deinit(void); + +QDF_STATUS cds_pre_enable(void); + +QDF_STATUS cds_open(struct wlan_objmgr_psoc *psoc); + +/** + * cds_dp_open() - Open datapath module + * @psoc: object manager soc handle + * + * API to map the datapath rings to interrupts + * and also open the datapath pdev module. + * + * Return: QDF status + */ +QDF_STATUS cds_dp_open(struct wlan_objmgr_psoc *psoc); + +/** + * cds_enable() - start/enable cds module + * @psoc: Psoc pointer + * + * Return: QDF status + */ +QDF_STATUS cds_enable(struct wlan_objmgr_psoc *psoc); + +QDF_STATUS cds_disable(struct wlan_objmgr_psoc *psoc); + +QDF_STATUS cds_post_disable(void); + +QDF_STATUS cds_close(struct wlan_objmgr_psoc *psoc); + +/** + * cds_dp_close() - Close datapath module + * @psoc: Object manager soc handle + * + * API used to detach interrupts assigned to service + * datapath rings and close pdev module + * + * Return: Status + */ +QDF_STATUS cds_dp_close(struct wlan_objmgr_psoc *psoc); + +/** + * cds_get_context() - get context data area + * @module_id: ID of the module who's context data is being retrieved. + * + * Each module in the system has a context/data area that is allocated + * and managed by CDS. This API allows any user to get a pointer to its + * allocated context data area from the CDS global context. + * + * Return: pointer to the context data area of the module ID + * specified, or NULL if the context data is not allocated for + * the module ID specified. + */ +#define cds_get_context(module_id) \ + __cds_get_context(module_id, __func__) +void *__cds_get_context(QDF_MODULE_ID module_id, const char *func); + +void *cds_get_global_context(void); + +QDF_STATUS cds_alloc_context(QDF_MODULE_ID module_id, void **module_context, + uint32_t size); + +QDF_STATUS cds_free_context(QDF_MODULE_ID module_id, void *module_context); + +QDF_STATUS cds_set_context(QDF_MODULE_ID module_id, void *context); + +void cds_flush_work(void *work); +void cds_flush_delayed_work(void *dwork); + +#ifdef REMOVE_PKT_LOG +static inline +bool cds_is_packet_log_enabled(void) +{ + return false; +} +#else +bool cds_is_packet_log_enabled(void); +#endif + +/** + * cds_get_recovery_reason() - get self recovery reason + * @reason: cds hang reason + * + * Return: None + */ +void cds_get_recovery_reason(enum qdf_hang_reason *reason); + +/** + * cds_reset_recovery_reason() - reset the reason to unspecified + * + * Return: None + */ +void cds_reset_recovery_reason(void); + +/** + * cds_trigger_recovery() - trigger self recovery + * @reason: recovery reason + * + * Return: none + */ +#define cds_trigger_recovery(reason) \ + __cds_trigger_recovery(reason, __func__, __LINE__) + +void cds_trigger_recovery_psoc(void *psoc, enum qdf_hang_reason reason, + const char *func, const uint32_t line); + +void __cds_trigger_recovery(enum qdf_hang_reason reason, const char *func, + const uint32_t line); + +void cds_set_wakelock_logging(bool value); +bool cds_is_wakelock_enabled(void); +void cds_set_ring_log_level(uint32_t ring_id, uint32_t log_level); +enum wifi_driver_log_level cds_get_ring_log_level(uint32_t ring_id); +void cds_set_multicast_logging(uint8_t value); +uint8_t cds_is_multicast_logging(void); +QDF_STATUS cds_set_log_completion(uint32_t is_fatal, + uint32_t type, + uint32_t sub_type, + bool recovery_needed); +void cds_get_and_reset_log_completion(uint32_t *is_fatal, + uint32_t *type, + uint32_t *sub_type, + bool *recovery_needed); +bool cds_is_log_report_in_progress(void); +bool cds_is_fatal_event_enabled(void); + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +bool cds_is_ptp_rx_opt_enabled(void); +bool cds_is_ptp_tx_opt_enabled(void); +#else +static inline bool cds_is_ptp_rx_opt_enabled(void) +{ + return false; +} + +static inline bool cds_is_ptp_tx_opt_enabled(void) +{ + return false; +} +#endif + +uint32_t cds_get_log_indicator(void); +void cds_set_fatal_event(bool value); +void cds_wlan_flush_host_logs_for_fatal(void); + +void cds_init_log_completion(void); +QDF_STATUS cds_flush_logs(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool dump_mac_trace, + bool recovery_needed); +void cds_logging_set_fw_flush_complete(void); +void cds_svc_fw_shutdown_ind(struct device *dev); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void cds_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t sub_type, uint8_t *peer_mac); +#else +static inline +void cds_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t sub_type, uint8_t *peer_mac) + +{ +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +int cds_get_radio_index(void); +QDF_STATUS cds_set_radio_index(int radio_index); +void cds_init_ini_config(struct cds_config_info *cds_cfg); +void cds_deinit_ini_config(void); +struct cds_config_info *cds_get_ini_config(void); + +bool cds_is_5_mhz_enabled(void); +bool cds_is_10_mhz_enabled(void); +bool cds_is_sub_20_mhz_enabled(void); +bool cds_is_self_recovery_enabled(void); +bool cds_is_fw_down(void); +enum QDF_GLOBAL_MODE cds_get_conparam(void); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +void cds_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); +#else +static inline +void cds_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) +{ +} +#endif + +#ifdef FEATURE_HTC_CREDIT_HISTORY +/** + * cds_print_htc_credit_history() - Helper function to copy HTC credit + * history via htc_print_credit_history() + * + * @count: Number of lines to be copied + * @print: Print callback to print in the buffer + * @print_priv: Print callback private data + * + * Return: none + */ +void cds_print_htc_credit_history(uint32_t count, + qdf_abstract_print * print, + void *print_priv); +#else + +static inline +void cds_print_htc_credit_history(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} +#endif +/** + * cds_is_group_addr() - checks whether addr is multi cast + * @mac_addr: address to be checked for multicast + * + * Check if the input mac addr is multicast addr + * + * Return: true if multicast addr else false + */ +static inline +bool cds_is_group_addr(uint8_t *mac_addr) +{ + if (mac_addr[0] & 0x01) + return true; + else + return false; +} + +#ifdef FEATURE_ALIGN_STATS_FROM_DP +/** + * cds_dp_get_vdev_stats() - get vdev stats from DP + * @vdev_id: vdev id + * @stats: structure of counters which CP is interested in + * + * Return: if get vdev stats from DP success, return true otherwise false + */ +bool cds_dp_get_vdev_stats(uint8_t vdev_id, struct cds_vdev_dp_stats *stats); +#else +static inline bool +cds_dp_get_vdev_stats(uint8_t vdev_id, struct cds_vdev_dp_stats *stats) +{ + return false; +} +#endif + +/** + * cds_smmu_mem_map_setup() - Check SMMU S1 stage enable + * status and setup wlan driver + * @osdev: Parent device instance + * @ipa_present: IPA HW support flag + * + * This API checks if SMMU S1 translation is enabled in + * platform driver or not and sets it accordingly in driver. + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_smmu_mem_map_setup(qdf_device_t osdev, bool ipa_present); + +/** + * cds_smmu_map_unmap() - Map / Unmap DMA buffer to IPA UC + * @map: Map / unmap operation + * @num_buf: Number of buffers in array + * @buf_arr: Buffer array of DMA mem mapping info + * + * This API maps/unmaps WLAN-IPA buffers if SMMU S1 translation + * is enabled. + * + * Return: Status of map operation + */ +int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr); + +/** + * cds_is_driver_transitioning() - Is driver transitioning + * + * Return: true if driver is loading/unloading/recovering and false otherwise. + */ +static inline bool cds_is_driver_transitioning(void) +{ + enum cds_driver_state state = cds_get_driver_state(); + + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_LOADING) || + __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_UNLOADING) || + __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_RECOVERING) || + __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_BAD); +} + +#endif /* if !defined __CDS_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_config.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_config.h new file mode 100644 index 0000000000..c39fff37d8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_config.h @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: cds_config.h + * + * Defines the configuration Information for various modules. Default values + * are read from the INI file and saved into cds_config_info which are passed + * to various modules for the initialization. + */ + +#if !defined(__CDS_CONFIG_H) +#define __CDS_CONFIG_H + +#include "osdep.h" +#include "cdp_txrx_mob_def.h" +#include "wlan_cmn.h" +#include "wlan_cmn_ieee80211.h" +#include "wlan_pmo_common_public_struct.h" +#include "qca_vendor.h" +#include "wmi_unified_param.h" + +/** + * enum cfg_sub_20_channel_width: ini values for su 20 MHz channel width + * @WLAN_SUB_20_CH_WIDTH_NONE: No sub-20 MHz channel width + * @WLAN_SUB_20_CH_WIDTH_5: Use 5 MHz channel width + * @WLAN_SUB_20_CH_WIDTH_10: Use 10 MHz channel width + */ +enum cfg_sub_20_channel_width { + WLAN_SUB_20_CH_WIDTH_NONE = 0, + WLAN_SUB_20_CH_WIDTH_5 = 1, + WLAN_SUB_20_CH_WIDTH_10 = 2, +}; + +#ifdef FEATURE_SET +/** + * struct wlan_cds_feature_set - CDS feature set struct + * @wifi_standard: Supported wifi standard + * @sap_5g_supported: 5GHz SAP supported or not + * @sap_6g_supported: 6GHz SAP supported or no + * @band_capability: Supported band capability bitmap; + */ +struct wlan_cds_feature_set { + WMI_HOST_WIFI_STANDARD wifi_standard; + bool sap_5g_supported; + bool sap_6g_supported; + uint32_t band_capability; +}; +#endif + +/** + * struct cds_config_info - Place Holder for cds configuration + * @max_station: Max station supported + * @max_bssid: Max Bssid Supported + * @sta_maxlimod_dtim: station max listen interval + * @sta_maxlimod_dtim_ms: station max listen interval ms + * @driver_type: Enumeration of Driver Type whether FTM or Mission mode + * currently rest of bits are not used + * Indicates whether support is enabled or not + * @ap_disable_intrabss_fwd: pass intra-bss-fwd info to txrx module + * @ap_maxoffload_peers: max offload peer + * @ap_maxoffload_reorderbuffs: max offload reorder buffs + * @is_ra_ratelimit_enabled: Indicate RA rate limit enabled or not + * @reorder_offload: is RX re-ordering offloaded to the fw + * @dfs_pri_multiplier: dfs radar pri multiplier + * @uc_offload_enabled: IPA Micro controller data path offload enable flag + * @enable_rxthread: Rx processing in thread from TXRX + * @tx_flow_stop_queue_th: Threshold to stop queue in percentage + * @tx_flow_start_queue_offset: Start queue offset in percentage + * @enable_dp_rx_threads: enable dp rx threads + * @is_lpass_enabled: Indicate whether LPASS is enabled or not + * @tx_chain_mask_cck: Tx chain mask enabled or not + * @sub_20_channel_width: Sub 20 MHz ch width, ini intersected with fw cap + * @max_msdus_per_rxinorderind: + * @self_recovery_enabled: + * @fw_timeout_crash: Indicate whether crash host when fw timesout or not + * @ac_specs: + * @ito_repeat_count: Indicates ito repeated count + * @force_target_assert_enabled: Indicate whether target assert enabled or not + * @bandcapability: Configured band by user + * @rps_enabled: RPS enabled in SAP mode + * Structure for holding cds ini parameters. + * @num_vdevs: Configured max number of VDEVs can be supported in the stack. + * @enable_tx_compl_tsf64: + * @cds_feature_set: CDS feature set structure. + * @get_wifi_features: Get wifi features from fw + * @exclude_selftx_from_cca_busy: Exclude selx tx time from cca busy time + */ + +struct cds_config_info { + uint16_t max_station; + uint16_t max_bssid; + uint8_t sta_maxlimod_dtim; + uint16_t sta_maxlimod_dtim_ms; + enum qdf_driver_type driver_type; + uint8_t ap_maxoffload_peers; + uint8_t ap_maxoffload_reorderbuffs; + uint8_t reorder_offload; + uint8_t uc_offload_enabled; + bool enable_rxthread; +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) + uint32_t tx_flow_stop_queue_th; + uint32_t tx_flow_start_queue_offset; +#endif + uint8_t enable_dp_rx_threads; +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif + enum cfg_sub_20_channel_width sub_20_channel_width; + uint8_t max_msdus_per_rxinorderind; + bool self_recovery_enabled; + bool fw_timeout_crash; + struct ol_tx_sched_wrr_ac_specs_t ac_specs[QCA_WLAN_AC_ALL]; + uint8_t ito_repeat_count; + bool force_target_assert_enabled; + uint8_t bandcapability; + bool rps_enabled; + uint32_t num_vdevs; + bool enable_tx_compl_tsf64; +#ifdef FEATURE_SET + struct wlan_cds_feature_set cds_feature_set; + bool get_wifi_features; +#endif + bool exclude_selftx_from_cca_busy; +}; +#endif /* !defined( __CDS_CONFIG_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h new file mode 100644 index 0000000000..84d4cc4a77 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_ieee80211_common.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2011,2014-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef EXTERNAL_USE_ONLY +#include "osdep.h" +#endif /* EXTERNAL_USE_ONLY */ +#include "cds_ieee80211_common_i.h" +#include "cdp_txrx_mob_def.h" + +#ifndef CDS_COMMON_IEEE80211_H_ +#define CDS_COMMON_IEEE80211_H_ + +/* + * generic definitions for IEEE 802.11 frames + */ +struct ieee80211_frame { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + union { + struct { + uint8_t i_addr1[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr2[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr3[QDF_MAC_ADDR_SIZE]; + }; + uint8_t i_addr_all[3 * QDF_MAC_ADDR_SIZE]; + }; + uint8_t i_seq[2]; + /* possibly followed by addr4[QDF_MAC_ADDR_SIZE]; */ + /* see below */ +} __packed; + +struct ieee80211_qosframe { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr2[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr3[QDF_MAC_ADDR_SIZE]; + uint8_t i_seq[2]; + uint8_t i_qos[2]; + /* possibly followed by addr4[QDF_MAC_ADDR_SIZE]; */ + /* see below */ +} __packed; + +struct ieee80211_frame_bar { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_ra[QDF_MAC_ADDR_SIZE]; + uint8_t i_ta[QDF_MAC_ADDR_SIZE]; + uint16_t i_ctl; + uint16_t i_seq; +/* FCS */ +} __packed; + +struct ieee80211_qoscntl { + uint8_t i_qos[2]; +}; + +struct ieee80211_frame_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr2[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr3[QDF_MAC_ADDR_SIZE]; + uint8_t i_seq[2]; + uint8_t i_addr4[QDF_MAC_ADDR_SIZE]; +} __packed; + +struct ieee80211_qosframe_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr2[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr3[QDF_MAC_ADDR_SIZE]; + uint8_t i_seq[2]; + uint8_t i_addr4[QDF_MAC_ADDR_SIZE]; + uint8_t i_qos[2]; +} __packed; + +/* HTC frame for TxBF*/ +/* for TxBF RC */ +struct ieee80211_frame_min_one { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[QDF_MAC_ADDR_SIZE]; +} __packed; /* For TxBF RC */ + +struct ieee80211_qosframe_htc_addr4 { + uint8_t i_fc[2]; + uint8_t i_dur[2]; + uint8_t i_addr1[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr2[QDF_MAC_ADDR_SIZE]; + uint8_t i_addr3[QDF_MAC_ADDR_SIZE]; + uint8_t i_seq[2]; + uint8_t i_addr4[QDF_MAC_ADDR_SIZE]; + uint8_t i_qos[2]; + uint8_t i_htc[4]; +} __packed; + +struct ieee80211_htc { + uint8_t i_htc[4]; +}; + +#define IEEE80211_FC0_VERSION_0 0x00 +#define IEEE80211_FC0_TYPE_MASK 0x0c +#define IEEE80211_FC0_TYPE_MGT 0x00 +#define IEEE80211_FC0_TYPE_CTL 0x04 +#define IEEE80211_FC0_TYPE_DATA 0x08 + +#define IEEE80211_FC0_SUBTYPE_MASK 0xf0 +#define IEEE80211_FC0_SUBTYPE_SHIFT 4 + +#define IEEE80211_FC1_DIR_MASK 0x03 +#define IEEE80211_FC1_DIR_NODS 0x00 /* STA->STA */ +#define IEEE80211_FC1_DIR_TODS 0x01 /* STA->AP */ +#define IEEE80211_FC1_DIR_FROMDS 0x02 /* AP ->STA */ +#define IEEE80211_FC1_DIR_DSTODS 0x03 /* AP ->AP */ + +#define IEEE80211_FC1_MORE_FRAG 0x04 +#define IEEE80211_FC1_RETRY 0x08 +#define IEEE80211_FC1_PWR_MGT 0x10 +#define IEEE80211_FC1_MORE_DATA 0x20 +#define IEEE80211_FC1_ORDER 0x80 + +#define IEEE80211_SEQ_FRAG_MASK 0x000f +#define IEEE80211_SEQ_FRAG_SHIFT 0 +#define IEEE80211_SEQ_SEQ_MASK 0xfff0 +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 + +#define IEEE80211_QOS_AMSDU 0x80 +#define IEEE80211_QOS_ACKPOLICY_S 5 +#define IEEE80211_QOS_TID 0x0f + +#define IEEE80211_IS_DATA(_frame) (((_frame)->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) + +/* does frame have QoS sequence control data */ +#define IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | QDF_IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | QDF_IEEE80211_FC0_SUBTYPE_QOS)) + +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +struct ieee80211_channelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_CHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +struct ieee80211_extendedchannelswitch_ie { + uint8_t ie; /* IEEE80211_ELEMID_EXTCHANSWITCHANN */ + uint8_t len; + uint8_t switchmode; + uint8_t newClass; + uint8_t newchannel; + uint8_t tbttcount; +} __packed; + +/* + * Reason codes + * + * Unlisted codes are reserved + */ +enum { + IEEE80211_REASON_UNSPECIFIED = 1, + IEEE80211_REASON_AUTH_EXPIRE = 2, + IEEE80211_REASON_AUTH_LEAVE = 3, + IEEE80211_REASON_ASSOC_EXPIRE = 4, + IEEE80211_REASON_ASSOC_TOOMANY = 5, + IEEE80211_REASON_NOT_AUTHED = 6, + IEEE80211_REASON_NOT_ASSOCED = 7, + IEEE80211_REASON_ASSOC_LEAVE = 8, + IEEE80211_REASON_ASSOC_NOT_AUTHED = 9, + + IEEE80211_REASON_RSN_REQUIRED = 11, + IEEE80211_REASON_RSN_INCONSISTENT = 12, + IEEE80211_REASON_IE_INVALID = 13, + IEEE80211_REASON_MIC_FAILURE = 14, + + IEEE80211_REASON_QOS = 32, + IEEE80211_REASON_QOS_BANDWITDH = 33, + IEEE80211_REASON_QOS_CH_CONDITIONS = 34, + IEEE80211_REASON_QOS_TXOP = 35, + IEEE80211_REASON_QOS_LEAVE = 36, + IEEE80211_REASON_QOS_DECLINED = 37, + IEEE80211_REASON_QOS_SETUP_REQUIRED = 38, + IEEE80211_REASON_QOS_TIMEOUT = 39, + IEEE80211_REASON_QOS_CIPHER = 45, + + IEEE80211_STATUS_SUCCESS = 0, + IEEE80211_STATUS_UNSPECIFIED = 1, + IEEE80211_STATUS_CAPINFO = 10, + IEEE80211_STATUS_NOT_ASSOCED = 11, + IEEE80211_STATUS_OTHER = 12, + IEEE80211_STATUS_ALG = 13, + IEEE80211_STATUS_SEQUENCE = 14, + IEEE80211_STATUS_CHALLENGE = 15, + IEEE80211_STATUS_TIMEOUT = 16, + IEEE80211_STATUS_TOOMANY = 17, + IEEE80211_STATUS_BASIC_RATE = 18, + IEEE80211_STATUS_SP_REQUIRED = 19, + IEEE80211_STATUS_PBCC_REQUIRED = 20, + IEEE80211_STATUS_CA_REQUIRED = 21, + IEEE80211_STATUS_TOO_MANY_STATIONS = 22, + IEEE80211_STATUS_RATES = 23, + IEEE80211_STATUS_SHORTSLOT_REQUIRED = 25, + IEEE80211_STATUS_DSSSOFDM_REQUIRED = 26, + IEEE80211_STATUS_NO_HT = 27, + IEEE80211_STATUS_REJECT_TEMP = 30, + IEEE80211_STATUS_MFP_VIOLATION = 31, + IEEE80211_STATUS_REFUSED = 37, + IEEE80211_STATUS_INVALID_PARAM = 38, + + IEEE80211_STATUS_DLS_NOT_ALLOWED = 48, +}; + +#define IEEE80211_WEP_IVLEN 3 /* 24bit */ +#define IEEE80211_WEP_KIDLEN 1 /* 1 octet */ +#define IEEE80211_WEP_CRCLEN 4 /* CRC-32 */ + +/* + * 802.11i defines an extended IV for use with non-WEP ciphers. + * When the EXTIV bit is set in the key id byte an additional + * 4 bytes immediately follow the IV for TKIP. For CCMP the + * EXTIV bit is likewise set but the 8 bytes represent the + * CCMP header rather than IV+extended-IV. + */ +#define IEEE80211_WEP_EXTIV 0x20 +#define IEEE80211_WEP_EXTIVLEN 4 /* extended IV length */ +#define IEEE80211_WEP_MICLEN 8 /* trailing MIC */ + +/* + * 802.11w defines a MMIE chunk to be attached at the end of + * any outgoing broadcast or multicast robust management frame. + * MMIE field is total 18 bytes in size. Following the diagram of MMIE + * + * <------------ 18 Bytes MMIE -----------------------> + * +--------+---------+---------+-----------+---------+ + * |Element | Length | Key id | IPN | MIC | + * | id | | | | | + * +--------+---------+---------+-----------+---------+ + * bytes 1 1 2 6 8 + * + */ +#define IEEE80211_MMIE_LEN 18 +#define IEEE80211_MMIE_IPNLEN 6 +#define IEEE80211_MMIE_MICLEN 8 + +/* + * 802.11ac Wide Bandwidth Channel Switch Element + */ + +struct ieee80211_ie_wide_bw_switch { + uint8_t elem_id; + uint8_t elem_len; + uint8_t new_ch_width; /* New channel width */ + uint8_t new_ch_freq_seg1; /* Channel Center frequency 1 */ + uint8_t new_ch_freq_seg2; /* Channel Center frequency 2 */ +} __packed; + +#endif /* CDS_COMMON_IEEE80211_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_packet.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_packet.h new file mode 100644 index 0000000000..d34427a411 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_packet.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014-2016, 2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__CDS_PKT_H) +#define __CDS_PKT_H + +/** + * DOC: cds_packet.h + * Connectivity driver services (CDS) network Packet APIs + * Network Protocol packet/buffer support interfaces + */ + +#include +#include + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +struct cds_pkt_t; +typedef struct cds_pkt_t cds_pkt_t; + +#include "qdf_nbuf.h" + +/** + * cds_pkt_return_packet() - Free the cds Packet + * @packet: cds Packet + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet); + +/** + * cds_pkt_get_packet_length() - Get packet length for a cds Packet + * @pPacket: the cds Packet to get the packet length from + * @pPacketSize: location to return the total size of the data + * contained in the cds Packet. + * + * Return: QDF_STATUS_SUCCESS if the length was returned, otherwise an + * appropriate QDF_STATUS_E_* status code. + */ +QDF_STATUS cds_pkt_get_packet_length(cds_pkt_t *pPacket, + uint16_t *pPacketSize); + +/* + * TODO: Remove later + * All the below definitions are not + * required for Host Driver 2.0 + * once corresponding references are removed + * from HDD and other layers + * below code will be removed + */ + +/** + * cds_packet_alloc() - Allocate a network buffer for TX + * @size: size of the packet + * @data: packet payload + * @ppPacket: pointer to return allocated packet + * + * Allocates a packet of the indicated @size, populates it with the + * @data payload, and returns the pointer via @ppPacket. Caller is + * responsible for calling cds_packet_free() after the packet has been + * sent to reclaim the packet. + * + * Return: QDF_STATUS_SUCCESS if a packet is allocated, otherwise a + * appropriate QDF_STATUS_E_* status code. + */ +#ifdef MEMORY_DEBUG +#define cds_packet_alloc(size, data, ppPacket) \ + cds_packet_alloc_debug(size, data, ppPacket, __func__, __LINE__) + +QDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + const char *func_name, uint32_t line_num); +#else +QDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket); +#endif + +/** + * cds_packet_free() - Free input network buffer + * @pPacket: network buffer + */ +void cds_packet_free(void *pPacket); + +#endif /* !defined( __CDS_PKT_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_reg_service.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_reg_service.h new file mode 100644 index 0000000000..227115bbc5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_reg_service.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2014-2017, 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CDS_REG_SERVICE_H +#define __CDS_REG_SERVICE_H + +/**========================================================================= + + \file cds_reg_service.h + + \brief Connectivity driver services (CDS): Non-Volatile storage API + + ========================================================================*/ + +#include "qdf_status.h" +#include +#include + +#define CDS_COUNTRY_CODE_LEN 2 +#define CDS_MAC_ADDRESS_LEN 6 +#define HT40PLUS_2G_FCC_CH_END 7 +#define HT40PLUS_2G_EURJAP_CH_END 9 +#define HT40MINUS_2G_CH_START 5 +#define HT40MINUS_2G_CH_END 13 + +/** + * cds_get_vendor_reg_flags() - This API returns vendor specific regulatory + * channel flags + * @pdev: pdev pointer + * @freq: channel frequency + * @bandwidth: channel BW + * @is_ht_enabled: HT enabled/disabled flag + * @is_vht_enabled: VHT enabled/disabled flag + * @sub_20_channel_width: Sub 20 channel bandwidth + * Return: channel flags + */ +uint32_t cds_get_vendor_reg_flags(struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq, + uint16_t bandwidth, + bool is_ht_enabled, bool is_vht_enabled, + uint8_t sub_20_channel_width); +#endif /* __CDS_REG_SERVICE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_regdomain.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_regdomain.h new file mode 100644 index 0000000000..e2845d0613 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_regdomain.h @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2011, 2014-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Notifications and licenses are retained for attribution purposes only. + */ +/* + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2010, Atheros Communications Inc. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + * + * This module contains the regulatory domain private structure definitions . + * + */ + +#ifndef __CDS_REGDOMAIN_H +#define __CDS_REGDOMAIN_H + +#include +#include +#include "reg_db.h" + +#define MIN_TX_PWR_CAP 8 +#define MAX_TX_PWR_CAP 24 + +#define CTRY_DEFAULT 0 +#define CTRY_FLAG 0x8000 +#define WORLD_ROAMING_FLAG 0x4000 +#define WORLD_ROAMING_MASK 0x00F0 +#define WORLD_ROAMING_PREFIX 0x0060 +/** + * struct reg_dmn_pair: regulatory domain pair + * @reg_dmn_pair: reg domain pair + * @reg_dmn_5ghz: 5G reg domain + * @reg_dmn_2ghz: 2G reg domain + * @single_cc: country with this reg domain + */ +struct reg_dmn_pair { + uint16_t reg_dmn_pair; + uint16_t reg_dmn_5ghz; + uint16_t reg_dmn_2ghz; + uint16_t single_cc; +}; + +/** + * struct country_code_to_reg_dmn: country code to reg domain mapping + * @country_code: country code + * @reg_dmn_pair: regulatory domain pair + * @alpha2: country alpha2 + * @name: country name + */ +struct country_code_to_reg_dmn { + uint16_t country_code; + uint16_t reg_dmn_pair; + const char *alpha2; + const char *name; +}; + +/** + * struct reg_dmn: regulatory domain structure + * @reg_dmn: regulatory domain + * @conformance_test_limit: CTL limit + */ +struct reg_dmn { + uint16_t reg_dmn; + uint8_t conformance_test_limit; +}; + +/** + * struct reg_dmn_tables: reg domain table + * @reg_dmn_pairs: list of reg domain pairs + * @all_countries: list of countries + * @reg_dmns: list of reg domains + * @reg_dmn_pairs_cnt: count of reg domain pairs + * @all_countries_cnt: count of countries + * @reg_dmns_cnt: count of reg domains + */ +struct reg_dmn_tables { + const struct reg_dmn_pair *reg_dmn_pairs; + const struct country_code_to_reg_dmn *all_countries; + const struct reg_dmn *reg_dmns; + uint16_t reg_dmn_pairs_cnt; + uint16_t all_countries_cnt; + uint16_t reg_dmns_cnt; +}; + +int32_t cds_fill_some_regulatory_info(struct regulatory *reg); +int32_t cds_get_country_from_alpha2(uint8_t *alpha2); +void cds_fill_and_send_ctl_to_fw(struct regulatory *reg); +/** + * cds_is_etsi_europe_country - check ETSI Europe country or not + * @country: country string with two Characters + * + * Return: true if country in ETSI Europe country list + */ +bool cds_is_etsi_europe_country(uint8_t *country); +#endif /* __CDS_REGDOMAIN_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_sched.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_sched.h new file mode 100644 index 0000000000..fa7aaf7057 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_sched.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CDS_SCHED_H +#define __CDS_SCHED_H + +/** + * DOC: cds_sched.h + * Connectivity driver services scheduler + */ + +#include +#include +#include +#if defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include +#include "qdf_lock.h" +#include "qdf_mc_timer.h" +#include "cds_config.h" +#include "qdf_cpuhp.h" +#include "cdp_txrx_cmn_struct.h" + +#define MC_SUSPEND_EVENT 0x002 +#define RX_POST_EVENT 0x001 +#define RX_SUSPEND_EVENT 0x002 +#define RX_VDEV_DEL_EVENT 0x004 +#define RX_SHUTDOWN_EVENT 0x010 + +#define RX_REFILL_POST_EVENT 0x001 +#define RX_REFILL_SUSPEND_EVENT 0x002 +#define RX_REFILL_SHUTDOWN_EVENT 0x004 + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD +/* +** Maximum number of cds messages to be allocated for +** OL Rx thread. +*/ +#define CDS_MAX_OL_RX_PKT 4000 + +#define CDS_ACTIVE_STAID_CLEANUP_DELAY 10 +#define CDS_ACTIVE_STAID_CLEANUP_TIMEOUT 200 +#endif + +typedef void (*cds_ol_rx_thread_cb)(void *context, + qdf_nbuf_t rxpkt, + uint16_t staid); + +/* +** CDS message wrapper for data rx from TXRX +*/ +struct cds_ol_rx_pkt { + struct list_head list; + void *context; + + /* Rx skb */ + qdf_nbuf_t Rxpkt; + + /* Station id to which this packet is destined */ + uint16_t staId; + + /* Call back to further send this packet to txrx layer */ + cds_ol_rx_thread_cb callback; + +}; + +/* +** CDS Scheduler context +** The scheduler context contains the following: +** ** the messages queues +** ** the handle to the thread +** ** pointer to the events that gracefully shutdown the MC and Tx threads +** +*/ +typedef struct _cds_sched_context { +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + spinlock_t ol_rx_thread_lock; + + /* OL Rx thread handle */ + struct task_struct *ol_rx_thread; + + /* Handle of Event for Rx thread to signal startup */ + struct completion ol_rx_start_event; + + /* Completion object to suspend OL rx thread */ + struct completion ol_suspend_rx_event; + + /* Completion object to resume OL rx thread */ + struct completion ol_resume_rx_event; + + /* Completion object for OL Rxthread shutdown */ + struct completion ol_rx_shutdown; + + /* Waitq for OL Rx thread */ + wait_queue_head_t ol_rx_wait_queue; + + unsigned long ol_rx_event_flag; + + /* Rx buffer queue */ + struct list_head ol_rx_thread_queue; + + /* Spinlock to synchronize between tasklet and thread */ + spinlock_t ol_rx_queue_lock; + + /* Lock to synchronize free buffer queue access */ + spinlock_t cds_ol_rx_pkt_freeq_lock; + + /* Free message queue for OL Rx processing */ + struct list_head cds_ol_rx_pkt_freeq; + + /* The CPU hotplug event registration handle, used to unregister */ + struct qdf_cpuhp_handler *cpuhp_event_handle; + + /* affinity lock */ + struct mutex affinity_lock; + + /* Saved rx thread CPU affinity */ + struct cpumask rx_thread_cpu_mask; + + /* CPU affinity bitmask */ + uint8_t conf_rx_thread_cpu_mask; + + /* high throughput required */ + bool high_throughput_required; + + /* affinity required during uplink traffic*/ + bool rx_affinity_required; + uint8_t conf_rx_thread_ul_affinity; + + /* sta id packets under processing in thread context*/ + uint16_t active_staid; +#endif +} cds_sched_context, *p_cds_sched_context; + +/** + * struct cds_log_complete - Log completion internal structure + * @is_fatal: Type is fatal or not + * @indicator: Source of bug report + * @reason_code: Reason code for bug report + * @is_report_in_progress: If bug report is in progress + * @recovery_needed: if recovery is needed after report completion + * + * This structure internally stores the log related params + */ +struct cds_log_complete { + uint32_t is_fatal; + uint32_t indicator; + uint32_t reason_code; + bool is_report_in_progress; + bool recovery_needed; +}; + +struct cds_context { + /* Scheduler Context */ + cds_sched_context qdf_sched; + + /* HDD Module Context */ + void *hdd_context; + + /* MAC Module Context */ + void *mac_context; + + uint32_t driver_state; + + /* WMA Context */ + void *wma_context; + + void *hif_context; + + void *htc_ctx; + + void *g_ol_context; + /* + * qdf_ctx will be used by qdf + * while allocating dma memory + * to access dev information. + */ + qdf_device_t qdf_ctx; + + void *dp_soc; + + /* Configuration handle used to get system configuration */ + struct cdp_cfg *cfg_ctx; + + /* radio index per driver */ + int radio_index; + + bool is_wakelock_log_enabled; + uint32_t wakelock_log_level; + uint32_t connectivity_log_level; + uint32_t packet_stats_log_level; + uint32_t driver_debug_log_level; + uint32_t fw_debug_log_level; + struct cds_log_complete log_complete; + qdf_spinlock_t bug_report_lock; + + bool enable_fatal_event; + struct cds_config_info *cds_cfg; + + struct ol_tx_sched_wrr_ac_specs_t ac_specs[QCA_WLAN_AC_ALL]; + qdf_work_t cds_recovery_work; + qdf_workqueue_t *cds_recovery_wq; + enum qdf_hang_reason recovery_reason; + + /* To protect bit(CDS_DRIVER_STATE_SYS_REBOOTING) of driver_state */ + qdf_mutex_t sys_reboot_lock; +}; + +/*--------------------------------------------------------------------------- + Function declarations and documentation + ---------------------------------------------------------------------------*/ +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + +/** + * cds_sched_handle_cpu_hot_plug() - cpu hotplug event handler + * + * cpu hotplug indication handler + * will find online cores and will assign proper core based on perf requirement + * + * Return: 0 success + * 1 fail + */ +int cds_sched_handle_cpu_hot_plug(void); + +/** + * cds_sched_handle_throughput_req() - cpu throughput requirement handler + * @high_tput_required: high throughput is required or not + * + * high or low throughput indication handler + * will find online cores and will assign proper core based on perf requirement + * + * Return: 0 success + * 1 fail + */ +int cds_sched_handle_throughput_req(bool high_tput_required); + +/** + * cds_sched_handle_rx_thread_affinity_req() - rx thread affinity req handler + * @high_throughput: high throughput is required or not + * + * rx thread affinity handler will find online cores and + * will assign proper core based on perf requirement + * + * Return: None + */ +void cds_sched_handle_rx_thread_affinity_req(bool high_throughput); + +/** + * cds_set_rx_thread_ul_cpu_mask() - Rx_thread affinity for UL from INI + * @cpu_affinity_mask: CPU affinity bitmap + * + * Return:None + */ +void cds_set_rx_thread_ul_cpu_mask(uint8_t cpu_affinity_mask); + +/** + * cds_set_rx_thread_cpu_mask() - Rx_thread affinity from INI + * @cpu_affinity_mask: CPU affinity bitmap + * + * Return:None + */ +void cds_set_rx_thread_cpu_mask(uint8_t cpu_affinity_mask); + +/** + * cds_drop_rxpkt_by_staid() - api to drop pending rx packets for a sta + * @pSchedContext: Pointer to the global CDS Sched Context + * @staId: Station Id + * + * This api drops queued packets for a station, to drop all the pending + * packets the caller has to send WLAN_MAX_STA_COUNT as staId. + * + * Return: none + */ +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId); + +/** + * cds_indicate_rxpkt() - indicate rx data packet + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS data message buffer + * + * This api enqueues the rx packet into ol_rx_thread_queue and notifies + * cds_ol_rx_thread() + * + * Return: none + */ +void cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); + +/** + * cds_close_rx_thread() - close the Rx thread + * + * This api closes the Rx thread: + * + * Return: qdf status + */ +QDF_STATUS cds_close_rx_thread(void); + +/** + * cds_alloc_ol_rx_pkt() - API to return next available cds message + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api returns next available cds message buffer used for rx data + * processing + * + * Return: Pointer to cds message buffer + */ +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext); + +/** + * cds_free_ol_rx_pkt() - api to release cds message to the freeq + * @pSchedContext: Pointer to the global CDS Sched Context + * @pkt: CDS message buffer to be returned to free queue. + * + * This api returns the cds message used for Rx data to the free queue + * + * Return: none + */ +void cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt); + +/** + * cds_free_ol_rx_pkt_freeq() - free cds buffer free queue + * @pSchedContext: pointer to the global CDS Sched Context + * + * This API does mem free of the buffers available in free cds buffer + * queue which is used for Data rx processing. + * + * Return: none + */ +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); + +/** + * cds_get_rx_thread_pending() - get rx thread status + * @soc: ol_txrx_soc_handle object + * + * Return: 1 if rx thread is not empty. + * 0 if rx thread is empty. + */ +int cds_get_rx_thread_pending(ol_txrx_soc_handle soc); +#else +static inline void cds_sched_handle_rx_thread_affinity_req( + bool high_throughput) {} + +static inline void cds_set_rx_thread_ul_cpu_mask(uint8_t cpu_affinity_mask) {} + +static inline void cds_set_rx_thread_cpu_mask(uint8_t cpu_affinity_mask) {} + +static inline +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId) +{ +} + +static inline +void cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ +} + +static inline +QDF_STATUS cds_close_rx_thread(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext) +{ + return NULL; +} + +static inline +void cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ +} + +static inline +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ +} + +static inline int cds_sched_handle_throughput_req( + bool high_tput_required) +{ + return 0; +} + +static inline int cds_get_rx_thread_pending(ol_txrx_soc_handle soc) +{ + return 0; +} +#endif + +/** + * cds_sched_open() - initialize the CDS Scheduler + * @p_cds_context: Pointer to the global CDS Context + * @pSchedContext: Pointer to a previously allocated buffer big + * enough to hold a scheduler context. + * @SchedCtxSize: CDS scheduler context size + * + * This function initializes the CDS Scheduler + * Upon successful initialization: + * - All the message queues are initialized + * - The Main Controller thread is created and ready to receive and + * dispatch messages. + * + * + * Return: QDF status + */ +QDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedContext, + uint32_t SchedCtxSize); + +/** + * cds_sched_close() - close the cds scheduler + * + * This api closes the CDS Scheduler upon successful closing: + * - All the message queues are flushed + * - The Main Controller thread is closed + * - The Tx thread is closed + * + * + * Return: qdf status + */ +QDF_STATUS cds_sched_close(void); + +/** + * get_cds_sched_ctxt() - get cds scheduler context + * + * Return: cds scheduler context + */ +p_cds_sched_context get_cds_sched_ctxt(void); + +void qdf_timer_module_init(void); +void qdf_timer_module_deinit(void); + +/** + * cds_ssr_protect_init() - initialize ssr protection debug functionality + * + * Return: + * void + */ +void cds_ssr_protect_init(void); + +/** + * cds_get_gfp_flags(): get GFP flags + * + * Based on the scheduled context, return GFP flags + * Return: gfp flags + */ +int cds_get_gfp_flags(void); + +/** + * cds_shutdown_notifier_register() - Register for shutdown notification + * @cb: Call back to be called + * @priv: Private pointer to be passed back to call back + * + * During driver remove or shutdown (recovery), external threads might be stuck + * waiting on some event from firmware at lower layers. Remove or shutdown can't + * proceed till the thread completes to avoid any race condition. Call backs can + * be registered here to get early notification of remove or shutdown so that + * waiting thread can be unblocked and hence remove or shutdown can proceed + * further as waiting there may not make sense when FW may already have been + * down. + * + * Return: QDF status + */ +QDF_STATUS cds_shutdown_notifier_register(void (*cb)(void *priv), void *priv); + +/** + * cds_shutdown_notifier_purge() - Purge all the notifiers + * + * Shutdown notifiers are added to provide the early notification of remove or + * shutdown being initiated. Adding this API to purge all the registered call + * backs as they are not useful any more while all the lower layers are being + * shutdown. + * + * Return: None + */ +void cds_shutdown_notifier_purge(void); + +/** + * cds_shutdown_notifier_call() - Call shutdown notifier call back + * + * Call registered shutdown notifier call back to indicate about remove or + * shutdown. + */ +void cds_shutdown_notifier_call(void); + +/** + * cds_resume_rx_thread() - resume rx thread by completing its resume event + * + * Resume RX thread by completing RX thread resume event + * + * Return: None + */ +void cds_resume_rx_thread(void); + +#endif /* #ifndef __CDS_SCHED_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_utils.h new file mode 100644 index 0000000000..35faf967eb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/inc/cds_utils.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CDS_UTILS_H +#define __CDS_UTILS_H + +/** + * DOC: cds_utils.h + * Connectivity driver services (CDS) utility APIs + * Various utility functions + */ + +#include +#include +#include +#include +#include "ani_global.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define CDS_24_GHZ_BASE_FREQ (2407) +#define CDS_5_GHZ_BASE_FREQ (5000) +#define CDS_24_GHZ_CHANNEL_1 (1) +#define CDS_24_GHZ_CHANNEL_14 (14) +#define CDS_24_GHZ_CHANNEL_15 (15) +#define CDS_24_GHZ_CHANNEL_27 (27) +#define CDS_5_GHZ_CHANNEL_165 (165) +#define CDS_5_GHZ_CHANNEL_170 (170) +#define CDS_CHAN_SPACING_5MHZ (5) +#define CDS_CHAN_SPACING_20MHZ (20) +#define CDS_CHAN_14_FREQ (2484) +#define CDS_CHAN_15_FREQ (2512) +#define CDS_CHAN_170_FREQ (5852) + +#define INVALID_SCAN_ID 0xFFFFFFFF + +#define CDS_DBS_SCAN_CLIENTS_MAX (7) +#define CDS_DBS_SCAN_PARAM_PER_CLIENT (3) + +#define cds_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_QDF, params) +#define cds_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, params) +#define cds_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_QDF, params) +#define cds_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_QDF, params) +#define cds_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_QDF, params) + +#define cds_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_QDF, params) +#define cds_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_QDF, params) +#define cds_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_QDF, params) +#define cds_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_QDF, params) +#define cds_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_QDF, params) + +#define cds_enter() QDF_TRACE_ENTER(QDF_MODULE_ID_QDF, "enter") +#define cds_exit() QDF_TRACE_EXIT(QDF_MODULE_ID_QDF, "exit") + +/** + * enum cds_band_type - Band type - 2g, 5g or all + * @CDS_BAND_ALL: Both 2G and 5G are valid. + * @CDS_BAND_2GHZ: only 2G is valid. + * @CDS_BAND_5GHZ: only 5G is valid. + */ +enum cds_band_type { + CDS_BAND_ALL = 0, + CDS_BAND_2GHZ = 1, + CDS_BAND_5GHZ = 2 +}; + +/*------------------------------------------------------------------------- + Function declarations and documentation + ------------------------------------------------------------------------*/ + +uint32_t cds_chan_to_freq(uint8_t chan); +uint8_t cds_freq_to_chan(uint32_t freq); +enum cds_band_type cds_chan_to_band(uint32_t chan); + +uint8_t cds_get_mmie_size(void); + +/** + * cds_get_gmac_mmie_size() - Gives length of GMAC MMIE size + * + * Return: Size of MMIE for GMAC + */ +uint8_t cds_get_gmac_mmie_size(void); + +static inline void cds_host_diag_log_work(qdf_wake_lock_t *lock, uint32_t msec, + uint32_t reason) { + if (((cds_get_ring_log_level(RING_ID_WAKELOCK) >= WLAN_LOG_LEVEL_ACTIVE) + && (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX == reason)) || + (WIFI_POWER_EVENT_WAKELOCK_HOLD_RX != reason)) { + host_diag_log_wlock(reason, qdf_wake_lock_name(lock), + msec, WIFI_POWER_EVENT_WAKELOCK_TAKEN); + } +} + +/** + * cds_copy_hlp_info() - Copy HLP info + * @input_dst_mac: input HLP destination MAC address + * @input_src_mac: input HLP source MAC address + * @input_hlp_data_len: input HLP data length + * @input_hlp_data: Pointer to input HLP data + * @output_dst_mac: output HLP destination MAC address + * @output_src_mac: output HLP source MAC address + * @output_hlp_data_len: Pointer to output HLP data length + * @output_hlp_data: output Pointer to HLP data + * + * Util API to copy HLP info from input to output + * + * Return: None + */ +void cds_copy_hlp_info(struct qdf_mac_addr *input_dst_mac, + struct qdf_mac_addr *input_src_mac, + uint16_t input_hlp_data_len, + uint8_t *input_hlp_data, + struct qdf_mac_addr *output_dst_mac, + struct qdf_mac_addr *output_src_mac, + uint16_t *output_hlp_data_len, + uint8_t *output_hlp_data); +#endif /* #ifndef __CDS_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_api.c b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_api.c new file mode 100644 index 0000000000..3248ac6d7b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_api.c @@ -0,0 +1,3051 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: cds_api.c + * + * Connectivity driver services APIs + */ + +#include +#include "sir_types.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "wlan_qct_sys.h" +#include "i_cds_packet.h" +#include "cds_reg_service.h" +#include "wma_types.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_tsf.h" +#include +#if (defined(__ANDROID_COMMON_KERNEL__) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) && \ + defined(MSM_PLATFORM)) +#include +#endif +#include + +#include "pld_common.h" +#include "sap_api.h" +#include "bmi.h" +#include "ol_fw.h" +#include "ol_if_athvar.h" +#include "hif.h" +#include "wlan_policy_mgr_api.h" +#include "cds_utils.h" +#include "wlan_logging_sock_svc.h" +#include "wma.h" +#include "pktlog_ac.h" +#include "wlan_policy_mgr_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include "target_type.h" +#include "wlan_ocb_ucfg_api.h" +#include "wlan_ipa_ucfg_api.h" + +#ifdef ENABLE_SMMU_S1_TRANSLATION +#include "pld_common.h" +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 4, 0)) +#include +#endif +#include +#endif + +#ifdef QCA_WIFI_QCA8074 +#include +#endif +#include "wlan_mlme_ucfg_api.h" +#include "cfg_ucfg_api.h" +#include "wlan_cp_stats_mc_ucfg_api.h" +#include +#include +#include +#include +#include +#include "wlan_dp_ucfg_api.h" +#include "wlan_dp_prealloc.h" +#include "wlan_dp_api.h" +#include "qdf_ipa.h" + +/* Preprocessor Definitions and Constants */ + +/* Preprocessor Definitions and Constants */ + +/* Data definitions */ +static struct cds_context g_cds_context; +static struct cds_context *gp_cds_context; +static struct __qdf_device g_qdf_ctx; + +static uint8_t cds_multicast_logging; + +#define DRIVER_VER_LEN (11) +#define HANG_EVENT_VER_LEN (1) + +struct cds_hang_event_fixed_param { + uint16_t tlv_header; + uint8_t recovery_reason; + char driver_version[DRIVER_VER_LEN]; + char hang_event_version[HANG_EVENT_VER_LEN]; +} qdf_packed; + +#ifdef QCA_WIFI_QCA8074 +static inline int +cds_send_delba(struct cdp_ctrl_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t *peer_macaddr, + uint8_t tid, uint8_t reason_code, + uint8_t cdp_reason_code) +{ + return wma_dp_send_delba_ind(vdev_id, peer_macaddr, tid, + reason_code, cdp_reason_code); +} + +static struct ol_if_ops dp_ol_if_ops = { + .peer_set_default_routing = target_if_peer_set_default_routing, + .peer_rx_reorder_queue_setup = target_if_peer_rx_reorder_queue_setup, + .peer_rx_reorder_queue_remove = target_if_peer_rx_reorder_queue_remove, + .peer_multi_rx_reorder_queue_setup = + target_if_peer_multi_rx_reorder_queue_setup, + .is_hw_dbs_capable = policy_mgr_is_dp_hw_dbs_capable, + .lro_hash_config = target_if_lro_hash_config, + .rx_invalid_peer = wma_rx_invalid_peer_ind, + .is_roam_inprogress = wma_is_roam_in_progress, + .get_con_mode = cds_get_conparam, + .send_delba = cds_send_delba, + .dp_rx_get_pending = dp_rx_tm_get_pending, +#ifdef DP_MEM_PRE_ALLOC + .dp_prealloc_get_context = dp_prealloc_get_context_memory, + .dp_prealloc_put_context = dp_prealloc_put_context_memory, + .dp_prealloc_get_consistent = dp_prealloc_get_coherent, + .dp_prealloc_put_consistent = dp_prealloc_put_coherent, + .dp_get_multi_pages = dp_prealloc_get_multi_pages, + .dp_put_multi_pages = dp_prealloc_put_multi_pages, +#endif + .dp_get_tx_inqueue = dp_get_tx_inqueue, + .dp_send_unit_test_cmd = wma_form_unit_test_cmd_and_send, + .dp_print_fisa_stats = wlan_dp_print_fisa_rx_stats, + /* TODO: Add any other control path calls required to OL_IF/WMA layer */ +}; +#else +static struct ol_if_ops dp_ol_if_ops = { + .dp_rx_get_pending = cds_get_rx_thread_pending, +}; +#endif + +static void cds_trigger_recovery_work(void *param); + +/** + * struct cds_recovery_call_info - caller information for cds_trigger_recovery + * @func: caller's function name + * @line: caller's line number + */ +struct cds_recovery_call_info { + const char *func; + uint32_t line; +} __cds_recovery_caller; + +/** + * cds_recovery_work_init() - Initialize recovery work queue + * + * Return: none + */ +static QDF_STATUS cds_recovery_work_init(void) +{ + qdf_create_work(0, &gp_cds_context->cds_recovery_work, + cds_trigger_recovery_work, &__cds_recovery_caller); + gp_cds_context->cds_recovery_wq = + qdf_create_workqueue("cds_recovery_workqueue"); + if (!gp_cds_context->cds_recovery_wq) { + cds_err("Failed to create cds_recovery_workqueue"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_recovery_work_deinit() - Initialize recovery work queue + * + * Return: none + */ +static void cds_recovery_work_deinit(void) +{ + if (gp_cds_context->cds_recovery_wq) { + qdf_flush_workqueue(0, gp_cds_context->cds_recovery_wq); + qdf_destroy_workqueue(0, gp_cds_context->cds_recovery_wq); + } +} + +static bool cds_is_drv_connected(void) +{ + int ret; + qdf_device_t qdf_ctx; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return false; + + ret = pld_is_drv_connected(qdf_ctx->dev); + + return ((ret > 0) ? true : false); +} + +static bool cds_is_drv_supported(void) +{ + qdf_device_t qdf_ctx; + struct pld_platform_cap cap = {0}; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return false; + + pld_get_platform_cap(qdf_ctx->dev, &cap); + + return ((cap.cap_flag & PLD_HAS_DRV_SUPPORT) ? true : false); +} + +static QDF_STATUS cds_wmi_send_recv_qmi(void *buf, uint32_t len, void * cb_ctx, + qdf_wmi_recv_qmi_cb wmi_rx_cb) +{ + qdf_device_t qdf_ctx; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return QDF_STATUS_E_INVAL; + + if (pld_qmi_send(qdf_ctx->dev, 0, buf, len, cb_ctx, wmi_rx_cb)) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS cds_qmi_indication(void *cb_ctx, qdf_qmi_ind_cb qmi_ind_cb) +{ + qdf_device_t qdf_ctx; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return QDF_STATUS_E_INVAL; + + if (pld_qmi_indication(qdf_ctx->dev, cb_ctx, qmi_ind_cb)) + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_update_recovery_reason() - update the recovery reason code + * @recovery_reason: recovery reason + * + * Return: None + */ +static void cds_update_recovery_reason(enum qdf_hang_reason recovery_reason) +{ + if (!gp_cds_context) { + cds_err("gp_cds_context is null"); + return; + } + + gp_cds_context->recovery_reason = recovery_reason; +} + +/** + * cds_sys_reboot_lock_init() - Create lock for system reboot + * + * Return: QDF_STATUS_SUCCESS if the lock was created and an error on failure + */ +static QDF_STATUS cds_sys_reboot_lock_init(void) +{ + return qdf_mutex_create(&gp_cds_context->sys_reboot_lock); +} + +/** + * cds_sys_reboot_lock_deinit() - destroy lock for system reboot + * + * Return: none + */ +static void cds_sys_reboot_lock_deinit(void) +{ + qdf_mutex_destroy(&gp_cds_context->sys_reboot_lock); +} + +void cds_set_sys_rebooting(void) +{ + qdf_mutex_acquire(&gp_cds_context->sys_reboot_lock); + cds_set_driver_state(CDS_DRIVER_STATE_SYS_REBOOTING); + qdf_mutex_release(&gp_cds_context->sys_reboot_lock); +} + +bool cds_sys_reboot_protect(void) +{ + enum cds_driver_state state; + + qdf_mutex_acquire(&gp_cds_context->sys_reboot_lock); + + state = cds_get_driver_state(); + return __CDS_IS_DRIVER_STATE(state, CDS_DRIVER_STATE_SYS_REBOOTING); +} + +void cds_sys_reboot_unprotect(void) +{ + qdf_mutex_release(&gp_cds_context->sys_reboot_lock); +} + +QDF_STATUS cds_init(void) +{ + QDF_STATUS status; + + gp_cds_context = &g_cds_context; + + status = cds_sys_reboot_lock_init(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to init sys reboot lock; status:%u", status); + goto deinit; + } + + status = cds_recovery_work_init(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to init recovery work; status:%u", status); + goto destroy_lock; + } + + cds_ssr_protect_init(); + + gp_cds_context->qdf_ctx = &g_qdf_ctx; + + qdf_register_self_recovery_callback(cds_trigger_recovery_psoc); + qdf_register_fw_down_callback(cds_is_fw_down); + qdf_register_is_driver_unloading_callback(cds_is_driver_unloading); + qdf_register_is_driver_state_module_stop_callback( + cds_is_driver_state_module_stop); + qdf_register_recovering_state_query_callback(cds_is_driver_recovering); + qdf_register_drv_connected_callback(cds_is_drv_connected); + qdf_register_drv_supported_callback(cds_is_drv_supported); + qdf_register_wmi_send_recv_qmi_callback(cds_wmi_send_recv_qmi); + qdf_register_qmi_indication_callback(cds_qmi_indication); + qdf_register_recovery_reason_update(cds_update_recovery_reason); + qdf_register_get_bus_reg_dump(pld_get_bus_reg_dump); + + return QDF_STATUS_SUCCESS; + +destroy_lock: + cds_sys_reboot_lock_deinit(); +deinit: + gp_cds_context = NULL; + qdf_mem_zero(&g_cds_context, sizeof(g_cds_context)); + + return status; +} + +/** + * cds_deinit() - Deinitialize CDS + * + * This function frees the CDS resources + */ +void cds_deinit(void) +{ + QDF_BUG(gp_cds_context); + if (!gp_cds_context) + return; + + qdf_register_get_bus_reg_dump(NULL); + qdf_register_recovery_reason_update(NULL); + qdf_register_recovering_state_query_callback(NULL); + qdf_register_fw_down_callback(NULL); + qdf_register_is_driver_unloading_callback(NULL); + qdf_register_is_driver_state_module_stop_callback(NULL); + qdf_register_self_recovery_callback(NULL); + qdf_register_wmi_send_recv_qmi_callback(NULL); + qdf_register_qmi_indication_callback(NULL); + + gp_cds_context->qdf_ctx = NULL; + qdf_mem_zero(&g_qdf_ctx, sizeof(g_qdf_ctx)); + + /* currently, no ssr_protect_deinit */ + + cds_recovery_work_deinit(); + cds_sys_reboot_lock_deinit(); + + gp_cds_context = NULL; + qdf_mem_zero(&g_cds_context, sizeof(g_cds_context)); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * cds_tdls_tx_rx_mgmt_event()- send tdls mgmt rx tx event + * @event_id: event id + * @tx_rx: tx or rx + * @type: type of frame + * @action_sub_type: action frame type + * @peer_mac: peer mac + * + * This Function sends tdls mgmt rx tx diag event + * + * Return: void. + */ +void cds_tdls_tx_rx_mgmt_event(uint8_t event_id, uint8_t tx_rx, + uint8_t type, uint8_t action_sub_type, uint8_t *peer_mac) +{ + WLAN_HOST_DIAG_EVENT_DEF(tdls_tx_rx_mgmt, + struct host_event_tdls_tx_rx_mgmt); + + tdls_tx_rx_mgmt.event_id = event_id; + tdls_tx_rx_mgmt.tx_rx = tx_rx; + tdls_tx_rx_mgmt.type = type; + tdls_tx_rx_mgmt.action_sub_type = action_sub_type; + qdf_mem_copy(tdls_tx_rx_mgmt.peer_mac, + peer_mac, CDS_MAC_ADDRESS_LEN); + WLAN_HOST_DIAG_EVENT_REPORT(&tdls_tx_rx_mgmt, + EVENT_WLAN_TDLS_TX_RX_MGMT); +} +#endif + +/** + * cds_cfg_update_ac_specs_params() - update ac_specs params + * @olcfg: cfg handle + * @cds_cfg: pointer to cds config + * + * Return: none + */ +static void +cds_cfg_update_ac_specs_params(struct txrx_pdev_cfg_param_t *olcfg, + struct cds_config_info *cds_cfg) +{ + int i; + + if (!olcfg) + return; + + if (!cds_cfg) + return; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + olcfg->ac_specs[i].wrr_skip_weight = + cds_cfg->ac_specs[i].wrr_skip_weight; + olcfg->ac_specs[i].credit_threshold = + cds_cfg->ac_specs[i].credit_threshold; + olcfg->ac_specs[i].send_limit = + cds_cfg->ac_specs[i].send_limit; + olcfg->ac_specs[i].credit_reserve = + cds_cfg->ac_specs[i].credit_reserve; + olcfg->ac_specs[i].discard_weight = + cds_cfg->ac_specs[i].discard_weight; + } +} + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +static inline void +cds_cdp_set_flow_control_params(struct wlan_objmgr_psoc *psoc, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{ + cdp_cfg->tx_flow_stop_queue_th = + cfg_get(psoc, CFG_DP_TX_FLOW_STOP_QUEUE_TH); + cdp_cfg->tx_flow_start_queue_offset = + cfg_get(psoc, CFG_DP_TX_FLOW_START_QUEUE_OFFSET); +} +#else +static inline void +cds_cdp_set_flow_control_params(struct wlan_objmgr_psoc *psoc, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{} +#endif + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +static inline void +cds_cdp_update_del_ack_params(struct wlan_objmgr_psoc *psoc, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{ + cdp_cfg->del_ack_enable = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_ENABLE); + cdp_cfg->del_ack_pkt_count = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_PKT_CNT); + cdp_cfg->del_ack_timer_value = + cfg_get(psoc, CFG_DP_DRIVER_TCP_DELACK_TIMER_VALUE); +} +#else +static inline void +cds_cdp_update_del_ack_params(struct wlan_objmgr_psoc *psoc, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{} +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +static inline void +cds_cdp_update_bundle_params(struct wlan_objmgr_psoc *psoc, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{ + cdp_cfg->bundle_timer_value = + cfg_get(psoc, CFG_DP_HL_BUNDLE_TIMER_VALUE); + cdp_cfg->bundle_size = + cfg_get(psoc, CFG_DP_HL_BUNDLE_SIZE); +} +#else +static inline void +cds_cdp_update_bundle_params(struct wlan_objmgr_psoc *psoc, + struct txrx_pdev_cfg_param_t *cdp_cfg) +{ +} +#endif + +/** + * cds_cdp_cfg_attach() - attach data path config module + * @psoc: psoc handle + * + * Return: none + */ +static void cds_cdp_cfg_attach(struct wlan_objmgr_psoc *psoc) +{ + struct txrx_pdev_cfg_param_t cdp_cfg = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t gro_bit_set; + + cdp_cfg.is_full_reorder_offload = DP_REORDER_OFFLOAD_SUPPORT; + cdp_cfg.is_uc_offload_enabled = ucfg_ipa_uc_is_enabled(); + cdp_cfg.uc_tx_buffer_count = cfg_get(psoc, CFG_DP_IPA_UC_TX_BUF_COUNT); + cdp_cfg.uc_tx_buffer_size = + cfg_get(psoc, CFG_DP_IPA_UC_TX_BUF_SIZE); + cdp_cfg.uc_rx_indication_ring_count = + cfg_get(psoc, CFG_DP_IPA_UC_RX_IND_RING_COUNT); + cdp_cfg.uc_tx_partition_base = + cfg_get(psoc, CFG_DP_IPA_UC_TX_PARTITION_BASE); + cdp_cfg.enable_rxthread = ucfg_dp_is_rx_common_thread_enabled(psoc); + cdp_cfg.ip_tcp_udp_checksum_offload = + cfg_get(psoc, CFG_DP_TCP_UDP_CKSUM_OFFLOAD); + cdp_cfg.nan_ip_tcp_udp_checksum_offload = + cfg_get(psoc, CFG_DP_NAN_TCP_UDP_CKSUM_OFFLOAD); + cdp_cfg.p2p_ip_tcp_udp_checksum_offload = + cfg_get(psoc, CFG_DP_P2P_TCP_UDP_CKSUM_OFFLOAD); + cdp_cfg.legacy_mode_csum_disable = + cfg_get(psoc, CFG_DP_LEGACY_MODE_CSUM_DISABLE); + cdp_cfg.ce_classify_enabled = + cfg_get(psoc, CFG_DP_CE_CLASSIFY_ENABLE); + cdp_cfg.tso_enable = cfg_get(psoc, CFG_DP_TSO); + cdp_cfg.lro_enable = cfg_get(psoc, CFG_DP_LRO); + cdp_cfg.sg_enable = cfg_get(psoc, CFG_DP_SG); + cdp_cfg.enable_data_stall_detection = + cfg_get(psoc, CFG_DP_ENABLE_DATA_STALL_DETECTION); + gro_bit_set = cfg_get(psoc, CFG_DP_GRO); + if (gro_bit_set & DP_GRO_ENABLE_BIT_SET) + cdp_cfg.gro_enable = true; + cdp_cfg.enable_flow_steering = + cfg_get(psoc, CFG_DP_FLOW_STEERING_ENABLED); + cdp_cfg.disable_intra_bss_fwd = + cfg_get(psoc, CFG_DP_AP_STA_SECURITY_SEPERATION); + cdp_cfg.pktlog_buffer_size = + cfg_get(psoc, CFG_DP_PKTLOG_BUFFER_SIZE); + + cds_cdp_update_del_ack_params(psoc, &cdp_cfg); + + cds_cdp_update_bundle_params(psoc, &cdp_cfg); + + gp_cds_context->cfg_ctx = cdp_cfg_attach(soc, gp_cds_context->qdf_ctx, + (void *)(&cdp_cfg)); + if (!gp_cds_context->cfg_ctx) { + cds_debug("failed to init cfg handle"); + return; + } + + /* Configure Receive flow steering */ + cdp_cfg_set_flow_steering(soc, gp_cds_context->cfg_ctx, + cfg_get(psoc, CFG_DP_FLOW_STEERING_ENABLED)); + + cds_cdp_set_flow_control_params(psoc, &cdp_cfg); + cdp_cfg_set_flow_control_parameters(soc, gp_cds_context->cfg_ctx, + (void *)&cdp_cfg); + + /* adjust the cfg_ctx default value based on setting */ + cdp_cfg_set_rx_fwd_disabled(soc, gp_cds_context->cfg_ctx, + cfg_get(psoc, + CFG_DP_AP_STA_SECURITY_SEPERATION)); + + /* + * adjust the packet log enable default value + * based on CFG INI setting + */ + cdp_cfg_set_packet_log_enabled(soc, gp_cds_context->cfg_ctx, + (uint8_t)cds_is_packet_log_enabled()); + + /* adjust the ptp rx option default value based on CFG INI setting */ + cdp_cfg_set_ptp_rx_opt_enabled(soc, gp_cds_context->cfg_ctx, + (uint8_t)cds_is_ptp_rx_opt_enabled()); +} +static QDF_STATUS cds_register_all_modules(void) +{ + QDF_STATUS status; + + scheduler_register_wma_legacy_handler(&wma_mc_process_handler); + scheduler_register_sys_legacy_handler(&sys_mc_process_handler); + + /* Register message queues in given order such that queue priority is + * intact: + * 1) QDF_MODULE_ID_SYS: Timer queue(legacy SYS queue) + * 2) QDF_MODULE_ID_TARGET_IF: Target interface queue + * 3) QDF_MODULE_ID_PE: Legacy PE message queue + * 4) QDF_MODULE_ID_SME: Legacy SME message queue + * 5) QDF_MODULE_ID_OS_IF: OS IF message queue for new components + */ + status = scheduler_register_module(QDF_MODULE_ID_SYS, + &scheduler_timer_q_mq_handler); + status = scheduler_register_module(QDF_MODULE_ID_TARGET_IF, + &scheduler_target_if_mq_handler); + status = scheduler_register_module(QDF_MODULE_ID_PE, + &pe_mc_process_handler); + status = scheduler_register_module(QDF_MODULE_ID_SME, + &sme_mc_process_handler); + status = scheduler_register_module(QDF_MODULE_ID_OS_IF, + &scheduler_os_if_mq_handler); + status = scheduler_register_module(QDF_MODULE_ID_SCAN, + &scheduler_scan_mq_handler); + return status; +} + +static QDF_STATUS cds_deregister_all_modules(void) +{ + QDF_STATUS status; + + scheduler_deregister_wma_legacy_handler(); + scheduler_deregister_sys_legacy_handler(); + status = scheduler_deregister_module(QDF_MODULE_ID_SCAN); + status = scheduler_deregister_module(QDF_MODULE_ID_SYS); + status = scheduler_deregister_module(QDF_MODULE_ID_TARGET_IF); + status = scheduler_deregister_module(QDF_MODULE_ID_PE); + status = scheduler_deregister_module(QDF_MODULE_ID_SME); + status = scheduler_deregister_module(QDF_MODULE_ID_OS_IF); + + return status; +} + +/** + * cds_set_ac_specs_params() - set ac_specs params in cds_config_info + * @cds_cfg: Pointer to cds_config_info + * + * Return: none + */ +static void +cds_set_ac_specs_params(struct cds_config_info *cds_cfg) +{ + int i; + struct cds_context *cds_ctx; + + if (!cds_cfg) + return; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) + return; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + cds_cfg->ac_specs[i] = cds_ctx->ac_specs[i]; + } +} + +static int cds_hang_event_notifier_call(struct notifier_block *block, + unsigned long state, + void *data) +{ + struct qdf_notifer_data *cds_hang_data = data; + uint32_t total_len; + struct cds_hang_event_fixed_param *cmd; + uint8_t *cds_hang_evt_buff; + + if (!cds_hang_data) + return NOTIFY_STOP_MASK; + + cds_hang_evt_buff = cds_hang_data->hang_data; + + if (!cds_hang_evt_buff) + return NOTIFY_STOP_MASK; + + total_len = sizeof(*cmd); + if (cds_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET) + return NOTIFY_STOP_MASK; + + cds_hang_evt_buff = cds_hang_data->hang_data + cds_hang_data->offset; + cmd = (struct cds_hang_event_fixed_param *)cds_hang_evt_buff; + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, HANG_EVT_TAG_CDS, + QDF_HANG_GET_STRUCT_TLVLEN(*cmd)); + + cmd->recovery_reason = gp_cds_context->recovery_reason; + + /* userspace expects a fixed format */ + qdf_mem_set(&cmd->driver_version, DRIVER_VER_LEN, ' '); + qdf_mem_copy(&cmd->driver_version, QWLAN_VERSIONSTR, + qdf_min(sizeof(QWLAN_VERSIONSTR) - 1, + (size_t)DRIVER_VER_LEN)); + + /* userspace expects a fixed format */ + qdf_mem_set(&cmd->hang_event_version, HANG_EVENT_VER_LEN, ' '); + qdf_mem_copy(&cmd->hang_event_version, QDF_HANG_EVENT_VERSION, + qdf_min(sizeof(QDF_HANG_EVENT_VERSION) - 1, + (size_t)HANG_EVENT_VER_LEN)); + + cds_hang_data->offset += total_len; + return NOTIFY_OK; +} + +static qdf_notif_block cds_hang_event_notifier = { + .notif_block.notifier_call = cds_hang_event_notifier_call, +}; + +/** + * cds_set_exclude_selftx_from_cca_busy_time() - Set exclude self tx time + * from cca busy time bool in cds config + * @exclude_selftx_from_cca_busy: Bool to be stored in cds config + * @cds_cfg: Pointer to cds config + * + * Return: None + */ +static void +cds_set_exclude_selftx_from_cca_busy_time(bool exclude_selftx_from_cca_busy, + struct cds_config_info *cds_cfg) +{ + cds_cfg->exclude_selftx_from_cca_busy = exclude_selftx_from_cca_busy; +} + +/** + * cds_open() - open the CDS Module + * + * cds_open() function opens the CDS Scheduler + * Upon successful initialization: + * - All CDS submodules should have been initialized + * + * - The CDS scheduler should have opened + * + * - All the WLAN SW components should have been opened. This includes + * SYS, MAC, SME, WMA and TL. + * @psoc: psoc handle + * + * Return: QDF status + */ +QDF_STATUS cds_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + struct cds_config_info *cds_cfg; + qdf_device_t qdf_ctx; + struct htc_init_info htcInfo = { 0 }; + struct dp_txrx_soc_attach_params soc_attach_params = {0}; + struct ol_context *ol_ctx; + struct hif_opaque_softc *scn; + void *HTCHandle; + struct hdd_context *hdd_ctx; + struct cds_context *cds_ctx; + mac_handle_t mac_handle; + + cds_debug("Opening CDS"); + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) + return QDF_STATUS_E_FAILURE; + + /* Initialize the timer module */ + qdf_timer_module_init(); + + /* Initialize bug reporting structure */ + cds_init_log_completion(); + + hdd_ctx = gp_cds_context->hdd_context; + if (!hdd_ctx || !hdd_ctx->config) { + cds_err("Hdd Context is Null"); + + status = QDF_STATUS_E_FAILURE; + return status; + } + + status = dispatcher_enable(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to enable dispatcher; status:%d", status); + return status; + } + + /* Now Open the CDS Scheduler */ + status = cds_sched_open(gp_cds_context, + &gp_cds_context->qdf_sched, + sizeof(cds_sched_context)); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Failed to open CDS Scheduler"); + goto err_dispatcher_disable; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + status = QDF_STATUS_E_FAILURE; + goto err_sched_close; + } + + cds_cfg = cds_get_ini_config(); + if (!cds_cfg) { + cds_err("Cds config is NULL"); + + status = QDF_STATUS_E_FAILURE; + goto err_sched_close; + } + + hdd_enable_fastpath(hdd_ctx, scn); + + /* Initialize BMI and Download firmware */ + ol_ctx = cds_get_context(QDF_MODULE_ID_BMI); + status = bmi_download_firmware(ol_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("BMI FIALED status:%d", status); + goto err_bmi_close; + } + + hdd_wlan_update_target_info(hdd_ctx, scn); + + htcInfo.pContext = ol_ctx; + htcInfo.TargetFailure = ol_target_failure; + htcInfo.TargetSendSuspendComplete = + ucfg_pmo_psoc_target_suspend_acknowledge; + htcInfo.target_initial_wakeup_cb = ucfg_pmo_psoc_handle_initial_wake_up; + htcInfo.target_psoc = (void *)psoc; + htcInfo.cfg_wmi_credit_cnt = hdd_ctx->config->cfg_wmi_credit_cnt; + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + /* Create HTC */ + gp_cds_context->htc_ctx = + htc_create(scn, &htcInfo, qdf_ctx, cds_get_conparam()); + if (!gp_cds_context->htc_ctx) { + cds_alert("Failed to Create HTC"); + + status = QDF_STATUS_E_FAILURE; + goto err_bmi_close; + } + ucfg_pmo_psoc_update_htc_handle(psoc, (void *)gp_cds_context->htc_ctx); + + status = bmi_done(ol_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Failed to complete BMI phase"); + goto err_htc_close; + } + + cds_set_exclude_selftx_from_cca_busy_time( + hdd_ctx->config->exclude_selftx_from_cca_busy, + cds_cfg); + /*Open the WMA module */ + status = wma_open(psoc, hdd_update_tgt_cfg, cds_cfg, + hdd_ctx->target_type); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Failed to open WMA module"); + goto err_htc_close; + } + + /* Number of peers limit differs in each chip version. If peer max + * limit configured in ini exceeds more than supported, WMA adjusts + * and keeps correct limit in cds_cfg.max_station. So, make sure + * config entry hdd_ctx->config->maxNumberOfPeers has adjusted value + */ + /* In FTM mode cds_cfg->max_stations will be zero. On updating same + * into hdd context config entry, leads to pe_open() to fail, if + * con_mode change happens from FTM mode to any other mode. + */ + if (QDF_DRIVER_TYPE_PRODUCTION == cds_cfg->driver_type) + ucfg_mlme_set_sap_max_peers(psoc, cds_cfg->max_station); + + HTCHandle = cds_get_context(QDF_MODULE_ID_HTC); + gp_cds_context->cfg_ctx = NULL; + if (!HTCHandle) { + status = QDF_STATUS_E_FAILURE; + goto err_wma_close; + } + + status = htc_wait_target(HTCHandle); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Failed to complete BMI phase. status: %d", status); + QDF_BUG(status == QDF_STATUS_E_NOMEM || cds_is_fw_down()); + + goto err_wma_close; + } + + cds_debug("target_type %d 8074:%d 6290:%d 6390: %d 6490: %d 6750: %d", + hdd_ctx->target_type, + TARGET_TYPE_QCA8074, + TARGET_TYPE_QCA6290, + TARGET_TYPE_QCA6390, + TARGET_TYPE_QCA6490, + TARGET_TYPE_QCA6750); + + /* Set default value to false */ + hdd_ctx->is_wifi3_0_target = false; + + soc_attach_params.target_type = hdd_ctx->target_type; + soc_attach_params.target_psoc = htcInfo.target_psoc; + soc_attach_params.dp_ol_if_ops = &dp_ol_if_ops; + gp_cds_context->dp_soc = + ucfg_dp_txrx_soc_attach(&soc_attach_params, + &hdd_ctx->is_wifi3_0_target); + if (!gp_cds_context->dp_soc) { + status = QDF_STATUS_E_FAILURE; + goto err_wma_close; + } + + wlan_psoc_set_dp_handle(psoc, gp_cds_context->dp_soc); + ucfg_dp_set_cmn_dp_handle(psoc, gp_cds_context->dp_soc); + ucfg_pmo_psoc_update_dp_handle(psoc, gp_cds_context->dp_soc); + ucfg_ocb_update_dp_handle(psoc, gp_cds_context->dp_soc); + + cds_set_ac_specs_params(cds_cfg); + cds_cfg_update_ac_specs_params((struct txrx_pdev_cfg_param_t *) + gp_cds_context->cfg_ctx, cds_cfg); + cds_cdp_cfg_attach(psoc); + + bmi_target_ready(scn, gp_cds_context->cfg_ctx); + + /* Now proceed to open the MAC */ + status = mac_open(psoc, &mac_handle, + gp_cds_context->hdd_context, cds_cfg); + + if (QDF_STATUS_SUCCESS != status) { + cds_alert("Failed to open MAC"); + goto err_soc_detach; + } + gp_cds_context->mac_context = mac_handle; + + /* Now proceed to open the SME */ + status = sme_open(mac_handle); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Failed to open SME"); + goto err_mac_close; + } + + cds_register_all_modules(); + + status = dispatcher_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + cds_alert("Failed to open PSOC Components"); + goto deregister_modules; + } + + ucfg_mc_cp_stats_register_pmo_handler(); + qdf_hang_event_register_notifier(&cds_hang_event_notifier); + + return QDF_STATUS_SUCCESS; + +deregister_modules: + cds_deregister_all_modules(); + sme_close(mac_handle); + +err_mac_close: + mac_close(mac_handle); + gp_cds_context->mac_context = NULL; + +err_soc_detach: + ucfg_dp_txrx_soc_detach(gp_cds_context->dp_soc); + gp_cds_context->dp_soc = NULL; + + ucfg_ocb_update_dp_handle(psoc, NULL); + ucfg_pmo_psoc_update_dp_handle(psoc, NULL); + wlan_psoc_set_dp_handle(psoc, NULL); + +err_wma_close: + cds_shutdown_notifier_purge(); + wma_close(); + wma_wmi_service_close(); + +err_htc_close: + if (gp_cds_context->htc_ctx) { + htc_destroy(gp_cds_context->htc_ctx); + gp_cds_context->htc_ctx = NULL; + ucfg_pmo_psoc_update_htc_handle(psoc, NULL); + } + +err_bmi_close: + bmi_cleanup(ol_ctx); + +err_sched_close: + if (QDF_IS_STATUS_ERROR(cds_sched_close())) + QDF_DEBUG_PANIC("Failed to close CDS Scheduler"); + +err_dispatcher_disable: + if (QDF_IS_STATUS_ERROR(dispatcher_disable())) + QDF_DEBUG_PANIC("Failed to disable dispatcher"); + + return status; +} /* cds_open() */ + +QDF_STATUS cds_dp_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + struct dp_txrx_config dp_config; + struct hdd_context *hdd_ctx; + + hdd_ctx = gp_cds_context->hdd_context; + if (!hdd_ctx) { + cds_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + ucfg_dp_txrx_pdev_attach(cds_get_context(QDF_MODULE_ID_SOC)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* Critical Error ... Cannot proceed further */ + cds_alert("Failed to open TXRX"); + QDF_ASSERT(0); + goto close; + } + + if (hdd_ctx->target_type == TARGET_TYPE_QCA6290 || + hdd_ctx->target_type == TARGET_TYPE_QCA6390 || + hdd_ctx->target_type == TARGET_TYPE_QCA6490 || + hdd_ctx->target_type == TARGET_TYPE_QCA6750 || + hdd_ctx->target_type == TARGET_TYPE_KIWI || + hdd_ctx->target_type == TARGET_TYPE_MANGO || + hdd_ctx->target_type == TARGET_TYPE_PEACH || + hdd_ctx->target_type == TARGET_TYPE_WCN6450) { + qdf_status = cdp_pdev_init(cds_get_context(QDF_MODULE_ID_SOC), + gp_cds_context->htc_ctx, + gp_cds_context->qdf_ctx, 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + /* Critical Error ... Cannot proceed further */ + cds_alert("Failed to init TXRX"); + QDF_ASSERT(0); + goto pdev_detach; + } + } + + if (cdp_txrx_intr_attach(gp_cds_context->dp_soc) + != QDF_STATUS_SUCCESS) { + cds_alert("Failed to attach interrupts"); + goto pdev_deinit; + } + + dp_config.enable_rx_threads = + (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) ? + false : gp_cds_context->cds_cfg->enable_dp_rx_threads; + + qdf_status = ucfg_dp_txrx_init(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, + &dp_config); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + goto intr_close; + + ucfg_pmo_psoc_set_txrx_pdev_id(psoc, OL_TXRX_PDEV_ID); + ucfg_ocb_set_txrx_pdev_id(psoc, OL_TXRX_PDEV_ID); + + cdp_set_rtpm_tput_policy_requirement(cds_get_context(QDF_MODULE_ID_SOC), + false); + + cds_debug("CDS successfully Opened"); + + if (cdp_cfg_get(gp_cds_context->dp_soc, cfg_dp_tc_based_dyn_gro_enable)) + ucfg_dp_set_tc_based_dyn_gro(psoc, true); + else + ucfg_dp_set_tc_based_dyn_gro(psoc, false); + + ucfg_dp_set_tc_ingress_prio(psoc, cdp_cfg_get(gp_cds_context->dp_soc, + cfg_dp_tc_ingress_prio)); + + return 0; + +intr_close: + cdp_txrx_intr_detach(gp_cds_context->dp_soc); + +pdev_deinit: + cdp_pdev_deinit(gp_cds_context->dp_soc, + OL_TXRX_PDEV_ID, false); + +pdev_detach: + ucfg_dp_txrx_pdev_detach(gp_cds_context->dp_soc, OL_TXRX_PDEV_ID, + false); + +close: + return QDF_STATUS_E_FAILURE; +} + +/** + * cds_should_suspend_target() - Get value whether target can suspend + * + * Return: true if target can suspend, otherwise false + */ +static bool cds_should_suspend_target(void) +{ + struct hif_opaque_softc *hif_ctx; + struct hif_target_info *tgt_info; + uint32_t target_type = TARGET_TYPE_UNKNOWN; + + /* don't suspend during SSR */ + if (cds_is_driver_recovering()) + return false; + + /* don't suspend if the driver is in a bad state */ + if (cds_is_driver_in_bad_state()) + return false; + + /* if we are in any mode other than FTM we should suspend */ + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) + return true; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (hif_ctx) { + tgt_info = hif_get_target_info_handle(hif_ctx); + if (tgt_info) + target_type = tgt_info->target_type; + } + + /* + * for most target we also want to suspend in FTM mode, + * but some targets do not support that. + */ + if (target_type == TARGET_TYPE_AR6320 || + target_type == TARGET_TYPE_AR6320V1 || + target_type == TARGET_TYPE_AR6320V2 || + target_type == TARGET_TYPE_AR6320V3 || + target_type == TARGET_TYPE_QCN7605) + return false; + + /* target should support suspend in FTM mode */ + return true; +} + +#ifdef HIF_USB +static inline void cds_suspend_target(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + /* Suspend the target and disable interrupt */ + status = ucfg_pmo_psoc_suspend_target(wma_handle->psoc, 0); + if (status) + cds_err("Failed to suspend target, status = %d", status); +} +#else +static inline void cds_suspend_target(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + /* Suspend the target and disable interrupt */ + status = ucfg_pmo_psoc_suspend_target(wma_handle->psoc, 1); + if (status) + cds_err("Failed to suspend target, status = %d", status); +} +#endif /* HIF_USB */ + +/** + * cds_pre_enable() - pre enable cds + * + * Return: QDF status + */ +QDF_STATUS cds_pre_enable(void) +{ + QDF_STATUS status; + int errno; + void *scn; + void *soc; + void *hif_ctx; + + cds_enter(); + + if (!gp_cds_context) { + cds_err("cds context is null"); + return QDF_STATUS_E_INVAL; + } + + if (!gp_cds_context->wma_context) { + cds_err("wma context is null"); + return QDF_STATUS_E_INVAL; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) + return QDF_STATUS_E_INVAL; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) + return QDF_STATUS_E_INVAL; + + /* call Packetlog connect service */ + if (QDF_GLOBAL_FTM_MODE != cds_get_conparam() && + QDF_GLOBAL_EPPING_MODE != cds_get_conparam()) + cdp_pkt_log_con_service(soc, OL_TXRX_PDEV_ID, + scn); + + /*call WMA pre start */ + status = wma_pre_start(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to WMA prestart"); + goto exit_pkt_log; + } + + status = htc_start(gp_cds_context->htc_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to Start HTC"); + goto exit_pkt_log; + } + + status = wma_wait_for_ready_event(gp_cds_context->wma_context); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to wait for ready event; status: %u", status); + goto stop_wmi; + } + + errno = cdp_pdev_post_attach(soc, OL_TXRX_PDEV_ID); + if (errno) { + cds_err("Failed to attach pdev"); + status = qdf_status_from_os_return(errno); + goto stop_wmi; + } + + return QDF_STATUS_SUCCESS; + +stop_wmi: + /* Send pdev suspend to fw otherwise FW is not aware that + * host is freeing resources. + */ + if (!(cds_is_driver_recovering() || cds_is_driver_in_bad_state())) + cds_suspend_target(gp_cds_context->wma_context); + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + wma_wmi_stop(); + + if (hif_ctx) { + cds_err("Disable the isr & reset the soc!"); + hif_disable_isr(hif_ctx); + hif_reset_soc(hif_ctx); + } + htc_stop(gp_cds_context->htc_ctx); + + wma_wmi_work_close(); + +exit_pkt_log: + if (QDF_GLOBAL_FTM_MODE != cds_get_conparam() && + QDF_GLOBAL_EPPING_MODE != cds_get_conparam()) + cdp_pkt_log_exit(soc, OL_TXRX_PDEV_ID); + + return status; +} + +QDF_STATUS cds_enable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + struct mac_start_params mac_params; + + /* We support only one instance for now ... */ + if (!gp_cds_context) { + cds_err("Invalid CDS context"); + return QDF_STATUS_E_FAILURE; + } + + if (!gp_cds_context->wma_context) { + cds_err("WMA NULL context"); + return QDF_STATUS_E_FAILURE; + } + + if (!gp_cds_context->mac_context) { + cds_err("MAC NULL context"); + return QDF_STATUS_E_FAILURE; + } + + /* Start the wma */ + qdf_status = wma_start(); + if (qdf_status != QDF_STATUS_SUCCESS) { + cds_err("Failed to start wma; status:%d", qdf_status); + return QDF_STATUS_E_FAILURE; + } + + /* Start the MAC */ + qdf_mem_zero(&mac_params, sizeof(mac_params)); + mac_params.driver_type = QDF_DRIVER_TYPE_PRODUCTION; + qdf_status = mac_start(gp_cds_context->mac_context, &mac_params); + + if (QDF_STATUS_SUCCESS != qdf_status) { + cds_err("Failed to start MAC; status:%d", qdf_status); + goto err_wma_stop; + } + + /* START SME */ + qdf_status = sme_start(gp_cds_context->mac_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to start SME; status:%d", qdf_status); + goto err_mac_stop; + } + + qdf_status = + ucfg_dp_txrx_attach_target(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to attach DP target; status:%d", qdf_status); + goto err_sme_stop; + } + + qdf_status = dispatcher_psoc_enable(psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("dispatcher_psoc_enable failed; status:%d", qdf_status); + goto err_soc_target_detach; + } + + /* Trigger psoc enable for CLD components */ + hdd_component_psoc_enable(psoc); + + return QDF_STATUS_SUCCESS; + +err_soc_target_detach: + /* NOOP */ + +err_sme_stop: + sme_stop(gp_cds_context->mac_context); + +err_mac_stop: + mac_stop(gp_cds_context->mac_context); + +err_wma_stop: + qdf_status = wma_stop(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to stop wma"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + return QDF_STATUS_E_FAILURE; +} /* cds_enable() */ + +/** + * cds_disable() - stop/disable cds module + * @psoc: Psoc pointer + * + * Return: QDF status + */ +QDF_STATUS cds_disable(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + void *handle; + + /* PSOC disable for all new components. It needs to happen before + * target is PDEV suspended such that a component can abort all its + * ongoing transaction with FW. Always keep it before wma_stop() as + * wma_stop() does target PDEV suspend. + */ + + /* Trigger psoc disable for CLD components */ + if (psoc) { + hdd_component_psoc_disable(psoc); + dispatcher_psoc_disable(psoc); + } + + qdf_status = wma_stop(); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to stop wma"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + handle = cds_get_context(QDF_MODULE_ID_PE); + if (!handle) + return QDF_STATUS_E_INVAL; + + umac_stop(); + + return qdf_status; +} + +/** + * cds_post_disable() - post disable cds module + * + * Return: QDF status + */ +QDF_STATUS cds_post_disable(void) +{ + tp_wma_handle wma_handle; + struct hif_opaque_softc *hif_ctx; + struct scheduler_ctx *sched_ctx; + QDF_STATUS qdf_status; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return QDF_STATUS_E_INVAL; + + /* flush any unprocessed scheduler messages */ + sched_ctx = scheduler_get_context(); + if (sched_ctx) { + qdf_status = scheduler_disable(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to disable scheduler"); + return QDF_STATUS_E_INVAL; + } + } + /* + * With new state machine changes cds_close can be invoked without + * cds_disable. So, send the following clean up prerequisites to fw, + * So Fw and host are in sync for cleanup indication: + * - Send PDEV_SUSPEND indication to firmware + * - Disable HIF Interrupts. + * - Clean up CE tasklets. + */ + + cds_debug("send deinit sequence to firmware"); + if (cds_should_suspend_target()) + cds_suspend_target(wma_handle); + hif_disable_isr(hif_ctx); + hif_reset_soc(hif_ctx); + + if (gp_cds_context->htc_ctx) { + wma_wmi_stop(); + htc_stop(gp_cds_context->htc_ctx); + } + + qdf_status = cds_close_rx_thread(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close RX thread!"); + return QDF_STATUS_E_INVAL; + } + + cdp_pdev_pre_detach(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, 1); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_close() - close cds module + * @psoc: Psoc pointer + * + * This API allows user to close modules registered + * with connectivity device services. + * + * Return: QDF status + */ +QDF_STATUS cds_close(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS qdf_status; + + qdf_hang_event_unregister_notifier(&cds_hang_event_notifier); + qdf_status = cds_sched_close(); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + if (QDF_IS_STATUS_ERROR(qdf_status)) + cds_err("Failed to close CDS Scheduler"); + + dispatcher_psoc_close(psoc); + + qdf_flush_work(&gp_cds_context->cds_recovery_work); + + cds_shutdown_notifier_purge(); + + qdf_status = wma_wmi_work_close(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close wma_wmi_work"); + QDF_ASSERT(0); + } + + if (gp_cds_context->htc_ctx) { + htc_destroy(gp_cds_context->htc_ctx); + ucfg_pmo_psoc_update_htc_handle(psoc, NULL); + gp_cds_context->htc_ctx = NULL; + } + + qdf_status = sme_close(gp_cds_context->mac_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close SME"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + qdf_status = mac_close(gp_cds_context->mac_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close MAC"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + gp_cds_context->mac_context = NULL; + + ucfg_dp_txrx_soc_detach(gp_cds_context->dp_soc); + gp_cds_context->dp_soc = NULL; + + ucfg_pmo_psoc_update_dp_handle(psoc, NULL); + wlan_psoc_set_dp_handle(psoc, NULL); + + + qdf_status = wma_close(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close wma"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + qdf_status = wma_wmi_service_close(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_err("Failed to close wma_wmi_service"); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + } + + cds_deinit_ini_config(); + qdf_timer_module_deinit(); + + cds_deregister_all_modules(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cds_dp_close(struct wlan_objmgr_psoc *psoc) +{ + cdp_txrx_intr_detach(gp_cds_context->dp_soc); + + qdf_nbuf_stop_replenish_timer(); + + ucfg_dp_txrx_deinit(cds_get_context(QDF_MODULE_ID_SOC)); + + cdp_pdev_deinit(cds_get_context(QDF_MODULE_ID_SOC), OL_TXRX_PDEV_ID, 1); + + ucfg_dp_txrx_pdev_detach(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, 1); + + ucfg_pmo_psoc_set_txrx_pdev_id(psoc, OL_TXRX_INVALID_PDEV_ID); + + return QDF_STATUS_SUCCESS; +} + +void *__cds_get_context(QDF_MODULE_ID module_id, const char *func) +{ + void *context = NULL; + + if (!gp_cds_context) { + cds_err("cds context pointer is null (via %s)", func); + return NULL; + } + + switch (module_id) { + case QDF_MODULE_ID_HDD: + { + context = gp_cds_context->hdd_context; + break; + } + + case QDF_MODULE_ID_SME: + case QDF_MODULE_ID_PE: + { + /* In all these cases, we just return the MAC Context */ + context = gp_cds_context->mac_context; + break; + } + + case QDF_MODULE_ID_WMA: + { + /* For wma module */ + context = gp_cds_context->wma_context; + break; + } + + case QDF_MODULE_ID_QDF: + { + /* For SYS this is CDS itself */ + context = gp_cds_context; + break; + } + + case QDF_MODULE_ID_HIF: + { + context = gp_cds_context->hif_context; + break; + } + + case QDF_MODULE_ID_HTC: + { + context = gp_cds_context->htc_ctx; + break; + } + + case QDF_MODULE_ID_QDF_DEVICE: + { + context = gp_cds_context->qdf_ctx; + break; + } + + case QDF_MODULE_ID_BMI: + { + context = gp_cds_context->g_ol_context; + break; + } + + case QDF_MODULE_ID_CFG: + { + context = gp_cds_context->cfg_ctx; + break; + } + + case QDF_MODULE_ID_SOC: + { + context = gp_cds_context->dp_soc; + break; + } + + default: + { + cds_err("Module ID %d does not have its context maintained by CDS (via %s)", + module_id, func); + QDF_ASSERT(0); + return NULL; + } + } + + if (!context) + cds_err("Module ID %d context is Null (via %s)", + module_id, func); + + return context; +} /* cds_get_context() */ + +/** + * cds_get_global_context() - get CDS global Context + * + * This API allows any user to get the CDS Global Context pointer from a + * module context data area. + * + * Return: pointer to the CDS global context, NULL if the function is + * unable to retrieve the CDS context. + */ +void *cds_get_global_context(void) +{ + if (!gp_cds_context) { + /* + * To avoid recursive call, this should not change to + * QDF_TRACE(). + */ + pr_err("%s: global cds context is NULL", __func__); + } + + return gp_cds_context; +} /* cds_get_global_context() */ + +/** + * cds_get_driver_state() - Get current driver state + * + * This API returns current driver state stored in global context. + * + * Return: Driver state enum + */ +enum cds_driver_state cds_get_driver_state(void) +{ + if (!gp_cds_context) { + cds_err("global cds context is NULL"); + + return CDS_DRIVER_STATE_UNINITIALIZED; + } + + return gp_cds_context->driver_state; +} + +/** + * cds_set_driver_state() - Set current driver state + * @state: Driver state to be set to. + * + * This API sets driver state to state. This API only sets the state and doesn't + * clear states, please make sure to use cds_clear_driver_state to clear any + * state if required. + * + * Return: None + */ +void cds_set_driver_state(enum cds_driver_state state) +{ + if (!gp_cds_context) { + cds_err("global cds context is NULL: %x", state); + + return; + } + + gp_cds_context->driver_state |= state; +} + +/** + * cds_clear_driver_state() - Clear current driver state + * @state: Driver state to be cleared. + * + * This API clears driver state. This API only clears the state, please make + * sure to use cds_set_driver_state to set any new states. + * + * Return: None + */ +void cds_clear_driver_state(enum cds_driver_state state) +{ + if (!gp_cds_context) { + cds_err("global cds context is NULL: %x", state); + + return; + } + + gp_cds_context->driver_state &= ~state; +} + +/** + * cds_alloc_context() - allocate a context within the CDS global Context + * @module_id: module ID who's context area is being allocated. + * @module_context: pointer to location where the pointer to the + * allocated context is returned. Note this output pointer + * is valid only if the API returns QDF_STATUS_SUCCESS + * @size: size of the context area to be allocated. + * + * This API allows any user to allocate a user context area within the + * CDS Global Context. + * + * Return: QDF status + */ +QDF_STATUS cds_alloc_context(QDF_MODULE_ID module_id, + void **module_context, uint32_t size) +{ + void **cds_mod_context = NULL; + + if (!gp_cds_context) { + cds_err("cds context is null"); + return QDF_STATUS_E_FAILURE; + } + + if (!module_context) { + cds_err("null param passed"); + return QDF_STATUS_E_FAILURE; + } + + switch (module_id) { + case QDF_MODULE_ID_WMA: + cds_mod_context = &gp_cds_context->wma_context; + break; + + case QDF_MODULE_ID_HIF: + cds_mod_context = &gp_cds_context->hif_context; + break; + + case QDF_MODULE_ID_BMI: + cds_mod_context = &gp_cds_context->g_ol_context; + break; + + default: + cds_err("Module ID %i does not have its context allocated by CDS", + module_id); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (*cds_mod_context) { + /* Context has already been allocated! + * Prevent double allocation + */ + cds_err("Module ID %i context has already been allocated", + module_id); + return QDF_STATUS_E_EXISTS; + } + + /* Dynamically allocate the context for module */ + + *module_context = qdf_mem_malloc(size); + + if (!*module_context) { + cds_err("Failed to allocate Context for module ID %i", + module_id); + QDF_ASSERT(0); + return QDF_STATUS_E_NOMEM; + } + + *cds_mod_context = *module_context; + + return QDF_STATUS_SUCCESS; +} /* cds_alloc_context() */ + +/** + * cds_set_context() - API to set context in global CDS Context + * @module_id: Module ID + * @context: Pointer to the Module Context + * + * API to set a MODULE Context in global CDS Context + * + * Return: QDF_STATUS + */ +QDF_STATUS cds_set_context(QDF_MODULE_ID module_id, void *context) +{ + struct cds_context *p_cds_context = cds_get_global_context(); + + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return QDF_STATUS_NOT_INITIALIZED; + } + + switch (module_id) { + case QDF_MODULE_ID_HDD: + p_cds_context->hdd_context = context; + break; + case QDF_MODULE_ID_HIF: + p_cds_context->hif_context = context; + break; + default: + cds_err("Module ID %i does not have its context managed by CDS", + module_id); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_free_context() - free an allocated context within the + * CDS global Context + * @module_id: module ID who's context area is being free + * @module_context: pointer to module context area to be free'd. + * + * This API allows a user to free the user context area within the + * CDS Global Context. + * + * Return: QDF status + */ +QDF_STATUS cds_free_context(QDF_MODULE_ID module_id, void *module_context) +{ + void **cds_mod_context = NULL; + + if (!gp_cds_context) { + cds_err("cds context is null"); + return QDF_STATUS_E_FAILURE; + } + + if (!module_context) { + cds_err("Null param"); + return QDF_STATUS_E_FAILURE; + } + + switch (module_id) { + case QDF_MODULE_ID_WMA: + cds_mod_context = &gp_cds_context->wma_context; + break; + + case QDF_MODULE_ID_HIF: + cds_mod_context = &gp_cds_context->hif_context; + break; + + case QDF_MODULE_ID_BMI: + cds_mod_context = &gp_cds_context->g_ol_context; + break; + + default: + cds_err("Module ID %i does not have its context allocated by CDS", + module_id); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (!*cds_mod_context) { + /* Context has not been allocated or freed already! */ + cds_err("Module ID %i context has not been allocated or freed already", + module_id); + return QDF_STATUS_E_FAILURE; + } + + if (*cds_mod_context != module_context) { + cds_err("cds_mod_context != module_context"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_free(module_context); + + *cds_mod_context = NULL; + + return QDF_STATUS_SUCCESS; +} /* cds_free_context() */ + + +/** + * cds_flush_work() - flush pending works + * @work: pointer to work + * + * Return: none + */ +void cds_flush_work(void *work) +{ + cancel_work_sync(work); +} + +/** + * cds_flush_delayed_work() - flush delayed works + * @dwork: pointer to delayed work + * + * Return: none + */ +void cds_flush_delayed_work(void *dwork) +{ + cancel_delayed_work_sync(dwork); +} + +#ifndef REMOVE_PKT_LOG +/** + * cds_is_packet_log_enabled() - check if packet log is enabled + * + * Return: true if packet log is enabled else false + */ +bool cds_is_packet_log_enabled(void) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = gp_cds_context->hdd_context; + if ((!hdd_ctx) || (!hdd_ctx->config)) { + cds_alert("Hdd Context is Null"); + return false; + } + return hdd_ctx->config->enable_packet_log; +} +#endif + +static int cds_force_assert_target_via_pld(qdf_device_t qdf) +{ + int errno; + + errno = pld_force_assert_target(qdf->dev); + if (errno == -EOPNOTSUPP) + cds_info("PLD does not support target force assert"); + else if (errno) + cds_err("Failed PLD target force assert; errno %d", errno); + else + cds_info("Target force assert triggered via PLD"); + + return errno; +} + +static QDF_STATUS cds_force_assert_target_via_wmi(qdf_device_t qdf) +{ + QDF_STATUS status; + t_wma_handle *wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_INVAL; + + status = wma_crash_inject(wma, RECOVERY_SIM_SELF_RECOVERY, 0); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed target force assert; status %d", status); + return status; + } + + status = qdf_wait_for_event_completion(&wma->recovery_event, + WMA_CRASH_INJECT_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed target force assert wait; status %d", status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_force_assert_target() - Send assert command to firmware + * @qdf: QDF device instance to assert + * + * An out-of-band recovery mechanism will cleanup and restart the entire wlan + * subsystem in the event of a firmware crash. This API injects a firmware + * crash to start this process when the wlan driver is known to be in a bad + * state. If a firmware assert inject fails, the wlan driver will schedule + * the driver recovery anyway, as a best effort attempt to return to a working + * state. + * + * Return: QDF_STATUS + */ +static QDF_STATUS cds_force_assert_target(qdf_device_t qdf) +{ + int errno; + QDF_STATUS status; + + /* first, try target assert inject via pld */ + errno = cds_force_assert_target_via_pld(qdf); + if (!errno) + return QDF_STATUS_SUCCESS; + if (errno != -EOPNOTSUPP) + return QDF_STATUS_E_FAILURE; + + /* pld assert is not supported, try target assert inject via wmi */ + status = cds_force_assert_target_via_wmi(qdf); + if (QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_SUCCESS; + + /* wmi assert failed, start recovery without the firmware assert */ + cds_err("Scheduling recovery work without firmware assert"); + pld_schedule_recovery_work(qdf->dev, PLD_REASON_DEFAULT); + + return status; +} + +/** + * cds_trigger_recovery_handler() - handle a self recovery request + * @func: the name of the function that called cds_trigger_recovery + * @line: the line number of the call site which called cds_trigger_recovery + * + * Return: none + */ +static void cds_trigger_recovery_handler(const char *func, const uint32_t line) +{ + QDF_STATUS status; + qdf_runtime_lock_t rtl; + qdf_device_t qdf; + bool ssr_ini_enabled = cds_is_self_recovery_enabled(); + + /* NOTE! This code path is delicate! Think very carefully before + * modifying the content or order of the following. Please review any + * potential changes with someone closely familiar with this feature. + */ + + if (cds_is_driver_recovering()) { + cds_info("WLAN recovery already in progress"); + return; + } + + if (cds_is_driver_in_bad_state()) { + cds_info("WLAN has already failed recovery"); + return; + } + + if (cds_is_fw_down()) { + cds_info("Firmware has already initiated recovery"); + return; + } + + qdf = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf) + return; + + /* + * if *wlan* recovery is disabled, crash here for debugging for + * snoc/IPCI targets. + */ + if ((qdf->bus_type == QDF_BUS_TYPE_SNOC || + qdf->bus_type == QDF_BUS_TYPE_IPCI) && !ssr_ini_enabled) { + QDF_DEBUG_PANIC("WLAN recovery is not enabled (via %s:%d)", + func, line); + return; + } + + if (cds_is_driver_unloading()) { + QDF_DEBUG_PANIC("WLAN is unloading recovery not expected(via %s:%d)", + func, line); + return; + } + + status = qdf_runtime_lock_init(&rtl); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("qdf_runtime_lock_init failed, status: %d", status); + return; + } + + status = qdf_runtime_pm_prevent_suspend(&rtl); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to acquire runtime pm lock"); + goto deinit_rtl; + } + + cds_err("critical host timeout trigger fw recovery for reason code %d", + gp_cds_context->recovery_reason); + + cds_set_recovery_in_progress(true); + cds_set_assert_target_in_progress(true); + if (pld_force_collect_target_dump(qdf->dev)) + cds_force_assert_target(qdf); + cds_set_assert_target_in_progress(false); + + /* Do not wait for firmware down block wmi transactions */ + wma_wmi_stop(); + + /* + * if *wlan* recovery is disabled, once all the required registers are + * read via the platform driver check and crash the system. + */ + if (qdf->bus_type == QDF_BUS_TYPE_PCI && !ssr_ini_enabled) + QDF_DEBUG_PANIC("WLAN recovery is not enabled (via %s:%d)", + func, line); + + status = qdf_runtime_pm_allow_suspend(&rtl); + if (QDF_IS_STATUS_ERROR(status)) + cds_err("Failed to release runtime pm lock"); + +deinit_rtl: + qdf_runtime_lock_deinit(&rtl); +} + +static void cds_trigger_recovery_work(void *context) +{ + struct cds_recovery_call_info *call_info = context; + + cds_trigger_recovery_handler(call_info->func, call_info->line); +} + +void __cds_trigger_recovery(enum qdf_hang_reason reason, const char *func, + const uint32_t line) +{ + if (!gp_cds_context) { + cds_err("gp_cds_context is null"); + return; + } + + gp_cds_context->recovery_reason = reason; + + __cds_recovery_caller.func = func; + __cds_recovery_caller.line = line; + qdf_queue_work(0, gp_cds_context->cds_recovery_wq, + &gp_cds_context->cds_recovery_work); +} + +void cds_trigger_recovery_psoc(void *psoc, enum qdf_hang_reason reason, + const char *func, const uint32_t line) +{ + __cds_trigger_recovery(reason, func, line); +} + + +/** + * cds_get_recovery_reason() - get self recovery reason + * @reason: recovery reason + * + * Return: None + */ +void cds_get_recovery_reason(enum qdf_hang_reason *reason) +{ + if (!gp_cds_context) { + cds_err("gp_cds_context is null"); + return; + } + + *reason = gp_cds_context->recovery_reason; +} + +/** + * cds_reset_recovery_reason() - reset the reason to unspecified + * + * Return: None + */ +void cds_reset_recovery_reason(void) +{ + if (!gp_cds_context) { + cds_err("gp_cds_context is null"); + return; + } + + gp_cds_context->recovery_reason = QDF_REASON_UNSPECIFIED; +} + +/** + * cds_set_wakelock_logging() - Logging of wakelock enabled/disabled + * @value: Boolean value + * + * This function is used to set the flag which will indicate whether + * logging of wakelock is enabled or not + * + * Return: None + */ +void cds_set_wakelock_logging(bool value) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return; + } + p_cds_context->is_wakelock_log_enabled = value; +} + +/** + * cds_is_wakelock_enabled() - Check if logging of wakelock is enabled/disabled + * + * This function is used to check whether logging of wakelock is enabled or not + * + * Return: true if logging of wakelock is enabled + */ +bool cds_is_wakelock_enabled(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return false; + } + return p_cds_context->is_wakelock_log_enabled; +} + +/** + * cds_set_ring_log_level() - Sets the log level of a particular ring + * @ring_id: ring_id + * @log_level: Log level specified + * + * This function converts HLOS values to driver log levels and sets the log + * level of a particular ring accordingly. + * + * Return: None + */ +void cds_set_ring_log_level(uint32_t ring_id, uint32_t log_level) +{ + struct cds_context *p_cds_context; + uint32_t log_val; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return; + } + + switch (log_level) { + case LOG_LEVEL_NO_COLLECTION: + log_val = WLAN_LOG_LEVEL_OFF; + break; + case LOG_LEVEL_NORMAL_COLLECT: + log_val = WLAN_LOG_LEVEL_NORMAL; + break; + case LOG_LEVEL_ISSUE_REPRO: + log_val = WLAN_LOG_LEVEL_REPRO; + break; + case LOG_LEVEL_ACTIVE: + default: + log_val = WLAN_LOG_LEVEL_ACTIVE; + break; + } + + if (ring_id == RING_ID_WAKELOCK) { + p_cds_context->wakelock_log_level = log_val; + return; + } else if (ring_id == RING_ID_CONNECTIVITY) { + p_cds_context->connectivity_log_level = log_val; + return; + } else if (ring_id == RING_ID_PER_PACKET_STATS) { + p_cds_context->packet_stats_log_level = log_val; + return; + } else if (ring_id == RING_ID_DRIVER_DEBUG) { + p_cds_context->driver_debug_log_level = log_val; + return; + } else if (ring_id == RING_ID_FIRMWARE_DEBUG) { + p_cds_context->fw_debug_log_level = log_val; + return; + } +} + +/** + * cds_get_ring_log_level() - Get the a ring id's log level + * @ring_id: Ring id + * + * Fetch and return the log level corresponding to a ring id + * + * Return: Log level corresponding to the ring ID + */ +enum wifi_driver_log_level cds_get_ring_log_level(uint32_t ring_id) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return WLAN_LOG_LEVEL_OFF; + } + + if (ring_id == RING_ID_WAKELOCK) + return p_cds_context->wakelock_log_level; + else if (ring_id == RING_ID_CONNECTIVITY) + return p_cds_context->connectivity_log_level; + else if (ring_id == RING_ID_PER_PACKET_STATS) + return p_cds_context->packet_stats_log_level; + else if (ring_id == RING_ID_DRIVER_DEBUG) + return p_cds_context->driver_debug_log_level; + else if (ring_id == RING_ID_FIRMWARE_DEBUG) + return p_cds_context->fw_debug_log_level; + + return WLAN_LOG_LEVEL_OFF; +} + +/** + * cds_set_multicast_logging() - Set mutlicast logging value + * @value: Value of multicast logging + * + * Set the multicast logging value which will indicate + * whether to multicast host and fw messages even + * without any registration by userspace entity + * + * Return: None + */ +void cds_set_multicast_logging(uint8_t value) +{ + cds_multicast_logging = value; +} + +/** + * cds_is_multicast_logging() - Get multicast logging value + * + * Get the multicast logging value which will indicate + * whether to multicast host and fw messages even + * without any registration by userspace entity + * + * Return: 0 - Multicast logging disabled, 1 - Multicast logging enabled + */ +uint8_t cds_is_multicast_logging(void) +{ + return cds_multicast_logging; +} + +/* + * cds_init_log_completion() - Initialize log param structure + * + * This function is used to initialize the logging related + * parameters + * + * Return: None + */ +void cds_init_log_completion(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return; + } + + p_cds_context->log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; + p_cds_context->log_complete.indicator = WLAN_LOG_INDICATOR_UNUSED; + p_cds_context->log_complete.reason_code = WLAN_LOG_REASON_CODE_UNUSED; + p_cds_context->log_complete.is_report_in_progress = false; +} + +/** + * cds_set_log_completion() - Store the logging params + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which triggered the bug report + * @reason_code: Reason for triggering bug report + * @recovery_needed: If recovery is needed after bug report + * + * This function is used to set the logging parameters based on the + * caller + * + * Return: 0 if setting of params is successful + */ +QDF_STATUS cds_set_log_completion(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool recovery_needed) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return QDF_STATUS_E_FAILURE; + } + + qdf_spinlock_acquire(&p_cds_context->bug_report_lock); + p_cds_context->log_complete.is_fatal = is_fatal; + p_cds_context->log_complete.indicator = indicator; + p_cds_context->log_complete.reason_code = reason_code; + p_cds_context->log_complete.recovery_needed = recovery_needed; + p_cds_context->log_complete.is_report_in_progress = true; + qdf_spinlock_release(&p_cds_context->bug_report_lock); + cds_debug("is_fatal %d indicator %d reason_code %d recovery needed %d", + is_fatal, indicator, reason_code, recovery_needed); + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_get_and_reset_log_completion() - Get and reset logging related params + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which triggered the bug report + * @reason_code: Reason for triggering bug report + * @recovery_needed: If recovery is needed after bug report + * + * This function is used to get the logging related parameters + * + * Return: None + */ +void cds_get_and_reset_log_completion(uint32_t *is_fatal, + uint32_t *indicator, + uint32_t *reason_code, + bool *recovery_needed) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return; + } + + qdf_spinlock_acquire(&p_cds_context->bug_report_lock); + *is_fatal = p_cds_context->log_complete.is_fatal; + *indicator = p_cds_context->log_complete.indicator; + *reason_code = p_cds_context->log_complete.reason_code; + *recovery_needed = p_cds_context->log_complete.recovery_needed; + + /* reset */ + p_cds_context->log_complete.indicator = WLAN_LOG_INDICATOR_UNUSED; + p_cds_context->log_complete.is_fatal = WLAN_LOG_TYPE_NON_FATAL; + p_cds_context->log_complete.is_report_in_progress = false; + p_cds_context->log_complete.reason_code = WLAN_LOG_REASON_CODE_UNUSED; + p_cds_context->log_complete.recovery_needed = false; + qdf_spinlock_release(&p_cds_context->bug_report_lock); +} + +/** + * cds_is_log_report_in_progress() - Check if bug reporting is in progress + * + * This function is used to check if the bug reporting is already in progress + * + * Return: true if the bug reporting is in progress + */ +bool cds_is_log_report_in_progress(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return true; + } + return p_cds_context->log_complete.is_report_in_progress; +} + +/** + * cds_is_fatal_event_enabled() - Return if fatal event is enabled + * + * Return true if fatal event is enabled. + */ +bool cds_is_fatal_event_enabled(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return false; + } + + + return p_cds_context->enable_fatal_event; +} + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +bool cds_is_ptp_rx_opt_enabled(void) +{ + struct hdd_context *hdd_ctx; + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return false; + } + + hdd_ctx = (struct hdd_context *)(p_cds_context->hdd_context); + if ((!hdd_ctx) || (!hdd_ctx->config)) { + cds_err("Hdd Context is Null"); + return false; + } + + return hdd_tsf_is_rx_set(hdd_ctx); +} + +bool cds_is_ptp_tx_opt_enabled(void) +{ + struct hdd_context *hdd_ctx; + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return false; + } + + hdd_ctx = (struct hdd_context *)(p_cds_context->hdd_context); + if ((!hdd_ctx) || (!hdd_ctx->config)) { + cds_err("Hdd Context is Null"); + return false; + } + + return hdd_tsf_is_tx_set(hdd_ctx); +} +#endif + +/** + * cds_get_log_indicator() - Get the log flush indicator + * + * This function is used to get the log flush indicator + * + * Return: log indicator + */ +uint32_t cds_get_log_indicator(void) +{ + struct cds_context *p_cds_context; + uint32_t indicator; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return WLAN_LOG_INDICATOR_UNUSED; + } + + if (cds_is_load_or_unload_in_progress() || + cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + return WLAN_LOG_INDICATOR_UNUSED; + } + + qdf_spinlock_acquire(&p_cds_context->bug_report_lock); + indicator = p_cds_context->log_complete.indicator; + qdf_spinlock_release(&p_cds_context->bug_report_lock); + return indicator; +} + +/** + * cds_wlan_flush_host_logs_for_fatal() - Wrapper to flush host logs + * + * This function is used to send signal to the logger thread to + * flush the host logs. + * + * Return: None + * + */ +void cds_wlan_flush_host_logs_for_fatal(void) +{ + if (cds_is_log_report_in_progress()) + wlan_flush_host_logs_for_fatal(); +} + +/** + * cds_flush_logs() - Report fatal event to userspace + * @is_fatal: Indicates if the event triggering bug report is fatal or not + * @indicator: Source which triggered the bug report + * @reason_code: Reason for triggering bug report + * @dump_mac_trace: If mac trace are needed in logs. + * @recovery_needed: If recovery is needed after bug report + * + * This function sets the log related params and send the WMI command to the + * FW to flush its logs. On receiving the flush completion event from the FW + * the same will be conveyed to userspace + * + * Return: 0 on success + */ +QDF_STATUS cds_flush_logs(uint32_t is_fatal, + uint32_t indicator, + uint32_t reason_code, + bool dump_mac_trace, + bool recovery_needed) +{ + QDF_STATUS status; + + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return QDF_STATUS_E_FAILURE; + } + if (!p_cds_context->enable_fatal_event) { + cds_err("Fatal event not enabled"); + return QDF_STATUS_E_FAILURE; + } + if (cds_is_load_or_unload_in_progress() || + cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + cds_err("un/Load/SSR in progress"); + return QDF_STATUS_E_FAILURE; + } + + if (cds_is_log_report_in_progress()) { + cds_err("Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + is_fatal, indicator, reason_code); + return QDF_STATUS_E_FAILURE; + } + + status = cds_set_log_completion(is_fatal, indicator, + reason_code, recovery_needed); + if (QDF_STATUS_SUCCESS != status) { + cds_err("Failed to set log trigger params"); + return QDF_STATUS_E_FAILURE; + } + + cds_debug("Triggering bug report: type:%d, indicator=%d reason_code=%d", + is_fatal, indicator, reason_code); + + if (dump_mac_trace) + qdf_trace_dump_all(p_cds_context->mac_context, 0, 0, 100, 0); + + if (WLAN_LOG_INDICATOR_HOST_ONLY == indicator) { + cds_wlan_flush_host_logs_for_fatal(); + return QDF_STATUS_SUCCESS; + } + + status = sme_send_flush_logs_cmd_to_fw(); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to send flush FW log"); + cds_init_log_completion(); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_logging_set_fw_flush_complete() - Wrapper for FW log flush completion + * + * This function is used to send signal to the logger thread to indicate + * that the flushing of FW logs is complete by the FW + * + * Return: None + * + */ +void cds_logging_set_fw_flush_complete(void) +{ + if (cds_is_fatal_event_enabled()) + wlan_logging_set_fw_flush_complete(); +} + +/** + * cds_set_fatal_event() - set fatal event status + * @value: pending statue to set + * + * Return: None + */ +void cds_set_fatal_event(bool value) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + cds_err("cds context is Invalid"); + return; + } + p_cds_context->enable_fatal_event = value; +} + +/** + * cds_get_radio_index() - get radio index + * + * Return: radio index otherwise, -EINVAL + */ +int cds_get_radio_index(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + /* + * To avoid recursive call, this should not change to + * QDF_TRACE(). + */ + pr_err("%s: cds context is invalid\n", __func__); + return -EINVAL; + } + + return p_cds_context->radio_index; +} + +/** + * cds_set_radio_index() - set radio index + * @radio_index: the radio index to set + * + * Return: QDF status + */ +QDF_STATUS cds_set_radio_index(int radio_index) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + pr_err("%s: cds context is invalid\n", __func__); + return QDF_STATUS_E_FAILURE; + } + + p_cds_context->radio_index = radio_index; + + return QDF_STATUS_SUCCESS; +} + +/** + * cds_init_ini_config() - API to initialize CDS configuration parameters + * @cfg: CDS Configuration + * + * Return: void + */ + +void cds_init_ini_config(struct cds_config_info *cfg) +{ + struct cds_context *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) + return; + + cds_ctx->cds_cfg = cfg; +} + +/** + * cds_deinit_ini_config() - API to free CDS configuration parameters + * + * Return: void + */ +void cds_deinit_ini_config(void) +{ + struct cds_context *cds_ctx; + struct cds_config_info *cds_cfg; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) + return; + + cds_cfg = cds_ctx->cds_cfg; + cds_ctx->cds_cfg = NULL; + + if (cds_cfg) + qdf_mem_free(cds_cfg); +} + +/** + * cds_get_ini_config() - API to get CDS configuration parameters + * + * Return: cds config structure + */ +struct cds_config_info *cds_get_ini_config(void) +{ + struct cds_context *cds_ctx; + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) + return NULL; + + return cds_ctx->cds_cfg; +} + +/** + * cds_is_5_mhz_enabled() - API to get 5MHZ enabled + * + * Return: true if 5 mhz is enabled, false otherwise + */ +bool cds_is_5_mhz_enabled(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) + return false; + + if (p_cds_context->cds_cfg) + return (p_cds_context->cds_cfg->sub_20_channel_width == + WLAN_SUB_20_CH_WIDTH_5); + + return false; +} + +/** + * cds_is_10_mhz_enabled() - API to get 10-MHZ enabled + * + * Return: true if 10 mhz is enabled, false otherwise + */ +bool cds_is_10_mhz_enabled(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) + return false; + + if (p_cds_context->cds_cfg) + return (p_cds_context->cds_cfg->sub_20_channel_width == + WLAN_SUB_20_CH_WIDTH_10); + + return false; +} + +/** + * cds_is_sub_20_mhz_enabled() - API to get sub 20-MHZ enabled + * + * Return: true if 5 or 10 mhz is enabled, false otherwise + */ +bool cds_is_sub_20_mhz_enabled(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) + return false; + + if (p_cds_context->cds_cfg) + return p_cds_context->cds_cfg->sub_20_channel_width; + + return false; +} + +/** + * cds_is_self_recovery_enabled() - API to get self recovery enabled + * + * Return: true if self recovery enabled, false otherwise + */ +bool cds_is_self_recovery_enabled(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_context(QDF_MODULE_ID_QDF); + if (!p_cds_context) + return false; + + if (p_cds_context->cds_cfg) + return p_cds_context->cds_cfg->self_recovery_enabled; + + return false; +} + +/** + * cds_is_fw_down() - Is FW down or not + * + * Return: true if FW is down and false otherwise. + */ +bool cds_is_fw_down(void) +{ + qdf_device_t qdf_ctx; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return false; + + return pld_is_fw_down(qdf_ctx->dev); +} + +/** + * cds_svc_fw_shutdown_ind() - API to send userspace about FW crash + * + * @dev: Device Pointer + * + * Return: None + */ +void cds_svc_fw_shutdown_ind(struct device *dev) +{ + hdd_svc_fw_shutdown_ind(dev); +} + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/* + * cds_pkt_stats_to_logger_thread() - send pktstats to user + * @pl_hdr: Pointer to pl_hdr + * @pkt_dump: Pointer to pkt_dump data structure. + * @data: Pointer to data + * + * This function is used to send the pkt stats to SVC module. + * + * Return: None + */ +inline void cds_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, + void *data) +{ + if (cds_get_ring_log_level(RING_ID_PER_PACKET_STATS) != + WLAN_LOG_LEVEL_ACTIVE) + return; + + wlan_pkt_stats_to_logger_thread(pl_hdr, pkt_dump, data); +} +#endif + +/** + * cds_get_conparam() - Get the connection mode parameters + * + * Return the connection mode parameter set by insmod or set during statically + * linked driver + * + * Return: enum QDF_GLOBAL_MODE + */ +enum QDF_GLOBAL_MODE cds_get_conparam(void) +{ + enum QDF_GLOBAL_MODE con_mode; + + con_mode = hdd_get_conparam(); + + return con_mode; +} + +#ifdef FEATURE_HTC_CREDIT_HISTORY +inline void +cds_print_htc_credit_history(uint32_t count, qdf_abstract_print *print, + void *print_priv) +{ + htc_print_credit_history(gp_cds_context->htc_ctx, count, + print, print_priv); +} +#endif + +#ifdef FEATURE_ALIGN_STATS_FROM_DP +/** + * cds_get_cdp_vdev_stats() - Function which retrieves cdp vdev stats + * @vdev_id: vdev id + * @vdev_stats: cdp vdev stats retrieves from DP + * + * Return: If get cdp vdev stats success return true, otherwise return false + */ +static bool +cds_get_cdp_vdev_stats(uint8_t vdev_id, struct cdp_vdev_stats *vdev_stats) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!vdev_stats) + return false; + + if (cdp_host_get_vdev_stats(soc, vdev_id, vdev_stats, true)) + return false; + + return true; +} + +bool +cds_dp_get_vdev_stats(uint8_t vdev_id, struct cds_vdev_dp_stats *stats) +{ + struct cdp_vdev_stats *vdev_stats; + bool ret = false; + + vdev_stats = qdf_mem_malloc(sizeof(*vdev_stats)); + if (!vdev_stats) + return false; + + if (cds_get_cdp_vdev_stats(vdev_id, vdev_stats)) { + stats->tx_retries = vdev_stats->tx.retries; + stats->tx_retries_mpdu = vdev_stats->tx.retries_mpdu; + stats->tx_mpdu_success_with_retries = + vdev_stats->tx.mpdu_success_with_retries; + ret = true; + } + + qdf_mem_free(vdev_stats); + return ret; +} +#endif + +#ifdef ENABLE_SMMU_S1_TRANSLATION +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +QDF_STATUS cds_smmu_mem_map_setup(qdf_device_t osdev, bool ipa_present) +{ + struct iommu_domain *domain; + bool ipa_smmu_enabled; + bool wlan_smmu_enabled; + + domain = pld_smmu_get_domain(osdev->dev); + if (domain) { + int attr = 0; + int errno = qdf_iommu_domain_get_attr(domain, + QDF_DOMAIN_ATTR_S1_BYPASS, + &attr); + + wlan_smmu_enabled = !errno && !attr; + } else { + cds_info("No SMMU mapping present"); + wlan_smmu_enabled = false; + } + + if (!wlan_smmu_enabled) { + osdev->smmu_s1_enabled = false; + goto exit_with_success; + } + + if (!ipa_present) { + osdev->smmu_s1_enabled = true; + goto exit_with_success; + } + + ipa_smmu_enabled = qdf_get_ipa_smmu_enabled(); + + osdev->smmu_s1_enabled = ipa_smmu_enabled && wlan_smmu_enabled; + if (ipa_smmu_enabled != wlan_smmu_enabled) { + cds_err("SMMU mismatch; IPA:%s, WLAN:%s", + ipa_smmu_enabled ? "enabled" : "disabled", + wlan_smmu_enabled ? "enabled" : "disabled"); + return QDF_STATUS_E_FAILURE; + } + +exit_with_success: + osdev->domain = domain; + + cds_info("SMMU S1 %s", osdev->smmu_s1_enabled ? "enabled" : "disabled"); + + return QDF_STATUS_SUCCESS; +} + +#else +QDF_STATUS cds_smmu_mem_map_setup(qdf_device_t osdev, bool ipa_present) +{ + struct dma_iommu_mapping *mapping; + bool ipa_smmu_enabled; + bool wlan_smmu_enabled; + + mapping = pld_smmu_get_mapping(osdev->dev); + if (mapping) { + int attr = 0; + int errno = qdf_iommu_domain_get_attr(mapping->domain, + QDF_DOMAIN_ATTR_S1_BYPASS, + &attr); + + wlan_smmu_enabled = !errno && !attr; + } else { + cds_info("No SMMU mapping present"); + wlan_smmu_enabled = false; + } + + if (!wlan_smmu_enabled) { + osdev->smmu_s1_enabled = false; + goto exit_with_success; + } + + if (!ipa_present) { + osdev->smmu_s1_enabled = true; + goto exit_with_success; + } + + ipa_smmu_enabled = qdf_get_ipa_smmu_enabled(); + + osdev->smmu_s1_enabled = ipa_smmu_enabled && wlan_smmu_enabled; + if (ipa_smmu_enabled != wlan_smmu_enabled) { + cds_err("SMMU mismatch; IPA:%s, WLAN:%s", + ipa_smmu_enabled ? "enabled" : "disabled", + wlan_smmu_enabled ? "enabled" : "disabled"); + return QDF_STATUS_E_FAILURE; + } + +exit_with_success: + osdev->iommu_mapping = mapping; + + cds_info("SMMU S1 %s", osdev->smmu_s1_enabled ? "enabled" : "disabled"); + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef IPA_OFFLOAD +int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + return ucfg_ipa_uc_smmu_map(map, num_buf, buf_arr); +} +#else +int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + return 0; +} +#endif + +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +QDF_STATUS cds_smmu_mem_map_setup(qdf_device_t osdev, bool ipa_present) +{ + osdev->smmu_s1_enabled = false; + osdev->domain = NULL; + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS cds_smmu_mem_map_setup(qdf_device_t osdev, bool ipa_present) +{ + osdev->smmu_s1_enabled = false; + return QDF_STATUS_SUCCESS; +} +#endif + +int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr) +{ + return 0; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h new file mode 100644 index 0000000000..368eb7f6c7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_ieee80211_common_i.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2013-2017,2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef CDS_COMMON__IEEE80211_I_H_ +#define CDS_COMMON__IEEE80211_I_H_ + +/** + * enum ieee80211_phymode - not really a mode; there are really multiple PHY's + * @IEEE80211_MODE_AUTO: autoselect + * @IEEE80211_MODE_11A: 5GHz, OFDM + * @IEEE80211_MODE_11B: 2GHz, CCK + * @IEEE80211_MODE_11G: 2GHz, OFDM + * @IEEE80211_MODE_FH: 2GHz, GFSK + * @IEEE80211_MODE_TURBO_A: 5GHz, OFDM, 2x clock dynamic turbo + * @IEEE80211_MODE_TURBO_G: 2GHz, OFDM, 2x clock dynamic turbo + * @IEEE80211_MODE_11NA_HT20: 5Ghz, HT20 + * @IEEE80211_MODE_11NG_HT20: 2Ghz, HT20 + * @IEEE80211_MODE_11NA_HT40PLUS: 5Ghz, HT40 (ext ch +1) + * @IEEE80211_MODE_11NA_HT40MINUS: 5Ghz, HT40 (ext ch -1) + * @IEEE80211_MODE_11NG_HT40PLUS: 2Ghz, HT40 (ext ch +1) + * @IEEE80211_MODE_11NG_HT40MINUS: 2Ghz, HT40 (ext ch -1) + * @IEEE80211_MODE_11NG_HT40: 2Ghz, Auto HT40 + * @IEEE80211_MODE_11NA_HT40: 2Ghz, Auto HT40 + * @IEEE80211_MODE_11AC_VHT20: 5Ghz, VHT20 + * @IEEE80211_MODE_11AC_VHT40PLUS: 5Ghz, VHT40 (Ext ch +1) + * @IEEE80211_MODE_11AC_VHT40MINUS: 5Ghz VHT40 (Ext ch -1) + * @IEEE80211_MODE_11AC_VHT40: 5Ghz, VHT40 + * @IEEE80211_MODE_11AC_VHT80: 5Ghz, VHT80 + * @IEEE80211_MODE_2G_AUTO: 2G 11 b/g/n autoselect + * @IEEE80211_MODE_5G_AUTO: 5G 11 a/n/ac autoselect + * @IEEE80211_MODE_11AGN: Support 11N in both 2G and 5G + * @IEEE80211_MODE_11AX_HE20: HE20 + * @IEEE80211_MODE_11AX_HE40: HE40 + * @IEEE80211_MODE_11AX_HE40PLUS: HE40 (ext ch +1) + * @IEEE80211_MODE_11AX_HE40MINUS: HE40 (ext ch -1) + * @IEEE80211_MODE_11AX_HE80: HE80 + * @IEEE80211_MODE_11AX_HE80P80: HE 80P80 + * @IEEE80211_MODE_11AX_HE160: HE160 + * @IEEE80211_MODE_MAX: Maximum possible value + */ +enum ieee80211_phymode { + IEEE80211_MODE_AUTO = 0, + IEEE80211_MODE_11A = 1, + IEEE80211_MODE_11B = 2, + IEEE80211_MODE_11G = 3, + IEEE80211_MODE_FH = 4, + IEEE80211_MODE_TURBO_A = 5, + IEEE80211_MODE_TURBO_G = 6, + IEEE80211_MODE_11NA_HT20 = 7, + IEEE80211_MODE_11NG_HT20 = 8, + IEEE80211_MODE_11NA_HT40PLUS = 9, + IEEE80211_MODE_11NA_HT40MINUS = 10, + IEEE80211_MODE_11NG_HT40PLUS = 11, + IEEE80211_MODE_11NG_HT40MINUS = 12, + IEEE80211_MODE_11NG_HT40 = 13, + IEEE80211_MODE_11NA_HT40 = 14, + IEEE80211_MODE_11AC_VHT20 = 15, + IEEE80211_MODE_11AC_VHT40PLUS = 16, + IEEE80211_MODE_11AC_VHT40MINUS = 17, + IEEE80211_MODE_11AC_VHT40 = 18, + IEEE80211_MODE_11AC_VHT80 = 19, + IEEE80211_MODE_2G_AUTO = 20, + IEEE80211_MODE_5G_AUTO = 21, + IEEE80211_MODE_11AGN = 22, + IEEE80211_MODE_11AX_HE20 = 23, + IEEE80211_MODE_11AX_HE40 = 24, + IEEE80211_MODE_11AX_HE40PLUS = 25, + IEEE80211_MODE_11AX_HE40MINUS = 26, + IEEE80211_MODE_11AX_HE80 = 27, + IEEE80211_MODE_11AX_HE80P80 = 28, + IEEE80211_MODE_11AX_HE160 = 29, + + /* Do not add after this line */ + IEEE80211_MODE_MAX = IEEE80211_MODE_11AX_HE160, +}; + +/* + * 802.11g protection mode. + */ +enum ieee80211_protmode { + IEEE80211_PROT_NONE = 0, /* no protection */ + IEEE80211_PROT_CTSONLY = 1, /* CTS to self */ + IEEE80211_PROT_RTSCTS = 2, /* RTS-CTS */ +}; + +/* bits 0-3 are for private use by drivers */ +/* channel attributes */ +#define IEEE80211_CHAN_TURBO 0x00000010 /* Turbo channel */ +#define IEEE80211_CHAN_CCK 0x00000020 /* CCK channel */ +#define IEEE80211_CHAN_OFDM 0x00000040 /* OFDM channel */ +#define IEEE80211_CHAN_2GHZ 0x00000080 /* 2 GHz spectrum channel. */ +#define IEEE80211_CHAN_5GHZ 0x00000100 /* 5 GHz spectrum channel */ +#define IEEE80211_CHAN_PASSIVE 0x00000200 /* Only passive scan allowed */ +#define IEEE80211_CHAN_DYN 0x00000400 /* Dynamic CCK-OFDM channel */ +#define IEEE80211_CHAN_GFSK 0x00000800 /* GFSK channel (FHSS PHY) */ +#define IEEE80211_CHAN_RADAR_DFS 0x00001000 /* Radar found on channel */ +#define IEEE80211_CHAN_STURBO 0x00002000 /* 11a static turbo channel only */ +#define IEEE80211_CHAN_HALF 0x00004000 /* Half rate channel */ +#define IEEE80211_CHAN_QUARTER 0x00008000 /* Quarter rate channel */ +#define IEEE80211_CHAN_HT20 0x00010000 /* HT 20 channel */ +#define IEEE80211_CHAN_HT40PLUS 0x00020000 /* HT 40 with extension channel above */ +#define IEEE80211_CHAN_HT40MINUS 0x00040000 /* HT 40 with extension channel below */ +#define IEEE80211_CHAN_HT40INTOL 0x00080000 /* HT 40 Intolerant */ +#define IEEE80211_CHAN_VHT20 0x00100000 /* VHT 20 channel */ +#define IEEE80211_CHAN_VHT40PLUS 0x00200000 /* VHT 40 with extension channel above */ +#define IEEE80211_CHAN_VHT40MINUS 0x00400000 /* VHT 40 with extension channel below */ +#define IEEE80211_CHAN_VHT80 0x00800000 /* VHT 80 channel */ +/* channel temporarily blocked due to noise */ +#define IEEE80211_CHAN_BLOCKED 0x02000000 +/* VHT 160 channel */ +#define IEEE80211_CHAN_VHT160 0x04000000 +/* VHT 80_80 channel */ +#define IEEE80211_CHAN_VHT80_80 0x08000000 + +/* flagext */ +#define IEEE80211_CHAN_DFS 0x0002 /* DFS required on channel */ +/* DFS required on channel for 2nd band of 80+80*/ +#define IEEE80211_CHAN_DFS_CFREQ2 0x0004 + +#define IEEE80211_SEQ_MASK 0xfff /* sequence generator mask */ +#define MIN_SW_SEQ 0x100 /* minimum sequence for SW generate packect */ + +#endif /* CDS_COMMON__IEEE80211_I_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_packet.c b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_packet.c new file mode 100644 index 0000000000..4b0f14fffb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_packet.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014-2016, 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: cds_packet.c + * Connectivity driver services (CDS) network Packet APIs + * Network Protocol packet/buffer support interfaces + */ + +#include +#include +#include +#include +#include +#include "qdf_nbuf.h" +#include "qdf_mem.h" +#include "cds_utils.h" + +#define TX_PKT_MIN_HEADROOM (64) + +QDF_STATUS cds_pkt_return_packet(cds_pkt_t *packet) +{ + /* Validate the input parameter pointer */ + if (unlikely(!packet)) { + return QDF_STATUS_E_INVAL; + } + + /* Free up the qdf nbuf */ + qdf_nbuf_free(packet->pkt_buf); + + packet->pkt_buf = NULL; + + /* Free up the Rx packet */ + qdf_mem_free(packet); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cds_pkt_get_packet_length(cds_pkt_t *pPacket, uint16_t *pPacketSize) +{ + /* Validate the parameter pointers */ + if (unlikely((!pPacket) || (!pPacketSize)) || + (!pPacket->pkt_buf)) { + cds_alert("NULL pointer"); + return QDF_STATUS_E_INVAL; + } + /* return the requested information */ + *pPacketSize = qdf_nbuf_len(pPacket->pkt_buf); + return QDF_STATUS_SUCCESS; +} + +#ifdef MEMORY_DEBUG +QDF_STATUS cds_packet_alloc_debug(uint16_t size, void **data, void **ppPacket, + const char *func_name, uint32_t line_num) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + qdf_nbuf_t nbuf; + + nbuf = qdf_nbuf_alloc_debug(NULL, + roundup(size + TX_PKT_MIN_HEADROOM, 4), + TX_PKT_MIN_HEADROOM, sizeof(uint32_t), false, + func_name, line_num); + + if (nbuf) { + qdf_nbuf_put_tail(nbuf, size); + qdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = qdf_nbuf_data(nbuf); + qdf_ret_status = QDF_STATUS_SUCCESS; + } + + return qdf_ret_status; +} +#else +QDF_STATUS cds_packet_alloc(uint16_t size, void **data, void **ppPacket) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + qdf_nbuf_t nbuf; + + nbuf = qdf_nbuf_alloc(NULL, roundup(size + TX_PKT_MIN_HEADROOM, 4), + TX_PKT_MIN_HEADROOM, sizeof(uint32_t), false); + + if (nbuf) { + qdf_nbuf_put_tail(nbuf, size); + qdf_nbuf_set_protocol(nbuf, ETH_P_CONTROL); + *ppPacket = nbuf; + *data = qdf_nbuf_data(nbuf); + qdf_ret_status = QDF_STATUS_SUCCESS; + } + + return qdf_ret_status; +} + +#endif + +void cds_packet_free(void *pPacket) +{ + qdf_nbuf_free((qdf_nbuf_t) pPacket); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_reg_service.c b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_reg_service.c new file mode 100644 index 0000000000..ae77a24c45 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_reg_service.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*============================================================================ + FILE: cds_reg_service.c + OVERVIEW: This source file contains definitions for CDS regulatory APIs + DEPENDENCIES: None + ============================================================================*/ + +#include "qdf_types.h" +#include "qdf_trace.h" +#include +#include "wlan_reg_services_api.h" +#include "cds_reg_service.h" +#include "cds_ieee80211_common_i.h" +#include "cds_config.h" +#include "cds_utils.h" +#include "wlan_reg_services_api.h" + +uint32_t cds_get_vendor_reg_flags(struct wlan_objmgr_pdev *pdev, + qdf_freq_t freq, uint16_t bandwidth, + bool is_ht_enabled, bool is_vht_enabled, + uint8_t sub_20_channel_width) +{ + uint32_t flags = 0; + enum channel_state state; + struct ch_params ch_params; + qdf_freq_t sec_freq; + + state = wlan_reg_get_channel_state_for_pwrmode(pdev, freq, + REG_CURRENT_PWR_MODE); + if (state == CHANNEL_STATE_INVALID) + return flags; + if (state == CHANNEL_STATE_DFS) { + flags |= IEEE80211_CHAN_PASSIVE; + } + if (state == CHANNEL_STATE_DISABLE) + flags |= IEEE80211_CHAN_BLOCKED; + + if (wlan_reg_is_24ghz_ch_freq(freq)) { + if ((bandwidth == CH_WIDTH_80P80MHZ) || + (bandwidth == CH_WIDTH_160MHZ) || + (bandwidth == CH_WIDTH_80MHZ)) { + bandwidth = CH_WIDTH_40MHZ; + } + flags |= IEEE80211_CHAN_2GHZ; + } else + flags |= IEEE80211_CHAN_5GHZ; + qdf_mem_zero(&ch_params, sizeof(ch_params)); + + switch (bandwidth) { + case CH_WIDTH_80P80MHZ: + ch_params.ch_width = bandwidth; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq, + &ch_params, REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT80_80; + } + bandwidth = CH_WIDTH_160MHZ; + fallthrough; + case CH_WIDTH_160MHZ: + ch_params.ch_width = bandwidth; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq, + &ch_params, REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT160; + } + bandwidth = CH_WIDTH_80MHZ; + fallthrough; + case CH_WIDTH_80MHZ: + ch_params.ch_width = bandwidth; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + pdev, freq, + &ch_params, REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT80; + } + bandwidth = CH_WIDTH_40MHZ; + fallthrough; + case CH_WIDTH_40MHZ: + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = bandwidth; + wlan_reg_set_channel_params_for_pwrmode(pdev, freq, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + + if (ch_params.sec_ch_offset == LOW_PRIMARY_CH) + sec_freq = freq + 20; + else if (ch_params.sec_ch_offset == HIGH_PRIMARY_CH) + sec_freq = freq - 20; + else + sec_freq = 0; + + if (wlan_reg_get_bonded_channel_state_for_pwrmode( + pdev, freq, + bandwidth, sec_freq, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID) { + if (ch_params.sec_ch_offset == LOW_PRIMARY_CH) { + flags |= IEEE80211_CHAN_HT40PLUS; + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT40PLUS; + } else if (ch_params.sec_ch_offset == + HIGH_PRIMARY_CH) { + flags |= IEEE80211_CHAN_HT40MINUS; + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT40MINUS; + } + } + bandwidth = CH_WIDTH_20MHZ; + fallthrough; + case CH_WIDTH_20MHZ: + if (is_vht_enabled) + flags |= IEEE80211_CHAN_VHT20; + if (is_ht_enabled) + flags |= IEEE80211_CHAN_HT20; + bandwidth = CH_WIDTH_10MHZ; + fallthrough; + case CH_WIDTH_10MHZ: + if (wlan_reg_get_bonded_channel_state_for_pwrmode( + pdev, freq, + bandwidth, 0, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID && + sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_10) + flags |= IEEE80211_CHAN_HALF; + bandwidth = CH_WIDTH_5MHZ; + fallthrough; + case CH_WIDTH_5MHZ: + if (wlan_reg_get_bonded_channel_state_for_pwrmode( + pdev, freq, + bandwidth, 0, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_INVALID && + sub_20_channel_width == WLAN_SUB_20_CH_WIDTH_5) + flags |= IEEE80211_CHAN_QUARTER; + break; + default: + cds_info("invalid channel width value %d", bandwidth); + } + + return flags; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_regdomain.c b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_regdomain.c new file mode 100644 index 0000000000..737c94caf0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_regdomain.c @@ -0,0 +1,712 @@ +/* + * Copyright (c) 2011,2013-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Notifications and licenses are retained for attribution purposes only. + */ +/* + * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2005-2006 Atheros Communications, Inc. + * Copyright (c) 2010, Atheros Communications Inc. + * + * Redistribution and use in source and binary forms are permitted + * provided that the following conditions are met: + * 1. The materials contained herein are unmodified and are used + * unmodified. + * 2. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following NO + * ''WARRANTY'' disclaimer below (''Disclaimer''), without + * modification. + * 3. Redistributions in binary form must reproduce at minimum a + * disclaimer similar to the Disclaimer below and any redistribution + * must be conditioned upon including a substantially similar + * Disclaimer requirement for further binary redistribution. + * 4. Neither the names of the above-listed copyright holders nor the + * names of any contributors may be used to endorse or promote + * product derived from this software without specific prior written + * permission. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, + * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE + * FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#include "qdf_types.h" +#include "wma.h" +#include "cds_regdomain.h" + + +static const struct reg_dmn_pair g_reg_dmn_pairs[] = { + {NO_ENUMRD, FCC8, FCCA, CTRY_DEFAULT}, + {NULL1_WORLD, NULL1, WORLD, CTRY_DEFAULT}, + {FCC1_FCCA, FCC1, FCCA, CTRY_DEFAULT}, + {FCC1_WORLD, FCC1, WORLD, CTRY_DEFAULT}, + {FCC2_WORLD, FCC2, WORLD, CTRY_DEFAULT}, + {FCC2_ETSIC, FCC2, ETSIC, CTRY_DEFAULT}, + {FCC2_FCCA, FCC2, FCCA, CTRY_DEFAULT}, + {FCC3_FCCA, FCC3, FCCA, CTRY_DEFAULT}, + {FCC3_WORLD, FCC3, WORLD, CTRY_DEFAULT}, + {FCC3_ETSIC, FCC3, ETSIC, CTRY_DEFAULT}, + {FCC4_FCCA, FCC4, FCCA, CTRY_DEFAULT}, + {FCC5_FCCA, FCC5, FCCA, CTRY_DEFAULT}, + {FCC6_FCCA, FCC6, FCCA, CTRY_DEFAULT}, + {FCC7_FCCA, FCC7, FCCA, CTRY_DEFAULT}, + {FCC8_FCCA, FCC8, FCCA, CTRY_DEFAULT}, + {FCC6_WORLD, FCC6, WORLD, CTRY_DEFAULT}, + {FCC9_FCCA, FCC9, FCCA, CTRY_DEFAULT}, + {FCC10_FCCA, FCC10, FCCA, CTRY_DEFAULT}, + {FCC11_WORLD, FCC11, WORLD, CTRY_DEFAULT}, + {FCC13_WORLD, FCC13, WORLD, CTRY_DEFAULT}, + {FCC14_FCCB, FCC14, FCCB, CTRY_DEFAULT}, + {ETSI1_WORLD, ETSI1, WORLD, CTRY_DEFAULT}, + {ETSI3_WORLD, ETSI3, WORLD, CTRY_DEFAULT}, + {ETSI4_WORLD, ETSI4, WORLD, CTRY_DEFAULT}, + {ETSI7_WORLD, ETSI4, WORLD, CTRY_DEFAULT}, + {ETSI8_WORLD, ETSI8, WORLD, CTRY_DEFAULT}, + {ETSI9_WORLD, ETSI9, WORLD, CTRY_DEFAULT}, + {APL4_WORLD, APL4, WORLD, CTRY_DEFAULT}, + {APL2_WORLD, APL2, WORLD, CTRY_DEFAULT}, + {APL2_FCCA, APL2, FCCA, CTRY_DEFAULT}, + {APL2_ETSIC, APL2, ETSIC, CTRY_DEFAULT}, + {APL1_WORLD, APL1, WORLD, CTRY_DEFAULT}, + {APL1_ETSIC, APL1, ETSIC, CTRY_DEFAULT}, + {APL6_WORLD, APL6, WORLD, CTRY_DEFAULT}, + {APL7_FCCA, APL7, FCCA, CTRY_DEFAULT}, + {APL8_WORLD, APL8, WORLD, CTRY_DEFAULT}, + {APL9_WORLD, APL9, WORLD, CTRY_DEFAULT}, + {APL10_WORLD, APL10, WORLD, CTRY_DEFAULT}, + {APL12_WORLD, APL12, WORLD, CTRY_DEFAULT}, + {APL13_WORLD, APL13, WORLD, CTRY_DEFAULT}, + {APL14_WORLD, APL14, WORLD, CTRY_DEFAULT}, + {APL15_WORLD, APL15, WORLD, CTRY_DEFAULT}, + {APL16_WORLD, APL16, WORLD, CTRY_DEFAULT}, + {APL17_ETSID, APL17, WORLD, CTRY_DEFAULT}, + {APL20_WORLD, APL20, WORLD, CTRY_DEFAULT}, + {APL23_WORLD, APL23, WORLD, CTRY_DEFAULT}, + {WOR0_WORLD, WOR0_WORLD, WOR0_WORLD, CTRY_DEFAULT}, + {WOR1_WORLD, WOR1_WORLD, WOR1_WORLD, CTRY_DEFAULT}, + {WOR2_WORLD, WOR2_WORLD, WOR2_WORLD, CTRY_DEFAULT}, + {WOR3_WORLD, WOR3_WORLD, WOR3_WORLD, CTRY_DEFAULT}, + {WOR4_FCCA, WOR4_FCCA, WOR4_FCCA, CTRY_DEFAULT}, + {WOR5_ETSIC, WOR5_ETSIC, WOR5_ETSIC, CTRY_DEFAULT}, + {WOR01_WORLD, WOR01_WORLD, WOR01_WORLD, CTRY_DEFAULT}, + {WOR02_WORLD, WOR02_WORLD, WOR02_WORLD, CTRY_DEFAULT}, + {EU1_WORLD, EU1_WORLD, EU1_WORLD, CTRY_DEFAULT}, + {WOR9_WORLD, WOR9_WORLD, WOR9_WORLD, CTRY_DEFAULT}, + {WORA_WORLD, WORA_WORLD, WORA_WORLD, CTRY_DEFAULT}, + {WORB_WORLD, WORB_WORLD, WORB_WORLD, CTRY_DEFAULT}, + {WORC_WORLD, WORC_WORLD, WORC_WORLD, CTRY_DEFAULT}, + {MKK5_MKKC, MKK5, MKKC, CTRY_JAPAN15}, + {MKK5_MKKA2, MKK5, MKKA, CTRY_DEFAULT}, +}; + +static const struct country_code_to_reg_dmn g_all_countries[] = { + {CTRY_AFGHANISTAN, ETSI1_WORLD, "AF", "AFGHANISTAN"}, + {CTRY_ALBANIA, ETSI1_WORLD, "AL", "ALBANIA"}, + {CTRY_ALGERIA, APL13_WORLD, "DZ", "ALGERIA"}, + {CTRY_AMERICAN_SAMOA, FCC3_FCCA, "AS", "AMERICAN SAMOA"}, + {CTRY_ANGUILLA, ETSI1_WORLD, "AI", "ANGUILLA"}, + {CTRY_ARGENTINA, APL17_ETSID, "AR", "ARGENTINA"}, + {CTRY_ARMENIA, ETSI4_WORLD, "AM", "ARMENIA"}, + {CTRY_ARUBA, ETSI1_WORLD, "AW", "ARUBA"}, + {CTRY_AUSTRALIA, FCC6_WORLD, "AU", "AUSTRALIA"}, + {CTRY_AUSTRIA, ETSI1_WORLD, "AT", "AUSTRIA"}, + {CTRY_AZERBAIJAN, ETSI4_WORLD, "AZ", "AZERBAIJAN"}, + {CTRY_BAHAMAS, FCC3_WORLD, "BS", "BAHAMAS"}, + {CTRY_BAHRAIN, APL15_WORLD, "BH", "BAHRAIN"}, + {CTRY_BANGLADESH, APL1_WORLD, "BD", "BANGLADESH"}, + {CTRY_BARBADOS, FCC2_WORLD, "BB", "BARBADOS"}, + {CTRY_BELARUS, ETSI1_WORLD, "BY", "BELARUS"}, + {CTRY_BELGIUM, ETSI1_WORLD, "BE", "BELGIUM"}, + {CTRY_BELIZE, ETSI8_WORLD, "BZ", "BELIZE"}, + {CTRY_BERMUDA, FCC3_FCCA, "BM", "BERMUDA"}, + {CTRY_BHUTAN, ETSI1_WORLD, "BT", "BHUTAN"}, + {CTRY_BOLIVIA, APL8_WORLD, "BO", "BOLIVIA"}, + {CTRY_BOSNIA_HERZ, ETSI1_WORLD, "BA", "BOSNIA AND HERZEGOVINA"}, + {CTRY_BRAZIL, FCC3_ETSIC, "BR", "BRAZIL"}, + {CTRY_BRUNEI_DARUSSALAM, APL6_WORLD, "BN", "BRUNEI DARUSSALAM"}, + {CTRY_BULGARIA, ETSI1_WORLD, "BG", "BULGARIA"}, + {CTRY_BURKINA_FASO, FCC3_WORLD, "BF", "BURKINA-FASO"}, + {CTRY_CAMBODIA, ETSI1_WORLD, "KH", "CAMBODIA"}, + {CTRY_CANADA, FCC3_FCCA, "CA", "CANADA"}, + {CTRY_CAYMAN_ISLANDS, FCC3_WORLD, "KY", "CAYMAN ISLANDS"}, + {CTRY_CENTRAL_AFRICA_REPUBLIC, FCC3_WORLD, "CF", "AFRICA REPUBLIC"}, + {CTRY_CHAD, ETSI1_WORLD, "TD", "CHAD"}, + {CTRY_CHILE, APL23_WORLD, "CL", "CHILE"}, + {CTRY_CHINA, APL14_WORLD, "CN", "CHINA"}, + {CTRY_CHRISTMAS_ISLAND, FCC3_WORLD, "CX", "CHRISTMAS ISLAND"}, + {CTRY_COLOMBIA, FCC3_WORLD, "CO", "COLOMBIA"}, + {CTRY_COSTA_RICA, FCC3_WORLD, "CR", "COSTA RICA"}, + {CTRY_COTE_DIVOIRE, FCC3_WORLD, "CI", "COTE DIVOIRE"}, + {CTRY_CROATIA, ETSI1_WORLD, "HR", "CROATIA"}, + {CTRY_CYPRUS, ETSI1_WORLD, "CY", "CYPRUS"}, + {CTRY_CZECH, ETSI1_WORLD, "CZ", "CZECH REPUBLIC"}, + {CTRY_DENMARK, ETSI1_WORLD, "DK", "DENMARK"}, + {CTRY_DOMINICA, FCC2_FCCA, "DM", "DOMINICA"}, + {CTRY_DOMINICAN_REPUBLIC, FCC2_FCCA, "DO", "DOMINICAN REPUBLIC"}, + {CTRY_ECUADOR, FCC3_WORLD, "EC", "ECUADOR"}, + {CTRY_EGYPT, ETSI3_WORLD, "EG", "EGYPT"}, + {CTRY_EL_SALVADOR, FCC2_WORLD, "SV", "EL SALVADOR"}, + {CTRY_ESTONIA, ETSI1_WORLD, "EE", "ESTONIA"}, + {CTRY_ETHIOPIA, ETSI1_WORLD, "ET", "ETHIOPIA"}, + {CTRY_FINLAND, ETSI1_WORLD, "FI", "FINLAND"}, + {CTRY_FRANCE, ETSI1_WORLD, "FR", "FRANCE"}, + {CTRY_FRENCH_GUIANA, ETSI1_WORLD, "GF", "FRENCH GUIANA"}, + {CTRY_FRENCH_POLYNESIA, ETSI1_WORLD, "PF", "FRENCH POLYNESIA"}, + {CTRY_GEORGIA, ETSI4_WORLD, "GE", "GEORGIA"}, + {CTRY_GERMANY, ETSI1_WORLD, "DE", "GERMANY"}, + {CTRY_GHANA, FCC3_WORLD, "GH", "GHANA"}, + {CTRY_GIBRALTAR, ETSI1_WORLD, "GI", "GIBRALTAR"}, + {CTRY_GREECE, ETSI1_WORLD, "GR", "GREECE"}, + {CTRY_GREENLAND, ETSI1_WORLD, "GL", "GREENLAND"}, + {CTRY_GRENADA, FCC3_FCCA, "GD", "GRENADA"}, + {CTRY_GUADELOUPE, ETSI1_WORLD, "GP", "GUADELOUPE"}, + {CTRY_GUAM, FCC3_FCCA, "GU", "GUAM"}, + {CTRY_GUATEMALA, ETSI1_WORLD, "GT", "GUATEMALA"}, + {CTRY_GUYANA, APL1_ETSIC, "GY", "GUYANA"}, + {CTRY_HAITI, FCC3_FCCA, "HT", "HAITI"}, + {CTRY_HONDURAS, FCC13_WORLD, "HN", "HONDURAS"}, + {CTRY_HONG_KONG, FCC3_WORLD, "HK", "HONG KONG"}, + {CTRY_HUNGARY, ETSI1_WORLD, "HU", "HUNGARY"}, + {CTRY_ICELAND, ETSI1_WORLD, "IS", "ICELAND"}, + {CTRY_INDIA, APL15_WORLD, "IN", "INDIA"}, + {CTRY_INDONESIA, APL2_ETSIC, "ID", "INDONESIA"}, + {CTRY_IRAQ, ETSI1_WORLD, "IQ", "IRAQ"}, + {CTRY_IRELAND, ETSI1_WORLD, "IE", "IRELAND"}, + {CTRY_ISRAEL, ETSI3_WORLD, "IL", "ISRAEL"}, + {CTRY_ITALY, ETSI1_WORLD, "IT", "ITALY"}, + {CTRY_JAMAICA, FCC13_WORLD, "JM", "JAMAICA"}, + {CTRY_JORDAN, APL4_WORLD, "JO", "JORDAN"}, + {CTRY_KAZAKHSTAN, NULL1_WORLD, "KZ", "KAZAKHSTAN"}, + {CTRY_KENYA, APL12_WORLD, "KE", "KENYA"}, + {CTRY_KOREA_ROC, APL9_WORLD, "KR", "KOREA REPUBLIC"}, + {CTRY_KUWAIT, ETSI3_WORLD, "KW", "KUWAIT"}, + {CTRY_LATVIA, ETSI1_WORLD, "LV", "LATVIA"}, + {CTRY_LEBANON, FCC3_WORLD, "LB", "LEBANON"}, + {CTRY_LESOTHO, ETSI1_WORLD, "LS", "LESOTHO"}, + {CTRY_LIECHTENSTEIN, ETSI1_WORLD, "LI", "LIECHTENSTEIN"}, + {CTRY_LITHUANIA, ETSI1_WORLD, "LT", "LITHUANIA"}, + {CTRY_LUXEMBOURG, ETSI1_WORLD, "LU", "LUXEMBOURG"}, + {CTRY_MACAU, FCC3_WORLD, "MO", "MACAU SAR"}, + {CTRY_MACEDONIA, ETSI1_WORLD, "MK", "MACEDONIA, FYRO"}, + {CTRY_MALAWI, ETSI1_WORLD, "MW", "MALAWI"}, + {CTRY_MALAYSIA, FCC11_WORLD, "MY", "MALAYSIA"}, + {CTRY_MALDIVES, APL6_WORLD, "MV", "MALDIVES"}, + {CTRY_MALTA, ETSI1_WORLD, "MT", "MALTA"}, + {CTRY_MARSHALL_ISLANDS, FCC3_FCCA, "MH", "MARSHALL ISLANDS"}, + {CTRY_MARTINIQUE, ETSI1_WORLD, "MQ", "MARTINIQUE"}, + {CTRY_MAURITANIA, ETSI1_WORLD, "MR", "MAURITANA"}, + {CTRY_MAURITIUS, FCC3_WORLD, "MU", "MAURITIUS"}, + {CTRY_MAYOTTE, ETSI1_WORLD, "YT", "MAYOTTE"}, + {CTRY_MEXICO, FCC3_ETSIC, "MX", "MEXICO"}, + {CTRY_MICRONESIA, FCC3_FCCA, "FM", "MICRONESIA"}, + {CTRY_MOLDOVA, ETSI1_WORLD, "MD", "MOLDOVA"}, + {CTRY_MONACO, ETSI1_WORLD, "MC", "MONACO"}, + {CTRY_MONGOLIA, FCC3_WORLD, "MN", "MONGOLIA"}, + {CTRY_MONTENEGRO, ETSI1_WORLD, "ME", "MONTENEGRO"}, + {CTRY_MOROCCO, ETSI3_WORLD, "MA", "MOROCCO"}, + {CTRY_NAMIBIA, APL20_WORLD, "NA", "NAMIBIA"}, + {CTRY_NEPAL, APL23_WORLD, "NP", "NEPAL"}, + {CTRY_NETHERLANDS, ETSI1_WORLD, "NL", "NETHERLANDS"}, + {CTRY_NETHERLANDS_ANTILLES, ETSI1_WORLD, "AN", "NETHERLANDS ANTILLES"}, + {CTRY_NEW_ZEALAND, FCC3_ETSIC, "NZ", "NEW ZEALAND"}, + {CTRY_NIGERIA, APL8_WORLD, "NG", "NIGERIA"}, + {CTRY_NORTHERN_MARIANA_ISLANDS, FCC3_FCCA, "MP", "MARIANA ISLANDS"}, + {CTRY_NICARAGUA, FCC3_FCCA, "NI", "NICARAGUA"}, + {CTRY_NORWAY, ETSI1_WORLD, "NO", "NORWAY"}, + {CTRY_OMAN, ETSI1_WORLD, "OM", "OMAN"}, + {CTRY_PAKISTAN, APL1_ETSIC, "PK", "PAKISTAN"}, + {CTRY_PALAU, FCC3_FCCA, "PW", "PALAU"}, + {CTRY_PANAMA, FCC14_FCCB, "PA", "PANAMA"}, + {CTRY_PAPUA_NEW_GUINEA, FCC3_WORLD, "PG", "PAPUA NEW GUINEA"}, + {CTRY_PARAGUAY, FCC3_WORLD, "PY", "PARAGUAY"}, + {CTRY_PERU, FCC3_WORLD, "PE", "PERU"}, + {CTRY_PHILIPPINES, FCC3_WORLD, "PH", "PHILIPPINES"}, + {CTRY_POLAND, ETSI1_WORLD, "PL", "POLAND"}, + {CTRY_PORTUGAL, ETSI1_WORLD, "PT", "PORTUGAL"}, + {CTRY_PUERTO_RICO, FCC3_FCCA, "PR", "PUERTO RICO"}, + {CTRY_QATAR, APL1_WORLD, "QA", "QATAR"}, + {CTRY_REUNION, ETSI1_WORLD, "RE", "REUNION"}, + {CTRY_ROMANIA, ETSI1_WORLD, "RO", "ROMANIA"}, + {CTRY_RUSSIA, ETSI8_WORLD, "RU", "RUSSIA"}, + {CTRY_RWANDA, FCC3_WORLD, "RW", "RWANDA"}, + {CTRY_SAINT_BARTHELEMY, ETSI1_WORLD, "BL", "SAINT BARTHELEMY"}, + {CTRY_SAINT_KITTS_AND_NEVIS, APL10_WORLD, "KN", "SAINT KITTS"}, + {CTRY_SAINT_LUCIA, APL10_WORLD, "LC", "SAINT LUCIA"}, + {CTRY_SAINT_MARTIN, ETSI1_WORLD, "MF", "SAINT MARTIN"}, + {CTRY_SAINT_PIERRE_AND_MIQUELON, ETSI1_WORLD, "PM", "SAINT PIERRE"}, + {CTRY_SAINT_VINCENT_AND_THE_GRENADIENS, ETSI1_WORLD, "VC", "VINCENT"}, + {CTRY_SAMOA, ETSI1_WORLD, "WS", "SAMOA"}, + {CTRY_SAUDI_ARABIA, ETSI1_WORLD, "SA", "SAUDI ARABIA"}, + {CTRY_SENEGAL, FCC13_WORLD, "SN", "SENEGAL"}, + {CTRY_SERBIA, ETSI1_WORLD, "RS", "REPUBLIC OF SERBIA"}, + {CTRY_SINGAPORE, FCC3_WORLD, "SG", "SINGAPORE"}, + {CTRY_SLOVAKIA, ETSI1_WORLD, "SK", "SLOVAKIA"}, + {CTRY_SLOVENIA, ETSI1_WORLD, "SI", "SLOVENIA"}, + {CTRY_SOUTH_AFRICA, FCC3_WORLD, "ZA", "SOUTH AFRICA"}, + {CTRY_SPAIN, ETSI1_WORLD, "ES", "SPAIN"}, + {CTRY_SURINAME, ETSI1_WORLD, "SR", "SURINAME"}, + {CTRY_SRI_LANKA, FCC3_WORLD, "LK", "SRI LANKA"}, + {CTRY_SWEDEN, ETSI1_WORLD, "SE", "SWEDEN"}, + {CTRY_SWITZERLAND, ETSI1_WORLD, "CH", "SWITZERLAND"}, + {CTRY_TAIWAN, FCC3_FCCA, "TW", "TAIWAN"}, + {CTRY_TANZANIA, APL1_WORLD, "TZ", "TANZANIA"}, + {CTRY_THAILAND, FCC3_WORLD, "TH", "THAILAND"}, + {CTRY_TOGO, ETSI1_WORLD, "TG", "TOGO"}, + {CTRY_TRINIDAD_Y_TOBAGO, FCC3_WORLD, "TT", "TRINIDAD AND TOBAGO"}, + {CTRY_TUNISIA, ETSI3_WORLD, "TN", "TUNISIA"}, + {CTRY_TURKEY, ETSI1_WORLD, "TR", "TURKEY"}, + {CTRY_TURKS_AND_CAICOS, FCC3_WORLD, "TC" "TURKS AND CAICOS"}, + {CTRY_UGANDA, FCC3_WORLD, "UG", "UGANDA"}, + {CTRY_UKRAINE, ETSI9_WORLD, "UA", "UKRAINE"}, + {CTRY_UAE, FCC3_WORLD, "AE", "UNITED ARAB EMIRATES"}, + {CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB", "UNITED KINGDOM"}, + {CTRY_UNITED_STATES, FCC8_FCCA, "US", "UNITED STATES"}, + {CTRY_URUGUAY, FCC2_WORLD, "UY", "URUGUAY"}, + {CTRY_UZBEKISTAN, ETSI3_WORLD, "UZ", "UZBEKISTAN"}, + {CTRY_VANUATU, FCC3_WORLD, "VU", "VANUATU"}, + {CTRY_VENEZUELA, FCC2_ETSIC, "VE", "VENEZUELA"}, + {CTRY_VIET_NAM, FCC3_WORLD, "VN", "VIETNAM"}, + {CTRY_VIRGIN_ISLANDS, FCC3_FCCA, "VI", "VIRGIN ISLANDS"}, + {CTRY_WALLIS_AND_FUTUNA, ETSI1_WORLD, "WF" "WALLIS"}, + {CTRY_YEMEN, NULL1_WORLD, "YE", "YEMEN"}, + {CTRY_ZIMBABWE, ETSI1_WORLD, "ZW", "ZIMBABWE"}, + {CTRY_JAPAN15, MKK5_MKKC, "JP", "JAPAN"}, + {CTRY_XA, MKK5_MKKA2, "XA", "JAPAN PASSIVE"} +}; + +static const struct reg_dmn g_reg_dmns[] = { + {FCC1, CTL_FCC}, + {FCC2, CTL_FCC}, + {FCC3, CTL_FCC}, + {FCC4, CTL_FCC}, + {FCC5, CTL_FCC}, + {FCC6, CTL_FCC}, + {FCC7, CTL_FCC}, + {FCC8, CTL_FCC}, + {FCC9, CTL_FCC}, + {FCC10, CTL_FCC}, + {FCC11, CTL_FCC}, + {FCC13, CTL_FCC}, + {FCC14, CTL_FCC}, + {ETSI1, CTL_ETSI}, + {ETSI2, CTL_ETSI}, + {ETSI3, CTL_ETSI}, + {ETSI4, CTL_ETSI}, + {ETSI5, CTL_ETSI}, + {ETSI6, CTL_ETSI}, + {ETSI8, CTL_ETSI}, + {ETSI9, CTL_ETSI}, + {ETSI10, CTL_ETSI}, + {ETSI11, CTL_ETSI}, + {APL1, CTL_ETSI}, + {APL2, CTL_ETSI}, + {APL3, CTL_ETSI}, + {APL4, CTL_ETSI}, + {APL5, CTL_ETSI}, + {APL6, CTL_ETSI}, + {APL7, CTL_ETSI}, + {APL8, CTL_ETSI}, + {APL9, CTL_ETSI}, + {APL10, CTL_ETSI}, + {APL11, CTL_ETSI}, + {APL12, CTL_ETSI}, + {APL13, CTL_ETSI}, + {APL14, CTL_FCC}, + {APL15, CTL_FCC}, + {APL16, CTL_FCC}, + {APL17, CTL_FCC}, + {APL20, CTL_ETSI}, + {APL23, CTL_ETSI}, + {NULL1, CTL_NONE}, + {MKK3, CTL_MKK}, + {MKK5, CTL_MKK}, + {MKK11, CTL_MKK}, + {WORLD, CTL_ETSI}, + {FCCA, CTL_FCC}, + {MKKA, CTL_MKK}, + {MKKC, CTL_MKK}, + {ETSIC, CTL_ETSI}, + {WOR0_WORLD, CTL_NONE}, + {WOR1_WORLD, CTL_NONE}, + {WOR2_WORLD, CTL_NONE}, + {WOR3_WORLD, CTL_NONE}, + {WOR4_FCCA, CTL_NONE}, + {WOR5_ETSIC, CTL_NONE}, + {WOR01_WORLD, CTL_NONE}, + {WOR02_WORLD, CTL_NONE}, + {EU1_WORLD, CTL_NONE}, + {WOR9_WORLD, CTL_NONE}, + {WORA_WORLD, CTL_NONE}, + {WORB_WORLD, CTL_NONE}, + {WORC_WORLD, CTL_NONE}, +}; + + +struct reg_dmn_tables g_reg_dmn_tbl = { + g_reg_dmn_pairs, + g_all_countries, + g_reg_dmns, + QDF_ARRAY_SIZE(g_reg_dmn_pairs), + QDF_ARRAY_SIZE(g_all_countries), + QDF_ARRAY_SIZE(g_reg_dmns), +}; + +/* + * ETSI is updating EN 301 893, which specifies 5 GHz channel access + * in Europe + */ +static const char etsi_europe_country[][2] = { + {'A', 'T'}, + {'B', 'E'}, + {'B', 'G'}, + {'C', 'Z'}, + {'D', 'K'}, + {'E', 'E'}, + {'F', 'R'}, + + {'D', 'E'}, + {'I', 'S'}, + {'I', 'E'}, + {'I', 'T'}, + {'E', 'L'}, + {'E', 'S'}, + {'C', 'Y'}, + + {'L', 'V'}, + {'L', 'I'}, + {'L', 'T'}, + {'L', 'U'}, + {'H', 'U'}, + {'M', 'T'}, + {'N', 'L'}, + + {'N', 'O'}, + {'P', 'L'}, + {'P', 'T'}, + {'R', 'O'}, + {'S', 'I'}, + {'S', 'K'}, + {'T', 'R'}, + + {'F', 'I'}, + {'S', 'E'}, + {'C', 'H'}, + {'U', 'K'}, + {'H', 'R'}, +}; + +bool cds_is_etsi_europe_country(uint8_t *country) +{ + int32_t i; + + for (i = 0; i < QDF_ARRAY_SIZE(etsi_europe_country); i++) { + if (country[0] == etsi_europe_country[i][0] && + country[1] == etsi_europe_country[i][1]) + return true; + } + + return false; +} + +/** + * get_bdf_reg_dmn() - get regulatory domain from BDF + * @reg_dmn: BDF regulatory domain + * + * Return: regulatory domain + */ +static uint16_t get_bdf_reg_dmn(uint16_t reg_dmn) +{ + return reg_dmn & ~WORLD_ROAMING_FLAG; +} + +/** + * is_reg_dmn_valid() - is regulatory domain valid + * @reg_dmn: regulatory domain + * + * Return: true or false + */ +static bool is_reg_dmn_valid(uint16_t reg_dmn) +{ + int32_t i; + + if (reg_dmn & CTRY_FLAG) { + uint16_t cc = reg_dmn & ~CTRY_FLAG; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) + if (g_reg_dmn_tbl.all_countries[i].country_code == cc) + return true; + } else { + for (i = 0; i < g_reg_dmn_tbl.reg_dmn_pairs_cnt; i++) + if (g_reg_dmn_tbl.reg_dmn_pairs[i].reg_dmn_pair + == reg_dmn) + return true; + } + + cds_err("invalid regulatory domain/country code 0x%x", reg_dmn); + + return false; +} + +/** + * find_country() - find country data + * @country_code: country code + * + * Return: country code data pointer + */ +static const struct country_code_to_reg_dmn *find_country(uint16_t country_code) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) { + if (g_reg_dmn_tbl.all_countries[i].country_code == country_code) + return &g_reg_dmn_tbl.all_countries[i]; + } + + return NULL; +} + +/** + * cds_get_country_from_alpha2() - get country from alpha2 + * @alpha2: country code alpha2 + * + * Return: country code + */ +int32_t cds_get_country_from_alpha2(uint8_t *alpha2) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) { + if (g_reg_dmn_tbl.all_countries[i].alpha2[0] == alpha2[0] && + g_reg_dmn_tbl.all_countries[i].alpha2[1] == alpha2[1]) + return g_reg_dmn_tbl.all_countries[i].country_code; + } + + return CTRY_DEFAULT; +} + +/** + * reg_dmn_get_default_country() - get default country for regulatory domain + * @reg_dmn: regulatory domain + * + * Return: default country + */ +static uint16_t reg_dmn_get_default_country(uint16_t reg_dmn) +{ + int32_t i; + const struct country_code_to_reg_dmn *country = NULL; + uint16_t cc = reg_dmn & ~CTRY_FLAG; + + if (reg_dmn & CTRY_FLAG) { + country = find_country(cc); + if (country) + return cc; + } + + for (i = 0; i < g_reg_dmn_tbl.reg_dmn_pairs_cnt; i++) { + if (g_reg_dmn_tbl.reg_dmn_pairs[i].reg_dmn_pair == reg_dmn) { + if (g_reg_dmn_tbl.reg_dmn_pairs[i].single_cc != 0) + return g_reg_dmn_tbl.reg_dmn_pairs[i].single_cc; + else + i = g_reg_dmn_tbl.reg_dmn_pairs_cnt; + } + } + + return CTRY_DEFAULT; +} + +/** + * get_reg_dmn_pair() - get regulatory domain pair pointer + * @reg_dmn: regulatory domain + * + * Return: pointer to regulatory domain pair data + */ +static const struct reg_dmn_pair *get_reg_dmn_pair(uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.reg_dmn_pairs_cnt; i++) { + if (g_reg_dmn_tbl.reg_dmn_pairs[i].reg_dmn_pair == reg_dmn) + return &g_reg_dmn_tbl.reg_dmn_pairs[i]; + } + + return NULL; +} + +/** + * get_reg_dmn() - get regulatory domain pointer + * @reg_dmn: regulatory domain + * + * Return: pointer to regulatory domain data + */ +static const struct reg_dmn *get_reg_dmn(uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.reg_dmns_cnt; i++) { + if (g_reg_dmn_tbl.reg_dmns[i].reg_dmn == reg_dmn) + return &g_reg_dmn_tbl.reg_dmns[i]; + } + + return NULL; +} + +/** + * get_country_from_rd() - get country from regulatory domain + * @reg_dmn: regulatory domain + * + * Return: country code enum + */ +static const struct country_code_to_reg_dmn *get_country_from_rd( + uint16_t reg_dmn) +{ + int32_t i; + + for (i = 0; i < g_reg_dmn_tbl.all_countries_cnt; i++) { + if (g_reg_dmn_tbl.all_countries[i].reg_dmn_pair == reg_dmn) + return &g_reg_dmn_tbl.all_countries[i]; + } + + return NULL; +} + +/** + * reg_dmn_sanitize() - sanitize regulatory domain + * @reg: regulatory data structure + * + * Return: none + */ +static void reg_dmn_sanitize(struct regulatory *reg) +{ + if (reg->reg_domain != CTRY_FLAG) + return; + + reg->reg_domain = WOR0_WORLD; +} + +/** + * cds_fill_some_regulatory_info() - fill regulatory information + * @reg: regulatory data structure + * + * Return: error code + */ +int32_t cds_fill_some_regulatory_info(struct regulatory *reg) +{ + uint16_t country_code; + uint16_t reg_dmn, rd; + const struct country_code_to_reg_dmn *country = NULL; + + reg_dmn_sanitize(reg); + rd = reg->reg_domain; + + if (!is_reg_dmn_valid(rd)) + return -EINVAL; + + reg_dmn = get_bdf_reg_dmn(rd); + + country_code = reg_dmn_get_default_country(reg_dmn); + if (country_code == CTRY_DEFAULT && reg_dmn == CTRY_DEFAULT) + country_code = CTRY_UNITED_STATES; + + if (country_code != CTRY_DEFAULT) { + country = find_country(country_code); + if (!country) { + cds_err("not a valid country code"); + return -EINVAL; + } + + reg_dmn = country->reg_dmn_pair; + } + + reg->regpair = get_reg_dmn_pair(reg_dmn); + if (!reg->regpair) { + cds_err("no regpair is found, can not proceed"); + return -EINVAL; + } + + reg->country_code = country_code; + + if (!country) + country = get_country_from_rd(reg_dmn); + + if (country) { + reg->alpha2[0] = country->alpha2[0]; + reg->alpha2[1] = country->alpha2[1]; + } else { + reg->alpha2[0] = '0'; + reg->alpha2[1] = '0'; + } + + return 0; +} + +/** + * cds_fill_and_send_ctl_to_fw() - fill and send ctl to firmware + * @reg: the regulatory handle + * + * Return: none + */ +void cds_fill_and_send_ctl_to_fw(struct regulatory *reg) +{ + const struct reg_dmn *reg_dmn_2g = NULL; + const struct reg_dmn *reg_dmn_5g = NULL; + uint8_t ctl_2g, ctl_5g; + const struct reg_dmn_pair *regpair; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return; + + if (!reg->regpair) { + cds_err(FL("no regpair is found, can not proceed")); + return; + } + regpair = reg->regpair; + reg_dmn_2g = get_reg_dmn(regpair->reg_dmn_2ghz); + if (!reg_dmn_2g) { + cds_err("failed to get regdmn 2G"); + return; + } + + reg_dmn_5g = get_reg_dmn(regpair->reg_dmn_5ghz); + if (!reg_dmn_5g) { + cds_err("failed to get regdmn 5G"); + return; + } + + ctl_2g = reg_dmn_2g->conformance_test_limit; + ctl_5g = reg_dmn_5g->conformance_test_limit; + + + reg->ctl_5g = ctl_5g; + reg->ctl_2g = ctl_2g; + + wma_send_regdomain_info_to_fw(reg->reg_domain, regpair->reg_dmn_2ghz, + regpair->reg_dmn_5ghz, ctl_2g, ctl_5g); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_sched.c b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_sched.c new file mode 100644 index 0000000000..73ba5c42dd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_sched.c @@ -0,0 +1,950 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: CDS Scheduler Implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include "cds_sched.h" +#include +#include "wma_types.h" +#include +#include +#include +#ifdef RX_PERFORMANCE +#include +#endif +#include "wlan_dp_ucfg_api.h" + +/* + * The following commit was introduced in v5.17: + * cead18552660 ("exit: Rename complete_and_exit to kthread_complete_and_exit") + * Use the old name for kernels before 5.17 + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)) +/** + * kthread_complete_and_exit - completes the thread and exit + * @c: thread or task to be completed + * @s: exit code + */ +#define kthread_complete_and_exit(c, s) complete_and_exit(c, s) +#endif + +static spinlock_t ssr_protect_lock; + +struct shutdown_notifier { + struct list_head list; + void (*cb)(void *priv); + void *priv; +}; + +struct list_head shutdown_notifier_head; + +enum notifier_state { + NOTIFIER_STATE_NONE, + NOTIFIER_STATE_NOTIFYING, +} notifier_state; + +static p_cds_sched_context gp_cds_sched_context; + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD +static int cds_ol_rx_thread(void *arg); +static uint32_t affine_cpu; +static QDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext); + +#define CDS_CORE_PER_CLUSTER (4) +/*Maximum 2 clusters supported*/ +#define CDS_MAX_CPU_CLUSTERS 2 + +#define CDS_CPU_CLUSTER_TYPE_LITTLE 0 +#define CDS_CPU_CLUSTER_TYPE_PERF 1 + +static inline +int cds_set_cpus_allowed_ptr_with_cpu(struct task_struct *task, + unsigned long cpu) +{ + return set_cpus_allowed_ptr(task, cpumask_of(cpu)); +} + +static inline +int cds_set_cpus_allowed_ptr_with_mask(struct task_struct *task, + qdf_cpu_mask *new_mask) +{ + return set_cpus_allowed_ptr(task, new_mask); +} + +void cds_set_rx_thread_cpu_mask(uint8_t cpu_affinity_mask) +{ + p_cds_sched_context sched_context = get_cds_sched_ctxt(); + + if (!sched_context) { + qdf_err("invalid context"); + return; + } + sched_context->conf_rx_thread_cpu_mask = cpu_affinity_mask; +} + +void cds_set_rx_thread_ul_cpu_mask(uint8_t cpu_affinity_mask) +{ + p_cds_sched_context sched_context = get_cds_sched_ctxt(); + + if (!sched_context) { + qdf_err("invalid context"); + return; + } + sched_context->conf_rx_thread_ul_affinity = cpu_affinity_mask; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +/** + * cds_rx_thread_log_cpu_affinity_change() - Log Rx thread affinity change + * @core_affine_cnt: Available cores + * @tput_req: Throughput request + * @old_mask: Old affinity mask + * @new_mask: New affinity mask + * + * Return: NONE + */ +static void cds_rx_thread_log_cpu_affinity_change(unsigned char core_affine_cnt, + int tput_req, + struct cpumask *old_mask, + struct cpumask *new_mask) +{ + char new_mask_str[10]; + char old_mask_str[10]; + + qdf_mem_zero(new_mask_str, sizeof(new_mask_str)); + qdf_mem_zero(new_mask_str, sizeof(old_mask_str)); + + cpumap_print_to_pagebuf(false, old_mask_str, old_mask); + cpumap_print_to_pagebuf(false, new_mask_str, new_mask); + + cds_debug("num online cores %d, high tput req %d, Rx_thread old mask %s new mask %s", + core_affine_cnt, tput_req, old_mask_str, new_mask_str); +} +#else +static void cds_rx_thread_log_cpu_affinity_change(unsigned char core_affine_cnt, + int tput_req, + struct cpumask *old_mask, + struct cpumask *new_mask) +{ +} +#endif + +/** + * cds_sched_find_attach_cpu - find available cores and attach to required core + * @pSchedContext: wlan scheduler context + * @high_throughput: high throughput is required or not + * + * Find current online cores. + * During high TPUT, + * 1) If user INI configured cores, affine to those cores + * 2) Otherwise perf cores. + * 3) Otherwise to all cores. + * + * During low TPUT, set affinity to any core, let system decide. + * + * Return: 0 success + * 1 fail + */ +static int cds_sched_find_attach_cpu(p_cds_sched_context pSchedContext, + bool high_throughput) +{ + unsigned char core_affine_count = 0; + qdf_cpu_mask new_mask; + unsigned long cpus; + struct cds_config_info *cds_cfg; + + cds_debug("num possible cpu %d", num_possible_cpus()); + + qdf_cpumask_clear(&new_mask); + + if (high_throughput) { + /* Get Online perf/pwr CPU count */ + for_each_online_cpu(cpus) { + if (topology_physical_package_id(cpus) > + CDS_MAX_CPU_CLUSTERS) { + cds_err("can handle max %d clusters, returning...", + CDS_MAX_CPU_CLUSTERS); + goto err; + } + + if (pSchedContext->conf_rx_thread_cpu_mask) { + if (pSchedContext->conf_rx_thread_cpu_mask & + (1 << cpus)) + qdf_cpumask_set_cpu(cpus, &new_mask); + } else if (topology_physical_package_id(cpus) == + CDS_CPU_CLUSTER_TYPE_PERF) { + qdf_cpumask_set_cpu(cpus, &new_mask); + } + + core_affine_count++; + } + } else { + /* Attach to all cores, let scheduler decide */ + qdf_cpumask_setall(&new_mask); + } + + cds_rx_thread_log_cpu_affinity_change(core_affine_count, + (int)pSchedContext->high_throughput_required, + &pSchedContext->rx_thread_cpu_mask, + &new_mask); + + if (!cpumask_equal(&pSchedContext->rx_thread_cpu_mask, &new_mask)) { + cds_cfg = cds_get_ini_config(); + cpumask_copy(&pSchedContext->rx_thread_cpu_mask, &new_mask); + if (cds_cfg && cds_cfg->enable_dp_rx_threads) + ucfg_dp_txrx_set_cpu_mask(cds_get_context(QDF_MODULE_ID_SOC), + &new_mask); + else + cds_set_cpus_allowed_ptr_with_mask(pSchedContext->ol_rx_thread, + &new_mask); + } + + return 0; +err: + return 1; +} + +int cds_sched_handle_cpu_hot_plug(void) +{ + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + + if (!pSchedContext) { + cds_err("invalid context"); + return 1; + } + + if (cds_is_load_or_unload_in_progress()) + return 0; + + mutex_lock(&pSchedContext->affinity_lock); + if (cds_sched_find_attach_cpu(pSchedContext, + pSchedContext->high_throughput_required)) { + cds_err("handle hot plug fail"); + mutex_unlock(&pSchedContext->affinity_lock); + return 1; + } + mutex_unlock(&pSchedContext->affinity_lock); + return 0; +} + +void cds_sched_handle_rx_thread_affinity_req(bool high_throughput) +{ + p_cds_sched_context pschedcontext = get_cds_sched_ctxt(); + unsigned long cpus; + qdf_cpu_mask new_mask; + unsigned char core_affine_count = 0; + + if (!pschedcontext || !pschedcontext->ol_rx_thread) + return; + + if (cds_is_load_or_unload_in_progress()) { + cds_err("load or unload in progress"); + return; + } + + if (pschedcontext->rx_affinity_required == high_throughput) + return; + + pschedcontext->rx_affinity_required = high_throughput; + qdf_cpumask_clear(&new_mask); + if (!high_throughput) { + /* Attach to all cores, let scheduler decide */ + qdf_cpumask_setall(&new_mask); + goto affine_thread; + } + for_each_online_cpu(cpus) { + if (topology_physical_package_id(cpus) > + CDS_MAX_CPU_CLUSTERS) { + cds_err("can handle max %d clusters ", + CDS_MAX_CPU_CLUSTERS); + return; + } + if (pschedcontext->conf_rx_thread_ul_affinity && + (pschedcontext->conf_rx_thread_ul_affinity & + (1 << cpus))) + qdf_cpumask_set_cpu(cpus, &new_mask); + + core_affine_count++; + } + +affine_thread: + cds_rx_thread_log_cpu_affinity_change( + core_affine_count, + (int)pschedcontext->rx_affinity_required, + &pschedcontext->rx_thread_cpu_mask, + &new_mask); + + mutex_lock(&pschedcontext->affinity_lock); + if (!cpumask_equal(&pschedcontext->rx_thread_cpu_mask, &new_mask)) { + cpumask_copy(&pschedcontext->rx_thread_cpu_mask, &new_mask); + cds_set_cpus_allowed_ptr_with_mask(pschedcontext->ol_rx_thread, + &new_mask); + } + mutex_unlock(&pschedcontext->affinity_lock); +} + +int cds_sched_handle_throughput_req(bool high_tput_required) +{ + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + + if (!pSchedContext) { + cds_err("invalid context"); + return 1; + } + + if (cds_is_load_or_unload_in_progress()) { + cds_err("load or unload in progress"); + return 0; + } + + mutex_lock(&pSchedContext->affinity_lock); + if (pSchedContext->high_throughput_required != high_tput_required) { + pSchedContext->high_throughput_required = high_tput_required; + if (cds_sched_find_attach_cpu(pSchedContext, + high_tput_required)) { + mutex_unlock(&pSchedContext->affinity_lock); + return 1; + } + } + mutex_unlock(&pSchedContext->affinity_lock); + return 0; +} + +/** + * cds_cpu_hotplug_multi_cluster() - calls the multi-cluster hotplug handler, + * when on a multi-cluster platform + * + * Return: QDF_STATUS + */ +static QDF_STATUS cds_cpu_hotplug_multi_cluster(void) +{ + int cpus; + unsigned int multi_cluster = 0; + + for_each_online_cpu(cpus) { + multi_cluster = topology_physical_package_id(cpus); + } + + if (!multi_cluster) + return QDF_STATUS_E_NOSUPPORT; + + if (cds_sched_handle_cpu_hot_plug()) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * __cds_cpu_hotplug_notify() - CPU hotplug event handler + * @cpu: CPU Id of the CPU generating the event + * @cpu_up: true if the CPU is online + * + * Return: None + */ +static void __cds_cpu_hotplug_notify(uint32_t cpu, bool cpu_up) +{ + unsigned long pref_cpu = 0; + p_cds_sched_context pSchedContext = get_cds_sched_ctxt(); + int i; + + if (!pSchedContext || !pSchedContext->ol_rx_thread) + return; + + if (cds_is_load_or_unload_in_progress() || cds_is_driver_recovering()) + return; + + cds_debug("'%s' event on CPU %u (of %d); Currently affine to CPU %u", + cpu_up ? "Up" : "Down", cpu, num_possible_cpus(), affine_cpu); + + /* try multi-cluster scheduling first */ + if (QDF_IS_STATUS_SUCCESS(cds_cpu_hotplug_multi_cluster())) + return; + + if (cpu_up) { + if (affine_cpu != 0) + return; + + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + break; + } + } else { + if (cpu != affine_cpu) + return; + + affine_cpu = 0; + for_each_online_cpu(i) { + if (i == 0) + continue; + pref_cpu = i; + break; + } + } + + if (pref_cpu == 0) + return; + + if (pSchedContext->ol_rx_thread && + !cds_set_cpus_allowed_ptr_with_cpu(pSchedContext->ol_rx_thread, + pref_cpu)) + affine_cpu = pref_cpu; +} + +/** + * cds_cpu_hotplug_notify() - cpu core up/down notification handler wrapper + * @cpu: CPU Id of the CPU generating the event + * @cpu_up: true if the CPU is online + * + * Return: None + */ +static void cds_cpu_hotplug_notify(uint32_t cpu, bool cpu_up) +{ + struct qdf_op_sync *op_sync; + + if (qdf_op_protect(&op_sync)) + return; + + __cds_cpu_hotplug_notify(cpu, cpu_up); + + qdf_op_unprotect(op_sync); +} + +static void cds_cpu_online_cb(void *context, uint32_t cpu) +{ + cds_cpu_hotplug_notify(cpu, true); +} + +static void cds_cpu_before_offline_cb(void *context, uint32_t cpu) +{ + cds_cpu_hotplug_notify(cpu, false); +} +#endif /* WLAN_DP_LEGACY_OL_RX_THREAD */ + +QDF_STATUS cds_sched_open(void *p_cds_context, + p_cds_sched_context pSchedContext, + uint32_t SchedCtxSize) +{ + cds_debug("Opening the CDS Scheduler"); + /* Sanity checks */ + if ((!p_cds_context) || (!pSchedContext)) { + cds_err("Null params being passed"); + return QDF_STATUS_E_FAILURE; + } + if (sizeof(cds_sched_context) != SchedCtxSize) { + cds_debug("Incorrect CDS Sched Context size passed"); + return QDF_STATUS_E_INVAL; + } + qdf_mem_zero(pSchedContext, sizeof(cds_sched_context)); +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + spin_lock_init(&pSchedContext->ol_rx_thread_lock); + init_waitqueue_head(&pSchedContext->ol_rx_wait_queue); + init_completion(&pSchedContext->ol_rx_start_event); + init_completion(&pSchedContext->ol_suspend_rx_event); + init_completion(&pSchedContext->ol_resume_rx_event); + init_completion(&pSchedContext->ol_rx_shutdown); + pSchedContext->ol_rx_event_flag = 0; + spin_lock_init(&pSchedContext->ol_rx_queue_lock); + spin_lock_init(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + INIT_LIST_HEAD(&pSchedContext->ol_rx_thread_queue); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + INIT_LIST_HEAD(&pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + if (cds_alloc_ol_rx_pkt_freeq(pSchedContext) != QDF_STATUS_SUCCESS) + goto pkt_freeqalloc_failure; + qdf_cpuhp_register(&pSchedContext->cpuhp_event_handle, + NULL, + cds_cpu_online_cb, + cds_cpu_before_offline_cb); + mutex_init(&pSchedContext->affinity_lock); + pSchedContext->high_throughput_required = false; + pSchedContext->rx_affinity_required = false; + pSchedContext->active_staid = OL_TXRX_INVALID_LOCAL_PEER_ID; +#endif + gp_cds_sched_context = pSchedContext; + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + pSchedContext->ol_rx_thread = kthread_create(cds_ol_rx_thread, + pSchedContext, + "cds_ol_rx_thread"); + if (IS_ERR(pSchedContext->ol_rx_thread)) { + + cds_alert("Could not Create CDS OL RX Thread"); + goto OL_RX_THREAD_START_FAILURE; + + } + wake_up_process(pSchedContext->ol_rx_thread); + cds_debug("CDS OL RX thread Created"); + wait_for_completion_interruptible(&pSchedContext->ol_rx_start_event); + cds_debug("CDS OL Rx Thread has started"); +#endif + /* We're good now: Let's get the ball rolling!!! */ + cds_debug("CDS Scheduler successfully Opened"); + return QDF_STATUS_SUCCESS; +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD +OL_RX_THREAD_START_FAILURE: + qdf_cpuhp_unregister(&pSchedContext->cpuhp_event_handle); + cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); +pkt_freeqalloc_failure: +#endif + gp_cds_sched_context = NULL; + + return QDF_STATUS_E_RESOURCES; + +} /* cds_sched_open() */ + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD +void cds_free_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + while (!list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) { + pkt = list_entry((&pSchedContext->cds_ol_rx_pkt_freeq)->next, + typeof(*pkt), list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); +} + +/** + * cds_alloc_ol_rx_pkt_freeq() - Function to allocate free buffer queue + * @pSchedContext: pointer to the global CDS Sched Context + * + * This API allocates CDS_MAX_OL_RX_PKT number of cds message buffers + * which are used for Rx data processing. + * + * Return: status of memory allocation + */ +static QDF_STATUS cds_alloc_ol_rx_pkt_freeq(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt, *tmp; + int i; + + for (i = 0; i < CDS_MAX_OL_RX_PKT; i++) { + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) { + cds_err("Vos packet allocation for ol rx thread failed"); + goto free; + } + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + + return QDF_STATUS_SUCCESS; + +free: + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_for_each_entry_safe(pkt, tmp, &pSchedContext->cds_ol_rx_pkt_freeq, + list) { + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + qdf_mem_free(pkt); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + } + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return QDF_STATUS_E_NOMEM; +} + +void +cds_free_ol_rx_pkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ + memset(pkt, 0, sizeof(*pkt)); + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + list_add_tail(&pkt->list, &pSchedContext->cds_ol_rx_pkt_freeq); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); +} + +struct cds_ol_rx_pkt *cds_alloc_ol_rx_pkt(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + + spin_lock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + if (list_empty(&pSchedContext->cds_ol_rx_pkt_freeq)) { + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return NULL; + } + pkt = list_first_entry(&pSchedContext->cds_ol_rx_pkt_freeq, + struct cds_ol_rx_pkt, list); + list_del(&pkt->list); + spin_unlock_bh(&pSchedContext->cds_ol_rx_pkt_freeq_lock); + return pkt; +} + +void +cds_indicate_rxpkt(p_cds_sched_context pSchedContext, + struct cds_ol_rx_pkt *pkt) +{ + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + list_add_tail(&pkt->list, &pSchedContext->ol_rx_thread_queue); + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + set_bit(RX_POST_EVENT, &pSchedContext->ol_rx_event_flag); + wake_up_interruptible(&pSchedContext->ol_rx_wait_queue); +} + +QDF_STATUS cds_close_rx_thread(void) +{ + cds_debug("invoked"); + + if (!gp_cds_sched_context) { + cds_err("!gp_cds_sched_context"); + return QDF_STATUS_E_FAILURE; + } + + if (!gp_cds_sched_context->ol_rx_thread) + return QDF_STATUS_SUCCESS; + + /* Shut down Tlshim Rx thread */ + set_bit(RX_SHUTDOWN_EVENT, &gp_cds_sched_context->ol_rx_event_flag); + set_bit(RX_POST_EVENT, &gp_cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&gp_cds_sched_context->ol_rx_wait_queue); + wait_for_completion(&gp_cds_sched_context->ol_rx_shutdown); + gp_cds_sched_context->ol_rx_thread = NULL; + cds_drop_rxpkt_by_staid(gp_cds_sched_context, WLAN_MAX_STA_COUNT); + cds_free_ol_rx_pkt_freeq(gp_cds_sched_context); + qdf_cpuhp_unregister(&gp_cds_sched_context->cpuhp_event_handle); + + return QDF_STATUS_SUCCESS; +} /* cds_close_rx_thread */ + +void cds_drop_rxpkt_by_staid(p_cds_sched_context pSchedContext, uint16_t staId) +{ + struct list_head local_list; + struct cds_ol_rx_pkt *pkt, *tmp; + qdf_nbuf_t buf, next_buf; + uint32_t timeout = 0; + + INIT_LIST_HEAD(&local_list); + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + if (list_empty(&pSchedContext->ol_rx_thread_queue)) { + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + return; + } + list_for_each_entry_safe(pkt, tmp, &pSchedContext->ol_rx_thread_queue, + list) { + if (pkt->staId == staId || staId == WLAN_MAX_STA_COUNT) + list_move_tail(&pkt->list, &local_list); + } + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + + list_for_each_entry_safe(pkt, tmp, &local_list, list) { + list_del(&pkt->list); + buf = pkt->Rxpkt; + while (buf) { + next_buf = qdf_nbuf_queue_next(buf); + qdf_nbuf_free(buf); + buf = next_buf; + } + cds_free_ol_rx_pkt(pSchedContext, pkt); + } + + while (pSchedContext->active_staid == staId && + timeout <= CDS_ACTIVE_STAID_CLEANUP_TIMEOUT) { + if (qdf_in_interrupt()) + qdf_mdelay(CDS_ACTIVE_STAID_CLEANUP_DELAY); + else + qdf_sleep(CDS_ACTIVE_STAID_CLEANUP_DELAY); + timeout += CDS_ACTIVE_STAID_CLEANUP_DELAY; + } + + if (pSchedContext->active_staid == staId) + cds_err("Failed to cleanup RX packets for staId:%u", staId); +} + +/** + * cds_rx_from_queue() - function to process pending Rx packets + * @pSchedContext: Pointer to the global CDS Sched Context + * + * This api traverses the pending buffer list and calling the callback. + * This callback would essentially send the packet to HDD. + * + * Return: none + */ +static void cds_rx_from_queue(p_cds_sched_context pSchedContext) +{ + struct cds_ol_rx_pkt *pkt; + uint16_t sta_id; + + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + while (!list_empty(&pSchedContext->ol_rx_thread_queue)) { + pkt = list_first_entry(&pSchedContext->ol_rx_thread_queue, + struct cds_ol_rx_pkt, list); + list_del(&pkt->list); + pSchedContext->active_staid = pkt->staId; + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); + sta_id = pkt->staId; + pkt->callback(pkt->context, pkt->Rxpkt, sta_id); + cds_free_ol_rx_pkt(pSchedContext, pkt); + spin_lock_bh(&pSchedContext->ol_rx_queue_lock); + pSchedContext->active_staid = OL_TXRX_INVALID_LOCAL_PEER_ID; + } + spin_unlock_bh(&pSchedContext->ol_rx_queue_lock); +} + +/** + * cds_ol_rx_thread() - cds main tlshim rx thread + * @arg: pointer to the global CDS Sched Context + * + * This api is the thread handler for Tlshim Data packet processing. + * + * Return: thread exit code + */ +static int cds_ol_rx_thread(void *arg) +{ + p_cds_sched_context pSchedContext = (p_cds_sched_context) arg; + bool shutdown = false; + int status; + +#ifdef RX_THREAD_PRIORITY + struct sched_param scheduler_params = {0}; + + scheduler_params.sched_priority = 1; + sched_setscheduler(current, SCHED_FIFO, &scheduler_params); +#else + set_user_nice(current, -1); +#endif + + qdf_set_wake_up_idle(true); + + complete(&pSchedContext->ol_rx_start_event); + + while (!shutdown) { + status = + wait_event_interruptible(pSchedContext->ol_rx_wait_queue, + test_bit(RX_POST_EVENT, + &pSchedContext->ol_rx_event_flag) + || test_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag)); + if (status == -ERESTARTSYS) + break; + + clear_bit(RX_POST_EVENT, &pSchedContext->ol_rx_event_flag); + while (true) { + if (test_bit(RX_SHUTDOWN_EVENT, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SHUTDOWN_EVENT, + &pSchedContext->ol_rx_event_flag); + if (test_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag); + complete + (&pSchedContext->ol_suspend_rx_event); + } + cds_debug("Shutting down OL RX Thread"); + shutdown = true; + break; + } + cds_rx_from_queue(pSchedContext); + + if (test_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag)) { + clear_bit(RX_SUSPEND_EVENT, + &pSchedContext->ol_rx_event_flag); + spin_lock(&pSchedContext->ol_rx_thread_lock); + INIT_COMPLETION + (pSchedContext->ol_resume_rx_event); + complete(&pSchedContext->ol_suspend_rx_event); + spin_unlock(&pSchedContext->ol_rx_thread_lock); + wait_for_completion_interruptible + (&pSchedContext->ol_resume_rx_event); + } + break; + } + } + + cds_debug("Exiting CDS OL rx thread"); + kthread_complete_and_exit(&pSchedContext->ol_rx_shutdown, 0); + + return 0; +} + +void cds_resume_rx_thread(void) +{ + p_cds_sched_context cds_sched_context; + + cds_sched_context = get_cds_sched_ctxt(); + if (!cds_sched_context) { + cds_err("cds_sched_context is NULL"); + return; + } + + complete(&cds_sched_context->ol_resume_rx_event); +} +#endif + +QDF_STATUS cds_sched_close(void) +{ + cds_debug("invoked"); + + if (!gp_cds_sched_context) { + cds_err("!gp_cds_sched_context"); + return QDF_STATUS_E_FAILURE; + } + + cds_close_rx_thread(); + + gp_cds_sched_context = NULL; + return QDF_STATUS_SUCCESS; +} /* cds_sched_close() */ + +p_cds_sched_context get_cds_sched_ctxt(void) +{ + /* Make sure that Vos Scheduler context has been initialized */ + if (!gp_cds_sched_context) + cds_err("!gp_cds_sched_context"); + + return gp_cds_sched_context; +} + +void cds_ssr_protect_init(void) +{ + spin_lock_init(&ssr_protect_lock); + INIT_LIST_HEAD(&shutdown_notifier_head); +} + +QDF_STATUS cds_shutdown_notifier_register(void (*cb)(void *priv), void *priv) +{ + struct shutdown_notifier *notifier; + unsigned long irq_flags; + + notifier = qdf_mem_malloc(sizeof(*notifier)); + + if (!notifier) + return QDF_STATUS_E_NOMEM; + + /* + * This logic can be simpilfied if there is separate state maintained + * for shutdown and reinit. Right now there is only recovery in progress + * state and it doesn't help to check against it as during reinit some + * of the modules may need to register the call backs. + * For now this logic added to avoid notifier registration happen while + * this function is trying to call the call back with the notification. + */ + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + if (notifier_state == NOTIFIER_STATE_NOTIFYING) { + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + qdf_mem_free(notifier); + return -EINVAL; + } + + notifier->cb = cb; + notifier->priv = priv; + + list_add_tail(¬ifier->list, &shutdown_notifier_head); + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + return 0; +} + +void cds_shutdown_notifier_purge(void) +{ + struct shutdown_notifier *notifier, *temp; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + list_for_each_entry_safe(notifier, temp, + &shutdown_notifier_head, list) { + list_del(¬ifier->list); + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + qdf_mem_free(notifier); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + } + + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +void cds_shutdown_notifier_call(void) +{ + struct shutdown_notifier *notifier; + unsigned long irq_flags; + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + notifier_state = NOTIFIER_STATE_NOTIFYING; + + list_for_each_entry(notifier, &shutdown_notifier_head, list) { + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); + + notifier->cb(notifier->priv); + + spin_lock_irqsave(&ssr_protect_lock, irq_flags); + } + + notifier_state = NOTIFIER_STATE_NONE; + spin_unlock_irqrestore(&ssr_protect_lock, irq_flags); +} + +int cds_get_gfp_flags(void) +{ + int flags = GFP_KERNEL; + + if (in_interrupt() || in_atomic() || irqs_disabled()) + flags = GFP_ATOMIC; + + return flags; +} + +/** + * cds_get_rx_thread_pending(): get rx thread status + * @soc: ol_txrx_soc_handle object + * + * Return: 1 if rx thread is not empty. + * 0 if rx thread is empty + */ +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD +int cds_get_rx_thread_pending(ol_txrx_soc_handle soc) +{ + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + + if (!cds_sched_context) { + cds_err("cds_sched_context is NULL"); + return 0; + } + + spin_lock_bh(&cds_sched_context->ol_rx_queue_lock); + + if (list_empty(&cds_sched_context->ol_rx_thread_queue)) { + spin_unlock_bh(&cds_sched_context->ol_rx_queue_lock); + return 0; + } + + /* In helium there is no scope to get no of pending frames + * in rx thread, Hence return 1 if frames are queued + */ + spin_unlock_bh(&cds_sched_context->ol_rx_queue_lock); + return 1; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_utils.c new file mode 100644 index 0000000000..ec060f33fb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/cds_utils.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*============================================================================ + FILE: cds_utils.c + + OVERVIEW: This source file contains definitions for CDS crypto APIs + The four APIs mentioned in this file are used for + initializing, and de-initializing a crypto context, and + obtaining truly random data (for keys), as well as + SHA1 HMAC, and AES encrypt and decrypt routines. + + The routines include: + cds_crypto_init() - Initializes Crypto module + cds_crypto_deinit() - De-initializes Crypto module + cds_rand_get_bytes() - Generates random byte + + DEPENDENCIES: + ============================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ + +#include "qdf_trace.h" +#include "cds_utils.h" +#include "qdf_mem.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cds_ieee80211_common.h" +#include + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + Function Definitions and Documentation + * -------------------------------------------------------------------------*/ + +uint8_t cds_get_mmie_size(void) +{ + return sizeof(struct ieee80211_mmie); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +uint8_t cds_get_gmac_mmie_size(void) +{ + return sizeof(struct ieee80211_mmie_16); +} +#else +uint8_t cds_get_gmac_mmie_size(void) +{ + return 0; +} +#endif + +uint32_t cds_chan_to_freq(uint8_t chan) +{ + if (chan < CDS_24_GHZ_CHANNEL_14) /* ch 0 - ch 13 */ + return CDS_24_GHZ_BASE_FREQ + chan * CDS_CHAN_SPACING_5MHZ; + else if (chan == CDS_24_GHZ_CHANNEL_14) /* ch 14 */ + return CDS_CHAN_14_FREQ; + else if (chan < CDS_24_GHZ_CHANNEL_27) /* ch 15 - ch 26 */ + return CDS_CHAN_15_FREQ + + (chan - CDS_24_GHZ_CHANNEL_15) * CDS_CHAN_SPACING_20MHZ; + else if (chan == CDS_5_GHZ_CHANNEL_170) + return CDS_CHAN_170_FREQ; + else + return CDS_5_GHZ_BASE_FREQ + chan * CDS_CHAN_SPACING_5MHZ; +} + +uint8_t cds_freq_to_chan(uint32_t freq) +{ + uint8_t chan; + + if (freq > CDS_24_GHZ_BASE_FREQ && freq < CDS_CHAN_14_FREQ) + chan = ((freq - CDS_24_GHZ_BASE_FREQ) / CDS_CHAN_SPACING_5MHZ); + else if (freq == CDS_CHAN_14_FREQ) + chan = CDS_24_GHZ_CHANNEL_14; + else if ((freq > CDS_24_GHZ_BASE_FREQ) && (freq < CDS_5_GHZ_BASE_FREQ)) + chan = (((freq - CDS_CHAN_15_FREQ) / CDS_CHAN_SPACING_20MHZ) + + CDS_24_GHZ_CHANNEL_15); + else + chan = (freq - CDS_5_GHZ_BASE_FREQ) / CDS_CHAN_SPACING_5MHZ; + return chan; +} + +enum cds_band_type cds_chan_to_band(uint32_t chan) +{ + if (chan <= CDS_24_GHZ_CHANNEL_14) + return CDS_BAND_2GHZ; + + return CDS_BAND_5GHZ; +} + +void cds_copy_hlp_info(struct qdf_mac_addr *input_dst_mac, + struct qdf_mac_addr *input_src_mac, + uint16_t input_hlp_data_len, + uint8_t *input_hlp_data, + struct qdf_mac_addr *output_dst_mac, + struct qdf_mac_addr *output_src_mac, + uint16_t *output_hlp_data_len, + uint8_t *output_hlp_data) +{ + if (!input_hlp_data_len) { + cds_debug("Input HLP data len zero\n"); + return; + } + + if (!input_dst_mac) { + cds_debug("HLP destination mac NULL"); + return; + } + + if (!input_src_mac) { + cds_debug("HLP source mac NULL"); + return; + } + qdf_copy_macaddr(output_dst_mac, input_dst_mac); + qdf_copy_macaddr(output_src_mac, input_src_mac); + *output_hlp_data_len = input_hlp_data_len; + qdf_mem_copy(output_hlp_data, input_hlp_data, input_hlp_data_len); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/cds/src/i_cds_packet.h b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/i_cds_packet.h new file mode 100644 index 0000000000..723b88c716 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/cds/src/i_cds_packet.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014-2016, 2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__I_CDS_PACKET_H) +#define __I_CDS_PACKET_H + +/** + * DOC: i_cds_packet.h + * Connectivity driver services network packet APIs + * Network Protocol packet/buffer internal include file + */ + +#include "qdf_types.h" + +/** + * struct packetmeta - Rx Packet Struct + * @frequency: Frequency + * @snr: Signal to noise ratio + * @rssi: Received signal strength indicator, normalized to -96 dBm as + * normal noise floor by adding -96 to snr. All the configured + * thresholds in the driver assume that noise floor is -96 dBm. + * @timestamp: System timestamp when frame was received. Set to jiffies. + * @mpdu_hdr_ptr: Pointer to beginning of 802.11 MPDU + * @mpdu_data_ptr: Pointer to beginning of payload + * @mpdu_len: Length of 802.11 MPDU + * @mpdu_hdr_len: Length of 802.11 MPDU header + * @mpdu_data_len: Length of 802.11 MPDU payload + * @offloadScanLearn: Bit set to 1 for beacons received during roaming scan + * @roamCandidateInd: Bit set to 1 when roaming candidate is found by fw + * @scan_src: Source of scan + * @dpuFeedback: DPU feedback for frame + * @session_id: PE session + * @tsf_delta: Delta between tsf in frame and local value of tsf + * @rssi_raw: rssi based on actual noise floor in hardware. + * @pkt_qdf_buf: Pointer to Packet + * + * Buffer for the packet received from WMA has pointers to 802.11 + * frame fields and additional information based on the type of frame. + */ +struct packetmeta { + uint32_t frequency; + uint8_t snr; + uint32_t rssi; + uint32_t timestamp; + uint8_t *mpdu_hdr_ptr; + uint8_t *mpdu_data_ptr; + uint32_t mpdu_len; + uint32_t mpdu_hdr_len; + uint32_t mpdu_data_len; + uint8_t offloadScanLearn:1; + uint8_t roamCandidateInd:1; + uint8_t scan_src; + uint8_t dpuFeedback; + uint8_t session_id; + uint32_t tsf_delta; + uint32_t rssi_raw; + void *pkt_qdf_buf; +}; + +typedef struct packetmeta t_packetmeta, *tp_packetmeta; + +/* implementation specific cds packet type */ +struct cds_pkt_t { + /* Packet Meta Information */ + t_packetmeta pkt_meta; + + /* Pointer to Packet */ + void *pkt_buf; +}; + +#endif /* !defined( __I_CDS_PACKET_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt.c new file mode 100644 index 0000000000..4b62d5329a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt.c @@ -0,0 +1,1025 @@ +/* + * Copyright (c) 2011, 2014-2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file htt.c + * @brief Provide functions to create+init and destroy a HTT instance. + * @details + * This file contains functions for creating a HTT instance; initializing + * the HTT instance, e.g. by allocating a pool of HTT tx descriptors and + * connecting the HTT service with HTC; and deleting a HTT instance. + */ + +#include /* qdf_mem_malloc */ +#include /* qdf_device_t, qdf_print */ + +#include /* htt_tx_msdu_desc_t */ +#include +#include /* ol_tx_dowload_done_ll, etc. */ +#include + +#include +#include +#include +#include "hif.h" +#include +#include + +#define HTT_HTC_PKT_POOL_INIT_SIZE 100 /* enough for a large A-MPDU */ + +QDF_STATUS(*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); +QDF_STATUS(*htt_h2t_rx_ring_rfs_cfg_msg)(struct htt_pdev_t *pdev); + +#ifdef IPA_OFFLOAD +static QDF_STATUS htt_ipa_config(htt_pdev_handle pdev, QDF_STATUS status) +{ + if ((QDF_STATUS_SUCCESS == status) && + ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + status = htt_h2t_ipa_uc_rsc_cfg_msg(pdev); + return status; +} + +#define HTT_IPA_CONFIG htt_ipa_config +#else +#define HTT_IPA_CONFIG(pdev, status) status /* no-op */ +#endif /* IPA_OFFLOAD */ + +struct htt_htc_pkt *htt_htc_pkt_alloc(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt = NULL; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + if (pdev->htt_htc_pkt_freelist) { + pkt = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = pdev->htt_htc_pkt_freelist->u.next; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + if (!pkt) + pkt = qdf_mem_malloc(sizeof(*pkt)); + + if (!pkt) + return NULL; + + htc_packet_set_magic_cookie(&(pkt->u.pkt.htc_pkt), 0); + return &pkt->u.pkt; /* not actually a dereference */ +} + +void htt_htc_pkt_free(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt) +{ + struct htt_htc_pkt_union *u_pkt = (struct htt_htc_pkt_union *)pkt; + + if (!u_pkt) { + qdf_print("HTC packet is NULL"); + return; + } + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + htc_packet_set_magic_cookie(&(u_pkt->u.pkt.htc_pkt), 0); + u_pkt->u.next = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = u_pkt; + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); +} + +void htt_htc_pkt_pool_free(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt, *next; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + pkt = pdev->htt_htc_pkt_freelist; + pdev->htt_htc_pkt_freelist = NULL; + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + while (pkt) { + next = pkt->u.next; + qdf_mem_free(pkt); + pkt = next; + } +} + +#ifdef ATH_11AC_TXCOMPACT + +void +htt_htc_misc_pkt_list_trim(struct htt_pdev_t *pdev, int level) +{ + struct htt_htc_pkt_union *pkt, *next, *prev = NULL; + int i = 0; + qdf_nbuf_t netbuf; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + pkt = pdev->htt_htc_pkt_misclist; + while (pkt) { + next = pkt->u.next; + /* trim the out grown list*/ + if (++i > level) { + netbuf = + (qdf_nbuf_t)(pkt->u.pkt.htc_pkt.pNetBufContext); + qdf_nbuf_unmap(pdev->osdev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(netbuf); + qdf_mem_free(pkt); + pkt = NULL; + if (prev) + prev->u.next = NULL; + } + prev = pkt; + pkt = next; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); +} + +void htt_htc_misc_pkt_list_add(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt) +{ + struct htt_htc_pkt_union *u_pkt = (struct htt_htc_pkt_union *)pkt; + int misclist_trim_level = htc_get_tx_queue_depth(pdev->htc_pdev, + pkt->htc_pkt.Endpoint) + + HTT_HTC_PKT_MISCLIST_SIZE; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + if (pdev->htt_htc_pkt_misclist) { + u_pkt->u.next = pdev->htt_htc_pkt_misclist; + pdev->htt_htc_pkt_misclist = u_pkt; + } else { + pdev->htt_htc_pkt_misclist = u_pkt; + } + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + /* only ce pipe size + tx_queue_depth could possibly be in use + * free older packets in the msiclist + */ + htt_htc_misc_pkt_list_trim(pdev, misclist_trim_level); +} + +void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt_union *pkt, *next; + qdf_nbuf_t netbuf; + + HTT_TX_MUTEX_ACQUIRE(&pdev->htt_tx_mutex); + pkt = pdev->htt_htc_pkt_misclist; + pdev->htt_htc_pkt_misclist = NULL; + HTT_TX_MUTEX_RELEASE(&pdev->htt_tx_mutex); + + while (pkt) { + next = pkt->u.next; + if (htc_packet_get_magic_cookie(&(pkt->u.pkt.htc_pkt)) != + HTC_PACKET_MAGIC_COOKIE) { + QDF_ASSERT(0); + pkt = next; + continue; + } + + netbuf = (qdf_nbuf_t) (pkt->u.pkt.htc_pkt.pNetBufContext); + qdf_nbuf_unmap(pdev->osdev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(netbuf); + qdf_mem_free(pkt); + pkt = next; + } +} +#endif + + +/* AR6004 don't need HTT layer. */ +#ifdef AR6004_HW +#define NO_HTT_NEEDED true +#else +#define NO_HTT_NEEDED false +#endif + +#if defined(QCA_TX_HTT2_SUPPORT) && defined(CONFIG_HL_SUPPORT) + +/** + * htt_htc_tx_htt2_service_start() - Start TX HTT2 service + * + * @pdev: pointer to htt device. + * @connect_req: pointer to service connection request information + * @connect_resp: pointer to service connection response information + * + * + * Return: None + */ +static void +htt_htc_tx_htt2_service_start(struct htt_pdev_t *pdev, + struct htc_service_connect_req *connect_req, + struct htc_service_connect_resp *connect_resp) +{ + QDF_STATUS status; + + qdf_mem_zero(connect_req, sizeof(struct htc_service_connect_req)); + qdf_mem_zero(connect_resp, sizeof(struct htc_service_connect_resp)); + + /* The same as HTT service but no RX. */ + connect_req->EpCallbacks.pContext = pdev; + connect_req->EpCallbacks.EpTxComplete = htt_h2t_send_complete; + connect_req->EpCallbacks.EpSendFull = htt_h2t_full; + connect_req->MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; + /* Should NOT support credit flow control. */ + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + /* Enable HTC schedule mechanism for TX HTT2 service. */ + connect_req->ConnectionFlags |= HTC_CONNECT_FLAGS_ENABLE_HTC_SCHEDULE; + + connect_req->service_id = HTT_DATA2_MSG_SVC; + + status = htc_connect_service(pdev->htc_pdev, connect_req, connect_resp); + + if (status != QDF_STATUS_SUCCESS) { + pdev->htc_tx_htt2_endpoint = ENDPOINT_UNUSED; + pdev->htc_tx_htt2_max_size = 0; + } else { + pdev->htc_tx_htt2_endpoint = connect_resp->Endpoint; + pdev->htc_tx_htt2_max_size = HTC_TX_HTT2_MAX_SIZE; + } + + qdf_print("TX HTT %s, ep %d size %d\n", + (status == QDF_STATUS_SUCCESS ? "ON" : "OFF"), + pdev->htc_tx_htt2_endpoint, + pdev->htc_tx_htt2_max_size); +} +#else + +static inline void +htt_htc_tx_htt2_service_start(struct htt_pdev_t *pdev, + struct htc_service_connect_req *connect_req, + struct htc_service_connect_resp *connect_resp) +{ +} +#endif + +/** + * htt_htc_credit_flow_disable() - disable flow control for + * HTT data message service + * + * @pdev: pointer to htt device. + * @connect_req: pointer to service connection request information + * + * HTC Credit mechanism is disabled based on + * default_tx_comp_req as throughput will be lower + * if we disable htc credit mechanism with default_tx_comp_req + * set since txrx download packet will be limited by ota + * completion. + * + * Return: None + */ +static +void htt_htc_credit_flow_disable(struct htt_pdev_t *pdev, + struct htc_service_connect_req *connect_req) +{ + if (pdev->osdev->bus_type == QDF_BUS_TYPE_SDIO) { + /* + * TODO:Conditional disabling will be removed once firmware + * with reduced tx completion is pushed into release builds. + */ + if (!pdev->cfg.default_tx_comp_req) + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + } else { + connect_req->ConnectionFlags |= + HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL; + } +} + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +/** + * htt_dump_bundle_stats() - dump wlan stats + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_dump_bundle_stats(htt_pdev_handle pdev) +{ + htc_dump_bundle_stats(pdev->htc_pdev); +} + +/** + * htt_clear_bundle_stats() - clear wlan stats + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_clear_bundle_stats(htt_pdev_handle pdev) +{ + htc_clear_bundle_stats(pdev->htc_pdev); +} +#endif + +#if defined(QCA_WIFI_3_0_ADRASTEA) +/** + * htt_htc_attach_all() - Connect to HTC service for HTT + * @pdev: pdev ptr + * + * Return: 0 for success or error code. + */ + +#if defined(QCN7605_SUPPORT) && defined(IPA_OFFLOAD) + +/* In case of QCN7605 with IPA offload only 2 CE + * are used for RFS + */ +static int +htt_htc_attach_all(struct htt_pdev_t *pdev) +{ + if (htt_htc_attach(pdev, HTT_DATA_MSG_SVC)) + goto flush_endpoint; + + if (htt_htc_attach(pdev, HTT_DATA2_MSG_SVC)) + goto flush_endpoint; + + return 0; + +flush_endpoint: + htc_flush_endpoint(pdev->htc_pdev, ENDPOINT_0, HTC_TX_PACKET_TAG_ALL); + + return -EIO; +} + +#else + +static int +htt_htc_attach_all(struct htt_pdev_t *pdev) +{ + if (htt_htc_attach(pdev, HTT_DATA_MSG_SVC)) + goto flush_endpoint; + + if (htt_htc_attach(pdev, HTT_DATA2_MSG_SVC)) + goto flush_endpoint; + + if (htt_htc_attach(pdev, HTT_DATA3_MSG_SVC)) + goto flush_endpoint; + + return 0; + +flush_endpoint: + htc_flush_endpoint(pdev->htc_pdev, ENDPOINT_0, HTC_TX_PACKET_TAG_ALL); + + return -EIO; +} + +#endif + +#else +/** + * htt_htc_attach_all() - Connect to HTC service for HTT + * @pdev: pdev ptr + * + * Return: 0 for success or error code. + */ +static int +htt_htc_attach_all(struct htt_pdev_t *pdev) +{ + return htt_htc_attach(pdev, HTT_DATA_MSG_SVC); +} +#endif + +/** + * htt_pdev_alloc() - allocate HTT pdev + * @txrx_pdev: txrx pdev + * @ctrl_pdev: cfg pdev + * @htc_pdev: HTC pdev + * @osdev: os device + * + * Return: HTT pdev handle + */ +htt_pdev_handle +htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, + struct cdp_cfg *ctrl_pdev, + HTC_HANDLE htc_pdev, qdf_device_t osdev) +{ + struct htt_pdev_t *pdev; + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + + if (!osc) + goto fail1; + + pdev = qdf_mem_malloc(sizeof(*pdev)); + if (!pdev) + goto fail1; + + pdev->osdev = osdev; + pdev->ctrl_pdev = ctrl_pdev; + pdev->txrx_pdev = txrx_pdev; + pdev->htc_pdev = htc_pdev; + + pdev->htt_htc_pkt_freelist = NULL; +#ifdef ATH_11AC_TXCOMPACT + pdev->htt_htc_pkt_misclist = NULL; +#endif + + /* for efficiency, store a local copy of the is_high_latency flag */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(pdev->ctrl_pdev); + /* + * Credit reporting through HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND + * enabled or not. + */ + pdev->cfg.credit_update_enabled = + ol_cfg_is_credit_update_enabled(pdev->ctrl_pdev); + + pdev->cfg.request_tx_comp = cds_is_ptp_rx_opt_enabled() || + cds_is_packet_log_enabled(); + + pdev->cfg.default_tx_comp_req = + !ol_cfg_tx_free_at_download(pdev->ctrl_pdev); + + pdev->cfg.is_full_reorder_offload = + ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "full_reorder_offloaded %d", + (int)pdev->cfg.is_full_reorder_offload); + + pdev->cfg.ce_classify_enabled = + ol_cfg_is_ce_classify_enabled(ctrl_pdev); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "ce_classify %d", + pdev->cfg.ce_classify_enabled); + + if (pdev->cfg.is_high_latency) { + qdf_atomic_init(&pdev->htt_tx_credit.target_delta); + qdf_atomic_init(&pdev->htt_tx_credit.bus_delta); + qdf_atomic_add(HTT_MAX_BUS_CREDIT, + &pdev->htt_tx_credit.bus_delta); + } + + pdev->targetdef = htc_get_targetdef(htc_pdev); +#if defined(HELIUMPLUS) + HTT_SET_WIFI_IP(pdev, 2, 0); +#endif /* defined(HELIUMPLUS) */ + + if (NO_HTT_NEEDED) + goto success; + /* + * Connect to HTC service. + * This has to be done before calling htt_rx_attach, + * since htt_rx_attach involves sending a rx ring configure + * message to the target. + */ + HTT_TX_MUTEX_INIT(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_INIT(pdev); + HTT_TX_MUTEX_INIT(&pdev->credit_mutex); + if (htt_htc_attach_all(pdev)) + goto htt_htc_attach_fail; + if (hif_ce_fastpath_cb_register(osc, htt_t2h_msg_handler_fast, pdev)) + qdf_print("failed to register fastpath callback\n"); + +success: + return pdev; + +htt_htc_attach_fail: + HTT_TX_MUTEX_DESTROY(&pdev->credit_mutex); + HTT_TX_MUTEX_DESTROY(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(pdev); + qdf_mem_free(pdev); + +fail1: + return NULL; + +} + +/** + * htt_attach() - Allocate and setup HTT TX/RX descriptors + * @pdev: pdev ptr + * @desc_pool_size: size of tx descriptors + * + * Return: 0 for success or error code. + */ +int +htt_attach(struct htt_pdev_t *pdev, int desc_pool_size) +{ + int i; + int ret = 0; + + pdev->is_ipa_uc_enabled = false; + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + pdev->is_ipa_uc_enabled = true; + + pdev->new_htt_format_enabled = false; + if (ol_cfg_is_htt_new_format_enabled(pdev->ctrl_pdev)) + pdev->new_htt_format_enabled = true; + + htc_enable_hdr_length_check(pdev->htc_pdev, + pdev->new_htt_format_enabled); + + ret = htt_tx_attach(pdev, desc_pool_size); + if (ret) + goto fail1; + + ret = htt_rx_attach(pdev); + if (ret) + goto fail2; + + /* pre-allocate some HTC_PACKET objects */ + for (i = 0; i < HTT_HTC_PKT_POOL_INIT_SIZE; i++) { + struct htt_htc_pkt_union *pkt; + + pkt = qdf_mem_malloc(sizeof(*pkt)); + if (!pkt) + break; + htt_htc_pkt_free(pdev, &pkt->u.pkt); + } + + if (pdev->cfg.is_high_latency) { + /* + * HL - download the whole frame. + * Specify a download length greater than the max MSDU size, + * so the downloads will be limited by the actual frame sizes. + */ + pdev->download_len = 5000; + + if (ol_cfg_tx_free_at_download(pdev->ctrl_pdev) && + !pdev->cfg.request_tx_comp) + pdev->tx_send_complete_part2 = + ol_tx_download_done_hl_free; + else + pdev->tx_send_complete_part2 = + ol_tx_download_done_hl_retain; + + /* + * CHECK THIS LATER: does the HL HTT version of + * htt_rx_mpdu_desc_list_next + * (which is not currently implemented) present the + * adf_nbuf_data(rx_ind_msg) + * as the abstract rx descriptor? + * If not, the rx_fw_desc_offset initialization + * here will have to be adjusted accordingly. + * NOTE: for HL, because fw rx desc is in ind msg, + * not in rx desc, so the + * offset should be negative value + */ + pdev->rx_fw_desc_offset = + HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + - HTT_RX_IND_HL_BYTES); + + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_hl; + htt_h2t_rx_ring_rfs_cfg_msg = htt_h2t_rx_ring_rfs_cfg_msg_hl; + + /* initialize the txrx credit count */ + ol_tx_target_credit_update( + pdev->txrx_pdev, ol_cfg_target_tx_credit( + pdev->ctrl_pdev)); + DPTRACE(qdf_dp_trace_credit_record(QDF_HTT_ATTACH, + QDF_CREDIT_INC, + ol_cfg_target_tx_credit(pdev->ctrl_pdev), + qdf_atomic_read(&pdev->txrx_pdev->target_tx_credit), + qdf_atomic_read(&pdev->txrx_pdev->txq_grps[0].credit), + qdf_atomic_read(&pdev->txrx_pdev->txq_grps[1].credit))); + + } else { + enum wlan_frm_fmt frm_type; + + /* + * LL - download just the initial portion of the frame. + * Download enough to cover the encapsulation headers checked + * by the target's tx classification descriptor engine. + * + * For LL, the FW rx desc directly referenced at its location + * inside the rx indication message. + */ + + /* account for the 802.3 or 802.11 header */ + frm_type = ol_cfg_frame_type(pdev->ctrl_pdev); + + if (frm_type == wlan_frm_fmt_native_wifi) { + pdev->download_len = HTT_TX_HDR_SIZE_NATIVE_WIFI; + } else if (frm_type == wlan_frm_fmt_802_3) { + pdev->download_len = HTT_TX_HDR_SIZE_ETHERNET; + } else { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Unexpected frame type spec: %d", frm_type); + HTT_ASSERT0(0); + } + + /* + * Account for the optional L2 / ethernet header fields: + * 802.1Q, LLC/SNAP + */ + pdev->download_len += + HTT_TX_HDR_SIZE_802_1Q + HTT_TX_HDR_SIZE_LLC_SNAP; + + /* + * Account for the portion of the L3 (IP) payload that the + * target needs for its tx classification. + */ + pdev->download_len += ol_cfg_tx_download_size(pdev->ctrl_pdev); + + /* + * Account for the HTT tx descriptor, including the + * HTC header + alignment padding. + */ + pdev->download_len += sizeof(struct htt_host_tx_desc_t); + + /* + * The TXCOMPACT htt_tx_sched function uses pdev->download_len + * to apply for all requeued tx frames. Thus, + * pdev->download_len has to be the largest download length of + * any tx frame that will be downloaded. + * This maximum download length is for management tx frames, + * which have an 802.11 header. + */ +#ifdef ATH_11AC_TXCOMPACT + pdev->download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); +#endif + pdev->tx_send_complete_part2 = ol_tx_download_done_ll; + + /* + * For LL, the FW rx desc is alongside the HW rx desc fields in + * the htt_host_rx_desc_base struct/. + */ + pdev->rx_fw_desc_offset = RX_STD_DESC_FW_MSDU_OFFSET; + + htt_h2t_rx_ring_cfg_msg = htt_h2t_rx_ring_cfg_msg_ll; + htt_h2t_rx_ring_rfs_cfg_msg = htt_h2t_rx_ring_rfs_cfg_msg_ll; + } + + return 0; + +fail2: + htt_tx_detach(pdev); + +fail1: + return ret; +} + +QDF_STATUS htt_attach_target(htt_pdev_handle pdev) +{ + QDF_STATUS status; + + status = htt_h2t_ver_req_msg(pdev); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s:%d: could not send h2t_ver_req msg", + __func__, __LINE__); + return status; + } +#if defined(HELIUMPLUS) + /* + * Send the frag_desc info to target. + */ + status = htt_h2t_frag_desc_bank_cfg_msg(pdev); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s:%d: could not send h2t_frag_desc_bank_cfg msg", + __func__, __LINE__); + return status; + } +#endif /* defined(HELIUMPLUS) */ + + + /* + * If applicable, send the rx ring config message to the target. + * The host could wait for the HTT version number confirmation message + * from the target before sending any further HTT messages, but it's + * reasonable to assume that the host and target HTT version numbers + * match, and proceed immediately with the remaining configuration + * handshaking. + */ + + status = htt_h2t_rx_ring_rfs_cfg_msg(pdev); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s:%d: could not send h2t_rx_ring_rfs_cfg msg", + __func__, __LINE__); + return status; + } + + status = htt_h2t_rx_ring_cfg_msg(pdev); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s:%d: could not send h2t_rx_ring_cfg msg", + __func__, __LINE__); + return status; + } + + status = HTT_IPA_CONFIG(pdev, status); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s:%d: could not send h2t_ipa_uc_rsc_cfg msg", + __func__, __LINE__); + return status; + } + + return status; +} + +void htt_detach(htt_pdev_handle pdev) +{ + htt_rx_detach(pdev); + htt_tx_detach(pdev); + htt_htc_pkt_pool_free(pdev); +#ifdef ATH_11AC_TXCOMPACT + htt_htc_misc_pkt_pool_free(pdev); +#endif + HTT_TX_MUTEX_DESTROY(&pdev->credit_mutex); + HTT_TX_MUTEX_DESTROY(&pdev->htt_tx_mutex); + HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(pdev); +} + +/** + * htt_pdev_free() - Free HTT pdev + * @pdev: htt pdev + * + * Return: none + */ +void htt_pdev_free(htt_pdev_handle pdev) +{ + qdf_mem_free(pdev); +} + +void htt_detach_target(htt_pdev_handle pdev) +{ +} + +static inline +int htt_update_endpoint(struct htt_pdev_t *pdev, + uint16_t service_id, HTC_ENDPOINT_ID ep) +{ + struct hif_opaque_softc *hif_ctx; + uint8_t ul = 0xff, dl = 0xff; + int ul_polled, dl_polled; + int tx_service = 0; + int rc = 0; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (qdf_unlikely(!hif_ctx)) { + QDF_ASSERT(hif_ctx); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s:%d: assuming non-tx service.", + __func__, __LINE__); + } else { + ul = dl = 0xff; + if (QDF_STATUS_SUCCESS != + hif_map_service_to_pipe(hif_ctx, service_id, + &ul, &dl, + &ul_polled, &dl_polled)) + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s:%d: assuming non-tx srv.", + __func__, __LINE__); + else + tx_service = (ul != 0xff); + } + if (tx_service) { + /* currently we have only one OUT htt tx service */ + QDF_BUG(service_id == HTT_DATA_MSG_SVC); + + pdev->htc_tx_endpoint = ep; + hif_save_htc_htt_config_endpoint(hif_ctx, ep); + rc = 1; + } + return rc; +} + +int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id) +{ + struct htc_service_connect_req connect; + struct htc_service_connect_resp response; + QDF_STATUS status; + + qdf_mem_zero(&connect, sizeof(connect)); + qdf_mem_zero(&response, sizeof(response)); + + connect.pMetaData = NULL; + connect.MetaDataLength = 0; + connect.EpCallbacks.pContext = pdev; + connect.EpCallbacks.EpTxComplete = htt_h2t_send_complete; + connect.EpCallbacks.EpTxCompleteMultiple = NULL; + connect.EpCallbacks.EpRecv = htt_t2h_msg_handler; + connect.EpCallbacks.ep_resume_tx_queue = htt_tx_resume_handler; + connect.EpCallbacks.ep_padding_credit_update = + htt_tx_padding_credit_update_handler; + + /* rx buffers currently are provided by HIF, not by EpRecvRefill */ + connect.EpCallbacks.EpRecvRefill = NULL; + connect.EpCallbacks.RecvRefillWaterMark = 1; + /* N/A, fill is done by HIF */ + + connect.EpCallbacks.EpSendFull = htt_h2t_full; + /* + * Specify how deep to let a queue get before htc_send_pkt will + * call the EpSendFull function due to excessive send queue depth. + */ + connect.MaxSendQueueDepth = HTT_MAX_SEND_QUEUE_DEPTH; + + /* disable flow control for HTT data message service */ + htt_htc_credit_flow_disable(pdev, &connect); + + /* connect to control service */ + connect.service_id = service_id; + + status = htc_connect_service(pdev->htc_pdev, &connect, &response); + + if (status != QDF_STATUS_SUCCESS) { + if (cds_is_fw_down()) + return -EIO; + + if (status == QDF_STATUS_E_NOMEM || + cds_is_self_recovery_enabled()) + return qdf_status_to_os_return(status); + + QDF_BUG(0); + } + + htt_update_endpoint(pdev, service_id, response.Endpoint); + + /* Start TX HTT2 service if the target support it. */ + htt_htc_tx_htt2_service_start(pdev, &connect, &response); + + return 0; /* success */ +} + +void htt_log_rx_ring_info(htt_pdev_handle pdev) +{ + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: htt pdev is NULL", __func__); + return; + } + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_DEBUG, + "%s: Data Stall Detected with reason 4 (=FW_RX_REFILL_FAILED)." + "src htt rx ring: space for %d elements, filled with %d buffers, buffers in the ring %d, refill debt %d", + __func__, pdev->rx_ring.size, pdev->rx_ring.fill_level, + qdf_atomic_read(&pdev->rx_ring.fill_cnt), + qdf_atomic_read(&pdev->rx_ring.refill_debt)); +} + +void htt_rx_refill_failure(htt_pdev_handle pdev) +{ + QDF_BUG(qdf_atomic_read(&pdev->rx_ring.refill_debt)); +} + +#if HTT_DEBUG_LEVEL > 5 +void htt_display(htt_pdev_handle pdev, int indent) +{ + qdf_print("%*s%s:\n", indent, " ", "HTT"); + qdf_print("%*stx desc pool: %d elems of %d bytes, %d allocated\n", + indent + 4, " ", + pdev->tx_descs.pool_elems, + pdev->tx_descs.size, pdev->tx_descs.alloc_cnt); + qdf_print("%*srx ring: space for %d elems, filled with %d buffers\n", + indent + 4, " ", + pdev->rx_ring.size, pdev->rx_ring.fill_level); + qdf_print("%*sat %pK (%llx paddr)\n", indent + 8, " ", + pdev->rx_ring.buf.paddrs_ring, + (unsigned long long)pdev->rx_ring.base_paddr); + qdf_print("%*snetbuf ring @ %pK\n", indent + 8, " ", + pdev->rx_ring.buf.netbufs_ring); + qdf_print("%*sFW_IDX shadow register: vaddr = %pK, paddr = %llx\n", + indent + 8, " ", + pdev->rx_ring.alloc_idx.vaddr, + (unsigned long long)pdev->rx_ring.alloc_idx.paddr); + qdf_print("%*sSW enqueue idx= %d, SW dequeue idx: desc= %d, buf= %d\n", + indent + 8, " ", *pdev->rx_ring.alloc_idx.vaddr, + pdev->rx_ring.sw_rd_idx.msdu_desc, + pdev->rx_ring.sw_rd_idx.msdu_payld); +} +#endif + +#ifdef IPA_OFFLOAD +/** + * htt_ipa_uc_attach() - Allocate UC data path resources + * @pdev: handle to the HTT instance + * + * Return: 0 success + * none 0 fail + */ +int htt_ipa_uc_attach(struct htt_pdev_t *pdev) +{ + int error; + + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_DEBUG, "%s: enter", + __func__); + + /* TX resource attach */ + error = htt_tx_ipa_uc_attach( + pdev, + ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev), + ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev), + ol_cfg_ipa_uc_tx_partition_base(pdev->ctrl_pdev)); + if (error) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "HTT IPA UC TX attach fail code %d", error); + HTT_ASSERT0(0); + return error; + } + + /* RX resource attach */ + error = htt_rx_ipa_uc_attach( + pdev, qdf_get_pwr2(pdev->rx_ring.fill_level)); + if (error) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "HTT IPA UC RX attach fail code %d", error); + htt_tx_ipa_uc_detach(pdev); + HTT_ASSERT0(0); + return error; + } + + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_DEBUG, "%s: exit", + __func__); + return 0; /* success */ +} + +/** + * htt_ipa_uc_attach() - Remove UC data path resources + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_DEBUG, "%s: enter", + __func__); + + /* TX IPA micro controller detach */ + htt_tx_ipa_uc_detach(pdev); + + /* RX IPA micro controller detach */ + htt_rx_ipa_uc_detach(pdev); + + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_DEBUG, "%s: exit", + __func__); +} + +int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + qdf_shared_mem_t **ce_sr, + qdf_shared_mem_t **tx_comp_ring, + qdf_shared_mem_t **rx_rdy_ring, + qdf_shared_mem_t **rx2_rdy_ring, + qdf_shared_mem_t **rx_proc_done_idx, + qdf_shared_mem_t **rx2_proc_done_idx, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_num_alloc_buffer) +{ + /* Release allocated resource to client */ + *tx_comp_ring = pdev->ipa_uc_tx_rsc.tx_comp_ring; + *rx_rdy_ring = pdev->ipa_uc_rx_rsc.rx_ind_ring; + *rx2_rdy_ring = pdev->ipa_uc_rx_rsc.rx2_ind_ring; + *rx_proc_done_idx = pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx; + *rx2_proc_done_idx = pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx; + *tx_num_alloc_buffer = (uint32_t)pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; + + /* Get copy engine, bus resource */ + htc_ipa_get_ce_resource(pdev->htc_pdev, ce_sr, + ce_sr_ring_size, ce_reg_paddr); + + return 0; +} + +/** + * htt_ipa_uc_set_doorbell_paddr() - Propagate IPA doorbell address + * @pdev: handle to the HTT instance + * @ipa_uc_tx_doorbell_paddr: TX doorbell base physical address + * @ipa_uc_rx_doorbell_paddr: RX doorbell base physical address + * + * Return: 0 success + */ +int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + qdf_dma_addr_t ipa_uc_tx_doorbell_paddr, + qdf_dma_addr_t ipa_uc_rx_doorbell_paddr) +{ + pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr = ipa_uc_tx_doorbell_paddr; + pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr = ipa_uc_rx_doorbell_paddr; + return 0; +} +#endif /* IPA_OFFLOAD */ + +/** + * htt_mark_first_wakeup_packet() - set flag to indicate that + * fw is compatible for marking first packet after wow wakeup + * @pdev: pointer to htt pdev + * @value: 1 for enabled/ 0 for disabled + * + * Return: None + */ +void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, + uint8_t value) +{ + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: htt pdev is NULL", __func__); + return; + } + + pdev->cfg.is_first_wakeup_packet = value; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_fw_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_fw_stats.c new file mode 100644 index 0000000000..759801cf12 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_fw_stats.c @@ -0,0 +1,1345 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file htt_fw_stats.c + * @brief Provide functions to process FW status retrieved from FW. + */ + +#include /* HTC_PACKET */ +#include /* HTT_T2H_MSG_TYPE, etc. */ +#include /* qdf_nbuf_t */ +#include /* qdf_mem_set */ +#include /* ol_fw_tx_dbg_ppdu_base */ + +#include +#include /* htt_tx_status */ + +#include + +#include + +static char *bw_str_arr[] = {"20MHz", "40MHz", "80MHz", "160MHz"}; + +/* + * Defined the macro tx_rate_stats_print_cmn() + * so that this could be used in both + * htt_t2h_stats_tx_rate_stats_print() & + * htt_t2h_stats_tx_rate_stats_print_v2(). + * Each of these functions take a different structure as argument, + * but with common fields in the structures--so using a macro + * to bypass the strong type-checking of a function seems a simple + * trick to use to avoid the code duplication. + */ +#define tx_rate_stats_print_cmn(_tx_rate_info, _concise) \ + do { \ + qdf_nofl_info("TX Rate Info:"); \ + \ + /* MCS */ \ + qdf_nofl_info("%s: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + "MCS counts (0..9)", \ + _tx_rate_info->mcs[0], \ + _tx_rate_info->mcs[1], \ + _tx_rate_info->mcs[2], \ + _tx_rate_info->mcs[3], \ + _tx_rate_info->mcs[4], \ + _tx_rate_info->mcs[5], \ + _tx_rate_info->mcs[6], \ + _tx_rate_info->mcs[7], \ + _tx_rate_info->mcs[8], \ + _tx_rate_info->mcs[9]); \ + \ + /* SGI */ \ + qdf_nofl_info("%s: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + "SGI counts (0..9)", \ + _tx_rate_info->sgi[0], \ + _tx_rate_info->sgi[1], \ + _tx_rate_info->sgi[2], \ + _tx_rate_info->sgi[3], \ + _tx_rate_info->sgi[4], \ + _tx_rate_info->sgi[5], \ + _tx_rate_info->sgi[6], \ + _tx_rate_info->sgi[7], \ + _tx_rate_info->sgi[8], \ + _tx_rate_info->sgi[9]); \ + \ + /* NSS */ \ + qdf_nofl_info("NSS counts: 1x1 %d, 2x2 %d, 3x3 %d", \ + _tx_rate_info->nss[0], \ + _tx_rate_info->nss[1], _tx_rate_info->nss[2]);\ + \ + /* BW */ \ + if (ARRAY_SIZE(_tx_rate_info->bw) == 3) \ + qdf_nofl_info("BW counts: %s %d, %s %d, %s %d", \ + bw_str_arr[0], _tx_rate_info->bw[0], \ + bw_str_arr[1], _tx_rate_info->bw[1], \ + bw_str_arr[2], _tx_rate_info->bw[2]); \ + else if (ARRAY_SIZE(_tx_rate_info->bw) == 4) \ + qdf_nofl_info("BW counts: %s %d, %s %d, %s %d, %s %d", \ + bw_str_arr[0], _tx_rate_info->bw[0], \ + bw_str_arr[1], _tx_rate_info->bw[1], \ + bw_str_arr[2], _tx_rate_info->bw[2], \ + bw_str_arr[3], _tx_rate_info->bw[3]); \ + \ + \ + /* Preamble */ \ + qdf_nofl_info("Preamble (O C H V) counts: %d, %d, %d, %d",\ + _tx_rate_info->pream[0], \ + _tx_rate_info->pream[1], \ + _tx_rate_info->pream[2], \ + _tx_rate_info->pream[3]); \ + \ + /* STBC rate counts */ \ + qdf_nofl_info("%s: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + "STBC rate counts (0..9)", \ + _tx_rate_info->stbc[0], \ + _tx_rate_info->stbc[1], \ + _tx_rate_info->stbc[2], \ + _tx_rate_info->stbc[3], \ + _tx_rate_info->stbc[4], \ + _tx_rate_info->stbc[5], \ + _tx_rate_info->stbc[6], \ + _tx_rate_info->stbc[7], \ + _tx_rate_info->stbc[8], \ + _tx_rate_info->stbc[9]); \ + \ + /* LDPC and TxBF counts */ \ + qdf_nofl_info("LDPC Counts: %d", _tx_rate_info->ldpc);\ + qdf_nofl_info("RTS Counts: %d", _tx_rate_info->rts_cnt);\ + /* RSSI Values for last ack frames */ \ + qdf_nofl_info("Ack RSSI: %d", _tx_rate_info->ack_rssi);\ + } while (0) + +static void htt_t2h_stats_tx_rate_stats_print(wlan_dbg_tx_rate_info_t * + tx_rate_info, int concise) +{ + tx_rate_stats_print_cmn(tx_rate_info, concise); +} + +static void htt_t2h_stats_tx_rate_stats_print_v2(wlan_dbg_tx_rate_info_v2_t * + tx_rate_info, int concise) +{ + tx_rate_stats_print_cmn(tx_rate_info, concise); +} + +/* + * Defined the macro rx_rate_stats_print_cmn() + * so that this could be used in both + * htt_t2h_stats_rx_rate_stats_print() & + * htt_t2h_stats_rx_rate_stats_print_v2(). + * Each of these functions take a different structure as argument, + * but with common fields in the structures -- so using a macro + * to bypass the strong type-checking of a function seems a simple + * trick to use to avoid the code duplication. + */ +#define rx_rate_stats_print_cmn(_rx_phy_info, _concise) \ + do { \ + qdf_nofl_info("RX Rate Info:"); \ + \ + /* MCS */ \ + qdf_nofl_info("%s: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + "MCS counts (0..9)", \ + _rx_phy_info->mcs[0], \ + _rx_phy_info->mcs[1], \ + _rx_phy_info->mcs[2], \ + _rx_phy_info->mcs[3], \ + _rx_phy_info->mcs[4], \ + _rx_phy_info->mcs[5], \ + _rx_phy_info->mcs[6], \ + _rx_phy_info->mcs[7], \ + _rx_phy_info->mcs[8], \ + _rx_phy_info->mcs[9]); \ + \ + /* SGI */ \ + qdf_nofl_info("%s: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + "SGI counts (0..9)", \ + _rx_phy_info->sgi[0], \ + _rx_phy_info->sgi[1], \ + _rx_phy_info->sgi[2], \ + _rx_phy_info->sgi[3], \ + _rx_phy_info->sgi[4], \ + _rx_phy_info->sgi[5], \ + _rx_phy_info->sgi[6], \ + _rx_phy_info->sgi[7], \ + _rx_phy_info->sgi[8], \ + _rx_phy_info->sgi[9]); \ + \ + /* + * NSS \ + * nss[0] just holds the count of non-stbc frames that were \ + * sent at 1x1 rates and nsts holds the count of frames sent \ + * with stbc. \ + * It was decided to not include PPDUs sent w/ STBC in nss[0] \ + * since it would be easier to change the value that needs to \ + * be printed (from stbc+non-stbc count to only non-stbc count)\ + * if needed in the future. Hence the addition in the host code\ + * at this line. + */ \ + qdf_nofl_info("NSS counts: 1x1 %d, 2x2 %d, 3x3 %d, 4x4 %d",\ + _rx_phy_info->nss[0] + _rx_phy_info->nsts,\ + _rx_phy_info->nss[1], \ + _rx_phy_info->nss[2], \ + _rx_phy_info->nss[3]); \ + \ + /* NSTS */ \ + qdf_nofl_info("NSTS count: %d", _rx_phy_info->nsts); \ + \ + /* BW */ \ + if (ARRAY_SIZE(_rx_phy_info->bw) == 3) \ + qdf_nofl_info("BW counts: %s %d, %s %d, %s %d", \ + bw_str_arr[0], _rx_phy_info->bw[0], \ + bw_str_arr[1], _rx_phy_info->bw[1], \ + bw_str_arr[2], _rx_phy_info->bw[2]); \ + else if (ARRAY_SIZE(_rx_phy_info->bw) == 4) \ + qdf_nofl_info("BW counts: %s %d, %s %d, %s %d, %s %d", \ + bw_str_arr[0], _rx_phy_info->bw[0], \ + bw_str_arr[1], _rx_phy_info->bw[1], \ + bw_str_arr[2], _rx_phy_info->bw[2], \ + bw_str_arr[3], _rx_phy_info->bw[3]); \ + \ + /* Preamble */ \ + qdf_nofl_info("Preamble counts: %d, %d, %d, %d, %d, %d",\ + _rx_phy_info->pream[0], \ + _rx_phy_info->pream[1], \ + _rx_phy_info->pream[2], \ + _rx_phy_info->pream[3], \ + _rx_phy_info->pream[4], \ + _rx_phy_info->pream[5]); \ + \ + /* STBC rate counts */ \ + qdf_nofl_info("%s: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d",\ + "STBC rate counts (0..9)", \ + _rx_phy_info->stbc[0], \ + _rx_phy_info->stbc[1], \ + _rx_phy_info->stbc[2], \ + _rx_phy_info->stbc[3], \ + _rx_phy_info->stbc[4], \ + _rx_phy_info->stbc[5], \ + _rx_phy_info->stbc[6], \ + _rx_phy_info->stbc[7], \ + _rx_phy_info->stbc[8], \ + _rx_phy_info->stbc[9]); \ + \ + /* LDPC and TxBF counts */ \ + qdf_nofl_info("LDPC TXBF Counts: %d, %d", \ + _rx_phy_info->ldpc, _rx_phy_info->txbf);\ + /* RSSI Values for last received frames */ \ + qdf_nofl_info("RSSI (data, mgmt): %d, %d", _rx_phy_info->data_rssi,\ + _rx_phy_info->mgmt_rssi); \ + \ + qdf_nofl_info("RSSI Chain 0 (0x%02x 0x%02x 0x%02x 0x%02x)",\ + ((_rx_phy_info->rssi_chain0 >> 24) & 0xff),\ + ((_rx_phy_info->rssi_chain0 >> 16) & 0xff),\ + ((_rx_phy_info->rssi_chain0 >> 8) & 0xff),\ + ((_rx_phy_info->rssi_chain0 >> 0) & 0xff));\ + \ + qdf_nofl_info("RSSI Chain 1 (0x%02x 0x%02x 0x%02x 0x%02x)",\ + ((_rx_phy_info->rssi_chain1 >> 24) & 0xff),\ + ((_rx_phy_info->rssi_chain1 >> 16) & 0xff),\ + ((_rx_phy_info->rssi_chain1 >> 8) & 0xff),\ + ((_rx_phy_info->rssi_chain1 >> 0) & 0xff));\ + \ + qdf_nofl_info("RSSI Chain 2 (0x%02x 0x%02x 0x%02x 0x%02x)",\ + ((_rx_phy_info->rssi_chain2 >> 24) & 0xff),\ + ((_rx_phy_info->rssi_chain2 >> 16) & 0xff),\ + ((_rx_phy_info->rssi_chain2 >> 8) & 0xff),\ + ((_rx_phy_info->rssi_chain2 >> 0) & 0xff));\ + } while (0) + +static void htt_t2h_stats_rx_rate_stats_print(wlan_dbg_rx_rate_info_t * + rx_phy_info, int concise) +{ + rx_rate_stats_print_cmn(rx_phy_info, concise); +} + +static void htt_t2h_stats_rx_rate_stats_print_v2(wlan_dbg_rx_rate_info_v2_t * + rx_phy_info, int concise) +{ + rx_rate_stats_print_cmn(rx_phy_info, concise); +} + +static void +htt_t2h_stats_pdev_stats_print(struct wlan_dbg_stats *wlan_pdev_stats, + int concise) +{ + struct wlan_dbg_tx_stats *tx = &wlan_pdev_stats->tx; + struct wlan_dbg_rx_stats *rx = &wlan_pdev_stats->rx; + + qdf_nofl_info("WAL Pdev stats:"); + qdf_nofl_info("### Tx ###"); + + /* Num HTT cookies queued to dispatch list */ + qdf_nofl_info("comp_queued :%d", tx->comp_queued); + /* Num HTT cookies dispatched */ + qdf_nofl_info("comp_delivered :%d", tx->comp_delivered); + /* Num MSDU queued to WAL */ + qdf_nofl_info("msdu_enqued :%d", tx->msdu_enqued); + /* Num MPDU queued to WAL */ + qdf_nofl_info("mpdu_enqued :%d", tx->mpdu_enqued); + /* Num MSDUs dropped by WMM limit */ + qdf_nofl_info("wmm_drop :%d", tx->wmm_drop); + /* Num Local frames queued */ + qdf_nofl_info("local_enqued :%d", tx->local_enqued); + /* Num Local frames done */ + qdf_nofl_info("local_freed :%d", tx->local_freed); + /* Num queued to HW */ + qdf_nofl_info("hw_queued :%d", tx->hw_queued); + /* Num PPDU reaped from HW */ + qdf_nofl_info("hw_reaped :%d", tx->hw_reaped); + /* Num underruns */ + qdf_nofl_info("mac underrun :%d", tx->underrun); + /* Num underruns */ + qdf_nofl_info("phy underrun :%d", tx->phy_underrun); + /* Num PPDUs cleaned up in TX abort */ + qdf_nofl_info("tx_abort :%d", tx->tx_abort); + /* Num MPDUs requed by SW */ + qdf_nofl_info("mpdus_requed :%d", tx->mpdus_requed); + /* Excessive retries */ +#if defined(AR900B) + qdf_nofl_info("excess retries :%d", tx->tx_xretry); +#endif + /* last data rate */ + qdf_nofl_info("last rc :%d", tx->data_rc); + /* scheduler self triggers */ + qdf_nofl_info("sched self trig :%d", tx->self_triggers); + /* SW retry failures */ + qdf_nofl_info("ampdu retry failed:%d", tx->sw_retry_failure); + /* illegal phy rate errors */ + qdf_nofl_info("illegal rate errs :%d", tx->illgl_rate_phy_err); + /* pdev continuous excessive retries */ + qdf_nofl_info("pdev cont xretry :%d", tx->pdev_cont_xretry); + /* pdev continuous excessive retries */ + qdf_nofl_info("pdev tx timeout :%d", tx->pdev_tx_timeout); + /* pdev resets */ + qdf_nofl_info("pdev resets :%d", tx->pdev_resets); + /* PPDU > txop duration */ + qdf_nofl_info("ppdu txop ovf :%d", tx->txop_ovf); +#if defined(AR900B) + qdf_nofl_info("seq_posted :%d", tx->seq_posted); + qdf_nofl_info("seq_failed_queueing :%d", tx->seq_failed_queueing); + qdf_nofl_info("seq_completed :%d", tx->seq_completed); + qdf_nofl_info("seq_restarted :%d", tx->seq_restarted); + qdf_nofl_info("mu_seq_posted :%d", tx->mu_seq_posted); + qdf_nofl_info("mpdus_sw_flush :%d", tx->mpdus_sw_flush); + qdf_nofl_info("mpdus_hw_filter :%d", tx->mpdus_hw_filter); + qdf_nofl_info("mpdus_truncated :%d", tx->mpdus_truncated); + qdf_nofl_info("mpdus_ack_failed :%d", tx->mpdus_ack_failed); + qdf_nofl_info("mpdus_expired :%d", tx->mpdus_expired); +#endif + + qdf_nofl_info("### Rx ###"); + /* Cnts any change in ring routing mid-ppdu */ + qdf_nofl_info("ppdu_route_change :%d", rx->mid_ppdu_route_change); + /* Total number of statuses processed */ + qdf_nofl_info("status_rcvd :%d", rx->status_rcvd); + /* Extra frags on rings 0-3 */ + qdf_nofl_info("r0_frags :%d", rx->r0_frags); + qdf_nofl_info("r1_frags :%d", rx->r1_frags); + qdf_nofl_info("r2_frags :%d", rx->r2_frags); + qdf_nofl_info("r3_frags :%d", rx->r3_frags); + /* MSDUs / MPDUs delivered to HTT */ + qdf_nofl_info("htt_msdus :%d", rx->htt_msdus); + qdf_nofl_info("htt_mpdus :%d", rx->htt_mpdus); + /* MSDUs / MPDUs delivered to local stack */ + qdf_nofl_info("loc_msdus :%d", rx->loc_msdus); + qdf_nofl_info("loc_mpdus :%d", rx->loc_mpdus); + /* AMSDUs that have more MSDUs than the status ring size */ + qdf_nofl_info("oversize_amsdu :%d", rx->oversize_amsdu); + /* Number of PHY errors */ + qdf_nofl_info("phy_errs :%d", rx->phy_errs); + /* Number of PHY errors dropped */ + qdf_nofl_info("phy_errs dropped :%d", rx->phy_err_drop); + /* Number of mpdu errors - FCS, MIC, ENC etc. */ + qdf_nofl_info("mpdu_errs :%d", rx->mpdu_errs); +#if defined(AR900B) + qdf_nofl_info("rx_ovfl_errs :%d", rx->rx_ovfl_errs); +#endif + +} + +static void +htt_t2h_stats_rx_reorder_stats_print(struct rx_reorder_stats *stats_ptr, + int concise) +{ + qdf_nofl_info("Rx reorder statistics:"); + qdf_nofl_info(" %u non-QoS frames received", + stats_ptr->deliver_non_qos); + qdf_nofl_info(" %u frames received in-order", + stats_ptr->deliver_in_order); + qdf_nofl_info(" %u frames flushed due to timeout", + stats_ptr->deliver_flush_timeout); + qdf_nofl_info(" %u frames flushed due to moving out of window", + stats_ptr->deliver_flush_oow); + qdf_nofl_info(" %u frames flushed due to receiving DELBA", + stats_ptr->deliver_flush_delba); + qdf_nofl_info(" %u frames discarded due to FCS error", + stats_ptr->fcs_error); + qdf_nofl_info(" %u frames discarded due to invalid peer", + stats_ptr->invalid_peer); + qdf_nofl_info + (" %u frames discarded due to duplication (non aggregation)", + stats_ptr->dup_non_aggr); + qdf_nofl_info(" %u frames discarded due to duplication in reorder queue", + stats_ptr->dup_in_reorder); + qdf_nofl_info(" %u frames discarded due to processed before", + stats_ptr->dup_past); + qdf_nofl_info(" %u times reorder timeout happened", + stats_ptr->reorder_timeout); + qdf_nofl_info(" %u times incorrect bar received", + stats_ptr->invalid_bar_ssn); + qdf_nofl_info(" %u times bar ssn reset happened", + stats_ptr->ssn_reset); + qdf_nofl_info(" %u times flushed due to peer delete", + stats_ptr->deliver_flush_delpeer); + qdf_nofl_info(" %u times flushed due to offload", + stats_ptr->deliver_flush_offload); + qdf_nofl_info(" %u times flushed due to ouf of buffer", + stats_ptr->deliver_flush_oob); + qdf_nofl_info(" %u MPDU's dropped due to PN check fail", + stats_ptr->pn_fail); + qdf_nofl_info(" %u MPDU's dropped due to lack of memory", + stats_ptr->store_fail); + qdf_nofl_info(" %u times tid pool alloc succeeded", + stats_ptr->tid_pool_alloc_succ); + qdf_nofl_info(" %u times MPDU pool alloc succeeded", + stats_ptr->mpdu_pool_alloc_succ); + qdf_nofl_info(" %u times MSDU pool alloc succeeded", + stats_ptr->msdu_pool_alloc_succ); + qdf_nofl_info(" %u times tid pool alloc failed", + stats_ptr->tid_pool_alloc_fail); + qdf_nofl_info(" %u times MPDU pool alloc failed", + stats_ptr->mpdu_pool_alloc_fail); + qdf_nofl_info(" %u times MSDU pool alloc failed", + stats_ptr->msdu_pool_alloc_fail); + qdf_nofl_info(" %u times tid pool freed", + stats_ptr->tid_pool_free); + qdf_nofl_info(" %u times MPDU pool freed", + stats_ptr->mpdu_pool_free); + qdf_nofl_info(" %u times MSDU pool freed", + stats_ptr->msdu_pool_free); + qdf_nofl_info(" %u MSDUs undelivered to HTT, queued to Rx MSDU free list", + stats_ptr->msdu_queued); + qdf_nofl_info(" %u MSDUs released from Rx MSDU list to MAC ring", + stats_ptr->msdu_recycled); + qdf_nofl_info(" %u MPDUs with invalid peer but A2 found in AST", + stats_ptr->invalid_peer_a2_in_ast); + qdf_nofl_info(" %u MPDUs with invalid peer but A3 found in AST", + stats_ptr->invalid_peer_a3_in_ast); + qdf_nofl_info(" %u MPDUs with invalid peer, Broadcast or Mulitcast frame", + stats_ptr->invalid_peer_bmc_mpdus); + qdf_nofl_info(" %u MSDUs with err attention word", + stats_ptr->rxdesc_err_att); + qdf_nofl_info(" %u MSDUs with flag of peer_idx_invalid", + stats_ptr->rxdesc_err_peer_idx_inv); + qdf_nofl_info(" %u MSDUs with flag of peer_idx_timeout", + stats_ptr->rxdesc_err_peer_idx_to); + qdf_nofl_info(" %u MSDUs with flag of overflow", + stats_ptr->rxdesc_err_ov); + qdf_nofl_info(" %u MSDUs with flag of msdu_length_err", + stats_ptr->rxdesc_err_msdu_len); + qdf_nofl_info(" %u MSDUs with flag of mpdu_length_err", + stats_ptr->rxdesc_err_mpdu_len); + qdf_nofl_info(" %u MSDUs with flag of tkip_mic_err", + stats_ptr->rxdesc_err_tkip_mic); + qdf_nofl_info(" %u MSDUs with flag of decrypt_err", + stats_ptr->rxdesc_err_decrypt); + qdf_nofl_info(" %u MSDUs with flag of fcs_err", + stats_ptr->rxdesc_err_fcs); + qdf_nofl_info(" %u Unicast frames with invalid peer handler", + stats_ptr->rxdesc_uc_msdus_inv_peer); + qdf_nofl_info(" %u unicast frame to DUT with invalid peer handler", + stats_ptr->rxdesc_direct_msdus_inv_peer); + qdf_nofl_info(" %u Broadcast/Multicast frames with invalid peer handler", + stats_ptr->rxdesc_bmc_msdus_inv_peer); + qdf_nofl_info(" %u MSDUs dropped due to no first MSDU flag", + stats_ptr->rxdesc_no_1st_msdu); + qdf_nofl_info(" %u MSDUs dropped due to ring overflow", + stats_ptr->msdu_drop_ring_ov); + qdf_nofl_info(" %u MSDUs dropped due to FC mismatch", + stats_ptr->msdu_drop_fc_mismatch); + qdf_nofl_info(" %u MSDUs dropped due to mgt frame in Remote ring", + stats_ptr->msdu_drop_mgmt_remote_ring); + qdf_nofl_info(" %u MSDUs dropped due to misc non error", + stats_ptr->msdu_drop_misc); + qdf_nofl_info(" %u MSDUs go to offload before reorder", + stats_ptr->offload_msdu_wal); + qdf_nofl_info(" %u data frame dropped by offload after reorder", + stats_ptr->offload_msdu_reorder); + qdf_nofl_info(" %u MPDUs with SN in the past & within BA window", + stats_ptr->dup_past_within_window); + qdf_nofl_info(" %u MPDUs with SN in the past & outside BA window", + stats_ptr->dup_past_outside_window); +} + +static void +htt_t2h_stats_rx_rem_buf_stats_print( + struct rx_remote_buffer_mgmt_stats *stats_ptr, int concise) +{ + qdf_nofl_info("Rx Remote Buffer Statistics:"); + qdf_nofl_info(" %u MSDU's reaped for Rx processing", + stats_ptr->remote_reaped); + qdf_nofl_info(" %u MSDU's recycled within firmware", + stats_ptr->remote_recycled); + qdf_nofl_info(" %u MSDU's stored by Data Rx", + stats_ptr->data_rx_msdus_stored); + qdf_nofl_info(" %u HTT indications from WAL Rx MSDU", + stats_ptr->wal_rx_ind); + qdf_nofl_info(" %u HTT indications unconsumed from WAL Rx MSDU", + stats_ptr->wal_rx_ind_unconsumed); + qdf_nofl_info(" %u HTT indications from Data Rx MSDU", + stats_ptr->data_rx_ind); + qdf_nofl_info(" %u HTT indications unconsumed from Data Rx MSDU", + stats_ptr->data_rx_ind_unconsumed); + qdf_nofl_info(" %u HTT indications from ATHBUF", + stats_ptr->athbuf_rx_ind); + qdf_nofl_info(" %u Remote buffers requested for refill", + stats_ptr->refill_buf_req); + qdf_nofl_info(" %u Remote buffers filled by host", + stats_ptr->refill_buf_rsp); + qdf_nofl_info(" %u times MAC has no buffers", + stats_ptr->mac_no_bufs); + qdf_nofl_info(" %u times f/w write & read indices on MAC ring are equal", + stats_ptr->fw_indices_equal); + qdf_nofl_info(" %u times f/w has no remote buffers to post to MAC", + stats_ptr->host_no_bufs); +} + +static void +htt_t2h_stats_txbf_info_buf_stats_print( + struct wlan_dbg_txbf_data_stats *stats_ptr) +{ + qdf_nofl_info("TXBF data Statistics:"); + qdf_nofl_info("tx_txbf_vht (0..9): %u, %u, %u, %u, %u, %u, %u, %u, %u, %d", + stats_ptr->tx_txbf_vht[0], + stats_ptr->tx_txbf_vht[1], + stats_ptr->tx_txbf_vht[2], + stats_ptr->tx_txbf_vht[3], + stats_ptr->tx_txbf_vht[4], + stats_ptr->tx_txbf_vht[5], + stats_ptr->tx_txbf_vht[6], + stats_ptr->tx_txbf_vht[7], + stats_ptr->tx_txbf_vht[8], + stats_ptr->tx_txbf_vht[9]); + qdf_nofl_info("rx_txbf_vht (0..9): %u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->rx_txbf_vht[0], + stats_ptr->rx_txbf_vht[1], + stats_ptr->rx_txbf_vht[2], + stats_ptr->rx_txbf_vht[3], + stats_ptr->rx_txbf_vht[4], + stats_ptr->rx_txbf_vht[5], + stats_ptr->rx_txbf_vht[6], + stats_ptr->rx_txbf_vht[7], + stats_ptr->rx_txbf_vht[8], + stats_ptr->rx_txbf_vht[9]); + qdf_nofl_info("tx_txbf_ht (0..7): %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->tx_txbf_ht[0], + stats_ptr->tx_txbf_ht[1], + stats_ptr->tx_txbf_ht[2], + stats_ptr->tx_txbf_ht[3], + stats_ptr->tx_txbf_ht[4], + stats_ptr->tx_txbf_ht[5], + stats_ptr->tx_txbf_ht[6], + stats_ptr->tx_txbf_ht[7]); + qdf_nofl_info("tx_txbf_ofdm (0..7): %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->tx_txbf_ofdm[0], + stats_ptr->tx_txbf_ofdm[1], + stats_ptr->tx_txbf_ofdm[2], + stats_ptr->tx_txbf_ofdm[3], + stats_ptr->tx_txbf_ofdm[4], + stats_ptr->tx_txbf_ofdm[5], + stats_ptr->tx_txbf_ofdm[6], + stats_ptr->tx_txbf_ofdm[7]); + qdf_nofl_info("tx_txbf_cck (0..6): %u, %u, %u, %u, %u, %u, %u", + stats_ptr->tx_txbf_cck[0], + stats_ptr->tx_txbf_cck[1], + stats_ptr->tx_txbf_cck[2], + stats_ptr->tx_txbf_cck[3], + stats_ptr->tx_txbf_cck[4], + stats_ptr->tx_txbf_cck[5], + stats_ptr->tx_txbf_cck[6]); +} + +static void +htt_t2h_stats_txbf_snd_buf_stats_print( + struct wlan_dbg_txbf_snd_stats *stats_ptr) +{ + qdf_nofl_info("TXBF snd Buffer Statistics:"); + qdf_nofl_info("cbf_20: %u, %u, %u, %u", + stats_ptr->cbf_20[0], + stats_ptr->cbf_20[1], + stats_ptr->cbf_20[2], + stats_ptr->cbf_20[3]); + qdf_nofl_info("cbf_40: %u, %u, %u, %u", + stats_ptr->cbf_40[0], + stats_ptr->cbf_40[1], + stats_ptr->cbf_40[2], + stats_ptr->cbf_40[3]); + qdf_nofl_info("cbf_80: %u, %u, %u, %u", + stats_ptr->cbf_80[0], + stats_ptr->cbf_80[1], + stats_ptr->cbf_80[2], + stats_ptr->cbf_80[3]); + qdf_nofl_info("sounding: %u, %u, %u, %u, %u, %u, %u, %u, %u", + stats_ptr->sounding[0], + stats_ptr->sounding[1], + stats_ptr->sounding[2], + stats_ptr->sounding[3], + stats_ptr->sounding[4], + stats_ptr->sounding[5], + stats_ptr->sounding[6], + stats_ptr->sounding[7], + stats_ptr->sounding[8]); +} + +static void +htt_t2h_stats_tx_selfgen_buf_stats_print( + struct wlan_dbg_tx_selfgen_stats *stats_ptr) +{ + qdf_nofl_info("Tx selfgen Buffer Statistics:"); + qdf_nofl_info(" %u su_ndpa", + stats_ptr->su_ndpa); + qdf_nofl_info(" %u mu_ndp", + stats_ptr->mu_ndp); + qdf_nofl_info(" %u mu_ndpa", + stats_ptr->mu_ndpa); + qdf_nofl_info(" %u mu_ndp", + stats_ptr->mu_ndp); + qdf_nofl_info(" %u mu_brpoll_1", + stats_ptr->mu_brpoll_1); + qdf_nofl_info(" %u mu_brpoll_2", + stats_ptr->mu_brpoll_2); + qdf_nofl_info(" %u mu_bar_1", + stats_ptr->mu_bar_1); + qdf_nofl_info(" %u mu_bar_2", + stats_ptr->mu_bar_2); + qdf_nofl_info(" %u cts_burst", + stats_ptr->cts_burst); + qdf_nofl_info(" %u su_ndp_err", + stats_ptr->su_ndp_err); + qdf_nofl_info(" %u su_ndpa_err", + stats_ptr->su_ndpa_err); + qdf_nofl_info(" %u mu_ndp_err", + stats_ptr->mu_ndp_err); + qdf_nofl_info(" %u mu_brp1_err", + stats_ptr->mu_brp1_err); + qdf_nofl_info(" %u mu_brp2_err", + stats_ptr->mu_brp2_err); +} + +static void +htt_t2h_stats_wifi2_error_stats_print( + struct wlan_dbg_wifi2_error_stats *stats_ptr) +{ + int i; + + qdf_nofl_info("Scheduler error Statistics:"); + qdf_nofl_info("urrn_stats: "); + qdf_nofl_info("urrn_stats: %d, %d, %d", + stats_ptr->urrn_stats[0], + stats_ptr->urrn_stats[1], + stats_ptr->urrn_stats[2]); + qdf_nofl_info("flush_errs (0..%d): ", + WHAL_DBG_FLUSH_REASON_MAXCNT); + for (i = 0; i < WHAL_DBG_FLUSH_REASON_MAXCNT; i++) + qdf_nofl_info(" %u", stats_ptr->flush_errs[i]); + qdf_nofl_info("\n"); + qdf_nofl_info("schd_stall_errs (0..3): "); + qdf_nofl_info("%d, %d, %d, %d", + stats_ptr->schd_stall_errs[0], + stats_ptr->schd_stall_errs[1], + stats_ptr->schd_stall_errs[2], + stats_ptr->schd_stall_errs[3]); + qdf_nofl_info("schd_cmd_result (0..%d): ", + WHAL_DBG_CMD_RESULT_MAXCNT); + for (i = 0; i < WHAL_DBG_CMD_RESULT_MAXCNT; i++) + qdf_nofl_info(" %u", stats_ptr->schd_cmd_result[i]); + qdf_nofl_info("\n"); + qdf_nofl_info("sifs_status (0..%d): ", + WHAL_DBG_SIFS_STATUS_MAXCNT); + for (i = 0; i < WHAL_DBG_SIFS_STATUS_MAXCNT; i++) + qdf_nofl_info(" %u", stats_ptr->sifs_status[i]); + qdf_nofl_info("\n"); + qdf_nofl_info("phy_errs (0..%d): ", + WHAL_DBG_PHY_ERR_MAXCNT); + for (i = 0; i < WHAL_DBG_PHY_ERR_MAXCNT; i++) + qdf_nofl_info(" %u", stats_ptr->phy_errs[i]); + qdf_nofl_info("\n"); + qdf_nofl_info(" %u rx_rate_inval", + stats_ptr->rx_rate_inval); +} + +static void +htt_t2h_rx_musu_ndpa_pkts_stats_print( + struct rx_txbf_musu_ndpa_pkts_stats *stats_ptr) +{ + qdf_nofl_info("Rx TXBF MU/SU Packets and NDPA Statistics:"); + qdf_nofl_info(" %u Number of TXBF MU packets received", + stats_ptr->number_mu_pkts); + qdf_nofl_info(" %u Number of TXBF SU packets received", + stats_ptr->number_su_pkts); + qdf_nofl_info(" %u Number of TXBF directed NDPA", + stats_ptr->txbf_directed_ndpa_count); + qdf_nofl_info(" %u Number of TXBF retried NDPA", + stats_ptr->txbf_ndpa_retry_count); + qdf_nofl_info(" %u Total number of TXBF NDPA", + stats_ptr->txbf_total_ndpa_count); +} + +#define HTT_TICK_TO_USEC(ticks, microsec_per_tick) (ticks * microsec_per_tick) +static inline int htt_rate_flags_to_mhz(uint8_t rate_flags) +{ + if (rate_flags & 0x20) + return 40; /* WHAL_RC_FLAG_40MHZ */ + if (rate_flags & 0x40) + return 80; /* WHAL_RC_FLAG_80MHZ */ + if (rate_flags & 0x80) + return 160; /* WHAL_RC_FLAG_160MHZ */ + return 20; +} + +#define HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW 64 + +static void +htt_t2h_tx_ppdu_bitmaps_pr(uint32_t *queued_ptr, uint32_t *acked_ptr) +{ + char queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; + char acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW + 1]; + int i, j, word; + + qdf_mem_set(queued_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '0'); + qdf_mem_set(acked_str, HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW, '-'); + i = 0; + for (word = 0; word < 2; word++) { + uint32_t queued = *(queued_ptr + word); + uint32_t acked = *(acked_ptr + word); + + for (j = 0; j < 32; j++, i++) { + if (queued & (1 << j)) { + queued_str[i] = '1'; + acked_str[i] = (acked & (1 << j)) ? 'y' : 'N'; + } + } + } + queued_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; + acked_str[HTT_FW_STATS_MAX_BLOCK_ACK_WINDOW] = '\0'; + qdf_nofl_info("%s\n", queued_str); + qdf_nofl_info("%s\n", acked_str); +} + +static inline uint16_t htt_msg_read16(uint16_t *p16) +{ +#ifdef BIG_ENDIAN_HOST + /* + * During upload, the bytes within each uint32_t word were + * swapped by the HIF HW. This results in the lower and upper bytes + * of each uint16_t to be in the correct big-endian order with + * respect to each other, but for each even-index uint16_t to + * have its position switched with its successor neighbor uint16_t. + * Undo this uint16_t position swapping. + */ + return (((size_t) p16) & 0x2) ? *(p16 - 1) : *(p16 + 1); +#else + return *p16; +#endif +} + +static inline uint8_t htt_msg_read8(uint8_t *p8) +{ +#ifdef BIG_ENDIAN_HOST + /* + * During upload, the bytes within each uint32_t word were + * swapped by the HIF HW. + * Undo this byte swapping. + */ + switch (((size_t) p8) & 0x3) { + case 0: + return *(p8 + 3); + case 1: + return *(p8 + 1); + case 2: + return *(p8 - 1); + default /* 3 */: + return *(p8 - 3); + } +#else + return *p8; +#endif +} + +static void htt_make_u8_list_str(uint32_t *aligned_data, + char *buffer, int space, int max_elems) +{ + uint8_t *p8 = (uint8_t *) aligned_data; + char *buf_p = buffer; + + while (max_elems-- > 0) { + int bytes; + uint8_t val; + + val = htt_msg_read8(p8); + if (val == 0) + /* not enough data to fill the reserved msg buffer*/ + break; + + bytes = qdf_snprint(buf_p, space, "%d,", val); + space -= bytes; + if (space > 0) + buf_p += bytes; + else /* not enough print buffer space for all the data */ + break; + p8++; + } + if (buf_p == buffer) + *buf_p = '\0'; /* nothing was written */ + else + *(buf_p - 1) = '\0'; /* erase the final comma */ + +} + +static void htt_make_u16_list_str(uint32_t *aligned_data, + char *buffer, int space, int max_elems) +{ + uint16_t *p16 = (uint16_t *) aligned_data; + char *buf_p = buffer; + + while (max_elems-- > 0) { + int bytes; + uint16_t val; + + val = htt_msg_read16(p16); + if (val == 0) + /* not enough data to fill the reserved msg buffer */ + break; + bytes = qdf_snprint(buf_p, space, "%d,", val); + space -= bytes; + if (space > 0) + buf_p += bytes; + else /* not enough print buffer space for all the data */ + break; + + p16++; + } + if (buf_p == buffer) + *buf_p = '\0'; /* nothing was written */ + else + *(buf_p - 1) = '\0'; /* erase the final comma */ +} + +static void +htt_t2h_tx_ppdu_log_print(struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr, + struct ol_fw_tx_dbg_ppdu_base *record, + int length, int concise) +{ + int i; + int record_size; + int calculated_record_size; + int num_records; + + record_size = sizeof(*record); + calculated_record_size = record_size + + hdr->mpdu_bytes_array_len * sizeof(uint16_t); + if (calculated_record_size < record_size) { + qdf_err("Overflow due to record and hdr->mpdu_bytes_array_len %u", + hdr->mpdu_bytes_array_len); + return; + } + record_size = calculated_record_size; + calculated_record_size += hdr->mpdu_msdus_array_len * sizeof(uint8_t); + if (calculated_record_size < record_size) { + qdf_err("Overflow due to hdr->mpdu_msdus_array_len %u", + hdr->mpdu_msdus_array_len); + return; + } + record_size = calculated_record_size; + calculated_record_size += hdr->msdu_bytes_array_len * sizeof(uint16_t); + if (calculated_record_size < record_size) { + qdf_err("Overflow due to hdr->msdu_bytes_array_len %u", + hdr->msdu_bytes_array_len); + return; + } + record_size = calculated_record_size; + num_records = (length - sizeof(*hdr)) / record_size; + if (num_records < 0) { + qdf_err("Underflow due to length %d", length); + return; + } + qdf_nofl_info("Tx PPDU log elements: num_records %d", num_records); + + for (i = 0; i < num_records; i++) { + uint16_t start_seq_num; + uint16_t start_pn_lsbs; + uint8_t num_mpdus; + uint16_t peer_id; + uint8_t ext_tid; + uint8_t rate_code; + uint8_t rate_flags; + uint8_t tries; + uint8_t complete; + uint32_t time_enqueue_us; + uint32_t time_completion_us; + uint32_t *msg_word = (uint32_t *) record; + + /* fields used for both concise and complete printouts */ + start_seq_num = + ((*(msg_word + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_WORD)) & + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_M) >> + OL_FW_TX_DBG_PPDU_START_SEQ_NUM_S; + complete = + ((*(msg_word + OL_FW_TX_DBG_PPDU_COMPLETE_WORD)) & + OL_FW_TX_DBG_PPDU_COMPLETE_M) >> + OL_FW_TX_DBG_PPDU_COMPLETE_S; + + /* fields used only for complete printouts */ + if (!concise) { +#define BUF_SIZE 80 + char buf[BUF_SIZE]; + uint8_t *p8; + uint8_t *calculated_p8; + + time_enqueue_us = + HTT_TICK_TO_USEC(record->timestamp_enqueue, + hdr->microsec_per_tick); + time_completion_us = + HTT_TICK_TO_USEC(record->timestamp_completion, + hdr->microsec_per_tick); + + start_pn_lsbs = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_START_PN_LSBS_WORD)) & + OL_FW_TX_DBG_PPDU_START_PN_LSBS_M) >> + OL_FW_TX_DBG_PPDU_START_PN_LSBS_S; + num_mpdus = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_NUM_MPDUS_WORD))& + OL_FW_TX_DBG_PPDU_NUM_MPDUS_M) >> + OL_FW_TX_DBG_PPDU_NUM_MPDUS_S; + peer_id = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_PEER_ID_WORD)) & + OL_FW_TX_DBG_PPDU_PEER_ID_M) >> + OL_FW_TX_DBG_PPDU_PEER_ID_S; + ext_tid = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_EXT_TID_WORD)) & + OL_FW_TX_DBG_PPDU_EXT_TID_M) >> + OL_FW_TX_DBG_PPDU_EXT_TID_S; + rate_code = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_RATE_CODE_WORD))& + OL_FW_TX_DBG_PPDU_RATE_CODE_M) >> + OL_FW_TX_DBG_PPDU_RATE_CODE_S; + rate_flags = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_RATE_FLAGS_WORD))& + OL_FW_TX_DBG_PPDU_RATE_FLAGS_M) >> + OL_FW_TX_DBG_PPDU_RATE_FLAGS_S; + tries = + ((*(msg_word + + OL_FW_TX_DBG_PPDU_TRIES_WORD)) & + OL_FW_TX_DBG_PPDU_TRIES_M) >> + OL_FW_TX_DBG_PPDU_TRIES_S; + + qdf_nofl_info(" - PPDU tx to peer %d, TID %d", peer_id, + ext_tid); + qdf_nofl_info(" start seq num= %u, start PN LSBs= %#04x", + start_seq_num, start_pn_lsbs); + qdf_nofl_info(" PPDU: %d MPDUs, (?) MSDUs, %d bytes", + num_mpdus, + /* num_msdus-not yet computed in target */ + record->num_bytes); + if (complete) { + qdf_nofl_info(" enqueued: %u, completed: %u usec)", + time_enqueue_us, + time_completion_us); + qdf_nofl_info(" %d tries, last tx used rate %d ", + tries, rate_code); + qdf_nofl_info("on %d MHz chan (flags = %#x)", + htt_rate_flags_to_mhz + (rate_flags), rate_flags); + qdf_nofl_info(" enqueued and acked MPDU bitmaps:"); + htt_t2h_tx_ppdu_bitmaps_pr(msg_word + + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD, + msg_word + + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD); + } else { + qdf_nofl_info(" enqueued: %d us, not yet completed", + time_enqueue_us); + } + /* skip the regular msg fields to reach the tail area */ + p8 = (uint8_t *) record; + calculated_p8 = p8 + sizeof(struct ol_fw_tx_dbg_ppdu_base); + if (calculated_p8 < p8) { + qdf_err("Overflow due to record %pK", p8); + continue; + } + p8 = calculated_p8; + if (hdr->mpdu_bytes_array_len) { + htt_make_u16_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr-> + mpdu_bytes_array_len); + qdf_nofl_info(" MPDU bytes: %s", buf); + } + calculated_p8 += hdr->mpdu_bytes_array_len * sizeof(uint16_t); + if (calculated_p8 < p8) { + qdf_err("Overflow due to hdr->mpdu_bytes_array_len %u", + hdr->mpdu_bytes_array_len); + continue; + } + p8 = calculated_p8; + if (hdr->mpdu_msdus_array_len) { + htt_make_u8_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr->mpdu_msdus_array_len); + qdf_nofl_info(" MPDU MSDUs: %s", buf); + } + calculated_p8 += hdr->mpdu_msdus_array_len * sizeof(uint8_t); + if (calculated_p8 < p8) { + qdf_err("Overflow due to hdr->mpdu_msdus_array_len %u", + hdr->mpdu_msdus_array_len); + continue; + } + p8 = calculated_p8; + if (hdr->msdu_bytes_array_len) { + htt_make_u16_list_str((uint32_t *) p8, buf, + BUF_SIZE, + hdr-> + msdu_bytes_array_len); + qdf_nofl_info(" MSDU bytes: %s", buf); + } + } else { + /* concise */ + qdf_nofl_info("start seq num = %u ", start_seq_num); + qdf_nofl_info("enqueued and acked MPDU bitmaps:"); + if (complete) { + htt_t2h_tx_ppdu_bitmaps_pr(msg_word + + OL_FW_TX_DBG_PPDU_ENQUEUED_LSBS_WORD, + msg_word + + OL_FW_TX_DBG_PPDU_BLOCK_ACK_LSBS_WORD); + } else { + qdf_nofl_info("(not completed)"); + } + } + record = (struct ol_fw_tx_dbg_ppdu_base *) + (((uint8_t *) record) + record_size); + } +} + +static void htt_t2h_stats_tidq_stats_print( + struct wlan_dbg_tidq_stats *tidq_stats, int concise) +{ + qdf_nofl_info("TID QUEUE STATS:"); + qdf_nofl_info("tid_txq_stats: %u", tidq_stats->wlan_dbg_tid_txq_status); + qdf_nofl_info("num_pkts_queued(0..9):"); + qdf_nofl_info("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.num_pkts_queued[0], + tidq_stats->txq_st.num_pkts_queued[1], + tidq_stats->txq_st.num_pkts_queued[2], + tidq_stats->txq_st.num_pkts_queued[3], + tidq_stats->txq_st.num_pkts_queued[4], + tidq_stats->txq_st.num_pkts_queued[5], + tidq_stats->txq_st.num_pkts_queued[6], + tidq_stats->txq_st.num_pkts_queued[7], + tidq_stats->txq_st.num_pkts_queued[8], + tidq_stats->txq_st.num_pkts_queued[9]); + qdf_nofl_info("tid_hw_qdepth(0..19):"); + qdf_nofl_info("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_hw_qdepth[0], + tidq_stats->txq_st.tid_hw_qdepth[1], + tidq_stats->txq_st.tid_hw_qdepth[2], + tidq_stats->txq_st.tid_hw_qdepth[3], + tidq_stats->txq_st.tid_hw_qdepth[4], + tidq_stats->txq_st.tid_hw_qdepth[5], + tidq_stats->txq_st.tid_hw_qdepth[6], + tidq_stats->txq_st.tid_hw_qdepth[7], + tidq_stats->txq_st.tid_hw_qdepth[8], + tidq_stats->txq_st.tid_hw_qdepth[9]); + qdf_nofl_info("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_hw_qdepth[10], + tidq_stats->txq_st.tid_hw_qdepth[11], + tidq_stats->txq_st.tid_hw_qdepth[12], + tidq_stats->txq_st.tid_hw_qdepth[13], + tidq_stats->txq_st.tid_hw_qdepth[14], + tidq_stats->txq_st.tid_hw_qdepth[15], + tidq_stats->txq_st.tid_hw_qdepth[16], + tidq_stats->txq_st.tid_hw_qdepth[17], + tidq_stats->txq_st.tid_hw_qdepth[18], + tidq_stats->txq_st.tid_hw_qdepth[19]); + qdf_nofl_info("tid_sw_qdepth(0..19):"); + qdf_nofl_info("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_sw_qdepth[0], + tidq_stats->txq_st.tid_sw_qdepth[1], + tidq_stats->txq_st.tid_sw_qdepth[2], + tidq_stats->txq_st.tid_sw_qdepth[3], + tidq_stats->txq_st.tid_sw_qdepth[4], + tidq_stats->txq_st.tid_sw_qdepth[5], + tidq_stats->txq_st.tid_sw_qdepth[6], + tidq_stats->txq_st.tid_sw_qdepth[7], + tidq_stats->txq_st.tid_sw_qdepth[8], + tidq_stats->txq_st.tid_sw_qdepth[9]); + qdf_nofl_info("%u, %u, %u, %u, %u, %u, %u, %u, %u, %u", + tidq_stats->txq_st.tid_sw_qdepth[10], + tidq_stats->txq_st.tid_sw_qdepth[11], + tidq_stats->txq_st.tid_sw_qdepth[12], + tidq_stats->txq_st.tid_sw_qdepth[13], + tidq_stats->txq_st.tid_sw_qdepth[14], + tidq_stats->txq_st.tid_sw_qdepth[15], + tidq_stats->txq_st.tid_sw_qdepth[16], + tidq_stats->txq_st.tid_sw_qdepth[17], + tidq_stats->txq_st.tid_sw_qdepth[18], + tidq_stats->txq_st.tid_sw_qdepth[19]); +} + +static void htt_t2h_stats_tx_mu_stats_print( + struct wlan_dbg_tx_mu_stats *tx_mu_stats, int concise) +{ + qdf_nofl_info("TX MU STATS:"); + qdf_nofl_info("mu_sch_nusers_2: %u", tx_mu_stats->mu_sch_nusers_2); + qdf_nofl_info("mu_sch_nusers_3: %u", tx_mu_stats->mu_sch_nusers_3); + qdf_nofl_info("mu_mpdus_queued_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_queued_usr[0], + tx_mu_stats->mu_mpdus_queued_usr[1], + tx_mu_stats->mu_mpdus_queued_usr[2], + tx_mu_stats->mu_mpdus_queued_usr[3]); + qdf_nofl_info("mu_mpdus_tried_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_tried_usr[0], + tx_mu_stats->mu_mpdus_tried_usr[1], + tx_mu_stats->mu_mpdus_tried_usr[2], + tx_mu_stats->mu_mpdus_tried_usr[3]); + qdf_nofl_info("mu_mpdus_failed_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_failed_usr[0], + tx_mu_stats->mu_mpdus_failed_usr[1], + tx_mu_stats->mu_mpdus_failed_usr[2], + tx_mu_stats->mu_mpdus_failed_usr[3]); + qdf_nofl_info("mu_mpdus_requeued_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdus_requeued_usr[0], + tx_mu_stats->mu_mpdus_requeued_usr[1], + tx_mu_stats->mu_mpdus_requeued_usr[2], + tx_mu_stats->mu_mpdus_requeued_usr[3]); + qdf_nofl_info("mu_err_no_ba_usr: %u, %u, %u, %u", + tx_mu_stats->mu_err_no_ba_usr[0], + tx_mu_stats->mu_err_no_ba_usr[1], + tx_mu_stats->mu_err_no_ba_usr[2], + tx_mu_stats->mu_err_no_ba_usr[3]); + qdf_nofl_info("mu_mpdu_underrun_usr: %u, %u, %u, %u", + tx_mu_stats->mu_mpdu_underrun_usr[0], + tx_mu_stats->mu_mpdu_underrun_usr[1], + tx_mu_stats->mu_mpdu_underrun_usr[2], + tx_mu_stats->mu_mpdu_underrun_usr[3]); + qdf_nofl_info("mu_ampdu_underrun_usr: %u, %u, %u, %u", + tx_mu_stats->mu_ampdu_underrun_usr[0], + tx_mu_stats->mu_ampdu_underrun_usr[1], + tx_mu_stats->mu_ampdu_underrun_usr[2], + tx_mu_stats->mu_ampdu_underrun_usr[3]); + +} + +static void htt_t2h_stats_sifs_resp_stats_print( + struct wlan_dbg_sifs_resp_stats *sifs_stats, int concise) +{ + qdf_nofl_info("SIFS RESP STATS:"); + qdf_nofl_info("num of ps-poll trigger frames: %u", + sifs_stats->ps_poll_trigger); + qdf_nofl_info("num of uapsd trigger frames: %u", + sifs_stats->uapsd_trigger); + qdf_nofl_info("num of data trigger frames: %u, %u", + sifs_stats->qb_data_trigger[0], + sifs_stats->qb_data_trigger[1]); + qdf_nofl_info("num of bar trigger frames: %u, %u", + sifs_stats->qb_bar_trigger[0], + sifs_stats->qb_bar_trigger[1]); + qdf_nofl_info("num of ppdu transmitted at SIFS interval: %u", + sifs_stats->sifs_resp_data); + qdf_nofl_info("num of ppdu failed to meet SIFS resp timing: %u", + sifs_stats->sifs_resp_err); +} + +void htt_t2h_stats_print(uint8_t *stats_data, int concise) +{ + uint32_t *msg_word = (uint32_t *) stats_data; + enum htt_dbg_stats_type type; + enum htt_dbg_stats_status status; + int length; + + type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); + status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); + length = HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); + + /* check that we've been given a valid stats type */ + if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) { + return; + } else if (status == HTT_DBG_STATS_STATUS_INVALID) { + qdf_debug("Target doesn't support stats type %d", type); + return; + } else if (status == HTT_DBG_STATS_STATUS_ERROR) { + qdf_debug("Target couldn't upload stats type %d (no mem?)", + type); + return; + } + /* got valid (though perhaps partial) stats - process them */ + switch (type) { + case HTT_DBG_STATS_WAL_PDEV_TXRX: + { + struct wlan_dbg_stats *wlan_dbg_stats_ptr; + + wlan_dbg_stats_ptr = + (struct wlan_dbg_stats *)(msg_word + 1); + htt_t2h_stats_pdev_stats_print(wlan_dbg_stats_ptr, + concise); + break; + } + case HTT_DBG_STATS_RX_REORDER: + { + struct rx_reorder_stats *rx_reorder_stats_ptr; + + rx_reorder_stats_ptr = + (struct rx_reorder_stats *)(msg_word + 1); + htt_t2h_stats_rx_reorder_stats_print + (rx_reorder_stats_ptr, concise); + break; + } + + case HTT_DBG_STATS_RX_RATE_INFO: + { + wlan_dbg_rx_rate_info_t *rx_phy_info; + + rx_phy_info = (wlan_dbg_rx_rate_info_t *) (msg_word + 1); + htt_t2h_stats_rx_rate_stats_print(rx_phy_info, concise); + break; + } + case HTT_DBG_STATS_RX_RATE_INFO_V2: + { + wlan_dbg_rx_rate_info_v2_t *rx_phy_info; + + rx_phy_info = (wlan_dbg_rx_rate_info_v2_t *) (msg_word + 1); + htt_t2h_stats_rx_rate_stats_print_v2(rx_phy_info, concise); + break; + } + case HTT_DBG_STATS_TX_PPDU_LOG: + { + struct ol_fw_tx_dbg_ppdu_msg_hdr *hdr; + struct ol_fw_tx_dbg_ppdu_base *record; + + if (status == HTT_DBG_STATS_STATUS_PARTIAL + && length == 0) { + qdf_debug("HTT_DBG_STATS_TX_PPDU_LOG -- length = 0!"); + break; + } + hdr = (struct ol_fw_tx_dbg_ppdu_msg_hdr *)(msg_word + 1); + record = (struct ol_fw_tx_dbg_ppdu_base *)(hdr + 1); + htt_t2h_tx_ppdu_log_print(hdr, record, length, concise); + } + break; + case HTT_DBG_STATS_TX_RATE_INFO: + { + wlan_dbg_tx_rate_info_t *tx_rate_info; + + tx_rate_info = (wlan_dbg_tx_rate_info_t *) (msg_word + 1); + htt_t2h_stats_tx_rate_stats_print(tx_rate_info, concise); + break; + } + case HTT_DBG_STATS_TX_RATE_INFO_V2: + { + wlan_dbg_tx_rate_info_v2_t *tx_rate_info; + + tx_rate_info = (wlan_dbg_tx_rate_info_v2_t *) (msg_word + 1); + htt_t2h_stats_tx_rate_stats_print_v2(tx_rate_info, concise); + break; + } + case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: + { + struct rx_remote_buffer_mgmt_stats *rx_rem_buf; + + rx_rem_buf = + (struct rx_remote_buffer_mgmt_stats *)(msg_word + 1); + htt_t2h_stats_rx_rem_buf_stats_print(rx_rem_buf, concise); + break; + } + case HTT_DBG_STATS_TXBF_INFO: + { + struct wlan_dbg_txbf_data_stats *txbf_info_buf; + + txbf_info_buf = + (struct wlan_dbg_txbf_data_stats *)(msg_word + 1); + htt_t2h_stats_txbf_info_buf_stats_print(txbf_info_buf); + break; + } + case HTT_DBG_STATS_SND_INFO: + { + struct wlan_dbg_txbf_snd_stats *txbf_snd_buf; + + txbf_snd_buf = (struct wlan_dbg_txbf_snd_stats *)(msg_word + 1); + htt_t2h_stats_txbf_snd_buf_stats_print(txbf_snd_buf); + break; + } + case HTT_DBG_STATS_TX_SELFGEN_INFO: + { + struct wlan_dbg_tx_selfgen_stats *tx_selfgen_buf; + + tx_selfgen_buf = + (struct wlan_dbg_tx_selfgen_stats *)(msg_word + 1); + htt_t2h_stats_tx_selfgen_buf_stats_print(tx_selfgen_buf); + break; + } + case HTT_DBG_STATS_ERROR_INFO: + { + struct wlan_dbg_wifi2_error_stats *wifi2_error_buf; + + wifi2_error_buf = + (struct wlan_dbg_wifi2_error_stats *)(msg_word + 1); + htt_t2h_stats_wifi2_error_stats_print(wifi2_error_buf); + break; + } + case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: + { + struct rx_txbf_musu_ndpa_pkts_stats *rx_musu_ndpa_stats; + + rx_musu_ndpa_stats = (struct rx_txbf_musu_ndpa_pkts_stats *) + (msg_word + 1); + htt_t2h_rx_musu_ndpa_pkts_stats_print(rx_musu_ndpa_stats); + break; + } + case HTT_DBG_STATS_TIDQ: + { + struct wlan_dbg_tidq_stats *tidq_stats; + + tidq_stats = (struct wlan_dbg_tidq_stats *)(msg_word + 1); + htt_t2h_stats_tidq_stats_print(tidq_stats, concise); + break; + } + case HTT_DBG_STATS_TX_MU_INFO: + { + struct wlan_dbg_tx_mu_stats *tx_mu_stats; + + tx_mu_stats = (struct wlan_dbg_tx_mu_stats *)(msg_word + 1); + htt_t2h_stats_tx_mu_stats_print(tx_mu_stats, concise); + break; + } + case HTT_DBG_STATS_SIFS_RESP_INFO: + { + struct wlan_dbg_sifs_resp_stats *sifs_stats; + + sifs_stats = (struct wlan_dbg_sifs_resp_stats *)(msg_word + 1); + htt_t2h_stats_sifs_resp_stats_print(sifs_stats, concise); + break; + } + default: + break; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_h2t.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_h2t.c new file mode 100644 index 0000000000..d1201a1c0b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_h2t.c @@ -0,0 +1,1546 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file htt_h2t.c + * @brief Provide functions to send host->target HTT messages. + * @details + * This file contains functions related to host->target HTT messages. + * There are a couple aspects of this host->target messaging: + * 1. This file contains the function that is called by HTC when + * a host->target send completes. + * This send-completion callback is primarily relevant to HL, + * to invoke the download scheduler to set up a new download, + * and optionally free the tx frame whose download is completed. + * For both HL and LL, this completion callback frees up the + * HTC_PACKET object used to specify the download. + * 2. This file contains functions for creating messages to send + * from the host to the target. + */ + +#include /* qdf_mem_copy */ +#include /* qdf_nbuf_map_single */ +#include /* HTC_PACKET */ +#include /* HTC_HDR_ALIGNMENT_PADDING */ +#include /* HTT host->target msg defs */ +#include /* HTT host->target WDI IPA msg defs */ +#include /* ol_tx_completion_handler, htt_tx_status */ +#include +#include +#include +#include + +#include +#include + +#define HTT_MSG_BUF_SIZE(msg_bytes) \ + ((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING) + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (char *)(&((type *)0)->member))) +#endif + +#ifdef ATH_11AC_TXCOMPACT +#define HTT_SEND_HTC_PKT(pdev, pkt) \ +do { \ + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == \ + QDF_STATUS_SUCCESS) { \ + htt_htc_misc_pkt_list_add(pdev, pkt); \ + } else { \ + qdf_nbuf_free((qdf_nbuf_t)(pkt->htc_pkt.pNetBufContext)); \ + htt_htc_pkt_free(pdev, pkt); \ + } \ +} while (0) +#else +#define HTT_SEND_HTC_PKT(pdev, ppkt) \ + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + +static void +htt_h2t_send_complete_free_netbuf(void *pdev, QDF_STATUS status, + qdf_nbuf_t netbuf, uint16_t msdu_id) +{ + qdf_nbuf_free(netbuf); +} + +#ifndef QCN7605_SUPPORT +static void htt_t2h_adjust_bus_target_delta(struct htt_pdev_t *pdev) +{ + int32_t credit_delta; + + if (pdev->cfg.is_high_latency && !pdev->cfg.default_tx_comp_req) { + HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex); + qdf_atomic_add(1, &pdev->htt_tx_credit.bus_delta); + credit_delta = htt_tx_credit_update(pdev); + HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex); + + if (credit_delta) + ol_tx_credit_completion_handler(pdev->txrx_pdev, + credit_delta); + } +} +#else +static void htt_t2h_adjust_bus_target_delta(struct htt_pdev_t *pdev) +{ + /* UNPAUSE OS Q */ + ol_tx_flow_ct_unpause_os_q(pdev->txrx_pdev); +} +#endif + +void htt_h2t_send_complete(void *context, HTC_PACKET *htc_pkt) +{ + void (*send_complete_part2)(void *pdev, QDF_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id); + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + struct htt_htc_pkt *htt_pkt; + qdf_nbuf_t netbuf; + + send_complete_part2 = htc_pkt->pPktContext; + + htt_pkt = container_of(htc_pkt, struct htt_htc_pkt, htc_pkt); + + /* process (free or keep) the netbuf that held the message */ + netbuf = (qdf_nbuf_t) htc_pkt->pNetBufContext; + if (send_complete_part2) { + send_complete_part2(htt_pkt->pdev_ctxt, htc_pkt->Status, netbuf, + htt_pkt->msdu_id); + } + + htt_t2h_adjust_bus_target_delta(pdev); + /* free the htt_htc_pkt / HTC_PACKET object */ + htt_htc_pkt_free(pdev, htt_pkt); +} + +enum htc_send_full_action htt_h2t_full(void *context, HTC_PACKET *pkt) +{ +/* FIX THIS */ + return HTC_SEND_FULL_KEEP; +} + +#if defined(HELIUMPLUS) +QDF_STATUS htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev) +{ + QDF_STATUS rc = QDF_STATUS_SUCCESS; + + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + u_int32_t *msg_word; + struct htt_tx_frag_desc_bank_cfg_t *bank_cfg; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return QDF_STATUS_E_FAILURE; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + msg = qdf_nbuf_alloc( + pdev->osdev, + HTT_MSG_BUF_SIZE(sizeof(struct htt_tx_frag_desc_bank_cfg_t)), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return QDF_STATUS_E_FAILURE; /* failure */ + } + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to adf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, sizeof(struct htt_tx_frag_desc_bank_cfg_t)); + + /* fill in the message contents */ + msg_word = (u_int32_t *) qdf_nbuf_data(msg); + + memset(msg_word, 0, sizeof(struct htt_tx_frag_desc_bank_cfg_t)); + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG); + + bank_cfg = (struct htt_tx_frag_desc_bank_cfg_t *)msg_word; + + /** @note @todo Hard coded to 0 Assuming just one pdev for now.*/ + HTT_H2T_FRAG_DESC_BANK_PDEVID_SET(*msg_word, 0); + /** @note Hard coded to 1.*/ + HTT_H2T_FRAG_DESC_BANK_NUM_BANKS_SET(*msg_word, 1); + HTT_H2T_FRAG_DESC_BANK_DESC_SIZE_SET(*msg_word, pdev->frag_descs.size); + HTT_H2T_FRAG_DESC_BANK_SWAP_SET(*msg_word, 0); + + /** Bank specific data structure.*/ +#if HTT_PADDR64 + bank_cfg->bank_base_address[0].lo = qdf_get_lower_32_bits( + pdev->frag_descs.desc_pages.dma_pages->page_p_addr); + bank_cfg->bank_base_address[0].hi = qdf_get_upper_32_bits( + pdev->frag_descs.desc_pages.dma_pages->page_p_addr); +#else /* ! HTT_PADDR64 */ + bank_cfg->bank_base_address[0] = + pdev->frag_descs.desc_pages.dma_pages->page_p_addr; +#endif /* HTT_PADDR64 */ + /* Logical Min index */ + HTT_H2T_FRAG_DESC_BANK_MIN_IDX_SET(bank_cfg->bank_info[0], 0); + /* Logical Max index */ + HTT_H2T_FRAG_DESC_BANK_MAX_IDX_SET(bank_cfg->bank_info[0], + pdev->frag_descs.pool_elems-1); + + SET_HTC_PACKET_INFO_TX( + &pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + + rc = htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#ifdef ATH_11AC_TXCOMPACT + if (rc == QDF_STATUS_SUCCESS) { + htt_htc_misc_pkt_list_add(pdev, pkt); + } else { + qdf_nbuf_free(msg); + htt_htc_pkt_free(pdev, pkt); + } +#endif + + return rc; +} + +#endif /* defined(HELIUMPLUS) */ + +QDF_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint32_t msg_size; + uint32_t max_tx_group; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return QDF_STATUS_E_FAILURE; /* failure */ + + max_tx_group = ol_tx_get_max_tx_groups_supported(pdev->txrx_pdev); + + if (max_tx_group) + msg_size = HTT_VER_REQ_BYTES + + sizeof(struct htt_option_tlv_mac_tx_queue_groups_t); + else + msg_size = HTT_VER_REQ_BYTES; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(msg_size), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return QDF_STATUS_E_FAILURE; /* failure */ + } + + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, msg_size); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_VERSION_REQ); + + if (max_tx_group) { + *(msg_word + 1) = 0; + + /* Fill Group Info */ + HTT_OPTION_TLV_TAG_SET(*(msg_word+1), + HTT_OPTION_TLV_TAG_MAX_TX_QUEUE_GROUPS); + HTT_OPTION_TLV_LENGTH_SET(*(msg_word+1), + (sizeof(struct htt_option_tlv_mac_tx_queue_groups_t)/ + sizeof(uint32_t))); + HTT_OPTION_TLV_VALUE0_SET(*(msg_word+1), max_tx_group); + } + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RTPM_PUT_RC); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + + ol_tx_deduct_one_credit(pdev->txrx_pdev); + + return QDF_STATUS_SUCCESS; +} + +#if defined(HELIUMPLUS) +/** + * htt_h2t_rx_ring_rfs_cfg_msg_ll() - Configure receive flow steering + * @pdev: handle to the HTT instance + * + * Return: QDF_STATUS_SUCCESS on success + * A_NO_MEMORY No memory fail + */ +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint32_t msg_local; + struct cds_config_info *cds_cfg; + + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "Receive flow steering configuration, disable gEnableFlowSteering(=0) in ini if FW does not support it\n"); + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return QDF_STATUS_E_NOMEM; /* failure */ + + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RFS_CFG_REQ_BYTES), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return QDF_STATUS_E_NOMEM; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RFS_CFG_REQ_BYTES); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + msg_local = 0; + HTT_H2T_MSG_TYPE_SET(msg_local, HTT_H2T_MSG_TYPE_RFS_CONFIG); + if (ol_cfg_is_flow_steering_enabled(pdev->ctrl_pdev)) { + HTT_RX_RFS_CONFIG_SET(msg_local, 1); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "Enable Rx flow steering"); + } else { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "Disable Rx flow steering"); + } + cds_cfg = cds_get_ini_config(); + if (cds_cfg) { + msg_local |= ((cds_cfg->max_msdus_per_rxinorderind & 0xff) + << 16); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "Updated maxMSDUsPerRxInd"); + } + + *msg_word = msg_local; + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "%s: Sending msg_word: 0x%08x", + __func__, *msg_word); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return QDF_STATUS_SUCCESS; +} +#else +/** + * htt_h2t_rx_ring_rfs_cfg_msg_ll() - Configure receive flow steering + * @pdev: handle to the HTT instance + * + * Return: QDF_STATUS_SUCCESS on success + * A_NO_MEMORY No memory fail + */ +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "Does not support receive flow steering configuration\n"); + return QDF_STATUS_SUCCESS; +} +#endif /* HELIUMPLUS */ + +QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + int enable_ctrl_data, enable_mgmt_data, + enable_null_data, enable_phy_data, enable_hdr, + enable_ppdu_start, enable_ppdu_end; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return QDF_STATUS_E_FAILURE; /* failure */ + + /* + * show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for the HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return QDF_STATUS_E_FAILURE; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to qdf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); + HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); + + msg_word++; + *msg_word = 0; +#if HTT_PADDR64 + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_LO_SET( + *msg_word, + qdf_get_lower_32_bits(pdev->rx_ring.alloc_idx.paddr)); + msg_word++; + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_HI_SET( + *msg_word, + qdf_get_upper_32_bits(pdev->rx_ring.alloc_idx.paddr)); +#else /* ! HTT_PADDR64 */ + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET(*msg_word, + pdev->rx_ring.alloc_idx.paddr); +#endif /* HTT_PADDR64 */ + + msg_word++; + *msg_word = 0; +#if HTT_PADDR64 + HTT_RX_RING_CFG_BASE_PADDR_LO_SET(*msg_word, + pdev->rx_ring.base_paddr); + { + uint32_t tmp; + + tmp = qdf_get_upper_32_bits(pdev->rx_ring.base_paddr); + if (tmp & 0xfffffe0) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s:%d paddr > 37 bits!. Trimmed.", + __func__, __LINE__); + tmp &= 0x01f; + } + + + msg_word++; + HTT_RX_RING_CFG_BASE_PADDR_HI_SET(*msg_word, tmp); + } +#else /* ! HTT_PADDR64 */ + HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); +#endif /* HTT_PADDR64 */ + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); + HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); + +/* FIX THIS: if the FW creates a complete translated rx descriptor, + * then the MAC DMA of the HW rx descriptor should be disabled. + */ + msg_word++; + *msg_word = 0; +#ifndef REMOVE_PKT_LOG + if (ol_cfg_is_packet_log_enabled(pdev->ctrl_pdev)) { + enable_ctrl_data = 1; + enable_mgmt_data = 1; + enable_null_data = 1; + enable_phy_data = 1; + enable_hdr = 1; + enable_ppdu_start = 1; + enable_ppdu_end = 1; + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "%s : %d Pkt log is enabled\n", __func__, __LINE__); + } else { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s : %d Pkt log is disabled\n", __func__, __LINE__); + enable_ctrl_data = 0; + enable_mgmt_data = 0; + enable_null_data = 0; + enable_phy_data = 0; + enable_hdr = 0; + enable_ppdu_start = 0; + enable_ppdu_end = 0; + } +#else + enable_ctrl_data = 0; + enable_mgmt_data = 0; + enable_null_data = 0; + enable_phy_data = 0; + enable_hdr = 0; + enable_ppdu_start = 0; + enable_ppdu_end = 0; +#endif + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) { + enable_ctrl_data = 1; + enable_mgmt_data = 1; + enable_null_data = 1; + enable_phy_data = 1; + enable_hdr = 1; + enable_ppdu_start = 1; + enable_ppdu_end = 1; + /* Disable ASPM for monitor mode */ + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s : %d Monitor mode is enabled\n", + __func__, __LINE__); + } + + htt_rx_enable_ppdu_end(&enable_ppdu_end); + HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, enable_hdr); + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, enable_ppdu_start); + HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, enable_ppdu_end); + HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 1); + /* always present? */ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); + /* Must change to dynamic enable at run time + * rather than at compile time + */ + HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, enable_ctrl_data); + HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, enable_mgmt_data); + HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, enable_null_data); + HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, enable_phy_data); + HTT_RX_RING_CFG_IDX_INIT_VAL_SET(*msg_word, + *pdev->rx_ring.alloc_idx.vaddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, + RX_DESC_HDR_STATUS_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, + HTT_RX_DESC_RESERVATION32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, + RX_DESC_PPDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, + RX_DESC_PPDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, + RX_DESC_MPDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, + RX_DESC_MPDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, + RX_DESC_MSDU_START_OFFSET32); + HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, + RX_DESC_MSDU_END_OFFSET32); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, + RX_DESC_ATTN_OFFSET32); + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, + RX_DESC_FRAG_INFO_OFFSET32); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + u_int32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_ERROR; /* failure */ + + /* + * show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + msg = qdf_nbuf_alloc( + pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_RX_RING_CFG_BYTES(1)), + /* reserve room for the HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, true); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_ERROR; /* failure */ + } + /* + * Set the length of the message. + * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added + * separately during the below call to adf_nbuf_push_head. + * The contribution from the HTC header is added separately inside HTC. + */ + qdf_nbuf_put_tail(msg, HTT_RX_RING_CFG_BYTES(1)); + + /* fill in the message contents */ + msg_word = (u_int32_t *)qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RX_RING_CFG); + HTT_RX_RING_CFG_NUM_RINGS_SET(*msg_word, 1); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_IDX_SHADOW_REG_PADDR_SET( + *msg_word, pdev->rx_ring.alloc_idx.paddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_BASE_PADDR_SET(*msg_word, pdev->rx_ring.base_paddr); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_LEN_SET(*msg_word, pdev->rx_ring.size); + HTT_RX_RING_CFG_BUF_SZ_SET(*msg_word, HTT_RX_BUF_SIZE); + + /* FIX THIS: if the FW creates a complete translated rx descriptor, + * then the MAC DMA of the HW rx descriptor should be disabled. */ + msg_word++; + *msg_word = 0; + + HTT_RX_RING_CFG_ENABLED_802_11_HDR_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_PAYLD_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_PPDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_PPDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MPDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MPDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_START_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MSDU_END_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_RX_ATTN_SET(*msg_word, 0); + /* always present? */ + HTT_RX_RING_CFG_ENABLED_FRAG_INFO_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_UCAST_SET(*msg_word, 1); + HTT_RX_RING_CFG_ENABLED_MCAST_SET(*msg_word, 1); + /* Must change to dynamic enable at run time + * rather than at compile time + */ + HTT_RX_RING_CFG_ENABLED_CTRL_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_MGMT_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_NULL_SET(*msg_word, 0); + HTT_RX_RING_CFG_ENABLED_PHY_SET(*msg_word, 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_802_11_HDR_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MSDU_PAYLD_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_PPDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_PPDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MPDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MPDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_MSDU_START_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_MSDU_END_SET(*msg_word, + 0); + + msg_word++; + *msg_word = 0; + HTT_RX_RING_CFG_OFFSET_RX_ATTN_SET(*msg_word, + 0); + HTT_RX_RING_CFG_OFFSET_FRAG_INFO_SET(*msg_word, + 0); + + SET_HTC_PACKET_INFO_TX( + &pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == QDF_STATUS_SUCCESS) { + htt_htc_misc_pkt_list_add(pdev, pkt); + } else { + qdf_nbuf_free(msg); + htt_htc_pkt_free(pdev, pkt); + } +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + ol_tx_deduct_one_credit(pdev->txrx_pdev); + + return QDF_STATUS_SUCCESS; +} + +/** + * htt_h2t_rx_ring_rfs_cfg_msg_hl() - Configure receive flow steering + * @pdev: handle to the HTT instance + * + * Return: QDF_STATUS_SUCCESS on success + * A_NO_MEMORY No memory fail + */ +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_hl(struct htt_pdev_t *pdev) +{ + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "Does not support Receive flow steering configuration\n"); + return QDF_STATUS_SUCCESS; +} + +int +htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, + uint32_t stats_type_upload_mask, + uint32_t stats_type_reset_mask, + uint8_t cfg_stat_type, uint32_t cfg_val, uint8_t cookie) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint16_t htc_tag = 1; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -EINVAL; /* failure */ + + if (stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + /* FIX THIS - add more details? */ + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%#x %#x stats not supported\n", + stats_type_upload_mask, stats_type_reset_mask); + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + + if (stats_type_reset_mask) + htc_tag = HTC_TX_PACKET_TAG_RUNTIME_PUT; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_H2T_STATS_REQ_MSG_SZ), + /* reserve room for HTC header */ + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_H2T_STATS_REQ_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_STATS_REQ); + HTT_H2T_STATS_REQ_UPLOAD_TYPES_SET(*msg_word, stats_type_upload_mask); + + msg_word++; + *msg_word = 0; + HTT_H2T_STATS_REQ_RESET_TYPES_SET(*msg_word, stats_type_reset_mask); + + msg_word++; + *msg_word = 0; + HTT_H2T_STATS_REQ_CFG_VAL_SET(*msg_word, cfg_val); + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_SET(*msg_word, cfg_stat_type); + + /* cookie LSBs */ + msg_word++; + *msg_word = cookie; + + /* cookie MSBs */ + msg_word++; + *msg_word = 0; + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + htc_tag); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == QDF_STATUS_SUCCESS) { + htt_htc_misc_pkt_list_add(pdev, pkt); + } else { + qdf_nbuf_free(msg); + htt_htc_pkt_free(pdev, pkt); + } +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + ol_tx_deduct_one_credit(pdev->txrx_pdev); + + return 0; +} + +A_STATUS htt_h2t_sync_msg(struct htt_pdev_t *pdev, uint8_t sync_cnt) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_H2T_SYNC_MSG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_H2T_SYNC_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_SYNC); + HTT_H2T_SYNC_COUNT_SET(*msg_word, sync_cnt); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + + ol_tx_deduct_one_credit(pdev->txrx_pdev); + + return A_OK; +} + +int +htt_h2t_aggr_cfg_msg(struct htt_pdev_t *pdev, + int max_subfrms_ampdu, int max_subfrms_amsdu) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -EINVAL; /* failure */ + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_AGGR_CFG_MSG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -EINVAL; /* failure */ + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_AGGR_CFG_MSG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_AGGR_CFG); + + if (max_subfrms_ampdu && (max_subfrms_ampdu <= 64)) { + HTT_AGGR_CFG_MAX_NUM_AMPDU_SUBFRM_SET(*msg_word, + max_subfrms_ampdu); + } + + if (max_subfrms_amsdu && (max_subfrms_amsdu < 32)) { + HTT_AGGR_CFG_MAX_NUM_AMSDU_SUBFRM_SET(*msg_word, + max_subfrms_amsdu); + } + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + +#ifdef ATH_11AC_TXCOMPACT + if (htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt) == QDF_STATUS_SUCCESS) { + htt_htc_misc_pkt_list_add(pdev, pkt); + } else { + qdf_nbuf_free(msg); + htt_htc_pkt_free(pdev, pkt); + } +#else + htc_send_pkt(pdev->htc_pdev, &pkt->htc_pkt); +#endif + + ol_tx_deduct_one_credit(pdev->txrx_pdev); + + return 0; +} + +#ifdef IPA_OFFLOAD +/** + * htt_h2t_ipa_uc_rsc_cfg_msg() - Send WDI IPA config message to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + * A_NO_MEMORY No memory fail + */ +#ifdef QCA_WIFI_3_0 +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + unsigned int tx_count = 0; + uint32_t addr; + qdf_mem_info_t *mem_info_t; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_CFG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_CFG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(*msg_word, + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_CFG); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_tx_rsc.tx_comp_ring->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_tx_rsc.tx_comp_ring->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + tx_count = qdf_get_pwr2(ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev)); + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET(*msg_word, tx_count); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); + msg_word++; + *msg_word = 0; + addr = (uint64_t)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr >> 32; + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_tx_rsc.tx_ce_idx->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_tx_rsc.tx_ce_idx->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx_ind_ring->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_rx_rsc.rx_ind_ring->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(*msg_word, + (unsigned int)qdf_get_pwr2(pdev->rx_ring.fill_level)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + msg_word++; + *msg_word = 0; + addr = (uint64_t)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr >> 32; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx2_ind_ring->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_rx_rsc.rx2_ind_ring->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_RX_RING2_BASE_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_SIZE_SET(*msg_word, + (unsigned int)qdf_get_pwr2(pdev->rx_ring.fill_level)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_RX_RING2_RD_IDX_ADDR_HI_SET(*msg_word, addr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_LO_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx->mem_info)); + msg_word++; + *msg_word = 0; + mem_info_t = &pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx->mem_info; + addr = (uint64_t)qdf_mem_get_dma_addr(pdev->osdev, mem_info_t) >> 32; + HTT_WDI_IPA_CFG_RX_RING2_WR_IDX_ADDR_HI_SET(*msg_word, addr); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} +#else +/* Rome Support only WDI 1.0 */ +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, HTT_MSG_BUF_SIZE(HTT_WDI_IPA_CFG_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_CFG_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_PKT_POOL_SIZE_SET(*msg_word, + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_CFG); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_BASE_ADDR_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_tx_rsc.tx_comp_ring->mem_info)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_RING_SIZE_SET( + *msg_word, + (unsigned int)ol_cfg_ipa_uc_tx_max_buf_cnt(pdev->ctrl_pdev)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_COMP_WR_IDX_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_tx_rsc.tx_comp_idx_paddr); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_TX_CE_WR_IDX_ADDR_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_tx_rsc.tx_ce_idx->mem_info)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_BASE_ADDR_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx_ind_ring->mem_info)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RING_SIZE_SET(*msg_word, + (unsigned int)qdf_get_pwr2(pdev->rx_ring.fill_level)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_RD_IDX_ADDR_SET(*msg_word, + (unsigned int)qdf_mem_get_dma_addr(pdev->osdev, + &pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx->mem_info)); + + msg_word++; + *msg_word = 0; + HTT_WDI_IPA_CFG_RX_IND_WR_IDX_ADDR_SET(*msg_word, + (unsigned int)pdev->ipa_uc_rx_rsc.rx_rdy_idx_paddr); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + HTC_TX_PACKET_TAG_RUNTIME_PUT); + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} +#endif + +/** + * htt_h2t_ipa_uc_set_active() - Propagate WDI path enable/disable to firmware + * @pdev: handle to the HTT instance + * @uc_active: WDI UC path enable or not + * @is_tx: TX path or RX path + * + * Return: 0 success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, + bool uc_active, bool is_tx) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + uint8_t active_target = 0; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + if (uc_active && is_tx) + active_target = HTT_WDI_IPA_OPCODE_TX_RESUME; + else if (!uc_active && is_tx) + active_target = HTT_WDI_IPA_OPCODE_TX_SUSPEND; + else if (uc_active && !is_tx) + active_target = HTT_WDI_IPA_OPCODE_RX_RESUME; + else if (!uc_active && !is_tx) + active_target = HTT_WDI_IPA_OPCODE_RX_SUSPEND; + + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s: HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ (%d)\n", + __func__, active_target); + + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, active_target); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +/** + * htt_h2t_ipa_uc_get_stats() - WDI UC state query request to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, + false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_DBG_STATS); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +/** + * htt_h2t_ipa_uc_get_share_stats() - WDI UC wifi sharing state request to FW + * @pdev: handle to the HTT instance + * + * Return: A_OK success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, uint8_t reset_stats) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ)+ + HTT_MSG_BUF_SIZE(WLAN_WDI_IPA_GET_SHARING_STATS_REQ_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ+ + WLAN_WDI_IPA_GET_SHARING_STATS_REQ_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_GET_SHARING_STATS); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + msg_word++; + *msg_word = 0; + WLAN_WDI_IPA_GET_SHARING_STATS_REQ_RESET_STATS_SET(*msg_word, + reset_stats); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} + +/** + * htt_h2t_ipa_uc_set_quota() - WDI UC state query request to firmware + * @pdev: handle to the HTT instance + * + * Return: A_OK success + * A_NO_MEMORY No memory fail + */ +int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, uint64_t quota_bytes) +{ + struct htt_htc_pkt *pkt; + qdf_nbuf_t msg; + uint32_t *msg_word; + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -A_NO_MEMORY; + + /* show that this is not a tx frame download + * (not required, but helpful) + */ + pkt->msdu_id = HTT_TX_COMPL_INV_MSDU_ID; + pkt->pdev_ctxt = NULL; /* not used during send-done callback */ + + /* reserve room for HTC header */ + msg = qdf_nbuf_alloc(pdev->osdev, + HTT_MSG_BUF_SIZE(HTT_WDI_IPA_OP_REQUEST_SZ)+ + HTT_MSG_BUF_SIZE(WLAN_WDI_IPA_SET_QUOTA_REQ_SZ), + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4, false); + if (!msg) { + htt_htc_pkt_free(pdev, pkt); + return -A_NO_MEMORY; + } + /* set the length of the message */ + qdf_nbuf_put_tail(msg, HTT_WDI_IPA_OP_REQUEST_SZ+ + WLAN_WDI_IPA_SET_QUOTA_REQ_SZ); + + /* fill in the message contents */ + msg_word = (uint32_t *) qdf_nbuf_data(msg); + + /* rewind beyond alignment pad to get to the HTC header reserved area */ + qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING); + + *msg_word = 0; + HTT_WDI_IPA_OP_REQUEST_OP_CODE_SET(*msg_word, + HTT_WDI_IPA_OPCODE_SET_QUOTA); + HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_WDI_IPA_OP_REQ); + + msg_word++; + *msg_word = 0; + WLAN_WDI_IPA_SET_QUOTA_REQ_SET_QUOTA_SET(*msg_word, quota_bytes > 0); + + msg_word++; + *msg_word = 0; + WLAN_WDI_IPA_SET_QUOTA_REQ_QUOTA_LO_SET(*msg_word, + (uint32_t)(quota_bytes & + WLAN_WDI_IPA_SET_QUOTA_REQ_QUOTA_LO_M)); + + msg_word++; + *msg_word = 0; + WLAN_WDI_IPA_SET_QUOTA_REQ_QUOTA_HI_SET(*msg_word, + (uint32_t)(quota_bytes>>32 & + WLAN_WDI_IPA_SET_QUOTA_REQ_QUOTA_HI_M)); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + htt_h2t_send_complete_free_netbuf, + qdf_nbuf_data(msg), + qdf_nbuf_len(msg), + pdev->htc_tx_endpoint, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg); + HTT_SEND_HTC_PKT(pdev, pkt); + return A_OK; +} +#endif /* IPA_OFFLOAD */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_internal.h new file mode 100644 index 0000000000..488f4d482e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_internal.h @@ -0,0 +1,1163 @@ +/* + * Copyright (c) 2011, 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HTT_INTERNAL__H_ +#define _HTT_INTERNAL__H_ + +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ +#include /* qdf_assert */ +#include /* HTC_PACKET */ + +#include + +/* htt_rx.c */ +#define RX_MSDU_END_4_FIRST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_MASK) +#define RX_MSDU_END_4_FIRST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_FIRST_MSDU_LSB) +#define RX_MPDU_START_0_RETRY_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_LSB) +#define RX_MPDU_START_0_RETRY_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_RETRY_MASK) +#define RX_MPDU_START_0_SEQ_NUM_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_MASK) +#define RX_MPDU_START_0_SEQ_NUM_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_SEQ_NUM_LSB) +#define RX_MPDU_START_2_PN_47_32_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_LSB) +#define RX_MPDU_START_2_PN_47_32_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_PN_47_32_MASK) +#define RX_MPDU_START_2_TID_LSB \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_LSB) +#define RX_MPDU_START_2_TID_MASK \ + (pdev->targetdef->d_RX_MPDU_START_2_TID_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_MASK) +#define RX_MSDU_END_1_KEY_ID_OCT_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_KEY_ID_OCT_LSB) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK) +#define RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB \ + (pdev->targetdef->d_RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB) +#define RX_MSDU_END_4_LAST_MSDU_MASK \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_MASK) +#define RX_MSDU_END_4_LAST_MSDU_LSB \ + (pdev->targetdef->d_RX_MSDU_END_4_LAST_MSDU_LSB) +#define RX_ATTENTION_0_MCAST_BCAST_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_MASK) +#define RX_ATTENTION_0_MCAST_BCAST_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_MCAST_BCAST_LSB) +#define RX_ATTENTION_0_FRAGMENT_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_MASK) +#define RX_ATTENTION_0_FRAGMENT_LSB \ + (pdev->targetdef->d_RX_ATTENTION_0_FRAGMENT_LSB) +#define RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) +#define RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB \ + (pdev->targetdef->d_RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB) +#define RX_MSDU_START_0_MSDU_LENGTH_MASK \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_MASK) +#define RX_MSDU_START_0_MSDU_LENGTH_LSB \ + (pdev->targetdef->d_RX_MSDU_START_0_MSDU_LENGTH_LSB) +#define RX_MPDU_START_0_ENCRYPTED_MASK \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_MASK) +#define RX_MPDU_START_0_ENCRYPTED_LSB \ + (pdev->targetdef->d_RX_MPDU_START_0_ENCRYPTED_LSB) +#define RX_ATTENTION_0_MORE_DATA_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MORE_DATA_MASK) +#define RX_ATTENTION_0_MSDU_DONE_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_MSDU_DONE_MASK) +#define RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK \ + (pdev->targetdef->d_RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) +#define RX_MSDU_START_2_DECAP_FORMAT_OFFSET \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_OFFSET) +#define RX_MSDU_START_2_DECAP_FORMAT_LSB \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_LSB) +#define RX_MSDU_START_2_DECAP_FORMAT_MASK \ + (pdev->targetdef->d_RX_MSDU_START_2_DECAP_FORMAT_MASK) +/* end */ + +#ifndef offsetof +#define offsetof(type, field) ((size_t)(&((type *)0)->field)) +#endif + +#undef MS +#define MS(_v, _f) (((_v) & _f ## _MASK) >> _f ## _LSB) +#undef SM +#define SM(_v, _f) (((_v) << _f ## _LSB) & _f ## _MASK) +#undef WO +#define WO(_f) ((_f ## _OFFSET) >> 2) + +#define GET_FIELD(_addr, _f) MS(*((A_UINT32 *)(_addr) + WO(_f)), _f) + +#include +#include /* struct rx_attention, etc */ + +struct htt_host_fw_desc_base { + union { + struct fw_rx_desc_base val; + A_UINT32 dummy_pad; /* make sure it is DOWRD aligned */ + } u; +}; + + +/* + * This struct defines the basic descriptor information used by host, + * which is written either by the 11ac HW MAC into the host Rx data + * buffer ring directly or generated by FW and copied from Rx indication + */ +struct htt_host_rx_desc_base { + struct htt_host_fw_desc_base fw_desc; + struct rx_attention attention; + struct rx_frag_info frag_info; + struct rx_mpdu_start mpdu_start; + struct rx_msdu_start msdu_start; + struct rx_msdu_end msdu_end; + struct rx_mpdu_end mpdu_end; + struct rx_ppdu_start ppdu_start; + struct rx_ppdu_end ppdu_end; +#ifdef QCA_WIFI_3_0_ADRASTEA +/* Increased to support some of offload features */ +#define RX_HTT_HDR_STATUS_LEN 256 +#else +#define RX_HTT_HDR_STATUS_LEN 64 +#endif + char rx_hdr_status[RX_HTT_HDR_STATUS_LEN]; +}; + +#define RX_DESC_ATTN_MPDU_LEN_ERR_BIT 0x08000000 + +#define RX_STD_DESC_ATTN_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, attention)) +#define RX_STD_DESC_FRAG_INFO_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, frag_info)) +#define RX_STD_DESC_MPDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, mpdu_start)) +#define RX_STD_DESC_MSDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, msdu_start)) +#define RX_STD_DESC_MSDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, msdu_end)) +#define RX_STD_DESC_MPDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, mpdu_end)) +#define RX_STD_DESC_PPDU_START_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, ppdu_start)) +#define RX_STD_DESC_PPDU_END_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, ppdu_end)) +#define RX_STD_DESC_HDR_STATUS_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, rx_hdr_status)) + +#define RX_STD_DESC_FW_MSDU_OFFSET \ + (offsetof(struct htt_host_rx_desc_base, fw_desc)) + +#define RX_STD_DESC_SIZE (sizeof(struct htt_host_rx_desc_base)) + +#define RX_DESC_ATTN_OFFSET32 (RX_STD_DESC_ATTN_OFFSET >> 2) +#define RX_DESC_FRAG_INFO_OFFSET32 (RX_STD_DESC_FRAG_INFO_OFFSET >> 2) +#define RX_DESC_MPDU_START_OFFSET32 (RX_STD_DESC_MPDU_START_OFFSET >> 2) +#define RX_DESC_MSDU_START_OFFSET32 (RX_STD_DESC_MSDU_START_OFFSET >> 2) +#define RX_DESC_MSDU_END_OFFSET32 (RX_STD_DESC_MSDU_END_OFFSET >> 2) +#define RX_DESC_MPDU_END_OFFSET32 (RX_STD_DESC_MPDU_END_OFFSET >> 2) +#define RX_DESC_PPDU_START_OFFSET32 (RX_STD_DESC_PPDU_START_OFFSET >> 2) +#define RX_DESC_PPDU_END_OFFSET32 (RX_STD_DESC_PPDU_END_OFFSET >> 2) +#define RX_DESC_HDR_STATUS_OFFSET32 (RX_STD_DESC_HDR_STATUS_OFFSET >> 2) + +#define RX_STD_DESC_SIZE_DWORD (RX_STD_DESC_SIZE >> 2) + +/* + * Make sure there is a minimum headroom provided in the rx netbufs + * for use by the OS shim and OS and rx data consumers. + */ +#define HTT_RX_BUF_OS_MIN_HEADROOM 32 +#define HTT_RX_STD_DESC_RESERVATION \ + ((HTT_RX_BUF_OS_MIN_HEADROOM > RX_STD_DESC_SIZE) ? \ + HTT_RX_BUF_OS_MIN_HEADROOM : RX_STD_DESC_SIZE) +#define HTT_RX_DESC_RESERVATION32 \ + (HTT_RX_STD_DESC_RESERVATION >> 2) + +#define HTT_RX_DESC_ALIGN_MASK 7 /* 8-byte alignment */ + +#ifdef DEBUG_RX_RING_BUFFER +#ifdef MSM_PLATFORM +#define HTT_ADDRESS_MASK 0xfffffffffffffffe +#else +#define HTT_ADDRESS_MASK 0xfffffffe +#endif /* MSM_PLATFORM */ + +/** + * rx_buf_debug: rx_ring history + * + * There are three types of entries in history: + * 1) rx-descriptors posted (and received) + * Both of these events are stored on the same entry + * @paddr : physical address posted on the ring + * @nbuf : virtual address of nbuf containing data + * @ndata : virtual address of data (corresponds to physical address) + * @posted: time-stamp when the buffer is posted to the ring + * @recved: time-stamp when the buffer is received (rx_in_order_ind) + * : or 0, if the buffer has not been received yet + * 2) ring alloc-index (fill-index) updates + * @paddr : = 0 + * @nbuf : = 0 + * @ndata : = 0 + * posted : time-stamp when alloc index was updated + * recved : value of alloc index + * 3) htt_rx_in_order_indication reception + * @paddr : = 0 + * @nbuf : = 0 + * @ndata : msdu_cnt + * @posted: time-stamp when HTT message is received + * @recvd : 0x48545452584D5367 ('HTTRXMSG') + */ +#ifdef CONFIG_SLUB_DEBUG_ON +#define HTT_RX_RING_BUFF_DBG_LIST (8 * 1024) +#else +#define HTT_RX_RING_BUFF_DBG_LIST (4 * 1024) +#endif +struct rx_buf_debug { + qdf_dma_addr_t paddr; + qdf_nbuf_t nbuf; + void *nbuf_data; + uint64_t posted; /* timestamp */ + uint64_t recved; /* timestamp */ + int cpu; + +}; +#endif + +static inline struct htt_host_rx_desc_base *htt_rx_desc(qdf_nbuf_t msdu) +{ + return (struct htt_host_rx_desc_base *) + (((size_t) (qdf_nbuf_head(msdu) + HTT_RX_DESC_ALIGN_MASK)) & + ~HTT_RX_DESC_ALIGN_MASK); +} + +#if defined(HELIUMPLUS) +/** + * htt_print_rx_desc_lro() - print LRO information in the rx + * descriptor + * @rx_desc: HTT rx descriptor + * + * Prints the LRO related fields in the HTT rx descriptor + * + * Return: none + */ +static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc) +{ + qdf_nofl_info + ("----------------------RX DESC LRO----------------------\n"); + qdf_nofl_info("msdu_end.lro_eligible:0x%x\n", + rx_desc->msdu_end.lro_eligible); + qdf_nofl_info("msdu_start.tcp_only_ack:0x%x\n", + rx_desc->msdu_start.tcp_only_ack); + qdf_nofl_info("msdu_end.tcp_udp_chksum:0x%x\n", + rx_desc->msdu_end.tcp_udp_chksum); + qdf_nofl_info("msdu_end.tcp_seq_number:0x%x\n", + rx_desc->msdu_end.tcp_seq_number); + qdf_nofl_info("msdu_end.tcp_ack_number:0x%x\n", + rx_desc->msdu_end.tcp_ack_number); + qdf_nofl_info("msdu_start.tcp_proto:0x%x\n", + rx_desc->msdu_start.tcp_proto); + qdf_nofl_info("msdu_start.ipv6_proto:0x%x\n", + rx_desc->msdu_start.ipv6_proto); + qdf_nofl_info("msdu_start.ipv4_proto:0x%x\n", + rx_desc->msdu_start.ipv4_proto); + qdf_nofl_info("msdu_start.l3_offset:0x%x\n", + rx_desc->msdu_start.l3_offset); + qdf_nofl_info("msdu_start.l4_offset:0x%x\n", + rx_desc->msdu_start.l4_offset); + qdf_nofl_info("msdu_start.flow_id_toeplitz:0x%x\n", + rx_desc->msdu_start.flow_id_toeplitz); + qdf_nofl_info + ("---------------------------------------------------------\n"); +} + +/** + * htt_print_rx_desc_lro() - extract LRO information from the rx + * descriptor + * @msdu: network buffer + * @rx_desc: HTT rx descriptor + * + * Extracts the LRO related fields from the HTT rx descriptor + * and stores them in the network buffer's control block + * + * Return: none + */ +static inline void htt_rx_extract_lro_info(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + if (rx_desc->attention.tcp_udp_chksum_fail) + QDF_NBUF_CB_RX_LRO_ELIGIBLE(msdu) = 0; + else + QDF_NBUF_CB_RX_LRO_ELIGIBLE(msdu) = + rx_desc->msdu_end.lro_eligible; + + if (QDF_NBUF_CB_RX_LRO_ELIGIBLE(msdu)) { + QDF_NBUF_CB_RX_TCP_PURE_ACK(msdu) = + rx_desc->msdu_start.tcp_only_ack; + QDF_NBUF_CB_RX_TCP_CHKSUM(msdu) = + rx_desc->msdu_end.tcp_udp_chksum; + QDF_NBUF_CB_RX_TCP_SEQ_NUM(msdu) = + rx_desc->msdu_end.tcp_seq_number; + QDF_NBUF_CB_RX_TCP_ACK_NUM(msdu) = + rx_desc->msdu_end.tcp_ack_number; + QDF_NBUF_CB_RX_TCP_WIN(msdu) = + rx_desc->msdu_end.window_size; + QDF_NBUF_CB_RX_TCP_PROTO(msdu) = + rx_desc->msdu_start.tcp_proto; + QDF_NBUF_CB_RX_IPV6_PROTO(msdu) = + rx_desc->msdu_start.ipv6_proto; + QDF_NBUF_CB_RX_TCP_OFFSET(msdu) = + rx_desc->msdu_start.l4_offset; + QDF_NBUF_CB_RX_FLOW_ID(msdu) = + rx_desc->msdu_start.flow_id_toeplitz; + } +} +#else +static inline void htt_print_rx_desc_lro(struct htt_host_rx_desc_base *rx_desc) +{} +static inline void htt_rx_extract_lro_info(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) {} +#endif /* HELIUMPLUS */ + +static inline void htt_print_rx_desc(struct htt_host_rx_desc_base *rx_desc) +{ + qdf_nofl_info + ("----------------------RX DESC----------------------------\n"); + qdf_nofl_info("attention: %#010x\n", + (unsigned int)(*(uint32_t *)&rx_desc->attention)); + qdf_nofl_info("frag_info: %#010x\n", + (unsigned int)(*(uint32_t *)&rx_desc->frag_info)); + qdf_nofl_info("mpdu_start: %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *)&rx_desc->mpdu_start)[0]), + (unsigned int)(((uint32_t *)&rx_desc->mpdu_start)[1]), + (unsigned int)(((uint32_t *)&rx_desc->mpdu_start)[2])); + qdf_nofl_info("msdu_start: %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *)&rx_desc->msdu_start)[0]), + (unsigned int)(((uint32_t *)&rx_desc->msdu_start)[1]), + (unsigned int)(((uint32_t *)&rx_desc->msdu_start)[2])); + qdf_nofl_info("msdu_end: %#010x %#010x %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *)&rx_desc->msdu_end)[0]), + (unsigned int)(((uint32_t *)&rx_desc->msdu_end)[1]), + (unsigned int)(((uint32_t *)&rx_desc->msdu_end)[2]), + (unsigned int)(((uint32_t *)&rx_desc->msdu_end)[3]), + (unsigned int)(((uint32_t *)&rx_desc->msdu_end)[4])); + qdf_nofl_info("mpdu_end: %#010x\n", + (unsigned int)(*(uint32_t *)&rx_desc->mpdu_end)); + qdf_nofl_info("ppdu_start: %#010x %#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n", + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[0]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[1]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[2]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[3]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[4]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[5]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[6]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[7]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[8]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_start)[9])); + qdf_nofl_info("ppdu_end: %#010x %#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n" + "%#010x,%#010x %#010x %#010x %#010x\n" + "%#010x %#010x %#010x %#010x %#010x\n" "%#010x %#010x\n", + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[0]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[1]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[2]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[3]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[4]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[5]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[6]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[7]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[8]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[9]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[10]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[11]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[12]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[13]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[14]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[15]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[16]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[17]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[18]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[19]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[20]), + (unsigned int)(((uint32_t *)&rx_desc->ppdu_end)[21])); + qdf_nofl_info + ("---------------------------------------------------------\n"); +} + +#ifndef HTT_ASSERT_LEVEL +#define HTT_ASSERT_LEVEL 3 +#endif + +#define HTT_ASSERT_ALWAYS(condition) qdf_assert_always((condition)) + +#define HTT_ASSERT0(condition) qdf_assert((condition)) +#if HTT_ASSERT_LEVEL > 0 +#define HTT_ASSERT1(condition) qdf_assert((condition)) +#else +#define HTT_ASSERT1(condition) +#endif + +#if HTT_ASSERT_LEVEL > 1 +#define HTT_ASSERT2(condition) qdf_assert((condition)) +#else +#define HTT_ASSERT2(condition) +#endif + +#if HTT_ASSERT_LEVEL > 2 +#define HTT_ASSERT3(condition) qdf_assert((condition)) +#else +#define HTT_ASSERT3(condition) +#endif + +/* + * HTT_MAX_SEND_QUEUE_DEPTH - + * How many packets HTC should allow to accumulate in a send queue + * before calling the EpSendFull callback to see whether to retain + * or drop packets. + * This is not relevant for LL, where tx descriptors should be immediately + * downloaded to the target. + * This is not very relevant for HL either, since it is anticipated that + * the HL tx download scheduler will not work this far in advance - rather, + * it will make its decisions just-in-time, so it can be responsive to + * changing conditions. + * Hence, this queue depth threshold spec is mostly just a formality. + */ +#define HTT_MAX_SEND_QUEUE_DEPTH 64 + +#define IS_PWR2(value) (((value) ^ ((value)-1)) == ((value) << 1) - 1) + +/* + * HTT_RX_PRE_ALLOC_POOL_SIZE - + * How many Rx Buffer should be there in pre-allocated pool of buffers. + * This is mainly for low memory condition where kernel fails to alloc + * SKB buffer to the Rx ring. + */ +#define HTT_RX_PRE_ALLOC_POOL_SIZE 64 +/* Max rx MSDU size including L2 headers */ +#define MSDU_SIZE 1560 +/* Rounding up to a cache line size. */ +#define HTT_RX_BUF_SIZE roundup(MSDU_SIZE + \ + sizeof(struct htt_host_rx_desc_base), \ + QDF_CACHE_LINE_SZ) +#define MAX_RX_PAYLOAD_SZ (HTT_RX_BUF_SIZE - RX_STD_DESC_SIZE) +/* + * DMA_MAP expects the buffer to be an integral number of cache lines. + * Rather than checking the actual cache line size, this code makes a + * conservative estimate of what the cache line size could be. + */ +#define HTT_LOG2_MAX_CACHE_LINE_SIZE 7 /* 2^7 = 128 */ +#define HTT_MAX_CACHE_LINE_SIZE_MASK ((1 << HTT_LOG2_MAX_CACHE_LINE_SIZE) - 1) + +#ifdef BIG_ENDIAN_HOST +/* + * big-endian: bytes within a 4-byte "word" are swapped: + * pre-swap post-swap + * index index + * 0 3 + * 1 2 + * 2 1 + * 3 0 + * 4 7 + * 5 6 + * etc. + * To compute the post-swap index from the pre-swap index, compute + * the byte offset for the start of the word (index & ~0x3) and add + * the swapped byte offset within the word (3 - (index & 0x3)). + */ +#define HTT_ENDIAN_BYTE_IDX_SWAP(idx) (((idx) & ~0x3) + (3 - ((idx) & 0x3))) +#else +/* little-endian: no adjustment needed */ +#define HTT_ENDIAN_BYTE_IDX_SWAP(idx) idx +#endif + +#define HTT_TX_MUTEX_INIT(_mutex) \ + qdf_spinlock_create(_mutex) + +#define HTT_TX_MUTEX_ACQUIRE(_mutex) \ + qdf_spin_lock_bh(_mutex) + +#define HTT_TX_MUTEX_RELEASE(_mutex) \ + qdf_spin_unlock_bh(_mutex) + +#define HTT_TX_MUTEX_DESTROY(_mutex) \ + qdf_spinlock_destroy(_mutex) + +#ifdef ATH_11AC_TXCOMPACT + +#define HTT_TX_NBUF_QUEUE_MUTEX_INIT(_pdev) \ + qdf_spinlock_create(&_pdev->txnbufq_mutex) + +#define HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(_pdev) \ + HTT_TX_MUTEX_DESTROY(&_pdev->txnbufq_mutex) + +#define HTT_TX_NBUF_QUEUE_REMOVE(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + _msdu = qdf_nbuf_queue_remove(&_pdev->txnbufq);\ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) + +#define HTT_TX_NBUF_QUEUE_ADD(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + qdf_nbuf_queue_add(&_pdev->txnbufq, _msdu); \ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) + +#define HTT_TX_NBUF_QUEUE_INSERT_HEAD(_pdev, _msdu) do { \ + HTT_TX_MUTEX_ACQUIRE(&_pdev->txnbufq_mutex); \ + qdf_nbuf_queue_insert_head(&_pdev->txnbufq, _msdu);\ + HTT_TX_MUTEX_RELEASE(&_pdev->txnbufq_mutex); \ + } while (0) +#else + +#define HTT_TX_NBUF_QUEUE_MUTEX_INIT(_pdev) +#define HTT_TX_NBUF_QUEUE_REMOVE(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_ADD(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_INSERT_HEAD(_pdev, _msdu) +#define HTT_TX_NBUF_QUEUE_MUTEX_DESTROY(_pdev) + +#endif + +#ifdef CONFIG_HL_SUPPORT + +static inline void htt_tx_resume_handler(void *context) +{ +} +#else + +void htt_tx_resume_handler(void *context); +#endif + +#ifdef ATH_11AC_TXCOMPACT +#define HTT_TX_SCHED htt_tx_sched +#else +#define HTT_TX_SCHED(pdev) /* no-op */ +#endif + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems); + +void htt_tx_detach(struct htt_pdev_t *pdev); + +int htt_rx_attach(struct htt_pdev_t *pdev); + +#if defined(CONFIG_HL_SUPPORT) + +static inline void htt_rx_detach(struct htt_pdev_t *pdev) +{ +} +#else + +void htt_rx_detach(struct htt_pdev_t *pdev); +#endif + +int htt_htc_attach(struct htt_pdev_t *pdev, uint16_t service_id); + +void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt); +#ifdef WLAN_FEATURE_FASTPATH +void htt_t2h_msg_handler_fast(void *htt_pdev, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls); +#else +static inline void htt_t2h_msg_handler_fast(void *htt_pdev, + qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls) +{ +} +#endif + +void htt_h2t_send_complete(void *context, HTC_PACKET *pkt); + +QDF_STATUS htt_h2t_ver_req_msg(struct htt_pdev_t *pdev); + +int htt_tx_padding_credit_update_handler(void *context, int pad_credit); + +#if defined(HELIUMPLUS) +QDF_STATUS +htt_h2t_frag_desc_bank_cfg_msg(struct htt_pdev_t *pdev); +#endif /* defined(HELIUMPLUS) */ + +QDF_STATUS htt_h2t_rx_ring_cfg_msg_ll(struct htt_pdev_t *pdev); + +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_ll(struct htt_pdev_t *pdev); + +QDF_STATUS htt_h2t_rx_ring_rfs_cfg_msg_hl(struct htt_pdev_t *pdev); + +QDF_STATUS htt_h2t_rx_ring_cfg_msg_hl(struct htt_pdev_t *pdev); + +extern QDF_STATUS (*htt_h2t_rx_ring_cfg_msg)(struct htt_pdev_t *pdev); + +enum htc_send_full_action htt_h2t_full(void *context, HTC_PACKET *pkt); + +struct htt_htc_pkt *htt_htc_pkt_alloc(struct htt_pdev_t *pdev); + +void htt_htc_pkt_free(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt); + +void htt_htc_pkt_pool_free(struct htt_pdev_t *pdev); + +#ifdef ATH_11AC_TXCOMPACT +void htt_htc_misc_pkt_list_trim(struct htt_pdev_t *pdev, int level); + +void +htt_htc_misc_pkt_list_add(struct htt_pdev_t *pdev, struct htt_htc_pkt *pkt); + +void htt_htc_misc_pkt_pool_free(struct htt_pdev_t *pdev); +#endif + +#ifdef WLAN_FULL_REORDER_OFFLOAD +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf); +#else +static inline int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf) +{ + return 0; +} +#endif + +qdf_nbuf_t +htt_rx_hash_list_lookup(struct htt_pdev_t *pdev, qdf_dma_addr_t paddr); + +#ifdef IPA_OFFLOAD +int +htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base); + +int +htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, unsigned int rx_ind_ring_size); + +int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev); + +int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev); + +#else +/** + * htt_tx_ipa_uc_attach() - attach htt ipa uc tx resource + * @pdev: htt context + * @uc_tx_buf_sz: single tx buffer size + * @uc_tx_buf_cnt: total tx buffer count + * @uc_tx_partition_base: tx buffer partition start + * + * Return: 0 success + */ +static inline int +htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + return 0; +} + +/** + * htt_rx_ipa_uc_attach() - attach htt ipa uc rx resource + * @pdev: htt context + * @rx_ind_ring_size: rx ring size + * + * Return: 0 success + */ +static inline int +htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, unsigned int rx_ind_ring_size) +{ + return 0; +} + +static inline int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + return 0; +} + +#endif /* IPA_OFFLOAD */ + +/* Maximum Outstanding Bus Download */ +#define HTT_MAX_BUS_CREDIT 33 + +#ifdef CONFIG_HL_SUPPORT + +/** + * htt_tx_credit_update() - check for diff in bus delta and target delta + * @pdev: pointer to htt device. + * + * Return: min of bus delta and target delta + */ +int +htt_tx_credit_update(struct htt_pdev_t *pdev); +#else + +static inline int +htt_tx_credit_update(struct htt_pdev_t *pdev) +{ + return 0; +} +#endif + + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +#define HTT_TX_GROUP_INDEX_OFFSET \ +(sizeof(struct htt_txq_group) / sizeof(u_int32_t)) + +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word); +#else + +static inline +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) +{ +} +#endif + +#ifdef DEBUG_RX_RING_BUFFER +/** + * htt_rx_dbg_rxbuf_init() - init debug rx buff list + * @pdev: pdev handle + * + * Allocation is done from bss segment. This uses vmalloc and has a bit + * of an overhead compared to kmalloc (which qdf_mem_alloc wraps). The impact + * of the overhead to performance will need to be quantified. + * + * Return: none + */ +static struct rx_buf_debug rx_buff_list_bss[HTT_RX_RING_BUFF_DBG_LIST]; +static inline +void htt_rx_dbg_rxbuf_init(struct htt_pdev_t *pdev) +{ + pdev->rx_buff_list = rx_buff_list_bss; + qdf_spinlock_create(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_index = 0; + pdev->rx_buff_posted_cum = 0; + pdev->rx_buff_recvd_cum = 0; + pdev->rx_buff_recvd_err = 0; + pdev->refill_retry_timer_starts = 0; + pdev->refill_retry_timer_calls = 0; + pdev->refill_retry_timer_doubles = 0; +} + +/** + * htt_display_rx_buf_debug() - display debug rx buff list and some counters + * @pdev: pdev handle + * + * Return: Success + */ +static inline int htt_display_rx_buf_debug(struct htt_pdev_t *pdev) +{ + int i; + struct rx_buf_debug *buf; + + if ((pdev) && + (pdev->rx_buff_list)) { + buf = pdev->rx_buff_list; + for (i = 0; i < HTT_RX_RING_BUFF_DBG_LIST; i++) { + if (buf[i].posted != 0) + qdf_nofl_info("[%d][0x%x] %pK %lu %pK %llu %llu", + i, buf[i].cpu, + buf[i].nbuf_data, + (unsigned long)buf[i].paddr, + buf[i].nbuf, + buf[i].posted, + buf[i].recved); + } + + qdf_nofl_info("rxbuf_idx %d all_posted: %d all_recvd: %d recv_err: %d", + pdev->rx_buff_index, + pdev->rx_buff_posted_cum, + pdev->rx_buff_recvd_cum, + pdev->rx_buff_recvd_err); + + qdf_nofl_info("timer kicks :%d actual :%d restarts:%d debtors: %d fill_n: %d", + pdev->refill_retry_timer_starts, + pdev->refill_retry_timer_calls, + pdev->refill_retry_timer_doubles, + pdev->rx_buff_debt_invoked, + pdev->rx_buff_fill_n_invoked); + } else + return -EINVAL; + return 0; +} + +/** + * htt_rx_dbg_rxbuf_set() - set element of rx buff list + * @pdev: pdev handle + * @paddr: physical address of netbuf + * @rx_netbuf: received netbuf + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_set(struct htt_pdev_t *pdev, qdf_dma_addr_t paddr, + qdf_nbuf_t rx_netbuf) +{ + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_list[pdev->rx_buff_index].paddr = paddr; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf = rx_netbuf; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf_data = + rx_netbuf->data; + pdev->rx_buff_list[pdev->rx_buff_index].posted = + qdf_get_log_timestamp(); + pdev->rx_buff_posted_cum++; + pdev->rx_buff_list[pdev->rx_buff_index].recved = 0; + pdev->rx_buff_list[pdev->rx_buff_index].cpu = + (1 << qdf_get_cpu()); + QDF_NBUF_CB_RX_MAP_IDX(rx_netbuf) = pdev->rx_buff_index; + if (++pdev->rx_buff_index >= + HTT_RX_RING_BUFF_DBG_LIST) + pdev->rx_buff_index = 0; + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} + +/** + * htt_rx_dbg_rxbuf_set() - reset element of rx buff list + * @pdev: pdev handle + * @netbuf: rx sk_buff + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_reset(struct htt_pdev_t *pdev, + qdf_nbuf_t netbuf) +{ + uint32_t index; + + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + index = QDF_NBUF_CB_RX_MAP_IDX(netbuf); + if (index < HTT_RX_RING_BUFF_DBG_LIST) { + pdev->rx_buff_list[index].recved = + qdf_get_log_timestamp(); + pdev->rx_buff_recvd_cum++; + } else { + pdev->rx_buff_recvd_err++; + } + pdev->rx_buff_list[pdev->rx_buff_index].cpu |= + (1 << qdf_get_cpu()); + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} +/** + * htt_rx_dbg_rxbuf_indupd() - add a record for alloc index update + * @pdev: pdev handle + * @idx : value of the index + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_indupd(struct htt_pdev_t *pdev, int alloc_index) +{ + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_list[pdev->rx_buff_index].paddr = 0; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf = 0; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf_data = 0; + pdev->rx_buff_list[pdev->rx_buff_index].posted = + qdf_get_log_timestamp(); + pdev->rx_buff_list[pdev->rx_buff_index].recved = + (uint64_t)alloc_index; + pdev->rx_buff_list[pdev->rx_buff_index].cpu = + (1 << qdf_get_cpu()); + if (++pdev->rx_buff_index >= + HTT_RX_RING_BUFF_DBG_LIST) + pdev->rx_buff_index = 0; + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} +/** + * htt_rx_dbg_rxbuf_httrxind() - add a record for recipt of htt rx_ind msg + * @pdev: pdev handle + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_httrxind(struct htt_pdev_t *pdev, unsigned int msdu_cnt) +{ + if (pdev->rx_buff_list) { + qdf_spin_lock_bh(&(pdev->rx_buff_list_lock)); + pdev->rx_buff_list[pdev->rx_buff_index].paddr = msdu_cnt; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf = 0; + pdev->rx_buff_list[pdev->rx_buff_index].nbuf_data = 0; + pdev->rx_buff_list[pdev->rx_buff_index].posted = + qdf_get_log_timestamp(); + pdev->rx_buff_list[pdev->rx_buff_index].recved = + (uint64_t)0x48545452584D5347; /* 'HTTRXMSG' */ + pdev->rx_buff_list[pdev->rx_buff_index].cpu = + (1 << qdf_get_cpu()); + if (++pdev->rx_buff_index >= + HTT_RX_RING_BUFF_DBG_LIST) + pdev->rx_buff_index = 0; + qdf_spin_unlock_bh(&(pdev->rx_buff_list_lock)); + } +} + +/** + * htt_rx_dbg_rxbuf_deinit() - deinit debug rx buff list + * @pdev: pdev handle + * + * Return: none + */ +static inline +void htt_rx_dbg_rxbuf_deinit(struct htt_pdev_t *pdev) +{ + if (pdev->rx_buff_list) + pdev->rx_buff_list = NULL; + qdf_spinlock_destroy(&(pdev->rx_buff_list_lock)); +} +#else +static inline +void htt_rx_dbg_rxbuf_init(struct htt_pdev_t *pdev) +{ +} +static inline int htt_display_rx_buf_debug(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline +void htt_rx_dbg_rxbuf_set(struct htt_pdev_t *pdev, + uint32_t paddr, + qdf_nbuf_t rx_netbuf) +{ +} +static inline +void htt_rx_dbg_rxbuf_reset(struct htt_pdev_t *pdev, + qdf_nbuf_t netbuf) +{ +} +static inline +void htt_rx_dbg_rxbuf_indupd(struct htt_pdev_t *pdev, + int alloc_index) +{ +} +static inline +void htt_rx_dbg_rxbuf_httrxind(struct htt_pdev_t *pdev, + unsigned int msdu_cnt) +{ +} +static inline +void htt_rx_dbg_rxbuf_deinit(struct htt_pdev_t *pdev) +{ + return; +} +#endif + +#ifndef HTT_RX_RING_SIZE_MIN +#define HTT_RX_RING_SIZE_MIN 128 /* slightly > than one large A-MPDU */ +#endif + +#ifndef HTT_RX_RING_SIZE_MAX +#define HTT_RX_RING_SIZE_MAX 2048 /* ~20 ms @ 1 Gbps of 1500B MSDUs */ +#endif + +#ifndef HTT_RX_RING_SIZE_1x1 +#define HTT_RX_RING_SIZE_1x1 1024 /* ~20 ms @ 400 Mbps of 1500B MSDUs */ +#endif + +#ifndef HTT_RX_AVG_FRM_BYTES +#define HTT_RX_AVG_FRM_BYTES 1000 +#endif + +#define HTT_FCS_LEN (4) + +#ifdef HTT_DEBUG_DATA +#define HTT_PKT_DUMP(x) x +#else +#define HTT_PKT_DUMP(x) /* no-op */ +#endif + +#ifdef RX_HASH_DEBUG +#define HTT_RX_CHECK_MSDU_COUNT(msdu_count) HTT_ASSERT_ALWAYS(msdu_count) +#else +#define HTT_RX_CHECK_MSDU_COUNT(msdu_count) /* no-op */ +#endif + +#if HTT_PADDR64 +#define NEXT_FIELD_OFFSET_IN32 2 +#else /* ! HTT_PADDR64 */ +#define NEXT_FIELD_OFFSET_IN32 1 +#endif /* HTT_PADDR64 */ + +#define RX_PADDR_MAGIC_PATTERN 0xDEAD0000 + +#if HTT_PADDR64 +static inline qdf_dma_addr_t htt_paddr_trim_to_37(qdf_dma_addr_t paddr) +{ + qdf_dma_addr_t ret = paddr; + + if (sizeof(paddr) > 4) + ret &= 0x1fffffffff; + return ret; +} +#else /* not 64 bits */ +static inline qdf_dma_addr_t htt_paddr_trim_to_37(qdf_dma_addr_t paddr) +{ + return paddr; +} +#endif /* HTT_PADDR64 */ + +#ifdef WLAN_FULL_REORDER_OFFLOAD +#ifdef ENABLE_DEBUG_ADDRESS_MARKING +static inline qdf_dma_addr_t +htt_rx_paddr_unmark_high_bits(qdf_dma_addr_t paddr) +{ + uint32_t markings; + + if (sizeof(qdf_dma_addr_t) > 4) { + markings = (uint32_t)((paddr >> 16) >> 16); + /* + * check if it is marked correctly: + * See the mark_high_bits function above for the expected + * pattern. + * the LS 5 bits are the high bits of physical address + * padded (with 0b0) to 8 bits + */ + if ((markings & 0xFFFF0000) != RX_PADDR_MAGIC_PATTERN) { + qdf_print("paddr not marked correctly: 0x%pK!\n", + (void *)paddr); + HTT_ASSERT_ALWAYS(0); + } + + /* clear markings for further use */ + paddr = htt_paddr_trim_to_37(paddr); + } + return paddr; +} + +static inline +qdf_dma_addr_t htt_rx_in_ord_paddr_get(uint32_t *u32p) +{ + qdf_dma_addr_t paddr = 0; + + paddr = (qdf_dma_addr_t)HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p); + if (sizeof(qdf_dma_addr_t) > 4) { + u32p++; + /* 32 bit architectures dont like <<32 */ + paddr |= (((qdf_dma_addr_t) + HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p)) + << 16 << 16); + } + paddr = htt_rx_paddr_unmark_high_bits(paddr); + + return paddr; +} +#else +#if HTT_PADDR64 +static inline +qdf_dma_addr_t htt_rx_in_ord_paddr_get(uint32_t *u32p) +{ + qdf_dma_addr_t paddr = 0; + + paddr = (qdf_dma_addr_t)HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p); + if (sizeof(qdf_dma_addr_t) > 4) { + u32p++; + /* 32 bit architectures dont like <<32 */ + paddr |= (((qdf_dma_addr_t) + HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p)) + << 16 << 16); + } + return paddr; +} +#else +static inline +qdf_dma_addr_t htt_rx_in_ord_paddr_get(uint32_t *u32p) +{ + return HTT_RX_IN_ORD_PADDR_IND_PADDR_GET(*u32p); +} +#endif +#endif /* ENABLE_DEBUG_ADDRESS_MARKING */ + +static inline +unsigned int htt_rx_in_order_ring_elems(struct htt_pdev_t *pdev) +{ + return (*pdev->rx_ring.alloc_idx.vaddr - + *pdev->rx_ring.target_idx.vaddr) & + pdev->rx_ring.size_mask; +} + +static inline qdf_nbuf_t +htt_rx_in_order_netbuf_pop(htt_pdev_handle pdev, qdf_dma_addr_t paddr) +{ + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + qdf_atomic_dec(&pdev->rx_ring.fill_cnt); + paddr = htt_paddr_trim_to_37(paddr); + return htt_rx_hash_list_lookup(pdev, paddr); +} + +#else +static inline +qdf_dma_addr_t htt_rx_in_ord_paddr_get(uint32_t *u32p) +{ + return 0; +} + +static inline qdf_nbuf_t +htt_rx_in_order_netbuf_pop(htt_pdev_handle pdev, qdf_dma_addr_t paddr) +{ + return NULL; +} +#endif + +#if defined(FEATURE_MONITOR_MODE_SUPPORT) && defined(WLAN_FULL_REORDER_OFFLOAD) +int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt); + +/** + * htt_rx_mon_get_rx_status() - Update information about the rx status, + * which is used later for radiotap updation. + * @pdev: Pointer to pdev handle + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * @rx_status: Return variable updated with rx_status + * + * Return: None + */ +void htt_rx_mon_get_rx_status(htt_pdev_handle pdev, + struct htt_host_rx_desc_base *rx_desc, + struct mon_rx_status *rx_status); +#else +static inline +int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt) +{ + return 0; +} + +static inline +void htt_rx_mon_get_rx_status(htt_pdev_handle pdev, + struct htt_host_rx_desc_base *rx_desc, + struct mon_rx_status *rx_status) +{ +} +#endif + +#endif /* _HTT_INTERNAL__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_monitor_rx.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_monitor_rx.c new file mode 100644 index 0000000000..c0725c3a82 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_monitor_rx.c @@ -0,0 +1,1079 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_mem_malloc,free, etc. */ +#include /* qdf_print, bool */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_timer_free */ + +#include /* HTT_HL_RX_DESC_SIZE */ +#include +#include +#include +#include /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ +#include "regtable.h" + +#include /* ieee80211_frame, ieee80211_qoscntl */ +#include +#include +#include "ol_txrx_types.h" +#ifdef DEBUG_DMA_DONE +#include +#include +#endif +#include + +#define HTT_FCS_LEN (4) + +enum { + HW_RX_DECAP_FORMAT_RAW = 0, + HW_RX_DECAP_FORMAT_NWIFI, + HW_RX_DECAP_FORMAT_8023, + HW_RX_DECAP_FORMAT_ETH2, +}; + +struct mon_rx_status g_ppdu_rx_status; + +/** + * htt_rx_mon_note_capture_channel() - Make note of channel to update in + * radiotap + * @pdev: handle to htt_pdev + * @mon_ch: capture channel number. + * + * Return: None + */ +void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch) +{ + struct mon_channel *ch_info = &pdev->mon_ch_info; + + ch_info->ch_num = mon_ch; + ch_info->ch_freq = cds_chan_to_freq(mon_ch); +} + +#ifndef CONFIG_HL_SUPPORT +/** + * htt_mon_rx_handle_amsdu_packet() - Handle consecutive fragments of amsdu + * @msdu: pointer to first msdu of amsdu + * @pdev: Handle to htt_pdev_handle + * @msg_word: Input and output variable, so pointer to HTT msg pointer + * @amsdu_len: remaining length of all N-1 msdu msdu's + * @frag_cnt: number of frags handled + * + * This function handles the (N-1) msdu's of amsdu, N'th msdu is already + * handled by calling function. N-1 msdu's are tied using frags_list. + * msdu_info field updated by FW indicates if this is last msdu. All the + * msdu's before last msdu will be of MAX payload. + * + * Return: 1 on success and 0 on failure. + */ +static +int htt_mon_rx_handle_amsdu_packet(qdf_nbuf_t msdu, htt_pdev_handle pdev, + uint32_t **msg_word, uint32_t amsdu_len, + uint32_t *frag_cnt) +{ + qdf_nbuf_t frag_nbuf; + qdf_nbuf_t prev_frag_nbuf; + uint32_t len; + uint32_t last_frag; + qdf_dma_addr_t paddr; + + *msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(*msg_word); + frag_nbuf = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(!frag_nbuf)) { + qdf_print("netbuf pop failed!"); + return 0; + } + *frag_cnt = *frag_cnt + 1; + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *)*msg_word)-> + msdu_info; + qdf_nbuf_append_ext_list(msdu, frag_nbuf, amsdu_len); + qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE); + /* For msdu's other than parent will not have htt_host_rx_desc_base */ + len = QDF_MIN(amsdu_len, HTT_RX_BUF_SIZE); + amsdu_len -= len; + qdf_nbuf_trim_tail(frag_nbuf, HTT_RX_BUF_SIZE - len); + + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_HIGH, + qdf_nbuf_data(frag_nbuf), + qdf_nbuf_len(frag_nbuf))); + prev_frag_nbuf = frag_nbuf; + while (!last_frag) { + *msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(*msg_word); + frag_nbuf = htt_rx_in_order_netbuf_pop(pdev, paddr); + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *) + *msg_word)->msdu_info; + + if (qdf_unlikely(!frag_nbuf)) { + qdf_print("netbuf pop failed!"); + prev_frag_nbuf->next = NULL; + return 0; + } + *frag_cnt = *frag_cnt + 1; + qdf_nbuf_set_pktlen(frag_nbuf, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, frag_nbuf, QDF_DMA_FROM_DEVICE); + + len = QDF_MIN(amsdu_len, HTT_RX_BUF_SIZE); + amsdu_len -= len; + qdf_nbuf_trim_tail(frag_nbuf, HTT_RX_BUF_SIZE - len); + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_HIGH, + qdf_nbuf_data(frag_nbuf), + qdf_nbuf_len(frag_nbuf))); + + qdf_nbuf_set_next(prev_frag_nbuf, frag_nbuf); + prev_frag_nbuf = frag_nbuf; + } + qdf_nbuf_set_next(prev_frag_nbuf, NULL); + return 1; +} + +#define SHORT_PREAMBLE 1 +#define LONG_PREAMBLE 0 +#ifdef HELIUMPLUS +/** + * htt_rx_get_rate() - get rate info in terms of 500Kbps from htt_rx_desc + * @l_sig_rate_select: OFDM or CCK rate + * @l_sig_rate: + * + * If l_sig_rate_select is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If l_sig_rate_select is 1: + * 0x1: DSSS 1 Mbps long preamble + * 0x2: DSSS 2 Mbps long preamble + * 0x3: CCK 5.5 Mbps long preamble + * 0x4: CCK 11 Mbps long preamble + * 0x5: DSSS 2 Mbps short preamble + * 0x6: CCK 5.5 Mbps + * 0x7: CCK 11 Mbps short preamble + * + * Return: rate interms of 500Kbps. + */ +static unsigned char htt_rx_get_rate(uint32_t l_sig_rate_select, + uint32_t l_sig_rate, uint8_t *preamble) +{ + char ret = 0x0; + *preamble = SHORT_PREAMBLE; + if (l_sig_rate_select == 0) { + switch (l_sig_rate) { + case 0x8: + ret = 0x60; + break; + case 0x9: + ret = 0x30; + break; + case 0xA: + ret = 0x18; + break; + case 0xB: + ret = 0x0c; + break; + case 0xC: + ret = 0x6c; + break; + case 0xD: + ret = 0x48; + break; + case 0xE: + ret = 0x24; + break; + case 0xF: + ret = 0x12; + break; + default: + break; + } + } else if (l_sig_rate_select == 1) { + switch (l_sig_rate) { + case 0x1: + ret = 0x2; + *preamble = LONG_PREAMBLE; + break; + case 0x2: + ret = 0x4; + *preamble = LONG_PREAMBLE; + break; + case 0x3: + ret = 0xB; + *preamble = LONG_PREAMBLE; + break; + case 0x4: + ret = 0x16; + *preamble = LONG_PREAMBLE; + break; + case 0x5: + ret = 0x4; + break; + case 0x6: + ret = 0xB; + break; + case 0x7: + ret = 0x16; + break; + default: + break; + } + } else { + qdf_print("Invalid rate info\n"); + } + return ret; +} +#else +/** + * htt_rx_get_rate() - get rate info in terms of 500Kbps from htt_rx_desc + * @l_sig_rate_select: OFDM or CCK rate + * @l_sig_rate: + * + * If l_sig_rate_select is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If l_sig_rate_select is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * + * Return: rate interms of 500Kbps. + */ +static unsigned char htt_rx_get_rate(uint32_t l_sig_rate_select, + uint32_t l_sig_rate, uint8_t *preamble) +{ + char ret = 0x0; + *preamble = SHORT_PREAMBLE; + if (l_sig_rate_select == 0) { + switch (l_sig_rate) { + case 0x8: + ret = 0x60; + break; + case 0x9: + ret = 0x30; + break; + case 0xA: + ret = 0x18; + break; + case 0xB: + ret = 0x0c; + break; + case 0xC: + ret = 0x6c; + break; + case 0xD: + ret = 0x48; + break; + case 0xE: + ret = 0x24; + break; + case 0xF: + ret = 0x12; + break; + default: + break; + } + } else if (l_sig_rate_select == 1) { + switch (l_sig_rate) { + case 0x8: + ret = 0x16; + *preamble = LONG_PREAMBLE; + break; + case 0x9: + ret = 0x0B; + *preamble = LONG_PREAMBLE; + break; + case 0xA: + ret = 0x4; + *preamble = LONG_PREAMBLE; + break; + case 0xB: + ret = 0x02; + *preamble = LONG_PREAMBLE; + break; + case 0xC: + ret = 0x16; + break; + case 0xD: + ret = 0x0B; + break; + case 0xE: + ret = 0x04; + break; + default: + break; + } + } else { + qdf_print("Invalid rate info\n"); + } + return ret; +} +#endif /* HELIUMPLUS */ + +/** + * htt_mon_rx_get_phy_info() - Get phy info + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * @rx_status: Return variable updated with phy_info in rx_status + * + * Return: None + */ +static void htt_mon_rx_get_phy_info(struct htt_host_rx_desc_base *rx_desc, + struct mon_rx_status *rx_status) +{ + uint8_t preamble = 0; + uint8_t preamble_type = rx_desc->ppdu_start.preamble_type; + uint8_t mcs = 0, nss = 0, sgi = 0, bw = 0, beamformed = 0; + uint16_t vht_flags = 0, ht_flags = 0; + uint32_t l_sig_rate_select = rx_desc->ppdu_start.l_sig_rate_select; + uint32_t l_sig_rate = rx_desc->ppdu_start.l_sig_rate; + bool is_stbc = 0, ldpc = 0; + + switch (preamble_type) { + case 4: + /* legacy */ + rx_status->rate = htt_rx_get_rate(l_sig_rate_select, l_sig_rate, + &preamble); + break; + case 8: + is_stbc = ((VHT_SIG_A_2(rx_desc) >> 4) & 3); + fallthrough; + case 9: + ht_flags = 1; + sgi = (VHT_SIG_A_2(rx_desc) >> 7) & 0x01; + bw = (VHT_SIG_A_1(rx_desc) >> 7) & 0x01; + mcs = (VHT_SIG_A_1(rx_desc) & 0x7f); + nss = mcs >> 3; + beamformed = + (VHT_SIG_A_2(rx_desc) >> 8) & 0x1; + break; + case 0x0c: + is_stbc = (VHT_SIG_A_2(rx_desc) >> 3) & 1; + ldpc = (VHT_SIG_A_2(rx_desc) >> 2) & 1; + fallthrough; + case 0x0d: + { + uint8_t gid_in_sig = ((VHT_SIG_A_1(rx_desc) >> 4) & 0x3f); + + vht_flags = 1; + sgi = VHT_SIG_A_2(rx_desc) & 0x01; + bw = (VHT_SIG_A_1(rx_desc) & 0x03); + if (gid_in_sig == 0 || gid_in_sig == 63) { + /* SU case */ + mcs = (VHT_SIG_A_2(rx_desc) >> 4) & + 0xf; + nss = (VHT_SIG_A_1(rx_desc) >> 10) & + 0x7; + } else { + /* MU case */ + uint8_t sta_user_pos = + (uint8_t)((rx_desc->ppdu_start.reserved_4a >> 8) + & 0x3); + mcs = (rx_desc->ppdu_start.vht_sig_b >> 16); + if (bw >= 2) + mcs >>= 3; + else if (bw > 0) + mcs >>= 1; + mcs &= 0xf; + nss = (((VHT_SIG_A_1(rx_desc) >> 10) + + sta_user_pos * 3) & 0x7); + } + beamformed = (VHT_SIG_A_2(rx_desc) >> 8) & 0x1; + } + fallthrough; + default: + break; + } + + rx_status->mcs = mcs; + rx_status->bw = bw; + rx_status->nr_ant = nss; + rx_status->is_stbc = is_stbc; + rx_status->sgi = sgi; + rx_status->ldpc = ldpc; + rx_status->beamformed = beamformed; + rx_status->vht_flag_values3[0] = mcs << 0x4 | (nss + 1); + if (ht_flags) + rx_status->ht_mcs = mcs; + rx_status->ht_flags = ht_flags; + rx_status->vht_flags = vht_flags; + rx_status->rtap_flags |= ((preamble == SHORT_PREAMBLE) ? BIT(1) : 0); + rx_status->vht_flag_values2 = bw; +} + +/** + * htt_mon_rx_get_rtap_flags() - Get radiotap flags + * @rx_desc: Pointer to struct htt_host_rx_desc_base + * + * Return: Bitmapped radiotap flags. + */ +static uint8_t htt_mon_rx_get_rtap_flags(struct htt_host_rx_desc_base *rx_desc) +{ + uint8_t rtap_flags = 0; + + /* WEP40 || WEP104 || WEP128 */ + if (rx_desc->mpdu_start.encrypt_type == 0 || + rx_desc->mpdu_start.encrypt_type == 1 || + rx_desc->mpdu_start.encrypt_type == 3) + rtap_flags |= BIT(2); + + /* IEEE80211_RADIOTAP_F_FRAG */ + if (rx_desc->attention.fragment) + rtap_flags |= BIT(3); + + /* IEEE80211_RADIOTAP_F_FCS */ + rtap_flags |= BIT(4); + + /* IEEE80211_RADIOTAP_F_BADFCS */ + if (rx_desc->mpdu_end.fcs_err) + rtap_flags |= BIT(6); + + return rtap_flags; +} + +void htt_rx_mon_get_rx_status(htt_pdev_handle pdev, + struct htt_host_rx_desc_base *rx_desc, + struct mon_rx_status *rx_status) +{ + struct mon_channel *ch_info = &pdev->mon_ch_info; + + rx_status->tsft = (u_int64_t)TSF_TIMESTAMP(rx_desc); + rx_status->chan_freq = ch_info->ch_freq; + rx_status->chan_num = ch_info->ch_num; + htt_mon_rx_get_phy_info(rx_desc, rx_status); + rx_status->rtap_flags |= htt_mon_rx_get_rtap_flags(rx_desc); + + if (rx_desc->ppdu_start.l_sig_rate_select) + rx_status->cck_flag = 1; + else + rx_status->ofdm_flag = 1; + + rx_status->ant_signal_db = rx_desc->ppdu_start.rssi_comb; + rx_status->rssi_comb = rx_desc->ppdu_start.rssi_comb; + rx_status->chan_noise_floor = pdev->txrx_pdev->chan_noise_floor; +} + +/** + * htt_rx_mon_amsdu_rx_in_order_pop_ll() - Monitor mode HTT Rx in order pop + * function + * @pdev: Handle to htt_pdev_handle + * @rx_ind_msg: In order indication message. + * @head_msdu: Return variable pointing to head msdu. + * @tail_msdu: Return variable pointing to tail msdu. + * + * This function pops the msdu based on paddr:length of inorder indication + * message. + * + * Return: 1 for success, 0 on failure. + */ +int htt_rx_mon_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt) +{ + qdf_nbuf_t msdu, next, prev = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + uint32_t msdu_count; + struct htt_host_rx_desc_base *rx_desc; + uint32_t amsdu_len; + uint32_t len; + uint32_t last_frag; + qdf_dma_addr_t paddr; + static uint8_t preamble_type; + static uint32_t vht_sig_a_1; + static uint32_t vht_sig_a_2; + + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + + *replenish_cnt = 0; + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_HIGH, + (void *)rx_ind_data, + (int)qdf_nbuf_len(rx_ind_msg))); + + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + HTT_RX_CHECK_MSDU_COUNT(msdu_count); + + msg_word = (uint32_t *)(rx_ind_data + + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES); + paddr = htt_rx_in_ord_paddr_get(msg_word); + msdu = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (qdf_unlikely(!msdu)) { + qdf_print("netbuf pop failed!"); + *tail_msdu = NULL; + return 0; + } + *replenish_cnt = *replenish_cnt + 1; + + while (msdu_count > 0) { + msdu_count--; + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); + + /* + * cache consistency has been taken care of by the + * qdf_nbuf_unmap + */ + rx_desc = htt_rx_desc(msdu); + if ((unsigned int)(*(uint32_t *)&rx_desc->attention) & + RX_DESC_ATTN_MPDU_LEN_ERR_BIT) { + qdf_nbuf_free(msdu); + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *) + msg_word)->msdu_info; + while (!last_frag) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + msdu = htt_rx_in_order_netbuf_pop(pdev, paddr); + last_frag = ((struct + htt_rx_in_ord_paddr_ind_msdu_t *) + msg_word)->msdu_info; + if (qdf_unlikely(!msdu)) { + qdf_print("netbuf pop failed!"); + return 0; + } + *replenish_cnt = *replenish_cnt + 1; + qdf_nbuf_unmap(pdev->osdev, msdu, + QDF_DMA_FROM_DEVICE); + qdf_nbuf_free(msdu); + } + msdu = prev; + goto next_pop; + } + + if (!prev) + (*head_msdu) = msdu; + prev = msdu; + + HTT_PKT_DUMP(htt_print_rx_desc(rx_desc)); + + /* + * Only the first mpdu has valid preamble type, so use it + * till the last mpdu is reached + */ + if (rx_desc->attention.first_mpdu) { + preamble_type = rx_desc->ppdu_start.preamble_type; + if (preamble_type == 8 || preamble_type == 9 || + preamble_type == 0x0c || preamble_type == 0x0d) { + vht_sig_a_1 = VHT_SIG_A_1(rx_desc); + vht_sig_a_2 = VHT_SIG_A_2(rx_desc); + } + } else { + rx_desc->ppdu_start.preamble_type = preamble_type; + if (preamble_type == 8 || preamble_type == 9 || + preamble_type == 0x0c || preamble_type == 0x0d) { + VHT_SIG_A_1(rx_desc) = vht_sig_a_1; + VHT_SIG_A_2(rx_desc) = vht_sig_a_2; + } + } + + if (rx_desc->attention.last_mpdu) { + preamble_type = 0; + vht_sig_a_1 = 0; + vht_sig_a_2 = 0; + } + + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + if (rx_desc->attention.first_mpdu) { + memset(&g_ppdu_rx_status, 0, + sizeof(struct mon_rx_status)); + htt_rx_mon_get_rx_status(pdev, rx_desc, + &g_ppdu_rx_status); + } + /* + * For certain platform, 350 bytes of headroom is already + * appended to accommodate radiotap header but + * qdf_nbuf_update_radiotap() API again will try to create + * a room for radiotap header. To make our design simple + * let qdf_nbuf_update_radiotap() API create a room for radiotap + * header and update it, do qdf_nbuf_pull_head() operation and + * pull 350 bytes of headroom. + * + * + * + * (SKB buffer) + * skb->head --> +-----------+ <-- skb->data + * | | (Before pulling headroom) + * | | + * | HEAD | 350 bytes of headroom + * | | + * | | + * +-----------+ <-- skb->data + * | | (After pulling headroom) + * | | + * | DATA | + * | | + * | | + * +-----------+ + * | | + * | | + * | TAIL | + * | | + * | | + * +-----------+ + * + */ + if (qdf_nbuf_head(msdu) == qdf_nbuf_data(msdu)) + qdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION); + qdf_nbuf_update_radiotap(&g_ppdu_rx_status, msdu, + HTT_RX_STD_DESC_RESERVATION); + amsdu_len = HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET(*(msg_word + + NEXT_FIELD_OFFSET_IN32)); + + /* + * MAX_RX_PAYLOAD_SZ when we have AMSDU packet. amsdu_len in + * which case is the total length of sum of all AMSDU's + */ + len = QDF_MIN(amsdu_len, MAX_RX_PAYLOAD_SZ); + amsdu_len -= len; + qdf_nbuf_trim_tail(msdu, HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + len)); + + HTT_PKT_DUMP(qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_HIGH, + qdf_nbuf_data(msdu), + qdf_nbuf_len(msdu))); + last_frag = ((struct htt_rx_in_ord_paddr_ind_msdu_t *) + msg_word)->msdu_info; + + /* Handle amsdu packet */ + if (!last_frag) { + /* + * For AMSDU packet msdu->len is sum of all the msdu's + * length, msdu->data_len is sum of length's of + * remaining msdu's other than parent. + */ + if (!htt_mon_rx_handle_amsdu_packet(msdu, pdev, + &msg_word, + amsdu_len, + replenish_cnt)) { + qdf_print("failed to handle amsdu packet"); + return 0; + } + } + +next_pop: + /* check if this is the last msdu */ + if (msdu_count) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(!next)) { + qdf_print("netbuf pop failed!"); + *tail_msdu = NULL; + return 0; + } + *replenish_cnt = *replenish_cnt + 1; + if (msdu) + qdf_nbuf_set_next(msdu, next); + msdu = next; + } else { + *tail_msdu = msdu; + if (msdu) + qdf_nbuf_set_next(msdu, NULL); + } + } + + return 1; +} +#endif /* CONFIG_HL_SUPPORT */ + +#if defined(FEATURE_MONITOR_MODE_SUPPORT) +#if !defined(QCA6290_HEADERS_DEF) && !defined(QCA6390_HEADERS_DEF) && \ + !defined(QCA6490_HEADERS_DEF) && !defined(QCA6750_HEADERS_DEF) && \ + !defined(KIWI_HEADERS_DEF) +static void +htt_rx_parse_ppdu_start_status(struct htt_host_rx_desc_base *rx_desc, + struct ieee80211_rx_status *rs) +{ + struct rx_ppdu_start *ppdu_start = &rx_desc->ppdu_start; + + /* RSSI */ + rs->rs_rssi = ppdu_start->rssi_comb; + + /* PHY rate */ + /* + * rs_ratephy coding + * [b3 - b0] + * 0 -> OFDM + * 1 -> CCK + * 2 -> HT + * 3 -> VHT + * OFDM / CCK + * [b7 - b4 ] => LSIG rate + * [b23 - b8 ] => service field + * (b'12 static/dynamic, + * b'14..b'13 BW for VHT) + * [b31 - b24 ] => Reserved + * HT / VHT + * [b15 - b4 ] => SIG A_2 12 LSBs + * [b31 - b16] => SIG A_1 16 LSBs + */ + if (ppdu_start->preamble_type == 0x4) { + rs->rs_ratephy = ppdu_start->l_sig_rate_select; + rs->rs_ratephy |= ppdu_start->l_sig_rate << 4; + rs->rs_ratephy |= ppdu_start->service << 8; + } else { + rs->rs_ratephy = (ppdu_start->preamble_type & 0x4) ? 3 : 2; +#ifdef HELIUMPLUS + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_ah_sig_a_2 & 0xFFF) << 4; + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_ah_sig_a_1 & 0xFFFF) << 16; +#else + rs->rs_ratephy |= (ppdu_start->ht_sig_vht_sig_a_2 & 0xFFF) << 4; + rs->rs_ratephy |= + (ppdu_start->ht_sig_vht_sig_a_1 & 0xFFFF) << 16; +#endif + } +} + +/* Util fake function that has same prototype as qdf_nbuf_clone that just + * returns the same nbuf + */ +static qdf_nbuf_t htt_rx_qdf_noclone_buf(qdf_nbuf_t buf) +{ + return buf; +} + +/* This function is used by montior mode code to restitch an MSDU list + * corresponding to an MPDU back into an MPDU by linking up the skbs. + */ +qdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + qdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned int clone_not_reqd) +{ + qdf_nbuf_t msdu, mpdu_buf, prev_buf, msdu_orig, head_frag_list_cloned; + unsigned int decap_format, wifi_hdr_len, sec_hdr_len, msdu_llc_len, + mpdu_buf_len, decap_hdr_pull_bytes, frag_list_sum_len, dir, + is_amsdu, is_first_frag, amsdu_pad, msdu_len; + struct htt_host_rx_desc_base *rx_desc; + char *hdr_desc; + unsigned char *dest; + struct ieee80211_frame *wh; + struct ieee80211_qoscntl *qos; + + /* The nbuf has been pulled just beyond the status and points to the + * payload + */ + msdu_orig = head_msdu; + rx_desc = htt_rx_desc(msdu_orig); + + /* Fill out the rx_status from the PPDU start and end fields */ + if (rx_desc->attention.first_mpdu) { + htt_rx_parse_ppdu_start_status(rx_desc, rx_status); + + /* The timestamp is no longer valid - It will be valid only for + * the last MPDU + */ + rx_status->rs_tstamp.tsf = ~0; + } + + decap_format = + GET_FIELD(&rx_desc->msdu_start, RX_MSDU_START_2_DECAP_FORMAT); + + head_frag_list_cloned = NULL; + + /* Easy case - The MSDU status indicates that this is a non-decapped + * packet in RAW mode. + * return + */ + if (decap_format == HW_RX_DECAP_FORMAT_RAW) { + /* Note that this path might suffer from headroom unavailabilty, + * but the RX status is usually enough + */ + if (clone_not_reqd) + mpdu_buf = htt_rx_qdf_noclone_buf(head_msdu); + else + mpdu_buf = qdf_nbuf_clone(head_msdu); + + if (!mpdu_buf) + goto mpdu_stitch_fail; + + prev_buf = mpdu_buf; + + frag_list_sum_len = 0; + is_first_frag = 1; + msdu_len = qdf_nbuf_len(mpdu_buf); + + /* Drop the zero-length msdu */ + if (!msdu_len) + goto mpdu_stitch_fail; + + msdu_orig = qdf_nbuf_next(head_msdu); + + while (msdu_orig) { + /* TODO: intra AMSDU padding - do we need it ??? */ + if (clone_not_reqd) + msdu = htt_rx_qdf_noclone_buf(msdu_orig); + else + msdu = qdf_nbuf_clone(msdu_orig); + + if (!msdu) + goto mpdu_stitch_fail; + + if (is_first_frag) { + is_first_frag = 0; + head_frag_list_cloned = msdu; + } + + msdu_len = qdf_nbuf_len(msdu); + /* Drop the zero-length msdu */ + if (!msdu_len) + goto mpdu_stitch_fail; + + frag_list_sum_len += msdu_len; + + /* Maintain the linking of the cloned MSDUS */ + qdf_nbuf_set_next_ext(prev_buf, msdu); + + /* Move to the next */ + prev_buf = msdu; + msdu_orig = qdf_nbuf_next(msdu_orig); + } + + /* The last msdu length need be larger than HTT_FCS_LEN */ + if (msdu_len < HTT_FCS_LEN) + goto mpdu_stitch_fail; + + qdf_nbuf_trim_tail(prev_buf, HTT_FCS_LEN); + + /* If there were more fragments to this RAW frame */ + if (head_frag_list_cloned) { + qdf_nbuf_append_ext_list(mpdu_buf, + head_frag_list_cloned, + frag_list_sum_len); + } + + goto mpdu_stitch_done; + } + + /* Decap mode: + * Calculate the amount of header in decapped packet to knock off based + * on the decap type and the corresponding number of raw bytes to copy + * status header + */ + + hdr_desc = &rx_desc->rx_hdr_status[0]; + + /* Base size */ + wifi_hdr_len = sizeof(struct ieee80211_frame); + wh = (struct ieee80211_frame *)hdr_desc; + + dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + if (dir == IEEE80211_FC1_DIR_DSTODS) + wifi_hdr_len += 6; + + is_amsdu = 0; + if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + qos = (struct ieee80211_qoscntl *) + (hdr_desc + wifi_hdr_len); + wifi_hdr_len += 2; + + is_amsdu = (qos->i_qos[0] & IEEE80211_QOS_AMSDU); + } + + /* TODO: Any security headers associated with MPDU */ + sec_hdr_len = 0; + + /* MSDU related stuff LLC - AMSDU subframe header etc */ + msdu_llc_len = is_amsdu ? (14 + 8) : 8; + + mpdu_buf_len = wifi_hdr_len + sec_hdr_len + msdu_llc_len; + + /* "Decap" header to remove from MSDU buffer */ + decap_hdr_pull_bytes = 14; + + /* Allocate a new nbuf for holding the 802.11 header retrieved from the + * status of the now decapped first msdu. Leave enough headroom for + * accommodating any radio-tap /prism like PHY header + */ +#define HTT_MAX_MONITOR_HEADER (512) + mpdu_buf = qdf_nbuf_alloc(pdev->osdev, + HTT_MAX_MONITOR_HEADER + mpdu_buf_len, + HTT_MAX_MONITOR_HEADER, 4, false); + + if (!mpdu_buf) + goto mpdu_stitch_fail; + + /* Copy the MPDU related header and enc headers into the first buffer + * - Note that there can be a 2 byte pad between heaader and enc header + */ + + prev_buf = mpdu_buf; + dest = qdf_nbuf_put_tail(prev_buf, wifi_hdr_len); + if (!dest) + goto mpdu_stitch_fail; + qdf_mem_copy(dest, hdr_desc, wifi_hdr_len); + hdr_desc += wifi_hdr_len; + + /* NOTE - This padding is present only in the RAW header status - not + * when the MSDU data payload is in RAW format. + */ + /* Skip the "IV pad" */ + if (wifi_hdr_len & 0x3) + hdr_desc += 2; + + /* The first LLC len is copied into the MPDU buffer */ + frag_list_sum_len = 0; + frag_list_sum_len -= msdu_llc_len; + + msdu_orig = head_msdu; + is_first_frag = 1; + amsdu_pad = 0; + + while (msdu_orig) { + /* TODO: intra AMSDU padding - do we need it ??? */ + if (clone_not_reqd) + msdu = htt_rx_qdf_noclone_buf(msdu_orig); + else + msdu = qdf_nbuf_clone(msdu_orig); + + if (!msdu) + goto mpdu_stitch_fail; + + if (is_first_frag) { + is_first_frag = 0; + head_frag_list_cloned = msdu; + } else { + /* Maintain the linking of the cloned MSDUS */ + qdf_nbuf_set_next_ext(prev_buf, msdu); + + /* Reload the hdr ptr only on non-first MSDUs */ + rx_desc = htt_rx_desc(msdu_orig); + hdr_desc = &rx_desc->rx_hdr_status[0]; + } + + /* Copy this buffers MSDU related status into the prev buffer */ + dest = qdf_nbuf_put_tail(prev_buf, msdu_llc_len + amsdu_pad); + dest += amsdu_pad; + qdf_mem_copy(dest, hdr_desc, msdu_llc_len); + + /* Push the MSDU buffer beyond the decap header */ + qdf_nbuf_pull_head(msdu, decap_hdr_pull_bytes); + frag_list_sum_len += + msdu_llc_len + qdf_nbuf_len(msdu) + amsdu_pad; + + /* + * Set up intra-AMSDU pad to be added to start of next buffer - + * AMSDU pad is 4 byte pad on AMSDU subframe + */ + amsdu_pad = (msdu_llc_len + qdf_nbuf_len(msdu)) & 0x3; + amsdu_pad = amsdu_pad ? (4 - amsdu_pad) : 0; + + /* + * TODO FIXME How do we handle MSDUs that have fraglist - Should + * probably iterate all the frags cloning them along the way and + * and also updating the prev_buf pointer + */ + + /* Move to the next */ + prev_buf = msdu; + msdu_orig = qdf_nbuf_next(msdu_orig); + } + + /* TODO: Convert this to suitable qdf routines */ + qdf_nbuf_append_ext_list(mpdu_buf, head_frag_list_cloned, + frag_list_sum_len); + +mpdu_stitch_done: + /* Check if this buffer contains the PPDU end status for TSF */ + if (rx_desc->attention.last_mpdu) +#ifdef HELIUMPLUS + rx_status->rs_tstamp.tsf = + rx_desc->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32; +#else + rx_status->rs_tstamp.tsf = rx_desc->ppdu_end.tsf_timestamp; +#endif + /* All the nbufs have been linked into the ext list + * and then unlink the nbuf list + */ + if (clone_not_reqd) { + msdu = head_msdu; + while (msdu) { + msdu_orig = msdu; + msdu = qdf_nbuf_next(msdu); + qdf_nbuf_set_next(msdu_orig, NULL); + } + } + + return mpdu_buf; + +mpdu_stitch_fail: + /* Free these alloced buffers and the orig buffers in non-clone case */ + if (!clone_not_reqd) { + /* Free the head buffer */ + if (mpdu_buf) + qdf_nbuf_free(mpdu_buf); + + /* Free the partial list */ + while (head_frag_list_cloned) { + msdu = head_frag_list_cloned; + head_frag_list_cloned = + qdf_nbuf_next_ext(head_frag_list_cloned); + qdf_nbuf_free(msdu); + } + } else { + /* Free the alloced head buffer */ + if (decap_format != HW_RX_DECAP_FORMAT_RAW) + if (mpdu_buf) + qdf_nbuf_free(mpdu_buf); + + /* Free the orig buffers */ + msdu = head_msdu; + while (msdu) { + msdu_orig = msdu; + msdu = qdf_nbuf_next(msdu); + qdf_nbuf_free(msdu_orig); + } + } + + return NULL; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx.c new file mode 100644 index 0000000000..a97ac17998 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx.c @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file htt_rx.c + * @brief Implement receive aspects of HTT. + * @details + * This file contains three categories of HTT rx code: + * 1. An abstraction of the rx descriptor, to hide the + * differences between the HL vs. LL rx descriptor. + * 2. Functions for providing access to the (series of) + * rx descriptor(s) and rx frame(s) associated with + * an rx indication message. + * 3. Functions for setting up and using the MAC DMA + * rx ring (applies to LL only). + */ + +#include /* qdf_mem_malloc,free, etc. */ +#include /* qdf_print, bool */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_timer_free */ + +#include /* HTT_HL_RX_DESC_SIZE */ +#include +#include +#include +#include /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ +#include "regtable.h" + +#include /* ieee80211_frame, ieee80211_qoscntl */ +#include +#include +#include "ol_txrx_types.h" +#ifdef DEBUG_DMA_DONE +#include +#include +#endif +#include + +/** + * htt_rx_mpdu_wifi_hdr_retrieve() - retrieve 802.11 header + * @pdev - pdev handle + * @mpdu_desc - mpdu descriptor + * + * Return : pointer to 802.11 header + */ +char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + if (!rx_desc) + return NULL; + else + return rx_desc->rx_hdr_status; +} + +/** + * htt_rx_mpdu_desc_tsf32() - Return the TSF timestamp indicating when + * a MPDU was received. + * @pdev - the HTT instance the rx data was received on + * @mpdu_desc - the abstract descriptor for the MPDU in question + * + * return : 32 LSBs of TSF time at which the MPDU's PPDU was received + */ +uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc) +{ + return 0; +} + +static inline +uint8_t htt_rx_msdu_fw_desc_get(htt_pdev_handle pdev, void *msdu_desc) +{ + /* + * HL and LL use the same format for FW rx desc, but have the FW rx desc + * in different locations. + * In LL, the FW rx descriptor has been copied into the same + * htt_host_rx_desc_base struct that holds the HW rx desc. + * In HL, the FW rx descriptor, along with the MSDU payload, + * is in the same buffer as the rx indication message. + * + * Use the FW rx desc offset configured during startup to account for + * this difference between HL vs. LL. + * + * An optimization would be to define the LL and HL msdu_desc pointer + * in such a way that they both use the same offset to the FW rx desc. + * Then the following functions could be converted to macros, without + * needing to expose the htt_pdev_t definition outside HTT. + */ + return *(((uint8_t *)msdu_desc) + pdev->rx_fw_desc_offset); +} + +int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_DISCARD_M; +} + +int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_FORWARD_M; +} + +int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc) +{ + return htt_rx_msdu_fw_desc_get(pdev, msdu_desc) & FW_RX_DESC_INSPECT_M; +} + +void +htt_rx_msdu_actions(htt_pdev_handle pdev, + void *msdu_desc, int *discard, int *forward, int *inspect) +{ + uint8_t rx_msdu_fw_desc = htt_rx_msdu_fw_desc_get(pdev, msdu_desc); +#ifdef HTT_DEBUG_DATA + HTT_PRINT("act:0x%x ", rx_msdu_fw_desc); +#endif + *discard = rx_msdu_fw_desc & FW_RX_DESC_DISCARD_M; + *forward = rx_msdu_fw_desc & FW_RX_DESC_FORWARD_M; + *inspect = rx_msdu_fw_desc & FW_RX_DESC_INSPECT_M; +} + +uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *)qdf_nbuf_data(rx_ind_msg); + return HTT_RX_IN_ORD_PADDR_IND_PKTLOG_GET(*msg_word); +} + +int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc) +{ + /* + * Currently the RSSI is provided only as a field in the + * HTT_T2H_RX_IND message, rather than in each rx descriptor. + */ + return HTT_RSSI_INVALID; +} + +/* + * htt_rx_amsdu_pop - + * global function pointer that is programmed during attach to point + * to either htt_rx_amsdu_pop_ll or htt_rx_amsdu_rx_in_order_pop_ll. + */ +int (*htt_rx_amsdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +/* + * htt_rx_frag_pop - + * global function pointer that is programmed during attach to point + * to either htt_rx_amsdu_pop_ll + */ +int (*htt_rx_frag_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +int (*htt_rx_offload_msdu_cnt)(htt_pdev_handle pdev); + +int +(*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); + +void * (*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg); + +bool (*htt_rx_mpdu_desc_retry)(htt_pdev_handle pdev, void *mpdu_desc); + +uint16_t (*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc, + bool update_seq_num); + +void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, int pn_len_bits); + +uint8_t (*htt_rx_mpdu_desc_tid)(htt_pdev_handle pdev, void *mpdu_desc); + +bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, void *msdu_desc); + +bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, void *msdu_desc); + +int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, void *msdu_desc); + +bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); + +int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); + +void * (*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, qdf_nbuf_t msdu); + +bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); + +bool (*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, + void *mpdu_desc, uint8_t *key_id); + +bool (*htt_rx_msdu_chan_info_present)( + htt_pdev_handle pdev, + void *mpdu_desc); + +bool (*htt_rx_msdu_center_freq)( + htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode); + +void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) +{ + qdf_nbuf_free(msdu); +} + +void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu) +{ + /* + * The rx descriptor is in the same buffer as the rx MSDU payload, + * and does not need to be freed separately. + */ +} + +void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev) +{ + if (qdf_atomic_dec_and_test(&pdev->rx_ring.refill_ref_cnt)) + htt_rx_fill_ring_count(pdev); + + qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); +} + +#ifdef IPA_OFFLOAD +#ifdef QCA_WIFI_3_0 +/** + * htt_rx_ipa_uc_alloc_wdi2_rsc() - Allocate WDI2.0 resources + * @pdev: htt context + * @rx_ind_ring_elements: rx ring elements + * + * Return: 0 success + */ +static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + /* + * Allocate RX2 indication ring + * RX2 IND ring element + * 4bytes: pointer + * 2bytes: VDEV ID + * 2bytes: length + * + * RX indication ring size, by bytes + */ + pdev->ipa_uc_rx_rsc.rx2_ind_ring = + qdf_mem_shared_mem_alloc(pdev->osdev, + rx_ind_ring_elements * + sizeof(target_paddr_t)); + if (!pdev->ipa_uc_rx_rsc.rx2_ind_ring) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate memory for IPA rx2 ind ring", + __func__); + return 1; + } + + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx = + qdf_mem_shared_mem_alloc(pdev->osdev, 4); + if (!pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate memory for IPA rx proc done index", + __func__); + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_rx_rsc.rx2_ind_ring); + return 1; + } + + return 0; +} + +/** + * htt_rx_ipa_uc_free_wdi2_rsc() - Free WDI2.0 resources + * @pdev: htt context + * + * Return: None + */ +static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev) +{ + qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx2_ind_ring); + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_rx_rsc.rx2_ipa_prc_done_idx); +} +#else +static int htt_rx_ipa_uc_alloc_wdi2_rsc(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + return 0; +} + +static void htt_rx_ipa_uc_free_wdi2_rsc(struct htt_pdev_t *pdev) +{ +} +#endif + +/** + * htt_rx_ipa_uc_attach() - attach htt ipa uc rx resource + * @pdev: htt context + * @rx_ind_ring_size: rx ring size + * + * Return: 0 success + */ +int htt_rx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int rx_ind_ring_elements) +{ + int ret = 0; + + /* + * Allocate RX indication ring + * RX IND ring element + * 4bytes: pointer + * 2bytes: VDEV ID + * 2bytes: length + */ + pdev->ipa_uc_rx_rsc.rx_ind_ring = + qdf_mem_shared_mem_alloc(pdev->osdev, + rx_ind_ring_elements * + sizeof(struct ipa_uc_rx_ring_elem_t)); + if (!pdev->ipa_uc_rx_rsc.rx_ind_ring) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate memory for IPA rx ind ring", + __func__); + return 1; + } + + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx = + qdf_mem_shared_mem_alloc(pdev->osdev, 4); + if (!pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: Unable to allocate memory for IPA rx proc done index", + __func__); + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_rx_rsc.rx_ind_ring); + return 1; + } + + ret = htt_rx_ipa_uc_alloc_wdi2_rsc(pdev, rx_ind_ring_elements); + if (ret) { + qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx_ind_ring); + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx); + } + return ret; +} + +int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + qdf_mem_shared_mem_free(pdev->osdev, pdev->ipa_uc_rx_rsc.rx_ind_ring); + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_rx_rsc.rx_ipa_prc_done_idx); + + htt_rx_ipa_uc_free_wdi2_rsc(pdev); + return 0; +} +#endif /* IPA_OFFLOAD */ + +#ifdef CONNECTIVITY_PKTLOG +/** + * htt_register_rx_pkt_dump_callback() - registers callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * @callback: callback to get rx pkt status and + * call callback to do rx packet dump + * + * This function is used to register the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb callback) +{ + if (!pdev) { + qdf_print("pdev is NULL"); + return; + } + pdev->rx_pkt_dump_cb = callback; +} + +/** + * htt_deregister_rx_pkt_dump_callback() - deregisters callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * + * This function is used to deregister the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("pdev is NULL"); + return; + } + pdev->rx_pkt_dump_cb = NULL; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +void htt_rx_enable_ppdu_end(int *enable_ppdu_end) +{ + *enable_ppdu_end = 1; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx_hl.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx_hl.c new file mode 100644 index 0000000000..8272037bec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx_hl.c @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_mem_malloc,free, etc. */ +#include /* qdf_print, bool */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_timer_free */ + +#include /* HTT_HL_RX_DESC_SIZE */ +#include +#include +#include +#include /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ +#include "regtable.h" + +#include /* ieee80211_frame, ieee80211_qoscntl */ +#include +#include +#include "ol_txrx_types.h" + +/* + * This function is used both below within this file (which the compiler + * will hopefully inline), and out-line from other files via the + * htt_rx_msdu_first_msdu_flag function pointer. + */ +static inline bool +htt_rx_msdu_first_msdu_flag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return ((u_int8_t *)msdu_desc - sizeof(struct hl_htt_rx_ind_base)) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_FLAG_OFFSET)] & + HTT_RX_IND_HL_FLAG_FIRST_MSDU ? true : false; +} + +u_int16_t +htt_rx_msdu_rx_desc_size_hl( + htt_pdev_handle pdev, + void *msdu_desc + ) +{ + return ((u_int8_t *)(msdu_desc) - HTT_RX_IND_HL_BYTES) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; +} + +#ifdef CHECKSUM_OFFLOAD +static void +htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ + u_int8_t flag = ((u_int8_t *)rx_desc - + sizeof(struct hl_htt_rx_ind_base))[ + HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_FLAG_OFFSET)]; + + int is_ipv6 = flag & HTT_RX_IND_HL_FLAG_IPV6 ? 1 : 0; + int is_tcp = flag & HTT_RX_IND_HL_FLAG_TCP ? 1 : 0; + int is_udp = flag & HTT_RX_IND_HL_FLAG_UDP ? 1 : 0; + + qdf_nbuf_rx_cksum_t cksum = { + QDF_NBUF_RX_CKSUM_NONE, + QDF_NBUF_RX_CKSUM_NONE, + 0 + }; + + switch ((is_udp << 2) | (is_tcp << 1) | (is_ipv6 << 0)) { + case 0x4: + cksum.l4_type = QDF_NBUF_RX_CKSUM_UDP; + break; + case 0x2: + cksum.l4_type = QDF_NBUF_RX_CKSUM_TCP; + break; + case 0x5: + cksum.l4_type = QDF_NBUF_RX_CKSUM_UDPIPV6; + break; + case 0x3: + cksum.l4_type = QDF_NBUF_RX_CKSUM_TCPIPV6; + break; + default: + cksum.l4_type = QDF_NBUF_RX_CKSUM_NONE; + break; + } + if (cksum.l4_type != (qdf_nbuf_l4_rx_cksum_type_t) + QDF_NBUF_RX_CKSUM_NONE) { + cksum.l4_result = flag & HTT_RX_IND_HL_FLAG_C4_FAILED ? + QDF_NBUF_RX_CKSUM_NONE : + QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + } + qdf_nbuf_set_rx_cksum(msdu, &cksum); +} +#else +static inline +void htt_set_checksum_result_hl(qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ +} +#endif + +/** + * htt_rx_fill_ring_count() - replenish rx msdu buffer + * @pdev: Handle (pointer) to HTT pdev. + * + * This function will replenish the rx buffer to the max number + * that can be kept in the ring + * + * Return: None + */ +void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ +} + +/** + * htt_rx_mpdu_desc_list_next_hl() - provides an abstract way to obtain + * the next MPDU descriptor + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * for HL, the returned value is not mpdu_desc, + * it's translated hl_rx_desc just after the hl_ind_msg + * for HL AMSDU, we can't point to payload now, because + * hl rx desc is not fixed, we can't retrieve the desc + * by minus rx_desc_size when release. keep point to hl rx desc + * now + * + * Return: next abstract rx descriptor from the series of MPDUs + * referenced by an rx ind msg + */ +static inline void * +htt_rx_mpdu_desc_list_next_hl(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + void *mpdu_desc = (void *)qdf_nbuf_data(rx_ind_msg); + return mpdu_desc; +} + +/** + * htt_rx_msdu_desc_retrieve_hl() - Retrieve a previously-stored rx descriptor + * from a MSDU buffer + * @pdev: the HTT instance the rx data was received on + * @msdu - the buffer containing the MSDU payload + * + * currently for HL AMSDU, we don't point to payload. + * we shift to payload in ol_rx_deliver later + * + * Return: the corresponding abstract rx MSDU descriptor + */ +static inline void * +htt_rx_msdu_desc_retrieve_hl(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + return qdf_nbuf_data(msdu); +} + +static +bool htt_rx_mpdu_is_encrypted_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + + return HTT_WORD_GET(*(u_int32_t *)rx_desc, + HTT_HL_RX_DESC_MPDU_ENC); + } else { + /* not first msdu, no encrypt info for hl */ + qdf_print( + "Error: get encrypted from a not-first msdu.\n"); + qdf_assert(0); + return false; + } +} + +static inline bool +htt_rx_msdu_chan_info_present_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true && + HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_CHAN_INFO_PRESENT)) + return true; + + return false; +} + +static bool +htt_rx_msdu_center_freq_hl(htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode) +{ + int pn_len, index; + uint32_t *chan_info; + + index = htt_rx_msdu_is_wlan_mcast(pdev, mpdu_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + pn_len = (peer ? + pdev->txrx_pdev->rx_pn[peer->security[index].sec_type]. + len : 0); + chan_info = (uint32_t *)((uint8_t *)mpdu_desc + + HTT_HL_RX_DESC_PN_OFFSET + pn_len); + + if (htt_rx_msdu_chan_info_present_hl(pdev, mpdu_desc)) { + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_PRIMARY_CHAN_CENTER_FREQ); + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_CONTIG_CHAN1_CENTER_FREQ); + chan_info++; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = + HTT_WORD_GET( + *chan_info, + HTT_CHAN_INFO_CONTIG_CHAN2_CENTER_FREQ); + if (phy_mode) + *phy_mode = + HTT_WORD_GET(*chan_info, + HTT_CHAN_INFO_PHY_MODE); + return true; + } + + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = 0; + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = 0; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = 0; + if (phy_mode) + *phy_mode = 0; + return false; +} + +static bool +htt_rx_msdu_desc_key_id_hl(htt_pdev_handle htt_pdev, + void *mpdu_desc, u_int8_t *key_id) +{ + if (htt_rx_msdu_first_msdu_flag_hl(htt_pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + + *key_id = rx_desc->key_id_oct; + return true; + } + + return false; +} + +/** + * htt_rx_mpdu_desc_retry_hl() - Returns the retry bit from the Rx descriptor + * for the High Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for MPDU + * before the beginning of the payload. + * + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. For the high latency driver, this function + * pretends as if the retry bit is never set so that the mcast duplicate + * detection never fails. + * + * Return: boolean -- false always for HL + */ +static inline bool +htt_rx_mpdu_desc_retry_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + return false; +} + +static int +htt_rx_amsdu_pop_hl( + htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + pdev->rx_desc_size_hl = + (qdf_nbuf_data(rx_ind_msg)) + [HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; + + /* point to the rx desc */ + qdf_nbuf_pull_head(rx_ind_msg, + sizeof(struct hl_htt_rx_ind_base)); + *head_msdu = *tail_msdu = rx_ind_msg; + + htt_set_checksum_result_hl(rx_ind_msg, + (struct htt_host_rx_desc_base *) + (qdf_nbuf_data(rx_ind_msg))); + + qdf_nbuf_set_next(*tail_msdu, NULL); + return 0; +} + +static int +htt_rx_frag_pop_hl( + htt_pdev_handle pdev, + qdf_nbuf_t frag_msg, + qdf_nbuf_t *head_msdu, + qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + qdf_nbuf_pull_head(frag_msg, HTT_RX_FRAG_IND_BYTES); + pdev->rx_desc_size_hl = + (qdf_nbuf_data(frag_msg)) + [HTT_ENDIAN_BYTE_IDX_SWAP( + HTT_RX_IND_HL_RX_DESC_LEN_OFFSET)]; + + /* point to the rx desc */ + qdf_nbuf_pull_head(frag_msg, + sizeof(struct hl_htt_rx_ind_base)); + *head_msdu = *tail_msdu = frag_msg; + + qdf_nbuf_set_next(*tail_msdu, NULL); + return 1; +} + +static inline int +htt_rx_offload_msdu_cnt_hl(htt_pdev_handle pdev) +{ + return 1; +} + +static inline int +htt_rx_offload_msdu_pop_hl(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + u_int8_t *fw_desc, + qdf_nbuf_t *head_buf, + qdf_nbuf_t *tail_buf) +{ + qdf_nbuf_t buf; + u_int32_t *msdu_hdr, msdu_len; + int ret = 0; + + *head_buf = *tail_buf = buf = offload_deliver_msg; + msdu_hdr = (u_int32_t *)qdf_nbuf_data(buf); + /* First dword */ + + /* Second dword */ + msdu_hdr++; + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Third dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + qdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES + + HTT_RX_OFFLOAD_DELIVER_IND_HDR_BYTES); + + if (msdu_len <= qdf_nbuf_len(buf)) { + qdf_nbuf_set_pktlen(buf, msdu_len); + } else { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "%s: drop frame with invalid msdu len %d %d", + __func__, msdu_len, (int)qdf_nbuf_len(buf)); + qdf_nbuf_free(offload_deliver_msg); + ret = -1; + } + + return ret; +} + +static uint16_t +htt_rx_mpdu_desc_seq_num_hl(htt_pdev_handle pdev, void *mpdu_desc, + bool update_seq_num) +{ + if (pdev->rx_desc_size_hl) { + if (update_seq_num) + return pdev->cur_seq_num_hl = + (u_int16_t)(HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_MPDU_SEQ_NUM)); + else + return (u_int16_t)(HTT_WORD_GET(*(u_int32_t *)mpdu_desc, + HTT_HL_RX_DESC_MPDU_SEQ_NUM)); + } else { + return (u_int16_t)(pdev->cur_seq_num_hl); + } +} + +static void +htt_rx_mpdu_desc_pn_hl( + htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, + int pn_len_bits) +{ + if (htt_rx_msdu_first_msdu_flag_hl(pdev, mpdu_desc) == true) { + /* Fix Me: only for little endian */ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)mpdu_desc; + u_int32_t *word_ptr = (u_int32_t *)pn->pn128; + + /* TODO: for Host of big endian */ + switch (pn_len_bits) { + case 128: + /* bits 128:64 */ + *(word_ptr + 3) = rx_desc->pn_127_96; + /* bits 63:0 */ + *(word_ptr + 2) = rx_desc->pn_95_64; + case 48: + /* bits 48:0 + * copy 64 bits + */ + *(word_ptr + 1) = rx_desc->u0.pn_63_32; + case 24: + /* bits 23:0 + * copy 32 bits + */ + *(word_ptr + 0) = rx_desc->pn_31_0; + break; + default: + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Error: invalid length spec (%d bits) for PN", + pn_len_bits); + qdf_assert(0); + break; + }; + } else { + /* not first msdu, no pn info */ + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Error: get pn from a not-first msdu."); + qdf_assert(0); + } +} + +/** + * htt_rx_mpdu_desc_tid_hl() - Returns the TID value from the Rx descriptor + * for High Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for the MPDU + * before the beginning of the payload. + * + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * For the HL driver, this is currently uimplemented and always returns + * an invalid tid. It is the responsibility of the caller to make + * sure that return value is checked for valid range. + * + * Return: Invalid TID value (0xff) for HL driver. + */ +static inline uint8_t +htt_rx_mpdu_desc_tid_hl(htt_pdev_handle pdev, void *mpdu_desc) +{ + return 0xff; /* Invalid TID */ +} + +static inline bool +htt_rx_msdu_desc_completes_mpdu_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return ( + ((u_int8_t *)(msdu_desc) - sizeof(struct hl_htt_rx_ind_base)) + [HTT_ENDIAN_BYTE_IDX_SWAP(HTT_RX_IND_HL_FLAG_OFFSET)] + & HTT_RX_IND_HL_FLAG_LAST_MSDU) + ? true : false; +} + +static inline int +htt_rx_msdu_has_wlan_mcast_flag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + /* currently, only first msdu has hl rx_desc */ + return htt_rx_msdu_first_msdu_flag_hl(pdev, msdu_desc) == true; +} + +static inline bool +htt_rx_msdu_is_wlan_mcast_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)msdu_desc; + + return + HTT_WORD_GET(*(u_int32_t *)rx_desc, HTT_HL_RX_DESC_MCAST_BCAST); +} + +static inline int +htt_rx_msdu_is_frag_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + struct hl_htt_rx_desc_base *rx_desc = + (struct hl_htt_rx_desc_base *)msdu_desc; + + return + HTT_WORD_GET(*(u_int32_t *)rx_desc, HTT_HL_RX_DESC_MCAST_BCAST); +} + +int htt_rx_attach(struct htt_pdev_t *pdev) +{ + pdev->rx_ring.size = HTT_RX_RING_SIZE_MIN; + HTT_ASSERT2(IS_PWR2(pdev->rx_ring.size)); + pdev->rx_ring.size_mask = pdev->rx_ring.size - 1; + /* host can force ring base address if it wish to do so */ + pdev->rx_ring.base_paddr = 0; + htt_rx_amsdu_pop = htt_rx_amsdu_pop_hl; + htt_rx_frag_pop = htt_rx_frag_pop_hl; + htt_rx_offload_msdu_cnt = htt_rx_offload_msdu_cnt_hl; + htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_hl; + htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_hl; + htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_hl; + htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_hl; + htt_rx_mpdu_desc_pn = htt_rx_mpdu_desc_pn_hl; + htt_rx_mpdu_desc_tid = htt_rx_mpdu_desc_tid_hl; + htt_rx_msdu_desc_completes_mpdu = htt_rx_msdu_desc_completes_mpdu_hl; + htt_rx_msdu_first_msdu_flag = htt_rx_msdu_first_msdu_flag_hl; + htt_rx_msdu_has_wlan_mcast_flag = htt_rx_msdu_has_wlan_mcast_flag_hl; + htt_rx_msdu_is_wlan_mcast = htt_rx_msdu_is_wlan_mcast_hl; + htt_rx_msdu_is_frag = htt_rx_msdu_is_frag_hl; + htt_rx_msdu_desc_retrieve = htt_rx_msdu_desc_retrieve_hl; + htt_rx_mpdu_is_encrypted = htt_rx_mpdu_is_encrypted_hl; + htt_rx_msdu_desc_key_id = htt_rx_msdu_desc_key_id_hl; + htt_rx_msdu_chan_info_present = htt_rx_msdu_chan_info_present_hl; + htt_rx_msdu_center_freq = htt_rx_msdu_center_freq_hl; + + /* + * HL case, the rx descriptor can be different sizes for + * different sub-types of RX_IND messages, e.g. for the + * initial vs. interior vs. final MSDUs within a PPDU. + * The size of each RX_IND message's rx desc is read from + * a field within the RX_IND message itself. + * In the meantime, until the rx_desc_size_hl variable is + * set to its real value based on the RX_IND message, + * initialize it to a reasonable value (zero). + */ + pdev->rx_desc_size_hl = 0; + return 0; /* success */ +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx_ll.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx_ll.c new file mode 100644 index 0000000000..1a83a56451 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_rx_ll.c @@ -0,0 +1,2433 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_mem_malloc,free, etc. */ +#include /* qdf_print, bool */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_timer_free */ + +#include /* HTT_HL_RX_DESC_SIZE */ +#include +#include +#include +#include /* HTT_ASSERT, htt_pdev_t, HTT_RX_BUF_SIZE */ +#include "regtable.h" + +#include /* ieee80211_frame, ieee80211_qoscntl */ +#include +#include +#include "ol_txrx_types.h" +#ifdef DEBUG_DMA_DONE +#include +#include +#endif +#include +#include + +#ifdef DEBUG_DMA_DONE +#define MAX_DONE_BIT_CHECK_ITER 5 +#endif + +#ifdef HTT_DEBUG_DATA +#define HTT_PKT_DUMP(x) x +#else +#define HTT_PKT_DUMP(x) /* no-op */ +#endif + +/*--- setup / tear-down functions -------------------------------------------*/ + +#ifndef HTT_RX_HOST_LATENCY_MAX_MS +#define HTT_RX_HOST_LATENCY_MAX_MS 20 /* ms */ /* very conservative */ +#endif + + /* very conservative to ensure enough buffers are allocated */ +#ifndef HTT_RX_HOST_LATENCY_WORST_LIKELY_MS +#ifdef QCA_WIFI_3_0 +#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 20 +#else +#define HTT_RX_HOST_LATENCY_WORST_LIKELY_MS 10 +#endif +#endif + +#ifndef HTT_RX_RING_REFILL_RETRY_TIME_MS +#define HTT_RX_RING_REFILL_RETRY_TIME_MS 50 +#endif + +#define RX_PADDR_MAGIC_PATTERN 0xDEAD0000 + +#ifdef ENABLE_DEBUG_ADDRESS_MARKING +static qdf_dma_addr_t +htt_rx_paddr_mark_high_bits(qdf_dma_addr_t paddr) +{ + if (sizeof(qdf_dma_addr_t) > 4) { + /* clear high bits, leave lower 37 bits (paddr) */ + paddr &= 0x01FFFFFFFFF; + /* mark upper 16 bits of paddr */ + paddr |= (((uint64_t)RX_PADDR_MAGIC_PATTERN) << 32); + } + return paddr; +} +#else +static qdf_dma_addr_t +htt_rx_paddr_mark_high_bits(qdf_dma_addr_t paddr) +{ + return paddr; +} +#endif + +/** + * htt_get_first_packet_after_wow_wakeup() - get first packet after wow wakeup + * @msg_word: pointer to rx indication message word + * @buf: pointer to buffer + * + * Return: None + */ +static void +htt_get_first_packet_after_wow_wakeup(uint32_t *msg_word, qdf_nbuf_t buf) +{ + if (HTT_RX_IN_ORD_PADDR_IND_MSDU_INFO_GET(*msg_word) & + FW_MSDU_INFO_FIRST_WAKEUP_M) { + qdf_nbuf_mark_wakeup_frame(buf); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s: First packet after WOW Wakeup rcvd", __func__); + } +} + +/** + * htt_rx_ring_smmu_mapped() - check if rx ring is smmu mapped or not + * @pdev: HTT pdev handle + * + * Return: true or false. + */ +static inline bool htt_rx_ring_smmu_mapped(htt_pdev_handle pdev) +{ + if (qdf_mem_smmu_s1_enabled(pdev->osdev) && + pdev->is_ipa_uc_enabled && + pdev->rx_ring.smmu_map) + return true; + else + return false; +} + +static inline qdf_nbuf_t htt_rx_netbuf_pop(htt_pdev_handle pdev) +{ + int idx; + qdf_nbuf_t msdu; + + HTT_ASSERT1(htt_rx_ring_elems(pdev) != 0); + +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_ring_idx++; + pdev->rx_ring.dbg_ring_idx &= pdev->rx_ring.size_mask; +#endif + + idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + msdu = pdev->rx_ring.buf.netbufs_ring[idx]; + idx++; + idx &= pdev->rx_ring.size_mask; + pdev->rx_ring.sw_rd_idx.msdu_payld = idx; + qdf_atomic_dec(&pdev->rx_ring.fill_cnt); + return msdu; +} + +static inline unsigned int htt_rx_ring_elems(struct htt_pdev_t *pdev) +{ + return + (*pdev->rx_ring.alloc_idx.vaddr - + pdev->rx_ring.sw_rd_idx.msdu_payld) & pdev->rx_ring.size_mask; +} + +/** + * htt_rx_buff_pool_init() - initialize the pool of buffers + * @pdev: pointer to device + * + * Return: 0 - success, 1 - failure + */ +static int htt_rx_buff_pool_init(struct htt_pdev_t *pdev) +{ + qdf_nbuf_t net_buf; + int i; + + pdev->rx_buff_pool.netbufs_ring = + qdf_mem_malloc(HTT_RX_PRE_ALLOC_POOL_SIZE * sizeof(qdf_nbuf_t)); + + if (!pdev->rx_buff_pool.netbufs_ring) + return 1; /* failure */ + + qdf_atomic_init(&pdev->rx_buff_pool.fill_cnt); + qdf_atomic_init(&pdev->rx_buff_pool.refill_low_mem); + + for (i = 0; i < HTT_RX_PRE_ALLOC_POOL_SIZE; i++) { + net_buf = qdf_nbuf_alloc(pdev->osdev, + HTT_RX_BUF_SIZE, + 0, 4, false); + if (net_buf) { + qdf_atomic_inc(&pdev->rx_buff_pool.fill_cnt); + /* + * Mark this netbuf to differentiate it + * from other buf. If set 1, this buf + * is from pre allocated pool. + */ + QDF_NBUF_CB_RX_PACKET_BUFF_POOL(net_buf) = 1; + } + /* Allow NULL to be inserted. + * Taken care during alloc from this pool. + */ + pdev->rx_buff_pool.netbufs_ring[i] = net_buf; + } + QDF_TRACE(QDF_MODULE_ID_HTT, + QDF_TRACE_LEVEL_INFO, + "max pool size %d pool filled %d", + HTT_RX_PRE_ALLOC_POOL_SIZE, + qdf_atomic_read(&pdev->rx_buff_pool.fill_cnt)); + + qdf_spinlock_create(&pdev->rx_buff_pool.rx_buff_pool_lock); + return 0; +} + +/** + * htt_rx_buff_pool_deinit() - deinitialize the pool of buffers + * @pdev: pointer to device + * + * Return: none + */ +static void htt_rx_buff_pool_deinit(struct htt_pdev_t *pdev) +{ + qdf_nbuf_t net_buf; + int i; + + if (!pdev->rx_buff_pool.netbufs_ring) + return; + + qdf_spin_lock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + for (i = 0; i < HTT_RX_PRE_ALLOC_POOL_SIZE; i++) { + net_buf = pdev->rx_buff_pool.netbufs_ring[i]; + if (!net_buf) + continue; + qdf_nbuf_free(net_buf); + qdf_atomic_dec(&pdev->rx_buff_pool.fill_cnt); + } + qdf_spin_unlock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + QDF_TRACE(QDF_MODULE_ID_HTT, + QDF_TRACE_LEVEL_INFO, + "max pool size %d pool filled %d", + HTT_RX_PRE_ALLOC_POOL_SIZE, + qdf_atomic_read(&pdev->rx_buff_pool.fill_cnt)); + + qdf_mem_free(pdev->rx_buff_pool.netbufs_ring); + qdf_spinlock_destroy(&pdev->rx_buff_pool.rx_buff_pool_lock); +} + +/** + * htt_rx_buff_pool_refill() - refill the pool with new buf or reuse same buf + * @pdev: pointer to device + * @netbuf: netbuf to reuse + * + * Return: true - if able to alloc new buf and insert into pool, + * false - if need to reuse the netbuf or not able to insert into pool + */ +static bool htt_rx_buff_pool_refill(struct htt_pdev_t *pdev, qdf_nbuf_t netbuf) +{ + bool ret = false; + qdf_nbuf_t net_buf; + int i; + + net_buf = qdf_nbuf_alloc(pdev->osdev, + HTT_RX_BUF_SIZE, + 0, 4, false); + if (net_buf) { + /* able to alloc new net_buf. + * mark this netbuf as pool buf. + */ + QDF_NBUF_CB_RX_PACKET_BUFF_POOL(net_buf) = 1; + ret = true; + } else { + /* reuse the netbuf and + * reset all fields of this netbuf. + */ + net_buf = netbuf; + qdf_nbuf_reset(net_buf, 0, 4); + + /* mark this netbuf as pool buf */ + QDF_NBUF_CB_RX_PACKET_BUFF_POOL(net_buf) = 1; + } + + qdf_spin_lock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + for (i = 0; i < HTT_RX_PRE_ALLOC_POOL_SIZE; i++) { + /* insert the netbuf in empty slot of pool */ + if (pdev->rx_buff_pool.netbufs_ring[i]) + continue; + + pdev->rx_buff_pool.netbufs_ring[i] = net_buf; + qdf_atomic_inc(&pdev->rx_buff_pool.fill_cnt); + break; + } + qdf_spin_unlock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + + if (i == HTT_RX_PRE_ALLOC_POOL_SIZE) { + /* fail to insert into pool, free net_buf */ + qdf_nbuf_free(net_buf); + ret = false; + } + + return ret; +} + +/** + * htt_rx_buff_alloc() - alloc the net buf from the pool + * @pdev: pointer to device + * + * Return: nbuf or NULL + */ +static qdf_nbuf_t htt_rx_buff_alloc(struct htt_pdev_t *pdev) +{ + qdf_nbuf_t net_buf = NULL; + int i; + + if (!pdev->rx_buff_pool.netbufs_ring) + return net_buf; + + qdf_spin_lock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + for (i = 0; i < HTT_RX_PRE_ALLOC_POOL_SIZE; i++) { + /* allocate the valid netbuf */ + if (!pdev->rx_buff_pool.netbufs_ring[i]) + continue; + + net_buf = pdev->rx_buff_pool.netbufs_ring[i]; + qdf_atomic_dec(&pdev->rx_buff_pool.fill_cnt); + pdev->rx_buff_pool.netbufs_ring[i] = NULL; + break; + } + qdf_spin_unlock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + return net_buf; +} + +/** + * htt_rx_ring_buf_attach() - return net buf to attach in ring + * @pdev: pointer to device + * + * Return: nbuf or NULL + */ +static qdf_nbuf_t htt_rx_ring_buf_attach(struct htt_pdev_t *pdev) +{ + qdf_nbuf_t net_buf = NULL; + bool allocated = true; + + net_buf = + qdf_nbuf_alloc(pdev->osdev, HTT_RX_BUF_SIZE, + 0, 4, false); + if (!net_buf) { + if (pdev->rx_buff_pool.netbufs_ring && + qdf_atomic_read(&pdev->rx_buff_pool.refill_low_mem) && + qdf_atomic_read(&pdev->rx_buff_pool.fill_cnt)) + net_buf = htt_rx_buff_alloc(pdev); + + allocated = false; /* allocated from pool */ + } + + if (allocated || !qdf_atomic_read(&pdev->rx_buff_pool.fill_cnt)) + qdf_atomic_set(&pdev->rx_buff_pool.refill_low_mem, 0); + + return net_buf; +} + +/** + * htt_rx_ring_buff_free() - free the net buff or reuse it + * @pdev: pointer to device + * @netbuf: netbuf + * + * Return: none + */ +static void htt_rx_ring_buff_free(struct htt_pdev_t *pdev, qdf_nbuf_t netbuf) +{ + bool status = false; + + if (pdev->rx_buff_pool.netbufs_ring && + QDF_NBUF_CB_RX_PACKET_BUFF_POOL(netbuf)) { + int i; + + /* rest this netbuf before putting back into pool */ + qdf_nbuf_reset(netbuf, 0, 4); + + /* mark this netbuf as pool buf */ + QDF_NBUF_CB_RX_PACKET_BUFF_POOL(netbuf) = 1; + + qdf_spin_lock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + for (i = 0; i < HTT_RX_PRE_ALLOC_POOL_SIZE; i++) { + /* insert the netbuf in empty slot of pool */ + if (!pdev->rx_buff_pool.netbufs_ring[i]) { + pdev->rx_buff_pool.netbufs_ring[i] = netbuf; + qdf_atomic_inc(&pdev->rx_buff_pool.fill_cnt); + status = true; /* valid insertion */ + break; + } + } + qdf_spin_unlock_bh(&pdev->rx_buff_pool.rx_buff_pool_lock); + } + if (!status) + qdf_nbuf_free(netbuf); +} + +/* full_reorder_offload case: this function is called with lock held */ +static int htt_rx_ring_fill_n(struct htt_pdev_t *pdev, int num) +{ + int idx; + QDF_STATUS status; + struct htt_host_rx_desc_base *rx_desc; + int filled = 0; + int debt_served = 0; + qdf_mem_info_t mem_map_table = {0}; + + idx = *pdev->rx_ring.alloc_idx.vaddr; + + if ((idx < 0) || (idx > pdev->rx_ring.size_mask) || + (num > pdev->rx_ring.size)) { + QDF_TRACE(QDF_MODULE_ID_HTT, + QDF_TRACE_LEVEL_ERROR, + "%s:rx refill failed!", __func__); + return filled; + } + +moretofill: + while (num > 0) { + qdf_dma_addr_t paddr, paddr_marked; + qdf_nbuf_t rx_netbuf; + int headroom; + + rx_netbuf = htt_rx_ring_buf_attach(pdev); + if (!rx_netbuf) { + qdf_timer_stop(&pdev->rx_ring. + refill_retry_timer); + /* + * Failed to fill it to the desired level - + * we'll start a timer and try again next time. + * As long as enough buffers are left in the ring for + * another A-MPDU rx, no special recovery is needed. + */ +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_refill_cnt++; +#endif + pdev->refill_retry_timer_starts++; + qdf_timer_start( + &pdev->rx_ring.refill_retry_timer, + HTT_RX_RING_REFILL_RETRY_TIME_MS); + goto update_alloc_idx; + } + + /* Clear rx_desc attention word before posting to Rx ring */ + rx_desc = htt_rx_desc(rx_netbuf); + *(uint32_t *)&rx_desc->attention = 0; + +#ifdef DEBUG_DMA_DONE + *(uint32_t *)&rx_desc->msdu_end = 1; + +#define MAGIC_PATTERN 0xDEADBEEF + *(uint32_t *)&rx_desc->msdu_start = MAGIC_PATTERN; + + /* + * To ensure that attention bit is reset and msdu_end is set + * before calling dma_map + */ + smp_mb(); +#endif + /* + * Adjust qdf_nbuf_data to point to the location in the buffer + * where the rx descriptor will be filled in. + */ + headroom = qdf_nbuf_data(rx_netbuf) - (uint8_t *)rx_desc; + qdf_nbuf_push_head(rx_netbuf, headroom); + +#ifdef DEBUG_DMA_DONE + status = qdf_nbuf_map(pdev->osdev, rx_netbuf, + QDF_DMA_BIDIRECTIONAL); +#else + status = qdf_nbuf_map(pdev->osdev, rx_netbuf, + QDF_DMA_FROM_DEVICE); +#endif + if (status != QDF_STATUS_SUCCESS) { + htt_rx_ring_buff_free(pdev, rx_netbuf); + goto update_alloc_idx; + } + + paddr = qdf_nbuf_get_frag_paddr(rx_netbuf, 0); + paddr_marked = htt_rx_paddr_mark_high_bits(paddr); + if (pdev->cfg.is_full_reorder_offload) { + if (qdf_unlikely(htt_rx_hash_list_insert( + pdev, paddr_marked, rx_netbuf))) { + QDF_TRACE(QDF_MODULE_ID_HTT, + QDF_TRACE_LEVEL_ERROR, + "%s: hash insert failed!", __func__); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, rx_netbuf, + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, rx_netbuf, + QDF_DMA_FROM_DEVICE); +#endif + htt_rx_ring_buff_free(pdev, rx_netbuf); + + goto update_alloc_idx; + } + htt_rx_dbg_rxbuf_set(pdev, paddr_marked, rx_netbuf); + } else { + pdev->rx_ring.buf.netbufs_ring[idx] = rx_netbuf; + } + + /* Caller already protected this function with refill_lock */ + if (qdf_nbuf_is_rx_ipa_smmu_map(rx_netbuf)) { + qdf_update_mem_map_table(pdev->osdev, &mem_map_table, + paddr, HTT_RX_BUF_SIZE); + qdf_assert_always( + !cds_smmu_map_unmap(true, 1, &mem_map_table)); + } + + pdev->rx_ring.buf.paddrs_ring[idx] = paddr_marked; + qdf_atomic_inc(&pdev->rx_ring.fill_cnt); + + num--; + idx++; + filled++; + idx &= pdev->rx_ring.size_mask; + } + + if (debt_served < qdf_atomic_read(&pdev->rx_ring.refill_debt)) { + num = qdf_atomic_read(&pdev->rx_ring.refill_debt) - debt_served; + debt_served += num; + goto moretofill; + } + +update_alloc_idx: + /* + * Make sure alloc index write is reflected correctly before FW polls + * remote ring write index as compiler can reorder the instructions + * based on optimizations. + */ + qdf_mb(); + *pdev->rx_ring.alloc_idx.vaddr = idx; + htt_rx_dbg_rxbuf_indupd(pdev, idx); + + return filled; +} + +static int htt_rx_ring_size(struct htt_pdev_t *pdev) +{ + int size; + QDF_STATUS status; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + bool enable_2x2 = true; + + /* + * It is expected that the host CPU will typically be able to service + * the rx indication from one A-MPDU before the rx indication from + * the subsequent A-MPDU happens, roughly 1-2 ms later. + * However, the rx ring should be sized very conservatively, to + * accommodate the worst reasonable delay before the host CPU services + * a rx indication interrupt. + * The rx ring need not be kept full of empty buffers. In theory, + * the htt host SW can dynamically track the low-water mark in the + * rx ring, and dynamically adjust the level to which the rx ring + * is filled with empty buffers, to dynamically meet the desired + * low-water mark. + * In contrast, it's difficult to resize the rx ring itself, once + * it's in use. + * Thus, the ring itself should be sized very conservatively, while + * the degree to which the ring is filled with empty buffers should + * be sized moderately conservatively. + */ + size = + ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS; + + if (size < HTT_RX_RING_SIZE_MIN) + size = HTT_RX_RING_SIZE_MIN; + else if (size > HTT_RX_RING_SIZE_MAX) + size = HTT_RX_RING_SIZE_MAX; + + size = qdf_get_pwr2(size); + + if (!soc) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Unable to get 2x2 cap soc is NULL ring size:%u selected ", size); + return size; + } + + status = wlan_mlme_get_vht_enable2x2((void *)soc->psoc, &enable_2x2); + if (QDF_IS_STATUS_SUCCESS(status)) + size = (enable_2x2) ? size : QDF_MIN(size, HTT_RX_RING_SIZE_1x1); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "HTT RX refill ring size:%u selected for %s mode", size, enable_2x2 ? "2x2" : "1x1"); + + return size; +} + +static int htt_rx_ring_fill_level(struct htt_pdev_t *pdev) +{ + int size; + + size = ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * HTT_RX_AVG_FRM_BYTES) * + HTT_RX_HOST_LATENCY_WORST_LIKELY_MS; + + size = qdf_get_pwr2(size); + /* + * Make sure the fill level is at least 1 less than the ring size. + * Leaving 1 element empty allows the SW to easily distinguish + * between a full ring vs. an empty ring. + */ + if (size >= pdev->rx_ring.size) + size = pdev->rx_ring.size - 1; + + return size; +} + +static void htt_rx_ring_refill_retry(void *arg) +{ + htt_pdev_handle pdev = (htt_pdev_handle)arg; + int filled = 0; + int num; + + pdev->refill_retry_timer_calls++; + qdf_spin_lock_bh(&pdev->rx_ring.refill_lock); + + num = qdf_atomic_read(&pdev->rx_ring.refill_debt); + qdf_atomic_sub(num, &pdev->rx_ring.refill_debt); + + qdf_atomic_set(&pdev->rx_buff_pool.refill_low_mem, 1); + + filled = htt_rx_ring_fill_n(pdev, num); + + if (filled > num) { + /* we served ourselves and some other debt */ + /* sub is safer than = 0 */ + qdf_atomic_sub(filled - num, &pdev->rx_ring.refill_debt); + } else if (num == filled) { /* nothing to be done */ + } else { + qdf_atomic_add(num - filled, &pdev->rx_ring.refill_debt); + /* we could not fill all, timer must have been started */ + pdev->refill_retry_timer_doubles++; + } + qdf_spin_unlock_bh(&pdev->rx_ring.refill_lock); +} + +/*--- rx descriptor field access functions ----------------------------------*/ +/* + * These functions need to use bit masks and shifts to extract fields + * from the rx descriptors, rather than directly using the bitfields. + * For example, use + * (desc & FIELD_MASK) >> FIELD_LSB + * rather than + * desc.field + * This allows the functions to work correctly on either little-endian + * machines (no endianness conversion needed) or big-endian machines + * (endianness conversion provided automatically by the HW DMA's + * byte-swizzling). + */ + +#ifdef CHECKSUM_OFFLOAD +static inline void +htt_set_checksum_result_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ +#define MAX_IP_VER 2 +#define MAX_PROTO_VAL 4 + struct rx_msdu_start *rx_msdu = &rx_desc->msdu_start; + unsigned int proto = (rx_msdu->tcp_proto) | (rx_msdu->udp_proto << 1); + + /* + * HW supports TCP & UDP checksum offload for ipv4 and ipv6 + */ + static const qdf_nbuf_l4_rx_cksum_type_t + cksum_table[][MAX_PROTO_VAL][MAX_IP_VER] = { + { + /* non-fragmented IP packet */ + /* non TCP/UDP packet */ + {QDF_NBUF_RX_CKSUM_ZERO, QDF_NBUF_RX_CKSUM_ZERO}, + /* TCP packet */ + {QDF_NBUF_RX_CKSUM_TCP, QDF_NBUF_RX_CKSUM_TCPIPV6}, + /* UDP packet */ + {QDF_NBUF_RX_CKSUM_UDP, QDF_NBUF_RX_CKSUM_UDPIPV6}, + /* invalid packet type */ + {QDF_NBUF_RX_CKSUM_ZERO, QDF_NBUF_RX_CKSUM_ZERO}, + }, + { + /* fragmented IP packet */ + {QDF_NBUF_RX_CKSUM_ZERO, QDF_NBUF_RX_CKSUM_ZERO}, + {QDF_NBUF_RX_CKSUM_ZERO, QDF_NBUF_RX_CKSUM_ZERO}, + {QDF_NBUF_RX_CKSUM_ZERO, QDF_NBUF_RX_CKSUM_ZERO}, + {QDF_NBUF_RX_CKSUM_ZERO, QDF_NBUF_RX_CKSUM_ZERO}, + } + }; + + qdf_nbuf_rx_cksum_t cksum = { + cksum_table[rx_msdu->ip_frag][proto][rx_msdu->ipv6_proto], + QDF_NBUF_RX_CKSUM_NONE, + 0 + }; + + if (cksum.l4_type != + (qdf_nbuf_l4_rx_cksum_type_t)QDF_NBUF_RX_CKSUM_NONE) { + cksum.l4_result = + ((*(uint32_t *)&rx_desc->attention) & + RX_ATTENTION_0_TCP_UDP_CHKSUM_FAIL_MASK) ? + QDF_NBUF_RX_CKSUM_NONE : + QDF_NBUF_RX_CKSUM_TCP_UDP_UNNECESSARY; + } + qdf_nbuf_set_rx_cksum(msdu, &cksum); +#undef MAX_IP_VER +#undef MAX_PROTO_VAL +} + +#else + +static inline +void htt_set_checksum_result_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu, + struct htt_host_rx_desc_base *rx_desc) +{ +} + +#endif + +static void *htt_rx_msdu_desc_retrieve_ll(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + return htt_rx_desc(msdu); +} + +static bool htt_rx_mpdu_is_encrypted_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return (((*((uint32_t *)&rx_desc->mpdu_start)) & + RX_MPDU_START_0_ENCRYPTED_MASK) >> + RX_MPDU_START_0_ENCRYPTED_LSB) ? true : false; +} + +static +bool htt_rx_msdu_chan_info_present_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + return false; +} + +static bool htt_rx_msdu_center_freq_ll(htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode) +{ + if (primary_chan_center_freq_mhz) + *primary_chan_center_freq_mhz = 0; + if (contig_chan1_center_freq_mhz) + *contig_chan1_center_freq_mhz = 0; + if (contig_chan2_center_freq_mhz) + *contig_chan2_center_freq_mhz = 0; + if (phy_mode) + *phy_mode = 0; + return false; +} + +static bool +htt_rx_msdu_first_msdu_flag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return (bool) + (((*(((uint32_t *)&rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_FIRST_MSDU_MASK) >> + RX_MSDU_END_4_FIRST_MSDU_LSB); +} + +static bool +htt_rx_msdu_desc_key_id_ll(htt_pdev_handle pdev, void *mpdu_desc, + uint8_t *key_id) +{ + struct htt_host_rx_desc_base *rx_desc = (struct htt_host_rx_desc_base *) + mpdu_desc; + + if (!htt_rx_msdu_first_msdu_flag_ll(pdev, mpdu_desc)) + return false; + + *key_id = ((*(((uint32_t *)&rx_desc->msdu_end) + 1)) & + (RX_MSDU_END_1_KEY_ID_OCT_MASK >> + RX_MSDU_END_1_KEY_ID_OCT_LSB)); + + return true; +} + +/** + * htt_rx_mpdu_desc_retry_ll() - Returns the retry bit from the Rx descriptor + * for the Low Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for MPDU + * before the beginning of the payload. + * + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. + * + * Return: boolean -- true if retry is set, false otherwise + */ +static bool +htt_rx_mpdu_desc_retry_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return + (bool)(((*((uint32_t *)&rx_desc->mpdu_start)) & + RX_MPDU_START_0_RETRY_MASK) >> + RX_MPDU_START_0_RETRY_LSB); +} + +static uint16_t htt_rx_mpdu_desc_seq_num_ll(htt_pdev_handle pdev, + void *mpdu_desc, + bool update_seq_num) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return + (uint16_t)(((*((uint32_t *)&rx_desc->mpdu_start)) & + RX_MPDU_START_0_SEQ_NUM_MASK) >> + RX_MPDU_START_0_SEQ_NUM_LSB); +} + +static void +htt_rx_mpdu_desc_pn_ll(htt_pdev_handle pdev, + void *mpdu_desc, union htt_rx_pn_t *pn, int pn_len_bits) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + switch (pn_len_bits) { + case 24: + /* bits 23:0 */ + pn->pn24 = rx_desc->mpdu_start.pn_31_0 & 0xffffff; + break; + case 48: + /* bits 31:0 */ + pn->pn48 = rx_desc->mpdu_start.pn_31_0; + /* bits 47:32 */ + pn->pn48 |= ((uint64_t) + ((*(((uint32_t *)&rx_desc->mpdu_start) + 2)) + & RX_MPDU_START_2_PN_47_32_MASK)) + << (32 - RX_MPDU_START_2_PN_47_32_LSB); + break; + case 128: + /* bits 31:0 */ + pn->pn128[0] = rx_desc->mpdu_start.pn_31_0; + /* bits 47:32 */ + pn->pn128[0] |= + ((uint64_t)((*(((uint32_t *)&rx_desc->mpdu_start) + 2)) + & RX_MPDU_START_2_PN_47_32_MASK)) + << (32 - RX_MPDU_START_2_PN_47_32_LSB); + /* bits 63:48 */ + pn->pn128[0] |= + ((uint64_t)((*(((uint32_t *)&rx_desc->msdu_end) + 2)) + & RX_MSDU_END_1_EXT_WAPI_PN_63_48_MASK)) + << (48 - RX_MSDU_END_1_EXT_WAPI_PN_63_48_LSB); + /* bits 95:64 */ + pn->pn128[1] = rx_desc->msdu_end.ext_wapi_pn_95_64; + /* bits 127:96 */ + pn->pn128[1] |= + ((uint64_t)rx_desc->msdu_end.ext_wapi_pn_127_96) << 32; + break; + default: + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Error: invalid length spec (%d bits) for PN", + pn_len_bits); + }; +} + +/** + * htt_rx_mpdu_desc_tid_ll() - Returns the TID value from the Rx descriptor + * for Low Latency driver + * @pdev: Handle (pointer) to HTT pdev. + * @mpdu_desc: Void pointer to the Rx descriptor for the MPDU + * before the beginning of the payload. + * + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * + * Return: Actual TID set in the packet header. + */ +static uint8_t +htt_rx_mpdu_desc_tid_ll(htt_pdev_handle pdev, void *mpdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)mpdu_desc; + + return + (uint8_t)(((*(((uint32_t *)&rx_desc->mpdu_start) + 2)) & + RX_MPDU_START_2_TID_MASK) >> + RX_MPDU_START_2_TID_LSB); +} + +static bool htt_rx_msdu_desc_completes_mpdu_ll(htt_pdev_handle pdev, + void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return (bool) + (((*(((uint32_t *)&rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_LAST_MSDU_MASK) >> RX_MSDU_END_4_LAST_MSDU_LSB); +} + +static int htt_rx_msdu_has_wlan_mcast_flag_ll(htt_pdev_handle pdev, + void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + /* + * HW rx desc: the mcast_bcast flag is only valid + * if first_msdu is set + */ + return ((*(((uint32_t *)&rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_FIRST_MSDU_MASK) >> RX_MSDU_END_4_FIRST_MSDU_LSB; +} + +static bool htt_rx_msdu_is_wlan_mcast_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return ((*((uint32_t *)&rx_desc->attention)) & + RX_ATTENTION_0_MCAST_BCAST_MASK) + >> RX_ATTENTION_0_MCAST_BCAST_LSB; +} + +static int htt_rx_msdu_is_frag_ll(htt_pdev_handle pdev, void *msdu_desc) +{ + struct htt_host_rx_desc_base *rx_desc = + (struct htt_host_rx_desc_base *)msdu_desc; + return ((*((uint32_t *)&rx_desc->attention)) & + RX_ATTENTION_0_FRAGMENT_MASK) >> RX_ATTENTION_0_FRAGMENT_LSB; +} + +static inline int +htt_rx_offload_msdu_cnt_ll(htt_pdev_handle pdev) +{ + return htt_rx_ring_elems(pdev); +} + +static int +htt_rx_offload_msdu_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf) +{ + qdf_nbuf_t buf; + uint32_t *msdu_hdr, msdu_len; + + *head_buf = *tail_buf = buf = htt_rx_netbuf_pop(pdev); + + if (qdf_unlikely(!buf)) { + qdf_print("netbuf pop failed!"); + return 1; + } + + /* Fake read mpdu_desc to keep desc ptr in sync */ + htt_rx_mpdu_desc_list_next(pdev, NULL); + qdf_nbuf_set_pktlen(buf, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_FROM_DEVICE); +#endif + msdu_hdr = (uint32_t *)qdf_nbuf_data(buf); + + /* First dword */ + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Second dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + qdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES); + qdf_nbuf_set_pktlen(buf, msdu_len); + return 0; +} + +int +htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev, + uint32_t *msg_word, + int msdu_iter, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf) +{ + qdf_nbuf_t buf; + uint32_t *msdu_hdr, msdu_len; + uint32_t *curr_msdu; + qdf_dma_addr_t paddr; + + curr_msdu = + msg_word + (msdu_iter * HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS); + paddr = htt_rx_in_ord_paddr_get(curr_msdu); + *head_buf = *tail_buf = buf = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (qdf_unlikely(!buf)) { + qdf_print("netbuf pop failed!"); + return 1; + } + qdf_nbuf_set_pktlen(buf, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, buf, QDF_DMA_FROM_DEVICE); +#endif + + if (pdev->cfg.is_first_wakeup_packet) + htt_get_first_packet_after_wow_wakeup( + msg_word + NEXT_FIELD_OFFSET_IN32, buf); + + msdu_hdr = (uint32_t *)qdf_nbuf_data(buf); + + /* First dword */ + msdu_len = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_LEN_GET(*msdu_hdr); + *peer_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_PEER_ID_GET(*msdu_hdr); + + /* Second dword */ + msdu_hdr++; + *vdev_id = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_VDEV_ID_GET(*msdu_hdr); + *tid = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_TID_GET(*msdu_hdr); + *fw_desc = HTT_RX_OFFLOAD_DELIVER_IND_MSDU_DESC_GET(*msdu_hdr); + + qdf_nbuf_pull_head(buf, HTT_RX_OFFLOAD_DELIVER_IND_MSDU_HDR_BYTES); + qdf_nbuf_set_pktlen(buf, msdu_len); + return 0; +} + +#ifdef WLAN_FULL_REORDER_OFFLOAD + +/* Number of buckets in the hash table */ +#define RX_NUM_HASH_BUCKETS 1024 /* This should always be a power of 2 */ +#define RX_NUM_HASH_BUCKETS_MASK (RX_NUM_HASH_BUCKETS - 1) + +/* Number of hash entries allocated per bucket */ +#define RX_ENTRIES_SIZE 10 + +#define RX_HASH_FUNCTION(a) \ + ((((a) >> 14) ^ ((a) >> 4)) & RX_NUM_HASH_BUCKETS_MASK) + +#ifdef RX_HASH_DEBUG_LOG +#define RX_HASH_LOG(x) x +#else +#define RX_HASH_LOG(x) /* no-op */ +#endif + +/* Return values: 1 - success, 0 - failure */ +#define RX_DESC_DISCARD_IS_SET ((*((u_int8_t *)&rx_desc->fw_desc.u.val)) & \ + FW_RX_DESC_DISCARD_M) +#define RX_DESC_MIC_ERR_IS_SET ((*((u_int8_t *)&rx_desc->fw_desc.u.val)) & \ + FW_RX_DESC_ANY_ERR_M) + +#define RX_RING_REFILL_DEBT_MAX 128 + +/* Initializes the circular linked list */ +static inline void htt_list_init(struct htt_list_node *head) +{ + head->prev = head; + head->next = head; +} + +/* Adds entry to the end of the linked list */ +static inline void htt_list_add_tail(struct htt_list_node *head, + struct htt_list_node *node) +{ + head->prev->next = node; + node->prev = head->prev; + node->next = head; + head->prev = node; +} + +/* Removes the entry corresponding to the input node from the linked list */ +static inline void htt_list_remove(struct htt_list_node *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; +} + +/* Helper macro to iterate through the linked list */ +#define HTT_LIST_ITER_FWD(iter, head) for (iter = (head)->next; \ + (iter) != (head); \ + (iter) = (iter)->next) \ + +#ifdef RX_HASH_DEBUG +/* Hash cookie related macros */ +#define HTT_RX_HASH_COOKIE 0xDEED + +#define HTT_RX_HASH_COOKIE_SET(hash_element) \ + ((hash_element)->cookie = HTT_RX_HASH_COOKIE) + +#define HTT_RX_HASH_COOKIE_CHECK(hash_element) \ + HTT_ASSERT_ALWAYS((hash_element)->cookie == HTT_RX_HASH_COOKIE) + +/* Hash count related macros */ +#define HTT_RX_HASH_COUNT_INCR(hash_bucket) \ + ((hash_bucket)->count++) + +#define HTT_RX_HASH_COUNT_DECR(hash_bucket) \ + ((hash_bucket)->count--) + +#define HTT_RX_HASH_COUNT_RESET(hash_bucket) ((hash_bucket)->count = 0) + +#define HTT_RX_HASH_COUNT_PRINT(hash_bucket) \ + RX_HASH_LOG(qdf_print(" count %d\n", (hash_bucket)->count)) +#else /* RX_HASH_DEBUG */ +/* Hash cookie related macros */ +#define HTT_RX_HASH_COOKIE_SET(hash_element) /* no-op */ +#define HTT_RX_HASH_COOKIE_CHECK(hash_element) /* no-op */ +/* Hash count related macros */ +#define HTT_RX_HASH_COUNT_INCR(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_DECR(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_PRINT(hash_bucket) /* no-op */ +#define HTT_RX_HASH_COUNT_RESET(hash_bucket) /* no-op */ +#endif /* RX_HASH_DEBUG */ + +/* + * Inserts the given "physical address - network buffer" pair into the + * hash table for the given pdev. This function will do the following: + * 1. Determine which bucket to insert the pair into + * 2. First try to allocate the hash entry for this pair from the pre-allocated + * entries list + * 3. If there are no more entries in the pre-allocated entries list, allocate + * the hash entry from the hash memory pool + * Note: this function is not thread-safe + * Returns 0 - success, 1 - failure + */ +int +htt_rx_hash_list_insert(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr, + qdf_nbuf_t netbuf) +{ + int i; + int rc = 0; + struct htt_rx_hash_entry *hash_element = NULL; + + qdf_spin_lock_bh(&pdev->rx_ring.rx_hash_lock); + + /* get rid of the marking bits if they are available */ + paddr = htt_paddr_trim_to_37(paddr); + + i = RX_HASH_FUNCTION(paddr); + + /* Check if there are any entries in the pre-allocated free list */ + if (pdev->rx_ring.hash_table[i]->freepool.next != + &pdev->rx_ring.hash_table[i]->freepool) { + hash_element = + (struct htt_rx_hash_entry *)( + (char *) + pdev->rx_ring.hash_table[i]->freepool.next - + pdev->rx_ring.listnode_offset); + if (qdf_unlikely(!hash_element)) { + HTT_ASSERT_ALWAYS(0); + rc = 1; + goto hli_end; + } + + htt_list_remove(pdev->rx_ring.hash_table[i]->freepool.next); + } else { + hash_element = qdf_mem_malloc(sizeof(struct htt_rx_hash_entry)); + if (qdf_unlikely(!hash_element)) { + HTT_ASSERT_ALWAYS(0); + rc = 1; + goto hli_end; + } + hash_element->fromlist = 0; + } + + hash_element->netbuf = netbuf; + hash_element->paddr = paddr; + HTT_RX_HASH_COOKIE_SET(hash_element); + + htt_list_add_tail(&pdev->rx_ring.hash_table[i]->listhead, + &hash_element->listnode); + + RX_HASH_LOG(qdf_print("rx hash: paddr 0x%x netbuf %pK bucket %d\n", + paddr, netbuf, (int)i)); + + if (htt_rx_ring_smmu_mapped(pdev)) { + if (qdf_unlikely(qdf_nbuf_is_rx_ipa_smmu_map(netbuf))) { + qdf_err("Already smmu mapped, nbuf: %pK", + netbuf); + qdf_assert_always(0); + } + qdf_nbuf_set_rx_ipa_smmu_map(netbuf, true); + } + + HTT_RX_HASH_COUNT_INCR(pdev->rx_ring.hash_table[i]); + HTT_RX_HASH_COUNT_PRINT(pdev->rx_ring.hash_table[i]); + +hli_end: + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + return rc; +} + +/* + * Given a physical address this function will find the corresponding network + * buffer from the hash table. + * paddr is already stripped off of higher marking bits. + */ +qdf_nbuf_t htt_rx_hash_list_lookup(struct htt_pdev_t *pdev, + qdf_dma_addr_t paddr) +{ + uint32_t i; + struct htt_list_node *list_iter = NULL; + qdf_nbuf_t netbuf = NULL; + struct htt_rx_hash_entry *hash_entry; + + qdf_spin_lock_bh(&pdev->rx_ring.rx_hash_lock); + + if (!pdev->rx_ring.hash_table) { + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + return NULL; + } + + i = RX_HASH_FUNCTION(paddr); + + HTT_LIST_ITER_FWD(list_iter, &pdev->rx_ring.hash_table[i]->listhead) { + hash_entry = (struct htt_rx_hash_entry *) + ((char *)list_iter - + pdev->rx_ring.listnode_offset); + + HTT_RX_HASH_COOKIE_CHECK(hash_entry); + + if (hash_entry->paddr == paddr) { + /* Found the entry corresponding to paddr */ + netbuf = hash_entry->netbuf; + /* set netbuf to NULL to trace if freed entry + * is getting unmapped in hash deinit. + */ + hash_entry->netbuf = NULL; + htt_list_remove(&hash_entry->listnode); + HTT_RX_HASH_COUNT_DECR(pdev->rx_ring.hash_table[i]); + /* + * if the rx entry is from the pre-allocated list, + * return it + */ + if (hash_entry->fromlist) + htt_list_add_tail( + &pdev->rx_ring.hash_table[i]->freepool, + &hash_entry->listnode); + else + qdf_mem_free(hash_entry); + + htt_rx_dbg_rxbuf_reset(pdev, netbuf); + break; + } + } + + if (netbuf && htt_rx_ring_smmu_mapped(pdev)) { + if (qdf_unlikely(!qdf_nbuf_is_rx_ipa_smmu_map(netbuf))) { + qdf_err("smmu not mapped nbuf: %pK", netbuf); + qdf_assert_always(0); + } + } + + RX_HASH_LOG(qdf_print("rx hash: paddr 0x%llx, netbuf %pK, bucket %d\n", + (unsigned long long)paddr, netbuf, (int)i)); + HTT_RX_HASH_COUNT_PRINT(pdev->rx_ring.hash_table[i]); + + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + + if (!netbuf) { + qdf_print("rx hash: no entry found for %llx!\n", + (unsigned long long)paddr); + cds_trigger_recovery(QDF_RX_HASH_NO_ENTRY_FOUND); + } + + return netbuf; +} + +/* + * Initialization function of the rx buffer hash table. This function will + * allocate a hash table of a certain pre-determined size and initialize all + * the elements + */ +static int htt_rx_hash_init(struct htt_pdev_t *pdev) +{ + int i, j; + int rc = 0; + void *allocation; + + HTT_ASSERT2(QDF_IS_PWR2(RX_NUM_HASH_BUCKETS)); + + /* hash table is array of bucket pointers */ + pdev->rx_ring.hash_table = + qdf_mem_malloc(RX_NUM_HASH_BUCKETS * + sizeof(struct htt_rx_hash_bucket *)); + + if (!pdev->rx_ring.hash_table) + return 1; + + qdf_spinlock_create(&pdev->rx_ring.rx_hash_lock); + qdf_spin_lock_bh(&pdev->rx_ring.rx_hash_lock); + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + /* pre-allocate bucket and pool of entries for this bucket */ + allocation = qdf_mem_malloc((sizeof(struct htt_rx_hash_bucket) + + (RX_ENTRIES_SIZE * sizeof(struct htt_rx_hash_entry)))); + qdf_spin_lock_bh(&pdev->rx_ring.rx_hash_lock); + pdev->rx_ring.hash_table[i] = allocation; + + HTT_RX_HASH_COUNT_RESET(pdev->rx_ring.hash_table[i]); + + /* initialize the hash table buckets */ + htt_list_init(&pdev->rx_ring.hash_table[i]->listhead); + + /* initialize the hash table free pool per bucket */ + htt_list_init(&pdev->rx_ring.hash_table[i]->freepool); + + /* pre-allocate a pool of entries for this bucket */ + pdev->rx_ring.hash_table[i]->entries = + (struct htt_rx_hash_entry *) + ((uint8_t *)pdev->rx_ring.hash_table[i] + + sizeof(struct htt_rx_hash_bucket)); + + if (!pdev->rx_ring.hash_table[i]->entries) { + qdf_print("rx hash bucket %d entries alloc failed\n", + (int)i); + while (i) { + i--; + qdf_mem_free(pdev->rx_ring.hash_table[i]); + } + qdf_mem_free(pdev->rx_ring.hash_table); + pdev->rx_ring.hash_table = NULL; + rc = 1; + goto hi_end; + } + + /* initialize the free list with pre-allocated entries */ + for (j = 0; j < RX_ENTRIES_SIZE; j++) { + pdev->rx_ring.hash_table[i]->entries[j].fromlist = 1; + htt_list_add_tail( + &pdev->rx_ring.hash_table[i]->freepool, + &pdev->rx_ring.hash_table[i]->entries[j]. + listnode); + } + } + + pdev->rx_ring.listnode_offset = + qdf_offsetof(struct htt_rx_hash_entry, listnode); +hi_end: + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + + return rc; +} + +/* De -initialization function of the rx buffer hash table. This function will + * free up the hash table which includes freeing all the pending rx buffers + */ +static void htt_rx_hash_deinit(struct htt_pdev_t *pdev) +{ + uint32_t i; + struct htt_rx_hash_entry *hash_entry; + struct htt_rx_hash_bucket **hash_table; + struct htt_list_node *list_iter = NULL; + qdf_mem_info_t mem_map_table = {0}; + bool ipa_smmu = false; + + if (!pdev->rx_ring.hash_table) + return; + + qdf_spin_lock_bh(&pdev->rx_ring.rx_hash_lock); + ipa_smmu = htt_rx_ring_smmu_mapped(pdev); + hash_table = pdev->rx_ring.hash_table; + pdev->rx_ring.hash_table = NULL; + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + /* Free the hash entries in hash bucket i */ + list_iter = hash_table[i]->listhead.next; + while (list_iter != &hash_table[i]->listhead) { + hash_entry = + (struct htt_rx_hash_entry *)((char *)list_iter - + pdev->rx_ring. + listnode_offset); + if (hash_entry->netbuf) { + if (ipa_smmu) { + if (qdf_unlikely( + !qdf_nbuf_is_rx_ipa_smmu_map( + hash_entry->netbuf))) { + qdf_err("nbuf: %pK NOT mapped", + hash_entry->netbuf); + qdf_assert_always(0); + } + qdf_nbuf_set_rx_ipa_smmu_map( + hash_entry->netbuf, + false); + qdf_update_mem_map_table(pdev->osdev, + &mem_map_table, + QDF_NBUF_CB_PADDR( + hash_entry->netbuf), + HTT_RX_BUF_SIZE); + + qdf_assert_always( + !cds_smmu_map_unmap( + false, 1, + &mem_map_table)); + } +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, hash_entry->netbuf, + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, hash_entry->netbuf, + QDF_DMA_FROM_DEVICE); +#endif + qdf_nbuf_free(hash_entry->netbuf); + hash_entry->paddr = 0; + } + list_iter = list_iter->next; + + if (!hash_entry->fromlist) + qdf_mem_free(hash_entry); + } + + qdf_mem_free(hash_table[i]); + } + qdf_mem_free(hash_table); + + qdf_spinlock_destroy(&pdev->rx_ring.rx_hash_lock); +} + +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num) +{ + int filled = 0; + + if (!qdf_spin_trylock_bh(&pdev->rx_ring.refill_lock)) { + if (qdf_atomic_read(&pdev->rx_ring.refill_debt) + < RX_RING_REFILL_DEBT_MAX) { + qdf_atomic_add(num, &pdev->rx_ring.refill_debt); + pdev->rx_buff_debt_invoked++; + return filled; /* 0 */ + } + /* + * else: + * If we have quite a debt, then it is better for the lock + * holder to finish its work and then acquire the lock and + * fill our own part. + */ + qdf_spin_lock_bh(&pdev->rx_ring.refill_lock); + } + pdev->rx_buff_fill_n_invoked++; + + filled = htt_rx_ring_fill_n(pdev, num); + + if (filled > num) { + /* we served ourselves and some other debt */ + /* sub is safer than = 0 */ + qdf_atomic_sub(filled - num, &pdev->rx_ring.refill_debt); + } else { + qdf_atomic_add(num - filled, &pdev->rx_ring.refill_debt); + } + qdf_spin_unlock_bh(&pdev->rx_ring.refill_lock); + + return filled; +} + +#if defined(WLAN_FEATURE_TSF_PLUS) && !defined(CONFIG_HL_SUPPORT) +/** + * htt_rx_tail_msdu_timestamp() - update tail msdu tsf64 timestamp + * @tail_rx_desc: pointer to tail msdu descriptor + * @timestamp_rx_desc: pointer to timestamp msdu descriptor + * + * Return: none + */ +static inline void htt_rx_tail_msdu_timestamp( + struct htt_host_rx_desc_base *tail_rx_desc, + struct htt_host_rx_desc_base *timestamp_rx_desc) +{ + if (tail_rx_desc) { + if (!timestamp_rx_desc) { + tail_rx_desc->ppdu_end.wb_timestamp_lower_32 = 0; + tail_rx_desc->ppdu_end.wb_timestamp_upper_32 = 0; + } else { + if (timestamp_rx_desc != tail_rx_desc) { + tail_rx_desc->ppdu_end.wb_timestamp_lower_32 = + timestamp_rx_desc->ppdu_end.wb_timestamp_lower_32; + tail_rx_desc->ppdu_end.wb_timestamp_upper_32 = + timestamp_rx_desc->ppdu_end.wb_timestamp_upper_32; + } + } + } +} +#else +static inline void htt_rx_tail_msdu_timestamp( + struct htt_host_rx_desc_base *tail_rx_desc, + struct htt_host_rx_desc_base *timestamp_rx_desc) +{ +} +#endif + +static int +htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt) +{ + qdf_nbuf_t msdu, next, prev = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + uint32_t rx_ctx_id; + unsigned int msdu_count = 0; + uint8_t offload_ind, frag_ind; + uint8_t peer_id; + struct htt_host_rx_desc_base *rx_desc = NULL; + enum qdf_dp_tx_rx_status status = QDF_TX_RX_STATUS_OK; + qdf_dma_addr_t paddr; + qdf_mem_info_t mem_map_table = {0}; + int ret = 1; + struct htt_host_rx_desc_base *timestamp_rx_desc = NULL; + + HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); + + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + rx_ctx_id = QDF_NBUF_CB_RX_CTX_ID(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET( + *(u_int32_t *)rx_ind_data); + + offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word); + + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + HTT_RX_CHECK_MSDU_COUNT(msdu_count); + + ol_rx_update_histogram_stats(msdu_count, frag_ind, offload_ind); + htt_rx_dbg_rxbuf_httrxind(pdev, msdu_count); + + msg_word = + (uint32_t *)(rx_ind_data + HTT_RX_IN_ORD_PADDR_IND_HDR_BYTES); + if (offload_ind) { + ol_rx_offload_paddr_deliver_ind_handler(pdev, msdu_count, + msg_word); + *head_msdu = *tail_msdu = NULL; + ret = 0; + goto end; + } + + paddr = htt_rx_in_ord_paddr_get(msg_word); + (*head_msdu) = msdu = htt_rx_in_order_netbuf_pop(pdev, paddr); + + if (qdf_unlikely(!msdu)) { + qdf_print("netbuf pop failed!"); + *tail_msdu = NULL; + pdev->rx_ring.pop_fail_cnt++; + ret = 0; + goto end; + } + + while (msdu_count > 0) { + if (qdf_nbuf_is_rx_ipa_smmu_map(msdu)) { + /* + * nbuf was already detached from hash_entry, + * there is no parallel IPA context to access + * this nbuf for smmu map/unmap, so updating + * this flag here without lock. + * + * This flag was not updated in netbuf_pop context + * htt_rx_hash_list_lookup (where lock held), to + * differentiate whether this nbuf to be + * smmu unmapped or it was never mapped so far. + */ + qdf_nbuf_set_rx_ipa_smmu_map(msdu, false); + qdf_update_mem_map_table(pdev->osdev, &mem_map_table, + QDF_NBUF_CB_PADDR(msdu), + HTT_RX_BUF_SIZE); + qdf_assert_always( + !cds_smmu_map_unmap(false, 1, &mem_map_table)); + } + + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); +#endif + msdu_count--; + + if (pdev->rx_buff_pool.netbufs_ring && + QDF_NBUF_CB_RX_PACKET_BUFF_POOL(msdu) && + !htt_rx_buff_pool_refill(pdev, msdu)) { + if (!msdu_count) { + if (!prev) { + *head_msdu = *tail_msdu = NULL; + ret = 1; + goto end; + } + *tail_msdu = prev; + qdf_nbuf_set_next(prev, NULL); + goto end; + } else { + /* get the next msdu */ + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(!next)) { + qdf_print("netbuf pop failed!"); + *tail_msdu = NULL; + pdev->rx_ring.pop_fail_cnt++; + ret = 0; + goto end; + } + /* if this is not the first msdu, update the + * next pointer of the preceding msdu + */ + if (prev) { + qdf_nbuf_set_next(prev, next); + } else { + /* if this is the first msdu, update + * head pointer + */ + *head_msdu = next; + } + msdu = next; + continue; + } + } + + /* cache consistency has been taken care of by qdf_nbuf_unmap */ + rx_desc = htt_rx_desc(msdu); + htt_rx_extract_lro_info(msdu, rx_desc); + + /* check if the msdu is last mpdu */ + if (rx_desc->attention.last_mpdu) + timestamp_rx_desc = rx_desc; + + /* + * Make the netbuf's data pointer point to the payload rather + * than the descriptor. + */ + qdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION); + + QDF_NBUF_CB_DP_TRACE_PRINT(msdu) = false; + qdf_dp_trace_set_track(msdu, QDF_RX); + QDF_NBUF_CB_TX_PACKET_TRACK(msdu) = QDF_NBUF_TX_PKT_DATA_TRACK; + QDF_NBUF_CB_RX_CTX_ID(msdu) = rx_ctx_id; + + if (qdf_nbuf_is_ipv4_arp_pkt(msdu)) + QDF_NBUF_CB_GET_PACKET_TYPE(msdu) = + QDF_NBUF_CB_PACKET_TYPE_ARP; + + DPTRACE(qdf_dp_trace(msdu, + QDF_DP_TRACE_RX_HTT_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_RX)); + + qdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + HTT_RX_IN_ORD_PADDR_IND_MSDU_LEN_GET( + *(msg_word + NEXT_FIELD_OFFSET_IN32)))); +#if defined(HELIUMPLUS_DEBUG) + ol_txrx_dump_pkt(msdu, 0, 64); +#endif + *((uint8_t *)&rx_desc->fw_desc.u.val) = + HTT_RX_IN_ORD_PADDR_IND_FW_DESC_GET(*(msg_word + + NEXT_FIELD_OFFSET_IN32)); + + /* calling callback function for packet logging */ + if (pdev->rx_pkt_dump_cb) { + if (qdf_unlikely(RX_DESC_MIC_ERR_IS_SET && + !RX_DESC_DISCARD_IS_SET)) + status = QDF_TX_RX_STATUS_FW_DISCARD; + pdev->rx_pkt_dump_cb(msdu, peer_id, status); + } + + if (pdev->cfg.is_first_wakeup_packet) + htt_get_first_packet_after_wow_wakeup( + msg_word + NEXT_FIELD_OFFSET_IN32, msdu); + + /* if discard flag is set (SA is self MAC), then + * don't check mic failure. + */ + if (qdf_unlikely(RX_DESC_MIC_ERR_IS_SET && + !RX_DESC_DISCARD_IS_SET)) { + uint8_t tid = + HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET( + *(u_int32_t *)rx_ind_data); + ol_rx_mic_error_handler(pdev->txrx_pdev, tid, peer_id, + rx_desc, msdu); + + htt_rx_desc_frame_free(pdev, msdu); + /* if this is the last msdu */ + if (!msdu_count) { + /* if this is the only msdu */ + if (!prev) { + *head_msdu = *tail_msdu = NULL; + ret = 0; + goto end; + } + *tail_msdu = prev; + qdf_nbuf_set_next(prev, NULL); + goto end; + } else { /* if this is not the last msdu */ + /* get the next msdu */ + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(!next)) { + qdf_print("netbuf pop failed!"); + *tail_msdu = NULL; + pdev->rx_ring.pop_fail_cnt++; + ret = 0; + goto end; + } + + /* if this is not the first msdu, update the + * next pointer of the preceding msdu + */ + if (prev) { + qdf_nbuf_set_next(prev, next); + } else { + /* if this is the first msdu, update the + * head pointer + */ + *head_msdu = next; + } + msdu = next; + continue; + } + } + /* check if this is the last msdu */ + if (msdu_count) { + msg_word += HTT_RX_IN_ORD_PADDR_IND_MSDU_DWORDS; + paddr = htt_rx_in_ord_paddr_get(msg_word); + next = htt_rx_in_order_netbuf_pop(pdev, paddr); + if (qdf_unlikely(!next)) { + qdf_print("netbuf pop failed!"); + *tail_msdu = NULL; + pdev->rx_ring.pop_fail_cnt++; + ret = 0; + goto end; + } + qdf_nbuf_set_next(msdu, next); + prev = msdu; + msdu = next; + } else { + *tail_msdu = msdu; + qdf_nbuf_set_next(msdu, NULL); + } + } + + htt_rx_tail_msdu_timestamp(rx_desc, timestamp_rx_desc); + +end: + return ret; +} + +static void *htt_rx_in_ord_mpdu_desc_list_next_ll(htt_pdev_handle pdev, + qdf_nbuf_t netbuf) +{ + return (void *)htt_rx_desc(netbuf); +} +#else + +static inline +int htt_rx_hash_init(struct htt_pdev_t *pdev) +{ + return 0; +} + +static inline +void htt_rx_hash_deinit(struct htt_pdev_t *pdev) +{ +} + +static inline int +htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *replenish_cnt) +{ + return 0; +} + +static inline +void *htt_rx_in_ord_mpdu_desc_list_next_ll(htt_pdev_handle pdev, + qdf_nbuf_t netbuf) +{ + return NULL; +} +#endif + +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD + +/* AR9888v1 WORKAROUND for EV#112367 */ +/* FIX THIS - remove this WAR when the bug is fixed */ +#define PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR + +static int +htt_rx_amsdu_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + int msdu_len, msdu_chaining = 0; + qdf_nbuf_t msdu; + struct htt_host_rx_desc_base *rx_desc; + uint8_t *rx_ind_data; + uint32_t *msg_word, num_msdu_bytes; + qdf_dma_addr_t rx_desc_paddr; + enum htt_t2h_msg_type msg_type; + uint8_t pad_bytes = 0; + + HTT_ASSERT1(htt_rx_ring_elems(pdev) != 0); + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + + if (qdf_unlikely(msg_type == HTT_T2H_MSG_TYPE_RX_FRAG_IND)) { + num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); + } else { + num_msdu_bytes = HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + + HTT_RX_IND_HDR_PREFIX_SIZE32 + + HTT_RX_PPDU_DESC_SIZE32)); + } + msdu = *head_msdu = htt_rx_netbuf_pop(pdev); + while (1) { + int last_msdu, msdu_len_invalid, msdu_chained; + int byte_offset; + qdf_nbuf_t next; + + /* + * Set the netbuf length to be the entire buffer length + * initially, so the unmap will unmap the entire buffer. + */ + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); +#endif + + /* cache consistency has been taken care of by qdf_nbuf_unmap */ + + /* + * Now read the rx descriptor. + * Set the length to the appropriate value. + * Check if this MSDU completes a MPDU. + */ + rx_desc = htt_rx_desc(msdu); +#if defined(HELIUMPLUS) + if (HTT_WIFI_IP(pdev, 2, 0)) + pad_bytes = rx_desc->msdu_end.l3_header_padding; +#endif /* defined(HELIUMPLUS) */ + + /* + * Save PADDR of descriptor and make the netbuf's data pointer + * point to the payload rather than the descriptor. + */ + rx_desc_paddr = QDF_NBUF_CB_PADDR(msdu); + qdf_nbuf_pull_head(msdu, HTT_RX_STD_DESC_RESERVATION + + pad_bytes); + + /* + * Sanity check - confirm the HW is finished filling in + * the rx data. + * If the HW and SW are working correctly, then it's guaranteed + * that the HW's MAC DMA is done before this point in the SW. + * To prevent the case that we handle a stale Rx descriptor, + * just assert for now until we have a way to recover. + */ + +#ifdef DEBUG_DMA_DONE + if (qdf_unlikely(!((*(uint32_t *)&rx_desc->attention) + & RX_ATTENTION_0_MSDU_DONE_MASK))) { + int dbg_iter = MAX_DONE_BIT_CHECK_ITER; + + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "malformed frame"); + + while (dbg_iter && + (!((*(uint32_t *)&rx_desc->attention) & + RX_ATTENTION_0_MSDU_DONE_MASK))) { + qdf_mdelay(1); + qdf_mem_dma_sync_single_for_cpu( + pdev->osdev, + rx_desc_paddr, + HTT_RX_STD_DESC_RESERVATION, + DMA_FROM_DEVICE); + + QDF_TRACE(QDF_MODULE_ID_HTT, + QDF_TRACE_LEVEL_INFO, + "debug iter %d success %d", dbg_iter, + pdev->rx_ring.dbg_sync_success); + + dbg_iter--; + } + + if (qdf_unlikely(!((*(uint32_t *)&rx_desc->attention) + & RX_ATTENTION_0_MSDU_DONE_MASK))) { +#ifdef HTT_RX_RESTORE + QDF_TRACE(QDF_MODULE_ID_HTT, + QDF_TRACE_LEVEL_ERROR, + "RX done bit error detected!"); + + qdf_nbuf_set_next(msdu, NULL); + *tail_msdu = msdu; + pdev->rx_ring.rx_reset = 1; + return msdu_chaining; +#else + wma_cli_set_command(0, GEN_PARAM_CRASH_INJECT, + 0, GEN_CMD); + HTT_ASSERT_ALWAYS(0); +#endif + } + pdev->rx_ring.dbg_sync_success++; + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "debug iter %d success %d", dbg_iter, + pdev->rx_ring.dbg_sync_success); + } +#else + HTT_ASSERT_ALWAYS((*(uint32_t *)&rx_desc->attention) & + RX_ATTENTION_0_MSDU_DONE_MASK); +#endif + /* + * Copy the FW rx descriptor for this MSDU from the rx + * indication message into the MSDU's netbuf. + * HL uses the same rx indication message definition as LL, and + * simply appends new info (fields from the HW rx desc, and the + * MSDU payload itself). + * So, the offset into the rx indication message only has to + * account for the standard offset of the per-MSDU FW rx + * desc info within the message, and how many bytes of the + * per-MSDU FW rx desc info have already been consumed. + * (And the endianness of the host, + * since for a big-endian host, the rx ind message contents, + * including the per-MSDU rx desc bytes, were byteswapped during + * upload.) + */ + if (pdev->rx_ind_msdu_byte_idx < num_msdu_bytes) { + if (qdf_unlikely + (msg_type == HTT_T2H_MSG_TYPE_RX_FRAG_IND)) + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET); + else + byte_offset = + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_IND_FW_RX_DESC_BYTE_OFFSET + + pdev->rx_ind_msdu_byte_idx); + + *((uint8_t *)&rx_desc->fw_desc.u.val) = + rx_ind_data[byte_offset]; + /* + * The target is expected to only provide the basic + * per-MSDU rx descriptors. Just to be sure, + * verify that the target has not attached + * extension data (e.g. LRO flow ID). + */ + /* + * The assertion below currently doesn't work for + * RX_FRAG_IND messages, since their format differs + * from the RX_IND format (no FW rx PPDU desc in + * the current RX_FRAG_IND message). + * If the RX_FRAG_IND message format is updated to match + * the RX_IND message format, then the following + * assertion can be restored. + */ + /* + * qdf_assert((rx_ind_data[byte_offset] & + * FW_RX_DESC_EXT_M) == 0); + */ + pdev->rx_ind_msdu_byte_idx += 1; + /* or more, if there's ext data */ + } else { + /* + * When an oversized AMSDU happened, FW will lost some + * of MSDU status - in this case, the FW descriptors + * provided will be less than the actual MSDUs + * inside this MPDU. + * Mark the FW descriptors so that it will still + * deliver to upper stack, if no CRC error for the MPDU. + * + * FIX THIS - the FW descriptors are actually for MSDUs + * in the end of this A-MSDU instead of the beginning. + */ + *((uint8_t *)&rx_desc->fw_desc.u.val) = 0; + } + + /* + * TCP/UDP checksum offload support + */ + htt_set_checksum_result_ll(pdev, msdu, rx_desc); + + msdu_len_invalid = (*(uint32_t *)&rx_desc->attention) & + RX_ATTENTION_0_MPDU_LENGTH_ERR_MASK; + msdu_chained = (((*(uint32_t *)&rx_desc->frag_info) & + RX_FRAG_INFO_0_RING2_MORE_COUNT_MASK) >> + RX_FRAG_INFO_0_RING2_MORE_COUNT_LSB); + msdu_len = + ((*((uint32_t *)&rx_desc->msdu_start)) & + RX_MSDU_START_0_MSDU_LENGTH_MASK) >> + RX_MSDU_START_0_MSDU_LENGTH_LSB; + + do { + if (!msdu_len_invalid && !msdu_chained) { +#if defined(PEREGRINE_1_0_ZERO_LEN_PHY_ERR_WAR) + if (msdu_len > 0x3000) + break; +#endif + qdf_nbuf_trim_tail(msdu, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + msdu_len)); + } + } while (0); + + while (msdu_chained--) { + next = htt_rx_netbuf_pop(pdev); + qdf_nbuf_set_pktlen(next, HTT_RX_BUF_SIZE); + msdu_len -= HTT_RX_BUF_SIZE; + qdf_nbuf_set_next(msdu, next); + msdu = next; + msdu_chaining = 1; + + if (msdu_chained == 0) { + /* Trim the last one to the correct size - + * accounting for inconsistent HW lengths + * causing length overflows and underflows + */ + if (((unsigned int)msdu_len) > + ((unsigned int) + (HTT_RX_BUF_SIZE - RX_STD_DESC_SIZE))) { + msdu_len = + (HTT_RX_BUF_SIZE - + RX_STD_DESC_SIZE); + } + + qdf_nbuf_trim_tail(next, + HTT_RX_BUF_SIZE - + (RX_STD_DESC_SIZE + + msdu_len)); + } + } + + last_msdu = + ((*(((uint32_t *)&rx_desc->msdu_end) + 4)) & + RX_MSDU_END_4_LAST_MSDU_MASK) >> + RX_MSDU_END_4_LAST_MSDU_LSB; + + if (last_msdu) { + qdf_nbuf_set_next(msdu, NULL); + break; + } + + next = htt_rx_netbuf_pop(pdev); + qdf_nbuf_set_next(msdu, next); + msdu = next; + } + *tail_msdu = msdu; + + /* + * Don't refill the ring yet. + * First, the elements popped here are still in use - it is + * not safe to overwrite them until the matching call to + * mpdu_desc_list_next. + * Second, for efficiency it is preferable to refill the rx ring + * with 1 PPDU's worth of rx buffers (something like 32 x 3 buffers), + * rather than one MPDU's worth of rx buffers (sth like 3 buffers). + * Consequently, we'll rely on the txrx SW to tell us when it is done + * pulling all the PPDU's rx buffers out of the rx ring, and then + * refill it just once. + */ + return msdu_chaining; +} + +static +void *htt_rx_mpdu_desc_list_next_ll(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + int idx = pdev->rx_ring.sw_rd_idx.msdu_desc; + qdf_nbuf_t netbuf = pdev->rx_ring.buf.netbufs_ring[idx]; + + pdev->rx_ring.sw_rd_idx.msdu_desc = pdev->rx_ring.sw_rd_idx.msdu_payld; + return (void *)htt_rx_desc(netbuf); +} + +#else + +static inline int +htt_rx_amsdu_pop_ll(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count) +{ + return 0; +} + +static inline +void *htt_rx_mpdu_desc_list_next_ll(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + return NULL; +} +#endif + +/** + * htt_rx_fill_ring_count() - replenish rx msdu buffer + * @pdev: Handle (pointer) to HTT pdev. + * + * This function will replenish the rx buffer to the max number + * that can be kept in the ring + * + * Return: None + */ +void htt_rx_fill_ring_count(htt_pdev_handle pdev) +{ + int num_to_fill; + + num_to_fill = pdev->rx_ring.fill_level - + qdf_atomic_read(&pdev->rx_ring.fill_cnt); + htt_rx_ring_fill_n(pdev, num_to_fill /* okay if <= 0 */); +} + +int htt_rx_attach(struct htt_pdev_t *pdev) +{ + qdf_dma_addr_t paddr; + uint32_t ring_elem_size = sizeof(target_paddr_t); + + pdev->rx_ring.size = htt_rx_ring_size(pdev); + HTT_ASSERT2(QDF_IS_PWR2(pdev->rx_ring.size)); + pdev->rx_ring.size_mask = pdev->rx_ring.size - 1; + + /* + * Set the initial value for the level to which the rx ring + * should be filled, based on the max throughput and the worst + * likely latency for the host to fill the rx ring. + * In theory, this fill level can be dynamically adjusted from + * the initial value set here to reflect the actual host latency + * rather than a conservative assumption. + */ + pdev->rx_ring.fill_level = htt_rx_ring_fill_level(pdev); + + if (pdev->cfg.is_full_reorder_offload) { + if (htt_rx_hash_init(pdev)) + goto fail1; + + /* allocate the target index */ + pdev->rx_ring.target_idx.vaddr = + qdf_mem_alloc_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), &paddr); + + if (!pdev->rx_ring.target_idx.vaddr) + goto fail2; + + pdev->rx_ring.target_idx.paddr = paddr; + *pdev->rx_ring.target_idx.vaddr = 0; + } else { + pdev->rx_ring.buf.netbufs_ring = + qdf_mem_malloc(pdev->rx_ring.size * sizeof(qdf_nbuf_t)); + if (!pdev->rx_ring.buf.netbufs_ring) + goto fail1; + + pdev->rx_ring.sw_rd_idx.msdu_payld = 0; + pdev->rx_ring.sw_rd_idx.msdu_desc = 0; + } + + pdev->rx_ring.buf.paddrs_ring = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + pdev->rx_ring.size * ring_elem_size, + &paddr); + if (!pdev->rx_ring.buf.paddrs_ring) + goto fail3; + + pdev->rx_ring.base_paddr = paddr; + pdev->rx_ring.alloc_idx.vaddr = + qdf_mem_alloc_consistent( + pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), &paddr); + + if (!pdev->rx_ring.alloc_idx.vaddr) + goto fail4; + + pdev->rx_ring.alloc_idx.paddr = paddr; + *pdev->rx_ring.alloc_idx.vaddr = 0; + + if (htt_rx_buff_pool_init(pdev)) + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "HTT: pre allocated packet pool alloc failed"); + + /* + * Initialize the Rx refill reference counter to be one so that + * only one thread is allowed to refill the Rx ring. + */ + qdf_atomic_init(&pdev->rx_ring.refill_ref_cnt); + qdf_atomic_inc(&pdev->rx_ring.refill_ref_cnt); + + /* Initialize the refill_lock and debt (for rx-parallelization) */ + qdf_spinlock_create(&pdev->rx_ring.refill_lock); + qdf_atomic_init(&pdev->rx_ring.refill_debt); + + /* Initialize the Rx refill retry timer */ + qdf_timer_init(pdev->osdev, + &pdev->rx_ring.refill_retry_timer, + htt_rx_ring_refill_retry, (void *)pdev, + QDF_TIMER_TYPE_SW); + + qdf_atomic_init(&pdev->rx_ring.fill_cnt); + pdev->rx_ring.pop_fail_cnt = 0; +#ifdef DEBUG_DMA_DONE + pdev->rx_ring.dbg_ring_idx = 0; + pdev->rx_ring.dbg_refill_cnt = 0; + pdev->rx_ring.dbg_sync_success = 0; +#endif +#ifdef HTT_RX_RESTORE + pdev->rx_ring.rx_reset = 0; + pdev->rx_ring.htt_rx_restore = 0; +#endif + htt_rx_dbg_rxbuf_init(pdev); + htt_rx_ring_fill_n(pdev, pdev->rx_ring.fill_level); + + if (pdev->cfg.is_full_reorder_offload) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "HTT: full reorder offload enabled"); + htt_rx_amsdu_pop = htt_rx_amsdu_rx_in_order_pop_ll; + htt_rx_frag_pop = htt_rx_amsdu_rx_in_order_pop_ll; + htt_rx_mpdu_desc_list_next = + htt_rx_in_ord_mpdu_desc_list_next_ll; + } else { + htt_rx_amsdu_pop = htt_rx_amsdu_pop_ll; + htt_rx_frag_pop = htt_rx_amsdu_pop_ll; + htt_rx_mpdu_desc_list_next = htt_rx_mpdu_desc_list_next_ll; + } + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + htt_rx_amsdu_pop = htt_rx_mon_amsdu_rx_in_order_pop_ll; + + htt_rx_offload_msdu_cnt = htt_rx_offload_msdu_cnt_ll; + htt_rx_offload_msdu_pop = htt_rx_offload_msdu_pop_ll; + htt_rx_mpdu_desc_retry = htt_rx_mpdu_desc_retry_ll; + htt_rx_mpdu_desc_seq_num = htt_rx_mpdu_desc_seq_num_ll; + htt_rx_mpdu_desc_pn = htt_rx_mpdu_desc_pn_ll; + htt_rx_mpdu_desc_tid = htt_rx_mpdu_desc_tid_ll; + htt_rx_msdu_desc_completes_mpdu = htt_rx_msdu_desc_completes_mpdu_ll; + htt_rx_msdu_first_msdu_flag = htt_rx_msdu_first_msdu_flag_ll; + htt_rx_msdu_has_wlan_mcast_flag = htt_rx_msdu_has_wlan_mcast_flag_ll; + htt_rx_msdu_is_wlan_mcast = htt_rx_msdu_is_wlan_mcast_ll; + htt_rx_msdu_is_frag = htt_rx_msdu_is_frag_ll; + htt_rx_msdu_desc_retrieve = htt_rx_msdu_desc_retrieve_ll; + htt_rx_mpdu_is_encrypted = htt_rx_mpdu_is_encrypted_ll; + htt_rx_msdu_desc_key_id = htt_rx_msdu_desc_key_id_ll; + htt_rx_msdu_chan_info_present = htt_rx_msdu_chan_info_present_ll; + htt_rx_msdu_center_freq = htt_rx_msdu_center_freq_ll; + + return 0; /* success */ + +fail4: + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + pdev->rx_ring.size * sizeof(target_paddr_t), + pdev->rx_ring.buf.paddrs_ring, + pdev->rx_ring.base_paddr, + qdf_get_dma_mem_context((&pdev->rx_ring.buf), + memctx)); + +fail3: + if (pdev->cfg.is_full_reorder_offload) + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + pdev->rx_ring.target_idx.vaddr, + pdev->rx_ring.target_idx.paddr, + qdf_get_dma_mem_context((&pdev-> + rx_ring. + target_idx), + memctx)); + else + qdf_mem_free(pdev->rx_ring.buf.netbufs_ring); + +fail2: + if (pdev->cfg.is_full_reorder_offload) + htt_rx_hash_deinit(pdev); + +fail1: + return 1; /* failure */ +} + +void htt_rx_detach(struct htt_pdev_t *pdev) +{ + bool ipa_smmu = false; + qdf_nbuf_t nbuf; + + qdf_timer_stop(&pdev->rx_ring.refill_retry_timer); + qdf_timer_free(&pdev->rx_ring.refill_retry_timer); + htt_rx_dbg_rxbuf_deinit(pdev); + + ipa_smmu = htt_rx_ring_smmu_mapped(pdev); + + if (pdev->cfg.is_full_reorder_offload) { + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + pdev->rx_ring.target_idx.vaddr, + pdev->rx_ring.target_idx.paddr, + qdf_get_dma_mem_context((&pdev-> + rx_ring. + target_idx), + memctx)); + htt_rx_hash_deinit(pdev); + } else { + int sw_rd_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + qdf_mem_info_t mem_map_table = {0}; + + while (sw_rd_idx != *pdev->rx_ring.alloc_idx.vaddr) { + nbuf = pdev->rx_ring.buf.netbufs_ring[sw_rd_idx]; + if (ipa_smmu) { + if (qdf_unlikely( + !qdf_nbuf_is_rx_ipa_smmu_map(nbuf))) { + qdf_err("smmu not mapped, nbuf: %pK", + nbuf); + qdf_assert_always(0); + } + qdf_nbuf_set_rx_ipa_smmu_map(nbuf, false); + qdf_update_mem_map_table(pdev->osdev, + &mem_map_table, + QDF_NBUF_CB_PADDR(nbuf), + HTT_RX_BUF_SIZE); + qdf_assert_always( + !cds_smmu_map_unmap(false, 1, + &mem_map_table)); + } +#ifdef DEBUG_DMA_DONE + qdf_nbuf_unmap(pdev->osdev, nbuf, + QDF_DMA_BIDIRECTIONAL); +#else + qdf_nbuf_unmap(pdev->osdev, nbuf, + QDF_DMA_FROM_DEVICE); +#endif + qdf_nbuf_free(nbuf); + sw_rd_idx++; + sw_rd_idx &= pdev->rx_ring.size_mask; + } + qdf_mem_free(pdev->rx_ring.buf.netbufs_ring); + } + + htt_rx_buff_pool_deinit(pdev); + + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + sizeof(uint32_t), + pdev->rx_ring.alloc_idx.vaddr, + pdev->rx_ring.alloc_idx.paddr, + qdf_get_dma_mem_context((&pdev->rx_ring. + alloc_idx), + memctx)); + + qdf_mem_free_consistent(pdev->osdev, pdev->osdev->dev, + pdev->rx_ring.size * sizeof(target_paddr_t), + pdev->rx_ring.buf.paddrs_ring, + pdev->rx_ring.base_paddr, + qdf_get_dma_mem_context((&pdev->rx_ring.buf), + memctx)); + + /* destroy the rx-parallelization refill spinlock */ + qdf_spinlock_destroy(&pdev->rx_ring.refill_lock); +} + +static QDF_STATUS htt_rx_hash_smmu_map(bool map, struct htt_pdev_t *pdev) +{ + uint32_t i; + struct htt_rx_hash_entry *hash_entry; + struct htt_rx_hash_bucket **hash_table; + struct htt_list_node *list_iter = NULL; + qdf_mem_info_t mem_map_table = {0}; + qdf_nbuf_t nbuf; + int ret; + + qdf_spin_lock_bh(&pdev->rx_ring.rx_hash_lock); + hash_table = pdev->rx_ring.hash_table; + + for (i = 0; i < RX_NUM_HASH_BUCKETS; i++) { + /* Free the hash entries in hash bucket i */ + list_iter = hash_table[i]->listhead.next; + while (list_iter != &hash_table[i]->listhead) { + hash_entry = + (struct htt_rx_hash_entry *)((char *)list_iter - + pdev->rx_ring. + listnode_offset); + nbuf = hash_entry->netbuf; + if (nbuf) { + if (qdf_unlikely(map == + qdf_nbuf_is_rx_ipa_smmu_map(nbuf))) { + qdf_err("map/unmap err:%d, nbuf:%pK", + map, nbuf); + list_iter = list_iter->next; + continue; + } + qdf_nbuf_set_rx_ipa_smmu_map(nbuf, map); + qdf_update_mem_map_table(pdev->osdev, + &mem_map_table, + QDF_NBUF_CB_PADDR(nbuf), + HTT_RX_BUF_SIZE); + ret = cds_smmu_map_unmap(map, 1, + &mem_map_table); + if (ret) { + qdf_nbuf_set_rx_ipa_smmu_map(nbuf, + !map); + qdf_err("map: %d failure, nbuf: %pK", + map, nbuf); + qdf_spin_unlock_bh( + &pdev->rx_ring.rx_hash_lock); + return QDF_STATUS_E_FAILURE; + } + } + list_iter = list_iter->next; + } + } + + pdev->rx_ring.smmu_map = map; + qdf_spin_unlock_bh(&pdev->rx_ring.rx_hash_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS htt_rx_update_smmu_map(struct htt_pdev_t *pdev, bool map) +{ + QDF_STATUS status; + + if (!pdev->rx_ring.hash_table) + return QDF_STATUS_SUCCESS; + + if (!qdf_mem_smmu_s1_enabled(pdev->osdev) || !pdev->is_ipa_uc_enabled) + return QDF_STATUS_SUCCESS; + + qdf_spin_lock_bh(&pdev->rx_ring.refill_lock); + status = htt_rx_hash_smmu_map(map, pdev); + qdf_spin_unlock_bh(&pdev->rx_ring.refill_lock); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_t2h.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_t2h.c new file mode 100644 index 0000000000..27a8bd2fa2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_t2h.c @@ -0,0 +1,1781 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: htt_t2h.c + * + * brief Provide functions to process target->host HTT messages. + * details + * This file contains functions related to target->host HTT messages. + * There are two categories of functions: + * 1. A function that receives a HTT message from HTC, and dispatches it + * based on the HTT message type. + * 2. functions that provide the info elements from specific HTT messages. + */ +#include +#include /* HTC_PACKET */ +#include /* HTT_T2H_MSG_TYPE, etc. */ +#include /* qdf_nbuf_t */ + +#include +#include +#include +#include /* htt_tx_status */ + +#include /* HTT_TX_SCHED, etc. */ +#include +#include +#include +#include +#include +#include "pktlog_ac.h" +#include +#include +#include +/*--- target->host HTT message dispatch function ----------------------------*/ + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if defined(CONFIG_HL_SUPPORT) + + + +/** + * htt_rx_frag_set_last_msdu() - set last msdu bit in rx descriptor + * for received frames + * @pdev: Handle (pointer) to HTT pdev. + * @msg: htt received msg + * + * Return: None + */ +static inline +void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) +{ +} +#else + +static void htt_rx_frag_set_last_msdu(struct htt_pdev_t *pdev, qdf_nbuf_t msg) +{ + uint32_t *msg_word; + unsigned int num_msdu_bytes; + qdf_nbuf_t msdu; + struct htt_host_rx_desc_base *rx_desc; + int start_idx; + uint8_t *p_fw_msdu_rx_desc = 0; + + msg_word = (uint32_t *) qdf_nbuf_data(msg); + num_msdu_bytes = HTT_RX_FRAG_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + HTT_RX_FRAG_IND_HDR_PREFIX_SIZE32)); + /* + * 1 word for the message header, + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + pdev->rx_mpdu_range_offset_words = 3 + ((num_msdu_bytes + 3) >> 2); + pdev->rx_ind_msdu_byte_idx = 0; + + p_fw_msdu_rx_desc = ((uint8_t *) (msg_word) + + HTT_ENDIAN_BYTE_IDX_SWAP + (HTT_RX_FRAG_IND_FW_DESC_BYTE_OFFSET)); + + /* + * Fix for EV126710, in which BSOD occurs due to last_msdu bit + * not set while the next pointer is deliberately set to NULL + * before calling ol_rx_pn_check_base() + * + * For fragment frames, the HW may not have set the last_msdu bit + * in the rx descriptor, but the SW expects this flag to be set, + * since each fragment is in a separate MPDU. Thus, set the flag here, + * just in case the HW didn't. + */ + start_idx = pdev->rx_ring.sw_rd_idx.msdu_payld; + msdu = pdev->rx_ring.buf.netbufs_ring[start_idx]; + qdf_nbuf_set_pktlen(msdu, HTT_RX_BUF_SIZE); + qdf_nbuf_unmap(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); + rx_desc = htt_rx_desc(msdu); + *((uint8_t *) &rx_desc->fw_desc.u.val) = *p_fw_msdu_rx_desc; + rx_desc->msdu_end.last_msdu = 1; + qdf_nbuf_map(pdev->osdev, msdu, QDF_DMA_FROM_DEVICE); +} +#endif + +static uint8_t *htt_t2h_mac_addr_deswizzle(uint8_t *tgt_mac_addr, + uint8_t *buffer) +{ +#ifdef BIG_ENDIAN_HOST + /* + * The host endianness is opposite of the target endianness. + * To make uint32_t elements come out correctly, the target->host + * upload has swizzled the bytes in each uint32_t element of the + * message. + * For byte-array message fields like the MAC address, this + * upload swizzling puts the bytes in the wrong order, and needs + * to be undone. + */ + buffer[0] = tgt_mac_addr[3]; + buffer[1] = tgt_mac_addr[2]; + buffer[2] = tgt_mac_addr[1]; + buffer[3] = tgt_mac_addr[0]; + buffer[4] = tgt_mac_addr[7]; + buffer[5] = tgt_mac_addr[6]; + return buffer; +#else + /* + * The host endianness matches the target endianness - + * we can use the mac addr directly from the message buffer. + */ + return tgt_mac_addr; +#endif +} + +/** + * htt_ipa_op_response() - invoke an event handler from FW + * @pdev: Handle (pointer) to HTT pdev. + * @msg_word: htt msg + * + * Return: None + */ +#ifdef IPA_OFFLOAD +static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word) +{ + uint8_t op_code; + uint16_t len; + uint8_t *op_msg_buffer; + uint8_t *msg_start_ptr; + + htc_pm_runtime_put(pdev->htc_pdev); + msg_start_ptr = (uint8_t *) msg_word; + op_code = + HTT_WDI_IPA_OP_RESPONSE_OP_CODE_GET(*msg_word); + msg_word++; + len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*msg_word); + + op_msg_buffer = + qdf_mem_malloc(sizeof + (struct htt_wdi_ipa_op_response_t) + + len); + if (!op_msg_buffer) + return; + + qdf_mem_copy(op_msg_buffer, + msg_start_ptr, + sizeof(struct htt_wdi_ipa_op_response_t) + + len); + cdp_ipa_op_response(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, op_msg_buffer); +} +#else +static void htt_ipa_op_response(struct htt_pdev_t *pdev, uint32_t *msg_word) +{ +} +#endif + +#ifndef QCN7605_SUPPORT +static int htt_t2h_adjust_bus_target_delta(struct htt_pdev_t *pdev, + int32_t htt_credit_delta) +{ + if (pdev->cfg.is_high_latency && !pdev->cfg.default_tx_comp_req) { + HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex); + qdf_atomic_add(htt_credit_delta, + &pdev->htt_tx_credit.target_delta); + htt_credit_delta = htt_tx_credit_update(pdev); + HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex); + } + return htt_credit_delta; +} +#else +static int htt_t2h_adjust_bus_target_delta(struct htt_pdev_t *pdev, + int32_t htt_credit_delta) +{ + return htt_credit_delta; +} +#endif + +#define MAX_TARGET_TX_CREDIT 204800 +#define HTT_CFR_DUMP_COMPL_HEAD_SZ 4 + +/* Target to host Msg/event handler for low priority messages*/ +static void htt_t2h_lp_msg_handler(void *context, qdf_nbuf_t htt_t2h_msg, + bool free_msg_buf) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + uint32_t *msg_word; + enum htt_t2h_msg_type msg_type; + + msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + switch (msg_type) { + case HTT_T2H_MSG_TYPE_VERSION_CONF: + { + if (htc_dec_return_htt_runtime_cnt(pdev->htc_pdev) >= 0) + htc_pm_runtime_put(pdev->htc_pdev); + + pdev->tgt_ver.major = HTT_VER_CONF_MAJOR_GET(*msg_word); + pdev->tgt_ver.minor = HTT_VER_CONF_MINOR_GET(*msg_word); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "target uses HTT version %d.%d; host uses %d.%d", + pdev->tgt_ver.major, pdev->tgt_ver.minor, + HTT_CURRENT_VERSION_MAJOR, + HTT_CURRENT_VERSION_MINOR); + if (pdev->tgt_ver.major != HTT_CURRENT_VERSION_MAJOR) + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_WARN, + "*** Incompatible host/target HTT versions!"); + /* abort if the target is incompatible with the host */ + qdf_assert(pdev->tgt_ver.major == + HTT_CURRENT_VERSION_MAJOR); + if (pdev->tgt_ver.minor != HTT_CURRENT_VERSION_MINOR) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "*** Warning: host/target HTT versions are "); + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO_LOW, + "different, though compatible!"); + } + break; + } + case HTT_T2H_MSG_TYPE_RX_FLUSH: + { + uint16_t peer_id; + uint8_t tid; + uint16_t seq_num_start, seq_num_end; + enum htt_rx_flush_action action; + + if (qdf_nbuf_len(htt_t2h_msg) < HTT_RX_FLUSH_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + peer_id = HTT_RX_FLUSH_PEER_ID_GET(*msg_word); + tid = HTT_RX_FLUSH_TID_GET(*msg_word); + seq_num_start = + HTT_RX_FLUSH_SEQ_NUM_START_GET(*(msg_word + 1)); + seq_num_end = + HTT_RX_FLUSH_SEQ_NUM_END_GET(*(msg_word + 1)); + action = + HTT_RX_FLUSH_MPDU_STATUS_GET(*(msg_word + 1)) == + 1 ? htt_rx_flush_release : htt_rx_flush_discard; + ol_rx_flush_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, action); + break; + } + case HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND: + { + uint16_t msdu_cnt; + + if (!pdev->cfg.is_high_latency && + pdev->cfg.is_full_reorder_offload) { + qdf_print("HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND not "); + qdf_print("supported when full reorder offload is "); + qdf_print("enabled in the configuration.\n"); + break; + } + msdu_cnt = + HTT_RX_OFFLOAD_DELIVER_IND_MSDU_CNT_GET(*msg_word); + ol_rx_offload_deliver_ind_handler(pdev->txrx_pdev, + htt_t2h_msg, + msdu_cnt); + if (pdev->cfg.is_high_latency) { + /* + * return here for HL to avoid double free on + * htt_t2h_msg + */ + return; + } + break; + } + case HTT_T2H_MSG_TYPE_RX_FRAG_IND: + { + uint16_t peer_id; + uint8_t tid; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_FRAG_IND_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + peer_id = HTT_RX_FRAG_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_FRAG_IND_EXT_TID_GET(*msg_word); + htt_rx_frag_set_last_msdu(pdev, htt_t2h_msg); + + /* If packet len is invalid, will discard this frame. */ + if (pdev->cfg.is_high_latency) { + u_int32_t rx_pkt_len = 0; + + rx_pkt_len = qdf_nbuf_len(htt_t2h_msg); + + if (rx_pkt_len < (HTT_RX_FRAG_IND_BYTES + + sizeof(struct hl_htt_rx_ind_base)+ + sizeof(struct ieee80211_frame))) { + + qdf_print("invalid packet len, %u", rx_pkt_len); + /* + * This buf will be freed before + * exiting this function. + */ + break; + } + } + + ol_rx_frag_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, + peer_id, tid); + + if (pdev->cfg.is_high_latency) { + /* + * For high latency solution, + * HTT_T2H_MSG_TYPE_RX_FRAG_IND message and RX packet + * share the same buffer. All buffer will be freed by + * ol_rx_frag_indication_handler or upper layer to + * avoid double free issue. + * + */ + return; + } + + break; + } + case HTT_T2H_MSG_TYPE_RX_ADDBA: + { + uint16_t peer_id; + uint8_t tid; + uint8_t win_sz; + uint16_t start_seq_num; + + /* + * FOR NOW, the host doesn't need to know the initial + * sequence number for rx aggregation. + * Thus, any value will do - specify 0. + */ + start_seq_num = 0; + peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word); + tid = HTT_RX_ADDBA_TID_GET(*msg_word); + win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word); + ol_rx_addba_handler(pdev->txrx_pdev, peer_id, tid, + win_sz, start_seq_num, + 0 /* success */); + break; + } + case HTT_T2H_MSG_TYPE_RX_DELBA: + { + uint16_t peer_id; + uint8_t tid; + + peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word); + tid = HTT_RX_DELBA_TID_GET(*msg_word); + ol_rx_delba_handler(pdev->txrx_pdev, peer_id, tid); + break; + } + case HTT_T2H_MSG_TYPE_PEER_MAP: + { + uint8_t mac_addr_deswizzle_buf[QDF_MAC_ADDR_SIZE]; + uint8_t *peer_mac_addr; + uint16_t peer_id; + uint8_t vdev_id; + + if (qdf_nbuf_len(htt_t2h_msg) < HTT_RX_PEER_MAP_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + peer_id = HTT_RX_PEER_MAP_PEER_ID_GET(*msg_word); + vdev_id = HTT_RX_PEER_MAP_VDEV_ID_GET(*msg_word); + peer_mac_addr = htt_t2h_mac_addr_deswizzle( + (uint8_t *) (msg_word + 1), + &mac_addr_deswizzle_buf[0]); + + if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { + qdf_print("%s: HTT_T2H_MSG_TYPE_PEER_MAP," + "invalid peer_id, %u\n", + __FUNCTION__, + peer_id); + break; + } + + ol_rx_peer_map_handler(pdev->txrx_pdev, peer_id, + vdev_id, peer_mac_addr, + 1 /*can tx */); + break; + } + case HTT_T2H_MSG_TYPE_PEER_UNMAP: + { + uint16_t peer_id; + + if (qdf_nbuf_len(htt_t2h_msg) < HTT_RX_PEER_UNMAP_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + peer_id = HTT_RX_PEER_UNMAP_PEER_ID_GET(*msg_word); + if (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) { + qdf_print("%s: HTT_T2H_MSG_TYPE_PEER_UNMAP," + "invalid peer_id, %u\n", + __FUNCTION__, + peer_id); + break; + } + + ol_rx_peer_unmap_handler(pdev->txrx_pdev, peer_id); + break; + } + case HTT_T2H_MSG_TYPE_SEC_IND: + { + uint16_t peer_id; + enum htt_sec_type sec_type; + int is_unicast; + + if (qdf_nbuf_len(htt_t2h_msg) < HTT_SEC_IND_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + peer_id = HTT_SEC_IND_PEER_ID_GET(*msg_word); + sec_type = HTT_SEC_IND_SEC_TYPE_GET(*msg_word); + is_unicast = HTT_SEC_IND_UNICAST_GET(*msg_word); + msg_word++; /* point to the first part of the Michael key */ + ol_rx_sec_ind_handler(pdev->txrx_pdev, peer_id, + sec_type, is_unicast, msg_word, + msg_word + 2); + break; + } + case HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND: + { + struct htt_mgmt_tx_compl_ind *compl_msg; + int32_t credit_delta = 1; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + if (msg_len < (sizeof(struct htt_mgmt_tx_compl_ind) + sizeof(*msg_word))) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Invalid msg_word length in HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND"); + WARN_ON(1); + break; + } + + compl_msg = + (struct htt_mgmt_tx_compl_ind *)(msg_word + 1); + + if (pdev->cfg.is_high_latency) { + if (!pdev->cfg.default_tx_comp_req) { + HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex); + qdf_atomic_add(credit_delta, + &pdev->htt_tx_credit. + target_delta); + credit_delta = htt_tx_credit_update(pdev); + HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex); + } + if (credit_delta) + ol_tx_target_credit_update( + pdev->txrx_pdev, credit_delta); + } + ol_tx_desc_update_group_credit( + pdev->txrx_pdev, compl_msg->desc_id, 1, + 0, compl_msg->status); + + DPTRACE(qdf_dp_trace_credit_record(QDF_TX_COMP, QDF_CREDIT_INC, + 1, qdf_atomic_read(&pdev->txrx_pdev->target_tx_credit), + qdf_atomic_read(&pdev->txrx_pdev->txq_grps[0].credit), + qdf_atomic_read(&pdev->txrx_pdev->txq_grps[1].credit))); + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) { + ol_tx_single_completion_handler(pdev->txrx_pdev, + compl_msg->status, + compl_msg->desc_id); + htc_pm_runtime_put(pdev->htc_pdev); + HTT_TX_SCHED(pdev); + } else { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "Ignoring HTT_T2H_MSG_TYPE_MGMT_TX_COMPL_IND indication"); + } + break; + } + case HTT_T2H_MSG_TYPE_STATS_CONF: + { + uint8_t cookie; + uint8_t *stats_info_list; + + cookie = *(msg_word + 1); + + stats_info_list = (uint8_t *) (msg_word + 3); + htc_pm_runtime_put(pdev->htc_pdev); + ol_txrx_fw_stats_handler(pdev->txrx_pdev, cookie, + stats_info_list); + break; + } +#ifndef REMOVE_PKT_LOG + case HTT_T2H_MSG_TYPE_PKTLOG: + { + uint32_t len = qdf_nbuf_len(htt_t2h_msg); + + if (len < sizeof(*msg_word) + sizeof(uint32_t)) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + /*len is reduced by sizeof(*msg_word)*/ + pktlog_process_fw_msg(OL_TXRX_PDEV_ID, msg_word + 1, + len - sizeof(*msg_word)); + break; + } +#endif + case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: + { + uint32_t htt_credit_delta_abs; + int32_t htt_credit_delta; + int sign, old_credit; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_TX_CREDIT_MSG_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + htt_credit_delta_abs = + HTT_TX_CREDIT_DELTA_ABS_GET(*msg_word); + sign = HTT_TX_CREDIT_SIGN_BIT_GET(*msg_word) ? -1 : 1; + htt_credit_delta = sign * htt_credit_delta_abs; + + old_credit = qdf_atomic_read(&pdev->htt_tx_credit.target_delta); + if (((old_credit + htt_credit_delta) > MAX_TARGET_TX_CREDIT) || + ((old_credit + htt_credit_delta) < -MAX_TARGET_TX_CREDIT)) { + qdf_err("invalid update,old_credit=%d, htt_credit_delta=%d", + old_credit, htt_credit_delta); + break; + } + htt_credit_delta = + htt_t2h_adjust_bus_target_delta(pdev, htt_credit_delta); + htt_tx_group_credit_process(pdev, msg_word); + DPTRACE(qdf_dp_trace_credit_record(QDF_TX_CREDIT_UPDATE, + QDF_CREDIT_INC, htt_credit_delta, + qdf_atomic_read(&pdev->txrx_pdev->target_tx_credit) + + htt_credit_delta, + qdf_atomic_read(&pdev->txrx_pdev->txq_grps[0].credit), + qdf_atomic_read(&pdev->txrx_pdev->txq_grps[1].credit))); + + ol_tx_credit_completion_handler(pdev->txrx_pdev, + htt_credit_delta); + break; + } + + case HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE: + { + uint16_t len; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + len = HTT_WDI_IPA_OP_RESPONSE_RSP_LEN_GET(*(msg_word + 1)); + + if (sizeof(struct htt_wdi_ipa_op_response_t) + len > msg_len) { + qdf_print("Invalid buf len size %zu len %d, msg_len %d", + sizeof(struct htt_wdi_ipa_op_response_t), + len, msg_len); + WARN_ON(1); + break; + } + htt_ipa_op_response(pdev, msg_word); + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP: + { + uint8_t num_flows; + struct htt_flow_pool_map_payload_t *pool_map_payoad; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word); + + if (((HTT_FLOW_POOL_MAP_PAYLOAD_SZ / + HTT_FLOW_POOL_MAP_HEADER_SZ) * num_flows + 1) * sizeof(*msg_word) > msg_len) { + qdf_print("Invalid num_flows"); + WARN_ON(1); + break; + } + + msg_word++; + while (num_flows) { + pool_map_payoad = (struct htt_flow_pool_map_payload_t *) + msg_word; + ol_tx_flow_pool_map_handler(pool_map_payoad->flow_id, + pool_map_payoad->flow_type, + pool_map_payoad->flow_pool_id, + pool_map_payoad->flow_pool_size); + + msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ / + HTT_FLOW_POOL_MAP_HEADER_SZ); + num_flows--; + } + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP: + { + struct htt_flow_pool_unmap_t *pool_numap_payload; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < sizeof(struct htt_flow_pool_unmap_t)) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Invalid msg_word length in HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP"); + WARN_ON(1); + break; + } + + pool_numap_payload = (struct htt_flow_pool_unmap_t *)msg_word; + ol_tx_flow_pool_unmap_handler(pool_numap_payload->flow_id, + pool_numap_payload->flow_type, + pool_numap_payload->flow_pool_id); + break; + } + + case HTT_T2H_MSG_TYPE_FLOW_POOL_RESIZE: + { + struct htt_flow_pool_resize_t *msg; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < sizeof(struct htt_flow_pool_resize_t)) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_ERROR, + "Invalid msg_word length in HTT_T2H_MSG_TYPE_FLOW_POOL_RESIZE"); + WARN_ON(1); + break; + } + + msg = (struct htt_flow_pool_resize_t *)msg_word; + ol_tx_flow_pool_resize_handler(msg->flow_pool_id, + msg->flow_pool_new_size); + + break; + } + + case HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR: + { + switch (HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word)) { + case HTT_RX_OFLD_PKT_ERR_TYPE_MIC_ERR: + { + struct ol_txrx_vdev_t *vdev; + struct ol_txrx_peer_t *peer; + uint64_t pn; + uint32_t key_id; + uint16_t peer_id; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_OFLD_PKT_ERR_MIC_ERR_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + peer_id = HTT_RX_OFLD_PKT_ERR_MIC_ERR_PEER_ID_GET + (*(msg_word + 1)); + + peer = ol_txrx_peer_find_by_id(pdev->txrx_pdev, + peer_id); + if (!peer) { + qdf_print("invalid peer id %d", peer_id); + qdf_assert(0); + break; + } + vdev = peer->vdev; + key_id = HTT_RX_OFLD_PKT_ERR_MIC_ERR_KEYID_GET + (*(msg_word + 1)); + qdf_mem_copy(&pn, (uint8_t *)(msg_word + 6), 6); + + ol_rx_send_mic_err_ind(vdev->pdev, vdev->vdev_id, + peer->mac_addr.raw, 0, 0, + OL_RX_ERR_TKIP_MIC, htt_t2h_msg, + &pn, key_id); + break; + } + default: + { + qdf_print("unhandled error type %d", + HTT_RX_OFLD_PKT_ERR_MSG_SUB_TYPE_GET(*msg_word)); + break; + } + } + break; + } +#ifdef WLAN_CFR_ENABLE + case HTT_T2H_MSG_TYPE_CFR_DUMP_COMPL_IND: + { + int expected_len; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + expected_len = HTT_CFR_DUMP_COMPL_HEAD_SZ + + sizeof(struct htt_cfr_dump_compl_ind); + if (msg_len < expected_len) { + qdf_print("Invalid length of CFR capture event"); + break; + } + + ol_rx_cfr_capture_msg_handler(htt_t2h_msg); + break; + } +#endif + default: + break; + }; + /* Free the indication buffer */ + if (free_msg_buf) + qdf_nbuf_free(htt_t2h_msg); +} + +#define HTT_TX_COMPL_HEAD_SZ 4 +#define HTT_TX_COMPL_BYTES_PER_MSDU_ID 2 + +/* + * Generic Target to host Msg/event handler for low priority messages + * Low priority message are handler in a different handler called from + * this function . So that the most likely success path like Rx and + * Tx comp has little code foot print + */ +void htt_t2h_msg_handler(void *context, HTC_PACKET *pkt) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + qdf_nbuf_t htt_t2h_msg = (qdf_nbuf_t) pkt->pPktContext; + uint32_t *msg_word; + enum htt_t2h_msg_type msg_type; + + /* check for successful message reception */ + if (pkt->Status != QDF_STATUS_SUCCESS) { + if (pkt->Status != QDF_STATUS_E_CANCELED) + pdev->stats.htc_err_cnt++; + qdf_nbuf_free(htt_t2h_msg); + return; + } +#ifdef HTT_RX_RESTORE + if (qdf_unlikely(pdev->rx_ring.rx_reset)) { + qdf_print("rx restore ..\n"); + qdf_nbuf_free(htt_t2h_msg); + return; + } +#endif + + /* confirm alignment */ + HTT_ASSERT3((((unsigned long)qdf_nbuf_data(htt_t2h_msg)) & 0x3) == 0); + + msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + +#if defined(HELIUMPLUS_DEBUG) + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s %d: msg_word 0x%x msg_type %d", __func__, __LINE__, + *msg_word, msg_type); +#endif + + switch (msg_type) { + case HTT_T2H_MSG_TYPE_RX_IND: + { + unsigned int num_mpdu_ranges; + unsigned int num_msdu_bytes; + unsigned int calculated_msg_len; + unsigned int rx_mpdu_range_offset_bytes; + uint16_t peer_id; + uint8_t tid; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (qdf_unlikely(pdev->cfg.is_full_reorder_offload)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND not supported "); + qdf_print("with full reorder offload\n"); + break; + } + peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IND_EXT_TID_GET(*msg_word); + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid tid %d\n", + tid); + break; + } + if (msg_len < (2 + HTT_RX_PPDU_DESC_SIZE32 + 1) * sizeof(uint32_t)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid msg_len\n"); + break; + } + num_msdu_bytes = + HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + 2 + HTT_RX_PPDU_DESC_SIZE32)); + /* + * 1 word for the message header, + * HTT_RX_PPDU_DESC_SIZE32 words for the FW rx PPDU desc + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + rx_mpdu_range_offset_bytes = + (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3); + if (qdf_unlikely(num_msdu_bytes > + rx_mpdu_range_offset_bytes)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %u\n", + "num_msdu_bytes", + num_msdu_bytes); + WARN_ON(1); + break; + } + pdev->rx_mpdu_range_offset_words = + rx_mpdu_range_offset_bytes >> 2; + num_mpdu_ranges = + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + 1)); + pdev->rx_ind_msdu_byte_idx = 0; + if (qdf_unlikely(rx_mpdu_range_offset_bytes > + msg_len)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %d\n", + "rx_mpdu_range_offset_words", + pdev->rx_mpdu_range_offset_words); + WARN_ON(1); + break; + } + calculated_msg_len = rx_mpdu_range_offset_bytes + + (num_mpdu_ranges * (int)sizeof(uint32_t)); + /* + * Check that the addition and multiplication + * do not cause integer overflow + */ + if (qdf_unlikely(calculated_msg_len < + rx_mpdu_range_offset_bytes)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %u\n", + "num_mpdu_ranges", + (num_mpdu_ranges * (int)sizeof(uint32_t))); + WARN_ON(1); + break; + } + if (qdf_unlikely(calculated_msg_len > msg_len)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid %s %u\n", + "offset_words + mpdu_ranges", + calculated_msg_len); + WARN_ON(1); + break; + } + ol_rx_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, peer_id, + tid, num_mpdu_ranges); + + if (pdev->cfg.is_high_latency) + return; + + break; + } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + { + int old_credit; + int num_msdus; + enum htt_tx_status status; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + /* status - no enum translation needed */ + status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + qdf_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different from FW CPU. + * This can result in even and odd MSDU IDs being + * switched. If this happens, copy the switched final + * odd MSDU ID from location payload[size], to + * location payload[size-1], where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + + if (pdev->cfg.is_high_latency && + !pdev->cfg.credit_update_enabled) { + old_credit = qdf_atomic_read( + &pdev->htt_tx_credit.target_delta); + if (((old_credit + num_msdus) > MAX_TARGET_TX_CREDIT) || + ((old_credit + num_msdus) < -MAX_TARGET_TX_CREDIT)) { + qdf_err("invalid update,old_credit=%d, num_msdus=%d", + old_credit, num_msdus); + } else { + if (!pdev->cfg.default_tx_comp_req) { + int credit_delta; + + HTT_TX_MUTEX_ACQUIRE(&pdev->credit_mutex); + qdf_atomic_add(num_msdus, + &pdev->htt_tx_credit. + target_delta); + credit_delta = htt_tx_credit_update(pdev); + HTT_TX_MUTEX_RELEASE(&pdev->credit_mutex); + + if (credit_delta) { + ol_tx_target_credit_update( + pdev->txrx_pdev, + credit_delta); + } + } else { + ol_tx_target_credit_update(pdev->txrx_pdev, + num_msdus); + } + } + } + + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, + status, msg_word); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_PN_IND: + { + uint16_t peer_id; + uint8_t tid, pn_ie_cnt, *pn_ie = NULL; + uint16_t seq_num_start, seq_num_end; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_PN_IND_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + /*First dword */ + peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word); + + msg_word++; + /*Second dword */ + seq_num_start = + HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word); + seq_num_end = HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); + pn_ie_cnt = HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + + if (msg_len - HTT_RX_PN_IND_BYTES < + pn_ie_cnt * sizeof(uint8_t)) { + qdf_print("invalid pn_ie count"); + WARN_ON(1); + break; + } + + msg_word++; + /*Third dword */ + if (pn_ie_cnt) + pn_ie = (uint8_t *) msg_word; + + ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, + pn_ie_cnt, pn_ie); + + break; + } + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + { + int num_msdus; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + qdf_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different from FW CPU. + * This can result in even and odd MSDU IDs being + * switched. If this happens, copy the switched final + * odd MSDU ID from location payload[size], to + * location payload[size-1], where the message handler + * function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_inspect_handler(pdev->txrx_pdev, num_msdus, + msg_word + 1); + HTT_TX_SCHED(pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: + { + uint16_t peer_id; + uint8_t tid; + uint8_t offload_ind, frag_ind; + + if (qdf_unlikely(!pdev->cfg.is_full_reorder_offload)) { + qdf_print("full reorder offload is disable"); + break; + } + + if (qdf_unlikely(pdev->cfg.is_high_latency)) { + qdf_print("full reorder offload not support in HL"); + break; + } + + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET(*msg_word); + offload_ind = HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET(*msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET(*msg_word); + +#if defined(HELIUMPLUS_DEBUG) + qdf_print("peerid %d tid %d offloadind %d fragind %d", + peer_id, tid, offload_ind, + frag_ind); +#endif + if (qdf_unlikely(frag_ind)) { + ol_rx_frag_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, + peer_id, tid); + break; + } + + ol_rx_in_order_indication_handler(pdev->txrx_pdev, + htt_t2h_msg, peer_id, + tid, offload_ind); + break; + } + + default: + htt_t2h_lp_msg_handler(context, htt_t2h_msg, true); + return; + + }; + + /* Free the indication buffer */ + qdf_nbuf_free(htt_t2h_msg); +} + +#ifdef WLAN_FEATURE_FASTPATH +#define HTT_T2H_MSG_BUF_REINIT(_buf, dev) \ + do { \ + qdf_nbuf_push_head(_buf, (HTC_HEADER_LEN) + \ + HTC_HDR_ALIGNMENT_PADDING); \ + qdf_nbuf_init_fast((_buf)); \ + qdf_mem_dma_sync_single_for_device(dev, \ + (QDF_NBUF_CB_PADDR(_buf)), \ + (skb_end_pointer(_buf) - \ + (_buf)->data), \ + DMA_FROM_DEVICE); \ + } while (0) + +/** + * htt_t2h_msg_handler_fast() - Fastpath specific message handler + * @context: HTT context + * @cmpl_msdus: netbuf completions + * @num_cmpls: number of completions to be handled + * + * Return: None + */ +void htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus, + uint32_t num_cmpls) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *)context; + qdf_nbuf_t htt_t2h_msg; + uint32_t *msg_word; + uint32_t i; + enum htt_t2h_msg_type msg_type; + uint32_t msg_len; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + + for (i = 0; i < num_cmpls; i++) { + htt_t2h_msg = cmpl_msdus[i]; + msg_len = qdf_nbuf_len(htt_t2h_msg); + + /* + * Move the data pointer to point to HTT header + * past the HTC header + HTC header alignment padding + */ + qdf_nbuf_pull_head(htt_t2h_msg, HTC_HEADER_LEN + + HTC_HDR_ALIGNMENT_PADDING); + + /* confirm alignment */ + HTT_ASSERT3((((unsigned long) qdf_nbuf_data(htt_t2h_msg)) & 0x3) + == 0); + + msg_word = (u_int32_t *) qdf_nbuf_data(htt_t2h_msg); + msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word); + + switch (msg_type) { + case HTT_T2H_MSG_TYPE_RX_IND: + { + unsigned int num_mpdu_ranges; + unsigned int num_msdu_bytes; + unsigned int calculated_msg_len; + unsigned int rx_mpdu_range_offset_bytes; + u_int16_t peer_id; + u_int8_t tid; + msg_len = qdf_nbuf_len(htt_t2h_msg); + + peer_id = HTT_RX_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_IND_EXT_TID_GET(*msg_word); + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, invalid tid %d\n", + tid); + WARN_ON(1); + break; + } + num_msdu_bytes = + HTT_RX_IND_FW_RX_DESC_BYTES_GET( + *(msg_word + 2 + + HTT_RX_PPDU_DESC_SIZE32)); + /* + * 1 word for the message header, + * HTT_RX_PPDU_DESC_SIZE32 words for the FW + * rx PPDU desc. + * 1 word to specify the number of MSDU bytes, + * 1 word for every 4 MSDU bytes (round up), + * 1 word for the MPDU range header + */ + rx_mpdu_range_offset_bytes = + (HTT_RX_IND_HDR_BYTES + num_msdu_bytes + 3); + if (qdf_unlikely(num_msdu_bytes > + rx_mpdu_range_offset_bytes)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %u\n", + "invalid num_msdu_bytes", + num_msdu_bytes); + WARN_ON(1); + break; + } + pdev->rx_mpdu_range_offset_words = + rx_mpdu_range_offset_bytes >> 2; + num_mpdu_ranges = + HTT_RX_IND_NUM_MPDU_RANGES_GET(*(msg_word + + 1)); + pdev->rx_ind_msdu_byte_idx = 0; + if (qdf_unlikely(rx_mpdu_range_offset_bytes > + msg_len)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %d\n", + "invalid rx_mpdu_range_offset_words", + pdev->rx_mpdu_range_offset_words); + WARN_ON(1); + break; + } + calculated_msg_len = rx_mpdu_range_offset_bytes + + (num_mpdu_ranges * + (int)sizeof(uint32_t)); + /* + * Check that the addition and multiplication + * do not cause integer overflow + */ + if (qdf_unlikely(calculated_msg_len < + rx_mpdu_range_offset_bytes)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %u\n", + "invalid num_mpdu_ranges", + (num_mpdu_ranges * + (int)sizeof(uint32_t))); + WARN_ON(1); + break; + } + if (qdf_unlikely(calculated_msg_len > msg_len)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IND, %s %u\n", + "invalid offset_words + mpdu_ranges", + calculated_msg_len); + WARN_ON(1); + break; + } + ol_rx_indication_handler(pdev->txrx_pdev, htt_t2h_msg, + peer_id, tid, num_mpdu_ranges); + break; + } + case HTT_T2H_MSG_TYPE_TX_COMPL_IND: + { + int num_msdus; + enum htt_tx_status status; + + /* status - no enum translation needed */ + status = HTT_TX_COMPL_IND_STATUS_GET(*msg_word); + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + qdf_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different + * from FW CPU. This can result in even + * and odd MSDU IDs being switched. If + * this happens, copy the switched final + * odd MSDU ID from location + * payload[size], to location + * payload[size-1],where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_completion_handler(pdev->txrx_pdev, num_msdus, + status, msg_word); + + break; + } + case HTT_T2H_MSG_TYPE_TX_OFFLOAD_DELIVER_IND: + { + struct htt_tx_offload_deliver_ind_hdr_t + *offload_deliver_msg; + uint8_t vdev_id; + struct ol_txrx_vdev_t *vdev; + bool is_pkt_during_roam = false; + struct ol_txrx_pdev_t *txrx_pdev = pdev->txrx_pdev; + struct ol_txrx_peer_t *peer; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint32_t freq = 0; + + if (!(ucfg_pkt_capture_get_pktcap_mode((void *)soc->psoc) & + PKT_CAPTURE_MODE_DATA_ONLY)) + break; + + offload_deliver_msg = + (struct htt_tx_offload_deliver_ind_hdr_t *)msg_word; + is_pkt_during_roam = + (offload_deliver_msg->reserved_2 ? true : false); + + if (qdf_unlikely( + !pdev->cfg.is_full_reorder_offload)) { + break; + } + + /* Is FW sends offload data during roaming */ + if (is_pkt_during_roam) { + vdev_id = HTT_INVALID_VDEV; + freq = + (uint32_t)offload_deliver_msg->reserved_3; + htt_rx_mon_note_capture_channel( + pdev, cds_freq_to_chan(freq)); + } else { + vdev_id = offload_deliver_msg->vdev_id; + vdev = (struct ol_txrx_vdev_t *) + ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (vdev) { + qdf_spin_lock_bh( + &txrx_pdev->peer_ref_mutex); + peer = TAILQ_FIRST(&vdev->peer_list); + qdf_spin_unlock_bh( + &txrx_pdev->peer_ref_mutex); + if (peer) { + qdf_spin_lock_bh( + &peer->peer_info_lock); + qdf_mem_copy( + bssid, + &peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh( + &peer->peer_info_lock); + } else { + break; + } + } else { + break; + } + } + ucfg_pkt_capture_offload_deliver_indication_handler( + msg_word, + vdev_id, bssid, pdev); + break; + } + case HTT_T2H_MSG_TYPE_RX_PN_IND: + { + u_int16_t peer_id; + u_int8_t tid, pn_ie_cnt, *pn_ie = NULL; + int seq_num_start, seq_num_end; + int msg_len = qdf_nbuf_len(htt_t2h_msg); + + if (msg_len < HTT_RX_PN_IND_BYTES) { + qdf_print("invalid nbuff len"); + WARN_ON(1); + break; + } + + /*First dword */ + peer_id = HTT_RX_PN_IND_PEER_ID_GET(*msg_word); + tid = HTT_RX_PN_IND_EXT_TID_GET(*msg_word); + + msg_word++; + /*Second dword */ + seq_num_start = + HTT_RX_PN_IND_SEQ_NUM_START_GET(*msg_word); + seq_num_end = + HTT_RX_PN_IND_SEQ_NUM_END_GET(*msg_word); + pn_ie_cnt = + HTT_RX_PN_IND_PN_IE_CNT_GET(*msg_word); + + if (msg_len - HTT_RX_PN_IND_BYTES < + pn_ie_cnt * sizeof(uint8_t)) { + qdf_print("invalid pn_ie len"); + WARN_ON(1); + break; + } + + msg_word++; + /*Third dword*/ + if (pn_ie_cnt) + pn_ie = (u_int8_t *)msg_word; + + ol_rx_pn_ind_handler(pdev->txrx_pdev, peer_id, tid, + seq_num_start, seq_num_end, pn_ie_cnt, pn_ie); + + break; + } + case HTT_T2H_MSG_TYPE_TX_INSPECT_IND: + { + int num_msdus; + + num_msdus = HTT_TX_COMPL_IND_NUM_GET(*msg_word); + /* + * each desc id will occupy 2 bytes. + * the 4 is for htt msg header + */ + if ((num_msdus * HTT_TX_COMPL_BYTES_PER_MSDU_ID + + HTT_TX_COMPL_HEAD_SZ) > msg_len) { + qdf_print("%s: num_msdus(%d) is invalid," + "adf_nbuf_len = %d\n", + __FUNCTION__, + num_msdus, + msg_len); + break; + } + + if (num_msdus & 0x1) { + struct htt_tx_compl_ind_base *compl = + (void *)msg_word; + + /* + * Host CPU endianness can be different + * from FW CPU. This * can result in + * even and odd MSDU IDs being switched. + * If this happens, copy the switched + * final odd MSDU ID from location + * payload[size], to location + * payload[size-1], where the message + * handler function expects to find it + */ + if (compl->payload[num_msdus] != + HTT_TX_COMPL_INV_MSDU_ID) { + compl->payload[num_msdus - 1] = + compl->payload[num_msdus]; + } + } + ol_tx_inspect_handler(pdev->txrx_pdev, + num_msdus, msg_word + 1); + break; + } + case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: + { + u_int16_t peer_id; + u_int8_t tid; + u_int8_t offload_ind, frag_ind; + + if (qdf_unlikely( + !pdev->cfg.is_full_reorder_offload)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported when full reorder offload is disabled\n"); + break; + } + + if (qdf_unlikely( + pdev->txrx_pdev->cfg.is_high_latency)) { + qdf_print("HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND not supported on high latency\n"); + break; + } + + peer_id = HTT_RX_IN_ORD_PADDR_IND_PEER_ID_GET( + *msg_word); + tid = HTT_RX_IN_ORD_PADDR_IND_EXT_TID_GET( + *msg_word); + offload_ind = + HTT_RX_IN_ORD_PADDR_IND_OFFLOAD_GET( + *msg_word); + frag_ind = HTT_RX_IN_ORD_PADDR_IND_FRAG_GET( + *msg_word); + + if (qdf_unlikely(frag_ind)) { + ol_rx_frag_indication_handler( + pdev->txrx_pdev, htt_t2h_msg, peer_id, + tid); + break; + } + + ol_rx_in_order_indication_handler( + pdev->txrx_pdev, htt_t2h_msg, + peer_id, tid, offload_ind); + break; + } + default: + htt_t2h_lp_msg_handler(context, htt_t2h_msg, false); + break; + }; + + /* Re-initialize the indication buffer */ + HTT_T2H_MSG_BUF_REINIT(htt_t2h_msg, pdev->osdev); + qdf_nbuf_set_pktlen(htt_t2h_msg, 0); + } +} +#endif /* WLAN_FEATURE_FASTPATH */ + +/*--- target->host HTT message Info Element access methods ------------------*/ + +/*--- tx completion message ---*/ + +uint16_t htt_tx_compl_desc_id(void *iterator, int num) +{ + /* + * The MSDU IDs are packed , 2 per 32-bit word. + * Iterate on them as an array of 16-bit elements. + * This will work fine if the host endianness matches + * the target endianness. + * If the host endianness is opposite of the target's, + * this iterator will produce descriptor IDs in a different + * order than the target inserted them into the message - + * if the target puts in [0, 1, 2, 3, ...] the host will + * put out [1, 0, 3, 2, ...]. + * This is fine, except for the last ID if there are an + * odd number of IDs. But the TX_COMPL_IND handling code + * in the htt_t2h_msg_handler already added a duplicate + * of the final ID, if there were an odd number of IDs, + * so this function can safely treat the IDs as an array + * of 16-bit elements. + */ + return *(((uint16_t *) iterator) + num); +} + +/*--- rx indication message ---*/ + +int htt_rx_ind_flush(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + return HTT_RX_IND_FLUSH_VALID_GET(*msg_word); +} + +void +htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned int *seq_num_start, + unsigned int *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_IND_FLUSH_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_IND_FLUSH_SEQ_NUM_END_GET(*msg_word); +} + +int htt_rx_ind_release(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + return HTT_RX_IND_REL_VALID_GET(*msg_word); +} + +void +htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned int *seq_num_start, + unsigned int *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_IND_REL_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_IND_REL_SEQ_NUM_END_GET(*msg_word); +} + +void +htt_rx_ind_mpdu_range_info(struct htt_pdev_t *pdev, + qdf_nbuf_t rx_ind_msg, + int mpdu_range_num, + enum htt_rx_status *status, int *mpdu_count) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_ind_msg); + msg_word += pdev->rx_mpdu_range_offset_words + mpdu_range_num; + *status = HTT_RX_IND_MPDU_STATUS_GET(*msg_word); + *mpdu_count = HTT_RX_IND_MPDU_COUNT_GET(*msg_word); +} + +/** + * htt_rx_ind_rssi_dbm() - Return the RSSI provided in a rx indication message. + * + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the RSSI from an rx indication message, in dBm units. + * + * Return: RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + int8_t rssi; + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) + return HTT_RSSI_INVALID; + + rssi = HTT_RX_IND_RSSI_CMB_GET(*msg_word); + return (HTT_TGT_RSSI_INVALID == rssi) ? + HTT_RSSI_INVALID : rssi; +} + +/** + * htt_rx_ind_rssi_dbm_chain() - Return the RSSI for a chain provided in a rx + * indication message. + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @chain: the index of the chain (0-4) + * + * Return the RSSI for a chain from an rx indication message, in dBm units. + * + * Return: RSSI, or HTT_INVALID_RSSI + */ +int16_t +htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + int8_t chain) +{ + int8_t rssi; + uint32_t *msg_word; + + if (chain < 0 || chain > 3) + return HTT_RSSI_INVALID; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) + return HTT_RSSI_INVALID; + + msg_word += 1 + chain; + + rssi = HTT_RX_IND_RSSI_PRI20_GET(*msg_word); + return (HTT_TGT_RSSI_INVALID == rssi) ? + HTT_RSSI_INVALID : + rssi; +} + +/** + * htt_rx_ind_legacy_rate() - Return the data rate + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @legacy_rate: (output) the data rate + * The legacy_rate parameter's value depends on the + * legacy_rate_sel value. + * If legacy_rate_sel is 0: + * 0x8: OFDM 48 Mbps + * 0x9: OFDM 24 Mbps + * 0xA: OFDM 12 Mbps + * 0xB: OFDM 6 Mbps + * 0xC: OFDM 54 Mbps + * 0xD: OFDM 36 Mbps + * 0xE: OFDM 18 Mbps + * 0xF: OFDM 9 Mbps + * If legacy_rate_sel is 1: + * 0x8: CCK 11 Mbps long preamble + * 0x9: CCK 5.5 Mbps long preamble + * 0xA: CCK 2 Mbps long preamble + * 0xB: CCK 1 Mbps long preamble + * 0xC: CCK 11 Mbps short preamble + * 0xD: CCK 5.5 Mbps short preamble + * 0xE: CCK 2 Mbps short preamble + * -1 on error. + * @legacy_rate_sel: (output) 0 to indicate OFDM, 1 to indicate CCK. + * -1 on error. + * + * Return the data rate provided in a rx indication message. + */ +void +htt_rx_ind_legacy_rate(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint8_t *legacy_rate, uint8_t *legacy_rate_sel) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_START_VALID_GET(*msg_word)) { + *legacy_rate = -1; + *legacy_rate_sel = -1; + return; + } + + *legacy_rate = HTT_RX_IND_LEGACY_RATE_GET(*msg_word); + *legacy_rate_sel = HTT_RX_IND_LEGACY_RATE_SEL_GET(*msg_word); +} + +/** + * htt_rx_ind_timestamp() - Return the timestamp + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * @timestamp_microsec: (output) the timestamp to microsecond resolution. + * -1 on error. + * @timestamp_submicrosec: the submicrosecond portion of the + * timestamp. -1 on error. + * + * Return the timestamp provided in a rx indication message. + */ +void +htt_rx_ind_timestamp(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint32_t *timestamp_microsec, + uint8_t *timestamp_submicrosec) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_END_VALID_GET(*msg_word)) { + *timestamp_microsec = -1; + *timestamp_submicrosec = -1; + return; + } + + *timestamp_microsec = *(msg_word + 6); + *timestamp_submicrosec = + HTT_RX_IND_TIMESTAMP_SUBMICROSEC_GET(*msg_word); +} + +#define INVALID_TSF -1 +/** + * htt_rx_ind_tsf32() - Return the TSF timestamp + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the TSF timestamp provided in a rx indication message. + * + * Return: TSF timestamp + */ +uint32_t +htt_rx_ind_tsf32(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg) + + HTT_RX_IND_FW_RX_PPDU_DESC_BYTE_OFFSET); + + /* check if the RX_IND message contains valid rx PPDU start info */ + if (!HTT_RX_IND_END_VALID_GET(*msg_word)) + return INVALID_TSF; + + return *(msg_word + 5); +} + +/** + * htt_rx_ind_ext_tid() - Return the extended traffic ID provided in a rx + * indication message. + * @pdev: the HTT instance the rx data was received on + * @rx_ind_msg: the netbuf containing the rx indication message + * + * Return the extended traffic ID in a rx indication message. + * + * Return: Extended TID + */ +uint8_t +htt_rx_ind_ext_tid(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) + (qdf_nbuf_data(rx_ind_msg)); + + return HTT_RX_IND_EXT_TID_GET(*msg_word); +} + +/*--- stats confirmation message ---*/ + +void +htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list, + enum htt_dbg_stats_type *type, + enum htt_dbg_stats_status *status, + int *length, uint8_t **stats_data) +{ + uint32_t *msg_word = (uint32_t *) stats_info_list; + *type = HTT_T2H_STATS_CONF_TLV_TYPE_GET(*msg_word); + *status = HTT_T2H_STATS_CONF_TLV_STATUS_GET(*msg_word); + *length = HTT_T2H_STATS_CONF_TLV_HDR_SIZE + /* header length */ + HTT_T2H_STATS_CONF_TLV_LENGTH_GET(*msg_word); /* data len */ + *stats_data = stats_info_list + HTT_T2H_STATS_CONF_TLV_HDR_SIZE; +} + +void +htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + uint16_t *seq_num_start, uint16_t *seq_num_end) +{ + uint32_t *msg_word; + + msg_word = (uint32_t *) qdf_nbuf_data(rx_frag_ind_msg); + msg_word++; + *seq_num_start = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_START_GET(*msg_word); + *seq_num_end = HTT_RX_FRAG_IND_FLUSH_SEQ_NUM_END_GET(*msg_word); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_tx.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_tx.c new file mode 100644 index 0000000000..27f564a9ab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_tx.c @@ -0,0 +1,1914 @@ +/* + * Copyright (c) 2011, 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file htt_tx.c + * @brief Implement transmit aspects of HTT. + * @details + * This file contains three categories of HTT tx code: + * 1. An abstraction of the tx descriptor, to hide the + * differences between the HL vs. LL tx descriptor. + * 2. Functions for allocating and freeing HTT tx descriptors. + * 3. The function that accepts a tx frame from txrx and sends the + * tx frame to HTC. + */ +#include /* uint32_t, offsetof, etc. */ +#include /* qdf_dma_addr_t */ +#include /* qdf_mem_alloc_consistent et al */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_mdelay */ + +#include /* htt_tx_msdu_desc_t */ +#include /* HTC_HDR_LENGTH */ +#include /* htc_flush_surprise_remove */ +#include /* ol_cfg_netbuf_frags_max, etc. */ +#include /* HTT_TX_DESC_VADDR_OFFSET */ +#include /* ol_tx_msdu_id_storage */ +#include +#include + +#include +#include +#include + +/* IPA Micro controller TX data packet HTT Header Preset + * 31 | 30 29 | 28 | 27 | 26 22 | 21 16 | 15 13 | 12 8 | 7 0 + ***---------------------------------------------------------------------------- + * R | CS OL | R | PP | ext TID | vdev ID | pkt type | pkt subtyp | msg type + * 0 | 0 | 0 | | 0x1F | 0 | 2 | 0 | 0x01 + ***---------------------------------------------------------------------------- + * pkt ID | pkt length + ***---------------------------------------------------------------------------- + * frag_desc_ptr + ***---------------------------------------------------------------------------- + * peer_id + ***---------------------------------------------------------------------------- + */ +#define HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT 0x07C04001 + +#ifdef QCA_WIFI_3_0 +#define IPA_UC_TX_BUF_FRAG_DESC_OFFSET 20 +#define IPA_UC_TX_BUF_FRAG_HDR_OFFSET 64 +#define IPA_UC_TX_BUF_TSO_HDR_SIZE 6 +#define IPA_UC_TX_BUF_PADDR_HI_MASK 0x0000001F +#else +#define IPA_UC_TX_BUF_FRAG_DESC_OFFSET 16 +#define IPA_UC_TX_BUF_FRAG_HDR_OFFSET 32 +#endif /* QCA_WIFI_3_0 */ + +#if HTT_PADDR64 +#define HTT_TX_DESC_FRAG_FIELD_UPDATE(frag_filed_ptr, frag_desc_addr) \ +do { \ + *frag_filed_ptr = qdf_get_lower_32_bits(frag_desc_addr); \ + frag_filed_ptr++; \ + /* frags_desc_ptr.hi */ \ + *frag_filed_ptr = qdf_get_upper_32_bits(frag_desc_addr) & 0x1F; \ +} while (0) +#else +#define HTT_TX_DESC_FRAG_FIELD_UPDATE(frag_filed_ptr, frag_desc_addr) \ +do { \ + *frag_filed_ptr = qdf_get_lower_32_bits(frag_desc_addr); \ +} while (0) +#endif + +/*--- setup / tear-down functions -------------------------------------------*/ + +static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr); + +#ifdef HELIUMPLUS +/** + * htt_tx_desc_get_size() - get tx descripotrs size + * @pdev: htt device instance pointer + * + * This function will get HTT TX descriptor size and fragment descriptor size + * + * Return: None + */ +static void htt_tx_desc_get_size(struct htt_pdev_t *pdev) +{ + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); + if (HTT_WIFI_IP_VERSION(pdev->wifi_ip_ver.major, 0x2)) { + /* + * sizeof MSDU_EXT/Fragmentation descriptor. + */ + pdev->frag_descs.size = sizeof(struct msdu_ext_desc_t); + } else { + /* + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->frag_descs.size = + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev)+1) * 8 + + 4; + } +} + +/** + * htt_tx_frag_desc_field_update() - Update fragment descriptor field + * @pdev: htt device instance pointer + * @fptr: Fragment descriptor field pointer + * @index: Descriptor index to find page and offset + * @desc_v_ptr: descriptor virtual pointot to find offset + * + * This function will update fragment descriptor field with actual fragment + * descriptor stating physical pointer + * + * Return: None + */ +static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, + uint32_t *fptr, unsigned int index, + struct htt_tx_msdu_desc_t *desc_v_ptr) +{ + unsigned int target_page; + unsigned int offset; + struct qdf_mem_dma_page_t *dma_page; + qdf_dma_addr_t frag_desc_addr; + + target_page = index / pdev->frag_descs.desc_pages.num_element_per_page; + offset = index % pdev->frag_descs.desc_pages.num_element_per_page; + dma_page = &pdev->frag_descs.desc_pages.dma_pages[target_page]; + frag_desc_addr = (dma_page->page_p_addr + + offset * pdev->frag_descs.size); + HTT_TX_DESC_FRAG_FIELD_UPDATE(fptr, frag_desc_addr); +} + +/** + * htt_tx_frag_desc_attach() - Attach fragment descriptor + * @pdev: htt device instance pointer + * @desc_pool_elems: Number of fragment descriptor + * + * This function will allocate fragment descriptor + * + * Return: 0 success + */ +static int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, + uint16_t desc_pool_elems) +{ + pdev->frag_descs.pool_elems = desc_pool_elems; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->frag_descs.desc_pages, + pdev->frag_descs.size, desc_pool_elems, + qdf_get_dma_mem_context((&pdev->frag_descs), memctx), false); + if ((0 == pdev->frag_descs.desc_pages.num_pages) || + (!pdev->frag_descs.desc_pages.dma_pages)) { + ol_txrx_err("FRAG descriptor alloc fail"); + return -ENOBUFS; + } + return 0; +} + +/** + * htt_tx_frag_desc_detach() - Detach fragment descriptor + * @pdev: htt device instance pointer + * + * This function will free fragment descriptor + * + * Return: None + */ +static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) +{ + qdf_mem_multi_pages_free(pdev->osdev, &pdev->frag_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->frag_descs), memctx), false); +} + +/** + * htt_tx_frag_alloc() - Allocate single fragment descriptor from the pool + * @pdev: htt device instance pointer + * @index: Descriptor index + * @frag_paddr: Fragment descriptor physical address + * @frag_ptr: Fragment descriptor virtual address + * + * This function will free fragment descriptor + * + * Return: None + */ +int htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr) +{ + uint16_t frag_page_index; + uint16_t frag_elem_index; + struct qdf_mem_dma_page_t *dma_page; + + /* + * Index should never be 0, since its used by the hardware + * to terminate the link. + */ + if (index >= pdev->tx_descs.pool_elems) { + *frag_ptr = NULL; + return 1; + } + + frag_page_index = index / + pdev->frag_descs.desc_pages.num_element_per_page; + frag_elem_index = index % + pdev->frag_descs.desc_pages.num_element_per_page; + dma_page = &pdev->frag_descs.desc_pages.dma_pages[frag_page_index]; + + *frag_ptr = dma_page->page_v_addr_start + + frag_elem_index * pdev->frag_descs.size; + if (((char *)(*frag_ptr) < dma_page->page_v_addr_start) || + ((char *)(*frag_ptr) > dma_page->page_v_addr_end)) { + *frag_ptr = NULL; + return 1; + } + + *frag_paddr = dma_page->page_p_addr + + frag_elem_index * pdev->frag_descs.size; + return 0; +} +#else + +/** + * htt_tx_desc_get_size() - get tx descripotrs size + * @pdev: htt device instance pointer + * + * This function will get HTT TX descriptor size and fragment descriptor size + * + * Return: None + */ +static inline void htt_tx_desc_get_size(struct htt_pdev_t *pdev) +{ + if (pdev->cfg.is_high_latency) { + pdev->tx_descs.size = sizeof(struct htt_host_tx_desc_t); + } else { + /* + * Start with the size of the base struct + * that actually gets downloaded. + * + * Add the fragmentation descriptor elements. + * Add the most that the OS may deliver, plus one more + * in case the txrx code adds a prefix fragment (for + * TSO or audio interworking SNAP header) + */ + pdev->tx_descs.size = + sizeof(struct htt_host_tx_desc_t) + + (ol_cfg_netbuf_frags_max(pdev->ctrl_pdev) + 1) * 8 + /* 2x uint32_t */ + + 4; /* uint32_t fragmentation list terminator */ + } +} + +#ifndef CONFIG_HL_SUPPORT + +/** + * htt_tx_frag_desc_field_update() - Update fragment descriptor field + * @pdev: htt device instance pointer + * @fptr: Fragment descriptor field pointer + * @index: Descriptor index to find page and offset + * @desc_v_ptr: descriptor virtual pointot to find offset + * + * This function will update fragment descriptor field with actual fragment + * descriptor stating physical pointer + * + * Return: None + */ +static void htt_tx_frag_desc_field_update(struct htt_pdev_t *pdev, + uint32_t *fptr, unsigned int index, + struct htt_tx_msdu_desc_t *desc_v_ptr) +{ + *fptr = (uint32_t)htt_tx_get_paddr(pdev, (char *)desc_v_ptr) + + HTT_TX_DESC_LEN; +} +#endif + +/** + * htt_tx_frag_desc_attach() - Attach fragment descriptor + * @pdev: htt device instance pointer + * @desc_pool_elems: Number of fragment descriptor + * + * This function will allocate fragment descriptor + * + * Return: 0 success + */ +static inline int htt_tx_frag_desc_attach(struct htt_pdev_t *pdev, + int desc_pool_elems) +{ + return 0; +} + +/** + * htt_tx_frag_desc_detach() - Detach fragment descriptor + * @pdev: htt device instance pointer + * + * This function will free fragment descriptor + * + * Return: None + */ +static void htt_tx_frag_desc_detach(struct htt_pdev_t *pdev) {} +#endif /* HELIUMPLUS */ + +#ifdef CONFIG_HL_SUPPORT + +/** + * htt_tx_attach() - Attach HTT device instance + * @pdev: htt device instance pointer + * @desc_pool_elems: Number of TX descriptors + * + * This function will allocate HTT TX resources + * + * Return: 0 Success + */ +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) +{ + int i, i_int, pool_size; + uint32_t **p; + uint32_t num_link = 0; + uint16_t num_page, num_desc_per_page; + void **cacheable_pages = NULL; + + htt_tx_desc_get_size(pdev); + + /* + * Make sure tx_descs.size is a multiple of 4-bytes. + * It should be, but round up just to be sure. + */ + pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); + + pdev->tx_descs.pool_elems = desc_pool_elems; + pdev->tx_descs.alloc_cnt = 0; + pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, + pdev->tx_descs.size, + pdev->tx_descs.pool_elems, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); + if ((0 == pdev->tx_descs.desc_pages.num_pages) || + (!pdev->tx_descs.desc_pages.cacheable_pages)) { + ol_txrx_err("HTT desc alloc fail"); + goto out_fail; + } + num_page = pdev->tx_descs.desc_pages.num_pages; + num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; + + /* link tx descriptors into a freelist */ + cacheable_pages = pdev->tx_descs.desc_pages.cacheable_pages; + + pdev->tx_descs.freelist = (uint32_t *)cacheable_pages[0]; + p = (uint32_t **)pdev->tx_descs.freelist; + for (i = 0; i < num_page; i++) { + for (i_int = 0; i_int < num_desc_per_page; i_int++) { + if (i_int == (num_desc_per_page - 1)) { + /* + * Last element on this page, + * should point next page + */ + if (!cacheable_pages[i + 1]) { + ol_txrx_err("over flow num link %d", + num_link); + goto free_htt_desc; + } + *p = (uint32_t *)cacheable_pages[i + 1]; + } else { + *p = (uint32_t *) + (((char *)p) + pdev->tx_descs.size); + } + num_link++; + p = (uint32_t **) *p; + /* Last link established exit */ + if (num_link == (pdev->tx_descs.pool_elems - 1)) + break; + } + } + *p = NULL; + + if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { + ol_txrx_err("HTT Frag descriptor alloc fail"); + goto free_htt_desc; + } + + /* success */ + return 0; + +free_htt_desc: + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); +out_fail: + return -ENOBUFS; +} + +void htt_tx_detach(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("htt tx detach invalid instance"); + return; + } + + htt_tx_frag_desc_detach(pdev); + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), + memctx), true); +} + +/** + * htt_tx_set_frag_desc_addr() - set up the fragmentation descriptor address + * @pdev: pointer to the HTT instance making the allocation + * @htt_tx_desc: Host tx descriptor that does not include HTC hdr + * @index: index to alloc htt tx desc + * + * + * Return: None + */ +static inline void +htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, + struct htt_tx_msdu_desc_t *htt_tx_desc, + uint16_t index) +{ +} + +/** + * htt_tx_desc_frags_table_set() - set up the descriptor and payload + * to correspondinf fragments + * @pdev: pointer to the HTT instance making the allocation + * @htt_tx_desc: Host tx descriptor that does not include HTC hdr + * @paddr: fragment physical address + * @frag_desc_paddr_lo: frag descriptor address + * @reset: reset + * + * Return: None + */ +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset) +{ + /* fragments table only applies to LL systems */ +} + +/** + * htt_tx_credit_update() - get the number of credits by which the amount of + * target credits needs to be updated + * @pdev: htt context + * + * Return: number of credits + */ +int htt_tx_credit_update(struct htt_pdev_t *pdev) +{ + int credit_delta; + + credit_delta = QDF_MIN(qdf_atomic_read( + &pdev->htt_tx_credit.target_delta), + qdf_atomic_read(&pdev->htt_tx_credit.bus_delta)); + if (credit_delta) { + qdf_atomic_add(-credit_delta, + &pdev->htt_tx_credit.target_delta); + qdf_atomic_add(-credit_delta, + &pdev->htt_tx_credit.bus_delta); + } + return credit_delta; +} + +/** + * htt_tx_get_paddr() - get physical address for htt desc + * + * Get HTT descriptor physical address from virtual address + * Find page first and find offset + * Not required for HL systems + * + * Return: Physical address of descriptor + */ +static inline +qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr) +{ + return 0; +} + + +#else + +int htt_tx_attach(struct htt_pdev_t *pdev, int desc_pool_elems) +{ + int i, i_int, pool_size; + uint32_t **p; + struct qdf_mem_dma_page_t *page_info; + uint32_t num_link = 0; + uint16_t num_page, num_desc_per_page; + + htt_tx_desc_get_size(pdev); + + /* + * Make sure tx_descs.size is a multiple of 4-bytes. + * It should be, but round up just to be sure. + */ + pdev->tx_descs.size = (pdev->tx_descs.size + 3) & (~0x3); + + pdev->tx_descs.pool_elems = desc_pool_elems; + pdev->tx_descs.alloc_cnt = 0; + pool_size = pdev->tx_descs.pool_elems * pdev->tx_descs.size; + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_descs.desc_pages, + pdev->tx_descs.size, pdev->tx_descs.pool_elems, + qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); + if ((0 == pdev->tx_descs.desc_pages.num_pages) || + (!pdev->tx_descs.desc_pages.dma_pages)) { + ol_txrx_err("HTT desc alloc fail"); + goto out_fail; + } + num_page = pdev->tx_descs.desc_pages.num_pages; + num_desc_per_page = pdev->tx_descs.desc_pages.num_element_per_page; + + /* link tx descriptors into a freelist */ + page_info = pdev->tx_descs.desc_pages.dma_pages; + pdev->tx_descs.freelist = (uint32_t *)page_info->page_v_addr_start; + p = (uint32_t **) pdev->tx_descs.freelist; + for (i = 0; i < num_page; i++) { + for (i_int = 0; i_int < num_desc_per_page; i_int++) { + if (i_int == (num_desc_per_page - 1)) { + /* + * Last element on this page, + * should pint next page + */ + if (!page_info->page_v_addr_start) { + ol_txrx_err("over flow num link %d", + num_link); + goto free_htt_desc; + } + page_info++; + *p = (uint32_t *)page_info->page_v_addr_start; + } else { + *p = (uint32_t *) + (((char *) p) + pdev->tx_descs.size); + } + num_link++; + p = (uint32_t **) *p; + /* Last link established exit */ + if (num_link == (pdev->tx_descs.pool_elems - 1)) + break; + } + } + *p = NULL; + + if (htt_tx_frag_desc_attach(pdev, desc_pool_elems)) { + ol_txrx_err("HTT Frag descriptor alloc fail"); + goto free_htt_desc; + } + + /* success */ + return 0; + +free_htt_desc: + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); +out_fail: + return -ENOBUFS; +} + +void htt_tx_detach(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("htt tx detach invalid instance"); + return; + } + + htt_tx_frag_desc_detach(pdev); + qdf_mem_multi_pages_free(pdev->osdev, &pdev->tx_descs.desc_pages, + qdf_get_dma_mem_context((&pdev->tx_descs), memctx), false); +} + +static void +htt_tx_set_frag_desc_addr(struct htt_pdev_t *pdev, + struct htt_tx_msdu_desc_t *htt_tx_desc, + uint16_t index) +{ + uint32_t *fragmentation_descr_field_ptr; + + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *)htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + /* + * The fragmentation descriptor is allocated from consistent + * memory. Therefore, we can use the address directly rather + * than having to map it from a virtual/CPU address to a + * physical/bus address. + */ + htt_tx_frag_desc_field_update(pdev, fragmentation_descr_field_ptr, + index, htt_tx_desc); + + return; +} + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset) +{ + uint32_t *fragmentation_descr_field_ptr; + + fragmentation_descr_field_ptr = (uint32_t *) + ((uint32_t *) htt_tx_desc) + + HTT_TX_DESC_FRAGS_DESC_PADDR_OFFSET_DWORD; + if (reset) { +#if defined(HELIUMPLUS) + *fragmentation_descr_field_ptr = frag_desc_paddr; +#else + *fragmentation_descr_field_ptr = + htt_tx_get_paddr(pdev, htt_tx_desc) + HTT_TX_DESC_LEN; +#endif + } else { + *fragmentation_descr_field_ptr = paddr; + } +} + +void htt_tx_pending_discard(htt_pdev_handle pdev) +{ + htc_flush_surprise_remove(pdev->htc_pdev); +} + +static qdf_dma_addr_t htt_tx_get_paddr(htt_pdev_handle pdev, + char *target_vaddr) +{ + uint16_t i; + struct qdf_mem_dma_page_t *page_info = NULL; + uint64_t offset; + + for (i = 0; i < pdev->tx_descs.desc_pages.num_pages; i++) { + page_info = pdev->tx_descs.desc_pages.dma_pages + i; + if (!page_info->page_v_addr_start) { + qdf_assert(0); + return 0; + } + if ((target_vaddr >= page_info->page_v_addr_start) && + (target_vaddr <= page_info->page_v_addr_end)) + break; + } + + if (!page_info) { + ol_txrx_err("invalid page_info"); + return 0; + } + + offset = (uint64_t)(target_vaddr - page_info->page_v_addr_start); + return page_info->page_p_addr + offset; +} + +#endif + +/*--- descriptor allocation functions ---------------------------------------*/ + +void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, + uint16_t index) +{ + struct htt_host_tx_desc_t *htt_host_tx_desc; /* includes HTC hdr */ + struct htt_tx_msdu_desc_t *htt_tx_desc; /* doesn't include HTC hdr */ + + htt_host_tx_desc = (struct htt_host_tx_desc_t *)pdev->tx_descs.freelist; + if (!htt_host_tx_desc) + return NULL; /* pool is exhausted */ + + htt_tx_desc = &htt_host_tx_desc->align32.tx_desc; + + if (pdev->tx_descs.freelist) { + pdev->tx_descs.freelist = + *((uint32_t **) pdev->tx_descs.freelist); + pdev->tx_descs.alloc_cnt++; + } + /* + * For LL, set up the fragmentation descriptor address. + * Currently, this HTT tx desc allocation is performed once up front. + * If this is changed to have the allocation done during tx, then it + * would be helpful to have separate htt_tx_desc_alloc functions for + * HL vs. LL, to remove the below conditional branch. + */ + htt_tx_set_frag_desc_addr(pdev, htt_tx_desc, index); + + /* + * Include the headroom for the HTC frame header when specifying the + * physical address for the HTT tx descriptor. + */ + *paddr = (qdf_dma_addr_t)htt_tx_get_paddr(pdev, + (char *)htt_host_tx_desc); + /* + * The allocated tx descriptor space includes headroom for a + * HTC frame header. Hide this headroom, so that we don't have + * to jump past the headroom each time we program a field within + * the tx desc, but only once when we download the tx desc (and + * the headroom) to the target via HTC. + * Skip past the headroom and return the address of the HTT tx desc. + */ + return (void *)htt_tx_desc; +} + +void htt_tx_desc_free(htt_pdev_handle pdev, void *tx_desc) +{ + char *htt_host_tx_desc = tx_desc; + /* rewind over the HTC frame header space */ + htt_host_tx_desc -= + offsetof(struct htt_host_tx_desc_t, align32.tx_desc); + *((uint32_t **) htt_host_tx_desc) = pdev->tx_descs.freelist; + pdev->tx_descs.freelist = (uint32_t *) htt_host_tx_desc; + pdev->tx_descs.alloc_cnt--; +} + +/*--- descriptor field access methods ---------------------------------------*/ + +/* PUT THESE AS inline IN ol_htt_tx_api.h */ + +void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc) +{ +} + +void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc) +{ +} + +/*--- tx send function ------------------------------------------------------*/ + +#ifdef ATH_11AC_TXCOMPACT + +/* + * Scheduling the Queued packets in HTT which could not be sent out + * because of No CE desc + */ +void htt_tx_sched(htt_pdev_handle pdev) +{ + qdf_nbuf_t msdu; + int download_len = pdev->download_len; + int packet_len; + + HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); + while (msdu) { + int not_accepted; + /* packet length includes HTT tx desc frag added above */ + packet_len = qdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the + * nominal download length can happen for a couple + * of reasons: + * In HL, the nominal download length is a large + * artificial value. + * In LL, the frame may not have the optional header + * fields accounted for in the nominal download size + * (LLC/SNAP header, IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + not_accepted = + htc_send_data_pkt(pdev->htc_pdev, msdu, + pdev->htc_tx_endpoint, + download_len); + if (not_accepted) { + HTT_TX_NBUF_QUEUE_INSERT_HEAD(pdev, msdu); + return; + } + HTT_TX_NBUF_QUEUE_REMOVE(pdev, msdu); + } +} + +int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + + int download_len = pdev->download_len; + + int packet_len; + + /* packet length includes HTT tx desc frag added above */ + packet_len = qdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the nominal + * download length can happen for a couple of reasons: + * In HL, the nominal download length is a large artificial + * value. + * In LL, the frame may not have the optional header fields + * accounted for in the nominal download size (LLC/SNAP header, + * IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu)) + download_len += sizeof(struct htt_tx_msdu_desc_ext_t); + + + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_HTT); + DPTRACE(qdf_dp_trace(msdu, QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_TX)); + if (qdf_nbuf_queue_len(&pdev->txnbufq) > 0) { + HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); + htt_tx_sched(pdev); + return 0; + } + + if (htc_send_data_pkt(pdev->htc_pdev, msdu, + pdev->htc_tx_endpoint, download_len)) { + HTT_TX_NBUF_QUEUE_ADD(pdev, msdu); + } + + return 0; /* success */ + +} + +#ifndef CONFIG_HL_SUPPORT +#ifdef FEATURE_RUNTIME_PM +/** + * htt_tx_resume_handler() - resume callback for the htt endpoint + * @context: a pointer to the htt context + * + * runs htt_tx_sched. + */ +void htt_tx_resume_handler(void *context) +{ + struct htt_pdev_t *pdev = (struct htt_pdev_t *) context; + + htt_tx_sched(pdev); +} +#else +void +htt_tx_resume_handler(void *context) { } +#endif +#endif + +qdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) +{ + qdf_print("Not apply to LL"); + qdf_assert(0); + return head_msdu; + +} + +int +htt_tx_send_nonstd(htt_pdev_handle pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type) +{ + int download_len; + + /* + * The pkt_type could be checked to see what L2 header type is present, + * and then the L2 header could be examined to determine its length. + * But for simplicity, just use the maximum possible header size, + * rather than computing the actual header size. + */ + download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); + qdf_assert(download_len <= pdev->download_len); + return htt_tx_send_std(pdev, msdu, msdu_id); +} + +#ifndef QCA_TX_PADDING_CREDIT_SUPPORT +int htt_tx_padding_credit_update_handler(void *context, int pad_credit) +{ + return 1; +} +#endif + +#else /*ATH_11AC_TXCOMPACT */ + +#ifdef QCA_TX_PADDING_CREDIT_SUPPORT +static int htt_tx_padding_credit_update(htt_pdev_handle htt_pdev, + int pad_credit) +{ + int ret = 0; + + if (pad_credit) + qdf_atomic_add(pad_credit, + &htt_pdev->txrx_pdev->pad_reserve_tx_credit); + + ret = qdf_atomic_read(&htt_pdev->txrx_pdev->pad_reserve_tx_credit); + + return ret; +} + +int htt_tx_padding_credit_update_handler(void *context, int pad_credit) +{ + struct htt_pdev_t *htt_pdev = (struct htt_pdev_t *)context; + + return htt_tx_padding_credit_update(htt_pdev, pad_credit); +} +#else +int htt_tx_padding_credit_update_handler(void *context, int pad_credit) +{ + return 1; +} +#endif + +#ifdef QCA_TX_HTT2_SUPPORT +static inline HTC_ENDPOINT_ID +htt_tx_htt2_get_ep_id(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + /* + * TX HTT2 service mainly for small sized frame and check if + * this candidate frame allow or not. + */ + if ((pdev->htc_tx_htt2_endpoint != ENDPOINT_UNUSED) && + qdf_nbuf_get_tx_parallel_dnload_frm(msdu) && + (qdf_nbuf_len(msdu) < pdev->htc_tx_htt2_max_size)) + return pdev->htc_tx_htt2_endpoint; + else + return pdev->htc_tx_endpoint; +} +#else +#define htt_tx_htt2_get_ep_id(pdev, msdu) (pdev->htc_tx_endpoint) +#endif /* QCA_TX_HTT2_SUPPORT */ + +static inline int +htt_tx_send_base(htt_pdev_handle pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, int download_len, uint8_t more_data) +{ + struct htt_host_tx_desc_t *htt_host_tx_desc; + struct htt_htc_pkt *pkt; + int packet_len; + HTC_ENDPOINT_ID ep_id; + + /* + * The HTT tx descriptor was attached as the prefix fragment to the + * msdu netbuf during the call to htt_tx_desc_init. + * Retrieve it so we can provide its HTC header space to HTC. + */ + htt_host_tx_desc = (struct htt_host_tx_desc_t *) + qdf_nbuf_get_frag_vaddr(msdu, 0); + + pkt = htt_htc_pkt_alloc(pdev); + if (!pkt) + return -ENOBUFS; /* failure */ + + pkt->msdu_id = msdu_id; + pkt->pdev_ctxt = pdev->txrx_pdev; + + /* packet length includes HTT tx desc frag added above */ + packet_len = qdf_nbuf_len(msdu); + if (packet_len < download_len) { + /* + * This case of packet length being less than the nominal + * download length can happen for a couple reasons: + * In HL, the nominal download length is a large artificial + * value. + * In LL, the frame may not have the optional header fields + * accounted for in the nominal download size (LLC/SNAP header, + * IPv4 or IPv6 header). + */ + download_len = packet_len; + } + + ep_id = htt_tx_htt2_get_ep_id(pdev, msdu); + + SET_HTC_PACKET_INFO_TX(&pkt->htc_pkt, + pdev->tx_send_complete_part2, + (unsigned char *)htt_host_tx_desc, + download_len - HTC_HDR_LENGTH, + ep_id, + 1); /* tag - not relevant here */ + + SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msdu); + + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_HTT); + DPTRACE(qdf_dp_trace(msdu, QDF_DP_TRACE_HTT_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_TX)); + htc_send_data_pkt(pdev->htc_pdev, &pkt->htc_pkt, more_data); + + return 0; /* success */ +} + +qdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle pdev, qdf_nbuf_t head_msdu, int num_msdus) +{ + qdf_nbuf_t rejected = NULL; + uint16_t *msdu_id_storage; + uint16_t msdu_id; + qdf_nbuf_t msdu; + + /* + * FOR NOW, iterate through the batch, sending the frames singly. + * Eventually HTC and HIF should be able to accept a batch of + * data frames rather than singles. + */ + msdu = head_msdu; + while (num_msdus--) { + qdf_nbuf_t next_msdu = qdf_nbuf_next(msdu); + + msdu_id_storage = ol_tx_msdu_id_storage(msdu); + msdu_id = *msdu_id_storage; + + /* htt_tx_send_base returns 0 as success and 1 as failure */ + if (htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, + num_msdus)) { + qdf_nbuf_set_next(msdu, rejected); + rejected = msdu; + } + msdu = next_msdu; + } + return rejected; +} + +int +htt_tx_send_nonstd(htt_pdev_handle pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type) +{ + int download_len; + + /* + * The pkt_type could be checked to see what L2 header type is present, + * and then the L2 header could be examined to determine its length. + * But for simplicity, just use the maximum possible header size, + * rather than computing the actual header size. + */ + download_len = sizeof(struct htt_host_tx_desc_t) + + HTT_TX_HDR_SIZE_OUTER_HDR_MAX /* worst case */ + + HTT_TX_HDR_SIZE_802_1Q + + HTT_TX_HDR_SIZE_LLC_SNAP + + ol_cfg_tx_download_size(pdev->ctrl_pdev); + return htt_tx_send_base(pdev, msdu, msdu_id, download_len, 0); +} + +int htt_tx_send_std(htt_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + return htt_tx_send_base(pdev, msdu, msdu_id, pdev->download_len, 0); +} + +#endif /*ATH_11AC_TXCOMPACT */ + +#if defined(HTT_DBG) +void htt_tx_desc_display(void *tx_desc) +{ + struct htt_tx_msdu_desc_t *htt_tx_desc; + + htt_tx_desc = (struct htt_tx_msdu_desc_t *)tx_desc; + + /* only works for little-endian */ + qdf_debug("HTT tx desc (@ %pK):", htt_tx_desc); + qdf_debug(" msg type = %d", htt_tx_desc->msg_type); + qdf_debug(" pkt subtype = %d", htt_tx_desc->pkt_subtype); + qdf_debug(" pkt type = %d", htt_tx_desc->pkt_type); + qdf_debug(" vdev ID = %d", htt_tx_desc->vdev_id); + qdf_debug(" ext TID = %d", htt_tx_desc->ext_tid); + qdf_debug(" postponed = %d", htt_tx_desc->postponed); + qdf_debug(" extension = %d", htt_tx_desc->extension); + qdf_debug(" cksum_offload = %d", htt_tx_desc->cksum_offload); + qdf_debug(" tx_compl_req= %d", htt_tx_desc->tx_compl_req); + qdf_debug(" length = %d", htt_tx_desc->len); + qdf_debug(" id = %d", htt_tx_desc->id); +#if HTT_PADDR64 + qdf_debug(" frag desc addr.lo = %#x", + htt_tx_desc->frags_desc_ptr.lo); + qdf_debug(" frag desc addr.hi = %#x", + htt_tx_desc->frags_desc_ptr.hi); +#else /* ! HTT_PADDR64 */ + qdf_debug(" frag desc addr = %#x", htt_tx_desc->frags_desc_ptr); +#endif /* HTT_PADDR64 */ + qdf_debug(" peerid = %d", htt_tx_desc->peerid); + qdf_debug(" chanfreq = %d", htt_tx_desc->chanfreq); +} +#endif + +#ifdef IPA_OFFLOAD +#ifdef QCA_WIFI_3_0 + +#ifndef LIMIT_IPA_TX_BUFFER +#define LIMIT_IPA_TX_BUFFER 2048 +#endif + +/** + * htt_tx_ipa_get_tx_buf_count() - Update WDI TX buffers count + * @uc_tx_buf_cnt: TX Buffer count + * + * Return: new uc tx buffer count + */ +static int htt_tx_ipa_get_limit_tx_buf_count(unsigned int uc_tx_buf_cnt) +{ + /* In order to improve the Genoa IPA DBS KPI, need to set + * IpaUcTxBufCount=2048, so tx complete ring size=2048, and + * total tx buffer count = 2047. + * But in fact, wlan fw just only have 5G 1100 tx desc + + * 2.4G 400 desc, it can cover about 1500 packets from + * IPA side. + * So the remaining 2047-1500 packet are not used, + * in order to save some memory, so we can use + * LIMIT_IPA_TX_BUFFER to limit the max tx buffer + * count, which varied from platform. + * And then the tx buffer count always equal to tx complete + * ring size -1 is not mandatory now. + * From the trying, it has the same KPI achievement while + * set LIMIT_IPA_TX_BUFFER=1500 or 2048. + */ + if (uc_tx_buf_cnt > LIMIT_IPA_TX_BUFFER) + return LIMIT_IPA_TX_BUFFER; + else + return uc_tx_buf_cnt; +} + +/** + * htt_tx_ipa_uc_wdi_tx_buf_alloc() - Alloc WDI TX buffers + * @pdev: htt context + * @uc_tx_buf_sz: TX buffer size + * @uc_tx_buf_cnt: TX Buffer count + * @uc_tx_partition_base: IPA UC TX partition base value + * + * Allocate WDI TX buffers. Also note Rome supports only WDI 1.0. + * + * Return: 0 success + */ + +static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + unsigned int tx_buffer_count; + qdf_dma_addr_t buffer_paddr; + uint32_t *header_ptr; + target_paddr_t *ring_vaddr; + qdf_shared_mem_t *shared_tx_buffer; + + ring_vaddr = (target_paddr_t *)pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr; + + /* Allocate TX buffers as many as possible */ + for (tx_buffer_count = 0; + tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { + + shared_tx_buffer = qdf_mem_shared_mem_alloc(pdev->osdev, + uc_tx_buf_sz); + if (!shared_tx_buffer || !shared_tx_buffer->vaddr) { + qdf_print("IPA WDI TX buffer alloc fail %d allocated", + tx_buffer_count); + goto out; + } + + header_ptr = shared_tx_buffer->vaddr; + buffer_paddr = qdf_mem_get_dma_addr(pdev->osdev, + &shared_tx_buffer->mem_info); + + /* HTT control header */ + *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; + header_ptr++; + + /* PKT ID */ + *header_ptr |= ((uint16_t) uc_tx_partition_base + + tx_buffer_count) << 16; + + header_ptr++; + + /* Frag Desc Pointer */ + /* 64bits descriptor, Low 32bits */ + *header_ptr = qdf_get_lower_32_bits(buffer_paddr + + IPA_UC_TX_BUF_FRAG_DESC_OFFSET); + header_ptr++; + + /* 64bits descriptor, high 32bits */ + *header_ptr = qdf_get_upper_32_bits(buffer_paddr) & + IPA_UC_TX_BUF_PADDR_HI_MASK; + header_ptr++; + + /* chanreq, peerid */ + *header_ptr = 0xFFFFFFFF; + header_ptr++; + + /* FRAG Header */ + /* 6 words TSO header */ + header_ptr += IPA_UC_TX_BUF_TSO_HDR_SIZE; + *header_ptr = buffer_paddr + IPA_UC_TX_BUF_FRAG_HDR_OFFSET; + + *ring_vaddr = buffer_paddr; + pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[tx_buffer_count] = + shared_tx_buffer; + + /* Memory barrier to ensure actual value updated */ + + ring_vaddr++; + } + +out: + + return tx_buffer_count; +} + +/** + * htt_tx_buf_pool_free() - Free tx buffer pool + * @pdev: htt context + * + * Free memory in tx buffer pool + * + * Return: 0 success + */ +static void htt_tx_buf_pool_free(struct htt_pdev_t *pdev) +{ + uint16_t idx; + + for (idx = 0; idx < pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx]) { + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc. + tx_buf_pool_strg[idx]); + pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx] = NULL; + } + } +} +#else +static int htt_tx_ipa_get_limit_tx_buf_count(unsigned int uc_tx_buf_cnt) +{ + return uc_tx_buf_cnt; +} + +static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + unsigned int tx_buffer_count; + unsigned int tx_buffer_count_pwr2; + qdf_dma_addr_t buffer_paddr; + uint32_t *header_ptr; + uint32_t *ring_vaddr; + uint16_t idx; + qdf_shared_mem_t *shared_tx_buffer; + + ring_vaddr = pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr; + + /* Allocate TX buffers as many as possible */ + for (tx_buffer_count = 0; + tx_buffer_count < (uc_tx_buf_cnt - 1); tx_buffer_count++) { + shared_tx_buffer = qdf_mem_shared_mem_alloc(pdev->osdev, + uc_tx_buf_sz); + if (!shared_tx_buffer || !shared_tx_buffer->vaddr) { + qdf_print("TX BUF alloc fail, loop index: %d", + tx_buffer_count); + goto pwr2; + } + + /* Init buffer */ + qdf_mem_zero(shared_tx_buffer->vaddr, uc_tx_buf_sz); + header_ptr = (uint32_t *)shared_tx_buffer->vaddr; + buffer_paddr = qdf_mem_get_dma_addr(pdev->osdev, + &shared_tx_buffer->mem_info); + + /* HTT control header */ + *header_ptr = HTT_IPA_UC_OFFLOAD_TX_HEADER_DEFAULT; + header_ptr++; + + /* PKT ID */ + *header_ptr |= ((uint16_t) uc_tx_partition_base + + tx_buffer_count) << 16; + header_ptr++; + + /*FRAG Desc Pointer */ + *header_ptr = (uint32_t) (buffer_paddr + + IPA_UC_TX_BUF_FRAG_DESC_OFFSET); + header_ptr++; + *header_ptr = 0xFFFFFFFF; + + /* FRAG Header */ + header_ptr++; + *header_ptr = buffer_paddr + IPA_UC_TX_BUF_FRAG_HDR_OFFSET; + + *ring_vaddr = buffer_paddr; + pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[tx_buffer_count] = + shared_tx_buffer; + /* Memory barrier to ensure actual value updated */ + + ring_vaddr++; + } + +pwr2: + /* + * Tx complete ring buffer count should be power of 2. + * So, allocated Tx buffer count should be one less than ring buffer + * size. + */ + tx_buffer_count_pwr2 = qdf_rounddown_pow_of_two(tx_buffer_count + 1) + - 1; + if (tx_buffer_count > tx_buffer_count_pwr2) { + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "%s: Allocated Tx buffer count %d is rounded down to %d", + __func__, tx_buffer_count, tx_buffer_count_pwr2); + + /* Free over allocated buffers below power of 2 */ + for (idx = tx_buffer_count_pwr2; idx < tx_buffer_count; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx]) { + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc. + tx_buf_pool_strg[idx]); + pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx] = + NULL; + } + } + } + + return tx_buffer_count_pwr2; +} + +static void htt_tx_buf_pool_free(struct htt_pdev_t *pdev) +{ + uint16_t idx; + + for (idx = 0; idx < pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; idx++) { + if (pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx]) { + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc. + tx_buf_pool_strg[idx]); + pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[idx] = NULL; + } + } +} +#endif + +/** + * htt_tx_ipa_uc_attach() - attach htt ipa uc tx resource + * @pdev: htt context + * @uc_tx_buf_sz: single tx buffer size + * @uc_tx_buf_cnt: total tx buffer count + * @uc_tx_partition_base: tx buffer partition start + * + * Return: 0 success + * ENOBUFS No memory fail + */ +int htt_tx_ipa_uc_attach(struct htt_pdev_t *pdev, + unsigned int uc_tx_buf_sz, + unsigned int uc_tx_buf_cnt, + unsigned int uc_tx_partition_base) +{ + int return_code = 0; + unsigned int tx_comp_ring_size; + + /* Allocate CE Write Index WORD */ + pdev->ipa_uc_tx_rsc.tx_ce_idx = + qdf_mem_shared_mem_alloc(pdev->osdev, 4); + if (!pdev->ipa_uc_tx_rsc.tx_ce_idx) { + qdf_print("Unable to allocate memory for IPA tx ce idx"); + return -ENOBUFS; + } + + /* Allocate TX COMP Ring */ + tx_comp_ring_size = qdf_get_pwr2(uc_tx_buf_cnt) + * sizeof(target_paddr_t); + pdev->ipa_uc_tx_rsc.tx_comp_ring = + qdf_mem_shared_mem_alloc(pdev->osdev, + tx_comp_ring_size); + if (!pdev->ipa_uc_tx_rsc.tx_comp_ring || + !pdev->ipa_uc_tx_rsc.tx_comp_ring->vaddr) { + qdf_print("TX COMP ring alloc fail"); + return_code = -ENOBUFS; + goto free_tx_ce_idx; + } + + uc_tx_buf_cnt = htt_tx_ipa_get_limit_tx_buf_count(uc_tx_buf_cnt); + /* Allocate TX BUF vAddress Storage */ + pdev->ipa_uc_tx_rsc.tx_buf_pool_strg = + qdf_mem_malloc(uc_tx_buf_cnt * + sizeof(*pdev->ipa_uc_tx_rsc.tx_buf_pool_strg)); + if (!pdev->ipa_uc_tx_rsc.tx_buf_pool_strg) { + return_code = -ENOBUFS; + goto free_tx_comp_base; + } + + qdf_mem_zero(pdev->ipa_uc_tx_rsc.tx_buf_pool_strg, + uc_tx_buf_cnt * + sizeof(*pdev->ipa_uc_tx_rsc.tx_buf_pool_strg)); + + pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt = htt_tx_ipa_uc_wdi_tx_buf_alloc( + pdev, uc_tx_buf_sz, uc_tx_buf_cnt, uc_tx_partition_base); + + pdev->ipa_uc_tx_rsc.ipa_smmu_mapped = false; + + + return 0; + +free_tx_comp_base: + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc.tx_comp_ring); +free_tx_ce_idx: + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc.tx_ce_idx); + + return return_code; +} + +/** + * htt_tx_ipa_uc_detach() - Free WDI TX resources + * @pdev: htt context + * + * Remove IPA WDI TX resources during device detach + * Free all of allocated resources + * + * Return: 0 success + */ +int htt_tx_ipa_uc_detach(struct htt_pdev_t *pdev) +{ + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc.tx_ce_idx); + qdf_mem_shared_mem_free(pdev->osdev, + pdev->ipa_uc_tx_rsc.tx_comp_ring); + + /* Free each single buffer */ + htt_tx_buf_pool_free(pdev); + + /* Free storage */ + qdf_mem_free(pdev->ipa_uc_tx_rsc.tx_buf_pool_strg); + + return 0; +} +#endif /* IPA_OFFLOAD */ + +#if defined(FEATURE_TSO) && defined(HELIUMPLUS) +void +htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, + struct qdf_tso_info_t *tso_info) +{ + u_int32_t *word; + int i; + struct qdf_tso_seg_elem_t *tso_seg = tso_info->curr_seg; + struct msdu_ext_desc_t *msdu_ext_desc = (struct msdu_ext_desc_t *)desc; + + word = (u_int32_t *)(desc); + + /* Initialize the TSO flags per MSDU */ + msdu_ext_desc->tso_flags = + tso_seg->seg.tso_flags; + + /* First 24 bytes (6*4) contain the TSO flags */ + TSO_DEBUG("%s seq# %u l2 len %d, ip len %d", + __func__, + tso_seg->seg.tso_flags.tcp_seq_num, + tso_seg->seg.tso_flags.l2_len, + tso_seg->seg.tso_flags.ip_len); + TSO_DEBUG("%s flags 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + __func__, + *word, + *(word + 1), + *(word + 2), + *(word + 3), + *(word + 4), + *(word + 5)); + + word += 6; + + for (i = 0; i < tso_seg->seg.num_frags; i++) { + uint32_t lo = 0; + uint32_t hi = 0; + + qdf_dmaaddr_to_32s(tso_seg->seg.tso_frags[i].paddr, + &lo, &hi); + /* [31:0] first 32 bits of the buffer pointer */ + *word = lo; + word++; + /* [15:0] the upper 16 bits of the first buffer pointer */ + /* [31:16] length of the first buffer */ + *word = (tso_seg->seg.tso_frags[i].length << 16) | hi; + word++; + TSO_DEBUG("%s frag[%d] ptr_low 0x%x ptr_hi 0x%x len %u", + __func__, i, + msdu_ext_desc->frags[i].u.frag32.ptr_low, + msdu_ext_desc->frags[i].u.frag32.ptr_hi, + msdu_ext_desc->frags[i].u.frag32.len); + } + + if (tso_seg->seg.num_frags < FRAG_NUM_MAX) + *word = 0; + qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_FILLHTTSEG); +} +#endif /* FEATURE_TSO */ + +/** + * htt_get_ext_tid() - get ext_tid value + * @type: extension header type + * @ext_header_data: header data + * @msdu_info: msdu info + * + * Return: ext_tid value + */ +static inline +int htt_get_ext_tid(enum extension_header_type type, + void *ext_header_data, struct htt_msdu_info_t *msdu_info) +{ + if (type == OCB_MODE_EXT_HEADER && ext_header_data) + return ((struct ocb_tx_ctrl_hdr_t *)ext_header_data)->ext_tid; + else + return msdu_info->info.ext_tid; +} + +/** + * htt_get_channel_freq() - get channel frequency + * @type: extension header type + * @ext_header_data: header data + * + * Return: channel frequency number + */ +static inline +int htt_get_channel_freq(enum extension_header_type type, + void *ext_header_data) +{ + if (type == OCB_MODE_EXT_HEADER && ext_header_data) + return ((struct ocb_tx_ctrl_hdr_t *)ext_header_data) + ->channel_freq; + else + return HTT_INVALID_CHANNEL; +} + +/** + * htt_fill_ocb_ext_header() - fill OCB extension header + * @msdu: network buffer + * @local_desc_ext: extension descriptor + * @type: extension header type + * @ext_header_data: header data + * @is_dsrc: is dsrc is eenabled or not + * + * Return: none + */ +#ifdef WLAN_FEATURE_DSRC +static +void htt_fill_ocb_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, + void *ext_header_data) +{ + struct ocb_tx_ctrl_hdr_t *tx_ctrl = + (struct ocb_tx_ctrl_hdr_t *)ext_header_data; + + if (tx_ctrl->all_flags == 0) + return; + /* + * Copy the info that was read from TX control header from the + * user application to the extended HTT header. + * First copy everything + * to a local temp structure, and then copy everything to the + * actual uncached structure in one go to save memory writes. + */ + local_desc_ext->valid_pwr = tx_ctrl->valid_pwr; + local_desc_ext->valid_mcs_mask = tx_ctrl->valid_datarate; + local_desc_ext->valid_retries = tx_ctrl->valid_retries; + local_desc_ext->valid_expire_tsf = tx_ctrl->valid_expire_tsf; + local_desc_ext->valid_chainmask = tx_ctrl->valid_chain_mask; + + local_desc_ext->pwr = tx_ctrl->pwr; + if (tx_ctrl->valid_datarate && + tx_ctrl->datarate <= htt_ofdm_datarate_max) + local_desc_ext->mcs_mask = + (1 << (tx_ctrl->datarate + 4)); + local_desc_ext->retry_limit = tx_ctrl->retry_limit; + local_desc_ext->expire_tsf_lo = tx_ctrl->expire_tsf_lo; + local_desc_ext->expire_tsf_hi = tx_ctrl->expire_tsf_hi; + local_desc_ext->chain_mask = tx_ctrl->chain_mask; + local_desc_ext->is_dsrc = 1; + qdf_nbuf_push_head(msdu, sizeof(struct htt_tx_msdu_desc_ext_t)); + qdf_mem_copy(qdf_nbuf_data(msdu), local_desc_ext, + sizeof(struct htt_tx_msdu_desc_ext_t)); + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu) = 1; +} +#else +static +void htt_fill_ocb_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, + void *ext_header_data) +{ +} +#endif + +/** + * htt_fill_wisa_ext_header() - fill WiSA extension header + * @msdu: network buffer + * @local_desc_ext: extension descriptor + * @type: extension header type + * @ext_header_data: header data + * + * Return: none + */ +static +void htt_fill_wisa_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, void *ext_header_data) +{ + void *qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + QDF_STATUS status; + + if (!qdf_ctx) + return; + + local_desc_ext->valid_mcs_mask = 1; + if (WISA_MODE_EXT_HEADER_6MBPS == type) + local_desc_ext->mcs_mask = htt_ofdm_datarate_6_mbps; + else + local_desc_ext->mcs_mask = htt_ofdm_datarate_24_mbps; + local_desc_ext->valid_nss_mask = 1; + local_desc_ext->nss_mask = 1; + local_desc_ext->valid_bandwidth = 1; + local_desc_ext->bandwidth_mask = htt_tx_bandwidth_20MHz; + local_desc_ext->valid_guard_interval = 1; + local_desc_ext->guard_interval = htt_tx_guard_interval_regular; + + /* + * Do dma_unmap and dma_map again if already mapped + * as adding extra bytes in skb + */ + if (QDF_NBUF_CB_PADDR(msdu) != 0) + qdf_nbuf_unmap_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); + + qdf_nbuf_push_head(msdu, sizeof(struct htt_tx_msdu_desc_ext_t)); + qdf_mem_copy(qdf_nbuf_data(msdu), local_desc_ext, + sizeof(struct htt_tx_msdu_desc_ext_t)); + + if (QDF_NBUF_CB_PADDR(msdu) != 0) { + status = qdf_nbuf_map_single(qdf_ctx, msdu, QDF_DMA_TO_DEVICE); + if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_WARN, + "%s: nbuf map failed", __func__); + return; + } + } + QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu) = 1; +} + +/** + * htt_push_ext_header() - fill extension header + * @msdu: network buffer + * @local_desc_ext: extension descriptor + * @type: extension header type + * @ext_header_data: header data + * @is_dsrc: is dsrc is eenabled or not + * + * Return: none + */ +static +void htt_push_ext_header(qdf_nbuf_t msdu, + struct htt_tx_msdu_desc_ext_t *local_desc_ext, + enum extension_header_type type, void *ext_header_data) +{ + switch (type) { + case OCB_MODE_EXT_HEADER: + htt_fill_ocb_ext_header(msdu, local_desc_ext, + type, ext_header_data); + break; + case WISA_MODE_EXT_HEADER_6MBPS: + case WISA_MODE_EXT_HEADER_24MBPS: + htt_fill_wisa_ext_header(msdu, local_desc_ext, + type, ext_header_data); + break; + default: + QDF_TRACE(QDF_MODULE_ID_HTT, QDF_TRACE_LEVEL_INFO, + "Invalid EXT header type %d\n", type); + break; + } +} + +QDF_STATUS +htt_tx_desc_init(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t htt_tx_desc_paddr, + uint16_t msdu_id, + qdf_nbuf_t msdu, struct htt_msdu_info_t *msdu_info, + struct qdf_tso_info_t *tso_info, + void *ext_header_data, + enum extension_header_type type) +{ + uint8_t pkt_type, pkt_subtype = 0, ce_pkt_type = 0; + uint32_t hw_classify = 0, data_attr = 0; + uint32_t *word0, *word1, local_word3; +#if HTT_PADDR64 + uint32_t *word4; +#else /* ! HTT_PADDR64 */ + uint32_t *word3; +#endif /* HTT_PADDR64 */ + uint32_t local_word0, local_word1; + struct htt_host_tx_desc_t *htt_host_tx_desc = + (struct htt_host_tx_desc_t *) + (((char *)htt_tx_desc) - HTT_TX_DESC_VADDR_OFFSET); + bool desc_ext_required = (type != EXT_HEADER_NOT_PRESENT); + int channel_freq; + void *qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + qdf_dma_dir_t dir; + QDF_STATUS status; + + if (qdf_unlikely(!qdf_ctx)) + return QDF_STATUS_E_FAILURE; + + if (qdf_unlikely(!msdu_info)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: bad arg: msdu_info is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + if (qdf_unlikely(!tso_info)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: bad arg: tso_info is NULL", __func__); + return QDF_STATUS_E_FAILURE; + } + + word0 = (uint32_t *) htt_tx_desc; + word1 = word0 + 1; + /* + * word2 is frag desc pointer + * word3 or 4 is peer_id + */ +#if HTT_PADDR64 + word4 = word0 + 4; /* Dword 3 */ +#else /* ! HTT_PADDR64 */ + word3 = word0 + 3; /* Dword 3 */ +#endif /* HTT_PADDR64 */ + + pkt_type = msdu_info->info.l2_hdr_type; + + if (qdf_likely(pdev->cfg.ce_classify_enabled)) { + if (qdf_likely(pkt_type == htt_pkt_type_eth2 || + pkt_type == htt_pkt_type_ethernet)) + qdf_nbuf_tx_info_get(msdu, pkt_type, pkt_subtype, + hw_classify); + + ce_pkt_type = htt_to_ce_pkt_type[pkt_type]; + if (0xffffffff == ce_pkt_type) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "Invalid HTT pkt type %d\n", pkt_type); + return QDF_STATUS_E_INVAL; + } + } + + /* + * HTT Tx Desc is in uncached memory. Used cached writes per word, to + * reduce unnecessary memory access. + */ + + local_word0 = 0; + + HTT_H2T_MSG_TYPE_SET(local_word0, HTT_H2T_MSG_TYPE_TX_FRM); + HTT_TX_DESC_PKT_TYPE_SET(local_word0, pkt_type); + HTT_TX_DESC_PKT_SUBTYPE_SET(local_word0, pkt_subtype); + HTT_TX_DESC_VDEV_ID_SET(local_word0, msdu_info->info.vdev_id); + HTT_TX_DESC_EXT_TID_SET(local_word0, htt_get_ext_tid(type, + ext_header_data, msdu_info)); + HTT_TX_DESC_EXTENSION_SET(local_word0, desc_ext_required); + HTT_TX_DESC_EXT_TID_SET(local_word0, msdu_info->info.ext_tid); + HTT_TX_DESC_CKSUM_OFFLOAD_SET(local_word0, + msdu_info->action.cksum_offload); + if (pdev->cfg.is_high_latency) + HTT_TX_DESC_TX_COMP_SET(local_word0, msdu_info->action. + tx_comp_req); + HTT_TX_DESC_NO_ENCRYPT_SET(local_word0, + msdu_info->action.do_encrypt ? + 0 : 1); + + *word0 = local_word0; + + local_word1 = 0; + + if (tso_info->is_tso) { + uint32_t total_len = tso_info->curr_seg->seg.total_len; + + HTT_TX_DESC_FRM_LEN_SET(local_word1, total_len); + TSO_DEBUG("%s setting HTT TX DESC Len = %d", + __func__, total_len); + } else { + HTT_TX_DESC_FRM_LEN_SET(local_word1, qdf_nbuf_len(msdu)); + } + + QDF_BUG(HTT_TX_DESC_FRM_LEN_GET(local_word1) != 0); + + HTT_TX_DESC_FRM_ID_SET(local_word1, msdu_id); + *word1 = local_word1; + + /* + * Initialize peer_id to INVALID_PEER because + * this is NOT Reinjection path + */ + local_word3 = HTT_INVALID_PEER; + channel_freq = htt_get_channel_freq(type, ext_header_data); + if (channel_freq != HTT_INVALID_CHANNEL && channel_freq > 0) + HTT_TX_DESC_CHAN_FREQ_SET(local_word3, channel_freq); +#if HTT_PADDR64 + *word4 = local_word3; +#else /* ! HTT_PADDR64 */ + *word3 = local_word3; +#endif /* HTT_PADDR64 */ + + /* + * If any of the tx control flags are set, then we need the extended + * HTT header. + */ + if (desc_ext_required) { + struct htt_tx_msdu_desc_ext_t local_desc_ext = {0}; + + htt_push_ext_header(msdu, &local_desc_ext, + type, ext_header_data); + } + + /* + * Specify that the data provided by the OS is a bytestream, + * and thus should not be byte-swapped during the HIF download + * even if the host is big-endian. + * There could be extra fragments added before the OS's fragments, + * e.g. for TSO, so it's incorrect to clear the frag 0 wordstream flag. + * Instead, clear the wordstream flag for the final fragment, which + * is certain to be (one of the) fragment(s) provided by the OS. + * Setting the flag for this final fragment suffices for specifying + * all fragments provided by the OS rather than added by the driver. + */ + qdf_nbuf_set_frag_is_wordstream(msdu, qdf_nbuf_get_num_frags(msdu) - 1, + 0); + + if (QDF_NBUF_CB_PADDR(msdu) == 0) { + dir = QDF_NBUF_CB_TX_DMA_BI_MAP(msdu) ? + QDF_DMA_BIDIRECTIONAL : QDF_DMA_TO_DEVICE; + status = qdf_nbuf_map_single(qdf_ctx, msdu, dir); + if (qdf_unlikely(status != QDF_STATUS_SUCCESS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: nbuf map failed", __func__); + return QDF_STATUS_E_NOMEM; + } + } + + /* store a link to the HTT tx descriptor within the netbuf */ + qdf_nbuf_frag_push_head(msdu, sizeof(struct htt_host_tx_desc_t), + (char *)htt_host_tx_desc, /* virtual addr */ + htt_tx_desc_paddr); + + /* + * Indicate that the HTT header (and HTC header) is a meta-data + * "wordstream", i.e. series of uint32_t, rather than a data + * bytestream. + * This allows the HIF download to byteswap the HTT + HTC headers if + * the host is big-endian, to convert to the target's little-endian + * format. + */ + qdf_nbuf_set_frag_is_wordstream(msdu, 0, 1); + + if (qdf_likely(pdev->cfg.ce_classify_enabled && + (msdu_info->info.l2_hdr_type != htt_pkt_type_mgmt))) { + uint32_t pkt_offset = qdf_nbuf_get_frag_len(msdu, 0); + + data_attr = hw_classify << CE_DESC_TX_CLASSIFY_BIT_S; + data_attr |= ce_pkt_type << CE_DESC_PKT_TYPE_BIT_S; + data_attr |= pkt_offset << CE_DESC_PKT_OFFSET_BIT_S; + } + + qdf_nbuf_data_attr_set(msdu, data_attr); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * htt_tx_group_credit_process() - process group data for + * credit update indication + * @pdev: pointer to htt device. + * @msg_word: htt msg + * + * Return: None + */ +void htt_tx_group_credit_process(struct htt_pdev_t *pdev, u_int32_t *msg_word) +{ + int group_credit_sign; + int32_t group_credit; + u_int32_t group_credit_abs, vdev_id_mask, ac_mask; + u_int8_t group_abs, group_id; + u_int8_t group_offset = 0, more_group_present = 0; + + more_group_present = HTT_TX_CREDIT_TXQ_GRP_GET(*msg_word); + + while (more_group_present) { + /* Parse the Group Data */ + group_id = HTT_TXQ_GROUP_ID_GET(*(msg_word+1 + +group_offset)); + group_credit_abs = + HTT_TXQ_GROUP_CREDIT_COUNT_GET(*(msg_word+1 + +group_offset)); + group_credit_sign = + HTT_TXQ_GROUP_SIGN_GET(*(msg_word+1 + +group_offset)) ? -1 : 1; + group_credit = group_credit_sign * group_credit_abs; + group_abs = HTT_TXQ_GROUP_ABS_GET(*(msg_word+1 + +group_offset)); + + vdev_id_mask = + HTT_TXQ_GROUP_VDEV_ID_MASK_GET(*(msg_word+2 + +group_offset)); + ac_mask = HTT_TXQ_GROUP_AC_MASK_GET(*(msg_word+2 + +group_offset)); + + ol_txrx_update_tx_queue_groups(pdev->txrx_pdev, group_id, + group_credit, group_abs, + vdev_id_mask, ac_mask); + more_group_present = HTT_TXQ_GROUP_EXT_GET(*(msg_word+1 + +group_offset)); + group_offset += HTT_TX_GROUP_INDEX_OFFSET; + } + ol_tx_update_group_credit_stats(pdev->txrx_pdev); +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_types.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_types.h new file mode 100644 index 0000000000..d20d3d3e80 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/htt_types.h @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2011, 2014-2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HTT_TYPES__H_ +#define _HTT_TYPES__H_ + +#include /* uint16_t, dma_addr_t */ +#include /* qdf_device_t */ +#include /* qdf_spinlock_t */ +#include /* qdf_timer_t */ +#include /* qdf_atomic_inc */ +#include /* qdf_nbuf_t */ +#include /* HTC_PACKET */ +#include +#include +#define DEBUG_DMA_DONE + +#define HTT_TX_MUTEX_TYPE qdf_spinlock_t + +#ifdef QCA_TX_HTT2_SUPPORT +#ifndef HTC_TX_HTT2_MAX_SIZE +/* Should sync to the target's implementation. */ +#define HTC_TX_HTT2_MAX_SIZE (120) +#endif +#endif /* QCA_TX_HTT2_SUPPORT */ + +/* + * Set the base misclist size to the size of the htt tx copy engine + * to guarantee that a packet on the misclist won't be freed while it + * is sitting in the copy engine. + */ +#define HTT_HTC_PKT_MISCLIST_SIZE 2048 + +struct htt_htc_pkt { + void *pdev_ctxt; + target_paddr_t nbuf_paddr; + HTC_PACKET htc_pkt; + uint16_t msdu_id; +}; + +struct htt_htc_pkt_union { + union { + struct htt_htc_pkt pkt; + struct htt_htc_pkt_union *next; + } u; +}; + +/* + * HTT host descriptor: + * Include the htt_tx_msdu_desc that gets downloaded to the target, + * but also include the HTC_FRAME_HDR and alignment padding that + * precede the htt_tx_msdu_desc. + * htc_send_data_pkt expects this header space at the front of the + * initial fragment (i.e. tx descriptor) that is downloaded. + */ +struct htt_host_tx_desc_t { + uint8_t htc_header[HTC_HEADER_LEN]; + /* force the tx_desc field to begin on a 4-byte boundary */ + union { + uint32_t dummy_force_align; + struct htt_tx_msdu_desc_t tx_desc; + } align32; +}; + +struct htt_list_node { + struct htt_list_node *prev; + struct htt_list_node *next; +}; + +struct htt_rx_hash_entry { + qdf_dma_addr_t paddr; + qdf_nbuf_t netbuf; + A_UINT8 fromlist; + struct htt_list_node listnode; +#ifdef RX_HASH_DEBUG + A_UINT32 cookie; +#endif +}; + +struct htt_rx_hash_bucket { + struct htt_list_node listhead; + struct htt_rx_hash_entry *entries; + struct htt_list_node freepool; +#ifdef RX_HASH_DEBUG + A_UINT32 count; +#endif +}; + +/* + * Micro controller datapath offload + * WLAN TX resources + */ +struct htt_ipa_uc_tx_resource_t { + qdf_shared_mem_t *tx_ce_idx; + qdf_shared_mem_t *tx_comp_ring; + + qdf_dma_addr_t tx_comp_idx_paddr; + qdf_shared_mem_t **tx_buf_pool_strg; + uint32_t alloc_tx_buf_cnt; + bool ipa_smmu_mapped; +}; + +/** + * struct htt_ipa_uc_rx_resource_t + * @rx_rdy_idx_paddr: rx ready index physical address + * @rx_ind_ring: rx indication ring memory info + * @rx_ipa_prc_done_idx: rx process done index memory info + * @rx2_ind_ring: rx2 indication ring memory info + * @rx2_ipa_prc_done_idx: rx2 process done index memory info + */ +struct htt_ipa_uc_rx_resource_t { + qdf_dma_addr_t rx_rdy_idx_paddr; + qdf_shared_mem_t *rx_ind_ring; + qdf_shared_mem_t *rx_ipa_prc_done_idx; + + /* 2nd RX ring */ + qdf_shared_mem_t *rx2_ind_ring; + qdf_shared_mem_t *rx2_ipa_prc_done_idx; +}; + +/** + * struct ipa_uc_rx_ring_elem_t + * @rx_packet_paddr: rx packet physical address + * @vdev_id: virtual interface id + * @rx_packet_leng: packet length + */ +#if HTT_PADDR64 +struct ipa_uc_rx_ring_elem_t { + target_paddr_t rx_packet_paddr; + uint32_t vdev_id; + uint32_t rx_packet_leng; +}; +#else +struct ipa_uc_rx_ring_elem_t { + target_paddr_t rx_packet_paddr; + uint16_t vdev_id; + uint16_t rx_packet_leng; +}; +#endif + +struct htt_tx_credit_t { + qdf_atomic_t bus_delta; + qdf_atomic_t target_delta; +}; + +#if defined(HELIUMPLUS) +/** + * msdu_ext_frag_desc: + * semantically, this is an array of 6 of 2-tuples of + * a 48-bit physical address and a 16 bit len field + * with the following layout: + * 31 16 8 0 + * | p t r - l o w 3 2 | + * | len | ptr-7/16 | + */ +struct msdu_ext_frag_desc { + union { + uint64_t desc64; + struct { + uint32_t ptr_low; + uint32_t ptr_hi:16, + len:16; + } frag32; + } u; +}; + +struct msdu_ext_desc_t { + struct qdf_tso_flags_t tso_flags; + struct msdu_ext_frag_desc frags[6]; +/* + * u_int32_t frag_ptr0; + * u_int32_t frag_len0; + * u_int32_t frag_ptr1; + * u_int32_t frag_len1; + * u_int32_t frag_ptr2; + * u_int32_t frag_len2; + * u_int32_t frag_ptr3; + * u_int32_t frag_len3; + * u_int32_t frag_ptr4; + * u_int32_t frag_len4; + * u_int32_t frag_ptr5; + * u_int32_t frag_len5; + */ +}; +#endif /* defined(HELIUMPLUS) */ + +/** + * struct mon_channel + * @ch_num: Monitor mode capture channel number + * @ch_freq: channel frequency. + */ +struct mon_channel { + uint32_t ch_num; + uint32_t ch_freq; +}; + +struct htt_pdev_t { + struct cdp_cfg *ctrl_pdev; + ol_txrx_pdev_handle txrx_pdev; + HTC_HANDLE htc_pdev; + qdf_device_t osdev; + + HTC_ENDPOINT_ID htc_tx_endpoint; + +#ifdef QCA_TX_HTT2_SUPPORT + HTC_ENDPOINT_ID htc_tx_htt2_endpoint; + uint16_t htc_tx_htt2_max_size; +#endif /* QCA_TX_HTT2_SUPPORT */ + +#ifdef ATH_11AC_TXCOMPACT + HTT_TX_MUTEX_TYPE txnbufq_mutex; + qdf_nbuf_queue_t txnbufq; + struct htt_htc_pkt_union *htt_htc_pkt_misclist; +#endif + + struct htt_htc_pkt_union *htt_htc_pkt_freelist; + struct { + int is_high_latency; + int is_full_reorder_offload; + int default_tx_comp_req; + int ce_classify_enabled; + uint8_t is_first_wakeup_packet; + /* + * To track if credit reporting through + * HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND is enabled/disabled. + * In Genoa(QCN7605) credits are reported through + * HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND only. + */ + u8 credit_update_enabled; + /* Explicitly request TX completions. */ + u8 request_tx_comp; + } cfg; + struct { + uint8_t major; + uint8_t minor; + } tgt_ver; +#if defined(HELIUMPLUS) + struct { + u_int8_t major; + u_int8_t minor; + } wifi_ip_ver; +#endif /* defined(HELIUMPLUS) */ + struct { + struct { + /* + * Ring of network buffer objects - + * This ring is used exclusively by the host SW. + * This ring mirrors the dev_addrs_ring that is shared + * between the host SW and the MAC HW. + * The host SW uses this netbufs ring to locate the nw + * buffer objects whose data buffers the HW has filled. + */ + qdf_nbuf_t *netbufs_ring; + /* + * Ring of buffer addresses - + * This ring holds the "physical" device address of the + * rx buffers the host SW provides for MAC HW to fill. + */ +#if HTT_PADDR64 + uint64_t *paddrs_ring; +#else /* ! HTT_PADDR64 */ + uint32_t *paddrs_ring; +#endif + qdf_dma_mem_context(memctx); + } buf; + /* + * Base address of ring, as a "physical" device address rather + * than a CPU address. + */ + qdf_dma_addr_t base_paddr; + int32_t size; /* how many elems in the ring (power of 2) */ + uint32_t size_mask; /* size - 1, at least 16 bits long */ + + int fill_level; /* how many rx buffers to keep in the ring */ + /* # of rx buffers (full+empty) in the ring */ + qdf_atomic_t fill_cnt; + int pop_fail_cnt; /* # of nebuf pop failures */ + + /* + * target_idx - + * Without reorder offload: + * not used + * With reorder offload: + * points to the location in the rx ring from which rx buffers + * are available to copy into the MAC DMA ring + */ + struct { + uint32_t *vaddr; + qdf_dma_addr_t paddr; + qdf_dma_mem_context(memctx); + } target_idx; + + /* + * alloc_idx/host_idx - + * Without reorder offload: + * where HTT SW has deposited empty buffers + * This is allocated in consistent mem, so that the FW can read + * this variable, and program the HW's FW_IDX reg with the value + * of this shadow register + * With reorder offload: + * points to the end of the available free rx buffers + */ + struct { + uint32_t *vaddr; + qdf_dma_addr_t paddr; + qdf_dma_mem_context(memctx); + } alloc_idx; + + /* + * sw_rd_idx - + * where HTT SW has processed bufs filled by rx MAC DMA + */ + struct { + unsigned int msdu_desc; + unsigned int msdu_payld; + } sw_rd_idx; + + /* + * refill_retry_timer - timer triggered when the ring is not + * refilled to the level expected + */ + qdf_timer_t refill_retry_timer; + + /* + * refill_ref_cnt - ref cnt for Rx buffer replenishment - this + * variable is used to guarantee that only one thread tries + * to replenish Rx ring. + */ + qdf_atomic_t refill_ref_cnt; + qdf_spinlock_t refill_lock; + qdf_atomic_t refill_debt; +#ifdef DEBUG_DMA_DONE + uint32_t dbg_initial_msdu_payld; + uint32_t dbg_mpdu_range; + uint32_t dbg_mpdu_count; + uint32_t dbg_ring_idx; + uint32_t dbg_refill_cnt; + uint32_t dbg_sync_success; +#endif +#ifdef HTT_RX_RESTORE + int rx_reset; + uint8_t htt_rx_restore; +#endif + qdf_spinlock_t rx_hash_lock; + struct htt_rx_hash_bucket **hash_table; + uint32_t listnode_offset; + bool smmu_map; + } rx_ring; + +#ifndef CONFIG_HL_SUPPORT + struct { + qdf_atomic_t fill_cnt; /* # of buffers in pool */ + qdf_atomic_t refill_low_mem; /* if set refill the ring */ + qdf_nbuf_t *netbufs_ring; + qdf_spinlock_t rx_buff_pool_lock; + } rx_buff_pool; +#endif + +#ifdef CONFIG_HL_SUPPORT + int rx_desc_size_hl; +#endif + long rx_fw_desc_offset; + int rx_mpdu_range_offset_words; + int rx_ind_msdu_byte_idx; + + struct { + int size; /* of each HTT tx desc */ + uint16_t pool_elems; + uint16_t alloc_cnt; + struct qdf_mem_multi_page_t desc_pages; + uint32_t *freelist; + qdf_dma_mem_context(memctx); + } tx_descs; +#if defined(HELIUMPLUS) + struct { + int size; /* of each Fragment/MSDU-Ext descriptor */ + int pool_elems; + struct qdf_mem_multi_page_t desc_pages; + qdf_dma_mem_context(memctx); + } frag_descs; +#endif /* defined(HELIUMPLUS) */ + + int download_len; + void (*tx_send_complete_part2)(void *pdev, A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id); + + HTT_TX_MUTEX_TYPE htt_tx_mutex; + HTT_TX_MUTEX_TYPE credit_mutex; + + struct { + int htc_err_cnt; + } stats; +#ifdef CONFIG_HL_SUPPORT + int cur_seq_num_hl; +#endif + struct targetdef_s *targetdef; + struct ce_reg_def *target_ce_def; + + struct htt_ipa_uc_tx_resource_t ipa_uc_tx_rsc; + struct htt_ipa_uc_rx_resource_t ipa_uc_rx_rsc; + int is_ipa_uc_enabled; + + struct htt_tx_credit_t htt_tx_credit; + +#ifdef DEBUG_RX_RING_BUFFER + struct rx_buf_debug *rx_buff_list; + qdf_spinlock_t rx_buff_list_lock; + int rx_buff_index; + int rx_buff_posted_cum; + int rx_buff_recvd_cum; + int rx_buff_recvd_err; +#endif + /* + * Counters below are being invoked from functions defined outside of + * DEBUG_RX_RING_BUFFER + */ + int rx_buff_debt_invoked; + int rx_buff_fill_n_invoked; + int refill_retry_timer_starts; + int refill_retry_timer_calls; + int refill_retry_timer_doubles; + + /* callback function for packetdump */ + tp_rx_pkt_dump_cb rx_pkt_dump_cb; + + struct mon_channel mon_ch_info; + + /* Flag to indicate whether new htt format is supported */ + bool new_htt_format_enabled; +}; + +#define HTT_EPID_GET(_htt_pdev_hdl) \ + (((struct htt_pdev_t *)(_htt_pdev_hdl))->htc_tx_endpoint) + +#if defined(HELIUMPLUS) +#define HTT_WIFI_IP(pdev, x, y) (((pdev)->wifi_ip_ver.major == (x)) && \ + ((pdev)->wifi_ip_ver.minor == (y))) + +#define HTT_SET_WIFI_IP(pdev, x, y) (((pdev)->wifi_ip_ver.major = (x)) && \ + ((pdev)->wifi_ip_ver.minor = (y))) +#endif /* defined(HELIUMPLUS) */ + +#endif /* _HTT_TYPES__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/rx_desc.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/rx_desc.h new file mode 100644 index 0000000000..cd31a86a86 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/htt/rx_desc.h @@ -0,0 +1,534 @@ +/* + * Copyright (c) 2011-2015, 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _RX_DESC_H_ +#define _RX_DESC_H_ + +/* + * REMIND: Copy one of rx_desc related structures here for export, + * hopes they are always the same between Peregrine and Rome in future + */ +struct rx_attention { + volatile + uint32_t first_mpdu:1, /* [0] */ + last_mpdu:1, /* [1] */ + mcast_bcast:1, /* [2] */ + peer_idx_invalid:1, /* [3] */ + peer_idx_timeout:1, /* [4] */ + power_mgmt:1, /* [5] */ + non_qos:1, /* [6] */ + null_data:1, /* [7] */ + mgmt_type:1, /* [8] */ + ctrl_type:1, /* [9] */ + more_data:1, /* [10] */ + eosp:1, /* [11] */ + u_apsd_trigger:1, /* [12] */ + fragment:1, /* [13] */ + order:1, /* [14] */ + classification:1, /* [15] */ + overflow_err:1, /* [16] */ + msdu_length_err:1, /* [17] */ + tcp_udp_chksum_fail:1, /* [18] */ + ip_chksum_fail:1, /* [19] */ + sa_idx_invalid:1, /* [20] */ + da_idx_invalid:1, /* [21] */ + sa_idx_timeout:1, /* [22] */ + da_idx_timeout:1, /* [23] */ + encrypt_required:1, /* [24] */ + directed:1, /* [25] */ + buffer_fragment:1, /* [26] */ + mpdu_length_err:1, /* [27] */ + tkip_mic_err:1, /* [28] */ + decrypt_err:1, /* [29] */ + fcs_err:1, /* [30] */ + msdu_done:1; /* [31] */ +}; + +struct rx_frag_info { + volatile + uint32_t ring0_more_count:8, /* [7:0] */ + ring1_more_count:8, /* [15:8] */ + ring2_more_count:8, /* [23:16] */ + ring3_more_count:8; /* [31:24] */ + volatile + uint32_t ring4_more_count:8, /* [7:0] */ + ring5_more_count:8, /* [15:8] */ + ring6_more_count:8, /* [23:16] */ + ring7_more_count:8; /* [31:24] */ +}; + +struct rx_msdu_start { + volatile + uint32_t msdu_length:14, /* [13:0] */ +#if defined(HELIUMPLUS) + l3_offset:7, /* [20:14] */ + ipsec_ah:1, /* [21] */ + reserved_0a:2, /* [23:22] */ + l4_offset:7, /* [30:24] */ + ipsec_esp:1; /* [31] */ +#else + ip_offset:6, /* [19:14] */ + ring_mask:4, /* [23:20] */ + tcp_udp_offset:7, /* [30:24] */ + reserved_0c:1; /* [31] */ +#endif /* defined(HELIUMPLUS) */ +#if defined(HELIUMPLUS) + volatile uint32_t flow_id_toeplitz:32; /* [31:0] */ +#else + volatile uint32_t flow_id_crc:32; /* [31:0] */ +#endif /* defined(HELIUMPLUS) */ + volatile + uint32_t msdu_number:8, /* [7:0] */ + decap_format:2, /* [9:8] */ + ipv4_proto:1, /* [10] */ + ipv6_proto:1, /* [11] */ + tcp_proto:1, /* [12] */ + udp_proto:1, /* [13] */ + ip_frag:1, /* [14] */ + tcp_only_ack:1, /* [15] */ + sa_idx:11, /* [26:16] */ + reserved_2b:5; /* [31:27] */ +#if defined(HELIUMPLUS) + volatile + uint32_t da_idx:11, /* [10:0] */ + da_is_bcast_mcast:1, /* [11] */ + reserved_3a:4, /* [15:12] */ + ip4_protocol_ip6_next_header:8, /* [23:16] */ + ring_mask:8; /* [31:24] */ + volatile uint32_t toeplitz_hash_2_or_4:32; /* [31:0] */ +#endif /* defined(HELIUMPLUS) */ +}; + +struct rx_msdu_end { + volatile + uint32_t ip_hdr_chksum:16, /* [15:0] */ + tcp_udp_chksum:16; /* [31:16] */ + volatile + uint32_t key_id_octet:8, /* [7:0] */ +#if defined(HELIUMPLUS) + classification_rule:6, /* [13:8] */ + classify_not_done_truncate:1, /* [14] */ + classify_not_done_cce_dis:1, /* [15] */ +#else + classification_filter:8, /* [15:8] */ +#endif /* defined(HELIUMPLUS) */ + ext_wapi_pn_63_48:16; /* [31:16] */ + volatile uint32_t ext_wapi_pn_95_64:32; /* [31:0] */ + volatile uint32_t ext_wapi_pn_127_96:32; /* [31:0] */ + volatile + uint32_t reported_mpdu_length:14, /* [13:0] */ + first_msdu:1, /* [14] */ + last_msdu:1, /* [15] */ +#if defined(HELIUMPLUS) + sa_idx_timeout:1, /* [16] */ + da_idx_timeout:1, /* [17] */ + msdu_limit_error:1, /* [18] */ + classify_ring_mask:8, /* [26:19] */ +#endif /* defined(HELIUMPLUS) */ + reserved_3a:3, /* [29:27] */ + pre_delim_err:1, /* [30] */ + reserved_3b:1; /* [31] */ +#if defined(HELIUMPLUS) + volatile uint32_t ipv6_options_crc:32; + volatile uint32_t tcp_seq_number:32; + volatile uint32_t tcp_ack_number:32; + volatile + uint32_t tcp_flag:9, /* [8:0] */ + lro_eligible:1, /* [9] */ + l3_header_padding:3, /* [12:10] */ + reserved_8a:3, /* [15:13] */ + window_size:16; /* [31:16] */ + volatile + uint32_t da_offset:6, /* [5:0] */ + sa_offset:6, /* [11:6] */ + da_offset_valid:1, /* [12] */ + sa_offset_valid:1, /* [13] */ + type_offset:7, /* [20:14] */ + reserved_9a:11; /* [31:21] */ + volatile uint32_t rule_indication_31_0:32; + volatile uint32_t rule_indication_63_32:32; + volatile uint32_t rule_indication_95_64:32; + volatile uint32_t rule_indication_127_96:32; +#endif /* defined(HELIUMPLUS) */ +}; + +struct rx_mpdu_end { + volatile + uint32_t reserved_0:13, /* [12:0] */ + overflow_err:1, /* [13] */ + last_mpdu:1, /* [14] */ + post_delim_err:1, /* [15] */ + post_delim_cnt:12, /* [27:16] */ + mpdu_length_err:1, /* [28] */ + tkip_mic_err:1, /* [29] */ + decrypt_err:1, /* [30] */ + fcs_err:1; /* [31] */ +}; + + +#if defined(HELIUMPLUS) + +struct rx_mpdu_start { + volatile + uint32_t peer_idx:11, /* [10:0] */ + fr_ds:1, /* [11] */ + to_ds:1, /* [12] */ + encrypted:1, /* [13] */ + retry:1, /* [14] */ + reserved:1, /* [15] */ + seq_num:12, /* [27:16] */ + encrypt_type:4; /* [31:28] */ + volatile uint32_t pn_31_0:32; /* [31:0] */ + volatile + uint32_t pn_47_32:16, /* [15:0] */ + toeplitz_hash:2, /* [17:16] */ + reserved_2:10, /* [27:18] */ + tid:4; /* [31:28] */ +}; + + +struct rx_ppdu_start { + volatile + uint32_t rssi_pri_chain0:8, /* [7:0] */ + rssi_sec20_chain0:8, /* [15:8] */ + rssi_sec40_chain0:8, /* [23:16] */ + rssi_sec80_chain0:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain1:8, /* [7:0] */ + rssi_sec20_chain1:8, /* [15:8] */ + rssi_sec40_chain1:8, /* [23:16] */ + rssi_sec80_chain1:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain2:8, /* [7:0] */ + rssi_sec20_chain2:8, /* [15:8] */ + rssi_sec40_chain2:8, /* [23:16] */ + rssi_sec80_chain2:8; /* [31:24] */ + volatile + uint32_t rssi_pri_chain3:8, /* [7:0] */ + rssi_sec20_chain3:8, /* [15:8] */ + rssi_sec40_chain3:8, /* [23:16] */ + rssi_sec80_chain3:8; /* [31:24] */ + volatile + uint32_t rssi_comb:8, /* [7:0] */ + bandwidth:3, /* [10:8] */ + reserved_4a:5, /* [15:11] */ + rssi_comb_ht:8, /* [23:16] */ + reserved_4b:8; /* [31:24] */ + volatile + uint32_t l_sig_rate:4, /*[3:0] */ + l_sig_rate_select:1, /* [4] */ + l_sig_length:12, /* [16:5] */ + l_sig_parity:1, /* [17] */ + l_sig_tail:6, /* [23:18] */ + preamble_type:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_ah_sig_a_1:24, /* [23:0] */ + captured_implicit_sounding:1, /* [24] */ + reserved_6:7; /* [31:25] */ + volatile + uint32_t ht_sig_vht_sig_ah_sig_a_2:24, /* [23:0] */ + reserved_7:8; /* [31:24] */ + volatile uint32_t vht_sig_b:32; /* [31:0] */ + volatile + uint32_t service:16, /* [15:0] */ + reserved_9:16; /* [31:16] */ +}; + +#define VHT_SIG_A_1(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_ah_sig_a_1) +#define VHT_SIG_A_2(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_ah_sig_a_2) +#define TSF_TIMESTAMP(rx_desc) \ +((rx_desc)->ppdu_end.rx_pkt_end.phy_timestamp_1_lower_32) + +struct rx_location_info { + volatile + uint32_t rtt_fac_legacy:14, /* [13:0] */ + rtt_fac_legacy_status:1, /* [14] */ + rtt_fac_vht:14, /* [28:15] */ + rtt_fac_vht_status:1, /* [29] */ + rtt_cfr_status:1, /* [30] */ + rtt_cir_status:1; /* [31] */ + volatile + uint32_t rtt_fac_sifs:10, /* [9:0] */ + rtt_fac_sifs_status:2, /* [11:10] */ + rtt_channel_dump_size:11, /* [22:12] */ + rtt_mac_phy_phase:2, /* [24:23] */ + rtt_hw_ifft_mode:1, /* [25] */ + rtt_btcf_status:1, /* [26] */ + rtt_preamble_type:2, /* [28:27] */ + rtt_pkt_bw:2, /* [30:29] */ + rtt_gi_type:1; /* [31] */ + volatile + uint32_t rtt_mcs_rate:4, /* [3:0] */ + rtt_strongest_chain:2, /* [5:4] */ + rtt_phase_jump:7, /* [12:6] */ + rtt_rx_chain_mask:4, /* [16:13] */ + rtt_tx_data_start_x_phase:1, /* [17] */ + reserved_2:13, /* [30:18] */ + rx_location_info_valid:1; /* [31] */ +}; + +struct rx_pkt_end { + volatile + uint32_t rx_success:1, /* [0] */ + reserved_0a:2, /* [2:1] */ + error_tx_interrupt_rx:1, /* [3] */ + error_ofdm_power_drop:1, /* [4] */ + error_ofdm_restart:1, /* [5] */ + error_cck_power_drop:1, /* [6] */ + error_cck_restart:1, /* [7] */ + reserved_0b:24; /* [31:8] */ + volatile uint32_t phy_timestamp_1_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_1_upper_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_2_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_2_upper_32:32; /* [31:0] */ + struct rx_location_info rx_location_info; +}; + +struct rx_phy_ppdu_end { + volatile + uint32_t reserved_0a:2, /* [1:0] */ + error_radar:1, /* [2] */ + error_rx_abort:1, /* [3] */ + error_rx_nap:1, /* [4] */ + error_ofdm_timing:1, /* [5] */ + error_ofdm_signal_parity:1, /* [6] */ + error_ofdm_rate_illegal:1, /* [7] */ + error_ofdm_length_illegal:1, /* [8] */ + error_ppdu_ofdm_restart:1, /* [9] */ + error_ofdm_service:1, /* [10] */ + error_ppdu_ofdm_power_drop:1, /* [11] */ + error_cck_blocker:1, /* [12] */ + error_cck_timing:1, /* [13] */ + error_cck_header_crc:1, /* [14] */ + error_cck_rate_illegal:1, /* [15] */ + error_cck_length_illegal:1, /* [16] */ + error_ppdu_cck_restart:1, /* [17] */ + error_cck_service:1, /* [18] */ + error_ppdu_cck_power_drop:1, /* [19] */ + error_ht_crc_err:1, /* [20] */ + error_ht_length_illegal:1, /* [21] */ + error_ht_rate_illegal:1, /* [22] */ + error_ht_zlf:1, /* [23] */ + error_false_radar_ext:1, /* [24] */ + error_green_field:1, /* [25] */ + error_spectral_scan:1, /* [26] */ + error_rx_bw_gt_dyn_bw:1, /* [27] */ + error_leg_ht_mismatch:1, /* [28] */ + error_vht_crc_error:1, /* [29] */ + error_vht_siga_unsupported:1, /* [30] */ + error_vht_lsig_len_invalid:1; /* [31] */ + volatile + uint32_t error_vht_ndp_or_zlf:1, /* [0] */ + error_vht_nsym_lt_zero:1, /* [1] */ + error_vht_rx_extra_symbol_mismatch:1, /* [2] */ + error_vht_rx_skip_group_id0:1, /* [3] */ + error_vht_rx_skip_group_id1to62:1, /* [4] */ + error_vht_rx_skip_group_id63:1, /* [5] */ + error_ofdm_ldpc_decoder_disabled:1, /* [6] */ + error_defer_nap:1, /* [7] */ + error_fdomain_timeout:1, /* [8] */ + error_lsig_rel_check:1, /* [9] */ + error_bt_collision:1, /* [10] */ + error_unsupported_mu_feedback:1, /* [11] */ + error_ppdu_tx_interrupt_rx:1, /* [12] */ + error_rx_unsupported_cbf:1, /* [13] */ + reserved_1:18; /* [31:14] */ +}; + +struct rx_timing_offset { + volatile + uint32_t timing_offset:12, /* [11:0] */ + reserved:20; /* [31:12] */ +}; + +struct rx_ppdu_end { + volatile uint32_t evm_p0:32; + volatile uint32_t evm_p1:32; + volatile uint32_t evm_p2:32; + volatile uint32_t evm_p3:32; + volatile uint32_t evm_p4:32; + volatile uint32_t evm_p5:32; + volatile uint32_t evm_p6:32; + volatile uint32_t evm_p7:32; + volatile uint32_t evm_p8:32; + volatile uint32_t evm_p9:32; + volatile uint32_t evm_p10:32; + volatile uint32_t evm_p11:32; + volatile uint32_t evm_p12:32; + volatile uint32_t evm_p13:32; + volatile uint32_t evm_p14:32; + volatile uint32_t evm_p15:32; + volatile uint32_t reserved_16:32; + volatile uint32_t reserved_17:32; + volatile uint32_t wb_timestamp_lower_32:32; + volatile uint32_t wb_timestamp_upper_32:32; + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + struct rx_timing_offset rx_timing_offset; + volatile + uint32_t rx_antenna:24, /* [23:0] */ + tx_ht_vht_ack:1, /* [24] */ + rx_pkt_end_valid:1, /* [25] */ + rx_phy_ppdu_end_valid:1, /* [26] */ + rx_timing_offset_valid:1, /* [27] */ + bb_captured_channel:1, /* [28] */ + unsupported_mu_nc:1, /* [29] */ + otp_txbf_disable:1, /* [30] */ + reserved_31:1; /* [31] */ + volatile + uint32_t coex_bt_tx_from_start_of_rx:1, /* [0] */ + coex_bt_tx_after_start_of_rx:1, /* [1] */ + coex_wan_tx_from_start_of_rx:1, /* [2] */ + coex_wan_tx_after_start_of_rx:1, /* [3] */ + coex_wlan_tx_from_start_of_rx:1, /* [4] */ + coex_wlan_tx_after_start_of_rx:1, /* [5] */ + mpdu_delimiter_errors_seen:1, /* [6] */ + ftm:1, /* [7] */ + ftm_dialog_token:8, /* [15:8] */ + ftm_follow_up_dialog_token:8, /* [23:16] */ + reserved_32:8; /* [31:24] */ + volatile + uint32_t before_mpdu_cnt_passing_fcs:8, /* [7:0] */ + before_mpdu_cnt_failing_fcs:8, /* [15:8] */ + after_mpdu_cnt_passing_fcs:8, /* [23:16] */ + after_mpdu_cnt_failing_fcs:8; /* [31:24] */ + volatile uint32_t phy_timestamp_tx_lower_32:32; /* [31:0] */ + volatile uint32_t phy_timestamp_tx_upper_32:32; /* [31:0] */ + volatile + uint32_t bb_length:16, /* [15:0] */ + bb_data:1, /* [16] */ + peer_idx_valid:1, /* [17] */ + peer_idx:11, /* [28:18] */ + reserved_26:2, /* [30:29] */ + ppdu_done:1; /* [31] */ +}; +#else +struct rx_ppdu_start { + volatile + uint32_t rssi_chain0_pri20:8, /* [7:0] */ + rssi_chain0_sec20:8, /* [15:8] */ + rssi_chain0_sec40:8, /* [23:16] */ + rssi_chain0_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain1_pri20:8, /* [7:0] */ + rssi_chain1_sec20:8, /* [15:8] */ + rssi_chain1_sec40:8, /* [23:16] */ + rssi_chain1_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain2_pri20:8, /* [7:0] */ + rssi_chain2_sec20:8, /* [15:8] */ + rssi_chain2_sec40:8, /* [23:16] */ + rssi_chain2_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_chain3_pri20:8, /* [7:0] */ + rssi_chain3_sec20:8, /* [15:8] */ + rssi_chain3_sec40:8, /* [23:16] */ + rssi_chain3_sec80:8; /* [31:24] */ + volatile + uint32_t rssi_comb:8, /* [7:0] */ + reserved_4a:16, /* [23:8] */ + is_greenfield:1, /* [24] */ + reserved_4b:7; /* [31:25] */ + volatile + uint32_t l_sig_rate:4, /* [3:0] */ + l_sig_rate_select:1, /* [4] */ + l_sig_length:12, /* [16:5] */ + l_sig_parity:1, /* [17] */ + l_sig_tail:6, /* [23:18] */ + preamble_type:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_a_1:24, /* [23:0] */ + reserved_6:8; /* [31:24] */ + volatile + uint32_t ht_sig_vht_sig_a_2:24, /* [23:0] */ + txbf_h_info:1, /* [24] */ + reserved_7:7; /* [31:25] */ + volatile + uint32_t vht_sig_b:29, /* [28:0] */ + reserved_8:3; /* [31:29] */ + volatile + uint32_t service:16, /* [15:0] */ + reserved_9:16; /* [31:16] */ +}; + +#define VHT_SIG_A_1(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_a_1) +#define VHT_SIG_A_2(rx_desc) ((rx_desc)->ppdu_start.ht_sig_vht_sig_a_2) + +#define TSF_TIMESTAMP(rx_desc) ((rx_desc)->ppdu_end.tsf_timestamp) + +struct rx_mpdu_start { + volatile + uint32_t peer_idx:11, /* [10:0] */ + fr_ds:1, /* [11] */ + to_ds:1, /* [12] */ + encrypted:1, /* [13] */ + retry:1, /* [14] */ + txbf_h_info:1, /* [15] */ + seq_num:12, /* [27:16] */ + encrypt_type:4; /* [31:28] */ + volatile uint32_t pn_31_0:32; /* [31:0] */ + volatile + uint32_t pn_47_32:16, /* [15:0] */ + directed:1, /* [16] */ + reserved_2:11, /* [27:17] */ + tid:4; /* [31:28] */ +}; + +struct rx_ppdu_end { + volatile uint32_t evm_p0:32; /* [31:0] */ + volatile uint32_t evm_p1:32; /* [31:0] */ + volatile uint32_t evm_p2:32; /* [31:0] */ + volatile uint32_t evm_p3:32; /* [31:0] */ + volatile uint32_t evm_p4:32; /* [31:0] */ + volatile uint32_t evm_p5:32; /* [31:0] */ + volatile uint32_t evm_p6:32; /* [31:0] */ + volatile uint32_t evm_p7:32; /* [31:0] */ + volatile uint32_t evm_p8:32; /* [31:0] */ + volatile uint32_t evm_p9:32; /* [31:0] */ + volatile uint32_t evm_p10:32; /* [31:0] */ + volatile uint32_t evm_p11:32; /* [31:0] */ + volatile uint32_t evm_p12:32; /* [31:0] */ + volatile uint32_t evm_p13:32; /* [31:0] */ + volatile uint32_t evm_p14:32; /* [31:0] */ + volatile uint32_t evm_p15:32; /* [31:0] */ + volatile uint32_t tsf_timestamp:32; /* [31:0] */ + volatile uint32_t wb_timestamp:32; /* [31:0] */ + volatile + uint32_t locationing_timestamp:8, /* [7:0] */ + phy_err_code:8, /* [15:8] */ + phy_err:1, /* [16] */ + rx_location:1, /* [17] */ + txbf_h_info:1, /* [18] */ + reserved_18:13; /* [31:19] */ + volatile + uint32_t rx_antenna:24, /* [23:0] */ + tx_ht_vht_ack:1, /* [24] */ + bb_captured_channel:1, /* [25] */ + reserved_19:6; /* [31:26] */ + volatile + uint32_t rtt_correction_value:24, /* [23:0] */ + reserved_20:7, /* [30:24] */ + rtt_normal_mode:1; /* [31] */ + volatile + uint32_t bb_length:16, /* [15:0] */ + reserved_21:15, /* [30:16] */ + ppdu_done:1; /* [31] */ +}; +#endif /* defined(HELIUMPLUS) */ + +#endif /*_RX_DESC_H_*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/cfg_legacy_dp.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/cfg_legacy_dp.h new file mode 100644 index 0000000000..e2d0288651 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/cfg_legacy_dp.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2012-2019, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __CFG_LEGACY_DP +#define __CFG_LEGACY_DP + +#include "cfg_define.h" +#include "cfg_converged.h" +#include "qdf_types.h" + +/* + * + * gEnableFlowSteering - Enable rx traffic flow steering + * @Default: true + * + * Enable Rx traffic flow steering to enable Rx interrupts on multiple CEs based + * on the flows. Different CEs<==>different IRQs<==>probably different CPUs. + * Parallel Rx paths. + * 1 - enable 0 - disable + * + * Usage: Internal + * + * + */ + #define CFG_DP_FLOW_STEERING_ENABLED \ + CFG_INI_BOOL( \ + "gEnableFlowSteering", \ + true, \ + "") + +/* + * + * maxMSDUsPerRxInd - Max number of MSDUs per HTT RX IN ORDER INDICATION msg. + * Note that this has a direct impact on the size of source CE rings. + * It is possible to go below 8, but would require testing; so we are + * restricting the lower limit to 8 artificially + * + * It is recommended that this value is a POWER OF 2. + * + * Values lower than 8 are for experimental purposes only + * + * . + */ +#define CFG_DP_MAX_MSDUS_PER_RXIND \ + CFG_INI_UINT("maxMSDUsPerRxInd", \ + 4, 32, 8, CFG_VALUE_OR_DEFAULT, \ + "Max number of MSDUs per HTT RX INORDER IND msg") + +/* + * + * gEnableTxSchedWrrVO - Set TX sched parameters for VO + * @Default: + * + * This key is mapping to VO defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for VO. + * e.g., gEnableTxSchedWrrVO = 10, 9, 8, 1, 8 + * + * + */ +#define CFG_DP_ENABLE_TX_SCHED_WRR_VO \ + CFG_INI_STRING("gEnableTxSchedWrrVO", \ + 0, 50, "", "et TX sched parameters for VO") + +/* + * + * gEnableTxSchedWrrVI - Set TX sched parameters for VI + * @Default: + * + * This key is mapping to VI defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for VI. + * e.g., gEnableTxSchedWrrVI = 10, 9, 8, 1, 8 + * + * + */ +#define CFG_DP_ENABLE_TX_SCHED_WRR_VI \ + CFG_INI_STRING("gEnableTxSchedWrrVI", \ + 0, 50, "", "Set TX sched parameters for VI") + +/* + * + * gEnableTxSchedWrrBE - Set TX sched parameters for BE + * @Default: + * + * This key is mapping to BE defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for BE. + * e.g., gEnableTxSchedWrrBE = 10, 9, 8, 1, 8 + * + * + */ +#define CFG_DP_ENABLE_TX_SCHED_WRR_BE \ + CFG_INI_STRING("gEnableTxSchedWrrBE", \ + 0, 50, "", "Set TX sched parameters for BE") + +/* + * + * gEnableTxSchedWrrBK - Set TX sched parameters for BK + * @Default: + * + * This key is mapping to BK defined in data path module through + * OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC. The user can tune the + * WRR TX sched parameters such as skip, credit, limit, credit, disc for BK. + * e.g., gEnableTxSchedWrrBK = 10, 9, 8, 1, 8 + * + * + */ +#define CFG_DP_ENABLE_TX_SCHED_WRR_BK \ + CFG_INI_STRING("gEnableTxSchedWrrBK", \ + 0, 50, "", "Set TX sched parameters for BK") + +#define CFG_DP_CE_CLASSIFY_ENABLE \ + CFG_INI_BOOL("gCEClassifyEnable", \ + true, "enable CE classify") + +/* + * + * gEnablePeerUnmapConfSupport - Set PEER UNMAP confirmation support + * Default: false + * 1 - enable 0 - disable + * + * Enable peer unmap confirmation support in the Host. Host will send + * this support to the FW only if FW support is enabled. + * + * + */ +#define CFG_DP_ENABLE_PEER_UMAP_CONF_SUPPORT \ + CFG_INI_BOOL("gEnablePeerUnmapConfSupport", \ + false, "enable PEER UNMAP CONF support") + +#define CFG_LEGACY_DP_ALL \ + CFG(CFG_DP_FLOW_STEERING_ENABLED) \ + CFG(CFG_DP_CE_CLASSIFY_ENABLE) \ + CFG(CFG_DP_MAX_MSDUS_PER_RXIND) \ + CFG(CFG_DP_ENABLE_TX_SCHED_WRR_VO) \ + CFG(CFG_DP_ENABLE_TX_SCHED_WRR_VI) \ + CFG(CFG_DP_ENABLE_TX_SCHED_WRR_BE) \ + CFG(CFG_DP_ENABLE_TX_SCHED_WRR_BK) \ + CFG(CFG_DP_ENABLE_PEER_UMAP_CONF_SUPPORT) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_cfg.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_cfg.h new file mode 100644 index 0000000000..eb77b71843 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_cfg.h @@ -0,0 +1,842 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_CFG__H_ +#define _OL_CFG__H_ + +#include /* uint32_t */ +#include /* ol_pdev_handle */ +#include /* ieee80211_qosframe_htc_addr4 */ +#include /* LLC_SNAP_HDR_LEN */ +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "ol_txrx_ctrl_api.h" /* txrx_pdev_cfg_param_t */ +#include +#include "qca_vendor.h" + +/** + * @brief format of data frames delivered to/from the WLAN driver by/to the OS + */ +enum wlan_frm_fmt { + wlan_frm_fmt_unknown, + wlan_frm_fmt_raw, + wlan_frm_fmt_native_wifi, + wlan_frm_fmt_802_3, +}; + +/* Max throughput */ +#ifdef SLUB_MEM_OPTIMIZE +#define MAX_THROUGHPUT 400 +#else +#define MAX_THROUGHPUT 800 +#endif + +/* Throttle period Different level Duty Cycle values*/ +#define THROTTLE_DUTY_CYCLE_LEVEL0 (0) +#define THROTTLE_DUTY_CYCLE_LEVEL1 (50) +#define THROTTLE_DUTY_CYCLE_LEVEL2 (75) +#define THROTTLE_DUTY_CYCLE_LEVEL3 (94) + +struct wlan_ipa_uc_rsc_t { + u8 uc_offload_enabled; + u32 tx_max_buf_cnt; + u32 tx_buf_size; + u32 rx_ind_ring_size; + u32 tx_partition_base; +}; + +/* Config parameters for txrx_pdev */ +struct txrx_pdev_cfg_t { + u8 is_high_latency; + u8 defrag_timeout_check; + u8 rx_pn_check; + u8 pn_rx_fwd_check; + u8 host_addba; + u8 tx_free_at_download; + u8 rx_fwd_inter_bss; + u32 max_thruput_mbps; + u32 target_tx_credit; + u32 vow_config; + u32 tx_download_size; + u32 max_peer_id; + u32 max_vdev; + u32 max_nbuf_frags; + u32 throttle_period_ms; + u8 dutycycle_level[THROTTLE_LEVEL_MAX]; + enum wlan_frm_fmt frame_type; + u8 rx_fwd_disabled; + u8 is_packet_log_enabled; + u8 is_full_reorder_offload; +#ifdef WLAN_FEATURE_TSF_PLUS + u8 is_ptp_rx_opt_enabled; +#endif + struct wlan_ipa_uc_rsc_t ipa_uc_rsc; + bool ip_tcp_udp_checksum_offload; + bool p2p_ip_tcp_udp_checksum_offload; + /* IP, TCP and UDP checksum offload for NAN Mode*/ + bool nan_tcp_udp_checksumoffload; + bool enable_rxthread; + bool ce_classify_enabled; +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) + uint32_t tx_flow_stop_queue_th; + uint32_t tx_flow_start_queue_offset; +#endif + bool flow_steering_enabled; + /* + * To track if credit reporting through + * HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND is enabled/disabled. + * In Genoa(QCN7605) credits are reported through + * HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND only. + */ + u8 credit_update_enabled; + struct ol_tx_sched_wrr_ac_specs_t ac_specs[QCA_WLAN_AC_ALL]; + bool gro_enable; + bool tso_enable; + bool lro_enable; + bool sg_enable; + uint32_t enable_data_stall_detection; + bool enable_flow_steering; + bool disable_intra_bss_fwd; + /* IPA Micro controller data path offload TX buffer size */ + uint32_t uc_tx_buffer_size; + /* IPA Micro controller data path offload RX indication ring count */ + uint32_t uc_rx_indication_ring_count; + /* IPA Micro controller data path offload TX partition base */ + uint32_t uc_tx_partition_base; + /* Flag to indicate whether new htt format is supported */ + bool new_htt_format_enabled; + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + /* enable the tcp delay ack feature in the driver */ + bool del_ack_enable; + /* timeout if no more tcp ack frames, unit is ms */ + uint16_t del_ack_timer_value; + /* the maximum number of replaced tcp ack frames */ + uint16_t del_ack_pkt_count; +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE + uint16_t bundle_timer_value; + uint16_t bundle_size; +#endif + uint8_t pktlog_buffer_size; +}; + +/** + * ol_tx_set_flow_control_parameters() - set flow control parameters + * @cfg_ctx: cfg context + * @cfg_param: cfg parameters + * + * Return: none + */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +void ol_tx_set_flow_control_parameters(struct cdp_cfg *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param); +#else +static inline +void ol_tx_set_flow_control_parameters(struct cdp_cfg *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param) +{ +} +#endif + +/** + * ol_pdev_cfg_attach - setup configuration parameters + * @osdev: OS handle needed as an argument for some OS primitives + * @cfg_param: configuration parameters + * + * Allocation configuration context that will be used across data path + * + * Return: the control device object + */ +struct cdp_cfg *ol_pdev_cfg_attach(qdf_device_t osdev, void *pcfg_param); + +/** + * @brief Specify whether the system is high-latency or low-latency. + * @details + * Indicate whether the system is operating in high-latency (message + * based, e.g. USB) mode or low-latency (memory-mapped, e.g. PCIe) mode. + * Some chips support just one type of host / target interface. + * Other chips support both LL and HL interfaces (e.g. PCIe and USB), + * so the selection will be made based on which bus HW is present, or + * which is preferred if both are present. + * + * @param pdev - handle to the physical device + * @return 1 -> high-latency -OR- 0 -> low-latency + */ +int ol_cfg_is_high_latency(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify whether credit reporting through + * HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND is enabled by default. + * In Genoa credits are reported only through + * HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND + * @details + * @param pdev - handle to the physical device + * @return 1 -> enabled -OR- 0 -> disabled + */ +int ol_cfg_is_credit_update_enabled(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify the range of peer IDs. + * @details + * Specify the maximum peer ID. This is the maximum number of peers, + * minus one. + * This is used by the host to determine the size of arrays indexed by + * peer ID. + * + * @param pdev - handle to the physical device + * @return maximum peer ID + */ +int ol_cfg_max_peer_id(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify the max number of virtual devices within a physical device. + * @details + * Specify how many virtual devices may exist within a physical device. + * + * @param pdev - handle to the physical device + * @return maximum number of virtual devices + */ +int ol_cfg_max_vdevs(struct cdp_cfg *cfg_pdev); + +/** + * @brief Check whether host-side rx PN check is enabled or disabled. + * @details + * Choose whether to allocate rx PN state information and perform + * rx PN checks (if applicable, based on security type) on the host. + * If the rx PN check is specified to be done on the host, the host SW + * will determine which peers are using a security type (e.g. CCMP) that + * requires a PN check. + * + * @param pdev - handle to the physical device + * @return 1 -> host performs rx PN check -OR- 0 -> no host-side rx PN check + */ +int ol_cfg_rx_pn_check(struct cdp_cfg *cfg_pdev); + +/** + * @brief Check whether host-side rx forwarding is enabled or disabled. + * @details + * Choose whether to check whether to forward rx frames to tx on the host. + * For LL systems, this rx -> tx host-side forwarding check is typically + * enabled. + * For HL systems, the rx -> tx forwarding check is typically done on the + * target. However, even in HL systems, the host-side rx -> tx forwarding + * will typically be enabled, as a second-tier safety net in case the + * target doesn't have enough memory to store all rx -> tx forwarded frames. + * + * @param pdev - handle to the physical device + * @return 1 -> host does rx->tx forward -OR- 0 -> no host-side rx->tx forward + */ +int ol_cfg_rx_fwd_check(struct cdp_cfg *cfg_pdev); + +/** + * ol_set_cfg_rx_fwd_disabled - set rx fwd disable/enable + * + * @pdev - handle to the physical device + * @disable_rx_fwd 1 -> no rx->tx forward -> rx->tx forward + * + * Choose whether to forward rx frames to tx (where applicable) within the + * WLAN driver, or to leave all forwarding up to the operating system. + * Currently only intra-bss fwd is supported. + * + */ +void ol_set_cfg_rx_fwd_disabled(struct cdp_cfg *ppdev, uint8_t disable_rx_fwd); + +/** + * ol_set_cfg_packet_log_enabled - Set packet log config in HTT + * config based on CFG ini configuration + * + * @pdev - handle to the physical device + * @val - 0 - disable, 1 - enable + */ +void ol_set_cfg_packet_log_enabled(struct cdp_cfg *ppdev, uint8_t val); + +/** + * @brief Check whether rx forwarding is enabled or disabled. + * @details + * Choose whether to forward rx frames to tx (where applicable) within the + * WLAN driver, or to leave all forwarding up to the operating system. + * + * @param pdev - handle to the physical device + * @return 1 -> no rx->tx forward -OR- 0 -> rx->tx forward (in host or target) + */ +int ol_cfg_rx_fwd_disabled(struct cdp_cfg *cfg_pdev); + +/** + * @brief Check whether to perform inter-BSS or intra-BSS rx->tx forwarding. + * @details + * Check whether data received by an AP on one virtual device destined + * to a STA associated with a different virtual device within the same + * physical device should be forwarded within the driver, or whether + * forwarding should only be done within a virtual device. + * + * @param pdev - handle to the physical device + * @return + * 1 -> forward both within and between vdevs + * -OR- + * 0 -> forward only within a vdev + */ +int ol_cfg_rx_fwd_inter_bss(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify data frame format used by the OS. + * @details + * Specify what type of frame (802.3 or native WiFi) the host data SW + * should expect from and provide to the OS shim. + * + * @param pdev - handle to the physical device + * @return enumerated data frame format + */ +enum wlan_frm_fmt ol_cfg_frame_type(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify the peak throughput. + * @details + * Specify the peak throughput that a system is expected to support. + * The data SW uses this configuration to help choose the size for its + * tx descriptor pool and rx buffer ring. + * The data SW assumes that the peak throughput applies to either rx or tx, + * rather than having separate specs of the rx max throughput vs. the tx + * max throughput. + * + * @param pdev - handle to the physical device + * @return maximum supported throughput in Mbps (not MBps) + */ +int ol_cfg_max_thruput_mbps(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify the maximum number of fragments per tx network buffer. + * @details + * Specify the maximum number of fragments that a tx frame provided to + * the WLAN driver by the OS may contain. + * In LL systems, the host data SW uses this maximum fragment count to + * determine how many elements to allocate in the fragmentation descriptor + * it creates to specify to the tx MAC DMA where to locate the tx frame's + * data. + * This maximum fragments count is only for regular frames, not TSO frames, + * since TSO frames are sent in segments with a limited number of fragments + * per segment. + * + * @param pdev - handle to the physical device + * @return maximum number of fragments that can occur in a regular tx frame + */ +int ol_cfg_netbuf_frags_max(struct cdp_cfg *cfg_pdev); + +/** + * @brief For HL systems, specify when to free tx frames. + * @details + * In LL systems, the host's tx frame is referenced by the MAC DMA, and + * thus cannot be freed until the target indicates that it is finished + * transmitting the frame. + * In HL systems, the entire tx frame is downloaded to the target. + * Consequently, the target has its own copy of the tx frame, and the + * host can free the tx frame as soon as the download completes. + * Alternatively, the HL host can keep the frame allocated until the + * target explicitly tells the HL host it is done transmitting the frame. + * This gives the target the option of discarding its copy of the tx + * frame, and then later getting a new copy from the host. + * This function tells the host whether it should retain its copy of the + * transmit frames until the target explicitly indicates it is finished + * transmitting them, or if it should free its copy as soon as the + * tx frame is downloaded to the target. + * + * @param pdev - handle to the physical device + * @return + * 0 -> retain the tx frame until the target indicates it is done + * transmitting the frame + * -OR- + * 1 -> free the tx frame as soon as the download completes + */ +int ol_cfg_tx_free_at_download(struct cdp_cfg *cfg_pdev); +void ol_cfg_set_tx_free_at_download(struct cdp_cfg *cfg_pdev); + +/** + * @brief Low water mark for target tx credit. + * Tx completion handler is invoked to reap the buffers when the target tx + * credit goes below Low Water Mark. + */ +#define OL_CFG_NUM_MSDU_REAP 512 +#define ol_cfg_tx_credit_lwm(pdev) \ + ((CFG_TGT_NUM_MSDU_DESC > OL_CFG_NUM_MSDU_REAP) ? \ + (CFG_TGT_NUM_MSDU_DESC - OL_CFG_NUM_MSDU_REAP) : 0) + +/** + * @brief In a HL system, specify the target initial credit count. + * @details + * The HL host tx data SW includes a module for determining which tx frames + * to download to the target at a given time. + * To make this judgement, the HL tx download scheduler has to know + * how many buffers the HL target has available to hold tx frames. + * Due to the possibility that a single target buffer pool can be shared + * between rx and tx frames, the host may not be able to obtain a precise + * specification of the tx buffer space available in the target, but it + * uses the best estimate, as provided by this configuration function, + * to determine how best to schedule the tx frame downloads. + * + * @param pdev - handle to the physical device + * @return the number of tx buffers available in a HL target + */ +uint16_t ol_cfg_target_tx_credit(struct cdp_cfg *cfg_pdev); + +/** + * @brief Specify the LL tx MSDU header download size. + * @details + * In LL systems, determine how many bytes from a tx frame to download, + * in order to provide the target FW's Descriptor Engine with enough of + * the packet's payload to interpret what kind of traffic this is, + * and who it is for. + * This download size specification does not include the 802.3 / 802.11 + * frame encapsulation headers; it starts with the encapsulated IP packet + * (or whatever ethertype is carried within the ethernet-ish frame). + * The LL host data SW will determine how many bytes of the MSDU header to + * download by adding this download size specification to the size of the + * frame header format specified by the ol_cfg_frame_type configuration + * function. + * + * @param pdev - handle to the physical device + * @return the number of bytes beyond the 802.3 or native WiFi header to + * download to the target for tx classification + */ +int ol_cfg_tx_download_size(struct cdp_cfg *cfg_pdev); + +/** + * brief Specify where defrag timeout and duplicate detection is handled + * @details + * non-aggregate duplicate detection and timing out stale fragments + * requires additional target memory. To reach max client + * configurations (128+), non-aggregate duplicate detection and the + * logic to time out stale fragments is moved to the host. + * + * @param pdev - handle to the physical device + * @return + * 0 -> target is responsible non-aggregate duplicate detection and + * timing out stale fragments. + * + * 1 -> host is responsible non-aggregate duplicate detection and + * timing out stale fragments. + */ +int ol_cfg_rx_host_defrag_timeout_duplicate_check(struct cdp_cfg *cfg_pdev); + +/** + * brief Query for the period in ms used for throttling for + * thermal mitigation + * @details + * In LL systems, transmit data throttling is used for thermal + * mitigation where data is paused and resumed during the + * throttle period i.e. the throttle period consists of an + * "on" phase when transmit is allowed and an "off" phase when + * transmit is suspended. This function returns the total + * period used for throttling. + * + * @param pdev - handle to the physical device + * @return the total throttle period in ms + */ +int ol_cfg_throttle_period_ms(struct cdp_cfg *cfg_pdev); + +/** + * brief Query for the duty cycle in percentage used for throttling for + * thermal mitigation + * + * @param pdev - handle to the physical device + * @param level - duty cycle level + * @return the duty cycle level in percentage + */ +int ol_cfg_throttle_duty_cycle_level(struct cdp_cfg *cfg_pdev, int level); + +/** + * brief Check whether full reorder offload is + * enabled/disable by the host + * @details + * If the host does not support receive reorder (i.e. the + * target performs full receive re-ordering) this will return + * "enabled" + * + * @param pdev - handle to the physical device + * @return 1 - enable, 0 - disable + */ +int ol_cfg_is_full_reorder_offload(struct cdp_cfg *cfg_pdev); + +int ol_cfg_is_rx_thread_enabled(struct cdp_cfg *cfg_pdev); + +#ifdef WLAN_FEATURE_TSF_PLUS +void ol_set_cfg_ptp_rx_opt_enabled(struct cdp_cfg *cfg_pdev, u_int8_t val); +u_int8_t ol_cfg_is_ptp_rx_opt_enabled(struct cdp_cfg *cfg_pdev); +#else +static inline void +ol_set_cfg_ptp_rx_opt_enabled(struct cdp_cfg *cfg_pdev, u_int8_t val) +{ +} + +static inline u_int8_t +ol_cfg_is_ptp_rx_opt_enabled(struct cdp_cfg *cfg_pdev) +{ + return 0; +} +#endif + +/** + * ol_cfg_is_ip_tcp_udp_checksum_offload_enabled() - return + * ip_tcp_udp_checksum_offload is enable/disable + * @pdev : handle to the physical device + * + * Return: 1 - enable, 0 - disable + */ +static inline +int ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->ip_tcp_udp_checksum_offload; +} + + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +int ol_cfg_get_tx_flow_stop_queue_th(struct cdp_cfg *cfg_pdev); + +int ol_cfg_get_tx_flow_start_queue_offset(struct cdp_cfg *cfg_pdev); +#endif + +bool ol_cfg_is_ce_classify_enabled(struct cdp_cfg *cfg_pdev); + +enum wlan_target_fmt_translation_caps { + wlan_frm_tran_cap_raw = 0x01, + wlan_frm_tran_cap_native_wifi = 0x02, + wlan_frm_tran_cap_8023 = 0x04, +}; + +/** + * @brief Specify the maximum header size added by SW tx encapsulation + * @details + * This function returns the maximum size of the new L2 header, not the + * difference between the new and old L2 headers. + * Thus, this function returns the maximum 802.11 header size that the + * tx SW may need to add to tx data frames. + * + * @param pdev - handle to the physical device + */ +static inline int ol_cfg_sw_encap_hdr_max_size(struct cdp_cfg *cfg_pdev) +{ + /* + * 24 byte basic 802.11 header + * + 6 byte 4th addr + * + 2 byte QoS control + * + 4 byte HT control + * + 8 byte LLC/SNAP + */ + return sizeof(struct ieee80211_qosframe_htc_addr4) + LLC_SNAP_HDR_LEN; +} + +static inline uint8_t ol_cfg_tx_encap(struct cdp_cfg *cfg_pdev) +{ + /* tx encap done in HW */ + return 0; +} + +static inline int ol_cfg_host_addba(struct cdp_cfg *cfg_pdev) +{ + /* + * ADDBA negotiation is handled by the target FW for Peregrine + Rome. + */ + return 0; +} + +/** + * @brief If the host SW's ADDBA negotiation fails, should it be retried? + * + * @param pdev - handle to the physical device + */ +static inline int ol_cfg_addba_retry(struct cdp_cfg *cfg_pdev) +{ + return 0; /* disabled for now */ +} + +/** + * @brief How many frames to hold in a paused vdev's tx queue in LL systems + */ +static inline int ol_tx_cfg_max_tx_queue_depth_ll(struct cdp_cfg *cfg_pdev) +{ + /* + * Store up to 1500 frames for a paused vdev. + * For example, if the vdev is sending 300 Mbps of traffic, and the + * PHY is capable of 600 Mbps, then it will take 56 ms for the PHY to + * drain both the 700 frames that are queued initially, plus the next + * 700 frames that come in while the PHY is catching up. + * So in this example scenario, the PHY will remain fully utilized + * in a MCC system that has a channel-switching period of 56 ms or less. + * 700 frames calculation was correct when FW drain packet without + * any overhead. Actual situation drain overhead will slowdown drain + * speed. And channel period is less than 56 msec + * Worst scenario, 1500 frames should be stored in host. + */ + return 1500; +} + +/** + * @brief Get packet log config from HTT config + */ +uint8_t ol_cfg_is_packet_log_enabled(struct cdp_cfg *cfg_pdev); + +#ifdef IPA_OFFLOAD +/** + * @brief IPA micro controller data path offload enable or not + * @detail + * This function returns IPA micro controller data path offload + * feature enabled or not + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_offload_enabled(struct cdp_cfg *cfg_pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * TX buffer size which should be pre-allocated by driver. + * Default buffer size is 2K + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_buf_size(struct cdp_cfg *cfg_pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * TX buffer count which should be pre-allocated by driver. + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt(struct cdp_cfg *cfg_pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @detail + * This function returns IPA micro controller data path offload + * RX indication ring size which will notified by WLAN FW to IPA + * micro controller + * + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(struct cdp_cfg *cfg_pdev); +/** + * @brief IPA micro controller data path TX buffer size + * @param pdev - handle to the physical device + */ +unsigned int ol_cfg_ipa_uc_tx_partition_base(struct cdp_cfg *cfg_pdev); +void ol_cfg_set_ipa_uc_tx_partition_base(struct cdp_cfg *cfg_pdev, + uint32_t value); +#else +static inline unsigned int ol_cfg_ipa_uc_offload_enabled( + struct cdp_cfg *cfg_pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_buf_size( + struct cdp_cfg *cfg_pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt( + struct cdp_cfg *cfg_pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_rx_ind_ring_size( + struct cdp_cfg *cfg_pdev) +{ + return 0; +} + +static inline unsigned int ol_cfg_ipa_uc_tx_partition_base( + struct cdp_cfg *cfg_pdev) +{ + return 0; +} + +static inline void ol_cfg_set_ipa_uc_tx_partition_base( + void *cfg_pdev, uint32_t value) +{ +} +#endif /* IPA_OFFLOAD */ + +/** + * ol_set_cfg_flow_steering - Set Rx flow steering config based on CFG ini + * config. + * + * @pdev - handle to the physical device + * @val - 0 - disable, 1 - enable + * + * Return: None + */ +static inline void ol_set_cfg_flow_steering(struct cdp_cfg *cfg_pdev, + uint8_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->flow_steering_enabled = val; +} + +/** + * ol_cfg_is_flow_steering_enabled - Return Rx flow steering config. + * + * @pdev - handle to the physical device + * + * Return: value of configured flow steering value. + */ +static inline uint8_t ol_cfg_is_flow_steering_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->flow_steering_enabled; +} + +/** + * ol_set_cfg_new_htt_format - Set whether FW supports new htt format + * + * @pdev - handle to the physical device + * @val - true - supported, false - not supported + * + * Return: None + */ +static inline void +ol_set_cfg_new_htt_format(struct cdp_cfg *cfg_pdev, bool val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->new_htt_format_enabled = val; +} + +/** + * ol_cfg_is_htt_new_format_enabled - Return whether FW supports new htt format + * + * @pdev - handle to the physical device + * + * Return: value of configured htt_new_format + */ +static inline bool +ol_cfg_is_htt_new_format_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->new_htt_format_enabled; +} + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +/** + * ol_cfg_get_del_ack_timer_value() - get delayed ack timer value + * @cfg_pdev: pdev handle + * + * Return: timer value + */ +int ol_cfg_get_del_ack_timer_value(struct cdp_cfg *cfg_pdev); + +/** + * ol_cfg_get_del_ack_enable_value() - get delayed ack enable value + * @cfg_pdev: pdev handle + * + * Return: enable/disable + */ +bool ol_cfg_get_del_ack_enable_value(struct cdp_cfg *cfg_pdev); + +/** + * ol_cfg_get_del_ack_count_value() - get delayed ack count value + * @cfg_pdev: pdev handle + * + * Return: count value + */ +int ol_cfg_get_del_ack_count_value(struct cdp_cfg *cfg_pdev); + +/** + * ol_cfg_update_del_ack_params() - update delayed ack params + * @cfg_ctx: cfg context + * @cfg_param: parameters + * + * Return: none + */ +void ol_cfg_update_del_ack_params(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param); +#else +/** + * ol_cfg_update_del_ack_params() - update delayed ack params + * @cfg_ctx: cfg context + * @cfg_param: parameters + * + * Return: none + */ +static inline +void ol_cfg_update_del_ack_params(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param) +{ +} +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +int ol_cfg_get_bundle_timer_value(struct cdp_cfg *cfg_pdev); +int ol_cfg_get_bundle_size(struct cdp_cfg *cfg_pdev); +#else +#endif +/** + * ol_cfg_get_wrr_skip_weight() - brief Query for the param of wrr_skip_weight + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: wrr_skip_weight for specified ac. + */ +int ol_cfg_get_wrr_skip_weight(struct cdp_cfg *pdev, int ac); + +/** + * ol_cfg_get_credit_threshold() - Query for the param of credit_threshold + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: credit_threshold for specified ac. + */ +uint32_t ol_cfg_get_credit_threshold(struct cdp_cfg *pdev, int ac); + +/** + * ol_cfg_get_send_limit() - Query for the param of send_limit + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: send_limit for specified ac. + */ +uint16_t ol_cfg_get_send_limit(struct cdp_cfg *pdev, int ac); + +/** + * ol_cfg_get_credit_reserve() - Query for the param of credit_reserve + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: credit_reserve for specified ac. + */ +int ol_cfg_get_credit_reserve(struct cdp_cfg *pdev, int ac); + +/** + * ol_cfg_get_discard_weight() - Query for the param of discard_weight + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: discard_weight for specified ac. + */ +int ol_cfg_get_discard_weight(struct cdp_cfg *pdev, int ac); +#endif /* _OL_CFG__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_defines.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_defines.h new file mode 100644 index 0000000000..c89a6e2d0b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_defines.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013-2014, 2016, 2018-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Offload specific Opaque Data types. + */ +#ifndef _DEV_OL_DEFINES_H +#define _DEV_OL_DEFINES_H + +#define OL_TXRX_PDEV_ID 0 + +#define NORMALIZED_TO_NOISE_FLOOR (-96) + + /** + * ol_txrx_pdev_handle - opaque handle for txrx physical device + * object + */ +struct ol_txrx_pdev_t; +typedef struct ol_txrx_pdev_t *ol_txrx_pdev_handle; + +/** + * ol_txrx_vdev_handle - opaque handle for txrx virtual device + * object + */ +struct ol_txrx_vdev_t; +typedef struct ol_txrx_vdev_t *ol_txrx_vdev_handle; + +/** + * ol_pdev_handle - opaque handle for the configuration + * associated with the physical device + */ +struct ol_pdev_t; +typedef struct ol_pdev_t *ol_pdev_handle; + +/** + * ol_txrx_peer_handle - opaque handle for txrx peer object + */ +struct ol_txrx_peer_t; +typedef struct ol_txrx_peer_t *ol_txrx_peer_handle; + +#endif /* _DEV_OL_DEFINES_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h new file mode 100644 index 0000000000..0313625eab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_api.h @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2011, 2014-2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_htt_api.h + * @brief Specify the general HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are not specific to + * either tx nor rx. + */ +#ifndef _OL_HTT_API__H_ +#define _OL_HTT_API__H_ + +#include /* qdf_device_t */ +#include /* qdf_nbuf_t */ +#include /* A_STATUS */ +#include /* HTC_HANDLE */ +#include "htt.h" /* htt_dbg_stats_type, etc. */ +#include /* ol_pdev_handle */ +#include +#include + +struct htt_pdev_t; +typedef struct htt_pdev_t *htt_pdev_handle; + +htt_pdev_handle +htt_pdev_alloc(ol_txrx_pdev_handle txrx_pdev, + struct cdp_cfg *ctrl_pdev, + HTC_HANDLE htc_pdev, qdf_device_t osdev); + +/** + * @brief Allocate and initialize a HTT instance. + * @details + * This function allocates and initializes an HTT instance. + * This involves allocating a pool of HTT tx descriptors in + * consistent memory, allocating and filling a rx ring (LL only), + * and connecting the HTC's HTT_DATA_MSG service. + * The HTC service connect call will block, so this function + * needs to be called in passive context. + * Because HTC setup has not been completed at the time this function + * is called, this function cannot send any HTC messages to the target. + * Messages to configure the target are instead sent in the + * htc_attach_target function. + * + * @param pdev - data SW's physical device handle + * (used as context pointer during HTT -> txrx calls) + * @param desc_pool_size - number of HTT descriptors to (pre)allocate + * @return success -> HTT pdev handle; failure -> NULL + */ +int +htt_attach(struct htt_pdev_t *pdev, int desc_pool_size); + +/** + * @brief Send HTT configuration messages to the target. + * @details + * For LL only, this function sends a rx ring configuration message to the + * target. For HL, this function is a no-op. + * + * @param htt_pdev - handle to the HTT instance being initialized + */ +QDF_STATUS htt_attach_target(htt_pdev_handle htt_pdev); + +/** + * enum htt_op_mode - Virtual device operation mode + * + * @htt_op_mode_unknown: Unknown mode + * @htt_op_mode_ap: AP mode + * @htt_op_mode_ibss: IBSS mode + * @htt_op_mode_sta: STA (client) mode + * @htt_op_mode_monitor: Monitor mode + * @htt_op_mode_ocb: OCB mode + */ +enum htt_op_mode { + htt_op_mode_unknown, + htt_op_mode_ap, + htt_op_mode_ibss, + htt_op_mode_sta, + htt_op_mode_monitor, + htt_op_mode_ocb, +}; + +/* no-ops */ +#define htt_vdev_attach(htt_pdev, vdev_id, op_mode) +#define htt_vdev_detach(htt_pdev, vdev_id) +#define htt_peer_qos_update(htt_pdev, peer_id, qos_capable) +#define htt_peer_uapsdmask_update(htt_pdev, peer_id, uapsd_mask) + +void htt_pdev_free(htt_pdev_handle pdev); + +/** + * @brief Deallocate a HTT instance. + * + * @param htt_pdev - handle to the HTT instance being torn down + */ +void htt_detach(htt_pdev_handle htt_pdev); + +/** + * @brief Stop the communication between HTT and target + * @details + * For ISOC solution, this function stop the communication between HTT and + * target. + * For Peregrine/Rome, it's already stopped by ol_ath_disconnect_htc + * before ol_txrx_pdev_detach called in ol_ath_detach. So this function is + * a no-op. + * Peregrine/Rome HTT layer is on top of HTC while ISOC solution HTT layer is + * on top of DXE layer. + * + * @param htt_pdev - handle to the HTT instance being initialized + */ +void htt_detach_target(htt_pdev_handle htt_pdev); + +/* + * @brief Tell the target side of HTT to suspend H2T processing until synced + * @param htt_pdev - the host HTT object + * @param sync_cnt - what sync count value the target HTT FW should wait for + * before resuming H2T processing + */ +A_STATUS htt_h2t_sync_msg(htt_pdev_handle htt_pdev, uint8_t sync_cnt); + +int +htt_h2t_aggr_cfg_msg(htt_pdev_handle htt_pdev, + int max_subfrms_ampdu, int max_subfrms_amsdu); + +/** + * @brief Get the FW status + * @details + * Trigger FW HTT to retrieve FW status. + * A separate HTT message will come back with the statistics we want. + * + * @param pdev - handle to the HTT instance + * @param stats_type_upload_mask - bitmask identifying which stats to upload + * @param stats_type_reset_mask - bitmask identifying which stats to reset + * @param cookie - unique value to distinguish and identify stats requests + * @return 0 - succeed to send the request to FW; otherwise, failed to do so. + */ +int +htt_h2t_dbg_stats_get(struct htt_pdev_t *pdev, + uint32_t stats_type_upload_mask, + uint32_t stats_type_reset_mask, + uint8_t cfg_stats_type, + uint32_t cfg_val, uint8_t cookie); + +/** + * @brief Get the fields from HTT T2H stats upload message's stats info header + * @details + * Parse the a HTT T2H message's stats info tag-length-value header, + * to obtain the stats type, status, data length, and data address. + * + * @param stats_info_list - address of stats record's header + * @param[out] type - which type of FW stats are contained in the record + * @param[out] status - whether the stats are (fully) present in the record + * @param[out] length - how large the data portion of the stats record is + * @param[out] stats_data - where the data portion of the stats record is + */ +void +htt_t2h_dbg_stats_hdr_parse(uint8_t *stats_info_list, + enum htt_dbg_stats_type *type, + enum htt_dbg_stats_status *status, + int *length, uint8_t **stats_data); + +/** + * @brief Display a stats record from the HTT T2H STATS_CONF message. + * @details + * Parse the stats type and status, and invoke a type-specified printout + * to display the stats values. + * + * @param stats_data - buffer holding the stats record from the STATS_CONF msg + * @param concise - whether to do a verbose or concise printout + */ +void htt_t2h_stats_print(uint8_t *stats_data, int concise); + +/** + * htt_log_rx_ring_info() - log htt rx ring info during FW_RX_REFILL failure + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_log_rx_ring_info(htt_pdev_handle pdev); + +/** + * htt_rx_refill_failure() - During refill failure check if debt is zero + * @pdev: handle to the HTT instance + * + * Return: None + */ +void htt_rx_refill_failure(htt_pdev_handle pdev); + +#ifndef HTT_DEBUG_LEVEL +#if defined(DEBUG) +#define HTT_DEBUG_LEVEL 10 +#else +#define HTT_DEBUG_LEVEL 0 +#endif +#endif + +#if HTT_DEBUG_LEVEL > 5 +void htt_display(htt_pdev_handle pdev, int indent); +#else +#define htt_display(pdev, indent) +#endif + +#define HTT_DXE_RX_LOG 0 +#define htt_rx_reorder_log_print(pdev) + +#ifdef IPA_OFFLOAD +int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev); + +/** + * htt_ipa_uc_get_resource() - Get uc resource from htt and lower layer + * @pdev - handle to the HTT instance + * @ce_sr - CE source ring DMA mapping info + * @tx_comp_ring - tx completion ring DMA mapping info + * @rx_rdy_ring - rx Ready ring DMA mapping info + * @rx2_rdy_ring - rx2 Ready ring DMA mapping info + * @rx_proc_done_idx - rx process done index + * @rx2_proc_done_idx - rx2 process done index + * @ce_sr_ring_size: copyengine source ring size + * @ce_reg_paddr - CE Register address + * @tx_num_alloc_buffer - Number of TX allocated buffers + * + * Return: 0 success + */ +int +htt_ipa_uc_get_resource(htt_pdev_handle pdev, + qdf_shared_mem_t **ce_sr, + qdf_shared_mem_t **tx_comp_ring, + qdf_shared_mem_t **rx_rdy_ring, + qdf_shared_mem_t **rx2_rdy_ring, + qdf_shared_mem_t **rx_proc_done_idx, + qdf_shared_mem_t **rx2_proc_done_idx, + uint32_t *ce_sr_ring_size, + qdf_dma_addr_t *ce_reg_paddr, + uint32_t *tx_num_alloc_buffer); + +int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + qdf_dma_addr_t ipa_uc_tx_doorbell_paddr, + qdf_dma_addr_t ipa_uc_rx_doorbell_paddr); + +int +htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, bool is_tx); + +int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev); + +int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, + uint8_t reset_stats); + +int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, uint64_t quota_bytes); + +int htt_ipa_uc_attach(struct htt_pdev_t *pdev); + +void htt_ipa_uc_detach(struct htt_pdev_t *pdev); +#else +/** + * htt_h2t_ipa_uc_rsc_cfg_msg() - Send WDI IPA config message to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_rsc_cfg_msg(struct htt_pdev_t *pdev) +{ + return 0; +} + +/** + * htt_ipa_uc_set_doorbell_paddr() - Propagate IPA doorbell address + * @pdev: handle to the HTT instance + * @ipa_uc_tx_doorbell_paddr: TX doorbell base physical address + * @ipa_uc_rx_doorbell_paddr: RX doorbell base physical address + * + * Return: 0 success + */ +static inline int +htt_ipa_uc_set_doorbell_paddr(htt_pdev_handle pdev, + uint32_t ipa_uc_tx_doorbell_paddr, + uint32_t ipa_uc_rx_doorbell_paddr) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_set_active() - Propagate WDI path enable/disable to firmware + * @pdev: handle to the HTT instance + * @uc_active: WDI UC path enable or not + * @is_tx: TX path or RX path + * + * Return: 0 success + */ +static inline int +htt_h2t_ipa_uc_set_active(struct htt_pdev_t *pdev, bool uc_active, + bool is_tx) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_get_stats() - WDI UC state query request to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_get_stats(struct htt_pdev_t *pdev) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_get_share_stats() - WDI UC wifi sharing state request to FW + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_get_share_stats(struct htt_pdev_t *pdev, + uint8_t reset_stats) +{ + return 0; +} + +/** + * htt_h2t_ipa_uc_set_quota() - WDI UC set quota request to firmware + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_h2t_ipa_uc_set_quota(struct htt_pdev_t *pdev, + uint64_t quota_bytes) +{ + return 0; +} + +/** + * htt_ipa_uc_attach() - Allocate UC data path resources + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline int htt_ipa_uc_attach(struct htt_pdev_t *pdev) +{ + return 0; +} + +/** + * htt_ipa_uc_attach() - Remove UC data path resources + * @pdev: handle to the HTT instance + * + * Return: 0 success + */ +static inline void htt_ipa_uc_detach(struct htt_pdev_t *pdev) +{ +} +#endif /* IPA_OFFLOAD */ + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch); + +void ol_htt_mon_note_chan(struct cdp_pdev *ppdev, int mon_ch); +#else +static inline +void htt_rx_mon_note_capture_channel(htt_pdev_handle pdev, int mon_ch) {} + +static inline +void ol_htt_mon_note_chan(struct cdp_pdev *ppdev, int mon_ch) {} +#endif + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void htt_dump_bundle_stats(struct htt_pdev_t *pdev); +void htt_clear_bundle_stats(struct htt_pdev_t *pdev); +#else + +static inline void htt_dump_bundle_stats(struct htt_pdev_t *pdev) +{ +} + +static inline void htt_clear_bundle_stats(struct htt_pdev_t *pdev) +{ +} +#endif + +void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, uint8_t value); + +typedef void (*tp_rx_pkt_dump_cb)(qdf_nbuf_t msdu, uint8_t peer_id, + uint8_t status); +#ifndef CONNECTIVITY_PKTLOG +static inline +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb ol_rx_pkt_dump_call) +{ +} + +static inline +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev) +{ +} + +static inline +void ol_rx_pkt_dump_call(qdf_nbuf_t msdu, uint8_t peer_id, uint8_t status) +{ +} +#else +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb ol_rx_pkt_dump_call); +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev); +void ol_rx_pkt_dump_call(qdf_nbuf_t msdu, uint8_t peer_id, uint8_t status); +#endif + +#endif /* _OL_HTT_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h new file mode 100644 index 0000000000..a7dbd803e2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_rx_api.h @@ -0,0 +1,1027 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_htt_rx_api.h + * @brief Specify the rx HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are specifically + * related to receive processing. + * In particular, this file specifies methods of the abstract HTT rx + * descriptor, and functions to iterate though a series of rx descriptors + * and rx MSDU buffers. + */ +#ifndef _OL_HTT_RX_API__H_ +#define _OL_HTT_RX_API__H_ + +#include /* uint16_t, etc. */ +#include /* qdf_nbuf_t */ +#include /* bool */ + +#include /* HTT_RX_IND_MPDU_STATUS */ +#include /* htt_pdev_handle */ + +#include +#include + +/*================ constants and types used in the rx API ===================*/ + +#define HTT_RSSI_INVALID 0x7fff + +#ifndef EXTERNAL_USE_ONLY + +#define IEEE80211_LSIG_LEN 3 +#define IEEE80211_HTSIG_LEN 6 +#define IEEE80211_SB_LEN 2 + +/** + * struct ieee80211_rx_status - RX status + * @rs_numchains: Number of chains + * @rs_flags: Flags + * @rs_rssi: RSSI (noise floor adjusted) + * @rs_abs_rssi: Absolute RSSI + * @rs_datarate: Data rate received + * @rs_rateieee: ieee rate + * @rs_ratephy: Phy rate + * @rs_rssictl: RSSI (noise floor adjusted) + * @rs_rssiextn: RSSI (noise floor adjusted) + * @rs_isvalidrssi: rs_rssi is valid or not + * @rs_phymode: Phy mode + * @rs_freq: Received frequency + * @rs_tstamp: Received timestamp + * @rs_full_chan: Detail channel structure of recv frame. + * It could be NULL if not available + * @rs_isaggr: Is Aggreggated? + * @rs_isapsd: Is APSD? + * @rs_noisefloor: Noise floor + * @rs_channel: Channel + * @rs_rpttstamp: txbf report time stamp + * @rs_cryptodecapcount: Crypto bytes decapped/demic'ed + * @rs_padspace: No. of padding bytes present after header + * in wbuf + * @rs_qosdecapcount: QoS/HTC bytes decapped + * @rs_lsig: lsig + * @rs_htsig: HT sig + * @rs_servicebytes: Received service bytes + */ +struct ieee80211_rx_status { + int rs_numchains; + int rs_flags; + int rs_rssi; + int rs_abs_rssi; + int rs_datarate; + int rs_rateieee; + int rs_ratephy; + + uint8_t rs_rssictl[IEEE80211_MAX_ANTENNA]; + uint8_t rs_rssiextn[IEEE80211_MAX_ANTENNA]; + uint8_t rs_isvalidrssi; + + enum ieee80211_phymode rs_phymode; + int rs_freq; + + union { + uint8_t data[8]; + uint64_t tsf; + } rs_tstamp; + + struct ieee80211_channel *rs_full_chan; + + uint8_t rs_isaggr; + uint8_t rs_isapsd; + int16_t rs_noisefloor; + uint16_t rs_channel; +#ifdef ATH_SUPPORT_TxBF + uint32_t rs_rpttstamp; +#endif + + /* + * The following counts are meant to assist in stats calculation. + * These variables are incremented only in specific situations, and + * should not be relied upon for any purpose other than the original + * stats related purpose they have been introduced for. + */ + + uint16_t rs_cryptodecapcount; + uint8_t rs_padspace; + uint8_t rs_qosdecapcount; + + /* End of stats calculation related counts. */ + + uint8_t rs_lsig[IEEE80211_LSIG_LEN]; + uint8_t rs_htsig[IEEE80211_HTSIG_LEN]; + uint8_t rs_servicebytes[IEEE80211_SB_LEN]; + +}; +#endif /* EXTERNAL_USE_ONLY */ + +/** + * struct ocb_rx_stats_hdr_t - RX stats header + * @version: The version must be 1. + * @length: The length of this structure + * @channel_freq: The center frequency for the packet + * @rssi_cmb: combined RSSI from all chains + * @rssi[4]: rssi for chains 0 through 3 (for 20 MHz bandwidth) + * @tsf32: timestamp in TSF units + * @timestamp_microsec: timestamp in microseconds + * @datarate: MCS index + * @timestamp_submicrosec: submicrosecond portion of the timestamp + * @ext_tid: Extended TID + * @reserved: Ensure the size of the structure is a multiple of 4. + * Must be 0. + * + * When receiving an OCB packet, the RX stats is sent to the user application + * so that the user application can do processing based on the RX stats. + * This structure will be preceded by an ethernet header with + * the proto field set to 0x8152. This struct includes various RX + * parameters including RSSI, data rate, and center frequency. + */ +PREPACK struct ocb_rx_stats_hdr_t { + uint16_t version; + uint16_t length; + uint16_t channel_freq; + int16_t rssi_cmb; + int16_t rssi[4]; + uint32_t tsf32; + uint32_t timestamp_microsec; + uint8_t datarate; + uint8_t timestamp_submicrosec; + uint8_t ext_tid; + uint8_t reserved; +}; + +/*================ rx indication message field access methods ===============*/ + +/** + * @brief Check if a rx indication message has a rx reorder flush command. + * @details + * Space is reserved in each rx indication message for a rx reorder flush + * command, to release specified MPDUs from the rx reorder holding array + * before processing the new MPDUs referenced by the rx indication message. + * This rx reorder flush command contains a flag to show whether the command + * is valid within a given rx indication message. + * This function checks the validity flag from the rx indication + * flush command IE within the rx indication message. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return + * 1 - the message's rx flush command is valid and should be processed + * before processing new rx MPDUs, + * -OR- + * 0 - the message's rx flush command is invalid and should be ignored + */ +int htt_rx_ind_flush(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +/** + * @brief Return the sequence number starting the range of MPDUs to flush. + * @details + * Read the fields of the rx indication message that identify the start + * and end of the range of MPDUs to flush from the rx reorder holding array + * and send on to subsequent stages of rx processing. + * These sequence numbers are the 6 LSBs of the 12-bit 802.11 sequence + * number. These sequence numbers are masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * The series of MPDUs to flush includes the one specified by the start + * sequence number. + * The series of MPDUs to flush excludes the one specified by the end + * sequence number; the MPDUs up to but not including the end sequence number + * are to be flushed. + * These start and end seq num fields are only valid if the "flush valid" + * flag is set. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to flush + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to flush + */ +void +htt_rx_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned *seq_num_start, unsigned *seq_num_end); + +/** + * @brief Check if a rx indication message has a rx reorder release command. + * @details + * Space is reserved in each rx indication message for a rx reorder release + * command, to release specified MPDUs from the rx reorder holding array + * after processing the new MPDUs referenced by the rx indication message. + * This rx reorder release command contains a flag to show whether the command + * is valid within a given rx indication message. + * This function checks the validity flag from the rx indication + * release command IE within the rx indication message. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return + * 1 - the message's rx release command is valid and should be processed + * after processing new rx MPDUs, + * -OR- + * 0 - the message's rx release command is invalid and should be ignored + */ +int htt_rx_ind_release(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +/** + * @brief Return the sequence number starting the range of MPDUs to release. + * @details + * Read the fields of the rx indication message that identify the start + * and end of the range of MPDUs to release from the rx reorder holding + * array and send on to subsequent stages of rx processing. + * These sequence numbers are the 6 LSBs of the 12-bit 802.11 sequence + * number. These sequence numbers are masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * The series of MPDUs to release includes the one specified by the start + * sequence number. + * The series of MPDUs to release excludes the one specified by the end + * sequence number; the MPDUs up to but not including the end sequence number + * are to be released. + * These start and end seq num fields are only valid if the "release valid" + * flag is set. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to release + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to release + */ +void +htt_rx_ind_release_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + unsigned int *seq_num_start, + unsigned int *seq_num_end); + +/* + * For now, the host HTT -> host data rx status enum + * exactly matches the target HTT -> host HTT rx status enum; + * no translation is required. + * However, the host data SW should only use the htt_rx_status, + * so that in the future a translation from target HTT rx status + * to host HTT rx status can be added, if the need ever arises. + */ +enum htt_rx_status { + htt_rx_status_unknown = HTT_RX_IND_MPDU_STATUS_UNKNOWN, + htt_rx_status_ok = HTT_RX_IND_MPDU_STATUS_OK, + htt_rx_status_err_fcs = HTT_RX_IND_MPDU_STATUS_ERR_FCS, + htt_rx_status_err_dup = HTT_RX_IND_MPDU_STATUS_ERR_DUP, + htt_rx_status_err_replay = HTT_RX_IND_MPDU_STATUS_ERR_REPLAY, + htt_rx_status_err_inv_peer = HTT_RX_IND_MPDU_STATUS_ERR_INV_PEER, + htt_rx_status_ctrl_mgmt_null = HTT_RX_IND_MPDU_STATUS_MGMT_CTRL, + htt_rx_status_tkip_mic_err = HTT_RX_IND_MPDU_STATUS_TKIP_MIC_ERR, + + htt_rx_status_err_misc = HTT_RX_IND_MPDU_STATUS_ERR_MISC +}; + +/** + * @brief Check the status MPDU range referenced by a rx indication message. + * @details + * Check the status of a range of MPDUs referenced by a rx indication message. + * This status determines whether the MPDUs should be processed or discarded. + * If the status is OK, then the MPDUs within the range should be processed + * as usual. + * Otherwise (FCS error, duplicate error, replay error, unknown sender error, + * etc.) the MPDUs within the range should be discarded. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param mpdu_range_num - which MPDU range within the rx ind msg to check, + * starting from 0 + * @param status - (call-by-reference output) MPDU status + * @param mpdu_count - (call-by-reference output) count of MPDUs comprising + * the specified MPDU range + */ +void +htt_rx_ind_mpdu_range_info(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + int mpdu_range_num, + enum htt_rx_status *status, int *mpdu_count); + +/** + * @brief Return the RSSI provided in a rx indication message. + * @details + * Return the RSSI from an rx indication message, converted to dBm units. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t +htt_rx_ind_rssi_dbm(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +int16_t +htt_rx_ind_rssi_dbm_chain(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + int8_t chain); + +void +htt_rx_ind_legacy_rate(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint8_t *legacy_rate, uint8_t *legacy_rate_sel); + + +void +htt_rx_ind_timestamp(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + uint32_t *timestamp_microsec, + uint8_t *timestamp_submicrosec); + +uint32_t +htt_rx_ind_tsf32(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +uint8_t +htt_rx_ind_ext_tid(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + + +/*==================== rx MPDU descriptor access methods ====================*/ + +/** + * @brief Check if the retry bit is set in Rx-descriptor + * @details + * This function returns the retry bit of the 802.11 header for the + * provided rx MPDU descriptor. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return boolean -- true if retry is set, false otherwise + */ +extern +bool (*htt_rx_mpdu_desc_retry)( + htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return a rx MPDU's sequence number. + * @details + * This function returns the LSBs of the 802.11 sequence number for the + * provided rx MPDU descriptor. + * Depending on the system, 6-12 LSBs from the 802.11 sequence number are + * returned. (Typically, either the 8 or 12 LSBs are returned.) + * This sequence number is masked with the block ack window size, + * rounded up to a power of two (minus one, to create a bitmask) to obtain + * the corresponding index into the rx reorder holding array. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return the LSBs of the sequence number for the MPDU + */ +extern uint16_t +(*htt_rx_mpdu_desc_seq_num)(htt_pdev_handle pdev, void *mpdu_desc, + bool update_seq_num); + +/** + * @brief Return a rx MPDU's rx reorder array index, based on sequence number. + * @details + * This function returns a sequence-number based index into the rx + * reorder array for the specified MPDU. + * In some systems, this rx reorder array is simply the LSBs of the + * sequence number, or possibly even the full sequence number. + * To support such systems, the returned index has to be masked with + * the power-of-two array size before using the value to index the + * rx reorder array. + * In other systems, this rx reorder array index is + * (sequence number) % (block ack window size) + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return the rx reorder array index the MPDU goes into + */ +/* use sequence number (or LSBs thereof) as rx reorder array index */ +#define htt_rx_mpdu_desc_reorder_idx htt_rx_mpdu_desc_seq_num + +union htt_rx_pn_t { + /* WEP: 24-bit PN */ + uint32_t pn24; + + /* TKIP or CCMP: 48-bit PN */ + uint64_t pn48; + + /* WAPI: 128-bit PN */ + uint64_t pn128[2]; +}; + +/** + * @brief Find the packet number (PN) for a MPDU. + * @details + * This function only applies when the rx PN check is configured to be + * performed in the host rather than the target, and on peers using a + * security type for which a PN check applies. + * The pn_len_bits argument is used to determine which element of the + * htt_rx_pn_t union to deposit the PN value read from the MPDU descriptor + * into. + * A 24-bit PN is deposited into pn->pn24. + * A 48-bit PN is deposited into pn->pn48. + * A 128-bit PN is deposited in little-endian order into pn->pn128. + * Specifically, bits 63:0 of the PN are copied into pn->pn128[0], while + * bits 127:64 of the PN are copied into pn->pn128[1]. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @param pn - the location to copy the packet number into + * @param pn_len_bits - the PN size, in bits + */ +extern void (*htt_rx_mpdu_desc_pn)(htt_pdev_handle pdev, + void *mpdu_desc, + union htt_rx_pn_t *pn, int pn_len_bits); + +/** + * @brief This function Returns the TID value from the Rx descriptor + * for Low Latency driver + * @details + * This function returns the TID set in the 802.11 QoS Control for the MPDU + * in the packet header, by looking at the mpdu_start of the Rx descriptor. + * Rx descriptor gets a copy of the TID from the MAC. + * @pdev: Handle (pointer) to HTT pdev. + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return: Actual TID set in the packet header. + */ +extern +uint8_t (*htt_rx_mpdu_desc_tid)( + htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the TSF timestamp indicating when a MPDU was received. + * @details + * This function provides the timestamp indicating when the PPDU that + * the specified MPDU belongs to was received. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return 32 LSBs of TSF time at which the MPDU's PPDU was received + */ +uint32_t htt_rx_mpdu_desc_tsf32(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the 802.11 header of the MPDU + * @details + * This function provides a pointer to the start of the 802.11 header + * of the Rx MPDU + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return pointer to 802.11 header of the received MPDU + */ +char *htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Return the RSSI provided in a rx descriptor. + * @details + * Return the RSSI from a rx descriptor, converted to dBm units. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return RSSI in dBm, or HTT_INVALID_RSSI + */ +int16_t htt_rx_mpdu_desc_rssi_dbm(htt_pdev_handle pdev, void *mpdu_desc); + +/*==================== rx MSDU descriptor access methods ====================*/ + +/** + * @brief Check if a MSDU completes a MPDU. + * @details + * When A-MSDU aggregation is used, a single MPDU will consist of + * multiple MSDUs. This function checks a MSDU's rx descriptor to + * see whether the MSDU is the final MSDU within a MPDU. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - there are subsequent MSDUs within the A-MSDU / MPDU + * -OR- + * 1 - this is the last MSDU within its MPDU + */ +extern bool (*htt_rx_msdu_desc_completes_mpdu)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Check if a MSDU is first msdu of MPDU. + * @details + * When A-MSDU aggregation is used, a single MPDU will consist of + * multiple MSDUs. This function checks a MSDU's rx descriptor to + * see whether the MSDU is the first MSDU within a MPDU. + * + * @param pdev - the handle of the physical device the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - this is interior MSDU in the A-MSDU / MPDU + * -OR- + * 1 - this is the first MSDU within its MPDU + */ +extern bool (*htt_rx_msdu_first_msdu_flag)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Retrieve encrypt bit from a mpdu desc. + * @details + * Fw will pass all the frame to the host whether encrypted or not, and will + * indicate the encrypt flag in the desc, this function is to get the info + * and used to make a judge whether should make pn check, because + * non-encrypted frames always get the same pn number 0. + * + * @param pdev - the HTT instance the rx data was received on + * @param mpdu_desc - the abstract descriptor for the MPDU in question + * @return 0 - the frame was not encrypted + * 1 - the frame was encrypted + */ +extern bool (*htt_rx_mpdu_is_encrypted)(htt_pdev_handle pdev, void *mpdu_desc); + +/** + * @brief Indicate whether a rx desc has a WLAN unicast vs. mcast/bcast flag. + * @details + * A flag indicating whether a MPDU was delivered over WLAN as unicast or + * multicast/broadcast may be only valid once per MPDU (LL), or within each + * rx descriptor for the MSDUs within the MPDU (HL). (In practice, it is + * unlikely that A-MSDU aggregation will be used in HL, so typically HL will + * only have one MSDU per MPDU anyway.) + * This function indicates whether the specified rx descriptor contains + * a WLAN ucast vs. mcast/bcast flag. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The rx descriptor does not contain a WLAN ucast vs. mcast flag. + * -OR- + * 1 - The rx descriptor has a valid WLAN ucast vs. mcast flag. + */ +extern int (*htt_rx_msdu_has_wlan_mcast_flag)(htt_pdev_handle pdev, + void *msdu_desc); + +/** + * @brief Indicate whether a MSDU was received as unicast or mcast/bcast + * @details + * Indicate whether the MPDU that the specified MSDU belonged to was + * delivered over the WLAN as unicast, or as multicast/broadcast. + * This query can only be performed on rx descriptors for which + * htt_rx_msdu_has_wlan_mcast_flag is true. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU was delivered over the WLAN as unicast. + * -OR- + * 1 - The MSDU was delivered over the WLAN as broadcast or multicast. + */ +extern bool (*htt_rx_msdu_is_wlan_mcast)(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU was received as a fragmented frame + * @details + * This query can only be performed on LL system. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU was a non-fragmented frame. + * -OR- + * 1 - The MSDU was fragmented frame. + */ +extern int (*htt_rx_msdu_is_frag)(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate if a MSDU should be delivered to the OS shim or discarded. + * @details + * Indicate whether a MSDU should be discarded or delivered to the OS shim. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU should be delivered to the OS + * -OR- + * non-zero - The MSDU should not be delivered to the OS. + * If the "forward" flag is set, it should be forwarded to tx. + * Else, it should be discarded. + */ +int htt_rx_msdu_discard(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU should be forwarded to tx. + * @details + * Indicate whether a MSDU should be forwarded to tx, e.g. for intra-BSS + * STA-to-STA forwarding in an AP, or for multicast echo in an AP. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - The MSDU should not be forwarded + * -OR- + * non-zero - The MSDU should be forwarded. + * If the "discard" flag is set, then the original MSDU can be + * directly forwarded into the tx path. + * Else, a copy (clone?) of the rx MSDU needs to be created to + * send to the tx path. + */ +int htt_rx_msdu_forward(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Indicate whether a MSDU's contents need to be inspected. + * @details + * Indicate whether the host data SW needs to examine the contents of the + * received MSDU, and based on the packet type infer what special handling + * to provide for the MSDU. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @return + * 0 - No inspection + special handling is required. + * -OR- + * non-zero - Inspect the MSDU contents to infer what special handling + * to apply to the MSDU. + */ +int htt_rx_msdu_inspect(htt_pdev_handle pdev, void *msdu_desc); + +/** + * @brief Provide all action specifications for a rx MSDU + * @details + * Provide all action specifications together. This provides the same + * information in a single function call as would be provided by calling + * the functions htt_rx_msdu_discard, htt_rx_msdu_forward, and + * htt_rx_msdu_inspect. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @param[out] discard - 1: discard the MSDU, 0: deliver the MSDU to the OS + * @param[out] forward - 1: forward the rx MSDU to tx, 0: no rx->tx forward + * @param[out] inspect - 1: process according to MSDU contents, 0: no inspect + */ +void +htt_rx_msdu_actions(htt_pdev_handle pdev, + void *msdu_desc, int *discard, int *forward, int *inspect); + +/** + * @brief Get the key id sent in IV of the frame + * @details + * Provide the key index octet which is taken from IV. + * This is valid only for the first MSDU. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu_desc - the abstract descriptor for the MSDU in question + * @key_id - Key id octet + * @return indication of whether key id access is successful + * true - Success + * false - if this is not first msdu + */ +extern bool +(*htt_rx_msdu_desc_key_id)(htt_pdev_handle pdev, + void *mpdu_desc, uint8_t *key_id); + +extern bool +(*htt_rx_msdu_chan_info_present)( + htt_pdev_handle pdev, + void *mpdu_desc); + +extern bool +(*htt_rx_msdu_center_freq)( + htt_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + void *mpdu_desc, + uint16_t *primary_chan_center_freq_mhz, + uint16_t *contig_chan1_center_freq_mhz, + uint16_t *contig_chan2_center_freq_mhz, + uint8_t *phy_mode); + +/*====================== rx MSDU + descriptor delivery ======================*/ + +/** + * @brief Return a linked-list of network buffer holding the next rx A-MSDU. + * @details + * In some systems, the rx MSDUs are uploaded along with the rx + * indication message, while in other systems the rx MSDUs are uploaded + * out of band, via MAC DMA. + * This function provides an abstract way to obtain a linked-list of the + * next MSDUs, regardless of whether the MSDU was delivered in-band with + * the rx indication message, or out of band through MAC DMA. + * In a LL system, this function returns a linked list of the one or more + * MSDUs that together comprise an A-MSDU. + * In a HL system, this function returns a degenerate linked list consisting + * of a single MSDU (head_msdu == tail_msdu). + * This function also makes sure each MSDU's rx descriptor can be found + * through the MSDU's network buffer. + * In most systems, this is trivial - a single network buffer stores both + * the MSDU rx descriptor and the MSDU payload. + * In systems where the rx descriptor is in a separate buffer from the + * network buffer holding the MSDU payload, a pointer to the rx descriptor + * has to be stored in the network buffer. + * After this function call, the descriptor for a given MSDU can be + * obtained via the htt_rx_msdu_desc_retrieve function. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @param head_msdu - call-by-reference network buffer handle, which gets set + * in this function to point to the head MSDU of the A-MSDU + * @param tail_msdu - call-by-reference network buffer handle, which gets set + * in this function to point to the tail MSDU of the A-MSDU, or the + * same MSDU that the head_msdu points to if only a single MSDU is + * delivered at a time. + * @return indication of whether any MSDUs in the AMSDU use chaining: + * 0 - no buffer chaining + * 1 - buffers are chained + */ +extern int +(*htt_rx_amsdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +extern int +(*htt_rx_frag_pop)(htt_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + qdf_nbuf_t *head_msdu, qdf_nbuf_t *tail_msdu, + uint32_t *msdu_count); + +/** + * @brief Return the maximum number of available msdus currently + * + * @param pdev - the HTT instance the rx data was received on + */ +extern int +(*htt_rx_offload_msdu_cnt)( + htt_pdev_handle pdev); + +/** + * @brief Return a linked list of buffers holding one MSDU + * In some systems the buffers are delivered along with offload delivery + * indication message itself, while in other systems the buffers are uploaded + * out of band, via MAC DMA. + * @details + * This function provides an abstract way to obtain a linked-list of the + * buffers corresponding to an msdu, regardless of whether the MSDU was + * delivered in-band with the rx indication message, or out of band through + * MAC DMA. + * In a LL system, this function returns a linked list of one or more + * buffers corresponding to an MSDU + * In a HL system , TODO + * + * @param pdev - the HTT instance the rx data was received on + * @param offload_deliver_msg - the nebuf containing the offload deliver message + * @param head_msdu - call-by-reference network buffer handle, which gets set in + * this function to the head buffer of this MSDU + * @param tail_msdu - call-by-reference network buffer handle, which gets set in + * this function to the tail buffer of this MSDU + */ +extern int +(*htt_rx_offload_msdu_pop)(htt_pdev_handle pdev, + qdf_nbuf_t offload_deliver_msg, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); + +/** + * @brief Return the rx descriptor for the next rx MPDU. + * @details + * The rx MSDU descriptors may be uploaded as part of the rx indication + * message, or delivered separately out of band. + * This function provides an abstract way to obtain the next MPDU descriptor, + * regardless of whether the MPDU descriptors are delivered in-band with + * the rx indication message, or out of band. + * This is used to iterate through the series of MPDU descriptors referenced + * by a rx indication message. + * The htt_rx_amsdu_pop function should be called before this function + * (or at least before using the returned rx descriptor handle), so that + * the cache location for the rx descriptor will be flushed before the + * rx descriptor gets used. + * + * @param pdev - the HTT instance the rx data was received on + * @param rx_ind_msg - the netbuf containing the rx indication message + * @return next abstract rx descriptor from the series of MPDUs referenced + * by an rx ind msg + */ +extern void * +(*htt_rx_mpdu_desc_list_next)(htt_pdev_handle pdev, qdf_nbuf_t rx_ind_msg); + +/** + * @brief Retrieve a previously-stored rx descriptor from a MSDU buffer. + * @details + * The data SW will call the htt_rx_msdu_desc_link macro/function to + * link a MSDU's rx descriptor with the buffer holding the MSDU payload. + * This function retrieves the rx MSDU descriptor. + * + * @param pdev - the HTT instance the rx data was received on + * @param msdu - the buffer containing the MSDU payload + * @return the corresponding abstract rx MSDU descriptor + */ +extern void * +(*htt_rx_msdu_desc_retrieve)(htt_pdev_handle pdev, qdf_nbuf_t msdu); + +/** + * @brief Free both an rx MSDU descriptor and the associated MSDU buffer. + * @details + * Usually the WLAN driver does not free rx MSDU buffers, but needs to + * do so when an invalid frame (e.g. FCS error) was deposited into the + * queue of rx buffers. + * This function frees both the rx descriptor and the rx frame. + * On some systems, the rx descriptor and rx frame are stored in the + * same buffer, and thus one free suffices for both objects. + * On other systems, the rx descriptor and rx frame are stored + * separately, so distinct frees are internally needed. + * However, in either case, the rx descriptor has been associated with + * the MSDU buffer, and can be retrieved by htt_rx_msdu_desc_retrieve. + * Hence, it is only necessary to provide the MSDU buffer; the HTT SW + * internally finds the corresponding MSDU rx descriptor. + * + * @param htt_pdev - the HTT instance the rx data was received on + * @param rx_msdu_desc - rx descriptor for the MSDU being freed + * @param msdu - rx frame buffer for the MSDU being freed + */ +void htt_rx_desc_frame_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu); + +/** + * @brief Look up and free the rx descriptor for a MSDU. + * @details + * When the driver delivers rx frames to the OS, it first needs + * to free the associated rx descriptors. + * In some systems the rx descriptors are allocated in the same + * buffer as the rx frames, so this operation is a no-op. + * In other systems, the rx descriptors are stored separately + * from the rx frames, so the rx descriptor has to be freed. + * The descriptor is located from the MSDU buffer with the + * htt_rx_desc_frame_free macro/function. + * + * @param htt_pdev - the HTT instance the rx data was received on + * @param msdu - rx frame buffer for the rx MSDU descriptor being freed + */ +void htt_rx_msdu_desc_free(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu); + +/** + * @brief Add new MSDU buffers for the target to fill. + * @details + * In some systems, the underlying upload mechanism (HIF) allocates new rx + * buffers itself. In other systems, the underlying upload mechanism + * (MAC DMA) needs to be provided with new rx buffers. + * This function is used as an abstract method to indicate to the underlying + * data upload mechanism when it is an appropriate time to allocate new rx + * buffers. + * If the allocation is automatically handled, a la HIF, then this function + * call is ignored. + * If the allocation has to be done explicitly, a la MAC DMA, then this + * function provides the context and timing for such replenishment + * allocations. + * + * @param pdev - the HTT instance the rx data will be received on + */ +void htt_rx_msdu_buff_replenish(htt_pdev_handle pdev); + +/** + * @brief Add new MSDU buffers for the target to fill. + * @details + * This is full_reorder_offload version of the replenish function. + * In full_reorder, FW sends HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND + * msg to host. It includes the number of MSDUs. Thgis will be fed + * into htt_rx_msdu_buff_in_order_replenish function. + * The reason for creating yet another function is to avoid checks + * in real-time. + * + * @param pdev - the HTT instance the rx data will be received on + * @num - number of buffers to replenish + * + * Return: number of buffers actually replenished + */ +#ifndef CONFIG_HL_SUPPORT +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num); +#else +static inline +int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num) +{ + return 0; +} +#endif + +/** + * @brief Links list of MSDUs into an single MPDU. Updates RX stats + * @details + * When HW MSDU splitting is turned on each MSDU in an AMSDU MPDU occupies + * a separate wbuf for delivery to the network stack. For delivery to the + * monitor mode interface they need to be restitched into an MPDU. This + * function does this. Also updates the RX status if the MPDU starts + * a new PPDU + * + * @param pdev - the HTT instance the rx data was received on + * @param head_msdu - network buffer handle, which points to the first MSDU + * in the list. This is a NULL terminated list + * @param rx_status - pointer to the status associated with this MPDU. + * Updated only if there is a new PPDU and new status associated with it + * @param clone_not_reqd - If set the MPDU linking destroys the passed in + * list, else operates on a cloned nbuf + * @return network buffer handle to the MPDU + */ +#if defined(FEATURE_MONITOR_MODE_SUPPORT) +#if !defined(QCA6290_HEADERS_DEF) && !defined(QCA6390_HEADERS_DEF) && \ + !defined(QCA6490_HEADERS_DEF) && !defined(QCA6750_HEADERS_DEF) +qdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + qdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned clone_not_reqd); +#else +static inline qdf_nbuf_t +htt_rx_restitch_mpdu_from_msdus(htt_pdev_handle pdev, + qdf_nbuf_t head_msdu, + struct ieee80211_rx_status *rx_status, + unsigned clone_not_reqd) +{ + return NULL; +} +#endif +#endif +/** + * @brief Return the sequence number of MPDUs to flush. + * @param pdev - the HTT instance the rx data was received on + * @param rx_frag_ind_msg - the netbuf containing the rx fragment indication + * message + * @param seq_num_start - (call-by-reference output) sequence number + * for the start of the range of MPDUs to flush + * @param seq_num_end - (call-by-reference output) sequence number + * for the end of the range of MPDUs to flush + */ +void +htt_rx_frag_ind_flush_seq_num_range(htt_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + uint16_t *seq_num_start, uint16_t *seq_num_end); + +#ifdef CONFIG_HL_SUPPORT +/** + * htt_rx_msdu_rx_desc_size_hl() - Return the HL rx desc size + * @pdev: the HTT instance the rx data was received on. + * @msdu_desc: the hl rx desc pointer + * + * Return: HL rx desc size + */ +uint16_t htt_rx_msdu_rx_desc_size_hl(htt_pdev_handle pdev, void *msdu_desc); +#else +static inline +uint16_t htt_rx_msdu_rx_desc_size_hl(htt_pdev_handle pdev, void *msdu_desc) +{ + return 0; +} +#endif + +/** + * @brief populates vowext stats by processing RX desc. + * @param msdu - network buffer handle + * @param vowstats - handle to vow ext stats. + */ +void htt_rx_get_vowext_stats(qdf_nbuf_t msdu, struct vow_extstats *vowstats); + +/** + * @brief parses the offload message passed by the target. + * @param pdev - pdev handle + * @param paddr - physical address of the rx buffer + * @param vdev_id - reference to vdev id to be filled + * @param peer_id - reference to the peer id to be filled + * @param tid - reference to the tid to be filled + * @param fw_desc - reference to the fw descriptor to be filled + * @param peer_id - reference to the peer id to be filled + * @param head_buf - reference to the head buffer + * @param tail_buf - reference to the tail buffer + */ +int +htt_rx_offload_paddr_msdu_pop_ll(htt_pdev_handle pdev, + uint32_t *msg_word, + int msdu_iter, + int *vdev_id, + int *peer_id, + int *tid, + uint8_t *fw_desc, + qdf_nbuf_t *head_buf, qdf_nbuf_t *tail_buf); + +uint32_t htt_rx_amsdu_rx_in_order_get_pktlog(qdf_nbuf_t rx_ind_msg); + +/** + * htt_rx_update_smmu_map() - set smmu map/unmap for rx buffers + * @pdev: htt pdev handle + * @map: value to set smmu map/unmap for rx buffers + * + * Return: QDF_STATUS + */ +QDF_STATUS htt_rx_update_smmu_map(struct htt_pdev_t *pdev, bool map); + +/** htt_tx_enable_ppdu_end + * @enable_ppdu_end - set it to 1 if WLAN_FEATURE_TSF_PLUS is defined, + * else do nothing + */ +#ifdef WLAN_FEATURE_TSF_PLUS +void htt_rx_enable_ppdu_end(int *enable_ppdu_end); +#else +static inline +void htt_rx_enable_ppdu_end(int *enable_ppdu_end) +{ +} +#endif + +#endif /* _OL_HTT_RX_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h new file mode 100644 index 0000000000..834c5a4781 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_htt_tx_api.h @@ -0,0 +1,844 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_htt_tx_api.h + * @brief Specify the tx HTT API functions called by the host data SW. + * @details + * This file declares the HTT API functions that are specifically + * related to transmit processing. + * In particular, the methods of the abstract HTT tx descriptor are + * specified. + */ +#ifndef _OL_HTT_TX_API__H_ +#define _OL_HTT_TX_API__H_ + +/* #include / * uint16_t, etc. * / */ +#include /* uint16_t, etc. */ +#include /* qdf_nbuf_t */ +#include /* wlan_frm_fmt */ + +#include /* needed by inline functions */ +#include +#include /* htt_pdev_handle */ +#include +#include +#include + +#define HTT_INVALID_CHANNEL -1 + +/* Remove these macros when they get added to htt.h. */ +#ifndef HTT_TX_DESC_EXTENSION_GET +#define HTT_TX_DESC_EXTENSION_OFFSET_DWORD 0 +#define HTT_TX_DESC_EXTENSION_M 0x10000000 +#define HTT_TX_DESC_EXTENSION_S 28 + +#define HTT_TX_DESC_EXTENSION_GET(_var) \ + (((_var) & HTT_TX_DESC_EXTENSION_M) >> HTT_TX_DESC_EXTENSION_S) +#define HTT_TX_DESC_EXTENSION_SET(_var, _val) \ + do { \ + HTT_CHECK_SET_VAL(HTT_TX_DESC_EXTENSION, _val); \ + ((_var) |= ((_val) << HTT_TX_DESC_EXTENSION_S)); \ + } while (0) +#endif + +/*================ meta-info about tx MSDUs =================================*/ + +/* + * For simplicity, use the IEEE 802.11 frame type values. + */ +enum htt_frm_type { + htt_frm_type_mgmt = 0, + htt_frm_type_ctrl = 1, + htt_frm_type_data = 2 +}; + +/* + * For simplicity, use the IEEE 802.11 frame sub-type values. + */ +enum htt_frm_subtype { + htt_frm_subtype_mgmt_assoc_req = 0, + htt_frm_subtype_mgmt_assoc_resp = 1, + htt_frm_subtype_mgmt_reassoc_req = 2, + htt_frm_subtype_mgmt_reassoc_resp = 3, + htt_frm_subtype_mgmt_probe_req = 4, + htt_frm_subtype_mgmt_probe_resp = 5, + htt_frm_subtype_mgmt_timing_adv = 6, + htt_frm_subtype_mgmt_beacon = 8, + htt_frm_subtype_mgmt_atim = 9, + htt_frm_subtype_mgmt_disassoc = 10, + htt_frm_subtype_mgmt_auth = 11, + htt_frm_subtype_mgmt_deauth = 12, + htt_frm_subtype_mgmt_action = 13, + htt_frm_subtype_mgmt_action_no_ack = 14, + + htt_frm_subtype_data_data = 0, + htt_frm_subtype_data_data_cf_ack = 1, + htt_frm_subtype_data_data_cf_poll = 2, + htt_frm_subtype_data_data_cf_ack_cf_poll = 3, + htt_frm_subtype_data_null = 4, + htt_frm_subtype_data_cf_ack = 5, + htt_frm_subtype_data_cf_poll = 6, + htt_frm_subtype_data_cf_ack_cf_poll = 7, + htt_frm_subtype_data_QoS_data = 8, + htt_frm_subtype_data_QoS_data_cf_ack = 9, + htt_frm_subtype_data_QoS_data_cf_poll = 10, + htt_frm_subtype_data_QoS_data_cf_ack_cf_poll = 11, + htt_frm_subtype_data_QoS_null = 12, + htt_frm_subtype_data_QoS_cf_poll = 14, + htt_frm_subtype_data_QoS_cf_ack_cf_poll = 15, +}; + +enum htt_ofdm_datarate { /* Value MBPS Modulation Coding*/ + htt_ofdm_datarate_6_mbps = 0, /* 0 6 BPSK 1/2 */ + htt_ofdm_datarate_9_mbps = 1, /* 1 9 BPSK 3/4 */ + htt_ofdm_datarate_12_mbps = 2, /* 2 12 QPSK 1/2 */ + htt_ofdm_datarate_18_mbps = 3, /* 3 18 QPSK 3/4 */ + htt_ofdm_datarate_24_mbps = 4, /* 4 24 16-QAM 1/2 */ + htt_ofdm_datarate_36_mbps = 5, /* 5 36 16-QAM 3/4 */ + htt_ofdm_datarate_48_mbps = 6, /* 6 48 64-QAM 1/2 */ + htt_ofdm_datarate_54_mbps = 7, /* 7 54 64-QAM 3/4 */ + htt_ofdm_datarate_max = 7, +}; + +/** + * struct ocb_tx_ctrl_hdr_t - TX control header + * @version: must be 1 + * @length: length of this structure + * @channel_freq: channel on which to transmit the packet + * @valid_pwr: bit 0: if set, tx pwr spec is valid + * @valid_datarate: bit 1: if set, tx MCS mask spec is valid + * @valid_retries: bit 2: if set, tx retries spec is valid + * @valid_chain_mask: bit 3: if set, chain mask is valid + * @valid_expire_tsf: bit 4: if set, tx expire TSF spec is valid + * @valid_tid: bit 5: if set, TID is valid + * @reserved0_15_6: bits 15:6 - unused, set to 0x0 + * @all_flags: union of all the flags + * @expire_tsf_lo: TX expiry time (TSF) LSBs + * @expire_tsf_hi: TX expiry time (TSF) MSBs + * @pwr: Specify what power the tx frame needs to be transmitted + * at. The power a signed (two's complement) value is in + * units of 0.5 dBm. The value needs to be appropriately + * sign-extended when extracting the value from the message + * and storing it in a variable that is larger than A_INT8. + * If the transmission uses multiple tx chains, this power + * spec is the total transmit power, assuming incoherent + * combination of per-chain power to produce the total + * power. + * @datarate: The desired modulation and coding scheme. + * VALUE DATA RATE MODULATION CODING RATE + * @ 20 MHz + * (MBPS) + * 0 6 BPSK 1/2 + * 1 9 BPSK 3/4 + * 2 12 QPSK 1/2 + * 3 18 QPSK 3/4 + * 4 24 16-QAM 1/2 + * 5 36 16-QAM 3/4 + * 6 48 64-QAM 1/2 + * 7 54 64-QAM 3/4 + * @retry_limit: Specify the maximum number of transmissions, including + * the initial transmission, to attempt before giving up if + * no ack is received. + * If the tx rate is specified, then all retries shall use + * the same rate as the initial transmission. + * If no tx rate is specified, the target can choose + * whether to retain the original rate during the + * retransmissions, or to fall back to a more robust rate. + * @chain_mask: specify which chains to transmit from + * @ext_tid: Extended Traffic ID (0-15) + * @reserved: Ensure that the size of the structure is a multiple of + * 4. Must be 0. + * + * When sending an OCB packet, the user application has + * the option of including the following struct following an ethernet header + * with the proto field set to 0x8151. This struct includes various TX + * parameters including the TX power and MCS. + */ +PREPACK struct ocb_tx_ctrl_hdr_t { + uint16_t version; + uint16_t length; + uint16_t channel_freq; + + union { + struct { + uint16_t + valid_pwr:1, + valid_datarate:1, + valid_retries:1, + valid_chain_mask:1, + valid_expire_tsf:1, + valid_tid:1, + reserved0_15_6:10; + }; + uint16_t all_flags; + }; + + uint32_t expire_tsf_lo; + uint32_t expire_tsf_hi; + int8_t pwr; + uint8_t datarate; + uint8_t retry_limit; + uint8_t chain_mask; + uint8_t ext_tid; + uint8_t reserved[3]; +} POSTPACK; + +/** + * @brief tx MSDU meta-data that HTT may use to program the FW/HW tx descriptor + */ +struct htt_msdu_info_t { + /* the info sub-struct specifies the characteristics of the MSDU */ + struct { + uint16_t ethertype; +#define HTT_INVALID_PEER_ID 0xffff + uint16_t peer_id; + uint8_t vdev_id; + uint8_t ext_tid; + /* + * l2_hdr_type - L2 format (802.3, native WiFi 802.11, + * or raw 802.11) + * Based on attach-time configuration, the tx frames provided + * by the OS to the tx data SW are expected to be either + * 802.3 format or the "native WiFi" variant of 802.11 format. + * Internally, the driver may also inject tx frames into the tx + * datapath, and these frames may be either 802.3 format or + * 802.11 "raw" format, with no further 802.11 encapsulation + * needed. + * The tx frames are tagged with their frame format, so target + * FW/HW will know how to interpret the packet's encapsulation + * headers when doing tx classification, and what form of 802.11 + * header encapsulation is needed, if any. + */ + uint8_t l2_hdr_type; /* enum htt_pkt_type */ + /* + * frame_type - is the tx frame management or data? + * Just to avoid confusion, the enum values for this frame type + * field use the 802.11 frame type values, although it is + * unexpected for control frames to be sent through the host + * data path. + */ + uint8_t frame_type; /* enum htt_frm_type */ + /* + * frame subtype - this field specifies the sub-type of + * management frames + * Just to avoid confusion, the enum values for this frame + * subtype field use the 802.11 management frame subtype values. + */ + uint8_t frame_subtype; /* enum htt_frm_subtype */ + uint8_t is_unicast; + + /* dest_addr is not currently used. + * It could be used as an input to a Tx BD (Riva tx descriptor) + * signature computation. + uint8_t *dest_addr; + */ + + uint8_t l3_hdr_offset; /* wrt qdf_nbuf_data(msdu), in bytes */ + + /* l4_hdr_offset is not currently used. + * It could be used to specify to a TCP/UDP checksum computation + * engine where the TCP/UDP header starts. + */ + /* uint8_t l4_hdr_offset; - wrt qdf_nbuf_data(msdu), in bytes */ + } info; + /* the action sub-struct specifies how to process the MSDU */ + struct { + /* mgmt frames: option to force 6 Mbps rate */ + uint8_t use_6mbps; + uint8_t do_encrypt; + uint8_t do_tx_complete; + uint8_t tx_comp_req; + + /* + * cksum_offload - Specify whether checksum offload is + * enabled or not + * Target FW uses this flag to turn on HW checksumming + * 0x0 - No checksum offload + * 0x1 - L3 header checksum only + * 0x2 - L4 checksum only + * 0x3 - L3 header checksum + L4 checksum + */ + qdf_nbuf_tx_cksum_t cksum_offload; + } action; +}; + +static inline void htt_msdu_info_dump(struct htt_msdu_info_t *msdu_info) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "HTT MSDU info object (%pK)\n", msdu_info); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " ethertype: %#x\n", msdu_info->info.ethertype); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " peer_id: %d\n", msdu_info->info.peer_id); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " vdev_id: %d\n", msdu_info->info.vdev_id); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " ext_tid: %d\n", msdu_info->info.ext_tid); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " l2_hdr_type: %d\n", msdu_info->info.l2_hdr_type); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " frame_type: %d\n", msdu_info->info.frame_type); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " frame_subtype: %d\n", msdu_info->info.frame_subtype); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " l3_hdr_offset: %u\n", msdu_info->info.l3_hdr_offset); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " use 6 Mbps: %d\n", msdu_info->action.use_6mbps); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " do_encrypt: %d\n", msdu_info->action.do_encrypt); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " do_tx_complete: %d\n", msdu_info->action.do_tx_complete); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + " is_unicast: %u\n", msdu_info->info.is_unicast); +} + +/*================ tx completion message field access methods ===============*/ + +/** + * @brief Look up the descriptor ID of the nth MSDU from a tx completion msg. + * @details + * A tx completion message tells the host that the target is done + * transmitting a series of MSDUs. The message uses a descriptor ID + * to identify each such MSDU. This function/macro is used to + * find the ID of one such MSDU referenced by the tx completion message. + * + * @param iterator - tx completion message context provided by HTT to the + * tx completion message handler. This abstract reference to the + * HTT tx completion message's payload allows the data SW's tx + * completion handler to not care about the format of the HTT + * tx completion message. + * @param num - (zero-based) index to specify a single MSDU within the + * series of MSDUs referenced by the tx completion message + * @return descriptor ID for the specified MSDU + */ +uint16_t htt_tx_compl_desc_id(void *iterator, int num); + +/*========================= tx descriptor operations ========================*/ + +/** + * @brief Allocate a HTT abstract tx descriptor. + * @details + * Allocate a HTT abstract tx descriptor from a pool within "consistent" + * memory, which is accessible by HIF and/or MAC DMA as well as by the + * host CPU. + * It is expected that the tx datapath will allocate HTT tx descriptors + * and link them with datapath SW tx descriptors up front as the driver + * is loaded. Thereafter, the link from datapath SW tx descriptor to + * HTT tx descriptor will be maintained until the driver is unloaded. + * + * @param htt_pdev - handle to the HTT instance making the allocation + * @param[OUT] paddr_lo - physical address of the HTT descriptor + * @return success -> descriptor handle, -OR- failure -> NULL + */ +void *htt_tx_desc_alloc(htt_pdev_handle pdev, qdf_dma_addr_t *paddr, + uint16_t index); + +/** + * @brief Free a HTT abstract tx descriptor. + * + * @param htt_pdev - handle to the HTT instance that made the allocation + * @param htt_tx_desc - the descriptor to free + */ +void htt_tx_desc_free(htt_pdev_handle htt_pdev, void *htt_tx_desc); + +#if defined(HELIUMPLUS) +/** + * @brief Allocate TX frag descriptor + * @details + * Allocate TX frag descriptor + * + * @param pdev - handle to the HTT instance that made the allocation + * @param index - tx descriptor index + * @param frag_paddr_lo - fragment descriptor physical address lower 32bits + * @param frag_ptr - fragment descriptor hlos pointe + * @return success 0 + */ +int htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr); +#else +static inline int htt_tx_frag_alloc(htt_pdev_handle pdev, + u_int16_t index, qdf_dma_addr_t *frag_paddr, void **frag_ptr) +{ + *frag_ptr = NULL; + return 0; +} +#endif /* defined(HELIUMPLUS) */ + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Discard all tx frames in the process of being downloaded. + * @details + * This function discards any tx frames queued in HTT or the layers + * under HTT. + * The download completion callback is invoked on these frames. + * + * @param htt_pdev - handle to the HTT instance + * @param[OUT] frag_paddr_lo - physical address of the fragment descriptor + * (MSDU Link Extension Descriptor) + */ +static inline void htt_tx_pending_discard(htt_pdev_handle pdev) +{ +} +#else + +void htt_tx_pending_discard(htt_pdev_handle pdev); +#endif + +/** + * @brief Download a MSDU descriptor and (a portion of) the MSDU payload. + * @details + * This function is used within LL systems to download a tx descriptor and + * the initial portion of the tx MSDU payload, and within HL systems to + * download the tx descriptor and the entire tx MSDU payload. + * The HTT layer determines internally how much of the tx descriptor + * actually needs to be downloaded. In particular, the HTT layer does not + * download the fragmentation descriptor, and only for the LL case downloads + * the physical address of the fragmentation descriptor. + * In HL systems, the tx descriptor and the entire frame are downloaded. + * In LL systems, only the tx descriptor and the header of the frame are + * downloaded. To determine how much of the tx frame to download, this + * function assumes the tx frame is the default frame type, as specified + * by ol_cfg_frame_type. "Raw" frames need to be transmitted through the + * alternate htt_tx_send_nonstd function. + * The tx descriptor has already been attached to the qdf_nbuf object during + * a preceding call to htt_tx_desc_init. + * + * @param htt_pdev - the handle of the physical device sending the tx data + * @param msdu - the frame being transmitted + * @param msdu_id - unique ID for the frame being transmitted + * @return 0 -> success, -OR- 1 -> failure + */ +int +htt_tx_send_std(htt_pdev_handle htt_pdev, qdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Download a Batch Of Tx MSDUs + * @details + * Each MSDU already has the MSDU ID stored in the headroom of the + * netbuf data buffer, and has the HTT tx descriptor already attached + * as a prefix fragment to the netbuf. + * + * @param htt_pdev - the handle of the physical device sending the tx data + * @param head_msdu - the MSDU Head for Tx batch being transmitted + * @param num_msdus - The total Number of MSDU's provided for batch tx + * @return null-terminated linked-list of unaccepted frames + */ +qdf_nbuf_t +htt_tx_send_batch(htt_pdev_handle htt_pdev, + qdf_nbuf_t head_msdu, int num_msdus); + +/* The htt scheduler for queued packets in htt + * htt when unable to send to HTC because of lack of resource + * forms a nbuf queue which is flushed when tx completion event from + * target is received + */ + +void htt_tx_sched(htt_pdev_handle pdev); + +/** + * @brief Same as htt_tx_send_std, but can handle raw frames. + */ +int +htt_tx_send_nonstd(htt_pdev_handle htt_pdev, + qdf_nbuf_t msdu, + uint16_t msdu_id, enum htt_pkt_type pkt_type); + +/** + * htt_pkt_dl_len_get() Gets the HTT PKT download length. + * @pdev: pointer to struct htt_pdev_t + * + * Return: size of HTT packet download length. + */ +int +htt_pkt_dl_len_get(struct htt_pdev_t *pdev); + +/* Used to set classify bit in HTT desc.*/ +#define HTT_TX_CLASSIFY_BIT_S 4 + +/** + * enum htt_ce_tx_pkt_type - enum of packet types to be set in CE + * descriptor + * @tx_pkt_type_raw: Value set for RAW frames + * @tx_pkt_type_native_wifi: Value set for NATIVE WIFI frames + * @tx_pkt_type_eth2: Value set for Ethernet II frames (mostly default) + * @tx_pkt_type_802_3: Value set for 802.3 / original ethernet frames + * @tx_pkt_type_mgmt: Value set for MGMT frames over HTT + * + */ +enum htt_ce_tx_pkt_type { + tx_pkt_type_raw = 0, + tx_pkt_type_native_wifi = 1, + tx_pkt_type_eth2 = 2, + tx_pkt_type_802_3 = 3, + tx_pkt_type_mgmt = 4 +}; + +/** + * enum extension_header_type - extension header type + * @EXT_HEADER_NOT_PRESENT: extension header not present + * @OCB_MODE_EXT_HEADER: Extension header for OCB mode + * @WISA_MODE_EXT_HEADER_6MBPS: WISA mode 6Mbps header + * @WISA_MODE_EXT_HEADER_24MBPS: WISA mode 24Mbps header + */ +enum extension_header_type { + EXT_HEADER_NOT_PRESENT, + OCB_MODE_EXT_HEADER, + WISA_MODE_EXT_HEADER_6MBPS, + WISA_MODE_EXT_HEADER_24MBPS, +}; + +extern const uint32_t htt_to_ce_pkt_type[]; + +/** + * Provide a constant to specify the offset of the HTT portion of the + * HTT tx descriptor, to avoid having to export the descriptor definition. + * The htt module checks internally that this exported offset is consistent + * with the private tx descriptor definition. + * + * Similarly, export a definition of the HTT tx descriptor size, and then + * check internally that this exported constant matches the private tx + * descriptor definition. + */ +#define HTT_TX_DESC_VADDR_OFFSET 8 + +/** + * htt_tx_desc_init() - Initialize the per packet HTT Tx descriptor + * @pdev: The handle of the physical device sending the + * tx data + * @htt_tx_desc: Abstract handle to the tx descriptor + * @htt_tx_desc_paddr_lo: Physical address of the HTT tx descriptor + * @msdu_id: ID to tag the descriptor with. + * The FW sends this ID back to host as a cookie + * during Tx completion, which the host uses to + * identify the MSDU. + * This ID is an index into the OL Tx desc. array. + * @msdu: The MSDU that is being prepared for transmission + * @msdu_info: Tx MSDU meta-data + * @tso_info: Storage for TSO meta-data + * @ext_header_data: extension header data + * @type: extension header type + * + * This function initializes the HTT tx descriptor. + * HTT Tx descriptor is a host-f/w interface structure, and meta-data + * accompanying every packet downloaded to f/w via the HTT interface. + * + * Return QDF_STATUS_SUCCESS for success, otherwise error. + */ +QDF_STATUS +htt_tx_desc_init(htt_pdev_handle pdev, + void *htt_tx_desc, + qdf_dma_addr_t htt_tx_desc_paddr, + uint16_t msdu_id, + qdf_nbuf_t msdu, struct htt_msdu_info_t *msdu_info, + struct qdf_tso_info_t *tso_info, + void *ext_header_data, + enum extension_header_type type); + +/** + * @brief Set a flag to indicate that the MSDU in question was postponed. + * @details + * In systems in which the host retains its tx frame until the target sends + * a tx completion, the target has the option of discarding it's copy of + * the tx descriptor (and frame, for HL) and sending a "postpone" message + * to the host, to inform the host that it must eventually download the + * tx descriptor (and frame, for HL). + * Before the host downloads the postponed tx desc/frame again, it will use + * this function to set a flag in the HTT tx descriptor indicating that this + * is a re-send of a postponed frame, rather than a new frame. The target + * uses this flag to keep the correct order between re-sent and new tx frames. + * This function is relevant for LL systems. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + */ +void htt_tx_desc_flag_postponed(htt_pdev_handle pdev, void *desc); + +/** + * @brief Set a flag to tell the target that more tx downloads are en route. + * @details + * At times, particularly in response to a U-APSD trigger in a HL system, the + * host will download multiple tx descriptors (+ frames, in HL) in a batch. + * The host will use this function to set a "more" flag in the initial + * and interior frames of the batch, to tell the target that more tx frame + * downloads within the batch are imminent. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + */ +void htt_tx_desc_flag_batch_more(htt_pdev_handle pdev, void *desc); + +/** + * @brief Specify the number of fragments in the fragmentation descriptor. + * @details + * Specify the number of fragments within the MSDU, i.e. the number of + * elements within the fragmentation descriptor. + * For LL, this is used to terminate the list of fragments used by the + * HW's tx MAC DMA. + * For HL, this is used to terminate the list of fragments provided to + * HTC for download. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the tx descriptor + * @param num_frags - the number of fragments comprising the MSDU + */ +static inline +void +htt_tx_desc_num_frags(htt_pdev_handle pdev, void *desc, uint32_t num_frags) +{ + /* + * Set the element after the valid frag elems to 0x0, + * to terminate the list of fragments. + */ +#if defined(HELIUMPLUS) + if (HTT_WIFI_IP(pdev, 2, 0)) { + struct msdu_ext_frag_desc *fdesc; + + /** Skip TSO related 4 dwords WIFI2.0*/ + fdesc = (struct msdu_ext_frag_desc *) + &(((struct msdu_ext_desc_t *)desc)->frags[0]); + fdesc[num_frags].u.desc64 = 0; + } else { + /* This piece of code should never be executed on HELIUMPLUS */ + *((u_int32_t *) + (((char *) desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0; + } +#else /* ! HELIUMPLUS */ + *((uint32_t *) + (((char *)desc) + HTT_TX_DESC_LEN + num_frags * 8)) = 0; +#endif /* HELIUMPLUS */ +} + +/* checksum offload flags for hw */ +#define IPV4_CSUM_EN 0x00010000 +#define UDP_IPV4_CSUM_EN 0x00020000 +#define UDP_IPV6_CSUM_EN 0x00040000 +#define TCP_IPV4_CSUM_EN 0x00080000 +#define TCP_IPV6_CSUM_EN 0x00100000 +#define PARTIAL_CSUM_EN 0x00200000 + +/** + * @brief Specify the location and size of a fragment of a tx MSDU. + * @details + * In LL systems, the tx MAC DMA needs to know how the MSDU is constructed + * from fragments. + * In LL and HL systems, the HIF's download DMA to the target (LL: tx desc + * + header of tx payload; HL: tx desc + entire tx payload) needs to know + * where to find the fragments to download. + * The tx data SW uses this function to specify the location and size of + * each of the MSDU's fragments. + * + * @param pdev - the handle of the physical device sending the tx data + * @param desc - abstract handle to the HTT tx descriptor + * @param frag_num - which fragment is being specified (zero-based indexing) + * @param frag_phys_addr - DMA/physical address of the fragment + * @param frag_len - number of bytes within the fragment + */ +static inline +void +htt_tx_desc_frag(htt_pdev_handle pdev, + void *desc, + int frag_num, qdf_dma_addr_t frag_phys_addr, uint16_t frag_len) +{ + uint32_t *word32; +#if defined(HELIUMPLUS) + uint64_t *word64; + + if (HTT_WIFI_IP(pdev, 2, 0)) { + word32 = (u_int32_t *)(desc); + /* Initialize top 6 words of TSO flags per packet */ + *word32++ = 0; + *word32++ = 0; + *word32++ = 0; + if (((struct txrx_pdev_cfg_t *)(pdev->ctrl_pdev)) + ->ip_tcp_udp_checksum_offload) + *word32 |= (IPV4_CSUM_EN | TCP_IPV4_CSUM_EN | + TCP_IPV6_CSUM_EN | UDP_IPV4_CSUM_EN | + UDP_IPV6_CSUM_EN); + else + *word32 = 0; + word32++; + *word32++ = 0; + *word32++ = 0; + + qdf_assert_always(word32 == (uint32_t *) + &(((struct msdu_ext_desc_t *)desc)->frags[0])); + + /* Each fragment consumes 2 DWORDS */ + word32 += (frag_num << 1); + word64 = (uint64_t *)word32; + *word64 = frag_phys_addr; + /* + * The frag_phys address is 37 bits. So, the higher 16 bits will + * be for len + */ + word32++; + *word32 &= 0x0000ffff; + *word32 |= (frag_len << 16); + } else { + /* For Helium+, this block cannot exist */ + QDF_ASSERT(0); + } +#else /* !defined(HELIUMPLUS) */ + { + uint64_t u64 = (uint64_t)frag_phys_addr; + uint32_t u32l = (u64 & 0xffffffff); + uint32_t u32h = (uint32_t)((u64 >> 32) & 0x1f); + uint64_t *word64; + + word32 = (uint32_t *) (((char *)desc) + + HTT_TX_DESC_LEN + frag_num * 8); + word64 = (uint64_t *)word32; + *word32 = u32l; + word32++; + *word32 = (u32h << 16) | frag_len; + } +#endif /* defined(HELIUMPLUS) */ +} + +void htt_tx_desc_frags_table_set(htt_pdev_handle pdev, + void *desc, + qdf_dma_addr_t paddr, + qdf_dma_addr_t frag_desc_paddr, + int reset); + +/** + * @brief Specify the type and subtype of a tx frame. + * + * @param pdev - the handle of the physical device sending the tx data + * @param type - format of the MSDU (802.3, native WiFi, raw, or mgmt) + * @param sub_type - sub_type (relevant for raw frames) + */ +static inline +void +htt_tx_desc_type(htt_pdev_handle pdev, + void *htt_tx_desc, enum htt_pkt_type type, uint8_t sub_type) +{ + uint32_t *word0; + + word0 = (uint32_t *) htt_tx_desc; + /* clear old values */ + *word0 &= ~(HTT_TX_DESC_PKT_TYPE_M | HTT_TX_DESC_PKT_SUBTYPE_M); + /* write new values */ + HTT_TX_DESC_PKT_TYPE_SET(*word0, type); + HTT_TX_DESC_PKT_SUBTYPE_SET(*word0, sub_type); +} + +/***** TX MGMT DESC management APIs ****/ + +/* Number of mgmt descriptors in the pool */ +#define HTT_MAX_NUM_MGMT_DESCS 32 + +/** htt_tx_mgmt_desc_pool_alloc + * @description - allocates the memory for mgmt frame descriptors + * @param - htt pdev object + * @param - num of descriptors to be allocated in the pool + */ +void htt_tx_mgmt_desc_pool_alloc(struct htt_pdev_t *pdev, A_UINT32 num_elems); + +/** htt_tx_mgmt_desc_alloc + * @description - reserves a mgmt descriptor from the pool + * @param - htt pdev object + * @param - pointer to variable to hold the allocated desc id + * @param - pointer to the mamangement from UMAC + * @return - pointer the allocated mgmt descriptor + */ +qdf_nbuf_t +htt_tx_mgmt_desc_alloc(struct htt_pdev_t *pdev, A_UINT32 *desc_id, + qdf_nbuf_t mgmt_frm); + +/** htt_tx_mgmt_desc_free + * @description - releases the management descriptor back to the pool + * @param - htt pdev object + * @param - descriptor ID + */ +void +htt_tx_mgmt_desc_free(struct htt_pdev_t *pdev, A_UINT8 desc_id, + A_UINT32 status); + +/** htt_tx_mgmt_desc_pool_free + * @description - releases all the resources allocated for mgmt desc pool + * @param - htt pdev object + */ +void htt_tx_mgmt_desc_pool_free(struct htt_pdev_t *pdev); + +/** + * @brief Provide a buffer to store a 802.11 header added by SW tx encap + * + * @param htt_tx_desc - which frame the 802.11 header is being added to + * @param new_l2_hdr_size - how large the buffer needs to be + */ +#define htt_tx_desc_mpdu_header(htt_tx_desc, new_l2_hdr_size) /*NULL*/ +/** + * @brief How many tx credits would be consumed by the specified tx frame. + * + * @param msdu - the tx frame in question + * @return number of credits used for this tx frame + */ +#define htt_tx_msdu_credit(msdu) 1 /* 1 credit per buffer */ +#ifdef HTT_DBG +void htt_tx_desc_display(void *tx_desc); +#else +#define htt_tx_desc_display(tx_desc) +#endif + +static inline void htt_tx_desc_set_peer_id(void *htt_tx_desc, uint16_t peer_id) +{ + uint16_t *peer_id_field_ptr; + + peer_id_field_ptr = (uint16_t *) + (htt_tx_desc + + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES); + + *peer_id_field_ptr = peer_id; +} + +static inline +void htt_tx_desc_set_chanfreq(void *htt_tx_desc, uint16_t chanfreq) +{ + uint16_t *chanfreq_field_ptr; + + /* + * The reason we dont use CHAN_FREQ_OFFSET_BYTES is because + * it uses DWORD as unit + * + * The reason we dont use the SET macro in htt.h is because + * htt_tx_desc is incomplete type + */ + chanfreq_field_ptr = (uint16_t *) + (htt_tx_desc + + HTT_TX_DESC_PEERID_DESC_PADDR_OFFSET_BYTES + + sizeof(A_UINT16)); + + *chanfreq_field_ptr = chanfreq; +} + +#if defined(FEATURE_TSO) && defined(HELIUMPLUS) +void +htt_tx_desc_fill_tso_info(htt_pdev_handle pdev, void *desc, + struct qdf_tso_info_t *tso_info); +#else +#define htt_tx_desc_fill_tso_info(pdev, desc, tso_info) +#endif +#endif /* _OL_HTT_TX_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h new file mode 100644 index 0000000000..8493d710a1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_api.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011-2014,2016-2017,2019,2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_api.h + * @brief Definitions used in multiple external interfaces to the txrx SW. + */ +#ifndef _OL_TXRX_API__H_ +#define _OL_TXRX_API__H_ + +#include "ol_txrx_htt_api.h" + +/** + * @brief ADDBA negotiation status, used both during requests and confirmations + */ +enum ol_addba_status { + /* status: negotiation started or completed successfully */ + ol_addba_success, + + /* reject: aggregation is not applicable - don't try again */ + ol_addba_reject, + + /* busy: ADDBA negotiation couldn't be performed - try again later */ + ol_addba_busy, +}; + +enum ol_sec_type { + ol_sec_type_none, + ol_sec_type_wep128, + ol_sec_type_wep104, + ol_sec_type_wep40, + ol_sec_type_tkip, + ol_sec_type_tkip_nomic, + ol_sec_type_aes_ccmp, + ol_sec_type_wapi, + + /* keep this last! */ + ol_sec_type_types +}; + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +typedef int (*tp_ol_timestamp_cb)(enum htt_tx_status status, + qdf_nbuf_t netbuf, uint64_t target_time); + +/** + * ol_register_timestamp_callback() - set callbacks for timestamp tx msdu. + * @ol_tx_timestamp_cb: callback function for time stamp tx msdu + * + * This function register timestamp callback, the callback will + * be called when tx a msdu + * + * Return: nothing + */ +void ol_register_timestamp_callback(tp_ol_timestamp_cb ol_tx_timestamp_cb); + +/** + * ol_deregister_timestamp_callback() - reset callbacks for timestamp + * tx msdu to NULL. + * + * This function reset the timestamp callbacks for tx + * + * Return: nothing + */ +void ol_deregister_timestamp_callback(void); +#endif +#endif /* _OL_TXRX_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h new file mode 100644 index 0000000000..bb14debfb0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_ctrl_api.h @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_ctrl_api.h + * @brief Define the host data API functions called by the host control SW. + */ +#ifndef _OL_TXRX_CTRL_API__H_ +#define _OL_TXRX_CTRL_API__H_ + +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ +#include /* qdf_device_t */ +#include /* HTC_HANDLE */ + +#include /* ol_sec_type */ +#include /* MAX_SPATIAL_STREAM */ +#include /* ol_pdev_handle, ol_vdev_handle, etc */ +#include +#include +#include +#define OL_ATH_TX_DRAIN_WAIT_DELAY 50 + +/** + * @brief Set up the data SW subsystem. + * @details + * As part of the WLAN device attach, the data SW subsystem has + * to be attached as a component within the WLAN device. + * This attach allocates and initializes the physical device object + * used by the data SW. + * The data SW subsystem attach needs to happen after the target has + * be started, and host / target parameter negotiation has completed, + * since the host data SW uses some of these host/target negotiated + * parameters (e.g. peer ID range) during the initializations within + * its attach function. + * However, the host data SW is not allowed to send HTC messages to the + * target within this pdev_attach function call, since the HTC setup + * has not complete at this stage of initializations. Any messaging + * to the target has to be done in the separate pdev_attach_target call + * that is invoked after HTC setup is complete. + * + * @param soc - datapath soc handle + * @param pdev_id - physical device instance id + * @return 0 for success or error code + */ +int +ol_txrx_pdev_post_attach(struct cdp_soc_t *soc, uint8_t pdev_id); + +/** + * @brief Parameter type to be input to ol_txrx_peer_update + * @details + * This struct is union,to be used to specify various information to update + * txrx peer object. + */ +union ol_txrx_peer_update_param_t { + uint8_t qos_capable; + uint8_t uapsd_mask; + enum ol_sec_type sec_type; +}; + +/** + * @brief Parameter type to be input to ol_txrx_peer_update + * @details + * This enum is used to specify what exact information in + * ol_txrx_peer_update_param_t + * is used to update the txrx peer object. + */ +enum ol_txrx_peer_update_select_t { + ol_txrx_peer_update_qos_capable = 1, + ol_txrx_peer_update_uapsdMask, + ol_txrx_peer_update_peer_security, +}; + +/** + * @brief Update the data peer object as some information changed in node. + * @details + * Only a single parameter can be changed for each call to this func. + * + * @param peer - pointer to the node's object + * @param param - new param to be updated in peer object. + * @param select - specify what's parameter needed to be update + */ +void +ol_txrx_peer_update(ol_txrx_vdev_handle data_vdev, uint8_t *peer_mac, + union ol_txrx_peer_update_param_t *param, + enum ol_txrx_peer_update_select_t select); + +#if defined(CONFIG_HL_SUPPORT) +/** + * @brief notify tx data SW that a peer-TID is ready to transmit to. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * If a peer-TID has tx paused, then the tx datapath will end up queuing + * any tx frames that arrive from the OS shim for that peer-TID. + * In a HL system, the host tx data SW itself will classify the tx frame, + * and determine that it needs to be queued rather than downloaded to the + * target for transmission. + * Once the peer-TID is ready to accept data, the host control SW will call + * this function to notify the host data SW that the queued frames can be + * enabled for transmission, or specifically to download the tx frames + * to the target to transmit. + * The TID parameter is an extended version of the QoS TID. Values 0-15 + * indicate a regular QoS TID, and the value 16 indicates either non-QoS + * data, multicast data, or broadcast data. + * + * @param data_peer - which peer is being unpaused + * @param tid - which TID within the peer is being unpaused, or -1 as a + * wildcard to unpause all TIDs within the peer + */ +void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid); + + +/** + * @brief Tell a paused peer to release a specified number of tx frames. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * Download up to a specified maximum number of tx frames from the tx + * queues of the specified TIDs within the specified paused peer, usually + * in response to a U-APSD trigger from the peer. + * It is up to the host data SW to determine how to choose frames from the + * tx queues of the specified TIDs. However, the host data SW does need to + * provide long-term fairness across the U-APSD enabled TIDs. + * The host data SW will notify the target data FW when it is done downloading + * the batch of U-APSD triggered tx frames, so the target data FW can + * differentiate between an in-progress download versus a case when there are + * fewer tx frames available than the specified limit. + * This function is relevant primarily to HL U-APSD, where the frames are + * held in the host. + * + * @param peer - which peer sent the U-APSD trigger + * @param tid_mask - bitmask of U-APSD enabled TIDs from whose tx queues + * tx frames can be released + * @param max_frms - limit on the number of tx frames to release from the + * specified TID's queues within the specified peer + */ +void ol_txrx_tx_release(ol_txrx_peer_handle peer, + u_int32_t tid_mask, + int max_frms); + +#else +static inline void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle data_peer, int tid) +{ +} + +static inline void +ol_txrx_tx_release(ol_txrx_peer_handle peer, + u_int32_t tid_mask, + int max_frms) +{ +} + +#endif /* CONFIG_HL_SUPPORT */ + +#ifdef QCA_SUPPORT_TX_THROTTLE +/** + * @brief Suspend all tx data per thermal event/timer for the + * specified physical device + * @details + * This function applies only to HL systerms, and it makes pause and + * unpause operations happen in pairs. + */ +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev); + + +/** + * @brief Resume all tx data per thermal event/timer for the + * specified physical device + * @details + * This function applies only to HL systerms, and it makes pause and + * unpause operations happen in pairs. + */ +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev); +#else + +static inline void +ol_txrx_throttle_pause(ol_txrx_pdev_handle data_pdev) +{ +} + +static inline void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle data_pdev) +{ +} +#endif + +/** + * @brief notify tx data SW that a peer's transmissions are suspended. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * The HL host tx data SW is doing tx classification and tx download + * scheduling, and therefore also needs to actively participate in tx + * flow control. Specifically, the HL tx data SW needs to check whether a + * given peer is available to transmit to, or is paused. + * This function is used to tell the HL tx data SW when a peer is paused, + * so the host tx data SW can hold the tx frames for that SW. + * + * @param data_peer - which peer is being paused + */ +static inline void ol_txrx_peer_pause(struct ol_txrx_peer_t *data_peer) +{ +} + +/** + * @brief Suspend all tx data for the specified physical device. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * In some systems it is necessary to be able to temporarily + * suspend all WLAN traffic, e.g. to allow another device such as bluetooth + * to temporarily have exclusive access to shared RF chain resources. + * This function suspends tx traffic within the specified physical device. + * + * @param data_pdev - the physical device being paused + */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason); +#else +static inline +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *data_pdev, uint32_t reason) +{ +} +#endif + +/** + * @brief Resume tx for the specified physical device. + * @details + * This function applies only to HL systems - in LL systems, tx flow control + * is handled entirely within the target FW. + * + * @param data_pdev - the physical device being unpaused + */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason); +#else +static inline +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ +} +#endif + +/** + * @brief Synchronize the data-path tx with a control-path target download + * @dtails + * @param data_pdev - the data-path physical device object + * @param sync_cnt - after the host data-path SW downloads this sync request + * to the target data-path FW, the target tx data-path will hold itself + * in suspension until it is given an out-of-band sync counter value that + * is equal to or greater than this counter value + */ +void ol_txrx_tx_sync(ol_txrx_pdev_handle data_pdev, uint8_t sync_cnt); + +/** + * @brief Store a delivery notification callback for specific data frames. + * @details + * Through a non-std tx function, the txrx SW can be given tx data frames + * that are specially marked to not be unmapped and freed by the tx SW + * when transmission completes. Rather, these specially-marked frames + * are provided to the callback registered with this function. + * + * @param soc - datapath soc handle + * @param vdev_id - id of which vdev the callback is being registered with + * (Currently the callback is stored in the pdev rather than the vdev.) + * @param callback - the function to call when tx frames marked as "no free" + * are done being transmitted + * @param ctxt - the context argument provided to the callback function + */ +void +ol_txrx_data_tx_cb_set(struct cdp_soc_t *soc, uint8_t vdev_id, + ol_txrx_data_tx_cb callback, void *ctxt); + +/** + * @brief Discard all tx frames that are pending in txrx. + * @details + * Mainly used in clean up path to make sure all pending tx packets + * held by txrx are returned back to OS shim immediately. + * + * @param pdev - the data physical device object + * @return - void + */ +void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev); + +void +ol_txrx_peer_keyinstalled_state_update(ol_txrx_peer_handle data_peer, + uint8_t val); + +#define ol_tx_addba_conf(data_peer, tid, status) /* no-op */ + +/** + * @brief Find a txrx peer handle from the peer's MAC address + * @details + * The control SW typically uses the txrx peer handle to refer to the peer. + * In unusual circumstances, if it is infeasible for the control SW maintain + * the txrx peer handle but it can maintain the peer's MAC address, + * this function allows the peer handled to be retrieved, based on the peer's + * MAC address. + * In cases where there are multiple peer objects with the same MAC address, + * it is undefined which such object is returned. + * This function does not increment the peer's reference count. Thus, it is + * only suitable for use as long as the control SW has assurance that it has + * not deleted the peer object, by calling ol_txrx_peer_detach. + * + * @param pdev - the data physical device object + * @param peer_mac_addr - MAC address of the peer in question + * @return handle to the txrx peer object + */ +ol_txrx_peer_handle +ol_txrx_peer_find_by_addr(ol_txrx_pdev_handle pdev, uint8_t *peer_mac_addr); + +struct ol_txrx_peer_stats_t { + struct { + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } frms; + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } bytes; + } tx; + struct { + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } frms; + struct { + uint32_t ucast; + uint32_t mcast; + uint32_t bcast; + } bytes; + } rx; +}; + +/** + * @brief Provide a snapshot of the txrx counters for the specified peer + * @details + * The txrx layer optionally maintains per-peer stats counters. + * This function provides the caller with a consistent snapshot of the + * txrx stats counters for the specified peer. + * + * @param pdev - the data physical device object + * @param peer - which peer's stats counters are requested + * @param stats - buffer for holding the stats counters snapshot + * @return success / failure status + */ +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +A_STATUS +ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev, + ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats); +#else +#define ol_txrx_peer_stats_copy(pdev, peer, stats) A_ERROR /* failure */ +#endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */ + + +#define OL_TXRX_RSSI_INVALID 0xffff +/** + * @brief Provide the current RSSI average from data frames sent by a peer. + * @details + * If a peer has sent data frames, the data SW will optionally keep + * a running average of the RSSI observed for those data frames. + * This function returns that time-average RSSI if is it available, + * or OL_TXRX_RSSI_INVALID if either RSSI tracking is disabled or if + * no data frame indications with valid RSSI meta-data have been received. + * The RSSI is in approximate dBm units, and is normalized with respect + * to a 20 MHz channel. For example, if a data frame is received on a + * 40 MHz channel, wherein both the primary 20 MHz channel and the + * secondary 20 MHz channel have an RSSI of -77 dBm, the reported RSSI + * will be -77 dBm, rather than the actual -74 dBm RSSI from the + * combination of the primary + extension 20 MHz channels. + * Alternatively, the RSSI may be evaluated only on the primary 20 MHz + * channel. + * + * @param peer - which peer's RSSI is desired + * @return RSSI evaluated from frames sent by the specified peer + */ +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer); +#else +#define ol_txrx_peer_rssi(peer) OL_TXRX_RSSI_INVALID +#endif /* QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * ol_txrx_bad_peer_txctl_set_setting() - Configure the bad peer tx + * limit setting. + * @soc_hdl: soc handle + * @pdev_id: datapath pdev identifier + * @enable: enable/disable setting + * @period: balance period in ms + * @txq_limit: balance txq limit + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_set_setting( + struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int enable, + int period, + int txq_limit); + +/** + * ol_txrx_bad_peer_txctl_update_threshold() - Configure the bad peer tx + * threshold limit + * @soc_hdl: soc handle + * @pdev_id: datapath pdev identifier + * @level: txctl level + * @tput_thresh throughput threshold + * @tx_limit: balance tx limit + * + * @param pdev - the physics device + */ +void +ol_txrx_bad_peer_txctl_update_threshold( + struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int level, + int tput_thresh, + int tx_limit); + +#else + +static inline void +ol_txrx_bad_peer_txctl_set_setting( + struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int enable, + int period, + int txq_limit) +{ +} + +static inline void +ol_txrx_bad_peer_txctl_update_threshold( + struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int level, + int tput_thresh, + int tx_limit) +{ +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + + +void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t **peer); + +void ol_tx_set_is_mgmt_over_wmi_enabled(uint8_t value); +uint8_t ol_tx_get_is_mgmt_over_wmi_enabled(void); + +#ifdef QCA_LL_TX_FLOW_CONTROL_RESIZE +void ol_tx_flow_pool_resize_handler(uint8_t flow_pool_id, + uint16_t flow_pool_size); +#else +static inline void ol_tx_flow_pool_resize_handler(uint8_t flow_pool_id, + uint16_t flow_pool_size) +{ +} +#endif + +/* TX FLOW Control related functions */ +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +#define TX_FLOW_MGMT_POOL_ID 0xEF + +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +#define TX_FLOW_MGMT_POOL_SIZE 32 +#else +#define TX_FLOW_MGMT_POOL_SIZE 0 +#endif + +void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev); +void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev); +void ol_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl); +void ol_tx_dump_flow_pool_info_compact(struct ol_txrx_pdev_t *pdev); +void ol_tx_clear_flow_pool_stats(void); +void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id, uint16_t flow_pool_size); +void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id); +struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id, + uint16_t flow_pool_size); + +/** + * ol_tx_inc_pool_ref() - increment pool ref count + * @pool: flow pool pointer + * + * Increments pool's ref count, used to make sure that no one is using + * pool when it is being deleted. + * As this function is taking pool->flow_pool_lock inside it, it should + * always be called outside this spinlock. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool); + +/** + * ol_tx_dec_pool_ref() - decrement pool ref count + * @pool: flow pool pointer + * @force: free pool forcefully + * + * Decrements pool's ref count and deletes the pool if ref count gets 0. + * As this function is taking pdev->tx_desc.flow_pool_list_lock and + * pool->flow_pool_lock inside it, it should always be called outside + * these two spinlocks. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force); + +#else + +static inline void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev) +{ +} +static inline void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev) +{ +} + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_HL_NETDEV_FLOW_CONTROL) +void ol_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl); +void ol_tx_dump_flow_pool_info_compact(struct ol_txrx_pdev_t *pdev); +#else +static inline void ol_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl) +{ +} + +static inline +void ol_tx_dump_flow_pool_info_compact(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +static inline void ol_tx_clear_flow_pool_stats(void) +{ +} +static inline void ol_tx_flow_pool_map_handler(uint8_t flow_id, + uint8_t flow_type, uint8_t flow_pool_id, uint16_t flow_pool_size) +{ +} +static inline void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, + uint8_t flow_type, uint8_t flow_pool_id) +{ +} +static inline struct ol_tx_flow_pool_t *ol_tx_create_flow_pool( + uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + return NULL; +} +static inline QDF_STATUS +ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool) +{ + return QDF_STATUS_SUCCESS; +} +static inline QDF_STATUS +ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#endif /* _OL_TXRX_CTRL_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h new file mode 100644 index 0000000000..438b406071 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_dbg.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2011, 2014-2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_dbg.h + * @brief Functions provided for visibility and debugging. + */ +#ifndef _OL_TXRX_DBG__H_ +#define _OL_TXRX_DBG__H_ + +#include /* A_STATUS, uint64_t */ +#include /* qdf_semaphore_t */ +#include /* htt_dbg_stats_type */ +#include /* ol_txrx_stats */ + +#ifndef TXRX_DEBUG_LEVEL +#define TXRX_DEBUG_LEVEL 0 /* no debug info */ +#endif + +enum { + TXRX_DBG_MASK_OBJS = 0x01, + TXRX_DBG_MASK_STATS = 0x02, + TXRX_DBG_MASK_PROT_ANALYZE = 0x04, + TXRX_DBG_MASK_RX_REORDER_TRACE = 0x08, + TXRX_DBG_MASK_RX_PN_TRACE = 0x10 +}; + +/*--- txrx printouts ---*/ + +/* + * Uncomment this to enable txrx printouts with dynamically adjustable + * verbosity. These printouts should not impact performance. + */ +#define TXRX_PRINT_ENABLE 1 +/* uncomment this for verbose txrx printouts (may impact performance) */ +/* #define TXRX_PRINT_VERBOSE_ENABLE 1 */ + +/*--- txrx object (pdev, vdev, peer) display debug functions ---*/ + +#if TXRX_DEBUG_LEVEL > 5 +void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent); +void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent); +void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent); +#else +#define ol_txrx_pdev_display(pdev, indent) +#define ol_txrx_vdev_display(vdev, indent) +#define ol_txrx_peer_display(peer, indent) +#endif + +/*--- txrx stats display debug functions ---*/ + +/** + * ol_txrx_stats_display() - display tx rx stats + * @pdev: pdev handle + * @level: verbosity level for logs + * + * Return: none + */ +void ol_txrx_stats_display(ol_txrx_pdev_handle pdev, + enum qdf_stats_verbosity_level level); + +void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev); + + +/*--- txrx protocol analyzer debug feature ---*/ + +/* uncomment this to enable the protocol analzyer feature */ +/* #define ENABLE_TXRX_PROT_ANALYZE 1 */ + +#if defined(ENABLE_TXRX_PROT_ANALYZE) + +void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev); + +#else + +#define ol_txrx_prot_ans_display(pdev) + +#endif /* ENABLE_TXRX_PROT_ANALYZE */ + +/*--- txrx sequence number trace debug feature ---*/ + +/* uncomment this to enable the rx reorder trace feature */ +/* #define ENABLE_RX_REORDER_TRACE 1 */ + +#define ol_txrx_seq_num_trace_display(pdev) \ + ol_rx_reorder_trace_display(pdev, 0, 0) + +#if defined(ENABLE_RX_REORDER_TRACE) + +void +ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit); + +#else + +#define ol_rx_reorder_trace_display(pdev, just_once, limit) + +#endif /* ENABLE_RX_REORDER_TRACE */ + +/*--- txrx packet number trace debug feature ---*/ + +/* uncomment this to enable the rx PN trace feature */ +/* #define ENABLE_RX_PN_TRACE 1 */ + +#define ol_txrx_pn_trace_display(pdev) ol_rx_pn_trace_display(pdev, 0) + +#if defined(ENABLE_RX_PN_TRACE) + +void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once); + +#else + +#define ol_rx_pn_trace_display(pdev, just_once) + +#endif /* ENABLE_RX_PN_TRACE */ + +/*--- tx queue log debug feature ---*/ +/* uncomment this to enable the tx queue log feature */ +/* #define ENABLE_TX_QUEUE_LOG 1 */ + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) + +void +ol_tx_queue_log_display(ol_txrx_pdev_handle pdev); +void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev); +#else + +static inline +void ol_tx_queue_log_display(ol_txrx_pdev_handle pdev) +{ +} + +static inline +void ol_tx_queue_log_clear(ol_txrx_pdev_handle pdev) +{ +} +#endif /* defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) */ + + +/*----------------------------------------*/ + +#endif /* _OL_TXRX_DBG__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h new file mode 100644 index 0000000000..f17e562561 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_htt_api.h @@ -0,0 +1,804 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_htt_api.h + * @brief Define the host data API functions called by the host HTT SW. + */ +#ifndef _OL_TXRX_HTT_API__H_ +#define _OL_TXRX_HTT_API__H_ + +#include /* HTT_TX_COMPL_IND_STAT */ +#include /* A_STATUS */ +#include /* qdf_nbuf_t */ + +#include /* ol_txrx_pdev_handle */ +#include + +#ifdef CONFIG_HL_SUPPORT +static inline uint16_t *ol_tx_msdu_id_storage(qdf_nbuf_t msdu) +{ + return (uint16_t *) (&QDF_NBUF_CB_TX_DESC_ID(msdu)); + +} + +/** + * @brief Deduct one credit from target_tx and one from any of the groups + * @details + * Deduct one credit from target_tx credit and one credit from any of the + * groups, whichever has more number of credits. + * + * @param pdev - the data physical device + */ +int ol_tx_deduct_one_credit(struct ol_txrx_pdev_t *pdev); +#else +static inline uint16_t *ol_tx_msdu_id_storage(qdf_nbuf_t msdu) +{ + qdf_assert(qdf_nbuf_headroom(msdu) >= (sizeof(uint16_t) * 2 - 1)); + return (uint16_t *) (((qdf_size_t) (qdf_nbuf_head(msdu) + 1)) & ~0x1); +} + +static inline int ol_tx_deduct_one_credit(struct ol_txrx_pdev_t *pdev) +{ + return 0; +} +#endif +/** + * @brief Tx MSDU download completion for a LL system + * @details + * Release the reference to the downloaded tx descriptor. + * In the unlikely event that the reference count is zero, free + * the tx descriptor and tx frame. + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_ll(void *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Tx MSDU download completion for HL system without tx completion msgs + * @details + * Free the tx descriptor and tx frame. + * Invoke the HL tx download scheduler. + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_hl_free(void *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id); + +/** + * @brief Tx MSDU download completion for HL system with tx completion msgs + * @details + * Release the reference to the downloaded tx descriptor. + * In the unlikely event that the reference count is zero, free + * the tx descriptor and tx frame. + * Optionally, invoke the HL tx download scheduler. (It is probable that + * the HL tx download scheduler would operate in response to tx completion + * messages rather than download completion events.) + * + * @param pdev - (abstract) pointer to the txrx physical device + * @param status - indication of whether the download succeeded + * @param msdu - the downloaded tx frame + * @param msdu_id - the txrx ID of the tx frame - this is used for + * locating the frame's tx descriptor + */ +void +ol_tx_download_done_hl_retain(void *pdev, + A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id); + +/* + * For now, make the host HTT -> host txrx tx completion status + * match the target HTT -> host HTT tx completion status, so no + * translation is needed. + */ +/* + * host-only statuses use a different part of the number space + * than host-target statuses + */ +#define HTT_HOST_ONLY_STATUS_CODE_START 128 +enum htt_tx_status { + /* ok - successfully sent + acked */ + htt_tx_status_ok = HTT_TX_COMPL_IND_STAT_OK, + + /* discard - not sent (congestion control) */ + htt_tx_status_discard = HTT_TX_COMPL_IND_STAT_DISCARD, + + /* no_ack - sent, but no ack */ + htt_tx_status_no_ack = HTT_TX_COMPL_IND_STAT_NO_ACK, + + /* drop may due to tx descriptor not enough*/ + htt_tx_status_drop = HTT_TX_COMPL_IND_STAT_DROP, + + /* download_fail - host could not deliver the tx frame to target */ + htt_tx_status_download_fail = HTT_HOST_ONLY_STATUS_CODE_START, +}; + +/** + * @brief Process a tx completion message sent by the target. + * @details + * When the target is done transmitting a tx frame (either because + * the frame was sent + acknowledged, or because the target gave up) + * it sends a tx completion message to the host. + * This notification function is used regardless of whether the + * transmission succeeded or not; the status argument indicates whether + * the transmission succeeded. + * This tx completion message indicates via the descriptor ID which + * tx frames were completed, and indicates via the status whether the + * frames were transmitted successfully. + * The host frees the completed descriptors / frames (updating stats + * in the process). + * + * @param pdev - the data physical device that sent the tx frames + * (registered with HTT as a context pointer during attach time) + * @param num_msdus - how many MSDUs are referenced by the tx completion + * message + * @param status - whether transmission was successful + * @param msg_word - the tx completion message + */ +void +ol_tx_completion_handler(ol_txrx_pdev_handle pdev, + int num_msdus, + enum htt_tx_status status, void *msg_word); + +void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits); + +struct rate_report_t { + u_int16_t id; + u_int16_t phy:4; + u_int32_t rate; +}; + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * @brief Process a link status report for all peers. + * @details + * The ol_txrx_peer_link_status_handler function performs basic peer link + * status analysis + * + * According to the design, there are 3 kinds of peers which will be + * treated differently: + * 1) normal: not do any flow control for the peer + * 2) limited: will apply flow control for the peer, but frames are allowed + * to send + * 3) paused: will apply flow control for the peer, no frame is allowed + * to send + * + * @param pdev - the data physical device that sent the tx frames + * @param status - the number of peers need to be handled + * @param peer_link_report - the link status dedail message + */ +void +ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status); + + +#else +static inline void ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status) +{ +} +#endif + + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if + * vdev id mask and ac mask is not matching + * @pdev: the data physical device + * @group_id: TXQ group id + * @credit: TXQ group credit count + * @absolute: TXQ group absolute + * @vdev_id_mask: TXQ vdev group id mask + * @ac_mask: TQX access category mask + * + * Return: None + */ +void +ol_txrx_update_tx_queue_groups( + ol_txrx_pdev_handle pdev, + u_int8_t group_id, + int32_t credit, + u_int8_t absolute, + u_int32_t vdev_id_mask, + u_int32_t ac_mask +); + +/** + * ol_tx_desc_update_group_credit() - update group credits for txq group + * @pdev: the data physical device + * @tx_desc_id: desc id of tx completion message + * @credit: number of credits to update + * @absolute: absolute value + * @status: tx completion message status + * + * Return: None + */ +void +ol_tx_desc_update_group_credit( + ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, + int credit, u_int8_t absolute, enum htt_tx_status status); + +void ol_tx_deduct_one_any_group_credit(ol_txrx_pdev_handle pdev); + +#ifdef DEBUG_HL_LOGGING + +/** + * ol_tx_update_group_credit_stats() - update group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev); + +/** + * ol_tx_dump_group_credit_stats() - dump group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev); + +/** + * ol_tx_clear_group_credit_stats() - clear group credits stats for txq groups + * @pdev: the data physical device + * + * Return: None + */ +void +ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev); +#else + +static inline void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev) +{ +} + +static inline void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev) +{ +} + +static inline void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev) +{ +} +#endif + +#else +static inline void +ol_tx_desc_update_group_credit( + ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, + int credit, u_int8_t absolute, enum htt_tx_status status) +{ +} + +static inline void ol_tx_deduct_one_any_group_credit(ol_txrx_pdev_handle pdev) +{} +#endif + +/** + * @brief Init the total amount of target credit. + * @details + * + * @param pdev - the data physical device that sent the tx frames + * @param credit_delta - how much to increment the target's tx credit by + */ +void ol_tx_target_credit_init(struct ol_txrx_pdev_t *pdev, int credit_delta); + +/** + * @brief Process a tx completion message for a single MSDU. + * @details + * The ol_tx_single_completion_handler function performs the same tx + * completion processing as the ol_tx_completion_handler, but for a + * single frame. + * ol_tx_completion_handler is optimized to handle batch completions + * as efficiently as possible; in contrast ol_tx_single_completion_handler + * handles single frames as simply and generally as possible. + * Thus, this ol_tx_single_completion_handler function is suitable for + * intermittent usage, such as for tx mgmt frames. + * + * @param pdev - the data physical device that sent the tx frames + * @param status - whether transmission was successful + * @param tx_msdu_id - ID of the frame which completed transmission + */ +void +ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, uint16_t tx_desc_id); + +/** + * @brief Update the amount of target credit. + * @details + * When the target finishes with an old transmit frame, it can use the + * space that was occupied by the old tx frame to store a new tx frame. + * This function is used to inform the txrx layer, where the HL tx download + * scheduler resides, about such updates to the target's tx credit. + * This credit update is done explicitly, rather than having the txrx layer + * update the credit count itself inside the ol_tx_completion handler + * function. This provides HTT with the flexibility to limit the rate of + * downloads from the TXRX layer's download scheduler, by controlling how + * much credit the download scheduler gets, and also provides the flexibility + * to account for a change in the tx memory pool size within the target. + * This function is only used for HL systems; in LL systems, each tx frame + * is assumed to use exactly one credit (for its target-side tx descriptor), + * and any rate limiting is managed within the target. + * + * @param pdev - the data physical device that sent the tx frames + * @param credit_delta - how much to increment the target's tx credit by + */ +void ol_tx_target_credit_update(struct ol_txrx_pdev_t *pdev, int credit_delta); + +/** + * @brief Process an rx indication message sent by the target. + * @details + * The target sends a rx indication message to the host as a + * notification that there are new rx frames available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx frames + * associated with the indication, and calls this function to + * invoke the rx data processing on the new frames. + * (For LL, the rx descriptors and frames are delivered directly + * to the host via MAC DMA, while for HL the rx descriptor and + * frame for individual frames are combined with the rx indication + * message.) + * All MPDUs referenced by a rx indication message belong to the + * same peer-TID. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_ind_msg - the network buffer holding the rx indication message + * (For HL, this netbuf also holds the rx desc and rx payload, but + * the data SW is agnostic to whether the desc and payload are + * piggybacked with the rx indication message.) + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + * @param num_mpdu_ranges - how many ranges of MPDUs does the message describe. + * Each MPDU within the range has the same rx status. + */ +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD +void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges); +#else +static inline void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges) +{ +} +#endif + +/** + * @brief Process an rx fragment indication message sent by the target. + * @details + * The target sends a rx fragment indication message to the host as a + * notification that there are new rx fragment available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx fragment + * associated with the indication, and calls this function to + * invoke the rx fragment data processing on the new fragment. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_frag_ind_msg - the network buffer holding the rx fragment + * indication message + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + */ +void ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + uint16_t peer_id, uint8_t tid); + +/** + * @brief Process rx offload deliver indication message sent by the target. + * @details + * When the target exits offload mode, target delivers packets that it has + * held in its memory to the host using this message. + * Low latency case: + * The message contains the number of MSDUs that are being delivered by the + * target to the host. The packet itself resides in host ring along with some + * metadata describing the peer id, vdev id, tid, FW desc and length of + * the packet being delivered. + * High latency case: + * The message itself contains the payload of the MSDU being delivered by + * the target to the host. The message also contains meta data describing + * the packet such as peer id, vdev id, tid, FW desc and length of the packet + * being delivered. Refer to htt.h for the exact structure of the message. + * @param pdev - the data physical device that received the frame. + * @param msg - offload deliver indication message + * @param msdu_cnt - number of MSDUs being delivred. + */ +void +ol_rx_offload_deliver_ind_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msg, uint16_t msdu_cnt); + +/** + * @brief Process a peer map message sent by the target. + * @details + * Each time the target allocates a new peer ID, it will inform the + * host via the "peer map" message. This function processes that + * message. The host data SW looks for a peer object whose MAC address + * matches the MAC address specified in the peer map message, and then + * sets up a mapping between the peer ID specified in the message and + * the peer object that was found. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID generated by the target to refer to the peer in question + * The target may create multiple IDs for a single peer. + * @param vdev_id - Reference to the virtual device the peer is associated with + * @param peer_mac_addr - MAC address of the peer in question + * @param tx_ready - whether transmits to this peer can be done already, or + * need to wait for a call to peer_tx_ready (only applies to HL systems) + */ +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready); + +/** + * @brief notify the host that the target is ready to transmit to a new peer. + * @details + * Some targets can immediately accept tx frames for a new peer, as soon as + * the peer's association completes. Other target need a short setup time + * before they are ready to accept tx frames for the new peer. + * If the target needs time for setup, it will provide a peer_tx_ready + * message when it is done with the setup. This function forwards this + * notification from the target to the host's tx queue manager. + * This function only applies for HL systems, in which the host determines + * which peer a given tx frame is for, and stores the tx frames in queues. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID for the new peer which can now accept tx frames + */ +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id); + +/** + * @brief Process a peer unmap message sent by the target. + * @details + * Each time the target frees a peer ID, it will inform the host via the + * "peer unmap" message. This function processes that message. + * The host data SW uses the peer ID from the message to find the peer + * object from peer_map[peer_id], then invalidates peer_map[peer_id] + * (by setting it to NULL), and checks whether there are any remaining + * references to the peer object. If not, the function deletes the + * peer object. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - ID that is being freed. + * The target may create multiple IDs for a single peer. + */ +void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id); + +/** + * @brief Process a security indication message sent by the target. + * @details + * When a key is assigned to a peer, the target will inform the host + * with a security indication message. + * The host remembers the security type, and infers whether a rx PN + * check is needed. + * + * @param pdev - data physical device handle + * @param peer_id - which peer the security info is for + * @param sec_type - which type of security / key the peer is using + * @param is_unicast - whether security spec is for a unicast or multicast key + * @param michael_key - key used for TKIP MIC (if sec_type == TKIP) + * @param rx_pn - RSC used for WAPI PN replay check (if sec_type == WAPI) + */ +void +ol_rx_sec_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + enum htt_sec_type sec_type, + int is_unicast, uint32_t *michael_key, uint32_t *rx_pn); + +/** + * @brief Process an ADDBA message sent by the target. + * @details + * When the target notifies the host of an ADDBA event for a specified + * peer-TID, the host will set up the rx reordering state for the peer-TID. + * Specifically, the host will create a rx reordering array whose length + * is based on the window size specified in the ADDBA. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer the ADDBA event is for + * @param tid - which traffic ID within the peer the ADDBA event is for + * @param win_sz - how many sequence numbers are in the ARQ block ack window + * set up by the ADDBA event + * @param start_seq_num - the initial value of the sequence number during the + * block ack agreement, as specified by the ADDBA request. + * @param failed - indicate whether the target's ADDBA setup succeeded: + * 0 -> success, 1 -> fail + */ +void +ol_rx_addba_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint8_t win_sz, uint16_t start_seq_num, uint8_t failed); + +/** + * @brief Process a DELBA message sent by the target. + * @details + * When the target notifies the host of a DELBA event for a specified + * peer-TID, the host will clean up the rx reordering state for the peer-TID. + * Specifically, the host will remove the rx reordering array, and will + * set the reorder window size to be 1 (stop and go ARQ). + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer the ADDBA event is for + * @param tid - which traffic ID within the peer the ADDBA event is for + */ +void +ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid); + +enum htt_rx_flush_action { + htt_rx_flush_release, + htt_rx_flush_discard, +}; + +/** + * @brief Process a rx reorder flush message sent by the target. + * @details + * The target's rx reorder logic can send a flush indication to the + * host's rx reorder buffering either as a flush IE within a rx + * indication message, or as a standalone rx reorder flush message. + * This ol_rx_flush_handler function processes the standalone rx + * reorder flush message from the target. + * The flush message specifies a range of sequence numbers whose + * rx frames are flushed. + * Some sequence numbers within the specified range may not have + * rx frames; the host needs to check for each sequence number in + * the specified range whether there are rx frames held for that + * sequence number. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer's rx data is being flushed + * @param tid - which traffic ID within the peer has the rx data being flushed + * @param seq_num_start - Which sequence number within the rx reordering + * buffer the flushing should start with. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The flush includes this initial sequence number. + * @param seq_num_end - Which sequence number within the rx reordering + * buffer the flushing should stop at. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The flush excludes this final sequence number. + * @param action - whether to release or discard the rx frames + */ +void +ol_rx_flush_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t seq_num_start, + uint16_t seq_num_end, enum htt_rx_flush_action action); + +/** + * @brief Process a rx pn indication message + * @details + * When the peer is configured to get PN checking done in target, + * the target instead of sending reorder flush/release messages + * sends PN indication messages which contain the start and end + * sequence numbers to be flushed/released along with the sequence + * numbers of MPDUs that failed the PN check in target. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param peer_id - which peer's rx data is being flushed + * @param tid - which traffic ID within the peer + * @param seq_num_start - Which sequence number within the rx reordering + * buffer to start with. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * This is the initial sequence number. + * @param seq_num_end - Which sequence number within the rx reordering + * buffer to stop at. + * This is the LSBs of the 802.11 sequence number. + * This sequence number is masked with the rounded-to-power-of-two + * window size to generate a reorder buffer index. + * The processing stops right before this sequence number + * @param pn_ie_cnt - Indicates the number of PN information elements. + * @param pn_ie - Pointer to the array of PN information elements. Each + * PN information element contains the LSBs of the 802.11 sequence number + * of the MPDU that failed the PN checking in target. + */ +void +ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t seq_num_start, + uint16_t seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie); + +/** + * @brief Process a stats message sent by the target. + * @details + * The host can request target for stats. + * The target sends the stats to the host via a confirmation message. + * This ol_txrx_fw_stats_handler function processes the confirmation message. + * Currently, this processing consists of copying the stats from the message + * buffer into the txrx pdev object, and waking the sleeping host context + * that requested the stats. + * + * @param pdev - data physical device handle + * (registered with HTT as a context pointer during attach time) + * @param cookie - Value echoed from the cookie in the stats request + * message. This allows the host SW to find the stats request object. + * (Currently, this cookie is unused.) + * @param stats_info_list - stats confirmation message contents, containing + * a list of the stats requested from the target + */ +void +ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, + uint8_t cookie, uint8_t *stats_info_list); + +/** + * @brief Process a tx inspect message sent by the target. + * @details: + * TODO: update + * This tx inspect message indicates via the descriptor ID + * which tx frames are to be inspected by host. The host + * re-injects the packet back to the host for a number of + * cases. + * + * @param pdev - the data physical device that sent the tx frames + * (registered with HTT as a context pointer during attach time) + * @param num_msdus - how many MSDUs are referenced by the tx completion + * message + * @param tx_msdu_id_iterator - abstract method of finding the IDs for the + * individual MSDUs referenced by the tx completion message, via the + * htt_tx_compl_desc_id API function + */ +void +ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, + int num_msdus, void *tx_desc_id_iterator); + +/** + * @brief Get the UAPSD mask. + * @details + * This function will return the UAPSD TID mask. + * + * @param txrx_pdev - pointer to the txrx pdev object + * @param peer_id - PeerID. + * @return uapsd mask value + */ +uint8_t +ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id); + +/** + * @brief Get the Qos Capable. + * @details + * This function will return the txrx_peer qos_capable. + * + * @param txrx_pdev - pointer to the txrx pdev object + * @param peer_id - PeerID. + * @return qos_capable value + */ +uint8_t +ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id); + +/** + * @brief Process an rx indication message sent by the target. + * @details + * The target sends a rx indication message to the host as a + * notification that there are new rx frames available for the + * host to process. + * The HTT host layer locates the rx descriptors and rx frames + * associated with the indication, and calls this function to + * invoke the rx data processing on the new frames. + * All MPDUs referenced by a rx indication message belong to the + * same peer-TID. The frames indicated have been re-ordered by + * the target. + * + * @param pdev - the data physical device that received the frames + * (registered with HTT as a context pointer during attach time) + * @param rx_ind_msg - the network buffer holding the rx indication message + * @param peer_id - which peer sent this rx data + * @param tid - what (extended) traffic type the rx data is + * @param is_offload - is this an offload indication? + */ +#ifdef WLAN_FULL_REORDER_OFFLOAD +void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload); +#else +static inline void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload) +{ +} +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_tx_get_max_tx_groups_supported() - get max TCQ groups supported + * @pdev: the data physical device that received the frames + * + * Return: number of max groups supported + */ +u_int32_t ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev); +#else + +static inline u_int32_t +ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev) +{ + return 0; +} +#endif + +#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \ + defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING) +int ol_txrx_distribute_group_credits(struct ol_txrx_pdev_t *pdev, u8 group_id, + u32 membership_new); +#else +static inline int ol_txrx_distribute_group_credits(struct ol_txrx_pdev_t *pdev, + u8 group_id, + u32 membership_new) +{ + return 0; +} +#endif /* + * FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL && + * FEATURE_HL_DBS_GROUP_CREDIT_SHARING + */ + +#ifdef WLAN_CFR_ENABLE +/** + * ol_rx_cfr_capture_msg_handler() - handler for HTT_PEER_CFR_CAPTURE_MSG_TYPE_1 + * @htt_t2h_msg: htt msg data + * + * Return: None + */ +void ol_rx_cfr_capture_msg_handler(qdf_nbuf_t htt_t2h_msg); +#else +static inline void ol_rx_cfr_capture_msg_handler(qdf_nbuf_t htt_t2h_msg) +{ +} +#endif + +#endif /* _OL_TXRX_HTT_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h new file mode 100644 index 0000000000..a880d46a29 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_osif_api.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2012, 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_osif_api.h + * @brief Define the host data API functions called by the host OS shim SW. + */ +#ifndef _OL_TXRX_OSIF_API__H_ +#define _OL_TXRX_OSIF_API__H_ + +#include /* qdf_nbuf_t */ +#include "cds_sched.h" +#include "ol_txrx_ctrl_api.h" +#include + +/** + * struct ol_rx_cached_buf - rx cached buffer + * @list: linked list + * @buf: skb buffer + */ +struct ol_rx_cached_buf { + struct list_head list; + qdf_nbuf_t buf; +}; + +struct txrx_rx_metainfo; + +/** + * @brief Divide a jumbo TCP frame into smaller segments. + * @details + * For efficiency, the protocol stack above the WLAN driver may operate + * on jumbo tx frames, which are larger than the 802.11 MTU. + * The OSIF SW uses this txrx API function to divide the jumbo tx TCP frame + * into a series of segment frames. + * The segments are created as clones of the input jumbo frame. + * The txrx SW generates a new encapsulation header (ethernet + IP + TCP) + * for each of the output segment frames. The exact format of this header, + * e.g. 802.3 vs. Ethernet II, and IPv4 vs. IPv6, is chosen to match the + * header format of the input jumbo frame. + * The input jumbo frame is not modified. + * After the ol_txrx_osif_tso_segment returns, the OSIF SW needs to perform + * DMA mapping on each of the segment network buffers, and also needs to + * + * @param txrx_vdev - which virtual device will transmit the TSO segments + * @param max_seg_payload_bytes - the maximum size for the TCP payload of + * each segment frame. + * This does not include the ethernet + IP + TCP header sizes. + * @param jumbo_tcp_frame - jumbo frame which needs to be cloned+segmented + * @return + * NULL if the segmentation fails, - OR - + * a NULL-terminated list of segment network buffers + */ +qdf_nbuf_t ol_txrx_osif_tso_segment(ol_txrx_vdev_handle txrx_vdev, + int max_seg_payload_bytes, + qdf_nbuf_t jumbo_tcp_frame); + +qdf_nbuf_t ol_tx_data(struct cdp_soc_t *soc, uint8_t vdev_id, qdf_nbuf_t skb); + +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + qdf_nbuf_t rx_buf_list); + +void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, + bool drop); +#endif /* _OL_TXRX_OSIF_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h new file mode 100644 index 0000000000..4a49d3dcd5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_txrx_stats.h @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2012, 2014-2017, 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_status.h + * @brief Functions provided for visibility and debugging. + * NOTE: This file is used by both kernel driver SW and userspace SW. + * Thus, do not reference use any kernel header files or defs in this file! + */ +#ifndef _OL_TXRX_STATS__H_ +#define _OL_TXRX_STATS__H_ + +#include /* uint64_t */ + + + +struct ol_txrx_stats_elem { + uint64_t pkts; + uint64_t bytes; +}; + +#define NUM_MAX_TSO_SEGS 4 +#define NUM_MAX_TSO_SEGS_MASK (NUM_MAX_TSO_SEGS - 1) + +#define NUM_MAX_TSO_MSDUS 32 +#define NUM_MAX_TSO_MSDUS_MASK (NUM_MAX_TSO_MSDUS - 1) + +struct ol_txrx_stats_tso_msdu { + struct qdf_tso_seg_t tso_segs[NUM_MAX_TSO_SEGS]; + uint8_t num_seg; + uint8_t tso_seg_idx; + uint32_t total_len; + uint32_t gso_size; + uint8_t nr_frags; +}; + +struct ol_txrx_stats_tso_info { + struct ol_txrx_stats_tso_msdu tso_msdu_info[NUM_MAX_TSO_MSDUS]; + uint32_t tso_msdu_idx; +}; + +/** + * @brief data stats published by the host txrx layer + * + * ------------------------- + * + * TX + * + */ +struct ol_txrx_stats_tx_dropped { + /* MSDUs that the host did not accept */ + struct ol_txrx_stats_elem host_reject; + /* MSDUs which could not be downloaded to the target */ + struct ol_txrx_stats_elem download_fail; + /* + * MSDUs which the target discarded + * (lack of memory or old age) + */ + struct ol_txrx_stats_elem target_discard; + /* + * MSDUs which the target sent but + * couldn't get an ack for + */ + struct ol_txrx_stats_elem no_ack; + + /* + * MSDUs which the target drop + * (lack of tx descriptor) + */ + struct ol_txrx_stats_elem target_drop; + + /* MSDU which were dropped for other reasons */ + struct ol_txrx_stats_elem others; +}; + +struct ol_txrx_tso_histogram { + uint32_t pkts_1; + uint32_t pkts_2_5; + uint32_t pkts_6_10; + uint32_t pkts_11_15; + uint32_t pkts_16_20; + uint32_t pkts_20_plus; +}; + +struct ol_txrx_stats_tx_histogram { + uint32_t pkts_1; + uint32_t pkts_2_10; + uint32_t pkts_11_20; + uint32_t pkts_21_30; + uint32_t pkts_31_40; + uint32_t pkts_41_50; + uint32_t pkts_51_60; + uint32_t pkts_61_plus; +}; +struct ol_txrx_stats_tx_tso { + struct ol_txrx_stats_elem tso_pkts; +#if defined(FEATURE_TSO) + struct ol_txrx_stats_tso_info tso_info; + struct ol_txrx_tso_histogram tso_hist; + qdf_spinlock_t tso_stats_lock; +#endif +}; + +struct ol_txrx_stats_tx { + /* MSDUs given to the txrx layer by the management stack */ + struct ol_txrx_stats_elem mgmt; + /* MSDUs received from the stack */ + struct ol_txrx_stats_elem from_stack; + /* MSDUs successfully sent across the WLAN */ + struct ol_txrx_stats_elem delivered; + struct ol_txrx_stats_tx_dropped dropped; + /* contains information of packets received per tx completion*/ + struct ol_txrx_stats_tx_histogram comp_histogram; + /* TSO (TCP segmentation offload) information */ + struct ol_txrx_stats_tx_tso tso; +}; + +/* + * RX + */ +struct ol_txrx_stats_rx_histogram { + uint32_t pkts_1; + uint32_t pkts_2_10; + uint32_t pkts_11_20; + uint32_t pkts_21_30; + uint32_t pkts_31_40; + uint32_t pkts_41_50; + uint32_t pkts_51_60; + uint32_t pkts_61_plus; +}; +struct ol_txrx_stats_rx_ibss_fwd { + /* MSDUs forwarded to network stack */ + u_int32_t packets_stack; + /* MSDUs forwarded from the rx path to the tx path */ + u_int32_t packets_fwd; + /* MSDUs forwarded to stack and tx path */ + u_int32_t packets_stack_n_fwd; +}; +struct ol_txrx_stats_rx { + /* MSDUs given to the OS shim */ + struct ol_txrx_stats_elem delivered; + struct ol_txrx_stats_elem dropped_err; + struct ol_txrx_stats_elem dropped_mic_err; + struct ol_txrx_stats_elem dropped_peer_invalid; + struct ol_txrx_stats_rx_ibss_fwd intra_bss_fwd; + struct ol_txrx_stats_rx_histogram rx_ind_histogram; + uint32_t msdus_with_frag_ind; + uint32_t msdus_with_offload_ind; +}; +struct ol_txrx_stats { + struct ol_txrx_stats_tx tx; + struct ol_txrx_stats_rx rx; +}; + +/* + * Structure to consolidate host stats + */ +struct ieee80211req_ol_ath_host_stats { + struct ol_txrx_stats txrx_stats; + struct { + int pkt_q_fail_count; + int pkt_q_empty_count; + int send_q_empty_count; + } htc; + struct { + int pipe_no_resrc_count; + int ce_ring_delta_fail_count; + } hif; +}; + +#endif /* _OL_TXRX_STATS__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h new file mode 100644 index 0000000000..ab82d5e00d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/ol/inc/ol_vowext_dbg_defs.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 2014-2016, 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _VOW_DEFINES__H_ +#define _VOW_DEFINES__H_ + +#define UDP_CKSUM_OFFSET 40 /* UDP check sum offset in network buffer */ +#define RTP_HDR_OFFSET 42 /* RTP header offset in network buffer */ +#define EXT_HDR_OFFSET 54 /* Extension header offset in network buffer */ +#define UDP_PDU_RTP_EXT 0x90 /* ((2 << 6) | (1 << 4)) RTP V2 + X bit */ +#define IP_VER4_N_NO_EXTRA_HEADERS 0x45 +#define IPERF3_DATA_OFFSET 12 /* iperf3 data offset from EXT_HDR_OFFSET */ +#define HAL_RX_40 0x08 /* 40 Mhz */ +#define HAL_RX_GI 0x04 /* full gi */ + +struct vow_extstats { + uint8_t rx_rssi_ctl0; /* control channel chain0 rssi */ + uint8_t rx_rssi_ctl1; /* control channel chain1 rssi */ + uint8_t rx_rssi_ctl2; /* control channel chain2 rssi */ + uint8_t rx_rssi_ext0; /* extension channel chain0 rssi */ + uint8_t rx_rssi_ext1; /* extension channel chain1 rssi */ + uint8_t rx_rssi_ext2; /* extension channel chain2 rssi */ + uint8_t rx_rssi_comb; /* combined RSSI value */ + uint8_t rx_bw; /* Band width 0-20, 1-40, 2-80 */ + uint8_t rx_sgi; /* Guard interval, 0-Long GI, 1-Short GI */ + uint8_t rx_nss; /* Number of spatial streams */ + uint8_t rx_mcs; /* Rate MCS value */ + uint8_t rx_ratecode; /* Hardware rate code */ + uint8_t rx_rs_flags; /* Receive misc flags */ + uint8_t rx_moreaggr; /* 0 - non aggr frame */ + uint32_t rx_macTs; /* Time stamp */ + uint16_t rx_seqno; /* rx sequence number */ +}; + +/** + * @brief populates vow ext stats in given network buffer. + * @param msdu - network buffer handle + * @param pdev - handle to htt dev. + */ +void ol_ath_add_vow_extstats(htt_pdev_handle pdev, qdf_nbuf_t msdu); + +#endif /* _VOW_DEFINES__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ipv6_defs.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ipv6_defs.h new file mode 100644 index 0000000000..ffdd6568af --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ipv6_defs.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012-2014, 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _IPV6__H_ +#define _IPV6__H_ + +#if defined(ATH_TARGET) +#include /* A_UINT8 */ +#else +#include /* A_UINT8 */ +#endif + +/* utilities for converting between network byte order and native endianness */ +#ifndef BYTESWAP32 +#define BYTESWAP32(x) \ + ((((x) & 0x000000ff) << 24) /* byte 0 -> byte 3 */ | \ + (((x) & 0x0000ff00) << 8) /* byte 1 -> byte 2 */ | \ + (((x) & 0x00ff0000) >> 8) /* byte 2 -> byte 1 */ | \ + (((x) & 0xff000000) >> 24) /* byte 3 -> byte 0 */) +#endif /* BYTESWAP32 */ + +#ifndef BE_TO_CPU32 +#if defined(ATH_TARGET) +/* assume target is little-endian */ +#define BE_TO_CPU32(x) BYTESWAP32(x) +#else +#ifdef BIG_ENDIAN_HOST +#define BE_TO_CPU32(x) (x) +#else +#define BE_TO_CPU32(x) BYTESWAP32(x) +#endif +#endif +#endif /* BE_TO_CPU32 */ + +/* IPv6 header definition */ + +#define IPV6_ADDR_LEN 4 /* bytes */ +struct ipv6_hdr_t { + /* version, traffic class, and flow label */ + A_UINT32 ver_tclass_flowlabel; + A_UINT8 pyld_len[2]; /* payload length */ + A_UINT8 next_hdr; + A_UINT8 hop_limit; + A_UINT8 src_addr[IPV6_ADDR_LEN]; + A_UINT8 dst_addr[IPV6_ADDR_LEN]; +}; + +#define IPV6_HDR_LEN (sizeof(struct ipv6_hdr_t)) +#define IPV6_HDR_OFFSET_NEXT_HDR (offsetof(struct ipv6_hdr_t, next_hdr)) +#define IPV6_HDR_OFFSET_DST_ADDR (offsetof(struct ipv6_hdr_t, dst_addr[0])) + +/* IPv6 header field access macros */ + +#define IPV6_HDR_VERSION_M 0xF0000000 +#define IPV6_HDR_VERSION_S 28 + +#define IPV6_HDR_TRAFFIC_CLASS_M 0x0FF00000 +#define IPV6_HDR_TRAFFIC_CLASS_S 20 + +#define IPV6_HDR_FLOW_LABEL_M 0x000FFFFF +#define IPV6_HDR_FLOW_LABEL_S 0 + +static inline A_UINT8 ipv6_version(struct ipv6_hdr_t *ipv6_hdr) +{ + return (BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_VERSION_M) >> IPV6_HDR_VERSION_S; +} + +static inline A_UINT8 ipv6_traffic_class(struct ipv6_hdr_t *ipv6_hdr) +{ + return (A_UINT8)((BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_TRAFFIC_CLASS_M) >> IPV6_HDR_TRAFFIC_CLASS_S); +} + +static inline A_UINT32 ipv6_flow_label(struct ipv6_hdr_t *ipv6_hdr) +{ + return (BE_TO_CPU32(ipv6_hdr->ver_tclass_flowlabel) & + IPV6_HDR_FLOW_LABEL_M) >> IPV6_HDR_FLOW_LABEL_S; +} + +#endif /* _IPV6__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_cfg.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_cfg.c new file mode 100644 index 0000000000..31ac0dd93e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_cfg.c @@ -0,0 +1,682 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +unsigned int vow_config; + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/** + * ol_tx_set_flow_control_parameters() - set flow control parameters + * @cfg_ctx: cfg context + * @cfg_param: cfg parameters + * + * Return: none + */ +void ol_tx_set_flow_control_parameters(struct cdp_cfg *cfg_pdev, + struct txrx_pdev_cfg_param_t *cfg_param) +{ + struct txrx_pdev_cfg_t *cfg_ctx = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg_ctx->tx_flow_start_queue_offset = + cfg_param->tx_flow_start_queue_offset; + cfg_ctx->tx_flow_stop_queue_th = + cfg_param->tx_flow_stop_queue_th; +} +#endif + +#ifdef CONFIG_HL_SUPPORT + +#ifdef CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE +static inline +void ol_pdev_cfg_credit_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + cfg_ctx->tx_free_at_download = 1; + cfg_ctx->credit_update_enabled = 1; +} +#else +static inline +void ol_pdev_cfg_credit_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + cfg_ctx->tx_free_at_download = 0; + cfg_ctx->credit_update_enabled = 0; +} +#endif /* CONFIG_CREDIT_REP_THROUGH_CREDIT_UPDATE */ + +/** + * ol_pdev_cfg_param_update() - assign download size of tx frame for txrx + * pdev that will be used across datapath + * @cfg_ctx: ptr to config parameter for txrx pdev + * + * Return: None + */ +static inline +void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + cfg_ctx->is_high_latency = 1; + /* 802.1Q and SNAP / LLC headers are accounted for elsewhere */ + cfg_ctx->tx_download_size = 1500; + ol_pdev_cfg_credit_update(cfg_ctx); +} + +#else /* CONFIG_HL_SUPPORT */ +static inline +void ol_pdev_cfg_param_update(struct txrx_pdev_cfg_t *cfg_ctx) +{ + /* + * Need to change HTT_LL_TX_HDR_SIZE_IP accordingly. + * Include payload, up to the end of UDP header for IPv4 case + */ + cfg_ctx->tx_download_size = 16; +} +#endif + +#ifdef CONFIG_RX_PN_CHECK_OFFLOAD +static inline +void ol_pdev_cfg_rx_pn_check(struct txrx_pdev_cfg_t *cfg_ctx) +{ + /* Do not do pn check on host */ + cfg_ctx->rx_pn_check = 0; +} +#else +static inline +void ol_pdev_cfg_rx_pn_check(struct txrx_pdev_cfg_t *cfg_ctx) +{ + /* Do pn check on host */ + cfg_ctx->rx_pn_check = 1; +} +#endif /* CONFIG_RX_PN_CHECK_OFFLOAD */ + +#if CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK +static inline +uint8_t ol_defrag_timeout_check(void) +{ + return 1; +} +#else +static inline +uint8_t ol_defrag_timeout_check(void) +{ + return 0; +} +#endif + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +/** + * ol_cfg_update_del_ack_params() - update delayed ack params + * @cfg_ctx: cfg context + * @cfg_param: parameters + * + * Return: none + */ +void ol_cfg_update_del_ack_params(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param) +{ + cfg_ctx->del_ack_enable = cfg_param->del_ack_enable; + cfg_ctx->del_ack_timer_value = cfg_param->del_ack_timer_value; + cfg_ctx->del_ack_pkt_count = cfg_param->del_ack_pkt_count; +} +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +static inline +void ol_cfg_update_bundle_params(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param) +{ + cfg_ctx->bundle_timer_value = cfg_param->bundle_timer_value; + cfg_ctx->bundle_size = cfg_param->bundle_size; +} +#else +static inline +void ol_cfg_update_bundle_params(struct txrx_pdev_cfg_t *cfg_ctx, + struct txrx_pdev_cfg_param_t *cfg_param) +{ +} +#endif + +/* FIX THIS - + * For now, all these configuration parameters are hardcoded. + * Many of these should actually be determined dynamically instead. + */ + +struct cdp_cfg *ol_pdev_cfg_attach(qdf_device_t osdev, void *pcfg_param) +{ + struct txrx_pdev_cfg_param_t *cfg_param = pcfg_param; + struct txrx_pdev_cfg_t *cfg_ctx; + int i; + + cfg_ctx = qdf_mem_malloc(sizeof(*cfg_ctx)); + if (!cfg_ctx) + return NULL; + + ol_pdev_cfg_param_update(cfg_ctx); + ol_pdev_cfg_rx_pn_check(cfg_ctx); + + cfg_ctx->defrag_timeout_check = ol_defrag_timeout_check(); + cfg_ctx->max_peer_id = 511; + cfg_ctx->max_vdev = CFG_TGT_NUM_VDEV; + cfg_ctx->pn_rx_fwd_check = 1; + cfg_ctx->frame_type = wlan_frm_fmt_802_3; + cfg_ctx->max_thruput_mbps = MAX_THROUGHPUT; + cfg_ctx->max_nbuf_frags = 1; + cfg_ctx->vow_config = vow_config; + cfg_ctx->target_tx_credit = CFG_TGT_NUM_MSDU_DESC; + cfg_ctx->throttle_period_ms = 40; + cfg_ctx->dutycycle_level[0] = THROTTLE_DUTY_CYCLE_LEVEL0; + cfg_ctx->dutycycle_level[1] = THROTTLE_DUTY_CYCLE_LEVEL1; + cfg_ctx->dutycycle_level[2] = THROTTLE_DUTY_CYCLE_LEVEL2; + cfg_ctx->dutycycle_level[3] = THROTTLE_DUTY_CYCLE_LEVEL3; + cfg_ctx->rx_fwd_disabled = 0; + cfg_ctx->is_packet_log_enabled = 0; + cfg_ctx->is_full_reorder_offload = cfg_param->is_full_reorder_offload; +#ifdef WLAN_FEATURE_TSF_PLUS + cfg_ctx->is_ptp_rx_opt_enabled = 0; +#endif + cfg_ctx->ipa_uc_rsc.uc_offload_enabled = + cfg_param->is_uc_offload_enabled; + cfg_ctx->ipa_uc_rsc.tx_max_buf_cnt = cfg_param->uc_tx_buffer_count; + cfg_ctx->ipa_uc_rsc.tx_buf_size = cfg_param->uc_tx_buffer_size; + cfg_ctx->ipa_uc_rsc.rx_ind_ring_size = + cfg_param->uc_rx_indication_ring_count; + cfg_ctx->ipa_uc_rsc.tx_partition_base = cfg_param->uc_tx_partition_base; + cfg_ctx->enable_rxthread = cfg_param->enable_rxthread; + cfg_ctx->ip_tcp_udp_checksum_offload = + cfg_param->ip_tcp_udp_checksum_offload; + cfg_ctx->p2p_ip_tcp_udp_checksum_offload = + cfg_param->p2p_ip_tcp_udp_checksum_offload; + cfg_ctx->nan_tcp_udp_checksumoffload = + cfg_param->nan_ip_tcp_udp_checksum_offload; + cfg_ctx->ce_classify_enabled = cfg_param->ce_classify_enabled; + cfg_ctx->gro_enable = cfg_param->gro_enable; + cfg_ctx->tso_enable = cfg_param->tso_enable; + cfg_ctx->lro_enable = cfg_param->lro_enable; + cfg_ctx->sg_enable = cfg_param->sg_enable; + cfg_ctx->enable_data_stall_detection = + cfg_param->enable_data_stall_detection; + cfg_ctx->enable_flow_steering = cfg_param->enable_flow_steering; + cfg_ctx->disable_intra_bss_fwd = cfg_param->disable_intra_bss_fwd; + cfg_ctx->pktlog_buffer_size = cfg_param->pktlog_buffer_size; + + ol_cfg_update_del_ack_params(cfg_ctx, cfg_param); + + ol_cfg_update_bundle_params(cfg_ctx, cfg_param); + + ol_tx_set_flow_control_parameters((struct cdp_cfg *)cfg_ctx, cfg_param); + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + cfg_ctx->ac_specs[i].wrr_skip_weight = + cfg_param->ac_specs[i].wrr_skip_weight; + cfg_ctx->ac_specs[i].credit_threshold = + cfg_param->ac_specs[i].credit_threshold; + cfg_ctx->ac_specs[i].send_limit = + cfg_param->ac_specs[i].send_limit; + cfg_ctx->ac_specs[i].credit_reserve = + cfg_param->ac_specs[i].credit_reserve; + cfg_ctx->ac_specs[i].discard_weight = + cfg_param->ac_specs[i].discard_weight; + } + + return (struct cdp_cfg *)cfg_ctx; +} + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE + +int ol_cfg_get_bundle_timer_value(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->bundle_timer_value; +} + +int ol_cfg_get_bundle_size(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->bundle_size; +} +#endif + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK +/** + * ol_cfg_get_del_ack_timer_value() - get delayed ack timer value + * @cfg_pdev: pdev handle + * + * Return: timer value + */ +int ol_cfg_get_del_ack_timer_value(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->del_ack_timer_value; +} + +/** + * ol_cfg_get_del_ack_enable_value() - get delayed ack enable value + * @cfg_pdev: pdev handle + * + * Return: enable/disable + */ +bool ol_cfg_get_del_ack_enable_value(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->del_ack_enable; +} + +/** + * ol_cfg_get_del_ack_count_value() - get delayed ack count value + * @pdev: cfg_pdev handle + * + * Return: count value + */ +int ol_cfg_get_del_ack_count_value(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->del_ack_pkt_count; +} +#endif + +int ol_cfg_is_high_latency(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->is_high_latency; +} + +int ol_cfg_is_credit_update_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->credit_update_enabled; +} + +int ol_cfg_max_peer_id(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + /* + * TBDXXX - this value must match the peer table + * size allocated in FW + */ + return cfg->max_peer_id; +} + +int ol_cfg_max_vdevs(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->max_vdev; +} + +int ol_cfg_rx_pn_check(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->rx_pn_check; +} + +int ol_cfg_rx_fwd_check(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->pn_rx_fwd_check; +} + +void ol_set_cfg_rx_fwd_disabled(struct cdp_cfg *cfg_pdev, + uint8_t disable_rx_fwd) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->rx_fwd_disabled = disable_rx_fwd; +} + +void ol_set_cfg_packet_log_enabled(struct cdp_cfg *cfg_pdev, uint8_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->is_packet_log_enabled = val; +} + +uint8_t ol_cfg_is_packet_log_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->is_packet_log_enabled; +} + +int ol_cfg_rx_fwd_disabled(struct cdp_cfg *cfg_pdev) +{ +#if defined(ATHR_WIN_NWF) + /* for Windows, let the OS handle the forwarding */ + return 1; +#else + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->rx_fwd_disabled; +#endif +} + +int ol_cfg_rx_fwd_inter_bss(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->rx_fwd_inter_bss; +} + +enum wlan_frm_fmt ol_cfg_frame_type(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->frame_type; +} + +int ol_cfg_max_thruput_mbps(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->max_thruput_mbps; +} + +int ol_cfg_netbuf_frags_max(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->max_nbuf_frags; +} + +int ol_cfg_tx_free_at_download(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->tx_free_at_download; +} + +void ol_cfg_set_tx_free_at_download(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->tx_free_at_download = 1; +} + + +#ifdef CONFIG_HL_SUPPORT +uint16_t ol_cfg_target_tx_credit(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->target_tx_credit; +} +#else + +uint16_t ol_cfg_target_tx_credit(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + uint16_t rc; + uint16_t vow_max_sta = (cfg->vow_config & 0xffff0000) >> 16; + uint16_t vow_max_desc_persta = cfg->vow_config & 0x0000ffff; + + rc = (cfg->target_tx_credit + (vow_max_sta * vow_max_desc_persta)); + + return rc; +} +#endif + +int ol_cfg_tx_download_size(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->tx_download_size; +} + +int ol_cfg_rx_host_defrag_timeout_duplicate_check(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->defrag_timeout_check; +} + +int ol_cfg_throttle_period_ms(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->throttle_period_ms; +} + +int ol_cfg_throttle_duty_cycle_level(struct cdp_cfg *cfg_pdev, int level) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->dutycycle_level[level]; +} + +#ifdef CONFIG_HL_SUPPORT +int ol_cfg_is_full_reorder_offload(struct cdp_cfg *cfg_pdev) +{ + return 0; +} +#else +int ol_cfg_is_full_reorder_offload(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->is_full_reorder_offload; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +void ol_set_cfg_ptp_rx_opt_enabled(struct cdp_cfg *cfg_pdev, u_int8_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->is_ptp_rx_opt_enabled = val; +} + +u_int8_t ol_cfg_is_ptp_rx_opt_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->is_ptp_rx_opt_enabled; +} +#endif + +/** + * ol_cfg_is_rx_thread_enabled() - return rx_thread is enable/disable + * @pdev : handle to the physical device + * + * Return: 1 - enable, 0 - disable + */ +int ol_cfg_is_rx_thread_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->enable_rxthread; +} + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/** + * ol_cfg_get_tx_flow_stop_queue_th() - return stop queue threshold + * @pdev : handle to the physical device + * + * Return: stop queue threshold + */ +int ol_cfg_get_tx_flow_stop_queue_th(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->tx_flow_stop_queue_th; +} + +/** + * ol_cfg_get_tx_flow_start_queue_offset() - return start queue offset + * @pdev : handle to the physical device + * + * Return: start queue offset + */ +int ol_cfg_get_tx_flow_start_queue_offset(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->tx_flow_start_queue_offset; +} +#endif + +#ifdef IPA_OFFLOAD +unsigned int ol_cfg_ipa_uc_offload_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return (unsigned int)cfg->ipa_uc_rsc.uc_offload_enabled; +} + +unsigned int ol_cfg_ipa_uc_tx_buf_size(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->ipa_uc_rsc.tx_buf_size; +} + +unsigned int ol_cfg_ipa_uc_tx_max_buf_cnt(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->ipa_uc_rsc.tx_max_buf_cnt; +} + +unsigned int ol_cfg_ipa_uc_rx_ind_ring_size(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->ipa_uc_rsc.rx_ind_ring_size; +} + +unsigned int ol_cfg_ipa_uc_tx_partition_base(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->ipa_uc_rsc.tx_partition_base; +} + +void ol_cfg_set_ipa_uc_tx_partition_base(struct cdp_cfg *cfg_pdev, uint32_t val) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + cfg->ipa_uc_rsc.tx_partition_base = val; +} +#endif /* IPA_OFFLOAD */ + +/** + * ol_cfg_is_ce_classify_enabled() - Return if CE classification is enabled + * or disabled + * @pdev : handle to the physical device + * + * Return: 1 - enabled, 0 - disabled + */ +bool ol_cfg_is_ce_classify_enabled(struct cdp_cfg *cfg_pdev) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)cfg_pdev; + + return cfg->ce_classify_enabled; +} + +/** + * ol_cfg_get_wrr_skip_weight() - brief Query for the param of wrr_skip_weight + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: wrr_skip_weight for specified ac. + */ +int ol_cfg_get_wrr_skip_weight(struct cdp_cfg *pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= QCA_WLAN_AC_BE && ac <= QCA_WLAN_AC_VO) + return cfg->ac_specs[ac].wrr_skip_weight; + + return 0; +} + +/** + * ol_cfg_get_credit_threshold() - Query for the param of credit_threshold + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: credit_threshold for specified ac. + */ +uint32_t ol_cfg_get_credit_threshold(struct cdp_cfg *pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= QCA_WLAN_AC_BE && ac <= QCA_WLAN_AC_VO) + return cfg->ac_specs[ac].credit_threshold; + + return 0; +} + +/** + * ol_cfg_get_send_limit() - Query for the param of send_limit + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: send_limit for specified ac. + */ +uint16_t ol_cfg_get_send_limit(struct cdp_cfg *pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= QCA_WLAN_AC_BE && ac <= QCA_WLAN_AC_VO) + return cfg->ac_specs[ac].send_limit; + + return 0; +} + +/** + * ol_cfg_get_credit_reserve() - Query for the param of credit_reserve + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: credit_reserve for specified ac. + */ +int ol_cfg_get_credit_reserve(struct cdp_cfg *pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= QCA_WLAN_AC_BE && ac <= QCA_WLAN_AC_VO) + return cfg->ac_specs[ac].credit_reserve; + + return 0; +} + +/** + * ol_cfg_get_discard_weight() - Query for the param of discard_weight + * @pdev: handle to the physical device. + * @ac: access control, it will be BE, BK, VI, VO + * + * Return: discard_weight for specified ac. + */ +int ol_cfg_get_discard_weight(struct cdp_cfg *pdev, int ac) +{ + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *)pdev; + + if (ac >= QCA_WLAN_AC_BE && ac <= QCA_WLAN_AC_VO) + return cfg->ac_specs[ac].discard_weight; + + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h new file mode 100644 index 0000000000..fa64c4a0c1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_ctrl_txrx_api.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_ctrl_txrx_api.h + * @brief Define the host control API functions called by the host data SW. + */ +#ifndef _OL_CTRL_TXRX_API__H_ +#define _OL_CTRL_TXRX_API__H_ + +#include /* uint8_t */ +#include /* qdf_nbuf_t */ + +#include /* ol_txrx_pdev_handle */ +#include +#include /* ieee80211_frame */ +#include +#ifdef SUPPORT_HOST_STATISTICS +/** * @brief Update tx statistics + * @details + * Update tx statistics after tx complete. + * + * @param pdev - ol_pdev_handle instance + * @param vdev_id - ID of the virtual device that tx frame + * @param had_error - whether there is error when tx + */ +void ol_tx_statistics(struct cdp_cfg *cfg_pdev, + uint16_t vdev_id, int had_error); +#else +#define ol_tx_statistics(pdev, vdev_id, had_error) +#endif + +/** * @brief Count on received packets for invalid peer case + * + * @param pdev - txrx pdev handle + * @param wh - received frame + * @param err_type - what kind of error occurred + */ +void ol_rx_err_inv_peer_statistics(struct cdp_cfg *cfg_pdev, + struct ieee80211_frame *wh, + enum ol_rx_err_type err_type); + +/** + * @brief Count on received packets, both success and failed + * + * @param pdev - ol_pdev_handle handle + * @param vdev_id - ID of the virtual device received the erroneous rx frame + * @param err_type - what kind of error occurred + * @param sec_type - The cipher type the peer is using + * @param is_mcast - whether this is one multi cast frame + */ +void ol_rx_err_statistics(struct cdp_cfg *cfg_pdev, + uint8_t vdev_id, + enum ol_rx_err_type err_type, + enum ol_sec_type sec_type, int is_mcast); + +/** + * @brief Provide notification of failure during host rx processing + * @details + * Indicate an error during host rx data processing, including what + * kind of error happened, when it happened, which peer and TID the + * erroneous rx frame is from, and what the erroneous rx frame itself + * is. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the erroneous rx frame + * @param peer_mac_addr - MAC address of the peer that sent the erroneous + * rx frame + * @param tid - which TID within the peer sent the erroneous rx frame + * @param tsf32 - the timstamp in TSF units of the erroneous rx frame, or + * one of the fragments that when reassembled, constitute the rx frame + * @param err_type - what kind of error occurred + * @param rx_frame - the rx frame that had an error + * @pn - Packet sequence number + * @key_id - Key index octet received in IV of the frame + */ +void +ol_rx_err(struct cdp_cfg *cfg_pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_err_type err_type, + qdf_nbuf_t rx_frame, uint64_t *pn, uint8_t key_id); + +#ifdef HL_RX_AGGREGATION_HOLE_DETECTION +/** + * ol_rx_aggregation_hole - ol rx aggregation hole report + * @hole_info: hole_info + * + * Return: void + */ +void ol_rx_aggregation_hole(uint32_t hole_info); +#endif + +enum ol_rx_notify_type { + OL_RX_NOTIFY_IPV4_IGMP, +}; + +/** + * @brief Provide notification of reception of data of special interest. + * @details + * Indicate when "special" data has been received. The nature of the + * data that results in it being considered special is specified in the + * notify_type argument. + * This function is currently used by the data-path SW to notify the + * control path SW when the following types of rx data are received: + * + IPv4 IGMP frames + * The control SW can use these to learn about multicast group + * membership, if it so chooses. + * + * @param pdev - handle to the ctrl SW's physical device object + * @param vdev_id - ID of the virtual device received the special data + * @param peer_mac_addr - MAC address of the peer that sent the special data + * @param tid - which TID within the peer sent the special data + * @param tsf32 - the timstamp in TSF units of the special data + * @param notify_type - what kind of special data was received + * @param rx_frame - the rx frame containing the special data + */ +void +ol_rx_notify(struct cdp_cfg *cfg_pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_notify_type notify_type, qdf_nbuf_t rx_frame); + +#define ol_ctrl_rx_addba_complete(pdev, peer_mac_addr, tid, failed) /* no-op */ + +#endif /* _OL_CTRL_TXRX_API__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h new file mode 100644 index 0000000000..ca40d9ca1c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_osif_txrx_api.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011, 2014-2016 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_osif_txrx_api.h + * @brief Define the OS specific API functions called by txrx SW. + */ +#ifndef _OL_OSIF_TXRX_API_H_ +#define _OL_OSIF_TXRX_API_H_ + +#include /* qdf_nbuf_t */ + +/** + * @brief Call tx completion handler to release the buffers + * @details + * + * Invoke tx completion handler when the tx credit goes below low water mark. + * This eliminate the packet drop in the host driver due to send routine not + * yielding the cpu when the amount of traffic pumped from the network layer + * is very high. + * + * @param osdev + */ + +void ol_osif_ath_tasklet(qdf_device_t osdev); + +#endif /* _OL_OSIF_TXRX_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx.c new file mode 100644 index 0000000000..030a5fac29 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx.c @@ -0,0 +1,2061 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_cpu_to_le64 */ +#include /* bool */ +#include /* ieee80211_frame */ + +/* external API header files */ +#include /* ol_rx_notify */ +#include /* ol_txrx_pdev_handle */ +#include /* ol_rx_indication_handler */ +#include /* htt_rx_peer_id, etc. */ + +/* internal API header files */ +#include /* ol_txrx_peer_find_by_id */ +#include /* ol_rx_reorder_store, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_UPDATE */ +#include /* ol_rx_defrag_waitlist_flush */ +#include +#include +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* ol_rx_decap_info_t, etc */ +#endif +#include + +/* FIX THIS: txrx should not include private header files of other modules */ +#include +#include +#include /* ethernet + SNAP/LLC header defs and + * ethertype values + */ +#include /* IP protocol values */ +#include /* IPv4 header defs */ +#include /* IPv6 header defs */ +#include +#include +#include +#include "pktlog_ac_fmt.h" +#include +#include +#include +#include +#include + +#ifndef OL_RX_INDICATION_MAX_RECORDS +#define OL_RX_INDICATION_MAX_RECORDS 2048 +#endif + +/** + * enum ol_rx_ind_record_type - OL rx indication events + * @OL_RX_INDICATION_POP_START: event recorded before netbuf pop + * @OL_RX_INDICATION_POP_END: event recorded after netbuf pop + * @OL_RX_INDICATION_BUF_REPLENISH: event recorded after buffer replenishment + */ +enum ol_rx_ind_record_type { + OL_RX_INDICATION_POP_START, + OL_RX_INDICATION_POP_END, + OL_RX_INDICATION_BUF_REPLENISH, +}; + +/** + * struct ol_rx_ind_record - structure for detailing ol txrx rx ind. event + * @value: info corresponding to rx indication event + * @type: what the event was + * @time: when it happened + */ +struct ol_rx_ind_record { + uint16_t value; + enum ol_rx_ind_record_type type; + uint64_t time; +}; + +#ifdef OL_RX_INDICATION_RECORD +static uint32_t ol_rx_ind_record_index; +struct ol_rx_ind_record + ol_rx_indication_record_history[OL_RX_INDICATION_MAX_RECORDS]; + +/** + * ol_rx_ind_record_event() - record ol rx indication events + * @value: contains rx ind. event related info + * @type: ol rx indication message type + * + * This API record the ol rx indiation event in a rx indication + * record buffer. + * + * Return: None + */ +static void ol_rx_ind_record_event(uint32_t value, + enum ol_rx_ind_record_type type) +{ + ol_rx_indication_record_history[ol_rx_ind_record_index].value = value; + ol_rx_indication_record_history[ol_rx_ind_record_index].type = type; + ol_rx_indication_record_history[ol_rx_ind_record_index].time = + qdf_get_log_timestamp(); + + ol_rx_ind_record_index++; + if (ol_rx_ind_record_index >= OL_RX_INDICATION_MAX_RECORDS) + ol_rx_ind_record_index = 0; +} +#else +static inline +void ol_rx_ind_record_event(uint32_t value, enum ol_rx_ind_record_type type) +{ +} + +#endif /* OL_RX_INDICATION_RECORD */ + +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + qdf_nbuf_t rx_buf_list); + +#ifdef WDI_EVENT_ENABLE +/** + * ol_rx_send_pktlog_event() - send rx packetlog event + * @pdev: pdev handle + * @peer: peer handle + * @msdu: skb list + * @pktlog_bit: packetlog bit from firmware + * + * Return: none + */ +#ifdef HELIUMPLUS +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ + struct ol_rx_remote_data data; + + /** + * pktlog is meant to log rx_desc information which is + * already overwritten by radio header when monitor mode is ON. + * Therefore, Do not log pktlog event when monitor mode is ON. + */ + if (!pktlog_bit || (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE)) + return; + + data.msdu = msdu; + if (peer) + data.mac_id = peer->vdev->mac_id; + else + data.mac_id = 0; + + wdi_event_handler(WDI_EVENT_RX_DESC_REMOTE, pdev->id, + &data); +} +#else +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, uint8_t pktlog_bit) +{ + struct ol_rx_remote_data data; + + /** + * pktlog is meant to log rx_desc information which is + * already overwritten by radio header when monitor mode is ON. + * Therefore, Do not log pktlog event when monitor mode is ON. + */ + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + return; + + data.msdu = msdu; + if (peer) + data.mac_id = peer->vdev->mac_id; + else + data.mac_id = 0; + + wdi_event_handler(WDI_EVENT_RX_DESC_REMOTE, pdev->id, + &data); +} +#endif +#endif /* WDI_EVENT_ENABLE */ + +#ifdef HTT_RX_RESTORE + +static void ol_rx_restore_handler(struct work_struct *htt_rx) +{ + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Enter: %s", __func__); + pld_device_self_recovery(qdf_ctx->dev); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Exit: %s", __func__); +} + +static DECLARE_WORK(ol_rx_restore_work, ol_rx_restore_handler); + +void ol_rx_trigger_restore(htt_pdev_handle htt_pdev, qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + qdf_nbuf_t next; + + while (head_msdu) { + next = qdf_nbuf_next(head_msdu); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "freeing %pK\n", head_msdu); + qdf_nbuf_free(head_msdu); + head_msdu = next; + } + + if (!htt_pdev->rx_ring.htt_rx_restore) { + cds_set_recovery_in_progress(true); + htt_pdev->rx_ring.htt_rx_restore = 1; + schedule_work(&ol_rx_restore_work); + } +} +#endif + +/** + * ol_rx_update_histogram_stats() - update rx histogram statistics + * @msdu_count: msdu count + * @frag_ind: fragment indication set + * @offload_ind: offload indication set + * + * Return: none + */ +void ol_rx_update_histogram_stats(uint32_t msdu_count, uint8_t frag_ind, + uint8_t offload_ind) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + if (msdu_count > 60) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_61_plus, 1); + } else if (msdu_count > 50) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_51_60, 1); + } else if (msdu_count > 40) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_41_50, 1); + } else if (msdu_count > 30) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_31_40, 1); + } else if (msdu_count > 20) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_21_30, 1); + } else if (msdu_count > 10) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_11_20, 1); + } else if (msdu_count > 1) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_2_10, 1); + } else if (msdu_count == 1) { + TXRX_STATS_ADD(pdev, pub.rx.rx_ind_histogram.pkts_1, 1); + } + + if (frag_ind) + TXRX_STATS_ADD(pdev, pub.rx.msdus_with_frag_ind, msdu_count); + + if (offload_ind) + TXRX_STATS_ADD(pdev, pub.rx.msdus_with_offload_ind, msdu_count); + +} + +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD + +#ifdef WDI_EVENT_ENABLE +static void ol_rx_process_inv_peer(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, qdf_nbuf_t msdu) +{ + uint8_t a1[QDF_MAC_ADDR_SIZE]; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + struct ol_txrx_vdev_t *vdev = NULL; + struct ieee80211_frame *wh; + struct wdi_event_rx_peer_invalid_msg msg; + + wh = (struct ieee80211_frame *) + htt_rx_mpdu_wifi_hdr_retrieve(htt_pdev, rx_mpdu_desc); + /* + * Klocwork issue #6152 + * All targets that send a "INVALID_PEER" rx status provide a + * 802.11 header for each rx MPDU, so it is certain that + * htt_rx_mpdu_wifi_hdr_retrieve will succeed. + * However, both for robustness, e.g. if this function is given a + * MSDU descriptor rather than a MPDU descriptor, and to make it + * clear to static analysis that this code is safe, add an explicit + * check that htt_rx_mpdu_wifi_hdr_retrieve provides a non-NULL value. + */ + if (!wh || !IEEE80211_IS_DATA(wh)) + return; + + /* ignore frames for non-existent bssids */ + qdf_mem_copy(a1, wh->i_addr1, QDF_MAC_ADDR_SIZE); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (qdf_mem_cmp(a1, vdev->mac_addr.raw, QDF_MAC_ADDR_SIZE)) + break; + } + if (!vdev) + return; + + msg.wh = wh; + msg.msdu = msdu; + msg.vdev_id = vdev->vdev_id; + wdi_event_handler(WDI_EVENT_RX_PEER_INVALID, pdev->id, + &msg); +} +#else +static inline +void ol_rx_process_inv_peer(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, qdf_nbuf_t msdu) +{ +} +#endif + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +static inline int16_t +ol_rx_rssi_avg(struct ol_txrx_pdev_t *pdev, int16_t rssi_old, int16_t rssi_new) +{ + int rssi_old_weight; + + if (rssi_new == HTT_RSSI_INVALID) + return rssi_old; + if (rssi_old == HTT_RSSI_INVALID) + return rssi_new; + + rssi_old_weight = + (1 << pdev->rssi_update_shift) - pdev->rssi_new_weight; + return (rssi_new * pdev->rssi_new_weight + + rssi_old * rssi_old_weight) >> pdev->rssi_update_shift; +} + +static void +ol_rx_ind_rssi_update(struct ol_txrx_peer_t *peer, qdf_nbuf_t rx_ind_msg) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + peer->rssi_dbm = ol_rx_rssi_avg(pdev, peer->rssi_dbm, + htt_rx_ind_rssi_dbm(pdev->htt_pdev, + rx_ind_msg)); +} + +static void +ol_rx_mpdu_rssi_update(struct ol_txrx_peer_t *peer, void *rx_mpdu_desc) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + if (!peer) + return; + peer->rssi_dbm = ol_rx_rssi_avg(pdev, peer->rssi_dbm, + htt_rx_mpdu_desc_rssi_dbm( + pdev->htt_pdev, + rx_mpdu_desc)); +} + +#else +#define ol_rx_ind_rssi_update(peer, rx_ind_msg) /* no-op */ +#define ol_rx_mpdu_rssi_update(peer, rx_mpdu_desc) /* no-op */ +#endif /* QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +static void discard_msdus(htt_pdev_handle htt_pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + while (1) { + qdf_nbuf_t next; + + next = qdf_nbuf_next( + head_msdu); + htt_rx_desc_frame_free + (htt_pdev, + head_msdu); + if (head_msdu == + tail_msdu) { + break; + } + head_msdu = next; + } +} + +static void chain_msdus(htt_pdev_handle htt_pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + while (1) { + qdf_nbuf_t next; + + next = qdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free( + htt_pdev, + head_msdu); + if (head_msdu == tail_msdu) + break; + head_msdu = next; + } +} + +static void process_reorder(ol_txrx_pdev_handle pdev, + void *rx_mpdu_desc, + uint8_t tid, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu, + int num_mpdu_ranges, + int num_mpdus, + bool rx_ind_release) +{ + htt_pdev_handle htt_pdev = pdev->htt_pdev; + enum htt_rx_status mpdu_status; + int reorder_idx; + + reorder_idx = htt_rx_mpdu_desc_reorder_idx(htt_pdev, rx_mpdu_desc, + true); + OL_RX_REORDER_TRACE_ADD(pdev, tid, + reorder_idx, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_mpdu_desc, false), + 1); + ol_rx_mpdu_rssi_update(peer, rx_mpdu_desc); + /* + * In most cases, out-of-bounds and duplicate sequence number detection + * is performed by the target, but in some cases it is done by the host. + * Specifically, the host does rx out-of-bounds sequence number + * detection for: + * 1. Peregrine or Rome target + * for peer-TIDs that do not have aggregation enabled, if the + * RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK flag + * is set during the driver build. + * 2. Riva-family targets, which have rx reorder timeouts handled by + * the host rather than the target. + * (The target already does duplicate detection, but the host + * may have given up waiting for a particular sequence number before + * it arrives. In this case, the out-of-bounds sequence number + * of the late frame allows the host to discard it, rather than + * sending it out of order. + */ + mpdu_status = OL_RX_SEQ_NUM_CHECK(pdev, + peer, + tid, + rx_mpdu_desc); + if (mpdu_status != htt_rx_status_ok) { + /* + * If the sequence number was out of bounds, the MPDU needs + * to be discarded. + */ + discard_msdus(htt_pdev, head_msdu, tail_msdu); + /* + * For Peregrine and Rome, + * OL_RX_REORDER_SEQ_NUM_CHECK should only fail for the case + * of (duplicate) non-aggregates. + * + * For Riva, Pronto and Northstar, + * there should be only one MPDU delivered at a time. + * Thus, there are no further MPDUs that need to be + * processed here. + * Just to be sure this is true, check the assumption + * that this was the only MPDU referenced by the rx + * indication. + */ + TXRX_ASSERT2((num_mpdu_ranges == 1) && num_mpdus == 1); + + /* + * The MPDU was not stored in the rx reorder array, so + * there's nothing to release. + */ + rx_ind_release = false; + } else { + ol_rx_reorder_store(pdev, peer, tid, + reorder_idx, head_msdu, tail_msdu); + if (peer->tids_rx_reorder[tid].win_sz_mask == 0) { + peer->tids_last_seq[tid] = htt_rx_mpdu_desc_seq_num( + htt_pdev, + rx_mpdu_desc, false); + } + } +} /* process_reorder */ + +#ifdef WLAN_FEATURE_DSRC +static void +ol_rx_ocb_update_peer(ol_txrx_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + struct ol_txrx_peer_t *peer) +{ + int i; + + htt_rx_ind_legacy_rate(pdev->htt_pdev, rx_ind_msg, + &peer->last_pkt_legacy_rate, + &peer->last_pkt_legacy_rate_sel); + peer->last_pkt_rssi_cmb = htt_rx_ind_rssi_dbm( + pdev->htt_pdev, rx_ind_msg); + for (i = 0; i < 4; i++) + peer->last_pkt_rssi[i] = + htt_rx_ind_rssi_dbm_chain(pdev->htt_pdev, rx_ind_msg, i); + + htt_rx_ind_timestamp(pdev->htt_pdev, rx_ind_msg, + &peer->last_pkt_timestamp_microsec, + &peer->last_pkt_timestamp_submicrosec); + peer->last_pkt_tsf = htt_rx_ind_tsf32(pdev->htt_pdev, rx_ind_msg); + peer->last_pkt_tid = htt_rx_ind_ext_tid(pdev->htt_pdev, rx_ind_msg); +} +#else +static void +ol_rx_ocb_update_peer(ol_txrx_pdev_handle pdev, qdf_nbuf_t rx_ind_msg, + struct ol_txrx_peer_t *peer) +{ +} +#endif + +void +ol_rx_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, uint8_t tid, int num_mpdu_ranges) +{ + int mpdu_range; + unsigned int seq_num_start = 0, seq_num_end = 0; + bool rx_ind_release = false; + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer; + htt_pdev_handle htt_pdev; + uint16_t center_freq; + uint16_t chan1; + uint16_t chan2; + uint8_t phymode; + bool ret; + uint32_t msdu_count = 0; + + htt_pdev = pdev->htt_pdev; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + /* + * If we can't find a peer send this packet to OCB interface + * using OCB self peer + */ + if (!ol_txrx_get_ocb_peer(pdev, &peer)) + peer = NULL; + } + + if (peer) { + vdev = peer->vdev; + ol_rx_ind_rssi_update(peer, rx_ind_msg); + + if (vdev->opmode == wlan_op_mode_ocb) + ol_rx_ocb_update_peer(pdev, rx_ind_msg, peer); + } + + TXRX_STATS_INCR(pdev, priv.rx.normal.ppdus); + + OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev); + + if (htt_rx_ind_flush(pdev->htt_pdev, rx_ind_msg) && peer) { + htt_rx_ind_flush_seq_num_range(pdev->htt_pdev, rx_ind_msg, + &seq_num_start, &seq_num_end); + if (tid == HTT_INVALID_TID) { + /* + * host/FW reorder state went out-of sync + * for a while because FW ran out of Rx indication + * buffer. We have to discard all the buffers in + * reorder queue. + */ + ol_rx_reorder_peer_cleanup(vdev, peer); + } else { + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("invalid tid, %u", tid); + WARN_ON(1); + return; + } + ol_rx_reorder_flush(vdev, peer, tid, seq_num_start, + seq_num_end, htt_rx_flush_release); + } + } + + if (htt_rx_ind_release(pdev->htt_pdev, rx_ind_msg)) { + /* + * The ind info of release is saved here and do release at the + * end. This is for the reason of in HL case, the qdf_nbuf_t + * for msg and payload are the same buf. And the buf will be + * changed during processing + */ + rx_ind_release = true; + htt_rx_ind_release_seq_num_range(pdev->htt_pdev, rx_ind_msg, + &seq_num_start, &seq_num_end); + } +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_initial_msdu_payld = + pdev->htt_pdev->rx_ring.sw_rd_idx.msdu_payld; +#endif + + for (mpdu_range = 0; mpdu_range < num_mpdu_ranges; mpdu_range++) { + enum htt_rx_status status; + int i, num_mpdus; + qdf_nbuf_t head_msdu, tail_msdu, msdu; + void *rx_mpdu_desc; + +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_mpdu_range = mpdu_range; +#endif + + htt_rx_ind_mpdu_range_info(pdev->htt_pdev, rx_ind_msg, + mpdu_range, &status, &num_mpdus); + if ((status == htt_rx_status_ok) && peer) { + TXRX_STATS_ADD(pdev, priv.rx.normal.mpdus, num_mpdus); + /* valid frame - deposit it into rx reordering buffer */ + for (i = 0; i < num_mpdus; i++) { + int msdu_chaining; + /* + * Get a linked list of the MSDUs that comprise + * this MPDU. + * This also attaches each rx MSDU descriptor to + * the corresponding rx MSDU network buffer. + * (In some systems, the rx MSDU desc is already + * in the same buffer as the MSDU payload; in + * other systems they are separate, so a pointer + * needs to be set in the netbuf to locate the + * corresponding rx descriptor.) + * + * It is necessary to call htt_rx_amsdu_pop + * before htt_rx_mpdu_desc_list_next, because + * the (MPDU) rx descriptor has DMA unmapping + * done during the htt_rx_amsdu_pop call. + * The rx desc should not be accessed until this + * DMA unmapping has been done, since the DMA + * unmapping involves making sure the cache area + * for the mapped buffer is flushed, so the data + * written by the MAC DMA into memory will be + * fetched, rather than garbage from the cache. + */ + +#ifdef DEBUG_DMA_DONE + pdev->htt_pdev->rx_ring.dbg_mpdu_count = i; +#endif + + msdu_chaining = + htt_rx_amsdu_pop(htt_pdev, + rx_ind_msg, + &head_msdu, + &tail_msdu, + &msdu_count); +#ifdef HTT_RX_RESTORE + if (htt_pdev->rx_ring.rx_reset) { + ol_rx_trigger_restore(htt_pdev, + head_msdu, + tail_msdu); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK( + pdev); + return; + } +#endif + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_ind_msg); + ret = htt_rx_msdu_center_freq(htt_pdev, peer, + rx_mpdu_desc, ¢er_freq, &chan1, + &chan2, &phymode); + if (ret == true) { + peer->last_pkt_center_freq = + center_freq; + } else { + peer->last_pkt_center_freq = 0; + } + + /* Pktlog */ + ol_rx_send_pktlog_event(pdev, peer, + head_msdu, 1); + + if (msdu_chaining) { + /* + * TBDXXX - to deliver SDU with + * chaining, we need to stitch those + * scattered buffers into one single + * buffer. + * Just discard it now. + */ + chain_msdus(htt_pdev, + head_msdu, + tail_msdu); + } else { + process_reorder(pdev, rx_mpdu_desc, + tid, peer, + head_msdu, tail_msdu, + num_mpdu_ranges, + num_mpdus, + rx_ind_release); + } + + } + } else { + /* invalid frames - discard them */ + OL_RX_REORDER_TRACE_ADD(pdev, tid, + TXRX_SEQ_NUM_ERR(status), + TXRX_SEQ_NUM_ERR(status), + num_mpdus); + TXRX_STATS_ADD(pdev, priv.rx.err.mpdu_bad, num_mpdus); + for (i = 0; i < num_mpdus; i++) { + /* pull the MPDU's MSDUs off the buffer queue */ + htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &msdu, + &tail_msdu, &msdu_count); +#ifdef HTT_RX_RESTORE + if (htt_pdev->rx_ring.rx_reset) { + ol_rx_trigger_restore(htt_pdev, msdu, + tail_msdu); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK( + pdev); + return; + } +#endif + /* pull the MPDU desc off the desc queue */ + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_ind_msg); + OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, + rx_mpdu_desc, msdu, + status); + + if (status == htt_rx_status_tkip_mic_err && + vdev && peer) { + union htt_rx_pn_t pn; + uint8_t key_id; + + htt_rx_mpdu_desc_pn( + pdev->htt_pdev, + htt_rx_msdu_desc_retrieve( + pdev->htt_pdev, + msdu), &pn, 48); + if (htt_rx_msdu_desc_key_id( + pdev->htt_pdev, + htt_rx_msdu_desc_retrieve( + pdev->htt_pdev, + msdu), + &key_id) == true) { + ol_rx_send_mic_err_ind( + vdev->pdev, + vdev->vdev_id, + peer->mac_addr.raw, + tid, 0, + OL_RX_ERR_TKIP_MIC, + msdu, &pn.pn48, + key_id); + } + } + + if (status != htt_rx_status_ctrl_mgmt_null) { + /* Pktlog */ + ol_rx_send_pktlog_event(pdev, + peer, msdu, 1); + } + + if (status == htt_rx_status_err_inv_peer) { + /* once per mpdu */ + ol_rx_process_inv_peer(pdev, + rx_mpdu_desc, + msdu); + } + + while (1) { + /* Free the nbuf */ + qdf_nbuf_t next; + + next = qdf_nbuf_next(msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + if (msdu == tail_msdu) + break; + msdu = next; + } + } + } + } + /* + * Now that a whole batch of MSDUs have been pulled out of HTT + * and put into the rx reorder array, it is an appropriate time + * to request HTT to provide new rx MSDU buffers for the target + * to fill. + * This could be done after the end of this function, but it's + * better to do it now, rather than waiting until after the driver + * and OS finish processing the batch of rx MSDUs. + */ + htt_rx_msdu_buff_replenish(htt_pdev); + + if ((true == rx_ind_release) && peer && vdev) { + ol_rx_reorder_release(vdev, peer, tid, seq_num_start, + seq_num_end); + } + OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); + + if (pdev->rx.flags.defrag_timeout_check) + ol_rx_defrag_waitlist_flush(pdev); +} +#endif + +void +ol_rx_sec_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + enum htt_sec_type sec_type, + int is_unicast, uint32_t *michael_key, uint32_t *rx_pn) +{ + struct ol_txrx_peer_t *peer; + int sec_index, i; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + ol_txrx_err( + "Couldn't find peer from ID %d - skipping security inits\n", + peer_id); + return; + } + ol_txrx_dbg( + "sec spec for peer %pK ("QDF_MAC_ADDR_FMT"): %s key of type %d\n", + peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + is_unicast ? "ucast" : "mcast", sec_type); + sec_index = is_unicast ? txrx_sec_ucast : txrx_sec_mcast; + peer->security[sec_index].sec_type = sec_type; + /* + * michael key only valid for TKIP + * but for simplicity, copy it anyway + */ + qdf_mem_copy(&peer->security[sec_index].michael_key[0], + michael_key, + sizeof(peer->security[sec_index].michael_key)); + + if (sec_type != htt_sec_type_wapi) { + qdf_mem_zero(peer->tids_last_pn_valid, + OL_TXRX_NUM_EXT_TIDS); + } else if (sec_index == txrx_sec_mcast || peer->tids_last_pn_valid[0]) { + for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) { + /* + * Setting PN valid bit for WAPI sec_type, + * since WAPI PN has to be started with predefined value + */ + peer->tids_last_pn_valid[i] = 1; + qdf_mem_copy((uint8_t *) &peer->tids_last_pn[i], + (uint8_t *) rx_pn, + sizeof(union htt_rx_pn_t)); + peer->tids_last_pn[i].pn128[1] = + qdf_cpu_to_le64( + peer->tids_last_pn[i].pn128[1]); + peer->tids_last_pn[i].pn128[0] = + qdf_cpu_to_le64( + peer->tids_last_pn[i].pn128[0]); + if (sec_index == txrx_sec_ucast) + peer->tids_rekey_flag[i] = 1; + } + } +} + +void ol_rx_notify(struct cdp_cfg *cfg_pdev, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tid, + uint32_t tsf32, + enum ol_rx_notify_type notify_type, qdf_nbuf_t rx_frame) +{ + /* + * NOTE: This is used in qca_main for AP mode to handle IGMP + * packets specially. Umac has a corresponding handler for this + * not sure if we need to have this for CLD as well. + */ +} + +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD +/** + * @brief Look into a rx MSDU to see what kind of special handling it requires + * @details + * This function is called when the host rx SW sees that the target + * rx FW has marked a rx MSDU as needing inspection. + * Based on the results of the inspection, the host rx SW will infer + * what special handling to perform on the rx frame. + * Currently, the only type of frames that require special handling + * are IGMP frames. The rx data-path SW checks if the frame is IGMP + * (it should be, since the target would not have set the inspect flag + * otherwise), and then calls the ol_rx_notify function so the + * control-path SW can perform multicast group membership learning + * by sniffing the IGMP frame. + */ +#define SIZEOF_80211_HDR (sizeof(struct ieee80211_frame)) +static void +ol_rx_inspect(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu, void *rx_desc) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + uint8_t *data, *l3_hdr; + uint16_t ethertype; + int offset; + + data = qdf_nbuf_data(msdu); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + offset = SIZEOF_80211_HDR + LLC_SNAP_HDR_OFFSET_ETHERTYPE; + l3_hdr = data + SIZEOF_80211_HDR + LLC_SNAP_HDR_LEN; + } else { + offset = QDF_MAC_ADDR_SIZE * 2; + l3_hdr = data + ETHERNET_HDR_LEN; + } + ethertype = (data[offset] << 8) | data[offset + 1]; + if (ethertype == ETHERTYPE_IPV4) { + offset = IPV4_HDR_OFFSET_PROTOCOL; + if (l3_hdr[offset] == IP_PROTOCOL_IGMP) { + ol_rx_notify(pdev->ctrl_pdev, + vdev->vdev_id, + peer->mac_addr.raw, + tid, + htt_rx_mpdu_desc_tsf32(pdev->htt_pdev, + rx_desc), + OL_RX_NOTIFY_IPV4_IGMP, msdu); + } + } +} +#endif + +void +ol_rx_offload_deliver_ind_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msg, uint16_t msdu_cnt) +{ + int vdev_id, peer_id, tid; + qdf_nbuf_t head_buf, tail_buf, buf; + struct ol_txrx_peer_t *peer; + uint8_t fw_desc; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + if (msdu_cnt > htt_rx_offload_msdu_cnt(htt_pdev)) { + ol_txrx_err("invalid msdu_cnt=%u", msdu_cnt); + + if (pdev->cfg.is_high_latency) + htt_rx_desc_frame_free(htt_pdev, msg); + + return; + } + + while (msdu_cnt) { + if (!htt_rx_offload_msdu_pop(htt_pdev, msg, &vdev_id, &peer_id, + &tid, &fw_desc, &head_buf, &tail_buf)) { + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + ol_rx_data_process(peer, head_buf); + } else { + buf = head_buf; + while (1) { + qdf_nbuf_t next; + + next = qdf_nbuf_next(buf); + htt_rx_desc_frame_free(htt_pdev, buf); + if (buf == tail_buf) + break; + buf = next; + } + } + } + msdu_cnt--; + } + htt_rx_msdu_buff_replenish(htt_pdev); +} + +void +ol_rx_send_mic_err_ind(struct ol_txrx_pdev_t *pdev, uint8_t vdev_id, + uint8_t *peer_mac_addr, int tid, uint32_t tsf32, + enum ol_rx_err_type err_type, qdf_nbuf_t rx_frame, + uint64_t *pn, uint8_t key_id) +{ + struct cdp_rx_mic_err_info mic_failure_info; + qdf_ether_header_t *eth_hdr; + struct ol_if_ops *tops = NULL; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_soc_handle ol_txrx_soc = &soc->cdp_soc; + + if (err_type != OL_RX_ERR_TKIP_MIC) + return; + + if (qdf_nbuf_len(rx_frame) < sizeof(*eth_hdr)) + return; + + eth_hdr = (qdf_ether_header_t *)qdf_nbuf_data(rx_frame); + + qdf_copy_macaddr((struct qdf_mac_addr *)&mic_failure_info.ta_mac_addr, + (struct qdf_mac_addr *)peer_mac_addr); + qdf_copy_macaddr((struct qdf_mac_addr *)&mic_failure_info.da_mac_addr, + (struct qdf_mac_addr *)eth_hdr->ether_dhost); + mic_failure_info.key_id = key_id; + mic_failure_info.multicast = + IEEE80211_IS_MULTICAST(eth_hdr->ether_dhost); + qdf_mem_copy(mic_failure_info.tsc, pn, SIR_CIPHER_SEQ_CTR_SIZE); + mic_failure_info.frame_type = cdp_rx_frame_type_802_3; + mic_failure_info.data = NULL; + mic_failure_info.vdev_id = vdev_id; + + tops = ol_txrx_soc->ol_ops; + if (tops->rx_mic_error) + tops->rx_mic_error(soc->psoc, pdev->id, &mic_failure_info); +} + +void +ol_rx_mic_error_handler( + ol_txrx_pdev_handle pdev, + u_int8_t tid, + u_int16_t peer_id, + void *msdu_desc, + qdf_nbuf_t msdu) +{ + union htt_rx_pn_t pn = {0}; + u_int8_t key_id = 0; + + struct ol_txrx_peer_t *peer = NULL; + struct ol_txrx_vdev_t *vdev = NULL; + + if (pdev) { + TXRX_STATS_MSDU_INCR(pdev, rx.dropped_mic_err, msdu); + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + vdev = peer->vdev; + if (vdev) { + htt_rx_mpdu_desc_pn(vdev->pdev->htt_pdev, + msdu_desc, &pn, 48); + + if (htt_rx_msdu_desc_key_id( + vdev->pdev->htt_pdev, msdu_desc, + &key_id) == true) { + ol_rx_send_mic_err_ind(vdev->pdev, + vdev->vdev_id, + peer->mac_addr.raw, tid, 0, + OL_RX_ERR_TKIP_MIC, msdu, + &pn.pn48, key_id); + } + } + } + /* Pktlog */ + ol_rx_send_pktlog_event(pdev, peer, msdu, 1); + } +} + +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD +/** + * @brief Check the first msdu to decide whether the a-msdu should be accepted. + */ +static bool +ol_rx_filter(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, void *rx_desc) +{ +#define FILTER_STATUS_REJECT 1 +#define FILTER_STATUS_ACCEPT 0 + uint8_t *wh; + uint32_t offset = 0; + uint16_t ether_type = 0; + bool is_encrypted = false, is_mcast = false; + uint8_t i; + enum privacy_filter_packet_type packet_type = + PRIVACY_FILTER_PACKET_UNICAST; + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + int sec_idx; + + /* + * Safemode must avoid the PrivacyExemptionList and + * ExcludeUnencrypted checking + */ + if (vdev->safemode) + return FILTER_STATUS_ACCEPT; + + is_mcast = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc); + if (vdev->num_filters > 0) { + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + offset = SIZEOF_80211_HDR + + LLC_SNAP_HDR_OFFSET_ETHERTYPE; + } else { + offset = QDF_MAC_ADDR_SIZE * 2; + } + /* get header info from msdu */ + wh = qdf_nbuf_data(msdu); + + /* get ether type */ + ether_type = (wh[offset] << 8) | wh[offset + 1]; + /* get packet type */ + if (true == is_mcast) + packet_type = PRIVACY_FILTER_PACKET_MULTICAST; + else + packet_type = PRIVACY_FILTER_PACKET_UNICAST; + } + /* get encrypt info */ + is_encrypted = htt_rx_mpdu_is_encrypted(htt_pdev, rx_desc); +#ifdef ATH_SUPPORT_WAPI + if ((true == is_encrypted) && (ETHERTYPE_WAI == ether_type)) { + /* + * We expect the WAI frames to be always unencrypted when + * the UMAC gets it + */ + return FILTER_STATUS_REJECT; + } +#endif /* ATH_SUPPORT_WAPI */ + + for (i = 0; i < vdev->num_filters; i++) { + enum privacy_filter filter_type; + enum privacy_filter_packet_type filter_packet_type; + + /* skip if the ether type does not match */ + if (vdev->privacy_filters[i].ether_type != ether_type) + continue; + + /* skip if the packet type does not match */ + filter_packet_type = vdev->privacy_filters[i].packet_type; + if (filter_packet_type != packet_type && + filter_packet_type != PRIVACY_FILTER_PACKET_BOTH) { + continue; + } + + filter_type = vdev->privacy_filters[i].filter_type; + if (filter_type == PRIVACY_FILTER_ALWAYS) { + /* + * In this case, we accept the frame if and only if + * it was originally NOT encrypted. + */ + if (true == is_encrypted) + return FILTER_STATUS_REJECT; + else + return FILTER_STATUS_ACCEPT; + + } else if (filter_type == PRIVACY_FILTER_KEY_UNAVAILABLE) { + /* + * In this case, we reject the frame if it was + * originally NOT encrypted but we have the key mapping + * key for this frame. + */ + if (!is_encrypted && + !is_mcast && + (peer->security[txrx_sec_ucast].sec_type != + htt_sec_type_none) && + (peer->keyinstalled || !ETHERTYPE_IS_EAPOL_WAPI( + ether_type))) { + return FILTER_STATUS_REJECT; + } else { + return FILTER_STATUS_ACCEPT; + } + } else { + /* + * The privacy exemption does not apply to this frame. + */ + break; + } + } + + /* + * If the privacy exemption list does not apply to the frame, + * check ExcludeUnencrypted. + * If ExcludeUnencrypted is not set, or if this was oringially + * an encrypted frame, it will be accepted. + */ + if (!vdev->drop_unenc || (true == is_encrypted)) + return FILTER_STATUS_ACCEPT; + + /* + * If this is a open connection, it will be accepted. + */ + sec_idx = (true == is_mcast) ? txrx_sec_mcast : txrx_sec_ucast; + if (peer->security[sec_idx].sec_type == htt_sec_type_none) + return FILTER_STATUS_ACCEPT; + + if ((false == is_encrypted) && vdev->drop_unenc) { + OL_RX_ERR_STATISTICS(pdev, vdev, OL_RX_ERR_PRIVACY, + pdev->sec_types[htt_sec_type_none], + is_mcast); + } + return FILTER_STATUS_REJECT; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +#ifdef CONFIG_HL_SUPPORT +void ol_rx_timestamp(struct cdp_cfg *cfg_pdev, + void *rx_desc, qdf_nbuf_t msdu) +{ + struct htt_rx_ppdu_desc_t *rx_ppdu_desc; + + if (!ol_cfg_is_ptp_rx_opt_enabled(cfg_pdev)) + return; + + if (!rx_desc || !msdu) + return; + + rx_ppdu_desc = (struct htt_rx_ppdu_desc_t *)((uint8_t *)(rx_desc) - + HTT_RX_IND_HL_BYTES + HTT_RX_IND_HDR_PREFIX_BYTES); + msdu->tstamp = ns_to_ktime((u_int64_t)rx_ppdu_desc->tsf32 * + NSEC_PER_USEC); +} + +static inline void ol_rx_timestamp_update(ol_txrx_pdev_handle pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + qdf_nbuf_t loop_msdu; + struct htt_host_rx_desc_base *rx_desc; + + loop_msdu = head_msdu; + while (loop_msdu) { + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, loop_msdu); + ol_rx_timestamp(pdev->ctrl_pdev, rx_desc, loop_msdu); + loop_msdu = qdf_nbuf_next(loop_msdu); + } +} +#else +void ol_rx_timestamp(struct cdp_cfg *cfg_pdev, + void *rx_desc, qdf_nbuf_t msdu) +{ + struct htt_host_rx_desc_base *rx_mpdu_desc = rx_desc; + uint32_t tsf64_low32, tsf64_high32; + uint64_t tsf64, tsf64_ns; + + if (!ol_cfg_is_ptp_rx_opt_enabled(cfg_pdev)) + return; + + if (!rx_mpdu_desc || !msdu) + return; + + tsf64_low32 = rx_mpdu_desc->ppdu_end.wb_timestamp_lower_32; + tsf64_high32 = rx_mpdu_desc->ppdu_end.wb_timestamp_upper_32; + + tsf64 = (uint64_t)tsf64_high32 << 32 | tsf64_low32; + if (tsf64 * NSEC_PER_USEC < tsf64) + tsf64_ns = 0; + else + tsf64_ns = tsf64 * NSEC_PER_USEC; + + msdu->tstamp = ns_to_ktime(tsf64_ns); +} + +/** + * ol_rx_timestamp_update() - update msdu tsf64 timestamp + * @pdev: pointer to txrx handle + * @head_msdu: pointer to head msdu + * @tail_msdu: pointer to tail msdu + * + * Return: none + */ +static inline void ol_rx_timestamp_update(ol_txrx_pdev_handle pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + qdf_nbuf_t loop_msdu; + uint64_t hostime, detlahostime, tsf64_time; + struct htt_host_rx_desc_base *rx_desc; + + if (!ol_cfg_is_ptp_rx_opt_enabled(pdev->ctrl_pdev)) + return; + + if (!tail_msdu) + return; + + hostime = ktime_get_ns(); + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, tail_msdu); + if (rx_desc->ppdu_end.wb_timestamp_lower_32 == 0 && + rx_desc->ppdu_end.wb_timestamp_upper_32 == 0) { + detlahostime = hostime - pdev->last_host_time; + do_div(detlahostime, NSEC_PER_USEC); + tsf64_time = pdev->last_tsf64_time + detlahostime; + + rx_desc->ppdu_end.wb_timestamp_lower_32 = + tsf64_time & 0xFFFFFFFF; + rx_desc->ppdu_end.wb_timestamp_upper_32 = tsf64_time >> 32; + } else { + pdev->last_host_time = hostime; + pdev->last_tsf64_time = + (uint64_t)rx_desc->ppdu_end.wb_timestamp_upper_32 << 32 | + rx_desc->ppdu_end.wb_timestamp_lower_32; + } + + loop_msdu = head_msdu; + while (loop_msdu) { + ol_rx_timestamp(pdev->ctrl_pdev, rx_desc, loop_msdu); + loop_msdu = qdf_nbuf_next(loop_msdu); + } +} +#endif +#else +void ol_rx_timestamp(struct cdp_cfg *cfg_pdev, + void *rx_desc, qdf_nbuf_t msdu) +{ +} + +static inline void ol_rx_timestamp_update(ol_txrx_pdev_handle pdev, + qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ +} +#endif + +#ifdef WLAN_FEATURE_DSRC +static inline +void ol_rx_ocb_prepare_rx_stats_header(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu) +{ + int i; + struct ol_txrx_ocb_chan_info *chan_info = 0; + int packet_freq = peer->last_pkt_center_freq; + + for (i = 0; i < vdev->ocb_channel_count; i++) { + if (vdev->ocb_channel_info[i].chan_freq == packet_freq) { + chan_info = &vdev->ocb_channel_info[i]; + break; + } + } + + if (!chan_info || !chan_info->disable_rx_stats_hdr) { + qdf_ether_header_t eth_header = { {0} }; + struct ocb_rx_stats_hdr_t rx_header = {0}; + + /* + * Construct the RX stats header and + * push that to the frontof the packet. + */ + rx_header.version = 1; + rx_header.length = sizeof(rx_header); + rx_header.channel_freq = peer->last_pkt_center_freq; + rx_header.rssi_cmb = peer->last_pkt_rssi_cmb; + qdf_mem_copy(rx_header.rssi, peer->last_pkt_rssi, + sizeof(rx_header.rssi)); + + if (peer->last_pkt_legacy_rate_sel) + rx_header.datarate = 0xFF; + else if (peer->last_pkt_legacy_rate == 0x8) + rx_header.datarate = 6; + else if (peer->last_pkt_legacy_rate == 0x9) + rx_header.datarate = 4; + else if (peer->last_pkt_legacy_rate == 0xA) + rx_header.datarate = 2; + else if (peer->last_pkt_legacy_rate == 0xB) + rx_header.datarate = 0; + else if (peer->last_pkt_legacy_rate == 0xC) + rx_header.datarate = 7; + else if (peer->last_pkt_legacy_rate == 0xD) + rx_header.datarate = 5; + else if (peer->last_pkt_legacy_rate == 0xE) + rx_header.datarate = 3; + else if (peer->last_pkt_legacy_rate == 0xF) + rx_header.datarate = 1; + else + rx_header.datarate = 0xFF; + + rx_header.timestamp_microsec = + peer->last_pkt_timestamp_microsec; + rx_header.timestamp_submicrosec = + peer->last_pkt_timestamp_submicrosec; + rx_header.tsf32 = peer->last_pkt_tsf; + rx_header.ext_tid = peer->last_pkt_tid; + + qdf_nbuf_push_head(msdu, sizeof(rx_header)); + qdf_mem_copy(qdf_nbuf_data(msdu), + &rx_header, sizeof(rx_header)); + + /* + * Construct the ethernet header with + * type 0x8152 and push that to the + * front of the packet to indicate the + * RX stats header. + */ + eth_header.ether_type = QDF_SWAP_U16(ETHERTYPE_OCB_RX); + qdf_nbuf_push_head(msdu, sizeof(eth_header)); + qdf_mem_copy(qdf_nbuf_data(msdu), ð_header, + sizeof(eth_header)); + } +} +#else +static inline +void ol_rx_ocb_prepare_rx_stats_header(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu) +{ +} +#endif + +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t msdu_list) +{ + ol_txrx_pdev_handle pdev = vdev->pdev; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + qdf_nbuf_t deliver_list_head = NULL; + qdf_nbuf_t deliver_list_tail = NULL; + qdf_nbuf_t msdu; + bool filter = false; +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + struct ol_rx_decap_info_t info; + + qdf_mem_zero(&info, sizeof(info)); +#endif + + msdu = msdu_list; + /* + * Check each MSDU to see whether it requires special handling, + * and free each MSDU's rx descriptor + */ + while (msdu) { + void *rx_desc; + int discard, inspect, dummy_fwd; + qdf_nbuf_t next = qdf_nbuf_next(msdu); + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + /* for HL, point to payload right now*/ + if (pdev->cfg.is_high_latency) { + qdf_nbuf_pull_head(msdu, + htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc)); + } + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + info.is_msdu_cmpl_mpdu = + htt_rx_msdu_desc_completes_mpdu(htt_pdev, rx_desc); + info.is_first_subfrm = + htt_rx_msdu_first_msdu_flag(htt_pdev, rx_desc); + if (OL_RX_DECAP(vdev, peer, msdu, &info) != A_OK) { + discard = 1; + ol_txrx_dbg( + "decap error %pK from peer %pK ("QDF_MAC_ADDR_FMT") len %d\n", + msdu, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + qdf_nbuf_len(msdu)); + goto DONE; + } +#endif + htt_rx_msdu_actions(pdev->htt_pdev, rx_desc, &discard, + &dummy_fwd, &inspect); + if (inspect) + ol_rx_inspect(vdev, peer, tid, msdu, rx_desc); + + /* + * Check the first msdu in the mpdu, if it will be filtered out, + * then discard the entire mpdu. + */ + if (htt_rx_msdu_first_msdu_flag(htt_pdev, rx_desc)) + filter = ol_rx_filter(vdev, peer, msdu, rx_desc); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +DONE: +#endif + htt_rx_msdu_desc_free(htt_pdev, msdu); + if (discard || (true == filter)) { + ol_txrx_frms_dump("rx discarding:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | + ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + qdf_nbuf_free(msdu); + /* + * If discarding packet is last packet of the delivery + * list, NULL terminator should be added + * for delivery list. + */ + if (!next && deliver_list_head) { + /* add NULL terminator */ + qdf_nbuf_set_next(deliver_list_tail, NULL); + } + } else { + /* + * If this is for OCB, + * then prepend the RX stats header. + */ + if (vdev->opmode == wlan_op_mode_ocb) + ol_rx_ocb_prepare_rx_stats_header(vdev, peer, + msdu); + + OL_RX_PEER_STATS_UPDATE(peer, msdu); + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, + OL_RX_ERR_NONE); + TXRX_STATS_MSDU_INCR(vdev->pdev, rx.delivered, msdu); + + ol_rx_timestamp(pdev->ctrl_pdev, rx_desc, msdu); + OL_TXRX_LIST_APPEND(deliver_list_head, + deliver_list_tail, msdu); + QDF_NBUF_CB_DP_TRACE_PRINT(msdu) = false; + qdf_dp_trace_set_track(msdu, QDF_RX); + } + msdu = next; + } + /* sanity check - are there any frames left to give to the OS shim? */ + if (!deliver_list_head) + return; + + ol_txrx_frms_dump("rx delivering:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + + ol_rx_data_process(peer, deliver_list_head); +} +#endif + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t msdu_list) +{ + while (msdu_list) { + qdf_nbuf_t msdu = msdu_list; + + msdu_list = qdf_nbuf_next(msdu_list); + ol_txrx_dbg("discard rx %pK", msdu); + qdf_nbuf_free(msdu); + } +} + +void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer) +{ + uint8_t tid; + + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + ol_rx_reorder_init(&peer->tids_rx_reorder[tid], tid); + + /* invalid sequence number */ + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; + /* invalid reorder index number */ + peer->tids_next_rel_idx[tid] = INVALID_REORDER_INDEX; + + } + /* + * Set security defaults: no PN check, no security. + * The target may send a HTT SEC_IND message to overwrite + * these defaults. + */ + peer->security[txrx_sec_ucast].sec_type = + peer->security[txrx_sec_mcast].sec_type = htt_sec_type_none; + peer->keyinstalled = 0; + + peer->last_assoc_rcvd = 0; + peer->last_disassoc_rcvd = 0; + peer->last_deauth_rcvd = 0; + + qdf_atomic_init(&peer->fw_pn_check); +} + +void +ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer) +{ + peer->keyinstalled = 0; + peer->last_assoc_rcvd = 0; + peer->last_disassoc_rcvd = 0; + peer->last_deauth_rcvd = 0; + ol_rx_reorder_peer_cleanup(vdev, peer); +} + +/* + * Free frames including both rx descriptors and buffers + */ +void ol_rx_frames_free(htt_pdev_handle htt_pdev, qdf_nbuf_t frames) +{ + qdf_nbuf_t next, frag = frames; + + while (frag) { + next = qdf_nbuf_next(frag); + htt_rx_desc_frame_free(htt_pdev, frag); + frag = next; + } +} + +#ifdef WLAN_FULL_REORDER_OFFLOAD +void +ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_ind_msg, + uint16_t peer_id, + uint8_t tid, uint8_t is_offload) +{ + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer = NULL; + struct ol_txrx_peer_t *peer_head = NULL; + htt_pdev_handle htt_pdev = NULL; + int status; + qdf_nbuf_t head_msdu = NULL, tail_msdu = NULL; + uint8_t *rx_ind_data; + uint32_t *msg_word; + uint32_t msdu_count; + uint8_t pktlog_bit; + uint32_t filled = 0; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + bool offloaded_pkt; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (qdf_unlikely(!soc)) + return; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("invalid tid, %u", tid); + WARN_ON(1); + return; + } + + if (pdev) { + if (qdf_unlikely(QDF_GLOBAL_MONITOR_MODE == cds_get_conparam())) + peer = pdev->self_peer; + else + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + htt_pdev = pdev->htt_pdev; + } else { + ol_txrx_err("Invalid pdev passed!"); + qdf_assert_always(pdev); + return; + } + +#if defined(HELIUMPLUS_DEBUG) + qdf_print("rx_ind_msg 0x%pK peer_id %d tid %d is_offload %d", + rx_ind_msg, peer_id, tid, is_offload); +#endif + + pktlog_bit = (htt_rx_amsdu_rx_in_order_get_pktlog(rx_ind_msg) == 0x01); + rx_ind_data = qdf_nbuf_data(rx_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + /* Get the total number of MSDUs */ + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + 1)); + + ol_rx_ind_record_event(msdu_count, OL_RX_INDICATION_POP_START); + + /* + * Get a linked list of the MSDUs in the rx in order indication. + * This also attaches each rx MSDU descriptor to the + * corresponding rx MSDU network buffer. + */ + status = htt_rx_amsdu_pop(htt_pdev, rx_ind_msg, &head_msdu, + &tail_msdu, &msdu_count); + ol_rx_ind_record_event(status, OL_RX_INDICATION_POP_END); + + if (qdf_unlikely(0 == status)) { + ol_txrx_warn("pop failed"); + return; + } + + /* + * Replenish the rx buffer ring first to provide buffers to the target + * rather than waiting for the indeterminate time taken by the OS + * to consume the rx frames + */ + filled = htt_rx_msdu_buff_in_order_replenish(htt_pdev, msdu_count); + ol_rx_ind_record_event(filled, OL_RX_INDICATION_BUF_REPLENISH); + + if (!head_msdu) { + ol_txrx_dbg("No packet to send to HDD"); + return; + } + + /* Send the chain of MSDUs to the OS */ + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + + /* Packet Capture Mode */ + + if ((ucfg_pkt_capture_get_pktcap_mode((void *)soc->psoc) & + PKT_CAPTURE_MODE_DATA_ONLY)) { + offloaded_pkt = ucfg_pkt_capture_rx_offloaded_pkt(rx_ind_msg); + if (peer) { + vdev = peer->vdev; + if (peer->vdev) { + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + peer_head = TAILQ_FIRST(&vdev->peer_list); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + if (peer_head) { + qdf_spin_lock_bh( + &peer_head->peer_info_lock); + qdf_mem_copy(bssid, + &peer_head->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh( + &peer_head->peer_info_lock); + + ucfg_pkt_capture_rx_msdu_process( + bssid, head_msdu, + peer->vdev->vdev_id, + htt_pdev); + } + } + } else if (offloaded_pkt) { + ucfg_pkt_capture_rx_msdu_process( + bssid, head_msdu, + HTT_INVALID_VDEV, + htt_pdev); + + ucfg_pkt_capture_rx_drop_offload_pkt(head_msdu); + return; + } + } + + /* Pktlog */ + ol_rx_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit); + + /* + * if this is an offload indication, peer id is carried in the + * rx buffer + */ + if (peer) { + vdev = peer->vdev; + } else { + ol_txrx_dbg("Couldn't find peer from ID 0x%x", peer_id); + while (head_msdu) { + qdf_nbuf_t msdu = head_msdu; + + head_msdu = qdf_nbuf_next(head_msdu); + TXRX_STATS_MSDU_INCR(pdev, + rx.dropped_peer_invalid, msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + } + return; + } + + /*Loop msdu to fill tstamp with tsf64 time in ol_rx_timestamp*/ + ol_rx_timestamp_update(pdev, head_msdu, tail_msdu); + + peer->rx_opt_proc(vdev, peer, tid, head_msdu); +} +#endif + +#ifdef CONNECTIVITY_PKTLOG +/** + * ol_rx_pkt_dump_call() - updates status and + * calls packetdump callback to log rx packet + * + * @msdu: rx packet + * @peer_id: peer id + * @status: status of rx packet + * + * This function is used to update the status of rx packet + * and then calls packetdump callback to log that packet. + * + * Return: None + * + */ +void ol_rx_pkt_dump_call( + qdf_nbuf_t msdu, + uint8_t peer_id, + uint8_t status) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_soc_handle soc_hdl = ol_txrx_soc_t_to_cdp_soc_t(soc); + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_pktdump_cb packetdump_cb; + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + ol_txrx_dbg("peer with peer id %d is NULL", peer_id); + return; + } + + packetdump_cb = pdev->ol_rx_packetdump_cb; + if (packetdump_cb && + wlan_op_mode_sta == peer->vdev->opmode) + packetdump_cb(soc_hdl, OL_TXRX_PDEV_ID, peer->vdev->vdev_id, + msdu, status, QDF_RX_DATA_PKT); +} +#endif + +#ifdef WLAN_FULL_REORDER_OFFLOAD +/* the msdu_list passed here must be NULL terminated */ +void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu; + + msdu = msdu_list; + /* + * Currently, this does not check each MSDU to see whether it requires + * special handling. MSDUs that need special handling (example: IGMP + * frames) should be sent via a separate HTT message. Also, this does + * not do rx->tx forwarding or filtering. + */ + + while (msdu) { + qdf_nbuf_t next = qdf_nbuf_next(msdu); + + DPTRACE(qdf_dp_trace(msdu, + QDF_DP_TRACE_RX_TXRX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), QDF_RX)); + + OL_RX_PEER_STATS_UPDATE(peer, msdu); + OL_RX_ERR_STATISTICS_1(vdev->pdev, vdev, peer, rx_desc, + OL_RX_ERR_NONE); + TXRX_STATS_MSDU_INCR(vdev->pdev, rx.delivered, msdu); + + msdu = next; + } + + ol_txrx_frms_dump("rx delivering:", + pdev, deliver_list_head, + ol_txrx_frm_dump_tcp_seq | ol_txrx_frm_dump_contents, + 0 /* don't print contents */); + + ol_rx_data_process(peer, msdu_list); +} +#endif + +#ifndef CONFIG_HL_SUPPORT +void +ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, + uint32_t msdu_count, + uint32_t *msg_word) +{ + int vdev_id, peer_id, tid; + qdf_nbuf_t head_buf, tail_buf, buf; + struct ol_txrx_peer_t *peer; + uint8_t fw_desc; + int msdu_iter = 0; + + while (msdu_count) { + if (htt_rx_offload_paddr_msdu_pop_ll( + htt_pdev, msg_word, msdu_iter, + &vdev_id, &peer_id, &tid, + &fw_desc, &head_buf, + &tail_buf)) { + msdu_iter++; + msdu_count--; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "skip msg_word %pK, msdu #%d, continue next", + msg_word, msdu_iter); + continue; + } + + peer = ol_txrx_peer_find_by_id(htt_pdev->txrx_pdev, peer_id); + if (peer) { + QDF_NBUF_CB_DP_TRACE_PRINT(head_buf) = false; + qdf_dp_trace_set_track(head_buf, QDF_RX); + QDF_NBUF_CB_TX_PACKET_TRACK(head_buf) = + QDF_NBUF_TX_PKT_DATA_TRACK; + qdf_dp_trace_log_pkt(peer->vdev->vdev_id, + head_buf, QDF_RX, + QDF_TRACE_DEFAULT_PDEV_ID, + peer->vdev->qdf_opmode); + DPTRACE(qdf_dp_trace(head_buf, + QDF_DP_TRACE_RX_OFFLOAD_HTT_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(head_buf), + sizeof(qdf_nbuf_data(head_buf)), QDF_RX)); + ol_rx_data_process(peer, head_buf); + } else { + buf = head_buf; + while (1) { + qdf_nbuf_t next; + + next = qdf_nbuf_next(buf); + htt_rx_desc_frame_free(htt_pdev, buf); + if (buf == tail_buf) + break; + buf = next; + } + } + msdu_iter++; + msdu_count--; + } + htt_rx_msdu_buff_replenish(htt_pdev); +} +#endif + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * ol_htt_mon_note_chan() - Update monitor channel information + * @pdev: handle to the physical device + * @mon_ch: Monitor channel + * + * Return: None + */ +void ol_htt_mon_note_chan(struct cdp_pdev *ppdev, int mon_ch) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + htt_rx_mon_note_capture_channel(pdev->htt_pdev, mon_ch); +} +#endif + +#ifdef NEVERDEFINED +/** + * @brief populates vow ext stats in given network buffer. + * @param msdu - network buffer handle + * @param pdev - handle to htt dev. + */ +void ol_ath_add_vow_extstats(htt_pdev_handle pdev, qdf_nbuf_t msdu) +{ + /* FIX THIS: + * txrx should not be directly using data types (scn) + * that are internal to other modules. + */ + struct ol_ath_softc_net80211 *scn = + (struct ol_ath_softc_net80211 *)pdev->ctrl_pdev; + uint8_t *data, *l3_hdr, *bp; + uint16_t ethertype; + int offset; + struct vow_extstats vowstats; + + if (scn->vow_extstats == 0) + return; + + data = qdf_nbuf_data(msdu); + + offset = QDF_MAC_ADDR_SIZE * 2; + l3_hdr = data + ETHERNET_HDR_LEN; + ethertype = (data[offset] << 8) | data[offset + 1]; + if (ethertype == ETHERTYPE_IPV4) { + offset = IPV4_HDR_OFFSET_PROTOCOL; + if ((l3_hdr[offset] == IP_PROTOCOL_UDP) && + (l3_hdr[0] == IP_VER4_N_NO_EXTRA_HEADERS)) { + bp = data + EXT_HDR_OFFSET; + + if ((data[RTP_HDR_OFFSET] == UDP_PDU_RTP_EXT) && + (bp[0] == 0x12) && + (bp[1] == 0x34) && + (bp[2] == 0x00) && (bp[3] == 0x08)) { + /* + * Clear UDP checksum so we do not have + * to recalculate it + * after filling in status fields. + */ + data[UDP_CKSUM_OFFSET] = 0; + data[(UDP_CKSUM_OFFSET + 1)] = 0; + + bp += IPERF3_DATA_OFFSET; + + htt_rx_get_vowext_stats(msdu, + &vowstats); + + /* control channel RSSI */ + *bp++ = vowstats.rx_rssi_ctl0; + *bp++ = vowstats.rx_rssi_ctl1; + *bp++ = vowstats.rx_rssi_ctl2; + + /* rx rate info */ + *bp++ = vowstats.rx_bw; + *bp++ = vowstats.rx_sgi; + *bp++ = vowstats.rx_nss; + + *bp++ = vowstats.rx_rssi_comb; + /* rsflags */ + *bp++ = vowstats.rx_rs_flags; + + /* Time stamp Lo */ + *bp++ = (uint8_t) + ((vowstats. + rx_macTs & 0x0000ff00) >> 8); + *bp++ = (uint8_t) + (vowstats.rx_macTs & 0x0000ff); + /* rx phy errors */ + *bp++ = (uint8_t) + ((scn->chan_stats. + phy_err_cnt >> 8) & 0xff); + *bp++ = + (uint8_t) (scn->chan_stats. + phy_err_cnt & 0xff); + /* rx clear count */ + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 24) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 16) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + rx_clear_count >> 8) & 0xff); + *bp++ = (uint8_t) + (scn->mib_cycle_cnts. + rx_clear_count & 0xff); + /* rx cycle count */ + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 24) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 16) & 0xff); + *bp++ = (uint8_t) + ((scn->mib_cycle_cnts. + cycle_count >> 8) & 0xff); + *bp++ = (uint8_t) + (scn->mib_cycle_cnts. + cycle_count & 0xff); + + *bp++ = vowstats.rx_ratecode; + *bp++ = vowstats.rx_moreaggr; + + /* sequence number */ + *bp++ = (uint8_t) + ((vowstats.rx_seqno >> 8) & + 0xff); + *bp++ = (uint8_t) + (vowstats.rx_seqno & 0xff); + } + } + } +} + +#endif + +#ifdef WLAN_CFR_ENABLE +void ol_rx_cfr_capture_msg_handler(qdf_nbuf_t htt_t2h_msg) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + HTT_PEER_CFR_CAPTURE_MSG_TYPE cfr_type; + struct htt_cfr_dump_compl_ind *cfr_dump; + struct htt_cfr_dump_ind_type_1 cfr_ind; + struct csi_cfr_header cfr_hdr = {}; + uint32_t mem_index, req_id, vdev_id; + uint32_t *msg_word; + uint8_t *mac_addr; + + msg_word = (uint32_t *)qdf_nbuf_data(htt_t2h_msg); + + /* First payload word */ + msg_word++; + cfr_dump = (struct htt_cfr_dump_compl_ind *)msg_word; + cfr_type = cfr_dump->msg_type; + if (cfr_type != HTT_PEER_CFR_CAPTURE_MSG_TYPE_1) { + ol_txrx_err("Unsupported cfr msg type 0x%x", cfr_type); + return; + } + + /* Second payload word */ + msg_word++; + req_id = HTT_T2H_CFR_DUMP_TYPE1_MEM_REQ_ID_GET(*msg_word); + if (req_id != CFR_CAPTURE_HOST_MEM_REQ_ID) { + ol_txrx_err("Invalid req id in cfr capture msg"); + return; + } + cfr_hdr.start_magic_num = 0xDEADBEAF; + cfr_hdr.u.meta_v1.status = HTT_T2H_CFR_DUMP_TYPE1_STATUS_GET( + *msg_word); + cfr_hdr.u.meta_v1.capture_bw = HTT_T2H_CFR_DUMP_TYPE1_CAP_BW_GET( + *msg_word); + cfr_hdr.u.meta_v1.capture_mode = HTT_T2H_CFR_DUMP_TYPE1_MODE_GET( + *msg_word); + cfr_hdr.u.meta_v1.sts_count = HTT_T2H_CFR_DUMP_TYPE1_STS_GET( + *msg_word); + cfr_hdr.u.meta_v1.channel_bw = HTT_T2H_CFR_DUMP_TYPE1_CHAN_BW_GET( + *msg_word); + cfr_hdr.u.meta_v1.capture_type = HTT_T2H_CFR_DUMP_TYPE1_CAP_TYPE_GET( + *msg_word); + + vdev_id = HTT_T2H_CFR_DUMP_TYPE1_VDEV_ID_GET(*msg_word); + + mac_addr = (uint8_t *)(msg_word + 1); + qdf_mem_copy(cfr_hdr.u.meta_v1.peer_addr, mac_addr, QDF_MAC_ADDR_SIZE); + + cfr_ind = cfr_dump->htt_cfr_dump_compl_ind_type_1; + + cfr_hdr.u.meta_v1.prim20_chan = cfr_ind.chan.chan_mhz; + cfr_hdr.u.meta_v1.center_freq1 = cfr_ind.chan.band_center_freq1; + cfr_hdr.u.meta_v1.center_freq2 = cfr_ind.chan.band_center_freq2; + cfr_hdr.u.meta_v1.phy_mode = cfr_ind.chan.chan_mode; + cfr_hdr.u.meta_v1.length = cfr_ind.length; + cfr_hdr.u.meta_v1.timestamp = cfr_ind.timestamp; + + mem_index = cfr_ind.index; + + ucfg_cfr_capture_data((void *)soc->psoc, vdev_id, &cfr_hdr, mem_index); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx.h new file mode 100644 index 0000000000..17c1101138 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx.h @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2011, 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_RX__H_ +#define _OL_RX__H_ + +#include /* qdf_nbuf_t */ +#include /* htt_pdev_handle */ +#include /* ol_txrx_vdev_t */ + +#ifdef WLAN_PARTIAL_REORDER_OFFLOAD +void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t head_msdu); +#else +static inline void +ol_rx_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t head_msdu) +{ +} +#endif + +void +ol_rx_discard(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t head_msdu); + +/** + * ol_rx_send_mic_err_ind() - ol rx mic err handler + * @pdev: ol pdev + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * @tid: TID + * @tsf32: TSF + * @err_type: error type + * @rx_frame: rx frame + * @pn: PN Number + * @key_id: key id + * + * This function handles rx error and send MIC error failure to HDD + * + * Return: none + */ +void +ol_rx_send_mic_err_ind(struct ol_txrx_pdev_t *pdev, uint8_t vdev_id, + uint8_t *peer_mac_addr, int tid, uint32_t tsf32, + enum ol_rx_err_type err_type, qdf_nbuf_t rx_frame, + uint64_t *pn, uint8_t key_id); + +void ol_rx_frames_free(htt_pdev_handle htt_pdev, qdf_nbuf_t frames); + +void ol_rx_peer_init(struct ol_txrx_pdev_t *pdev, struct ol_txrx_peer_t *peer); + +void +ol_rx_peer_cleanup(struct ol_txrx_vdev_t *vdev, struct ol_txrx_peer_t *peer); + +#ifdef WDI_EVENT_ENABLE +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, + uint8_t pktlog_bit); +#else +static inline +void ol_rx_send_pktlog_event(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, qdf_nbuf_t msdu, + uint8_t pktlog_bit) +{ +} +#endif + +#ifdef WLAN_FULL_REORDER_OFFLOAD +void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t head_msdu); +#else +static inline void +ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t head_msdu) +{ +} +#endif + +void ol_rx_log_packet(htt_pdev_handle htt_pdev, + uint8_t peer_id, qdf_nbuf_t msdu); +void +ol_rx_offload_paddr_deliver_ind_handler(htt_pdev_handle htt_pdev, + uint32_t msdu_count, + uint32_t *msg_word); +void ol_rx_update_histogram_stats(uint32_t msdu_count, + uint8_t frag_ind, uint8_t offload_ind); + +void +ol_rx_mic_error_handler( + ol_txrx_pdev_handle pdev, + u_int8_t tid, + u_int16_t peer_id, + void *msdu_desc, + qdf_nbuf_t msdu); + +void htt_rx_fill_ring_count(htt_pdev_handle pdev); + +void ol_rx_timestamp(struct cdp_cfg *cfg_pdev, void *rx_desc, qdf_nbuf_t msdu); + +#endif /* _OL_RX__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c new file mode 100644 index 0000000000..afa85d4872 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_defrag.c @@ -0,0 +1,1446 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*- + * Copyright (c) 2002-2007 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* qdf_system_time */ +#include + +#define DEFRAG_IEEE80211_ADDR_EQ(a1, a2) \ + (!qdf_mem_cmp(a1, a2, QDF_MAC_ADDR_SIZE)) + +#define DEFRAG_IEEE80211_ADDR_COPY(dst, src) \ + qdf_mem_copy(dst, src, QDF_MAC_ADDR_SIZE) + +#define DEFRAG_IEEE80211_QOS_HAS_SEQ(wh) \ + (((wh)->i_fc[0] & \ + (IEEE80211_FC0_TYPE_MASK | QDF_IEEE80211_FC0_SUBTYPE_QOS)) == \ + (IEEE80211_FC0_TYPE_DATA | QDF_IEEE80211_FC0_SUBTYPE_QOS)) + +#define DEFRAG_IEEE80211_QOS_GET_TID(_x) \ + ((_x)->i_qos[0] & IEEE80211_QOS_TID) + +const struct ol_rx_defrag_cipher f_ccmp = { + "AES-CCM", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, + IEEE80211_WEP_MICLEN, + 0, +}; + +const struct ol_rx_defrag_cipher f_tkip = { + "TKIP", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN + IEEE80211_WEP_EXTIVLEN, + IEEE80211_WEP_CRCLEN, + IEEE80211_WEP_MICLEN, +}; + +const struct ol_rx_defrag_cipher f_wep = { + "WEP", + IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN, + IEEE80211_WEP_CRCLEN, + 0, +}; + +const struct ol_rx_defrag_cipher f_gcmp = { + "AES-GCMP", + WLAN_IEEE80211_GCMP_HEADERLEN, + WLAN_IEEE80211_GCMP_MICLEN, + WLAN_IEEE80211_GCMP_MICLEN, +}; + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_rx_frag_get_mac_hdr() - retrieve mac header + * @htt_pdev: pointer to htt pdev handle + * @frag: rx fragment + * + * Return: pointer to ieee mac header of frag + */ +static struct ieee80211_frame *ol_rx_frag_get_mac_hdr( + htt_pdev_handle htt_pdev, qdf_nbuf_t frag) +{ + void *rx_desc; + int rx_desc_len; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc); + return (struct ieee80211_frame *)(qdf_nbuf_data(frag) + rx_desc_len); +} + +/** + * ol_rx_frag_pull_hdr() - point to payload of rx frag + * @htt_pdev: pointer to htt pdev handle + * @frag: rx fragment + * @hdrsize: header size + * + * Return: None + */ +static void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag, int hdrsize) +{ + void *rx_desc; + int rx_desc_len; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, rx_desc); + qdf_nbuf_pull_head(frag, rx_desc_len + hdrsize); +} + +/** + * ol_rx_frag_desc_adjust() - adjust rx frag descriptor position + * @pdev: pointer to txrx handle + * @msdu: msdu + * @rx_desc_old_position: rx descriptor old position + * @ind_old_position:index of old position + * @rx_desc_len: rx descriptor length + * + * Return: None + */ +static void +ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void **rx_desc_old_position, + void **ind_old_position, int *rx_desc_len) +{ + *rx_desc_old_position = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, + msdu); + *ind_old_position = *rx_desc_old_position - HTT_RX_IND_HL_BYTES; + *rx_desc_len = htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev, + *rx_desc_old_position); +} + +/** + * ol_rx_frag_restructure() - point to payload for HL + * @pdev: physical device object + * @msdu: the buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * @ind_old_position: rx msdu indication + * @f_type: pointing to rx defrag cipher + * @rx_desc_len: length by which rx descriptor to move + * + * Return: None + */ +static void +ol_rx_frag_restructure( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void *rx_desc_old_position, + void *ind_old_position, + const struct ol_rx_defrag_cipher *f_type, + int rx_desc_len) +{ + if ((!ind_old_position) || (!rx_desc_old_position)) { + ol_txrx_err("ind_old_position,rx_desc_old_position is NULL"); + ASSERT(0); + return; + } + /* move rx description*/ + qdf_mem_move(rx_desc_old_position + f_type->ic_header, + rx_desc_old_position, rx_desc_len); + /* move rx indication*/ + qdf_mem_move(ind_old_position + f_type->ic_header, ind_old_position, + HTT_RX_IND_HL_BYTES); +} + +/** + * ol_rx_get_desc_len() - point to payload for HL + * @htt_pdev: the HTT instance the rx data was received on + * @wbuf: buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * + * Return: Return the HL rx desc size + */ +static +int ol_rx_get_desc_len(htt_pdev_handle htt_pdev, + qdf_nbuf_t wbuf, + void **rx_desc_old_position) +{ + int rx_desc_len = 0; + *rx_desc_old_position = htt_rx_msdu_desc_retrieve(htt_pdev, wbuf); + rx_desc_len = htt_rx_msdu_rx_desc_size_hl(htt_pdev, + *rx_desc_old_position); + + return rx_desc_len; +} + +/** + * ol_rx_defrag_push_rx_desc() - point to payload for HL + * @nbuf: buffer containing the MSDU payload + * @rx_desc_old_position: rx MSDU descriptor + * @ind_old_position: rx msdu indication + * @rx_desc_len: HL rx desc size + * + * Return: Return the HL rx desc size + */ +static +void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf, + void *rx_desc_old_position, + void *ind_old_position, + int rx_desc_len) +{ + qdf_nbuf_push_head(nbuf, rx_desc_len); + qdf_mem_move( + qdf_nbuf_data(nbuf), rx_desc_old_position, rx_desc_len); + qdf_mem_move( + qdf_nbuf_data(nbuf) - HTT_RX_IND_HL_BYTES, ind_old_position, + HTT_RX_IND_HL_BYTES); +} +#else + +static inline struct ieee80211_frame *ol_rx_frag_get_mac_hdr( + htt_pdev_handle htt_pdev, + qdf_nbuf_t frag) +{ + return + (struct ieee80211_frame *) qdf_nbuf_data(frag); +} + +static inline void ol_rx_frag_pull_hdr(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag, int hdrsize) +{ + qdf_nbuf_pull_head(frag, hdrsize); +} + +static inline void +ol_rx_frag_desc_adjust(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void **rx_desc_old_position, + void **ind_old_position, int *rx_desc_len) +{ + *rx_desc_old_position = NULL; + *ind_old_position = NULL; + *rx_desc_len = 0; +} + +static inline void +ol_rx_frag_restructure( + ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, + void *rx_desc_old_position, + void *ind_old_position, + const struct ol_rx_defrag_cipher *f_type, + int rx_desc_len) +{ + /* no op */ +} + +static inline +int ol_rx_get_desc_len(htt_pdev_handle htt_pdev, + qdf_nbuf_t wbuf, + void **rx_desc_old_position) +{ + return 0; +} + +static inline +void ol_rx_defrag_push_rx_desc(qdf_nbuf_t nbuf, + void *rx_desc_old_position, + void *ind_old_position, + int rx_desc_len) +{ + return; +} +#endif /* CONFIG_HL_SUPPORT */ + +/* + * Process incoming fragments + */ +void +ol_rx_frag_indication_handler(ol_txrx_pdev_handle pdev, + qdf_nbuf_t rx_frag_ind_msg, + uint16_t peer_id, uint8_t tid) +{ + uint16_t seq_num; + uint16_t seq_num_start, seq_num_end; + struct ol_txrx_peer_t *peer; + htt_pdev_handle htt_pdev; + qdf_nbuf_t head_msdu, tail_msdu; + void *rx_mpdu_desc; + uint8_t pktlog_bit; + uint32_t msdu_count = 0; + int ret; + void *rx_desc; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("Invalid tid: %u", tid); + return; + } + + htt_pdev = pdev->htt_pdev; + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + + if (!ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) && + htt_rx_ind_flush(pdev->htt_pdev, rx_frag_ind_msg) && peer) { + htt_rx_frag_ind_flush_seq_num_range(pdev->htt_pdev, + rx_frag_ind_msg, + &seq_num_start, + &seq_num_end); + /* + * Assuming flush indication for frags sent from target is + * separate from normal frames + */ + ol_rx_reorder_flush_frag(htt_pdev, peer, tid, seq_num_start); + } else { + uint32_t *msg_word; + uint8_t *rx_ind_data; + + rx_ind_data = qdf_nbuf_data(rx_frag_ind_msg); + msg_word = (uint32_t *)rx_ind_data; + msdu_count = HTT_RX_IN_ORD_PADDR_IND_MSDU_CNT_GET(*(msg_word + + 1)); + } + + pktlog_bit = + (htt_rx_amsdu_rx_in_order_get_pktlog(rx_frag_ind_msg) == 0x01); + ret = htt_rx_frag_pop(htt_pdev, rx_frag_ind_msg, &head_msdu, + &tail_msdu, &msdu_count); + /* Return if msdu pop fails from rx hash table, as recovery + * is triggered and we exit gracefully. + */ + if (!ret) + return; + if (peer) { + qdf_assert(head_msdu == tail_msdu); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, head_msdu); + } else { + rx_mpdu_desc = + htt_rx_mpdu_desc_list_next(htt_pdev, + rx_frag_ind_msg); + } + seq_num = htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_mpdu_desc, true); + OL_RX_ERR_STATISTICS_1(pdev, peer->vdev, peer, rx_mpdu_desc, + OL_RX_ERR_NONE_FRAG); + ol_rx_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit); + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, head_msdu); + ol_rx_timestamp(pdev->ctrl_pdev, rx_desc, head_msdu); + ol_rx_reorder_store_frag(pdev, peer, tid, seq_num, head_msdu); + } else { + /* invalid frame - discard it */ + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) + htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu); + else + htt_rx_mpdu_desc_list_next(htt_pdev, rx_frag_ind_msg); + + ol_rx_send_pktlog_event(pdev, peer, head_msdu, pktlog_bit); + htt_rx_desc_frame_free(htt_pdev, head_msdu); + } + /* request HTT to provide new rx MSDU buffers for the target to fill. */ + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev) && + !pdev->cfg.is_high_latency) + htt_rx_msdu_buff_in_order_replenish(htt_pdev, msdu_count); + else + htt_rx_msdu_buff_replenish(htt_pdev); +} + +/* + * Flushing fragments + */ +void +ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, uint16_t seq_num) +{ + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + int seq; + + seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq]; + if (rx_reorder_array_elem->head) { + ol_rx_frames_free(htt_pdev, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } +} + +/* + * Reorder and store fragments + */ +void +ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, uint16_t seq_num, qdf_nbuf_t frag) +{ + struct ieee80211_frame *fmac_hdr, *mac_hdr; + uint8_t fragno, more_frag, all_frag_present = 0; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + uint16_t frxseq, rxseq, seq; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + void *rx_desc; + uint8_t index; + + seq = seq_num & peer->tids_rx_reorder[tid].win_sz_mask; + qdf_assert(seq == 0); + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[seq]; + + mac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, frag); + rxseq = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + fragno = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + more_frag = mac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag); + qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + /* + * Multicast/Broadcast frames should not be fragmented so drop + * such frames. + */ + if (index != txrx_sec_ucast) { + ol_rx_frames_free(htt_pdev, frag); + return; + } + + if (peer->security[index].sec_type != htt_sec_type_none && + !htt_rx_mpdu_is_encrypted(htt_pdev, rx_desc)) { + ol_txrx_err("Unencrypted fragment received in security mode %d", + peer->security[index].sec_type); + ol_rx_frames_free(htt_pdev, frag); + return; + } + + if ((!more_frag) && (!fragno) && (!rx_reorder_array_elem->head)) { + rx_reorder_array_elem->head = frag; + rx_reorder_array_elem->tail = frag; + qdf_nbuf_set_next(frag, NULL); + ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + return; + } + if (rx_reorder_array_elem->head) { + fmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, + rx_reorder_array_elem->head); + frxseq = qdf_le16_to_cpu(*(uint16_t *) fmac_hdr->i_seq) >> + IEEE80211_SEQ_SEQ_SHIFT; + if (rxseq != frxseq + || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr1, + fmac_hdr->i_addr1) + || !DEFRAG_IEEE80211_ADDR_EQ(mac_hdr->i_addr2, + fmac_hdr->i_addr2)) { + ol_rx_frames_free(htt_pdev, + rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + ol_txrx_err("ol_rx_reorder_store:%s mismatch", + (rxseq == frxseq) + ? "address" + : "seq number"); + } + } + + ol_rx_fraglist_insert(htt_pdev, &rx_reorder_array_elem->head, + &rx_reorder_array_elem->tail, frag, + &all_frag_present); + + if (pdev->rx.flags.defrag_timeout_check) + ol_rx_defrag_waitlist_remove(peer, tid); + + if (all_frag_present) { + ol_rx_defrag(pdev, peer, tid, rx_reorder_array_elem->head); + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + peer->tids_rx_reorder[tid].defrag_timeout_ms = 0; + peer->tids_last_seq[tid] = seq_num; + } else if (pdev->rx.flags.defrag_timeout_check) { + uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + peer->tids_rx_reorder[tid].defrag_timeout_ms = + now_ms + pdev->rx.defrag.timeout_ms; + ol_rx_defrag_waitlist_add(peer, tid); + } +} + +/* + * Insert and store fragments + */ +void +ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, + qdf_nbuf_t *head_addr, + qdf_nbuf_t *tail_addr, + qdf_nbuf_t frag, uint8_t *all_frag_present) +{ + qdf_nbuf_t next, prev = NULL, cur = *head_addr; + struct ieee80211_frame *mac_hdr, *cmac_hdr, *next_hdr, *lmac_hdr; + uint8_t fragno, cur_fragno, lfragno, next_fragno; + uint8_t last_morefrag = 1, count = 0; + + qdf_assert(frag); + + mac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, frag); + fragno = qdf_le16_to_cpu(*(uint16_t *) mac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + + if (!(*head_addr)) { + *head_addr = frag; + *tail_addr = frag; + qdf_nbuf_set_next(*tail_addr, NULL); + return; + } + /* For efficiency, compare with tail first */ + lmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, *tail_addr); + lfragno = qdf_le16_to_cpu(*(uint16_t *) lmac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + if (fragno > lfragno) { + qdf_nbuf_set_next(*tail_addr, frag); + *tail_addr = frag; + qdf_nbuf_set_next(*tail_addr, NULL); + } else { + do { + cmac_hdr = (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, cur); + cur_fragno = + qdf_le16_to_cpu(*(uint16_t *) cmac_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + prev = cur; + cur = qdf_nbuf_next(cur); + } while (fragno > cur_fragno); + + if (fragno == cur_fragno) { + htt_rx_desc_frame_free(htt_pdev, frag); + *all_frag_present = 0; + return; + } + + qdf_nbuf_set_next(prev, frag); + qdf_nbuf_set_next(frag, cur); + } + next = qdf_nbuf_next(*head_addr); + lmac_hdr = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, + *tail_addr); + last_morefrag = lmac_hdr->i_fc[1] & IEEE80211_FC1_MORE_FRAG; + if (!last_morefrag) { + do { + next_hdr = + (struct ieee80211_frame *) + ol_rx_frag_get_mac_hdr(htt_pdev, next); + next_fragno = + qdf_le16_to_cpu(*(uint16_t *) next_hdr->i_seq) & + IEEE80211_SEQ_FRAG_MASK; + count++; + if (next_fragno != count) + break; + + next = qdf_nbuf_next(next); + } while (next); + + if (!next) { + *all_frag_present = 1; + return; + } + } + *all_frag_present = 0; +} + +/* + * add tid to pending fragment wait list + */ +void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned int tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid]; + + TAILQ_INSERT_TAIL(&pdev->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); +} + +/* + * remove tid from pending fragment wait list + */ +void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, unsigned int tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + struct ol_rx_reorder_t *rx_reorder = &peer->tids_rx_reorder[tid]; + + if (rx_reorder->defrag_waitlist_elem.tqe_next) { + + TAILQ_REMOVE(&pdev->rx.defrag.waitlist, rx_reorder, + defrag_waitlist_elem); + + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; + } else if (rx_reorder->defrag_waitlist_elem.tqe_next) { + ol_txrx_alert("waitlist->tqe_prv = NULL"); + QDF_ASSERT(0); + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + } +} + +#ifndef container_of +#define container_of(ptr, type, member) \ + ((type *)((char *)(ptr) - (char *)(&((type *)0)->member))) +#endif + +/* + * flush stale fragments from the waitlist + */ +void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev) +{ + struct ol_rx_reorder_t *rx_reorder, *tmp; + uint32_t now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + TAILQ_FOREACH_SAFE(rx_reorder, &pdev->rx.defrag.waitlist, + defrag_waitlist_elem, tmp) { + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder_base; + unsigned int tid; + + if (rx_reorder->defrag_timeout_ms > now_ms) + break; + + tid = rx_reorder->tid; + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("Invalid tid: %u", tid); + WARN_ON(1); + continue; + } + /* get index 0 of the rx_reorder array */ + rx_reorder_base = rx_reorder - tid; + peer = + container_of(rx_reorder_base, struct ol_txrx_peer_t, + tids_rx_reorder[0]); + + ol_rx_defrag_waitlist_remove(peer, tid); + ol_rx_reorder_flush_frag(pdev->htt_pdev, peer, tid, + 0 /* frags always stored at seq 0 */); + } +} + +/** + * ol_rx_frag_gcmp_decap() - Remove GCMP header from fragment + * @pdev : data path pdev handle + * @nbuf : network buffer + * @hdrlen : MAC header len + * + * Return: OL_RX_DEFRAG_OK on success else failure code + */ +static int +ol_rx_frag_gcmp_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *orig_hdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + orig_hdr = (uint8_t *)(qdf_nbuf_data(nbuf) + rx_desc_len); + ivp = orig_hdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_mem_move(orig_hdr + f_gcmp.ic_header, orig_hdr, hdrlen); + ol_rx_frag_restructure( + pdev, + nbuf, + rx_desc_old_position, + ind_old_position, + &f_gcmp, + rx_desc_len); + qdf_nbuf_pull_head(nbuf, f_gcmp.ic_header); + + return OL_RX_DEFRAG_OK; +} + +/** + * ol_rx_frag_gcmp_demic() - Remove MIC info from GCMP fragment + * @pdev : data path pdev handle + * @nbuf : network buffer + * @hdrlen : MAC header len + * + * Return: OL_RX_DEFRAG_OK on success else failure code + */ +static int +ol_rx_frag_gcmp_demic(ol_txrx_pdev_handle pdev, + qdf_nbuf_t wbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *orig_hdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + orig_hdr = (uint8_t *)(qdf_nbuf_data(wbuf) + rx_desc_len); + + ivp = orig_hdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_nbuf_trim_tail(wbuf, f_gcmp.ic_trailer); + + return OL_RX_DEFRAG_OK; +} + +/* + * Handling security checking and processing fragments + */ +void +ol_rx_defrag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t frag_list) +{ + struct ol_txrx_vdev_t *vdev = NULL; + qdf_nbuf_t tmp_next, msdu, prev = NULL, cur = frag_list; + uint8_t index, tkip_demic = 0; + uint16_t hdr_space; + void *rx_desc; + struct ieee80211_frame *wh; + uint8_t key[DEFRAG_IEEE80211_KEY_LEN]; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + struct ol_txrx_peer_t *peer_head = NULL; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (qdf_unlikely(!soc)) + return; + + vdev = peer->vdev; + + /* bypass defrag for safe mode */ + if (vdev->safemode) { + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) + ol_rx_in_order_deliver(vdev, peer, tid, frag_list); + else + ol_rx_deliver(vdev, peer, tid, frag_list); + return; + } + + while (cur) { + tmp_next = qdf_nbuf_next(cur); + qdf_nbuf_set_next(cur, NULL); + /* + * Strict PN check between the first fragment of the current + * frame and the last fragment of the previous frame is not + * necessary. + */ + if (!ol_rx_pn_check_base(vdev, peer, tid, cur, + (cur == frag_list) ? false : true)) { + /* PN check failed,discard frags */ + if (prev) { + qdf_nbuf_set_next(prev, NULL); + ol_rx_frames_free(htt_pdev, frag_list); + } + ol_rx_frames_free(htt_pdev, tmp_next); + ol_txrx_err("PN Check failed"); + return; + } + /* remove FCS from each fragment */ + qdf_nbuf_trim_tail(cur, DEFRAG_IEEE80211_FCS_LEN); + prev = cur; + qdf_nbuf_set_next(cur, tmp_next); + cur = tmp_next; + } + cur = frag_list; + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, cur); + hdr_space = ol_rx_frag_hdrsize(wh); + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, frag_list); + qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + + switch (peer->security[index].sec_type) { + case htt_sec_type_tkip: + tkip_demic = 1; + fallthrough; + /* fall-through to rest of tkip ops */ + case htt_sec_type_tkip_nomic: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_tkip_decap(pdev, cur, hdr_space)) { + /* TKIP decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + ol_txrx_err("TKIP decap failed"); + return; + } + cur = tmp_next; + } + break; + + case htt_sec_type_aes_ccmp: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_ccmp_demic(pdev, cur, hdr_space)) { + /* CCMP demic failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + ol_txrx_err("CCMP demic failed"); + return; + } + if (!ol_rx_frag_ccmp_decap(pdev, cur, hdr_space)) { + /* CCMP decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + ol_txrx_err("CCMP decap failed"); + return; + } + cur = tmp_next; + } + break; + + case htt_sec_type_wep40: + case htt_sec_type_wep104: + case htt_sec_type_wep128: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_wep_decap(pdev, cur, hdr_space)) { + /* wep decap failed, discard frags */ + ol_rx_frames_free(htt_pdev, frag_list); + ol_txrx_err("wep decap failed"); + return; + } + cur = tmp_next; + } + break; + case htt_sec_type_aes_gcmp: + case htt_sec_type_aes_gcmp_256: + while (cur) { + tmp_next = qdf_nbuf_next(cur); + if (!ol_rx_frag_gcmp_demic(pdev, cur, hdr_space)) { + ol_rx_frames_free(htt_pdev, frag_list); + ol_txrx_err("GCMP demic failed"); + return; + } + if (!ol_rx_frag_gcmp_decap(pdev, cur, hdr_space)) { + ol_rx_frames_free(htt_pdev, frag_list); + ol_txrx_err("GCMP decap failed"); + return; + } + cur = tmp_next; + } + + break; + default: + break; + } + + msdu = ol_rx_defrag_decap_recombine(htt_pdev, frag_list, hdr_space); + if (!msdu) + return; + + if (tkip_demic) { + qdf_mem_copy(key, + peer->security[index].michael_key, + sizeof(peer->security[index].michael_key)); + if (!ol_rx_frag_tkip_demic(pdev, key, msdu, hdr_space)) { + uint64_t pn = 0; + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, 0, + OL_RX_ERR_TKIP_MIC, msdu, &pn, 0); + htt_rx_desc_frame_free(htt_pdev, msdu); + ol_txrx_err("TKIP demic failed"); + return; + } + } + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, msdu); + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) + ol_rx_defrag_qos_decap(pdev, msdu, hdr_space); + if (ol_cfg_frame_type(pdev->ctrl_pdev) == wlan_frm_fmt_802_3) + ol_rx_defrag_nwifi_to_8023(pdev, msdu); + + /* Packet Capture Mode */ + + if ((ucfg_pkt_capture_get_pktcap_mode((void *)soc->psoc) & + PKT_CAPTURE_MODE_DATA_ONLY)) { + if (peer) { + if (peer->vdev) { + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + peer_head = TAILQ_FIRST(&vdev->peer_list); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + if (peer_head) { + qdf_spin_lock_bh( + &peer_head->peer_info_lock); + qdf_mem_copy(bssid, + &peer_head->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh( + &peer_head->peer_info_lock); + + ucfg_pkt_capture_rx_msdu_process( + bssid, msdu, + vdev->vdev_id, + htt_pdev); + } + } + } + } + + ol_rx_fwd_check(vdev, peer, tid, msdu); +} + +/* + * Handling TKIP processing for defragmentation + */ +int +ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + /* Header should have extended IV */ + origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len); + + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_mem_move(origHdr + f_tkip.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + msdu, + rx_desc_old_position, + ind_old_position, + &f_tkip, + rx_desc_len); + qdf_nbuf_pull_head(msdu, f_tkip.ic_header); + qdf_nbuf_trim_tail(msdu, f_tkip.ic_trailer); + return OL_RX_DEFRAG_OK; +} + +/* + * Handling WEP processing for defragmentation + */ +int +ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu, uint16_t hdrlen) +{ + uint8_t *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + origHdr = (uint8_t *) (qdf_nbuf_data(msdu) + rx_desc_len); + qdf_mem_move(origHdr + f_wep.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + msdu, + rx_desc_old_position, + ind_old_position, + &f_wep, + rx_desc_len); + qdf_nbuf_pull_head(msdu, f_wep.ic_header); + qdf_nbuf_trim_tail(msdu, f_wep.ic_trailer); + return OL_RX_DEFRAG_OK; +} + +/* + * Verify and strip MIC from the frame. + */ +int +ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, const uint8_t *key, + qdf_nbuf_t msdu, uint16_t hdrlen) +{ + int status; + uint32_t pktlen; + uint8_t mic[IEEE80211_WEP_MICLEN]; + uint8_t mic0[IEEE80211_WEP_MICLEN]; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + pktlen = ol_rx_defrag_len(msdu) - rx_desc_len; + + status = ol_rx_defrag_mic(pdev, key, msdu, hdrlen, + pktlen - (hdrlen + f_tkip.ic_miclen), mic); + if (status != OL_RX_DEFRAG_OK) + return OL_RX_DEFRAG_ERR; + + ol_rx_defrag_copydata(msdu, pktlen - f_tkip.ic_miclen + rx_desc_len, + f_tkip.ic_miclen, (caddr_t) mic0); + if (qdf_mem_cmp(mic, mic0, f_tkip.ic_miclen)) + return OL_RX_DEFRAG_ERR; + + qdf_nbuf_trim_tail(msdu, f_tkip.ic_miclen); + return OL_RX_DEFRAG_OK; +} + +/* + * Handling CCMP processing for defragmentation + */ +int +ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + origHdr = (uint8_t *) (qdf_nbuf_data(nbuf) + rx_desc_len); + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_mem_move(origHdr + f_ccmp.ic_header, origHdr, hdrlen); + ol_rx_frag_restructure( + pdev, + nbuf, + rx_desc_old_position, + ind_old_position, + &f_ccmp, + rx_desc_len); + qdf_nbuf_pull_head(nbuf, f_ccmp.ic_header); + + return OL_RX_DEFRAG_OK; +} + +/* + * Verify and strip MIC from the frame. + */ +int +ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev, + qdf_nbuf_t wbuf, uint16_t hdrlen) +{ + uint8_t *ivp, *origHdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + origHdr = (uint8_t *) (qdf_nbuf_data(wbuf) + rx_desc_len); + + ivp = origHdr + hdrlen; + if (!(ivp[IEEE80211_WEP_IVLEN] & IEEE80211_WEP_EXTIV)) + return OL_RX_DEFRAG_ERR; + + qdf_nbuf_trim_tail(wbuf, f_ccmp.ic_trailer); + + return OL_RX_DEFRAG_OK; +} + +/* + * Craft pseudo header used to calculate the MIC. + */ +void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[]) +{ + const struct ieee80211_frame_addr4 *wh = + (const struct ieee80211_frame_addr4 *)wh0; + + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_TODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE, + wh->i_addr2); + break; + case IEEE80211_FC1_DIR_FROMDS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr1); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE, + wh->i_addr3); + break; + case IEEE80211_FC1_DIR_DSTODS: + DEFRAG_IEEE80211_ADDR_COPY(hdr, wh->i_addr3); /* DA */ + DEFRAG_IEEE80211_ADDR_COPY(hdr + QDF_MAC_ADDR_SIZE, + wh->i_addr4); + break; + } + /* + * Bit 7 is QDF_IEEE80211_FC0_SUBTYPE_QOS for data frame, but + * it could also be set for deauth, disassoc, action, etc. for + * a mgt type frame. It comes into picture for MFP. + */ + if (wh->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + const struct ieee80211_qosframe *qwh = + (const struct ieee80211_qosframe *)wh; + hdr[12] = qwh->i_qos[0] & IEEE80211_QOS_TID; + } else { + hdr[12] = 0; + } + hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ +} + +/* + * Michael_mic for defragmentation + */ +int +ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, + const uint8_t *key, + qdf_nbuf_t wbuf, + uint16_t off, uint16_t data_len, uint8_t mic[]) +{ + uint8_t hdr[16] = { 0, }; + uint32_t l, r; + const uint8_t *data; + uint32_t space; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + ol_rx_frag_desc_adjust(pdev, + wbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + ol_rx_defrag_michdr((struct ieee80211_frame *)(qdf_nbuf_data(wbuf) + + rx_desc_len), hdr); + l = get_le32(key); + r = get_le32(key + 4); + + /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */ + l ^= get_le32(hdr); + michael_block(l, r); + l ^= get_le32(&hdr[4]); + michael_block(l, r); + l ^= get_le32(&hdr[8]); + michael_block(l, r); + l ^= get_le32(&hdr[12]); + michael_block(l, r); + + /* first buffer has special handling */ + data = (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len + off; + space = ol_rx_defrag_len(wbuf) - rx_desc_len - off; + for (;; ) { + if (space > data_len) + space = data_len; + + /* collect 32-bit blocks from current buffer */ + while (space >= sizeof(uint32_t)) { + l ^= get_le32(data); + michael_block(l, r); + data += sizeof(uint32_t); + space -= sizeof(uint32_t); + data_len -= sizeof(uint32_t); + } + if (data_len < sizeof(uint32_t)) + break; + + wbuf = qdf_nbuf_next(wbuf); + if (!wbuf) + return OL_RX_DEFRAG_ERR; + + rx_desc_len = ol_rx_get_desc_len(htt_pdev, wbuf, + &rx_desc_old_position); + + if (space != 0) { + const uint8_t *data_next; + /* + * Block straddles buffers, split references. + */ + data_next = + (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len; + if ((ol_rx_defrag_len(wbuf) - rx_desc_len) < + sizeof(uint32_t) - space) { + return OL_RX_DEFRAG_ERR; + } + switch (space) { + case 1: + l ^= get_le32_split(data[0], data_next[0], + data_next[1], data_next[2]); + data = data_next + 3; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 3; + break; + case 2: + l ^= get_le32_split(data[0], data[1], + data_next[0], data_next[1]); + data = data_next + 2; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 2; + break; + case 3: + l ^= get_le32_split(data[0], data[1], data[2], + data_next[0]); + data = data_next + 1; + space = (ol_rx_defrag_len(wbuf) - rx_desc_len) + - 1; + break; + } + michael_block(l, r); + data_len -= sizeof(uint32_t); + } else { + /* + * Setup for next buffer. + */ + data = (uint8_t *) qdf_nbuf_data(wbuf) + rx_desc_len; + space = ol_rx_defrag_len(wbuf) - rx_desc_len; + } + } + /* Last block and padding (0x5a, 4..7 x 0) */ + switch (data_len) { + case 0: + l ^= get_le32_split(0x5a, 0, 0, 0); + break; + case 1: + l ^= get_le32_split(data[0], 0x5a, 0, 0); + break; + case 2: + l ^= get_le32_split(data[0], data[1], 0x5a, 0); + break; + case 3: + l ^= get_le32_split(data[0], data[1], data[2], 0x5a); + break; + } + michael_block(l, r); + michael_block(l, r); + put_le32(mic, l); + put_le32(mic + 4, r); + + return OL_RX_DEFRAG_OK; +} + +/* + * Calculate headersize + */ +uint16_t ol_rx_frag_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + uint16_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + size += QDF_MAC_ADDR_SIZE; + + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) { + size += sizeof(uint16_t); + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + size += sizeof(struct ieee80211_htc); + } + return size; +} + +/* + * Recombine and decap fragments + */ +qdf_nbuf_t +ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag_list, uint16_t hdrsize) +{ + qdf_nbuf_t tmp; + qdf_nbuf_t msdu = frag_list; + qdf_nbuf_t rx_nbuf = frag_list; + struct ieee80211_frame *wh; + + msdu = qdf_nbuf_next(msdu); + qdf_nbuf_set_next(rx_nbuf, NULL); + while (msdu) { + htt_rx_msdu_desc_free(htt_pdev, msdu); + tmp = qdf_nbuf_next(msdu); + qdf_nbuf_set_next(msdu, NULL); + ol_rx_frag_pull_hdr(htt_pdev, msdu, hdrsize); + if (!ol_rx_defrag_concat(rx_nbuf, msdu)) { + ol_rx_frames_free(htt_pdev, tmp); + htt_rx_desc_frame_free(htt_pdev, rx_nbuf); + qdf_nbuf_free(msdu); + /* msdu rx desc already freed above */ + return NULL; + } + msdu = tmp; + } + wh = (struct ieee80211_frame *)ol_rx_frag_get_mac_hdr(htt_pdev, + rx_nbuf); + wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; + *(uint16_t *) wh->i_seq &= ~IEEE80211_SEQ_FRAG_MASK; + + return rx_nbuf; +} + +void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu) +{ + struct ieee80211_frame wh; + uint32_t hdrsize; + struct llc_snap_hdr_t llchdr; + struct ethernet_hdr_t *eth_hdr; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + struct ieee80211_frame *wh_ptr; + + ol_rx_frag_desc_adjust(pdev, + msdu, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + wh_ptr = (struct ieee80211_frame *)(qdf_nbuf_data(msdu) + rx_desc_len); + qdf_mem_copy(&wh, wh_ptr, sizeof(wh)); + hdrsize = sizeof(struct ieee80211_frame); + qdf_mem_copy(&llchdr, ((uint8_t *) (qdf_nbuf_data(msdu) + + rx_desc_len)) + hdrsize, + sizeof(struct llc_snap_hdr_t)); + + /* + * Now move the data pointer to the beginning of the mac header : + * new-header = old-hdr + (wifhdrsize + llchdrsize - ethhdrsize) + */ + qdf_nbuf_pull_head(msdu, (rx_desc_len + hdrsize + + sizeof(struct llc_snap_hdr_t) - + sizeof(struct ethernet_hdr_t))); + eth_hdr = (struct ethernet_hdr_t *)(qdf_nbuf_data(msdu)); + switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr3, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr2, QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(eth_hdr->dest_addr, wh.i_addr1, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(eth_hdr->src_addr, wh.i_addr3, QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_DSTODS: + break; + } + + qdf_mem_copy(eth_hdr->ethertype, llchdr.ethertype, + sizeof(llchdr.ethertype)); + + ol_rx_defrag_push_rx_desc(msdu, rx_desc_old_position, + ind_old_position, rx_desc_len); +} + +/* + * Handling QOS for defragmentation + */ +void +ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen) +{ + struct ieee80211_frame *wh; + uint16_t qoslen; + void *rx_desc_old_position = NULL; + void *ind_old_position = NULL; + int rx_desc_len = 0; + + ol_rx_frag_desc_adjust(pdev, + nbuf, + &rx_desc_old_position, + &ind_old_position, &rx_desc_len); + + wh = (struct ieee80211_frame *)(qdf_nbuf_data(nbuf) + rx_desc_len); + if (DEFRAG_IEEE80211_QOS_HAS_SEQ(wh)) { + qoslen = sizeof(struct ieee80211_qoscntl); + /* Qos frame with Order bit set indicates a HTC frame */ + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + qoslen += sizeof(struct ieee80211_htc); + + /* remove QoS filed from header */ + hdrlen -= qoslen; + qdf_mem_move((uint8_t *) wh + qoslen, wh, hdrlen); + wh = (struct ieee80211_frame *)qdf_nbuf_pull_head(nbuf, + rx_desc_len + + qoslen); + /* clear QoS bit */ + /* + * KW# 6154 'qdf_nbuf_pull_head' in turn calls + * __qdf_nbuf_pull_head, + * which returns NULL if there is not sufficient data to pull. + * It's guaranteed that qdf_nbuf_pull_head will succeed rather + * than returning NULL, since the entire rx frame is already + * present in the rx buffer. + * However, to make it obvious to static analyzers that this + * code is safe, add an explicit check that qdf_nbuf_pull_head + * returns a non-NULL value. + * Since this part of the code is not performance-critical, + * adding this explicit check is okay. + */ + if (wh) + wh->i_fc[0] &= ~QDF_IEEE80211_FC0_SUBTYPE_QOS; + + ol_rx_defrag_push_rx_desc(nbuf, rx_desc_old_position, + ind_old_position, rx_desc_len); + + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h new file mode 100644 index 0000000000..96f0c33248 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_defrag.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2011-2017, 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_RX_DEFRAG_H_ +#define _OL_RX_DEFRAG_H_ + +#include +#include +#include +#include +#include +#include +#include + +#define DEFRAG_IEEE80211_KEY_LEN 8 +#define DEFRAG_IEEE80211_FCS_LEN 4 + +struct ol_rx_defrag_cipher { + const char *ic_name; + uint16_t ic_header; + uint8_t ic_trailer; + uint8_t ic_miclen; +}; + +enum { + OL_RX_DEFRAG_ERR, + OL_RX_DEFRAG_OK, + OL_RX_DEFRAG_PN_ERR +}; + +#define ol_rx_defrag_copydata(buf, offset, len, _to) \ + qdf_nbuf_copy_bits(buf, offset, len, _to) + +#define ol_rx_defrag_len(buf) \ + qdf_nbuf_len(buf) + +void +ol_rx_fraglist_insert(htt_pdev_handle htt_pdev, + qdf_nbuf_t *head_addr, + qdf_nbuf_t *tail_addr, + qdf_nbuf_t frag, uint8_t *all_frag_present); + +void ol_rx_defrag_waitlist_add(struct ol_txrx_peer_t *peer, unsigned int tid); + +void ol_rx_defrag_waitlist_remove(struct ol_txrx_peer_t *peer, + unsigned int tid); + +void ol_rx_defrag_waitlist_flush(struct ol_txrx_pdev_t *pdev); + +void +ol_rx_defrag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t frag_list); + +int +ol_rx_frag_tkip_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t msdu, uint16_t hdrlen); + +int +ol_rx_frag_wep_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen); + +void ol_rx_defrag_nwifi_to_8023(ol_txrx_pdev_handle pdev, qdf_nbuf_t msdu); + +void +ol_rx_defrag_qos_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen); + +int +ol_rx_frag_tkip_demic(ol_txrx_pdev_handle pdev, + const uint8_t *key, qdf_nbuf_t msdu, uint16_t hdrlen); + +int +ol_rx_frag_ccmp_decap(ol_txrx_pdev_handle pdev, + qdf_nbuf_t nbuf, uint16_t hdrlen); + +int +ol_rx_frag_ccmp_demic(ol_txrx_pdev_handle pdev, + qdf_nbuf_t wbuf, uint16_t hdrlen); + +uint16_t ol_rx_frag_hdrsize(const void *data); + +void ol_rx_defrag_michdr(const struct ieee80211_frame *wh0, uint8_t hdr[]); + +void +ol_rx_reorder_store_frag(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, uint16_t seq_num, qdf_nbuf_t frag); + +qdf_nbuf_t +ol_rx_defrag_decap_recombine(htt_pdev_handle htt_pdev, + qdf_nbuf_t frag_list, uint16_t hdrsize); + +int +ol_rx_defrag_mic(ol_txrx_pdev_handle pdev, + const uint8_t *key, + qdf_nbuf_t wbuf, + uint16_t off, uint16_t data_len, uint8_t mic[]); + +void +ol_rx_reorder_flush_frag(htt_pdev_handle htt_pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, uint16_t seq_num); + +static inline void xor_block(uint8_t *b, const uint8_t *a, qdf_size_t len) +{ + qdf_size_t i; + + for (i = 0; i < len; i++) + b[i] ^= a[i]; +} + +static inline uint32_t rotl(uint32_t val, int bits) +{ + return (val << bits) | (val >> (32 - bits)); +} + +static inline uint32_t rotr(uint32_t val, int bits) +{ + return (val >> bits) | (val << (32 - bits)); +} + +static inline uint32_t xswap(uint32_t val) +{ + return ((val & 0x00ff00ff) << 8) | ((val & 0xff00ff00) >> 8); +} + +static inline uint32_t +get_le32_split(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) +{ + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); +} + +static inline uint32_t get_le32(const uint8_t *p) +{ + return get_le32_split(p[0], p[1], p[2], p[3]); +} + +static inline void put_le32(uint8_t *p, uint32_t v) +{ + p[0] = (v) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = (v >> 24) & 0xff; +} + +static inline uint8_t ol_rx_defrag_concat(qdf_nbuf_t dst, qdf_nbuf_t src) +{ + /* + * Inside qdf_nbuf_cat, if it is necessary to reallocate dst + * to provide space for src, the headroom portion is copied from + * the original dst buffer to the larger new dst buffer. + * (This is needed, because the headroom of the dst buffer + * contains the rx desc.) + */ + if (qdf_nbuf_cat(dst, src)) + return OL_RX_DEFRAG_ERR; + + /* Free source buffer */ + qdf_nbuf_free(src); + + return OL_RX_DEFRAG_OK; +} + +#define michael_block(l, r) \ + do { \ + r ^= rotl(l, 17); \ + l += r; \ + r ^= xswap(l); \ + l += r; \ + r ^= rotl(l, 3); \ + l += r; \ + r ^= rotr(l, 2); \ + l += r; \ + } while (0) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c new file mode 100644 index 0000000000..0326908cb9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_fwd.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2011, 2014-2019, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* standard header files */ +#include /* qdf_nbuf_map */ +#include /* qdf_mem_cmp */ + +/* external header files */ +#include /* wlan_op_mode_ap, etc. */ +#include /* htt_rx_msdu_desc_retrieve */ +#include /* ieee80211_frame, etc. */ + +/* internal header files */ +#include /* our own defs */ +#include /* ol_rx_deliver */ +#include /* TXRX_ASSERT1 */ +#include +#include + +/* + * Porting from Ap11PrepareForwardedPacket. + * This routine is called when a RX data frame from an associated station is + * to be forwarded to another associated station. We will prepare the + * received packet so that it is suitable for transmission again. + * Check that this Packet is suitable for forwarding. If yes, then + * prepare the new 802.11 header. + */ +static inline void ol_ap_fwd_check(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu) +{ + struct ieee80211_frame *mac_header; + unsigned char tmp_addr[QDF_MAC_ADDR_SIZE]; + unsigned char type; + unsigned char subtype; + unsigned char fromds; + unsigned char tods; + + mac_header = (struct ieee80211_frame *)(qdf_nbuf_data(msdu)); + TXRX_ASSERT1(mac_header); + + type = mac_header->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + subtype = mac_header->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + tods = mac_header->i_fc[1] & IEEE80211_FC1_DIR_TODS; + fromds = mac_header->i_fc[1] & IEEE80211_FC1_DIR_FROMDS; + + /* + * Make sure no QOS or any other non-data subtype + * Should be a ToDs data frame. + * Make sure that this frame is unicast and not for us. + * These packets should come up through the normal rx path and + * not forwarded. + */ + if (type != IEEE80211_FC0_TYPE_DATA || + subtype != 0x0 || + ((tods != 1) || (fromds != 0)) || + qdf_mem_cmp + (mac_header->i_addr3, vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE)) { + ol_txrx_dbg("Exit | Unnecessary to adjust mac header"); + } else { + /* Flip the ToDs bit to FromDs */ + mac_header->i_fc[1] &= 0xfe; + mac_header->i_fc[1] |= 0x2; + + /* + * Flip the addresses + * (ToDs, addr1, RA=BSSID) move to (FrDs, addr2, TA=BSSID) + * (ToDs, addr2, SA) move to (FrDs, addr3, SA) + * (ToDs, addr3, DA) move to (FrDs, addr1, DA) + */ + + memcpy(tmp_addr, mac_header->i_addr2, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr2, + mac_header->i_addr1, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr1, + mac_header->i_addr3, sizeof(tmp_addr)); + + memcpy(mac_header->i_addr3, tmp_addr, sizeof(tmp_addr)); + } +} + +static inline void ol_rx_fwd_to_tx(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) + ol_ap_fwd_check(vdev, msdu); + + /* + * Map the netbuf, so it's accessible to the DMA that + * sends it to the target. + */ + qdf_nbuf_set_next(msdu, NULL); /* add NULL terminator */ + + /* for HL, point to payload before send to tx again.*/ + if (pdev->cfg.is_high_latency) { + void *rx_desc; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, + msdu); + qdf_nbuf_pull_head(msdu, + htt_rx_msdu_rx_desc_size_hl(pdev->htt_pdev, + rx_desc)); + } + + /* Clear the msdu control block as it will be re-interpreted */ + qdf_mem_zero(msdu->cb, sizeof(msdu->cb)); + /* update any cb field expected by OL_TX_SEND */ + + msdu = OL_TX_SEND(vdev, msdu); + + if (msdu) { + /* + * The frame was not accepted by the tx. + * We could store the frame and try again later, + * but the simplest solution is to discard the frames. + */ + qdf_nbuf_tx_free(msdu, QDF_NBUF_PKT_ERROR); + } +} + +void +ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + qdf_nbuf_t deliver_list_head = NULL; + qdf_nbuf_t deliver_list_tail = NULL; + qdf_nbuf_t msdu; + + msdu = msdu_list; + while (msdu) { + struct ol_txrx_vdev_t *tx_vdev; + void *rx_desc; + uint16_t off = 0; + /* + * Remember the next list elem, because our processing + * may cause the MSDU to get linked into a different list. + */ + msdu_list = qdf_nbuf_next(msdu); + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu); + + if (!vdev->disable_intrabss_fwd && + htt_rx_msdu_forward(pdev->htt_pdev, rx_desc)) { + /* + * Use the same vdev that received the frame to + * transmit the frame. + * This is exactly what we want for intra-BSS + * forwarding, like STA-to-STA forwarding and + * multicast echo. + * If this is a intra-BSS forwarding case (which is not + * currently supported), then the tx vdev is different + * from the rx vdev. + * On the LL host the vdevs are not actually used + * for tx, so it would still work to use the rx vdev + * rather than the tx vdev. + * For HL, the tx classification searches for the DA + * within the given vdev, so we would want to get the DA + * peer ID from the target, so we can locate + * the tx vdev. + */ + tx_vdev = vdev; + /* + * Copying TID value of RX packet to forwarded + * packet if the tid is other than non qos tid. + * But for non qos tid fill invalid tid so that + * Fw will take care of filling proper tid. + */ + if (tid != HTT_NON_QOS_TID) { + qdf_nbuf_set_tid(msdu, tid); + } else { + qdf_nbuf_set_tid(msdu, + QDF_NBUF_TX_EXT_TID_INVALID); + } + + if (!ol_txrx_fwd_desc_thresh_check(vdev)) { + /* Drop the packet*/ + htt_rx_msdu_desc_free(pdev->htt_pdev, msdu); + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + /* add NULL terminator */ + qdf_nbuf_set_next(msdu, NULL); + qdf_nbuf_tx_free(msdu, + QDF_NBUF_PKT_ERROR); + msdu = msdu_list; + continue; + } + + if (pdev->cfg.is_high_latency) + off = htt_rx_msdu_rx_desc_size_hl( + pdev->htt_pdev, + rx_desc); + + if (vdev->opmode == wlan_op_mode_ap && + __qdf_nbuf_data_is_ipv4_eapol_pkt( + qdf_nbuf_data(msdu) + off) && + qdf_mem_cmp(qdf_nbuf_data(msdu) + + QDF_NBUF_DEST_MAC_OFFSET, + vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE)) { + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + qdf_nbuf_set_next(msdu, NULL); + qdf_nbuf_tx_free(msdu, QDF_NBUF_PKT_ERROR); + msdu = msdu_list; + continue; + } + + /* + * This MSDU needs to be forwarded to the tx path. + * Check whether it also needs to be sent to the OS + * shim, in which case we need to make a copy + * (or clone?). + */ + if (htt_rx_msdu_discard(pdev->htt_pdev, rx_desc)) { + htt_rx_msdu_desc_free(pdev->htt_pdev, msdu); + ol_rx_fwd_to_tx(tx_vdev, msdu); + msdu = NULL; /* already handled this MSDU */ + tx_vdev->fwd_tx_packets++; + vdev->fwd_rx_packets++; + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_fwd, 1); + } else { + qdf_nbuf_t copy; + + copy = qdf_nbuf_copy(msdu); + if (copy) { + ol_rx_fwd_to_tx(tx_vdev, copy); + tx_vdev->fwd_tx_packets++; + } + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_stack_n_fwd, 1); + } + } else { + TXRX_STATS_ADD(pdev, + pub.rx.intra_bss_fwd.packets_stack, 1); + } + if (msdu) { + /* send this frame to the OS */ + OL_TXRX_LIST_APPEND(deliver_list_head, + deliver_list_tail, msdu); + } + msdu = msdu_list; + } + if (deliver_list_head) { + /* add NULL terminator */ + qdf_nbuf_set_next(deliver_list_tail, NULL); + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + ol_rx_in_order_deliver(vdev, peer, tid, + deliver_list_head); + } else { + ol_rx_deliver(vdev, peer, tid, deliver_list_head); + } + } +} + +/* + * ol_get_intra_bss_fwd_pkts_count() - to get the total tx and rx packets + * that has been forwarded from txrx layer without going to upper layers. + * @soc_hdl: Datapath soc handle + * @vdev_id: vdev id + * @fwd_tx_packets: pointer to forwarded tx packets count parameter + * @fwd_rx_packets: pointer to forwarded rx packets count parameter + * + * Return: status -> A_OK - success, A_ERROR - failure + */ +A_STATUS ol_get_intra_bss_fwd_pkts_count(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + uint64_t *fwd_tx_packets, + uint64_t *fwd_rx_packets) +{ + struct ol_txrx_vdev_t *vdev = NULL; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) + return A_ERROR; + + *fwd_tx_packets = vdev->fwd_tx_packets; + *fwd_rx_packets = vdev->fwd_rx_packets; + return A_OK; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h new file mode 100644 index 0000000000..ff1494e27c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_fwd.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011, 2014-2017, 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_RX_FWD_H_ +#define _OL_RX_FWD_H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +/** + * ol_rx_fwd_check() - Check if rx frames should be transmitted over WLAN. + * @vdev: which virtual device the frames were addressed to + * @peer: which peer the rx frames belong to + * @tid: which TID within the peer the rx frames belong to + * @msdu_list: NULL-terminated list of MSDUs to perform the rx->tx + * forwarding check on + * + * Check if rx frames should be transmitted back over WLAN, instead of + * or in addition to delivering the rx frames to the OS. + * Rx frames will be forwarded to the transmit path under the following + * conditions: + * 1. If the destination is a STA associated to the same virtual device + * within this physical device, the rx frame will be forwarded to the + * tx path rather than being sent to the OS. If the destination is a + * STA associated to a different virtual device within this physical + * device, then the rx frame will optionally be forwarded to the tx path. + * 2. If the frame is received by an AP, but the destination is for another + * AP that the current AP is associated with for WDS forwarding, the + * intermediate AP will forward the rx frame to the tx path to transmit + * to send to the destination AP, rather than sending it to the OS. + * 3. If the AP receives a multicast frame, it will retransmit the frame + * within the BSS, in addition to sending the frame to the OS. + * + */ +void +ol_rx_fwd_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list); + +/** + * ol_get_intra_bss_fwd_pkts_count() - to get the total tx and rx packets + * that has been forwarded from txrx layer without going to upper layers. + * @soc_hdl: Datapath soc handle + * @vdev_id: vdev id + * @fwd_tx_packets: pointer to forwarded tx packets count parameter + * @fwd_rx_packets: pointer to forwarded rx packets count parameter + * + * Return: status -> A_OK - success, A_ERROR - failure + */ +A_STATUS +ol_get_intra_bss_fwd_pkts_count(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + uint64_t *fwd_tx_packets, + uint64_t *fwd_rx_packets); + +#endif /* _OL_RX_FWD_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_pn.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_pn.c new file mode 100644 index 0000000000..0d8d715845 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_pn.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2011, 2013-2017, 2019-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_nbuf_t */ + +#include /* htt_rx_pn_t, etc. */ +#include /* ol_rx_err */ + +#include /* ol_rx_mpdu_list_next */ +#include /* our own defs */ +#include /* ol_rx_fwd_check */ +#include /* ol_rx_deliver */ + +/* add the MSDUs from this MPDU to the list of good frames */ +#define ADD_MPDU_TO_LIST(head, tail, mpdu, mpdu_tail) do { \ + if (!head) { \ + head = mpdu; \ + } else { \ + qdf_nbuf_set_next(tail, mpdu); \ + } \ + tail = mpdu_tail; \ + } while (0) + +int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode, + bool strict_chk) +{ + if (strict_chk) + return ((new_pn->pn24 & 0xffffff) - (old_pn->pn24 & 0xffffff) + != 1); + else + return ((new_pn->pn24 & 0xffffff) <= (old_pn->pn24 & 0xffffff)); +} + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode, + bool strict_chk) +{ + if (strict_chk) + return ((new_pn->pn48 & 0xffffffffffffULL) - + (old_pn->pn48 & 0xffffffffffffULL) != 1); + else + return ((new_pn->pn48 & 0xffffffffffffULL) <= + (old_pn->pn48 & 0xffffffffffffULL)); +} + +int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode, + bool strict_chk) +{ + int pn_is_replay = 0; + + /* TODO Strick check for WAPI is not implemented*/ + + if (new_pn->pn128[1] == old_pn->pn128[1]) + pn_is_replay = (new_pn->pn128[0] <= old_pn->pn128[0]); + else + pn_is_replay = (new_pn->pn128[1] < old_pn->pn128[1]); + + if (is_unicast) { + if (opmode == wlan_op_mode_ap) + pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 0); + else + pn_is_replay |= ((new_pn->pn128[0] & 0x1ULL) != 1); + } + return pn_is_replay; +} + +qdf_nbuf_t +ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list, bool strict_chk) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + union htt_rx_pn_t *last_pn; + qdf_nbuf_t out_list_head = NULL; + qdf_nbuf_t out_list_tail = NULL; + qdf_nbuf_t mpdu; + int index; /* unicast vs. multicast */ + int pn_len; + void *rx_desc; + int last_pn_valid; + + /* Make sure host pn check is not redundant */ + if ((qdf_atomic_read(&peer->fw_pn_check)) || + (vdev->opmode == wlan_op_mode_ibss)) { + return msdu_list; + } + + /* First, check whether the PN check applies */ + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, msdu_list); + qdf_assert(htt_rx_msdu_has_wlan_mcast_flag(pdev->htt_pdev, rx_desc)); + index = htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc) ? + txrx_sec_mcast : txrx_sec_ucast; + pn_len = pdev->rx_pn[peer->security[index].sec_type].len; + if (pn_len == 0) + return msdu_list; + + last_pn_valid = peer->tids_last_pn_valid[tid]; + last_pn = &peer->tids_last_pn[tid]; + mpdu = msdu_list; + while (mpdu) { + qdf_nbuf_t mpdu_tail, next_mpdu; + union htt_rx_pn_t new_pn; + int pn_is_replay = 0; + + rx_desc = htt_rx_msdu_desc_retrieve(pdev->htt_pdev, mpdu); + + /* + * Find the last MSDU within this MPDU, and + * the find the first MSDU within the next MPDU. + */ + ol_rx_mpdu_list_next(pdev, mpdu, &mpdu_tail, &next_mpdu); + + /* Don't check the PN replay for non-encrypted frames */ + if (!htt_rx_mpdu_is_encrypted(pdev->htt_pdev, rx_desc)) { + ADD_MPDU_TO_LIST(out_list_head, out_list_tail, + mpdu, mpdu_tail); + mpdu = next_mpdu; + continue; + } + + /* retrieve PN from rx descriptor */ + htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &new_pn, pn_len); + + /* if there was no prior PN, there's nothing to check */ + if (last_pn_valid) { + pn_is_replay = + pdev->rx_pn[peer->security[index].sec_type]. + cmp(&new_pn, last_pn, index == txrx_sec_ucast, + vdev->opmode, strict_chk); + } else { + last_pn_valid = peer->tids_last_pn_valid[tid] = 1; + } + + if (pn_is_replay) { + qdf_nbuf_t msdu; + static uint32_t last_pncheck_print_time /* = 0 */; + uint32_t current_time_ms; + + /* + * This MPDU failed the PN check: + * 1. notify the control SW of the PN failure + * (so countermeasures can be taken, if necessary) + * 2. Discard all the MSDUs from this MPDU. + */ + msdu = mpdu; + current_time_ms = + qdf_system_ticks_to_msecs(qdf_system_ticks()); + if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS < + (current_time_ms - last_pncheck_print_time)) { + last_pncheck_print_time = current_time_ms; + ol_txrx_warn( + "PN check failed - TID %d, peer %pK " + "("QDF_MAC_ADDR_FMT") %s\n" + " old PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + (index == + txrx_sec_ucast) ? "ucast" : "mcast", + last_pn->pn128[1], last_pn->pn128[0], + last_pn->pn128[0] & 0xffffffffffffULL, + new_pn.pn128[1], new_pn.pn128[0], + new_pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, + rx_desc, false)); + } else { + ol_txrx_dbg( + "PN check failed - TID %d, peer %pK " + "("QDF_MAC_ADDR_FMT") %s\n" + " old PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + (index == + txrx_sec_ucast) ? "ucast" : "mcast", + last_pn->pn128[1], last_pn->pn128[0], + last_pn->pn128[0] & 0xffffffffffffULL, + new_pn.pn128[1], new_pn.pn128[0], + new_pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, + rx_desc, false)); + } +#if defined(ENABLE_RX_PN_TRACE) + ol_rx_pn_trace_display(pdev, 1); +#endif /* ENABLE_RX_PN_TRACE */ + ol_rx_err(pdev->ctrl_pdev, + vdev->vdev_id, peer->mac_addr.raw, tid, + htt_rx_mpdu_desc_tsf32(pdev->htt_pdev, + rx_desc), OL_RX_ERR_PN, + mpdu, NULL, 0); + /* free all MSDUs within this MPDU */ + do { + qdf_nbuf_t next_msdu; + + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, + rx_desc, OL_RX_ERR_PN); + next_msdu = qdf_nbuf_next(msdu); + htt_rx_desc_frame_free(pdev->htt_pdev, msdu); + if (msdu == mpdu_tail) + break; + msdu = next_msdu; + } while (1); + } else { + ADD_MPDU_TO_LIST(out_list_head, out_list_tail, + mpdu, mpdu_tail); + /* + * Remember the new PN. + * For simplicity, just do 2 64-bit word copies to + * cover the worst case (WAPI), regardless of the length + * of the PN. + * This is more efficient than doing a conditional + * branch to copy only the relevant portion. + + * IWNCOM AP will send 1 packet with old PN after USK + * rekey, don't update last_pn when recv the packet, or + * PN check failed for later packets + */ + if ((peer->security[index].sec_type + == htt_sec_type_wapi) && + (peer->tids_rekey_flag[tid] == 1) && + (index == txrx_sec_ucast)) { + peer->tids_rekey_flag[tid] = 0; + } else { + last_pn->pn128[0] = new_pn.pn128[0]; + last_pn->pn128[1] = new_pn.pn128[1]; + OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc); + } + } + + mpdu = next_mpdu; + } + /* make sure the list is null-terminated */ + if (out_list_tail) + qdf_nbuf_set_next(out_list_tail, NULL); + + return out_list_head; +} + +void +ol_rx_pn_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t msdu_list) +{ + msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list, false); + ol_rx_fwd_check(vdev, peer, tid, msdu_list); +} + +void +ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list) +{ + msdu_list = ol_rx_pn_check_base(vdev, peer, tid, msdu_list, false); + ol_rx_deliver(vdev, peer, tid, msdu_list); +} + +#if defined(ENABLE_RX_PN_TRACE) + +A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev) +{ + int num_elems; + + num_elems = 1 << TXRX_RX_PN_TRACE_SIZE_LOG2; + pdev->rx_pn_trace.idx = 0; + pdev->rx_pn_trace.cnt = 0; + pdev->rx_pn_trace.mask = num_elems - 1; + pdev->rx_pn_trace.data = + qdf_mem_malloc(sizeof(*pdev->rx_pn_trace.data) * num_elems); + if (!pdev->rx_pn_trace.data) + return A_NO_MEMORY; + return A_OK; +} + +void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev) +{ + qdf_mem_free(pdev->rx_pn_trace.data); +} + +void +ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, uint16_t tid, void *rx_desc) +{ + uint32_t idx = pdev->rx_pn_trace.idx; + union htt_rx_pn_t pn; + uint32_t pn32; + uint16_t seq_num; + uint8_t unicast; + + htt_rx_mpdu_desc_pn(pdev->htt_pdev, rx_desc, &pn, 48); + pn32 = pn.pn48 & 0xffffffff; + seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_desc, false); + unicast = !htt_rx_msdu_is_wlan_mcast(pdev->htt_pdev, rx_desc); + + pdev->rx_pn_trace.data[idx].peer = peer; + pdev->rx_pn_trace.data[idx].tid = tid; + pdev->rx_pn_trace.data[idx].seq_num = seq_num; + pdev->rx_pn_trace.data[idx].unicast = unicast; + pdev->rx_pn_trace.data[idx].pn32 = pn32; + pdev->rx_pn_trace.cnt++; + idx++; + pdev->rx_pn_trace.idx = idx & pdev->rx_pn_trace.mask; +} + +void ol_rx_pn_trace_display(ol_txrx_pdev_handle pdev, int just_once) +{ + static int print_count /* = 0 */; + uint32_t i, start, end; + uint64_t cnt; + int elems; + int limit = 0; /* move this to the arg list? */ + + if (print_count != 0 && just_once) + return; + + print_count++; + + end = pdev->rx_pn_trace.idx; + if (pdev->rx_pn_trace.cnt <= pdev->rx_pn_trace.mask) { + /* trace log has not yet wrapped around - start at the top */ + start = 0; + cnt = 0; + } else { + start = end; + cnt = pdev->rx_pn_trace.cnt - (pdev->rx_pn_trace.mask + 1); + } + elems = (end - 1 - start) & pdev->rx_pn_trace.mask; + if (limit > 0 && elems > limit) { + int delta; + + delta = elems - limit; + start += delta; + start &= pdev->rx_pn_trace.mask; + cnt += delta; + } + + i = start; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " seq PN"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " count idx peer tid uni num LSBs"); + do { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " %6lld %4d %pK %2d %d %4d %8d", + cnt, i, + pdev->rx_pn_trace.data[i].peer, + pdev->rx_pn_trace.data[i].tid, + pdev->rx_pn_trace.data[i].unicast, + pdev->rx_pn_trace.data[i].seq_num, + pdev->rx_pn_trace.data[i].pn32); + cnt++; + i++; + i &= pdev->rx_pn_trace.mask; + } while (i != end); +} +#endif /* ENABLE_RX_PN_TRACE */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_pn.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_pn.h new file mode 100644 index 0000000000..fa64c3e513 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_pn.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2011, 2014-2017, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_RX_PN_H_ +#define _OL_RX_PN_H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +int ol_rx_pn_cmp24(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode, + bool strict_chk); + +int ol_rx_pn_cmp48(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode, + bool strict_chk); + +int ol_rx_pn_wapi_cmp(union htt_rx_pn_t *new_pn, + union htt_rx_pn_t *old_pn, int is_unicast, int opmode, + bool strict_chk); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Determine whether a PN check is needed, and if so, what the PN size is. + * (A PN size of 0 is used to indirectly bypass the PN check for security + * methods that don't involve a PN check.) + * This function produces event notifications for any PN failures, via the + * ol_rx_err function. + * After the PN check, call the next stage of rx processing (rx --> tx + * forwarding check). + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + */ +void +ol_rx_pn_check(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, unsigned int tid, + qdf_nbuf_t msdu_list); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Determine whether a PN check is needed, and if so, what the PN size is. + * (A PN size of 0 is used to indirectly bypass the PN check for security + * methods that don't involve a PN check.) + * This function produces event notifications for any PN failures, via the + * ol_rx_err function. + * After the PN check, deliver the valid rx frames to the OS shim. + * (Don't perform a rx --> tx forwarding check.) + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + */ +void +ol_rx_pn_check_only(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list); + +/** + * @brief If applicable, check the Packet Number to detect replays. + * @details + * Same as ol_rx_pn_check but return valid rx netbufs + * rather than invoking the rx --> tx forwarding check. + * + * @param vdev - which virtual device the frames were addressed to + * @param peer - which peer the rx frames belong to + * @param tid - which TID within the peer the rx frames belong to + * @param msdu_list - NULL-terminated list of MSDUs to perform PN check on + * (if PN check is applicable, i.e. PN length > 0) + * @param strick_chk - if PN consecutive stric check is needed or not + * @return list of netbufs that didn't fail the PN check + */ +qdf_nbuf_t +ol_rx_pn_check_base(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list, bool strict_chk); + +#endif /* _OL_RX_PN_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c new file mode 100644 index 0000000000..9219957c7d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder.c @@ -0,0 +1,932 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=== header file includes ===*/ +/* generic utilities */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_mem_malloc */ + +/* external interfaces */ +#include /* ol_txrx_pdev_handle */ +#include /* ol_rx_addba_handler, etc. */ +#include /* ol_ctrl_rx_addba_complete */ +#include /* htt_rx_desc_frame_free */ +#include /* ol_rx_err */ + +/* datapath internal interfaces */ +#include /* ol_txrx_peer_find_by_id */ +#include /* TXRX_ASSERT */ +#include /* OL_RX_REORDER_TIMEOUT_REMOVE, etc. */ +#include +#include + +/*=== data types and defines ===*/ +#define OL_RX_REORDER_ROUND_PWR2(value) g_log2ceil[value] + +/*=== global variables ===*/ + +static char g_log2ceil[] = { + 1, /* 0 -> 1 */ + 1, /* 1 -> 1 */ + 2, /* 2 -> 2 */ + 4, 4, /* 3-4 -> 4 */ + 8, 8, 8, 8, /* 5-8 -> 8 */ + 16, 16, 16, 16, 16, 16, 16, 16, /* 9-16 -> 16 */ + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, /* 17-32 -> 32 */ + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, /* 33-64 -> 64 */ +}; + +/*=== function definitions ===*/ + +/*---*/ + +#define QCA_SUPPORT_RX_REORDER_RELEASE_CHECK 0 +#define OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, idx_start) /* no-op */ +#define OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask) { idx &= win_sz_mask; } +#define OL_RX_REORDER_IDX_MAX(win_sz, win_sz_mask) win_sz_mask +#define OL_RX_REORDER_IDX_INIT(seq_num, win_sz, win_sz_mask) 0 /* n/a */ +#define OL_RX_REORDER_NO_HOLES(rx_reorder) 0 +#define OL_RX_REORDER_MPDU_CNT_INCR(rx_reorder, incr) /* n/a */ +#define OL_RX_REORDER_MPDU_CNT_DECR(rx_reorder, decr) /* n/a */ + +/*---*/ + +/* reorder array elements are known to be non-NULL */ +#define OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, rx_reorder_array_elem) \ + do { \ + if (tail_msdu) { \ + qdf_nbuf_set_next(tail_msdu, \ + rx_reorder_array_elem->head); \ + } \ + } while (0) + +/* functions called by txrx components */ + +void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid) +{ + rx_reorder->win_sz = 1; + rx_reorder->win_sz_mask = 0; + rx_reorder->array = &rx_reorder->base; + rx_reorder->base.head = rx_reorder->base.tail = NULL; + rx_reorder->tid = tid; + rx_reorder->defrag_timeout_ms = 0; + + rx_reorder->defrag_waitlist_elem.tqe_next = NULL; + rx_reorder->defrag_waitlist_elem.tqe_prev = NULL; +} + +static enum htt_rx_status +ol_rx_reorder_seq_num_check( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, unsigned int seq_num) +{ + unsigned int seq_num_delta; + + /* don't check the new seq_num against last_seq + if last_seq is not valid */ + if (peer->tids_last_seq[tid] == IEEE80211_SEQ_MAX) + return htt_rx_status_ok; + + /* + * For duplicate detection, it might be helpful to also check + * whether the retry bit is set or not - a strict duplicate packet + * should be the one with retry bit set. + * However, since many implementations do not set the retry bit, + * and since this same function is also used for filtering out + * late-arriving frames (frames that arrive after their rx reorder + * timeout has expired) which are not retries, don't bother checking + * the retry bit for now. + */ + /* note: if new seq_num == old seq_num, seq_num_delta = 4095 */ + seq_num_delta = (seq_num - 1 - peer->tids_last_seq[tid]) & + (IEEE80211_SEQ_MAX - 1); /* account for wraparound */ + + if (seq_num_delta > (IEEE80211_SEQ_MAX >> 1)) { + return htt_rx_status_err_replay; + /* or maybe htt_rx_status_err_dup */ + } + return htt_rx_status_ok; +} + +/** + * ol_rx_seq_num_check() - Does duplicate detection for mcast packets and + * duplicate detection & check for out-of-order + * packets for unicast packets. + * @pdev: Pointer to pdev maintained by OL + * @peer: Pointer to peer structure maintained by OL + * @tid: TID value passed as part of HTT msg by f/w + * @rx_mpdu_desc: Pointer to Rx Descriptor for the given MPDU + * + * This function + * 1) For Multicast Frames -- does duplicate detection + * A frame is considered duplicate & dropped if it has a seq.number + * which is received twice in succession and with the retry bit set + * in the second case. + * A frame which is older than the last sequence number received + * is not considered duplicate but out-of-order. This function does + * perform out-of-order check for multicast frames, which is in + * keeping with the 802.11 2012 spec section 9.3.2.10 + * 2) For Unicast Frames -- does duplicate detection & out-of-order check + * only for non-aggregation tids. + * + * Return: Returns htt_rx_status_err_replay, if packet needs to be + * dropped, htt_rx_status_ok otherwise. + */ +enum htt_rx_status +ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint8_t tid, + void *rx_mpdu_desc) +{ + uint16_t pkt_tid = 0xffff; + uint16_t seq_num = IEEE80211_SEQ_MAX; + bool retry = 0; + + seq_num = htt_rx_mpdu_desc_seq_num(pdev->htt_pdev, rx_mpdu_desc, false); + + /* For mcast packets, we only the dup-detection, not re-order check */ + + if (qdf_unlikely(OL_RX_MCAST_TID == tid)) { + + pkt_tid = htt_rx_mpdu_desc_tid(pdev->htt_pdev, rx_mpdu_desc); + + /* Invalid packet TID, expected only for HL */ + /* Pass the packet on */ + if (qdf_unlikely(pkt_tid >= OL_TXRX_NUM_EXT_TIDS)) + return htt_rx_status_ok; + + retry = htt_rx_mpdu_desc_retry(pdev->htt_pdev, rx_mpdu_desc); + + /* + * At this point, we define frames to be duplicate if they + * arrive "ONLY" in succession with the same sequence number + * and the last one has the retry bit set. For an older frame, + * we consider that as an out of order frame, and hence do not + * perform the dup-detection or out-of-order check for multicast + * frames as per discussions & spec. + * Hence "seq_num <= last_seq_num" check is not necessary. + */ + if (qdf_unlikely(retry && + (seq_num == peer->tids_mcast_last_seq[pkt_tid]))) { + /* drop mcast */ + TXRX_STATS_INCR(pdev, priv.rx.err.msdu_mc_dup_drop); + return htt_rx_status_err_replay; + } + + /* + * This is a multicast packet likely to be passed on... + * Set the mcast last seq number here + * This is fairly accurate since: + * a) f/w sends multicast as separate PPDU/HTT messages + * b) Mcast packets are not aggregated & hence single + * c) Result of b) is that, flush / release bit is set + * always on the mcast packets, so likely to be + * immediatedly released. + */ + peer->tids_mcast_last_seq[pkt_tid] = seq_num; + return htt_rx_status_ok; + } else + return ol_rx_reorder_seq_num_check(pdev, peer, tid, seq_num); +} + + +void +ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, + unsigned int idx, qdf_nbuf_t head_msdu, + qdf_nbuf_t tail_msdu) +{ + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + + idx &= peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + qdf_nbuf_set_next(rx_reorder_array_elem->tail, head_msdu); + } else { + rx_reorder_array_elem->head = head_msdu; + OL_RX_REORDER_MPDU_CNT_INCR(&peer->tids_rx_reorder[tid], 1); + } + rx_reorder_array_elem->tail = tail_msdu; +} + +void +ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, unsigned int idx_start, + unsigned int idx_end) +{ + unsigned int idx; + unsigned int win_sz, win_sz_mask; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + qdf_nbuf_t head_msdu; + qdf_nbuf_t tail_msdu; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + /* may get reset below */ + peer->tids_next_rel_idx[tid] = (uint16_t) idx_end; + + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + idx_start &= win_sz_mask; + idx_end &= win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx_start]; + + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = rx_reorder_array_elem->tail = NULL; + if (head_msdu) + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], 1); + + idx = (idx_start + 1); + OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask); + while (idx != idx_end) { + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], + 1); + OL_RX_REORDER_LIST_APPEND(head_msdu, tail_msdu, + rx_reorder_array_elem); + tail_msdu = rx_reorder_array_elem->tail; + } + rx_reorder_array_elem->head = rx_reorder_array_elem->tail = + NULL; + idx++; + OL_RX_REORDER_IDX_WRAP(idx, win_sz, win_sz_mask); + } + if (head_msdu) { + uint16_t seq_num; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + + /* + * This logic is not quite correct - the last_seq value should + * be the sequence number of the final MPDU released rather than + * the initial MPDU released. + * However, tracking the sequence number of the first MPDU in + * the released batch works well enough: + * For Peregrine and Rome, the last_seq is checked only for + * non-aggregate cases, where only one MPDU at a time is + * released. + * For Riva, Pronto, and Northstar, the last_seq is checked to + * filter out late-arriving rx frames, whose sequence number + * will be less than the first MPDU in this release batch. + */ + seq_num = htt_rx_mpdu_desc_seq_num( + htt_pdev, + htt_rx_msdu_desc_retrieve(htt_pdev, + head_msdu), false); + peer->tids_last_seq[tid] = seq_num; + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } + /* + * If the rx reorder timeout is handled by host SW rather than the + * target's rx reorder logic, then stop the timer here. + * (If there are remaining rx holes, then the timer will be restarted.) + */ + OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid); +} + +void +ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, + unsigned int idx_start, + unsigned int idx_end, enum htt_rx_flush_action action) +{ + struct ol_txrx_pdev_t *pdev; + unsigned int win_sz; + uint8_t win_sz_mask; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + qdf_nbuf_t head_msdu = NULL; + qdf_nbuf_t tail_msdu = NULL; + + pdev = vdev->pdev; + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + /* a idx_end value of 0xffff means to flush the entire array */ + if (idx_end == 0xffff) { + idx_end = idx_start; + /* + * The array is being flushed in entirety because the block + * ack window has been shifted to a new position that does not + * overlap with the old position. (Or due to reception of a + * DELBA.) + * Thus, since the block ack window is essentially being reset, + * reset the "next release index". + */ + peer->tids_next_rel_idx[tid] = + OL_RX_REORDER_IDX_INIT(0 /*n/a */, win_sz, win_sz_mask); + } else { + peer->tids_next_rel_idx[tid] = (uint16_t) idx_end; + } + + idx_start &= win_sz_mask; + idx_end &= win_sz_mask; + + do { + rx_reorder_array_elem = + &peer->tids_rx_reorder[tid].array[idx_start]; + idx_start = (idx_start + 1); + OL_RX_REORDER_IDX_WRAP(idx_start, win_sz, win_sz_mask); + + if (rx_reorder_array_elem->head) { + OL_RX_REORDER_MPDU_CNT_DECR(&peer->tids_rx_reorder[tid], + 1); + if (!head_msdu) { + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + continue; + } + qdf_nbuf_set_next(tail_msdu, + rx_reorder_array_elem->head); + tail_msdu = rx_reorder_array_elem->tail; + rx_reorder_array_elem->head = + rx_reorder_array_elem->tail = NULL; + } + } while (idx_start != idx_end); + + ol_rx_defrag_waitlist_remove(peer, tid); + + if (head_msdu) { + uint16_t seq_num; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + + seq_num = htt_rx_mpdu_desc_seq_num( + htt_pdev, + htt_rx_msdu_desc_retrieve(htt_pdev, head_msdu), false); + peer->tids_last_seq[tid] = seq_num; + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + if (action == htt_rx_flush_release) { + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } else { + do { + qdf_nbuf_t next; + + next = qdf_nbuf_next(head_msdu); + htt_rx_desc_frame_free(pdev->htt_pdev, + head_msdu); + head_msdu = next; + } while (head_msdu); + } + } + /* + * If the rx reorder array is empty, then reset the last_seq value - + * it is likely that a BAR or a sequence number shift caused the + * sequence number to jump, so the old last_seq value is not relevant. + */ + if (OL_RX_REORDER_NO_HOLES(&peer->tids_rx_reorder[tid])) + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */ + + OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid); +} + +void +ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer, + unsigned int tid, unsigned int *idx_end) +{ + unsigned int win_sz, win_sz_mask; + unsigned int idx_start = 0, tmp_idx = 0; + + win_sz = peer->tids_rx_reorder[tid].win_sz; + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + + OL_RX_REORDER_IDX_START_SELF_SELECT(peer, tid, &idx_start); + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + /* bypass the initial hole */ + while (tmp_idx != idx_start && + !peer->tids_rx_reorder[tid].array[tmp_idx].head) { + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + } + /* bypass the present frames following the initial hole */ + while (tmp_idx != idx_start && + peer->tids_rx_reorder[tid].array[tmp_idx].head) { + tmp_idx++; + OL_RX_REORDER_IDX_WRAP(tmp_idx, win_sz, win_sz_mask); + } + /* + * idx_end is exclusive rather than inclusive. + * In other words, it is the index of the first slot of the second + * hole, rather than the index of the final present frame following + * the first hole. + */ + *idx_end = tmp_idx; +} + +#ifdef HL_RX_AGGREGATION_HOLE_DETECTION + +/** + * ol_rx_reorder_detect_hole - ol rx reorder detect hole + * @peer: ol_txrx_peer_t + * @tid: tid + * @idx_start: idx_start + * + * Return: void + */ +static void ol_rx_reorder_detect_hole(struct ol_txrx_peer_t *peer, + uint32_t tid, + uint32_t idx_start) +{ + uint32_t win_sz_mask, next_rel_idx, hole_size; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("Invalid tid: %u", tid); + return; + } + + if (peer->tids_next_rel_idx[tid] == INVALID_REORDER_INDEX) + return; + + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + /* Return directly if block-ack not enable */ + if (win_sz_mask == 0) + return; + + idx_start &= win_sz_mask; + next_rel_idx = peer->tids_next_rel_idx[tid] & win_sz_mask; + + if (idx_start != next_rel_idx) { + hole_size = ((int)idx_start - (int)next_rel_idx) & win_sz_mask; + + ol_rx_aggregation_hole(hole_size); + } + + return; +} + +#else + +/** + * ol_rx_reorder_detect_hole - ol rx reorder detect hole + * @peer: ol_txrx_peer_t + * @tid: tid + * @idx_start: idx_start + * + * Return: void + */ +static void ol_rx_reorder_detect_hole(struct ol_txrx_peer_t *peer, + uint32_t tid, + uint32_t idx_start) +{ + /* no-op */ +} + +#endif + +void +ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer) +{ + int tid; + + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + ol_rx_reorder_flush(vdev, peer, tid, 0, 0, + htt_rx_flush_discard); + } + OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer); +} + +/* functions called by HTT */ + +void +ol_rx_addba_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint8_t win_sz, uint16_t start_seq_num, uint8_t failed) +{ + uint8_t round_pwr2_win_sz; + unsigned int array_size; + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder; + void *array_mem = NULL; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("invalid tid, %u", tid); + WARN_ON(1); + return; + } + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + ol_txrx_err("not able to find peer, %u", peer_id); + return; + } + + if (pdev->cfg.host_addba) { + ol_ctrl_rx_addba_complete(pdev->ctrl_pdev, + &peer->mac_addr.raw[0], tid, failed); + } + if (failed) + return; + + peer->tids_last_seq[tid] = IEEE80211_SEQ_MAX; /* invalid */ + rx_reorder = &peer->tids_rx_reorder[tid]; + + TXRX_ASSERT2(win_sz <= 64); + round_pwr2_win_sz = OL_RX_REORDER_ROUND_PWR2(win_sz); + array_size = + round_pwr2_win_sz * sizeof(struct ol_rx_reorder_array_elem_t); + + array_mem = qdf_mem_malloc(array_size); + if (!array_mem) + return; + + if (rx_reorder->array != &rx_reorder->base) { + ol_txrx_info("delete array for tid %d", tid); + qdf_mem_free(rx_reorder->array); + } + + rx_reorder->array = array_mem; + rx_reorder->win_sz = win_sz; + TXRX_ASSERT1(rx_reorder->array); + + rx_reorder->win_sz_mask = round_pwr2_win_sz - 1; + rx_reorder->num_mpdus = 0; + + peer->tids_next_rel_idx[tid] = + OL_RX_REORDER_IDX_INIT(start_seq_num, rx_reorder->win_sz, + rx_reorder->win_sz_mask); +} + +void +ol_rx_delba_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id, uint8_t tid) +{ + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_t *rx_reorder; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("invalid tid, %u", tid); + WARN_ON(1); + return; + } + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + ol_txrx_err("not able to find peer, %u", peer_id); + return; + } + + peer->tids_next_rel_idx[tid] = INVALID_REORDER_INDEX; + rx_reorder = &peer->tids_rx_reorder[tid]; + + /* check that there really was a block ack agreement */ + TXRX_ASSERT1(rx_reorder->win_sz_mask != 0); + /* + * Deallocate the old rx reorder array. + * The call to ol_rx_reorder_init below + * will reset rx_reorder->array to point to + * the single-element statically-allocated reorder array + * used for non block-ack cases. + */ + if (rx_reorder->array != &rx_reorder->base) { + ol_txrx_dbg("delete reorder array, tid:%d", + tid); + qdf_mem_free(rx_reorder->array); + } + + /* set up the TID with default parameters (ARQ window size = 1) */ + ol_rx_reorder_init(rx_reorder, tid); +} + +void +ol_rx_flush_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t idx_start, + uint16_t idx_end, enum htt_rx_flush_action action) +{ + struct ol_txrx_vdev_t *vdev = NULL; + void *rx_desc; + struct ol_txrx_peer_t *peer; + int idx; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("Invalid tid: %u", tid); + return; + } + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) + vdev = peer->vdev; + else + return; + + OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev); + + idx = idx_start & peer->tids_rx_reorder[tid].win_sz_mask; + rx_reorder_array_elem = &peer->tids_rx_reorder[tid].array[idx]; + if (rx_reorder_array_elem->head) { + rx_desc = + htt_rx_msdu_desc_retrieve(htt_pdev, + rx_reorder_array_elem->head); + if (htt_rx_msdu_is_frag(htt_pdev, rx_desc)) { + ol_rx_reorder_flush_frag(htt_pdev, peer, tid, + idx_start); + /* + * Assuming flush message sent separately for frags + * and for normal frames + */ + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); + return; + } + } + + if (action == htt_rx_flush_release) + ol_rx_reorder_detect_hole(peer, tid, idx_start); + + ol_rx_reorder_flush(vdev, peer, tid, idx_start, idx_end, action); + /* + * If the rx reorder timeout is handled by host SW, see if there are + * remaining rx holes that require the timer to be restarted. + */ + OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid); + OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev); +} + +void +ol_rx_pn_ind_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t tid, + uint16_t seq_num_start, + uint16_t seq_num_end, uint8_t pn_ie_cnt, uint8_t *pn_ie) +{ + struct ol_txrx_vdev_t *vdev = NULL; + void *rx_desc; + struct ol_txrx_peer_t *peer; + struct ol_rx_reorder_array_elem_t *rx_reorder_array_elem; + unsigned int win_sz_mask; + qdf_nbuf_t head_msdu = NULL; + qdf_nbuf_t tail_msdu = NULL; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + uint16_t seq_num; + int i = 0; + + if (tid >= OL_TXRX_NUM_EXT_TIDS) { + ol_txrx_err("Invalid tid: %u", tid); + WARN_ON(1); + return; + } + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + + if (!peer) { + /* + * If we can't find a peer send this packet to OCB interface + * using OCB self peer + */ + if (!ol_txrx_get_ocb_peer(pdev, &peer)) + peer = NULL; + } + + if (peer) + vdev = peer->vdev; + else + return; + + qdf_atomic_set(&peer->fw_pn_check, 1); + /*TODO: Fragmentation case */ + win_sz_mask = peer->tids_rx_reorder[tid].win_sz_mask; + seq_num_start &= win_sz_mask; + seq_num_end &= win_sz_mask; + seq_num = seq_num_start; + + do { + rx_reorder_array_elem = + &peer->tids_rx_reorder[tid].array[seq_num]; + + if (rx_reorder_array_elem->head) { + if (pn_ie_cnt && seq_num == (int)(pn_ie[i])) { + qdf_nbuf_t msdu, next_msdu, mpdu_head, + mpdu_tail; + static uint32_t last_pncheck_print_time; + /* Do not need to initialize as C does it */ + + uint32_t current_time_ms; + union htt_rx_pn_t pn = { 0 }; + int index, pn_len; + + mpdu_head = msdu = rx_reorder_array_elem->head; + mpdu_tail = rx_reorder_array_elem->tail; + + pn_ie_cnt--; + i++; + rx_desc = htt_rx_msdu_desc_retrieve(htt_pdev, + msdu); + index = htt_rx_msdu_is_wlan_mcast( + pdev->htt_pdev, rx_desc) + ? txrx_sec_mcast + : txrx_sec_ucast; + pn_len = pdev->rx_pn[peer->security[index]. + sec_type].len; + htt_rx_mpdu_desc_pn(htt_pdev, rx_desc, &pn, + pn_len); + + current_time_ms = qdf_system_ticks_to_msecs( + qdf_system_ticks()); + if (TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS < + (current_time_ms - + last_pncheck_print_time)) { + last_pncheck_print_time = + current_time_ms; + ol_txrx_warn( + "Tgt PN check failed - TID %d, peer %pK " + "("QDF_MAC_ADDR_FMT")\n" + " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + pn.pn128[1], + pn.pn128[0], + pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_desc, + false)); + } else { + ol_txrx_dbg( + "Tgt PN check failed - TID %d, peer %pK " + "("QDF_MAC_ADDR_FMT")\n" + " PN (u64 x2)= 0x%08llx %08llx (LSBs = %lld)\n" + " new seq num = %d\n", + tid, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw), + pn.pn128[1], + pn.pn128[0], + pn.pn128[0] & 0xffffffffffffULL, + htt_rx_mpdu_desc_seq_num(htt_pdev, + rx_desc, + false)); + } + ol_rx_err(pdev->ctrl_pdev, vdev->vdev_id, + peer->mac_addr.raw, tid, + htt_rx_mpdu_desc_tsf32(htt_pdev, + rx_desc), + OL_RX_ERR_PN, mpdu_head, NULL, 0); + + /* free all MSDUs within this MPDU */ + do { + next_msdu = qdf_nbuf_next(msdu); + htt_rx_desc_frame_free(htt_pdev, msdu); + if (msdu == mpdu_tail) + break; + msdu = next_msdu; + } while (1); + + } else { + if (!head_msdu) { + head_msdu = rx_reorder_array_elem->head; + tail_msdu = rx_reorder_array_elem->tail; + } else { + qdf_nbuf_set_next( + tail_msdu, + rx_reorder_array_elem->head); + tail_msdu = rx_reorder_array_elem->tail; + } + } + rx_reorder_array_elem->head = NULL; + rx_reorder_array_elem->tail = NULL; + } + seq_num = (seq_num + 1) & win_sz_mask; + } while (seq_num != seq_num_end); + + if (head_msdu) { + /* rx_opt_proc takes a NULL-terminated list of msdu netbufs */ + qdf_nbuf_set_next(tail_msdu, NULL); + peer->rx_opt_proc(vdev, peer, tid, head_msdu); + } +} + +#if defined(ENABLE_RX_REORDER_TRACE) + +A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev) +{ + int num_elems; + + num_elems = 1 << TXRX_RX_REORDER_TRACE_SIZE_LOG2; + pdev->rx_reorder_trace.idx = 0; + pdev->rx_reorder_trace.cnt = 0; + pdev->rx_reorder_trace.mask = num_elems - 1; + pdev->rx_reorder_trace.data = qdf_mem_malloc( + sizeof(*pdev->rx_reorder_trace.data) * num_elems); + if (!pdev->rx_reorder_trace.data) + return A_NO_MEMORY; + + while (--num_elems >= 0) + pdev->rx_reorder_trace.data[num_elems].seq_num = 0xffff; + + return A_OK; +} + +void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev) +{ + qdf_mem_free(pdev->rx_reorder_trace.data); +} + +void +ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, + uint8_t tid, + uint16_t reorder_idx, uint16_t seq_num, int num_mpdus) +{ + uint32_t idx = pdev->rx_reorder_trace.idx; + + pdev->rx_reorder_trace.data[idx].tid = tid; + pdev->rx_reorder_trace.data[idx].reorder_idx = reorder_idx; + pdev->rx_reorder_trace.data[idx].seq_num = seq_num; + pdev->rx_reorder_trace.data[idx].num_mpdus = num_mpdus; + pdev->rx_reorder_trace.cnt++; + idx++; + pdev->rx_reorder_trace.idx = idx & pdev->rx_reorder_trace.mask; +} + +void +ol_rx_reorder_trace_display(ol_txrx_pdev_handle pdev, int just_once, int limit) +{ + static int print_count; + uint32_t i, start, end; + uint64_t cnt; + int elems; + + if (print_count != 0 && just_once) + return; + + print_count++; + + end = pdev->rx_reorder_trace.idx; + if (pdev->rx_reorder_trace.data[end].seq_num == 0xffff) { + /* trace log has not yet wrapped around - start at the top */ + start = 0; + cnt = 0; + } else { + start = end; + cnt = pdev->rx_reorder_trace.cnt - + (pdev->rx_reorder_trace.mask + 1); + } + elems = (end - 1 - start) & pdev->rx_reorder_trace.mask; + if (limit > 0 && elems > limit) { + int delta; + + delta = elems - limit; + start += delta; + start &= pdev->rx_reorder_trace.mask; + cnt += delta; + } + + i = start; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " log array seq"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " count idx tid idx num (LSBs)"); + do { + uint16_t seq_num, reorder_idx; + + seq_num = pdev->rx_reorder_trace.data[i].seq_num; + reorder_idx = pdev->rx_reorder_trace.data[i].reorder_idx; + if (seq_num < (1 << 14)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " %6lld %4d %3d %4d %4d (%d)", + cnt, i, pdev->rx_reorder_trace.data[i].tid, + reorder_idx, seq_num, seq_num & 63); + } else { + int err = TXRX_SEQ_NUM_ERR(seq_num); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " %6lld %4d err %d (%d MPDUs)", + cnt, i, err, + pdev->rx_reorder_trace.data[i].num_mpdus); + } + cnt++; + i++; + i &= pdev->rx_reorder_trace.mask; + } while (i != end); +} + +#endif /* ENABLE_RX_REORDER_TRACE */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h new file mode 100644 index 0000000000..07fa12fca8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2011, 2014-2017, 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_RX_REORDER__H_ +#define _OL_RX_REORDER__H_ + +#include /* qdf_nbuf_t, etc. */ + +#include /* ol_txrx_peer_t, etc. */ + +#include /* ol_rx_reorder_t */ + +void +ol_rx_reorder_store(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, + unsigned int reorder_array_index, + qdf_nbuf_t head_msdu, qdf_nbuf_t tail_msdu); + +void +ol_rx_reorder_release(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, + unsigned int seq_num_start, unsigned int seq_num_end); + +void +ol_rx_reorder_flush(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, + unsigned int seq_num_start, + unsigned int seq_num_end, enum htt_rx_flush_action action); + +/** + * @brief - find end of first range of present MPDUs after the initial rx hole + * @param[in] peer - which sender's data is being checked + * @param[in] tid - which type of data is being checked + * @param[out] idx_end - the reorder array index holding the last MPDU in the + * range of in-order MPDUs that following the initial hole. + * Note that this is the index of the last in-order MPDU following the + * first hole, rather than the starting index of the second hole. + */ +void +ol_rx_reorder_first_hole(struct ol_txrx_peer_t *peer, + unsigned int tid, unsigned int *idx_end); + +void +ol_rx_reorder_peer_cleanup(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer); + +void ol_rx_reorder_init(struct ol_rx_reorder_t *rx_reorder, uint8_t tid); + +enum htt_rx_status +ol_rx_seq_num_check(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint8_t tid, void *rx_mpdu_desc); + +/* + * Peregrine and Rome: do sequence number checking in the host + * for peer-TIDs without aggregation enabled + */ + +#define OL_RX_SEQ_NUM_CHECK(pdev, peer, tid, rx_mpdu_desc) \ + (pdev->rx.flags.dup_check && peer->tids_rx_reorder[tid].win_sz_mask == \ + 0) ? ol_rx_seq_num_check(pdev, peer, tid, rx_mpdu_desc) : \ + htt_rx_status_ok + +#endif /* _OL_RX_REORDER__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c new file mode 100644 index 0000000000..487b140b25 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=== header file includes ===*/ +/* generic utilities */ +#include /* qdf_nbuf_t, etc. */ +#include +#include + +/* datapath internal interfaces */ +#include /* TXRX_ASSERT, etc. */ +#include /* ol_rx_reorder_flush, etc. */ +#include + +#ifdef QCA_SUPPORT_OL_RX_REORDER_TIMEOUT + +void ol_rx_reorder_timeout_remove(struct ol_txrx_peer_t *peer, unsigned int tid) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + int ac; + + pdev = peer->vdev->pdev; + ac = TXRX_TID_TO_WMM_AC(tid); + rx_reorder_timeout_ac = &pdev->rx.reorder_timeout.access_cats[ac]; + list_elem = &peer->tids_rx_reorder[tid].timeout; + if (!list_elem->active) { + /* this element has already been removed */ + return; + } + list_elem->active = 0; + TAILQ_REMOVE(&rx_reorder_timeout_ac->virtual_timer_list, list_elem, + reorder_timeout_list_elem); +} + +static void +ol_rx_reorder_timeout_start(struct ol_tx_reorder_cat_timeout_t + *rx_reorder_timeout_ac, uint32_t time_now_ms) +{ + uint32_t duration_ms; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + + list_elem = TAILQ_FIRST(&rx_reorder_timeout_ac->virtual_timer_list); + + duration_ms = list_elem->timestamp_ms - time_now_ms; + qdf_timer_start(&rx_reorder_timeout_ac->timer, duration_ms); +} + +static inline void +ol_rx_reorder_timeout_add(struct ol_txrx_peer_t *peer, uint8_t tid) +{ + uint32_t time_now_ms; + struct ol_txrx_pdev_t *pdev; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + struct ol_rx_reorder_timeout_list_elem_t *list_elem; + int ac; + int start; + + pdev = peer->vdev->pdev; + ac = TXRX_TID_TO_WMM_AC(tid); + rx_reorder_timeout_ac = &pdev->rx.reorder_timeout.access_cats[ac]; + list_elem = &peer->tids_rx_reorder[tid].timeout; + + list_elem->active = 1; + list_elem->peer = peer; + list_elem->tid = tid; + + /* set the expiration timestamp */ + time_now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + list_elem->timestamp_ms = + time_now_ms + rx_reorder_timeout_ac->duration_ms; + + /* add to the queue */ + start = TAILQ_EMPTY(&rx_reorder_timeout_ac->virtual_timer_list); + TAILQ_INSERT_TAIL(&rx_reorder_timeout_ac->virtual_timer_list, + list_elem, reorder_timeout_list_elem); + if (start) + ol_rx_reorder_timeout_start(rx_reorder_timeout_ac, time_now_ms); +} + +void ol_rx_reorder_timeout_update(struct ol_txrx_peer_t *peer, uint8_t tid) +{ + if (!peer) + return; + + /* + * If there are no holes, i.e. no queued frames, + * then timeout doesn't apply. + */ + if (peer->tids_rx_reorder[tid].num_mpdus == 0) + return; + + /* + * If the virtual timer for this peer-TID is already running, + * then leave it. + */ + if (peer->tids_rx_reorder[tid].timeout.active) + return; + + ol_rx_reorder_timeout_add(peer, tid); +} + +static void ol_rx_reorder_timeout(void *arg) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_rx_reorder_timeout_list_elem_t *list_elem, *tmp; + uint32_t time_now_ms; + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + + rx_reorder_timeout_ac = (struct ol_tx_reorder_cat_timeout_t *)arg; + time_now_ms = qdf_system_ticks_to_msecs(qdf_system_ticks()); + + pdev = rx_reorder_timeout_ac->pdev; + qdf_spin_lock(&pdev->rx.mutex); +/* TODO: conditionally take mutex lock during regular rx */ + TAILQ_FOREACH_SAFE(list_elem, + &rx_reorder_timeout_ac->virtual_timer_list, + reorder_timeout_list_elem, tmp) { + unsigned int idx_start, idx_end; + struct ol_txrx_peer_t *peer; + + if (list_elem->timestamp_ms > time_now_ms) + break; /* time has not expired yet for this element */ + + list_elem->active = 0; + /* remove the expired element from the list */ + TAILQ_REMOVE(&rx_reorder_timeout_ac->virtual_timer_list, + list_elem, reorder_timeout_list_elem); + + peer = list_elem->peer; + + idx_start = 0xffff; /* start from next_rel_idx */ + ol_rx_reorder_first_hole(peer, list_elem->tid, &idx_end); + ol_rx_reorder_flush(peer->vdev, + peer, + list_elem->tid, + idx_start, idx_end, htt_rx_flush_release); + } + /* restart the timer if unexpired elements are left in the list */ + if (!TAILQ_EMPTY(&rx_reorder_timeout_ac->virtual_timer_list)) + ol_rx_reorder_timeout_start(rx_reorder_timeout_ac, time_now_ms); + + qdf_spin_unlock(&pdev->rx.mutex); +} + +void ol_rx_reorder_timeout_init(struct ol_txrx_pdev_t *pdev) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(pdev->rx.reorder_timeout.access_cats); + i++) { + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + + rx_reorder_timeout_ac = + &pdev->rx.reorder_timeout.access_cats[i]; + /* init the per-AC timers */ + qdf_timer_init(pdev->osdev, + &rx_reorder_timeout_ac->timer, + ol_rx_reorder_timeout, + rx_reorder_timeout_ac, + QDF_TIMER_TYPE_SW); + /* init the virtual timer list */ + TAILQ_INIT(&rx_reorder_timeout_ac->virtual_timer_list); + rx_reorder_timeout_ac->pdev = pdev; + } + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_VO].duration_ms = 40; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_VI].duration_ms = 100; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_BE].duration_ms = 100; + pdev->rx.reorder_timeout.access_cats[TXRX_WMM_AC_BK].duration_ms = 100; +} + +void ol_rx_reorder_timeout_peer_cleanup(struct ol_txrx_peer_t *peer) +{ + int tid; + + for (tid = 0; tid < OL_TXRX_NUM_EXT_TIDS; tid++) { + if (peer->tids_rx_reorder[tid].timeout.active) + ol_rx_reorder_timeout_remove(peer, tid); + } +} + +void ol_rx_reorder_timeout_cleanup(struct ol_txrx_pdev_t *pdev) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(pdev->rx.reorder_timeout.access_cats); + i++) { + struct ol_tx_reorder_cat_timeout_t *rx_reorder_timeout_ac; + + rx_reorder_timeout_ac = + &pdev->rx.reorder_timeout.access_cats[i]; + qdf_timer_stop(&rx_reorder_timeout_ac->timer); + qdf_timer_free(&rx_reorder_timeout_ac->timer); + } +} + +#endif /* QCA_SUPPORT_OL_RX_REORDER_TIMEOUT */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h new file mode 100644 index 0000000000..9f095015eb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_rx_reorder_timeout.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2012, 2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_RX_REORDER_TIMEOUT__H_ +#define _OL_RX_REORDER_TIMEOUT__H_ + +#include /* ol_txrx_vdev_t, etc. */ +#ifdef QCA_SUPPORT_OL_RX_REORDER_TIMEOUT + +void ol_rx_reorder_timeout_init(struct ol_txrx_pdev_t *pdev); +void ol_rx_reorder_timeout_cleanup(struct ol_txrx_pdev_t *pdev); +void ol_rx_reorder_timeout_remove(struct ol_txrx_peer_t *peer, + unsigned int tid); +void ol_rx_reorder_timeout_update(struct ol_txrx_peer_t *peer, uint8_t tid); +void ol_rx_reorder_timeout_peer_cleanup(struct ol_txrx_peer_t *peer); + +#define OL_RX_REORDER_TIMEOUT_INIT ol_rx_reorder_timeout_init +#define OL_RX_REORDER_TIMEOUT_PEER_CLEANUP ol_rx_reorder_timeout_peer_cleanup +#define OL_RX_REORDER_TIMEOUT_CLEANUP ol_rx_reorder_timeout_cleanup +#define OL_RX_REORDER_TIMEOUT_REMOVE ol_rx_reorder_timeout_remove +#define OL_RX_REORDER_TIMEOUT_UPDATE ol_rx_reorder_timeout_update +#define OL_RX_REORDER_TIMEOUT_PEER_TID_INIT(peer, tid) \ + (peer)->tids_rx_reorder[(tid)].timeout.active = 0 +#define OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev) \ + qdf_spin_lock(&(pdev)->rx.mutex) +#define OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev) \ + qdf_spin_unlock(&(pdev)->rx.mutex) + +#else + +#define OL_RX_REORDER_TIMEOUT_INIT(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_PEER_CLEANUP(peer) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_CLEANUP(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_REMOVE(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_UPDATE(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_PEER_TID_INIT(peer, tid) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_MUTEX_LOCK(pdev) /* no-op */ +#define OL_RX_REORDER_TIMEOUT_MUTEX_UNLOCK(pdev) /* no-op */ + +#endif /* QCA_SUPPORT_OL_RX_REORDER_TIMEOUT */ + +#endif /* _OL_RX_REORDER_TIMEOUT__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx.c new file mode 100644 index 0000000000..9caeabc078 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_classify, ol_tx_classify_mgmt */ +#include /* ol_tx_enqueue */ +#include /* ol_tx_sched */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include + +/** + * ol_tx_data() - send data frame + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * @skb: skb + * + * Return: skb/NULL for success + */ +qdf_nbuf_t ol_tx_data(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + qdf_nbuf_t skb) +{ + struct ol_txrx_pdev_t *pdev; + qdf_nbuf_t ret; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (qdf_unlikely(!vdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s:vdev is null", __func__); + return skb; + } + + pdev = vdev->pdev; + + if (qdf_unlikely(!pdev)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s:pdev is null", __func__); + return skb; + } + + if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) + && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) + && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) + qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); + + /* Terminate the (single-element) list of tx frames */ + qdf_nbuf_set_next(skb, NULL); + ret = OL_TX_SEND(vdev, skb); + if (ret) { + ol_txrx_dbg("Failed to tx"); + return ret; + } + + return NULL; +} + +#ifdef IPA_OFFLOAD +qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + qdf_nbuf_t skb) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id( + soc, OL_TXRX_PDEV_ID); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + qdf_nbuf_t ret; + + if (qdf_unlikely(!pdev)) { + ol_txrx_err("Invalid pdev"); + return skb; + } + if (qdf_unlikely(!vdev)) { + ol_txrx_err("Invalid vdev, vdev_id:%d", vdev_id); + return skb; + } + + if ((ol_cfg_is_ip_tcp_udp_checksum_offload_enabled(pdev->ctrl_pdev)) + && (qdf_nbuf_get_protocol(skb) == htons(ETH_P_IP)) + && (qdf_nbuf_get_ip_summed(skb) == CHECKSUM_PARTIAL)) + qdf_nbuf_set_ip_summed(skb, CHECKSUM_COMPLETE); + + /* Terminate the (single-element) list of tx frames */ + qdf_nbuf_set_next(skb, NULL); + + /* + * Add SKB to internal tracking table before further processing + * in WLAN driver. + */ + qdf_net_buf_debug_acquire_skb(skb, __FILE__, __LINE__); + + ret = OL_TX_SEND((struct ol_txrx_vdev_t *)vdev, skb); + if (ret) { + ol_txrx_dbg("Failed to tx"); + return ret; + } + + return NULL; +} +#endif + +void +ol_txrx_data_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + ol_txrx_data_tx_cb callback, void *ctxt) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + struct ol_txrx_pdev_t *pdev; + + if (!vdev || !vdev->pdev) + return; + + pdev = vdev->pdev; + pdev->tx_data_callback.func = callback; + pdev->tx_data_callback.ctxt = ctxt; +} + +QDF_STATUS +ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + + if (!pdev) + return QDF_STATUS_E_FAILURE; + + TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); + pdev->tx_mgmt_cb.download_cb = download_cb; + pdev->tx_mgmt_cb.ota_ack_cb = ota_ack_cb; + pdev->tx_mgmt_cb.ctxt = ctxt; + + return QDF_STATUS_SUCCESS; +} + +int +ol_txrx_mgmt_send_ext(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + qdf_nbuf_t tx_mgmt_frm, uint8_t type, + uint8_t use_6mbps, uint16_t chanfreq) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + struct ol_txrx_pdev_t *pdev; + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_msdu_info_t tx_msdu_info; + int result = 0; + + if (!vdev || !vdev->pdev) + return QDF_STATUS_E_FAULT; + + pdev = vdev->pdev; + tx_msdu_info.tso_info.is_tso = 0; + + tx_msdu_info.htt.action.use_6mbps = use_6mbps; + tx_msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; + tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; + tx_msdu_info.htt.action.do_tx_complete = + pdev->tx_mgmt_cb.ota_ack_cb ? 1 : 0; + + /* + * FIX THIS: l2_hdr_type should only specify L2 header type + * The Peregrine/Rome HTT layer provides the FW with a "pkt type" + * that is a combination of L2 header type and 802.11 frame type. + * If the 802.11 frame type is "mgmt", then the HTT pkt type is "mgmt". + * But if the 802.11 frame type is "data", then the HTT pkt type is + * the L2 header type (more or less): 802.3 vs. Native WiFi + * (basic 802.11). + * (Or the header type can be "raw", which is any version of the 802.11 + * header, and also implies that some of the offloaded tx data + * processing steps may not apply.) + * For efficiency, the Peregrine/Rome HTT uses the msdu_info's + * l2_hdr_type field to program the HTT pkt type. Thus, this txrx SW + * needs to overload the l2_hdr_type to indicate whether the frame is + * data vs. mgmt, as well as 802.3 L2 header vs. 802.11 L2 header. + * To fix this, the msdu_info's l2_hdr_type should be left specifying + * just the L2 header type. For mgmt frames, there should be a + * separate function to patch the HTT pkt type to store a "mgmt" value + * rather than the L2 header type. Then the HTT pkt type can be + * programmed efficiently for data frames, and the msdu_info's + * l2_hdr_type field won't be confusingly overloaded to hold the 802.11 + * frame type rather than the L2 header type. + */ + /* + * FIX THIS: remove duplication of htt_frm_type_mgmt and + * htt_pkt_type_mgmt + * The htt module expects a "enum htt_pkt_type" value. + * The htt_dxe module expects a "enum htt_frm_type" value. + * This needs to be cleaned up, so both versions of htt use a + * consistent method of specifying the frame type. + */ +#ifdef QCA_SUPPORT_INTEGRATED_SOC + /* tx mgmt frames always come with a 802.11 header */ + tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_native_wifi; + tx_msdu_info.htt.info.frame_type = htt_frm_type_mgmt; +#else + tx_msdu_info.htt.info.l2_hdr_type = htt_pkt_type_mgmt; + tx_msdu_info.htt.info.frame_type = htt_pkt_type_mgmt; +#endif + + tx_msdu_info.peer = NULL; + + tx_desc = ol_txrx_mgmt_tx_desc_alloc(pdev, vdev, tx_mgmt_frm, + &tx_msdu_info); + if (!tx_desc) + return -EINVAL; /* can't accept the tx mgmt frame */ + + TXRX_STATS_MSDU_INCR(pdev, tx.mgmt, tx_mgmt_frm); + TXRX_ASSERT1(type < OL_TXRX_MGMT_NUM_TYPES); + tx_desc->pkt_type = type + OL_TXRX_MGMT_TYPE_BASE; + + result = ol_txrx_mgmt_send_frame(vdev, tx_desc, tx_mgmt_frm, + &tx_msdu_info, chanfreq); + + return 0; /* accepted the tx mgmt frame */ +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx.h new file mode 100644 index 0000000000..7ad3355dc2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_tx.h + * @brief Internal definitions for the high-level tx module. + */ +#ifndef _OL_TX__H_ +#define _OL_TX__H_ + +#include /* qdf_nbuf_t */ +#include +#include /* ol_txrx_vdev_t, etc. */ +#include /* ol_tx_spec */ +#include +#include /* ol_tx_desc_t, ol_txrx_msdu_info_t */ +#include +#include + +#ifdef IPA_OFFLOAD +/** + * ol_tx_send_ipa_data_frame() - send IPA data frame + * @soc_hdl: datapath soc handle + * @vdev: virtual interface id + * @skb: skb + * + * Return: skb/ NULL is for success + */ +qdf_nbuf_t ol_tx_send_ipa_data_frame(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + qdf_nbuf_t skb); +#endif + +#ifdef CONFIG_LL_DP_SUPPORT +struct ol_tx_desc_t * +ol_tx_prepare_ll(ol_txrx_vdev_handle vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info); +#endif + +qdf_nbuf_t ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); +#ifdef WLAN_FEATURE_FASTPATH +qdf_nbuf_t ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); + +void ol_tx_setup_fastpath_ce_handles(struct hif_opaque_softc *osc, + struct ol_txrx_pdev_t *pdev); +#else +static inline +void ol_tx_setup_fastpath_ce_handles(struct hif_opaque_softc *osc, + struct ol_txrx_pdev_t *pdev) +{ } + +qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); +#endif + +qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); + +#ifdef CONFIG_HL_SUPPORT +#define OL_TX_SEND ol_tx_hl +#else +#define OL_TX_SEND OL_TX_LL +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +#define OL_TX_LL ol_tx_ll_queue +#else +#define OL_TX_LL ol_tx_ll_wrapper +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +void ol_tx_hl_vdev_bundle_timer(void *context); + +void ol_tx_hl_queue_flush_all(struct ol_txrx_vdev_t *vdev); +qdf_nbuf_t +ol_tx_hl_pdev_queue_send_all(struct ol_txrx_pdev_t *pdev); +#else +static inline +void ol_tx_hl_vdev_bundle_timer(void *context) +{ +} + +static inline +void ol_tx_hl_queue_flush_all(struct ol_txrx_vdev_t *vdev) +{ +} + +static inline +qdf_nbuf_t +ol_tx_hl_pdev_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + return NULL; +} +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void ol_tx_vdev_ll_pause_queue_send(void *context); +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev); +#else +static inline void ol_tx_vdev_ll_pause_queue_send(void *context) +{ +} +static inline +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +/** + * ol_tx_comp_hw_to_qdf_status(): map ol hw to qdf status + * @status: hw status + * + * Return: qdf tx rx status + */ +static inline enum qdf_dp_tx_rx_status +ol_tx_comp_hw_to_qdf_status(uint16_t status) +{ + switch (status) { + case HTT_TX_COMPL_IND_STAT_OK: + return QDF_TX_RX_STATUS_OK; + case HTT_TX_COMPL_IND_STAT_DISCARD: + case HTT_TX_COMPL_IND_STAT_DROP: + return QDF_TX_RX_STATUS_FW_DISCARD; + case HTT_TX_COMPL_IND_STAT_NO_ACK: + return QDF_TX_RX_STATUS_NO_ACK; + default: + return QDF_TX_RX_STATUS_DEFAULT; + } +} + +static inline +int ol_txrx_tx_is_raw(enum ol_tx_spec tx_spec) +{ + return tx_spec & + (OL_TX_SPEC_RAW | OL_TX_SPEC_NO_AGGR | OL_TX_SPEC_NO_ENCRYPT); +} + +static inline +uint8_t ol_txrx_tx_raw_subtype(enum ol_tx_spec tx_spec) +{ + uint8_t sub_type = 0x1; /* 802.11 MAC header present */ + + if (tx_spec & OL_TX_SPEC_NO_AGGR) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_AGGR_S; + if (tx_spec & OL_TX_SPEC_NO_ENCRYPT) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S; + if (tx_spec & OL_TX_SPEC_NWIFI_NO_ENCRYPT) + sub_type |= 0x1 << HTT_TX_MSDU_DESC_RAW_SUBTYPE_NO_ENCRYPT_S; + return sub_type; +} + +/** + * ol_tx_hl() - transmit tx frames for a HL system. + * @vdev: the virtual device transmit the data + * @msdu_list: the tx frames to send + * + * Return: NULL if all MSDUs are accepted + */ +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list); + +/** + * ol_tx_non_std() - Allow the control-path SW to send data frames + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * @tx_spec: what non-standard handling to apply to the tx data frames + * @msdu_list: NULL-terminated list of tx MSDUs + * + * Generally, all tx data frames come from the OS shim into the txrx layer. + * However, there are rare cases such as TDLS messaging where the UMAC + * control-path SW creates tx data frames. + * This UMAC SW can call this function to provide the tx data frames to + * the txrx layer. + * The UMAC SW can request a callback for these data frames after their + * transmission completes, by using the ol_txrx_data_tx_cb_set function + * to register a tx completion callback, and by specifying + * ol_tx_spec_no_free as the tx_spec arg when giving the frames to + * ol_tx_non_std. + * The MSDUs need to have the appropriate L2 header type (802.3 vs. 802.11), + * as specified by ol_cfg_frame_type(). + * + * Return: null - success, skb - failure + */ +#ifdef CONFIG_HL_SUPPORT +qdf_nbuf_t ol_tx_non_std_hl(struct ol_txrx_vdev_t *vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list); + +static inline qdf_nbuf_t +ol_tx_non_std(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_vdev_t *vdev; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) + return msdu_list; + else + return ol_tx_non_std_hl(vdev, tx_spec, msdu_list); +} +#else +qdf_nbuf_t ol_tx_non_std_ll(struct ol_txrx_vdev_t *vdev, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list); + +static inline qdf_nbuf_t +ol_tx_non_std(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_vdev_t *vdev; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) + return msdu_list; + else + return ol_tx_non_std_ll(vdev, tx_spec, msdu_list); +} +#endif + +/** + * ol_tx_trace_pkt() - Trace TX packet at OL layer + * + * @skb: skb to be traced + * @msdu_id: msdu_id of the packet + * @vdev_id: vdev_id of the packet + * @op_mode: Vdev Operation mode + * + * Return: None + */ +void ol_tx_trace_pkt(qdf_nbuf_t skb, uint16_t msdu_id, uint8_t vdev_id, + enum QDF_OPMODE op_mode); + +void ol_txrx_mgmt_tx_complete(void *ctxt, qdf_nbuf_t netbuf, int err); + +/** + * ol_txrx_mgmt_tx_cb_set() - Store a callback for delivery + * notifications for management frames. + * @soc: Datapath soc handle + * @pdev_id: Physical device instance id + * @type: the type of mgmt frame the callback is used for + * @download_cb: the callback for notification of delivery to the target + * @ota_ack_cb: the callback for notification of delivery to the peer + * @ctxt: context to use with the callback + * + * When the txrx SW receives notifications from the target that a tx frame + * has been delivered to its recipient, it will check if the tx frame + * is a management frame. If so, the txrx SW will check the management + * frame type specified when the frame was submitted for transmission. + * If there is a callback function registered for the type of management + * frame in question, the txrx code will invoke the callback to inform + * the management + control SW that the mgmt frame was delivered. + * This function is used by the control SW to store a callback pointer + * for a given type of management frame. + */ +QDF_STATUS +ol_txrx_mgmt_tx_cb_set(struct cdp_soc_t *soc, uint8_t pdev_id, uint8_t type, + ol_txrx_mgmt_tx_cb download_cb, + ol_txrx_mgmt_tx_cb ota_ack_cb, void *ctxt); + +/** + * ol_txrx_mgmt_send_ext() - Transmit a management frame + * @soc: Datapath soc handle + * @vdev_id: virtual interface id + * @tx_mgmt_frm: management frame to transmit + * @type: the type of management frame (determines what callback to use) + * @use_6mbps: specify whether management frame to transmit should + * use 6 Mbps rather than 1 Mbps min rate(for 5GHz band or P2P) + * @chanfreq: channel to transmit the frame on + * + * Send the specified management frame from the specified virtual device. + * The type is used for determining whether to invoke a callback to inform + * the sender that the tx mgmt frame was delivered, and if so, which + * callback to use. + * + * Return: 0 - the frame is accepted for transmission + * 1 - the frame was not accepted + */ +int +ol_txrx_mgmt_send_ext(struct cdp_soc_t *soc, uint8_t vdev_id, + qdf_nbuf_t tx_mgmt_frm, + uint8_t type, uint8_t use_6mbps, uint16_t chanfreq); + +qdf_nbuf_t +ol_tx_reinject(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu, uint16_t peer_id); + +#if defined(FEATURE_TSO) +void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg); +void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev); +void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg); +void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev); +uint32_t ol_tx_tso_get_stats_idx(struct ol_txrx_pdev_t *pdev); +uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info); +void ol_tx_tso_update_stats(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_info_t *tso_info, qdf_nbuf_t msdu, + uint32_t tso_msdu_idx); +#else +static inline uint32_t ol_tx_tso_get_stats_idx(struct ol_txrx_pdev_t *pdev) +{ + return 0; +} + +static inline void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, + uint32_t num_seg) +{ +} + +static inline void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, + uint32_t num_seg) +{ +} + +static inline void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return 0; +} + +static inline void ol_tx_tso_update_stats(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_info_t *tso_info, + qdf_nbuf_t msdu, + uint32_t tso_msdu_idx) +{ +} +#endif + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +bool ol_tx_desc_is_high_prio(qdf_nbuf_t msdu); +#endif + +#if defined(HELIUMPLUS) +void ol_txrx_dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc); +#else +static inline +void ol_txrx_dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +#endif /* _OL_TX__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_classify.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_classify.c new file mode 100644 index 0000000000..872b36b208 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_classify.c @@ -0,0 +1,917 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync */ +#include +#include /* TXRX_ASSERT1 */ +#include /* pdev stats */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include +#include +#include +#include +#include +#include +#include /* ETHERTYPE_VLAN, etc. */ +#include /* ieee80211_frame */ +#include +/* + * In theory, this tx classify code could be used on the host or in the target. + * Thus, this code uses generic OS primitives, that can be aliased to either + * the host's OS primitives or the target's OS primitives. + * For now, the following #defines set up these host-specific or + * target-specific aliases. + */ + +#define OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq) +#define OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, netbuf, msdu_info, txq) + +#ifdef QCA_TX_HTT2_SUPPORT +static void +ol_tx_classify_htt2_frm( + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct htt_msdu_info_t *htt = &tx_msdu_info->htt; + A_UINT8 candi_frm = 0; + + /* + * Offload the frame re-order to L3 protocol and ONLY support + * TCP protocol now. + */ + if ((htt->info.l2_hdr_type == htt_pkt_type_ethernet) && + (htt->info.frame_type == htt_frm_type_data) && + htt->info.is_unicast && + (htt->info.ethertype == ETHERTYPE_IPV4)) { + struct ipv4_hdr_t *ipHdr; + + ipHdr = (struct ipv4_hdr_t *)(qdf_nbuf_data(tx_nbuf) + + htt->info.l3_hdr_offset); + if (ipHdr->protocol == IP_PROTOCOL_TCP) + candi_frm = 1; + } + + qdf_nbuf_set_tx_parallel_dnload_frm(tx_nbuf, candi_frm); +} + +#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) \ + ol_tx_classify_htt2_frm(vdev, netbuf, msdu_info) +#else +#define OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, netbuf, msdu_info) /* no-op */ +#endif /* QCA_TX_HTT2_SUPPORT */ +/* DHCP go with voice priority; WMM_AC_VO_TID1();*/ +#define TX_DHCP_TID 6 + +#if defined(QCA_BAD_PEER_TX_FLOW_CL) +static inline A_BOOL +ol_if_tx_bad_peer_txq_overflow( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + struct ol_tx_frms_queue_t *txq) +{ + if (peer && pdev && txq && (peer->tx_limit_flag) && + (txq->frms >= pdev->tx_peer_bal.peer_bal_txq_limit)) + return true; + else + return false; +} +#else +static inline A_BOOL ol_if_tx_bad_peer_txq_overflow( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + struct ol_tx_frms_queue_t *txq) +{ + return false; +} +#endif + +/* EAPOL go with voice priority: WMM_AC_TO_TID1(WMM_AC_VO);*/ +#define TX_EAPOL_TID 6 + +/* ARP go with voice priority: WMM_AC_TO_TID1(pdev->arp_ac_override)*/ +#define TX_ARP_TID 6 + +/* For non-IP case, use default TID */ +#define TX_DEFAULT_TID 0 + +/* + * Determine IP TOS priority + * IP Tos format : + * (Refer Pg 57 WMM-test-plan-v1.2) + * IP-TOS - 8bits + * : DSCP(6-bits) ECN(2-bits) + * : DSCP - P2 P1 P0 X X X + * where (P2 P1 P0) form 802.1D + */ +static inline A_UINT8 +ol_tx_tid_by_ipv4(A_UINT8 *pkt) +{ + A_UINT8 ipPri, tid; + struct ipv4_hdr_t *ipHdr = (struct ipv4_hdr_t *)pkt; + + ipPri = ipHdr->tos >> 5; + tid = ipPri & 0x7; + + return tid; +} + +static inline A_UINT8 +ol_tx_tid_by_ipv6(A_UINT8 *pkt) +{ + return (ipv6_traffic_class((struct ipv6_hdr_t *)pkt) >> 5) & 0x7; +} + +static inline void +ol_tx_set_ether_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT16 typeorlength; + A_UINT8 *ptr; + A_UINT8 *l3_data_ptr; + + if (tx_msdu_info->htt.info.l2_hdr_type == htt_pkt_type_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + struct llc_snap_hdr_t *llc; + /* dot11 encapsulated frame */ + struct ieee80211_qosframe *whqos = + (struct ieee80211_qosframe *)datap; + if (whqos->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) { + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_qosframe); + } else { + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_frame); + } + llc = (struct llc_snap_hdr_t *) + (datap + tx_msdu_info->htt.info.l3_hdr_offset); + tx_msdu_info->htt.info.ethertype = + (llc->ethertype[0] << 8) | llc->ethertype[1]; + /* + * l3_hdr_offset refers to the end of the 802.3 or + * 802.11 header, which may be a LLC/SNAP header rather + * than the IP header. + * Thus, don't increment l3_hdr_offset += sizeof(*llc); + * rather,leave it as is. + */ + } else { + /* + * This function should only be applied to data frames. + * For management frames, we already know to use + * HTT_TX_EXT_TID_MGMT. + */ + TXRX_ASSERT2(0); + } + } else if (tx_msdu_info->htt.info.l2_hdr_type == + htt_pkt_type_ethernet) { + ptr = (datap + QDF_MAC_ADDR_SIZE * 2); + typeorlength = (ptr[0] << 8) | ptr[1]; + /*ETHERNET_HDR_LEN;*/ + l3_data_ptr = datap + sizeof(struct ethernet_hdr_t); + + if (typeorlength == ETHERTYPE_VLAN) { + ptr = (datap + QDF_MAC_ADDR_SIZE * 2 + + ETHERTYPE_VLAN_LEN); + typeorlength = (ptr[0] << 8) | ptr[1]; + l3_data_ptr += ETHERTYPE_VLAN_LEN; + } + + if (!IS_ETHERTYPE(typeorlength)) { + /* 802.3 header*/ + struct llc_snap_hdr_t *llc_hdr = + (struct llc_snap_hdr_t *)l3_data_ptr; + typeorlength = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + l3_data_ptr += sizeof(struct llc_snap_hdr_t); + } + + tx_msdu_info->htt.info.l3_hdr_offset = (A_UINT8)(l3_data_ptr - + datap); + tx_msdu_info->htt.info.ethertype = typeorlength; + } +} + +static inline A_UINT8 +ol_tx_tid_by_ether_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 tid; + A_UINT8 *l3_data_ptr; + A_UINT16 typeorlength; + + l3_data_ptr = datap + tx_msdu_info->htt.info.l3_hdr_offset; + typeorlength = tx_msdu_info->htt.info.ethertype; + + /* IP packet, do packet inspection for TID */ + if (typeorlength == ETHERTYPE_IPV4) { + tid = ol_tx_tid_by_ipv4(l3_data_ptr); + } else if (typeorlength == ETHERTYPE_IPV6) { + tid = ol_tx_tid_by_ipv6(l3_data_ptr); + } else if (ETHERTYPE_IS_EAPOL_WAPI(typeorlength)) { + /* EAPOL go with voice priority*/ + tid = TX_EAPOL_TID; + } else if (typeorlength == ETHERTYPE_ARP) { + tid = TX_ARP_TID; + } else { + /* For non-IP case, use default TID */ + tid = TX_DEFAULT_TID; + } + return tid; +} + +static inline A_UINT8 +ol_tx_tid_by_raw_type( + A_UINT8 *datap, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 tid = HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST; + + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = (struct ieee80211_frame *)datap; + + /* FIXME: This code does not handle 4 address formats. The QOS field + * is not at usual location. + */ + if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == + IEEE80211_FC0_TYPE_DATA) { + /* dot11 encapsulated frame */ + struct ieee80211_qosframe *whqos = + (struct ieee80211_qosframe *)datap; + if (whqos->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_QOS) + tid = whqos->i_qos[0] & IEEE80211_QOS_TID; + else + tid = HTT_NON_QOS_TID; + } else { + /* + * This function should only be applied to data frames. + * For management frames, we already know to use + * HTT_TX_EXT_TID_MGMT. + */ + qdf_assert(0); + } + return tid; +} + +static A_UINT8 +ol_tx_tid( + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + A_UINT8 *datap = qdf_nbuf_data(tx_nbuf); + A_UINT8 tid; + + if (pdev->frame_format == wlan_frm_fmt_raw) { + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_raw; + + ol_tx_set_ether_type(datap, tx_msdu_info); + tid = tx_msdu_info->htt.info.ext_tid == + QDF_NBUF_TX_EXT_TID_INVALID ? + ol_tx_tid_by_raw_type(datap, tx_msdu_info) : + tx_msdu_info->htt.info.ext_tid; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_ethernet; + + ol_tx_set_ether_type(datap, tx_msdu_info); + tid = + tx_msdu_info->htt.info.ext_tid == + QDF_NBUF_TX_EXT_TID_INVALID ? + ol_tx_tid_by_ether_type(datap, tx_msdu_info) : + tx_msdu_info->htt.info.ext_tid; + } else if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + struct llc_snap_hdr_t *llc; + + tx_msdu_info->htt.info.l2_hdr_type = htt_pkt_type_native_wifi; + tx_msdu_info->htt.info.l3_hdr_offset = + sizeof(struct ieee80211_frame); + llc = (struct llc_snap_hdr_t *) + (datap + tx_msdu_info->htt.info.l3_hdr_offset); + tx_msdu_info->htt.info.ethertype = + (llc->ethertype[0] << 8) | llc->ethertype[1]; + /* + * Native WiFi is a special case of "raw" 802.11 header format. + * However, we expect that for all cases that use native WiFi, + * the TID will be directly specified out of band. + */ + tid = tx_msdu_info->htt.info.ext_tid; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "Invalid standard frame type: %d\n", + pdev->frame_format); + qdf_assert(0); + tid = HTT_TX_EXT_TID_INVALID; + } + return tid; +} + +#if defined(FEATURE_WLAN_TDLS) +static inline +struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *dest_addr, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 }; + enum peer_debug_id_type id_type = PEER_DEBUG_ID_OL_INTERNAL; + + struct ol_txrx_peer_t *(*find_peer)(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + u8 check_valid, + enum peer_debug_id_type dbg_id) + = ol_txrx_peer_find_hash_find_get_ref; + + if (vdev->hlTdlsFlag) { + peer = find_peer(pdev, vdev->hl_tdls_ap_mac_addr.raw, + 0, 1, id_type); + + if (peer && (peer->peer_ids[0] == HTT_INVALID_PEER_ID)) { + ol_txrx_peer_release_ref(peer, id_type); + peer = NULL; + } else { + if (peer) { + *peer_id = peer->local_id; + return peer; + } + } + } + + /* Packets destined to TDLS Peer or AP with 'No TDLS Link'. + * Optimized to directly get the peer based on 'dest_addr' + */ + if (vdev->last_real_peer && + !qdf_mem_cmp(vdev->last_real_peer->mac_addr.raw, + dest_addr, QDF_MAC_ADDR_SIZE)) { + ol_txrx_peer_get_ref(vdev->last_real_peer, id_type); + *peer_id = vdev->last_real_peer->local_id; + peer = vdev->last_real_peer; + } else { + /* packets destined for other peers or AP with TDLS Link */ + if (vdev->last_real_peer && + !qdf_mem_cmp(vdev->hl_tdls_ap_mac_addr.raw, + zero_mac_addr, + QDF_MAC_ADDR_SIZE)) { + /* With No TDLS Link return last_real_peer for both AP + * and other bss peer + */ + ol_txrx_peer_get_ref(vdev->last_real_peer, id_type); + *peer_id = vdev->last_real_peer->local_id; + peer = vdev->last_real_peer; + } else { /* packet destined for other peers and AP when + * STA has TDLS link + */ + peer = find_peer(pdev, vdev->hl_tdls_ap_mac_addr.raw, + 0, 1, id_type); + + if (peer && + (peer->peer_ids[0] == HTT_INVALID_PEER_ID)) { + ol_txrx_peer_release_ref(peer, id_type); + peer = NULL; + } else { + if (peer) + *peer_id = peer->local_id; + } + } + } + return peer; +} + +#else +static struct ol_txrx_peer_t *ol_tx_tdls_peer_find(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *dest_addr, + uint8_t *peer_id) +{ + struct ol_txrx_peer_t *peer = NULL; + + peer = ol_txrx_assoc_peer_find(vdev); + + return peer; +} +#endif + +struct ol_tx_frms_queue_t * +ol_tx_classify( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer = NULL; + struct ol_tx_frms_queue_t *txq = NULL; + A_UINT8 *dest_addr; + A_UINT8 tid; + u_int8_t peer_id; + + TX_SCHED_DEBUG_PRINT("Enter"); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if (unlikely(!dest_addr)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: dest_addr is NULL.\n"); + return NULL; /*error*/ + } + if ((IEEE80211_IS_MULTICAST(dest_addr)) || + (vdev->opmode == wlan_op_mode_ocb)) { + txq = &vdev->txqs[OL_TX_VDEV_MCAST_BCAST]; + tx_msdu_info->htt.info.ext_tid = + HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST; + if (vdev->opmode == wlan_op_mode_sta) { + /* + * The STA sends a frame with a broadcast + * dest addr (DA) as a + * unicast frame to the AP's receive addr (RA). + * Find the peer object that represents the AP + * that the STA is associated with. + */ + peer = ol_txrx_assoc_peer_find(vdev); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: STA %pK ("QDF_MAC_ADDR_FMT") trying to send bcast DA tx data frame w/o association\n", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + return NULL; /* error */ + } else if ((peer->security[ + OL_TXRX_PEER_SECURITY_MULTICAST].sec_type + != htt_sec_type_wapi) && + (qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) { + if (QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE( + tx_nbuf)) { + /* DHCP frame to go with + * voice priority + */ + txq = &peer->txqs[TX_DHCP_TID]; + tx_msdu_info->htt.info.ext_tid = + TX_DHCP_TID; + } + } + /* + * The following line assumes each peer object has a + * single ID. This is currently true, and is expected + * to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + } else if (vdev->opmode == wlan_op_mode_ocb) { + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + /* + * In OCB mode, don't worry about the peer. + * We don't need it. + */ + peer = NULL; + } else { + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + /* + * Look up the vdev's BSS peer, so that the + * classify_extension function can check whether to + * encrypt multicast / broadcast frames. + */ + peer = ol_txrx_peer_find_hash_find_get_ref + (pdev, + vdev->mac_addr.raw, + 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: vdev %pK ("QDF_MAC_ADDR_FMT") trying to send bcast/mcast, but no self-peer found\n", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + return NULL; /* error */ + } + } + tx_msdu_info->htt.info.is_unicast = false; + } else { + /* tid would be overwritten for non QoS case*/ + tid = ol_tx_tid(pdev, tx_nbuf, tx_msdu_info); + if ((HTT_TX_EXT_TID_INVALID == tid) || + (tid >= OL_TX_NUM_TIDS)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%s Error: could not classify packet into valid TID(%d).\n", + __func__, tid); + return NULL; + } +#ifdef ATH_SUPPORT_WAPI + /* Check to see if a frame is a WAI frame */ + if (tx_msdu_info->htt.info.ethertype == ETHERTYPE_WAI) { + /* WAI frames should not be encrypted */ + tx_msdu_info->htt.action.do_encrypt = 0; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Tx Frame is a WAI frame\n"); + } +#endif /* ATH_SUPPORT_WAPI */ + + /* + * Find the peer and increment its reference count. + * If this vdev is an AP, use the dest addr (DA) to determine + * which peer STA this unicast data frame is for. + * If this vdev is a STA, the unicast data frame is for the + * AP the STA is associated with. + */ + if (vdev->opmode == wlan_op_mode_sta) { + /* + * TO DO: + * To support TDLS, first check if there is a TDLS + * peer STA, + * and if so, check if the DA matches the TDLS peer + * STA's MAC address. If there is no peer TDLS STA, + * or if the DA is not the TDLS STA's address, + * then the frame is either for the AP itself, or is + * supposed to be sent to the AP for forwarding. + */ + peer = ol_tx_tdls_peer_find(pdev, vdev, + dest_addr, + &peer_id); + } else { + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, + dest_addr, + 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + } + tx_msdu_info->htt.info.is_unicast = true; + if (!peer) { + /* + * Unicast data xfer can only happen to an + * associated peer. It is illegitimate to send unicast + * data if there is no peer to send it to. + */ + ol_txrx_err_rl("Error: vdev %pK (" QDF_MAC_ADDR_FMT ") trying to send unicast tx data frame to an unknown peer", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + return NULL; /* error */ + } + TX_SCHED_DEBUG_PRINT("Peer found"); + if (!peer->qos_capable) { + tid = OL_TX_NON_QOS_TID; + } else if ((peer->security[ + OL_TXRX_PEER_SECURITY_UNICAST].sec_type + != htt_sec_type_wapi) && + (qdf_nbuf_is_ipv4_pkt(tx_nbuf) == true)) { + if (QDF_NBUF_CB_PACKET_TYPE_DHCP == + QDF_NBUF_CB_GET_PACKET_TYPE(tx_nbuf)) + /* DHCP frame to go with voice priority */ + tid = TX_DHCP_TID; + } + + /* Only allow encryption when in authenticated state */ + if (OL_TXRX_PEER_STATE_AUTH != peer->state) + tx_msdu_info->htt.action.do_encrypt = 0; + + txq = &peer->txqs[tid]; + tx_msdu_info->htt.info.ext_tid = tid; + /* + * The following line assumes each peer object has a single ID. + * This is currently true, and is expected to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + /* + * WORKAROUND - check that the peer ID is valid. + * If tx data is provided before ol_rx_peer_map_handler is + * called to record the peer ID specified by the target, + * then we could end up here with an invalid peer ID. + * TO DO: rather than dropping the tx frame, pause the txq it + * goes into, then fill in the peer ID for the entries in the + * txq when the peer_map event provides the peer ID, and then + * unpause the txq. + */ + if (tx_msdu_info->htt.info.peer_id == HTT_INVALID_PEER_ID) { + if (peer) { + ol_txrx_info("remove the peer for invalid peer_id %pK", + peer); + /* remove the peer reference added above */ + ol_txrx_peer_release_ref + (peer, + PEER_DEBUG_ID_OL_INTERNAL); + tx_msdu_info->peer = NULL; + } + return NULL; + } + } + tx_msdu_info->peer = peer; + if (ol_if_tx_bad_peer_txq_overflow(pdev, peer, txq)) + return NULL; + /* + * If relevant, do a deeper inspection to determine additional + * characteristics of the tx frame. + * If the frame is invalid, then the txq will be set to NULL to + * indicate an error. + */ + OL_TX_CLASSIFY_EXTENSION(vdev, tx_desc, tx_nbuf, tx_msdu_info, txq); + if (IEEE80211_IS_MULTICAST(dest_addr) && vdev->opmode != + wlan_op_mode_sta && tx_msdu_info->peer != + NULL) { + ol_txrx_dbg("remove the peer reference %pK", peer); + /* remove the peer reference added above */ + ol_txrx_peer_release_ref(tx_msdu_info->peer, + PEER_DEBUG_ID_OL_INTERNAL); + /* Making peer NULL in case if multicast non STA mode */ + tx_msdu_info->peer = NULL; + } + + /* Whether this frame can download though HTT2 data pipe or not. */ + OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info); + + /* Update Tx Queue info */ + tx_desc->txq = txq; + + TX_SCHED_DEBUG_PRINT("Leave"); + return txq; +} + +struct ol_tx_frms_queue_t * +ol_tx_classify_mgmt( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_nbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_txrx_peer_t *peer = NULL; + struct ol_tx_frms_queue_t *txq = NULL; + A_UINT8 *dest_addr; + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + + TX_SCHED_DEBUG_PRINT("Enter"); + dest_addr = ol_tx_dest_addr_find(pdev, tx_nbuf); + if (unlikely(!dest_addr)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Error: dest_addr is NULL.\n"); + return NULL; /*error*/ + } + if (IEEE80211_IS_MULTICAST(dest_addr)) { + /* + * AP: beacons are broadcast, + * public action frames (e.g. extended channel + * switch announce) may be broadcast + * STA: probe requests can be either broadcast or unicast + */ + txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT]; + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + tx_msdu_info->peer = NULL; + tx_msdu_info->htt.info.is_unicast = 0; + } else { + /* + * Find the peer and increment its reference count. + * If this vdev is an AP, use the receiver addr (RA) to + * determine which peer STA this unicast mgmt frame is for. + * If this vdev is a STA, the unicast mgmt frame is for the + * AP the STA is associated with. + * Probe request / response and Assoc request / response are + * sent before the peer exists - in this case, use the + * vdev's default tx queue. + */ + if (vdev->opmode == wlan_op_mode_sta) { + /* + * TO DO: + * To support TDLS, first check if there is a TDLS + * peer STA, and if so, check if the DA matches + * the TDLS peer STA's MAC address. + */ + peer = ol_txrx_assoc_peer_find(vdev); + /* + * Some special case(preauth for example) needs to send + * unicast mgmt frame to unassociated AP. In such case, + * we need to check if dest addr match the associated + * peer addr. If not, we set peer as NULL to queue this + * frame to vdev queue. + */ + if (peer) { + + qdf_mem_copy( + &local_mac_addr_aligned.raw[0], + dest_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + if (ol_txrx_peer_find_mac_addr_cmp + (mac_addr, + &peer->mac_addr) != 0) { + ol_txrx_peer_release_ref + (peer, + PEER_DEBUG_ID_OL_INTERNAL); + peer = NULL; + } + } + } else { + /* find the peer and increment its reference count */ + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, + dest_addr, + 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + } + tx_msdu_info->peer = peer; + if (!peer) { + txq = &vdev->txqs[OL_TX_VDEV_DEFAULT_MGMT]; + tx_msdu_info->htt.info.peer_id = HTT_INVALID_PEER_ID; + } else { + txq = &peer->txqs[HTT_TX_EXT_TID_MGMT]; + tx_msdu_info->htt.info.ext_tid = HTT_TX_EXT_TID_MGMT; + /* + * The following line assumes each peer object has a + * single ID. This is currently true, and is expected + * to remain true. + */ + tx_msdu_info->htt.info.peer_id = peer->peer_ids[0]; + } + tx_msdu_info->htt.info.is_unicast = 1; + } + /* + * If relevant, do a deeper inspection to determine additional + * characteristics of the tx frame. + * If the frame is invalid, then the txq will be set to NULL to + * indicate an error. + */ + OL_TX_CLASSIFY_MGMT_EXTENSION(vdev, tx_desc, tx_nbuf, + tx_msdu_info, txq); + + /* Whether this frame can download though HTT2 data pipe or not. */ + OL_TX_CLASSIFY_HTT2_EXTENSION(vdev, tx_nbuf, tx_msdu_info); + + /* Update Tx Queue info */ + tx_desc->txq = txq; + + TX_SCHED_DEBUG_PRINT("Leave"); + return txq; +} + +#ifdef currently_unused +QDF_STATUS +ol_tx_classify_extension( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + u8 *datap = qdf_nbuf_data(tx_msdu); + struct ol_txrx_peer_t *peer; + int which_key; + + /* + * The following msdu_info fields were already filled in by the + * ol_tx entry function or the regular ol_tx_classify function: + * htt.info.vdev_id (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.ext_tid (ol_tx_non_std_hl or ol_tx_classify) + * htt.info.frame_type (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.l2_hdr_type (ol_tx_hl or ol_tx_non_std_hl) + * htt.info.is_unicast (ol_tx_classify) + * htt.info.peer_id (ol_tx_classify) + * peer (ol_tx_classify) + * if (is_unicast) { + * htt.info.ethertype (ol_tx_classify) + * htt.info.l3_hdr_offset (ol_tx_classify) + * } + * The following fields need to be filled in by this function: + * if (!is_unicast) { + * htt.info.ethertype + * htt.info.l3_hdr_offset + * } + * htt.action.band (NOT CURRENTLY USED) + * htt.action.do_encrypt + * htt.action.do_tx_complete + * The following fields are not needed for data frames, and can + * be left uninitialized: + * htt.info.frame_subtype + */ + + if (!msdu_info->htt.info.is_unicast) { + int l2_hdr_size; + u16 ethertype; + + if (msdu_info->htt.info.l2_hdr_type == htt_pkt_type_ethernet) { + struct ethernet_hdr_t *eh; + + eh = (struct ethernet_hdr_t *)datap; + l2_hdr_size = sizeof(*eh); + ethertype = (eh->ethertype[0] << 8) | eh->ethertype[1]; + + if (ethertype == ETHERTYPE_VLAN) { + struct ethernet_vlan_hdr_t *evh; + + evh = (struct ethernet_vlan_hdr_t *)datap; + l2_hdr_size = sizeof(*evh); + ethertype = (evh->ethertype[0] << 8) | + evh->ethertype[1]; + } + + if (!IS_ETHERTYPE(ethertype)) { + /* 802.3 header*/ + struct llc_snap_hdr_t *llc = + (struct llc_snap_hdr_t *)(datap + + l2_hdr_size); + ethertype = (llc->ethertype[0] << 8) | + llc->ethertype[1]; + l2_hdr_size += sizeof(*llc); + } + msdu_info->htt.info.l3_hdr_offset = l2_hdr_size; + msdu_info->htt.info.ethertype = ethertype; + } else { /* 802.11 */ + struct llc_snap_hdr_t *llc; + + l2_hdr_size = ol_txrx_ieee80211_hdrsize(datap); + llc = (struct llc_snap_hdr_t *)(datap + l2_hdr_size); + ethertype = (llc->ethertype[0] << 8) | + llc->ethertype[1]; + /* + * Don't include the LLC/SNAP header in l2_hdr_size, + * because l3_hdr_offset is actually supposed to refer + * to the header after the 802.3 or 802.11 header, + * which could be a LLC/SNAP header rather + * than the L3 header. + */ + } + msdu_info->htt.info.l3_hdr_offset = l2_hdr_size; + msdu_info->htt.info.ethertype = ethertype; + which_key = txrx_sec_mcast; + } else { + which_key = txrx_sec_ucast; + } + peer = msdu_info->peer; + /* + * msdu_info->htt.action.do_encrypt is initially set in ol_tx_desc_hl. + * Add more check here. + */ + msdu_info->htt.action.do_encrypt = (!peer) ? 0 : + (peer->security[which_key].sec_type == htt_sec_type_none) ? 0 : + msdu_info->htt.action.do_encrypt; + /* + * For systems that have a frame by frame spec for whether to receive + * a tx completion notification, use the tx completion notification + * only for certain management frames, not for data frames. + * (In the future, this may be changed slightly, e.g. to request a + * tx completion notification for the final EAPOL message sent by a + * STA during the key delivery handshake.) + */ + msdu_info->htt.action.do_tx_complete = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +ol_tx_classify_mgmt_extension( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ieee80211_frame *wh; + + /* + * The following msdu_info fields were already filled in by the + * ol_tx entry function or the regular ol_tx_classify_mgmt function: + * htt.info.vdev_id (ol_txrx_mgmt_send) + * htt.info.frame_type (ol_txrx_mgmt_send) + * htt.info.l2_hdr_type (ol_txrx_mgmt_send) + * htt.action.do_tx_complete (ol_txrx_mgmt_send) + * htt.info.peer_id (ol_tx_classify_mgmt) + * htt.info.ext_tid (ol_tx_classify_mgmt) + * htt.info.is_unicast (ol_tx_classify_mgmt) + * peer (ol_tx_classify_mgmt) + * The following fields need to be filled in by this function: + * htt.info.frame_subtype + * htt.info.l3_hdr_offset + * htt.action.band (NOT CURRENTLY USED) + * The following fields are not needed for mgmt frames, and can + * be left uninitialized: + * htt.info.ethertype + * htt.action.do_encrypt + * (This will be filled in by other SW, which knows whether + * the peer has robust-management-frames enabled.) + */ + wh = (struct ieee80211_frame *)qdf_nbuf_data(tx_msdu); + msdu_info->htt.info.frame_subtype = + (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >> + IEEE80211_FC0_SUBTYPE_SHIFT; + msdu_info->htt.info.l3_hdr_offset = sizeof(struct ieee80211_frame); + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_classify.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_classify.h new file mode 100644 index 0000000000..b88f329476 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_classify.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2012, 2014, 2016 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_tx_classify.h + * @brief API definitions for the tx classify module within the data SW. + */ +#ifndef _OL_TX_CLASSIFY__H_ +#define _OL_TX_CLASSIFY__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ + +static inline u_int8_t * +ol_tx_dest_addr_find( + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t tx_nbuf) +{ + u_int8_t *hdr_ptr; + void *datap = qdf_nbuf_data(tx_nbuf); + + if (pdev->frame_format == wlan_frm_fmt_raw) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = + (struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == + wlan_frm_fmt_native_wifi) { + /* adjust hdr_ptr to RA */ + struct ieee80211_frame *wh = ( + struct ieee80211_frame *)datap; + hdr_ptr = wh->i_addr1; + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + hdr_ptr = datap; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Invalid standard frame type: %d\n", + pdev->frame_format); + qdf_assert(0); + hdr_ptr = NULL; + } + return hdr_ptr; +} + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Classify a tx frame to which tid queue. + * + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param tx_desc - descriptor object with meta-data about the tx frame + * @param netbuf - the tx frame + * @param tx_msdu_info - characteristics of the tx frame + */ +struct ol_tx_frms_queue_t * +ol_tx_classify( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +struct ol_tx_frms_queue_t * +ol_tx_classify_mgmt( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +#else + +#define ol_tx_classify(vdev, tx_desc, netbuf, tx_msdu_info) NULL +#define ol_tx_classify_mgmt(vdev, tx_desc, netbuf, tx_msdu_info) NULL + +#endif /* defined(CONFIG_HL_SUPPORT) */ + + +#endif /* _OL_TX_CLASSIFY__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_desc.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_desc.c new file mode 100644 index 0000000000..475d7099ac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_desc.c @@ -0,0 +1,1149 @@ +/* + * Copyright (c) 2011, 2014-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* QDF_NBUF_EXEMPT_NO_EXEMPTION, etc. */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_assert */ +#include /* qdf_spinlock */ +#include /* qdf_tso_seg_dbg stuff */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* qdf_system_ticks */ +#endif + +#include /* htt_tx_desc_id */ + +#include +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +static inline void ol_tx_desc_sanity_checks(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + if (tx_desc->pkt_type != ol_tx_frm_freed) { + ol_txrx_err("Potential tx_desc corruption pkt_type:0x%x pdev:0x%pK", + tx_desc->pkt_type, pdev); + qdf_assert(0); + } +} +static inline void ol_tx_desc_reset_pkt_type(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->pkt_type = ol_tx_frm_freed; +} +#ifdef QCA_COMPUTE_TX_DELAY +static inline void ol_tx_desc_compute_delay(struct ol_tx_desc_t *tx_desc) +{ + if (tx_desc->entry_timestamp_ticks != 0xffffffff) { + ol_txrx_err("Timestamp:0x%x", tx_desc->entry_timestamp_ticks); + qdf_assert(0); + } + tx_desc->entry_timestamp_ticks = qdf_system_ticks(); +} +static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->entry_timestamp_ticks = 0xffffffff; +} +#endif +#else +static inline void ol_tx_desc_sanity_checks(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} +static inline void ol_tx_desc_reset_pkt_type(struct ol_tx_desc_t *tx_desc) +{ +} +static inline void ol_tx_desc_compute_delay(struct ol_tx_desc_t *tx_desc) +{ +} +static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +#ifdef DESC_TIMESTAMP_DEBUG_INFO +static inline void ol_tx_desc_update_tx_ts(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->desc_debug_info.prev_tx_ts = tx_desc + ->desc_debug_info.curr_tx_ts; + tx_desc->desc_debug_info.curr_tx_ts = qdf_get_log_timestamp(); +} +#else +static inline void ol_tx_desc_update_tx_ts(struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +/** + * ol_tx_desc_vdev_update() - vedv assign. + * @tx_desc: tx descriptor pointer + * @vdev: vdev handle + * + * Return: None + */ +static inline void +ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, + struct ol_txrx_vdev_t *vdev) +{ + tx_desc->vdev = vdev; + tx_desc->vdev_id = vdev->vdev_id; +} + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL + +/** + * ol_tx_desc_count_inc() - tx desc count increment for desc allocation. + * @vdev: vdev handle + * + * Return: None + */ +static inline void +ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_inc(&vdev->tx_desc_count); +} +#else + +static inline void +ol_tx_desc_count_inc(struct ol_txrx_vdev_t *vdev) +{ +} + +#endif + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +#ifdef QCA_LL_PDEV_TX_FLOW_CONTROL +/** + * ol_tx_do_pdev_flow_control_pause - pause queues when stop_th reached. + * @pdev: pdev handle + * + * Return: void + */ +static void ol_tx_do_pdev_flow_control_pause(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + if (qdf_unlikely(pdev->tx_desc.num_free < + pdev->tx_desc.stop_th && + pdev->tx_desc.num_free >= + pdev->tx_desc.stop_priority_th && + pdev->tx_desc.status == + FLOW_POOL_ACTIVE_UNPAUSED)) { + pdev->tx_desc.status = FLOW_POOL_NON_PRIO_PAUSED; + /* pause network NON PRIORITY queues */ + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + pdev->pause_cb(vdev->vdev_id, + WLAN_STOP_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } + } else if (qdf_unlikely((pdev->tx_desc.num_free < + pdev->tx_desc.stop_priority_th) && + pdev->tx_desc.status == + FLOW_POOL_NON_PRIO_PAUSED)) { + pdev->tx_desc.status = FLOW_POOL_ACTIVE_PAUSED; + /* pause priority queue */ + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + pdev->pause_cb(vdev->vdev_id, + WLAN_NETIF_PRIORITY_QUEUE_OFF, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + } + } +} + +/** + * ol_tx_do_pdev_flow_control_unpause - unpause queues when start_th restored. + * @pdev: pdev handle + * + * Return: void + */ +static void ol_tx_do_pdev_flow_control_unpause(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + switch (pdev->tx_desc.status) { + case FLOW_POOL_ACTIVE_PAUSED: + if (pdev->tx_desc.num_free > + pdev->tx_desc.start_priority_th) { + /* unpause priority queue */ + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + pdev->pause_cb(vdev->vdev_id, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + } + pdev->tx_desc.status = FLOW_POOL_NON_PRIO_PAUSED; + } + break; + case FLOW_POOL_NON_PRIO_PAUSED: + if (pdev->tx_desc.num_free > pdev->tx_desc.start_th) { + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + pdev->pause_cb(vdev->vdev_id, + WLAN_WAKE_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } + pdev->tx_desc.status = FLOW_POOL_ACTIVE_UNPAUSED; + } + break; + case FLOW_POOL_INVALID: + if (pdev->tx_desc.num_free == pdev->tx_desc.pool_size) + ol_txrx_err("pool is INVALID State!!"); + break; + case FLOW_POOL_ACTIVE_UNPAUSED: + break; + default: + ol_txrx_err("pool is INACTIVE State!!"); + break; + }; +} +#else +static inline void +ol_tx_do_pdev_flow_control_pause(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline void +ol_tx_do_pdev_flow_control_unpause(struct ol_txrx_pdev_t *pdev) +{ +} +#endif +/** + * ol_tx_desc_alloc() - allocate descriptor from freelist + * @pdev: pdev handle + * @vdev: vdev handle + * + * Return: tx descriptor pointer/ NULL in case of error + */ +static +struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + qdf_spin_lock_bh(&pdev->tx_mutex); + if (pdev->tx_desc.freelist) { + tx_desc = ol_tx_get_desc_global_pool(pdev); + if (!tx_desc) { + qdf_spin_unlock_bh(&pdev->tx_mutex); + return NULL; + } + ol_tx_desc_dup_detect_set(pdev, tx_desc); + ol_tx_do_pdev_flow_control_pause(pdev); + ol_tx_desc_sanity_checks(pdev, tx_desc); + ol_tx_desc_compute_delay(tx_desc); + ol_tx_desc_vdev_update(tx_desc, vdev); + ol_tx_desc_count_inc(vdev); + ol_tx_desc_update_tx_ts(tx_desc); + qdf_atomic_inc(&tx_desc->ref_cnt); + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + return tx_desc; +} + +/** + * ol_tx_desc_alloc_wrapper() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @msdu_info: msdu handler + * + * Return: tx descriptor or NULL + */ +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return ol_tx_desc_alloc(pdev, vdev); +} + +#else +/** + * ol_tx_desc_alloc() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @pool: flow pool + * + * Return: tx descriptor or NULL + */ +static +struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_tx_flow_pool_t *pool) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + if (!pool) { + pdev->pool_stats.pkt_drop_no_pool++; + goto end; + } + + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc) { + tx_desc = ol_tx_get_desc_flow_pool(pool); + ol_tx_desc_dup_detect_set(pdev, tx_desc); + if (qdf_unlikely(pool->avail_desc < pool->stop_th && + (pool->avail_desc >= pool->stop_priority_th) && + (pool->status == FLOW_POOL_ACTIVE_UNPAUSED))) { + pool->status = FLOW_POOL_NON_PRIO_PAUSED; + /* pause network NON PRIORITY queues */ + pdev->pause_cb(vdev->vdev_id, + WLAN_STOP_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } else if (qdf_unlikely((pool->avail_desc < + pool->stop_priority_th) && + pool->status == FLOW_POOL_NON_PRIO_PAUSED)) { + pool->status = FLOW_POOL_ACTIVE_PAUSED; + /* pause priority queue */ + pdev->pause_cb(vdev->vdev_id, + WLAN_NETIF_PRIORITY_QUEUE_OFF, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + } + + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + ol_tx_desc_sanity_checks(pdev, tx_desc); + ol_tx_desc_compute_delay(tx_desc); + ol_tx_desc_update_tx_ts(tx_desc); + ol_tx_desc_vdev_update(tx_desc, vdev); + qdf_atomic_inc(&tx_desc->ref_cnt); + } else { + pool->pkt_drop_no_desc++; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + +end: + return tx_desc; +} + +/** + * ol_tx_desc_alloc_wrapper() -allocate tx descriptor + * @pdev: pdev handler + * @vdev: vdev handler + * @msdu_info: msdu handler + * + * Return: tx descriptor or NULL + */ +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + if (qdf_unlikely(msdu_info->htt.info.frame_type == htt_pkt_type_mgmt)) + return ol_tx_desc_alloc(pdev, vdev, pdev->mgmt_pool); + else + return ol_tx_desc_alloc(pdev, vdev, vdev->pool); +} +#else +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + return ol_tx_desc_alloc(pdev, vdev, vdev->pool); +} +#endif +#endif + +/** + * ol_tx_desc_alloc_hl() - allocate tx descriptor + * @pdev: pdev handle + * @vdev: vdev handle + * @msdu_info: tx msdu info + * + * Return: tx descriptor pointer/ NULL in case of error + */ +static struct ol_tx_desc_t * +ol_tx_desc_alloc_hl(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + qdf_atomic_dec(&pdev->tx_queue.rsrc_cnt); + + return tx_desc; +} + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL + +/** + * ol_tx_desc_vdev_rm() - decrement the tx desc count for vdev. + * @tx_desc: tx desc + * + * Return: None + */ +static inline void +ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc) +{ + /* + * In module exit context, vdev handle could be destroyed but still + * we need to free pending completion tx_desc. + */ + if (!tx_desc || !tx_desc->vdev) + return; + + qdf_atomic_dec(&tx_desc->vdev->tx_desc_count); + tx_desc->vdev = NULL; +} +#else + +static inline void +ol_tx_desc_vdev_rm(struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +#ifdef FEATURE_TSO +/** + * ol_tso_unmap_tso_segment() - Unmap TSO segment + * @pdev: pointer to ol_txrx_pdev_t structure + * @tx_desc: pointer to ol_tx_desc_t containing the TSO segment + * + * Unmap TSO segment (frag[1]). If it is the last TSO segment corresponding the + * nbuf, also unmap the EIT header(frag[0]). + * + * Return: None + */ +static void ol_tso_unmap_tso_segment(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + bool is_last_seg = false; + struct qdf_tso_num_seg_elem_t *tso_num_desc = NULL; + + if (qdf_unlikely(!tx_desc->tso_desc)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO desc is NULL!", + __func__, __LINE__); + qdf_assert(0); + return; + } else if (qdf_unlikely(!tx_desc->tso_num_desc)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d TSO common info is NULL!", + __func__, __LINE__); + qdf_assert(0); + return; + } + + tso_num_desc = tx_desc->tso_num_desc; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + + tso_num_desc->num_seg.tso_cmn_num_seg--; + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == 0) ? + true : false; + qdf_nbuf_unmap_tso_segment(pdev->osdev, tx_desc->tso_desc, is_last_seg); + + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + +} + +/** + * ol_tx_tso_desc_free() - Add TSO TX descs back to the freelist + * @pdev: pointer to ol_txrx_pdev_t structure + * @tx_desc: pointer to ol_tx_desc_t containing the TSO segment + * + * Add qdf_tso_seg_elem_t corresponding to the TSO seg back to freelist. + * If it is the last segment of the jumbo skb, also add the + * qdf_tso_num_seg_elem_t to the free list. + * + * Return: None + */ +static void ol_tx_tso_desc_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + bool is_last_seg; + struct qdf_tso_num_seg_elem_t *tso_num_desc = tx_desc->tso_num_desc; + + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == 0) ? + true : false; + if (is_last_seg) { + ol_tso_num_seg_free(pdev, tx_desc->tso_num_desc); + tx_desc->tso_num_desc = NULL; + } + + ol_tso_free_segment(pdev, tx_desc->tso_desc); + tx_desc->tso_desc = NULL; +} + +#else +static inline void ol_tx_tso_desc_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} + +static inline void ol_tso_unmap_tso_segment( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +/** + * ol_tx_desc_free_common() - common funcs to free tx_desc for all flow ctl vers + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Set of common functions needed for QCA_LL_TX_FLOW_CONTROL_V2 and older + * versions of flow control. Needs to be called from within a spinlock. + * + * Return: None + */ +static void ol_tx_desc_free_common(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ol_tx_desc_dup_detect_reset(pdev, tx_desc); + + if (tx_desc->pkt_type == OL_TX_FRM_TSO) + ol_tx_tso_desc_free(pdev, tx_desc); + + ol_tx_desc_reset_pkt_type(tx_desc); + ol_tx_desc_reset_timestamp(tx_desc); + /* clear the ref cnt */ + qdf_atomic_init(&tx_desc->ref_cnt); + tx_desc->vdev_id = OL_TXRX_INVALID_VDEV_ID; +} + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_desc_free() - put descriptor to freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: None + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + qdf_spin_lock_bh(&pdev->tx_mutex); + + ol_tx_desc_free_common(pdev, tx_desc); + + ol_tx_put_desc_global_pool(pdev, tx_desc); + ol_tx_desc_vdev_rm(tx_desc); + ol_tx_do_pdev_flow_control_unpause(pdev); + + qdf_spin_unlock_bh(&pdev->tx_mutex); +} + +#else + +/** + * ol_tx_update_free_desc_to_pool() - update free desc to pool + * @pdev: pdev handle + * @tx_desc: descriptor + * + * Return : 1 desc distribution required / 0 don't need distribution + */ +#ifdef QCA_LL_TX_FLOW_CONTROL_RESIZE +static inline bool ol_tx_update_free_desc_to_pool(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + struct ol_tx_flow_pool_t *pool = tx_desc->pool; + bool distribute_desc = false; + + if (unlikely(pool->overflow_desc)) { + ol_tx_put_desc_global_pool(pdev, tx_desc); + --pool->overflow_desc; + distribute_desc = true; + } else { + ol_tx_put_desc_flow_pool(pool, tx_desc); + } + + return distribute_desc; +} +#else +static inline bool ol_tx_update_free_desc_to_pool(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ol_tx_put_desc_flow_pool(tx_desc->pool, tx_desc); + return false; +} +#endif + +/** + * ol_tx_desc_free() - put descriptor to pool freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: None + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + bool distribute_desc = false; + struct ol_tx_flow_pool_t *pool = tx_desc->pool; + + qdf_spin_lock_bh(&pool->flow_pool_lock); + + ol_tx_desc_free_common(pdev, tx_desc); + distribute_desc = ol_tx_update_free_desc_to_pool(pdev, tx_desc); + + switch (pool->status) { + case FLOW_POOL_ACTIVE_PAUSED: + if (pool->avail_desc > pool->start_priority_th) { + /* unpause priority queue */ + pdev->pause_cb(pool->member_flow_id, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + pool->status = FLOW_POOL_NON_PRIO_PAUSED; + } + break; + case FLOW_POOL_NON_PRIO_PAUSED: + if (pool->avail_desc > pool->start_th) { + pdev->pause_cb(pool->member_flow_id, + WLAN_WAKE_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + } + break; + case FLOW_POOL_INVALID: + if (pool->avail_desc == pool->flow_pool_size) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_tx_free_invalid_flow_pool(pool); + qdf_print("pool is INVALID State!!"); + return; + } + break; + case FLOW_POOL_ACTIVE_UNPAUSED: + break; + default: + qdf_print("pool is INACTIVE State!!"); + break; + }; + + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + if (unlikely(distribute_desc)) + ol_tx_distribute_descs_to_deficient_pools_from_global_pool(); + +} +#endif + +const uint32_t htt_to_ce_pkt_type[] = { + [htt_pkt_type_raw] = tx_pkt_type_raw, + [htt_pkt_type_native_wifi] = tx_pkt_type_native_wifi, + [htt_pkt_type_ethernet] = tx_pkt_type_802_3, + [htt_pkt_type_mgmt] = tx_pkt_type_mgmt, + [htt_pkt_type_eth2] = tx_pkt_type_eth2, + [htt_pkt_num_types] = 0xffffffff +}; + +#define WISA_DEST_PORT_6MBPS 50000 +#define WISA_DEST_PORT_24MBPS 50001 + +/** + * ol_tx_get_wisa_ext_hdr_type() - get header type for WiSA mode + * @netbuf: network buffer + * + * Return: extension header type + */ +static enum extension_header_type +ol_tx_get_wisa_ext_hdr_type(qdf_nbuf_t netbuf) +{ + uint8_t *buf = qdf_nbuf_data(netbuf); + uint16_t dport; + + if (qdf_is_macaddr_group( + (struct qdf_mac_addr *)(buf + QDF_NBUF_DEST_MAC_OFFSET))) { + + dport = (uint16_t)(*(uint16_t *)(buf + + QDF_NBUF_TRAC_IPV4_OFFSET + + QDF_NBUF_TRAC_IPV4_HEADER_SIZE + sizeof(uint16_t))); + + if (dport == QDF_SWAP_U16(WISA_DEST_PORT_6MBPS)) + return WISA_MODE_EXT_HEADER_6MBPS; + else if (dport == QDF_SWAP_U16(WISA_DEST_PORT_24MBPS)) + return WISA_MODE_EXT_HEADER_24MBPS; + else + return EXT_HEADER_NOT_PRESENT; + } else { + return EXT_HEADER_NOT_PRESENT; + } +} + +/** + * ol_tx_get_ext_header_type() - extension header is required or not + * @vdev: vdev pointer + * @netbuf: network buffer + * + * This function returns header type and if extension header is + * not required than returns EXT_HEADER_NOT_PRESENT. + * + * Return: extension header type + */ +enum extension_header_type +ol_tx_get_ext_header_type(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf) +{ + if (vdev->is_wisa_mode_enable == true) + return ol_tx_get_wisa_ext_hdr_type(netbuf); + else + return EXT_HEADER_NOT_PRESENT; +} + +struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + unsigned int i; + uint32_t num_frags; + enum extension_header_type type; + + msdu_info->htt.info.vdev_id = vdev->vdev_id; + msdu_info->htt.action.cksum_offload = qdf_nbuf_get_tx_cksum(netbuf); + switch (qdf_nbuf_get_exemption_type(netbuf)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 0; + break; + default: + qdf_assert(0); + break; + } + + /* allocate the descriptor */ + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + /* initialize the SW tx descriptor */ + tx_desc->netbuf = netbuf; + + if (msdu_info->tso_info.is_tso) { + tx_desc->tso_desc = msdu_info->tso_info.curr_seg; + tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list; + tx_desc->pkt_type = OL_TX_FRM_TSO; + TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, netbuf); + } else { + tx_desc->pkt_type = OL_TX_FRM_STD; + } + + type = ol_tx_get_ext_header_type(vdev, netbuf); + + /* initialize the HW tx descriptor */ + if (qdf_unlikely(htt_tx_desc_init(pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), netbuf, &msdu_info->htt, + &msdu_info->tso_info, NULL, type))) { + /* + * HTT Tx descriptor initialization failed. + * therefore, free the tx desc + */ + ol_tx_desc_free(pdev, tx_desc); + return NULL; + } + + /* + * Initialize the fragmentation descriptor. + * Skip the prefix fragment (HTT tx descriptor) that was added + * during the call to htt_tx_desc_init above. + */ + num_frags = qdf_nbuf_get_num_frags(netbuf); + /* num_frags are expected to be 2 max */ + num_frags = (num_frags > QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS) + ? QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS + : num_frags; +#if defined(HELIUMPLUS) + /* + * Use num_frags - 1, since 1 frag is used to store + * the HTT/HTC descriptor + * Refer to htt_tx_desc_init() + */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_frag_desc, + num_frags - 1); +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_tx_desc, + num_frags - 1); +#endif /* defined(HELIUMPLUS) */ + + if (msdu_info->tso_info.is_tso) { + htt_tx_desc_fill_tso_info(pdev->htt_pdev, + tx_desc->htt_frag_desc, &msdu_info->tso_info); + TXRX_STATS_TSO_SEG_UPDATE(pdev, + msdu_info->tso_info.msdu_stats_idx, + msdu_info->tso_info.curr_seg->seg); + } else { + for (i = 1; i < num_frags; i++) { + qdf_size_t frag_len; + qdf_dma_addr_t frag_paddr; +#ifdef HELIUMPLUS_DEBUG + void *frag_vaddr; + + frag_vaddr = qdf_nbuf_get_frag_vaddr(netbuf, i); +#endif + frag_len = qdf_nbuf_get_frag_len(netbuf, i); + frag_paddr = qdf_nbuf_get_frag_paddr(netbuf, i); +#if defined(HELIUMPLUS) + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_frag_desc, + i - 1, frag_paddr, frag_len); +#if defined(HELIUMPLUS_DEBUG) + qdf_debug("htt_fdesc=%pK frag=%d frag_vaddr=0x%pK frag_paddr=0x%llx len=%zu", + tx_desc->htt_frag_desc, + i-1, frag_vaddr, frag_paddr, frag_len); + ol_txrx_dump_pkt(netbuf, frag_paddr, 64); +#endif /* HELIUMPLUS_DEBUG */ +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_tx_desc, + i - 1, frag_paddr, frag_len); +#endif /* defined(HELIUMPLUS) */ + } + } + +#if defined(HELIUMPLUS_DEBUG) + ol_txrx_dump_frag_desc("ol_tx_desc_ll()", tx_desc); +#endif + return tx_desc; +} + +struct ol_tx_desc_t * +ol_tx_desc_hl( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + /* FIX THIS: these inits should probably be done by tx classify */ + msdu_info->htt.info.vdev_id = vdev->vdev_id; + msdu_info->htt.info.frame_type = pdev->htt_pkt_type; + msdu_info->htt.action.cksum_offload = qdf_nbuf_get_tx_cksum(netbuf); + switch (qdf_nbuf_get_exemption_type(netbuf)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info->htt.action.do_encrypt = 0; + break; + default: + qdf_assert(0); + break; + } + + /* allocate the descriptor */ + tx_desc = ol_tx_desc_alloc_hl(pdev, vdev, msdu_info); + if (!tx_desc) + return NULL; + + /* initialize the SW tx descriptor */ + tx_desc->netbuf = netbuf; + /* fix this - get pkt_type from msdu_info */ + tx_desc->pkt_type = OL_TX_FRM_STD; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + tx_desc->orig_l2_hdr_bytes = 0; +#endif + /* the HW tx descriptor will be initialized later by the caller */ + + return tx_desc; +} + +void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, + ol_tx_desc_list *tx_descs, int had_error) +{ + struct ol_tx_desc_t *tx_desc, *tmp; + qdf_nbuf_t msdus = NULL; + + TAILQ_FOREACH_SAFE(tx_desc, tx_descs, tx_desc_list_elem, tmp) { + qdf_nbuf_t msdu = tx_desc->netbuf; + + qdf_atomic_init(&tx_desc->ref_cnt); /* clear the ref cnt */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* restore original hdr offset */ + OL_TX_RESTORE_HDR(tx_desc, msdu); +#endif + + /* + * In MCC IPA tx context, IPA driver provides skb with directly + * DMA mapped address. In such case, there's no need for WLAN + * driver to DMA unmap the skb. + */ + if (qdf_nbuf_get_users(msdu) <= 1) { + if (!qdf_nbuf_ipa_owned_get(msdu)) + qdf_nbuf_unmap(pdev->osdev, msdu, + QDF_DMA_TO_DEVICE); + } + + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); + /* link the netbuf into a list to free as a batch */ + qdf_nbuf_set_next(msdu, msdus); + msdus = msdu; + } + /* free the netbufs as a batch */ + qdf_nbuf_tx_free(msdus, had_error); +} + +void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, int had_error) +{ + int mgmt_type; + ol_txrx_mgmt_tx_cb ota_ack_cb; + + qdf_atomic_init(&tx_desc->ref_cnt); /* clear the ref cnt */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* restore original hdr offset */ + OL_TX_RESTORE_HDR(tx_desc, (tx_desc->netbuf)); +#endif + if (tx_desc->pkt_type == OL_TX_FRM_NO_FREE) { + + /* free the tx desc but don't unmap or free the frame */ + if (pdev->tx_data_callback.func) { + qdf_nbuf_set_next(tx_desc->netbuf, NULL); + pdev->tx_data_callback.func(pdev->tx_data_callback.ctxt, + tx_desc->netbuf, had_error); + goto free_tx_desc; + } + /* let the code below unmap and free the frame */ + } + if (tx_desc->pkt_type == OL_TX_FRM_TSO) + ol_tso_unmap_tso_segment(pdev, tx_desc); + else + qdf_nbuf_unmap(pdev->osdev, tx_desc->netbuf, QDF_DMA_TO_DEVICE); + /* check the frame type to see what kind of special steps are needed */ + if ((tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) && + (tx_desc->pkt_type != ol_tx_frm_freed)) { + qdf_dma_addr_t frag_desc_paddr = 0; + +#if defined(HELIUMPLUS) + frag_desc_paddr = tx_desc->htt_frag_desc_paddr; + /* FIX THIS - + * The FW currently has trouble using the host's fragments + * table for management frames. Until this is fixed, + * rather than specifying the fragment table to the FW, + * the host SW will specify just the address of the initial + * fragment. + * Now that the mgmt frame is done, the HTT tx desc's frags + * table pointer needs to be reset. + */ +#if defined(HELIUMPLUS_DEBUG) + qdf_print("Frag Descriptor Reset [%d] to 0x%x", + tx_desc->id, + frag_desc_paddr); +#endif /* HELIUMPLUS_DEBUG */ +#endif /* HELIUMPLUS */ + htt_tx_desc_frags_table_set(pdev->htt_pdev, + tx_desc->htt_tx_desc, 0, + frag_desc_paddr, 1); + + mgmt_type = tx_desc->pkt_type - OL_TXRX_MGMT_TYPE_BASE; + /* + * we already checked the value when the mgmt frame was + * provided to the txrx layer. + * no need to check it a 2nd time. + */ + ota_ack_cb = pdev->tx_mgmt_cb.ota_ack_cb; + if (ota_ack_cb) { + void *ctxt; + ctxt = pdev->tx_mgmt_cb.ctxt; + ota_ack_cb(ctxt, tx_desc->netbuf, had_error); + } + } else if (had_error == htt_tx_status_download_fail) { + /* Failed to send to target */ + goto free_tx_desc; + } else { + /* single regular frame, called from completion path */ + qdf_nbuf_set_next(tx_desc->netbuf, NULL); + qdf_nbuf_tx_free(tx_desc->netbuf, had_error); + } +free_tx_desc: + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); +} + +#if defined(FEATURE_TSO) +#ifdef TSOSEG_DEBUG +static int +ol_tso_seg_dbg_sanitize(struct qdf_tso_seg_elem_t *tsoseg) +{ + int rc = -1; + struct ol_tx_desc_t *txdesc; + + if (tsoseg) { + txdesc = tsoseg->dbg.txdesc; + /* Don't validate if TX desc is NULL*/ + if (!txdesc) + return 0; + if (txdesc->tso_desc != tsoseg) + qdf_tso_seg_dbg_bug("Owner sanity failed"); + else + rc = 0; + } + return rc; + +}; +#else +static int +ol_tso_seg_dbg_sanitize(struct qdf_tso_seg_elem_t *tsoseg) +{ + return 0; +} +#endif /* TSOSEG_DEBUG */ + +/** + * ol_tso_alloc_segment() - function to allocate a TSO segment + * element + * @pdev: the data physical device sending the data + * + * Allocates a TSO segment element from the free list held in + * the pdev + * + * Return: tso_seg + */ +struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev) +{ + struct qdf_tso_seg_elem_t *tso_seg = NULL; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + if (pdev->tso_seg_pool.freelist) { + pdev->tso_seg_pool.num_free--; + tso_seg = pdev->tso_seg_pool.freelist; + if (tso_seg->on_freelist != 1) { + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_print("tso seg alloc failed: not in freelist"); + QDF_BUG(0); + return NULL; + } else if (tso_seg->cookie != TSO_SEG_MAGIC_COOKIE) { + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_print("tso seg alloc failed: bad cookie"); + QDF_BUG(0); + return NULL; + } + /*this tso seg is not a part of freelist now.*/ + tso_seg->on_freelist = 0; + tso_seg->sent_to_target = 0; + tso_seg->force_free = 0; + pdev->tso_seg_pool.freelist = pdev->tso_seg_pool.freelist->next; + qdf_tso_seg_dbg_record(tso_seg, TSOSEG_LOC_ALLOC); + } + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + return tso_seg; +} + +/** + * ol_tso_free_segment() - function to free a TSO segment + * element + * @pdev: the data physical device sending the data + * @tso_seg: The TSO segment element to be freed + * + * Returns a TSO segment element to the free list held in the + * pdev + * + * Return: none + */ +void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_seg_elem_t *tso_seg) +{ + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + if (tso_seg->on_freelist != 0) { + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_print("Do not free tso seg, already freed"); + QDF_BUG(0); + return; + } else if (tso_seg->cookie != TSO_SEG_MAGIC_COOKIE) { + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_print("Do not free tso seg: cookie is not good."); + QDF_BUG(0); + return; + } else if ((tso_seg->sent_to_target != 1) && + (tso_seg->force_free != 1)) { + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_print("Do not free tso seg: yet to be sent to target"); + QDF_BUG(0); + return; + } + /* sanitize before free */ + ol_tso_seg_dbg_sanitize(tso_seg); + qdf_tso_seg_dbg_setowner(tso_seg, NULL); + /*this tso seg is now a part of freelist*/ + /* retain segment history, if debug is enabled */ + qdf_tso_seg_dbg_zero(tso_seg); + tso_seg->next = pdev->tso_seg_pool.freelist; + tso_seg->on_freelist = 1; + tso_seg->sent_to_target = 0; + tso_seg->cookie = TSO_SEG_MAGIC_COOKIE; + pdev->tso_seg_pool.freelist = tso_seg; + pdev->tso_seg_pool.num_free++; + qdf_tso_seg_dbg_record(tso_seg, tso_seg->force_free + ? TSOSEG_LOC_FORCE_FREE + : TSOSEG_LOC_FREE); + tso_seg->force_free = 0; + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); +} + +/** + * ol_tso_num_seg_alloc() - function to allocate a element to count TSO segments + * in a jumbo skb packet. + * @pdev: the data physical device sending the data + * + * Allocates a element to count TSO segments from the free list held in + * the pdev + * + * Return: tso_num_seg + */ +struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc(struct ol_txrx_pdev_t *pdev) +{ + struct qdf_tso_num_seg_elem_t *tso_num_seg = NULL; + + qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + if (pdev->tso_num_seg_pool.freelist) { + pdev->tso_num_seg_pool.num_free--; + tso_num_seg = pdev->tso_num_seg_pool.freelist; + pdev->tso_num_seg_pool.freelist = + pdev->tso_num_seg_pool.freelist->next; + } + qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + + return tso_num_seg; +} + +/** + * ol_tso_num_seg_free() - function to free a TSO segment + * element + * @pdev: the data physical device sending the data + * @tso_seg: The TSO segment element to be freed + * + * Returns a element to the free list held in the pdev + * + * Return: none + */ +void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_num_seg_elem_t *tso_num_seg) +{ + qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + tso_num_seg->next = pdev->tso_num_seg_pool.freelist; + pdev->tso_num_seg_pool.freelist = tso_num_seg; + pdev->tso_num_seg_pool.num_free++; + qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_desc.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_desc.h new file mode 100644 index 0000000000..96342bca7c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_desc.h @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2011, 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_tx_desc.h + * @brief API definitions for the tx descriptor module within the data SW. + */ +#ifndef _OL_TX_DESC__H_ +#define _OL_TX_DESC__H_ + +#include "queue.h" /* TAILQ_HEAD */ +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include /*TXRX_ASSERT2 */ +#include + +#define DIV_BY_8 3 +#define DIV_BY_32 5 +#define MOD_BY_8 0x7 +#define MOD_BY_32 0x1F + +struct ol_tx_desc_t * +ol_tx_desc_alloc_wrapper(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Allocate and initialize a tx descriptor for a LL system. + * @details + * Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor + * for private use within the host data SW, and a HTT tx descriptor for + * downloading tx meta-data to the target FW/HW. + * Fill in the fields of this pair of tx descriptors based on the + * information in the netbuf. + * For LL, this includes filling in a fragmentation descriptor to + * specify to the MAC HW where to find the tx frame's fragments. + * + * @param pdev - the data physical device sending the data + * (for accessing the tx desc pool) + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param msdu_info - tx meta-data + */ +struct ol_tx_desc_t *ol_tx_desc_ll(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Allocate and initialize a tx descriptor for a HL system. + * @details + * Allocate a tx descriptor pair for a new tx frame - a SW tx descriptor + * for private use within the host data SW, and a HTT tx descriptor for + * downloading tx meta-data to the target FW/HW. + * Fill in the fields of this pair of tx descriptors based on the + * information in the netbuf. + * + * @param pdev - the data physical device sending the data + * (for accessing the tx desc pool) + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param msdu_info - tx meta-data + */ +struct ol_tx_desc_t * +ol_tx_desc_hl( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf, + struct ol_txrx_msdu_info_t *msdu_info); + + +/** + * @brief Use a tx descriptor ID to find the corresponding descriptor object. + * + * @param pdev - the data physical device sending the data + * @param tx_desc_id - the ID of the descriptor in question + * @return the descriptor object that has the specified ID + */ +static inline struct ol_tx_desc_t *ol_tx_desc_find( + struct ol_txrx_pdev_t *pdev, uint16_t tx_desc_id) +{ + void **td_base = (void **)pdev->tx_desc.desc_pages.cacheable_pages; + + return &((union ol_tx_desc_list_elem_t *) + (td_base[tx_desc_id >> pdev->tx_desc.page_divider] + + (pdev->tx_desc.desc_reserved_size * + (tx_desc_id & pdev->tx_desc.offset_filter))))->tx_desc; +} + +/** + * @brief Use a tx descriptor ID to find the corresponding descriptor object + * and add sanity check. + * + * @param pdev - the data physical device sending the data + * @param tx_desc_id - the ID of the descriptor in question + * @return the descriptor object that has the specified ID, + * if failure, will return NULL. + */ + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS +static inline struct ol_tx_desc_t * +ol_tx_desc_find_check(struct ol_txrx_pdev_t *pdev, u_int16_t tx_desc_id) +{ + struct ol_tx_desc_t *tx_desc; + + if (tx_desc_id >= pdev->tx_desc.pool_size) + return NULL; + + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + + if (tx_desc->pkt_type == ol_tx_frm_freed) + return NULL; + + return tx_desc; +} + +#else + +static inline struct ol_tx_desc_t * +ol_tx_desc_find_check(struct ol_txrx_pdev_t *pdev, u_int16_t tx_desc_id) +{ + struct ol_tx_desc_t *tx_desc; + + if (tx_desc_id >= pdev->tx_desc.pool_size) + return NULL; + + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + + /* check against invalid tx_desc_id */ + if (ol_cfg_is_high_latency(pdev->ctrl_pdev) && !tx_desc->vdev) + return NULL; + + return tx_desc; +} +#endif + +/** + * @brief Free a list of tx descriptors and the tx frames they refer to. + * @details + * Free a batch of "standard" tx descriptors and their tx frames. + * Free each tx descriptor, by returning it to the freelist. + * Unmap each netbuf, and free the netbufs as a batch. + * Irregular tx frames like TSO or management frames that require + * special handling are processed by the ol_tx_desc_frame_free_nonstd + * function rather than this function. + * + * @param pdev - the data physical device that sent the data + * @param tx_descs - a list of SW tx descriptors for the tx frames + * @param had_error - bool indication of whether the transmission failed. + * This is provided to callback functions that get notified of + * the tx frame completion. + */ +void ol_tx_desc_frame_list_free(struct ol_txrx_pdev_t *pdev, + ol_tx_desc_list *tx_descs, int had_error); + +/** + * @brief Free a non-standard tx frame and its tx descriptor. + * @details + * Check the tx frame type (e.g. TSO vs. management) to determine what + * special steps, if any, need to be performed prior to freeing the + * tx frame and its tx descriptor. + * This function can also be used to free single standard tx frames. + * After performing any special steps based on tx frame type, free the + * tx descriptor, i.e. return it to the freelist, and unmap and + * free the netbuf referenced by the tx descriptor. + * + * @param pdev - the data physical device that sent the data + * @param tx_desc - the SW tx descriptor for the tx frame that was sent + * @param had_error - bool indication of whether the transmission failed. + * This is provided to callback functions that get notified of + * the tx frame completion. + */ +void ol_tx_desc_frame_free_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, int had_error); + +/* + * @brief Determine the ID of a tx descriptor. + * + * @param pdev - the physical device that is sending the data + * @param tx_desc - the descriptor whose ID is being determined + * @return numeric ID that uniquely identifies the tx descriptor + */ +static inline uint16_t +ol_tx_desc_id(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc) +{ + TXRX_ASSERT2(tx_desc->id < pdev->tx_desc.pool_size); + return tx_desc->id; +} + +/* + * @brief Retrieves the beacon headr for the vdev + * @param pdev - opaque pointe to scn + * @param vdevid - vdev id + * @return void pointer to the beacon header for the given vdev + */ + +void *ol_ath_get_bcn_header(struct cdp_cfg *cfg_pdev, A_UINT32 vdev_id); + +/* + * @brief Free a tx descriptor, without freeing the matching frame. + * @details + * This function is using during the function call that submits tx frames + * into the txrx layer, for cases where a tx descriptor is successfully + * allocated, but for other reasons the frame could not be accepted. + * + * @param pdev - the data physical device that is sending the data + * @param tx_desc - the descriptor being freed + */ +void ol_tx_desc_free(struct ol_txrx_pdev_t *pdev, struct ol_tx_desc_t *tx_desc); + +#if defined(FEATURE_TSO) +struct qdf_tso_seg_elem_t *ol_tso_alloc_segment(struct ol_txrx_pdev_t *pdev); + +void ol_tso_free_segment(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_seg_elem_t *tso_seg); +struct qdf_tso_num_seg_elem_t *ol_tso_num_seg_alloc( + struct ol_txrx_pdev_t *pdev); +void ol_tso_num_seg_free(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_num_seg_elem_t *tso_num_seg); +void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev, + struct ol_txrx_msdu_info_t *msdu_info, + bool is_tso_seg_mapping_done); + +#else +#define ol_tso_alloc_segment(pdev) /*no-op*/ +#define ol_tso_free_segment(pdev, tso_seg) /*no-op*/ +#define ol_tso_num_seg_alloc(pdev) /*no-op*/ +#define ol_tso_num_seg_free(pdev, tso_num_seg) /*no-op*/ +/*no-op*/ +#define ol_free_remaining_tso_segs(vdev, msdu_info, is_tso_seg_mapping_done) +#endif + +/** + * ol_tx_get_desc_global_pool() - get descriptor from global pool + * @pdev: pdev handler + * + * Caller needs to take lock and do sanity checks. + * + * Return: tx descriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_get_desc_global_pool(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_desc_t *tx_desc = &pdev->tx_desc.freelist->tx_desc; + + pdev->tx_desc.freelist = pdev->tx_desc.freelist->next; + pdev->tx_desc.num_free--; + return tx_desc; +} + +/** + * ol_tx_put_desc_global_pool() - put descriptor to global pool freelist + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Caller needs to take lock and do sanity checks. + * + * Return: none + */ +static inline +void ol_tx_put_desc_global_pool(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + pdev->tx_desc.freelist; + pdev->tx_desc.freelist = + (union ol_tx_desc_list_elem_t *)tx_desc; + pdev->tx_desc.num_free++; +} + + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + +#ifdef QCA_LL_TX_FLOW_CONTROL_RESIZE +int ol_tx_distribute_descs_to_deficient_pools_from_global_pool(void); +#else +static inline +int ol_tx_distribute_descs_to_deficient_pools_from_global_pool(void) +{ + return 0; +} +#endif + +int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool); +/** + * ol_tx_get_desc_flow_pool() - get descriptor from flow pool + * @pool: flow pool + * + * Caller needs to take lock and do sanity checks. + * + * Return: tx descriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_get_desc_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + struct ol_tx_desc_t *tx_desc = &pool->freelist->tx_desc; + + pool->freelist = pool->freelist->next; + pool->avail_desc--; + return tx_desc; +} + +/** + * ol_tx_put_desc_flow_pool() - put descriptor to flow pool freelist + * @pool: flow pool + * @tx_desc: tx descriptor + * + * Caller needs to take lock and do sanity checks. + * + * Return: none + */ +static inline +void ol_tx_put_desc_flow_pool(struct ol_tx_flow_pool_t *pool, + struct ol_tx_desc_t *tx_desc) +{ + tx_desc->pool = pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = pool->freelist; + pool->freelist = (union ol_tx_desc_list_elem_t *)tx_desc; + pool->avail_desc++; +} + +#else +static inline int ol_tx_free_invalid_flow_pool(void *pool) +{ + return 0; +} +#endif + +#ifdef DESC_DUP_DETECT_DEBUG +/** + * ol_tx_desc_dup_detect_init() - initialize descriptor duplication logic + * @pdev: pdev handle + * @pool_size: global pool size + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_init(struct ol_txrx_pdev_t *pdev, uint16_t pool_size) +{ + uint16_t size = (pool_size >> DIV_BY_8) + + sizeof(*pdev->tx_desc.free_list_bitmap); + pdev->tx_desc.free_list_bitmap = qdf_mem_malloc(size); +} + +/** + * ol_tx_desc_dup_detect_deinit() - deinit descriptor duplication logic + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_deinit(struct ol_txrx_pdev_t *pdev) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: pool_size %d num_free %d\n", __func__, + pdev->tx_desc.pool_size, pdev->tx_desc.num_free); + if (pdev->tx_desc.free_list_bitmap) + qdf_mem_free(pdev->tx_desc.free_list_bitmap); +} + +/** + * ol_tx_desc_dup_detect_set() - set bit for msdu_id + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_set(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + uint16_t msdu_id = ol_tx_desc_id(pdev, tx_desc); + bool test; + + if (!pdev->tx_desc.free_list_bitmap) + return; + + if (qdf_unlikely(msdu_id > pdev->tx_desc.pool_size)) { + qdf_print("msdu_id %d > pool_size %d", + msdu_id, pdev->tx_desc.pool_size); + QDF_BUG(0); + } + + test = test_and_set_bit(msdu_id, pdev->tx_desc.free_list_bitmap); + if (qdf_unlikely(test)) { + uint16_t size = (pdev->tx_desc.pool_size >> DIV_BY_8) + + ((pdev->tx_desc.pool_size & MOD_BY_8) ? 1 : 0); + qdf_print("duplicate msdu_id %d detected!!", msdu_id); + qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + (void *)pdev->tx_desc.free_list_bitmap, size); + QDF_BUG(0); + } +} + +/** + * ol_tx_desc_dup_detect_reset() - reset bit for msdu_id + * @pdev: pdev handle + * @tx_desc: tx descriptor + * + * Return: none + */ +static inline +void ol_tx_desc_dup_detect_reset(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + uint16_t msdu_id = ol_tx_desc_id(pdev, tx_desc); + bool test; + + if (!pdev->tx_desc.free_list_bitmap) + return; + + if (qdf_unlikely(msdu_id > pdev->tx_desc.pool_size)) { + qdf_print("msdu_id %d > pool_size %d", + msdu_id, pdev->tx_desc.pool_size); + QDF_BUG(0); + } + + test = !test_and_clear_bit(msdu_id, pdev->tx_desc.free_list_bitmap); + if (qdf_unlikely(test)) { + uint16_t size = (pdev->tx_desc.pool_size >> DIV_BY_8) + + ((pdev->tx_desc.pool_size & MOD_BY_8) ? 1 : 0); + qdf_print("duplicate free msg received for msdu_id %d!!\n", + msdu_id); + qdf_trace_hex_dump(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + (void *)pdev->tx_desc.free_list_bitmap, size); + QDF_BUG(0); + } +} +#else +static inline +void ol_tx_desc_dup_detect_init(struct ol_txrx_pdev_t *pdev, uint16_t size) +{ +} + +static inline +void ol_tx_desc_dup_detect_deinit(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline +void ol_tx_desc_dup_detect_set(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} + +static inline +void ol_tx_desc_dup_detect_reset(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +enum extension_header_type +ol_tx_get_ext_header_type(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t netbuf); +enum extension_header_type +ol_tx_get_wisa_ext_type(qdf_nbuf_t netbuf); + + +#endif /* _OL_TX_DESC__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_hl.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_hl.c new file mode 100644 index 0000000000..1c284a2b5f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_hl.c @@ -0,0 +1,2351 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_atomic_inc, etc. */ +#include /* qdf_os_spinlock */ +#include /* qdf_system_ticks, etc. */ +#include /* qdf_nbuf_t */ +#include /* QDF_NBUF_TX_EXT_TID_INVALID */ + +#include "queue.h" /* TAILQ */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ethernet_hdr_t, etc. */ +#include /* ipv6_traffic_class */ +#endif + +#include /* ol_txrx_vdev_handle, etc. */ +#include /* htt_tx_compl_desc_id */ +#include /* htt_tx_status */ + +#include +#include +#include /* ol_txrx_vdev_t, etc */ +#include /* ol_tx_desc_find, ol_tx_desc_frame_free */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ol_tx_dest_addr_find */ +#endif +#include /* OL_TX_DESC_NO_REFS, etc. */ +#include +#include /* ol_tx_reinject */ +#include + +#include /* ol_cfg_is_high_latency */ +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include +#include +#include +#include +#include +#include "qdf_hrtimer.h" + +/* High/Low tx resource count in percentage */ +/* Set default high threshold to 15% */ +#ifndef TX_RESOURCE_HIGH_TH_IN_PER +#define TX_RESOURCE_HIGH_TH_IN_PER 15 +#endif + +/* Set default low threshold to 5% */ +#ifndef TX_RESOURCE_LOW_TH_IN_PER +#define TX_RESOURCE_LOW_TH_IN_PER 5 +#endif + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +static u16 ol_txrx_tx_desc_alloc_table[TXRX_FC_MAX] = { + [TXRX_FC_5GH_80M_2x2] = 2000, + [TXRX_FC_2GH_40M_2x2] = 800, +}; +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +/* tx filtering is handled within the target FW */ +#define TX_FILTER_CHECK(tx_msdu_info) 0 /* don't filter */ + +u_int16_t +ol_tx_desc_pool_size_hl(struct cdp_cfg *ctrl_pdev) +{ + uint16_t desc_pool_size; + uint16_t steady_state_tx_lifetime_ms; + uint16_t safety_factor; + + /* + * Steady-state tx latency: + * roughly 1-2 ms flight time + * + roughly 1-2 ms prep time, + * + roughly 1-2 ms target->host notification time. + * = roughly 6 ms total + * Thus, steady state number of frames = + * steady state max throughput / frame size * tx latency, e.g. + * 1 Gbps / 1500 bytes * 6 ms = 500 + * + */ + steady_state_tx_lifetime_ms = 6; + + safety_factor = 8; + + desc_pool_size = + ol_cfg_max_thruput_mbps(ctrl_pdev) * + 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ / + (8 * OL_TX_AVG_FRM_BYTES) * + steady_state_tx_lifetime_ms * + safety_factor; + + /* minimum */ + if (desc_pool_size < OL_TX_DESC_POOL_SIZE_MIN_HL) + desc_pool_size = OL_TX_DESC_POOL_SIZE_MIN_HL; + + /* maximum */ + if (desc_pool_size > OL_TX_DESC_POOL_SIZE_MAX_HL) + desc_pool_size = OL_TX_DESC_POOL_SIZE_MAX_HL; + + return desc_pool_size; +} + +#ifdef CONFIG_TX_DESC_HI_PRIO_RESERVE + +/** + * ol_tx_hl_desc_alloc() - Allocate and initialize a tx descriptor + * for a HL system. + * @pdev: the data physical device sending the data + * @vdev: the virtual device sending the data + * @msdu: the tx frame + * @msdu_info: the tx meta data + * + * Return: the tx descriptor + */ +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + if (qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) > + TXRX_HL_TX_DESC_HI_PRIO_RESERVED) { + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + } else if (qdf_nbuf_is_ipv4_pkt(msdu) == true) { + if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_DHCP) || + (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL)) { + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + ol_txrx_info("Got tx desc from resv pool"); + } + } + return tx_desc; +} + +#elif defined(QCA_HL_NETDEV_FLOW_CONTROL) +bool ol_tx_desc_is_high_prio(qdf_nbuf_t msdu) +{ + enum qdf_proto_subtype proto_subtype; + bool high_prio = false; + + if (qdf_nbuf_is_ipv4_pkt(msdu) == true) { + if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_DHCP) || + (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_EAPOL)) + high_prio = true; + } else if (QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_ARP) { + high_prio = true; + } else if ((QDF_NBUF_CB_GET_PACKET_TYPE(msdu) == + QDF_NBUF_CB_PACKET_TYPE_ICMPv6)) { + proto_subtype = qdf_nbuf_get_icmpv6_subtype(msdu); + switch (proto_subtype) { + case QDF_PROTO_ICMPV6_NA: + case QDF_PROTO_ICMPV6_NS: + high_prio = true; + default: + high_prio = false; + } + } + return high_prio; +} + +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = + ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + + if (!tx_desc) + return NULL; + + qdf_spin_lock_bh(&pdev->tx_mutex); + /* return if TX flow control disabled */ + if (vdev->tx_desc_limit == 0) { + qdf_spin_unlock_bh(&pdev->tx_mutex); + return tx_desc; + } + + if (!qdf_atomic_read(&vdev->os_q_paused) && + (qdf_atomic_read(&vdev->tx_desc_count) >= vdev->queue_stop_th)) { + /* + * Pause normal priority + * netdev queues if tx desc limit crosses + */ + pdev->pause_cb(vdev->vdev_id, + WLAN_STOP_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + qdf_atomic_set(&vdev->os_q_paused, 1); + } else if (ol_tx_desc_is_high_prio(msdu) && !vdev->prio_q_paused && + (qdf_atomic_read(&vdev->tx_desc_count) + == vdev->tx_desc_limit)) { + /* Pause high priority queue */ + pdev->pause_cb(vdev->vdev_id, + WLAN_NETIF_PRIORITY_QUEUE_OFF, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + vdev->prio_q_paused = 1; + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + return tx_desc; +} + +#else + +static inline +struct ol_tx_desc_t *ol_tx_hl_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + + tx_desc = ol_tx_desc_hl(pdev, vdev, msdu, msdu_info); + return tx_desc; +} +#endif + +static inline uint16_t +ol_txrx_rsrc_threshold_lo(int desc_pool_size) +{ + int threshold_low; + + /* always maintain a 5% margin of unallocated descriptors */ + threshold_low = ((TX_RESOURCE_LOW_TH_IN_PER) * + desc_pool_size) / 100; + + return threshold_low; +} + +static inline uint16_t +ol_txrx_rsrc_threshold_hi(int desc_pool_size) +{ + int threshold_high; + /* when freeing up descriptors, keep going until + * there's a 15% margin + */ + threshold_high = ((TX_RESOURCE_HIGH_TH_IN_PER) * + desc_pool_size) / 100; + + return threshold_high; +} + +void ol_tx_init_pdev(ol_txrx_pdev_handle pdev) +{ + uint16_t desc_pool_size, i; + + desc_pool_size = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev); + + qdf_atomic_init(&pdev->tx_queue.rsrc_cnt); + qdf_atomic_add(desc_pool_size, &pdev->tx_queue.rsrc_cnt); + + pdev->tx_queue.rsrc_threshold_lo = + ol_txrx_rsrc_threshold_lo(desc_pool_size); + pdev->tx_queue.rsrc_threshold_hi = + ol_txrx_rsrc_threshold_hi(desc_pool_size); + + for (i = 0 ; i < OL_TX_MAX_TXQ_GROUPS; i++) + qdf_atomic_init(&pdev->txq_grps[i].credit); + + ol_tx_target_credit_init(pdev, desc_pool_size); +} + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +static inline int ol_tx_encap_wrapper(struct ol_txrx_pdev_t *pdev, + ol_txrx_vdev_handle vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + if (OL_TX_ENCAP(vdev, tx_desc, msdu, tx_msdu_info) != A_OK) { + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + if (tx_msdu_info->peer) { + /* remove the peer reference added above */ + ol_txrx_peer_release_ref(tx_msdu_info->peer, + PEER_DEBUG_ID_OL_INTERNAL); + } + return -EINVAL; + } + + return 0; +} +#else +static inline int ol_tx_encap_wrapper(struct ol_txrx_pdev_t *pdev, + ol_txrx_vdev_handle vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + /* no-op */ + return 0; +} +#endif + +/** + * parse_ocb_tx_header() - Function to check for OCB + * @msdu: Pointer to OS packet (qdf_nbuf_t) + * @tx_ctrl: TX control header on a packet and extract it if present + * + * Return: true if ocb parsing is successful + */ +#ifdef WLAN_FEATURE_DSRC +#define OCB_HEADER_VERSION 1 +static bool parse_ocb_tx_header(qdf_nbuf_t msdu, + struct ocb_tx_ctrl_hdr_t *tx_ctrl) +{ + qdf_ether_header_t *eth_hdr_p; + struct ocb_tx_ctrl_hdr_t *tx_ctrl_hdr; + + /* Check if TX control header is present */ + eth_hdr_p = (qdf_ether_header_t *)qdf_nbuf_data(msdu); + if (eth_hdr_p->ether_type != QDF_SWAP_U16(ETHERTYPE_OCB_TX)) + /* TX control header is not present. Nothing to do.. */ + return true; + + /* Remove the ethernet header */ + qdf_nbuf_pull_head(msdu, sizeof(qdf_ether_header_t)); + + /* Parse the TX control header */ + tx_ctrl_hdr = (struct ocb_tx_ctrl_hdr_t *)qdf_nbuf_data(msdu); + + if (tx_ctrl_hdr->version == OCB_HEADER_VERSION) { + if (tx_ctrl) + qdf_mem_copy(tx_ctrl, tx_ctrl_hdr, + sizeof(*tx_ctrl_hdr)); + } else { + /* The TX control header is invalid. */ + return false; + } + + /* Remove the TX control header */ + qdf_nbuf_pull_head(msdu, tx_ctrl_hdr->length); + return true; +} +#else +static bool parse_ocb_tx_header(qdf_nbuf_t msdu, + struct ocb_tx_ctrl_hdr_t *tx_ctrl) +{ + return true; +} +#endif + +/** + * ol_txrx_mgmt_tx_desc_alloc() - Allocate and initialize a tx descriptor + * for management frame + * @pdev: the data physical device sending the data + * @vdev: the virtual device sending the data + * @tx_mgmt_frm: the tx management frame + * @tx_msdu_info: the tx meta data + * + * Return: the tx descriptor + */ +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + tx_msdu_info->htt.action.tx_comp_req = 1; + tx_desc = ol_tx_desc_hl(pdev, vdev, tx_mgmt_frm, tx_msdu_info); + return tx_desc; +} + +/** + * ol_txrx_mgmt_send_frame() - send a management frame + * @vdev: virtual device sending the frame + * @tx_desc: tx desc + * @tx_mgmt_frm: management frame to send + * @tx_msdu_info: the tx meta data + * @chanfreq: download change frequency + * + * Return: + * 0 -> the frame is accepted for transmission, -OR- + * 1 -> the frame was not accepted + */ +int ol_txrx_mgmt_send_frame( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_frms_queue_t *txq; + int status = 1; + + /* + * 1. Look up the peer and queue the frame in the peer's mgmt queue. + * 2. Invoke the download scheduler. + */ + txq = ol_tx_classify_mgmt(vdev, tx_desc, tx_mgmt_frm, tx_msdu_info); + if (!txq) { + /* TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, tx.dropped.no_txq, + * msdu); + */ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(vdev->pdev, tx_desc, + 1 /* error */); + goto out; /* can't accept the tx mgmt frame */ + } + /* Initialize the HTT tx desc l2 header offset field. + * Even though tx encap does not apply to mgmt frames, + * htt_tx_desc_mpdu_header still needs to be called, + * to specify that there was no L2 header added by tx encap, + * so the frame's length does not need to be adjusted to account for + * an added L2 header. + */ + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0); + if (qdf_unlikely(htt_tx_desc_init( + pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), + tx_mgmt_frm, + &tx_msdu_info->htt, &tx_msdu_info->tso_info, NULL, 0))) + goto out; + htt_tx_desc_display(tx_desc->htt_tx_desc); + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + + ol_tx_enqueue(vdev->pdev, txq, tx_desc, tx_msdu_info); + ol_tx_sched(vdev->pdev); + status = 0; +out: + if (tx_msdu_info->peer) { + /* remove the peer reference added above */ + ol_txrx_peer_release_ref(tx_msdu_info->peer, + PEER_DEBUG_ID_OL_INTERNAL); + } + + return status; +} + +/** + * ol_tx_hl_base() - send tx frames for a HL system. + * @vdev: the virtual device sending the data + * @tx_spec: indicate what non-standard transmission actions to apply + * @msdu_list: the tx frames to send + * @tx_comp_req: tx completion req + * @call_sched: will schedule the tx if true + * + * Return: NULL if all MSDUs are accepted + */ +static inline qdf_nbuf_t +ol_tx_hl_base( + ol_txrx_vdev_handle vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list, + int tx_comp_req, + bool call_sched) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t tx_msdu_info; + struct ocb_tx_ctrl_hdr_t tx_ctrl; + htt_pdev_handle htt_pdev = pdev->htt_pdev; + + tx_msdu_info.tso_info.is_tso = 0; + + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_frms_queue_t *txq; + struct ol_tx_desc_t *tx_desc = NULL; + + qdf_mem_zero(&tx_ctrl, sizeof(tx_ctrl)); + tx_msdu_info.peer = NULL; + /* + * The netbuf will get stored into a (peer-TID) tx queue list + * inside the ol_tx_classify_store function or else dropped, + * so store the next pointer immediately. + */ + next = qdf_nbuf_next(msdu); + + tx_desc = ol_tx_hl_desc_alloc(pdev, vdev, msdu, &tx_msdu_info); + + if (!tx_desc) { + /* + * If we're out of tx descs, there's no need to try + * to allocate tx descs for the remaining MSDUs. + */ + TXRX_STATS_MSDU_LIST_INCR(pdev, tx.dropped.host_reject, + msdu); + return msdu; /* the list of unaccepted MSDUs */ + } + + /* OL_TXRX_PROT_AN_LOG(pdev->prot_an_tx_sent, msdu);*/ + + qdf_dp_trace_log_pkt(vdev->vdev_id, msdu, QDF_TX, + QDF_TRACE_DEFAULT_PDEV_ID, + vdev->qdf_opmode); + DPTRACE(qdf_dp_trace_data_pkt(msdu, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_TX_PACKET_RECORD, + tx_desc->id, QDF_TX)); + + if (tx_spec != OL_TX_SPEC_STD) { +#if defined(FEATURE_WLAN_TDLS) + if (tx_spec & OL_TX_SPEC_NO_FREE) { + tx_desc->pkt_type = OL_TX_FRM_NO_FREE; + } else if (tx_spec & OL_TX_SPEC_TSO) { +#else + if (tx_spec & OL_TX_SPEC_TSO) { +#endif + tx_desc->pkt_type = OL_TX_FRM_TSO; + } + if (ol_txrx_tx_is_raw(tx_spec)) { + /* CHECK THIS: does this need + * to happen after htt_tx_desc_init? + */ + /* different types of raw frames */ + u_int8_t sub_type = + ol_txrx_tx_raw_subtype( + tx_spec); + htt_tx_desc_type(htt_pdev, + tx_desc->htt_tx_desc, + htt_pkt_type_raw, + sub_type); + } + } + + tx_msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + tx_msdu_info.htt.info.vdev_id = vdev->vdev_id; + tx_msdu_info.htt.info.frame_type = htt_frm_type_data; + tx_msdu_info.htt.info.l2_hdr_type = pdev->htt_pkt_type; + + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(msdu) + == 1) { + tx_msdu_info.htt.action.tx_comp_req = 1; + tx_desc->pkt_type = OL_TX_FRM_NO_FREE; + } else { + tx_msdu_info.htt.action.tx_comp_req = + tx_comp_req; + } + + /* If the vdev is in OCB mode, + * parse the tx control header. + */ + if (vdev->opmode == wlan_op_mode_ocb) { + if (!parse_ocb_tx_header(msdu, &tx_ctrl)) { + /* There was an error parsing + * the header.Skip this packet. + */ + goto MSDU_LOOP_BOTTOM; + } + } + + txq = ol_tx_classify(vdev, tx_desc, msdu, + &tx_msdu_info); + + /* initialize the HW tx descriptor */ + htt_tx_desc_init( + pdev->htt_pdev, tx_desc->htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + ol_tx_desc_id(pdev, tx_desc), + msdu, + &tx_msdu_info.htt, + &tx_msdu_info.tso_info, + &tx_ctrl, + vdev->opmode == wlan_op_mode_ocb); + + if ((!txq) || TX_FILTER_CHECK(&tx_msdu_info)) { + /* drop this frame, + * but try sending subsequent frames + */ + /* TXRX_STATS_MSDU_LIST_INCR(pdev, + * tx.dropped.no_txq, msdu); + */ + qdf_atomic_inc(&pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + if (tx_msdu_info.peer) { + /* remove the peer reference + * added above + */ + ol_txrx_peer_release_ref( + tx_msdu_info.peer, + PEER_DEBUG_ID_OL_INTERNAL); + } + goto MSDU_LOOP_BOTTOM; + } + + if (tx_msdu_info.peer) { + /* + * If the state is not associated then drop all + * the data packets received for that peer + */ + if (tx_msdu_info.peer->state == + OL_TXRX_PEER_STATE_DISC) { + qdf_atomic_inc( + &pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, + 1); + ol_txrx_peer_release_ref( + tx_msdu_info.peer, + PEER_DEBUG_ID_OL_INTERNAL); + msdu = next; + continue; + } else if (tx_msdu_info.peer->state != + OL_TXRX_PEER_STATE_AUTH) { + if (tx_msdu_info.htt.info.ethertype != + ETHERTYPE_PAE && + tx_msdu_info.htt.info.ethertype + != ETHERTYPE_WAI) { + qdf_atomic_inc( + &pdev->tx_queue. + rsrc_cnt); + ol_tx_desc_frame_free_nonstd( + pdev, + tx_desc, 1); + ol_txrx_peer_release_ref( + tx_msdu_info.peer, + PEER_DEBUG_ID_OL_INTERNAL); + msdu = next; + continue; + } + } + } + /* + * Initialize the HTT tx desc l2 header offset field. + * htt_tx_desc_mpdu_header needs to be called to + * make sure, the l2 header size is initialized + * correctly to handle cases where TX ENCAP is disabled + * or Tx Encap fails to perform Encap + */ + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, 0); + + /* + * Note: when the driver is built without support for + * SW tx encap,the following macro is a no-op. + * When the driver is built with support for SW tx + * encap, it performs encap, and if an error is + * encountered, jumps to the MSDU_LOOP_BOTTOM label. + */ + if (ol_tx_encap_wrapper(pdev, vdev, tx_desc, msdu, + &tx_msdu_info)) + goto MSDU_LOOP_BOTTOM; + + /* + * If debug display is enabled, show the meta-data + * being downloaded to the target via the + * HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + ol_tx_enqueue(pdev, txq, tx_desc, &tx_msdu_info); + if (tx_msdu_info.peer) { + OL_TX_PEER_STATS_UPDATE(tx_msdu_info.peer, + msdu); + /* remove the peer reference added above */ + ol_txrx_peer_release_ref + (tx_msdu_info.peer, + PEER_DEBUG_ID_OL_INTERNAL); + } +MSDU_LOOP_BOTTOM: + msdu = next; + } + + if (call_sched) + ol_tx_sched(pdev); + return NULL; /* all MSDUs were accepted */ +} + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + +/** + * ol_tx_pdev_reset_driver_del_ack() - reset driver delayed ack enabled flag + * @soc_hdl: soc handle + * @pdev_id: datapath pdev identifier + * + * Return: none + */ +void +ol_tx_pdev_reset_driver_del_ack(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_vdev_t *vdev; + + if (!pdev) + return; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + vdev->driver_del_ack_enabled = false; + + dp_debug("vdev_id %d driver_del_ack_enabled %d", + vdev->vdev_id, vdev->driver_del_ack_enabled); + } +} + +/** + * ol_tx_vdev_set_driver_del_ack_enable() - set driver delayed ack enabled flag + * @soc_hdl: datapath soc handle + * @vdev_id: vdev id + * @rx_packets: number of rx packets + * @time_in_ms: time in ms + * @high_th: high threshold + * @low_th: low threshold + * + * Return: none + */ +void +ol_tx_vdev_set_driver_del_ack_enable(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + unsigned long rx_packets, + uint32_t time_in_ms, + uint32_t high_th, + uint32_t low_th) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *) + ol_txrx_get_vdev_from_vdev_id(vdev_id); + bool old_driver_del_ack_enabled; + + if ((!vdev) || (low_th > high_th)) + return; + + old_driver_del_ack_enabled = vdev->driver_del_ack_enabled; + if (rx_packets > high_th) + vdev->driver_del_ack_enabled = true; + else if (rx_packets < low_th) + vdev->driver_del_ack_enabled = false; + + if (old_driver_del_ack_enabled != vdev->driver_del_ack_enabled) { + dp_debug("vdev_id %d driver_del_ack_enabled %d rx_packets %ld time_in_ms %d high_th %d low_th %d", + vdev->vdev_id, vdev->driver_del_ack_enabled, + rx_packets, time_in_ms, high_th, low_th); + } +} + +/** + * ol_tx_hl_send_all_tcp_ack() - send all queued tcp ack packets + * @vdev: vdev handle + * + * Return: none + */ +void ol_tx_hl_send_all_tcp_ack(struct ol_txrx_vdev_t *vdev) +{ + int i; + struct tcp_stream_node *tcp_node_list; + struct tcp_stream_node *temp; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + for (i = 0; i < OL_TX_HL_DEL_ACK_HASH_SIZE; i++) { + tcp_node_list = NULL; + qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock); + if (vdev->tcp_ack_hash.node[i].no_of_entries) + tcp_node_list = vdev->tcp_ack_hash.node[i].head; + + vdev->tcp_ack_hash.node[i].no_of_entries = 0; + vdev->tcp_ack_hash.node[i].head = NULL; + qdf_spin_unlock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock); + + /* Send all packets */ + while (tcp_node_list) { + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + qdf_nbuf_t msdu_list; + + temp = tcp_node_list; + tcp_node_list = temp->next; + + msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, + temp->head, + tx_comp_req, false); + if (msdu_list) + qdf_nbuf_tx_free(msdu_list, 1/*error*/); + ol_txrx_vdev_free_tcp_node(vdev, temp); + } + } + ol_tx_sched(vdev->pdev); +} + +/** + * tcp_del_ack_tasklet() - tasklet function to send ack packets + * @data: vdev handle + * + * Return: none + */ +void tcp_del_ack_tasklet(void *data) +{ + struct ol_txrx_vdev_t *vdev = data; + + ol_tx_hl_send_all_tcp_ack(vdev); +} + +/** + * ol_tx_get_stream_id() - get stream_id from packet info + * @info: packet info + * + * Return: stream_id + */ +uint16_t ol_tx_get_stream_id(struct packet_info *info) +{ + return ((info->dst_port + info->dst_ip + info->src_port + info->src_ip) + & (OL_TX_HL_DEL_ACK_HASH_SIZE - 1)); +} + +/** + * ol_tx_is_tcp_ack() - check whether the packet is tcp ack frame + * @msdu: packet + * + * Return: true if the packet is tcp ack frame + */ +static bool +ol_tx_is_tcp_ack(qdf_nbuf_t msdu) +{ + uint16_t ether_type; + uint8_t protocol; + uint8_t flag, ip_header_len, tcp_header_len; + uint32_t seg_len; + uint8_t *skb_data; + uint32_t skb_len; + bool tcp_acked = false; + uint32_t tcp_header_off; + + qdf_nbuf_peek_header(msdu, &skb_data, &skb_len); + if (skb_len < (QDF_NBUF_TRAC_IPV4_OFFSET + + QDF_NBUF_TRAC_IPV4_HEADER_SIZE + + QDF_NBUF_TRAC_TCP_FLAGS_OFFSET)) + goto exit; + + ether_type = (uint16_t)(*(uint16_t *) + (skb_data + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + protocol = (uint16_t)(*(uint16_t *) + (skb_data + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + + if ((QDF_SWAP_U16(QDF_NBUF_TRAC_IPV4_ETH_TYPE) == ether_type) && + (protocol == QDF_NBUF_TRAC_TCP_TYPE)) { + ip_header_len = ((uint8_t)(*(uint8_t *) + (skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) & + QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2; + tcp_header_off = QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len; + + tcp_header_len = ((uint8_t)(*(uint8_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_HEADER_LEN_OFFSET))) >> 2; + seg_len = skb_len - tcp_header_len - tcp_header_off; + flag = (uint8_t)(*(uint8_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_FLAGS_OFFSET)); + + if ((flag == QDF_NBUF_TRAC_TCP_ACK_MASK) && (seg_len == 0)) + tcp_acked = true; + } + +exit: + + return tcp_acked; +} + +/** + * ol_tx_get_packet_info() - update packet info for passed msdu + * @msdu: packet + * @info: packet info + * + * Return: none + */ +void ol_tx_get_packet_info(qdf_nbuf_t msdu, struct packet_info *info) +{ + uint16_t ether_type; + uint8_t protocol; + uint8_t flag, ip_header_len, tcp_header_len; + uint32_t seg_len; + uint8_t *skb_data; + uint32_t skb_len; + uint32_t tcp_header_off; + + info->type = NO_TCP_PKT; + + qdf_nbuf_peek_header(msdu, &skb_data, &skb_len); + if (skb_len < (QDF_NBUF_TRAC_IPV4_OFFSET + + QDF_NBUF_TRAC_IPV4_HEADER_SIZE + + QDF_NBUF_TRAC_TCP_FLAGS_OFFSET)) + return; + + ether_type = (uint16_t)(*(uint16_t *) + (skb_data + QDF_NBUF_TRAC_ETH_TYPE_OFFSET)); + protocol = (uint16_t)(*(uint16_t *) + (skb_data + QDF_NBUF_TRAC_IPV4_PROTO_TYPE_OFFSET)); + + if ((QDF_SWAP_U16(QDF_NBUF_TRAC_IPV4_ETH_TYPE) == ether_type) && + (protocol == QDF_NBUF_TRAC_TCP_TYPE)) { + ip_header_len = ((uint8_t)(*(uint8_t *) + (skb_data + QDF_NBUF_TRAC_IPV4_OFFSET)) & + QDF_NBUF_TRAC_IPV4_HEADER_MASK) << 2; + tcp_header_off = QDF_NBUF_TRAC_IPV4_OFFSET + ip_header_len; + + tcp_header_len = ((uint8_t)(*(uint8_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_HEADER_LEN_OFFSET))) >> 2; + seg_len = skb_len - tcp_header_len - tcp_header_off; + flag = (uint8_t)(*(uint8_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_FLAGS_OFFSET)); + + info->src_ip = QDF_SWAP_U32((uint32_t)(*(uint32_t *) + (skb_data + QDF_NBUF_TRAC_IPV4_SRC_ADDR_OFFSET))); + info->dst_ip = QDF_SWAP_U32((uint32_t)(*(uint32_t *) + (skb_data + QDF_NBUF_TRAC_IPV4_DEST_ADDR_OFFSET))); + info->src_port = QDF_SWAP_U16((uint16_t)(*(uint16_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_SPORT_OFFSET))); + info->dst_port = QDF_SWAP_U16((uint16_t)(*(uint16_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_DPORT_OFFSET))); + info->stream_id = ol_tx_get_stream_id(info); + + if ((flag == QDF_NBUF_TRAC_TCP_ACK_MASK) && (seg_len == 0)) { + info->type = TCP_PKT_ACK; + info->ack_number = (uint32_t)(*(uint32_t *) + (skb_data + tcp_header_off + + QDF_NBUF_TRAC_TCP_ACK_OFFSET)); + info->ack_number = QDF_SWAP_U32(info->ack_number); + } else { + info->type = TCP_PKT_NO_ACK; + } + } +} + +/** + * ol_tx_hl_find_and_send_tcp_stream() - find and send tcp stream for passed + * stream info + * @vdev: vdev handle + * @info: packet info + * + * Return: none + */ +void ol_tx_hl_find_and_send_tcp_stream(struct ol_txrx_vdev_t *vdev, + struct packet_info *info) +{ + uint8_t no_of_entries; + struct tcp_stream_node *node_to_be_remove = NULL; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + /* remove tcp node from hash */ + qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[info->stream_id]. + hash_node_lock); + + no_of_entries = vdev->tcp_ack_hash.node[info->stream_id]. + no_of_entries; + if (no_of_entries > 1) { + /* collision case */ + struct tcp_stream_node *head = + vdev->tcp_ack_hash.node[info->stream_id].head; + struct tcp_stream_node *temp; + + if ((head->dst_ip == info->dst_ip) && + (head->src_ip == info->src_ip) && + (head->src_port == info->src_port) && + (head->dst_port == info->dst_port)) { + node_to_be_remove = head; + vdev->tcp_ack_hash.node[info->stream_id].head = + head->next; + vdev->tcp_ack_hash.node[info->stream_id]. + no_of_entries--; + } else { + temp = head; + while (temp->next) { + if ((temp->next->dst_ip == info->dst_ip) && + (temp->next->src_ip == info->src_ip) && + (temp->next->src_port == info->src_port) && + (temp->next->dst_port == info->dst_port)) { + node_to_be_remove = temp->next; + temp->next = temp->next->next; + vdev->tcp_ack_hash. + node[info->stream_id]. + no_of_entries--; + break; + } + temp = temp->next; + } + } + } else if (no_of_entries == 1) { + /* Only one tcp_node */ + node_to_be_remove = + vdev->tcp_ack_hash.node[info->stream_id].head; + vdev->tcp_ack_hash.node[info->stream_id].head = NULL; + vdev->tcp_ack_hash.node[info->stream_id].no_of_entries = 0; + } + qdf_spin_unlock_bh(&vdev->tcp_ack_hash. + node[info->stream_id].hash_node_lock); + + /* send packets */ + if (node_to_be_remove) { + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + qdf_nbuf_t msdu_list; + + msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, + node_to_be_remove->head, + tx_comp_req, true); + if (msdu_list) + qdf_nbuf_tx_free(msdu_list, 1/*error*/); + ol_txrx_vdev_free_tcp_node(vdev, node_to_be_remove); + } +} + +static struct tcp_stream_node * +ol_tx_hl_rep_tcp_ack(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu, + struct packet_info *info, bool *is_found, + bool *start_timer) +{ + struct tcp_stream_node *node_to_be_remove = NULL; + struct tcp_stream_node *head = + vdev->tcp_ack_hash.node[info->stream_id].head; + struct tcp_stream_node *temp; + + if ((head->dst_ip == info->dst_ip) && + (head->src_ip == info->src_ip) && + (head->src_port == info->src_port) && + (head->dst_port == info->dst_port)) { + *is_found = true; + if ((head->ack_number < info->ack_number) && + (head->no_of_ack_replaced < + ol_cfg_get_del_ack_count_value(vdev->pdev->ctrl_pdev))) { + /* replace ack packet */ + qdf_nbuf_tx_free(head->head, 1); + head->head = msdu; + head->ack_number = info->ack_number; + head->no_of_ack_replaced++; + *start_timer = true; + + vdev->no_of_tcpack_replaced++; + + if (head->no_of_ack_replaced == + ol_cfg_get_del_ack_count_value( + vdev->pdev->ctrl_pdev)) { + node_to_be_remove = head; + vdev->tcp_ack_hash.node[info->stream_id].head = + head->next; + vdev->tcp_ack_hash.node[info->stream_id]. + no_of_entries--; + } + } else { + /* append and send packets */ + head->head->next = msdu; + node_to_be_remove = head; + vdev->tcp_ack_hash.node[info->stream_id].head = + head->next; + vdev->tcp_ack_hash.node[info->stream_id]. + no_of_entries--; + } + } else { + temp = head; + while (temp->next) { + if ((temp->next->dst_ip == info->dst_ip) && + (temp->next->src_ip == info->src_ip) && + (temp->next->src_port == info->src_port) && + (temp->next->dst_port == info->dst_port)) { + *is_found = true; + if ((temp->next->ack_number < + info->ack_number) && + (temp->next->no_of_ack_replaced < + ol_cfg_get_del_ack_count_value( + vdev->pdev->ctrl_pdev))) { + /* replace ack packet */ + qdf_nbuf_tx_free(temp->next->head, 1); + temp->next->head = msdu; + temp->next->ack_number = + info->ack_number; + temp->next->no_of_ack_replaced++; + *start_timer = true; + + vdev->no_of_tcpack_replaced++; + + if (temp->next->no_of_ack_replaced == + ol_cfg_get_del_ack_count_value( + vdev->pdev->ctrl_pdev)) { + node_to_be_remove = temp->next; + temp->next = temp->next->next; + vdev->tcp_ack_hash. + node[info->stream_id]. + no_of_entries--; + } + } else { + /* append and send packets */ + temp->next->head->next = msdu; + node_to_be_remove = temp->next; + temp->next = temp->next->next; + vdev->tcp_ack_hash. + node[info->stream_id]. + no_of_entries--; + } + break; + } + temp = temp->next; + } + } + return node_to_be_remove; +} + +/** + * ol_tx_hl_find_and_replace_tcp_ack() - find and replace tcp ack packet for + * passed packet info + * @vdev: vdev handle + * @msdu: packet + * @info: packet info + * + * Return: none + */ +void ol_tx_hl_find_and_replace_tcp_ack(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct packet_info *info) +{ + uint8_t no_of_entries; + struct tcp_stream_node *node_to_be_remove = NULL; + bool is_found = false, start_timer = false; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + /* replace ack if required or send packets */ + qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[info->stream_id]. + hash_node_lock); + + no_of_entries = vdev->tcp_ack_hash.node[info->stream_id].no_of_entries; + if (no_of_entries > 0) { + node_to_be_remove = ol_tx_hl_rep_tcp_ack(vdev, msdu, info, + &is_found, + &start_timer); + } + + if (no_of_entries == 0 || !is_found) { + /* Alloc new tcp node */ + struct tcp_stream_node *new_node; + + new_node = ol_txrx_vdev_alloc_tcp_node(vdev); + if (!new_node) { + qdf_spin_unlock_bh(&vdev->tcp_ack_hash. + node[info->stream_id].hash_node_lock); + dp_alert("Malloc failed"); + return; + } + new_node->stream_id = info->stream_id; + new_node->dst_ip = info->dst_ip; + new_node->src_ip = info->src_ip; + new_node->dst_port = info->dst_port; + new_node->src_port = info->src_port; + new_node->ack_number = info->ack_number; + new_node->head = msdu; + new_node->next = NULL; + new_node->no_of_ack_replaced = 0; + + start_timer = true; + /* insert new_node */ + if (!vdev->tcp_ack_hash.node[info->stream_id].head) { + vdev->tcp_ack_hash.node[info->stream_id].head = + new_node; + vdev->tcp_ack_hash.node[info->stream_id]. + no_of_entries = 1; + } else { + struct tcp_stream_node *temp = + vdev->tcp_ack_hash.node[info->stream_id].head; + while (temp->next) + temp = temp->next; + + temp->next = new_node; + vdev->tcp_ack_hash.node[info->stream_id]. + no_of_entries++; + } + } + qdf_spin_unlock_bh(&vdev->tcp_ack_hash.node[info->stream_id]. + hash_node_lock); + + /* start timer */ + if (start_timer && + (!qdf_atomic_read(&vdev->tcp_ack_hash.is_timer_running))) { + qdf_hrtimer_start(&vdev->tcp_ack_hash.timer, + qdf_ns_to_ktime(( + ol_cfg_get_del_ack_timer_value( + vdev->pdev->ctrl_pdev) * + 1000000)), + __QDF_HRTIMER_MODE_REL); + qdf_atomic_set(&vdev->tcp_ack_hash.is_timer_running, 1); + } + + /* send packets */ + if (node_to_be_remove) { + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + qdf_nbuf_t msdu_list = NULL; + + msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, + node_to_be_remove->head, + tx_comp_req, true); + if (msdu_list) + qdf_nbuf_tx_free(msdu_list, 1/*error*/); + ol_txrx_vdev_free_tcp_node(vdev, node_to_be_remove); + } +} + +/** + * ol_tx_hl_vdev_tcp_del_ack_timer() - delayed ack timer function + * @timer: timer handle + * + * Return: enum + */ +enum qdf_hrtimer_restart_status +ol_tx_hl_vdev_tcp_del_ack_timer(qdf_hrtimer_data_t *timer) +{ + struct ol_txrx_vdev_t *vdev = qdf_container_of(timer, + struct ol_txrx_vdev_t, + tcp_ack_hash.timer); + enum qdf_hrtimer_restart_status ret = QDF_HRTIMER_NORESTART; + + qdf_sched_bh(&vdev->tcp_ack_hash.tcp_del_ack_tq); + qdf_atomic_set(&vdev->tcp_ack_hash.is_timer_running, 0); + return ret; +} + +/** + * ol_tx_hl_del_ack_queue_flush_all() - drop all queued packets + * @vdev: vdev handle + * + * Return: none + */ +void ol_tx_hl_del_ack_queue_flush_all(struct ol_txrx_vdev_t *vdev) +{ + int i; + struct tcp_stream_node *tcp_node_list; + struct tcp_stream_node *temp; + + qdf_hrtimer_cancel(&vdev->tcp_ack_hash.timer); + for (i = 0; i < OL_TX_HL_DEL_ACK_HASH_SIZE; i++) { + tcp_node_list = NULL; + qdf_spin_lock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock); + + if (vdev->tcp_ack_hash.node[i].no_of_entries) + tcp_node_list = vdev->tcp_ack_hash.node[i].head; + + vdev->tcp_ack_hash.node[i].no_of_entries = 0; + vdev->tcp_ack_hash.node[i].head = NULL; + qdf_spin_unlock_bh(&vdev->tcp_ack_hash.node[i].hash_node_lock); + + /* free all packets */ + while (tcp_node_list) { + temp = tcp_node_list; + tcp_node_list = temp->next; + + qdf_nbuf_tx_free(temp->head, 1/*error*/); + ol_txrx_vdev_free_tcp_node(vdev, temp); + } + } + ol_txrx_vdev_deinit_tcp_del_ack(vdev); +} + +/** + * ol_txrx_vdev_init_tcp_del_ack() - initialize tcp delayed ack structure + * @vdev: vdev handle + * + * Return: none + */ +void ol_txrx_vdev_init_tcp_del_ack(struct ol_txrx_vdev_t *vdev) +{ + int i; + + vdev->driver_del_ack_enabled = false; + + dp_debug("vdev-id=%u, driver_del_ack_enabled=%d", + vdev->vdev_id, + vdev->driver_del_ack_enabled); + + vdev->no_of_tcpack = 0; + vdev->no_of_tcpack_replaced = 0; + + qdf_hrtimer_init(&vdev->tcp_ack_hash.timer, + ol_tx_hl_vdev_tcp_del_ack_timer, + __QDF_CLOCK_MONOTONIC, + __QDF_HRTIMER_MODE_REL, + QDF_CONTEXT_HARDWARE + ); + qdf_create_bh(&vdev->tcp_ack_hash.tcp_del_ack_tq, + tcp_del_ack_tasklet, + vdev); + qdf_atomic_init(&vdev->tcp_ack_hash.is_timer_running); + qdf_atomic_init(&vdev->tcp_ack_hash.tcp_node_in_use_count); + qdf_spinlock_create(&vdev->tcp_ack_hash.tcp_free_list_lock); + vdev->tcp_ack_hash.tcp_free_list = NULL; + for (i = 0; i < OL_TX_HL_DEL_ACK_HASH_SIZE; i++) { + qdf_spinlock_create(&vdev->tcp_ack_hash.node[i].hash_node_lock); + vdev->tcp_ack_hash.node[i].no_of_entries = 0; + vdev->tcp_ack_hash.node[i].head = NULL; + } +} + +/** + * ol_txrx_vdev_deinit_tcp_del_ack() - deinitialize tcp delayed ack structure + * @vdev: vdev handle + * + * Return: none + */ +void ol_txrx_vdev_deinit_tcp_del_ack(struct ol_txrx_vdev_t *vdev) +{ + struct tcp_stream_node *temp; + + qdf_destroy_bh(&vdev->tcp_ack_hash.tcp_del_ack_tq); + + qdf_spin_lock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock); + while (vdev->tcp_ack_hash.tcp_free_list) { + temp = vdev->tcp_ack_hash.tcp_free_list; + vdev->tcp_ack_hash.tcp_free_list = temp->next; + qdf_mem_free(temp); + } + qdf_spin_unlock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock); +} + +/** + * ol_txrx_vdev_free_tcp_node() - add tcp node in free list + * @vdev: vdev handle + * @node: tcp stream node + * + * Return: none + */ +void ol_txrx_vdev_free_tcp_node(struct ol_txrx_vdev_t *vdev, + struct tcp_stream_node *node) +{ + qdf_atomic_dec(&vdev->tcp_ack_hash.tcp_node_in_use_count); + + qdf_spin_lock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock); + if (vdev->tcp_ack_hash.tcp_free_list) { + node->next = vdev->tcp_ack_hash.tcp_free_list; + vdev->tcp_ack_hash.tcp_free_list = node; + } else { + vdev->tcp_ack_hash.tcp_free_list = node; + node->next = NULL; + } + qdf_spin_unlock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock); +} + +/** + * ol_txrx_vdev_alloc_tcp_node() - allocate tcp node + * @vdev: vdev handle + * + * Return: tcp stream node + */ +struct tcp_stream_node *ol_txrx_vdev_alloc_tcp_node(struct ol_txrx_vdev_t *vdev) +{ + struct tcp_stream_node *node = NULL; + + qdf_spin_lock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock); + if (vdev->tcp_ack_hash.tcp_free_list) { + node = vdev->tcp_ack_hash.tcp_free_list; + vdev->tcp_ack_hash.tcp_free_list = node->next; + } + qdf_spin_unlock_bh(&vdev->tcp_ack_hash.tcp_free_list_lock); + + if (!node) { + node = qdf_mem_malloc(sizeof(struct ol_txrx_vdev_t)); + if (!node) + return NULL; + } + qdf_atomic_inc(&vdev->tcp_ack_hash.tcp_node_in_use_count); + return node; +} + +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + struct packet_info pkt_info; + qdf_nbuf_t temp; + + if (ol_tx_is_tcp_ack(msdu_list)) + vdev->no_of_tcpack++; + + /* check Enable through ini */ + if (!ol_cfg_get_del_ack_enable_value(vdev->pdev->ctrl_pdev) || + (!vdev->driver_del_ack_enabled)) { + if (qdf_atomic_read(&vdev->tcp_ack_hash.tcp_node_in_use_count)) + ol_tx_hl_send_all_tcp_ack(vdev); + + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, + tx_comp_req, true); + } + + ol_tx_get_packet_info(msdu_list, &pkt_info); + + if (pkt_info.type == TCP_PKT_NO_ACK) { + ol_tx_hl_find_and_send_tcp_stream(vdev, &pkt_info); + temp = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, + tx_comp_req, true); + return temp; + } + + if (pkt_info.type == TCP_PKT_ACK) { + ol_tx_hl_find_and_replace_tcp_ack(vdev, msdu_list, &pkt_info); + return NULL; + } + + temp = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, + tx_comp_req, true); + return temp; +} +#else + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +void +ol_tx_pdev_reset_bundle_require(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + struct ol_txrx_vdev_t *vdev; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + vdev->bundling_required = false; + ol_txrx_info("vdev_id %d bundle_require %d", + vdev->vdev_id, vdev->bundling_required); + } +} + +void +ol_tx_vdev_set_bundle_require(uint8_t vdev_id, unsigned long tx_bytes, + uint32_t time_in_ms, uint32_t high_th, + uint32_t low_th) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *) + ol_txrx_get_vdev_from_vdev_id(vdev_id); + bool old_bundle_required; + + if ((!vdev) || (low_th > high_th)) + return; + + old_bundle_required = vdev->bundling_required; + if (tx_bytes > ((high_th * time_in_ms * 1500) / 1000)) + vdev->bundling_required = true; + else if (tx_bytes < ((low_th * time_in_ms * 1500) / 1000)) + vdev->bundling_required = false; + + if (old_bundle_required != vdev->bundling_required) + ol_txrx_info("vdev_id %d bundle_require %d tx_bytes %ld time_in_ms %d high_th %d low_th %d", + vdev->vdev_id, vdev->bundling_required, tx_bytes, + time_in_ms, high_th, low_th); +} + +/** + * ol_tx_hl_queue_flush_all() - drop all packets in vdev bundle queue + * @vdev: vdev handle + * + * Return: none + */ +void +ol_tx_hl_queue_flush_all(struct ol_txrx_vdev_t *vdev) +{ + qdf_spin_lock_bh(&vdev->bundle_queue.mutex); + if (vdev->bundle_queue.txq.depth != 0) { + qdf_timer_stop(&vdev->bundle_queue.timer); + vdev->pdev->total_bundle_queue_length -= + vdev->bundle_queue.txq.depth; + qdf_nbuf_tx_free(vdev->bundle_queue.txq.head, 1/*error*/); + vdev->bundle_queue.txq.depth = 0; + vdev->bundle_queue.txq.head = NULL; + vdev->bundle_queue.txq.tail = NULL; + } + qdf_spin_unlock_bh(&vdev->bundle_queue.mutex); +} + +/** + * ol_tx_hl_vdev_queue_append() - append pkt in tx queue + * @vdev: vdev handle + * @msdu_list: msdu list + * + * Return: none + */ +static void +ol_tx_hl_vdev_queue_append(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu_list) +{ + qdf_spin_lock_bh(&vdev->bundle_queue.mutex); + + if (!vdev->bundle_queue.txq.head) { + qdf_timer_start( + &vdev->bundle_queue.timer, + ol_cfg_get_bundle_timer_value(vdev->pdev->ctrl_pdev)); + vdev->bundle_queue.txq.head = msdu_list; + vdev->bundle_queue.txq.tail = msdu_list; + } else { + qdf_nbuf_set_next(vdev->bundle_queue.txq.tail, msdu_list); + } + + while (qdf_nbuf_next(msdu_list)) { + vdev->bundle_queue.txq.depth++; + vdev->pdev->total_bundle_queue_length++; + msdu_list = qdf_nbuf_next(msdu_list); + } + + vdev->bundle_queue.txq.depth++; + vdev->pdev->total_bundle_queue_length++; + vdev->bundle_queue.txq.tail = msdu_list; + qdf_spin_unlock_bh(&vdev->bundle_queue.mutex); +} + +/** + * ol_tx_hl_vdev_queue_send_all() - send all packets in vdev bundle queue + * @vdev: vdev handle + * @call_sched: invoke scheduler + * + * Return: NULL for success + */ +static qdf_nbuf_t +ol_tx_hl_vdev_queue_send_all(struct ol_txrx_vdev_t *vdev, bool call_sched, + bool in_timer_context) +{ + qdf_nbuf_t msdu_list = NULL; + qdf_nbuf_t skb_list_head, skb_list_tail; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + int pkt_to_sent; + + qdf_spin_lock_bh(&vdev->bundle_queue.mutex); + + if (!vdev->bundle_queue.txq.depth) { + qdf_spin_unlock_bh(&vdev->bundle_queue.mutex); + return msdu_list; + } + + if (likely((qdf_atomic_read(&vdev->tx_desc_count) + + vdev->bundle_queue.txq.depth) < + vdev->queue_stop_th)) { + qdf_timer_stop(&vdev->bundle_queue.timer); + vdev->pdev->total_bundle_queue_length -= + vdev->bundle_queue.txq.depth; + msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, + vdev->bundle_queue.txq.head, + tx_comp_req, call_sched); + vdev->bundle_queue.txq.depth = 0; + vdev->bundle_queue.txq.head = NULL; + vdev->bundle_queue.txq.tail = NULL; + } else { + pkt_to_sent = vdev->queue_stop_th - + qdf_atomic_read(&vdev->tx_desc_count); + + if (pkt_to_sent) { + skb_list_head = vdev->bundle_queue.txq.head; + + while (pkt_to_sent) { + skb_list_tail = + vdev->bundle_queue.txq.head; + vdev->bundle_queue.txq.head = + qdf_nbuf_next(vdev->bundle_queue.txq.head); + vdev->pdev->total_bundle_queue_length--; + vdev->bundle_queue.txq.depth--; + pkt_to_sent--; + if (!vdev->bundle_queue.txq.head) { + qdf_timer_stop( + &vdev->bundle_queue.timer); + break; + } + } + + qdf_nbuf_set_next(skb_list_tail, NULL); + msdu_list = ol_tx_hl_base(vdev, OL_TX_SPEC_STD, + skb_list_head, tx_comp_req, + call_sched); + } + + if (in_timer_context && vdev->bundle_queue.txq.head) { + qdf_timer_start( + &vdev->bundle_queue.timer, + ol_cfg_get_bundle_timer_value( + vdev->pdev->ctrl_pdev)); + } + } + qdf_spin_unlock_bh(&vdev->bundle_queue.mutex); + + return msdu_list; +} + +/** + * ol_tx_hl_pdev_queue_send_all() - send all packets from all vdev bundle queue + * @pdev: pdev handle + * + * Return: NULL for success + */ +qdf_nbuf_t +ol_tx_hl_pdev_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + qdf_nbuf_t msdu_list; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + msdu_list = ol_tx_hl_vdev_queue_send_all(vdev, false, false); + if (msdu_list) + qdf_nbuf_tx_free(msdu_list, 1/*error*/); + } + ol_tx_sched(pdev); + return NULL; /* all msdus were accepted */ +} + +/** + * ol_tx_hl_vdev_bundle_timer() - bundle timer function + * @vdev: vdev handle + * + * Return: none + */ +void +ol_tx_hl_vdev_bundle_timer(void *ctx) +{ + qdf_nbuf_t msdu_list; + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)ctx; + + vdev->no_of_bundle_sent_in_timer++; + msdu_list = ol_tx_hl_vdev_queue_send_all(vdev, true, true); + if (msdu_list) + qdf_nbuf_tx_free(msdu_list, 1/*error*/); +} + +qdf_nbuf_t +ol_tx_hl(struct ol_txrx_vdev_t *vdev, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + + /* No queuing for high priority packets */ + if (ol_tx_desc_is_high_prio(msdu_list)) { + vdev->no_of_pkt_not_added_in_queue++; + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, + tx_comp_req, true); + } else if (vdev->bundling_required && + (ol_cfg_get_bundle_size(vdev->pdev->ctrl_pdev) > 1)) { + ol_tx_hl_vdev_queue_append(vdev, msdu_list); + + if (pdev->total_bundle_queue_length >= + ol_cfg_get_bundle_size(vdev->pdev->ctrl_pdev)) { + vdev->no_of_bundle_sent_after_threshold++; + return ol_tx_hl_pdev_queue_send_all(pdev); + } + } else { + if (vdev->bundle_queue.txq.depth != 0) { + ol_tx_hl_vdev_queue_append(vdev, msdu_list); + return ol_tx_hl_vdev_queue_send_all(vdev, true, false); + } else { + vdev->no_of_pkt_not_added_in_queue++; + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, msdu_list, + tx_comp_req, true); + } + } + + return NULL; /* all msdus were accepted */ +} + +#else + +qdf_nbuf_t +ol_tx_hl(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + + return ol_tx_hl_base(vdev, OL_TX_SPEC_STD, + msdu_list, tx_comp_req, true); +} +#endif +#endif + +qdf_nbuf_t ol_tx_non_std_hl(struct ol_txrx_vdev_t *vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int tx_comp_req = pdev->cfg.default_tx_comp_req || + pdev->cfg.request_tx_comp; + + if (!tx_comp_req) { + if ((tx_spec == OL_TX_SPEC_NO_FREE) && + (pdev->tx_data_callback.func)) + tx_comp_req = 1; + } + return ol_tx_hl_base(vdev, tx_spec, msdu_list, tx_comp_req, true); +} + +#ifdef FEATURE_WLAN_TDLS +void ol_txrx_copy_mac_addr_raw(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *bss_addr) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return; + + qdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + if (bss_addr && vdev->last_real_peer && + !qdf_mem_cmp((u8 *)bss_addr, + vdev->last_real_peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE)) + qdf_mem_copy(vdev->hl_tdls_ap_mac_addr.raw, + vdev->last_real_peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); +} + +void +ol_txrx_add_last_real_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint8_t vdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + ol_txrx_peer_handle peer; + + if (!pdev || !vdev) + return; + + peer = ol_txrx_find_peer_by_addr( + (struct cdp_pdev *)pdev, + vdev->hl_tdls_ap_mac_addr.raw); + + qdf_spin_lock_bh(&pdev->last_real_peer_mutex); + if (!vdev->last_real_peer && peer && + (peer->peer_ids[0] != HTT_INVALID_PEER_ID)) { + vdev->last_real_peer = peer; + qdf_mem_zero(vdev->hl_tdls_ap_mac_addr.raw, + QDF_MAC_ADDR_SIZE); + } + qdf_spin_unlock_bh(&pdev->last_real_peer_mutex); +} + +bool is_vdev_restore_last_peer(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return false; + + pdev = vdev->pdev; + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, peer_mac); + + return vdev->last_real_peer && (vdev->last_real_peer == peer); +} + +void ol_txrx_update_last_real_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint8_t vdev_id, bool restore_last_peer) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + struct ol_txrx_peer_t *peer; + + if (!restore_last_peer || !pdev || !vdev) + return; + + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, + vdev->hl_tdls_ap_mac_addr.raw); + + qdf_spin_lock_bh(&pdev->last_real_peer_mutex); + if (!vdev->last_real_peer && peer && + (peer->peer_ids[0] != HTT_INVALID_PEER_ID)) { + vdev->last_real_peer = peer; + qdf_mem_zero(vdev->hl_tdls_ap_mac_addr.raw, + QDF_MAC_ADDR_SIZE); + } + qdf_spin_unlock_bh(&pdev->last_real_peer_mutex); +} + +void ol_txrx_set_peer_as_tdls_peer(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac, bool val) +{ + ol_txrx_peer_handle peer; + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return; + + pdev = vdev->pdev; + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, peer_mac); + + ol_txrx_info_high("peer %pK, peer->ref_cnt %d", + peer, qdf_atomic_read(&peer->ref_cnt)); + + /* Mark peer as tdls */ + if (peer) + peer->is_tdls_peer = val; +} + +void ol_txrx_set_tdls_offchan_enabled(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac, bool val) +{ + ol_txrx_peer_handle peer; + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return; + + pdev = vdev->pdev; + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, peer_mac); + + ol_txrx_info_high("peer %pK, peer->ref_cnt %d", + peer, qdf_atomic_read(&peer->ref_cnt)); + + /* Set TDLS Offchan operation enable/disable */ + if (peer && peer->is_tdls_peer) + peer->tdls_offchan_enabled = val; +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) +/** + * ol_txrx_pdev_txq_log_init() - initialise pdev txq logs + * @pdev: the physical device object + * + * Return: None + */ +void ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->txq_log_spinlock); + pdev->txq_log.size = OL_TXQ_LOG_SIZE; + pdev->txq_log.oldest_record_offset = 0; + pdev->txq_log.offset = 0; + pdev->txq_log.allow_wrap = 1; + pdev->txq_log.wrapped = 0; +} + +/** + * ol_txrx_pdev_txq_log_destroy() - remove txq log spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +void ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->txq_log_spinlock); +} +#endif + +#if defined(DEBUG_HL_LOGGING) + +/** + * ol_txrx_pdev_grp_stats_init() - initialise group stat spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +void ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->grp_stat_spinlock); + pdev->grp_stats.last_valid_index = -1; + pdev->grp_stats.wrap_around = 0; +} + +/** + * ol_txrx_pdev_grp_stat_destroy() - destroy group stat spinlock for pdev + * @pdev: the physical device object + * + * Return: None + */ +void ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->grp_stat_spinlock); +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +/** + * ol_txrx_hl_tdls_flag_reset() - reset tdls flag for vdev + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * @flag: flag + * + * Return: None + */ +void +ol_txrx_hl_tdls_flag_reset(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + bool flag) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return; + } + + vdev->hlTdlsFlag = flag; +} +#endif + +/** + * ol_txrx_vdev_txqs_init() - initialise vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +void ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) +{ + uint8_t i; + + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + TAILQ_INIT(&vdev->txqs[i].head); + vdev->txqs[i].paused_count.total = 0; + vdev->txqs[i].frms = 0; + vdev->txqs[i].bytes = 0; + vdev->txqs[i].ext_tid = OL_TX_NUM_TIDS + i; + vdev->txqs[i].flag = ol_tx_queue_empty; + /* aggregation is not applicable for vdev tx queues */ + vdev->txqs[i].aggr_state = ol_tx_aggr_disabled; + ol_tx_txq_set_group_ptr(&vdev->txqs[i], NULL); + ol_txrx_set_txq_peer(&vdev->txqs[i], NULL); + } +} + +/** + * ol_txrx_vdev_tx_queue_free() - free vdev tx queues + * @vdev: the virtual device object + * + * Return: None + */ +void ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_frms_queue_t *txq; + int i; + + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + txq = &vdev->txqs[i]; + ol_tx_queue_free(pdev, txq, (i + OL_TX_NUM_TIDS), false); + } +} + +/** + * ol_txrx_peer_txqs_init() - initialise peer tx queues + * @pdev: the physical device object + * @peer: peer object + * + * Return: None + */ +void ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + uint8_t i; + struct ol_txrx_vdev_t *vdev = peer->vdev; + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + TAILQ_INIT(&peer->txqs[i].head); + peer->txqs[i].paused_count.total = 0; + peer->txqs[i].frms = 0; + peer->txqs[i].bytes = 0; + peer->txqs[i].ext_tid = i; + peer->txqs[i].flag = ol_tx_queue_empty; + peer->txqs[i].aggr_state = ol_tx_aggr_untried; + ol_tx_set_peer_group_ptr(pdev, peer, vdev->vdev_id, i); + ol_txrx_set_txq_peer(&peer->txqs[i], peer); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + /* aggregation is not applicable for mgmt and non-QoS tx queues */ + for (i = OL_TX_NUM_QOS_TIDS; i < OL_TX_NUM_TIDS; i++) + peer->txqs[i].aggr_state = ol_tx_aggr_disabled; + + ol_txrx_peer_pause(peer); +} + +/** + * ol_txrx_peer_tx_queue_free() - free peer tx queues + * @pdev: the physical device object + * @peer: peer object + * + * Return: None + */ +void ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + struct ol_tx_frms_queue_t *txq; + uint8_t i; + + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + txq = &peer->txqs[i]; + ol_tx_queue_free(pdev, txq, i, true); + } +} + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_txrx_update_group_credit() - update group credit for tx queue + * @group: for which credit needs to be updated + * @credit: credits + * @absolute: TXQ group absolute + * + * Return: allocated pool size + */ +void ol_txrx_update_group_credit( + struct ol_tx_queue_group_t *group, + int32_t credit, + u_int8_t absolute) +{ + if (absolute) + qdf_atomic_set(&group->credit, credit); + else + qdf_atomic_add(credit, &group->credit); +} + +/** + * ol_txrx_update_tx_queue_groups() - update vdev tx queue group if + * vdev id mask and ac mask is not matching + * @pdev: the data physical device + * @group_id: TXQ group id + * @credit: TXQ group credit count + * @absolute: TXQ group absolute + * @vdev_id_mask: TXQ vdev group id mask + * @ac_mask: TQX access category mask + * + * Return: None + */ +void ol_txrx_update_tx_queue_groups( + ol_txrx_pdev_handle pdev, + u_int8_t group_id, + int32_t credit, + u_int8_t absolute, + u_int32_t vdev_id_mask, + u_int32_t ac_mask + ) +{ + struct ol_tx_queue_group_t *group; + u_int32_t group_vdev_bit_mask, vdev_bit_mask, group_vdev_id_mask; + u_int32_t membership; + struct ol_txrx_vdev_t *vdev; + + if (group_id >= OL_TX_MAX_TXQ_GROUPS) { + ol_txrx_warn("invalid group_id=%u, ignore update", group_id); + return; + } + + group = &pdev->txq_grps[group_id]; + + membership = OL_TXQ_GROUP_MEMBERSHIP_GET(vdev_id_mask, ac_mask); + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + /* + * if the membership (vdev id mask and ac mask) + * matches then no need to update tx qeue groups. + */ + if (group->membership == membership) + /* Update Credit Only */ + goto credit_update; + + credit += ol_txrx_distribute_group_credits(pdev, group_id, + vdev_id_mask); + /* + * membership (vdev id mask and ac mask) is not matching + * TODO: ignoring ac mask for now + */ + qdf_assert(ac_mask == 0xffff); + group_vdev_id_mask = + OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership); + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + group_vdev_bit_mask = + OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET( + group_vdev_id_mask, vdev->vdev_id); + vdev_bit_mask = + OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET( + vdev_id_mask, vdev->vdev_id); + + if (group_vdev_bit_mask != vdev_bit_mask) { + /* + * Change in vdev tx queue group + */ + if (!vdev_bit_mask) { + /* Set Group Pointer (vdev and peer) to NULL */ + ol_txrx_info("Group membership removed for vdev_id %d from group_id %d", + vdev->vdev_id, group_id); + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, NULL); + } else { + /* Set Group Pointer (vdev and peer) */ + ol_txrx_info("Group membership updated for vdev_id %d to group_id %d", + vdev->vdev_id, group_id); + ol_tx_set_vdev_group_ptr( + pdev, vdev->vdev_id, group); + } + } + } + /* Update membership */ + group->membership = membership; + ol_txrx_info("Group membership updated for group_id %d membership 0x%x", + group_id, group->membership); +credit_update: + /* Update Credit */ + ol_txrx_update_group_credit(group, credit, absolute); + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); +} +#endif + +#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \ + defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING) +#define MIN_INIT_GROUP_CREDITS 10 +int ol_txrx_distribute_group_credits(struct ol_txrx_pdev_t *pdev, + u8 group_id, + u32 vdevid_mask_new) +{ + struct ol_tx_queue_group_t *grp = &pdev->txq_grps[group_id]; + struct ol_tx_queue_group_t *grp_nxt = &pdev->txq_grps[!group_id]; + int creds_nxt = qdf_atomic_read(&grp_nxt->credit); + int vdevid_mask = OL_TXQ_GROUP_VDEV_ID_MASK_GET(grp->membership); + int vdevid_mask_othgrp = + OL_TXQ_GROUP_VDEV_ID_MASK_GET(grp_nxt->membership); + int creds_distribute = 0; + + /* if vdev added to the group is the first vdev */ + if ((vdevid_mask == 0) && (vdevid_mask_new != 0)) { + /* if other group has members */ + if (vdevid_mask_othgrp) { + if (creds_nxt < MIN_INIT_GROUP_CREDITS) + creds_distribute = creds_nxt / 2; + else + creds_distribute = MIN_INIT_GROUP_CREDITS; + + ol_txrx_update_group_credit(grp_nxt, -creds_distribute, + 0); + } else { + /* + * Other grp has no members, give all credits to this + * grp. + */ + creds_distribute = + qdf_atomic_read(&pdev->target_tx_credit); + } + /* if all vdevs are removed from this grp */ + } else if ((vdevid_mask != 0) && (vdevid_mask_new == 0)) { + if (vdevid_mask_othgrp) + /* Transfer credits to other grp */ + ol_txrx_update_group_credit(grp_nxt, + qdf_atomic_read(&grp-> + credit), + 0); + /* Set current grp credits to zero */ + ol_txrx_update_group_credit(grp, 0, 1); + } + + return creds_distribute; +} +#endif /* + * FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL && + * FEATURE_HL_DBS_GROUP_CREDIT_SHARING + */ + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +int ol_txrx_register_hl_flow_control(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + tx_pause_callback flowcontrol) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + u32 desc_pool_size; + + if (!pdev || !flowcontrol) { + ol_txrx_err("pdev or pause_cb is NULL"); + return QDF_STATUS_E_INVAL; + } + + desc_pool_size = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev); + /* + * Assert if the tx descriptor pool size meets the requirements + * Maximum 2 sessions are allowed on a band. + */ + QDF_ASSERT((2 * ol_txrx_tx_desc_alloc_table[TXRX_FC_5GH_80M_2x2] + + ol_txrx_tx_desc_alloc_table[TXRX_FC_2GH_40M_2x2]) + <= desc_pool_size); + + pdev->pause_cb = flowcontrol; + return 0; +} + +int ol_txrx_set_vdev_os_queue_status(struct cdp_soc_t *soc_hdl, u8 vdev_id, + enum netif_action_type action) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + switch (action) { + case WLAN_NETIF_PRIORITY_QUEUE_ON: + qdf_spin_lock_bh(&vdev->pdev->tx_mutex); + vdev->prio_q_paused = 0; + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + break; + case WLAN_WAKE_NON_PRIORITY_QUEUE: + qdf_atomic_set(&vdev->os_q_paused, 0); + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid action %d", __func__, action); + return -EINVAL; + } + return 0; +} + +int ol_txrx_set_vdev_tx_desc_limit(struct cdp_soc_t *soc_hdl, u8 vdev_id, + u32 chan_freq) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + enum ol_txrx_fc_limit_id fc_limit_id; + u32 td_limit; + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + /* TODO: Handle no of spatial streams and channel BW */ + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) + fc_limit_id = TXRX_FC_5GH_80M_2x2; + else + fc_limit_id = TXRX_FC_2GH_40M_2x2; + + qdf_spin_lock_bh(&vdev->pdev->tx_mutex); + td_limit = ol_txrx_tx_desc_alloc_table[fc_limit_id]; + vdev->tx_desc_limit = td_limit; + vdev->queue_stop_th = td_limit - TXRX_HL_TX_DESC_HI_PRIO_RESERVED; + vdev->queue_restart_th = td_limit - TXRX_HL_TX_DESC_QUEUE_RESTART_TH; + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + + return 0; +} + +void ol_tx_dump_flow_pool_info_compact(struct ol_txrx_pdev_t *pdev) +{ + char *comb_log_str; + int bytes_written = 0; + uint32_t free_size; + struct ol_txrx_vdev_t *vdev; + int i = 0; + + free_size = WLAN_MAX_VDEVS * 100; + comb_log_str = qdf_mem_malloc(free_size); + if (!comb_log_str) + return; + + qdf_spin_lock_bh(&pdev->tx_mutex); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + bytes_written += snprintf(&comb_log_str[bytes_written], + free_size, "%d (%d,%d)(%d,%d)(%d,%d) |", + vdev->vdev_id, vdev->tx_desc_limit, + qdf_atomic_read(&vdev->tx_desc_count), + qdf_atomic_read(&vdev->os_q_paused), + vdev->prio_q_paused, vdev->queue_stop_th, + vdev->queue_restart_th); + free_size -= bytes_written; + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + qdf_nofl_debug("STATS | FC: %s", comb_log_str); + + free_size = WLAN_MAX_VDEVS * 100; + bytes_written = 0; + qdf_mem_zero(comb_log_str, free_size); + + bytes_written = snprintf(&comb_log_str[bytes_written], free_size, + "%d ", + qdf_atomic_read(&pdev->target_tx_credit)); + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + bytes_written += snprintf(&comb_log_str[bytes_written], + free_size, "|%d, (0x%x, %d)", i, + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership), + qdf_atomic_read( + &pdev->txq_grps[i].credit)); + free_size -= bytes_written; + } + qdf_nofl_debug("STATS | CREDIT: %s", comb_log_str); + qdf_mem_free(comb_log_str); +} + +void ol_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev; + struct ol_txrx_vdev_t *vdev; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + qdf_spin_lock_bh(&pdev->tx_mutex); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + txrx_nofl_info("vdev_id %d", vdev->vdev_id); + txrx_nofl_info("limit %d available %d stop_threshold %d restart_threshold %d", + vdev->tx_desc_limit, + qdf_atomic_read(&vdev->tx_desc_count), + vdev->queue_stop_th, vdev->queue_restart_th); + txrx_nofl_info("q_paused %d prio_q_paused %d", + qdf_atomic_read(&vdev->os_q_paused), + vdev->prio_q_paused); + txrx_nofl_info("no_of_bundle_sent_after_threshold %lld", + vdev->no_of_bundle_sent_after_threshold); + txrx_nofl_info("no_of_bundle_sent_in_timer %lld", + vdev->no_of_bundle_sent_in_timer); + txrx_nofl_info("no_of_pkt_not_added_in_queue %lld", + vdev->no_of_pkt_not_added_in_queue); + } + qdf_spin_unlock_bh(&pdev->tx_mutex); +} +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll.c new file mode 100644 index 0000000000..389249b81b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll.c @@ -0,0 +1,800 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_atomic_inc, etc. */ +#include /* qdf_os_spinlock */ +#include /* qdf_system_ticks, etc. */ +#include /* qdf_nbuf_t */ +#include /* QDF_NBUF_TX_EXT_TID_INVALID */ + +#include "queue.h" /* TAILQ */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ethernet_hdr_t, etc. */ +#include /* ipv6_traffic_class */ +#endif + +#include /* ol_txrx_vdev_handle, etc. */ +#include /* htt_tx_compl_desc_id */ +#include /* htt_tx_status */ + +#include +#include +#include /* ol_txrx_vdev_t, etc */ +#include /* ol_tx_desc_find, ol_tx_desc_frame_free */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ol_tx_dest_addr_find */ +#endif +#include /* OL_TX_DESC_NO_REFS, etc. */ +#include +#include /* ol_tx_reinject */ +#include + +#include /* ol_cfg_is_high_latency */ +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include +#include +#include +#include + +void ol_tx_init_pdev(ol_txrx_pdev_handle pdev) +{ + qdf_atomic_add(ol_cfg_target_tx_credit(pdev->ctrl_pdev), + &pdev->target_tx_credit); +} + +qdf_nbuf_t ol_tx_reinject(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, uint16_t peer_id) +{ + struct ol_tx_desc_t *tx_desc = NULL; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.info.ext_tid = HTT_TX_EXT_TID_INVALID; + msdu_info.peer = NULL; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + + tx_desc = ol_tx_prepare_ll(vdev, msdu, &msdu_info); + if (!tx_desc) + return msdu; + + HTT_TX_DESC_POSTPONED_SET(*((uint32_t *)(tx_desc->htt_tx_desc)), true); + + htt_tx_desc_set_peer_id(tx_desc->htt_tx_desc, peer_id); + + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + + return NULL; +} + +/* + * The TXRX module doesn't accept tx frames unless the target has + * enough descriptors for them. + * For LL, the TXRX descriptor pool is sized to match the target's + * descriptor pool. Hence, if the descriptor allocation in TXRX + * succeeds, that guarantees that the target has room to accept + * the new tx frame. + */ +struct ol_tx_desc_t * +ol_tx_prepare_ll(ol_txrx_vdev_handle vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + (msdu_info)->htt.info.frame_type = pdev->htt_pkt_type; + tx_desc = ol_tx_desc_ll(pdev, vdev, msdu, msdu_info); + if (qdf_unlikely(!tx_desc)) { + /* + * If TSO packet, free associated + * remaining TSO segment descriptors + */ + if (qdf_nbuf_is_tso(msdu)) + ol_free_remaining_tso_segs( + vdev, msdu_info, true); + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + return NULL; + } + + return tx_desc; +} + +qdf_nbuf_t +ol_tx_non_std_ll(struct ol_txrx_vdev_t *vdev, + enum ol_tx_spec tx_spec, + qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + htt_pdev_handle htt_pdev = vdev->pdev->htt_pdev; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc = NULL; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + msdu_info.tso_info.is_tso = 0; + + tx_desc = ol_tx_prepare_ll(vdev, msdu, &msdu_info); + if (!tx_desc) + return msdu; + + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = qdf_nbuf_next(msdu); + + if (tx_spec != OL_TX_SPEC_STD) { + if (tx_spec & OL_TX_SPEC_NO_FREE) { + tx_desc->pkt_type = OL_TX_FRM_NO_FREE; + } else if (tx_spec & OL_TX_SPEC_TSO) { + tx_desc->pkt_type = OL_TX_FRM_TSO; + } else if (tx_spec & OL_TX_SPEC_NWIFI_NO_ENCRYPT) { + uint8_t sub_type = + ol_txrx_tx_raw_subtype(tx_spec); + htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, + htt_pkt_type_native_wifi, + sub_type); + } else if (ol_txrx_tx_is_raw(tx_spec)) { + /* different types of raw frames */ + uint8_t sub_type = + ol_txrx_tx_raw_subtype(tx_spec); + htt_tx_desc_type(htt_pdev, tx_desc->htt_tx_desc, + htt_pkt_type_raw, sub_type); + } + } + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + msdu = next; + } + return NULL; /* all MSDUs were accepted */ +} + +void ol_tx_trace_pkt(qdf_nbuf_t skb, uint16_t msdu_id, uint8_t vdev_id, + enum QDF_OPMODE op_mode) +{ + DPTRACE(qdf_dp_trace_ptr(skb, + QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(skb), + sizeof(qdf_nbuf_data(skb)), + msdu_id, vdev_id, 0, + op_mode)); + + qdf_dp_trace_log_pkt(vdev_id, skb, QDF_TX, QDF_TRACE_DEFAULT_PDEV_ID, + op_mode); + + DPTRACE(qdf_dp_trace_data_pkt(skb, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_TX_PACKET_RECORD, + msdu_id, QDF_TX)); +} + +#if defined(HELIUMPLUS) +void ol_txrx_dump_frag_desc(char *msg, struct ol_tx_desc_t *tx_desc) +{ + uint32_t *frag_ptr_i_p; + int i; + + ol_txrx_err("OL TX Descriptor 0x%pK msdu_id %d", + tx_desc, tx_desc->id); + ol_txrx_err("HTT TX Descriptor vaddr: 0x%pK paddr: %pad", + tx_desc->htt_tx_desc, &tx_desc->htt_tx_desc_paddr); + ol_txrx_err("Fragment Descriptor 0x%pK (paddr=%pad)", + tx_desc->htt_frag_desc, &tx_desc->htt_frag_desc_paddr); + + /* + * it looks from htt_tx_desc_frag() that tx_desc->htt_frag_desc + * is already de-referrable (=> in virtual address space) + */ + frag_ptr_i_p = tx_desc->htt_frag_desc; + + /* Dump 6 words of TSO flags */ + print_hex_dump(KERN_DEBUG, "MLE Desc:TSO Flags: ", + DUMP_PREFIX_NONE, 8, 4, + frag_ptr_i_p, 24, true); + + frag_ptr_i_p += 6; /* Skip 6 words of TSO flags */ + + i = 0; + while (*frag_ptr_i_p) { + print_hex_dump(KERN_DEBUG, "MLE Desc:Frag Ptr: ", + DUMP_PREFIX_NONE, 8, 4, + frag_ptr_i_p, 8, true); + i++; + if (i > 5) /* max 6 times: frag_ptr0 to frag_ptr5 */ + break; + /* jump to next pointer - skip length */ + frag_ptr_i_p += 2; + } +} +#endif /* HELIUMPLUS */ + +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + struct ol_tx_desc_t *tx_desc; + + /* For LL tx_comp_req is not used so initialized to 0 */ + tx_msdu_info->htt.action.tx_comp_req = 0; + tx_desc = ol_tx_desc_ll(pdev, vdev, tx_mgmt_frm, tx_msdu_info); + /* FIX THIS - + * The FW currently has trouble using the host's fragments table + * for management frames. Until this is fixed, rather than + * specifying the fragment table to the FW, specify just the + * address of the initial fragment. + */ +#if defined(HELIUMPLUS) + /* ol_txrx_dump_frag_desc("ol_txrx_mgmt_send(): after ol_tx_desc_ll", + * tx_desc); + */ +#endif /* defined(HELIUMPLUS) */ + if (tx_desc) { + /* + * Following the call to ol_tx_desc_ll, frag 0 is the + * HTT tx HW descriptor, and the frame payload is in + * frag 1. + */ + htt_tx_desc_frags_table_set( + pdev->htt_pdev, + tx_desc->htt_tx_desc, + qdf_nbuf_get_frag_paddr(tx_mgmt_frm, 1), + 0, 0); +#if defined(HELIUMPLUS) && defined(HELIUMPLUS_DEBUG) + ol_txrx_dump_frag_desc( + "after htt_tx_desc_frags_table_set", + tx_desc); +#endif /* defined(HELIUMPLUS) */ + } + + return tx_desc; +} + +int ol_txrx_mgmt_send_frame( + struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + htt_tx_desc_set_chanfreq(tx_desc->htt_tx_desc, chanfreq); + QDF_NBUF_CB_TX_PACKET_TRACK(tx_desc->netbuf) = + QDF_NBUF_TX_PKT_MGMT_TRACK; + ol_tx_send_nonstd(pdev, tx_desc, tx_mgmt_frm, + htt_pkt_type_mgmt); + + return 0; +} + +#if defined(FEATURE_TSO) +void ol_free_remaining_tso_segs(ol_txrx_vdev_handle vdev, + struct ol_txrx_msdu_info_t *msdu_info, + bool is_tso_seg_mapping_done) +{ + struct qdf_tso_seg_elem_t *next_seg; + struct qdf_tso_seg_elem_t *free_seg = msdu_info->tso_info.curr_seg; + struct ol_txrx_pdev_t *pdev; + bool is_last_seg = false; + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is null"); + return; + } + + pdev = vdev->pdev; + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is null"); + return; + } + + /* + * TSO segment are mapped already, therefore, + * 1. unmap the tso segments, + * 2. free tso num segment if it is a last segment, and + * 3. free the tso segments. + */ + + if (is_tso_seg_mapping_done) { + struct qdf_tso_num_seg_elem_t *tso_num_desc = + msdu_info->tso_info.tso_num_seg_list; + + if (qdf_unlikely(!tso_num_desc)) { + ol_txrx_err("TSO common info is NULL!"); + return; + } + + while (free_seg) { + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + tso_num_desc->num_seg.tso_cmn_num_seg--; + + is_last_seg = (tso_num_desc->num_seg.tso_cmn_num_seg == + 0) ? true : false; + qdf_nbuf_unmap_tso_segment(pdev->osdev, free_seg, + is_last_seg); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + if (is_last_seg) { + ol_tso_num_seg_free(pdev, + msdu_info->tso_info. + tso_num_seg_list); + msdu_info->tso_info.tso_num_seg_list = NULL; + } + + next_seg = free_seg->next; + free_seg->force_free = 1; + ol_tso_free_segment(pdev, free_seg); + free_seg = next_seg; + } + } else { + /* + * TSO segment are not mapped therefore, + * free the tso segments only. + */ + while (free_seg) { + next_seg = free_seg->next; + free_seg->force_free = 1; + ol_tso_free_segment(pdev, free_seg); + free_seg = next_seg; + } + } +} + +/** + * ol_tx_prepare_tso() - Given a jumbo msdu, prepare the TSO + * related information in the msdu_info meta data + * @vdev: virtual device handle + * @msdu: network buffer + * @msdu_info: meta data associated with the msdu + * + * Return: 0 - success, >0 - error + */ +uint8_t ol_tx_prepare_tso(ol_txrx_vdev_handle vdev, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info) +{ + msdu_info->tso_info.curr_seg = NULL; + if (qdf_nbuf_is_tso(msdu)) { + int num_seg = qdf_nbuf_get_tso_num_seg(msdu); + struct qdf_tso_num_seg_elem_t *tso_num_seg; + + msdu_info->tso_info.tso_num_seg_list = NULL; + msdu_info->tso_info.tso_seg_list = NULL; + msdu_info->tso_info.num_segs = num_seg; + while (num_seg) { + struct qdf_tso_seg_elem_t *tso_seg = + ol_tso_alloc_segment(vdev->pdev); + if (tso_seg) { + qdf_tso_seg_dbg_record(tso_seg, + TSOSEG_LOC_PREPARETSO); + tso_seg->next = + msdu_info->tso_info.tso_seg_list; + msdu_info->tso_info.tso_seg_list + = tso_seg; + num_seg--; + } else { + /* Free above allocated TSO segments till now */ + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + ol_free_remaining_tso_segs(vdev, msdu_info, + false); + return 1; + } + } + tso_num_seg = ol_tso_num_seg_alloc(vdev->pdev); + if (tso_num_seg) { + tso_num_seg->next = msdu_info->tso_info. + tso_num_seg_list; + msdu_info->tso_info.tso_num_seg_list = tso_num_seg; + } else { + /* Free the already allocated num of segments */ + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + ol_free_remaining_tso_segs(vdev, msdu_info, false); + return 1; + } + + if (qdf_unlikely(!qdf_nbuf_get_tso_info(vdev->pdev->osdev, + msdu, &msdu_info->tso_info))) { + /* Free the already allocated num of segments */ + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + ol_free_remaining_tso_segs(vdev, msdu_info, false); + return 1; + } + + msdu_info->tso_info.curr_seg = + msdu_info->tso_info.tso_seg_list; + num_seg = msdu_info->tso_info.num_segs; + } else { + msdu_info->tso_info.is_tso = 0; + msdu_info->tso_info.num_segs = 1; + } + return 0; +} + +/** + * ol_tx_tso_update_stats() - update TSO stats + * @pdev: pointer to ol_txrx_pdev_t structure + * @msdu_info: tso msdu_info for the msdu + * @msdu: tso mdsu for which stats are updated + * @tso_msdu_idx: stats index in the global TSO stats array where stats will be + * updated + * + * Return: None + */ +void ol_tx_tso_update_stats(struct ol_txrx_pdev_t *pdev, + struct qdf_tso_info_t *tso_info, qdf_nbuf_t msdu, + uint32_t tso_msdu_idx) +{ + TXRX_STATS_TSO_HISTOGRAM(pdev, tso_info->num_segs); + TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, tso_msdu_idx, + qdf_nbuf_tcp_tso_size(msdu)); + TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, + tso_msdu_idx, qdf_nbuf_len(msdu)); + TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, tso_msdu_idx, + qdf_nbuf_get_nr_frags(msdu)); +} + +/** + * ol_tx_tso_get_stats_idx() - retrieve global TSO stats index and increment it + * @pdev: pointer to ol_txrx_pdev_t structure + * + * Retrieve the current value of the global variable and increment it. This is + * done in a spinlock as the global TSO stats may be accessed in parallel by + * multiple TX streams. + * + * Return: The current value of TSO stats index. + */ +uint32_t ol_tx_tso_get_stats_idx(struct ol_txrx_pdev_t *pdev) +{ + uint32_t msdu_stats_idx = 0; + + qdf_spin_lock_bh(&pdev->stats.pub.tx.tso.tso_stats_lock); + msdu_stats_idx = pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx; + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx++; + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx &= + NUM_MAX_TSO_MSDUS_MASK; + qdf_spin_unlock_bh(&pdev->stats.pub.tx.tso.tso_stats_lock); + + TXRX_STATS_TSO_RESET_MSDU(pdev, msdu_stats_idx); + + return msdu_stats_idx; +} + +/** + * ol_tso_seg_list_init() - function to initialise the tso seg freelist + * @pdev: the data physical device sending the data + * @num_seg: number of segments needs to be initialized + * + * Return: none + */ +void ol_tso_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) +{ + int i = 0; + struct qdf_tso_seg_elem_t *c_element; + + /* Host should not allocate any c_element. */ + if (num_seg <= 0) { + ol_txrx_err("Pool size passed is 0"); + QDF_BUG(0); + pdev->tso_seg_pool.pool_size = i; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); + return; + } + + c_element = qdf_mem_malloc(sizeof(struct qdf_tso_seg_elem_t)); + pdev->tso_seg_pool.freelist = c_element; + for (i = 0; i < (num_seg - 1); i++) { + if (qdf_unlikely(!c_element)) { + ol_txrx_err("c_element NULL for seg %d", i); + QDF_BUG(0); + pdev->tso_seg_pool.pool_size = i; + pdev->tso_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); + return; + } + /* set the freelist bit and magic cookie*/ + c_element->on_freelist = 1; + c_element->cookie = TSO_SEG_MAGIC_COOKIE; +#ifdef TSOSEG_DEBUG + c_element->dbg.txdesc = NULL; + qdf_atomic_init(&c_element->dbg.cur); /* history empty */ + qdf_tso_seg_dbg_record(c_element, TSOSEG_LOC_INIT1); +#endif /* TSOSEG_DEBUG */ + c_element->next = + qdf_mem_malloc(sizeof(struct qdf_tso_seg_elem_t)); + c_element = c_element->next; + } + /* + * NULL check for the last c_element of the list or + * first c_element if num_seg is equal to 1. + */ + if (qdf_unlikely(!c_element)) { + ol_txrx_err("c_element NULL for seg %d", i); + QDF_BUG(0); + pdev->tso_seg_pool.pool_size = i; + pdev->tso_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); + return; + } + c_element->on_freelist = 1; + c_element->cookie = TSO_SEG_MAGIC_COOKIE; +#ifdef TSOSEG_DEBUG + qdf_tso_seg_dbg_init(c_element); + qdf_tso_seg_dbg_record(c_element, TSOSEG_LOC_INIT2); +#endif /* TSOSEG_DEBUG */ + c_element->next = NULL; + pdev->tso_seg_pool.pool_size = num_seg; + pdev->tso_seg_pool.num_free = num_seg; + qdf_spinlock_create(&pdev->tso_seg_pool.tso_mutex); +} + +/** + * ol_tso_seg_list_deinit() - function to de-initialise the tso seg freelist + * @pdev: the data physical device sending the data + * + * Return: none + */ +void ol_tso_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ + int i; + struct qdf_tso_seg_elem_t *c_element; + struct qdf_tso_seg_elem_t *temp; + + /* pool size 0 implies that tso seg list is not initialised*/ + if (!pdev->tso_seg_pool.freelist && + pdev->tso_seg_pool.pool_size == 0) + return; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + c_element = pdev->tso_seg_pool.freelist; + i = pdev->tso_seg_pool.pool_size; + + pdev->tso_seg_pool.freelist = NULL; + pdev->tso_seg_pool.num_free = 0; + pdev->tso_seg_pool.pool_size = 0; + + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + qdf_spinlock_destroy(&pdev->tso_seg_pool.tso_mutex); + + while (i-- > 0 && c_element) { + temp = c_element->next; + if (c_element->on_freelist != 1) { + qdf_tso_seg_dbg_bug("seg already freed (double?)"); + return; + } else if (c_element->cookie != TSO_SEG_MAGIC_COOKIE) { + qdf_tso_seg_dbg_bug("seg cookie is bad (corruption?)"); + return; + } + /* free this seg, so reset the cookie value*/ + c_element->cookie = 0; + qdf_mem_free(c_element); + c_element = temp; + } +} + +/** + * ol_tso_num_seg_list_init() - function to initialise the freelist of elements + * use to count the num of tso segments in jumbo + * skb packet freelist + * @pdev: the data physical device sending the data + * @num_seg: number of elements needs to be initialized + * + * Return: none + */ +void ol_tso_num_seg_list_init(struct ol_txrx_pdev_t *pdev, uint32_t num_seg) +{ + int i = 0; + struct qdf_tso_num_seg_elem_t *c_element; + + /* Host should not allocate any c_element. */ + if (num_seg <= 0) { + ol_txrx_err("Pool size passed is 0"); + QDF_BUG(0); + pdev->tso_num_seg_pool.num_seg_pool_size = i; + qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + return; + } + + c_element = qdf_mem_malloc(sizeof(struct qdf_tso_num_seg_elem_t)); + pdev->tso_num_seg_pool.freelist = c_element; + for (i = 0; i < (num_seg - 1); i++) { + if (qdf_unlikely(!c_element)) { + ol_txrx_err("c_element NULL for num of seg %d", i); + QDF_BUG(0); + pdev->tso_num_seg_pool.num_seg_pool_size = i; + pdev->tso_num_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_num_seg_pool. + tso_num_seg_mutex); + return; + } + c_element->next = + qdf_mem_malloc(sizeof(struct qdf_tso_num_seg_elem_t)); + c_element = c_element->next; + } + /* + * NULL check for the last c_element of the list or + * first c_element if num_seg is equal to 1. + */ + if (qdf_unlikely(!c_element)) { + ol_txrx_err("c_element NULL for num of seg %d", i); + QDF_BUG(0); + pdev->tso_num_seg_pool.num_seg_pool_size = i; + pdev->tso_num_seg_pool.num_free = i; + qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + return; + } + c_element->next = NULL; + pdev->tso_num_seg_pool.num_seg_pool_size = num_seg; + pdev->tso_num_seg_pool.num_free = num_seg; + qdf_spinlock_create(&pdev->tso_num_seg_pool.tso_num_seg_mutex); +} + +/** + * ol_tso_num_seg_list_deinit() - function to de-initialise the freelist of + * elements use to count the num of tso segment + * in a jumbo skb packet freelist + * @pdev: the data physical device sending the data + * + * Return: none + */ +void ol_tso_num_seg_list_deinit(struct ol_txrx_pdev_t *pdev) +{ + int i; + struct qdf_tso_num_seg_elem_t *c_element; + struct qdf_tso_num_seg_elem_t *temp; + + /* pool size 0 implies that tso num seg list is not initialised*/ + if (!pdev->tso_num_seg_pool.freelist && + pdev->tso_num_seg_pool.num_seg_pool_size == 0) + return; + + qdf_spin_lock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + c_element = pdev->tso_num_seg_pool.freelist; + i = pdev->tso_num_seg_pool.num_seg_pool_size; + + pdev->tso_num_seg_pool.freelist = NULL; + pdev->tso_num_seg_pool.num_free = 0; + pdev->tso_num_seg_pool.num_seg_pool_size = 0; + + qdf_spin_unlock_bh(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + qdf_spinlock_destroy(&pdev->tso_num_seg_pool.tso_num_seg_mutex); + + while (i-- > 0 && c_element) { + temp = c_element->next; + qdf_mem_free(c_element); + c_element = temp; + } +} +#endif /* FEATURE_TSO */ + +#if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) +void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev) +{ + qdf_spinlock_create(&pdev->stats.pub.tx.tso.tso_stats_lock); +} + +void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev) +{ + qdf_spinlock_destroy(&pdev->stats.pub.tx.tso.tso_stats_lock); +} + +void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + int msdu_idx; + int seg_idx; + + txrx_nofl_info("TSO Statistics:"); + txrx_nofl_info("TSO pkts %lld, bytes %lld", + pdev->stats.pub.tx.tso.tso_pkts.pkts, + pdev->stats.pub.tx.tso.tso_pkts.bytes); + + txrx_nofl_info("TSO Histogram for numbers of segments:\n" + "Single segment %d\n" + " 2-5 segments %d\n" + " 6-10 segments %d\n" + "11-15 segments %d\n" + "16-20 segments %d\n" + " 20+ segments %d\n", + pdev->stats.pub.tx.tso.tso_hist.pkts_1, + pdev->stats.pub.tx.tso.tso_hist.pkts_2_5, + pdev->stats.pub.tx.tso.tso_hist.pkts_6_10, + pdev->stats.pub.tx.tso.tso_hist.pkts_11_15, + pdev->stats.pub.tx.tso.tso_hist.pkts_16_20, + pdev->stats.pub.tx.tso.tso_hist.pkts_20_plus); + + txrx_nofl_info("TSO History Buffer: Total size %d, current_index %d", + NUM_MAX_TSO_MSDUS, + TXRX_STATS_TSO_MSDU_IDX(pdev)); + + for (msdu_idx = 0; msdu_idx < NUM_MAX_TSO_MSDUS; msdu_idx++) { + if (TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, msdu_idx) == 0) + continue; + txrx_nofl_info("jumbo pkt idx: %d num segs %d gso_len %d total_len %d nr_frags %d", + msdu_idx, + TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, msdu_idx), + TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, msdu_idx)); + + for (seg_idx = 0; + ((seg_idx < TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, + msdu_idx)) && (seg_idx < NUM_MAX_TSO_SEGS)); + seg_idx++) { + struct qdf_tso_seg_t tso_seg = + TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx); + + txrx_nofl_info("seg idx: %d", seg_idx); + txrx_nofl_info("tso_enable: %d", + tso_seg.tso_flags.tso_enable); + txrx_nofl_info("fin %d syn %d rst %d psh %d ack %d urg %d ece %d cwr %d ns %d", + tso_seg.tso_flags.fin, + tso_seg.tso_flags.syn, + tso_seg.tso_flags.rst, + tso_seg.tso_flags.psh, + tso_seg.tso_flags.ack, + tso_seg.tso_flags.urg, + tso_seg.tso_flags.ece, + tso_seg.tso_flags.cwr, + tso_seg.tso_flags.ns); + txrx_nofl_info("tcp_seq_num: 0x%x ip_id: %d", + tso_seg.tso_flags.tcp_seq_num, + tso_seg.tso_flags.ip_id); + } + } +} + +void ol_txrx_tso_stats_clear(ol_txrx_pdev_handle pdev) +{ + qdf_mem_zero(&pdev->stats.pub.tx.tso.tso_pkts, + sizeof(struct ol_txrx_stats_elem)); +#if defined(FEATURE_TSO) + qdf_mem_zero(&pdev->stats.pub.tx.tso.tso_info, + sizeof(struct ol_txrx_stats_tso_info)); + qdf_mem_zero(&pdev->stats.pub.tx.tso.tso_hist, + sizeof(struct ol_txrx_tso_histogram)); +#endif +} +#endif /* defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll_fastpath.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll_fastpath.c new file mode 100644 index 0000000000..b51932968c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll_fastpath.c @@ -0,0 +1,588 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_classify, ol_tx_classify_mgmt */ +#include /* ol_tx_enqueue */ +#include /* ol_tx_sched */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include + +#include /* HIF_DEVICE */ +#include /* Layering violation, but required for fast path */ +#include +#include /* htc_endpoint */ +#include +#include + +#if defined(HIF_PCI) || defined(HIF_SNOC) || defined(HIF_AHB) || \ + defined(HIF_IPCI) +#include +#endif + +/** + * ol_tx_setup_fastpath_ce_handles() Update ce_handle for fastpath use. + * + * @osc: pointer to HIF context + * @pdev: pointer to ol pdev + * + * Return: void + */ +void ol_tx_setup_fastpath_ce_handles(struct hif_opaque_softc *osc, + struct ol_txrx_pdev_t *pdev) +{ + /* + * Before the HTT attach, set up the CE handles + * CE handles are (struct CE_state *) + * This is only required in the fast path + */ + pdev->ce_tx_hdl = hif_get_ce_handle(osc, CE_HTT_H2T_MSG); +} + +qdf_nbuf_t +ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + struct hif_opaque_softc *hif_device = + (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF); + + if (qdf_likely(hif_device && + hif_is_fastpath_mode_enabled(hif_device))) { + msdu_list = ol_tx_ll_fast(vdev, msdu_list); + } else { + qdf_print("Fast path is disabled"); + QDF_BUG(0); + } + return msdu_list; +} + +/** + * ol_tx_tso_adjust_pkt_dnld_len() Update download len for TSO pkt + * + * @msdu: tso mdsu for which download length is updated + * @msdu_info: tso msdu_info for the msdu + * @download_len: packet download length + * + * Return: Updated download length + */ +#if defined(FEATURE_TSO) +static uint32_t +ol_tx_tso_adjust_pkt_dnld_len(qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info, + uint32_t download_len) +{ + uint32_t frag0_len = 0, delta = 0, eit_hdr_len = 0; + uint32_t loc_download_len = download_len; + + frag0_len = qdf_nbuf_get_frag_len(msdu, 0); + loc_download_len -= frag0_len; + eit_hdr_len = msdu_info->tso_info.curr_seg->seg.tso_frags[0].length; + + if (eit_hdr_len < loc_download_len) { + delta = loc_download_len - eit_hdr_len; + download_len -= delta; + } + + return download_len; +} +#else +static uint32_t +ol_tx_tso_adjust_pkt_dnld_len(qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *msdu_info, + uint32_t download_len) +{ + return download_len; +} +#endif + +/** + * ol_tx_prepare_ll_fast() Alloc and prepare Tx descriptor + * + * Allocate and prepare Tx descriptor with msdu and fragment descritor + * information. + * + * @pdev: pointer to ol pdev handle + * @vdev: pointer to ol vdev handle + * @msdu: linked list of msdu packets + * @pkt_download_len: packet download length + * @ep_id: endpoint ID + * @msdu_info: Handle to msdu_info + * + * Return: Pointer to Tx descriptor + */ +static inline struct ol_tx_desc_t * +ol_tx_prepare_ll_fast(struct ol_txrx_pdev_t *pdev, + ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu, + uint32_t *pkt_download_len, uint32_t ep_id, + struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_tx_desc_t *tx_desc = NULL; + uint32_t *htt_tx_desc; + void *htc_hdr_vaddr; + u_int32_t num_frags, i; + enum extension_header_type type; + + tx_desc = ol_tx_desc_alloc_wrapper(pdev, vdev, msdu_info); + if (qdf_unlikely(!tx_desc)) + return NULL; + + tx_desc->netbuf = msdu; + if (msdu_info->tso_info.is_tso) { + tx_desc->tso_desc = msdu_info->tso_info.curr_seg; + qdf_tso_seg_dbg_setowner(tx_desc->tso_desc, tx_desc); + qdf_tso_seg_dbg_record(tx_desc->tso_desc, + TSOSEG_LOC_TXPREPLLFAST); + tx_desc->tso_num_desc = msdu_info->tso_info.tso_num_seg_list; + tx_desc->pkt_type = OL_TX_FRM_TSO; + TXRX_STATS_MSDU_INCR(pdev, tx.tso.tso_pkts, msdu); + } else { + tx_desc->pkt_type = OL_TX_FRM_STD; + } + + htt_tx_desc = tx_desc->htt_tx_desc; + +#if defined(HELIUMPLUS) + qdf_mem_zero(tx_desc->htt_frag_desc, sizeof(struct msdu_ext_desc_t)); +#endif + + /* Make sure frags num is set to 0 */ + /* + * Do this here rather than in hardstart, so + * that we can hopefully take only one cache-miss while + * accessing skb->cb. + */ + + /* HTT Header */ + /* TODO : Take care of multiple fragments */ + + type = ol_tx_get_ext_header_type(vdev, msdu); + + /* TODO: Precompute and store paddr in ol_tx_desc_t */ + /* Virtual address of the HTT/HTC header, added by driver */ + htc_hdr_vaddr = (char *)htt_tx_desc - HTC_HEADER_LEN; + if (qdf_unlikely(htt_tx_desc_init(pdev->htt_pdev, htt_tx_desc, + tx_desc->htt_tx_desc_paddr, + tx_desc->id, msdu, + &msdu_info->htt, + &msdu_info->tso_info, + NULL, type))) { + /* + * HTT Tx descriptor initialization failed. + * therefore, free the tx desc + */ + ol_tx_desc_free(pdev, tx_desc); + return NULL; + } + + num_frags = qdf_nbuf_get_num_frags(msdu); + /* num_frags are expected to be 2 max */ + num_frags = (num_frags > QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS) + ? QDF_NBUF_CB_TX_MAX_EXTRA_FRAGS + : num_frags; +#if defined(HELIUMPLUS) + /* + * Use num_frags - 1, since 1 frag is used to store + * the HTT/HTC descriptor + * Refer to htt_tx_desc_init() + */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_frag_desc, + num_frags - 1); +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_num_frags(pdev->htt_pdev, tx_desc->htt_tx_desc, + num_frags - 1); +#endif /* defined(HELIUMPLUS) */ + if (msdu_info->tso_info.is_tso) { + htt_tx_desc_fill_tso_info(pdev->htt_pdev, + tx_desc->htt_frag_desc, + &msdu_info->tso_info); + TXRX_STATS_TSO_SEG_UPDATE(pdev, + msdu_info->tso_info.msdu_stats_idx, + msdu_info->tso_info.curr_seg->seg); + } else { + for (i = 1; i < num_frags; i++) { + qdf_size_t frag_len; + qdf_dma_addr_t frag_paddr; + + frag_len = qdf_nbuf_get_frag_len(msdu, i); + frag_paddr = qdf_nbuf_get_frag_paddr(msdu, i); + if (type != EXT_HEADER_NOT_PRESENT) { + frag_paddr += + sizeof(struct htt_tx_msdu_desc_ext_t); + frag_len -= + sizeof(struct htt_tx_msdu_desc_ext_t); + } +#if defined(HELIUMPLUS) + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_frag_desc, + i - 1, frag_paddr, frag_len); +#if defined(HELIUMPLUS_DEBUG) + qdf_debug("htt_fdesc=%pK frag=%d frag_paddr=0x%0llx len=%zu", + tx_desc->htt_frag_desc, + i - 1, frag_paddr, frag_len); + ol_txrx_dump_pkt(netbuf, frag_paddr, 64); +#endif /* HELIUMPLUS_DEBUG */ +#else /* ! defined(HELIUMPLUS) */ + htt_tx_desc_frag(pdev->htt_pdev, tx_desc->htt_tx_desc, + i - 1, frag_paddr, frag_len); +#endif /* defined(HELIUMPLUS) */ + } + } + + /* + * Do we want to turn on word_stream bit-map here ? For linux, non-TSO + * this is not required. We still have to mark the swap bit correctly, + * when posting to the ring + */ + /* Check to make sure, data download length is correct */ + + /* + * TODO : Can we remove this check and always download a fixed length ? + */ + + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_EXT_HEADER(msdu)) + *pkt_download_len += sizeof(struct htt_tx_msdu_desc_ext_t); + + if (qdf_unlikely(qdf_nbuf_len(msdu) < *pkt_download_len)) + *pkt_download_len = qdf_nbuf_len(msdu); + + if (msdu_info->tso_info.curr_seg) + *pkt_download_len = ol_tx_tso_adjust_pkt_dnld_len( + msdu, msdu_info, + *pkt_download_len); + + /* Fill the HTC header information */ + /* + * Passing 0 as the seq_no field, we can probably get away + * with it for the time being, since this is not checked in f/w + */ + /* TODO : Prefill this, look at multi-fragment case */ + if (ol_txrx_get_new_htt_msg_format(pdev)) + HTC_TX_DESC_FILL(htc_hdr_vaddr, + *pkt_download_len - HTC_HEADER_LEN, ep_id, 0); + else + HTC_TX_DESC_FILL(htc_hdr_vaddr, *pkt_download_len, ep_id, 0); + + return tx_desc; +} + +#if defined(FEATURE_TSO) +/** + * ol_tx_ll_fast() Update metadata information and send msdu to HIF/CE + * + * @vdev: handle to ol_txrx_vdev_t + * @msdu_list: msdu list to be sent out. + * + * Return: on success return NULL, pointer to nbuf when it fails to send. + */ +qdf_nbuf_t +ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint32_t pkt_download_len; + uint32_t ep_id = HTT_EPID_GET(pdev->htt_pdev); + struct ol_txrx_msdu_info_t msdu_info; + uint32_t tso_msdu_stats_idx = 0; + + qdf_mem_zero(&msdu_info, sizeof(msdu_info)); + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + int segments = 1; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + if (qdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) { + ol_txrx_err("ol_tx_prepare_tso failed"); + TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, + tx.dropped.host_reject, + msdu); + return msdu; + } + + segments = msdu_info.tso_info.num_segs; + + if (msdu_info.tso_info.is_tso) { + tso_msdu_stats_idx = + ol_tx_tso_get_stats_idx(vdev->pdev); + msdu_info.tso_info.msdu_stats_idx = tso_msdu_stats_idx; + ol_tx_tso_update_stats(vdev->pdev, + &(msdu_info.tso_info), + msdu, tso_msdu_stats_idx); + } + + /* + * The netbuf may get linked into a different list + * inside the ce_send_fast function, so store the next + * pointer before the ce_send call. + */ + next = qdf_nbuf_next(msdu); + + /* init the current segment to the 1st segment in the list */ + while (segments) { + if (msdu_info.tso_info.curr_seg) + QDF_NBUF_CB_PADDR(msdu) = msdu_info.tso_info. + curr_seg->seg.tso_frags[0].paddr; + + segments--; + + msdu_info.htt.info.frame_type = pdev->htt_pkt_type; + msdu_info.htt.info.vdev_id = vdev->vdev_id; + msdu_info.htt.action.cksum_offload = + qdf_nbuf_get_tx_cksum(msdu); + switch (qdf_nbuf_get_exemption_type(msdu)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 0; + break; + default: + msdu_info.htt.action.do_encrypt = 1; + qdf_assert(0); + break; + } + + pkt_download_len = ((struct htt_pdev_t *) + (pdev->htt_pdev))->download_len; + tx_desc = ol_tx_prepare_ll_fast(pdev, vdev, msdu, + &pkt_download_len, + ep_id, &msdu_info); + + TXRX_STATS_MSDU_INCR(pdev, tx.from_stack, msdu); + + if (qdf_likely(tx_desc)) { + struct qdf_tso_seg_elem_t *next_seg; + + ol_tx_trace_pkt(msdu, tx_desc->id, + vdev->vdev_id, + vdev->qdf_opmode); + /* + * If debug display is enabled, show the meta + * data being downloaded to the target via the + * HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + /* mark the relevant tso_seg free-able */ + if (msdu_info.tso_info.curr_seg) { + msdu_info.tso_info.curr_seg-> + sent_to_target = 1; + next_seg = msdu_info.tso_info. + curr_seg->next; + /* + * If this is a jumbo nbuf, then increment the + * number of nbuf users for each additional + * segment of the msdu. This will ensure that + * the skb is freed only after receiving tx + * completion for all segments of an nbuf + */ + if (next_seg) + qdf_nbuf_inc_users(msdu); + } else { + next_seg = NULL; + } + + if ((ce_send_fast(pdev->ce_tx_hdl, msdu, + ep_id, + pkt_download_len) == 0)) { + struct qdf_tso_info_t *tso_info = + &msdu_info.tso_info; + /* + * If TSO packet, free associated + * remaining TSO segment descriptors + */ + if (tx_desc->pkt_type == + OL_TX_FRM_TSO) { + tso_info->curr_seg = next_seg; + ol_free_remaining_tso_segs(vdev, + &msdu_info, true); + /* + * Revert the nbuf users + * increment done for the + * current segment + */ + if (next_seg) + qdf_nbuf_tx_free( + msdu, + QDF_NBUF_PKT_ERROR); + } + + /* + * The packet could not be sent. + * Free the descriptor, return the + * packet to the caller. + */ + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, + htt_tx_status_download_fail); + return msdu; + } + if (msdu_info.tso_info.curr_seg) + msdu_info.tso_info.curr_seg = next_seg; + + if (msdu_info.tso_info.is_tso) { + TXRX_STATS_TSO_INC_SEG(vdev->pdev, + tso_msdu_stats_idx); + TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev, + tso_msdu_stats_idx); + } + } else { + /* + * If TSO packet, free associated + * remaining TSO segment descriptors + */ + if (qdf_nbuf_is_tso(msdu)) + ol_free_remaining_tso_segs(vdev, + &msdu_info, true); + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + /* the list of unaccepted MSDUs */ + return msdu; + } + } /* while segments */ + + msdu = next; + } /* while msdus */ + return NULL; /* all MSDUs were accepted */ +} +#else +qdf_nbuf_t +ol_tx_ll_fast(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint32_t pkt_download_len; + uint32_t ep_id = HTT_EPID_GET(pdev->htt_pdev); + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + msdu_info.htt.info.frame_type = pdev->htt_pkt_type; + msdu_info.htt.info.vdev_id = vdev->vdev_id; + msdu_info.htt.action.cksum_offload = + qdf_nbuf_get_tx_cksum(msdu); + switch (qdf_nbuf_get_exemption_type(msdu)) { + case QDF_NBUF_EXEMPT_NO_EXEMPTION: + case QDF_NBUF_EXEMPT_ON_KEY_MAPPING_KEY_UNAVAILABLE: + /* We want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 1; + break; + case QDF_NBUF_EXEMPT_ALWAYS: + /* We don't want to encrypt this frame */ + msdu_info.htt.action.do_encrypt = 0; + break; + default: + msdu_info.htt.action.do_encrypt = 1; + qdf_assert(0); + break; + } + + pkt_download_len = ((struct htt_pdev_t *) + (pdev->htt_pdev))->download_len; + tx_desc = ol_tx_prepare_ll_fast(pdev, vdev, msdu, + &pkt_download_len, ep_id, + &msdu_info); + + TXRX_STATS_MSDU_INCR(pdev, tx.from_stack, msdu); + + if (qdf_likely(tx_desc)) { + DPTRACE(qdf_dp_trace_ptr(msdu, + QDF_DP_TRACE_TXRX_FAST_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), tx_desc->id, + vdev->vdev_id, 0, vdev->qdf_opmode)); + + ol_tx_trace_pkt(msdu, tx_desc->id, vdev->vdev_id, + vdev->qdf_opmode); + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + /* + * The netbuf may get linked into a different list + * inside the ce_send_fast function, so store the next + * pointer before the ce_send call. + */ + next = qdf_nbuf_next(msdu); + if ((ce_send_fast(pdev->ce_tx_hdl, msdu, + ep_id, pkt_download_len) == 0)) { + /* + * The packet could not be sent + * Free the descriptor, return the packet to the + * caller + */ + ol_tx_desc_free(pdev, tx_desc); + return msdu; + } + msdu = next; + } else { + TXRX_STATS_MSDU_LIST_INCR( + pdev, tx.dropped.host_reject, msdu); + return msdu; /* the list of unaccepted MSDUs */ + } + } + + return NULL; /* all MSDUs were accepted */ +} +#endif /* FEATURE_TSO */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll_legacy.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll_legacy.c new file mode 100644 index 0000000000..9eec766e11 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_ll_legacy.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2011-2018,The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_classify, ol_tx_classify_mgmt */ +#include /* ol_tx_enqueue */ +#include /* ol_tx_sched */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include + +/** + * ol_tx_ll_wrapper() wrapper to ol_tx_ll + * + */ +qdf_nbuf_t +ol_tx_ll_wrapper(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + return ol_tx_ll(vdev, msdu_list); +} + +#if defined(FEATURE_TSO) +qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t msdu_info; + uint32_t tso_msdu_stats_idx = 0; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc = NULL; + int segments = 1; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + + if (qdf_unlikely(ol_tx_prepare_tso(vdev, msdu, &msdu_info))) { + qdf_print("ol_tx_prepare_tso failed\n"); + TXRX_STATS_MSDU_LIST_INCR(vdev->pdev, + tx.dropped.host_reject, + msdu); + return msdu; + } + + segments = msdu_info.tso_info.num_segs; + + if (msdu_info.tso_info.is_tso) { + tso_msdu_stats_idx = + ol_tx_tso_get_stats_idx(vdev->pdev); + msdu_info.tso_info.msdu_stats_idx = tso_msdu_stats_idx; + ol_tx_tso_update_stats(vdev->pdev, + &(msdu_info.tso_info), + msdu, tso_msdu_stats_idx); + } + + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = qdf_nbuf_next(msdu); + /* init the current segment to the 1st segment in the list */ + while (segments) { + if (msdu_info.tso_info.curr_seg) + QDF_NBUF_CB_PADDR(msdu) = + msdu_info.tso_info.curr_seg-> + seg.tso_frags[0].paddr; + + segments--; + + tx_desc = ol_tx_prepare_ll(vdev, msdu, &msdu_info); + if (!tx_desc) + return msdu; + + ol_tx_trace_pkt(msdu, tx_desc->id, vdev->vdev_id, + vdev->qdf_opmode); + + /* + * If this is a jumbo nbuf, then increment the number + * of nbuf users for each additional segment of the msdu + * This will ensure that the skb is freed only after + * receiving tx completion for all segments of an nbuf. + */ + if (segments) + qdf_nbuf_inc_users(msdu); + + TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu); + + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + + if (msdu_info.tso_info.curr_seg) { + msdu_info.tso_info.curr_seg = + msdu_info.tso_info.curr_seg->next; + } + + if (msdu_info.tso_info.is_tso) { + TXRX_STATS_TSO_INC_SEG(vdev->pdev, + tso_msdu_stats_idx); + TXRX_STATS_TSO_INC_SEG_IDX(vdev->pdev, + tso_msdu_stats_idx); + } + } /* while segments */ + + msdu = next; + } /* while msdus */ + return NULL; /* all MSDUs were accepted */ +} +#else /* TSO */ + +qdf_nbuf_t ol_tx_ll(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + qdf_nbuf_t msdu = msdu_list; + struct ol_txrx_msdu_info_t msdu_info; + + msdu_info.htt.info.l2_hdr_type = vdev->pdev->htt_pkt_type; + msdu_info.htt.action.tx_comp_req = 0; + msdu_info.tso_info.is_tso = 0; + /* + * The msdu_list variable could be used instead of the msdu var, + * but just to clarify which operations are done on a single MSDU + * vs. a list of MSDUs, use a distinct variable for single MSDUs + * within the list. + */ + while (msdu) { + qdf_nbuf_t next; + struct ol_tx_desc_t *tx_desc = NULL; + + msdu_info.htt.info.ext_tid = qdf_nbuf_get_tid(msdu); + msdu_info.peer = NULL; + tx_desc = ol_tx_prepare_ll(vdev, msdu, &msdu_info); + if (!tx_desc) + return msdu; + + ol_tx_trace_pkt(msdu, tx_desc->id, vdev->vdev_id, + vdev->qdf_opmode); + + TXRX_STATS_MSDU_INCR(vdev->pdev, tx.from_stack, msdu); + + /* + * If debug display is enabled, show the meta-data being + * downloaded to the target via the HTT tx descriptor. + */ + htt_tx_desc_display(tx_desc->htt_tx_desc); + /* + * The netbuf may get linked into a different list inside the + * ol_tx_send function, so store the next pointer before the + * tx_send call. + */ + next = qdf_nbuf_next(msdu); + ol_tx_send(vdev->pdev, tx_desc, msdu, vdev->vdev_id); + msdu = next; + } + return NULL; /* all MSDUs were accepted */ +} +#endif /* TSO */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_queue.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_queue.c new file mode 100644 index 0000000000..a121bf1fb4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_queue.c @@ -0,0 +1,2048 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* ol_cfg_addba_retry */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync, ol_tx_addba_conf */ +#include +#include /* ol_ctrl_addba_req */ +#include /* TXRX_ASSERT1, etc. */ +#include /* ol_tx_desc, ol_tx_desc_frame_list_free */ +#include /* ol_tx_vdev_ll_pause_queue_send */ +#include /* ol_tx_sched_notify, etc. */ +#include +#include /* ol_tx_desc_pool_size_hl */ +#include /* ENABLE_TX_QUEUE_LOG */ +#include /* bool */ +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#if defined(CONFIG_HL_SUPPORT) + +#ifndef offsetof +#define offsetof(type, field) ((qdf_size_t)(&((type *)0)->field)) +#endif + +/*--- function prototypes for optional host ADDBA negotiation ---------------*/ + +#define OL_TX_QUEUE_ADDBA_CHECK(pdev, txq, tx_msdu_info) /* no-op */ + +#ifndef container_of +#define container_of(ptr, type, member) ((type *)( \ + (char *)(ptr) - (char *)(&((type *)0)->member))) +#endif +/*--- function definitions --------------------------------------------------*/ + +/** + * ol_tx_queue_vdev_flush() - try to flush pending frames in the tx queues + * no matter it's queued in the TX scheduler or not + * @pdev: the physical device object + * @vdev: the virtual device object + * + * Return: None + */ +static void +ol_tx_queue_vdev_flush(struct ol_txrx_pdev_t *pdev, struct ol_txrx_vdev_t *vdev) +{ +#define PEER_ARRAY_COUNT 10 + struct ol_tx_frms_queue_t *txq; + struct ol_txrx_peer_t *peer, *peers[PEER_ARRAY_COUNT]; + int i, j, peer_count; + + ol_tx_hl_queue_flush_all(vdev); + + /* flush VDEV TX queues */ + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + txq = &vdev->txqs[i]; + /* + * currently txqs of MCAST_BCAST/DEFAULT_MGMT packet are using + * tid HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST/HTT_TX_EXT_TID_MGMT + * when inserted into scheduler, so use same tid when we flush + * them + */ + if (i == OL_TX_VDEV_MCAST_BCAST) + ol_tx_queue_free(pdev, + txq, + HTT_TX_EXT_TID_NON_QOS_MCAST_BCAST, + false); + else if (i == OL_TX_VDEV_DEFAULT_MGMT) + ol_tx_queue_free(pdev, + txq, + HTT_TX_EXT_TID_MGMT, + false); + else + ol_tx_queue_free(pdev, + txq, + (i + OL_TX_NUM_TIDS), + false); + } + /* flush PEER TX queues */ + do { + peer_count = 0; + /* select candidate peers */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + txq = &peer->txqs[i]; + if (txq->frms) { + ol_txrx_peer_get_ref + (peer, + PEER_DEBUG_ID_OL_TXQ_VDEV_FL); + peers[peer_count++] = peer; + break; + } + } + if (peer_count >= PEER_ARRAY_COUNT) + break; + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* flush TX queues of candidate peers */ + for (i = 0; i < peer_count; i++) { + for (j = 0; j < OL_TX_NUM_TIDS; j++) { + txq = &peers[i]->txqs[j]; + if (txq->frms) + ol_tx_queue_free(pdev, txq, j, true); + } + ol_txrx_info("Delete Peer %pK", peer); + ol_txrx_peer_release_ref(peers[i], + PEER_DEBUG_ID_OL_TXQ_VDEV_FL); + } + } while (peer_count >= PEER_ARRAY_COUNT); +} + +/** + * ol_tx_queue_flush() - try to flush pending frames in the tx queues + * no matter it's queued in the TX scheduler or not + * @pdev: the physical device object + * + * Return: None + */ +static inline void +ol_tx_queue_flush(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + ol_tx_queue_vdev_flush(pdev, vdev); + } +} + +void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs) +{ + u_int16_t num; + u_int16_t discarded, actual_discarded = 0; + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + if (flush_all == true) + /* flush all the pending tx queues in the scheduler */ + num = ol_tx_desc_pool_size_hl(pdev->ctrl_pdev) - + qdf_atomic_read(&pdev->tx_queue.rsrc_cnt); + else + /*TODO: Discard frames for a particular vdev only */ + num = pdev->tx_queue.rsrc_threshold_hi - + pdev->tx_queue.rsrc_threshold_lo; + + TX_SCHED_DEBUG_PRINT("+%u", qdf_atomic_read(&pdev->tx_queue.rsrc_cnt)); + while (num > 0) { + discarded = ol_tx_sched_discard_select( + pdev, (u_int16_t)num, tx_descs, flush_all); + if (discarded == 0) + /* + * No more packets could be discarded. + * Probably tx queues are empty. + */ + break; + + num -= discarded; + actual_discarded += discarded; + } + qdf_atomic_add(actual_discarded, &pdev->tx_queue.rsrc_cnt); + TX_SCHED_DEBUG_PRINT("-"); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + if (flush_all == true && num > 0) + /* + * try to flush pending frames in the tx queues + * which are not queued in the TX scheduler. + */ + ol_tx_queue_flush(pdev); +} + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL + +/** + * is_ol_tx_discard_frames_success() - check whether currently queued tx frames + * can be discarded or not + * @pdev: the physical device object + * @tx_desc: tx descriptor ptr + * + * Return: Success if available tx descriptors are too few + */ +static inline bool +is_ol_tx_discard_frames_success(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + ol_txrx_vdev_handle vdev; + bool discard_frames; + + vdev = tx_desc->vdev; + + qdf_spin_lock_bh(&vdev->pdev->tx_mutex); + if (vdev->tx_desc_limit == 0) { + /* Flow control not enabled */ + discard_frames = qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) <= + pdev->tx_queue.rsrc_threshold_lo; + } else { + /* + * Discard + * if netbuf is normal priority and tx_desc_count greater than + * queue stop threshold + * AND + * if netbuf is high priority and tx_desc_count greater than + * tx desc limit. + */ + discard_frames = (!ol_tx_desc_is_high_prio(tx_desc->netbuf) && + qdf_atomic_read(&vdev->tx_desc_count) > + vdev->queue_stop_th) || + (ol_tx_desc_is_high_prio(tx_desc->netbuf) && + qdf_atomic_read(&vdev->tx_desc_count) > + vdev->tx_desc_limit); + } + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + + return discard_frames; +} +#else + +static inline bool +is_ol_tx_discard_frames_success(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc) +{ + return qdf_atomic_read(&pdev->tx_queue.rsrc_cnt) <= + pdev->tx_queue.rsrc_threshold_lo; +} +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + int bytes; + struct ol_tx_sched_notify_ctx_t notify_ctx; + + TX_SCHED_DEBUG_PRINT("Enter"); + + /* + * If too few tx descriptors are available, drop some currently-queued + * tx frames, to provide enough tx descriptors for new frames, which + * may be higher priority than the current frames. + */ + if (is_ol_tx_discard_frames_success(pdev, tx_desc)) { + ol_tx_desc_list tx_descs; + + TAILQ_INIT(&tx_descs); + ol_tx_queue_discard(pdev, false, &tx_descs); + /*Discard Frames in Discard List*/ + ol_tx_desc_frame_list_free(pdev, &tx_descs, 1 /* error */); + } + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + TAILQ_INSERT_TAIL(&txq->head, tx_desc, tx_desc_list_elem); + + bytes = qdf_nbuf_len(tx_desc->netbuf); + txq->frms++; + txq->bytes += bytes; + ol_tx_update_grp_frm_count(txq, 1); + ol_tx_queue_log_enqueue(pdev, tx_msdu_info, 1, bytes); + + if (txq->flag != ol_tx_queue_paused) { + notify_ctx.event = OL_TX_ENQUEUE_FRAME; + notify_ctx.frames = 1; + notify_ctx.bytes = qdf_nbuf_len(tx_desc->netbuf); + notify_ctx.txq = txq; + notify_ctx.info.tx_msdu_info = tx_msdu_info; + ol_tx_sched_notify(pdev, ¬ify_ctx); + txq->flag = ol_tx_queue_active; + } + + if (!ETHERTYPE_IS_EAPOL_WAPI(tx_msdu_info->htt.info.ethertype)) + OL_TX_QUEUE_ADDBA_CHECK(pdev, txq, tx_msdu_info); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave"); +} + +u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t max_frames, + u_int32_t *credit, + int *bytes) +{ + u_int16_t num_frames; + int bytes_sum; + unsigned int credit_sum; + + TXRX_ASSERT2(txq->flag != ol_tx_queue_paused); + TX_SCHED_DEBUG_PRINT("Enter"); + + if (txq->frms < max_frames) + max_frames = txq->frms; + + bytes_sum = 0; + credit_sum = 0; + for (num_frames = 0; num_frames < max_frames; num_frames++) { + unsigned int frame_credit; + struct ol_tx_desc_t *tx_desc; + + tx_desc = TAILQ_FIRST(&txq->head); + + frame_credit = htt_tx_msdu_credit(tx_desc->netbuf); + if (credit_sum + frame_credit > *credit) + break; + + credit_sum += frame_credit; + bytes_sum += qdf_nbuf_len(tx_desc->netbuf); + TAILQ_REMOVE(&txq->head, tx_desc, tx_desc_list_elem); + TAILQ_INSERT_TAIL(head, tx_desc, tx_desc_list_elem); + } + txq->frms -= num_frames; + txq->bytes -= bytes_sum; + ol_tx_update_grp_frm_count(txq, -credit_sum); + + /* a paused queue remains paused, regardless of whether it has frames */ + if (txq->frms == 0 && txq->flag == ol_tx_queue_active) + txq->flag = ol_tx_queue_empty; + + ol_tx_queue_log_dequeue(pdev, txq, num_frames, bytes_sum); + TX_SCHED_DEBUG_PRINT("Leave"); + + *bytes = bytes_sum; + *credit = credit_sum; + return num_frames; +} + +void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, bool is_peer_txq) +{ + int frms = 0, bytes = 0; + struct ol_tx_desc_t *tx_desc; + struct ol_tx_sched_notify_ctx_t notify_ctx; + ol_tx_desc_list tx_tmp_list; + + TAILQ_INIT(&tx_tmp_list); + TX_SCHED_DEBUG_PRINT("Enter"); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + notify_ctx.event = OL_TX_DELETE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + frms = txq->frms; + tx_desc = TAILQ_FIRST(&txq->head); + while (txq->frms) { + bytes += qdf_nbuf_len(tx_desc->netbuf); + txq->frms--; + tx_desc = TAILQ_NEXT(tx_desc, tx_desc_list_elem); + } + ol_tx_queue_log_free(pdev, txq, tid, frms, bytes, is_peer_txq); + txq->bytes -= bytes; + ol_tx_queue_log_free(pdev, txq, tid, frms, bytes, is_peer_txq); + txq->flag = ol_tx_queue_empty; + /* txq->head gets reset during the TAILQ_CONCAT call */ + TAILQ_CONCAT(&tx_tmp_list, &txq->head, tx_desc_list_elem); + ol_tx_update_grp_frm_count(txq, -frms); + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + /* free tx frames without holding tx_queue_spinlock */ + qdf_atomic_add(frms, &pdev->tx_queue.rsrc_cnt); + while (frms) { + tx_desc = TAILQ_FIRST(&tx_tmp_list); + TAILQ_REMOVE(&tx_tmp_list, tx_desc, tx_desc_list_elem); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 0); + frms--; + } + TX_SCHED_DEBUG_PRINT("Leave"); +} + + +/*--- queue pause / unpause functions ---------------------------------------*/ + +/** + * ol_txrx_peer_tid_pause_base() - suspend/pause txq for a given tid given peer + * @pdev: the physical device object + * @peer: peer device object + * @tid: tid for which queue needs to be paused + * + * Return: None + */ +static void +ol_txrx_peer_tid_pause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + int tid) +{ + struct ol_tx_frms_queue_t *txq = &peer->txqs[tid]; + + if (txq->paused_count.total++ == 0) { + struct ol_tx_sched_notify_ctx_t notify_ctx; + + notify_ctx.event = OL_TX_PAUSE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + txq->flag = ol_tx_queue_paused; + } +} +#ifdef QCA_BAD_PEER_TX_FLOW_CL + +/** + * ol_txrx_peer_pause_but_no_mgmt_q_base() - suspend/pause all txqs except + * management queue for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_pause_but_no_mgmt_q_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + for (i = 0; i < OL_TX_MGMT_TID; i++) + ol_txrx_peer_tid_pause_base(pdev, peer, i); +} +#endif + + +/** + * ol_txrx_peer_pause_base() - suspend/pause all txqs for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_pause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_pause_base(pdev, peer, i); +} + +/** + * ol_txrx_peer_tid_unpause_base() - unpause txq for a given tid given peer + * @pdev: the physical device object + * @peer: peer device object + * @tid: tid for which queue needs to be unpaused + * + * Return: None + */ +static void +ol_txrx_peer_tid_unpause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + int tid) +{ + struct ol_tx_frms_queue_t *txq = &peer->txqs[tid]; + /* + * Don't actually unpause the tx queue until all pause requests + * have been removed. + */ + TXRX_ASSERT2(txq->paused_count.total > 0); + /* return, if not already paused */ + if (txq->paused_count.total == 0) + return; + + if (--txq->paused_count.total == 0) { + struct ol_tx_sched_notify_ctx_t notify_ctx; + + notify_ctx.event = OL_TX_UNPAUSE_QUEUE; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = tid; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + if (txq->frms == 0) { + txq->flag = ol_tx_queue_empty; + } else { + txq->flag = ol_tx_queue_active; + /* + * Now that the are new tx frames available to download, + * invoke the scheduling function, to see if it wants to + * download the new frames. + * Since the queue lock is currently held, and since + * the scheduler function takes the lock, temporarily + * release the lock. + */ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + ol_tx_sched(pdev); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + } + } +} + +/** + * ol_txrx_peer_unpause_base() - unpause all txqs for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_unpause_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); +} + +#ifdef QCA_BAD_PEER_TX_FLOW_CL +/** + * ol_txrx_peer_unpause_but_no_mgmt_q_base() - unpause all txqs except + * management queue for a given peer + * @pdev: the physical device object + * @peer: peer device object + * + * Return: None + */ +static void +ol_txrx_peer_unpause_but_no_mgmt_q_base( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + for (i = 0; i < OL_TX_MGMT_TID; i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); +} +#endif + +void +ol_txrx_peer_tid_unpause(ol_txrx_peer_handle peer, int tid) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue unpause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + if (tid == -1) { + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) + ol_txrx_peer_tid_unpause_base(pdev, peer, i); + + } else { + ol_txrx_peer_tid_unpause_base(pdev, peer, tid); + } + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void +ol_txrx_vdev_pause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_peer_t *peer; + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + pdev = vdev->pdev; + + /* use peer_ref_mutex before accessing peer_list */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + if (pause_type == PAUSE_TYPE_CHOP) { + if (!(peer->is_tdls_peer && peer->tdls_offchan_enabled)) + ol_txrx_peer_pause_base(pdev, peer); + } else if (pause_type == PAUSE_TYPE_CHOP_TDLS_OFFCHAN) { + if (peer->is_tdls_peer && peer->tdls_offchan_enabled) + ol_txrx_peer_pause_base(pdev, peer); + } else { + ol_txrx_peer_pause_base(pdev, peer); + } + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void ol_txrx_vdev_unpause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_peer_t *peer; + + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + pdev = vdev->pdev; + + /* take peer_ref_mutex before accessing peer_list */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + if (pause_type == PAUSE_TYPE_CHOP) { + if (!(peer->is_tdls_peer && peer->tdls_offchan_enabled)) + ol_txrx_peer_unpause_base(pdev, peer); + } else if (pause_type == PAUSE_TYPE_CHOP_TDLS_OFFCHAN) { + if (peer->is_tdls_peer && peer->tdls_offchan_enabled) + ol_txrx_peer_unpause_base(pdev, peer); + } else { + ol_txrx_peer_unpause_base(pdev, peer); + } + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void ol_txrx_vdev_flush(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + if (!vdev) + return; + + ol_tx_queue_vdev_flush(vdev->pdev, vdev); +} + +#ifdef QCA_BAD_PEER_TX_FLOW_CL + +/** + * ol_txrx_peer_bal_add_limit_peer() - add one peer into limit list + * @pdev: Pointer to PDEV structure. + * @peer_id: Peer Identifier. + * @peer_limit Peer limit threshold + * + * Add one peer into the limit list of pdev + * Note that the peer limit info will be also updated + * If it is the first time, start the timer + * + * Return: None + */ +void +ol_txrx_peer_bal_add_limit_peer(struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, u_int16_t peer_limit) +{ + u_int16_t i, existed = 0; + struct ol_txrx_peer_t *peer = NULL; + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].peer_id == peer_id) { + existed = 1; + break; + } + } + + if (!existed) { + u_int32_t peer_num = pdev->tx_peer_bal.peer_num; + /* Check if peer_num has reached the capabilit */ + if (peer_num >= MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "reach the maximum peer num %d", peer_num); + return; + } + pdev->tx_peer_bal.limit_list[peer_num].peer_id = peer_id; + pdev->tx_peer_bal.limit_list[peer_num].limit_flag = true; + pdev->tx_peer_bal.limit_list[peer_num].limit = peer_limit; + pdev->tx_peer_bal.peer_num++; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + peer->tx_limit_flag = true; + peer->tx_limit = peer_limit; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Add one peer into limit queue, peer_id %d, cur peer num %d", + peer_id, + pdev->tx_peer_bal.peer_num); + } + + /* Only start the timer once */ + if (pdev->tx_peer_bal.peer_bal_timer_state == + ol_tx_peer_bal_timer_inactive) { + qdf_timer_start(&pdev->tx_peer_bal.peer_bal_timer, + pdev->tx_peer_bal.peer_bal_period_ms); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_active; + } +} + +/** + * ol_txrx_peer_bal_remove_limit_peer() - remove one peer from limit list + * @pdev: Pointer to PDEV structure. + * @peer_id: Peer Identifier. + * + * Remove one peer from the limit list of pdev + * Note that Only stop the timer if no peer in limit state + * + * Return: NULL + */ +void +ol_txrx_peer_bal_remove_limit_peer(struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id) +{ + u_int16_t i; + struct ol_txrx_peer_t *peer = NULL; + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].peer_id == peer_id) { + pdev->tx_peer_bal.limit_list[i] = + pdev->tx_peer_bal.limit_list[ + pdev->tx_peer_bal.peer_num - 1]; + pdev->tx_peer_bal.peer_num--; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) + peer->tx_limit_flag = false; + + + TX_SCHED_DEBUG_PRINT( + "Remove one peer from limitq, peer_id %d, cur peer num %d", + peer_id, + pdev->tx_peer_bal.peer_num); + break; + } + } + + /* Only stop the timer if no peer in limit state */ + if (pdev->tx_peer_bal.peer_num == 0) { + qdf_timer_stop(&pdev->tx_peer_bal.peer_bal_timer); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_inactive; + } +} + +void +ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue pause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + ol_txrx_peer_pause_but_no_mgmt_q_base(pdev, peer); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void +ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ + struct ol_txrx_pdev_t *pdev = peer->vdev->pdev; + + /* TO DO: log the queue pause */ + + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + + ol_txrx_peer_unpause_but_no_mgmt_q_base(pdev, peer); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave"); +} + +u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag) +{ + if (txq && (txq->peer) && (txq->peer->tx_limit_flag) && + (txq->peer->tx_limit < max_frames)) { + TX_SCHED_DEBUG_PRINT( + "Peer ID %d goes to limit, threshold is %d", + txq->peer->peer_ids[0], txq->peer->tx_limit); + *tx_limit_flag = 1; + return txq->peer->tx_limit; + } else { + return max_frames; + } +} + +void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag) +{ + if (unlikely(!pdev)) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL pdev handler"); + return; + } + + if (unlikely(!txq)) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL txq"); + return; + } + + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + if (tx_limit_flag && (txq->peer) && + (txq->peer->tx_limit_flag)) { + if (txq->peer->tx_limit < frames) + txq->peer->tx_limit = 0; + else + txq->peer->tx_limit -= frames; + + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Peer ID %d in limit, deque %d frms", + txq->peer->peer_ids[0], frames); + } else if (txq->peer) { + TX_SCHED_DEBUG_PRINT("Download peer_id %d, num_frames %d", + txq->peer->peer_ids[0], frames); + } + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); +} + +void +ol_txrx_bad_peer_txctl_set_setting(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int enable, int period, int txq_limit) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (enable) + pdev->tx_peer_bal.enabled = ol_tx_peer_bal_enable; + else + pdev->tx_peer_bal.enabled = ol_tx_peer_bal_disable; + + /* Set the current settingl */ + pdev->tx_peer_bal.peer_bal_period_ms = period; + pdev->tx_peer_bal.peer_bal_txq_limit = txq_limit; +} + +void +ol_txrx_bad_peer_txctl_update_threshold(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, int level, + int tput_thresh, int tx_limit) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + /* Set the current settingl */ + pdev->tx_peer_bal.ctl_thresh[level].tput_thresh = + tput_thresh; + pdev->tx_peer_bal.ctl_thresh[level].tx_limit = + tx_limit; +} + +/** + * ol_tx_pdev_peer_bal_timer() - timer function + * @context: context of timer function + * + * Return: None + */ +static void +ol_tx_pdev_peer_bal_timer(void *context) +{ + int i; + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + + for (i = 0; i < pdev->tx_peer_bal.peer_num; i++) { + if (pdev->tx_peer_bal.limit_list[i].limit_flag) { + u_int16_t peer_id = + pdev->tx_peer_bal.limit_list[i].peer_id; + u_int16_t tx_limit = + pdev->tx_peer_bal.limit_list[i].limit; + + struct ol_txrx_peer_t *peer = NULL; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + TX_SCHED_DEBUG_PRINT( + "peer_id %d peer = 0x%x tx limit %d", + peer_id, + (int)peer, tx_limit); + + /* + * It is possible the peer limit is still not 0, + * but it is the scenario should not be cared + */ + if (peer) { + peer->tx_limit = tx_limit; + } else { + ol_txrx_peer_bal_remove_limit_peer(pdev, + peer_id); + TX_SCHED_DEBUG_PRINT_ALWAYS( + "No such a peer, peer id = %d", + peer_id); + } + } + } + + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); + + if (pdev->tx_peer_bal.peer_num) { + ol_tx_sched(pdev); + qdf_timer_start(&pdev->tx_peer_bal.peer_bal_timer, + pdev->tx_peer_bal.peer_bal_period_ms); + } +} + +void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer) +{ + if (txq) + txq->peer = peer; +} + +void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev) +{ + u_int32_t timer_period; + + qdf_spinlock_create(&pdev->tx_peer_bal.mutex); + pdev->tx_peer_bal.peer_num = 0; + pdev->tx_peer_bal.peer_bal_timer_state + = ol_tx_peer_bal_timer_inactive; + + timer_period = 2000; + pdev->tx_peer_bal.peer_bal_period_ms = timer_period; + + qdf_timer_init( + pdev->osdev, + &pdev->tx_peer_bal.peer_bal_timer, + ol_tx_pdev_peer_bal_timer, + pdev, QDF_TIMER_TYPE_SW); +} + +void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev) +{ + qdf_timer_stop(&pdev->tx_peer_bal.peer_bal_timer); + pdev->tx_peer_bal.peer_bal_timer_state = + ol_tx_peer_bal_timer_inactive; + qdf_timer_free(&pdev->tx_peer_bal.peer_bal_timer); + qdf_spinlock_destroy(&pdev->tx_peer_bal.mutex); +} + +void +ol_txrx_peer_link_status_handler( + ol_txrx_pdev_handle pdev, + u_int16_t peer_num, + struct rate_report_t *peer_link_status) +{ + u_int16_t i = 0; + struct ol_txrx_peer_t *peer = NULL; + + if (!pdev) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Error: NULL pdev handler"); + return; + } + + if (!peer_link_status) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Error:NULL link report message. peer num %d", + peer_num); + return; + } + + /* Check if bad peer tx flow CL is enabled */ + if (pdev->tx_peer_bal.enabled != ol_tx_peer_bal_enable) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "Bad peer tx flow CL is not enabled, ignore it"); + return; + } + + /* Check peer_num is reasonable */ + if (peer_num > MAX_NO_PEERS_IN_LIMIT) { + TX_SCHED_DEBUG_PRINT_ALWAYS("Bad peer_num %d", peer_num); + return; + } + + TX_SCHED_DEBUG_PRINT_ALWAYS("peer_num %d", peer_num); + + for (i = 0; i < peer_num; i++) { + u_int16_t peer_limit, peer_id; + u_int16_t pause_flag, unpause_flag; + u_int32_t peer_phy, peer_tput; + + peer_id = peer_link_status->id; + peer_phy = peer_link_status->phy; + peer_tput = peer_link_status->rate; + + TX_SCHED_DEBUG_PRINT("peer id %d tput %d phy %d", + peer_id, peer_tput, peer_phy); + + /* Sanity check for the PHY mode value */ + if (peer_phy > TXRX_IEEE11_AC) { + TX_SCHED_DEBUG_PRINT_ALWAYS( + "PHY value is illegal: %d, and the peer_id %d", + peer_link_status->phy, peer_id); + continue; + } + pause_flag = false; + unpause_flag = false; + peer_limit = 0; + + /* From now on, PHY, PER info should be all fine */ + qdf_spin_lock_bh(&pdev->tx_peer_bal.mutex); + + /* Update link status analysis for each peer */ + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + u_int32_t thresh, limit, phy; + + phy = peer_link_status->phy; + thresh = pdev->tx_peer_bal.ctl_thresh[phy].tput_thresh; + limit = pdev->tx_peer_bal.ctl_thresh[phy].tx_limit; + + if (((peer->tx_pause_flag) || (peer->tx_limit_flag)) && + (peer_tput) && (peer_tput < thresh)) + peer_limit = limit; + + if (peer_limit) { + ol_txrx_peer_bal_add_limit_peer(pdev, peer_id, + peer_limit); + } else if (pdev->tx_peer_bal.peer_num) { + TX_SCHED_DEBUG_PRINT( + "Check if peer_id %d exit limit", + peer_id); + ol_txrx_peer_bal_remove_limit_peer(pdev, + peer_id); + } + if ((peer_tput == 0) && + (peer->tx_pause_flag == false)) { + peer->tx_pause_flag = true; + pause_flag = true; + } else if (peer->tx_pause_flag) { + unpause_flag = true; + peer->tx_pause_flag = false; + } + } else { + TX_SCHED_DEBUG_PRINT( + "Remove peer_id %d from limit list", peer_id); + ol_txrx_peer_bal_remove_limit_peer(pdev, peer_id); + } + + peer_link_status++; + qdf_spin_unlock_bh(&pdev->tx_peer_bal.mutex); + if (pause_flag) + ol_txrx_peer_pause_but_no_mgmt_q(peer); + else if (unpause_flag) + ol_txrx_peer_unpause_but_no_mgmt_q(peer); + } +} +#endif /* QCA_BAD_PEER_TX_FLOW_CL */ + +/*--- ADDBA triggering functions --------------------------------------------*/ + + +/*=== debug functions =======================================================*/ + +/*--- queue event log -------------------------------------------------------*/ + +#if defined(DEBUG_HL_LOGGING) + +#define negative_sign -1 + +/** + * ol_tx_queue_log_entry_type_info() - log queues entry info + * @type: log entry type + * @size: size + * @align: alignment + * @var_size: variable size record + * + * Return: None + */ +static void +ol_tx_queue_log_entry_type_info( + u_int8_t *type, int *size, int *align, int var_size) +{ + switch (*type) { + case ol_tx_log_entry_type_enqueue: + case ol_tx_log_entry_type_dequeue: + case ol_tx_log_entry_type_queue_free: + *size = sizeof(struct ol_tx_log_queue_add_t); + *align = 2; + break; + + case ol_tx_log_entry_type_queue_state: + *size = offsetof(struct ol_tx_log_queue_state_var_sz_t, data); + *align = 4; + if (var_size) { + /* read the variable-sized record, + * to see how large it is + */ + int align_pad; + struct ol_tx_log_queue_state_var_sz_t *record; + + align_pad = + (*align - (uint32_t)(((unsigned long) type) + 1)) + & (*align - 1); + record = (struct ol_tx_log_queue_state_var_sz_t *) + (type + 1 + align_pad); + *size += record->num_cats_active * + (sizeof(u_int32_t) /* bytes */ + + sizeof(u_int16_t) /* frms */); + } + break; + + /*case ol_tx_log_entry_type_drop:*/ + default: + *size = 0; + *align = 0; + }; +} + +/** + * ol_tx_queue_log_oldest_update() - log oldest record + * @pdev: pointer to txrx handle + * @offset: offset value + * + * Return: None + */ +static void +ol_tx_queue_log_oldest_update(struct ol_txrx_pdev_t *pdev, int offset) +{ + int oldest_record_offset; + + /* + * If the offset of the oldest record is between the current and + * new values of the offset of the newest record, then the oldest + * record has to be dropped from the log to provide room for the + * newest record. + * Advance the offset of the oldest record until it points to a + * record that is beyond the new value of the offset of the newest + * record. + */ + if (!pdev->txq_log.wrapped) + /* + * The log has not even filled up yet - no need to remove + * the oldest record to make room for a new record. + */ + return; + + + if (offset > pdev->txq_log.offset) { + /* + * not wraparound - + * The oldest record offset may have already wrapped around, + * even if the newest record has not. In this case, then + * the oldest record offset is fine where it is. + */ + if (pdev->txq_log.oldest_record_offset == 0) + return; + + oldest_record_offset = pdev->txq_log.oldest_record_offset; + } else + /* wraparound */ + oldest_record_offset = 0; + + + while (oldest_record_offset < offset) { + int size, align, align_pad; + u_int8_t type; + + type = pdev->txq_log.data[oldest_record_offset]; + if (type == ol_tx_log_entry_type_wrap) { + oldest_record_offset = 0; + break; + } + ol_tx_queue_log_entry_type_info( + &pdev->txq_log.data[oldest_record_offset], + &size, &align, 1); + align_pad = + (align - ((oldest_record_offset + 1/*type*/))) + & (align - 1); + /* + * QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + * "TXQ LOG old alloc: offset %d, type %d, size %d (%d)\n", + * oldest_record_offset, type, size, size + 1 + align_pad); + */ + oldest_record_offset += size + 1 + align_pad; + } + if (oldest_record_offset >= pdev->txq_log.size) + oldest_record_offset = 0; + + pdev->txq_log.oldest_record_offset = oldest_record_offset; +} + +/** + * ol_tx_queue_log_alloc() - log data allocation + * @pdev: physical device object + * @type: ol_tx_log_entry_type + * @extra_bytes: extra bytes + * + * + * Return: log element + */ +static void * +ol_tx_queue_log_alloc( + struct ol_txrx_pdev_t *pdev, + u_int8_t type /* ol_tx_log_entry_type */, + int extra_bytes) +{ + int size, align, align_pad; + int offset; + + ol_tx_queue_log_entry_type_info(&type, &size, &align, 0); + size += extra_bytes; + + offset = pdev->txq_log.offset; + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + + if (pdev->txq_log.size - offset >= size + 1 + align_pad) + /* no need to wrap around */ + goto alloc_found; + + if (!pdev->txq_log.allow_wrap) + return NULL; /* log is full and can't wrap */ + + /* handle wrap-around */ + pdev->txq_log.wrapped = 1; + offset = 0; + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + /* sanity check that the log is large enough to hold this entry */ + if (pdev->txq_log.size <= size + 1 + align_pad) + return NULL; + + +alloc_found: + ol_tx_queue_log_oldest_update(pdev, offset + size + 1 + align_pad); + if (offset == 0) + pdev->txq_log.data[pdev->txq_log.offset] = + ol_tx_log_entry_type_wrap; + + /* + * QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + * "TXQ LOG new alloc: offset %d, type %d, size %d (%d)\n", + * offset, type, size, size + 1 + align_pad); + */ + pdev->txq_log.data[offset] = type; + pdev->txq_log.offset = offset + size + 1 + align_pad; + if (pdev->txq_log.offset >= pdev->txq_log.size) { + pdev->txq_log.offset = 0; + pdev->txq_log.wrapped = 1; + } + return &pdev->txq_log.data[offset + 1 + align_pad]; +} + +/** + * ol_tx_queue_log_record_display() - show log record of tx queue + * @pdev: pointer to txrx handle + * @offset: offset value + * + * Return: size of record + */ +static int +ol_tx_queue_log_record_display(struct ol_txrx_pdev_t *pdev, int offset) +{ + int size, align, align_pad; + u_int8_t type; + struct ol_txrx_peer_t *peer; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + type = pdev->txq_log.data[offset]; + ol_tx_queue_log_entry_type_info( + &pdev->txq_log.data[offset], &size, &align, 1); + align_pad = (align - ((offset + 1/*type*/))) & (align - 1); + + switch (type) { + case ol_tx_log_entry_type_enqueue: + { + struct ol_tx_log_queue_add_t record; + + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, + record.peer_id); + if (peer) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d ("QDF_MAC_ADDR_FMT")", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "Q: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "Q: %6d %5d %3d from vdev", + record.num_frms, record.num_bytes, + record.tid); + } + break; + } + case ol_tx_log_entry_type_dequeue: + { + struct ol_tx_log_queue_add_t record; + + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, record.peer_id); + if (peer) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d ("QDF_MAC_ADDR_FMT")", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "DQ: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "DQ: %6d %5d %3d from vdev", + record.num_frms, record.num_bytes, + record.tid); + } + break; + } + case ol_tx_log_entry_type_queue_free: + { + struct ol_tx_log_queue_add_t record; + + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_add_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + if (record.peer_id != 0xffff) { + peer = ol_txrx_peer_find_by_id(pdev, record.peer_id); + if (peer) + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d ("QDF_MAC_ADDR_FMT")", + record.num_frms, record.num_bytes, + record.tid, + record.peer_id, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "F: %6d %5d %3d %4d", + record.num_frms, record.num_bytes, + record.tid, record.peer_id); + } else { + /* shouldn't happen */ + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "Unexpected vdev queue removal\n"); + } + break; + } + + case ol_tx_log_entry_type_queue_state: + { + int i, j; + u_int32_t active_bitmap; + struct ol_tx_log_queue_state_var_sz_t record; + u_int8_t *data; + + qdf_mem_copy(&record, + &pdev->txq_log.data[offset + 1 + align_pad], + sizeof(struct ol_tx_log_queue_state_var_sz_t)); + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "S: bitmap = %#x", + record.active_bitmap); + data = &record.data[0]; + j = 0; + i = 0; + active_bitmap = record.active_bitmap; + while (active_bitmap) { + if (active_bitmap & 0x1) { + u_int16_t frms; + u_int32_t bytes; + + frms = data[0] | (data[1] << 8); + bytes = (data[2] << 0) | (data[3] << 8) | + (data[4] << 16) | (data[5] << 24); + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "cat %2d: %6d %5d", + i, frms, bytes); + data += 6; + j++; + } + i++; + active_bitmap >>= 1; + } + break; + } + + /*case ol_tx_log_entry_type_drop:*/ + + case ol_tx_log_entry_type_wrap: + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return negative_sign * offset; /* go back to the top */ + + default: + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "*** invalid tx log entry type (%d)\n", type); + return 0; /* error */ + }; + + return size + 1 + align_pad; +} + +/** + * ol_tx_queue_log_display() - show tx queue log + * @pdev: pointer to txrx handle + * + * Return: None + */ +void +ol_tx_queue_log_display(struct ol_txrx_pdev_t *pdev) +{ + int offset; + int unwrap; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + offset = pdev->txq_log.oldest_record_offset; + unwrap = pdev->txq_log.wrapped; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + /* + * In theory, this should use mutex to guard against the offset + * being changed while in use, but since this is just for debugging, + * don't bother. + */ + txrx_nofl_info("Current target credit: %d", + qdf_atomic_read(&pdev->target_tx_credit)); + txrx_nofl_info("Tx queue log:"); + txrx_nofl_info(": Frames Bytes TID PEER"); + + while (unwrap || offset != pdev->txq_log.offset) { + int delta = ol_tx_queue_log_record_display(pdev, offset); + + if (delta == 0) + return; /* error */ + + if (delta < 0) + unwrap = 0; + + offset += delta; + } +} + +void +ol_tx_queue_log_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes) +{ + int tid; + u_int16_t peer_id = msdu_info->htt.info.peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + tid = msdu_info->htt.info.ext_tid; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_enqueue, 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int frms, int bytes) +{ + int ext_tid; + u_int16_t peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + ext_tid = txq->ext_tid; + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_dequeue, 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + if (ext_tid < OL_TX_NUM_TIDS) { + struct ol_txrx_peer_t *peer; + struct ol_tx_frms_queue_t *txq_base; + + txq_base = txq - ext_tid; + peer = container_of(txq_base, struct ol_txrx_peer_t, txqs[0]); + peer_id = peer->peer_ids[0]; + } else { + peer_id = ~0; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = ext_tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes, bool is_peer_txq) +{ + u_int16_t peer_id; + struct ol_tx_log_queue_add_t *log_elem; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc(pdev, ol_tx_log_entry_type_queue_free, + 0); + if (!log_elem) { + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + + if ((tid < OL_TX_NUM_TIDS) && is_peer_txq) { + struct ol_txrx_peer_t *peer; + struct ol_tx_frms_queue_t *txq_base; + + txq_base = txq - tid; + peer = container_of(txq_base, struct ol_txrx_peer_t, txqs[0]); + peer_id = peer->peer_ids[0]; + } else { + peer_id = ~0; + } + + log_elem->num_frms = frms; + log_elem->num_bytes = bytes; + log_elem->peer_id = peer_id; + log_elem->tid = tid; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +void +ol_tx_queue_log_sched( + struct ol_txrx_pdev_t *pdev, + int credit, + int *num_cats, + u_int32_t **active_bitmap, + u_int8_t **data) +{ + int data_size; + struct ol_tx_log_queue_state_var_sz_t *log_elem; + + data_size = sizeof(u_int32_t) /* bytes */ + + sizeof(u_int16_t) /* frms */; + data_size *= *num_cats; + + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + log_elem = ol_tx_queue_log_alloc( + pdev, ol_tx_log_entry_type_queue_state, data_size); + if (!log_elem) { + *num_cats = 0; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); + return; + } + log_elem->num_cats_active = *num_cats; + log_elem->active_bitmap = 0; + log_elem->credit = credit; + + *active_bitmap = &log_elem->active_bitmap; + *data = &log_elem->data[0]; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} + +/** + * ol_tx_queue_log_clear() - clear tx queue log + * @pdev: pointer to txrx handle + * + * Return: None + */ +void +ol_tx_queue_log_clear(struct ol_txrx_pdev_t *pdev) +{ + qdf_spin_lock_bh(&pdev->txq_log_spinlock); + qdf_mem_zero(&pdev->txq_log, sizeof(pdev->txq_log)); + pdev->txq_log.size = OL_TXQ_LOG_SIZE; + pdev->txq_log.oldest_record_offset = 0; + pdev->txq_log.offset = 0; + pdev->txq_log.allow_wrap = 1; + pdev->txq_log.wrapped = 0; + qdf_spin_unlock_bh(&pdev->txq_log_spinlock); +} +#endif /* defined(DEBUG_HL_LOGGING) */ + +/*--- queue state printouts -------------------------------------------------*/ + +#if TXRX_DEBUG_LEVEL > 5 + +/** + * ol_tx_queue_display() - show tx queue info + * @txq: pointer to txq frames + * @indent: indent + * + * Return: None + */ +static void +ol_tx_queue_display(struct ol_tx_frms_queue_t *txq, int indent) +{ + char *state; + + state = (txq->flag == ol_tx_queue_active) ? "active" : "paused"; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxq %pK (%s): %d frms, %d bytes\n", + indent, " ", txq, state, txq->frms, txq->bytes); +} + +void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_vdev_t *vdev; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "pdev %pK tx queues:\n", pdev); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + struct ol_txrx_peer_t *peer; + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(vdev->txqs); i++) { + if (vdev->txqs[i].frms == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "vdev %d (%pK), txq %d\n", vdev->vdev_id, + vdev, i); + ol_tx_queue_display(&vdev->txqs[i], 4); + } + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) { + if (peer->txqs[i].frms == 0) + continue; + + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_LOW, + "peer %d (%pK), txq %d\n", + peer->peer_ids[0], vdev, i); + ol_tx_queue_display(&peer->txqs[i], 6); + } + } + } +} +#endif + +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(CONFIG_HL_SUPPORT) + +/** + * ol_txrx_pdev_pause() - pause network queues for each vdev + * @pdev: pdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + cdp_fc_vdev_pause(cds_get_context(QDF_MODULE_ID_SOC), + vdev->vdev_id, reason, 0); + } + +} + +/** + * ol_txrx_pdev_unpause() - unpause network queues for each vdev + * @pdev: pdev handle + * @reason: reason + * + * Return: none + */ +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + cdp_fc_vdev_unpause(cds_get_context(QDF_MODULE_ID_SOC), + vdev->vdev_id, reason, 0); + } + +} +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +/** + * ol_tx_vdev_has_tx_queue_group() - check for vdev having txq groups + * @group: pointer to tx queue grpup + * @vdev_id: vdev id + * + * Return: true if vedv has txq groups + */ +static bool +ol_tx_vdev_has_tx_queue_group( + struct ol_tx_queue_group_t *group, + u_int8_t vdev_id) +{ + u_int16_t vdev_bitmap; + + vdev_bitmap = OL_TXQ_GROUP_VDEV_ID_MASK_GET(group->membership); + if (OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_bitmap, vdev_id)) + return true; + + return false; +} + +/** + * ol_tx_ac_has_tx_queue_group() - check for ac having txq groups + * @group: pointer to tx queue grpup + * @ac: access category + * + * Return: true if vedv has txq groups + */ +static bool +ol_tx_ac_has_tx_queue_group( + struct ol_tx_queue_group_t *group, + u_int8_t ac) +{ + u_int16_t ac_bitmap; + + ac_bitmap = OL_TXQ_GROUP_AC_MASK_GET(group->membership); + if (OL_TXQ_GROUP_AC_BIT_MASK_GET(ac_bitmap, ac)) + return true; + + return false; +} + +#ifdef FEATURE_HL_DBS_GROUP_CREDIT_SHARING +static inline struct ol_tx_queue_group_t * +ol_tx_txq_find_other_group(struct ol_txrx_pdev_t *pdev, + struct ol_tx_queue_group_t *txq_grp) +{ + int i; + struct ol_tx_queue_group_t *other_grp = NULL; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + if (&pdev->txq_grps[i] != txq_grp) { + other_grp = &pdev->txq_grps[i]; + break; + } + } + return other_grp; +} + +u32 ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u32 credit) +{ + struct ol_tx_queue_group_t *txq_grp = txq->group_ptrs[0]; + struct ol_tx_queue_group_t *other_grp; + u32 ask; + u32 updated_credit; + u32 credit_oth_grp; + + if (qdf_unlikely(!txq_grp)) + return credit; + + updated_credit = qdf_atomic_read(&txq_grp->credit); + + if (credit <= updated_credit) + /* We have enough credits */ + return credit; + + ask = credit - updated_credit; + other_grp = ol_tx_txq_find_other_group(pdev, txq_grp); + if (qdf_unlikely(!other_grp)) + return credit; + + credit_oth_grp = qdf_atomic_read(&other_grp->credit); + if (other_grp->frm_count < credit_oth_grp) { + u32 spare = credit_oth_grp - other_grp->frm_count; + + if (pdev->limit_lend) { + if (spare > pdev->min_reserve) + spare -= pdev->min_reserve; + else + spare = 0; + } + updated_credit += min(spare, ask); + } + return updated_credit; +} + +u32 ol_tx_txq_update_borrowed_group_credits(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u32 credits_used) +{ + struct ol_tx_queue_group_t *txq_grp = txq->group_ptrs[0]; + u32 credits_cur_grp; + u32 credits_brwd; + + if (qdf_unlikely(!txq_grp)) + return credits_used; + + credits_cur_grp = qdf_atomic_read(&txq_grp->credit); + if (credits_used > credits_cur_grp) { + struct ol_tx_queue_group_t *other_grp = + ol_tx_txq_find_other_group(pdev, txq_grp); + + if (qdf_likely(other_grp)) { + credits_brwd = credits_used - credits_cur_grp; + /* + * All the credits were used from the active txq group. + */ + credits_used = credits_cur_grp; + /* Deduct credits borrowed from other group */ + ol_txrx_update_group_credit(other_grp, -credits_brwd, + 0); + } + } + return credits_used; +} +#else /* FEATURE_HL_DBS_GROUP_CREDIT_SHARING */ +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit) +{ + u_int8_t i; + int updated_credit = credit; + + /* + * If this tx queue belongs to a group, check whether the group's + * credit limit is more stringent than the global credit limit. + */ + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) { + int group_credit; + + group_credit = qdf_atomic_read( + &txq->group_ptrs[i]->credit); + updated_credit = QDF_MIN(updated_credit, group_credit); + } + } + + credit = (updated_credit < 0) ? 0 : updated_credit; + + return credit; +} +#endif /* FEATURE_HL_DBS_GROUP_CREDIT_SHARING */ + +void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute) +{ + u_int8_t i; + /* + * If this tx queue belongs to a group then + * update group credit + */ + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) + ol_txrx_update_group_credit(txq->group_ptrs[i], + credit, absolute); + } + ol_tx_update_group_credit_stats(pdev); +} + +void +ol_tx_set_vdev_group_ptr( + ol_txrx_pdev_handle pdev, + u_int8_t vdev_id, + struct ol_tx_queue_group_t *grp_ptr) +{ + struct ol_txrx_vdev_t *vdev = NULL; + struct ol_txrx_peer_t *peer = NULL; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) { + u_int8_t i, j; + + /* update vdev queues group pointers */ + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + for (j = 0; j < OL_TX_MAX_GROUPS_PER_QUEUE; j++) + vdev->txqs[i].group_ptrs[j] = grp_ptr; + } + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* Update peer queue group pointers */ + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + for (j = 0; + j < OL_TX_MAX_GROUPS_PER_QUEUE; + j++) + peer->txqs[i].group_ptrs[j] = + grp_ptr; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + break; + } + } +} + +void ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr) +{ + u_int8_t i; + + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) + txq->group_ptrs[i] = grp_ptr; +} + +void ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid) +{ + u_int8_t i, j = 0; + struct ol_tx_queue_group_t *group = NULL; + + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) + peer->txqs[tid].group_ptrs[i] = NULL; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + group = &pdev->txq_grps[i]; + if (ol_tx_vdev_has_tx_queue_group(group, vdev_id)) { + if (tid < OL_TX_NUM_QOS_TIDS) { + if (ol_tx_ac_has_tx_queue_group( + group, + TXRX_TID_TO_WMM_AC(tid))) { + peer->txqs[tid].group_ptrs[j] = group; + j++; + } + } else { + peer->txqs[tid].group_ptrs[j] = group; + j++; + } + } + if (j >= OL_TX_MAX_GROUPS_PER_QUEUE) + break; + } +} + +u_int32_t ol_tx_get_max_tx_groups_supported(struct ol_txrx_pdev_t *pdev) +{ + return OL_TX_MAX_TXQ_GROUPS; +} +#endif /* FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL */ + +#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \ + defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING) +void ol_tx_update_grp_frm_count(struct ol_tx_frms_queue_t *txq, int num_frms) +{ + int i; + + if (!num_frms || !txq) { + ol_txrx_dbg("Invalid params"); + return; + } + + for (i = 0; i < OL_TX_MAX_GROUPS_PER_QUEUE; i++) { + if (txq->group_ptrs[i]) { + txq->group_ptrs[i]->frm_count += num_frms; + qdf_assert(txq->group_ptrs[i]->frm_count >= 0); + } + } +} +#endif + +/*--- End of LL tx throttle queue code ---------------------------------------*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_queue.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_queue.h new file mode 100644 index 0000000000..0688cb4e9b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_queue.h @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_tx_queue.h + * @brief API definitions for the tx frame queue module within the data SW. + */ +#ifndef _OL_TX_QUEUE__H_ +#define _OL_TX_QUEUE__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include /* bool */ + +/*--- function prototypes for optional queue log feature --------------------*/ +#if defined(ENABLE_TX_QUEUE_LOG) || \ + (defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT)) + +/** + * ol_tx_queue_log_enqueue() - enqueue tx queue logs + * @pdev: physical device object + * @msdu_info: tx msdu meta data + * @frms: number of frames for which logs need to be enqueued + * @bytes: number of bytes + * + * + * Return: None + */ +void +ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes); + +/** + * ol_tx_queue_log_dequeue() - dequeue tx queue logs + * @pdev: physical device object + * @txq: tx queue + * @frms: number of frames for which logs need to be dequeued + * @bytes: number of bytes + * + * + * Return: None + */ +void +ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, int frms, int bytes); + +/** + * ol_tx_queue_log_free() - free tx queue logs + * @pdev: physical device object + * @txq: tx queue + * @tid: tid value + * @frms: number of frames for which logs need to be freed + * @bytes: number of bytes + * @is_peer_txq - peer queue or not + * + * + * Return: None + */ +void +ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes, bool is_peer_txq); + +#else + +static inline void +ol_tx_queue_log_enqueue(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_msdu_info_t *msdu_info, + int frms, int bytes) +{ +} + +static inline void +ol_tx_queue_log_dequeue(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, int frms, int bytes) +{ +} + +static inline void +ol_tx_queue_log_free(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frms, int bytes, bool is_peer_txq) +{ +} + +#endif + +#if defined(CONFIG_HL_SUPPORT) + +/** + * @brief Queue a tx frame to the tid queue. + * + * @param pdev - the data virtual device sending the data + * (for storing the tx desc in the virtual dev's tx_target_list, + * and for accessing the phy dev) + * @param txq - which queue the tx frame gets stored in + * @param tx_desc - tx meta-data, including prev and next ptrs + * @param tx_msdu_info - characteristics of the tx frame + */ +void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +/** + * @brief - remove the specified number of frames from the head of a tx queue + * @details + * This function removes frames from the head of a tx queue, + * and returns them as a NULL-terminated linked list. + * The function will remove frames until one of the following happens: + * 1. The tx queue is empty + * 2. The specified number of frames have been removed + * 3. Removal of more frames would exceed the specified credit limit + * + * @param pdev - the physical device object + * @param txq - which tx queue to remove frames from + * @param head - which contains return linked-list of tx frames (descriptors) + * @param num_frames - maximum number of frames to remove + * @param[in/out] credit - + * input: max credit the dequeued frames can consume + * output: how much credit the dequeued frames consume + * @param[out] bytes - the sum of the sizes of the dequeued frames + * @return number of frames dequeued + */ +u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t num_frames, + u_int32_t *credit, + int *bytes); + +/** + * @brief - free all of frames from the tx queue while deletion + * @details + * This function frees all of frames from the tx queue. + * This function is called during peer or vdev deletion. + * This function notifies the scheduler, so the scheduler can update + * its state to account for the absence of the queue. + * + * @param pdev - the physical device object, which stores the txqs + * @param txq - which tx queue to free frames from + * @param tid - the extended TID that the queue belongs to + * @param is_peer_txq - peer queue or not + */ +void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, bool is_peer_txq); + +/** + * @brief - discard pending tx frames from the tx queue + * @details + * This function is called if there are too many queues in tx scheduler. + * This function is called if we wants to flush all pending tx + * queues in tx scheduler. + * + * @param pdev - the physical device object, which stores the txqs + * @param flush_all - flush all pending tx queues if set to true + * @param tx_descs - List Of tx_descs to be discarded will be returned by this + * function + */ + +void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs); + +#else + +static inline void +ol_tx_enqueue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + struct ol_tx_desc_t *tx_desc, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ +} + +static inline u_int16_t +ol_tx_dequeue( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + ol_tx_desc_list *head, + u_int16_t num_frames, + u_int32_t *credit, + int *bytes) +{ + return 0; +} + +static inline void +ol_tx_queue_free( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, bool is_peer_txq) +{ +} + +static inline void +ol_tx_queue_discard( + struct ol_txrx_pdev_t *pdev, + bool flush_all, + ol_tx_desc_list *tx_descs) +{ +} +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if (!defined(QCA_LL_LEGACY_TX_FLOW_CONTROL)) && (!defined(CONFIG_HL_SUPPORT)) +static inline +void ol_txrx_vdev_flush(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ +} +#else +/** + * ol_txrx_vdev_flush() - Drop all tx data for the specified virtual device + * @soc_hdl: soc handle + * @vdev_id: vdev id + * + * Returns: none + * + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + * This function would typically be used by the ctrl SW after it parks + * a STA vdev and then resumes it, but to a new AP. In this case, though + * the same vdev can be used, any old tx frames queued inside it would be + * stale, and would need to be discarded. + */ +void ol_txrx_vdev_flush(struct cdp_soc_t *soc_hdl, uint8_t vdev_id); +#endif + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + (defined(QCA_LL_TX_FLOW_CONTROL_V2)) || \ + defined(CONFIG_HL_SUPPORT) +/** + * ol_txrx_vdev_pause- Suspend all tx data for the specified virtual device + * soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * @reason: the reason for which vdev queue is getting paused + * @pause_type: type of pause + * + * Return: none + * + * This function applies primarily to HL systems, but also + * applies to LL systems that use per-vdev tx queues for MCC or + * thermal throttling. As an example, this function could be + * used when a single-channel physical device supports multiple + * channels by jumping back and forth between the channels in a + * time-shared manner. As the device is switched from channel A + * to channel B, the virtual devices that operate on channel A + * will be paused. + */ +void ol_txrx_vdev_pause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type); + +/** + * ol_txrx_vdev_unpause - Resume tx for the specified virtual device + * soc_hdl: Datapath soc handle + * @vdev_id: id of vdev being unpaused + * @reason: the reason for which vdev queue is getting unpaused + * @pause_type: type of pause + * + * Return: none + * + * This function applies primarily to HL systems, but also applies to + * LL systems that use per-vdev tx queues for MCC or thermal throttling. + */ +void ol_txrx_vdev_unpause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type); +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +void +ol_txrx_peer_bal_add_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, + u_int16_t peer_limit); + +void +ol_txrx_peer_bal_remove_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id); + +/** + * ol_txrx_peer_pause_but_no_mgmt_q() - suspend/pause all txqs except + * management queue for a given peer + * @peer: peer device object + * + * Return: None + */ +void +ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer); + +/** + * ol_txrx_peer_unpause_but_no_mgmt_q() - unpause all txqs except management + * queue for a given peer + * @peer: peer device object + * + * Return: None + */ +void +ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer); + +/** + * ol_tx_bad_peer_dequeue_check() - retrieve the send limit + * of the tx queue category + * @txq: tx queue of the head of the category list + * @max_frames: send limit of the txq category + * @tx_limit_flag: set true is tx limit is reached + * + * Return: send limit + */ +u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag); + +/** + * ol_tx_bad_peer_update_tx_limit() - update the send limit of the + * tx queue category + * @pdev: the physical device object + * @txq: tx queue of the head of the category list + * @frames: frames that has been dequeued + * @tx_limit_flag: tx limit reached flag + * + * Return: None + */ +void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag); + +/** + * ol_txrx_set_txq_peer() - set peer to the tx queue's peer + * @txq: tx queue for a given tid + * @peer: the peer device object + * + * Return: None + */ +void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer); + +/** + * @brief - initialize the peer balance context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev); + +/** + * @brief - deinitialize the peer balance context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void ol_txrx_peer_bal_add_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id, + u_int16_t peer_limit) +{ +} + +static inline void ol_txrx_peer_bal_remove_limit_peer( + struct ol_txrx_pdev_t *pdev, + u_int16_t peer_id) +{ +} + +static inline void ol_txrx_peer_pause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ +} + +static inline void ol_txrx_peer_unpause_but_no_mgmt_q(ol_txrx_peer_handle peer) +{ +} + +static inline u_int16_t +ol_tx_bad_peer_dequeue_check(struct ol_tx_frms_queue_t *txq, + u_int16_t max_frames, + u_int16_t *tx_limit_flag) +{ + /* just return max_frames */ + return max_frames; +} + +static inline void +ol_tx_bad_peer_update_tx_limit(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int16_t frames, + u_int16_t tx_limit_flag) +{ +} + +static inline void +ol_txrx_set_txq_peer( + struct ol_tx_frms_queue_t *txq, + struct ol_txrx_peer_t *peer) +{ +} + +static inline void ol_tx_badpeer_flow_cl_init(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline void ol_tx_badpeer_flow_cl_deinit(struct ol_txrx_pdev_t *pdev) +{ +} + +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) + +/** + * ol_tx_queue_log_sched() - start logging of tx queues for HL + * @pdev: physical device object + * @credit: number of credits + * @num_active_tids: number of active tids for which logging needs to be done + * @active_bitmap:bitmap + * @data: buffer + * + * Return: None + */ +void +ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, + int credit, + int *num_active_tids, + uint32_t **active_bitmap, uint8_t **data); +#else + +static inline void +ol_tx_queue_log_sched(struct ol_txrx_pdev_t *pdev, + int credit, + int *num_active_tids, + uint32_t **active_bitmap, uint8_t **data) +{ +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) */ + +#if defined(CONFIG_HL_SUPPORT) && TXRX_DEBUG_LEVEL > 5 +/** + * @brief - show current state of all tx queues + * @param pdev - the physical device object, which stores the txqs + */ +void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev); + +#else + +static inline void +ol_tx_queues_display(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +#define ol_tx_queue_decs_reinit(peer, peer_id) /* no-op */ + +#ifdef QCA_SUPPORT_TX_THROTTLE +void ol_tx_throttle_set_level(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, int level); +void ol_tx_throttle_init_period(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, int period, + uint8_t *dutycycle_level); + +/** + * @brief - initialize the throttle context + * @param pdev - the physical device object, which stores the txqs + */ +void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev); +#else +static inline void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) {} + +static inline void ol_tx_throttle_set_level(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, int level) +{} + +static inline void +ol_tx_throttle_init_period(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int period, uint8_t *dutycycle_level) +{} +#endif + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +static inline bool +ol_tx_if_iterate_next_txq(struct ol_tx_frms_queue_t *first, + struct ol_tx_frms_queue_t *txq) +{ + return (first != txq); +} + +/** + * ol_tx_txq_group_credit_limit() - check for credit limit of a given tx queue + * @pdev: physical device object + * @txq: tx queue for which credit limit needs be to checked + * @credit: number of credits of the selected category + * + * Return: updated credits + */ +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit); + +/** + * ol_tx_txq_group_credit_update() - update group credits of the + * selected catoegory + * @pdev: physical device object + * @txq: tx queue for which credit needs to be updated + * @credit: number of credits by which selected category needs to be updated + * @absolute: TXQ group absolute value + * + * Return: None + */ +void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute); + +/** + * ol_tx_set_vdev_group_ptr() - update vdev queues group pointer + * @pdev: physical device object + * @vdev_id: vdev id for which group pointer needs to update + * @grp_ptr: pointer to ol tx queue group which needs to be set for vdev queues + * + * Return: None + */ +void +ol_tx_set_vdev_group_ptr( + ol_txrx_pdev_handle pdev, + u_int8_t vdev_id, + struct ol_tx_queue_group_t *grp_ptr); + +/** + * ol_tx_txq_set_group_ptr() - update tx queue group pointer + * @txq: tx queue of which group pointer needs to update + * @grp_ptr: pointer to ol tx queue group which needs to be + * set for given tx queue + * + * + * Return: None + */ +void +ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr); + +/** + * ol_tx_set_peer_group_ptr() - update peer tx queues group pointer + * for a given tid + * @pdev: physical device object + * @peer: peer device object + * @vdev_id: vdev id + * @tid: tid for which group pointer needs to update + * + * + * Return: None + */ +void +ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid); +#else + +static inline bool +ol_tx_if_iterate_next_txq(struct ol_tx_frms_queue_t *first, + struct ol_tx_frms_queue_t *txq) +{ + return 0; +} + +static inline +u_int32_t ol_tx_txq_group_credit_limit( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u_int32_t credit) +{ + return credit; +} + +static inline void ol_tx_txq_group_credit_update( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int32_t credit, + u_int8_t absolute) +{ +} + +static inline void +ol_tx_txq_set_group_ptr( + struct ol_tx_frms_queue_t *txq, + struct ol_tx_queue_group_t *grp_ptr) +{ +} + +static inline void +ol_tx_set_peer_group_ptr( + ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer, + u_int8_t vdev_id, + u_int8_t tid) +{ +} +#endif + +#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \ + defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING) +/** + * @brief: Update group frame count + * @details: This function is used to maintain the count of frames + * enqueued in a particular group. + * + * @param: txq - The txq to which the frame is getting enqueued. + * @param: num_frms - Number of frames to be added/removed from the group. + */ +void ol_tx_update_grp_frm_count(struct ol_tx_frms_queue_t *txq, int num_frms); + +u32 ol_tx_txq_update_borrowed_group_credits(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u32 credits_used); +#else +static inline void ol_tx_update_grp_frm_count(struct ol_tx_frms_queue_t *txq, + int num_frms) +{} + +static inline u32 +ol_tx_txq_update_borrowed_group_credits(struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + u32 credits_used) +{ + return credits_used; +} +#endif /* + * FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL && + * FEATURE_HL_DBS_GROUP_CREDIT_SHARING + */ + +#endif /* _OL_TX_QUEUE__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_sched.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_sched.c new file mode 100644 index 0000000000..26a7f67e91 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_sched.c @@ -0,0 +1,1643 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync */ +#include /* TXRX_ASSERT1 */ +#include /* pdev stats, etc. */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include /* OL_TX_SCHED, etc. */ +#include +#include +#include +#include /* qdf_os_mem_alloc_consistent et al */ +#include +#if defined(CONFIG_HL_SUPPORT) + +#if defined(DEBUG_HL_LOGGING) +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev); + +#else +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev) +{ +} +#endif /* defined(DEBUG_HL_LOGGING) */ + +#if DEBUG_HTT_CREDIT +#define OL_TX_DISPATCH_LOG_CREDIT() \ + do { \ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, \ + "TX %d bytes\n", qdf_nbuf_len(msdu)); \ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, \ + " Decrease credit %d - 1 = %d, len:%d.\n", \ + qdf_atomic_read(&pdev->target_tx_credit), \ + qdf_atomic_read(&pdev->target_tx_credit) - 1, \ + qdf_nbuf_len(msdu)); \ + } while (0) +#else +#define OL_TX_DISPATCH_LOG_CREDIT() +#endif + +/*--- generic definitions used by the scheduler framework for all algs ---*/ + +struct ol_tx_sched_ctx { + ol_tx_desc_list head; + int frms; +}; + +typedef TAILQ_HEAD(ol_tx_frms_queue_list_s, ol_tx_frms_queue_t) + ol_tx_frms_queue_list; + + /*--- scheduler algorithm selection ---*/ + + /*--- scheduler options ----------------------------------------------- + * 1. Round-robin scheduler: + * Select the TID that is at the head of the list of active TIDs. + * Select the head tx queue for this TID. + * Move the tx queue to the back of the list of tx queues for + * this TID. + * Move the TID to the back of the list of active TIDs. + * Send as many frames from the tx queue as credit allows. + * 2. Weighted-round-robin advanced scheduler: + * Keep an ordered list of which TID gets selected next. + * Use a weighted-round-robin scheme to determine when to promote + * a TID within this list. + * If a TID at the head of the list is inactive, leave it at the + * head, but check the next TIDs. + * If the credit available is less than the credit threshold for the + * next active TID, don't send anything, and leave the TID at the + * head of the list. + * After a TID is selected, move it to the back of the list. + * Select the head tx queue for this TID. + * Move the tx queue to the back of the list of tx queues for this + * TID. + * Send no more frames than the limit specified for the TID. + */ +#define OL_TX_SCHED_RR 1 +#define OL_TX_SCHED_WRR_ADV 2 + +#ifndef OL_TX_SCHED + /*#define OL_TX_SCHED OL_TX_SCHED_RR*/ +#define OL_TX_SCHED OL_TX_SCHED_WRR_ADV /* default */ +#endif + + +#if OL_TX_SCHED == OL_TX_SCHED_RR + +#define ol_tx_sched_rr_t ol_tx_sched_t + +#define OL_TX_SCHED_NUM_CATEGORIES (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES) + +#define ol_tx_sched_init ol_tx_sched_init_rr +#define ol_tx_sched_select_init(pdev) /* no-op */ +#define ol_tx_sched_select_batch ol_tx_sched_select_batch_rr +#define ol_tx_sched_txq_enqueue ol_tx_sched_txq_enqueue_rr +#define ol_tx_sched_txq_deactivate ol_tx_sched_txq_deactivate_rr +#define ol_tx_sched_category_tx_queues ol_tx_sched_category_tx_queues_rr +#define ol_tx_sched_txq_discard ol_tx_sched_txq_discard_rr +#define ol_tx_sched_category_info ol_tx_sched_category_info_rr +#define ol_tx_sched_discard_select_category \ + ol_tx_sched_discard_select_category_rr + +#elif OL_TX_SCHED == OL_TX_SCHED_WRR_ADV + +#define ol_tx_sched_wrr_adv_t ol_tx_sched_t + +#define OL_TX_SCHED_NUM_CATEGORIES OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES + +#define ol_tx_sched_init ol_tx_sched_init_wrr_adv +#define ol_tx_sched_select_init(pdev) \ + do { \ + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); \ + ol_tx_sched_select_init_wrr_adv(pdev); \ + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); \ + } while (0) +#define ol_tx_sched_select_batch ol_tx_sched_select_batch_wrr_adv +#define ol_tx_sched_txq_enqueue ol_tx_sched_txq_enqueue_wrr_adv +#define ol_tx_sched_txq_deactivate ol_tx_sched_txq_deactivate_wrr_adv +#define ol_tx_sched_category_tx_queues ol_tx_sched_category_tx_queues_wrr_adv +#define ol_tx_sched_txq_discard ol_tx_sched_txq_discard_wrr_adv +#define ol_tx_sched_category_info ol_tx_sched_category_info_wrr_adv +#define ol_tx_sched_discard_select_category \ + ol_tx_sched_discard_select_category_wrr_adv + +#else + +#error Unknown OL TX SCHED specification + +#endif /* OL_TX_SCHED */ + + /*--- round-robin scheduler ----------------------------------------*/ +#if OL_TX_SCHED == OL_TX_SCHED_RR + + /*--- definitions ---*/ + + struct ol_tx_active_queues_in_tid_t { + /* list_elem is used to queue up into up level queues*/ + TAILQ_ENTRY(ol_tx_active_queues_in_tid_t) list_elem; + u_int32_t frms; + u_int32_t bytes; + ol_tx_frms_queue_list head; + bool active; + int tid; + }; + + struct ol_tx_sched_rr_t { + struct ol_tx_active_queues_in_tid_t + tx_active_queues_in_tid_array[OL_TX_NUM_TIDS + + OL_TX_VDEV_NUM_QUEUES]; + TAILQ_HEAD(ol_tx_active_tids_s, ol_tx_active_queues_in_tid_t) + tx_active_tids_list; + u_int8_t discard_weights[OL_TX_NUM_TIDS + + OL_TX_VDEV_NUM_QUEUES]; + }; + +#define TX_SCH_MAX_CREDIT_FOR_THIS_TID(tidq) 16 + +/*--- functions ---*/ + +/* + * The scheduler sync spinlock has been acquired outside this function, + * so there is no need to worry about mutex within this function. + */ +static int +ol_tx_sched_select_batch_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx, + u_int32_t credit) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + struct ol_tx_frms_queue_t *next_tq; + u_int16_t frames, used_credits = 0, tx_limit, tx_limit_flag = 0; + int bytes; + + TX_SCHED_DEBUG_PRINT("Enter"); + + if (TAILQ_EMPTY(&scheduler->tx_active_tids_list)) + return used_credits; + + txq_queue = TAILQ_FIRST(&scheduler->tx_active_tids_list); + + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, list_elem); + txq_queue->active = false; + + next_tq = TAILQ_FIRST(&txq_queue->head); + TAILQ_REMOVE(&txq_queue->head, next_tq, list_elem); + + credit = QDF_MIN(credit, TX_SCH_MAX_CREDIT_FOR_THIS_TID(next_tq)); + frames = next_tq->frms; /* download as many frames as credit allows */ + tx_limit = ol_tx_bad_peer_dequeue_check(next_tq, + frames, + &tx_limit_flag); + frames = ol_tx_dequeue( + pdev, next_tq, &sctx->head, tx_limit, &credit, &bytes); + ol_tx_bad_peer_update_tx_limit(pdev, next_tq, frames, tx_limit_flag); + + used_credits = credit; + txq_queue->frms -= frames; + txq_queue->bytes -= bytes; + + if (next_tq->frms > 0) { + TAILQ_INSERT_TAIL(&txq_queue->head, next_tq, list_elem); + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } else if (!TAILQ_EMPTY(&txq_queue->head)) { + /* + * This tx queue is empty, but there's another tx queue for the + * same TID that is not empty. + *Thus, the TID as a whole is active. + */ + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } + sctx->frms += frames; + + TX_SCHED_DEBUG_PRINT("Leave"); + return used_credits; +} + +static inline void +ol_tx_sched_txq_enqueue_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, + int frms, + int bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + if (txq->flag != ol_tx_queue_active) + TAILQ_INSERT_TAIL(&txq_queue->head, txq, list_elem); + + txq_queue->frms += frms; + txq_queue->bytes += bytes; + + if (!txq_queue->active) { + TAILQ_INSERT_TAIL( + &scheduler->tx_active_tids_list, + txq_queue, list_elem); + txq_queue->active = true; + } +} + +static inline void +ol_tx_sched_txq_deactivate_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + txq_queue->frms -= txq->frms; + txq_queue->bytes -= txq->bytes; + + TAILQ_REMOVE(&txq_queue->head, txq, list_elem); + /*if (txq_queue->frms == 0 && txq_queue->active) {*/ + if (TAILQ_EMPTY(&txq_queue->head) && txq_queue->active) { + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, + list_elem); + txq_queue->active = false; + } +} + +ol_tx_frms_queue_list * +ol_tx_sched_category_tx_queues_rr(struct ol_txrx_pdev_t *pdev, int tid) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + return &txq_queue->head; +} + +int +ol_tx_sched_discard_select_category_rr(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_rr_t *scheduler; + u_int8_t i, tid = 0; + int max_score = 0; + + scheduler = pdev->tx_sched.scheduler; + /* + * Choose which TID's tx frames to drop next based on two factors: + * 1. Which TID has the most tx frames present + * 2. The TID's priority (high-priority TIDs have a low discard_weight) + */ + for (i = 0; i < (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES); i++) { + int score; + + score = + scheduler->tx_active_queues_in_tid_array[i].frms * + scheduler->discard_weights[i]; + if (max_score == 0 || score > max_score) { + max_score = score; + tid = i; + } + } + return tid; +} + +void +ol_tx_sched_txq_discard_rr( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, int frames, int bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[tid]; + + if (0 == txq->frms) + TAILQ_REMOVE(&txq_queue->head, txq, list_elem); + + txq_queue->frms -= frames; + txq_queue->bytes -= bytes; + if (txq_queue->active == true && txq_queue->frms == 0) { + TAILQ_REMOVE(&scheduler->tx_active_tids_list, txq_queue, + list_elem); + txq_queue->active = false; + } +} + +void +ol_tx_sched_category_info_rr( + struct ol_txrx_pdev_t *pdev, + int cat, int *active, + int *frms, int *bytes) +{ + struct ol_tx_sched_rr_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_active_queues_in_tid_t *txq_queue; + + txq_queue = &scheduler->tx_active_queues_in_tid_array[cat]; + + *active = txq_queue->active; + *frms = txq_queue->frms; + *bytes = txq_queue->bytes; +} + +enum { + ol_tx_sched_discard_weight_voice = 1, + ol_tx_sched_discard_weight_video = 4, + ol_tx_sched_discard_weight_ucast_default = 8, + ol_tx_sched_discard_weight_mgmt_non_qos = 1, /* 0? */ + ol_tx_sched_discard_weight_mcast = 1, /* 0? also for probe & assoc */ +}; + +void * +ol_tx_sched_init_rr( + struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_rr_t *scheduler; + int i; + + scheduler = qdf_mem_malloc(sizeof(struct ol_tx_sched_rr_t)); + if (!scheduler) + return scheduler; + + for (i = 0; i < (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES); i++) { + scheduler->tx_active_queues_in_tid_array[i].tid = i; + TAILQ_INIT(&scheduler->tx_active_queues_in_tid_array[i].head); + scheduler->tx_active_queues_in_tid_array[i].active = 0; + scheduler->tx_active_queues_in_tid_array[i].frms = 0; + scheduler->tx_active_queues_in_tid_array[i].bytes = 0; + } + for (i = 0; i < OL_TX_NUM_TIDS; i++) { + scheduler->tx_active_queues_in_tid_array[i].tid = i; + if (i < OL_TX_NON_QOS_TID) { + int ac = TXRX_TID_TO_WMM_AC(i); + + switch (ac) { + case TXRX_WMM_AC_VO: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_voice; + case TXRX_WMM_AC_VI: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_video; + default: + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_ucast_default; + }; + } else { + scheduler->discard_weights[i] = + ol_tx_sched_discard_weight_mgmt_non_qos; + } + } + for (i = 0; i < OL_TX_VDEV_NUM_QUEUES; i++) { + int j = i + OL_TX_NUM_TIDS; + + scheduler->tx_active_queues_in_tid_array[j].tid = + OL_TX_NUM_TIDS - 1; + scheduler->discard_weights[j] = + ol_tx_sched_discard_weight_mcast; + } + TAILQ_INIT(&scheduler->tx_active_tids_list); + + return scheduler; +} + +void +ol_txrx_set_wmm_param(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct ol_tx_wmm_param_t wmm_param) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "Dummy function when OL_TX_SCHED_RR is enabled\n"); +} + +/** + * ol_tx_sched_stats_display() - tx sched stats display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ +} + +/** + * ol_tx_sched_cur_state_display() - tx sched cur stat display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ +} + +/** + * ol_tx_sched_cur_state_display() - reset tx sched stats + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ +} + +#endif /* OL_TX_SCHED == OL_TX_SCHED_RR */ + +/*--- advanced scheduler ----------------------------------------------------*/ +#if OL_TX_SCHED == OL_TX_SCHED_WRR_ADV + +/*--- definitions ---*/ + +struct ol_tx_sched_wrr_adv_category_info_t { + struct { + int wrr_skip_weight; + u_int32_t credit_threshold; + u_int16_t send_limit; + int credit_reserve; + int discard_weight; + } specs; + struct { + int wrr_count; + int frms; + int bytes; + ol_tx_frms_queue_list head; + bool active; + } state; +#ifdef DEBUG_HL_LOGGING + struct { + char *cat_name; + unsigned int queued; + unsigned int dispatched; + unsigned int discard; + } stat; +#endif +}; + +#define OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(cat, \ + wrr_skip_weight, \ + credit_threshold, \ + send_limit, \ + credit_reserve, \ + discard_weights) \ + enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _WRR_SKIP_WEIGHT = \ + (wrr_skip_weight) }; \ + enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _CREDIT_THRESHOLD = \ + (credit_threshold) }; \ + enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _SEND_LIMIT = \ + (send_limit) }; \ + enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _CREDIT_RESERVE = \ + (credit_reserve) }; \ + enum { OL_TX_SCHED_WRR_ADV_ ## cat ## _DISCARD_WEIGHT = \ + (discard_weights) }; +/* Rome: + * For high-volume traffic flows (VI, BE, BK), use a credit threshold + * roughly equal to a large A-MPDU (occupying half the target memory + * available for holding tx frames) to download AMPDU-sized batches + * of traffic. + * For high-priority, low-volume traffic flows (VO and mgmt), use no + * credit threshold, to minimize download latency. + */ +/* WRR send + * skip credit limit credit disc + * wts thresh (frms) reserv wts + */ +#ifdef HIF_SDIO +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VO, 1, 17, 24, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VI, 3, 17, 16, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BE, 10, 17, 16, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BK, 12, 6, 6, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(NON_QOS_DATA,10, 17, 16, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(UCAST_MGMT, 1, 1, 4, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_DATA, 10, 17, 4, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_MGMT, 1, 1, 4, 0, 1); +#else +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VO, 1, 16, 24, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(VI, 3, 16, 16, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BE, 10, 12, 12, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(BK, 12, 6, 6, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(NON_QOS_DATA, 12, 6, 4, 1, 8); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(UCAST_MGMT, 1, 1, 4, 0, 1); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_DATA, 10, 16, 4, 1, 4); +OL_TX_SCHED_WRR_ADV_CAT_CFG_SPEC(MCAST_MGMT, 1, 1, 4, 0, 1); +#endif + +#ifdef DEBUG_HL_LOGGING + +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler) \ + do { \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.queued = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.discard = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.dispatched = 0; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .stat.cat_name = #category; \ + } while (0) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms) \ + category->stat.queued += frms; +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frms) \ + category->stat.discard += frms; +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, frms) \ + category->stat.dispatched += frms; +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(scheduler) \ + ol_tx_sched_wrr_adv_cat_stat_dump(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(scheduler) \ + ol_tx_sched_wrr_adv_cat_cur_state_dump(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(scheduler) \ + ol_tx_sched_wrr_adv_cat_stat_clear(scheduler) + +#else /* DEBUG_HL_LOGGING */ + +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, frms) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(scheduler) +#define OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(scheduler) + +#endif /* DEBUG_HL_LOGGING */ + +#define OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(category, scheduler) \ + do { \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.wrr_skip_weight = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _WRR_SKIP_WEIGHT; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.credit_threshold = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _CREDIT_THRESHOLD; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.send_limit = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _SEND_LIMIT; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.credit_reserve = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _CREDIT_RESERVE; \ + scheduler->categories[OL_TX_SCHED_WRR_ADV_CAT_ ## category] \ + .specs.discard_weight = \ + OL_TX_SCHED_WRR_ADV_ ## category ## _DISCARD_WEIGHT; \ + OL_TX_SCHED_WRR_ADV_CAT_STAT_INIT(category, scheduler); \ + } while (0) + +struct ol_tx_sched_wrr_adv_t { + int order[OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES]; + int index; + struct ol_tx_sched_wrr_adv_category_info_t + categories[OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES]; +}; + +#define OL_TX_AIFS_DEFAULT_VO 2 +#define OL_TX_AIFS_DEFAULT_VI 2 +#define OL_TX_AIFS_DEFAULT_BE 3 +#define OL_TX_AIFS_DEFAULT_BK 7 +#define OL_TX_CW_MIN_DEFAULT_VO 3 +#define OL_TX_CW_MIN_DEFAULT_VI 7 +#define OL_TX_CW_MIN_DEFAULT_BE 15 +#define OL_TX_CW_MIN_DEFAULT_BK 15 + +/*--- functions ---*/ + +#ifdef DEBUG_HL_LOGGING +static void ol_tx_sched_wrr_adv_cat_stat_dump( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + + txrx_nofl_info("Scheduler Stats:"); + txrx_nofl_info("====category(CRR,CRT,WSW): Queued Discard Dequeued frms wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + txrx_nofl_info("%12s(%2d, %2d, %2d): %6d %7d %8d %4d %3d", + scheduler->categories[i].stat.cat_name, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs. + credit_threshold, + scheduler->categories[i]. + specs.wrr_skip_weight, + scheduler->categories[i].stat.queued, + scheduler->categories[i].stat.discard, + scheduler->categories[i].stat.dispatched, + scheduler->categories[i].state.frms, + scheduler->categories[i].state.wrr_count); + } +} + +static void ol_tx_sched_wrr_adv_cat_cur_state_dump( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + + txrx_nofl_info("Scheduler State Snapshot:"); + txrx_nofl_info("====category(CRR,CRT,WSW): IS_Active Pend_Frames Pend_bytes wrr==="); + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + txrx_nofl_info("%12s(%2d, %2d, %2d): %9d %11d %10d %3d", + scheduler->categories[i].stat.cat_name, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs. + credit_threshold, + scheduler->categories[i].specs. + wrr_skip_weight, + scheduler->categories[i].state.active, + scheduler->categories[i].state.frms, + scheduler->categories[i].state.bytes, + scheduler->categories[i].state.wrr_count); + } +} + +static void ol_tx_sched_wrr_adv_cat_stat_clear( + struct ol_tx_sched_wrr_adv_t *scheduler) +{ + int i; + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; ++i) { + scheduler->categories[i].stat.queued = 0; + scheduler->categories[i].stat.discard = 0; + scheduler->categories[i].stat.dispatched = 0; + } +} + +#endif + +static void +ol_tx_sched_select_init_wrr_adv(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + /* start selection from the front of the ordered list */ + scheduler->index = 0; +} + +static void +ol_tx_sched_wrr_adv_rotate_order_list_tail( + struct ol_tx_sched_wrr_adv_t *scheduler, int idx) +{ + int value; + /* remember the value of the specified element */ + value = scheduler->order[idx]; + /* shift all further elements up one space */ + for (; idx < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES-1; idx++) + scheduler->order[idx] = scheduler->order[idx + 1]; + + /* put the specified element at the end */ + scheduler->order[idx] = value; +} + +static void +ol_tx_sched_wrr_adv_credit_sanity_check(struct ol_txrx_pdev_t *pdev, + u_int32_t credit) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + int i; + int okay = 1; + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + if (scheduler->categories[i].specs.credit_threshold > credit) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "*** Config error: credit (%d) not enough to support category %d threshold (%d)\n", + credit, i, + scheduler->categories[i].specs. + credit_threshold); + okay = 0; + } + } + qdf_assert(okay); +} + +/* + * The scheduler sync spinlock has been acquired outside this function, + * so there is no need to worry about mutex within this function. + */ +static int +ol_tx_sched_select_batch_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx, + u_int32_t credit) +{ + static int first = 1; + int category_index = 0; + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_frms_queue_t *txq, *first_txq = NULL; + int index; + struct ol_tx_sched_wrr_adv_category_info_t *category = NULL; + int frames, bytes, used_credits = 0, tx_limit; + u_int16_t tx_limit_flag; + u32 credit_rem = credit; + + /* + * Just for good measure, do a sanity check that the initial credit + * is enough to cover every category's credit threshold. + */ + if (first) { + first = 0; + ol_tx_sched_wrr_adv_credit_sanity_check(pdev, credit); + } + + /* choose the traffic category from the ordered list */ + index = scheduler->index; + while (index < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES) { + category_index = scheduler->order[index]; + category = &scheduler->categories[category_index]; + if (!category->state.active) { + /* move on to the next category */ + index++; + continue; + } + if (++category->state.wrr_count < + category->specs.wrr_skip_weight) { + /* skip this category (move it to the back) */ + ol_tx_sched_wrr_adv_rotate_order_list_tail(scheduler, + index); + /* + * try again (iterate) on the new element + * that was moved up + */ + continue; + } + /* found the first active category whose WRR turn is present */ + break; + } + if (index >= OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES) { + /* no categories are active */ + return 0; + } + + /* is there enough credit for the selected category? */ + if (credit < category->specs.credit_threshold) { + /* + * Can't send yet - wait until more credit becomes available. + * In the meantime, restore the WRR counter (since we didn't + * service this category after all). + */ + category->state.wrr_count = category->state.wrr_count - 1; + return 0; + } + /* enough credit is available - go ahead and send some frames */ + /* + * This category was serviced - reset the WRR counter, and move this + * category to the back of the order list. + */ + category->state.wrr_count = 0; + ol_tx_sched_wrr_adv_rotate_order_list_tail(scheduler, index); + /* + * With this category moved to the back, if there's still any credit + * left, set up the next invocation of this function to start from + * where this one left off, by looking at the category that just got + * shifted forward into the position the service category was + * occupying. + */ + scheduler->index = index; + + /* + * Take the tx queue from the head of the category list. + */ + txq = TAILQ_FIRST(&category->state.head); + + while (txq) { + TAILQ_REMOVE(&category->state.head, txq, list_elem); + credit = ol_tx_txq_group_credit_limit(pdev, txq, credit); + if (credit > category->specs.credit_reserve) { + credit -= category->specs.credit_reserve; + tx_limit = ol_tx_bad_peer_dequeue_check(txq, + category->specs.send_limit, + &tx_limit_flag); + frames = ol_tx_dequeue( + pdev, txq, &sctx->head, + tx_limit, &credit, &bytes); + ol_tx_bad_peer_update_tx_limit(pdev, txq, + frames, + tx_limit_flag); + + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISPATCHED(category, + frames); + /* Update used global credits */ + used_credits = credit; + credit = + ol_tx_txq_update_borrowed_group_credits(pdev, txq, + credit); + category->state.frms -= frames; + category->state.bytes -= bytes; + if (txq->frms > 0) { + TAILQ_INSERT_TAIL(&category->state.head, + txq, list_elem); + } else { + if (category->state.frms == 0) + category->state.active = 0; + } + sctx->frms += frames; + ol_tx_txq_group_credit_update(pdev, txq, -credit, 0); + break; + } else { + /* + * Current txq belongs to a group which does not have + * enough credits, + * Iterate over to next txq and see if we can download + * packets from that queue. + */ + if (ol_tx_if_iterate_next_txq(first_txq, txq)) { + credit = credit_rem; + if (!first_txq) + first_txq = txq; + + TAILQ_INSERT_TAIL(&category->state.head, + txq, list_elem); + + txq = TAILQ_FIRST(&category->state.head); + } else { + TAILQ_INSERT_HEAD(&category->state.head, txq, + list_elem); + break; + } + } + } /* while(txq) */ + + return used_credits; +} + +static inline void +ol_tx_sched_txq_enqueue_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid, + int frms, + int bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[pdev->tid_to_ac[tid]]; + category->state.frms += frms; + category->state.bytes += bytes; + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_QUEUED(category, frms); + if (txq->flag != ol_tx_queue_active) { + TAILQ_INSERT_TAIL(&category->state.head, txq, list_elem); + category->state.active = 1; /* may have already been active */ + } +} + +static inline void +ol_tx_sched_txq_deactivate_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int tid) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[pdev->tid_to_ac[tid]]; + category->state.frms -= txq->frms; + category->state.bytes -= txq->bytes; + + TAILQ_REMOVE(&category->state.head, txq, list_elem); + + if (category->state.frms == 0 && category->state.active) + category->state.active = 0; +} + +static ol_tx_frms_queue_list * +ol_tx_sched_category_tx_queues_wrr_adv(struct ol_txrx_pdev_t *pdev, int cat) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + return &category->state.head; +} + +static int +ol_tx_sched_discard_select_category_wrr_adv(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler; + u_int8_t i, cat = 0; + int max_score = 0; + + scheduler = pdev->tx_sched.scheduler; + /* + * Choose which category's tx frames to drop next based on two factors: + * 1. Which category has the most tx frames present + * 2. The category's priority (high-priority categories have a low + * discard_weight) + */ + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + int score; + + score = + scheduler->categories[i].state.frms * + scheduler->categories[i].specs.discard_weight; + if (max_score == 0 || score > max_score) { + max_score = score; + cat = i; + } + } + return cat; +} + +static void +ol_tx_sched_txq_discard_wrr_adv( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_frms_queue_t *txq, + int cat, int frames, int bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + + if (0 == txq->frms) + TAILQ_REMOVE(&category->state.head, txq, list_elem); + + + category->state.frms -= frames; + category->state.bytes -= bytes; + OL_TX_SCHED_WRR_ADV_CAT_STAT_INC_DISCARD(category, frames); + if (category->state.frms == 0) + category->state.active = 0; +} + +static void +ol_tx_sched_category_info_wrr_adv( + struct ol_txrx_pdev_t *pdev, + int cat, int *active, + int *frms, int *bytes) +{ + struct ol_tx_sched_wrr_adv_t *scheduler = pdev->tx_sched.scheduler; + struct ol_tx_sched_wrr_adv_category_info_t *category; + + category = &scheduler->categories[cat]; + *active = category->state.active; + *frms = category->state.frms; + *bytes = category->state.bytes; +} + +/** + * ol_tx_sched_wrr_param_update() - update the WRR TX sched params + * @pdev: Pointer to PDEV structure. + * @scheduler: Pointer to tx scheduler. + * + * Update the WRR TX schedule parameters for each category if it is + * specified in the ini file by user. + * + * Return: none + */ +static void ol_tx_sched_wrr_param_update(struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_wrr_adv_t * + scheduler) +{ + int i; + static const char * const tx_sched_wrr_name[4] = { + "BE", + "BK", + "VI", + "VO" + }; + + if (!scheduler) + return; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s: Tuning the TX scheduler wrr parameters by ini file:", + __func__); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " skip credit limit credit disc"); + + for (i = OL_TX_SCHED_WRR_ADV_CAT_BE; + i <= OL_TX_SCHED_WRR_ADV_CAT_VO; i++) { + if (ol_cfg_get_wrr_skip_weight(pdev->ctrl_pdev, i)) { + scheduler->categories[i].specs.wrr_skip_weight = + ol_cfg_get_wrr_skip_weight(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.credit_threshold = + ol_cfg_get_credit_threshold(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.send_limit = + ol_cfg_get_send_limit(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.credit_reserve = + ol_cfg_get_credit_reserve(pdev->ctrl_pdev, i); + scheduler->categories[i].specs.discard_weight = + ol_cfg_get_discard_weight(pdev->ctrl_pdev, i); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s-update: %d, %d, %d, %d, %d", + tx_sched_wrr_name[i], + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.send_limit, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.discard_weight); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "%s-orig: %d, %d, %d, %d, %d", + tx_sched_wrr_name[i], + scheduler->categories[i].specs.wrr_skip_weight, + scheduler->categories[i].specs.credit_threshold, + scheduler->categories[i].specs.send_limit, + scheduler->categories[i].specs.credit_reserve, + scheduler->categories[i].specs.discard_weight); + } + } +} + +static void * +ol_tx_sched_init_wrr_adv( + struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_wrr_adv_t *scheduler; + int i; + + scheduler = qdf_mem_malloc( + sizeof(struct ol_tx_sched_wrr_adv_t)); + if (!scheduler) + return scheduler; + + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VO, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VI, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BE, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BK, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(NON_QOS_DATA, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(UCAST_MGMT, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(MCAST_DATA, scheduler); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(MCAST_MGMT, scheduler); + + ol_tx_sched_wrr_param_update(pdev, scheduler); + + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) { + scheduler->categories[i].state.active = 0; + scheduler->categories[i].state.frms = 0; + /*scheduler->categories[i].state.bytes = 0;*/ + TAILQ_INIT(&scheduler->categories[i].state.head); + /* + * init categories to not be skipped before + * their initial selection + */ + scheduler->categories[i].state.wrr_count = + scheduler->categories[i].specs.wrr_skip_weight - 1; + } + + /* + * Init the order array - the initial ordering doesn't matter, as the + * order array will get reshuffled as data arrives. + */ + for (i = 0; i < OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES; i++) + scheduler->order[i] = i; + + return scheduler; +} + + +/* WMM parameters are suppposed to be passed when associate with AP. + * According to AIFS+CWMin, the function maps each queue to one of four default + * settings of the scheduler, ie. VO, VI, BE, or BK. + */ +void +ol_txrx_set_wmm_param(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct ol_tx_wmm_param_t wmm_param) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle data_pdev = + ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_tx_sched_wrr_adv_t def_cfg; + struct ol_tx_sched_wrr_adv_t *scheduler = + data_pdev->tx_sched.scheduler; + u_int32_t i, ac_selected; + u_int32_t weight[QCA_WLAN_AC_ALL], default_edca[QCA_WLAN_AC_ALL]; + + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VO, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(VI, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BE, (&def_cfg)); + OL_TX_SCHED_WRR_ADV_CAT_CFG_STORE(BK, (&def_cfg)); + + /* default_eca = AIFS + CWMin */ + default_edca[OL_TX_SCHED_WRR_ADV_CAT_VO] = + OL_TX_AIFS_DEFAULT_VO + OL_TX_CW_MIN_DEFAULT_VO; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_VI] = + OL_TX_AIFS_DEFAULT_VI + OL_TX_CW_MIN_DEFAULT_VI; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_BE] = + OL_TX_AIFS_DEFAULT_BE + OL_TX_CW_MIN_DEFAULT_BE; + default_edca[OL_TX_SCHED_WRR_ADV_CAT_BK] = + OL_TX_AIFS_DEFAULT_BK + OL_TX_CW_MIN_DEFAULT_BK; + + weight[OL_TX_SCHED_WRR_ADV_CAT_VO] = + wmm_param.ac[QCA_WLAN_AC_VO].aifs + + wmm_param.ac[QCA_WLAN_AC_VO].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_VI] = + wmm_param.ac[QCA_WLAN_AC_VI].aifs + + wmm_param.ac[QCA_WLAN_AC_VI].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BK] = + wmm_param.ac[QCA_WLAN_AC_BK].aifs + + wmm_param.ac[QCA_WLAN_AC_BK].cwmin; + weight[OL_TX_SCHED_WRR_ADV_CAT_BE] = + wmm_param.ac[QCA_WLAN_AC_BE].aifs + + wmm_param.ac[QCA_WLAN_AC_BE].cwmin; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_VO] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_VO; + else if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_VI] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_VI; + else if (default_edca[OL_TX_SCHED_WRR_ADV_CAT_BE] >= weight[i]) + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_BE; + else + ac_selected = OL_TX_SCHED_WRR_ADV_CAT_BK; + + + scheduler->categories[i].specs.wrr_skip_weight = + def_cfg.categories[ac_selected].specs.wrr_skip_weight; + scheduler->categories[i].specs.credit_threshold = + def_cfg.categories[ac_selected].specs.credit_threshold; + scheduler->categories[i].specs.send_limit = + def_cfg.categories[ac_selected].specs.send_limit; + scheduler->categories[i].specs.credit_reserve = + def_cfg.categories[ac_selected].specs.credit_reserve; + scheduler->categories[i].specs.discard_weight = + def_cfg.categories[ac_selected].specs.discard_weight; + } +} + +/** + * ol_tx_sched_stats_display() - tx sched stats display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_STAT_DUMP(pdev->tx_sched.scheduler); +} + +/** + * ol_tx_sched_cur_state_display() - tx sched cur stat display + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_CUR_STATE_DUMP(pdev->tx_sched.scheduler); +} + +/** + * ol_tx_sched_cur_state_display() - reset tx sched stats + * @pdev: Pointer to the PDEV structure. + * + * Return: none. + */ +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ + OL_TX_SCHED_WRR_ADV_CAT_STAT_CLEAR(pdev->tx_sched.scheduler); +} + +#endif /* OL_TX_SCHED == OL_TX_SCHED_WRR_ADV */ + +/*--- congestion control discard --------------------------------------------*/ + +static struct ol_tx_frms_queue_t * +ol_tx_sched_discard_select_txq( + struct ol_txrx_pdev_t *pdev, + ol_tx_frms_queue_list *tx_queues) +{ + struct ol_tx_frms_queue_t *txq; + struct ol_tx_frms_queue_t *selected_txq = NULL; + int max_frms = 0; + + /* return the tx queue with the most frames */ + TAILQ_FOREACH(txq, tx_queues, list_elem) { + if (txq->frms > max_frms) { + max_frms = txq->frms; + selected_txq = txq; + } + } + return selected_txq; +} + +u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force) +{ + int cat; + struct ol_tx_frms_queue_t *txq; + int bytes; + u_int32_t credit; + struct ol_tx_sched_notify_ctx_t notify_ctx; + + /* + * first decide what category of traffic (e.g. TID or AC) + * to discard next + */ + cat = ol_tx_sched_discard_select_category(pdev); + + /* then decide which peer within this category to discard from next */ + txq = ol_tx_sched_discard_select_txq( + pdev, ol_tx_sched_category_tx_queues(pdev, cat)); + if (!txq) + /* No More pending Tx Packets in Tx Queue. Exit Discard loop */ + return 0; + + + if (force == false) { + /* + * Now decide how many frames to discard from this peer-TID. + * Don't discard more frames than the caller has specified. + * Don't discard more than a fixed quantum of frames at a time. + * Don't discard more than 50% of the queue's frames at a time, + * but if there's only 1 frame left, go ahead and discard it. + */ +#define OL_TX_DISCARD_QUANTUM 10 + if (OL_TX_DISCARD_QUANTUM < frms) + frms = OL_TX_DISCARD_QUANTUM; + + + if (txq->frms > 1 && frms >= (txq->frms >> 1)) + frms = txq->frms >> 1; + } + + /* + * Discard from the head of the queue, because: + * 1. Front-dropping gives applications like TCP that include ARQ + * an early notification of congestion. + * 2. For time-sensitive applications like RTP, the newest frames are + * most relevant. + */ + credit = 10000; /* no credit limit */ + frms = ol_tx_dequeue(pdev, txq, tx_descs, frms, &credit, &bytes); + + notify_ctx.event = OL_TX_DISCARD_FRAMES; + notify_ctx.frames = frms; + notify_ctx.bytes = bytes; + notify_ctx.txq = txq; + notify_ctx.info.ext_tid = cat; + ol_tx_sched_notify(pdev, ¬ify_ctx); + + TX_SCHED_DEBUG_PRINT("Tx Drop : %d", frms); + return frms; +} + +/*--- scheduler framework ---------------------------------------------------*/ + +/* + * The scheduler mutex spinlock has been acquired outside this function, + * so there is need to take locks inside this function. + */ +void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx) +{ + struct ol_tx_frms_queue_t *txq = ctx->txq; + int tid; + + if (!pdev->tx_sched.scheduler) + return; + + switch (ctx->event) { + case OL_TX_ENQUEUE_FRAME: + tid = ctx->info.tx_msdu_info->htt.info.ext_tid; + ol_tx_sched_txq_enqueue(pdev, txq, tid, 1, ctx->bytes); + break; + case OL_TX_DELETE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->flag == ol_tx_queue_active) + ol_tx_sched_txq_deactivate(pdev, txq, tid); + + break; + case OL_TX_PAUSE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->flag == ol_tx_queue_active) + ol_tx_sched_txq_deactivate(pdev, txq, tid); + + break; + case OL_TX_UNPAUSE_QUEUE: + tid = ctx->info.ext_tid; + if (txq->frms != 0) + ol_tx_sched_txq_enqueue(pdev, txq, tid, + txq->frms, txq->bytes); + + break; + case OL_TX_DISCARD_FRAMES: + /* not necessarily TID, could be category */ + tid = ctx->info.ext_tid; + ol_tx_sched_txq_discard(pdev, txq, tid, + ctx->frames, ctx->bytes); + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Error: unknown sched notification (%d)\n", + ctx->event); + qdf_assert(0); + break; + } +} + +#define OL_TX_MSDU_ID_STORAGE_ERR(ptr) (!ptr) + +static void +ol_tx_sched_dispatch( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_ctx *sctx) +{ + qdf_nbuf_t msdu, prev = NULL, head_msdu = NULL; + struct ol_tx_desc_t *tx_desc; + u_int16_t *msdu_id_storage; + u_int16_t msdu_id; + int num_msdus = 0; + + TX_SCHED_DEBUG_PRINT("Enter"); + while (sctx->frms) { + tx_desc = TAILQ_FIRST(&sctx->head); + if (!tx_desc) { + /* TODO: find its reason */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: err, no enough tx_desc from stx->head.\n", + __func__); + break; + } + msdu = tx_desc->netbuf; + TAILQ_REMOVE(&sctx->head, tx_desc, tx_desc_list_elem); + if (!head_msdu) + head_msdu = msdu; + + if (prev) + qdf_nbuf_set_next(prev, msdu); + + prev = msdu; + +#ifndef ATH_11AC_TXCOMPACT + /* + * When the tx frame is downloaded to the target, there are two + * outstanding references: + * 1. The host download SW (HTT, HTC, HIF) + * This reference is cleared by the ol_tx_send_done callback + * functions. + * 2. The target FW + * This reference is cleared by the ol_tx_completion_handler + * function. + * It is extremely probable that the download completion is + * processed before the tx completion message. However, under + * exceptional conditions the tx completion may be processed + *first. Thus, rather that assuming that reference (1) is + *done before reference (2), + * explicit reference tracking is needed. + * Double-increment the ref count to account for both references + * described above. + */ + qdf_atomic_init(&tx_desc->ref_cnt); + qdf_atomic_inc(&tx_desc->ref_cnt); + qdf_atomic_inc(&tx_desc->ref_cnt); +#endif + + /*Store the MSDU Id for each MSDU*/ + /* store MSDU ID */ + msdu_id = ol_tx_desc_id(pdev, tx_desc); + msdu_id_storage = ol_tx_msdu_id_storage(msdu); + if (OL_TX_MSDU_ID_STORAGE_ERR(msdu_id_storage)) { + /* + * Send the prior frames as a batch, + *then send this as a single, + * then resume handling the remaining frames. + */ + if (head_msdu) + ol_tx_send_batch(pdev, head_msdu, num_msdus); + + prev = NULL; + head_msdu = prev; + num_msdus = 0; + + if (htt_tx_send_std(pdev->htt_pdev, msdu, msdu_id)) { + ol_tx_target_credit_incr(pdev, msdu); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + 1 /* error */); + } + } else { + *msdu_id_storage = msdu_id; + num_msdus++; + } + sctx->frms--; + } + + /*Send Batch Of Frames*/ + if (head_msdu) + ol_tx_send_batch(pdev, head_msdu, num_msdus); + TX_SCHED_DEBUG_PRINT("Leave"); +} + +#ifdef QCA_TX_PADDING_CREDIT_SUPPORT +static void replenish_tx_pad_credit(struct ol_txrx_pdev_t *pdev) +{ + int replenish_credit = 0, avail_targ_tx_credit = 0; + int cur_tx_pad_credit = 0, grp_credit = 0, i = 0; + qdf_atomic_t *tx_grp_credit = NULL; + + cur_tx_pad_credit = qdf_atomic_read(&pdev->pad_reserve_tx_credit); + if (cur_tx_pad_credit < MIN_TX_PAD_CREDIT_THRESH) { + replenish_credit = MAX_TX_PAD_CREDIT_THRESH - cur_tx_pad_credit; + avail_targ_tx_credit = qdf_atomic_read(&pdev->target_tx_credit); + replenish_credit = (replenish_credit < avail_targ_tx_credit) ? + replenish_credit : avail_targ_tx_credit; + if (replenish_credit < 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "Tx Pad Credits = %d Target Tx Credits = %d", + cur_tx_pad_credit, + avail_targ_tx_credit); + qdf_assert(0); + } + qdf_atomic_add(replenish_credit, &pdev->pad_reserve_tx_credit); + qdf_atomic_add(-replenish_credit, &pdev->target_tx_credit); + + while (replenish_credit > 0) { + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + tx_grp_credit = &pdev->txq_grps[i].credit; + grp_credit = qdf_atomic_read(tx_grp_credit); + if (grp_credit) { + qdf_atomic_add(-1, tx_grp_credit); + replenish_credit--; + } + if (!replenish_credit) + break; + } + } + } +} +#else +static void replenish_tx_pad_credit(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +void +ol_tx_sched(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_sched_ctx sctx; + u_int32_t credit; + + TX_SCHED_DEBUG_PRINT("Enter"); + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + if (pdev->tx_sched.tx_sched_status != ol_tx_scheduler_idle) { + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + return; + } + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_running; + + ol_tx_sched_log(pdev); + /* + *adf_os_print("BEFORE tx sched:\n"); + *ol_tx_queues_display(pdev); + */ + replenish_tx_pad_credit(pdev); + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + TAILQ_INIT(&sctx.head); + sctx.frms = 0; + + ol_tx_sched_select_init(pdev); + while (qdf_atomic_read(&pdev->target_tx_credit) > 0) { + int num_credits; + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + replenish_tx_pad_credit(pdev); + credit = qdf_atomic_read(&pdev->target_tx_credit); + num_credits = ol_tx_sched_select_batch(pdev, &sctx, credit); + if (num_credits > 0) { +#if DEBUG_HTT_CREDIT + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " Decrease credit %d - %d = %d.\n", + qdf_atomic_read(&pdev->target_tx_credit), + num_credits, + qdf_atomic_read(&pdev->target_tx_credit) - + num_credits); +#endif + DPTRACE(qdf_dp_trace_credit_record(QDF_TX_SCHED, + QDF_CREDIT_DEC, num_credits, + qdf_atomic_read(&pdev->target_tx_credit) - + num_credits, + qdf_atomic_read(&pdev->txq_grps[0].credit), + qdf_atomic_read(&pdev->txq_grps[1].credit))); + + qdf_atomic_add(-num_credits, &pdev->target_tx_credit); + } + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + + if (num_credits == 0) + break; + } + ol_tx_sched_dispatch(pdev, &sctx); + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + /* + *adf_os_print("AFTER tx sched:\n"); + *ol_tx_queues_display(pdev); + */ + + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_idle; + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void * +ol_tx_sched_attach( + struct ol_txrx_pdev_t *pdev) +{ + pdev->tx_sched.tx_sched_status = ol_tx_scheduler_idle; + return ol_tx_sched_init(pdev); +} + +void +ol_tx_sched_detach( + struct ol_txrx_pdev_t *pdev) +{ + if (pdev->tx_sched.scheduler) { + qdf_mem_free(pdev->tx_sched.scheduler); + pdev->tx_sched.scheduler = NULL; + } +} + +/*--- debug functions -------------------------------------------------------*/ + +#if defined(DEBUG_HL_LOGGING) + +static void +ol_tx_sched_log(struct ol_txrx_pdev_t *pdev) +{ + u_int8_t *buf; + u_int32_t *active_bitmap; + int i, j, num_cats_active; + int active, frms, bytes; + int credit; + + /* don't bother recording state if credit is zero */ + credit = qdf_atomic_read(&pdev->target_tx_credit); + if (credit == 0) + return; + + + /* + * See how many TIDs are active, so queue state can be stored only + * for those TIDs. + * Do an initial iteration through all categories to see if any + * are active. Doing an extra iteration is inefficient, but + * efficiency is not a dominant concern when logging is enabled. + */ + num_cats_active = 0; + for (i = 0; i < OL_TX_SCHED_NUM_CATEGORIES; i++) { + ol_tx_sched_category_info(pdev, i, &active, &frms, &bytes); + if (active) + num_cats_active++; + } + /* don't bother recording state if there are no active queues */ + if (num_cats_active == 0) + return; + + + ol_tx_queue_log_sched(pdev, credit, &num_cats_active, + &active_bitmap, &buf); + + if (num_cats_active == 0) + return; + + *active_bitmap = 0; + for (i = 0, j = 0; + i < OL_TX_SCHED_NUM_CATEGORIES && j < num_cats_active; + i++) { + u_int8_t *p; + + ol_tx_sched_category_info(pdev, i, &active, &frms, &bytes); + if (!active) + continue; + + p = &buf[j*6]; + p[0] = (frms >> 0) & 0xff; + p[1] = (frms >> 8) & 0xff; + + p[2] = (bytes >> 0) & 0xff; + p[3] = (bytes >> 8) & 0xff; + p[4] = (bytes >> 16) & 0xff; + p[5] = (bytes >> 24) & 0xff; + j++; + *active_bitmap |= 1 << i; + } +} + +#endif /* defined(DEBUG_HL_LOGGING) */ + +#endif /* defined(CONFIG_HL_SUPPORT) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_sched.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_sched.h new file mode 100644 index 0000000000..51987d701b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_sched.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2012-2013, 2016-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_tx_sched.h + * @brief API definitions for the tx scheduler module within the data SW. + */ +#ifndef _OL_TX_SCHED__H_ +#define _OL_TX_SCHED__H_ + +#include + +enum ol_tx_queue_action { + OL_TX_ENQUEUE_FRAME, + OL_TX_DELETE_QUEUE, + OL_TX_PAUSE_QUEUE, + OL_TX_UNPAUSE_QUEUE, + OL_TX_DISCARD_FRAMES, +}; + +struct ol_tx_sched_notify_ctx_t { + int event; + struct ol_tx_frms_queue_t *txq; + union { + int ext_tid; + struct ol_txrx_msdu_info_t *tx_msdu_info; + } info; + int frames; + int bytes; +}; + +#if defined(CONFIG_HL_SUPPORT) + +void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx); + +void +ol_tx_sched(struct ol_txrx_pdev_t *pdev); + +u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force); + +void * +ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev); + +void +ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev); + +void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev); + +void +ol_txrx_set_wmm_param(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct ol_tx_wmm_param_t wmm_param); + +#else + +static inline void +ol_tx_sched_notify( + struct ol_txrx_pdev_t *pdev, + struct ol_tx_sched_notify_ctx_t *ctx) +{ +} + +static inline void +ol_tx_sched(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline u_int16_t +ol_tx_sched_discard_select( + struct ol_txrx_pdev_t *pdev, + u_int16_t frms, + ol_tx_desc_list *tx_descs, + bool force) +{ + return 0; +} + +static inline void * +ol_tx_sched_attach(struct ol_txrx_pdev_t *pdev) +{ + return NULL; +} + +static inline void +ol_tx_sched_detach(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline void ol_tx_sched_stats_display(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline void ol_tx_sched_cur_state_display(struct ol_txrx_pdev_t *pdev) +{ +} + +static inline void ol_tx_sched_stats_clear(struct ol_txrx_pdev_t *pdev) +{ +} + +#endif /* defined(CONFIG_HL_SUPPORT) */ + +#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT) +/* + * HL needs to keep track of the amount of credit available to download + * tx frames to the target - the download scheduler decides when to + * download frames, and which frames to download, based on the credit + * availability. + * LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track + * of the target_tx_credit, to determine when to poll for tx completion + * messages. + */ + +static inline void +ol_tx_target_credit_adjust(int factor, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + qdf_atomic_add(factor * htt_tx_msdu_credit(msdu), + &pdev->target_tx_credit); +} + +static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + ol_tx_target_credit_adjust(-1, pdev, msdu); +} + +static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ + ol_tx_target_credit_adjust(1, pdev, msdu); +} + +#ifdef QCA_TX_PADDING_CREDIT_SUPPORT + +#define MIN_TX_PAD_CREDIT_THRESH 4 +#define MAX_TX_PAD_CREDIT_THRESH 5 + +#endif /* QCA_TX_PADDING_CREDIT_SUPPORT */ + +#else +/* + * LL does not need to keep track of target credit. + * Since the host tx descriptor pool size matches the target's, + * we know the target has space for the new tx frame if the host's + * tx descriptor allocation succeeded. + */ +static inline void +ol_tx_target_credit_adjust(int factor, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ +} + +static inline void ol_tx_target_credit_decr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ +} + +static inline void ol_tx_target_credit_incr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu) +{ +} + +#endif +#endif /* _OL_TX_SCHED__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_send.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_send.c new file mode 100644 index 0000000000..80df08a321 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_send.c @@ -0,0 +1,1865 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include /* qdf_atomic_inc, etc. */ +#include /* qdf_os_spinlock */ +#include /* qdf_system_ticks, etc. */ +#include /* qdf_nbuf_t */ +#include /* QDF_NBUF_TX_EXT_TID_INVALID */ + +#include "queue.h" /* TAILQ */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ethernet_hdr_t, etc. */ +#include /* ipv6_traffic_class */ +#endif + +#include /* ol_txrx_vdev_handle, etc. */ +#include /* htt_tx_compl_desc_id */ +#include /* htt_tx_status */ + +#include +#include +#include /* ol_txrx_vdev_t, etc */ +#include /* ol_tx_desc_find, ol_tx_desc_frame_free */ +#ifdef QCA_COMPUTE_TX_DELAY +#include /* ol_tx_dest_addr_find */ +#endif +#include /* OL_TX_DESC_NO_REFS, etc. */ +#include +#include /* ol_tx_reinject */ +#include + +#include /* ol_cfg_is_high_latency */ +#include +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP +#include /* OL_TX_RESTORE_HDR, etc */ +#endif +#include +#include +#include +#include +#include +#include +#ifdef TX_CREDIT_RECLAIM_SUPPORT + +#define OL_TX_CREDIT_RECLAIM(pdev) \ + do { \ + if (qdf_atomic_read(&pdev->target_tx_credit) < \ + ol_cfg_tx_credit_lwm(pdev->ctrl_pdev)) { \ + ol_osif_ath_tasklet(pdev->osdev); \ + } \ + } while (0) + +#else + +#define OL_TX_CREDIT_RECLAIM(pdev) + +#endif /* TX_CREDIT_RECLAIM_SUPPORT */ + +#if defined(CONFIG_HL_SUPPORT) || defined(TX_CREDIT_RECLAIM_SUPPORT) + +/* + * HL needs to keep track of the amount of credit available to download + * tx frames to the target - the download scheduler decides when to + * download frames, and which frames to download, based on the credit + * availability. + * LL systems that use TX_CREDIT_RECLAIM_SUPPORT also need to keep track + * of the target_tx_credit, to determine when to poll for tx completion + * messages. + */ +static inline void +ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + qdf_atomic_add(-1 * delta, &pdev->target_tx_credit); +} + +static inline void +ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ + qdf_atomic_add(delta, &pdev->target_tx_credit); +} +#else + +static inline void +ol_tx_target_credit_decr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ +} + +static inline void +ol_tx_target_credit_incr_int(struct ol_txrx_pdev_t *pdev, int delta) +{ +} +#endif + +#ifdef DESC_TIMESTAMP_DEBUG_INFO +static inline void ol_tx_desc_update_comp_ts(struct ol_tx_desc_t *tx_desc) +{ + tx_desc->desc_debug_info.last_comp_ts = qdf_get_log_timestamp(); +} +#else +static inline void ol_tx_desc_update_comp_ts(struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_HL_NETDEV_FLOW_CONTROL) +void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + bool trigger_unpause = false; + + qdf_spin_lock_bh(&pdev->tx_mutex); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->tx_desc_limit == 0) + continue; + + /* un-pause high priority queue */ + if (vdev->prio_q_paused && + (qdf_atomic_read(&vdev->tx_desc_count) + < vdev->tx_desc_limit)) { + pdev->pause_cb(vdev->vdev_id, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + vdev->prio_q_paused = 0; + } + /* un-pause non priority queues */ + if (qdf_atomic_read(&vdev->os_q_paused) && + (qdf_atomic_read(&vdev->tx_desc_count) + <= vdev->queue_restart_th)) { + pdev->pause_cb(vdev->vdev_id, + WLAN_WAKE_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + qdf_atomic_set(&vdev->os_q_paused, 0); + trigger_unpause = true; + } + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + if (trigger_unpause) + ol_tx_hl_pdev_queue_send_all(pdev); +} +#endif + +static inline uint16_t +ol_tx_send_base(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t msdu) +{ + int msdu_credit_consumed; + + TX_CREDIT_DEBUG_PRINT("TX %d bytes\n", qdf_nbuf_len(msdu)); + TX_CREDIT_DEBUG_PRINT(" Decrease credit %d - 1 = %d, len:%d.\n", + qdf_atomic_read(&pdev->target_tx_credit), + qdf_atomic_read(&pdev->target_tx_credit) - 1, + qdf_nbuf_len(msdu)); + + msdu_credit_consumed = htt_tx_msdu_credit(msdu); + ol_tx_target_credit_decr_int(pdev, msdu_credit_consumed); + OL_TX_CREDIT_RECLAIM(pdev); + + /* + * When the tx frame is downloaded to the target, there are two + * outstanding references: + * 1. The host download SW (HTT, HTC, HIF) + * This reference is cleared by the ol_tx_send_done callback + * functions. + * 2. The target FW + * This reference is cleared by the ol_tx_completion_handler + * function. + * It is extremely probable that the download completion is processed + * before the tx completion message. However, under exceptional + * conditions the tx completion may be processed first. Thus, rather + * that assuming that reference (1) is done before reference (2), + * explicit reference tracking is needed. + * Double-increment the ref count to account for both references + * described above. + */ + + OL_TX_DESC_REF_INIT(tx_desc); + OL_TX_DESC_REF_INC(tx_desc); + OL_TX_DESC_REF_INC(tx_desc); + + return msdu_credit_consumed; +} + +void +ol_tx_send(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t msdu, uint8_t vdev_id) +{ + int msdu_credit_consumed; + uint16_t id; + int failed; + + msdu_credit_consumed = ol_tx_send_base(pdev, tx_desc, msdu); + id = ol_tx_desc_id(pdev, tx_desc); + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_TXRX); + DPTRACE(qdf_dp_trace_ptr(msdu, QDF_DP_TRACE_TXRX_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), tx_desc->id, + vdev_id, 0, + tx_desc->vdev->qdf_opmode + )); + failed = htt_tx_send_std(pdev->htt_pdev, msdu, id); + if (qdf_unlikely(failed)) { + ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + } +} + +void +ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t head_msdu, int num_msdus) +{ + qdf_nbuf_t rejected; + + OL_TX_CREDIT_RECLAIM(pdev); + + rejected = htt_tx_send_batch(pdev->htt_pdev, head_msdu, num_msdus); + while (qdf_unlikely(rejected)) { + struct ol_tx_desc_t *tx_desc; + uint16_t *msdu_id_storage; + qdf_nbuf_t next; + + next = qdf_nbuf_next(rejected); + msdu_id_storage = ol_tx_msdu_id_storage(rejected); + tx_desc = ol_tx_desc_find(pdev, *msdu_id_storage); + + ol_tx_target_credit_incr(pdev, rejected); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + + rejected = next; + } +} + +void +ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, enum htt_pkt_type pkt_type) +{ + int msdu_credit_consumed; + uint16_t id; + int failed; + + msdu_credit_consumed = ol_tx_send_base(pdev, tx_desc, msdu); + id = ol_tx_desc_id(pdev, tx_desc); + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu, QDF_NBUF_TX_PKT_TXRX); + failed = htt_tx_send_nonstd(pdev->htt_pdev, msdu, id, pkt_type); + if (failed) { + ol_txrx_err( + "Error: freeing tx frame after htt_tx failed"); + ol_tx_target_credit_incr_int(pdev, msdu_credit_consumed); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1 /* had error */); + } +} + +static inline bool +ol_tx_download_done_base(struct ol_txrx_pdev_t *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_tx_desc_t *tx_desc; + bool is_frame_freed = false; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + qdf_assert(tx_desc); + + /* + * If the download is done for + * the Management frame then + * call the download callback if registered + */ + if (tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) { + ol_txrx_mgmt_tx_cb download_cb = + pdev->tx_mgmt_cb.download_cb; + if (download_cb) { + download_cb(pdev->tx_mgmt_cb.ctxt, + tx_desc->netbuf, status != A_OK); + } + } + + if (status != A_OK) { + ol_tx_target_credit_incr(pdev, msdu); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + 1 /* download err */); + is_frame_freed = true; + } else { + if (OL_TX_DESC_NO_REFS(tx_desc)) { + /* + * The decremented value was zero - free the frame. + * Use the tx status recorded previously during + * tx completion handling. + */ + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + tx_desc->status != + htt_tx_status_ok); + is_frame_freed = true; + } + } + return is_frame_freed; +} + +void +ol_tx_download_done_ll(void *pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + ol_tx_download_done_base((struct ol_txrx_pdev_t *)pdev, status, msdu, + msdu_id); +} + +void +ol_tx_download_done_hl_retain(void *txrx_pdev, + A_STATUS status, + qdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_txrx_pdev_t *pdev = txrx_pdev; + + ol_tx_download_done_base(pdev, status, msdu, msdu_id); +} + +void +ol_tx_download_done_hl_free(void *txrx_pdev, + A_STATUS status, qdf_nbuf_t msdu, uint16_t msdu_id) +{ + struct ol_txrx_pdev_t *pdev = txrx_pdev; + struct ol_tx_desc_t *tx_desc; + bool is_frame_freed; + uint8_t dp_status; + + tx_desc = ol_tx_desc_find(pdev, msdu_id); + qdf_assert(tx_desc); + dp_status = qdf_dp_get_status_from_a_status(status); + DPTRACE(qdf_dp_trace_ptr(msdu, + QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu), + sizeof(qdf_nbuf_data(msdu)), tx_desc->id, + dp_status, 0, + tx_desc->vdev->qdf_opmode + )); + + is_frame_freed = ol_tx_download_done_base(pdev, status, msdu, msdu_id); + + /* + * if frame is freed in ol_tx_download_done_base then return. + */ + if (is_frame_freed) { + qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + return; + } + + if ((tx_desc->pkt_type != OL_TX_FRM_NO_FREE) && + (tx_desc->pkt_type < OL_TXRX_MGMT_TYPE_BASE)) { + qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, status != A_OK); + } +} + +void ol_tx_target_credit_init(struct ol_txrx_pdev_t *pdev, int credit_delta) +{ + qdf_atomic_add(credit_delta, &pdev->orig_target_tx_credit); +} + +void ol_tx_target_credit_update(struct ol_txrx_pdev_t *pdev, int credit_delta) +{ + TX_CREDIT_DEBUG_PRINT(" Increase credit %d + %d = %d\n", + qdf_atomic_read(&pdev->target_tx_credit), + credit_delta, + qdf_atomic_read(&pdev->target_tx_credit) + + credit_delta); + qdf_atomic_add(credit_delta, &pdev->target_tx_credit); +} + +#ifdef QCA_COMPUTE_TX_DELAY + +static void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus); + +#else +static inline void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus) +{ +} +#endif /* QCA_COMPUTE_TX_DELAY */ + +#if defined(CONFIG_HL_SUPPORT) +int ol_tx_deduct_one_credit(struct ol_txrx_pdev_t *pdev) +{ + /* TODO: Check if enough credits */ + + if (!pdev->cfg.default_tx_comp_req) { + ol_tx_target_credit_update(pdev, -1); + ol_tx_deduct_one_any_group_credit(pdev); + + DPTRACE(qdf_dp_trace_credit_record(QDF_TX_HTT_MSG, + QDF_CREDIT_DEC, 1, + qdf_atomic_read(&pdev->target_tx_credit), + qdf_atomic_read(&pdev->txq_grps[0].credit), + qdf_atomic_read(&pdev->txq_grps[1].credit))); + } + + return 0; +} +#endif /* CONFIG_HL_SUPPORT */ + +#ifndef OL_TX_RESTORE_HDR +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) +#endif +/* + * The following macros could have been inline functions too. + * The only rationale for choosing macros, is to force the compiler to inline + * the implementation, which cannot be controlled for actual "inline" functions, + * since "inline" is only a hint to the compiler. + * In the performance path, we choose to force the inlining, in preference to + * type-checking offered by the actual inlined functions. + */ +#define ol_tx_msdu_complete_batch(_pdev, _tx_desc, _tx_descs, _status) \ + TAILQ_INSERT_TAIL(&(_tx_descs), (_tx_desc), tx_desc_list_elem) +#ifndef ATH_11AC_TXCOMPACT +#define ol_tx_msdu_complete_single(_pdev, _tx_desc, _netbuf,\ + _lcl_freelist, _tx_desc_last) \ + do { \ + qdf_atomic_init(&(_tx_desc)->ref_cnt); \ + /* restore original hdr offset */ \ + OL_TX_RESTORE_HDR((_tx_desc), (_netbuf)); \ + qdf_nbuf_unmap((_pdev)->osdev, (_netbuf), QDF_DMA_TO_DEVICE); \ + qdf_nbuf_free((_netbuf)); \ + ((union ol_tx_desc_list_elem_t *)(_tx_desc))->next = \ + (_lcl_freelist); \ + if (qdf_unlikely(!lcl_freelist)) { \ + (_tx_desc_last) = (union ol_tx_desc_list_elem_t *)\ + (_tx_desc); \ + } \ + (_lcl_freelist) = (union ol_tx_desc_list_elem_t *)(_tx_desc); \ + } while (0) +#else /*!ATH_11AC_TXCOMPACT */ +#define ol_tx_msdu_complete_single(_pdev, _tx_desc, _netbuf,\ + _lcl_freelist, _tx_desc_last) \ + do { \ + /* restore original hdr offset */ \ + OL_TX_RESTORE_HDR((_tx_desc), (_netbuf)); \ + qdf_nbuf_unmap((_pdev)->osdev, (_netbuf), QDF_DMA_TO_DEVICE); \ + qdf_nbuf_free((_netbuf)); \ + ((union ol_tx_desc_list_elem_t *)(_tx_desc))->next = \ + (_lcl_freelist); \ + if (qdf_unlikely(!lcl_freelist)) { \ + (_tx_desc_last) = (union ol_tx_desc_list_elem_t *)\ + (_tx_desc); \ + } \ + (_lcl_freelist) = (union ol_tx_desc_list_elem_t *)(_tx_desc); \ + } while (0) + +#endif /*!ATH_11AC_TXCOMPACT */ + +#ifdef QCA_TX_SINGLE_COMPLETIONS +#ifdef QCA_TX_STD_PATH_ONLY +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status, is_tx_desc_freed) \ + { \ + is_tx_desc_freed = 0; \ + ol_tx_msdu_complete_single((_pdev), (_tx_desc), \ + (_netbuf), (_lcl_freelist), \ + _tx_desc_last) \ + } +#else /* !QCA_TX_STD_PATH_ONLY */ +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status, is_tx_desc_freed) \ + do { \ + if (qdf_likely((_tx_desc)->pkt_type == OL_TX_FRM_STD)) { \ + is_tx_desc_freed = 0; \ + ol_tx_msdu_complete_single((_pdev), (_tx_desc),\ + (_netbuf), (_lcl_freelist), \ + (_tx_desc_last)); \ + } else { \ + is_tx_desc_freed = 1; \ + ol_tx_desc_frame_free_nonstd( \ + (_pdev), (_tx_desc), \ + (_status) != htt_tx_status_ok); \ + } \ + } while (0) +#endif /* !QCA_TX_STD_PATH_ONLY */ +#else /* !QCA_TX_SINGLE_COMPLETIONS */ +#ifdef QCA_TX_STD_PATH_ONLY +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status, is_tx_desc_freed) \ + { \ + is_tx_desc_freed = 0; \ + ol_tx_msdu_complete_batch((_pdev), (_tx_desc), \ + (_tx_descs), (_status)) \ + } +#else /* !QCA_TX_STD_PATH_ONLY */ +#define ol_tx_msdu_complete(_pdev, _tx_desc, _tx_descs, \ + _netbuf, _lcl_freelist, \ + _tx_desc_last, _status, is_tx_desc_freed) \ + do { \ + if (qdf_likely((_tx_desc)->pkt_type == OL_TX_FRM_STD)) { \ + is_tx_desc_freed = 0; \ + ol_tx_msdu_complete_batch((_pdev), (_tx_desc), \ + (_tx_descs), (_status)); \ + } else { \ + is_tx_desc_freed = 1; \ + ol_tx_desc_frame_free_nonstd((_pdev), (_tx_desc), \ + (_status) != \ + htt_tx_status_ok); \ + } \ + } while (0) +#endif /* !QCA_TX_STD_PATH_ONLY */ +#endif /* QCA_TX_SINGLE_COMPLETIONS */ + +#if !defined(CONFIG_HL_SUPPORT) +void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) +{ + int i = 0; + struct ol_tx_desc_t *tx_desc; + int num_disarded = 0; + + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + /* + * Confirm that each tx descriptor is "empty", i.e. it has + * no tx frame attached. + * In particular, check that there are no frames that have + * been given to the target to transmit, for which the + * target has never provided a response. + */ + if (qdf_atomic_read(&tx_desc->ref_cnt)) { + ol_txrx_dbg( + "Warning: freeing tx desc %d", tx_desc->id); + ol_tx_desc_frame_free_nonstd(pdev, + tx_desc, 1); + num_disarded++; + } + } + + if (num_disarded) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "Warning: freed %d tx descs for which no tx completion rcvd from the target", + num_disarded); +} +#endif + +void ol_tx_credit_completion_handler(ol_txrx_pdev_handle pdev, int credits) +{ + ol_tx_target_credit_update(pdev, credits); + + if (pdev->cfg.is_high_latency) + ol_tx_sched(pdev); + + /* UNPAUSE OS Q */ + ol_tx_flow_ct_unpause_os_q(pdev); +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_tx_flow_pool_lock() - take flow pool lock + * @tx_desc: tx desc + * + * Return: None + */ +static inline +void ol_tx_flow_pool_lock(struct ol_tx_desc_t *tx_desc) +{ + struct ol_tx_flow_pool_t *pool; + + pool = tx_desc->pool; + qdf_spin_lock_bh(&pool->flow_pool_lock); +} + +/** + * ol_tx_flow_pool_unlock() - release flow pool lock + * @tx_desc: tx desc + * + * Return: None + */ +static inline +void ol_tx_flow_pool_unlock(struct ol_tx_desc_t *tx_desc) +{ + struct ol_tx_flow_pool_t *pool; + + pool = tx_desc->pool; + qdf_spin_unlock_bh(&pool->flow_pool_lock); +} +#else +static inline +void ol_tx_flow_pool_lock(struct ol_tx_desc_t *tx_desc) +{ +} + +static inline +void ol_tx_flow_pool_unlock(struct ol_tx_desc_t *tx_desc) +{ +} +#endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE +#define RESERVE_BYTES 100 +/** + * ol_tx_pkt_capture_tx_completion_process(): process tx packets + * for pkt capture mode + * @pdev: device handler + * @tx_desc: tx desc + * @payload: tx data header + * @tid: tid number + * @status: Tx status + * + * Return: none + */ +static void +ol_tx_pkt_capture_tx_completion_process( + ol_txrx_pdev_handle pdev, + struct ol_tx_desc_t *tx_desc, + struct htt_tx_data_hdr_information *payload_hdr, + uint8_t tid, uint8_t status) +{ + qdf_nbuf_t netbuf; + int nbuf_len; + struct qdf_tso_seg_elem_t *tso_seg = NULL; + struct ol_txrx_peer_t *peer; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t pkt_type = 0; + + qdf_assert(tx_desc); + + ol_tx_flow_pool_lock(tx_desc); + /* + * In cases when vdev has gone down and tx completion + * are received, leads to NULL vdev access. + * So, check for NULL before dereferencing it. + */ + if (!tx_desc->vdev) { + ol_tx_flow_pool_unlock(tx_desc); + return; + } + + ol_tx_flow_pool_unlock(tx_desc); + + if (tx_desc->pkt_type == OL_TX_FRM_TSO) { + if (!tx_desc->tso_desc) + return; + + tso_seg = tx_desc->tso_desc; + nbuf_len = tso_seg->seg.total_len; + } else { + int i, extra_frag_len = 0; + + i = QDF_NBUF_CB_TX_NUM_EXTRA_FRAGS(tx_desc->netbuf); + if (i > 0) + extra_frag_len = + QDF_NBUF_CB_TX_EXTRA_FRAG_LEN(tx_desc->netbuf); + nbuf_len = qdf_nbuf_len(tx_desc->netbuf) - extra_frag_len; + } + + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + peer = TAILQ_FIRST(&tx_desc->vdev->peer_list); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + if (!peer) + return; + + qdf_spin_lock_bh(&peer->peer_info_lock); + qdf_mem_copy(bssid, &peer->mac_addr.raw, QDF_MAC_ADDR_SIZE); + qdf_spin_unlock_bh(&peer->peer_info_lock); + + netbuf = qdf_nbuf_alloc(NULL, + roundup(nbuf_len + RESERVE_BYTES, 4), + RESERVE_BYTES, 4, false); + if (!netbuf) + return; + + qdf_nbuf_put_tail(netbuf, nbuf_len); + + if (tx_desc->pkt_type == OL_TX_FRM_TSO) { + uint8_t frag_cnt, num_frags = 0; + int frag_len = 0; + uint32_t tcp_seq_num; + uint16_t ip_len; + + qdf_spin_lock_bh(&pdev->tso_seg_pool.tso_mutex); + + if (tso_seg->seg.num_frags > 0) + num_frags = tso_seg->seg.num_frags - 1; + + /*Num of frags in a tso seg cannot be less than 2 */ + if (num_frags < 1) { + qdf_print("ERROR: num of frags in tso segment is %d\n", + (num_frags + 1)); + qdf_nbuf_free(netbuf); + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + return; + } + + tcp_seq_num = tso_seg->seg.tso_flags.tcp_seq_num; + tcp_seq_num = qdf_cpu_to_be32(tcp_seq_num); + + ip_len = tso_seg->seg.tso_flags.ip_len; + ip_len = qdf_cpu_to_be16(ip_len); + + for (frag_cnt = 0; frag_cnt <= num_frags; frag_cnt++) { + qdf_mem_copy(qdf_nbuf_data(netbuf) + frag_len, + tso_seg->seg.tso_frags[frag_cnt].vaddr, + tso_seg->seg.tso_frags[frag_cnt].length); + frag_len += tso_seg->seg.tso_frags[frag_cnt].length; + } + + qdf_spin_unlock_bh(&pdev->tso_seg_pool.tso_mutex); + + qdf_mem_copy((qdf_nbuf_data(netbuf) + IPV4_PKT_LEN_OFFSET), + &ip_len, sizeof(ip_len)); + qdf_mem_copy((qdf_nbuf_data(netbuf) + IPV4_TCP_SEQ_NUM_OFFSET), + &tcp_seq_num, sizeof(tcp_seq_num)); + } else { + qdf_mem_copy(qdf_nbuf_data(netbuf), + qdf_nbuf_data(tx_desc->netbuf), + nbuf_len); + } + + qdf_nbuf_push_head( + netbuf, + sizeof(struct htt_tx_data_hdr_information)); + qdf_mem_copy(qdf_nbuf_data(netbuf), payload_hdr, + sizeof(struct htt_tx_data_hdr_information)); + + ucfg_pkt_capture_tx_completion_process( + tx_desc->vdev_id, + netbuf, pkt_type, + tid, status, + TXRX_PKTCAPTURE_PKT_FORMAT_8023, bssid, + pdev->htt_pdev, payload_hdr->tx_retry_cnt); +} +#else +static void +ol_tx_pkt_capture_tx_completion_process( + ol_txrx_pdev_handle pdev, + struct ol_tx_desc_t *tx_desc, + struct htt_tx_data_hdr_information *payload_hdr, + uint8_t tid, uint8_t status) +{ +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +static inline struct htt_tx_compl_ind_append_tx_tstamp *ol_tx_get_txtstamps( + u_int32_t *msg_word_header, u_int32_t **msg_word_payload, + int num_msdus) +{ + u_int32_t has_tx_tsf; + u_int32_t has_retry; + + struct htt_tx_compl_ind_append_tx_tstamp *txtstamp_list = NULL; + struct htt_tx_compl_ind_append_retries *retry_list = NULL; + int offset_dwords; + + if (num_msdus <= 0) + return NULL; + + has_tx_tsf = HTT_TX_COMPL_IND_APPEND1_GET(*msg_word_header); + + /* skip header and MSDUx ID part*/ + offset_dwords = ((num_msdus + 1) >> 1); + *msg_word_payload += offset_dwords; + + if (!has_tx_tsf) + return NULL; + + has_retry = HTT_TX_COMPL_IND_APPEND_GET(*msg_word_header); + if (has_retry) { + int retry_index = 0; + int width_for_each_retry = + (sizeof(struct htt_tx_compl_ind_append_retries) + + 3) >> 2; + + retry_list = (struct htt_tx_compl_ind_append_retries *) + (*msg_word_payload + offset_dwords); + while (retry_list) { + if (retry_list[retry_index++].flag == 0) + break; + } + offset_dwords = retry_index * width_for_each_retry; + } + + *msg_word_payload += offset_dwords; + txtstamp_list = (struct htt_tx_compl_ind_append_tx_tstamp *) + (*msg_word_payload); + return txtstamp_list; +} + +static inline +struct htt_tx_compl_ind_append_tx_tsf64 *ol_tx_get_txtstamp64s( + u_int32_t *msg_word_header, u_int32_t **msg_word_payload, + int num_msdus) +{ + u_int32_t has_tx_tstamp64; + u_int32_t has_rssi; + struct htt_tx_compl_ind_append_tx_tsf64 *txtstamp64_list = NULL; + + int offset_dwords = 0; + + if (num_msdus <= 0) + return NULL; + + has_tx_tstamp64 = HTT_TX_COMPL_IND_APPEND3_GET(*msg_word_header); + if (!has_tx_tstamp64) + return NULL; + + /*skip MSDUx ACK RSSI part*/ + has_rssi = HTT_TX_COMPL_IND_APPEND2_GET(*msg_word_header); + if (has_rssi) + offset_dwords = ((num_msdus + 1) >> 1); + + *msg_word_payload = *msg_word_payload + offset_dwords; + txtstamp64_list = + (struct htt_tx_compl_ind_append_tx_tsf64 *) + (*msg_word_payload); + + return txtstamp64_list; +} + +static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, + qdf_nbuf_t netbuf, u_int64_t ts) +{ + if (!netbuf) + return; + + if (pdev->ol_tx_timestamp_cb) + pdev->ol_tx_timestamp_cb(status, netbuf, ts); +} +#else +static inline struct htt_tx_compl_ind_append_tx_tstamp *ol_tx_get_txtstamps( + u_int32_t *msg_word_header, u_int32_t **msg_word_payload, + int num_msdus) +{ + return NULL; +} + +static inline +struct htt_tx_compl_ind_append_tx_tsf64 *ol_tx_get_txtstamp64s( + u_int32_t *msg_word_header, u_int32_t **msg_word_payload, + int num_msdus) +{ + return NULL; +} + +static inline void ol_tx_timestamp(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, + qdf_nbuf_t netbuf, u_int64_t ts) +{ +} +#endif /* WLAN_FEATURE_TSF_PLUS_SOCK_TS */ + +static void ol_tx_update_ack_count(struct ol_tx_desc_t *tx_desc, + enum htt_tx_status status) +{ + if (!tx_desc->vdev) + return; + + if (status == htt_tx_status_ok) + ++tx_desc->vdev->txrx_stats.txack_success; + else + ++tx_desc->vdev->txrx_stats.txack_failed; +} + +/** + * ol_tx_notify_completion() - Notify tx completion for this desc + * @tx_desc: tx desc + * @netbuf: buffer + * @status: tx status + * + * Return: none + */ +static void ol_tx_notify_completion(struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, uint8_t status) +{ + void *osif_dev; + ol_txrx_completion_fp tx_compl_cbk = NULL; + uint16_t flag = 0; + + qdf_assert(tx_desc); + + ol_tx_flow_pool_lock(tx_desc); + + if (!tx_desc->vdev || + !tx_desc->vdev->osif_dev) { + ol_tx_flow_pool_unlock(tx_desc); + return; + } + osif_dev = tx_desc->vdev->osif_dev; + tx_compl_cbk = tx_desc->vdev->tx_comp; + ol_tx_flow_pool_unlock(tx_desc); + + if (status == htt_tx_status_ok) + flag = (BIT(QDF_TX_RX_STATUS_OK) | + BIT(QDF_TX_RX_STATUS_DOWNLOAD_SUCC)); + else if (status != htt_tx_status_download_fail) + flag = BIT(QDF_TX_RX_STATUS_DOWNLOAD_SUCC); + + if (tx_compl_cbk) + tx_compl_cbk(netbuf, osif_dev, flag); +} + +/** + * ol_tx_update_connectivity_stats() - update connectivity stats + * @tx_desc: tx desc + * @netbuf: buffer + * @status: htt status + * + * + * Return: none + */ +static void ol_tx_update_connectivity_stats(struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t netbuf, + enum htt_tx_status status) +{ + void *osif_dev; + uint32_t pkt_type_bitmap; + ol_txrx_stats_rx_fp stats_rx = NULL; + uint8_t pkt_type = 0; + + qdf_assert(tx_desc); + + ol_tx_flow_pool_lock(tx_desc); + /* + * In cases when vdev has gone down and tx completion + * are received, leads to NULL vdev access. + * So, check for NULL before dereferencing it. + */ + if (!tx_desc->vdev || + !tx_desc->vdev->osif_dev || + !tx_desc->vdev->stats_rx) { + ol_tx_flow_pool_unlock(tx_desc); + return; + } + osif_dev = tx_desc->vdev->osif_dev; + stats_rx = tx_desc->vdev->stats_rx; + ol_tx_flow_pool_unlock(tx_desc); + + pkt_type_bitmap = wlan_dp_intf_get_pkt_type_bitmap_value(tx_desc->vdev); + + if (pkt_type_bitmap) { + if (status != htt_tx_status_download_fail) + stats_rx(netbuf, osif_dev, + PKT_TYPE_TX_HOST_FW_SENT, &pkt_type); + if (status == htt_tx_status_ok) + stats_rx(netbuf, osif_dev, + PKT_TYPE_TX_ACK_CNT, &pkt_type); + } +} + +#ifdef CONNECTIVITY_PKTLOG +static inline enum qdf_dp_tx_rx_status +htt_qdf_status_map(enum htt_tx_status status) +{ + switch (status) { + case HTT_TX_COMPL_IND_STAT_OK: + return QDF_TX_RX_STATUS_OK; + case HTT_TX_COMPL_IND_STAT_DISCARD: + return QDF_TX_RX_STATUS_FW_DISCARD; + case HTT_TX_COMPL_IND_STAT_NO_ACK: + return QDF_TX_RX_STATUS_NO_ACK; + case HTT_TX_COMPL_IND_STAT_DROP: + return QDF_TX_RX_STATUS_DROP; + case HTT_HOST_ONLY_STATUS_CODE_START: + return QDF_TX_RX_STATUS_DROP; + default: + return QDF_TX_RX_STATUS_DROP; + } +} + +static inline void +ol_tx_send_pktlog(struct ol_txrx_soc_t *soc, ol_txrx_pdev_handle pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t netbuf, + enum htt_tx_status status, enum qdf_pkt_type pkt_type) +{ + ol_txrx_pktdump_cb packetdump_cb; + enum qdf_dp_tx_rx_status tx_status; + + if (tx_desc->pkt_type != OL_TX_FRM_TSO) { + packetdump_cb = pdev->ol_tx_packetdump_cb; + if (packetdump_cb) { + tx_status = htt_qdf_status_map(status); + packetdump_cb((void *)soc, pdev->id, + tx_desc->vdev_id, + netbuf, tx_status, pkt_type); + } + } +} +#else +static inline void +ol_tx_send_pktlog(struct ol_txrx_soc_t *soc, ol_txrx_pdev_handle pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t netbuf, + enum htt_tx_status status, enum qdf_pkt_type pkt_type) +{ +} +#endif + +/** + * WARNING: ol_tx_inspect_handler()'s behavior is similar to that of + * ol_tx_completion_handler(). + * any change in ol_tx_completion_handler() must be mirrored in + * ol_tx_inspect_handler(). + */ +void +ol_tx_completion_handler(ol_txrx_pdev_handle pdev, + int num_msdus, + enum htt_tx_status status, void *msg) +{ + int i; + uint16_t tx_desc_id; + struct ol_tx_desc_t *tx_desc; + uint32_t byte_cnt = 0; + qdf_nbuf_t netbuf; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t is_tx_desc_freed = 0; + struct htt_tx_compl_ind_append_tx_tstamp *txtstamp_list = NULL; + struct htt_tx_compl_ind_append_tx_tsf64 *txtstamp64_list = NULL; + struct htt_tx_data_hdr_information *pkt_capture_txcomp_hdr_list = NULL; + u_int32_t *msg_word_header = (u_int32_t *)msg; + /*msg_word skip header*/ + u_int32_t *msg_word_payload = msg_word_header + 1; + u_int32_t *msg_word = (u_int32_t *)msg; + u_int16_t *desc_ids = (u_int16_t *)(msg_word + 1); + union ol_tx_desc_list_elem_t *lcl_freelist = NULL; + union ol_tx_desc_list_elem_t *tx_desc_last = NULL; + ol_tx_desc_list tx_descs; + uint64_t tx_tsf64; + uint8_t tid; + uint8_t dp_status; + + TAILQ_INIT(&tx_descs); + + tid = HTT_TX_COMPL_IND_TID_GET(*msg_word); + + ol_tx_delay_compute(pdev, status, desc_ids, num_msdus); + if (status == htt_tx_status_ok || + status == htt_tx_status_discard || + status == htt_tx_status_no_ack) { + txtstamp_list = ol_tx_get_txtstamps( + msg_word_header, &msg_word_payload, num_msdus); + if (pdev->enable_tx_compl_tsf64) + txtstamp64_list = ol_tx_get_txtstamp64s( + msg_word_header, &msg_word_payload, num_msdus); + } + + if ((ucfg_pkt_capture_get_mode((void *)soc->psoc) == + PACKET_CAPTURE_MODE_DATA_ONLY)) + pkt_capture_txcomp_hdr_list = + ucfg_pkt_capture_tx_get_txcomplete_data_hdr( + msg_word, + num_msdus); + + for (i = 0; i < num_msdus; i++) { + tx_desc_id = desc_ids[i]; + if (tx_desc_id >= pdev->tx_desc.pool_size) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: drop due to invalid msdu id = %x\n", + __func__, tx_desc_id); + continue; + } + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + qdf_assert(tx_desc); + ol_tx_desc_update_comp_ts(tx_desc); + tx_desc->status = status; + netbuf = tx_desc->netbuf; + + if (txtstamp64_list) { + tx_tsf64 = + (u_int64_t)txtstamp64_list[i].tx_tsf64_high << 32 | + txtstamp64_list[i].tx_tsf64_low; + + ol_tx_timestamp(pdev, status, netbuf, tx_tsf64); + } else if (txtstamp_list) + ol_tx_timestamp(pdev, status, netbuf, + (u_int64_t)txtstamp_list->timestamp[i] + ); + + if (pkt_capture_txcomp_hdr_list) { + ol_tx_pkt_capture_tx_completion_process( + pdev, + tx_desc, + &pkt_capture_txcomp_hdr_list[i], + tid, status); + } + + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + + /* check tx completion notification */ + if (QDF_NBUF_CB_TX_EXTRA_FRAG_FLAGS_NOTIFY_COMP(netbuf)) + ol_tx_notify_completion(tx_desc, netbuf, status); + + /* track connectivity stats */ + ol_tx_update_connectivity_stats(tx_desc, netbuf, + status); + ol_tx_update_ack_count(tx_desc, status); + + ol_tx_send_pktlog(soc, pdev, tx_desc, netbuf, status, + QDF_TX_DATA_PKT); + + dp_status = ol_tx_comp_hw_to_qdf_status(status); + + DPTRACE(qdf_dp_trace_ptr(netbuf, + QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(netbuf), + sizeof(qdf_nbuf_data(netbuf)), tx_desc->id, status, + dp_status, + tx_desc->vdev->qdf_opmode)); + + /* + * If credits are reported through credit_update_ind then do not + * update group credits on tx_complete_ind. + */ + if (!pdev->cfg.credit_update_enabled) + ol_tx_desc_update_group_credit(pdev, + tx_desc_id, + 1, 0, status); + /* Per SDU update of byte count */ + byte_cnt += qdf_nbuf_len(netbuf); + if (OL_TX_DESC_NO_REFS(tx_desc)) { + ol_tx_statistics( + pdev->ctrl_pdev, + HTT_TX_DESC_VDEV_ID_GET(*((uint32_t *) + (tx_desc-> + htt_tx_desc))), + status != htt_tx_status_ok); + ol_tx_msdu_complete(pdev, tx_desc, tx_descs, netbuf, + lcl_freelist, tx_desc_last, status, + is_tx_desc_freed); + +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + if (!is_tx_desc_freed) { + tx_desc->pkt_type = ol_tx_frm_freed; +#ifdef QCA_COMPUTE_TX_DELAY + tx_desc->entry_timestamp_ticks = 0xffffffff; +#endif + } +#endif + } + } + + /* One shot protected access to pdev freelist, when setup */ + if (lcl_freelist) { + qdf_spin_lock(&pdev->tx_mutex); + tx_desc_last->next = pdev->tx_desc.freelist; + pdev->tx_desc.freelist = lcl_freelist; + pdev->tx_desc.num_free += (uint16_t) num_msdus; + qdf_spin_unlock(&pdev->tx_mutex); + } else { + ol_tx_desc_frame_list_free(pdev, &tx_descs, + status != htt_tx_status_ok); + } + + if (pdev->cfg.is_high_latency) { + /* + * Credit was already explicitly updated by HTT, + * but update the number of available tx descriptors, + * then invoke the scheduler, since new credit is probably + * available now. + */ + qdf_atomic_add(num_msdus, &pdev->tx_queue.rsrc_cnt); + ol_tx_sched(pdev); + } else { + ol_tx_target_credit_adjust(num_msdus, pdev, NULL); + } + + /* UNPAUSE OS Q */ + ol_tx_flow_ct_unpause_os_q(pdev); + /* Do one shot statistics */ + TXRX_STATS_UPDATE_TX_STATS(pdev, status, num_msdus, byte_cnt); +} + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +void ol_tx_desc_update_group_credit(ol_txrx_pdev_handle pdev, + u_int16_t tx_desc_id, int credit, u_int8_t absolute, + enum htt_tx_status status) +{ + uint8_t i, is_member; + uint16_t vdev_id_mask; + struct ol_tx_desc_t *tx_desc; + + if (tx_desc_id >= pdev->tx_desc.pool_size) { + qdf_print("Invalid desc id"); + return; + } + + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + vdev_id_mask = + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership); + is_member = OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(vdev_id_mask, + tx_desc->vdev_id); + if (is_member) { + ol_txrx_update_group_credit(&pdev->txq_grps[i], + credit, absolute); + break; + } + } + ol_tx_update_group_credit_stats(pdev); +} + +void ol_tx_deduct_one_any_group_credit(ol_txrx_pdev_handle pdev) +{ + int credits_group_0, credits_group_1; + + qdf_spin_lock_bh(&pdev->tx_queue_spinlock); + credits_group_0 = qdf_atomic_read(&pdev->txq_grps[0].credit); + credits_group_1 = qdf_atomic_read(&pdev->txq_grps[1].credit); + + if (credits_group_0 > credits_group_1) + ol_txrx_update_group_credit(&pdev->txq_grps[0], -1, 0); + else if (credits_group_1 != 0) + ol_txrx_update_group_credit(&pdev->txq_grps[1], -1, 0); + + qdf_spin_unlock_bh(&pdev->tx_queue_spinlock); +} + +#ifdef DEBUG_HL_LOGGING + +void ol_tx_update_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + uint16_t curr_index; + uint8_t i; + + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + pdev->grp_stats.last_valid_index++; + if (pdev->grp_stats.last_valid_index > (OL_TX_GROUP_STATS_LOG_SIZE + - 1)) { + pdev->grp_stats.last_valid_index -= OL_TX_GROUP_STATS_LOG_SIZE; + pdev->grp_stats.wrap_around = 1; + } + curr_index = pdev->grp_stats.last_valid_index; + + for (i = 0; i < OL_TX_MAX_TXQ_GROUPS; i++) { + pdev->grp_stats.stats[curr_index].grp[i].member_vdevs = + OL_TXQ_GROUP_VDEV_ID_MASK_GET( + pdev->txq_grps[i].membership); + pdev->grp_stats.stats[curr_index].grp[i].credit = + qdf_atomic_read(&pdev->txq_grps[i].credit); + } + + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); +} + +void ol_tx_dump_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + uint16_t i, j, is_break = 0; + int16_t curr_index, old_index, wrap_around; + uint16_t curr_credit, mem_vdevs; + uint16_t old_credit = 0; + + txrx_nofl_info("Group credit stats:"); + txrx_nofl_info(" No: GrpID: Credit: Change: vdev_map"); + + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + curr_index = pdev->grp_stats.last_valid_index; + wrap_around = pdev->grp_stats.wrap_around; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); + + if (curr_index < 0) { + txrx_nofl_info("Not initialized"); + return; + } + + for (i = 0; i < OL_TX_GROUP_STATS_LOG_SIZE; i++) { + old_index = curr_index - 1; + if (old_index < 0) { + if (wrap_around == 0) + is_break = 1; + else + old_index = OL_TX_GROUP_STATS_LOG_SIZE - 1; + } + + for (j = 0; j < OL_TX_MAX_TXQ_GROUPS; j++) { + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + curr_credit = + pdev->grp_stats.stats[curr_index]. + grp[j].credit; + if (!is_break) + old_credit = + pdev->grp_stats.stats[old_index]. + grp[j].credit; + + mem_vdevs = + pdev->grp_stats.stats[curr_index].grp[j]. + member_vdevs; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); + + if (!is_break) + txrx_nofl_info("%4d: %5d: %6d %6d %8x", + curr_index, j, + curr_credit, + (curr_credit - old_credit), + mem_vdevs); + else + txrx_nofl_info("%4d: %5d: %6d %6s %8x", + curr_index, j, + curr_credit, "NA", mem_vdevs); + } + + if (is_break) + break; + + curr_index = old_index; + } +} + +void ol_tx_clear_group_credit_stats(ol_txrx_pdev_handle pdev) +{ + qdf_spin_lock_bh(&pdev->grp_stat_spinlock); + qdf_mem_zero(&pdev->grp_stats, sizeof(pdev->grp_stats)); + pdev->grp_stats.last_valid_index = -1; + pdev->grp_stats.wrap_around = 0; + qdf_spin_unlock_bh(&pdev->grp_stat_spinlock); +} +#endif +#endif + +/* + * ol_tx_single_completion_handler performs the same tx completion + * processing as ol_tx_completion_handler, but for a single frame. + * ol_tx_completion_handler is optimized to handle batch completions + * as efficiently as possible; in contrast ol_tx_single_completion_handler + * handles single frames as simply and generally as possible. + * Thus, this ol_tx_single_completion_handler function is suitable for + * intermittent usage, such as for tx mgmt frames. + */ +void +ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, + enum htt_tx_status status, uint16_t tx_desc_id) +{ + struct ol_tx_desc_t *tx_desc; + qdf_nbuf_t netbuf; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + tx_desc = ol_tx_desc_find_check(pdev, tx_desc_id); + if (!tx_desc) { + ol_txrx_err("invalid desc_id(%u), ignore it", tx_desc_id); + return; + } + + tx_desc->status = status; + netbuf = tx_desc->netbuf; + + QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + /* Do one shot statistics */ + TXRX_STATS_UPDATE_TX_STATS(pdev, status, 1, qdf_nbuf_len(netbuf)); + + ol_tx_send_pktlog(soc, pdev, tx_desc, netbuf, status, QDF_TX_MGMT_PKT); + + if (OL_TX_DESC_NO_REFS(tx_desc)) { + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, + status != htt_tx_status_ok); + } + + TX_CREDIT_DEBUG_PRINT(" Increase credit %d + %d = %d\n", + qdf_atomic_read(&pdev->target_tx_credit), + 1, qdf_atomic_read(&pdev->target_tx_credit) + 1); + + if (pdev->cfg.is_high_latency) { + /* + * Credit was already explicitly updated by HTT, + * but update the number of available tx descriptors, + * then invoke the scheduler, since new credit is probably + * available now. + */ + qdf_atomic_add(1, &pdev->tx_queue.rsrc_cnt); + ol_tx_sched(pdev); + } else { + qdf_atomic_add(1, &pdev->target_tx_credit); + } +} + +/** + * WARNING: ol_tx_inspect_handler()'s behavior is similar to that of + * ol_tx_completion_handler(). + * any change in ol_tx_completion_handler() must be mirrored here. + */ +void +ol_tx_inspect_handler(ol_txrx_pdev_handle pdev, + int num_msdus, void *tx_desc_id_iterator) +{ + uint16_t vdev_id, i; + struct ol_txrx_vdev_t *vdev; + uint16_t *desc_ids = (uint16_t *) tx_desc_id_iterator; + uint16_t tx_desc_id; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *lcl_freelist = NULL; + union ol_tx_desc_list_elem_t *tx_desc_last = NULL; + qdf_nbuf_t netbuf; + ol_tx_desc_list tx_descs; + uint32_t is_tx_desc_freed = 0; + + TAILQ_INIT(&tx_descs); + + for (i = 0; i < num_msdus; i++) { + tx_desc_id = desc_ids[i]; + if (tx_desc_id >= pdev->tx_desc.pool_size) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: drop due to invalid msdu id = %x\n", + __func__, tx_desc_id); + continue; + } + tx_desc = ol_tx_desc_find(pdev, tx_desc_id); + qdf_assert(tx_desc); + ol_tx_desc_update_comp_ts(tx_desc); + netbuf = tx_desc->netbuf; + + /* find the "vdev" this tx_desc belongs to */ + vdev_id = HTT_TX_DESC_VDEV_ID_GET(*((uint32_t *) + (tx_desc->htt_tx_desc))); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + /* vdev now points to the vdev for this descriptor. */ + +#ifndef ATH_11AC_TXCOMPACT + /* save this multicast packet to local free list */ + if (qdf_atomic_dec_and_test(&tx_desc->ref_cnt)) +#endif + { + /* + * For this function only, force htt status to be + * "htt_tx_status_ok" + * for graceful freeing of this multicast frame + */ + ol_tx_msdu_complete(pdev, tx_desc, tx_descs, netbuf, + lcl_freelist, tx_desc_last, + htt_tx_status_ok, + is_tx_desc_freed); +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + if (!is_tx_desc_freed) { + tx_desc->pkt_type = ol_tx_frm_freed; +#ifdef QCA_COMPUTE_TX_DELAY + tx_desc->entry_timestamp_ticks = 0xffffffff; +#endif + } +#endif + } + } + + if (lcl_freelist) { + qdf_spin_lock(&pdev->tx_mutex); + tx_desc_last->next = pdev->tx_desc.freelist; + pdev->tx_desc.freelist = lcl_freelist; + qdf_spin_unlock(&pdev->tx_mutex); + } else { + ol_tx_desc_frame_list_free(pdev, &tx_descs, + htt_tx_status_discard); + } + TX_CREDIT_DEBUG_PRINT(" Increase HTT credit %d + %d = %d..\n", + qdf_atomic_read(&pdev->target_tx_credit), + num_msdus, + qdf_atomic_read(&pdev->target_tx_credit) + + num_msdus); + + if (pdev->cfg.is_high_latency) { + /* credit was already explicitly updated by HTT */ + ol_tx_sched(pdev); + } else { + ol_tx_target_credit_adjust(num_msdus, pdev, NULL); + } +} + +#ifdef QCA_COMPUTE_TX_DELAY +/** + * ol_tx_set_compute_interval - updates the compute interval + * period for TSM stats. + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @param interval: interval for stats computation + * + * Return: None + */ +void ol_tx_set_compute_interval(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint32_t interval) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + pdev->tx_delay.avg_period_ticks = qdf_system_msecs_to_ticks(interval); +} + +/** + * ol_tx_packet_count() - Return the uplink (transmitted) packet count + and loss count. + * @soc_hdl: soc handle + * @pdev_id: pdev identifier + * @out_packet_count - number of packets transmitted + * @out_packet_loss_count - number of packets lost + * @category - access category of interest + * + * This function will be called for getting uplink packet count and + * loss count for given stream (access category) a regular interval. + * This also resets the counters hence, the value returned is packets + * counted in last 5(default) second interval. These counter are + * incremented per access category in ol_tx_completion_handler() + */ +void +ol_tx_packet_count(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + *out_packet_count = pdev->packet_count[category]; + *out_packet_loss_count = pdev->packet_loss_count[category]; + pdev->packet_count[category] = 0; + pdev->packet_loss_count[category] = 0; +} + +static uint32_t ol_tx_delay_avg(uint64_t sum, uint32_t num) +{ + uint32_t sum32; + int shift = 0; + /* + * To avoid doing a 64-bit divide, shift the sum down until it is + * no more than 32 bits (and shift the denominator to match). + */ + while ((sum >> 32) != 0) { + sum >>= 1; + shift++; + } + sum32 = (uint32_t) sum; + num >>= shift; + return (sum32 + (num >> 1)) / num; /* round to nearest */ +} + +void +ol_tx_delay(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int index; + uint32_t avg_delay_ticks; + struct ol_tx_delay_data *data; + + qdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + qdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = 1 - pdev->tx_delay.cats[category].in_progress_idx; + + data = &pdev->tx_delay.cats[category].copies[index]; + + if (data->avgs.transmit_num > 0) { + avg_delay_ticks = + ol_tx_delay_avg(data->avgs.transmit_sum_ticks, + data->avgs.transmit_num); + *tx_delay_microsec = + qdf_system_ticks_to_msecs(avg_delay_ticks * 1000); + } else { + /* + * This case should only happen if there's a query + * within 5 sec after the first tx data frame. + */ + *tx_delay_microsec = 0; + } + if (data->avgs.queue_num > 0) { + avg_delay_ticks = + ol_tx_delay_avg(data->avgs.queue_sum_ticks, + data->avgs.queue_num); + *queue_delay_microsec = + qdf_system_ticks_to_msecs(avg_delay_ticks * 1000); + } else { + /* + * This case should only happen if there's a query + * within 5 sec after the first tx data frame. + */ + *queue_delay_microsec = 0; + } + + qdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +void +ol_tx_delay_hist(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint16_t *report_bin_values, int category) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int index, i, j; + struct ol_tx_delay_data *data; + + qdf_assert(category >= 0 && category < QCA_TX_DELAY_NUM_CATEGORIES); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + qdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = 1 - pdev->tx_delay.cats[category].in_progress_idx; + + data = &pdev->tx_delay.cats[category].copies[index]; + + for (i = 0, j = 0; i < QCA_TX_DELAY_HIST_REPORT_BINS - 1; i++) { + uint16_t internal_bin_sum = 0; + + while (j < (1 << i)) + internal_bin_sum += data->hist_bins_queue[j++]; + + report_bin_values[i] = internal_bin_sum; + } + report_bin_values[i] = data->hist_bins_queue[j]; /* overflow */ + + qdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID +static uint8_t +ol_tx_delay_tid_from_l3_hdr(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu, struct ol_tx_desc_t *tx_desc) +{ + uint16_t ethertype; + uint8_t *dest_addr, *l3_hdr; + int is_mgmt, is_mcast; + int l2_hdr_size; + + dest_addr = ol_tx_dest_addr_find(pdev, msdu); + if (!dest_addr) + return QDF_NBUF_TX_EXT_TID_INVALID; + + is_mcast = IEEE80211_IS_MULTICAST(dest_addr); + is_mgmt = tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE; + if (is_mgmt) { + return (is_mcast) ? + OL_TX_NUM_TIDS + OL_TX_VDEV_DEFAULT_MGMT : + HTT_TX_EXT_TID_MGMT; + } + if (is_mcast) + return OL_TX_NUM_TIDS + OL_TX_VDEV_MCAST_BCAST; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + struct ethernet_hdr_t *enet_hdr; + + enet_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + l2_hdr_size = sizeof(struct ethernet_hdr_t); + ethertype = + (enet_hdr->ethertype[0] << 8) | enet_hdr->ethertype[1]; + if (!IS_ETHERTYPE(ethertype)) { + struct llc_snap_hdr_t *llc_hdr; + + llc_hdr = (struct llc_snap_hdr_t *) + (qdf_nbuf_data(msdu) + l2_hdr_size); + l2_hdr_size += sizeof(struct llc_snap_hdr_t); + ethertype = + (llc_hdr->ethertype[0] << 8) | llc_hdr-> + ethertype[1]; + } + } else { + struct llc_snap_hdr_t *llc_hdr; + + l2_hdr_size = sizeof(struct ieee80211_frame); + llc_hdr = (struct llc_snap_hdr_t *)(qdf_nbuf_data(msdu) + + l2_hdr_size); + l2_hdr_size += sizeof(struct llc_snap_hdr_t); + ethertype = + (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + } + l3_hdr = qdf_nbuf_data(msdu) + l2_hdr_size; + if (ETHERTYPE_IPV4 == ethertype) { + return (((struct ipv4_hdr_t *)l3_hdr)->tos >> 5) & 0x7; + } else if (ETHERTYPE_IPV6 == ethertype) { + return (ipv6_traffic_class((struct ipv6_hdr_t *)l3_hdr) >> 5) & + 0x7; + } else { + return QDF_NBUF_TX_EXT_TID_INVALID; + } +} + +static int ol_tx_delay_category(struct ol_txrx_pdev_t *pdev, uint16_t msdu_id) +{ + struct ol_tx_desc_t *tx_desc = ol_tx_desc_find(pdev, msdu_id); + uint8_t tid; + qdf_nbuf_t msdu = tx_desc->netbuf; + + tid = qdf_nbuf_get_tid(msdu); + if (tid == QDF_NBUF_TX_EXT_TID_INVALID) { + tid = ol_tx_delay_tid_from_l3_hdr(pdev, msdu, tx_desc); + if (tid == QDF_NBUF_TX_EXT_TID_INVALID) { + /* + * TID could not be determined + * (this is not an IP frame?) + */ + return -EINVAL; + } + } + return tid; +} +#else +static int ol_tx_delay_category(struct ol_txrx_pdev_t *pdev, uint16_t msdu_id) +{ + return 0; +} +#endif + +static inline int +ol_tx_delay_hist_bin(struct ol_txrx_pdev_t *pdev, uint32_t delay_ticks) +{ + int bin; + /* + * For speed, multiply and shift to approximate a divide. This causes + * a small error, but the approximation error should be much less + * than the other uncertainties in the tx delay computation. + */ + bin = (delay_ticks * pdev->tx_delay.hist_internal_bin_width_mult) >> + pdev->tx_delay.hist_internal_bin_width_shift; + if (bin >= QCA_TX_DELAY_HIST_INTERNAL_BINS) + bin = QCA_TX_DELAY_HIST_INTERNAL_BINS - 1; + + return bin; +} + +static void +ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, + enum htt_tx_status status, + uint16_t *desc_ids, int num_msdus) +{ + int i, index, cat; + uint32_t now_ticks = qdf_system_ticks(); + uint32_t tx_delay_transmit_ticks, tx_delay_queue_ticks; + uint32_t avg_time_ticks; + struct ol_tx_delay_data *data; + + qdf_assert(num_msdus > 0); + + /* + * keep static counters for total packet and lost packets + * reset them in ol_tx_delay(), function used to fetch the stats + */ + + cat = ol_tx_delay_category(pdev, desc_ids[0]); + if (cat < 0 || cat >= QCA_TX_DELAY_NUM_CATEGORIES) + return; + + pdev->packet_count[cat] = pdev->packet_count[cat] + num_msdus; + if (status != htt_tx_status_ok) { + for (i = 0; i < num_msdus; i++) { + cat = ol_tx_delay_category(pdev, desc_ids[i]); + if (cat < 0 || cat >= QCA_TX_DELAY_NUM_CATEGORIES) + return; + pdev->packet_loss_count[cat]++; + } + return; + } + + /* since we may switch the ping-pong index, provide mutex w. readers */ + qdf_spin_lock_bh(&pdev->tx_delay.mutex); + index = pdev->tx_delay.cats[cat].in_progress_idx; + + data = &pdev->tx_delay.cats[cat].copies[index]; + + if (pdev->tx_delay.tx_compl_timestamp_ticks != 0) { + tx_delay_transmit_ticks = + now_ticks - pdev->tx_delay.tx_compl_timestamp_ticks; + /* + * We'd like to account for the number of MSDUs that were + * transmitted together, but we don't know this. All we know + * is the number of MSDUs that were acked together. + * Since the frame error rate is small, this is nearly the same + * as the number of frames transmitted together. + */ + data->avgs.transmit_sum_ticks += tx_delay_transmit_ticks; + data->avgs.transmit_num += num_msdus; + } + pdev->tx_delay.tx_compl_timestamp_ticks = now_ticks; + + for (i = 0; i < num_msdus; i++) { + int bin; + uint16_t id = desc_ids[i]; + struct ol_tx_desc_t *tx_desc = ol_tx_desc_find(pdev, id); + + tx_delay_queue_ticks = + now_ticks - tx_desc->entry_timestamp_ticks; + + data->avgs.queue_sum_ticks += tx_delay_queue_ticks; + data->avgs.queue_num++; + bin = ol_tx_delay_hist_bin(pdev, tx_delay_queue_ticks); + data->hist_bins_queue[bin]++; + } + + /* check if it's time to start a new average */ + avg_time_ticks = + now_ticks - pdev->tx_delay.cats[cat].avg_start_time_ticks; + if (avg_time_ticks > pdev->tx_delay.avg_period_ticks) { + pdev->tx_delay.cats[cat].avg_start_time_ticks = now_ticks; + index = 1 - index; + pdev->tx_delay.cats[cat].in_progress_idx = index; + qdf_mem_zero(&pdev->tx_delay.cats[cat].copies[index], + sizeof(pdev->tx_delay.cats[cat].copies[index])); + } + + qdf_spin_unlock_bh(&pdev->tx_delay.mutex); +} + +#endif /* QCA_COMPUTE_TX_DELAY */ + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +void ol_register_timestamp_callback(tp_ol_timestamp_cb ol_tx_timestamp_cb) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + pdev->ol_tx_timestamp_cb = ol_tx_timestamp_cb; +} + +void ol_deregister_timestamp_callback(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + pdev->ol_tx_timestamp_cb = NULL; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_send.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_send.h new file mode 100644 index 0000000000..a3e84ab61c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_send.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2011, 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_tx_send.h + * @brief API definitions for the tx sendriptor module within the data SW. + */ +#ifndef _OL_TX_SEND__H_ +#define _OL_TX_SEND__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ + +#if defined(CONFIG_HL_SUPPORT) + +static inline void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev) +{ +} +#else + +/** + * @flush the ol tx when surprise remove. + * + */ +void ol_tx_discard_target_frms(ol_txrx_pdev_handle pdev); +#endif + +/** + * @brief Send a tx frame to the target. + * @details + * + * @param pdev - the phy dev + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + */ +void +ol_tx_send(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, qdf_nbuf_t msdu, uint8_t vdev_id); + +/** + * @brief Send a tx batch download to the target. + * @details + * This function is different from above in that + * it accepts a list of msdu's to be downloaded as a batch + * + * @param pdev - the phy dev + * @param msdu_list - the Head pointer to the Tx Batch + * @param num_msdus - Total msdus chained in msdu_list + */ + +void +ol_tx_send_batch(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t msdu_list, int num_msdus); + +/** + * @brief Send a tx frame with a non-std header or payload type to the target. + * @details + * + * @param pdev - the phy dev + * @param vdev - the virtual device sending the data + * (for specifying the transmitter address for multicast / broadcast data) + * @param netbuf - the tx frame + * @param pkt_type - what kind of non-std frame is being sent + */ +void +ol_tx_send_nonstd(struct ol_txrx_pdev_t *pdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, enum htt_pkt_type pkt_type); + +#ifdef QCA_COMPUTE_TX_DELAY +/** + * ol_tx_set_compute_interval() - update compute interval period for TSM stats + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @interval: interval for stats computation + * + * Return: NONE + */ +void ol_tx_set_compute_interval(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint32_t interval); + +/** + * ol_tx_packet_count() - Return the uplink (transmitted) packet counts + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @out_packet_count: number of packets transmitted + * @out_packet_loss_count: number of packets lost + * @category: access category of interest + * + * This function will be called for getting uplink packet count and + * loss count for given stream (access category) a regular interval. + * This also resets the counters hence, the value returned is packets + * counted in last 5(default) second interval. These counter are + * incremented per access category in ol_tx_completion_handler() + * + * Return: NONE + */ +void +ol_tx_packet_count(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint16_t *out_packet_count, + uint16_t *out_packet_loss_count, int category); + +/** + * ol_tx_delay() - get tx packet delay + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @queue_delay_microsec: tx packet delay within queue, usec + * @tx_delay_microsec: tx packet delay, usec + * @category: packet category + * + * Return: NONE + */ +void +ol_tx_delay(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint32_t *queue_delay_microsec, + uint32_t *tx_delay_microsec, int category); + +/** + * ol_tx_delay_hist() - get tx packet delay histogram + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @report_bin_values: bin + * @category: packet category + * + * Return: NONE + */ +void +ol_tx_delay_hist(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint16_t *report_bin_values, int category); +#endif /* QCA_COMPUTE_TX_DELAY */ + +/** + * ol_txrx_flow_control_cb() - call osif flow control callback + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * @tx_resume: tx resume flag + * + * Return: none + */ +void ol_txrx_flow_control_cb(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + bool tx_resume); + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || (defined(CONFIG_HL_SUPPORT) && \ + defined(QCA_HL_NETDEV_FLOW_CONTROL)) +void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev); +#else +static inline void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ +} +#endif +#endif /* _OL_TX_SEND__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_throttle.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_throttle.c new file mode 100644 index 0000000000..6afad51152 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_tx_throttle.c @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* ol_cfg_addba_retry */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ +#include /* ol_txrx_vdev_handle */ +#include /* ol_txrx_sync, ol_tx_addba_conf */ +#include +#include /* ol_ctrl_addba_req */ +#include /* TXRX_ASSERT1, etc. */ +#include /* ol_tx_desc, ol_tx_desc_frame_list_free */ +#include /* ol_tx_vdev_ll_pause_queue_send */ +#include /* ol_tx_sched_notify, etc. */ +#include +#include /* ol_tx_desc_pool_size_hl */ +#include /* ENABLE_TX_QUEUE_LOG */ +#include /* bool */ +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +/** + * ol_txrx_thermal_pause() - pause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_pdev_pause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION); +} + +/** + * ol_txrx_thermal_unpause() - unpause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_pdev_unpause(pdev, OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION); +} +#else +/** + * ol_txrx_thermal_pause() - pause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_pause(struct ol_txrx_pdev_t *pdev) +{ +} + +/** + * ol_txrx_thermal_unpause() - unpause due to thermal mitigation + * @pdev: pdev handle + * + * Return: none + */ +static inline +void ol_txrx_thermal_unpause(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_pdev_ll_pause_queue_send_all(pdev); +} +#endif + +static void ol_tx_pdev_throttle_phase_timer(void *context) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + int ms; + enum throttle_level cur_level; + enum throttle_phase cur_phase; + + /* update the phase */ + pdev->tx_throttle.current_throttle_phase++; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_MAX) + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) { + /* Traffic is stopped */ + ol_txrx_dbg( + "throttle phase --> OFF"); + ol_txrx_throttle_pause(pdev); + ol_txrx_thermal_pause(pdev); + pdev->tx_throttle.prev_outstanding_num = 0; + cur_level = pdev->tx_throttle.current_throttle_level; + cur_phase = pdev->tx_throttle.current_throttle_phase; + ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase]; + if (pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + ol_txrx_dbg( + "start timer %d ms", ms); + qdf_timer_start(&pdev->tx_throttle. + phase_timer, ms); + } + } else { + /* Traffic can go */ + ol_txrx_dbg( + "throttle phase --> ON"); + ol_txrx_throttle_unpause(pdev); + ol_txrx_thermal_unpause(pdev); + cur_level = pdev->tx_throttle.current_throttle_level; + cur_phase = pdev->tx_throttle.current_throttle_phase; + ms = pdev->tx_throttle.throttle_time_ms[cur_level][cur_phase]; + if (pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + ol_txrx_dbg("start timer %d ms", ms); + qdf_timer_start(&pdev->tx_throttle.phase_timer, ms); + } + } +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +static void ol_tx_pdev_throttle_tx_timer(void *context) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)context; + + ol_tx_pdev_ll_pause_queue_send_all(pdev); +} +#endif + +#ifdef CONFIG_HL_SUPPORT + +/** + * ol_tx_set_throttle_phase_time() - Set the thermal mitgation throttle phase + * and time + * @pdev: the peer device object + * @level: throttle phase level + * @ms: throttle time + * + * Return: None + */ +static void +ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms) +{ + qdf_timer_stop(&pdev->tx_throttle.phase_timer); + + /* Set the phase */ + if (level != THROTTLE_LEVEL_0) { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + *ms = pdev->tx_throttle.throttle_time_ms[level] + [THROTTLE_PHASE_OFF]; + + /* pause all */ + ol_txrx_throttle_pause(pdev); + } else { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_ON; + *ms = pdev->tx_throttle.throttle_time_ms[level] + [THROTTLE_PHASE_ON]; + + /* unpause all */ + ol_txrx_throttle_unpause(pdev); + } +} +#else + +static void +ol_tx_set_throttle_phase_time(struct ol_txrx_pdev_t *pdev, int level, int *ms) +{ + int phase_on_time, phase_off_time; + + qdf_timer_stop(&pdev->tx_throttle.phase_timer); + + phase_on_time = + pdev->tx_throttle.throttle_time_ms[level][THROTTLE_PHASE_ON]; + phase_off_time = + pdev->tx_throttle.throttle_time_ms[level][THROTTLE_PHASE_OFF]; + if (phase_on_time && phase_off_time) { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + *ms = + pdev->tx_throttle.throttle_time_ms[level][THROTTLE_PHASE_OFF]; + ol_txrx_throttle_pause(pdev); + ol_txrx_thermal_pause(pdev); + } else if (!phase_off_time) { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + *ms = 0; + ol_txrx_throttle_unpause(pdev); + ol_txrx_thermal_unpause(pdev); + } else { + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + *ms = 0; + ol_txrx_throttle_pause(pdev); + ol_txrx_thermal_pause(pdev); + } +} +#endif + +void ol_tx_throttle_set_level(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, int level) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int ms = 0; + + if (level >= THROTTLE_LEVEL_MAX) { + ol_txrx_dbg("invalid throttle level set %d, ignoring", level); + return; + } + + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is NULL"); + return; + } + + ol_txrx_info("Setting throttle level %d", level); + + /* Set the current throttle level */ + pdev->tx_throttle.current_throttle_level = (enum throttle_level)level; + pdev->tx_throttle.prev_outstanding_num = 0; + + ol_tx_set_throttle_phase_time(pdev, level, &ms); + + if (ms) + qdf_timer_start(&pdev->tx_throttle.phase_timer, ms); +} + +void ol_tx_throttle_init_period(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, int period, + uint8_t *dutycycle_level) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev; + int i; + + if (qdf_unlikely(!soc)) { + ol_txrx_err("soc is NULL"); + return; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is NULL"); + return; + } + + /* Set the current throttle level */ + pdev->tx_throttle.throttle_period_ms = period; + + ol_txrx_dbg("level OFF ON"); + for (i = 0; i < THROTTLE_LEVEL_MAX; i++) { + pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_ON] = + pdev->tx_throttle.throttle_period_ms - + ((dutycycle_level[i] * + pdev->tx_throttle.throttle_period_ms) / 100); + pdev->tx_throttle.throttle_time_ms[i][THROTTLE_PHASE_OFF] = + pdev->tx_throttle.throttle_period_ms - + pdev->tx_throttle.throttle_time_ms[ + i][THROTTLE_PHASE_ON]; + ol_txrx_dbg("%d %d %d", i, + pdev->tx_throttle. + throttle_time_ms[i][THROTTLE_PHASE_OFF], + pdev->tx_throttle. + throttle_time_ms[i][THROTTLE_PHASE_ON]); + } +} + +void ol_tx_throttle_init(struct ol_txrx_pdev_t *pdev) +{ + uint32_t throttle_period; + uint8_t dutycycle_level[THROTTLE_LEVEL_MAX]; + int i; + + pdev->tx_throttle.current_throttle_level = THROTTLE_LEVEL_0; + pdev->tx_throttle.current_throttle_phase = THROTTLE_PHASE_OFF; + qdf_spinlock_create(&pdev->tx_throttle.mutex); + + throttle_period = ol_cfg_throttle_period_ms(pdev->ctrl_pdev); + + for (i = 0; i < THROTTLE_LEVEL_MAX; i++) + dutycycle_level[i] = + ol_cfg_throttle_duty_cycle_level(pdev->ctrl_pdev, i); + + ol_tx_throttle_init_period(cds_get_context(QDF_MODULE_ID_SOC), pdev->id, + throttle_period, &dutycycle_level[0]); + + qdf_timer_init(pdev->osdev, &pdev->tx_throttle.phase_timer, + ol_tx_pdev_throttle_phase_timer, pdev, + QDF_TIMER_TYPE_SW); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + qdf_timer_init(pdev->osdev, &pdev->tx_throttle.tx_timer, + ol_tx_pdev_throttle_tx_timer, pdev, QDF_TIMER_TYPE_SW); +#endif + + pdev->tx_throttle.tx_threshold = THROTTLE_TX_THRESHOLD; +} + +void +ol_txrx_throttle_pause(ol_txrx_pdev_handle pdev) +{ + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (pdev->tx_throttle.is_paused) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = true; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + ol_txrx_pdev_pause(pdev, 0); +} + +void +ol_txrx_throttle_unpause(ol_txrx_pdev_handle pdev) +{ + qdf_spin_lock_bh(&pdev->tx_throttle.mutex); + + if (!pdev->tx_throttle.is_paused) { + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + return; + } + + pdev->tx_throttle.is_paused = false; + qdf_spin_unlock_bh(&pdev->tx_throttle.mutex); + ol_txrx_pdev_unpause(pdev, 0); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx.c new file mode 100644 index 0000000000..41e7ee54b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx.c @@ -0,0 +1,6553 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* qdf_mem_malloc,free */ +#include /* qdf_device_t, qdf_print */ +#include /* qdf_spinlock */ +#include /* qdf_atomic_read */ +#include + +/* header files for utilities */ +#include "queue.h" /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_is_high_latency */ +#include + +/* header files for HTT API */ +#include +#include + +/* header files for our own APIs */ +#include +#include +#include +#include +#include +#include +/* header files for our internal definitions */ +#include /* TXRX_ASSERT, etc. */ +#include /* WDI events */ +#include /* ol_tx_ll */ +#include /* ol_rx_deliver */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include /* ol_rx_pn_check, etc. */ +#include /* ol_rx_fwd_check, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_INIT, etc. */ +#include +#include /* ol_tx_discard_target_frms */ +#include /* ol_tx_desc_frame_free */ +#include +#include /* ol_tx_sched_attach, etc. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "wma.h" +#include "hif.h" +#include "hif_main.h" +#include +#ifndef REMOVE_PKT_LOG +#include "pktlog_ac.h" +#endif +#include +#include "epping_main.h" +#include +#include +#include +#include "wlan_qct_sys.h" + +#include +#include +#include "wlan_roam_debug.h" +#include "cfg_ucfg_api.h" +#ifdef DP_SUPPORT_RECOVERY_NOTIFY +#include +#include +#endif + +#define DPT_DEBUGFS_PERMS (QDF_FILE_USR_READ | \ + QDF_FILE_USR_WRITE | \ + QDF_FILE_GRP_READ | \ + QDF_FILE_OTH_READ) + +#define DPT_DEBUGFS_NUMBER_BASE 10 +/** + * enum dpt_set_param_debugfs - dpt set params + * @DPT_SET_PARAM_PROTO_BITMAP : set proto bitmap + * @DPT_SET_PARAM_NR_RECORDS: set num of records + * @DPT_SET_PARAM_VERBOSITY: set verbosity + */ +enum dpt_set_param_debugfs { + DPT_SET_PARAM_PROTO_BITMAP = 1, + DPT_SET_PARAM_NR_RECORDS = 2, + DPT_SET_PARAM_VERBOSITY = 3, + DPT_SET_PARAM_NUM_RECORDS_TO_DUMP = 4, + DPT_SET_PARAM_MAX, +}; + +static void ol_vdev_rx_set_intrabss_fwd(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool val); +uint32_t ol_txrx_get_tx_pending(struct cdp_pdev *pdev_handle); +extern void +ol_txrx_set_wmm_param(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct ol_tx_wmm_param_t wmm_param); + +/* thresh for peer's cached buf queue beyond which the elements are dropped */ +#define OL_TXRX_CACHED_BUFQ_THRESH 128 + +#ifdef DP_SUPPORT_RECOVERY_NOTIFY +static +int ol_peer_recovery_notifier_cb(struct notifier_block *block, + unsigned long state, void *data) +{ + struct qdf_notifer_data *notif_data = data; + qdf_notif_block *notif_block; + struct ol_txrx_peer_t *peer; + struct peer_hang_data hang_data = {0}; + enum peer_debug_id_type dbg_id; + + if (!data || !block) + return -EINVAL; + + notif_block = qdf_container_of(block, qdf_notif_block, notif_block); + + peer = notif_block->priv_data; + if (!peer) + return -EINVAL; + + if (notif_data->offset + sizeof(struct peer_hang_data) > + QDF_WLAN_HANG_FW_OFFSET) + return NOTIFY_STOP_MASK; + + QDF_HANG_EVT_SET_HDR(&hang_data.tlv_header, + HANG_EVT_TAG_DP_PEER_INFO, + QDF_HANG_GET_STRUCT_TLVLEN(struct peer_hang_data)); + + qdf_mem_copy(&hang_data.peer_mac_addr, &peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + + for (dbg_id = 0; dbg_id < PEER_DEBUG_ID_MAX; dbg_id++) + if (qdf_atomic_read(&peer->access_list[dbg_id])) + hang_data.peer_timeout_bitmask |= (1 << dbg_id); + + qdf_mem_copy(notif_data->hang_data + notif_data->offset, + &hang_data, sizeof(struct peer_hang_data)); + notif_data->offset += sizeof(struct peer_hang_data); + + return 0; +} + +static qdf_notif_block ol_peer_recovery_notifier = { + .notif_block.notifier_call = ol_peer_recovery_notifier_cb, +}; + +static +QDF_STATUS ol_register_peer_recovery_notifier(struct ol_txrx_peer_t *peer) +{ + ol_peer_recovery_notifier.priv_data = peer; + + return qdf_hang_event_register_notifier(&ol_peer_recovery_notifier); +} + +static +QDF_STATUS ol_unregister_peer_recovery_notifier(void) +{ + return qdf_hang_event_unregister_notifier(&ol_peer_recovery_notifier); +} +#else +static inline +QDF_STATUS ol_register_peer_recovery_notifier(struct ol_txrx_peer_t *peer) +{ + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS ol_unregister_peer_recovery_notifier(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ol_tx_mark_first_wakeup_packet() - set flag to indicate that + * fw is compatible for marking first packet after wow wakeup + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @value: 1 for enabled/ 0 for disabled + * + * Return: None + */ +static void ol_tx_mark_first_wakeup_packet(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint8_t value) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + htt_mark_first_wakeup_packet(pdev->htt_pdev, value); +} + +/** + * ol_tx_set_is_mgmt_over_wmi_enabled() - set flag to indicate that mgmt over + * wmi is enabled or not. + * @value: 1 for enabled/ 0 for disable + * + * Return: None + */ +void ol_tx_set_is_mgmt_over_wmi_enabled(uint8_t value) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + pdev->is_mgmt_over_wmi_enabled = value; +} + +/** + * ol_tx_get_is_mgmt_over_wmi_enabled() - get value of is_mgmt_over_wmi_enabled + * + * Return: is_mgmt_over_wmi_enabled + */ +uint8_t ol_tx_get_is_mgmt_over_wmi_enabled(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return 0; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return 0; + } + + return pdev->is_mgmt_over_wmi_enabled; +} + + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +static void * +ol_txrx_find_peer_by_addr_and_vdev(struct cdp_pdev *ppdev, + struct cdp_vdev *pvdev, uint8_t *peer_addr) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_vdev_find_hash(pdev, vdev, peer_addr, 0, 1); + if (!peer) + return NULL; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + return peer; +} + +/** + * ol_txrx_get_vdevid() - Get virtual interface id which peer registered + * @soc_hdl - data path soc handle + * @peer_mac - peer mac address + * @vdev_id - virtual interface id which peer registered + * + * Get virtual interface id which peer registered + * + * Return: QDF_STATUS_SUCCESS registration success + * QDF_STATUS_E_NOSUPPORT not support this feature + */ +static QDF_STATUS ol_txrx_get_vdevid(struct cdp_soc_t *soc_hdl, + uint8_t *peer_mac, uint8_t *vdev_id) +{ + uint8_t pdev_id = OL_TXRX_PDEV_ID; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_peer_t *peer = + ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "peer argument is null!!"); + return QDF_STATUS_E_FAILURE; + } + + *vdev_id = peer->vdev->vdev_id; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + + return QDF_STATUS_SUCCESS; +} + +ol_txrx_vdev_handle +ol_txrx_get_vdev_by_peer_addr(struct cdp_pdev *ppdev, + struct qdf_mac_addr peer_addr) +{ + struct ol_txrx_pdev_t *pdev = cdp_pdev_to_ol_txrx_pdev_t(ppdev); + struct ol_txrx_peer_t *peer = NULL; + ol_txrx_vdev_handle vdev; + + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "PDEV not found for peer_addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr.bytes)); + return NULL; + } + + peer = ol_txrx_peer_get_ref_by_addr(pdev, peer_addr.bytes, + PEER_DEBUG_ID_OL_INTERNAL); + + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "Peer not found for peer_addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr.bytes)); + return NULL; + } + + vdev = peer->vdev; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + + return vdev; +} + +/** + * ol_txrx_wrapper_get_vdev_by_peer_addr() - Get vdev handle by peer mac address + * @ppdev - data path device instance + * @peer_addr - peer mac address + * + * Get virtual interface handle by local peer mac address + * + * Return: Virtual interface instance handle + * NULL in case cannot find + */ +static struct cdp_vdev * +ol_txrx_wrapper_get_vdev_by_peer_addr(struct cdp_pdev *ppdev, + struct qdf_mac_addr peer_addr) +{ + return (struct cdp_vdev *)ol_txrx_get_vdev_by_peer_addr(ppdev, + peer_addr); +} + +/* + * ol_txrx_find_peer_exist - find peer if already exists + * @soc_hdl: datapath soc handle + * @pdev_id: physical device instance id + * @peer_mac_addr: peer mac address + * + * Return: true or false + */ +static bool ol_txrx_find_peer_exist(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint8_t *peer_addr) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) + return false; + + return !!ol_txrx_find_peer_by_addr(ol_txrx_pdev_t_to_cdp_pdev(pdev), + peer_addr); +} + +/* + * ol_txrx_find_peer_exist_on_vdev - find if duplicate peer exists + * on the given vdev + * @soc_hdl: datapath soc handle + * @vdev_id: vdev instance id + * @peer_mac_addr: peer mac address + * + * Return: true or false + */ +static bool ol_txrx_find_peer_exist_on_vdev(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + uint8_t *peer_addr) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return false; + + return !!ol_txrx_find_peer_by_addr_and_vdev( + ol_txrx_pdev_t_to_cdp_pdev(vdev->pdev), + ol_txrx_vdev_t_to_cdp_vdev(vdev), + peer_addr); +} + +/* + * ol_txrx_find_peer_exist_on_other_vdev - find if duplicate peer exists + * on other than the given vdev + * @soc_hdl: datapath soc handle + * @vdev_id: vdev instance id + * @peer_mac_addr: peer mac address + * @max_bssid: max number of bssids + * + * Return: true or false + */ +static bool ol_txrx_find_peer_exist_on_other_vdev(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + uint8_t *peer_addr, + uint16_t max_bssid) +{ + int i; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_vdev_t *vdev; + + for (i = 0; i < max_bssid; i++) { + vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, i); + /* Need to check vdevs other than the vdev_id */ + if (vdev_id == i || !vdev) + continue; + if (ol_txrx_find_peer_by_addr_and_vdev( + ol_txrx_pdev_t_to_cdp_pdev(vdev->pdev), + ol_txrx_vdev_t_to_cdp_vdev(vdev), + peer_addr)) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, + "%s: Duplicate peer "QDF_MAC_ADDR_FMT" already exist on vdev %d", + __func__, QDF_MAC_ADDR_REF(peer_addr), i); + return true; + } + } + + return false; +} + +/** + * ol_txrx_find_peer_by_addr() - find peer via peer mac addr and peer_id + * @ppdev: pointer of type cdp_pdev + * @peer_addr: peer mac addr + * + * This function finds a peer with given mac address and returns its peer_id. + * Note that this function does not increment the peer->ref_cnt. + * This means that the peer may be deleted in some other parallel context after + * its been found. + * + * Return: peer handle if peer is found, NULL if peer is not found. + */ +void *ol_txrx_find_peer_by_addr(struct cdp_pdev *ppdev, + uint8_t *peer_addr) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_addr, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) + return NULL; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + return peer; +} + +/** + * ol_txrx_peer_get_ref_by_addr() - get peer ref via peer mac addr and peer_id + * @pdev: pointer of type ol_txrx_pdev_handle + * @peer_addr: peer mac addr + * + * This function finds the peer with given mac address and returns its peer_id. + * Note that this function increments the peer->ref_cnt. + * This makes sure that peer will be valid. This also means the caller needs to + * call the corresponding API - ol_txrx_peer_release_ref to delete the peer + * reference. + * Sample usage: + * { + * //the API call below increments the peer->ref_cnt + * peer = ol_txrx_peer_get_ref_by_addr(pdev, peer_addr, peer_id, dbg_id); + * + * // Once peer usage is done + * + * //the API call below decrements the peer->ref_cnt + * ol_txrx_peer_release_ref(peer, dbg_id); + * } + * + * Return: peer handle if the peer is found, NULL if peer is not found. + */ +ol_txrx_peer_handle ol_txrx_peer_get_ref_by_addr(ol_txrx_pdev_handle pdev, + u8 *peer_addr, + enum peer_debug_id_type dbg_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_addr, 0, 1, + dbg_id); + if (!peer) + return NULL; + + return peer; +} + +/** + * @brief Find a txrx peer handle from a peer's local ID + * @param pdev - the data physical device object + * @param local_peer_id - the ID txrx assigned locally to the peer in question + * @dbg_id - debug_id to track caller + * @return handle to the txrx peer object + * @details + * The control SW typically uses the txrx peer handle to refer to the peer. + * In unusual circumstances, if it is infeasible for the control SW maintain + * the txrx peer handle but it can maintain a small integer local peer ID, + * this function allows the peer handled to be retrieved, based on the local + * peer ID. + * + * Note that this function increments the peer->ref_cnt. + * This makes sure that peer will be valid. This also means the caller needs to + * call the corresponding API - + * ol_txrx_peer_release_ref + * + * reference. + * Sample usage: + * { + * //the API call below increments the peer->ref_cnt + * peer = ol_txrx_peer_get_ref_by_local_id(pdev,local_peer_id, dbg_id); + * + * // Once peer usage is done + * + * //the API call below decrements the peer->ref_cnt + * ol_txrx_peer_release_ref(peer, dbg_id); + * } + * + * Return: peer handle if the peer is found, NULL if peer is not found. + */ +ol_txrx_peer_handle +ol_txrx_peer_get_ref_by_local_id(struct cdp_pdev *ppdev, + uint8_t local_peer_id, + enum peer_debug_id_type dbg_id) +{ + struct ol_txrx_peer_t *peer = NULL; + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + + if ((local_peer_id == OL_TXRX_INVALID_LOCAL_PEER_ID) || + (local_peer_id >= OL_TXRX_NUM_LOCAL_PEER_IDS)) { + return NULL; + } + + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + peer = pdev->local_peer_ids.map[local_peer_id]; + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); + if (peer && peer->valid) + ol_txrx_peer_get_ref(peer, dbg_id); + else + peer = NULL; + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + return peer; +} + +static void ol_txrx_local_peer_id_pool_init(struct ol_txrx_pdev_t *pdev) +{ + int i; + + /* point the freelist to the first ID */ + pdev->local_peer_ids.freelist = 0; + + /* link each ID to the next one */ + for (i = 0; i < OL_TXRX_NUM_LOCAL_PEER_IDS; i++) { + pdev->local_peer_ids.pool[i] = i + 1; + pdev->local_peer_ids.map[i] = NULL; + } + + /* link the last ID to itself, to mark the end of the list */ + i = OL_TXRX_NUM_LOCAL_PEER_IDS; + pdev->local_peer_ids.pool[i] = i; + + qdf_spinlock_create(&pdev->local_peer_ids.lock); +} + +static void +ol_txrx_local_peer_id_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + i = pdev->local_peer_ids.freelist; + if (pdev->local_peer_ids.pool[i] == i) { + /* the list is empty, except for the list-end marker */ + peer->local_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + } else { + /* take the head ID and advance the freelist */ + peer->local_id = i; + pdev->local_peer_ids.freelist = pdev->local_peer_ids.pool[i]; + pdev->local_peer_ids.map[i] = peer; + } + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); +} + +static void +ol_txrx_local_peer_id_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + int i = peer->local_id; + + if ((i == OL_TXRX_INVALID_LOCAL_PEER_ID) || + (i >= OL_TXRX_NUM_LOCAL_PEER_IDS)) { + return; + } + /* put this ID on the head of the freelist */ + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + pdev->local_peer_ids.pool[i] = pdev->local_peer_ids.freelist; + pdev->local_peer_ids.freelist = i; + pdev->local_peer_ids.map[i] = NULL; + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); +} + +static void ol_txrx_local_peer_id_cleanup(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_destroy(&pdev->local_peer_ids.lock); +} + +#else +#define ol_txrx_local_peer_id_pool_init(pdev) /* no-op */ +#define ol_txrx_local_peer_id_alloc(pdev, peer) /* no-op */ +#define ol_txrx_local_peer_id_free(pdev, peer) /* no-op */ +#define ol_txrx_local_peer_id_cleanup(pdev) /* no-op */ +#endif + +#if defined(CONFIG_DP_TRACE) && defined(WLAN_DEBUGFS) +/** + * ol_txrx_read_dpt_buff_debugfs() - read dp trace buffer + * @file: file to read + * @arg: pdev object + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_read_dpt_buff_debugfs(qdf_debugfs_file_t file, + void *arg) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)arg; + uint32_t i = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (pdev->state == QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INVALID) + return QDF_STATUS_E_INVAL; + else if (pdev->state == QDF_DPT_DEBUGFS_STATE_SHOW_COMPLETE) { + pdev->state = QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INIT; + return QDF_STATUS_SUCCESS; + } + + i = qdf_dpt_get_curr_pos_debugfs(file, pdev->state); + status = qdf_dpt_dump_stats_debugfs(file, i); + if (status == QDF_STATUS_E_FAILURE) + pdev->state = QDF_DPT_DEBUGFS_STATE_SHOW_IN_PROGRESS; + else if (status == QDF_STATUS_SUCCESS) + pdev->state = QDF_DPT_DEBUGFS_STATE_SHOW_COMPLETE; + + return status; +} + +/** + * ol_txrx_conv_str_to_int_debugfs() - convert string to int + * @buf: buffer containing string + * @len: buffer len + * @proto_bitmap: defines the protocol to be tracked + * @nr_records: defines the nth packet which is traced + * @verbosity: defines the verbosity level + * + * This function expects char buffer to be null terminated. + * Otherwise results could be unexpected values. + * + * Return: 0 on success + */ +static int ol_txrx_conv_str_to_int_debugfs(char *buf, qdf_size_t len, + int *proto_bitmap, + int *nr_records, + int *verbosity, + int *num_records_to_dump) +{ + int num_value = DPT_SET_PARAM_PROTO_BITMAP; + int ret, param_value = 0; + char *buf_param = buf; + int i; + + for (i = 1; i < DPT_SET_PARAM_MAX; i++) { + /* Loop till you reach space as kstrtoint operates till + * null character. Replace space with null character + * to read each value. + * terminate the loop either at null terminated char or + * len is 0. + */ + while (*buf && len) { + if (*buf == ' ') { + *buf = '\0'; + buf++; + len--; + break; + } + buf++; + len--; + } + /* get the parameter */ + ret = qdf_kstrtoint(buf_param, + DPT_DEBUGFS_NUMBER_BASE, + ¶m_value); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%s: Error while parsing buffer. ret %d", + __func__, ret); + return ret; + } + switch (num_value) { + case DPT_SET_PARAM_PROTO_BITMAP: + *proto_bitmap = param_value; + break; + case DPT_SET_PARAM_NR_RECORDS: + *nr_records = param_value; + break; + case DPT_SET_PARAM_VERBOSITY: + *verbosity = param_value; + break; + case DPT_SET_PARAM_NUM_RECORDS_TO_DUMP: + if (param_value > MAX_QDF_DP_TRACE_RECORDS) + param_value = MAX_QDF_DP_TRACE_RECORDS; + *num_records_to_dump = param_value; + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d: :Set command needs exactly 4 arguments in format .", + __func__, __LINE__); + break; + } + num_value++; + /*buf_param should now point to the next param value. */ + buf_param = buf; + } + + /* buf is not yet NULL implies more than 4 params are passed. */ + if (*buf) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s %d: :Set command needs exactly 4 arguments in format .", + __func__, __LINE__); + return -EINVAL; + } + return 0; +} + +/** + * ol_txrx_write_dpt_buff_debugfs() - set dp trace parameters + * @priv: pdev object + * @buf: buff to get value for dpt parameters + * @len: buf length + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_write_dpt_buff_debugfs(void *priv, + const char *buf, + qdf_size_t len) +{ + int ret; + int proto_bitmap = 0; + int nr_records = 0; + int verbosity = 0; + int num_records_to_dump = 0; + char *buf1 = NULL; + + if (!buf || !len) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: null buffer or len. len %u", + __func__, (uint8_t)len); + return QDF_STATUS_E_FAULT; + } + + buf1 = (char *)qdf_mem_malloc(len); + if (!buf1) + return QDF_STATUS_E_FAULT; + + qdf_mem_copy(buf1, buf, len); + ret = ol_txrx_conv_str_to_int_debugfs(buf1, len, &proto_bitmap, + &nr_records, &verbosity, + &num_records_to_dump); + if (ret) { + qdf_mem_free(buf1); + return QDF_STATUS_E_INVAL; + } + + qdf_dpt_set_value_debugfs(proto_bitmap, nr_records, verbosity, + num_records_to_dump); + qdf_mem_free(buf1); + return QDF_STATUS_SUCCESS; +} + +static int ol_txrx_debugfs_init(struct ol_txrx_pdev_t *pdev) +{ + pdev->dpt_debugfs_fops.show = ol_txrx_read_dpt_buff_debugfs; + pdev->dpt_debugfs_fops.write = ol_txrx_write_dpt_buff_debugfs; + pdev->dpt_debugfs_fops.priv = pdev; + + pdev->dpt_stats_log_dir = qdf_debugfs_create_dir("dpt_stats", NULL); + + if (!pdev->dpt_stats_log_dir) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: error while creating debugfs dir for %s", + __func__, "dpt_stats"); + pdev->state = QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INVALID; + return -EBUSY; + } + + if (!qdf_debugfs_create_file("dump_set_dpt_logs", DPT_DEBUGFS_PERMS, + pdev->dpt_stats_log_dir, + &pdev->dpt_debugfs_fops)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: debug Entry creation failed!", + __func__); + pdev->state = QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INVALID; + return -EBUSY; + } + + pdev->state = QDF_DPT_DEBUGFS_STATE_SHOW_STATE_INIT; + return 0; +} + +static void ol_txrx_debugfs_exit(ol_txrx_pdev_handle pdev) +{ + qdf_debugfs_remove_dir_recursive(pdev->dpt_stats_log_dir); +} +#else +static inline int ol_txrx_debugfs_init(struct ol_txrx_pdev_t *pdev) +{ + return 0; +} + +static inline void ol_txrx_debugfs_exit(ol_txrx_pdev_handle pdev) +{ +} +#endif + +/** + * ol_txrx_pdev_attach() - allocate txrx pdev + * @soc_hdl: datapath soc handle + * @htc_pdev: HTC pdev + * @osdev: os dev + * @pdev_id: pdev identifier for pdev attach + * + * Return: QDF_STATUS_SUCCESS on success + * QDF error code for failure + */ +static QDF_STATUS +ol_txrx_pdev_attach(ol_txrx_soc_handle soc, + struct cdp_pdev_attach_params *params) +{ + struct ol_txrx_soc_t *ol_soc = cdp_soc_t_to_ol_txrx_soc_t(soc); + struct ol_txrx_pdev_t *pdev; + struct cdp_cfg *cfg_pdev = cds_get_context(QDF_MODULE_ID_CFG); + QDF_STATUS status; + int i, tid; + + if (params->pdev_id == OL_TXRX_INVALID_PDEV_ID) + return QDF_STATUS_E_INVAL; + + pdev = qdf_mem_malloc(sizeof(*pdev)); + if (!pdev) { + status = QDF_STATUS_E_NOMEM; + goto fail0; + } + + /* init LL/HL cfg here */ + pdev->cfg.is_high_latency = ol_cfg_is_high_latency(cfg_pdev); + /* + * Credit reporting through HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND + * enabled or not. + */ + pdev->cfg.credit_update_enabled = + ol_cfg_is_credit_update_enabled(cfg_pdev); + + /* Explicitly request TX Completions from FW */ + pdev->cfg.request_tx_comp = cds_is_ptp_rx_opt_enabled() || + cds_is_packet_log_enabled(); + + pdev->cfg.default_tx_comp_req = !ol_cfg_tx_free_at_download(cfg_pdev); + + /* store provided params */ + pdev->ctrl_pdev = cfg_pdev; + pdev->osdev = params->qdf_osdev; + pdev->id = params->pdev_id; + pdev->soc = ol_soc; + ol_soc->pdev_list[params->pdev_id] = pdev; + + for (i = 0; i < htt_num_sec_types; i++) + pdev->sec_types[i] = (enum ol_sec_type)i; + + TXRX_STATS_INIT(pdev); + ol_txrx_tso_stats_init(pdev); + ol_txrx_fw_stats_desc_pool_init(pdev, FW_STATS_DESC_POOL_SIZE); + + TAILQ_INIT(&pdev->vdev_list); + + TAILQ_INIT(&pdev->inactive_peer_list); + + TAILQ_INIT(&pdev->req_list); + pdev->req_list_depth = 0; + qdf_spinlock_create(&pdev->req_list_spinlock); + qdf_spinlock_create(&pdev->tx_mutex); + + /* do initial set up of the peer ID -> peer object lookup map */ + if (ol_txrx_peer_find_attach(pdev)) { + status = QDF_STATUS_E_FAILURE; + goto fail1; + } + + /* initialize the counter of the target's tx buffer availability */ + qdf_atomic_init(&pdev->target_tx_credit); + qdf_atomic_init(&pdev->orig_target_tx_credit); + qdf_atomic_init(&pdev->pad_reserve_tx_credit); + qdf_atomic_add(1, &pdev->pad_reserve_tx_credit); + + if (ol_cfg_is_high_latency(cfg_pdev)) { + qdf_spinlock_create(&pdev->tx_queue_spinlock); + pdev->tx_sched.scheduler = ol_tx_sched_attach(pdev); + if (!pdev->tx_sched.scheduler) { + status = QDF_STATUS_E_FAILURE; + goto fail2; + } + } + ol_txrx_pdev_txq_log_init(pdev); + ol_txrx_pdev_grp_stats_init(pdev); + + pdev->htt_pdev = + htt_pdev_alloc(pdev, cfg_pdev, + params->htc_handle, params->qdf_osdev); + if (!pdev->htt_pdev) { + status = QDF_STATUS_E_FAILURE; + goto fail3; + } + + htt_register_rx_pkt_dump_callback(pdev->htt_pdev, + ol_rx_pkt_dump_call); + + /* + * Init the tid --> category table. + * Regular tids (0-15) map to their AC. + * Extension tids get their own categories. + */ + for (tid = 0; tid < OL_TX_NUM_QOS_TIDS; tid++) { + int ac = TXRX_TID_TO_WMM_AC(tid); + + pdev->tid_to_ac[tid] = ac; + } + pdev->tid_to_ac[OL_TX_NON_QOS_TID] = + OL_TX_SCHED_WRR_ADV_CAT_NON_QOS_DATA; + pdev->tid_to_ac[OL_TX_MGMT_TID] = + OL_TX_SCHED_WRR_ADV_CAT_UCAST_MGMT; + pdev->tid_to_ac[OL_TX_NUM_TIDS + OL_TX_VDEV_MCAST_BCAST] = + OL_TX_SCHED_WRR_ADV_CAT_MCAST_DATA; + pdev->tid_to_ac[OL_TX_NUM_TIDS + OL_TX_VDEV_DEFAULT_MGMT] = + OL_TX_SCHED_WRR_ADV_CAT_MCAST_MGMT; + + if (ol_cfg_is_flow_steering_enabled(pdev->ctrl_pdev)) + pdev->peer_id_unmap_ref_cnt = + TXRX_RFS_ENABLE_PEER_ID_UNMAP_COUNT; + else + pdev->peer_id_unmap_ref_cnt = + TXRX_RFS_DISABLE_PEER_ID_UNMAP_COUNT; + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + pdev->chan_noise_floor = NORMALIZED_TO_NOISE_FLOOR; + + ol_txrx_debugfs_init(pdev); + + return QDF_STATUS_SUCCESS; + +fail3: + ol_txrx_peer_find_detach(pdev); + +fail2: + if (ol_cfg_is_high_latency(cfg_pdev)) + qdf_spinlock_destroy(&pdev->tx_queue_spinlock); + +fail1: + qdf_spinlock_destroy(&pdev->req_list_spinlock); + qdf_spinlock_destroy(&pdev->tx_mutex); + ol_txrx_tso_stats_deinit(pdev); + ol_txrx_fw_stats_desc_pool_deinit(pdev); + qdf_mem_free(pdev); + +fail0: + return status; +} + +#if !defined(REMOVE_PKT_LOG) && !defined(QVIT) +/** + * htt_pkt_log_init() - API to initialize packet log + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @scn: HIF context + * + * Return: void + */ +void htt_pkt_log_init(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, void *scn) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle handle = + ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (handle->pkt_log_init) { + ol_txrx_err("pktlog already initialized"); + return; + } + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + pktlog_sethandle(&handle->pl_dev, scn); + pktlog_set_pdev_id(handle->pl_dev, pdev_id); + pktlog_set_callback_regtype(PKTLOG_DEFAULT_CALLBACK_REGISTRATION); + if (pktlogmod_init(scn)) + qdf_print(" pktlogmod_init failed"); + else + handle->pkt_log_init = true; + } else { + ol_txrx_err("Invalid conn mode: %d", cds_get_conparam()); + } +} + +/** + * htt_pktlogmod_exit() - API to cleanup pktlog info + * @handle: Pdev handle + * @scn: HIF Context + * + * Return: void + */ +static void htt_pktlogmod_exit(struct ol_txrx_pdev_t *handle) +{ + if (!handle->pkt_log_init) { + ol_txrx_err("pktlog is not initialized"); + return; + } + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE && + !QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + pktlogmod_exit(handle); + handle->pkt_log_init = false; + } else { + ol_txrx_err("Invalid conn mode: %d", cds_get_conparam()); + } +} + +#else +void htt_pkt_log_init(struct cdp_soc_t *soc_hdl, uint8_t pdev, void *scn) { } +static void htt_pktlogmod_exit(ol_txrx_pdev_handle handle) { } +#endif + +#ifdef QCA_LL_PDEV_TX_FLOW_CONTROL +/** + * ol_txrx_pdev_set_threshold() - set pdev pool stop/start threshold + * @pdev: txrx pdev + * + * Return: void + */ +static void ol_txrx_pdev_set_threshold(struct ol_txrx_pdev_t *pdev) +{ + uint32_t stop_threshold; + uint32_t start_threshold; + uint16_t desc_pool_size = pdev->tx_desc.pool_size; + + stop_threshold = ol_cfg_get_tx_flow_stop_queue_th(pdev->ctrl_pdev); + start_threshold = stop_threshold + + ol_cfg_get_tx_flow_start_queue_offset(pdev->ctrl_pdev); + pdev->tx_desc.start_th = (start_threshold * desc_pool_size) / 100; + pdev->tx_desc.stop_th = (stop_threshold * desc_pool_size) / 100; + pdev->tx_desc.stop_priority_th = + (TX_PRIORITY_TH * pdev->tx_desc.stop_th) / 100; + if (pdev->tx_desc.stop_priority_th >= MAX_TSO_SEGMENT_DESC) + pdev->tx_desc.stop_priority_th -= MAX_TSO_SEGMENT_DESC; + + pdev->tx_desc.start_priority_th = + (TX_PRIORITY_TH * pdev->tx_desc.start_th) / 100; + if (pdev->tx_desc.start_priority_th >= MAX_TSO_SEGMENT_DESC) + pdev->tx_desc.start_priority_th -= MAX_TSO_SEGMENT_DESC; + pdev->tx_desc.status = FLOW_POOL_ACTIVE_UNPAUSED; +} +#else +static inline void ol_txrx_pdev_set_threshold(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +/** + * ol_txrx_pdev_post_attach() - attach txrx pdev + * @soc_hdl: datapath soc handle + * @pdev_id: physical device instance id + * + * Return: 0 for success + */ +int +ol_txrx_pdev_post_attach(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + uint16_t i; + uint16_t fail_idx = 0; + int ret = 0; + uint16_t desc_pool_size; + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + uint16_t desc_element_size = sizeof(union ol_tx_desc_list_elem_t); + union ol_tx_desc_list_elem_t *c_element; + unsigned int sig_bit; + uint16_t desc_per_page; + + if (!osc || !pdev) { + ret = -EINVAL; + goto ol_attach_fail; + } + + /* + * For LL, limit the number of host's tx descriptors to match + * the number of target FW tx descriptors. + * This simplifies the FW, by ensuring the host will never + * download more tx descriptors than the target has space for. + * The FW will drop/free low-priority tx descriptors when it + * starts to run low, so that in theory the host should never + * run out of tx descriptors. + */ + + /* + * LL - initialize the target credit ourselves. + * HL - wait for a HTT target credit initialization + * during htt_attach. + */ + desc_pool_size = ol_tx_get_desc_global_pool_size(pdev); + ol_tx_init_pdev(pdev); + + ol_tx_desc_dup_detect_init(pdev, desc_pool_size); + + ol_tx_setup_fastpath_ce_handles(osc, pdev); + + if ((ol_txrx_get_new_htt_msg_format(pdev))) + ol_set_cfg_new_htt_format(pdev->ctrl_pdev, true); + else + ol_set_cfg_new_htt_format(pdev->ctrl_pdev, false); + + ret = htt_attach(pdev->htt_pdev, desc_pool_size); + if (ret) + goto htt_attach_fail; + + /* Attach micro controller data path offload resource */ + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) { + ret = htt_ipa_uc_attach(pdev->htt_pdev); + if (ret) + goto uc_attach_fail; + } + + /* Calculate single element reserved size power of 2 */ + pdev->tx_desc.desc_reserved_size = qdf_get_pwr2(desc_element_size); + qdf_mem_multi_pages_alloc(pdev->osdev, &pdev->tx_desc.desc_pages, + pdev->tx_desc.desc_reserved_size, desc_pool_size, 0, true); + if ((0 == pdev->tx_desc.desc_pages.num_pages) || + (!pdev->tx_desc.desc_pages.cacheable_pages)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Page alloc fail"); + ret = -ENOMEM; + goto page_alloc_fail; + } + desc_per_page = pdev->tx_desc.desc_pages.num_element_per_page; + pdev->tx_desc.offset_filter = desc_per_page - 1; + /* Calculate page divider to find page number */ + sig_bit = 0; + while (desc_per_page) { + sig_bit++; + desc_per_page = desc_per_page >> 1; + } + pdev->tx_desc.page_divider = (sig_bit - 1); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "page_divider 0x%x, offset_filter 0x%x num elem %d, ol desc num page %d, ol desc per page %d", + pdev->tx_desc.page_divider, pdev->tx_desc.offset_filter, + desc_pool_size, pdev->tx_desc.desc_pages.num_pages, + pdev->tx_desc.desc_pages.num_element_per_page); + + /* + * Each SW tx desc (used only within the tx datapath SW) has a + * matching HTT tx desc (used for downloading tx meta-data to FW/HW). + * Go ahead and allocate the HTT tx desc and link it with the SW tx + * desc now, to avoid doing it during time-critical transmit. + */ + pdev->tx_desc.pool_size = desc_pool_size; + pdev->tx_desc.freelist = + (union ol_tx_desc_list_elem_t *) + (*pdev->tx_desc.desc_pages.cacheable_pages); + c_element = pdev->tx_desc.freelist; + for (i = 0; i < desc_pool_size; i++) { + void *htt_tx_desc; + void *htt_frag_desc = NULL; + qdf_dma_addr_t frag_paddr = 0; + qdf_dma_addr_t paddr; + + if (i == (desc_pool_size - 1)) + c_element->next = NULL; + else + c_element->next = (union ol_tx_desc_list_elem_t *) + ol_tx_desc_find(pdev, i + 1); + + htt_tx_desc = htt_tx_desc_alloc(pdev->htt_pdev, &paddr, i); + if (!htt_tx_desc) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "%s: failed to alloc HTT tx desc (%d of %d)", + __func__, i, desc_pool_size); + fail_idx = i; + ret = -ENOMEM; + goto desc_alloc_fail; + } + + c_element->tx_desc.htt_tx_desc = htt_tx_desc; + c_element->tx_desc.htt_tx_desc_paddr = paddr; + ret = htt_tx_frag_alloc(pdev->htt_pdev, + i, &frag_paddr, &htt_frag_desc); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: failed to alloc HTT frag dsc (%d/%d)", + __func__, i, desc_pool_size); + /* Is there a leak here, is this handling correct? */ + fail_idx = i; + goto desc_alloc_fail; + } + if (!ret && htt_frag_desc) { + /* + * Initialize the first 6 words (TSO flags) + * of the frag descriptor + */ + memset(htt_frag_desc, 0, 6 * sizeof(uint32_t)); + c_element->tx_desc.htt_frag_desc = htt_frag_desc; + c_element->tx_desc.htt_frag_desc_paddr = frag_paddr; + } +#ifdef QCA_SUPPORT_TXDESC_SANITY_CHECKS + c_element->tx_desc.pkt_type = 0xff; +#ifdef QCA_COMPUTE_TX_DELAY + c_element->tx_desc.entry_timestamp_ticks = + 0xffffffff; +#endif +#endif + c_element->tx_desc.id = i; + qdf_atomic_init(&c_element->tx_desc.ref_cnt); + c_element = c_element->next; + fail_idx = i; + } + + /* link SW tx descs into a freelist */ + pdev->tx_desc.num_free = desc_pool_size; + ol_txrx_dbg("first tx_desc:0x%pK Last tx desc:0x%pK", + (uint32_t *)pdev->tx_desc.freelist, + (uint32_t *)(pdev->tx_desc.freelist + desc_pool_size)); + + ol_txrx_pdev_set_threshold(pdev); + + /* check what format of frames are expected to be delivered by the OS */ + pdev->frame_format = ol_cfg_frame_type(pdev->ctrl_pdev); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) + pdev->htt_pkt_type = htt_pkt_type_native_wifi; + else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (ol_cfg_is_ce_classify_enabled(pdev->ctrl_pdev)) + pdev->htt_pkt_type = htt_pkt_type_eth2; + else + pdev->htt_pkt_type = htt_pkt_type_ethernet; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s Invalid standard frame type: %d", + __func__, pdev->frame_format); + ret = -EINVAL; + goto control_init_fail; + } + + /* setup the global rx defrag waitlist */ + TAILQ_INIT(&pdev->rx.defrag.waitlist); + + /* configure where defrag timeout and duplicate detection is handled */ + pdev->rx.flags.defrag_timeout_check = + pdev->rx.flags.dup_check = + ol_cfg_rx_host_defrag_timeout_duplicate_check(pdev->ctrl_pdev); + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* Need to revisit this part. Currently,hardcode to riva's caps */ + pdev->target_tx_tran_caps = wlan_frm_tran_cap_raw; + pdev->target_rx_tran_caps = wlan_frm_tran_cap_raw; + /* + * The Riva HW de-aggregate doesn't have capability to generate 802.11 + * header for non-first subframe of A-MSDU. + */ + pdev->sw_subfrm_hdr_recovery_enable = 1; + /* + * The Riva HW doesn't have the capability to set Protected Frame bit + * in the MAC header for encrypted data frame. + */ + pdev->sw_pf_proc_enable = 1; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + /* + * sw llc process is only needed in + * 802.3 to 802.11 transform case + */ + pdev->sw_tx_llc_proc_enable = 1; + pdev->sw_rx_llc_proc_enable = 1; + } else { + pdev->sw_tx_llc_proc_enable = 0; + pdev->sw_rx_llc_proc_enable = 0; + } + + switch (pdev->frame_format) { + case wlan_frm_fmt_raw: + pdev->sw_tx_encap = + pdev->target_tx_tran_caps & wlan_frm_tran_cap_raw + ? 0 : 1; + pdev->sw_rx_decap = + pdev->target_rx_tran_caps & wlan_frm_tran_cap_raw + ? 0 : 1; + break; + case wlan_frm_fmt_native_wifi: + pdev->sw_tx_encap = + pdev-> + target_tx_tran_caps & wlan_frm_tran_cap_native_wifi + ? 0 : 1; + pdev->sw_rx_decap = + pdev-> + target_rx_tran_caps & wlan_frm_tran_cap_native_wifi + ? 0 : 1; + break; + case wlan_frm_fmt_802_3: + pdev->sw_tx_encap = + pdev->target_tx_tran_caps & wlan_frm_tran_cap_8023 + ? 0 : 1; + pdev->sw_rx_decap = + pdev->target_rx_tran_caps & wlan_frm_tran_cap_8023 + ? 0 : 1; + break; + default: + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid std frame type; [en/de]cap: f:%x t:%x r:%x", + pdev->frame_format, + pdev->target_tx_tran_caps, pdev->target_rx_tran_caps); + ret = -EINVAL; + goto control_init_fail; + } +#endif + + /* + * Determine what rx processing steps are done within the host. + * Possibilities: + * 1. Nothing - rx->tx forwarding and rx PN entirely within target. + * (This is unlikely; even if the target is doing rx->tx forwarding, + * the host should be doing rx->tx forwarding too, as a back up for + * the target's rx->tx forwarding, in case the target runs short on + * memory, and can't store rx->tx frames that are waiting for + * missing prior rx frames to arrive.) + * 2. Just rx -> tx forwarding. + * This is the typical configuration for HL, and a likely + * configuration for LL STA or small APs (e.g. retail APs). + * 3. Both PN check and rx -> tx forwarding. + * This is the typical configuration for large LL APs. + * Host-side PN check without rx->tx forwarding is not a valid + * configuration, since the PN check needs to be done prior to + * the rx->tx forwarding. + */ + if (ol_cfg_is_full_reorder_offload(pdev->ctrl_pdev)) { + /* + * PN check, rx-tx forwarding and rx reorder is done by + * the target + */ + if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) + pdev->rx_opt_proc = ol_rx_in_order_deliver; + else + pdev->rx_opt_proc = ol_rx_fwd_check; + } else { + if (ol_cfg_rx_pn_check(pdev->ctrl_pdev)) { + if (ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) { + /* + * PN check done on host, + * rx->tx forwarding not done at all. + */ + pdev->rx_opt_proc = ol_rx_pn_check_only; + } else if (ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) { + /* + * Both PN check and rx->tx forwarding done + * on host. + */ + pdev->rx_opt_proc = ol_rx_pn_check; + } else { +#define TRACESTR01 "invalid config: if rx PN check is on the host,"\ +"rx->tx forwarding check needs to also be on the host" + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + "%s: %s", __func__, TRACESTR01); +#undef TRACESTR01 + ret = -EINVAL; + goto control_init_fail; + } + } else { + /* PN check done on target */ + if ((!ol_cfg_rx_fwd_disabled(pdev->ctrl_pdev)) && + ol_cfg_rx_fwd_check(pdev->ctrl_pdev)) { + /* + * rx->tx forwarding done on host (possibly as + * back-up for target-side primary rx->tx + * forwarding) + */ + pdev->rx_opt_proc = ol_rx_fwd_check; + } else { + /* + * rx->tx forwarding either done in target, + * or not done at all + */ + pdev->rx_opt_proc = ol_rx_deliver; + } + } + } + + /* initialize mutexes for tx desc alloc and peer lookup */ + qdf_spinlock_create(&pdev->peer_ref_mutex); + qdf_spinlock_create(&pdev->rx.mutex); + qdf_spinlock_create(&pdev->last_real_peer_mutex); + qdf_spinlock_create(&pdev->peer_map_unmap_lock); + OL_TXRX_PEER_STATS_MUTEX_INIT(pdev); + + if (OL_RX_REORDER_TRACE_ATTACH(pdev) != A_OK) { + ret = -ENOMEM; + goto reorder_trace_attach_fail; + } + + if (OL_RX_PN_TRACE_ATTACH(pdev) != A_OK) { + ret = -ENOMEM; + goto pn_trace_attach_fail; + } + + /* + * WDI event attach + */ + wdi_event_attach(pdev); + + /* + * Initialize rx PN check characteristics for different security types. + */ + qdf_mem_zero(&pdev->rx_pn[0], sizeof(pdev->rx_pn)); + + /* TKIP: 48-bit TSC, CCMP: 48-bit PN */ + pdev->rx_pn[htt_sec_type_tkip].len = + pdev->rx_pn[htt_sec_type_tkip_nomic].len = + pdev->rx_pn[htt_sec_type_aes_ccmp].len = 48; + + pdev->rx_pn[htt_sec_type_aes_ccmp_256].len = + pdev->rx_pn[htt_sec_type_aes_gcmp].len = + pdev->rx_pn[htt_sec_type_aes_gcmp_256].len = 48; + + pdev->rx_pn[htt_sec_type_tkip].cmp = + pdev->rx_pn[htt_sec_type_tkip_nomic].cmp = + pdev->rx_pn[htt_sec_type_aes_ccmp].cmp = ol_rx_pn_cmp48; + + pdev->rx_pn[htt_sec_type_aes_ccmp_256].cmp = + pdev->rx_pn[htt_sec_type_aes_gcmp].cmp = + pdev->rx_pn[htt_sec_type_aes_gcmp_256].cmp = ol_rx_pn_cmp48; + + /* WAPI: 128-bit PN */ + pdev->rx_pn[htt_sec_type_wapi].len = 128; + pdev->rx_pn[htt_sec_type_wapi].cmp = ol_rx_pn_wapi_cmp; + + OL_RX_REORDER_TIMEOUT_INIT(pdev); + + ol_txrx_dbg("Created pdev %pK", pdev); + + pdev->cfg.host_addba = ol_cfg_host_addba(pdev->ctrl_pdev); + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +#define OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT 3 + +/* #if 1 -- TODO: clean this up */ +#define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT \ + /* avg = 100% * new + 0% * old */ \ + (1 << OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT) +/* + * #else + * #define OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT + * //avg = 25% * new + 25% * old + * (1 << (OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT-2)) + * #endif + */ + pdev->rssi_update_shift = OL_TXRX_RSSI_UPDATE_SHIFT_DEFAULT; + pdev->rssi_new_weight = OL_TXRX_RSSI_NEW_WEIGHT_DEFAULT; +#endif + + ol_txrx_local_peer_id_pool_init(pdev); + + pdev->cfg.ll_pause_txq_limit = + ol_tx_cfg_max_tx_queue_depth_ll(pdev->ctrl_pdev); + + /* TX flow control for peer who is in very bad link status */ + ol_tx_badpeer_flow_cl_init(pdev); + +#ifdef QCA_COMPUTE_TX_DELAY + qdf_mem_zero(&pdev->tx_delay, sizeof(pdev->tx_delay)); + qdf_spinlock_create(&pdev->tx_delay.mutex); + + /* initialize compute interval with 5 seconds (ESE default) */ + pdev->tx_delay.avg_period_ticks = qdf_system_msecs_to_ticks(5000); + { + uint32_t bin_width_1000ticks; + + bin_width_1000ticks = + qdf_system_msecs_to_ticks + (QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS + * 1000); + /* + * Compute a factor and shift that together are equal to the + * inverse of the bin_width time, so that rather than dividing + * by the bin width time, approximately the same result can be + * obtained much more efficiently by a multiply + shift. + * multiply_factor >> shift = 1 / bin_width_time, so + * multiply_factor = (1 << shift) / bin_width_time. + * + * Pick the shift semi-arbitrarily. + * If we knew statically what the bin_width would be, we could + * choose a shift that minimizes the error. + * Since the bin_width is determined dynamically, simply use a + * shift that is about half of the uint32_t size. This should + * result in a relatively large multiplier value, which + * minimizes error from rounding the multiplier to an integer. + * The rounding error only becomes significant if the tick units + * are on the order of 1 microsecond. In most systems, it is + * expected that the tick units will be relatively low-res, + * on the order of 1 millisecond. In such systems the rounding + * error is negligible. + * It would be more accurate to dynamically try out different + * shifts and choose the one that results in the smallest + * rounding error, but that extra level of fidelity is + * not needed. + */ + pdev->tx_delay.hist_internal_bin_width_shift = 16; + pdev->tx_delay.hist_internal_bin_width_mult = + ((1 << pdev->tx_delay.hist_internal_bin_width_shift) * + 1000 + (bin_width_1000ticks >> 1)) / + bin_width_1000ticks; + } +#endif /* QCA_COMPUTE_TX_DELAY */ + + /* Thermal Mitigation */ + ol_tx_throttle_init(pdev); + + ol_tso_seg_list_init(pdev, desc_pool_size); + + ol_tso_num_seg_list_init(pdev, desc_pool_size); + + ol_tx_register_flow_control(pdev); + + return 0; /* success */ + +pn_trace_attach_fail: + OL_RX_REORDER_TRACE_DETACH(pdev); + +reorder_trace_attach_fail: + qdf_spinlock_destroy(&pdev->peer_ref_mutex); + qdf_spinlock_destroy(&pdev->rx.mutex); + qdf_spinlock_destroy(&pdev->last_real_peer_mutex); + qdf_spinlock_destroy(&pdev->peer_map_unmap_lock); + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); + +control_init_fail: +desc_alloc_fail: + for (i = 0; i < fail_idx; i++) + htt_tx_desc_free(pdev->htt_pdev, + (ol_tx_desc_find(pdev, i))->htt_tx_desc); + + qdf_mem_multi_pages_free(pdev->osdev, + &pdev->tx_desc.desc_pages, 0, true); + +page_alloc_fail: + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + htt_ipa_uc_detach(pdev->htt_pdev); +uc_attach_fail: + htt_detach(pdev->htt_pdev); +htt_attach_fail: + ol_tx_desc_dup_detect_deinit(pdev); +ol_attach_fail: + return ret; /* fail */ +} + +/** + * ol_txrx_pdev_attach_target() - send target configuration + * + * @soc_hdl - data path soc handle + * @pdev_id - device instance id + * + * The majority of the data SW setup are done by the pdev_attach + * functions, but this function completes the data SW setup by + * sending datapath configuration messages to the target. + * + * Return: 0 - success 1 - failure + */ +static int ol_txrx_pdev_attach_target(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) + return QDF_STATUS_E_FAULT; + + return htt_attach_target(pdev->htt_pdev) == QDF_STATUS_SUCCESS ? 0:1; +} + +/** + * ol_tx_free_descs_inuse - free tx descriptors which are in use + * @pdev - the physical device for which tx descs need to be freed + * + * Cycle through the list of TX descriptors (for a pdev) which are in use, + * for which TX completion has not been received and free them. Should be + * called only when the interrupts are off and all lower layer RX is stopped. + * Otherwise there may be a race condition with TX completions. + * + * Return: None + */ +static void ol_tx_free_descs_inuse(ol_txrx_pdev_handle pdev) +{ + int i; + void *htt_tx_desc; + struct ol_tx_desc_t *tx_desc; + int num_freed_tx_desc = 0; + + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + /* + * Confirm that each tx descriptor is "empty", i.e. it has + * no tx frame attached. + * In particular, check that there are no frames that have + * been given to the target to transmit, for which the + * target has never provided a response. + * + * Rome supports mgmt Tx via HTT interface, not via WMI. + * When mgmt frame is sent, 2 tx desc is allocated: + * mgmt_txrx_desc is allocated in wlan_mgmt_txrx_mgmt_frame_tx, + * ol_tx_desc is allocated in ol_txrx_mgmt_send_ext. + * They point to same net buffer. + * net buffer is mapped in htt_tx_desc_init. + * + * When SSR during Rome STA connected, deauth frame is sent, + * but no tx complete since firmware hung already. + * Pending mgmt frames are unmapped and freed when destroy + * vdev. + * hdd_reset_all_adapters->hdd_stop_adapter->hdd_vdev_destroy + * ->wma_handle_vdev_detach->wlan_mgmt_txrx_vdev_drain + * ->wma_mgmt_frame_fill_peer_cb + * ->mgmt_txrx_tx_completion_handler. + * + * Don't need unmap and free net buffer of mgmt frames again + * during data path clean up, just free ol_tx_desc. + * hdd_wlan_stop_modules->cds_post_disable->cdp_pdev_pre_detach + * ->ol_txrx_pdev_pre_detach->ol_tx_free_descs_inuse. + */ + if (qdf_atomic_read(&tx_desc->ref_cnt)) { + if (!ol_tx_get_is_mgmt_over_wmi_enabled() && + tx_desc->pkt_type >= OL_TXRX_MGMT_TYPE_BASE) { + qdf_atomic_init(&tx_desc->ref_cnt); + ol_txrx_dbg("Pending mgmt frames nbuf unmapped and freed already when vdev destroyed"); + /* free the tx desc */ + ol_tx_desc_free(pdev, tx_desc); + } else { + ol_txrx_dbg("Warning: freeing tx frame (no compltn)"); + ol_tx_desc_frame_free_nonstd(pdev, tx_desc, 1); + } + num_freed_tx_desc++; + } + htt_tx_desc = tx_desc->htt_tx_desc; + htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc); + } + + if (num_freed_tx_desc) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "freed %d tx frames for which no resp from target", + num_freed_tx_desc); + +} + +/** + * ol_txrx_pdev_pre_detach() - detach the data SW state + * @soc_hdl - datapath soc handle + * @pdev_id - the data physical device id being removed + * @force - delete the pdev (and its vdevs and peers) even if + * there are outstanding references by the target to the vdevs + * and peers within the pdev + * + * This function is used when the WLAN driver is being removed to + * detach the host data component within the driver. + * + * Return: none + */ +static void ol_txrx_pdev_pre_detach(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int force) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + + /* preconditions */ + TXRX_ASSERT2(pdev); + + /* check that the pdev has no vdevs allocated */ + TXRX_ASSERT1(TAILQ_EMPTY(&pdev->vdev_list)); + +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + qdf_timer_stop(&pdev->tx_throttle.phase_timer); + qdf_timer_free(&pdev->tx_throttle.phase_timer); +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + qdf_timer_stop(&pdev->tx_throttle.tx_timer); + qdf_timer_free(&pdev->tx_throttle.tx_timer); +#endif +#endif + + if (force) { + /* + * The assertion above confirms that all vdevs within this pdev + * were detached. However, they may not have actually been + * deleted. + * If the vdev had peers which never received a PEER_UNMAP msg + * from the target, then there are still zombie peer objects, + * and the vdev parents of the zombie peers are also zombies, + * hanging around until their final peer gets deleted. + * Go through the peer hash table and delete any peers left. + * As a side effect, this will complete the deletion of any + * vdevs that are waiting for their peers to finish deletion. + */ + ol_txrx_dbg("Force delete for pdev %pK", + pdev); + ol_txrx_peer_find_hash_erase(pdev); + ol_txrx_peer_free_inactive_list(pdev); + } + + /* to get flow pool status before freeing descs */ + ol_tx_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); + ol_tx_free_descs_inuse(pdev); + ol_tx_deregister_flow_control(pdev); + + /* + * ol_tso_seg_list_deinit should happen after + * ol_tx_deinit_tx_desc_inuse as it tries to access the tso seg freelist + * which is being de-initilized in ol_tso_seg_list_deinit + */ + ol_tso_seg_list_deinit(pdev); + ol_tso_num_seg_list_deinit(pdev); + + /* Stop the communication between HTT and target at first */ + htt_detach_target(pdev->htt_pdev); + + qdf_mem_multi_pages_free(pdev->osdev, + &pdev->tx_desc.desc_pages, 0, true); + pdev->tx_desc.freelist = NULL; + + /* Detach micro controller data path offload resource */ + if (ol_cfg_ipa_uc_offload_enabled(pdev->ctrl_pdev)) + htt_ipa_uc_detach(pdev->htt_pdev); + + htt_detach(pdev->htt_pdev); + ol_tx_desc_dup_detect_deinit(pdev); + + qdf_spinlock_destroy(&pdev->peer_ref_mutex); + qdf_spinlock_destroy(&pdev->last_real_peer_mutex); + qdf_spinlock_destroy(&pdev->rx.mutex); + qdf_spinlock_destroy(&pdev->peer_map_unmap_lock); +#ifdef QCA_SUPPORT_TX_THROTTLE + /* Thermal Mitigation */ + qdf_spinlock_destroy(&pdev->tx_throttle.mutex); +#endif + + /* TX flow control for peer who is in very bad link status */ + ol_tx_badpeer_flow_cl_deinit(pdev); + + OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev); + + OL_RX_REORDER_TRACE_DETACH(pdev); + OL_RX_PN_TRACE_DETACH(pdev); + + htt_pktlogmod_exit(pdev); + + /* + * WDI event detach + */ + wdi_event_detach(pdev); + + ol_txrx_local_peer_id_cleanup(pdev); + +#ifdef QCA_COMPUTE_TX_DELAY + qdf_spinlock_destroy(&pdev->tx_delay.mutex); +#endif + + return; +} + +/** + * ol_txrx_pdev_detach() - delete the data SW state + * @soc_hdl - data path soc handle + * @pdev_id - device instance id + * @force - delete the pdev (and its vdevs and peers) even if + * there are outstanding references by the target to the vdevs + * and peers within the pdev + * + * This function is used when the WLAN driver is being removed to + * remove the host data component within the driver. + * All virtual devices within the physical device need to be deleted + * (ol_txrx_vdev_detach) before the physical device itself is deleted. + * + * Return: Success or Failure + */ +static QDF_STATUS ol_txrx_pdev_detach(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + int force) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + struct ol_txrx_stats_req_internal *req, *temp_req; + int i = 0; + + if (!soc) { + ol_txrx_err("soc is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /*checking to ensure txrx pdev structure is not NULL */ + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + qdf_spin_lock_bh(&pdev->req_list_spinlock); + if (pdev->req_list_depth > 0) + ol_txrx_err( + "Warning: the txrx req list is not empty, depth=%d", + pdev->req_list_depth + ); + TAILQ_FOREACH_SAFE(req, &pdev->req_list, req_list_elem, temp_req) { + TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); + pdev->req_list_depth--; + ol_txrx_err( + "%d: %pK,verbose(%d), concise(%d), up_m(0x%x), reset_m(0x%x)", + i++, + req, + req->base.print.verbose, + req->base.print.concise, + req->base.stats_type_upload_mask, + req->base.stats_type_reset_mask + ); + qdf_mem_free(req); + } + qdf_spin_unlock_bh(&pdev->req_list_spinlock); + + qdf_spinlock_destroy(&pdev->req_list_spinlock); + qdf_spinlock_destroy(&pdev->tx_mutex); + + OL_RX_REORDER_TIMEOUT_CLEANUP(pdev); + + if (pdev->cfg.is_high_latency) + ol_tx_sched_detach(pdev); + + htt_deregister_rx_pkt_dump_callback(pdev->htt_pdev); + + htt_pdev_free(pdev->htt_pdev); + ol_txrx_peer_find_detach(pdev); + ol_txrx_tso_stats_deinit(pdev); + ol_txrx_fw_stats_desc_pool_deinit(pdev); + + ol_txrx_pdev_txq_log_destroy(pdev); + ol_txrx_pdev_grp_stat_destroy(pdev); + + ol_txrx_debugfs_exit(pdev); + ol_unregister_peer_recovery_notifier(); + + soc->pdev_list[pdev->id] = NULL; + qdf_mem_free(pdev); + + return QDF_STATUS_SUCCESS; +} + +#if defined(QCA_HL_NETDEV_FLOW_CONTROL) + +/** + * ol_txrx_vdev_per_vdev_tx_desc_init() - initialise per vdev tx desc count + * related variables. + * @vdev: the virtual device object + * + * Return: None + */ +static inline void +ol_txrx_vdev_per_vdev_tx_desc_init(struct ol_txrx_vdev_t *vdev) +{ + qdf_atomic_init(&vdev->tx_desc_count); + vdev->tx_desc_limit = 0; + vdev->queue_restart_th = 0; + vdev->prio_q_paused = 0; + vdev->queue_stop_th = 0; +} +#else + +static inline void +ol_txrx_vdev_per_vdev_tx_desc_init(struct ol_txrx_vdev_t *vdev) +{ +} +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +/** + * ol_txrx_vdev_attach - Allocate and initialize the data object + * for a new virtual device. + * + * @@soc_hdl - data path soc handle + * @pdev_id - physical device instance id + * @vdev_mac_addr - the MAC address of the virtual device + * @vdev_id - the ID used to identify the virtual device to the target + * @op_mode - whether this virtual device is operating as an AP, + * an IBSS, or a STA + * @subtype: Subtype of the operating vdev + * + * Return: QDF_STATUS_SUCCESS on success, + QDF error code on failure + */ +static QDF_STATUS +ol_txrx_vdev_attach(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct cdp_vdev_info *vdev_info) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + uint8_t *vdev_mac_addr = vdev_info->vdev_mac_addr; + uint8_t vdev_id = vdev_info->vdev_id; + enum wlan_op_mode op_mode = vdev_info->op_mode; + enum wlan_op_subtype subtype = vdev_info->subtype; + enum QDF_OPMODE qdf_opmode = vdev_info->qdf_opmode; + + struct ol_txrx_vdev_t *vdev; + QDF_STATUS qdf_status; + + /* preconditions */ + TXRX_ASSERT2(pdev); + TXRX_ASSERT2(vdev_mac_addr); + + if (qdf_unlikely(!soc)) { + ol_txrx_err("soc is NULL"); + return QDF_STATUS_E_INVAL; + } + + vdev = qdf_mem_malloc(sizeof(*vdev)); + if (!vdev) + return QDF_STATUS_E_NOMEM; /* failure */ + + /* store provided params */ + vdev->pdev = pdev; + vdev->vdev_id = vdev_id; + vdev->opmode = op_mode; + vdev->subtype = subtype; + vdev->qdf_opmode = qdf_opmode; + + vdev->delete.pending = 0; + vdev->safemode = 0; + vdev->drop_unenc = 1; + vdev->num_filters = 0; + vdev->fwd_tx_packets = 0; + vdev->fwd_rx_packets = 0; + + ol_txrx_vdev_per_vdev_tx_desc_init(vdev); + + qdf_mem_copy(&vdev->mac_addr.raw[0], vdev_mac_addr, + QDF_MAC_ADDR_SIZE); + + TAILQ_INIT(&vdev->peer_list); + vdev->last_real_peer = NULL; + +#ifdef QCA_IBSS_SUPPORT + vdev->ibss_peer_num = 0; + vdev->ibss_peer_heart_beat_timer = 0; +#endif + + ol_txrx_vdev_txqs_init(vdev); + + qdf_spinlock_create(&vdev->ll_pause.mutex); + vdev->ll_pause.paused_reason = 0; + vdev->ll_pause.txq.head = vdev->ll_pause.txq.tail = NULL; + vdev->ll_pause.txq.depth = 0; + qdf_atomic_init(&vdev->delete.detaching); + qdf_timer_init(pdev->osdev, + &vdev->ll_pause.timer, + ol_tx_vdev_ll_pause_queue_send, vdev, + QDF_TIMER_TYPE_SW); + qdf_atomic_init(&vdev->os_q_paused); + qdf_atomic_set(&vdev->os_q_paused, 0); + vdev->tx_fl_lwm = 0; + vdev->tx_fl_hwm = 0; + vdev->rx = NULL; + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + qdf_mem_zero(&vdev->last_peer_mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + qdf_spinlock_create(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_flow_control_is_pause = NULL; + vdev->osif_fc_ctx = NULL; + + vdev->txrx_stats.txack_success = 0; + vdev->txrx_stats.txack_failed = 0; + + vdev->bundling_required = false; + qdf_spinlock_create(&vdev->bundle_queue.mutex); + vdev->bundle_queue.txq.head = NULL; + vdev->bundle_queue.txq.tail = NULL; + vdev->bundle_queue.txq.depth = 0; + qdf_timer_init( + pdev->osdev, + &vdev->bundle_queue.timer, + ol_tx_hl_vdev_bundle_timer, + vdev, QDF_TIMER_TYPE_SW); + + /* Default MAX Q depth for every VDEV */ + vdev->ll_pause.max_q_depth = + ol_tx_cfg_max_tx_queue_depth_ll(vdev->pdev->ctrl_pdev); + qdf_status = qdf_event_create(&vdev->wait_delete_comp); + + ol_txrx_vdev_init_tcp_del_ack(vdev); + + /* add this vdev into the pdev's list */ + TAILQ_INSERT_TAIL(&pdev->vdev_list, vdev, vdev_list_elem); + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) + pdev->monitor_vdev = vdev; + + ol_txrx_hl_tdls_flag_reset(soc_hdl, vdev_id, false); + + ol_txrx_dbg( + "Created vdev %pK ("QDF_MAC_ADDR_FMT")", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + + /* + * We've verified that htt_op_mode == wlan_op_mode, + * so no translation is needed. + */ + htt_vdev_attach(pdev->htt_pdev, vdev_id, op_mode); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_vdev_register - Link a vdev's data object with the + * matching OS shim vdev object. + * + * @soc_hdl: datapath soc handle + * @vdev_id: the virtual device's id + * @osif_vdev: the virtual device's OS shim object + * @txrx_ops: (pointers to)functions used for tx and rx data xfer + * + * The data object for a virtual device is created by the + * function ol_txrx_vdev_attach. However, rather than fully + * linking the data vdev object with the vdev objects from the + * other subsystems that the data vdev object interacts with, + * the txrx_vdev_attach function focuses primarily on creating + * the data vdev object. After the creation of both the data + * vdev object and the OS shim vdev object, this + * txrx_osif_vdev_attach function is used to connect the two + * vdev objects, so the data SW can use the OS shim vdev handle + * when passing rx data received by a vdev up to the OS shim. + */ +static QDF_STATUS ol_txrx_vdev_register(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + ol_osif_vdev_handle osif_vdev, + struct ol_txrx_ops *txrx_ops) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (qdf_unlikely(!vdev) || qdf_unlikely(!txrx_ops)) { + qdf_print("vdev/txrx_ops is NULL!"); + qdf_assert(0); + return QDF_STATUS_E_FAILURE; + } + + vdev->osif_dev = osif_vdev; + vdev->rx = txrx_ops->rx.rx; + vdev->stats_rx = txrx_ops->rx.stats_rx; + vdev->tx_comp = txrx_ops->tx.tx_comp; + vdev->vdev_del_notify = txrx_ops->vdev_del_notify; + txrx_ops->tx.tx = ol_tx_data; + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_set_privacy_filters - set the privacy filter + * @vdev - the data virtual device object + * @filter - filters to be set + * @num - the number of filters + * + * Rx related. Set the privacy filters. When rx packets, check + * the ether type, filter type and packet type to decide whether + * discard these packets. + */ +static void +ol_txrx_set_privacy_filters(ol_txrx_vdev_handle vdev, + void *filters, uint32_t num) +{ + qdf_mem_copy(vdev->privacy_filters, filters, + num * sizeof(struct privacy_exemption)); + vdev->num_filters = num; +} + +#if defined(CONFIG_HL_SUPPORT) || defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) + +static void +ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + int i; + struct ol_tx_desc_t *tx_desc; + + qdf_spin_lock_bh(&pdev->tx_mutex); + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + if (tx_desc->vdev == vdev) + tx_desc->vdev = NULL; + } + qdf_spin_unlock_bh(&pdev->tx_mutex); +} + +#else +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +static void ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ol_tx_flow_pool_t *pool; + int i; + struct ol_tx_desc_t *tx_desc; + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + for (i = 0; i < pdev->tx_desc.pool_size; i++) { + tx_desc = ol_tx_desc_find(pdev, i); + if (!qdf_atomic_read(&tx_desc->ref_cnt)) + /* not in use */ + continue; + + pool = tx_desc->pool; + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (tx_desc->vdev == vdev) + tx_desc->vdev = NULL; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); +} + +#else +static void +ol_txrx_tx_desc_reset_vdev(ol_txrx_vdev_handle vdev) +{ +} +#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ +#endif /* CONFIG_HL_SUPPORT */ + +/** + * ol_txrx_vdev_detach - Deallocate the specified data virtual + * device object. + * @soc_hdl - data path soc handle + * @vdev_id: vdev id + * @callback: function to call (if non-NULL) once the vdev has + * been wholly deleted + * @callback_context: context to provide in the callback + * + * All peers associated with the virtual device need to be deleted + * (ol_txrx_peer_detach) before the virtual device itself is deleted. + * However, for the peers to be fully deleted, the peer deletion has to + * percolate through the target data FW and back up to the host data SW. + * Thus, even though the host control SW may have issued a peer_detach + * call for each of the vdev's peers, the peer objects may still be + * allocated, pending removal of all references to them by the target FW. + * In this case, though the vdev_detach function call will still return + * immediately, the vdev itself won't actually be deleted, until the + * deletions of all its peers complete. + * The caller can provide a callback function pointer to be notified when + * the vdev deletion actually happens - whether it's directly within the + * vdev_detach call, or if it's deferred until all in-progress peer + * deletions have completed. + */ +static QDF_STATUS +ol_txrx_vdev_detach(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + ol_txrx_vdev_delete_cb callback, void *context) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + struct ol_txrx_pdev_t *pdev; + ol_txrx_vdev_delete_cb vdev_del_notify; + void *vdev_del_context; + + if (qdf_unlikely(!vdev)) + return QDF_STATUS_E_FAILURE; + + /* preconditions */ + TXRX_ASSERT2(vdev); + pdev = vdev->pdev; + + /* prevent anyone from restarting the ll_pause timer again */ + qdf_atomic_set(&vdev->delete.detaching, 1); + + vdev_del_notify = vdev->vdev_del_notify; + vdev_del_context = vdev->osif_dev; + ol_txrx_vdev_tx_queue_free(vdev); + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + qdf_timer_stop(&vdev->ll_pause.timer); + vdev->ll_pause.is_q_timer_on = false; + while (vdev->ll_pause.txq.head) { + qdf_nbuf_t next = qdf_nbuf_next(vdev->ll_pause.txq.head); + + qdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL); + qdf_nbuf_tx_free(vdev->ll_pause.txq.head, QDF_NBUF_PKT_ERROR); + vdev->ll_pause.txq.head = next; + } + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + /* ll_pause timer should be deleted without any locks held, and + * no timer function should be executed after this point because + * qdf_timer_free is deleting the timer synchronously. + */ + qdf_timer_free(&vdev->ll_pause.timer); + qdf_spinlock_destroy(&vdev->ll_pause.mutex); + + qdf_timer_free(&vdev->bundle_queue.timer); + qdf_spinlock_destroy(&vdev->bundle_queue.mutex); + + qdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_flow_control_is_pause = NULL; + vdev->osif_fc_ctx = NULL; + qdf_spin_unlock_bh(&vdev->flow_control_lock); + qdf_spinlock_destroy(&vdev->flow_control_lock); + + /* remove the vdev from its parent pdev's list */ + TAILQ_REMOVE(&pdev->vdev_list, vdev, vdev_list_elem); + + /* + * Use peer_ref_mutex while accessing peer_list, in case + * a peer is in the process of being removed from the list. + */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* check that the vdev has no peers allocated */ + if (!TAILQ_EMPTY(&vdev->peer_list)) { + /* debug print - will be removed later */ + ol_txrx_dbg( + "not deleting vdev object %pK ("QDF_MAC_ADDR_FMT") until deletion finishes for all its peers", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + /* indicate that the vdev needs to be deleted */ + vdev->delete.pending = 1; + vdev->delete.callback = callback; + vdev->delete.context = context; + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return QDF_STATUS_E_FAILURE; + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + qdf_event_destroy(&vdev->wait_delete_comp); + + ol_txrx_dbg( + "deleting vdev obj %pK ("QDF_MAC_ADDR_FMT")", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + + htt_vdev_detach(pdev->htt_pdev, vdev->vdev_id); + + /* + * The ol_tx_desc_free might access the invalid content of vdev referred + * by tx desc, since this vdev might be detached in another thread + * asynchronous. + * + * Go through tx desc pool to set corresponding tx desc's vdev to NULL + * when detach this vdev, and add vdev checking in the ol_tx_desc_free + * to avoid crash. + * + */ + ol_txrx_tx_desc_reset_vdev(vdev); + + /* + * Doesn't matter if there are outstanding tx frames - + * they will be freed once the target sends a tx completion + * message for them. + */ + qdf_mem_free(vdev); + if (callback) + callback(context); + + if (vdev_del_notify) + vdev_del_notify(vdev_del_context); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_flush_rx_frames() - flush cached rx frames + * @peer: peer + * @drop: set flag to drop frames + * + * Return: None + */ +void ol_txrx_flush_rx_frames(struct ol_txrx_peer_t *peer, + bool drop) +{ + struct ol_txrx_cached_bufq_t *bufqi; + struct ol_rx_cached_buf *cache_buf; + QDF_STATUS ret; + ol_txrx_rx_fp data_rx = NULL; + + if (qdf_atomic_inc_return(&peer->flush_in_progress) > 1) { + qdf_atomic_dec(&peer->flush_in_progress); + return; + } + + qdf_assert(peer->vdev); + qdf_spin_lock_bh(&peer->peer_info_lock); + bufqi = &peer->bufq_info; + + if (peer->state >= OL_TXRX_PEER_STATE_CONN && peer->vdev->rx) + data_rx = peer->vdev->rx; + else + drop = true; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + qdf_spin_lock_bh(&bufqi->bufq_lock); + cache_buf = list_entry((&bufqi->cached_bufq)->next, + typeof(*cache_buf), list); + while (!list_empty(&bufqi->cached_bufq)) { + list_del(&cache_buf->list); + bufqi->curr--; + qdf_assert(bufqi->curr >= 0); + qdf_spin_unlock_bh(&bufqi->bufq_lock); + if (drop) { + qdf_nbuf_free(cache_buf->buf); + } else { + /* Flush the cached frames to HDD */ + ret = data_rx(peer->vdev->osif_dev, cache_buf->buf); + if (ret != QDF_STATUS_SUCCESS) + qdf_nbuf_free(cache_buf->buf); + } + qdf_mem_free(cache_buf); + qdf_spin_lock_bh(&bufqi->bufq_lock); + cache_buf = list_entry((&bufqi->cached_bufq)->next, + typeof(*cache_buf), list); + } + bufqi->qdepth_no_thresh = bufqi->curr; + qdf_spin_unlock_bh(&bufqi->bufq_lock); + qdf_atomic_dec(&peer->flush_in_progress); +} + +static void ol_txrx_flush_cache_rx_queue(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_peer_t *peer; + struct ol_txrx_vdev_t *vdev; + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) + return; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + ol_txrx_flush_rx_frames(peer, 1); + } + } +} + +/* Define short name to use in cds_trigger_recovery */ +#define PEER_DEL_TIMEOUT QDF_PEER_DELETION_TIMEDOUT + +/** + * ol_txrx_dump_peer_access_list() - dump peer access list + * @peer: peer handle + * + * This function will dump if any peer debug ids are still accessing peer + * + * Return: None + */ +static void ol_txrx_dump_peer_access_list(ol_txrx_peer_handle peer) +{ + u32 i; + u32 pending_ref; + + for (i = 0; i < PEER_DEBUG_ID_MAX; i++) { + pending_ref = qdf_atomic_read(&peer->access_list[i]); + if (pending_ref) + ol_txrx_info_high("id %d pending refs %d", + i, pending_ref); + } +} + +/** + * ol_txrx_peer_attach - Allocate and set up references for a + * data peer object. + * @soc_hdl - data path soc handle + * @vdev_id - virtual device instance id + * @peer_mac_addr - MAC address of the new peer + * + * When an association with a peer starts, the host's control SW + * uses this function to inform the host data SW. + * The host data SW allocates its own peer object, and stores a + * reference to the control peer object within the data peer object. + * The host data SW also stores a reference to the virtual device + * that the peer is associated with. This virtual device handle is + * used when the data SW delivers rx data frames to the OS shim layer. + * The host data SW returns a handle to the new peer data object, + * so a reference within the control peer object can be set to the + * data peer object. + * + * Return: QDF status code + */ +static QDF_STATUS +ol_txrx_peer_attach(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac_addr, enum cdp_peer_type peer_type) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + struct ol_txrx_peer_t *peer; + struct ol_txrx_peer_t *temp_peer; + uint8_t i; + bool wait_on_deletion = false; + unsigned long rc; + struct ol_txrx_pdev_t *pdev; + bool cmp_wait_mac = false; + uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 }; + u8 check_valid = 0; + + /* preconditions */ + TXRX_ASSERT2(vdev); + TXRX_ASSERT2(peer_mac_addr); + + pdev = vdev->pdev; + TXRX_ASSERT2(pdev); + + if (pdev->enable_peer_unmap_conf_support) + check_valid = 1; + + if (qdf_mem_cmp(&zero_mac_addr, &vdev->last_peer_mac_addr, + QDF_MAC_ADDR_SIZE)) + cmp_wait_mac = true; + + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* check for duplicate existing peer */ + TAILQ_FOREACH(temp_peer, &vdev->peer_list, peer_list_elem) { + if (!ol_txrx_peer_find_mac_addr_cmp(&temp_peer->mac_addr, + (union ol_txrx_align_mac_addr_t *)peer_mac_addr) && + (check_valid == 0 || temp_peer->valid)) { + ol_txrx_info_high( + "vdev_id %d ("QDF_MAC_ADDR_FMT") already exists", + vdev->vdev_id, + QDF_MAC_ADDR_REF(peer_mac_addr)); + if (qdf_atomic_read(&temp_peer->delete_in_progress)) { + vdev->wait_on_peer_id = temp_peer->local_id; + qdf_event_reset(&vdev->wait_delete_comp); + wait_on_deletion = true; + break; + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return QDF_STATUS_E_FAILURE; + } + } + if (cmp_wait_mac && !ol_txrx_peer_find_mac_addr_cmp( + &temp_peer->mac_addr, + &vdev->last_peer_mac_addr) && + (check_valid == 0 || + temp_peer->valid)) { + ol_txrx_info_high( + "vdev_id %d ("QDF_MAC_ADDR_FMT") old peer exists", + vdev->vdev_id, + QDF_MAC_ADDR_REF(vdev->last_peer_mac_addr.raw)); + if (qdf_atomic_read(&temp_peer->delete_in_progress)) { + vdev->wait_on_peer_id = temp_peer->local_id; + qdf_event_reset(&vdev->wait_delete_comp); + wait_on_deletion = true; + break; + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + ol_txrx_err("peer not found"); + return QDF_STATUS_E_FAILURE; + } + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + qdf_mem_zero(&vdev->last_peer_mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + if (wait_on_deletion) { + /* wait for peer deletion */ + rc = qdf_wait_for_event_completion(&vdev->wait_delete_comp, + PEER_DELETION_TIMEOUT); + if (QDF_STATUS_SUCCESS != rc) { + ol_txrx_err("error waiting for peer_id(%d) deletion, status %d", + vdev->wait_on_peer_id, (int) rc); + /* Added for debugging only */ + ol_txrx_dump_peer_access_list(temp_peer); + wlan_roam_debug_dump_table(); + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + + return QDF_STATUS_E_FAILURE; + } + } + + peer = qdf_mem_malloc(sizeof(*peer)); + if (!peer) + return QDF_STATUS_E_NOMEM; + + /* store provided params */ + peer->vdev = vdev; + qdf_mem_copy(&peer->mac_addr.raw[0], peer_mac_addr, + QDF_MAC_ADDR_SIZE); + + ol_txrx_peer_txqs_init(pdev, peer); + + INIT_LIST_HEAD(&peer->bufq_info.cached_bufq); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* add this peer into the vdev's list */ + TAILQ_INSERT_TAIL(&vdev->peer_list, peer, peer_list_elem); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + /* check whether this is a real peer (peer mac addr != vdev mac addr) */ + if (ol_txrx_peer_find_mac_addr_cmp(&vdev->mac_addr, &peer->mac_addr)) { + qdf_spin_lock_bh(&pdev->last_real_peer_mutex); + vdev->last_real_peer = peer; + qdf_spin_unlock_bh(&pdev->last_real_peer_mutex); + } + + peer->rx_opt_proc = pdev->rx_opt_proc; + + ol_rx_peer_init(pdev, peer); + + /* initialize the peer_id */ + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) + peer->peer_ids[i] = HTT_INVALID_PEER; + + qdf_spinlock_create(&peer->peer_info_lock); + qdf_spinlock_create(&peer->bufq_info.bufq_lock); + + peer->bufq_info.thresh = OL_TXRX_CACHED_BUFQ_THRESH; + + qdf_atomic_init(&peer->delete_in_progress); + qdf_atomic_init(&peer->flush_in_progress); + qdf_atomic_init(&peer->ref_cnt); + qdf_atomic_init(&peer->del_ref_cnt); + + for (i = 0; i < PEER_DEBUG_ID_MAX; i++) + qdf_atomic_init(&peer->access_list[i]); + + /* keep one reference for attach */ + ol_txrx_peer_get_ref(peer, PEER_DEBUG_ID_OL_PEER_ATTACH); + + /* Set a flag to indicate peer create is pending in firmware */ + qdf_atomic_init(&peer->fw_create_pending); + qdf_atomic_set(&peer->fw_create_pending, 1); + + peer->valid = 1; + qdf_timer_init(pdev->osdev, &peer->peer_unmap_timer, + peer_unmap_timer_handler, peer, QDF_TIMER_TYPE_SW); + + ol_txrx_peer_find_hash_add(pdev, peer); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "vdev %pK created peer %pK ref_cnt %d ("QDF_MAC_ADDR_FMT")", + vdev, peer, qdf_atomic_read(&peer->ref_cnt), + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + /* + * For every peer MAp message search and set if bss_peer + */ + if (qdf_mem_cmp(peer->mac_addr.raw, vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE)) + peer->bss_peer = 1; + + /* + * The peer starts in the "disc" state while association is in progress. + * Once association completes, the peer will get updated to "auth" state + * by a call to ol_txrx_peer_state_update if the peer is in open mode, + * or else to the "conn" state. For non-open mode, the peer will + * progress to "auth" state once the authentication completes. + */ + peer->state = OL_TXRX_PEER_STATE_INVALID; + ol_txrx_peer_state_update(soc_hdl, peer->mac_addr.raw, + OL_TXRX_PEER_STATE_DISC); + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI + peer->rssi_dbm = HTT_RSSI_INVALID; +#endif + if ((QDF_GLOBAL_MONITOR_MODE == cds_get_conparam()) && + !pdev->self_peer) { + pdev->self_peer = peer; + /* + * No Tx in monitor mode, otherwise results in target assert. + * Setting disable_intrabss_fwd to true + */ + ol_vdev_rx_set_intrabss_fwd(soc_hdl, vdev_id, true); + } + + ol_txrx_local_peer_id_alloc(pdev, peer); + + return QDF_STATUS_SUCCESS; +} + +#undef PEER_DEL_TIMEOUT + +/* + * Discarding tx filter - removes all data frames (disconnected state) + */ +static A_STATUS ol_tx_filter_discard(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return A_ERROR; +} + +/* + * Non-autentication tx filter - filters out data frames that are not + * related to authentication, but allows EAPOL (PAE) or WAPI (WAI) + * data frames (connected state) + */ +static A_STATUS ol_tx_filter_non_auth(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return + (tx_msdu_info->htt.info.ethertype == ETHERTYPE_PAE || + tx_msdu_info->htt.info.ethertype == + ETHERTYPE_WAI) ? A_OK : A_ERROR; +} + +/* + * Pass-through tx filter - lets all data frames through (authenticated state) + */ +static A_STATUS ol_tx_filter_pass_thru(struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + return A_OK; +} + +/** + * ol_txrx_peer_get_peer_mac_addr() - return mac_addr from peer handle. + * @peer: handle to peer + * + * returns mac addrs for module which do not know peer type + * + * Return: the mac_addr from peer + */ +static uint8_t * +ol_txrx_peer_get_peer_mac_addr(void *ppeer) +{ + ol_txrx_peer_handle peer = ppeer; + + if (!peer) + return NULL; + + return peer->mac_addr.raw; +} + +/** + * ol_txrx_get_pn_info() - Returns pn info from peer + * @soc_hdl: soc handle + * @peer_mac: mac address of the peer + * @vdev_id: vdev identifier + * @last_pn_valid: return last_rmf_pn_valid value from peer. + * @last_pn: return last_rmf_pn value from peer. + * @rmf_pn_replays: return rmf_pn_replays value from peer. + * + * Return: NONE + */ +static void +ol_txrx_get_pn_info(struct cdp_soc_t *soc_hdl, uint8_t *peer_mac, + uint8_t vdev_id, uint8_t **last_pn_valid, + uint64_t **last_pn, uint32_t **rmf_pn_replays) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) + return; + + *last_pn_valid = &peer->last_rmf_pn_valid; + *last_pn = &peer->last_rmf_pn; + *rmf_pn_replays = &peer->rmf_pn_replays; + + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); +} + +/** + * ol_txrx_get_opmode() - Return operation mode of vdev + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * + * Return: interface opmode if SUCCESS, + * 0 if interface does not exist. + */ +static int ol_txrx_get_opmode(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + ol_txrx_err("vdev for id %d is NULL", vdev_id); + return 0; + } + + return vdev->opmode; +} + +/** + * ol_txrx_get_peer_state() - Return peer state of peer + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * @peer_mac: peer mac addr + * @slowpath: called from slow path or not + * + * Return: return peer state + */ +static int ol_txrx_get_peer_state(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac, bool slowpath) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = + ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + ol_txrx_peer_handle peer; + enum ol_txrx_peer_state peer_state; + + if (!pdev) + return QDF_STATUS_E_FAILURE; + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) + return QDF_STATUS_E_FAILURE; + + peer_state = peer->state; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + if (peer->vdev->vdev_id != vdev_id) + return OL_TXRX_PEER_STATE_INVALID; + + return peer_state; +} + +/** + * ol_txrx_get_vdev_mac_addr() - Return mac addr of vdev + * @soc_hdl: datapath soc handle + x @vdev_id: virtual interface id + * + * Return: vdev mac address + */ +static uint8_t * +ol_txrx_get_vdev_mac_addr(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return NULL; + + return vdev->mac_addr.raw; +} + +#ifdef currently_unused +/** + * ol_txrx_get_vdev_struct_mac_addr() - Return handle to struct qdf_mac_addr of + * vdev + * @vdev: vdev handle + * + * Return: Handle to struct qdf_mac_addr + */ +struct qdf_mac_addr * +ol_txrx_get_vdev_struct_mac_addr(ol_txrx_vdev_handle vdev) +{ + return (struct qdf_mac_addr *)&(vdev->mac_addr); +} +#endif + +#ifdef currently_unused +/** + * ol_txrx_get_pdev_from_vdev() - Return handle to pdev of vdev + * @vdev: vdev handle + * + * Return: Handle to pdev + */ +ol_txrx_pdev_handle ol_txrx_get_pdev_from_vdev(ol_txrx_vdev_handle vdev) +{ + return vdev->pdev; +} +#endif + +/** + * ol_txrx_get_ctrl_pdev_from_vdev() - Return control pdev of vdev + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * + * Return: Handle to control pdev + */ +static struct cdp_cfg * +ol_txrx_get_ctrl_pdev_from_vdev(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return NULL; + + return vdev->pdev->ctrl_pdev; +} + +/** + * ol_txrx_is_rx_fwd_disabled() - returns the rx_fwd_disabled status on vdev + * @vdev: vdev handle + * + * Return: Rx Fwd disabled status + */ +static uint8_t +ol_txrx_is_rx_fwd_disabled(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + struct txrx_pdev_cfg_t *cfg = (struct txrx_pdev_cfg_t *) + vdev->pdev->ctrl_pdev; + return cfg->rx_fwd_disabled; +} + +#ifdef QCA_IBSS_SUPPORT +/** + * ol_txrx_update_ibss_add_peer_num_of_vdev() - update and return peer num + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * @peer_num_delta: peer nums to be adjusted + * + * Return: -1 for failure or total peer nums after adjustment. + */ +static int16_t +ol_txrx_update_ibss_add_peer_num_of_vdev(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + int16_t peer_num_delta) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + int16_t new_peer_num; + + if (!vdev) + return QDF_STATUS_E_FAILURE; + + new_peer_num = vdev->ibss_peer_num + peer_num_delta; + if (new_peer_num > MAX_PEERS || new_peer_num < 0) + return OL_TXRX_INVALID_NUM_PEERS; + + vdev->ibss_peer_num = new_peer_num; + + return new_peer_num; +} + +/** + * ol_txrx_set_ibss_vdev_heart_beat_timer() - Update ibss vdev heart + * beat timer + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * @timer_value_sec: new heart beat timer value + * + * Return: Old timer value set in vdev. + */ +static uint16_t +ol_txrx_set_ibss_vdev_heart_beat_timer(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + uint16_t timer_value_sec) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + uint16_t old_timer_value = vdev->ibss_peer_heart_beat_timer; + + vdev->ibss_peer_heart_beat_timer = timer_value_sec; + + return old_timer_value; +} +#else /* !QCA_IBSS_SUPPORT */ +static inline int16_t +ol_txrx_update_ibss_add_peer_num_of_vdev(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + int16_t peer_num_delta) +{ + return 0; +} + +static uint16_t ol_txrx_set_ibss_vdev_heart_beat_timer( + struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint16_t timer_value_sec) +{ + return 0; +} +#endif /* QCA_IBSS_SUPPORT */ + +#ifdef WLAN_FEATURE_DSRC +/** + * ol_txrx_set_ocb_chan_info() - set OCB channel info to vdev. + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * @ocb_set_chan: OCB channel information to be set in vdev. + * + * Return: NONE + */ +static void +ol_txrx_set_ocb_chan_info(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + struct ol_txrx_ocb_set_chan ocb_set_chan) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("pdev is NULL"); + return; + } + + vdev->ocb_channel_info = ocb_set_chan.ocb_channel_info; + vdev->ocb_channel_count = ocb_set_chan.ocb_channel_count; +} + +/** + * ol_txrx_get_ocb_chan_info() - return handle to vdev ocb_channel_info + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * + * Return: handle to struct ol_txrx_ocb_chan_info + */ +static struct ol_txrx_ocb_chan_info * +ol_txrx_get_ocb_chan_info(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("pdev is NULL"); + return NULL; + } + + return vdev->ocb_channel_info; +} +#endif + +QDF_STATUS ol_txrx_peer_state_update(struct cdp_soc_t *soc_hdl, + uint8_t *peer_mac, + enum ol_txrx_peer_state state) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = + ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + struct ol_txrx_peer_t *peer; + int peer_ref_cnt; + + if (qdf_unlikely(!pdev)) { + ol_txrx_err("Pdev is NULL"); + qdf_assert(0); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) { + ol_txrx_err( + "peer is null for peer_mac 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x", + peer_mac[0], peer_mac[1], peer_mac[2], peer_mac[3], + peer_mac[4], peer_mac[5]); + return QDF_STATUS_E_INVAL; + } + + /* TODO: Should we send WMI command of the connection state? */ + /* avoid multiple auth state change. */ + if (peer->state == state) { +#ifdef TXRX_PRINT_VERBOSE_ENABLE + ol_txrx_dbg("no state change, returns directly"); +#endif + peer_ref_cnt = ol_txrx_peer_release_ref + (peer, + PEER_DEBUG_ID_OL_INTERNAL); + return QDF_STATUS_SUCCESS; + } + + ol_txrx_dbg("change from %d to %d", + peer->state, state); + + peer->tx_filter = (state == OL_TXRX_PEER_STATE_AUTH) + ? ol_tx_filter_pass_thru + : ((state == OL_TXRX_PEER_STATE_CONN) + ? ol_tx_filter_non_auth + : ol_tx_filter_discard); + + if (peer->vdev->pdev->cfg.host_addba) { + if (state == OL_TXRX_PEER_STATE_AUTH) { + int tid; + /* + * Pause all regular (non-extended) TID tx queues until + * data arrives and ADDBA negotiation has completed. + */ + ol_txrx_dbg("pause peer and unpause mgmt/non-qos"); + ol_txrx_peer_pause(peer); /* pause all tx queues */ + /* unpause mgmt and non-QoS tx queues */ + for (tid = OL_TX_NUM_QOS_TIDS; + tid < OL_TX_NUM_TIDS; tid++) + ol_txrx_peer_tid_unpause(peer, tid); + } + } + peer_ref_cnt = ol_txrx_peer_release_ref(peer, + PEER_DEBUG_ID_OL_INTERNAL); + /* + * after ol_txrx_peer_release_ref, peer object cannot be accessed + * if the return code was 0 + */ + if (peer_ref_cnt > 0) + /* + * Set the state after the Pause to avoid the race condiction + * with ADDBA check in tx path + */ + peer->state = state; + return QDF_STATUS_SUCCESS; +} + +void +ol_txrx_peer_keyinstalled_state_update(struct ol_txrx_peer_t *peer, uint8_t val) +{ + peer->keyinstalled = val; +} + +void +ol_txrx_peer_update(ol_txrx_vdev_handle vdev, + uint8_t *peer_mac, + union ol_txrx_peer_update_param_t *param, + enum ol_txrx_peer_update_select_t select) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_hash_find_get_ref(vdev->pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) { + ol_txrx_dbg("peer is null"); + return; + } + + switch (select) { + case ol_txrx_peer_update_qos_capable: + { + /* save qos_capable here txrx peer, + * when HTT_ISOC_T2H_MSG_TYPE_PEER_INFO comes then save. + */ + peer->qos_capable = param->qos_capable; + /* + * The following function call assumes that the peer has a + * single ID. This is currently true, and + * is expected to remain true. + */ + htt_peer_qos_update(peer->vdev->pdev->htt_pdev, + peer->peer_ids[0], + peer->qos_capable); + break; + } + case ol_txrx_peer_update_uapsdMask: + { + peer->uapsd_mask = param->uapsd_mask; + htt_peer_uapsdmask_update(peer->vdev->pdev->htt_pdev, + peer->peer_ids[0], + peer->uapsd_mask); + break; + } + case ol_txrx_peer_update_peer_security: + { + enum ol_sec_type sec_type = param->sec_type; + enum htt_sec_type peer_sec_type = htt_sec_type_none; + + switch (sec_type) { + case ol_sec_type_none: + peer_sec_type = htt_sec_type_none; + break; + case ol_sec_type_wep128: + peer_sec_type = htt_sec_type_wep128; + break; + case ol_sec_type_wep104: + peer_sec_type = htt_sec_type_wep104; + break; + case ol_sec_type_wep40: + peer_sec_type = htt_sec_type_wep40; + break; + case ol_sec_type_tkip: + peer_sec_type = htt_sec_type_tkip; + break; + case ol_sec_type_tkip_nomic: + peer_sec_type = htt_sec_type_tkip_nomic; + break; + case ol_sec_type_aes_ccmp: + peer_sec_type = htt_sec_type_aes_ccmp; + break; + case ol_sec_type_wapi: + peer_sec_type = htt_sec_type_wapi; + break; + default: + peer_sec_type = htt_sec_type_none; + break; + } + + peer->security[txrx_sec_ucast].sec_type = + peer->security[txrx_sec_mcast].sec_type = + peer_sec_type; + + break; + } + default: + { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ERROR: unknown param %d in %s", select, + __func__); + break; + } + } /* switch */ + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); +} + +uint8_t +ol_txrx_peer_uapsdmask_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id) +{ + + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_by_id(txrx_pdev, peer_id); + if (peer) + return peer->uapsd_mask; + return 0; +} + +uint8_t +ol_txrx_peer_qoscapable_get(struct ol_txrx_pdev_t *txrx_pdev, uint16_t peer_id) +{ + + struct ol_txrx_peer_t *peer_t = + ol_txrx_peer_find_by_id(txrx_pdev, peer_id); + if (peer_t) + return peer_t->qos_capable; + return 0; +} + +/** + * ol_txrx_peer_free_tids() - free tids for the peer + * @peer: peer handle + * + * Return: None + */ +static inline void ol_txrx_peer_free_tids(ol_txrx_peer_handle peer) +{ + int i = 0; + /* + * 'array' is allocated in addba handler and is supposed to be + * freed in delba handler. There is the case (for example, in + * SSR) where delba handler is not called. Because array points + * to address of 'base' by default and is reallocated in addba + * handler later, only free the memory when the array does not + * point to base. + */ + for (i = 0; i < OL_TXRX_NUM_EXT_TIDS; i++) { + if (peer->tids_rx_reorder[i].array != + &peer->tids_rx_reorder[i].base) { + ol_txrx_dbg("delete reorder arr, tid:%d", i); + qdf_mem_free(peer->tids_rx_reorder[i].array); + ol_rx_reorder_init(&peer->tids_rx_reorder[i], + (uint8_t)i); + } + } +} + +/** + * ol_txrx_peer_drop_pending_frames() - drop pending frames in the RX queue + * @peer: peer handle + * + * Drop pending packets pertaining to the peer from the RX thread queue. + * + * Return: None + */ +static void ol_txrx_peer_drop_pending_frames(struct ol_txrx_peer_t *peer) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + + if (sched_ctx) + cds_drop_rxpkt_by_staid(sched_ctx, peer->local_id); +} + +/** + * ol_txrx_peer_release_ref() - release peer reference + * @peer: peer handle + * + * Release peer reference and delete peer if refcount is 0 + * + * Return: Resulting peer ref_cnt after this function is invoked + */ +int ol_txrx_peer_release_ref(ol_txrx_peer_handle peer, + enum peer_debug_id_type debug_id) +{ + int rc; + struct ol_txrx_vdev_t *vdev; + struct ol_txrx_pdev_t *pdev; + bool ref_silent = true; + int access_list = 0; + uint32_t err_code = 0; + int del_rc; + + /* preconditions */ + TXRX_ASSERT2(peer); + + vdev = peer->vdev; + if (!vdev) { + ol_txrx_err("The vdev is not present anymore"); + return -EINVAL; + } + + pdev = vdev->pdev; + if (!pdev) { + ol_txrx_err("The pdev is not present anymore"); + err_code = 0xbad2; + goto ERR_STATE; + } + + if (debug_id >= PEER_DEBUG_ID_MAX || debug_id < 0) { + ol_txrx_err("incorrect debug_id %d ", debug_id); + err_code = 0xbad3; + goto ERR_STATE; + } + + if (debug_id == PEER_DEBUG_ID_OL_RX_THREAD) + ref_silent = true; + + if (!ref_silent) + wlan_roam_debug_log(vdev->vdev_id, DEBUG_PEER_UNREF_DELETE, + DEBUG_INVALID_PEER_ID, &peer->mac_addr.raw, + peer, 0xdead, + qdf_atomic_read(&peer->ref_cnt)); + + + /* + * Hold the lock all the way from checking if the peer ref count + * is zero until the peer references are removed from the hash + * table and vdev list (if the peer ref count is zero). + * This protects against a new HL tx operation starting to use the + * peer object just after this function concludes it's done being used. + * Furthermore, the lock needs to be held while checking whether the + * vdev's list of peers is empty, to make sure that list is not modified + * concurrently with the empty check. + */ + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + + /* + * Check for the reference count before deleting the peer + * as we noticed that sometimes we are re-entering this + * function again which is leading to dead-lock. + * (A double-free should never happen, so assert if it does.) + */ + rc = qdf_atomic_read(&(peer->ref_cnt)); + + if (rc == 0) { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + ol_txrx_err("The Peer is not present anymore"); + qdf_assert(0); + return -EACCES; + } + /* + * now decrement rc; this will be the return code. + * 0 : peer deleted + * >0: peer ref removed, but still has other references + * <0: sanity failed - no changes to the state of the peer + */ + rc--; + + if (!qdf_atomic_read(&peer->access_list[debug_id])) { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + ol_txrx_err("peer %pK ref was not taken by %d", + peer, debug_id); + ol_txrx_dump_peer_access_list(peer); + QDF_BUG(0); + return -EACCES; + } + qdf_atomic_dec(&peer->access_list[debug_id]); + + if (qdf_atomic_dec_and_test(&peer->ref_cnt)) { + u16 peer_id; + wlan_roam_debug_log(vdev->vdev_id, + DEBUG_DELETING_PEER_OBJ, + DEBUG_INVALID_PEER_ID, + &peer->mac_addr.raw, peer, 0, + qdf_atomic_read(&peer->ref_cnt)); + peer_id = peer->local_id; + + /* Drop all pending frames in the rx thread queue */ + ol_txrx_peer_drop_pending_frames(peer); + + /* remove the reference to the peer from the hash table */ + ol_txrx_peer_find_hash_remove(pdev, peer); + + /* remove the peer from its parent vdev's list */ + TAILQ_REMOVE(&peer->vdev->peer_list, peer, peer_list_elem); + + /* cleanup the Rx reorder queues for this peer */ + ol_rx_peer_cleanup(vdev, peer); + + qdf_spinlock_destroy(&peer->peer_info_lock); + qdf_spinlock_destroy(&peer->bufq_info.bufq_lock); + + /* peer is removed from peer_list */ + qdf_atomic_set(&peer->delete_in_progress, 0); + + /* + * Set wait_delete_comp event if the current peer id matches + * with registered peer id. + */ + if (peer_id == vdev->wait_on_peer_id) { + qdf_event_set(&vdev->wait_delete_comp); + vdev->wait_on_peer_id = OL_TXRX_INVALID_LOCAL_PEER_ID; + } + + qdf_timer_sync_cancel(&peer->peer_unmap_timer); + qdf_timer_free(&peer->peer_unmap_timer); + + /* check whether the parent vdev has no peers left */ + if (TAILQ_EMPTY(&vdev->peer_list)) { + /* + * Check if the parent vdev was waiting for its peers + * to be deleted, in order for it to be deleted too. + */ + if (vdev->delete.pending) { + ol_txrx_vdev_delete_cb vdev_delete_cb = + vdev->delete.callback; + void *vdev_delete_context = + vdev->delete.context; + ol_txrx_vdev_delete_cb vdev_del_notify = + vdev->vdev_del_notify; + void *vdev_del_context = vdev->osif_dev; + /* + * Now that there are no references to the peer, + * we can release the peer reference lock. + */ + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + /* + * The ol_tx_desc_free might access the invalid + * content of vdev referred by tx desc, since + * this vdev might be detached in another thread + * asynchronous. + * + * Go through tx desc pool to set corresponding + * tx desc's vdev to NULL when detach this vdev, + * and add vdev checking in the ol_tx_desc_free + * to avoid crash. + */ + ol_txrx_tx_desc_reset_vdev(vdev); + ol_txrx_dbg( + "deleting vdev object %pK ("QDF_MAC_ADDR_FMT") - its last peer is done", + vdev, + QDF_MAC_ADDR_REF(vdev->mac_addr.raw)); + /* all peers are gone, go ahead and delete it */ + qdf_mem_free(vdev); + if (vdev_delete_cb) + vdev_delete_cb(vdev_delete_context); + + if (vdev_del_notify) + vdev_del_notify(vdev_del_context); + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } + } else { + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + } + + del_rc = qdf_atomic_read(&peer->del_ref_cnt); + + ol_txrx_info_high("[%d][%d]: Deleting peer %pK ref_cnt -> %d del_ref_cnt -> %d %s", + debug_id, + qdf_atomic_read(&peer->access_list[debug_id]), + peer, rc, del_rc, + qdf_atomic_read(&peer->fw_create_pending) == + 1 ? "(No Maps received)" : ""); + + ol_txrx_peer_tx_queue_free(pdev, peer); + + /* Remove mappings from peer_id to peer object */ + ol_txrx_peer_clear_map_peer(pdev, peer); + + /* Remove peer pointer from local peer ID map */ + ol_txrx_local_peer_id_free(pdev, peer); + + ol_txrx_peer_free_tids(peer); + + ol_txrx_dump_peer_access_list(peer); + + if (QDF_GLOBAL_MONITOR_MODE == cds_get_conparam() && + pdev->self_peer == peer) + pdev->self_peer = NULL; + + if (!del_rc) + qdf_mem_free(peer); + } else { + access_list = qdf_atomic_read(&peer->access_list[debug_id]); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + if (!ref_silent) + ol_txrx_info_high("[%d][%d]: ref delete peer %pK ref_cnt -> %d", + debug_id, access_list, peer, rc); + } + return rc; +ERR_STATE: + wlan_roam_debug_log(vdev->vdev_id, DEBUG_PEER_UNREF_DELETE, + DEBUG_INVALID_PEER_ID, &peer->mac_addr.raw, + peer, err_code, qdf_atomic_read(&peer->ref_cnt)); + return -EINVAL; +} + +/** + * ol_txrx_clear_peer_internal() - ol internal function to clear peer + * @peer: pointer to ol txrx peer structure + * + * Return: QDF Status + */ +static QDF_STATUS +ol_txrx_clear_peer_internal(struct ol_txrx_peer_t *peer) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + /* Drop pending Rx frames in CDS */ + if (sched_ctx) + cds_drop_rxpkt_by_staid(sched_ctx, peer->local_id); + + /* Purge the cached rx frame queue */ + ol_txrx_flush_rx_frames(peer, 1); + + qdf_spin_lock_bh(&peer->peer_info_lock); + peer->state = OL_TXRX_PEER_STATE_DISC; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_clear_peer() - clear peer + * peer_addr: peer mac address + * + * Return: QDF Status + */ +static QDF_STATUS +ol_txrx_clear_peer(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct qdf_mac_addr peer_addr) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = + ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_peer_t *peer; + QDF_STATUS status; + + if (!pdev) { + ol_txrx_err("Unable to find pdev!"); + return QDF_STATUS_E_FAILURE; + } + + peer = ol_txrx_peer_get_ref_by_addr(pdev, peer_addr.bytes, + PEER_DEBUG_ID_OL_INTERNAL); + + /* Return success, if the peer is already cleared by + * data path via peer detach function. + */ + if (!peer) + return QDF_STATUS_SUCCESS; + + ol_txrx_dbg("Clear peer rx frames: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + ol_txrx_clear_peer_internal(peer); + status = ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + + return status; +} + +/** + * peer_unmap_timer_handler() - peer unmap timer function + * @data: peer object pointer + * + * Return: none + */ +void peer_unmap_timer_handler(void *data) +{ + ol_txrx_peer_handle peer = (ol_txrx_peer_handle)data; + + if (!peer) + return; + + ol_txrx_err("all unmap events not received for peer %pK, ref_cnt %d", + peer, qdf_atomic_read(&peer->ref_cnt)); + ol_txrx_err("peer %pK ("QDF_MAC_ADDR_FMT")", + peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + ol_register_peer_recovery_notifier(peer); + + cds_trigger_recovery(QDF_PEER_UNMAP_TIMEDOUT); +} + + +/** + * ol_txrx_peer_detach() - Delete a peer's data object. + + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * @peer_mac: peer MAC address + * @bitmap: bitmap indicating special handling of request. + * @peer_type: link or mld peer + * When the host's control SW disassociates a peer, it calls + * this function to detach and delete the peer. The reference + * stored in the control peer object to the data peer + * object (set up by a call to ol_peer_store()) is provided. + * + * Return: SUCCESS or Failure + */ +static QDF_STATUS ol_txrx_peer_detach(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, uint8_t *peer_mac, + uint32_t bitmap, + enum cdp_peer_type peer_type) +{ + ol_txrx_peer_handle peer; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return QDF_STATUS_E_FAILURE; + + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)vdev->pdev, + peer_mac); + if (!peer) + return QDF_STATUS_E_FAILURE; + + ol_txrx_info_high("peer %pK, peer->ref_cnt %d", + peer, qdf_atomic_read(&peer->ref_cnt)); + + /* redirect peer's rx delivery function to point to a discard func */ + peer->rx_opt_proc = ol_rx_discard; + + peer->valid = 0; + + /* flush all rx packets before clearing up the peer local_id */ + ol_txrx_clear_peer_internal(peer); + + /* debug print to dump rx reorder state */ + /* htt_rx_reorder_log_print(vdev->pdev->htt_pdev); */ + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s:peer %pK ("QDF_MAC_ADDR_FMT")", + __func__, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + + qdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + if (vdev->last_real_peer == peer) + vdev->last_real_peer = NULL; + qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); + htt_rx_reorder_log_print(peer->vdev->pdev->htt_pdev); + + /* + * set delete_in_progress to identify that wma + * is waiting for unmap massage for this peer + */ + qdf_atomic_set(&peer->delete_in_progress, 1); + + if (!(bitmap & (1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER))) { + if (vdev->opmode == wlan_op_mode_sta) { + qdf_mem_copy(&peer->vdev->last_peer_mac_addr, + &peer->mac_addr, + sizeof(union ol_txrx_align_mac_addr_t)); + + /* + * Create a timer to track unmap events when the + * sta peer gets deleted. + */ + qdf_timer_start(&peer->peer_unmap_timer, + OL_TXRX_PEER_UNMAP_TIMEOUT); + ol_txrx_info_high + ("started peer_unmap_timer for peer %pK", + peer); + } + } + + /* + * Remove the reference added during peer_attach. + * The peer will still be left allocated until the + * PEER_UNMAP message arrives to remove the other + * reference, added by the PEER_MAP message. + */ + peer->state = OL_TXRX_PEER_STATE_INVALID; + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_PEER_ATTACH); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_peer_detach_force_delete() - Detach and delete a peer's data object + * @soc_hdl - datapath soc handle + * @vdev_id - virtual interface id + * @peer_mac - peer mac address + * + * Detach a peer and force peer object to be removed. It is called during + * roaming scenario when the firmware has already deleted a peer. + * Remove it from the peer_id_to_object map. Peer object is actually freed + * when last reference is deleted. + * + * Return: None + */ +static void ol_txrx_peer_detach_force_delete(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, uint8_t *peer_mac) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev || !vdev->pdev) + return; + + pdev = vdev->pdev; + peer = ol_txrx_find_peer_by_addr(ol_txrx_pdev_t_to_cdp_pdev(pdev), + peer_mac); + if (!peer) + return; + + /* Clear the peer_id_to_obj map entries */ + ol_txrx_peer_remove_obj_map_entries(pdev, peer); + ol_txrx_peer_detach(soc_hdl, vdev_id, peer_mac, + 1 << CDP_PEER_DELETE_NO_SPECIAL, + CDP_LINK_PEER_TYPE); +} + +/** + * ol_txrx_peer_detach_sync() - peer detach sync callback + * @soc_hdl - datapath soc handle + * @vdev_id - virtual interface id + * @peer_mac - peer mac address + * @peer_unmap_sync - peer unmap sync cb. + * @bitmap - bitmap indicating special handling of request. + * + * Return: None + */ +static void ol_txrx_peer_detach_sync(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac, + ol_txrx_peer_unmap_sync_cb peer_unmap_sync, + uint32_t bitmap) +{ + struct ol_txrx_pdev_t *pdev; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev || !vdev->pdev) + return; + + pdev = vdev->pdev; + if (!pdev->peer_unmap_sync_cb) + pdev->peer_unmap_sync_cb = peer_unmap_sync; + + ol_txrx_peer_detach(soc_hdl, vdev_id, peer_mac, bitmap, + CDP_LINK_PEER_TYPE); +} + +/** + * ol_txrx_peer_unmap_sync_cb_set() - set peer unmap sync callback + * @soc_hdl - datapath soc handle + * pdev_id - physical device instance id + * @peer_unmap_sync - peer unmap sync callback + * + * Return: None + */ +static void ol_txrx_peer_unmap_sync_cb_set( + struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + ol_txrx_peer_unmap_sync_cb peer_unmap_sync) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + + if (!pdev) + return; + + if (!pdev->peer_unmap_sync_cb) + pdev->peer_unmap_sync_cb = peer_unmap_sync; +} + +/** + * ol_txrx_peer_flush_frags() - Flush fragments for a particular peer + * @soc_hdl - datapath soc handle + * @vdev_id - virtual device id + * @peer_mac - peer mac address + * + * Return: None + */ +static void +ol_txrx_peer_flush_frags(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t *peer_mac) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = + ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + + if (!pdev) + return; + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) + return; + + ol_rx_reorder_peer_cleanup(peer->vdev, peer); + + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); +} + +/** + * ol_txrx_dump_tx_desc() - dump tx desc total and free count + * @txrx_pdev: Pointer to txrx pdev + * + * Return: none + */ +static void ol_txrx_dump_tx_desc(ol_txrx_pdev_handle pdev_handle) +{ + struct ol_txrx_pdev_t *pdev = (ol_txrx_pdev_handle) pdev_handle; + uint32_t total, num_free; + + if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) + total = qdf_atomic_read(&pdev->orig_target_tx_credit); + else + total = ol_tx_get_desc_global_pool_size(pdev); + + num_free = ol_tx_get_total_free_desc(pdev); + + ol_txrx_info_high( + "total tx credit %d num_free %d", + total, num_free); + +} + +/** + * ol_txrx_wait_for_pending_tx() - wait for tx queue to be empty + * @timeout: timeout in ms + * + * Wait for tx queue to be empty, return timeout error if + * queue doesn't empty before timeout occurs. + * + * Return: + * QDF_STATUS_SUCCESS if the queue empties, + * QDF_STATUS_E_TIMEOUT in case of timeout, + * QDF_STATUS_E_FAULT in case of missing handle + */ +static QDF_STATUS ol_txrx_wait_for_pending_tx(int timeout) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_pdev_t *txrx_pdev; + + if (qdf_unlikely(!soc)) + return QDF_STATUS_E_FAULT; + + txrx_pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!txrx_pdev) { + ol_txrx_err("txrx context is null"); + return QDF_STATUS_E_FAULT; + } + + while (ol_txrx_get_tx_pending((struct cdp_pdev *)txrx_pdev)) { + qdf_sleep(OL_ATH_TX_DRAIN_WAIT_DELAY); + if (timeout <= 0) { + ol_txrx_err("tx frames are pending"); + ol_txrx_dump_tx_desc(txrx_pdev); + return QDF_STATUS_E_TIMEOUT; + } + timeout = timeout - OL_ATH_TX_DRAIN_WAIT_DELAY; + } + return QDF_STATUS_SUCCESS; +} + +#ifndef QCA_WIFI_3_0_EMU +#define SUSPEND_DRAIN_WAIT 500 +#else +#define SUSPEND_DRAIN_WAIT 3000 +#endif + +#ifdef FEATURE_RUNTIME_PM +/** + * ol_txrx_runtime_suspend() - ensure TXRX is ready to runtime suspend + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * + * TXRX is ready to runtime suspend if there are no pending packets + * in the tx queue. + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_runtime_suspend(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct cdp_pdev *txrx_pdev = (struct cdp_pdev *) + ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (ol_txrx_get_tx_pending(txrx_pdev)) + return QDF_STATUS_E_BUSY; + else + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_runtime_resume() - ensure TXRX is ready to runtime resume + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * + * This is a dummy function for symmetry. + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS ol_txrx_runtime_resume(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * ol_txrx_bus_suspend() - bus suspend + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * + * Ensure that ol_txrx is ready for bus suspend + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_bus_suspend(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + return ol_txrx_wait_for_pending_tx(SUSPEND_DRAIN_WAIT); +} + +/** + * ol_txrx_bus_resume() - bus resume + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * + * Dummy function for symmetry + * + * Return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS ol_txrx_bus_resume(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_get_tx_pending - Get the number of pending transmit + * frames that are awaiting completion. + * + * @pdev - the data physical device object + * Mainly used in clean up path to make sure all buffers have been freed + * + * Return: count of pending frames + */ +uint32_t ol_txrx_get_tx_pending(struct cdp_pdev *ppdev) +{ + struct ol_txrx_pdev_t *pdev = (struct ol_txrx_pdev_t *)ppdev; + uint32_t total; + + if (ol_cfg_is_high_latency(pdev->ctrl_pdev)) + total = qdf_atomic_read(&pdev->orig_target_tx_credit); + else + total = ol_tx_get_desc_global_pool_size(pdev); + + return total - ol_tx_get_total_free_desc(pdev); +} + +void ol_txrx_discard_tx_pending(ol_txrx_pdev_handle pdev_handle) +{ + ol_tx_desc_list tx_descs; + /* + * First let hif do the qdf_atomic_dec_and_test(&tx_desc->ref_cnt) + * then let htt do the qdf_atomic_dec_and_test(&tx_desc->ref_cnt) + * which is the same with normal data send complete path + */ + htt_tx_pending_discard(pdev_handle->htt_pdev); + + TAILQ_INIT(&tx_descs); + ol_tx_queue_discard(pdev_handle, true, &tx_descs); + /* Discard Frames in Discard List */ + ol_tx_desc_frame_list_free(pdev_handle, &tx_descs, 1 /* error */); + + ol_tx_discard_target_frms(pdev_handle); +} + +static inline +uint64_t ol_txrx_stats_ptr_to_u64(struct ol_txrx_stats_req_internal *req) +{ + return (uint64_t) ((size_t) req); +} + +static inline +struct ol_txrx_stats_req_internal *ol_txrx_u64_to_stats_ptr(uint64_t cookie) +{ + return (struct ol_txrx_stats_req_internal *)((size_t) cookie); +} + +#ifdef currently_unused +void +ol_txrx_fw_stats_cfg(ol_txrx_vdev_handle vdev, + uint8_t cfg_stats_type, uint32_t cfg_val) +{ + uint8_t dummy_cookie = 0; + + htt_h2t_dbg_stats_get(vdev->pdev->htt_pdev, 0 /* upload mask */, + 0 /* reset mask */, + cfg_stats_type, cfg_val, dummy_cookie); +} +#endif + +/** + * ol_txrx_fw_stats_desc_pool_init() - Initialize the fw stats descriptor pool + * @pdev: handle to ol txrx pdev + * @pool_size: Size of fw stats descriptor pool + * + * Return: 0 for success, error code on failure. + */ +int ol_txrx_fw_stats_desc_pool_init(struct ol_txrx_pdev_t *pdev, + uint8_t pool_size) +{ + int i; + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return -EINVAL; + } + pdev->ol_txrx_fw_stats_desc_pool.pool = qdf_mem_malloc(pool_size * + sizeof(struct ol_txrx_fw_stats_desc_elem_t)); + if (!pdev->ol_txrx_fw_stats_desc_pool.pool) + return -ENOMEM; + + pdev->ol_txrx_fw_stats_desc_pool.freelist = + &pdev->ol_txrx_fw_stats_desc_pool.pool[0]; + pdev->ol_txrx_fw_stats_desc_pool.pool_size = pool_size; + + for (i = 0; i < (pool_size - 1); i++) { + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.desc_id = i; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.req = NULL; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].next = + &pdev->ol_txrx_fw_stats_desc_pool.pool[i + 1]; + } + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.desc_id = i; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].desc.req = NULL; + pdev->ol_txrx_fw_stats_desc_pool.pool[i].next = NULL; + qdf_spinlock_create(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + qdf_atomic_init(&pdev->ol_txrx_fw_stats_desc_pool.initialized); + qdf_atomic_set(&pdev->ol_txrx_fw_stats_desc_pool.initialized, 1); + return 0; +} + +/** + * ol_txrx_fw_stats_desc_pool_deinit() - Deinitialize the + * fw stats descriptor pool + * @pdev: handle to ol txrx pdev + * + * Return: None + */ +void ol_txrx_fw_stats_desc_pool_deinit(struct ol_txrx_pdev_t *pdev) +{ + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + ol_txrx_err("Pool is not initialized"); + return; + } + if (!pdev->ol_txrx_fw_stats_desc_pool.pool) { + ol_txrx_err("Pool is not allocated"); + return; + } + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + qdf_atomic_set(&pdev->ol_txrx_fw_stats_desc_pool.initialized, 0); + qdf_mem_free(pdev->ol_txrx_fw_stats_desc_pool.pool); + pdev->ol_txrx_fw_stats_desc_pool.pool = NULL; + + pdev->ol_txrx_fw_stats_desc_pool.freelist = NULL; + pdev->ol_txrx_fw_stats_desc_pool.pool_size = 0; + qdf_spin_unlock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); +} + +/** + * ol_txrx_fw_stats_desc_alloc() - Get fw stats descriptor from fw stats + * free descriptor pool + * @pdev: handle to ol txrx pdev + * + * Return: pointer to fw stats descriptor, NULL on failure + */ +struct ol_txrx_fw_stats_desc_t + *ol_txrx_fw_stats_desc_alloc(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_fw_stats_desc_t *desc = NULL; + + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + qdf_spin_unlock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool.pool_lock); + ol_txrx_err("Pool deinitialized"); + return NULL; + } + if (pdev->ol_txrx_fw_stats_desc_pool.freelist) { + desc = &pdev->ol_txrx_fw_stats_desc_pool.freelist->desc; + pdev->ol_txrx_fw_stats_desc_pool.freelist = + pdev->ol_txrx_fw_stats_desc_pool.freelist->next; + } + qdf_spin_unlock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + + if (desc) + ol_txrx_dbg("desc_id %d allocated", desc->desc_id); + else + ol_txrx_err("fw stats descriptors are exhausted"); + + return desc; +} + +/** + * ol_txrx_fw_stats_desc_get_req() - Put fw stats descriptor + * back into free pool + * @pdev: handle to ol txrx pdev + * @fw_stats_desc: fw_stats_desc_get descriptor + * + * Return: pointer to request + */ +struct ol_txrx_stats_req_internal + *ol_txrx_fw_stats_desc_get_req(struct ol_txrx_pdev_t *pdev, + unsigned char desc_id) +{ + struct ol_txrx_fw_stats_desc_elem_t *desc_elem; + struct ol_txrx_stats_req_internal *req; + + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + if (!qdf_atomic_read(&pdev->ol_txrx_fw_stats_desc_pool.initialized)) { + qdf_spin_unlock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool.pool_lock); + ol_txrx_err("Desc ID %u Pool deinitialized", desc_id); + return NULL; + } + desc_elem = &pdev->ol_txrx_fw_stats_desc_pool.pool[desc_id]; + req = desc_elem->desc.req; + desc_elem->desc.req = NULL; + desc_elem->next = + pdev->ol_txrx_fw_stats_desc_pool.freelist; + pdev->ol_txrx_fw_stats_desc_pool.freelist = desc_elem; + qdf_spin_unlock_bh(&pdev->ol_txrx_fw_stats_desc_pool.pool_lock); + return req; +} + +/** + * ol_txrx_fw_stats_get() - Get fw stats + * + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * @req: specifications of stats request + * @per_vdev: bool input whether stats requested per vdev or not + * @response_expected: bool input whether expecting response or not + * + * Return: success or failure + */ +static A_STATUS +ol_txrx_fw_stats_get(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + struct ol_txrx_stats_req *req, bool per_vdev, + bool response_expected) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + struct ol_txrx_pdev_t *pdev; + uint8_t cookie = FW_STATS_DESC_POOL_SIZE; + struct ol_txrx_stats_req_internal *non_volatile_req; + struct ol_txrx_fw_stats_desc_t *desc = NULL; + struct ol_txrx_fw_stats_desc_elem_t *elem = NULL; + + if (!vdev) + return A_EINVAL; + + pdev = vdev->pdev; + if (!pdev || + req->stats_type_upload_mask >= 1 << HTT_DBG_NUM_STATS || + req->stats_type_reset_mask >= 1 << HTT_DBG_NUM_STATS) { + return A_EINVAL; + } + + /* + * Allocate a non-transient stats request object. + * (The one provided as an argument is likely allocated on the stack.) + */ + non_volatile_req = qdf_mem_malloc(sizeof(*non_volatile_req)); + if (!non_volatile_req) + return A_NO_MEMORY; + + /* copy the caller's specifications */ + non_volatile_req->base = *req; + non_volatile_req->serviced = 0; + non_volatile_req->offset = 0; + if (response_expected) { + desc = ol_txrx_fw_stats_desc_alloc(pdev); + if (!desc) { + qdf_mem_free(non_volatile_req); + return A_NO_MEMORY; + } + + /* use the desc id as the cookie */ + cookie = desc->desc_id; + desc->req = non_volatile_req; + qdf_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_INSERT_TAIL(&pdev->req_list, non_volatile_req, req_list_elem); + pdev->req_list_depth++; + qdf_spin_unlock_bh(&pdev->req_list_spinlock); + } + + if (htt_h2t_dbg_stats_get(pdev->htt_pdev, + req->stats_type_upload_mask, + req->stats_type_reset_mask, + HTT_H2T_STATS_REQ_CFG_STAT_TYPE_INVALID, 0, + cookie)) { + if (response_expected) { + qdf_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_REMOVE(&pdev->req_list, non_volatile_req, + req_list_elem); + pdev->req_list_depth--; + qdf_spin_unlock_bh(&pdev->req_list_spinlock); + if (desc) { + qdf_spin_lock_bh(&pdev->ol_txrx_fw_stats_desc_pool. + pool_lock); + desc->req = NULL; + elem = container_of(desc, + struct ol_txrx_fw_stats_desc_elem_t, + desc); + elem->next = + pdev->ol_txrx_fw_stats_desc_pool.freelist; + pdev->ol_txrx_fw_stats_desc_pool.freelist = elem; + qdf_spin_unlock_bh(&pdev-> + ol_txrx_fw_stats_desc_pool. + pool_lock); + } + } + + qdf_mem_free(non_volatile_req); + return A_ERROR; + } + + if (response_expected == false) + qdf_mem_free(non_volatile_req); + + return A_OK; +} + +void +ol_txrx_fw_stats_handler(ol_txrx_pdev_handle pdev, + uint8_t cookie, uint8_t *stats_info_list) +{ + enum htt_dbg_stats_type type; + enum htt_cmn_dbg_stats_type cmn_type = HTT_DBG_CMN_NUM_STATS_INVALID; + enum htt_dbg_stats_status status; + int length; + uint8_t *stats_data; + struct ol_txrx_stats_req_internal *req, *tmp; + int more = 0; + int found = 0; + + if (cookie >= FW_STATS_DESC_POOL_SIZE) { + ol_txrx_err("Cookie is not valid"); + return; + } + req = ol_txrx_fw_stats_desc_get_req(pdev, (uint8_t)cookie); + if (!req) { + ol_txrx_err("Request not retrieved for cookie %u", + (uint8_t)cookie); + return; + } + qdf_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { + if (req == tmp) { + found = 1; + break; + } + } + qdf_spin_unlock_bh(&pdev->req_list_spinlock); + + if (!found) { + ol_txrx_err( + "req(%pK) from firmware can't be found in the list", req); + return; + } + + do { + htt_t2h_dbg_stats_hdr_parse(stats_info_list, &type, &status, + &length, &stats_data); + if (status == HTT_DBG_STATS_STATUS_SERIES_DONE) + break; + if (status == HTT_DBG_STATS_STATUS_PRESENT || + status == HTT_DBG_STATS_STATUS_PARTIAL) { + uint8_t *buf; + int bytes = 0; + + if (status == HTT_DBG_STATS_STATUS_PARTIAL) + more = 1; + if (req->base.print.verbose || req->base.print.concise) + /* provide the header along with the data */ + htt_t2h_stats_print(stats_info_list, + req->base.print.concise); + + switch (type) { + case HTT_DBG_STATS_WAL_PDEV_TXRX: + bytes = sizeof(struct wlan_dbg_stats); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(struct wlan_dbg_stats); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + case HTT_DBG_STATS_RX_REORDER: + bytes = sizeof(struct rx_reorder_stats); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(struct rx_reorder_stats); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + case HTT_DBG_STATS_RX_RATE_INFO: + bytes = sizeof(wlan_dbg_rx_rate_info_t); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(wlan_dbg_rx_rate_info_t); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + + case HTT_DBG_STATS_TX_RATE_INFO: + bytes = sizeof(wlan_dbg_tx_rate_info_t); + if (req->base.copy.buf) { + int lmt; + + lmt = sizeof(wlan_dbg_tx_rate_info_t); + if (req->base.copy.byte_limit < lmt) + lmt = req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, lmt); + } + break; + + case HTT_DBG_STATS_TX_PPDU_LOG: + bytes = 0; + /* TO DO: specify how many bytes are present */ + /* TO DO: add copying to the requestor's buf */ + fallthrough; + case HTT_DBG_STATS_RX_REMOTE_RING_BUFFER_INFO: + bytes = sizeof(struct + rx_remote_buffer_mgmt_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + rx_remote_buffer_mgmt_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy. + byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TXBF_INFO: + bytes = sizeof(struct wlan_dbg_txbf_data_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + wlan_dbg_txbf_data_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy. + byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_SND_INFO: + bytes = sizeof(struct wlan_dbg_txbf_snd_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + wlan_dbg_txbf_snd_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy. + byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TX_SELFGEN_INFO: + bytes = sizeof(struct + wlan_dbg_tx_selfgen_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + wlan_dbg_tx_selfgen_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy. + byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_ERROR_INFO: + bytes = + sizeof(struct wlan_dbg_wifi2_error_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + wlan_dbg_wifi2_error_stats); + if (req->base.copy.byte_limit < limit) + limit = req->base.copy. + byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + case HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT: + bytes = + sizeof(struct rx_txbf_musu_ndpa_pkts_stats); + if (req->base.copy.buf) { + int limit; + + limit = sizeof(struct + rx_txbf_musu_ndpa_pkts_stats); + if (req->base.copy.byte_limit < limit) + limit = + req->base.copy.byte_limit; + buf = req->base.copy.buf + req->offset; + qdf_mem_copy(buf, stats_data, limit); + } + break; + + default: + break; + } + buf = req->base.copy.buf ? + req->base.copy.buf : stats_data; + + /* Not implemented for MCL */ + if (req->base.callback.fp) + req->base.callback.fp(req->base.callback.ctxt, + cmn_type, buf, bytes); + } + stats_info_list += length; + } while (1); + + if (!more) { + qdf_spin_lock_bh(&pdev->req_list_spinlock); + TAILQ_FOREACH(tmp, &pdev->req_list, req_list_elem) { + if (req == tmp) { + TAILQ_REMOVE(&pdev->req_list, req, req_list_elem); + pdev->req_list_depth--; + qdf_mem_free(req); + break; + } + } + qdf_spin_unlock_bh(&pdev->req_list_spinlock); + } +} + +#ifndef ATH_PERF_PWR_OFFLOAD /*---------------------------------------------*/ +int ol_txrx_debug(ol_txrx_vdev_handle vdev, int debug_specs) +{ + if (debug_specs & TXRX_DBG_MASK_OBJS) { +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 + ol_txrx_pdev_display(vdev->pdev, 0); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "The pdev,vdev,peer display functions are disabled.\n To enable them, recompile with TXRX_DEBUG_LEVEL > 5"); +#endif + } + if (debug_specs & TXRX_DBG_MASK_STATS) + ol_txrx_stats_display(vdev->pdev, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + if (debug_specs & TXRX_DBG_MASK_PROT_ANALYZE) { +#if defined(ENABLE_TXRX_PROT_ANALYZE) + ol_txrx_prot_ans_display(vdev->pdev); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "txrx protocol analysis is disabled.\n To enable it, recompile with ENABLE_TXRX_PROT_ANALYZE defined"); +#endif + } + if (debug_specs & TXRX_DBG_MASK_RX_REORDER_TRACE) { +#if defined(ENABLE_RX_REORDER_TRACE) + ol_rx_reorder_trace_display(vdev->pdev, 0, 0); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_FATAL, + "rx reorder seq num trace is disabled.\n To enable it, recompile with ENABLE_RX_REORDER_TRACE defined"); +#endif + + } + return 0; +} +#endif + +#ifdef currently_unused +int ol_txrx_aggr_cfg(ol_txrx_vdev_handle vdev, + int max_subfrms_ampdu, int max_subfrms_amsdu) +{ + return htt_h2t_aggr_cfg_msg(vdev->pdev->htt_pdev, + max_subfrms_ampdu, max_subfrms_amsdu); +} +#endif + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_pdev_display(ol_txrx_pdev_handle pdev, int indent) +{ + struct ol_txrx_vdev_t *vdev; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*s%s:\n", indent, " ", "txrx pdev"); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*spdev object: %pK", indent + 4, " ", pdev); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*svdev list:", indent + 4, " "); + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + ol_txrx_vdev_display(vdev, indent + 8); + } + ol_txrx_peer_find_display(pdev, indent + 4); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stx desc pool: %d elems @ %pK", indent + 4, " ", + pdev->tx_desc.pool_size, pdev->tx_desc.array); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, " "); + htt_display(pdev->htt_pdev, indent); +} + +void ol_txrx_vdev_display(ol_txrx_vdev_handle vdev, int indent) +{ + struct ol_txrx_peer_t *peer; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxrx vdev: %pK\n", indent, " ", vdev); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sID: %d\n", indent + 4, " ", vdev->vdev_id); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sMAC addr: %d:%d:%d:%d:%d:%d", + indent + 4, " ", + vdev->mac_addr.raw[0], vdev->mac_addr.raw[1], + vdev->mac_addr.raw[2], vdev->mac_addr.raw[3], + vdev->mac_addr.raw[4], vdev->mac_addr.raw[5]); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*speer list:", indent + 4, " "); + TAILQ_FOREACH(peer, &vdev->peer_list, peer_list_elem) { + ol_txrx_peer_display(peer, indent + 8); + } +} + +void ol_txrx_peer_display(ol_txrx_peer_handle peer, int indent) +{ + int i; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*stxrx peer: %pK", indent, " ", peer); + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] != HTT_INVALID_PEER) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sID: %d", indent + 4, " ", + peer->peer_ids[i]); + } + } +} +#endif /* TXRX_DEBUG_LEVEL */ + +/** + * ol_txrx_stats() - update ol layer stats + * @vdev_id: vdev_id + * @buffer: pointer to buffer + * @buf_len: length of the buffer + * + * Return: length of string + */ +static int +ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned int buf_len) +{ + uint32_t len = 0; + + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *) + ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: vdev is NULL", __func__); + snprintf(buffer, buf_len, "vdev not found"); + return len; + } + + len = scnprintf(buffer, buf_len, + "\n\nTXRX stats:\nllQueue State : %s\npause %u unpause %u\noverflow %u\nllQueue timer state : %s", + ((vdev->ll_pause.is_q_paused == false) ? + "UNPAUSED" : "PAUSED"), + vdev->ll_pause.q_pause_cnt, + vdev->ll_pause.q_unpause_cnt, + vdev->ll_pause.q_overflow_cnt, + ((vdev->ll_pause.is_q_timer_on == false) + ? "NOT-RUNNING" : "RUNNING")); + return len; +} + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +/** + * ol_txrx_disp_peer_cached_bufq_stats() - display peer cached_bufq stats + * @peer: peer pointer + * + * Return: None + */ +static void ol_txrx_disp_peer_cached_bufq_stats(struct ol_txrx_peer_t *peer) +{ + txrx_nofl_info("cached_bufq: curr %d drops %d hwm %d whatifs %d thresh %d", + peer->bufq_info.curr, + peer->bufq_info.dropped, + peer->bufq_info.high_water_mark, + peer->bufq_info.qdepth_no_thresh, + peer->bufq_info.thresh); +} + +/** + * ol_txrx_disp_peer_stats() - display peer stats + * @pdev: pdev pointer + * + * Return: None + */ +static void ol_txrx_disp_peer_stats(ol_txrx_pdev_handle pdev) +{ int i; + struct ol_txrx_peer_t *peer; + struct hif_opaque_softc *osc = cds_get_context(QDF_MODULE_ID_HIF); + + if (osc && hif_is_load_or_unload_in_progress(HIF_GET_SOFTC(osc))) + return; + + for (i = 0; i < OL_TXRX_NUM_LOCAL_PEER_IDS; i++) { + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + qdf_spin_lock_bh(&pdev->local_peer_ids.lock); + peer = pdev->local_peer_ids.map[i]; + if (peer) { + ol_txrx_peer_get_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + } + qdf_spin_unlock_bh(&pdev->local_peer_ids.lock); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + + if (peer) { + txrx_nofl_info("stats: peer 0x%pK local peer id %d", + peer, i); + ol_txrx_disp_peer_cached_bufq_stats(peer); + ol_txrx_peer_release_ref(peer, + PEER_DEBUG_ID_OL_INTERNAL); + } + } +} +#else +static void ol_txrx_disp_peer_stats(ol_txrx_pdev_handle pdev) +{ + txrx_nofl_info("peer stats not supported w/o QCA_SUPPORT_TXRX_LOCAL_PEER_ID"); +} +#endif + +void ol_txrx_stats_display(ol_txrx_pdev_handle pdev, + enum qdf_stats_verbosity_level level) +{ + u64 tx_dropped = + pdev->stats.pub.tx.dropped.download_fail.pkts + + pdev->stats.pub.tx.dropped.target_discard.pkts + + pdev->stats.pub.tx.dropped.no_ack.pkts + + pdev->stats.pub.tx.dropped.target_drop.pkts + + pdev->stats.pub.tx.dropped.others.pkts; + + if (level == QDF_STATS_VERBOSITY_LEVEL_LOW) { + txrx_nofl_dbg("STATS |%u %u|TX: %lld tso %lld ok %lld drops(%u-%lld %u-%lld %u-%lld %u-%lld ?-%lld hR-%lld)|RX: %lld drops(E %lld PI %lld ME %lld) fwd(S %d F %d SF %d)|", + pdev->tx_desc.num_free, + pdev->tx_desc.pool_size, + pdev->stats.pub.tx.from_stack.pkts, + pdev->stats.pub.tx.tso.tso_pkts.pkts, + pdev->stats.pub.tx.delivered.pkts, + htt_tx_status_download_fail, + pdev->stats.pub.tx.dropped.download_fail.pkts, + htt_tx_status_discard, + pdev->stats.pub.tx.dropped. + target_discard.pkts, + htt_tx_status_no_ack, + pdev->stats.pub.tx.dropped.no_ack.pkts, + htt_tx_status_drop, + pdev->stats.pub.tx.dropped.target_drop.pkts, + pdev->stats.pub.tx.dropped.others.pkts, + pdev->stats.pub.tx.dropped.host_reject.pkts, + pdev->stats.pub.rx.delivered.pkts, + pdev->stats.pub.rx.dropped_err.pkts, + pdev->stats.pub.rx.dropped_peer_invalid.pkts, + pdev->stats.pub.rx.dropped_mic_err.pkts, + pdev->stats.pub.rx.intra_bss_fwd. + packets_stack, + pdev->stats.pub.rx.intra_bss_fwd. + packets_fwd, + pdev->stats.pub.rx.intra_bss_fwd. + packets_stack_n_fwd); + return; + } + + txrx_nofl_info("TX PATH Statistics:"); + txrx_nofl_info("sent %lld msdus (%lld B), host rejected %lld (%lld B), dropped %lld (%lld B)", + pdev->stats.pub.tx.from_stack.pkts, + pdev->stats.pub.tx.from_stack.bytes, + pdev->stats.pub.tx.dropped.host_reject.pkts, + pdev->stats.pub.tx.dropped.host_reject.bytes, + tx_dropped, + pdev->stats.pub.tx.dropped.download_fail.bytes + + pdev->stats.pub.tx.dropped.target_discard.bytes + + pdev->stats.pub.tx.dropped.target_drop.bytes + + pdev->stats.pub.tx.dropped.no_ack.bytes); + txrx_nofl_info("successfully delivered: %lld (%lld B), download fail: %lld (%lld B), target discard: %lld (%lld B), no ack: %lld (%lld B),target drop: %lld (%lld B), others: %lld (%lld B)", + pdev->stats.pub.tx.delivered.pkts, + pdev->stats.pub.tx.delivered.bytes, + pdev->stats.pub.tx.dropped.download_fail.pkts, + pdev->stats.pub.tx.dropped.download_fail.bytes, + pdev->stats.pub.tx.dropped.target_discard.pkts, + pdev->stats.pub.tx.dropped.target_discard.bytes, + pdev->stats.pub.tx.dropped.no_ack.pkts, + pdev->stats.pub.tx.dropped.no_ack.bytes, + pdev->stats.pub.tx.dropped.target_drop.pkts, + pdev->stats.pub.tx.dropped.target_drop.bytes, + pdev->stats.pub.tx.dropped.others.pkts, + pdev->stats.pub.tx.dropped.others.bytes); + txrx_nofl_info("Tx completions per HTT message:\n" + "Single Packet %d\n" + " 2-10 Packets %d\n" + "11-20 Packets %d\n" + "21-30 Packets %d\n" + "31-40 Packets %d\n" + "41-50 Packets %d\n" + "51-60 Packets %d\n" + " 60+ Packets %d\n", + pdev->stats.pub.tx.comp_histogram.pkts_1, + pdev->stats.pub.tx.comp_histogram.pkts_2_10, + pdev->stats.pub.tx.comp_histogram.pkts_11_20, + pdev->stats.pub.tx.comp_histogram.pkts_21_30, + pdev->stats.pub.tx.comp_histogram.pkts_31_40, + pdev->stats.pub.tx.comp_histogram.pkts_41_50, + pdev->stats.pub.tx.comp_histogram.pkts_51_60, + pdev->stats.pub.tx.comp_histogram.pkts_61_plus); + + txrx_nofl_info("RX PATH Statistics:"); + txrx_nofl_info("%lld ppdus, %lld mpdus, %lld msdus, %lld bytes\n" + "dropped: err %lld (%lld B), peer_invalid %lld (%lld B), mic_err %lld (%lld B)\n" + "msdus with frag_ind: %d msdus with offload_ind: %d", + pdev->stats.priv.rx.normal.ppdus, + pdev->stats.priv.rx.normal.mpdus, + pdev->stats.pub.rx.delivered.pkts, + pdev->stats.pub.rx.delivered.bytes, + pdev->stats.pub.rx.dropped_err.pkts, + pdev->stats.pub.rx.dropped_err.bytes, + pdev->stats.pub.rx.dropped_peer_invalid.pkts, + pdev->stats.pub.rx.dropped_peer_invalid.bytes, + pdev->stats.pub.rx.dropped_mic_err.pkts, + pdev->stats.pub.rx.dropped_mic_err.bytes, + pdev->stats.pub.rx.msdus_with_frag_ind, + pdev->stats.pub.rx.msdus_with_offload_ind); + + txrx_nofl_info(" fwd to stack %d, fwd to fw %d, fwd to stack & fw %d\n", + pdev->stats.pub.rx.intra_bss_fwd.packets_stack, + pdev->stats.pub.rx.intra_bss_fwd.packets_fwd, + pdev->stats.pub.rx.intra_bss_fwd.packets_stack_n_fwd); + + txrx_nofl_info("packets per HTT message:\n" + "Single Packet %d\n" + " 2-10 Packets %d\n" + "11-20 Packets %d\n" + "21-30 Packets %d\n" + "31-40 Packets %d\n" + "41-50 Packets %d\n" + "51-60 Packets %d\n" + " 60+ Packets %d\n", + pdev->stats.pub.rx.rx_ind_histogram.pkts_1, + pdev->stats.pub.rx.rx_ind_histogram.pkts_2_10, + pdev->stats.pub.rx.rx_ind_histogram.pkts_11_20, + pdev->stats.pub.rx.rx_ind_histogram.pkts_21_30, + pdev->stats.pub.rx.rx_ind_histogram.pkts_31_40, + pdev->stats.pub.rx.rx_ind_histogram.pkts_41_50, + pdev->stats.pub.rx.rx_ind_histogram.pkts_51_60, + pdev->stats.pub.rx.rx_ind_histogram.pkts_61_plus); + + ol_txrx_disp_peer_stats(pdev); +} + +void ol_txrx_stats_clear(ol_txrx_pdev_handle pdev) +{ + qdf_mem_zero(&pdev->stats, sizeof(pdev->stats)); +} + +#if defined(ENABLE_TXRX_PROT_ANALYZE) + +void ol_txrx_prot_ans_display(ol_txrx_pdev_handle pdev) +{ + ol_txrx_prot_an_display(pdev->prot_an_tx_sent); + ol_txrx_prot_an_display(pdev->prot_an_rx_sent); +} + +#endif /* ENABLE_TXRX_PROT_ANALYZE */ + +#ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI +int16_t ol_txrx_peer_rssi(ol_txrx_peer_handle peer) +{ + return (peer->rssi_dbm == HTT_RSSI_INVALID) ? + OL_TXRX_RSSI_INVALID : peer->rssi_dbm; +} +#endif /* #ifdef QCA_SUPPORT_PEER_DATA_RX_RSSI */ + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +A_STATUS +ol_txrx_peer_stats_copy(ol_txrx_pdev_handle pdev, + ol_txrx_peer_handle peer, ol_txrx_peer_stats_t *stats) +{ + qdf_assert(pdev && peer && stats); + qdf_spin_lock_bh(&pdev->peer_stat_mutex); + qdf_mem_copy(stats, &peer->stats, sizeof(*stats)); + qdf_spin_unlock_bh(&pdev->peer_stat_mutex); + return A_OK; +} +#endif /* QCA_ENABLE_OL_TXRX_PEER_STATS */ + +/** + * ol_vdev_rx_set_intrabss_fwd() - Get fw stats + * + * @soc_hdl: datapath soc handle + * @vdev_id: virtual interface id + * @val: enable or disable + * + * Return: void + */ +static void ol_vdev_rx_set_intrabss_fwd(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool val) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_vdev_handle vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, + vdev_id); + + if (!vdev) + return; + + vdev->disable_intrabss_fwd = val; +} + +/** + * ol_txrx_update_mac_id() - update mac_id for vdev + * @soc_hdl: Datapath soc handle + * @vdev_id: vdev id + * @mac_id: mac id + * + * Return: none + */ +static void ol_txrx_update_mac_id(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint8_t mac_id) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *) + ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return; + } + vdev->mac_id = mac_id; +} + +/** + * ol_txrx_get_tx_ack_count() - get tx ack count + * @soc_hdl: Datapath soc handle + * @vdev_id: vdev_id + * + * Return: tx ack count + */ +static uint32_t ol_txrx_get_tx_ack_stats(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return 0; + } + + return vdev->txrx_stats.txack_success; +} + +/** + * ol_txrx_display_stats() - Display OL TXRX display stats + * @soc_hdl: Datapath soc handle + * @value: Module id for which stats needs to be displayed + * @verb_level: verbose level of stats to be displayed + * + * Return: status + */ +static QDF_STATUS +ol_txrx_display_stats(struct cdp_soc_t *soc_hdl, uint16_t value, + enum qdf_stats_verbosity_level verb_level) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id( + soc, + OL_TXRX_PDEV_ID); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return QDF_STATUS_E_NULL_VALUE; + } + + switch (value) { + case CDP_TXRX_PATH_STATS: + ol_txrx_stats_display(pdev, verb_level); + break; + case CDP_TXRX_TSO_STATS: + ol_txrx_stats_display_tso(pdev); + break; + case CDP_DUMP_TX_FLOW_POOL_INFO: + if (verb_level == QDF_STATS_VERBOSITY_LEVEL_LOW) + ol_tx_dump_flow_pool_info_compact(pdev); + else + ol_tx_dump_flow_pool_info(soc_hdl); + break; + case CDP_TXRX_DESC_STATS: + qdf_nbuf_tx_desc_count_display(); + break; + case CDP_WLAN_RX_BUF_DEBUG_STATS: + htt_display_rx_buf_debug(pdev->htt_pdev); + break; +#ifdef CONFIG_HL_SUPPORT + case CDP_SCHEDULER_STATS: + ol_tx_sched_cur_state_display(pdev); + ol_tx_sched_stats_display(pdev); + break; + case CDP_TX_QUEUE_STATS: + ol_tx_queue_log_display(pdev); + break; +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + case CDP_CREDIT_STATS: + ol_tx_dump_group_credit_stats(pdev); + break; +#endif + +#ifdef DEBUG_HL_LOGGING + case CDP_BUNDLE_STATS: + htt_dump_bundle_stats(pdev->htt_pdev); + break; +#endif +#endif + default: + status = QDF_STATUS_E_INVAL; + break; + } + return status; +} + +/** + * ol_txrx_clear_stats() - Clear OL TXRX stats + * @soc - ol soc handle + * @pdev_id: pdev identifier + * @value - Module id for which stats needs to be cleared + * + * Return: 0 - success/ non-zero failure + */ +static QDF_STATUS ol_txrx_clear_stats(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint8_t value) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL", __func__); + return QDF_STATUS_E_INVAL; + } + + switch (value) { + case CDP_TXRX_PATH_STATS: + ol_txrx_stats_clear(pdev); + break; + case CDP_TXRX_TSO_STATS: + ol_txrx_tso_stats_clear(pdev); + break; + case CDP_DUMP_TX_FLOW_POOL_INFO: + ol_tx_clear_flow_pool_stats(); + break; + case CDP_TXRX_DESC_STATS: + qdf_nbuf_tx_desc_count_clear(); + break; +#ifdef CONFIG_HL_SUPPORT + case CDP_SCHEDULER_STATS: + ol_tx_sched_stats_clear(pdev); + break; + case CDP_TX_QUEUE_STATS: + ol_tx_queue_log_clear(pdev); + break; +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + case CDP_CREDIT_STATS: + ol_tx_clear_group_credit_stats(pdev); + break; +#endif + case CDP_BUNDLE_STATS: + htt_clear_bundle_stats(pdev->htt_pdev); + break; +#endif + default: + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +/** + * ol_txrx_drop_nbuf_list() - drop an nbuf list + * @buf_list: buffer list to be dropepd + * + * Return: int (number of bufs dropped) + */ +static inline int ol_txrx_drop_nbuf_list(qdf_nbuf_t buf_list) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + int num_dropped = 0; + qdf_nbuf_t buf, next_buf; + + if (qdf_unlikely(!soc)) + return 0; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return 0; + } + + buf = buf_list; + while (buf) { + QDF_NBUF_CB_RX_PEER_CACHED_FRM(buf) = 1; + next_buf = qdf_nbuf_queue_next(buf); + if (pdev) + TXRX_STATS_MSDU_INCR(pdev, + rx.dropped_peer_invalid, buf); + qdf_nbuf_free(buf); + buf = next_buf; + num_dropped++; + } + return num_dropped; +} + +/** + * ol_rx_data_handler() - data rx handler + * @pdev: dev handle + * @buf_list: buffer list + * @staid: Station id + * + * Return: None + */ +static void ol_rx_data_handler(struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t buf_list, uint16_t staid) +{ + void *osif_dev; + uint8_t drop_count = 0; + qdf_nbuf_t buf, next_buf; + QDF_STATUS ret; + ol_txrx_rx_fp data_rx = NULL; + struct ol_txrx_peer_t *peer; + + if (qdf_unlikely(!pdev)) + goto free_buf; + + /* Do not use peer directly. Derive peer from staid to + * make sure that peer is valid. + */ + peer = ol_txrx_peer_get_ref_by_local_id((struct cdp_pdev *)pdev, + staid, PEER_DEBUG_ID_OL_RX_THREAD); + if (!peer) + goto free_buf; + + qdf_spin_lock_bh(&peer->peer_info_lock); + if (qdf_unlikely(!(peer->state >= OL_TXRX_PEER_STATE_CONN) || + !peer->vdev->rx)) { + qdf_spin_unlock_bh(&peer->peer_info_lock); + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_RX_THREAD); + goto free_buf; + } + + data_rx = peer->vdev->rx; + osif_dev = peer->vdev->osif_dev; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + qdf_spin_lock_bh(&peer->bufq_info.bufq_lock); + if (!list_empty(&peer->bufq_info.cached_bufq)) { + qdf_spin_unlock_bh(&peer->bufq_info.bufq_lock); + /* Flush the cached frames to HDD before passing new rx frame */ + ol_txrx_flush_rx_frames(peer, 0); + } else + qdf_spin_unlock_bh(&peer->bufq_info.bufq_lock); + + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_RX_THREAD); + + buf = buf_list; + while (buf) { + next_buf = qdf_nbuf_queue_next(buf); + qdf_nbuf_set_next(buf, NULL); /* Add NULL terminator */ + ret = data_rx(osif_dev, buf); + if (ret != QDF_STATUS_SUCCESS) { + ol_txrx_err("Frame Rx to HDD failed"); + if (pdev) + TXRX_STATS_MSDU_INCR(pdev, rx.dropped_err, buf); + qdf_nbuf_free(buf); + } + buf = next_buf; + } + return; + +free_buf: + drop_count = ol_txrx_drop_nbuf_list(buf_list); + ol_txrx_warn("Dropped frames %u", drop_count); +} + +/** + * ol_rx_data_cb() - data rx callback + * @context: dev handle + * @buf_list: buffer list + * @staid: Station id + * + * Return: None + */ +static inline void +ol_rx_data_cb(void *context, qdf_nbuf_t buf_list, uint16_t staid) +{ + struct ol_txrx_pdev_t *pdev = context; + + ol_rx_data_handler(pdev, buf_list, staid); +} + +/* print for every 16th packet */ +#define OL_TXRX_PRINT_RATE_LIMIT_THRESH 0x0f +struct ol_rx_cached_buf *cache_buf; + +/** helper function to drop packets + * Note: caller must hold the cached buq lock before invoking + * this function. Also, it assumes that the pointers passed in + * are valid (non-NULL) + */ +static inline void ol_txrx_drop_frames( + struct ol_txrx_cached_bufq_t *bufqi, + qdf_nbuf_t rx_buf_list) +{ + uint32_t dropped = ol_txrx_drop_nbuf_list(rx_buf_list); + + bufqi->dropped += dropped; + bufqi->qdepth_no_thresh += dropped; + + if (bufqi->qdepth_no_thresh > bufqi->high_water_mark) + bufqi->high_water_mark = bufqi->qdepth_no_thresh; +} + +static QDF_STATUS ol_txrx_enqueue_rx_frames( + struct ol_txrx_peer_t *peer, + struct ol_txrx_cached_bufq_t *bufqi, + qdf_nbuf_t rx_buf_list) +{ + struct ol_rx_cached_buf *cache_buf; + qdf_nbuf_t buf, next_buf; + static uint32_t count; + + if ((count++ & OL_TXRX_PRINT_RATE_LIMIT_THRESH) == 0) + ol_txrx_info_high( + "Data on the peer before it is registered bufq->curr %d bufq->drops %d", + bufqi->curr, bufqi->dropped); + + qdf_spin_lock_bh(&bufqi->bufq_lock); + if (bufqi->curr >= bufqi->thresh) { + ol_txrx_drop_frames(bufqi, rx_buf_list); + qdf_spin_unlock_bh(&bufqi->bufq_lock); + return QDF_STATUS_E_FAULT; + } + qdf_spin_unlock_bh(&bufqi->bufq_lock); + + buf = rx_buf_list; + while (buf) { + QDF_NBUF_CB_RX_PEER_CACHED_FRM(buf) = 1; + next_buf = qdf_nbuf_queue_next(buf); + cache_buf = qdf_mem_malloc(sizeof(*cache_buf)); + if (!cache_buf) { + qdf_nbuf_free(buf); + } else { + /* Add NULL terminator */ + qdf_nbuf_set_next(buf, NULL); + cache_buf->buf = buf; + if (peer && peer->valid) { + qdf_spin_lock_bh(&bufqi->bufq_lock); + list_add_tail(&cache_buf->list, + &bufqi->cached_bufq); + bufqi->curr++; + qdf_spin_unlock_bh(&bufqi->bufq_lock); + } else { + qdf_mem_free(cache_buf); + rx_buf_list = buf; + qdf_nbuf_set_next(rx_buf_list, next_buf); + qdf_spin_lock_bh(&bufqi->bufq_lock); + ol_txrx_drop_frames(bufqi, rx_buf_list); + qdf_spin_unlock_bh(&bufqi->bufq_lock); + return QDF_STATUS_E_FAULT; + } + } + buf = next_buf; + } + return QDF_STATUS_SUCCESS; +} +/** + * ol_rx_data_process() - process rx frame + * @peer: peer + * @rx_buf_list: rx buffer list + * + * Return: None + */ +void ol_rx_data_process(struct ol_txrx_peer_t *peer, + qdf_nbuf_t rx_buf_list) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + /* + * Firmware data path active response will use shim RX thread + * T2H MSG running on SIRQ context, + * IPA kernel module API should not be called on SIRQ CTXT + */ + ol_txrx_rx_fp data_rx = NULL; + + if (qdf_unlikely(!soc)) + goto drop_rx_buf; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if ((!peer) || (!pdev)) { + ol_txrx_err("peer/pdev is NULL"); + goto drop_rx_buf; + } + + qdf_assert(peer->vdev); + + qdf_spin_lock_bh(&peer->peer_info_lock); + if (peer->state >= OL_TXRX_PEER_STATE_CONN) + data_rx = peer->vdev->rx; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + /* + * If there is a data frame from peer before the peer is + * registered for data service, enqueue them on to pending queue + * which will be flushed to HDD once that station is registered. + */ + if (!data_rx) { + if (ol_txrx_enqueue_rx_frames(peer, &peer->bufq_info, + rx_buf_list) + != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: failed to enqueue rx frm to cached_bufq", + __func__); + } else { +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + /* + * If the kernel is SMP, schedule rx thread to + * better use multicores. + */ + if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) { + ol_rx_data_handler(pdev, rx_buf_list, peer->local_id); + } else { + p_cds_sched_context sched_ctx = + get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + + if (unlikely(!sched_ctx)) + goto drop_rx_buf; + + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (!pkt) + goto drop_rx_buf; + + pkt->callback = ol_rx_data_cb; + pkt->context = pdev; + pkt->Rxpkt = rx_buf_list; + pkt->staId = peer->local_id; + cds_indicate_rxpkt(sched_ctx, pkt); + } +#else /* WLAN_DP_LEGACY_OL_RX_THREAD */ + ol_rx_data_handler(pdev, rx_buf_list, peer->local_id); +#endif /* WLAN_DP_LEGACY_OL_RX_THREAD */ + } + + return; + +drop_rx_buf: + ol_txrx_drop_nbuf_list(rx_buf_list); +} + +/** + * ol_txrx_register_peer() - register peer + * @sta_desc: sta descriptor + * + * Return: QDF Status + */ +static QDF_STATUS ol_txrx_register_peer(struct ol_txrx_desc_type *sta_desc) +{ + struct ol_txrx_peer_t *peer; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + union ol_txrx_peer_update_param_t param; + struct privacy_exemption privacy_filter; + + if (!soc) { + ol_txrx_err("Soc is NULL"); + return QDF_STATUS_E_INVAL; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + + if (!pdev) { + ol_txrx_err("Pdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, + sta_desc->peer_addr.bytes); + + if (!peer) + return QDF_STATUS_E_FAULT; + + qdf_spin_lock_bh(&peer->peer_info_lock); + peer->state = OL_TXRX_PEER_STATE_CONN; + qdf_spin_unlock_bh(&peer->peer_info_lock); + + param.qos_capable = sta_desc->is_qos_enabled; + ol_txrx_peer_update(peer->vdev, peer->mac_addr.raw, ¶m, + ol_txrx_peer_update_qos_capable); + + if (sta_desc->is_wapi_supported) { + /*Privacy filter to accept unencrypted WAI frames */ + privacy_filter.ether_type = ETHERTYPE_WAI; + privacy_filter.filter_type = PRIVACY_FILTER_ALWAYS; + privacy_filter.packet_type = PRIVACY_FILTER_PACKET_BOTH; + ol_txrx_set_privacy_filters(peer->vdev, &privacy_filter, 1); + } + + ol_txrx_flush_rx_frames(peer, 0); + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_register_ocb_peer - Function to register the OCB peer + * @mac_addr: MAC address of the self peer + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure + */ +static QDF_STATUS ol_txrx_register_ocb_peer(uint8_t *mac_addr) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + ol_txrx_peer_handle peer; + + if (!soc) { + ol_txrx_err("Unable to find soc!"); + return QDF_STATUS_E_FAILURE; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + + if (!pdev) { + ol_txrx_err("Unable to find pdev!"); + return QDF_STATUS_E_FAILURE; + } + + peer = ol_txrx_find_peer_by_addr((struct cdp_pdev *)pdev, + mac_addr); + if (!peer) { + ol_txrx_err("Unable to find OCB peer!"); + return QDF_STATUS_E_FAILURE; + } + + ol_txrx_set_ocb_peer(pdev, peer); + + /* Set peer state to connected */ + ol_txrx_peer_state_update((struct cdp_soc_t *)soc, peer->mac_addr.raw, + OL_TXRX_PEER_STATE_AUTH); + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_set_ocb_peer - Function to store the OCB peer + * @pdev: Handle to the HTT instance + * @peer: Pointer to the peer + */ +void ol_txrx_set_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + if (!pdev) + return; + + pdev->ocb_peer = peer; + pdev->ocb_peer_valid = (NULL != peer); +} + +/** + * ol_txrx_get_ocb_peer - Function to retrieve the OCB peer + * @pdev: Handle to the HTT instance + * @peer: Pointer to the returned peer + * + * Return: true if the peer is valid, false if not + */ +bool ol_txrx_get_ocb_peer(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t **peer) +{ + int rc; + + if ((!pdev) || (!peer)) { + rc = false; + goto exit; + } + + if (pdev->ocb_peer_valid) { + *peer = pdev->ocb_peer; + rc = true; + } else { + rc = false; + } + +exit: + return rc; +} + +/** + * ol_txrx_register_pause_cb() - register pause callback + * @soc_hdl: Datapath soc handle + * @pause_cb: pause callback + * + * Return: QDF status + */ +static QDF_STATUS ol_txrx_register_pause_cb(struct cdp_soc_t *soc_hdl, + tx_pause_callback pause_cb) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev || !pause_cb) { + ol_txrx_err("pdev or pause_cb is NULL"); + return QDF_STATUS_E_INVAL; + } + pdev->pause_cb = pause_cb; + return QDF_STATUS_SUCCESS; +} + +#ifdef RECEIVE_OFFLOAD +/** + * ol_txrx_offld_flush_handler() - offld flush handler + * @context: dev handle + * @rxpkt: rx data + * @staid: station id + * + * This function handles an offld flush indication. + * If the rx thread is enabled, it will be invoked by the rx + * thread else it will be called in the tasklet context + * + * Return: none + */ +static void ol_txrx_offld_flush_handler(void *context, + qdf_nbuf_t rxpkt, + uint16_t staid) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) { + qdf_assert(0); + return; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (qdf_unlikely(!pdev)) { + ol_txrx_err("Invalid pdev context"); + qdf_assert(0); + return; + } + + if (pdev->offld_flush_cb) + pdev->offld_flush_cb(context); + else + ol_txrx_err("offld_flush_cb NULL"); +} + +/** + * ol_txrx_offld_flush() - offld flush callback + * @data: opaque data pointer + * + * This is the callback registered with CE to trigger + * an offld flush + * + * Return: none + */ +static void ol_txrx_offld_flush(void *data) +{ + p_cds_sched_context sched_ctx = get_cds_sched_ctxt(); + struct cds_ol_rx_pkt *pkt; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!sched_ctx)) + return; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (qdf_unlikely(!pdev)) { + ol_txrx_err("TXRX module context is NULL"); + return; + } + + if (!ol_cfg_is_rx_thread_enabled(pdev->ctrl_pdev)) { + ol_txrx_offld_flush_handler(data, NULL, 0); + } else { + pkt = cds_alloc_ol_rx_pkt(sched_ctx); + if (qdf_unlikely(!pkt)) + return; + + pkt->callback = ol_txrx_offld_flush_handler; + pkt->context = data; + pkt->Rxpkt = NULL; + pkt->staId = 0; + cds_indicate_rxpkt(sched_ctx, pkt); + } +} + +/** + * ol_register_offld_flush_cb() - register the offld flush callback + * @offld_flush_cb: flush callback function + * @offld_init_cb: Allocate and initialize offld data structure. + * + * Store the offld flush callback provided and in turn + * register OL's offld flush handler with CE + * + * Return: none + */ +static void ol_register_offld_flush_cb(void (offld_flush_cb)(void *)) +{ + struct hif_opaque_softc *hif_device; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) { + TXRX_ASSERT2(0); + goto out; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev NULL!"); + TXRX_ASSERT2(0); + goto out; + } + if (pdev->offld_flush_cb) { + ol_txrx_info("offld already initialised"); + if (pdev->offld_flush_cb != offld_flush_cb) { + ol_txrx_err( + "offld_flush_cb is differ to previously registered callback") + TXRX_ASSERT2(0); + goto out; + } + goto out; + } + pdev->offld_flush_cb = offld_flush_cb; + hif_device = cds_get_context(QDF_MODULE_ID_HIF); + + if (qdf_unlikely(!hif_device)) { + qdf_assert(0); + goto out; + } + + hif_offld_flush_cb_register(hif_device, ol_txrx_offld_flush); + +out: + return; +} + +/** + * ol_deregister_offld_flush_cb() - deregister the offld flush callback + * + * Remove the offld flush callback provided and in turn + * deregister OL's offld flush handler with CE + * + * Return: none + */ +static void ol_deregister_offld_flush_cb(void) +{ + struct hif_opaque_softc *hif_device; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev NULL!"); + return; + } + hif_device = cds_get_context(QDF_MODULE_ID_HIF); + + if (qdf_unlikely(!hif_device)) { + qdf_assert(0); + return; + } + + hif_offld_flush_cb_deregister(hif_device); + + pdev->offld_flush_cb = NULL; +} +#endif /* RECEIVE_OFFLOAD */ + +/** + * ol_register_data_stall_detect_cb() - register data stall callback + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @data_stall_detect_callback: data stall callback function + * + * + * Return: QDF_STATUS Enumeration + */ +static QDF_STATUS ol_register_data_stall_detect_cb( + struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + data_stall_detect_cb data_stall_detect_callback) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev NULL!"); + return QDF_STATUS_E_INVAL; + } + pdev->data_stall_detect_callback = data_stall_detect_callback; + return QDF_STATUS_SUCCESS; +} + +/** + * ol_deregister_data_stall_detect_cb() - de-register data stall callback + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @data_stall_detect_callback: data stall callback function + * + * + * Return: QDF_STATUS Enumeration + */ +static QDF_STATUS ol_deregister_data_stall_detect_cb( + struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + data_stall_detect_cb data_stall_detect_callback) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev NULL!"); + return QDF_STATUS_E_INVAL; + } + pdev->data_stall_detect_callback = NULL; + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_post_data_stall_event() - post data stall event + * @indicator: Module triggering data stall + * @data_stall_type: data stall event type + * @pdev_id: pdev id + * @vdev_id_bitmap: vdev id bitmap + * @recovery_type: data stall recovery type + * + * Return: None + */ +static void ol_txrx_post_data_stall_event( + struct cdp_soc_t *soc_hdl, + enum data_stall_log_event_indicator indicator, + enum data_stall_log_event_type data_stall_type, + uint32_t pdev_id, uint32_t vdev_id_bitmap, + enum data_stall_log_recovery_type recovery_type) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct data_stall_event_info data_stall_info; + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) { + ol_txrx_err("soc is NULL"); + return; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + if (!pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: pdev is NULL.", __func__); + return; + } + + if (!pdev->data_stall_detect_callback) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: data stall cb not registered", __func__); + return; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: data_stall_type: %x pdev_id: %d", + __func__, data_stall_type, pdev_id); + + data_stall_info.indicator = indicator; + data_stall_info.data_stall_type = data_stall_type; + data_stall_info.vdev_id_bitmap = vdev_id_bitmap; + data_stall_info.pdev_id = pdev_id; + data_stall_info.recovery_type = recovery_type; + + if (data_stall_info.data_stall_type == + DATA_STALL_LOG_FW_RX_REFILL_FAILED) { + htt_log_rx_ring_info(pdev->htt_pdev); + htt_rx_refill_failure(pdev->htt_pdev); + } + + pdev->data_stall_detect_callback(&data_stall_info); +} + +void +ol_txrx_dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len) +{ + qdf_print(" Pkt: VA 0x%pK PA 0x%llx len %d\n", + qdf_nbuf_data(nbuf), (unsigned long long int)nbuf_paddr, len); + print_hex_dump(KERN_DEBUG, "Pkt: ", DUMP_PREFIX_ADDRESS, 16, 4, + qdf_nbuf_data(nbuf), len, true); +} + +struct cdp_vdev *ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_vdev_handle vdev = NULL; + + if (qdf_unlikely(!soc)) + return NULL; + + vdev = ol_txrx_get_vdev_from_soc_vdev_id(soc, vdev_id); + + return ol_txrx_vdev_t_to_cdp_vdev(vdev); +} + +struct ol_txrx_vdev_t *ol_txrx_get_vdev_from_soc_vdev_id( + struct ol_txrx_soc_t *soc, uint8_t vdev_id) +{ + ol_txrx_pdev_handle pdev; + ol_txrx_vdev_handle vdev = NULL; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (qdf_unlikely(!pdev)) + return NULL; + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if (vdev->vdev_id == vdev_id) + break; + } + + return vdev; +} + +/** + * ol_txrx_get_mon_vdev_from_pdev() - get monitor mode vdev from pdev + * @soc_hdl: datapath soc handle + * @pdev_id: the physical device id the virtual device belongs to + * + * Return: vdev id + * error if not found. + */ +uint8_t ol_txrx_get_mon_vdev_from_pdev(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = (struct ol_txrx_soc_t *)soc_hdl; + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (qdf_unlikely(!pdev)) + return -EINVAL; + + return pdev->monitor_vdev->vdev_id; +} + +/** + * ol_txrx_set_wisa_mode() - set wisa mode + * @soc_hdl: Datapath soc handle + * @vdev_id: vdev_id + * @enable: enable flag + * + * Return: QDF STATUS + */ +static QDF_STATUS ol_txrx_set_wisa_mode(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool enable) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) + return QDF_STATUS_E_INVAL; + + vdev->is_wisa_mode_enable = enable; + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_get_vdev_id() - get interface id from interface context + * @pvdev: vdev handle + * + * Return: virtual interface id + */ +static uint16_t ol_txrx_get_vdev_id(struct cdp_vdev *pvdev) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)pvdev; + + return vdev->vdev_id; +} + +/** + * ol_txrx_soc_attach_target() - attach soc target + * @soc: soc handle + * + * MCL legacy OL do nothing here + * + * Return: 0 + */ +static QDF_STATUS ol_txrx_soc_attach_target(ol_txrx_soc_handle soc) +{ + /* MCL legacy OL do nothing here */ + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_soc_detach() - detach soc target + * @soc: soc handle + * + * MCL legacy OL do nothing here + * + * Return: none + */ +static void ol_txrx_soc_detach(struct cdp_soc_t *soc) +{ + qdf_mem_free(soc); +} + +#ifdef REMOVE_PKT_LOG +/** + * ol_txrx_pkt_log_con_service() - connect packet log service + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @scn: device context + * + * Return: none + */ +static void ol_txrx_pkt_log_con_service(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, void *scn) +{ +} + +/** + * ol_txrx_pkt_log_exit() - cleanup packet log info + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * + * Return: none + */ +static void ol_txrx_pkt_log_exit(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ +} + +#else +static void ol_txrx_pkt_log_con_service(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, void *scn) +{ + htt_pkt_log_init(soc_hdl, pdev_id, scn); + pktlog_htc_attach(); +} + +static void ol_txrx_pkt_log_exit(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev handle is NULL"); + return; + } + + htt_pktlogmod_exit(pdev); +} +#endif + +/* OL wrapper functions for CDP abstraction */ +/** + * ol_txrx_wrapper_flush_rx_frames() - flush rx frames on the queue + * @soc: data path soc handle + * @pdev_id: datapath pdev identifier + * @peer_mac: peer mac address + * @drop: rx packets drop or deliver + * + * Return: none + */ +static void ol_txrx_wrapper_flush_rx_frames(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, void *peer_mac, + bool drop) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_peer_t *peer; + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + peer = ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac, 0, 1, + PEER_DEBUG_ID_OL_INTERNAL); + if (!peer) { + ol_txrx_err("peer "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(peer_mac)); + return; + } + + ol_txrx_flush_rx_frames(peer, drop); +} + +/** + * ol_txrx_wrapper_register_peer() - register peer + * @pdev: pdev handle + * @sta_desc: peer description + * + * Return: QDF STATUS + */ +static QDF_STATUS ol_txrx_wrapper_register_peer( + struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + struct ol_txrx_desc_type *sta_desc) +{ + return ol_txrx_register_peer(sta_desc); +} + +/** + * ol_txrx_wrapper_cfg_is_high_latency() - device is high or low latency device + * @pdev: pdev handle + * + * Return: 1 high latency bus + * 0 low latency bus + */ +static int ol_txrx_wrapper_cfg_is_high_latency(struct cdp_cfg *cfg_pdev) +{ + return ol_cfg_is_high_latency(cfg_pdev); +} + +/** + * ol_txrx_wrapper_peer_state_update() - specify the peer's authentication state + * @soc_hdl - datapath soc handle + * @peer_mac - mac address of which peer has changed its state + * @state - the new state of the peer + * + * Specify the peer's authentication state (none, connected, authenticated) + * to allow the data SW to determine whether to filter out invalid data frames. + * (In the "connected" state, where security is enabled, but authentication + * has not completed, tx and rx data frames other than EAPOL or WAPI should + * be discarded.) + * This function is only relevant for systems in which the tx and rx filtering + * are done in the host rather than in the target. + * + * Return: QDF Status + */ +static QDF_STATUS ol_txrx_wrapper_peer_state_update( + struct cdp_soc_t *soc_hdl, + uint8_t *peer_mac, + enum ol_txrx_peer_state state) +{ + return ol_txrx_peer_state_update(soc_hdl, peer_mac, state); +} + +/** + * ol_txrx_wrapper_set_flow_control_parameters() - set flow control parameters + * @cfg_ctx: cfg context + * @cfg_param: cfg parameters + * + * Return: none + */ +static void +ol_txrx_wrapper_set_flow_control_parameters(struct cdp_cfg *cfg_pdev, + void *cfg_param) +{ + return ol_tx_set_flow_control_parameters( + cfg_pdev, + (struct txrx_pdev_cfg_param_t *)cfg_param); +} + +/** + * ol_txrx_get_cfg() - get ini/cgf values in legacy dp + * @soc_hdl: soc context + * @cfg_param: cfg parameters + * + * Return: none + */ +static uint32_t ol_txrx_get_cfg(struct cdp_soc_t *soc_hdl, enum cdp_dp_cfg cfg) +{ + struct txrx_pdev_cfg_t *cfg_ctx; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id( + soc, + OL_TXRX_PDEV_ID); + uint32_t value = 0; + + if (!pdev) { + qdf_print("pdev is NULL"); + return 0; + } + + cfg_ctx = (struct txrx_pdev_cfg_t *)(pdev->ctrl_pdev); + switch (cfg) { + case cfg_dp_enable_data_stall: + value = cfg_ctx->enable_data_stall_detection; + break; + case cfg_dp_enable_ip_tcp_udp_checksum_offload: + value = cfg_ctx->ip_tcp_udp_checksum_offload; + break; + case cfg_dp_enable_p2p_ip_tcp_udp_checksum_offload: + value = cfg_ctx->p2p_ip_tcp_udp_checksum_offload; + break; + case cfg_dp_enable_nan_ip_tcp_udp_checksum_offload: + value = cfg_ctx->nan_tcp_udp_checksumoffload; + break; + case cfg_dp_tso_enable: + value = cfg_ctx->tso_enable; + break; + case cfg_dp_lro_enable: + value = cfg_ctx->lro_enable; + break; + case cfg_dp_sg_enable: + value = cfg_ctx->sg_enable; + break; + case cfg_dp_gro_enable: + value = cfg_ctx->gro_enable; + break; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + case cfg_dp_tx_flow_start_queue_offset: + value = cfg_ctx->tx_flow_start_queue_offset; + break; + case cfg_dp_tx_flow_stop_queue_threshold: + value = cfg_ctx->tx_flow_stop_queue_th; + break; +#endif + case cfg_dp_ipa_uc_tx_buf_size: + value = cfg_ctx->uc_tx_buffer_size; + break; + case cfg_dp_ipa_uc_tx_partition_base: + value = cfg_ctx->uc_tx_partition_base; + break; + case cfg_dp_ipa_uc_rx_ind_ring_count: + value = cfg_ctx->uc_rx_indication_ring_count; + break; + case cfg_dp_enable_flow_steering: + value = cfg_ctx->enable_flow_steering; + break; + case cfg_dp_reorder_offload_supported: + value = cfg_ctx->is_full_reorder_offload; + break; + case cfg_dp_ce_classify_enable: + value = cfg_ctx->ce_classify_enabled; + break; + case cfg_dp_disable_intra_bss_fwd: + value = cfg_ctx->disable_intra_bss_fwd; + break; + case cfg_dp_pktlog_buffer_size: + value = cfg_ctx->pktlog_buffer_size; + break; + default: + value = 0; + break; + } + + return value; +} + +/* + * ol_get_pdev_param: function to get parameters from pdev + * @cdp_soc: txrx soc handle + * @pdev_id: id of pdev handle + * @param: parameter type to be get + * @val: parameter type to be get + * + * Return: SUCCESS or FAILURE + */ +static QDF_STATUS ol_get_pdev_param(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + enum cdp_pdev_param_type param, + cdp_config_param_type *val) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *olpdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + struct cdp_pdev *pdev = ol_txrx_pdev_t_to_cdp_pdev(olpdev); + + if (!pdev) + return QDF_STATUS_E_FAILURE; + + switch (param) { + case CDP_TX_PENDING: + val->cdp_pdev_param_tx_pending = ol_txrx_get_tx_pending(pdev); + break; + default: + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * ol_set_pdev_param: function to get parameters from pdev + * @cdp_soc: txrx soc handle + * @pdev_id: id of pdev handle + * @param: parameter type to be get + * @val: parameter type to be get + * + * Return: SUCCESS or FAILURE + */ +static QDF_STATUS ol_set_pdev_param(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + enum cdp_pdev_param_type param, + cdp_config_param_type val) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *olpdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + struct cdp_pdev *pdev = ol_txrx_pdev_t_to_cdp_pdev(olpdev); + + if (!pdev) + return QDF_STATUS_E_FAILURE; + + switch (param) { + case CDP_MONITOR_CHANNEL: + { + ol_htt_mon_note_chan(pdev, val.cdp_pdev_param_monitor_chan); + break; + } + default: + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WDI_EVENT_ENABLE +void *ol_get_pldev(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + struct ol_txrx_pdev_t *pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + + if (pdev) + return pdev->pl_dev; + + return NULL; +} +#endif + +/** + * ol_register_packetdump_callback() - registers + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler. + * + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * @ol_tx_packetdump_cb: tx packetdump cb + * @ol_rx_packetdump_cb: rx packetdump cb + * + * This function is used to register tx data pkt, tx mgmt. + * pkt and rx data pkt dump callback + * + * Return: None + * + */ +static inline +void ol_register_packetdump_callback(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + ol_txrx_pktdump_cb ol_tx_packetdump_cb, + ol_txrx_pktdump_cb ol_rx_packetdump_cb) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + pdev->ol_tx_packetdump_cb = ol_tx_packetdump_cb; + pdev->ol_rx_packetdump_cb = ol_rx_packetdump_cb; +} + +/** + * ol_deregister_packetdump_callback() - deregidters + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler + * @soc_hdl: Datapath soc handle + * @pdev_id: id of data path pdev handle + * + * This function is used to deregidter tx data pkt., + * tx mgmt. pkt and rx data pkt. dump callback + * + * Return: None + * + */ +static inline +void ol_deregister_packetdump_callback(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + pdev->ol_tx_packetdump_cb = NULL; + pdev->ol_rx_packetdump_cb = NULL; +} + +static struct cdp_cmn_ops ol_ops_cmn = { + .txrx_soc_attach_target = ol_txrx_soc_attach_target, + .txrx_vdev_attach = ol_txrx_vdev_attach, + .txrx_vdev_detach = ol_txrx_vdev_detach, + .txrx_pdev_attach = ol_txrx_pdev_attach, + .txrx_pdev_attach_target = ol_txrx_pdev_attach_target, + .txrx_pdev_post_attach = ol_txrx_pdev_post_attach, + .txrx_pdev_pre_detach = ol_txrx_pdev_pre_detach, + .txrx_pdev_detach = ol_txrx_pdev_detach, + .txrx_peer_create = ol_txrx_peer_attach, + .txrx_peer_setup = NULL, + .txrx_peer_teardown = NULL, + .txrx_peer_delete = ol_txrx_peer_detach, + .txrx_peer_delete_sync = ol_txrx_peer_detach_sync, + .txrx_vdev_register = ol_txrx_vdev_register, + .txrx_soc_detach = ol_txrx_soc_detach, + .txrx_get_vdev_mac_addr = ol_txrx_get_vdev_mac_addr, + .txrx_get_ctrl_pdev_from_vdev = ol_txrx_get_ctrl_pdev_from_vdev, + .txrx_get_mon_vdev_from_pdev = ol_txrx_get_mon_vdev_from_pdev, + .txrx_mgmt_send_ext = ol_txrx_mgmt_send_ext, + .txrx_mgmt_tx_cb_set = ol_txrx_mgmt_tx_cb_set, + .txrx_data_tx_cb_set = ol_txrx_data_tx_cb_set, + .txrx_peer_unmap_sync_cb_set = ol_txrx_peer_unmap_sync_cb_set, + .flush_cache_rx_queue = ol_txrx_flush_cache_rx_queue, + .txrx_fw_stats_get = ol_txrx_fw_stats_get, + .display_stats = ol_txrx_display_stats, + .txrx_get_cfg = ol_txrx_get_cfg, + /* TODO: Add other functions */ +}; + +static struct cdp_misc_ops ol_ops_misc = { + .set_ibss_vdev_heart_beat_timer = + ol_txrx_set_ibss_vdev_heart_beat_timer, +#ifdef CONFIG_HL_SUPPORT + .set_wmm_param = ol_txrx_set_wmm_param, +#endif /* CONFIG_HL_SUPPORT */ + .bad_peer_txctl_set_setting = ol_txrx_bad_peer_txctl_set_setting, + .bad_peer_txctl_update_threshold = + ol_txrx_bad_peer_txctl_update_threshold, + .hl_tdls_flag_reset = ol_txrx_hl_tdls_flag_reset, + .tx_non_std = ol_tx_non_std, + .get_vdev_id = ol_txrx_get_vdev_id, + .get_tx_ack_stats = ol_txrx_get_tx_ack_stats, + .set_wisa_mode = ol_txrx_set_wisa_mode, + .txrx_data_stall_cb_register = ol_register_data_stall_detect_cb, + .txrx_data_stall_cb_deregister = ol_deregister_data_stall_detect_cb, + .txrx_post_data_stall_event = ol_txrx_post_data_stall_event, +#ifdef FEATURE_RUNTIME_PM + .runtime_suspend = ol_txrx_runtime_suspend, + .runtime_resume = ol_txrx_runtime_resume, +#endif /* FEATURE_RUNTIME_PM */ + .get_opmode = ol_txrx_get_opmode, + .mark_first_wakeup_packet = ol_tx_mark_first_wakeup_packet, + .update_mac_id = ol_txrx_update_mac_id, + .flush_rx_frames = ol_txrx_wrapper_flush_rx_frames, + .get_intra_bss_fwd_pkts_count = ol_get_intra_bss_fwd_pkts_count, + .pkt_log_init = htt_pkt_log_init, + .pkt_log_con_service = ol_txrx_pkt_log_con_service, + .pkt_log_exit = ol_txrx_pkt_log_exit, + .register_pktdump_cb = ol_register_packetdump_callback, + .unregister_pktdump_cb = ol_deregister_packetdump_callback, +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + .pdev_reset_driver_del_ack = ol_tx_pdev_reset_driver_del_ack, + .vdev_set_driver_del_ack_enable = ol_tx_vdev_set_driver_del_ack_enable, +#endif +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE + .vdev_set_bundle_require_flag = ol_tx_vdev_set_bundle_require, + .pdev_reset_bundle_require_flag = ol_tx_pdev_reset_bundle_require, +#endif +}; + +static struct cdp_flowctl_ops ol_ops_flowctl = { + .register_pause_cb = ol_txrx_register_pause_cb, +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + .set_desc_global_pool_size = ol_tx_set_desc_global_pool_size, + .dump_flow_pool_info = ol_tx_dump_flow_pool_info, + .tx_desc_thresh_reached = ol_tx_desc_thresh_reached, +#endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ +}; + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) +static struct cdp_lflowctl_ops ol_ops_l_flowctl = { + .register_tx_flow_control = ol_txrx_register_tx_flow_control, + .deregister_tx_flow_control_cb = ol_txrx_deregister_tx_flow_control_cb, + .flow_control_cb = ol_txrx_flow_control_cb, + .get_tx_resource = ol_txrx_get_tx_resource, + .ll_set_tx_pause_q_depth = ol_txrx_ll_set_tx_pause_q_depth, + .vdev_flush = ol_txrx_vdev_flush, + .vdev_pause = ol_txrx_vdev_pause, + .vdev_unpause = ol_txrx_vdev_unpause +}; /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ +#elif defined(QCA_HL_NETDEV_FLOW_CONTROL) +static struct cdp_lflowctl_ops ol_ops_l_flowctl = { + .register_tx_flow_control = ol_txrx_register_hl_flow_control, + .vdev_flush = ol_txrx_vdev_flush, + .vdev_pause = ol_txrx_vdev_pause, + .vdev_unpause = ol_txrx_vdev_unpause, + .set_vdev_os_queue_status = ol_txrx_set_vdev_os_queue_status, + .set_vdev_tx_desc_limit = ol_txrx_set_vdev_tx_desc_limit +}; +#else /* QCA_HL_NETDEV_FLOW_CONTROL */ +static struct cdp_lflowctl_ops ol_ops_l_flowctl = { }; +#endif + +#ifdef IPA_OFFLOAD +static struct cdp_ipa_ops ol_ops_ipa = { + .ipa_get_resource = ol_txrx_ipa_uc_get_resource, + .ipa_set_doorbell_paddr = ol_txrx_ipa_uc_set_doorbell_paddr, + .ipa_set_active = ol_txrx_ipa_uc_set_active, + .ipa_op_response = ol_txrx_ipa_uc_op_response, + .ipa_register_op_cb = ol_txrx_ipa_uc_register_op_cb, + .ipa_get_stat = ol_txrx_ipa_uc_get_stat, + .ipa_tx_data_frame = ol_tx_send_ipa_data_frame, + .ipa_set_uc_tx_partition_base = ol_cfg_set_ipa_uc_tx_partition_base, + .ipa_enable_autonomy = ol_txrx_ipa_enable_autonomy, + .ipa_disable_autonomy = ol_txrx_ipa_disable_autonomy, + .ipa_setup = ol_txrx_ipa_setup, + .ipa_cleanup = ol_txrx_ipa_cleanup, + .ipa_setup_iface = ol_txrx_ipa_setup_iface, + .ipa_cleanup_iface = ol_txrx_ipa_cleanup_iface, + .ipa_enable_pipes = ol_txrx_ipa_enable_pipes, + .ipa_disable_pipes = ol_txrx_ipa_disable_pipes, + .ipa_set_perf_level = ol_txrx_ipa_set_perf_level, +#ifdef FEATURE_METERING + .ipa_uc_get_share_stats = ol_txrx_ipa_uc_get_share_stats, + .ipa_uc_set_quota = ol_txrx_ipa_uc_set_quota, +#endif + .ipa_tx_buf_smmu_mapping = ol_txrx_ipa_tx_buf_smmu_mapping, + .ipa_tx_buf_smmu_unmapping = ol_txrx_ipa_tx_buf_smmu_unmapping +}; +#endif + +#ifdef RECEIVE_OFFLOAD +static struct cdp_rx_offld_ops ol_rx_offld_ops = { + .register_rx_offld_flush_cb = ol_register_offld_flush_cb, + .deregister_rx_offld_flush_cb = ol_deregister_offld_flush_cb +}; +#endif + +static struct cdp_bus_ops ol_ops_bus = { + .bus_suspend = ol_txrx_bus_suspend, + .bus_resume = ol_txrx_bus_resume +}; + +#ifdef WLAN_FEATURE_DSRC +static struct cdp_ocb_ops ol_ops_ocb = { + .set_ocb_chan_info = ol_txrx_set_ocb_chan_info, + .get_ocb_chan_info = ol_txrx_get_ocb_chan_info +}; +#endif + +static struct cdp_throttle_ops ol_ops_throttle = { +#ifdef QCA_SUPPORT_TX_THROTTLE + .throttle_init_period = ol_tx_throttle_init_period, + .throttle_set_level = ol_tx_throttle_set_level +#endif /* QCA_SUPPORT_TX_THROTTLE */ +}; + +static struct cdp_mob_stats_ops ol_ops_mob_stats = { + .clear_stats = ol_txrx_clear_stats, + .stats = ol_txrx_stats +}; + +static struct cdp_cfg_ops ol_ops_cfg = { + .set_cfg_rx_fwd_disabled = ol_set_cfg_rx_fwd_disabled, + .set_cfg_packet_log_enabled = ol_set_cfg_packet_log_enabled, + .cfg_attach = ol_pdev_cfg_attach, + .vdev_rx_set_intrabss_fwd = ol_vdev_rx_set_intrabss_fwd, + .is_rx_fwd_disabled = ol_txrx_is_rx_fwd_disabled, + .tx_set_is_mgmt_over_wmi_enabled = ol_tx_set_is_mgmt_over_wmi_enabled, + .is_high_latency = ol_txrx_wrapper_cfg_is_high_latency, + .set_flow_control_parameters = + ol_txrx_wrapper_set_flow_control_parameters, + .set_flow_steering = ol_set_cfg_flow_steering, + .set_ptp_rx_opt_enabled = ol_set_cfg_ptp_rx_opt_enabled, + .set_new_htt_msg_format = + ol_txrx_set_new_htt_msg_format, + .set_peer_unmap_conf_support = ol_txrx_set_peer_unmap_conf_support, + .get_peer_unmap_conf_support = ol_txrx_get_peer_unmap_conf_support, + .set_tx_compl_tsf64 = ol_txrx_set_tx_compl_tsf64, + .get_tx_compl_tsf64 = ol_txrx_get_tx_compl_tsf64, +}; + +static struct cdp_peer_ops ol_ops_peer = { + .register_peer = ol_txrx_wrapper_register_peer, + .clear_peer = ol_txrx_clear_peer, + .find_peer_exist = ol_txrx_find_peer_exist, + .find_peer_exist_on_vdev = ol_txrx_find_peer_exist_on_vdev, + .find_peer_exist_on_other_vdev = ol_txrx_find_peer_exist_on_other_vdev, + .peer_state_update = ol_txrx_wrapper_peer_state_update, + .get_vdevid = ol_txrx_get_vdevid, + .get_vdev_by_peer_addr = ol_txrx_wrapper_get_vdev_by_peer_addr, + .register_ocb_peer = ol_txrx_register_ocb_peer, + .peer_get_peer_mac_addr = ol_txrx_peer_get_peer_mac_addr, + .get_peer_state = ol_txrx_get_peer_state, + .update_ibss_add_peer_num_of_vdev = + ol_txrx_update_ibss_add_peer_num_of_vdev, +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + .copy_mac_addr_raw = ol_txrx_copy_mac_addr_raw, + .add_last_real_peer = ol_txrx_add_last_real_peer, + .is_vdev_restore_last_peer = is_vdev_restore_last_peer, + .update_last_real_peer = ol_txrx_update_last_real_peer, + .set_tdls_offchan_enabled = ol_txrx_set_tdls_offchan_enabled, + .set_peer_as_tdls_peer = ol_txrx_set_peer_as_tdls_peer, +#endif /* CONFIG_HL_SUPPORT */ + .peer_detach_force_delete = ol_txrx_peer_detach_force_delete, + .peer_flush_frags = ol_txrx_peer_flush_frags, +}; + +static struct cdp_tx_delay_ops ol_ops_delay = { +#ifdef QCA_COMPUTE_TX_DELAY + .tx_delay = ol_tx_delay, + .tx_delay_hist = ol_tx_delay_hist, + .tx_packet_count = ol_tx_packet_count, + .tx_set_compute_interval = ol_tx_set_compute_interval +#endif /* QCA_COMPUTE_TX_DELAY */ +}; + +static struct cdp_pmf_ops ol_ops_pmf = { + .get_pn_info = ol_txrx_get_pn_info +}; + +static struct cdp_ctrl_ops ol_ops_ctrl = { + .txrx_get_pldev = ol_get_pldev, + .txrx_wdi_event_sub = wdi_event_sub, + .txrx_wdi_event_unsub = wdi_event_unsub, + .txrx_get_pdev_param = ol_get_pdev_param, + .txrx_set_pdev_param = ol_set_pdev_param +}; + +/* WINplatform specific structures */ +static struct cdp_me_ops ol_ops_me = { + /* EMPTY FOR MCL */ +}; + +static struct cdp_mon_ops ol_ops_mon = { + /* EMPTY FOR MCL */ +}; + +static struct cdp_host_stats_ops ol_ops_host_stats = { + /* EMPTY FOR MCL */ +}; + +static struct cdp_wds_ops ol_ops_wds = { + /* EMPTY FOR MCL */ +}; + +static struct cdp_raw_ops ol_ops_raw = { + /* EMPTY FOR MCL */ +}; + +static struct cdp_ops ol_txrx_ops = { + .cmn_drv_ops = &ol_ops_cmn, + .ctrl_ops = &ol_ops_ctrl, + .me_ops = &ol_ops_me, + .mon_ops = &ol_ops_mon, + .host_stats_ops = &ol_ops_host_stats, + .wds_ops = &ol_ops_wds, + .raw_ops = &ol_ops_raw, + .misc_ops = &ol_ops_misc, + .cfg_ops = &ol_ops_cfg, + .flowctl_ops = &ol_ops_flowctl, + .l_flowctl_ops = &ol_ops_l_flowctl, +#ifdef IPA_OFFLOAD + .ipa_ops = &ol_ops_ipa, +#endif +#ifdef RECEIVE_OFFLOAD + .rx_offld_ops = &ol_rx_offld_ops, +#endif + .bus_ops = &ol_ops_bus, +#ifdef WLAN_FEATURE_DSRC + .ocb_ops = &ol_ops_ocb, +#endif + .peer_ops = &ol_ops_peer, + .throttle_ops = &ol_ops_throttle, + .mob_stats_ops = &ol_ops_mob_stats, + .delay_ops = &ol_ops_delay, + .pmf_ops = &ol_ops_pmf, +}; + +ol_txrx_soc_handle ol_txrx_soc_attach(void *scn_handle, + struct ol_if_ops *dp_ol_if_ops) +{ + struct ol_txrx_soc_t *soc; + + soc = qdf_mem_malloc(sizeof(*soc)); + if (!soc) + return NULL; + + soc->psoc = scn_handle; + soc->cdp_soc.ops = &ol_txrx_ops; + soc->cdp_soc.ol_ops = dp_ol_if_ops; + + return ol_txrx_soc_t_to_cdp_soc_t(soc); +} + +bool ol_txrx_get_new_htt_msg_format(struct ol_txrx_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("%s: pdev is NULL", __func__); + return false; + } + return pdev->new_htt_msg_format; +} + +void ol_txrx_set_new_htt_msg_format(uint8_t val) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + qdf_print("%s: pdev is NULL", __func__); + return; + } + pdev->new_htt_msg_format = val; +} + +bool ol_txrx_get_peer_unmap_conf_support(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return false; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + qdf_print("%s: pdev is NULL", __func__); + return false; + } + return pdev->enable_peer_unmap_conf_support; +} + +void ol_txrx_set_peer_unmap_conf_support(bool val) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + qdf_print("%s: pdev is NULL", __func__); + return; + } + pdev->enable_peer_unmap_conf_support = val; +} + +#ifdef WLAN_FEATURE_TSF_PLUS +bool ol_txrx_get_tx_compl_tsf64(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return false; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + qdf_print("%s: pdev is NULL", __func__); + return false; + } + return pdev->enable_tx_compl_tsf64; +} + +void ol_txrx_set_tx_compl_tsf64(bool val) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + pdev->enable_tx_compl_tsf64 = val; +} +#else +bool ol_txrx_get_tx_compl_tsf64(void) +{ + return false; +} + +void ol_txrx_set_tx_compl_tsf64(bool val) +{ +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx.h new file mode 100644 index 0000000000..ff619e6d8b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx.h @@ -0,0 +1,920 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_TXRX__H_ +#define _OL_TXRX__H_ + +#include /* qdf_nbuf_t */ +#include /* ol_txrx_vdev_t, etc. */ +#include "cds_sched.h" +#include +#include +#include +#include + +/* + * Pool of tx descriptors reserved for + * high-priority traffic, such as ARP/EAPOL etc + * only for forwarding path. + */ +#define OL_TX_NON_FWD_RESERVE 100 + +/** + * enum ol_txrx_fc_limit_id - Flow control identifier for + * vdev limits based on band, channel bw and number of spatial streams + * @TXRX_FC_5GH_80M_2x2: Limit for 5GHz, 80MHz BW, 2x2 NSS + * @TXRX_FC_5GH_40M_2x2: + * @TXRX_FC_5GH_20M_2x2: + * @TXRX_FC_5GH_80M_1x1: + * @TXRX_FC_5GH_40M_1x1: + * @TXRX_FC_5GH_20M_1x1: + * @TXRX_FC_2GH_40M_2x2: + * @TXRX_FC_2GH_20M_2x2: + * @TXRX_FC_2GH_40M_1x1: + * @TXRX_FC_2GH_20M_1x1: + */ +enum ol_txrx_fc_limit_id { + TXRX_FC_5GH_80M_2x2, + TXRX_FC_5GH_40M_2x2, + TXRX_FC_5GH_20M_2x2, + TXRX_FC_5GH_80M_1x1, + TXRX_FC_5GH_40M_1x1, + TXRX_FC_5GH_20M_1x1, + TXRX_FC_2GH_40M_2x2, + TXRX_FC_2GH_20M_2x2, + TXRX_FC_2GH_40M_1x1, + TXRX_FC_2GH_20M_1x1, + TXRX_FC_MAX +}; + +#define TXRX_RFS_ENABLE_PEER_ID_UNMAP_COUNT 3 +#define TXRX_RFS_DISABLE_PEER_ID_UNMAP_COUNT 1 + +ol_txrx_peer_handle ol_txrx_peer_get_ref_by_addr(ol_txrx_pdev_handle pdev, + u8 *peer_addr, + enum peer_debug_id_type + dbg_id); + +int ol_txrx_peer_release_ref(ol_txrx_peer_handle peer, + enum peer_debug_id_type dbg_id); + +/** + * ol_txrx_soc_attach() - initialize the soc + * @scn_handle: Opaque SOC handle from control plane + * @dp_ol_if_ops: Offload Operations + * + * Return: SOC handle on success, NULL on failure + */ +ol_txrx_soc_handle ol_txrx_soc_attach(void *scn_handle, + struct ol_if_ops *dp_ol_if_ops); + +/** + * ol_tx_desc_pool_size_hl() - allocate tx descriptor pool size for HL systems + * @ctrl_pdev: the control pdev handle + * + * Return: allocated pool size + */ +u_int16_t +ol_tx_desc_pool_size_hl(struct cdp_cfg *ctrl_pdev); + +#ifndef OL_TX_AVG_FRM_BYTES +#define OL_TX_AVG_FRM_BYTES 1000 +#endif + +#ifndef OL_TX_DESC_POOL_SIZE_MIN_HL +#define OL_TX_DESC_POOL_SIZE_MIN_HL 500 +#endif + +#ifndef OL_TX_DESC_POOL_SIZE_MAX_HL +#define OL_TX_DESC_POOL_SIZE_MAX_HL 5000 +#endif + +#ifndef FW_STATS_DESC_POOL_SIZE +#define FW_STATS_DESC_POOL_SIZE 10 +#endif + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +#define TXRX_HL_TX_FLOW_CTRL_VDEV_LOW_WATER_MARK 400 +#define TXRX_HL_TX_FLOW_CTRL_MGMT_RESERVED 100 +#endif + +#define TXRX_HL_TX_DESC_HI_PRIO_RESERVED 20 +#define TXRX_HL_TX_DESC_QUEUE_RESTART_TH \ + (TXRX_HL_TX_DESC_HI_PRIO_RESERVED + 100) + +struct peer_hang_data { + uint16_t tlv_header; + uint8_t peer_mac_addr[QDF_MAC_ADDR_SIZE]; + uint16_t peer_timeout_bitmask; +} qdf_packed; + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + +void +ol_txrx_hl_tdls_flag_reset(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool flag); +#else + +static inline void +ol_txrx_hl_tdls_flag_reset(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, bool flag) +{ +} +#endif + +#ifdef WDI_EVENT_ENABLE +void *ol_get_pldev(struct cdp_soc_t *soc, uint8_t pdev_id); +#else +static inline +void *ol_get_pldev(struct cdp_soc_t *soc, uint8_t pdev_id) +{ + return NULL; +} +#endif + +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID +ol_txrx_peer_handle +ol_txrx_peer_get_ref_by_local_id(struct cdp_pdev *ppdev, + uint8_t local_peer_id, + enum peer_debug_id_type dbg_id); +#endif /* QCA_SUPPORT_TXRX_LOCAL_PEER_ID */ + +/** + * ol_txrx_get_pdev_from_pdev_id() - Returns pdev object given the pdev id + * @soc: core DP soc context + * @pdev_id: pdev id from pdev object can be retrieved + * + * Return: Pointer to DP pdev object + */ + +static inline struct ol_txrx_pdev_t * +ol_txrx_get_pdev_from_pdev_id(struct ol_txrx_soc_t *soc, + uint8_t pdev_id) +{ + return soc->pdev_list[pdev_id]; +} + +/* + * @nbuf: buffer which contains data to be displayed + * @nbuf_paddr: physical address of the buffer + * @len: defines the size of the data to be displayed + * + * Return: None + */ +void +ol_txrx_dump_pkt(qdf_nbuf_t nbuf, uint32_t nbuf_paddr, int len); + +/** + * ol_txrx_get_vdev_from_vdev_id() - get vdev from vdev_id + * @vdev_id: vdev_id + * + * Return: vdev handle + * NULL if not found. + */ +struct cdp_vdev *ol_txrx_get_vdev_from_vdev_id(uint8_t vdev_id); + +/** + * ol_txrx_get_vdev_from_soc_vdev_id() - get vdev from soc and vdev_id + * @soc: datapath soc handle + * @vdev_id: vdev_id + * + * Return: vdev handle + * NULL if not found. + */ +struct ol_txrx_vdev_t *ol_txrx_get_vdev_from_soc_vdev_id( + struct ol_txrx_soc_t *soc, uint8_t vdev_id); + +/** + * ol_txrx_get_mon_vdev_from_pdev() - get monitor mode vdev from pdev + * @soc: datapath soc handle + * @pdev_id: the physical device id the virtual device belongs to + * + * Return: vdev id + * error if not found. + */ +uint8_t ol_txrx_get_mon_vdev_from_pdev(struct cdp_soc_t *soc, + uint8_t pdev_id); + +/** + * ol_txrx_get_vdev_by_peer_addr() - Get vdev handle by peer mac address + * @ppdev - data path device instance + * @peer_addr - peer mac address + * + * Get virtual interface handle by local peer mac address + * + * Return: Virtual interface instance handle + * NULL in case cannot find + */ +ol_txrx_vdev_handle +ol_txrx_get_vdev_by_peer_addr(struct cdp_pdev *ppdev, + struct qdf_mac_addr peer_addr); + +void *ol_txrx_find_peer_by_addr(struct cdp_pdev *pdev, + uint8_t *peer_addr); + +/** + * @brief specify the peer's authentication state + * @details + * Specify the peer's authentication state (none, connected, authenticated) + * to allow the data SW to determine whether to filter out invalid data frames. + * (In the "connected" state, where security is enabled, but authentication + * has not completed, tx and rx data frames other than EAPOL or WAPI should + * be discarded.) + * This function is only relevant for systems in which the tx and rx filtering + * are done in the host rather than in the target. + * + * @param soc - datapath soc handle + * @param peer_mac - mac address of which peer has changed its state + * @param state - the new state of the peer + * + * Return: QDF Status + */ +QDF_STATUS ol_txrx_peer_state_update(struct cdp_soc_t *soc_hdl, + uint8_t *peer_mac, + enum ol_txrx_peer_state state); + +void htt_pkt_log_init(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, void *scn); +void peer_unmap_timer_handler(void *data); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * ol_txrx_register_tx_flow_control() - register tx flow control callback + * @soc_hdl: soc handle + * @vdev_id: vdev_id + * @flowControl: flow control callback + * @osif_fc_ctx: callback context + * @flow_control_is_pause: is vdev paused by flow control + * + * Return: 0 for success or error code + */ +int ol_txrx_register_tx_flow_control(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + ol_txrx_tx_flow_control_fp flow_control, + void *osif_fc_ctx, + ol_txrx_tx_flow_control_is_pause_fp + flow_control_is_pause); + +/** + * ol_txrx_de_register_tx_flow_control_cb() - deregister tx flow control + * callback + * @soc_hdl: soc handle + * @vdev_id: vdev_id + * + * Return: 0 for success or error code + */ +int ol_txrx_deregister_tx_flow_control_cb(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id); + +bool ol_txrx_get_tx_resource(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct qdf_mac_addr peer_addr, + unsigned int low_watermark, + unsigned int high_watermark_offset); + +/** + * ol_txrx_ll_set_tx_pause_q_depth() - set pause queue depth + * @soc_hdl: soc handle + * @vdev_id: vdev id + * @pause_q_depth: pause queue depth + * + * Return: 0 for success or error code + */ +int ol_txrx_ll_set_tx_pause_q_depth(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, int pause_q_depth); +#endif + +void ol_tx_init_pdev(ol_txrx_pdev_handle pdev); + +#ifdef CONFIG_HL_SUPPORT +void ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev); +void ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev); +void ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); +void ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); +#else +static inline void +ol_txrx_vdev_txqs_init(struct ol_txrx_vdev_t *vdev) {} + +static inline void +ol_txrx_vdev_tx_queue_free(struct ol_txrx_vdev_t *vdev) {} + +static inline void +ol_txrx_peer_txqs_init(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) {} + +static inline void +ol_txrx_peer_tx_queue_free(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) {} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(DEBUG_HL_LOGGING) +void ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev); +void ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev); +void ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev); +void ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev); +#else +static inline void +ol_txrx_pdev_txq_log_init(struct ol_txrx_pdev_t *pdev) {} + +static inline void +ol_txrx_pdev_txq_log_destroy(struct ol_txrx_pdev_t *pdev) {} + +static inline void +ol_txrx_pdev_grp_stats_init(struct ol_txrx_pdev_t *pdev) {} + +static inline void +ol_txrx_pdev_grp_stat_destroy(struct ol_txrx_pdev_t *pdev) {} +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) +/** + * ol_txrx_copy_mac_addr_raw() - copy raw mac addr + * @soc_hdl: datapath soc handle + * @vdev_id: the data virtual device id + * @bss_addr: bss address + * + * Return: None + */ +void ol_txrx_copy_mac_addr_raw(struct cdp_soc_t *soc, uint8_t vdev_id, + uint8_t *bss_addr); + +/** + * ol_txrx_add_last_real_peer() - add last peer + * @soc_hdl: datapath soc handle + * @pdev_id: the data physical device id + * @vdev_id: virtual device id + * + * Return: None + */ +void ol_txrx_add_last_real_peer(struct cdp_soc_t *soc, uint8_t pdev_id, + uint8_t vdev_id); + +/** + * is_vdev_restore_last_peer() - check for vdev last peer + * @soc: datapath soc handle + * vdev_id: vdev id + * @peer_mac: peer mac address + * + * Return: true if last peer is not null + */ +bool is_vdev_restore_last_peer(struct cdp_soc_t *soc, uint8_t vdev_id, + uint8_t *peer_mac); + +/** + * ol_txrx_update_last_real_peer() - check for vdev last peer + * @soc: datapath soc handle + * @pdev_id: the data physical device id + * @vdev_id: vdev_id + * @restore_last_peer: restore last peer flag + * + * Return: None + */ +void ol_txrx_update_last_real_peer(struct cdp_soc_t *soc, uint8_t pdev_id, + uint8_t vdev_id, + bool restore_last_peer); + +/** + * ol_txrx_set_peer_as_tdls_peer() - mark peer as tdls peer + * @soc: pointer to SOC handle + * @vdev_id: virtual interface id + * @peer_mac: peer mac address + * @value: false/true + * + * Return: None + */ +void ol_txrx_set_peer_as_tdls_peer(struct cdp_soc_t *soc, uint8_t vdev_id, + uint8_t *peer_mac, bool val); + +/** + * ol_txrx_set_tdls_offchan_enabled() - set tdls offchan enabled + * @soc: pointer to SOC handle + * @vdev_id: virtual interface id + * @peer_mac: peer mac address + * @value: false/true + * + * Return: None + */ +void ol_txrx_set_tdls_offchan_enabled(struct cdp_soc_t *soc, uint8_t vdev_id, + uint8_t *peer_mac, bool val); +#endif + +#if defined(FEATURE_TSO) && defined(FEATURE_TSO_DEBUG) +void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev); +void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev); +void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev); +void ol_txrx_tso_stats_clear(ol_txrx_pdev_handle pdev); +#else +static inline +void ol_txrx_stats_display_tso(ol_txrx_pdev_handle pdev) +{ + ol_txrx_err("TSO is not supported"); +} + +static inline +void ol_txrx_tso_stats_init(ol_txrx_pdev_handle pdev) {} + +static inline +void ol_txrx_tso_stats_deinit(ol_txrx_pdev_handle pdev) {} + +static inline +void ol_txrx_tso_stats_clear(ol_txrx_pdev_handle pdev) {} +#endif + +struct ol_tx_desc_t * +ol_txrx_mgmt_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info); + +int ol_txrx_mgmt_send_frame(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t tx_mgmt_frm, + struct ol_txrx_msdu_info_t *tx_msdu_info, + uint16_t chanfreq); + +#ifdef CONFIG_HL_SUPPORT +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return ol_tx_desc_pool_size_hl(pdev->ctrl_pdev); +} +#else +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return pdev->num_msdu_desc; +} +#else +static inline +uint32_t ol_tx_get_desc_global_pool_size(struct ol_txrx_pdev_t *pdev) +{ + return ol_cfg_target_tx_credit(pdev->ctrl_pdev); +} +#endif +#endif + +/** + * cdp_soc_t_to_ol_txrx_soc_t() - typecast cdp_soc_t to ol_txrx_soc_t + * @soc: OL soc handle + * + * Return: struct ol_txrx_soc_t pointer + */ +static inline +struct ol_txrx_soc_t *cdp_soc_t_to_ol_txrx_soc_t(ol_txrx_soc_handle soc) +{ + return (struct ol_txrx_soc_t *)soc; +} + +/** + * ol_txrx_soc_t_to_cdp_soc_t() - typecast ol_txrx_soc_t to cdp_soc + * @soc: Opaque soc handle + * + * Return: struct cdp_soc_t pointer + */ +static inline +ol_txrx_soc_handle ol_txrx_soc_t_to_cdp_soc_t(struct ol_txrx_soc_t *soc) +{ + return (struct cdp_soc_t *)soc; +} + +/** + * cdp_pdev_to_ol_txrx_pdev_t() - typecast cdp_pdev to ol_txrx_pdev_t + * @pdev: OL pdev handle + * + * Return: struct ol_txrx_pdev_t pointer + */ +static inline +struct ol_txrx_pdev_t *cdp_pdev_to_ol_txrx_pdev_t(struct cdp_pdev *pdev) +{ + return (struct ol_txrx_pdev_t *)pdev; +} + +/** + * ol_txrx_pdev_t_to_cdp_pdev() - typecast ol_txrx_pdev_t to cdp_pdev + * @pdev: Opaque pdev handle + * + * Return: struct cdp_pdev pointer + */ +static inline +struct cdp_pdev *ol_txrx_pdev_t_to_cdp_pdev(struct ol_txrx_pdev_t *pdev) +{ + return (struct cdp_pdev *)pdev; +} + +/** + * cdp_vdev_to_ol_txrx_vdev_t() - typecast cdp_vdev to ol_txrx_vdev_t + * @vdev: OL vdev handle + * + * Return: struct ol_txrx_vdev_t pointer + */ +static inline +struct ol_txrx_vdev_t *cdp_vdev_to_ol_txrx_vdev_t(struct cdp_vdev *vdev) +{ + return (struct ol_txrx_vdev_t *)vdev; +} + +/** + * ol_txrx_vdev_t_to_cdp_vdev() - typecast ol_txrx_vdev_t to cdp_vdev + * @vdev: Opaque vdev handle + * + * Return: struct cdp_vdev pointer + */ +static inline +struct cdp_vdev *ol_txrx_vdev_t_to_cdp_vdev(struct ol_txrx_vdev_t *vdev) +{ + return (struct cdp_vdev *)vdev; +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc); +uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev); +/** + * ol_txrx_fwd_desc_thresh_check() - check to forward packet to tx path + * @vdev: which virtual device the frames were addressed to + * + * This API is to check whether enough descriptors are available or not + * to forward packet to tx path. If not enough descriptors left, + * start dropping tx-path packets. + * Do not pause netif queues as still a pool of descriptors is reserved + * for high-priority traffic such as EAPOL/ARP etc. + * In case of intra-bss forwarding, it could be possible that tx-path can + * consume all the tx descriptors and pause netif queues. Due to this, + * there would be some left for stack triggered packets such as ARP packets + * which could lead to disconnection of device. To avoid this, reserved + * a pool of descriptors for high-priority packets, i.e., reduce the + * threshold of drop in the intra-bss forwarding path. + * + * Return: true ; forward the packet, i.e., below threshold + * false; not enough descriptors, drop the packet + */ +bool ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *txrx_vdev); + +/** + * ol_tx_desc_thresh_reached() - is tx desc threshold reached + * @soc_hdl: Datapath soc handle + * @vdev_id: id of vdev + * + * Return: true if tx desc available reached threshold or false otherwise + */ +static inline bool ol_tx_desc_thresh_reached(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + dp_err("vdev is NULL"); + return false; + } + + return !(ol_txrx_fwd_desc_thresh_check(vdev)); +} + +#else +/** + * ol_tx_get_total_free_desc() - get total free descriptors + * @pdev: pdev handle + * + * Return: total free descriptors + */ +static inline +uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev) +{ + return pdev->tx_desc.num_free; +} + +static inline +bool ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *txrx_vdev) +{ + return true; +} + +#endif + +#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \ + defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING) +static inline void +ol_txrx_init_txq_group_limit_lend(struct ol_txrx_pdev_t *pdev) +{ + BUILD_BUG_ON(OL_TX_MAX_GROUPS_PER_QUEUE > 1); + BUILD_BUG_ON(OL_TX_MAX_TXQ_GROUPS > 2); + pdev->limit_lend = 0; + pdev->min_reserve = 0; +} +#else +static inline void +ol_txrx_init_txq_group_limit_lend(struct ol_txrx_pdev_t *pdev) +{} +#endif + +int ol_txrx_fw_stats_desc_pool_init(struct ol_txrx_pdev_t *pdev, + uint8_t pool_size); +void ol_txrx_fw_stats_desc_pool_deinit(struct ol_txrx_pdev_t *pdev); +struct ol_txrx_fw_stats_desc_t + *ol_txrx_fw_stats_desc_alloc(struct ol_txrx_pdev_t *pdev); +struct ol_txrx_stats_req_internal + *ol_txrx_fw_stats_desc_get_req(struct ol_txrx_pdev_t *pdev, + uint8_t desc_id); + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +/** + * ol_txrx_register_hl_flow_control() -register hl netdev flow control callback + * @soc_hdl: soc handle + * @pdev_id: datapath pdev identifier + * @flowControl: flow control callback + * + * Return: 0 for success or error code + */ +int ol_txrx_register_hl_flow_control(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + tx_pause_callback flowcontrol); + +/** + * ol_txrx_set_vdev_os_queue_status() - Set OS queue status for a vdev + * @soc_hdl: soc handle + * @vdev_id: vdev id for the vdev under consideration. + * @action: action to be done on queue for vdev + * + * Return: 0 on success, -EINVAL on failure + */ +int ol_txrx_set_vdev_os_queue_status(struct cdp_soc_t *soc_hdl, u8 vdev_id, + enum netif_action_type action); + +/** + * ol_txrx_set_vdev_tx_desc_limit() - Set TX descriptor limits for a vdev + * @soc_hdl: soc handle + * @vdev_id: vdev id for the vdev under consideration. + * @chan_freq: channel frequency on which the vdev has been started. + * + * Return: 0 on success, -EINVAL on failure + */ +int ol_txrx_set_vdev_tx_desc_limit(struct cdp_soc_t *soc_hdl, u8 vdev_id, + u32 chan_freq); +#endif + +/** + * ol_txrx_get_new_htt_msg_format() - check htt h2t msg feature + * @pdev - datapath device instance + * + * Check if h2t message length includes htc header length + * + * return if new htt h2t msg feature enabled + */ +bool ol_txrx_get_new_htt_msg_format(struct ol_txrx_pdev_t *pdev); + +/** + * ol_txrx_set_new_htt_msg_format() - set htt h2t msg feature + * @val - enable or disable new htt h2t msg feature + * + * Set if h2t message length includes htc header length + * + * return NONE + */ +void ol_txrx_set_new_htt_msg_format(uint8_t val); + +/** + * ol_txrx_set_peer_unmap_conf_support() - set peer unmap conf feature + * @val - enable or disable peer unmap conf feature + * + * Set if peer unamp conf feature is supported by both FW and in INI + * + * return NONE + */ +void ol_txrx_set_peer_unmap_conf_support(bool val); + +/** + * ol_txrx_get_peer_unmap_conf_support() - check peer unmap conf feature + * + * Check if peer unmap conf feature is enabled + * + * return true is peer unmap conf feature is enabled else false + */ +bool ol_txrx_get_peer_unmap_conf_support(void); + +/** + * ol_txrx_get_tx_compl_tsf64() - check tx compl tsf64 feature + * + * Check if tx compl tsf64 feature is enabled + * + * return true is tx compl tsf64 feature is enabled else false + */ +bool ol_txrx_get_tx_compl_tsf64(void); + +/** + * ol_txrx_set_tx_compl_tsf64() - set tx compl tsf64 feature + * @val - enable or disable tx compl tsf64 feature + * + * Set if tx compl tsf64 feature is supported FW + * + * return NONE + */ +void ol_txrx_set_tx_compl_tsf64(bool val); + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + +/** + * ol_txrx_vdev_init_tcp_del_ack() - initialize tcp delayed ack structure + * @vdev: vdev handle + * + * Return: none + */ +void ol_txrx_vdev_init_tcp_del_ack(struct ol_txrx_vdev_t *vdev); + +/** + * ol_txrx_vdev_deinit_tcp_del_ack() - deinitialize tcp delayed ack structure + * @vdev: vdev handle + * + * Return: none + */ +void ol_txrx_vdev_deinit_tcp_del_ack(struct ol_txrx_vdev_t *vdev); + +/** + * ol_txrx_vdev_free_tcp_node() - add tcp node in free list + * @vdev: vdev handle + * @node: tcp stream node + * + * Return: none + */ +void ol_txrx_vdev_free_tcp_node(struct ol_txrx_vdev_t *vdev, + struct tcp_stream_node *node); + +/** + * ol_txrx_vdev_alloc_tcp_node() - allocate tcp node + * @vdev: vdev handle + * + * Return: tcp stream node + */ +struct tcp_stream_node * +ol_txrx_vdev_alloc_tcp_node(struct ol_txrx_vdev_t *vdev); + +/** + * ol_tx_pdev_reset_driver_del_ack() - reset driver delayed ack enabled flag + * @ppdev: the data physical device + * + * Return: none + */ +void +ol_tx_pdev_reset_driver_del_ack(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); + +/** + * ol_tx_vdev_set_driver_del_ack_enable() - set driver delayed ack enabled flag + * @soc_hdl: datapath soc handle + * @vdev_id: vdev id + * @rx_packets: number of rx packets + * @time_in_ms: time in ms + * @high_th: high threshold + * @low_th: low threshold + * + * Return: none + */ +void +ol_tx_vdev_set_driver_del_ack_enable(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + unsigned long rx_packets, + uint32_t time_in_ms, + uint32_t high_th, + uint32_t low_th); + +/** + * ol_tx_hl_send_all_tcp_ack() - send all queued tcp ack packets + * @vdev: vdev handle + * + * Return: none + */ +void ol_tx_hl_send_all_tcp_ack(struct ol_txrx_vdev_t *vdev); + +/** + * tcp_del_ack_tasklet() - tasklet function to send ack packets + * @data: vdev handle + * + * Return: none + */ +void tcp_del_ack_tasklet(void *data); + +/** + * ol_tx_get_stream_id() - get stream_id from packet info + * @info: packet info + * + * Return: stream_id + */ +uint16_t ol_tx_get_stream_id(struct packet_info *info); + +/** + * ol_tx_get_packet_info() - update packet info for passed msdu + * @msdu: packet + * @info: packet info + * + * Return: none + */ +void ol_tx_get_packet_info(qdf_nbuf_t msdu, struct packet_info *info); + +/** + * ol_tx_hl_find_and_send_tcp_stream() - find and send tcp stream for passed + * stream info + * @vdev: vdev handle + * @info: packet info + * + * Return: none + */ +void ol_tx_hl_find_and_send_tcp_stream(struct ol_txrx_vdev_t *vdev, + struct packet_info *info); + +/** + * ol_tx_hl_find_and_replace_tcp_ack() - find and replace tcp ack packet for + * passed packet info + * @vdev: vdev handle + * @msdu: packet + * @info: packet info + * + * Return: none + */ +void ol_tx_hl_find_and_replace_tcp_ack(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct packet_info *info); + +/** + * ol_tx_hl_vdev_tcp_del_ack_timer() - delayed ack timer function + * @timer: timer handle + * + * Return: enum + */ +enum qdf_hrtimer_restart_status +ol_tx_hl_vdev_tcp_del_ack_timer(qdf_hrtimer_data_t *timer); + +/** + * ol_tx_hl_del_ack_queue_flush_all() - drop all queued packets + * @vdev: vdev handle + * + * Return: none + */ +void ol_tx_hl_del_ack_queue_flush_all(struct ol_txrx_vdev_t *vdev); + +#else + +static inline +void ol_txrx_vdev_init_tcp_del_ack(struct ol_txrx_vdev_t *vdev) +{ +} + +static inline +void ol_txrx_vdev_deinit_tcp_del_ack(struct ol_txrx_vdev_t *vdev) +{ +} + +static inline +void ol_tx_pdev_reset_driver_del_ack(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ +} + +static inline +void ol_tx_vdev_set_driver_del_ack_enable(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + unsigned long rx_packets, + uint32_t time_in_ms, + uint32_t high_th, + uint32_t low_th) +{ +} + +#endif + +#ifdef WLAN_SUPPORT_TXRX_HL_BUNDLE +void ol_tx_vdev_set_bundle_require(uint8_t vdev_id, unsigned long tx_bytes, + uint32_t time_in_ms, uint32_t high_th, + uint32_t low_th); + +void ol_tx_pdev_reset_bundle_require(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); + +#else + +static inline +void ol_tx_vdev_set_bundle_require(uint8_t vdev_id, unsigned long tx_bytes, + uint32_t time_in_ms, uint32_t high_th, + uint32_t low_th) +{ +} + +static inline +void ol_tx_pdev_reset_bundle_require(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ +} +#endif + +#endif /* _OL_TXRX__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c new file mode 100644 index 0000000000..2fdd09e63c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_encap.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2012-2017, 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_encap.c + * @brief Provide functions to encap/decap on txrx frames. + * @details + * This file contains functions for data frame encap/decap: + * ol_tx_encap: encap outgoing data frames. + * ol_rx_decap: decap incoming data frames. + */ +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + +#include /* qdf_nbuf_t, etc. */ +#include /* ieee80211_frame */ +#include /* TXRX_ASSERT1 */ +#include /* struct ol_rx_decap_info_t */ + +static inline A_STATUS +ol_tx_copy_native_wifi_header(qdf_nbuf_t msdu, + uint8_t *hdsize, uint8_t *localbuf) +{ + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(msdu); + if ((wh->i_fc[1] & + IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) { + *hdsize = sizeof(struct ieee80211_frame_addr4); + } else { + *hdsize = sizeof(struct ieee80211_frame); + } + if (qdf_nbuf_len(msdu) < *hdsize) + return A_ERROR; + + qdf_mem_copy(localbuf, wh, *hdsize); + return A_OK; +} + +static inline A_STATUS +ol_tx_encap_from_native_wifi(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, + struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4)]; + struct ieee80211_frame *wh; + uint8_t hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + struct ol_txrx_peer_t *peer; + + if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) + return A_OK; + + peer = tx_msdu_info->peer; + /* + * for unicast,the peer should not be NULL. + * for multicast, the peer is AP. + */ + if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) { + if (A_OK != + ol_tx_copy_native_wifi_header(msdu, &hdsize, localbuf)) + return A_ERROR; + wh = (struct ieee80211_frame *)localbuf; + + /*add qos cntl */ + qos_cntl = (struct ieee80211_qoscntl *)(localbuf + hdsize); + qos_cntl->i_qos[0] = + tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID; + +#ifdef NEVERDEFINED + if (wmmParam[ac].wmep_noackPolicy) + qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; +#endif + + qos_cntl->i_qos[1] = 0; + wh->i_fc[0] |= QDF_IEEE80211_FC0_SUBTYPE_QOS; + /* count for qos field */ + new_hdsize = + hdsize + sizeof(struct ieee80211_qosframe) - + sizeof(struct ieee80211_frame); + + /*add ht control field if needed */ + + /* copy new hd to bd */ + qdf_mem_copy((void *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + new_hdsize), localbuf, + new_hdsize); + qdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = new_hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + } + /* Set Protected Frame bit in MAC header */ + if (vdev->pdev->sw_pf_proc_enable + && tx_msdu_info->htt.action.do_encrypt) { + if (tx_desc->orig_l2_hdr_bytes) { + wh = (struct ieee80211_frame *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + tx_msdu_info->htt.info. + l3_hdr_offset); + } else { + if (A_OK != + ol_tx_copy_native_wifi_header(msdu, &hdsize, + localbuf)) + return A_ERROR; + wh = (struct ieee80211_frame *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + hdsize); + qdf_mem_copy((void *)wh, localbuf, hdsize); + qdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + } + wh->i_fc[1] |= IEEE80211_FC1_WEP; + } + return A_OK; +} + +static inline A_STATUS +ol_tx_encap_from_8023(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *tx_msdu_info) +{ + uint8_t localbuf[sizeof(struct ieee80211_qosframe_htc_addr4) + + sizeof(struct llc_snap_hdr_t)]; + struct llc_snap_hdr_t *llc_hdr; + struct ethernet_hdr_t *eth_hdr; + struct ieee80211_frame *wh; + uint8_t hdsize, new_l2_hdsize, new_hdsize; + struct ieee80211_qoscntl *qos_cntl; + const uint8_t ethernet_II_llc_snap_header_prefix[] = { + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; + struct ol_txrx_peer_t *peer; + uint16_t ether_type; + + if (tx_msdu_info->htt.info.frame_type != htt_frm_type_data) + return A_OK; + + /* + * for unicast,the peer should not be NULL. + * for multicast, the peer is AP. + */ + peer = tx_msdu_info->peer; + + eth_hdr = (struct ethernet_hdr_t *)qdf_nbuf_data(msdu); + hdsize = sizeof(struct ethernet_hdr_t); + wh = (struct ieee80211_frame *)localbuf; + wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; + *(uint16_t *) wh->i_dur = 0; + new_hdsize = 0; + + switch (vdev->opmode) { + case wlan_op_mode_ap: + /* DA , BSSID , SA */ + qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, &vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_ibss: + /* DA, SA, BSSID */ + qdf_mem_copy(wh->i_addr1, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + /* need to check the bssid behaviour for IBSS vdev */ + qdf_mem_copy(wh->i_addr3, &vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_sta: + /* BSSID, SA , DA */ + qdf_mem_copy(wh->i_addr1, &peer->mac_addr.raw, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, eth_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, eth_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; + new_hdsize = sizeof(struct ieee80211_frame); + break; + case wlan_op_mode_monitor: + default: + return A_ERROR; + } + /*add qos cntl */ + if (tx_msdu_info->htt.info.is_unicast && peer->qos_capable) { + qos_cntl = (struct ieee80211_qoscntl *)(localbuf + new_hdsize); + qos_cntl->i_qos[0] = + tx_msdu_info->htt.info.ext_tid & IEEE80211_QOS_TID; + wh->i_fc[0] |= QDF_IEEE80211_FC0_SUBTYPE_QOS; +#ifdef NEVERDEFINED + if (wmmParam[ac].wmep_noackPolicy) + qos_cntl->i_qos[0] |= 1 << IEEE80211_QOS_ACKPOLICY_S; +#endif + qos_cntl->i_qos[1] = 0; + new_hdsize += sizeof(struct ieee80211_qoscntl); + + /*add ht control field if needed */ + } + /* Set Protected Frame bit in MAC header */ + if (vdev->pdev->sw_pf_proc_enable + && tx_msdu_info->htt.action.do_encrypt) { + wh->i_fc[1] |= IEEE80211_FC1_WEP; + } + new_l2_hdsize = new_hdsize; + /* add llc snap if needed */ + if (vdev->pdev->sw_tx_llc_proc_enable) { + llc_hdr = (struct llc_snap_hdr_t *)(localbuf + new_hdsize); + ether_type = + (eth_hdr->ethertype[0] << 8) | (eth_hdr->ethertype[1]); + if (ether_type >= ETH_P_802_3_MIN) { + qdf_mem_copy(llc_hdr, + ethernet_II_llc_snap_header_prefix, + sizeof + (ethernet_II_llc_snap_header_prefix)); + if (ether_type == ETHERTYPE_AARP + || ether_type == ETHERTYPE_IPX) { + llc_hdr->org_code[2] = BTEP_SNAP_ORGCODE_2; + /* 0xf8; bridge tunnel header */ + } + llc_hdr->ethertype[0] = eth_hdr->ethertype[0]; + llc_hdr->ethertype[1] = eth_hdr->ethertype[1]; + new_hdsize += sizeof(struct llc_snap_hdr_t); + } else { + /* + * llc ready, and it's in payload pdu, + * do we need to move to BD pdu? + */ + } + } + qdf_mem_copy((void *) + htt_tx_desc_mpdu_header(tx_desc->htt_tx_desc, + new_l2_hdsize), localbuf, + new_hdsize); + qdf_nbuf_pull_head(msdu, hdsize); + tx_msdu_info->htt.info.l3_hdr_offset = new_l2_hdsize; + tx_desc->orig_l2_hdr_bytes = hdsize; + return A_OK; +} + +A_STATUS +ol_tx_encap(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + return ol_tx_encap_from_native_wifi(vdev, tx_desc, msdu, + msdu_info); + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + return ol_tx_encap_from_8023(vdev, tx_desc, msdu, msdu_info); + } + + /* todo for other types */ + return A_ERROR; +} + +static inline void +ol_rx_decap_to_native_wifi(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_rx_decap_info_t *info, + struct ethernet_hdr_t *ethr_hdr) +{ + struct ieee80211_frame_addr4 *wh; + uint16_t hdsize; + + /* + * we need to remove Qos control field and HT control. + * MSFT: http://msdn.microsoft.com/en-us/library/windows/ + * hardware/ff552608(v=vs.85).aspx + */ + wh = (struct ieee80211_frame_addr4 *)info->hdr; + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS) + hdsize = sizeof(struct ieee80211_frame_addr4); + else + hdsize = sizeof(struct ieee80211_frame); + + wh = (struct ieee80211_frame_addr4 *)qdf_nbuf_push_head(msdu, hdsize); + TXRX_ASSERT2(wh); + TXRX_ASSERT2(hdsize <= info->hdr_len); + qdf_mem_copy((uint8_t *) wh, info->hdr, hdsize); + + /* amsdu subfrm handling if ethr_hdr is not NULL */ + if (ethr_hdr) { + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(wh->i_addr2, ethr_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(wh->i_addr1, ethr_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr3, ethr_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(wh->i_addr3, ethr_hdr->dest_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(wh->i_addr4, ethr_hdr->src_addr, + QDF_MAC_ADDR_SIZE); + break; + } + } + if (IEEE80211_QOS_HAS_SEQ(wh)) { + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + wh->i_fc[1] &= ~IEEE80211_FC1_ORDER; + wh->i_fc[0] &= ~QDF_IEEE80211_FC0_SUBTYPE_QOS; + } +} + +static inline void +ol_rx_decap_to_8023(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, + struct ol_rx_decap_info_t *info, + struct ethernet_hdr_t *ethr_hdr) +{ + struct llc_snap_hdr_t *llc_hdr; + uint16_t ether_type; + uint16_t l2_hdr_space; + struct ieee80211_frame_addr4 *wh; + uint8_t local_buf[ETHERNET_HDR_LEN]; + uint8_t *buf; + + /* + * populate Ethernet header, + * if ethr_hdr is null, rx frame is 802.11 format(HW ft disabled) + * if ethr_hdr is not null, rx frame is "subfrm of amsdu". + */ + buf = (uint8_t *) qdf_nbuf_data(msdu); + llc_hdr = (struct llc_snap_hdr_t *)buf; + ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + /* do llc remove if needed */ + l2_hdr_space = 0; + if (IS_SNAP(llc_hdr)) { + if (IS_BTEP(llc_hdr)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } else if (IS_RFC1042(llc_hdr)) { + if (!(ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } + } + } + if (l2_hdr_space > ETHERNET_HDR_LEN) + buf = qdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN); + else if (l2_hdr_space < ETHERNET_HDR_LEN) + buf = qdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space); + + /* normal msdu(non-subfrm of A-MSDU) if ethr_hdr is null */ + if (!ethr_hdr) { + /* + * mpdu hdr should be present in info, + * re-create ethr_hdr based on mpdu hdr + */ + TXRX_ASSERT2(info->hdr_len != 0); + wh = (struct ieee80211_frame_addr4 *)info->hdr; + ethr_hdr = (struct ethernet_hdr_t *)local_buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + QDF_MAC_ADDR_SIZE); + break; + } + } + if (!llc_hdr) { + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } else { + uint32_t pktlen = + qdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype); + TXRX_ASSERT2(pktlen <= ETHERNET_MTU); + ether_type = (uint16_t) pktlen; + ether_type = qdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t); + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } + qdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN); +} + +static inline A_STATUS +ol_rx_decap_subfrm_amsdu(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + uint8_t *subfrm_hdr; + uint8_t localbuf[ETHERNET_HDR_LEN]; + struct ethernet_hdr_t *ether_hdr = (struct ethernet_hdr_t *)localbuf; + + subfrm_hdr = (uint8_t *) qdf_nbuf_data(msdu); + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* decap to native wifi */ + qdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN); + qdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN); + ol_rx_decap_to_native_wifi(vdev, msdu, info, ether_hdr); + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (pdev->sw_rx_llc_proc_enable) { + /* remove llc snap hdr if it's necessary according to + * 802.11 table P-3 + */ + qdf_mem_copy(ether_hdr, subfrm_hdr, ETHERNET_HDR_LEN); + qdf_nbuf_pull_head(msdu, ETHERNET_HDR_LEN); + ol_rx_decap_to_8023(vdev, msdu, info, ether_hdr); + } else { + /* subfrm of A-MSDU is already in 802.3 format. + * if target HW or FW has done LLC rmv process, + * we do nothing here. + */ + } + } else { + /* todo for othertype */ + } + return A_OK; + +} + +static inline A_STATUS +ol_rx_decap_msdu(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + struct ol_txrx_pdev_t *pdev = vdev->pdev; + struct ieee80211_frame *wh; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(msdu); + + if (pdev->frame_format == wlan_frm_fmt_native_wifi) { + /* Decap to native wifi because according to MSFT( + * MSFT: http://msdn.microsoft.com/en-us/library/windows/ + * hardware/ff552608(v=vs.85).aspx), + * we need to remove Qos and HTC field before indicate to OS. + */ + if (IEEE80211_QOS_HAS_SEQ(wh)) { + info->hdr_len = ol_txrx_ieee80211_hdrsize(wh); + TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr)); + qdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */ + wh, info->hdr_len); + qdf_nbuf_pull_head(msdu, info->hdr_len); + ol_rx_decap_to_native_wifi(vdev, msdu, info, NULL); + /* 802.11 hdr^ eth_hdr^ */ + } + } else if (pdev->frame_format == wlan_frm_fmt_802_3) { + if (pdev->sw_rx_llc_proc_enable) { + info->hdr_len = ol_txrx_ieee80211_hdrsize(wh); + TXRX_ASSERT2(info->hdr_len <= sizeof(info->hdr)); + qdf_mem_copy(info->hdr, /* use info->hdr as temp buf. */ + wh, info->hdr_len); + qdf_nbuf_pull_head(msdu, info->hdr_len); + /* remove llc snap hdr if it's necessary according to + * 802.11 table P-3 + */ + ol_rx_decap_to_8023(vdev, msdu, info, /* 802.11 hdr */ + NULL); /* ethernet hdr */ + } else { + /* Subfrm of A-MSDU is already in 802.3 format. + * And if target HW or FW has done LLC rmv process ( + * sw_rx_lc_proc_enable == 0), we do nothing here. + */ + } + } else { + /* todo for othertype */ + } + return A_OK; + +} + +A_STATUS +ol_rx_decap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + A_STATUS status; + uint8_t *mpdu_hdr; + + if (!info->is_subfrm) { + if (info->is_msdu_cmpl_mpdu && !info->is_first_subfrm) { + /* It's normal MSDU. */ + } else { + /* + * It's a first subfrm of A-MSDU and + * may also be the last subfrm of A-MSDU + */ + info->is_subfrm = 1; + info->hdr_len = 0; + if (vdev->pdev->sw_subfrm_hdr_recovery_enable) { + /* we save the first subfrm mpdu hdr for + * subsequent subfrm 802.11 header recovery + * in certain chip(such as Riva). + */ + mpdu_hdr = qdf_nbuf_data(msdu); + info->hdr_len = + ol_txrx_ieee80211_hdrsize(mpdu_hdr); + TXRX_ASSERT2(info->hdr_len <= + sizeof(info->hdr)); + qdf_mem_copy(info->hdr, mpdu_hdr, + info->hdr_len); + qdf_nbuf_pull_head(msdu, info->hdr_len); + } + } + } + + if (info->is_subfrm && vdev->pdev->sw_subfrm_hdr_recovery_enable) { + /* + * This case is enabled for some HWs (such as Riva). The HW + * de-aggregate doesn't have capability to generate 802.11 + * header for non-first subframe of A-MSDU. That means sw needs + * to cache the first subfrm mpdu header to generate the + * subsequent subfrm's 802.11 header. + */ + TXRX_ASSERT2(info->hdr_len != 0); + status = ol_rx_decap_subfrm_amsdu(vdev, msdu, info); + } else { + status = ol_rx_decap_msdu(vdev, msdu, info); + } + + if (info->is_msdu_cmpl_mpdu) + info->is_subfrm = info->is_first_subfrm = info->hdr_len = 0; + + return status; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h new file mode 100644 index 0000000000..360717e7a1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_encap.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2012, 2014-2016, 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_encap.h + * @brief definitions for txrx encap/decap function and struct + */ +#ifndef _OL_TXRX_ENCAP__H_ +#define _OL_TXRX_ENCAP__H_ + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + +#include /* qdf_nbuf_t */ +#include /* ieee80211_qosframe_htc_addr4 */ +#include /* ol_txrx_vdev_t, etc. */ + +/** + * @brief Encap outgoing frm from OS dependent format to Target + * acceptable frm format + * @details + * For native wifi format, the function will add Qos control field + * based on peer's QOS capbabilities . + * For 802.3 format, the function will transform to 802.11 format + * with or without QOS control field based on peer's QOS capabilities. + * @param vdev - handle to vdev object + * @param tx_desc - tx desc struct,some fields will be updated. + * @param msdu - qdf_nbuf_t + * @param msdu_info - information from tx classification. + * @return + * A_OK: encap operation successful + * other: operation failed,the msdu need be dropped. + */ +A_STATUS +ol_tx_encap(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info); + +struct ol_rx_decap_info_t { + uint8_t hdr[sizeof(struct ieee80211_qosframe_htc_addr4)]; + int hdr_len; + uint8_t is_subfrm:1, is_first_subfrm:1, is_msdu_cmpl_mpdu:1; +}; + +/** + * @brief decap incoming frm from Target to Host OS + * acceptable frm format + * @details + * For native wifi format, the function will remove Qos control field + * and HT control field if any. + * For 802.3 format, the function will will do llc snap header process + * if Target haven't done that. + * @param vdev - handle to vdev object + * @param peer - the peer object. + * @param msdu - qdf_nbuf_t + * @param info - ol_rx_decap_info_t: context info for decap + * @return + * A_OK: decap operation successful + * other: operation failed,the msdu need be dropped. + */ +A_STATUS +ol_rx_decap(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info); + +static inline A_STATUS +OL_TX_ENCAP(struct ol_txrx_vdev_t *vdev, + struct ol_tx_desc_t *tx_desc, + qdf_nbuf_t msdu, struct ol_txrx_msdu_info_t *msdu_info) +{ + if (vdev->pdev->sw_tx_encap) + return ol_tx_encap(vdev, tx_desc, msdu, msdu_info); + return A_OK; +} + +static inline A_STATUS +OL_RX_DECAP(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + qdf_nbuf_t msdu, struct ol_rx_decap_info_t *info) +{ + if (vdev->pdev->sw_rx_decap) + return ol_rx_decap(vdev, peer, msdu, info); + return A_OK; +} + +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) \ + do { \ + if (__tx_desc->orig_l2_hdr_bytes != 0) \ + qdf_nbuf_push_head(__msdu, \ + __tx_desc->orig_l2_hdr_bytes); \ + } while (0) +#else +#define OL_TX_ENCAP(vdev, tx_desc, msdu, msdu_info) A_OK +#define OL_RX_DECAP(vdev, peer, msdu, info) A_OK +#define OL_TX_RESTORE_HDR(__tx_desc, __msdu) +#endif +#endif /* _OL_TXRX_ENCAP__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_event.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_event.c new file mode 100644 index 0000000000..38265dd84a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_event.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ol_txrx_types.h" +#include "ol_txrx.h" + +static inline wdi_event_subscribe *wdi_event_next_sub(wdi_event_subscribe * + wdi_sub) +{ + if (!wdi_sub) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid subscriber in %s\n", __func__); + return NULL; + } + return wdi_sub->priv.next; +} + +static inline void +wdi_event_del_subs(wdi_event_subscribe *wdi_sub, int event_index) +{ + wdi_event_notify deallocate_sub; + + while (wdi_sub) { + wdi_event_subscribe *next = wdi_event_next_sub(wdi_sub); + /* + * Context is NULL for static allocation of subs + * In dynamic allocation case notify the user + */ + if (wdi_sub->context) { + deallocate_sub = wdi_sub->context; + deallocate_sub(WDI_EVENT_SUB_DEALLOCATE, + WDI_EVENT_BASE + event_index); + } + wdi_sub = next; + } + /* qdf_mem_free(wdi_sub); */ +} + +static inline void +wdi_event_iter_sub(struct ol_txrx_pdev_t *pdev, + uint32_t event_index, + wdi_event_subscribe *wdi_sub, void *data) +{ + enum WDI_EVENT event = event_index + WDI_EVENT_BASE; + + if (wdi_sub) { + do { + wdi_sub->callback(pdev, event, data, 0, 0); + } while ((wdi_sub = wdi_event_next_sub(wdi_sub))); + } +} + +void +wdi_event_handler(enum WDI_EVENT event, + uint8_t pdev_id, void *data) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle txrx_pdev; + + /* + * Input validation + */ + if (!event) { + ol_txrx_err("Invalid WDI event"); + return; + } + if (!soc) + return; + + txrx_pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + if (!txrx_pdev) { + ol_txrx_err("Invalid pdev"); + return; + } + /* + * There can be NULL data, so no validation for the data + * Subscribers must do the sanity based on the requirements + */ + event_index = event - WDI_EVENT_BASE; + + wdi_sub = txrx_pdev->wdi_event_list[event_index]; + + /* Find the subscriber */ + wdi_event_iter_sub(txrx_pdev, event_index, wdi_sub, data); +} + +int +wdi_event_sub(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + wdi_event_subscribe *pevent_cb_sub, uint32_t event) +{ + uint32_t event_index; + wdi_event_subscribe *wdi_sub; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle txrx_pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + wdi_event_subscribe *event_cb_sub = pevent_cb_sub; + + /* Input validation */ + if (!txrx_pdev || !txrx_pdev->wdi_event_list) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid txrx_pdev or wdi_event_list in %s", + __func__); + return -EINVAL; + } + if (!event_cb_sub) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid callback in %s", __func__); + return -EINVAL; + } + if ((!event) || (event >= WDI_EVENT_LAST) || (event < WDI_EVENT_BASE)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid event in %s", __func__); + return -EINVAL; + } + /* Input validation */ + event_index = event - WDI_EVENT_BASE; + + wdi_sub = txrx_pdev->wdi_event_list[event_index]; + /* + * Check if it is the first subscriber of the event + */ + if (!wdi_sub) { + wdi_sub = event_cb_sub; + wdi_sub->priv.next = NULL; + wdi_sub->priv.prev = NULL; + txrx_pdev->wdi_event_list[event_index] = wdi_sub; + return 0; + } + event_cb_sub->priv.next = wdi_sub; + event_cb_sub->priv.prev = NULL; + wdi_sub->priv.prev = event_cb_sub; + txrx_pdev->wdi_event_list[event_index] = event_cb_sub; + + return 0; +} + +int +wdi_event_unsub(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + wdi_event_subscribe *pevent_cb_sub, uint32_t event) +{ + uint32_t event_index = event - WDI_EVENT_BASE; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle txrx_pdev = ol_txrx_get_pdev_from_pdev_id(soc, + pdev_id); + + wdi_event_subscribe *event_cb_sub = pevent_cb_sub; + + /* Input validation */ + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid txrx_pdev in %s", __func__); + return -EINVAL; + } + + /* Input validation */ + if (!event_cb_sub) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid callback in %s", __func__); + return -EINVAL; + } + if (!event_cb_sub->priv.prev) { + txrx_pdev->wdi_event_list[event_index] = + event_cb_sub->priv.next; + } else { + event_cb_sub->priv.prev->priv.next = event_cb_sub->priv.next; + } + if (event_cb_sub->priv.next) + event_cb_sub->priv.next->priv.prev = event_cb_sub->priv.prev; + + /* qdf_mem_free(event_cb_sub); */ + + return 0; +} + +A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev) +{ + /* Input validation */ + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid device in %s\nWDI event attach failed", + __func__); + return A_ERROR; + } + /* Separate subscriber list for each event */ + txrx_pdev->wdi_event_list = (wdi_event_subscribe **) + qdf_mem_malloc( + sizeof(wdi_event_subscribe *) * + WDI_NUM_EVENTS); + if (!txrx_pdev->wdi_event_list) + return A_NO_MEMORY; + + return A_OK; +} + +A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev) +{ + int i; + wdi_event_subscribe *wdi_sub; + + if (!txrx_pdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Invalid device in %s\nWDI detach failed", + __func__); + return A_ERROR; + } + if (!txrx_pdev->wdi_event_list) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: wdi_event_list is NULL", __func__); + return A_ERROR; + } + + for (i = 0; i < WDI_NUM_EVENTS; i++) { + wdi_sub = txrx_pdev->wdi_event_list[i]; + if (wdi_sub) { + /* Delete all the subscribers */ + wdi_event_del_subs(wdi_sub, i); + } + } + /* txrx_pdev->wdi_event_list would be non-null */ + qdf_mem_free(txrx_pdev->wdi_event_list); + txrx_pdev->wdi_event_list = NULL; + return A_OK; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c new file mode 100644 index 0000000000..3a5d965be4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_flow_control.c @@ -0,0 +1,1445 @@ +/* + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include /* ol_txrx_get_vdev_from_vdev_id */ + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_enqueue */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include +#include +#define INVALID_FLOW_ID 0xFF +#define MAX_INVALID_BIN 3 + +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL +#define TX_FLOW_MGMT_POOL_ID 0xEF +#define TX_FLOW_MGMT_POOL_SIZE 32 + +/** + * ol_tx_register_global_mgmt_pool() - register global pool for mgmt packets + * @pdev: pdev handler + * + * Return: none + */ +static void +ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + pdev->mgmt_pool = ol_tx_create_flow_pool(TX_FLOW_MGMT_POOL_ID, + TX_FLOW_MGMT_POOL_SIZE); + if (!pdev->mgmt_pool) + ol_txrx_err("Management pool creation failed"); +} + +/** + * ol_tx_deregister_global_mgmt_pool() - Deregister global pool for mgmt packets + * @pdev: pdev handler + * + * Return: none + */ +static void +ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ + ol_tx_dec_pool_ref(pdev->mgmt_pool, false); +} +#else +static inline void +ol_tx_register_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ +} +static inline void +ol_tx_deregister_global_mgmt_pool(struct ol_txrx_pdev_t *pdev) +{ +} +#endif + +bool ol_txrx_fwd_desc_thresh_check(struct ol_txrx_vdev_t *txrx_vdev) +{ + struct ol_tx_flow_pool_t *pool; + bool enough_desc_flag; + + if (!txrx_vdev) + return false; + + pool = txrx_vdev->pool; + + if (!pool) + return false; + + qdf_spin_lock_bh(&pool->flow_pool_lock); + enough_desc_flag = (pool->avail_desc < (pool->stop_th + + OL_TX_NON_FWD_RESERVE)) + ? false : true; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + return enough_desc_flag; +} + +/** + * ol_tx_set_desc_global_pool_size() - set global pool size + * @num_msdu_desc: total number of descriptors + * + * Return: none + */ +void ol_tx_set_desc_global_pool_size(uint32_t num_msdu_desc) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + qdf_print("pdev is NULL"); + return; + } + pdev->num_msdu_desc = num_msdu_desc; + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + pdev->num_msdu_desc += TX_FLOW_MGMT_POOL_SIZE; + ol_txrx_info_high("Global pool size: %d", pdev->num_msdu_desc); +} + +/** + * ol_tx_get_total_free_desc() - get total free descriptors + * @pdev: pdev handle + * + * Return: total free descriptors + */ +uint32_t ol_tx_get_total_free_desc(struct ol_txrx_pdev_t *pdev) +{ + struct ol_tx_flow_pool_t *pool = NULL; + uint32_t free_desc; + + free_desc = pdev->tx_desc.num_free; + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&pool->flow_pool_lock); + free_desc += pool->avail_desc; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return free_desc; +} + +/** + * ol_tx_register_flow_control() - Register fw based tx flow control + * @pdev: pdev handle + * + * Return: none + */ +void ol_tx_register_flow_control(struct ol_txrx_pdev_t *pdev) +{ + qdf_spinlock_create(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INIT(&pdev->tx_desc.flow_pool_list); + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + ol_tx_register_global_mgmt_pool(pdev); +} + +/** + * ol_tx_deregister_flow_control() - Deregister fw based tx flow control + * @pdev: pdev handle + * + * Return: none + */ +void ol_tx_deregister_flow_control(struct ol_txrx_pdev_t *pdev) +{ + int i = 0; + struct ol_tx_flow_pool_t *pool = NULL; + struct cdp_soc_t *soc; + + if (!ol_tx_get_is_mgmt_over_wmi_enabled()) + ol_tx_deregister_global_mgmt_pool(pdev); + + soc = cds_get_context(QDF_MODULE_ID_SOC); + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + while (!TAILQ_EMPTY(&pdev->tx_desc.flow_pool_list)) { + pool = TAILQ_FIRST(&pdev->tx_desc.flow_pool_list); + if (!pool) + break; + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + ol_txrx_info("flow pool list is not empty %d!!!", i++); + + if (i == 1) + ol_tx_dump_flow_pool_info(soc); + + ol_tx_dec_pool_ref(pool, true); + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + qdf_spinlock_destroy(&pdev->tx_desc.flow_pool_list_lock); +} + +/** + * ol_tx_delete_flow_pool() - delete flow pool + * @pool: flow pool pointer + * @force: free pool forcefully + * + * Delete flow_pool if all tx descriptors are available. + * Otherwise put it in FLOW_POOL_INVALID state. + * If force is set then pull all available descriptors to + * global pool. + * + * Return: 0 for success or error + */ +static int ol_tx_delete_flow_pool(struct ol_tx_flow_pool_t *pool, bool force) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + uint16_t i, size; + union ol_tx_desc_list_elem_t *temp_list = NULL; + struct ol_tx_desc_t *tx_desc = NULL; + + if (!pool) { + ol_txrx_err("pool is NULL"); + QDF_ASSERT(0); + return -ENOMEM; + } + + if (qdf_unlikely(!soc)) { + QDF_ASSERT(0); + return -ENOMEM; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + QDF_ASSERT(0); + return -ENOMEM; + } + + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc == pool->flow_pool_size || force == true) + pool->status = FLOW_POOL_INACTIVE; + else + pool->status = FLOW_POOL_INVALID; + + /* Take all free descriptors and put it in temp_list */ + temp_list = pool->freelist; + size = pool->avail_desc; + pool->freelist = NULL; + pool->avail_desc = 0; + + if (pool->status == FLOW_POOL_INACTIVE) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + /* Free flow_pool */ + qdf_spinlock_destroy(&pool->flow_pool_lock); + qdf_mem_free(pool); + } else { /* FLOW_POOL_INVALID case*/ + pool->flow_pool_size -= size; + pool->flow_pool_id = INVALID_FLOW_ID; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_tx_inc_pool_ref(pool); + + pdev->tx_desc.num_invalid_bin++; + ol_txrx_info("invalid pool created %d", + pdev->tx_desc.num_invalid_bin); + if (pdev->tx_desc.num_invalid_bin > MAX_INVALID_BIN) + ASSERT(0); + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + + /* put free descriptors to global pool */ + qdf_spin_lock_bh(&pdev->tx_mutex); + for (i = 0; i < size; i++) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + + ol_tx_put_desc_global_pool(pdev, tx_desc); + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + ol_tx_distribute_descs_to_deficient_pools_from_global_pool(); + + return 0; +} + +QDF_STATUS ol_tx_inc_pool_ref(struct ol_tx_flow_pool_t *pool) +{ + if (!pool) { + ol_txrx_err("flow pool is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&pool->flow_pool_lock); + qdf_atomic_inc(&pool->ref_cnt); + qdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_txrx_dbg("pool %pK, ref_cnt %x", + pool, qdf_atomic_read(&pool->ref_cnt)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_tx_dec_pool_ref(struct ol_tx_flow_pool_t *pool, bool force) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (!pool) { + ol_txrx_err("flow pool is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (qdf_unlikely(!soc)) { + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (qdf_atomic_dec_and_test(&pool->ref_cnt)) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + TAILQ_REMOVE(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + ol_txrx_dbg("Deleting pool %pK", pool); + ol_tx_delete_flow_pool(pool, force); + } else { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + ol_txrx_dbg("pool %pK, ref_cnt %x", + pool, qdf_atomic_read(&pool->ref_cnt)); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_tx_flow_pool_status_to_str() - convert flow pool status to string + * @status - flow pool status + * + * Returns: String corresponding to flow pool status + */ +static const char *ol_tx_flow_pool_status_to_str + (enum flow_pool_status status) +{ + switch (status) { + CASE_RETURN_STRING(FLOW_POOL_ACTIVE_UNPAUSED); + CASE_RETURN_STRING(FLOW_POOL_ACTIVE_PAUSED); + CASE_RETURN_STRING(FLOW_POOL_NON_PRIO_PAUSED); + CASE_RETURN_STRING(FLOW_POOL_INVALID); + CASE_RETURN_STRING(FLOW_POOL_INACTIVE); + default: + return "unknown"; + } +} + +void ol_tx_dump_flow_pool_info_compact(struct ol_txrx_pdev_t *pdev) +{ + char *comb_log_str; + int bytes_written = 0; + uint32_t free_size; + struct ol_tx_flow_pool_t *pool = NULL; + + free_size = WLAN_MAX_VDEVS * 100 + 100; + comb_log_str = qdf_mem_malloc(free_size); + if (!comb_log_str) + return; + + bytes_written = snprintf(&comb_log_str[bytes_written], free_size, + "G:(%d,%d) ", + pdev->tx_desc.pool_size, + pdev->tx_desc.num_free); + + free_size -= bytes_written; + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&pool->flow_pool_lock); + bytes_written += snprintf(&comb_log_str[bytes_written], + free_size, "| %d (%d,%d)", + pool->flow_pool_id, + pool->flow_pool_size, + pool->avail_desc); + free_size -= bytes_written; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + qdf_nofl_debug("STATS | FC: %s", comb_log_str); + qdf_mem_free(comb_log_str); +} + +/** + * ol_tx_dump_flow_pool_info() - dump global_pool and flow_pool info + * @soc_hdl: cdp_soc context, required only in lithium_dp flow control. + * + * Return: none + */ +void ol_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *pool = NULL, *pool_prev = NULL; + struct ol_tx_flow_pool_t tmp_pool; + + if (qdf_unlikely(!soc)) { + ol_txrx_err("soc is NULL"); + QDF_ASSERT(0); + return; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("ERROR: pdev NULL"); + QDF_ASSERT(0); /* traceback */ + return; + } + + txrx_nofl_info("Global total %d :: avail %d invalid flow_pool %d ", + pdev->tx_desc.pool_size, + pdev->tx_desc.num_free, + pdev->tx_desc.num_invalid_bin); + + txrx_nofl_info("maps %d pool unmaps %d pool resize %d pkt drops %d", + pdev->pool_stats.pool_map_count, + pdev->pool_stats.pool_unmap_count, + pdev->pool_stats.pool_resize_count, + pdev->pool_stats.pkt_drop_no_pool); + /* + * Nested spin lock. + * Always take in below order. + * flow_pool_list_lock -> flow_pool_lock + */ + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + ol_tx_inc_pool_ref(pool); + qdf_spin_lock_bh(&pool->flow_pool_lock); + qdf_mem_copy(&tmp_pool, pool, sizeof(tmp_pool)); + qdf_spin_unlock_bh(&pool->flow_pool_lock); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + if (pool_prev) + ol_tx_dec_pool_ref(pool_prev, false); + + txrx_nofl_info("flow_pool_id %d ::", tmp_pool.flow_pool_id); + txrx_nofl_info("status %s flow_id %d flow_type %d", + ol_tx_flow_pool_status_to_str + (tmp_pool.status), + tmp_pool.member_flow_id, tmp_pool.flow_type); + txrx_nofl_info("total %d :: available %d :: deficient %d :: overflow %d :: pkt dropped (no desc) %d", + tmp_pool.flow_pool_size, tmp_pool.avail_desc, + tmp_pool.deficient_desc, + tmp_pool.overflow_desc, + tmp_pool.pkt_drop_no_desc); + txrx_nofl_info("thresh: start %d stop %d prio start %d prio stop %d", + tmp_pool.start_th, tmp_pool.stop_th, + tmp_pool.start_priority_th, + tmp_pool.stop_priority_th); + pool_prev = pool; + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + /* decrement ref count for last pool in list */ + if (pool_prev) + ol_tx_dec_pool_ref(pool_prev, false); + +} + +/** + * ol_tx_clear_flow_pool_stats() - clear flow pool statistics + * + * Return: none + */ +void ol_tx_clear_flow_pool_stats(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is null"); + return; + } + qdf_mem_zero(&pdev->pool_stats, sizeof(pdev->pool_stats)); +} + +/** + * ol_tx_move_desc_n() - Move n descriptors from src_pool to dst_pool. + * @src_pool: source pool + * @dst_pool: destination pool + * @desc_move_count: descriptor move count + * + * Return: actual descriptors moved + */ +static int ol_tx_move_desc_n(struct ol_tx_flow_pool_t *src_pool, + struct ol_tx_flow_pool_t *dst_pool, + int desc_move_count) +{ + uint16_t count = 0, i; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *temp_list = NULL; + + /* Take descriptors from source pool and put it in temp_list */ + qdf_spin_lock_bh(&src_pool->flow_pool_lock); + for (i = 0; i < desc_move_count; i++) { + tx_desc = ol_tx_get_desc_flow_pool(src_pool); + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + + } + qdf_spin_unlock_bh(&src_pool->flow_pool_lock); + + /* Take descriptors from temp_list and put it in destination pool */ + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + for (i = 0; i < desc_move_count; i++) { + if (dst_pool->deficient_desc) + dst_pool->deficient_desc--; + else + break; + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_flow_pool(dst_pool, tx_desc); + count++; + } + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + + /* If anything is there in temp_list put it back to source pool */ + qdf_spin_lock_bh(&src_pool->flow_pool_lock); + while (temp_list) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_flow_pool(src_pool, tx_desc); + } + qdf_spin_unlock_bh(&src_pool->flow_pool_lock); + + return count; +} + + +/** + * ol_tx_distribute_descs_to_deficient_pools() - Distribute descriptors + * @src_pool: source pool + * + * Distribute all descriptors of source pool to all + * deficient pools as per flow_pool_list. + * + * Return: 0 for success + */ +static int +ol_tx_distribute_descs_to_deficient_pools(struct ol_tx_flow_pool_t *src_pool) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *dst_pool = NULL; + uint16_t desc_count = src_pool->avail_desc; + uint16_t desc_move_count = 0; + + if (qdf_unlikely(!soc)) + return -EINVAL; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return -EINVAL; + } + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(dst_pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + if (dst_pool->deficient_desc) { + desc_move_count = + (dst_pool->deficient_desc > desc_count) ? + desc_count : dst_pool->deficient_desc; + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + desc_move_count = ol_tx_move_desc_n(src_pool, + dst_pool, desc_move_count); + desc_count -= desc_move_count; + + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + if (dst_pool->status == FLOW_POOL_ACTIVE_PAUSED) { + if (dst_pool->avail_desc > dst_pool->start_th) { + pdev->pause_cb(dst_pool->member_flow_id, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + + pdev->pause_cb(dst_pool->member_flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + dst_pool->status = + FLOW_POOL_ACTIVE_UNPAUSED; + } + } + } + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + if (desc_count == 0) + break; + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return 0; +} + +/** + * ol_tx_create_flow_pool() - create flow pool + * @flow_pool_id: flow pool id + * @flow_pool_size: flow pool size + * + * Return: flow_pool pointer / NULL for error + */ +struct ol_tx_flow_pool_t *ol_tx_create_flow_pool(uint8_t flow_pool_id, + uint16_t flow_pool_size) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *pool; + uint16_t size = 0, i; + struct ol_tx_desc_t *tx_desc; + union ol_tx_desc_list_elem_t *temp_list = NULL; + uint32_t stop_threshold; + uint32_t start_threshold; + + if (qdf_unlikely(!soc)) + return NULL; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return NULL; + } + stop_threshold = ol_cfg_get_tx_flow_stop_queue_th(pdev->ctrl_pdev); + start_threshold = stop_threshold + + ol_cfg_get_tx_flow_start_queue_offset(pdev->ctrl_pdev); + pool = qdf_mem_malloc(sizeof(*pool)); + if (!pool) + return NULL; + + pool->flow_pool_id = flow_pool_id; + pool->flow_pool_size = flow_pool_size; + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + pool->start_th = (start_threshold * flow_pool_size)/100; + pool->stop_th = (stop_threshold * flow_pool_size)/100; + pool->stop_priority_th = (TX_PRIORITY_TH * pool->stop_th)/100; + if (pool->stop_priority_th >= MAX_TSO_SEGMENT_DESC) + pool->stop_priority_th -= MAX_TSO_SEGMENT_DESC; + + pool->start_priority_th = (TX_PRIORITY_TH * pool->start_th)/100; + if (pool->start_priority_th >= MAX_TSO_SEGMENT_DESC) + pool->start_priority_th -= MAX_TSO_SEGMENT_DESC; + + qdf_spinlock_create(&pool->flow_pool_lock); + qdf_atomic_init(&pool->ref_cnt); + ol_tx_inc_pool_ref(pool); + + /* Take TX descriptor from global_pool and put it in temp_list*/ + qdf_spin_lock_bh(&pdev->tx_mutex); + if (pdev->tx_desc.num_free >= pool->flow_pool_size) + size = pool->flow_pool_size; + else + size = pdev->tx_desc.num_free; + + for (i = 0; i < size; i++) { + tx_desc = ol_tx_get_desc_global_pool(pdev); + tx_desc->pool = pool; + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + /* put temp_list to flow_pool */ + pool->freelist = temp_list; + pool->avail_desc = size; + pool->deficient_desc = pool->flow_pool_size - pool->avail_desc; + /* used for resize pool*/ + pool->overflow_desc = 0; + + /* Add flow_pool to flow_pool_list */ + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_INSERT_TAIL(&pdev->tx_desc.flow_pool_list, pool, + flow_pool_list_elem); + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + return pool; +} + +/** + * ol_tx_free_invalid_flow_pool() - free invalid pool + * @pool: pool + * + * Return: 0 for success or failure + */ +int ol_tx_free_invalid_flow_pool(struct ol_tx_flow_pool_t *pool) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + + if (qdf_unlikely(!soc)) + return -EINVAL; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if ((!pdev) || (!pool) || (pool->status != FLOW_POOL_INVALID)) { + ol_txrx_err("Invalid pool/pdev"); + return -EINVAL; + } + + /* directly distribute to other deficient pools */ + ol_tx_distribute_descs_to_deficient_pools(pool); + + qdf_spin_lock_bh(&pool->flow_pool_lock); + pool->flow_pool_size = pool->avail_desc; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + pdev->tx_desc.num_invalid_bin--; + ol_txrx_info("invalid pool deleted %d", + pdev->tx_desc.num_invalid_bin); + + return ol_tx_dec_pool_ref(pool, false); +} + +/** + * ol_tx_get_flow_pool() - get flow_pool from flow_pool_id + * @flow_pool_id: flow pool id + * + * Return: flow_pool ptr / NULL if not found + */ +static struct ol_tx_flow_pool_t *ol_tx_get_flow_pool(uint8_t flow_pool_id) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *pool = NULL; + bool is_found = false; + + if (qdf_unlikely(!soc)) { + QDF_ASSERT(0); + return NULL; + } + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("ERROR: pdev NULL"); + QDF_ASSERT(0); /* traceback */ + return NULL; + } + + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->flow_pool_id == flow_pool_id) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + is_found = true; + break; + } + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + if (is_found == false) + pool = NULL; + + return pool; +} + +/** + * ol_tx_flow_pool_vdev_map() - Map flow_pool with vdev + * @pool: flow_pool + * @vdev_id: flow_id /vdev_id + * + * Return: none + */ +static void ol_tx_flow_pool_vdev_map(struct ol_tx_flow_pool_t *pool, + uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + ol_txrx_err("invalid vdev_id %d", vdev_id); + return; + } + + vdev->pool = pool; + qdf_spin_lock_bh(&pool->flow_pool_lock); + pool->member_flow_id = vdev_id; + qdf_spin_unlock_bh(&pool->flow_pool_lock); +} + +/** + * ol_tx_flow_pool_vdev_unmap() - Unmap flow_pool from vdev + * @pool: flow_pool + * @vdev_id: flow_id /vdev_id + * + * Return: none + */ +static void ol_tx_flow_pool_vdev_unmap(struct ol_tx_flow_pool_t *pool, + uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev; + + vdev = (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + if (!vdev) { + ol_txrx_dbg("invalid vdev_id %d", vdev_id); + return; + } + + vdev->pool = NULL; + qdf_spin_lock_bh(&pool->flow_pool_lock); + pool->member_flow_id = INVALID_FLOW_ID; + qdf_spin_unlock_bh(&pool->flow_pool_lock); +} + +/** + * ol_tx_flow_pool_map_handler() - Map flow_id with pool of descriptors + * @flow_id: flow id + * @flow_type: flow type + * @flow_pool_id: pool id + * @flow_pool_size: pool size + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_MAP + * + * Return: none + */ +void ol_tx_flow_pool_map_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id, uint16_t flow_pool_size) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *pool; + uint8_t pool_create = 0; + enum htt_flow_type type = flow_type; + + ol_txrx_dbg("flow_id %d flow_type %d flow_pool_id %d flow_pool_size %d", + flow_id, flow_type, flow_pool_id, flow_pool_size); + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is NULL"); + return; + } + pdev->pool_stats.pool_map_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + pool = ol_tx_create_flow_pool(flow_pool_id, flow_pool_size); + if (!pool) { + ol_txrx_err("creation of flow_pool %d size %d failed", + flow_pool_id, flow_pool_size); + return; + } + pool_create = 1; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_map(pool, flow_id); + pdev->pause_cb(flow_id, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + pdev->pause_cb(flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + break; + default: + if (pool_create) + ol_tx_dec_pool_ref(pool, false); + ol_txrx_err("flow type %d not supported", type); + break; + } +} + +/** + * ol_tx_flow_pool_unmap_handler() - Unmap flow_id from pool of descriptors + * @flow_id: flow id + * @flow_type: flow type + * @flow_pool_id: pool id + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP + * + * Return: none + */ +void ol_tx_flow_pool_unmap_handler(uint8_t flow_id, uint8_t flow_type, + uint8_t flow_pool_id) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *pool; + enum htt_flow_type type = flow_type; + + ol_txrx_dbg("flow_id %d flow_type %d flow_pool_id %d", + flow_id, flow_type, flow_pool_id); + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is NULL"); + return; + } + pdev->pool_stats.pool_unmap_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + ol_txrx_info("flow_pool not available flow_pool_id %d", type); + return; + } + + switch (type) { + + case FLOW_TYPE_VDEV: + ol_tx_flow_pool_vdev_unmap(pool, flow_id); + break; + default: + ol_txrx_info("flow type %d not supported", type); + return; + } + + /* + * only delete if all descriptors are available + * and pool ref count becomes 0 + */ + ol_tx_dec_pool_ref(pool, false); +} + +#ifdef QCA_LL_TX_FLOW_CONTROL_RESIZE +/** + * ol_tx_distribute_descs_to_deficient_pools_from_global_pool() + * + * Distribute descriptors of global pool to all + * deficient pools as per need. + * + * Return: 0 for success + */ +int ol_tx_distribute_descs_to_deficient_pools_from_global_pool(void) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *dst_pool = NULL; + struct ol_tx_flow_pool_t *tmp_pool = NULL; + uint16_t total_desc_req = 0; + uint16_t desc_move_count = 0; + uint16_t temp_count = 0, i; + union ol_tx_desc_list_elem_t *temp_list = NULL; + struct ol_tx_desc_t *tx_desc; + uint8_t free_invalid_pool = 0; + + if (qdf_unlikely(!soc)) + return -EINVAL; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return -EINVAL; + } + + /* Nested locks: maintain flow_pool_list_lock->flow_pool_lock */ + /* find out total deficient desc required */ + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(dst_pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + total_desc_req += dst_pool->deficient_desc; + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + qdf_spin_lock_bh(&pdev->tx_mutex); + desc_move_count = (pdev->tx_desc.num_free >= total_desc_req) ? + total_desc_req : pdev->tx_desc.num_free; + + for (i = 0; i < desc_move_count; i++) { + tx_desc = ol_tx_get_desc_global_pool(pdev); + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + if (!desc_move_count) + return 0; + + /* distribute desc to deficient pool */ + qdf_spin_lock_bh(&pdev->tx_desc.flow_pool_list_lock); + TAILQ_FOREACH(dst_pool, &pdev->tx_desc.flow_pool_list, + flow_pool_list_elem) { + qdf_spin_lock_bh(&dst_pool->flow_pool_lock); + if (dst_pool->deficient_desc) { + temp_count = + (dst_pool->deficient_desc > desc_move_count) ? + desc_move_count : dst_pool->deficient_desc; + + desc_move_count -= temp_count; + dst_pool->deficient_desc -= temp_count; + for (i = 0; i < temp_count; i++) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_flow_pool(dst_pool, tx_desc); + } + + if (dst_pool->status == FLOW_POOL_ACTIVE_PAUSED) { + if (dst_pool->avail_desc > dst_pool->start_th) { + pdev->pause_cb(dst_pool->member_flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + dst_pool->status = + FLOW_POOL_ACTIVE_UNPAUSED; + } + } else if ((dst_pool->status == FLOW_POOL_INVALID) && + (dst_pool->avail_desc == + dst_pool->flow_pool_size)) { + free_invalid_pool = 1; + tmp_pool = dst_pool; + } + } + qdf_spin_unlock_bh(&dst_pool->flow_pool_lock); + if (desc_move_count == 0) + break; + } + qdf_spin_unlock_bh(&pdev->tx_desc.flow_pool_list_lock); + + if (free_invalid_pool && tmp_pool) + ol_tx_free_invalid_flow_pool(tmp_pool); + + return 0; +} + +/** + * ol_tx_flow_pool_update_queue_state() - update network queue for pool based on + * new available count. + * @pool : pool handle + * + * Return : none + */ +static void ol_tx_flow_pool_update_queue_state(struct ol_txrx_pdev_t *pdev, + struct ol_tx_flow_pool_t *pool) +{ + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->avail_desc > pool->start_th) { + pool->status = FLOW_POOL_ACTIVE_UNPAUSED; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + pdev->pause_cb(pool->member_flow_id, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } else if (pool->avail_desc < pool->stop_th && + pool->avail_desc >= pool->stop_priority_th) { + pool->status = FLOW_POOL_NON_PRIO_PAUSED; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + pdev->pause_cb(pool->member_flow_id, + WLAN_STOP_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + pdev->pause_cb(pool->member_flow_id, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL); + } else if (pool->avail_desc < pool->stop_priority_th) { + pool->status = FLOW_POOL_ACTIVE_PAUSED; + qdf_spin_unlock_bh(&pool->flow_pool_lock); + pdev->pause_cb(pool->member_flow_id, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } else { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + } +} + +/** + * ol_tx_flow_pool_update() - update pool parameters with new size + * @pool : pool handle + * @new_pool_size : new pool size + * @deficient_count : deficient count + * @overflow_count : overflow count + * + * Return : none + */ +static void ol_tx_flow_pool_update(struct ol_tx_flow_pool_t *pool, + uint16_t new_pool_size, + uint16_t deficient_count, + uint16_t overflow_count) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + uint32_t stop_threshold; + uint32_t start_threshold; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + stop_threshold = ol_cfg_get_tx_flow_stop_queue_th(pdev->ctrl_pdev); + start_threshold = stop_threshold + + ol_cfg_get_tx_flow_start_queue_offset(pdev->ctrl_pdev); + pool->flow_pool_size = new_pool_size; + pool->start_th = (start_threshold * new_pool_size) / 100; + pool->stop_th = (stop_threshold * new_pool_size) / 100; + pool->stop_priority_th = (TX_PRIORITY_TH * pool->stop_th) / 100; + if (pool->stop_priority_th >= MAX_TSO_SEGMENT_DESC) + pool->stop_priority_th -= MAX_TSO_SEGMENT_DESC; + + pool->start_priority_th = (TX_PRIORITY_TH * pool->start_th) / 100; + if (pool->start_priority_th >= MAX_TSO_SEGMENT_DESC) + pool->start_priority_th -= MAX_TSO_SEGMENT_DESC; + + if (deficient_count) + pool->deficient_desc = deficient_count; + + if (overflow_count) + pool->overflow_desc = overflow_count; +} + +/** + * ol_tx_flow_pool_resize() - resize pool with new size + * @pool: pool pointer + * @new_pool_size: new pool size + * + * Return: none + */ +static void ol_tx_flow_pool_resize(struct ol_tx_flow_pool_t *pool, + uint16_t new_pool_size) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + uint16_t diff = 0, overflow_count = 0, deficient_count = 0; + uint16_t move_desc_to_global = 0, move_desc_from_global = 0; + union ol_tx_desc_list_elem_t *temp_list = NULL; + int i = 0, update_done = 0; + struct ol_tx_desc_t *tx_desc = NULL; + uint16_t temp = 0; + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("pdev is NULL"); + return; + } + + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->flow_pool_size == new_pool_size) { + qdf_spin_unlock_bh(&pool->flow_pool_lock); + ol_txrx_info("pool resize received with same size"); + return; + } + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + /* Reduce pool size */ + /* start_priority_th desc should available after reduction */ + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->flow_pool_size > new_pool_size) { + diff = pool->flow_pool_size - new_pool_size; + diff += pool->overflow_desc; + pool->overflow_desc = 0; + temp = QDF_MIN(pool->deficient_desc, diff); + pool->deficient_desc -= temp; + diff -= temp; + + if (diff) { + /* Have enough descriptors */ + if (pool->avail_desc >= + (diff + pool->start_priority_th)) { + move_desc_to_global = diff; + } + /* Do not have enough descriptors */ + else if (pool->avail_desc > pool->start_priority_th) { + move_desc_to_global = pool->avail_desc - + pool->start_priority_th; + overflow_count = diff - move_desc_to_global; + } + + /* Move desc to temp_list */ + for (i = 0; i < move_desc_to_global; i++) { + tx_desc = ol_tx_get_desc_flow_pool(pool); + ((union ol_tx_desc_list_elem_t *)tx_desc)->next + = temp_list; + temp_list = + (union ol_tx_desc_list_elem_t *)tx_desc; + } + } + + /* update pool size and threshold */ + ol_tx_flow_pool_update(pool, new_pool_size, 0, overflow_count); + update_done = 1; + } + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + if (move_desc_to_global && temp_list) { + /* put free descriptors to global pool */ + qdf_spin_lock_bh(&pdev->tx_mutex); + for (i = 0; i < move_desc_to_global; i++) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_global_pool(pdev, tx_desc); + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + } + + if (update_done) + goto update_done; + + /* Increase pool size */ + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (pool->flow_pool_size < new_pool_size) { + diff = new_pool_size - pool->flow_pool_size; + diff += pool->deficient_desc; + pool->deficient_desc = 0; + temp = QDF_MIN(pool->overflow_desc, diff); + pool->overflow_desc -= temp; + diff -= temp; + } + qdf_spin_unlock_bh(&pool->flow_pool_lock); + + if (diff) { + /* take descriptors from global pool */ + qdf_spin_lock_bh(&pdev->tx_mutex); + + if (pdev->tx_desc.num_free >= diff) { + move_desc_from_global = diff; + } else { + move_desc_from_global = pdev->tx_desc.num_free; + deficient_count = diff - move_desc_from_global; + } + + for (i = 0; i < move_desc_from_global; i++) { + tx_desc = ol_tx_get_desc_global_pool(pdev); + ((union ol_tx_desc_list_elem_t *)tx_desc)->next = + temp_list; + temp_list = (union ol_tx_desc_list_elem_t *)tx_desc; + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + } + /* update desc to pool */ + qdf_spin_lock_bh(&pool->flow_pool_lock); + if (move_desc_from_global && temp_list) { + for (i = 0; i < move_desc_from_global; i++) { + tx_desc = &temp_list->tx_desc; + temp_list = temp_list->next; + ol_tx_put_desc_flow_pool(pool, tx_desc); + } + } + /* update pool size and threshold */ + ol_tx_flow_pool_update(pool, new_pool_size, deficient_count, 0); + qdf_spin_unlock_bh(&pool->flow_pool_lock); + +update_done: + + ol_tx_flow_pool_update_queue_state(pdev, pool); +} + +/** + * ol_tx_flow_pool_resize_handler() - Resize pool with new size + * @flow_pool_id: pool id + * @flow_pool_size: pool size + * + * Process below target to host message + * HTT_T2H_MSG_TYPE_FLOW_POOL_RESIZE + * + * Return: none + */ +void ol_tx_flow_pool_resize_handler(uint8_t flow_pool_id, + uint16_t flow_pool_size) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + ol_txrx_pdev_handle pdev; + struct ol_tx_flow_pool_t *pool; + + ol_txrx_dbg("flow_pool_id %d flow_pool_size %d", + flow_pool_id, flow_pool_size); + + if (qdf_unlikely(!soc)) + return; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is NULL"); + return; + } + pdev->pool_stats.pool_resize_count++; + + pool = ol_tx_get_flow_pool(flow_pool_id); + if (!pool) { + ol_txrx_err("resize for flow_pool %d size %d failed", + flow_pool_id, flow_pool_size); + return; + } + + ol_tx_inc_pool_ref(pool); + ol_tx_flow_pool_resize(pool, flow_pool_size); + ol_tx_dec_pool_ref(pool, false); +} +#endif + +/** + * ol_txrx_map_to_netif_reason_type() - map to netif_reason_type + * @reason: network queue pause reason + * + * Return: netif_reason_type + */ +static enum netif_reason_type +ol_txrx_map_to_netif_reason_type(uint32_t reason) +{ + switch (reason) { + case OL_TXQ_PAUSE_REASON_FW: + return WLAN_FW_PAUSE; + case OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED: + return WLAN_PEER_UNAUTHORISED; + case OL_TXQ_PAUSE_REASON_TX_ABORT: + return WLAN_TX_ABORT; + case OL_TXQ_PAUSE_REASON_VDEV_STOP: + return WLAN_VDEV_STOP; + case OL_TXQ_PAUSE_REASON_THERMAL_MITIGATION: + return WLAN_THERMAL_MITIGATION; + default: + ol_txrx_err("reason not supported %d", reason); + return WLAN_REASON_TYPE_MAX; + } +} + +void ol_txrx_vdev_pause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + struct ol_txrx_pdev_t *pdev; + enum netif_reason_type netif_reason; + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + pdev = vdev->pdev; + if (qdf_unlikely((!pdev) || (!pdev->pause_cb))) { + ol_txrx_err("invalid pdev"); + return; + } + + netif_reason = ol_txrx_map_to_netif_reason_type(reason); + if (netif_reason == WLAN_REASON_TYPE_MAX) + return; + + pdev->pause_cb(vdev->vdev_id, WLAN_STOP_ALL_NETIF_QUEUE, netif_reason); +} + +/** + * ol_txrx_vdev_unpause() - unpause vdev network queues + * @soc_hdl: datapath soc handle + * @vdev: vdev handle + * @reason: network queue pause reason + * @pause_type: type of pause + * + * Return: none + */ +void ol_txrx_vdev_unpause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + struct ol_txrx_pdev_t *pdev; + enum netif_reason_type netif_reason; + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + pdev = vdev->pdev; + if (qdf_unlikely((!pdev) || (!pdev->pause_cb))) { + ol_txrx_err("invalid pdev"); + return; + } + + netif_reason = ol_txrx_map_to_netif_reason_type(reason); + if (netif_reason == WLAN_REASON_TYPE_MAX) + return; + + pdev->pause_cb(vdev->vdev_id, WLAN_WAKE_ALL_NETIF_QUEUE, + netif_reason); +} + +/** + * ol_txrx_pdev_pause() - pause network queues for each vdev + * @pdev: pdev handle + * @reason: network queue pause reason + * + * Return: none + */ +void ol_txrx_pdev_pause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + ol_txrx_vdev_pause(ol_txrx_soc_t_to_cdp_soc_t(soc), + vdev->vdev_id, reason, 0); + } +} + +/** + * ol_txrx_pdev_unpause() - unpause network queues for each vdev + * @pdev: pdev handle + * @reason: network queue pause reason + * + * Return: none + */ +void ol_txrx_pdev_unpause(struct ol_txrx_pdev_t *pdev, uint32_t reason) +{ + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ol_txrx_vdev_t *vdev = NULL, *tmp; + + TAILQ_FOREACH_SAFE(vdev, &pdev->vdev_list, vdev_list_elem, tmp) { + ol_txrx_vdev_unpause(ol_txrx_soc_t_to_cdp_soc_t(soc), + vdev->vdev_id, reason, 0); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h new file mode 100644 index 0000000000..c0ecf3ee6e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_internal.h @@ -0,0 +1,831 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_TXRX_INTERNAL__H_ +#define _OL_TXRX_INTERNAL__H_ + +#include /* qdf_assert */ +#include /* qdf_nbuf_t */ +#include /* qdf_mem_set */ +#include /* ieee80211_frame */ +#include /* htt_rx_msdu_desc_completes_mpdu, etc. */ + +#include + +#include +#include /* ETHERNET_HDR_LEN, etc. */ +#include /* IPV4_HDR_LEN, etc. */ +#include /* IP_PROTOCOL_TCP, etc. */ + +#ifdef ATH_11AC_TXCOMPACT +#define OL_TX_DESC_NO_REFS(tx_desc) 1 +#define OL_TX_DESC_REF_INIT(tx_desc) /* no-op */ +#define OL_TX_DESC_REF_INC(tx_desc) /* no-op */ +#else +#define OL_TX_DESC_NO_REFS(tx_desc) \ + qdf_atomic_dec_and_test(&tx_desc->ref_cnt) +#define OL_TX_DESC_REF_INIT(tx_desc) qdf_atomic_init(&tx_desc->ref_cnt) +#define OL_TX_DESC_REF_INC(tx_desc) qdf_atomic_inc(&tx_desc->ref_cnt) +#endif + +#ifndef TXRX_ASSERT_LEVEL +#define TXRX_ASSERT_LEVEL 3 +#endif + +#ifdef __KLOCWORK__ +#define TXRX_ASSERT1(x) do { if (!(x)) abort(); } while (0) +#define TXRX_ASSERT2(x) do { if (!(x)) abort(); } while (0) +#else /* #ifdef __KLOCWORK__ */ + +#if TXRX_ASSERT_LEVEL > 0 +#define TXRX_ASSERT1(condition) qdf_assert((condition)) +#else +#define TXRX_ASSERT1(condition) +#endif + +#if TXRX_ASSERT_LEVEL > 1 +#define TXRX_ASSERT2(condition) qdf_assert((condition)) +#else +#define TXRX_ASSERT2(condition) +#endif +#endif /* #ifdef __KLOCWORK__ */ + +#ifdef TXRX_PRINT_ENABLE + +#include "qdf_types.h" /* qdf_vprint */ + +#define ol_txrx_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_TXRX, params) +#define ol_txrx_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_TXRX, params) +#define ol_txrx_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_TXRX, params) +#define ol_txrx_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_TXRX, params) +#define ol_txrx_info_high(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_TXRX, params) +#define ol_txrx_dbg(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_TXRX, params) + +#define txrx_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_TXRX, params) +#define txrx_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_TXRX, params) +#define txrx_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_TXRX, params) +#define txrx_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_TXRX, params) +#define txrx_nofl_dbg(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_TXRX, params) + +#define ol_txrx_err_rl(params...) \ + QDF_TRACE_ERROR_RL(QDF_MODULE_ID_TXRX, params) + +/* + * define PN check failure message print rate + * as 1 second + */ +#define TXRX_PN_CHECK_FAILURE_PRINT_PERIOD_MS 1000 + +#else + +#define ol_txrx_alert(format, args...) +#define ol_txrx_err(format, args...) +#define ol_txrx_warn(format, args...) +#define ol_txrx_info(format, args...) +#define ol_txrx_info_high(format, args...) +#define ol_txrx_dbg(format, args...) + +#define txrx_nofl_alert(params...) +#define txrx_nofl_err(params...) +#define txrx_nofl_warn(params...) +#define txrx_nofl_info(params...) +#define txrx_nofl_dbg(params...) + +#define ol_txrx_err_rl(params...) + +#endif /* TXRX_PRINT_ENABLE */ + +/*--- tx credit debug printouts ---*/ + +#ifndef DEBUG_CREDIT +#define DEBUG_CREDIT 0 +#endif + +#if DEBUG_CREDIT +#define TX_CREDIT_DEBUG_PRINT(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) +#else +#define TX_CREDIT_DEBUG_PRINT(fmt, ...) +#endif + +/*--- tx scheduler debug printouts ---*/ + +#ifdef HOST_TX_SCHED_DEBUG +#define TX_SCHED_DEBUG_PRINT(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) +#else +#define TX_SCHED_DEBUG_PRINT(fmt, ...) +#endif +#define TX_SCHED_DEBUG_PRINT_ALWAYS(fmt, ...) qdf_print(fmt, ## __VA_ARGS__) + +#define OL_TXRX_LIST_APPEND(head, tail, elem) \ + do { \ + if (!(head)) { \ + (head) = (elem); \ + } else { \ + qdf_nbuf_set_next((tail), (elem)); \ + } \ + (tail) = (elem); \ + } while (0) + +static inline void +ol_rx_mpdu_list_next(struct ol_txrx_pdev_t *pdev, + void *mpdu_list, + qdf_nbuf_t *mpdu_tail, qdf_nbuf_t *next_mpdu) +{ + htt_pdev_handle htt_pdev = pdev->htt_pdev; + qdf_nbuf_t msdu; + + /* + * For now, we use a simply flat list of MSDUs. + * So, traverse the list until we reach the last MSDU within the MPDU. + */ + TXRX_ASSERT2(mpdu_list); + msdu = mpdu_list; + while (!htt_rx_msdu_desc_completes_mpdu + (htt_pdev, htt_rx_msdu_desc_retrieve(htt_pdev, msdu))) { + if (!qdf_nbuf_next(msdu)) { + qdf_err("last-msdu bit not set!"); + break; + } else { + msdu = qdf_nbuf_next(msdu); + } + TXRX_ASSERT2(msdu); + } + /* msdu now points to the last MSDU within the first MPDU */ + *mpdu_tail = msdu; + *next_mpdu = qdf_nbuf_next(msdu); +} + +/*--- txrx stats macros ---*/ + +/* unconditional defs */ +#define TXRX_STATS_INCR(pdev, field) TXRX_STATS_ADD(pdev, field, 1) + +/* default conditional defs (may be undefed below) */ + +#define TXRX_STATS_INIT(_pdev) \ + qdf_mem_zero(&((_pdev)->stats), sizeof((_pdev)->stats)) +#define TXRX_STATS_ADD(_pdev, _field, _delta) { \ + _pdev->stats._field += _delta; } +#define TXRX_STATS_MSDU_INCR(pdev, field, netbuf) \ + do { \ + TXRX_STATS_INCR((pdev), pub.field.pkts); \ + TXRX_STATS_ADD((pdev), pub.field.bytes, qdf_nbuf_len(netbuf)); \ + } while (0) + +/* conditional defs based on verbosity level */ + + +#define TXRX_STATS_MSDU_LIST_INCR(pdev, field, netbuf_list) \ + do { \ + qdf_nbuf_t tmp_list = netbuf_list; \ + while (tmp_list) { \ + TXRX_STATS_MSDU_INCR(pdev, field, tmp_list); \ + tmp_list = qdf_nbuf_next(tmp_list); \ + } \ + } while (0) + +#define TXRX_STATS_MSDU_INCR_TX_STATUS(status, pdev, netbuf) do { \ + if (status == htt_tx_status_ok) \ + TXRX_STATS_MSDU_INCR(pdev, tx.delivered, netbuf); \ + else if (status == htt_tx_status_discard) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.target_discard, \ + netbuf); \ + else if (status == htt_tx_status_no_ack) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.no_ack, netbuf); \ + else if (status == htt_tx_status_drop) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.target_drop, \ + netbuf); \ + else if (status == htt_tx_status_download_fail) \ + TXRX_STATS_MSDU_INCR(pdev, tx.dropped.download_fail, \ + netbuf); \ + else \ + /* NO-OP */; \ + } while (0) + +#define TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs) \ + do { \ + if (_p_cntrs == 1) { \ + TXRX_STATS_ADD(_pdev, pub.tx.comp_histogram.pkts_1, 1);\ + } else if (_p_cntrs > 2 && _p_cntrs <= 10) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_2_10, 1); \ + } else if (_p_cntrs > 10 && _p_cntrs <= 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_11_20, 1); \ + } else if (_p_cntrs > 20 && _p_cntrs <= 30) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_21_30, 1); \ + } else if (_p_cntrs > 30 && _p_cntrs <= 40) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_31_40, 1); \ + } else if (_p_cntrs > 40 && _p_cntrs <= 50) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_41_50, 1); \ + } else if (_p_cntrs > 50 && _p_cntrs <= 60) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_51_60, 1); \ + } else { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.comp_histogram.pkts_61_plus, 1); \ + } \ + } while (0) + +#define TXRX_STATS_UPDATE_TX_STATS(_pdev, _status, _p_cntrs, _b_cntrs) \ + do { \ + switch (status) { \ + case htt_tx_status_ok: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.delivered.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.delivered.bytes, _b_cntrs); \ + break; \ + case htt_tx_status_discard: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_discard.pkts, _p_cntrs);\ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_discard.bytes, _b_cntrs);\ + break; \ + case htt_tx_status_no_ack: \ + TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.pkts, \ + _p_cntrs); \ + TXRX_STATS_ADD(_pdev, pub.tx.dropped.no_ack.bytes, \ + _b_cntrs); \ + break; \ + case htt_tx_status_drop: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_drop.pkts, _p_cntrs);\ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.target_drop.bytes, _b_cntrs);\ + break; \ + case htt_tx_status_download_fail: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.download_fail.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.download_fail.bytes, _b_cntrs);\ + break; \ + default: \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.others.pkts, _p_cntrs); \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.dropped.others.bytes, _b_cntrs); \ + break; \ + } \ + TXRX_STATS_UPDATE_TX_COMP_HISTOGRAM(_pdev, _p_cntrs); \ + } while (0) + + +/*--- txrx sequence number trace macros ---*/ + +#define TXRX_SEQ_NUM_ERR(_status) (0xffff - _status) + +#if defined(ENABLE_RX_REORDER_TRACE) + +A_STATUS ol_rx_reorder_trace_attach(ol_txrx_pdev_handle pdev); +void ol_rx_reorder_trace_detach(ol_txrx_pdev_handle pdev); +void ol_rx_reorder_trace_add(ol_txrx_pdev_handle pdev, + uint8_t tid, + uint16_t reorder_idx, + uint16_t seq_num, int num_mpdus); + +#define OL_RX_REORDER_TRACE_ATTACH ol_rx_reorder_trace_attach +#define OL_RX_REORDER_TRACE_DETACH ol_rx_reorder_trace_detach +#define OL_RX_REORDER_TRACE_ADD ol_rx_reorder_trace_add + +#else + +#define OL_RX_REORDER_TRACE_ATTACH(_pdev) A_OK +#define OL_RX_REORDER_TRACE_DETACH(_pdev) +#define OL_RX_REORDER_TRACE_ADD(pdev, tid, reorder_idx, seq_num, num_mpdus) + +#endif /* ENABLE_RX_REORDER_TRACE */ + +/*--- txrx packet number trace macros ---*/ + +#if defined(ENABLE_RX_PN_TRACE) + +A_STATUS ol_rx_pn_trace_attach(ol_txrx_pdev_handle pdev); +void ol_rx_pn_trace_detach(ol_txrx_pdev_handle pdev); +void ol_rx_pn_trace_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer, + uint16_t tid, void *rx_desc); + +#define OL_RX_PN_TRACE_ATTACH ol_rx_pn_trace_attach +#define OL_RX_PN_TRACE_DETACH ol_rx_pn_trace_detach +#define OL_RX_PN_TRACE_ADD ol_rx_pn_trace_add + +#else + +#define OL_RX_PN_TRACE_ATTACH(_pdev) A_OK +#define OL_RX_PN_TRACE_DETACH(_pdev) +#define OL_RX_PN_TRACE_ADD(pdev, peer, tid, rx_desc) + +#endif /* ENABLE_RX_PN_TRACE */ + +static inline int ol_txrx_ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int size = sizeof(struct ieee80211_frame); + + /* NB: we don't handle control frames */ + TXRX_ASSERT1((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != + IEEE80211_FC0_TYPE_CTL); + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == + IEEE80211_FC1_DIR_DSTODS) + size += QDF_MAC_ADDR_SIZE; + if (IEEE80211_QOS_HAS_SEQ(wh)) { + size += sizeof(uint16_t); + /* Qos frame with Order bit set indicates an HTC frame */ + if (wh->i_fc[1] & IEEE80211_FC1_ORDER) + size += sizeof(struct ieee80211_htc); + } + return size; +} + +/*--- frame display utility ---*/ + +enum ol_txrx_frm_dump_options { + ol_txrx_frm_dump_contents = 0x1, + ol_txrx_frm_dump_tcp_seq = 0x2, +}; + +#ifdef TXRX_DEBUG_DATA +static inline void +ol_txrx_frms_dump(const char *name, + struct ol_txrx_pdev_t *pdev, + qdf_nbuf_t frm, + enum ol_txrx_frm_dump_options display_options, int max_len) +{ +#define TXRX_FRM_DUMP_MAX_LEN 128 + uint8_t local_buf[TXRX_FRM_DUMP_MAX_LEN] = { 0 }; + uint8_t *p; + + if (name) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, "%s\n", + name); + } + while (frm) { + p = qdf_nbuf_data(frm); + if (display_options & ol_txrx_frm_dump_tcp_seq) { + int tcp_offset; + int l2_hdr_size; + uint16_t ethtype; + uint8_t ip_prot; + + if (pdev->frame_format == wlan_frm_fmt_802_3) { + struct ethernet_hdr_t *enet_hdr = + (struct ethernet_hdr_t *)p; + l2_hdr_size = ETHERNET_HDR_LEN; + + /* + * LLC/SNAP present? + */ + ethtype = (enet_hdr->ethertype[0] << 8) | + enet_hdr->ethertype[1]; + if (!IS_ETHERTYPE(ethertype)) { + /* 802.3 format */ + struct llc_snap_hdr_t *llc_hdr; + + llc_hdr = (struct llc_snap_hdr_t *) + (p + l2_hdr_size); + l2_hdr_size += LLC_SNAP_HDR_LEN; + ethtype = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + } + } else { + struct llc_snap_hdr_t *llc_hdr; + + /* (generic?) 802.11 */ + l2_hdr_size = sizeof(struct ieee80211_frame); + llc_hdr = (struct llc_snap_hdr_t *) + (p + l2_hdr_size); + l2_hdr_size += LLC_SNAP_HDR_LEN; + ethtype = (llc_hdr->ethertype[0] << 8) | + llc_hdr->ethertype[1]; + } + if (ethtype == ETHERTYPE_IPV4) { + struct ipv4_hdr_t *ipv4_hdr; + + ipv4_hdr = + (struct ipv4_hdr_t *)(p + l2_hdr_size); + ip_prot = ipv4_hdr->protocol; + tcp_offset = l2_hdr_size + IPV4_HDR_LEN; + } else if (ethtype == ETHERTYPE_IPV6) { + struct ipv6_hdr_t *ipv6_hdr; + + ipv6_hdr = + (struct ipv6_hdr_t *)(p + l2_hdr_size); + ip_prot = ipv6_hdr->next_hdr; + tcp_offset = l2_hdr_size + IPV6_HDR_LEN; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %pK non-IP ethertype (%x)\n", + frm, ethtype); + goto NOT_IP_TCP; + } + if (ip_prot == IP_PROTOCOL_TCP) { +#if NEVERDEFINED + struct tcp_hdr_t *tcp_hdr; + uint32_t tcp_seq_num; + + tcp_hdr = (struct tcp_hdr_t *)(p + tcp_offset); + tcp_seq_num = + (tcp_hdr->seq_num[0] << 24) | + (tcp_hdr->seq_num[1] << 16) | + (tcp_hdr->seq_num[1] << 8) | + (tcp_hdr->seq_num[1] << 0); + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %pK: TCP seq num = %d\n", frm, + tcp_seq_num); +#else + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %pK: TCP seq num = %d\n", frm, + ((*(p + tcp_offset + 4)) << 24) | + ((*(p + tcp_offset + 5)) << 16) | + ((*(p + tcp_offset + 6)) << 8) | + (*(p + tcp_offset + 7))); +#endif + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + "frame %pK non-TCP IP protocol (%x)\n", + frm, ip_prot); + } + } +NOT_IP_TCP: + if (display_options & ol_txrx_frm_dump_contents) { + int i, frag_num, len_lim; + + len_lim = max_len; + if (len_lim > qdf_nbuf_len(frm)) + len_lim = qdf_nbuf_len(frm); + if (len_lim > TXRX_FRM_DUMP_MAX_LEN) + len_lim = TXRX_FRM_DUMP_MAX_LEN; + + /* + * Gather frame contents from netbuf fragments + * into a contiguous buffer. + */ + frag_num = 0; + i = 0; + while (i < len_lim) { + int frag_bytes; + + frag_bytes = + qdf_nbuf_get_frag_len(frm, frag_num); + if (frag_bytes > len_lim - i) + frag_bytes = len_lim - i; + if (frag_bytes > 0) { + p = qdf_nbuf_get_frag_vaddr(frm, + frag_num); + qdf_mem_copy(&local_buf[i], p, + frag_bytes); + } + frag_num++; + i += frag_bytes; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "frame %pK data (%pK), hex dump of bytes 0-%d of %d:\n", + frm, p, len_lim - 1, (int)qdf_nbuf_len(frm)); + p = local_buf; + while (len_lim > 16) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, + " " /* indent */ + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + *(p + 0), *(p + 1), *(p + 2), + *(p + 3), *(p + 4), *(p + 5), + *(p + 6), *(p + 7), *(p + 8), + *(p + 9), *(p + 10), *(p + 11), + *(p + 12), *(p + 13), *(p + 14), + *(p + 15)); + p += 16; + len_lim -= 16; + } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + " " /* indent */); + while (len_lim > 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO, "%02x ", *p); + p++; + len_lim--; + } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO, + "\n"); + } + frm = qdf_nbuf_next(frm); + } +} +#else +#define ol_txrx_frms_dump(name, pdev, frms, display_options, max_len) +#endif /* TXRX_DEBUG_DATA */ + +#ifdef SUPPORT_HOST_STATISTICS + +#define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) \ + ol_rx_err_statistics(pdev->ctrl_pdev, vdev->vdev_id, err_type, \ + sec_type, is_mcast) + +#define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) \ + do { \ + int is_mcast; \ + enum htt_sec_type sec_type; \ + is_mcast = htt_rx_msdu_is_wlan_mcast( \ + pdev->htt_pdev, rx_desc); \ + sec_type = peer->security[is_mcast \ + ? txrx_sec_mcast \ + : txrx_sec_ucast].sec_type; \ + OL_RX_ERR_STATISTICS(pdev, vdev, err_type, \ + pdev->sec_types[sec_type], \ + is_mcast); \ + } while (false) + +#ifdef CONFIG_HL_SUPPORT + + /** + * ol_rx_err_inv_get_wifi_header() - retrieve wifi header + * @pdev: handle to the physical device + * @rx_msdu: msdu of which header needs to be retrieved + * + * Return: wifi header + */ + static inline + struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( + struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) + { + return NULL; + } +#else + + static inline + struct ieee80211_frame *ol_rx_err_inv_get_wifi_header( + struct ol_pdev_t *pdev, qdf_nbuf_t rx_msdu) + { + struct ieee80211_frame *wh = NULL; + + if (ol_cfg_frame_type(pdev) == wlan_frm_fmt_native_wifi) + /* For windows, it is always native wifi header .*/ + wh = (struct ieee80211_frame *)qdf_nbuf_data(rx_msdu); + + return wh; + } +#endif + +#define OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu) \ + do { \ + struct ieee80211_frame *wh = NULL; \ + /*FIX THIS : */ \ + /* Here htt_rx_mpdu_wifi_hdr_retrieve should be used. */ \ + /*But at present it seems it does not work.*/ \ + /*wh = (struct ieee80211_frame *) */ \ + /*htt_rx_mpdu_wifi_hdr_retrieve(pdev->htt_pdev, rx_desc);*/ \ + /* this only apply to LL device.*/ \ + wh = ol_rx_err_inv_get_wifi_header(pdev->ctrl_pdev, rx_msdu); \ + ol_rx_err_inv_peer_statistics(pdev->ctrl_pdev, \ + wh, OL_RX_ERR_UNKNOWN_PEER); \ + } while (false) + +#define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) \ + do { \ + enum ol_rx_err_type err_type = OL_RX_ERR_NONE; \ + if (rx_status == htt_rx_status_decrypt_err) \ + err_type = OL_RX_ERR_DECRYPT; \ + else if (rx_status == htt_rx_status_tkip_mic_err) \ + err_type = OL_RX_ERR_TKIP_MIC; \ + else if (rx_status == htt_rx_status_mpdu_length_err) \ + err_type = OL_RX_ERR_MPDU_LENGTH; \ + else if (rx_status == htt_rx_status_mpdu_encrypt_required_err) \ + err_type = OL_RX_ERR_ENCRYPT_REQUIRED; \ + else if (rx_status == htt_rx_status_err_dup) \ + err_type = OL_RX_ERR_DUP; \ + else if (rx_status == htt_rx_status_err_fcs) \ + err_type = OL_RX_ERR_FCS; \ + else \ + err_type = OL_RX_ERR_UNKNOWN; \ + \ + if (vdev && peer) { \ + OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, \ + rx_mpdu_desc, err_type); \ + } else { \ + OL_RX_ERR_INV_PEER_STATISTICS(pdev, rx_msdu); \ + } \ + } while (false) +#else +#define OL_RX_ERR_STATISTICS(pdev, vdev, err_type, sec_type, is_mcast) +#define OL_RX_ERR_STATISTICS_1(pdev, vdev, peer, rx_desc, err_type) +#define OL_RX_ERR_STATISTICS_2(pdev, vdev, peer, rx_desc, rx_msdu, rx_status) +#endif /* SUPPORT_HOST_STATISTICS */ + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS +#define OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, type, msdu) \ + do { \ + qdf_spin_lock_bh(&peer->vdev->pdev->peer_stat_mutex); \ + peer->stats.tx_or_rx.frms.type += 1; \ + peer->stats.tx_or_rx.bytes.type += qdf_nbuf_len(msdu); \ + qdf_spin_unlock_bh(&peer->vdev->pdev->peer_stat_mutex); \ + } while (0) +#define OL_TXRX_PEER_STATS_UPDATE(peer, tx_or_rx, msdu) \ + do { \ + struct ol_txrx_vdev_t *vdev = peer->vdev; \ + struct ol_txrx_pdev_t *pdev = vdev->pdev; \ + uint8_t *dest_addr; \ + if (pdev->frame_format == wlan_frm_fmt_802_3) { \ + dest_addr = qdf_nbuf_data(msdu); \ + } else { /* 802.11 format */ \ + struct ieee80211_frame *frm; \ + frm = (struct ieee80211_frame *) qdf_nbuf_data(msdu); \ + if (vdev->opmode == wlan_op_mode_ap) { \ + dest_addr = (uint8_t *) &(frm->i_addr1[0]); \ + } else { \ + dest_addr = (uint8_t *) &(frm->i_addr3[0]); \ + } \ + } \ + if (qdf_unlikely(QDF_IS_ADDR_BROADCAST(dest_addr))) { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + bcast, msdu); \ + } else if (qdf_unlikely(IEEE80211_IS_MULTICAST(dest_addr))) { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + mcast, msdu); \ + } else { \ + OL_TXRX_PEER_STATS_UPDATE_BASE(peer, tx_or_rx, \ + ucast, msdu); \ + } \ + } while (0) +#define OL_TX_PEER_STATS_UPDATE(peer, msdu) \ + OL_TXRX_PEER_STATS_UPDATE(peer, tx, msdu) +#define OL_RX_PEER_STATS_UPDATE(peer, msdu) \ + OL_TXRX_PEER_STATS_UPDATE(peer, rx, msdu) +#define OL_TXRX_PEER_STATS_MUTEX_INIT(pdev) \ + qdf_spinlock_create(&pdev->peer_stat_mutex) +#define OL_TXRX_PEER_STATS_MUTEX_DESTROY(pdev) \ + qdf_spinlock_destroy(&pdev->peer_stat_mutex) +#else +#define OL_TX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ +#define OL_RX_PEER_STATS_UPDATE(peer, msdu) /* no-op */ +#define OL_TXRX_PEER_STATS_MUTEX_INIT(peer) /* no-op */ +#define OL_TXRX_PEER_STATS_MUTEX_DESTROY(peer) /* no-op */ +#endif + +#ifndef DEBUG_HTT_CREDIT +#define DEBUG_HTT_CREDIT 0 +#endif + +#if defined(FEATURE_TSO_DEBUG) +#define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) \ + do { \ + if (_p_cntrs == 1) { \ + TXRX_STATS_ADD(_pdev, pub.tx.tso.tso_hist.pkts_1, 1); \ + } else if (_p_cntrs >= 2 && _p_cntrs <= 5) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_2_5, 1); \ + } else if (_p_cntrs > 5 && _p_cntrs <= 10) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_6_10, 1); \ + } else if (_p_cntrs > 10 && _p_cntrs <= 15) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_11_15, 1); \ + } else if (_p_cntrs > 15 && _p_cntrs <= 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_16_20, 1); \ + } else if (_p_cntrs > 20) { \ + TXRX_STATS_ADD(_pdev, \ + pub.tx.tso.tso_hist.pkts_20_plus, 1); \ + } \ + } while (0) + +#define TXRX_STATS_TSO_RESET_MSDU(pdev, idx) \ + do { \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg \ + = 0; \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].tso_seg_idx \ + = 0; \ + } while (0) + +#define TXRX_STATS_TSO_MSDU_IDX(pdev) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_idx + +#define TXRX_STATS_TSO_MSDU(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx] + +#define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].num_seg + +#define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].gso_size + +#define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].total_len + +#define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) \ + pdev->stats.pub.tx.tso.tso_info.tso_msdu_info[idx].nr_frags + +#define TXRX_STATS_TSO_CURR_MSDU(pdev, idx) \ + TXRX_STATS_TSO_MSDU(pdev, idx) + +#define TXRX_STATS_TSO_SEG_IDX(pdev, idx) \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).tso_seg_idx + +#define TXRX_STATS_TSO_INC_SEG(pdev, idx) \ + do { \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg++; \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg &= \ + NUM_MAX_TSO_SEGS_MASK; \ + } while (0) + +#define TXRX_STATS_TSO_RST_SEG(pdev, idx) \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).num_seg = 0 + +#define TXRX_STATS_TSO_RST_SEG_IDX(pdev, idx) \ + TXRX_STATS_TSO_CURR_MSDU(pdev, idx).tso_seg_idx = 0 + +#define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) \ + TXRX_STATS_TSO_MSDU(pdev, msdu_idx).tso_segs[seg_idx] + +#define TXRX_STATS_TSO_CURR_SEG(pdev, idx) \ + TXRX_STATS_TSO_SEG(pdev, idx, \ + TXRX_STATS_TSO_SEG_IDX(pdev, idx)) \ + +#define TXRX_STATS_TSO_INC_SEG_IDX(pdev, idx) \ + do { \ + TXRX_STATS_TSO_SEG_IDX(pdev, idx)++; \ + TXRX_STATS_TSO_SEG_IDX(pdev, idx) &= NUM_MAX_TSO_SEGS_MASK; \ + } while (0) + +#define TXRX_STATS_TSO_SEG_UPDATE(pdev, idx, tso_seg) \ + (TXRX_STATS_TSO_CURR_SEG(pdev, idx) = tso_seg) + +#define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, idx, size) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).gso_size = size) + +#define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, idx, len) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).total_len = len) + +#define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, idx, frags) \ + (TXRX_STATS_TSO_CURR_MSDU(pdev, idx).nr_frags = frags) + +#else +#define TXRX_STATS_TSO_HISTOGRAM(_pdev, _p_cntrs) /* no-op */ +#define TXRX_STATS_TSO_RESET_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_NUM_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_CURR_MSDU(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_INC_MSDU_IDX(pdev) /* no-op */ +#define TXRX_STATS_TSO_SEG_IDX(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_SEG(pdev, msdu_idx, seg_idx) /* no-op */ +#define TXRX_STATS_TSO_CURR_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_INC_SEG_IDX(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_SEG_UPDATE(pdev, idx, tso_seg) /* no-op */ +#define TXRX_STATS_TSO_INC_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_RST_SEG(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_RST_SEG_IDX(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_GSO_SIZE_UPDATE(pdev, idx, size) /* no-op */ +#define TXRX_STATS_TSO_TOTAL_LEN_UPDATE(pdev, idx, len) /* no-op */ +#define TXRX_STATS_TSO_NUM_FRAGS_UPDATE(pdev, idx, frags) /* no-op */ +#define TXRX_STATS_TSO_MSDU_GSO_SIZE(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_TOTAL_LEN(pdev, idx) /* no-op */ +#define TXRX_STATS_TSO_MSDU_NR_FRAGS(pdev, idx) /* no-op */ + +#endif /* FEATURE_TSO_DEBUG */ + +#ifdef FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL + +void +ol_txrx_update_group_credit( + struct ol_tx_queue_group_t *group, + int32_t credit, + u_int8_t absolute); +#endif + +#endif /* _OL_TXRX_INTERNAL__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.c new file mode 100644 index 0000000000..710e08b565 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.c @@ -0,0 +1,1883 @@ +/* + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* qdf_mem_malloc,free */ +#include /* qdf_device_t, qdf_print */ +#include /* qdf_spinlock */ +#include /* qdf_atomic_read */ + +/* header files for utilities */ +#include "queue.h" /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_is_high_latency */ +#include + +/* header files for HTT API */ +#include +#include + +/* header files for our own APIs */ +#include +#include +#include +#include +#include +#include +/* header files for our internal definitions */ +#include /* TXRX_ASSERT, etc. */ +#include /* WDI events */ +#include /* ol_tx_ll */ +#include /* ol_rx_deliver */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include /* ol_rx_pn_check, etc. */ +#include /* ol_rx_fwd_check, etc. */ +#include /* OL_RX_REORDER_TIMEOUT_INIT, etc. */ +#include +#include /* ol_tx_discard_target_frms */ +#include /* ol_tx_desc_frame_free */ +#include +#include /* ol_tx_sched_attach, etc. */ +#include +#include +#include +#include +#include +#include +#include "wma.h" +#include "hif.h" +#include +#ifndef REMOVE_PKT_LOG +#include "pktlog_ac.h" +#endif +#include "epping_main.h" +#include + +#ifdef IPA_OFFLOAD +#include + +/* For Tx pipes, use Ethernet-II Header format */ +#ifdef QCA_WIFI_3_0 +struct ol_txrx_ipa_uc_tx_hdr ipa_uc_tx_hdr = { + { + 0x0000, + 0x00000000, + 0x00000000 + }, + { + 0x00000000 + }, + { + {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc}, + {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff}, + 0x0008 + } +}; +#else +struct ol_txrx_ipa_uc_tx_hdr ipa_uc_tx_hdr = { + { + 0x00000000, + 0x00000000 + }, + { + 0x00000000 + }, + { + {0x00, 0x03, 0x7f, 0xaa, 0xbb, 0xcc}, + {0x00, 0x03, 0x7f, 0xdd, 0xee, 0xff}, + 0x0008 + } +}; +#endif + +QDF_STATUS ol_txrx_ipa_uc_get_resource(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_ipa_resources *ipa_res; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + if (!osdev) + return QDF_STATUS_E_NOENT; + + ipa_res = &pdev->ipa_resource; + htt_ipa_uc_get_resource(pdev->htt_pdev, + &ipa_res->ce_sr, + &ipa_res->tx_comp_ring, + &ipa_res->rx_rdy_ring, + &ipa_res->rx2_rdy_ring, + &ipa_res->rx_proc_done_idx, + &ipa_res->rx2_proc_done_idx, + &ipa_res->ce_sr_ring_size, + &ipa_res->ce_reg_paddr, + &ipa_res->tx_num_alloc_buffer); + + if ((0 == qdf_mem_get_dma_addr(osdev, + &ipa_res->ce_sr->mem_info)) || + (0 == qdf_mem_get_dma_addr(osdev, + &ipa_res->tx_comp_ring->mem_info)) || + (0 == qdf_mem_get_dma_addr(osdev, + &ipa_res->rx_rdy_ring->mem_info)) +#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3) + || (0 == qdf_mem_get_dma_addr(osdev, + &ipa_res->rx2_rdy_ring->mem_info)) +#endif + ) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_set_doorbell_paddr(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_ipa_resources *ipa_res; + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + ipa_res = &pdev->ipa_resource; + ret = htt_ipa_uc_set_doorbell_paddr(pdev->htt_pdev, + ipa_res->tx_comp_doorbell_dmaaddr, + ipa_res->rx_ready_doorbell_dmaaddr); + + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "htt_ipa_uc_set_doorbell_dmaaddr fail: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_set_active(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + bool uc_active, bool is_tx) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + ret = htt_h2t_ipa_uc_set_active(pdev->htt_pdev, uc_active, is_tx); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "htt_h2t_ipa_uc_set_active fail: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_op_response(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint8_t *op_msg) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + if (pdev->ipa_uc_op_cb) { + pdev->ipa_uc_op_cb(op_msg, pdev->usr_ctxt); + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPA callback function is not registered", __func__); + qdf_mem_free(op_msg); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_register_op_cb(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + ipa_uc_op_cb_type op_cb, + void *usr_ctxt) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + pdev->ipa_uc_op_cb = op_cb; + pdev->usr_ctxt = usr_ctxt; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + ret = htt_h2t_ipa_uc_get_stats(pdev->htt_pdev); + + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "htt_h2t_ipa_uc_get_stats fail: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + /* TBD */ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id) +{ + /* TBD */ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS __ol_txrx_ipa_tx_buf_smmu_mapping(struct ol_txrx_pdev_t *pdev, + bool create) +{ + uint32_t index; + uint32_t unmap_cnt = 0; + uint32_t tx_buffer_cnt; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct htt_pdev_t *htt_pdev = pdev->htt_pdev; + qdf_mem_info_t *mem_map_table = NULL, *mem_info = NULL; + + if (!htt_pdev) { + ol_txrx_err("htt_pdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!qdf_mem_smmu_s1_enabled(htt_pdev->osdev)) { + ol_txrx_info("SMMU-S1 mapping is disabled"); + return QDF_STATUS_SUCCESS; + } + + tx_buffer_cnt = htt_pdev->ipa_uc_tx_rsc.alloc_tx_buf_cnt; + mem_map_table = qdf_mem_map_table_alloc(tx_buffer_cnt); + if (!mem_map_table) { + ol_txrx_err("Failed to allocate memory"); + return QDF_STATUS_E_FAILURE; + } + mem_info = mem_map_table; + + for (index = 0; index < tx_buffer_cnt; index++) { + if (htt_pdev->ipa_uc_tx_rsc.tx_buf_pool_strg[index]) { + *mem_info = htt_pdev->ipa_uc_tx_rsc. + tx_buf_pool_strg[index]->mem_info; + mem_info++; + unmap_cnt++; + } + } + + ret = cds_smmu_map_unmap(create, unmap_cnt, mem_map_table); + qdf_assert_always(!ret); + qdf_mem_free(mem_map_table); + htt_pdev->ipa_uc_tx_rsc.ipa_smmu_mapped = create; + ol_txrx_info("smmu_map_unmap:%d of %d Tx buffers", create, unmap_cnt); + + return ret; +} + +QDF_STATUS ol_txrx_ipa_tx_buf_smmu_mapping(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + const char *func, + uint32_t line) +{ + QDF_STATUS ret; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + if (!qdf_mem_smmu_s1_enabled(pdev->htt_pdev->osdev)) { + ol_txrx_err("SMMU S1 disabled"); + return QDF_STATUS_SUCCESS; + } + ret = __ol_txrx_ipa_tx_buf_smmu_mapping(pdev, true); + + return ret; +} + +QDF_STATUS ol_txrx_ipa_tx_buf_smmu_unmapping(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + const char *func, + uint32_t line) +{ + QDF_STATUS ret; + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + + if (!pdev) { + ol_txrx_err("invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + if (!qdf_mem_smmu_s1_enabled(pdev->htt_pdev->osdev)) { + ol_txrx_err("SMMU S1 disabled"); + return QDF_STATUS_SUCCESS; + } + ret = __ol_txrx_ipa_tx_buf_smmu_mapping(pdev, false); + + return ret; +} + +#ifdef CONFIG_IPA_WDI_UNIFIED_API + +#ifndef QCA_LL_TX_FLOW_CONTROL_V2 +static inline void ol_txrx_setup_mcc_sys_pipes( + qdf_ipa_sys_connect_params_t *sys_in, + qdf_ipa_wdi_conn_in_params_t *pipe_in) +{ + int i = 0; + + /* Setup MCC sys pipe */ + QDF_IPA_WDI_CONN_IN_PARAMS_NUM_SYS_PIPE_NEEDED(pipe_in) = + OL_TXRX_IPA_MAX_IFACE; + for (i = 0; i < OL_TXRX_IPA_MAX_IFACE; i++) + memcpy(&QDF_IPA_WDI_CONN_IN_PARAMS_SYS_IN(pipe_in)[i], + &sys_in[i], sizeof(qdf_ipa_sys_connect_params_t)); +} +#else +static inline void ol_txrx_setup_mcc_sys_pipes( + qdf_ipa_sys_connect_params_t *sys_in, + qdf_ipa_wdi_conn_in_params_t *pipe_in) +{ + QDF_IPA_WDI_CONN_IN_PARAMS_NUM_SYS_PIPE_NEEDED(pipe_in) = 0; +} +#endif + +#ifdef ENABLE_SMMU_S1_TRANSLATION +#ifdef QCA_WIFI_3_0 +/** + * ol_txrx_ipa_wdi_tx_smmu_params() - Config IPA TX params + * @ipa_res: IPA resources + * @tx_smmu: IPA WDI pipe setup info + * + * Return: None + */ +static inline void ol_txrx_ipa_wdi_tx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_smmu_t *tx_smmu, + bool over_gsi) +{ + QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(tx_smmu) = + QDF_IPA_CLIENT_WLAN_WDI2_CONS; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_BASE( + tx_smmu), + &ipa_res->tx_comp_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_SIZE(tx_smmu) = + ipa_res->tx_comp_ring->mem_info.size; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_BASE( + tx_smmu), + &ipa_res->ce_sr->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_SIZE(tx_smmu) = + ipa_res->ce_sr_ring_size; + QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_DOORBELL_PA(tx_smmu) = + ipa_res->ce_reg_paddr; + if (over_gsi) + QDF_IPA_WDI_SETUP_INFO_SMMU_IS_EVT_RN_DB_PCIE_ADDR(tx_smmu) = true; + QDF_IPA_WDI_SETUP_INFO_SMMU_NUM_PKT_BUFFERS(tx_smmu) = + ipa_res->tx_num_alloc_buffer; + QDF_IPA_WDI_SETUP_INFO_SMMU_PKT_OFFSET(tx_smmu) = 0; +} + +/** + * ol_txrx_ipa_wdi_rx_smmu_params() - Config IPA RX params + * @ipa_res: IPA resources + * @rx_smmu: IPA WDI pipe setup info + * + * Return: None + */ +static inline void ol_txrx_ipa_wdi_rx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu, + bool over_gsi) +{ + QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) = + QDF_IPA_CLIENT_WLAN_WDI2_PROD; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_BASE( + rx_smmu), + &ipa_res->rx_rdy_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_SIZE(rx_smmu) = + ipa_res->rx_rdy_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_DOORBELL_PA(rx_smmu) = + ipa_res->rx_proc_done_idx->mem_info.pa; + if (over_gsi) + QDF_IPA_WDI_SETUP_INFO_SMMU_IS_TXR_RN_DB_PCIE_ADDR(rx_smmu) = false; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_BASE( + rx_smmu), + &ipa_res->rx2_rdy_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_SIZE(rx_smmu) = + ipa_res->rx2_rdy_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_DOORBELL_PA(rx_smmu) = + ipa_res->rx2_proc_done_idx->mem_info.pa; + if (over_gsi) + QDF_IPA_WDI_SETUP_INFO_SMMU_IS_EVT_RN_DB_PCIE_ADDR(rx_smmu) = false; + QDF_IPA_WDI_SETUP_INFO_SMMU_PKT_OFFSET(rx_smmu) = 0; + +} +#else + +static inline void ol_txrx_ipa_wdi_tx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_smmu_t *tx_smmu, + bool over_gsi) +{ + QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(tx_smmu) = + QDF_IPA_CLIENT_WLAN_LEGACY_CONS; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_BASE( + tx_smmu), + &ipa_res->tx_comp_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_SIZE(tx_smmu) = + ipa_res->tx_comp_ring->mem_info.size; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_BASE( + tx_smmu), + &ipa_res->ce_sr->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_SIZE(tx_smmu) = + ipa_res->ce_sr_ring_size; + QDF_IPA_WDI_SETUP_INFO_SMMU_EVENT_RING_DOORBELL_PA(tx_smmu) = + ipa_res->ce_reg_paddr; + QDF_IPA_WDI_SETUP_INFO_SMMU_NUM_PKT_BUFFERS(tx_smmu) = + ipa_res->tx_num_alloc_buffer; + QDF_IPA_WDI_SETUP_INFO_SMMU_PKT_OFFSET(tx_smmu) = 0; +} + +static inline void ol_txrx_ipa_wdi_rx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu, + bool over_gsi) +{ + QDF_IPA_WDI_SETUP_INFO_SMMU_CLIENT(rx_smmu) = + QDF_IPA_CLIENT_WLAN_LEGACY_PROD; + qdf_mem_copy(&QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_BASE( + rx_smmu), + &ipa_res->rx_rdy_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_SIZE(rx_smmu) = + ipa_res->rx_rdy_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_SMMU_TRANSFER_RING_DOORBELL_PA(rx_smmu) = + ipa_res->rx_proc_done_idx->mem_info.pa; + QDF_IPA_WDI_SETUP_INFO_SMMU_PKT_OFFSET(rx_smmu) = 0; +} + +#endif + +#else + +static inline void ol_txrx_ipa_wdi_tx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_smmu_t *tx_smmu, + bool over_gsi) +{ +} + +static inline void ol_txrx_ipa_wdi_rx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu, + bool over_gsi) +{ +} +#endif + +#ifdef QCA_WIFI_3_0 +/** + * ol_txrx_ipa_wdi_tx_params() - Config IPA TX params + * @ipa_res: IPA resources + * @tx: IPA WDI pipe setup info + * + * Return: None + */ +static inline void ol_txrx_ipa_wdi_tx_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_t *tx, + bool over_gsi) +{ + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!osdev) + return; + + QDF_IPA_WDI_SETUP_INFO_CLIENT(tx) = IPA_CLIENT_WLAN1_CONS; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(tx) = + qdf_mem_get_dma_addr(osdev, + &ipa_res->tx_comp_ring->mem_info); + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(tx) = + ipa_res->tx_comp_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_BASE_PA(tx) = + qdf_mem_get_dma_addr(osdev, + &ipa_res->ce_sr->mem_info); + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_SIZE(tx) = + ipa_res->ce_sr_ring_size; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_DOORBELL_PA(tx) = + ipa_res->ce_reg_paddr; + if (over_gsi) + QDF_IPA_WDI_SETUP_INFO_IS_EVT_RN_DB_PCIE_ADDR(tx) = true; + QDF_IPA_WDI_SETUP_INFO_NUM_PKT_BUFFERS(tx) = + ipa_res->tx_num_alloc_buffer; + QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(tx) = 0; +} + +/** + * ol_txrx_ipa_wdi_rx_params() - Config IPA RX params + * @ipa_res: IPA resources + * @rx: IPA WDI pipe setup info + * + * Return: None + */ +static inline void ol_txrx_ipa_wdi_rx_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_t *rx, + bool over_gsi) +{ + QDF_IPA_WDI_SETUP_INFO_CLIENT(rx) = IPA_CLIENT_WLAN1_PROD; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(rx) = + ipa_res->rx_rdy_ring->mem_info.pa; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(rx) = + ipa_res->rx_rdy_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_DOORBELL_PA(rx) = + ipa_res->rx_proc_done_idx->mem_info.pa; + if (over_gsi) + QDF_IPA_WDI_SETUP_INFO_IS_TXR_RN_DB_PCIE_ADDR(rx) = false; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_BASE_PA(rx) = + ipa_res->rx2_rdy_ring->mem_info.pa; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_SIZE(rx) = + ipa_res->rx2_rdy_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_DOORBELL_PA(rx) = + ipa_res->rx2_proc_done_idx->mem_info.pa; + if (over_gsi) + QDF_IPA_WDI_SETUP_INFO_IS_EVT_RN_DB_PCIE_ADDR(rx) = false; + QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(rx) = 0; +} + +#else +static inline void ol_txrx_ipa_wdi_tx_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_t *tx, + bool over_gsi) +{ + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!osdev) + return; + + QDF_IPA_WDI_SETUP_INFO_CLIENT(tx) = QDF_IPA_CLIENT_WLAN_LEGACY_CONS; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(tx) = + qdf_mem_get_dma_addr(osdev, + &ipa_res->tx_comp_ring->mem_info); + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(tx) = + ipa_res->tx_comp_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_BASE_PA(tx) = + qdf_mem_get_dma_addr(osdev, + &ipa_res->ce_sr->mem_info); + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_SIZE(tx) = + ipa_res->ce_sr_ring_size; + QDF_IPA_WDI_SETUP_INFO_EVENT_RING_DOORBELL_PA(tx) = + ipa_res->ce_reg_paddr; + QDF_IPA_WDI_SETUP_INFO_NUM_PKT_BUFFERS(tx) = + ipa_res->tx_num_alloc_buffer; + QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(tx) = 0; +} + +static inline void ol_txrx_ipa_wdi_rx_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_pipe_setup_info_t *rx, + bool over_gsi) +{ + QDF_IPA_WDI_SETUP_INFO_CLIENT(rx) = QDF_IPA_CLIENT_WLAN_LEGACY_PROD; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_BASE_PA(rx) = + ipa_res->rx_rdy_ring->mem_info.pa; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_SIZE(rx) = + ipa_res->rx_rdy_ring->mem_info.size; + QDF_IPA_WDI_SETUP_INFO_TRANSFER_RING_DOORBELL_PA(rx) = + ipa_res->rx_proc_done_idx->mem_info.pa; + QDF_IPA_WDI_SETUP_INFO_PKT_OFFSET(rx) = 0; +} + +#endif + +QDF_STATUS ol_txrx_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + void *ipa_i2w_cb, void *ipa_w2i_cb, + void *ipa_wdi_meter_notifier_cb, + uint32_t ipa_desc_size, void *ipa_priv, + bool is_rm_enabled, uint32_t *p_tx_pipe_handle, + uint32_t *p_rx_pipe_handle, bool is_smmu_enabled, + qdf_ipa_sys_connect_params_t *sys_in, + bool over_gsi, + qdf_ipa_wdi_hdl_t hdl, + qdf_ipa_wdi_hdl_t id, + void *ipa_ast_notify_cb) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_ipa_resources *ipa_res; + qdf_ipa_ep_cfg_t *tx_cfg; + qdf_ipa_ep_cfg_t *rx_cfg; + qdf_ipa_wdi_pipe_setup_info_t *tx; + qdf_ipa_wdi_pipe_setup_info_t *rx; + qdf_ipa_wdi_pipe_setup_info_smmu_t *tx_smmu; + qdf_ipa_wdi_pipe_setup_info_smmu_t *rx_smmu; + qdf_ipa_wdi_conn_in_params_t *pipe_in = NULL; + qdf_ipa_wdi_conn_out_params_t pipe_out; + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + uint32_t tx_comp_db_dmaaddr = 0, rx_rdy_db_dmaaddr = 0; + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + if (!osdev) + return QDF_STATUS_E_NOENT; + + pipe_in = qdf_mem_malloc(sizeof(*pipe_in)); + if (!pipe_in) + return QDF_STATUS_E_NOMEM; + + ipa_res = &pdev->ipa_resource; + qdf_mem_zero(pipe_in, sizeof(*pipe_in)); + qdf_mem_zero(&pipe_out, sizeof(pipe_out)); + + ol_txrx_setup_mcc_sys_pipes(sys_in, pipe_in); + + /* TX PIPE */ + if (is_smmu_enabled) { + QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(pipe_in) = true; + tx_smmu = &QDF_IPA_WDI_CONN_IN_PARAMS_TX_SMMU(pipe_in); + tx_cfg = &QDF_IPA_WDI_SETUP_INFO_SMMU_EP_CFG(tx_smmu); + } else { + QDF_IPA_WDI_CONN_IN_PARAMS_SMMU_ENABLED(pipe_in) = false; + tx = &QDF_IPA_WDI_CONN_IN_PARAMS_TX(pipe_in); + tx_cfg = &QDF_IPA_WDI_SETUP_INFO_EP_CFG(tx); + } + + QDF_IPA_EP_CFG_NAT_EN(tx_cfg) = IPA_BYPASS_NAT; + QDF_IPA_EP_CFG_HDR_LEN(tx_cfg) = OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN; + QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE_VALID(tx_cfg) = 1; + QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE(tx_cfg) = 0; + QDF_IPA_EP_CFG_HDR_ADDITIONAL_CONST_LEN(tx_cfg) = + OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE; + QDF_IPA_EP_CFG_MODE(tx_cfg) = IPA_BASIC; + QDF_IPA_EP_CFG_HDR_LITTLE_ENDIAN(tx_cfg) = true; + + if (is_smmu_enabled) + ol_txrx_ipa_wdi_tx_smmu_params(ipa_res, tx_smmu, over_gsi); + else + ol_txrx_ipa_wdi_tx_params(ipa_res, tx, over_gsi); + + + /* RX PIPE */ + if (is_smmu_enabled) { + rx_smmu = &QDF_IPA_WDI_CONN_IN_PARAMS_RX_SMMU(pipe_in); + rx_cfg = &QDF_IPA_WDI_SETUP_INFO_EP_CFG(rx_smmu); + } else { + rx = &QDF_IPA_WDI_CONN_IN_PARAMS_RX(pipe_in); + rx_cfg = &QDF_IPA_WDI_SETUP_INFO_EP_CFG(rx); + } + + QDF_IPA_EP_CFG_NAT_EN(rx_cfg) = IPA_BYPASS_NAT; + QDF_IPA_EP_CFG_HDR_LEN(rx_cfg) = OL_TXRX_IPA_UC_WLAN_RX_HDR_LEN; + QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE_VALID(rx_cfg) = 1; + QDF_IPA_EP_CFG_HDR_OFST_PKT_SIZE(rx_cfg) = 0; + QDF_IPA_EP_CFG_HDR_ADDITIONAL_CONST_LEN(rx_cfg) = + OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE; + QDF_IPA_EP_CFG_HDR_OFST_METADATA_VALID(rx_cfg) = 0; + QDF_IPA_EP_CFG_HDR_METADATA_REG_VALID(rx_cfg) = 1; + QDF_IPA_EP_CFG_MODE(rx_cfg) = IPA_BASIC; + QDF_IPA_EP_CFG_HDR_LITTLE_ENDIAN(rx_cfg) = true; + + if (is_smmu_enabled) + ol_txrx_ipa_wdi_rx_smmu_params(ipa_res, rx_smmu, over_gsi); + else + ol_txrx_ipa_wdi_rx_params(ipa_res, rx, over_gsi); + + QDF_IPA_WDI_CONN_IN_PARAMS_NOTIFY(pipe_in) = ipa_w2i_cb; + QDF_IPA_WDI_CONN_IN_PARAMS_PRIV(pipe_in) = ipa_priv; + + /* Connect WDI IPA PIPE */ + ret = qdf_ipa_wdi_conn_pipes(pipe_in, &pipe_out); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: ipa_wdi_conn_pipes: IPA pipe setup failed: ret=%d", + __func__, ret); + qdf_mem_free(pipe_in); + return QDF_STATUS_E_FAILURE; + } + + /* IPA uC Doorbell registers */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Tx DB PA=0x%x, Rx DB PA=0x%x", __func__, + (unsigned int) + QDF_IPA_WDI_CONN_OUT_PARAMS_TX_UC_DB_PA(&pipe_out), + (unsigned int) + QDF_IPA_WDI_CONN_OUT_PARAMS_RX_UC_DB_PA(&pipe_out)); + + ipa_res->tx_comp_doorbell_dmaaddr = + QDF_IPA_WDI_CONN_OUT_PARAMS_TX_UC_DB_PA(&pipe_out); + ipa_res->rx_ready_doorbell_dmaaddr = + QDF_IPA_WDI_CONN_OUT_PARAMS_RX_UC_DB_PA(&pipe_out); + + if (is_smmu_enabled) { + pld_smmu_map(osdev->dev, ipa_res->tx_comp_doorbell_dmaaddr, + &tx_comp_db_dmaaddr, sizeof(uint32_t)); + ipa_res->tx_comp_doorbell_dmaaddr = tx_comp_db_dmaaddr; + + pld_smmu_map(osdev->dev, ipa_res->rx_ready_doorbell_dmaaddr, + &rx_rdy_db_dmaaddr, sizeof(uint32_t)); + ipa_res->rx_ready_doorbell_dmaaddr = rx_rdy_db_dmaaddr; + } + + qdf_mem_free(pipe_in); + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_cleanup() - Disconnect IPA pipes + * @soc_hdl: soc handle + * @pdev_id: pdev id + * @tx_pipe_handle: Tx pipe handle + * @rx_pipe_handle: Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint32_t tx_pipe_handle, + uint32_t rx_pipe_handle, + qdf_ipa_wdi_hdl_t hdl) +{ + int ret; + struct ol_txrx_ipa_resources *ipa_res; + struct ol_txrx_soc_t *soc = cds_get_context(QDF_MODULE_ID_SOC); + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + ol_txrx_pdev_handle pdev; + + if (!soc || !osdev) + return QDF_STATUS_E_FAILURE; + + pdev = ol_txrx_get_pdev_from_pdev_id(soc, OL_TXRX_PDEV_ID); + if (!pdev) { + ol_txrx_err("NULL pdev invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + ipa_res = &pdev->ipa_resource; + if (osdev->smmu_s1_enabled) { + ret = pld_smmu_unmap(osdev->dev, + ipa_res->rx_ready_doorbell_dmaaddr, + sizeof(uint32_t)); + if (ret) + ol_txrx_err("rx_ready, smmu unmap failed"); + + ret = pld_smmu_unmap(osdev->dev, + ipa_res->tx_comp_doorbell_dmaaddr, + sizeof(uint32_t)); + if (ret) + ol_txrx_err("tx_comp, smmu unmap failed"); + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disconnect IPA pipe", __func__); + ret = qdf_ipa_wdi_disconn_pipes(hdl); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_wdi_disconn_pipes failed: ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_setup_iface() - Setup IPA header and register interface + * @ifname: Interface name + * @mac_addr: Interface MAC address + * @prod_client: IPA prod client type + * @cons_client: IPA cons client type + * @session_id: Session ID + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr, + qdf_ipa_client_type_t prod_client, + qdf_ipa_client_type_t cons_client, + uint8_t session_id, bool is_ipv6_enabled, + qdf_ipa_wdi_hdl_t hdl) +{ + qdf_ipa_wdi_reg_intf_in_params_t in; + qdf_ipa_wdi_hdr_info_t hdr_info; + struct ol_txrx_ipa_uc_tx_hdr uc_tx_hdr; + struct ol_txrx_ipa_uc_tx_hdr uc_tx_hdr_v6; + int ret = -EINVAL; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Add Partial hdr: %s, "QDF_MAC_ADDR_FMT, + __func__, ifname, QDF_MAC_ADDR_REF(mac_addr)); + + qdf_mem_zero(&hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t)); + memcpy(&uc_tx_hdr, &ipa_uc_tx_hdr, OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN); + qdf_ether_addr_copy(uc_tx_hdr.eth.h_source, mac_addr); + uc_tx_hdr.ipa_hd.vdev_id = session_id; + + /* IPV4 header */ + uc_tx_hdr.eth.h_proto = qdf_htons(ETH_P_IP); + + QDF_IPA_WDI_HDR_INFO_HDR(&hdr_info) = (uint8_t *)&uc_tx_hdr; + QDF_IPA_WDI_HDR_INFO_HDR_LEN(&hdr_info) = + OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN; + QDF_IPA_WDI_HDR_INFO_HDR_TYPE(&hdr_info) = IPA_HDR_L2_ETHERNET_II; + QDF_IPA_WDI_HDR_INFO_DST_MAC_ADDR_OFFSET(&hdr_info) = + OL_TXRX_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + + QDF_IPA_WDI_REG_INTF_IN_PARAMS_NETDEV_NAME(&in) = ifname; + memcpy(&(QDF_IPA_WDI_REG_INTF_IN_PARAMS_HDR_INFO(&in)[IPA_IP_v4]), + &hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t)); + QDF_IPA_WDI_REG_INTF_IN_PARAMS_ALT_DST_PIPE(&in) = cons_client; + QDF_IPA_WDI_REG_INTF_IN_PARAMS_IS_META_DATA_VALID(&in) = 1; + QDF_IPA_WDI_REG_INTF_IN_PARAMS_META_DATA(&in) = + htonl(session_id << 16); + QDF_IPA_WDI_REG_INTF_IN_PARAMS_META_DATA_MASK(&in) = htonl(0x00FF0000); + + /* IPV6 header */ + if (is_ipv6_enabled) { + memcpy(&uc_tx_hdr_v6, &uc_tx_hdr, + OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN); + uc_tx_hdr_v6.eth.h_proto = qdf_htons(ETH_P_IPV6); + QDF_IPA_WDI_HDR_INFO_HDR(&hdr_info) = (uint8_t *)&uc_tx_hdr_v6; + memcpy(&(QDF_IPA_WDI_REG_INTF_IN_PARAMS_HDR_INFO(&in)[IPA_IP_v6]), + &hdr_info, sizeof(qdf_ipa_wdi_hdr_info_t)); + } + + ret = qdf_ipa_wdi_reg_intf(&in); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: ipa_wdi_reg_intf failed: ret=%d", __func__, ret); + } + + return ret; +} + +/** + * ol_txrx_ipa_cleanup_iface() - Cleanup IPA header and deregister interface + * @ifname: Interface name + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled, + qdf_ipa_wdi_hdl_t hdl) +{ + int ret; + + /* unregister the interface with IPA */ + ret = qdf_ipa_wdi_dereg_intf(ifname, hdl); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: ipa_wdi_dereg_intf failed: devname=%s, ret=%d", + __func__, ifname, ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + qdf_ipa_wdi_hdl_t hdl) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + QDF_STATUS status; + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + status = htt_rx_update_smmu_map(pdev->htt_pdev, true); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "IPA SMMU map failed status:%d", status); + return status; + } + + /* ACTIVATE TX PIPE */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Enable IPA pipes", __func__); + ret = qdf_ipa_wdi_enable_pipes(hdl); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: ipa_wdi_enable_pipes failed: ret=%d", + __func__, ret); + status = htt_rx_update_smmu_map(pdev->htt_pdev, false); + if (status != QDF_STATUS_SUCCESS) + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "IPA SMMU unmap failed"); + return QDF_STATUS_E_FAILURE; + } + + ol_txrx_ipa_uc_set_active(soc_hdl, pdev_id, true, true); + ol_txrx_ipa_uc_set_active(soc_hdl, pdev_id, true, false); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + qdf_ipa_wdi_hdl_t hdl) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disable IPA pipes", __func__); + ret = qdf_ipa_wdi_disable_pipes(hdl); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: ipa_wdi_disable_pipes failed: ret=%d", + __func__, ret); + } + + if (htt_rx_update_smmu_map(pdev->htt_pdev, false) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "IPA SMMU unmap failed"); + } + + return ret ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_set_perf_level() - Set IPA clock bandwidth based on data rates + * @client: Client type + * @max_supported_bw_mbps: Maximum bandwidth needed (in Mbps) + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_set_perf_level(int client, + uint32_t max_supported_bw_mbps, + qdf_ipa_wdi_hdl_t hdl) +{ + qdf_ipa_wdi_perf_profile_t profile; + int result; + + QDF_IPA_WDI_PERF_PROFILE_CLIENT(&profile) = client; + QDF_IPA_WDI_PERF_PROFILE_MAX_SUPPORTED_BW_MBPS(&profile) = + max_supported_bw_mbps; + result = qdf_ipa_wdi_set_perf_profile(hdl, &profile); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Set perf profile failed, code %d", result); + + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#else /* CONFIG_IPA_WDI_UNIFIED_API */ + +#ifdef ENABLE_SMMU_S1_TRANSLATION +/** + * ol_txrx_ipa_tx_smmu_params() - Config IPA TX params + * @ipa_res: IPA resources + * @pipe_in: IPA WDI TX pipe params + * + * Return: None + */ +static inline void ol_txrx_ipa_tx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_in_params_t *pipe_in) +{ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: SMMU Enabled", __func__); + + QDF_IPA_PIPE_IN_SMMU_ENABLED(pipe_in) = true; + qdf_mem_copy(&QDF_IPA_PIPE_IN_DL_SMMU_COMP_RING(pipe_in), + &ipa_res->tx_comp_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_PIPE_IN_DL_SMMU_COMP_RING_SIZE(pipe_in) = + ipa_res->tx_comp_ring->mem_info.size; + qdf_mem_copy(&QDF_IPA_PIPE_IN_DL_SMMU_CE_RING(pipe_in), + &ipa_res->ce_sr->sgtable, + sizeof(sgtable_t)); + QDF_IPA_PIPE_IN_DL_SMMU_CE_DOOR_BELL_PA(pipe_in) = + ipa_res->ce_reg_paddr; + QDF_IPA_PIPE_IN_DL_SMMU_CE_RING_SIZE(pipe_in) = + ipa_res->ce_sr_ring_size; + QDF_IPA_PIPE_IN_DL_SMMU_NUM_TX_BUFFERS(pipe_in) = + ipa_res->tx_num_alloc_buffer; +} + +/** + * ol_txrx_ipa_rx_smmu_params() - Config IPA TX params + * @ipa_res: IPA resources + * @pipe_in: IPA WDI TX pipe params + * + * Return: None + */ +static inline void ol_txrx_ipa_rx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_in_params_t *pipe_in) +{ + qdf_mem_copy(&QDF_IPA_PIPE_IN_UL_SMMU_RDY_RING(pipe_in), + &ipa_res->rx_rdy_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_PIPE_IN_UL_SMMU_RDY_RING_SIZE(pipe_in) = + ipa_res->rx_rdy_ring->mem_info.size; + QDF_IPA_PIPE_IN_UL_SMMU_RDY_RING_RP_PA(pipe_in) = + ipa_res->rx_proc_done_idx->mem_info.pa; + + QDF_IPA_PIPE_IN_UL_SMMU_RDY_RING_RP_VA(pipe_in) = + ipa_res->rx_proc_done_idx->vaddr; + qdf_mem_copy(&QDF_IPA_PIPE_IN_UL_SMMU_RDY_COMP_RING(pipe_in), + &ipa_res->rx2_rdy_ring->sgtable, + sizeof(sgtable_t)); + QDF_IPA_PIPE_IN_UL_SMMU_RDY_COMP_RING_SIZE(pipe_in) = + ipa_res->rx2_rdy_ring->mem_info.size; + QDF_IPA_PIPE_IN_UL_SMMU_RDY_COMP_RING_WP_PA(pipe_in) = + ipa_res->rx2_proc_done_idx->mem_info.pa; + QDF_IPA_PIPE_IN_UL_SMMU_RDY_COMP_RING_WP_VA(pipe_in) = + ipa_res->rx2_proc_done_idx->vaddr; +} +#else +static inline void ol_txrx_ipa_tx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_in_params_t *pipe_in) +{ +} + +static inline void ol_txrx_ipa_rx_smmu_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_in_params_t *pipe_in) +{ +} +#endif + +/** + * ol_txrx_ipa_tx_params() - Config IPA TX params + * @ipa_res: IPA resources + * @pipe_in: IPA WDI TX pipe params + * + * Return: None + */ +static inline void ol_txrx_ipa_tx_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_in_params_t *pipe_in) +{ + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!osdev) + return; + + QDF_IPA_PIPE_IN_DL_COMP_RING_BASE_PA(pipe_in) = + qdf_mem_get_dma_addr(osdev, + &ipa_res->tx_comp_ring->mem_info); + QDF_IPA_PIPE_IN_DL_COMP_RING_SIZE(pipe_in) = + ipa_res->tx_comp_ring->mem_info.size; + QDF_IPA_PIPE_IN_DL_CE_RING_BASE_PA(pipe_in) = + qdf_mem_get_dma_addr(osdev, + &ipa_res->ce_sr->mem_info); + QDF_IPA_PIPE_IN_DL_CE_DOOR_BELL_PA(pipe_in) = + ipa_res->ce_reg_paddr; + QDF_IPA_PIPE_IN_DL_CE_RING_SIZE(pipe_in) = + ipa_res->ce_sr_ring_size; + QDF_IPA_PIPE_IN_DL_NUM_TX_BUFFERS(pipe_in) = + ipa_res->tx_num_alloc_buffer; +} + +/** + * ol_txrx_ipa_rx_params() - Config IPA RX params + * @ipa_res: IPA resources + * @pipe_in: IPA WDI RX pipe params + * + * Return: None + */ +static inline void ol_txrx_ipa_rx_params( + struct ol_txrx_ipa_resources *ipa_res, + qdf_ipa_wdi_in_params_t *pipe_in) +{ + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!osdev) + return; + + QDF_IPA_PIPE_IN_UL_RDY_RING_BASE_PA(pipe_in) = + ipa_res->rx_rdy_ring->mem_info.pa; + QDF_IPA_PIPE_IN_UL_RDY_RING_SIZE(pipe_in) = + ipa_res->rx_rdy_ring->mem_info.size; + QDF_IPA_PIPE_IN_UL_RDY_RING_RP_PA(pipe_in) = + ipa_res->rx_proc_done_idx->mem_info.pa; + OL_TXRX_IPA_WDI2_SET(pipe_in, ipa_res, + osdev); +} + +QDF_STATUS ol_txrx_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + void *ipa_i2w_cb, void *ipa_w2i_cb, + void *ipa_wdi_meter_notifier_cb, + uint32_t ipa_desc_size, void *ipa_priv, + bool is_rm_enabled, uint32_t *p_tx_pipe_handle, + uint32_t *p_rx_pipe_handle) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + qdf_device_t osdev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct ol_txrx_ipa_resources *ipa_res; + qdf_ipa_wdi_in_params_t pipe_in; + qdf_ipa_wdi_out_params_t pipe_out; + uint32_t tx_comp_db_dmaaddr = 0, rx_rdy_db_dmaaddr = 0; + int ret; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + if (!osdev) + return QDF_STATUS_E_NOENT; + + ipa_res = &pdev->ipa_resource; + qdf_mem_zero(&pipe_in, sizeof(pipe_in)); + qdf_mem_zero(&pipe_out, sizeof(pipe_out)); + + /* TX PIPE */ + QDF_IPA_PIPE_IN_NAT_EN(&pipe_in) = IPA_BYPASS_NAT; + QDF_IPA_PIPE_IN_HDR_LEN(&pipe_in) = OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN; + QDF_IPA_PIPE_IN_HDR_OFST_PKT_SIZE_VALID(&pipe_in) = 1; + QDF_IPA_PIPE_IN_HDR_OFST_PKT_SIZE(&pipe_in) = 0; + QDF_IPA_PIPE_IN_HDR_ADDITIONAL_CONST_LEN(&pipe_in) = + OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE; + QDF_IPA_PIPE_IN_MODE(&pipe_in) = IPA_BASIC; + QDF_IPA_PIPE_IN_CLIENT(&pipe_in) = IPA_CLIENT_WLAN1_CONS; + QDF_IPA_PIPE_IN_DESC_FIFO_SZ(&pipe_in) = ipa_desc_size; + QDF_IPA_PIPE_IN_PRIV(&pipe_in) = ipa_priv; + QDF_IPA_PIPE_IN_HDR_LITTLE_ENDIAN(&pipe_in) = true; + QDF_IPA_PIPE_IN_NOTIFY(&pipe_in) = ipa_i2w_cb; + + if (!is_rm_enabled) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + QDF_IPA_PIPE_IN_KEEP_IPA_AWAKE(&pipe_in) = true; + } + + if (qdf_mem_smmu_s1_enabled(osdev)) + ol_txrx_ipa_tx_smmu_params(ipa_res, &pipe_in); + else + ol_txrx_ipa_tx_params(ipa_res, &pipe_in); + + /* Connect WDI IPA PIPE */ + ret = qdf_ipa_connect_wdi_pipe(&pipe_in, &pipe_out); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe: Tx pipe setup failed: ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + + /* Micro Controller Doorbell register */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s CONS DB pipe out 0x%x TX PIPE Handle 0x%x", __func__, + (unsigned int)QDF_IPA_PIPE_OUT_UC_DOOR_BELL_PA(&pipe_out), + pipe_out.clnt_hdl); + ipa_res->tx_comp_doorbell_dmaaddr = + QDF_IPA_PIPE_OUT_UC_DOOR_BELL_PA(&pipe_out); + /* WLAN TX PIPE Handle */ + ipa_res->tx_pipe_handle = QDF_IPA_PIPE_OUT_CLNT_HDL(&pipe_out); + *p_tx_pipe_handle = QDF_IPA_PIPE_OUT_CLNT_HDL(&pipe_out); + + /* RX PIPE */ + QDF_IPA_PIPE_IN_NAT_EN(&pipe_in) = IPA_BYPASS_NAT; + QDF_IPA_PIPE_IN_HDR_LEN(&pipe_in) = OL_TXRX_IPA_UC_WLAN_RX_HDR_LEN; + QDF_IPA_PIPE_IN_HDR_OFST_METADATA_VALID(&pipe_in) = 0; + QDF_IPA_PIPE_IN_HDR_METADATA_REG_VALID(&pipe_in) = 1; + QDF_IPA_PIPE_IN_MODE(&pipe_in) = IPA_BASIC; + QDF_IPA_PIPE_IN_CLIENT(&pipe_in) = IPA_CLIENT_WLAN1_PROD; + QDF_IPA_PIPE_IN_DESC_FIFO_SZ(&pipe_in) = + ipa_desc_size + SPS_DESC_SIZE; + QDF_IPA_PIPE_IN_NOTIFY(&pipe_in) = ipa_w2i_cb; + if (!is_rm_enabled) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPA RM DISABLED, IPA AWAKE", __func__); + QDF_IPA_PIPE_IN_KEEP_IPA_AWAKE(&pipe_in) = true; + } + + if (qdf_mem_smmu_s1_enabled(osdev)) + ol_txrx_ipa_rx_smmu_params(ipa_res, &pipe_in); + else + ol_txrx_ipa_rx_params(ipa_res, &pipe_in); + +#ifdef FEATURE_METERING + QDF_IPA_PIPE_IN_WDI_NOTIFY(&pipe_in) = ipa_wdi_meter_notifier_cb; +#endif + + ret = qdf_ipa_connect_wdi_pipe(&pipe_in, &pipe_out); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_connect_wdi_pipe: Rx pipe setup failed: ret=%d", ret); + return QDF_STATUS_E_FAILURE; + } + ipa_res->rx_ready_doorbell_dmaaddr = + QDF_IPA_PIPE_OUT_UC_DOOR_BELL_PA(&pipe_out); + ipa_res->rx_pipe_handle = QDF_IPA_PIPE_OUT_CLNT_HDL(&pipe_out); + *p_rx_pipe_handle = QDF_IPA_PIPE_OUT_CLNT_HDL(&pipe_out); + + if (qdf_mem_smmu_s1_enabled(osdev)) { + pld_smmu_map(osdev->dev, ipa_res->tx_comp_doorbell_dmaaddr, + &tx_comp_db_dmaaddr, sizeof(uint32_t)); + ipa_res->tx_comp_doorbell_dmaaddr = tx_comp_db_dmaaddr; + + pld_smmu_map(osdev->dev, ipa_res->rx_ready_doorbell_dmaaddr, + &rx_rdy_db_dmaaddr, sizeof(uint32_t)); + ipa_res->rx_ready_doorbell_dmaaddr = rx_rdy_db_dmaaddr; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_cleanup() - Disconnect IPA pipes + * @soc_hdl: soc handle + * @pdev_id: pdev id + * @tx_pipe_handle: Tx pipe handle + * @rx_pipe_handle: Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint32_t tx_pipe_handle, + uint32_t rx_pipe_handle) +{ + int ret; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disconnect TX PIPE tx_pipe_handle=0x%x", + __func__, tx_pipe_handle); + ret = qdf_ipa_disconnect_wdi_pipe(tx_pipe_handle); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_disconnect_wdi_pipe: Tx pipe cleanup failed: ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disconnect RX PIPE rx_pipe_handle=0x%x", + __func__, rx_pipe_handle); + ret = qdf_ipa_disconnect_wdi_pipe(rx_pipe_handle); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "ipa_disconnect_wdi_pipe: Rx pipe cleanup failed: ret=%d", + ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_remove_ipa_header() - Remove a specific header from IPA + * @name: Name of the header to be removed + * + * Return: QDF_STATUS + */ +static QDF_STATUS ol_txrx_ipa_remove_header(char *name) +{ + qdf_ipa_ioc_get_hdr_t hdrlookup; + int ret = 0, len; + qdf_ipa_ioc_del_hdr_t *ipa_hdr; + + qdf_mem_zero(&hdrlookup, sizeof(hdrlookup)); + strlcpy(hdrlookup.name, name, sizeof(hdrlookup.name)); + ret = qdf_ipa_get_hdr(&hdrlookup); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "Hdr deleted already %s, %d", name, ret); + return QDF_STATUS_E_FAILURE; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, "hdl: 0x%x", + hdrlookup.hdl); + len = sizeof(qdf_ipa_ioc_del_hdr_t) + sizeof(qdf_ipa_hdr_del_t) * 1; + ipa_hdr = (qdf_ipa_ioc_del_hdr_t *)qdf_mem_malloc(len); + if (!ipa_hdr) + return QDF_STATUS_E_FAILURE; + + QDF_IPA_IOC_DEL_HDR_NUM_HDRS(ipa_hdr) = 1; + QDF_IPA_IOC_DEL_HDR_COMMIT(ipa_hdr) = 0; + QDF_IPA_IOC_DEL_HDR_HDL(ipa_hdr) = QDF_IPA_IOC_GET_HDR_HDL(&hdrlookup); + QDF_IPA_IOC_DEL_HDR_STATUS(ipa_hdr) = -1; + ret = qdf_ipa_del_hdr(ipa_hdr); + if (ret != 0) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Delete header failed: %d", ret); + qdf_mem_free(ipa_hdr); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_free(ipa_hdr); + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_add_header_info() - Add IPA header for a given interface + * @ifname: Interface name + * @mac_addr: Interface MAC address + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: 0 on success, negativer errno value on error + */ +static int ol_txrx_ipa_add_header_info(char *ifname, uint8_t *mac_addr, + uint8_t session_id, bool is_ipv6_enabled) +{ + qdf_ipa_ioc_add_hdr_t *ipa_hdr = NULL; + int ret = -EINVAL; + struct ol_txrx_ipa_uc_tx_hdr *uc_tx_hdr = NULL; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "Add Partial hdr: %s, "QDF_MAC_ADDR_FMT, ifname, + QDF_MAC_ADDR_REF(mac_addr)); + + /* dynamically allocate the memory to add the hdrs */ + ipa_hdr = qdf_mem_malloc(sizeof(qdf_ipa_ioc_add_hdr_t) + + sizeof(qdf_ipa_hdr_add_t)); + if (!ipa_hdr) { + ret = -ENOMEM; + goto end; + } + + QDF_IPA_IOC_ADD_HDR_COMMIT(ipa_hdr) = 0; + QDF_IPA_IOC_ADD_HDR_NUM_HDRS(ipa_hdr) = 1; + + uc_tx_hdr = (struct ol_txrx_ipa_uc_tx_hdr *) + QDF_IPA_IOC_ADD_HDR_HDR(ipa_hdr); + memcpy(uc_tx_hdr, &ipa_uc_tx_hdr, OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN); + memcpy(uc_tx_hdr->eth.h_source, mac_addr, ETH_ALEN); + uc_tx_hdr->ipa_hd.vdev_id = session_id; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "ifname=%s, vdev_id=%d", + ifname, uc_tx_hdr->ipa_hd.vdev_id); + snprintf(QDF_IPA_IOC_ADD_HDR_NAME(ipa_hdr), IPA_RESOURCE_NAME_MAX, + "%s%s", ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + QDF_IPA_IOC_ADD_HDR_HDR_LEN(ipa_hdr) = OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN; + QDF_IPA_IOC_ADD_HDR_TYPE(ipa_hdr) = IPA_HDR_L2_ETHERNET_II; + QDF_IPA_IOC_ADD_HDR_IS_PARTIAL(ipa_hdr) = 1; + QDF_IPA_IOC_ADD_HDR_HDR_HDL(ipa_hdr) = 0; + QDF_IPA_IOC_ADD_HDR_IS_ETH2_OFST_VALID(ipa_hdr) = 1; + QDF_IPA_IOC_ADD_HDR_ETH2_OFST(ipa_hdr) = + OL_TXRX_IPA_UC_WLAN_HDR_DES_MAC_OFFSET; + + ret = qdf_ipa_add_hdr(ipa_hdr); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s IPv4 add hdr failed: %d", ifname, ret); + goto end; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: IPv4 hdr_hdl: 0x%x", + QDF_IPA_IOC_ADD_HDR_NAME(ipa_hdr), + QDF_IPA_IOC_ADD_HDR_HDR_HDL(ipa_hdr)); + + if (is_ipv6_enabled) { + snprintf(QDF_IPA_IOC_ADD_HDR_NAME(ipa_hdr), + IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV6_NAME_EXT); + + uc_tx_hdr = (struct ol_txrx_ipa_uc_tx_hdr *) + QDF_IPA_IOC_ADD_HDR_HDR(ipa_hdr); + uc_tx_hdr->eth.h_proto = cpu_to_be16(ETH_P_IPV6); + + ret = qdf_ipa_add_hdr(ipa_hdr); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: IPv6 add hdr failed: %d", ifname, ret); + goto clean_ipv4_hdr; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: IPv6 hdr_hdl: 0x%x", + QDF_IPA_IOC_ADD_HDR_NAME(ipa_hdr), + QDF_IPA_IOC_ADD_HDR_HDR_HDL(ipa_hdr)); + } + + qdf_mem_free(ipa_hdr); + + return ret; + +clean_ipv4_hdr: + snprintf(ipa_hdr->hdr[0].name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + ol_txrx_ipa_remove_header(ipa_hdr->hdr[0].name); +end: + if (ipa_hdr) + qdf_mem_free(ipa_hdr); + + return ret; +} + +/** + * ol_txrx_ipa_register_interface() - register IPA interface + * @ifname: Interface name + * @prod_client: IPA prod client type + * @cons_client: IPA cons client type + * @session_id: Session ID + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: 0 on success, negative errno on error + */ +static int ol_txrx_ipa_register_interface(char *ifname, + qdf_ipa_client_type_t prod_client, + qdf_ipa_client_type_t cons_client, + uint8_t session_id, + bool is_ipv6_enabled) +{ + qdf_ipa_tx_intf_t tx_intf; + qdf_ipa_rx_intf_t rx_intf; + qdf_ipa_ioc_tx_intf_prop_t *tx_prop = NULL; + qdf_ipa_ioc_rx_intf_prop_t *rx_prop = NULL; + + char ipv4_hdr_name[IPA_RESOURCE_NAME_MAX]; + char ipv6_hdr_name[IPA_RESOURCE_NAME_MAX]; + + int num_prop = 1; + int ret = 0; + + if (is_ipv6_enabled) + num_prop++; + + /* Allocate TX properties for TOS categories, 1 each for IPv4 & IPv6 */ + tx_prop = + qdf_mem_malloc(sizeof(qdf_ipa_ioc_tx_intf_prop_t) * num_prop); + if (!tx_prop) + goto register_interface_fail; + + /* Allocate RX properties, 1 each for IPv4 & IPv6 */ + rx_prop = + qdf_mem_malloc(sizeof(qdf_ipa_ioc_rx_intf_prop_t) * num_prop); + if (!rx_prop) + goto register_interface_fail; + + qdf_mem_zero(&tx_intf, sizeof(tx_intf)); + qdf_mem_zero(&rx_intf, sizeof(rx_intf)); + + snprintf(ipv4_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + snprintf(ipv6_hdr_name, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV6_NAME_EXT); + + QDF_IPA_IOC_RX_INTF_PROP_IP(&rx_prop[IPA_IP_v4]) = IPA_IP_v4; + QDF_IPA_IOC_RX_INTF_PROP_SRC_PIPE(&rx_prop[IPA_IP_v4]) = prod_client; + QDF_IPA_IOC_RX_INTF_PROP_HDR_L2_TYPE(&rx_prop[IPA_IP_v4]) = + IPA_HDR_L2_ETHERNET_II; + QDF_IPA_IOC_RX_INTF_PROP_ATTRIB_MASK(&rx_prop[IPA_IP_v4]) = + IPA_FLT_META_DATA; + + /* + * Interface ID is 3rd byte in the CLD header. Add the meta data and + * mask to identify the interface in IPA hardware + */ + QDF_IPA_IOC_RX_INTF_PROP_META_DATA(&rx_prop[IPA_IP_v4]) = + htonl(session_id << 16); + QDF_IPA_IOC_RX_INTF_PROP_META_DATA_MASK(&rx_prop[IPA_IP_v4]) = + htonl(0x00FF0000); + + rx_intf.num_props++; + if (is_ipv6_enabled) { + QDF_IPA_IOC_RX_INTF_PROP_IP(&rx_prop[IPA_IP_v6]) = IPA_IP_v6; + QDF_IPA_IOC_RX_INTF_PROP_SRC_PIPE(&rx_prop[IPA_IP_v6]) = + prod_client; + QDF_IPA_IOC_RX_INTF_PROP_HDR_L2_TYPE(&rx_prop[IPA_IP_v6]) = + IPA_HDR_L2_ETHERNET_II; + QDF_IPA_IOC_RX_INTF_PROP_ATTRIB_MASK(&rx_prop[IPA_IP_v6]) = + IPA_FLT_META_DATA; + QDF_IPA_IOC_RX_INTF_PROP_META_DATA(&rx_prop[IPA_IP_v6]) = + htonl(session_id << 16); + QDF_IPA_IOC_RX_INTF_PROP_META_DATA_MASK(&rx_prop[IPA_IP_v6]) = + htonl(0x00FF0000); + + rx_intf.num_props++; + } + + QDF_IPA_IOC_TX_INTF_PROP_IP(&tx_prop[IPA_IP_v4]) = IPA_IP_v4; + QDF_IPA_IOC_TX_INTF_PROP_HDR_L2_TYPE(&tx_prop[IPA_IP_v4]) = + IPA_HDR_L2_ETHERNET_II; + QDF_IPA_IOC_TX_INTF_PROP_DST_PIPE(&tx_prop[IPA_IP_v4]) = + IPA_CLIENT_WLAN1_CONS; + QDF_IPA_IOC_TX_INTF_PROP_ALT_DST_PIPE(&tx_prop[IPA_IP_v4]) = + cons_client; + strlcpy(QDF_IPA_IOC_TX_INTF_PROP_HDR_NAME(&tx_prop[IPA_IP_v4]), + ipv4_hdr_name, IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + + if (is_ipv6_enabled) { + QDF_IPA_IOC_TX_INTF_PROP_IP(&tx_prop[IPA_IP_v6]) = IPA_IP_v6; + QDF_IPA_IOC_TX_INTF_PROP_HDR_L2_TYPE(&tx_prop[IPA_IP_v6]) = + IPA_HDR_L2_ETHERNET_II; + QDF_IPA_IOC_TX_INTF_PROP_DST_PIPE(&tx_prop[IPA_IP_v6]) = + IPA_CLIENT_WLAN1_CONS; + QDF_IPA_IOC_TX_INTF_PROP_ALT_DST_PIPE(&tx_prop[IPA_IP_v6]) = + cons_client; + strlcpy(QDF_IPA_IOC_TX_INTF_PROP_HDR_NAME(&tx_prop[IPA_IP_v6]), + ipv6_hdr_name, IPA_RESOURCE_NAME_MAX); + tx_intf.num_props++; + } + + QDF_IPA_TX_INTF_PROP(&tx_intf) = tx_prop; + QDF_IPA_RX_INTF_PROP(&rx_intf) = rx_prop; + + /* Call the ipa api to register interface */ + ret = qdf_ipa_register_intf(ifname, &tx_intf, &rx_intf); + +register_interface_fail: + qdf_mem_free(tx_prop); + qdf_mem_free(rx_prop); + return ret; +} + +/** + * ol_txrx_ipa_setup_iface() - Setup IPA header and register interface + * @ifname: Interface name + * @mac_addr: Interface MAC address + * @prod_client: IPA prod client type + * @cons_client: IPA cons client type + * @session_id: Session ID + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr, + qdf_ipa_client_type_t prod_client, + qdf_ipa_client_type_t cons_client, + uint8_t session_id, bool is_ipv6_enabled) +{ + int ret; + + ret = ol_txrx_ipa_add_header_info(ifname, mac_addr, session_id, + is_ipv6_enabled); + if (ret) + return QDF_STATUS_E_FAILURE; + + /* Configure the TX and RX pipes filter rules */ + ret = ol_txrx_ipa_register_interface(ifname, + prod_client, + cons_client, + session_id, is_ipv6_enabled); + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_cleanup_iface() - Cleanup IPA header and deregister interface + * @ifname: Interface name + * @is_ipv6_enabled: Is IPV6 enabled or not + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled) +{ + char name_ipa[IPA_RESOURCE_NAME_MAX]; + int ret; + + /* Remove the headers */ + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV4_NAME_EXT); + ol_txrx_ipa_remove_header(name_ipa); + + if (is_ipv6_enabled) { + snprintf(name_ipa, IPA_RESOURCE_NAME_MAX, "%s%s", + ifname, OL_TXRX_IPA_IPV6_NAME_EXT); + ol_txrx_ipa_remove_header(name_ipa); + } + /* unregister the interface with IPA */ + ret = qdf_ipa_deregister_intf(ifname); + if (ret) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: ipa_deregister_intf fail: %d", + ifname, ret); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_ipa_resources *ipa_res; + int result; + QDF_STATUS status; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + ipa_res = &pdev->ipa_resource; + status = htt_rx_update_smmu_map(pdev->htt_pdev, true); + if (status != QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "IPA SMMU map failed status:%d", status); + return status; + } + + /* ACTIVATE TX PIPE */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Enable TX PIPE(tx_pipe_handle=%d)", + __func__, ipa_res->tx_pipe_handle); + result = qdf_ipa_enable_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Enable TX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + result = qdf_ipa_resume_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Resume TX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + ol_txrx_ipa_uc_set_active(soc_hdl, pdev_id, true, true); + + /* ACTIVATE RX PIPE */ + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Enable RX PIPE(rx_pipe_handle=%d)", + __func__, ipa_res->rx_pipe_handle); + result = qdf_ipa_enable_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Enable RX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + result = qdf_ipa_resume_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Resume RX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + ol_txrx_ipa_uc_set_active(soc_hdl, pdev_id, true, false); + + return QDF_STATUS_SUCCESS; + +smmu_unmap: + if (htt_rx_update_smmu_map(pdev->htt_pdev, false) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "IPA SMMU unmap failed"); + } + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + struct ol_txrx_ipa_resources *ipa_res; + int result; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + ipa_res = &pdev->ipa_resource; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disable RX PIPE", __func__); + result = qdf_ipa_suspend_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Suspend RX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + + result = qdf_ipa_disable_wdi_pipe(ipa_res->rx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Disable RX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Disable TX PIPE", __func__); + result = qdf_ipa_suspend_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Suspend TX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + result = qdf_ipa_disable_wdi_pipe(ipa_res->tx_pipe_handle); + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Disable TX PIPE fail, code %d", + __func__, result); + goto smmu_unmap; + } + +smmu_unmap: + if (htt_rx_update_smmu_map(pdev->htt_pdev, false) != + QDF_STATUS_SUCCESS) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "IPA SMMU unmap failed"); + } + + return result ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +/** + * ol_txrx_ipa_set_perf_level() - Set IPA clock bandwidth based on data rates + * @client: Client type + * @max_supported_bw_mbps: Maximum bandwidth needed (in Mbps) + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_set_perf_level(int client, + uint32_t max_supported_bw_mbps) +{ + qdf_ipa_rm_resource_name_t resource_name; + qdf_ipa_rm_perf_profile_t profile; + int result; + + if (client == QDF_IPA_CLIENT_WLAN1_PROD) { + resource_name = QDF_IPA_RM_RESOURCE_WLAN_PROD; + } else if (client == QDF_IPA_CLIENT_WLAN1_CONS) { + resource_name = QDF_IPA_RM_RESOURCE_WLAN_CONS; + } else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "not supported client %d", client); + return QDF_STATUS_E_FAILURE; + } + + QDF_IPA_RM_PERF_PROFILE_MAX_SUPPORTED_BANDWIDTH_MBPS(&profile) = + max_supported_bw_mbps; + result = qdf_ipa_rm_set_perf_profile(resource_name, &profile); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Set perf profile failed, code %d", result); + + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ + +#ifdef FEATURE_METERING +QDF_STATUS ol_txrx_ipa_uc_get_share_stats(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint8_t reset_stats) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int result; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + result = htt_h2t_ipa_uc_get_share_stats(pdev->htt_pdev, reset_stats); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Get IPA sharing stats failed, code %d", result); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS ol_txrx_ipa_uc_set_quota(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint64_t quota_bytes) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + int result; + + if (!pdev) { + ol_txrx_err("Invalid instance"); + return QDF_STATUS_E_FAILURE; + } + + result = htt_h2t_ipa_uc_set_quota(pdev->htt_pdev, quota_bytes); + + if (result) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Set IPA quota failed, code %d", result); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* IPA_UC_OFFLOAD */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.h new file mode 100644 index 0000000000..fb579d5a21 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_ipa.h @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OL_TXRX_IPA_H_ +#define _OL_TXRX_IPA_H_ + +#ifdef IPA_OFFLOAD + +#include /* ol_txrx_vdev_t, etc. */ +#include + +/** + * struct frag_header - fragment header type registered to IPA hardware + * @length: fragment length + * @reserved1: Reserved not used + * @reserved2: Reserved not used + * + */ +#ifdef QCA_WIFI_3_0 +struct frag_header { + uint16_t length; + uint32_t reserved1; + uint32_t reserved2; +} __packed; +#else +struct frag_header { + uint32_t + length:16, + reserved16:16; + uint32_t reserved2; +} __packed; +#endif + +/** + * struct ipa_header - ipa header type registered to IPA hardware + * @vdev_id: vdev id + * @reserved: Reserved not used + * + */ +struct ipa_header { + uint32_t + vdev_id:8, /* vdev_id field is LSB of IPA DESC */ + reserved:24; +} __packed; + +/** + * struct ol_txrx_ipa_uc_tx_hdr - full tx header registered to IPA hardware + * @frag_hd: fragment header + * @ipa_hd: ipa header + * @eth: ether II header + * + */ +struct ol_txrx_ipa_uc_tx_hdr { + struct frag_header frag_hd; + struct ipa_header ipa_hd; + struct ethhdr eth; +} __packed; + +/** + * struct ol_txrx_ipa_uc_rx_hdr - full rx header registered to IPA hardware + * @eth: ether II header + * + */ +struct ol_txrx_ipa_uc_rx_hdr { + struct ethhdr eth; +} __packed; + +#define OL_TXRX_IPA_UC_WLAN_8023_HDR_SIZE 14 + +#define OL_TXRX_IPA_IPV4_NAME_EXT "_ipv4" +#define OL_TXRX_IPA_IPV6_NAME_EXT "_ipv6" + +#define OL_TXRX_IPA_MAX_IFACE MAX_IPA_IFACE + +#define OL_TXRX_IPA_WLAN_FRAG_HEADER sizeof(struct frag_header) +#define OL_TXRX_IPA_WLAN_IPA_HEADER sizeof(struct ipa_header) +#define OL_TXRX_IPA_UC_WLAN_TX_HDR_LEN sizeof(struct ol_txrx_ipa_uc_tx_hdr) +#define OL_TXRX_IPA_UC_WLAN_RX_HDR_LEN sizeof(struct ol_txrx_ipa_uc_rx_hdr) +#define OL_TXRX_IPA_UC_WLAN_HDR_DES_MAC_OFFSET \ + (OL_TXRX_IPA_WLAN_FRAG_HEADER + OL_TXRX_IPA_WLAN_IPA_HEADER) + +#if defined(QCA_WIFI_3_0) && defined(CONFIG_IPA3) +#define OL_TXRX_IPA_WDI2_SET(pipe_in, ipa_res, osdev) \ + do { \ + QDF_IPA_PIPE_IN_UL_RDY_RING_RP_VA(pipe_in) = \ + ipa_res->rx_proc_done_idx->vaddr; \ + QDF_IPA_PIPE_IN_UL_RDY_COMP_RING(pipe_in) = \ + qdf_mem_get_dma_addr(osdev, \ + &ipa_res->rx2_rdy_ring->mem_info);\ + QDF_IPA_PIPE_IN_UL_RDY_COMP_RING_SIZE(pipe_in) = \ + ipa_res->rx2_rdy_ring->mem_info.size; \ + QDF_IPA_PIPE_IN_UL_RDY_COMP_RING_WP_PA(pipe_in) = \ + qdf_mem_get_dma_addr(osdev, \ + &ipa_res->rx2_proc_done_idx->mem_info); \ + QDF_IPA_PIPE_IN_UL_RDY_COMP_RING_WP_VA(pipe_in) = \ + ipa_res->rx2_proc_done_idx->vaddr; \ + } while (0) +#else +/* Do nothing */ +#define OL_TXRX_IPA_WDI2_SET(pipe_in, ipa_res, osdev) +#endif /* IPA3 */ + +/** + * ol_txrx_ipa_uc_get_resource() - Client request resource information + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * OL client will request IPA UC related resource information + * Resource information will be distributted to IPA module + * All of the required resources should be pre-allocated + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_get_resource(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id); + +/** + * ol_txrx_ipa_uc_set_doorbell_paddr() - Client set IPA UC doorbell register + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_set_doorbell_paddr(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id); + +/** + * ol_txrx_ipa_uc_set_active() - Client notify IPA UC data path active or not + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * @uc_active: WDI UC path enable or not + * @is_tx: TX path or RX path + * + * IPA UC let know doorbell register physical address + * WLAN firmware will use this physical address to notify IPA UC + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_set_active(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + bool uc_active, bool is_tx); + +/** + * ol_txrx_ipa_uc_op_response() - Handle OP command response from firmware + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * @op_msg: op response message from firmware + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_op_response(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint8_t *op_msg); + +/** + * ol_txrx_ipa_uc_register_op_cb() - Register OP handler function + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * @op_cb: handler function pointer + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_register_op_cb(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + ipa_uc_op_cb_type op_cb, + void *usr_ctxt); + +/** + * ol_txrx_ipa_uc_get_stat() - Get firmware wdi status + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * Return: none + */ +QDF_STATUS ol_txrx_ipa_uc_get_stat(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); + +/** + * ol_txrx_ipa_enable_autonomy() - Enable autonomy RX path + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * Set all RX packet route to IPA + * Return: none + */ +QDF_STATUS ol_txrx_ipa_enable_autonomy(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id); + +/** + * ol_txrx_ipa_disable_autonomy() - Disable autonomy RX path + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * Disable RX packet route to host + * Return: none + */ +QDF_STATUS ol_txrx_ipa_disable_autonomy(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id); + +/** + * ol_txrx_ipa_tx_buf_smmu_mapping() - Create SMMU mappings for IPA + * allocated TX buffers + * @soc_hdl: handle to the soc + * @pdev_id: pdev id number, to get the handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_tx_buf_smmu_mapping(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + const char *func, + uint32_t line); + +/** + * ol_txrx_ipa_tx_buf_smmu_unmapping() - Release SMMU mappings for IPA + * allocated TX buffers + * @soc_hdl: handle to the soc + * @pdev_id: pdev id number, to get the handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_tx_buf_smmu_unmapping(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + const char *func, + uint32_t line); + +#ifdef CONFIG_IPA_WDI_UNIFIED_API +/** + * ol_txrx_ipa_setup() - Setup and connect IPA pipes + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * @ipa_i2w_cb: IPA to WLAN callback + * @ipa_w2i_cb: WLAN to IPA callback + * @ipa_wdi_meter_notifier_cb: IPA WDI metering callback + * @ipa_desc_size: IPA descriptor size + * @ipa_priv: handle to the HTT instance + * @is_rm_enabled: Is IPA RM enabled or not + * @p_tx_pipe_handle: pointer to Tx pipe handle + * @p_rx_pipe_handle: pointer to Rx pipe handle + * @is_smmu_enabled: Is SMMU enabled or not + * @sys_in: parameters to setup sys pipe in mcc mode + * @over_gsi: is ipa ver gsi fw + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + void *ipa_i2w_cb, void *ipa_w2i_cb, + void *ipa_wdi_meter_notifier_cb, + uint32_t ipa_desc_size, + void *ipa_priv, bool is_rm_enabled, + uint32_t *tx_pipe_handle, uint32_t *rx_pipe_handle, + bool is_smmu_enabled, + qdf_ipa_sys_connect_params_t *sys_in, + bool over_gsi, + qdf_ipa_wdi_hdl_t hdl, + qdf_ipa_wdi_hdl_t id, + void *ipa_ast_notify_cb); +#else /* CONFIG_IPA_WDI_UNIFIED_API */ +/** + * ol_txrx_ipa_setup() - Setup and connect IPA pipes + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * @ipa_i2w_cb: IPA to WLAN callback + * @ipa_w2i_cb: WLAN to IPA callback + * @ipa_wdi_meter_notifier_cb: IPA WDI metering callback + * @ipa_desc_size: IPA descriptor size + * @ipa_priv: handle to the HTT instance + * @is_rm_enabled: Is IPA RM enabled or not + * @p_tx_pipe_handle: pointer to Tx pipe handle + * @p_rx_pipe_handle: pointer to Rx pipe handle + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_setup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + void *ipa_i2w_cb, void *ipa_w2i_cb, + void *ipa_wdi_meter_notifier_cb, + uint32_t ipa_desc_size, void *ipa_priv, + bool is_rm_enabled, uint32_t *tx_pipe_handle, + uint32_t *rx_pipe_handle, + qdf_ipa_wdi_hdl_t hdl); +#endif /* CONFIG_IPA_WDI_UNIFIED_API */ +QDF_STATUS ol_txrx_ipa_cleanup(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint32_t tx_pipe_handle, + uint32_t rx_pipe_handle, + qdf_ipa_wdi_hdl_t hdl); +QDF_STATUS ol_txrx_ipa_setup_iface(char *ifname, uint8_t *mac_addr, + qdf_ipa_client_type_t prod_client, + qdf_ipa_client_type_t cons_client, + uint8_t session_id, bool is_ipv6_enabled, + qdf_ipa_wdi_hdl_t hdl); +QDF_STATUS ol_txrx_ipa_cleanup_iface(char *ifname, bool is_ipv6_enabled, + qdf_ipa_wdi_hdl_t hdl); + +/** + * ol_txrx_ipa_enable_pipes() - Enable and resume traffic on Tx/Rx pipes + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_enable_pipes(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + qdf_ipa_wdi_hdl_t hdl); + +/** + * ol_txrx_ipa_disable_pipes() – Suspend traffic and disable Tx/Rx pipes + * @soc_hdl: data path soc handle + * @pdev_id: device instance id + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_disable_pipes(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + qdf_ipa_wdi_hdl_t hdl); +QDF_STATUS ol_txrx_ipa_set_perf_level(int client, + uint32_t max_supported_bw_mbps, + qdf_ipa_wdi_hdl_t hdl); +#ifdef FEATURE_METERING +/** + * ol_txrx_ipa_uc_get_share_stats() - get Tx/Rx byte stats from FW + * @soc_hdl: data path soc handle + * @pdev_id: physical device instance id + * @value: reset stats + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_get_share_stats(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, uint8_t reset_stats); +/** + * ol_txrx_ipa_uc_set_quota() - set quota limit to FW + * @soc_hdl: data path soc handle + * @pdev_id: physical device instance number + * @value: quota limit bytes + * + * Return: QDF_STATUS + */ +QDF_STATUS ol_txrx_ipa_uc_set_quota(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + uint64_t quota_bytes); +#endif +#endif +#endif /* _OL_TXRX_IPA_H_*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_legacy_flow_control.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_legacy_flow_control.c new file mode 100644 index 0000000000..163ba61c8e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_legacy_flow_control.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* OS abstraction libraries */ +#include /* qdf_nbuf_t, etc. */ +#include /* qdf_atomic_read, etc. */ +#include /* qdf_unlikely */ + +/* APIs for other modules */ +#include /* HTT_TX_EXT_TID_MGMT */ +#include /* htt_tx_desc_tid */ + +/* internal header files relevant for all systems */ +#include /* TXRX_ASSERT1 */ +#include /* ol_tx_desc */ +#include /* ol_tx_send */ +#include /* ol_txrx_get_vdev_from_vdev_id */ + +/* internal header files relevant only for HL systems */ +#include /* ol_tx_enqueue */ + +/* internal header files relevant only for specific systems (Pronto) */ +#include /* OL_TX_ENCAP, etc */ +#include +#include +#include + +void ol_txrx_vdev_pause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + /* TO DO: log the queue pause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + vdev->ll_pause.paused_reason |= reason; + vdev->ll_pause.q_pause_cnt++; + vdev->ll_pause.is_q_paused = true; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void ol_txrx_vdev_unpause(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + uint32_t reason, uint32_t pause_type) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + /* TO DO: log the queue unpause */ + /* acquire the mutex lock, since we'll be modifying the queues */ + TX_SCHED_DEBUG_PRINT("Enter"); + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.paused_reason & reason) { + vdev->ll_pause.paused_reason &= ~reason; + if (!vdev->ll_pause.paused_reason) { + vdev->ll_pause.is_q_paused = false; + vdev->ll_pause.q_unpause_cnt++; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + ol_tx_vdev_ll_pause_queue_send((void *)vdev); + } else { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } else { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + TX_SCHED_DEBUG_PRINT("Leave"); +} + +void ol_txrx_vdev_flush(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + qdf_timer_stop(&vdev->ll_pause.timer); + vdev->ll_pause.is_q_timer_on = false; + while (vdev->ll_pause.txq.head) { + qdf_nbuf_t next = + qdf_nbuf_next(vdev->ll_pause.txq.head); + qdf_nbuf_set_next(vdev->ll_pause.txq.head, NULL); + if (QDF_NBUF_CB_PADDR(vdev->ll_pause.txq.head)) { + if (!qdf_nbuf_ipa_owned_get(vdev->ll_pause.txq.head)) + qdf_nbuf_unmap(vdev->pdev->osdev, + vdev->ll_pause.txq.head, + QDF_DMA_TO_DEVICE); + } + qdf_nbuf_tx_free(vdev->ll_pause.txq.head, + QDF_NBUF_PKT_ERROR); + vdev->ll_pause.txq.head = next; + } + vdev->ll_pause.txq.tail = NULL; + vdev->ll_pause.txq.depth = 0; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); +} + +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN 400 +#define OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS 5 + +#define OL_TX_THROTTLE_MAX_SEND_LEVEL1 80 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL2 65 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL3 55 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL4 45 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL5 35 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL6 20 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL7 10 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL8 5 +#define OL_TX_THROTTLE_MAX_SEND_LEVEL9 1 + +/** + * ol_tx_get_max_to_send() - Get the maximum number of packets + * that can be sent for different phy rate + * @pdev: datapath pdev handle + * + * Return: int type value + */ +static int ol_tx_get_max_to_send(struct ol_txrx_pdev_t *pdev) +{ + uint16_t consume_num_last_timer; + int max_to_send; + + qdf_spin_lock_bh(&pdev->tx_mutex); + if (!pdev->tx_throttle.prev_outstanding_num) { + max_to_send = OL_TX_THROTTLE_MAX_SEND_LEVEL5; + } else { + consume_num_last_timer = + (pdev->tx_throttle.prev_outstanding_num - + pdev->tx_desc.pool_size + + pdev->tx_desc.num_free); + if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL1) { + max_to_send = pdev->tx_throttle.tx_threshold; + } else if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL2) { + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL1; + } else if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL3) { + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL2; + } else if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL4) { + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL3; + } else if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL5) { + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL4; + } else if (pdev->tx_throttle.prev_outstanding_num > + consume_num_last_timer) { + /* + * when TX packet number is smaller than 35, + * most likely low phy rate is being used. + * As long as pdev->tx_throttle.prev_outstanding_num + * is greater than consume_num_last_timer, it + * means small TX packet number isn't limited + * by packets injected from host. + */ + if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL6) + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL6; + else if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL7) + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL7; + else if (consume_num_last_timer >= + OL_TX_THROTTLE_MAX_SEND_LEVEL8) + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL8; + else + max_to_send = + OL_TX_THROTTLE_MAX_SEND_LEVEL9; + } else { + /* + * when come here, it means it's hard to evaluate + * current phy rate, for safety, max_to_send set + * to OL_TX_THROTTLE_MAX_SEND_LEVEL5. + */ + max_to_send = OL_TX_THROTTLE_MAX_SEND_LEVEL5; + } + } + qdf_spin_unlock_bh(&pdev->tx_mutex); + + return max_to_send; +} + +static void ol_tx_vdev_ll_pause_queue_send_base(struct ol_txrx_vdev_t *vdev) +{ + int max_to_accept; + + if (!vdev) + return; + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.paused_reason) { + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + return; + } + + /* + * Send as much of the backlog as possible, but leave some margin + * of unallocated tx descriptors that can be used for new frames + * being transmitted by other vdevs. + * Ideally there would be a scheduler, which would not only leave + * some margin for new frames for other vdevs, but also would + * fairly apportion the tx descriptors between multiple vdevs that + * have backlogs in their pause queues. + * However, the fairness benefit of having a scheduler for frames + * from multiple vdev's pause queues is not sufficient to outweigh + * the extra complexity. + */ + max_to_accept = vdev->pdev->tx_desc.num_free - + OL_TX_VDEV_PAUSE_QUEUE_SEND_MARGIN; + while (max_to_accept > 0 && vdev->ll_pause.txq.depth) { + qdf_nbuf_t tx_msdu; + + max_to_accept--; + vdev->ll_pause.txq.depth--; + tx_msdu = vdev->ll_pause.txq.head; + if (tx_msdu) { + vdev->ll_pause.txq.head = qdf_nbuf_next(tx_msdu); + if (!vdev->ll_pause.txq.head) + vdev->ll_pause.txq.tail = NULL; + qdf_nbuf_set_next(tx_msdu, NULL); + QDF_NBUF_UPDATE_TX_PKT_COUNT(tx_msdu, + QDF_NBUF_TX_PKT_TXRX_DEQUEUE); + tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu); + /* + * It is unexpected that ol_tx_ll would reject the frame + * since we checked that there's room for it, though + * there's an infinitesimal possibility that between the + * time we checked the room available and now, a + * concurrent batch of tx frames used up all the room. + * For simplicity, just drop the frame. + */ + if (tx_msdu) { + qdf_nbuf_unmap(vdev->pdev->osdev, tx_msdu, + QDF_DMA_TO_DEVICE); + qdf_nbuf_tx_free(tx_msdu, QDF_NBUF_PKT_ERROR); + } + } + } + if (vdev->ll_pause.txq.depth) { + qdf_timer_stop(&vdev->ll_pause.timer); + if (!qdf_atomic_read(&vdev->delete.detaching)) { + qdf_timer_start(&vdev->ll_pause.timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + vdev->ll_pause.is_q_timer_on = true; + } + if (vdev->ll_pause.txq.depth >= vdev->ll_pause.max_q_depth) + vdev->ll_pause.q_overflow_cnt++; + } + + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); +} + +static qdf_nbuf_t +ol_tx_vdev_pause_queue_append(struct ol_txrx_vdev_t *vdev, + qdf_nbuf_t msdu_list, uint8_t start_timer) +{ + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + while (msdu_list && + vdev->ll_pause.txq.depth < vdev->ll_pause.max_q_depth) { + qdf_nbuf_t next = qdf_nbuf_next(msdu_list); + + QDF_NBUF_UPDATE_TX_PKT_COUNT(msdu_list, + QDF_NBUF_TX_PKT_TXRX_ENQUEUE); + DPTRACE(qdf_dp_trace(msdu_list, + QDF_DP_TRACE_TXRX_QUEUE_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(msdu_list), + sizeof(qdf_nbuf_data(msdu_list)), QDF_TX)); + + vdev->ll_pause.txq.depth++; + if (!vdev->ll_pause.txq.head) { + vdev->ll_pause.txq.head = msdu_list; + vdev->ll_pause.txq.tail = msdu_list; + } else { + qdf_nbuf_set_next(vdev->ll_pause.txq.tail, msdu_list); + } + vdev->ll_pause.txq.tail = msdu_list; + + msdu_list = next; + } + if (vdev->ll_pause.txq.tail) + qdf_nbuf_set_next(vdev->ll_pause.txq.tail, NULL); + + if (start_timer) { + qdf_timer_stop(&vdev->ll_pause.timer); + if (!qdf_atomic_read(&vdev->delete.detaching)) { + qdf_timer_start(&vdev->ll_pause.timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); + vdev->ll_pause.is_q_timer_on = true; + } + } + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + return msdu_list; +} + +/* + * Store up the tx frame in the vdev's tx queue if the vdev is paused. + * If there are too many frames in the tx queue, reject it. + */ +qdf_nbuf_t ol_tx_ll_queue(ol_txrx_vdev_handle vdev, qdf_nbuf_t msdu_list) +{ + uint16_t eth_type; + uint32_t paused_reason; + + if (!msdu_list) + return NULL; + + paused_reason = vdev->ll_pause.paused_reason; + if (paused_reason) { + if (qdf_unlikely((paused_reason & + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED) == + paused_reason)) { + eth_type = (((struct ethernet_hdr_t *) + qdf_nbuf_data(msdu_list))-> + ethertype[0] << 8) | + (((struct ethernet_hdr_t *) + qdf_nbuf_data(msdu_list))->ethertype[1]); + if (ETHERTYPE_IS_EAPOL_WAPI(eth_type)) { + msdu_list = ol_tx_ll_wrapper(vdev, msdu_list); + return msdu_list; + } + } + msdu_list = ol_tx_vdev_pause_queue_append(vdev, msdu_list, 1); + } else { + if (vdev->ll_pause.txq.depth > 0 || + vdev->pdev->tx_throttle.current_throttle_level != + THROTTLE_LEVEL_0) { + /* + * not paused, but there is a backlog of frms + * from a prior pause or throttle off phase + */ + msdu_list = ol_tx_vdev_pause_queue_append( + vdev, msdu_list, 0); + /* + * if throttle is disabled or phase is "on", + * send the frame + */ + if (vdev->pdev->tx_throttle.current_throttle_level == + THROTTLE_LEVEL_0) { + /* + * send as many frames as possible + * from the vdevs backlog + */ + ol_tx_vdev_ll_pause_queue_send_base(vdev); + } + } else { + /* + * not paused, no throttle and no backlog - + * send the new frames + */ + msdu_list = ol_tx_ll_wrapper(vdev, msdu_list); + } + } + return msdu_list; +} + +/* + * Run through the transmit queues for all the vdevs and + * send the pending frames + */ +void ol_tx_pdev_ll_pause_queue_send_all(struct ol_txrx_pdev_t *pdev) +{ + int max_to_send; /* tracks how many frames have been sent */ + qdf_nbuf_t tx_msdu; + struct ol_txrx_vdev_t *vdev = NULL; + uint8_t more; + + if (!pdev) + return; + + if (pdev->tx_throttle.current_throttle_phase == THROTTLE_PHASE_OFF) + return; + + /* + * For host implementation thermal mitigation, there has limitation + * in low phy rate case, like 11A 6M, 11B 11M. Host may have entered + * throttle off state, if a big number packets are queued to ring + * buffer in low phy rate, FW will have to keep active state during + * the whole throttle cycle. So you need to be careful when + * configuring the max_to_send value to avoid the chip temperature + * suddenly rises to very high in high temperature test. + * So add variable prev_outstanding_num to save last time outstanding + * number, when pdev->tx_throttle.tx_timer come again, we can check + * the gap to know high or low phy rate is being used, then choose + * right max_to_send. + * When it's the first time to enter the function, there doesn't have + * info for prev_outstanding_num, to satisfy all rate, the maximum + * safe number is OL_TX_THROTTLE_MAX_SEND_LEVEL5(35). + */ + max_to_send = ol_tx_get_max_to_send(pdev); + + /* round robin through the vdev queues for the given pdev */ + + /* + * Potential improvement: download several frames from the same vdev + * at a time, since it is more likely that those frames could be + * aggregated together, remember which vdev was serviced last, + * so the next call this function can resume the round-robin + * traversing where the current invocation left off + */ + do { + more = 0; + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + if (vdev->ll_pause.txq.depth) { + if (vdev->ll_pause.paused_reason) { + qdf_spin_unlock_bh(&vdev->ll_pause. + mutex); + continue; + } + + tx_msdu = vdev->ll_pause.txq.head; + if (!tx_msdu) { + qdf_spin_unlock_bh(&vdev->ll_pause. + mutex); + continue; + } + + max_to_send--; + vdev->ll_pause.txq.depth--; + + vdev->ll_pause.txq.head = + qdf_nbuf_next(tx_msdu); + + if (!vdev->ll_pause.txq.head) + vdev->ll_pause.txq.tail = NULL; + + qdf_nbuf_set_next(tx_msdu, NULL); + tx_msdu = ol_tx_ll_wrapper(vdev, tx_msdu); + /* + * It is unexpected that ol_tx_ll would reject + * the frame, since we checked that there's + * room for it, though there's an infinitesimal + * possibility that between the time we checked + * the room available and now, a concurrent + * batch of tx frames used up all the room. + * For simplicity, just drop the frame. + */ + if (tx_msdu) { + qdf_nbuf_unmap(pdev->osdev, tx_msdu, + QDF_DMA_TO_DEVICE); + qdf_nbuf_tx_free(tx_msdu, + QDF_NBUF_PKT_ERROR); + } + } + /*check if there are more msdus to transmit */ + if (vdev->ll_pause.txq.depth) + more = 1; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + } + } while (more && max_to_send); + + qdf_spin_lock_bh(&pdev->tx_mutex); + pdev->tx_throttle.prev_outstanding_num = + (pdev->tx_desc.pool_size - pdev->tx_desc.num_free); + qdf_spin_unlock_bh(&pdev->tx_mutex); + + /* + * currently as long as pdev->tx_throttle.current_throttle_level + * isn't THROTTLE_LEVEL_0, all TX data is scheduled by Tx + * throttle. It's needed to always start pdev->tx_throttle.tx_timer + * at the end of each TX throttle processing to avoid TX cannot be + * scheduled in the remaining throttle_on time. + */ + qdf_timer_stop(&pdev->tx_throttle.tx_timer); + qdf_timer_start(&pdev->tx_throttle.tx_timer, + OL_TX_VDEV_PAUSE_QUEUE_SEND_PERIOD_MS); +} + +void ol_tx_vdev_ll_pause_queue_send(void *context) +{ + struct ol_txrx_vdev_t *vdev = (struct ol_txrx_vdev_t *)context; + struct ol_txrx_pdev_t *pdev = vdev->pdev; + + if (pdev && + pdev->tx_throttle.current_throttle_level != THROTTLE_LEVEL_0) + return; + ol_tx_vdev_ll_pause_queue_send_base(vdev); +} + +int ol_txrx_register_tx_flow_control(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id, + ol_txrx_tx_flow_control_fp flowControl, + void *osif_fc_ctx, + ol_txrx_tx_flow_control_is_pause_fp + flow_control_is_pause) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + qdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = flowControl; + vdev->osif_flow_control_is_pause = flow_control_is_pause; + vdev->osif_fc_ctx = osif_fc_ctx; + qdf_spin_unlock_bh(&vdev->flow_control_lock); + return 0; +} + +int ol_txrx_deregister_tx_flow_control_cb(struct cdp_soc_t *soc_hdl, + uint8_t vdev_id) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id", __func__); + return -EINVAL; + } + + qdf_spin_lock_bh(&vdev->flow_control_lock); + vdev->osif_flow_control_cb = NULL; + vdev->osif_flow_control_is_pause = NULL; + vdev->osif_fc_ctx = NULL; + qdf_spin_unlock_bh(&vdev->flow_control_lock); + return 0; +} + +/** + * ol_txrx_get_tx_resource() - if tx resource less than low_watermark + * soc_hdl: soc handle + * @pdev_id: datapath pdev identifier + * @peer_addr: peer mac address + * @low_watermark: low watermark + * @high_watermark_offset: high watermark offset value + * + * Return: true/false + */ +bool +ol_txrx_get_tx_resource(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct qdf_mac_addr peer_addr, + unsigned int low_watermark, + unsigned int high_watermark_offset) +{ + struct ol_txrx_soc_t *soc = cdp_soc_t_to_ol_txrx_soc_t(soc_hdl); + ol_txrx_pdev_handle pdev = + ol_txrx_get_pdev_from_pdev_id(soc, pdev_id); + ol_txrx_vdev_handle vdev; + + if (qdf_unlikely(!pdev)) { + ol_txrx_err("pdev is NULL"); + return true; + } + + vdev = ol_txrx_get_vdev_by_peer_addr(ol_txrx_pdev_t_to_cdp_pdev(pdev), + peer_addr); + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: Invalid peer address: " QDF_MAC_ADDR_FMT, + __func__, QDF_MAC_ADDR_REF(peer_addr.bytes)); + /* Return true so caller do not understand that resource + * is less than low_watermark. + * sta_id validation will be done in ol_tx_send_data_frame + * and if sta_id is not registered then host will drop + * packet. + */ + return true; + } + + qdf_spin_lock_bh(&vdev->pdev->tx_mutex); + + if (vdev->pdev->tx_desc.num_free < (uint16_t)low_watermark) { + vdev->tx_fl_lwm = (uint16_t)low_watermark; + vdev->tx_fl_hwm = + (uint16_t)(low_watermark + high_watermark_offset); + /* Not enough free resource, stop TX OS Q */ + qdf_atomic_set(&vdev->os_q_paused, 1); + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + return false; + } + qdf_spin_unlock_bh(&vdev->pdev->tx_mutex); + return true; +} + +int ol_txrx_ll_set_tx_pause_q_depth(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + int pause_q_depth) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (!vdev) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Invalid vdev_id %d", __func__, vdev_id); + return -EINVAL; + } + + qdf_spin_lock_bh(&vdev->ll_pause.mutex); + vdev->ll_pause.max_q_depth = pause_q_depth; + qdf_spin_unlock_bh(&vdev->ll_pause.mutex); + + return 0; +} + +void ol_txrx_flow_control_cb(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, + bool tx_resume) +{ + struct ol_txrx_vdev_t *vdev = + (struct ol_txrx_vdev_t *)ol_txrx_get_vdev_from_vdev_id(vdev_id); + + if (qdf_unlikely(!vdev)) { + ol_txrx_err("vdev is NULL"); + return; + } + + qdf_spin_lock_bh(&vdev->flow_control_lock); + if ((vdev->osif_flow_control_cb) && (vdev->osif_fc_ctx)) + vdev->osif_flow_control_cb(vdev->osif_fc_ctx, tx_resume); + qdf_spin_unlock_bh(&vdev->flow_control_lock); +} + +/** + * ol_txrx_flow_control_is_pause() - is osif paused by flow control + * @vdev: vdev handle + * + * Return: true if osif is paused by flow control + */ +static bool ol_txrx_flow_control_is_pause(ol_txrx_vdev_handle vdev) +{ + bool is_pause = false; + + if ((vdev->osif_flow_control_is_pause) && (vdev->osif_fc_ctx)) + is_pause = vdev->osif_flow_control_is_pause(vdev->osif_fc_ctx); + + return is_pause; +} + +/** + * ol_tx_flow_ct_unpause_os_q() - Unpause OS Q + * @pdev: physical device object + * + * + * Return: None + */ +void ol_tx_flow_ct_unpause_os_q(ol_txrx_pdev_handle pdev) +{ + struct ol_txrx_vdev_t *vdev; + struct cdp_soc_t *soc_hdl = ol_txrx_soc_t_to_cdp_soc_t(pdev->soc); + + TAILQ_FOREACH(vdev, &pdev->vdev_list, vdev_list_elem) { + if ((qdf_atomic_read(&vdev->os_q_paused) && + (vdev->tx_fl_hwm != 0)) || + ol_txrx_flow_control_is_pause(vdev)) { + qdf_spin_lock(&pdev->tx_mutex); + if (pdev->tx_desc.num_free > vdev->tx_fl_hwm) { + qdf_atomic_set(&vdev->os_q_paused, 0); + qdf_spin_unlock(&pdev->tx_mutex); + ol_txrx_flow_control_cb(soc_hdl, + vdev->vdev_id, true); + } else { + qdf_spin_unlock(&pdev->tx_mutex); + } + } + } +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c new file mode 100644 index 0000000000..d3620ab4d8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.c @@ -0,0 +1,879 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=== includes ===*/ +/* header files for OS primitives */ +#include /* uint32_t, etc. */ +#include /* qdf_mem_malloc, etc. */ +#include /* qdf_device_t, qdf_print */ +/* header files for utilities */ +#include "queue.h" /* TAILQ */ + +/* header files for configuration API */ +#include /* ol_cfg_max_peer_id */ + +/* header files for our internal definitions */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_DEBUG_LEVEL */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* ol_txrx_peer_release_ref */ +#include /* ol_txrx_peer_find_attach, etc. */ +#include +#include "wlan_roam_debug.h" + +/*=== misc. / utility function definitions ==================================*/ + +static int ol_txrx_log2_ceil(unsigned int value) +{ + /* need to switch to unsigned math so that negative values + * will right-shift towards 0 instead of -1 + */ + unsigned int tmp = value; + int log2 = -1; + + if (value == 0) { + TXRX_ASSERT2(0); + return 0; + } + + while (tmp) { + log2++; + tmp >>= 1; + } + if (1U << log2 != value) + log2++; + + return log2; +} + +int ol_txrx_peer_get_ref(struct ol_txrx_peer_t *peer, + enum peer_debug_id_type dbg_id) +{ + int refs_dbg_id; + + if (!peer) { + ol_txrx_err("peer is null for ID %d", dbg_id); + return -EINVAL; + } + + if (dbg_id >= PEER_DEBUG_ID_MAX || dbg_id < 0) { + ol_txrx_err("incorrect debug_id %d ", dbg_id); + return -EINVAL; + } + + qdf_atomic_inc(&peer->ref_cnt); + qdf_atomic_inc(&peer->access_list[dbg_id]); + refs_dbg_id = qdf_atomic_read(&peer->access_list[dbg_id]); + + return refs_dbg_id; +} + +/*=== function definitions for peer MAC addr --> peer object hash table =====*/ + +/* + * TXRX_PEER_HASH_LOAD_FACTOR: + * Multiply by 2 and divide by 2^0 (shift by 0), then round up to a + * power of two. + * This provides at least twice as many bins in the peer hash table + * as there will be entries. + * Having substantially more bins than spaces minimizes the probability of + * having to compare MAC addresses. + * Because the MAC address comparison is fairly efficient, it is okay if the + * hash table is sparsely loaded, but it's generally better to use extra mem + * to keep the table sparse, to keep the lookups as fast as possible. + * An optimization would be to apply a more conservative loading factor for + * high latency, where the lookup happens during the tx classification of + * every tx frame, than for low-latency, where the lookup only happens + * during association, when the PEER_MAP message is received. + */ +#define TXRX_PEER_HASH_LOAD_MULT 2 +#define TXRX_PEER_HASH_LOAD_SHIFT 0 + +static int ol_txrx_peer_find_hash_attach(struct ol_txrx_pdev_t *pdev) +{ + int i, hash_elems, log2; + + /* allocate the peer MAC address -> peer object hash table */ + hash_elems = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + hash_elems *= TXRX_PEER_HASH_LOAD_MULT; + hash_elems >>= TXRX_PEER_HASH_LOAD_SHIFT; + log2 = ol_txrx_log2_ceil(hash_elems); + hash_elems = 1 << log2; + + pdev->peer_hash.mask = hash_elems - 1; + pdev->peer_hash.idx_bits = log2; + /* allocate an array of TAILQ peer object lists */ + pdev->peer_hash.bins = + qdf_mem_malloc(hash_elems * + sizeof(TAILQ_HEAD(anonymous_tail_q, + ol_txrx_peer_t))); + if (!pdev->peer_hash.bins) + return 1; /* failure */ + + for (i = 0; i < hash_elems; i++) + TAILQ_INIT(&pdev->peer_hash.bins[i]); + + return 0; /* success */ +} + +static void ol_txrx_peer_find_hash_detach(struct ol_txrx_pdev_t *pdev) +{ + qdf_mem_free(pdev->peer_hash.bins); +} + +static inline unsigned int +ol_txrx_peer_find_hash_index(struct ol_txrx_pdev_t *pdev, + union ol_txrx_align_mac_addr_t *mac_addr) +{ + unsigned int index; + + index = + mac_addr->align2.bytes_ab ^ + mac_addr->align2.bytes_cd ^ mac_addr->align2.bytes_ef; + index ^= index >> pdev->peer_hash.idx_bits; + index &= pdev->peer_hash.mask; + return index; +} + +void +ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + unsigned int index; + + index = ol_txrx_peer_find_hash_index(pdev, &peer->mac_addr); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + /* + * It is important to add the new peer at the tail of the peer list + * with the bin index. Together with having the hash_find function + * search from head to tail, this ensures that if two entries with + * the same MAC address are stored, the one added first will be + * found first. + */ + TAILQ_INSERT_TAIL(&pdev->peer_hash.bins[index], peer, hash_list_elem); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); +} + +struct ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid) +{ + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + unsigned int index; + struct ol_txrx_peer_t *peer; + + if (mac_addr_is_aligned) { + mac_addr = (union ol_txrx_align_mac_addr_t *)peer_mac_addr; + } else { + qdf_mem_copy(&local_mac_addr_aligned.raw[0], + peer_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + } + index = ol_txrx_peer_find_hash_index(pdev, mac_addr); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[index], hash_list_elem) { + if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == + 0 && (check_valid == 0 || peer->valid) + && peer->vdev == vdev) { + /* found it */ + ol_txrx_peer_get_ref(peer, PEER_DEBUG_ID_OL_INTERNAL); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return peer; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; /* failure */ +} + +struct ol_txrx_peer_t * + ol_txrx_peer_find_hash_find_get_ref + (struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + u8 check_valid, + enum peer_debug_id_type dbg_id) +{ + union ol_txrx_align_mac_addr_t local_mac_addr_aligned, *mac_addr; + unsigned int index; + struct ol_txrx_peer_t *peer; + + if (mac_addr_is_aligned) { + mac_addr = (union ol_txrx_align_mac_addr_t *)peer_mac_addr; + } else { + qdf_mem_copy(&local_mac_addr_aligned.raw[0], + peer_mac_addr, QDF_MAC_ADDR_SIZE); + mac_addr = &local_mac_addr_aligned; + } + index = ol_txrx_peer_find_hash_index(pdev, mac_addr); + qdf_spin_lock_bh(&pdev->peer_ref_mutex); + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[index], hash_list_elem) { + if (ol_txrx_peer_find_mac_addr_cmp(mac_addr, &peer->mac_addr) == + 0 && (check_valid == 0 || peer->valid)) { + /* found it */ + ol_txrx_peer_get_ref(peer, dbg_id); + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return peer; + } + } + qdf_spin_unlock_bh(&pdev->peer_ref_mutex); + return NULL; /* failure */ +} + +void +ol_txrx_peer_find_hash_remove(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer) +{ + unsigned int index; + + index = ol_txrx_peer_find_hash_index(pdev, &peer->mac_addr); + /* + * DO NOT take the peer_ref_mutex lock here - it needs to be taken + * by the caller. + * The caller needs to hold the lock from the time the peer object's + * reference count is decremented and tested up through the time the + * reference to the peer object is removed from the hash table, by + * this function. + * Holding the lock only while removing the peer object reference + * from the hash table keeps the hash table consistent, but does not + * protect against a new HL tx context starting to use the peer object + * if it looks up the peer object from its MAC address just after the + * peer ref count is decremented to zero, but just before the peer + * object reference is removed from the hash table. + */ + /* qdf_spin_lock_bh(&pdev->peer_ref_mutex); */ + TAILQ_REMOVE(&pdev->peer_hash.bins[index], peer, hash_list_elem); + /* qdf_spin_unlock_bh(&pdev->peer_ref_mutex); */ +} + +void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev) +{ + unsigned int i; + /* + * Not really necessary to take peer_ref_mutex lock - by this point, + * it's known that the pdev is no longer in use. + */ + + for (i = 0; i <= pdev->peer_hash.mask; i++) { + if (!TAILQ_EMPTY(&pdev->peer_hash.bins[i])) { + struct ol_txrx_peer_t *peer, *peer_next; + + /* + * TAILQ_FOREACH_SAFE must be used here to avoid any + * memory access violation after peer is freed + */ + TAILQ_FOREACH_SAFE(peer, &pdev->peer_hash.bins[i], + hash_list_elem, peer_next) { + /* + * Don't remove the peer from the hash table - + * that would modify the list we are currently + * traversing, + * and it's not necessary anyway. + */ + /* + * Artificially adjust the peer's ref count to + * 1, so it will get deleted by + * ol_txrx_peer_release_ref. + */ + qdf_atomic_init(&peer->ref_cnt); /* set to 0 */ + ol_txrx_peer_get_ref(peer, + PEER_DEBUG_ID_OL_HASH_ERS); + ol_txrx_peer_release_ref(peer, + PEER_DEBUG_ID_OL_HASH_ERS); + } + } + } +} + +void ol_txrx_peer_free_inactive_list(struct ol_txrx_pdev_t *pdev) +{ + struct ol_txrx_peer_t *peer = NULL, *tmp; + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + if (!TAILQ_EMPTY(&pdev->inactive_peer_list)) { + TAILQ_FOREACH_SAFE(peer, &pdev->inactive_peer_list, + inactive_peer_list_elem, tmp) { + qdf_atomic_init(&peer->del_ref_cnt); /* set to 0 */ + qdf_mem_free(peer); + } + } + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); +} + +/*=== function definitions for peer id --> peer object map ==================*/ + +static int ol_txrx_peer_find_map_attach(struct ol_txrx_pdev_t *pdev) +{ + int max_peers, peer_map_size; + + /* allocate the peer ID -> peer object map */ + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + peer_map_size = max_peers * sizeof(pdev->peer_id_to_obj_map[0]); + pdev->peer_id_to_obj_map = qdf_mem_malloc(peer_map_size); + if (!pdev->peer_id_to_obj_map) + return 1; /* failure */ + + return 0; /* success */ +} + +static void ol_txrx_peer_find_map_detach(struct ol_txrx_pdev_t *pdev) +{ + qdf_mem_free(pdev->peer_id_to_obj_map); +} + +/** + * ol_txrx_peer_clear_map_peer() - Remove map entries that refer to a peer. + * @pdev: pdev handle + * @peer: peer for removing obj map entries + * + * Run through the entire peer_id_to_obj map and nullify all the entries + * that map to a particular peer. Called before deleting the peer object. + * + * Return: None + */ +void ol_txrx_peer_clear_map_peer(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer) +{ + int max_peers; + int i; + + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + for (i = 0; i < max_peers; i++) { + if (pdev->peer_id_to_obj_map[i].peer == peer) { + /* Found a map entry for this peer, clear it. */ + pdev->peer_id_to_obj_map[i].peer = NULL; + } + } + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); +} + +/* + * ol_txrx_peer_find_add_id() - Add peer_id entry to peer + * + * @pdev: Handle to pdev object + * @peer_mac_addr: MAC address of peer provided by firmware + * @peer_id: peer_id provided by firmware + * + * Search for peer object for the MAC address, add the peer_id to + * its array of peer_id's and update the peer_id_to_obj map entry + * for that peer_id. Increment corresponding reference counts. + * + * Riva/Pronto has one peer id for each peer. + * Peregrine/Rome has two peer id for each peer. + * iHelium has upto three peer id for each peer. + * + * Return: None + */ +static inline void ol_txrx_peer_find_add_id(struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + int status; + int i; + uint32_t peer_id_ref_cnt; + uint32_t peer_ref_cnt; + u8 check_valid = 0; + + if (pdev->enable_peer_unmap_conf_support) + check_valid = 1; + + /* check if there's already a peer object with this MAC address */ + peer = + ol_txrx_peer_find_hash_find_get_ref(pdev, peer_mac_addr, + 1 /* is aligned */, + check_valid, + PEER_DEBUG_ID_OL_PEER_MAP); + + if (!peer || peer_id == HTT_INVALID_PEER) { + /* + * Currently peer IDs are assigned for vdevs as well as peers. + * If the peer ID is for a vdev, then we will fail to find a + * peer with a matching MAC address. + */ + ol_txrx_err("peer not found or peer ID is %d invalid", + peer_id); + wlan_roam_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_MAP_EVENT, + peer_id, peer_mac_addr, + peer, 0, 0); + + return; + } + + qdf_spin_lock(&pdev->peer_map_unmap_lock); + + /* peer's ref count was already incremented by + * peer_find_hash_find + */ + if (!pdev->peer_id_to_obj_map[peer_id].peer) { + pdev->peer_id_to_obj_map[peer_id].peer = peer; + qdf_atomic_init + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + } + qdf_atomic_inc + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + + status = 1; + + /* find a place in peer_id array and insert peer_id */ + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] == HTT_INVALID_PEER) { + peer->peer_ids[i] = peer_id; + status = 0; + break; + } + } + + if (qdf_atomic_read(&peer->fw_create_pending) == 1) { + qdf_atomic_set(&peer->fw_create_pending, 0); + } + + qdf_spin_unlock(&pdev->peer_map_unmap_lock); + + peer_id_ref_cnt = qdf_atomic_read(&pdev-> + peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + peer_ref_cnt = qdf_atomic_read(&peer->ref_cnt); + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_HIGH, + "%s: peer %pK ID %d peer_id[%d] peer_id_ref_cnt %d peer->ref_cnt %d", + __func__, peer, peer_id, i, peer_id_ref_cnt, peer_ref_cnt); + wlan_roam_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_MAP_EVENT, + peer_id, &peer->mac_addr.raw, peer, + peer_id_ref_cnt, + peer_ref_cnt); + + + if (status) { + /* TBDXXX: assert for now */ + qdf_assert(0); + } +} + +/*=== allocation / deallocation function definitions ========================*/ + +int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev) +{ + if (ol_txrx_peer_find_map_attach(pdev)) + return 1; + if (ol_txrx_peer_find_hash_attach(pdev)) { + ol_txrx_peer_find_map_detach(pdev); + return 1; + } + return 0; /* success */ +} + +void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev) +{ + ol_txrx_peer_find_map_detach(pdev); + ol_txrx_peer_find_hash_detach(pdev); +} + +/** + * ol_txrx_peer_unmap_conf_handler() - send peer unmap conf cmd to FW + * @pdev: pdev_handle + * @peer_id: peer_id + * + * Return: None + */ +static inline void +ol_txrx_peer_unmap_conf_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (peer_id == HTT_INVALID_PEER) { + ol_txrx_err( + "invalid peer ID %d\n", peer_id); + return; + } + + qdf_atomic_inc(&pdev->peer_id_to_obj_map[peer_id].peer_id_unmap_cnt); + + if (qdf_atomic_read( + &pdev->peer_id_to_obj_map[peer_id].peer_id_unmap_cnt) == + pdev->peer_id_unmap_ref_cnt) { + ol_txrx_dbg("send unmap conf cmd: peer_id[%d] unmap_cnt[%d]", + peer_id, pdev->peer_id_unmap_ref_cnt); + status = pdev->peer_unmap_sync_cb( + DEBUG_INVALID_VDEV_ID, + 1, &peer_id); + + if (status == QDF_STATUS_SUCCESS || + status == QDF_STATUS_E_BUSY) { + qdf_atomic_init( + &pdev->peer_id_to_obj_map[peer_id].peer_id_unmap_cnt); + } else { + qdf_atomic_set( + &pdev->peer_id_to_obj_map[peer_id].peer_id_unmap_cnt, + OL_TXRX_INVALID_PEER_UNMAP_COUNT); + ol_txrx_err("unable to send unmap conf cmd [%d]", + peer_id); + } + + } +} + +/*=== function definitions for message handling =============================*/ + +#if defined(CONFIG_HL_SUPPORT) + +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, uint8_t *peer_mac_addr, int tx_ready) +{ + ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); + if (!tx_ready) { + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + /* ol_txrx_peer_detach called before peer map arrived*/ + return; + } else { + if (tx_ready) { + int i; + + /* unpause all tx queues now, since the + * target is ready + */ + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); + i++) + ol_txrx_peer_tid_unpause(peer, i); + + } else { + /* walk through paused mgmt queue, + * update tx descriptors + */ + ol_tx_queue_decs_reinit(peer, peer_id); + + /* keep non-mgmt tx queues paused until assoc + * is finished tx queues were paused in + * ol_txrx_peer_attach + */ + /* unpause tx mgmt queue */ + ol_txrx_peer_tid_unpause(peer, + HTT_TX_EXT_TID_MGMT); + } + } + } +} + +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (peer) { + int i; + /* + * Unpause all data tx queues now that the target is ready. + * The mgmt tx queue was not paused, so skip it. + */ + for (i = 0; i < QDF_ARRAY_SIZE(peer->txqs); i++) { + if (i == HTT_TX_EXT_TID_MGMT) + continue; /* mgmt tx queue was not paused */ + + ol_txrx_peer_tid_unpause(peer, i); + } + } +} +#else + +void +ol_rx_peer_map_handler(ol_txrx_pdev_handle pdev, + uint16_t peer_id, + uint8_t vdev_id, + uint8_t *peer_mac_addr, + int tx_ready) +{ + ol_txrx_peer_find_add_id(pdev, peer_mac_addr, peer_id); +} + +void ol_txrx_peer_tx_ready_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ +} + +#endif + +/* + * ol_rx_peer_unmap_handler() - Handle peer unmap event from firmware + * + * @pdev: Handle to pdev pbject + * @peer_id: peer_id unmapped by firmware + * + * Decrement reference count for the peer_id in peer_id_to_obj_map, + * decrement reference count in corresponding peer object and clear the entry + * in peer's peer_ids array. + * In case of unmap events for a peer that is already deleted, just decrement + * del_peer_id_ref_cnt. + * + * Return: None + */ +void ol_rx_peer_unmap_handler(ol_txrx_pdev_handle pdev, uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + int i = 0; + int32_t ref_cnt; + int del_ref_cnt; + + if (peer_id == HTT_INVALID_PEER) { + ol_txrx_err( + "invalid peer ID %d\n", peer_id); + wlan_roam_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, NULL, NULL, 0, 0x100); + return; + } + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + + /* send peer unmap conf cmd to fw for unmapped peer_ids */ + if (pdev->enable_peer_unmap_conf_support && + pdev->peer_unmap_sync_cb) + ol_txrx_peer_unmap_conf_handler(pdev, peer_id); + + if (qdf_atomic_read( + &pdev->peer_id_to_obj_map[peer_id].del_peer_id_ref_cnt)) { + /* This peer_id belongs to a peer already deleted */ + peer = pdev->peer_id_to_obj_map[peer_id].del_peer; + if (qdf_atomic_dec_and_test + (&pdev->peer_id_to_obj_map[peer_id].del_peer_id_ref_cnt)) { + pdev->peer_id_to_obj_map[peer_id].del_peer = NULL; + } + + del_ref_cnt = qdf_atomic_read(&peer->del_ref_cnt); + if (qdf_atomic_dec_and_test(&peer->del_ref_cnt)) { + TAILQ_REMOVE(&pdev->inactive_peer_list, peer, + inactive_peer_list_elem); + qdf_mem_free(peer); + } + del_ref_cnt--; + + ref_cnt = qdf_atomic_read(&pdev->peer_id_to_obj_map[peer_id]. + del_peer_id_ref_cnt); + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + wlan_roam_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, NULL, NULL, ref_cnt, 0x101); + ol_txrx_dbg("peer already deleted, peer_id %d del_ref_cnt:%d del_peer_id_ref_cnt %d", + peer_id, del_ref_cnt, ref_cnt); + return; + } + peer = pdev->peer_id_to_obj_map[peer_id].peer; + + if (!peer) { + /* + * Currently peer IDs are assigned for vdevs as well as peers. + * If the peer ID is for a vdev, then the peer pointer stored + * in peer_id_to_obj_map will be NULL. + */ + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + ol_txrx_info("peer not found for peer_id %d", peer_id); + wlan_roam_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, NULL, NULL, 0, 0x102); + return; + } + + if (qdf_atomic_dec_and_test + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt)) { + pdev->peer_id_to_obj_map[peer_id].peer = NULL; + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (peer->peer_ids[i] == peer_id) { + peer->peer_ids[i] = HTT_INVALID_PEER; + break; + } + } + } + + ref_cnt = qdf_atomic_read + (&pdev->peer_id_to_obj_map[peer_id].peer_id_ref_cnt); + + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + + wlan_roam_debug_log(DEBUG_INVALID_VDEV_ID, + DEBUG_PEER_UNMAP_EVENT, + peer_id, &peer->mac_addr.raw, peer, ref_cnt, + qdf_atomic_read(&peer->ref_cnt)); + + /* + * Remove a reference to the peer. + * If there are no more references, delete the peer object. + */ + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_PEER_MAP); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: peer_id %d peer %pK peer_id_ref_cnt %d", + __func__, peer_id, peer, ref_cnt); +} + +/** + * ol_txrx_peer_remove_obj_map_entries() - Remove matching pdev peer map entries + * @pdev: pdev handle + * @peer: peer for removing obj map entries + * + * Saves peer_id_ref_cnt to a different field and removes the link + * to peer object. It also decrements the peer reference count by + * the number of references removed. + * + * Return: None + */ +void ol_txrx_peer_remove_obj_map_entries(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer) +{ + int i; + uint16_t peer_id; + int32_t peer_id_ref_cnt; + int32_t num_deleted_maps = 0; + uint16_t save_peer_ids[MAX_NUM_PEER_ID_PER_PEER]; + uint16_t save_peer_id_ref_cnt[MAX_NUM_PEER_ID_PER_PEER] = {0}; + + qdf_spin_lock_bh(&pdev->peer_map_unmap_lock); + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + peer_id = peer->peer_ids[i]; + save_peer_ids[i] = HTT_INVALID_PEER; + if (peer_id == HTT_INVALID_PEER || + !pdev->peer_id_to_obj_map[peer_id].peer) { + /* unused peer_id, or object is already dereferenced */ + continue; + } + if (pdev->peer_id_to_obj_map[peer_id].peer != peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_ERROR, + FL("peer pointer mismatch in peer_id_to_obj")); + continue; + } + peer_id_ref_cnt = qdf_atomic_read( + &pdev->peer_id_to_obj_map[peer_id]. + peer_id_ref_cnt); + save_peer_ids[i] = peer_id; + save_peer_id_ref_cnt[i] = peer_id_ref_cnt; + + /* + * Transfer peer_id_ref_cnt into del_peer_id_ref_cnt so that + * ol_txrx_peer_release_ref will decrement del_peer_id_ref_cnt + * and any map events will increment peer_id_ref_cnt. Otherwise + * accounting will be messed up. + * + * Add operation will ensure that back to back roaming in the + * middle of unmap/map event sequence will be accounted for. + */ + qdf_atomic_add(peer_id_ref_cnt, + &pdev->peer_id_to_obj_map[peer_id].del_peer_id_ref_cnt); + qdf_atomic_init(&pdev->peer_id_to_obj_map[peer_id]. + peer_id_ref_cnt); + num_deleted_maps += peer_id_ref_cnt; + pdev->peer_id_to_obj_map[peer_id].peer = NULL; + pdev->peer_id_to_obj_map[peer_id].del_peer = peer; + peer->peer_ids[i] = HTT_INVALID_PEER; + } + qdf_atomic_init(&peer->del_ref_cnt); + if (num_deleted_maps != 0) { + qdf_atomic_add(num_deleted_maps, &peer->del_ref_cnt); + TAILQ_INSERT_TAIL(&pdev->inactive_peer_list, peer, + inactive_peer_list_elem); + } + qdf_spin_unlock_bh(&pdev->peer_map_unmap_lock); + + /* Debug print the information after releasing bh spinlock */ + for (i = 0; i < MAX_NUM_PEER_ID_PER_PEER; i++) { + if (save_peer_ids[i] == HTT_INVALID_PEER) + continue; + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + FL("peer_id = %d, peer_id_ref_cnt = %d, index = %d"), + save_peer_ids[i], save_peer_id_ref_cnt[i], i); + } + + if (num_deleted_maps > qdf_atomic_read(&peer->ref_cnt)) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + FL("num_deleted_maps %d ref_cnt %d"), + num_deleted_maps, qdf_atomic_read(&peer->ref_cnt)); + QDF_BUG(0); + return; + } + + while (num_deleted_maps-- > 0) + ol_txrx_peer_release_ref(peer, PEER_DEBUG_ID_OL_PEER_MAP); +} + +struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev) +{ + struct ol_txrx_peer_t *peer; + + qdf_spin_lock_bh(&vdev->pdev->last_real_peer_mutex); + /* + * Check the TXRX Peer is itself valid And also + * if HTT Peer ID has been setup for this peer + */ + if (vdev->last_real_peer + && vdev->last_real_peer->peer_ids[0] != HTT_INVALID_PEER_ID) { + qdf_spin_lock_bh(&vdev->pdev->peer_ref_mutex); + ol_txrx_peer_get_ref(vdev->last_real_peer, + PEER_DEBUG_ID_OL_INTERNAL); + qdf_spin_unlock_bh(&vdev->pdev->peer_ref_mutex); + peer = vdev->last_real_peer; + } else { + peer = NULL; + } + qdf_spin_unlock_bh(&vdev->pdev->last_real_peer_mutex); + return peer; +} + + +/*=== function definitions for debug ========================================*/ + +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_peer_find_display(ol_txrx_pdev_handle pdev, int indent) +{ + int i, max_peers; + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*speer map:\n", indent, " "); + max_peers = ol_cfg_max_peer_id(pdev->ctrl_pdev) + 1; + for (i = 0; i < max_peers; i++) { + if (pdev->peer_id_to_obj_map[i].peer) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*sid %d -> %pK\n", + indent + 4, " ", i, + pdev->peer_id_to_obj_map[i].peer); + } + } + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO_LOW, + "%*speer hash table:\n", indent, " "); + for (i = 0; i <= pdev->peer_hash.mask; i++) { + if (!TAILQ_EMPTY(&pdev->peer_hash.bins[i])) { + struct ol_txrx_peer_t *peer; + + TAILQ_FOREACH(peer, &pdev->peer_hash.bins[i], + hash_list_elem) { + QDF_TRACE(QDF_MODULE_ID_TXRX, + QDF_TRACE_LEVEL_INFO_LOW, + "%*shash idx %d -> %pK ("QDF_MAC_ADDR_FMT")\n", + indent + 4, " ", i, peer, + QDF_MAC_ADDR_REF(peer->mac_addr.raw)); + } + } + } +} + +#endif /* if TXRX_DEBUG_LEVEL */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h new file mode 100644 index 0000000000..2d926d0749 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_peer_find.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2011, 2015-2019,2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * @file ol_txrx_peer_find.h + * @brief Define the API for the rx peer lookup datapath module. + */ +#ifndef _OL_TXRX_PEER_FIND__H_ +#define _OL_TXRX_PEER_FIND__H_ + +#include /* HTT_INVALID_PEER */ +#include /* ol_txrx_pdev_t, etc. */ +#include /* TXRX_ASSERT */ + +/** + * ol_txrx_peer_get_ref() - get peer reference + * @peer: peer for removing obj map entries + * @dbg_id: debug id to keep track of peer references + * + * The function increments the peer ref count. The ref count can be reduced by + * calling ol_txrx_peer_release_ref function. Callers are responsible for + * acquiring the peer_ref_mutex lock when needed. + * + * Return: peer debug id ref count or error + */ +int +ol_txrx_peer_get_ref(struct ol_txrx_peer_t *peer, + enum peer_debug_id_type dbg_id); + +int ol_txrx_peer_find_attach(struct ol_txrx_pdev_t *pdev); + +void ol_txrx_peer_find_detach(struct ol_txrx_pdev_t *pdev); + +static inline +int +ol_txrx_peer_find_mac_addr_cmp(union ol_txrx_align_mac_addr_t *mac_addr1, + union ol_txrx_align_mac_addr_t *mac_addr2) +{ + return !((mac_addr1->align4.bytes_abcd == mac_addr2->align4.bytes_abcd) + /* + * Intentionally use & rather than &&. + * because the operands are binary rather than generic bool, + * the functionality is equivalent. + * Using && has the advantage of short-circuited evaluation, + * but using & has the advantage of no conditional branching, + * which is a more significant benefit. + */ + & (mac_addr1->align4.bytes_ef == mac_addr2->align4.bytes_ef)); +} + +static inline +struct ol_txrx_peer_t *ol_txrx_peer_find_by_id(struct ol_txrx_pdev_t *pdev, + uint16_t peer_id) +{ + struct ol_txrx_peer_t *peer; + + peer = (peer_id > ol_cfg_max_peer_id(pdev->ctrl_pdev)) ? NULL : + pdev->peer_id_to_obj_map[peer_id].peer; + /* + * Currently, peer IDs are assigned to vdevs as well as peers. + * If the peer ID is for a vdev, the peer_id_to_obj_map entry + * will hold NULL rather than a valid peer pointer. + */ + /* TXRX_ASSERT2(peer); */ + /* + * Only return the peer object if it is valid, + * i.e. it has not already been detached. + * If it has already been detached, then returning the + * peer object could result in unpausing the peer's tx queues + * in HL systems, which is an invalid operation following peer_detach. + */ + if (peer && peer->valid) + return peer; + + return NULL; +} + +void +ol_txrx_peer_find_hash_add(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +struct ol_txrx_peer_t * + ol_txrx_peer_find_hash_find_get_ref + (struct ol_txrx_pdev_t *pdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + u8 check_valid, + enum peer_debug_id_type dbg_id); + +struct +ol_txrx_peer_t *ol_txrx_peer_vdev_find_hash(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_vdev_t *vdev, + uint8_t *peer_mac_addr, + int mac_addr_is_aligned, + uint8_t check_valid); + +void +ol_txrx_peer_find_hash_remove(struct ol_txrx_pdev_t *pdev, + struct ol_txrx_peer_t *peer); + +void ol_txrx_peer_find_hash_erase(struct ol_txrx_pdev_t *pdev); + +void ol_txrx_peer_free_inactive_list(struct ol_txrx_pdev_t *pdev); + +struct ol_txrx_peer_t *ol_txrx_assoc_peer_find(struct ol_txrx_vdev_t *vdev); +void ol_txrx_peer_remove_obj_map_entries(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer); +void ol_txrx_peer_clear_map_peer(ol_txrx_pdev_handle pdev, + struct ol_txrx_peer_t *peer); +#if defined(TXRX_DEBUG_LEVEL) && TXRX_DEBUG_LEVEL > 5 +void ol_txrx_peer_find_display(ol_txrx_pdev_handle pdev, int indent); +#else +#define ol_txrx_peer_find_display(pdev, indent) +#endif /* TXRX_DEBUG_LEVEL */ + +#endif /* _OL_TXRX_PEER_FIND__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_types.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_types.h new file mode 100644 index 0000000000..feb42e5559 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/ol_txrx_types.h @@ -0,0 +1,1571 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: ol_txrx_types.h + * Define the major data types used internally by the host datapath SW. + */ +#ifndef _OL_TXRX_TYPES__H_ +#define _OL_TXRX_TYPES__H_ + +#include /* qdf_nbuf_t */ +#include +#include "queue.h" /* TAILQ */ +#include /* A_UINT8 */ +#include /* htt_sec_type, htt_pkt_type, etc. */ +#include /* qdf_atomic_t */ +#include /* wdi_event_subscribe */ +#include /* qdf_timer_t */ +#include /* qdf_spinlock */ +#include +#include "ol_txrx_htt_api.h" +#include "ol_htt_tx_api.h" +#include "ol_htt_rx_api.h" +#include "ol_txrx_ctrl_api.h" /* WLAN_MAX_STA_COUNT */ +#include "ol_txrx_osif_api.h" /* ol_rx_callback */ +#include "cdp_txrx_flow_ctrl_v2.h" +#include "cdp_txrx_peer_ops.h" +#include +#include "qdf_hrtimer.h" + +/* + * The target may allocate multiple IDs for a peer. + * In particular, the target may allocate one ID to represent the + * multicast key the peer uses, and another ID to represent the + * unicast key the peer uses. + */ +#define MAX_NUM_PEER_ID_PER_PEER 16 + +/* OL_TXRX_NUM_EXT_TIDS - + * 16 "real" TIDs + 3 pseudo-TIDs for mgmt, mcast/bcast & non-QoS data + */ +#define OL_TXRX_NUM_EXT_TIDS 19 + +#define OL_TX_NUM_QOS_TIDS 16 /* 16 regular TIDs */ +#define OL_TX_NON_QOS_TID 16 +#define OL_TX_MGMT_TID 17 +#define OL_TX_NUM_TIDS 18 +#define OL_RX_MCAST_TID 18 /* Mcast TID only between f/w & host */ + +#define OL_TX_VDEV_MCAST_BCAST 0 /* HTT_TX_EXT_TID_MCAST_BCAST */ +#define OL_TX_VDEV_DEFAULT_MGMT 1 /* HTT_TX_EXT_TID_DEFALT_MGMT */ +#define OL_TX_VDEV_NUM_QUEUES 2 + +#define OL_TXRX_MGMT_TYPE_BASE htt_pkt_num_types +#define OL_TXRX_MGMT_NUM_TYPES 8 + +#define OL_TX_MUTEX_TYPE qdf_spinlock_t +#define OL_RX_MUTEX_TYPE qdf_spinlock_t + +/* TXRX Histogram defines */ +#define TXRX_DATA_HISTROGRAM_GRANULARITY 1000 +#define TXRX_DATA_HISTROGRAM_NUM_INTERVALS 100 + +#define OL_TXRX_INVALID_VDEV_ID (-1) +#define ETHERTYPE_OCB_TX 0x8151 +#define ETHERTYPE_OCB_RX 0x8152 + +#define OL_TXRX_MAX_PDEV_CNT 1 + +struct ol_txrx_pdev_t; +struct ol_txrx_vdev_t; +struct ol_txrx_peer_t; + +/* rx filter related */ +#define MAX_PRIVACY_FILTERS 4 /* max privacy filters */ + +enum privacy_filter { + PRIVACY_FILTER_ALWAYS, + PRIVACY_FILTER_KEY_UNAVAILABLE, +}; + +enum privacy_filter_packet_type { + PRIVACY_FILTER_PACKET_UNICAST, + PRIVACY_FILTER_PACKET_MULTICAST, + PRIVACY_FILTER_PACKET_BOTH +}; + +struct privacy_exemption { + /* ethertype - + * type of ethernet frames this filter applies to, in host byte order + */ + uint16_t ether_type; + enum privacy_filter filter_type; + enum privacy_filter_packet_type packet_type; +}; + +enum ol_tx_frm_type { + OL_TX_FRM_STD = 0, /* regular frame - no added header fragments */ + OL_TX_FRM_TSO, /* TSO segment, with a modified IP header added */ + OL_TX_FRM_AUDIO, /* audio frames, with a custom LLC/SNAP hdr added */ + OL_TX_FRM_NO_FREE, /* frame requires special tx completion callback */ + ol_tx_frm_freed = 0xff, /* the tx desc is in free list */ +}; + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +#define MAX_NO_PEERS_IN_LIMIT (2*10 + 2) + +enum ol_tx_peer_bal_state { + ol_tx_peer_bal_enable = 0, + ol_tx_peer_bal_disable, +}; + +enum ol_tx_peer_bal_timer_state { + ol_tx_peer_bal_timer_disable = 0, + ol_tx_peer_bal_timer_active, + ol_tx_peer_bal_timer_inactive, +}; + +struct ol_tx_limit_peer_t { + u_int16_t limit_flag; + u_int16_t peer_id; + u_int16_t limit; +}; + +enum tx_peer_level { + TXRX_IEEE11_B = 0, + TXRX_IEEE11_A_G, + TXRX_IEEE11_N, + TXRX_IEEE11_AC, + TXRX_IEEE11_AX, + TXRX_IEEE11_MAX, +}; + +struct tx_peer_threshold { + u_int32_t tput_thresh; + u_int32_t tx_limit; +}; +#endif + + +struct ol_tx_desc_t { + qdf_nbuf_t netbuf; + void *htt_tx_desc; + uint16_t id; + qdf_dma_addr_t htt_tx_desc_paddr; + void *htt_frag_desc; /* struct msdu_ext_desc_t * */ + qdf_dma_addr_t htt_frag_desc_paddr; + qdf_atomic_t ref_cnt; + enum htt_tx_status status; + +#ifdef QCA_COMPUTE_TX_DELAY + uint32_t entry_timestamp_ticks; +#endif + +#ifdef DESC_TIMESTAMP_DEBUG_INFO + struct { + uint64_t prev_tx_ts; + uint64_t curr_tx_ts; + uint64_t last_comp_ts; + } desc_debug_info; +#endif + + /* + * Allow tx descriptors to be stored in (doubly-linked) lists. + * This is mainly used for HL tx queuing and scheduling, but is + * also used by LL+HL for batch processing of tx frames. + */ + TAILQ_ENTRY(ol_tx_desc_t) tx_desc_list_elem; + + /* + * Remember whether the tx frame is a regular packet, or whether + * the driver added extra header fragments (e.g. a modified IP header + * for TSO fragments, or an added LLC/SNAP header for audio interworking + * data) that need to be handled in a special manner. + * This field is filled in with the ol_tx_frm_type enum. + */ + uint8_t pkt_type; + + u_int8_t vdev_id; + + struct ol_txrx_vdev_t *vdev; + + void *txq; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* + * used by tx encap, to restore the os buf start offset + * after tx complete + */ + uint8_t orig_l2_hdr_bytes; +#endif + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + struct ol_tx_flow_pool_t *pool; +#endif + void *tso_desc; + void *tso_num_desc; +}; + +typedef TAILQ_HEAD(some_struct_name, ol_tx_desc_t) ol_tx_desc_list; + +union ol_tx_desc_list_elem_t { + union ol_tx_desc_list_elem_t *next; + struct ol_tx_desc_t tx_desc; +}; + +union ol_txrx_align_mac_addr_t { + uint8_t raw[QDF_MAC_ADDR_SIZE]; + struct { + uint16_t bytes_ab; + uint16_t bytes_cd; + uint16_t bytes_ef; + } align2; + struct { + uint32_t bytes_abcd; + uint16_t bytes_ef; + } align4; +}; + +struct ol_rx_reorder_timeout_list_elem_t { + TAILQ_ENTRY(ol_rx_reorder_timeout_list_elem_t) + reorder_timeout_list_elem; + uint32_t timestamp_ms; + struct ol_txrx_peer_t *peer; + uint8_t tid; + uint8_t active; +}; + +/* wait on peer deletion timeout value in milliseconds */ +#define PEER_DELETION_TIMEOUT 500 + +enum txrx_wmm_ac { + TXRX_WMM_AC_BE, + TXRX_WMM_AC_BK, + TXRX_WMM_AC_VI, + TXRX_WMM_AC_VO, + + TXRX_NUM_WMM_AC +}; + +#define TXRX_TID_TO_WMM_AC(_tid) ( \ + (((_tid) >> 1) == 3) ? TXRX_WMM_AC_VO : \ + (((_tid) >> 1) == 2) ? TXRX_WMM_AC_VI : \ + (((_tid) ^ ((_tid) >> 1)) & 0x1) ? TXRX_WMM_AC_BK : \ + TXRX_WMM_AC_BE) + +enum { + OL_TX_SCHED_WRR_ADV_CAT_BE, + OL_TX_SCHED_WRR_ADV_CAT_BK, + OL_TX_SCHED_WRR_ADV_CAT_VI, + OL_TX_SCHED_WRR_ADV_CAT_VO, + OL_TX_SCHED_WRR_ADV_CAT_NON_QOS_DATA, + OL_TX_SCHED_WRR_ADV_CAT_UCAST_MGMT, + OL_TX_SCHED_WRR_ADV_CAT_MCAST_DATA, + OL_TX_SCHED_WRR_ADV_CAT_MCAST_MGMT, + + OL_TX_SCHED_WRR_ADV_NUM_CATEGORIES /* must be last */ +}; + +A_COMPILE_TIME_ASSERT(ol_tx_sched_htt_ac_values, + /* check that regular WMM AC enum values match */ + ((int)OL_TX_SCHED_WRR_ADV_CAT_VO == (int)HTT_AC_WMM_VO) && + ((int)OL_TX_SCHED_WRR_ADV_CAT_VI == (int)HTT_AC_WMM_VI) && + ((int)OL_TX_SCHED_WRR_ADV_CAT_BK == (int)HTT_AC_WMM_BK) && + ((int)OL_TX_SCHED_WRR_ADV_CAT_BE == (int)HTT_AC_WMM_BE) && + + /* check that extension AC enum values match */ + ((int)OL_TX_SCHED_WRR_ADV_CAT_NON_QOS_DATA + == (int)HTT_AC_EXT_NON_QOS) && + ((int)OL_TX_SCHED_WRR_ADV_CAT_UCAST_MGMT + == (int)HTT_AC_EXT_UCAST_MGMT) && + ((int)OL_TX_SCHED_WRR_ADV_CAT_MCAST_DATA + == (int)HTT_AC_EXT_MCAST_DATA) && + ((int)OL_TX_SCHED_WRR_ADV_CAT_MCAST_MGMT + == (int)HTT_AC_EXT_MCAST_MGMT)); + +struct ol_tx_reorder_cat_timeout_t { + TAILQ_HEAD(, ol_rx_reorder_timeout_list_elem_t) virtual_timer_list; + qdf_timer_t timer; + uint32_t duration_ms; + struct ol_txrx_pdev_t *pdev; +}; + +enum ol_tx_scheduler_status { + ol_tx_scheduler_idle = 0, + ol_tx_scheduler_running, +}; + +enum ol_tx_queue_status { + ol_tx_queue_empty = 0, + ol_tx_queue_active, + ol_tx_queue_paused, +}; + +struct ol_txrx_msdu_info_t { + struct htt_msdu_info_t htt; + struct ol_txrx_peer_t *peer; + struct qdf_tso_info_t tso_info; +}; + +enum { + ol_tx_aggr_untried = 0, + ol_tx_aggr_enabled, + ol_tx_aggr_disabled, + ol_tx_aggr_retry, + ol_tx_aggr_in_progress, +}; + +#define OL_TX_MAX_GROUPS_PER_QUEUE 1 +#define OL_TX_MAX_VDEV_ID 16 +#define OL_TXQ_GROUP_VDEV_ID_MASK_GET(_membership) \ + (((_membership) & 0xffff0000) >> 16) +#define OL_TXQ_GROUP_VDEV_ID_BIT_MASK_GET(_mask, _vdev_id) \ + ((_mask >> _vdev_id) & 0x01) +#define OL_TXQ_GROUP_AC_MASK_GET(_membership) \ + ((_membership) & 0x0000ffff) +#define OL_TXQ_GROUP_AC_BIT_MASK_GET(_mask, _ac_mask) \ + ((_mask >> _ac_mask) & 0x01) +#define OL_TXQ_GROUP_MEMBERSHIP_GET(_vdev_mask, _ac_mask) \ + ((_vdev_mask << 16) | _ac_mask) + +struct ol_tx_frms_queue_t { + /* list_elem - + * Allow individual tx frame queues to be linked together into + * scheduler queues of tx frame queues + */ + TAILQ_ENTRY(ol_tx_frms_queue_t) list_elem; + uint8_t aggr_state; + struct { + uint8_t total; + /* pause requested by ctrl SW rather than txrx SW */ + uint8_t by_ctrl; + } paused_count; + uint8_t ext_tid; + uint16_t frms; + uint32_t bytes; + ol_tx_desc_list head; + enum ol_tx_queue_status flag; + struct ol_tx_queue_group_t *group_ptrs[OL_TX_MAX_GROUPS_PER_QUEUE]; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + struct ol_txrx_peer_t *peer; +#endif +}; + +enum { + ol_tx_log_entry_type_invalid, + ol_tx_log_entry_type_queue_state, + ol_tx_log_entry_type_enqueue, + ol_tx_log_entry_type_dequeue, + ol_tx_log_entry_type_drop, + ol_tx_log_entry_type_queue_free, + + ol_tx_log_entry_type_wrap, +}; + +struct ol_tx_log_queue_state_var_sz_t { + uint32_t active_bitmap; + uint16_t credit; + uint8_t num_cats_active; + uint8_t data[1]; +}; + +struct ol_tx_log_queue_add_t { + uint8_t num_frms; + uint8_t tid; + uint16_t peer_id; + uint16_t num_bytes; +}; + +struct ol_mac_addr { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; +}; + +struct ol_tx_sched_t; + +#ifndef ol_txrx_local_peer_id_t +#define ol_txrx_local_peer_id_t uint8_t /* default */ +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +/* + * Delay histogram bins: 16 bins of 10 ms each to count delays + * from 0-160 ms, plus one overflow bin for delays > 160 ms. + */ +#define QCA_TX_DELAY_HIST_INTERNAL_BINS 17 +#define QCA_TX_DELAY_HIST_INTERNAL_BIN_WIDTH_MS 10 + +struct ol_tx_delay_data { + struct { + uint64_t transmit_sum_ticks; + uint64_t queue_sum_ticks; + uint32_t transmit_num; + uint32_t queue_num; + } avgs; + uint16_t hist_bins_queue[QCA_TX_DELAY_HIST_INTERNAL_BINS]; +}; + +#endif /* QCA_COMPUTE_TX_DELAY */ + +/* Thermal Mitigation */ +enum throttle_phase { + THROTTLE_PHASE_OFF, + THROTTLE_PHASE_ON, + /* Invalid */ + THROTTLE_PHASE_MAX, +}; + +#define THROTTLE_TX_THRESHOLD (100) + +/* + * Threshold to stop/start priority queue in term of % the actual flow start + * and stop thresholds. When num of available descriptors falls below + * stop_priority_th, priority queue will be paused. When num of available + * descriptors are greater than start_priority_th, priority queue will be + * un-paused. + */ +#define TX_PRIORITY_TH (80) + +/* + * No of maximum descriptor used by TSO jumbo packet with + * 64K aggregation. + */ +#define MAX_TSO_SEGMENT_DESC (44) + +struct ol_tx_queue_group_t { + qdf_atomic_t credit; + u_int32_t membership; + int frm_count; +}; +#define OL_TX_MAX_TXQ_GROUPS 2 + +#define OL_TX_GROUP_STATS_LOG_SIZE 128 +struct ol_tx_group_credit_stats_t { + struct { + struct { + u_int16_t member_vdevs; + u_int16_t credit; + } grp[OL_TX_MAX_TXQ_GROUPS]; + } stats[OL_TX_GROUP_STATS_LOG_SIZE]; + u_int16_t last_valid_index; + u_int16_t wrap_around; +}; + + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/** + * enum flow_pool_status - flow pool status + * @FLOW_POOL_ACTIVE_UNPAUSED : pool is active (can take/put descriptors) + * and network queues are unpaused + * @FLOW_POOL_ACTIVE_PAUSED: pool is active (can take/put descriptors) + * and network queues are paused + * @FLOW_POOL_INVALID: pool is invalid (put descriptor) + * @FLOW_POOL_INACTIVE: pool is inactive (pool is free) + * @FLOW_POOL_NON_PRIO_PAUSED: non-priority queues are paused + */ +enum flow_pool_status { + FLOW_POOL_ACTIVE_UNPAUSED = 0, + FLOW_POOL_ACTIVE_PAUSED = 1, + FLOW_POOL_NON_PRIO_PAUSED = 2, + FLOW_POOL_INVALID = 3, + FLOW_POOL_INACTIVE = 4 +}; + +/** + * struct ol_txrx_pool_stats - flow pool related statistics + * @pool_map_count: flow pool map received + * @pool_unmap_count: flow pool unmap received + * @pool_resize_count: flow pool resize command received + * @pkt_drop_no_pool: packets dropped due to unavailablity of pool + */ +struct ol_txrx_pool_stats { + uint16_t pool_map_count; + uint16_t pool_unmap_count; + uint16_t pool_resize_count; + uint16_t pkt_drop_no_pool; +}; + +/** + * struct ol_tx_flow_pool_t - flow_pool info + * @flow_pool_list_elem: flow_pool_list element + * @flow_pool_lock: flow_pool lock + * @flow_pool_id: flow_pool id + * @flow_pool_size: flow_pool size + * @avail_desc: available descriptors + * @deficient_desc: deficient descriptors + * @overflow_desc: overflow descriptors + * @status: flow pool status + * @flow_type: flow pool type + * @member_flow_id: member flow id + * @stop_th: stop threshold + * @start_th: start threshold + * @freelist: tx descriptor freelist + * @pkt_drop_no_desc: drop due to no descriptors + * @ref_cnt: pool's ref count + * @stop_priority_th: Threshold to stop priority queue + * @start_priority_th: Threshold to start priority queue + */ +struct ol_tx_flow_pool_t { + TAILQ_ENTRY(ol_tx_flow_pool_t) flow_pool_list_elem; + qdf_spinlock_t flow_pool_lock; + uint8_t flow_pool_id; + uint16_t flow_pool_size; + uint16_t avail_desc; + uint16_t deficient_desc; + uint16_t overflow_desc; + enum flow_pool_status status; + enum htt_flow_type flow_type; + uint8_t member_flow_id; + uint16_t stop_th; + uint16_t start_th; + union ol_tx_desc_list_elem_t *freelist; + uint16_t pkt_drop_no_desc; + qdf_atomic_t ref_cnt; + uint16_t stop_priority_th; + uint16_t start_priority_th; +}; +#endif + +#define OL_TXRX_INVALID_PEER_UNMAP_COUNT 0xF +/* + * struct ol_txrx_peer_id_map - Map of firmware peer_ids to peers on host + * @peer: Pointer to peer object + * @peer_id_ref_cnt: No. of firmware references to the peer_id + * @del_peer_id_ref_cnt: No. of outstanding unmap events for peer_id + * after the peer object is deleted on the host. + * + * peer_id is used as an index into the array of ol_txrx_peer_id_map. + */ +struct ol_txrx_peer_id_map { + struct ol_txrx_peer_t *peer; + struct ol_txrx_peer_t *del_peer; + qdf_atomic_t peer_id_ref_cnt; + qdf_atomic_t del_peer_id_ref_cnt; + qdf_atomic_t peer_id_unmap_cnt; +}; + +/* + * ol_txrx_stats_req_internal - specifications of the requested + * statistics internally + */ +struct ol_txrx_stats_req_internal { + struct ol_txrx_stats_req base; + TAILQ_ENTRY(ol_txrx_stats_req_internal) req_list_elem; + int serviced; /* state of this request */ + int offset; +}; + +struct ol_txrx_fw_stats_desc_t { + struct ol_txrx_stats_req_internal *req; + unsigned char desc_id; +}; + +struct ol_txrx_fw_stats_desc_elem_t { + struct ol_txrx_fw_stats_desc_elem_t *next; + struct ol_txrx_fw_stats_desc_t desc; +}; + +/** + * struct ol_txrx_soc_t - soc reference structure + * @cdp_soc: common base structure + * @psoc: opaque handle for UMAC psoc object + * @pdev_list: list of all the pdev on a soc + * + * This is the reference to the soc and all the data + * which is soc specific. + */ +struct ol_txrx_soc_t { + /* Common base structure - Should be the first member */ + struct cdp_soc_t cdp_soc; + + struct cdp_ctrl_objmgr_psoc *psoc; + struct ol_txrx_pdev_t *pdev_list[OL_TXRX_MAX_PDEV_CNT]; +}; + +/* + * As depicted in the diagram below, the pdev contains an array of + * NUM_EXT_TID ol_tx_active_queues_in_tid_t elements. + * Each element identifies all the tx queues that are active for + * the TID, from the different peers. + * + * Each peer contains an array of NUM_EXT_TID ol_tx_frms_queue_t elements. + * Each element identifies the tx frames for the TID that need to be sent + * to the peer. + * + * + * pdev: ol_tx_active_queues_in_tid_t active_in_tids[NUM_EXT_TIDS] + * TID + * 0 1 2 17 + * +============+============+============+== ==+============+ + * | active (y) | active (n) | active (n) | | active (y) | + * |------------+------------+------------+-- --+------------| + * | queues | queues | queues | | queues | + * +============+============+============+== ==+============+ + * | | + * .--+-----------------------------------------------' + * | | + * | | peer X: peer Y: + * | | ol_tx_frms_queue_t ol_tx_frms_queue_t + * | | tx_queues[NUM_EXT_TIDS] tx_queues[NUM_EXT_TIDS] + * | | TID +======+ TID +======+ + * | `---->| next |-------------------------->| next |--X + * | 0 | prev | .------. .------. 0 | prev | .------. + * | | txq |-->|txdesc|-->|txdesc| | txq |-->|txdesc| + * | +======+ `------' `------' +======+ `------' + * | | next | | | 1 | next | | + * | 1 | prev | v v | prev | v + * | | txq | .------. .------. | txq | .------. + * | +======+ |netbuf| |netbuf| +======+ |netbuf| + * | | next | `------' `------' | next | `------' + * | 2 | prev | 2 | prev | + * | | txq | | txq | + * | +======+ +======+ + * | | | | | + * | + * | + * | | | | | + * | +======+ +======+ + * `------->| next |--X | next | + * 17 | prev | .------. 17 | prev | + * | txq |-->|txdesc| | txq | + * +======+ `------' +======+ + * | + * v + * .------. + * |netbuf| + * `------' + */ +struct ol_txrx_pdev_t { + /* soc - reference to soc structure */ + struct ol_txrx_soc_t *soc; + + /* ctrl_pdev - handle for querying config info */ + struct cdp_cfg *ctrl_pdev; + + /* osdev - handle for mem alloc / free, map / unmap */ + qdf_device_t osdev; + + htt_pdev_handle htt_pdev; + +#ifdef WLAN_FEATURE_FASTPATH + struct CE_handle *ce_tx_hdl; /* Handle to Tx packet posting CE */ + struct CE_handle *ce_htt_msg_hdl; /* Handle to TxRx completion CE */ +#endif /* WLAN_FEATURE_FASTPATH */ + + struct { + int is_high_latency; + int host_addba; + int ll_pause_txq_limit; + int default_tx_comp_req; + u8 credit_update_enabled; + u8 request_tx_comp; + } cfg; + + /* WDI subscriber's event list */ + wdi_event_subscribe **wdi_event_list; + +#if !defined(REMOVE_PKT_LOG) && !defined(QVIT) + bool pkt_log_init; + /* Pktlog pdev */ + struct pktlog_dev_t *pl_dev; +#endif /* #ifndef REMOVE_PKT_LOG */ + + /* Monitor mode interface*/ + struct ol_txrx_vdev_t *monitor_vdev; + + enum ol_sec_type sec_types[htt_num_sec_types]; + /* standard frame type */ + enum wlan_frm_fmt frame_format; + enum htt_pkt_type htt_pkt_type; + +#ifdef QCA_SUPPORT_SW_TXRX_ENCAP + /* txrx encap/decap */ + uint8_t sw_tx_encap; + uint8_t sw_rx_decap; + uint8_t target_tx_tran_caps; + uint8_t target_rx_tran_caps; + /* llc process */ + uint8_t sw_tx_llc_proc_enable; + uint8_t sw_rx_llc_proc_enable; + /* A-MSDU */ + uint8_t sw_subfrm_hdr_recovery_enable; + /* Protected Frame bit handling */ + uint8_t sw_pf_proc_enable; +#endif + /* + * target tx credit - + * not needed for LL, but used for HL download scheduler to keep + * track of roughly how much space is available in the target for + * tx frames + */ + qdf_atomic_t target_tx_credit; + qdf_atomic_t orig_target_tx_credit; + + /* + * needed for SDIO HL, Genoa Adma + */ + qdf_atomic_t pad_reserve_tx_credit; + + struct { + uint16_t pool_size; + struct ol_txrx_fw_stats_desc_elem_t *pool; + struct ol_txrx_fw_stats_desc_elem_t *freelist; + qdf_spinlock_t pool_lock; + qdf_atomic_t initialized; + } ol_txrx_fw_stats_desc_pool; + + /* Peer mac address to staid mapping */ + struct ol_mac_addr mac_to_staid[WLAN_MAX_STA_COUNT + 3]; + + /* ol_txrx_vdev list */ + TAILQ_HEAD(, ol_txrx_vdev_t) vdev_list; + + /* Inactive peer list */ + TAILQ_HEAD(, ol_txrx_peer_t) inactive_peer_list; + + TAILQ_HEAD(, ol_txrx_stats_req_internal) req_list; + int req_list_depth; + qdf_spinlock_t req_list_spinlock; + + /* peer ID to peer object map (array of pointers to peer objects) */ + struct ol_txrx_peer_id_map *peer_id_to_obj_map; + + struct { + unsigned int mask; + unsigned int idx_bits; + + TAILQ_HEAD(, ol_txrx_peer_t) * bins; + } peer_hash; + + /* rx specific processing */ + struct { + struct { + TAILQ_HEAD(, ol_rx_reorder_t) waitlist; + uint32_t timeout_ms; + } defrag; + struct { + int defrag_timeout_check; + int dup_check; + } flags; + + struct { + struct ol_tx_reorder_cat_timeout_t + access_cats[TXRX_NUM_WMM_AC]; + } reorder_timeout; + qdf_spinlock_t mutex; + } rx; + + /* rx proc function */ + void (*rx_opt_proc)(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list); + + /* tx data delivery notification callback function */ + struct { + ol_txrx_data_tx_cb func; + void *ctxt; + } tx_data_callback; + + /* tx management delivery notification callback functions */ + struct { + ol_txrx_mgmt_tx_cb download_cb; + ol_txrx_mgmt_tx_cb ota_ack_cb; + void *ctxt; + } tx_mgmt_cb; + + data_stall_detect_cb data_stall_detect_callback; + /* packetdump callback functions */ + ol_txrx_pktdump_cb ol_tx_packetdump_cb; + ol_txrx_pktdump_cb ol_rx_packetdump_cb; + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS + tp_ol_timestamp_cb ol_tx_timestamp_cb; +#endif + + struct { + uint16_t pool_size; + uint16_t num_free; + union ol_tx_desc_list_elem_t *array; + union ol_tx_desc_list_elem_t *freelist; +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + uint8_t num_invalid_bin; + qdf_spinlock_t flow_pool_list_lock; + TAILQ_HEAD(flow_pool_list_t, ol_tx_flow_pool_t) flow_pool_list; +#endif + uint32_t page_size; + uint16_t desc_reserved_size; + uint8_t page_divider; + uint32_t offset_filter; + struct qdf_mem_multi_page_t desc_pages; +#ifdef DESC_DUP_DETECT_DEBUG + unsigned long *free_list_bitmap; +#endif +#ifdef QCA_LL_PDEV_TX_FLOW_CONTROL + uint16_t stop_th; + uint16_t start_th; + uint16_t stop_priority_th; + uint16_t start_priority_th; + enum flow_pool_status status; +#endif + } tx_desc; + + /* The pdev_id for this pdev */ + uint8_t id; + + uint8_t is_mgmt_over_wmi_enabled; +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) + struct ol_txrx_pool_stats pool_stats; + uint32_t num_msdu_desc; +#ifdef QCA_LL_TX_FLOW_GLOBAL_MGMT_POOL + struct ol_tx_flow_pool_t *mgmt_pool; +#endif +#endif + + struct { + int (*cmp)(union htt_rx_pn_t *new, + union htt_rx_pn_t *old, + int is_unicast, int opmode, bool strict_chk); + int len; + } rx_pn[htt_num_sec_types]; + + /* tx mutex */ + OL_TX_MUTEX_TYPE tx_mutex; + + /* + * peer ref mutex: + * 1. Protect peer object lookups until the returned peer object's + * reference count is incremented. + * 2. Provide mutex when accessing peer object lookup structures. + */ + OL_RX_MUTEX_TYPE peer_ref_mutex; + + /* + * last_real_peer_mutex: + * Protect lookups of any vdev's last_real_peer pointer until the + * reference count for the pointed-to peer object is incremented. + * This mutex could be in the vdev struct, but it's slightly simpler + * to have a single lock in the pdev struct. Since the lock is only + * held for an extremely short time, and since it's very unlikely for + * two vdev's to concurrently access the lock, there's no real + * benefit to having a per-vdev lock. + */ + OL_RX_MUTEX_TYPE last_real_peer_mutex; + + qdf_spinlock_t peer_map_unmap_lock; + + ol_txrx_peer_unmap_sync_cb peer_unmap_sync_cb; + + struct { + struct { + struct { + struct { + uint64_t ppdus; + uint64_t mpdus; + } normal; + struct { + /* + * mpdu_bad is general - + * replace it with the specific counters + * below + */ + uint64_t mpdu_bad; + /* uint64_t mpdu_fcs; */ + /* uint64_t mpdu_duplicate; */ + /* uint64_t mpdu_pn_replay; */ + /* uint64_t mpdu_bad_sender; */ + /* ^ comment: peer not found */ + /* uint64_t mpdu_flushed; */ + /* uint64_t msdu_defrag_mic_err; */ + uint64_t msdu_mc_dup_drop; + } err; + } rx; + } priv; + struct ol_txrx_stats pub; + } stats; + +#if defined(ENABLE_RX_REORDER_TRACE) + struct { + uint32_t mask; + uint32_t idx; + uint64_t cnt; +#define TXRX_RX_REORDER_TRACE_SIZE_LOG2 8 /* 256 entries */ + struct { + uint16_t reorder_idx; + uint16_t seq_num; + uint8_t num_mpdus; + uint8_t tid; + } *data; + } rx_reorder_trace; +#endif /* ENABLE_RX_REORDER_TRACE */ + +#if defined(ENABLE_RX_PN_TRACE) + struct { + uint32_t mask; + uint32_t idx; + uint64_t cnt; +#define TXRX_RX_PN_TRACE_SIZE_LOG2 5 /* 32 entries */ + struct { + struct ol_txrx_peer_t *peer; + uint32_t pn32; + uint16_t seq_num; + uint8_t unicast; + uint8_t tid; + } *data; + } rx_pn_trace; +#endif /* ENABLE_RX_PN_TRACE */ + + /* + * tx_sched only applies for HL, but is defined unconditionally + * rather than only if defined(CONFIG_HL_SUPPORT). + * This is because the struct only + * occupies a few bytes, and to avoid the complexity of + * wrapping references + * to the struct members in "defined(CONFIG_HL_SUPPORT)" conditional + * compilation. + * If this struct gets expanded to a non-trivial size, + * then it should be + * conditionally compiled to only apply if defined(CONFIG_HL_SUPPORT). + */ + qdf_spinlock_t tx_queue_spinlock; + struct { + enum ol_tx_scheduler_status tx_sched_status; + struct ol_tx_sched_t *scheduler; + } tx_sched; + /* + * tx_queue only applies for HL, but is defined unconditionally to avoid + * wrapping references to tx_queue in "defined(CONFIG_HL_SUPPORT)" + * conditional compilation. + */ + struct { + qdf_atomic_t rsrc_cnt; + /* threshold_lo - when to start tx desc margin replenishment */ + uint16_t rsrc_threshold_lo; + /* + * threshold_hi - where to stop during tx desc margin + * replenishment + */ + uint16_t rsrc_threshold_hi; + } tx_queue; + +#if defined(DEBUG_HL_LOGGING) && defined(CONFIG_HL_SUPPORT) +#define OL_TXQ_LOG_SIZE 512 + qdf_spinlock_t txq_log_spinlock; + struct { + int size; + int oldest_record_offset; + int offset; + int allow_wrap; + u_int32_t wrapped; + /* aligned to u_int32_t boundary */ + u_int8_t data[OL_TXQ_LOG_SIZE]; + } txq_log; +#endif + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS + qdf_spinlock_t peer_stat_mutex; +#endif + + int rssi_update_shift; + int rssi_new_weight; +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID + struct { + ol_txrx_local_peer_id_t pool[OL_TXRX_NUM_LOCAL_PEER_IDS + 1]; + ol_txrx_local_peer_id_t freelist; + qdf_spinlock_t lock; + ol_txrx_peer_handle map[OL_TXRX_NUM_LOCAL_PEER_IDS]; + } local_peer_ids; +#endif + +#ifdef QCA_COMPUTE_TX_DELAY +#ifdef QCA_COMPUTE_TX_DELAY_PER_TID +#define QCA_TX_DELAY_NUM_CATEGORIES \ + (OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES) +#else +#define QCA_TX_DELAY_NUM_CATEGORIES 1 +#endif + struct { + qdf_spinlock_t mutex; + struct { + struct ol_tx_delay_data copies[2]; /* ping-pong */ + int in_progress_idx; + uint32_t avg_start_time_ticks; + } cats[QCA_TX_DELAY_NUM_CATEGORIES]; + uint32_t tx_compl_timestamp_ticks; + uint32_t avg_period_ticks; + uint32_t hist_internal_bin_width_mult; + uint32_t hist_internal_bin_width_shift; + } tx_delay; + + uint16_t packet_count[QCA_TX_DELAY_NUM_CATEGORIES]; + uint16_t packet_loss_count[QCA_TX_DELAY_NUM_CATEGORIES]; + +#endif /* QCA_COMPUTE_TX_DELAY */ + + struct { + qdf_spinlock_t mutex; + /* timer used to monitor the throttle "on" phase and + * "off" phase + */ + qdf_timer_t phase_timer; + /* timer used to send tx frames */ + qdf_timer_t tx_timer; + /* This is the time in ms of the throttling window, it will + * include an "on" phase and an "off" phase + */ + uint32_t throttle_period_ms; + /* Current throttle level set by the client ex. level 0, + * level 1, etc + */ + enum throttle_level current_throttle_level; + /* Index that points to the phase within the throttle period */ + enum throttle_phase current_throttle_phase; + /* Maximum number of frames to send to the target at one time */ + uint32_t tx_threshold; + /* stores time in ms of on/off phase for each throttle level */ + int throttle_time_ms[THROTTLE_LEVEL_MAX][THROTTLE_PHASE_MAX]; + /* mark true if traffic is paused due to thermal throttling */ + bool is_paused; + /* Save outstanding packet number */ + uint16_t prev_outstanding_num; + } tx_throttle; + +#if defined(FEATURE_TSO) + struct { + uint16_t pool_size; + uint16_t num_free; + struct qdf_tso_seg_elem_t *freelist; + /* tso mutex */ + OL_TX_MUTEX_TYPE tso_mutex; + } tso_seg_pool; + struct { + uint16_t num_seg_pool_size; + uint16_t num_free; + struct qdf_tso_num_seg_elem_t *freelist; + /* tso mutex */ + OL_TX_MUTEX_TYPE tso_num_seg_mutex; + } tso_num_seg_pool; +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + struct { + enum ol_tx_peer_bal_state enabled; + qdf_spinlock_t mutex; + /* timer used to trigger more frames for bad peers */ + qdf_timer_t peer_bal_timer; + /*This is the time in ms of the peer balance timer period */ + u_int32_t peer_bal_period_ms; + /*This is the txq limit */ + u_int32_t peer_bal_txq_limit; + /*This is the state of the peer balance timer */ + enum ol_tx_peer_bal_timer_state peer_bal_timer_state; + /*This is the counter about active peers which are under + *tx flow control + */ + u_int32_t peer_num; + /*This is peer list which are under tx flow control */ + struct ol_tx_limit_peer_t limit_list[MAX_NO_PEERS_IN_LIMIT]; + /*This is threshold configurationl */ + struct tx_peer_threshold ctl_thresh[TXRX_IEEE11_MAX]; + } tx_peer_bal; +#endif /* CONFIG_Hl_SUPPORT && QCA_BAD_PEER_TX_FLOW_CL */ + + struct ol_tx_queue_group_t txq_grps[OL_TX_MAX_TXQ_GROUPS]; +#if defined(FEATURE_HL_GROUP_CREDIT_FLOW_CONTROL) && \ + defined(FEATURE_HL_DBS_GROUP_CREDIT_SHARING) + bool limit_lend; + u16 min_reserve; +#endif +#ifdef DEBUG_HL_LOGGING + qdf_spinlock_t grp_stat_spinlock; + struct ol_tx_group_credit_stats_t grp_stats; +#endif + int tid_to_ac[OL_TX_NUM_TIDS + OL_TX_VDEV_NUM_QUEUES]; + uint8_t ocb_peer_valid; + struct ol_txrx_peer_t *ocb_peer; + tx_pause_callback pause_cb; + + void (*offld_flush_cb)(void *); + struct ol_txrx_peer_t *self_peer; + + /* dp debug fs */ + struct dentry *dpt_stats_log_dir; + enum qdf_dpt_debugfs_state state; + struct qdf_debugfs_fops dpt_debugfs_fops; + +#ifdef IPA_OFFLOAD + ipa_uc_op_cb_type ipa_uc_op_cb; + void *usr_ctxt; + struct ol_txrx_ipa_resources ipa_resource; +#endif /* IPA_UC_OFFLOAD */ + bool new_htt_msg_format; + uint8_t peer_id_unmap_ref_cnt; + bool enable_peer_unmap_conf_support; + bool enable_tx_compl_tsf64; + uint64_t last_host_time; + uint64_t last_tsf64_time; + + /* Current noise-floor reading for the pdev channel */ + int16_t chan_noise_floor; + uint32_t total_bundle_queue_length; +}; + +#define OL_TX_HL_DEL_ACK_HASH_SIZE 256 + +/** + * enum ol_tx_hl_packet_type - type for tcp packet + * @TCP_PKT_ACK: TCP ACK frame + * @TCP_PKT_NO_ACK: TCP frame, but not the ack + * @NO_TCP_PKT: Not the TCP frame + */ +enum ol_tx_hl_packet_type { + TCP_PKT_ACK, + TCP_PKT_NO_ACK, + NO_TCP_PKT +}; + +/** + * struct packet_info - tcp packet information + */ +struct packet_info { + /** @type: flag the packet type */ + enum ol_tx_hl_packet_type type; + /** @stream_id: stream identifier */ + uint16_t stream_id; + /** @ack_number: tcp ack number */ + uint32_t ack_number; + /** @dst_ip: destination ip address */ + uint32_t dst_ip; + /** @src_ip: source ip address */ + uint32_t src_ip; + /** @dst_port: destination port */ + uint16_t dst_port; + /** @src_port: source port */ + uint16_t src_port; +}; + +/** + * struct tcp_stream_node - tcp stream node + */ +struct tcp_stream_node { + /** @next: next tcp stream node */ + struct tcp_stream_node *next; + /** @no_of_ack_replaced: count for ack replaced frames */ + uint8_t no_of_ack_replaced; + /** @stream_id: stream identifier */ + uint16_t stream_id; + /** @dst_ip: destination ip address */ + uint32_t dst_ip; + /** @src_ip: source ip address */ + uint32_t src_ip; + /** @dst_port: destination port */ + uint16_t dst_port; + /** @src_port: source port */ + uint16_t src_port; + /** @ack_number: tcp ack number */ + uint32_t ack_number; + /** @head: point to the tcp ack frame */ + qdf_nbuf_t head; +}; + +/** + * struct tcp_del_ack_hash_node - hash node for tcp delayed ack + */ +struct tcp_del_ack_hash_node { + /** @hash_node_lock: spin lock */ + qdf_spinlock_t hash_node_lock; + /** @no_of_entries: number of entries */ + uint8_t no_of_entries; + /** @head: the head of the steam node list */ + struct tcp_stream_node *head; +}; + +struct ol_txrx_vdev_t { + struct ol_txrx_pdev_t *pdev; /* pdev - the physical device that is + * the parent of this virtual device + */ + uint8_t vdev_id; /* ID used to specify a particular vdev + * to the target + */ + void *osif_dev; + + void *ctrl_vdev; /* vdev objmgr handle */ + + union ol_txrx_align_mac_addr_t mac_addr; /* MAC address */ + /* tx paused - NO LONGER NEEDED? */ + TAILQ_ENTRY(ol_txrx_vdev_t) vdev_list_elem; /* node in the pdev's list + * of vdevs + */ + TAILQ_HEAD(peer_list_t, ol_txrx_peer_t) peer_list; + struct ol_txrx_peer_t *last_real_peer; /* last real peer created for + * this vdev (not "self" + * pseudo-peer) + */ + ol_txrx_rx_fp rx; /* receive function used by this vdev */ + ol_txrx_stats_rx_fp stats_rx; /* receive function used by this vdev */ + + struct { + uint32_t txack_success; + uint32_t txack_failed; + } txrx_stats; + + /* completion function used by this vdev*/ + ol_txrx_completion_fp tx_comp; + + /* delete notifier to DP component */ + ol_txrx_vdev_delete_cb vdev_del_notify; + + struct { + /* + * If the vdev object couldn't be deleted immediately because + * it still had some peer objects left, remember that a delete + * was requested, so it can be deleted once all its peers have + * been deleted. + */ + int pending; + /* + * Store a function pointer and a context argument to provide a + * notification for when the vdev is deleted. + */ + ol_txrx_vdev_delete_cb callback; + void *context; + atomic_t detaching; + } delete; + + /* safe mode control to bypass the encrypt and decipher process */ + uint32_t safemode; + + /* rx filter related */ + uint32_t drop_unenc; + struct privacy_exemption privacy_filters[MAX_PRIVACY_FILTERS]; + uint32_t num_filters; + + enum wlan_op_mode opmode; + enum wlan_op_subtype subtype; + enum QDF_OPMODE qdf_opmode; + +#ifdef QCA_IBSS_SUPPORT + /* ibss mode related */ + int16_t ibss_peer_num; /* the number of active peers */ + int16_t ibss_peer_heart_beat_timer; /* for detecting peer departure */ +#endif + +#if defined(CONFIG_HL_SUPPORT) + struct ol_tx_frms_queue_t txqs[OL_TX_VDEV_NUM_QUEUES]; +#endif + + struct { + struct { + qdf_nbuf_t head; + qdf_nbuf_t tail; + int depth; + } txq; + uint32_t paused_reason; + qdf_spinlock_t mutex; + qdf_timer_t timer; + int max_q_depth; + bool is_q_paused; + bool is_q_timer_on; + uint32_t q_pause_cnt; + uint32_t q_unpause_cnt; + uint32_t q_overflow_cnt; + } ll_pause; + bool disable_intrabss_fwd; + qdf_atomic_t os_q_paused; + uint16_t tx_fl_lwm; + uint16_t tx_fl_hwm; + qdf_spinlock_t flow_control_lock; + ol_txrx_tx_flow_control_fp osif_flow_control_cb; + ol_txrx_tx_flow_control_is_pause_fp osif_flow_control_is_pause; + void *osif_fc_ctx; + +#ifdef QCA_SUPPORT_TXRX_DRIVER_TCP_DEL_ACK + /** @driver_del_ack_enabled: true if tcp delayed ack enabled*/ + bool driver_del_ack_enabled; + /** @no_of_tcpack_replaced: number of tcp ack replaced */ + uint32_t no_of_tcpack_replaced; + /** @no_of_tcpack: number of tcp ack frames */ + uint32_t no_of_tcpack; + + /** @tcp_ack_hash: hash table for tcp delay ack running information */ + struct { + /** @node: tcp ack frame will be stored in this hash table */ + struct tcp_del_ack_hash_node node[OL_TX_HL_DEL_ACK_HASH_SIZE]; + /** @timer: timeout if no more tcp ack feeding */ + qdf_hrtimer_data_t timer; + /** @is_timer_running: is timer running? */ + qdf_atomic_t is_timer_running; + /** @tcp_node_in_use_count: number of nodes in use */ + qdf_atomic_t tcp_node_in_use_count; + /** @tcp_del_ack_tq: bh to handle the tcp delayed ack */ + qdf_bh_t tcp_del_ack_tq; + /** @tcp_free_list: free list */ + struct tcp_stream_node *tcp_free_list; + /** @tcp_free_list_lock: spin lock */ + qdf_spinlock_t tcp_free_list_lock; + } tcp_ack_hash; +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(FEATURE_WLAN_TDLS) + union ol_txrx_align_mac_addr_t hl_tdls_ap_mac_addr; + bool hlTdlsFlag; +#endif + +#if defined(QCA_HL_NETDEV_FLOW_CONTROL) + qdf_atomic_t tx_desc_count; + int tx_desc_limit; + int queue_restart_th; + int queue_stop_th; + int prio_q_paused; +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + + uint16_t wait_on_peer_id; + union ol_txrx_align_mac_addr_t last_peer_mac_addr; + qdf_event_t wait_delete_comp; +#if defined(FEATURE_TSO) + struct { + int pool_elems; /* total number of elements in the pool */ + int alloc_cnt; /* number of allocated elements */ + uint32_t *freelist; /* free list of qdf_tso_seg_elem_t */ + } tso_pool_t; +#endif + + /* last channel change event received */ + struct { + bool is_valid; /* whether the rest of the members are valid */ + uint16_t mhz; + uint16_t band_center_freq1; + uint16_t band_center_freq2; + WLAN_PHY_MODE phy_mode; + } ocb_channel_event; + + /* Information about the schedules in the schedule */ + struct ol_txrx_ocb_chan_info *ocb_channel_info; + uint32_t ocb_channel_count; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 + struct ol_tx_flow_pool_t *pool; +#endif + /* intra bss forwarded tx and rx packets count */ + uint64_t fwd_tx_packets; + uint64_t fwd_rx_packets; + bool is_wisa_mode_enable; + uint8_t mac_id; + + uint64_t no_of_bundle_sent_after_threshold; + uint64_t no_of_bundle_sent_in_timer; + uint64_t no_of_pkt_not_added_in_queue; + bool bundling_required; + struct { + struct { + qdf_nbuf_t head; + qdf_nbuf_t tail; + int depth; + } txq; + qdf_spinlock_t mutex; + qdf_timer_t timer; + } bundle_queue; +}; + +struct ol_rx_reorder_array_elem_t { + qdf_nbuf_t head; + qdf_nbuf_t tail; +}; + +struct ol_rx_reorder_t { + uint8_t win_sz; + uint8_t win_sz_mask; + uint8_t num_mpdus; + struct ol_rx_reorder_array_elem_t *array; + /* base - single rx reorder element used for non-aggr cases */ + struct ol_rx_reorder_array_elem_t base; +#if defined(QCA_SUPPORT_OL_RX_REORDER_TIMEOUT) + struct ol_rx_reorder_timeout_list_elem_t timeout; +#endif + /* only used for defrag right now */ + TAILQ_ENTRY(ol_rx_reorder_t) defrag_waitlist_elem; + uint32_t defrag_timeout_ms; + /* get back to parent ol_txrx_peer_t when ol_rx_reorder_t is in a + * waitlist + */ + uint16_t tid; +}; + +enum { + txrx_sec_mcast = 0, + txrx_sec_ucast +}; + +typedef A_STATUS (*ol_tx_filter_func)(struct ol_txrx_msdu_info_t * + tx_msdu_info); + +#define OL_TXRX_PEER_SECURITY_MULTICAST 0 +#define OL_TXRX_PEER_SECURITY_UNICAST 1 +#define OL_TXRX_PEER_SECURITY_MAX 2 + + +/* Allow 6000 ms to receive peer unmap events after peer is deleted */ +#define OL_TXRX_PEER_UNMAP_TIMEOUT (6000) + +struct ol_txrx_cached_bufq_t { + /* cached_bufq is used to enqueue the pending RX frames from a peer + * before the peer is registered for data service. The list will be + * flushed to HDD once that station is registered. + */ + struct list_head cached_bufq; + /* mutual exclusion lock to access the cached_bufq queue */ + qdf_spinlock_t bufq_lock; + /* # entries in queue after which subsequent adds will be dropped */ + uint32_t thresh; + /* # entries in present in cached_bufq */ + uint32_t curr; + /* # max num of entries in the queue if bufq thresh was not in place */ + uint32_t high_water_mark; + /* # max num of entries in the queue if we did not drop packets */ + uint32_t qdepth_no_thresh; + /* # of packes (beyond threshold) dropped from cached_bufq */ + uint32_t dropped; +}; + +struct ol_txrx_peer_t { + struct ol_txrx_vdev_t *vdev; + + /* UMAC peer objmgr handle */ + struct cdp_ctrl_objmgr_peer *ctrl_peer; + + qdf_atomic_t ref_cnt; + qdf_atomic_t del_ref_cnt; + qdf_atomic_t access_list[PEER_DEBUG_ID_MAX]; + qdf_atomic_t delete_in_progress; + qdf_atomic_t flush_in_progress; + + /* The peer state tracking is used for HL systems + * that don't support tx and rx filtering within the target. + * In such systems, the peer's state determines what kind of + * tx and rx filtering, if any, is done. + * This variable doesn't apply to LL systems, or to HL systems for + * which the target handles tx and rx filtering. However, it is + * simplest to declare and update this variable unconditionally, + * for all systems. + */ + enum ol_txrx_peer_state state; + qdf_spinlock_t peer_info_lock; + + /* Wrapper around the cached_bufq list */ + struct ol_txrx_cached_bufq_t bufq_info; + + ol_tx_filter_func tx_filter; + + /* peer ID(s) for this peer */ + uint16_t peer_ids[MAX_NUM_PEER_ID_PER_PEER]; +#ifdef QCA_SUPPORT_TXRX_LOCAL_PEER_ID + uint16_t local_id; +#endif + + union ol_txrx_align_mac_addr_t mac_addr; + + /* node in the vdev's list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t) peer_list_elem; + /* node in the hash table bin's list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t) hash_list_elem; + /* node in the pdev's inactive list of peers */ + TAILQ_ENTRY(ol_txrx_peer_t)inactive_peer_list_elem; + + /* + * per TID info - + * stored in separate arrays to avoid alignment padding mem overhead + */ + struct ol_rx_reorder_t tids_rx_reorder[OL_TXRX_NUM_EXT_TIDS]; + union htt_rx_pn_t tids_last_pn[OL_TXRX_NUM_EXT_TIDS]; + uint8_t tids_last_pn_valid[OL_TXRX_NUM_EXT_TIDS]; + uint8_t tids_rekey_flag[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_next_rel_idx[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_last_seq[OL_TXRX_NUM_EXT_TIDS]; + uint16_t tids_mcast_last_seq[OL_TXRX_NUM_EXT_TIDS]; + + struct { + enum htt_sec_type sec_type; + uint32_t michael_key[2]; /* relevant for TKIP */ + } security[2]; /* 0 -> multicast, 1 -> unicast */ + + /* + * rx proc function: this either is a copy of pdev's rx_opt_proc for + * regular rx processing, or has been redirected to a /dev/null discard + * function when peer deletion is in progress. + */ + void (*rx_opt_proc)(struct ol_txrx_vdev_t *vdev, + struct ol_txrx_peer_t *peer, + unsigned int tid, qdf_nbuf_t msdu_list); + +#if defined(CONFIG_HL_SUPPORT) + struct ol_tx_frms_queue_t txqs[OL_TX_NUM_TIDS]; +#endif + +#ifdef QCA_ENABLE_OL_TXRX_PEER_STATS + ol_txrx_peer_stats_t stats; +#endif + int16_t rssi_dbm; + + /* NAWDS Flag and Bss Peer bit */ + uint16_t nawds_enabled:1, bss_peer:1, valid:1; + + /* QoS info */ + uint8_t qos_capable; + /* U-APSD tid mask */ + uint8_t uapsd_mask; + /*flag indicating key installed */ + uint8_t keyinstalled; + + /* Bit to indicate if PN check is done in fw */ + qdf_atomic_t fw_pn_check; + + /* PN counter for Robust Management Frames */ + uint64_t last_rmf_pn; + uint32_t rmf_pn_replays; + uint8_t last_rmf_pn_valid; + + /* Properties of the last received PPDU */ + int16_t last_pkt_rssi_cmb; + int16_t last_pkt_rssi[4]; + uint8_t last_pkt_legacy_rate; + uint8_t last_pkt_legacy_rate_sel; + uint32_t last_pkt_timestamp_microsec; + uint8_t last_pkt_timestamp_submicrosec; + uint32_t last_pkt_tsf; + uint8_t last_pkt_tid; + uint16_t last_pkt_center_freq; +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + u_int16_t tx_limit; + u_int16_t tx_limit_flag; + u_int16_t tx_pause_flag; +#endif + qdf_time_t last_assoc_rcvd; + qdf_time_t last_disassoc_rcvd; + qdf_time_t last_deauth_rcvd; + qdf_atomic_t fw_create_pending; + qdf_timer_t peer_unmap_timer; + bool is_tdls_peer; /* Mark peer as tdls peer */ + bool tdls_offchan_enabled; /* TDLS OffChan operation in use */ +}; + +struct ol_rx_remote_data { + qdf_nbuf_t msdu; + uint8_t mac_id; +}; + +struct ol_fw_data { + void *data; + uint32_t len; +}; + +#define INVALID_REORDER_INDEX 0xFFFF + +#define SPS_DESC_SIZE 8 + +#endif /* _OL_TXRX_TYPES__H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/wdi_event.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/wdi_event.h new file mode 100644 index 0000000000..fcf771bbce --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/wdi_event.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WDI_EVENT_H_ +#define _WDI_EVENT_H_ + +#include "athdefs.h" +#include "qdf_nbuf.h" +#include + +#define WDI_NO_VAL (-1) + +struct wdi_event_rx_peer_invalid_msg { + qdf_nbuf_t msdu; + struct ieee80211_frame *wh; + uint8_t vdev_id; +}; + +#define WDI_EVENT_NOTIFY_BASE 0x200 +enum WDI_EVENT_NOTIFY { + WDI_EVENT_SUB_DEALLOCATE = WDI_EVENT_NOTIFY_BASE, + /* End of new notification types */ + + WDI_EVENT_NOTIFY_LAST +}; + +/* Opaque event callback */ +typedef void (*wdi_event_cb)(void *pdev, enum WDI_EVENT event, void *data, + u_int16_t peer_id, uint32_t status); + +/* Opaque event notify */ +typedef void (*wdi_event_notify)(enum WDI_EVENT_NOTIFY notify, + enum WDI_EVENT event); + +/** + * @typedef wdi_event_subscribe + * @brief Used by consumers to subscribe to WDI event notifications. + * @details + * The event_subscribe struct includes pointers to other event_subscribe + * objects. These pointers are simply to simplify the management of + * lists of event subscribers. These pointers are set during the + * event_sub() function, and shall not be modified except by the + * WDI event management SW, until after the object's event subscription + * is canceled by calling event_unsub(). + */ + +typedef struct wdi_event_subscribe_t { + /* subscriber event callback structure head */ + wdi_event_cb callback; + /* subscriber object that processes the event callback */ + void *context; + struct { + /* + * private - the event subscriber SW shall not use this struct + */ + struct wdi_event_subscribe_t *next; + struct wdi_event_subscribe_t *prev; + } priv; +} wdi_event_subscribe; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/wdi_event_api.h b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/wdi_event_api.h new file mode 100644 index 0000000000..11358b25e0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/dp/txrx/wdi_event_api.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012-2014, 2017-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WDI_EVENT_API_H_ +#define _WDI_EVENT_API_H_ + +#include "wdi_event.h" +#include +#include +struct ol_txrx_pdev_t; + +#ifdef WDI_EVENT_ENABLE +/** + * @brief Subscribe to a specified WDI event. + * @details + * This function adds the provided wdi_event_subscribe object to a list of + * subscribers for the specified WDI event. + * When the event in question happens, each subscriber for the event will + * have their callback function invoked. + * The order in which callback functions from multiple subscribers are + * invoked is unspecified. + * + * @param soc_hdl - datapath soc handle + * @param pdev_id - physical device instance id + * @param event_cb_sub - the callback and context for the event subscriber + * @param event - which event's notifications are being subscribed to + * @return error code, or 0 for success + */ +int wdi_event_sub(struct cdp_soc_t *soc, uint8_t pdev_id, + wdi_event_subscribe *event_cb_sub, uint32_t event); + +/** + * @brief Unsubscribe from a specified WDI event. + * @details + * This function removes the provided event subscription object from the + * list of subscribers for its event. + * This function shall only be called if there was a successful prior call + * to event_sub() on the same wdi_event_subscribe object. + * + * @param soc_hdl - datapath soc handle + * @param pdev_id - physical device instance id + * @param event_cb_sub - the event subscription object + * @param event - which event is being unsubscribed + * @return error code, or 0 for success + */ +int wdi_event_unsub(struct cdp_soc_t *soc, uint8_t pdev_id, + wdi_event_subscribe *event_cb_sub, uint32_t event); + + +void wdi_event_handler(enum WDI_EVENT event, + uint8_t pdev_id, void *data); +A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev); +A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev); + +#else + +static inline void wdi_event_handler(enum WDI_EVENT event, + uint8_t pdev_id, void *data) +{ +} + +static inline A_STATUS wdi_event_attach(struct ol_txrx_pdev_t *txrx_pdev) +{ + return A_OK; +} + +static inline A_STATUS wdi_event_detach(struct ol_txrx_pdev_t *txrx_pdev) +{ + return A_OK; +} + +static inline int wdi_event_sub(struct cdp_soc_t *soc, uint8_t pdev_id, + wdi_event_subscribe *event_cb_sub, + uint32_t event) +{ + return 0; +} + +static inline int wdi_event_unsub(struct cdp_soc_t *soc, uint8_t pdev_id, + wdi_event_subscribe *event_cb_sub, + uint32_t event) +{ + return 0; +} +#endif /* WDI_EVENT_ENABLE */ + +#endif /* _WDI_EVENT_API_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_config.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_config.h new file mode 100644 index 0000000000..c057459abe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_config.h @@ -0,0 +1,1387 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __HDD_CONFIG_H +#define __HDD_CONFIG_H + +#include "hdd_sar_safety_config.h" + +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif + +#define CFG_QDF_TRACE_ENABLE_DEFAULT (0xffff) +#include + +/** + * enum hdd_wext_control - knob for wireless extensions + * @hdd_wext_disabled: interface is completely disabled. An access + * control error log will be generated for each attempted use. + * @hdd_wext_deprecated: interface is available but should not be + * used. An access control warning log will be generated for each + * use. + * @hdd_wext_enabled: interface is available without restriction. No + * access control logs will be generated. + * + * enum hdd_wext_control is used to enable coarse grained control on + * wireless extensions ioctls. This control is used by configuration + * item private_wext_control. + * + */ +enum hdd_wext_control { + hdd_wext_disabled = 0, + hdd_wext_deprecated = 1, + hdd_wext_enabled = 2, +}; + +/* + * + * private_wext_control - Private wireless extensions control + * @Min: 0 + * @Max: 2 + * @Default: 1 + * + * Values are per enum hdd_wext_control. + * This ini is used to control access to private wireless extensions + * ioctls SIOCIWFIRSTPRIV (0x8BE0) thru SIOCIWLASTPRIV (0x8BFF). The + * functionality provided by some of these ioctls has been superseded + * by cfg80211 (either standard commands or vendor commands), but many + * of the private ioctls do not have a cfg80211-based equivalent, so + * by default support for these ioctls is deprecated. + * + * Related: None + * + * Supported Feature: All + * + * Usage: Internal/External + * + * + */ +#define CFG_PRIVATE_WEXT_CONTROL CFG_INI_UINT( \ + "private_wext_control", \ + hdd_wext_disabled, \ + hdd_wext_enabled, \ + hdd_wext_deprecated, \ + CFG_VALUE_OR_DEFAULT, \ + "Private WEXT Control") + +enum hdd_dot11_mode { + eHDD_DOT11_MODE_AUTO = 0, /* covers all things we support */ + eHDD_DOT11_MODE_abg, /* 11a/b/g only, no HT, no proprietary */ + eHDD_DOT11_MODE_11b, + eHDD_DOT11_MODE_11g, + eHDD_DOT11_MODE_11n, + eHDD_DOT11_MODE_11g_ONLY, + eHDD_DOT11_MODE_11n_ONLY, + eHDD_DOT11_MODE_11b_ONLY, + eHDD_DOT11_MODE_11ac_ONLY, + eHDD_DOT11_MODE_11ac, + eHDD_DOT11_MODE_11a, + eHDD_DOT11_MODE_11ax_ONLY, + eHDD_DOT11_MODE_11ax, +#ifdef WLAN_FEATURE_11BE + eHDD_DOT11_MODE_11be, + eHDD_DOT11_MODE_11be_ONLY, +#endif +}; + +/* + * + * gDot11Mode - Phymode of vdev + * @Min: 0 (auto) + * @Max: 12 (11ax) + * @Default: 12 (11ax) + * + * This ini is used to set Phy Mode (auto, b, g, n, etc/) Valid values are + * 0-12, with 0 = Auto, 12 = 11ax. + * + * Related: None. + * + * Supported Feature: SAP + * + * Usage: Internal/External + * + * + */ + #define CFG_HDD_DOT11_MODE CFG_INI_UINT( \ + "gDot11Mode", \ + eHDD_DOT11_MODE_AUTO, \ + eHDD_DOT11_MODE_11ax, \ + eHDD_DOT11_MODE_11ax, \ + CFG_VALUE_OR_DEFAULT, \ + "dot11 mode") + +#ifdef FEATURE_SET + /* + * + * get_wifi_features - Get wifi features info from fw + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable feature to get wifi supported features from fw + * + * Related: None + * + * Supported Feature: All + * + * Usage: External + * + * + */ +#define CFG_GET_WIFI_FEATURES CFG_INI_BOOL( \ + "get_wifi_features", \ + 0, \ + "Get wifi features") +#define CFG_GET_WIFI_FEATURES_ALL CFG(CFG_GET_WIFI_FEATURES) +#else +#define CFG_GET_WIFI_FEATURES_ALL +#endif + +#ifdef FEATURE_RUNTIME_PM +/* + * + * cpu_cxpc_threshold - PM QOS threshold + * @Min: 0 + * @Max: 15000 + * @Default: 10000 + * + * This ini is used to set PM QOS threshold value + * + * Related: None. + * + * Supported Feature: ALL + * + * Usage: External + * + * + */ + #define CFG_CPU_CXPC_THRESHOLD CFG_INI_UINT( \ + "cpu_cxpc_threshold", \ + 0, \ + 15000, \ + 10000, \ + CFG_VALUE_OR_DEFAULT, \ + "PM QOS threshold") +#define CFG_CPU_CXPC_THRESHOLD_ALL CFG(CFG_CPU_CXPC_THRESHOLD) +#else +#define CFG_CPU_CXPC_THRESHOLD_ALL +#endif + +#ifdef QCA_WIFI_EMULATION +#define CFG_INTERFACE_CHANGE_WAIT_DEFAULT 300000 +#else +#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND +#define CFG_INTERFACE_CHANGE_WAIT_DEFAULT 10000 +#else +#define CFG_INTERFACE_CHANGE_WAIT_DEFAULT 250 +#endif +#endif + +/* + * + * gInterfaceChangeWait - Interface change wait + * @Min: 0, + * @Max: 500000 + * @Default: 10000 (300000 for emulation) + * + * Timer waiting for interface up from the upper layer. If + * this timer expires all the cds modules shall be closed. + * Time Units: ms + * + * Value 0 can be used to disable idle module stop. + * + * Related: None + * + * Supported Feature: All + * + * + */ +#define CFG_INTERFACE_CHANGE_WAIT CFG_INI_UINT( \ + "gInterfaceChangeWait", \ + 0, \ + 500000, \ + CFG_INTERFACE_CHANGE_WAIT_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Interface change wait") + +#ifdef QCA_WIFI_EMULATION +#define CFG_TIMER_MULTIPLIER_DEFAULT 100 +#else +#define CFG_TIMER_MULTIPLIER_DEFAULT 1 +#endif + +/* + * + * gTimerMultiplier - Scale QDF timers by this value + * @Min: 1 + * @Max: 0xFFFFFFFF + * @Default: 1 (100 for emulation) + * + * To assist in debugging emulation setups, scale QDF timers by this factor. + * + * @E.g. + * # QDF timers expire in real time + * gTimerMultiplier=1 + * # QDF timers expire after 100 times real time + * gTimerMultiplier=100 + * + * Related: None + * + * Usage: Internal + * + * + */ +#define CFG_TIMER_MULTIPLIER CFG_INI_UINT( \ + "gTimerMultiplier", \ + 1, \ + 0xFFFFFFFF, \ + CFG_TIMER_MULTIPLIER_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Timer Multiplier") + +#define CFG_BUG_ON_REINIT_FAILURE_DEFAULT 0 +/* + * + * g_bug_on_reinit_failure - Enable/Disable bug on reinit + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to debug ssr reinit failure issues by raising vos bug so + * dumps can be collected. + * g_bug_on_reinit_failure = 0 wlan driver will only recover after driver + * unload and load + * g_bug_on_reinit_failure = 1 raise vos bug to collect dumps + * + * Related: gEnableSSR + * + * Supported Feature: SSR + * + * Usage: External + * + * + */ +#define CFG_BUG_ON_REINIT_FAILURE CFG_INI_BOOL( \ + "g_bug_on_reinit_failure", \ + CFG_BUG_ON_REINIT_FAILURE_DEFAULT, \ + "BUG on reinit failure") + +/* + * + * gEnableDumpCollect - It will use for collect the dumps + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to set collect default dump + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_RAMDUMP_COLLECTION CFG_INI_BOOL( \ + "gEnableDumpCollect", \ + 1, \ + "Enable dump collect") + +#if defined(MDM_PLATFORM) && !defined(FEATURE_MULTICAST_HOST_FW_MSGS) +#define CFG_MULTICAST_HOST_FW_MSGS_DEFAULT 0 +#else +#define CFG_MULTICAST_HOST_FW_MSGS_DEFAULT 1 +#endif + +/* + * + * gMulticastHostFwMsgs - Multicast host FW messages + * @Min: 0 + * @Max: 1 + * @Default: 0 for MDM platform and 1 for other + * + * + */ +#define CFG_MULTICAST_HOST_FW_MSGS CFG_INI_UINT( \ + "gMulticastHostFwMsgs", \ + 0, \ + 1, \ + CFG_MULTICAST_HOST_FW_MSGS_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, \ + "Multicast host FW msgs") + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/* + * + * wlanLoggingEnable - Wlan logging enable + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * + */ +#define CFG_WLAN_LOGGING_SUPPORT CFG_INI_BOOL( \ + "wlanLoggingEnable", \ + 1, \ + "Wlan logging enable") + +/* + * + * host_log_custom_nl_proto - Host log netlink protocol + * @Min: 0 + * @Max: 32 + * @Default: 2 + * + * This ini is used to set host log netlink protocol. The default + * value is 2 (NETLINK_USERSOCK), customer should avoid selecting the + * netlink protocol that already used on their platform by other + * applications or services. By choosing the non-default value(2), + * Customer need to change the netlink protocol of application receive + * tool(cnss_diag) accordingly. Available values could be: + * + * host_log_custom_nl_proto = 0 - NETLINK_ROUTE, Routing/device hook + * host_log_custom_nl_proto = 1 - NETLINK_UNUSED, Unused number + * host_log_custom_nl_proto = 2 - NETLINK_USERSOCK, Reserved for user + * mode socket protocols + * host_log_custom_nl_proto = 3 - NETLINK_FIREWALL, Unused number, + * formerly ip_queue + * host_log_custom_nl_proto = 4 - NETLINK_SOCK_DIAG, socket monitoring + * host_log_custom_nl_proto = 5 - NETLINK_NFLOG, netfilter/iptables ULOG + * host_log_custom_nl_proto = 6 - NETLINK_XFRM, ipsec + * host_log_custom_nl_proto = 7 - NETLINK_SELINUX, SELinux event + * notifications + * host_log_custom_nl_proto = 8 - NETLINK_ISCSI, Open-iSCSI + * host_log_custom_nl_proto = 9 - NETLINK_AUDIT, auditing + * host_log_custom_nl_proto = 10 - NETLINK_FIB_LOOKUP + * host_log_custom_nl_proto = 11 - NETLINK_CONNECTOR + * host_log_custom_nl_proto = 12 - NETLINK_NETFILTER, netfilter subsystem + * host_log_custom_nl_proto = 13 - NETLINK_IP6_FW + * host_log_custom_nl_proto = 14 - NETLINK_DNRTMSG, DECnet routing messages + * host_log_custom_nl_proto = 15 - NETLINK_KOBJECT_UEVENT, Kernel + * messages to userspace + * host_log_custom_nl_proto = 16 - NETLINK_GENERIC, leave room for + * NETLINK_DM (DM Events) + * host_log_custom_nl_proto = 18 - NETLINK_SCSITRANSPORT, SCSI Transports + * host_log_custom_nl_proto = 19 - NETLINK_ECRYPTFS + * host_log_custom_nl_proto = 20 - NETLINK_RDMA + * host_log_custom_nl_proto = 21 - NETLINK_CRYPTO, Crypto layer + * host_log_custom_nl_proto = 22 - NETLINK_SMC, SMC monitoring + * + * The max value is: MAX_LINKS which is 32 + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_HOST_LOG_CUSTOM_NETLINK_PROTO CFG_INI_UINT( \ + "host_log_custom_nl_proto", \ + 0, \ + 32, \ + 2, \ + CFG_VALUE_OR_DEFAULT, \ + "host log custom netlink protocol") + +/* + * + * wlanConsoleLogLevelsBitmap - Bitmap to enable/disable console log levels + * @Min: 0x00000000 + * @Max: 0x000003ff + * @Default: 0x0000001e + * + * This INI is used to enable/disable console logs for specific log level. + * + * bit-0: Reserved + * bit-1: QDF_TRACE_LEVEL_FATAL + * bit-2: QDF_TRACE_LEVEL_ERROR + * bit-3: QDF_TRACE_LEVEL_WARN + * bit-4: QDF_TRACE_LEVEL_INFO + * bit-5: QDF_TRACE_LEVEL_INFO_HIGH + * bit-6: QDF_TRACE_LEVEL_INFO_MED + * bit-7: QDF_TRACE_LEVEL_INFO_LOW + * bit-8: QDF_TRACE_LEVEL_DEBUG + * bit-9: QDF_TRACE_LEVEL_TRACE + * bit-10 to bit-31: Reserved + * + * + */ +#define CFG_WLAN_LOGGING_CONSOLE_SUPPORT CFG_INI_UINT( \ + "wlanConsoleLogLevelsBitmap", \ + 0x00000000, \ + 0x000003ff, \ + 0x0000001e, \ + CFG_VALUE_OR_DEFAULT, \ + "Wlan logging to console") + +#define CFG_WLAN_LOGGING_SUPPORT_ALL \ + CFG(CFG_WLAN_LOGGING_SUPPORT) \ + CFG(CFG_WLAN_LOGGING_CONSOLE_SUPPORT) \ + CFG(CFG_HOST_LOG_CUSTOM_NETLINK_PROTO) +#else +#define CFG_WLAN_LOGGING_SUPPORT_ALL +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/* + * + * gWlanAutoShutdown - Wlan auto shutdown timer value + * @Min: 0 + * @Max: 86400 + * @Default: 0 + * + * This ini specifies the seconds of WLAN inactivity firmware has to wait + * before indicating WLAN idle event to driver. Upon receiving firmware's + * WLAN idle indication, driver may indicate similar event to upper layer + * daemons(SCM, or any other components working to achieve the same purpose), + * who may choose what to do next, e.g. whether to unload driver module or not. + * 0 indicates no auto shutdown will take place. + * + * + */ +#define CFG_WLAN_AUTO_SHUTDOWN CFG_INI_UINT( \ + "gWlanAutoShutdown", \ + 0, \ + 86400, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "Wlan auto shutdown") +#define CFG_WLAN_AUTO_SHUTDOWN_ALL \ + CFG(CFG_WLAN_AUTO_SHUTDOWN) +#else +#define CFG_WLAN_AUTO_SHUTDOWN_ALL +#endif + +/* + * + * gEnablefwprint - Enable FW uart print + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * + */ +#define CFG_ENABLE_FW_UART_PRINT CFG_INI_BOOL( \ + "gEnablefwprint", \ + 0, \ + "Enable FW uart print") + +/* + * + * gEnablefwlog - Enable FW log + * @Min: 0 + * @Max: 2 + * @Default: 1 + * + * + */ +#define CFG_ENABLE_FW_LOG CFG_INI_UINT( \ + "gEnablefwlog", \ + 0, \ + 2, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable FW log") + +#ifndef REMOVE_PKT_LOG + +#ifdef FEATURE_PKTLOG +#define CFG_ENABLE_PACKET_LOG_DEFAULT 1 +#else +#define CFG_ENABLE_PACKET_LOG_DEFAULT 0 +#endif + +/* + * + * gEnablePacketLog - Enale packet log + * @Min: 0 + * @Max: 1 + * @Default: 1 if packet log code is enabled, 0 otherwise + * + * This option enables/disables packet log collecting. + * + * + */ +#define CFG_ENABLE_PACKET_LOG CFG_INI_BOOL( \ + "gEnablePacketLog", \ + CFG_ENABLE_PACKET_LOG_DEFAULT, \ + "Enable packet log") + +#define CFG_ENABLE_PACKET_LOG_ALL \ + CFG(CFG_ENABLE_PACKET_LOG) +#else +#define CFG_ENABLE_PACKET_LOG_ALL +#endif + +#ifdef FEATURE_RUNTIME_PM + +/** + * enum hdd_runtime_pm_cfg - Runtime PM (RTPM) configuration options + * @hdd_runtime_pm_disabled: RTPM and CxPC aware RTPM disabled + * @hdd_runtime_pm_static: RTPM enabled, but CxPC aware RTPM disabled + * @hdd_runtime_pm_dynamic: RTPM and CxPC aware RTPM enabled + */ +enum hdd_runtime_pm_cfg { + hdd_runtime_pm_disabled = 0, + hdd_runtime_pm_static = 1, + hdd_runtime_pm_dynamic = 2, +}; + +/* + * + * gRuntimePM - enable runtime suspend + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to enable runtime PM + * + * 0: RTPM disabled, so CxPC aware RTPM will be disabled as well + * 1: RTPM enabled, but CxPC aware RTPM disabled + * 2: RTPM enabled and CxPC aware RTPM enabled as well + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_RUNTIME_PM CFG_INI_UINT( \ + "gRuntimePM", \ + 0, \ + 2, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "This ini is used to enable runtime_suspend") +#define CFG_ENABLE_RUNTIME_PM_ALL \ + CFG(CFG_ENABLE_RUNTIME_PM) +#else +#define CFG_ENABLE_RUNTIME_PM_ALL +#endif + +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +/* + * + * enable_qmi_stats - enable periodic stats over qmi + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to enable periodic stats over qmi if DUT is + * in RTPM suspended state to avoid WoW enter/exit for every stats + * request. + * + * 0: Periodic stats over QMI is disabled + * 1: Periodic stats over QMI is enabled + * Related: None + * + * Supported Feature: Power Save + * + * Usage: External + * + * + */ +#define CFG_ENABLE_QMI_STATS CFG_INI_UINT( \ + "enable_qmi_stats", \ + 0, \ + 1, \ + 1, \ + CFG_VALUE_OR_DEFAULT, \ + "This ini is used to enable periodic stats over qmi") +#define CFG_ENABLE_QMI_STATS_ALL \ + CFG(CFG_ENABLE_QMI_STATS) +#else +#define CFG_ENABLE_QMI_STATS_ALL +#endif + +/* + * + * gInformBssRssiRaw - Report rssi in cfg80211_inform_bss_frame + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * Option to report rssi in cfg80211_inform_bss_frame() + * + * Related: None + * + * Supported Feature: N/A + * + * Usage: External + * + * + */ +#define CFG_INFORM_BSS_RSSI_RAW CFG_INI_BOOL( \ + "gInformBssRssiRaw", \ + 1, \ + "Option to report rssi in cfg80211_inform_bss_frame") + +#ifdef FEATURE_WLAN_DYNAMIC_CVM +/* + * + * gConfigVCmodeBitmap - Bitmap for operating voltage corner mode + * @Min: 0x00000000 + * @Max: 0x0fffffff + * @Default: 0x0000000a + * This ini is used to set operating voltage corner mode for differenet + * phymode and bw configurations. Every 2 bits till BIT27 are dedicated + * for a specific configuration. Bit values decide the type of voltage + * corner mode. All the details below - + * + * Configure operating voltage corner mode based on phymode and bw. + * bit 0-1 - operating voltage corner mode for 11a/b. + * bit 2-3 - operating voltage corner mode for 11g. + * bit 4-5 - operating voltage corner mode for 11n, 20MHz, 1x1. + * bit 6-7 - operating voltage corner mode for 11n, 20MHz, 2x2. + * bit 8-9 - operating voltage corner mode for 11n, 40MHz, 1x1. + * bit 10-11 - operating voltage corner mode for 11n, 40MHz, 2x2. + * bit 12-13 - operating voltage corner mode for 11ac, 20MHz, 1x1. + * bit 14-15 - operating voltage corner mode for 11ac, 20MHz, 2x2. + * bit 16-17 - operating voltage corner mode for 11ac, 40MHz, 1x1. + * bit 18-19 - operating voltage corner mode for 11ac, 40MHz, 2x2. + * bit 20-21 - operating voltage corner mode for 11ac, 80MHz, 1x1. + * bit 22-23 - operating voltage corner mode for 11ac, 80MHz, 2x2. + * bit 24-25 - operating voltage corner mode for 11ac, 160MHz, 1x1. + * bit 26-27 - operating voltage corner mode for 11ac, 160MHz, 2x2. + * --------------------------------------------- + * 00 - Static voltage corner SVS + * 01 - static voltage corner LOW SVS + * 10 - Dynamic voltage corner selection based on TPUT + * 11 - Dynamic voltage corner selection based on TPUT and Tx Flush counters + + * Related: None + * + * Supported Feature: None + * + * Usage: External + * + * + */ +#define CFG_VC_MODE_BITMAP CFG_INI_INT( \ + "gConfigVCmode", \ + 0x00000000, \ + 0x0fffffff, \ + 0x00000005, \ + CFG_VALUE_OR_DEFAULT, \ + "Bitmap for operating voltage corner mode") + +#define CFG_VC_MODE_BITMAP_ALL CFG(CFG_VC_MODE_BITMAP) +#else +#define CFG_VC_MODE_BITMAP_ALL +#endif + +/* + * + * def_sta_operating_freq - Default STA operating Freq + * @Min: 0 + * @Max: 2484 + * @Default: 2412 + * + * This ini is used to specify the default operating frequency of a STA during + * initialization. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_OPERATING_FREQUENCY CFG_INI_UINT( \ + "def_sta_operating_freq", \ + 0, \ + 2484, \ + 2412, \ + CFG_VALUE_OR_DEFAULT, \ + "Default STA Operating Frequency") +#ifdef DHCP_SERVER_OFFLOAD +#define IPADDR_NUM_ENTRIES (4) +#define IPADDR_STRING_LENGTH (16) +#define CFG_DHCP_SERVER_IP_DEFAULT "" + +/* + * struct wlan_mlme_chainmask - All chainmask related cfg items + * @dhcpServerIP: Dhcp server IP address + * @is_dhcp_server_ip_valid: is dhcp server valid + */ +struct dhcp_server { + uint8_t dhcp_server_ip[IPADDR_NUM_ENTRIES]; + bool is_dhcp_server_ip_valid; +} + +/* + * + * gDHCPServerIP - Dhcp server Ip name + * @Default: + * + * This ini is used to give the DHCP IP server name + */ +#define CFG_DHCP_SERVER_IP_NAME \ + CFG_INI_STRING("gDHCPServerIP", \ + 0, IPADDR_STRING_LENGTH, CFG_DHCP_SERVER_IP_DEFAULT, "DHCP Server IP") +#endif /* DHCP_SERVER_OFFLOAD */ + +/* + * + * gNumVdevs - max number of VDEVs supported + * + * @Min: 0x1 + * @Max: 0x5 + * @Default: CFG_TGT_NUM_VDEV + * + * Usage: External + * + * + */ +#define CFG_NUM_VDEV_ENABLE CFG_INI_UINT( \ + "gNumVdevs", \ + 1, \ + 5, \ + CFG_TGT_NUM_VDEV, \ + CFG_VALUE_OR_DEFAULT, \ + "Number of VDEVs") + +#define CFG_CONCURRENT_IFACE_MAX_LEN 16 +/* + * + * gEnableConcurrentSTA - This will control the creation of concurrent STA + * interface + * @Default: NULL + * + * This ini is used for providing control to create a concurrent STA session + * along with the creation of wlan0 and p2p0. The name of the interface is + * specified as the parameter + * + * Usage: Internal + * + * + */ + +#define CFG_ENABLE_CONCURRENT_STA CFG_INI_STRING( \ + "gEnableConcurrentSTA", \ + 0, \ + CFG_CONCURRENT_IFACE_MAX_LEN, \ + "", \ + "Enable Concurrent STA") + +#define CFG_DBS_SCAN_PARAM_LENGTH 42 +/* + * + * gdbs_scan_selection - DBS Scan Selection. + * @Default: "" + * + * This ini is used to enable DBS scan selection. + * Example + * @Value: "5,2,2,16,2,2" + * 1st argument is module_id, 2nd argument is number of DBS scan, + * 3rd argument is number of non-DBS scan, + * and other arguments follows. + * 5,2,2,16,2,2 means: + * 5 is module id, 2 is num of DBS scan, 2 is num of non-DBS scan. + * 16 is module id, 2 is num of DBS scan, 2 is num of non-DBS scan. + * + * Related: None. + * + * Supported Feature: DBS Scan + * + * Usage: Internal/External + * + * + */ +#define CFG_DBS_SCAN_SELECTION CFG_INI_STRING( \ + "gdbs_scan_selection", \ + 0, \ + CFG_DBS_SCAN_PARAM_LENGTH, \ + "", \ + "DBS Scan Selection") + +/* + * + * enable_mac_provision - Enable/disable MAC address provisioning feature + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used to enable/disable MAC address provisioning feature + * + * Supported Feature: STA/SAP/P2P + * + * Usage: External + * + * + */ +#define CFG_ENABLE_MAC_PROVISION CFG_INI_BOOL( \ + "enable_mac_provision", \ + 0, \ + "enable/disable MAC address provisioning feature") + +/* + * + * read_mac_addr_from_mac_file - Use/ignore MAC address from mac cfg file + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * This ini is used whether to configure MAC address from the cfg file or not + * + * Supported Feature: STA/SAP/P2P + * + * Usage: External + * + * + */ +#define CFG_READ_MAC_ADDR_FROM_MAC_FILE CFG_INI_BOOL( \ + "read_mac_addr_from_mac_file", \ + 0, \ + "Use/ignore MAC address from cfg file") + +/* + * + * provisioned_intf_pool - It is bit mask value of Interfaces + * @Min: 0 + * @Max: 0xffffffff + * @Default: 0xffffffff + * + * This ini will contain the bitmask of all the interfaces + * which can use addresses from provisioned list. Using enum QDF_OPMODE + * for deciding the bit positions corresponding to each interface. + * Bit 0 : QDF_STA_MODE + * Bit 1 : QDF_SAP_MODE + * Bit 2 : QDF_P2P_CLIENT_MODE + * Bit 3 : QDF_P2P_GO_MODE + * Bit 4 : QDF_FTM_MODE + * Bit 5 : QDF_IBSS_MODE + * Bit 6 : QDF_MONITOR_MODE + * Bit 7 : QDF_P2P_DEVICE_MODE + * Bit 8 : QDF_OCB_MODE + * Bit 9 : QDF_EPPING_MODE + * Bit 10 : QDF_QVIT_MODE + * Bit 11 : QDF_NDI_MODE + * Bit 12 : QDF_MAX_NO_OF_MODE + * For example : + * If Bit 0 represents STA + * Bit 1 represents SAP + * Bit 2 represents P2PGO + * If only STA and SAP can use addresses from provisioned list then the value + * of ini should be 3 (00000011) as first and second bit should be set. + * If only STA and P2PGO can use addresses from provisioned list then the value + * of ini should be 5 (00000101) as first and third bit should be set. + * Similarly, for only SAP and P2PGO ini should be 6 (00000110) + * + * Supported Feature: STA/SAP/P2P + * + * Usage: External + * + * + */ +#define CFG_PROVISION_INTERFACE_POOL CFG_INI_UINT( \ + "provisioned_intf_pool", \ + 0, \ + 0xffffffff, \ + 0xffffffff, \ + CFG_VALUE_OR_DEFAULT, \ + "It is bit mask value of Interfaces") + +/* + * + * deriveded_intf_pool - It is bit mask value of Interfaces + * @Min: 0 + * @Max: 0xffffffff + * @Default: 0xffffffff + * + * This ini will contain the bitmask of all the interfaces + * which can use addresses from derived list + * + * + * Supported Feature: STA/SAP/P2P + * + * Usage: External + * + * + */ +#define CFG_DERIVED_INTERFACE_POOL CFG_INI_UINT( \ + "derived_intf_pool", \ + 0, \ + 0xffffffff, \ + 0xffffffff, \ + CFG_VALUE_OR_DEFAULT, \ + "It is bit mask value of Interfaces") + +#ifdef ENABLE_MTRACE_LOG +/* + * + * enable_mtrace - Enable Mtrace. + * @Default: 0 + * + * This ini is used to enable MTRACE logging + * + * Related: None. + * + * Supported Feature: MTRACE + * + * Usage: Internal/External + * + * + */ +#define CFG_ENABLE_MTRACE CFG_INI_BOOL( \ + "enable_mtrace", \ + false, \ + "Enable MTRACE") +#define CFG_ENABLE_MTRACE_ALL CFG(CFG_ENABLE_MTRACE) +#else +#define CFG_ENABLE_MTRACE_ALL +#endif + +/* + * + * gAdvertiseConcurrentOperation - Iface combination advertising + * @Min: 0 + * @Max: 1 + * @Default: 1 + * + * This ini is used to control whether driver should indicate to kernel + * wiphy layer the combination of all its interfaces' supportability. + * + * Related: None + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define CFG_ADVERTISE_CONCURRENT_OPERATION CFG_INI_BOOL( \ + "gAdvertiseConcurrentOperation", \ + 1, \ + "Iface combination advertising") + +/* + * + * gEnableUnitTestFramework - Enable/Disable unit test framework + * @Min: 0 + * @Max: 1 + * @Default: 0 + * + * Related: None + * + * Supported Feature: unit test framework + * + * Usage: Internal (only for dev and test team) + * + * + */ +#define CFG_ENABLE_UNIT_TEST_FRAMEWORK CFG_INI_BOOL( \ + "gEnableUnitTestFramework", \ + 0, \ + "Enable/Disable unit test framework") + +/* + * + * gDisableChannel - Used to disable channels specified + * + * @Min: 0 + * @Max: 1 + * Default: 0 + * + * This ini is used to disable the channels given in the command + * SET_DISABLE_CHANNEL_LIST and to restore the channels when the + * command is given with channel list as 0 + * Usage: External + * + * + */ +#define CFG_ENABLE_DISABLE_CHANNEL CFG_INI_BOOL( \ + "gDisableChannel", \ + 0, \ + "Enable/Disable to disable channels specified") + +/* + * + * gEnableSARV1toSARV2 - Used to Enable/Disable SAR version conversion + * + * @Min: 0 + * @Max: 1 + * Default: 1 + * + * If user space is using SARV1 and FW is using SARV2 in BDF in that case + * this ini is used to enable conversion from user specified SARV1 command + * to FW expected SARV2 command. + * If value of this ini is set to 0, SAR version 1 will + * not be converted to SARV2 and command will be rejected. + * If value of this ini is set to 1 SAR version 1 will be converted to + * SARV2 based on FW capability + * Usage: External + * + * + */ +#define CFG_SAR_CONVERSION CFG_INI_BOOL( \ + "gEnableSARV1toSARV2", \ + 1, \ + "Enable/Disable conversion from SARV1 to SARV2") + +/* + * + * nb_commands_interval - Used to rate limit nb commands from userspace + * + * @Min: 0 + * @Max: 10 + * Default: 3 + * + * This ini is used to specify the duration in which any supp. nb command from + * userspace will not be processed completely in driver. For ex, the default + * value of 3 seconds signifies that consecutive commands within that + * time will not be processed fully. + * + * Usage: Internal + * + * + */ +#define CFG_NB_COMMANDS_RATE_LIMIT CFG_INI_UINT( \ + "nb_commands_interval", \ + 0, \ + 10, \ + 3, \ + CFG_VALUE_OR_DEFAULT, \ + "Rate limiting for nb commands") + +#ifdef WLAN_FEATURE_PERIODIC_STA_STATS +/* + * + * periodic_stats_timer_interval - Print selective stats on this specified + * interval + * + * @Min: 0 + * @Max: 10000 + * Default: 3000 + * + * This ini is used to specify interval in milliseconds for periodic stats + * timer. This timer will print selective stats after expiration of each + * interval. STA starts this periodic timer after initial connection or after + * roaming is successful. This will be restarted for every + * periodic_stats_timer_interval till the periodic_stats_timer_duration expires. + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_PERIODIC_STATS_TIMER_INTERVAL CFG_INI_UINT( \ + "periodic_stats_timer_interval", \ + 0, \ + 10000, \ + 3000, \ + CFG_VALUE_OR_DEFAULT, \ + "Periodic stats timer interval") + +/* + * + * periodic_stats_timer_duration - Used as duration for which periodic timer + * should run + * + * @Min: 0 + * @Max: 60000 + * Default: 30000 + * + * This ini is used as duration in milliseconds for which periodic stats timer + * should run. This periodic timer will print selective stats for every + * periodic_stats_timer_interval until this duration is reached. + * + * Supported Feature: STA + * + * Usage: Internal + * + * + */ +#define CFG_PERIODIC_STATS_TIMER_DURATION CFG_INI_UINT( \ + "periodic_stats_timer_duration", \ + 0, \ + 60000, \ + 30000, \ + CFG_VALUE_OR_DEFAULT, \ + "Periodic stats timer duration") + +#define CFG_WLAN_STA_PERIODIC_STATS \ + CFG(CFG_PERIODIC_STATS_TIMER_DURATION) \ + CFG(CFG_PERIODIC_STATS_TIMER_INTERVAL) +#else +#define CFG_WLAN_STA_PERIODIC_STATS +#endif /* WLAN_FEATURE_PERIODIC_STA_STATS */ + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +/* + * + * club_get_sta_in_ll_stats_req - Flag used to club ll_stats and get_station + * requests in the driver + * + * @Min: 0 + * @Max: 1 + * Default: 1 + * + * This ini param is used to enable/disable the feature for clubbing ll stats + * and get station requests. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_CLUB_LL_STA_AND_GET_STATION CFG_INI_BOOL( \ + "club_get_sta_in_ll_stats_req", \ + 1, \ + "Club ll_stats and get station requests") + +/* + * + * sta_stats_cache_expiry_time - Expiry time for cached station stats + * + * @Min: 0 + * @Max: 5000 + * Default: 400 + * + * This ini is used as duration in milliseconds for which cached station stats + * are valid. Driver sends the cached information as response, if it gets the + * get_station request with in this duration. Otherwise driver sends new + * request to the firmware to get the updated stats. + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define CFG_STA_STATS_CACHE_EXPIRY CFG_INI_UINT( \ + "sta_stats_cache_expiry_time", \ + 0, \ + 5000, \ + 400, \ + CFG_VALUE_OR_DEFAULT, \ + "Station stats cache expiry") + +#define CFG_WLAN_CLUB_GET_STA_IN_LL_STA_REQ \ + CFG(CFG_CLUB_LL_STA_AND_GET_STATION) \ + CFG(CFG_STA_STATS_CACHE_EXPIRY) +#else +#define CFG_WLAN_CLUB_GET_STA_IN_LL_STA_REQ +#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */ + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * + * link_state_cache_expiry_time - Expiry time for cached ml link state + * + * @Min: 0 + * @Max: 5000 + * Default: 400 + * + * This ini is used as duration in milliseconds for which cached ml link state + * are valid. Driver sends the cached information as response, if it gets the + * ml link state request with in this duration. Otherwise driver sends new + * request to the firmware to get the updated ml link state. + * + * Supported Feature: MLO STA + * + * Usage: External + * + * + */ +#define CFG_LINK_STATE_CACHE_EXPIRY CFG_INI_UINT( \ + "link_state_cache_expiry_time", \ + 0, \ + 5000, \ + 400, \ + CFG_VALUE_OR_DEFAULT, \ + "link state cache expiry") + +#define CFG_LINK_STATE_CACHE_EXPIRY_ALL \ + CFG(CFG_LINK_STATE_CACHE_EXPIRY) +#else +#define CFG_LINK_STATE_CACHE_EXPIRY_ALL +#endif /* WLAN_FEATURE_11BE_MLO */ + +/** + * enum host_log_level - Debug verbose level imposed by user + * @HOST_LOG_LEVEL_NONE: no trace will be logged. + * @HOST_LOG_LEVEL_FATAL: fatal error will be logged + * @HOST_LOG_LEVEL_ERROR: error(include level less than error) will be logged + * @HOST_LOG_LEVEL_WARN: warning(include level less than warning) will be logged + * @HOST_LOG_LEVEL_INFO: inform(include level less than inform) will be logged + * @HOST_LOG_LEVEL_DEBUG: debug(include level less than debug) will be logged + * @HOST_LOG_LEVEL_TRACE: trace(include level less than trace) will be logged + * @HOST_LOG_LEVEL_MAX: Max host log level + */ +enum host_log_level { + HOST_LOG_LEVEL_NONE = 0, + HOST_LOG_LEVEL_FATAL, + HOST_LOG_LEVEL_ERROR, + HOST_LOG_LEVEL_WARN, + HOST_LOG_LEVEL_INFO, + HOST_LOG_LEVEL_DEBUG, + HOST_LOG_LEVEL_TRACE, + HOST_LOG_LEVEL_MAX, +}; + +/* + * + * gHostModuleLoglevel - modulized host debug log level + * @Min: N/A + * @Max: N/A + * @Default: N/A + * + * This ini is used to set modulized host debug log level. + * WLAN host module log level input string format looks like below: + * gHostModuleLoglevel=",,..." + * For example: + * gHostModuleLoglevel=51,1,52,2,53,3,54,4,55,5,56,6 + * The above input string means: + * For WLAN host module ID 51 enable log level HOST_LOG_LEVEL_FATAL + * For WLAN host module ID 52 enable log level HOST_LOG_LEVEL_ERROR + * For WLAN host module ID 53 enable log level HOST_LOG_LEVEL_WARN + * For WLAN host module ID 54 enable log level HOST_LOG_LEVEL_INFO + * For WLAN host module ID 55 enable log level HOST_LOG_LEVEL_DEBUG + * For WLAN host module ID 55 enable log level HOST_LOG_LEVEL_TRACE + * For valid values of module ids check enum QDF_MODULE_ID and + * for valid values of log levels check below. + * HOST_LOG_LEVEL_NONE = 0, No trace will be logged + * HOST_LOG_LEVEL_FATAL = 1, fatal error log + * HOST_LOG_LEVEL_ERROR = 2, error(include level less than error) log + * HOST_LOG_LEVEL_WARN = 3, warning(include level less than warning) log + * HOST_LOG_LEVEL_INFO = 4, inform(include level less than inform) log + * HOST_LOG_LEVEL_DEBUG = 5, debug(include level less than debug) log + * HOST_LOG_LEVEL_TRACE = 6, trace(include level less than trace) log + * + * Related: None + * + * Supported Feature: Debugging + * + * Usage: Internal + * + * + */ + +#define HOST_MODULE_LOG_LEVEL_STRING_MAX_LENGTH (QDF_MODULE_ID_MAX * 6) +#define CFG_ENABLE_HOST_MODULE_LOG_LEVEL CFG_INI_STRING( \ + "gHostModuleLoglevel", \ + 0, \ + HOST_MODULE_LOG_LEVEL_STRING_MAX_LENGTH, \ + "", \ + "Set modulized host debug log level") + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +/* + * + * dynamic_mac_addr_update_supported - Flag to configure dynamic MAC address + * support in the driver + * + * @Min: 0 + * @Max: 1 + * Default: 1 + * + * This ini param is used to enable/disable the dynamic MAC address support + * in the driver. + * + * Supported Feature: STA/SAP/P2P_Device + * + * Usage: External + * + * + */ +#define CFG_DYNAMIC_MAC_ADDR_UPDATE_SUPPORTED CFG_INI_BOOL( \ + "dynamic_mac_addr_update_supported", \ + 1, \ + "Dynamic MAC address update support") +#define CFG_DYNAMIC_MAC_ADDR_UPDATE_SUPPORTED_ALL \ + CFG(CFG_DYNAMIC_MAC_ADDR_UPDATE_SUPPORTED) +#else +#define CFG_DYNAMIC_MAC_ADDR_UPDATE_SUPPORTED_ALL +#endif + +/* + * + * exclude_selftx_from_cca_busy_time - Exclude self tx time from cca busy time + * @Default: false + * + * This ini is used to exclude self tx time from cca busy time. + * + * false: Don't exclude self tx time from cca busy time. + * true: Deduct tx time from cca busy time. + * + * Usage: External + * + * + */ +#define CFG_EXCLUDE_SELFTX_FROM_CCA_BUSY_TIME CFG_INI_BOOL( \ + "exclude_selftx_from_cca_busy_time", \ + false, \ + "This ini is used to exclude self tx time from CCA busy time") + +#define CFG_HDD_ALL \ + CFG_DYNAMIC_MAC_ADDR_UPDATE_SUPPORTED_ALL \ + CFG_ENABLE_PACKET_LOG_ALL \ + CFG_ENABLE_RUNTIME_PM_ALL \ + CFG_ENABLE_QMI_STATS_ALL \ + CFG_VC_MODE_BITMAP_ALL \ + CFG_WLAN_AUTO_SHUTDOWN_ALL \ + CFG_WLAN_CLUB_GET_STA_IN_LL_STA_REQ \ + CFG_WLAN_LOGGING_SUPPORT_ALL \ + CFG_WLAN_STA_PERIODIC_STATS \ + CFG(CFG_ADVERTISE_CONCURRENT_OPERATION) \ + CFG(CFG_BUG_ON_REINIT_FAILURE) \ + CFG(CFG_DBS_SCAN_SELECTION) \ + CFG(CFG_DERIVED_INTERFACE_POOL) \ + CFG(CFG_ENABLE_CONCURRENT_STA) \ + CFG(CFG_ENABLE_FW_LOG) \ + CFG(CFG_ENABLE_FW_UART_PRINT) \ + CFG(CFG_ENABLE_MAC_PROVISION) \ + CFG_ENABLE_MTRACE_ALL \ + CFG(CFG_ENABLE_RAMDUMP_COLLECTION) \ + CFG(CFG_ENABLE_UNIT_TEST_FRAMEWORK) \ + CFG(CFG_INTERFACE_CHANGE_WAIT) \ + CFG(CFG_INFORM_BSS_RSSI_RAW) \ + CFG(CFG_MULTICAST_HOST_FW_MSGS) \ + CFG(CFG_NUM_VDEV_ENABLE) \ + CFG(CFG_OPERATING_FREQUENCY) \ + CFG(CFG_PRIVATE_WEXT_CONTROL) \ + CFG(CFG_PROVISION_INTERFACE_POOL) \ + CFG(CFG_TIMER_MULTIPLIER) \ + CFG(CFG_NB_COMMANDS_RATE_LIMIT) \ + CFG(CFG_HDD_DOT11_MODE) \ + CFG(CFG_ENABLE_DISABLE_CHANNEL) \ + CFG(CFG_READ_MAC_ADDR_FROM_MAC_FILE) \ + CFG(CFG_SAR_CONVERSION) \ + CFG(CFG_ENABLE_HOST_MODULE_LOG_LEVEL) \ + SAR_SAFETY_FEATURE_ALL \ + CFG_GET_WIFI_FEATURES_ALL \ + CFG_CPU_CXPC_THRESHOLD_ALL \ + CFG(CFG_EXCLUDE_SELFTX_FROM_CCA_BUSY_TIME) \ + CFG_LINK_STATE_CACHE_EXPIRY_ALL +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_dp_cfg.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_dp_cfg.h new file mode 100644 index 0000000000..2e2118901d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_dp_cfg.h @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __HDD_DP_CONFIG_H +#define __HDD_DP_CONFIG_H + +#define CFG_ENABLE_RX_THREAD BIT(0) +#define CFG_ENABLE_RPS BIT(1) +#define CFG_ENABLE_NAPI BIT(2) +#define CFG_ENABLE_DYNAMIC_RPS BIT(3) +#define CFG_ENABLE_DP_RX_THREADS BIT(4) +#define CFG_RX_MODE_MAX (CFG_ENABLE_RX_THREAD | \ + CFG_ENABLE_RPS | \ + CFG_ENABLE_NAPI | \ + CFG_ENABLE_DYNAMIC_RPS | \ + CFG_ENABLE_DP_RX_THREADS) +#ifdef MDM_PLATFORM +#define CFG_RX_MODE_DEFAULT 0 +#elif defined(HELIUMPLUS) +#define CFG_RX_MODE_DEFAULT CFG_ENABLE_NAPI +#endif + +#ifndef CFG_RX_MODE_DEFAULT +#if defined(FEATURE_WLAN_DP_RX_THREADS) +#define CFG_RX_MODE_DEFAULT (CFG_ENABLE_DP_RX_THREADS | CFG_ENABLE_NAPI) +#else +#define CFG_RX_MODE_DEFAULT (CFG_ENABLE_RX_THREAD | CFG_ENABLE_NAPI) +#endif +#endif + +/* Max # of packets to be processed in 1 tx comp loop */ +#define CFG_DP_TX_COMP_LOOP_PKT_LIMIT_DEFAULT 64 +#define CFG_DP_TX_COMP_LOOP_PKT_LIMIT_MAX (1024 * 1024) + +/*Max # of packets to be processed in 1 rx reap loop */ +#define CFG_DP_RX_REAP_LOOP_PKT_LIMIT_DEFAULT 64 +#define CFG_DP_RX_REAP_LOOP_PKT_LIMIT_MAX (1024 * 1024) + +/* Max # of HP OOS (out of sync) updates */ +#define CFG_DP_RX_HP_OOS_UPDATE_LIMIT_DEFAULT 0 +#define CFG_DP_RX_HP_OOS_UPDATE_LIMIT_MAX 1024 + +/* Max Yield time duration for RX Softirq */ +#define CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_DEFAULT (500 * 1000) +#define CFG_DP_RX_SOFTIRQ_MAX_YIELD_TIME_NS_MAX (10 * 1000 * 1000) + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + +/* + * + * TxFlowLowWaterMark - Low watermark for pausing network queues + * + * @Min: 0 + * @Max: 1000 + * @Default: 300 + * + * This ini specifies the low watermark of data packets transmitted + * before pausing netif queues in tx flow path. It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowHighWaterMarkOffset, TxFlowMaxQueueDepth, + * TxLbwFlowLowWaterMark, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_FLOW_LWM \ + CFG_INI_UINT( \ + "TxFlowLowWaterMark", \ + 0, \ + 1000, \ + 300, \ + CFG_VALUE_OR_DEFAULT, \ + "Low watermark for pausing network queues") + +/* + * + * TxFlowHighWaterMarkOffset - High Watermark offset to unpause Netif queues + * @Min: 0 + * @Max: 300 + * @Default: 94 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxFlowLowWaterMark. It is only applicable where legacy flow control + * is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowMaxQueueDepth, + * TxLbwFlowLowWaterMark, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_FLOW_HWM_OFFSET \ + CFG_INI_UINT( \ + "TxFlowHighWaterMarkOffset", \ + 0, \ + 300, \ + 94, \ + CFG_VALUE_OR_DEFAULT, \ + "High Watermark offset to unpause Netif queues") + +/* + * + * TxFlowMaxQueueDepth - Max pause queue depth. + * + * @Min: 400 + * @Max: 3500 + * @Default: 1500 + * + * This ini specifies the max queue pause depth.It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxLbwFlowLowWaterMark, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_FLOW_MAX_Q_DEPTH \ + CFG_INI_UINT( \ + "TxFlowMaxQueueDepth", \ + 400, \ + 3500, \ + 1500, \ + CFG_VALUE_OR_DEFAULT, \ + "Max pause queue depth") + +/* + * + * TxLbwFlowLowWaterMark - Low watermark for pausing network queues + * in low bandwidth band + * @Min: 0 + * @Max: 1000 + * @Default: 450 + * + * This ini specifies the low watermark of data packets transmitted + * before pausing netif queues in tx flow path in low bandwidth band. + * It is only applicable where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowHighWaterMarkOffset, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_LBW_FLOW_LWM \ + CFG_INI_UINT( \ + "TxLbwFlowLowWaterMark", \ + 0, \ + 1000, \ + 450, \ + CFG_VALUE_OR_DEFAULT, \ + "Low watermark for pausing network queues") + +/* + * + * TxLbwFlowHighWaterMarkOffset - High Watermark offset to unpause Netif queues + * in low bandwidth band. + * @Min: 0 + * @Max: 300 + * @Default: 50 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxLbwFlowLowWaterMark in low bandwidth band. It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowMaxQueueDepth, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_LBW_FLOW_HWM_OFFSET \ + CFG_INI_UINT( \ + "TxLbwFlowHighWaterMarkOffset", \ + 0, \ + 300, \ + 50, \ + CFG_VALUE_OR_DEFAULT, \ + "High Watermark offset to unpause Netif queues") + +/* + * + * TxLbwFlowMaxQueueDepth - Max pause queue depth in low bandwidth band + * + * @Min: 400 + * @Max: 3500 + * @Default: 750 + * + * This ini specifies the max queue pause depth in low bandwidth band. + * It is only applicable where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxHbwFlowLowWaterMark, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_LBW_FLOW_MAX_Q_DEPTH \ + CFG_INI_UINT( \ + "TxLbwFlowMaxQueueDepth", \ + 400, \ + 3500, \ + 750, \ + CFG_VALUE_OR_DEFAULT, \ + "Max pause queue depth in low bandwidth band") + +/* + * + * TxHbwFlowLowWaterMark - Low watermark for pausing network queues + * in high bandwidth band + * @Min: 0 + * @Max: 1000 + * @Default: 406 + * + * This ini specifies the threshold of data packets transmitted + * before pausing netif queues.It is only applicable where + * legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxLbwFlowMaxQueueDepth, + * TxHbwFlowHighWaterMarkOffset, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_HBW_FLOW_LWM \ + CFG_INI_UINT( \ + "TxHbwFlowLowWaterMark", \ + 0, \ + 1000, \ + 406, \ + CFG_VALUE_OR_DEFAULT, \ + "Low watermark for pausing network queues") + +/* + * + * TxHbwFlowHighWaterMarkOffset - High Watermark offset to unpause Netif queues + * in high bandwidth band. + * @Min: 0 + * @Max: 300 + * @Default: 94 + * + * This ini specifies the offset to upause the netif queues + * when they are paused due to insufficient descriptors as guided by + * ini TxHbwFlowLowWaterMark in high bandwidth band. It is only applicable + * where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxLbwFlowMaxQueueDepth, + * TxHbwFlowLowWaterMark, TxHbwFlowMaxQueueDepth + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_HBW_FLOW_HWM_OFFSET \ + CFG_INI_UINT( \ + "TxHbwFlowHighWaterMarkOffset", \ + 0, \ + 300, \ + 94, \ + CFG_VALUE_OR_DEFAULT, \ + "High Watermark offset to unpause Netif queues") + +/* + * + * TxHbwFlowMaxQueueDepth - Max pause queue depth in high bandwidth band + * @Min: 4000 + * @Max: 3500 + * @Default: 1500 + * + * This ini specifies the max queue pause depth in high bandwidth band. + * It is only applicable where legacy flow control is used i.e.for Rome. + * + * Related: TxFlowLowWaterMark, TxFlowHighWaterMarkOffset, + * TxFlowMaxQueueDepth, TxLbwFlowLowWaterMark, + * TxLbwFlowHighWaterMarkOffset, TxLbwFlowMaxQueueDepth, + * TxHbwFlowLowWaterMark, TxHbwFlowHighWaterMarkOffset + * + * Supported Feature: Dynamic Flow Control + * + * Usage: Internal + * + * + */ +#define CFG_DP_LL_TX_HBW_FLOW_MAX_Q_DEPTH \ + CFG_INI_UINT( \ + "TxHbwFlowMaxQueueDepth", \ + 400, \ + 3500, \ + 1500, \ + CFG_VALUE_OR_DEFAULT, \ + "Max pause queue depth in high bandwidth band") + +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef WLAN_FEATURE_MSCS +/* + * + * mscs_pkt_threshold - Voice pkt count threshold + * + * @Min: 0 + * @Max: 10000 + * @Default: 1200 + * + * This ini specifies the Voice pkt count threshold to + * Send MSCS action frame to AP + * + * Usage: Internal + * + * + */ +#define CFG_VO_PKT_COUNT_THRESHOLD \ + CFG_INI_UINT( \ + "mscs_pkt_threshold", \ + 0, \ + 10000, \ + 1200, \ + CFG_VALUE_OR_DEFAULT, \ + "Voice pkt count threshold") + +/* + * + * mscs_voice_interval - mscs voice interval in sec + * + * @Min: 0 + * @Max: 300 + * @Default: 30 + * + * This ini specifies the mscs voice interval to + * monitor voice tx packet count to send MSCS action frame + * + * Related: mscs_pkt_threshold + * + * Usage: Internal + * + * + */ +#define CFG_MSCS_VOICE_INTERVAL \ + CFG_INI_UINT( \ + "mscs_voice_interval", \ + 0, \ + 300, \ + 30, \ + CFG_VALUE_OR_DEFAULT, \ + "mscs voice interval") + +#define CFG_MSCS_FEATURE_ALL \ + CFG(CFG_VO_PKT_COUNT_THRESHOLD) \ + CFG(CFG_MSCS_VOICE_INTERVAL) + +#else +#define CFG_MSCS_FEATURE_ALL +#endif + +/* + * + * NAPI_CPU_AFFINITY_MASK - CPU mask to affine NAPIs + * + * @Min: 0 + * @Max: 0xFF + * @Default: 0 + * + * This ini is used to set NAPI IRQ CPU affinity + * + * Supported Feature: NAPI + * + * Usage: Internal + * + * + */ +#define CFG_DP_NAPI_CE_CPU_MASK \ + CFG_INI_UINT( \ + "NAPI_CPU_AFFINITY_MASK", \ + 0, \ + 0xFF, \ + 0, \ + CFG_VALUE_OR_DEFAULT, \ + "CPU mask to affine NAPIs") + +/* + * + * gWmiCreditCount - Credit count for WMI exchange + * @0: Not allowed + * @1: Serialize WMI commands, 1 command at a time + * @Default: 2: As advertised by FW + * + * This ini is used to serialize the WMI commandsif required. + * + * Related: None + * + * Usage: External + * + * + */ +#define WLAN_CFG_WMI_CREDIT_DEFAULT 0 +#define WLAN_CFG_WMI_CREDIT_MIN 1 +#define WLAN_CFG_WMI_CREDIT_MAX 2 + +#define CFG_DP_HTC_WMI_CREDIT_CNT \ + CFG_INI_UINT("gWmiCreditCount", \ + WLAN_CFG_WMI_CREDIT_MIN, \ + WLAN_CFG_WMI_CREDIT_MAX, \ + WLAN_CFG_WMI_CREDIT_DEFAULT, \ + CFG_VALUE_OR_DEFAULT, "WMI HTC CREDIT COUNT") + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +#define CFG_HDD_DP_LEGACY_TX_FLOW \ + CFG(CFG_DP_LL_TX_FLOW_LWM) \ + CFG(CFG_DP_LL_TX_FLOW_HWM_OFFSET) \ + CFG(CFG_DP_LL_TX_FLOW_MAX_Q_DEPTH) \ + CFG(CFG_DP_LL_TX_LBW_FLOW_LWM) \ + CFG(CFG_DP_LL_TX_LBW_FLOW_HWM_OFFSET) \ + CFG(CFG_DP_LL_TX_LBW_FLOW_MAX_Q_DEPTH) \ + CFG(CFG_DP_LL_TX_HBW_FLOW_LWM) \ + CFG(CFG_DP_LL_TX_HBW_FLOW_HWM_OFFSET) \ + CFG(CFG_DP_LL_TX_HBW_FLOW_MAX_Q_DEPTH) +#else +#define CFG_HDD_DP_LEGACY_TX_FLOW +#endif + +#ifdef FEATURE_ENABLE_CE_DP_IRQ_AFFINE +/* + * + * Enable_ce_dp_irq_affine - Enable/disable affinity on datapath CE IRQs + * + * @Min: 0 + * @Max: 1 + * Default: 0 + * + * This ini param is used to enable/disable the affinity on datapath + * Copy Engine IRQs. + * + * Supported Feature: STA/SAP + * + * Usage: External + * + * + */ +#define CFG_ENABLE_CE_DP_IRQ_AFFINE CFG_INI_BOOL(\ + "Enable_ce_dp_irq_affine", \ + 0, \ + "Enable/disable irq affinity on datapath CEs") +#define CFG_ENABLE_CE_DP_IRQ_AFFINE_ALL \ + CFG(CFG_ENABLE_CE_DP_IRQ_AFFINE) +#else +#define CFG_ENABLE_CE_DP_IRQ_AFFINE_ALL +#endif + +#define CFG_HDD_DP_ALL \ + CFG(CFG_DP_NAPI_CE_CPU_MASK) \ + CFG(CFG_DP_HTC_WMI_CREDIT_CNT) \ + CFG_MSCS_FEATURE_ALL \ + CFG_HDD_DP_LEGACY_TX_FLOW \ + CFG_ENABLE_CE_DP_IRQ_AFFINE_ALL +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_sar_safety_config.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_sar_safety_config.h new file mode 100644 index 0000000000..d6da096b7c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/hdd_sar_safety_config.h @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of converged configuration. + */ + +#ifndef __HDD_SAR_SAFETY_CONFIG_H +#define __HDD_SAR_SAFETY_CONFIG_H + +#ifdef SAR_SAFETY_FEATURE + +/* + * SAR_SAFETY_DISABLED - feature disabled + * SAR_SAFETY_ENABLED_TIMER - SAR feature enabled with timer mechanism + * SAR_SAFETY_ENABLED_INIT - SAR feature enabled at init time + * SAR_SAFETY_ENABLED_MAX - SAR max valid value + */ +#define SAR_SAFETY_DISABLED 0x0 +#define SAR_SAFETY_ENABLED_TIMER BIT(0) +#define SAR_SAFETY_ENABLED_INIT BIT(1) +#define SAR_SAFETY_ENABLED_MAX 0x3 +/* + * + * gSarSafetyTimeout - Specify SAR safety timeout value in milliseconds + * + * @Min: 120000 + * @Max: 600000 + * Default: 300000 + * + * This ini is used to define SAR safety timeout value in milliseconds. + * This timer is started when the QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS + * is received first time. + * SAR safety timer will wait for the gSarSafetyTimeout for + * QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command and if + * SAR safety timer timeouts host will configure the gSarSafetyIndex + * to the FW. + * + * Usage: External + * + * + */ + +#define CFG_SAR_SAFETY_TIMEOUT CFG_INI_UINT( \ + "gSarSafetyTimeout", \ + 120000, \ + 600000, \ + 300000, \ + CFG_VALUE_OR_DEFAULT, \ + "Timeout value for SAR safety timer") + +/* + * + * gSarSafetyUnsolicitedTimeout - Specify SAR safety unsolicited timeout value + * in milliseconds + * + * @Min: 5000 + * @Max: 30000 + * Default: 15000 + * + * This ini is used to define SAR safety unsolicited timeout value in + * milliseconds. This timer is started on first data tx. + * SAR unsolicited timer will wait for the + * gSarSafetyUnsolicitedTimeout for QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS + * vendor command and if SAR unsolicited timer timeouts host will indicate + * user space with QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT to send + * QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command. + * + * Usage: External + * + * + */ + +#define CFG_SAR_SAFETY_UNSOLICITED_TIMEOUT CFG_INI_UINT( \ + "gSarSafetyUnsolicitedTimeout", \ + 5000, \ + 30000, \ + 15000, \ + CFG_VALUE_OR_DEFAULT, \ + "Timeout value for SAR Unsolicited timer") + +/* + * + * gSarSafetyReqRespTimeout - Specify SAR safety request response timeout value + * in milliseconds + * + * @Min: 500 + * @Max: 3000 + * Default: 1000 + * + * This ini is used to define SAR request-response timeout value + * in milliseconds. SAR request-response timer will wait for the + * gSarSafetyReqRespTimeout for QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS + * vendor command and if SAR request-response timer timeouts host will + * indicate user space with QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_EVENT + * for gSarSafetyReqRespRetry number of times to send + * QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command and still if host + * does not get QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command, host + * will configure the gSarSafetyIndex to the FW. + * + * Usage: External + * + * + */ + +#define CFG_SAR_SAFETY_REQ_RESP_TIMEOUT CFG_INI_UINT( \ + "gSarSafetyReqRespTimeout", \ + 500, \ + 1000, \ + 1000, \ + CFG_VALUE_OR_DEFAULT, \ + "Timeout value for SAR safety request response timer") + +/* + * + * gSarSafetyReqRespRetry - Specify SAR request response retries value + * + * @Min: 1 + * @Max: 10 + * Default: 5 + * + * This ini is used to define SAR request-response retries value. + * SAR request-response timer will wait for the gSarReqRespTimeout for + * QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command and if + * SAR request-response timer timeouts host will indicate user space + * for gSarSafetyReqRespRetry number of times to send + * QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor command and still if + * host does not get QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS vendor + * command, host will configure the gSarSafetyIndex to the FW. + * + * Usage: External + * + * + */ + +#define CFG_SAR_SAFETY_REQ_RESP_RETRIES CFG_INI_UINT( \ + "gSarSafetyReqRespRetry", \ + 1, \ + 5, \ + 5, \ + CFG_VALUE_OR_DEFAULT, \ + "Max Number of SAR Request Response Retries") + +/* + * + * gSarSafetyIndex - Specify SAR safety index + * + * @Min: 0 + * @Max: 11 + * Default: 11 + * + * This ini is used to define SAR safety index, when sar safety timer + * timeouts or sar request response timer timeouts for gSarSafetyReqRespRetry + * number of times, host will configure gSarSafetyIndex value to the FW. + * + * Usage: External + * + * + */ + +#define CFG_SAR_SAFETY_INDEX CFG_INI_UINT( \ + "gSarSafetyIndex", \ + 0, \ + 11, \ + 11, \ + CFG_VALUE_OR_DEFAULT, \ + "SAR safety index value") +/* + * + * gSarSafetySleepIndex - Specify SAR Safety sleep index + * + * @Min: 0 + * @Max: 11 + * Default: 11 + * + * This ini is used to define SAR sleep index, when device goes into the + * sleep mode, before going into the sleep mode host configures + * gSarSafetySleepIndex value to the FW. + * + * Usage: External + * + * + */ + +#define CFG_SAR_SAFETY_SLEEP_INDEX CFG_INI_UINT( \ + "gSarSafetySleepIndex", \ + 0, \ + 11, \ + 11, \ + CFG_VALUE_OR_DEFAULT, \ + "SAR safety sleep index value") + +/* + * + * gEnableSarSafety - Enable/Disable SAR safety feature + * this ini is also used to set SAR index at init time + * + * @Min: 0 + * @Max: 3 + * Default: 0 + * + * This ini is used to enable/disable SAR safety feature + * Value 0 of this ini disables SAR safety feature and + * value 1 of this ini enables SAR safety feature and + * value 2 of this ini enable setting SAR index at init time + * value 3 of this enables both modes + * + * Usage: External + * + * + */ + +#define CFG_ENABLE_SAR_SAFETY_FEATURE CFG_INI_UINT( \ + "gEnableSarSafety", \ + SAR_SAFETY_DISABLED, \ + SAR_SAFETY_ENABLED_MAX, \ + SAR_SAFETY_DISABLED, \ + CFG_VALUE_OR_DEFAULT, \ + "Enable/Disable SAR safety feature type") + +/* + * + * gConfigSarSafetySleepIndex - Enable/Disable SAR Safety sleep index + * + * @Min: 0 + * @Max: 1 + * Default: 0 + * + * This Configuration is to decide that before going to + * sleep mode whether to maintain high RF power + * (SAR disable) or to configure SAR sleep mode index + * + * Value 0 for this ini indicates to maintain high + * RF power (SAR disable) + * Value 1 for this ini indicates to configure SAR + * sleep mode index. + * + * Usage: External + * + * + */ + +#define CFG_CONFIG_SAR_SAFETY_SLEEP_MODE_INDEX CFG_INI_BOOL( \ + "gConfigSarSafetySleepIndex", \ + 0, \ + "Config SAR sleep Index") + +#define SAR_SAFETY_FEATURE_ALL \ + CFG(CFG_SAR_SAFETY_TIMEOUT) \ + CFG(CFG_SAR_SAFETY_UNSOLICITED_TIMEOUT) \ + CFG(CFG_SAR_SAFETY_REQ_RESP_TIMEOUT) \ + CFG(CFG_SAR_SAFETY_REQ_RESP_RETRIES) \ + CFG(CFG_SAR_SAFETY_INDEX) \ + CFG(CFG_SAR_SAFETY_SLEEP_INDEX) \ + CFG(CFG_ENABLE_SAR_SAFETY_FEATURE) \ + CFG(CFG_CONFIG_SAR_SAFETY_SLEEP_MODE_INDEX) \ + +#else +#define SAR_SAFETY_FEATURE_ALL +#endif + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h new file mode 100644 index 0000000000..e7d194a29a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/qc_sap_ioctl.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _QC_SAP_IOCTL_H_ +#define _QC_SAP_IOCTL_H_ + +/* + * QCSAP ioctls. + */ + +/* + * Channel List Info + */ + +struct channel_list_info { + uint8_t num_channels; + uint8_t channels[NUM_CHANNELS]; +}; + +#ifdef __linux__ +/* + * Wireless Extensions API, private ioctl interfaces. + * + * NB: Even-numbered ioctl numbers have set semantics and are privileged! + * (regardless of the incorrect comment in wireless.h!) + */ + +#define QCSAP_IOCTL_SETPARAM (SIOCIWFIRSTPRIV + 0) +#define QCSAP_IOCTL_GETPARAM (SIOCIWFIRSTPRIV + 1) +/* (SIOCIWFIRSTPRIV+2) is unused */ +#define QCSAP_IOCTL_SET_NONE_GET_THREE (SIOCIWFIRSTPRIV + 3) +#define WE_GET_TSF 1 +#define QCSAP_IOCTL_GET_STAWPAIE (SIOCIWFIRSTPRIV + 4) +#define QCSAP_IOCTL_STOPBSS (SIOCIWFIRSTPRIV + 6) +#define QCSAP_IOCTL_VERSION (SIOCIWFIRSTPRIV + 7) +/* (SIOCIWFIRSTPRIV + 8) is unused */ +#define QCSAP_IOCTL_GET_CHANNEL (SIOCIWFIRSTPRIV + 9) +#define QCSAP_IOCTL_ASSOC_STA_MACADDR (SIOCIWFIRSTPRIV + 10) +#define QCSAP_IOCTL_DISASSOC_STA (SIOCIWFIRSTPRIV + 11) +#define QCSAP_IOCTL_SET_PKTLOG (SIOCIWFIRSTPRIV + 12) + +/* Private ioctls and their sub-ioctls */ +#define QCSAP_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 13) +#define QCSAP_GET_STATS 1 +#define QCSAP_LIST_FW_PROFILE 2 + +/* (SIOCIWFIRSTPRIV + 14) is unused */ + +#define QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 15) +#define WE_SET_WLAN_DBG 1 +#define WE_SET_DP_TRACE 2 +#define QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 16) +#define WE_UNIT_TEST_CMD 7 +/* + * + * ch_avoid - unit test SAP channel avoidance + * + * @INPUT: chan avoid ranges + * + * @OUTPUT: none + * + * This IOCTL is used to fake a channel avoidance event. + * To test SAP/GO chan switch during chan avoid event process. + * + * @E.g: iwpriv wlan0 ch_avoid 2452 2462 + * + * Supported Feature: SAP chan avoidance. + * + * Usage: Internal + * + * + */ +#define WE_SET_CHAN_AVOID 21 + +#define WE_SET_THERMAL_THROTTLE_CFG 27 + +#define WE_P2P_NOA_CMD 2 + +#define QCSAP_IOCTL_MODIFY_ACL (SIOCIWFIRSTPRIV + 18) +#define QCSAP_IOCTL_GET_CHANNEL_LIST (SIOCIWFIRSTPRIV + 19) +#define QCSAP_IOCTL_SET_TX_POWER (SIOCIWFIRSTPRIV + 20) +#define QCSAP_IOCTL_GET_STA_INFO (SIOCIWFIRSTPRIV + 21) +#define QCSAP_IOCTL_SET_MAX_TX_POWER (SIOCIWFIRSTPRIV + 22) +#define QCSAP_IOCTL_GET_INI_CFG (SIOCIWFIRSTPRIV + 25) + +#define QCSAP_IOCTL_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +/* QCSAP_IOCTL_SET_TWO_INT_GET_NONE sub commands */ +#define QCSAP_IOCTL_SET_FW_CRASH_INJECT 1 +#define QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL 2 +#define QCSAP_ENABLE_FW_PROFILE 3 +#define QCSAP_SET_FW_PROFILE_HIST_INTVL 4 +/* Private sub-ioctl for initiating WoW suspend without Apps suspend */ +#define QCSAP_SET_WLAN_SUSPEND 5 +#define QCSAP_SET_WLAN_RESUME 6 +#define QCSAP_SET_BA_AGEING_TIMEOUT 7 + +#define QCSAP_IOCTL_PRIV_GET_RSSI (SIOCIWFIRSTPRIV + 29) +#define QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED (SIOCIWFIRSTPRIV + 31) +#define QCSAP_IOCTL_GET_BA_AGEING_TIMEOUT (SIOCIWFIRSTPRIV + 32) + +#define MAX_VAR_ARGS 7 + +#define QCSAP_IOCTL_MAX_STR_LEN 1024 + +#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) + +#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf) +#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1) + +#define RC_2_RATE_IDX_11AX(_rc) ((_rc) & 0x1f) +#define HT_RC_2_STREAMS_11AX(_rc) (((_rc) >> 5) & 0x7) + +#ifdef WLAN_FEATURE_11BE +#define RC_2_RATE_IDX_11BE(_rc) ((_rc) & 0x1f) +#define HT_RC_2_STREAMS_11BE(_rc) (((_rc) >> 5) & 0x7) +#endif + +/* + * + * setRadar - simulate a radar event + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to simulate a radar event, state machines for + * SAP will behave as same way in which a radar event is reported by WMA + * + * @E.g: iwpriv wlan0 setRadar + * + * Supported Feature: DFS + * + * Usage: Internal + * + * + */ + +/* + * + * setRadarDbg - enable/disable radar specific logs + * + * @INPUT: 1/0 + * + * @OUTPUT: None + * + * This IOCTL is enable radar phyerror info in wma + * + * @E.g: iwpriv wlan0 setRadarDbg + * iwpriv wlan0 setRadarDbg 1 + * + * Supported Feature: DFS + * + * Usage: Internal + * + * + */ +enum { + QCSAP_PARAM_MAX_ASSOC = 1, + QCSAP_PARAM_GET_WLAN_DBG, + QCSAP_PARAM_CLR_ACL = 4, + QCSAP_PARAM_ACL_MODE, + QCSAP_PARAM_HIDE_SSID, + QCSAP_PARAM_SET_MC_RATE, + QCSAP_PARAM_SET_TXRX_FW_STATS, + QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY, + QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA, + QCSAP_DBGLOG_LOG_LEVEL, + QCSAP_DBGLOG_VAP_ENABLE, + QCSAP_DBGLOG_VAP_DISABLE, + QCSAP_DBGLOG_MODULE_ENABLE, + QCSAP_DBGLOG_MODULE_DISABLE, + QCSAP_DBGLOG_MOD_LOG_LEVEL, + QCSAP_DBGLOG_TYPE, + QCSAP_DBGLOG_REPORT_ENABLE, + QCASAP_TXRX_FWSTATS_RESET, + QCSAP_PARAM_RTSCTS, + QCASAP_SET_11N_RATE, + QCASAP_SET_VHT_RATE, + QCASAP_SHORT_GI, + QCSAP_SET_AMPDU, + QCSAP_SET_AMSDU, + QCSAP_GTX_HT_MCS, + QCSAP_GTX_VHT_MCS, + QCSAP_GTX_USRCFG, + QCSAP_GTX_THRE, + QCSAP_GTX_MARGIN, + QCSAP_GTX_STEP, + QCSAP_GTX_MINTPC, + QCSAP_GTX_BWMASK, + QCASAP_SET_TM_LEVEL, + QCASAP_SET_DFS_IGNORE_CAC, + QCASAP_GET_DFS_NOL, + QCASAP_SET_DFS_NOL, + QCSAP_PARAM_SET_CHANNEL_CHANGE, + QCASAP_SET_DFS_TARGET_CHNL, + QCASAP_SET_RADAR_CMD, + QCSAP_GET_ACL, + QCASAP_TX_CHAINMASK_CMD, + QCASAP_RX_CHAINMASK_CMD, + QCASAP_NSS_CMD, + QCSAP_IPA_UC_STAT, + QCASAP_SET_PHYMODE, + QCASAP_GET_TEMP_CMD, + QCASAP_DUMP_STATS, + QCASAP_CLEAR_STATS, + QCASAP_SET_RADAR_DBG, + QCSAP_GET_FW_PROFILE_DATA, + QCSAP_START_FW_PROFILING, + QCSAP_CAP_TSF, + QCSAP_GET_TSF, + QCSAP_PARAM_CONC_SYSTEM_PREF, + QCASAP_PARAM_LDPC, + QCASAP_PARAM_TX_STBC, + QCASAP_PARAM_RX_STBC, + QCSAP_PARAM_CHAN_WIDTH, + QCSAP_PARAM_SET_TXRX_STATS, + QCASAP_SET_11AX_RATE, + QCASAP_SET_PEER_RATE, /* Not Supported */ + QCASAP_PARAM_DCM, + QCASAP_PARAM_RANGE_EXT, + QCSAP_SET_DEFAULT_AMPDU, + QCSAP_ENABLE_RTS_BURSTING, + QCASAP_SET_HE_BSS_COLOR, + QCSAP_SET_BTCOEX_MODE, + QCSAP_SET_BTCOEX_LOW_RSSI_THRESHOLD, +}; + +int iw_get_channel_list_with_cc(struct net_device *dev, + mac_handle_t mac_handle, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra); + +#endif /* __linux__ */ + +#endif /*_QC_SAP_IOCTL_H_*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_afc.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_afc.h new file mode 100644 index 0000000000..50aca722e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_afc.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_afc.h + * + * This file has the AFC osif interface with linux kernel. + */ + +#ifndef __WLAN_HDD_AFC_H__ +#define __WLAN_HDD_AFC_H__ +#include +#include +#include +#include + +#ifdef CONFIG_AFC_SUPPORT + +#define FEATURE_AFC_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AFC_RESPONSE, \ + .doit = wlan_hdd_vendor_afc_response, \ + vendor_command_policy(wlan_cfg80211_afc_response_policy, \ + QCA_WLAN_VENDOR_ATTR_AFC_RESP_MAX) \ +}, + +#define FEATURE_AFC_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_AFC_EVENT, \ +}, + +/** + * wlan_hdd_vendor_afc_response() - OSIF callback function of NL vendor AFC + * response command. + * @wiphy: Pointer to WIPHY object + * @wdev: Pointer to wireless device + * @data: Pointer to NL vendor command of AFC response + * @data_len: Length of NL vendor command of AFC response + * + * Return: 0 if success, otherwise error code + */ +int wlan_hdd_vendor_afc_response(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_register_afc_pld_cb() - API to register AFC PLD function to pass + * AFC response data to target. + * @psoc: Pointer to PSOC object + * + * Return: None + */ +void wlan_hdd_register_afc_pld_cb(struct wlan_objmgr_psoc *psoc); +#else +#define FEATURE_AFC_VENDOR_COMMANDS +#define FEATURE_AFC_VENDOR_EVENTS + +static inline void wlan_hdd_register_afc_pld_cb(struct wlan_objmgr_psoc *psoc) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_apf.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_apf.h new file mode 100644 index 0000000000..65682ae307 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_apf.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_apf.h + * + * Android Packet Filter related API's and definitions + */ + +#ifndef __WLAN_HDD_APF_H +#define __WLAN_HDD_APF_H + +#ifdef FEATURE_WLAN_APF + +#include +#include "sir_api.h" +#include "wlan_hdd_main.h" +#include "wmi_unified_param.h" +#include "qca_vendor.h" + +#define APF_CONTEXT_MAGIC 0x4575354 + +#define MAX_APF_MEMORY_LEN 4096 + +/* APF commands wait times in msec */ +#define WLAN_WAIT_TIME_APF_READ_MEM 10000 + +/* QCA_NL80211_VENDOR_PACKET_FILTER policy */ +extern const struct nla_policy wlan_hdd_apf_offload_policy[ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX + 1]; + +#define FEATURE_APF_OFFLOAD_VENDOR_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_apf_offload, \ + vendor_command_policy(wlan_hdd_apf_offload_policy, \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX) \ + }, + +/** + * wlan_hdd_cfg80211_apf_offload() - SSR Wrapper to APF Offload + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ + +int wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * hdd_apf_context_init - APF Context initialization operations + * @adapter: hdd adapter + * + * Return: None + */ +void hdd_apf_context_init(struct hdd_adapter *adapter); + +/** + * hdd_apf_context_destroy - APF Context de-init operations + * @adapter: hdd adapter + * + * Return: None + */ +void hdd_apf_context_destroy(struct hdd_adapter *adapter); + +/** + * hdd_get_apf_capabilities_cb() - Callback function to get APF capabilities + * @hdd_context: pointer to the hdd context + * @data: pointer to the data received + * + * This function receives the response/data from the lower layer and + * checks to see if the thread is still waiting then post the results to + * upper layer, if the request has timed out then ignore. + * + * Return: None + */ +void hdd_get_apf_capabilities_cb(void *hdd_context, + struct sir_apf_get_offload *data); +#else /* FEATURE_WLAN_APF */ + +#define FEATURE_APF_OFFLOAD_VENDOR_COMMANDS + +static inline void hdd_apf_context_init(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_apf_context_destroy(struct hdd_adapter *adapter) +{ +} + +#endif /* FEATURE_WLAN_APF */ + +#endif /* WLAN_HDD_APF_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h new file mode 100644 index 0000000000..dec04ffb0a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_assoc.h @@ -0,0 +1,651 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_ASSOC_H__) +#define WLAN_HDD_ASSOC_H__ + +/** + * DOC: wlan_hdd_assoc.h + * + */ + +/* Include files */ +#include +#include +#include "cdp_txrx_peer_ops.h" +#include +#include + +#define HDD_TIME_STRING_LEN 24 + +/* Timeout (in ms) for Link to Up before Registering Station */ +#define ASSOC_LINKUP_TIMEOUT 60 + +#define INVALID_PEER_IDX -1 + +/** + * enum eConnectionState - connection state values at HDD + * @eConnectionState_NotConnected: Not associated in Infra + * @eConnectionState_NdiDisconnected: NDI in disconnected state - no peers + * @eConnectionState_NdiConnected: NDI in connected state - at least one peer + */ +typedef enum { + eConnectionState_NotConnected, + eConnectionState_NdiDisconnected, + eConnectionState_NdiConnected, +} eConnectionState; + +/** + * enum peer_status - Peer status + * @ePeerConnected: peer connected + * @ePeerDisconnected: peer disconnected + */ +enum peer_status { + ePeerConnected = 1, + ePeerDisconnected +}; + +/** + * struct hdd_conn_flag - connection flags + * @ht_present: ht element present or not + * @vht_present: vht element present or not + * @eht_present: eht element present or not + * @hs20_present: hs20 element present or not + * @ht_op_present: ht operation present or not + * @vht_op_present: vht operation present or not + * @he_present: he operation present or not + * @eht_op_present: eht operation present or not + */ +struct hdd_conn_flag { + uint8_t ht_present:1; + uint8_t vht_present:1; + uint8_t eht_present:1; + uint8_t hs20_present:1; + uint8_t ht_op_present:1; + uint8_t vht_op_present:1; + uint8_t he_present:1; + uint8_t eht_op_present:1; +}; + +/*defines for tx_BF_cap_info */ +#define TX_BF_CAP_INFO_TX_BF 0x00000001 +#define TX_BF_CAP_INFO_RX_STAG_RED_SOUNDING 0x00000002 +#define TX_BF_CAP_INFO_TX_STAG_RED_SOUNDING 0x00000004 +#define TX_BF_CAP_INFO_RX_ZFL 0x00000008 +#define TX_BF_CAP_INFO_TX_ZFL 0x00000010 +#define TX_BF_CAP_INFO_IMP_TX_BF 0x00000020 +#define TX_BF_CAP_INFO_CALIBRATION 0x000000c0 +#define TX_BF_CAP_INFO_CALIBRATION_SHIFT 6 +#define TX_BF_CAP_INFO_EXP_CSIT_BF 0x00000100 +#define TX_BF_CAP_INFO_EXP_UNCOMP_STEER_MAT 0x00000200 +#define TX_BF_CAP_INFO_EXP_BF_CSI_FB 0x00001c00 +#define TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT 10 +#define TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT 0x0000e000 +#define TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT 13 +#define TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB 0x00070000 +#define TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT 16 +#define TX_BF_CAP_INFO_CSI_NUM_BF_ANT 0x00180000 +#define TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT 18 +#define TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT 0x00600000 +#define TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT 20 +#define TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT 0x01800000 +#define TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT 22 +#define TX_BF_CAP_INFO_RSVD 0xfe000000 + +/* defines for antenna selection info */ +#define ANTENNA_SEL_INFO 0x01 +#define ANTENNA_SEL_INFO_EXP_CSI_FB_TX 0x02 +#define ANTENNA_SEL_INFO_ANT_ID_FB_TX 0x04 +#define ANTENNA_SEL_INFO_EXP_CSI_FB 0x08 +#define ANTENNA_SEL_INFO_ANT_ID_FB 0x10 +#define ANTENNA_SEL_INFO_RX_AS 0x20 +#define ANTENNA_SEL_INFO_TX_SOUNDING_PPDU 0x40 +#define ANTENNA_SEL_INFO_RSVD 0x80 + +/** + * struct hdd_connection_info - structure to store connection information + * @conn_state: connection state of the NIC + * @bssid: BSSID + * @ssid: SSID Info + * @peer_macaddr:Peer Mac Address of the IBSS Stations + * @auth_type: Auth Type + * @uc_encrypt_type: Unicast Encryption Type + * @is_authenticated: Remembers authenticated state + * @dot11mode: dot11mode + * @proxy_arp_service: proxy arp service + * @ptk_installed: ptk installed state + * @gtk_installed: gtk installed state + * @nss: number of spatial streams negotiated + * @rate_flags: rate flags for current connection + * @chan_freq: channel frequency + * @txrate: txrate structure holds nss & datarate info + * @rxrate: rx rate info + * @noise: holds noise information + * @ht_caps: holds ht capabilities info + * @vht_caps: holds vht capabilities info + * @conn_flag: flag conn info params is present or not + * @hs20vendor_ie: holds passpoint/hs20 info + * @ht_operation: HT operation info + * @vht_operation: VHT operation info + * @he_operation: HE operation info + * @he_oper_len: length of @he_operation + * @roam_count: roaming counter + * @signal: holds rssi info + * @assoc_status_code: holds assoc fail reason + * @congestion: holds congestion percentage + * @last_ssid: holds last ssid + * @last_auth_type: holds last auth type + * @auth_time: last authentication established time + * @connect_time: last association established time + * @ch_width: channel width of operating channel + * @max_tx_bitrate: Max tx bitrate supported by the AP + * to which currently sta is connected. + * @prev_ap_bcn_ie: ap beacon IE information to which sta is currently connected + * @ieee_link_id: AP Link Id valid for MLO connection + * @eht_operation: EHT operation info + * @eht_oper_len: length of @eht_operation + */ +struct hdd_connection_info { + eConnectionState conn_state; + struct qdf_mac_addr bssid; + tCsrSSIDInfo ssid; + struct qdf_mac_addr peer_macaddr[MAX_PEERS]; + enum csr_akm_type auth_type; + eCsrEncryptionType uc_encrypt_type; + uint8_t is_authenticated; + uint32_t dot11mode; + uint8_t proxy_arp_service; + bool ptk_installed; + bool gtk_installed; + uint8_t nss; + uint32_t rate_flags; + uint32_t chan_freq; + struct rate_info txrate; + struct rate_info rxrate; + int8_t noise; + struct ieee80211_ht_cap ht_caps; + struct ieee80211_vht_cap vht_caps; + struct hdd_conn_flag conn_flag; + tDot11fIEhs20vendor_ie hs20vendor_ie; + struct ieee80211_ht_operation ht_operation; + struct ieee80211_vht_operation vht_operation; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) \ + && defined(WLAN_FEATURE_11AX) + struct ieee80211_he_operation *he_operation; + uint32_t he_oper_len; +#endif + uint32_t roam_count; + int8_t signal; + int32_t assoc_status_code; + tCsrSSIDInfo last_ssid; + enum csr_akm_type last_auth_type; + char auth_time[HDD_TIME_STRING_LEN]; + char connect_time[HDD_TIME_STRING_LEN]; + enum phy_ch_width ch_width; + struct rate_info max_tx_bitrate; + struct element_info prev_ap_bcn_ie; +#ifdef WLAN_FEATURE_11BE_MLO + int32_t ieee_link_id; +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) && \ + defined(WLAN_FEATURE_11BE) + struct ieee80211_eht_operation eht_operation; + uint32_t eht_oper_len; +#endif +}; + +/* Forward declarations */ +struct hdd_adapter; +struct hdd_station_ctx; +struct hdd_context; +struct wlan_hdd_link_info; + +/* + * hdd_is_fils_connection: API to determine if connection is FILS + * @hdd_ctx: hdd context + * @adapter: hdd adapter + * + * Return: true if fils connection else false + */ +bool hdd_is_fils_connection(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * hdd_conn_set_authenticated() - set authentication state + * @link_info: Link info pointer in HDD adapter + * @auth_state: authentication state + * + * This function updates the global HDD station context + * authentication state. And to start auto powersave timer + * if ptk installed case and open security case. + * + * Return: none + */ +void hdd_conn_set_authenticated(struct wlan_hdd_link_info *link_info, + uint8_t auth_state); + +/** + * hdd_conn_set_connection_state() - set connection state + * @adapter: pointer to the adapter + * @conn_state: connection state + * + * This function updates the global HDD station context connection state. + * + * Return: none + */ +void hdd_conn_set_connection_state(struct hdd_adapter *adapter, + eConnectionState conn_state); + +/** + * hdd_conn_get_connected_band() - get current connection radio band + * @link_info: pointer to the link_info structure + * + * Return: BAND_2G or BAND_5G based on current AP connection + * BAND_ALL if not connected + */ +enum band_info +hdd_conn_get_connected_band(struct wlan_hdd_link_info *link_info); + +/** + * hdd_get_sta_connection_in_progress() - get STA for which connection + * is in progress + * @hdd_ctx: hdd context + * + * Return: Link info pointer in adapter for which connection is in progress + */ +struct wlan_hdd_link_info * +hdd_get_sta_connection_in_progress(struct hdd_context *hdd_ctx); + +/** + * hdd_abort_ongoing_sta_connection() - Disconnect the sta for which the + * connection is in progress. + * + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx); + +/** + * hdd_abort_ongoing_sta_sae_connection() - Disconnect the sta for which the + * sae connection is in progress. + * + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_abort_ongoing_sta_sae_connection(struct hdd_context *hdd_ctx); + +/** + * hdd_is_any_sta_connected() - check if any sta in connected state + * @hdd_ctx: hdd context + * + * Return: true if any connected sta + */ +bool hdd_is_any_sta_connected(struct hdd_context *hdd_ctx); + +/** + * hdd_get_first_connected_sta_vdev_id() - check if any sta in connected state + * and exteact the vdev id of connected STA. + * @hdd_ctx: hdd context + * @vdev_id: pointer to vdev id + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_get_first_connected_sta_vdev_id(struct hdd_context *hdd_ctx, + uint32_t *vdev_id); + +/** + * hdd_sme_roam_callback() - hdd sme roam callback + * @context: pointer to link info context in HDD adapter + * @roam_info: pointer to roam info + * @roam_status: roam status + * @roam_result: roam result + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_sme_roam_callback(void *context, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); + +#ifdef FEATURE_WLAN_TDLS +/** + * hdd_roam_register_tdlssta() - register new TDLS station + * @adapter: pointer to adapter + * @peerMac: pointer to peer MAC address + * @qos: Quality of service + * + * Construct the txrx_desc and register the new STA with the Data Plane. + * This is called as part of ADD_STA in the TDLS setup. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_register_tdlssta(struct hdd_adapter *adapter, + const uint8_t *peerMac, uint8_t qos); +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results + * @adapter: pointer to adapter + * @measurementToken: measurement token + * @flag: flag + * @numBss: number of bss + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +void +hdd_indicate_ese_bcn_report_no_results(const struct hdd_adapter *adapter, + const uint16_t measurementToken, + const bool flag, + const uint8_t numBss); +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_change_peer_state() - change peer state + * @link_info: Link info pointer of VDEV in adapter + * @peer_mac_addr: Peer MAC address + * @sta_state: peer state + * + * Return: QDF status + */ +QDF_STATUS hdd_change_peer_state(struct wlan_hdd_link_info *link_info, + uint8_t *peer_mac_addr, + enum ol_txrx_peer_state sta_state); + +/** + * hdd_update_dp_vdev_flags() - update datapath vdev flags + * @cbk_data: callback data + * @vdev_id: virtual interface id + * @vdev_param: vdev parameter + * @is_link_up: link state up or down + * + * Return: QDF status + */ +QDF_STATUS hdd_update_dp_vdev_flags(void *cbk_data, + uint8_t vdev_id, + uint32_t vdev_param, + bool is_link_up); + +/** + * hdd_roam_register_sta() - register station + * @link_info: Link info pointer in HDD adapter + * @bssid: bssid of the connection + * @is_auth_required: is upper layer authenticatoin required + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_roam_register_sta(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *bssid, + bool is_auth_required); + +/** + * hdd_save_peer() - Save peer MAC address in adapter peer table. + * @sta_ctx: pointer to hdd station context + * @peer_mac_addr: mac address of new peer + * + * This information is passed to iwconfig later. The peer that joined + * last is passed as information to iwconfig. + * + * Return: true if success, false otherwise + */ +bool hdd_save_peer(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *peer_mac_addr); + +/** + * hdd_delete_peer() - removes peer from hdd station context peer table + * @sta_ctx: pointer to hdd station context + * @peer_mac_addr: mac address of peer to be deleted + * + * Return: None + */ +void hdd_delete_peer(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *peer_mac_addr); + +/** + * hdd_copy_ht_caps()- copy ht caps info from roam ht caps + * info to source ht_cap info of type ieee80211_ht_cap. + * @hdd_ht_cap: pointer to Source ht_cap info of type ieee80211_ht_cap + * @roam_ht_cap: pointer to roam ht_caps info + * + * Return: None + */ + +void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, + tDot11fIEHTCaps *roam_ht_cap); + +/** + * hdd_add_beacon_filter() - add beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +int hdd_add_beacon_filter(struct hdd_adapter *adapter); + +/** + * hdd_copy_vht_caps()- copy vht caps info from roam vht caps + * info to source vht_cap info of type ieee80211_vht_cap. + * @hdd_vht_cap: pointer to Source vht_cap info of type ieee80211_vht_cap + * @roam_vht_cap: pointer to roam vht_caps info + * + * Return: None + */ +void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap, + tDot11fIEVHTCaps *roam_vht_cap); + +/** + * hdd_roam_profile_init() - initialize adapter roam profile + * @link_info: Link info pointer in HDD adapter + * + * This function initializes the roam profile that is embedded within + * the adapter. + * + * Return: void + */ +void hdd_roam_profile_init(struct wlan_hdd_link_info *link_info); + +/** + * hdd_any_valid_peer_present() - Check if any valid peer is present + * @link_info: Pointer of link_info in adapter struct + * + * Check if there is any peer present with non-zero mac address other than + * broadcast address. + * + * Return: True if there is any valid peer present + */ +bool hdd_any_valid_peer_present(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_register_cb() - Sets legacy callbacks to osif + * + * API to set legacy callbacks to osif + * Context: Any context. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_register_cb(void); + +/** + * hdd_cm_unregister_cb - Resets legacy callbacks to osif + * + * API to reset legacy callbacks to osif + * Context: Any context. + * + * Return: QDF_STATUS + */ +void hdd_cm_unregister_cb(void); + +/** + * hdd_conn_remove_connect_info() - remove connection info + * @sta_ctx: pointer to global HDD station context + * + * Return: none + */ +void hdd_conn_remove_connect_info(struct hdd_station_ctx *sta_ctx); + +/** + * hdd_clear_roam_profile_ie() - Clear Roam Profile IEs + * @adapter: adapter who's IEs are to be cleared + * + * Return: None + */ +void hdd_clear_roam_profile_ie(struct hdd_adapter *adapter); + +/** + * hdd_remove_beacon_filter() - remove beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +int hdd_remove_beacon_filter(struct hdd_adapter *adapter); + +/** + * hdd_copy_ht_operation()- copy HT operation element to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @ht_ops: pointer to ht operation + * + * Return: None + */ +void hdd_copy_ht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEHTInfo *ht_ops); + +/** + * hdd_copy_vht_operation()- copy VHT operations element to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @vht_ops: pointer to vht operation + * + * Return: None + */ +void hdd_copy_vht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEVHTOperation *vht_ops); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) && \ + defined(WLAN_FEATURE_11BE) +/** + * hdd_copy_eht_operation()- copy EHT operations element to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @eht_ops: pointer to eht operation + * + * Return: None + */ +void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEeht_op *eht_ops); + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) && \ + defined(WLAN_FEATURE_11BE) +void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEeht_op *eht_ops); +#else +static inline void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEeht_op *eht_ops) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ + defined(WLAN_FEATURE_11AX) +/** + * hdd_copy_he_operation()- copy HE operations element to + * hdd station context. + * @hdd_sta_ctx: pointer to hdd station context + * @he_operation: pointer to he operation + * + * Return: None + */ +void hdd_copy_he_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEhe_op *he_operation); +#else +static inline void hdd_copy_he_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEhe_op *he_operation) +{ +} +#endif + +/** + * hdd_is_roam_sync_in_progress()- Check if roam offloaded + * @hdd_ctx: Pointer to hdd context + * @vdev_id: Vdev id + * + * Return: roam sync status if roaming offloaded else false + */ +bool hdd_is_roam_sync_in_progress(struct hdd_context *hdd_ctx, uint8_t vdev_id); + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * wlan_hdd_ft_set_key_delay() - hdd set key delayed for FT mode + * @vdev: vdev + * + * Return: void + */ +void wlan_hdd_ft_set_key_delay(struct wlan_objmgr_vdev *vdev); +#else +static inline void +wlan_hdd_ft_set_key_delay(struct wlan_objmgr_vdev *vdev) +{ +} +#endif + +#ifdef FEATURE_WLAN_WAPI +/** + * hdd_translate_wapi_to_csr_auth_type() - Translate WAPI to CSR auth type + * @auth_suite: auth suite + * + * Return: enum csr_akm_type enumeration + */ +enum csr_akm_type hdd_translate_wapi_to_csr_auth_type(uint8_t auth_suite[4]); + +/** + * hdd_translate_wapi_to_csr_encryption_type() - + * Translate WAPI to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_wapi_to_csr_encryption_type(uint8_t cipher_suite[4]); +#else +enum csr_akm_type hdd_translate_wapi_to_csr_auth_type(uint8_t auth_suite[4]) +{ + return eCSR_AUTH_TYPE_UNKNOWN; +} + +eCsrEncryptionType +hdd_translate_wapi_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + return eCSR_AUTH_TYPE_UNKNOWN; +} +#endif + +/** + * hdd_convert_ch_width_to_cdp_peer_bw() - Convert ch_width to DP format + * @ch_width: ch_width + * + * Return: cdp_peer_bw enumeration + */ +enum cdp_peer_bw +hdd_convert_ch_width_to_cdp_peer_bw(enum phy_ch_width ch_width); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_avoid_freq_ext.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_avoid_freq_ext.h new file mode 100644 index 0000000000..f4d6446ecd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_avoid_freq_ext.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_avoid_freq_ext.h + * + * WLAN Host Device Driver extended avoid frequency interface implementation. + */ + +#if !defined(__WLAN_HDD_AVOID_FREQ_EXT_H) +#define __WLAN_HDD_AVOID_FREQ_EXT_H + +#include +#include +#include +#include +#include "wlan_hdd_main.h" + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +extern const struct nla_policy +avoid_freq_ext_policy[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1]; + +#define FEATURE_AVOID_FREQ_EXT_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_avoid_freq_ext, \ + vendor_command_policy(avoid_freq_ext_policy, \ + QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX) \ +}, + +int wlan_hdd_cfg80211_avoid_freq_ext(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +#else +#define FEATURE_AVOID_FREQ_EXT_VENDOR_COMMANDS +static inline void wlan_hdd_cfg80211_avoid_freq_ext(void) {} +#endif +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_bcn_recv.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_bcn_recv.h new file mode 100644 index 0000000000..77aef061c5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_bcn_recv.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: feature_bcn_recv + * Feature for receiving beacons of connected AP and sending select + * params to upper layer via vendor event + */ + +#ifdef WLAN_BCN_RECV_FEATURE + +struct wireless_dev; +struct wiphy; + +/** + * wlan_hdd_cfg80211_bcn_rcv_op() - Process beacon report operations + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_bcn_rcv_op() + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * hdd_beacon_recv_pause_indication()- Send vendor event to user space + * to inform SCAN started indication + * @hdd_handle: hdd handler + * @vdev_id: vdev id + * @type: scan event type + * @is_disconnected: Connection state of driver + * + * Return: None + */ +void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, + uint8_t vdev_id, + enum scan_event_type type, + bool is_disconnected); + +extern const struct nla_policy + beacon_reporting_params_policy + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1]; + +#define BCN_RECV_FEATURE_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_bcn_rcv_op, \ + vendor_command_policy(beacon_reporting_params_policy, \ + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX)\ +}, + +#define BCN_RECV_FEATURE_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING \ +}, +#else +#define BCN_RECV_FEATURE_VENDOR_COMMANDS +#define BCN_RECV_FEATURE_VENDOR_EVENTS + +static inline +void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, + uint8_t vdev_id, + enum scan_event_type type, + bool is_disconnected) +{ +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_bootup_marker.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_bootup_marker.h new file mode 100644 index 0000000000..f3c00e304c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_bootup_marker.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_HDD_BOOTUP_MARKER_H +#define WLAN_HDD_BOOTUP_MARKER_H + +/** + * DOC: wlan_hdd_bootup_marker.h + * + * WLAN Host Device Driver Bootup Marker header file + */ + +#include "wlan_hdd_main.h" + +#ifdef WLAN_BOOTUP_MARKER +/** + * hdd_place_marker() - record bootup marker for some events + * @adapter: hdd adapter pointer + * @format: The strings of the events + * @mac: mac address of peer device + * + * Return: None + */ +void hdd_place_marker(struct hdd_adapter *adapter, + const char *format, + uint8_t *mac); +#else +static inline +void hdd_place_marker(struct hdd_adapter *adapter, + const char *format, + uint8_t *mac) +{ +} +#endif +#endif /* WLAN_HDD_BOOTUP_MARKER_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h new file mode 100644 index 0000000000..2a0e341529 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h @@ -0,0 +1,519 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(HDD_CONFIG_H__) +#define HDD_CONFIG_H__ + +/** + * DOC: wlan_hdd_config.h + * + * WLAN Adapter Configuration functions + */ + +/* $HEADER$ */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include "osapi_linux.h" +#include +#include "wlan_pmo_hw_filter_public_struct.h" +#include "wlan_action_oui_public_struct.h" +#include "hdd_config.h" + +struct hdd_context; + +#define CFG_DP_RPS_RX_QUEUE_CPU_MAP_LIST_LEN 30 + +#define FW_MODULE_LOG_LEVEL_STRING_LENGTH (512) +#define TX_SCHED_WRR_PARAMS_NUM (5) + +/* Defines for all of the things we read from the configuration (registry). */ + +#ifdef CONFIG_DP_TRACE +/* Max length of gDptraceConfig string. e.g.- "1, 6, 1, 62" */ +#define DP_TRACE_CONFIG_STRING_LENGTH (20) + +/* At max 4 DP Trace config parameters are allowed. Refer - gDptraceConfig */ +#define DP_TRACE_CONFIG_NUM_PARAMS (4) + +/* + * Default value of live mode in case it cannot be determined from cfg string + * gDptraceConfig + */ +#define DP_TRACE_CONFIG_DEFAULT_LIVE_MODE (1) + +/* + * Default value of thresh (packets/second) beyond which DP Trace is disabled. + * Use this default in case the value cannot be determined from cfg string + * gDptraceConfig + */ +#define DP_TRACE_CONFIG_DEFAULT_THRESH (6) + +/* + * Number of intervals of BW timer to wait before enabling/disabling DP Trace. + * Since throughput threshold to disable live logging for DP Trace is very low, + * we calculate throughput based on # packets received in a second. + * For example assuming bandwidth timer interval is 100ms, and if more than 6 + * prints are received in 10 * 100 ms interval, we want to disable DP Trace + * live logging. DP_TRACE_CONFIG_DEFAULT_THRESH_TIME_LIMIT is the default + * value, to be used in case the real value cannot be derived from + * bw timer interval + */ +#define DP_TRACE_CONFIG_DEFAULT_THRESH_TIME_LIMIT (10) + +/* Default proto bitmap in case its missing in gDptraceConfig string */ +#define DP_TRACE_CONFIG_DEFAULT_BITMAP \ + (QDF_NBUF_PKT_TRAC_TYPE_EAPOL |\ + QDF_NBUF_PKT_TRAC_TYPE_DHCP |\ + QDF_NBUF_PKT_TRAC_TYPE_MGMT_ACTION |\ + QDF_NBUF_PKT_TRAC_TYPE_ARP |\ + QDF_NBUF_PKT_TRAC_TYPE_ICMP |\ + QDF_NBUF_PKT_TRAC_TYPE_ICMPv6)\ + +/* Default verbosity, in case its missing in gDptraceConfig string*/ +#define DP_TRACE_CONFIG_DEFAULT_VERBOSTY QDF_DP_TRACE_VERBOSITY_LOW + +#endif + +/* + * Type declarations + */ + +struct hdd_config { + /* Config parameters */ + enum hdd_dot11_mode dot11Mode; + +#ifdef FEATURE_WLAN_DYNAMIC_CVM + /* Bitmap for operating voltage corner mode */ + uint32_t vc_mode_cfg_bitmap; +#endif +#ifdef ENABLE_MTRACE_LOG + bool enable_mtrace; +#endif + bool advertise_concurrent_operation; +#ifdef DHCP_SERVER_OFFLOAD + struct dhcp_server dhcp_server_ip; +#endif /* DHCP_SERVER_OFFLOAD */ + bool apf_enabled; + uint16_t sap_tx_leakage_threshold; + bool sap_internal_restart; + bool is_11k_offload_supported; + bool is_unit_test_framework_enabled; + bool disable_channel; + + /* HDD converged ini items are listed below this*/ + bool bug_on_reinit_failure; + bool is_ramdump_enabled; + uint32_t iface_change_wait_time; + uint8_t multicast_host_fw_msgs; + enum hdd_wext_control private_wext_control; + bool enablefwprint; + uint8_t enable_fw_log; + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + /* WLAN Logging */ + bool wlan_logging_enable; + uint32_t wlan_console_log_levels; + uint8_t host_log_custom_nl_proto; +#endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + uint32_t wlan_auto_shutdown; +#endif + +#ifndef REMOVE_PKT_LOG + bool enable_packet_log; +#endif + +#ifdef WLAN_FEATURE_MSCS + uint32_t mscs_pkt_threshold; + uint32_t mscs_voice_interval; +#endif /* WLAN_FEATURE_MSCS */ + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + uint32_t tx_flow_low_watermark; + uint32_t tx_flow_hi_watermark_offset; + uint32_t tx_flow_max_queue_depth; + uint32_t tx_lbw_flow_low_watermark; + uint32_t tx_lbw_flow_hi_watermark_offset; + uint32_t tx_lbw_flow_max_queue_depth; + uint32_t tx_hbw_flow_low_watermark; + uint32_t tx_hbw_flow_hi_watermark_offset; + uint32_t tx_hbw_flow_max_queue_depth; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + uint32_t napi_cpu_affinity_mask; + uint32_t operating_chan_freq; + uint8_t num_vdevs; + uint8_t enable_concurrent_sta[CFG_CONCURRENT_IFACE_MAX_LEN]; + uint8_t dbs_scan_selection[CFG_DBS_SCAN_PARAM_LENGTH]; +#ifdef FEATURE_RUNTIME_PM + uint8_t runtime_pm; +#endif +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI + bool is_qmi_stats_enabled; +#endif + uint8_t inform_bss_rssi_raw; + + bool mac_provision; + uint32_t provisioned_intf_pool; + uint32_t derived_intf_pool; + uint32_t cfg_wmi_credit_cnt; + uint32_t enable_sar_conversion; +#ifdef WLAN_FEATURE_TSF_PLUS + uint8_t tsf_ptp_options; +#endif /* WLAN_FEATURE_TSF_PLUS */ + +#ifdef SAR_SAFETY_FEATURE + uint32_t sar_safety_timeout; + uint32_t sar_safety_unsolicited_timeout; + uint32_t sar_safety_req_resp_timeout; + uint32_t sar_safety_req_resp_retry; + uint32_t sar_safety_index; + uint32_t sar_safety_sleep_index; + uint8_t enable_sar_safety; + bool config_sar_safety_sleep_index; +#endif + uint8_t nb_commands_interval; + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION + uint32_t sta_stats_cache_expiry_time; +#endif + bool read_mac_addr_from_mac_file; +#ifdef FEATURE_SET + bool get_wifi_features; +#endif +#ifdef FEATURE_RUNTIME_PM + uint16_t cpu_cxpc_threshold; +#endif + bool exclude_selftx_from_cca_busy; +#ifdef WLAN_FEATURE_11BE_MLO + /* ml link state cache expiry time*/ + qdf_time_t link_state_cache_expiry_time; +#endif +}; + +/** + * hdd_to_csr_wmm_mode() - Utility function to convert HDD to CSR WMM mode + * + * @mode: hdd WMM user mode + * + * Return: CSR WMM mode + */ +enum wmm_user_mode hdd_to_csr_wmm_mode(uint8_t mode); + +QDF_STATUS hdd_update_mac_config(struct hdd_context *hdd_ctx); +QDF_STATUS hdd_set_sme_config(struct hdd_context *hdd_ctx); +QDF_STATUS hdd_set_policy_mgr_user_cfg(struct hdd_context *hdd_ctx); +QDF_STATUS hdd_set_sme_chan_list(struct hdd_context *hdd_ctx); +bool hdd_update_config_cfg(struct hdd_context *hdd_ctx); +void hdd_cfg_get_global_config(struct hdd_context *hdd_ctx, char *buf, + int buflen); + +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(enum hdd_dot11_mode dot11Mode); + +QDF_STATUS hdd_set_idle_ps_config(struct hdd_context *hdd_ctx, bool val); +void hdd_get_pmkid_modes(struct hdd_context *hdd_ctx, + struct pmkid_mode_bits *pmkid_modes); + +int hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg); + +/** + * hdd_string_to_u8_array() - used to convert decimal string into u8 array + * @str: Decimal string + * @array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * + * This API is called to convert decimal string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *array, + uint8_t *len, uint16_t array_max_len); + +QDF_STATUS hdd_hex_string_to_u16_array(char *str, uint16_t *int_array, + uint8_t *len, uint8_t int_array_max_len); + +void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx); + +/** + * hdd_update_nss() - Update the number of spatial streams supported. + * @link_info: Link info pointer in HDD adapter + * @tx_nss: the number of Tx spatial streams to be updated + * @rx_nss: the number of Rx spatial streams to be updated + * + * This function is used to modify the number of spatial streams + * supported when not in connected state. + * + * Return: QDF_STATUS_SUCCESS if nss is correctly updated, + * otherwise QDF_STATUS_E_FAILURE would be returned + */ +QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info, + uint8_t tx_nss, uint8_t rx_nss); + +/** + * hdd_get_nss() - Get the number of spatial streams supported by the adapter + * + * @adapter: the pointer to adapter + * @nss: the number of spatial streams supported by the adapter + * + * This function is used to get the number of spatial streams supported by + * the adapter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss); + +/** + * hdd_get_num_tx_chains() - Get the number of tx chains supported by the + * adapter + * @link_info: Link info pointer in HDD adapter + * @tx_chains: the number of Tx chains supported by the adapter + * + * This function is used to get the number of Tx chains supported by + * the adapter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *tx_chains); + +/** + * hdd_get_tx_nss() - Get the number of spatial streams supported by the adapter + * @link_info: Link info pointer in HDD adapter + * @tx_nss: the number Tx of spatial streams supported by the adapter + * + * This function is used to get the number of Tx spatial streams supported by + * the adapter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, + uint8_t *tx_nss); + +/** + * hdd_get_num_rx_chains() - Get the number of chains supported by the adapter + * @link_info: Link info pointer in HDD adapter + * @rx_chains: the number of Rx chains supported by the adapter + * + * This function is used to get the number of Rx chains supported by + * the adapter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *rx_chains); + +/** + * hdd_get_rx_nss() - Get the number of spatial streams supported by the adapter + * @link_info: Link info pointer in HDD adapter + * @rx_nss: the number Rx of spatial streams supported by the adapter + * + * This function is used to get the number of Rx spatial streams supported by + * the adapter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_rx_nss(struct wlan_hdd_link_info *link_info, + uint8_t *rx_nss); + + +/** + * hdd_dfs_indicate_radar() - Block tx as radar found on the channel + * @hdd_ctx: HDD context pointer + * + * This function is invoked in atomic context when a radar + * is found on the SAP current operating channel and Data Tx + * from netif has to be stopped to honor the DFS regulations. + * Actions: Stop the netif Tx queues,Indicate Radar present + * in HDD context for future usage. + * + * Return: true on success, else false + */ +bool hdd_dfs_indicate_radar(struct hdd_context *hdd_ctx); + +/** + * hdd_restore_all_ps() - Restore all the powersave configuration overwritten + * by hdd_override_all_ps. + * @hdd_ctx: Pointer to HDD context. + * + * Return: None + */ +void hdd_restore_all_ps(struct hdd_context *hdd_ctx); + +/** + * hdd_override_all_ps() - overrides to disables all the powersave features. + * @hdd_ctx: Pointer to HDD context. + * Overrides below powersave ini configurations. + * gEnableImps=0 + * gEnableBmps=0 + * gRuntimePM=0 + * gWlanAutoShutdown = 0 + * gEnableWoW=0 + * + * Return: None + */ +void hdd_override_all_ps(struct hdd_context *hdd_ctx); + +/** + * hdd_vendor_mode_to_phymode() - Get eCsrPhyMode according to vendor phy mode + * @vendor_phy_mode: vendor phy mode + * @csr_phy_mode: phy mode of eCsrPhyMode + * + * Return: 0 on success, negative errno value on error + */ +int hdd_vendor_mode_to_phymode(enum qca_wlan_vendor_phy_mode vendor_phy_mode, + eCsrPhyMode *csr_phy_mode); + +/** + * hdd_phymode_to_vendor_mode() - Get vendor phy mode according to CSR phy mode. + * @csr_phy_mode: phy mode of eCsrPhyMode + * @vendor_phy_mode: vendor phy mode + * + * Return: 0 on success, negative error value on failure + */ +int hdd_phymode_to_vendor_mode(eCsrPhyMode csr_phy_mode, + enum qca_wlan_vendor_phy_mode *vendor_phy_mode); + +/** + * hdd_vendor_mode_to_band() - Get band_info according to vendor phy mode + * @vendor_phy_mode: vendor phy mode + * @supported_band: supported band bitmap + * @is_6ghz_supported: whether 6ghz is supported + * + * Return: 0 on success, negative errno value on error + */ +int hdd_vendor_mode_to_band(enum qca_wlan_vendor_phy_mode vendor_phy_mode, + uint8_t *supported_band, bool is_6ghz_supported); + +/** + * hdd_vendor_mode_to_bonding_mode() - Get channel bonding mode according to + * vendor phy mode + * @vendor_phy_mode: vendor phy mode + * @bonding_mode: channel bonding mode + * + * Return: 0 on success, negative errno value on error + */ +int +hdd_vendor_mode_to_bonding_mode(enum qca_wlan_vendor_phy_mode vendor_phy_mode, + uint32_t *bonding_mode); + +/** + * hdd_phymode_to_dot11_mode() - Mapping phymode to dot11mode + * @phymode: phy mode + * @dot11_mode: dot11 mode + * + * Return: 0 on success, negative errno value on error + */ +int hdd_phymode_to_dot11_mode(eCsrPhyMode phymode, + enum hdd_dot11_mode *dot11_mode); + +/** + * hdd_update_phymode() - update the PHY mode of the adapter + * @adapter: adapter being modified + * @phymode: new PHY mode for the adapter + * @supported_band: supported band bitmap for the adapter + * @bonding_mode: new channel bonding mode for the adapter + * + * This function is called when the adapter is set to a new PHY mode. + * It takes a holistic look at the desired PHY mode along with the + * configured capabilities of the driver and the reported capabilities + * of the hardware in order to correctly configure all PHY-related + * parameters. + * + * Return: 0 on success, negative errno value on error + */ +int hdd_update_phymode(struct hdd_adapter *adapter, eCsrPhyMode phymode, + uint8_t supported_band, uint32_t bonding_mode); + +/** + * hdd_get_ldpc() - Get adapter LDPC + * @adapter: adapter being queried + * @value: where to store the value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_get_ldpc(struct hdd_adapter *adapter, int *value); + +/** + * hdd_set_ldpc() - Set adapter LDPC + * @link_info: Link info pointer in adapter + * @value: new LDPC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_ldpc(struct wlan_hdd_link_info *link_info, int value); + +/** + * hdd_get_tx_stbc() - Get adapter TX STBC + * @adapter: adapter being queried + * @value: where to store the value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_get_tx_stbc(struct hdd_adapter *adapter, int *value); + +/** + * hdd_set_tx_stbc() - Set adapter TX STBC + * @link_info: Link info pointer in HDD adapter + * @value: new TX STBC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_tx_stbc(struct wlan_hdd_link_info *link_info, int value); + +/** + * hdd_get_rx_stbc() - Get adapter RX STBC + * @adapter: adapter being queried + * @value: where to store the value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_get_rx_stbc(struct hdd_adapter *adapter, int *value); + +/** + * hdd_set_rx_stbc() - Set adapter RX STBC + * @link_info: Link info pointer in HDD adapter + * @value: new RX STBC value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_rx_stbc(struct wlan_hdd_link_info *link_info, int value); + +/** + * hdd_update_channel_width() - Update adapter channel width settings + * @link_info: Link info in HDD adapter + * @chwidth: new channel width of enum eSirMacHTChannelWidth + * @bonding_mode: channel bonding mode of the new channel width + * @link_id: mlo link id + * @is_restore: is restore + * + * Return: 0 on success, negative errno on failure + */ +int hdd_update_channel_width(struct wlan_hdd_link_info *link_info, + enum eSirMacHTChannelWidth chwidth, + uint32_t bonding_mode, uint8_t link_id, + bool is_restore); +#endif /* end #if !defined(HDD_CONFIG_H__) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_cfr.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_cfr.h new file mode 100644 index 0000000000..a855d90dd4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_cfr.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_cfr.h + * + * WLAN Host Device Driver cfr capture implementation + * + */ + +#if !defined(_WLAN_HDD_CFR_H) +#define _WLAN_HDD_CFR_H + +#ifdef WLAN_CFR_ENABLE + +#include "wlan_cfr_utils_api.h" + +#define HDD_INVALID_GROUP_ID MAX_TA_RA_ENTRIES +#define LEGACY_CFR_VERSION 1 +#define ENHANCED_CFR_VERSION 2 + +/** + * wlan_hdd_cfg80211_peer_cfr_capture_cfg() - configure peer cfr capture + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function starts CFR capture + * + * Return: 0 on success and errno on failure + */ +int +wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#ifdef WLAN_ENH_CFR_ENABLE +/** + * hdd_cfr_disconnect() - Handle disconnection event in CFR + * @vdev: Pointer to vdev object + * + * Handle disconnection event in CFR. Stop CFR if it started and get + * disconnection event. + * + * Return: QDF status + */ +QDF_STATUS hdd_cfr_disconnect(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +hdd_cfr_disconnect(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +extern const struct nla_policy cfr_config_policy[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1]; + +#define FEATURE_CFR_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_peer_cfr_capture_cfg, \ + vendor_command_policy(cfr_config_policy, \ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX) \ +}, +#else +#define FEATURE_CFR_VENDOR_COMMANDS +static inline QDF_STATUS +hdd_cfr_disconnect(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_CFR_ENABLE */ +#endif /* _WLAN_HDD_CFR_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_connectivity_logging.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_connectivity_logging.h new file mode 100644 index 0000000000..869abe891a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_connectivity_logging.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_hdd_connectivity_logging.h + * + * Implementation for the Common connectivity logging api. + */ + +#ifndef __WLAN_HDD_CONNECTIVITY_LOGGING_H__ +#define __WLAN_HDD_CONNECTIVITY_LOGGING_H__ + +#include +#include +#include +#include "wlan_hdd_main.h" + +#if defined(WLAN_FEATURE_CONNECTIVITY_LOGGING) + +#define FEATURE_CONNECTIVITY_LOGGING_EVENT \ +[QCA_NL80211_VENDOR_SUBCMD_DIAG_EVENT_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DIAG_DATA, \ +}, + +/** + * wlan_hdd_start_connectivity_logging() - Initialize logging callbacks + * and allocate global buffers + * @hdd_ctx: Pointer to hdd context + * + * Return: None + */ +void wlan_hdd_start_connectivity_logging(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_connectivity_event_connecting() - Queue the connecting event to + * the logging queue + * @hdd_ctx: HDD context + * @req: Request + * @vdev_id: Vdev id + */ +void wlan_hdd_connectivity_event_connecting(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req, + uint8_t vdev_id); + +/** + * wlan_hdd_connectivity_fail_event()- Connectivity queue logging event + * @vdev: VDEV object + * @rsp: Connection manager connect response + * + * Return: None + */ +void wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); +#elif defined(CONNECTIVITY_DIAG_EVENT) +/** + * wlan_hdd_connectivity_event_connecting() - Queue the connecting event to + * the logging queue + * @hdd_ctx: HDD context + * @req: Request + * @vdev_id: Vdev id + */ +void wlan_hdd_connectivity_event_connecting(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req, + uint8_t vdev_id); + +/** + * wlan_hdd_connectivity_fail_event()- Connectivity queue logging event + * @vdev: VDEV object + * @rsp: Connection manager connect response + * + * Return: None + */ +void wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); + +static inline +void wlan_hdd_start_connectivity_logging(struct hdd_context *hdd_ctx) +{} + +#else +static inline +void wlan_hdd_start_connectivity_logging(struct hdd_context *hdd_ctx) +{} + +static inline +void wlan_hdd_connectivity_event_connecting(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req, + uint8_t vdev_id) +{} + +static inline +void wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{} +#endif +#endif /* __WLAN_HDD_CONNECTIVITY_LOGGING_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_data_stall_detection.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_data_stall_detection.h new file mode 100644 index 0000000000..4104ba58cc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_data_stall_detection.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_DATA_STALL_DETECTION_H +#define __WLAN_HDD_DATA_STALL_DETECTION_H + +/** + * DOC: wlan_hdd_data_stall_detection.h + * + * WLAN Host Device Driver data stall detection API specification + */ + +/** + * hdd_register_data_stall_detect_cb() - register data stall callback + * + * Return: 0 for success or Error code for failure + */ +int hdd_register_data_stall_detect_cb(void); + +/** + * hdd_deregister_data_stall_detect_cb() - de-register data stall callback + * + * Return: 0 for success or Error code for failure + */ +int hdd_deregister_data_stall_detect_cb(void); +#endif /* __WLAN_HDD_DATA_STALL_DETECTION_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h new file mode 100644 index 0000000000..bb0e7654e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs.h @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2013-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_DEBUGFS_H +#define _WLAN_HDD_DEBUGFS_H + +#ifdef WLAN_DEBUGFS + +#define HDD_DEBUGFS_FILE_NAME_MAX 24 + +/** + * enum hdd_debugfs_file_id - Debugfs file Identifier + * @HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO: roam_scan_stats file id + * @HDD_DEBUFS_FILE_ID_OFFLOAD_INFO: offload_info file id + * @HDD_DEBUGFS_FILE_ID_MAX: maximum id of csr debugfs file + */ +enum hdd_debugfs_file_id { + HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO = 0, + HDD_DEBUFS_FILE_ID_OFFLOAD_INFO = 1, + + HDD_DEBUGFS_FILE_ID_MAX, +}; + +/** + * struct hdd_debugfs_file_info - Debugfs file info + * @name: name of debugfs file + * @id: id from enum hdd_debugfs_file_id used to identify file + * @buf_max_size: max size of buffer from which debugfs file is updated + * @entry: dentry pointer to debugfs file + */ +struct hdd_debugfs_file_info { + uint8_t name[HDD_DEBUGFS_FILE_NAME_MAX]; + enum hdd_debugfs_file_id id; + ssize_t buf_max_size; + struct dentry *entry; +}; + +QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter); +void hdd_debugfs_exit(struct hdd_adapter *adapter); + +/** + * hdd_wait_for_debugfs_threads_completion() - Wait for debugfs threads + * completion before proceeding further to stop modules + * + * Return: true if there is no debugfs open + * false if there is at least one debugfs open + */ +bool hdd_wait_for_debugfs_threads_completion(void); + +/** + * hdd_return_debugfs_threads_count() - Return active debugfs threads + * + * Return: total number of active debugfs threads in driver + */ +int hdd_return_debugfs_threads_count(void); + +/** + * hdd_debugfs_thread_increment() - Increment debugfs thread count + * + * This function is used to increment and keep track of debugfs thread count. + * This is invoked for every file open operation. + * + * Return: None + */ +void hdd_debugfs_thread_increment(void); + +/** + * hdd_debugfs_thread_decrement() - Decrement debugfs thread count + * + * This function is used to decrement and keep track of debugfs thread count. + * This is invoked for every file release operation. + * + * Return: None + */ +void hdd_debugfs_thread_decrement(void); + +#else +static inline QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_debugfs_exit(struct hdd_adapter *adapter) +{ +} + +/** + * hdd_wait_for_debugfs_threads_completion() - Wait for debugfs threads + * completion before proceeding further to stop modules + * + * Return: true if there is no debugfs open + * false if there is at least one debugfs open + */ +static inline +bool hdd_wait_for_debugfs_threads_completion(void) +{ + return true; +} + +/** + * hdd_return_debugfs_threads_count() - Return active debugfs threads + * + * Return: total number of active debugfs threads in driver + */ +static inline +int hdd_return_debugfs_threads_count(void) +{ + return 0; +} + +/** + * hdd_debugfs_thread_increment() - Increment debugfs thread count + * + * This function is used to increment and keep track of debugfs thread count. + * This is invoked for every file open operation. + * + * Return: None + */ +static inline +void hdd_debugfs_thread_increment(void) +{ +} + +/** + * hdd_debugfs_thread_decrement() - Decrement debugfs thread count + * + * This function is used to decrement and keep track of debugfs thread count. + * This is invoked for every file release operation. + * + * Return: None + */ +static inline +void hdd_debugfs_thread_decrement(void) +{ +} + +#endif /* #ifdef WLAN_DEBUGFS */ +#endif /* #ifndef _WLAN_HDD_DEBUGFS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_coex.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_coex.h new file mode 100644 index 0000000000..5a6bfed882 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_coex.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_DEBUGFS_COEX_H +#define _WLAN_HDD_DEBUGFS_COEX_H + +#ifdef WLAN_MWS_INFO_DEBUGFS +/** + * hdd_debugfs_mws_coex_info_init() - MWS coex initialization + * @hdd_ctx: Pointer to the hdd_ctx + * + * This function is called to initialize the coex debugfs. + * Return: None + */ +void hdd_debugfs_mws_coex_info_init(struct hdd_context *hdd_ctx); + +/** + * hdd_debugfs_mws_coex_info_deinit() - MWS coex deintialization + * @hdd_ctx: Pointer to the hdd_ctx + * + * This function is called to deinitialize the coex debugfs. + * Return: None + */ +void hdd_debugfs_mws_coex_info_deinit(struct hdd_context *hdd_ctx); +#else +static inline void hdd_debugfs_mws_coex_info_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_debugfs_mws_coex_info_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_config.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_config.h new file mode 100644 index 0000000000..d0fa1ab4d1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_config.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_config.h + * + * WLAN Host Device Driver implementation to update + * debugfs with ini configs + */ + +#ifndef _WLAN_HDD_DEBUGFS_CONFIG_H +#define _WLAN_HDD_DEBUGFS_CONFIG_H + +#ifdef WLAN_DEBUGFS +/** + * hdd_debugfs_ini_config_init() - API to initialize ini config file + * @hdd_ctx: hdd context + * + * Return: 0 on success and errno on failure + */ +int hdd_debugfs_ini_config_init(struct hdd_context *hdd_ctx); + +/** + * hdd_debugfs_ini_config_deinit() - API to deinit ini config file + * @hdd_ctx: hdd context + * + * Return: None + */ +void hdd_debugfs_ini_config_deinit(struct hdd_context *hdd_ctx); +#else +static inline int hdd_debugfs_ini_config_init(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline void hdd_debugfs_ini_config_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif /* WLAN_DEBUGFS */ +#endif /* _WLAN_HDD_DEBUGFS_CONFIG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_csr.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_csr.h new file mode 100644 index 0000000000..05f214a4a6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_csr.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_csr.h + * + * WLAN Host Device Driver implementation to update + * debugfs with connect, scan and roam information + */ + +#ifndef _WLAN_HDD_DEBUGFS_CSR_H +#define _WLAN_HDD_DEBUGFS_CSR_H + +#include + +#ifdef WLAN_DEBUGFS + +#define DEBUGFS_OFFLOAD_INFO_BUF_SIZE (4 * 1024) +#define DEBUGFS_ROAM_SCAN_STATS_INFO_BUF_SIZE (4 * 1024) + +/** + * struct wlan_hdd_debugfs_buffer_info - Debugfs buffer info + * @length: current length of the debugfs buffer + * @max_buf_len: maximum buffer length of the debugfs buffer + * @id: id from enum hdd_debugfs_file_id used to identify file + * @data: start of debugfs buffer from which file read starts + * @adapter: pointer to adapter + * + * This structure is used to hold the debugfs buffer details and is stored in + * private data of file argument in file open operation. + */ +struct wlan_hdd_debugfs_buffer_info { + ssize_t length; + ssize_t max_buf_len; + enum hdd_debugfs_file_id id; + uint8_t *data; + struct hdd_adapter *adapter; +}; + +/** + * struct hdd_roam_scan_stats_debugfs_priv - private data for request mgr + * @roam_scan_stats_res: pointer to roam scan stats response + */ +struct hdd_roam_scan_stats_debugfs_priv { + struct wmi_roam_scan_stats_res *roam_scan_stats_res; +}; + +/** + * wlan_hdd_debugfs_csr_init() - Create wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be created + * + * Return: None + */ +void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter); + +/** + * wlan_hdd_debugfs_csr_deinit() - Remove wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be removed + * + * Return: None + */ +void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter); + +/** + * wlan_hdd_current_time_info_debugfs() - API to get time into user buffer + * @buf: output buffer to hold current time when queried + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len); + +/** + * wlan_hdd_debugfs_update_filters_info() - API to get offload info + * into user buffer + * @hdd_ctx: Pointer to hdd context + * @adapter: pointer to the adapter targeted by the debugfs operation + * @buf: output buffer to hold offload info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +ssize_t +wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len); + +/** + * wlan_hdd_debugfs_update_roam_stats() - API to get roam scan stats info + * into user buffer + * @hdd_ctx: Pointer to hdd context + * @adapter: pointer to the adapter targeted by the debugfs operation + * @buf: output buffer to hold roam scan stats info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +ssize_t +wlan_hdd_debugfs_update_roam_stats(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len); + +#else + +static inline void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter) +{ +} + +static inline void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter) +{ +} + +static inline ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len) +{ + return 0; +} + +static inline ssize_t +wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + return 0; +} + +static inline ssize_t +wlan_hdd_debugfs_update_roam_stats(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + return 0; +} + +#endif + +#endif /* _WLAN_HDD_DEBUGFS_CSR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_llstat.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_llstat.h new file mode 100644 index 0000000000..52427dbcaa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_llstat.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_llstat.h + * + * WLAN Host Device Driver implementation to update + * debugfs with Link Layer statistics + */ + +#ifndef _WLAN_HDD_DEBUGFS_LLSTAT_H +#define _WLAN_HDD_DEBUGFS_LLSTAT_H + +#include + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#define DEBUGFS_LLSTATS_BUF_SIZE 32768 +#else +#define DEBUGFS_LLSTATS_BUF_SIZE 16384 +#endif + +#define DEBUGFS_LLSTATS_REQID 4294967295UL +#define DEBUGFS_LLSTATS_REQMASK 0x7 + +#if defined(WLAN_FEATURE_LINK_LAYER_STATS) && defined(WLAN_DEBUGFS) +/** + * hdd_debugfs_process_peer_stats() - Parse Peer stats and add it to buffer + * @adapter: Pointer to device adapter + * @data: Pointer to stats data + * + * Receiving Link Layer peer statistics from FW. This function stores the + * firmware data in a buffer to be written into debugfs. + * + * Return: None + */ +void hdd_debugfs_process_peer_stats(struct hdd_adapter *adapter, void *data); + +/** + * hdd_debugfs_process_radio_stats() - Parse Radio stats and add it to buffer + * @adapter: Pointer to device adapter + * @more_data: More data + * @data: Pointer to stats data + * @num_radio: Number of radios + * + * Receiving Link Layer Radio statistics from FW. This function stores the + * firmware data in a buffer to be written into debugfs. + * + * Return: None + */ +void hdd_debugfs_process_radio_stats(struct hdd_adapter *adapter, + uint32_t more_data, void *data, uint32_t num_radio); + +/** + * hdd_debugfs_process_iface_stats() - This function is called after + * @link_info: Link info pointer in HDD adapter + * @data: Pointer to stats data + * @num_peers: Number of peers + * + * Receiving Link Layer Interface statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +void hdd_debugfs_process_iface_stats(struct wlan_hdd_link_info *link_info, + void *data, uint32_t num_peers); + +/** + * wlan_hdd_create_ll_stats_file() - API to create Link Layer stats file + * @adapter: interface adapter pointer + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_create_ll_stats_file(struct hdd_adapter *adapter); +#else +static inline void hdd_debugfs_process_peer_stats(struct hdd_adapter *adapter, + void *data) +{ +} + +static inline void hdd_debugfs_process_radio_stats( + struct hdd_adapter *adapter, + uint32_t more_data, void *data, uint32_t num_radio) +{ +} + +static inline void +hdd_debugfs_process_iface_stats(struct wlan_hdd_link_info *link_info, + void *data, uint32_t num_peers) +{ +} + +static inline int wlan_hdd_create_ll_stats_file(struct hdd_adapter *adapter) +{ + return 0; +} +#endif +#endif /* #ifndef _WLAN_HDD_DEBUGFS_LLSTAT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_mibstat.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_mibstat.h new file mode 100644 index 0000000000..da813430fd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_mibstat.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_mibstat.h + * + * WLAN Host Device Driver implementation to update + * debugfs with MIB statistics + */ + +#ifndef _WLAN_HDD_DEBUGFS_MIBSTAT_H +#define _WLAN_HDD_DEBUGFS_MIBSTAT_H + +#define DEBUGFS_MIBSTATS_BUF_SIZE 4096 + +#include + +#if defined(WLAN_FEATURE_MIB_STATS) && defined(WLAN_DEBUGFS) +/** + * hdd_debugfs_process_mib_stats() - Process mib stats from fw + * @adapter: interface adapter pointer + * @stats: mib stats + * + * This function is used to store mib stats to global variable mib_stats. + * + * Return: None + */ +void hdd_debugfs_process_mib_stats(struct hdd_adapter *adapter, + struct stats_event *stats); + +/** + * wlan_hdd_create_mib_stats_file() - API to create MIB stats file + * @adapter: interface adapter pointer + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_create_mib_stats_file(struct hdd_adapter *adapter); + +/** + * wlan_hdd_create_mib_stats_lock() - API to create MIB stats lock + * + * Return: No return + */ +void wlan_hdd_create_mib_stats_lock(void); + +/** + * wlan_hdd_destroy_mib_stats_lock() - API to destroy MIB stats lock + * + * Return: No return + */ +void wlan_hdd_destroy_mib_stats_lock(void); +#else +static inline int wlan_hdd_create_mib_stats_file(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void wlan_hdd_create_mib_stats_lock(void) +{ +} + +static inline void wlan_hdd_destroy_mib_stats_lock(void) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_DEBUGFS_MIBSTAT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_unit_test.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_unit_test.h new file mode 100644 index 0000000000..2d04ac6f58 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_debugfs_unit_test.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_unit_test.h + * + * WLAN Host Device Driver implementation to create debugfs + * unit_test_host/unit_test_target + */ + +#ifndef _WLAN_HDD_DEBUGFS_UNIT_TEST_H +#define _WLAN_HDD_DEBUGFS_UNIT_TEST_H + +#if defined(WLAN_DEBUGFS) && defined(WLAN_UNIT_TEST) +/** + * wlan_hdd_debugfs_unit_test_host_create() - API to create unit_test_target + * @hdd_ctx: hdd context + * + * this file is created per driver. + * file path: /sys/kernel/debug/wlan_xx/unit_test_host + * (wlan_xx is driver name) + * usage: + * echo 'all'>unit_test_host + * echo 'qdf_periodic_work'>unit_test_host + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_debugfs_unit_test_host_create(struct hdd_context *hdd_ctx); +#else +static inline int +wlan_hdd_debugfs_unit_test_host_create(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif +#endif /* _WLAN_HDD_DEBUGFS_UNIT_TEST_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h new file mode 100644 index 0000000000..dbb8fc7456 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_driver_ops.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015-2017, 2019, 2021 The Linux Foundation. + * All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_DRIVER_OPS_H__ +#define __WLAN_HDD_DRIVER_OPS_H__ + +#include "hif.h" +#include + +struct hdd_context; + +#define wlan_hdd_trigger_cds_recovery(reason) \ + __wlan_hdd_trigger_cds_recovery(reason, __func__, __LINE__) + +void __wlan_hdd_trigger_cds_recovery(enum qdf_hang_reason reason, + const char *func, const uint32_t line); +/** + * DOC: wlan_hdd_driver_ops.h + * + * Functions to register the wlan driver. + */ + +/** + * wlan_hdd_register_driver() - Register with platform layer + * + * This function is used to register HDD callbacks with the platform + * layer. + * + * Return: 0 if registration is successful, negative errno if + * registration fails + */ +int wlan_hdd_register_driver(void); + +/** + * wlan_hdd_unregister_driver() - Unregister from platform layer + * + * This function is used to unregister HDD callbacks from the platform + * layer. + * + * Return: void + */ + +void wlan_hdd_unregister_driver(void); + +/** + * wlan_hdd_bus_suspend() - suspend the wlan bus + * + * This function is called by the platform driver to suspend the + * wlan bus + * + * Return: 0 on success, negative errno on error + */ +int wlan_hdd_bus_suspend(void); + +/** + * wlan_hdd_bus_suspend_noirq() - handle .suspend_noirq callback + * + * This function is called by the platform driver to complete the + * bus suspend callback when device interrupts are disabled by kernel. + * Call HIF and WMA suspend_noirq callbacks to make sure there is no + * wake up pending from FW before allowing suspend. + * + * Return: 0 for success and -EBUSY if FW is requesting wake up + */ +int wlan_hdd_bus_suspend_noirq(void); + +/** + * wlan_hdd_bus_resume() - wake up the bus + * + * @type: WoW suspend type + * + * This function is called by the platform driver to resume wlan + * bus + * + * Return: 0 for success and negative errno if failure + */ +int wlan_hdd_bus_resume(enum qdf_suspend_type type); + +/** + * wlan_hdd_bus_resume_noirq() - handle bus resume no irq + * + * This function is called by the platform driver to do bus + * resume no IRQ before calling resume callback. Call WMA and HIF + * layers to complete the resume_noirq. + * + * Return: 0 for success and negative error code for failure + */ +int wlan_hdd_bus_resume_noirq(void); + +/** + * hdd_hif_close() - HIF close helper + * @hdd_ctx: HDD context + * @hif_ctx: HIF context + * + * Helper function to close HIF + */ +void hdd_hif_close(struct hdd_context *hdd_ctx, void *hif_ctx); + +/** + * hdd_hif_open() - HIF open helper + * @dev: wlan device structure + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * @reinit: true if we are reinitializing the driver during recovery phase + * + * This function brings-up HIF layer during load/recovery phase. + * + * Return: 0 on success and errno on failure. + */ +int hdd_hif_open(struct device *dev, void *bdev, const struct hif_bus_id *bid, + enum qdf_bus_type bus_type, bool reinit); + +/** + * hdd_soc_idle_restart_lock() - Takes wakelock for idle restart + * @dev: wlan device structure + * + * This function takes wakelock to prevent suspend during idle restart + * + * Return: 0 for success and non zero for error + */ +int hdd_soc_idle_restart_lock(struct device *dev); + +/** + * hdd_soc_idle_restart_unlock() - Releases wakelock for idle restart + * + * This function releases wakelock to allow suspend after idle restart + * + * Return: none + */ +void hdd_soc_idle_restart_unlock(void); + +#ifdef FORCE_WAKE +/** + * hdd_set_hif_init_phase() - Enable/disable the + * init_phase flag + * @hif_ctx: hif opaque handle + * @init_phase: init phase flag + * + * Return: None + */ +void hdd_set_hif_init_phase(struct hif_opaque_softc *hif_ctx, + bool init_phase); +#else +static inline +void hdd_set_hif_init_phase(struct hif_opaque_softc *hif_ctx, + bool init_phase) +{ +} +#endif /* FORCE_WAKE */ + +#ifdef HIF_DETECTION_LATENCY_ENABLE +/** + * hdd_hif_set_enable_detection() - enable detection + * @hif_ctx: hif opaque handle + * @value: enable/disable + * + * Return: None + */ +void hdd_hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value); +#else +static inline +void hdd_hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value) +{ +} +#endif /* HIF_DETECTION_LATENCY_ENABLE */ + +/** + * hdd_deinit_qdf_ctx() - API to Deinitialize global QDF Device structure + * @domain: Debug domain + * + * Return: 0 - success, < 0 - failure + */ +int hdd_deinit_qdf_ctx(uint8_t domain); +#endif /* __WLAN_HDD_DRIVER_OPS_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_eht.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_eht.h new file mode 100644 index 0000000000..ee930b4087 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_eht.h @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_eht.h + * + * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) + * support. + * + */ + +#if !defined(WLAN_HDD_EHT_H) +#define WLAN_HDD_EHT_H +#include "wlan_osif_features.h" + +struct hdd_context; +struct wma_tgt_cfg; +struct hdd_beacon_data; +struct sap_config; + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +/** + * hdd_update_tgt_eht_cap() - Update EHT related capabilities + * @hdd_ctx: HDD context + * @cfg: Target capabilities + * + * This function updates WNI CFG with Target capabilities received as part of + * Default values present in WNI CFG are the values supported by FW/HW. + * INI should be introduced if user control is required to control the value. + * + * Return: None + */ +void hdd_update_tgt_eht_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg); + +/** + * wlan_hdd_check_11be_support() - check if beacon IE and update hw mode + * @beacon: beacon IE buffer + * @config: pointer to sap config + * + * Check if EHT cap IE is present in beacon IE, if present update hw mode + * to 11be. + * + * Return: None + */ +void wlan_hdd_check_11be_support(struct hdd_beacon_data *beacon, + struct sap_config *config); + +/** + * hdd_update_wiphy_eht_cap() - update the wiphy with eht capabilities + * @hdd_ctx: HDD context + * + * update wiphy with the eht capabilities. + * + * Return: None + */ +void hdd_update_wiphy_eht_cap(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_get_mlo_link_id() - get link id and number of links + * @beacon: beacon IE buffer + * @link_id: link id to return + * @num_link: total links + * + * Return: None + */ +void wlan_hdd_get_mlo_link_id(struct hdd_beacon_data *beacon, + uint8_t *link_id, uint8_t *num_link); + +/** + * hdd_set_11be_rate_code() - set 11be rate code + * @adapter: net device adapter + * @rate_code: new 11be rate code + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_11be_rate_code(struct hdd_adapter *adapter, uint16_t rate_code); + +/** + * wlan_hdd_fill_os_eht_rateflags() - Fill EHT related rate_info + * @os_rate: rate info for os + * @rate_flags: rate flags + * @dcm: dcm from rate + * @guard_interval: guard interval from rate + * + * Return: none + */ +void wlan_hdd_fill_os_eht_rateflags(struct rate_info *os_rate, + enum tx_rate_info rate_flags, + uint8_t dcm, + enum txrate_gi guard_interval); +#else +static inline +void hdd_update_tgt_eht_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} + +static inline void wlan_hdd_check_11be_support(struct hdd_beacon_data *beacon, + struct sap_config *config) +{ +} + +static inline +void hdd_update_wiphy_eht_cap(struct hdd_context *hdd_ctx) +{ +} + +static inline int +hdd_set_11be_rate_code(struct hdd_adapter *adapter, uint16_t rate_code) +{ + return 0; +} + +static inline void wlan_hdd_get_mlo_link_id(struct hdd_beacon_data *beacon, + uint8_t *link_id, uint8_t *num_link) +{ +} + +static inline +void wlan_hdd_fill_os_eht_rateflags(struct rate_info *os_rate, + enum tx_rate_info rate_flags, + uint8_t dcm, + enum txrate_gi guard_interval) +{ +} +#endif + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) && \ + defined(FEATURE_RX_LINKSPEED_ROAM_TRIGGER) +/** + * wlan_hdd_refill_os_eht_rateflags() - Refill EHT rate flag + * @os_rate: rate info for os + * @preamble: Use to acquire wlan mode, whether in EHT mode + * + * Fill out os ETH MCS rate flag according to preamble. + * + * Return: none + */ +void +wlan_hdd_refill_os_eht_rateflags(struct rate_info *os_rate, uint8_t preamble); + +/** + * wlan_hdd_refill_os_eht_bw() - Refill EHT bandwidth + * @os_rate: rate info for os + * @bw: Bandwidth of the frame + * + * Fill out os ETH BW flag according to CMN BW from driver. + * + * Return: none + */ +void +wlan_hdd_refill_os_eht_bw(struct rate_info *os_rate, enum rx_tlv_bw bw); +#else +static inline void +wlan_hdd_refill_os_eht_rateflags(struct rate_info *os_rate, uint8_t preamble) +{ +} + +static inline void +wlan_hdd_refill_os_eht_bw(struct rate_info *os_rate, enum rx_tlv_bw bw) +{ +} +#endif +#endif /* if !defined(WLAN_HDD_EHT_H)*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h new file mode 100644 index 0000000000..1c71e01d07 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ether.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_ETHER_H +#define _WLAN_HDD_ETHER_H +/** + * DOC: wlan_hdd_ether.h + * + * This module describes Ethernet packet formats for processing by HDD. + */ + +/* + * Include Files + */ +#include +#include +#include +#include + +/* + * Preprocessor Definitions and Constants + */ +#define WLAN_SNAP_OUI_LEN 3 +#define WLAN_SNAP_DSAP 0xAAU +#define WLAN_SNAP_SSAP 0xAAU +#define WLAN_SNAP_CTRL 0x03 +#define WLAN_MIN_PROTO 0x0600 + +/* + * Type Declarations + */ +struct wlan_snap_hdr { + unsigned char dsap; + unsigned char ssap; + unsigned char ctrl; + unsigned char oui[WLAN_SNAP_OUI_LEN]; +} __packed; + +struct wlan_8023 { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + __be16 h_len; + struct wlan_snap_hdr h_snap; + __be16 h_proto; +} __packed; + +struct wlan_8023_vlan { + unsigned char h_dest[ETH_ALEN]; + unsigned char h_source[ETH_ALEN]; + __be16 h_vlan_proto; + __be16 h_vlan_TCI; + __be16 h_len; + struct wlan_snap_hdr h_snap; + __be16 h_proto; +} __packed; + +union generic_ethhdr { + struct ethhdr eth_II; + struct vlan_ethhdr eth_IIv; + struct wlan_8023 eth_8023; + struct wlan_8023_vlan eth_8023v; +}; + +#endif /* #ifndef _WLAN_HDD_ETHER_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h new file mode 100644 index 0000000000..c975ec6afb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_HDD_FTM_H +#define WLAN_HDD_FTM_H + +/** + * DOC: wlan_hdd_ftm.h + * + * WLAN Host Device Driver Factory Test Mode header file + */ + +#include "qdf_status.h" +#include "scheduler_api.h" +#include "cds_api.h" +#include "qdf_types.h" +#include + +struct hdd_context; + +#if defined(QCA_WIFI_FTM) +int wlan_hdd_qcmbr_unified_ioctl(struct hdd_adapter *adapter, + void __user *data); +int hdd_update_cds_config_ftm(struct hdd_context *hdd_ctx); +#else +static inline int hdd_update_cds_config_ftm(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif /* QCA_WIFI_FTM */ +#endif /* WLAN_HDD_FTM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm_time_sync.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm_time_sync.h new file mode 100644 index 0000000000..24468fe855 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ftm_time_sync.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "ftm_time_sync_ucfg_api.h" +#include "wlan_hdd_main.h" + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM +/** + * hdd_ftm_time_sync_sta_state_notify() - notify FTM TIME SYNC sta state change + * @adapter: pointer to adapter + * @state: enum ftm_time_sync_sta_state + * + * This function is called by hdd connect and disconnect handler and notifies + * the FTM TIME SYNC component about the sta state. + * + * Return: None + */ +void +hdd_ftm_time_sync_sta_state_notify(struct hdd_adapter *adapter, + enum ftm_time_sync_sta_state state); + +#else + +static inline void +hdd_ftm_time_sync_sta_state_notify(struct hdd_adapter *adapter, + enum ftm_time_sync_sta_state state) +{ +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_fw_state.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_fw_state.h new file mode 100644 index 0000000000..8a1132e406 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_fw_state.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_fw_state.h + * + * Get firmware state related API's and definitions + */ + +#ifndef __WLAN_HDD_FW_STATE_H +#define __WLAN_HDD_FW_STATE_H + +#ifdef FEATURE_FW_STATE +#include +/** + * wlan_hdd_cfg80211_get_fw_state() - get fw state + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_get_fw_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_FW_STATE_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_FW_STATE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_get_fw_state, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, +#else /* FEATURE_FW_STATE */ +#define FEATURE_FW_STATE_COMMANDS +#endif /* FEATURE_FW_STATE */ +#endif /* __WLAN_HDD_FW_STATE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_gpio.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_gpio.h new file mode 100644 index 0000000000..20d4e977c3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_gpio.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_gpio.h + * + * This Header file provide declaration for cfg80211 command handler API + */ + +#ifndef __WLAN_HDD_GPIO_H__ +#define __WLAN_HDD_GPIO_H__ + +#include +#include +#include + +#ifdef WLAN_FEATURE_GPIO_CFG +#include + +#define FEATURE_GPIO_CFG_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GPIO_CONFIG_COMMAND, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_gpio_config, \ + vendor_command_policy(wlan_cfg80211_gpio_config_policy, \ + QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX) \ +}, + +/** + * wlan_hdd_cfg80211_set_gpio_config() - set GPIO config + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data to be passed via vendor interface + * @data_len: Length of the data to be passed + * + * Return: Return the Success or Failure code + */ +int wlan_hdd_cfg80211_set_gpio_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +#else +#define FEATURE_GPIO_CFG_VENDOR_COMMANDS +#endif /* WLAN_FEATURE_GPIO_CFG */ +#endif /* __WLAN_CFG80211_GPIO_CFG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_gpio_wakeup.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_gpio_wakeup.h new file mode 100644 index 0000000000..e42831e63d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_gpio_wakeup.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_GPIO_WAKEUP_H__ +#define __WLAN_HDD_GPIO_WAKEUP_H__ + +#ifdef WLAN_ENABLE_GPIO_WAKEUP +/** + * wlan_hdd_gpio_wakeup_init() - Init gpio wakeup + * @hdd_ctx: pointer to the struct hdd_context + * + * Init gpio wakeup + * + * Return: success or not + */ +int wlan_hdd_gpio_wakeup_init(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_gpio_wakeup_deinit() - Deinit gpio wakeup + * @hdd_ctx: pointer to the struct hdd_context + * + * Deinit gpio wakeup + * + * Return: success or not + */ +int wlan_hdd_gpio_wakeup_deinit(struct hdd_context *hdd_ctx); +#else +static inline int wlan_hdd_gpio_wakeup_init(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline int wlan_hdd_gpio_wakeup_deinit(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_hang_event.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_hang_event.h new file mode 100644 index 0000000000..3eb7bc4cc0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_hang_event.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef WLAN_HDD_HANG_EVENT_H +#define WLAN_HDD_HANG_EVENT_H +#include +#include + +#ifdef WLAN_HANG_EVENT +/** + * wlan_hdd_hang_event_notifier_register() - HDD hang event notifier register + * @hdd_ctx: HDD context + * + * This function registers hdd layer notifier for the hang event notifier chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_hang_event_notifier_register(struct hdd_context *hdd_ctx); +/** + * wlan_hdd_hang_event_notifier_unregister() - HDD hang event notifier + * unregister + * + * This function unregisters hdd layer notifier for the hang event notifier + * chain. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_hang_event_notifier_unregister(void); +#else +static inline +QDF_STATUS wlan_hdd_hang_event_notifier_register(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS wlan_hdd_hang_event_notifier_unregister(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_he.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_he.h new file mode 100644 index 0000000000..d2774fd02a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_he.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_he.h + * + * WLAN Host Device Driver file for 802.11ax (High Efficiency) support. + * + */ + +#if !defined(WLAN_HDD_HE_H) +#define WLAN_HDD_HE_H + +struct hdd_context; +struct wma_tgt_cfg; +struct hdd_beacon_data; +struct sap_config; + +#ifdef WLAN_FEATURE_11AX +/** + * enum qca_wlan_vendor_attr_get_he_capabilities - attributes for HE caps + * vendor command. + * @QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID: invalid + * @QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED: to check if HE capabilities is supported + * @QCA_WLAN_VENDOR_ATTR_PHY_CAPAB: to get HE PHY capabilities + * @QCA_WLAN_VENDOR_ATTR_MAC_CAPAB: to get HE MAC capabilities + * @QCA_WLAN_VENDOR_ATTR_HE_MCS: to get HE MCS + * @QCA_WLAN_VENDOR_ATTR_NUM_SS: to get NUM SS + * @QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK: to get RU index mask + * @QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD: to get PPE Threshold, + * @QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST: next to last valid enum + * @QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX: max value supported + * + * enum values are used for NL attributes for data used by + * QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES sub command. + */ +enum qca_wlan_vendor_attr_get_he_capabilities { + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED, + QCA_WLAN_VENDOR_ATTR_PHY_CAPAB, + QCA_WLAN_VENDOR_ATTR_MAC_CAPAB, + QCA_WLAN_VENDOR_ATTR_HE_MCS, + QCA_WLAN_VENDOR_ATTR_NUM_SS = 5, + QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK, + QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD, + + /* keep last */ + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_MAX = + QCA_WLAN_VENDOR_ATTR_HE_CAPABILITIES_AFTER_LAST - 1, +}; + +/* QCA_NL80211_VENDOR_SUBCMD_SR policy*/ +extern const struct nla_policy +wlan_hdd_sr_policy[QCA_WLAN_VENDOR_ATTR_SR_MAX + 1]; + +/** + * hdd_update_tgt_he_cap() - Update HE related capabilities + * @hdd_ctx: HDD context + * @cfg: Target capabilities + * + * This function updaates WNI CFG with Target capabilities received as part of + * Default values present in WNI CFG are the values supported by FW/HW. + * INI should be introduced if user control is required to control the value. + * + * Return: None + */ +void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg); + +/** + * wlan_hdd_check_11ax_support() - check if beacon IE and update hw mode + * @beacon: beacon IE buffer + * @config: pointer to sap config + * + * Check if HE cap IE is present in beacon IE, if present update hw mode + * to 11ax. + * + * Return: None + */ +void wlan_hdd_check_11ax_support(struct hdd_beacon_data *beacon, + struct sap_config *config); + +/** + * hdd_update_he_cap_in_cfg() - update HE cap in global CFG + * @hdd_ctx: pointer to hdd context + * + * This API will update the HE config in CFG after taking intersection + * of INI and firmware capabilities provided reading CFG + * + * Return: 0 on success and errno on failure + */ +int hdd_update_he_cap_in_cfg(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_cfg80211_get_he_cap() - get HE Capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len); +#ifdef WLAN_FEATURE_SR +/** + * wlan_hdd_cfg80211_sr_operations() - Spatial Reuse Operations + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_sr_operations(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * hdd_sr_register_callbacks() - register hdd callback for sr + * @hdd_ctx: hdd context + * + * Return: void + */ +void hdd_sr_register_callbacks(struct hdd_context *hdd_ctx); + +#else +static inline +int wlan_hdd_cfg80211_sr_operations(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} + +static inline void hdd_sr_register_callbacks(struct hdd_context *hdd_ctx) +{ +} +#endif + +#define FEATURE_11AX_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_HE_CAPABILITIES, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_get_he_cap, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SR, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_sr_operations, \ + vendor_command_policy(wlan_hdd_sr_policy, \ + QCA_WLAN_VENDOR_ATTR_SR_MAX) \ +}, + +#else +static inline void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} + +static inline void wlan_hdd_check_11ax_support(struct hdd_beacon_data *beacon, + struct sap_config *config) +{ +} + +static inline int hdd_update_he_cap_in_cfg(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline void hdd_sr_register_callbacks(struct hdd_context *hdd_ctx) +{ +} + +/* dummy definition */ +#define FEATURE_11AX_VENDOR_COMMANDS + +#endif +#endif /* if !defined(WLAN_HDD_HE_H)*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h new file mode 100644 index 0000000000..e9b984e5d2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_host_offload.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2014-2017, 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_HOST_OFFLOAD_H__ +#define __WLAN_HDD_HOST_OFFLOAD_H__ + +/** + * DOC: wlan_hdd_host_offload.h + * + * Android WLAN HDD Host Offload API + */ + +/* Offload types. */ +#define WLAN_IPV4_ARP_REPLY_OFFLOAD 0 +#define WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD 1 + +/* Enable or disable offload. */ +#define WLAN_OFFLOAD_DISABLE 0 +#define WLAN_OFFLOAD_ENABLE 0x1 +#define WLAN_OFFLOAD_BC_FILTER_ENABLE 0x2 +#define WLAN_OFFLOAD_ARP_AND_BC_FILTER_ENABLE \ + (WLAN_OFFLOAD_ENABLE | WLAN_OFFLOAD_BC_FILTER_ENABLE) + +/* Offload request. */ +struct host_offload_req { + uint8_t offloadType; + uint8_t enableOrDisable; + union { + uint8_t hostIpv4Addr[QDF_IPV4_ADDR_SIZE]; + uint8_t hostIpv6Addr[QDF_IPV6_ADDR_SIZE]; + } params; + struct qdf_mac_addr bssId; +}; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_wlan_offload_event(uint8_t type, uint8_t state); +#else +static inline +void hdd_wlan_offload_event(uint8_t type, uint8_t state) +{ +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#endif /* __WLAN_HDD_HOST_OFFLOAD_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h new file mode 100644 index 0000000000..1c1c90a0e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_includes.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2014, 2016-2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(HDD_INCLUDES_H__) +#define HDD_INCLUDES_H__ + +/** + * DOC: wlan_hdd_includes.h + * + * Internal includes for the Linux HDD + */ + +/* + * Include files + * + * throw all the includes in here to get the .c files in the HDD to compile. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_wext.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_tx_rx.h" +#include + +#ifdef FEATURE_OEM_DATA_SUPPORT +#include "wlan_hdd_oemdata.h" +#endif + +#endif /* end #if !defined(HDD_INCLUDES_H__) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h new file mode 100644 index 0000000000..efeab27bce --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ipa.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef HDD_IPA_H__ +#define HDD_IPA_H__ + +/** + * DOC: wlan_hdd_ipa.h + * + * WLAN IPA interface module headers + */ + +#include + +#ifdef IPA_OFFLOAD + +/** + * hdd_ipa_send_nbuf_to_network() - Send network buffer to kernel + * @nbuf: network buffer + * @dev: network adapter + * + * Called when a network buffer is received which should not be routed + * to the IPA module. + * + * Return: None + */ +void hdd_ipa_send_nbuf_to_network(qdf_nbuf_t nbuf, qdf_netdev_t dev); + +/** + * hdd_ipa_set_mcc_mode() - To set mcc mode if IPA is enabled + * @mcc_mode: mcc mode + * + * This routine is called to set mcc mode if IPA is enabled + * + * Return: None + */ +void hdd_ipa_set_mcc_mode(bool mcc_mode); + +/** + * hdd_ipa_get_tx_pipe() - Get tx pipe for the new connection + * @hdd_ctx: pointer to hdd_context + * @link: pointer to struct wlan_hdd_link_info + * @tx_pipe: boolean output param to store which pipe to use for @link. + * false is the primary tx pipe and true is the alternate tx pipe. + * + * Return: QDF_STATUS_SUCCESS for success, and otherwise for failure scenarios. + * + */ +QDF_STATUS hdd_ipa_get_tx_pipe(struct hdd_context *hdd_ctx, + struct wlan_hdd_link_info *link, + bool *tx_pipe); + +/* + * hdd_ipa_set_perf_level_bw() - Set ipa perf level based on BW + * @bw: enum hw_mode_bandwidth + * + * This routine is called to set IPA perf level based on max BW configured + * among in-use STA and SAP vdevs. + * + * Return: None + */ +void hdd_ipa_set_perf_level_bw(enum hw_mode_bandwidth bw); + +#else +static inline +void hdd_ipa_send_nbuf_to_network(qdf_nbuf_t skb, qdf_netdev_t dev) +{ +} + +static inline void hdd_ipa_set_mcc_mode(bool mcc_mode) +{ +} + +static inline QDF_STATUS +hdd_ipa_get_tx_pipe(struct hdd_context *hdd_ctx, + struct wlan_hdd_link_info *link, + bool *tx_pipe) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_ipa_set_perf_level_bw(enum hw_mode_bandwidth bw) +{ +} + +#endif +#endif /* HDD_IPA_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ll_lt_sap.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ll_lt_sap.h new file mode 100644 index 0000000000..c53ce748be --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_ll_lt_sap.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_lt_sap_declarations specific to the ll_lt_sap module + */ + +#ifndef __WLAN_HDD_LL_LT_SAP_H +#define __WLAN_HDD_LL_LT_SAP_H + +#include "wlan_hdd_main.h" +#include "qca_vendor.h" + +extern const struct nla_policy + wlan_hdd_ll_lt_sap_transport_switch_policy + [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1]; + +#define FEATURE_LL_LT_SAP_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ll_lt_sap_transport_switch, \ + vendor_command_policy(wlan_hdd_ll_lt_sap_transport_switch_policy, \ + QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX)\ +}, + +/** + * wlan_hdd_cfg80211_ll_lt_sap_transport_switch() - Request to switch the + * transport + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#endif /* __WLAN_HDD_LL_LT_SAP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h new file mode 100644 index 0000000000..197748d90d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h @@ -0,0 +1,5594 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_MAIN_H) +#define WLAN_HDD_MAIN_H +/** + * DOC: wlan_hdd_main.h + * + * Linux HDD Adapter Type + */ + +/* + * The following terms were in use in prior versions of the driver but + * have now been replaced with terms that are aligned with the Linux + * Coding style. Macros are defined to hopefully prevent new instances + * from being introduced, primarily by code propagation. + */ +#define pHddCtx +#define pAdapter +#define pHostapdAdapter +#define pHddApCtx +#define pHddStaCtx +#define pHostapdState +#define pRoamInfo +#define pScanInfo +#define pBeaconIes + +/* + * Include files + */ + +#include +#include +#include +#include +#include +#include +#include +#include "sir_mac_prot_def.h" +#include "csr_api.h" +#include "wlan_dsc.h" +#include +#include +#include +#include +#include +#if defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#ifdef WLAN_FEATURE_TSF_PTP +#include +#include +#endif +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_debugfs.h" +#include +#include "sap_api.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include "wlan_hdd_nan_datapath.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include +#include +#include +#include +#include +#include +#include "wlan_pmo_ucfg_api.h" +#ifdef WIFI_POS_CONVERGED +#include "os_if_wifi_pos.h" +#include "wifi_pos_api.h" +#else +#include "wlan_hdd_oemdata.h" +#endif +#include "wlan_hdd_he.h" + +#include +#include +#include "wlan_hdd_twt.h" +#include "wma_sar_public_structs.h" +#include "wlan_mlme_ucfg_api.h" +#include "pld_common.h" +#include "wlan_cm_roam_public_struct.h" + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +#include "qdf_periodic_work.h" +#endif + +#if defined(CLD_PM_QOS) || defined(FEATURE_RUNTIME_PM) +#include +#endif + +#include "wlan_hdd_sta_info.h" +#include +#include "wlan_hdd_mlo.h" +#include "wlan_osif_features.h" +#include "wlan_dp_public_struct.h" + +/* + * Preprocessor definitions and constants + */ + +/* Milli seconds to delay SSR thread when an packet is getting processed */ +#define SSR_WAIT_SLEEP_TIME 200 +/* MAX iteration count to wait for dp tx to complete */ +#define MAX_SSR_WAIT_ITERATIONS 100 +#define MAX_SSR_PROTECT_LOG (16) + +#define HDD_MAX_OEM_DATA_LEN 1024 +#define HDD_MAX_FILE_NAME_LEN 64 +#ifdef FEATURE_WLAN_APF +/** + * struct hdd_apf_context - hdd Context for apf + * @magic: magic number + * @qdf_apf_event: Completion variable for APF get operations + * @capability_response: capabilities response received from fw + * @apf_enabled: True: APF Interpreter enabled, False: Disabled + * @cmd_in_progress: Flag that indicates an APF command is in progress + * @buf: Buffer to accumulate read memory chunks + * @buf_len: Length of the read memory requested + * @offset: APF work memory offset to fetch from + * @lock: APF Context lock + */ +struct hdd_apf_context { + unsigned int magic; + qdf_event_t qdf_apf_event; + bool apf_enabled; + bool cmd_in_progress; + uint8_t *buf; + uint32_t buf_len; + uint32_t offset; + qdf_spinlock_t lock; +}; +#endif /* FEATURE_WLAN_APF */ + +#ifdef TX_MULTIQ_PER_AC +#define TX_GET_QUEUE_IDX(ac, off) (((ac) * TX_QUEUES_PER_AC) + (off)) +#define TX_QUEUES_PER_AC 4 +#else +#define TX_GET_QUEUE_IDX(ac, off) (ac) +#define TX_QUEUES_PER_AC 1 +#endif + +/** Number of Tx Queues */ +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || \ + defined(QCA_HL_NETDEV_FLOW_CONTROL) || \ + defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/* Only one HI_PRIO queue */ +#define NUM_TX_QUEUES (4 * TX_QUEUES_PER_AC + 1) +#else +#define NUM_TX_QUEUES (4 * TX_QUEUES_PER_AC) +#endif + +#define NUM_RX_QUEUES 5 + +/* + * Number of DPTRACE records to dump when a cfg80211 disconnect with reason + * WLAN_REASON_DEAUTH_LEAVING DEAUTH is received from user-space. + */ +#define WLAN_DEAUTH_DPTRACE_DUMP_COUNT 100 + +/* HDD_IS_RATE_LIMIT_REQ: Macro helper to implement rate limiting + * @flag: The flag to determine if limiting is required or not + * @rate: The number of seconds within which if multiple commands come, the + * flag will be set to true + * + * If the function in which this macro is used is called multiple times within + * "rate" number of seconds, the "flag" will be set to true which can be used + * to reject/take appropriate action. + */ +#define HDD_IS_RATE_LIMIT_REQ(flag, rate)\ + do {\ + static ulong __last_ticks;\ + ulong __ticks = jiffies;\ + flag = false; \ + if (!time_after(__ticks,\ + __last_ticks + rate * HZ)) {\ + flag = true; \ + } \ + else { \ + __last_ticks = __ticks;\ + } \ + } while (0) + +/* + * API in_compat_syscall() is introduced in 4.6 kernel to check whether we're + * in a compat syscall or not. It is a new way to query the syscall type, which + * works properly on all architectures. + * + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)) +static inline bool in_compat_syscall(void) { return is_compat_task(); } +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) || \ + defined(CFG80211_REMOVE_IEEE80211_BACKPORT) +#define HDD_NL80211_BAND_2GHZ NL80211_BAND_2GHZ +#define HDD_NL80211_BAND_5GHZ NL80211_BAND_5GHZ +#define HDD_NUM_NL80211_BANDS NUM_NL80211_BANDS +#else +#define HDD_NL80211_BAND_2GHZ IEEE80211_BAND_2GHZ +#define HDD_NL80211_BAND_5GHZ IEEE80211_BAND_5GHZ +#define HDD_NUM_NL80211_BANDS ((enum nl80211_band)IEEE80211_NUM_BANDS) +#endif + +#if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \ + (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)) +#define HDD_NL80211_BAND_6GHZ NL80211_BAND_6GHZ +#endif + +#define TSF_GPIO_PIN_INVALID 255 + +/** Length of the TX queue for the netdev */ +#define HDD_NETDEV_TX_QUEUE_LEN (3000) + +/** Hdd Tx Time out value */ +#define HDD_TX_TIMEOUT msecs_to_jiffies(5000) + +#define HDD_TX_STALL_THRESHOLD 4 + +/** Hdd Default MTU */ +#define HDD_DEFAULT_MTU (1500) + +#ifdef QCA_CONFIG_SMP +#define NUM_CPUS NR_CPUS +#else +#define NUM_CPUS 1 +#endif + +#define ACS_COMPLETE_TIMEOUT 3000 + +#define HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY (1000) +/** + * enum hdd_adapter_flags - event bitmap flags registered net device + * @NET_DEVICE_REGISTERED: Adapter is registered with the kernel + * @WMM_INIT_DONE: Adapter is initialized + * @DEVICE_IFACE_OPENED: Adapter has been "opened" via the kernel + * @WDEV_ONLY_REGISTERED: Only WDEV is registered + */ +enum hdd_adapter_flags { + NET_DEVICE_REGISTERED, + WMM_INIT_DONE, + DEVICE_IFACE_OPENED, + WDEV_ONLY_REGISTERED, +}; + +/** + * enum hdd_link_flags - Event bitmap flags specific to per link + * @SME_SESSION_OPENED: Firmware vdev has been created + * @SOFTAP_BSS_STARTED: Software Access Point (SAP) is running + * @SOFTAP_INIT_DONE: Software Access Point (SAP) is initialized + * @VENDOR_ACS_RESPONSE_PENDING: Waiting for event for vendor acs + */ +enum hdd_link_flags { + SME_SESSION_OPENED, + SOFTAP_BSS_STARTED, + SOFTAP_INIT_DONE, + VENDOR_ACS_RESPONSE_PENDING, +}; + +/** + * enum hdd_nb_cmd_id - North bound command IDs received during SSR + * @NO_COMMAND: No NB command received during SSR + * @INTERFACE_DOWN: Received interface down during SSR + */ +enum hdd_nb_cmd_id { + NO_COMMAND, + INTERFACE_DOWN +}; + +#define WLAN_WAIT_TIME_STATS 800 +#define WLAN_WAIT_TIME_LINK_STATUS 800 + +/** Maximum time(ms) to wait for mc thread suspend **/ +#define WLAN_WAIT_TIME_MCTHREAD_SUSPEND 1200 + +/** Maximum time(ms) to wait for target to be ready for suspend **/ +#define WLAN_WAIT_TIME_READY_TO_SUSPEND 2000 + +/* Scan Req Timeout */ +#define WLAN_WAIT_TIME_SCAN_REQ 100 + +#define WLAN_WAIT_TIME_APF 1000 + +#define WLAN_WAIT_TIME_FW_ROAM_STATS 1000 + +#define WLAN_WAIT_TIME_ANTENNA_ISOLATION 8000 + +/* Maximum time(ms) to wait for RSO CMD status event */ +#define WAIT_TIME_RSO_CMD_STATUS 2000 + +/* rcpi request timeout in milli seconds */ +#define WLAN_WAIT_TIME_RCPI 500 + +#define WLAN_WAIT_PEER_CLEANUP 5000 + +#define MAX_CFG_STRING_LEN 255 + +/* Maximum time(ms) to wait for external acs response */ +#define WLAN_VENDOR_ACS_WAIT_TIME 1000 + +/* Maximum time(ms) to wait for monitor mode vdev up event completion*/ +#define WLAN_MONITOR_MODE_VDEV_UP_EVT SME_CMD_VDEV_START_BSS_TIMEOUT + +/* Mac Address string length */ +#define MAC_ADDRESS_STR_LEN 18 /* Including null terminator */ +/* Max and min IEs length in bytes */ +#define MAX_GENIE_LEN (512) +#define MIN_GENIE_LEN (2) + +#define WPS_OUI_TYPE "\x00\x50\xf2\x04" +#define WPS_OUI_TYPE_SIZE 4 + +#define P2P_OUI_TYPE "\x50\x6f\x9a\x09" +#define P2P_OUI_TYPE_SIZE 4 + +#define OSEN_OUI_TYPE "\x50\x6f\x9a\x12" +#define OSEN_OUI_TYPE_SIZE 4 + +#ifdef WLAN_FEATURE_WFD +#define WFD_OUI_TYPE "\x50\x6f\x9a\x0a" +#define WFD_OUI_TYPE_SIZE 4 +#endif + +#define MBO_OUI_TYPE "\x50\x6f\x9a\x16" +#define MBO_OUI_TYPE_SIZE 4 + +#define QCN_OUI_TYPE "\x8c\xfd\xf0\x01" +#define QCN_OUI_TYPE_SIZE 4 + +#define wlan_hdd_get_wps_ie_ptr(ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE, \ + ie, ie_len) + +#define hdd_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_HDD, params) +#define hdd_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_HDD, params) +#define hdd_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_HDD, params) +#define hdd_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_HDD, params) +#define hdd_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_HDD, params) + +#define hdd_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_HDD, params) +#define hdd_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_HDD, params) +#define hdd_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_HDD, params) +#define hdd_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_HDD, params) +#define hdd_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_HDD, params) + +#define hdd_alert_rl(params...) QDF_TRACE_FATAL_RL(QDF_MODULE_ID_HDD, params) +#define hdd_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_HDD, params) +#define hdd_warn_rl(params...) QDF_TRACE_WARN_RL(QDF_MODULE_ID_HDD, params) +#define hdd_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_HDD, params) +#define hdd_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD, params) + +#define hdd_enter() QDF_TRACE_ENTER(QDF_MODULE_ID_HDD, "enter") +#define hdd_enter_dev(dev) \ + QDF_TRACE_ENTER(QDF_MODULE_ID_HDD, "enter(%s)", (dev)->name) +#define hdd_exit() QDF_TRACE_EXIT(QDF_MODULE_ID_HDD, "exit") + +#define WLAN_HDD_GET_PRIV_PTR(__dev__) \ + (struct hdd_adapter *)(netdev_priv((__dev__))) + +#define MAX_NO_OF_2_4_CHANNELS 14 + +#define WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET 24 + +#define WLAN_HDD_IS_SOCIAL_CHANNEL(center_freq) \ + (((center_freq) == 2412) || ((center_freq) == 2437) || \ + ((center_freq) == 2462)) + +#define WLAN_HDD_QOS_ACTION_FRAME 1 +#define WLAN_HDD_QOS_MAP_CONFIGURE 4 +#define HDD_SAP_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED + +/* SAP client disconnect wake lock duration in milli seconds */ +#define HDD_SAP_CLIENT_DISCONNECT_WAKE_LOCK_DURATION \ + WAKELOCK_DURATION_RECOMMENDED + +#define HDD_CFG_REQUEST_FIRMWARE_RETRIES (3) +#define HDD_CFG_REQUEST_FIRMWARE_DELAY (20) + +#define MAX_USER_COMMAND_SIZE 4096 +#define DNS_DOMAIN_NAME_MAX_LEN 255 +#define ICMPv6_ADDR_LEN 16 + + +#define HDD_MIN_TX_POWER (-100) /* minimum tx power */ +#define HDD_MAX_TX_POWER (+100) /* maximum tx power */ + +/* If IPA UC data path is enabled, target should reserve extra tx descriptors + * for IPA data path. + * Then host data path should allow less TX packet pumping in case + * IPA data path enabled + */ +#define WLAN_TFC_IPAUC_TX_DESC_RESERVE 100 + +/* + * NET_NAME_UNKNOWN is only introduced after Kernel 3.17, to have a macro + * here if the Kernel version is less than 3.17 to avoid the interleave + * conditional compilation. + */ +#if !((LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) ||\ + defined(WITH_BACKPORTS)) +#define NET_NAME_UNKNOWN 0 +#endif + +#define PRE_CAC_SSID "pre_cac_ssid" + +#define SCAN_REJECT_THRESHOLD_TIME 300000 /* Time is in msec, equal to 5 mins */ +#define SCAN_REJECT_THRESHOLD 15 + +/* Default Psoc id */ +#define DEFAULT_PSOC_ID 1 + +/* wait time for nud stats in milliseconds */ +#define WLAN_WAIT_TIME_NUD_STATS 800 +/* nud stats skb max length */ +#define WLAN_NUD_STATS_LEN 800 +/* ARP packet type for NUD debug stats */ +#define WLAN_NUD_STATS_ARP_PKT_TYPE 1 +/* Assigned size of driver memory dump is 4096 bytes */ +#define DRIVER_MEM_DUMP_SIZE 4096 + +/* MAX OS Q block time value in msec + * Prevent from permanent stall, resume OS Q if timer expired + */ +#define WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 1000 +#define WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 100 +#define WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH 14 + +#ifndef NUM_TX_RX_HISTOGRAM +#define NUM_TX_RX_HISTOGRAM 128 +#endif + +#define NUM_TX_RX_HISTOGRAM_MASK (NUM_TX_RX_HISTOGRAM - 1) + +#define HDD_NOISE_FLOOR_DBM (-96) + +#define INTF_MACADDR_MASK 0x7 + +/** + * typedef wlan_net_dev_ref_dbgid - Debug IDs to detect net device reference + * leaks. + * NOTE: New values added to the enum must also be reflected in function + * net_dev_ref_debug_string_from_id() + */ +typedef enum { + NET_DEV_HOLD_ID_RESERVED = 0, + NET_DEV_HOLD_GET_STA_CONNECTION_IN_PROGRESS = 1, + NET_DEV_HOLD_CHECK_DFS_CHANNEL_FOR_ADAPTER = 2, + NET_DEV_HOLD_GET_SAP_OPERATING_BAND = 3, + NET_DEV_HOLD_RECOVERY_NOTIFIER_CALL = 4, + NET_DEV_HOLD_IS_ANY_STA_CONNECTING = 5, + NET_DEV_HOLD_SAP_DESTROY_CTX_ALL = 6, + NET_DEV_HOLD_DRV_CMD_MAX_TX_POWER = 7, + NET_DEV_HOLD_IPA_SET_TX_FLOW_INFO = 8, + NET_DEV_HOLD_SET_RPS_CPU_MASK = 9, + NET_DEV_HOLD_DFS_INDICATE_RADAR = 10, + NET_DEV_HOLD_MAX_STA_INTERFACE_UP_COUNT_REACHED = 11, + NET_DEV_HOLD_IS_CHAN_SWITCH_IN_PROGRESS = 12, + NET_DEV_HOLD_STA_DESTROY_CTX_ALL = 13, + NET_DEV_HOLD_CHECK_FOR_EXISTING_MACADDR = 14, + NET_DEV_HOLD_DEINIT_ALL_ADAPTERS = 15, + NET_DEV_HOLD_STOP_ALL_ADAPTERS = 16, + NET_DEV_HOLD_RESET_ALL_ADAPTERS = 17, + NET_DEV_HOLD_IS_ANY_INTERFACE_OPEN = 18, + NET_DEV_HOLD_START_ALL_ADAPTERS = 19, + NET_DEV_HOLD_GET_ADAPTER_BY_RAND_MACADDR = 20, + NET_DEV_HOLD_GET_ADAPTER_BY_MACADDR = 21, + NET_DEV_HOLD_GET_ADAPTER_BY_VDEV = 22, + NET_DEV_HOLD_ADAPTER_GET_BY_REFERENCE = 23, + NET_DEV_HOLD_GET_ADAPTER_BY_IFACE_NAME = 24, + NET_DEV_HOLD_GET_ADAPTER = 25, + NET_DEV_HOLD_GET_OPERATING_CHAN_FREQ = 26, + NET_DEV_HOLD_UNREGISTER_WEXT_ALL_ADAPTERS = 27, + NET_DEV_HOLD_ABORT_MAC_SCAN_ALL_ADAPTERS = 28, + NET_DEV_HOLD_ABORT_SCHED_SCAN_ALL_ADAPTERS = 29, + NET_DEV_HOLD_GET_FIRST_VALID_ADAPTER = 30, + NET_DEV_HOLD_CLEAR_RPS_CPU_MASK = 31, + NET_DEV_HOLD_BUS_BW_WORK_HANDLER = 32, + NET_DEV_HOLD_DISPLAY_NETIF_QUEUE_HISTORY_COMPACT = 33, + NET_DEV_HOLD_DISPLAY_NETIF_QUEUE_HISTORY = 34, + NET_DEV_HOLD_CLEAR_NETIF_QUEUE_HISTORY = 35, + NET_DEV_HOLD_UNSAFE_CHANNEL_RESTART_SAP = 36, + NET_DEV_HOLD_INDICATE_MGMT_FRAME = 37, + NET_DEV_HOLD_STATE_INFO_DUMP = 38, + NET_DEV_HOLD_DISABLE_ROAMING = 39, + NET_DEV_HOLD_ENABLE_ROAMING = 40, + NET_DEV_HOLD_AUTO_SHUTDOWN_ENABLE = 41, + NET_DEV_HOLD_GET_CON_SAP_ADAPTER = 42, + NET_DEV_HOLD_IS_ANY_ADAPTER_CONNECTED = 43, + NET_DEV_HOLD_IS_ROAMING_IN_PROGRESS = 44, + NET_DEV_HOLD_DEL_P2P_INTERFACE = 45, + NET_DEV_HOLD_IS_NDP_ALLOWED = 46, + NET_DEV_HOLD_NDI_OPEN = 47, + NET_DEV_HOLD_SEND_OEM_REG_RSP_NLINK_MSG = 48, + NET_DEV_HOLD_PERIODIC_STA_STATS_DISPLAY = 49, + NET_DEV_HOLD_SUSPEND_WLAN = 50, + NET_DEV_HOLD_RESUME_WLAN = 51, + NET_DEV_HOLD_SSR_RESTART_SAP = 52, + NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES = 53, + NET_DEV_HOLD_CFG80211_SUSPEND_WLAN = 54, + NET_DEV_HOLD_COUNTRY_CHANGE_UPDATE_STA = 55, + NET_DEV_HOLD_COUNTRY_CHANGE_UPDATE_SAP = 56, + NET_DEV_HOLD_CACHE_STATION_STATS_CB = 57, + NET_DEV_HOLD_DISPLAY_TXRX_STATS = 58, + NET_DEV_HOLD_BUS_BW_MGR = 59, + NET_DEV_HOLD_START_PRE_CAC_TRANS = 60, + NET_DEV_HOLD_IS_ANY_STA_CONNECTED = 61, + NET_DEV_HOLD_GET_ADAPTER_BY_BSSID = 62, + NET_DEV_HOLD_ALLOW_NEW_INTF = 63, + + /* Keep it at the end */ + NET_DEV_HOLD_ID_MAX +} wlan_net_dev_ref_dbgid; + +struct hdd_tx_rx_stats { + struct { + /* start_xmit stats */ + __u32 tx_classified_ac[WLAN_MAX_AC]; + __u32 tx_dropped_ac[WLAN_MAX_AC]; +#ifdef TX_MULTIQ_PER_AC + /* Neither valid socket nor skb->hash */ + uint32_t inv_sk_and_skb_hash; + /* skb->hash already calculated */ + uint32_t qselect_existing_skb_hash; + /* valid tx queue id in socket */ + uint32_t qselect_sk_tx_map; + /* skb->hash calculated in select queue */ + uint32_t qselect_skb_hash_calc; +#endif + } per_cpu[NUM_CPUS]; + + /* txflow stats */ + bool is_txflow_paused; + __u32 txflow_pause_cnt; + __u32 txflow_unpause_cnt; + __u32 txflow_timer_cnt; + +}; + +/** + * struct hdd_pmf_stats - Protected Management Frame statistics + * @num_unprot_deauth_rx: Number of unprotected deauth frames received + * @num_unprot_disassoc_rx: Number of unprotected disassoc frames received + */ +struct hdd_pmf_stats { + uint8_t num_unprot_deauth_rx; + uint8_t num_unprot_disassoc_rx; +}; + +/** + * struct hdd_peer_stats - Peer stats at HDD level + * @rx_count: RX count + * @rx_bytes: RX bytes + * @fcs_count: FCS err count + */ +struct hdd_peer_stats { + uint32_t rx_count; + uint64_t rx_bytes; + uint32_t fcs_count; +}; + +#define HDD_MAX_PER_PEER_RATES 16 +#if defined(WLAN_FEATURE_11BE_MLO) +/** + * struct wlan_hdd_station_stats_info - Station stats info + * @signal: Signal strength of last received PPDU + * @signal_avg: Average signal strength + * @chain_signal_avg: Per-chain signal strength average + * @rxrate: Last unicast data frame rx rate + * @txrate: Current unicasr tx rate + * @rx_bytes: Total received bytes (MPDU length) + * @tx_bytes: Total transmitted bytes (MPDU length) + * @rx_packets: Total received packets (MSDUs and MMPDUs) + * @tx_packets: Total transmitted packets (MSDUs and MMPDUs) + * @tx_retries: Cumulative retry count (MPDU) + * @tx_failed: Number of failed transmissions (MPDUs) + * @rx_mpdu_count: Number of MPDUs received from this station + * @fcs_err_count: Number of MPDUs received from this station with an FCS error + */ +struct wlan_hdd_station_stats_info { + int8_t signal; + int8_t signal_avg; + int8_t chain_signal_avg[IEEE80211_MAX_CHAINS]; + struct rate_info txrate; + struct rate_info rxrate; + uint64_t rx_bytes; + uint64_t tx_bytes; + uint32_t rx_packets; + uint32_t tx_packets; + uint32_t tx_retries; + uint32_t tx_failed; + uint32_t rx_mpdu_count; + uint32_t fcs_err_count; +}; + +/** + * struct wlan_hdd_mlo_iface_stats_info - mlo iface stats info + * @link_id: mlo link_id + * @freq: frequency of the mlo link + * @radio_id: radio id of the mlo link + */ +struct wlan_hdd_mlo_iface_stats_info { + uint8_t link_id; + uint32_t freq; + uint32_t radio_id; +}; + +/** + * struct wlan_hdd_peer_info - hdd per peer info + * @type: peer type (AP, TDLS, GO etc.) + * @peer_mac: peer mac address + * @capabilities: peer WIFI_CAPABILITY_XXX + * @power_saving: peer power saving mode + * @num_rate: number of rates + * @rate_stats: per rate statistics, num entries = HDD_MAX_PER_PEER_RATES + * @stats_cached: whether peer stats cached into link_info struct + * @link_id: IEEE link id for the link + */ +struct wlan_hdd_peer_info { + enum wmi_peer_type type; + struct qdf_mac_addr peer_mac; + uint32_t capabilities; + union { + uint32_t power_saving; + uint32_t num_rate; + }; + struct wifi_rate_stat rate_stats[HDD_MAX_PER_PEER_RATES]; + bool stats_cached; + uint32_t link_id; +}; +#endif + +#define MAX_SUBTYPES_TRACKED 4 + +struct hdd_stats { + tCsrSummaryStatsInfo summary_stat; + tCsrGlobalClassAStatsInfo class_a_stat; + tCsrGlobalClassDStatsInfo class_d_stat; + struct csr_per_chain_rssi_stats_info per_chain_rssi_stats; + struct hdd_tx_rx_stats tx_rx_stats; + struct hdd_peer_stats peer_stats; + struct hdd_pmf_stats hdd_pmf_stats; + struct pmf_bcn_protect_stats bcn_protect_stats; +}; + +/** + * struct hdd_roaming_info - HDD Internal Roaming Information + * @bssid: BSSID to which we are connected + * @peer_mac: Peer MAC address for IBSS connection + * @roam_id: Unique identifier for a roaming instance + * @roam_status: Current roam command status + */ +struct hdd_roaming_info { + tSirMacAddr bssid; + tSirMacAddr peer_mac; + uint32_t roam_id; + eRoamCmdStatus roam_status; +}; + +#ifdef FEATURE_WLAN_WAPI +/* Define WAPI macros for Length, BKID count etc*/ +#define MAX_NUM_AKM_SUITES 16 + +/** WAPI AUTH mode definition */ +enum wapi_auth_mode { + WAPI_AUTH_MODE_OPEN = 0, + WAPI_AUTH_MODE_PSK = 1, + WAPI_AUTH_MODE_CERT +} __packed; + +#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) +#define WPA_GET_BE24(a) ((u32) ((a[0] << 16) | (a[1] << 8) | a[2])) +#define WAPI_PSK_AKM_SUITE 0x02721400 +#define WAPI_CERT_AKM_SUITE 0x01721400 + +/** + * struct hdd_wapi_info - WAPI Information structure definition + * @wapi_mode: Is WAPI enabled on this adapter? + * @is_wapi_sta: Is the STA associated with WAPI? + * @wapi_auth_mode: WAPI authentication mode used by this adapter + */ +struct hdd_wapi_info { + bool wapi_mode; + bool is_wapi_sta; + enum wapi_auth_mode wapi_auth_mode; +}; +#endif /* FEATURE_WLAN_WAPI */ + +struct hdd_beacon_data { + u8 *head; + u8 *tail; + u8 *proberesp_ies; + u8 *assocresp_ies; + int head_len; + int tail_len; + int proberesp_ies_len; + int assocresp_ies_len; + int dtim_period; +}; + +/** + * struct hdd_mon_set_ch_info - Holds monitor mode channel switch params + * @freq: Channel frequency. + * @cb_mode: Channel bonding + * @channel_width: Channel width 0/1/2 for 20/40/80MHz respectively. + * @phy_mode: PHY mode + */ +struct hdd_mon_set_ch_info { + uint32_t freq; + uint8_t cb_mode; + uint32_t channel_width; + eCsrPhyMode phy_mode; +}; + +/** + * struct hdd_station_ctx -- STA-specific information + * @roam_profile: current roaming profile + * @conn_info: current connection information + * @cache_conn_info: prev connection info + * @reg_phymode: reg phymode + * @ch_info: monitor mode channel information + * @ap_supports_immediate_power_save: Does the current AP allow our STA + * to immediately go into power save? + * @user_cfg_chn_width: max channel bandwidth set by user space + */ +struct hdd_station_ctx { + uint32_t reg_phymode; + struct csr_roam_profile roam_profile; + struct hdd_connection_info conn_info; + struct hdd_connection_info cache_conn_info; + struct hdd_mon_set_ch_info ch_info; + bool ap_supports_immediate_power_save; + uint8_t user_cfg_chn_width; +}; + +/** + * enum bss_state - current state of the BSS + * @BSS_STOP: BSS is stopped + * @BSS_START: BSS is started + */ +enum bss_state { + BSS_STOP, + BSS_START, +}; + +/** + * struct hdd_hostapd_state - hostapd-related state information + * @bss_state: Current state of the BSS + * @qdf_event: Event to synchronize actions between hostapd thread and + * internal callback threads + * @qdf_stop_bss_event: Event to synchronize Stop BSS. When Stop BSS + * is issued userspace thread can wait on this event. The event will + * be set when the Stop BSS processing in UMAC has completed. + * @qdf_sta_disassoc_event: Event to synchronize STA Disassociation. + * When a STA is disassociated userspace thread can wait on this + * event. The event will be set when the STA Disassociation + * processing in UMAC has completed. + * @qdf_sta_eap_frm_done_event: Event to synchronize P2P GO disassoc + * frame and EAP frame. + * @qdf_status: Used to communicate state from other threads to the + * userspace thread. + */ +struct hdd_hostapd_state { + enum bss_state bss_state; + qdf_event_t qdf_event; + qdf_event_t qdf_stop_bss_event; + qdf_event_t qdf_sta_disassoc_event; + qdf_event_t qdf_sta_eap_frm_done_event; + QDF_STATUS qdf_status; +}; + +/** + * enum bss_stop_reason - reasons why a BSS is stopped. + * @BSS_STOP_REASON_INVALID: no reason specified explicitly. + * @BSS_STOP_DUE_TO_MCC_SCC_SWITCH: BSS stopped due to host + * driver is trying to switch AP role to a different channel + * to maintain SCC mode with the STA role on the same card. + * this usually happens when STA is connected to an external + * AP that runs on a different channel + * @BSS_STOP_DUE_TO_VENDOR_CONFIG_CHAN: BSS stopped due to + * vendor subcmd set sap config channel + */ +enum bss_stop_reason { + BSS_STOP_REASON_INVALID = 0, + BSS_STOP_DUE_TO_MCC_SCC_SWITCH = 1, + BSS_STOP_DUE_TO_VENDOR_CONFIG_CHAN = 2, +}; + +/** + * struct hdd_rate_info - rate_info in HDD + * @rate: tx/rx rate (kbps) + * @mode: 0->11abg legacy, 1->HT, 2->VHT (refer to sir_sme_phy_mode) + * @nss: number of streams + * @mcs: mcs index for HT/VHT mode + * @rate_flags: rate flags for last tx/rx + * + * rate info in HDD + */ +struct hdd_rate_info { + uint32_t rate; + uint8_t mode; + uint8_t nss; + uint8_t mcs; + enum tx_rate_info rate_flags; +}; + +enum hdd_work_status { + HDD_WORK_UNINITIALIZED, + HDD_WORK_INITIALIZED, +}; + +/** + * struct hdd_fw_txrx_stats - fw txrx status in HDD + * (refer to station_info struct in Kernel) + * @tx_packets: packets transmitted to this station + * @tx_bytes: bytes transmitted to this station + * @rx_packets: packets received from this station + * @rx_bytes: bytes received from this station + * @tx_retries: cumulative retry counts + * @tx_failed: the number of failed frames + * @tx_succeed: the number of succeed frames + * @rssi: The signal strength (dbm) + * @tx_rate: last used tx rate info + * @rx_rate: last used rx rate info + * + * fw txrx status in HDD + */ +struct hdd_fw_txrx_stats { + uint32_t tx_packets; + uint64_t tx_bytes; + uint32_t rx_packets; + uint64_t rx_bytes; + uint32_t tx_retries; + uint32_t tx_failed; + uint32_t tx_succeed; + int8_t rssi; + struct hdd_rate_info tx_rate; + struct hdd_rate_info rx_rate; +}; + +/** + * struct hdd_ap_ctx - SAP/P2PGO specific information + * @hostapd_state: state control information + * @dfs_cac_block_tx: Is data tramsmission blocked due to DFS CAC? + * @ap_active: Are any stations active? + * @disable_intrabss_fwd: Prevent forwarding between stations + * @broadcast_sta_id: Station ID assigned after BSS starts + * @privacy: The privacy bits of configuration + * @encryption_type: The encryption being used + * @group_key: Group Encryption Key + * @wep_key: WEP key array + * @wep_def_key_idx: WEP default key index + * @sap_context: Pointer to context maintained by SAP (opaque to HDD) + * @sap_config: SAP configuration + * @operating_chan_freq: channel upon which the SAP is operating + * @beacon: Beacon information + * @vendor_acs_timer: Timer for ACS + * @vendor_acs_timer_initialized: Is @vendor_acs_timer initialized? + * @bss_stop_reason: Reason why the BSS was stopped + * @acs_in_progress: In progress acs flag for an adapter + * @ch_switch_in_progress: channel change in progress or not + * @client_count: client count per dot11_mode + * @country_ie_updated: country ie is updated or not by hdd hostapd + * @during_auth_offload: auth mgmt frame is offloading to hostapd + * @reg_punc_bitmap: puncturing bitmap + */ +struct hdd_ap_ctx { + struct hdd_hostapd_state hostapd_state; + bool dfs_cac_block_tx; + bool ap_active; + bool disable_intrabss_fwd; + uint8_t broadcast_sta_id; + uint8_t privacy; + eCsrEncryptionType encryption_type; + uint8_t wep_def_key_idx; + struct sap_context *sap_context; + struct sap_config sap_config; + uint32_t operating_chan_freq; + struct hdd_beacon_data *beacon; + qdf_mc_timer_t vendor_acs_timer; + bool vendor_acs_timer_initialized; + enum bss_stop_reason bss_stop_reason; + qdf_atomic_t acs_in_progress; + qdf_atomic_t ch_switch_in_progress; + uint16_t client_count[QCA_WLAN_802_11_MODE_INVALID]; + bool country_ie_updated; + bool during_auth_offload; +#ifdef WLAN_FEATURE_11BE + uint16_t reg_punc_bitmap; +#endif +}; + +/** + * struct hdd_scan_info - Per-adapter scan information + * @scan_add_ie: Additional IE for scan + * @default_scan_ies: Default scan IEs + * @default_scan_ies_len: Length of @default_scan_ies + * @scan_mode: Scan mode + */ +struct hdd_scan_info { + tSirAddie scan_add_ie; + uint8_t *default_scan_ies; + uint16_t default_scan_ies_len; + tSirScanType scan_mode; +}; + +#define WLAN_HDD_MAX_MC_ADDR_LIST CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES + +struct hdd_multicast_addr_list { + uint8_t mc_cnt; + uint8_t addr[WLAN_HDD_MAX_MC_ADDR_LIST][ETH_ALEN]; +}; + +#define WLAN_HDD_MAX_HISTORY_ENTRY 25 + +/** + * struct hdd_netif_queue_stats - netif queue operation statistics + * @pause_count: pause counter + * @unpause_count: unpause counter + * @total_pause_time: amount of time in paused state + */ +struct hdd_netif_queue_stats { + u32 pause_count; + u32 unpause_count; + qdf_time_t total_pause_time; +}; + +/** + * struct hdd_netif_queue_history - netif queue operation history + * @time: timestamp + * @netif_action: action type + * @netif_reason: reason type + * @pause_map: pause map + * @tx_q_state: state of the netdev TX queues + */ +struct hdd_netif_queue_history { + qdf_time_t time; + uint16_t netif_action; + uint16_t netif_reason; + uint32_t pause_map; + unsigned long tx_q_state[NUM_TX_QUEUES]; +}; + +/** + * struct hdd_chan_change_params - channel related information + * @chan_freq: operating channel frequency + * @chan_params: channel parameters + */ +struct hdd_chan_change_params { + uint32_t chan_freq; + struct ch_params chan_params; +}; + +/** + * struct hdd_runtime_pm_context - context to prevent/allow runtime pm + * @dfs: dfs context to prevent/allow runtime pm + * @connect: connect context to prevent/allow runtime pm + * @user: user context to prevent/allow runtime pm + * @is_user_wakelock_acquired: boolean to check if user wakelock status + * @monitor_mode: monitor mode context to prevent/allow runtime pm + * @wow_unit_test: wow unit test mode context to prevent/allow runtime pm + * @system_suspend: system suspend context to prevent/allow runtime pm + * @dyn_mac_addr_update: update mac addr context to prevent/allow runtime pm + * @vdev_destroy: vdev destroy context to prevent/allow runtime pm + * @oem_data_cmd: OEM data context to prevent/allow runtime pm + * + * Runtime PM control for underlying activities + */ +struct hdd_runtime_pm_context { + qdf_runtime_lock_t dfs; + qdf_runtime_lock_t connect; + qdf_runtime_lock_t user; + bool is_user_wakelock_acquired; + qdf_runtime_lock_t monitor_mode; + qdf_runtime_lock_t wow_unit_test; + qdf_runtime_lock_t system_suspend; + qdf_runtime_lock_t dyn_mac_addr_update; + qdf_runtime_lock_t vdev_destroy; + qdf_runtime_lock_t oem_data_cmd; +}; + +/* + * WLAN_HDD_ADAPTER_MAGIC is a magic number used to identify net devices + * belonging to this driver from net devices belonging to other devices. + * Therefore, the magic number must be unique relative to the numbers for + * other drivers in the system. If WLAN_HDD_ADAPTER_MAGIC is already defined + * (e.g. by compiler argument), then use that. If it's not already defined, + * then use the first 4 characters of MULTI_IF_NAME to construct the magic + * number. If MULTI_IF_NAME is not defined, then use a default magic number. + */ +#ifndef WLAN_HDD_ADAPTER_MAGIC +#ifdef MULTI_IF_NAME +#define WLAN_HDD_ADAPTER_MAGIC \ + (MULTI_IF_NAME[0] == 0 ? 0x574c414e : \ + (MULTI_IF_NAME[1] == 0 ? (MULTI_IF_NAME[0] << 24) : \ + (MULTI_IF_NAME[2] == 0 ? (MULTI_IF_NAME[0] << 24) | \ + (MULTI_IF_NAME[1] << 16) : \ + (MULTI_IF_NAME[0] << 24) | (MULTI_IF_NAME[1] << 16) | \ + (MULTI_IF_NAME[2] << 8) | MULTI_IF_NAME[3]))) +#else +#define WLAN_HDD_ADAPTER_MAGIC 0x574c414e /* ASCII "WLAN" */ +#endif +#endif + +/** + * struct rcpi_info - rcpi info + * @rcpi: computed value in dB + * @mac_addr: peer mac addr for which rcpi is computed + */ +struct rcpi_info { + int32_t rcpi; + struct qdf_mac_addr mac_addr; +}; + +struct hdd_context; + +#ifdef MULTI_CLIENT_LL_SUPPORT +/* Max host clients which can request the FW arbiter with the latency level */ +#define WLM_MAX_HOST_CLIENT 5 + +/** + * struct wlm_multi_client_info_table - To store multi client id information + * @client_id: host id for a client + * @port_id: client id coming from upper layer + * @in_use: set true for a client when host receives vendor cmd for that client + */ +struct wlm_multi_client_info_table { + uint32_t client_id; + uint32_t port_id; + bool in_use; +}; +#endif + +/** + * enum udp_qos_upgrade - Enumeration of the various User priority (UP) types + * UDP QoS upgrade request + * @UDP_QOS_UPGRADE_NONE: Do not upgrade UDP QoS AC + * @UDP_QOS_UPGRADE_BK_BE: Upgrade UDP QoS for BK/BE only + * @UDP_QOS_UPGRADE_ALL: Upgrade UDP QoS for all packets + * @UDP_QOS_UPGRADE_MAX: Max enum limit, not to add new beyond this + */ +enum udp_qos_upgrade { + UDP_QOS_UPGRADE_NONE, + UDP_QOS_UPGRADE_BK_BE, + UDP_QOS_UPGRADE_ALL, + UDP_QOS_UPGRADE_MAX +}; + +#define WLAN_HDD_DEFLINK_IDX 0 + +/** + * struct wlan_hdd_link_info - Data structure to store the link specific info + * @adapter: Reverse pointer to HDD adapter + * @vdev_id: Unique value to identify VDEV. Equal to WLAN_UMAC_VDEV_ID_MAX + * for invalid VDEVs. + * @vdev_lock: Lock to protect VDEV pointer access. + * @vdev: Pointer to VDEV objmgr. + * @vdev_destroy_event: vdev_destroy_event is moved from the qdf_event + * to linux event consciously, Lets take example + * when sap interface is waiting on the + * session_close event and then there is a SSR + * the wait event is completed the interface down + * is returned and the next command to the driver + * will be hdd_hostapd_uinit--> + * hdd_deinit_ap_mode--> + * hdd_hostapd_deinit_sap_session where in the + * sap_ctx would be freed. During the SSR if the + * same sap context is used it would result in + * null pointer de-reference. + * @link_addr: Link MAC address + * @session: union of @ap and @station specific structs + * @session.station: station mode information + * @session.ap: ap mode specific information + * @acs_complete_event: acs complete event + * @rssi: The signal strength (dBm) + * @snr: SNR measured from @rssi + * @rssi_on_disconnect: Rssi at disconnection time in STA mode + * @rssi_send: Notify RSSI over lpass + * @is_mlo_vdev_active: is the mlo vdev currently active + * @estimated_linkspeed: estimated link speed + * @hdd_stats: HDD statistics + * @big_data_stats: Big data stats + * @ll_iface_stats: Link Layer interface stats + * @hdd_sinfo: hdd vdev station stats that will be sent to userspace + * @mlo_peer_info: mlo peer stats info + * @mscs_prev_tx_vo_pkts: count of prev VO AC packets transmitted + * @mscs_counter: Counter on MSCS action frames sent + * @link_flags: a bitmap of hdd_link_flags + * @chan_change_notify_work: Channel change notify work + */ +struct wlan_hdd_link_info { + struct hdd_adapter *adapter; + uint8_t vdev_id; + qdf_spinlock_t vdev_lock; + struct wlan_objmgr_vdev *vdev; + struct completion vdev_destroy_event; + struct qdf_mac_addr link_addr; + + union { + struct hdd_station_ctx station; + struct hdd_ap_ctx ap; + } session; + + qdf_event_t acs_complete_event; + + int8_t rssi; + uint8_t snr; + int32_t rssi_on_disconnect; +#ifdef WLAN_FEATURE_LPSS + bool rssi_send; +#endif + bool is_mlo_vdev_active; + uint32_t estimated_linkspeed; + struct hdd_stats hdd_stats; +#ifdef WLAN_FEATURE_BIG_DATA_STATS + struct big_data_stats_event big_data_stats; +#endif +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) + struct wifi_interface_stats ll_iface_stats; + struct wlan_hdd_station_stats_info hdd_sinfo; + struct wlan_hdd_peer_info mlo_peer_info; +#endif + +#ifdef WLAN_FEATURE_MSCS + unsigned long mscs_prev_tx_vo_pkts; + uint32_t mscs_counter; +#endif /* WLAN_FEATURE_MSCS */ + + unsigned long link_flags; + qdf_work_t chan_change_notify_work; +}; + +/** + * struct wlan_hdd_tx_power - Structure to store connection tx power info + * @tx_pwr: connection tx power sent by firmware + * @tx_pwr_cached_timestamp: timestamp when tx_pwr is cached into adapter + */ +struct wlan_hdd_tx_power { + int tx_pwr; + uint32_t tx_pwr_cached_timestamp; +}; + +/** + * struct hdd_adapter - hdd vdev/net_device context + * @magic: Magic cookie for adapter sanity verification. Note that this + * needs to be at the beginning of the private data structure so + * that it will exist at the beginning of dev->priv and hence + * will always be in mapped memory + * @node: list node for membership in the adapter list + * @hdd_ctx: + * @dev: Handle to the network device + * @device_mode: + * @ipv4_notifier_work: IPv4 notifier callback for handling ARP offload on + * change in IP + * @ipv6_notifier_work: IPv6 notifier callback for handling NS offload on + * change in IP + * @wdev: TODO Move this to sta Ctx + * @ops: ops checks if Opportunistic Power Save is Enable or Not + * @ctw: stores CT Window value once we receive Opps command from + * wpa_supplicant then using CT Window value we need to Enable + * Opportunistic Power Save + * @allow_power_save: STA/CLI powersave enable/disable from userspace + * @mac_addr: Current MAC Address for the adapter + * @mld_addr: MLD address for adapter + * @event_flags: a bitmap of hdd_adapter_flags + * @curr_link_info_map: Current mapping of link info in adapter array + * @active_links: a bitmap of active links in @link_info array + * @num_links_on_create: No of active links set on initial hdd_open_adapter(). + * @is_ll_stats_req_pending: atomic variable to check active stats req + * @sta_stats_cached_timestamp: last updated stats timestamp + * @qdf_monitor_mode_vdev_up_event: QDF event for monitor mode vdev up + * @disconnect_comp_var: completion variable for disconnect callback + * @linkup_event_var: completion variable for Linkup Event + * @is_link_up_service_needed: Track whether the linkup handling is needed + * @hdd_wmm_status: WMM Status + * @sta_info: + * @cache_sta_info: + * @sta_info_list: + * @cache_sta_info_list: + * @cache_sta_count: number of currently cached stations + * @wapi_info: + * @sap_stop_bss_work: + * @tsf: structure containing tsf related information + * @mc_addr_list: multicast address list + * @mc_list_lock: spin lock for multicast list + * @addr_filter_pattern: + * @scan_info: + * @psb_changed: Flag to ensure PSB is configured through framework + * @configured_psb: UAPSD psb value configured through framework + * @scan_block_work: + * @blocked_scan_request_q: + * @blocked_scan_request_q_lock: + * @tx_flow_control_timer: + * @tx_flow_timer_initialized: + * @tx_flow_low_watermark: + * @tx_flow_hi_watermark_offset: + * @dscp_to_up_map: DSCP to UP QoS Mapping + * @is_link_layer_stats_set: + * @ll_stats_failure_count: + * @link_status: + * @upgrade_udp_qos_threshold: The threshold for user priority upgrade for + * any UDP packet. + * @udp_qos_upgrade_type: UDP QoS packet upgrade request type + * @temperature: variable for temperature in Celsius + * @ocb_mac_address: MAC addresses used for OCB interfaces + * @ocb_mac_addr_count: + * @pause_map: BITMAP indicating pause reason + * @subqueue_pause_map: + * @pause_map_lock: + * @start_time: + * @last_time: + * @total_pause_time: + * @total_unpause_time: + * @history_index: + * @queue_oper_history: + * @queue_oper_stats: + * @debugfs_phy: debugfs entry + * @lfr_fw_status: + * @active_ac: + * @mon_chan_freq: + * @mon_bandwidth: + * @latency_level: 0 - normal, 1 - xr, 2 - low, 3 - ultralow + * @multi_client_ll_support: to check multi client ll support in driver + * @client_info: To store multi client id information + * @multi_ll_response_cookie: cookie for multi client ll command + * @multi_ll_req_in_progress: to check multi client ll request in progress + * @multi_ll_resp_expected: to decide whether host will wait for multi client + * event or not + * @monitor_mode_vdev_up_in_progress: + * @rcpi: rcpi information + * @send_mode_change: + * @apf_context: + * @csr_file: + * @motion_detection_mode: + * @motion_det_cfg: + * @motion_det_in_progress: + * @motion_det_baseline_value: + * @last_disconnect_reason: Last disconnected internal reason code + * as per enum qca_disconnect_reason_codes + * @connect_req_status: Last disconnected internal status code + * as per enum qca_sta_connect_fail_reason_codes + * @peer_cleanup_done: + * @oem_data_in_progress: + * @cookie: + * @response_expected: + * @handle_feature_update: Handle feature update only if it is triggered + * by hdd_netdev_feature_update + * @tso_csum_feature_enabled: Indicate if TSO and checksum offload features + * are enabled or not + * @netdev_features_update_work: work for handling the netdev features update + * for the adapter. + * @netdev_features_update_work_status: status for netdev_features_update_work + * @net_dev_hold_ref_count: + * @delete_in_progress: Flag to indicate that the adapter delete is in + * progress, and any operation using rtnl lock inside + * the driver can be avoided/skipped. + * @is_virtual_iface: Indicates that netdev is called from virtual interface + * @mon_adapter: hdd_adapter of monitor mode. + * @mlo_adapter_info: + * @set_mac_addr_req_ctx: Set MAC address command request context + * @delta_qtime: delta between host qtime and monotonic time + * @traffic_end_ind_en: traffic end indication feature enable/disable + * @is_dbam_configured: + * @user_phy_mode: phy mode is set per vdev + * @deflink: Default link pointing to the 0th index of the linkinfo array + * @link_info: Data structure to hold link specific information + * @tx_power: Structure to hold connection tx Power info + * @tx_latency_cfg: configuration for per-link transmit latency statistics + * @link_state_cached_timestamp: link state cached timestamp + * @keep_alive_interval: user configured STA keep alive interval + */ +struct hdd_adapter { + uint32_t magic; + qdf_list_node_t node; + + struct hdd_context *hdd_ctx; + + struct net_device *dev; + + enum QDF_OPMODE device_mode; + + struct work_struct ipv4_notifier_work; +#ifdef WLAN_NS_OFFLOAD + /* IPv6 notifier callback for handling NS offload on change in IP */ + struct work_struct ipv6_notifier_work; +#endif + + /* TODO Move this to sta Ctx */ + struct wireless_dev wdev; + + uint8_t ops; + uint32_t ctw; + bool allow_power_save; + + struct qdf_mac_addr mac_addr; +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV + struct qdf_mac_addr mld_addr; +#endif + unsigned long event_flags; + uint8_t curr_link_info_map[WLAN_MAX_ML_BSS_LINKS]; + unsigned long active_links; + uint8_t num_links_on_create; + + qdf_atomic_t is_ll_stats_req_pending; + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION + uint32_t sta_stats_cached_timestamp; +#endif + +#ifdef FEATURE_MONITOR_MODE_SUPPORT + qdf_event_t qdf_monitor_mode_vdev_up_event; +#endif + + /* TODO: move these to sta ctx. These may not be used in AP */ + struct completion disconnect_comp_var; + struct completion linkup_event_var; + + bool is_link_up_service_needed; + + struct hdd_wmm_status hdd_wmm_status; + + /* TODO: Will be removed as a part of next phase of clean up */ + struct hdd_station_info sta_info[WLAN_MAX_STA_COUNT]; + struct hdd_station_info cache_sta_info[WLAN_MAX_STA_COUNT]; + + /* TODO: _list from name will be removed after clean up */ + struct hdd_sta_info_obj sta_info_list; + struct hdd_sta_info_obj cache_sta_info_list; + qdf_atomic_t cache_sta_count; + +#ifdef FEATURE_WLAN_WAPI + struct hdd_wapi_info wapi_info; +#endif + + struct work_struct sap_stop_bss_work; + +#ifdef WLAN_FEATURE_TSF + struct hdd_vdev_tsf tsf; +#endif + struct hdd_multicast_addr_list mc_addr_list; + qdf_spinlock_t mc_list_lock; + uint8_t addr_filter_pattern; + + struct hdd_scan_info scan_info; + + uint8_t psb_changed; + uint8_t configured_psb; + + struct work_struct scan_block_work; + qdf_list_t blocked_scan_request_q; + qdf_mutex_t blocked_scan_request_q_lock; + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_HL_NETDEV_FLOW_CONTROL) + qdf_mc_timer_t tx_flow_control_timer; + bool tx_flow_timer_initialized; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL || QCA_HL_NETDEV_FLOW_CONTROL */ +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL + unsigned int tx_flow_low_watermark; + unsigned int tx_flow_hi_watermark_offset; +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + enum sme_qos_wmmuptype dscp_to_up_map[WLAN_MAX_DSCP + 1]; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + bool is_link_layer_stats_set; + uint8_t ll_stats_failure_count; +#endif + uint8_t link_status; + uint8_t upgrade_udp_qos_threshold; + enum udp_qos_upgrade udp_qos_upgrade_type; + + int temperature; + +#ifdef WLAN_FEATURE_DSRC + struct qdf_mac_addr ocb_mac_address[QDF_MAX_CONCURRENCY_PERSONA]; + int ocb_mac_addr_count; +#endif + + uint32_t pause_map; + uint32_t subqueue_pause_map; + spinlock_t pause_map_lock; + qdf_time_t start_time; + qdf_time_t last_time; + qdf_time_t total_pause_time; + qdf_time_t total_unpause_time; + uint8_t history_index; + struct hdd_netif_queue_history + queue_oper_history[WLAN_HDD_MAX_HISTORY_ENTRY]; + struct hdd_netif_queue_stats queue_oper_stats[WLAN_REASON_TYPE_MAX]; + + struct dentry *debugfs_phy; + struct lfr_firmware_status lfr_fw_status; + uint8_t active_ac; + uint32_t mon_chan_freq; + uint32_t mon_bandwidth; + uint16_t latency_level; +#ifdef MULTI_CLIENT_LL_SUPPORT + bool multi_client_ll_support; + struct wlm_multi_client_info_table client_info[WLM_MAX_HOST_CLIENT]; + void *multi_ll_response_cookie; + bool multi_ll_req_in_progress; + bool multi_ll_resp_expected; +#endif +#ifdef FEATURE_MONITOR_MODE_SUPPORT + bool monitor_mode_vdev_up_in_progress; +#endif + + struct rcpi_info rcpi; + bool send_mode_change; +#ifdef FEATURE_WLAN_APF + struct hdd_apf_context apf_context; +#endif /* FEATURE_WLAN_APF */ + +#ifdef WLAN_DEBUGFS + struct hdd_debugfs_file_info csr_file[HDD_DEBUGFS_FILE_ID_MAX]; +#endif /* WLAN_DEBUGFS */ + +#ifdef WLAN_FEATURE_MOTION_DETECTION + bool motion_detection_mode; + bool motion_det_cfg; + bool motion_det_in_progress; + uint32_t motion_det_baseline_value; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + enum qca_disconnect_reason_codes last_disconnect_reason; + enum wlan_status_code connect_req_status; + qdf_event_t peer_cleanup_done; +#ifdef FEATURE_OEM_DATA + bool oem_data_in_progress; + void *cookie; + bool response_expected; +#endif + bool handle_feature_update; + + bool tso_csum_feature_enabled; + + qdf_work_t netdev_features_update_work; + enum hdd_work_status netdev_features_update_work_status; + qdf_atomic_t net_dev_hold_ref_count[NET_DEV_HOLD_ID_MAX]; + bool delete_in_progress; + bool is_virtual_iface; +#ifdef WLAN_FEATURE_PKT_CAPTURE + struct hdd_adapter *mon_adapter; +#endif +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) + struct hdd_mlo_adapter_info mlo_adapter_info; +#endif +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE + void *set_mac_addr_req_ctx; +#endif + int64_t delta_qtime; +#ifdef DP_TRAFFIC_END_INDICATION + bool traffic_end_ind_en; +#endif +#ifdef WLAN_FEATURE_DBAM_CONFIG + bool is_dbam_configured; +#endif + enum qca_wlan_vendor_phy_mode user_phy_mode; + struct wlan_hdd_link_info *deflink; + struct wlan_hdd_link_info link_info[WLAN_MAX_ML_BSS_LINKS]; + struct wlan_hdd_tx_power tx_power; +#ifdef WLAN_FEATURE_TX_LATENCY_STATS + struct cdp_tx_latency_config tx_latency_cfg; +#endif +#ifdef WLAN_FEATURE_11BE_MLO + qdf_time_t link_state_cached_timestamp; +#endif + uint16_t keep_alive_interval; +}; + +#define WLAN_HDD_GET_STATION_CTX_PTR(link_info) (&(link_info)->session.station) +#define WLAN_HDD_GET_AP_CTX_PTR(link_info) (&(link_info)->session.ap) +#define WLAN_HDD_GET_CTX(adapter) ((adapter)->hdd_ctx) +#define WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info) \ + (&(WLAN_HDD_GET_AP_CTX_PTR((link_info))->hostapd_state)) +#define WLAN_HDD_GET_SAP_CTX_PTR(link_info) \ + (WLAN_HDD_GET_AP_CTX_PTR((link_info))->sap_context) + +#ifdef WLAN_FEATURE_NAN +#define WLAN_HDD_IS_NDP_ENABLED(hdd_ctx) ((hdd_ctx)->nan_datapath_enabled) +#else +/* WLAN_HDD_GET_NDP_CTX_PTR and WLAN_HDD_GET_NDP_WEXT_STATE_PTR are not defined + * intentionally so that all references to these must be within NDP code. + * non-NDP code can call WLAN_HDD_IS_NDP_ENABLED(), and when it is enabled, + * invoke NDP code to do all work. + */ +#define WLAN_HDD_IS_NDP_ENABLED(hdd_ctx) (false) +#endif + +/* Set mac address locally administered bit */ +#define WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(macaddr) (macaddr[0] &= 0xFD) + +#define HDD_DEFAULT_MCC_P2P_QUOTA 70 +#define HDD_RESET_MCC_P2P_QUOTA 50 + +/* + * struct hdd_priv_data - driver ioctl private data payload + * @buf: pointer to command buffer (may be in userspace) + * @used_len: length of the command/data currently in @buf + * @total_len: total length of the @buf memory allocation + */ +struct hdd_priv_data { + uint8_t *buf; + int used_len; + int total_len; +}; + +#define MAX_MOD_LOGLEVEL 10 +struct fw_log_info { + uint8_t enable; + uint8_t dl_type; + uint8_t dl_report; + uint8_t dl_loglevel; + uint8_t index; + uint32_t dl_mod_loglevel[MAX_MOD_LOGLEVEL]; + +}; + +/** + * enum antenna_mode - number of TX/RX chains + * @HDD_ANTENNA_MODE_INVALID: Invalid mode place holder + * @HDD_ANTENNA_MODE_1X1: Number of TX/RX chains equals 1 + * @HDD_ANTENNA_MODE_2X2: Number of TX/RX chains equals 2 + * @HDD_ANTENNA_MODE_MAX: Place holder for max mode + */ +enum antenna_mode { + HDD_ANTENNA_MODE_INVALID, + HDD_ANTENNA_MODE_1X1, + HDD_ANTENNA_MODE_2X2, + HDD_ANTENNA_MODE_MAX +}; + +/** + * enum smps_mode - SM power save mode + * @HDD_SMPS_MODE_STATIC: Static power save + * @HDD_SMPS_MODE_DYNAMIC: Dynamic power save + * @HDD_SMPS_MODE_RESERVED: Reserved + * @HDD_SMPS_MODE_DISABLED: Disable power save + * @HDD_SMPS_MODE_MAX: Place holder for max mode + */ +enum smps_mode { + HDD_SMPS_MODE_STATIC, + HDD_SMPS_MODE_DYNAMIC, + HDD_SMPS_MODE_RESERVED, + HDD_SMPS_MODE_DISABLED, + HDD_SMPS_MODE_MAX +}; + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * struct hdd_offloaded_packets - request id to pattern id mapping + * @request_id: request id + * @pattern_id: pattern id + * + */ +struct hdd_offloaded_packets { + uint32_t request_id; + uint8_t pattern_id; +}; + +/** + * struct hdd_offloaded_packets_ctx - offloaded packets context + * @op_table: request id to pattern id table + * @op_lock: mutex lock + */ +struct hdd_offloaded_packets_ctx { + struct hdd_offloaded_packets op_table[MAXNUM_PERIODIC_TX_PTRNS]; + struct mutex op_lock; +}; +#endif + +/** + * enum driver_modules_status - Driver Modules status + * @DRIVER_MODULES_UNINITIALIZED: Driver CDS modules uninitialized + * @DRIVER_MODULES_ENABLED: Driver CDS modules opened + * @DRIVER_MODULES_CLOSED: Driver CDS modules closed + */ +enum driver_modules_status { + DRIVER_MODULES_UNINITIALIZED, + DRIVER_MODULES_ENABLED, + DRIVER_MODULES_CLOSED +}; + +/** + * struct acs_dfs_policy - Define ACS policies + * @acs_dfs_mode: Dfs mode enabled/disabled. + * @acs_chan_freq: pre defined channel frequency to avoid ACS. + */ +struct acs_dfs_policy { + enum dfs_mode acs_dfs_mode; + uint32_t acs_chan_freq; +}; + +/** + * enum suspend_fail_reason - Reasons a WLAN suspend might fail + * @SUSPEND_FAIL_IPA: IPA in progress + * @SUSPEND_FAIL_RADAR: radar scan in progress + * @SUSPEND_FAIL_ROAM: roaming in progress + * @SUSPEND_FAIL_SCAN: scan in progress + * @SUSPEND_FAIL_INITIAL_WAKEUP: received initial wakeup from firmware + * @SUSPEND_FAIL_MAX_COUNT: the number of wakeup reasons, always at the end + */ +enum suspend_fail_reason { + SUSPEND_FAIL_IPA, + SUSPEND_FAIL_RADAR, + SUSPEND_FAIL_ROAM, + SUSPEND_FAIL_SCAN, + SUSPEND_FAIL_INITIAL_WAKEUP, + SUSPEND_FAIL_MAX_COUNT +}; + +/** + * struct suspend_resume_stats - counters for suspend/resume events + * @suspends: number of suspends completed + * @resumes: number of resumes completed + * @suspend_fail: counters for failed suspend reasons + */ +struct suspend_resume_stats { + uint32_t suspends; + uint32_t resumes; + uint32_t suspend_fail[SUSPEND_FAIL_MAX_COUNT]; +}; + +/** + * enum hdd_sta_smps_param - SMPS parameters to configure from hdd + * @HDD_STA_SMPS_PARAM_UPPER_RSSI_THRESH: RSSI threshold to enter Dynamic SMPS + * mode from inactive mode + * @HDD_STA_SMPS_PARAM_STALL_RSSI_THRESH: RSSI threshold to enter + * Stalled-D-SMPS mode from D-SMPS mode or to enter D-SMPS mode from + * Stalled-D-SMPS mode + * @HDD_STA_SMPS_PARAM_LOWER_RSSI_THRESH: RSSI threshold to disable SMPS modes + * @HDD_STA_SMPS_PARAM_UPPER_BRSSI_THRESH: Upper threshold for beacon-RSSI. + * Used to reduce RX chainmask. + * @HDD_STA_SMPS_PARAM_LOWER_BRSSI_THRESH: Lower threshold for beacon-RSSI. + * Used to increase RX chainmask. + * @HDD_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE: Enable/Disable DTIM 1chRx feature + */ +enum hdd_sta_smps_param { + HDD_STA_SMPS_PARAM_UPPER_RSSI_THRESH = 0, + HDD_STA_SMPS_PARAM_STALL_RSSI_THRESH = 1, + HDD_STA_SMPS_PARAM_LOWER_RSSI_THRESH = 2, + HDD_STA_SMPS_PARAM_UPPER_BRSSI_THRESH = 3, + HDD_STA_SMPS_PARAM_LOWER_BRSSI_THRESH = 4, + HDD_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE = 5 +}; + +/** + * enum RX_OFFLOAD - Receive offload modes + * @CFG_LRO_ENABLED: Large Rx offload + * @CFG_GRO_ENABLED: Generic Rx Offload + */ +enum RX_OFFLOAD { + CFG_LRO_ENABLED = 1, + CFG_GRO_ENABLED, +}; + +/* One per STA: 1 for BCMC_STA_ID, 1 for each SAP_SELF_STA_ID, + * 1 for WDS_STAID + */ +#define HDD_MAX_ADAPTERS (WLAN_MAX_STA_COUNT + QDF_MAX_NO_OF_SAP_MODE + 2) + +#ifdef DISABLE_CHANNEL_LIST + +/** + * struct hdd_cache_channel_info - Structure of the channel info + * which needs to be cached + * @freq: frequency + * @reg_status: Current regulatory status of the channel + * Enable + * Disable + * DFS + * Invalid + * @wiphy_status: Current wiphy status + */ +struct hdd_cache_channel_info { + qdf_freq_t freq; + enum channel_state reg_status; + uint32_t wiphy_status; +}; + +/** + * struct hdd_cache_channels - Structure of the channels to be cached + * @num_channels: Number of channels to be cached + * @channel_info: Structure of the channel info + */ +struct hdd_cache_channels { + uint32_t num_channels; + struct hdd_cache_channel_info *channel_info; +}; +#endif + +/** + * struct hdd_dynamic_mac - hdd structure to handle dynamic mac address changes + * @dynamic_mac: Dynamically configured mac, this contains the mac on which + * current interface is up + * @is_provisioned_mac: is this mac from provisioned list + * @bit_position: holds the bit mask position from where this mac is assigned, + * if mac is assigned from provisioned this field contains the position from + * provisioned_intf_addr_mask else contains the position from + * derived_intf_addr_mask + */ +struct hdd_dynamic_mac { + struct qdf_mac_addr dynamic_mac; + bool is_provisioned_mac; + uint8_t bit_position; +}; + +/** + * struct hdd_fw_ver_info - FW version info structure + * @major_spid: FW version - major spid. + * @minor_spid: FW version - minor spid + * @siid: FW version - siid + * @sub_id: FW version - sub id + * @rel_id: FW version - release id + * @crmid: FW version - crmid + */ + +struct hdd_fw_ver_info { + uint32_t major_spid; + uint32_t minor_spid; + uint32_t siid; + uint32_t sub_id; + uint32_t rel_id; + uint32_t crmid; +}; + +/* + * The logic for get current index of history is dependent on this + * value being power of 2. + */ +#define WLAN_HDD_ADAPTER_OPS_HISTORY_MAX 4 +QDF_COMPILE_TIME_ASSERT(adapter_ops_history_size, + (WLAN_HDD_ADAPTER_OPS_HISTORY_MAX & + (WLAN_HDD_ADAPTER_OPS_HISTORY_MAX - 1)) == 0); + +/** + * enum hdd_adapter_ops_event - events for adapter ops history + * @WLAN_HDD_ADAPTER_OPS_WORK_POST: adapter ops work posted + * @WLAN_HDD_ADAPTER_OPS_WORK_SCHED: adapter ops work scheduled + */ +enum hdd_adapter_ops_event { + WLAN_HDD_ADAPTER_OPS_WORK_POST, + WLAN_HDD_ADAPTER_OPS_WORK_SCHED, +}; + +/** + * struct hdd_adapter_ops_record - record of adapter ops history + * @timestamp: time of the occurrence of event + * @event: event + * @vdev_id: vdev id corresponding to the event + */ +struct hdd_adapter_ops_record { + uint64_t timestamp; + enum hdd_adapter_ops_event event; + int vdev_id; +}; + +/** + * struct hdd_adapter_ops_history - history of adapter ops + * @index: index to store the next event + * @entry: array of events + */ +struct hdd_adapter_ops_history { + qdf_atomic_t index; + struct hdd_adapter_ops_record entry[WLAN_HDD_ADAPTER_OPS_HISTORY_MAX]; +}; + +/** + * struct hdd_dual_sta_policy - Concurrent STA policy configuration + * @dual_sta_policy: Possible values are defined in enum + * qca_wlan_concurrent_sta_policy_config + * @primary_vdev_id: specified iface is the primary STA iface, say 0 means + * vdev 0 is acting as primary interface + */ +struct hdd_dual_sta_policy { + uint8_t dual_sta_policy; + uint8_t primary_vdev_id; +}; + +#ifdef FEATURE_CNSS_HW_SECURE_DISABLE +/** + * hdd_get_wlan_driver_status() - get status of soft driver unload + * + * Return: true if wifi is disabled by soft driver unload, else false + */ +bool hdd_get_wlan_driver_status(void); +#else +static inline bool hdd_get_wlan_driver_status(void) +{ + return false; +} +#endif + +/** + * struct hdd_lpc_info - Local packet capture information + * @lpc_wk: local packet capture work + * @lpc_wk_scheduled: flag to indicate if lpc work is scheduled or not + * @mon_adapter: monitor adapter + */ +struct hdd_lpc_info { + qdf_work_t lpc_wk; + bool lpc_wk_scheduled; + struct hdd_adapter *mon_adapter; +}; + +/** + * enum wlan_state_ctrl_str_id - state control param string id + * @WLAN_OFF_STR: Turn OFF WiFi + * @WLAN_ON_STR: Turn ON WiFi + * @WLAN_ENABLE_STR: Enable WiFi + * @WLAN_DISABLE_STR: Disable Wifi + * @WLAN_WAIT_FOR_READY_STR: Driver should wait for ongoing recovery + * @WLAN_FORCE_DISABLE_STR: Disable Wifi by soft driver unload + */ +enum wlan_state_ctrl_str_id { + WLAN_OFF_STR = 0, + WLAN_ON_STR, + WLAN_ENABLE_STR, + WLAN_DISABLE_STR, + WLAN_WAIT_FOR_READY_STR, + WLAN_FORCE_DISABLE_STR +}; + +#define MAX_TGT_HW_NAME_LEN 32 + +/** + * struct hdd_context - hdd shared driver and psoc/device context + * @psoc: object manager psoc context + * @pdev: object manager pdev context + * @mac_handle: opaque handle to MAC context + * @wiphy: Linux wiphy + * @hdd_adapter_lock: lock for @hdd_adapters + * @hdd_adapters: list of all instantiated adapters + * @is_therm_cmd_supp: get temperature command enable or disable + * @fw: pointer to firmware image data + * @cfg: pointer to configuration data + * @parent_dev: pointer to parent device + * @config: Config values read from qcom_cfg.ini file + * @channels_2ghz: pointer for wiphy 2 GHz channels + * @channels_5ghz: pointer for wiphy 5 GHz channels + * @iftype_data_2g: Interface data for 2 GHz band + * @iftype_data_5g: Interface data for 5 GHz band + * @iftype_data_6g: Interface data for 6 GHz band + * @mc_sus_event_var: Completion variable to indicate Mc Thread Suspended + * @is_scheduler_suspended: true if the MC Thread is suspended + * @is_ol_rx_thread_suspended: true if the RX Thread is suspended + * @hdd_wlan_suspended: true if the HDD is suspended + * @suspended: unused??? + * @is_pktlog_enabled: true if pktlog is enabled, used to start pktlog after + * SSR/PDR if previously enabled + * @sap_lock: Lock to avoid race condition during start/stop bss + * @oem_app_registered: OEM App registered or not + * @oem_pid: OEM App Process ID when registered + * @concurrency_mode: Concurrency Parameters + * @no_of_open_sessions: number of open sessions per operating mode + * @no_of_active_sessions: number of active sessions per operating mode + * @p2p_device_address: P2P Device MAC Address for the adapter + * @sap_wake_lock: Soft AP wakelock + * @is_wiphy_suspended: Flag keeps track of wiphy suspend/resume + * @ready_to_suspend: completed when ready to suspend + * @target_type: defining the solution type + * @target_fw_version: firmware version + * @target_fw_vers_ext: firmware version extension + * @fw_version_info: detailed firmware version information + * @target_hw_version: the chip/rom version + * @target_hw_revision: the chip/rom revision + * @target_hw_name: chip/rom name + * @reg: regulatory information + * @unsafe_channel_count: number of unsafe channels + * @unsafe_channel_list: list of unsafe channels + * @restriction_mask: channel avoidance restrictions mask + * @max_intf_count: maximum number of supported interfaces + * @lpss_support: Is LPSS offload supported + * @ap_arpns_support: Is AP ARP/NS offload supported + * @ioctl_scan_mode: scan mode + * @sta_ap_intf_check_work: workqueue for interface check + * @dev_dfs_cac_status: DFS CAC status + * @bt_coex_mode_set: Has BT coex mode been set + * @skip_acs_scan_timer: timer used to skip ACS scan + * @skip_acs_scan_status: status of skip ACS scan + * @last_acs_freq_list: ACS frequency list + * @num_of_channels: number of channels in @last_acs_freq_list + * @acs_skip_lock: use to synchronize "skip ACS scan" feature + * @sap_dfs_wakelock : SAP DFS wakelock + * @sap_dfs_ref_cnt: SAP DFS reference count + * @is_extwow_app_type1_param_set: is extwow app type1 param set + * @is_extwow_app_type2_param_set: is extwow app type2 param set + * @ext_scan_start_since_boot: Time since boot up to extscan start (in micro + * seconds) + * @miracast_value: value of driver miracast command + * @ipv6_notifier: IPv6 notifier callback for handling NS offload on change + * in IP + * @ns_offload_enable: Is NS offload enabled + * @ipv4_notifier: IPv4 notifier callback for handling ARP offload on change + * in IP + * @pm_qos_notifier: Device PM QoS notifier + * @runtime_pm_prevented: Is PM prevented + * @pm_qos_lock: Lock for PM QoS data + * @num_rf_chains: number of rf chains supported by target + * @ht_tx_stbc_supported: Is HT Tx STBC supported by target + * @op_ctx: Offloaded packets context + * @mcc_mode: Is Multi-channel Concurrency enabled + * @memdump_lock: Lock for memdump data + * @driver_dump_size: Size of the memdump data buffer + * @driver_dump_mem: memdump data buffer + * @connection_in_progress: Is connection in progress + * @connection_status_lock: Lock for connection status + * @fine_time_meas_cap_target: place to store FTM capab of target. This + * allows changing of FTM capab at runtime + * and intersecting it with target capab before + * updating. + * @current_antenna_mode: Current number of TX X RX chains being used + * @radio_index: the radio index assigned by cnss_logger + * @hbw_requested: Has high bandwidth been requested + * @pm_qos_request: Is PM QoS requested + * @nan_datapath_enabled: Is NAN datapath enabled + * @driver_status: Present state of driver cds modules + * @psoc_idle_timeout_work: delayed work for psoc idle shutdown + * @pm_notifier: PM notifier of hdd modules + * @acs_policy: ACS DFS policy + * @wmi_max_len: MTU of the WMI interface + * @suspend_resume_stats: Suspend/Resume statistics + * @runtime_context: Runtime PM context + * @chan_info: scan channel information + * @chan_info_lock: lock for @chan_info + * @tdls_source_bitmap: bit map to set/reset TDLS by different sources + * @tdls_umac_comp_active: Is the TDLS component active + * @tdls_nap_active: Is napier specific tdls data path enabled + * @beacon_probe_rsp_cnt_per_scan: + * @last_scan_reject_vdev_id: + * @last_scan_reject_reason: + * @last_scan_reject_timestamp: + * @scan_reject_cnt: + * @dfs_cac_offload: + * @reg_offload: + * @rcpi_enabled: + * @coex_avoid_freq_list: + * @dnbs_avoid_freq_list: + * @avoid_freq_lock: Lock to control access to dnbs and coex avoid freq list + * @tsf: structure containing tsf related information + * @bt_a2dp_active: + * @bt_vo_active: + * @bt_profile_con: + * @curr_band: + * @imps_enabled: + * @user_configured_pkt_filter_rules: + * @is_fils_roaming_supported: + * @receive_offload_cb: + * @vendor_disable_lro_flag: + * @force_rsne_override: + * @monitor_mode_wakelock: + * @lte_coex_ant_share: + * @obss_scan_offload: + * @sscan_pid: + * @track_arp_ip: + * @hw_bd_id: defining the board related information + * @hw_bd_info: + * @twt_state: + * @twt_disable_comp_evt: + * @twt_enable_comp_evt: + * @apf_version: + * @apf_enabled_v2: + * @original_channels: + * @cache_channel_lock: + * @sar_version: + * @dynamic_mac_list: + * @dynamic_nss_chains_support: Per vdev dynamic nss chains update capability + * @hw_macaddr: + * @provisioned_mac_addr: + * @derived_mac_addr: + * @num_provisioned_addr: + * @num_derived_addr: + * @provisioned_intf_addr_mask: + * @derived_intf_addr_mask: + * @sar_cmd_params: SAR command params to be configured to the FW + * @sar_safety_timer: + * @sar_safety_unsolicited_work: + * @sar_safety_req_resp_event: + * @sar_safety_req_resp_event_in_progress: + * @runtime_resume_start_time_stamp: + * @runtime_suspend_done_time_stamp: + * @pm_qos_req: + * @qos_cpu_mask: voted cpu core mask + * @pm_qos_req: pm_qos request for all cpu cores + * @roam_ch_from_fw_supported: + * @dutycycle_off_percent: + * @pm_qos_request_flags: + * @country_change_work: work for updating vdev when country changes + * @current_pcie_gen_speed: current pcie gen speed + * @adapter_ops_wq: High priority workqueue for handling adapter operations + * @adapter_ops_history: + * @ll_stats_per_chan_rx_tx_time: + * @is_get_station_clubbed_in_ll_stats_req: + * @multi_client_thermal_mitigation: Multi client thermal mitigation by fw + * @is_dual_mac_cfg_updated: indicate whether dual mac cfg has been updated + * @is_regulatory_update_in_progress: + * @regulatory_update_event: + * @regulatory_status_lock: + * @is_fw_dbg_log_levels_configured: + * @twt_en_dis_work: work to send twt enable/disable cmd on MCC/SCC concurrency + * @is_wifi3_0_target: + * @dump_in_progress: Stores value of dump in progress + * @dual_sta_policy: Concurrent STA policy configuration + * @is_therm_stats_in_progress: + * @is_vdev_macaddr_dynamic_update_supported: + * @power_type: + * @is_wlan_disabled: if wlan is disabled by userspace + * @oem_data: + * @oem_data_len: + * @file_name: + * @dbam_mode: + * @last_pagefault_ssr_time: Time when last recovery was triggered because of + * @host wakeup from fw with reason as pagefault + * @bridgeaddr: Bridge MAC address + * @is_mlo_per_link_stats_supported: Per link mlo stats is supported or not + * @num_mlo_peers: Total number of MLO peers + * @more_peer_data: more mlo peer data in peer stats + * @lpc_info: Local packet capture info + */ +struct hdd_context { + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + mac_handle_t mac_handle; + struct wiphy *wiphy; + qdf_spinlock_t hdd_adapter_lock; + qdf_list_t hdd_adapters; + bool is_therm_cmd_supp; + const struct firmware *fw; + const struct firmware *cfg; + struct device *parent_dev; + struct hdd_config *config; + + /* Pointer for wiphy 2G/5G band channels */ + struct ieee80211_channel *channels_2ghz; + struct ieee80211_channel *channels_5ghz; + +#if defined(WLAN_FEATURE_11AX) && \ + (defined(CFG80211_SBAND_IFTYPE_DATA_BACKPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))) + struct ieee80211_sband_iftype_data *iftype_data_2g; + struct ieee80211_sband_iftype_data *iftype_data_5g; +#if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \ + (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)) + struct ieee80211_sband_iftype_data *iftype_data_6g; +#endif +#endif + struct completion mc_sus_event_var; + bool is_scheduler_suspended; + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + bool is_ol_rx_thread_suspended; +#endif + + bool hdd_wlan_suspended; + bool suspended; + bool is_pktlog_enabled; + struct mutex sap_lock; + +#ifdef FEATURE_OEM_DATA_SUPPORT + bool oem_app_registered; + int32_t oem_pid; +#endif + + uint32_t concurrency_mode; + + uint8_t no_of_open_sessions[QDF_MAX_NO_OF_MODE]; + uint8_t no_of_active_sessions[QDF_MAX_NO_OF_MODE]; + struct qdf_mac_addr p2p_device_address; + qdf_wake_lock_t sap_wake_lock; + bool is_wiphy_suspended; + struct completion ready_to_suspend; + uint32_t target_type; + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; + struct hdd_fw_ver_info fw_version_info; + uint32_t target_hw_version; + uint32_t target_hw_revision; + char target_hw_name[MAX_TGT_HW_NAME_LEN]; + struct regulatory reg; +#ifdef FEATURE_WLAN_CH_AVOID + uint16_t unsafe_channel_count; + uint16_t unsafe_channel_list[NUM_CHANNELS]; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_CH_AVOID_EXT + uint32_t restriction_mask; +#endif + + uint8_t max_intf_count; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; + tSirScanType ioctl_scan_mode; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + qdf_work_t sta_ap_intf_check_work; +#endif + + uint8_t dev_dfs_cac_status; + + bool bt_coex_mode_set; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + qdf_mc_timer_t skip_acs_scan_timer; + uint8_t skip_acs_scan_status; + uint32_t *last_acs_freq_list; + uint8_t num_of_channels; + qdf_spinlock_t acs_skip_lock; +#endif + + qdf_wake_lock_t sap_dfs_wakelock; + atomic_t sap_dfs_ref_cnt; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + bool is_extwow_app_type1_param_set; + bool is_extwow_app_type2_param_set; +#endif + + uint64_t ext_scan_start_since_boot; + uint8_t miracast_value; + +#ifdef WLAN_NS_OFFLOAD + /* IPv6 notifier callback for handling NS offload on change in IP */ + struct notifier_block ipv6_notifier; +#endif + bool ns_offload_enable; + /* IPv4 notifier callback for handling ARP offload on change in IP */ + struct notifier_block ipv4_notifier; + +#ifdef FEATURE_RUNTIME_PM + struct notifier_block pm_qos_notifier; + bool runtime_pm_prevented; + qdf_spinlock_t pm_qos_lock; +#endif + uint32_t num_rf_chains; + uint8_t ht_tx_stbc_supported; +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + struct hdd_offloaded_packets_ctx op_ctx; +#endif + bool mcc_mode; + struct mutex memdump_lock; + uint16_t driver_dump_size; + uint8_t *driver_dump_mem; + + bool connection_in_progress; + qdf_spinlock_t connection_status_lock; + + uint32_t fine_time_meas_cap_target; + enum antenna_mode current_antenna_mode; + + int radio_index; + bool hbw_requested; + bool pm_qos_request; +#ifdef WLAN_FEATURE_NAN + bool nan_datapath_enabled; +#endif + enum driver_modules_status driver_status; + struct qdf_delayed_work psoc_idle_timeout_work; + struct notifier_block pm_notifier; + struct acs_dfs_policy acs_policy; + uint16_t wmi_max_len; + struct suspend_resume_stats suspend_resume_stats; + struct hdd_runtime_pm_context runtime_context; + struct scan_chan_info *chan_info; + struct mutex chan_info_lock; + unsigned long tdls_source_bitmap; + bool tdls_umac_comp_active; + bool tdls_nap_active; + uint8_t beacon_probe_rsp_cnt_per_scan; + uint8_t last_scan_reject_vdev_id; + enum scan_reject_states last_scan_reject_reason; + unsigned long last_scan_reject_timestamp; + uint8_t scan_reject_cnt; + bool dfs_cac_offload; + bool reg_offload; + bool rcpi_enabled; +#ifdef FEATURE_WLAN_CH_AVOID + struct ch_avoid_ind_type coex_avoid_freq_list; + struct ch_avoid_ind_type dnbs_avoid_freq_list; + /* Lock to control access to dnbs and coex avoid freq list */ + struct mutex avoid_freq_lock; +#endif +#ifdef WLAN_FEATURE_TSF + struct hdd_ctx_tsf tsf; +#endif + + uint8_t bt_a2dp_active:1; + uint8_t bt_vo_active:1; + uint8_t bt_profile_con:1; + enum band_info curr_band; + bool imps_enabled; +#ifdef WLAN_FEATURE_PACKET_FILTERING + int user_configured_pkt_filter_rules; +#endif + bool is_fils_roaming_supported; + QDF_STATUS (*receive_offload_cb)(struct hdd_adapter *, + struct sk_buff *); + qdf_atomic_t vendor_disable_lro_flag; + bool force_rsne_override; + qdf_wake_lock_t monitor_mode_wakelock; + bool lte_coex_ant_share; + bool obss_scan_offload; + int sscan_pid; + uint32_t track_arp_ip; + + /* defining the board related information */ + uint32_t hw_bd_id; + struct board_info hw_bd_info; +#ifdef WLAN_SUPPORT_TWT + enum twt_status twt_state; + qdf_event_t twt_disable_comp_evt; + qdf_event_t twt_enable_comp_evt; +#endif +#ifdef FEATURE_WLAN_APF + uint32_t apf_version; + bool apf_enabled_v2; +#endif + +#ifdef DISABLE_CHANNEL_LIST + struct hdd_cache_channels *original_channels; + qdf_mutex_t cache_channel_lock; +#endif + enum sar_version sar_version; + struct hdd_dynamic_mac dynamic_mac_list[QDF_MAX_CONCURRENCY_PERSONA]; + bool dynamic_nss_chains_support; + struct qdf_mac_addr hw_macaddr; + struct qdf_mac_addr provisioned_mac_addr[QDF_MAX_CONCURRENCY_PERSONA]; + struct qdf_mac_addr derived_mac_addr[QDF_MAX_CONCURRENCY_PERSONA]; + uint32_t num_provisioned_addr; + uint32_t num_derived_addr; + unsigned long provisioned_intf_addr_mask; + unsigned long derived_intf_addr_mask; + + struct sar_limit_cmd_params *sar_cmd_params; +#ifdef SAR_SAFETY_FEATURE + qdf_mc_timer_t sar_safety_timer; + struct qdf_delayed_work sar_safety_unsolicited_work; + qdf_event_t sar_safety_req_resp_event; + qdf_atomic_t sar_safety_req_resp_event_in_progress; +#endif + + qdf_time_t runtime_resume_start_time_stamp; + qdf_time_t runtime_suspend_done_time_stamp; +#if defined(CLD_PM_QOS) && defined(CLD_DEV_PM_QOS) + struct dev_pm_qos_request pm_qos_req[NR_CPUS]; + struct cpumask qos_cpu_mask; +#elif defined(CLD_PM_QOS) + struct pm_qos_request pm_qos_req; +#endif + bool roam_ch_from_fw_supported; +#ifdef FW_THERMAL_THROTTLE_SUPPORT + uint8_t dutycycle_off_percent; +#endif + uint8_t pm_qos_request_flags; + qdf_work_t country_change_work; + int current_pcie_gen_speed; + qdf_workqueue_t *adapter_ops_wq; + struct hdd_adapter_ops_history adapter_ops_history; + bool ll_stats_per_chan_rx_tx_time; +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION + bool is_get_station_clubbed_in_ll_stats_req; +#endif +#ifdef FEATURE_WPSS_THERMAL_MITIGATION + bool multi_client_thermal_mitigation; +#endif + bool is_dual_mac_cfg_updated; + bool is_regulatory_update_in_progress; + qdf_event_t regulatory_update_event; + qdf_mutex_t regulatory_status_lock; + bool is_fw_dbg_log_levels_configured; +#ifdef WLAN_SUPPORT_TWT + qdf_work_t twt_en_dis_work; +#endif + bool is_wifi3_0_target; + bool dump_in_progress; + struct hdd_dual_sta_policy dual_sta_policy; +#ifdef THERMAL_STATS_SUPPORT + bool is_therm_stats_in_progress; +#endif +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE + bool is_vdev_macaddr_dynamic_update_supported; +#endif +#ifdef CONFIG_WLAN_FREQ_LIST + uint8_t power_type; +#endif + bool is_wlan_disabled; + + uint8_t oem_data[HDD_MAX_OEM_DATA_LEN]; + uint8_t oem_data_len; + uint8_t file_name[HDD_MAX_FILE_NAME_LEN]; +#ifdef WLAN_FEATURE_DBAM_CONFIG + enum coex_dbam_config_mode dbam_mode; +#endif + qdf_time_t last_pagefault_ssr_time; + uint8_t bridgeaddr[QDF_MAC_ADDR_SIZE]; +#ifdef WLAN_FEATURE_11BE_MLO + bool is_mlo_per_link_stats_supported; + uint8_t num_mlo_peers; + uint32_t more_peer_data; +#endif +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE + struct hdd_lpc_info lpc_info; +#endif +}; + +/** + * struct hdd_vendor_acs_chan_params - vendor acs channel parameters + * @pcl_count: pcl list count + * @vendor_pcl_list: pointer to pcl frequency (MHz) list + * @vendor_weight_list: pointer to pcl weight list + */ +struct hdd_vendor_acs_chan_params { + uint32_t pcl_count; + uint32_t *vendor_pcl_list; + uint8_t *vendor_weight_list; +}; + +/** + * struct hdd_external_acs_timer_context - acs timer context + * @reason: reason for acs trigger + * @adapter: hdd adapter for acs + */ +struct hdd_external_acs_timer_context { + int8_t reason; + struct hdd_adapter *adapter; +}; + +/** + * struct hdd_vendor_chan_info - vendor channel info + * @band: channel operating band + * @pri_chan_freq: primary channel freq in MHz + * @ht_sec_chan_freq: secondary channel freq in MHz + * @vht_seg0_center_chan_freq: segment0 for vht in MHz + * @vht_seg1_center_chan_freq: vht segment 1 in MHz + * @chan_width: channel width + */ +struct hdd_vendor_chan_info { + uint8_t band; + uint32_t pri_chan_freq; + uint32_t ht_sec_chan_freq; + uint32_t vht_seg0_center_chan_freq; + uint32_t vht_seg1_center_chan_freq; + uint8_t chan_width; +}; + +/** + * struct hdd_channel_info - standard channel info + * @freq: Freq in Mhz + * @flags: channel info flags + * @flagext: extended channel info flags + * @ieee_chan_number: channel number + * @max_reg_power: max tx power according to regulatory + * @max_radio_power: max radio power + * @min_radio_power: min radio power + * @reg_class_id: regulatory class + * @max_antenna_gain: max antenna gain allowed on channel + * @vht_center_freq_seg0: vht center freq segment 0 + * @vht_center_freq_seg1: vht center freq segment 1 + */ +struct hdd_channel_info { + u_int16_t freq; + u_int32_t flags; + u_int16_t flagext; + u_int8_t ieee_chan_number; + int8_t max_reg_power; + int8_t max_radio_power; + int8_t min_radio_power; + u_int8_t reg_class_id; + u_int8_t max_antenna_gain; + u_int8_t vht_center_freq_seg0; + u_int8_t vht_center_freq_seg1; +}; + +/** + * struct hdd_chwidth_info - channel width related info + * @sir_chwidth_valid: If nl_chan_width is valid in Sir + * @sir_chwidth: enum eSirMacHTChannelWidth + * @ch_bw: enum hw_mode_bandwidth + * @ch_bw_str: ch_bw in string format + * @phy_chwidth: enum phy_ch_width + * @bonding_mode: WNI_CFG_CHANNEL_BONDING_MODE_DISABLE or + * WNI_CFG_CHANNEL_BONDING_MODE_ENABLE + */ +struct hdd_chwidth_info { + bool sir_chwidth_valid; + enum eSirMacHTChannelWidth sir_chwidth; + enum hw_mode_bandwidth ch_bw; + char *ch_bw_str; + enum phy_ch_width phy_chwidth; + int bonding_mode; +}; + +/** + * struct mac_addr_set_priv: Set MAC addr private context + * @fw_resp_status: F/W response status + * @pending_rsp_cnt: Pending response count + */ +struct mac_addr_set_priv { + uint32_t fw_resp_status; + qdf_atomic_t pending_rsp_cnt; +}; + +/* + * Function declarations and documentation + */ + +/** + * wlan_hdd_history_get_next_index() - get next index to store the history + * entry + * @curr_idx: current index + * @max_entries: max entries in the history + * + * Returns: The index at which record is to be stored in history + */ +static inline uint32_t wlan_hdd_history_get_next_index(qdf_atomic_t *curr_idx, + uint32_t max_entries) +{ + uint32_t idx = qdf_atomic_inc_return(curr_idx); + + return idx & (max_entries - 1); +} + +/** + * hdd_adapter_ops_record_event() - record an entry in the adapter ops history + * @hdd_ctx: pointer to hdd context + * @event: event + * @vdev_id: vdev id corresponding to event + * + * Returns: None + */ +static inline void +hdd_adapter_ops_record_event(struct hdd_context *hdd_ctx, + enum hdd_adapter_ops_event event, + int vdev_id) +{ + struct hdd_adapter_ops_history *adapter_hist; + struct hdd_adapter_ops_record *record; + uint32_t idx; + + adapter_hist = &hdd_ctx->adapter_ops_history; + + idx = wlan_hdd_history_get_next_index(&adapter_hist->index, + WLAN_HDD_ADAPTER_OPS_HISTORY_MAX); + + record = &adapter_hist->entry[idx]; + record->event = event; + record->vdev_id = vdev_id; + record->timestamp = qdf_get_log_timestamp(); +} + +/** + * hdd_validate_channel_and_bandwidth() - Validate the channel-bandwidth combo + * @adapter: HDD adapter + * @chan_freq: Channel frequency + * @chan_bw: Bandwidth + * + * Checks if the given bandwidth is valid for the given channel number. + * + * Return: 0 for success, non-zero for failure + */ +int hdd_validate_channel_and_bandwidth(struct hdd_adapter *adapter, + qdf_freq_t chan_freq, + enum phy_ch_width chan_bw); + +/** + * hdd_get_front_adapter() - Get the first adapter from the adapter list + * @hdd_ctx: pointer to the HDD context + * @out_adapter: double pointer to pass the next adapter + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_front_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter); + +/** + * hdd_get_next_adapter() - Get the next adapter from the adapter list + * @hdd_ctx: pointer to the HDD context + * @current_adapter: pointer to the current adapter + * @out_adapter: double pointer to pass the next adapter + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_next_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *current_adapter, + struct hdd_adapter **out_adapter); + +/** + * hdd_get_front_adapter_no_lock() - Get the first adapter from the adapter list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * @hdd_ctx: pointer to the HDD context + * @out_adapter: double pointer to pass the next adapter + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_front_adapter_no_lock(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter); + +/** + * hdd_get_next_adapter_no_lock() - Get the next adapter from the adapter list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * @hdd_ctx: pointer to the HDD context + * @current_adapter: pointer to the current adapter + * @out_adapter: double pointer to pass the next adapter + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_next_adapter_no_lock(struct hdd_context *hdd_ctx, + struct hdd_adapter *current_adapter, + struct hdd_adapter **out_adapter); + +/** + * hdd_remove_adapter() - Remove the adapter from the adapter list + * @hdd_ctx: pointer to the HDD context + * @adapter: pointer to the adapter to be removed + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_remove_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * hdd_remove_front_adapter() - Remove the first adapter from the adapter list + * @hdd_ctx: pointer to the HDD context + * @out_adapter: pointer to the adapter to be removed + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_remove_front_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter); + +/** + * hdd_add_adapter_back() - Add an adapter to the adapter list + * @hdd_ctx: pointer to the HDD context + * @adapter: pointer to the adapter to be added + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_add_adapter_back(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * hdd_add_adapter_front() - Add an adapter to the head of the adapter list + * @hdd_ctx: pointer to the HDD context + * @adapter: pointer to the adapter to be added + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_add_adapter_front(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * typedef hdd_adapter_iterate_cb() - Iteration callback function + * @link_info: Link info pointer in HDD adapter + * @context: user context supplied to the iterator + * + * This specifies the type of a callback function to supply to + * hdd_adapter_iterate(). + * + * Return: + * * QDF_STATUS_SUCCESS if further iteration should continue + * * QDF_STATUS_E_ABORTED if further iteration should be aborted + */ +typedef QDF_STATUS +(*hdd_adapter_iterate_cb)(struct wlan_hdd_link_info *link_info, void *context); + +/** + * hdd_adapter_iterate() - Safely iterate over all adapters + * @cb: callback function to invoke for each adapter + * @context: user-supplied context to pass to @cb + * + * This function will iterate over all of the adapters known to the system in + * a safe manner, invoking the callback function for each adapter. + * The callback function will be invoked in the same context/thread as the + * caller without any additional locks in force. + * Iteration continues until either the callback has been invoked for all + * adapters or a callback returns a value of QDF_STATUS_E_ABORTED to indicate + * that further iteration should cease. + * + * Return: + * * QDF_STATUS_E_ABORTED if any callback function returns that value + * * QDF_STATUS_E_FAILURE if the callback was not invoked for all adapters due + * to concurrency (i.e. adapter was deleted while iterating) + * * QDF_STATUS_SUCCESS if @cb was invoked for each adapter and none returned + * an error + */ +QDF_STATUS hdd_adapter_iterate(hdd_adapter_iterate_cb cb, + void *context); + +/** + * hdd_adapter_dev_hold_debug - Debug API to call dev_hold + * @adapter: hdd_adapter pointer + * @dbgid: Debug ID corresponding to API that is requesting the dev_hold + * + * Return: none + */ +void hdd_adapter_dev_hold_debug(struct hdd_adapter *adapter, + wlan_net_dev_ref_dbgid dbgid); + +/** + * hdd_adapter_dev_put_debug - Debug API to call dev_put + * @adapter: hdd_adapter pointer + * @dbgid: Debug ID corresponding to API that is requesting the dev_put + * + * Return: none + */ +void hdd_adapter_dev_put_debug(struct hdd_adapter *adapter, + wlan_net_dev_ref_dbgid dbgid); + +/** + * hdd_validate_next_adapter - API to check for infinite loop + * in the adapter list traversal + * @curr: current adapter pointer + * @next: next adapter pointer + * @dbg_id: Debug ID corresponding to API that is requesting the dev_put + * + * Return: None + */ +void hdd_validate_next_adapter(struct hdd_adapter **curr, + struct hdd_adapter **next, + wlan_net_dev_ref_dbgid dbg_id); + +/** + * __hdd_take_ref_and_fetch_front_adapter_safe - Helper macro to lock, fetch + * front and next adapters, take ref and unlock. + * @hdd_ctx: the global HDD context + * @adapter: an hdd_adapter pointer to use as a cursor + * @next_adapter: hdd_adapter pointer to next adapter + * @dbgid: debug ID to detect reference leaks + */ +#define __hdd_take_ref_and_fetch_front_adapter_safe(hdd_ctx, adapter, \ + next_adapter, dbgid) \ + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock), \ + hdd_get_front_adapter_no_lock(hdd_ctx, &adapter), \ + (adapter) ? hdd_adapter_dev_hold_debug(adapter, dbgid) : (false), \ + hdd_get_next_adapter_no_lock(hdd_ctx, adapter, &next_adapter), \ + (next_adapter) ? hdd_adapter_dev_hold_debug(next_adapter, dbgid) : \ + (false), \ + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock) + +/** + * __hdd_take_ref_and_fetch_next_adapter_safe - Helper macro to lock, fetch next + * adapter, take ref and unlock. + * @hdd_ctx: the global HDD context + * @adapter: hdd_adapter pointer to use as a cursor + * @next_adapter: hdd_adapter pointer to next adapter + * @dbgid: debug ID to detect reference leaks + */ +#define __hdd_take_ref_and_fetch_next_adapter_safe(hdd_ctx, adapter, \ + next_adapter, dbgid) \ + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock), \ + adapter = next_adapter, \ + hdd_get_next_adapter_no_lock(hdd_ctx, adapter, &next_adapter), \ + hdd_validate_next_adapter(&adapter, &next_adapter, dbgid), \ + (next_adapter) ? hdd_adapter_dev_hold_debug(next_adapter, dbgid) : \ + (false), \ + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock) + +/** + * __hdd_is_adapter_valid - Helper macro to return true/false for valid adapter. + * @_adapter: an hdd_adapter pointer to use as a cursor + */ +#define __hdd_is_adapter_valid(_adapter) !!_adapter + +/** + * hdd_for_each_adapter_dev_held_safe - Adapter iterator with dev_hold called + * in a delete safe manner + * @hdd_ctx: the global HDD context + * @adapter: an hdd_adapter pointer to use as a cursor + * @next_adapter: hdd_adapter pointer to the next adapter + * @dbgid: reference count debugging id + * + * This iterator will take the reference of the netdev associated with the + * given adapter so as to prevent it from being removed in other context. It + * also takes the reference of the next adapter if exist. This avoids infinite + * loop due to deletion of the adapter list entry inside the loop. Deletion of + * list entry will make the list entry to point to self. If the control goes + * inside the loop body then the dev_hold has been invoked. + * + * ***** NOTE ***** + * Before the end of each iteration, hdd_adapter_dev_put_debug(adapter, dbgid) + * must be called. Not calling this will keep hold of a reference, thus + * preventing unregister of the netdevice. If the loop is terminated in + * between with return/goto/break statements, + * hdd_adapter_dev_put_debug(next_adapter, dbgid) must be done along with + * hdd_adapter_dev_put_debug(adapter, dbgid) before termination of the loop. + * + * Usage example: + * hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, dbgid) { + * + * + * hdd_adapter_dev_put_debug(adapter, dbgid) + * } + */ +#define hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, \ + dbgid) \ + for (__hdd_take_ref_and_fetch_front_adapter_safe(hdd_ctx, adapter, \ + next_adapter, dbgid); \ + __hdd_is_adapter_valid(adapter); \ + __hdd_take_ref_and_fetch_next_adapter_safe(hdd_ctx, adapter, \ + next_adapter, dbgid)) + +/* Helper MACROS and APIs definition to iterate + * link info array in HDD adapter. + */ +#define __hdd_adapter_is_active_link(adapter, link_idx) \ + qdf_atomic_test_bit(link_idx, &(adapter)->active_links) + +#define hdd_adapter_get_link_info_if_active(adapter, link_idx) \ + __hdd_adapter_is_active_link((adapter), (link_idx)) ? \ + &((adapter)->link_info[(link_idx)]) : NULL + +#define __hdd_is_link_info_valid(_link_info) !!_link_info + +#define __hdd_adapter_get_first_active_link_info(adapter, link_info) \ + link_info = NULL, \ + hdd_adapter_get_next_active_link_info(adapter, &link_info) + + +static inline uint8_t +hdd_adapter_get_index_of_link_info(struct wlan_hdd_link_info *link_info) +{ + return (link_info - &link_info->adapter->link_info[0]); +} + +static inline void +hdd_adapter_get_next_active_link_info(struct hdd_adapter *adapter, + struct wlan_hdd_link_info **link_info) +{ + uint8_t link_idx = WLAN_HDD_DEFLINK_IDX; + uint8_t link_idx_max; + + if (!link_info || !adapter) + return; + + /* If @link_info already points to valid link info address, get the + * index of that link info and get the next valid link info which is + * set to active. + * If @link_info points to invalid address, then start the search + * for active link info from WLAN_HDD_DEFLINK_IDX index. + */ + if (*link_info) + link_idx = hdd_adapter_get_index_of_link_info(*link_info) + 1; + + *link_info = NULL; + link_idx_max = QDF_ARRAY_SIZE(adapter->link_info); + while (link_idx < link_idx_max && !(*link_info)) { + *link_info = hdd_adapter_get_link_info_if_active(adapter, + link_idx); + link_idx++; + } +} + +/** + * hdd_adapter_for_each_active_link_info() - Link info iterator which loops + * through the link info array elements which are set to active. + * @adapter: HDD adapter to iterate for each active link info pointer. + * @link_info: Pointer of active link info. + * + * The "active_links" bitmap in @adapter says which indices are active + * in the link info array. + * The MACRO iterates through all the active link info elements in link info + * array and ends loop when no more active link info entries are present. + * The @link_info points next active link info pointer on each iteration or + * NULL value at the end of the loop. + * + * Callers to take reference of adapter if needed. + */ +#define hdd_adapter_for_each_active_link_info(adapter, link_info) \ + for (__hdd_adapter_get_first_active_link_info(adapter, link_info); \ + __hdd_is_link_info_valid(link_info); \ + hdd_adapter_get_next_active_link_info(adapter, &link_info)) + +#define __hdd_adapter_get_firstlink(adapter, __link_info) \ + (__link_info = adapter ? &((adapter)->link_info[0]) : NULL) + +#define __hdd_is_link_info_idx_valid(adapter, __link_info) \ + ((__link_info - &(adapter)->link_info[0]) < \ + QDF_ARRAY_SIZE((adapter)->link_info)) + +#define __hdd_adapter_next_link_info(link_info) ((link_info)++) + +/** + * hdd_adapter_for_each_link_info() - Link info iterator for all + * link_info fields. + * @adapter: HDD adapter to iterate each link_info. + * @link_info: Pointer to each link info element in the array. + * + * The function iterates from the start index of link_info array + * in @adapter till the end of the link_info array. + * + * Callers to take reference of adapter if needed. + */ + +#define hdd_adapter_for_each_link_info(adapter, link_info) \ + for (__hdd_adapter_get_firstlink(adapter, link_info); \ + __hdd_is_link_info_valid(link_info) && \ + __hdd_is_link_info_idx_valid(adapter, link_info); \ + __hdd_adapter_next_link_info(link_info)) + +/** + * wlan_hdd_get_link_info_from_objmgr() - Fetch adapter from objmgr + * @vdev: the vdev whose corresponding adapter has to be fetched + * + * Return: Address of link info pointer in HDD adapter corresponding to VDEV + */ +struct wlan_hdd_link_info * +wlan_hdd_get_link_info_from_objmgr(struct wlan_objmgr_vdev *vdev); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +/** + * hdd_adapter_disable_all_links() - Reset the links on stop adapter. + * @adapter: HDD adapter + * @clear_macaddr: Clears mac address if set to true + * + * Resets the MAC address in each link info and resets the link info + * mapping in adapter array. + * + * Return: void + */ +void +hdd_adapter_disable_all_links(struct hdd_adapter *adapter, bool clear_macaddr); +#else +static inline void +hdd_adapter_disable_all_links(struct hdd_adapter *adapter, bool clear_macaddr) +{ +} +#endif + +struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, + uint8_t session_type, + const char *name, tSirMacAddr mac_addr, + unsigned char name_assign_type, + bool rtnl_held, + struct hdd_adapter_create_param *params); + +QDF_STATUS hdd_open_adapter_no_trans(struct hdd_context *hdd_ctx, + enum QDF_OPMODE op_mode, + const char *iface_name, + uint8_t *mac_addr_bytes, + struct hdd_adapter_create_param *params); +/** + * hdd_close_adapter() - remove and free @adapter from the adapter list + * @hdd_ctx: The Hdd context containing the adapter list + * @adapter: the adapter to remove and free + * @rtnl_held: if the caller is already holding the RTNL lock + * + * Return: None + */ +void hdd_close_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held); + +/** + * hdd_close_all_adapters() - remove and free all adapters from the adapter list + * @hdd_ctx: The Hdd context containing the adapter list + * @rtnl_held: if the caller is already holding the RTNL lock + * + * Return: None + */ +void hdd_close_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held); + +QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx); +void hdd_deinit_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held); +QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx); +QDF_STATUS hdd_start_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held); + +/** + * hdd_get_link_info_by_vdev() - Return link info with the given vdev id + * @hdd_ctx: hdd context. + * @vdev_id: vdev id for the link info to get. + * + * This function is used to get the link info with provided vdev id + * + * Return: adapter pointer if found + * + */ +struct wlan_hdd_link_info * +hdd_get_link_info_by_vdev(struct hdd_context *hdd_ctx, uint32_t vdev_id); + +/** + * hdd_adapter_get_by_reference() - Return adapter with the given reference + * @hdd_ctx: hdd context + * @reference: reference for the adapter to get + * + * This function is used to get the adapter with provided reference. + * The adapter reference will be held until being released by calling + * hdd_adapter_put(). + * + * Return: adapter pointer if found + * + */ +struct hdd_adapter *hdd_adapter_get_by_reference(struct hdd_context *hdd_ctx, + struct hdd_adapter *reference); + +/** + * hdd_adapter_put() - Release reference to adapter + * @adapter: adapter reference + * + * Release reference to adapter previously acquired via + * hdd_adapter_get_*() function + */ +void hdd_adapter_put(struct hdd_adapter *adapter); + +/** + * hdd_get_link_info_by_link_addr() - Get the link info pointer where + * the link address matches. + * @hdd_ctx: HDD context pointer + * @link_addr: Link address to search + * + * In the given @adapter search for @link_addr in each entry of link_info + * array, and return the matching link_info pointer. + * + * Return: NULL / Valid link info pointer + */ +struct wlan_hdd_link_info * +hdd_get_link_info_by_link_addr(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *link_addr); + +struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr); + +/** + * hdd_get_link_info_home_channel() - return home channel of adapter + * @link_info: Pointer of link_info in @adapter + * + * This function returns operation channel of station/p2p-cli if + * connected, returns operation channel of sap/p2p-go if started. + * + * Return: home channel if connected/started or invalid channel 0 + */ +uint32_t hdd_get_link_info_home_channel(struct wlan_hdd_link_info *link_info); + +/** + * hdd_get_link_info_width() - return current bandwidth of adapter + * @link_info: Pointer of link_info in @adapter + * + * This function returns current bandwidth of station/p2p-cli if + * connected, returns current bandwidth of sap/p2p-go if started. + * + * Return: bandwidth if connected/started or invalid bandwidth 0 + */ +enum phy_ch_width hdd_get_link_info_width(struct wlan_hdd_link_info *link_info); + +/* + * hdd_get_adapter_by_rand_macaddr() - find Random mac adapter + * @hdd_ctx: hdd context + * @mac_addr: random mac addr + * + * Find the Adapter based on random mac addr. Adapter's vdev + * have active random mac list. + * + * Return: adapter ptr or null + */ +struct hdd_adapter * +hdd_get_adapter_by_rand_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr); + +/** + * hdd_adapter_update_mlo_mgr_mac_addr() - Update each link address to MLO mgr. + * @adapter: HDD adapter + * + * Update MLO manager with each link address and corresponding VDEV ID. + * Only update for ML-STA adapter types. + * + * Return: void + */ +void hdd_adapter_update_mlo_mgr_mac_addr(struct hdd_adapter *adapter); + +/** + * hdd_is_vdev_in_conn_state() - Check whether the vdev is in + * connected/started state. + * @link_info: Pointer to link_info in adapter + * + * This function will give whether the vdev in the adapter is in + * connected/started state. + * + * Return: True/false + */ +bool hdd_is_vdev_in_conn_state(struct wlan_hdd_link_info *link_info); + +/** + * hdd_adapter_deregister_fc() - Deregisters flow control + * callbacks + * @adapter: HDD adapter + * + * The function call deregisters flow control callbacks + * + * Return: void + */ +void hdd_adapter_deregister_fc(struct hdd_adapter *adapter); + +#ifdef WLAN_OPEN_SOURCE +/** + * hdd_cancel_ip_notifier_work() - Cancel scheduled IP + * notifier deferred work + * @adapter: HDD adapter + * + * The API calls cancel work for IPv4 and IPv6 notifier + * deferred task + * + * Return: void + */ +void hdd_cancel_ip_notifier_work(struct hdd_adapter *adapter); +#else +static inline +void hdd_cancel_ip_notifier_work(struct hdd_adapter *adapter) +{ +} +#endif + +/** + * hdd_vdev_create() - Create the vdev in the firmware + * @link_info: Link info pointer in HDD adapter + * + * This function will create the vdev in the firmware + * + * Return: 0 when the vdev create is sent to firmware or -EINVAL when + * there is a failure to send the command. + */ +int hdd_vdev_create(struct wlan_hdd_link_info *link_info); + +/** + * hdd_vdev_destroy() - Destroy the vdev in the firmware + * @link_info: Link info pointer in HDD adapter + * + * This function will destroy the vdev in the firmware + * + * Return: 0 when the vdev destroy is sent to firmware + * or -EINVAL when there is a failure to send the command. + */ +int hdd_vdev_destroy(struct wlan_hdd_link_info *link_info); + +/** + * hdd_vdev_ready() - Configure FW post VDEV create + * @vdev: VDEV object. + * @bridgeaddr: Bridge MAC address + * + * The function is used send configuration to the FW + * post VDEV creation. + * The caller to ensure to hold the VDEV reference + * + * Return: 0 on success, negative value on failure. + */ +int hdd_vdev_ready(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr); + +/** + * hdd_init_station_mode() - Initialize STA mode adapter + * post vdev creation. + * @link_info: Link info pointer in HDD adapter + * + * The function initializes the adapter post vdev + * create for STA mode type adapters on start + * adapter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_init_station_mode(struct wlan_hdd_link_info *link_info); + +struct hdd_adapter *hdd_get_adapter(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode); + +/** + * hdd_get_device_mode() - Get device mode + * @vdev_id: vdev id + * + * Return: Device mode + */ +enum QDF_OPMODE hdd_get_device_mode(uint32_t vdev_id); + +/** + * hdd_deinit_session() - Cleanup session context in + * adapter + * @adapter: HDD adapter + * + * The API cleans up session context and scan IEs + * in link_info and adapter. + * + * Return: None + */ +void hdd_deinit_session(struct hdd_adapter *adapter); + +void hdd_deinit_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held); +QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * hdd_set_station_ops() - update net_device ops + * @dev: Handle to struct net_device to be updated. + * Return: None + */ +void hdd_set_station_ops(struct net_device *dev); + +/** + * wlan_hdd_get_intf_addr() - Get address for the interface + * @hdd_ctx: Pointer to hdd context + * @interface_type: type of the interface for which address is queried + * + * This function is used to get mac address for every new interface + * + * Return: If addr is present then return pointer to MAC address + * else NULL + */ + +uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx, + enum QDF_OPMODE interface_type); +void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx, + uint8_t *releaseAddr); + +/** + * hdd_get_operating_chan_freq() - return operating channel of the device mode + * @hdd_ctx: Pointer to the HDD context. + * @mode: Device mode for which operating channel is required. + * Supported modes: + * QDF_STA_MODE, + * QDF_P2P_CLIENT_MODE, + * QDF_SAP_MODE, + * QDF_P2P_GO_MODE. + * + * This API returns the operating channel of the requested device mode + * + * Return: channel frequency, or + * 0 if the requested device mode is not found. + */ +uint32_t hdd_get_operating_chan_freq(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode); + +void hdd_set_conparam(int32_t con_param); +enum QDF_GLOBAL_MODE hdd_get_conparam(void); + +/** + * wlan_hdd_reset_prob_rspies() - Reset probe response IEs + * @link_info: Link info pointer in HDD adapter. + * + * Reset the probe response IEs for the VDEV pointer by link info. + * + * Return: void + */ +void wlan_hdd_reset_prob_rspies(struct wlan_hdd_link_info *link_info); +void hdd_prevent_suspend(uint32_t reason); + +/* + * hdd_get_first_valid_adapter() - Get the first valid adapter from adapter list + * + * This function is used to fetch the first valid adapter from the adapter + * list. If there is no valid adapter then it returns NULL + * + * @hdd_ctx: HDD context handler + * + * Return: NULL if no valid adapter found in the adapter list + * + */ +struct hdd_adapter *hdd_get_first_valid_adapter(struct hdd_context *hdd_ctx); + +void hdd_allow_suspend(uint32_t reason); +void hdd_prevent_suspend_timeout(uint32_t timeout, uint32_t reason); + +/** + * wlan_hdd_validate_context() - check the HDD context + * @hdd_ctx: Global HDD context pointer + * + * Return: 0 if the context is valid. Error code otherwise + */ +#define wlan_hdd_validate_context(hdd_ctx) \ + __wlan_hdd_validate_context(hdd_ctx, __func__) + +int __wlan_hdd_validate_context(struct hdd_context *hdd_ctx, const char *func); + +/** + * hdd_validate_adapter() - Validate the given adapter + * @adapter: the adapter to validate + * + * This function validates the given adapter, and ensures that it is open. + * + * Return: Errno + */ +#define hdd_validate_adapter(adapter) \ + __hdd_validate_adapter(adapter, __func__) + +int __hdd_validate_adapter(struct hdd_adapter *adapter, const char *func); + +/** + * wlan_hdd_validate_vdev_id() - ensure the given vdev Id is valid + * @vdev_id: the vdev Id to validate + * + * Return: Errno + */ +#define wlan_hdd_validate_vdev_id(vdev_id) \ + __wlan_hdd_validate_vdev_id(vdev_id, __func__) + +int __wlan_hdd_validate_vdev_id(uint8_t vdev_id, const char *func); + +/** + * hdd_is_valid_mac_address() - validate MAC address + * @mac_addr: Pointer to the input MAC address + * + * This function validates whether the given MAC address is valid or not + * Expected MAC address is of the format XX:XX:XX:XX:XX:XX + * where X is the hexa decimal digit character and separated by ':' + * This algorithm works even if MAC address is not separated by ':' + * + * This code checks given input string mac contains exactly 12 hexadecimal + * digits and a separator colon : appears in the input string only after + * an even number of hex digits. + * + * Return: true for valid and false for invalid + */ +bool hdd_is_valid_mac_address(const uint8_t *mac_addr); + +bool wlan_hdd_validate_modules_state(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_validate_mac_address() - Function to validate mac address + * @mac_addr: input mac address + * + * Return QDF_STATUS + */ +#define wlan_hdd_validate_mac_address(mac_addr) \ + __wlan_hdd_validate_mac_address(mac_addr, __func__) + +QDF_STATUS __wlan_hdd_validate_mac_address(struct qdf_mac_addr *mac_addr, + const char *func); + +/** + * hdd_is_any_adapter_connected() - Check if any adapter is in connected state + * @hdd_ctx: the global hdd context + * + * Returns: true, if any of the adapters is in connected state, + * false, if none of the adapters is in connected state. + */ +bool hdd_is_any_adapter_connected(struct hdd_context *hdd_ctx); + +/** + * hdd_init_adapter_ops_wq() - Init global workqueue for adapter operations. + * @hdd_ctx: pointer to HDD context + * + * Return: QDF_STATUS_SUCCESS if workqueue is allocated, + * QDF_STATUS_E_NOMEM if workqueue aloocation fails. + */ +QDF_STATUS hdd_init_adapter_ops_wq(struct hdd_context *hdd_ctx); + +/** + * hdd_deinit_adapter_ops_wq() - Deinit global workqueue for adapter operations. + * @hdd_ctx: pointer to HDD context + * + * Return: None + */ +void hdd_deinit_adapter_ops_wq(struct hdd_context *hdd_ctx); + +/** + * hdd_adapter_feature_update_work_init() - Init per adapter work for netdev + * feature update + * @adapter: pointer to adapter structure + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_adapter_feature_update_work_init(struct hdd_adapter *adapter); + +/** + * hdd_adapter_feature_update_work_deinit() - Deinit per adapter work for + * netdev feature update + * @adapter: pointer to adapter structure + * + * Return: QDF_STATUS + */ +void hdd_adapter_feature_update_work_deinit(struct hdd_adapter *adapter); + +int hdd_qdf_trace_enable(QDF_MODULE_ID module_id, uint32_t bitmask); + +int hdd_init(void); +void hdd_deinit(void); + +/** + * hdd_wlan_startup() - HDD init function + * @hdd_ctx: the HDD context corresponding to the psoc to startup + * + * Return: Errno + */ +int hdd_wlan_startup(struct hdd_context *hdd_ctx); + +/** + * hdd_wlan_exit() - HDD WLAN exit function + * @hdd_ctx: pointer to the HDD Context + * + * Return: None + */ +void hdd_wlan_exit(struct hdd_context *hdd_ctx); + +/** + * hdd_psoc_create_vdevs() - create the default vdevs for a psoc + * @hdd_ctx: the HDD context for the psoc to operate against + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_psoc_create_vdevs(struct hdd_context *hdd_ctx); + +/* + * hdd_context_create() - Allocate and inialize HDD context. + * @dev: Device Pointer to the underlying device + * + * Allocate and initialize HDD context. HDD context is allocated as part of + * wiphy allocation and then context is initialized. + * + * Return: HDD context on success and ERR_PTR on failure + */ +struct hdd_context *hdd_context_create(struct device *dev); + +/** + * hdd_context_destroy() - Destroy HDD context + * @hdd_ctx: HDD context to be destroyed. + * + * Free config and HDD context as well as destroy all the resources. + * + * Return: None + */ +void hdd_context_destroy(struct hdd_context *hdd_ctx); + +int hdd_wlan_notify_modem_power_state(int state); + +void wlan_hdd_send_svc_nlink_msg(int radio, int type, void *data, int len); +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_enable(struct hdd_context *hdd_ctx, bool enable); +#else +static inline void +wlan_hdd_auto_shutdown_enable(struct hdd_context *hdd_ctx, bool enable) +{ +} +#endif + +struct hdd_adapter * +hdd_get_con_sap_adapter(struct hdd_adapter *this_sap_adapter, + bool check_start_bss); + +bool hdd_is_5g_supported(struct hdd_context *hdd_ctx); + +/** + * hdd_is_2g_supported() - check if 2GHz channels are supported + * @hdd_ctx: Pointer to the hdd context + * + * HDD function to know if 2GHz channels are supported + * + * Return: true if 2GHz channels are supported + */ +bool hdd_is_2g_supported(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_scan_abort() - abort ongoing scan + * @link_info: Link info pointer in HDD adapter + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_scan_abort(struct wlan_hdd_link_info *link_info); + +/** + * hdd_indicate_active_ndp_cnt() - Callback to indicate active ndp count to hdd + * if ndp connection is on NDI established + * @psoc: pointer to psoc object + * @vdev_id: vdev id + * @cnt: number of active ndp sessions + * + * This HDD callback registered with policy manager to indicates number of active + * ndp sessions to hdd. + * + * Return: none + */ +void hdd_indicate_active_ndp_cnt(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t cnt); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline bool roaming_offload_enabled(struct hdd_context *hdd_ctx) +{ + bool is_roam_offload; + + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &is_roam_offload); + + return is_roam_offload; +} +#else +static inline bool roaming_offload_enabled(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_HOST_ROAM +static inline bool hdd_driver_roaming_supported(struct hdd_context *hdd_ctx) +{ + bool lfr_enabled; + + ucfg_mlme_is_lfr_enabled(hdd_ctx->psoc, &lfr_enabled); + + return lfr_enabled; +} +#else +static inline bool hdd_driver_roaming_supported(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +static inline bool hdd_roaming_supported(struct hdd_context *hdd_ctx) +{ + bool val; + + val = hdd_driver_roaming_supported(hdd_ctx) || + roaming_offload_enabled(hdd_ctx); + + return val; +} + +#ifdef WLAN_NS_OFFLOAD +static inline void +hdd_adapter_flush_ipv6_notifier_work(struct hdd_adapter *adapter) +{ + flush_work(&adapter->ipv6_notifier_work); +} +#else +static inline void +hdd_adapter_flush_ipv6_notifier_work(struct hdd_adapter *adapter) +{ +} +#endif + +#ifdef CFG80211_SCAN_RANDOM_MAC_ADDR +static inline bool hdd_scan_random_mac_addr_supported(void) +{ + return true; +} +#else +static inline bool hdd_scan_random_mac_addr_supported(void) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +static inline bool hdd_dynamic_mac_addr_supported(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->is_vdev_macaddr_dynamic_update_supported; +} +#else +static inline bool hdd_dynamic_mac_addr_supported(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +/** + * hdd_adapter_get_link_info_ptr() - To get the pointer of link_info + * in adapter. + * @adapter: HDD adapter + * @link_idx: Index of link_info in @adapter. + * + * The API returns link_info in @adapter pointed at @link_idx in the array. + * + * Return: Pointer to wlan_hdd_link_info or NULL. + */ +static inline struct wlan_hdd_link_info * +hdd_adapter_get_link_info_ptr(struct hdd_adapter *adapter, uint8_t link_idx) +{ + if (!adapter || (link_idx >= QDF_ARRAY_SIZE(adapter->link_info))) + return NULL; + + return &adapter->link_info[link_idx]; +} + +/** + * hdd_start_vendor_acs(): Start vendor ACS procedure + * @adapter: pointer to SAP adapter struct + * + * This function sends the ACS config to the ACS daemon and + * starts the vendor ACS timer to wait for the next command. + * + * Return: Status of vendor ACS procedure + */ +int hdd_start_vendor_acs(struct hdd_adapter *adapter); + +/** + * hdd_acs_response_timeout_handler() - timeout handler for acs_timer + * @context: timeout handler context + * + * Return: None + */ +void hdd_acs_response_timeout_handler(void *context); + +/** + * wlan_hdd_cfg80211_start_acs(): Start ACS Procedure for SAP + * @link_info: Link info pointer in HDD adapter + * + * This function starts the ACS procedure if there are no + * constraints like MBSSID DFS restrictions. + * + * Return: Status of ACS Start procedure + */ +int wlan_hdd_cfg80211_start_acs(struct wlan_hdd_link_info *link_info); + +/** + * wlan_hdd_trim_acs_channel_list() - Trims ACS channel list with + * intersection of PCL + * @pcl: preferred channel list + * @pcl_count: Preferred channel list count + * @org_freq_list: ACS channel list from user space + * @org_ch_list_count: ACS channel count from user space + * + * Return: None + */ +void wlan_hdd_trim_acs_channel_list(uint32_t *pcl, uint8_t pcl_count, + uint32_t *org_freq_list, + uint8_t *org_ch_list_count); + +/** + * wlan_hdd_handle_zero_acs_list() - Handle worst case of ACS channel + * trimmed to zero + * @hdd_ctx: struct hdd_context + * @acs_freq_list: Calculated ACS channel list + * @acs_ch_list_count: Calculated ACS channel count + * @org_freq_list: ACS channel list from user space + * @org_ch_list_count: ACS channel count from user space + * + * When all channels in the ACS freq list is filtered out by + * wlan_hdd_trim_acs_channel_list(), the hostapd start will fail. + * This happens when PCL is PM_24G_SCC_CH_SBS_CH, and SAP ACS range + * includes 5 GHz channel list. One example is STA active on 6 GHz + * chan. Hostapd start SAP on 5 GHz ACS range. The intersection of PCL + * and ACS range is zero. Instead of ACS failure, this API selects + * one channel from ACS range and report to Hostapd. When hostapd do + * start_ap, the driver will force SCC to 6 GHz or move SAP to 2 GHz + * based on SAP's configuration. + * + * Return: None + */ +void wlan_hdd_handle_zero_acs_list(struct hdd_context *hdd_ctx, + uint32_t *acs_freq_list, + uint8_t *acs_ch_list_count, + uint32_t *org_freq_list, + uint8_t org_ch_list_count); + +/** + * hdd_cfg80211_update_acs_config() - update acs config to application + * @adapter: hdd adapter + * @reason: channel change reason + * + * Return: 0 for success else error code + */ +int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter, + uint8_t reason); + +/** + * hdd_update_acs_timer_reason() - update acs timer start reason + * @adapter: hdd adapter + * @reason: channel change reason + * + * Return: 0 for success + */ +int hdd_update_acs_timer_reason(struct hdd_adapter *adapter, uint8_t reason); + +/** + * hdd_switch_sap_channel() - Move SAP to the given channel + * @link_info: Pointer of link_info in adapter + * @channel: Channel + * @forced: Force to switch channel, ignore SCC/MCC check + * + * Moves the SAP interface by invoking the function which + * executes the callback to perform channel switch using (E)CSA. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_switch_sap_channel(struct wlan_hdd_link_info *link_info, + uint8_t channel, bool forced); + +/** + * hdd_switch_sap_chan_freq() - Move SAP to the given channel + * @adapter: AP adapter + * @chan_freq: Channel frequency + * @ch_width: channel bandwidth + * @forced: Force to switch channel, ignore SCC/MCC check + * + * Moves the SAP interface by invoking the function which + * executes the callback to perform channel switch using (E)CSA. + * + * Return: QDF_STATUS_SUCCESS if successfully + */ +QDF_STATUS hdd_switch_sap_chan_freq(struct hdd_adapter *adapter, + qdf_freq_t chan_freq, + enum phy_ch_width ch_width, + bool forced); + +#if defined(FEATURE_WLAN_CH_AVOID) +QDF_STATUS hdd_unsafe_channel_restart_sap(struct hdd_context *hdd_ctx); + +void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt, + struct unsafe_ch_list *unsafe_chan_list, + struct ch_avoid_ind_type *avoid_freq_list); +#else +static inline +QDF_STATUS hdd_unsafe_channel_restart_sap(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt, + struct unsafe_ch_list *unsafe_chan_list, + struct ch_avoid_ind_type *avoid_freq_list) +{ +} +#endif + +/** + * hdd_free_mac_address_lists() - Free both the MAC address lists + * @hdd_ctx: HDD context + * + * This API clears/memset provisioned address list and + * derived address list + * + */ +void hdd_free_mac_address_lists(struct hdd_context *hdd_ctx); + +/** + * hdd_update_macaddr() - update mac address + * @hdd_ctx: hdd contxt + * @hw_macaddr: mac address + * @generate_mac_auto: Indicates whether the first address is + * provisioned address or derived address. + * + * Mac address for multiple virtual interface is found as following + * i) The mac address of the first interface is just the actual hw mac address. + * ii) MSM 3 or 4 bits of byte5 of the actual mac address are used to + * define the mac address for the remaining interfaces and locally + * admistered bit is set. INTF_MACADDR_MASK is based on the number of + * supported virtual interfaces, right now this is 0x07 (meaning 8 + * interface). + * Byte[3] of second interface will be hw_macaddr[3](bit5..7) + 1, + * for third interface it will be hw_macaddr[3](bit5..7) + 2, etc. + * + * Return: None + */ +void hdd_update_macaddr(struct hdd_context *hdd_ctx, + struct qdf_mac_addr hw_macaddr, bool generate_mac_auto); + +/** + * hdd_store_nss_chains_cfg_in_vdev() - Store the per vdev ini cfg in vdev_obj + * @hdd_ctx: HDD context passed from caller + * @vdev: VDEV passed with caller holding reference. + * + * This function will store the per vdev nss params to the particular mlme + * vdev obj. + * Caller shall acquire the reference for vdev objmgr and release on return. + * + * Return: None + */ +void +hdd_store_nss_chains_cfg_in_vdev(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev); + +/** + * wlan_hdd_set_roaming_state() - Enable or disable roaming + * on all STAs except the input one + * @cur_link_info: Current link info pointer in HDD adapter + * @rso_op_requestor: roam disable requestor + * @enab_roam: Set to true to enable roaming or else set false + * + * This function loops through all adapters and enables or + * disables roaming on each STA mode adapter except the + * current adapter passed from the caller. + * If @enab_roam is true, roaming is enabled or else + * roaming is disabled + * + * Return: None + */ +void +wlan_hdd_set_roaming_state(struct wlan_hdd_link_info *cur_link_info, + enum wlan_cm_rso_control_requestor rso_op_requestor, + bool enab_roam); + +QDF_STATUS hdd_post_cds_enable_config(struct hdd_context *hdd_ctx); + +QDF_STATUS hdd_abort_mac_scan_all_adapters(struct hdd_context *hdd_ctx); + +void wlan_hdd_stop_sap(struct hdd_adapter *ap_adapter); + +/** + * wlan_hdd_start_sap() - this function starts bss of SAP. + * @link_info: Link info pointer in SAP/GO adapter + * @reinit: true if this is a re-init, otherwise initial int + * + * This function will process the starting of sap adapter. + * + * Return: None + */ +void wlan_hdd_start_sap(struct wlan_hdd_link_info *link_info, bool reinit); + +/** + * wlan_hdd_set_sap_beacon_protection() - this function will set beacon + * protection for SAP. + * @hdd_ctx: pointer to HDD context + * @link_info: Link info pointer + * @beacon: pointer to beacon data structure + * + * This function will enable beacon protection and cache the value in vdev + * priv object. + * + * Return: None + */ +void wlan_hdd_set_sap_beacon_protection(struct hdd_context *hdd_ctx, + struct wlan_hdd_link_info *link_info, + struct hdd_beacon_data *beacon); +#ifdef QCA_CONFIG_SMP +int wlan_hdd_get_cpu(void); +#else +static inline int wlan_hdd_get_cpu(void) +{ + return 0; +} +#endif + +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason); + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +void wlan_hdd_mod_fc_timer(struct hdd_adapter *adapter, + enum netif_action_type action); +#else +static inline void wlan_hdd_mod_fc_timer(struct hdd_adapter *adapter, + enum netif_action_type action) +{ +} +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +/** + * hdd_wlan_dump_stats() - display dump Stats + * @adapter: adapter handle + * @stats_id: stats id from user + * + * Return: 0 => success, error code on failure + */ +int hdd_wlan_dump_stats(struct hdd_adapter *adapter, int stats_id); + +/** + * hdd_wlan_clear_stats() - clear Stats + * @adapter: adapter handle + * @stats_id: stats id from user + * + * Return: 0 => success, error code on failure + */ +int hdd_wlan_clear_stats(struct hdd_adapter *adapter, int stats_id); + +/** + * hdd_cb_handle_to_context() - turn an HDD handle into an HDD context + * @hdd_handle: HDD handle to be converted + * + * Return: HDD context referenced by @hdd_handle + */ +static inline +struct hdd_context *hdd_cb_handle_to_context(hdd_cb_handle hdd_handle) +{ + return (struct hdd_context *)hdd_handle; +} + +/** + * wlan_hdd_display_netif_queue_history() - display netif queue history + * @context: opaque handle to hdd context + * @verb_lvl: Verbosity levels for stats + * + * Return: none + */ +void +wlan_hdd_display_netif_queue_history(hdd_cb_handle context, + enum qdf_stats_verbosity_level verb_lvl); + +/** + * wlan_hdd_display_adapter_netif_queue_history() - display adapter based netif + * queue history + * @adapter: hdd adapter + * + * Return: none + */ +void +wlan_hdd_display_adapter_netif_queue_history(struct hdd_adapter *adapter); + +void wlan_hdd_clear_netif_queue_history(struct hdd_context *hdd_ctx); +const char *hdd_get_fwpath(void); +void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind); + +/** + * hdd_get_adapter_by_iface_name() - Return adapter with given interface name + * @hdd_ctx: hdd context. + * @iface_name: interface name + * + * This function is used to get the adapter with given interface name + * + * Return: adapter pointer if found, NULL otherwise + * + */ +struct hdd_adapter *hdd_get_adapter_by_iface_name(struct hdd_context *hdd_ctx, + const char *iface_name); + +/** + * hdd_get_adapter_by_ifindex() - Return adapter associated with an ifndex + * @hdd_ctx: hdd context. + * @if_index: netdev interface index + * + * This function is used to get the adapter associated with a netdev with the + * given interface index. + * + * Return: adapter pointer if found, NULL otherwise + * + */ +struct hdd_adapter *hdd_get_adapter_by_ifindex(struct hdd_context *hdd_ctx, + uint32_t if_index); + +enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width); + +/** + * hdd_nl_to_qdf_iface_type() - map nl80211_iftype to QDF_OPMODE + * @nl_type: the input NL80211 interface type to map + * @out_qdf_type: the output, equivalent QDF operating mode + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_nl_to_qdf_iface_type(enum nl80211_iftype nl_type, + enum QDF_OPMODE *out_qdf_type); + +/** + * wlan_hdd_find_opclass() - Find operating class for a channel + * @mac_handle: global MAC handle + * @channel: channel id + * @bw_offset: bandwidth offset + * + * Function invokes sme api to find the operating class + * + * Return: operating class + */ +uint8_t wlan_hdd_find_opclass(mac_handle_t mac_handle, uint8_t channel, + uint8_t bw_offset); + +int hdd_update_config(struct hdd_context *hdd_ctx); + +/** + * hdd_update_components_config() - Initialize driver per module ini parameters + * @hdd_ctx: HDD Context + * + * API is used to initialize components configuration parameters + * Return: 0 for success, errno for failure + */ +int hdd_update_components_config(struct hdd_context *hdd_ctx); + +/** + * hdd_chan_change_notify_work_handler() - Function to notify hostapd about + * channel change + * @work: work pointer + * + * This function is used to notify hostapd about the channel change + * + * Return: None + * + */ +void hdd_chan_change_notify_work_handler(void *work); + +int wlan_hdd_set_channel(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type channel_type); + +/** + * wlan_hdd_cfg80211_start_bss() - start bss + * @link_info: Link info pointer in hostapd adapter + * @params: Pointer to start bss beacon parameters + * @ssid: Pointer ssid + * @ssid_len: Length of ssid + * @hidden_ssid: Hidden SSID parameter + * @check_for_concurrency: Flag to indicate if check for concurrency is needed + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_start_bss(struct wlan_hdd_link_info *link_info, + struct cfg80211_beacon_data *params, + const u8 *ssid, size_t ssid_len, + enum nl80211_hidden_ssid hidden_ssid, + bool check_for_concurrency); + +#if !defined(REMOVE_PKT_LOG) +int hdd_process_pktlog_command(struct hdd_context *hdd_ctx, uint32_t set_value, + int set_value2); +int hdd_pktlog_enable_disable(struct hdd_context *hdd_ctx, bool enable, + uint8_t user_triggered, int size); + +#else +static inline +int hdd_pktlog_enable_disable(struct hdd_context *hdd_ctx, bool enable, + uint8_t user_triggered, int size) +{ + return 0; +} + +static inline +int hdd_process_pktlog_command(struct hdd_context *hdd_ctx, + uint32_t set_value, int set_value2) +{ + return 0; +} +#endif /* REMOVE_PKT_LOG */ + +#if defined(FEATURE_SG) && !defined(CONFIG_HL_SUPPORT) +/** + * hdd_set_sg_flags() - enable SG flag in the network device + * @hdd_ctx: HDD context + * @wlan_dev: network device structure + * + * This function enables the SG feature flag in the + * given network device. + * + * Return: none + */ +static inline void hdd_set_sg_flags(struct hdd_context *hdd_ctx, + struct net_device *wlan_dev) +{ + hdd_debug("SG Enabled"); + wlan_dev->features |= NETIF_F_SG; +} +#else +static inline void hdd_set_sg_flags(struct hdd_context *hdd_ctx, + struct net_device *wlan_dev){} +#endif + +/** + * hdd_set_netdev_flags() - set netdev flags for adapter as per ini config + * @adapter: hdd adapter context + * + * This function sets netdev feature flags for the adapter. + * + * Return: none + */ +void hdd_set_netdev_flags(struct hdd_adapter *adapter); + +#ifdef FEATURE_TSO +/** + * hdd_get_tso_csum_feature_flags() - Return TSO and csum flags if enabled + * + * Return: Enabled feature flags set, 0 on failure + */ +static inline netdev_features_t hdd_get_tso_csum_feature_flags(void) +{ + netdev_features_t netdev_features = 0; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + hdd_err("soc handle is NULL"); + return 0; + } + + if (cdp_cfg_get(soc, cfg_dp_enable_ip_tcp_udp_checksum_offload)) { + netdev_features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + + if (cdp_cfg_get(soc, cfg_dp_tso_enable)) { + /* + * Enable TSO only if IP/UDP/TCP TX checksum flag is + * enabled. + */ + netdev_features |= NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_SG; + } + } + return netdev_features; +} + +/** + * hdd_set_tso_flags() - enable TSO flags in the network device + * @hdd_ctx: HDD context + * @wlan_dev: network device structure + * + * This function enables the TSO related feature flags in the + * given network device. + * + * Return: none + */ +static inline void hdd_set_tso_flags(struct hdd_context *hdd_ctx, + struct net_device *wlan_dev) +{ + hdd_debug("TSO Enabled"); + + wlan_dev->features |= hdd_get_tso_csum_feature_flags(); +} +#else +static inline void hdd_set_tso_flags(struct hdd_context *hdd_ctx, + struct net_device *wlan_dev) +{ + hdd_set_sg_flags(hdd_ctx, wlan_dev); +} + +static inline netdev_features_t hdd_get_tso_csum_feature_flags(void) +{ + return 0; +} +#endif /* FEATURE_TSO */ + +/** + * wlan_hdd_get_host_log_nl_proto() - Get host log netlink protocol + * @hdd_ctx: HDD context + * + * This function returns with host log netlink protocol settings + * + * Return: none + */ +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +static inline int wlan_hdd_get_host_log_nl_proto(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->config->host_log_custom_nl_proto; +} +#else +static inline int wlan_hdd_get_host_log_nl_proto(struct hdd_context *hdd_ctx) +{ + return NETLINK_USERSOCK; +} +#endif + +#ifdef CONFIG_CNSS_LOGGER +/** + * wlan_hdd_nl_init() - wrapper function to CNSS_LOGGER case + * @hdd_ctx: the hdd context pointer + * + * The nl_srv_init() will call to cnss_logger_device_register() and + * expect to get a radio_index from cnss_logger module and assign to + * hdd_ctx->radio_index, then to maintain the consistency to original + * design, adding the radio_index check here, then return the error + * code if radio_index is not assigned correctly, which means the nl_init + * from cnss_logger is failed. + * + * Return: 0 if successfully, otherwise error code + */ +static inline int wlan_hdd_nl_init(struct hdd_context *hdd_ctx) +{ + int proto; + + proto = wlan_hdd_get_host_log_nl_proto(hdd_ctx); + hdd_ctx->radio_index = nl_srv_init(hdd_ctx->wiphy, proto); + + /* radio_index is assigned from 0, so only >=0 will be valid index */ + if (hdd_ctx->radio_index >= 0) + return 0; + else + return -EINVAL; +} +#else +/** + * wlan_hdd_nl_init() - wrapper function to non CNSS_LOGGER case + * @hdd_ctx: the hdd context pointer + * + * In case of non CNSS_LOGGER case, the nl_srv_init() will initialize + * the netlink socket and return the success or not. + * + * Return: the return value from nl_srv_init() + */ +static inline int wlan_hdd_nl_init(struct hdd_context *hdd_ctx) +{ + int proto; + + proto = wlan_hdd_get_host_log_nl_proto(hdd_ctx); + return nl_srv_init(hdd_ctx->wiphy, proto); +} +#endif + +QDF_STATUS hdd_sme_close_session_callback(uint8_t vdev_id); + +int hdd_register_cb(struct hdd_context *hdd_ctx); +void hdd_deregister_cb(struct hdd_context *hdd_ctx); + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +static inline struct qdf_mac_addr * +hdd_adapter_get_netdev_mac_addr(struct hdd_adapter *adapter) +{ + return &adapter->mac_addr; +} +#else +static inline struct qdf_mac_addr * +hdd_adapter_get_netdev_mac_addr(struct hdd_adapter *adapter) +{ + if (hdd_adapter_is_ml_adapter(adapter) || + hdd_adapter_is_link_adapter(adapter)) + return &adapter->mld_addr; + + return &adapter->mac_addr; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +/** + * hdd_adapter_fill_link_address() - Fill derived + * link address in adapter + * @adapter: HDD adapter + * + * The API takes MLD address of @adapter and calls link address + * derive API and fills the derived link address in each link. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter); +#else +static inline +QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_adapter_get_link_mac_addr() - Returns the appropriate + * MAC address pointer in adapter. + * @link_info: Link info in HDD adapter. + * + * If WLAN_HDD_MULTI_VDEV_SINGLE_NDEV flag is enabled, then MAC address pointer + * returned is based on following conditions: + * -if adapter of link info is non-ml: + * Return pointer of mac_addr in adapter. + * -else if link_addr in @link_info is NULL: + * Return pointer of mac_addr in adapter. + * -else + * Return pointer of link_addr in @link_info. + * + * If WLAN_HDD_MULTI_VDEV_SINGLE_NDEV flag is not enabled, then return pointer + * of mac_addr in adapter. + * + * Return: MAC address pointer based on adapter type. + */ +struct qdf_mac_addr * +hdd_adapter_get_link_mac_addr(struct wlan_hdd_link_info *link_info); + +/** + * hdd_adapter_check_duplicate_session() - Check for duplicate + * session on start adapter. + * @adapter: HDD adapter + * + * The API passes list of addresses contained in @adapter to + * sme_check_for_duplicate_session() to check the status + * of existing peer with same MAC address. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_adapter_check_duplicate_session(struct hdd_adapter *adapter); + +/** + * hdd_adapter_reset_station_ctx() - Resets station context with appropriate + * initial value. + * @adapter: HDD adapter + * + * Return: void + */ +void hdd_adapter_reset_station_ctx(struct hdd_adapter *adapter); + +/** + * hdd_start_station_adapter()- Start the Station Adapter + * @adapter: HDD adapter + * + * This function initializes the adapter for the station mode. + * + * Return: 0 on success or errno on failure. + */ +int hdd_start_station_adapter(struct hdd_adapter *adapter); + +/** + * hdd_start_ap_adapter()- Start AP Adapter + * @adapter: HDD adapter + * @rtnl_held: True if rtnl lock is taken, otherwise false + * + * This function initializes the adapter for the AP mode. + * + * Return: 0 on success errno on failure. + */ +int hdd_start_ap_adapter(struct hdd_adapter *adapter, bool rtnl_held); +int hdd_configure_cds(struct hdd_context *hdd_ctx); +int hdd_set_fw_params(struct hdd_adapter *adapter); + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * wlan_hdd_deinit_multi_client_info_table() - to deinit multi client info table + * @adapter: hdd vdev/net_device context + * + * Return: none + */ +void wlan_hdd_deinit_multi_client_info_table(struct hdd_adapter *adapter); +#else +static inline void +wlan_hdd_deinit_multi_client_info_table(struct hdd_adapter *adapter) +{} +#endif + +/** + * hdd_wlan_start_modules() - Single driver state machine for starting modules + * @hdd_ctx: HDD context + * @reinit: flag to indicate from SSR or normal path + * + * This function maintains the driver state machine it will be invoked from + * startup, reinit and change interface. Depending on the driver state shall + * perform the opening of the modules. + * + * Return: Errno + */ +int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit); + +/** + * hdd_wlan_stop_modules - Single driver state machine for stopping modules + * @hdd_ctx: HDD context + * @ftm_mode: ftm mode + * + * This function maintains the driver state machine it will be invoked from + * exit, shutdown and con_mode change handler. Depending on the driver state + * shall perform the stopping/closing of the modules. + * + * Return: Errno + */ +int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode); + +/** + * hdd_psoc_idle_timer_start() - start the idle psoc detection timer + * @hdd_ctx: the hdd context for which the timer should be started + * + * Return: None + */ +void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx); + +/** + * hdd_psoc_idle_timer_stop() - stop the idle psoc detection timer + * @hdd_ctx: the hdd context for which the timer should be stopped + * + * Return: None + */ +void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx); + +/** + * hdd_trigger_psoc_idle_restart() - trigger restart of a previously shutdown + * idle psoc, if needed + * @hdd_ctx: the hdd context which should be restarted + * + * This API does nothing if the given psoc is already active. + * + * Return: Errno + */ +int hdd_trigger_psoc_idle_restart(struct hdd_context *hdd_ctx); + +int hdd_start_adapter(struct hdd_adapter *adapter, bool rtnl_held); +void hdd_populate_random_mac_addr(struct hdd_context *hdd_ctx, uint32_t num); +/** + * hdd_is_interface_up()- Check if the given interface is up + * @adapter: interface to check + * + * Checks whether the given interface was brought up by userspace. + * + * Return: true if interface was opened else false + */ +bool hdd_is_interface_up(struct hdd_adapter *adapter); + +#ifdef WLAN_FEATURE_FASTPATH +void hdd_enable_fastpath(struct hdd_context *hdd_ctx, + void *context); +#else +static inline void hdd_enable_fastpath(struct hdd_context *hdd_ctx, + void *context) +{ +} +#endif +void hdd_wlan_update_target_info(struct hdd_context *hdd_ctx, void *context); + +enum sap_acs_dfs_mode wlan_hdd_get_dfs_mode(enum dfs_mode mode); + +/** + * hdd_clone_local_unsafe_chan() - clone hdd ctx unsafe chan list + * @hdd_ctx: hdd context pointer + * @local_unsafe_list: copied unsafe chan list array + * @local_unsafe_list_count: channel number in returned local_unsafe_list + * + * The function will allocate memory and make a copy the current unsafe + * channels from hdd ctx. The caller need to free the local_unsafe_list + * memory after use. + * + * Return: 0 if successfully clone unsafe chan list. + */ +int hdd_clone_local_unsafe_chan(struct hdd_context *hdd_ctx, + uint16_t **local_unsafe_list, uint16_t *local_unsafe_list_count); + +/** + * hdd_local_unsafe_channel_updated() - check unsafe chan list same or not + * @hdd_ctx: hdd context pointer + * @local_unsafe_list: unsafe chan list to be compared with hdd_ctx's list + * @local_unsafe_list_count: channel number in local_unsafe_list + * @restriction_mask: restriction mask is to differentiate current channel + * list different from previous channel list + * + * The function checked the input channel is same as current unsafe chan + * list in hdd_ctx. + * + * Return: true if input channel list is same as the list in hdd_ctx + */ +bool hdd_local_unsafe_channel_updated(struct hdd_context *hdd_ctx, + uint16_t *local_unsafe_list, uint16_t local_unsafe_list_count, + uint32_t restriction_mask); + +int hdd_enable_disable_ca_event(struct hdd_context *hddctx, + uint8_t set_value); + +/** + * wlan_hdd_undo_acs : Do cleanup of DO_ACS + * @link_info: Pointer of link_info in adapter + * + * This function handle cleanup of what was done in DO_ACS, including free + * memory. + * + * Return: void + */ +void wlan_hdd_undo_acs(struct wlan_hdd_link_info *link_info); + +/** + * wlan_hdd_set_restriction_mask() - set restriction mask for hdd context + * @hdd_ctx: hdd context pointer + * + * Return: None + */ +void wlan_hdd_set_restriction_mask(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_get_restriction_mask() - get restriction mask from hdd context + * @hdd_ctx: hdd context pointer + * + * Return: restriction_mask + */ +uint32_t wlan_hdd_get_restriction_mask(struct hdd_context *hdd_ctx); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) +static inline int +hdd_wlan_nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put_u64(skb, attrtype, value); +} +#else +static inline int +hdd_wlan_nla_put_u64(struct sk_buff *skb, int attrtype, u64 value) +{ + return nla_put_u64_64bit(skb, attrtype, value, NL80211_ATTR_PAD); +} +#endif + +/** + * hdd_roam_profile() - Get adapter's roam profile + * @link_info: Link info pointer in HDD adapter + * + * Given an adapter this function returns a pointer to its roam profile. + * + * NOTE WELL: Caller is responsible for ensuring this interface is only + * invoked for STA-type interfaces + * + * Return: pointer to the adapter's roam profile + */ +static inline struct csr_roam_profile * +hdd_roam_profile(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + return &sta_ctx->roam_profile; +} + +/** + * hdd_is_roaming_in_progress() - check if roaming is in progress + * @hdd_ctx: Global HDD context + * + * Checks if roaming is in progress on any of the adapters + * + * Return: true if roaming is in progress else false + */ +bool hdd_is_roaming_in_progress(struct hdd_context *hdd_ctx); + +/** + * hdd_is_connection_in_progress() - check if connection is in progress + * @out_vdev_id: id of vdev where connection is occurring + * @out_reason: scan reject reason + * + * Go through each adapter and check if connection is in progress. + * Output parameters @out_vdev_id and @out_reason will only be written + * when a connection is in progress. + * + * Return: true if connection is in progress else false + */ +bool hdd_is_connection_in_progress(uint8_t *out_vdev_id, + enum scan_reject_states *out_reason); + +/** + * hdd_restart_sap() - to restart SAP in driver internally + * @link_info: Link info pointer of SAP adapter + * + * Return: None + */ +void hdd_restart_sap(struct wlan_hdd_link_info *link_info); +bool hdd_set_connection_in_progress(bool value); + +/** + * wlan_hdd_init_chan_info() - initialize channel info variables + * @hdd_ctx: hdd ctx + * + * This API initialize channel info variables + * + * Return: None + */ +void wlan_hdd_init_chan_info(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_deinit_chan_info() - deinitialize channel info variables + * @hdd_ctx: hdd ctx + * + * This API deinitialize channel info variables + * + * Return: None + */ +void wlan_hdd_deinit_chan_info(struct hdd_context *hdd_ctx); + +/** + * hdd_is_any_interface_open() - Check for interface up + * @hdd_ctx: HDD context + * + * Return: true if any interface is open + */ +bool hdd_is_any_interface_open(struct hdd_context *hdd_ctx); + +#ifdef WIFI_POS_CONVERGED +/** + * hdd_send_peer_status_ind_to_app() - wrapper to call legacy or new wifi_pos + * function to send peer status to a registered application + * @peer_mac: MAC address of peer + * @peer_status: ePeerConnected or ePeerDisconnected + * @peer_timing_meas_cap: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @vdev_id: ID of the underlying vdev + * @chan_info: operating channel information + * @dev_mode: dev mode for which indication is sent + * + * Return: none + */ +static inline void hdd_send_peer_status_ind_to_app( + struct qdf_mac_addr *peer_mac, + uint8_t peer_status, + uint8_t peer_timing_meas_cap, + uint8_t vdev_id, + struct oem_channel_info *chan_info, + enum QDF_OPMODE dev_mode) +{ + struct wifi_pos_ch_info ch_info; + + if (!chan_info) { + os_if_wifi_pos_send_peer_status(peer_mac, peer_status, + peer_timing_meas_cap, vdev_id, + NULL, dev_mode); + return; + } + + /* chan_id is obsoleted by mhz */ + ch_info.chan_id = 0; + ch_info.mhz = chan_info->mhz; + ch_info.band_center_freq1 = chan_info->band_center_freq1; + ch_info.band_center_freq2 = chan_info->band_center_freq2; + ch_info.info = chan_info->info; + ch_info.reg_info_1 = chan_info->reg_info_1; + ch_info.reg_info_2 = chan_info->reg_info_2; + ch_info.nss = chan_info->nss; + ch_info.rate_flags = chan_info->rate_flags; + ch_info.sec_ch_offset = chan_info->sec_ch_offset; + ch_info.ch_width = chan_info->ch_width; + os_if_wifi_pos_send_peer_status(peer_mac, peer_status, + peer_timing_meas_cap, vdev_id, + &ch_info, dev_mode); +} +#else +static inline void hdd_send_peer_status_ind_to_app( + struct qdf_mac_addr *peer_mac, + uint8_t peer_status, + uint8_t peer_timing_meas_cap, + uint8_t vdev_id, + struct oem_channel_info *chan_info, + enum QDF_OPMODE dev_mode) +{ + hdd_send_peer_status_ind_to_oem_app(peer_mac, peer_status, + peer_timing_meas_cap, vdev_id, chan_info, dev_mode); +} +#endif /* WIFI_POS_CONVERGENCE */ + +/** + * wlan_hdd_send_mcc_vdev_quota()- Send mcc vdev quota value to FW + * @adapter: Adapter data + * @sval: mcc vdev quota value + * + * Send mcc vdev quota value value to FW + * + * Return: 0 success else failure + */ +int wlan_hdd_send_mcc_vdev_quota(struct hdd_adapter *adapter, int sval); + +/** + * wlan_hdd_send_mcc_latency()- Send MCC latency to FW + * @adapter: Adapter data + * @sval: MCC latency value + * + * Send MCC latency value to FW + * + * Return: 0 success else failure + */ +int wlan_hdd_send_mcc_latency(struct hdd_adapter *adapter, int sval); + +/** + * wlan_hdd_get_link_info_from_vdev()- Get link info from vdev id + * and PSOC object data + * @psoc: Psoc object data + * @vdev_id: vdev id + * + * Get link info from vdev id and PSOC object data + * + * Return: link info pointer + */ +struct wlan_hdd_link_info * +wlan_hdd_get_link_info_from_vdev(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + +/** + * hdd_unregister_notifiers()- unregister kernel notifiers + * @hdd_ctx: Hdd Context + * + * Unregister netdev notifiers like Netdevice,IPv4 and IPv6. + * + */ +void hdd_unregister_notifiers(struct hdd_context *hdd_ctx); + +/** + * hdd_dbs_scan_selection_init() - initialization for DBS scan selection config + * @hdd_ctx: HDD context + * + * This function sends the DBS scan selection config configuration to the + * firmware via WMA + * + * Return: 0 - success, < 0 - failure + */ +int hdd_dbs_scan_selection_init(struct hdd_context *hdd_ctx); + +/** + * hdd_update_scan_config - API to update scan configuration parameters + * @hdd_ctx: HDD context + * + * Return: 0 if success else err + */ +int hdd_update_scan_config(struct hdd_context *hdd_ctx); + +/** + * hdd_start_complete()- complete the start event + * @ret: return value for complete event. + * + * complete the startup event and set the return in + * global variable + * + * Return: void + */ + +void hdd_start_complete(int ret); + +/** + * hdd_chip_pwr_save_fail_detected_cb() - chip power save failure detected + * callback + * @hdd_handle: HDD handle + * @data: chip power save failure detected data + * + * This function reads the chip power save failure detected data and fill in + * the skb with NL attributes and send up the NL event. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ + +void hdd_chip_pwr_save_fail_detected_cb(hdd_handle_t hdd_handle, + struct chip_pwr_save_fail_detected_params + *data); + +/** + * hdd_update_ie_allowlist_attr() - Copy probe req ie allowlist attrs from cfg + * @ie_allowlist: output parameter + * @hdd_ctx: pointer to hdd context + * + * Return: None + */ +void hdd_update_ie_allowlist_attr(struct probe_req_allowlist_attr *ie_allowlist, + struct hdd_context *hdd_ctx); + +/** + * hdd_get_rssi_snr_by_bssid() - gets the rssi and snr by bssid from scan cache + * @mac_handle: MAC handle + * @bssid: bssid to look for in scan cache + * @rssi: rssi value found + * @snr: snr value found + * + * Return: QDF_STATUS + */ +int hdd_get_rssi_snr_by_bssid(mac_handle_t mac_handle, const uint8_t *bssid, + int8_t *rssi, int8_t *snr); + +/** + * hdd_reset_limit_off_chan() - reset limit off-channel command parameters + * @adapter: HDD adapter + * + * Return: 0 on success and non zero value on failure + */ +int hdd_reset_limit_off_chan(struct hdd_adapter *adapter); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +static inline void hdd_dev_setup_destructor(struct net_device *dev) +{ + dev->destructor = free_netdev; +} +#else +static inline void hdd_dev_setup_destructor(struct net_device *dev) +{ + dev->needs_free_netdev = true; +} +#endif /* KERNEL_VERSION(4, 12, 0) */ + +/** + * hdd_update_score_config - API to update candidate scoring related params + * configuration parameters + * @hdd_ctx: hdd context + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_update_score_config(struct hdd_context *hdd_ctx); + +/** + * hdd_get_stainfo() - get stainfo for the specified peer + * @astainfo: array of the station info in which the sta info + * corresponding to mac_addr needs to be searched + * @mac_addr: mac address of requested peer + * + * This function find the stainfo for the peer with mac_addr + * + * Return: stainfo if found, NULL if not found + */ +struct hdd_station_info *hdd_get_stainfo(struct hdd_station_info *astainfo, + struct qdf_mac_addr mac_addr); + +/** + * hdd_component_psoc_open() - Open the legacy components + * @psoc: Pointer to psoc object + * + * This function opens the legacy components and initializes the + * component's private objects. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_component_psoc_open(struct wlan_objmgr_psoc *psoc); + +/** + * hdd_component_psoc_close() - Close the legacy components + * @psoc: Pointer to psoc object + * + * This function closes the legacy components and resets the + * component's private objects. + * + * Return: None + */ +void hdd_component_psoc_close(struct wlan_objmgr_psoc *psoc); + +/** + * hdd_component_psoc_enable() - Trigger psoc enable for CLD Components + * @psoc: Pointer to psoc object + * + * Return: None + */ +void hdd_component_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * hdd_component_psoc_disable() - Trigger psoc disable for CLD Components + * @psoc: Pointer to psoc object + * + * Return: None + */ +void hdd_component_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * hdd_component_pdev_open() - Trigger pdev open for CLD Components + * @pdev: Pointer to pdev object + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_component_pdev_open(struct wlan_objmgr_pdev *pdev); + +/** + * hdd_component_pdev_close() - Trigger pdev close for CLD Components + * @pdev: Pointer to pdev object + * + * Return: None + */ +void hdd_component_pdev_close(struct wlan_objmgr_pdev *pdev); + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +int hdd_driver_memdump_init(void); +void hdd_driver_memdump_deinit(void); + +/** + * hdd_driver_mem_cleanup() - Frees memory allocated for + * driver dump + * + * This function frees driver dump memory. + * + * Return: None + */ +void hdd_driver_mem_cleanup(void); + +#else /* WLAN_FEATURE_MEMDUMP_ENABLE */ +static inline int hdd_driver_memdump_init(void) +{ + return 0; +} +static inline void hdd_driver_memdump_deinit(void) +{ +} + +static inline void hdd_driver_mem_cleanup(void) +{ +} +#endif /* WLAN_FEATURE_MEMDUMP_ENABLE */ + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * wlan_hdd_set_mon_chan() - Set capture channel on the monitor mode interface. + * @adapter: Handle to adapter + * @freq: Monitor mode frequency (MHz) + * @bandwidth: Capture channel bandwidth + * + * Return: 0 on success else error code. + */ +int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, qdf_freq_t freq, + uint32_t bandwidth); +#else +static inline +int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, qdf_freq_t freq, + uint32_t bandwidth) +{ + return 0; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + !defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +/** + * hdd_set_mld_address() - Set the MLD address of the adapter + * @adapter: Handle to adapter + * @mac_addr: MAC address to be copied + * + * The function copies the MAC address sent in @mac_addr to + * the adapter's MLD address and the MLD address of each + * link adapter mapped of the @adapter. + * The mode of operation must be 11be capable and @adapter + * has to be ML type. + * + * Return: void + */ +void +hdd_set_mld_address(struct hdd_adapter *adapter, + const struct qdf_mac_addr *mac_addr); +#else +static inline void +hdd_set_mld_address(struct hdd_adapter *adapter, + const struct qdf_mac_addr *mac_addr) +{ +} +#endif + +/** + * hdd_wlan_get_version() - Get version information + * @hdd_ctx: Global HDD context + * @version_len: length of the version buffer size + * @version: the buffer to the version string + * + * This function is used to get Wlan Driver, Firmware, Hardware Version + * & the Board related information. + * + * Return: the length of the version string + */ +uint32_t hdd_wlan_get_version(struct hdd_context *hdd_ctx, + const size_t version_len, uint8_t *version); +/** + * hdd_assemble_rate_code() - assemble rate code to be sent to FW + * @preamble: rate preamble + * @nss: number of streams + * @rate: rate index + * + * Rate code assembling is different for targets which are 11ax capable. + * Check for the target support and assemble the rate code accordingly. + * + * Return: assembled rate code + */ +int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate); + +/** + * hdd_update_country_code - Update country code + * @hdd_ctx: HDD context + * + * Update country code based on module parameter country_code + * + * Return: 0 on success and errno on failure + */ +int hdd_update_country_code(struct hdd_context *hdd_ctx); + +/** + * hdd_set_11ax_rate() - set 11ax rate + * @adapter: adapter being modified + * @value: new 11ax rate code + * @sap_config: pointer to SAP config to check HW mode + * this will be NULL for call from STA persona + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_11ax_rate(struct hdd_adapter *adapter, int value, + struct sap_config *sap_config); + +/** + * hdd_update_hw_sw_info() - API to update the HW/SW information + * @hdd_ctx: Global HDD context + * + * API to update the HW and SW information in the driver + * + * Note: + * All the version/revision information would only be retrieved after + * firmware download + * + * Return: None + */ +void hdd_update_hw_sw_info(struct hdd_context *hdd_ctx); + +/** + * hdd_context_get_mac_handle() - get mac handle from hdd context + * @hdd_ctx: Global HDD context pointer + * + * Retrieves the global MAC handle from the HDD context + * + * Return: The global MAC handle (which may be NULL) + */ +static inline +mac_handle_t hdd_context_get_mac_handle(struct hdd_context *hdd_ctx) +{ + return hdd_ctx ? hdd_ctx->mac_handle : NULL; +} + +/** + * hdd_adapter_get_mac_handle() - get mac handle from hdd adapter + * @adapter: HDD adapter pointer + * + * Retrieves the global MAC handle given an HDD adapter + * + * Return: The global MAC handle (which may be NULL) + */ +static inline +mac_handle_t hdd_adapter_get_mac_handle(struct hdd_adapter *adapter) +{ + return adapter ? + hdd_context_get_mac_handle(adapter->hdd_ctx) : NULL; +} + +/** + * hdd_handle_to_context() - turn an HDD handle into an HDD context + * @hdd_handle: HDD handle to be converted + * + * Return: HDD context referenced by @hdd_handle + */ +static inline +struct hdd_context *hdd_handle_to_context(hdd_handle_t hdd_handle) +{ + return (struct hdd_context *)hdd_handle; +} + +/** + * wlan_hdd_free_cache_channels() - Free the cache channels list + * @hdd_ctx: Pointer to HDD context + * + * Return: None + */ +void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx); + +/** + * hdd_update_dynamic_mac() - Updates the dynamic MAC list + * @hdd_ctx: Pointer to HDD context + * @curr_mac_addr: Current interface mac address + * @new_mac_addr: New mac address which needs to be updated + * + * This function updates newly configured MAC address to the + * dynamic MAC address list corresponding to the current + * adapter MAC address + * + * Return: None + */ +void hdd_update_dynamic_mac(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *curr_mac_addr, + struct qdf_mac_addr *new_mac_addr); + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * hdd_md_host_evt_cb - Callback for Motion Detection Event + * @ctx: HDD context + * @event: motion detect event + * + * Callback for Motion Detection Event. Re-enables Motion + * Detection again upon event + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and + * QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS hdd_md_host_evt_cb(void *ctx, struct sir_md_evt *event); + +/** + * hdd_md_bl_evt_cb - Callback for Motion Detection Baseline Event + * @ctx: HDD context + * @event: motion detect baseline event + * + * Callback for Motion Detection Baseline Event + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and + * QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS hdd_md_bl_evt_cb(void *ctx, struct sir_md_bl_evt *event); +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +/** + * hdd_hidden_ssid_enable_roaming() - enable roaming after hidden ssid rsp + * @hdd_handle: Hdd handler + * @vdev_id: Vdev Id + * + * This is a wrapper function to enable roaming after getting hidden + * ssid rsp + */ +void hdd_hidden_ssid_enable_roaming(hdd_handle_t hdd_handle, uint8_t vdev_id); + +/** + * hdd_psoc_idle_shutdown - perform idle shutdown after interface inactivity + * timeout + * @dev: pointer to struct device + * + * Return: 0 for success non-zero error code for failure + */ +int hdd_psoc_idle_shutdown(struct device *dev); + +/** + * hdd_psoc_idle_restart - perform idle restart after idle shutdown + * @dev: pointer to struct device + * + * Return: 0 for success non-zero error code for failure + */ +int hdd_psoc_idle_restart(struct device *dev); + +/** + * hdd_adapter_is_ap() - whether adapter is ap or not + * @adapter: adapter to check + * Return: true if it is AP + */ +bool hdd_adapter_is_ap(struct hdd_adapter *adapter); + +/** + * hdd_common_roam_callback() - common sme roam callback + * @psoc: Object Manager Psoc + * @session_id: session id for which callback is called + * @roam_info: pointer to roam info + * @roam_status: roam status + * @roam_result: roam result + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_common_roam_callback(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); + +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * wlan_hdd_is_mon_concurrency() - check if MONITOR and STA concurrency + * is UP when packet capture mode is enabled. + * + * Return: True - if STA and monitor concurrency is there, else False + * + */ +bool wlan_hdd_is_mon_concurrency(void); + +/** + * wlan_hdd_del_monitor() - delete monitor interface + * @hdd_ctx: pointer to hdd context + * @adapter: adapter to be deleted + * @rtnl_held: rtnl lock held + * + * This function is invoked to delete monitor interface. + * + * Return: None + */ +void wlan_hdd_del_monitor(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held); + +/** + * wlan_hdd_del_p2p_interface() - delete p2p interface + * @hdd_ctx: pointer to hdd context + * + * This function is invoked to delete p2p interface. + * + * Return: None + */ +void +wlan_hdd_del_p2p_interface(struct hdd_context *hdd_ctx); + +/** + * hdd_reset_monitor_interface() - reset monitor interface flags + * @sta_adapter: station adapter + * + * Return: void + */ +void hdd_reset_monitor_interface(struct hdd_adapter *sta_adapter); + +/** + * hdd_is_pkt_capture_mon_enable() - Is packet capture monitor mode enable + * @sta_adapter: station adapter + * + * Return: status of packet capture monitor adapter + */ +struct hdd_adapter * +hdd_is_pkt_capture_mon_enable(struct hdd_adapter *sta_adapter); +#else +static inline +void wlan_hdd_del_monitor(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held) +{ +} + +static inline +bool wlan_hdd_is_mon_concurrency(void) +{ + return false; +} + +static inline +void wlan_hdd_del_p2p_interface(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_reset_monitor_interface(struct hdd_adapter *sta_adapter) +{ +} + +static inline int hdd_is_pkt_capture_mon_enable(struct hdd_adapter *adapter) +{ + return 0; +} +#endif /* WLAN_FEATURE_PKT_CAPTURE */ +/** + * wlan_hdd_is_session_type_monitor() - check if session type is MONITOR + * @session_type: session type + * + * Return: True - if session type for adapter is monitor, else False + * + */ +bool wlan_hdd_is_session_type_monitor(uint8_t session_type); + +/** + * wlan_hdd_add_monitor_check() - check for monitor intf and add if needed + * @hdd_ctx: pointer to hdd context + * @adapter: output pointer to hold created monitor adapter + * @name: name of the interface + * @rtnl_held: True if RTNL lock is held + * @name_assign_type: the name of assign type of the netdev + * @is_rx_mon: if monitor mode is getting enabled + * + * Return: 0 - on success + * err code - on failure + */ +int wlan_hdd_add_monitor_check(struct hdd_context *hdd_ctx, + struct hdd_adapter **adapter, + const char *name, bool rtnl_held, + unsigned char name_assign_type, + bool is_rx_mon); + +#ifdef CONFIG_WLAN_DEBUG_CRASH_INJECT +/** + * hdd_crash_inject() - Inject a crash + * @adapter: Adapter upon which the command was received + * @v1: first value to inject + * @v2: second value to inject + * + * This function is the handler for the crash inject debug feature. + * This feature only exists for internal testing and must not be + * enabled on a production device. + * + * Return: 0 on success and errno on failure + */ +int hdd_crash_inject(struct hdd_adapter *adapter, uint32_t v1, uint32_t v2); +#else +static inline +int hdd_crash_inject(struct hdd_adapter *adapter, uint32_t v1, uint32_t v2) +{ + return -ENOTSUPP; +} +#endif + +#ifdef FEATURE_MONITOR_MODE_SUPPORT + +void hdd_sme_monitor_mode_callback(uint8_t vdev_id); + +QDF_STATUS hdd_monitor_mode_vdev_status(struct hdd_adapter *adapter); + +QDF_STATUS hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter, + uint8_t session_type); +#else +static inline void hdd_sme_monitor_mode_callback(uint8_t vdev_id) {} + +static inline QDF_STATUS +hdd_monitor_mode_vdev_status(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter, + uint8_t session_type) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_cleanup_conn_info() - Cleanup connectin info + * @link_info: pointer to link_info struct in adapter + * + * This function frees the memory allocated for the connection + * info structure + * + * Return: none + */ +void hdd_cleanup_conn_info(struct wlan_hdd_link_info *link_info); + +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +extern char *country_code; +extern int con_mode; +extern const struct kernel_param_ops con_mode_ops; +extern int con_mode_ftm; +extern const struct kernel_param_ops con_mode_ftm_ops; +#endif + +/** + * hdd_driver_load() - Perform the driver-level load operation + * + * Note: this is used in both static and DLKM driver builds + * + * Return: Errno + */ +int hdd_driver_load(void); + +/** + * hdd_driver_unload() - Performs the driver-level unload operation + * + * Note: this is used in both static and DLKM driver builds + * + * Return: None + */ +void hdd_driver_unload(void); + +/** + * hdd_init_start_completion() - Init the completion variable to wait on ON/OFF + * + * Return: None + */ +void hdd_init_start_completion(void); + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) +/** + * hdd_beacon_latency_event_cb() - Callback function to get latency level + * @latency_level: latency level received from firmware + * + * Return: None + */ +void hdd_beacon_latency_event_cb(uint32_t latency_level); +#else +static inline void hdd_beacon_latency_event_cb(uint32_t latency_level) +{ +} +#endif + +#if defined(CLD_PM_QOS) || defined(FEATURE_RUNTIME_PM) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +/** + * wlan_hdd_get_default_pm_qos_cpu_latency() - get default PM QOS CPU latency + * + * Return: PM QOS CPU latency value + */ +static inline unsigned long wlan_hdd_get_default_pm_qos_cpu_latency(void) +{ + return PM_QOS_CPU_LATENCY_DEFAULT_VALUE; +} +#else +static inline unsigned long wlan_hdd_get_default_pm_qos_cpu_latency(void) +{ + return PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE; +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */ +#endif /* defined(CLD_PM_QOS) || defined(FEATURE_RUNTIME_PM) */ + +/** + * hdd_get_wifi_standard() - Get wifi standard + * @hdd_ctx: hdd context pointer + * @dot11_mode: hdd dot11 mode + * @band_capability: band capability bitmap + * + * Return: WMI_HOST_WIFI_STANDARD + */ +WMI_HOST_WIFI_STANDARD +hdd_get_wifi_standard(struct hdd_context *hdd_ctx, + enum hdd_dot11_mode dot11_mode, uint32_t band_capability); + +/** + * hdd_is_runtime_pm_enabled - if runtime pm enabled + * @hdd_ctx: hdd context + * + * Return: true if runtime pm enabled. false if disabled. + */ +bool hdd_is_runtime_pm_enabled(struct hdd_context *hdd_ctx); + +/** + * hdd_netdev_update_features() - Update the netdev features + * @adapter: adapter associated with the net_device + * + * This func holds the rtnl_lock. Do not call with rtnl_lock held. + * + * Return: None + */ +void hdd_netdev_update_features(struct hdd_adapter *adapter); + +/** + * hdd_stop_no_trans() - HDD stop function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig down. Vdev sync transaction + * should be started before calling this API. + * + * Return: 0 for success; non-zero for failure + */ +int hdd_stop_no_trans(struct net_device *dev); + +#if defined(CLD_PM_QOS) +/** + * wlan_hdd_set_pm_qos_request() - Function to set pm_qos config in wlm mode + * @hdd_ctx: HDD context + * @pm_qos_request: pm_qos_request flag + * + * Return: None + */ +void wlan_hdd_set_pm_qos_request(struct hdd_context *hdd_ctx, + bool pm_qos_request); +#else +static inline +void wlan_hdd_set_pm_qos_request(struct hdd_context *hdd_ctx, + bool pm_qos_request) +{ +} +#endif + +/** + * hdd_nl80211_chwidth_to_chwidth - Get sir chan width from nl chan width + * @nl80211_chwidth: enum nl80211_chan_width + * + * Return: enum eSirMacHTChannelWidth or -INVAL for unsupported nl chan width + */ +enum eSirMacHTChannelWidth +hdd_nl80211_chwidth_to_chwidth(uint8_t nl80211_chwidth); + +/** + * hdd_chwidth_to_nl80211_chwidth - Get nl chan width from sir chan width + * @chwidth: enum eSirMacHTChannelWidth + * + * Return: enum nl80211_chan_width or 0xFF for unsupported sir chan width + */ +uint8_t hdd_chwidth_to_nl80211_chwidth(enum eSirMacHTChannelWidth chwidth); + +/** + * hdd_phy_chwidth_to_nl80211_chwidth() - Get nl chan width from phy chan width + * @chwidth: enum phy_ch_width + * + * Return: enum nl80211_chan_width or 0xFF for unsupported phy chan width + */ +uint8_t hdd_phy_chwidth_to_nl80211_chwidth(enum phy_ch_width chwidth); + +/** + * wlan_hdd_get_channel_bw() - get channel bandwidth + * @width: input channel width in nl80211_chan_width value + * + * Return: channel width value defined by driver + */ +enum hw_mode_bandwidth wlan_hdd_get_channel_bw(enum nl80211_chan_width width); + +/** + * hdd_ch_width_str() - Get string for channel width + * @ch_width: channel width from connect info + * + * Return: User readable string for channel width + */ +uint8_t *hdd_ch_width_str(enum phy_ch_width ch_width); + +/** + * hdd_we_set_ch_width - Function to update channel width + * @link_info: Link info pointer in HDD adapter. + * @ch_width: enum eSirMacHTChannelWidth + * + * Return: 0 for success otherwise failure + */ +int hdd_we_set_ch_width(struct wlan_hdd_link_info *link_info, int ch_width); + +/** + * hdd_stop_adapter_ext: close/delete the vdev session in host/fw. + * @hdd_ctx: HDD context + * @adapter: Pointer to hdd_adapter + * + * Close/delete the vdev session in host/firmware. + */ +QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +/** + * hdd_check_for_net_dev_ref_leak: check for vdev reference leak in driver + * @adapter: Pointer to hdd_adapter + * + * various function take netdev reference to get protected against netdev + * getting deleted in parallel, check if all those references are cleanly + * released. + */ +void hdd_check_for_net_dev_ref_leak(struct hdd_adapter *adapter); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) + +/** + * hdd_link_switch_vdev_mac_addr_update() - API to update OSIF/HDD on VDEV + * mac addr update due to link switch. + * @ieee_old_link_id: Current IEEE link ID of VDEV prior to link switch + * @ieee_new_link_id: New IEEE link ID of VDEV post link switch + * @vdev_id: VDEV undergoing link switch. + * + * Check if both @ieee_old_link_id and @ieee_new_link_id are part of adapter + * corresponding to @vdev_id. Then take necessary actions to support link switch + * MAC update and update DP to change link MAC address to new link's address. + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_link_switch_vdev_mac_addr_update(int32_t ieee_old_link_id, + int32_t ieee_new_link_id, uint8_t vdev_id); + +/** + * hdd_get_link_info_by_ieee_link_id() - Find link info pointer matching with + * IEEE link ID. + * @adapter: HDD adapter + * @link_id: IEEE link ID to search for. + * + * Search the station ctx connection info for matching link ID in @adapter and + * return the link info pointer on match. The IEEE link ID is updated in station + * context during MLO connection and reset on disconnection. + * + * Return: link info pointer + */ +struct wlan_hdd_link_info * +hdd_get_link_info_by_ieee_link_id(struct hdd_adapter *adapter, int32_t link_id); +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +/** + * hdd_dynamic_mac_address_set(): API to set MAC address, when interface + * is up. + * @link_info: Link info pointer in HDD adapter + * @mac_addr: MAC address to set + * @mld_addr: MLD address to set + * @update_self_peer: Set to true to update self peer's address + * + * This API is used to update the current VDEV MAC address. + * + * Return: 0 for success. non zero valure for failure. + */ +int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + bool update_self_peer); + +/** + * hdd_is_dynamic_set_mac_addr_allowed() - API to check dynamic MAC address + * update is allowed or not + * @adapter: Pointer to the adapter structure + * + * Return: true or false + */ +bool hdd_is_dynamic_set_mac_addr_allowed(struct hdd_adapter *adapter); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * hdd_update_vdev_mac_address() - Update VDEV MAC address dynamically + * @adapter: Pointer to HDD adapter + * @mac_addr: MAC address to be updated + * + * API to update VDEV MAC address during interface is in UP state. + * + * Return: 0 for Success. Error code for failure + */ +int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr); +#else +static inline int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + return hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, + mld_addr, true); +} +#endif /* WLAN_FEATURE_11BE_MLO */ +#else +static inline int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + return 0; +} + +static inline int +hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + bool update_self_peer) +{ + return 0; +} + +static inline bool +hdd_is_dynamic_set_mac_addr_allowed(struct hdd_adapter *adapter) +{ + return false; +} + +#endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */ + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && \ +defined(FEATURE_RX_LINKSPEED_ROAM_TRIGGER) +/** + * wlan_hdd_link_speed_update() - Update link speed to F/W + * @psoc: pointer to soc + * @vdev_id: Vdev ID + * @is_link_speed_good: true means good link speed, false means bad link speed + * + * Return: None + */ +void wlan_hdd_link_speed_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good); +#else +static inline void wlan_hdd_link_speed_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good) +{} +#endif + +/** + * hdd_update_multicast_list() - update the multicast list + * @vdev: pointer to VDEV object + * + * Return: none + */ +void hdd_update_multicast_list(struct wlan_objmgr_vdev *vdev); + +/** + * hdd_set_sar_init_index() - Set SAR safety index at init. + * @hdd_ctx: HDD context + * + */ +#ifdef SAR_SAFETY_FEATURE +void hdd_set_sar_init_index(struct hdd_context *hdd_ctx); +#else +static inline void hdd_set_sar_init_index(struct hdd_context *hdd_ctx) +{} +#endif +/** + * hdd_send_coex_traffic_shaping_mode() - Send coex traffic shaping mode + * to FW + * @vdev_id: vdev ID + * @mode: traffic shaping mode + * + * This function is used to send coex traffic shaping mode to FW + * + * Return: 0 on success and -EINVAL on failure + */ +int hdd_send_coex_traffic_shaping_mode(uint8_t vdev_id, uint8_t mode); + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +/** + * wlan_hdd_lpc_handle_concurrency() - Handle local packet capture + * concurrency scenario + * @hdd_ctx: hdd_ctx + * @is_virtual_iface: is virtual interface + * + * This function takes care of handling concurrency scenario + * If STA+Mon present and SAP is coming up, terminate Mon and let SAP come up + * If STA+Mon present and P2P is coming up, terminate Mon and let P2P come up + * If STA+Mon present and NAN is coming up, terminate Mon and let NAN come up + * + * Return: none + */ +void wlan_hdd_lpc_handle_concurrency(struct hdd_context *hdd_ctx, + bool is_virtual_iface); + +/** + * hdd_lpc_is_work_scheduled() - function to return if lpc wq scheduled + * @hdd_ctx: hdd_ctx + * + * Return: true if scheduled; false otherwise + */ +bool hdd_lpc_is_work_scheduled(struct hdd_context *hdd_ctx); + +#else +static inline void +wlan_hdd_lpc_handle_concurrency(struct hdd_context *hdd_ctx, + bool is_virtual_iface) +{} + +static inline bool +hdd_lpc_is_work_scheduled(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +/** + * hdd_allow_new_intf() - Allow new intf created or not + * @hdd_ctx: hdd context + * @mode: qdf opmode of new interface + * + * Return: true if allowed, otherwise false + */ +bool hdd_allow_new_intf(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode); + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * wlan_hdd_is_link_switch_in_progress() - Function to check if there is any + * link switch in progress + * @link_info: Link info pointer in HDD adapter + * + * Return: true if link switch in progress, false otherwise + */ +bool wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info); +#else +static inline bool +wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info) +{ + return false; +} +#endif + +/** + * wlan_hdd_is_mlo_connection() - Check if connection is legacy or mlo + * @link_info: Link info pointer in HDD adapter + * + * Return: True if MLO connection, else False + */ +bool wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info *link_info); +#endif /* end #if !defined(WLAN_HDD_MAIN_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mdns_offload.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mdns_offload.h new file mode 100644 index 0000000000..ca609ad619 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mdns_offload.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mdns_offload.h + * + * WLAN Host Device Driver MDNS Offload interface implementation. + */ + +#ifndef __WLAN_HDD_MDNS_OFFLOAD_H +#define __WLAN_HDD_MDNS_OFFLOAD_H + +#include +#include +#include + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD +extern const struct nla_policy +wlan_hdd_set_mdns_offload_policy[QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1]; + +#define FEATURE_MDNS_OFFLOAD_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MDNS_OFFLOAD, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_mdns_offload, \ + vendor_command_policy(wlan_hdd_set_mdns_offload_policy, \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX) \ +}, + +int wlan_hdd_cfg80211_set_mdns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +#else +#define FEATURE_MDNS_OFFLOAD_VENDOR_COMMANDS +static inline void wlan_hdd_cfg80211_set_mdns_offload(void) {} +#endif +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h new file mode 100644 index 0000000000..2ca6877f98 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_misc.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2012-2014,2016-2017,2019, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_HDD_MISC_H +#define WLAN_HDD_MISC_H +/* + * To prevent name conflicts when loading different instances of the driver: + * + * If DYNAMIC_SINGLE_CHIP is defined, which means there are multiple possible + * drivers, but only one instance of driver at a time(WLAN dynamic detect), + * prepend DYNAMIC_SINGLE_CHIP to the filenames. + * + * Otherwise, if MULTI_IF_NAME is defined, which means there are multiple + * instances of the driver with different module names, prepend MULTI_IF_NAME + * to the filenames. + */ +#ifdef DYNAMIC_SINGLE_CHIP +#define PREFIX DYNAMIC_SINGLE_CHIP "/" +#else + +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME "/" +#else +#define PREFIX "" +#endif + +#endif + +#ifdef MSM_PLATFORM +#define WLAN_INI_FILE "wlan/qca_cld/" PREFIX "WCNSS_qcom_cfg.ini" +#define WLAN_MAC_FILE "wlan/qca_cld/" PREFIX "wlan_mac.bin" +#else +#define WLAN_INI_FILE "wlan/" PREFIX "qcom_cfg.ini" +#define WLAN_MAC_FILE "wlan/" PREFIX "wlan_mac.bin" +#endif /* MSM_PLATFORM */ + +#define WLAN_CONNECTION_ROAMING_INI_FILE "wlan-connection-roaming.ini" +#define WLAN_CONNECTION_ROAMING_BACKUP_INI_FILE "wlan-connection-roaming-backup.ini" + +#endif /* WLAN_HDD_MISC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mlo.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mlo.h new file mode 100644 index 0000000000..e1754f0312 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mlo.h @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mlo.h + * + * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) + * support. + * + */ +#if !defined(WLAN_HDD_MLO_H) +#define WLAN_HDD_MLO_H +#include +#include "wlan_osif_features.h" + +/** + * struct hdd_adapter_create_param - adapter create parameters + * @only_wdev_register: Register only the wdev not the netdev + * @associate_with_ml_adapter: Vdev points to the same netdev adapter + * @is_ml_adapter: is a ml adapter with associated netdev + * @is_add_virtual_iface: is netdev create request from add virtual interface + * @is_single_link: Is the adapter single link ML + * @num_sessions: No of session to create on start adapter + * @is_pre_cac_adapter: is a pre cac adapter with associated netdev + * @unused: Reserved spare bits + */ +struct hdd_adapter_create_param { + uint32_t only_wdev_register:1, + associate_with_ml_adapter:1, + is_ml_adapter:1, + is_add_virtual_iface:1, + is_single_link:1, + num_sessions:4, + is_pre_cac_adapter:1, + unused:22; +}; + +#ifdef WLAN_FEATURE_11BE_MLO +#define MAX_SIMULTANEOUS_STA_ML_LINKS 1 +#define MAX_NUM_STA_ML_LINKS 3 +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#define hdd_adapter_is_ml_adapter(x) ((x)->mlo_adapter_info.is_ml_adapter) + +/* MLO_STATE_COMMANDS */ +#define FEATURE_ML_LINK_STATE_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MLO_LINK_STATE,\ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_process_ml_link_state, \ + vendor_command_policy(ml_link_state_request_policy, \ + QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX) \ + }, + +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +#define hdd_adapter_is_link_adapter(x) ((x)->mlo_adapter_info.is_link_adapter) +#define hdd_adapter_is_sl_ml_adapter(x) \ + ((x)->mlo_adapter_info.is_single_link_ml) +#define hdd_adapter_is_associated_with_ml_adapter(x) \ + ((x)->mlo_adapter_info.associate_with_ml_adapter) +#define hdd_adapter_get_mlo_adapter_from_link(x) \ + ((x)->mlo_adapter_info.ml_adapter) + +#else +#define hdd_adapter_is_link_adapter(x) (0) +#define hdd_adapter_is_sl_ml_adapter(x) (0) +#define hdd_adapter_is_associated_with_ml_adapter(x) (0) +#define hdd_adapter_get_mlo_adapter_from_link(x) (NULL) +#endif /* WLAN_HDD_MULTI_VDEV_SINGLE_NDEV */ +#else +#define hdd_adapter_is_link_adapter(x) (0) +#define hdd_adapter_is_ml_adapter(x) (0) +#define hdd_adapter_is_sl_ml_adapter(x) (0) +#define hdd_adapter_is_associated_with_ml_adapter(x) (0) +#define hdd_adapter_get_mlo_adapter_from_link(x) (NULL) +#endif /* WLAN_FEATURE_11BE_MLO && CFG80211_11BE_BASIC */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +/** + * struct hdd_mlo_adapter_info - Mlo specific adapter information + * @is_ml_adapter: Whether this is the main ml adaper attached to netdev + * @is_link_adapter: Whether this a link adapter without netdev + * @associate_with_ml_adapter: adapter which shares the vdev object with the ml + * adapter + * @num_of_vdev_links: Num of vdevs/links part of the association + * @is_single_link_ml: Is the adapter a single link ML adapter + * @unused: Reserved spare bits + * @ml_adapter: ML adapter backpointer + * @link_adapter: backpointers to link adapters part of association + */ +struct hdd_mlo_adapter_info { + uint32_t is_ml_adapter:1, + is_link_adapter:1, + associate_with_ml_adapter:1, + num_of_vdev_links:2, + is_single_link_ml:1, + unused:26; + struct hdd_adapter *ml_adapter; + struct hdd_adapter *link_adapter[WLAN_MAX_MLD]; +}; +#else +struct hdd_mlo_adapter_info { + uint32_t is_ml_adapter:1, + unused:31; +}; +#endif +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + !defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +/** + * hdd_register_wdev() - Function to register only wdev + * @sta_adapter : Station adapter linked with netdevice + * @link_adapter: Link adapter + * @adapter_params: Adapter params + * + * Function to register only the wdev not the netdev + * Return: none + */ +void hdd_register_wdev(struct hdd_adapter *sta_adapter, + struct hdd_adapter *link_adapter, + struct hdd_adapter_create_param *adapter_params); +/** + * hdd_wlan_unregister_mlo_interfaces() - Function to unregister mlo + * interfaces + * @adapter: Link adapter + * @rtnl_held: RTNL held or not + * + * Function to unregister only the link adapter/wdev. + * Return: none + */ +QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter, + bool rtnl_held); +/** + * hdd_wlan_register_mlo_interfaces() - Function to register mlo wdev interfaces + * @hdd_ctx: hdd context + * + * Function to register mlo wdev interfaces. + * Return: none + */ +void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx); + +/** + * hdd_get_assoc_link_adapter() - get assoc link adapter + * @ml_adapter: ML adapter + * + * This function returns assoc link adapter. + * For single link ML adapter, function returns + * same adapter pointer. + * + * Return: adapter or NULL + */ +struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter); + +/** + * hdd_adapter_set_sl_ml_adapter() - Set adapter as sl ml adapter + * @adapter: HDD adapter + * + * This function sets adapter as single link ML adapter + * Return: None + */ +void hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter); + +/** + * hdd_adapter_clear_sl_ml_adapter() - Set adapter as sl ml adapter + * @adapter: HDD adapter + * + * This function clears adapter single link ML adapter flag + * Return: None + */ +void hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter); + +/** + * hdd_get_ml_adapter() - get an ml adapter + * @hdd_ctx: HDD context + * + * This function returns ml adapter from adapter list + * Return: adapter or NULL + */ +struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx); + +#else +static inline +QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter, + bool rtnl_held) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_register_wdev(struct hdd_adapter *sta_adapter, + struct hdd_adapter *link_adapter, + struct hdd_adapter_create_param *adapter_params) +{ +} + +static inline +struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter) +{ + return NULL; +} + +static inline void +hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter) +{ +} + +static inline void +hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter) +{ +} + +static inline +struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx) +{ + return NULL; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * hdd_adapter_set_ml_adapter() - set adapter as ml adapter + * @adapter: HDD adapter + * + * This function sets adapter as ml adapter + * Return: None + */ +void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter); + +/** + * hdd_adapter_link_switch_notification() - Get HDD notification on link switch + * start. + * @vdev: VDEV on which link switch will happen + * @non_trans_vdev_id: VDEV not part of link switch. + * + * Return: QDF_STATUS. + */ +QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev, + uint8_t non_trans_vdev_id); + +/** + * hdd_mlo_t2lm_register_callback() - Register T2LM callback + * @vdev: Pointer to vdev + * + * Return: None + */ +void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev); + +/** + * hdd_mlo_t2lm_unregister_callback() - Unregister T2LM callback + * @vdev: Pointer to vdev + * + * Return: None + */ +void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_handle_mlo_link_state_operation() - mlo link state operation + * @adapter: HDD adapter + * @wiphy: wiphy pointer + * @vdev: vdev handler + * @hdd_ctx: hdd context + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Based on the data get or set the mlo link state + * + * Return: 0 on success and error number otherwise. + */ +int wlan_handle_mlo_link_state_operation(struct hdd_adapter *adapter, + struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + const void *data, int data_len); + +extern const struct nla_policy +ml_link_state_request_policy[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1]; + +/** + * wlan_hdd_send_t2lm_event() - Send t2lm info to userspace + * @vdev: vdev handler + * @t2lm: tid to link mapping info + * + * This function is called when driver needs to send vendor specific + * t2lm info to userspace + */ +QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm); + +/** + * wlan_hdd_cfg80211_process_ml_link_state() - process ml link state + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Set (or) get the ml link state. + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +/** + * hdd_update_link_state_cached_timestamp() - update link state cached timestamp + * @adapter: HDD adapter + * + * Return: none + */ +void hdd_update_link_state_cached_timestamp(struct hdd_adapter *adapter); + +/** + * hdd_derive_link_address_from_mld() - Function to derive link address from + * MLD address which is passed as input argument. + * @psoc: PSOC object manager + * @mld_addr: Input MLD address + * @link_addr_list: Start index of array to hold derived MAC addresses + * @max_idx: Number of addresses to derive + * + * The API will generate link addresses from the input MLD address and saves + * each link address as an array in @link_addr_list. + * + * If CFG_MLO_SAME_LINK_MLD_ADDR is enabled, then API will not derive first + * link address and will use MLD address in that place. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *mld_addr, + struct qdf_mac_addr *link_addr_list, + uint8_t max_idx); + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +/** + * hdd_adapter_restore_link_vdev_map() - Change the VDEV to link info mapping + * in adapter. + * @adapter: HDD adapter pointer + * @same_vdev_mac_map: Maintain VDEV to MAC address mapping during the restore. + * + * This API restores the VDEV to HDD link info mapping to its initial order + * which could have got remapped in the process of link switch. If + * @same_vdev_mac_map is set to %true then the MAC address to VDEV mapping is + * preserved. + * + * Returns: %true if any mapping changes or %false otherwise. + */ +bool hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter, + bool same_vdev_mac_map); + +/** + * hdd_mlo_mgr_register_osif_ops() - Register OSIF ops with global MLO manager + * for callback to notify. + * + * The @ops contain callback functions which are triggered to update OSIF about + * necessary events from MLO manager. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_mlo_mgr_register_osif_ops(void); + +/** + * hdd_mlo_mgr_unregister_osif_ops() - Deregister OSIF ops with + * global MLO manager + * + * Deregister the calbacks registered with global MLO manager for OSIF + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void); +#else +static inline bool +hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter, + bool same_vdev_mac_map) +{ + return false; +} + +static inline QDF_STATUS hdd_mlo_mgr_register_osif_ops(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#else +static inline void +hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter) +{ +} + +static inline QDF_STATUS hdd_mlo_mgr_register_osif_ops(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline int +wlan_handle_mlo_link_state_operation(struct hdd_adapter *adapter, + struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + const void *data, int data_len) +{ + return 0; +} + +static inline +int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} + +static inline +QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *mld_addr, + struct qdf_mac_addr *link_addr_list, + uint8_t max_idx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +void hdd_update_link_state_cached_timestamp(struct hdd_adapter *adapter) +{ +} + +#define FEATURE_ML_LINK_STATE_COMMANDS +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mpta_helper.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mpta_helper.h new file mode 100644 index 0000000000..1c6b524e58 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_mpta_helper.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mpta_helper.h + * + * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG + */ + +#ifndef __WLAN_HDD_MPTA_HELPER_H +#define __WLAN_HDD_MPTA_HELPER_H + +#include "wlan_fw_offload_main.h" + +#ifdef FEATURE_MPTA_HELPER +#include + +/** + * wlan_hdd_mpta_helper_enable() - enable/disable mpta helper + * according to cfg from INI + * @coex_cfg_params: pointer of coex config command params + * @config: pointer of BTC config items + * + * Return: 0 on success; error number otherwise. + * + */ +int +wlan_hdd_mpta_helper_enable(struct coex_config_params *coex_cfg_params, + struct wlan_fwol_coex_config *config); + +/** + * wlan_hdd_cfg80211_mpta_helper_config() - update + * tri-radio coex status by mpta helper + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 on success; error number otherwise. + * + */ +int wlan_hdd_cfg80211_mpta_helper_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +extern const struct nla_policy +qca_wlan_vendor_mpta_helper_attr[QCA_MPTA_HELPER_VENDOR_ATTR_MAX + 1]; + +#define FEATURE_MPTA_HELPER_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG,\ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_mpta_helper_config, \ + vendor_command_policy(qca_wlan_vendor_mpta_helper_attr, \ + QCA_MPTA_HELPER_VENDOR_ATTR_MAX) \ +}, + +#else /* FEATURE_MPTA_HELPER */ +#define FEATURE_MPTA_HELPER_COMMANDS + +static inline int +wlan_hdd_mpta_helper_enable(struct coex_config_params *coex_cfg_params, + struct wlan_fwol_coex_config *config) +{ + return 0; +} + +#endif /* FEATURE_MPTA_HELPER */ + +#endif /* __WLAN_HDD_MPTA_HELPER_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h new file mode 100644 index 0000000000..e2bf0435d2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_nan.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_NAN_H +#define __WLAN_HDD_NAN_H + +/** + * DOC: wlan_hdd_nan.h + * + * WLAN Host Device Driver NAN API specification + */ + +struct hdd_context; + +#ifdef WLAN_FEATURE_NAN +struct wiphy; +struct wireless_dev; + +bool wlan_hdd_nan_is_supported(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_cfg80211_nan_ext_request() - handle NAN Extended request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to send a NAN request to + * firmware. This is an SSR-protected wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_nan_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#ifdef WLAN_FEATURE_SR +/** + * hdd_nan_sr_concurrency_update() - NAN Spatial Reuse concurrency + * @nan_evt: nan event params + * + * Return: None + */ +void hdd_nan_sr_concurrency_update(struct nan_event_params *nan_evt); +#endif +#define FEATURE_NAN_VENDOR_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN_EXT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_nan_ext_request, \ + vendor_command_policy(nan_attr_policy, \ + QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX) \ + }, \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NDP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_process_ndp_cmd, \ + vendor_command_policy(vendor_attr_policy, \ + QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX) \ + }, + +#else /* WLAN_FEATURE_NAN */ +#define FEATURE_NAN_VENDOR_COMMANDS + +static inline bool wlan_hdd_nan_is_supported(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif /* WLAN_FEATURE_NAN */ + +/** + * hdd_nan_concurrency_update() - NAN concurrency + * + * Return: None + */ +void hdd_nan_concurrency_update(void); + +#endif /* __WLAN_HDD_NAN_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h new file mode 100644 index 0000000000..dfd30fff55 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_napi.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __HDD_NAPI_H__ +#define __HDD_NAPI_H__ + +#ifdef FEATURE_NAPI +/** + * DOC: wlan_hdd_napi.h + * + * WLAN NAPI interface module headers + */ + +/* CLD headers */ +#include "hif_napi.h" + +/* Linux headers */ +#include /* net_device */ + +struct hdd_context; + +#define HDD_NAPI_ANY (-1) + +int hdd_napi_enabled(int id); +int hdd_napi_create(void); +int hdd_napi_destroy(int force); +int hdd_display_napi_stats(void); +int hdd_clear_napi_stats(void); + +/* the following triggers napi_enable/disable as required */ +int hdd_napi_event(enum qca_napi_event event, void *data); + +int hdd_napi_poll(struct napi_struct *napi, int budget); + +struct qca_napi_data *hdd_napi_get_all(void); + +#if defined HELIUMPLUS && defined MSM_PLATFORM +int hdd_napi_apply_throughput_policy(struct hdd_context *hddctx, + uint64_t tx_packets, + uint64_t rx_packets); +int hdd_napi_serialize(int is_on); +#else +static inline int hdd_napi_apply_throughput_policy(struct hdd_context *hddctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + return 0; +} +static inline int hdd_napi_serialize(int is_on) +{ + return -EINVAL; +} +#endif /* HELIUMPLUS && MSM_PLATFORM */ + +#else /* ! defined(FEATURE_NAPI) */ +#include "hif_napi.h" +/* + * Stub API + * + */ + +#define HDD_NAPI_ANY (-1) + +static inline int hdd_napi_enabled(int id) { return 0; } +static inline int hdd_napi_create(void) { return 0; } +static inline int hdd_napi_destroy(int force) { return 0; } +static inline int hdd_display_napi_stats(void) { return 0; } +static inline int hdd_clear_napi_stats(void) { return 0; } +static inline int hdd_napi_event(enum qca_napi_event event, void *data) +{ + return 0; +} +static inline struct qca_napi_data *hdd_napi_get_all(void) { return NULL; } +static inline int hdd_napi_apply_throughput_policy(void *hdd_ctx, + uint64_t tx_packets, uint64_t rx_packets) +{ + return 0; +} + +static inline int hdd_napi_serialize(int is_on) +{ + return -EINVAL; +} +#endif /* FEATURE_NAPI */ + +#endif /* HDD_NAPI_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h new file mode 100644 index 0000000000..557d435f8a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_oemdata.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_oemdata.h + * + * Internal includes for the oem data + */ + +#ifndef __WLAN_HDD_OEM_DATA_H__ +#define __WLAN_HDD_OEM_DATA_H__ + +#include "wmi_unified_param.h" + +struct hdd_context; + +#ifdef FEATURE_OEM_DATA +#define WLAN_WAIT_TIME_GET_OEM_DATA 1000 +#endif +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_REQ_SIZE +#define OEM_DATA_REQ_SIZE 500 +#endif + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +#define OEM_APP_SIGNATURE_LEN 16 +#define OEM_APP_SIGNATURE_STR "QUALCOMM-OEM-APP" + +#define OEM_TARGET_SIGNATURE_LEN 8 +#define OEM_TARGET_SIGNATURE "QUALCOMM" + +#define OEM_CAP_MAX_NUM_CHANNELS 128 + +/** + * enum oem_err_code - OEM error codes + * @OEM_ERR_NULL_CONTEXT: %NULL context + * @OEM_ERR_APP_NOT_REGISTERED: OEM App is not registered + * @OEM_ERR_INVALID_SIGNATURE: Invalid signature + * @OEM_ERR_NULL_MESSAGE_HEADER: Invalid message header + * @OEM_ERR_INVALID_MESSAGE_TYPE: Invalid message type + * @OEM_ERR_INVALID_MESSAGE_LENGTH: Invalid length in message body + */ +enum oem_err_code { + OEM_ERR_NULL_CONTEXT = 1, + OEM_ERR_APP_NOT_REGISTERED, + OEM_ERR_INVALID_SIGNATURE, + OEM_ERR_NULL_MESSAGE_HEADER, + OEM_ERR_INVALID_MESSAGE_TYPE, + OEM_ERR_INVALID_MESSAGE_LENGTH +}; + +/** + * struct driver_version - Driver version identifier (w.x.y.z) + * @major: Version ID major number + * @minor: Version ID minor number + * @patch: Version ID patch number + * @build: Version ID build number + */ +struct driver_version { + uint8_t major; + uint8_t minor; + uint8_t patch; + uint8_t build; +}; + +/** + * struct oem_data_cap - OEM Data Capabilities + * @oem_target_signature: Signature of chipset vendor, e.g. QUALCOMM + * @oem_target_type: Chip type + * @oem_fw_version: Firmware version + * @driver_version: Host software version + * @allowed_dwell_time_min: Channel dwell time - allowed minimum + * @allowed_dwell_time_max: Channel dwell time - allowed maximum + * @curr_dwell_time_min: Channel dwell time - current minimim + * @curr_dwell_time_max: Channel dwell time - current maximum + * @supported_bands: Supported bands, 2.4G or 5G Hz + * @num_channels: Num of channels IDs to follow + * @channel_list: List of channel IDs + */ +struct oem_data_cap { + uint8_t oem_target_signature[OEM_TARGET_SIGNATURE_LEN]; + uint32_t oem_target_type; + uint32_t oem_fw_version; + struct driver_version driver_version; + uint16_t allowed_dwell_time_min; + uint16_t allowed_dwell_time_max; + uint16_t curr_dwell_time_min; + uint16_t curr_dwell_time_max; + uint16_t supported_bands; + uint16_t num_channels; + uint8_t channel_list[OEM_CAP_MAX_NUM_CHANNELS]; +}; + +/** + * struct hdd_channel_info - Channel information + * @reserved0: reserved for padding and future use + * @mhz: primary 20 MHz channel frequency in mhz + * @band_center_freq1: Center frequency 1 in MHz + * @band_center_freq2: Center frequency 2 in MHz, valid only for 11ac + * VHT 80+80 mode + * @info: channel info + * @reg_info_1: regulatory information field 1 which contains min power, + * max power, reg power and reg class id + * @reg_info_2: regulatory information field 2 which contains antennamax + */ +struct hdd_channel_info { + uint32_t reserved0; + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; +}; + +/** + * struct peer_status_info - Status information for a given peer + * @peer_mac_addr: peer mac address + * @peer_status: peer status: 1: CONNECTED, 2: DISCONNECTED + * @vdev_id: vdev_id for the peer mac + * @peer_capability: peer capability: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @reserved0: reserved0 + * @peer_chan_info: channel info on which peer is connected + */ +struct peer_status_info { + uint8_t peer_mac_addr[ETH_ALEN]; + uint8_t peer_status; + uint8_t vdev_id; + uint32_t peer_capability; + uint32_t reserved0; + struct hdd_channel_info peer_chan_info; +}; + +/** + * struct oem_get_capability_rsp - capabilities set by userspace and target. + * @target_cap: target capabilities + * @cap: capabilities set by userspace via set request + */ +struct oem_get_capability_rsp { + struct oem_data_cap target_cap; + struct sme_oem_capability cap; +}; + +/** + * hdd_send_peer_status_ind_to_oem_app() - + * Function to send peer status to a registered application + * @peer_mac: MAC address of peer + * @peer_status: ePeerConnected or ePeerDisconnected + * @peer_capability: 0: RTT/RTT2, 1: RTT3. Default is 0 + * @vdev_id: vdev_id + * @chan_info: operating channel information + * @dev_mode: dev mode for which indication is sent + * + * Return: none + */ +void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peer_mac, + uint8_t peer_status, + uint8_t peer_capability, + uint8_t vdev_id, + struct oem_channel_info *chan_info, + enum QDF_OPMODE dev_mode); + +int iw_get_oem_data_cap(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +/** + * oem_activate_service() - API to register the oem command handler + * @hdd_ctx: Pointer to HDD Context + * + * This API is used to register the handler to receive netlink message + * from an OEM application process + * + * Return: 0 on success and errno on failure + */ +int oem_activate_service(struct hdd_context *hdd_ctx); + +/** + * oem_deactivate_service() - API to unregister the oem command handler + * + * This API is used to deregister the handler to receive netlink message + * from an OEM application process + * + * Return: 0 on success and errno on failure + */ +int oem_deactivate_service(void); + +void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_rsp); + +/** + * hdd_update_channel_bw_info() - set bandwidth info for the chan + * @hdd_ctx: hdd context + * @chan_freq: channel freq for which info are required + * @hdd_chan_info: struct where the bandwidth info is filled + * + * This function finds the maximum bandwidth allowed, secondary + * channel offset and center freq for the channel as per regulatory + * domain and uses these info calculate the phy mode for the + * channel. + * + * Return: void + */ +void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx, + uint32_t chan_freq, + void *hdd_chan_info); +#else +static inline int oem_activate_service(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline int oem_deactivate_service(void) +{ + return 0; +} + +static inline void hdd_send_oem_data_rsp_msg(void *oem_rsp) {} + +static inline void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx, + uint32_t chan_freq, + void *hdd_chan_info) {} +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +#ifdef FEATURE_OEM_DATA +#define OEM_DATA_MAX_SIZE 1500 +/** + * wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +extern const struct nla_policy + oem_data_attr_policy + [QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1]; + +#define FEATURE_OEM_DATA_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OEM_DATA, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_oem_data_handler, \ + vendor_command_policy(oem_data_attr_policy, \ + QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX) \ +}, +#else +#define FEATURE_OEM_DATA_VENDOR_COMMANDS +#endif + +#ifdef FEATURE_OEM_DATA +/** + * hdd_oem_event_async_cb() - callback for oem data async event + * @oem_event_data: oem data received in the event from the FW + * + * Return: None + */ +void hdd_oem_event_async_cb(const struct oem_data *oem_event_data); + +/** + * hdd_oem_event_handler_cb() - callback for oem data event + * @oem_event_data: oem data received in the event from the FW + * @vdev_id: vdev id + * + * Return: None + */ +void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data, + uint8_t vdev_id); +#else +static inline void hdd_oem_event_handler_cb(void *oem_event_data, + uint8_t vdev_id) +{ +} + +static inline void hdd_oem_event_async_cb(void *oem_event_data) +{ +} +#endif +#endif /* __WLAN_HDD_OEM_DATA_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h new file mode 100644 index 0000000000..74b14e9f8c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_p2p.h @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2012-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __P2P_H +#define __P2P_H + +/** + * DOC: wlan_hdd_p2p.h + * + * Linux HDD P2P include file + */ + +#define WLAN_HDD_GET_TYPE_FRM_FC(__fc__) (((__fc__) & 0x0F) >> 2) +#define WLAN_HDD_GET_SUBTYPE_FRM_FC(__fc__) (((__fc__) & 0xF0) >> 4) +#define WLAN_HDD_80211_FRM_DA_OFFSET 4 + +#define P2P_POWER_SAVE_TYPE_OPPORTUNISTIC (1 << 0) +#define P2P_POWER_SAVE_TYPE_PERIODIC_NOA (1 << 1) +#define P2P_POWER_SAVE_TYPE_SINGLE_NOA (1 << 2) + +struct p2p_app_set_ps { + uint8_t opp_ps; + uint32_t ct_window; + uint8_t count; + uint32_t duration; + uint32_t interval; + uint32_t single_noa_duration; + uint8_t ps_selection; +}; + +int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie); + +int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie); + +int hdd_set_p2p_ps(struct net_device *dev, void *msgData); +int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command); +int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command); + +/** + * hdd_indicate_mgmt_frame_to_user- send mgmt frame to user + * @adapter: adapter pointer + * @frm_len: frame length + * @pb_frames: frame bytes + * @frame_type: frame type + * @rx_freq: frequency on which frame was received + * @rx_rssi: rssi + * @rx_flags: rx flags of the frame + */ +void hdd_indicate_mgmt_frame_to_user(struct hdd_adapter *adapter, + uint32_t frm_len, uint8_t *pb_frames, + uint8_t frame_type, uint32_t rx_freq, + int8_t rx_rssi, + enum rxmgmt_flags rx_flags); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie); +#else +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie); +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || defined(WITH_BACKPORTS) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +#else +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); + +#endif + +/** + * hdd_clean_up_interface() - clean up hdd interface + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * + * This function clean up hdd interface. + * + * Return: None + */ +void hdd_clean_up_interface(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); +int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); + +/** + * wlan_hdd_cleanup_remain_on_channel_ctx - Cleanup ROC on VDEV + * @link_info: pointer to link_info struct in adapter + * + * This function is used to cleanup the ROC on the vdev + * pointed in the @link_info + * + * Return: void + */ +void +wlan_hdd_cleanup_remain_on_channel_ctx(struct wlan_hdd_link_info *link_info); + +/** + * wlan_hdd_set_power_save() - hdd set power save + * @adapter: adapter context + * @ps_config: pointer to power save configure + * + * This function sets power save parameters. + * + * Return: 0 - success + * others - failure + */ +int wlan_hdd_set_power_save(struct hdd_adapter *adapter, + struct p2p_ps_config *ps_config); + +/** + * wlan_hdd_set_mas() - Function to set MAS value to FW + * @adapter: Pointer to HDD adapter + * @mas_value: 0-Disable, 1-Enable MAS + * + * This function passes down the value of MAS to FW + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int32_t wlan_hdd_set_mas(struct hdd_adapter *adapter, uint8_t mas_value); + +/** + * wlan_hdd_set_mcc_p2p_quota() - Function to set quota for P2P + * to FW + * @adapter: Pointer to HDD adapter + * @set_value: Quota value for the interface + * + * This function is used to set the quota for P2P cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int wlan_hdd_set_mcc_p2p_quota(struct hdd_adapter *adapter, + uint32_t set_value); + +/** + * wlan_hdd_go_set_mcc_p2p_quota() - Function to set quota for + * P2P GO to FW + * @hostapd_adapter: Pointer to HDD adapter + * @set_value: Quota value for the interface + * + * This function is used to set the quota for P2P GO cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int wlan_hdd_go_set_mcc_p2p_quota(struct hdd_adapter *hostapd_adapter, + uint32_t set_value); +/** + * wlan_hdd_set_mcc_latency() - Set MCC latency to FW + * @adapter: Pointer to HDD adapter + * @set_value: Latency value + * + * Sets the MCC latency value during STA-P2P concurrency + * + * Return: None + */ +void wlan_hdd_set_mcc_latency(struct hdd_adapter *adapter, int set_value); + +/** + * wlan_hdd_cleanup_actionframe() - Cleanup action frame + * @link_info: pointer to link_info struct in adapter + * + * This function cleans up action frame. + * + * Return: None + */ +void wlan_hdd_cleanup_actionframe(struct wlan_hdd_link_info *link_info); +#endif /* __P2P_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h new file mode 100644 index 0000000000..47121d39af --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_api.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_PACKET_FILTER_API_H__) +#define WLAN_HDD_PACKET_FILTER_API_H__ + +/** + * DOC: wlan_hdd_packet_filter_rules.h + * + */ + +/* Include files */ +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_power.h" + +#ifdef WLAN_FEATURE_PACKET_FILTERING + +/** + * hdd_enable_default_pkt_filters() - Enable default packet filters based + * on, filters bit map provided in INI, when target goes to suspend mode + * @hdd_ctx: Global HDD Context + * @vdev_id: vdev_id + * + * Return: zero if success, non-zero otherwise + */ +int +hdd_enable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id); + +/** + * hdd_disable_default_pkt_filters() - Disable default packet filters based + * on, filters bit map provided in INI, when target resumes + * @hdd_ctx: Global HDD Context + * @vdev_id: vdev_id + * + * Return: zero if success, non-zero otherwise + */ +int +hdd_disable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id); + +/** + * wlan_hdd_set_filter() - Set packet filter + * @hdd_ctx: Global HDD context + * @request: Packet filter request struct + * @vdev_id: Target vdev for the request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_set_filter(struct hdd_context *hdd_ctx, + struct pkt_filter_cfg *request, + uint8_t vdev_id); + +#else /* WLAN_FEATURE_PACKET_FILTERING */ + +static inline int +hdd_enable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ + return 0; +} + +static inline int +hdd_disable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ + return 0; +} + +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h new file mode 100644 index 0000000000..5ae2d6b583 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_packet_filter_rules.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_PACKET_FILTER_RULES_H__) +#define WLAN_HDD_PACKET_FILTER_RULES_H__ + +/** + * DOC: wlan_hdd_packet_filter_rules.h + * + */ + +/* Include files */ + +#define MAX_NUM_PACKET_FILTERS 6 + +/* + * @filter_action: Filter action, set/clear the filter + * Ex: filter_action = 1 set the filter + * filter_action = 2 clear the filter + * @filter_id: Filter id Ex: 1/2/3/4/5 .... MAX_NUM_FILTERS + * @num_params: Number of parameters Ex: 1/2/3/4/5 + * @params_data: Packet filter parameters details + * + * @protocol_layer: the type of protocol layer header to which the data + * being configured correspond + * Ex: protocol_layer = 1 - MAC Header + * protocol_layer = 2 - ARP Header + * protocol_layer = 3 - IP Header + * @compare_flag: comparison type + * EX: compare_flag = 0 - comparison is invalid + * compare_flag = 1 - compare for equality of the data present in received + * packet to the corresponding configured data + * compare_flag = 2 - compare for equality of the data present in received + * packet to the corresponding configured data after + * applying the mask + * compare_flag = 3 - compare for non-equality of the data present in + * received packet to the corresponding configured data + * compare_flag = 4 - compare for non-equality of the data present in + * received packet to the corresponding configured data + * after applying the mask + * @data_fffset: Offset of the data to compare from the respective protocol + * layer header start (as per the respective protocol + * specification) in terms of bytes + * @data_length: length of data to compare + * @compare_data: Array of 8 bytes + * @data_mask: Mask to be applied on the received packet data (Array of 8 bytes) + */ +static struct pkt_filter_cfg + packet_filter_default_rules[MAX_NUM_PACKET_FILTERS] = { + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {134, 221, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 24, + .data_length = 2, + .compare_data = {255, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {255, 0, 0, 0, 0, 0, 0, 0} } } }, + + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {8, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 16, + .data_length = 1, + .compare_data = {224, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {240, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 3, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {8, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 3, + .compare_flag = 4, + .data_offset = 18, + .data_length = 2, + .compare_data = {0, 255, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 255, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 8, + .data_length = 4, + .compare_data = {0, 1, 175, 129, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 6, + .data_length = 2, + .compare_data = {0, 39, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } }, + { .filter_action = 1, + .filter_id = 0, + .num_params = 2, + .params_data = { + { .protocol_layer = 1, + .compare_flag = 5, + .data_offset = 0, + .data_length = 1, + .compare_data = {1, 0, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} }, + { .protocol_layer = 2, + .compare_flag = 3, + .data_offset = 4, + .data_length = 2, + .compare_data = {0, 12, 0, 0, 0, 0, 0, 0}, + .data_mask = {0, 0, 0, 0, 0, 0, 0, 0} } } } }; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h new file mode 100644 index 0000000000..d3b89237ab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_power.h @@ -0,0 +1,716 @@ +/* + * Copyright (c) 2012, 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_POWER_H +#define __WLAN_HDD_POWER_H + +/** + * DOC: wlan_hdd_power.h + * + * HDD Power Management API + */ + +#include "wlan_hdd_main.h" +#include +#include + +#define HDD_WAKELOCK_TIMEOUT_CONNECT 1000 +#define HDD_WAKELOCK_TIMEOUT_RESUME 1000 +#define DISABLE_KRAIT_IDLE_PS_VAL 1 + +/* + * HDD_WAKELOCK_CONNECT_COMPLETE = CSR_JOIN_FAILURE_TIMEOUT_DEFAULT (3000) + + * WNI_CFG_AUTHENTICATE_FAILURE_TIMEOUT_STADEF (1000) + + * WNI_CFG_ASSOCIATION_FAILURE_TIMEOUT_STADEF (2000) + */ +#define HDD_WAKELOCK_CONNECT_COMPLETE 6000 + +#ifdef WLAN_FEATURE_PACKET_FILTERING + +#define HDD_MAX_CMP_PER_PACKET_FILTER 5 + +/** + * enum pkt_filter_protocol_layer - packet filter protocol layer + * @HDD_FILTER_PROTO_TYPE_INVALID: Invalid initial value + * @HDD_FILTER_PROTO_TYPE_MAC: MAC protocol + * @HDD_FILTER_PROTO_TYPE_ARP: ARP protocol + * @HDD_FILTER_PROTO_TYPE_IPV4: IP V4 protocol + * @HDD_FILTER_PROTO_TYPE_IPV6: IP V6 protocol + * @HDD_FILTER_PROTO_TYPE_UDP: UDP protocol + * @HDD_FILTER_PROTO_TYPE_MAX: Max place holder value + */ +enum pkt_filter_protocol_layer { + HDD_FILTER_PROTO_TYPE_INVALID = 0, + HDD_FILTER_PROTO_TYPE_MAC = 1, + HDD_FILTER_PROTO_TYPE_ARP = 2, + HDD_FILTER_PROTO_TYPE_IPV4 = 3, + HDD_FILTER_PROTO_TYPE_IPV6 = 4, + HDD_FILTER_PROTO_TYPE_UDP = 5, + HDD_FILTER_PROTO_TYPE_MAX +}; + +/** + * enum pkt_filter_action - packet filter action + * @HDD_RCV_FILTER_INVALID: Invalid initial value + * @HDD_RCV_FILTER_SET: Packet filter set + * @HDD_RCV_FILTER_CLEAR: Packet filter clear + * @HDD_RCV_FILTER_MAX: Max place holder value + */ +enum pkt_filter_action { + HDD_RCV_FILTER_INVALID = 0, + HDD_RCV_FILTER_SET = 1, + HDD_RCV_FILTER_CLEAR = 2, + HDD_RCV_FILTER_MAX +}; + +/** + * enum pkt_filter_compare_flag - packet filter compare flag + * @HDD_FILTER_CMP_TYPE_INVALID: Invalid initial value + * @HDD_FILTER_CMP_TYPE_EQUAL: Compare if filter is equal + * @HDD_FILTER_CMP_TYPE_MASK_EQUAL: Compare if filter mask is equal + * @HDD_FILTER_CMP_TYPE_NOT_EQUAL: Compare if filter is not equal + * @HDD_FILTER_CMP_TYPE_MASK_NOT_EQUAL: Compare if filter mask is not equal + * @HDD_FILTER_CMP_TYPE_MAX: Max place holder value + */ +enum pkt_filter_compare_flag { + HDD_FILTER_CMP_TYPE_INVALID = 0, + HDD_FILTER_CMP_TYPE_EQUAL = 1, + HDD_FILTER_CMP_TYPE_MASK_EQUAL = 2, + HDD_FILTER_CMP_TYPE_NOT_EQUAL = 3, + HDD_FILTER_CMP_TYPE_MASK_NOT_EQUAL = 4, + HDD_FILTER_CMP_TYPE_MAX +}; + +/** + * struct pkt_filter_param_cfg - packet filter parameter config + * @protocol_layer: Protocol layer + * @compare_flag: Compare flag + * @data_offset: Data offset + * @data_length: Data length + * @compare_data: Compare data + * @data_mask: Data mask + */ +struct pkt_filter_param_cfg { + uint8_t protocol_layer; + uint8_t compare_flag; + uint8_t data_offset; + uint8_t data_length; + uint8_t compare_data[SIR_MAX_FILTER_TEST_DATA_LEN]; + uint8_t data_mask[SIR_MAX_FILTER_TEST_DATA_LEN]; +}; + +/** + * struct pkt_filter_cfg - packet filter config received from user space + * @filter_action: Filter action + * @filter_id: Filter id + * @num_params: Number of parameters + * @params_data: Packet filter parameters detail + */ +struct pkt_filter_cfg { + uint8_t filter_action; + uint8_t filter_id; + uint8_t num_params; + struct pkt_filter_param_cfg params_data[HDD_MAX_CMP_PER_PACKET_FILTER]; +}; + +#endif + +#ifdef FEATURE_ANI_LEVEL_REQUEST +/** + * struct ani_priv - structure to store the priv data for get ani request + * @num_freq: number of freq received from the FW + * @ani: data received from the FW + */ +struct ani_priv { + uint32_t num_freq; + struct wmi_host_ani_level_event *ani; +}; +#endif + +/** + * enum suspend_resume_state - Suspend resume state + * @HDD_WLAN_EARLY_SUSPEND: Early suspend state. + * @HDD_WLAN_SUSPEND: Suspend state. + * @HDD_WLAN_EARLY_RESUME: Early resume state. + * @HDD_WLAN_RESUME: Resume state. + * + * Suspend state to indicate in diag event of suspend resume. + */ +enum suspend_resume_state { + HDD_WLAN_EARLY_SUSPEND, + HDD_WLAN_SUSPEND, + HDD_WLAN_EARLY_RESUME, + HDD_WLAN_RESUME +}; + +/** + * hdd_svc_fw_shutdown_ind() - API to send FW SHUTDOWN IND to Userspace + * @dev: Device Pointer + * + * Return: None + */ +void hdd_svc_fw_shutdown_ind(struct device *dev); + +/** + * hdd_wlan_shutdown() - HDD SSR shutdown function + * + * This function is called by the HIF to shutdown the driver during SSR. + * + * Return: QDF_STATUS_SUCCESS if the driver was shut down, + * or an error status otherwise + */ +QDF_STATUS hdd_wlan_shutdown(void); + +/** + * hdd_wlan_re_init() - HDD SSR re-init function + * + * This function is called by the HIF to re-initialize the driver after SSR. + * + * Return: QDF_STATUS_SUCCESS if the driver was re-initialized, + * or an error status otherwise + */ +QDF_STATUS hdd_wlan_re_init(void); + +/** + * hdd_handle_cached_commands() - Handle north bound commands during SSR + * + * This api will be invoked afte SSR re-initialization to execute the north + * bound commands received during SSR. + * + * Return: None + */ +void hdd_handle_cached_commands(void); + +/** + * hdd_enable_arp_offload() - API to enable ARP offload + * @adapter: Adapter context for which ARP offload is to be configured + * @vdev: VDEV objmgr pointer + * @trigger: trigger reason for request + * + * Return: None + */ +void hdd_enable_arp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * hdd_disable_arp_offload() - API to disable ARP offload + * @adapter: Adapter context for which ARP offload is to be configured + * @vdev: VDEV objmgr pointer + * @trigger: trigger reason for request + * + * Return: None + */ +void hdd_disable_arp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * hdd_enable_host_offloads() - Central API to enable the supported offloads + * @adapter: pointer to the adapter + * @trigger: trigger reason for request + * + * Central function to enable the supported offloads + * + * Return: nothing + */ +void hdd_enable_host_offloads(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * hdd_disable_host_offloads() - Central API to disable the supported offloads + * @adapter: pointer to the adapter + * @trigger: trigger reason for request + * + * Central function to disable the supported offloads + * + * Return: nothing + */ +void hdd_disable_host_offloads(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * hdd_set_grat_arp_keepalive() - Enable gratuitous ARP keepalive + * @adapter: the HDD adapter to configure + * + * This configures gratuitous ARP keepalive based on the adapter's current + * connection information, specifically IPv4 address and BSSID + * + * return: zero for success, non-zero for failure + */ +int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter); + +/** + * hdd_enable_mc_addr_filtering() - enable MC address list in FW + * @adapter: adapter whose MC list is being set + * @trigger: trigger reason for request + * + * Return: nothing + */ +void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * hdd_disable_mc_addr_filtering() - disable MC address list in FW + * @adapter: adapter whose MC list is being set + * @trigger: trigger reason for request + * + * Return: nothing + */ +void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * hdd_cache_mc_addr_list() - API to cache MC address list + * @mc_list_config: set of mc address list configurations + * + * Return: 0 on success else error code + */ +int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config); + +/** + * hdd_disable_and_flush_mc_addr_list() - API to Disable & Flush cached MC list + * @adapter: adapter whose MC list is being set + * @trigger: trigger reason for request + * + * Return: nothing + */ +void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger); + +/** + * wlan_hdd_cfg80211_update_replay_counter_cb() - replay counter callback + * @cb_ctx: Callback context as void* as PMO do not about HDD adapter type + * @gtk_rsp_param: Pointer to gtk offload response parameter + * + * Callback routine called upon receiving of gtk offload rsp from fwr + * + * Return: none + */ +void wlan_hdd_cfg80211_update_replay_counter_cb( + void *cb_ctx, + struct pmo_gtk_rsp_params *gtk_rsp_param); + +/** + * wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback + * @wiphy: Pointer to wiphy + * @wow: Pointer to wow + * + * This API is called when cfg80211 driver suspends + * + * Return: integer status + */ +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow); + +/** + * wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback + * @wiphy: Pointer to wiphy + * + * This API is called when cfg80211 driver resumes driver updates + * latest sched_scan scan result(if any) to cfg80211 database + * + * Return: integer status + */ +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy); + +/** + * hdd_ipv4_notifier_work_queue() - IP V4 change notifier work handler + * @work: Pointer to work context + * + * Return: none + */ +void hdd_ipv4_notifier_work_queue(struct work_struct *work); + +#ifdef WLAN_NS_OFFLOAD +/** + * hdd_enable_ns_offload() - enable NS offload + * @adapter: pointer to the adapter + * @vdev: VDEV objmgr pointer + * @trigger: trigger reason to enable ns offload + * + * Return: nothing + */ +void hdd_enable_ns_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * hdd_disable_ns_offload() - disable NS offload + * @adapter: pointer to the adapter + * @vdev: VDEV objmgr pointer + * @trigger: trigger reason to enable ns offload + * + * Return: nothing + */ +void hdd_disable_ns_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); + +/** + * hdd_send_ps_config_to_fw() - Check user pwr save config set/reset PS + * @adapter: pointer to hdd adapter + * + * This function checks the power save configuration saved in MAC context + * and sends power save config to FW. + * + * Return: None + */ +void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter); +#else /* WLAN_NS_OFFLOAD */ +static inline +void hdd_enable_ns_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ +} + +static inline +void hdd_disable_ns_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ +} + +static inline +void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter) +{ +} +#endif /* WLAN_NS_OFFLOAD */ + +/** + * hdd_ipv6_notifier_work_queue() - IP V6 change notifier work handler + * @work: Pointer to work context + * + * Return: none + */ +void hdd_ipv6_notifier_work_queue(struct work_struct *work); + +/** + * wlan_hdd_cfg80211_get_txpower() - cfg80211 get power handler function + * @wiphy: Pointer to wiphy structure. + * @wdev: Pointer to wireless_dev structure. + * @dbm: dbm + * + * This is the cfg80211 get txpower handler function which invokes + * the internal function @__wlan_hdd_cfg80211_get_txpower with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm); + +/** + * wlan_hdd_cfg80211_set_txpower() - set TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @type: TX power setting type + * @dbm: TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int dbm); + +/** + * wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @allow_power_save: is wlan allowed to go into power save mode + * @timeout: Timeout value + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool allow_power_save, + int timeout); + +/** + * wlan_hdd_ipv4_changed() - IPv4 change notifier callback + * @nb: pointer to notifier block + * @data: data + * @arg: arg + * + * This is the IPv4 notifier callback function gets invoked + * if any change in IP and then invoke the function @__wlan_hdd_ipv4_changed + * to reconfigure the offload parameters. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *arg); + +#ifdef FEATURE_RUNTIME_PM +/** + * wlan_hdd_pm_qos_notify() - PM QOS notifier call back function + * @nb: Pointer to notifier block kernel structure + * @curr_val: PM QOS current value + * @context: call back context + * + * This callback function for PM QOS change notification is used to setup + * dynamic runtime PM. + * + * Return: NOTIFY_DONE for success + */ +int wlan_hdd_pm_qos_notify(struct notifier_block *nb, unsigned long curr_val, + void *context); + +/** + * wlan_hdd_is_cpu_pm_qos_in_progress() - WLAN HDD PM QoS Status Function + * + * This function check for PM QoS global vote. + * + * @hdd_ctx: hdd_context pointer + * + * Return: true if there is PM QoS global vote, + * or an false otherwise + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && \ + defined(__ANDROID_COMMON_KERNEL__)) +bool wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context *hdd_ctx); +#else +static inline bool +wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif +#endif +/** + * wlan_hdd_ipv6_changed() - IPv6 change notifier callback + * @nb: pointer to notifier block + * @data: data + * @arg: arg + * + * This is the IPv6 notifier callback function gets invoked + * if any change in IP and then invoke the function @__wlan_hdd_ipv6_changed + * to reconfigure the offload parameters. + * + * Return: 0 on success, error number otherwise. + */ +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *arg); + +/** + * hdd_set_power_config() - set power config to firmware + * @hddctx: HDD context + * @adapter: HDD adapter + * @opm_mode: pointer to vendor opm_mode + * + * Return: 0 on success; Errno on failure + */ +int hdd_set_power_config(struct hdd_context *hddctx, + struct hdd_adapter *adapter, + enum qca_wlan_vendor_opm_mode *opm_mode); + +/** + * hdd_set_power_config_params() - set power config parameters + * @hddctx: HDD context + * @adapter: HDD adapter + * @ps_ito: power save inactivitiy duration in ms + * @spec_wake: power save speculative wake duration in ms + * + * Return: 0 on success; Errno on failure + */ +int hdd_set_power_config_params(struct hdd_context *hddctx, + struct hdd_adapter *adapter, + uint16_t ps_ito, uint16_t spec_wake); +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_suspend_resume_event()- send suspend/resume state + * @state: suspend/resume state + * + * This Function sends suspend resume state diag event + * + * Return: void. + */ +void hdd_wlan_suspend_resume_event(uint8_t state); + +#else +static inline +void hdd_wlan_suspend_resume_event(uint8_t state) {} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * wlan_hdd_set_powersave() - Set powersave mode + * @link_info: Link inof pointer in HDD adapter + * @allow_power_save: is wlan allowed to go into power save mode + * @timeout: timeout period in ms + * + * Return: 0 on success, non-zero on any error + */ +int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info, + bool allow_power_save, uint32_t timeout); + +/** + * wlan_hdd_inc_suspend_stats() - Prints, then increments, then prints suspend + * failed statistics. + * @hdd_ctx: The HDD context to operate on + * @reason: The suspend failed reason to increment + * + * This function prints all of the suspend failed statistics, increments the + * specified suspend fail reason statistic, and prints the them all again. This + * is for easily keeping track of the most common reasons suspend fails. + * + * Return: none + */ +void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx, + enum suspend_fail_reason reason); + +/* + * Unit-test suspend/resume is a testing feature that allows putting firmware + * into WoW suspend irrespective of Apps suspend status. It emulates the chain + * of events that occur during normal system-level suspend/resume, such as + * initiating all of the suspend/resume stages in the correct order, and + * enabling/disabling appropriate copy engine irqs. + */ +#ifdef WLAN_SUSPEND_RESUME_TEST +/** + * wlan_hdd_unit_test_bus_suspend() - suspend the wlan bus + * @wow_params: collection of wow enable override parameters + * + * This function does the same as wlan_hdd_bus_suspend, but additionally passes + * the appropriate flags to FW, indicating this is a unit-test suspend and it + * should use an HTC wakeup method to resume. + * + * Return: 0 for success or error code + */ +int wlan_hdd_unit_test_bus_suspend(struct wow_enable_params wow_params); + +/** + * hdd_wlan_fake_apps_resume() - Resume from unit-test triggered suspend + * @wiphy: the kernel wiphy struct for the device being resumed + * @dev: the kernel net_device struct for the device being resumed + * + * Return: Zero on success, calls QDF_BUG() on failure + */ +int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev); + +/** + * hdd_wlan_fake_apps_suspend() - Initiate a unit-test triggered suspend + * @wiphy: the kernel wiphy struct for the device being suspended + * @dev: the kernel net_device struct for the device being suspended + * @pause_setting: interface pause override setting + * @resume_setting: resume trigger override setting + * + * Return: Zero on success, suspend related non-zero error code on failure + */ +int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev, + enum wow_interface_pause pause_setting, + enum wow_resume_trigger resume_setting); +#else +static inline int +hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev) +{ + return 0; +} + +static inline int +hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev, + enum wow_interface_pause pause_setting, + enum wow_resume_trigger resume_setting) +{ + return 0; +} +#endif /* WLAN_SUSPEND_RESUME_TEST */ + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD +/** + * wlan_hdd_rx_thread_resume() - Resume RX thread + * @hdd_ctx: HDD context + * + * Check if RX thread suspended, and resume if yes. + * + * Return: None + */ +void wlan_hdd_rx_thread_resume(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_rx_thread_suspend() - Suspend RX thread + * @hdd_ctx: HDD context + * + * To suspend RX thread + * + * Return: 0 for success + */ +int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx); + +#else +static inline void wlan_hdd_rx_thread_resume(struct hdd_context *hdd_ctx) {} +static inline int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#ifdef FEATURE_ANI_LEVEL_REQUEST +/** + * wlan_hdd_get_ani_level() - Wrapper to call API to fetch ani level + * @adapter: pointer to HDD adapter + * @ani: pointer to structure storing ani level for channels + * @parsed_freqs: parsed freqs from the get ani command + * @num_freqs: number of parsed channels + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_get_ani_level(struct hdd_adapter *adapter, + struct wmi_host_ani_level_event *ani, + uint32_t *parsed_freqs, + uint8_t num_freqs); +#endif /* FEATURE_ANI_LEVEL_REQUEST */ + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +/** + * hdd_enable_icmp_offload() - API to enable ICMP offload + * @adapter: Adapter context for which ICMP offload is to be configured + * @vdev: VDEV ojgmgr pointer + * @trigger: trigger reason for request + * + * Return: None + */ +void hdd_enable_icmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger); +#else +static inline +void hdd_enable_icmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{} +#endif /* FEATURE_ICMP_OFFLOAD */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter, + bool allow_power_save, int timeout, + int link_id); +#else +static inline +int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter, + bool allow_power_save, int timeout, + int link_id) +{ + return 0; +} +#endif +#endif /* __WLAN_HDD_POWER_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_pre_cac.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_pre_cac.h new file mode 100644 index 0000000000..f8751f1d5e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_pre_cac.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_PRE_CAC_H_ +#define _WLAN_HDD_PRE_CAC_H_ + +#ifdef PRE_CAC_SUPPORT + +/* default pre cac channel bandwidth */ +#define DEFAULT_PRE_CAC_BANDWIDTH CH_WIDTH_80MHZ + +/** + * wlan_hdd_request_pre_cac() - Start pre CAC in the driver + * @hdd_ctx: the HDD context to operate against + * @chan_freq: channel freq option provided by userspace + * + * Sets the driver to the required hardware mode and start an adapter for + * pre CAC which will mimic an AP. + * + * Return: Zero on success, non-zero value on error + */ +int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq); + +/** + * hdd_close_pre_cac_adapter() - Close pre CAC adapter + * @hdd_ctx: the HDD context to operate against + * + * Return: None + */ +void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx); + +/** + * hdd_pre_cac_register_cb() - Sets legacy callbacks to osif + * + * API to set legacy callbacks to osif + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_pre_cac_register_cb(void); + +/** + * hdd_pre_cac_unregister_cb() - Resets legacy callbacks to osif + * + * API to reset legacy callbacks to osif + * + * Return: QDF_STATUS + */ +void hdd_pre_cac_unregister_cb(void); +#else +static inline int +wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq) +{ + return 0; +} + +static inline void +hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx) +{ +} + +static inline QDF_STATUS hdd_pre_cac_register_cb(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_pre_cac_unregister_cb(void) +{ +} +#endif /* PRE_CAC_SUPPORT */ +#endif /* _WLAN_HDD_PRE_CAC_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h new file mode 100644 index 0000000000..7d689cb5e9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_regulatory.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined __HDD_REGULATORY_H +#define __HDD_REGULATORY_H + +/** + * DOC: wlan_hdd_regulatory.h + * + * HDD Regulatory prototype implementation + */ + +struct hdd_context; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +#define IEEE80211_CHAN_PASSIVE_SCAN IEEE80211_CHAN_NO_IR +#endif + +#define CHANNEL_LIST_UPDATE_TIMEOUT 4500 + +/** + * hdd_update_regulatory_config() - API to update regulatory config parameters + * @hdd_ctx: HDD context + * + * Return: 0 on success, err on failure + */ +int hdd_update_regulatory_config(struct hdd_context *hdd_ctx); + +/** + * hdd_init_regulatory_update_event() - Initialize the regulatory update event + * @hdd_ctx: HDD context + * + * Return: 0 on success, err on failure + */ +int hdd_init_regulatory_update_event(struct hdd_context *hdd_ctx); + +/** + * hdd_deinit_regulatory_update_event() - Cleanup the regulatory update event + * @hdd_ctx: HDD context + * + * Return: none + */ +void hdd_deinit_regulatory_update_event(struct hdd_context *hdd_ctx); + +int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy); + +/** + * hdd_regulatory_deinit() - cleanup all components of regulatory + * @hdd_ctx: HDD context + * + * Return: None + */ +void hdd_regulatory_deinit(struct hdd_context *hdd_ctx); + +void hdd_program_country_code(struct hdd_context *hdd_ctx); +void hdd_reset_global_reg_params(void); + +/** + * hdd_send_wiphy_regd_sync_event() - sends the regulatory sync event + * @hdd_ctx: HDD context + * + * Return: None + */ +void hdd_send_wiphy_regd_sync_event(struct hdd_context *hdd_ctx); + +/** + * hdd_reg_wait_for_country_change() - Wait for country change event + * @hdd_ctx: the HDD context + * + * Return: None + */ +void hdd_reg_wait_for_country_change(struct hdd_context *hdd_ctx); + +/** + * hdd_reg_set_country() - helper function for setting the regulatory country + * @hdd_ctx: the HDD context to set the country for + * @country_code: the two character country code to configure + * + * Return: zero for success, non-zero error code for failure + */ +int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code); + +/** + * hdd_reg_legacy_setband_to_reg_wifi_band_bitmap() - Convert the user space + * band input to a bitmap of band capabilities, with reg_wifi_band as the + * bit value + * @qca_setband: user space/setband value band input, can be 0, 1, or 2 + * + * Return: bitmap on top of reg_wifi_band of bands enabled + */ +uint32_t hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(uint8_t qca_setband); + +/** + * hdd_reg_set_band() - helper function for setting the regulatory band + * @dev: the network device to set the band for + * @band_bitmap: the band bitmap to configure + * + * Return: zero for success, non-zero error code for failure + */ +int hdd_reg_set_band(struct net_device *dev, uint32_t band_bitmap); + +/** + * hdd_update_indoor_channel() - enable/disable indoor channel + * @hdd_ctx: hdd context + * @disable: whether to enable / disable indoor channel + * + * enable/disable indoor channel in wiphy/cds + * + * Return: void + */ +void hdd_update_indoor_channel(struct hdd_context *hdd_ctx, + bool disable); +/** + * hdd_modify_indoor_channel_state_flags() - modify wiphy flags and cds state + * @hdd_ctx: HDD context + * @wiphy_chan: wiphy channel number + * @cds_chan: cds channel structure + * @chan_enum: channel enum maintain in reg db + * @chan_num: channel index + * @disable: Disable/enable the flags + * + * Modify wiphy flags and cds state if channel is indoor. + * + * Return: void + */ +void hdd_modify_indoor_channel_state_flags( + struct hdd_context *hdd_ctx, + struct ieee80211_channel *wiphy_chan, + struct regulatory_channel *cds_chan, + enum channel_enum chan_enum, int chan_num, bool disable); + +/** + * hdd_update_regdb_offload_config() - Update regdb offload disable ini + * for regulatory component. + * @hdd_ctx: HDD context + * + * Return: None + */ +void hdd_update_regdb_offload_config(struct hdd_context *hdd_ctx); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h new file mode 100644 index 0000000000..d76d790d20 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_softap_tx_rx.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_SOFTAP_TX_RX_H) +#define WLAN_HDD_SOFTAP_TX_RX_H + +/** + * DOC: wlan_hdd_softap_tx_rx.h + * + * Linux HDD SOFTAP Tx/Rx APIs + */ + +#include +#include + +#define hdd_sapd_alert(params...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_err(params...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_warn(params...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_info(params...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_debug(params...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_HDD_SAP_DATA, params) + +#define hdd_sapd_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_HDD_SAP_DATA, params) + +#define hdd_sapd_alert_rl(params...) \ + QDF_TRACE_FATAL_RL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_err_rl(params...) \ + QDF_TRACE_ERROR_RL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_warn_rl(params...) \ + QDF_TRACE_WARN_RL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_info_rl(params...) \ + QDF_TRACE_INFO_RL(QDF_MODULE_ID_HDD_SAP_DATA, params) +#define hdd_sapd_debug_rl(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD_SAP_DATA, params) + +/** + * hdd_softap_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet + * @dev: pointer to net_device structure + * + * Function registered as a net_device .ndo_start_xmit() method for + * master mode interfaces (SoftAP/P2P GO), called by the OS if any + * packet needs to be transmitted. + * + * Return: Status of the transmission + */ +netdev_tx_t hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev); + +/** + * hdd_softap_ipa_start_xmit() - Transmit a frame, request from IPA + * @nbuf: pointer to buffer/packet + * @dev: pointer to net_device structure + * + * Function registered as a xmit callback in SAP mode, + * called by IPA if any packet needs to be transmitted. + * + * Return: Status of the transmission + */ +QDF_STATUS hdd_softap_ipa_start_xmit(qdf_nbuf_t nbuf, qdf_netdev_t dev); + +/** + * hdd_softap_tx_timeout() - TX timeout handler + * @dev: pointer to network device + * @txqueue: tx queue + * + * Function registered as a net_device .ndo_tx_timeout() method for + * master mode interfaces (SoftAP/P2P GO), called by the OS if the + * driver takes too long to transmit a frame. + * + * Return: None + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +void hdd_softap_tx_timeout(struct net_device *dev, unsigned int txqueue); +#else +void hdd_softap_tx_timeout(struct net_device *dev); +#endif + +/** + * hdd_softap_init_tx_rx_sta() - Initialize Tx/Rx for a softap station + * @adapter: pointer to adapter context + * @sta_mac: pointer to the MAC address of the station + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_init_tx_rx_sta(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac); + +/** + * hdd_softap_deregister_sta() - Deregister a STA with the Data Path + * @adapter: pointer to adapter context + * @sta_info: double pointer to HDD station info structure + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_deregister_sta(struct hdd_adapter *adapter, + struct hdd_station_info **sta_info); + +/** + * hdd_softap_register_sta() - Register a SoftAP STA + * @link_info: Link info pointer in HDD adapter + * @auth_required: is additional authentication required? + * @privacy_required: should 802.11 privacy bit be set? + * @sta_mac: station MAC address + * @event: STA assoc complete event (Can be NULL) + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +hdd_softap_register_sta(struct wlan_hdd_link_info *link_info, + bool auth_required, bool privacy_required, + struct qdf_mac_addr *sta_mac, + tSap_StationAssocReassocCompleteEvent *event); + +/** + * hdd_softap_register_bc_sta() - Register the SoftAP broadcast STA + * @link_info: Link info pointer in HDD adapter + * @privacy_required: should 802.11 privacy bit be set? + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_register_bc_sta(struct wlan_hdd_link_info *link_info, + bool privacy_required); + +/** + * hdd_softap_stop_bss() - Stop the BSS + * @adapter: pointer to adapter context + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_stop_bss(struct hdd_adapter *adapter); + +/** + * hdd_softap_change_sta_state() - Change the state of a SoftAP station + * @adapter: pointer to adapter context + * @sta_mac: MAC address of the station + * @state: new state of the station + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS hdd_softap_change_sta_state(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac, + enum ol_txrx_peer_state state); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_softap_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * TX Q resume timer handler for SAP and P2P GO interface. If Blocked + * OS Q is not resumed during timeout period, to prevent permanent + * stall, resume OS Q forcefully for SAP and P2P GO interface. + * + * Return: None + */ +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context); + +/** + * hdd_softap_tx_resume_cb() - Resume OS TX Q. + * @adapter_context: pointer to vdev apdapter + * @tx_resume: TX Q resume trigger + * + * Q was stopped due to WLAN TX path low resource condition + * + * Return: None + */ +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume); +#else +static inline +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) +{ +} + +static inline +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) +{ +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +/** + * hdd_ipa_update_rx_mcbc_stats() - Update broadcast multicast stats + * @adapter: pointer to hdd adapter + * @skb: pointer to netbuf + * + * Check if multicast or broadcast pkt was received and increment + * the stats accordingly. This is required only if IPA is enabled + * as in case of regular Rx path mcast/bcast stats are processed + * in the dp layer. + * + * Return: None + */ +void hdd_ipa_update_rx_mcbc_stats(struct hdd_adapter *adapter, + struct sk_buff *skb); + +#ifdef FEATURE_WDS +/** + * hdd_softap_ind_l2_update() - Send L2 update frame to bridge + * @adapter: pointer to adapter context + * @sta_mac: pointer to the MAC address of the station + * + * The layer-2 update frame is an 802.2 type LLC exchange identifier (XID) + * update response frame. This frame is sent using a MAC source address of + * the newly associated station. Upon the reception of this frame, + * all the layer-2 devices update their forwarding tables with the correct + * port to reach the new location of the station according to the ieee802.1d + * bridge table self learning procedure. + * + * Return: QDF_STATUS_E_FAILURE if any errors encountered, + * QDF_STATUS_SUCCESS otherwise + */ +QDF_STATUS hdd_softap_ind_l2_update(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac); +#else +static inline +QDF_STATUS hdd_softap_ind_l2_update(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* end #if !defined(WLAN_HDD_SOFTAP_TX_RX_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_spectralscan.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_spectralscan.h new file mode 100644 index 0000000000..0db6f163b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_spectralscan.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_spectralscan.h + * + * WLAN Host Device Driver spectral scan implementation + * + */ + +#if !defined(WLAN_HDD_SPECTRALSCAN_H) +#define WLAN_HDD_SPECTRALSCAN_H + +#ifdef WLAN_CONV_SPECTRAL_ENABLE + +/* + * enum spectral_scan_msg_type - spectral scan registration + * @SPECTRAL_SCAN_REGISTER_REQ: spectral scan app register request + * @SPECTRAL_SCAN_REGISTER_RSP: spectral scan app register response + */ +enum spectral_scan_msg_type { + SPECTRAL_SCAN_REGISTER_REQ, + SPECTRAL_SCAN_REGISTER_RSP, +}; + +/* + * struct spectral_scan_msg - spectral scan request message + * @msg_type: message type + * @pid: process id + */ +struct spectral_scan_msg { + uint32_t msg_type; + uint32_t pid; +}; + +/** + * struct spectral_scan_msg_v - spectral scan request message included version + * @msg_type: message type + * @pid: process id + * @version: version information + * @sub_version: sub version information + */ +struct spectral_scan_msg_v { + uint32_t msg_type; + uint32_t pid; + uint32_t version; + uint32_t sub_version; +}; + +#define FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_START, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_spectral_scan_start, \ + vendor_command_policy(spectral_scan_policy, \ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_STOP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_spectral_scan_stop, \ + vendor_command_policy(spectral_scan_policy, \ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CONFIG, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_spectral_scan_get_config, \ + vendor_command_policy(spectral_scan_policy, \ + QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CONFIG_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_DIAG_STATS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_spectral_scan_get_diag_stats, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_CAP_INFO, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_spectral_scan_get_cap_info, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SPECTRAL_SCAN_GET_STATUS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_spectral_scan_get_status, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, + +/** + * wlan_hdd_cfg80211_spectral_scan_start() - start spectral scan + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function starts spectral scan + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_cfg80211_spectral_scan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_spectral_scan_stop() - stop spectral scan + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function stops spectral scan + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_cfg80211_spectral_scan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_spectral_scan_get_config() - get spectral scan config + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets the spectral scan configuration + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_cfg80211_spectral_scan_get_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_spectral_scan_get_diag_stats() - + * get spectral scan diag stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets spectral scan diagnostic statistics + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_cfg80211_spectral_scan_get_diag_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_spectral_scan_get_cap_info() - get spectral scan cpa + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets the spectral scan capabilities + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_cfg80211_spectral_scan_get_cap_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_spectral_scan_get_status() - get spectral scan status + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets the spectral scan status + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_cfg80211_spectral_scan_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * hdd_spectral_register_to_dbr() - Register spectral to DBR + * @hdd_ctx: pointer to hdd context + * + * This function registers spectral to Direct Buffer RX component. + * + * Return: None + */ +void hdd_spectral_register_to_dbr(struct hdd_context *hdd_ctx); +#else +#define FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS +static inline void +hdd_spectral_register_to_dbr(struct hdd_context *hdd_ctx) +{ +} +#endif + +#if defined(CNSS_GENL) && defined(WLAN_CONV_SPECTRAL_ENABLE) +/** + * spectral_scan_activate_service() - Activate spectral scan message handler + * @hdd_ctx: callback context to use + * + * This function registers a handler to receive netlink message from + * the spectral scan application process. + * + * Return: None + */ +void spectral_scan_activate_service(struct hdd_context *hdd_ctx); + +/** + * spectral_scan_deactivate_service() - Deactivate spectral scan message handler + * + * This function deregisters a handler to receive netlink message from + * the spectral scan application process. + * + * Return: None + */ +void spectral_scan_deactivate_service(void); + +/** + * wlan_spectral_update_rx_chainmask() - API to update rx chainmask before + * start spectral gen3 + * @link_info: Link info pointer in HDD adapter. + * + * API to update rx chainmask before start spectral gen3. + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS +wlan_spectral_update_rx_chainmask(struct wlan_hdd_link_info *link_info); +#else +static inline void spectral_scan_activate_service(struct hdd_context *hdd_ctx) +{ +} + +static inline void spectral_scan_deactivate_service(void) +{ +} + +#ifdef WLAN_CONV_SPECTRAL_ENABLE +static inline QDF_STATUS +wlan_spectral_update_rx_chainmask(struct wlan_hdd_link_info *link_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_CONV_SPECTRAL_ENABLE */ +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs.h new file mode 100644 index 0000000000..fc46ec4b54 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2017-2018, 2020 The Linux Foundation. All rights reserved. +* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_H_ +#define _WLAN_HDD_SYSFS_H_ + +/** + * struct hdd_sysfs_print_ctx - keeps track of sysfs buffer printing + * @buf: pointer to sysfs char buffer + * @idx: current position in char buffer + * @new_line: if set true, newline will be added at end of each print + */ +struct hdd_sysfs_print_ctx { + char *buf; + int idx; + bool new_line; +}; + +#ifdef WLAN_SYSFS + +#define MAX_SYSFS_USER_COMMAND_SIZE_LENGTH (32) +#define MAX_CMD_INPUT (512) + +/** + * hdd_sysfs_validate_and_copy_buf() - validate sysfs input buf and copy into + * destination buffer + * @dest_buf: pointer to destination buffer where data should be copied + * @dest_buf_size: size of destination buffer + * @src_buf: pointer to constant sysfs source buffer + * @src_buf_size: size of source buffer + * + * Return: 0 for success and error code for failure + */ +int +hdd_sysfs_validate_and_copy_buf(char *dest_buf, size_t dest_buf_size, + char const *src_buf, size_t src_buf_size); + +/** + * hdd_create_sysfs_files() - create sysfs files + * @hdd_ctx: pointer to hdd context + * + * Return: none + */ +void hdd_create_sysfs_files(struct hdd_context *hdd_ctx); + +/** + * hdd_destroy_sysfs_files() - destroy sysfs files + * + * Return: none + */ +void hdd_destroy_sysfs_files(void); + +/** + * hdd_create_adapter_sysfs_files - create adapter sysfs files + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_create_adapter_sysfs_files(struct hdd_adapter *adapter); + +/** + * hdd_destroy_adapter_sysfs_files - destroy adapter sysfs files + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_destroy_adapter_sysfs_files(struct hdd_adapter *adapter); + +/** + * hdd_create_wifi_feature_interface_sysfs_file - Create wifi feature interface + * sysfs file + * + * Return: none + */ +void hdd_create_wifi_feature_interface_sysfs_file(void); + +/** + * hdd_destroy_wifi_feature_interface_sysfs_file - Destroy wifi feature + * interface sysfs file + * + * Return: none + */ +void hdd_destroy_wifi_feature_interface_sysfs_file(void); + +/** + * hdd_sysfs_create_wifi_root_obj() - create wifi root kobj + * + * Return: none + */ +void hdd_sysfs_create_wifi_root_obj(void); + +/** + * hdd_sysfs_destroy_wifi_root_obj() - Destroy wifi root kobj + * + * Return: none + */ +void hdd_sysfs_destroy_wifi_root_obj(void); + +/* + * hdd_sysfs_print() - print to sysfs char buffer + * @ctx: pointer to struct hdd_sysfs_print_ctx + * @fmt: string format + * + * To use this function, create a hdd_sysfs_print_ctx variable, set + * idx to 0, set buf to the outbuffer and set new_line to true or false. + * Pass this context struct to every function call. + * Using this function will then write the data to the outbuffer and + * increment the counter. + * + * The context pointer is void to be compatible with qdf_abstract_print, + * to allow for abstract printing. + * + * Return: Number of characters written + */ +int hdd_sysfs_print(void *ctx, const char *fmt, ...); + +#else +static inline int +hdd_sysfs_validate_and_copy_buf(char *dest_buf, size_t dest_buf_size, + char const *src_buf, size_t src_buf_size) +{ + return -EPERM; +} + +static inline void hdd_create_sysfs_files(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_destroy_sysfs_files(void) +{ +} + +static inline void hdd_create_adapter_sysfs_files(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_destroy_adapter_sysfs_files(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_create_wifi_feature_interface_sysfs_file(void) +{ +} + +static inline void hdd_destroy_wifi_feature_interface_sysfs_file(void) +{ +} + +static inline void hdd_sysfs_create_wifi_root_obj(void) +{ +} + +static inline void hdd_sysfs_destroy_wifi_root_obj(void) +{ +} + +#endif /* End of WLAN SYSFS*/ + +#endif /* End of _WLAN_HDD_SYSFS_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_channel.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_channel.h new file mode 100644 index 0000000000..bb19a3ffb9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_channel.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_channel.h + * + * Implementation for creating sysfs file channel + */ + +#ifndef _WLAN_HDD_SYSFS_CHANNEL_H +#define _WLAN_HDD_SYSFS_CHANNEL_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_CHANNEL) +/** + * hdd_sysfs_channel_interface_create() - API to create channel sysfs + * @adapter: pointer to adapter + * + * this file is created for SAP adapter. + * file path: /sys/class/net/wlanxx/channel + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/channel + * + * Return: none + */ +void hdd_sysfs_channel_interface_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_channel_interface_destroy() - API to destroy channel + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_channel_interface_destroy(struct hdd_adapter *adapter); + +#else +static inline +void hdd_sysfs_channel_interface_create(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_sysfs_channel_interface_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_CHANNEL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_connect_info.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_connect_info.h new file mode 100644 index 0000000000..43bd7e6a03 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_connect_info.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_connect_info.h + * + * implementation for creating sysfs file connect_info + */ + +#ifndef _WLAN_HDD_SYSFS_CONNECT_INFO_H +#define _WLAN_HDD_SYSFS_CONNECT_INFO_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_CONNECT_INFO) + +#define SYSFS_CONNECT_INFO_BUF_SIZE (4 * 1024) + +/** + * hdd_sysfs_connect_info_interface_create() - API to create connect_info sysfs + * interface + * @adapter: pointer to adapter + * + * file path: /sys/class/net/wlanxx/connect_info + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/connect_info + * + * Return: none + */ +void hdd_sysfs_connect_info_interface_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_connect_info_interface_destroy() - API to destroy connect_info + * sysfs interface + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_connect_info_interface_destroy(struct hdd_adapter *adapter); + +#else +static inline +void hdd_sysfs_connect_info_interface_create(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_sysfs_connect_info_interface_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_CONNECT_INFO_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_dump_in_progress.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_dump_in_progress.h new file mode 100644 index 0000000000..fddd94b8bb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_dump_in_progress.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dump_in_progress.h + * + * hdd dump in progress declarations + */ + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_DUMP_IN_PROGRESS) +/** + * hdd_sysfs_create_dump_in_progress_interface() - API to create + * dump_in_progress sysfs file + * @wifi_kobject: sysfs wifi kobject + * + * Return: None + */ +void hdd_sysfs_create_dump_in_progress_interface(struct kobject *wifi_kobject); + +/** + * hdd_sysfs_destroy_dump_in_progress_interface() - API to destroy + * dump_in_progress sysfs file + * @wifi_kobject: sysfs wifi kobject + * + * Return: None + */ +void hdd_sysfs_destroy_dump_in_progress_interface(struct kobject *wifi_kobject); + +#else +static inline void +hdd_sysfs_create_dump_in_progress_interface(struct kobject *wifi_kobject) +{ +} +static inline void +hdd_sysfs_destroy_dump_in_progress_interface(struct kobject *wifi_kobject) +{ +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_ipa.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_ipa.h new file mode 100644 index 0000000000..9ac49c51a5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_ipa.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef WLAN_HDD_SYSFS_IPA_H +#define WLAN_HDD_SYSFS_IPA_H + +#if defined(WLAN_SYSFS) && defined(IPA_OFFLOAD) + +enum ipa_debug_cmd { + IPA_UC_STAT = 1, + IPA_UC_INFO, + IPA_UC_RT_DEBUG_HOST_DUMP, + IPA_DUMP_INFO, +}; + +/** + * hdd_sysfs_ipa_create(): Initialize ipa specific sysfs file + * @adapter: os if adapter + * + * Function to initialize ipa specific mode syfs files. + * + * Return: NONE + */ +void hdd_sysfs_ipa_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_ipa_destroy(): Remove ipucstat specific sysfs file + * @adapter: os if adapter + * + * Function to remove ipa specific mode syfs files. + * + * Return: NONE + */ +void hdd_sysfs_ipa_destroy(struct hdd_adapter *adapter); +#else +static inline +void hdd_sysfs_ipa_create(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_sysfs_ipa_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_pkt_log.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_pkt_log.h new file mode 100644 index 0000000000..7ab1edde26 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_pkt_log.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef WLAN_HDD_SYSFS_PKT_LOG_H +#define WLAN_HDD_SYSFS_PKT_LOG_H + + #if defined(WLAN_SYSFS) && !defined(REMOVE_PKT_LOG) + +/** + * hdd_sysfs_pktlog_create(): Initialize pktlog specific sysfs file + * @driver_kobject: Driver Kobject + * + * Function to initialize pktlog specific mode syfs files. + * + * Return: NONE + */ +void hdd_sysfs_pktlog_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_pktlog_destroy(): Remove pktlog sysfs file + * @driver_kobject: Driver Kobject + * + * Function to remove pktlog specific mode syfs files. + * + * Return: NONE + */ +void hdd_sysfs_pktlog_destroy(struct kobject *driver_kobject); +#else +static inline +void hdd_sysfs_pktlog_create(struct kobject *driver_kobject) +{ +} + +static inline +void hdd_sysfs_pktlog_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_policy_mgr.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_policy_mgr.h new file mode 100644 index 0000000000..49833c5391 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_policy_mgr.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef WLAN_HDD_SYSFS_POLICY_MGR_H +#define WLAN_HDD_SYSFS_POLICY_MGR_H + + #ifdef WLAN_SYSFS + +/** + * hdd_sysfs_pm_cinfo_create(): Initialize pm_cinfo specific sysfs + * @driver_kobject: Driver Kobject + * + * Function to initialize pm_cinfo specific mode syfs files. + * + * Return: NONE + */ +void hdd_sysfs_pm_cinfo_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_pm_cinfo_destroy(): Remove pm_cinfo sysfs file + * @driver_kobject: Driver Kobject + * + * Function to remove pm_cinfo specific mode syfs files. + * + * Return: NONE + */ +void hdd_sysfs_pm_cinfo_destroy(struct kobject *driver_kobject); + +/** + * hdd_sysfs_pm_pcl_create() - API to create pm_pcl + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/pm_pcl + * + * usage: + * echo [arg_0] > pm_pcl + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_pm_pcl_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_pm_pcl_destroy() - API to destroy pm_pcl + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_pm_pcl_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_pm_pcl_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_pm_pcl_destroy(struct kobject *driver_kobject) +{ +} + +static inline +void hdd_sysfs_pm_cinfo_create(struct kobject *driver_kobject) +{ +} + +static inline +void hdd_sysfs_pm_cinfo_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_range_ext.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_range_ext.h new file mode 100644 index 0000000000..2266de8a22 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_range_ext.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_range_ext.h + * + * Implementation for creating sysfs file range_ext + */ + +#ifndef _WLAN_HDD_SYSFS_RANGE_EXT_H +#define _WLAN_HDD_SYSFS_RANGE_EXT_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_RANGE_EXT) +/** + * hdd_sysfs_range_ext_create() - API to create range_ext + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/range_ext + * (wlanxx is adapter name) + * usage: + * echo 1 > range_ext + * + * Return: none + */ +void hdd_sysfs_range_ext_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_range_ext_destroy() - API to destroy range_ext + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_range_ext_destroy(struct hdd_adapter *adapter); +#else +static inline void +hdd_sysfs_range_ext_create(struct hdd_adapter *adapter) +{ +} + +static inline void +hdd_sysfs_range_ext_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_RANGE_EXT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_sta_info.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_sta_info.h new file mode 100644 index 0000000000..01ebfc89ec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_sta_info.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_sta_info.h + * + * implementation for creating sysfs file sta_info + */ + +#ifndef _WLAN_HDD_SYSFS_STA_INFO_H +#define _WLAN_HDD_SYSFS_STA_INFO_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_STA_INFO) +/** + * hdd_sysfs_sta_info_interface_create() - API to create sta_info sysfs + * interface + * @adapter: pointer to adapter + * + * this file is created for SAP adapter. + * file path: /sys/class/net/wlanxx/sta_info + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/sta_info + * + * Return: none + */ +void hdd_sysfs_sta_info_interface_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_sta_info_interface_destroy() - API to destroy sta_info + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_sta_info_interface_destroy(struct hdd_adapter *adapter); + +#else +static inline +void hdd_sysfs_sta_info_interface_create(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_sysfs_sta_info_interface_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_STA_INFO_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_swlm.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_swlm.h new file mode 100644 index 0000000000..2298af541e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_swlm.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_SWLM_H_ +#define _WLAN_HDD_SYSFS_SWLM_H_ + +#ifdef WLAN_DP_FEATURE_SW_LATENCY_MGR +/** + * hdd_sysfs_dp_swlm_create() - Create SWLM specific sysfs entry + * @driver_kobject: Driver kobject + * + * Returns: none + */ +int hdd_sysfs_dp_swlm_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_dp_swlm_destroy() - Destroy SWLM specific sysfs entry + * @driver_kobject: Driver kobject + * + * Returns: none + */ +void hdd_sysfs_dp_swlm_destroy(struct kobject *driver_kobject); +#else +static inline int hdd_sysfs_dp_swlm_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void hdd_sysfs_dp_swlm_destroy(struct kobject *driver_kobject) +{ +} +#endif /* WLAN_DP_FEATURE_SW_LATENCY_MGR */ + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_tdls_peers.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_tdls_peers.h new file mode 100644 index 0000000000..499772b9b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_tdls_peers.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_tdls_peers.h + * + * Implementation for creating sysfs file tdls_peers + */ + +#ifndef _WLAN_HDD_SYSFS_TDLS_PEERS_H +#define _WLAN_HDD_SYSFS_TDLS_PEERS_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_TDLS_PEERS) +/** + * hdd_sysfs_tdls_peers_interface_create() - API to create tdls_peers + * sysfs interface + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/tdls_peers + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/tdls_peers + * + * Return: none + */ +void hdd_sysfs_tdls_peers_interface_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_tdls_peers_interface_destroy() - API to destroy tdls_peers + * sysfs interface + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_tdls_peers_interface_destroy(struct hdd_adapter *adapter); + +#else +static inline +void hdd_sysfs_tdls_peers_interface_create(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_sysfs_tdls_peers_interface_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_TDLS_PEERS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_wifi_features.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_wifi_features.h new file mode 100644 index 0000000000..b5cb8c52f3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_sysfs_wifi_features.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_SYSFS_WIFI_FEATURES_H) +#define WLAN_HDD_SYSFS_WIFI_FEATURES_H +/** + * DOC: wlan_hdd_sysfs_wifi_features.h + * + * Wifi features declarations + */ + +#if defined(WLAN_SYSFS) && defined(FEATURE_SET) +/** + * hdd_sysfs_create_wifi_feature_interface() - API to create + * wifi feature sysfs file + * @wifi_kobject: sysfs wifi kobject + * + * Return: None + */ +void hdd_sysfs_create_wifi_feature_interface(struct kobject *wifi_kobject); + +/** + * hdd_sysfs_destroy_wifi_feature_interface() - API to destroy + * wifi feature sysfs file + * @wifi_kobject: sysfs wifi kobject + * + * Return: None + */ +void hdd_sysfs_destroy_wifi_feature_interface(struct kobject *wifi_kobject); +#else +static inline void +hdd_sysfs_create_wifi_feature_interface(struct kobject *wifi_kobject) +{ +} + +static inline void +hdd_sysfs_destroy_wifi_feature_interface(struct kobject *wifi_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h new file mode 100644 index 0000000000..17869fcf1b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tdls.h @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __HDD_TDLS_H +#define __HDD_TDLS_H +/** + * DOC: wlan_hdd_tdls.h + * WLAN Host Device Driver TDLS include file + */ + +#include "qca_vendor.h" + +struct hdd_context; + +#ifdef FEATURE_WLAN_TDLS + +extern const struct nla_policy + wlan_hdd_tdls_mode_configuration_policy + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1]; + +extern const struct nla_policy + wlan_hdd_tdls_disc_rsp_policy + [QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX + 1]; + +#define FEATURE_TDLS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_CONFIGURE_TDLS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_configure_tdls_mode, \ + vendor_command_policy(wlan_hdd_tdls_mode_configuration_policy, \ + QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_exttdls_enable, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_exttdls_disable, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_exttdls_get_status, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_DISC_RSP_EXT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_exttdls_set_link_id, \ + vendor_command_policy(wlan_hdd_tdls_disc_rsp_policy, \ + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK) \ +}, + +/* Bit mask flag for tdls_option to FW */ +#define ENA_TDLS_OFFCHAN (1 << 0) /* TDLS Off Channel support */ +#define ENA_TDLS_BUFFER_STA (1 << 1) /* TDLS Buffer STA support */ +#define ENA_TDLS_SLEEP_STA (1 << 2) /* TDLS Sleep STA support */ + +int wlan_hdd_tdls_get_all_peers(struct hdd_adapter *adapter, char *buf, + int buflen); + +int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_exttdls_set_link_id() - set link id + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int +wlan_hdd_cfg80211_exttdls_set_link_id(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper); +#else +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *peer, + enum nl80211_tdls_operation oper); +#endif + +#ifdef TDLS_MGMT_VERSION5 +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len, int link_id); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const u8 *peer, + int link_id, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || defined(TDLS_MGMT_VERSION2) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len); +#else +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, const uint8_t *buf, + size_t len); +#endif + +/** + * hdd_set_tdls_offchannel() - set tdls off-channel number + * @hdd_ctx: Pointer to the HDD context + * @adapter: Pointer to the HDD adapter + * @offchannel: tdls off-channel number + * + * This function sets tdls off-channel number + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_offchannel(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + int offchannel); + +/** + * hdd_get_tdls_connected_peer_count() - Gets connected TDLS peer count. + * @link_info: Pointer to link_info in hdd adapter + * + * This function return number of connected peer. + * + * Return: void + */ +uint16_t +hdd_get_tdls_connected_peer_count(struct wlan_hdd_link_info *link_info); + +/** + * hdd_check_and_set_tdls_conn_params() - Sets and Overwrite netdev params if + * stations is connected in 11A, 11B and 11G mode. + * @vdev: Pointer to vdev objmgr + * + * This function updates the netdev params such as enabling checksum/tso + * if the feature "disable checksum/tso for 11abg connections" is enabled via + * INI. if INI is enabled then 11abg sta link will be created by disabling + * checksum/tso which are needed to be enabled for better throughput + * for TDLS connected in 11AX, 11AC, 11N mode + * + * Return: void + */ +void hdd_check_and_set_tdls_conn_params(struct wlan_objmgr_vdev *vdev); + +/** + * hdd_check_and_set_tdls_disconn_params() - Overwrite netdev params if BSS + * STA link is 11A, 11B and 11G mode + * when TDLS is disconnected + * @vdev: Pointer to vdev objmgr + * + * During TDLS connection if STA-BSS link is in 11a, 11b, 11g mode, then + * legacy netdev features such as checksum/tso are enabled. This function will + * take care of disabling them during TDLS disconnection if the feature + * "disable checksum/tso for 11abg connections" is enabled via INI. + * + * Return: void + */ +void hdd_check_and_set_tdls_disconn_params(struct wlan_objmgr_vdev *vdev); + +/** + * hdd_set_tdls_secoffchanneloffset() - set secondary tdls off-channel offset + * @hdd_ctx: Pointer to the HDD context + * @adapter: Pointer to the HDD adapter + * @offchanoffset: tdls off-channel offset + * + * This function sets secondary tdls off-channel offset + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_secoffchanneloffset(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + int offchanoffset); + +/** + * hdd_set_tdls_offchannelmode() - set tdls off-channel mode + * @hdd_ctx: Pointer to the HDD context + * @adapter: Pointer to the HDD adapter + * @offchanmode: tdls off-channel mode + * 1-Enable Channel Switch + * 2-Disable Channel Switch + * + * This function sets tdls off-channel mode + * + * Return: 0 on success; negative errno otherwise + */ +int hdd_set_tdls_offchannelmode(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + int offchanmode); +int hdd_set_tdls_scan_type(struct hdd_context *hdd_ctx, int val); + +/** + * wlan_hdd_tdls_antenna_switch() - Dynamic TDLS antenna switch 1x1 <-> 2x2 + * antenna mode in standalone station + * @link_info: Pointer to link_info in hdd adapter + * @mode: enum antenna_mode + * + * Return: 0 if success else non zero + */ +int wlan_hdd_tdls_antenna_switch(struct wlan_hdd_link_info *link_info, + uint32_t mode); + +/** + * wlan_hdd_cfg80211_configure_tdls_mode() - configure tdls mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +QDF_STATUS hdd_tdls_register_peer(void *userdata, uint32_t vdev_id, + const uint8_t *mac, uint8_t qos); + +/** + * hdd_init_tdls_config() - initialize tdls config + * @tdls_cfg: pointer to tdls_start_params structure + * + * Return: none + */ +void hdd_init_tdls_config(struct tdls_start_params *tdls_cfg); + +/** + * hdd_config_tdls_with_band_switch() - configure tdls when band changes + * Disable tdls offchmode if only one of + * bands is supported + * Enable tdls offchmode if all band enable + * @hdd_ctx: Pointer to the HDD context + * + * Return: none + */ +void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx); +#else + +#define FEATURE_TDLS_VENDOR_COMMANDS + +static inline int +wlan_hdd_tdls_antenna_switch(struct wlan_hdd_link_info *link_info, + uint32_t mode) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline +QDF_STATUS hdd_tdls_register_peer(void *userdata, uint32_t vdev_id, + const uint8_t *mac, uint8_t qos) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_init_tdls_config(struct tdls_start_params *tdls_cfg) +{ +} + +static inline void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) +{ +} + +static inline uint16_t +hdd_get_tdls_connected_peer_count(struct wlan_hdd_link_info *link_info) +{ + return 0; +} + +static inline void +hdd_check_and_set_tdls_conn_params(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +hdd_check_and_set_tdls_disconn_params(struct wlan_objmgr_vdev *vdev) +{ +} +#endif /* End of FEATURE_WLAN_TDLS */ +#endif /* __HDD_TDLS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h new file mode 100644 index 0000000000..8e73a02644 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_trace.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2014-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_TRACE_H__ +#define __WLAN_HDD_TRACE_H__ + +#include "mac_trace.h" + +#define NO_SESSION 0xFF + +#undef ENUMS +#define ENUMS \ + ENUM(TRACE_CODE_HDD_OPEN_REQUEST) \ + ENUM(TRACE_CODE_HDD_STOP_REQUEST) \ + ENUM(TRACE_CODE_HDD_TX_TIMEOUT) \ + ENUM(TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETSUSPENDMODE_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMDELTA_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMDELTA_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETBAND_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETCOUNTRYREV_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_UNINIT_REQUEST) \ + ENUM(TRACE_CODE_HDD_SOFTAP_TX_TIMEOUT) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_SET_MAC_ADDR) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_P2P_SET_NOA_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_P2P_SET_PS_IOCTL) \ + ENUM(TRACE_CODE_HDD_HOSTAPD_SET_SAP_CHANNEL_LIST_IOCTL) \ + ENUM(TRACE_CODE_HDD_ADD_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_DEL_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_CHANGE_VIRTUAL_INTF) \ + ENUM(TRACE_CODE_HDD_CFG80211_START_AP) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_STOP_AP) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_BSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_CONNECT) \ + ENUM(TRACE_CODE_HDD_CFG80211_DISCONNECT) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_TXPOWER) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_TXPOWER) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_CHANNEL) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_BEACON) \ + ENUM(TRACE_CODE_HDD_CFG80211_CHANGE_IFACE) \ + ENUM(TRACE_CODE_HDD_CHANGE_STATION) \ + ENUM(TRACE_CODE_HDD_CFG80211_UPDATE_BSS) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCAN) \ + ENUM(TRACE_CODE_HDD_REMAIN_ON_CHANNEL) \ + ENUM(TRACE_CODE_HDD_REMAINCHANREADYHANDLER) \ + ENUM(TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL) \ + ENUM(TRACE_CODE_HDD_ACTION) \ + ENUM(TRACE_CODE_HDD_MGMT_TX_CANCEL_WAIT) \ + ENUM(TRACE_CODE_HDD_CFG80211_GET_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT) \ + ENUM(TRACE_CODE_HDD_CFG80211_DEL_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_ADD_STA) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_PMKSA) \ + ENUM(TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES) \ + ENUM(TRACE_CODE_HDD_CFG80211_TDLS_MGMT) \ + ENUM(TRACE_CODE_HDD_CFG80211_TDLS_OPER) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA) \ + ENUM(TRACE_CODE_HDD_UNSUPPORTED_IOCTL) \ + ENUM(TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL) \ + ENUM(TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL) \ + ENUM(TRACE_CODE_HDD_STORE_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_CLEAR_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_ISSUE_JOIN_REQ) \ + ENUM(TRACE_CODE_HDD_CFG80211_RESUME_WLAN) \ + ENUM(TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN) \ + ENUM(TRACE_CODE_HDD_CFG80211_SET_MAC_ACL) \ + ENUM(TRACE_CODE_HDD_CFG80211_TESTMODE) \ + ENUM(TRACE_CODE_HDD_CFG80211_DUMP_SURVEY) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START) \ + ENUM(TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP) \ + ENUM(TRACE_CODE_HDD_CFG80211_DEL_PMKSA) \ + ENUM(TRACE_CODE_HDD_SEND_MGMT_TX) \ + /* + * New CFG80211 enums to be added before this comment. + * TRACE_CODE_HDD_RX_SME_MSG is used as code for MTRACE commands. + */ \ + ENUM(TRACE_CODE_HDD_RX_SME_MSG) + +enum { +#undef ENUM +#define ENUM(enum) enum, + ENUMS +}; + +/** + * hdd_trace_event_string() - Convert trace event to string + * @code: trace event enumeration to convert + * + * Return: string representation of the input enumeration + */ +static inline const char *hdd_trace_event_string(uint32_t code) +{ + switch (code) { + default: + return "UNKNOWN"; +#undef ENUM +#define ENUM(enum) CASE_RETURN_STRING(enum) + ENUMS + } +} + +#undef ENUMS +#undef ENUM + +#ifdef HDD_TRACE_RECORD +void hdd_trace_init(void); +#else +static inline void hdd_trace_init(void) {} +#endif + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h new file mode 100644 index 0000000000..92012b40b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tsf.h @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined WLAN_HDD_TSF_H +#define WLAN_HDD_TSF_H +#include "wlan_hdd_cfg.h" +#include "wlan_hdd_main.h" +#ifdef WLAN_FEATURE_TSF_ACCURACY +#include "qdf_hrtimer.h" +#endif +/** + * enum hdd_tsf_get_state - status of get tsf action + * @TSF_RETURN: get tsf + * @TSF_STA_NOT_CONNECTED_NO_TSF: sta not connected to ap + * @TSF_NOT_RETURNED_BY_FW: fw not returned tsf + * @TSF_CURRENT_IN_CAP_STATE: driver in capture state + * @TSF_CAPTURE_FAIL: capture fail + * @TSF_GET_FAIL: get fail + * @TSF_RESET_GPIO_FAIL: GPIO reset fail + * @TSF_SAP_NOT_STARTED_NO_TSF: SAP not started + * @TSF_NOT_READY: TSF module is not initialized or init failed + * @TSF_DISABLED_BY_TSFPLUS: cap_tsf/get_tsf are disabled due to TSF_PLUS + */ +enum hdd_tsf_get_state { + TSF_RETURN = 0, + TSF_STA_NOT_CONNECTED_NO_TSF, + TSF_NOT_RETURNED_BY_FW, + TSF_CURRENT_IN_CAP_STATE, + TSF_CAPTURE_FAIL, + TSF_GET_FAIL, + TSF_RESET_GPIO_FAIL, + TSF_SAP_NOT_STARTED_NO_TSF, + TSF_NOT_READY, + TSF_DISABLED_BY_TSFPLUS +}; + +/** + * enum hdd_tsf_capture_state - status of capture + * @TSF_IDLE: idle + * @TSF_CAP_STATE: current is in capture state + */ +enum hdd_tsf_capture_state { + TSF_IDLE = 0, + TSF_CAP_STATE +}; + +/** + * struct hdd_tsf_op_response - Store TSF sync parameters if TSF sync is active + * @status: TSF response status defined by enum hdd_tsf_get_state + * @time: TSF sync Target time. Time unit is microseconds. + * @soc_time: TSF sync SOC time. Time unit is microseconds. + */ +struct hdd_tsf_op_response { + enum hdd_tsf_get_state status; + uint64_t time; + uint64_t soc_time; +}; + +/** + * enum hdd_tsf_auto_rpt_source - trigger source of tsf auto report + * @HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY: uplink delay feature + * @HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY: transmit latency statistics + */ +enum hdd_tsf_auto_rpt_source { + HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY, + HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY, +}; + +#ifdef WLAN_FEATURE_TSF_AUTO_REPORT +/** + * hdd_set_tsf_auto_report() - enable or disable tsf auto report + * for an adapter + * @adapter: pointer to Adapter context + * @ena: requesting state (true or false) + * @source: source of the request + * + * Return: 0 for success or non-zero negative failure code + */ +int +hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena, + enum hdd_tsf_auto_rpt_source source); + +/** + * hdd_tsf_auto_report_init() - initialize tsf auto report related + * structures for an adapter + * @adapter: pointer to Adapter context + * + * Return: None + */ +void hdd_tsf_auto_report_init(struct hdd_adapter *adapter); +#else +static inline int +hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena, + enum hdd_tsf_auto_rpt_source source) +{ + return -ENOTSUPP; +} + +static inline void hdd_tsf_auto_report_init(struct hdd_adapter *adapter) +{ +} +#endif + +/** + * struct hdd_vdev_tsf - Adapter level tsf params + * @cur_target_time: tsf value received from firmware. + * @cur_tsf_sync_soc_time: Current SOC time. + * @last_tsf_sync_soc_time: Last SOC time when TSF was synced. + * @cur_target_global_tsf_time: Global Fw TSF time. + * @last_target_global_tsf_time: Last reported global Fw TSF time. + * @host_capture_req_timer: Host timer to capture TSF time. + * @tsf_id: TSF id as obtained from FW report. + * @tsf_mac_id: mac_id as obtained from FW report. + * @tsf_details_valid: flag indicating whether tsf details are valid. + * @host_target_sync_lock: spin lock for read/write timestamps. + * @host_target_sync_timer: Timer to Sync host target. + * @host_trigger_gpio_timer: A hrtimer used for TSF Accuracy Feature to + * indicate TSF cycle complete. + * @enable_dynamic_tsf_sync: Enable/Disable TSF sync through NL interface. + * @host_target_sync_force: Force update host to TSF mapping. + * @dynamic_tsf_sync_interval: TSF sync interval configure through NL interface. + * @cur_host_time: Current Host time. + * @last_host_time: Host time when TSF read was done. + * @last_target_time: Last Fw reported time when TSF read was done. + * @continuous_error_count: Store the count of continuous invalid tstamp-pair. + * @continuous_cap_retry_count: to store the count of continuous capture retry. + * @tsf_sync_ready_flag: to indicate whether tsf_sync has been initialized. + * @gpio_tsf_sync_work: work to sync send TSF CAP WMI command. + * @auto_rpt_src: bitmap to record trigger sources of TSF auto report + */ +struct hdd_vdev_tsf { + uint64_t cur_target_time; + uint64_t cur_tsf_sync_soc_time; + uint64_t last_tsf_sync_soc_time; + uint64_t cur_target_global_tsf_time; + uint64_t last_target_global_tsf_time; + qdf_mc_timer_t host_capture_req_timer; +#ifdef QCA_GET_TSF_VIA_REG + int tsf_id; + int tsf_mac_id; + qdf_atomic_t tsf_details_valid; +#endif +#ifdef WLAN_FEATURE_TSF_PLUS + qdf_spinlock_t host_target_sync_lock; + qdf_mc_timer_t host_target_sync_timer; +#ifdef WLAN_FEATURE_TSF_ACCURACY + qdf_hrtimer_data_t host_trigger_gpio_timer; +#endif + bool enable_dynamic_tsf_sync; + bool host_target_sync_force; + uint32_t dynamic_tsf_sync_interval; + uint64_t cur_host_time; + uint64_t last_host_time; + uint64_t last_target_time; + int continuous_error_count; + int continuous_cap_retry_count; + qdf_atomic_t tsf_sync_ready_flag; +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC + qdf_work_t gpio_tsf_sync_work; +#endif +#endif /* WLAN_FEATURE_TSF_PLUS */ +#ifdef WLAN_FEATURE_TSF_AUTO_REPORT + unsigned long auto_rpt_src; + +#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ +}; + +/** + * struct hdd_ctx_tsf - Context level tsf params + * @tsf_ready_flag: indicate whether tsf has been initialized. + * @cap_tsf_flag: indicate whether it's now capturing tsf(updating tstamp-pair). + * @cap_tsf_context: the context that is capturing tsf. + * @tsf_accuracy_context: the context that is capturing tsf accuracy. + * @ptp_cinfo: TSF PTP clock info. + * @ptp_clock: TSF PTP clock. + */ +struct hdd_ctx_tsf { + qdf_atomic_t tsf_ready_flag; + qdf_atomic_t cap_tsf_flag; + struct hdd_adapter *cap_tsf_context; +#ifdef WLAN_FEATURE_TSF_ACCURACY + struct hdd_adapter *tsf_accuracy_context; +#endif +#ifdef WLAN_FEATURE_TSF_PTP + struct ptp_clock_info ptp_cinfo; + struct ptp_clock *ptp_clock; +#endif +}; + +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY +/** + * hdd_get_uplink_delay_len() - get uplink delay length + * @adapter: pointer to the adapter + * + * Return: uplink delay length + */ +uint32_t hdd_get_uplink_delay_len(struct hdd_adapter *adapter); + +/** + * hdd_add_uplink_delay() - add uplink delay + * @adapter: pointer to the adapter + * @skb: nbuf + * + * Return: status + */ +QDF_STATUS hdd_add_uplink_delay(struct hdd_adapter *adapter, + struct sk_buff *skb); +#else /* !WLAN_FEATURE_TSF_UPLINK_DELAY */ +static inline uint32_t hdd_get_uplink_delay_len(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline QDF_STATUS hdd_add_uplink_delay(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ +#ifdef WLAN_FEATURE_TSF +/** + * wlan_hdd_tsf_init() - set gpio and callbacks for + * capturing tsf and init tsf_plus + * @hdd_ctx: pointer to the struct hdd_context + * + * This function set the callback to sme module, the callback will be + * called when a tsf event is reported by firmware; set gpio number + * to FW, FW will toggle this gpio when received a CAP_TSF command; + * do tsf_plus init + * + * Return: nothing + */ +void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_tsf_deinit() - reset callbacks for capturing tsf, deinit tsf_plus + * @hdd_ctx: pointer to the struct hdd_context + * + * This function reset the callback to sme module, and deinit tsf_plus + * + * Return: nothing + */ +void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx); + +/** + * hdd_capture_tsf() - capture tsf + * @adapter: pointer to adapter + * @buf: pointer to uplayer buf + * @len : the length of buf + * + * This function returns tsf value to uplayer. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len); + +/** + * hdd_indicate_tsf() - return tsf to uplayer + * + * @adapter: pointer to adapter + * @tsf_op_resp: pointer to struct hdd_tsf_op_response + * + * This function returns tsf value to uplayer. + * + * Return: Describe the execute result of this routine + */ +int hdd_indicate_tsf(struct hdd_adapter *adapter, + struct hdd_tsf_op_response *tsf_op_resp); + +/** + * wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Handle TSF SET / GET operation from userspace + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf); + +extern const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1]; + +#define FEATURE_HANDLE_TSF_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TSF, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_handle_tsf_cmd, \ + vendor_command_policy(tsf_policy, QCA_WLAN_VENDOR_ATTR_TSF_MAX)\ +}, +#else +static inline void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx) +{ +} + +static inline int hdd_indicate_tsf(struct hdd_adapter *adapter, + struct hdd_tsf_op_response *tsf_op_resp) +{ + return -ENOTSUPP; +} + +static inline int +hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len) +{ + return -ENOTSUPP; +} + +static inline int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return -ENOTSUPP; +} +static inline int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) +{ + return -ENOTSUPP; +} + +#define FEATURE_HANDLE_TSF_VENDOR_COMMANDS +#endif + +#if defined(WLAN_FEATURE_TSF_PLUS) && defined(WLAN_FEATURE_TSF) +/** + * hdd_tsf_is_tx_set() - check ini configuration + * @hdd: pointer to hdd context + * + * This function checks tsf configuration for ptp on tx + * + * Return: true on enable, false on disable + */ + +bool hdd_tsf_is_tx_set(struct hdd_context *hdd); +/** + * hdd_tsf_is_rx_set() - check ini configuration + * @hdd: pointer to hdd context + * + * This function checks tsf configuration for ptp on rx + * + * Return: true on enable, false on disable + */ +bool hdd_tsf_is_rx_set(struct hdd_context *hdd); +/** + * hdd_tsf_is_raw_set() - check ini configuration + * @hdd: pointer to hdd context + * + * This function checks tsf configuration for ptp on raw + * + * Return: true on enable, false on disable + */ +bool hdd_tsf_is_raw_set(struct hdd_context *hdd); +/** + * hdd_tsf_is_dbg_fs_set() - check ini configuration + * @hdd: pointer to hdd context + * + * This function checks tsf configuration for ptp on dbg fs + * + * Return: true on enable, false on disable + */ +bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd); + +/** + * hdd_start_tsf_sync() - start tsf sync + * @adapter: pointer to adapter + * + * This function initialize and start TSF synchronization + * + * Return: Describe the execute result of this routine + */ +int hdd_start_tsf_sync(struct hdd_adapter *adapter); + +/** + * hdd_restart_tsf_sync_post_wlan_resume() - restart host TSF sync + * @adapter: pointer to adapter + * + * This function restarts host TSF sync immediately after wlan resume + * + * Return: none + */ +void hdd_restart_tsf_sync_post_wlan_resume(struct hdd_adapter *adapter); + +/** + * hdd_stop_tsf_sync() - stop tsf sync + * @adapter: pointer to adapter + * + * This function stop and de-initialize TSF synchronization + * + * Return: Describe the execute result of this routine + */ +int hdd_stop_tsf_sync(struct hdd_adapter *adapter); + +/** + * hdd_capture_req_timer_expired_handler() - capture req timer handler + * @arg: pointer to a adapter + * + * This function set a timeout handler for TSF capture timer. + * + * Return: none + */ + +void hdd_capture_req_timer_expired_handler(void *arg); + +/** + * hdd_tsf_is_tsf64_tx_set() - check ini configuration + * @hdd: pointer to hdd context + * + * This function checks tsf configuration for ptp on tsf64 tx + * + * Return: true on enable, false on disable + */ +bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd); + +/** + * hdd_tsf_is_time_sync_enabled_cfg() - check ini configuration + * @hdd_ctx: pointer to hdd context + * + * This function checks tsf configuration for ptp for tsf + * sync period + * Return: true on enable, false on disable + */ +bool hdd_tsf_is_time_sync_enabled_cfg(struct hdd_context *hdd_ctx); + +/** + * hdd_update_dynamic_tsf_sync - Configure TSF mode for vdev + * @adapter: pointer to hdd adapter + * + * This function configures TSF mode for vdev with ini parameter + */ +void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter); + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +/** + * hdd_rx_timestamp() - time stamp RX netbuf + * + * @netbuf: pointer to a RX netbuf + * @target_time: RX time for the netbuf + * + * This function get corresponding host time from target time, + * and time stamp the RX netbuf with this time + * + * Return: Describe the execute result of this routine + */ +int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time); +#endif + +/** + * hdd_get_tsf_time() - get tsf time for system time + * + * @adapter_ctx: adapter context + * @input_time: input system time + * @tsf_time: tsf time for system time + * + * Return: qdf status + */ +QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time, + uint64_t *tsf_time); +#else +static inline int hdd_start_tsf_sync(struct hdd_adapter *adapter) +{ + return -ENOTSUPP; +} + +static inline int hdd_stop_tsf_sync(struct hdd_adapter *adapter) +{ + return -ENOTSUPP; +} + +static inline +void hdd_capture_req_timer_expired_handler(void *arg) +{ +} + +static inline +bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd) +{ + return FALSE; +} + +static inline +bool hdd_tsf_is_time_sync_enabled_cfg(struct hdd_context *hdd_ctx) +{ + return false; +} + +static inline +void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter) +{ +} + +static inline +void hdd_restart_tsf_sync_post_wlan_resume(struct hdd_adapter *adapter) +{ +} + +static inline +QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time, + uint64_t *tsf_time) +{ + *tsf_time = 0; + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PTP +/** + * wlan_get_ts_info() - return ts info to uplayer + * @dev: pointer to net_device + * @info: pointer to ethtool_ts_info + * + * Return: Describe the execute result of this routine + */ +int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info); + +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_twt.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_twt.h new file mode 100644 index 0000000000..0d6cc7672c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_twt.h @@ -0,0 +1,531 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_twt.h + * + * WLAN Host Device Driver file for TWT (Target Wake Time) support. + * + */ + +#if !defined(WLAN_HDD_TWT_H) +#define WLAN_HDD_TWT_H + +#include "qdf_types.h" +#include "qdf_status.h" +#include "qca_vendor.h" +#include + +struct hdd_context; +struct hdd_adapter; +struct wlan_hdd_link_info; +struct wma_tgt_cfg; +struct wmi_twt_add_dialog_param; +struct wmi_twt_del_dialog_param; +struct wmi_twt_pause_dialog_cmd_param; +struct wmi_twt_resume_dialog_cmd_param; + +extern const struct nla_policy +wlan_hdd_wifi_twt_config_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1]; + +#define FEATURE_TWT_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT, \ +}, + +/** + * enum twt_role - TWT role definitions + * @TWT_REQUESTOR: Individual/Bcast TWT requestor role + * @TWT_REQUESTOR_INDV: Individual TWT requestor role + * @TWT_REQUESTOR_BCAST: Broadcast TWT requestor role + * @TWT_RESPONDER: Individual/Bcast TWT responder role + * @TWT_RESPONDER_INDV: Individual TWT responder role + * @TWT_RESPONDER_BCAST: Broadcast TWT responder role + * @TWT_ROLE_ALL: All TWT roles + * @TWT_ROLE_MAX: Place holder for max mode + */ +enum twt_role { + TWT_REQUESTOR, + TWT_REQUESTOR_INDV, + /* Bcast alone cannot be enabled, but can be disabled */ + TWT_REQUESTOR_BCAST, + TWT_RESPONDER, + TWT_RESPONDER_INDV, + /* Bcast alone cannot be enabled, but can be disabled */ + TWT_RESPONDER_BCAST, + TWT_ROLE_ALL, + TWT_ROLE_MAX, +}; + +#ifdef WLAN_SUPPORT_TWT +/** + * enum twt_status - TWT target state + * @TWT_INIT: Init State + * @TWT_DISABLED: TWT is disabled + * @TWT_FW_TRIGGER_ENABLE_REQUESTED: FW triggered enable requested + * @TWT_FW_TRIGGER_ENABLED: FW triggered twt enabled + * @TWT_HOST_TRIGGER_ENABLE_REQUESTED: Host triggered TWT requested + * @TWT_HOST_TRIGGER_ENABLED: Host triggered TWT enabled + * @TWT_DISABLE_REQUESTED: TWT disable requested + * @TWT_SUSPEND_REQUESTED: TWT suspend requested + * @TWT_SUSPENDED: Successfully suspended TWT + * @TWT_RESUME_REQUESTED: TWT Resume requested + * @TWT_RESUMED: Successfully resumed TWT + * @TWT_CLOSED: Deinitialized TWT feature and closed + */ +enum twt_status { + TWT_INIT, + TWT_DISABLED, + TWT_FW_TRIGGER_ENABLE_REQUESTED, + TWT_FW_TRIGGER_ENABLED, + TWT_HOST_TRIGGER_ENABLE_REQUESTED, + TWT_HOST_TRIGGER_ENABLED, + TWT_DISABLE_REQUESTED, + TWT_SUSPEND_REQUESTED, + TWT_SUSPENDED, + TWT_RESUME_REQUESTED, + TWT_RESUMED, + TWT_CLOSED, +}; + +/** + * struct twt_conc_arg: TWT concurrency args + * @hdd_ctx: pointer to hdd context + */ +struct twt_conc_arg { + struct hdd_context *hdd_ctx; +}; + +/** + * struct twt_ack_info_priv - twt ack private info + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @dialog_id: dialog id + * @twt_cmd_ack: twt ack command + * @status: twt command status + */ +struct twt_ack_info_priv { + uint32_t vdev_id; + struct qdf_mac_addr peer_macaddr; + uint32_t dialog_id; + uint32_t twt_cmd_ack; + uint32_t status; +}; + +/** + * wlan_hdd_cfg80211_wifi_twt_config() - Wifi twt configuration + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT + * + * Return: 0 for success, negative errno for failure. + */ +int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * hdd_update_tgt_twt_cap() - Update TWT target capabilities + * @hdd_ctx: HDD Context + * @cfg: Pointer to target configuration + * + * Return: None + */ +void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg); + +/** + * hdd_send_twt_requestor_enable_cmd() - Send TWT requestor enable command to + * target + * @hdd_ctx: HDD Context + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx); + +/** + * hdd_send_twt_responder_enable_cmd() - Send TWT responder enable command to + * target + * @hdd_ctx: HDD Context + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx); + +/** + * hdd_send_twt_requestor_disable_cmd() - Send TWT requestor disable command + * to target + * @hdd_ctx: HDD Context + * @reason: Disable reason code + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_send_twt_requestor_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason); + +/** + * hdd_send_twt_responder_disable_cmd() - Send TWT responder disable command + * to target + * @hdd_ctx: HDD Context + * @reason: Disable reason code + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason); + +/** + * wlan_hdd_twt_init() - Initialize TWT + * @hdd_ctx: pointer to global HDD Context + * + * Initialize the TWT feature by registering the callbacks + * with the lower layers. + * + * Return: None + */ +void wlan_hdd_twt_init(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_twt_deinit() - Deinitialize TWT + * @hdd_ctx: pointer to global HDD Context + * + * Deinitialize the TWT feature by deregistering the + * callbacks with the lower layers. + * + * Return: None + */ +void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx); + +/** + * hdd_test_config_twt_setup_session() - Process TWT setup + * operation in the received test config vendor command and + * send it to firmware + * @adapter: adapter pointer + * @tb: nl attributes + * + * Handles QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP + * + * Return: 0 for Success and negative value for failure + */ +int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter, + struct nlattr **tb); + +/** + * hdd_test_config_twt_terminate_session() - Process TWT terminate + * operation in the received test config vendor command and send + * it to firmware + * @adapter: adapter pointer + * @tb: nl attributes + * + * Handles QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_TERMINATE + * + * Return: 0 for Success and negative value for failure + */ +int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr **tb); +/** + * hdd_send_twt_role_disable_cmd() - Send a specific TWT role + * disable to firmware + * @hdd_ctx: hdd context pointer + * @role : TWT role to be disabled + * + * Return: None + */ +void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx, + enum twt_role role); + +/** + * hdd_send_twt_del_all_sessions_to_userspace() - Terminate all TWT sessions + * @link_info: Link info pointer in HDD adapter + * + * This function checks if association exists and TWT session is setup, + * then send the TWT teardown vendor NL event to the user space. + * + * Return: None + */ +void +hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info *link_info); + +/** + * hdd_twt_concurrency_update_on_scc() - Send TWT disable command to fw if + * SCC exists in two vdevs + * @pdev: pdev pointer + * @object: object pointer + * @arg: argument pointer + * + * Return: None + */ +void hdd_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg); + +/** + * hdd_twt_concurrency_update_on_mcc() - Send TWT disable command to fw if + * MCC exists in two vdevs + * @pdev: pdev pointer + * @object: object pointer + * @arg: argument pointer + * + * Return: None + */ +void hdd_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg); + +/** + * hdd_twt_concurrency_update_on_dbs() - Send TWT enable command to fw if DBS + * exists in two vdevs + * @pdev: pdev pointer + * @object: object pointer + * @arg: argument pointer + * + * Return: None + */ +void hdd_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev, + void *object, void *arg); + +/** + * __hdd_twt_update_work_handler() - TWT work handler to send TWT enable/disable + * command to fw + * @hdd_ctx: HDD pointer context + * + * Return: None + */ +void __hdd_twt_update_work_handler(struct hdd_context *hdd_ctx); + +/** + * hdd_twt_update_work_handler() - Wrapper function + * @data: data pointer + * + * Return: None + */ +void hdd_twt_update_work_handler(void *data); + +/** + * wlan_twt_concurrency_update() - Handles twt concurrency in case of SCC/MCC + * or DBS + * @hdd_ctx: hdd context pointer + * + * Return: None + */ +void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx); + +/** + * hdd_twt_del_dialog_in_ps_disable() - TWT teardown in case of ps disable + * @hdd_ctx: hdd context pointer + * @mac_addr: STA mac address + * @vdev_id: vdev id + * + * Return: None + */ +void hdd_twt_del_dialog_in_ps_disable(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id); + +#define FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_wifi_twt_config, \ + vendor_command_policy(wlan_hdd_wifi_twt_config_policy, \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX) \ +}, + +/** + * hdd_get_twt_requestor() - Get TWT requestor config + * @psoc: global psoc object + * @val: output variable to store the value + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * hdd_get_twt_responder() - Get TWT responder config + * @psoc: global psoc object + * @val: output variable to store the value + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val); + +/** + * wlan_hdd_resume_pmo_twt() - resume twt worker + * @hdd_ctx: hdd context + * + * Return: None + */ +void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx); +/** + * wlan_hdd_suspend_pmo_twt() - suspend twt worker + * @hdd_ctx: hdd context + * + * Return: None + */ +void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx); +/** + * wlan_hdd_is_twt_pmo_allowed() - check twt disabled + * @hdd_ctx: hdd context + * + * Return: true if twt pmo is allowed otherwise false + */ +bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx); +#else +static inline void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} + +static inline +QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS hdd_send_twt_requestor_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ +} + +static inline +int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return -EINVAL; +} + +static inline +int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return -EINVAL; +} + +static inline +void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx, + enum twt_role role) +{ +} + +static inline void +hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info *link_info) +{ +} + +static inline +void hdd_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ +} + +static inline +void hdd_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ +} + +static inline +void hdd_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ +} + +static inline +void __hdd_twt_update_work_handler(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_twt_update_work_handler(void *data) +{ +} + +static inline void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_twt_del_dialog_in_ps_disable(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id) +{ +} + +static inline +QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + *val = false; + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx) +{ +} + +static inline bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx) +{ + return true; +} + +#define FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT + +#endif + +#endif /* if !defined(WLAN_HDD_TWT_H)*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h new file mode 100644 index 0000000000..b4202dce80 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_tx_rx.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_TX_RX_H) +#define WLAN_HDD_TX_RX_H + +/** + * DOC: wlan_hdd_tx_rx.h + * + * Linux HDD Tx/RX APIs + */ + +#include +#include +#include +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include "wlan_dp_public_struct.h" + +struct hdd_netif_queue_history; +struct hdd_context; + +#define hdd_dp_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_HDD_DATA, params) + +#define hdd_dp_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_HDD_DATA, params) + +#define hdd_dp_alert_rl(params...) \ + QDF_TRACE_FATAL_RL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_err_rl(params...) \ + QDF_TRACE_ERROR_RL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_warn_rl(params...) \ + QDF_TRACE_WARN_RL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_info_rl(params...) \ + QDF_TRACE_INFO_RL(QDF_MODULE_ID_HDD_DATA, params) +#define hdd_dp_debug_rl(params...) \ + QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_HDD_DATA, params) + +#define hdd_dp_enter() hdd_dp_debug("enter") +#define hdd_dp_enter_dev(dev) hdd_dp_debug("enter(%s)", (dev)->name) +#define hdd_dp_exit() hdd_dp_debug("exit") + +#define HDD_ETHERTYPE_802_1_X 0x888E +#ifdef FEATURE_WLAN_WAPI +#define HDD_ETHERTYPE_WAI 0x88b4 +#define IS_HDD_ETHERTYPE_WAI(_skb) (ntohs(_skb->protocol) == \ + HDD_ETHERTYPE_WAI) +#else +#define IS_HDD_ETHERTYPE_WAI(_skb) (false) +#endif + +#define HDD_PSB_CFG_INVALID 0xFF +#define HDD_PSB_CHANGED 0xFF +#define SME_QOS_UAPSD_CFG_BK_CHANGED_MASK 0xF1 +#define SME_QOS_UAPSD_CFG_BE_CHANGED_MASK 0xF2 +#define SME_QOS_UAPSD_CFG_VI_CHANGED_MASK 0xF4 +#define SME_QOS_UAPSD_CFG_VO_CHANGED_MASK 0xF8 + +#ifdef CFG80211_CTRL_FRAME_SRC_ADDR_TA_ADDR +#define SEND_EAPOL_OVER_NL true +#else +#define SEND_EAPOL_OVER_NL false +#endif + +netdev_tx_t hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *dev); + +/** + * hdd_tx_timeout() - Wrapper function to protect __hdd_tx_timeout from SSR + * @dev: pointer to net_device structure + * @txqueue: tx queue + * + * Function called by OS if there is any timeout during transmission. + * Since HDD simply enqueues packet and returns control to OS right away, + * this would never be invoked + * + * Return: none + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +void hdd_tx_timeout(struct net_device *dev, unsigned int txqueue); +#else +void hdd_tx_timeout(struct net_device *dev); +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +/** + * hdd_tsf_timestamp_rx() - HDD function to set rx packet timestamp + * @ctx: pointer to HDD context + * @netbuf: pointer to skb + * + * Return: None + */ +void hdd_tsf_timestamp_rx(hdd_cb_handle ctx, qdf_nbuf_t netbuf); + +/** + * hdd_get_tsf_time_cb() - HDD helper function to get TSF time + * @netdev: netdev + * @input_time: Input time + * @tsf_time: time from TFS module + * + * Return: None + */ +void hdd_get_tsf_time_cb(qdf_netdev_t netdev, uint64_t input_time, + uint64_t *tsf_time); +#else +static inline +void hdd_tsf_timestamp_rx(hdd_cb_handle ctx, qdf_nbuf_t netbuf) { } + +static inline +void hdd_get_tsf_time_cb(qdf_netdev_t netdev, uint64_t input_time, + uint64_t *tsf_time) +{ +} +#endif + +/** + * hdd_legacy_gro_get_napi() - HDD function to get napi in legacy gro case + * @nbuf: n/w buffer pointer + * @enable_rxthread: Rx thread enabled/disabled + * + * Return: qdf napi struct on success, NULL on failure + */ +qdf_napi_struct +*hdd_legacy_gro_get_napi(qdf_nbuf_t nbuf, bool enable_rxthread); + +/** + * hdd_disable_rx_ol_in_concurrency() - Disable RX Offload in concurrency + * for rx + * @disable: true if rx offload should be disabled in concurrency + * + * Return: none + */ +void hdd_disable_rx_ol_in_concurrency(bool disable); + +/** + * hdd_tx_queue_cb() - Disable/Enable the Transmit Queues + * @hdd_handle: HDD handle + * @vdev_id: vdev id + * @action: Action to be taken on the Tx Queues + * @reason: Reason for the netif action + * + * Return: None + */ +void hdd_tx_queue_cb(hdd_handle_t hdd_handle, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void hdd_tx_resume_cb(void *adapter_context, bool tx_resume); + +/** + * hdd_tx_flow_control_is_pause() - Is TX Q paused by flow control + * @adapter_context: pointer to vdev apdapter + * + * Return: true if TX Q is paused by flow control + */ +bool hdd_tx_flow_control_is_pause(void *adapter_context); + +/** + * hdd_register_tx_flow_control() - Register TX Flow control + * @adapter: adapter handle + * @timer_callback: timer callback + * @flow_control_fp: txrx flow control + * @flow_control_is_pause_fp: is txrx paused by flow control + * + * Return: none + */ +void hdd_register_tx_flow_control(struct hdd_adapter *adapter, + qdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flow_control_fp, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause_fp); +void hdd_deregister_tx_flow_control(struct hdd_adapter *adapter); + +/** + * hdd_get_tx_resource() - check tx resources and take action + * @vdev_id: vdev id mapped to HDD adapter + * @mac_addr: mac address + * + * Return: none + */ +void hdd_get_tx_resource(uint8_t vdev_id, + struct qdf_mac_addr *mac_addr); + +/** + * hdd_get_tx_flow_low_watermark() - Get TX flow low watermark info + * @cb_ctx: HDD opaque ctx + * @netdev: netdev + * + * Return: flow low watermark value + */ +unsigned int +hdd_get_tx_flow_low_watermark(hdd_cb_handle cb_ctx, qdf_netdev_t netdev); +#else +static inline void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) +{ +} +static inline bool hdd_tx_flow_control_is_pause(void *adapter_context) +{ + return false; +} +static inline void hdd_register_tx_flow_control(struct hdd_adapter *adapter, + qdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flow_control_fp, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause) +{ +} +static inline void hdd_deregister_tx_flow_control(struct hdd_adapter *adapter) +{ +} + +/** + * hdd_get_tx_resource() - check tx resources and take action + * @vdev_id: vdev id mapped to HDD adapter + * @mac_addr: mac address + * + * Return: none + */ +static inline +void hdd_get_tx_resource(uint8_t vdev_id, + struct qdf_mac_addr *mac_addr) { } + +static inline unsigned int +hdd_get_tx_flow_low_watermark(hdd_cb_handle cb_ctx, qdf_netdev_t netdev) +{ + return 0; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_HL_NETDEV_FLOW_CONTROL) +void hdd_tx_resume_timer_expired_handler(void *adapter_context); +#else +static inline void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ +} +#endif + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +void hdd_register_hl_netdev_fc_timer(struct hdd_adapter *adapter, + qdf_mc_timer_callback_t timer_callback); +void hdd_deregister_hl_netdev_fc_timer(struct hdd_adapter *adapter); +#else +static inline void hdd_register_hl_netdev_fc_timer(struct hdd_adapter *adapter, + qdf_mc_timer_callback_t + timer_callback) +{} + +static inline void + hdd_deregister_hl_netdev_fc_timer(struct hdd_adapter *adapter) +{} +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +const char *hdd_reason_type_to_string(enum netif_reason_type reason); +const char *hdd_action_type_to_string(enum netif_action_type action); + +void wlan_hdd_netif_queue_control(struct hdd_adapter *adapter, + enum netif_action_type action, enum netif_reason_type reason); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +int hdd_set_mon_rx_cb(struct net_device *dev); +#else +static inline +int hdd_set_mon_rx_cb(struct net_device *dev) +{ + return 0; +} +#endif + +/** + * hdd_set_udp_qos_upgrade_config() - Set the threshold for UDP packet + * QoS upgrade. + * @adapter: adapter for which this configuration is to be applied + * @priority: the threshold priority + * + * Returns: 0 on success, -EINVAL on failure + */ +int hdd_set_udp_qos_upgrade_config(struct hdd_adapter *adapter, + uint8_t priority); + +/* + * As of the 4.7 kernel, net_device->trans_start is removed. Create shims to + * support compiling against older versions of the kernel. + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)) +static inline void netif_trans_update(struct net_device *dev) +{ + dev->trans_start = jiffies; +} + +#define TX_TIMEOUT_TRACE(dev, module_id) QDF_TRACE( \ + module_id, QDF_TRACE_LEVEL_ERROR, \ + "%s: Transmission timeout occurred jiffies %lu trans_start %lu", \ + __func__, jiffies, dev->trans_start) +#else +#define TX_TIMEOUT_TRACE(dev, module_id) QDF_TRACE( \ + module_id, QDF_TRACE_LEVEL_ERROR, \ + "%s: Transmission timeout occurred jiffies %lu", \ + __func__, jiffies) +#endif + +/** + * hdd_dp_cfg_update() - update hdd config for HDD DP INIs + * @psoc: Pointer to psoc obj + * @hdd_ctx: Pointer to hdd context + * + * Return: None + */ +void hdd_dp_cfg_update(struct wlan_objmgr_psoc *psoc, + struct hdd_context *hdd_ctx); + +/** + * hdd_print_netdev_txq_status() - print netdev tx queue status + * @dev: Pointer to network device + * + * This function is used to print netdev tx queue status + * + * Return: None + */ +void hdd_print_netdev_txq_status(struct net_device *dev); + +/** + * wlan_hdd_dump_queue_history_state() - Dump hdd queue history states + * @q_hist: pointer to hdd queue history structure + * @buf: buffer where the queue history string is dumped + * @size: size of the buffer + * + * Dump hdd queue history states into a buffer + * + * Return: number of bytes written to the buffer + */ +uint32_t +wlan_hdd_dump_queue_history_state(struct hdd_netif_queue_history *q_hist, + char *buf, uint32_t size); + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * wlan_hdd_set_tx_flow_info() - To set TX flow info + * + * This routine is called to set TX flow info + * + * Return: None + */ +void wlan_hdd_set_tx_flow_info(void); +#else +static inline void wlan_hdd_set_tx_flow_info(void) +{ +} +#endif +#endif /* end #if !defined(WLAN_HDD_TX_RX_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h new file mode 100644 index 0000000000..c272544687 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wext.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WEXT_IW_H__ +#define __WEXT_IW_H__ + +#include +#include +#include +#include +#include +#include +#include "qdf_event.h" + +struct hdd_context; +struct sap_config; + +/* + * order of parameters in addTs private ioctl + */ +#define HDD_WLAN_WMM_PARAM_HANDLE 0 +#define HDD_WLAN_WMM_PARAM_TID 1 +#define HDD_WLAN_WMM_PARAM_DIRECTION 2 +#define HDD_WLAN_WMM_PARAM_APSD 3 +#define HDD_WLAN_WMM_PARAM_USER_PRIORITY 4 +#define HDD_WLAN_WMM_PARAM_NOMINAL_MSDU_SIZE 5 +#define HDD_WLAN_WMM_PARAM_MAXIMUM_MSDU_SIZE 6 +#define HDD_WLAN_WMM_PARAM_MINIMUM_DATA_RATE 7 +#define HDD_WLAN_WMM_PARAM_MEAN_DATA_RATE 8 +#define HDD_WLAN_WMM_PARAM_PEAK_DATA_RATE 9 +#define HDD_WLAN_WMM_PARAM_MAX_BURST_SIZE 10 +#define HDD_WLAN_WMM_PARAM_MINIMUM_PHY_RATE 11 +#define HDD_WLAN_WMM_PARAM_SURPLUS_BANDWIDTH_ALLOWANCE 12 +#define HDD_WLAN_WMM_PARAM_SERVICE_INTERVAL 13 +#define HDD_WLAN_WMM_PARAM_SUSPENSION_INTERVAL 14 +#define HDD_WLAN_WMM_PARAM_BURST_SIZE_DEFN 15 +#define HDD_WLAN_WMM_PARAM_ACK_POLICY 16 +#define HDD_WLAN_WMM_PARAM_INACTIVITY_INTERVAL 17 +#define HDD_WLAN_WMM_PARAM_MAX_SERVICE_INTERVAL 18 +#define HDD_WLAN_WMM_PARAM_COUNT 19 + +#define MHZ 6 + +#define WE_MAX_STR_LEN IW_PRIV_SIZE_MASK +#define WLAN_HDD_UI_BAND_AUTO 0 +#define WLAN_HDD_UI_BAND_5_GHZ 1 +#define WLAN_HDD_UI_BAND_2_4_GHZ 2 + +enum hdd_wlan_wmm_direction { + HDD_WLAN_WMM_DIRECTION_UPSTREAM = 0, + HDD_WLAN_WMM_DIRECTION_DOWNSTREAM = 1, + HDD_WLAN_WMM_DIRECTION_BIDIRECTIONAL = 2, +}; + +enum hdd_wlan_wmm_power_save { + HDD_WLAN_WMM_POWER_SAVE_LEGACY = 0, + HDD_WLAN_WMM_POWER_SAVE_UAPSD = 1, +}; + +typedef enum { + /* TSPEC/re-assoc done, async */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS = 0, + /* no need to setup TSPEC since ACM=0 and no UAPSD desired, + * sync + async + */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD = 1, + /* no need to setup TSPEC since ACM=0 and UAPSD already exists, + * sync + async + */ + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING = 2, + /* TSPEC result pending, sync */ + HDD_WLAN_WMM_STATUS_SETUP_PENDING = 3, + /* TSPEC/re-assoc failed, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED = 4, + /* Request rejected due to invalid params, sync + async */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM = 5, + /* TSPEC request rejected since AP!=QAP, sync */ + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM = 6, + + /* TSPEC modification/re-assoc successful, async */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS = 7, + /* TSPEC modification a no-op since ACM=0 and + * no change in UAPSD, sync + async + */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD = 8, + /* TSPEC modification a no-op since ACM=0 and + * requested U-APSD already exists, sync + async + */ + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING = 9, + /* TSPEC result pending, sync */ + HDD_WLAN_WMM_STATUS_MODIFY_PENDING = 10, + /* TSPEC modification failed, prev TSPEC in effect, sync + async */ + HDD_WLAN_WMM_STATUS_MODIFY_FAILED = 11, + /* TSPEC modification request rejected due to invalid params, + * sync + async + */ + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM = 12, + + /* TSPEC release successful, sync and also async */ + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS = 13, + /* TSPEC release pending, sync */ + HDD_WLAN_WMM_STATUS_RELEASE_PENDING = 14, + /* TSPEC release failed, sync + async */ + HDD_WLAN_WMM_STATUS_RELEASE_FAILED = 15, + /* TSPEC release rejected due to invalid params, sync */ + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM = 16, + /* TSPEC modified due to the mux'ing of requests on ACs, async */ + + HDD_WLAN_WMM_STATUS_MODIFIED = 17, + /* TSPEC revoked by AP, async */ + HDD_WLAN_WMM_STATUS_LOST = 18, + /* some internal failure like memory allocation failure, etc, sync */ + HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE = 19, + + /* U-APSD failed during setup but OTA setup (whether TSPEC exchange or + * re-assoc) was done so app should release this QoS, async + */ + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED = 20, + /* U-APSD failed during modify, but OTA setup (whether TSPEC exchange or + * re-assoc) was done so app should release this QoS, async + */ + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED = 21 +} hdd_wlan_wmm_status_e; + +/** Enable 11d */ +#define ENABLE_11D 1 + +/** Disable 11d */ +#define DISABLE_11D 0 + +#define HDD_RTSCTS_EN_MASK 0xF +#define HDD_RTSCTS_ENABLE 1 +#define HDD_CTS_ENABLE 2 + +#define HDD_AUTO_RATE_SGI 0x8 + +/* Packet Types. */ +#define WLAN_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 +#define WLAN_KEEP_ALIVE_NULL_PKT 1 + +/* + * Defines for fw_test command + */ +#define HDD_FWTEST_PARAMS 3 +#define HDD_FWTEST_SU_PARAM_ID 53 +#define HDD_FWTEST_MU_PARAM_ID 2 +#define HDD_FWTEST_SU_DEFAULT_VALUE 100 +#define HDD_FWTEST_MU_DEFAULT_VALUE 40 +#define HDD_FWTEST_MAX_VALUE 500 + +#ifdef WLAN_WEXT_SUPPORT_ENABLE +/** + * hdd_register_wext() - register wext context + * @dev: net device handle + * + * Registers wext interface context for a given net device + * + * Returns: None + */ +void hdd_register_wext(struct net_device *dev); + +/** + * hdd_wext_unregister() - unregister wext context with rtnl lock dependency + * @dev: net device from which wireless extensions are being unregistered + * @rtnl_held: flag which indicates if caller is holding the rtnl_lock + * + * Unregisters wext context for a given net device. This behaves the + * same as hdd_unregister_wext() except it does not take the rtnl_lock + * if the caller is already holding it. + * + * Returns: None + */ +void hdd_wext_unregister(struct net_device *dev, + bool rtnl_held); + +static inline +void hdd_wext_send_event(struct net_device *dev, unsigned int cmd, + union iwreq_data *wrqu, const char *extra) +{ + wireless_send_event(dev, cmd, wrqu, extra); +} + +/** + * hdd_wlan_get_stats() - Get txrx stats in SAP mode + * @link_info: Link info pointer in HDD adapter + * @length: Size of the data copied + * @buffer: Pointer to char buffer. + * @buf_len: Length of the char buffer. + * + * This function called when the "iwpriv wlan0 get_stats" command is given. + * It used to collect the txrx stats when the device is configured in SAP mode. + * + * Return - none + */ +void hdd_wlan_get_stats(struct wlan_hdd_link_info *link_info, uint16_t *length, + char *buffer, uint16_t buf_len); + +void hdd_wlan_list_fw_profile(uint16_t *length, + char *buffer, uint16_t buf_len); + +int iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +int hdd_priv_get_data(struct iw_point *p_priv_data, + union iwreq_data *wrqu); + +void *mem_alloc_copy_from_user_helper(const void *wrqu_data, size_t len); + +/** + * hdd_we_set_short_gi() - Set adapter Short GI + * @link_info: Link info pointer in HDD adapter + * @sgi: new sgi value + * + * Return: 0 on success, negative errno on failure + */ +int hdd_we_set_short_gi(struct wlan_hdd_link_info *link_info, int sgi); + +/** + * hdd_assemble_rate_code() - assemble rate code to be sent to FW + * @preamble: rate preamble + * @nss: number of streams + * @rate: rate index + * + * Rate code assembling is different for targets which are 11ax capable. + * Check for the target support and assemble the rate code accordingly. + * + * Return: assembled rate code + */ +int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate); + +/** + * hdd_set_11ax_rate() - set 11ax rate + * @adapter: adapter being modified + * @value: new 11ax rate code + * @sap_config: pointer to SAP config to check HW mode + * this will be NULL for call from STA persona + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_11ax_rate(struct hdd_adapter *adapter, int value, + struct sap_config *sap_config); + +/** + * hdd_we_update_phymode() - handle change in PHY mode + * @link_info: Link info pointer in HDD adapter. + * @new_phymode: new PHY mode for the device + * + * This function is called when the device is set to a new PHY mode. + * It takes a holistic look at the desired PHY mode along with the + * configured capabilities of the driver and the reported capabilities + * of the hardware in order to correctly configure all PHY-related + * parameters. + * + * Return: 0 on success, negative errno value on error + */ +int hdd_we_update_phymode(struct wlan_hdd_link_info *link_info, + int new_phymode); + +/** + * wlan_hdd_set_btcoex_mode() - set BTCoex Mode + * @link_info: Link info pointer in HDD adapter + * @value: new BTCoex mode for the adapter + * + * This function is called to set a BTCoex Operation Mode + * + * Return: 0 on success, negative errno value on error + */ +int wlan_hdd_set_btcoex_mode(struct wlan_hdd_link_info *link_info, int value); + +/** + * wlan_hdd_set_btcoex_rssi_threshold() - set RSSI threshold + * @link_info: Link info pointer in HDD adapter + * @value: new RSSI Threshold for the adapter + * + * This function is called to set a new RSSI threshold for + * change of Coex operating mode from TDD to FDD + * + * Return: 0 on success, negative errno value on error + */ +int wlan_hdd_set_btcoex_rssi_threshold(struct wlan_hdd_link_info *link_info, + int value); + +struct iw_request_info; + +/** + * hdd_check_private_wext_control() - Check to see if private + * wireless extensions ioctls are allowed + * @hdd_ctx: Global HDD context + * @info: Wireless extensions ioctl information passed by the kernel + * + * This function will examine the "private_wext_control" configuration + * item to determine whether or not private wireless extensions ioctls + * are allowed. + * + * Return: 0 if the ioctl is allowed to be processed, -ENOTSUPP if the + * ioctls have been disabled. Note that in addition to returning + * status, this function will log a message if the ioctls are disabled + * or deprecated. + */ +int hdd_check_private_wext_control(struct hdd_context *hdd_ctx, + struct iw_request_info *info); + +#ifdef CONFIG_DP_TRACE +void hdd_set_dump_dp_trace(uint16_t cmd_type, uint16_t count); +#else +static inline +void hdd_set_dump_dp_trace(uint16_t cmd_type, uint16_t count) {} +#endif +#else /* WLAN_WEXT_SUPPORT_ENABLE */ +static inline void hdd_register_wext(struct net_device *dev) +{ +} + +static inline void hdd_wext_unregister(struct net_device *dev, + bool rtnl_locked) +{ +} + +static inline +void hdd_wext_send_event(struct net_device *dev, unsigned int cmd, + union iwreq_data *wrqu, const char *extra) +{ +} +#endif /* WLAN_WEXT_SUPPORT_ENABLE */ + +#if defined(WLAN_WEXT_SUPPORT_ENABLE) && defined(HASTINGS_BT_WAR) +int hdd_hastings_bt_war_enable_fw(struct hdd_context *hdd_ctx); +int hdd_hastings_bt_war_disable_fw(struct hdd_context *hdd_ctx); +#else +static inline +int hdd_hastings_bt_war_enable_fw(struct hdd_context *hdd_ctx) +{ + return -ENOTSUPP; +} + +static inline +int hdd_hastings_bt_war_disable_fw(struct hdd_context *hdd_ctx) +{ + return -ENOTSUPP; +} + +#endif + +#endif /* __WEXT_IW_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wifi_pos_pasn.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wifi_pos_pasn.h new file mode 100644 index 0000000000..e4d6126ce5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wifi_pos_pasn.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_wifi_pos_pasn.h + * + * WLAN Host Device Driver WIFI POSITION module PASN authentication + * feature interface definitions + * + */ +#ifndef __WLAN_HDD_WIFI_POS_PASN_H__ +#define __WLAN_HDD_WIFI_POS_PASN_H__ +#include "qdf_types.h" +#include "qdf_status.h" +#include "qca_vendor.h" +#include +#include "wlan_hdd_object_manager.h" + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) + +extern const struct nla_policy +wifi_pos_pasn_auth_status_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + +extern const struct nla_policy +wifi_pos_pasn_auth_policy[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1]; + +extern const struct nla_policy +wifi_pos_pasn_set_ranging_ctx_policy[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX + 1]; + +int wlan_hdd_wifi_pos_send_pasn_auth_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_WIFI_POS_11AZ_AUTH_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PASN, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_wifi_pos_send_pasn_auth_status, \ + vendor_command_policy(wifi_pos_pasn_auth_status_policy, \ + QCA_WLAN_VENDOR_ATTR_MAX) \ +}, + +int +wlan_hdd_cfg80211_set_secure_ranging_context(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +#define FEATURE_WIFI_POS_SET_SECURE_RANGING_CONTEXT_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SECURE_RANGING_CONTEXT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV, \ + .doit = wlan_hdd_cfg80211_set_secure_ranging_context, \ + vendor_command_policy(wifi_pos_pasn_set_ranging_ctx_policy, \ + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX) \ +}, +#else +#define FEATURE_WIFI_POS_11AZ_AUTH_COMMANDS +#define FEATURE_WIFI_POS_SET_SECURE_RANGING_CONTEXT_COMMANDS +#endif /* WIFI_POS_CONVERGED && WLAN_FEATURE_RTT_11AZ_SUPPORT */ +#endif /* __WLAN_HDD_WIFI_POS_PASN_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h new file mode 100644 index 0000000000..a1573a79e3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wmm.h @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2011-2012,2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_WMM_H +#define _WLAN_HDD_WMM_H + +/** + * DOC: HDD WMM + * + * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) + * houses all the logic for WMM in HDD. + * + * On the control path, it has the logic to setup QoS, modify QoS and delete + * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an + * explicit application invoked and an internal HDD invoked. The implicit QoS + * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but + * which DO mark their traffic for priortization. It also has logic to start, + * update and stop the U-APSD trigger frame generation. It also has logic to + * read WMM related config parameters from the registry. + * + * On the data path, it has the logic to figure out the WMM AC of an egress + * packet and when to signal TL to serve a particular AC queue. It also has the + * logic to retrieve a packet based on WMM priority in response to a fetch from + * TL. + * + * The remaining functions are utility functions for information hiding. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include + +/*Maximum number of ACs */ +#define WLAN_MAX_AC 4 + + +/* Preprocessor Definitions and Constants */ + +/* #define HDD_WMM_DEBUG 1 */ + +#define HDD_WMM_CTX_MAGIC 0x574d4d58 /* "WMMX" */ + +#define HDD_WMM_HANDLE_IMPLICIT 0xFFFFFFFF + +#define HDD_WLAN_INVALID_STA_ID 0xFF + +/* Type Declarations */ + +/** + * enum hdd_wmm_user_mode - WMM modes of operation + * + * @HDD_WMM_USER_MODE_AUTO: STA can associate with any AP, & HDD looks at + * the SME notification after association to find out if associated + * with QAP and acts accordingly + * @HDD_WMM_USER_MODE_QBSS_ONLY: SME will add the extra logic to make sure + * STA associates with a QAP only + * @HDD_WMM_USER_MODE_NO_QOS: Join any AP, but uapsd is disabled + */ +enum hdd_wmm_user_mode { + HDD_WMM_USER_MODE_AUTO = 0, + HDD_WMM_USER_MODE_QBSS_ONLY = 1, + HDD_WMM_USER_MODE_NO_QOS = 2, +}; + +/* UAPSD Mask bits */ +/* (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) */ +#define HDD_AC_VO 0x1 +#define HDD_AC_VI 0x2 +#define HDD_AC_BK 0x4 +#define HDD_AC_BE 0x8 + +/** + * enum hdd_wmm_linuxac: AC/Queue Index values for Linux Qdisc to + * operate on different traffic. + * @HDD_LINUX_AC_VO: voice priority + * @HDD_LINUX_AC_VI: video priority + * @HDD_LINUX_AC_BE: best effort priority + * @HDD_LINUX_AC_BK: background priority + * @HDD_LINUX_AC_HI_PRIO: unclassified high priority + */ +enum hdd_wmm_linuxac { + HDD_LINUX_AC_VO = 0, + HDD_LINUX_AC_VI = 1, + HDD_LINUX_AC_BE = 2, + HDD_LINUX_AC_BK = 3, + HDD_LINUX_AC_HI_PRIO = 4, +}; + +/** + * struct hdd_wmm_qos_context - HDD WMM QoS Context + * + * This structure holds the context for a single flow which has either + * been configured explicitly from userspace or implicitly via the + * Implicit QoS feature. + * + * @node: list node which can be used to put the context into a list + * of contexts + * @handle: identifier which uniquely identifies this context to userspace + * @flow_id: identifier which uniquely identifies this flow to SME + * @adapter: adapter upon which this flow was configured + * @ac_type: access category for this flow + * @status: the status of the last operation performed on this flow by SME + * @implicit_qos_work: work structure used for deferring implicit QoS work + * from softirq context to thread context + * @magic: magic number used to verify that this is a valid context when + * referenced anonymously + * @is_inactivity_timer_running: true if inactivity timer is running + * @ts_id: identifier which gets used at time of DEL request + */ +struct hdd_wmm_qos_context { + struct list_head node; + uint32_t handle; + uint32_t flow_id; + struct hdd_adapter *adapter; + sme_ac_enum_type ac_type; + hdd_wlan_wmm_status_e status; + struct work_struct implicit_qos_work; + uint32_t magic; + bool is_inactivity_timer_running; + uint8_t ts_id; +}; + +/** + * struct hdd_wmm_ac_status - WMM related per-AC state & status info + * @is_access_required: does the AP require access to this AC? + * @is_access_needed: does the worker thread need to acquire access to + * this AC? + * @is_access_pending: is implicit QoS negotiation currently taking place? + * @has_access_failed: has implicit QoS negotiation already failed? + * @was_access_granted: has implicit QoS negotiation already succeeded? + * @is_access_allowed: is access to this AC allowed, either because we + * are not doing WMM, we are not doing implicit QoS, implicit QoS has + * completed, or explicit QoS has completed? + * @is_tspec_valid: is the tspec valid? + * @is_uapsd_info_valid: are the UAPSD-related fields valid? + * @tspec: current (possibly aggregate) Tspec for this AC + * @is_uapsd_enabled: is UAPSD enabled on this AC? + * @uapsd_service_interval: service interval for this AC + * @uapsd_suspension_interval: suspension interval for this AC + * @uapsd_direction: direction for this AC + * @inactivity_time: inactivity time for this AC + * @last_traffic_count: TX counter used for inactivity detection + * @inactivity_timer: timer used for inactivity detection + */ +struct hdd_wmm_ac_status { + bool is_access_required; + bool is_access_needed; + bool is_access_pending; + bool has_access_failed; + bool was_access_granted; + bool is_access_allowed; + bool is_tspec_valid; + bool is_uapsd_info_valid; + struct sme_qos_wmmtspecinfo tspec; + bool is_uapsd_enabled; + uint32_t uapsd_service_interval; + uint32_t uapsd_suspension_interval; + enum sme_qos_wmm_dir_type uapsd_direction; + +#ifdef FEATURE_WLAN_ESE + uint32_t inactivity_time; + uint32_t last_traffic_count; + qdf_mc_timer_t inactivity_timer; +#endif +}; + +/** + * struct hdd_wmm_status - WMM status maintained per-adapter + * @context_list: list of WMM contexts active on the adapter + * @mutex: mutex used for exclusive access to this adapter's WMM status + * @ac_status: per-AC WMM status + * @qap: is this connected to a QoS-enabled AP? + * @qos_connection: is this a QoS connection? + */ +struct hdd_wmm_status { + struct list_head context_list; + struct mutex mutex; + struct hdd_wmm_ac_status ac_status[WLAN_MAX_AC]; + bool qap; + bool qos_connection; +}; + +extern const uint8_t hdd_qdisc_ac_to_tl_ac[]; +extern const uint8_t hdd_wmm_up_to_ac_map[]; +extern const uint8_t hdd_linux_up_to_ac_map[]; + +/** + * hdd_wmmps_helper() - Function to set uapsd psb dynamically + * + * @adapter: [in] pointer to adapter structure + * @ptr: [in] pointer to command buffer + * + * Return: Zero on success, appropriate error on failure. + */ +int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr); + +/** + * hdd_send_dscp_up_map_to_fw() - send dscp to up map to FW + * @adapter : [in] pointer to Adapter context + * + * This function will send the WMM DSCP configuration of an + * adapter to FW. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_send_dscp_up_map_to_fw(struct hdd_adapter *adapter); + +/** + * hdd_wmm_dscp_initial_state() - initialize the WMM DSCP configuration + * @adapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuration of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs or via QoS Map sent OTA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_dscp_initial_state(struct hdd_adapter *adapter); + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @adapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuration and status of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter); + +/** + * hdd_wmm_adapter_close() - WMM close function + * @adapter: [in] pointer to adapter context + * + * Function which will perform any necessary work to to clean up the + * WMM functionality prior to the kernel module unload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter); + +/** + * hdd_select_queue() - Return queue to be used. + * @dev: Pointer to the WLAN device. + * @skb: Pointer to OS packet (sk_buff). + * @sb_dev: Pointer to subordinate device (unused) + * + * This function is registered with the Linux OS for network + * core to decide which queue to use for the skb. + * + * Return: Qdisc queue index. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev, + select_queue_fallback_t fallback); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv); +#else +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb); +#endif + +/** + * hdd_wmm_select_queue() - Function which will classify the packet + * according to linux qdisc expectation. + * + * @dev: [in] pointer to net_device structure + * @skb: [in] pointer to os packet + * + * Return: Qdisc queue index + */ +uint16_t hdd_wmm_select_queue(struct net_device *dev, + struct sk_buff *skb); + +/** + * hdd_wmm_acquire_access_required() - Function which will determine + * acquire admittance for a WMM AC is required or not based on psb configuration + * done in framework + * + * @adapter: [in] pointer to adapter structure + * @ac_type: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter, + sme_ac_enum_type ac_type); + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @adapter: [in] pointer to adapter context + * @ac_type: [in] WMM AC type of OS packet + * @granted: [out] pointer to bool flag when indicates if access + * has been granted or not + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter, + sme_ac_enum_type ac_type, bool *granted); + +/** + * hdd_wmm_assoc() - Function which will handle the housekeeping + * required by WMM when association takes place + * + * @adapter: pointer to adapter context + * @is_reassoc: is this reassoc scenario + * @uapsd_mask : Negotiated uapsd msk + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter, + bool is_reassoc, uint8_t uapsd_mask); + +/** + * hdd_wmm_connect() - Function which will handle the housekeeping + * required by WMM when a connection is established + * + * @adapter : [in] pointer to adapter context + * @roam_info: [in] pointer to roam information + * @bss_type : [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType bss_type); + +/** + * hdd_wmm_is_active() - Function which will determine if WMM is + * active on the current connection + * + * @adapter: [in] pointer to adapter context + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_active(struct hdd_adapter *adapter); + +/** + * hdd_wmm_is_acm_allowed() - Function which will determine if WMM is + * active on the current connection + * + * @vdev_id: vdev id + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_acm_allowed(uint8_t vdev_id); + + +/** + * hdd_wmm_addts() - Function which will add a traffic spec at the + * request of an application + * + * @adapter : [in] pointer to adapter context + * @handle : [in] handle to uniquely identify a TS + * @tspec : [in] pointer to the traffic spec + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter, + uint32_t handle, + struct sme_qos_wmmtspecinfo *tspec); + +/** + * hdd_wmm_delts() - Function which will delete a traffic spec at the + * request of an application + * + * @adapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter, + uint32_t handle); + +/** + * hdd_wmm_checkts() - Function which will return the status of a traffic + * spec at the request of an application + * + * @adapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter, + uint32_t handle); +/** + * hdd_wmm_adapter_clear() - Function which will clear the WMM status + * for all the ACs + * + * @adapter: [in] pointer to Adapter context + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter); + +void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter); + +extern const struct nla_policy +config_tspec_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1]; + +/** + * wlan_hdd_cfg80211_config_tspec() - config tpsec + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to config tspec command parameters. + * @data_len: the length in byte of config tspec command parameters. + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +#ifdef QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES +/** + * hdd_wmm_classify_pkt_cb() - Call back to identify critical packets + * @adapter: adapter for which callback is called + * @nbuf: skb for which callback is called + * + * Callback used by intrabss forwarding path to identify critical packets. + * QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL is marked 1 for such packets. + * The function also populates sb->priority for these packets. + * skb->priority is used as TID for these frames during TX. + * + * Return: None + */ +void hdd_wmm_classify_pkt_cb(void *adapter, + qdf_nbuf_t nbuf); +#else +static inline +void hdd_wmm_classify_pkt_cb(void *adapter, + qdf_nbuf_t nbuf) +{ +} +#endif + +#define FEATURE_WMM_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_CONFIG_TSPEC, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_config_tspec, \ + vendor_command_policy(config_tspec_policy, \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX) \ +}, + +#endif /* #ifndef _WLAN_HDD_WMM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h new file mode 100644 index 0000000000..3ad61acc23 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/inc/wlan_hdd_wowl.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_WOWL_H +#define _WLAN_HDD_WOWL_H + +/** + * DOC: wlan_hdd_wowl + * + * This module houses all the logic for WOWL in HDD. + * + * It provides the following APIs + * + * - Ability to enable/disable following WoWL modes + * 1) Magic packet (MP) mode + * 2) Pattern Byte Matching (PBM) mode + * - Ability to add/remove patterns for PBM + * + * A Magic Packet is a packet that contains 6 0xFFs followed by 16 + * contiguous copies of the receiving NIC's Ethernet address. There is + * no API to configure Magic Packet Pattern. + * + * Wakeup pattern (used for PBM) is defined as following: + * typedef struct + * { + * U8 PatternSize; // Non-Zero pattern size + * U8 PatternMaskSize; // Non-zero pattern mask size + * U8 PatternMask[PatternMaskSize]; // Pattern mask + * U8 Pattern[PatternSize]; // Pattern + * } hdd_wowl_ptrn_t; + * + * PatternSize and PatternMaskSize indicate size of the variable + * length Pattern and PatternMask. PatternMask indicates which bytes + * of an incoming packet should be compared with corresponding bytes + * in the pattern. + * + * Maximum allowed pattern size is 128 bytes. Maximum allowed + * PatternMaskSize is 16 bytes. + * + * Maximum number of patterns that can be configured is 8 + * + * HDD will add following 2 commonly used patterns for PBM by default: + * 1) ARP Broadcast Pattern + * 2) Unicast Pattern + * + * However note that WoWL will not be enabled by default by HDD. WoWL + * needs to enabled explcitly by exercising the iwpriv command. + * + * HDD will expose an API that accepts patterns as Hex string in the + * following format: + * "PatternSize:PatternMaskSize:PatternMask:Pattern" + * + * Multiple patterns can be specified by deleimiting each pattern with + * the ';' token: + * "PatternSize1:PatternMaskSize1:PatternMask1:Pattern1;PatternSize2:..." + * + * Patterns can be configured dynamically via iwpriv cmd or statically + * via qcom_cfg.ini file + * + * PBM (when enabled) can perform filtering on unicast data or + * broadcast data or both. These configurations are part of factory + * defaults (cfg.dat) and the default behavior is to perform filtering + * on both unicast and data frames. + * + * MP filtering (when enabled) is performed ALWAYS on both unicast and + * broadcast data frames. + * + * Management frames are not subjected to WoWL filtering and are + * discarded when WoWL is enabled. + * + * Whenever a pattern match succeeds, RX path is restored and packets + * (both management and data) will be pushed to the host from that + * point onwards. Therefore, exit from WoWL is implicit and happens + * automatically when the first packet match succeeds. + * + * WoWL works on top of BMPS. So when WoWL is requested, SME will + * attempt to put the device in BMPS mode (if not already in BMPS). If + * attempt to BMPS fails, request for WoWL will be rejected. + */ + +#include +#include "wlan_pmo_wow_public_struct.h" + +#define WOWL_PTRN_MAX_SIZE 146 +#define WOWL_PTRN_MASK_MAX_SIZE 19 +#define WOWL_MAX_PTRNS_ALLOWED PMO_WOW_FILTERS_MAX + +/** + * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be + * used when PBM filtering is enabled + * @adapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn(struct hdd_adapter *adapter, const char *ptrn); + +/** + * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern + * @adapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn(struct hdd_adapter *adapter, const char *ptrn); + +/** + * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern + * sent from debugfs interface + * @adapter: pointer to the adapter + * @pattern_idx: index of the pattern to be added + * @pattern_offset: offset of the pattern in the frame payload + * @pattern_buf: pointer to the pattern hex string to be added + * @pattern_mask: pointer to the pattern mask hex string + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn_debugfs(struct hdd_adapter *adapter, uint8_t pattern_idx, + uint8_t pattern_offset, char *pattern_buf, + char *pattern_mask); + +/** + * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern + * sent from debugfs interface + * @adapter: pointer to the adapter + * @pattern_idx: index of the pattern to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn_debugfs(struct hdd_adapter *adapter, + uint8_t pattern_idx); + +/** + * hdd_free_user_wowl_ptrns() - Deinit function to cleanup WoWL allocated memory + * + * Return: None + */ +void hdd_free_user_wowl_ptrns(void); + +#endif /* #ifndef _WLAN_HDD_WOWL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_active_tos.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_active_tos.c new file mode 100644 index 0000000000..44290e1ef8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_active_tos.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_active_tos.c + * + * WLAN active tos functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_scan_ucfg_api.h" + +#define HDD_AC_BK_BIT 1 +#define HDD_AC_BE_BIT 2 +#define HDD_AC_VI_BIT 4 +#define HDD_AC_VO_BIT 8 + +#define HDD_MAX_OFF_CHAN_TIME_FOR_VO 20 +#define HDD_MAX_OFF_CHAN_TIME_FOR_VI 20 +#define HDD_MAX_OFF_CHAN_TIME_FOR_BE 40 +#define HDD_MAX_OFF_CHAN_TIME_FOR_BK 40 + +#define HDD_MAX_OFF_CHAN_ENTRIES 2 + +#define HDD_AC_BIT_INDX 0 +#define HDD_DWELL_TIME_INDX 1 + +static int limit_off_chan_tbl[QCA_WLAN_AC_ALL][HDD_MAX_OFF_CHAN_ENTRIES] = { + { HDD_AC_BK_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BK }, + { HDD_AC_BE_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_BE }, + { HDD_AC_VI_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VI }, + { HDD_AC_VO_BIT, HDD_MAX_OFF_CHAN_TIME_FOR_VO }, +}; + +const struct nla_policy +wlan_hdd_set_limit_off_channel_param_policy +[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START] = {.type = NLA_U8 }, +}; + +/** + * hdd_set_limit_off_chan_for_tos() - set limit off-channel command parameters + * @adapter: HDD adapter + * @tos: type of service + * @is_tos_active: status of the traffic + * + * Return: 0 on success and non zero value on failure + */ + +static int +hdd_set_limit_off_chan_for_tos(struct hdd_adapter *adapter, + enum qca_wlan_ac_type tos, + bool is_tos_active) +{ + int ac_bit; + struct hdd_context *hdd_ctx; + uint32_t max_off_chan_time = 0; + QDF_STATUS status; + int ret; + uint8_t def_sys_pref = 0; + uint32_t rest_conc_time; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + + if (ret < 0) + return ret; + ucfg_policy_mgr_get_sys_pref(hdd_ctx->psoc, + &def_sys_pref); + + ac_bit = limit_off_chan_tbl[tos][HDD_AC_BIT_INDX]; + + if (is_tos_active) + adapter->active_ac |= ac_bit; + else + adapter->active_ac &= ~ac_bit; + + if (adapter->active_ac) { + if (adapter->active_ac & HDD_AC_VO_BIT) { + max_off_chan_time = + limit_off_chan_tbl[QCA_WLAN_AC_VO][HDD_DWELL_TIME_INDX]; + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, + PM_LATENCY); + } else if (adapter->active_ac & HDD_AC_VI_BIT) { + max_off_chan_time = + limit_off_chan_tbl[QCA_WLAN_AC_VI][HDD_DWELL_TIME_INDX]; + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, + PM_LATENCY); + } else { + /*ignore this command if only BE/BK is active */ + is_tos_active = false; + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, + def_sys_pref); + } + } else { + /* No active tos */ + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, + def_sys_pref); + } + + ucfg_scan_cfg_get_conc_max_resttime(hdd_ctx->psoc, &rest_conc_time); + status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + is_tos_active, + max_off_chan_time, + rest_conc_time, + true); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to set limit off chan params"); + ret = -EINVAL; + } + + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd + * parameters + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * This is called when application wants to limit the off channel time due to + * active voip traffic. + * + * Return: An error code or 0 on success. + */ +static int +__wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1]; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + uint8_t tos; + uint8_t tos_status; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret < 0) + return ret; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX, + data, data_len, + wlan_hdd_set_limit_off_channel_param_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]) { + hdd_err("attr tos failed"); + goto fail; + } + + tos = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS]); + if (tos >= QCA_WLAN_AC_ALL) { + hdd_err("tos value %d exceeded Max value %d", + tos, QCA_WLAN_AC_ALL); + goto fail; + } + hdd_debug("tos %d", tos); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]) { + hdd_err("attr tos active failed"); + goto fail; + } + tos_status = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_START]); + + hdd_debug("tos status %d", tos_status); + ret = hdd_set_limit_off_chan_for_tos(adapter, tos, tos_status); + +fail: + return ret; +} + +int wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) + +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_limit_offchan_param(wiphy, wdev, data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_active_tos.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_active_tos.h new file mode 100644 index 0000000000..08ac79d76b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_active_tos.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_ACTIVE_TOS_H +#define __WLAN_HDD_ACTIVE_TOS_H + +/** + * DOC: wlan_hdd_active_tos_h + * + * WLAN Host Device Driver ACTIVE TOS API specification + */ + +#ifdef FEATURE_ACTIVE_TOS +/** + * wlan_hdd_cfg80211_set_limit_offchan_param() - set limit off-channel cmd + * parameters + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * This is called when application wants to limit the off channel time due to + * active voip traffic. + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_set_limit_offchan_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +extern const struct nla_policy + wlan_hdd_set_limit_off_channel_param_policy + [QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX + 1]; + +#define FEATURE_ACTIVE_TOS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ACTIVE_TOS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_limit_offchan_param, \ + vendor_command_policy(wlan_hdd_set_limit_off_channel_param_policy, \ + QCA_WLAN_VENDOR_ATTR_ACTIVE_TOS_MAX) \ +}, +#else /* FEATURE_ACTIVE_TOS */ +#define FEATURE_ACTIVE_TOS_VENDOR_COMMANDS +#endif /* FEATURE_ACTIVE_TOS */ + +#endif /* __WLAN_HDD_ACTIVE_TOS_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_afc.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_afc.c new file mode 100644 index 0000000000..cb8a8a02d5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_afc.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_hdd_afc.c + * + * This file has the AFC osif interface with linux kernel. + */ + +#include +#include +#include +#include +#include +#include + +int wlan_hdd_vendor_afc_response(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter(); + + ret = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (ret) + return ret; + + hdd_ctx = wiphy_priv(wiphy); + + if (!hdd_ctx->psoc) { + osif_err("psoc is null"); + ret = -EINVAL; + goto sync_stop; + } + + if (!hdd_ctx->pdev) { + osif_err("pdev is null"); + ret = -EINVAL; + goto sync_stop; + } + + ret = wlan_cfg80211_vendor_afc_response(hdd_ctx->psoc, + hdd_ctx->pdev, + data, + data_len); +sync_stop: + osif_psoc_sync_op_stop(psoc_sync); + + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_send_response_to_afcmem() - Callback function register to AFC + * common component. + * @psoc: Pointer to PSOC object + * @pdev: Pointer to PDEV object + * @data: Pointer to AFC response data pass to target + * @len: Length of AFC response data pass to target + * + * Return: 0 if success, otherwise error code + */ +static int wlan_hdd_send_response_to_afcmem(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct wlan_afc_host_resp *data, + uint32_t len) +{ + qdf_device_t qdf_dev; + int pdev_id; + const uint8_t *afcdb = (const uint8_t *)data; + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + if (!qdf_dev) { + osif_err("Invalid qdf dev"); + return -EINVAL; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + + return pld_send_buffer_to_afcmem(qdf_dev->dev, + afcdb, + len, + pdev_id); +} + +void wlan_hdd_register_afc_pld_cb(struct wlan_objmgr_psoc *psoc) +{ + ucfg_afc_register_data_send_cb(psoc, wlan_hdd_send_response_to_afcmem); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_apf.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_apf.c new file mode 100644 index 0000000000..952b8702f1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_apf.c @@ -0,0 +1,723 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_apf.c + * + * Android Packet Filter support and implementation + */ + +#include "wlan_hdd_apf.h" +#include "osif_sync.h" +#include "qca_vendor.h" +#include "wlan_osif_request_manager.h" + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_apf_offload() + */ +#define APF_INVALID \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_INVALID +#define APF_SUBCMD \ + QCA_WLAN_VENDOR_ATTR_SET_RESET_PACKET_FILTER +#define APF_VERSION \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION +#define APF_FILTER_ID \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_ID +#define APF_PACKET_SIZE \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_SIZE +#define APF_CURRENT_OFFSET \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_CURRENT_OFFSET +#define APF_PROGRAM \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROGRAM +#define APF_PROG_LEN \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_PROG_LENGTH +#define APF_MAX \ + QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX + +const struct nla_policy wlan_hdd_apf_offload_policy[APF_MAX + 1] = { + [APF_SUBCMD] = {.type = NLA_U32}, + [APF_VERSION] = {.type = NLA_U32}, + [APF_FILTER_ID] = {.type = NLA_U32}, + [APF_PACKET_SIZE] = {.type = NLA_U32}, + [APF_CURRENT_OFFSET] = {.type = NLA_U32}, + [APF_PROGRAM] = {.type = NLA_BINARY, + .len = MAX_APF_MEMORY_LEN}, + [APF_PROG_LEN] = {.type = NLA_U32}, +}; + +void hdd_apf_context_init(struct hdd_adapter *adapter) +{ + qdf_event_create(&adapter->apf_context.qdf_apf_event); + qdf_spinlock_create(&adapter->apf_context.lock); + adapter->apf_context.apf_enabled = true; +} + +void hdd_apf_context_destroy(struct hdd_adapter *adapter) +{ + qdf_event_destroy(&adapter->apf_context.qdf_apf_event); + qdf_spinlock_destroy(&adapter->apf_context.lock); + qdf_mem_zero(&adapter->apf_context, + sizeof(struct hdd_apf_context)); +} + +struct apf_offload_priv { + struct sir_apf_get_offload apf_get_offload; +}; + +void hdd_get_apf_capabilities_cb(void *context, + struct sir_apf_get_offload *data) +{ + struct osif_request *request; + struct apf_offload_priv *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->apf_get_offload = *data; + osif_request_complete(request); + osif_request_put(request); + + hdd_exit(); +} + +/** + * hdd_post_get_apf_capabilities_rsp() - Callback function to APF Offload + * @hdd_ctx: hdd_context + * @apf_get_offload: struct for get offload + * + * Return: 0 on success, error number otherwise. + */ +static int +hdd_post_get_apf_capabilities_rsp(struct hdd_context *hdd_ctx, + struct sir_apf_get_offload *apf_get_offload) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + + hdd_enter(); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += + (sizeof(apf_get_offload->max_bytes_for_apf_inst) + NLA_HDRLEN) + + (sizeof(apf_get_offload->apf_version) + NLA_HDRLEN); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_ctx->apf_version = apf_get_offload->apf_version; + hdd_debug("APF Version: %u APF max bytes: %u", + apf_get_offload->apf_version, + apf_get_offload->max_bytes_for_apf_inst); + + if (nla_put_u32(skb, APF_PACKET_SIZE, + apf_get_offload->max_bytes_for_apf_inst) || + nla_put_u32(skb, APF_VERSION, apf_get_offload->apf_version)) { + hdd_err("nla put failure"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + hdd_exit(); + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * hdd_get_apf_capabilities - Get APF offload Capabilities + * @hdd_ctx: Hdd context + * + * Return: 0 on success, errno on failure + */ +static int hdd_get_apf_capabilities(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct apf_offload_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_APF, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Unable to allocate request"); + return -EINVAL; + } + cookie = osif_request_cookie(request); + + status = sme_get_apf_capabilities(hdd_ctx->mac_handle, + hdd_get_apf_capabilities_cb, + cookie); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to retrieve APF caps"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out"); + goto cleanup; + } + priv = osif_request_priv(request); + ret = hdd_post_get_apf_capabilities_rsp(hdd_ctx, + &priv->apf_get_offload); + if (ret) + hdd_err("Failed to post get apf capabilities"); + +cleanup: + /* + * either we never sent a request to SME, we sent a request to + * SME and timed out, or we sent a request to SME, received a + * response from SME, and posted the response to userspace. + * regardless we are done with the request. + */ + osif_request_put(request); + hdd_exit(); + + return ret; +} + +/** + * hdd_set_reset_apf_offload - Post set/reset apf to SME + * @hdd_ctx: Hdd context + * @tb: Length of @data + * @adapter: pointer to adapter struct + * + * Return: 0 on success; errno on failure + */ +static int hdd_set_reset_apf_offload(struct hdd_context *hdd_ctx, + struct nlattr **tb, + struct hdd_adapter *adapter) +{ + struct sir_apf_set_offload apf_set_offload = {0}; + QDF_STATUS status; + int prog_len; + int ret = 0; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + /* Parse and fetch apf packet size */ + if (!tb[APF_PACKET_SIZE]) { + hdd_err("attr apf packet size failed"); + ret = -EINVAL; + goto fail; + } + + apf_set_offload.session_id = adapter->deflink->vdev_id; + apf_set_offload.total_length = nla_get_u32(tb[APF_PACKET_SIZE]); + + if (!apf_set_offload.total_length) { + hdd_debug("APF reset packet"); + goto post_sme; + } + + /* Parse and fetch apf program */ + if (!tb[APF_PROGRAM]) { + hdd_err("attr apf program failed"); + ret = -EINVAL; + goto fail; + } + + prog_len = nla_len(tb[APF_PROGRAM]); + apf_set_offload.program = qdf_mem_malloc(sizeof(uint8_t) * prog_len); + + if (!apf_set_offload.program) { + ret = -ENOMEM; + goto fail; + } + + apf_set_offload.current_length = prog_len; + nla_memcpy(apf_set_offload.program, tb[APF_PROGRAM], prog_len); + + /* Parse and fetch filter Id */ + if (!tb[APF_FILTER_ID]) { + hdd_err("attr filter id failed"); + ret = -EINVAL; + goto fail; + } + apf_set_offload.filter_id = nla_get_u32(tb[APF_FILTER_ID]); + + /* Parse and fetch current offset */ + if (!tb[APF_CURRENT_OFFSET]) { + hdd_err("attr current offset failed"); + ret = -EINVAL; + goto fail; + } + apf_set_offload.current_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); + +post_sme: + hdd_debug("Posting, session_id: %d APF Version: %d filter ID: %d total_len: %d current_len: %d offset: %d", + apf_set_offload.session_id, apf_set_offload.version, + apf_set_offload.filter_id, apf_set_offload.total_length, + apf_set_offload.current_length, + apf_set_offload.current_offset); + + status = sme_set_apf_instructions(hdd_ctx->mac_handle, + &apf_set_offload); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_apf_instructions failed(err=%d)", status); + ret = -EINVAL; + goto fail; + } + hdd_exit(); + +fail: + if (apf_set_offload.current_length) + qdf_mem_free(apf_set_offload.program); + + if (!ret) + hdd_ctx->apf_enabled_v2 = true; + + return ret; +} + +/** + * hdd_enable_disable_apf - Enable or Disable the APF interpreter + * @adapter: HDD Adapter + * @apf_enable: true: Enable APF Int., false: disable APF Int. + * + * Return: 0 on success, errno on failure + */ +static int +hdd_enable_disable_apf(struct hdd_adapter *adapter, bool apf_enable) +{ + QDF_STATUS status; + + status = sme_set_apf_enable_disable(hdd_adapter_get_mac_handle(adapter), + adapter->deflink->vdev_id, + apf_enable); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to post sme apf enable/disable message (status-%d)", + status); + return -EINVAL; + } + + adapter->apf_context.apf_enabled = apf_enable; + + return 0; +} + +/** + * hdd_apf_write_memory - Write into the apf work memory + * @adapter: HDD Adapter + * @tb: list of attributes + * + * This function writes code/data into the APF work memory and + * provides program length that is passed on to the interpreter. + * + * Return: 0 on success, errno on failure + */ +static int +hdd_apf_write_memory(struct hdd_adapter *adapter, struct nlattr **tb) +{ + struct wmi_apf_write_memory_params write_mem_params = {0}; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int ret = 0; + + write_mem_params.vdev_id = adapter->deflink->vdev_id; + if (adapter->apf_context.apf_enabled) { + hdd_err("Cannot get/set when APF interpreter is enabled"); + return -EINVAL; + } + + /* Read program length */ + if (!tb[APF_PROG_LEN]) { + hdd_err("attr program length failed"); + return -EINVAL; + } + write_mem_params.program_len = nla_get_u32(tb[APF_PROG_LEN]); + + /* Read APF work memory offset */ + if (!tb[APF_CURRENT_OFFSET]) { + hdd_err("attr apf packet size failed"); + return -EINVAL; + } + write_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); + + /* Parse and fetch apf program */ + if (!tb[APF_PROGRAM]) { + hdd_err("attr apf program failed"); + return -EINVAL; + } + + write_mem_params.length = nla_len(tb[APF_PROGRAM]); + if (!write_mem_params.length) { + hdd_err("Program attr with empty data"); + return -EINVAL; + } + + write_mem_params.buf = qdf_mem_malloc(sizeof(uint8_t) + * write_mem_params.length); + if (!write_mem_params.buf) + return -EINVAL; + nla_memcpy(write_mem_params.buf, tb[APF_PROGRAM], + write_mem_params.length); + + write_mem_params.apf_version = hdd_ctx->apf_version; + + status = sme_apf_write_work_memory(hdd_adapter_get_mac_handle(adapter), + &write_mem_params); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to retrieve APF caps"); + ret = -EINVAL; + } + + hdd_debug("Writing successful into APF work memory from offset 0x%X:", + write_mem_params.addr_offset); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + write_mem_params.buf, write_mem_params.length); + + if (write_mem_params.buf) + qdf_mem_free(write_mem_params.buf); + + return ret; +} + +/** + * hdd_apf_read_memory_callback - HDD Callback for the APF read memory + * operation + * @hdd_context: Hdd context + * @evt: APF read memory event response parameters + * + * Return: 0 on success, errno on failure + */ +static void +hdd_apf_read_memory_callback(void *hdd_context, + struct wmi_apf_read_memory_resp_event_params *evt) +{ + struct hdd_context *hdd_ctx = hdd_context; + struct hdd_apf_context *context; + uint8_t *buf_ptr; + uint32_t pkt_offset; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx) || !evt) { + hdd_err("HDD context is invalid or event buf(%pK) is null", + evt); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, evt->vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return; + + context = &link_info->adapter->apf_context; + + if (context->magic != APF_CONTEXT_MAGIC) { + /* The caller presumably timed out, nothing to do */ + hdd_err("Caller timed out or corrupt magic, simply return"); + return; + } + + if (evt->offset < context->offset) { + hdd_err("Offset in read event(%d) smaller than offset in request(%d)!", + evt->offset, context->offset); + return; + } + + /* + * offset in the event is relative to the APF work memory. + * Calculate the packet offset, which gives us the relative + * location in the buffer to start copy into. + */ + pkt_offset = evt->offset - context->offset; + + if ((pkt_offset > context->buf_len) || + (context->buf_len - pkt_offset < evt->length)) { + hdd_err("Read chunk exceeding allocated space"); + return; + } + buf_ptr = context->buf + pkt_offset; + + qdf_mem_copy(buf_ptr, evt->data, evt->length); + + if (!evt->more_data) { + /* Release the caller after last event, clear magic */ + context->magic = 0; + qdf_event_set(&context->qdf_apf_event); + } + + hdd_exit(); +} + +/** + * hdd_apf_read_memory - Read part of the apf work memory + * @adapter: HDD Adapter + * @tb: list of attributes + * + * Return: 0 on success, errno on failure + */ +static int hdd_apf_read_memory(struct hdd_adapter *adapter, struct nlattr **tb) +{ + struct wmi_apf_read_memory_params read_mem_params = {0}; + struct hdd_apf_context *context = &adapter->apf_context; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + unsigned long nl_buf_len = NLMSG_HDRLEN; + int ret = 0; + struct sk_buff *skb = NULL; + uint8_t *bufptr; + mac_handle_t mac_handle; + + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (!mac_handle) { + hdd_debug("mac ctx NULL"); + return -EINVAL; + } + + if (context->apf_enabled) { + hdd_err("Cannot get/set while interpreter is enabled"); + return -EINVAL; + } + + read_mem_params.vdev_id = adapter->deflink->vdev_id; + + /* Read APF work memory offset */ + if (!tb[APF_CURRENT_OFFSET]) { + hdd_err("attr apf memory offset failed"); + return -EINVAL; + } + read_mem_params.addr_offset = nla_get_u32(tb[APF_CURRENT_OFFSET]); + if (read_mem_params.addr_offset > MAX_APF_MEMORY_LEN) { + hdd_err("attr apf memory offset should be less than %d", + MAX_APF_MEMORY_LEN); + return -EINVAL; + } + + /* Read length */ + if (!tb[APF_PACKET_SIZE]) { + hdd_err("attr apf packet size failed"); + return -EINVAL; + } + read_mem_params.length = nla_get_u32(tb[APF_PACKET_SIZE]); + if (!read_mem_params.length) { + hdd_err("apf read length cannot be zero!"); + return -EINVAL; + } + bufptr = qdf_mem_malloc(read_mem_params.length); + if (!bufptr) + return -ENOMEM; + + qdf_event_reset(&context->qdf_apf_event); + context->offset = read_mem_params.addr_offset; + + context->buf = bufptr; + context->buf_len = read_mem_params.length; + context->magic = APF_CONTEXT_MAGIC; + + status = sme_apf_read_work_memory(mac_handle, &read_mem_params, + hdd_apf_read_memory_callback); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to post sme APF read memory message (status-%d)", + status); + ret = -EINVAL; + goto fail; + } + + /* request was sent -- wait for the response */ + status = qdf_wait_for_event_completion(&context->qdf_apf_event, + WLAN_WAIT_TIME_APF_READ_MEM); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Target response timed out"); + context->magic = 0; + ret = -ETIMEDOUT; + goto fail; + } + + nl_buf_len += sizeof(uint32_t) + NLA_HDRLEN; + nl_buf_len += context->buf_len + NLA_HDRLEN; + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto fail; + } + + if (nla_put_u32(skb, APF_SUBCMD, QCA_WLAN_READ_PACKET_FILTER) || + nla_put(skb, APF_PROGRAM, read_mem_params.length, context->buf)) { + hdd_err("put fail"); + wlan_cfg80211_vendor_free_skb(skb); + ret = -EINVAL; + goto fail; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + + hdd_debug("Reading APF work memory from offset 0x%X:", + read_mem_params.addr_offset); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + context->buf, read_mem_params.length); +fail: + if (context->buf) { + qdf_mem_free(context->buf); + context->buf = NULL; + } + + return ret; +} + +/** + * __wlan_hdd_cfg80211_apf_offload() - Set/Reset to APF Offload + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[APF_MAX + 1]; + int ret_val = 0, apf_subcmd; + struct hdd_apf_context *context; + + hdd_enter_dev(dev); + + if (!adapter) { + hdd_err("Adapter is null"); + return -EINVAL; + } + + context = &adapter->apf_context; + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!ucfg_pmo_is_apf_enabled(hdd_ctx->psoc)) { + hdd_err("APF is not supported or disabled through INI"); + return -ENOTSUPP; + } + + if (!(adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + hdd_err("APF only supported in STA or P2P CLI modes!"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, APF_MAX, data, data_len, + wlan_hdd_apf_offload_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[APF_SUBCMD]) { + hdd_err("attr apf sub-command failed"); + return -EINVAL; + } + apf_subcmd = nla_get_u32(tb[APF_SUBCMD]); + + /* Do not allow simultaneous new APF commands on the same adapter */ + qdf_spin_lock(&context->lock); + if (context->cmd_in_progress) { + qdf_spin_unlock(&context->lock); + hdd_err("Another cmd in progress for same session!"); + return -EAGAIN; + } + context->cmd_in_progress = true; + qdf_spin_unlock(&context->lock); + + switch (apf_subcmd) { + /* Legacy APF sub-commands */ + case QCA_WLAN_SET_PACKET_FILTER: + ret_val = hdd_set_reset_apf_offload(hdd_ctx, tb, + adapter); + break; + case QCA_WLAN_GET_PACKET_FILTER: + ret_val = hdd_get_apf_capabilities(hdd_ctx); + break; + + /* APF 3.0 sub-commands */ + case QCA_WLAN_WRITE_PACKET_FILTER: + ret_val = hdd_apf_write_memory(adapter, tb); + break; + case QCA_WLAN_READ_PACKET_FILTER: + ret_val = hdd_apf_read_memory(adapter, tb); + break; + case QCA_WLAN_ENABLE_PACKET_FILTER: + ret_val = hdd_enable_disable_apf(adapter, true); + break; + case QCA_WLAN_DISABLE_PACKET_FILTER: + ret_val = hdd_enable_disable_apf(adapter, false); + break; + default: + hdd_err("Unknown APF Sub-command: %d", apf_subcmd); + ret_val = -ENOTSUPP; + } + + qdf_spin_lock(&context->lock); + context->cmd_in_progress = false; + qdf_spin_unlock(&context->lock); + + return ret_val; +} + +int +wlan_hdd_cfg80211_apf_offload(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_apf_offload(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c new file mode 100644 index 0000000000..590658cbb5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c @@ -0,0 +1,2959 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_assoc.c + * + * WLAN Host Device Driver implementation + * + */ + +#include "wlan_hdd_includes.h" +#include +#include "dot11f.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_trace.h" +#include +#include +#include +#include +#include "wlan_hdd_cfg80211.h" +#include "csr_inside_api.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_tdls.h" +#include "sme_api.h" +#include "wlan_hdd_hostapd.h" +#include +#include +#include "wlan_hdd_lpass.h" +#include +#include +#include "wlan_policy_mgr_api.h" +#include +#include "sme_power_save_api.h" +#include "wlan_hdd_napi.h" +#include +#include +#include +#include +#include +#include "ol_txrx.h" +#include +#include +#include +#include "wlan_pmo_ucfg_api.h" +#include "wlan_hdd_tsf.h" +#include "wlan_utility.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_ipa_ucfg_api.h" +#include "wlan_hdd_stats.h" +#include "wlan_hdd_scan.h" +#include "wlan_crypto_global_api.h" +#include "wlan_hdd_bcn_recv.h" +#include "wlan_mlme_twt_ucfg_api.h" + +#include +#include +#include "wlan_dlm_ucfg_api.h" +#include "wlan_hdd_sta_info.h" +#include "wlan_hdd_ftm_time_sync.h" +#include "wlan_cm_roam_api.h" + +#include +#include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_if_mgr_ucfg_api.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_cm_public_struct.h" +#include "osif_cm_util.h" +#include "wlan_hdd_cm_api.h" +#include "cm_utf.h" + +#include "wlan_hdd_bootup_marker.h" +#include "wlan_roam_debug.h" + +#include "wlan_hdd_twt.h" +#include "wlan_cm_roam_ucfg_api.h" +#include "wlan_hdd_son.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_cm_ucfg_api.h" + +/* These are needed to recognize WPA and RSN suite types */ +#define HDD_WPA_OUI_SIZE 4 +#define HDD_RSN_OUI_SIZE 4 +uint8_t ccp_wpa_oui00[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x00 }; +uint8_t ccp_wpa_oui01[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x01 }; +uint8_t ccp_wpa_oui02[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x02 }; +uint8_t ccp_wpa_oui03[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x03 }; +uint8_t ccp_wpa_oui04[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x04 }; +uint8_t ccp_wpa_oui05[HDD_WPA_OUI_SIZE] = { 0x00, 0x50, 0xf2, 0x05 }; + +#ifdef FEATURE_WLAN_ESE +/* CCKM */ +uint8_t ccp_wpa_oui06[HDD_WPA_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; +/* CCKM */ +uint8_t ccp_rsn_oui06[HDD_RSN_OUI_SIZE] = { 0x00, 0x40, 0x96, 0x00 }; +#endif /* FEATURE_WLAN_ESE */ + +/* group cipher */ +uint8_t ccp_rsn_oui00[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x00 }; + +/* WEP-40 or RSN */ +uint8_t ccp_rsn_oui01[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x01 }; + +/* TKIP or RSN-PSK */ +uint8_t ccp_rsn_oui02[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x02 }; + +/* Reserved */ +uint8_t ccp_rsn_oui03[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x03 }; + +/* AES-CCMP */ +uint8_t ccp_rsn_oui04[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x04 }; + +/* WEP-104 */ +uint8_t ccp_rsn_oui05[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; + +/* RSN-PSK-SHA256 */ +uint8_t ccp_rsn_oui07[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x06 }; + +/* RSN-8021X-SHA256 */ +uint8_t ccp_rsn_oui08[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x05 }; + +/* AES-GCMP-128 */ +uint8_t ccp_rsn_oui09[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x08 }; + +/* AES-GCMP-256 */ +uint8_t ccp_rsn_oui0a[HDD_RSN_OUI_SIZE] = { 0x00, 0x0F, 0xAC, 0x09 }; +#ifdef WLAN_FEATURE_FILS_SK +uint8_t ccp_rsn_oui_0e[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0E}; +uint8_t ccp_rsn_oui_0f[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0F}; +uint8_t ccp_rsn_oui_10[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x10}; +uint8_t ccp_rsn_oui_11[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x11}; +#endif +uint8_t ccp_rsn_oui_12[HDD_RSN_OUI_SIZE] = {0x50, 0x6F, 0x9A, 0x02}; +uint8_t ccp_rsn_oui_0b[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0B}; +uint8_t ccp_rsn_oui_0c[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0C}; +/* FT-SUITE-B AKM */ +uint8_t ccp_rsn_oui_0d[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x0D}; + +/* OWE https://tools.ietf.org/html/rfc8110 */ +uint8_t ccp_rsn_oui_18[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x12}; + +#ifdef WLAN_FEATURE_SAE +/* SAE AKM */ +uint8_t ccp_rsn_oui_80[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x08}; +/* FT SAE AKM */ +uint8_t ccp_rsn_oui_90[HDD_RSN_OUI_SIZE] = {0x00, 0x0F, 0xAC, 0x09}; +#endif +static const +u8 ccp_rsn_oui_13[HDD_RSN_OUI_SIZE] = {0x50, 0x6F, 0x9A, 0x01}; + +#ifdef FEATURE_WLAN_WAPI +#define HDD_WAPI_OUI_SIZE 4 +/* WPI-SMS4 */ +uint8_t ccp_wapi_oui01[HDD_WAPI_OUI_SIZE] = { 0x00, 0x14, 0x72, 0x01 }; +/* WAI-PSK */ +uint8_t ccp_wapi_oui02[HDD_WAPI_OUI_SIZE] = { 0x00, 0x14, 0x72, 0x02 }; +#endif /* FEATURE_WLAN_WAPI */ + +/* Offset where the EID-Len-IE, start. */ +#define ASSOC_RSP_IES_OFFSET 6 /* Capability(2) + AID(2) + Status Code(2) */ +#define ASSOC_REQ_IES_OFFSET 4 /* Capability(2) + LI(2) */ + +/* + * beacon_filter_table - table of IEs used for beacon filtering + */ +static const int beacon_filter_table[] = { + WLAN_ELEMID_DSPARMS, + WLAN_ELEMID_ERP, + WLAN_ELEMID_EDCAPARMS, + WLAN_ELEMID_QOS_CAPABILITY, + WLAN_ELEMID_HTINFO_ANA, + WLAN_ELEMID_OP_MODE_NOTIFY, + WLAN_ELEMID_VHTOP, + WLAN_ELEMID_QUIET_CHANNEL, + WLAN_ELEMID_TWT, +#ifdef WLAN_FEATURE_11AX_BSS_COLOR + /* + * EID: 221 vendor IE is being used temporarily by 11AX + * bss-color-change IE till it gets any fixed number. This + * vendor EID needs to be replaced with bss-color-change IE + * number. + */ + WLAN_ELEMID_VENDOR, +#endif +}; + +/* + * beacon_filter_extn_table - table of extn IEs used for beacon filtering + */ +static const int beacon_filter_extn_table[] = { + WLAN_EXTN_ELEMID_HEOP, + WLAN_EXTN_ELEMID_UORA, + WLAN_EXTN_ELEMID_MUEDCA, +#ifdef WLAN_FEATURE_11BE + WLAN_EXTN_ELEMID_EHTOP, +#endif +}; + +/* HE operation BIT positins */ +#if defined(WLAN_FEATURE_11AX) +#define HE_OPERATION_DFLT_PE_DURATION_POS 0 +#define HE_OPERATION_TWT_REQUIRED_POS 3 +#define HE_OPERATION_RTS_THRESHOLD_POS 4 +#define HE_OPERATION_VHT_OPER_POS 14 +#define HE_OPERATION_CO_LOCATED_BSS_POS 15 +#define HE_OPERATION_ER_SU_DISABLE_POS 16 +#define HE_OPERATION_OPER_INFO_6G_POS 17 +#define HE_OPERATION_RESERVED_POS 18 +#define HE_OPERATION_BSS_COLOR_POS 24 +#define HE_OPERATION_PARTIAL_BSS_COLOR_POS 30 +#define HE_OPERATION_BSS_COL_DISABLED_POS 31 +#endif + +/* EHT operation BIT positins */ +#if defined(WLAN_FEATURE_11BE) +#define EHT_OPER_BASIC_RX_NSS_MCS_0_TO_7_POS 0 +#define EHT_OPER_BASIC_TX_NSS_MCS_0_TO_7_POS 4 +#define EHT_OPER_BASIC_RX_NSS_MCS_8_AND_9_POS 8 +#define EHT_OPER_BASIC_TX_NSS_MCS_8_AND_9_POS 12 +#define EHT_OPER_BASIC_RX_NSS_MCS_10_AND_11_POS 16 +#define EHT_OPER_BASIC_TX_NSS_MCS_10_AND_11_POS 20 +#define EHT_OPER_BASIC_RX_NSS_MCS_12_AND_13_POS 24 +#define EHT_OPER_BASIC_TX_NSS_MCS_12_AND_13_POS 28 +#endif + +#if defined(WLAN_FEATURE_SAE) && \ + (defined(CFG80211_EXTERNAL_AUTH_SUPPORT) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) +#if defined (CFG80211_SAE_AUTH_TA_ADDR_SUPPORT) +/** + * wlan_hdd_sae_copy_ta_addr() - Send TA address to supplicant + * @params: pointer to external auth params + * @link_info: Link info pointer in HDD adapter + * + * This API is used to copy TA address info in supplicant structure. + * + * Return: None + */ +static inline +void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params, + struct wlan_hdd_link_info *link_info) +{ + struct qdf_mac_addr ta = QDF_MAC_ADDR_ZERO_INIT; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t *link_addr; + + status = ucfg_cm_get_sae_auth_ta(link_info->adapter->hdd_ctx->pdev, + link_info->vdev_id, + &ta); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_ether_addr_copy(params->tx_addr, ta.bytes); + else if (wlan_vdev_mlme_is_mlo_vdev(link_info->vdev)) { + link_addr = wlan_vdev_mlme_get_linkaddr(link_info->vdev); + qdf_ether_addr_copy(params->tx_addr, link_addr); + } + + hdd_debug("status:%d ta:" QDF_MAC_ADDR_FMT, status, + QDF_MAC_ADDR_REF(params->tx_addr)); + +} +#else +static inline +void wlan_hdd_sae_copy_ta_addr(struct cfg80211_external_auth_params *params, + struct wlan_hdd_link_info *link_info) +{ +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_EXTERNAL_AUTH_MLO_SUPPORT) +/** + * wlan_hdd_sae_update_mld_addr() - Send mld address to supplicant + * @params: pointer to external auth params + * @link_info: Link info pointer in HDD adapter + * + * This API is used to copy MLD address info in supplicant structure. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +wlan_hdd_sae_update_mld_addr(struct cfg80211_external_auth_params *params, + struct wlan_hdd_link_info *link_info) +{ + struct qdf_mac_addr mld_addr; + struct qdf_mac_addr *mld_roaming_addr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev; + + if (!link_info->vdev) + return QDF_STATUS_E_INVAL; + + vdev = link_info->vdev; + wlan_objmgr_vdev_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + + if (!ucfg_cm_is_sae_auth_addr_conversion_required(vdev)) + goto end; + + if (ucfg_cm_is_vdev_roaming(vdev)) { + /* + * while roaming, peer is not created yet till authentication + * So retrieving the MLD address which is cached from the + * scan entry. + */ + mld_roaming_addr = ucfg_cm_roaming_get_peer_mld_addr(vdev); + if (!mld_roaming_addr) { + status = QDF_STATUS_E_INVAL; + goto end; + } + mld_addr = *mld_roaming_addr; + } else { + status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr); + if (QDF_IS_STATUS_ERROR(status)) { + status = QDF_STATUS_E_INVAL; + goto end; + } + } + + qdf_mem_copy(params->mld_addr, mld_addr.bytes, QDF_MAC_ADDR_SIZE); + hdd_debug("Sending MLD:" QDF_MAC_ADDR_FMT" to userspace", + QDF_MAC_ADDR_REF(mld_addr.bytes)); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return status; +} +#else +static inline QDF_STATUS +wlan_hdd_sae_update_mld_addr(struct cfg80211_external_auth_params *params, + struct wlan_hdd_link_info *link_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_hdd_get_keymgmt_for_sae_akm() - Get the keymgmt OUI + * corresponding to the SAE AKM type + * @akm: AKM type + * + * This API is used to get the keymgmt OUI for the SAE AKM type. + * Return: keymgmt OUI + */ +static uint32_t +wlan_hdd_get_keymgmt_for_sae_akm(uint32_t akm) +{ + if (akm == WLAN_AKM_SAE) + return WLAN_AKM_SUITE_SAE; + else if (akm == WLAN_AKM_FT_SAE) + return WLAN_AKM_SUITE_FT_OVER_SAE; + else if (akm == WLAN_AKM_SAE_EXT_KEY) + return WLAN_AKM_SUITE_SAE_EXT_KEY; + else if (akm == WLAN_AKM_FT_SAE_EXT_KEY) + return WLAN_AKM_SUITE_FT_SAE_EXT_KEY; + /** + * Legacy FW doesn't support SAE-EXK-KEY or + * Cross-SAE_AKM roaming. In such cases, send + * SAE for both SAE and FT-SAE AKMs. The supplicant + * has backward compatibility to handle this case. + */ + else + return WLAN_AKM_SUITE_SAE; +} + +/** + * wlan_hdd_sae_callback() - Sends SAE info to supplicant + * @link_info: Link info pointer in HDD adapter + * @roam_info: pointer to roam info + * + * This API is used to send required SAE info to trigger SAE in supplicant. + * + * Return: None + */ +static void wlan_hdd_sae_callback(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + int flags; + struct sir_sae_info *sae_info = roam_info->sae_info; + struct cfg80211_external_auth_params params = {0}; + QDF_STATUS status; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!sae_info) { + hdd_err("SAE info in NULL"); + return; + } + + flags = cds_get_gfp_flags(); + + params.key_mgmt_suite = + wlan_hdd_get_keymgmt_for_sae_akm(sae_info->akm); + + params.action = NL80211_EXTERNAL_AUTH_START; + qdf_ether_addr_copy(params.bssid, sae_info->peer_mac_addr.bytes); + wlan_hdd_sae_copy_ta_addr(¶ms, link_info); + status = wlan_hdd_sae_update_mld_addr(¶ms, link_info); + if (QDF_IS_STATUS_ERROR(status)) + return; + + qdf_mem_copy(params.ssid.ssid, sae_info->ssid.ssId, + sae_info->ssid.length); + params.ssid.ssid_len = sae_info->ssid.length; + cfg80211_external_auth_request(adapter->dev, ¶ms, flags); + hdd_debug("SAE: sent cmd"); +} +#else +static inline void wlan_hdd_sae_callback(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info) +{ } +#endif + +/** + * hdd_start_powersave_timer_on_associated() - Start auto powersave timer + * after associated + * @link_info: Link info pointer in HDD adapter + * + * This function will start auto powersave timer for STA/P2P Client. + * + * Return: none + */ +static void +hdd_start_powersave_timer_on_associated(struct wlan_hdd_link_info *link_info) +{ + uint32_t timeout; + uint32_t auto_bmps_timer_val; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) + return; + + ucfg_mlme_get_auto_bmps_timer_value(hdd_ctx->psoc, + &auto_bmps_timer_val); + timeout = hdd_cm_is_vdev_roaming(link_info) ? + AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE : + (auto_bmps_timer_val * 1000); + sme_ps_enable_auto_ps_timer(hdd_ctx->mac_handle, + link_info->vdev_id, + timeout); +} + +void hdd_conn_set_authenticated(struct wlan_hdd_link_info *link_info, + uint8_t auth_state) +{ + struct hdd_station_ctx *sta_ctx; + struct wlan_objmgr_vdev *vdev; + char *auth_time; + uint32_t time_buffer_size; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + /* save the new connection state */ + hdd_debug("Authenticated state Changed from oldState:%d to State:%d", + sta_ctx->conn_info.is_authenticated, auth_state); + sta_ctx->conn_info.is_authenticated = auth_state; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_conn_info_set_peer_authenticate(vdev, auth_state); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + auth_time = sta_ctx->conn_info.auth_time; + time_buffer_size = sizeof(sta_ctx->conn_info.auth_time); + + if (auth_state) + qdf_get_time_of_the_day_in_hr_min_sec_usec(auth_time, + time_buffer_size); + else + qdf_mem_zero(auth_time, time_buffer_size); + if (auth_state && + (sta_ctx->conn_info.ptk_installed || + sta_ctx->conn_info.uc_encrypt_type == eCSR_ENCRYPT_TYPE_NONE)) + hdd_start_powersave_timer_on_associated(link_info); +} + +void hdd_conn_set_connection_state(struct hdd_adapter *adapter, + eConnectionState conn_state) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + /* save the new connection state */ + if (conn_state == hdd_sta_ctx->conn_info.conn_state) + return; + + hdd_nofl_debug("connection state changed %d --> %d for dev %s (vdev %d)", + hdd_sta_ctx->conn_info.conn_state, conn_state, + adapter->dev->name, adapter->deflink->vdev_id); + + hdd_sta_ctx->conn_info.conn_state = conn_state; +} + +enum band_info hdd_conn_get_connected_band(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + uint32_t sta_freq = 0; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (hdd_cm_is_vdev_associated(link_info)) + sta_freq = sta_ctx->conn_info.chan_freq; + + if (wlan_reg_is_24ghz_ch_freq(sta_freq)) + return BAND_2G; + else if (wlan_reg_is_5ghz_ch_freq(sta_freq) || + wlan_reg_is_6ghz_chan_freq(sta_freq)) + return BAND_5G; + else /* If station is not connected return as BAND_ALL */ + return BAND_ALL; +} + +/** + * hdd_conn_get_connected_cipher_algo() - get current connection cipher type + * @link_info: Link info pointer in HDD adapter. + * @sta_ctx: pointer to global HDD Station context + * @pConnectedCipherAlgo: pointer to connected cipher algo + * + * Return: false if any errors encountered, true otherwise + */ +static inline bool +hdd_conn_get_connected_cipher_algo(struct wlan_hdd_link_info *link_info, + struct hdd_station_ctx *sta_ctx, + eCsrEncryptionType *pConnectedCipherAlgo) +{ + bool connected; + + connected = hdd_cm_is_vdev_associated(link_info); + if (pConnectedCipherAlgo) + *pConnectedCipherAlgo = sta_ctx->conn_info.uc_encrypt_type; + + return connected; +} + +struct wlan_hdd_link_info * +hdd_get_sta_connection_in_progress(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_GET_STA_CONNECTION_IN_PROGRESS; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return NULL; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { + hdd_adapter_for_each_active_link_info(adapter, + link_info) { + if (!hdd_cm_is_connecting(link_info)) + continue; + + hdd_debug("vdev_id %d: Connection is in progress", + link_info->vdev_id); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return link_info; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + return NULL; +} + +void hdd_abort_ongoing_sta_connection(struct hdd_context *hdd_ctx) +{ + struct wlan_hdd_link_info *link_info; + + link_info = hdd_get_sta_connection_in_progress(hdd_ctx); + if (link_info && + !wlan_vdev_mlme_is_mlo_link_switch_in_progress(link_info->vdev)) + wlan_hdd_cm_issue_disconnect(link_info, + REASON_UNSPEC_FAILURE, false); +} + +void hdd_abort_ongoing_sta_sae_connection(struct hdd_context *hdd_ctx) +{ + struct wlan_hdd_link_info *link_info; + struct wlan_objmgr_vdev *vdev; + int32_t key_mgmt; + + link_info = hdd_get_sta_connection_in_progress(hdd_ctx); + if (!link_info || + wlan_vdev_mlme_is_mlo_link_switch_in_progress(link_info->vdev)) + return; + + vdev = hdd_objmgr_get_vdev_by_user(link_info->adapter->deflink, + WLAN_OSIF_ID); + if (!vdev) + return; + + key_mgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (key_mgmt < 0) { + hdd_debug_rl("Invalid key_mgmt: %d", key_mgmt); + return; + } + + if (QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || + QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY) || + QDF_HAS_PARAM(key_mgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + wlan_hdd_cm_issue_disconnect(link_info->adapter->deflink, + REASON_DISASSOC_NETWORK_LEAVING, + false); +} + +QDF_STATUS hdd_get_first_connected_sta_vdev_id(struct hdd_context *hdd_ctx, + uint32_t *vdev_id) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_ANY_STA_CONNECTED; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_INVAL; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_adapter_for_each_active_link_info(adapter, + link_info) { + if (!hdd_cm_is_vdev_connected(link_info)) + continue; + + *vdev_id = link_info->vdev_id; + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return QDF_STATUS_SUCCESS; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + return QDF_STATUS_E_FAILURE; +} + +bool hdd_is_any_sta_connected(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t vdev_id; + + status = hdd_get_first_connected_sta_vdev_id(hdd_ctx, &vdev_id); + return QDF_IS_STATUS_ERROR(status) ? false : true; +} + +/** + * hdd_remove_beacon_filter() - remove beacon filter + * @adapter: Pointer to the hdd adapter + * + * Return: 0 on success and errno on failure + */ +int hdd_remove_beacon_filter(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = sme_remove_beacon_filter(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_remove_beacon_filter() failed"); + return -EFAULT; + } + + return 0; +} + +int hdd_add_beacon_filter(struct hdd_adapter *adapter) +{ + int i; + uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST] = {0}; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + for (i = 0; i < ARRAY_SIZE(beacon_filter_table); i++) + qdf_set_bit(beacon_filter_table[i], + (unsigned long *)ie_map); + + for (i = 0; i < ARRAY_SIZE(beacon_filter_extn_table); i++) + qdf_set_bit(beacon_filter_extn_table[i] + WLAN_ELEMID_EXTN_ELEM, + (unsigned long *)ie_map); + + status = sme_add_beacon_filter(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, ie_map); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_add_beacon_filter() failed"); + return -EFAULT; + } + return 0; +} + +void hdd_copy_ht_caps(struct ieee80211_ht_cap *hdd_ht_cap, + tDot11fIEHTCaps *roam_ht_cap) + +{ + uint32_t i, temp_ht_cap; + + qdf_mem_zero(hdd_ht_cap, sizeof(struct ieee80211_ht_cap)); + + if (roam_ht_cap->advCodingCap) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LDPC_CODING; + if (roam_ht_cap->supportedChannelWidthSet) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + temp_ht_cap = roam_ht_cap->mimoPowerSave & + (IEEE80211_HT_CAP_SM_PS >> IEEE80211_HT_CAP_SM_PS_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->cap_info |= + temp_ht_cap << IEEE80211_HT_CAP_SM_PS_SHIFT; + if (roam_ht_cap->greenField) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_GRN_FLD; + if (roam_ht_cap->shortGI20MHz) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_20; + if (roam_ht_cap->shortGI40MHz) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_SGI_40; + if (roam_ht_cap->txSTBC) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_TX_STBC; + temp_ht_cap = roam_ht_cap->rxSTBC & (IEEE80211_HT_CAP_RX_STBC >> + IEEE80211_HT_CAP_RX_STBC_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->cap_info |= + temp_ht_cap << IEEE80211_HT_CAP_RX_STBC_SHIFT; + if (roam_ht_cap->delayedBA) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DELAY_BA; + if (roam_ht_cap->maximalAMSDUsize) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_MAX_AMSDU; + if (roam_ht_cap->dsssCckMode40MHz) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_DSSSCCK40; + if (roam_ht_cap->psmp) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_RESERVED; + if (roam_ht_cap->stbcControlFrame) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_40MHZ_INTOLERANT; + if (roam_ht_cap->lsigTXOPProtection) + hdd_ht_cap->cap_info |= IEEE80211_HT_CAP_LSIG_TXOP_PROT; + + /* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ + if (roam_ht_cap->maxRxAMPDUFactor) + hdd_ht_cap->ampdu_params_info |= + IEEE80211_HT_AMPDU_PARM_FACTOR; + temp_ht_cap = roam_ht_cap->mpduDensity & + (IEEE80211_HT_AMPDU_PARM_DENSITY >> + IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->ampdu_params_info |= + temp_ht_cap << IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT; + + /* 802.11n HT extended capabilities masks */ + if (roam_ht_cap->pco) + hdd_ht_cap->extended_ht_cap_info |= + IEEE80211_HT_EXT_CAP_PCO; + temp_ht_cap = roam_ht_cap->transitionTime & + (IEEE80211_HT_EXT_CAP_PCO_TIME >> + IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->extended_ht_cap_info |= + temp_ht_cap << IEEE80211_HT_EXT_CAP_PCO_TIME_SHIFT; + temp_ht_cap = roam_ht_cap->mcsFeedback & + (IEEE80211_HT_EXT_CAP_MCS_FB >> IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->extended_ht_cap_info |= + temp_ht_cap << IEEE80211_HT_EXT_CAP_MCS_FB_SHIFT; + + /* tx_bf_cap_info capabilities */ + if (roam_ht_cap->txBF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_BF; + if (roam_ht_cap->rxStaggeredSounding) + hdd_ht_cap->tx_BF_cap_info |= + TX_BF_CAP_INFO_RX_STAG_RED_SOUNDING; + if (roam_ht_cap->txStaggeredSounding) + hdd_ht_cap->tx_BF_cap_info |= + TX_BF_CAP_INFO_TX_STAG_RED_SOUNDING; + if (roam_ht_cap->rxZLF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_RX_ZFL; + if (roam_ht_cap->txZLF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_TX_ZFL; + if (roam_ht_cap->implicitTxBF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_IMP_TX_BF; + temp_ht_cap = roam_ht_cap->calibration & + (TX_BF_CAP_INFO_CALIBRATION >> TX_BF_CAP_INFO_CALIBRATION_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << TX_BF_CAP_INFO_CALIBRATION_SHIFT; + if (roam_ht_cap->explicitCSITxBF) + hdd_ht_cap->tx_BF_cap_info |= TX_BF_CAP_INFO_EXP_CSIT_BF; + if (roam_ht_cap->explicitUncompressedSteeringMatrix) + hdd_ht_cap->tx_BF_cap_info |= + TX_BF_CAP_INFO_EXP_UNCOMP_STEER_MAT; + temp_ht_cap = roam_ht_cap->explicitBFCSIFeedback & + (TX_BF_CAP_INFO_EXP_BF_CSI_FB >> + TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << TX_BF_CAP_INFO_EXP_BF_CSI_FB_SHIFT; + temp_ht_cap = + roam_ht_cap->explicitUncompressedSteeringMatrixFeedback & + (TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT >> + TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_EXP_UNCMP_STEER_MAT_SHIFT; + temp_ht_cap = + roam_ht_cap->explicitCompressedSteeringMatrixFeedback & + (TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB >> + TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_EXP_CMP_STEER_MAT_FB_SHIFT; + temp_ht_cap = roam_ht_cap->csiNumBFAntennae & + (TX_BF_CAP_INFO_CSI_NUM_BF_ANT >> + TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << TX_BF_CAP_INFO_CSI_NUM_BF_ANT_SHIFT; + temp_ht_cap = roam_ht_cap->uncompressedSteeringMatrixBFAntennae & + (TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT >> + TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_UNCOMP_STEER_MAT_BF_ANT_SHIFT; + temp_ht_cap = roam_ht_cap->compressedSteeringMatrixBFAntennae & + (TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT >> + TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT); + if (temp_ht_cap) + hdd_ht_cap->tx_BF_cap_info |= + temp_ht_cap << + TX_BF_CAP_INFO_COMP_STEER_MAT_BF_ANT_SHIFT; + + /* antenna selection */ + if (roam_ht_cap->antennaSelection) + hdd_ht_cap->antenna_selection_info |= ANTENNA_SEL_INFO; + if (roam_ht_cap->explicitCSIFeedbackTx) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_EXP_CSI_FB_TX; + if (roam_ht_cap->antennaIndicesFeedbackTx) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_ANT_ID_FB_TX; + if (roam_ht_cap->explicitCSIFeedback) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_EXP_CSI_FB; + if (roam_ht_cap->antennaIndicesFeedback) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_ANT_ID_FB; + if (roam_ht_cap->rxAS) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_RX_AS; + if (roam_ht_cap->txSoundingPPDUs) + hdd_ht_cap->antenna_selection_info |= + ANTENNA_SEL_INFO_TX_SOUNDING_PPDU; + + /* mcs data rate */ + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; ++i) + hdd_ht_cap->mcs.rx_mask[i] = + roam_ht_cap->supportedMCSSet[i]; + hdd_ht_cap->mcs.rx_highest = + ((short) (roam_ht_cap->supportedMCSSet[11]) << 8) | + ((short) (roam_ht_cap->supportedMCSSet[10])); + hdd_ht_cap->mcs.tx_params = + roam_ht_cap->supportedMCSSet[12]; +} + +#define VHT_CAP_MAX_MPDU_LENGTH_MASK 0x00000003 +#define VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT 2 +#define VHT_CAP_RXSTBC_MASK_SHIFT 8 +#define VHT_CAP_BEAMFORMEE_STS_SHIFT 13 +#define VHT_CAP_BEAMFORMEE_STS_MASK \ + (0x0000e000 >> VHT_CAP_BEAMFORMEE_STS_SHIFT) +#define VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 +#define VHT_CAP_SOUNDING_DIMENSIONS_MASK \ + (0x00070000 >> VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) +#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT 23 +#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK \ + (0x03800000 >> VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT) +#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT 26 + +void hdd_copy_vht_caps(struct ieee80211_vht_cap *hdd_vht_cap, + tDot11fIEVHTCaps *roam_vht_cap) +{ + uint32_t temp_vht_cap; + + qdf_mem_zero(hdd_vht_cap, sizeof(struct ieee80211_vht_cap)); + + temp_vht_cap = roam_vht_cap->maxMPDULen & VHT_CAP_MAX_MPDU_LENGTH_MASK; + hdd_vht_cap->vht_cap_info |= temp_vht_cap; + temp_vht_cap = roam_vht_cap->supportedChannelWidthSet & + (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK >> + VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT); + if (temp_vht_cap) { + if (roam_vht_cap->supportedChannelWidthSet & + (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ >> + VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT)) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + if (roam_vht_cap->supportedChannelWidthSet & + (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ >> + VHT_CAP_SUPP_CHAN_WIDTH_MASK_SHIFT)) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + } + if (roam_vht_cap->ldpcCodingCap) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_RXLDPC; + if (roam_vht_cap->shortGI80MHz) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_80; + if (roam_vht_cap->shortGI160and80plus80MHz) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_SHORT_GI_160; + if (roam_vht_cap->txSTBC) + hdd_vht_cap->vht_cap_info |= IEEE80211_VHT_CAP_TXSTBC; + temp_vht_cap = roam_vht_cap->rxSTBC & (IEEE80211_VHT_CAP_RXSTBC_MASK >> + VHT_CAP_RXSTBC_MASK_SHIFT); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << VHT_CAP_RXSTBC_MASK_SHIFT; + if (roam_vht_cap->suBeamFormerCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + if (roam_vht_cap->suBeamformeeCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + temp_vht_cap = roam_vht_cap->csnofBeamformerAntSup & + (VHT_CAP_BEAMFORMEE_STS_MASK); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << VHT_CAP_BEAMFORMEE_STS_SHIFT; + temp_vht_cap = roam_vht_cap->numSoundingDim & + (VHT_CAP_SOUNDING_DIMENSIONS_MASK); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << VHT_CAP_SOUNDING_DIMENSIONS_SHIFT; + if (roam_vht_cap->muBeamformerCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + if (roam_vht_cap->muBeamformeeCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + if (roam_vht_cap->vhtTXOPPS) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_VHT_TXOP_PS; + if (roam_vht_cap->htcVHTCap) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_HTC_VHT; + temp_vht_cap = roam_vht_cap->maxAMPDULenExp & + (VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= + temp_vht_cap << + VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK_SHIFT; + temp_vht_cap = roam_vht_cap->vhtLinkAdaptCap & + (IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB >> + VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT); + if (temp_vht_cap) + hdd_vht_cap->vht_cap_info |= temp_vht_cap << + VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB_SHIFT; + if (roam_vht_cap->rxAntPattern) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN; + if (roam_vht_cap->txAntPattern) + hdd_vht_cap->vht_cap_info |= + IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; + hdd_vht_cap->supp_mcs.rx_mcs_map = roam_vht_cap->rxMCSMap; + hdd_vht_cap->supp_mcs.rx_highest = + ((uint16_t)roam_vht_cap->rxHighSupDataRate); + hdd_vht_cap->supp_mcs.tx_mcs_map = roam_vht_cap->txMCSMap; + hdd_vht_cap->supp_mcs.tx_highest = + ((uint16_t)roam_vht_cap->txSupDataRate); +} + +/* ht param */ +#define HT_PARAM_CONTROLLED_ACCESS_ONLY 0x10 +#define HT_PARAM_SERVICE_INT_GRAN 0xe0 +#define HT_PARAM_SERVICE_INT_GRAN_SHIFT 5 + +/* operatinon mode */ +#define HT_OP_MODE_TX_BURST_LIMIT 0x0008 + +/* stbc_param */ +#define HT_STBC_PARAM_MCS 0x007f + +void hdd_copy_ht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEHTInfo *ht_ops) +{ + struct ieee80211_ht_operation *hdd_ht_ops = + &hdd_sta_ctx->conn_info.ht_operation; + uint32_t i, temp_ht_ops; + + qdf_mem_zero(hdd_ht_ops, sizeof(struct ieee80211_ht_operation)); + + hdd_ht_ops->primary_chan = ht_ops->primaryChannel; + + /* HT_PARAMS */ + temp_ht_ops = ht_ops->secondaryChannelOffset & + IEEE80211_HT_PARAM_CHA_SEC_OFFSET; + if (temp_ht_ops) + hdd_ht_ops->ht_param |= temp_ht_ops; + else + hdd_ht_ops->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (ht_ops->recommendedTxWidthSet) + hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY; + if (ht_ops->rifsMode) + hdd_ht_ops->ht_param |= IEEE80211_HT_PARAM_RIFS_MODE; + if (ht_ops->controlledAccessOnly) + hdd_ht_ops->ht_param |= HT_PARAM_CONTROLLED_ACCESS_ONLY; + temp_ht_ops = ht_ops->serviceIntervalGranularity & + (HT_PARAM_SERVICE_INT_GRAN >> HT_PARAM_SERVICE_INT_GRAN_SHIFT); + if (temp_ht_ops) + hdd_ht_ops->ht_param |= temp_ht_ops << + HT_PARAM_SERVICE_INT_GRAN_SHIFT; + + /* operation mode */ + temp_ht_ops = ht_ops->opMode & + IEEE80211_HT_OP_MODE_PROTECTION; + switch (temp_ht_ops) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_20MHZ; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED; + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONE: + default: + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_PROTECTION_NONE; + } + if (ht_ops->nonGFDevicesPresent) + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT; + if (ht_ops->transmitBurstLimit) + hdd_ht_ops->operation_mode |= + HT_OP_MODE_TX_BURST_LIMIT; + if (ht_ops->obssNonHTStaPresent) + hdd_ht_ops->operation_mode |= + IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; + + if (ht_ops->chan_center_freq_seg2) + hdd_ht_ops->operation_mode |= + (ht_ops->chan_center_freq_seg2 << IEEE80211_HT_OP_MODE_CCFS2_SHIFT); + /* stbc_param */ + temp_ht_ops = ht_ops->basicSTBCMCS & + HT_STBC_PARAM_MCS; + if (temp_ht_ops) + hdd_ht_ops->stbc_param |= temp_ht_ops; + if (ht_ops->dualCTSProtection) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT; + if (ht_ops->secondaryBeacon) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_STBC_BEACON; + if (ht_ops->lsigTXOPProtectionFullSupport) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT; + if (ht_ops->pcoActive) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_PCO_ACTIVE; + if (ht_ops->pcoPhase) + hdd_ht_ops->stbc_param |= + IEEE80211_HT_STBC_PARAM_PCO_PHASE; + + /* basic MCs set */ + for (i = 0; i < 16; ++i) + hdd_ht_ops->basic_set[i] = + ht_ops->basicMCSSet[i]; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) +static void hdd_copy_vht_center_freq(struct ieee80211_vht_operation *ieee_ops, + tDot11fIEVHTOperation *roam_ops) +{ + ieee_ops->center_freq_seg0_idx = roam_ops->chan_center_freq_seg0; + ieee_ops->center_freq_seg1_idx = roam_ops->chan_center_freq_seg1; +} +#else +static void hdd_copy_vht_center_freq(struct ieee80211_vht_operation *ieee_ops, + tDot11fIEVHTOperation *roam_ops) +{ + ieee_ops->center_freq_seg1_idx = roam_ops->chan_center_freq_seg0; + ieee_ops->center_freq_seg2_idx = roam_ops->chan_center_freq_seg1; +} +#endif /* KERNEL_VERSION(4, 12, 0) */ + +void hdd_copy_vht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEVHTOperation *vht_ops) +{ + struct ieee80211_vht_operation *hdd_vht_ops = + &hdd_sta_ctx->conn_info.vht_operation; + + qdf_mem_zero(hdd_vht_ops, sizeof(struct ieee80211_vht_operation)); + + hdd_vht_ops->chan_width = vht_ops->chanWidth; + hdd_copy_vht_center_freq(hdd_vht_ops, vht_ops); + hdd_vht_ops->basic_mcs_set = vht_ops->basicMCSSet; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) && \ + defined(WLAN_FEATURE_11BE) +void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEeht_op *eht_ops) +{ + struct ieee80211_eht_operation *hdd_eht_ops = + &hdd_sta_ctx->conn_info.eht_operation; + struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_param; + uint32_t filled = 0, len = 0; + + qdf_mem_zero(hdd_eht_ops, sizeof(struct ieee80211_eht_operation)); + + if (!eht_ops->eht_op_information_present) + return; + + /* Min length if op_info_present */ + len += 3; + + hdd_eht_ops->params |= IEEE80211_EHT_OPER_INFO_PRESENT; + + if (eht_ops->eht_default_pe_duration) + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION; + if (eht_ops->group_addr_bu_indication_limit) + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT; + if (eht_ops->group_addr_bu_indication_exponent) + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK; + + mcs_param.rx_tx_mcs7_max_nss = + eht_ops->basic_rx_max_nss_for_mcs_0_to_7 << + EHT_OPER_BASIC_RX_NSS_MCS_0_TO_7_POS; + mcs_param.rx_tx_mcs7_max_nss |= + eht_ops->basic_tx_max_nss_for_mcs_0_to_7 << + EHT_OPER_BASIC_TX_NSS_MCS_0_TO_7_POS; + mcs_param.rx_tx_mcs9_max_nss = + eht_ops->basic_rx_max_nss_for_mcs_8_and_9 << + EHT_OPER_BASIC_RX_NSS_MCS_8_AND_9_POS; + mcs_param.rx_tx_mcs9_max_nss |= + eht_ops->basic_tx_max_nss_for_mcs_8_and_9 << + EHT_OPER_BASIC_TX_NSS_MCS_8_AND_9_POS; + mcs_param.rx_tx_mcs11_max_nss = + eht_ops->basic_rx_max_nss_for_mcs_10_and_11 << + EHT_OPER_BASIC_RX_NSS_MCS_10_AND_11_POS; + mcs_param.rx_tx_mcs11_max_nss |= + eht_ops->basic_tx_max_nss_for_mcs_10_and_11 << + EHT_OPER_BASIC_TX_NSS_MCS_10_AND_11_POS; + mcs_param.rx_tx_mcs13_max_nss = + eht_ops->basic_rx_max_nss_for_mcs_12_and_13 << + EHT_OPER_BASIC_RX_NSS_MCS_12_AND_13_POS; + mcs_param.rx_tx_mcs13_max_nss |= + eht_ops->basic_tx_max_nss_for_mcs_12_and_13 << + EHT_OPER_BASIC_TX_NSS_MCS_12_AND_13_POS; + + hdd_eht_ops->basic_mcs_nss = mcs_param; + hdd_eht_ops->optional[filled++] = eht_ops->channel_width; + hdd_eht_ops->optional[filled++] = eht_ops->ccfs0; + hdd_eht_ops->optional[filled++] = eht_ops->ccfs1; + + if (eht_ops->disabled_sub_chan_bitmap_present) { + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT; + len += 2; + hdd_eht_ops->optional[filled++] = + eht_ops->disabled_sub_chan_bitmap[0][0]; + hdd_eht_ops->optional[filled++] = + eht_ops->disabled_sub_chan_bitmap[0][1]; + } + hdd_sta_ctx->conn_info.eht_oper_len = + sizeof(struct ieee80211_eht_operation) + len; +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) && \ + defined(WLAN_FEATURE_11BE) +void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEeht_op *eht_ops) +{ + struct ieee80211_eht_operation *hdd_eht_ops = + &hdd_sta_ctx->conn_info.eht_operation; + uint32_t mcs_param = 0, filled = 0, len = 0; + + qdf_mem_zero(hdd_eht_ops, sizeof(struct ieee80211_eht_operation)); + + if (!eht_ops->eht_op_information_present) + return; + + /* Min length if op_info_present */ + len += 3; + + hdd_eht_ops->params |= IEEE80211_EHT_OPER_INFO_PRESENT; + + if (eht_ops->eht_default_pe_duration) + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_EHT_DEF_PE_DURATION; + if (eht_ops->group_addr_bu_indication_limit) + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_LIMIT; + if (eht_ops->group_addr_bu_indication_exponent) + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_GROUP_ADDRESSED_BU_IND_EXP_MASK; + + mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_0_to_7 << + EHT_OPER_BASIC_RX_NSS_MCS_0_TO_7_POS; + mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_0_to_7 << + EHT_OPER_BASIC_TX_NSS_MCS_0_TO_7_POS; + mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_8_and_9 << + EHT_OPER_BASIC_RX_NSS_MCS_8_AND_9_POS; + mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_8_and_9 << + EHT_OPER_BASIC_TX_NSS_MCS_8_AND_9_POS; + mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_10_and_11 << + EHT_OPER_BASIC_RX_NSS_MCS_10_AND_11_POS; + mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_10_and_11 << + EHT_OPER_BASIC_TX_NSS_MCS_10_AND_11_POS; + mcs_param |= eht_ops->basic_rx_max_nss_for_mcs_12_and_13 << + EHT_OPER_BASIC_RX_NSS_MCS_12_AND_13_POS; + mcs_param |= eht_ops->basic_tx_max_nss_for_mcs_12_and_13 << + EHT_OPER_BASIC_TX_NSS_MCS_12_AND_13_POS; + + hdd_eht_ops->basic_mcs_nss = mcs_param; + hdd_eht_ops->optional[filled++] = eht_ops->channel_width; + hdd_eht_ops->optional[filled++] = eht_ops->ccfs0; + hdd_eht_ops->optional[filled++] = eht_ops->ccfs1; + + if (eht_ops->disabled_sub_chan_bitmap_present) { + hdd_eht_ops->params |= + IEEE80211_EHT_OPER_DISABLED_SUBCHANNEL_BITMAP_PRESENT; + len += 2; + hdd_eht_ops->optional[filled++] = + eht_ops->disabled_sub_chan_bitmap[0][0]; + hdd_eht_ops->optional[filled++] = + eht_ops->disabled_sub_chan_bitmap[0][1]; + } + hdd_sta_ctx->conn_info.eht_oper_len = + sizeof(struct ieee80211_eht_operation) + len; +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) && \ + defined(WLAN_FEATURE_11BE) +void hdd_copy_eht_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEeht_op *eht_ops) +{ + struct ieee80211_eht_operation *hdd_eht_ops = + &hdd_sta_ctx->conn_info.eht_operation; + uint32_t filled = 0, len = 0; + + qdf_mem_zero(hdd_eht_ops, sizeof(struct ieee80211_eht_operation)); + + if (!eht_ops->eht_op_information_present) + return; + + hdd_eht_ops->chan_width = eht_ops->channel_width; + hdd_eht_ops->ccfs = eht_ops->ccfs0; + hdd_eht_ops->present_bm = eht_ops->disabled_sub_chan_bitmap_present; + + if (eht_ops->disabled_sub_chan_bitmap_present) { + hdd_eht_ops->disable_subchannel_bitmap[filled++] = + eht_ops->disabled_sub_chan_bitmap[0][0]; + hdd_eht_ops->disable_subchannel_bitmap[filled++] = + eht_ops->disabled_sub_chan_bitmap[0][1]; + len += 2; + } + hdd_sta_ctx->conn_info.eht_oper_len = + sizeof(struct ieee80211_eht_operation) + len; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ + defined(WLAN_FEATURE_11AX) +void hdd_copy_he_operation(struct hdd_station_ctx *hdd_sta_ctx, + tDot11fIEhe_op *he_operation) +{ + struct ieee80211_he_operation *hdd_he_operation; + uint32_t he_oper_params = 0; + uint32_t len = 0, filled = 0; + uint8_t he_oper_6g_params = 0; + uint32_t he_oper_len; + + if (!he_operation->present) + return; + if (he_operation->vht_oper_present) + len += 3; + if (he_operation->co_located_bss) + len += 1; + if (he_operation->oper_info_6g_present) + len += 5; + + he_oper_len = sizeof(struct ieee80211_he_operation) + len; + + hdd_he_operation = qdf_mem_malloc(he_oper_len); + if (!hdd_he_operation) + return; + + /* Fill he_oper_params */ + he_oper_params |= he_operation->default_pe << + HE_OPERATION_DFLT_PE_DURATION_POS; + he_oper_params |= he_operation->twt_required << + HE_OPERATION_TWT_REQUIRED_POS; + he_oper_params |= he_operation->txop_rts_threshold << + HE_OPERATION_RTS_THRESHOLD_POS; + he_oper_params |= he_operation->vht_oper_present << + HE_OPERATION_VHT_OPER_POS; + he_oper_params |= he_operation->co_located_bss << + HE_OPERATION_CO_LOCATED_BSS_POS; + he_oper_params |= he_operation->er_su_disable << + HE_OPERATION_ER_SU_DISABLE_POS; + he_oper_params |= he_operation->oper_info_6g_present << + HE_OPERATION_OPER_INFO_6G_POS; + he_oper_params |= he_operation->reserved2 << + HE_OPERATION_RESERVED_POS; + he_oper_params |= he_operation->bss_color << + HE_OPERATION_BSS_COLOR_POS; + he_oper_params |= he_operation->partial_bss_col << + HE_OPERATION_PARTIAL_BSS_COLOR_POS; + he_oper_params |= he_operation->bss_col_disabled << + HE_OPERATION_BSS_COL_DISABLED_POS; + + hdd_he_operation->he_oper_params = he_oper_params; + + /* Fill he_mcs_nss set */ + qdf_mem_copy(&hdd_he_operation->he_mcs_nss_set, + he_operation->basic_mcs_nss, + sizeof(hdd_he_operation->he_mcs_nss_set)); + + /* Fill he_params_optional fields */ + + if (he_operation->vht_oper_present) { + hdd_he_operation->optional[filled++] = + he_operation->vht_oper.info.chan_width; + hdd_he_operation->optional[filled++] = + he_operation->vht_oper.info.center_freq_seg0; + hdd_he_operation->optional[filled++] = + he_operation->vht_oper.info.center_freq_seg1; + } + if (he_operation->co_located_bss) + hdd_he_operation->optional[filled++] = + he_operation->maxbssid_ind.info.data; + + if (he_operation->oper_info_6g_present) { + hdd_he_operation->optional[filled++] = + he_operation->oper_info_6g.info.primary_ch; + he_oper_6g_params |= + he_operation->oper_info_6g.info.ch_width << 0; + he_oper_6g_params |= + he_operation->oper_info_6g.info.dup_bcon << 2; + he_oper_6g_params |= + he_operation->oper_info_6g.info.reserved << 3; + + hdd_he_operation->optional[filled++] = he_oper_6g_params; + hdd_he_operation->optional[filled++] = + he_operation->oper_info_6g.info.center_freq_seg0; + hdd_he_operation->optional[filled++] = + he_operation->oper_info_6g.info.center_freq_seg1; + hdd_he_operation->optional[filled] = + he_operation->oper_info_6g.info.min_rate; + } + + if (hdd_sta_ctx->cache_conn_info.he_operation) { + qdf_mem_free(hdd_sta_ctx->cache_conn_info.he_operation); + hdd_sta_ctx->cache_conn_info.he_operation = NULL; + } + + hdd_sta_ctx->cache_conn_info.he_oper_len = he_oper_len; + + hdd_sta_ctx->cache_conn_info.he_operation = hdd_he_operation; +} +#endif + +bool hdd_is_roam_sync_in_progress(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ + return wlan_cm_is_roam_sync_in_progress(hdd_ctx->psoc, vdev_id); +} + +void hdd_conn_remove_connect_info(struct hdd_station_ctx *sta_ctx) +{ + /* Remove bssid and peer_macaddr */ + qdf_mem_zero(&sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_zero(&sta_ctx->conn_info.peer_macaddr[0], + QDF_MAC_ADDR_SIZE); + + /* Clear all security settings */ + sta_ctx->conn_info.auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + sta_ctx->conn_info.uc_encrypt_type = eCSR_ENCRYPT_TYPE_NONE; + + sta_ctx->conn_info.proxy_arp_service = 0; + + qdf_mem_zero(&sta_ctx->conn_info.ssid, sizeof(tCsrSSIDInfo)); + + /* + * Reset the ptk, gtk status flags to avoid using current connection + * status in further connections. + */ + sta_ctx->conn_info.gtk_installed = false; + sta_ctx->conn_info.ptk_installed = false; +} + +void hdd_clear_roam_profile_ie(struct hdd_adapter *adapter) +{ + hdd_enter(); + +#ifdef FEATURE_WLAN_WAPI + adapter->wapi_info.wapi_auth_mode = WAPI_AUTH_MODE_OPEN; + adapter->wapi_info.wapi_mode = false; +#endif + + hdd_exit(); +} + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +static inline void hdd_set_unpause_queue(void *soc, uint8_t vdev_id) +{ + cdp_fc_vdev_unpause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED, 0); +} +#else +static inline void hdd_set_unpause_queue(void *soc, uint8_t vdev_id) +{ +} +#endif + +#ifdef FEATURE_WDS +/** + * hdd_config_wds_repeater_mode() - configures vdev for wds repeater mode + * @link_info: Link info pointer in HDD adapter + * @peer_addr: peer mac address + * + * Configure dp vdev to detect and drop multicast echo packets and enable + * 4 address frame format in fw. + * + * Return: None + */ +static void hdd_config_wds_repeater_mode(struct wlan_hdd_link_info *link_info, + uint8_t *peer_addr) +{ + cdp_config_param_type vdev_param; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + vdev_param.cdp_vdev_param_mec = true; + if (cdp_txrx_set_vdev_param(soc, link_info->vdev_id, + CDP_ENABLE_MEC, vdev_param)) + hdd_debug("Failed to set MEC param on DP vdev"); + + hdd_nofl_info("Turn on 4 address for peer: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + if (sme_set_peer_param(peer_addr, WMI_HOST_PEER_USE_4ADDR, true, + link_info->vdev_id)) + hdd_err("Failed to enable WDS on vdev"); +} +#else +static inline void +hdd_config_wds_repeater_mode(struct wlan_hdd_link_info *link_info, + uint8_t *peer_addr) +{ +} +#endif + +QDF_STATUS hdd_change_peer_state(struct wlan_hdd_link_info *link_info, + uint8_t *peer_mac, + enum ol_txrx_peer_state sta_state) +{ + QDF_STATUS err; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + err = cdp_peer_state_update(soc, peer_mac, sta_state); + if (err != QDF_STATUS_SUCCESS) { + hdd_err("peer state update failed"); + return QDF_STATUS_E_FAULT; + } + + if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id)) { + if (adapter->device_mode == QDF_STA_MODE && + (wlan_mlme_get_wds_mode(hdd_ctx->psoc) == + WLAN_WDS_MODE_REPEATER)) + hdd_config_wds_repeater_mode(link_info, peer_mac); + + hdd_son_deliver_peer_authorize_event(link_info, peer_mac); + return QDF_STATUS_SUCCESS; + } + + if (sta_state == OL_TXRX_PEER_STATE_AUTH) { + /* Reset scan reject params on successful set key */ + hdd_debug("Reset scan reject params"); + hdd_init_scan_reject_params(hdd_ctx); + + err = sme_set_peer_authorized(peer_mac, link_info->vdev_id); + if (err != QDF_STATUS_SUCCESS) { + hdd_err("Failed to set the peer state to authorized"); + return QDF_STATUS_E_FAULT; + } + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_set_unpause_queue(soc, link_info->vdev_id); + } + + if (adapter->device_mode == QDF_STA_MODE && + (wlan_mlme_get_wds_mode(hdd_ctx->psoc) == + WLAN_WDS_MODE_REPEATER)) + hdd_config_wds_repeater_mode(link_info, peer_mac); + + hdd_son_deliver_peer_authorize_event(link_info, peer_mac); + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_update_dp_vdev_flags(void *cbk_data, + uint8_t vdev_id, + uint32_t vdev_param, + bool is_link_up) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_psoc **psoc; + cdp_config_param_type val; + + if (!cbk_data) + return status; + + psoc = cbk_data; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return QDF_STATUS_E_INVAL; + + if (!hdd_ctx->tdls_nap_active) + return status; + + if (vdev_id == WLAN_INVALID_VDEV_ID) { + status = QDF_STATUS_E_FAILURE; + return status; + } + + val.cdp_vdev_param_tdls_flags = is_link_up; + cdp_txrx_set_vdev_param(soc, vdev_id, vdev_param, val); + + return status; +} + +QDF_STATUS hdd_roam_register_sta(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *bssid, + bool is_auth_required) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type txrx_desc = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + enum phy_ch_width ch_width; + enum wlan_phymode phymode; + struct wlan_objmgr_vdev *vdev; + struct hdd_adapter *adapter = link_info->adapter; + + /* Get the Station ID from the one saved during the association */ + if (!QDF_IS_ADDR_BROADCAST(bssid->bytes)) + WLAN_ADDR_COPY(txrx_desc.peer_addr.bytes, + bssid->bytes); + else + WLAN_ADDR_COPY(txrx_desc.peer_addr.bytes, + adapter->mac_addr.bytes); + + /* set the QoS field appropriately */ + if (hdd_wmm_is_active(adapter)) + txrx_desc.is_qos_enabled = 1; + else + txrx_desc.is_qos_enabled = 0; + +#ifdef FEATURE_WLAN_WAPI + hdd_debug("WAPI STA Registered: %d", + adapter->wapi_info.is_wapi_sta); + if (adapter->wapi_info.is_wapi_sta) + txrx_desc.is_wapi_supported = 1; + else + txrx_desc.is_wapi_supported = 0; +#endif /* FEATURE_WLAN_WAPI */ + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + qdf_status = ucfg_dp_sta_register_txrx_ops(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("DP tx/rx ops register failed Status: %d", qdf_status); + return qdf_status; + } + + if (adapter->device_mode == QDF_NDI_MODE) { + phymode = ucfg_mlme_get_vdev_phy_mode( + adapter->hdd_ctx->psoc, + link_info->vdev_id); + ch_width = ucfg_mlme_get_ch_width_from_phymode(phymode); + } else { + ch_width = ucfg_mlme_get_peer_ch_width(adapter->hdd_ctx->psoc, + txrx_desc.peer_addr.bytes); + } + txrx_desc.bw = hdd_convert_ch_width_to_cdp_peer_bw(ch_width); + qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &txrx_desc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("cdp_peer_register() failed Status: %d [0x%08X]", + qdf_status, qdf_status); + return qdf_status; + } + + hdd_cm_set_peer_authenticate(link_info, &txrx_desc.peer_addr, + is_auth_required); + + return qdf_status; +} + +/** + * hdd_change_sta_state_authenticated()- + * This function changes STA state to authenticated + * @link_info: Link info pointer in HDD adapter + * @roaminfo: pointer to the RoamInfo structure. + * + * This is called from hdd_RoamSetKeyCompleteHandler + * in context to eCSR_ROAM_SET_KEY_COMPLETE event from fw. + * + * Return: 0 on success and errno on failure + */ +static int +hdd_change_sta_state_authenticated(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roaminfo) +{ + uint8_t *mac_addr; + struct hdd_station_ctx *sta_ctx; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + bool alt_pipe; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + mac_addr = sta_ctx->conn_info.bssid.bytes; + + if (ucfg_ipa_is_enabled() && !sta_ctx->conn_info.is_authenticated && + adapter->device_mode == QDF_STA_MODE && + sta_ctx->conn_info.auth_type != eCSR_AUTH_TYPE_NONE && + sta_ctx->conn_info.auth_type != eCSR_AUTH_TYPE_OPEN_SYSTEM && + sta_ctx->conn_info.auth_type != eCSR_AUTH_TYPE_SHARED_KEY) { + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = hdd_ipa_get_tx_pipe(hdd_ctx, link_info, &alt_pipe); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("Failed to get alternate pipe for vdev %d", + link_info->vdev_id); + alt_pipe = false; + } + + ucfg_ipa_wlan_evt(adapter->hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + link_info->vdev_id, + WLAN_IPA_STA_CONNECT, mac_addr, + alt_pipe); + } + + hdd_cm_set_peer_authenticate(link_info, + &sta_ctx->conn_info.bssid, false); + + return 0; +} + +/** + * hdd_change_peer_state_after_set_key() - change the peer state on set key + * complete + * @link_info: Link info pointer in HDD adapter + * @roaminfo: pointer to roam info + * @roam_result: roam result + * + * Peer state will be OL_TXRX_PEER_STATE_CONN until set key is complete. + * This function checks for the successful set key completion and update + * the peer state to OL_TXRX_PEER_STATE_AUTH. + * + * Return: None + */ +static void +hdd_change_peer_state_after_set_key(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roaminfo, + eCsrRoamResult roam_result) +{ + struct hdd_station_ctx *hdd_sta_ctx; + eCsrEncryptionType encr_type; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + encr_type = hdd_sta_ctx->conn_info.uc_encrypt_type; + + if (eCSR_ROAM_RESULT_AUTHENTICATED == roam_result) { + hdd_sta_ctx->conn_info.gtk_installed = true; + /* + * PTK exchange happens in preauthentication itself if key_mgmt + * is FT-PSK, ptk_installed was false as there is no set PTK + * after roaming. STA TL state moves to authenticated only if + * ptk_installed is true. So, make ptk_installed to true in + * case of 11R roaming. + */ + if (sme_neighbor_roam_is11r_assoc(adapter->hdd_ctx->mac_handle, + link_info->vdev_id)) + hdd_sta_ctx->conn_info.ptk_installed = true; + } else { + hdd_sta_ctx->conn_info.ptk_installed = true; + } + + /* In WPA case move STA to authenticated when ptk is installed. Earlier + * in WEP case STA was moved to AUTHENTICATED prior to setting the + * unicast key and it was resulting in sending few un-encrypted packet. + * Now in WEP case STA state will be moved to AUTHENTICATED after we + * set the unicast and broadcast key. + */ + if ((encr_type == eCSR_ENCRYPT_TYPE_WEP40) || + (encr_type == eCSR_ENCRYPT_TYPE_WEP104) || + (encr_type == eCSR_ENCRYPT_TYPE_WEP40_STATICKEY) || + (encr_type == eCSR_ENCRYPT_TYPE_WEP104_STATICKEY)) { + if (hdd_sta_ctx->conn_info.gtk_installed && + hdd_sta_ctx->conn_info.ptk_installed) + hdd_change_sta_state_authenticated(link_info, roaminfo); + } else if (hdd_sta_ctx->conn_info.ptk_installed) { + hdd_change_sta_state_authenticated(link_info, roaminfo); + } + + if (hdd_sta_ctx->conn_info.gtk_installed && + hdd_sta_ctx->conn_info.ptk_installed) { + hdd_sta_ctx->conn_info.gtk_installed = false; + hdd_sta_ctx->conn_info.ptk_installed = false; + } +} + +/** + * hdd_roam_set_key_complete_handler() - Update the security parameters + * @link_info: Link info pointer in HDD adapter + * @roam_info: pointer to roam info + * @roam_status: roam status + * @roam_result: roam result + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_roam_set_key_complete_handler(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + eCsrEncryptionType algorithm; + bool connected; + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + hdd_enter(); + + if (!roam_info) { + hdd_err("roam_info is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err("hdd_ctx or psoc is NULL"); + return QDF_STATUS_E_FAILURE; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + /* + * if (WPA), tell TL to go to 'authenticated' after the keys are set. + * then go to 'authenticated'. For all other authentication types + * (those that do not require upper layer authentication) we can put TL + * directly into 'authenticated' state. + */ + hdd_debug("Set Key completion roam_status =%d roam_result=%d " + QDF_MAC_ADDR_FMT, roam_status, roam_result, + QDF_MAC_ADDR_REF(roam_info->peerMac.bytes)); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + connected = hdd_conn_get_connected_cipher_algo(link_info, sta_ctx, + &algorithm); + if (connected) { + hdd_change_peer_state_after_set_key(link_info, + roam_info, roam_result); + } + + policy_mgr_restart_opportunistic_timer(hdd_ctx->psoc, false); + + hdd_exit(); + return QDF_STATUS_SUCCESS; +} + +bool hdd_save_peer(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *peer_mac_addr) +{ + int idx; + struct qdf_mac_addr *mac_addr; + + for (idx = 0; idx < MAX_PEERS; idx++) { + mac_addr = &sta_ctx->conn_info.peer_macaddr[idx]; + if (qdf_is_macaddr_zero(mac_addr)) { + hdd_debug("adding peer: "QDF_MAC_ADDR_FMT" at idx: %d", + QDF_MAC_ADDR_REF(peer_mac_addr->bytes), idx); + qdf_copy_macaddr(mac_addr, peer_mac_addr); + return true; + } + } + + return false; +} + +void hdd_delete_peer(struct hdd_station_ctx *sta_ctx, + struct qdf_mac_addr *peer_mac_addr) +{ + int i; + struct qdf_mac_addr *mac_addr; + + for (i = 0; i < MAX_PEERS; i++) { + mac_addr = &sta_ctx->conn_info.peer_macaddr[i]; + if (qdf_is_macaddr_equal(mac_addr, peer_mac_addr)) { + qdf_zero_macaddr(mac_addr); + return; + } + } +} + +bool hdd_any_valid_peer_present(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + int i; + struct qdf_mac_addr *mac_addr; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + for (i = 0; i < MAX_PEERS; i++) { + mac_addr = &sta_ctx->conn_info.peer_macaddr[i]; + if (!qdf_is_macaddr_zero(mac_addr) && + !qdf_is_macaddr_broadcast(mac_addr)) { + hdd_debug("peer: index: %u " QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return true; + } + } + + return false; +} + +/** + * hdd_roam_mic_error_indication_handler() - MIC error indication handler + * @link_info: Link info pointer in HDD adapter + * @roam_info: pointer to roam info + * + * This function indicates the Mic failure to the supplicant + * + * Return: None + */ +static void +hdd_roam_mic_error_indication_handler(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + tSirMicFailureInfo *mic_failure_info; + + if (!hdd_cm_is_vdev_associated(link_info)) + return; + + mic_failure_info = roam_info->u.pMICFailureInfo; + cfg80211_michael_mic_failure(adapter->dev, + mic_failure_info->taMacAddr, + mic_failure_info->multicast ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE, + mic_failure_info->keyId, + mic_failure_info->TSC, + GFP_KERNEL); +} + +#ifdef FEATURE_WLAN_TDLS +QDF_STATUS hdd_roam_register_tdlssta(struct hdd_adapter *adapter, + const uint8_t *peerMac, uint8_t qos) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type txrx_desc = { 0 }; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + enum phy_ch_width ch_width; + struct wlan_objmgr_vdev *vdev; + + /* + * TDLS sta in BSS should be set as STA type TDLS and STA MAC should + * be peer MAC, here we are working on direct Link + */ + WLAN_ADDR_COPY(txrx_desc.peer_addr.bytes, peerMac); + + /* set the QoS field appropriately .. */ + txrx_desc.is_qos_enabled = qos; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + qdf_status = ucfg_dp_tdlsta_register_txrx_ops(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("DP tx/rx ops register failed Status: %d", qdf_status); + return qdf_status; + } + + ch_width = ucfg_mlme_get_peer_ch_width(adapter->hdd_ctx->psoc, + txrx_desc.peer_addr.bytes); + txrx_desc.bw = hdd_convert_ch_width_to_cdp_peer_bw(ch_width); + /* Register the Station with TL... */ + qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &txrx_desc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("cdp_peer_register() failed Status: %d [0x%08X]", + qdf_status, qdf_status); + return qdf_status; + } + + return qdf_status; +} + +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + +static void hdd_rx_unprot_disassoc(struct net_device *dev, + const u8 *buf, size_t len) +{ + cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); +} + +static void hdd_rx_unprot_deauth(struct net_device *dev, + const u8 *buf, size_t len) +{ + cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); +} + +#else + +static void hdd_rx_unprot_disassoc(struct net_device *dev, + const u8 *buf, size_t len) +{ + cfg80211_send_unprot_disassoc(dev, buf, len); +} + +static void hdd_rx_unprot_deauth(struct net_device *dev, + const u8 *buf, size_t len) +{ + cfg80211_send_unprot_deauth(dev, buf, len); +} + +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) */ + +/** + * hdd_indicate_unprot_mgmt_frame() - indicate unprotected management frame + * @link_info: Link info pointer in HDD adapter + * @frame_length: Length of the unprotected frame being passed + * @frame: Pointer to the frame buffer + * @frame_type: 802.11 frame type + * + * This function forwards the unprotected management frame to the supplicant. + * + * Return: nothing + */ +static void +hdd_indicate_unprot_mgmt_frame(struct wlan_hdd_link_info *link_info, + uint32_t frame_length, uint8_t *frame, + uint8_t frame_type) +{ + uint8_t type, subtype; + struct hdd_stats *hdd_stats; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_debug("Frame Type = %d Frame Length = %d", + frame_type, frame_length); + + if (hdd_validate_adapter(adapter)) + return; + + if (!frame_length) { + hdd_err("Frame Length is Invalid ZERO"); + return; + } + + if (!frame) { + hdd_err("frame is NULL"); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(frame[0]); + if (type != SIR_MAC_MGMT_FRAME) { + hdd_warn("Unexpected frame type %d", type); + return; + } + + hdd_stats = &link_info->hdd_stats; + subtype = WLAN_HDD_GET_SUBTYPE_FRM_FC(frame[0]); + switch (subtype) { + case SIR_MAC_MGMT_DISASSOC: + hdd_rx_unprot_disassoc(adapter->dev, frame, frame_length); + hdd_stats->hdd_pmf_stats.num_unprot_disassoc_rx++; + break; + case SIR_MAC_MGMT_DEAUTH: + hdd_rx_unprot_deauth(adapter->dev, frame, frame_length); + hdd_stats->hdd_pmf_stats.num_unprot_deauth_rx++; + break; + default: + hdd_warn("Unexpected frame subtype %d", subtype); + break; + } +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_indicate_tsm_ie() - send traffic stream metrics ie + * @adapter: pointer to adapter + * @tid: traffic identifier + * @state: state + * @measInterval: measurement interval + * + * This function sends traffic stream metrics IE information to + * the supplicant via wireless event. + * + * Return: none + */ +static void +hdd_indicate_tsm_ie(struct hdd_adapter *adapter, uint8_t tid, + uint8_t state, uint16_t measInterval) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + int nBytes = 0; + + if (!adapter) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hdd_debug("TSM Ind tid(%d) state(%d) MeasInt(%d)", + tid, state, measInterval); + + nBytes = + snprintf(buf, IW_CUSTOM_MAX, "TSMIE=%d:%d:%d", tid, state, + measInterval); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + /* send the event */ + hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_adj_ap_rep_ind() - send adjacent AP report indication + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * + * Return: none + */ +static void +hdd_indicate_ese_adj_ap_rep_ind(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + int nBytes = 0; + + if ((!adapter) || (!roam_info)) + return; + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hdd_debug("CCXADJAPREP=%u", roam_info->tsmRoamDelay); + + nBytes = + snprintf(buf, IW_CUSTOM_MAX, "CCXADJAPREP=%u", + roam_info->tsmRoamDelay); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + + /* send the event */ + hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_bcn_report_no_results() - beacon report no scan results + * @adapter: pointer to adapter + * @measurementToken: measurement token + * @flag: flag + * @numBss: number of bss + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +void +hdd_indicate_ese_bcn_report_no_results(const struct hdd_adapter *adapter, + const uint16_t measurementToken, + const bool flag, const uint8_t numBss) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + hdd_debug("CCXBCNREP=%d %d %d", measurementToken, + flag, numBss); + + nBytes = + snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d", measurementToken, + flag, numBss); + + wrqu.data.pointer = buf; + wrqu.data.length = nBytes; + /* send the event */ + hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * hdd_indicate_ese_bcn_report_ind() - send beacon report indication + * @adapter: pointer to adapter + * @roam_info: pointer to roam info + * + * If the measurement is none and no scan results found, + * indicate the supplicant about measurement done. + * + * Return: none + */ +static void +hdd_indicate_ese_bcn_report_ind(const struct hdd_adapter *adapter, + const struct csr_roam_info *roam_info) +{ + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX]; + char *pos = buf; + int nBytes = 0, freeBytes = IW_CUSTOM_MAX; + uint8_t i = 0, len = 0; + uint8_t tot_bcn_ieLen = 0; /* total size of the beacon report data */ + uint8_t lastSent = 0, sendBss = 0; + int bcnRepFieldSize = + sizeof(roam_info->pEseBcnReportRsp->bcnRepBssInfo[0]. + bcnReportFields); + uint8_t ieLenByte = 1; + /* + * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes + */ +#define ESEBCNREPHEADER_LEN (18) + + if ((!adapter) || (!roam_info)) + return; + + /* + * Custom event can pass maximum of 256 bytes of data, + * based on the IE len we need to identify how many BSS info can + * be filled in to custom event data. + */ + /* + * meas_tokflagno_of_bsstot_bcn_ie_len bcn_rep_data + * bcn_rep_data will have bcn_rep_fields,ie_len,ie without any spaces + * CCXBCNREP=meas_tokflagno_of_bsstot_bcn_ie_len = 18 bytes + */ + + if ((roam_info->pEseBcnReportRsp->flag >> 1) + && (!roam_info->pEseBcnReportRsp->numBss)) { + hdd_debug("Measurement Done but no scan results"); + /* If the measurement is none and no scan results found, + * indicate the supplicant about measurement done + */ + hdd_indicate_ese_bcn_report_no_results( + adapter, + roam_info->pEseBcnReportRsp-> + measurementToken, + roam_info->pEseBcnReportRsp->flag, + roam_info->pEseBcnReportRsp->numBss); + } else { + while (lastSent < roam_info->pEseBcnReportRsp->numBss) { + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + tot_bcn_ieLen = 0; + sendBss = 0; + pos = buf; + freeBytes = IW_CUSTOM_MAX; + + for (i = lastSent; + i < roam_info->pEseBcnReportRsp->numBss; i++) { + len = + bcnRepFieldSize + ieLenByte + + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i].ieLen; + if ((len + tot_bcn_ieLen) > + (IW_CUSTOM_MAX - ESEBCNREPHEADER_LEN)) { + break; + } + tot_bcn_ieLen += len; + sendBss++; + hdd_debug("i(%d) sizeof bcnReportFields(%d) IeLength(%d) Length of Ie(%d) totLen(%d)", + i, bcnRepFieldSize, 1, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i].ieLen, tot_bcn_ieLen); + } + + hdd_debug("Sending %d BSS Info", sendBss); + hdd_debug("CCXBCNREP=%d %d %d %d", + roam_info->pEseBcnReportRsp->measurementToken, + roam_info->pEseBcnReportRsp->flag, sendBss, + tot_bcn_ieLen); + + nBytes = snprintf(pos, freeBytes, "CCXBCNREP=%d %d %d ", + roam_info->pEseBcnReportRsp-> + measurementToken, + roam_info->pEseBcnReportRsp->flag, + sendBss); + pos += nBytes; + freeBytes -= nBytes; + + /* Copy total Beacon report data length */ + qdf_mem_copy(pos, (char *)&tot_bcn_ieLen, + sizeof(tot_bcn_ieLen)); + pos += sizeof(tot_bcn_ieLen); + freeBytes -= sizeof(tot_bcn_ieLen); + + for (i = 0; i < sendBss; i++) { + hdd_debug("ChanNum(%d) Spare(%d) MeasDuration(%d)" + " PhyType(%d) RecvSigPower(%d) ParentTSF(%u)" + " TargetTSF[0](%u) TargetTSF[1](%u) BeaconInterval(%u)" + " CapabilityInfo(%d) BSSID(%02X:%02X:%02X:%02X:%02X:%02X)", + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + ChanNum, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Spare, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + MeasDuration, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + PhyType, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + RecvSigPower, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + ParentTsf, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + TargetTsf[0], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + TargetTsf[1], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + BcnInterval, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + CapabilityInfo, + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[0], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[1], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[2], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[3], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[4], + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent].bcnReportFields. + Bssid[5]); + + /* bcn report fields are copied */ + len = + sizeof(roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + + lastSent]. + bcnReportFields); + qdf_mem_copy(pos, + (char *)&roam_info-> + pEseBcnReportRsp->bcnRepBssInfo[i + + lastSent]. + bcnReportFields, len); + pos += len; + freeBytes -= len; + + /* Add 1 byte of ie len */ + len = + roam_info->pEseBcnReportRsp-> + bcnRepBssInfo[i + lastSent].ieLen; + qdf_mem_copy(pos, (char *)&len, sizeof(len)); + pos += sizeof(len); + freeBytes -= sizeof(len); + + /* copy IE from scan results */ + qdf_mem_copy(pos, + (char *)roam_info-> + pEseBcnReportRsp->bcnRepBssInfo[i + + lastSent]. + pBuf, len); + pos += len; + freeBytes -= len; + } + + wrqu.data.pointer = buf; + wrqu.data.length = IW_CUSTOM_MAX - freeBytes; + + /* send the event */ + hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, + buf); + lastSent += sendBss; + } + } +} + +#endif /* FEATURE_WLAN_ESE */ + +/* + * hdd_roam_channel_switch_handler() - hdd channel switch handler + * @link_info: Link info pointer in HDD adapter + * @roam_info: Pointer to roam info + * + * Return: None + */ +static void +hdd_roam_channel_switch_handler(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info) +{ + struct hdd_chan_change_params chan_change = {0}; + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle_t mac_handle; + struct hdd_station_ctx *sta_ctx; + uint8_t connected_vdev; + bool notify = true, is_sap_go_moved_before_sta = false; + struct wlan_objmgr_vdev *vdev; + + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (!mac_handle) + return; + + /* Enable Roaming on STA interface which was disabled before CSA */ + if (adapter->device_mode == QDF_STA_MODE) + sme_start_roaming(mac_handle, link_info->vdev_id, + REASON_VDEV_RESTART_FROM_HOST, + RSO_CHANNEL_SWITCH); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (sta_ctx) { + sta_ctx->conn_info.chan_freq = roam_info->chan_info.mhz; + sta_ctx->conn_info.ch_width = roam_info->chan_info.ch_width; + } + + chan_change.chan_freq = roam_info->chan_info.mhz; + chan_change.chan_params.ch_width = + roam_info->chan_info.ch_width; + chan_change.chan_params.sec_ch_offset = + roam_info->chan_info.sec_ch_offset; + chan_change.chan_params.mhz_freq_seg0 = + roam_info->chan_info.band_center_freq1; + chan_change.chan_params.mhz_freq_seg1 = + roam_info->chan_info.band_center_freq2; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Invalid vdev"); + return; + } + + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + if (!wlan_get_connected_vdev_by_bssid( + hdd_ctx->pdev, sta_ctx->conn_info.bssid.bytes, + &connected_vdev)) + notify = false; + else if (link_info->vdev_id != connected_vdev || + !ucfg_cm_is_vdev_active(vdev)) + notify = false; + } + if (notify) { + qdf_sched_work(0, &link_info->chan_change_notify_work); + } else { + hdd_err("BSS "QDF_MAC_ADDR_FMT" no connected with vdev %d (%d)", + QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes), + link_info->vdev_id, connected_vdev); + } + status = policy_mgr_set_hw_mode_on_channel_switch(hdd_ctx->psoc, + link_info->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("set hw mode change not done"); + + is_sap_go_moved_before_sta = + wlan_vdev_mlme_is_sap_go_move_before_sta(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (!is_sap_go_moved_before_sta) + policy_mgr_check_concurrent_intf_and_restart_sap( + hdd_ctx->psoc, + !!link_info->session.ap.sap_config.acs_cfg.acs_mode); + + wlan_twt_concurrency_update(hdd_ctx); + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_ID); + if (!vdev) + return; + + status = ucfg_if_mgr_deliver_event( + vdev, WLAN_IF_MGR_EV_STA_CSA_COMPLETE, NULL); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("Failed to deliver CSA complete evt"); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + } +} + +#ifdef WLAN_FEATURE_HOST_ROAM +void wlan_hdd_ft_set_key_delay(struct wlan_objmgr_vdev *vdev) +{ + int errno = 0; + + if (ucfg_cm_ft_key_ready_for_install(vdev)) + errno = + wlan_cfg80211_crypto_add_key(vdev, + WLAN_CRYPTO_KEY_TYPE_UNICAST, + 0, false); + if (errno) + hdd_err("ft set key failed"); +} +#endif + +QDF_STATUS hdd_sme_roam_callback(void *context, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + struct wlan_hdd_link_info *link_info = context; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_station_ctx *sta_ctx = NULL; + struct hdd_context *hdd_ctx; + + hdd_debug("CSR Callback: status=%s (%d) result= %s (%d)", + get_e_roam_cmd_status_str(roam_status), roam_status, + get_e_csr_roam_result_str(roam_result), roam_result); + + /* Sanity check */ + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_FAILURE; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + MTRACE(qdf_trace(QDF_MODULE_ID_HDD, TRACE_CODE_HDD_RX_SME_MSG, + link_info->vdev_id, roam_status)); + + switch (roam_status) { + case eCSR_ROAM_MIC_ERROR_IND: + hdd_roam_mic_error_indication_handler(link_info, roam_info); + break; + + case eCSR_ROAM_SET_KEY_COMPLETE: + { + qdf_ret_status = + hdd_roam_set_key_complete_handler(link_info, roam_info, + roam_status, + roam_result); + if (eCSR_ROAM_RESULT_AUTHENTICATED == roam_result) + hdd_debug("set key complete, session: %d", + link_info->vdev_id); + } + break; + case eCSR_ROAM_UNPROT_MGMT_FRAME_IND: + if (roam_info) + hdd_indicate_unprot_mgmt_frame(link_info, + roam_info->nFrameLength, + roam_info->pbFrames, + roam_info->frameType); + break; +#ifdef FEATURE_WLAN_ESE + case eCSR_ROAM_TSM_IE_IND: + if (roam_info) + hdd_indicate_tsm_ie(adapter, + roam_info->tsm_ie.tsid, + roam_info->tsm_ie.state, + roam_info->tsm_ie.msmt_interval); + break; + case eCSR_ROAM_ESE_ADJ_AP_REPORT_IND: + { + hdd_indicate_ese_adj_ap_rep_ind(adapter, roam_info); + break; + } + + case eCSR_ROAM_ESE_BCN_REPORT_IND: + { + hdd_indicate_ese_bcn_report_ind(adapter, roam_info); + break; + } +#endif /* FEATURE_WLAN_ESE */ + case eCSR_ROAM_STA_CHANNEL_SWITCH: + hdd_roam_channel_switch_handler(link_info, roam_info); + break; + + case eCSR_ROAM_NDP_STATUS_UPDATE: + hdd_ndp_event_handler(link_info, roam_info, + roam_status, roam_result); + break; + case eCSR_ROAM_SAE_COMPUTE: + if (roam_info) + wlan_hdd_sae_callback(link_info, roam_info); + break; + default: + break; + } + return qdf_ret_status; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * hdd_translate_fils_rsn_to_csr_auth() - Translate FILS RSN to CSR auth type + * @auth_suite: auth suite + * @auth_type: pointer to enum csr_akm_type + * + * Return: None + */ +static void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4], + enum csr_akm_type *auth_type) +{ + if (!memcmp(auth_suite, ccp_rsn_oui_0e, 4)) + *auth_type = eCSR_AUTH_TYPE_FILS_SHA256; + else if (!memcmp(auth_suite, ccp_rsn_oui_0f, 4)) + *auth_type = eCSR_AUTH_TYPE_FILS_SHA384; + else if (!memcmp(auth_suite, ccp_rsn_oui_10, 4)) + *auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA256; + else if (!memcmp(auth_suite, ccp_rsn_oui_11, 4)) + *auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA384; +} +#else +static inline void hdd_translate_fils_rsn_to_csr_auth(int8_t auth_suite[4], + enum csr_akm_type *auth_type) +{ +} +#endif + +#ifdef WLAN_FEATURE_SAE +/** + * hdd_translate_sae_rsn_to_csr_auth() - Translate SAE RSN to CSR auth type + * @auth_suite: auth suite + * @auth_type: pointer to enum csr_akm_type + * + * Return: None + */ +static void hdd_translate_sae_rsn_to_csr_auth(int8_t auth_suite[4], + enum csr_akm_type *auth_type) +{ + if (qdf_mem_cmp(auth_suite, ccp_rsn_oui_80, 4) == 0) + *auth_type = eCSR_AUTH_TYPE_SAE; + else if (qdf_mem_cmp(auth_suite, ccp_rsn_oui_90, 4) == 0) + *auth_type = eCSR_AUTH_TYPE_FT_SAE; + +} +#else +static inline void hdd_translate_sae_rsn_to_csr_auth(int8_t auth_suite[4], + enum csr_akm_type *auth_type) +{ +} +#endif + +void *hdd_filter_ft_info(const uint8_t *frame, size_t len, + uint32_t *ft_info_len) +{ + uint32_t ft_ie_len, md_ie_len, rsn_ie_len, ie_len; + const uint8_t *rsn_ie, *md_ie, *ft_ie; + void *ft_info; + + ft_ie_len = 0; + md_ie_len = 0; + rsn_ie_len = 0; + ie_len = len - DOT11F_FF_CAPABILITIES_LEN - DOT11F_FF_STATUS_LEN + - DOT11F_IE_AID_MAX_LEN - sizeof(tSirMacMgmtHdr); + rsn_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_RSN, frame, ie_len); + + if (rsn_ie) { + rsn_ie_len = rsn_ie[1] + 2; + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (void *)rsn_ie, rsn_ie_len); + } + md_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_MOBILITYDOMAIN, + frame, ie_len); + if (md_ie) { + md_ie_len = md_ie[1] + 2; + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (void *)md_ie, md_ie_len); + } + ft_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_FTINFO, frame, ie_len); + if (ft_ie) + ft_ie_len = ft_ie[1] + 2; + + *ft_info_len = rsn_ie_len + md_ie_len + ft_ie_len; + ft_info = qdf_mem_malloc(*ft_info_len); + if (!ft_info) + return NULL; + if (rsn_ie_len) + qdf_mem_copy(ft_info, rsn_ie, rsn_ie_len); + if (md_ie_len) + qdf_mem_copy(ft_info + rsn_ie_len, md_ie, md_ie_len); + if (ft_ie_len) + qdf_mem_copy(ft_info + rsn_ie_len + md_ie_len, + ft_ie, ft_ie_len); + return ft_info; +} + +/** + * hdd_translate_rsn_to_csr_auth_type() - Translate RSN to CSR auth type + * @auth_suite: auth suite + * + * Return: enum csr_akm_type enumeration + */ +enum csr_akm_type hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]) +{ + enum csr_akm_type auth_type = eCSR_AUTH_TYPE_UNKNOWN; + /* is the auth type supported? */ + if (memcmp(auth_suite, ccp_rsn_oui01, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN; + } else if (memcmp(auth_suite, ccp_rsn_oui02, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_PSK; + } else if (memcmp(auth_suite, ccp_rsn_oui04, 4) == 0) { + /* Check for 11r FT Authentication with PSK */ + auth_type = eCSR_AUTH_TYPE_FT_RSN_PSK; + } else if (memcmp(auth_suite, ccp_rsn_oui03, 4) == 0) { + /* Check for 11R FT Authentication with 802.1X */ + auth_type = eCSR_AUTH_TYPE_FT_RSN; + } else +#ifdef FEATURE_WLAN_ESE + if (memcmp(auth_suite, ccp_rsn_oui06, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_CCKM_RSN; + } else +#endif /* FEATURE_WLAN_ESE */ + if (memcmp(auth_suite, ccp_rsn_oui07, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + } else if (memcmp(auth_suite, ccp_rsn_oui08, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + } else if (memcmp(auth_suite, ccp_rsn_oui_18, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_OWE; + } else if (memcmp(auth_suite, ccp_rsn_oui_12, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_DPP_RSN; + } else if (memcmp(auth_suite, ccp_rsn_oui_0b, 4) == 0) { + /* Check for Suite B EAP 256 */ + auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; + } else if (memcmp(auth_suite, ccp_rsn_oui_0c, 4) == 0) { + /* Check for Suite B EAP 384 */ + auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + } else if (memcmp(auth_suite, ccp_rsn_oui_0d, 4) == 0) { + /* Check for FT Suite B EAP 384 */ + auth_type = eCSR_AUTH_TYPE_FT_SUITEB_EAP_SHA384; + } else if (memcmp(auth_suite, ccp_rsn_oui_13, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_OSEN; + } else { + hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type); + hdd_translate_sae_rsn_to_csr_auth(auth_suite, &auth_type); + } + + return auth_type; +} + +/** + * hdd_translate_wpa_to_csr_auth_type() - Translate WPA to CSR auth type + * @auth_suite: auth suite + * + * Return: enum csr_akm_type enumeration + */ +enum csr_akm_type hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]) +{ + enum csr_akm_type auth_type = eCSR_AUTH_TYPE_UNKNOWN; + /* is the auth type supported? */ + if (memcmp(auth_suite, ccp_wpa_oui01, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_WPA; + } else if (memcmp(auth_suite, ccp_wpa_oui02, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_WPA_PSK; + } else +#ifdef FEATURE_WLAN_ESE + if (memcmp(auth_suite, ccp_wpa_oui06, 4) == 0) { + auth_type = eCSR_AUTH_TYPE_CCKM_WPA; + } else +#endif /* FEATURE_WLAN_ESE */ + { + hdd_translate_fils_rsn_to_csr_auth(auth_suite, &auth_type); + } + + return auth_type; +} + +/** + * hdd_translate_rsn_to_csr_encryption_type() - + * Translate RSN to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_rsn_oui04, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (memcmp(cipher_suite, ccp_rsn_oui09, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP; + else if (memcmp(cipher_suite, ccp_rsn_oui0a, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP_256; + else if (memcmp(cipher_suite, ccp_rsn_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (memcmp(cipher_suite, ccp_rsn_oui00, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_NONE; + else if (memcmp(cipher_suite, ccp_rsn_oui01, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + else if (memcmp(cipher_suite, ccp_rsn_oui05, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + return cipher_type; +} + +/** + * hdd_translate_wpa_to_csr_encryption_type() - + * Translate WPA to CSR encryption type + * @cipher_suite: cipher suite + * + * Return: eCsrEncryptionType enumeration + */ +eCsrEncryptionType +hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_wpa_oui04, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (memcmp(cipher_suite, ccp_wpa_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (memcmp(cipher_suite, ccp_wpa_oui00, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_NONE; + else if (memcmp(cipher_suite, ccp_wpa_oui01, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP40_STATICKEY; + else if (memcmp(cipher_suite, ccp_wpa_oui05, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WEP104_STATICKEY; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + return cipher_type; +} + +#ifdef FEATURE_WLAN_WAPI +enum csr_akm_type hdd_translate_wapi_to_csr_auth_type(uint8_t auth_suite[4]) +{ + enum csr_akm_type auth_type; + + if (memcmp(auth_suite, ccp_wapi_oui01, 4) == 0) + auth_type = eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + else if (memcmp(auth_suite, ccp_wapi_oui02, 4) == 0) + auth_type = eCSR_AUTH_TYPE_WAPI_WAI_PSK; + else + auth_type = eCSR_AUTH_TYPE_UNKNOWN; + + return auth_type; +} + +eCsrEncryptionType +hdd_translate_wapi_to_csr_encryption_type(uint8_t cipher_suite[4]) +{ + eCsrEncryptionType cipher_type; + + if (memcmp(cipher_suite, ccp_wapi_oui01, 4) == 0 || + memcmp(cipher_suite, ccp_wapi_oui02, 4) == 0) + cipher_type = eCSR_ENCRYPT_TYPE_WPI; + else + cipher_type = eCSR_ENCRYPT_TYPE_FAILED; + + return cipher_type; +} +#endif /* FEATURE_WLAN_WAPI */ + +enum cdp_peer_bw +hdd_convert_ch_width_to_cdp_peer_bw(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + return CDP_20_MHZ; + case CH_WIDTH_40MHZ: + return CDP_40_MHZ; + case CH_WIDTH_80MHZ: + return CDP_80_MHZ; + case CH_WIDTH_160MHZ: + return CDP_160_MHZ; + case CH_WIDTH_80P80MHZ: + return CDP_80P80_MHZ; + case CH_WIDTH_5MHZ: + return CDP_5_MHZ; + case CH_WIDTH_10MHZ: + return CDP_10_MHZ; + case CH_WIDTH_320MHZ: + return CDP_320_MHZ; + default: + return CDP_BW_INVALID; + } + + return CDP_BW_INVALID; +} + +#ifdef WLAN_FEATURE_FILS_SK +bool hdd_is_fils_connection(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_fils_connection_info *fils_info; + + fils_info = wlan_cm_get_fils_connection_info(hdd_ctx->psoc, + adapter->deflink->vdev_id); + if (fils_info) + return fils_info->is_fils_connection; + + return false; +} +#else +bool hdd_is_fils_connection(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + return false; +} +#endif + +void hdd_roam_profile_init(struct wlan_hdd_link_info *link_info) +{ + struct csr_roam_profile *roam_profile; + struct hdd_station_ctx *sta_ctx; + + hdd_enter(); + + roam_profile = hdd_roam_profile(link_info); + qdf_mem_zero(roam_profile, sizeof(*roam_profile)); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + /* Configure the roaming profile links to SSID and bssid. */ + roam_profile->SSIDs.numOfSSIDs = 0; + roam_profile->SSIDs.SSIDList = &sta_ctx->conn_info.ssid; + + roam_profile->BSSIDs.numOfBSSIDs = 0; + roam_profile->BSSIDs.bssid = &sta_ctx->conn_info.bssid; + + /* Set the numOfChannels to zero to scan all the channels */ + roam_profile->ChannelInfo.numOfChannels = 0; + roam_profile->ChannelInfo.freq_list = NULL; + + roam_profile->BSSType = eCSR_BSS_TYPE_INFRASTRUCTURE; + + roam_profile->phyMode = eCSR_DOT11_MODE_AUTO; + + /* Set the default scan mode */ + link_info->adapter->scan_info.scan_mode = eSIR_ACTIVE_SCAN; + + hdd_clear_roam_profile_ie(link_info->adapter); + hdd_exit(); +} + +struct osif_cm_ops osif_ops = { + .connect_active_notify_cb = hdd_cm_connect_active_notify, + .connect_complete_cb = hdd_cm_connect_complete, + .disconnect_complete_cb = hdd_cm_disconnect_complete, + .netif_queue_control_cb = hdd_cm_netif_queue_control, + .napi_serialize_control_cb = hdd_cm_napi_serialize_control, + .save_gtk_cb = hdd_cm_save_gtk, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + .roam_rt_stats_event_cb = wlan_hdd_cfg80211_roam_events_callback, +#endif +#ifdef WLAN_FEATURE_FILS_SK + .set_hlp_data_cb = hdd_cm_set_hlp_data, +#endif +#ifdef WLAN_FEATURE_PREAUTH_ENABLE + .ft_preauth_complete_cb = hdd_cm_ft_preauth_complete, +#ifdef FEATURE_WLAN_ESE + .cckm_preauth_complete_cb = hdd_cm_cckm_preauth_complete, +#endif +#endif +#ifdef WLAN_VENDOR_HANDOFF_CONTROL + .vendor_handoff_params_cb = hdd_cm_get_vendor_handoff_params, +#endif + .send_vdev_keys_cb = hdd_cm_send_vdev_keys, + .get_scan_ie_params_cb = hdd_cm_get_scan_ie_params, +#ifdef WLAN_BOOST_CPU_FREQ_IN_ROAM + .perfd_set_cpufreq_cb = hdd_cm_perfd_set_cpufreq, +#endif +}; + +QDF_STATUS hdd_cm_register_cb(void) +{ + QDF_STATUS status; + osif_cm_set_legacy_cb(&osif_ops); + + status = osif_cm_register_cb(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* Overwrite with UTF cb if UTF enabled */ + return cm_utf_register_os_if_cb(); +} + +void hdd_cm_unregister_cb(void) +{ + osif_cm_reset_legacy_cb(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_avoid_freq_ext.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_avoid_freq_ext.c new file mode 100644 index 0000000000..1db62ccf0c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_avoid_freq_ext.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_avoid_freq_ext.c + * + * WLAN Host Device Driver extended avoid frequency interface implementation. + */ + +/* Include Files */ + +#include +#include "wlan_hdd_avoid_freq_ext.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_reg_services_api.h" + +#define AVOID_FREQ_EXT_MAX QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + +const struct nla_policy +avoid_freq_ext_policy [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE] = { .type = NLA_NESTED }, + [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM] = {.type = + NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK] = {.type = + NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_avoid_freq_ext() - exclude channels from upper layer. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_avoid_freq_ext() extract the valid avoid frequency + * list from upper layer and prepared one extended avoid frequency list for + * regulatory component. + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_avoid_freq_ext(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + struct ch_avoid_ind_type avoid_freq_list; + enum QDF_GLOBAL_MODE curr_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX + 1]; + struct nlattr *freq_ext; + int id, rem, i, sub_id; + struct ch_avoid_freq_type *avoid_freq_range; + + hdd_enter_dev(wdev->netdev); + + if (!ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer(hdd_ctx->psoc)) { + hdd_debug_rl("Coex unsafe chan nb user prefer is not set"); + return -EOPNOTSUPP; + } + + curr_mode = hdd_get_conparam(); + if (curr_mode == QDF_GLOBAL_FTM_MODE || + curr_mode == QDF_GLOBAL_MONITOR_MODE) { + hdd_debug_rl("Command not allowed in FTM/MONITOR mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_is_connection_in_progress(NULL, NULL)) { + hdd_debug_rl("Update chan list refused: conn in progress"); + ret = -EPERM; + goto out; + } + + qdf_mem_zero(&avoid_freq_list, sizeof(struct ch_avoid_ind_type)); + + if (!data && data_len == 0) { + hdd_debug_rl("Clear extended avoid frequency list"); + goto process_avoid_channel_ext; + } + + ret = wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_MAX, + data, + data_len, + avoid_freq_ext_policy); + if (ret) { + hdd_err_rl("Invalid avoid freq ext ATTR"); + ret = -EINVAL; + goto out; + } + + id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_RANGE; + + if (!tb[id]) { + hdd_err_rl("Attr avoid frequency ext range failed"); + ret = -EINVAL; + goto out; + } + + i = 0; + avoid_freq_list.ch_avoid_range_cnt = CH_AVOID_MAX_RANGE; + + /* restriction mask */ + sub_id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_IFACES_BITMASK; + + if (tb[sub_id]) + avoid_freq_list.restriction_mask = nla_get_u32(tb[sub_id]); + + if (avoid_freq_list.restriction_mask & BIT(NL80211_IFTYPE_AP)) + avoid_freq_list.restriction_mask = (1 << QDF_SAP_MODE); + + nla_for_each_nested(freq_ext, tb[id], rem) { + if (i == CH_AVOID_MAX_RANGE) { + hdd_warn_rl("Ignoring excess range number"); + break; + } + + if (wlan_cfg80211_nla_parse(tb2, AVOID_FREQ_EXT_MAX, + nla_data(freq_ext), + nla_len(freq_ext), + avoid_freq_ext_policy)) { + hdd_err_rl("nla_parse failed"); + ret = -EINVAL; + goto out; + } + + avoid_freq_range = &avoid_freq_list.avoid_freq_range[i]; + + /* ext avoid freq start */ + sub_id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_START; + if (!tb2[sub_id]) { + ret = -EINVAL; + goto out; + } + avoid_freq_range->start_freq = nla_get_u32(tb2[sub_id]); + + /* ext avoid freq end */ + sub_id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_END; + if (!tb2[sub_id]) { + ret = -EINVAL; + goto out; + } + avoid_freq_range->end_freq = nla_get_u32(tb2[sub_id]); + + if (!avoid_freq_range->start_freq && + !avoid_freq_range->end_freq && (i < 1)) { + hdd_debug_rl("Clear unsafe channel list"); + } else if (!wlan_reg_is_same_band_freqs( + avoid_freq_range->start_freq, + avoid_freq_range->end_freq)) { + hdd_debug_rl("start freq %d end freq %d not in same band", + avoid_freq_range->start_freq, + avoid_freq_range->end_freq); + ret = -EINVAL; + goto out; + } + + if (avoid_freq_range->end_freq < + avoid_freq_range->start_freq) { + ret = -EINVAL; + goto out; + } + + /* ext txpower */ + sub_id = QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_POWER_CAP_DBM; + + if (tb2[sub_id]) { + avoid_freq_range->txpower = nla_get_s32(tb2[sub_id]); + avoid_freq_range->is_valid_txpower = true; + } + + hdd_debug_rl("ext avoid freq start: %u end: %u txpower %d mask %d", + avoid_freq_range->start_freq, + avoid_freq_range->end_freq, + avoid_freq_range->txpower, + avoid_freq_list.restriction_mask); + i++; + } + + if (i < CH_AVOID_MAX_RANGE) { + hdd_warn_rl("Number of freq range %u less than expected %u", + i, CH_AVOID_MAX_RANGE); + avoid_freq_list.ch_avoid_range_cnt = i; + } + +process_avoid_channel_ext: + ucfg_reg_ch_avoid_ext(hdd_ctx->psoc, &avoid_freq_list); +out: + return ret; +} + +/** + * wlan_hdd_cfg80211_avoid_freq_ext() - exclude channels from upper layer. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * wlan_hdd_cfg80211_avoid_freq_ext() will pass the extended avoid frequency + * list from upper layer to regulatory component to compute one new channel + * list. + * + * Return: 0 on success; errno on failure + */ +int wlan_hdd_cfg80211_avoid_freq_ext(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_avoid_freq_ext(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bcn_recv.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bcn_recv.c new file mode 100644 index 0000000000..623e243869 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bcn_recv.c @@ -0,0 +1,555 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_bcn_recv.c + * Feature for receiving beacons of connected AP and sending select + * params to upper layer via vendor event + */ + +#include +#include +#include "wlan_osif_priv.h" +#include "qdf_trace.h" +#include "wlan_hdd_main.h" +#include "osif_sync.h" +#include "wlan_hdd_bcn_recv.h" +#include +#include + +#define SET_BIT(value, mask) ((value) |= (1 << (mask))) + +#define BOOTTIME QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED + +#ifndef CHAR_BIT +#define CHAR_BIT 8 /* Normally in */ +#endif + +const struct nla_policy + beacon_reporting_params_policy + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING] = {.type = + NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME] = {.type = + NLA_FLAG}, +}; + +/** + * get_beacon_report_data_len() - Calculate length for beacon + * report to allocate skb buffer + * @report: beacon report structure + * + * Return: skb buffer length + */ +static +int get_beacon_report_data_len(struct wlan_beacon_report *report) +{ + uint32_t data_len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID */ + data_len += nla_total_size(report->ssid.length); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID */ + data_len += nla_total_size(ETH_ALEN); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI */ + data_len += nla_total_size(sizeof(u16)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF */ + data_len += nla_total_size(sizeof(uint64_t)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BOOTTIME_WHEN_RECEIVED */ + data_len += nla_total_size(sizeof(uint64_t)); + + return data_len; +} + +/** + * get_pause_ind_data_len() - Calculate skb buffer length + * @is_disconnected: Connection state + * + * Calculate length for pause indication to allocate skb buffer + * + * Return: skb buffer length + */ +static int get_pause_ind_data_len(bool is_disconnected) +{ + uint32_t data_len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON */ + data_len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES */ + if (!is_disconnected) + data_len += nla_total_size(sizeof(u8)); + + return data_len; +} + +/** + * hdd_send_bcn_recv_info() - Send beacon info to userspace for + * connected AP + * @hdd_handle: hdd_handle to get hdd_adapter + * @beacon_report: Required beacon report + * + * Send beacon info to userspace for connected AP through a vendor event: + * QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING. + */ +static QDF_STATUS hdd_send_bcn_recv_info(hdd_handle_t hdd_handle, + struct wlan_beacon_report + *beacon_report) +{ + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + uint32_t data_len; + int flags = cds_get_gfp_flags(); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX; + + if (wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_FAILURE; + + data_len = get_beacon_report_data_len(beacon_report); + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, beacon_report->vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return QDF_STATUS_E_FAILURE; + + adapter = link_info->adapter; + vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &adapter->wdev, + data_len, index, flags); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return QDF_STATUS_E_FAILURE; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE, + QCA_WLAN_VENDOR_BEACON_REPORTING_OP_BEACON_INFO) || + nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_SSID, + beacon_report->ssid.length, beacon_report->ssid.ssid) || + nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BSSID, + ETH_ALEN, beacon_report->bssid.bytes) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_FREQ, + beacon_report->frequency) || + nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_BI, + beacon_report->beacon_interval) || + wlan_cfg80211_nla_put_u64(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_TSF, + beacon_report->time_stamp) || + wlan_cfg80211_nla_put_u64(vendor_event, BOOTTIME, + beacon_report->boot_time)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return QDF_STATUS_E_FAILURE; + } + + wlan_cfg80211_vendor_event(vendor_event, flags); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_handle_beacon_reporting_start_op() - Process bcn recv start op + * @hdd_ctx: Pointer to hdd context + * @adapter: Pointer to network adapter + * @active_report: Active reporting flag + * @nth_value: Beacon report period + * @do_not_resume: beacon reporting resume after a pause is completed + * + * This function process beacon reporting start operation. + */ +static int hdd_handle_beacon_reporting_start_op(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool active_report, + uint32_t nth_value, + bool do_not_resume) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int errno; + uint32_t mask = 0; + + if (active_report) { + /* Register beacon report callback */ + qdf_status = + sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, + hdd_send_bcn_recv_info); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("bcn recv info cb reg failed = %d", qdf_status); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + + /* Register pause indication callback */ + qdf_status = + sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, + hdd_beacon_recv_pause_indication); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("pause_ind_cb reg failed = %d", qdf_status); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + /* Update Beacon report period in case of active reporting */ + nth_value = 1; + /* + * Set MSB which indicates fw to don't wakeup host in wow + * mode in case of active beacon report. + */ + mask = (sizeof(uint32_t) * CHAR_BIT) - 1; + SET_BIT(nth_value, mask); + } + /* Handle beacon receive start indication */ + qdf_status = sme_handle_bcn_recv_start(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + nth_value, do_not_resume); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("bcn rcv start failed with status=%d", qdf_status); + if (sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, NULL)) + hdd_err("bcn report cb deregistration failed"); + if (sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, + NULL)) + hdd_err("bcn pause ind cb deregistration failed"); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + + errno = qdf_status_to_os_return(qdf_status); + + return errno; +} + +/** + * hdd_handle_beacon_reporting_stop_op() - Process bcn recv stop op + * @hdd_ctx: Pointer to hdd context + * @adapter: Pointer to network adapter + * + * This function process beacon reporting stop operation. + */ +static int hdd_handle_beacon_reporting_stop_op(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int errno; + + /* Reset bcn recv start flag */ + sme_stop_beacon_report(hdd_ctx->mac_handle, adapter->deflink->vdev_id); + + /* Deregister beacon report callback */ + qdf_status = sme_register_bcn_report_pe_cb(hdd_ctx->mac_handle, NULL); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("Callback de-registration failed = %d", qdf_status); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + + /* Deregister pause indication callback */ + qdf_status = sme_register_bcn_recv_pause_ind_cb(hdd_ctx->mac_handle, + NULL); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("scan even deregister failed = %d", qdf_status); + errno = qdf_status_to_os_return(qdf_status); + return errno; + } + + if (hdd_cm_is_vdev_associated(adapter->deflink)) + /* Add beacon filter */ + if (hdd_add_beacon_filter(adapter)) { + hdd_err("Beacon filter addition failed"); + return -EINVAL; + } + + errno = qdf_status_to_os_return(qdf_status); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_bcn_rcv_op() - enable/disable beacon reporting + * indication + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to enable/disable asynchronous beacon + * reporting feature using vendor commands. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX + 1]; + uint32_t bcn_report, nth_value = 1; + int errno; + bool active_report, do_not_resume; + struct wlan_objmgr_vdev *vdev; + enum scm_scan_status scan_req_status; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("Command not allowed as device not in STA mode"); + return -EINVAL; + } + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("STA not in connected state"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID); + if (!vdev) + return -EINVAL; + + scan_req_status = ucfg_scan_get_pdev_status(wlan_vdev_get_pdev(vdev)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_SCAN_ID); + + if (scan_req_status != SCAN_NOT_IN_PROGRESS) { + hdd_debug("Scan in progress: %d, bcn rpt start OP not allowed", + scan_req_status); + return -EBUSY; + } + + errno = + wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_MAX, + data, + data_len, beacon_reporting_params_policy); + if (errno) { + hdd_err("Failed to parse the beacon reporting params %d", + errno); + return errno; + } + + /* Parse and fetch OP Type */ + if (!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]) { + hdd_err("attr beacon report OP type failed"); + return -EINVAL; + } + bcn_report = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE]); + hdd_debug("Bcn Report: OP type:%d", bcn_report); + + switch (bcn_report) { + case QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START: + active_report = + !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_ACTIVE_REPORTING]; + hdd_debug("attr active_report %d", active_report); + + do_not_resume = + !!tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_DO_NOT_RESUME]; + hdd_debug("Attr beacon report do not resume %d", do_not_resume); + + if (tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]) + nth_value = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PERIOD]); + hdd_debug("Beacon Report: Period: %d", nth_value); + + if (sme_is_beacon_report_started(hdd_ctx->mac_handle, + adapter->deflink->vdev_id)) { + hdd_debug("Start cmd already in progress, issue the stop to FW, before new start"); + if (hdd_handle_beacon_reporting_stop_op(hdd_ctx, + adapter)) { + hdd_err("Failed to stop the beacon reporting before starting new start"); + return -EAGAIN; + } + } + errno = hdd_handle_beacon_reporting_start_op(hdd_ctx, + adapter, + active_report, + nth_value, + do_not_resume); + if (errno) { + hdd_err("Failed to start beacon reporting %d,", errno); + break; + } + break; + case QCA_WLAN_VENDOR_BEACON_REPORTING_OP_STOP: + if (sme_is_beacon_report_started(hdd_ctx->mac_handle, + adapter->deflink->vdev_id)) { + errno = hdd_handle_beacon_reporting_stop_op(hdd_ctx, + adapter); + if (errno) { + hdd_err("Failed to stop the beacon report, %d", + errno); + } + } else { + hdd_err_rl("BCN_RCV_STOP rej as no START CMD active"); + errno = -EINVAL; + } + break; + default: + hdd_debug("Invalid bcn report type %d", bcn_report); + } + + return errno; +} + +void hdd_beacon_recv_pause_indication(hdd_handle_t hdd_handle, + uint8_t vdev_id, + enum scan_event_type type, + bool is_disconnected) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct hdd_adapter *adapter; + struct sk_buff *vendor_event; + uint32_t data_len; + int flags; + uint32_t abort_reason; + bool do_not_resume; + struct wlan_hdd_link_info *link_info; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return; + + adapter = link_info->adapter; + data_len = get_pause_ind_data_len(is_disconnected); + flags = cds_get_gfp_flags(); + + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &(adapter->wdev), + data_len, + QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING_INDEX, + flags); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + do_not_resume = + sme_is_beacon_reporting_do_not_resume(hdd_ctx->mac_handle, + link_info->vdev_id); + + if (is_disconnected) { + abort_reason = + QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_DISCONNECTED; + /* Deregister callbacks and Reset bcn recv start flag */ + if (sme_is_beacon_report_started(hdd_ctx->mac_handle, + link_info->vdev_id)) + hdd_handle_beacon_reporting_stop_op(hdd_ctx, adapter); + } else { + /* + * In case of scan, Check that auto resume of beacon reporting + * is allowed or not. + * If not allowed: + * Deregister callbacks and Reset bcn recv start flag in order + * to make sure host should not send beacon report to userspace + * further. + * If Auto resume allowed: + * Send pause indication to userspace and continue sending + * connected AP's beacon to userspace. + */ + if (do_not_resume) + hdd_handle_beacon_reporting_stop_op(hdd_ctx, adapter); + + switch (type) { + case SCAN_EVENT_TYPE_STARTED: + abort_reason = + QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_SCAN_STARTED; + break; + default: + abort_reason = + QCA_WLAN_VENDOR_BEACON_REPORTING_PAUSE_REASON_UNSPECIFIED; + } + } + /* Send vendor event to user space to inform ABORT */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_OP_TYPE, + QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_PAUSE_REASON, + abort_reason)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + /* + * Send auto resume flag to user space to specify the driver will + * automatically resume reporting beacon events only in case of + * pause indication due to scan started. + * If do_not_resume flag is set in the recent + * QCA_WLAN_VENDOR_BEACON_REPORTING_OP_START command, then in the + * subsequent QCA_WLAN_VENDOR_BEACON_REPORTING_OP_PAUSE event (if any) + * the QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES shall not be + * set by the driver. + */ + if (!is_disconnected && !do_not_resume) + if (nla_put_flag(vendor_event, + QCA_WLAN_VENDOR_ATTR_BEACON_REPORTING_AUTO_RESUMES)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, flags); +} + +int wlan_hdd_cfg80211_bcn_rcv_op(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_bcn_rcv_op(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bootup_marker.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bootup_marker.c new file mode 100644 index 0000000000..dc2a643685 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bootup_marker.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_bootup_marker.c + * + * WLAN Host Device Driver bootup marker implementation + * + */ + +#include "wlan_hdd_bootup_marker.h" +#include +#include + +#ifdef DYNAMIC_SINGLE_CHIP +#define PREFIX_MARKER DYNAMIC_SINGLE_CHIP +#else +#ifdef MULTI_IF_NAME +#define PREFIX_MARKER MULTI_IF_NAME +#else +#define PREFIX_MARKER "" +#endif +#endif + +#ifndef WLAN_PLACEMARKER_PREFIX +#define WLAN_PLACEMARKER_PREFIX "" +#define WLAN_MARKER WLAN_PLACEMARKER_PREFIX PREFIX_MARKER " " +#else +#define WLAN_MARKER WLAN_PLACEMARKER_PREFIX " " PREFIX_MARKER " " +#endif + +void hdd_place_marker(struct hdd_adapter *adapter, + const char *format, + uint8_t *mac) +{ + char marker[100]; + + if (adapter) { + if (mac) + qdf_snprintf(marker, sizeof(marker), + (WLAN_MARKER "%s:%s %s:" QDF_MAC_ADDR_FMT), + (adapter->dev->name), + qdf_opmode_str(adapter->device_mode), + format, QDF_MAC_ADDR_REF(mac)); + else + qdf_snprintf(marker, sizeof(marker), + (WLAN_MARKER "%s:%s %s"), + (adapter->dev->name), + qdf_opmode_str(adapter->device_mode), + format); + } else { + qdf_snprintf(marker, sizeof(marker), + (WLAN_MARKER "%s"), + format); + } + + place_marker(marker); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bss_transition.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bss_transition.c new file mode 100644 index 0000000000..558bad33a7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bss_transition.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_bss_transition.c + * + * WLAN bss transition functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include + +/** + * wlan_hdd_is_bt_in_progress() - check if bt activity is in progress + * @hdd_ctx : HDD context + * + * Return: true if BT activity is in progress else false + */ +static bool wlan_hdd_is_bt_in_progress(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->bt_a2dp_active || hdd_ctx->bt_vo_active) + return true; + + return false; +} + +/** + * wlan_hdd_fill_btm_resp() - Fill bss candidate response buffer + * @reply_skb : pointer to reply_skb + * @info : bss candidate information + * @index : attribute type index for nla_next_start() + * + * Return : 0 on success and errno on failure + */ +static int wlan_hdd_fill_btm_resp(struct sk_buff *reply_skb, + struct bss_candidate_info *info, + int index) +{ + struct nlattr *attr; + + attr = nla_nest_start(reply_skb, index); + if (!attr) { + hdd_err("nla_nest_start failed"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + + if (nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID, + ETH_ALEN, info->bssid.bytes) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS, + info->status)) { + hdd_err("nla_put failed"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + + nla_nest_end(reply_skb, attr); + + return 0; +} + +const struct nla_policy +btm_params_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO] = + VENDOR_NLA_POLICY_NESTED(btm_cand_list_policy), +}; + +const struct nla_policy +btm_cand_list_policy[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1] + = {[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID] = { + .len = QDF_MAC_ADDR_SIZE}, + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_STATUS] = { + .type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_fetch_bss_transition_status() - fetch bss transition + * status + * @wiphy : WIPHY structure pointer + * @wdev : Wireless device structure pointer + * @data : Pointer to the data received + * @data_len : Length of the data received + * + * This function is used to fetch transition status for candidate bss. The + * transition status is either accept or reason for reject. + * + * Return : 0 on success and errno on failure + */ +static int +__wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1]; + uint8_t transition_reason; + struct nlattr *attr; + struct sk_buff *skb; + int rem, j; + int ret; + bool is_bt_in_progress; + struct bss_candidate_info candidate_info[MAX_CANDIDATE_INFO]; + uint16_t nof_candidates, i = 0; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_station_ctx *hdd_sta_ctx; + mac_handle_t mac_handle; + QDF_STATUS status; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (adapter->device_mode != QDF_STA_MODE || + !hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Command is either not invoked for STA mode (device mode: %d) or STA is not associated (Connection state: %d)", + adapter->device_mode, hdd_sta_ctx->conn_info.conn_state); + return -EINVAL; + } + + ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, + data_len, btm_params_policy); + if (ret) { + hdd_err("Attribute parse failed"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON] || + !tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO]) { + hdd_err("Missing attributes"); + return -EINVAL; + } + + transition_reason = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_BTM_MBO_TRANSITION_REASON]); + + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO], + rem) { + ret = wlan_cfg80211_nla_parse_nested(tb_msg, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX, + attr, btm_cand_list_policy); + if (ret) { + hdd_err("Attribute parse failed"); + return -EINVAL; + } + + if (!tb_msg[QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]) { + hdd_err("Missing BSSID attribute"); + return -EINVAL; + } + + qdf_mem_copy((void *)candidate_info[i].bssid.bytes, + nla_data(tb_msg[ + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_BSSID]), + QDF_MAC_ADDR_SIZE); + i++; + if (i == MAX_CANDIDATE_INFO) + break; + } + + /* + * Determine status for each candidate and fill in the status field. + * Also arrange the candidates in the order of preference. + */ + nof_candidates = i; + + is_bt_in_progress = wlan_hdd_is_bt_in_progress(hdd_ctx); + + mac_handle = hdd_ctx->mac_handle; + status = sme_get_bss_transition_status(mac_handle, transition_reason, + &hdd_sta_ctx->conn_info.bssid, + candidate_info, + nof_candidates, + is_bt_in_progress); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + /* Prepare the reply and send it to userspace */ + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + (QDF_MAC_ADDR_SIZE + + sizeof(uint32_t)) * + nof_candidates + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("reply buffer alloc failed"); + return -ENOMEM; + } + + attr = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO); + if (!attr) { + hdd_err("nla_nest_start failed"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + /* + * Order candidates as - accepted candidate list followed by rejected + * candidate list + */ + for (i = 0, j = 0; i < nof_candidates; i++) { + /* copy accepted candidate list */ + if (candidate_info[i].status == QCA_STATUS_ACCEPT) { + if (wlan_hdd_fill_btm_resp(skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + for (i = 0; i < nof_candidates; i++) { + /* copy rejected candidate list */ + if (candidate_info[i].status != QCA_STATUS_ACCEPT) { + if (wlan_hdd_fill_btm_resp(skb, + &candidate_info[i], j)) + return -EINVAL; + j++; + } + } + nla_nest_end(skb, attr); + + hdd_exit(); + + return wlan_cfg80211_vendor_cmd_reply(skb); +} + +int wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_fetch_bss_transition_status(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bss_transition.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bss_transition.h new file mode 100644 index 0000000000..e5831ad33b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_bss_transition.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_BSS_TRANSITION_H +#define __WLAN_HDD_BSS_TRANSITION_H + +/** + * DOC: wlan_hdd_bss_transition_h + * + * WLAN Host Device Driver BSS transition API specification + */ + +#ifdef FEATURE_BSS_TRANSITION +/** + * wlan_hdd_cfg80211_fetch_bss_transition_status() - fetch bss transition status + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to fetch transition status for candidate bss. The + * transition status is either accept or reason for reject. + * + * Return: 0 on success and errno on failure + */ +int +wlan_hdd_cfg80211_fetch_bss_transition_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +extern const struct nla_policy + btm_params_policy + [QCA_WLAN_VENDOR_ATTR_MAX + 1]; + +extern const struct nla_policy + btm_cand_list_policy + [QCA_WLAN_VENDOR_ATTR_BTM_CANDIDATE_INFO_MAX + 1]; + +#define FEATURE_BSS_TRANSITION_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_FETCH_BSS_TRANSITION_STATUS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_fetch_bss_transition_status, \ + vendor_command_policy(btm_params_policy, \ + QCA_WLAN_VENDOR_ATTR_MAX) \ +}, +#else /* FEATURE_BSS_TRANSITION */ +#define FEATURE_BSS_TRANSITION_VENDOR_COMMANDS +#endif /* FEATURE_BSS_TRANSITION */ + +#endif /* __WLAN_HDD_BSS_TRANSITION_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_btc_chain_mode.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_btc_chain_mode.c new file mode 100644 index 0000000000..350b08cf79 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_btc_chain_mode.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_btc_chain_mode.c + * + * The implementation of bt coex chain mode configuration + * + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_btc_chain_mode.h" +#include "osif_sync.h" +#include "wlan_coex_ucfg_api.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_cfg80211_coex.h" + +static QDF_STATUS +wlan_hdd_btc_chain_mode_handler(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct hdd_adapter *adapter; + mac_handle_t mac_handle; + uint8_t nss, band; + enum coex_btc_chain_mode mode; + uint8_t vdev_id; + uint32_t freq; + struct wlan_objmgr_psoc *psoc; + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("NULL vdev"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + if (wlan_hdd_validate_vdev_id(vdev_id)) + return QDF_STATUS_E_INVAL; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("NULL psoc"); + return QDF_STATUS_E_INVAL; + } + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_STATUS_E_INVAL; + } + + adapter = link_info->adapter; + status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get cur BTC chain mode, status %d", status); + return -EFAULT; + } + + mac_handle = adapter->hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("NULL MAC handle"); + return -EINVAL; + } + + nss = ((mode == WLAN_COEX_BTC_CHAIN_MODE_FDD || + mode == WLAN_COEX_BTC_CHAIN_MODE_HYBRID) ? 1 : 2); + + hdd_debug("update nss to %d for vdev %d, device mode %d", + nss, link_info->vdev_id, adapter->device_mode); + band = NSS_CHAINS_BAND_2GHZ; + sme_update_nss_in_mlme_cfg(mac_handle, nss, nss, + adapter->device_mode, band); + sme_update_vdev_type_nss(mac_handle, nss, band); + + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_OSIF_ID); + if (QDF_IS_STATUS_SUCCESS(status)) { + hdd_store_nss_chains_cfg_in_vdev(adapter->hdd_ctx, vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + } + + sme_update_he_cap_nss(mac_handle, link_info->vdev_id, nss); + freq = hdd_get_link_info_home_channel(link_info); + + /* + * BT coex chain mode is for COEX between BT and WiFi-2.4G. + * Nss and related parameters have been updated upon for + * NSS_CHAINS_BAND_2GHZ. + * If the current home channel is NOT 2.4G, these parameters + * will take effect when switching to 2.4G, so no need to do + * restart here. + */ + if (!WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + return QDF_STATUS_SUCCESS; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + wlan_hdd_cm_issue_disconnect(link_info, + REASON_PREV_AUTH_NOT_VALID, false); + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + hdd_restart_sap(link_info); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc) +{ + ucfg_coex_register_cfg_updated_handler(psoc, + COEX_CONFIG_BTC_CHAIN_MODE, + wlan_hdd_btc_chain_mode_handler + ); +} + +/** + * __wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to btc chain mode command parameters. + * @data_len: the length in byte of btc chain mode command parameters. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int errno; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno != 0) + return errno; + + if (hdd_ctx->num_rf_chains < 2) { + hdd_debug("Num of chains [%u] is less than 2, setting BTC separate chain mode is not allowed", + hdd_ctx->num_rf_chains); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + errno = wlan_cfg80211_coex_set_btc_chain_mode(vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return errno; +} + +/** + * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to btc chain mode command parameters. + * @data_len: the length in byte of btc chain mode command parameters. + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_btc_chain_mode(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_btc_chain_mode.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_btc_chain_mode.h new file mode 100644 index 0000000000..71ebda6e4e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_btc_chain_mode.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_btc_chain_mode.h + * + * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE + */ + +#ifndef __WLAN_HDD_BTC_CHAIN_MODE_H +#define __WLAN_HDD_BTC_CHAIN_MODE_H + +#ifdef FEATURE_BTC_CHAIN_MODE +#include + +/** + * wlan_hdd_register_btc_chain_mode_handler() - register handler for BT coex + * chain mode notification. + * @psoc: pointer to psoc object + * + * Return: None + */ +void wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to btc chain mode command parameters. + * @data_len: the length in byte of btc chain mode command parameters. + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_set_btc_chain_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +extern const struct nla_policy +btc_chain_mode_policy[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1]; + +#define FEATURE_BTC_CHAIN_MODE_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_btc_chain_mode, \ + vendor_command_policy(btc_chain_mode_policy, \ + QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX) \ +}, +#else /* FEATURE_BTC_CHAIN_MODE */ +static inline void +wlan_hdd_register_btc_chain_mode_handler(struct wlan_objmgr_psoc *psoc) {} + +#define FEATURE_BTC_CHAIN_MODE_COMMANDS +#endif /* FEATURE_BTC_CHAIN_MODE */ + +#endif /* __WLAN_HDD_BTC_CHAIN_MODE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c new file mode 100644 index 0000000000..cbdf7350fe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c @@ -0,0 +1,2798 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_cfg.c + * + * WLAN Host Device Driver configuration interface implementation + */ + +/* Include Files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_he.h" +#include +#include "wifi_pos_api.h" +#include "wlan_hdd_green_ap.h" +#include "wlan_hdd_twt.h" +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_fwol_ucfg_api.h" +#include "cfg_ucfg_api.h" +#include "hdd_dp_cfg.h" +#include +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_cmn.h" + +#ifndef WLAN_MAC_ADDR_UPDATE_DISABLE +/** + * get_next_line() - find and locate the new line pointer + * @str: pointer to string + * + * This function returns a pointer to the character after the occurrence + * of a new line character. It also modifies the original string by replacing + * the '\n' character with the null character. + * + * Return: the pointer to the character at new line, + * or NULL if no new line character was found + */ +static char *get_next_line(char *str) +{ + char c; + + if (!str || *str == '\0') + return NULL; + + c = *str; + while (c != '\n' && c != '\0' && c != 0xd) { + str = str + 1; + c = *str; + } + + if (c == '\0') + return NULL; + + *str = '\0'; + return str + 1; +} + +/** look for space. Ascii values to look are + * 0x09 == horizontal tab + * 0x0a == Newline ("\n") + * 0x0b == vertical tab + * 0x0c == Newpage or feed form. + * 0x0d == carriage return (CR or "\r") + * Null ('\0') should not considered as space. + */ +#define i_isspace(ch) (((ch) >= 0x09 && (ch) <= 0x0d) || (ch) == ' ') + +/** + * i_trim() - trims any leading and trailing white spaces + * @str: pointer to string + * + * Return: the pointer of the string + */ +static char *i_trim(char *str) +{ + char *ptr; + + if (*str == '\0') + return str; + + /* Find the first non white-space */ + ptr = str; + while (i_isspace(*ptr)) + ptr++; + + if (*ptr == '\0') + return str; + + /* This is the new start of the string */ + str = ptr; + + /* Find the last non white-space */ + ptr += strlen(ptr) - 1; + + while (ptr != str && i_isspace(*ptr)) + ptr--; + + /* Null terminate the following character */ + ptr[1] = '\0'; + + return str; +} + +/** struct hdd_cfg_entry - ini configuration entry + * @name: name of the entry + * @value: value of the entry + */ +struct hdd_cfg_entry { + char *name; + char *value; +}; + +/** + * update_mac_from_string() - convert string to 6 bytes mac address + * @hdd_ctx: the pointer to hdd context + * @mac_table: the mac_table to carry the conversion + * @num: number of the interface + * + * 00AA00BB00CC -> 0x00 0xAA 0x00 0xBB 0x00 0xCC + * + * Return: QDF_STATUS + */ +static QDF_STATUS update_mac_from_string(struct hdd_context *hdd_ctx, + struct hdd_cfg_entry *mac_table, + int num) +{ + int i = 0, j = 0, res = 0; + char *candidate = NULL; + struct qdf_mac_addr macaddr[QDF_MAX_CONCURRENCY_PERSONA]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + memset(macaddr, 0, sizeof(macaddr)); + + for (i = 0; i < num; i++) { + candidate = mac_table[i].value; + for (j = 0; j < QDF_MAC_ADDR_SIZE; j++) { + res = + hex2bin(&macaddr[i].bytes[j], &candidate[(j << 1)], + 1); + if (res < 0) + break; + } + if (res == 0 && !qdf_is_macaddr_zero(&macaddr[i])) { + qdf_mem_copy((uint8_t *)&hdd_ctx-> + provisioned_mac_addr[i].bytes[0], + (uint8_t *) &macaddr[i].bytes[0], + QDF_MAC_ADDR_SIZE); + } else { + status = QDF_STATUS_E_FAILURE; + break; + } + } + return status; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) +static inline +int hdd_firmware_request_nowarn(const struct firmware **fw, + const char *name, + struct device *device) +{ + return firmware_request_nowarn(fw, name, device); +} +#else +static inline +int hdd_firmware_request_nowarn(const struct firmware **fw, + const char *name, + struct device *device) +{ + return request_firmware(fw, name, device); +} +#endif + +/** + * hdd_update_mac_config() - update MAC address from cfg file + * @hdd_ctx: the pointer to hdd context + * + * It overwrites the MAC address if config file exist. + * + * Return: QDF_STATUS_SUCCESS if the MAC address is found from cfg file + * and overwritten, otherwise QDF_STATUS_E_INVAL + */ +QDF_STATUS hdd_update_mac_config(struct hdd_context *hdd_ctx) +{ + int status, i = 0; + const struct firmware *fw = NULL; + char *line, *buffer = NULL; + char *temp = NULL; + char *name, *value; + int max_mac_addr = QDF_MAX_CONCURRENCY_PERSONA; + struct hdd_cfg_entry mac_table[QDF_MAX_CONCURRENCY_PERSONA]; + struct qdf_mac_addr custom_mac_addr; + + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (!hdd_ctx->config->read_mac_addr_from_mac_file) { + hdd_debug("Reading MAC address from MAC file is not enabled."); + return QDF_STATUS_E_FAILURE; + } + + memset(mac_table, 0, sizeof(mac_table)); + status = hdd_firmware_request_nowarn(&fw, WLAN_MAC_FILE, + hdd_ctx->parent_dev); + if (status) { + /* + * request_firmware "fails" if the file is not found, which is a + * valid setup for us, so log using debug instead of error + */ + hdd_debug("request_firmware failed; status:%d", status); + return QDF_STATUS_E_FAILURE; + } + + if (!fw || !fw->data || !fw->size) { + hdd_alert("invalid firmware"); + qdf_status = QDF_STATUS_E_INVAL; + goto config_exit; + } + + hdd_debug("wlan_mac.bin size %zu", fw->size); + + temp = qdf_mem_malloc(fw->size + 1); + if (!temp) { + qdf_status = QDF_STATUS_E_NOMEM; + goto config_exit; + } + buffer = temp; + qdf_mem_copy(buffer, fw->data, fw->size); + buffer[fw->size] = 0x0; + + /* data format: + * Intf0MacAddress=00AA00BB00CC + * Intf1MacAddress=00AA00BB00CD + * END + */ + while (buffer) { + line = get_next_line(buffer); + buffer = i_trim(buffer); + + if (strlen((char *)buffer) == 0 || *buffer == '#') { + buffer = line; + continue; + } + if (strncmp(buffer, "END", 3) == 0) + break; + + name = buffer; + buffer = strnchr(buffer, strlen(buffer), '='); + if (buffer) { + *buffer++ = '\0'; + i_trim(name); + if (strlen(name) != 0) { + buffer = i_trim(buffer); + if (strlen(buffer) == 12) { + value = buffer; + mac_table[i].name = name; + mac_table[i++].value = value; + if (i >= QDF_MAX_CONCURRENCY_PERSONA) + break; + } + } + } + buffer = line; + } + + if (i != 0 && i <= QDF_MAX_CONCURRENCY_PERSONA) { + hdd_debug("%d Mac addresses provided", i); + } else { + hdd_err("invalid number of Mac address provided, nMac = %d", i); + qdf_status = QDF_STATUS_E_INVAL; + goto config_exit; + } + + qdf_status = update_mac_from_string(hdd_ctx, &mac_table[0], i); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("Invalid MAC addresses provided"); + goto config_exit; + } + hdd_ctx->num_provisioned_addr = i; + hdd_debug("Populating remaining %d Mac addresses", + max_mac_addr - i); + hdd_populate_random_mac_addr(hdd_ctx, max_mac_addr - i); + + if (hdd_ctx->num_provisioned_addr) + qdf_mem_copy(custom_mac_addr.bytes, + &hdd_ctx->provisioned_mac_addr[0].bytes[0], + sizeof(custom_mac_addr)); + else + qdf_mem_copy(custom_mac_addr.bytes, + &hdd_ctx->derived_mac_addr[0].bytes[0], + sizeof(custom_mac_addr)); + + qdf_status = sme_set_custom_mac_addr(custom_mac_addr.bytes); + +config_exit: + qdf_mem_free(temp); + release_firmware(fw); + return qdf_status; +} +#else +QDF_STATUS hdd_update_mac_config(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * hdd_set_power_save_offload_config() - set power save offload configuration + * @hdd_ctx: the pointer to hdd context + * + * Return: none + */ +static void hdd_set_power_save_offload_config(struct hdd_context *hdd_ctx) +{ + uint32_t listen_interval = 0; + char *power_usage = NULL; + + power_usage = ucfg_mlme_get_power_usage(hdd_ctx->psoc); + if (!power_usage) { + hdd_err("invalid power usage"); + return; + } + + if (strcmp(power_usage, "Min") == 0) + ucfg_mlme_get_bmps_min_listen_interval(hdd_ctx->psoc, + &listen_interval); + else if (strcmp(power_usage, "Max") == 0) + ucfg_mlme_get_bmps_max_listen_interval(hdd_ctx->psoc, + &listen_interval); + /* + * Based on Mode Set the LI + * Otherwise default LI value of 1 will + * be taken + */ + if (listen_interval) { + /* + * setcfg for listenInterval. + * Make sure CFG is updated because PE reads this + * from CFG at the time of assoc or reassoc + */ + ucfg_mlme_set_sap_listen_interval(hdd_ctx->psoc, + listen_interval); + } +} + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_disable_runtime_pm() - Override to disable runtime_pm. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ + cfg_ini->runtime_pm = 0; +} + +/** + * hdd_restore_runtime_pm() - Restore runtime_pm configuration. + * @hdd_ctx: HDD context + * + * Return: None + */ +static void hdd_restore_runtime_pm(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + + cfg_ini->runtime_pm = cfg_get(hdd_ctx->psoc, CFG_ENABLE_RUNTIME_PM); +} +#else +static void hdd_disable_runtime_pm(struct hdd_config *cfg_ini) +{ +} + +static void hdd_restore_runtime_pm(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * hdd_disable_auto_shutdown() - Override to disable auto_shutdown. + * @cfg_ini: Handle to struct hdd_config + * + * Return: None + */ +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ + cfg_ini->wlan_auto_shutdown = 0; +} + +/** + * hdd_restore_auto_shutdown() - Restore auto_shutdown configuration. + * @hdd_ctx: HDD context + * + * Return: None + */ +static void hdd_restore_auto_shutdown(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + + cfg_ini->wlan_auto_shutdown = cfg_get(hdd_ctx->psoc, + CFG_WLAN_AUTO_SHUTDOWN); +} +#else +static void hdd_disable_auto_shutdown(struct hdd_config *cfg_ini) +{ +} + +static void hdd_restore_auto_shutdown(struct hdd_context *hdd_ctx) +{ +} +#endif + +void hdd_restore_all_ps(struct hdd_context *hdd_ctx) +{ + /* + * imps/bmps configuration will be restored in driver mode change + * sequence as part of hdd_wlan_start_modules + */ + + hdd_restore_runtime_pm(hdd_ctx); + hdd_restore_auto_shutdown(hdd_ctx); +} + +void hdd_override_all_ps(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg_ini = hdd_ctx->config; + + ucfg_mlme_override_bmps_imps(hdd_ctx->psoc); + hdd_disable_runtime_pm(cfg_ini); + hdd_disable_auto_shutdown(cfg_ini); +} + +/** + * hdd_cfg_xlate_to_csr_phy_mode() - convert PHY mode + * @dot11Mode: the mode to convert + * + * Convert the configuration PHY mode to CSR PHY mode + * + * Return: the CSR phy mode value + */ +eCsrPhyMode hdd_cfg_xlate_to_csr_phy_mode(enum hdd_dot11_mode dot11Mode) +{ + if (cds_is_sub_20_mhz_enabled()) + return eCSR_DOT11_MODE_abg; + + switch (dot11Mode) { + case (eHDD_DOT11_MODE_abg): + return eCSR_DOT11_MODE_abg; + case (eHDD_DOT11_MODE_11b): + return eCSR_DOT11_MODE_11b; + case (eHDD_DOT11_MODE_11g): + return eCSR_DOT11_MODE_11g; + default: + case (eHDD_DOT11_MODE_11n): + return eCSR_DOT11_MODE_11n; + case (eHDD_DOT11_MODE_11g_ONLY): + return eCSR_DOT11_MODE_11g_ONLY; + case (eHDD_DOT11_MODE_11n_ONLY): + return eCSR_DOT11_MODE_11n_ONLY; + case (eHDD_DOT11_MODE_11b_ONLY): + return eCSR_DOT11_MODE_11b_ONLY; + case (eHDD_DOT11_MODE_11ac_ONLY): + return eCSR_DOT11_MODE_11ac_ONLY; + case (eHDD_DOT11_MODE_11ac): + return eCSR_DOT11_MODE_11ac; + case (eHDD_DOT11_MODE_AUTO): + return eCSR_DOT11_MODE_AUTO; + case (eHDD_DOT11_MODE_11a): + return eCSR_DOT11_MODE_11a; + case (eHDD_DOT11_MODE_11ax_ONLY): + return eCSR_DOT11_MODE_11ax_ONLY; + case (eHDD_DOT11_MODE_11ax): + return eCSR_DOT11_MODE_11ax; +#ifdef WLAN_FEATURE_11BE + case (eHDD_DOT11_MODE_11be): + return eCSR_DOT11_MODE_11be; + case (eHDD_DOT11_MODE_11be_ONLY): + return eCSR_DOT11_MODE_11be_ONLY; +#endif + } + +} + +/** + * hdd_set_idle_ps_config() - set idle power save configuration + * @hdd_ctx: the pointer to hdd context + * @val: the value to configure + * + * Return: QDF_STATUS_SUCCESS if command set correctly, + * otherwise the QDF_STATUS return from SME layer + */ +QDF_STATUS hdd_set_idle_ps_config(struct hdd_context *hdd_ctx, bool val) +{ + QDF_STATUS status; + + hdd_debug("Enter Val %d", val); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_debug("Skipping powersave in FTM"); + return QDF_STATUS_SUCCESS; + } + + if (hdd_ctx->imps_enabled == val) { + hdd_nofl_debug("Already in the requested power state:%d", val); + return QDF_STATUS_SUCCESS; + } + + status = sme_set_idle_powersave_config(val); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Fail to Set Idle PS Config val %d", val); + return status; + } + + hdd_ctx->imps_enabled = val; + + return status; +} + +/** + * hdd_set_fine_time_meas_cap() - set fine timing measurement capability + * @hdd_ctx: HDD context + * + * This function is used to pass fine timing measurement capability coming + * from INI to SME. This function make sure that configure INI is supported + * by the device. Use bit mask to mask out the unsupported capabilities. + * + * Return: None + */ +static void hdd_set_fine_time_meas_cap(struct hdd_context *hdd_ctx) +{ + uint32_t capability = 0; + + ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, &capability); + ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, capability); + hdd_debug("fine time meas capability - Enabled: %04x", capability); +} + +/** + * hdd_set_oem_6g_supported() - set oem 6g support enabled/disable + * @hdd_ctx: HDD context + * + * This function is used to pass oem 6g support enabled/disable value + * coming from INI to SME. This function make sure that configure + * INI is supported by the device. + * + * Return: None + */ +static void hdd_set_oem_6g_supported(struct hdd_context *hdd_ctx) +{ + bool oem_6g_disable = true; + bool is_reg_6g_support, set_wifi_pos_6g_disabled; + + ucfg_mlme_get_oem_6g_supported(hdd_ctx->psoc, &oem_6g_disable); + is_reg_6g_support = wlan_reg_is_6ghz_supported(hdd_ctx->psoc); + set_wifi_pos_6g_disabled = (oem_6g_disable || !is_reg_6g_support); + + /** + * Host uses following truth table to set wifi pos 6Ghz disable in + * ucfg_wifi_pos_set_oem_6g_supported(). + * ----------------------------------------------------------------- + * oem_6g_disable INI value | reg domain 6G support | Disable 6Ghz | + * ----------------------------------------------------------------- + * 1 | 1 | 1 | + * 1 | 0 | 1 | + * 0 | 1 | 0 | + * 0 | 0 | 1 | + * ----------------------------------------------------------------- + */ + ucfg_wifi_pos_set_oem_6g_supported(hdd_ctx->psoc, + set_wifi_pos_6g_disabled); + hdd_debug("oem 6g support is - %s", + set_wifi_pos_6g_disabled ? "Disabled" : "Enabled"); +} + +/** + * hdd_convert_string_to_array() - used to convert string into u8 array + * @str: String to be converted + * @array: Array where converted value is stored + * @len: Length of the populated array + * @array_max_len: Maximum length of the array + * @to_hex: true, if conversion required for hex string + * + * This API is called to convert string (each byte separated by + * a comma) into an u8 array + * + * Return: QDF_STATUS + */ + +static QDF_STATUS hdd_convert_string_to_array(char *str, uint8_t *array, + uint8_t *len, uint16_t array_max_len, bool to_hex) +{ + char *format, *s = str; + + if (!str || !array || !len) + return QDF_STATUS_E_INVAL; + + format = (to_hex) ? "%02x" : "%d"; + + *len = 0; + while ((s) && (*len < array_max_len)) { + int val; + /* Increment length only if sscanf successfully extracted + * one element. Any other return value means error. + * Ignore it. + */ + if (sscanf(s, format, &val) == 1) { + array[*len] = (uint8_t) val; + *len += 1; + } + + s = strpbrk(s, ","); + if (s) + s++; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_string_to_u8_array(char *str, uint8_t *array, + uint8_t *len, uint16_t array_max_len) +{ + return hdd_convert_string_to_array(str, array, len, + array_max_len, false); +} + +/** + * hdd_hex_string_to_u16_array() - convert a hex string to a uint16 array + * @str: input string + * @int_array: pointer to input array of type uint16 + * @len: pointer to number of elements which the function adds to the array + * @int_array_max_len: maximum number of elements in input uint16 array + * + * This function is used to convert a space separated hex string to an array of + * uint16_t. For example, an input string str = "a b c d" would be converted to + * a unint16 array, int_array = {0xa, 0xb, 0xc, 0xd}, *len = 4. + * This assumes that input value int_array_max_len >= 4. + * + * Return: QDF_STATUS_SUCCESS - if the conversion is successful + * non zero value - if the conversion is a failure + */ +QDF_STATUS hdd_hex_string_to_u16_array(char *str, + uint16_t *int_array, uint8_t *len, uint8_t int_array_max_len) +{ + char *s = str; + uint32_t val = 0; + + if (!str || !int_array || !len) + return QDF_STATUS_E_INVAL; + + hdd_debug("str %pK intArray %pK intArrayMaxLen %d", + s, int_array, int_array_max_len); + + *len = 0; + + while ((s) && (*len < int_array_max_len)) { + /* + * Increment length only if sscanf successfully extracted one + * element. Any other return value means error. Ignore it. + */ + if (sscanf(s, "%x", &val) == 1) { + int_array[*len] = (uint16_t) val; + hdd_debug("s %pK val %x intArray[%d]=0x%x", + s, val, *len, int_array[*len]); + *len += 1; + } + s = strpbrk(s, " "); + if (s) + s++; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_update_config_cfg() - API to update INI setting based on hw/fw caps + * @hdd_ctx: pointer to hdd_ctx + * + * This API reads the cfg file which is updated with hardware/firmware + * capabilities and intersect it with INI setting provided by user. After + * taking intersection it adjust cfg it self. For example, if user has enabled + * RX LDPC through INI but hardware/firmware doesn't support it then disable + * it in CFG file here. + * + * Return: true or false based on outcome. + */ +bool hdd_update_config_cfg(struct hdd_context *hdd_ctx) +{ + bool status = true; + + /* + * During the initialization both 2G and 5G capabilities should be same. + * So read 5G HT capability and update 2G and 5G capabilities. + */ + + if (0 != hdd_update_he_cap_in_cfg(hdd_ctx)) { + status = false; + hdd_err("Couldn't set HE CAP in cfg"); + } + + return status; +} + +/** + * hdd_set_policy_mgr_user_cfg() -initializes the policy manager + * configuration parameters + * + * @hdd_ctx: the pointer to hdd context + * + * Return: QDF_STATUS_SUCCESS if configuration is correctly applied, + * otherwise the appropriate QDF_STATUS would be returned + */ +QDF_STATUS hdd_set_policy_mgr_user_cfg(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct policy_mgr_user_cfg *user_cfg; + + user_cfg = qdf_mem_malloc(sizeof(*user_cfg)); + if (!user_cfg) + return QDF_STATUS_E_NOMEM; + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, + &user_cfg->enable2x2); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + user_cfg->sub_20_mhz_enabled = cds_is_sub_20_mhz_enabled(); + status = policy_mgr_set_user_cfg(hdd_ctx->psoc, user_cfg); + qdf_mem_free(user_cfg); + + return status; +} + +enum wmm_user_mode hdd_to_csr_wmm_mode(uint8_t mode) +{ + switch (mode) { + case HDD_WMM_USER_MODE_QBSS_ONLY: + return WMM_USER_MODE_QBSS_ONLY; + case HDD_WMM_USER_MODE_NO_QOS: + return WMM_USER_MODE_NO_QOS; + case HDD_WMM_USER_MODE_AUTO: + default: + return WMM_USER_MODE_AUTO; + } +} + +static QDF_STATUS +hdd_set_sme_cfgs_related_to_plcy_mgr(struct hdd_context *hdd_ctx, + struct sme_config_params *sme_cfg) +{ + uint8_t mcc_to_scc_switch = 0, is_force_1x1 = 0, allow_diff_bi = 0; + uint8_t conc_rule1 = 0, conc_rule2 = 0, sta_cxn_5g = 0; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_mcc_scc_switch(hdd_ctx->psoc, + &mcc_to_scc_switch)) { + hdd_err("can't get mcc to scc switch"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.cc_switch_mode = mcc_to_scc_switch; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_conc_rule1(hdd_ctx->psoc, + &conc_rule1)) { + hdd_err("can't get conc rule1"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.conc_custom_rule1 = conc_rule1; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_conc_rule2(hdd_ctx->psoc, + &conc_rule2)) { + hdd_err("can't get conc rule2"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.conc_custom_rule2 = conc_rule2; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_sta_cxn_5g_band(hdd_ctx->psoc, + &sta_cxn_5g)) { + hdd_err("can't get conc rule2"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.is_sta_connection_in_5gz_enabled = sta_cxn_5g; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_force_1x1(hdd_ctx->psoc, + &is_force_1x1)) { + hdd_err("can't get force 1x1 flag"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.is_force_1x1 = is_force_1x1; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_allow_mcc_go_diff_bi(hdd_ctx->psoc, + &allow_diff_bi)) { + hdd_err("can't get allow mcc go diff BI flag"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.fAllowMCCGODiffBI = allow_diff_bi; + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +static QDF_STATUS hdd_set_sap_mcc_chnl_avoid(struct sme_config_params *sme_cfg, + uint8_t val) +{ + sme_cfg->csr_config.sap_channel_avoidance = val; + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS hdd_set_sap_mcc_chnl_avoid(struct sme_config_params *sme_cfg, + uint8_t val) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static +QDF_STATUS hdd_set_sme_cfgs_related_to_mlme(struct hdd_context *hdd_ctx, + struct sme_config_params *sme_cfg) +{ + QDF_STATUS status; + uint8_t wmm_mode = 0, enable_mcc = 0, sap_mcc_avoid = 0; + uint8_t mcc_rts_cts = 0, mcc_bcast_prob_rsp = 0; + uint32_t mcast_mcc_rest_time = 0; + bool b80211e_enabled = 0; + + status = ucfg_mlme_get_80211e_is_enabled(hdd_ctx->psoc, + &b80211e_enabled); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get b80211e_enabled failed"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.Is11eSupportEnabled = b80211e_enabled; + + status = ucfg_mlme_get_wmm_mode(hdd_ctx->psoc, &wmm_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get wmm_mode failed"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.WMMSupportMode = hdd_to_csr_wmm_mode(wmm_mode); + hdd_debug("wmm_mode=%d 802_11e_enabled=%d", wmm_mode, b80211e_enabled); + + status = ucfg_mlme_get_mcc_feature(hdd_ctx->psoc, &enable_mcc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ucfg_mlme_get_mcc_feature fail, use def"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.fEnableMCCMode = enable_mcc; + + status = ucfg_mlme_get_mcc_rts_cts_prot(hdd_ctx->psoc, &mcc_rts_cts); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ucfg_mlme_get_mcc_rts_cts_prot fail, use def"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.mcc_rts_cts_prot_enable = mcc_rts_cts; + + status = ucfg_mlme_get_mcc_bcast_prob_resp(hdd_ctx->psoc, + &mcc_bcast_prob_rsp); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ucfg_mlme_get_mcc_bcast_prob_resp fail, use def"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.mcc_bcast_prob_resp_enable = mcc_bcast_prob_rsp; + + status = ucfg_mlme_get_sta_miracast_mcc_rest_time(hdd_ctx->psoc, + &mcast_mcc_rest_time); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ucfg_mlme_get_sta_miracast_mcc_rest_time, use def"); + return QDF_STATUS_E_FAILURE; + } + sme_cfg->csr_config.f_sta_miracast_mcc_rest_time_val = + mcast_mcc_rest_time; + status = ucfg_mlme_get_sap_mcc_chnl_avoid(hdd_ctx->psoc, + &sap_mcc_avoid); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ucfg_mlme_get_sap_mcc_chnl_avoid, use def"); + return QDF_STATUS_E_FAILURE; + } + status = hdd_set_sap_mcc_chnl_avoid(sme_cfg, sap_mcc_avoid); + + return status; +} + +/** + * hdd_set_sme_config() -initializes the sme configuration parameters + * + * @hdd_ctx: the pointer to hdd context + * + * Return: QDF_STATUS_SUCCESS if configuration is correctly applied, + * otherwise the appropriate QDF_STATUS would be returned + */ +QDF_STATUS hdd_set_sme_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sme_config_params *sme_config; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + bool roam_scan_enabled; + bool enable_dfs_scan = true; + bool disconnect_nud; + uint32_t channel_bonding_mode; + +#ifdef FEATURE_WLAN_ESE + bool ese_enabled; +#endif + struct hdd_config *config = hdd_ctx->config; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(hdd_ctx->psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) + return QDF_STATUS_E_NOMEM; + + /* Config params obtained from the registry + * To Do: set regulatory information here + */ + sme_config->csr_config.phyMode = + hdd_cfg_xlate_to_csr_phy_mode(config->dot11Mode); + + if (config->dot11Mode == eHDD_DOT11_MODE_abg || + config->dot11Mode == eHDD_DOT11_MODE_11b || + config->dot11Mode == eHDD_DOT11_MODE_11g || + config->dot11Mode == eHDD_DOT11_MODE_11b_ONLY || + config->dot11Mode == eHDD_DOT11_MODE_11g_ONLY) { + sme_config->csr_config.channelBondingMode24GHz = 0; + sme_config->csr_config.channelBondingMode5GHz = 0; + } else { + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode); + sme_config->csr_config.channelBondingMode24GHz = + channel_bonding_mode; + ucfg_mlme_get_channel_bonding_5ghz(hdd_ctx->psoc, + &channel_bonding_mode); + sme_config->csr_config.channelBondingMode5GHz = + channel_bonding_mode; + } + /* Remaining config params not obtained from registry + * On RF EVB beacon using channel 1. + */ + /* This param cannot be configured from INI */ + sme_config->csr_config.send_smps_action = true; + sme_config->csr_config.ProprietaryRatesEnabled = 0; + sme_config->csr_config.HeartbeatThresh50 = 40; + ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc, + &enable_dfs_scan); + sme_config->csr_config.fEnableDFSChnlScan = enable_dfs_scan; + sme_config->csr_config.Csr11dinfo.Channels.numChannels = 0; + hdd_set_power_save_offload_config(hdd_ctx); + +#ifdef FEATURE_WLAN_ESE + ucfg_mlme_is_ese_enabled(hdd_ctx->psoc, &ese_enabled); + if (ese_enabled) + ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, true); +#endif + + ucfg_mlme_is_roam_scan_offload_enabled(hdd_ctx->psoc, + &roam_scan_enabled); + + if (!roam_scan_enabled) { + /* Disable roaming in concurrency if roam scan + * offload is disabled + */ + ucfg_mlme_set_fast_roam_in_concurrency_enabled( + hdd_ctx->psoc, false); + } + + /* Update maximum interfaces information */ + sme_config->csr_config.max_intf_count = hdd_ctx->max_intf_count; + + hdd_set_fine_time_meas_cap(hdd_ctx); + hdd_set_oem_6g_supported(hdd_ctx); + + cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs); + + mlme_obj->cfg.lfr.rso_user_config.policy_params.dfs_mode = + STA_ROAM_POLICY_DFS_ENABLED; + mlme_obj->cfg.lfr.rso_user_config.policy_params.skip_unsafe_channels = 0; + + disconnect_nud = ucfg_dp_is_disconect_after_roam_fail(hdd_ctx->psoc); + mlme_obj->cfg.lfr.disconnect_on_nud_roam_invoke_fail = disconnect_nud; + + status = hdd_set_sme_cfgs_related_to_mlme(hdd_ctx, sme_config); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("hdd_set_sme_cfgs_related_to_mlme() fail: %d", status); + status = hdd_set_sme_cfgs_related_to_plcy_mgr(hdd_ctx, sme_config); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("hdd_set_sme_cfgs_related_to_plcy_mgr fail: %d", + status); + hdd_debug("dot11Mode=%d", config->dot11Mode); + status = sme_update_config(mac_handle, sme_config); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("sme_update_config() failure: %d", status); + + qdf_mem_free(sme_config); + return status; +} + +/** + * hdd_cfg_get_global_config() - get the configuration table + * @hdd_ctx: pointer to hdd context + * @buf: buffer to store the configuration + * @buflen: size of the buffer + * + * Return: none + */ +void hdd_cfg_get_global_config(struct hdd_context *hdd_ctx, char *buf, + int buflen) +{ + ucfg_cfg_store_print(hdd_ctx->psoc); + + snprintf(buf, buflen, + "WLAN configuration written to debug log"); +} + +/** + * hdd_cfg_print_global_config() - print the configuration table + * @hdd_ctx: pointer to hdd context + * + * Return: none + */ +void hdd_cfg_print_global_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = ucfg_cfg_store_print(hdd_ctx->psoc); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to log cfg ini"); +} + +/** + * hdd_get_pmkid_modes() - returns PMKID mode bits + * @hdd_ctx: the pointer to hdd context + * @pmkid_modes: struct to update with current PMKID modes + * + * Return: value of pmkid_modes + */ +void hdd_get_pmkid_modes(struct hdd_context *hdd_ctx, + struct pmkid_mode_bits *pmkid_modes) +{ + uint32_t cur_pmkid_modes; + QDF_STATUS status; + + status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc, &cur_pmkid_modes); + if (status != QDF_STATUS_SUCCESS) + hdd_err("get pmkid modes fail"); + + pmkid_modes->fw_okc = (cur_pmkid_modes & + CFG_PMKID_MODES_OKC) ? 1 : 0; + pmkid_modes->fw_pmksa_cache = (cur_pmkid_modes & + CFG_PMKID_MODES_PMKSA_CACHING) ? 1 : 0; +} + +static void +hdd_populate_vdev_nss(struct wlan_mlme_nss_chains *user_cfg, + uint8_t tx_nss, + uint8_t rx_nss, + enum nss_chains_band_info band) +{ + user_cfg->rx_nss[band] = rx_nss; + user_cfg->tx_nss[band] = tx_nss; +} + +static QDF_STATUS hdd_set_nss_params(struct wlan_hdd_link_info *link_info, + uint8_t tx_nss, uint8_t rx_nss) +{ + enum nss_chains_band_info band; + struct wlan_mlme_nss_chains user_cfg; + mac_handle_t mac_handle; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_vdev *vdev; + + qdf_mem_zero(&user_cfg, sizeof(user_cfg)); + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(hdd_ctx->pdev, + link_info->vdev_id, + WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL %d", link_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + /* For STA tx/rx nss value is updated at the time of connection, + * for SAP case nss values will not get update, so can skip check + * for SAP/P2P_GO mode. + */ + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE && + (tx_nss > wlan_vdev_mlme_get_nss(vdev) || + rx_nss > wlan_vdev_mlme_get_nss(vdev))) { + hdd_err("Given tx nss/rx nss is greater than intersected nss = %d", + wlan_vdev_mlme_get_nss(vdev)); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return QDF_STATUS_E_FAILURE; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) + hdd_populate_vdev_nss(&user_cfg, tx_nss, rx_nss, band); + if (QDF_IS_STATUS_ERROR( + sme_nss_chains_update(mac_handle, &user_cfg, + link_info->vdev_id))) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +static void hdd_update_nss_in_vdev(struct wlan_hdd_link_info *link_info, + mac_handle_t mac_handle, uint8_t tx_nss, + uint8_t rx_nss) +{ + uint8_t band, max_supp_nss = MAX_VDEV_NSS; + struct wlan_objmgr_vdev *vdev; + struct hdd_adapter *adapter = link_info->adapter; + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; + band++) { + /* This API will change the global ini in mlme cfg */ + sme_update_nss_in_mlme_cfg(mac_handle, rx_nss, tx_nss, + adapter->device_mode, band); + /* + * This API will change the vdev nss params in mac + * context + */ + sme_update_vdev_type_nss(mac_handle, max_supp_nss, band); + } + /* + * This API will change the ini and dynamic nss params in + * mlme vdev priv obj. + */ + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return; + + hdd_store_nss_chains_cfg_in_vdev(adapter->hdd_ctx, vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); +} + +static void hdd_set_sap_nss_params(struct wlan_hdd_link_info *link_info, + mac_handle_t mac_handle, + uint8_t tx_nss, uint8_t rx_nss) +{ + hdd_update_nss_in_vdev(link_info, mac_handle, tx_nss, rx_nss); + hdd_restart_sap(link_info); +} + +/** + * hdd_get_sap_rx_nss() - get the sap rx nss + * @link_info: Pointer to link_info + * @rx_nss: pointer to rx_nss + * + * get the sap tx nss + * + * Return: None + */ +static QDF_STATUS +hdd_get_sap_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + mac_handle_t mac_handle; + uint8_t vdev_nss; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_debug("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + operating_band = hdd_get_sap_operating_band_by_link_info(link_info); + if (operating_band == BAND_UNKNOWN) + return QDF_STATUS_E_INVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band); + if (hdd_ctx->dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_debug("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + switch (operating_band) { + case BAND_2G: + *rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ]; + break; + default: + hdd_debug("Band %d Not 2G or 5G", operating_band); + break; + } + } else { + *rx_nss = vdev_nss; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_sap_tx_nss() - get the sap tx nss + * @link_info: Pointer of link_info + * @tx_nss: pointer to tx_nss + * + * get the sap tx nss + * + * Return: None + */ +static QDF_STATUS +hdd_get_sap_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + mac_handle_t mac_handle; + uint8_t vdev_nss; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_debug("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + operating_band = hdd_get_sap_operating_band_by_link_info(link_info); + if (operating_band == BAND_UNKNOWN) + return QDF_STATUS_E_INVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + sme_get_sap_vdev_type_nss(mac_handle, &vdev_nss, operating_band); + if (hdd_ctx->dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_debug("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + switch (operating_band) { + case BAND_2G: + *tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ]; + break; + default: + hdd_debug("Band %d Not 2G or 5G", operating_band); + break; + } + } else { + *tx_nss = vdev_nss; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return QDF_STATUS_SUCCESS; +} + +static bool +hdd_get_sap_restart_required_for_nss(struct wlan_hdd_link_info *link_info, + uint8_t tx_nss, uint8_t rx_nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint8_t rx_prev, tx_prev; + bool restart_sap = 0; + + ucfg_mlme_get_restart_sap_on_dynamic_nss_chains_cfg(hdd_ctx->psoc, + &restart_sap); + + if (!restart_sap) + return false; + + hdd_get_sap_rx_nss(link_info, &rx_prev); + hdd_get_sap_tx_nss(link_info, &tx_prev); + + if (rx_prev != rx_nss && tx_prev != tx_nss) + return true; + return false; +} + +QDF_STATUS hdd_update_nss(struct wlan_hdd_link_info *link_info, + uint8_t tx_nss, uint8_t rx_nss) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t rx_supp_data_rate, tx_supp_data_rate; + bool status = true; + QDF_STATUS qdf_status; + qdf_size_t val_len; + struct mlme_ht_capabilities_info ht_cap_info; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET] = {0}; + uint8_t mcs_set_temp[SIZE_OF_SUPPORTED_MCS_SET]; + uint8_t enable2x2; + mac_handle_t mac_handle; + bool bval = 0, restart_sap = 0; + + if ((tx_nss == 2 || rx_nss == 2) && (hdd_ctx->num_rf_chains != 2)) { + hdd_err("No support for 2 spatial streams"); + return QDF_STATUS_E_INVAL; + } + + if (tx_nss > MAX_VDEV_NSS || rx_nss > MAX_VDEV_NSS) { + hdd_debug("Cannot support tx_nss: %d rx_nss: %d", tx_nss, + rx_nss); + return QDF_STATUS_E_INVAL; + } + + qdf_status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("unable to get vht_enable2x2"); + return QDF_STATUS_E_FAILURE; + } + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + /* + * If FW is supporting the dynamic nss update, this command is meant to + * be per vdev, so update only the ini params of that particular vdev + * and not the global param enable2x2 + */ + if (hdd_ctx->dynamic_nss_chains_support) { + restart_sap = + hdd_get_sap_restart_required_for_nss(link_info, tx_nss, rx_nss); + + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && restart_sap) { + if ((tx_nss == 2 && rx_nss == 2) || + (tx_nss == 1 && rx_nss == 1)) { + hdd_set_sap_nss_params(link_info, mac_handle, + tx_nss, rx_nss); + return QDF_STATUS_SUCCESS; + } + hdd_err("tx_nss %d rx_nss %d not supported ", + tx_nss, rx_nss); + return QDF_STATUS_E_FAILURE; + } + + if (hdd_is_vdev_in_conn_state(link_info)) + return hdd_set_nss_params(link_info, tx_nss, rx_nss); + + if (tx_nss != rx_nss) { + hdd_err("TX NSS = %d, RX NSS = %d value mismatch, doesn't support asymmetric config in disconnected state", + tx_nss, rx_nss); + return QDF_STATUS_E_FAILURE; + } + hdd_debug("Vdev %d in disconnect state, changing ini nss params", + link_info->vdev_id); + if (!bval) { + hdd_err("Nss in 1x1, no change required, 2x2 mode disabled"); + return QDF_STATUS_SUCCESS; + } + + hdd_update_nss_in_vdev(link_info, mac_handle, tx_nss, rx_nss); + sme_set_nss_capability(mac_handle, link_info->vdev_id, + rx_nss, adapter->device_mode); + + return QDF_STATUS_SUCCESS; + } + + /* + * The code below is executed only when fw doesn't support dynamic + * update of nss and chains per vdev feature, for the upcoming + * connection + */ + enable2x2 = (rx_nss == 2) ? 1 : 0; + + if (bval == enable2x2) { + hdd_debug("NSS same as requested"); + return QDF_STATUS_SUCCESS; + } + + if (sme_is_any_session_in_connected_state(mac_handle)) { + hdd_err("Connected sessions present, Do not change NSS"); + return QDF_STATUS_E_INVAL; + } + + qdf_status = ucfg_mlme_set_vht_enable2x2(hdd_ctx->psoc, enable2x2); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to set vht_enable2x2"); + return QDF_STATUS_E_FAILURE; + } + + if (tx_nss == 1 && rx_nss == 2) { + /* 1x2 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } else if (enable2x2) { + /* 2x2 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + } else { + /* 1x1 */ + rx_supp_data_rate = VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + tx_supp_data_rate = VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + + /* Update Rx Highest Long GI data Rate */ + qdf_status = + ucfg_mlme_cfg_set_vht_rx_supp_data_rate(hdd_ctx->psoc, + rx_supp_data_rate); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to set rx_supp_data_rate"); + status = false; + } + /* Update Tx Highest Long GI data Rate */ + qdf_status = + ucfg_mlme_cfg_set_vht_tx_supp_data_rate(hdd_ctx->psoc, + tx_supp_data_rate); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to set tx_supp_data_rate"); + status = false; + } + + qdf_status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, &ht_cap_info); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to get HT Cap info"); + goto skip_ht_cap_update; + } + + if (!(hdd_ctx->ht_tx_stbc_supported && enable2x2)) { + ht_cap_info.tx_stbc = 0; + } else { + qdf_status = + ucfg_mlme_cfg_get_vht_tx_stbc(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to get vht_tx_stbc"); + ht_cap_info.tx_stbc = bval; + } + } + + qdf_status = ucfg_mlme_set_ht_cap_info(hdd_ctx->psoc, ht_cap_info); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Could not set the HT_CAP_INFO"); + } +skip_ht_cap_update: + qdf_status = ucfg_mlme_update_nss_vht_cap(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to set update_nss_vht_cap"); + status = false; + } + +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + val_len = SIZE_OF_SUPPORTED_MCS_SET; + qdf_status = ucfg_mlme_get_supported_mcs_set(hdd_ctx->psoc, + mcs_set_temp, + &val_len); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + mcs_set[0] = mcs_set_temp[0]; + if (enable2x2) + for (val_len = 0; val_len < rx_nss; val_len++) + mcs_set[val_len] = + WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + if (ucfg_mlme_set_supported_mcs_set( + hdd_ctx->psoc, mcs_set, + (qdf_size_t)SIZE_OF_SUPPORTED_MCS_SET) == + QDF_STATUS_E_FAILURE) { + status = false; + hdd_err("Could not pass on MCS SET to CFG"); + } + } else { + status = false; + hdd_err("Could not get MCS SET from CFG"); + } + sme_set_nss_capability(mac_handle, link_info->vdev_id, + rx_nss, adapter->device_mode); +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES + + if (QDF_STATUS_SUCCESS != sme_update_nss(mac_handle, rx_nss)) + status = false; + + hdd_set_policy_mgr_user_cfg(hdd_ctx); + + return (status == false) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_get_nss(struct hdd_adapter *adapter, uint8_t *nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool bval; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* + * If FW is supporting the dynamic nss update, this command is meant to + * be per vdev, so get nss in the ini params of that particular vdev + * otherwise get it from the global param enable2x2 + */ + if (hdd_ctx->dynamic_nss_chains_support) { + uint8_t nss_2g, nss_5g; + + sme_get_vdev_type_nss(adapter->device_mode, &nss_2g, &nss_5g); + /* Different settings in 2G and 5G is not supported */ + *nss = nss_2g; + } else { + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("unable to get vht_enable2x2"); + return status; + } + + *nss = (bval) ? 2 : 1; + if (!policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc) && + policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc)) + *nss = *nss - 1; + } + + return status; +} + +/** + * hdd_get_sap_num_tx_chains() - get the sap num tx chains + * @link_info: Pointer of link_info + * @tx_chains: pointer to tx_chains + * + * get the sap num tx chains + * + * Return: None + */ +static QDF_STATUS +hdd_get_sap_num_tx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *tx_chains) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_debug("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + operating_band = hdd_get_sap_operating_band_by_link_info(link_info); + if (operating_band == BAND_UNKNOWN) + return QDF_STATUS_E_INVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + if (hdd_ctx->dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_debug("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + switch (operating_band) { + case BAND_2G: + *tx_chains = + dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *tx_chains = + dynamic_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]; + break; + default: + hdd_debug("Band %d Not 2G or 5G", operating_band); + break; + } + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_sta_num_tx_chains() - get the sta num tx chains + * @link_info: Pointer of link_info + * @tx_chains: pointer to tx_chains + * + * get the STA num tx chains + * + * Return: None + */ +static QDF_STATUS +hdd_get_sta_num_tx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *tx_chains) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = ucfg_mlme_get_sta_num_tx_chains(hdd_ctx->psoc, vdev, + tx_chains); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get sta_tx_nss"); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return status; +} + +/** + * hdd_get_sta_tx_nss() - get the sta tx nss + * @link_info: Pointer of link_info + * @tx_nss: pointer to tx_nss + * + * get the STA tx nss + * + * Return: None + */ +static QDF_STATUS +hdd_get_sta_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = ucfg_mlme_get_sta_tx_nss(hdd_ctx->psoc, vdev, tx_nss); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get sta_tx_nss"); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return status; +} + +QDF_STATUS hdd_get_num_tx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *tx_chains) +{ + struct hdd_adapter *adapter = link_info->adapter; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + status = hdd_get_sap_num_tx_chains(link_info, tx_chains); + else + status = hdd_get_sta_num_tx_chains(link_info, tx_chains); + + return status; +} + +QDF_STATUS hdd_get_tx_nss(struct wlan_hdd_link_info *link_info, uint8_t *tx_nss) +{ + struct hdd_adapter *adapter = link_info->adapter; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + status = hdd_get_sap_tx_nss(link_info, tx_nss); + else + status = hdd_get_sta_tx_nss(link_info, tx_nss); + + return status; +} + +/** + * hdd_get_sap_num_rx_chains() - get the sap num rx chains + * @link_info: Pointer to link_info + * @rx_chains: pointer to rx_chains + * + * get the sap num rx chains + * + * Return: None + */ +static QDF_STATUS +hdd_get_sap_num_rx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *rx_chains) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + struct wlan_mlme_nss_chains *dynamic_cfg; + enum band_info operating_band; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_debug("NULL MAC handle"); + return QDF_STATUS_E_INVAL; + } + + operating_band = hdd_get_sap_operating_band_by_link_info(link_info); + if (operating_band == BAND_UNKNOWN) + return QDF_STATUS_E_INVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + if (hdd_ctx->dynamic_nss_chains_support) { + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_debug("nss chain dynamic config NULL"); + return QDF_STATUS_E_INVAL; + } + switch (operating_band) { + case BAND_2G: + *rx_chains = + dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + *rx_chains = + dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ]; + break; + default: + hdd_debug("Band %d Not 2G or 5G", operating_band); + break; + } + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_sta_num_rx_chains() - get the sta num rx chains + * @link_info: Pointer to link_info in adapter + * @rx_chains: pointer to rx_chains + * + * get the STA num rx chains + * + * Return: QDF_STATUS_SUCCESS if the RX NSS is returned, otherwise a suitable + * QDF_STATUS_E_* error code + */ +static QDF_STATUS +hdd_get_sta_num_rx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *rx_chains) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = ucfg_mlme_get_sta_num_rx_chains(hdd_ctx->psoc, vdev, + rx_chains); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get sta_rx_nss"); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return status; +} + +/** + * hdd_get_sta_rx_nss() - get the sta rx nss + * @link_info: Pointer to link_info in adapter + * @rx_nss: pointer to rx_nss + * + * get the STA rx nss + * + * Return: QDF_STATUS_SUCCESS if the RX NSS is returned, otherwise a suitable + * QDF_STATUS_E_* error code + */ +static QDF_STATUS +hdd_get_sta_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = wlan_mlme_get_sta_rx_nss(hdd_ctx->psoc, vdev, rx_nss); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get sta_rx_nss"); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return status; +} + +QDF_STATUS hdd_get_num_rx_chains(struct wlan_hdd_link_info *link_info, + uint8_t *rx_chains) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter = link_info->adapter; + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + status = hdd_get_sap_num_rx_chains(link_info, rx_chains); + else + status = hdd_get_sta_num_rx_chains(link_info, rx_chains); + + return status; +} + +QDF_STATUS hdd_get_rx_nss(struct wlan_hdd_link_info *link_info, uint8_t *rx_nss) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter = link_info->adapter; + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + status = hdd_get_sap_rx_nss(link_info, rx_nss); + else + status = hdd_get_sta_rx_nss(link_info, rx_nss); + + return status; +} + +int hdd_phymode_to_vendor_mode(eCsrPhyMode csr_phy_mode, + enum qca_wlan_vendor_phy_mode *vendor_phy_mode) +{ + switch (csr_phy_mode) { + case eCSR_DOT11_MODE_AUTO: + case eCSR_DOT11_MODE_11be: + case eCSR_DOT11_MODE_11be_ONLY: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_AUTO; + break; + case eCSR_DOT11_MODE_11a: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11A; + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11B; + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11G; + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11AGN; + break; + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160; + break; + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + *vendor_phy_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160; + break; + case eCSR_DOT11_MODE_abg: + default: + hdd_err("Not supported mode %d", csr_phy_mode); + return -EINVAL; + } + + return 0; +} + +int hdd_vendor_mode_to_phymode(enum qca_wlan_vendor_phy_mode vendor_phy_mode, + eCsrPhyMode *csr_phy_mode) +{ + switch (vendor_phy_mode) { + case QCA_WLAN_VENDOR_PHY_MODE_AUTO: + case QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO: + case QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO: + *csr_phy_mode = eCSR_DOT11_MODE_AUTO; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11A: + *csr_phy_mode = eCSR_DOT11_MODE_11a; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11B: + *csr_phy_mode = eCSR_DOT11_MODE_11b; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11G: + *csr_phy_mode = eCSR_DOT11_MODE_11g; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AGN: + *csr_phy_mode = eCSR_DOT11_MODE_11n; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: + *csr_phy_mode = eCSR_DOT11_MODE_11ac; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: + *csr_phy_mode = eCSR_DOT11_MODE_11ax; + break; + default: + hdd_err("Not supported mode %d", vendor_phy_mode); + return -EINVAL; + } + + return 0; +} + +int hdd_vendor_mode_to_band(enum qca_wlan_vendor_phy_mode vendor_phy_mode, + uint8_t *supported_band, bool is_6ghz_supported) +{ + switch (vendor_phy_mode) { + case QCA_WLAN_VENDOR_PHY_MODE_AUTO: + if (is_6ghz_supported) + *supported_band = REG_BAND_MASK_ALL; + else + *supported_band = + BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: + *supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: + case QCA_WLAN_VENDOR_PHY_MODE_11AGN: + if (is_6ghz_supported) + *supported_band = REG_BAND_MASK_ALL; + else + *supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + break; + case QCA_WLAN_VENDOR_PHY_MODE_11A: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO: + *supported_band = BIT(REG_BAND_5G); + break; + case QCA_WLAN_VENDOR_PHY_MODE_11B: + case QCA_WLAN_VENDOR_PHY_MODE_11G: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO: + *supported_band = BIT(REG_BAND_2G); + break; + default: + hdd_err("Not supported mode %d", vendor_phy_mode); + return -EINVAL; + } + + return 0; +} + +int +hdd_vendor_mode_to_bonding_mode(enum qca_wlan_vendor_phy_mode vendor_phy_mode, + uint32_t *bonding_mode) +{ + switch (vendor_phy_mode) { + case QCA_WLAN_VENDOR_PHY_MODE_AUTO: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: + case QCA_WLAN_VENDOR_PHY_MODE_2G_AUTO: + case QCA_WLAN_VENDOR_PHY_MODE_5G_AUTO: + case QCA_WLAN_VENDOR_PHY_MODE_11AGN: + *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11A: + case QCA_WLAN_VENDOR_PHY_MODE_11B: + case QCA_WLAN_VENDOR_PHY_MODE_11G: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: + *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + break; + default: + hdd_err("Not supported mode %d", vendor_phy_mode); + return -EINVAL; + } + + return 0; +} + +int hdd_phymode_to_dot11_mode(eCsrPhyMode phymode, + enum hdd_dot11_mode *dot11_mode) +{ + switch (phymode) { + case eCSR_DOT11_MODE_AUTO: + case eCSR_DOT11_MODE_11be: + *dot11_mode = eHDD_DOT11_MODE_AUTO; + break; + case eCSR_DOT11_MODE_11a: + *dot11_mode = eHDD_DOT11_MODE_11a; + break; + case eCSR_DOT11_MODE_11b: + *dot11_mode = eHDD_DOT11_MODE_11b; + break; + case eCSR_DOT11_MODE_11g: + *dot11_mode = eHDD_DOT11_MODE_11g; + break; + case eCSR_DOT11_MODE_11n: + *dot11_mode = eHDD_DOT11_MODE_11n; + break; + case eCSR_DOT11_MODE_11ac: + *dot11_mode = eHDD_DOT11_MODE_11ac; + break; + case eCSR_DOT11_MODE_11ax: + *dot11_mode = eHDD_DOT11_MODE_11ax; + break; + default: + hdd_err("Not supported mode %d", phymode); + return -EINVAL; + } + + return 0; +} + +#ifdef QCA_HT_2040_COEX +static QDF_STATUS +hdd_set_ht2040_mode(struct hdd_adapter *adapter, + struct csr_config_params *csr_config, + uint32_t bonding_mode) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (csr_config->phyMode == eCSR_DOT11_MODE_11n) { + if (bonding_mode == WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) + csr_config->obssEnabled = true; + else + csr_config->obssEnabled = false; + status = sme_set_ht2040_mode(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + eHT_CHAN_HT20, + csr_config->obssEnabled); + } + + return status; +} +#else +static QDF_STATUS +hdd_set_ht2040_mode(struct hdd_adapter *adapter, + struct csr_config_params *csr_config, + uint32_t bonding_mode) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +int hdd_update_phymode(struct hdd_adapter *adapter, eCsrPhyMode phymode, + uint8_t supported_band, uint32_t bonding_mode) +{ + struct net_device *net = adapter->dev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sme_config_params *sme_config = NULL; + struct csr_config_params *csr_config; + eCsrPhyMode old_phymode; + enum hdd_dot11_mode hdd_dot11mode; + int ret = 0; + QDF_STATUS status; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret < 0) + return ret; + + ret = hdd_phymode_to_dot11_mode(phymode, &hdd_dot11mode); + if (ret < 0) + return ret; + + hdd_debug("phymode=%d bonding_mode=%d supported_band=%d", + phymode, bonding_mode, supported_band); + + old_phymode = sme_get_phy_mode(hdd_ctx->mac_handle); + + sme_set_phy_mode(hdd_ctx->mac_handle, phymode); + + if (hdd_reg_set_band(net, supported_band)) { + sme_set_phy_mode(hdd_ctx->mac_handle, old_phymode); + return -EIO; + } + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) + return -ENOMEM; + + sme_get_config_param(hdd_ctx->mac_handle, sme_config); + csr_config = &sme_config->csr_config; + csr_config->phyMode = phymode; + + status = hdd_set_ht2040_mode(adapter, csr_config, bonding_mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set ht2040 mode"); + ret = -EIO; + goto free; + } + + status = ucfg_mlme_set_band_capability(hdd_ctx->psoc, supported_band); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to set MLME band capability"); + ret = -EIO; + goto free; + } + + if (supported_band == BIT(REG_BAND_2G)) { + status = ucfg_mlme_set_11h_enabled(hdd_ctx->psoc, 0); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to set 11h_enable flag"); + ret = -EIO; + goto free; + } + } + if (supported_band & BIT(REG_BAND_2G)) + csr_config->channelBondingMode24GHz = bonding_mode; + + if (supported_band & BIT(REG_BAND_5G)) + csr_config->channelBondingMode5GHz = bonding_mode; + + sme_update_config(hdd_ctx->mac_handle, sme_config); + + hdd_ctx->config->dot11Mode = hdd_dot11mode; + ucfg_mlme_set_channel_bonding_24ghz(hdd_ctx->psoc, + csr_config->channelBondingMode24GHz); + ucfg_mlme_set_channel_bonding_5ghz(hdd_ctx->psoc, + csr_config->channelBondingMode5GHz); + if (hdd_update_config_cfg(hdd_ctx) == false) { + hdd_err("could not update config_dat"); + ret = -EIO; + goto free; + } + + if (supported_band & BIT(REG_BAND_5G)) { + struct ieee80211_supported_band *ieee_band; + uint32_t channel_bonding_mode; + + ucfg_mlme_get_channel_bonding_5ghz(hdd_ctx->psoc, + &channel_bonding_mode); + ieee_band = hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]; + if (channel_bonding_mode) + ieee_band->ht_cap.cap |= + IEEE80211_HT_CAP_SUP_WIDTH_20_40; + else + ieee_band->ht_cap.cap &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + } + +free: + if (sme_config) + qdf_mem_free(sme_config); + return ret; +} + +int hdd_get_ldpc(struct hdd_adapter *adapter, int *value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id, + WNI_CFG_HT_CAP_INFO_ADVANCE_CODING); + if (ret < 0) { + hdd_err("Failed to get LDPC value"); + } else { + *value = ret; + ret = 0; + } + return ret; +} + +int hdd_set_ldpc(struct wlan_hdd_link_info *link_info, int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int ret; + QDF_STATUS status; + struct mlme_ht_capabilities_info ht_cap_info; + + hdd_debug("%d", value); + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, &ht_cap_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get HT capability info"); + return -EIO; + } + + ht_cap_info.adv_coding_cap = value; + status = ucfg_mlme_set_ht_cap_info(hdd_ctx->psoc, ht_cap_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set HT capability info"); + return -EIO; + } + status = ucfg_mlme_cfg_set_vht_ldpc_coding_cap(hdd_ctx->psoc, value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set VHT LDPC capability info"); + return -EIO; + } + ret = sme_update_ht_config(mac_handle, link_info->vdev_id, + WNI_CFG_HT_CAP_INFO_ADVANCE_CODING, value); + if (ret) + hdd_err("Failed to set LDPC value"); + ret = sme_update_he_ldpc_supp(mac_handle, + link_info->vdev_id, value); + if (ret) + hdd_err("Failed to set HE LDPC value"); + ret = sme_set_auto_rate_ldpc(mac_handle, link_info->vdev_id, + (value ? 0 : 1)); + + return ret; +} + +int hdd_get_tx_stbc(struct hdd_adapter *adapter, int *value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id, + WNI_CFG_HT_CAP_INFO_TX_STBC); + if (ret < 0) { + hdd_err("Failed to get TX STBC value"); + } else { + *value = ret; + ret = 0; + } + + return ret; +} + +int hdd_set_tx_stbc(struct wlan_hdd_link_info *link_info, int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int ret; + QDF_STATUS status; + struct mlme_ht_capabilities_info ht_cap_info; + + hdd_debug("%d", value); + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + if (value) { + /* make sure HT capabilities allow this */ + status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, + &ht_cap_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get HT capability info"); + return -EIO; + } + if (!ht_cap_info.tx_stbc) { + hdd_err("TX STBC not supported"); + return -EINVAL; + } + } + ret = sme_update_ht_config(mac_handle, link_info->vdev_id, + WNI_CFG_HT_CAP_INFO_TX_STBC, + value); + if (ret) + hdd_err("Failed to set TX STBC value"); + ret = sme_update_he_tx_stbc_cap(mac_handle, + link_info->vdev_id, value); + if (ret) + hdd_err("Failed to set HE TX STBC value"); + + return ret; +} + +int hdd_get_rx_stbc(struct hdd_adapter *adapter, int *value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id, + WNI_CFG_HT_CAP_INFO_RX_STBC); + if (ret < 0) { + hdd_err("Failed to get RX STBC value"); + } else { + *value = ret; + ret = 0; + } + + return ret; +} + +int hdd_set_rx_stbc(struct wlan_hdd_link_info *link_info, int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int ret; + QDF_STATUS status; + struct mlme_ht_capabilities_info ht_cap_info; + + hdd_debug("%d", value); + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + if (value) { + /* make sure HT capabilities allow this */ + status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, + &ht_cap_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get HT capability info"); + return -EIO; + } + if (!ht_cap_info.rx_stbc) { + hdd_warn("RX STBC not supported"); + return -EINVAL; + } + } + ret = sme_update_ht_config(mac_handle, link_info->vdev_id, + WNI_CFG_HT_CAP_INFO_RX_STBC, + value); + if (ret) + hdd_err("Failed to set RX STBC value"); + + ret = sme_update_he_rx_stbc_cap(mac_handle, + link_info->vdev_id, value); + if (ret) + hdd_err("Failed to set HE RX STBC value"); + + return ret; +} + +/** + * hdd_convert_chwidth_to_phy_chwidth() - convert channel width of type enum + * eSirMacHTChannelWidth to enum phy_ch_width + * @chwidth: channel width of type enum eSirMacHTChannelWidth + * + * Return: channel width of type enum phy_ch_width + */ +static enum phy_ch_width +hdd_convert_chwidth_to_phy_chwidth(enum eSirMacHTChannelWidth chwidth) +{ + enum phy_ch_width ch_width = CH_WIDTH_INVALID; + + switch (chwidth) { + case eHT_CHANNEL_WIDTH_20MHZ: + ch_width = CH_WIDTH_20MHZ; + break; + case eHT_CHANNEL_WIDTH_40MHZ: + ch_width = CH_WIDTH_40MHZ; + break; + case eHT_CHANNEL_WIDTH_80MHZ: + ch_width = CH_WIDTH_80MHZ; + break; + case eHT_CHANNEL_WIDTH_160MHZ: + ch_width = CH_WIDTH_160MHZ; + break; + case eHT_CHANNEL_WIDTH_80P80MHZ: + ch_width = CH_WIDTH_80P80MHZ; + break; + case eHT_CHANNEL_WIDTH_320MHZ: + ch_width = CH_WIDTH_320MHZ; + break; + default: + hdd_debug("Invalid channel width %d", chwidth); + break; + } + + return ch_width; +} + +/** + * hdd_update_bss_rate_flags() - update bss rate flag as per new channel width + * @link_info: Link info in HDD adapter + * @psoc: psoc common object + * @cw: channel width for which bss rate flag being updated + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_update_bss_rate_flags(struct wlan_hdd_link_info *link_info, + struct wlan_objmgr_psoc *psoc, enum phy_ch_width cw) +{ + struct hdd_station_ctx *hdd_sta_ctx; + uint8_t eht_present, he_present, vht_present, ht_present; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + eht_present = hdd_sta_ctx->conn_info.conn_flag.eht_present; + he_present = hdd_sta_ctx->conn_info.conn_flag.he_present; + vht_present = hdd_sta_ctx->conn_info.conn_flag.vht_present; + ht_present = hdd_sta_ctx->conn_info.conn_flag.ht_present; + + return ucfg_mlme_update_bss_rate_flags(psoc, link_info->vdev_id, + cw, eht_present, he_present, + vht_present, ht_present); +} + +/** + * struct sme_config_msg_ctx - sme config update message ctx + * @vdev: vdev object + * @chwidth: channel width + * @is_restore: restore default or not + * @bonding_mode: bonding mode + */ +struct sme_config_msg_ctx { + struct wlan_objmgr_vdev *vdev; + enum eSirMacHTChannelWidth chwidth; + bool is_restore; + uint32_t bonding_mode; +}; + +/** + * hdd_restore_sme_config_cb() - restore bonding mode sme config cb + * @msg: msg data + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_restore_sme_config_cb(struct scheduler_msg *msg) +{ + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + struct sme_config_params *sme_config = NULL; + struct sme_config_msg_ctx *sme_config_msg_ctx = NULL; + struct wlan_objmgr_vdev *vdev = NULL; + uint8_t vdev_id; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!msg) { + hdd_debug("msg is null"); + return QDF_STATUS_E_INVAL; + } + + sme_config_msg_ctx = msg->bodyptr; + if (!sme_config_msg_ctx) { + hdd_debug("bodyptr is null"); + return QDF_STATUS_E_INVAL; + } + + vdev = sme_config_msg_ctx->vdev; + if (!vdev) + goto end; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx)) + goto end; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + goto end; + + if (!hdd_ctx->psoc) + goto end; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) + goto end; + + vdev_id = wlan_vdev_get_id(vdev); + hdd_debug("vdev id %d is_restore %d bonding_mode %d chwdith %d", + vdev_id, + sme_config_msg_ctx->is_restore, + sme_config_msg_ctx->bonding_mode, + sme_config_msg_ctx->chwidth); + sme_get_config_param(mac_handle, sme_config); + if (sme_config_msg_ctx->is_restore) { + sme_config->csr_config.channelBondingMode5GHz = + cfg_get(hdd_ctx->psoc, CFG_CHANNEL_BONDING_MODE_5GHZ); + sme_config->csr_config.channelBondingMode24GHz = + cfg_get(hdd_ctx->psoc, CFG_CHANNEL_BONDING_MODE_24GHZ); + } else { + sme_config->csr_config.channelBondingMode5GHz = + sme_config_msg_ctx->bonding_mode; + sme_config->csr_config.channelBondingMode24GHz = + sme_config_msg_ctx->bonding_mode; + } + sme_update_config(mac_handle, sme_config); + sme_set_he_bw_cap(hdd_ctx->mac_handle, vdev_id, + sme_config_msg_ctx->chwidth); + sme_set_eht_bw_cap(hdd_ctx->mac_handle, vdev_id, + sme_config_msg_ctx->chwidth); + + status = QDF_STATUS_SUCCESS; +end: + qdf_mem_free(sme_config); + if (vdev) + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + qdf_mem_free(sme_config_msg_ctx); + + return status; +} + +/** + * hdd_restore_sme_config_flush_cb() - bonding mode sme config flush cb + * @msg: msg data + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_restore_sme_config_flush_cb(struct scheduler_msg *msg) +{ + struct sme_config_msg_ctx *sme_config_msg_ctx; + + if (!msg) { + hdd_debug("msg is null"); + return QDF_STATUS_E_INVAL; + } + + sme_config_msg_ctx = msg->bodyptr; + if (!sme_config_msg_ctx) { + hdd_debug("bodyptr is null"); + return QDF_STATUS_E_INVAL; + } + + if (sme_config_msg_ctx->vdev) + hdd_objmgr_put_vdev_by_user(sme_config_msg_ctx->vdev, + WLAN_HDD_ID_OBJ_MGR); + else + hdd_debug("vdev is null"); + + qdf_mem_free(sme_config_msg_ctx); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_restore_sme_config() - restore bonding mode for sme config + * @link_info: link info + * @chwidth: channel width + * @is_restore: msg data + * @bonding_mode: bonding mode + * + * Return: void + */ +static void hdd_restore_sme_config(struct wlan_hdd_link_info *link_info, + enum eSirMacHTChannelWidth chwidth, + bool is_restore, uint32_t bonding_mode) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct sme_config_msg_ctx *sme_config_msg_ctx; + + sme_config_msg_ctx = qdf_mem_malloc(sizeof(*sme_config_msg_ctx)); + if (!sme_config_msg_ctx) + return; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + qdf_mem_free(sme_config_msg_ctx); + hdd_debug("no vdev from link info"); + return; + } + + sme_config_msg_ctx->vdev = vdev; + sme_config_msg_ctx->chwidth = chwidth; + sme_config_msg_ctx->is_restore = is_restore; + sme_config_msg_ctx->bonding_mode = bonding_mode; + msg.bodyptr = sme_config_msg_ctx; + msg.callback = hdd_restore_sme_config_cb; + msg.flush_callback = hdd_restore_sme_config_flush_cb; + + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("status %d", status); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + qdf_mem_free(sme_config_msg_ctx); + } +} + +/** + * wlan_update_mlo_link_chn_width() - API to update mlo link chn width + * @adapter: the pointer to adapter + * @ch_width: channel width to update + * @link_id: mlo link id + * + * Get link id and channel bandwidth from user space and save in link_info. + * When link switch happen and host driver connect done, if the link change + * from standby to non-standby, ch_width will send to fw again. + * + * Return: QDF_STATUS + */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static struct wlan_hdd_link_info * +wlan_update_mlo_link_chn_width(struct hdd_adapter *adapter, + enum phy_ch_width ch_width, + uint8_t link_id) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + link_info = hdd_get_link_info_by_ieee_link_id(adapter, link_id); + if (!link_info) + return NULL; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + sta_ctx->user_cfg_chn_width = ch_width; + hdd_debug("save ch_width:%u to link_id:%u vdev_id:%u", + ch_width, link_id, link_info->vdev_id); + + return link_info; +} +#else +static struct wlan_hdd_link_info * +wlan_update_mlo_link_chn_width(struct hdd_adapter *adapter, + enum phy_ch_width ch_width, + uint8_t link_id) +{ + return NULL; +} +#endif + +int hdd_update_channel_width(struct wlan_hdd_link_info *link_info, + enum eSirMacHTChannelWidth chwidth, + uint32_t bonding_mode, uint8_t link_id, + bool is_restore) +{ + struct hdd_context *hdd_ctx; + int ret; + enum phy_ch_width ch_width; + struct wlan_objmgr_vdev *link_vdev; + struct wlan_objmgr_vdev *vdev; + struct wlan_hdd_link_info *link_info_t; + uint8_t link_vdev_id; + enum QDF_OPMODE op_mode; + QDF_STATUS status; + uint8_t vdev_id = link_info->vdev_id; + enum phy_ch_width new_ch_width; + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx failure"); + return -EINVAL; + } + + op_mode = link_info->adapter->device_mode; + if (op_mode != QDF_STA_MODE) { + hdd_debug("vdev %d: op mode %d, CW update not supported", + vdev_id, op_mode); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("vdev %d: vdev not found", vdev_id); + return -EINVAL; + } + + ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth); + + /** + * Link_id check is for disconnect restore process. + * Disconnect will not update channel bandwidth into cache struct. + */ + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + link_id != WLAN_INVALID_LINK_ID) { + link_info_t = wlan_update_mlo_link_chn_width(link_info->adapter, + ch_width, link_id); + if (!link_info_t) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return -EINVAL; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + link_vdev = hdd_objmgr_get_vdev_by_user(link_info_t, + WLAN_OSIF_ID); + if (!link_vdev) + return 0; + + link_vdev_id = link_info_t->vdev_id; + status = wlan_mlme_get_bw_no_punct(hdd_ctx->psoc, + link_vdev, + wlan_vdev_mlme_get_des_chan(link_vdev), + &new_ch_width); + if (QDF_IS_STATUS_SUCCESS(status) && ch_width > new_ch_width) + ch_width = new_ch_width; + } else { + link_vdev = vdev; + link_vdev_id = vdev_id; + link_info_t = link_info; + } + + if (ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc) && + hdd_cm_is_vdev_connected(link_info_t)) { + ch_width = hdd_convert_chwidth_to_phy_chwidth(chwidth); + hdd_debug("vdev %d : process update ch width request to %d", + link_vdev_id, ch_width); + status = ucfg_mlme_send_ch_width_update_with_notify(hdd_ctx->psoc, + link_vdev, + ch_width, + link_vdev_id); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID); + return -EIO; + } + status = hdd_update_bss_rate_flags(link_info_t, hdd_ctx->psoc, + ch_width); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID); + return -EIO; + } + + hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID); + return 0; + } + hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID); + + ret = wma_cli_set_command(link_vdev_id, wmi_vdev_param_chwidth, + chwidth, VDEV_CMD); + if (ret) + return ret; + + hdd_restore_sme_config(link_info_t, chwidth, is_restore, bonding_mode); + + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c new file mode 100644 index 0000000000..035fef7733 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c @@ -0,0 +1,30082 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_cfg80211.c + * + * WLAN Host Device Driver cfg80211 APIs implementation + * + */ + +#include +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include "sir_params.h" +#include "dot11f.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_wext.h" +#include "sme_api.h" +#include "sme_power_save_api.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_hdd_softap_tx_rx.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_tx_rx.h" +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "qdf_net_if.h" +#include "cds_utils.h" +#include "cds_sched.h" +#include "wlan_hdd_scan.h" +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_wmm.h" +#include "wma_types.h" +#include "wma.h" +#include "wma_twt.h" +#include "wlan_hdd_misc.h" +#include "wlan_hdd_nan.h" +#include "wlan_logging_sock_svc.h" +#include "sap_api.h" +#include "csr_api.h" +#include "pld_common.h" +#include "wmi_unified_param.h" + +#include +#include +#include + +#include "wlan_hdd_ext_scan.h" + +#include "wlan_hdd_stats.h" +#include "cds_api.h" +#include "wlan_policy_mgr_api.h" +#include "qwlan_version.h" + +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_tsf.h" + +#include "sap_internal.h" + +#include "wlan_hdd_green_ap.h" + +#include "wlan_hdd_subnet_detect.h" +#include +#include "wlan_hdd_lpass.h" +#include "wlan_hdd_nan_datapath.h" +#include "wlan_hdd_disa.h" +#include "wlan_osif_request_manager.h" +#include "wlan_hdd_he.h" +#ifdef FEATURE_WLAN_APF +#include "wlan_hdd_apf.h" +#endif +#include "wlan_hdd_fw_state.h" +#include "wlan_hdd_mpta_helper.h" + +#include +#include +#include +#include "wlan_pmo_ucfg_api.h" +#include "os_if_wifi_pos.h" +#include "wlan_utility.h" +#include "wlan_reg_ucfg_api.h" +#include "wifi_pos_api.h" +#include "wlan_hdd_spectralscan.h" +#include "wlan_ipa_ucfg_api.h" +#include +#include +#include "wlan_tdls_cfg_api.h" +#include "wlan_tdls_ucfg_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_twt_ucfg_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_extscan_ucfg_api.h" +#include "wlan_pmo_cfg.h" +#include "cfg_ucfg_api.h" + +#include "wlan_crypto_def_i.h" +#include "wlan_crypto_global_api.h" +#include "wlan_nl_to_crypto_params.h" +#include "wlan_crypto_global_def.h" +#include "cdp_txrx_cfg.h" +#include "wlan_hdd_object_manager.h" +#include "nan_ucfg_api.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_cfg80211_crypto.h" +#include "wlan_cfg80211_interop_issues_ap.h" +#include "wlan_scan_ucfg_api.h" +#include "wlan_hdd_coex_config.h" +#include "wlan_hdd_bcn_recv.h" +#include "wlan_hdd_connectivity_logging.h" +#include "wlan_dlm_ucfg_api.h" +#include "wlan_hdd_hw_capability.h" +#include "wlan_hdd_oemdata.h" +#include "os_if_fwol.h" +#include "wlan_hdd_sta_info.h" +#include "sme_api.h" +#include "wlan_hdd_thermal.h" +#include +#include "wlan_hdd_btc_chain_mode.h" +#include "os_if_nan.h" +#include "wlan_hdd_apf.h" +#include "wlan_hdd_cfr.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_cm_roam_ucfg_api.h" +#include "hif.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_hdd_afc.h" +#include "wlan_hdd_twt.h" +#include "wlan_hdd_gpio.h" +#include "wlan_hdd_medium_assess.h" +#include "wlan_if_mgr_ucfg_api.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_wfa_ucfg_api.h" +#include "wifi_pos_ucfg_i.h" +#include +#include +#include "wlan_hdd_bootup_marker.h" +#include "wlan_hdd_cm_api.h" +#include "wlan_roam_debug.h" +#include "wlan_hdd_avoid_freq_ext.h" +#include "qdf_util.h" +#include "wlan_hdd_mdns_offload.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include "wifi_pos_public_struct.h" +#include "wifi_pos_pasn_api.h" +#include "os_if_pkt_capture.h" +#include "os_if_dp_local_pkt_capture.h" +#include "wlan_hdd_son.h" +#include "wlan_hdd_mcc_quota.h" +#include "wlan_hdd_peer_txq_flush.h" +#include "wlan_cfg80211_wifi_pos.h" +#include "wlan_osif_features.h" +#include "wlan_hdd_wifi_pos_pasn.h" +#include "wlan_coex_ucfg_api.h" +#include "wlan_coex_public_structs.h" +#include "wlan_dp_ucfg_api.h" +#include "os_if_dp.h" +#include "os_if_dp_lro.h" +#include "wlan_mlo_mgr_sta.h" +#include +#include "wlan_hdd_coap.h" +#include "wlan_hdd_tdls.h" +#include "wlan_psoc_mlme_api.h" +#include +#include "wlan_mlo_mgr_roam.h" +#include "wlan_hdd_mlo.h" +#include +#include "wlan_epcs_api.h" +#include "wlan_mlo_epcs_ucfg_api.h" +#include +#include +#include +#include "wlan_cp_stats_mc_defs.h" +#include "wlan_policy_mgr_ll_sap.h" + +/* + * A value of 100 (milliseconds) can be sent to FW. + * FW would enable Tx beamforming based on this. + */ +#define TX_BFER_NDP_PERIODICITY 100 + +#define g_mode_rates_size (12) +#define a_mode_rates_size (8) + +#define WLAN_WAIT_WLM_LATENCY_LEVEL 1000 + +/* + * BIT map values for vdev_param_set_profile + * bit 0: 0 - XR SAP profile disabled + * 1 - XR SAP profile enabled + * bit 1: 0 - XPAN profile disabled + * 1 - XPAN profile enabled + */ +#define AP_PROFILE_XR_ENABLE 0x1 +#define AP_PROFILE_XPAN_ENABLE 0x2 + +/** + * rtt_is_enabled - Macro to check if the bitmap has any RTT roles set + * @bitmap: The bitmap to be checked + */ +#define rtt_is_enabled(bitmap) \ + ((bitmap) & (WMI_FW_STA_RTT_INITR | \ + WMI_FW_STA_RTT_RESPR | \ + WMI_FW_AP_RTT_INITR | \ + WMI_FW_AP_RTT_RESPR)) + +/* + * Android CTS verifier needs atleast this much wait time (in msec) + */ +#define MAX_REMAIN_ON_CHANNEL_DURATION (2000) + +#define HDD2GHZCHAN(freq, chan, flag) { \ + .band = HDD_NL80211_BAND_2GHZ, \ + .center_freq = (freq), \ + .hw_value = (chan), \ + .flags = (flag), \ + .max_antenna_gain = 0, \ + .max_power = 0, \ +} + +#define HDD5GHZCHAN(freq, chan, flag) { \ + .band = HDD_NL80211_BAND_5GHZ, \ + .center_freq = (freq), \ + .hw_value = (chan), \ + .flags = (flag), \ + .max_antenna_gain = 0, \ + .max_power = 0, \ +} + +#define HDD_G_MODE_RATETAB(rate, rate_id, flag) \ + { \ + .bitrate = rate, \ + .hw_value = rate_id, \ + .flags = flag, \ + } + +#define IS_DFS_MODE_VALID(mode) ((mode >= DFS_MODE_NONE && \ + mode <= DFS_MODE_DEPRIORITIZE)) + +#ifndef WLAN_CIPHER_SUITE_GCMP +#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 +#endif +#ifndef WLAN_CIPHER_SUITE_GCMP_256 +#define WLAN_CIPHER_SUITE_GCMP_256 0x000FAC09 +#endif + +/* Default number of Simultaneous Transmit */ +#define DEFAULT_MAX_STR_LINK_COUNT 1 +/* Maximum number of Simultaneous Transmit */ +#define MAX_STR_LINK_COUNT 2 + +static const u32 hdd_gcmp_cipher_suits[] = { + WLAN_CIPHER_SUITE_GCMP, + WLAN_CIPHER_SUITE_GCMP_256, +}; + +static const u32 hdd_cipher_suites[] = { + WLAN_CIPHER_SUITE_WEP40, + WLAN_CIPHER_SUITE_WEP104, + WLAN_CIPHER_SUITE_TKIP, +#ifdef FEATURE_WLAN_ESE +#define WLAN_CIPHER_SUITE_BTK 0x004096fe /* use for BTK */ +#define WLAN_CIPHER_SUITE_KRK 0x004096ff /* use for KRK */ + WLAN_CIPHER_SUITE_BTK, + WLAN_CIPHER_SUITE_KRK, + WLAN_CIPHER_SUITE_CCMP, +#else + WLAN_CIPHER_SUITE_CCMP, +#endif +#ifdef FEATURE_WLAN_WAPI + WLAN_CIPHER_SUITE_SMS4, +#endif + WLAN_CIPHER_SUITE_AES_CMAC, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) + WLAN_CIPHER_SUITE_BIP_GMAC_128, + WLAN_CIPHER_SUITE_BIP_GMAC_256, +#endif +}; + +static const struct ieee80211_channel hdd_channels_2_4_ghz[] = { + HDD2GHZCHAN(2412, 1, 0), + HDD2GHZCHAN(2417, 2, 0), + HDD2GHZCHAN(2422, 3, 0), + HDD2GHZCHAN(2427, 4, 0), + HDD2GHZCHAN(2432, 5, 0), + HDD2GHZCHAN(2437, 6, 0), + HDD2GHZCHAN(2442, 7, 0), + HDD2GHZCHAN(2447, 8, 0), + HDD2GHZCHAN(2452, 9, 0), + HDD2GHZCHAN(2457, 10, 0), + HDD2GHZCHAN(2462, 11, 0), + HDD2GHZCHAN(2467, 12, 0), + HDD2GHZCHAN(2472, 13, 0), + HDD2GHZCHAN(2484, 14, 0), +}; + +static const struct ieee80211_channel hdd_channels_5_ghz[] = { + HDD5GHZCHAN(5180, 36, 0), + HDD5GHZCHAN(5200, 40, 0), + HDD5GHZCHAN(5220, 44, 0), + HDD5GHZCHAN(5240, 48, 0), + HDD5GHZCHAN(5260, 52, 0), + HDD5GHZCHAN(5280, 56, 0), + HDD5GHZCHAN(5300, 60, 0), + HDD5GHZCHAN(5320, 64, 0), + HDD5GHZCHAN(5500, 100, 0), + HDD5GHZCHAN(5520, 104, 0), + HDD5GHZCHAN(5540, 108, 0), + HDD5GHZCHAN(5560, 112, 0), + HDD5GHZCHAN(5580, 116, 0), + HDD5GHZCHAN(5600, 120, 0), + HDD5GHZCHAN(5620, 124, 0), + HDD5GHZCHAN(5640, 128, 0), + HDD5GHZCHAN(5660, 132, 0), + HDD5GHZCHAN(5680, 136, 0), + HDD5GHZCHAN(5700, 140, 0), + HDD5GHZCHAN(5720, 144, 0), + HDD5GHZCHAN(5745, 149, 0), + HDD5GHZCHAN(5765, 153, 0), + HDD5GHZCHAN(5785, 157, 0), + HDD5GHZCHAN(5805, 161, 0), + HDD5GHZCHAN(5825, 165, 0), +}; + +#ifdef WLAN_FEATURE_DSRC +static const struct ieee80211_channel hdd_channels_dot11p[] = { + HDD5GHZCHAN(5852, 170, 0), + HDD5GHZCHAN(5855, 171, 0), + HDD5GHZCHAN(5860, 172, 0), + HDD5GHZCHAN(5865, 173, 0), + HDD5GHZCHAN(5870, 174, 0), + HDD5GHZCHAN(5875, 175, 0), + HDD5GHZCHAN(5880, 176, 0), + HDD5GHZCHAN(5885, 177, 0), + HDD5GHZCHAN(5890, 178, 0), + HDD5GHZCHAN(5895, 179, 0), + HDD5GHZCHAN(5900, 180, 0), + HDD5GHZCHAN(5905, 181, 0), + HDD5GHZCHAN(5910, 182, 0), + HDD5GHZCHAN(5915, 183, 0), + HDD5GHZCHAN(5920, 184, 0), +}; +#else +static const struct ieee80211_channel hdd_5dot9_ghz_ch[] = { + HDD5GHZCHAN(5845, 169, 0), + HDD5GHZCHAN(5865, 173, 0), + HDD5GHZCHAN(5885, 177, 0), +}; +#endif + +#define band_2_ghz_channels_size sizeof(hdd_channels_2_4_ghz) + +#ifdef WLAN_FEATURE_DSRC +#define band_5_ghz_channels_size (sizeof(hdd_channels_5_ghz) + \ + sizeof(hdd_channels_dot11p)) +#else +#define band_5_ghz_channels_size (sizeof(hdd_channels_5_ghz) + \ + sizeof(hdd_5dot9_ghz_ch)) +#endif + +static struct ieee80211_rate g_mode_rates[] = { + HDD_G_MODE_RATETAB(10, 0x1, 0), + HDD_G_MODE_RATETAB(20, 0x2, 0), + HDD_G_MODE_RATETAB(55, 0x4, 0), + HDD_G_MODE_RATETAB(110, 0x8, 0), + HDD_G_MODE_RATETAB(60, 0x10, 0), + HDD_G_MODE_RATETAB(90, 0x20, 0), + HDD_G_MODE_RATETAB(120, 0x40, 0), + HDD_G_MODE_RATETAB(180, 0x80, 0), + HDD_G_MODE_RATETAB(240, 0x100, 0), + HDD_G_MODE_RATETAB(360, 0x200, 0), + HDD_G_MODE_RATETAB(480, 0x400, 0), + HDD_G_MODE_RATETAB(540, 0x800, 0), +}; + +static struct ieee80211_rate a_mode_rates[] = { + HDD_G_MODE_RATETAB(60, 0x10, 0), + HDD_G_MODE_RATETAB(90, 0x20, 0), + HDD_G_MODE_RATETAB(120, 0x40, 0), + HDD_G_MODE_RATETAB(180, 0x80, 0), + HDD_G_MODE_RATETAB(240, 0x100, 0), + HDD_G_MODE_RATETAB(360, 0x200, 0), + HDD_G_MODE_RATETAB(480, 0x400, 0), + HDD_G_MODE_RATETAB(540, 0x800, 0), +}; + +static struct ieee80211_supported_band wlan_hdd_band_2_4_ghz = { + .channels = NULL, + .n_channels = ARRAY_SIZE(hdd_channels_2_4_ghz), + .band = HDD_NL80211_BAND_2GHZ, + .bitrates = g_mode_rates, + .n_bitrates = g_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_LSIG_TXOP_PROT + | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, +}; + +static struct ieee80211_supported_band wlan_hdd_band_5_ghz = { + .channels = NULL, + .n_channels = ARRAY_SIZE(hdd_channels_5_ghz), + .band = HDD_NL80211_BAND_5GHZ, + .bitrates = a_mode_rates, + .n_bitrates = a_mode_rates_size, + .ht_cap.ht_supported = 1, + .ht_cap.cap = IEEE80211_HT_CAP_SGI_20 + | IEEE80211_HT_CAP_GRN_FLD + | IEEE80211_HT_CAP_DSSSCCK40 + | IEEE80211_HT_CAP_LSIG_TXOP_PROT + | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40, + .ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K, + .ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, + .ht_cap.mcs.rx_mask = {0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0,}, + .ht_cap.mcs.rx_highest = cpu_to_le16(72), + .ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED, + .vht_cap.vht_supported = 1, +}; + +enum hdd_hw_rate_cck { + HDD_HW_RATE_CCK_LP_11M = 0, + HDD_HW_RATE_CCK_LP_5_5M, + HDD_HW_RATE_CCK_LP_2M, + HDD_HW_RATE_CCK_LP_1M, + HDD_HW_RATE_CCK_SP_11M, + HDD_HW_RATE_CCK_SP_5_5M, + HDD_HW_RATE_CCK_SP_2M, +}; + +enum hdd_hw_rate_ofdm { + HDD_HW_RATE_OFDM_48M = 0, + HDD_HW_RATE_OFDM_24M, + HDD_HW_RATE_OFDM_12M, + HDD_HW_RATE_OFDM_6M, + HDD_HW_RATE_OFDM_54M, + HDD_HW_RATE_OFDM_36M, + HDD_HW_RATE_OFDM_18M, + HDD_HW_RATE_OFDM_9M, +}; + +static struct ieee80211_rate hdd_legacy_rates[] = { + { .bitrate = 10, + .hw_value = HDD_HW_RATE_CCK_LP_1M }, + { .bitrate = 20, + .hw_value = HDD_HW_RATE_CCK_LP_2M }, + { .bitrate = 55, + .hw_value = HDD_HW_RATE_CCK_LP_5_5M }, + { .bitrate = 110, + .hw_value = HDD_HW_RATE_CCK_LP_11M }, + { .bitrate = 60, .hw_value = HDD_HW_RATE_OFDM_6M }, + { .bitrate = 90, .hw_value = HDD_HW_RATE_OFDM_9M }, + { .bitrate = 120, .hw_value = HDD_HW_RATE_OFDM_12M }, + { .bitrate = 180, .hw_value = HDD_HW_RATE_OFDM_18M }, + { .bitrate = 240, .hw_value = HDD_HW_RATE_OFDM_24M }, + { .bitrate = 360, .hw_value = HDD_HW_RATE_OFDM_36M }, + { .bitrate = 480, .hw_value = HDD_HW_RATE_OFDM_48M }, + { .bitrate = 540, .hw_value = HDD_HW_RATE_OFDM_54M }, +}; + +#if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \ + (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)) + +static struct ieee80211_channel hdd_channels_6_ghz[NUM_6GHZ_CHANNELS]; + +static struct ieee80211_supported_band wlan_hdd_band_6_ghz = { + .channels = NULL, + .n_channels = 0, + .band = HDD_NL80211_BAND_6GHZ, + .bitrates = a_mode_rates, + .n_bitrates = a_mode_rates_size, +}; + +#define HDD_SET_6GHZCHAN(ch, freq, chan, flag) { \ + (ch).band = HDD_NL80211_BAND_6GHZ; \ + (ch).center_freq = (freq); \ + (ch).hw_value = (chan); \ + (ch).flags = (flag); \ + (ch).max_antenna_gain = 0; \ + (ch).max_power = 0; \ +} + +static void hdd_init_6ghz(struct hdd_context *hdd_ctx) +{ + uint32_t i; + struct wiphy *wiphy = hdd_ctx->wiphy; + struct ieee80211_channel *chlist = hdd_channels_6_ghz; + uint32_t num = ARRAY_SIZE(hdd_channels_6_ghz); + uint16_t base_freq; + QDF_STATUS status; + uint32_t band_capability; + + hdd_enter(); + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get MLME Band Capability"); + return; + } + + if (!(band_capability & (BIT(REG_BAND_6G)))) { + hdd_debug("6ghz band not enabled"); + return; + } + + qdf_mem_zero(chlist, sizeof(*chlist) * num); + base_freq = wlan_reg_min_6ghz_chan_freq(); + + for (i = 0; i < num; i++) + HDD_SET_6GHZCHAN(chlist[i], + base_freq + i * 20, + wlan_reg_freq_to_chan(hdd_ctx->pdev, + base_freq + i * 20), + IEEE80211_CHAN_DISABLED); + wiphy->bands[HDD_NL80211_BAND_6GHZ] = &wlan_hdd_band_6_ghz; + wiphy->bands[HDD_NL80211_BAND_6GHZ]->channels = chlist; + wiphy->bands[HDD_NL80211_BAND_6GHZ]->n_channels = num; + + hdd_exit(); +} + +/** + * wlan_hdd_populate_6g_chan_info() - Populate 6 GHz chan info in hdd context + * @hdd_ctx: pointer to hdd context + * @index: 6 GHz channel beginning index in chan_info of @hdd_ctx + * + * Return: Number of 6 GHz channels populated + */ +static uint32_t +wlan_hdd_populate_6g_chan_info(struct hdd_context *hdd_ctx, uint32_t index) +{ + uint32_t num_6g, i; + struct scan_chan_info *chan_info; + + if (!hdd_ctx->wiphy->bands[HDD_NL80211_BAND_6GHZ] || + !hdd_ctx->wiphy->bands[HDD_NL80211_BAND_6GHZ]->n_channels) { + hdd_debug("6GHz channel list not populated to wiphy"); + return 0; + } + + num_6g = QDF_ARRAY_SIZE(hdd_channels_6_ghz); + chan_info = hdd_ctx->chan_info; + + for (i = 0; i < num_6g; i++) + chan_info[index + i].freq = hdd_channels_6_ghz[i].center_freq; + + return num_6g; +} + +#else +static void hdd_init_6ghz(struct hdd_context *hdd_ctx) +{ +} + +static inline uint32_t +wlan_hdd_populate_6g_chan_info(struct hdd_context *hdd_ctx, uint32_t index) +{ + return 0; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) || \ + defined(CFG80211_IFTYPE_AKM_SUITES_SUPPORT) +/*akm suits supported by sta*/ +static const u32 hdd_sta_akm_suites[] = { + WLAN_AKM_SUITE_8021X, + WLAN_AKM_SUITE_PSK, + WLAN_AKM_SUITE_FT_8021X, + WLAN_AKM_SUITE_FT_PSK, + WLAN_AKM_SUITE_8021X_SHA256, + WLAN_AKM_SUITE_PSK_SHA256, + WLAN_AKM_SUITE_TDLS, + WLAN_AKM_SUITE_SAE, + WLAN_AKM_SUITE_FT_OVER_SAE, + WLAN_AKM_SUITE_EAP_SHA256, + WLAN_AKM_SUITE_EAP_SHA384, + WLAN_AKM_SUITE_FILS_SHA256, + WLAN_AKM_SUITE_FILS_SHA384, + WLAN_AKM_SUITE_FT_FILS_SHA256, + WLAN_AKM_SUITE_FT_FILS_SHA384, + WLAN_AKM_SUITE_OWE, + WLAN_AKM_SUITE_DPP_RSN, + WLAN_AKM_SUITE_FT_EAP_SHA_384, + RSN_AUTH_KEY_MGMT_CCKM, + RSN_AUTH_KEY_MGMT_OSEN, + WAPI_PSK_AKM_SUITE, + WAPI_CERT_AKM_SUITE, + WLAN_AKM_SUITE_SAE_EXT_KEY, + WLAN_AKM_SUITE_FT_SAE_EXT_KEY, +}; + +/*akm suits supported by AP*/ +static const u32 hdd_ap_akm_suites[] = { + WLAN_AKM_SUITE_PSK, + WLAN_AKM_SUITE_SAE, + WLAN_AKM_SUITE_OWE, +}; + +/* This structure contain information what akm suits are + * supported for each mode + */ +static const struct wiphy_iftype_akm_suites + wlan_hdd_akm_suites[] = { + { + .iftypes_mask = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT), + .akm_suites = hdd_sta_akm_suites, + .n_akm_suites = (sizeof(hdd_sta_akm_suites) / sizeof(u32)), + }, + { + .iftypes_mask = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO), + .akm_suites = hdd_ap_akm_suites, + .n_akm_suites = (sizeof(hdd_ap_akm_suites) / sizeof(u32)), + }, +}; +#endif + +/* This structure contain information what kind of frame are expected in + * TX/RX direction for each kind of interface + */ +static const struct ieee80211_txrx_stypes + wlan_hdd_txrx_stypes[NUM_NL80211_IFTYPES] = { + [NL80211_IFTYPE_STATION] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ACTION) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_AUTH), + }, + [NL80211_IFTYPE_AP] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_ADHOC] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_P2P_CLIENT] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ACTION) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_PROBE_REQ), + }, + [NL80211_IFTYPE_P2P_GO] = { + /* This is also same as for SoftAP */ + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_ASSOC_REQ) | + BIT(SIR_MAC_MGMT_REASSOC_REQ) | + BIT(SIR_MAC_MGMT_PROBE_REQ) | + BIT(SIR_MAC_MGMT_DISASSOC) | + BIT(SIR_MAC_MGMT_AUTH) | + BIT(SIR_MAC_MGMT_DEAUTH) | + BIT(SIR_MAC_MGMT_ACTION), + }, + [NL80211_IFTYPE_NAN] = { + .tx = 0xffff, + .rx = BIT(SIR_MAC_MGMT_AUTH) | BIT(SIR_MAC_MGMT_ACTION), + }, +}; + +/* Interface limits and combinations registered by the driver */ + +/* STA ( + STA ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_iface_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, +}; + +/* AP ( + AP ) combination */ +static const struct ieee80211_iface_limit + wlan_hdd_ap_iface_limit[] = { + { + .max = (QDF_MAX_NO_OF_SAP_MODE), + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +#ifndef WLAN_FEATURE_NO_P2P_CONCURRENCY +/* P2P limit */ +static const struct ieee80211_iface_limit + wlan_hdd_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO), + }, +}; + +/* STA + P2P + P2P combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_p2p_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* Support for two identical (GO + GO or CLI + CLI) + * or dissimilar (GO + CLI) P2P interfaces + */ + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +/* STA + AP + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sta_ap_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + }, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ +}; + +/* SAP + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sap_p2p_iface_limit[] = { + { + /* The p2p interface in SAP+P2P can be GO/CLI. + * The p2p connection can be formed on p2p0 or p2p-p2p0-x. + */ + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, + { + /* SAP+GO to support only one SAP interface */ + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + } +}; + +/* P2P + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_p2p_p2p_iface_limit[] = { + { + /* The p2p interface in P2P+P2P can be GO/CLI. + * For P2P+P2P, the new interfaces are formed on p2p-p2p0-x. + */ + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, +}; +#elif defined(WLAN_FEATURE_STA_SAP_P2P_CONCURRENCY) +/* STA + AP + P2P combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sta_ap_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT) + }, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + }, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ +}; +#endif + +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY +/* STA + AP combination */ +static const struct ieee80211_iface_limit +wlan_hdd_sta_ap_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + }, +}; +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ + +/* STA + P2P combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_p2p_iface_limit[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* Support for either (GO or CLI) */ + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +/* Monitor interface */ +static const struct ieee80211_iface_limit + wlan_hdd_mon_iface_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_MONITOR), + }, +}; + +#if defined(WLAN_FEATURE_NAN) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) +#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY +/* STA + NAN disc combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sta_nan_iface_limit[] = { + { + /* STA */ + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION) + }, + { + /* NAN */ + .max = 1, + .types = BIT(NL80211_IFTYPE_NAN), + }, +}; +#endif /* WLAN_FEATURE_NO_STA_NAN_CONCURRENCY */ + +#ifndef WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY +/* SAP + NAN disc combination */ +static const struct ieee80211_iface_limit + wlan_hdd_sap_nan_iface_limit[] = { + { + /* SAP */ + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) + }, + { + /* NAN */ + .max = 1, + .types = BIT(NL80211_IFTYPE_NAN), + }, +}; +#endif /* !WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY */ +#endif /* WLAN_FEATURE_NAN */ + +static struct ieee80211_iface_combination + wlan_hdd_iface_combination[] = { + /* STA */ + { + .limits = wlan_hdd_sta_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit), + }, + /* AP */ + { + .limits = wlan_hdd_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (QDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_ap_iface_limit), +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) || \ + defined(CFG80211_BEACON_INTERVAL_BACKPORT) + .beacon_int_min_gcd = 1, +#endif + }, +#ifndef WLAN_FEATURE_NO_P2P_CONCURRENCY + /* P2P */ + { + .limits = wlan_hdd_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit), + }, + /* STA + P2P + P2P */ + { + .limits = wlan_hdd_sta_p2p_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 3, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* STA + P2P + SAP */ + { + .limits = wlan_hdd_sta_ap_p2p_iface_limit, + /* we can allow 3 channels for three different persona + * but due to firmware limitation, allow max 2 concrnt channels. + */ + .num_different_channels = 2, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + .max_interfaces = 3, +#else + .max_interfaces = 2, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* SAP + P2P */ + { + .limits = wlan_hdd_sap_p2p_iface_limit, + .num_different_channels = 2, + /* 1-SAP + 1-P2P */ + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* P2P + P2P */ + { + .limits = wlan_hdd_p2p_p2p_iface_limit, + .num_different_channels = 2, + /* 2-P2P */ + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#elif defined(WLAN_FEATURE_STA_SAP_P2P_CONCURRENCY) + /* STA + P2P + SAP */ + { + .limits = wlan_hdd_sta_ap_p2p_iface_limit, + /* we can allow 3 channels for three different persona + * but due to firmware limitation, allow max 2 concrnt channels. + */ + .num_different_channels = 2, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + .max_interfaces = 3, +#else + .max_interfaces = 2, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* WLAN_FEATURE_NO_P2P_CONCURRENCY */ + /* STA + P2P */ + { + .limits = wlan_hdd_sta_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + /* STA + SAP */ + { + .limits = wlan_hdd_sta_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ + /* Monitor */ + { + .limits = wlan_hdd_mon_iface_limit, + .max_interfaces = 2, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit), + }, +#if defined(WLAN_FEATURE_NAN) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) +#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY + /* NAN + STA */ + { + .limits = wlan_hdd_sta_nan_iface_limit, + .max_interfaces = 2, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_nan_iface_limit), + }, +#endif /* WLAN_FEATURE_NO_STA_NAN_CONCURRENCY */ +#ifndef WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY + /* NAN + SAP */ + { + .limits = wlan_hdd_sap_nan_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_nan_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* !WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY */ +#endif /* WLAN_FEATURE_NAN */ +}; + +/* 1 and 2 port concurrencies */ +static struct ieee80211_iface_combination + wlan_hdd_derived_combination[] = { + /* STA */ + { + .limits = wlan_hdd_sta_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_iface_limit), + }, + /* AP */ + { + .limits = wlan_hdd_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = (QDF_MAX_NO_OF_SAP_MODE), + .n_limits = ARRAY_SIZE(wlan_hdd_ap_iface_limit), +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) || \ + defined(CFG80211_BEACON_INTERVAL_BACKPORT) + .beacon_int_min_gcd = 1, +#endif + }, +#ifndef WLAN_FEATURE_NO_P2P_CONCURRENCY + /* P2P */ + { + .limits = wlan_hdd_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit), + }, + + /* SAP + P2P */ + { + .limits = wlan_hdd_sap_p2p_iface_limit, + .num_different_channels = 2, + /* 1-SAP + 1-P2P */ + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* P2P + P2P */ + { + .limits = wlan_hdd_p2p_p2p_iface_limit, + .num_different_channels = 2, + /* 2-P2P */ + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#endif + /* STA + P2P */ + { + .limits = wlan_hdd_sta_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + /* STA + SAP */ + { + .limits = wlan_hdd_sta_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ + /* Monitor */ + { + .limits = wlan_hdd_mon_iface_limit, + .max_interfaces = 2, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit), + }, +#if defined(WLAN_FEATURE_NAN) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) +#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY + /* NAN + STA */ + { + .limits = wlan_hdd_sta_nan_iface_limit, + .max_interfaces = 2, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_nan_iface_limit), + }, +#endif /* WLAN_FEATURE_NO_STA_NAN_CONCURRENCY */ +#ifndef WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY + /* NAN + SAP */ + { + .limits = wlan_hdd_sap_nan_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_nan_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* !WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY */ +#endif /* WLAN_FEATURE_NAN */ +}; + +static struct ieee80211_iface_combination + wlan_hdd_non_dbs_iface_combination[] = { +#ifndef WLAN_FEATURE_NO_P2P_CONCURRENCY + /* P2P */ + { + .limits = wlan_hdd_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_iface_limit), + }, + + /* SAP + P2P */ + { + .limits = wlan_hdd_sap_p2p_iface_limit, + .num_different_channels = 2, + /* 1-SAP + 1-P2P */ + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_p2p_iface_limit), + .beacon_int_infra_match = true, + }, + /* P2P + P2P */ + { + .limits = wlan_hdd_p2p_p2p_iface_limit, + .num_different_channels = 2, + /* 2-P2P */ + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_p2p_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#endif + /* STA + P2P */ + { + .limits = wlan_hdd_sta_p2p_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_p2p_iface_limit), + .beacon_int_infra_match = true, + }, +#ifndef WLAN_FEATURE_NO_STA_SAP_CONCURRENCY + /* STA + SAP */ + { + .limits = wlan_hdd_sta_ap_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_ap_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* WLAN_FEATURE_NO_STA_SAP_CONCURRENCY */ + /* Monitor */ + { + .limits = wlan_hdd_mon_iface_limit, + .max_interfaces = 2, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_mon_iface_limit), + }, +#if defined(WLAN_FEATURE_NAN) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) +#ifndef WLAN_FEATURE_NO_STA_NAN_CONCURRENCY + /* NAN + STA */ + { + .limits = wlan_hdd_sta_nan_iface_limit, + .max_interfaces = 2, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sta_nan_iface_limit), + }, +#endif /* WLAN_FEATURE_NO_STA_NAN_CONCURRENCY */ +#ifndef WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY + /* NAN + SAP */ + { + .limits = wlan_hdd_sap_nan_iface_limit, + .num_different_channels = 2, + .max_interfaces = 2, + .n_limits = ARRAY_SIZE(wlan_hdd_sap_nan_iface_limit), + .beacon_int_infra_match = true, + }, +#endif /* !WLAN_FEATURE_NO_SAP_NAN_CONCURRENCY */ +#endif /* WLAN_FEATURE_NAN */ +}; +static struct cfg80211_ops wlan_hdd_cfg80211_ops; + +#ifdef WLAN_NL80211_TESTMODE +enum wlan_hdd_tm_attr { + WLAN_HDD_TM_ATTR_INVALID = 0, + WLAN_HDD_TM_ATTR_CMD = 1, + WLAN_HDD_TM_ATTR_DATA = 2, + WLAN_HDD_TM_ATTR_STREAM_ID = 3, + WLAN_HDD_TM_ATTR_TYPE = 4, + /* keep last */ + WLAN_HDD_TM_ATTR_AFTER_LAST, + WLAN_HDD_TM_ATTR_MAX = WLAN_HDD_TM_ATTR_AFTER_LAST - 1, +}; + +enum wlan_hdd_tm_cmd { + WLAN_HDD_TM_CMD_WLAN_FTM = 0, + WLAN_HDD_TM_CMD_WLAN_HB = 1, +}; + +#define WLAN_HDD_TM_DATA_MAX_LEN 5000 + +static const struct nla_policy wlan_hdd_tm_policy[WLAN_HDD_TM_ATTR_MAX + 1] = { + [WLAN_HDD_TM_ATTR_CMD] = {.type = NLA_U32}, + [WLAN_HDD_TM_ATTR_DATA] = {.type = NLA_BINARY, + .len = WLAN_HDD_TM_DATA_MAX_LEN}, +}; +#endif /* WLAN_NL80211_TESTMODE */ + +enum wlan_hdd_vendor_ie_access_policy { + WLAN_HDD_VENDOR_IE_ACCESS_NONE = 0, + WLAN_HDD_VENDOR_IE_ACCESS_ALLOW_IF_LISTED, +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support wowlan_support_cfg80211_init = { + .flags = WIPHY_WOWLAN_MAGIC_PKT, + .n_patterns = WOWL_MAX_PTRNS_ALLOWED, + .pattern_min_len = 1, + .pattern_max_len = WOWL_PTRN_MAX_SIZE, +}; +#endif + +/** + * hdd_add_channel_switch_support()- Adds Channel Switch flag if supported + * @flags: Pointer to the flags to Add channel switch flag. + * + * This Function adds Channel Switch support flag, if channel switch is + * supported by kernel. + * Return: void. + */ +#ifdef CHANNEL_SWITCH_SUPPORTED +static inline void hdd_add_channel_switch_support(uint32_t *flags) +{ + *flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; +} +#else +static inline void hdd_add_channel_switch_support(uint32_t *flags) +{ +} +#endif + +#ifdef FEATURE_WLAN_TDLS + +/* TDLS capabilities params */ +#define PARAM_MAX_TDLS_SESSION \ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_MAX_CONC_SESSIONS +#define PARAM_TDLS_FEATURE_SUPPORT \ + QCA_WLAN_VENDOR_ATTR_TDLS_GET_CAPS_FEATURES_SUPPORTED + +/** + * __wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilities. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function provides TDLS capabilities + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int status; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_objmgr_vdev *vdev; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + uint32_t set = 0; + uint32_t max_num_tdls_sta = 0; + bool tdls_support; + bool tdls_external_control; + bool tdls_sleep_sta_enable; + bool tdls_buffer_sta; + bool tdls_off_channel; + bool tdls_fw_wideband_cap; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + (2 * sizeof(u32)) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -EINVAL; + } + + if ((cfg_tdls_get_support_enable(hdd_ctx->psoc, &tdls_support) == + QDF_STATUS_SUCCESS) && !tdls_support) { + hdd_debug("TDLS feature not Enabled or Not supported in FW"); + if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, 0) || + nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, 0)) { + hdd_err("nla put fail"); + goto fail; + } + } else { + cfg_tdls_get_external_control(hdd_ctx->psoc, + &tdls_external_control); + cfg_tdls_get_sleep_sta_enable(hdd_ctx->psoc, + &tdls_sleep_sta_enable); + cfg_tdls_get_buffer_sta_enable(hdd_ctx->psoc, + &tdls_buffer_sta); + cfg_tdls_get_off_channel_enable(hdd_ctx->psoc, + &tdls_off_channel); + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Vdev is null return"); + goto fail; + } + + tdls_fw_wideband_cap = + wlan_cfg80211_tdls_is_fw_wideband_capable(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + set = set | WIFI_TDLS_SUPPORT; + set = set | (tdls_external_control ? + WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT : 0); + set = set | (tdls_off_channel ? + WIFI_TDLS_OFFCHANNEL_SUPPORT : 0); + set = set | (tdls_fw_wideband_cap ? + WIFI_TDLS_WIDER_BW_SUPPORT : 0); + max_num_tdls_sta = cfg_tdls_get_max_peer_count(hdd_ctx->psoc); + + hdd_debug("TDLS Feature supported value %x tdls_max_peer_count:%d", + set, max_num_tdls_sta); + if (nla_put_u32(skb, PARAM_MAX_TDLS_SESSION, + max_num_tdls_sta) || + nla_put_u32(skb, PARAM_TDLS_FEATURE_SUPPORT, set)) { + hdd_err("nla put fail"); + goto fail; + } + } + return wlan_cfg80211_vendor_cmd_reply(skb); +fail: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_tdls_capabilities() - Provide TDLS Capabilities. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function provides TDLS capabilities + * + * Return: 0 on success and errno on failure + */ +static int +wlan_hdd_cfg80211_get_tdls_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_tdls_capabilities(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +static uint8_t hdd_get_bw_offset(uint32_t ch_width) +{ + uint8_t bw_offset = 0; + + if (ch_width == CH_WIDTH_40MHZ) + bw_offset = 1 << BW_40_OFFSET_BIT; + else if (ch_width == CH_WIDTH_20MHZ) + bw_offset = 1 << BW_20_OFFSET_BIT; + + return bw_offset; +} + +#else /* !FEATURE_WLAN_TDLS */ + +static inline uint8_t hdd_get_bw_offset(uint32_t ch_width) +{ + return 0; +} + +#endif /* FEATURE_WLAN_TDLS */ + +/** + * wlan_vendor_bitmap_to_reg_wifi_band_bitmap() - Convert vendor bitmap to + * reg_wifi_band bitmap + * @psoc: PSOC pointer + * @vendor_bitmap: vendor bitmap value coming via vendor command + * + * Return: reg_wifi_band bitmap + */ +static uint32_t +wlan_vendor_bitmap_to_reg_wifi_band_bitmap(struct wlan_objmgr_psoc *psoc, + uint32_t vendor_bitmap) +{ + uint32_t reg_bitmap = 0; + + if (vendor_bitmap == QCA_SETBAND_AUTO) + reg_bitmap |= REG_BAND_MASK_ALL; + if (vendor_bitmap & QCA_SETBAND_2G) + reg_bitmap |= BIT(REG_BAND_2G); + if (vendor_bitmap & QCA_SETBAND_5G) + reg_bitmap |= BIT(REG_BAND_5G); + if (vendor_bitmap & QCA_SETBAND_6G) + reg_bitmap |= BIT(REG_BAND_6G); + + if (!wlan_reg_is_6ghz_supported(psoc)) { + hdd_debug("Driver doesn't support 6ghz"); + reg_bitmap = (reg_bitmap & (~BIT(REG_BAND_6G))); + } + + return reg_bitmap; +} + +int wlan_hdd_merge_avoid_freqs(struct ch_avoid_ind_type *destFreqList, + struct ch_avoid_ind_type *srcFreqList) +{ + int i; + uint32_t room; + struct ch_avoid_freq_type *avoid_range = + &destFreqList->avoid_freq_range[destFreqList->ch_avoid_range_cnt]; + + room = CH_AVOID_MAX_RANGE - destFreqList->ch_avoid_range_cnt; + if (srcFreqList->ch_avoid_range_cnt > room) { + hdd_err("avoid freq overflow"); + return -EINVAL; + } + destFreqList->ch_avoid_range_cnt += srcFreqList->ch_avoid_range_cnt; + + for (i = 0; i < srcFreqList->ch_avoid_range_cnt; i++) { + avoid_range->start_freq = + srcFreqList->avoid_freq_range[i].start_freq; + avoid_range->end_freq = + srcFreqList->avoid_freq_range[i].end_freq; + avoid_range++; + } + return 0; +} +/* + * FUNCTION: wlan_hdd_send_avoid_freq_event + * This is called when wlan driver needs to send vendor specific + * avoid frequency range event to userspace + */ +int wlan_hdd_send_avoid_freq_event(struct hdd_context *hdd_ctx, + struct ch_avoid_ind_type *avoid_freq_list) +{ + struct sk_buff *skb; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX; + + hdd_enter(); + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + if (!avoid_freq_list) { + hdd_err("avoid_freq_list is null"); + return -EINVAL; + } + + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + sizeof(struct ch_avoid_ind_type), + index, GFP_KERNEL); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + + memcpy(skb_put(skb, sizeof(struct ch_avoid_ind_type)), + (void *)avoid_freq_list, sizeof(struct ch_avoid_ind_type)); + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + + hdd_exit(); + return 0; +} + +/* + * define short names for the global vendor params + * used by QCA_NL80211_VENDOR_SUBCMD_HANG + */ +#define HANG_REASON_INDEX QCA_NL80211_VENDOR_SUBCMD_HANG_REASON_INDEX + +/** + * hdd_convert_hang_reason() - Convert cds recovery reason to vendor specific + * hang reason + * @reason: cds recovery reason + * + * Return: Vendor specific reason code + */ +static enum qca_wlan_vendor_hang_reason +hdd_convert_hang_reason(enum qdf_hang_reason reason) +{ + u32 ret_val; + + switch (reason) { + case QDF_RX_HASH_NO_ENTRY_FOUND: + ret_val = QCA_WLAN_HANG_RX_HASH_NO_ENTRY_FOUND; + break; + case QDF_PEER_DELETION_TIMEDOUT: + ret_val = QCA_WLAN_HANG_PEER_DELETION_TIMEDOUT; + break; + case QDF_PEER_UNMAP_TIMEDOUT: + ret_val = QCA_WLAN_HANG_PEER_UNMAP_TIMEDOUT; + break; + case QDF_SCAN_REQ_EXPIRED: + ret_val = QCA_WLAN_HANG_SCAN_REQ_EXPIRED; + break; + case QDF_SCAN_ATTEMPT_FAILURES: + ret_val = QCA_WLAN_HANG_SCAN_ATTEMPT_FAILURES; + break; + case QDF_GET_MSG_BUFF_FAILURE: + ret_val = QCA_WLAN_HANG_GET_MSG_BUFF_FAILURE; + break; + case QDF_ACTIVE_LIST_TIMEOUT: + ret_val = QCA_WLAN_HANG_ACTIVE_LIST_TIMEOUT; + break; + case QDF_SUSPEND_TIMEOUT: + ret_val = QCA_WLAN_HANG_SUSPEND_TIMEOUT; + break; + case QDF_RESUME_TIMEOUT: + ret_val = QCA_WLAN_HANG_RESUME_TIMEOUT; + break; + case QDF_WMI_EXCEED_MAX_PENDING_CMDS: + ret_val = QCA_WLAN_HANG_WMI_EXCEED_MAX_PENDING_CMDS; + break; + case QDF_AP_STA_CONNECT_REQ_TIMEOUT: + ret_val = QCA_WLAN_HANG_AP_STA_CONNECT_REQ_TIMEOUT; + break; + case QDF_STA_AP_CONNECT_REQ_TIMEOUT: + ret_val = QCA_WLAN_HANG_STA_AP_CONNECT_REQ_TIMEOUT; + break; + case QDF_MAC_HW_MODE_CHANGE_TIMEOUT: + ret_val = QCA_WLAN_HANG_MAC_HW_MODE_CHANGE_TIMEOUT; + break; + case QDF_MAC_HW_MODE_CONFIG_TIMEOUT: + ret_val = QCA_WLAN_HANG_MAC_HW_MODE_CONFIG_TIMEOUT; + break; + case QDF_VDEV_START_RESPONSE_TIMED_OUT: + ret_val = QCA_WLAN_HANG_VDEV_START_RESPONSE_TIMED_OUT; + break; + case QDF_VDEV_RESTART_RESPONSE_TIMED_OUT: + ret_val = QCA_WLAN_HANG_VDEV_RESTART_RESPONSE_TIMED_OUT; + break; + case QDF_VDEV_STOP_RESPONSE_TIMED_OUT: + ret_val = QCA_WLAN_HANG_VDEV_STOP_RESPONSE_TIMED_OUT; + break; + case QDF_VDEV_DELETE_RESPONSE_TIMED_OUT: + ret_val = QCA_WLAN_HANG_VDEV_DELETE_RESPONSE_TIMED_OUT; + break; + case QDF_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT: + ret_val = QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT; + break; + case QDF_WMI_BUF_SEQUENCE_MISMATCH: + ret_val = QCA_WLAN_HANG_VDEV_PEER_DELETE_ALL_RESPONSE_TIMED_OUT; + break; + case QDF_HAL_REG_WRITE_FAILURE: + ret_val = QCA_WLAN_HANG_REG_WRITE_FAILURE; + break; + case QDF_SUSPEND_NO_CREDIT: + ret_val = QCA_WLAN_HANG_SUSPEND_NO_CREDIT; + break; + case QCA_HANG_BUS_FAILURE: + ret_val = QCA_WLAN_HANG_BUS_FAILURE; + break; + case QDF_TASKLET_CREDIT_LATENCY_DETECT: + ret_val = QCA_WLAN_HANG_TASKLET_CREDIT_LATENCY_DETECT; + break; + case QDF_RX_REG_PKT_ROUTE_ERR: + ret_val = QCA_WLAN_HANG_RX_MSDU_BUF_RCVD_IN_ERR_RING; + break; + case QDF_VDEV_SM_OUT_OF_SYNC: + ret_val = QCA_WLAN_HANG_VDEV_SM_OUT_OF_SYNC; + break; + case QDF_STATS_REQ_TIMEDOUT: + ret_val = QCA_WLAN_HANG_STATS_REQ_TIMEOUT; + break; + case QDF_TX_DESC_LEAK: + ret_val = QCA_WLAN_HANG_TX_DESC_LEAK; + break; + case QDF_SCHED_TIMEOUT: + ret_val = QCA_WLAN_HANG_SCHED_TIMEOUT; + break; + case QDF_SELF_PEER_DEL_FAILED: + ret_val = QCA_WLAN_HANG_SELF_PEER_DEL_FAIL; + break; + case QDF_DEL_SELF_STA_FAILED: + ret_val = QCA_WLAN_HANG_DEL_SELF_STA_FAIL; + break; + case QDF_FLUSH_LOGS: + ret_val = QCA_WLAN_HANG_FLUSH_LOGS; + break; + case QDF_HOST_WAKEUP_REASON_PAGEFAULT: + ret_val = QCA_WLAN_HANG_HOST_WAKEUP_REASON_PAGE_FAULT; + break; + case QDF_REASON_UNSPECIFIED: + default: + ret_val = QCA_WLAN_HANG_REASON_UNSPECIFIED; + break; + } + return ret_val; +} + +/** + * wlan_hdd_send_hang_reason_event() - Send hang reason to the userspace + * @hdd_ctx: Pointer to hdd context + * @reason: cds recovery reason + * @data: Hang Data + * @data_len: length of @data + * + * Return: 0 on success or failure reason + */ +int wlan_hdd_send_hang_reason_event(struct hdd_context *hdd_ctx, + enum qdf_hang_reason reason, uint8_t *data, + size_t data_len) +{ + struct sk_buff *vendor_event; + enum qca_wlan_vendor_hang_reason hang_reason; + + hdd_enter(); + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + NULL, + sizeof(uint32_t) + + data_len, + HANG_REASON_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + hang_reason = hdd_convert_hang_reason(reason); + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_HANG_REASON, + (uint32_t)hang_reason) || + nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_HANG_REASON_DATA, + data_len, data)) { + hdd_err("QCA_WLAN_VENDOR_ATTR_HANG_REASON put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return -EINVAL; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + hdd_exit(); + return 0; +} + +#undef HANG_REASON_INDEX + +/** + * wlan_hdd_get_adjacent_chan_freq(): Gets next/previous channel + * with respect to the channel passed. + * @freq: Channel frequency + * @upper: If "true" then next channel is returned or else + * previous channel is returned. + * + * This function returns the next/previous adjacent-channel to + * the channel passed. If "upper = true" then next channel is + * returned else previous is returned. + */ +static qdf_freq_t wlan_hdd_get_adjacent_chan_freq(qdf_freq_t freq, bool upper) +{ + enum channel_enum ch_idx = wlan_reg_get_chan_enum_for_freq(freq); + + if (reg_is_chan_enum_invalid(ch_idx)) + return -EINVAL; + + if (upper && (ch_idx < (NUM_CHANNELS - 1))) + ch_idx++; + else if (!upper && (ch_idx > CHAN_ENUM_2412)) + ch_idx--; + else + return -EINVAL; + + return WLAN_REG_CH_TO_FREQ(ch_idx); +} + +/** + * wlan_hdd_send_avoid_freq_for_dnbs(): Sends list of frequencies to be + * avoided when Do_Not_Break_Stream is active. + * @hdd_ctx: HDD Context + * @op_freq: AP/P2P-GO operating channel frequency + * + * This function sends list of frequencies to be avoided when + * Do_Not_Break_Stream is active. + * To clear the avoid_frequency_list in the application, + * op_freq = 0 can be passed. + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_send_avoid_freq_for_dnbs(struct hdd_context *hdd_ctx, + qdf_freq_t op_freq) +{ + struct ch_avoid_ind_type p2p_avoid_freq_list; + qdf_freq_t min_freq, max_freq; + int ret; + qdf_freq_t freq; + + hdd_enter(); + + if (!hdd_ctx) { + hdd_err("invalid param"); + return -EINVAL; + } + + qdf_mem_zero(&p2p_avoid_freq_list, sizeof(struct ch_avoid_ind_type)); + /* + * If channel passed is zero, clear the avoid_freq list in application. + */ + if (!op_freq) { +#ifdef FEATURE_WLAN_CH_AVOID + mutex_lock(&hdd_ctx->avoid_freq_lock); + qdf_mem_zero(&hdd_ctx->dnbs_avoid_freq_list, + sizeof(struct ch_avoid_ind_type)); + if (hdd_ctx->coex_avoid_freq_list.ch_avoid_range_cnt) + memcpy(&p2p_avoid_freq_list, + &hdd_ctx->coex_avoid_freq_list, + sizeof(struct ch_avoid_ind_type)); + mutex_unlock(&hdd_ctx->avoid_freq_lock); +#endif + ret = wlan_hdd_send_avoid_freq_event(hdd_ctx, + &p2p_avoid_freq_list); + if (ret) + hdd_err("wlan_hdd_send_avoid_freq_event error:%d", + ret); + + return ret; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(op_freq)) { + min_freq = WLAN_REG_MIN_24GHZ_CHAN_FREQ; + max_freq = WLAN_REG_MAX_24GHZ_CHAN_FREQ; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ(op_freq)) { + min_freq = WLAN_REG_MIN_5GHZ_CHAN_FREQ; + max_freq = WLAN_REG_MAX_5GHZ_CHAN_FREQ; + } else { + hdd_err("invalid channel freq:%d", op_freq); + return -EINVAL; + } + + if (op_freq > min_freq && op_freq < max_freq) { + p2p_avoid_freq_list.ch_avoid_range_cnt = 2; + p2p_avoid_freq_list.avoid_freq_range[0].start_freq = min_freq; + + /* Get channel before the op_freq */ + freq = wlan_hdd_get_adjacent_chan_freq(op_freq, false); + if (freq < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[0].end_freq = freq; + + /* Get channel next to the op_freq */ + freq = wlan_hdd_get_adjacent_chan_freq(op_freq, true); + if (freq < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[1].start_freq = freq; + + p2p_avoid_freq_list.avoid_freq_range[1].end_freq = max_freq; + } else if (op_freq == min_freq) { + p2p_avoid_freq_list.ch_avoid_range_cnt = 1; + + freq = wlan_hdd_get_adjacent_chan_freq(op_freq, true); + if (freq < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[0].start_freq = freq; + + p2p_avoid_freq_list.avoid_freq_range[0].end_freq = max_freq; + } else { + p2p_avoid_freq_list.ch_avoid_range_cnt = 1; + p2p_avoid_freq_list.avoid_freq_range[0].start_freq = min_freq; + + freq = wlan_hdd_get_adjacent_chan_freq(op_freq, false); + if (freq < 0) + return -EINVAL; + p2p_avoid_freq_list.avoid_freq_range[0].end_freq = freq; + } +#ifdef FEATURE_WLAN_CH_AVOID + mutex_lock(&hdd_ctx->avoid_freq_lock); + hdd_ctx->dnbs_avoid_freq_list = p2p_avoid_freq_list; + if (hdd_ctx->coex_avoid_freq_list.ch_avoid_range_cnt) { + ret = wlan_hdd_merge_avoid_freqs(&p2p_avoid_freq_list, + &hdd_ctx->coex_avoid_freq_list); + if (ret) { + mutex_unlock(&hdd_ctx->avoid_freq_lock); + hdd_err("avoid freq merge failed"); + return ret; + } + } + mutex_unlock(&hdd_ctx->avoid_freq_lock); +#endif + ret = wlan_hdd_send_avoid_freq_event(hdd_ctx, &p2p_avoid_freq_list); + if (ret) + hdd_err("wlan_hdd_send_avoid_freq_event error:%d", ret); + + return ret; +} + +/* vendor specific events */ +static const struct nl80211_vendor_cmd_info wlan_hdd_cfg80211_vendor_events[] = { + [QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY + }, + + [QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_NAN + }, + +#ifdef WLAN_FEATURE_STATS_EXT + [QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT + }, +#endif /* WLAN_FEATURE_STATS_EXT */ + [QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS + }, + +#ifdef FEATURE_WLAN_EXTSCAN + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE_INDEX] = { + . + vendor_id + = + QCA_NL80211_VENDOR_ID, + . + subcmd + = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_RADIO_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_IFACE_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_PEER_INFO_STATS_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS + }, + [QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT + }, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + [QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE_CHANGE_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE + }, + [QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS + }, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + [QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH + }, +#endif + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED + }, + [QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX] = { + .vendor_id = + QCA_NL80211_VENDOR_ID, + .subcmd = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED + }, +#ifdef FEATURE_WLAN_EXTSCAN + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND + }, + [QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST + }, +#endif /* FEATURE_WLAN_EXTSCAN */ + + FEATURE_RSSI_MONITOR_VENDOR_EVENTS + +#ifdef WLAN_FEATURE_TSF + [QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TSF + }, +#endif + [QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE + }, + [QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN + }, + /* OCB events */ + [QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT + }, +#ifdef FEATURE_LFR_SUBNET_DETECTION + [QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG + }, +#endif /*FEATURE_LFR_SUBNET_DETECTION */ + + FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS_INDEX + + [QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NDP + }, + + [QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP + }, + [QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH + }, + [QCA_NL80211_VENDOR_SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS + }, + [QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_CHIP_PWRSAVE_FAILURE + }, + [QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + }, + [QCA_NL80211_VENDOR_SUBCMD_HANG_REASON_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_HANG, + }, + [QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO, + }, + [QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT, + }, + [QCA_NL80211_VENDOR_SUBCMD_NAN_EXT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_NAN_EXT + }, + [QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES, + }, + + BCN_RECV_FEATURE_VENDOR_EVENTS + FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS + [QCA_NL80211_VENDOR_SUBCMD_ROAM_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM, + }, + [QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_OEM_DATA, + }, + [QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS_EVENT, + }, + [QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO, + }, + FEATURE_THERMAL_VENDOR_EVENTS + FEATURE_DRIVER_DISCONNECT_REASON +#ifdef WLAN_SUPPORT_TWT + FEATURE_TWT_VENDOR_EVENTS +#endif + FEATURE_CFR_DATA_VENDOR_EVENTS +#ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING + FEATURE_CONNECTIVITY_LOGGING_EVENT +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + [QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS, + }, +#endif + FEATURE_MCC_QUOTA_VENDOR_EVENTS + [QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY, + }, + FEATURE_WIFI_POS_11AZ_AUTH_EVENTS +#ifdef WLAN_FEATURE_SR + [QCA_NL80211_VENDOR_SUBCMD_SR_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_SR, + }, +#endif + FEATURE_GREEN_AP_LOW_LATENCY_PWR_SAVE_EVENT + FEATURE_ROAM_STATS_EVENTS +#ifdef WLAN_FEATURE_11BE_MLO + [QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP, + }, + [QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG, + }, +#endif + FEATURE_AFC_VENDOR_EVENTS + + [QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH, + }, + + FEATURE_TX_LATENCY_STATS_EVENTS + [QCA_NL80211_VENDOR_SUBCMD_FW_PAGE_FAULT_REPORT_INDEX] = { + .vendor_id = QCA_NL80211_VENDOR_ID, + .subcmd = QCA_NL80211_VENDOR_SUBCMD_FW_PAGE_FAULT_REPORT, + }, +}; + +/** + * __is_driver_dfs_capable() - get driver DFS capability + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to indicate whether or not + * the driver supports DFS offload. + * + * Return: 0 on success, negative errno on failure + */ +static int __is_driver_dfs_capable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + u32 dfs_capability = 0; + struct sk_buff *temp_skbuff; + int ret_val; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + hdd_enter_dev(wdev->netdev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) || \ + defined(CFG80211_DFS_OFFLOAD_BACKPORT) + dfs_capability = + wiphy_ext_feature_isset(wiphy, + NL80211_EXT_FEATURE_DFS_OFFLOAD); +#else + dfs_capability = !!(wiphy->flags & WIPHY_FLAG_DFS_OFFLOAD); +#endif + + temp_skbuff = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u32) + + NLMSG_HDRLEN); + if (temp_skbuff) { + ret_val = nla_put_u32(temp_skbuff, QCA_WLAN_VENDOR_ATTR_DFS, + dfs_capability); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_DFS put fail"); + wlan_cfg80211_vendor_free_skb(temp_skbuff); + + return ret_val; + } + + return wlan_cfg80211_vendor_cmd_reply(temp_skbuff); + } + + hdd_err("dfs capability: buffer alloc fail"); + return -ENOMEM; +} + +/** + * is_driver_dfs_capable() - get driver DFS capability + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called by userspace to indicate whether or not + * the driver supports DFS offload. This is an SSR-protected + * wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +static int is_driver_dfs_capable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __is_driver_dfs_capable(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_sap_cfg_dfs_override() - DFS MCC restriction check + * + * @adapter: SAP adapter pointer + * + * DFS in MCC is not supported for Multi bssid SAP mode due to single physical + * radio. So in case of DFS MCC scenario override current SAP given config + * to follow concurrent SAP DFS config + * + * Return: 0 - No DFS issue, 1 - Override done and negative error codes + */ +int wlan_hdd_sap_cfg_dfs_override(struct hdd_adapter *adapter) +{ + struct hdd_adapter *con_sap_adapter; + struct sap_config *sap_config, *con_sap_config; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t con_ch_freq; + + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return 0; + } + + /* + * Check if AP+AP case, once primary AP chooses a DFS + * channel secondary AP should always follow primary APs channel + */ + if (!policy_mgr_concurrent_beaconing_sessions_running( + hdd_ctx->psoc)) + return 0; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, true); + if (!con_sap_adapter) + return 0; + + sap_config = &adapter->deflink->session.ap.sap_config; + con_sap_config = &con_sap_adapter->deflink->session.ap.sap_config; + con_ch_freq = con_sap_adapter->deflink->session.ap.operating_chan_freq; + + if (!wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, con_ch_freq)) + return 0; + + hdd_debug("Only SCC AP-AP DFS Permitted (ch_freq=%d, con_ch_freq=%d)", + sap_config->chan_freq, con_ch_freq); + hdd_debug("Overriding guest AP's channel"); + sap_config->chan_freq = con_ch_freq; + + if (con_sap_config->acs_cfg.acs_mode == true) { + if (con_ch_freq != con_sap_config->acs_cfg.pri_ch_freq && + con_ch_freq != con_sap_config->acs_cfg.ht_sec_ch_freq) { + hdd_err("Primary AP channel config error"); + hdd_err("Operating ch: %d ACS ch freq: %d Sec Freq %d", + con_ch_freq, + con_sap_config->acs_cfg.pri_ch_freq, + con_sap_config->acs_cfg.ht_sec_ch_freq); + return -EINVAL; + } + /* Sec AP ACS info is overwritten with Pri AP due to DFS + * MCC restriction. So free ch list allocated in do_acs + * func for Sec AP and realloc for Pri AP ch list size + */ + if (sap_config->acs_cfg.freq_list) { + qdf_mem_free(sap_config->acs_cfg.freq_list); + sap_config->acs_cfg.freq_list = NULL; + } + if (sap_config->acs_cfg.master_freq_list) { + qdf_mem_free(sap_config->acs_cfg.master_freq_list); + sap_config->acs_cfg.master_freq_list = NULL; + } + + qdf_mem_copy(&sap_config->acs_cfg, + &con_sap_config->acs_cfg, + sizeof(struct sap_acs_cfg)); + + sap_config->acs_cfg.freq_list = + qdf_mem_malloc(sizeof(uint32_t) * + con_sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.freq_list) { + sap_config->acs_cfg.ch_list_count = 0; + return -ENOMEM; + } + qdf_mem_copy(sap_config->acs_cfg.freq_list, + con_sap_config->acs_cfg.freq_list, + con_sap_config->acs_cfg.ch_list_count * + sizeof(uint32_t)); + + sap_config->acs_cfg.master_freq_list = + qdf_mem_malloc(sizeof(uint32_t) * + con_sap_config->acs_cfg.master_ch_list_count); + if (!sap_config->acs_cfg.master_freq_list) { + sap_config->acs_cfg.master_ch_list_count = 0; + qdf_mem_free(sap_config->acs_cfg.freq_list); + sap_config->acs_cfg.freq_list = NULL; + return -ENOMEM; + } + qdf_mem_copy(sap_config->acs_cfg.master_freq_list, + con_sap_config->acs_cfg.master_freq_list, + con_sap_config->acs_cfg.master_ch_list_count * + sizeof(uint32_t)); + } else { + sap_config->acs_cfg.pri_ch_freq = con_ch_freq; + if (sap_config->acs_cfg.ch_width > eHT_CHANNEL_WIDTH_20MHZ) + sap_config->acs_cfg.ht_sec_ch_freq = + con_sap_config->sec_ch_freq; + } + + return con_ch_freq; +} + +/** + * wlan_hdd_set_acs_ch_range : Populate ACS hw mode and channel range values + * @sap_cfg: pointer to SAP config struct + * @hw_mode: hw mode retrieved from vendor command buffer + * @ht_enabled: whether HT phy mode is enabled + * @vht_enabled: whether VHT phy mode is enabled + * + * This function populates the ACS hw mode based on the configuration retrieved + * from the vendor command buffer; and sets ACS start and end channel for the + * given band. + * + * Return: 0 if success; -EINVAL if ACS channel list is NULL + */ +static int wlan_hdd_set_acs_ch_range( + struct sap_config *sap_cfg, enum qca_wlan_vendor_acs_hw_mode hw_mode, + bool ht_enabled, bool vht_enabled) +{ + int i; + + if (hw_mode == QCA_ACS_MODE_IEEE80211B) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11b; + sap_cfg->acs_cfg.start_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_2412); + sap_cfg->acs_cfg.end_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_2484); + } else if (hw_mode == QCA_ACS_MODE_IEEE80211G) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11g; + sap_cfg->acs_cfg.start_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_2412); + sap_cfg->acs_cfg.end_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_2472); + } else if (hw_mode == QCA_ACS_MODE_IEEE80211A) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11a; + sap_cfg->acs_cfg.start_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_5180); + sap_cfg->acs_cfg.end_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_5885); + } else if (hw_mode == QCA_ACS_MODE_IEEE80211ANY) { + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_abg; + sap_cfg->acs_cfg.start_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_2412); + sap_cfg->acs_cfg.end_ch_freq = + wlan_reg_ch_to_freq(CHAN_ENUM_5885); + } + + if (ht_enabled) + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11n; + + if (vht_enabled) + sap_cfg->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + + /* Parse ACS Chan list from hostapd */ + if (!sap_cfg->acs_cfg.freq_list) + return -EINVAL; + + sap_cfg->acs_cfg.start_ch_freq = sap_cfg->acs_cfg.freq_list[0]; + sap_cfg->acs_cfg.end_ch_freq = + sap_cfg->acs_cfg.freq_list[sap_cfg->acs_cfg.ch_list_count - 1]; + for (i = 0; i < sap_cfg->acs_cfg.ch_list_count; i++) { + /* avoid channel as start channel */ + if (sap_cfg->acs_cfg.start_ch_freq > + sap_cfg->acs_cfg.freq_list[i] && + sap_cfg->acs_cfg.freq_list[i] != 0) + sap_cfg->acs_cfg.start_ch_freq = + sap_cfg->acs_cfg.freq_list[i]; + if (sap_cfg->acs_cfg.end_ch_freq < + sap_cfg->acs_cfg.freq_list[i]) + sap_cfg->acs_cfg.end_ch_freq = + sap_cfg->acs_cfg.freq_list[i]; + } + + return 0; +} + +static void hdd_update_acs_channel_list(struct sap_config *sap_config, + enum band_info band) +{ + int i, temp_count = 0; + int acs_list_count = sap_config->acs_cfg.ch_list_count; + + for (i = 0; i < acs_list_count; i++) { + if (BAND_2G == band) { + if (WLAN_REG_IS_24GHZ_CH_FREQ( + sap_config->acs_cfg.freq_list[i])) { + sap_config->acs_cfg.freq_list[temp_count] = + sap_config->acs_cfg.freq_list[i]; + temp_count++; + } + } else if (BAND_5G == band) { + if (WLAN_REG_IS_5GHZ_CH_FREQ( + sap_config->acs_cfg.freq_list[i]) || + WLAN_REG_IS_6GHZ_CHAN_FREQ( + sap_config->acs_cfg.freq_list[i])) { + sap_config->acs_cfg.freq_list[temp_count] = + sap_config->acs_cfg.freq_list[i]; + temp_count++; + } + } + } + sap_config->acs_cfg.ch_list_count = temp_count; +} + +/** + * wlan_hdd_cfg80211_start_acs : Start ACS Procedure for SAP + * @link_info: Link info pointer in SAP HDD adapter + * + * This function starts the ACS procedure if there are no + * constraints like MBSSID DFS restrictions. + * + * Return: Status of ACS Start procedure + */ +int wlan_hdd_cfg80211_start_acs(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx; + struct sap_config *sap_config; + struct sap_context *sap_ctx; + struct hdd_ap_ctx *ap_ctx; + sap_event_cb acs_event_callback; + uint8_t mcc_to_scc_switch = 0; + int status; + QDF_STATUS qdf_status; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + sap_config = &ap_ctx->sap_config; + + if (hdd_ctx->acs_policy.acs_chan_freq) + sap_config->chan_freq = hdd_ctx->acs_policy.acs_chan_freq; + else + sap_config->chan_freq = AUTO_CHANNEL_SELECT; + ucfg_policy_mgr_get_mcc_scc_switch(hdd_ctx->psoc, + &mcc_to_scc_switch); + /* + * No DFS SCC is allowed in Auto use case. Hence not + * calling DFS override + */ + if (QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION != + mcc_to_scc_switch && + !(policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + WLAN_REG_IS_24GHZ_CH_FREQ(sap_config->acs_cfg.end_ch_freq)) && + !wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx)) { + status = wlan_hdd_sap_cfg_dfs_override(adapter); + if (status < 0) + return status; + + if (status > 0) { + /*notify hostapd about channel override */ + wlan_hdd_cfg80211_acs_ch_select_evt(link_info, true); + wlansap_dcs_set_wlan_interference_mitigation_on_band(sap_ctx, + sap_config); + return 0; + } + } + /* When first 2 connections are on the same frequency band, + * then PCL would include only channels from the other + * frequency band on which no connections are active + */ + if ((policy_mgr_get_connection_count(hdd_ctx->psoc) == 2) && + (sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211ANY)) { + struct policy_mgr_conc_connection_info *conc_connection_info; + uint32_t i; + + conc_connection_info = policy_mgr_get_conn_info(&i); + if (policy_mgr_are_2_freq_on_same_mac(hdd_ctx->psoc, + conc_connection_info[0].freq, + conc_connection_info[1].freq)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ( + sap_config->acs_cfg.pcl_chan_freq[0])) { + sap_config->acs_cfg.band = + QCA_ACS_MODE_IEEE80211A; + hdd_update_acs_channel_list(sap_config, + BAND_5G); + } else { + sap_config->acs_cfg.band = + QCA_ACS_MODE_IEEE80211G; + hdd_update_acs_channel_list(sap_config, + BAND_2G); + } + } + } + status = wlan_hdd_config_acs(hdd_ctx, adapter); + if (status) { + hdd_err("ACS config failed"); + return -EINVAL; + } + + acs_event_callback = hdd_hostapd_sap_event_cb; + + qdf_mem_copy(sap_config->self_macaddr.bytes, + adapter->mac_addr.bytes, sizeof(struct qdf_mac_addr)); + + qdf_status = wlansap_acs_chselect(sap_ctx, acs_event_callback, + sap_config, adapter->dev); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("ACS channel select failed"); + return -EINVAL; + } + if (sap_is_auto_channel_select(sap_ctx)) + sap_config->acs_cfg.acs_mode = true; + + /* If ACS scan is skipped then ACS request would be completed by now, + * so no need to set acs in progress + */ + if (!sap_config->acs_cfg.skip_acs_scan) + qdf_atomic_set(&ap_ctx->acs_in_progress, 1); + + return 0; +} + +/** + * hdd_update_vendor_pcl_list() - This API will return unsorted pcl list + * @hdd_ctx: hdd context + * @acs_chan_params: external acs channel params + * @sap_config: SAP config + * + * This API provides unsorted pcl list. + * this list is a subset of the valid channel list given by hostapd. + * if channel is not present in pcl, weightage will be given as zero + * + * Return: Zero on success, non-zero on failure + */ +static void hdd_update_vendor_pcl_list(struct hdd_context *hdd_ctx, + struct hdd_vendor_acs_chan_params *acs_chan_params, + struct sap_config *sap_config) +{ + int i, j; + /* + * PCL shall contain only the preferred channels from the + * application. If those channels are not present in the + * driver PCL, then set the weight to zero + */ + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) { + acs_chan_params->vendor_pcl_list[i] = + sap_config->acs_cfg.freq_list[i]; + acs_chan_params->vendor_weight_list[i] = 0; + for (j = 0; j < sap_config->acs_cfg.pcl_ch_count; j++) { + if (sap_config->acs_cfg.freq_list[i] == + sap_config->acs_cfg.pcl_chan_freq[j]) { + acs_chan_params->vendor_weight_list[i] = + sap_config->acs_cfg.pcl_channels_weight_list[j]; + break; + } + } + } + acs_chan_params->pcl_count = sap_config->acs_cfg.ch_list_count; +} + +/** + * hdd_update_reg_chan_info : This API constructs channel info + * for all the given channel + * @adapter: pointer to SAP adapter struct + * @channel_count: channel count + * @freq_list: channel frequency (MHz) list + * + * Return: Status of of channel information updation + */ +static int +hdd_update_reg_chan_info(struct hdd_adapter *adapter, + uint32_t channel_count, uint32_t *freq_list) +{ + int i; + struct hdd_channel_info *icv; + struct ch_params ch_params = {0}; + uint8_t bw_offset = 0, chan = 0; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sap_config *sap_config = + &adapter->deflink->session.ap.sap_config; + mac_handle_t mac_handle; + uint8_t sub_20_chan_width = 0; + QDF_STATUS status; + + mac_handle = hdd_ctx->mac_handle; + sap_config->channel_info_count = channel_count; + + status = ucfg_mlme_get_sub_20_chan_width(hdd_ctx->psoc, + &sub_20_chan_width); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get sub_20_chan_width config"); + + for (i = 0; i < channel_count; i++) { + icv = &sap_config->channel_info[i]; + chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, + freq_list[i]); + if (chan == 0) + continue; + + icv->freq = freq_list[i]; + icv->ieee_chan_number = chan; + icv->max_reg_power = wlan_reg_get_channel_reg_power_for_freq( + hdd_ctx->pdev, freq_list[i]); + + /* filling demo values */ + icv->max_radio_power = HDD_MAX_TX_POWER; + icv->min_radio_power = HDD_MIN_TX_POWER; + /* not supported in current driver */ + icv->max_antenna_gain = 0; + + bw_offset = hdd_get_bw_offset(sap_config->acs_cfg.ch_width); + icv->reg_class_id = + wlan_hdd_find_opclass(mac_handle, chan, bw_offset); + + if (WLAN_REG_IS_5GHZ_CH_FREQ(freq_list[i])) { + if (sap_phymode_is_eht(sap_config->SapHw_mode)) + wlan_reg_set_create_punc_bitmap(&ch_params, + true); + ch_params.ch_width = sap_config->acs_cfg.ch_width; + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + icv->freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + icv->vht_center_freq_seg0 = ch_params.center_freq_seg0; + icv->vht_center_freq_seg1 = ch_params.center_freq_seg1; + } + + icv->flags = 0; + icv->flags = cds_get_vendor_reg_flags(hdd_ctx->pdev, + icv->freq, + sap_config->acs_cfg.ch_width, + sap_config->acs_cfg.is_ht_enabled, + sap_config->acs_cfg.is_vht_enabled, + sub_20_chan_width); + if (icv->flags & IEEE80211_CHAN_PASSIVE) + icv->flagext |= IEEE80211_CHAN_DFS; + + hdd_debug("freq %d flags %d flagext %d ieee %d maxreg %d maxpw %d minpw %d regClass %d antenna %d seg0 %d seg1 %d", + icv->freq, icv->flags, + icv->flagext, icv->ieee_chan_number, + icv->max_reg_power, icv->max_radio_power, + icv->min_radio_power, icv->reg_class_id, + icv->max_antenna_gain, icv->vht_center_freq_seg0, + icv->vht_center_freq_seg1); + } + return 0; +} + +/* Short name for QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO event */ +#define CHAN_INFO_ATTR_FLAGS \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS +#define CHAN_INFO_ATTR_FLAG_EXT \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT +#define CHAN_INFO_ATTR_FREQ \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ +#define CHAN_INFO_ATTR_MAX_REG_POWER \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_REG_POWER +#define CHAN_INFO_ATTR_MAX_POWER \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_POWER +#define CHAN_INFO_ATTR_MIN_POWER \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MIN_POWER +#define CHAN_INFO_ATTR_REG_CLASS_ID \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_REG_CLASS_ID +#define CHAN_INFO_ATTR_ANTENNA_GAIN \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_ANTENNA_GAIN +#define CHAN_INFO_ATTR_VHT_SEG_0 \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0 +#define CHAN_INFO_ATTR_VHT_SEG_1 \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1 + +#define CHAN_INFO_ATTR_FREQ_VHT_SEG_0 \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 +#define CHAN_INFO_ATTR_FREQ_VHT_SEG_1 \ + QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 + +/** + * hdd_cfg80211_update_channel_info() - add channel info attributes + * @hdd_ctx: pointer to hdd context + * @skb: pointer to sk buff + * @sap_config: pointer to SAP configuration + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_cfg80211_update_channel_info(struct hdd_context *hdd_ctx, + struct sk_buff *skb, + struct sap_config *sap_config, int idx) +{ + struct nlattr *nla_attr, *channel; + struct hdd_channel_info *icv; + int i; + uint32_t freq_seg_0 = 0, freq_seg_1 = 0; + enum reg_wifi_band band; + uint8_t band_mask; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + for (i = 0; i < sap_config->channel_info_count; i++) { + channel = nla_nest_start(skb, i); + if (!channel) + goto fail; + + icv = &sap_config->channel_info[i]; + if (!icv) { + hdd_err("channel info not found"); + goto fail; + } + + band = wlan_reg_freq_to_band(icv->freq); + band_mask = 1 << band; + + if (icv->vht_center_freq_seg0) + freq_seg_0 = wlan_reg_chan_band_to_freq(hdd_ctx->pdev, + icv->vht_center_freq_seg0, + band_mask); + if (icv->vht_center_freq_seg1) + freq_seg_1 = wlan_reg_chan_band_to_freq(hdd_ctx->pdev, + icv->vht_center_freq_seg1, + band_mask); + + if (nla_put_u16(skb, CHAN_INFO_ATTR_FREQ, + icv->freq) || + nla_put_u32(skb, CHAN_INFO_ATTR_FLAGS, + icv->flags) || + nla_put_u32(skb, CHAN_INFO_ATTR_FLAG_EXT, + icv->flagext) || + nla_put_u8(skb, CHAN_INFO_ATTR_MAX_REG_POWER, + icv->max_reg_power) || + nla_put_u8(skb, CHAN_INFO_ATTR_MAX_POWER, + icv->max_radio_power) || + nla_put_u8(skb, CHAN_INFO_ATTR_MIN_POWER, + icv->min_radio_power) || + nla_put_u8(skb, CHAN_INFO_ATTR_REG_CLASS_ID, + icv->reg_class_id) || + nla_put_u8(skb, CHAN_INFO_ATTR_ANTENNA_GAIN, + icv->max_antenna_gain) || + nla_put_u8(skb, CHAN_INFO_ATTR_VHT_SEG_0, + icv->vht_center_freq_seg0) || + nla_put_u8(skb, CHAN_INFO_ATTR_VHT_SEG_1, + icv->vht_center_freq_seg1) || + nla_put_u32(skb, CHAN_INFO_ATTR_FREQ_VHT_SEG_0, + freq_seg_0) || + nla_put_u32(skb, CHAN_INFO_ATTR_FREQ_VHT_SEG_1, + freq_seg_1)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, channel); + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + hdd_err("nl channel update failed"); + return -EINVAL; +} +#undef CHAN_INFO_ATTR_FLAGS +#undef CHAN_INFO_ATTR_FLAG_EXT +#undef CHAN_INFO_ATTR_FREQ +#undef CHAN_INFO_ATTR_MAX_REG_POWER +#undef CHAN_INFO_ATTR_MAX_POWER +#undef CHAN_INFO_ATTR_MIN_POWER +#undef CHAN_INFO_ATTR_REG_CLASS_ID +#undef CHAN_INFO_ATTR_ANTENNA_GAIN +#undef CHAN_INFO_ATTR_VHT_SEG_0 +#undef CHAN_INFO_ATTR_VHT_SEG_1 + +#undef CHAN_INFO_ATTR_FREQ_VHT_SEG_0 +#undef CHAN_INFO_ATTR_FREQ_VHT_SEG_1 + +/** + * hdd_cfg80211_update_pcl() - add pcl info attributes + * @hdd_ctx: pointer to hdd context + * @skb: pointer to sk buff + * @ch_list_count: number of channels to add + * @idx: attribute index + * @vendor_pcl_list: PCL list + * @vendor_weight_list: PCL weights + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_cfg80211_update_pcl(struct hdd_context *hdd_ctx, + struct sk_buff *skb, + uint8_t ch_list_count, int idx, + uint32_t *vendor_pcl_list, uint8_t *vendor_weight_list) +{ + struct nlattr *nla_attr, *channel; + int i; + uint8_t chan; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + for (i = 0; i < ch_list_count; i++) { + channel = nla_nest_start(skb, i); + if (!channel) + goto fail; + + chan = (uint8_t)wlan_reg_freq_to_chan(hdd_ctx->pdev, + vendor_pcl_list[i]); + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL, chan) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_PCL_FREQ, + vendor_pcl_list[i]) || + nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT, + vendor_weight_list[i])) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, channel); + } + nla_nest_end(skb, nla_attr); + + return 0; +fail: + hdd_err("updating pcl list failed"); + return -EINVAL; +} + +static void hdd_get_scan_band(struct hdd_context *hdd_ctx, + struct sap_config *sap_config, + enum band_info *band) +{ + /* Get scan band */ + if ((sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211B) || + (sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211G)) { + *band = BAND_2G; + } else if (sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211A) { + *band = BAND_5G; + } else if (sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211ANY) { + *band = BAND_ALL; + } +} + +/** + * wlan_hdd_sap_get_valid_channellist() - Get SAPs valid channel list + * @adapter: adapter + * @channel_count: valid channel count + * @freq_list: valid channel frequency (MHz) list + * @band: frequency band + * + * This API returns valid channel list for SAP after removing nol and + * channel which lies outside of configuration. + * + * Return: Zero on success, non-zero on failure + */ +static int wlan_hdd_sap_get_valid_channellist(struct hdd_adapter *adapter, + uint32_t *channel_count, + uint32_t *freq_list, + enum band_info band) +{ + struct sap_config *sap_config; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t pcl_freqs[NUM_CHANNELS] = {0}; + uint32_t chan_count; + uint32_t i; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev = hdd_ctx->pdev; + + sap_config = &adapter->deflink->session.ap.sap_config; + + status = policy_mgr_get_valid_chans(hdd_ctx->psoc, + pcl_freqs, + &chan_count); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get channel list"); + return -EINVAL; + } + + *channel_count = 0; + for (i = 0; i < chan_count; i++) { + if (*channel_count >= NUM_CHANNELS) + break; + + if (band == BAND_2G && + WLAN_REG_IS_24GHZ_CH_FREQ(pcl_freqs[i]) && + !wlan_reg_is_disable_for_pwrmode(pdev, pcl_freqs[i], + REG_CURRENT_PWR_MODE)) { + freq_list[*channel_count] = pcl_freqs[i]; + *channel_count += 1; + } else if (band == BAND_5G && + (WLAN_REG_IS_5GHZ_CH_FREQ(pcl_freqs[i]) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(pcl_freqs[i])) && + !wlan_reg_is_disable_for_pwrmode( + pdev, pcl_freqs[i], + REG_CURRENT_PWR_MODE)) { + freq_list[*channel_count] = pcl_freqs[i]; + *channel_count += 1; + } + } + + if (*channel_count == 0) { + hdd_err("no valid channel found"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_external_acs_event_len() - Get event buffer length for external ACS + * @channel_count: number of channels for ACS operation + * + * Return: External ACS event (SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG) buffer length. + */ +static int hdd_get_external_acs_event_len(uint32_t channel_count) +{ + uint32_t len = NLMSG_HDRLEN; + uint32_t i; + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_WIDTH */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_FREQ_LIST */ + len += nla_total_size(channel_count * sizeof(u32)); + + for (i = 0; i < channel_count; i++) { + /* QCA_WLAN_VENDOR_ATTR_PCL_CHANNEL */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_PCL_FREQ */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT */ + len += nla_total_size(sizeof(u8)); + } + + for (i = 0; i < channel_count; i++) { + /* QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ */ + len += nla_total_size(sizeof(u16)); + + /* QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAGS */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FLAG_EXT */ + len += nla_total_size(sizeof(u32)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_REG_POWER */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MAX_POWER */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_MIN_POWER */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_REG_CLASS_ID */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_ANTENNA_GAIN */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_0 */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_VHT_SEG_1 */ + len += nla_total_size(sizeof(u8)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_0 */ + len += nla_total_size(sizeof(u32)); + + /* VENDOR_EXTERNAL_ACS_EVENT_CHAN_INFO_ATTR_FREQ_VHT_SEG_1 */ + len += nla_total_size(sizeof(u32)); + } + + /* QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY */ + len += nla_total_size(sizeof(u32)); + + return len; +} + +int hdd_cfg80211_update_acs_config(struct hdd_adapter *adapter, + uint8_t reason) +{ + struct sk_buff *skb = NULL; + struct sap_config *sap_config; + uint32_t channel_count = 0, status = -EINVAL; + uint32_t *freq_list; + uint32_t vendor_pcl_list[NUM_CHANNELS] = {0}; + uint8_t vendor_weight_list[NUM_CHANNELS] = {0}; + struct hdd_vendor_acs_chan_params acs_chan_params; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum band_info band = BAND_2G; + eCsrPhyMode phy_mode; + enum qca_wlan_vendor_attr_external_acs_policy acs_policy; + uint32_t i, id; + QDF_STATUS qdf_status; + bool is_external_acs_policy = cfg_default(CFG_EXTERNAL_ACS_POLICY); + uint32_t len; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return -EINVAL; + } + + hdd_enter(); + sap_config = &adapter->deflink->session.ap.sap_config; + /* When first 2 connections are on the same frequency band, + * then PCL would include only channels from the other + * frequency band on which no connections are active + */ + if ((policy_mgr_get_connection_count(hdd_ctx->psoc) == 2) && + (sap_config->acs_cfg.band == QCA_ACS_MODE_IEEE80211ANY)) { + struct policy_mgr_conc_connection_info *conc_connection_info; + + conc_connection_info = policy_mgr_get_conn_info(&i); + if (policy_mgr_are_2_freq_on_same_mac(hdd_ctx->psoc, + conc_connection_info[0].freq, + conc_connection_info[1].freq)) { + if (!WLAN_REG_IS_24GHZ_CH_FREQ( + sap_config->acs_cfg.pcl_chan_freq[0])) { + sap_config->acs_cfg.band = + QCA_ACS_MODE_IEEE80211A; + hdd_update_acs_channel_list(sap_config, + BAND_5G); + } else { + sap_config->acs_cfg.band = + QCA_ACS_MODE_IEEE80211G; + hdd_update_acs_channel_list(sap_config, + BAND_2G); + } + } + } + + hdd_get_scan_band(hdd_ctx, &adapter->deflink->session.ap.sap_config, + &band); + + freq_list = qdf_mem_malloc(sizeof(uint32_t) * NUM_CHANNELS); + if (!freq_list) + return -ENOMEM; + + if (sap_config->acs_cfg.freq_list) { + /* Copy INI or hostapd provided ACS channel range*/ + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) + freq_list[i] = sap_config->acs_cfg.freq_list[i]; + channel_count = sap_config->acs_cfg.ch_list_count; + } else { + /* No channel list provided, copy all valid channels */ + wlan_hdd_sap_get_valid_channellist(adapter, + &channel_count, + freq_list, + band); + } + + sap_config->channel_info = qdf_mem_malloc( + sizeof(struct hdd_channel_info) * + channel_count); + if (!sap_config->channel_info) { + status = -ENOMEM; + goto fail; + } + + hdd_update_reg_chan_info(adapter, channel_count, freq_list); + + /* Get phymode */ + phy_mode = adapter->deflink->session.ap.sap_config.acs_cfg.hw_mode; + + len = hdd_get_external_acs_event_len(channel_count); + id = QCA_NL80211_VENDOR_SUBCMD_UPDATE_EXTERNAL_ACS_CONFIG; + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, &adapter->wdev, + len, id, GFP_KERNEL); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + status = -ENOMEM; + goto fail; + } + /* + * Application expects pcl to be a subset of channel list + * Remove all channels which are not in channel list from pcl + * and add weight as zero + */ + acs_chan_params.vendor_pcl_list = vendor_pcl_list; + acs_chan_params.vendor_weight_list = vendor_weight_list; + + hdd_update_vendor_pcl_list(hdd_ctx, &acs_chan_params, + sap_config); + + if (acs_chan_params.pcl_count) { + hdd_debug("ACS PCL list: len: %d", + acs_chan_params.pcl_count); + for (i = 0; i < acs_chan_params.pcl_count; i++) + hdd_debug("channel_frequency: %u, weight: %u", + acs_chan_params. + vendor_pcl_list[i], + acs_chan_params. + vendor_weight_list[i]); + } + + qdf_status = ucfg_mlme_get_external_acs_policy(hdd_ctx->psoc, + &is_external_acs_policy); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("get_external_acs_policy failed, set default"); + + if (is_external_acs_policy) { + acs_policy = + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_POLICY_PCL_MANDATORY; + } else { + acs_policy = + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_POLICY_PCL_PREFERRED; + } + /* Update values in NL buffer */ + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_REASON, + reason) || + nla_put_flag(skb, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_IS_OFFLOAD_ENABLED) || + nla_put_flag(skb, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_ADD_CHAN_STATS_SUPPORT) + || + nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_WIDTH, + sap_config->acs_cfg.ch_width) || + nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_BAND, + band) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PHY_MODE, + phy_mode) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_FREQ_LIST, + channel_count * sizeof(uint32_t), freq_list)) { + hdd_err("nla put fail"); + goto fail; + } + status = + hdd_cfg80211_update_pcl(hdd_ctx, skb, + acs_chan_params.pcl_count, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_PCL, + vendor_pcl_list, + vendor_weight_list); + + if (status != 0) + goto fail; + + id = QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_CHAN_INFO; + + status = hdd_cfg80211_update_channel_info(hdd_ctx, skb, sap_config, id); + if (status != 0) + goto fail; + + status = nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_EVENT_POLICY, + acs_policy); + + if (status != 0) + goto fail; + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + qdf_mem_free(freq_list); + qdf_mem_free(sap_config->channel_info); + + return 0; +fail: + qdf_mem_free(freq_list); + if (sap_config->channel_info) + qdf_mem_free(sap_config->channel_info); + wlan_cfg80211_vendor_free_skb(skb); + return status; +} + +/** + * hdd_create_acs_timer(): Initialize vendor ACS timer + * @adapter: pointer to SAP adapter struct + * + * This function initializes the vendor ACS timer. + * + * Return: Status of create vendor ACS timer + */ +static int hdd_create_acs_timer(struct hdd_adapter *adapter) +{ + struct hdd_external_acs_timer_context *timer_context; + QDF_STATUS status; + + if (adapter->deflink->session.ap.vendor_acs_timer_initialized) + return 0; + + hdd_debug("Starting vendor app based ACS"); + timer_context = qdf_mem_malloc(sizeof(*timer_context)); + if (!timer_context) + return -ENOMEM; + + timer_context->adapter = adapter; + + set_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->deflink->link_flags); + status = qdf_mc_timer_init( + &adapter->deflink->session.ap.vendor_acs_timer, + QDF_TIMER_TYPE_SW, + hdd_acs_response_timeout_handler, timer_context); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to initialize acs response timeout timer"); + return -EFAULT; + } + adapter->deflink->session.ap.vendor_acs_timer_initialized = true; + return 0; +} + +static const struct nla_policy +wlan_hdd_cfg80211_do_acs_policy[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH] = { .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST] = { .type = NLA_BINARY, + .len = sizeof(NLA_U8) * NUM_CHANNELS }, + [QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST] = { .type = NLA_BINARY, + .len = sizeof(NLA_U32) * NUM_CHANNELS }, + [QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP] = { .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_ACS_EDMG_ENABLED] = { .type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_ACS_EDMG_CHANNEL] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME] = { .type = NLA_U32 }, +}; + +int hdd_start_vendor_acs(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int status; + QDF_STATUS qdf_status; + bool is_acs_support_for_dfs_ltecoex = cfg_default(CFG_USER_ACS_DFS_LTE); + + status = hdd_create_acs_timer(adapter); + if (status != 0) { + hdd_err("failed to create acs timer"); + return status; + } + status = hdd_update_acs_timer_reason(adapter, + QCA_WLAN_VENDOR_ACS_SELECT_REASON_INIT); + if (status != 0) { + hdd_err("failed to update acs timer reason"); + return status; + } + qdf_status = ucfg_mlme_get_acs_support_for_dfs_ltecoex( + hdd_ctx->psoc, + &is_acs_support_for_dfs_ltecoex); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("get_acs_support_for_dfs_ltecoex failed, set def"); + + if (is_acs_support_for_dfs_ltecoex) + status = qdf_status_to_os_return(wlan_sap_set_vendor_acs( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + true)); + else + status = qdf_status_to_os_return(wlan_sap_set_vendor_acs( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + false)); + + return status; +} + +/** + * hdd_avoid_acs_channels() - Avoid acs channels + * @hdd_ctx: Pointer to the hdd context + * @sap_config: Sap config structure pointer + * + * This function avoids channels from the acs corresponding to + * the frequencies configured in the ini sap_avoid_acs_freq_list + * + * Return: None + */ + +#ifdef SAP_AVOID_ACS_FREQ_LIST +static void hdd_avoid_acs_channels(struct hdd_context *hdd_ctx, + struct sap_config *sap_config) +{ + int i, j, ch_cnt = 0; + uint16_t avoid_acs_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t avoid_acs_freq_list_num; + + ucfg_mlme_get_acs_avoid_freq_list(hdd_ctx->psoc, + avoid_acs_freq_list, + &avoid_acs_freq_list_num); + + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) { + for (j = 0; j < avoid_acs_freq_list_num; j++) { + if (sap_config->acs_cfg.freq_list[i] == + avoid_acs_freq_list[j]) { + hdd_debug("skip freq %d", + sap_config->acs_cfg.freq_list[i]); + break; + } + } + if (j == avoid_acs_freq_list_num) + sap_config->acs_cfg.freq_list[ch_cnt++] = + sap_config->acs_cfg.freq_list[i]; + } + sap_config->acs_cfg.ch_list_count = ch_cnt; +} +#else +static void hdd_avoid_acs_channels(struct hdd_context *hdd_ctx, + struct sap_config *sap_config) +{ +} +#endif + +void wlan_hdd_trim_acs_channel_list(uint32_t *pcl, uint8_t pcl_count, + uint32_t *org_freq_list, + uint8_t *org_ch_list_count) +{ + uint16_t i, j, ch_list_count = 0; + + if (*org_ch_list_count >= NUM_CHANNELS) { + hdd_err("org_ch_list_count too big %d", + *org_ch_list_count); + return; + } + + if (pcl_count >= NUM_CHANNELS) { + hdd_err("pcl_count is too big %d", pcl_count); + return; + } + + hdd_debug("Update ACS chan freq with PCL"); + for (j = 0; j < *org_ch_list_count; j++) + for (i = 0; i < pcl_count; i++) + if (pcl[i] == org_freq_list[j]) { + org_freq_list[ch_list_count++] = pcl[i]; + break; + } + + *org_ch_list_count = ch_list_count; +} + +/* wlan_hdd_dump_freq_list() - Dump the ACS master frequency list + * + * @freq_list: Frequency list + * @num_freq: num of frequencies in list + * + * Dump the ACS master frequency list. + */ +static inline +void wlan_hdd_dump_freq_list(uint32_t *freq_list, uint8_t num_freq) +{ + uint32_t buf_len = 0; + uint32_t i = 0, j = 0; + uint8_t *master_chlist; + + if (num_freq >= NUM_CHANNELS) + return; + + buf_len = NUM_CHANNELS * 4; + master_chlist = qdf_mem_malloc(buf_len); + + if (!master_chlist) + return; + + for (i = 0; i < num_freq && j < buf_len; i++) { + j += qdf_scnprintf(master_chlist + j, buf_len - j, + "%d ", freq_list[i]); + } + + hdd_debug("Master channel list: %s", master_chlist); + qdf_mem_free(master_chlist); +} + +void wlan_hdd_handle_zero_acs_list(struct hdd_context *hdd_ctx, + uint32_t *acs_freq_list, + uint8_t *acs_ch_list_count, + uint32_t *org_freq_list, + uint8_t org_ch_list_count) +{ + uint16_t i, sta_count; + uint32_t acs_chan_default = 0, acs_dfs_chan = 0; + bool force_sap_allowed = false; + enum channel_state state; + + if (!acs_ch_list_count || *acs_ch_list_count > 0 || + !acs_freq_list) { + return; + } + if (!org_ch_list_count || !org_freq_list) + return; + + if (!policy_mgr_is_force_scc(hdd_ctx->psoc)) + return; + sta_count = policy_mgr_mode_specific_connection_count + (hdd_ctx->psoc, PM_STA_MODE, NULL); + sta_count += policy_mgr_mode_specific_connection_count + (hdd_ctx->psoc, PM_P2P_CLIENT_MODE, NULL); + + ucfg_mlme_get_force_sap_enabled(hdd_ctx->psoc, &force_sap_allowed); + if (!sta_count && !force_sap_allowed) + return; + + wlan_hdd_dump_freq_list(org_freq_list, org_ch_list_count); + + for (i = 0; i < org_ch_list_count; i++) { + state = wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, org_freq_list[i], + REG_CURRENT_PWR_MODE); + if (state == CHANNEL_STATE_DISABLE || + state == CHANNEL_STATE_INVALID) + continue; + + if (wlan_reg_is_6ghz_chan_freq(org_freq_list[i]) && + !wlan_reg_is_6ghz_psc_chan_freq(org_freq_list[i])) + continue; + + if (!policy_mgr_is_safe_channel(hdd_ctx->psoc, + org_freq_list[i])) + continue; + /* Make dfs channel as last choice */ + if (state == CHANNEL_STATE_DFS || + state == CHANNEL_STATE_PASSIVE) { + acs_dfs_chan = org_freq_list[i]; + continue; + } + acs_chan_default = org_freq_list[i]; + break; + } + if (!acs_chan_default) { + if (acs_dfs_chan) + acs_chan_default = acs_dfs_chan; + else + acs_chan_default = org_freq_list[0]; + } + + acs_freq_list[0] = acs_chan_default; + *acs_ch_list_count = 1; + hdd_debug("restore acs chan list to single freq %d", acs_chan_default); +} + +/** + * wlan_hdd_handle_single_ch_in_acs_list() - Handle acs list with single channel + * @link_info: Link info pointer in HDD adapter + * + * If only one acs channel is left after filter, driver will return the channel + * to hostapd without ACS scan. + * + * Return: None + */ +static void +wlan_hdd_handle_single_ch_in_acs_list(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint32_t channel_bonding_mode_2g; + struct sap_config *sap_config; + + sap_config = &link_info->session.ap.sap_config; + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode_2g); + sap_config->acs_cfg.start_ch_freq = + sap_config->acs_cfg.freq_list[0]; + sap_config->acs_cfg.end_ch_freq = + sap_config->acs_cfg.freq_list[0]; + sap_config->acs_cfg.pri_ch_freq = + sap_config->acs_cfg.freq_list[0]; + if (sap_config->acs_cfg.pri_ch_freq <= + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484) && + sap_config->acs_cfg.ch_width >= + CH_WIDTH_40MHZ && + !channel_bonding_mode_2g) { + sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ; + hdd_debug("2.4ghz channel resetting BW to %d 2.4 cbmode %d", + sap_config->acs_cfg.ch_width, + channel_bonding_mode_2g); + } + + wlan_sap_set_sap_ctx_acs_cfg( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), sap_config); + sap_config_acs_result(hdd_ctx->mac_handle, + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + sap_config->acs_cfg.ht_sec_ch_freq); + sap_config->ch_params.ch_width = + sap_config->acs_cfg.ch_width; + sap_config->ch_params.sec_ch_offset = + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_config->acs_cfg.ht_sec_ch_freq); + sap_config->ch_params.center_freq_seg0 = + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_config->acs_cfg.vht_seg0_center_ch_freq); + sap_config->ch_params.center_freq_seg1 = + wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_config->acs_cfg.vht_seg1_center_ch_freq); + sap_config->ch_params.mhz_freq_seg0 = + sap_config->acs_cfg.vht_seg0_center_ch_freq; + sap_config->ch_params.mhz_freq_seg1 = + sap_config->acs_cfg.vht_seg1_center_ch_freq; + /*notify hostapd about channel override */ + wlan_hdd_cfg80211_acs_ch_select_evt(link_info, true); + wlansap_dcs_set_wlan_interference_mitigation_on_band( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + sap_config); +} + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +static void wlan_hdd_set_sap_acs_ch_width_320(struct sap_config *sap_config) +{ + sap_config->acs_cfg.ch_width = CH_WIDTH_320MHZ; +} + +static bool wlan_hdd_is_sap_acs_ch_width_320(struct sap_config *sap_config) +{ + return sap_config->acs_cfg.ch_width == CH_WIDTH_320MHZ; +} + +static void wlan_hdd_set_chandef_for_11be(struct cfg80211_chan_def *chandef, + struct wlan_channel *chan_info) +{ + if (chan_info->ch_width != CH_WIDTH_320MHZ) + return; + + chandef->width = NL80211_CHAN_WIDTH_320; + /* Set center_freq1 to center frequency of complete 320MHz */ + chandef->center_freq1 = chan_info->ch_cfreq2; +} + +#else /* !WLAN_FEATURE_11BE */ +static inline +void wlan_hdd_set_sap_acs_ch_width_320(struct sap_config *sap_config) +{ +} + +static inline +bool wlan_hdd_is_sap_acs_ch_width_320(struct sap_config *sap_config) +{ + return false; +} + +static inline void +wlan_hdd_set_chandef_for_11be(struct cfg80211_chan_def *chandef, + struct wlan_channel *chan_info) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +#ifdef WLAN_FEATURE_11BE +/** + * wlan_hdd_acs_set_eht_enabled() - set is_eht_enabled of acs config + * @sap_config: pointer to sap_config + * @eht_enabled: eht is enabled + * + * Return: void + */ +static void wlan_hdd_acs_set_eht_enabled(struct sap_config *sap_config, + bool eht_enabled) +{ + if (!sap_config) { + hdd_err("Invalid sap_config"); + return; + } + + sap_config->acs_cfg.is_eht_enabled = eht_enabled; +} +#else +static void wlan_hdd_acs_set_eht_enabled(struct sap_config *sap_config, + bool eht_enabled) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +static uint16_t wlan_hdd_update_bw_from_mlme(struct hdd_context *hdd_ctx, + struct sap_config *sap_config) +{ + uint16_t ch_width, temp_ch_width = 0; + QDF_STATUS status; + uint8_t hw_mode = HW_MODE_DBS; + struct wma_caps_per_phy caps_per_phy = {0}; + + ch_width = sap_config->acs_cfg.ch_width; + + if (ch_width > CH_WIDTH_80P80MHZ) + return ch_width; + + /* 2.4ghz is already handled for acs */ + if (sap_config->acs_cfg.end_ch_freq <= + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484)) + return ch_width; + + if (!policy_mgr_is_dbs_enable(hdd_ctx->psoc)) + hw_mode = HW_MODE_DBS_NONE; + + status = wma_get_caps_for_phyidx_hwmode(&caps_per_phy, hw_mode, + CDS_BAND_5GHZ); + if (!QDF_IS_STATUS_SUCCESS(status)) + return ch_width; + + switch (ch_width) { + case CH_WIDTH_80P80MHZ: + if (!(caps_per_phy.vht_5g & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)) + { + if (caps_per_phy.vht_5g & WMI_VHT_CAP_CH_WIDTH_160MHZ) + temp_ch_width = CH_WIDTH_160MHZ; + else + temp_ch_width = CH_WIDTH_80MHZ; + } + break; + case CH_WIDTH_160MHZ: + if (!((caps_per_phy.vht_5g & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) + || (caps_per_phy.vht_5g & WMI_VHT_CAP_CH_WIDTH_160MHZ))) + temp_ch_width = CH_WIDTH_80MHZ; + break; + default: + break; + } + + if (!temp_ch_width) + return ch_width; + + hdd_debug("ch_width updated from %d to %d vht_5g: %x", ch_width, + temp_ch_width, caps_per_phy.vht_5g); + return temp_ch_width; +} + +/** + * wlan_hdd_check_is_acs_request_same() - API to compare ongoing ACS and + * current received ACS request + * @adapter: hdd adapter + * @data: ACS data + * @data_len: ACS data length + * + * This function is used to compare ongoing ACS params with current received + * ACS request on same interface. + * + * Return: true only if ACS request received is same as ongoing ACS + */ +static bool wlan_hdd_check_is_acs_request_same(struct hdd_adapter *adapter, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1]; + uint8_t hw_mode, ht_enabled, ht40_enabled, vht_enabled, eht_enabled; + struct sap_config *sap_config; + uint32_t last_scan_ageout_time = 0; + uint8_t ch_list_count; + uint16_t ch_width; + int ret, i, j; + struct wlan_objmgr_psoc *psoc; + + ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, + data_len, + wlan_hdd_cfg80211_do_acs_policy); + if (ret) { + hdd_err("Invalid ATTR"); + return false; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) + return false; + + sap_config = &adapter->deflink->session.ap.sap_config; + + hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + if (sap_config->acs_cfg.master_acs_cfg.hw_mode != hw_mode) + return false; + + ht_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]); + if (sap_config->acs_cfg.master_acs_cfg.ht != ht_enabled) + return false; + + ht40_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]); + if (sap_config->acs_cfg.master_acs_cfg.ht40 != ht40_enabled) + return false; + + vht_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]); + if (sap_config->acs_cfg.master_acs_cfg.vht != vht_enabled) + return false; + + eht_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED]); + if (sap_config->acs_cfg.master_acs_cfg.eht != eht_enabled) + return false; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) + ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); + else + ch_width = 0; + if (sap_config->acs_cfg.master_acs_cfg.ch_width != ch_width) + return false; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME]) { + last_scan_ageout_time = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME]); + } else { + psoc = wlan_vdev_get_psoc(adapter->deflink->vdev); + if (psoc) + wlan_scan_get_last_scan_ageout_time( + psoc, + &last_scan_ageout_time); + } + if (sap_config->acs_cfg.last_scan_ageout_time != last_scan_ageout_time) + return false; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) { + uint32_t *freq = + nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]); + + ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) / + sizeof(uint32_t); + if (sap_config->acs_cfg.master_ch_list_count != ch_list_count) + return false; + for (i = 0; i < ch_list_count; i++) { + j = 0; + while (j < ch_list_count && freq[i] != + sap_config->acs_cfg.master_freq_list[j]) + j++; + if (j == ch_list_count) + return false; + } + } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) { + uint8_t *tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + + ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + if (sap_config->acs_cfg.master_ch_list_count != ch_list_count) + return false; + for (i = 0; i < ch_list_count; i++) { + j = 0; + while (j < ch_list_count && + wlan_reg_legacy_chan_to_freq( + adapter->hdd_ctx->pdev, tmp[i]) != + sap_config->acs_cfg.master_freq_list[j]) + j++; + if (j == ch_list_count) + return false; + } + } + + return true; +} + +#ifndef WLAN_FEATURE_LL_LT_SAP +/** + * hdd_remove_passive_dfs_acs_channel_for_ll_sap(): Remove passive/dfs channel + * for LL SAP + * @sap_config: Pointer to sap_config + * @psoc: Pointer to psoc + * @pdev: Pointer to pdev + * @vdev_id: Vdev Id + * + * This function will remove passive/dfs acs channel for low latency SAP + * which are configured through userspace. + * + * Return: void + */ +static void hdd_remove_passive_dfs_acs_channel_for_ll_sap( + struct sap_config *sap_config, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + uint32_t i, ch_cnt = 0; + uint32_t freq = 0; + + if (!policy_mgr_is_vdev_ll_sap(psoc, vdev_id)) + return; + + for (i = 0; i < sap_config->acs_cfg.ch_list_count; i++) { + freq = sap_config->acs_cfg.freq_list[i]; + + /* Remove passive/dfs channel for LL SAP */ + if (wlan_reg_is_passive_for_freq(pdev, freq) || + wlan_reg_is_dfs_for_freq(pdev, freq)) + continue; + + sap_config->acs_cfg.freq_list[ch_cnt++] = freq; + } + + if (ch_cnt != sap_config->acs_cfg.ch_list_count) { + hdd_debug("New count after modification %d", ch_cnt); + sap_config->acs_cfg.ch_list_count = ch_cnt; + sap_dump_acs_channel(&sap_config->acs_cfg); + } +} +#else +static inline void +hdd_remove_passive_dfs_acs_channel_for_ll_sap(struct sap_config *sap_config, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ +} +#endif + +/* Stored ACS Frequency timeout in msec */ +#define STORED_ACS_FREQ_TIMEOUT 5000 +static bool +wlan_hdd_is_prev_acs_freq_present_in_acs_config(struct sap_config *sap_cfg) +{ + uint32_t i = 0; + bool prev_acs_freq_found = false; + + if (!qdf_system_time_before( + qdf_get_time_of_the_day_ms(), + sap_cfg->last_acs_complete_time + STORED_ACS_FREQ_TIMEOUT)) + return prev_acs_freq_found; + + for (i = 0; i < sap_cfg->acs_cfg.ch_list_count; i++) { + if (sap_cfg->acs_cfg.freq_list[i] == sap_cfg->last_acs_freq) { + prev_acs_freq_found = true; + break; + } + } + + return prev_acs_freq_found; +} + +static bool +wlan_hdd_ll_lt_sap_get_valid_last_acs_freq(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + struct sap_config *sap_config; + int status; + bool prev_acs_freq_valid = false; + struct sap_context *sap_ctx; + + if (!adapter) { + hdd_err("adapter is NULL"); + return prev_acs_freq_valid; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) { + hdd_err("Invalid HDD context"); + return prev_acs_freq_valid; + } + + sap_config = &adapter->deflink->session.ap.sap_config; + if (!sap_config) { + hdd_err("SAP config is NULL"); + return prev_acs_freq_valid; + } + + if (!sap_config->last_acs_freq || !sap_config->last_acs_complete_time) + return prev_acs_freq_valid; + + if (!policy_mgr_is_vdev_ll_lt_sap( + hdd_ctx->psoc, + adapter->deflink->vdev_id)) + return prev_acs_freq_valid; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (wlan_hdd_is_prev_acs_freq_present_in_acs_config(sap_config)) { + wlansap_update_ll_lt_sap_acs_result(sap_ctx, + sap_config->last_acs_freq); + + hdd_debug("vdev %d, return prev ACS freq %d stored at %lu, current time %lu", + adapter->deflink->vdev_id, sap_config->last_acs_freq, + sap_config->last_acs_complete_time, + qdf_get_time_of_the_day_ms()); + + /* Notify to hostapd without storing the last acs frequency. + * Reason for not storing the last acs frequency is to avoid + * storing the same freq again and again + */ + wlan_hdd_cfg80211_acs_ch_select_evt(adapter->deflink, false); + wlansap_dcs_set_wlan_interference_mitigation_on_band(sap_ctx, + sap_config); + + prev_acs_freq_valid = true; + } + + return prev_acs_freq_valid; +} + +/** + * hdd_remove_6ghz_freq_from_acs_list(): Removed 6 GHz frequecies from ACS list + * @org_freq_list: ACS frequecny list + * @org_ch_list_count: Number of frequencies in ACS list + * + * Return: None + */ +static void hdd_remove_6ghz_freq_from_acs_list(uint32_t *org_freq_list, + uint8_t *org_ch_list_count) +{ + uint16_t i, ch_list_count = 0; + + hdd_debug("Remove 6 GHz channels from ACS list"); + for (i = 0; i < *org_ch_list_count; i++) { + if (wlan_reg_is_6ghz_chan_freq(org_freq_list[i])) + continue; + org_freq_list[ch_list_count++] = org_freq_list[i]; + } + *org_ch_list_count = ch_list_count; +} + +/** + * __wlan_hdd_cfg80211_do_acs(): CFG80211 handler function for DO_ACS Vendor CMD + * @wiphy: Linux wiphy struct pointer + * @wdev: Linux wireless device struct pointer + * @data: ACS information from hostapd + * @data_len: ACS information length + * + * This function handle DO_ACS Vendor command from hostapd, parses ACS config + * and starts ACS procedure. + * + * Return: ACS procedure start status + */ +static int __wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sap_config *sap_config; + struct sap_context *sap_ctx; + struct hdd_ap_ctx *ap_ctx; + struct sk_buff *temp_skbuff; + int ret, i; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1]; + bool ht_enabled, ht40_enabled, vht_enabled, eht_enabled; + uint16_t ch_width; + enum qca_wlan_vendor_acs_hw_mode hw_mode; + enum policy_mgr_con_mode pm_mode; + QDF_STATUS qdf_status; + bool is_vendor_acs_support = false; + bool is_external_acs_policy = false; + bool is_vendor_unsafe_ch_present = false; + bool sap_force_11n_for_11ac = 0; + bool go_force_11n_for_11ac = 0; + bool is_ll_lt_sap = false; + bool sap_force_11n = false; + bool go_11ac_override = 0; + bool sap_11ac_override = 0; + uint8_t vht_ch_width; + uint32_t channel_bonding_mode_2g; + uint32_t last_scan_ageout_time; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + /* ***Note*** Donot set SME config related to ACS operation here because + * ACS operation is not synchronouse and ACS for Second AP may come when + * ACS operation for first AP is going on. So only do_acs is split to + * separate start_acs routine. Also SME-PMAC struct that is used to + * pass parameters from HDD to SAP is global. Thus All ACS related SME + * config shall be set only from start_acs. + */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + ucfg_mlme_get_sap_force_11n_for_11ac(hdd_ctx->psoc, + &sap_force_11n_for_11ac); + ucfg_mlme_get_go_force_11n_for_11ac(hdd_ctx->psoc, + &go_force_11n_for_11ac); + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode_2g); + + if (policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc, link_info->vdev_id)) { + is_ll_lt_sap = true; + policy_mgr_ll_lt_sap_restart_concurrent_sap(hdd_ctx->psoc, + true); + } + + if (is_ll_lt_sap || sap_force_11n_for_11ac) + sap_force_11n = true; + + if (!((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE))) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + if (cds_is_sub_20_mhz_enabled()) { + hdd_err("ACS not supported in sub 20 MHz ch wd."); + return -EINVAL; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + if (qdf_atomic_read(&ap_ctx->acs_in_progress) > 0) { + if (wlan_hdd_check_is_acs_request_same(adapter, + data, data_len)) { + hdd_debug("Same ACS req as ongoing is received, return success"); + ret = 0; + goto out; + } + hdd_err("ACS rejected as previous ACS req already in progress"); + return -EINVAL; + } else { + qdf_atomic_set(&ap_ctx->acs_in_progress, 1); + qdf_event_reset(&link_info->acs_complete_event); + } + + hdd_reg_wait_for_country_change(hdd_ctx); + + ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX, data, + data_len, + wlan_hdd_cfg80211_do_acs_policy); + if (ret) { + hdd_err("Invalid ATTR"); + goto out; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]) { + hdd_err("Attr hw_mode failed"); + ret = -EINVAL; + goto out; + } + + sap_config = &ap_ctx->sap_config; + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + + /* Check and free if memory is already allocated for acs channel list */ + wlan_hdd_undo_acs(link_info); + + qdf_mem_zero(&sap_config->acs_cfg, sizeof(struct sap_acs_cfg)); + + hw_mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE]); + hdd_nofl_info("ACS request vid %d hw mode %d", + link_info->vdev_id, hw_mode); + ht_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED]); + ht40_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED]); + vht_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED]); + eht_enabled = nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED]); + + sap_config->acs_cfg.master_acs_cfg.hw_mode = hw_mode; + sap_config->acs_cfg.master_acs_cfg.ht = ht_enabled; + sap_config->acs_cfg.master_acs_cfg.ht40 = ht40_enabled; + sap_config->acs_cfg.master_acs_cfg.vht = vht_enabled; + sap_config->acs_cfg.master_acs_cfg.eht = eht_enabled; + + if (((adapter->device_mode == QDF_SAP_MODE) && + sap_force_11n) || + ((adapter->device_mode == QDF_P2P_GO_MODE) && + go_force_11n_for_11ac)) { + vht_enabled = 0; + hdd_info("VHT is Disabled in ACS"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]) { + ch_width = nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH]); + sap_config->acs_cfg.master_acs_cfg.ch_width = ch_width; + } else { + if (ht_enabled && ht40_enabled) + ch_width = 40; + else + ch_width = 20; + sap_config->acs_cfg.master_acs_cfg.ch_width = 0; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED]) + eht_enabled = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_ACS_EHT_ENABLED]); + else + eht_enabled = 0; + + if (ch_width == 320 && !eht_enabled) + ch_width = 160; + + /* this may be possible, when sap_force_11n_for_11ac or + * go_force_11n_for_11ac is set + */ + if ((ch_width == 80 || ch_width == 160) && !vht_enabled) { + if (ht_enabled && ht40_enabled) + ch_width = 40; + else + ch_width = 20; + } + if (is_ll_lt_sap) + ch_width = 20; + + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME]) + last_scan_ageout_time = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ACS_LAST_SCAN_AGEOUT_TIME]); + else + wlan_scan_get_last_scan_ageout_time(hdd_ctx->psoc, + &last_scan_ageout_time); + + if (ch_width == 320) + wlan_hdd_set_sap_acs_ch_width_320(sap_config); + else if (ch_width == 160) + sap_config->acs_cfg.ch_width = CH_WIDTH_160MHZ; + else if (ch_width == 80) + sap_config->acs_cfg.ch_width = CH_WIDTH_80MHZ; + else if (ch_width == 40) + sap_config->acs_cfg.ch_width = CH_WIDTH_40MHZ; + else + sap_config->acs_cfg.ch_width = CH_WIDTH_20MHZ; + + /* Firstly try to get channel frequencies */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) { + uint32_t *freq = + nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]); + sap_config->acs_cfg.ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQ_LIST]) / + sizeof(uint32_t); + if (sap_config->acs_cfg.ch_list_count) { + sap_config->acs_cfg.freq_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count * + sizeof(uint32_t)); + sap_config->acs_cfg.master_freq_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count * + sizeof(uint32_t)); + if (!sap_config->acs_cfg.freq_list || + !sap_config->acs_cfg.master_freq_list) { + ret = -ENOMEM; + goto out; + } + + for (i = 0; i < sap_config->acs_cfg.ch_list_count; + i++) { + sap_config->acs_cfg.master_freq_list[i] = + freq[i]; + sap_config->acs_cfg.freq_list[i] = freq[i]; + } + sap_config->acs_cfg.master_ch_list_count = + sap_config->acs_cfg.ch_list_count; + } + } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]) { + uint8_t *tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + + sap_config->acs_cfg.ch_list_count = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST]); + if (sap_config->acs_cfg.ch_list_count) { + sap_config->acs_cfg.freq_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count * + sizeof(uint32_t)); + sap_config->acs_cfg.master_freq_list = qdf_mem_malloc( + sap_config->acs_cfg.ch_list_count * + sizeof(uint32_t)); + if (!sap_config->acs_cfg.freq_list || + !sap_config->acs_cfg.master_freq_list) { + ret = -ENOMEM; + goto out; + } + + /* convert channel to frequency */ + for (i = 0; i < sap_config->acs_cfg.ch_list_count; + i++) { + sap_config->acs_cfg.freq_list[i] = + wlan_reg_legacy_chan_to_freq( + hdd_ctx->pdev, + tmp[i]); + sap_config->acs_cfg.master_freq_list[i] = + sap_config->acs_cfg.freq_list[i]; + } + sap_config->acs_cfg.master_ch_list_count = + sap_config->acs_cfg.ch_list_count; + } + } + + if (!sap_config->acs_cfg.ch_list_count) { + hdd_err("acs config chan count 0"); + ret = -EINVAL; + goto out; + } else { + hdd_nofl_debug("Dump raw ACS chanlist - "); + sap_dump_acs_channel(&sap_config->acs_cfg); + } + + hdd_handle_acs_2g_preferred_sap_conc(hdd_ctx->psoc, adapter, + sap_config); + hdd_avoid_acs_channels(hdd_ctx, sap_config); + + pm_mode = + policy_mgr_qdf_opmode_to_pm_con_mode(hdd_ctx->psoc, + adapter->device_mode, + adapter->deflink->vdev_id); + + /* Remove passive/dfs acs channel for ll sap */ + hdd_remove_passive_dfs_acs_channel_for_ll_sap( + sap_config, hdd_ctx->psoc, + hdd_ctx->pdev, + link_info->vdev_id); + + /* consult policy manager to get PCL */ + qdf_status = policy_mgr_get_pcl(hdd_ctx->psoc, pm_mode, + sap_config->acs_cfg.pcl_chan_freq, + &sap_config->acs_cfg.pcl_ch_count, + sap_config->acs_cfg. + pcl_channels_weight_list, + NUM_CHANNELS, + link_info->vdev_id); + + policy_mgr_get_pcl_channel_for_ll_sap_concurrency( + hdd_ctx->psoc, + link_info->vdev_id, + sap_config->acs_cfg.pcl_chan_freq, + sap_config->acs_cfg.pcl_channels_weight_list, + &sap_config->acs_cfg.pcl_ch_count); + + sap_config->acs_cfg.band = hw_mode; + + qdf_status = ucfg_mlme_get_external_acs_policy(hdd_ctx->psoc, + &is_external_acs_policy); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("get_external_acs_policy failed"); + + sap_config->acs_cfg.acs_mode = true; + + if (wlan_reg_get_keep_6ghz_sta_cli_connection(hdd_ctx->pdev)) + hdd_remove_6ghz_freq_from_acs_list( + sap_config->acs_cfg.freq_list, + &sap_config->acs_cfg.ch_list_count); + + if ((is_external_acs_policy && + policy_mgr_is_force_scc(hdd_ctx->psoc) && + policy_mgr_get_connection_count(hdd_ctx->psoc)) || is_ll_lt_sap) { + if (adapter->device_mode == QDF_SAP_MODE) + is_vendor_unsafe_ch_present = + wlansap_filter_vendor_unsafe_ch_freq(sap_ctx, + sap_config); + wlan_hdd_trim_acs_channel_list( + sap_config->acs_cfg.pcl_chan_freq, + sap_config->acs_cfg.pcl_ch_count, + sap_config->acs_cfg.freq_list, + &sap_config->acs_cfg.ch_list_count); + if (!sap_config->acs_cfg.ch_list_count && + sap_config->acs_cfg.master_ch_list_count && + !is_vendor_unsafe_ch_present && + !is_ll_lt_sap) + wlan_hdd_handle_zero_acs_list( + hdd_ctx, + sap_config->acs_cfg.freq_list, + &sap_config->acs_cfg.ch_list_count, + sap_config->acs_cfg.master_freq_list, + sap_config->acs_cfg.master_ch_list_count); + /* if it is only one channel, send ACS event to upper layer */ + if (sap_config->acs_cfg.ch_list_count == 1) { + wlan_hdd_handle_single_ch_in_acs_list(link_info); + ret = 0; + goto out; + } else if (!sap_config->acs_cfg.ch_list_count) { + hdd_err("channel list count 0"); + ret = -EINVAL; + goto out; + } + } else if (adapter->device_mode == QDF_SAP_MODE) { + wlansap_filter_vendor_unsafe_ch_freq(sap_ctx, sap_config); + if (sap_config->acs_cfg.ch_list_count == 1) { + wlan_hdd_handle_single_ch_in_acs_list(link_info); + ret = 0; + goto out; + } else if (!sap_config->acs_cfg.ch_list_count) { + hdd_err("channel count 0 after vendor unsafe filter"); + ret = -EINVAL; + goto out; + } + } + + ret = wlan_hdd_set_acs_ch_range(sap_config, hw_mode, + ht_enabled, vht_enabled); + if (ret) { + hdd_err("set acs channel range failed"); + goto out; + } + + ucfg_mlme_is_go_11ac_override(hdd_ctx->psoc, &go_11ac_override); + ucfg_mlme_is_sap_11ac_override(hdd_ctx->psoc, &sap_11ac_override); + /* ACS override for android */ + if (ht_enabled && + sap_config->acs_cfg.end_ch_freq >= + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_5180) && + ((adapter->device_mode == QDF_SAP_MODE && + !sap_force_11n && + sap_11ac_override) || + (adapter->device_mode == QDF_P2P_GO_MODE && + !go_force_11n_for_11ac && + go_11ac_override))) { + vht_enabled = 1; + sap_config->acs_cfg.hw_mode = eCSR_DOT11_MODE_11ac; + qdf_status = + ucfg_mlme_get_vht_channel_width(hdd_ctx->psoc, + &vht_ch_width); + ch_width = vht_ch_width; + sap_config->acs_cfg.ch_width = ch_width; + } + + /* Check 2.4ghz cbmode and update BW if only 2.4 channels are present */ + if (sap_config->acs_cfg.end_ch_freq <= + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484) && + sap_config->acs_cfg.ch_width >= eHT_CHANNEL_WIDTH_40MHZ) { + + sap_config->acs_cfg.ch_width = channel_bonding_mode_2g ? + eHT_CHANNEL_WIDTH_40MHZ : eHT_CHANNEL_WIDTH_20MHZ; + + hdd_debug("Only 2.4ghz channels, resetting BW to %d 2.4 cbmode %d", + sap_config->acs_cfg.ch_width, + channel_bonding_mode_2g); + } + + sap_config->acs_cfg.ch_width = wlan_hdd_update_bw_from_mlme(hdd_ctx, + sap_config); + + hdd_nofl_debug("ACS Config country %s ch_width %d hw_mode %d ACS_BW: %d HT: %d VHT: %d EHT: %d START_CH: %d END_CH: %d band %d last_scan_ageout_time %d", + hdd_ctx->reg.alpha2, ch_width, + sap_config->acs_cfg.hw_mode, sap_config->acs_cfg.ch_width, + ht_enabled, vht_enabled, eht_enabled, + sap_config->acs_cfg.start_ch_freq, + sap_config->acs_cfg.end_ch_freq, + sap_config->acs_cfg.band, last_scan_ageout_time); + host_log_acs_req_event(adapter->dev->name, + csr_phy_mode_str(sap_config->acs_cfg.hw_mode), + ch_width, ht_enabled, vht_enabled, + sap_config->acs_cfg.start_ch_freq, + sap_config->acs_cfg.end_ch_freq); + + sap_config->acs_cfg.is_ht_enabled = ht_enabled; + sap_config->acs_cfg.is_vht_enabled = vht_enabled; + wlan_hdd_acs_set_eht_enabled(sap_config, eht_enabled); + sap_config->acs_cfg.last_scan_ageout_time = last_scan_ageout_time; + + sap_dump_acs_channel(&sap_config->acs_cfg); + + if (wlan_hdd_ll_lt_sap_get_valid_last_acs_freq(adapter)) { + ret = 0; + goto out; + } + + qdf_status = ucfg_mlme_get_vendor_acs_support(hdd_ctx->psoc, + &is_vendor_acs_support); + if (QDF_IS_STATUS_ERROR(qdf_status)) + hdd_err("get_vendor_acs_support failed, set default"); + + /* Check if vendor specific acs is enabled */ + if (is_vendor_acs_support) + ret = hdd_start_vendor_acs(adapter); + else + ret = wlan_hdd_cfg80211_start_acs(link_info); + +out: + if (ret == 0) { + temp_skbuff = + wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + NLMSG_HDRLEN); + if (temp_skbuff) + return wlan_cfg80211_vendor_cmd_reply(temp_skbuff); + } + qdf_atomic_set(&ap_ctx->acs_in_progress, 0); + + return ret; +} + +/** + * wlan_hdd_cfg80211_do_acs : CFG80211 handler function for DO_ACS Vendor CMD + * @wiphy: Linux wiphy struct pointer + * @wdev: Linux wireless device struct pointer + * @data: ACS information from hostapd + * @data_len: ACS information len + * + * This function handle DO_ACS Vendor command from hostapd, parses ACS config + * and starts ACS procedure. + * + * Return: ACS procedure start status + */ + +static int wlan_hdd_cfg80211_do_acs(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_do_acs(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +void wlan_hdd_undo_acs(struct wlan_hdd_link_info *link_info) +{ + sap_undo_acs(WLAN_HDD_GET_SAP_CTX_PTR(link_info), + &link_info->session.ap.sap_config); +} + +/** + * hdd_fill_acs_chan_freq() - Populate channel frequencies (MHz) selected in ACS + * @hdd_ctx: pointer to hdd context + * @sap_cfg: sap acs configuration + * @vendor_event: output pointer to populate channel frequencies (MHz) + * + * Return: If populated successfully return 0 else negative value. + */ +static int hdd_fill_acs_chan_freq(struct hdd_context *hdd_ctx, + struct sap_config *sap_cfg, + struct sk_buff *vendor_event) +{ + uint32_t id; + int errno; + + id = QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY; + errno = nla_put_u32(vendor_event, id, sap_cfg->acs_cfg.pri_ch_freq); + if (errno) { + hdd_err("VENDOR_ATTR_ACS_PRIMARY_FREQUENCY put fail"); + return errno; + } + + id = QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY; + errno = nla_put_u32(vendor_event, id, sap_cfg->acs_cfg.ht_sec_ch_freq); + if (errno) { + hdd_err("VENDOR_ATTR_ACS_SECONDARY_FREQUENCY put fail"); + return errno; + } + + id = QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY; + errno = nla_put_u32(vendor_event, id, + sap_cfg->acs_cfg.vht_seg0_center_ch_freq); + if (errno) { + hdd_err("VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY put fail"); + return errno; + } + + id = QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY; + errno = nla_put_u32(vendor_event, id, + sap_cfg->acs_cfg.vht_seg1_center_ch_freq); + if (errno) { + hdd_err("VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY put fail"); + return errno; + } + + return 0; +} + +static int hdd_get_acs_evt_data_len(struct sap_config *sap_cfg) +{ + uint32_t len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_FREQUENCY */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_FREQUENCY */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_FREQUENCY */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_FREQUENCY */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH */ + len += nla_total_size(sizeof(u16)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP */ + if (sap_acs_is_puncture_applicable(&sap_cfg->acs_cfg)) + len += nla_total_size(sizeof(u16)); + + return len; +} + +#ifdef WLAN_FEATURE_11BE +/** + * wlan_hdd_acs_get_puncture_bitmap() - get puncture_bitmap for acs result + * @acs_cfg: pointer to struct sap_acs_cfg + * + * Return: acs puncture bitmap + */ +static uint16_t wlan_hdd_acs_get_puncture_bitmap(struct sap_acs_cfg *acs_cfg) +{ + if (sap_acs_is_puncture_applicable(acs_cfg)) + return acs_cfg->acs_puncture_bitmap; + + return 0; +} +#else +static uint16_t wlan_hdd_acs_get_puncture_bitmap(struct sap_acs_cfg *acs_cfg) +{ + return 0; +} +#endif /* WLAN_FEATURE_11BE */ + +void wlan_hdd_cfg80211_acs_ch_select_evt(struct wlan_hdd_link_info *link_info, + bool store_acs_freq) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sap_config *sap_cfg; + struct sk_buff *vendor_event; + int ret_val; + uint16_t ch_width; + uint8_t pri_channel; + uint8_t ht_sec_channel; + uint8_t vht_seg0_center_ch, vht_seg1_center_ch; + uint32_t id = QCA_NL80211_VENDOR_SUBCMD_DO_ACS_INDEX; + uint32_t len; + uint16_t puncture_bitmap; + + qdf_atomic_set(&link_info->session.ap.acs_in_progress, 0); + qdf_event_set(&link_info->acs_complete_event); + + sap_cfg = &(WLAN_HDD_GET_AP_CTX_PTR(link_info))->sap_config; + len = hdd_get_acs_evt_data_len(sap_cfg); + + if (store_acs_freq && + policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc, + link_info->vdev_id)) { + sap_cfg->last_acs_freq = sap_cfg->acs_cfg.pri_ch_freq; + sap_cfg->last_acs_complete_time = qdf_get_time_of_the_day_ms(); + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &adapter->wdev, len, id, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + ret_val = hdd_fill_acs_chan_freq(hdd_ctx, sap_cfg, vendor_event); + if (ret_val) { + hdd_err("failed to put frequencies"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + pri_channel = wlan_reg_freq_to_chan(hdd_ctx->pdev, + sap_cfg->acs_cfg.pri_ch_freq); + + ht_sec_channel = wlan_reg_freq_to_chan(hdd_ctx->pdev, + sap_cfg->acs_cfg.ht_sec_ch_freq); + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL, + pri_channel); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL, + ht_sec_channel); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + vht_seg0_center_ch = wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_cfg->acs_cfg.vht_seg0_center_ch_freq); + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL, + vht_seg0_center_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + vht_seg1_center_ch = wlan_reg_freq_to_chan( + hdd_ctx->pdev, + sap_cfg->acs_cfg.vht_seg1_center_ch_freq); + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL, + vht_seg1_center_ch); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + if (wlan_hdd_is_sap_acs_ch_width_320(sap_cfg)) + ch_width = 320; + else if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_160MHZ) + ch_width = 160; + else if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_80MHZ) + ch_width = 80; + else if (sap_cfg->acs_cfg.ch_width == CH_WIDTH_40MHZ) + ch_width = 40; + else + ch_width = 20; + + ret_val = nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH, + ch_width); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_cfg->acs_cfg.pri_ch_freq)) + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211G); + else + ret_val = nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, + QCA_ACS_MODE_IEEE80211A); + + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + puncture_bitmap = wlan_hdd_acs_get_puncture_bitmap(&sap_cfg->acs_cfg); + if (sap_acs_is_puncture_applicable(&sap_cfg->acs_cfg)) { + ret_val = nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP, + puncture_bitmap); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_ACS_PUNCTURE_BITMAP put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + } + + hdd_debug("ACS result for %s: PRI_CH_FREQ: %d SEC_CH_FREQ: %d VHT_SEG0: %d VHT_SEG1: %d ACS_BW: %d punc support: %d punc bitmap: %d", + adapter->dev->name, sap_cfg->acs_cfg.pri_ch_freq, + sap_cfg->acs_cfg.ht_sec_ch_freq, + sap_cfg->acs_cfg.vht_seg0_center_ch_freq, + sap_cfg->acs_cfg.vht_seg1_center_ch_freq, ch_width, + sap_acs_is_puncture_applicable(&sap_cfg->acs_cfg), + puncture_bitmap); + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * hdd_is_wlm_latency_manager_supported - Checks if WLM Latency manager is + * supported + * @hdd_ctx: The HDD context + * + * Return: True if supported, false otherwise + */ +static inline +bool hdd_is_wlm_latency_manager_supported(struct hdd_context *hdd_ctx) +{ + bool latency_enable; + + if (QDF_IS_STATUS_ERROR(ucfg_mlme_get_latency_enable + (hdd_ctx->psoc, &latency_enable))) + return false; + + if (latency_enable && + sme_is_feature_supported_by_fw(VDEV_LATENCY_CONFIG)) + return true; + else + return false; +} + +static int +__wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb = NULL; + uint32_t fset = 0; + int ret; +#ifdef FEATURE_WLAN_TDLS + bool bvalue; +#endif + uint32_t fine_time_meas_cap; + + /* ENTER_DEV() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { + hdd_debug("Infra Station mode is supported by driver"); + fset |= WIFI_FEATURE_INFRA; + } + if (true == hdd_is_5g_supported(hdd_ctx)) { + hdd_debug("INFRA_5G is supported by firmware"); + fset |= WIFI_FEATURE_INFRA_5G; + } +#ifdef WLAN_FEATURE_P2P + if ((wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) && + (wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_GO))) { + hdd_debug("WiFi-Direct is supported by driver"); + fset |= WIFI_FEATURE_P2P; + } +#endif + fset |= WIFI_FEATURE_SOFT_AP; + + /* HOTSPOT is a supplicant feature, enable it by default */ + fset |= WIFI_FEATURE_HOTSPOT; + + if (ucfg_extscan_get_enable(hdd_ctx->psoc) && + sme_is_feature_supported_by_fw(EXTENDED_SCAN)) { + hdd_debug("EXTScan is supported by firmware"); + fset |= WIFI_FEATURE_EXTSCAN | WIFI_FEATURE_HAL_EPNO; + } + if (wlan_hdd_nan_is_supported(hdd_ctx)) { + hdd_debug("NAN is supported by firmware"); + fset |= WIFI_FEATURE_NAN; + } + + ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, &fine_time_meas_cap); + + if (sme_is_feature_supported_by_fw(RTT) && + rtt_is_enabled(fine_time_meas_cap)) { + hdd_debug("RTT is supported by firmware and driver: %x", + fine_time_meas_cap); + fset |= WIFI_FEATURE_D2D_RTT; + fset |= WIFI_FEATURE_D2AP_RTT; + } +#ifdef FEATURE_WLAN_SCAN_PNO + if (ucfg_scan_get_pno_scan_support(hdd_ctx->psoc) && + sme_is_feature_supported_by_fw(PNO)) { + hdd_debug("PNO is supported by firmware"); + fset |= WIFI_FEATURE_PNO; + } +#endif + if (ucfg_policy_mgr_get_dual_sta_feature(hdd_ctx->psoc)) + fset |= WIFI_FEATURE_ADDITIONAL_STA; + +#ifdef FEATURE_WLAN_TDLS + cfg_tdls_get_support_enable(hdd_ctx->psoc, &bvalue); + if ((bvalue) && sme_is_feature_supported_by_fw(TDLS)) { + hdd_debug("TDLS is supported by firmware"); + fset |= WIFI_FEATURE_TDLS; + } + + cfg_tdls_get_off_channel_enable(hdd_ctx->psoc, &bvalue); + if (sme_is_feature_supported_by_fw(TDLS) && + bvalue && sme_is_feature_supported_by_fw(TDLS_OFF_CHANNEL)) { + hdd_debug("TDLS off-channel is supported by firmware"); + fset |= WIFI_FEATURE_TDLS_OFFCHANNEL; + } +#endif + fset |= WIFI_FEATURE_AP_STA; + fset |= WIFI_FEATURE_RSSI_MONITOR; + fset |= WIFI_FEATURE_TX_TRANSMIT_POWER; + fset |= WIFI_FEATURE_SET_TX_POWER_LIMIT; + fset |= WIFI_FEATURE_CONFIG_NDO; + + if (hdd_link_layer_stats_supported()) + fset |= WIFI_FEATURE_LINK_LAYER_STATS; + + if (hdd_roaming_supported(hdd_ctx)) + fset |= WIFI_FEATURE_CONTROL_ROAMING; + + if (hdd_scan_random_mac_addr_supported()) + fset |= WIFI_FEATURE_SCAN_RAND; + + if (hdd_is_wlm_latency_manager_supported(hdd_ctx)) + fset |= WIFI_FEATURE_SET_LATENCY_MODE; + + if (hdd_dynamic_mac_addr_supported(hdd_ctx)) + fset |= WIFI_FEATURE_DYNAMIC_SET_MAC; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(fset) + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -EINVAL; + } + hdd_debug("Supported Features : 0x%x", fset); + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_SET, fset)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + ret = wlan_cfg80211_vendor_cmd_reply(skb); + return ret; +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_supported_features() - get supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_supported_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_supported_features(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Set the MAC address that is to be used for scanning. + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct scan_mac_oui scan_mac_oui = { {0} }; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX + 1]; + QDF_STATUS status; + int ret, len; + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + mac_handle_t mac_handle; + bool mac_spoofing_enabled; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + mac_spoofing_enabled = ucfg_scan_is_mac_spoofing_enabled(hdd_ctx->psoc); + if (!mac_spoofing_enabled) { + hdd_debug("MAC address spoofing is not enabled"); + return -ENOTSUPP; + } + + /* + * audit note: it is ok to pass a NULL policy here since only + * one attribute is parsed and it is explicitly validated + */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]) { + hdd_err("attr mac oui failed"); + return -EINVAL; + } + + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI]); + if (len != sizeof(scan_mac_oui.oui)) { + hdd_err("attr mac oui invalid size %d expected %zu", + len, sizeof(scan_mac_oui.oui)); + return -EINVAL; + } + + nla_memcpy(scan_mac_oui.oui, + tb[QCA_WLAN_VENDOR_ATTR_SET_SCANNING_MAC_OUI], + sizeof(scan_mac_oui.oui)); + + /* populate rest of scan_mac_oui for mac addr randomization */ + scan_mac_oui.vdev_id = adapter->deflink->vdev_id; + scan_mac_oui.enb_probe_req_sno_randomization = true; + + hdd_debug("Oui (%02x:%02x:%02x), vdev_id = %d", + scan_mac_oui.oui[0], scan_mac_oui.oui[1], + scan_mac_oui.oui[2], scan_mac_oui.vdev_id); + + hdd_update_ie_allowlist_attr(&scan_mac_oui.ie_allowlist, hdd_ctx); + + mac_handle = hdd_ctx->mac_handle; + status = sme_set_scanning_mac_oui(mac_handle, &scan_mac_oui); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("sme_set_scanning_mac_oui failed(err=%d)", status); + + return qdf_status_to_os_return(status); +} + +/** + * wlan_hdd_cfg80211_set_scanning_mac_oui() - set scan MAC + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Set the MAC address that is to be used for scanning. This is an + * SSR-protecting wrapper function. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_scanning_mac_oui(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_scanning_mac_oui(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define NUM_BITS_IN_BYTE 8 + +/** + * wlan_hdd_cfg80211_set_feature() - Set the bitmask for supported features + * @feature_flags: pointer to the byte array of features. + * @feature: Feature to be turned ON in the byte array. + * + * Return: None + * + * This is called to turn ON or SET the feature flag for the requested feature. + **/ +static void wlan_hdd_cfg80211_set_feature(uint8_t *feature_flags, + uint8_t feature) +{ + uint32_t index; + uint8_t bit_mask; + + index = feature / NUM_BITS_IN_BYTE; + bit_mask = 1 << (feature % NUM_BITS_IN_BYTE); + feature_flags[index] |= bit_mask; +} + +/** + * wlan_hdd_set_ndi_feature() - Set NDI related features + * @feature_flags: pointer to the byte array of features. + * + * Return: None + **/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +static void wlan_hdd_set_ndi_feature(uint8_t *feature_flags) +{ + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_USE_ADD_DEL_VIRTUAL_INTF_FOR_NDI); +} +#else +static inline void wlan_hdd_set_ndi_feature(uint8_t *feature_flags) +{ +} +#endif + +static inline void wlan_hdd_set_ll_lt_sap_feature(struct wlan_objmgr_psoc *psoc, + uint8_t *feature_flags) +{ + /* To Do: Once FW feature capability changes for ll_lt_sap feature are + * merged, then this feature will be set based on that feature set + * capability + */ + if (!ucfg_is_ll_lt_sap_supported(psoc)) { + hdd_debug("ll_lt_sap feature is disabled in FW"); + return; + } + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_ENHANCED_AUDIO_EXPERIENCE_OVER_WLAN); +} + +#define MAX_CONCURRENT_CHAN_ON_24G 2 +#define MAX_CONCURRENT_CHAN_ON_5G 2 + +/** + * __wlan_hdd_cfg80211_get_features() - Get the Driver Supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send supported feature set to + * supplicant upon a request/query from the supplicant. + * + * Return: Return the Success or Failure code. + **/ +static int +__wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct sk_buff *skb = NULL; + uint32_t dbs_capability = 0; + bool one_by_one_dbs, two_by_two_dbs; + bool value, twt_req, twt_res; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + QDF_STATUS status; + int ret_val; + uint8_t max_assoc_cnt = 0; + uint8_t max_str_link_count = 0; + + uint8_t feature_flags[(NUM_QCA_WLAN_VENDOR_FEATURES + 7) / 8] = {0}; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + hdd_enter_dev(wdev->netdev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (roaming_offload_enabled(hdd_ctx)) { + hdd_debug("Key Mgmt Offload is supported"); + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD); + } + + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_SUPPORT_HW_MODE_ANY); + if (policy_mgr_is_scan_simultaneous_capable(hdd_ctx->psoc)) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OFFCHANNEL_SIMULTANEOUS); + + if (policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc)) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_CONCURRENT_BAND_SESSIONS); + + if (wma_is_p2p_lo_capable()) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_P2P_LISTEN_OFFLOAD); + + value = false; + status = ucfg_mlme_get_oce_sta_enabled_info(hdd_ctx->psoc, &value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not get OCE STA enable info"); + if (value) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OCE_STA); + + value = false; + status = ucfg_mlme_get_oce_sap_enabled_info(hdd_ctx->psoc, &value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not get OCE SAP enable info"); + if (value) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_OCE_STA_CFON); + + value = false; + status = ucfg_mlme_get_adaptive11r_enabled(hdd_ctx->psoc, &value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not get FT-Adaptive 11R info"); + if (value) { + hdd_debug("FT-Adaptive 11R is Enabled"); + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_ADAPTIVE_11R); + } + + hdd_get_twt_requestor(hdd_ctx->psoc, &twt_req); + hdd_get_twt_responder(hdd_ctx->psoc, &twt_res); + hdd_debug("twt_req:%d twt_res:%d", twt_req, twt_res); + + if (twt_req || twt_res) { + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_TWT); + + wlan_hdd_cfg80211_set_feature( + feature_flags, + QCA_WLAN_VENDOR_FEATURE_TWT_ASYNC_SUPPORT); + } + + /* Check the kernel version for upstream commit aced43ce780dc5 that + * has support for processing user cell_base hints when wiphy is + * self managed or check the backport flag for the same. + */ +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY); +#endif + + if (wlan_hdd_thermal_config_support()) + wlan_hdd_cfg80211_set_feature(feature_flags, + QCA_WLAN_VENDOR_FEATURE_THERMAL_CONFIG); + + wlan_hdd_set_ndi_feature(feature_flags); + wlan_hdd_cfg80211_set_feature( + feature_flags, + QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST); + wlan_wifi_pos_cfg80211_set_features(hdd_ctx->psoc, feature_flags); + wlan_hdd_set_ll_lt_sap_feature(hdd_ctx->psoc, feature_flags); + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(feature_flags) + + NLMSG_HDRLEN); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS, + sizeof(feature_flags), feature_flags)) + goto nla_put_failure; + + ret = policy_mgr_get_dbs_hw_modes(hdd_ctx->psoc, + &one_by_one_dbs, &two_by_two_dbs); + if (QDF_STATUS_SUCCESS == ret) { + if (one_by_one_dbs) + dbs_capability = DRV_DBS_CAPABILITY_1X1; + + if (two_by_two_dbs) + dbs_capability = DRV_DBS_CAPABILITY_2X2; + + if (!one_by_one_dbs && !two_by_two_dbs) + dbs_capability = DRV_DBS_CAPABILITY_DISABLED; + } else { + hdd_err("wma_get_dbs_hw_mode failed"); + dbs_capability = DRV_DBS_CAPABILITY_DISABLED; + } + + hdd_debug("dbs_capability is %d", dbs_capability); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_CONCURRENCY_CAPA, + dbs_capability)) + goto nla_put_failure; + + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_2_4_BAND, + MAX_CONCURRENT_CHAN_ON_24G)) + goto nla_put_failure; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_MAX_CONCURRENT_CHANNELS_5_0_BAND, + MAX_CONCURRENT_CHAN_ON_5G)) + goto nla_put_failure; + + max_assoc_cnt = wlan_mlme_get_sta_mlo_conn_max_num(hdd_ctx->psoc); + if (max_assoc_cnt) { + if (nla_put_u8( + skb, + QCA_WLAN_VENDOR_ATTR_MLO_CAPABILITY_MAX_ASSOCIATION_COUNT, + max_assoc_cnt)) + goto nla_put_failure; + + max_str_link_count = DEFAULT_MAX_STR_LINK_COUNT; + + if (policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) || + policy_mgr_is_hw_sbs_capable(hdd_ctx->psoc)) + max_str_link_count = MAX_STR_LINK_COUNT; + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_MLO_CAPABILITY_MAX_STR_LINK_COUNT, + max_str_link_count)) + goto nla_put_failure; + } + + hdd_debug("max_assoc_cnt %d max_str_link_count %d", + max_assoc_cnt, max_str_link_count); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + feature_flags, sizeof(feature_flags)); + + return wlan_cfg80211_vendor_cmd_reply(skb); + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_features() - Get the Driver Supported features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send supported feature set to + * supplicant upon a request/query from the supplicant. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_features(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_features(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#define PARAM_NUM_NW \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS +#define PARAM_SET_BSSID \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID +#define PARAM_SET_BSSID_HINT \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_HINT +#define PARAM_SSID_LIST QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST +#define PARAM_LIST_SSID QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID +#define MAX_ROAMING_PARAM \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX +#define PARAM_NUM_BSSID \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_NUM_BSSID +#define PARAM_BSSID_PREFS \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS +#define PARAM_ROAM_BSSID \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_BSSID +#define PARAM_RSSI_MODIFIER \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_RSSI_MODIFIER +#define PARAMS_NUM_BSSID \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID +#define PARAM_BSSID_PARAMS \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS +#define PARAM_A_BAND_BOOST_THLD \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_THRESHOLD +#define PARAM_A_BAND_PELT_THLD \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_THRESHOLD +#define PARAM_A_BAND_BOOST_FACTOR \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_BOOST_FACTOR +#define PARAM_A_BAND_PELT_FACTOR \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_PENALTY_FACTOR +#define PARAM_A_BAND_MAX_BOOST \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_A_BAND_MAX_BOOST +#define PARAM_ROAM_HISTERESYS \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_LAZY_ROAM_HISTERESYS +#define PARAM_RSSI_TRIGGER \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_ALERT_ROAM_RSSI_TRIGGER +#define PARAM_ROAM_ENABLE \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_LAZY_ROAM_ENABLE +#define PARAM_ROAM_CONTROL_CONFIG \ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_CONTROL +#define PARAM_FREQ_LIST_SCHEME \ + QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME +#define PARAM_FREQ_LIST_SCHEME_MAX \ + QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_SCHEME_MAX +#define PARAM_SCAN_FREQ_LIST \ + QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST +#define PARAM_SCAN_FREQ_LIST_TYPE \ + QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST_TYPE +#define PARAM_CAND_SEL_CRITERIA_MAX \ + QCA_ATTR_ROAM_CAND_SEL_CRITERIA_RATE_MAX +#define PARAM_CAND_SEL_SCORE_RSSI \ + QCA_ATTR_ROAM_CAND_SEL_CRITERIA_SCORE_RSSI + +const struct nla_policy wlan_hdd_set_roam_param_policy[ + MAX_ROAMING_PARAM + 1] = { + [QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID] = {.type = NLA_U32}, + [PARAM_NUM_NW] = {.type = NLA_U32}, + [PARAM_SSID_LIST] = { .type = NLA_NESTED }, + [PARAM_LIST_SSID] = { .type = NLA_BINARY }, + [PARAM_A_BAND_BOOST_FACTOR] = {.type = NLA_U32}, + [PARAM_A_BAND_PELT_FACTOR] = {.type = NLA_U32}, + [PARAM_A_BAND_MAX_BOOST] = {.type = NLA_U32}, + [PARAM_ROAM_HISTERESYS] = {.type = NLA_S32}, + [PARAM_A_BAND_BOOST_THLD] = {.type = NLA_S32}, + [PARAM_A_BAND_PELT_THLD] = {.type = NLA_S32}, + [PARAM_RSSI_TRIGGER] = {.type = NLA_U32}, + [PARAM_ROAM_ENABLE] = { .type = NLA_S32}, + [PARAM_BSSID_PREFS] = { .type = NLA_NESTED }, + [PARAM_NUM_BSSID] = {.type = NLA_U32}, + [PARAM_RSSI_MODIFIER] = {.type = NLA_U32}, + [PARAM_BSSID_PARAMS] = {.type = NLA_NESTED}, + [PARAMS_NUM_BSSID] = {.type = NLA_U32}, + [PARAM_ROAM_BSSID] = VENDOR_NLA_POLICY_MAC_ADDR, + [PARAM_SET_BSSID] = VENDOR_NLA_POLICY_MAC_ADDR, + [PARAM_SET_BSSID_HINT] = {.type = NLA_FLAG}, + [PARAM_ROAM_CONTROL_CONFIG] = {.type = NLA_NESTED}, +}; + +/** + * hdd_set_allow_list() - parse allow list + * @hdd_ctx: HDD context + * @rso_config: rso config + * @tb: list of attributes + * @vdev_id: vdev id + * @rso_usr_cfg: roam userspace params + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_allow_list(struct hdd_context *hdd_ctx, + struct rso_config_params *rso_config, + struct nlattr **tb, uint8_t vdev_id, + struct rso_user_config *rso_usr_cfg) +{ + int rem, i; + uint32_t buf_len = 0, count; + struct nlattr *tb2[MAX_ROAMING_PARAM + 1]; + struct nlattr *curr_attr = NULL; + mac_handle_t mac_handle; + struct wlan_ssid *ssid; + + i = 0; + if (tb[PARAM_NUM_NW]) { + count = nla_get_u32(tb[PARAM_NUM_NW]); + } else { + hdd_err("Number of networks is not provided"); + goto fail; + } + + if (count && tb[PARAM_SSID_LIST]) { + nla_for_each_nested(curr_attr, + tb[PARAM_SSID_LIST], rem) { + if (i == MAX_SSID_ALLOWED_LIST) { + hdd_err("Excess MAX_SSID_ALLOWED_LIST"); + goto fail; + } + if (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), + nla_len(curr_attr), + wlan_hdd_set_roam_param_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + /* Parse and Fetch allowed SSID list*/ + if (!tb2[PARAM_LIST_SSID]) { + hdd_err("attr allowed ssid failed"); + goto fail; + } + buf_len = nla_len(tb2[PARAM_LIST_SSID]); + /* + * Upper Layers include a null termination + * character. Check for the actual permissible + * length of SSID and also ensure not to copy + * the NULL termination character to the driver + * buffer. + */ + if (buf_len <= 1 || (buf_len - 1) > WLAN_SSID_MAX_LEN) { + hdd_err("Invalid buffer length"); + continue; + } + + ssid = &rso_usr_cfg->ssid_allowed_list[i]; + nla_memcpy(ssid->ssid, + tb2[PARAM_LIST_SSID], buf_len - 1); + ssid->length = buf_len - 1; + hdd_debug("SSID[%d]: " QDF_SSID_FMT ",length = %d", i, + QDF_SSID_REF(ssid->length, ssid->ssid), + rso_usr_cfg->ssid_allowed_list[i].length); + i++; + } + } + + if (i != count) { + hdd_err("Invalid number of SSIDs i = %d, count = %d", i, count); + goto fail; + } + + rso_usr_cfg->num_ssid_allowed_list = i; + hdd_debug("Num of Allowed SSID %d", rso_usr_cfg->num_ssid_allowed_list); + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_params(mac_handle, vdev_id, rso_config, rso_usr_cfg, + REASON_ROAM_SET_SSID_ALLOWED); + return 0; + +fail: + return -EINVAL; +} + +/** + * hdd_set_bssid_prefs() - parse set bssid prefs + * @hdd_ctx: HDD context + * @rso_config: rso config + * @tb: list of attributes + * @vdev_id: vdev id + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_bssid_prefs(struct hdd_context *hdd_ctx, + struct rso_config_params *rso_config, + struct nlattr **tb, uint8_t vdev_id) +{ + int rem, i; + uint32_t count; + struct nlattr *tb2[MAX_ROAMING_PARAM + 1]; + struct nlattr *curr_attr = NULL; + mac_handle_t mac_handle; + + /* Parse and fetch number of preferred BSSID */ + if (!tb[PARAM_NUM_BSSID]) { + hdd_err("attr num of preferred bssid failed"); + goto fail; + } + count = nla_get_u32(tb[PARAM_NUM_BSSID]); + if (count > MAX_BSSID_FAVORED) { + hdd_err("Preferred BSSID count %u exceeds max %u", + count, MAX_BSSID_FAVORED); + goto fail; + } + hdd_debug("Num of Preferred BSSID (%d)", count); + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS]) { + hdd_err("attr Preferred BSSID failed"); + goto fail; + } + + i = 0; + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PREFS], + rem) { + if (i == count) { + hdd_warn("Ignoring excess Preferred BSSID"); + break; + } + + if (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), + nla_len(curr_attr), + wlan_hdd_set_roam_param_policy)) { + hdd_err("nla_parse failed"); + goto fail; + } + /* Parse and fetch MAC address */ + if (!tb2[PARAM_ROAM_BSSID]) { + hdd_err("attr mac address failed"); + goto fail; + } + nla_memcpy(rso_config->bssid_favored[i].bytes, + tb2[PARAM_ROAM_BSSID], + QDF_MAC_ADDR_SIZE); + hdd_debug(QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(rso_config->bssid_favored[i].bytes)); + /* Parse and fetch preference factor*/ + if (!tb2[PARAM_RSSI_MODIFIER]) { + hdd_err("BSSID Preference score failed"); + goto fail; + } + rso_config->bssid_favored_factor[i] = nla_get_u32( + tb2[PARAM_RSSI_MODIFIER]); + hdd_debug("BSSID Preference score (%d)", + rso_config->bssid_favored_factor[i]); + i++; + } + if (i < count) + hdd_warn("Num Preferred BSSID %u less than expected %u", + i, count); + + rso_config->num_bssid_favored = i; + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_params(mac_handle, vdev_id, rso_config, NULL, + REASON_ROAM_SET_FAVORED_BSSID); + + return 0; + +fail: + return -EINVAL; +} + +/** + * hdd_set_denylist_bssid() - parse set denylist bssid + * @hdd_ctx: HDD context + * @rso_config: roam params + * @tb: list of attributes + * @vdev_id: vdev id + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_denylist_bssid(struct hdd_context *hdd_ctx, + struct rso_config_params *rso_config, + struct nlattr **tb, + uint8_t vdev_id) +{ + int rem, i; + uint32_t count; + uint8_t j = 0; + struct nlattr *tb2[MAX_ROAMING_PARAM + 1]; + struct nlattr *curr_attr = NULL; + struct qdf_mac_addr *deny_list_bssid; + mac_handle_t mac_handle; + + /* Parse and fetch number of denylist BSSID */ + if (!tb[PARAMS_NUM_BSSID]) { + hdd_err("attr num of denylist bssid failed"); + goto fail; + } + count = nla_get_u32(tb[PARAMS_NUM_BSSID]); + if (count > MAX_BSSID_AVOID_LIST) { + hdd_err("Denylist BSSID count %u exceeds max %u", + count, MAX_BSSID_AVOID_LIST); + goto fail; + } + hdd_debug("Num of denylist BSSID (%d)", count); + deny_list_bssid = qdf_mem_malloc(sizeof(*deny_list_bssid) * + MAX_BSSID_AVOID_LIST); + if (!deny_list_bssid) + goto fail; + + i = 0; + if (count && tb[PARAM_BSSID_PARAMS]) { + nla_for_each_nested(curr_attr, + tb[PARAM_BSSID_PARAMS], + rem) { + if (i == count) { + hdd_warn("Ignoring excess Denylist BSSID"); + break; + } + + if (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX, + nla_data(curr_attr), + nla_len(curr_attr), + wlan_hdd_set_roam_param_policy)) { + hdd_err("nla_parse failed"); + qdf_mem_free(deny_list_bssid); + goto fail; + } + /* Parse and fetch MAC address */ + if (!tb2[PARAM_SET_BSSID]) { + hdd_err("attr denylist addr failed"); + qdf_mem_free(deny_list_bssid); + goto fail; + } + if (tb2[PARAM_SET_BSSID_HINT]) { + struct reject_ap_info ap_info; + + qdf_mem_zero(&ap_info, + sizeof(struct reject_ap_info)); + nla_memcpy(ap_info.bssid.bytes, + tb2[PARAM_SET_BSSID], + QDF_MAC_ADDR_SIZE); + ap_info.reject_ap_type = USERSPACE_AVOID_TYPE; + ap_info.reject_reason = + REASON_USERSPACE_AVOID_LIST; + ap_info.source = ADDED_BY_DRIVER; + + /* This BSSID is avoided and not denylisted */ + ucfg_dlm_add_bssid_to_reject_list(hdd_ctx->pdev, + &ap_info); + i++; + continue; + } + nla_memcpy(deny_list_bssid[j].bytes, + tb2[PARAM_SET_BSSID], QDF_MAC_ADDR_SIZE); + hdd_debug(QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(deny_list_bssid[j].bytes)); + i++; + j++; + } + } + + if (i < count) + hdd_warn("Num Denylist BSSID %u less than expected %u", + i, count); + + /* Send the denylist to the denylist mgr component */ + ucfg_dlm_add_userspace_deny_list(hdd_ctx->pdev, deny_list_bssid, j); + qdf_mem_free(deny_list_bssid); + mac_handle = hdd_ctx->mac_handle; + sme_update_roam_params(mac_handle, vdev_id, rso_config, NULL, + REASON_ROAM_SET_DENYLIST_BSSID); + + return 0; +fail: + return -EINVAL; +} + +static const struct nla_policy +roam_scan_freq_list_scheme_policy[PARAM_FREQ_LIST_SCHEME_MAX + 1] = { + [PARAM_SCAN_FREQ_LIST_TYPE] = {.type = NLA_U32}, + [PARAM_SCAN_FREQ_LIST] = {.type = NLA_NESTED}, +}; + +/** + * hdd_send_roam_scan_channel_freq_list_to_sme() - Send control roam scan freqs + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @tb: Nested attribute carrying frequency list scheme + * + * Extracts the frequency list and frequency list type from the frequency + * list scheme and send the frequencies to SME. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_roam_scan_channel_freq_list_to_sme(struct hdd_context *hdd_ctx, + uint8_t vdev_id, struct nlattr *tb) +{ + QDF_STATUS status; + struct nlattr *tb2[PARAM_FREQ_LIST_SCHEME_MAX + 1], *curr_attr; + uint8_t num_chan = 0; + uint32_t freq_list[SIR_MAX_SUPPORTED_CHANNEL_LIST] = {0}; + uint32_t list_type; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int rem; + + if (wlan_cfg80211_nla_parse_nested(tb2, PARAM_FREQ_LIST_SCHEME_MAX, + tb, + roam_scan_freq_list_scheme_policy)) { + hdd_err("nla_parse failed"); + return QDF_STATUS_E_INVAL; + } + + if (!tb2[PARAM_SCAN_FREQ_LIST] || !tb2[PARAM_SCAN_FREQ_LIST_TYPE]) { + hdd_err("ROAM_CONTROL_SCAN_FREQ_LIST or type are not present"); + return QDF_STATUS_E_INVAL; + } + + list_type = nla_get_u32(tb2[PARAM_SCAN_FREQ_LIST_TYPE]); + if (list_type != QCA_PREFERRED_SCAN_FREQ_LIST && + list_type != QCA_SPECIFIC_SCAN_FREQ_LIST) { + hdd_err("Invalid freq list type received: %u", list_type); + return QDF_STATUS_E_INVAL; + } + + nla_for_each_nested(curr_attr, tb2[PARAM_SCAN_FREQ_LIST], rem) { + if (num_chan >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_chan, SIR_MAX_SUPPORTED_CHANNEL_LIST); + return QDF_STATUS_E_INVAL; + } + num_chan++; + } + num_chan = 0; + + nla_for_each_nested(curr_attr, tb2[PARAM_SCAN_FREQ_LIST], rem) { + if (nla_len(curr_attr) != sizeof(uint32_t)) { + hdd_err("len is not correct for frequency %d", + num_chan); + return QDF_STATUS_E_INVAL; + } + freq_list[num_chan++] = nla_get_u32(curr_attr); + } + + status = sme_update_roam_scan_freq_list(mac_handle, vdev_id, freq_list, + num_chan, list_type); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to update channel list information"); + + return status; +} + +static const struct nla_policy +roam_control_policy[QCA_ATTR_ROAM_CONTROL_MAX + 1] = { + [QCA_ATTR_ROAM_CONTROL_ENABLE] = {.type = NLA_U8}, + [QCA_ATTR_ROAM_CONTROL_STATUS] = {.type = NLA_U8}, + [PARAM_FREQ_LIST_SCHEME] = {.type = NLA_NESTED}, + [QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_CLEAR_ALL] = {.type = NLA_FLAG}, + [QCA_ATTR_ROAM_CONTROL_TRIGGERS] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA] = {.type = NLA_NESTED}, + [QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_2P4GHZ] = { + .type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_5GHZ] = { + .type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_6GHZ] = { + .type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_USER_REASON] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_BAND_MASK] = {.type = NLA_U32}, + [QCA_ATTR_ROAM_CONTROL_RX_LINKSPEED_THRESHOLD] = {.type = NLA_U16}, + [QCA_ATTR_ROAM_CONTROL_HO_DELAY_FOR_RX] = {.type = NLA_U16}, + [QCA_ATTR_ROAM_CONTROL_FULL_SCAN_NO_REUSE_PARTIAL_SCAN_FREQ] = { + .type = NLA_U8}, + [QCA_ATTR_ROAM_CONTROL_FULL_SCAN_6GHZ_ONLY_ON_PRIOR_DISCOVERY] = { + .type = NLA_U8}, + [QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET] = {.type = NLA_U8}, +}; + +/** + * hdd_send_roam_full_scan_period_to_sme() - Send full roam scan period to SME + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @full_roam_scan_period: Idle period in seconds between two successive + * full channel roam scans + * @check_and_update: If this is true/set, update the value only if the current + * configured value is not same as global value read from + * ini param. This is to give priority to the user configured + * values and retain the value, if updated already. + * If this is not set, update the value without any check. + * + * Validate the full roam scan period and send it to firmware + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_roam_full_scan_period_to_sme(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + uint32_t full_roam_scan_period, + bool check_and_update) +{ + QDF_STATUS status; + uint32_t full_roam_scan_period_current, full_roam_scan_period_global; + + if (!ucfg_mlme_validate_full_roam_scan_period(full_roam_scan_period)) + return QDF_STATUS_E_INVAL; + + hdd_debug("Received Command to Set full roam scan period = %u", + full_roam_scan_period); + + status = sme_get_full_roam_scan_period(hdd_ctx->mac_handle, vdev_id, + &full_roam_scan_period_current); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + full_roam_scan_period_global = + sme_get_full_roam_scan_period_global(hdd_ctx->mac_handle); + if (check_and_update && + full_roam_scan_period_current != full_roam_scan_period_global) { + hdd_debug("Full roam scan period is already updated, value: %u", + full_roam_scan_period_current); + return QDF_STATUS_SUCCESS; + } + status = sme_update_full_roam_scan_period(hdd_ctx->mac_handle, vdev_id, + full_roam_scan_period); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set full scan period"); + + return status; +} + +/** + * wlan_hdd_convert_control_roam_trigger_bitmap - Convert the + * vendor specific reason code to internal reason code. + * @trigger_reason_bitmap: Vendor specific roam trigger bitmap + * + * Return: Internal roam trigger bitmap + */ +static uint32_t +wlan_hdd_convert_control_roam_trigger_bitmap(uint32_t trigger_reason_bitmap) +{ + uint32_t drv_trigger_bitmap = 0, all_bitmap; + + /* Enable the complete trigger bitmap when all bits are set in + * the control config bitmap + */ + all_bitmap = (QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN << 1) - 1; + if (trigger_reason_bitmap == all_bitmap) + return BIT(ROAM_TRIGGER_REASON_MAX) - 1; + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_PER) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_PER); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BEACON_MISS) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_BMISS); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_POOR_RSSI) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_LOW_RSSI); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BETTER_RSSI) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_HIGH_RSSI); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_PERIODIC) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_PERIODIC); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_DENSE) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_DENSE); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BTM) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_BTM); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BSS_LOAD) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_BSS_LOAD); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_USER_TRIGGER) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_FORCED); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_DEAUTH) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_DEAUTH); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_IDLE) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_IDLE); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_TX_FAILURES) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_STA_KICKOUT); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN) + drv_trigger_bitmap |= BIT(ROAM_TRIGGER_REASON_BACKGROUND); + + return drv_trigger_bitmap; +} + +/** + * wlan_hdd_convert_control_roam_scan_scheme_bitmap() - Convert the + * vendor specific roam scan scheme for roam triggers to internal roam trigger + * bitmap for partial scan. + * @trigger_reason_bitmap: Vendor specific roam trigger bitmap + * + * Return: Internal roam scan scheme bitmap + */ +static uint32_t +wlan_hdd_convert_control_roam_scan_scheme_bitmap(uint32_t trigger_reason_bitmap) +{ + uint32_t drv_scan_scheme_bitmap = 0; + + /* + * Partial scan scheme override over default scan scheme only for + * the PER, BMISS, Low RSSI, BTM, BSS_LOAD Triggers + */ + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_PER) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_PER); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BEACON_MISS) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_BMISS); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_POOR_RSSI) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_LOW_RSSI); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BTM) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_BTM); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_BSS_LOAD) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_BSS_LOAD); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_USER_TRIGGER) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_FORCED); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_DEAUTH) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_DEAUTH); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_IDLE) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_IDLE); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_TX_FAILURES) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_STA_KICKOUT); + + if (trigger_reason_bitmap & QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN) + drv_scan_scheme_bitmap |= BIT(ROAM_TRIGGER_REASON_BACKGROUND); + + return drv_scan_scheme_bitmap; +} + +/** + * hdd_send_roam_triggers_to_sme() - Send roam trigger bitmap to SME + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @roam_trigger_bitmap: Vendor configured roam trigger bitmap to be configured + * to firmware + * + * Send the roam trigger bitmap received to SME + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_roam_triggers_to_sme(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + uint32_t roam_trigger_bitmap) +{ + QDF_STATUS status; + struct wlan_roam_triggers triggers; + struct wlan_hdd_link_info *link_info; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_STATUS_E_FAILURE; + } + + if (link_info->adapter->device_mode != QDF_STA_MODE) { + hdd_err("Roam trigger bitmap supported only in STA mode"); + return QDF_STATUS_E_FAILURE; + } + + triggers.vdev_id = vdev_id; + triggers.trigger_bitmap = + wlan_hdd_convert_control_roam_trigger_bitmap(roam_trigger_bitmap); + hdd_debug("trigger bitmap: 0x%x converted trigger_bitmap: 0x%x", + roam_trigger_bitmap, triggers.trigger_bitmap); + /* + * In standalone STA, if this vendor command is received between + * ROAM_START and roam synch indication, it is better to reject + * roam disable since driver would send vdev_params command to + * de-initialize roaming structures in fw. + * In STA+STA mode, if this vendor command to enable roaming is + * received for one STA vdev and ROAM_START was received for other + * STA vdev, then also driver would be send vdev_params command to + * de-initialize roaming structures in fw on the roaming enabled + * vdev. + */ + if (hdd_is_roaming_in_progress(hdd_ctx)) { + mlme_set_roam_trigger_bitmap(hdd_ctx->psoc, + link_info->vdev_id, + triggers.trigger_bitmap); + hdd_err("Reject set roam trigger as roaming is in progress"); + + return QDF_STATUS_E_BUSY; + } + + /* + * roam trigger bitmap is > 0 - Roam triggers are set. + * roam trigger bitmap is 0 - Disable roaming + * + * For both the above modes, reset the roam scan scheme bitmap to + * 0. + */ + status = ucfg_cm_update_roam_scan_scheme_bitmap(hdd_ctx->psoc, + vdev_id, 0); + + status = ucfg_cm_rso_set_roam_trigger(hdd_ctx->pdev, vdev_id, + &triggers); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set roam control trigger bitmap"); + + return status; +} + +/* + * Disable default scoring algorithm. This is intended to set all bits of the + * disable_bitmap in struct scoring_param. + */ +#define DISABLE_SCORING 0 + +/* + * Enable scoring algorithm. This is intended to clear all bits of the + * disable_bitmap in struct scoring_param. + */ +#define ENABLE_SCORING 1 + +/* + * Controlled roam candidate selection is enabled from userspace. + * Driver/firmware should honor the selection criteria + */ +#define CONTROL_ROAM_CAND_SEL_ENABLE 1 + +/* + * Controlled roam candidate selection is disabled from userspace. + * Driver/firmware can use its internal candidate selection criteria + */ +#define CONTROL_ROAM_CAND_SEL_DISABLE 0 + +static const struct nla_policy +roam_scan_cand_sel_policy[PARAM_CAND_SEL_CRITERIA_MAX + 1] = { + [PARAM_CAND_SEL_SCORE_RSSI] = {.type = NLA_U8}, +}; + +/** + * hdd_send_roam_cand_sel_criteria_to_sme() - Send candidate sel criteria to SME + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @attr: Nested attribute carrying candidate selection criteria + * + * Extract different candidate sel criteria mentioned and convert it to + * driver/firmware understable format. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_roam_cand_sel_criteria_to_sme(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + struct nlattr *attr) +{ + QDF_STATUS status; + struct nlattr *tb2[PARAM_CAND_SEL_CRITERIA_MAX + 1]; + struct nlattr *curr_attr; + uint8_t sel_criteria = 0, rssi_score = 0, scoring; + int rem; + + hdd_debug("Received Command to Set candidate selection criteria "); + nla_for_each_nested(curr_attr, attr, rem) { + sel_criteria++; + break; + } + + if (sel_criteria && + wlan_cfg80211_nla_parse_nested(tb2, PARAM_CAND_SEL_CRITERIA_MAX, + attr, roam_scan_cand_sel_policy)) { + hdd_err("nla_parse failed"); + return QDF_STATUS_E_INVAL; + } + + /* + * Firmware supports the below configurations currently, + * 1. Default selection criteria where all scoring params + * are enabled and different weightages/scores are given to + * different parameters. + * When userspace doesn't specify any candidate selection criteria, + * this will be enabled. + * 2. Legacy candidate selection criteria where scoring + * algorithm is disabled and only RSSI is considered for + * roam candidate selection. + * When userspace specify 100% weightage for RSSI, this will + * be enabled. + * Rest of the combinations are not supported for now. + */ + if (sel_criteria == CONTROL_ROAM_CAND_SEL_ENABLE) { + /* Legacy selection criteria: 100% weightage to RSSI */ + if (tb2[PARAM_CAND_SEL_SCORE_RSSI]) + rssi_score = nla_get_u8(tb2[PARAM_CAND_SEL_SCORE_RSSI]); + + if (rssi_score != 100) { + hdd_debug("Ignore the candidate selection criteria"); + return QDF_STATUS_E_INVAL; + } + scoring = DISABLE_SCORING; + } else { + /* Default selection criteria */ + scoring = ENABLE_SCORING; + } + + status = sme_modify_roam_cand_sel_criteria(hdd_ctx->mac_handle, vdev_id, + !!scoring); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to disable scoring"); + + return status; +} + +/** + * hdd_send_roam_scan_period_to_sme() - Send roam scan period to SME + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @roam_scan_period: Roam scan period in seconds + * @check_and_update: If this is true/set, update the value only if the current + * configured value is not same as global value read from + * ini param. This is to give priority to the user configured + * values and retain the value, if updated already. + * If this is not set, update the value without any check. + * + * Validate the roam scan period and send it to firmware if valid. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_roam_scan_period_to_sme(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + uint32_t roam_scan_period, + bool check_and_update) +{ + QDF_STATUS status; + uint16_t roam_scan_period_current, roam_scan_period_global = 0; + + if (!ucfg_mlme_validate_scan_period(hdd_ctx->psoc, + roam_scan_period * 1000)) + return QDF_STATUS_E_INVAL; + + hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d", + roam_scan_period); + + status = ucfg_cm_get_empty_scan_refresh_period( + hdd_ctx->psoc, vdev_id, + &roam_scan_period_current); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + ucfg_cm_get_empty_scan_refresh_period_global(hdd_ctx->psoc, + &roam_scan_period_global); + if (check_and_update && + roam_scan_period_current != roam_scan_period_global) { + hdd_debug("roam scan period is already updated, value: %u", + roam_scan_period_current / 1000); + return QDF_STATUS_SUCCESS; + } + status = sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle, + vdev_id, + roam_scan_period * 1000); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set scan period"); + + return status; +} + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && \ +defined(FEATURE_RX_LINKSPEED_ROAM_TRIGGER) +/** + * hdd_set_roam_rx_linkspeed_threshold() - Set rx link speed threshold + * @psoc: Pointer to psoc + * @vdev: vdev + * @linkspeed_threshold: threshold value to set + * + * Return: none + */ +static QDF_STATUS +hdd_set_roam_rx_linkspeed_threshold(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t linkspeed_threshold) +{ + if (!ucfg_cm_is_linkspeed_roam_trigger_supported(psoc)) + return QDF_STATUS_E_NOSUPPORT; + + if (linkspeed_threshold) { + dp_ucfg_enable_link_monitoring(psoc, vdev, + linkspeed_threshold); + } else { + dp_ucfg_disable_link_monitoring(psoc, vdev); + wlan_hdd_link_speed_update(psoc, wlan_vdev_get_id(vdev), + false); + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +hdd_set_roam_rx_linkspeed_threshold(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t linkspeed_threshold) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/* Roam Hand-off delay range is 20 to 1000 msec */ +#define MIN_ROAM_HO_DELAY 20 +#define MAX_ROAM_HO_DELAY 1000 + +/* Include/Exclude roam partial scan channels in full scan */ +#define INCLUDE_ROAM_PARTIAL_SCAN_FREQ 0 +#define EXCLUDE_ROAM_PARTIAL_SCAN_FREQ 1 + +/* Include the supported 6 GHz PSC channels in full scan by default */ +#define INCLUDE_6GHZ_IN_FULL_SCAN_BY_DEF 0 +/* Include the 6 GHz channels in roam full scan only on prior discovery */ +#define INCLUDE_6GHZ_IN_FULL_SCAN_IF_DISC 1 + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * hdd_get_handoff_param() - get vendor handoff parameters + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * + * Wrapper function for hdd_cm_get_handoff_param + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_get_handoff_param(struct hdd_context *hdd_ctx, + uint8_t vdev_id) +{ + return hdd_cm_get_handoff_param(hdd_ctx->psoc, vdev_id, + VENDOR_CONTROL_PARAM_ROAM_ALL); +} +#else +static inline QDF_STATUS +hdd_get_handoff_param(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_set_roam_with_control_config() - Set roam control configuration + * @hdd_ctx: HDD context + * @tb: List of attributes carrying roam subcmd data + * @vdev_id: vdev id + * + * Extracts the attribute PARAM_ROAM_CONTROL_CONFIG from the attributes list tb + * and sends the corresponding roam control configuration to driver/firmware. + * + * Return: 0 on success; error number on failure + */ +static int +hdd_set_roam_with_control_config(struct hdd_context *hdd_ctx, + struct nlattr **tb, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct nlattr *tb2[QCA_ATTR_ROAM_CONTROL_MAX + 1], *attr; + uint32_t value; + struct wlan_cm_roam_vendor_btm_params param = {0}; + bool is_wtc_param_updated = false; + uint32_t band_mask; + uint16_t threshold; + struct wlan_hdd_link_info *link_info; + uint8_t roam_control_enable = false; + + hdd_enter(); + + /* The command must carry PARAM_ROAM_CONTROL_CONFIG */ + if (!tb[PARAM_ROAM_CONTROL_CONFIG]) { + hdd_err("Attribute CONTROL_CONFIG is not present"); + return -EINVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return QDF_STATUS_E_FAILURE; + + if (wlan_cfg80211_nla_parse_nested(tb2, QCA_ATTR_ROAM_CONTROL_MAX, + tb[PARAM_ROAM_CONTROL_CONFIG], + roam_control_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + attr = tb2[PARAM_FREQ_LIST_SCHEME]; + if (attr) { + status = hdd_send_roam_scan_channel_freq_list_to_sme(hdd_ctx, + vdev_id, + attr); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to config roam control"); + } + + if (tb2[QCA_ATTR_ROAM_CONTROL_TRIGGERS]) { + value = nla_get_u32(tb2[QCA_ATTR_ROAM_CONTROL_TRIGGERS]); + hdd_debug("Received roam trigger bitmap: 0x%x", value); + status = hdd_send_roam_triggers_to_sme(hdd_ctx, + vdev_id, + value); + if (status) + hdd_err("failed to config roam triggers"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_ENABLE]; + if (attr) { + roam_control_enable = nla_get_u8(attr); + if (roam_control_enable && + ucfg_cm_roam_is_vendor_handoff_control_enable( + hdd_ctx->psoc)) { + status = hdd_get_handoff_param(hdd_ctx, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get vendor handoff params"); + return qdf_status_to_os_return(status); + } + } + + hdd_debug("Parse and send roam control to FW: %s", + roam_control_enable ? "Enable" : "Disable"); + + status = sme_set_roam_config_enable(hdd_ctx->mac_handle, + vdev_id, + roam_control_enable); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to enable/disable roam control config"); + + attr = tb2[QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD]; + if (attr) { + /* Default value received as part of Roam control enable + * Set this only if user hasn't configured any value so + * far. + */ + value = nla_get_u32(attr); + status = hdd_send_roam_scan_period_to_sme(hdd_ctx, + vdev_id, + value, true); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to send scan period to firmware"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD]; + if (attr) { + value = nla_get_u32(attr); + /* Default value received as part of Roam control enable + * Set this only if user hasn't configured any value so + * far. + */ + status = hdd_send_roam_full_scan_period_to_sme(hdd_ctx, + vdev_id, + value, + true); + if (status) + hdd_err("failed to config full scan period"); + } + } else { + attr = tb2[QCA_ATTR_ROAM_CONTROL_SCAN_PERIOD]; + if (attr) { + /* User configured value, cache the value directly */ + value = nla_get_u32(attr); + status = hdd_send_roam_scan_period_to_sme(hdd_ctx, + vdev_id, + value, false); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to send scan period to firmware"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD]; + if (attr) { + value = nla_get_u32(attr); + /* User configured value, cache the value directly */ + status = hdd_send_roam_full_scan_period_to_sme(hdd_ctx, + vdev_id, + value, + false); + if (status) + hdd_err("failed to config full scan period"); + } + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME_TRIGGERS]; + if (attr) { + value = wlan_hdd_convert_control_roam_scan_scheme_bitmap( + nla_get_u32(attr)); + status = ucfg_cm_update_roam_scan_scheme_bitmap(hdd_ctx->psoc, + vdev_id, + value); + } + + /* Scoring and roam candidate selection criteria */ + attr = tb2[QCA_ATTR_ROAM_CONTROL_SELECTION_CRITERIA]; + if (attr) { + status = hdd_send_roam_cand_sel_criteria_to_sme(hdd_ctx, + vdev_id, attr); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set candidate selection criteria"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_SCAN_SCHEME]; + if (attr) { + param.scan_freq_scheme = nla_get_u32(attr); + is_wtc_param_updated = true; + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_CONNECTED_RSSI_THRESHOLD]; + if (attr) { + param.connected_rssi_threshold = nla_get_u32(attr); + is_wtc_param_updated = true; + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD]; + if (attr) { + param.candidate_rssi_threshold_2g = nla_get_u32(attr); + is_wtc_param_updated = true; + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_2P4GHZ]; + if (attr) { + param.candidate_rssi_threshold_2g = nla_get_u32(attr); + is_wtc_param_updated = true; + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_5GHZ]; + if (attr) { + param.candidate_rssi_threshold_5g = nla_get_u32(attr); + is_wtc_param_updated = true; + } else { + param.candidate_rssi_threshold_5g = + param.candidate_rssi_threshold_2g; + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_CANDIDATE_RSSI_THRESHOLD_6GHZ]; + if (attr) { + param.candidate_rssi_threshold_6g = nla_get_u32(attr); + is_wtc_param_updated = true; + } else { + param.candidate_rssi_threshold_6g = + param.candidate_rssi_threshold_2g; + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_USER_REASON]; + if (attr) { + param.user_roam_reason = nla_get_u32(attr); + is_wtc_param_updated = true; + } else { + param.user_roam_reason = DISABLE_VENDOR_BTM_CONFIG; + } + + if (tb2[QCA_ATTR_ROAM_CONTROL_BAND_MASK]) { + band_mask = + nla_get_u32(tb2[QCA_ATTR_ROAM_CONTROL_BAND_MASK]); + band_mask = + wlan_vendor_bitmap_to_reg_wifi_band_bitmap(hdd_ctx->psoc, + band_mask); + hdd_debug("[ROAM BAND] set roam band mask:%d", band_mask); + if (band_mask) { + ucfg_cm_set_roam_band_mask(hdd_ctx->psoc, vdev_id, + band_mask); + } else { + hdd_debug("Invalid roam BAND_MASK"); + return -EINVAL; + } + + if (ucfg_cm_is_change_in_band_allowed(hdd_ctx->psoc, vdev_id, + band_mask)) { + + /* Disable roaming on Vdev before setting PCL */ + sme_stop_roaming(hdd_ctx->mac_handle, vdev_id, + REASON_DRIVER_DISABLED, RSO_SET_PCL); + + policy_mgr_set_pcl_for_existing_combo(hdd_ctx->psoc, + PM_STA_MODE, + vdev_id); + + /* Enable roaming once SET pcl is done */ + sme_start_roaming(hdd_ctx->mac_handle, vdev_id, + REASON_DRIVER_ENABLED, RSO_SET_PCL); + } + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_RX_LINKSPEED_THRESHOLD]; + if (attr) { + threshold = nla_get_u16(attr); + status = hdd_set_roam_rx_linkspeed_threshold(hdd_ctx->psoc, + link_info->vdev, + threshold); + } + + if (is_wtc_param_updated) { + wlan_cm_roam_set_vendor_btm_params(hdd_ctx->psoc, ¶m); + /* Sends RSO update */ + sme_send_vendor_btm_params(hdd_ctx->mac_handle, vdev_id); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_HO_DELAY_FOR_RX]; + if (attr) { + value = nla_get_u16(attr); + if (value < MIN_ROAM_HO_DELAY || value > MAX_ROAM_HO_DELAY) { + hdd_err("Invalid roam HO delay value: %d", value); + return -EINVAL; + } + + hdd_debug("Received roam HO delay value: %d", value); + + status = ucfg_cm_roam_send_ho_delay_config(hdd_ctx->pdev, + vdev_id, value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set hand-off delay"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_NO_REUSE_PARTIAL_SCAN_FREQ]; + if (attr) { + value = nla_get_u8(attr); + if (value < INCLUDE_ROAM_PARTIAL_SCAN_FREQ || + value > EXCLUDE_ROAM_PARTIAL_SCAN_FREQ) { + hdd_err("Invalid value %d to exclude partial scan freq", + value); + return -EINVAL; + } + + hdd_debug("%s partial scan channels in roam full scan", + value ? "Exclude" : "Include"); + + status = ucfg_cm_exclude_rm_partial_scan_freq(hdd_ctx->pdev, + vdev_id, value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Fail to exclude roam partial scan channels"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_6GHZ_ONLY_ON_PRIOR_DISCOVERY]; + if (attr) { + value = nla_get_u8(attr); + if (value < INCLUDE_6GHZ_IN_FULL_SCAN_BY_DEF || + value > INCLUDE_6GHZ_IN_FULL_SCAN_IF_DISC) { + hdd_err("Invalid value %d to decide inclusion of 6 GHz channels", + value); + return -EINVAL; + } + + hdd_debug("Include 6 GHz channels in roam full scan by %s", + value ? "prior discovery" : "default"); + + status = ucfg_cm_roam_full_scan_6ghz_on_disc(hdd_ctx->pdev, + vdev_id, value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Fail to decide inclusion of 6 GHz channels"); + } + + attr = tb2[QCA_ATTR_ROAM_CONTROL_CONNECTED_HIGH_RSSI_OFFSET]; + if (attr) { + value = nla_get_u8(attr); + if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HI_RSSI_DELTA, value)) { + hdd_err("High RSSI offset value %d is out of range", + value); + return -EINVAL; + } + + hdd_debug("%s roam scan high RSSI with offset: %d for vdev %d", + value ? "Enable" : "Disable", value, vdev_id); + + if (!value && + !wlan_cm_get_roam_scan_high_rssi_offset(hdd_ctx->psoc)) { + hdd_debug("Roam scan high RSSI is already disabled"); + return -EINVAL; + } + + status = ucfg_cm_set_roam_scan_high_rssi_offset(hdd_ctx->psoc, + vdev_id, value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Fail to set roam scan high RSSI offset for vdev %d", + vdev_id); + } + + return qdf_status_to_os_return(status); +} + +#define ENABLE_ROAM_TRIGGERS_ALL (QCA_ROAM_TRIGGER_REASON_PER | \ + QCA_ROAM_TRIGGER_REASON_BEACON_MISS | \ + QCA_ROAM_TRIGGER_REASON_POOR_RSSI | \ + QCA_ROAM_TRIGGER_REASON_BETTER_RSSI | \ + QCA_ROAM_TRIGGER_REASON_PERIODIC | \ + QCA_ROAM_TRIGGER_REASON_DENSE | \ + QCA_ROAM_TRIGGER_REASON_BTM | \ + QCA_ROAM_TRIGGER_REASON_BSS_LOAD | \ + QCA_ROAM_TRIGGER_REASON_USER_TRIGGER | \ + QCA_ROAM_TRIGGER_REASON_DEAUTH | \ + QCA_ROAM_TRIGGER_REASON_IDLE | \ + QCA_ROAM_TRIGGER_REASON_TX_FAILURES | \ + QCA_ROAM_TRIGGER_REASON_EXTERNAL_SCAN) + +static int +hdd_clear_roam_control_config(struct hdd_context *hdd_ctx, + struct nlattr **tb, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct nlattr *tb2[QCA_ATTR_ROAM_CONTROL_MAX + 1]; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + uint32_t value; + + /* The command must carry PARAM_ROAM_CONTROL_CONFIG */ + if (!tb[PARAM_ROAM_CONTROL_CONFIG]) { + hdd_err("Attribute CONTROL_CONFIG is not present"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb2, QCA_ATTR_ROAM_CONTROL_MAX, + tb[PARAM_ROAM_CONTROL_CONFIG], + roam_control_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + hdd_debug("Clear the control config done through SET"); + if (tb2[QCA_ATTR_ROAM_CONTROL_CLEAR_ALL]) { + hdd_debug("Disable roam control config done through SET"); + status = sme_set_roam_config_enable(hdd_ctx->mac_handle, + vdev_id, 0); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to enable/disable roam control config"); + return qdf_status_to_os_return(status); + } + + value = ENABLE_ROAM_TRIGGERS_ALL; + hdd_debug("Reset roam trigger bitmap to 0x%x", value); + status = hdd_send_roam_triggers_to_sme(hdd_ctx, vdev_id, value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to restore roam trigger bitmap"); + return qdf_status_to_os_return(status); + } + + status = sme_roam_control_restore_default_config(mac_handle, + vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to config roam control"); + return qdf_status_to_os_return(status); + } + } + + return 0; +} + +/** + * hdd_roam_control_config_buf_size() - Calculate the skb size to be allocated + * @hdd_ctx: HDD context + * @tb: List of attributes to be populated + * + * Calculate the buffer size to be allocated based on the attributes + * mentioned in tb. + * + * Return: buffer size to be allocated + */ +static uint16_t +hdd_roam_control_config_buf_size(struct hdd_context *hdd_ctx, + struct nlattr **tb) +{ + uint16_t skb_len = 0; + + if (tb[QCA_ATTR_ROAM_CONTROL_STATUS]) + skb_len += NLA_HDRLEN + sizeof(uint8_t); + + if (tb[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD]) + skb_len += NLA_HDRLEN + sizeof(uint32_t); + + if (tb[QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME]) + /* + * Response has 3 nests, 1 atrribure value and a + * attribute list of frequencies. + */ + skb_len += 3 * nla_total_size(0) + + nla_total_size(sizeof(uint32_t)) + + (nla_total_size(sizeof(uint32_t)) * + NUM_CHANNELS); + + if (tb[QCA_ATTR_ROAM_CONTROL_BAND_MASK]) + skb_len += NLA_HDRLEN + sizeof(uint32_t); + + return skb_len; +} + +/** + * wlan_reg_wifi_band_bitmap_to_vendor_bitmap() - Convert enum reg_wifi_band + * to enum qca_set_band + * @reg_wifi_band_bitmap: enum reg_wifi_band + * + * Return: qca_set_band value + */ +static uint32_t +wlan_reg_wifi_band_bitmap_to_vendor_bitmap(uint32_t reg_wifi_band_bitmap) +{ + uint32_t vendor_mask = 0; + + if (reg_wifi_band_bitmap & BIT(REG_BAND_2G)) + vendor_mask |= QCA_SETBAND_2G; + if (reg_wifi_band_bitmap & BIT(REG_BAND_5G)) + vendor_mask |= QCA_SETBAND_5G; + if (reg_wifi_band_bitmap & BIT(REG_BAND_6G)) + vendor_mask |= QCA_SETBAND_6G; + + return vendor_mask; +} + +/** + * hdd_roam_control_config_fill_data() - Fill the data requested by userspace + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @skb: SK buffer + * @tb: List of attributes + * + * Get the data corresponding to the attribute list specified in tb and + * update the same to skb by populating the same attributes. + * + * Return: 0 on success; error number on failure + */ +static int +hdd_roam_control_config_fill_data(struct hdd_context *hdd_ctx, uint8_t vdev_id, + struct sk_buff *skb, struct nlattr **tb) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t roam_control; + struct nlattr *config, *get_freq_scheme, *get_freq; + uint32_t full_roam_scan_period, roam_band, vendor_band_mask; + uint8_t num_channels = 0; + uint32_t i = 0, freq_list[NUM_CHANNELS] = { 0 }; + struct wlan_hdd_link_info *link_info; + + config = nla_nest_start(skb, PARAM_ROAM_CONTROL_CONFIG); + if (!config) { + hdd_err("nla nest start failure"); + return -EINVAL; + } + + if (tb[QCA_ATTR_ROAM_CONTROL_STATUS]) { + status = sme_get_roam_config_status(hdd_ctx->mac_handle, + vdev_id, + &roam_control); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + hdd_debug("Roam control: %s", + roam_control ? "Enabled" : "Disabled"); + if (nla_put_u8(skb, QCA_ATTR_ROAM_CONTROL_STATUS, + roam_control)) { + hdd_info("failed to put vendor_roam_control"); + return -ENOMEM; + } + } + + if (tb[QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD]) { + status = sme_get_full_roam_scan_period(hdd_ctx->mac_handle, + vdev_id, + &full_roam_scan_period); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + hdd_debug("full_roam_scan_period: %u", full_roam_scan_period); + + if (nla_put_u32(skb, QCA_ATTR_ROAM_CONTROL_FULL_SCAN_PERIOD, + full_roam_scan_period)) { + hdd_info("failed to put full_roam_scan_period"); + return -EINVAL; + } + } + + if (tb[QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME]) { + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_info("Invalid vdev"); + return -EINVAL; + } + + hdd_debug("Get roam scan frequencies req received"); + status = hdd_get_roam_scan_freq(link_info->adapter, + hdd_ctx->mac_handle, + freq_list, &num_channels); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_info("failed to get roam scan freq"); + goto out; + } + + hdd_debug("num_channels %d", num_channels); + get_freq_scheme = nla_nest_start( + skb, QCA_ATTR_ROAM_CONTROL_FREQ_LIST_SCHEME); + if (!get_freq_scheme) { + hdd_info("failed to nest start for roam scan freq"); + return -EINVAL; + } + + if (nla_put_u32(skb, PARAM_SCAN_FREQ_LIST_TYPE, 0)) { + hdd_info("failed to put list type"); + return -EINVAL; + } + + get_freq = nla_nest_start( + skb, QCA_ATTR_ROAM_CONTROL_SCAN_FREQ_LIST); + if (!get_freq) { + hdd_info("failed to nest start for roam scan freq"); + return -EINVAL; + } + + for (i = 0; i < num_channels; i++) { + if (nla_put_u32(skb, PARAM_SCAN_FREQ_LIST, + freq_list[i])) { + hdd_info("failed to put freq at index %d", i); + return -EINVAL; + } + } + nla_nest_end(skb, get_freq); + nla_nest_end(skb, get_freq_scheme); + } + + if (tb[QCA_ATTR_ROAM_CONTROL_BAND_MASK]) { + status = ucfg_cm_get_roam_band(hdd_ctx->psoc, vdev_id, + &roam_band); + if (QDF_IS_STATUS_ERROR(status)) + goto out; + vendor_band_mask = + wlan_reg_wifi_band_bitmap_to_vendor_bitmap(roam_band); + if (nla_put_u32(skb, QCA_ATTR_ROAM_CONTROL_BAND_MASK, + vendor_band_mask)) { + hdd_info("failed to put roam_band"); + return -EINVAL; + } + hdd_debug("sending vendor_band_mask: %d reg band:%d", + vendor_band_mask, roam_band); + } + + nla_nest_end(skb, config); + +out: + return qdf_status_to_os_return(status); +} + +/** + * hdd_send_roam_control_config() - Send the roam config as vendor cmd reply + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @tb: List of attributes + * + * Parse the attributes list tb and get the data corresponding to the + * attributes specified in tb. Send them as a vendor response. + * + * Return: 0 on success; error number on failure + */ +static int +hdd_send_roam_control_config(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + struct nlattr **tb) +{ + struct sk_buff *skb; + uint16_t skb_len; + int status; + + skb_len = hdd_roam_control_config_buf_size(hdd_ctx, tb); + if (!skb_len) { + hdd_err("No data requested"); + return -EINVAL; + } + + skb_len += NLMSG_HDRLEN; + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len); + if (!skb) { + hdd_info("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + status = hdd_roam_control_config_fill_data(hdd_ctx, vdev_id, skb, tb); + if (status) + goto fail; + + return wlan_cfg80211_vendor_cmd_reply(skb); + +fail: + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(skb); + return status; +} + +/** + * hdd_get_roam_control_config() - Send requested roam config to userspace + * @hdd_ctx: HDD context + * @tb: list of attributes + * @vdev_id: vdev id + * + * Return: 0 on success; error number on failure + */ +static int hdd_get_roam_control_config(struct hdd_context *hdd_ctx, + struct nlattr **tb, + uint8_t vdev_id) +{ + QDF_STATUS status; + struct nlattr *tb2[QCA_ATTR_ROAM_CONTROL_MAX + 1]; + + /* The command must carry PARAM_ROAM_CONTROL_CONFIG */ + if (!tb[PARAM_ROAM_CONTROL_CONFIG]) { + hdd_err("Attribute CONTROL_CONFIG is not present"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb2, QCA_ATTR_ROAM_CONTROL_MAX, + tb[PARAM_ROAM_CONTROL_CONFIG], + roam_control_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + status = hdd_send_roam_control_config(hdd_ctx, vdev_id, tb2); + if (status) { + hdd_err("failed to enable/disable roam control"); + return status; + } + + return qdf_status_to_os_return(status); +} + +#undef PARAM_ROAM_CONTROL_CONFIG +#undef PARAM_FREQ_LIST_SCHEME_MAX +#undef PARAM_FREQ_LIST_SCHEME +#undef PARAM_SCAN_FREQ_LIST +#undef PARAM_SCAN_FREQ_LIST_TYPE +#undef PARAM_CAND_SEL_CRITERIA_MAX +#undef PARAM_CAND_SEL_SCORE_RSSI + +/** + * hdd_set_ext_roam_params() - parse ext roam params + * @hdd_ctx: HDD context + * @data: ext roam params attribute payload + * @data_len: length of @data + * @vdev_id: vdev id + * @rso_config: roam params + * @rso_usr_cfg: roam userspace params + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_ext_roam_params(struct hdd_context *hdd_ctx, + const void *data, int data_len, + uint8_t vdev_id, + struct rso_config_params *rso_config, + struct rso_user_config *rso_usr_cfg) +{ + uint32_t cmd_type, req_id; + struct nlattr *tb[MAX_ROAMING_PARAM + 1]; + int ret; + mac_handle_t mac_handle; + + if (wlan_cfg80211_nla_parse(tb, MAX_ROAMING_PARAM, data, data_len, + wlan_hdd_set_roam_param_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + /* Parse and fetch Command Type */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]) { + hdd_err("roam cmd type failed"); + goto fail; + } + + cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD]); + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]) { + hdd_err("attr request id failed"); + goto fail; + } + mac_handle = hdd_ctx->mac_handle; + req_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID]); + hdd_debug("Req Id: %u Cmd Type: %u", req_id, cmd_type); + switch (cmd_type) { + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_SSID_WHITE_LIST: + ret = hdd_set_allow_list(hdd_ctx, rso_config, tb, vdev_id, + rso_usr_cfg); + if (ret) + goto fail; + break; + + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_EXTSCAN_ROAM_PARAMS: + /* Parse and fetch 5G Boost Threshold */ + if (!tb[PARAM_A_BAND_BOOST_THLD]) { + hdd_err("5G boost threshold failed"); + goto fail; + } + rso_config->raise_rssi_thresh_5g = nla_get_s32( + tb[PARAM_A_BAND_BOOST_THLD]); + hdd_debug("5G Boost Threshold (%d)", + rso_config->raise_rssi_thresh_5g); + /* Parse and fetch 5G Penalty Threshold */ + if (!tb[PARAM_A_BAND_PELT_THLD]) { + hdd_err("5G penalty threshold failed"); + goto fail; + } + rso_config->drop_rssi_thresh_5g = nla_get_s32( + tb[PARAM_A_BAND_PELT_THLD]); + hdd_debug("5G Penalty Threshold (%d)", + rso_config->drop_rssi_thresh_5g); + /* Parse and fetch 5G Boost Factor */ + if (!tb[PARAM_A_BAND_BOOST_FACTOR]) { + hdd_err("5G boost Factor failed"); + goto fail; + } + rso_config->raise_factor_5g = nla_get_u32( + tb[PARAM_A_BAND_BOOST_FACTOR]); + hdd_debug("5G Boost Factor (%d)", + rso_config->raise_factor_5g); + /* Parse and fetch 5G Penalty factor */ + if (!tb[PARAM_A_BAND_PELT_FACTOR]) { + hdd_err("5G Penalty Factor failed"); + goto fail; + } + rso_config->drop_factor_5g = nla_get_u32( + tb[PARAM_A_BAND_PELT_FACTOR]); + hdd_debug("5G Penalty factor (%d)", + rso_config->drop_factor_5g); + /* Parse and fetch 5G Max Boost */ + if (!tb[PARAM_A_BAND_MAX_BOOST]) { + hdd_err("5G Max Boost failed"); + goto fail; + } + rso_config->max_raise_rssi_5g = nla_get_u32( + tb[PARAM_A_BAND_MAX_BOOST]); + hdd_debug("5G Max Boost (%d)", + rso_config->max_raise_rssi_5g); + /* Parse and fetch Rssi Diff */ + if (!tb[PARAM_ROAM_HISTERESYS]) { + hdd_err("Rssi Diff failed"); + goto fail; + } + rso_config->rssi_diff = nla_get_s32( + tb[PARAM_ROAM_HISTERESYS]); + hdd_debug("RSSI Diff (%d)", + rso_config->rssi_diff); + /* Parse and fetch Alert Rssi Threshold */ + if (!tb[PARAM_RSSI_TRIGGER]) { + hdd_err("Alert Rssi Threshold failed"); + goto fail; + } + rso_config->alert_rssi_threshold = nla_get_u32( + tb[PARAM_RSSI_TRIGGER]); + hdd_debug("Alert RSSI Threshold (%d)", + rso_config->alert_rssi_threshold); + sme_update_roam_params(mac_handle, vdev_id, rso_config, NULL, + REASON_ROAM_EXT_SCAN_PARAMS_CHANGED); + break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_LAZY_ROAM: + /* Parse and fetch Activate Good Rssi Roam */ + if (!tb[PARAM_ROAM_ENABLE]) { + hdd_err("Activate Good Rssi Roam failed"); + goto fail; + } + rso_config->good_rssi_roam = nla_get_s32( + tb[PARAM_ROAM_ENABLE]); + hdd_debug("Activate Good Rssi Roam (%d)", + rso_config->good_rssi_roam); + sme_update_roam_params(mac_handle, vdev_id, rso_config, NULL, + REASON_ROAM_GOOD_RSSI_CHANGED); + break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BSSID_PREFS: + ret = hdd_set_bssid_prefs(hdd_ctx, rso_config, tb, vdev_id); + if (ret) + goto fail; + break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_SET_BLACKLIST_BSSID: + ret = hdd_set_denylist_bssid(hdd_ctx, rso_config, tb, vdev_id); + if (ret) + goto fail; + break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_SET: + ret = hdd_set_roam_with_control_config(hdd_ctx, tb, vdev_id); + if (ret) + goto fail; + break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_CLEAR: + ret = hdd_clear_roam_control_config(hdd_ctx, tb, vdev_id); + if (ret) + goto fail; + break; + case QCA_WLAN_VENDOR_ROAMING_SUBCMD_CONTROL_GET: + ret = hdd_get_roam_control_config(hdd_ctx, tb, vdev_id); + if (ret) + goto fail; + break; + } + + return 0; + +fail: + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_set_ext_roam_params() - Settings for roaming parameters + * @wiphy: The wiphy structure + * @wdev: The wireless device + * @data: Data passed by framework + * @data_len: Parameters to be configured passed as data + * + * The roaming related parameters are configured by the framework + * using this interface. + * + * Return: Return either success or failure code. + */ +static int +__wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct rso_config_params *rso_config; + struct rso_user_config *rso_usr_cfg = NULL; + + int ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + rso_config = qdf_mem_malloc(sizeof(*rso_config)); + if (!rso_config) + return -ENOMEM; + + rso_usr_cfg = qdf_mem_malloc(sizeof(*rso_usr_cfg)); + if (!rso_usr_cfg) + return -ENOMEM; + + ret = hdd_set_ext_roam_params(hdd_ctx, data, data_len, + adapter->deflink->vdev_id, rso_config, + rso_usr_cfg); + qdf_mem_free(rso_config); + qdf_mem_free(rso_usr_cfg); + + if (ret) + goto fail; + + return 0; +fail: + return ret; +} +#undef PARAM_NUM_NW +#undef PARAM_SET_BSSID +#undef PARAM_SET_BSSID_HINT +#undef PARAM_SSID_LIST +#undef PARAM_LIST_SSID +#undef MAX_ROAMING_PARAM +#undef PARAM_NUM_BSSID +#undef PARAM_BSSID_PREFS +#undef PARAM_ROAM_BSSID +#undef PARAM_RSSI_MODIFIER +#undef PARAMS_NUM_BSSID +#undef PARAM_BSSID_PARAMS +#undef PARAM_A_BAND_BOOST_THLD +#undef PARAM_A_BAND_PELT_THLD +#undef PARAM_A_BAND_BOOST_FACTOR +#undef PARAM_A_BAND_PELT_FACTOR +#undef PARAM_A_BAND_MAX_BOOST +#undef PARAM_ROAM_HISTERESYS +#undef PARAM_RSSI_TRIGGER +#undef PARAM_ROAM_ENABLE + + +/** + * wlan_hdd_cfg80211_set_ext_roam_params() - set ext scan roam params + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_ext_roam_params(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_ext_roam_params(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define RATEMASK_PARAMS_TYPE_MAX 4 +#define RATEMASK_PARAMS_BITMAP_MAX 16 +#define RATEMASK_PARAMS_MAX QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_MAX +const struct nla_policy wlan_hdd_set_ratemask_param_policy[ + RATEMASK_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST] = {.type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP] = {.type = NLA_BINARY, + .len = RATEMASK_PARAMS_BITMAP_MAX}, +}; + +/** + * hdd_set_ratemask_params() - parse ratemask params + * @hdd_ctx: HDD context + * @data: ratemask attribute payload + * @data_len: length of @data + * @vdev: vdev to modify + * + * Return: 0 on success; error number on failure + */ +static int hdd_set_ratemask_params(struct hdd_context *hdd_ctx, + const void *data, int data_len, + struct wlan_objmgr_vdev *vdev) +{ + struct nlattr *tb[RATEMASK_PARAMS_MAX + 1]; + struct nlattr *tb2[RATEMASK_PARAMS_MAX + 1]; + struct nlattr *curr_attr; + int ret, rem; + struct config_ratemask_params rate_params[RATEMASK_PARAMS_TYPE_MAX]; + uint8_t ratemask_type, num_ratemask = 0, len; + uint32_t bitmap[RATEMASK_PARAMS_BITMAP_MAX / 4]; + + ret = wlan_cfg80211_nla_parse(tb, + RATEMASK_PARAMS_MAX, + data, data_len, + wlan_hdd_set_ratemask_param_policy); + if (ret) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST]) { + hdd_err("ratemask array attribute not present"); + return -EINVAL; + } + + memset(rate_params, 0, (RATEMASK_PARAMS_TYPE_MAX * + sizeof(struct config_ratemask_params))); + + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_LIST], + rem) { + if (num_ratemask >= RATEMASK_PARAMS_TYPE_MAX) { + hdd_err("Exceeding ratemask_list_param_num value"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse( + tb2, RATEMASK_PARAMS_MAX, + nla_data(curr_attr), nla_len(curr_attr), + wlan_hdd_set_ratemask_param_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + if (!tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE]) { + hdd_err("type attribute not present"); + return -EINVAL; + } + + if (!tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP]) { + hdd_err("bitmap attribute not present"); + return -EINVAL; + } + + ratemask_type = + nla_get_u8(tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_TYPE]); + if (ratemask_type >= RATEMASK_PARAMS_TYPE_MAX) { + hdd_err("invalid ratemask type"); + return -EINVAL; + } + + len = nla_len(tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP]); + qdf_mem_zero(bitmap, sizeof(bitmap)); + nla_memcpy(bitmap, + tb2[QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_BITMAP], + len); + + hdd_debug("rate_type:%d, lower32 0x%x, lower32_2 0x%x, higher32 0x%x, higher32_2 0x%x", + ratemask_type, bitmap[0], bitmap[1], + bitmap[2], bitmap[3]); + + rate_params[num_ratemask].type = ratemask_type; + rate_params[num_ratemask].lower32 = bitmap[0]; + rate_params[num_ratemask].lower32_2 = bitmap[1]; + rate_params[num_ratemask].higher32 = bitmap[2]; + rate_params[num_ratemask].higher32_2 = bitmap[3]; + + num_ratemask += 1; + } + + ret = ucfg_set_ratemask_params(vdev, num_ratemask, rate_params); + if (ret) + hdd_err("ucfg_set_ratemask_params failed"); + return ret; +} + +/** + * __wlan_hdd_cfg80211_set_ratemask_config() - Ratemask parameters + * @wiphy: The wiphy structure + * @wdev: The wireless device + * @data: Data passed by framework + * @data_len: Parameters to be configured passed as data + * + * The ratemask parameters are configured by the framework + * using this interface. + * + * Return: Return either success or failure code. + */ +static int +__wlan_hdd_cfg80211_set_ratemask_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct wlan_objmgr_vdev *vdev; + int ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev not present"); + return -EINVAL; + } + + ret = hdd_set_ratemask_params(hdd_ctx, data, data_len, vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (ret) + goto fail; + + return 0; +fail: + return ret; +} + +/** + * wlan_hdd_cfg80211_set_ratemask_config() - set ratemask config + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_set_ratemask_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_ratemask_config(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define PWR_SAVE_FAIL_CMD_INDEX \ + QCA_NL80211_VENDOR_SUBCMD_PWR_SAVE_FAIL_DETECTED_INDEX + +void hdd_chip_pwr_save_fail_detected_cb(hdd_handle_t hdd_handle, + struct chip_pwr_save_fail_detected_params + *data) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct sk_buff *skb; + int flags = cds_get_gfp_flags(); + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!data) { + hdd_debug("data is null"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + NLMSG_HDRLEN + + sizeof(uint32_t) + + NLMSG_HDRLEN, + PWR_SAVE_FAIL_CMD_INDEX, flags); + if (!skb) { + hdd_info("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("failure reason code: %u", data->failure_reason_code); + + if (nla_put_u32(skb, + QCA_ATTR_CHIP_POWER_SAVE_FAILURE_REASON, + data->failure_reason_code)) + goto fail; + + wlan_cfg80211_vendor_event(skb, flags); + hdd_exit(); + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); +} +#undef PWR_SAVE_FAIL_CMD_INDEX + +const struct nla_policy +wlan_hdd_set_no_dfs_flag_config_policy[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + +1] = { + [QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG] = {.type = NLA_U32 }, +}; + +/** + * wlan_hdd_check_dfs_channel_for_adapter() - check dfs channel in adapter + * @hdd_ctx: HDD context + * @device_mode: device mode + * Return: bool + */ +static bool wlan_hdd_check_dfs_channel_for_adapter(struct hdd_context *hdd_ctx, + enum QDF_OPMODE device_mode) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct hdd_ap_ctx *ap_ctx; + struct hdd_station_ctx *sta_ctx; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_CHECK_DFS_CHANNEL_FOR_ADAPTER; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != device_mode) + goto next_adapter; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (device_mode == QDF_SAP_MODE) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + /* + * if there is SAP already running on + * DFS channel, do not disable scan on + * dfs channels. Note that with SAP on DFS, + * there cannot be conurrency on single radio. + * But then we can have multiple radios !! + * + * Indoor channels are also marked DFS, + * therefore check if the channel has + * REGULATORY_CHAN_RADAR channel flag to + * identify if the channel is DFS + */ + if (wlan_reg_is_dfs_for_freq( + hdd_ctx->pdev, + ap_ctx->operating_chan_freq)) { + hdd_err("SAP running on DFS channel"); + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return true; + } + } + + if (device_mode == QDF_STA_MODE) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + /* + * if STA is already connected on DFS channel, + * do not disable scan on dfs channels. + * + * Indoor channels are also marked DFS, + * therefore check if the channel has + * REGULATORY_CHAN_RADAR channel flag to + * identify if the channel is DFS + */ + if (hdd_cm_is_vdev_associated(link_info) && + wlan_reg_is_dfs_for_freq( + hdd_ctx->pdev, + sta_ctx->conn_info.chan_freq)) { + hdd_err("client connected on DFS channel"); + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return true; + } + } + } +next_adapter: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return false; +} + +/** + * wlan_hdd_enable_dfs_chan_scan() - disable/enable DFS channels + * @hdd_ctx: HDD context within host driver + * @enable_dfs_channels: If true, DFS channels can be used for scanning + * + * Loops through devices to see who is operating on DFS channels + * and then disables/enables DFS channels. + * Fails the disable request if any device is active on a DFS channel. + * + * Return: 0 or other error codes. + */ + +int wlan_hdd_enable_dfs_chan_scan(struct hdd_context *hdd_ctx, + bool enable_dfs_channels) +{ + QDF_STATUS status; + bool err; + mac_handle_t mac_handle; + bool enable_dfs_scan = true; + + ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc, + &enable_dfs_scan); + + if (enable_dfs_channels == enable_dfs_scan) { + hdd_debug("DFS channels are already %s", + enable_dfs_channels ? "enabled" : "disabled"); + return 0; + } + + if (!enable_dfs_channels) { + err = wlan_hdd_check_dfs_channel_for_adapter(hdd_ctx, + QDF_STA_MODE); + if (err) + return -EOPNOTSUPP; + + err = wlan_hdd_check_dfs_channel_for_adapter(hdd_ctx, + QDF_SAP_MODE); + if (err) + return -EOPNOTSUPP; + } + + ucfg_scan_cfg_set_dfs_chan_scan_allowed(hdd_ctx->psoc, + enable_dfs_channels); + + mac_handle = hdd_ctx->mac_handle; + status = sme_enable_dfs_chan_scan(mac_handle, enable_dfs_channels); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set DFS channel scan flag to %d", + enable_dfs_channels); + return qdf_status_to_os_return(status); + } + + hdd_abort_mac_scan_all_adapters(hdd_ctx); + + /* pass dfs channel status to regulatory component */ + status = ucfg_reg_enable_dfs_channels(hdd_ctx->pdev, + enable_dfs_channels); + + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to %s DFS channels", + enable_dfs_channels ? "enable" : "disable"); + + return qdf_status_to_os_return(status); +} + +/** + * __wlan_hdd_cfg80211_disable_dfs_chan_scan() - DFS channel configuration + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * Return: success(0) or reason code for failure + */ +static int __wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + 1]; + int ret_val; + uint32_t no_dfs_flag = 0; + bool enable_dfs_scan = true; + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX, + data, data_len, + wlan_hdd_set_no_dfs_flag_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]) { + hdd_err("attr dfs flag failed"); + return -EINVAL; + } + + no_dfs_flag = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG]); + + hdd_debug("DFS flag: %d", no_dfs_flag); + + if (no_dfs_flag > 1) { + hdd_err("invalid value of dfs flag"); + return -EINVAL; + } + ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc, + &enable_dfs_scan); + + if (enable_dfs_scan) { + ret_val = wlan_hdd_enable_dfs_chan_scan(hdd_ctx, !no_dfs_flag); + } else { + if ((!no_dfs_flag) != enable_dfs_scan) { + hdd_err("DFS chan ini configured %d, no dfs flag: %d", + enable_dfs_scan, + no_dfs_flag); + return -EINVAL; + } + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_disable_dfs_chan_scan () - DFS scan vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX. Validate it and + * call wlan_hdd_disable_dfs_chan_scan to send it to firmware. + * + * Return: EOK or other error codes. + */ + +static int wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_disable_dfs_chan_scan(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +const struct nla_policy +wlan_hdd_wisa_cmd_policy[QCA_WLAN_VENDOR_ATTR_WISA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WISA_MODE] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_handle_wisa_cmd() - Handle WISA vendor cmd + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_SUBCMD_WISA. Validate cmd attributes and + * setup WISA Mode features. + * + * Return: Success(0) or reason code for failure + */ +static int __wlan_hdd_cfg80211_handle_wisa_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WISA_MAX + 1]; + struct sir_wisa_params wisa; + int ret_val; + QDF_STATUS status; + bool wisa_mode; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + goto err; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_WISA_MAX, data, + data_len, wlan_hdd_wisa_cmd_policy)) { + hdd_err("Invalid WISA cmd attributes"); + ret_val = -EINVAL; + goto err; + } + if (!tb[QCA_WLAN_VENDOR_ATTR_WISA_MODE]) { + hdd_err("Invalid WISA mode"); + ret_val = -EINVAL; + goto err; + } + + wisa_mode = !!nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_WISA_MODE]); + hdd_debug("WISA Mode: %d", wisa_mode); + wisa.mode = wisa_mode; + wisa.vdev_id = adapter->deflink->vdev_id; + mac_handle = hdd_ctx->mac_handle; + status = sme_set_wisa_params(mac_handle, &wisa); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to set WISA mode: %d to FW", wisa_mode); + ret_val = -EINVAL; + } + if (QDF_IS_STATUS_SUCCESS(status) || !wisa_mode) + cdp_set_wisa_mode(soc, adapter->deflink->vdev_id, wisa_mode); +err: + hdd_exit(); + return ret_val; +} + +/** + * wlan_hdd_cfg80211_handle_wisa_cmd() - Handle WISA vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_WLAN_VENDOR_SUBCMD_WISA. Validate cmd attributes and + * setup WISA mode features. + * + * Return: Success(0) or reason code for failure + */ +static int wlan_hdd_cfg80211_handle_wisa_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_handle_wisa_cmd(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +struct hdd_station_info *hdd_get_stainfo(struct hdd_station_info *astainfo, + struct qdf_mac_addr mac_addr) +{ + struct hdd_station_info *stainfo = NULL; + int i; + + for (i = 0; i < WLAN_MAX_STA_COUNT; i++) { + if (!qdf_mem_cmp(&astainfo[i].sta_mac, + &mac_addr, + QDF_MAC_ADDR_SIZE)) { + stainfo = &astainfo[i]; + break; + } + } + + return stainfo; +} + +/* + * undef short names defined for get station command + * used by __wlan_hdd_cfg80211_get_station_cmd() + */ +#undef STATION_INVALID +#undef STATION_INFO +#undef STATION_ASSOC_FAIL_REASON +#undef STATION_REMOTE +#undef STATION_MAX +#undef LINK_INFO_STANDARD_NL80211_ATTR +#undef AP_INFO_STANDARD_NL80211_ATTR +#undef INFO_ROAM_COUNT +#undef INFO_AKM +#undef WLAN802_11_MODE +#undef AP_INFO_HS20_INDICATION +#undef HT_OPERATION +#undef VHT_OPERATION +#undef INFO_ASSOC_FAIL_REASON +#undef REMOTE_MAX_PHY_RATE +#undef REMOTE_TX_PACKETS +#undef REMOTE_TX_BYTES +#undef REMOTE_RX_PACKETS +#undef REMOTE_RX_BYTES +#undef REMOTE_LAST_TX_RATE +#undef REMOTE_LAST_RX_RATE +#undef REMOTE_WMM +#undef REMOTE_SUPPORTED_MODE +#undef REMOTE_AMPDU +#undef REMOTE_TX_STBC +#undef REMOTE_RX_STBC +#undef REMOTE_CH_WIDTH +#undef REMOTE_SGI_ENABLE +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +#undef REMOTE_PAD +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * __wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the Key data + * @data_len:Length of the data passed + * + * This is called when wlan driver needs to save the keys received via + * vendor specific command. + * + * Return: Return the Success or Failure code. + */ +static int __wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *hdd_adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(hdd_adapter->deflink); + struct wlan_crypto_pmksa pmksa; + int status; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if ((!data) || (data_len <= 0) || + (data_len > MAX_PMK_LEN)) { + hdd_err("Invalid data"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(hdd_adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + mac_handle = hdd_ctx->mac_handle; + qdf_mem_zero(&pmksa, sizeof(pmksa)); + pmksa.pmk_len = data_len; + qdf_mem_copy(pmksa.pmk, data, data_len); + + qdf_mem_copy(&pmksa.bssid, &sta_ctx->conn_info.bssid, + QDF_MAC_ADDR_SIZE); + + sme_roam_set_psk_pmk(mac_handle, &pmksa, + hdd_adapter->deflink->vdev_id, true); + qdf_mem_zero(&pmksa, sizeof(pmksa)); + return 0; +} + +/** + * wlan_hdd_cfg80211_keymgmt_set_key() - Store the Keys in the driver session + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the Key data + * @data_len:Length of the data passed + * + * This is called when wlan driver needs to save the keys received via + * vendor specific command. + * + * Return: Return the Success or Failure code. + */ +static int wlan_hdd_cfg80211_keymgmt_set_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_keymgmt_set_key(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +const struct nla_policy qca_wlan_vendor_get_wifi_info_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1]; + uint8_t *firmware_version = NULL; + int status; + struct sk_buff *reply_skb; + uint32_t skb_len = 0; + struct pld_soc_info info; + bool stt_flag = false; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (wlan_cfg80211_nla_parse(tb_vendor, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX, + data, data_len, + qca_wlan_vendor_get_wifi_info_policy)) { + hdd_err("WIFI_INFO_GET NL CMD parsing failed"); + return -EINVAL; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { + hdd_debug("Rcvd req for Driver version"); + skb_len += nla_total_size(strlen(QWLAN_VERSIONSTR) + 1); + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + hdd_debug("Rcvd req for FW version"); + if (!pld_get_soc_info(hdd_ctx->parent_dev, &info)) + stt_flag = true; + + firmware_version = qdf_mem_malloc(SIR_VERSION_STRING_LEN); + if (!firmware_version) + return -ENOMEM; + + snprintf(firmware_version, SIR_VERSION_STRING_LEN, + "FW:%d.%d.%d.%d.%d.%d HW:%s STT:%s", + hdd_ctx->fw_version_info.major_spid, + hdd_ctx->fw_version_info.minor_spid, + hdd_ctx->fw_version_info.siid, + hdd_ctx->fw_version_info.rel_id, + hdd_ctx->fw_version_info.crmid, + hdd_ctx->fw_version_info.sub_id, + hdd_ctx->target_hw_name, + (stt_flag ? info.fw_build_id : " ")); + skb_len += nla_total_size(strlen(firmware_version) + 1); + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX]) { + hdd_debug("Rcvd req for Radio index"); + skb_len += nla_total_size(sizeof(uint32_t)); + } + + if (!skb_len) { + hdd_err("unknown attribute in get_wifi_info request"); + qdf_mem_free(firmware_version); + return -EINVAL; + } + + skb_len += NLMSG_HDRLEN; + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + if (!reply_skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + qdf_mem_free(firmware_version); + return -ENOMEM; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION]) { + if (nla_put_string(reply_skb, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_DRIVER_VERSION, + QWLAN_VERSIONSTR)) + goto error_nla_fail; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION]) { + if (nla_put_string(reply_skb, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_FIRMWARE_VERSION, + firmware_version)) + goto error_nla_fail; + } + + if (tb_vendor[QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX]) { + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_RADIO_INDEX, + hdd_ctx->radio_index)) + goto error_nla_fail; + } + + qdf_mem_free(firmware_version); + return wlan_cfg80211_vendor_cmd_reply(reply_skb); + +error_nla_fail: + hdd_err("nla put fail"); + qdf_mem_free(firmware_version); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_wifi_info() - Get the wifi driver related info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called when wlan driver needs to send wifi driver related info + * (driver/fw version) to the user space application upon request. + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_wifi_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_wifi_info(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +const struct nla_policy get_logger_set_policy[ + QCA_WLAN_VENDOR_ATTR_LOGGER_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called by userspace to know the supported logger features + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int status; + uint32_t features; + struct sk_buff *reply_skb = NULL; + bool enable_ring_buffer; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + features = 0; + wlan_mlme_get_status_ring_buffer(hdd_ctx->psoc, &enable_ring_buffer); + if (enable_ring_buffer) { + features |= WIFI_LOGGER_PER_PACKET_TX_RX_STATUS_SUPPORTED; + features |= WIFI_LOGGER_CONNECT_EVENT_SUPPORTED; + features |= WIFI_LOGGER_WAKE_LOCK_SUPPORTED; + features |= WIFI_LOGGER_DRIVER_DUMP_SUPPORTED; + features |= WIFI_LOGGER_PACKET_FATE_SUPPORTED; + hdd_debug("Supported logger features: 0x%0x", features); + } else { + hdd_info("Ring buffer disable"); + } + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(uint32_t) + + NLA_HDRLEN + + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_LOGGER_SUPPORTED, + features)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * wlan_hdd_cfg80211_get_logger_supp_feature() - Get the wifi logger features + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This is called by userspace to know the supported logger features + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_logger_supp_feature(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_logger_supp_feature(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter, + uint8_t *kck_ptr, uint8_t kck_len, + uint8_t *kek_ptr, uint32_t kek_len, + uint8_t *replay_ctr, bool big_endian) +{ + struct hdd_station_ctx *hdd_sta_ctx; + uint8_t *buf; + int i; + struct pmo_gtk_req *gtk_req = NULL; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + gtk_req = qdf_mem_malloc(sizeof(*gtk_req)); + if (!gtk_req) + return; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (kck_ptr) { + if (kck_len > sizeof(gtk_req->kck)) { + kck_len = sizeof(gtk_req->kck); + QDF_ASSERT(0); + } + qdf_mem_copy(gtk_req->kck, kck_ptr, kck_len); + gtk_req->kck_len = kck_len; + } + + if (kek_ptr) { + /* paranoia */ + if (kek_len > sizeof(gtk_req->kek)) { + kek_len = sizeof(gtk_req->kek); + QDF_ASSERT(0); + } + qdf_mem_copy(gtk_req->kek, kek_ptr, kek_len); + } + + qdf_copy_macaddr(>k_req->bssid, &hdd_sta_ctx->conn_info.bssid); + + gtk_req->kek_len = kek_len; + gtk_req->is_fils_connection = hdd_is_fils_connection(hdd_ctx, adapter); + + /* convert big to little endian since driver work on little endian */ + buf = (uint8_t *)>k_req->replay_counter; + for (i = 0; i < 8; i++) + buf[7 - i] = replay_ctr[i]; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) + goto end; + status = ucfg_pmo_cache_gtk_offload_req(vdev, gtk_req); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Failed to cache GTK Offload"); + +end: + qdf_mem_free(gtk_req); +} +#endif + +#ifdef WLAN_CFR_ENABLE +void hdd_cfr_data_send_nl_event(uint8_t vdev_id, uint32_t pid, + const void *data, uint32_t data_len) +{ + uint32_t len, ret; + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct nlmsghdr *nlhdr; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("adapter NULL for vdev id %d", vdev_id); + return; + } + + hdd_debug("vdev id %d pid %d data len %d", vdev_id, pid, data_len); + len = nla_total_size(data_len) + NLMSG_HDRLEN; + vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &link_info->adapter->wdev, len, + QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG_INDEX, + qdf_mem_malloc_flags()); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed vdev id %d, data len %d", + vdev_id, data_len); + return; + } + + ret = nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_RESP_DATA, + data_len, data); + if (ret) { + hdd_err("CFR event put fails status %d", ret); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + if (pid) { + nlhdr = nlmsg_hdr(vendor_event); + if (nlhdr) + nlhdr->nlmsg_pid = pid; + else + hdd_err_rl("nlhdr is null"); + } + + wlan_cfg80211_vendor_event(vendor_event, qdf_mem_malloc_flags()); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx, + uint8_t vdev_id, uint16_t buf_len, + uint8_t *buf) +{ + struct sk_buff *vendor_event; + uint32_t len, ret; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err_rl("hdd context is null"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) + return; + + len = nla_total_size(buf_len) + NLMSG_HDRLEN; + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &link_info->adapter->wdev, len, + QCA_NL80211_VENDOR_SUBCMD_UPDATE_STA_INFO_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + ret = nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_UPDATE_STA_INFO_CONNECT_CHANNELS, + buf_len, buf); + if (ret) { + hdd_err("OEM event put fails status %d", ret); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} +#endif + +#define ANT_DIV_SET_PERIOD(probe_period, stay_period) \ + ((1 << 26) | \ + (((probe_period) & 0x1fff) << 13) | \ + ((stay_period) & 0x1fff)) + +#define ANT_DIV_SET_SNR_DIFF(snr_diff) \ + ((1 << 27) | \ + ((snr_diff) & 0x1fff)) + +#define ANT_DIV_SET_PROBE_DWELL_TIME(probe_dwell_time) \ + ((1 << 28) | \ + ((probe_dwell_time) & 0x1fff)) + +#define ANT_DIV_SET_WEIGHT(mgmt_snr_weight, data_snr_weight, ack_snr_weight) \ + ((1 << 29) | \ + (((mgmt_snr_weight) & 0xff) << 16) | \ + (((data_snr_weight) & 0xff) << 8) | \ + ((ack_snr_weight) & 0xff)) + +#define RX_REORDER_TIMEOUT_VOICE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VOICE +#define RX_REORDER_TIMEOUT_VIDEO \ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VIDEO +#define RX_REORDER_TIMEOUT_BESTEFFORT \ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BESTEFFORT +#define RX_REORDER_TIMEOUT_BACKGROUND \ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BACKGROUND +#define RX_BLOCKSIZE_PEER_MAC \ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC +#define RX_BLOCKSIZE_WINLIMIT \ + QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT + +#define CONFIG_CHANNEL_WIDTH \ + QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH +#define CONFIG_MLO_LINK_ID \ + QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID +#define CONFIG_MLO_LINKS \ + QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS + +const struct nla_policy wlan_hdd_wifi_config_policy[ + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_CONFIG_PENALIZE_AFTER_NCONS_BEACON_MISS] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES] = {.type = NLA_BINARY}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA] = {.type = NLA_BINARY, + .len = 5000 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VOICE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_VIDEO] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BESTEFFORT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_REORDER_TIMEOUT_BACKGROUND] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_PEER_MAC] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_BLOCKSIZE_WINLIMIT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_24] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_MISS_THRESHOLD_5] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_BEACON_REPORT_FAIL] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONF_TX_RATE] = {.type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR] = {.type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_PERIOD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_STAY_PERIOD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SNR_DIFF] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_DWELL_TIME] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_MGMT_SNR_WEIGHT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_DATA_SNR_WEIGHT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ACK_SNR_WEIGHT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL] = {.type = NLA_U8}, + [RX_REORDER_TIMEOUT_VOICE] = {.type = NLA_U32}, + [RX_REORDER_TIMEOUT_VIDEO] = {.type = NLA_U32}, + [RX_REORDER_TIMEOUT_BESTEFFORT] = {.type = NLA_U32}, + [RX_REORDER_TIMEOUT_BACKGROUND] = {.type = NLA_U32}, + [RX_BLOCKSIZE_PEER_MAC] = VENDOR_NLA_POLICY_MAC_ADDR, + [RX_BLOCKSIZE_WINLIMIT] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_LRO] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL] = {.type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_GTX] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST] = { + .type = NLA_BINARY, + .len = WLAN_MAX_IE_LEN + 2}, + [QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES] = { + .type = NLA_BINARY, + .len = SIR_MAC_MAX_ADD_IE_LENGTH + 2}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_NSS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO] = {.type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL] = { + .type = NLA_U16 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_SETTING] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL] = {.type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_FT_OVER_DS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_DBAM] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE_FOR_BE_BK] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_BEAMFORMER_PERIODIC_SOUNDING] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_WFC_STATE] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_EML_CAPABILITY] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_SIMULTANEOUS_LINKS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_CAPABILITY] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_FUNCTION] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_NUM_LINKS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MODE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_ACTIVE_LINKS] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_EMLSR_MODE_SWITCH] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_UL_MU_CONFIG] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS] = { + .type = NLA_NESTED }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_AMPDU_CNT] = {.type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TTLM_NEGOTIATION_SUPPORT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_COEX_TRAFFIC_SHAPING_MODE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_BTM_SUPPORT] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL] = { + .type = NLA_U16}, +}; + +#define WLAN_MAX_LINK_ID 15 + +static const struct nla_policy bandwidth_mlo_policy[ + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID] = { + .type = NLA_U8 }, +}; + +static const struct nla_policy +qca_wlan_vendor_attr_omi_tx_policy [QCA_WLAN_VENDOR_ATTR_OMI_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN] = {.type = NLA_U8 }, +}; + +static const struct nla_policy +wlan_oci_override_policy [QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY] = {.type = NLA_U32 }, +}; + +const struct nla_policy +wlan_hdd_wifi_test_config_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WMM_ENABLE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ACCEPT_ADDBA_REQ] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MCS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SEND_ADDBA_REQ] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_FRAGMENTATION] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WEP_TKIP_IN_HE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADD_DEL_BA_SESSION] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_KEEP_ALIVE_FRAME_TYPE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BA_TID] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE] = { + .type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_NO_ACK] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_NO_ACK_AC] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_LTF] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RX_CTRL_FRAME_TO_MBSS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_BEAMFORMEE_NSTS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MAC_PADDING_DUR] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MU_EDCA_AC] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OVERRIDE_MU_EDCA] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_SUPP] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_BW] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_NSS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_SUPPDU] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_USE_BSSID_IN_PROBE_REQ_RA] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_HTC_HE_SUPP] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OMI_TX] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_HE_TESTBED_DEFAULTS] + = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_2G_VHT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_TERMINATE] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD_ENABLE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PMF_PROTECTION] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_DATA_MGMT_RSP_TX] + = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD] = { + .type = NLA_U16}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ER_SU_PPDU_TYPE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PUNCTURED_PREAMBLE_RX] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISASSOC_TX] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FT_REASSOCREQ_RSNXE_USED] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_CSA] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_SA_QUERY_TIMEOUT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FILS_DISCOVERY_FRAMES_TX] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FULL_BW_UL_MU_MIMO] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RU_242_TONE_TX] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_6GHZ_SECURITY_TEST_MODE] + = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_H2E_RSNXE] + = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BEAMFORMER_PERIODIC_SOUNDING] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_80MHZ] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_160MHZ] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_320MHZ] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EXCLUDE_STA_PROF_IN_PROBE_REQ] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_EHT_TESTBED_DEFAULTS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MCS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_TB_SOUNDING_FB_RL] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_OM_CTRL_SUPPORT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EMLSR_PADDING_DELAY] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FORCE_MLO_POWER_SAVE_BCN_PERIOD] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_STR_TX] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_LINK_POWER_SAVE] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MLD_ID_ML_PROBE_REQ] = { + .type = NLA_U8}, +}; + +/** + * wlan_hdd_save_default_scan_ies() - API to store the default scan IEs + * @hdd_ctx: HDD context + * @adapter: Pointer to HDD adapter + * @ie_data: Pointer to Scan IEs buffer + * @ie_len: Length of Scan IEs + * + * This API is used to store the default scan ies received from + * supplicant. Also saves QCN IE if g_qcn_ie_support INI is enabled + * + * Return: 0 on success; error number otherwise + */ +static int wlan_hdd_save_default_scan_ies(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *ie_data, uint16_t ie_len) +{ + struct hdd_scan_info *scan_info = &adapter->scan_info; + bool add_qcn_ie; + + if (!scan_info) + return -EINVAL; + + if (scan_info->default_scan_ies) { + qdf_mem_free(scan_info->default_scan_ies); + scan_info->default_scan_ies = NULL; + } + + scan_info->default_scan_ies_len = ie_len; + ucfg_mlme_get_qcn_ie_support(hdd_ctx->psoc, &add_qcn_ie); + if (add_qcn_ie) + ie_len += (QCN_IE_HDR_LEN + QCN_IE_VERSION_SUBATTR_LEN); + + scan_info->default_scan_ies = qdf_mem_malloc(ie_len); + if (!scan_info->default_scan_ies) { + scan_info->default_scan_ies_len = 0; + return -ENOMEM; + } + + qdf_mem_copy(scan_info->default_scan_ies, ie_data, + scan_info->default_scan_ies_len); + + /* Add QCN IE if g_qcn_ie_support INI is enabled */ + if (add_qcn_ie) + sme_add_qcn_ie(hdd_ctx->mac_handle, + scan_info->default_scan_ies, + &scan_info->default_scan_ies_len); + + hdd_debug("Saved default scan IE:len %d", + scan_info->default_scan_ies_len); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *) scan_info->default_scan_ies, + scan_info->default_scan_ies_len); + + return 0; +} + +/** + * wlan_hdd_handle_restrict_offchan_config() - + * Handle wifi configuration attribute : + * QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL + * @adapter: Pointer to HDD adapter + * @restrict_offchan: Restrict offchannel setting done by + * application + * + * Return: 0 on success; error number otherwise + */ +static int wlan_hdd_handle_restrict_offchan_config(struct hdd_adapter *adapter, + u8 restrict_offchan) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum QDF_OPMODE dev_mode = adapter->device_mode; + struct wlan_objmgr_vdev *vdev; + int ret_val = 0; + + if (!(dev_mode == QDF_SAP_MODE || dev_mode == QDF_P2P_GO_MODE)) { + hdd_err("Invalid interface type:%d", dev_mode); + return -EINVAL; + } + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + if (restrict_offchan == 1) { + u32 vdev_id = wlan_vdev_get_id(vdev); + enum policy_mgr_con_mode pmode = + policy_mgr_qdf_opmode_to_pm_con_mode(hdd_ctx->psoc, dev_mode, + vdev_id); + uint32_t freq; + + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_cap_set(vdev, WLAN_VDEV_C_RESTRICT_OFFCHAN); + wlan_vdev_obj_unlock(vdev); + freq = policy_mgr_get_channel(hdd_ctx->psoc, pmode, &vdev_id); + if (!freq || + wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, freq)) { + hdd_err("unable to send avoid_freq"); + ret_val = -EINVAL; + } + hdd_info("vdev %d mode %d dnbs enabled", vdev_id, dev_mode); + } else if (restrict_offchan == 0) { + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_cap_clear(vdev, WLAN_VDEV_C_RESTRICT_OFFCHAN); + wlan_vdev_obj_unlock(vdev); + if (wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, 0)) { + hdd_err("unable to clear avoid_freq"); + ret_val = -EINVAL; + } + hdd_info("vdev mode %d dnbs disabled", dev_mode); + } else { + ret_val = -EINVAL; + hdd_err("Invalid RESTRICT_OFFCHAN setting"); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return ret_val; +} + +/** + * wlan_hdd_cfg80211_wifi_set_reorder_timeout() - set reorder timeout + * @link_info: link info pointer in HDD adapter + * @tb: array of pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_hdd_cfg80211_wifi_set_reorder_timeout(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + int ret_val = 0; + QDF_STATUS qdf_status; + struct sir_set_rx_reorder_timeout_val reorder_timeout; + mac_handle_t mac_handle; + +#define RX_TIMEOUT_VAL_MIN 10 +#define RX_TIMEOUT_VAL_MAX 1000 + + if (tb[RX_REORDER_TIMEOUT_VOICE] || + tb[RX_REORDER_TIMEOUT_VIDEO] || + tb[RX_REORDER_TIMEOUT_BESTEFFORT] || + tb[RX_REORDER_TIMEOUT_BACKGROUND]) { + + /* if one is specified, all must be specified */ + if (!tb[RX_REORDER_TIMEOUT_VOICE] || + !tb[RX_REORDER_TIMEOUT_VIDEO] || + !tb[RX_REORDER_TIMEOUT_BESTEFFORT] || + !tb[RX_REORDER_TIMEOUT_BACKGROUND]) { + hdd_err("four AC timeout val are required MAC"); + return -EINVAL; + } + + reorder_timeout.rx_timeout_pri[0] = nla_get_u32( + tb[RX_REORDER_TIMEOUT_VOICE]); + reorder_timeout.rx_timeout_pri[1] = nla_get_u32( + tb[RX_REORDER_TIMEOUT_VIDEO]); + reorder_timeout.rx_timeout_pri[2] = nla_get_u32( + tb[RX_REORDER_TIMEOUT_BESTEFFORT]); + reorder_timeout.rx_timeout_pri[3] = nla_get_u32( + tb[RX_REORDER_TIMEOUT_BACKGROUND]); + /* timeout value is required to be in the rang 10 to 1000ms */ + if (reorder_timeout.rx_timeout_pri[0] >= RX_TIMEOUT_VAL_MIN && + reorder_timeout.rx_timeout_pri[0] <= RX_TIMEOUT_VAL_MAX && + reorder_timeout.rx_timeout_pri[1] >= RX_TIMEOUT_VAL_MIN && + reorder_timeout.rx_timeout_pri[1] <= RX_TIMEOUT_VAL_MAX && + reorder_timeout.rx_timeout_pri[2] >= RX_TIMEOUT_VAL_MIN && + reorder_timeout.rx_timeout_pri[2] <= RX_TIMEOUT_VAL_MAX && + reorder_timeout.rx_timeout_pri[3] >= RX_TIMEOUT_VAL_MIN && + reorder_timeout.rx_timeout_pri[3] <= RX_TIMEOUT_VAL_MAX) { + mac_handle = hdd_ctx->mac_handle; + qdf_status = sme_set_reorder_timeout(mac_handle, + &reorder_timeout); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to set reorder timeout err %d", + qdf_status); + ret_val = -EPERM; + } + } else { + hdd_err("one of the timeout value is not in range"); + ret_val = -EINVAL; + } + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_wifi_set_rx_blocksize() - set rx blocksize + * @link_info: Link info pointer in HDD adapter + * @tb: array of pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_hdd_cfg80211_wifi_set_rx_blocksize(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + int ret_val = 0; + uint32_t set_value; + QDF_STATUS qdf_status; + struct sir_peer_set_rx_blocksize rx_blocksize; + mac_handle_t mac_handle; + +#define WINDOW_SIZE_VAL_MIN 1 +#define WINDOW_SIZE_VAL_MAX 64 + + if (tb[RX_BLOCKSIZE_WINLIMIT]) { + + /* if one is specified, both must be specified */ + if (!tb[RX_BLOCKSIZE_PEER_MAC]) { + hdd_err("Both Peer MAC and windows limit required"); + return -EINVAL; + } + + memcpy(&rx_blocksize.peer_macaddr, + nla_data(tb[RX_BLOCKSIZE_PEER_MAC]), + sizeof(rx_blocksize.peer_macaddr)), + + rx_blocksize.vdev_id = link_info->vdev_id; + set_value = nla_get_u32(tb[RX_BLOCKSIZE_WINLIMIT]); + /* maximum window size is 64 */ + if (set_value >= WINDOW_SIZE_VAL_MIN && + set_value <= WINDOW_SIZE_VAL_MAX) { + rx_blocksize.rx_block_ack_win_limit = set_value; + mac_handle = hdd_ctx->mac_handle; + qdf_status = sme_set_rx_set_blocksize(mac_handle, + &rx_blocksize); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to set aggr sizes err %d", + qdf_status); + ret_val = -EPERM; + } + } else { + hdd_err("window size val is not in range"); + ret_val = -EINVAL; + } + } + + return ret_val; +} + +int hdd_set_vdev_phy_mode(struct hdd_adapter *adapter, + enum qca_wlan_vendor_phy_mode vendor_phy_mode) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct wlan_hdd_link_info *link_info = adapter->deflink; + eCsrPhyMode csr_req_phymode, csr_max_phymode; + enum reg_phymode reg_req_phymode, reg_max_phymode; + enum qca_wlan_vendor_phy_mode max_vendor_phy_mode; + WMI_HOST_WIFI_STANDARD std; + enum hdd_dot11_mode dot11_mode; + uint8_t supported_band; + int ret; + + if (hdd_cm_is_vdev_connected(link_info)) { + hdd_err("Station is connected, command is not supported"); + return -EINVAL; + } + ret = hdd_vendor_mode_to_phymode(vendor_phy_mode, &csr_req_phymode); + if (ret < 0) + return ret; + + reg_req_phymode = csr_convert_to_reg_phy_mode(csr_req_phymode, 0); + reg_max_phymode = wlan_reg_get_max_phymode(hdd_ctx->pdev, + reg_req_phymode, 0); + if (reg_req_phymode != reg_max_phymode) { + hdd_debug("reg_max_phymode %d, req_req_phymode %d", + reg_max_phymode, reg_req_phymode); + csr_max_phymode = + csr_convert_from_reg_phy_mode(reg_max_phymode); + ret = hdd_phymode_to_vendor_mode(csr_max_phymode, + &max_vendor_phy_mode); + if (ret) + return ret; + } else { + csr_max_phymode = csr_req_phymode; + max_vendor_phy_mode = vendor_phy_mode; + } + + adapter->user_phy_mode = max_vendor_phy_mode; + + ret = hdd_phymode_to_dot11_mode(csr_max_phymode, &dot11_mode); + if (ret) + return ret; + + ret = hdd_vendor_mode_to_band(max_vendor_phy_mode, &supported_band, + wlan_reg_is_6ghz_supported(psoc)); + if (ret) + return ret; + + std = hdd_get_wifi_standard(hdd_ctx, dot11_mode, supported_band); + hdd_debug("wifi_standard %d, vendor_phy_mode %d", + std, max_vendor_phy_mode); + + ret = sme_cli_set_command(link_info->vdev_id, + wmi_vdev_param_wifi_standard_version, + std, VDEV_CMD); + if (ret) { + hdd_err("Failed to set standard version to fw"); + return ret; + } + + ucfg_mlme_set_vdev_wifi_std(hdd_ctx->psoc, link_info->vdev_id, std); + + return 0; +} + +int hdd_set_phy_mode(struct hdd_adapter *adapter, + enum qca_wlan_vendor_phy_mode vendor_phy_mode) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + eCsrPhyMode csr_req_phymode, csr_max_phymode; + enum reg_phymode reg_req_phymode, reg_max_phymode; + enum qca_wlan_vendor_phy_mode max_vendor_phy_mode = vendor_phy_mode; + uint8_t supported_band; + uint32_t bonding_mode; + int ret = 0; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_VDEV; + struct hdd_adapter *curr_adapter, *next_adapter; + + if (!psoc) { + hdd_err("psoc is NULL"); + return -EINVAL; + } + + ret = hdd_vendor_mode_to_phymode(vendor_phy_mode, &csr_req_phymode); + if (ret < 0) + return ret; + + reg_req_phymode = csr_convert_to_reg_phy_mode(csr_req_phymode, 0); + reg_max_phymode = wlan_reg_get_max_phymode(hdd_ctx->pdev, + reg_req_phymode, 0); + + if (reg_req_phymode != reg_max_phymode) { + hdd_debug("reg_max_phymode %d, req_req_phymode %d", + reg_max_phymode, reg_req_phymode); + csr_max_phymode = + csr_convert_from_reg_phy_mode(reg_max_phymode); + ret = hdd_phymode_to_vendor_mode(csr_max_phymode, + &max_vendor_phy_mode); + if (ret) + return ret; + } else { + csr_max_phymode = csr_req_phymode; + max_vendor_phy_mode = vendor_phy_mode; + } + + ret = hdd_vendor_mode_to_band(max_vendor_phy_mode, &supported_band, + wlan_reg_is_6ghz_supported(psoc)); + if (ret < 0) + return ret; + + ret = hdd_vendor_mode_to_bonding_mode(max_vendor_phy_mode, + &bonding_mode); + if (ret < 0) + return ret; + + ret = hdd_update_phymode(adapter, csr_max_phymode, supported_band, + bonding_mode); + if (ret) + return ret; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, curr_adapter, next_adapter, + dbgid) { + if (curr_adapter->device_mode == QDF_STA_MODE && + !hdd_cm_is_vdev_connected(curr_adapter->deflink)) { + hdd_set_vdev_phy_mode(curr_adapter, + max_vendor_phy_mode); + } + hdd_adapter_dev_put_debug(curr_adapter, dbgid); + } + + return 0; +} + +/** + * hdd_config_phy_mode() - set PHY mode + * @link_info: Link info pointer in HDD adapter + * @tb: nla attr sent from userspace + * + * Return: 0 on success; error number otherwise + */ +static int hdd_config_phy_mode(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + enum qca_wlan_vendor_phy_mode vendor_phy_mode; + uint32_t ifindex; + struct nlattr *phy_mode_attr = tb[QCA_WLAN_VENDOR_ATTR_CONFIG_PHY_MODE]; + struct nlattr *ifindex_attr = tb[QCA_WLAN_VENDOR_ATTR_CONFIG_IFINDEX]; + + if (!phy_mode_attr) + return 0; + + vendor_phy_mode = nla_get_u32(phy_mode_attr); + if (!ifindex_attr) + return hdd_set_phy_mode(link_info->adapter, vendor_phy_mode); + + ifindex = nla_get_u32(ifindex_attr); + if (ifindex == link_info->adapter->dev->ifindex) + return hdd_set_vdev_phy_mode(link_info->adapter, + vendor_phy_mode); + + hdd_err_rl("ifindex %d, expected ifindex %d", ifindex, + link_info->adapter->dev->ifindex); + return -EINVAL; +} + +/** + * hdd_config_peer_ampdu() - Configure peer A-MPDU count + * @link_info: Link info pointer in HDD adapter + * @tb: nla attr sent from userspace + * + * Return: 0 on success; error number otherwise + */ +static int hdd_config_peer_ampdu(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct nlattr *ampdu_cnt_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_AMPDU_CNT]; + struct nlattr *ampdu_mac_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_PEER_MAC]; + struct qdf_mac_addr peer_macaddr; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + bool is_sap; + uint16_t cfg_val; + + if (!ampdu_cnt_attr) + return 0; + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + is_sap = true; + else if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) + is_sap = false; + else { + hdd_debug("mode not support"); + return -EINVAL; + } + + if (is_sap) { + if (!ampdu_mac_attr) { + hdd_debug("sap must provide peer mac attr"); + return -EINVAL; + } + nla_memcpy(&peer_macaddr, ampdu_mac_attr, QDF_MAC_ADDR_SIZE); + } else { + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_debug("vdev is null"); + return -EINVAL; + } + status = wlan_vdev_get_bss_peer_mac(vdev, &peer_macaddr); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("fail to get bss peer mac"); + return -EINVAL; + } + } + cfg_val = nla_get_u16(ampdu_cnt_attr); + return sme_set_peer_ampdu(hdd_ctx->mac_handle, + link_info->vdev_id, + &peer_macaddr, + cfg_val); +} + +/** + * hdd_set_roam_reason_vsie_status() - enable/disable inclusion of + * roam reason vsie in Reassoc + * @link_info: Link info pointer in adapter + * @attr: nla attr sent by supplicant + * + * Return: 0 on success, negative errno on failure + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static int hdd_set_roam_reason_vsie_status(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t roam_reason_vsie_enabled; + int errno; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx) { + hdd_err("hdd_ctx failure"); + return -EINVAL; + } + + roam_reason_vsie_enabled = nla_get_u8(attr); + if (roam_reason_vsie_enabled > 1) + roam_reason_vsie_enabled = 1; + + status = + ucfg_mlme_set_roam_reason_vsie_status(hdd_ctx->psoc, + roam_reason_vsie_enabled); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("set roam reason vsie failed"); + return -EINVAL; + } + + errno = sme_cli_set_command + (link_info->vdev_id, + wmi_vdev_param_enable_disable_roam_reason_vsie, + roam_reason_vsie_enabled, VDEV_CMD); + if (errno) { + hdd_err("Failed to set beacon report error vsie"); + status = QDF_STATUS_E_FAILURE; + } + + return qdf_status_to_os_return(status); +} +#else +static inline int +hdd_set_roam_reason_vsie_status(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return -ENOTSUPP; +} +#endif + +static int hdd_set_ft_over_ds(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t ft_over_ds_enable; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + if (!hdd_ctx) { + hdd_err("hdd_ctx failure"); + return -EINVAL; + } + + ft_over_ds_enable = nla_get_u8(attr); + + if (ft_over_ds_enable != 0 && ft_over_ds_enable != 1) { + hdd_err_rl("Invalid ft_over_ds_enable: %d", ft_over_ds_enable); + return -EINVAL; + } + + status = ucfg_mlme_set_ft_over_ds(hdd_ctx->psoc, ft_over_ds_enable); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("set ft_over_ds failed"); + return -EINVAL; + } + + return status; +} + +static int hdd_config_ldpc(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t ldpc; + int ret; + + ldpc = nla_get_u8(attr); + + ret = hdd_set_ldpc(link_info, ldpc); + + return ret; +} + +static int hdd_config_tx_stbc(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t tx_stbc; + int ret; + + tx_stbc = nla_get_u8(attr); + + ret = hdd_set_tx_stbc(link_info, tx_stbc); + + return ret; +} + +static int hdd_config_rx_stbc(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t rx_stbc; + int ret; + + rx_stbc = nla_get_u8(attr); + + ret = hdd_set_rx_stbc(link_info, rx_stbc); + + return ret; +} + +static int hdd_config_access_policy(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct nlattr *policy_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY]; + struct nlattr *ielist_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ACCESS_POLICY_IE_LIST]; + uint32_t access_policy; + uint8_t ie[WLAN_MAX_IE_LEN + 2]; + QDF_STATUS status; + + /* nothing to do if neither attribute is present */ + if (!ielist_attr && !policy_attr) + return 0; + + /* if one is present, both must be present */ + if (!ielist_attr || !policy_attr) { + hdd_err("Missing attribute for %s", + policy_attr ? + "ACCESS_POLICY_IE_LIST" : "ACCESS_POLICY"); + return -EINVAL; + } + + /* validate the access policy */ + access_policy = nla_get_u32(policy_attr); + switch (access_policy) { + case QCA_ACCESS_POLICY_ACCEPT_UNLESS_LISTED: + case QCA_ACCESS_POLICY_DENY_UNLESS_LISTED: + /* valid */ + break; + default: + hdd_err("Invalid value. access_policy %u", access_policy); + return -EINVAL; + } + + /* + * ie length is validated by the nla_policy. need to make a + * copy since SME will always read WLAN_MAX_IE_LEN+2 bytes + */ + nla_memcpy(ie, ielist_attr, sizeof(ie)); + + hdd_debug("calling sme_update_access_policy_vendor_ie"); + status = sme_update_access_policy_vendor_ie(hdd_ctx->mac_handle, + link_info->vdev_id, + ie, access_policy); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set vendor ie and access policy, %d", + status); + + return qdf_status_to_os_return(status); +} + +static int hdd_config_mpdu_aggregation(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct nlattr *tx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION]; + struct nlattr *rx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION]; + uint8_t tx_size, rx_size; + QDF_STATUS status; + + /* nothing to do if neither attribute is present */ + if (!tx_attr && !rx_attr) + return 0; + + /* if one is present, both must be present */ + if (!tx_attr || !rx_attr) { + hdd_err("Missing attribute for %s", + tx_attr ? "RX" : "TX"); + return -EINVAL; + } + + tx_size = nla_get_u8(tx_attr); + rx_size = nla_get_u8(rx_attr); + if (!cfg_in_range(CFG_TX_AGGREGATION_SIZE, tx_size) || + !cfg_in_range(CFG_RX_AGGREGATION_SIZE, rx_size)) { + hdd_err("TX %d RX %d MPDU aggr size not in range", + tx_size, rx_size); + + return -EINVAL; + } + + status = wma_set_tx_rx_aggr_size(link_info->vdev_id, + tx_size, rx_size, + WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU); + + return qdf_status_to_os_return(status); +} + +static int hdd_config_msdu_aggregation(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct nlattr *tx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION]; + struct nlattr *rx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION]; + uint8_t tx_size, rx_size; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + QDF_STATUS status; + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + /* nothing to do if neither attribute is present */ + if (!tx_attr && !rx_attr) + return 0; + + /* if one is present, both must be present */ + if (!tx_attr || !rx_attr) { + hdd_err("Missing attribute for %s", + tx_attr ? "RX" : "TX"); + return -EINVAL; + } + + tx_size = nla_get_u8(tx_attr); + rx_size = nla_get_u8(rx_attr); + if (!cfg_in_range(CFG_TX_AGGREGATION_SIZE, tx_size) || + !cfg_in_range(CFG_RX_AGGREGATION_SIZE, rx_size)) { + hdd_err("TX %d RX %d MSDU aggr size not in range", + tx_size, rx_size); + + return -EINVAL; + } + + if (tx_size > 1) + sme_set_amsdu(mac_handle, true); + else + sme_set_amsdu(mac_handle, false); + + hdd_debug("tx size: %d", tx_size); + status = wma_cli_set_command(link_info->vdev_id, + GEN_VDEV_PARAM_AMSDU, + tx_size, GEN_CMD); + if (status) { + hdd_err("Failed to set AMSDU param to FW, status %d", status); + return qdf_status_to_os_return(status); + } + + return qdf_status_to_os_return(status); +} + +static QDF_STATUS +hdd_populate_vdev_chains(struct wlan_mlme_nss_chains *nss_chains_cfg, + uint8_t tx_chains, + uint8_t rx_chains, + enum nss_chains_band_info band, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlme_nss_chains *dynamic_cfg; + + nss_chains_cfg->num_rx_chains[band] = rx_chains; + nss_chains_cfg->num_tx_chains[band] = tx_chains; + + dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + hdd_err("nss chain dynamic config NULL"); + return QDF_STATUS_E_FAILURE; + } + /* + * If user gives any nss value, then chains will be adjusted based on + * nss (in SME func sme_validate_user_nss_chain_params). + * If Chains are not suitable as per current NSS then, we need to + * return, and the below logic is added for the same. + */ + + if ((dynamic_cfg->rx_nss[band] > rx_chains) || + (dynamic_cfg->tx_nss[band] > tx_chains)) { + hdd_err("Chains less than nss, configure correct nss first."); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +int +hdd_set_dynamic_antenna_mode(struct wlan_hdd_link_info *link_info, + uint8_t num_rx_chains, uint8_t num_tx_chains) +{ + enum nss_chains_band_info band; + struct wlan_mlme_nss_chains user_cfg; + QDF_STATUS status; + mac_handle_t mac_handle; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct wlan_objmgr_vdev *vdev; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("NULL MAC handle"); + return -EINVAL; + } + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_debug("Vdev (id %d) not in connected/started state, cannot accept command", + link_info->vdev_id); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + qdf_mem_zero(&user_cfg, sizeof(user_cfg)); + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) { + status = hdd_populate_vdev_chains(&user_cfg, + num_tx_chains, + num_rx_chains, band, vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return -EINVAL; + } + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + status = sme_nss_chains_update(mac_handle, + &user_cfg, + link_info->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return 0; +} + +static int hdd_config_vdev_chains(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t tx_chains, rx_chains; + struct nlattr *tx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS]; + struct nlattr *rx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS]; + + if (!tx_attr && !rx_attr) + return 0; + + /* if one is present, both must be present */ + if (!tx_attr || !rx_attr) { + hdd_err("Missing attribute for %s", + tx_attr ? "RX" : "TX"); + return -EINVAL; + } + + tx_chains = nla_get_u8(tx_attr); + rx_chains = nla_get_u8(rx_attr); + + hdd_debug("tx_chains %d rx_chains %d", tx_chains, rx_chains); + if (hdd_ctx->dynamic_nss_chains_support) + return hdd_set_dynamic_antenna_mode(link_info, + rx_chains, tx_chains); + return 0; +} + +static int hdd_config_tx_rx_nss(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + uint8_t tx_nss, rx_nss; + QDF_STATUS status; + + struct nlattr *tx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS]; + struct nlattr *rx_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS]; + + if (!tx_attr && !rx_attr) + return 0; + + /* if one is present, both must be present */ + if (!tx_attr || !rx_attr) { + hdd_err("Missing attribute for %s", + tx_attr ? "RX" : "TX"); + return -EINVAL; + } + + tx_nss = nla_get_u8(tx_attr); + rx_nss = nla_get_u8(rx_attr); + hdd_debug("tx_nss %d rx_nss %d", tx_nss, rx_nss); + /* Only allow NSS for tx_rx_nss for 1x1, 1x2, 2x2 */ + if (!((tx_nss == 1 && rx_nss == 2) || (tx_nss == 1 && rx_nss == 1) || + (tx_nss == 2 && rx_nss == 2))) { + hdd_err("Setting tx_nss %d rx_nss %d not allowed", tx_nss, + rx_nss); + return -EINVAL; + } + status = hdd_update_nss(link_info, tx_nss, rx_nss); + if (status != QDF_STATUS_SUCCESS) { + hdd_debug("Can't set tx_nss %d rx_nss %d", tx_nss, rx_nss); + return -EINVAL; + } + + return 0; +} + +#ifdef WLAN_FEATURE_SON +static int hdd_process_generic_set_cmd(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct hdd_adapter *adapter = link_info->adapter; + + if (!adapter) + return 0; + + wdev = &adapter->wdev; + if (!wdev || !wdev->wiphy) + return 0; + wiphy = wdev->wiphy; + + /* Generic command is used by EasyMesh, + * route the command to SON module if it is Generic + */ + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND]) + return hdd_son_send_set_wifi_generic_command(wiphy, wdev, tb); + + return 0; +} +#else +static inline int +hdd_process_generic_set_cmd(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + return 0; +} +#endif + +static int hdd_config_ani(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + int errno; + uint8_t ani_setting_type; + int32_t ani_level = 0, enable_ani; + struct nlattr *ani_setting_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_SETTING]; + struct nlattr *ani_level_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANI_LEVEL]; + + if (!ani_setting_attr) + return 0; + + ani_setting_type = nla_get_u8(ani_setting_attr); + if (ani_setting_type != QCA_WLAN_ANI_SETTING_AUTO && + ani_setting_type != QCA_WLAN_ANI_SETTING_FIXED) { + hdd_err("invalid ani_setting_type %d", ani_setting_type); + return -EINVAL; + } + + if (ani_setting_type == QCA_WLAN_ANI_SETTING_AUTO && + ani_level_attr) { + hdd_err("Not support to set ani level in QCA_WLAN_ANI_SETTING_AUTO"); + return -EINVAL; + } + + if (ani_setting_type == QCA_WLAN_ANI_SETTING_FIXED) { + if (!ani_level_attr) { + hdd_err("invalid ani_level_attr"); + return -EINVAL; + } + ani_level = nla_get_s32(ani_level_attr); + } + hdd_debug("ani_setting_type %u, ani_level %d", + ani_setting_type, ani_level); + + /* ANI (Adaptive noise immunity) */ + if (ani_setting_type == QCA_WLAN_ANI_SETTING_AUTO) + enable_ani = 1; + else + enable_ani = 0; + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ani_enable, + enable_ani, PDEV_CMD); + if (errno) { + hdd_err("Failed to set ani enable, errno %d", errno); + return errno; + } + + if (ani_setting_type == QCA_WLAN_ANI_SETTING_FIXED) { + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ani_ofdm_level, + ani_level, PDEV_CMD); + if (errno) { + hdd_err("Failed to set ani level, errno %d", errno); + return errno; + } + } + + return 0; +} + +static int hdd_config_ant_div_period(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct nlattr *probe_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_PERIOD]; + struct nlattr *stay_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_STAY_PERIOD]; + uint32_t probe_period, stay_period, ant_div_usrcfg; + int errno; + + /* nothing to do if neither attribute is present */ + if (!probe_attr && !stay_attr) + return 0; + + /* if one is present, both must be present */ + if (!probe_attr || !stay_attr) { + hdd_err("Missing attribute for %s", + probe_attr ? "STAY" : "PROBE"); + return -EINVAL; + } + + probe_period = nla_get_u32(probe_attr); + stay_period = nla_get_u32(stay_attr); + ant_div_usrcfg = ANT_DIV_SET_PERIOD(probe_period, stay_period); + hdd_debug("ant div set period: %x", ant_div_usrcfg); + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ant_div_usrcfg, + ant_div_usrcfg, PDEV_CMD); + if (errno) + hdd_err("Failed to set ant div period, %d", errno); + + return errno; +} + +static int hdd_config_ant_div_snr_weight(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct nlattr *mgmt_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_MGMT_SNR_WEIGHT]; + struct nlattr *data_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_DATA_SNR_WEIGHT]; + struct nlattr *ack_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ACK_SNR_WEIGHT]; + uint32_t mgmt_snr, data_snr, ack_snr, ant_div_usrcfg; + int errno; + + /* nothing to do if none of the attributes are present */ + if (!mgmt_attr && !data_attr && !ack_attr) + return 0; + + /* if one is present, all must be present */ + if (!mgmt_attr || !data_attr || !ack_attr) { + hdd_err("Missing attribute"); + return -EINVAL; + } + + mgmt_snr = nla_get_u32(mgmt_attr); + data_snr = nla_get_u32(data_attr); + ack_snr = nla_get_u32(ack_attr); + ant_div_usrcfg = ANT_DIV_SET_WEIGHT(mgmt_snr, data_snr, ack_snr); + hdd_debug("ant div set weight: %x", ant_div_usrcfg); + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ant_div_usrcfg, + ant_div_usrcfg, PDEV_CMD); + if (errno) + hdd_err("Failed to set ant div weight, %d", errno); + + return errno; +} + +static int +hdd_config_fine_time_measurement(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t user_capability; + uint32_t target_capability; + uint32_t final_capability; + QDF_STATUS status; + + user_capability = nla_get_u32(attr); + target_capability = hdd_ctx->fine_time_meas_cap_target; + final_capability = user_capability & target_capability; + + status = ucfg_mlme_set_fine_time_meas_cap(hdd_ctx->psoc, + final_capability); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to set value, status %d", status); + return -EINVAL; + } + + sme_update_fine_time_measurement_capab(hdd_ctx->mac_handle, + link_info->vdev_id, + final_capability); + ucfg_wifi_pos_set_ftm_cap(hdd_ctx->psoc, final_capability); + + hdd_debug("user: 0x%x, target: 0x%x, final: 0x%x", + user_capability, target_capability, final_capability); + + return 0; +} + +static int hdd_config_dynamic_dtim(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t modulated_dtim; + QDF_STATUS status; + + modulated_dtim = nla_get_u32(attr); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + status = ucfg_pmo_config_modulated_dtim(vdev, modulated_dtim); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return qdf_status_to_os_return(status); +} + +static int hdd_config_listen_interval(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t listen_interval; + QDF_STATUS status; + + listen_interval = nla_get_u32(attr); + if (listen_interval > cfg_max(CFG_PMO_ENABLE_DYNAMIC_DTIM)) { + hdd_err_rl("Invalid value for listen interval - %d", + listen_interval); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_PMO_ID); + if (!vdev) + return -EINVAL; + + status = ucfg_pmo_config_listen_interval(vdev, listen_interval); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_PMO_ID); + + return qdf_status_to_os_return(status); +} + +static int hdd_config_lro(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct wlan_objmgr_vdev *vdev; + uint8_t enable_flag; + QDF_STATUS status = QDF_STATUS_E_FAULT; + + enable_flag = nla_get_u8(attr); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + status = osif_dp_lro_set_reset(vdev, enable_flag); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + return qdf_status_to_os_return(status); +} + +static int hdd_config_scan_enable(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint8_t enable_flag; + + enable_flag = nla_get_u8(attr); + if (enable_flag) + ucfg_scan_psoc_set_enable(hdd_ctx->psoc, REASON_USER_SPACE); + else + ucfg_scan_psoc_set_disable(hdd_ctx->psoc, REASON_USER_SPACE); + + return 0; +} + +/** + * hdd_config_udp_qos_upgrade_be_bk() - Set UDP QoS threshold for BE/BK AC. + * @link_info: Link info pointer in HDD adapter + * @attr: NL attribute + * + * Returns: 0 on success, -EINVAL on failure + */ +static int +hdd_config_udp_qos_upgrade_be_bk(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + uint8_t priority = nla_get_u8(attr); + + adapter->udp_qos_upgrade_type = UDP_QOS_UPGRADE_BK_BE; + return hdd_set_udp_qos_upgrade_config(adapter, priority); +} + +/** + * hdd_config_udp_qos_upgrade_threshold() - NL attribute handler to parse + * priority upgrade threshold value. + * @link_info: Link info pointer in adapter + * @attr: NL attribute + * + * Returns: 0 on success, -EINVAL on failure + */ +static int +hdd_config_udp_qos_upgrade_threshold(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + uint8_t priority = nla_get_u8(attr); + + adapter->udp_qos_upgrade_type = UDP_QOS_UPGRADE_ALL; + return hdd_set_udp_qos_upgrade_config(adapter, priority); +} + +static enum powersave_mode +hdd_vendor_opm_to_pmo_opm(enum qca_wlan_vendor_opm_mode opm_mode) +{ + switch (opm_mode) { + case QCA_WLAN_VENDOR_OPM_MODE_DISABLE: + return PMO_PS_ADVANCED_POWER_SAVE_DISABLE; + case QCA_WLAN_VENDOR_OPM_MODE_ENABLE: + return PMO_PS_ADVANCED_POWER_SAVE_ENABLE; + case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED: + return PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED; + default: + hdd_debug("Invalid opm_mode: %d", opm_mode); + return PMO_PS_ADVANCED_POWER_SAVE_DISABLE; + } +} + +static int hdd_config_power(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_vdev *vdev; + enum qca_wlan_vendor_opm_mode opm_mode; + struct pmo_ps_params ps_params = {0}; + struct nlattr *power_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_QPOWER]; + struct nlattr *opm_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT]; + struct nlattr *ps_ito_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_ITO]; + struct nlattr *spec_wake_attr = + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_OPM_SPEC_WAKE_INTERVAL]; + int ret; + + hdd_enter_dev(adapter->dev); + + if (!power_attr && !opm_attr) { + hdd_err_rl("power attr and opm attr is null"); + return 0; + } + + + if (power_attr && opm_attr) { + hdd_err_rl("Invalid OPM set attribute"); + return -EINVAL; + } + + if (!ucfg_pmo_get_default_power_save_mode(hdd_ctx->psoc)) { + hdd_err_rl("OPM power save is disabled in ini"); + return -EINVAL; + } + + opm_mode = power_attr ? nla_get_u8(power_attr) : nla_get_u8(opm_attr); + hdd_debug("opm_mode %d", opm_mode); + + if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) { + if (!ps_ito_attr || !spec_wake_attr) { + hdd_err_rl("Invalid User defined OPM attributes"); + return -EINVAL; + } + } + + ret = hdd_set_power_config(hdd_ctx, adapter, &opm_mode); + if (ret) + return ret; + + ps_params.opm_mode = hdd_vendor_opm_to_pmo_opm(opm_mode); + if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) { + ps_params.ps_ito = nla_get_u16(ps_ito_attr); + ps_params.spec_wake = nla_get_u16(spec_wake_attr); + + if (!ps_params.ps_ito) + return -EINVAL; + + hdd_debug("ps_ito %d spec_wake %d opm_mode %d", + ps_params.ps_ito, ps_params.spec_wake, + ps_params.opm_mode); + + ret = hdd_set_power_config_params(hdd_ctx, adapter, + ps_params.ps_ito, + ps_params.spec_wake); + + if (ret) + return ret; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev is null"); + return 0; + } + + if (opm_mode == QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED) + ucfg_pmo_set_ps_params(vdev, &ps_params); + else + ucfg_pmo_core_vdev_set_ps_opm_mode(vdev, ps_params.opm_mode); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + return 0; +} + +static int hdd_config_stats_avg_factor(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint16_t stats_avg_factor; + QDF_STATUS status; + + stats_avg_factor = nla_get_u16(attr); + status = sme_configure_stats_avg_factor(hdd_ctx->mac_handle, + link_info->vdev_id, + stats_avg_factor); + + return qdf_status_to_os_return(status); +} + +static int hdd_config_non_agg_retry(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t retry; + + retry = nla_get_u8(attr); + /* Value less than CFG_AGG_RETRY_MIN has side effect to t-put */ + retry = (retry > CFG_NON_AGG_RETRY_MAX) ? CFG_NON_AGG_RETRY_MAX : + ((retry < CFG_NON_AGG_RETRY_MIN) ? CFG_NON_AGG_RETRY_MIN : + retry); + hdd_debug("sending Non-Agg Retry Th: %d", retry); + + return sme_set_vdev_sw_retry(link_info->vdev_id, retry, + WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR); +} + +static int hdd_config_agg_retry(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t retry; + + retry = nla_get_u8(attr); + /* Value less than CFG_AGG_RETRY_MIN has side effect to t-put */ + retry = (retry > CFG_AGG_RETRY_MAX) ? CFG_AGG_RETRY_MAX : + ((retry < CFG_AGG_RETRY_MIN) ? CFG_AGG_RETRY_MIN : + retry); + hdd_debug("sending Agg Retry Th: %d", retry); + + return sme_set_vdev_sw_retry(link_info->vdev_id, retry, + WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR); +} + +static int hdd_config_mgmt_retry(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t retry; + int param_id; + uint8_t max_mgmt_retry; + + retry = nla_get_u8(attr); + max_mgmt_retry = (cfg_max(CFG_MGMT_RETRY_MAX)); + retry = retry > max_mgmt_retry ? + max_mgmt_retry : retry; + param_id = wmi_pdev_param_mgmt_retry_limit; + + return wma_cli_set_command(link_info->vdev_id, param_id, + retry, PDEV_CMD); +} + +static int hdd_config_ctrl_retry(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t retry; + int param_id; + + retry = nla_get_u8(attr); + retry = retry > CFG_CTRL_RETRY_MAX ? + CFG_CTRL_RETRY_MAX : retry; + param_id = wmi_pdev_param_ctrl_retry_limit; + + return wma_cli_set_command(link_info->vdev_id, param_id, + retry, PDEV_CMD); +} + +static int hdd_config_propagation_delay(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t delay; + uint32_t abs_delay; + int param_id; + + delay = nla_get_u8(attr); + delay = delay > CFG_PROPAGATION_DELAY_MAX ? + CFG_PROPAGATION_DELAY_MAX : delay; + abs_delay = delay + CFG_PROPAGATION_DELAY_BASE; + param_id = wmi_pdev_param_propagation_delay; + + return wma_cli_set_command(link_info->vdev_id, param_id, + abs_delay, PDEV_CMD); +} + +static int +hdd_config_propagation_abs_delay(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t abs_delay; + int param_id; + + abs_delay = nla_get_u32(attr); + param_id = wmi_pdev_param_propagation_delay; + + return wma_cli_set_command(link_info->vdev_id, param_id, + abs_delay, PDEV_CMD); +} + +static int hdd_config_tx_fail_count(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint32_t tx_fail_count; + QDF_STATUS status; + + tx_fail_count = nla_get_u32(attr); + if (!tx_fail_count) + return 0; + + status = sme_update_tx_fail_cnt_threshold(hdd_ctx->mac_handle, + link_info->vdev_id, + tx_fail_count); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("sme_update_tx_fail_cnt_threshold (err=%d)", + status); + + return qdf_status_to_os_return(status); +} + +static int +hdd_config_channel_avoidance_ind(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint8_t set_value; + + set_value = nla_get_u8(attr); + hdd_debug("set_value: %d", set_value); + + return hdd_enable_disable_ca_event(hdd_ctx, set_value); +} + +static int hdd_config_guard_time(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t guard_time; + QDF_STATUS status; + + guard_time = nla_get_u32(attr); + status = sme_configure_guard_time(hdd_ctx->mac_handle, + link_info->vdev_id, guard_time); + + return qdf_status_to_os_return(status); +} + +static int +hdd_config_scan_default_ies(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t *scan_ie; + uint16_t scan_ie_len; + QDF_STATUS status; + mac_handle_t mac_handle; + + scan_ie_len = nla_len(attr); + hdd_debug("IE len %d session %d device mode %d", + scan_ie_len, link_info->vdev_id, adapter->device_mode); + + if (!scan_ie_len) { + hdd_err("zero-length IE prohibited"); + return -EINVAL; + } + + if (scan_ie_len > MAX_DEFAULT_SCAN_IE_LEN) { + hdd_err("IE length %d exceeds max of %d", + scan_ie_len, MAX_DEFAULT_SCAN_IE_LEN); + return -EINVAL; + } + + scan_ie = nla_data(attr); + if (!wlan_is_ie_valid(scan_ie, scan_ie_len)) { + hdd_err("Invalid default scan IEs"); + return -EINVAL; + } + + if (wlan_hdd_save_default_scan_ies(hdd_ctx, adapter, + scan_ie, scan_ie_len)) + hdd_err("Failed to save default scan IEs"); + + if (adapter->device_mode == QDF_STA_MODE) { + mac_handle = hdd_ctx->mac_handle; + status = sme_set_default_scan_ie(mac_handle, + link_info->vdev_id, + scan_ie, scan_ie_len); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to set default scan IEs in sme: %d", + status); + return -EPERM; + } + } + + return 0; +} + +static int hdd_config_ant_div_ena(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t antdiv_enable; + int errno; + + antdiv_enable = nla_get_u32(attr); + hdd_debug("antdiv_enable: %d", antdiv_enable); + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ena_ant_div, + antdiv_enable, PDEV_CMD); + if (errno) + hdd_err("Failed to set antdiv_enable, %d", errno); + + return errno; +} + +static int hdd_config_ant_div_snr_diff(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t ant_div_snr_diff; + uint32_t ant_div_usrcfg; + int errno; + + ant_div_snr_diff = nla_get_u32(attr); + hdd_debug("snr diff: %x", ant_div_snr_diff); + + ant_div_usrcfg = ANT_DIV_SET_SNR_DIFF(ant_div_snr_diff); + hdd_debug("usrcfg: %x", ant_div_usrcfg); + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ant_div_usrcfg, + ant_div_usrcfg, PDEV_CMD); + if (errno) + hdd_err("Failed to set snr diff, %d", errno); + + return errno; +} + +static int +hdd_config_ant_div_probe_dwell_time(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t dwell_time; + uint32_t ant_div_usrcfg; + int errno; + + dwell_time = nla_get_u32(attr); + hdd_debug("dwell time: %x", dwell_time); + + ant_div_usrcfg = ANT_DIV_SET_PROBE_DWELL_TIME(dwell_time); + hdd_debug("usrcfg: %x", ant_div_usrcfg); + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ant_div_usrcfg, + ant_div_usrcfg, PDEV_CMD); + if (errno) + hdd_err("Failed to set probe dwell time, %d", errno); + + return errno; +} + +static int hdd_config_ant_div_chain(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t antdiv_chain; + int errno; + + antdiv_chain = nla_get_u32(attr); + hdd_debug("antdiv_chain: %d", antdiv_chain); + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_force_chain_ant, + antdiv_chain, PDEV_CMD); + if (errno) + hdd_err("Failed to set chain, %d", errno); + + return errno; +} + +static int hdd_config_ant_div_selftest(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t antdiv_selftest; + int errno; + + antdiv_selftest = nla_get_u32(attr); + hdd_debug("antdiv_selftest: %d", antdiv_selftest); + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ant_div_selftest, + antdiv_selftest, PDEV_CMD); + if (errno) + hdd_err("Failed to set selftest, %d", errno); + + return errno; +} + +static int +hdd_config_ant_div_selftest_intvl(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint32_t antdiv_selftest_intvl; + int errno; + + antdiv_selftest_intvl = nla_get_u32(attr); + hdd_debug("antdiv_selftest_intvl: %d", antdiv_selftest_intvl); + errno = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_ant_div_selftest_intvl, + antdiv_selftest_intvl, PDEV_CMD); + if (errno) + hdd_err("Failed to set selftest interval, %d", errno); + + return errno; +} + +static int +hdd_config_ignore_assoc_disallowed(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint8_t ignore_assoc_disallowed; + + ignore_assoc_disallowed = nla_get_u8(attr); + hdd_debug("%u", ignore_assoc_disallowed); + if ((ignore_assoc_disallowed < QCA_IGNORE_ASSOC_DISALLOWED_DISABLE) || + (ignore_assoc_disallowed > QCA_IGNORE_ASSOC_DISALLOWED_ENABLE)) + return -EINVAL; + + sme_set_check_assoc_disallowed(hdd_ctx->mac_handle, + !ignore_assoc_disallowed); + + return 0; +} + +static int hdd_config_restrict_offchannel(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t restrict_offchan; + + restrict_offchan = nla_get_u8(attr); + hdd_debug("%u", restrict_offchan); + + if (restrict_offchan > 1) { + hdd_err("Invalid value %u", restrict_offchan); + return -EINVAL; + } + + return wlan_hdd_handle_restrict_offchan_config(link_info->adapter, + restrict_offchan); +} + +static int +hdd_config_total_beacon_miss_count(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t first_miss_count; + uint8_t final_miss_count; + uint8_t total_miss_count; + QDF_STATUS status; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("Only supported in sta mode"); + return -EINVAL; + } + + total_miss_count = nla_get_u8(attr); + ucfg_mlme_get_roam_bmiss_first_bcnt(hdd_ctx->psoc, + &first_miss_count); + if (total_miss_count <= first_miss_count) { + hdd_err("Total %u needs to exceed first %u", + total_miss_count, first_miss_count); + return -EINVAL; + } + + final_miss_count = total_miss_count - first_miss_count; + + if (!ucfg_mlme_validate_roam_bmiss_final_bcnt(final_miss_count)) + return -EINVAL; + + hdd_debug("First count %u, final count %u", + first_miss_count, final_miss_count); + + status = sme_set_roam_bmiss_final_bcnt(hdd_ctx->mac_handle, + link_info->vdev_id, + final_miss_count); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set final count, status %u", status); + return qdf_status_to_os_return(status); + } + + status = sme_set_bmiss_bcnt(link_info->vdev_id, + first_miss_count, + final_miss_count); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set count, status %u", status); + + return qdf_status_to_os_return(status); +} + +#ifdef WLAN_FEATURE_LL_MODE +static inline +void wlan_hdd_set_wlm_mode(struct hdd_context *hdd_ctx, uint16_t latency_level) +{ + if (latency_level == + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW) + wlan_hdd_set_pm_qos_request(hdd_ctx, true); + else + wlan_hdd_set_pm_qos_request(hdd_ctx, false); +} +#else +static inline +void wlan_hdd_set_wlm_mode(struct hdd_context *hdd_ctx, uint16_t latency_level) +{ +} +#endif + +/** + * hdd_set_wlm_host_latency_level() - set latency flags based on latency flags + * @hdd_ctx: hdd context + * @adapter: adapter context + * @latency_host_flags: host latency flags + * + * Return: none + */ +static void hdd_set_wlm_host_latency_level(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint32_t latency_host_flags) +{ + ol_txrx_soc_handle soc_hdl = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_vdev *vdev; + + if (!soc_hdl) + return; + + if (latency_host_flags & WLM_HOST_PM_QOS_FLAG) { + hdd_ctx->pm_qos_request_flags |= + (1 << adapter->deflink->vdev_id); + } else { + hdd_ctx->pm_qos_request_flags &= + ~(1 << adapter->deflink->vdev_id); + } + + if (hdd_ctx->pm_qos_request_flags) + wlan_hdd_set_pm_qos_request(hdd_ctx, true); + else + wlan_hdd_set_pm_qos_request(hdd_ctx, false); + + if (latency_host_flags & WLM_HOST_HBB_FLAG) + ucfg_dp_set_high_bus_bw_request(hdd_ctx->psoc, + adapter->deflink->vdev_id, + true); + else + ucfg_dp_set_high_bus_bw_request(hdd_ctx->psoc, + adapter->deflink->vdev_id, + false); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return; + + if (latency_host_flags & WLM_HOST_RX_THREAD_FLAG) + ucfg_dp_runtime_disable_rx_thread(vdev, true); + else + ucfg_dp_runtime_disable_rx_thread(vdev, false); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +void +hdd_latency_level_event_handler_cb(const struct latency_level_data *event_data, + uint8_t vdev_id) +{ + struct osif_request *request; + struct latency_level_data *data; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *hdd_adapter; + uint32_t latency_host_flags = 0; + QDF_STATUS status; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!event_data) { + hdd_err("Invalid latency level event data"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("adapter is NULL vdev_id = %d", vdev_id); + return; + } + + hdd_adapter = link_info->adapter; + if (hdd_adapter->multi_ll_resp_expected) { + request = + osif_request_get(hdd_adapter->multi_ll_response_cookie); + if (!request) { + hdd_err("Invalid request"); + return; + } + data = osif_request_priv(request); + data->latency_level = event_data->latency_level; + data->vdev_id = event_data->vdev_id; + osif_request_complete(request); + osif_request_put(request); + } else { + hdd_adapter->latency_level = event_data->latency_level; + wlan_hdd_set_wlm_mode(hdd_ctx, hdd_adapter->latency_level); + hdd_debug("adapter->latency_level:%d", + hdd_adapter->latency_level); + status = ucfg_mlme_get_latency_host_flags(hdd_ctx->psoc, + hdd_adapter->latency_level, + &latency_host_flags); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to get latency host flags"); + else + hdd_set_wlm_host_latency_level(hdd_ctx, hdd_adapter, + latency_host_flags); + } + + hdd_exit(); +} + +uint8_t wlan_hdd_get_client_id_bitmap(struct hdd_adapter *adapter) +{ + uint8_t i, client_id_bitmap = 0; + + for (i = 0; i < WLM_MAX_HOST_CLIENT; i++) { + if (!adapter->client_info[i].in_use) + continue; + client_id_bitmap |= + BIT(adapter->client_info[i].client_id); + } + + return client_id_bitmap; +} + +QDF_STATUS wlan_hdd_get_set_client_info_id(struct hdd_adapter *adapter, + uint32_t port_id, + uint32_t *client_id) +{ + uint8_t i; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + for (i = 0; i < WLM_MAX_HOST_CLIENT; i++) { + if (adapter->client_info[i].in_use) { + /* Receives set latency cmd for an existing port id */ + if (port_id == adapter->client_info[i].port_id) { + *client_id = adapter->client_info[i].client_id; + status = QDF_STATUS_SUCCESS; + break; + } + continue; + } else { + /* Process set latency level from a new client */ + adapter->client_info[i].in_use = true; + adapter->client_info[i].port_id = port_id; + *client_id = adapter->client_info[i].client_id; + status = QDF_STATUS_SUCCESS; + break; + } + } + + if (i == WLM_MAX_HOST_CLIENT) + hdd_debug("Max client ID reached"); + + return status; +} + +QDF_STATUS wlan_hdd_set_wlm_latency_level(struct hdd_adapter *adapter, + uint16_t latency_level, + uint32_t client_id_bitmap, + bool force_reset) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + struct osif_request *request = NULL; + struct latency_level_data *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_WLM_LATENCY_LEVEL, + .dealloc = NULL, + }; + + /* ignore unless in STA mode */ + if (adapter->device_mode != QDF_STA_MODE) { + hdd_debug_rl("WLM offload is supported in STA mode only"); + return QDF_STATUS_E_FAILURE; + } + + adapter->multi_ll_resp_expected = true; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_FAILURE; + } + adapter->multi_ll_response_cookie = osif_request_cookie(request); + adapter->multi_ll_req_in_progress = true; + + status = sme_set_wlm_latency_level(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + latency_level, client_id_bitmap, + force_reset); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failure while sending command to fw"); + goto err; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving latency level"); + status = qdf_status_from_os_return(ret); + goto err; + } + priv = osif_request_priv(request); + if (!priv) { + hdd_err("invalid get latency level"); + status = QDF_STATUS_E_FAILURE; + goto err; + } + + hdd_debug("latency level received from FW:%d", priv->latency_level); + adapter->latency_level = priv->latency_level; +err: + if (request) + osif_request_put(request); + adapter->multi_ll_req_in_progress = false; + adapter->multi_ll_resp_expected = false; + adapter->multi_ll_response_cookie = NULL; + + return status; +} + +bool hdd_get_multi_client_ll_support(struct hdd_adapter *adapter) +{ + return adapter->multi_client_ll_support; +} + +/** + * wlan_hdd_reset_client_info() - reset multi client info table + * @adapter: adapter context + * @client_id: client id + * + * Return: none + */ +static void wlan_hdd_reset_client_info(struct hdd_adapter *adapter, + uint32_t client_id) +{ + adapter->client_info[client_id].in_use = false; + adapter->client_info[client_id].port_id = 0; + adapter->client_info[client_id].client_id = client_id; +} + +QDF_STATUS wlan_hdd_set_wlm_client_latency_level(struct hdd_adapter *adapter, + uint32_t port_id, + uint16_t latency_level) +{ + uint32_t client_id, client_id_bitmap; + QDF_STATUS status; + + status = wlan_hdd_get_set_client_info_id(adapter, port_id, + &client_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + client_id_bitmap = BIT(client_id); + status = wlan_hdd_set_wlm_latency_level(adapter, + latency_level, + client_id_bitmap, + false); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Fail to set latency level for client_id:%d", + client_id); + wlan_hdd_reset_client_info(adapter, client_id); + return status; + } + return status; +} + +/** + * wlan_hdd_get_multi_ll_req_in_progress() - get multi_ll_req_in_progress flag + * @adapter: adapter context + * + * Return: true if multi ll req in progress + */ +static bool wlan_hdd_get_multi_ll_req_in_progress(struct hdd_adapter *adapter) +{ + return adapter->multi_ll_req_in_progress; +} +#else +static inline bool +wlan_hdd_get_multi_ll_req_in_progress(struct hdd_adapter *adapter) +{ + return false; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)) +static QDF_STATUS hdd_get_netlink_sender_portid(struct hdd_context *hdd_ctx, + uint32_t *port_id) +{ + struct wiphy *wiphy = hdd_ctx->wiphy; + + /* get netlink portid of sender */ + *port_id = cfg80211_vendor_cmd_get_sender(wiphy); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +hdd_get_netlink_sender_portid(struct hdd_context *hdd_ctx, uint32_t *port_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +static int hdd_config_latency_level(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t port_id; + uint16_t latency_level, host_latency_level; + QDF_STATUS status; + uint32_t latency_host_flags = 0; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + if (!hdd_is_wlm_latency_manager_supported(hdd_ctx)) + return -ENOTSUPP; + + latency_level = nla_get_u16(attr); + switch (latency_level) { + case QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL: + case QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_XR: + case QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW: + case QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW: + /* valid values */ + break; + default: + hdd_err("Invalid value %u", latency_level); + return -EINVAL; + } + + host_latency_level = latency_level - 1; + + if (hdd_get_multi_client_ll_support(adapter)) { + if (wlan_hdd_get_multi_ll_req_in_progress(adapter)) { + hdd_err_rl("multi ll request already in progress"); + return -EBUSY; + } + /* get netlink portid of sender */ + status = hdd_get_netlink_sender_portid(hdd_ctx, &port_id); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + status = wlan_hdd_set_wlm_client_latency_level(adapter, port_id, + host_latency_level); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Fail to set latency level"); + goto error; + } + } else { + status = sme_set_wlm_latency_level(hdd_ctx->mac_handle, + link_info->vdev_id, + host_latency_level, 0, + false); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("set latency level failed, %u", status); + goto error; + } + adapter->latency_level = host_latency_level; + } + + wlan_hdd_set_wlm_mode(hdd_ctx, adapter->latency_level); + hdd_debug("adapter->latency_level:%d", adapter->latency_level); + + status = ucfg_mlme_get_latency_host_flags(hdd_ctx->psoc, + adapter->latency_level, + &latency_host_flags); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to get latency host flags"); + else + hdd_set_wlm_host_latency_level(hdd_ctx, adapter, + latency_host_flags); +error: + ret = qdf_status_to_os_return(status); + + return ret; +} + +static int hdd_config_disable_fils(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t disable_fils; + bool enabled; + QDF_STATUS status; + + /* ignore unless in STA mode */ + if (adapter->device_mode != QDF_STA_MODE) + return 0; + + disable_fils = nla_get_u8(attr); + hdd_debug("%u", disable_fils); + + enabled = !disable_fils; + status = ucfg_mlme_set_fils_enabled_info(hdd_ctx->psoc, enabled); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set fils enabled info, %d", status); + + status = ucfg_mlme_set_enable_bcast_probe_rsp(hdd_ctx->psoc, enabled); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set enable bcast probe resp info, %d", + status); + + status = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_enable_bcast_probe_response, + !disable_fils, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set enable bcast probe resp, %d", + status); + + return qdf_status_to_os_return(status); +} + +static int hdd_set_primary_interface(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool is_set_primary_iface; + QDF_STATUS status; + uint8_t vdev_id, primary_vdev_id, dual_sta_policy; + int set_value; + uint32_t count; + bool enable_mcc_adaptive_sch = false; + + /* ignore unless in STA mode */ + if (adapter->device_mode != QDF_STA_MODE) + return 0; + + is_set_primary_iface = nla_get_u8(attr); + + vdev_id = link_info->vdev_id; + primary_vdev_id = + is_set_primary_iface ? vdev_id : WLAN_UMAC_VDEV_ID_MAX; + + status = ucfg_mlme_set_primary_interface(hdd_ctx->psoc, + primary_vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not set primary interface, %d", status); + return -EINVAL; + } + + /* After SSR, the dual sta configuration is lost. As SSR is hidden from + * userland, this command will not come from userspace after a SSR. To + * restore this configuration, save this in hdd context and restore + * after re-init. + */ + hdd_ctx->dual_sta_policy.primary_vdev_id = primary_vdev_id; + + count = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc, + PM_STA_MODE, NULL); + + if (count < 2) { + hdd_debug("STA + STA concurrency not present, count:%d", count); + return 0; + } + + /* If dual sta roaming enabled and sta concurrency on different mac then + * no need to enable roaming on primary as both STA's have roaming + * enabled. + * If dual sta roaming enabled and both sta in MCC or SCC then need + * to enable roaming on primary vdev. + * If dual sta roaming NOT enabled then need to enable roaming on + * primary vdev for sta concurrency on different mac. + */ + if (wlan_mlme_is_primary_interface_configured(hdd_ctx->psoc)) + if ((ucfg_mlme_get_dual_sta_roaming_enabled(hdd_ctx->psoc) && + !policy_mgr_concurrent_sta_on_different_mac(hdd_ctx->psoc)) || + !ucfg_mlme_get_dual_sta_roaming_enabled(hdd_ctx->psoc)) { + hdd_err("Enable roaming on requested interface: %d", + link_info->vdev_id); + hdd_debug("Enable roaming on requested interface: %d", + link_info->vdev_id); + wlan_cm_roam_state_change(hdd_ctx->pdev, + link_info->vdev_id, + WLAN_ROAM_RSO_ENABLED, + REASON_ROAM_SET_PRIMARY); + } + + /* + * send duty cycle percentage to FW only if STA + STA + * concurrency is in MCC. + */ + if (!policy_mgr_current_concurrency_is_mcc(hdd_ctx->psoc)) { + hdd_debug("STA + STA concurrency not in MCC"); + return 0; + } + + status = ucfg_mlme_get_dual_sta_policy(hdd_ctx->psoc, &dual_sta_policy); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get dual sta policy, %d", status); + return -EINVAL; + } + + hdd_debug("is_set_primary_iface: %d, primary vdev id: %d, dual_sta_policy:%d", + is_set_primary_iface, primary_vdev_id, dual_sta_policy); + + if (is_set_primary_iface && dual_sta_policy == + QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY) { + hdd_debug("Disable mcc_adaptive_scheduler"); + ucfg_policy_mgr_get_mcc_adaptive_sch(hdd_ctx->psoc, + &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch( + hdd_ctx->psoc, false); + if (QDF_IS_STATUS_ERROR(sme_set_mas(false))) { + hdd_err("Fail to disable mcc adaptive sched."); + return -EINVAL; + } + } + /* Configure mcc duty cycle percentage */ + set_value = + ucfg_mlme_get_mcc_duty_cycle_percentage(hdd_ctx->pdev); + if (set_value < 0) { + hdd_err("Invalid mcc duty cycle"); + return -EINVAL; + } + wlan_hdd_send_mcc_vdev_quota(adapter, set_value); + } else { + hdd_debug("Enable mcc_adaptive_scheduler"); + ucfg_policy_mgr_get_mcc_adaptive_sch(hdd_ctx->psoc, + &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch( + hdd_ctx->psoc, true); + if (QDF_STATUS_SUCCESS != sme_set_mas(true)) { + hdd_err("Fail to enable mcc_adaptive_sched."); + return -EAGAIN; + } + } + } + + return 0; +} + +static int hdd_config_rsn_ie(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint8_t force_rsne_override; + + force_rsne_override = nla_get_u8(attr); + if (force_rsne_override > 1) { + hdd_err("Invalid value %d", force_rsne_override); + return -EINVAL; + } + + hdd_ctx->force_rsne_override = force_rsne_override; + hdd_debug("force_rsne_override - %d", force_rsne_override); + + return 0; +} + +static int hdd_config_gtx(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t config_gtx; + int errno; + + config_gtx = nla_get_u8(attr); + if (config_gtx > 1) { + hdd_err_rl("Invalid config_gtx value %d", config_gtx); + return -EINVAL; + } + + errno = sme_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_enable, + config_gtx, VDEV_CMD); + if (errno) + hdd_err("Failed to set GTX, %d", errno); + + return errno; +} + +/** + * hdd_config_disconnect_ies() - Configure disconnect IEs + * @link_info: Link info pointer in HDD adapter + * @attr: array of pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_config_disconnect_ies(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + + hdd_debug("IE len %u session %u device mode %u", + nla_len(attr), link_info->vdev_id, + adapter->device_mode); + if (!nla_len(attr) || + nla_len(attr) > SIR_MAC_MAX_ADD_IE_LENGTH + 2 || + !wlan_is_ie_valid(nla_data(attr), nla_len(attr))) { + hdd_err("Invalid disconnect IEs"); + return -EINVAL; + } + + status = sme_set_disconnect_ies(hdd_ctx->mac_handle, + link_info->vdev_id, + nla_data(attr), + nla_len(attr)); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set disconnect_ies"); + + return qdf_status_to_os_return(status); +} + +#ifdef WLAN_FEATURE_ELNA +/** + * hdd_set_elna_bypass() - Set eLNA bypass + * @link_info: Link info pointer in HDD adapter + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_set_elna_bypass(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + int ret; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_FWOL_NB_ID); + if (!vdev) + return -EINVAL; + + ret = os_if_fwol_set_elna_bypass(vdev, attr); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_FWOL_NB_ID); + + return ret; +} +#endif + +/** + * hdd_mac_chwidth_to_bonding_mode() - get bonding_mode from chan width + * @chwidth: chan width + * + * Return: bonding mode + */ +static uint32_t hdd_mac_chwidth_to_bonding_mode( + enum eSirMacHTChannelWidth chwidth) +{ + uint32_t bonding_mode; + + switch (chwidth) { + case eHT_CHANNEL_WIDTH_20MHZ: + bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + break; + default: + bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + } + + return bonding_mode; +} + +int hdd_set_mac_chan_width(struct wlan_hdd_link_info *link_info, + enum eSirMacHTChannelWidth chwidth, + uint8_t link_id, bool is_restore) +{ + uint32_t bonding_mode; + + bonding_mode = hdd_mac_chwidth_to_bonding_mode(chwidth); + + return hdd_update_channel_width(link_info, chwidth, + bonding_mode, link_id, is_restore); +} + +/** + * hdd_set_channel_width() - set channel width + * @link_info: Link info pointer in HDD adapter. + * @tb: array of pointer to struct nlattr + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_channel_width(struct wlan_hdd_link_info *link_info, + struct nlattr *tb[]) +{ + int rem; + uint8_t nl80211_chwidth = CH_WIDTH_INVALID; + uint8_t link_id = WLAN_INVALID_LINK_ID; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + struct nlattr *curr_attr; + struct nlattr *chn_bd = NULL; + struct nlattr *mlo_link_id; + enum eSirMacHTChannelWidth chwidth; + struct wlan_objmgr_psoc *psoc; + bool update_cw_allowed; + + psoc = wlan_vdev_get_psoc(link_info->vdev); + if (!psoc) { + hdd_debug("psoc is null"); + return -EINVAL; + } + + ucfg_mlme_get_update_chan_width_allowed(psoc, &update_cw_allowed); + if (!update_cw_allowed) { + hdd_debug("update_channel_width is disabled via INI"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS]) + goto skip_mlo; + + nla_for_each_nested(curr_attr, + tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS], rem) { + if (wlan_cfg80211_nla_parse_nested(tb2, + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, + curr_attr, + bandwidth_mlo_policy)){ + hdd_err_rl("nla_parse failed"); + return -EINVAL; + } + + chn_bd = tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH]; + mlo_link_id = tb2[QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINK_ID]; + + if (!chn_bd || !mlo_link_id) + return -EINVAL; + + nl80211_chwidth = nla_get_u8(chn_bd); + chwidth = hdd_nl80211_chwidth_to_chwidth(nl80211_chwidth); + if (chwidth < eHT_CHANNEL_WIDTH_20MHZ || + chwidth >= eHT_MAX_CHANNEL_WIDTH) { + hdd_err("Invalid channel width:%u", chwidth); + return -EINVAL; + } + + link_id = nla_get_u8(mlo_link_id); + if (link_id > WLAN_MAX_LINK_ID) { + hdd_debug("invalid link_id:%u", link_id); + return -EINVAL; + } + } + + if (link_id != WLAN_INVALID_LINK_ID) + goto set_chan_width; + +skip_mlo: + chn_bd = tb[QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH]; + + if (!chn_bd) + return 0; + + nl80211_chwidth = nla_get_u8(chn_bd); + chwidth = hdd_nl80211_chwidth_to_chwidth(nl80211_chwidth); + + if (chwidth < eHT_CHANNEL_WIDTH_20MHZ || + chwidth >= eHT_MAX_CHANNEL_WIDTH) { + hdd_err("Invalid channel width %u", chwidth); + return -EINVAL; + } + +set_chan_width: + hdd_debug("channel width:%u, link_id:%u", chwidth, link_id); + return hdd_set_mac_chan_width(link_info, chwidth, link_id, true); +} + +/** + * hdd_set_dynamic_bw() - enable / disable dynamic bandwidth + * @link_info: Link info in adapter + * @attr: nla attr sent by supplicant + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_dynamic_bw(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t enable; + + enable = nla_get_u8(attr); + return wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_dynamic_bw, + enable, PDEV_CMD); +} + +/** + * hdd_set_nss() - set the number of spatial streams supported by the adapter + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_nss(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t nss; + int ret; + QDF_STATUS status; + + nss = nla_get_u8(attr); + status = hdd_update_nss(link_info, nss, nss); + ret = qdf_status_to_os_return(status); + + if (ret == 0 && link_info->adapter->device_mode == QDF_SAP_MODE) + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_nss, nss, VDEV_CMD); + + return ret; +} + +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD +#define DYNAMIC_ARP_NS_ENABLE 1 +#define DYNAMIC_ARP_NS_DISABLE 0 + +/** + * hdd_set_arp_ns_offload() - enable/disable arp/ns offload feature + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_arp_ns_offload(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t offload_state; + int errno; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_vdev *vdev; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (!ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc) || + !ucfg_pmo_is_ns_offloaded(hdd_ctx->psoc)) { + hdd_err_rl("ARP/NS Offload is disabled by ini"); + return -EINVAL; + } + + if (!ucfg_pmo_is_active_mode_offloaded(hdd_ctx->psoc)) { + hdd_err_rl("active mode offload is disabled by ini"); + return -EINVAL; + } + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_err_rl("only support on sta/p2p-cli mode"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + offload_state = nla_get_u8(attr); + + if (offload_state == DYNAMIC_ARP_NS_ENABLE) + qdf_status = ucfg_pmo_dynamic_arp_ns_offload_enable(vdev); + else if (offload_state == DYNAMIC_ARP_NS_DISABLE) + qdf_status = ucfg_pmo_dynamic_arp_ns_offload_disable(vdev); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (offload_state == DYNAMIC_ARP_NS_ENABLE) + ucfg_pmo_dynamic_arp_ns_offload_runtime_allow(vdev); + else + ucfg_pmo_dynamic_arp_ns_offload_runtime_prevent(vdev); + } + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + if (qdf_status == QDF_STATUS_E_ALREADY) { + hdd_info_rl("already set arp/ns offload %d", + offload_state); + errno = qdf_status_to_os_return(QDF_STATUS_SUCCESS); + } else { + errno = qdf_status_to_os_return(qdf_status); + } + + goto vdev_ref; + } + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_info("set not in connect state, updated state %d", + offload_state); + errno = qdf_status_to_os_return(QDF_STATUS_SUCCESS); + goto vdev_ref; + } + + if (offload_state == DYNAMIC_ARP_NS_ENABLE) { + hdd_enable_arp_offload(adapter, vdev, + pmo_arp_ns_offload_dynamic_update); + hdd_enable_ns_offload(adapter, vdev, + pmo_arp_ns_offload_dynamic_update); + } else if (offload_state == DYNAMIC_ARP_NS_DISABLE) { + hdd_disable_arp_offload(adapter, vdev, + pmo_arp_ns_offload_dynamic_update); + hdd_disable_ns_offload(adapter, vdev, + pmo_arp_ns_offload_dynamic_update); + } + +vdev_ref: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return errno; +} + +#undef DYNAMIC_ARP_NS_ENABLE +#undef DYNAMIC_ARP_NS_DISABLE +#endif + +#ifdef WLAN_FEATURE_DBAM_CONFIG + +static int +hdd_convert_qca_dbam_config_mode(enum qca_dbam_config qca_dbam, + enum coex_dbam_config_mode *coex_dbam) +{ + switch (qca_dbam) { + case QCA_DBAM_DISABLE: + *coex_dbam = COEX_DBAM_DISABLE; + break; + case QCA_DBAM_ENABLE: + *coex_dbam = COEX_DBAM_ENABLE; + break; + case QCA_DBAM_FORCE_ENABLE: + *coex_dbam = COEX_DBAM_FORCE_ENABLE; + break; + default: + hdd_err("Invalid dbam config mode %d", qca_dbam); + return -EINVAL; + } + + return 0; +} + +static int +hdd_convert_dbam_comp_status(enum coex_dbam_comp_status dbam_resp) +{ + switch (dbam_resp) { + case COEX_DBAM_COMP_SUCCESS: + return 0; + case COEX_DBAM_COMP_NOT_SUPPORT: + return -ENOTSUPP; + case COEX_DBAM_COMP_FAIL: + return -EINVAL; + default: + hdd_err("Invalid dbam config resp received from FW"); + break; + } + + return -EINVAL; +} + +/** + * hdd_dbam_config_resp_cb() - DBAM config response callback + * @context: request manager context + * @resp: pointer to dbam config fw response + * + * Return: 0 on success, negative errno on failure + */ +static void +hdd_dbam_config_resp_cb(void *context, + enum coex_dbam_comp_status *resp) +{ + struct osif_request *request; + struct coex_dbam_config_resp *priv; + + request = osif_request_get(context); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->dbam_resp = *resp; + + osif_request_complete(request); + osif_request_put(request); +} + +int hdd_send_dbam_config(struct hdd_adapter *adapter, + enum coex_dbam_config_mode dbam_mode) +{ + int errno; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + enum coex_dbam_comp_status dbam_resp; + struct coex_dbam_config_params dbam_params = {0}; + void *cookie; + struct osif_request *request; + struct coex_dbam_config_resp *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_SET_DBAM_CONFIG_TIMEOUT, + }; + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + dbam_params.vdev_id = adapter->deflink->vdev_id; + dbam_params.dbam_mode = dbam_mode; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + errno = -EINVAL; + goto err; + } + + status = ucfg_coex_send_dbam_config(vdev, &dbam_params, + hdd_dbam_config_resp_cb, cookie); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to set dbam config to [%u]", dbam_mode); + errno = qdf_status_to_os_return(status); + goto err; + } + + errno = osif_request_wait_for_response(request); + if (errno) { + osif_err("DBAM config operation timed out"); + goto err; + } + + priv = osif_request_priv(request); + dbam_resp = priv->dbam_resp; + errno = hdd_convert_dbam_comp_status(dbam_resp); +err: + osif_request_put(request); + return errno; +} + +/** + * hdd_set_dbam_config() - set DBAM config + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_set_dbam_config(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int errno; + enum qca_dbam_config dbam_config; + enum coex_dbam_config_mode dbam_mode; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + if (hdd_ctx->num_rf_chains < 2) { + hdd_debug("Num of chains [%u] < 2, DBAM config is not allowed", + hdd_ctx->num_rf_chains); + return -EINVAL; + } + + dbam_config = nla_get_u8(attr); + errno = hdd_convert_qca_dbam_config_mode(dbam_config, &dbam_mode); + if (errno) + return errno; + + /* Store dbam config in hdd_ctx, to restore in case of an SSR */ + adapter->is_dbam_configured = true; + hdd_ctx->dbam_mode = dbam_mode; + + return hdd_send_dbam_config(adapter, dbam_mode); +} +#endif + +/** + * hdd_set_beamformer_periodic_sounding() - enable/disable Tx Beamforming + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int +hdd_set_beamformer_periodic_sounding(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + int set_val; + + cfg_val = nla_get_u8(attr); + + set_val = cfg_val ? TX_BFER_NDP_PERIODICITY : 0; + return wma_cli_set_command(link_info->vdev_id, + WMI_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + set_val, PDEV_CMD); +} + +/** + * hdd_set_wfc_state() - Set wfc state + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int hdd_set_wfc_state(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + enum pld_wfc_mode set_val; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + cfg_val = nla_get_u8(attr); + + hdd_debug_rl("set wfc state %d", cfg_val); + if (cfg_val == 0) + set_val = PLD_WFC_MODE_OFF; + else if (cfg_val == 1) + set_val = PLD_WFC_MODE_ON; + else + return -EINVAL; + + return pld_set_wfc_mode(hdd_ctx->parent_dev, set_val); + +} + +/** + * hdd_set_ul_mu_config() - Configure UL MU i.e suspend/enable + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ + +static int hdd_set_ul_mu_config(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t ulmu; + uint8_t ulmu_disable; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + int errno; + QDF_STATUS qdf_status; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) { + hdd_err("Invalid HDD ctx, errno : %d", errno); + return errno; + } + + ulmu = nla_get_u8(attr); + if (ulmu != QCA_UL_MU_SUSPEND && ulmu != QCA_UL_MU_ENABLE) { + hdd_err("Invalid ulmu value, ulmu : %d", ulmu); + return -EINVAL; + } + + hdd_debug("UL MU value : %d", ulmu); + + if (ulmu == QCA_UL_MU_SUSPEND) + ulmu_disable = 1; + else + ulmu_disable = 0; + + qdf_status = ucfg_mlme_set_ul_mu_config(hdd_ctx->psoc, + link_info->vdev_id, + ulmu_disable); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + errno = -EINVAL; + hdd_err("Failed to set UL MU, errno : %d", errno); + } + + return errno; +} + +/** + * hdd_set_coex_traffic_shaping_mode() - Configure coex traffic + * shaping mode + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ + +static int +hdd_set_coex_traffic_shaping_mode(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t mode; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + int errno, ret; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) { + hdd_err("Invalid HDD ctx, errno : %d", errno); + return errno; + } + + mode = nla_get_u8(attr); + if (mode > QCA_COEX_TRAFFIC_SHAPING_MODE_ENABLE) { + hdd_err("Invalid traffic shaping mode : %d", mode); + return -EINVAL; + } + + hdd_debug("Coex Traffic shaping mode : %d", mode); + + ret = hdd_send_coex_traffic_shaping_mode(link_info->vdev_id, mode); + + return ret; +} + +#define STA_KEEPALIVE_INTERVAL_MAX 255 +#define STA_KEEPALIVE_INTERVAL_MIN 5 + +int hdd_vdev_send_sta_keep_alive_interval( + struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint16_t keep_alive_interval) +{ + struct keep_alive_req request; + + qdf_mem_zero(&request, sizeof(request)); + + request.timePeriod = keep_alive_interval; + request.packetType = WLAN_KEEP_ALIVE_NULL_PKT; + + if (QDF_STATUS_SUCCESS != + sme_set_keep_alive(hdd_ctx->mac_handle, link_info->vdev_id, + &request)) { + hdd_err("Failure to execute Keep Alive"); + return -EINVAL; + } + + return 0; +} + +void wlan_hdd_save_sta_keep_alive_interval(struct hdd_adapter *adapter, + uint16_t keep_alive_interval) +{ + adapter->keep_alive_interval = keep_alive_interval; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * hdd_ml_vdev_set_sta_keep_alive_interval() - Set STA KEEPALIVE interval for + * all connected ml vdev + * @vdev: Pointer to vdev + * @hdd_ctx: Pointer to hdd context + * @keep_alive_interval: KEEPALIVE interval + * + * Return: 0 on success, negative on failure + */ +static int hdd_ml_vdev_set_sta_keep_alive_interval( + struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + uint16_t keep_alive_interval) +{ + struct wlan_objmgr_vdev *ml_vdev; + uint8_t ml_vdev_id; + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_hdd_link_info *link_info; + int status, i; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + hdd_err("MLO dev context null"); + return -EINVAL; + } + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS ; i++) { + ml_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!ml_vdev) + continue; + + ml_vdev_id = ml_vdev->vdev_objmgr.vdev_id; + link_info = hdd_get_link_info_by_vdev(hdd_ctx, ml_vdev_id); + if (!link_info) + continue; + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_debug("Vdev (id %d) not in connected/started state", + link_info->vdev_id); + continue; + } + + status = hdd_vdev_send_sta_keep_alive_interval(link_info, + hdd_ctx, + keep_alive_interval); + if (status) + return status; + } + + return 0; +} +#else +static inline int hdd_ml_vdev_set_sta_keep_alive_interval( + struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + uint16_t keep_alive_interval) +{ + return -EINVAL; +} +#endif +/** + * hdd_vdev_set_sta_keep_alive_interval() - Set sta keep alive interval + * @link_info: Link info pointer. + * @attr: NL attribute pointer. + * + * Return: 0 on success, negative on failure. + */ +static int hdd_vdev_set_sta_keep_alive_interval( + struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum QDF_OPMODE device_mode = link_info->adapter->device_mode; + uint16_t keep_alive_interval; + struct wlan_objmgr_vdev *vdev = link_info->vdev; + + keep_alive_interval = nla_get_u16(attr); + if (keep_alive_interval > STA_KEEPALIVE_INTERVAL_MAX || + keep_alive_interval < STA_KEEPALIVE_INTERVAL_MIN) { + hdd_err("Sta keep alive period: %d is out of range", + keep_alive_interval); + return -EINVAL; + } + + if (device_mode != QDF_STA_MODE) { + hdd_debug("This command is not supported for %s device mode", + device_mode_to_string(device_mode)); + return -EINVAL; + } + + hdd_debug("sta keep alive interval = %u", keep_alive_interval); + wlan_hdd_save_sta_keep_alive_interval(adapter, keep_alive_interval); + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_debug("Vdev (id %d) not in connected/started state, configure KEEPALIVE interval after connection", + link_info->vdev_id); + return 0; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return hdd_vdev_send_sta_keep_alive_interval(link_info, + hdd_ctx, + keep_alive_interval); + + return hdd_ml_vdev_set_sta_keep_alive_interval(vdev, hdd_ctx, + keep_alive_interval); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static int hdd_test_config_emlsr_mode(struct hdd_context *hdd_ctx, + bool cfg_val) + +{ + hdd_debug("11be op mode setting %d", cfg_val); + if (cfg_val && policy_mgr_is_hw_emlsr_capable(hdd_ctx->psoc)) { + hdd_debug("HW supports EMLSR mode, set caps"); + ucfg_mlme_set_emlsr_mode_enabled(hdd_ctx->psoc, cfg_val); + } else { + hdd_debug("Default mode: MLMR, no action required"); + } + + return 0; +} + +static int +hdd_test_config_emlsr_action_mode(struct hdd_adapter *adapter, + enum wlan_emlsr_action_mode emlsr_mode) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t i, num_links = 0; + uint16_t vdev_count = 0; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; + struct qdf_mac_addr active_link_addr[2]; + + mlo_sta_get_vdev_list(adapter->deflink->vdev, &vdev_count, + wlan_vdev_list); + for (i = 0; i < vdev_count; i++) { + if (!wlan_vdev_list[i]) + continue; + qdf_mem_copy(&active_link_addr[i], + wlan_vdev_mlme_get_macaddr(wlan_vdev_list[i]), + QDF_MAC_ADDR_SIZE); + num_links++; + if (emlsr_mode == WLAN_EMLSR_MODE_EXIT) + break; + } + + for (i = 0; i < vdev_count; i++) + mlo_release_vdev_ref(wlan_vdev_list[i]); + + hdd_debug("number of links to force enable: %d", num_links); + + if (num_links >= 1) + sme_activate_mlo_links(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + num_links, active_link_addr); + + return 0; +} + +/** + * hdd_set_epcs_capability() - Set EPCS capability enable or not + * @link_info: link info pointer + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int hdd_set_epcs_capability(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + cfg_val = nla_get_u8(attr); + hdd_debug("Configure EPCS capability %s(%d)", + cfg_val ? "Enable" : "Disable", cfg_val); + if (cfg_val < WLAN_EPCS_CAP_DISABLED || + cfg_val > WLAN_EPCS_CAP_ENABLE) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return -EINVAL; + } + + ucfg_epcs_set_config(vdev, cfg_val); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return 0; +} + +/** + * hdd_trigger_epcs_function() - Trigger EPCS function to enable or disable + * @link_info: link info pointer + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int hdd_trigger_epcs_function(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct wlan_objmgr_vdev *vdev; + enum wlan_epcs_evt event; + int status = -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return status; + + cfg_val = nla_get_u8(attr); + hdd_debug("Trigger EPCS %d", cfg_val); + + switch (cfg_val) { + /* enable EPCS function to send request frame */ + case WLAN_EPCS_FRAME_REQUEST: + event = WLAN_EPCS_EV_ACTION_FRAME_TX_REQ; + break; + /* disable EPCS function to send teardown frame */ + case WLAN_EPCS_FRAME_TEARDOWN: + event = WLAN_EPCS_EV_ACTION_FRAME_TX_TEARDOWN; + break; + default: + goto rel_ref; + } + + ucfg_epcs_deliver_cmd(vdev, event); + status = 0; + +rel_ref: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return status; +} +#else +static inline int +hdd_test_config_emlsr_mode(struct hdd_context *hdd_ctx, bool cfg_val) +{ + return 0; +} + +static inline int +hdd_test_config_emlsr_action_mode(struct hdd_adapter *adapter, + enum wlan_emlsr_action_mode emlsr_mode) +{ + return 0; +} +#endif + +/** + * hdd_set_btm_support_config() - Update BTM support policy + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int hdd_set_btm_support_config(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum QDF_OPMODE op_mode = adapter->device_mode; + bool is_vdev_in_conn_state, is_disable_btm; + + is_vdev_in_conn_state = hdd_is_vdev_in_conn_state(link_info); + cfg_val = nla_get_u8(attr); + + hdd_debug("vdev: %d, cfg_val: %d for op_mode: %d, conn_state:%d", + link_info->vdev_id, cfg_val, op_mode, + is_vdev_in_conn_state); + + /* + * Change in BTM support configuration is applicable only for STA + * interface and not allowed in connected state. + */ + if (op_mode != QDF_STA_MODE || is_vdev_in_conn_state) + return -EINVAL; + + switch (cfg_val) { + case QCA_WLAN_BTM_SUPPORT_DISABLE: + is_disable_btm = true; + break; + case QCA_WLAN_BTM_SUPPORT_DEFAULT: + is_disable_btm = false; + break; + default: + return -EINVAL; + } + + ucfg_cm_set_btm_config(hdd_ctx->psoc, link_info->vdev_id, + is_disable_btm); + + return 0; +} + +#ifdef WLAN_FEATURE_11BE +/** + * hdd_set_eht_emlsr_capability() - Set EMLSR capability for EHT STA + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int +hdd_set_eht_emlsr_capability(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + cfg_val = nla_get_u8(attr); + hdd_debug("EMLSR capable: %d", cfg_val); + hdd_test_config_emlsr_mode(hdd_ctx, cfg_val); + + return 0; +} + +/** + * hdd_set_eht_max_simultaneous_links() - Set EHT maximum number of + * simultaneous links + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int +hdd_set_eht_max_simultaneous_links(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + cfg_val = nla_get_u8(attr); + if (cfg_val > MAX_SIMULTANEOUS_STA_ML_LINKS) + return -EINVAL; + + sme_set_mlo_max_simultaneous_links(hdd_ctx->mac_handle, + link_info->vdev_id, cfg_val); + + return 0; +} + +/** + * hdd_set_eht_max_num_links() - Set EHT maximum number of links + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int hdd_set_eht_max_num_links(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + cfg_val = nla_get_u8(attr); + if (cfg_val > MAX_NUM_STA_ML_LINKS) + return -EINVAL; + + sme_set_mlo_max_links(hdd_ctx->mac_handle, + link_info->vdev_id, cfg_val); + + return 0; +} + +/** + * hdd_get_cfg_eht_mode() - Convert qca wlan EHT mode enum to cfg wlan EHT mode + * @qca_wlan_eht_mode: qca wlan eht mode + * + * Return: EHT mode on success, 0 on failure + */ +static enum wlan_eht_mode +hdd_get_cfg_eht_mode(enum qca_wlan_eht_mlo_mode qca_wlan_eht_mode) +{ + switch (qca_wlan_eht_mode) { + case QCA_WLAN_EHT_MLSR: + return WLAN_EHT_MODE_MLSR; + case QCA_WLAN_EHT_EMLSR: + return WLAN_EHT_MODE_EMLSR; + case QCA_WLAN_EHT_NON_STR_MLMR: + case QCA_WLAN_EHT_STR_MLMR: + return WLAN_EHT_MODE_MLMR; + default: + hdd_debug("Invalid EHT mode"); + return WLAN_EHT_MODE_DISABLED; + } +} + +/** + * hdd_set_eht_mlo_mode() - Set EHT MLO mode of operation + * @link_info: Link info pointer in HDD adapter + * @attr: pointer to nla attr + * + * Return: 0 on success, negative on failure + */ +static int hdd_set_eht_mlo_mode(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum wlan_eht_mode eht_mode; + + cfg_val = nla_get_u8(attr); + hdd_debug("Configure EHT mode of operation: %d", cfg_val); + + eht_mode = hdd_get_cfg_eht_mode(cfg_val); + + if (eht_mode == WLAN_EHT_MODE_EMLSR && + adapter->device_mode == QDF_STA_MODE) { + hdd_test_config_emlsr_mode(hdd_ctx, true); + ucfg_mlme_set_bss_color_collision_det_sta(hdd_ctx->psoc, false); + } + + ucfg_mlme_set_eht_mode(hdd_ctx->psoc, eht_mode); + + return 0; +} +#else +static inline int +hdd_set_eht_emlsr_capability(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline int +hdd_set_eht_max_simultaneous_links(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline int +hdd_set_eht_max_num_links(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline int +hdd_set_eht_mlo_mode(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static int hdd_set_link_force_active(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = NULL; + struct nlattr *curr_attr; + struct qdf_mac_addr active_link_addr[2]; + struct qdf_mac_addr *mac_addr_ptr; + uint32_t num_links = 0; + int32_t len; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return -EINVAL; + + if (attr && adapter->device_mode == QDF_STA_MODE) { + nla_for_each_nested(curr_attr, &attr[0], len) { + mac_addr_ptr = &active_link_addr[num_links]; + qdf_mem_copy(mac_addr_ptr, nla_data(curr_attr), + ETH_ALEN); + hdd_debug(QDF_MAC_ADDR_FMT " is link[%d] mac address", + QDF_MAC_ADDR_REF(mac_addr_ptr->bytes), + num_links); + num_links++; + } + sme_activate_mlo_links(hdd_ctx->mac_handle, + link_info->vdev_id, num_links, + active_link_addr); + } + hdd_debug("number of links to force active: %d", num_links); + + return 0; +} + +/** + * hdd_get_cfg_emlsr_mode() - Convert qca wlan EMLSR mode enum to cfg wlan + * EMLSR action mode + * @qca_wlan_emlsr_mode: qca wlan EMLSR mode + * + * Return: EMLSR mode on success, 0 on failure + */ +static enum wlan_emlsr_action_mode +hdd_get_cfg_emlsr_mode(enum qca_wlan_eht_mlo_mode qca_wlan_emlsr_mode) +{ + switch (qca_wlan_emlsr_mode) { + case QCA_WLAN_EMLSR_MODE_ENTER: + return WLAN_EMLSR_MODE_ENTER; + case QCA_WLAN_EMLSR_MODE_EXIT: + return WLAN_EMLSR_MODE_EXIT; + default: + hdd_debug("Invalid EMLSR action mode"); + return WLAN_EMLSR_MODE_DISABLED; + } +} + +/** + * hdd_get_cfg_t2lm_neg_support_type() - Convert qca wlan TID-to-link mapping + * enum to cfg wlan + * + * @qca_wlan_t2lm_support: qca wlan TID-to-link mapping + * + * Return: TID-to-link mapping support on success, 0 on failure + */ +static enum wlan_t2lm_negotiation_support +hdd_get_cfg_t2lm_neg_support_type(enum qca_wlan_ttlm_negotiation_support + qca_wlan_t2lm_support) +{ + switch (qca_wlan_t2lm_support) { + case QCA_WLAN_TTLM_DISABLE: + return WLAN_T2LM_DISABLE; + case QCA_WLAN_TTLM_SAME_LINK_SET: + return WLAN_T2LM_SAME_LINK_SET; + case QCA_WLAN_TTLM_SAME_DIFF_LINK_SET: + return WLAN_T2LM_SAME_DIFF_LINK_SET; + default: + hdd_debug("Invalid T2LM negotiation support"); + return WLAN_T2LM_DISABLE; + } +} + +static int hdd_set_emlsr_mode(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + uint8_t cfg_val; + enum wlan_emlsr_action_mode emlsr_action_mode; + + if (!attr) + return -EINVAL; + + cfg_val = nla_get_u8(attr); + + emlsr_action_mode = hdd_get_cfg_emlsr_mode(cfg_val); + + hdd_debug("EMLSR mode: %s", emlsr_action_mode == WLAN_EMLSR_MODE_ENTER ? + "Enter" : "Exit"); + + hdd_test_config_emlsr_action_mode(link_info->adapter, + emlsr_action_mode); + + return 0; +} + +static int hdd_set_t2lm_negotiation_support(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = NULL; + uint8_t cfg_val; + enum wlan_t2lm_negotiation_support t2lm_support; + + if (!attr) + return -EINVAL; + + cfg_val = nla_get_u8(attr); + + t2lm_support = hdd_get_cfg_t2lm_neg_support_type(cfg_val); + hdd_debug("T2LM negotiation support: %d", t2lm_support); + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + wlan_mlme_set_t2lm_negotiation_supported(hdd_ctx->psoc, + t2lm_support); + + return 0; +} +#else +static inline int +hdd_set_link_force_active(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline +int hdd_set_emlsr_mode(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline +int hdd_set_t2lm_negotiation_support(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline int +hdd_set_epcs_capability(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} + +static inline int +hdd_trigger_epcs_function(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + return 0; +} +#endif + +/** + * hdd_set_master_channel_list() - set master channel list from set wifi + * attribute + * @link_info: hdd link info + * @attr: Pointer to struct nlattr + * + * Return: 0 on success, else error number + */ +static int +hdd_set_master_channel_list(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr) +{ + struct sap_config *sap_config; + qdf_freq_t freq; + uint16_t count = 0; + qdf_freq_t *freq_list; + struct nlattr *nested_attr; + int tmp, ret = 0; + + if (link_info->adapter->device_mode != QDF_SAP_MODE) { + hdd_debug("command not received for sap"); + return -EINVAL; + } + freq_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(qdf_freq_t)); + if (!freq_list) + return -ENOMEM; + + sap_config = &link_info->adapter->deflink->session.ap.sap_config; + + nla_for_each_nested(nested_attr, attr, tmp) { + freq = nla_get_u32(nested_attr); + if (!freq) { + hdd_err("invalid freq"); + ret = -EINVAL; + goto out; + } + freq_list[count] = freq; + count++; + if (count >= NUM_CHANNELS) + break; + } + if (!count) { + hdd_err("no valid freq found"); + ret = -EINVAL; + goto out; + } + ret = wlansap_update_sap_chan_list(sap_config, freq_list, count); + if (ret) + hdd_err("sap chan list update failure"); +out: + qdf_mem_free(freq_list); + + return ret; +} + +/** + * typedef independent_setter_fn - independent attribute handler + * @link_info: Link info pointer in HDD adapter + * @attr: The nl80211 attribute being applied + * + * Defines the signature of functions in the independent attribute vtable + * + * Return: 0 if the attribute was handled successfully, otherwise an errno + */ +typedef int (*independent_setter_fn)(struct wlan_hdd_link_info *link_info, + const struct nlattr *attr); + +/** + * struct independent_setters + * @id: vendor attribute which this entry handles + * @cb: callback function to invoke to process the attribute when present + */ +struct independent_setters { + uint32_t id; + independent_setter_fn cb; +}; + +/* vtable for independent setters */ +static const struct independent_setters independent_setters[] = { + {QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_DEFAULT_IES, + hdd_config_scan_default_ies}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_FINE_TIME_MEASUREMENT, + hdd_config_fine_time_measurement}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM, + hdd_config_dynamic_dtim}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL, + hdd_config_listen_interval}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_LRO, + hdd_config_lro}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_SCAN_ENABLE, + hdd_config_scan_enable}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR, + hdd_config_stats_avg_factor}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME, + hdd_config_guard_time}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_NON_AGG_RETRY, + hdd_config_non_agg_retry}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_AGG_RETRY, + hdd_config_agg_retry}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_MGMT_RETRY, + hdd_config_mgmt_retry}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_CTRL_RETRY, + hdd_config_ctrl_retry}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_DELAY, + hdd_config_propagation_delay}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_PROPAGATION_ABS_DELAY, + hdd_config_propagation_abs_delay}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TX_FAIL_COUNT, + hdd_config_tx_fail_count}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_AVOIDANCE_IND, + hdd_config_channel_avoidance_ind}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_ENA, + hdd_config_ant_div_ena}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SNR_DIFF, + hdd_config_ant_div_snr_diff}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_PROBE_DWELL_TIME, + hdd_config_ant_div_probe_dwell_time}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_CHAIN, + hdd_config_ant_div_chain}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST, + hdd_config_ant_div_selftest}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_ANT_DIV_SELFTEST_INTVL, + hdd_config_ant_div_selftest_intvl}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_IGNORE_ASSOC_DISALLOWED, + hdd_config_ignore_assoc_disallowed}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RESTRICT_OFFCHANNEL, + hdd_config_restrict_offchannel}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TOTAL_BEACON_MISS_COUNT, + hdd_config_total_beacon_miss_count}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL, + hdd_config_latency_level}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_DISABLE_FILS, + hdd_config_disable_fils}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RSN_IE, + hdd_config_rsn_ie}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_GTX, + hdd_config_gtx}, + {QCA_WLAN_VENDOR_ATTR_DISCONNECT_IES, + hdd_config_disconnect_ies}, +#ifdef WLAN_FEATURE_ELNA + {QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS, + hdd_set_elna_bypass}, +#endif + {QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON, + hdd_set_roam_reason_vsie_status}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC, + hdd_config_ldpc}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC, + hdd_config_tx_stbc}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC, + hdd_config_rx_stbc}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW, + hdd_set_dynamic_bw}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_NSS, + hdd_set_nss}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE, + hdd_config_udp_qos_upgrade_threshold}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_CONCURRENT_STA_PRIMARY, + hdd_set_primary_interface}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_FT_OVER_DS, + hdd_set_ft_over_ds}, +#ifdef FEATURE_WLAN_DYNAMIC_ARP_NS_OFFLOAD + {QCA_WLAN_VENDOR_ATTR_CONFIG_ARP_NS_OFFLOAD, + hdd_set_arp_ns_offload}, +#endif +#ifdef WLAN_FEATURE_DBAM_CONFIG + {QCA_WLAN_VENDOR_ATTR_CONFIG_DBAM, + hdd_set_dbam_config}, +#endif + {QCA_WLAN_VENDOR_ATTR_CONFIG_UDP_QOS_UPGRADE_FOR_BE_BK, + hdd_config_udp_qos_upgrade_be_bk}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_BEAMFORMER_PERIODIC_SOUNDING, + hdd_set_beamformer_periodic_sounding}, + + {QCA_WLAN_VENDOR_ATTR_CONFIG_WFC_STATE, + hdd_set_wfc_state}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_EML_CAPABILITY, + hdd_set_eht_emlsr_capability}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_SIMULTANEOUS_LINKS, + hdd_set_eht_max_simultaneous_links}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_CAPABILITY, + hdd_set_epcs_capability}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EPCS_FUNCTION, + hdd_trigger_epcs_function}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MAX_NUM_LINKS, + hdd_set_eht_max_num_links}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_MODE, + hdd_set_eht_mlo_mode}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EHT_MLO_ACTIVE_LINKS, + hdd_set_link_force_active}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_EMLSR_MODE_SWITCH, + hdd_set_emlsr_mode}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_UL_MU_CONFIG, + hdd_set_ul_mu_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST, + hdd_set_master_channel_list}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TTLM_NEGOTIATION_SUPPORT, + hdd_set_t2lm_negotiation_support}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_COEX_TRAFFIC_SHAPING_MODE, + hdd_set_coex_traffic_shaping_mode}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_BTM_SUPPORT, + hdd_set_btm_support_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL, + hdd_vdev_set_sta_keep_alive_interval}, +}; + +#ifdef WLAN_FEATURE_ELNA +/** + * hdd_get_elna_bypass() - Get eLNA bypass + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_elna_bypass(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + int ret; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_FWOL_NB_ID); + if (!vdev) + return -EINVAL; + + ret = os_if_fwol_get_elna_bypass(vdev, skb, attr); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_FWOL_NB_ID); + + return ret; +} +#endif + +/** + * hdd_get_roam_reason_vsie_status() - Get roam_reason_vsie + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static int hdd_get_roam_reason_vsie_status(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + uint8_t roam_reason_vsie_enabled; + struct hdd_context *hdd_ctx = NULL; + QDF_STATUS status; + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + status = ucfg_mlme_get_roam_reason_vsie_status + (hdd_ctx->psoc, + &roam_reason_vsie_enabled); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get roam reason vsie failed"); + return -EINVAL; + } + hdd_debug("is roam_reason_vsie_enabled %d", roam_reason_vsie_enabled); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON, + roam_reason_vsie_enabled)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} +#else +static inline int +hdd_get_roam_reason_vsie_status(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + return -EINVAL; +} +#endif + +static int hdd_vendor_attr_ldpc_get(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + int ldpc, ret; + + ret = hdd_get_ldpc(link_info->adapter, &ldpc); + if (ret) { + hdd_err("get ldpc failed"); + return -EINVAL; + } + + hdd_debug("ldpc %u", ldpc); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC, + (uint8_t)ldpc)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +static int hdd_vendor_attr_tx_stbc_get(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + int tx_stbc; + int ret; + + ret = hdd_get_tx_stbc(link_info->adapter, &tx_stbc); + if (ret) { + hdd_err("get tx_stbc failed"); + return -EINVAL; + } + + hdd_debug("tx_stbc %u", tx_stbc); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC, + (uint8_t)tx_stbc)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +static int hdd_vendor_attr_rx_stbc_get(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + int rx_stbc; + int ret; + + ret = hdd_get_rx_stbc(link_info->adapter, &rx_stbc); + if (ret) { + hdd_err("get rx_stbc failed"); + return -EINVAL; + } + + hdd_debug("rx_stbc %u", rx_stbc); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC, + (uint8_t)rx_stbc)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_tx_ampdu() - Get TX AMPDU + * @link_info: Link info in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_tx_ampdu(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + int value; + + value = wma_cli_get_command(link_info->vdev_id, + GEN_VDEV_PARAM_TX_AMPDU, GEN_CMD); + if (value < 0) { + hdd_err("Failed to get tx_ampdu"); + return -EINVAL; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION, + (uint8_t)value)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_rx_ampdu() - Get RX AMPDU + * @link_info: Link info in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_rx_ampdu(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + int value; + + value = wma_cli_get_command(link_info->vdev_id, + GEN_VDEV_PARAM_RX_AMPDU, GEN_CMD); + if (value < 0) { + hdd_err("Failed to get rx_ampdu"); + return -EINVAL; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION, + (uint8_t)value)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_tx_amsdu() - Get TX AMSDU + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_tx_amsdu(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + int value; + + value = wma_cli_get_command(link_info->vdev_id, + GEN_VDEV_PARAM_TX_AMSDU, GEN_CMD); + if (value < 0) { + hdd_err("Failed to get tx_amsdu"); + return -EINVAL; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION, + (uint8_t)value)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_rx_amsdu() - Get RX AMSDU + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_rx_amsdu(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + int value; + + value = wma_cli_get_command(link_info->vdev_id, + GEN_VDEV_PARAM_RX_AMSDU, GEN_CMD); + if (value < 0) { + hdd_err("Failed to get rx_amsdu"); + return -EINVAL; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION, + (uint8_t)value)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_channel_width() - Get channel width + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_channel_width(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + uint8_t nl80211_chwidth; + struct wlan_channel *bss_chan; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + bss_chan = wlan_vdev_mlme_get_bss_chan(vdev); + if (!bss_chan) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_err("get bss_chan failed"); + return QDF_STATUS_E_FAILURE; + } + + nl80211_chwidth = hdd_phy_chwidth_to_nl80211_chwidth(bss_chan->ch_width); + if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH, nl80211_chwidth)) { + hdd_err("nla_put chn width failure"); + return -EINVAL; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return 0; +} + +/** + * hdd_get_mlo_max_band_info() - Get channel width + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +#ifdef WLAN_FEATURE_11BE_MLO +static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + enum eSirMacHTChannelWidth chwidth; + struct nlattr *mlo_bd = NULL; + struct nlattr *mlo_bd_info = NULL; + uint32_t i = 0; + uint32_t link_id = 0; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *link_vdev = NULL; + struct wlan_channel *bss_chan; + struct wlan_hdd_link_info *link_info_t; + struct hdd_station_ctx *sta_ctx; + uint8_t nl80211_chwidth; + uint8_t chn_width; + int8_t ret = 0; + + chwidth = wma_cli_get_command(link_info->vdev_id, + wmi_vdev_param_chwidth, VDEV_CMD); + if (chwidth < 0) { + hdd_err("Failed to get chwidth %u", chwidth); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_err("not mlo vdev"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return -EINVAL; + } + + mlo_bd_info = nla_nest_start(skb, CONFIG_MLO_LINKS); + hdd_adapter_for_each_link_info(link_info->adapter, link_info_t) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info_t); + if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID) + continue; + + link_id = sta_ctx->conn_info.ieee_link_id; + + mlo_bd = nla_nest_start(skb, i); + if (!mlo_bd) { + hdd_err("nla_nest_start fail"); + ret = -EINVAL; + goto end; + } + + if (nla_put_u8(skb, CONFIG_MLO_LINK_ID, link_id)) { + hdd_err("nla_put failure"); + ret = -EINVAL; + goto end; + } + + link_vdev = mlo_get_vdev_by_link_id(vdev, link_id, + WLAN_OSIF_ID); + + if (link_vdev) { + bss_chan = wlan_vdev_mlme_get_bss_chan(link_vdev); + if (!bss_chan) { + hdd_err("fail to get bss_chan info"); + ret = -EINVAL; + goto end; + } + chn_width = bss_chan->ch_width; + } else if (link_info_t->vdev_id == WLAN_INVALID_VDEV_ID) { + chn_width = sta_ctx->user_cfg_chn_width; + } else { + chn_width = CH_WIDTH_INVALID; + } + + hdd_debug("get link_id:%u ch width:%u", link_id, chn_width); + + nl80211_chwidth = hdd_phy_chwidth_to_nl80211_chwidth(chn_width); + if (nla_put_u8(skb, CONFIG_CHANNEL_WIDTH, nl80211_chwidth)) { + hdd_err("nla_put failure"); + ret = -EINVAL; + goto end; + } + nla_nest_end(skb, mlo_bd); + i++; + + if (link_vdev) + hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID); + } + nla_nest_end(skb, mlo_bd_info); +end: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (link_vdev) + hdd_objmgr_put_vdev_by_user(link_vdev, WLAN_OSIF_ID); + + return ret; +} +#else +static int hdd_get_mlo_max_band_info(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + return 0; +} +#endif + +/** + * hdd_get_dynamic_bw() - Get dynamic bandwidth disabled / enabled + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_dynamic_bw(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + int enable; + + enable = wma_cli_get_command(link_info->vdev_id, + wmi_pdev_param_dynamic_bw, PDEV_CMD); + if (enable < 0) { + hdd_err("Failed to get dynamic_bw"); + return -EINVAL; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW, + (uint8_t)enable)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_nss_config() - Get the number of spatial streams supported by + * the adapter + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_nss_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + uint8_t nss; + struct hdd_adapter *adapter = link_info->adapter; + + if (adapter->device_mode == QDF_SAP_MODE) { + int value; + + value = wma_cli_get_command(link_info->vdev_id, + wmi_vdev_param_nss, VDEV_CMD); + if (value < 0) { + hdd_err("Failed to get nss"); + return -EINVAL; + } + nss = (uint8_t)value; + } else { + QDF_STATUS status; + + status = hdd_get_nss(adapter, &nss); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get nss"); + return -EINVAL; + } + } + + hdd_debug("nss %d", nss); + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_NSS, nss)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_num_tx_chains_config() - Get the number of tx chains supported by + * the adapter + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_num_tx_chains_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + uint8_t tx_chains; + QDF_STATUS status; + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_err("Not in connected state"); + return -EINVAL; + } + + status = hdd_get_num_tx_chains(link_info, &tx_chains); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get num tx chains"); + return -EINVAL; + } + + hdd_debug("num_tx_chains %d", tx_chains); + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS, tx_chains)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_tx_nss_config() - Get the number of tx spatial streams supported by + * the adapter + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_tx_nss_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + uint8_t tx_nss; + QDF_STATUS status; + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_err("Not in connected state"); + return -EINVAL; + } + + status = hdd_get_tx_nss(link_info, &tx_nss); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get nss"); + return -EINVAL; + } + + hdd_debug("tx_nss %d", tx_nss); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS, tx_nss)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_num_rx_chains_config() - Get the number of rx chains supported by + * the adapter + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_num_rx_chains_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + uint8_t rx_chains; + QDF_STATUS status; + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_err("Not in connected state"); + return -EINVAL; + } + + status = hdd_get_num_rx_chains(link_info, &rx_chains); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get num rx chains"); + return -EINVAL; + } + + hdd_debug("num_rx_chains %d", rx_chains); + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS, rx_chains)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_rx_nss_config() - Get the number of rx spatial streams supported by + * the adapter + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_rx_nss_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, const struct nlattr *attr) +{ + uint8_t rx_nss; + QDF_STATUS status; + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_err("Not in connected state"); + return -EINVAL; + } + + status = hdd_get_rx_nss(link_info, &rx_nss); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get nss"); + return -EINVAL; + } + + hdd_debug("rx_nss %d", rx_nss); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS, rx_nss)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_listen_interval_config() - Get listen interval from driver + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_listen_interval_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + uint32_t listen_interval = 0; + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + struct wlan_objmgr_vdev *vdev; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_err("Device not in STA / P2P-CLI mode"); + return -EINVAL; + } + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Failed to get vdev"); + return -EINVAL; + } + + status = ucfg_pmo_get_listen_interval(vdev, &listen_interval); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("vdev/vdev ctx NULL for getting listen interval"); + return -EINVAL; + } + + hdd_debug("listen interval %d", listen_interval); + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL, + listen_interval)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_optimized_power_config() - Get the number of spatial streams + * supported by the adapter + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_optimized_power_config(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint8_t optimized_power_cfg; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + optimized_power_cfg = ucfg_pmo_get_power_save_mode(hdd_ctx->psoc); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT, + optimized_power_cfg)) { + hdd_err_rl("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_get_sta_keepalive_interval() - Get keep alive interval + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +static int hdd_get_sta_keepalive_interval(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum QDF_OPMODE device_mode = adapter->device_mode; + uint32_t keep_alive_interval; + struct wlan_objmgr_vdev *vdev; + + if (device_mode != QDF_STA_MODE) { + hdd_debug("This command is not supported for %s device mode", + device_mode_to_string(device_mode)); + return -EINVAL; + } + + if (!hdd_is_vdev_in_conn_state(link_info)) { + if (adapter->keep_alive_interval) + keep_alive_interval = adapter->keep_alive_interval; + else + ucfg_mlme_get_sta_keep_alive_period( + hdd_ctx->psoc, + &keep_alive_interval); + } else { + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + keep_alive_interval = ucfg_mlme_get_keepalive_period(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + } + + hdd_debug("STA KEEPALIVE interval = %d", keep_alive_interval); + if (nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL, + keep_alive_interval)) { + hdd_err("nla_put failure"); + return -EINVAL; + } + + return 0; +} + +/** + * typedef config_getter_fn - get configuration handler + * @link_info: Link info pointer in HDD adapter + * @skb: sk buffer to hold nl80211 attributes + * @attr: The nl80211 attribute being applied + * + * Defines the signature of functions in the attribute vtable + * + * Return: 0 if the attribute was handled successfully, otherwise an errno + */ +typedef int (*config_getter_fn)(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb, + const struct nlattr *attr); + +/** + * struct config_getters + * @id: vendor attribute which this entry handles + * @max_attr_len: Maximum length of the attribute + * @cb: callback function to invoke to process the attribute when present + */ +struct config_getters { + uint32_t id; + size_t max_attr_len; + config_getter_fn cb; +}; + +/* vtable for config getters */ +static const struct config_getters config_getters[] = { +#ifdef WLAN_FEATURE_ELNA + {QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS, + sizeof(uint8_t), + hdd_get_elna_bypass}, +#endif + {QCA_WLAN_VENDOR_ATTR_CONFIG_ROAM_REASON, + sizeof(uint8_t), + hdd_get_roam_reason_vsie_status}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MPDU_AGGREGATION, + sizeof(uint8_t), + hdd_get_tx_ampdu}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MPDU_AGGREGATION, + sizeof(uint8_t), + hdd_get_rx_ampdu}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TX_MSDU_AGGREGATION, + sizeof(uint8_t), + hdd_get_tx_amsdu}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RX_MSDU_AGGREGATION, + sizeof(uint8_t), + hdd_get_rx_amsdu}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_LDPC, + sizeof(uint8_t), + hdd_vendor_attr_ldpc_get}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TX_STBC, + sizeof(uint8_t), + hdd_vendor_attr_tx_stbc_get}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RX_STBC, + sizeof(uint8_t), + hdd_vendor_attr_rx_stbc_get}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_CHANNEL_WIDTH, + sizeof(uint8_t), + hdd_get_channel_width}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_BW, + sizeof(uint8_t), + hdd_get_dynamic_bw}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_NSS, + sizeof(uint8_t), + hdd_get_nss_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_OPTIMIZED_POWER_MANAGEMENT, + sizeof(uint8_t), + hdd_get_optimized_power_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_TX_NSS, + sizeof(uint8_t), + hdd_get_tx_nss_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_RX_NSS, + sizeof(uint8_t), + hdd_get_rx_nss_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_LISTEN_INTERVAL, + sizeof(uint32_t), + hdd_get_listen_interval_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_TX_CHAINS, + sizeof(uint8_t), + hdd_get_num_tx_chains_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_NUM_RX_CHAINS, + sizeof(uint8_t), + hdd_get_num_rx_chains_config}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_MLO_LINKS, + WLAN_MAX_ML_BSS_LINKS * sizeof(uint8_t) * 2, + hdd_get_mlo_max_band_info}, + {QCA_WLAN_VENDOR_ATTR_CONFIG_KEEP_ALIVE_INTERVAL, + sizeof(uint16_t), + hdd_get_sta_keepalive_interval}, +}; + +/** + * hdd_get_configuration() - Handle get configuration + * @link_info: Link info pointer in HDD adapter + * @tb: parsed attribute array + * + * This is a table-driven function which dispatches attributes + * in a QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION + * vendor command. + * + * Return: 0 if there were no issues, otherwise errno of the last issue + */ +static int hdd_get_configuration(struct wlan_hdd_link_info *link_info, + struct nlattr **tb) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + uint32_t i, id; + unsigned long nl_buf_len = NLMSG_HDRLEN; + struct sk_buff *skb; + struct nlattr *attr; + config_getter_fn cb; + int errno = 0; + + for (i = 0; i < QDF_ARRAY_SIZE(config_getters); i++) { + id = config_getters[i].id; + attr = tb[id]; + if (!attr) + continue; + + nl_buf_len += NLA_HDRLEN + + NLA_ALIGN(config_getters[i].max_attr_len); + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + for (i = 0; i < QDF_ARRAY_SIZE(config_getters); i++) { + id = config_getters[i].id; + attr = tb[id]; + if (!attr) + continue; + + hdd_debug("Get wifi configuration %d", id); + + cb = config_getters[i].cb; + errno = cb(link_info, skb, attr); + if (errno) + break; + } + + if (errno) { + hdd_err("Failed to get wifi configuration, errno = %d", errno); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + + return errno; +} + +/** + * hdd_set_independent_configuration() - Handle independent attributes + * @link_info: Link info pointer in HDD adapter + * @tb: parsed attribute array + * + * This is a table-driven function which dispatches independent + * attributes in a QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION + * vendor command. An attribute is considered independent if it + * doesn't depend upon any other attributes + * + * Return: 0 if there were no issues, otherwise errno of the last issue + */ +static int +hdd_set_independent_configuration(struct wlan_hdd_link_info *link_info, + struct nlattr **tb) +{ + uint32_t i; + uint32_t id; + struct nlattr *attr; + independent_setter_fn cb; + int errno = 0; + int ret; + + for (i = 0; i < QDF_ARRAY_SIZE(independent_setters); i++) { + id = independent_setters[i].id; + attr = tb[id]; + if (!attr) + continue; + + hdd_debug("Set wifi configuration %d", id); + + cb = independent_setters[i].cb; + ret = cb(link_info, attr); + if (ret) + errno = ret; + } + + return errno; +} + +/** + * typedef interdependent_setter_fn - interdependent attribute handler + * @link_info: Link info pointer in HDD adapter + * @tb: The parsed nl80211 attributes being applied + * + * Defines the signature of functions in the interdependent attribute vtable + * + * Return: 0 if attributes were handled successfully, otherwise an errno + */ +typedef int (*interdependent_setter_fn)(struct wlan_hdd_link_info *link_info, + struct nlattr **tb); + +/* vtable for interdependent setters */ +static const interdependent_setter_fn interdependent_setters[] = { + hdd_config_access_policy, + hdd_config_mpdu_aggregation, + hdd_config_ant_div_period, + hdd_config_ant_div_snr_weight, + wlan_hdd_cfg80211_wifi_set_reorder_timeout, + wlan_hdd_cfg80211_wifi_set_rx_blocksize, + hdd_config_msdu_aggregation, + hdd_config_vdev_chains, + hdd_config_ani, + hdd_config_tx_rx_nss, + hdd_process_generic_set_cmd, + hdd_config_phy_mode, + hdd_config_power, + hdd_set_channel_width, + hdd_config_peer_ampdu, +}; + +/** + * hdd_set_interdependent_configuration() - Handle interdependent attributes + * @link_info: Link info pointer in hdd adapter + * @tb: parsed attribute array + * + * This is a table-driven function which handles interdependent + * attributes in a QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION + * vendor command. A set of attributes is considered interdependent if + * they depend upon each other. In the typical case if one of the + * attributes is present in the the attribute array, then all of the + * attributes must be present. + * + * Return: 0 if there were no issues, otherwise errno of the last issue + */ +static int +hdd_set_interdependent_configuration(struct wlan_hdd_link_info *link_info, + struct nlattr **tb) +{ + uint32_t i; + interdependent_setter_fn cb; + int errno = 0; + int ret; + + for (i = 0; i < QDF_ARRAY_SIZE(interdependent_setters); i++) { + cb = interdependent_setters[i]; + ret = cb(link_info, tb); + if (ret) + errno = ret; + } + + return errno; +} + +/** + * __wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + int errno, ret; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, data, + data_len, wlan_hdd_wifi_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + ret = hdd_set_independent_configuration(adapter->deflink, tb); + if (ret) + errno = ret; + + ret = hdd_set_interdependent_configuration(adapter->deflink, tb); + if (ret) + errno = ret; + + return errno; +} + +/** + * wlan_hdd_cfg80211_wifi_configuration_set() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. + */ +static int wlan_hdd_cfg80211_wifi_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_wifi_configuration_set(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_wifi_configuration_get() - Wifi configuration + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_wifi_configuration_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + int errno, ret; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_MAX, data, + data_len, wlan_hdd_wifi_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + /* Generic command is used by EasyMesh, + * route the command to SON module if it is Generic + * + * GENERIC_COMMAND to get configs can not be done as part of dispatch + * table because, for each command sent as part of GENERIC command, + * return value is different and is handled in SON module as well. + * Hence having return type with dispatch table is not possible as + * we will not be able to generalize the return for each of get sub + * command sent as part of GENERIC command. + */ + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND]) + return hdd_son_send_get_wifi_generic_command(wiphy, wdev, tb); + + ret = hdd_get_configuration(adapter->deflink, tb); + if (ret) + errno = ret; + + return errno; +} + +/** + * wlan_hdd_cfg80211_wifi_configuration_get() - Wifi configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_MAX. + * + * Return: EOK or other error codes. + */ +static int wlan_hdd_cfg80211_wifi_configuration_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_wifi_configuration_get(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static void hdd_disable_runtime_pm_for_user(struct hdd_context *hdd_ctx) +{ + struct hdd_runtime_pm_context *ctx = &hdd_ctx->runtime_context; + + if (!ctx) + return; + + if (ctx->is_user_wakelock_acquired) + return; + + ctx->is_user_wakelock_acquired = true; + qdf_runtime_pm_prevent_suspend(&ctx->user); +} + +static int hdd_test_config_6ghz_security_test_mode(struct hdd_context *hdd_ctx, + struct nlattr *attr) + +{ + uint8_t cfg_val; + bool rf_test_mode = false; + QDF_STATUS status; + + status = ucfg_mlme_is_rf_test_mode_enabled(hdd_ctx->psoc, + &rf_test_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get rf test mode failed"); + return -EINVAL; + } + if (rf_test_mode) { + hdd_err("rf test mode is enabled, ignore setting"); + return 0; + } + + cfg_val = nla_get_u8(attr); + hdd_debug("safe mode setting %d", cfg_val); + wlan_mlme_set_safe_mode_enable(hdd_ctx->psoc, cfg_val); + if (cfg_val) { + wlan_cm_set_check_6ghz_security(hdd_ctx->psoc, false); + wlan_cm_set_6ghz_key_mgmt_mask(hdd_ctx->psoc, + DEFAULT_KEYMGMT_6G_MASK); + } else { + wlan_cm_set_check_6ghz_security(hdd_ctx->psoc, true); + wlan_cm_set_6ghz_key_mgmt_mask(hdd_ctx->psoc, + ALLOWED_KEYMGMT_6G_MASK); + } + + return 0; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void wlan_hdd_set_listen_interval(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + enum wlan_eht_mode eht_mode; + uint16_t max_simult_link_num; + + ucfg_mlme_get_eht_mode(psoc, &eht_mode); + max_simult_link_num = wlan_mlme_get_sta_mlo_simultaneous_links(psoc); + + if (eht_mode == WLAN_EHT_MODE_MLSR && max_simult_link_num == 0) + sme_set_listen_interval(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + + hdd_debug("EHT mode: %d, max simultaneous link num: %d", + eht_mode, max_simult_link_num); +} +#else +static inline void wlan_hdd_set_listen_interval(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ +} +#endif + +/** + * __wlan_hdd_cfg80211_set_wifi_test_config() - Wifi test configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX + 1]; + int ret_val = 0; + uint8_t cfg_val = 0; + uint8_t ini_val = 0; + uint8_t set_val = 0; + struct sme_config_params *sme_config; + bool update_sme_cfg = false; + uint8_t tid = 0, ac; + uint16_t buff_size = 0; + mac_handle_t mac_handle; + QDF_STATUS status; + bool bval = false; + uint8_t value = 0; + uint8_t wmm_mode = 0; + uint32_t bss_max_idle_period = 0; + uint32_t cmd_id; + uint8_t link_id = 0xFF; + struct keep_alive_req keep_alive_req = {0}; + struct set_wfatest_params wfa_param = {0}; + struct wlan_hdd_link_info *link_info = adapter->deflink; + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + uint8_t op_mode; + + hdd_enter_dev(dev); + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) + return -ENOMEM; + + mac_handle = hdd_ctx->mac_handle; + sme_get_config_param(mac_handle, sme_config); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + ret_val = -EPERM; + goto send_err; + } + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + goto send_err; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed, can not start logger"); + ret_val = -EINVAL; + goto send_err; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX, + data, data_len, wlan_hdd_wifi_test_config_policy)) { + hdd_err("invalid attr"); + ret_val = -EINVAL; + goto send_err; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ACCEPT_ADDBA_REQ]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ACCEPT_ADDBA_REQ] + ); + hdd_debug("set addba accept req from peer value %d", cfg_val); + ret_val = sme_set_addba_accept(mac_handle, + link_info->vdev_id, + cfg_val); + if (ret_val) + goto send_err; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MCS]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MCS]); + hdd_debug("set HE MCS value 0x%0X", cfg_val); + ret_val = sme_update_he_mcs(mac_handle, + link_info->vdev_id, cfg_val); + if (ret_val) + goto send_err; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WMM_ENABLE]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WMM_ENABLE]); + if (!cfg_val) { + sme_config->csr_config.WMMSupportMode = + hdd_to_csr_wmm_mode(HDD_WMM_USER_MODE_NO_QOS); + hdd_debug("wmm is disabled"); + } else { + status = ucfg_mlme_get_wmm_mode(hdd_ctx->psoc, + &wmm_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get wmm_mode failed"); + ret_val = -EINVAL; + goto send_err; + } + sme_config->csr_config.WMMSupportMode = + hdd_to_csr_wmm_mode(wmm_mode); + hdd_debug("using wmm default value"); + } + update_sme_cfg = true; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SEND_ADDBA_REQ]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SEND_ADDBA_REQ]); + if (cfg_val) { + /*Auto BA mode*/ + set_val = HDD_BA_MODE_AUTO; + hdd_debug("BA operating mode is set to auto"); + } else { + /*Manual BA mode*/ + set_val = HDD_BA_MODE_MANUAL; + hdd_debug("BA operating mode is set to Manual"); + } + + op_mode = wlan_get_opmode_from_vdev_id( + hdd_ctx->pdev, + link_info->vdev_id); + + sme_set_per_link_ba_mode(mac_handle, set_val); + + if (!cfg_val) { + ret_val = wma_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_amsdu_aggregation_size_optimization, + 0, VDEV_CMD); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_FRAGMENTATION]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_FRAGMENTATION] + ); + if (cfg_val > HE_FRAG_LEVEL1) + set_val = HE_FRAG_LEVEL1; + else + set_val = cfg_val; + + hdd_debug("set HE fragmention to %d", set_val); + ret_val = sme_update_he_frag_supp(mac_handle, + link_info->vdev_id, + set_val); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WEP_TKIP_IN_HE]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_WEP_TKIP_IN_HE]); + sme_config->csr_config.wep_tkip_in_he = cfg_val; + hdd_debug("Set WEP/TKIP allow in HE %d", cfg_val); + + update_sme_cfg = true; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADD_DEL_BA_SESSION]) { + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BA_TID]) { + tid = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BA_TID]); + } else { + hdd_err("TID is not set for ADD/DEL BA cfg"); + ret_val = -EINVAL; + goto send_err; + } + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADD_DEL_BA_SESSION]); + if (cfg_val == QCA_WLAN_ADD_BA) { + if (tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE]) + buff_size = nla_get_u16(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE]); + ret_val = sme_send_addba_req(mac_handle, + link_info->vdev_id, + tid, buff_size); + } else if (cfg_val == QCA_WLAN_DELETE_BA) { + } else { + hdd_err("Invalid BA session cfg"); + ret_val = -EINVAL; + goto send_err; + } + } else if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE]) { + uint32_t arg[2]; + buff_size = nla_get_u16(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ADDBA_BUFF_SIZE]); + hdd_debug("set buff size to %d for all tids", buff_size); + ret_val = sme_set_ba_buff_size(mac_handle, + link_info->vdev_id, + buff_size); + if (ret_val) + goto send_err; + + if (buff_size > 512) + /* Configure ADDBA req buffer size to 1024 */ + set_val = HDD_BA_MODE_1024; + else if (buff_size > 256) + /* Configure ADDBA req buffer size to 512 */ + set_val = HDD_BA_MODE_512; + else if (buff_size > 64) + /* Configure ADDBA req buffer size to 256 */ + set_val = HDD_BA_MODE_256; + else + /* Configure ADDBA req buffer size to 64 */ + set_val = HDD_BA_MODE_64; + + sme_set_per_link_ba_mode(mac_handle, set_val); + + ret_val = wma_cli_set_command(link_info->vdev_id, + GEN_VDEV_PARAM_AMPDU, + buff_size, GEN_CMD); + + if (set_val == HDD_BA_MODE_512) { + arg[0] = 703; + arg[1] = 0; + ret_val = sme_send_unit_test_cmd( + adapter->deflink->vdev_id, + 0x48, 2, arg); + if (ret_val) + hdd_err("Failed to set Full state BA support"); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_NO_ACK]) { + int he_mcs_val; + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_NO_ACK_AC]) { + ac = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_NO_ACK_AC]); + } else { + hdd_err("AC is not set for NO ACK policy config"); + ret_val = -EINVAL; + goto send_err; + } + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_NO_ACK]); + hdd_debug("Set NO_ACK to %d for ac %d", cfg_val, ac); + ret_val = sme_set_no_ack_policy(mac_handle, + link_info->vdev_id, + cfg_val, ac); + if (cfg_val) { + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, + &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + if (bval) + /*2x2 MCS 5 value*/ + he_mcs_val = 0x45; + else + /*1x1 MCS 5 value*/ + he_mcs_val = 0x25; + + if (hdd_set_11ax_rate(adapter, he_mcs_val, NULL)) + hdd_err("HE MCS set failed, MCS val %0x", + he_mcs_val); + } else { + if (hdd_set_11ax_rate(adapter, 0xFF, NULL)) + hdd_err("disable fixed rate failed"); + } + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_KEEP_ALIVE_FRAME_TYPE; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Keep alive data type %d", cfg_val); + if (cfg_val == QCA_WLAN_KEEP_ALIVE_DATA) { + ret_val = hdd_set_grat_arp_keepalive(adapter); + if (ret_val) { + hdd_err("Keep alive data type set failed"); + goto send_err; + } + } else { + if (cfg_val == QCA_WLAN_KEEP_ALIVE_MGMT) + keep_alive_req.packetType = + SIR_KEEP_ALIVE_MGMT_FRAME; + else + keep_alive_req.packetType = + SIR_KEEP_ALIVE_NULL_PKT; + ucfg_mlme_get_sta_keep_alive_period( + hdd_ctx->psoc, + &keep_alive_req.timePeriod); + keep_alive_req.sessionId = link_info->vdev_id; + status = sme_set_keep_alive(hdd_ctx->mac_handle, + link_info->vdev_id, + &keep_alive_req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set keepalive"); + ret_val = qdf_status_to_os_return(status); + goto send_err; + } + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_LTF]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_LTF]); + hdd_debug("Set HE LTF to %d", cfg_val); + ret_val = sme_set_auto_rate_he_ltf(mac_handle, + link_info->vdev_id, + cfg_val); + if (ret_val) + sme_err("Failed to set auto rate HE LTF"); + + ret_val = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_set_he_ltf, + cfg_val, VDEV_CMD); + if (ret_val) + goto send_err; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_TX_BEAMFORMEE]); + hdd_debug("Set Tx beamformee to %d", cfg_val); + ret_val = sme_update_tx_bfee_supp(mac_handle, + link_info->vdev_id, + cfg_val); + if (ret_val) + sme_err("Failed to update Tx beamformee support"); + + ret_val = sme_update_eht_caps(mac_handle, link_info->vdev_id, + cfg_val, EHT_TX_BFEE_ENABLE, + adapter->device_mode); + if (ret_val) + sme_err("Failed to set Tx beamformee cap"); + + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RX_CTRL_FRAME_TO_MBSS; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + ret_val = sme_update_he_capabilities(mac_handle, + link_info->vdev_id, + cfg_val, cmd_id); + if (ret_val) + sme_err("Failed to update HE cap"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + ret_val = sme_update_he_capabilities(mac_handle, + link_info->vdev_id, + cfg_val, cmd_id); + if (ret_val) + sme_err("Failed to update HE cap"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_BEAMFORMEE_NSTS]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_BEAMFORMEE_NSTS]); + status = ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp(hdd_ctx->psoc, + &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get tx_bfee_ant_supp"); + + if (!cfg_in_range(CFG_VHT_BEAMFORMEE_ANT_SUPP, cfg_val)) { + hdd_err("NSTS %d not supported, supp_val %d", cfg_val, + value); + ret_val = -ENOTSUPP; + goto send_err; + } + hdd_debug("Set Tx beamformee NSTS to %d", cfg_val); + ret_val = sme_update_tx_bfee_nsts(hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val, + value); + if (ret_val) + sme_err("Failed to set Tx beamformee cap"); + + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MAC_PADDING_DUR]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_MAC_PADDING_DUR]); + if (cfg_val) { + hdd_debug("Set HE mac padding dur to %d", cfg_val); + ret_val = sme_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_mu_edca_fw_update_en, + 0, VDEV_CMD); + if (ret_val) + hdd_err("MU_EDCA update disable failed"); + sme_set_usr_cfg_mu_edca(hdd_ctx->mac_handle, true); + sme_set_he_mu_edca_def_cfg(hdd_ctx->mac_handle); + if (sme_update_mu_edca_params( + hdd_ctx->mac_handle, + link_info->vdev_id)) + hdd_err("Failed to send mu edca params"); + } else { + ret_val = sme_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_mu_edca_fw_update_en, + 1, VDEV_CMD); + sme_set_usr_cfg_mu_edca(hdd_ctx->mac_handle, false); + } + ret_val = sme_update_he_trigger_frm_mac_pad( + hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val); + if (ret_val) + hdd_err("Failed to set Trig frame mac padding cap"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OVERRIDE_MU_EDCA]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OVERRIDE_MU_EDCA]); + if (cfg_val) { + ret_val = sme_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_mu_edca_fw_update_en, + 0, VDEV_CMD); + if (ret_val) + hdd_err("MU_EDCA update disable failed"); + sme_set_usr_cfg_mu_edca(hdd_ctx->mac_handle, true); + sme_set_he_mu_edca_def_cfg(hdd_ctx->mac_handle); + if (sme_update_mu_edca_params( + hdd_ctx->mac_handle, + link_info->vdev_id)) + hdd_err("Failed to send mu edca params"); + } else { + ret_val = sme_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_mu_edca_fw_update_en, + 1, VDEV_CMD); + sme_set_usr_cfg_mu_edca(hdd_ctx->mac_handle, false); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_SUPP]) { + cfg_val = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_OM_CTRL_SUPP]); + ret_val = sme_update_he_om_ctrl_supp(hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val); + } + + cmd_id = + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_USE_BSSID_IN_PROBE_REQ_RA; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + if (cfg_val) + status = ucfg_mlme_set_scan_probe_unicast_ra( + hdd_ctx->psoc, true); + else + status = ucfg_mlme_set_scan_probe_unicast_ra( + hdd_ctx->psoc, false); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to set unicat probe ra cfg"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OMI_TX; + if (tb[cmd_id]) { + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_OMI_MAX + 1]; + struct nlattr *curr_attr; + int tmp, rc; + struct omi_ctrl_tx omi_data = {0}; + + nla_for_each_nested(curr_attr, tb[cmd_id], tmp) { + rc = wlan_cfg80211_nla_parse( + tb2, QCA_WLAN_VENDOR_ATTR_OMI_MAX, + nla_data(curr_attr), + nla_len(curr_attr), + qca_wlan_vendor_attr_omi_tx_policy); + if (rc) { + hdd_err("Invalid ATTR"); + goto send_err; + } + cmd_id = QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + ret_val = sme_set_he_om_ctrl_param( + hdd_ctx->mac_handle, + link_info->vdev_id, + cmd_id, cfg_val); + } + cmd_id = QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + ret_val = sme_set_he_om_ctrl_param( + hdd_ctx->mac_handle, + link_info->vdev_id, + cmd_id, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + ret_val = sme_set_he_om_ctrl_param( + hdd_ctx->mac_handle, + link_info->vdev_id, + cmd_id, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + ret_val = sme_set_he_om_ctrl_param( + hdd_ctx->mac_handle, + link_info->vdev_id, + cmd_id, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + ret_val = sme_set_he_om_ctrl_param( + hdd_ctx->mac_handle, + link_info->vdev_id, + cmd_id, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_EHT_OMI_RX_NSS_EXTN; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + hdd_debug("EHT OM ctrl Rx Nss %d", cfg_val); + omi_data.eht_rx_nss_ext = cfg_val; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_EHT_OMI_CH_BW_EXTN; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + hdd_debug("Set EHT OM ctrl BW to %d", cfg_val); + omi_data.eht_ch_bw_ext = cfg_val; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_EHT_OMI_TX_NSS_EXTN; + if (tb2[cmd_id]) { + cfg_val = nla_get_u8(tb2[cmd_id]); + hdd_debug("EHT OM ctrl Tx Nss %d", cfg_val); + omi_data.eht_tx_nss_ext = cfg_val; + } + } + + if (ret_val) { + sme_reset_he_om_ctrl(hdd_ctx->mac_handle); + goto send_err; + } + ret_val = sme_send_he_om_ctrl_update(hdd_ctx->mac_handle, + link_info->vdev_id, + &omi_data); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_CLEAR_HE_OM_CTRL_CONFIG]) + sme_reset_he_om_ctrl(hdd_ctx->mac_handle); + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TX_SUPPDU; + if (tb[cmd_id]) { + int i; + enum wlan_eht_mode eht_mode; + uint8_t op_mode; + + cfg_val = nla_get_u8(tb[cmd_id]); + ucfg_mlme_get_eht_mode(hdd_ctx->psoc, &eht_mode); + if (eht_mode == WLAN_EHT_MODE_MLMR || + eht_mode == WLAN_EHT_MODE_MLSR || + eht_mode == WLAN_EHT_MODE_EMLSR) { + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + op_mode = wlan_get_opmode_from_vdev_id( + hdd_ctx->pdev, i); + if (op_mode != QDF_STA_MODE) { + hdd_debug("vdev_id %d is not STA", i); + continue; + } + hdd_debug("Tx SU PPDU enable %d, vdev_id %d", + cfg_val, i); + if (cfg_val) + sme_config_su_ppdu_queue(i, true); + else + sme_config_su_ppdu_queue(i, false); + } + } else { + if (cfg_val) + sme_config_su_ppdu_queue(link_info->vdev_id, + true); + else + sme_config_su_ppdu_queue(link_info->vdev_id, + false); + } + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ENABLE_2G_VHT; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure 2G VHT support %d", cfg_val); + ucfg_mlme_set_vht_for_24ghz(hdd_ctx->psoc, + (cfg_val ? true : false)); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_HTC_HE_SUPP; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure +HTC_HE support %d", cfg_val); + sme_update_he_htc_he_supp(hdd_ctx->mac_handle, + link_info->vdev_id, + (cfg_val ? true : false)); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PUNCTURED_PREAMBLE_RX; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure Punctured preamble Rx %d", cfg_val); + ret_val = sme_update_he_capabilities(mac_handle, + link_info->vdev_id, + cfg_val, cmd_id); + if (ret_val) + sme_err("Failed to update HE cap"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_HE_TESTBED_DEFAULTS; + if (tb[cmd_id]) { + hdd_disable_runtime_pm_for_user(hdd_ctx); + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure HE testbed defaults %d", cfg_val); + if (!cfg_val) + sme_reset_he_caps(hdd_ctx->mac_handle, + link_info->vdev_id); + else + sme_set_he_testbed_def(hdd_ctx->mac_handle, + link_info->vdev_id); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_ACTION_TX_TB_PPDU; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure Action frame Tx in TB PPDU %d", cfg_val); + sme_config_action_tx_in_tb_ppdu(hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP]) { + ret_val = hdd_test_config_twt_setup_session(adapter, tb); + if (ret_val) + goto send_err; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_TERMINATE]) { + ret_val = hdd_test_config_twt_terminate_session(adapter, tb); + if (ret_val) + goto send_err; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_HE_TWT_REQ_SUPPORT; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("twt_request: val %d", cfg_val); + ret_val = sme_update_he_twt_req_support( + hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FULL_BW_UL_MU_MIMO; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + ini_val = cfg_get(hdd_ctx->psoc, CFG_HE_UL_MUMIMO); + hdd_debug("fullbw_ulmumimo: cfg %d, ini %d", cfg_val, ini_val); + if (cfg_val) { + switch (ini_val) { + case CFG_NO_SUPPORT_UL_MUMIMO: + case CFG_FULL_BW_SUPPORT_UL_MUMIMO: + cfg_val = CFG_FULL_BW_SUPPORT_UL_MUMIMO; + break; + case CFG_PARTIAL_BW_SUPPORT_UL_MUMIMO: + case CFG_FULL_PARTIAL_BW_SUPPORT_UL_MUMIMO: + cfg_val = CFG_FULL_PARTIAL_BW_SUPPORT_UL_MUMIMO; + break; + } + } else { + switch (ini_val) { + case CFG_NO_SUPPORT_UL_MUMIMO: + case CFG_FULL_BW_SUPPORT_UL_MUMIMO: + cfg_val = CFG_NO_SUPPORT_UL_MUMIMO; + break; + case CFG_PARTIAL_BW_SUPPORT_UL_MUMIMO: + case CFG_FULL_PARTIAL_BW_SUPPORT_UL_MUMIMO: + cfg_val = CFG_PARTIAL_BW_SUPPORT_UL_MUMIMO; + break; + } + } + ret_val = sme_update_he_full_ul_mumimo( + hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISABLE_DATA_MGMT_RSP_TX; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("disable Tx cfg: val %d", cfg_val); + sme_set_cfg_disable_tx(hdd_ctx->mac_handle, + link_info->vdev_id, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PMF_PROTECTION; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("pmf cfg: val %d", cfg_val); + sme_set_pmf_wep_cfg(hdd_ctx->mac_handle, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD; + if (tb[cmd_id]) { + cfg_val = nla_get_u16(tb[cmd_id]); + hdd_debug("bss max idle period %d", cfg_val); + sme_set_bss_max_idle_period(hdd_ctx->mac_handle, cfg_val); + } + + cmd_id = + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BSS_MAX_IDLE_PERIOD_ENABLE; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + if (cfg_val) + ucfg_mlme_get_sta_keep_alive_period( + hdd_ctx->psoc, + &bss_max_idle_period); + hdd_debug("bss max idle period %d", bss_max_idle_period); + sme_set_bss_max_idle_period(hdd_ctx->mac_handle, + bss_max_idle_period); + } + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_DISASSOC_TX; + if (tb[cmd_id]) { + hdd_info("Send disassoc mgmt frame"); + sme_send_disassoc_req_frame(hdd_ctx->mac_handle, + link_info->vdev_id, + hdd_sta_ctx->conn_info.bssid.bytes, + 1, false); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RU_242_TONE_TX; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_info("RU 242 tone Tx enable: %d", cfg_val); + sme_set_ru_242_tone_tx_cfg(hdd_ctx->mac_handle, cfg_val); + if (cfg_val) + hdd_update_channel_width( + link_info, eHT_CHANNEL_WIDTH_20MHZ, + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE, + link_id, false); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_ER_SU_PPDU_TYPE; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("EU SU PPDU type Tx enable: %d", cfg_val); + if (cfg_val) { + hdd_update_channel_width( + link_info, eHT_CHANNEL_WIDTH_20MHZ, + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE, + link_id, false); + hdd_set_tx_stbc(link_info, 0); + hdd_set_11ax_rate(adapter, 0x400, NULL); + status = wma_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_he_range_ext, + 1, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set HE_RANGE_EXT, %d", + status); + status = wma_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_non_data_he_range_ext, + 1, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("fail to set NON_DATA_HE_RANGE_EXT %d", + status); + } else { + hdd_update_channel_width( + link_info, eHT_CHANNEL_WIDTH_160MHZ, + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE, + link_id, false); + hdd_set_tx_stbc(link_info, 1); + hdd_set_11ax_rate(adapter, 0xFFFF, NULL); + status = wma_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_he_range_ext, + 0, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set HE_RANGE_EXT, %d", + status); + status = wma_cli_set_command( + link_info->vdev_id, + wmi_vdev_param_non_data_he_range_ext, + 0, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("fail to set NON_DATA_HE_RANGE_EXT %d", + status); + } + + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FT_REASSOCREQ_RSNXE_USED; + if (tb[cmd_id]) { + wfa_param.vdev_id = link_info->vdev_id; + wfa_param.value = nla_get_u8(tb[cmd_id]); + + if (wfa_param.value < RSNXE_DEFAULT || + wfa_param.value > RSNXE_OVERRIDE_2) { + hdd_debug("Invalid RSNXE override %d", wfa_param.value); + goto send_err; + } + wfa_param.cmd = WFA_CONFIG_RXNE; + hdd_info("send wfa test config RXNE used %d", wfa_param.value); + + ret_val = ucfg_send_wfatest_cmd(link_info->vdev, + &wfa_param); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_CSA; + if (tb[cmd_id]) { + wfa_param.vdev_id = link_info->vdev_id; + wfa_param.value = nla_get_u8(tb[cmd_id]); + + if (wfa_param.value != CSA_DEFAULT && + wfa_param.value != CSA_IGNORE) { + hdd_debug("Invalid CSA config %d", wfa_param.value); + goto send_err; + } + wfa_param.cmd = WFA_CONFIG_CSA; + hdd_info("send wfa test config CSA used %d", wfa_param.value); + + ret_val = ucfg_send_wfatest_cmd(link_info->vdev, + &wfa_param); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_6GHZ_SECURITY_TEST_MODE; + if (tb[cmd_id]) { + ret_val = hdd_test_config_6ghz_security_test_mode(hdd_ctx, + tb[cmd_id]); + if (ret_val) + goto send_err; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_OCI_OVERRIDE; + if (tb[cmd_id]) { + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_MAX + 1]; + + wfa_param.vdev_id = link_info->vdev_id; + wfa_param.cmd = WFA_CONFIG_OCV; + if (wlan_cfg80211_nla_parse_nested( + tb2, QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_MAX, + tb[cmd_id], wlan_oci_override_policy)) { + hdd_debug("Failed to parse OCI override"); + goto send_err; + } + + if (!(tb2[QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE] && + tb2[QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY])) { + hdd_debug("Invalid ATTR FRAME_TYPE/FREQUENCY"); + goto send_err; + } + + wfa_param.ocv_param = qdf_mem_malloc( + sizeof(struct ocv_wfatest_params)); + if (!wfa_param.ocv_param) { + hdd_err("Failed to alloc memory for ocv param"); + goto send_err; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FRAME_TYPE; + switch (nla_get_u8(tb2[cmd_id])) { + case QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_REQ: + wfa_param.ocv_param->frame_type = + WMI_HOST_WFA_CONFIG_OCV_FRMTYPE_SAQUERY_REQ; + break; + + case QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_SA_QUERY_RESP: + wfa_param.ocv_param->frame_type = + WMI_HOST_WFA_CONFIG_OCV_FRMTYPE_SAQUERY_RSP; + break; + + case QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FT_REASSOC_REQ: + wfa_param.ocv_param->frame_type = + WMI_HOST_WFA_CONFIG_OCV_FRMTYPE_FT_REASSOC_REQ; + break; + + case QCA_WLAN_VENDOR_OCI_OVERRIDE_FRAME_FILS_REASSOC_REQ: + wfa_param.ocv_param->frame_type = + WMI_HOST_WFA_CONFIG_OCV_FRMTYPE_FILS_REASSOC_REQ; + break; + + default: + hdd_debug("Invalid frame type for ocv test config %d", + nla_get_u8(tb2[cmd_id])); + qdf_mem_free(wfa_param.ocv_param); + goto send_err; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_OCI_OVERRIDE_FREQUENCY; + wfa_param.ocv_param->freq = nla_get_u32(tb2[cmd_id]); + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(wfa_param.ocv_param->freq) && + !WLAN_REG_IS_5GHZ_CH_FREQ(wfa_param.ocv_param->freq) && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(wfa_param.ocv_param->freq)) { + hdd_debug("Invalid Freq %d", wfa_param.ocv_param->freq); + qdf_mem_free(wfa_param.ocv_param); + goto send_err; + } + + hdd_info("send wfa test config OCV frame type %d freq %d", + wfa_param.ocv_param->frame_type, + wfa_param.ocv_param->freq); + ret_val = ucfg_send_wfatest_cmd(link_info->vdev, + &wfa_param); + qdf_mem_free(wfa_param.ocv_param); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_SA_QUERY_TIMEOUT; + if (tb[cmd_id]) { + wfa_param.vdev_id = link_info->vdev_id; + wfa_param.value = nla_get_u8(tb[cmd_id]); + + if (wfa_param.value != SA_QUERY_TIMEOUT_DEFAULT && + wfa_param.value != SA_QUERY_TIMEOUT_IGNORE) { + hdd_debug("Invalid SA query timeout config %d", + wfa_param.value); + goto send_err; + } + wfa_param.cmd = WFA_CONFIG_SA_QUERY; + hdd_info("send wfa test config SAquery %d", wfa_param.value); + + ret_val = ucfg_send_wfatest_cmd(link_info->vdev, + &wfa_param); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FILS_DISCOVERY_FRAMES_TX; + if (tb[cmd_id] && adapter->device_mode == QDF_SAP_MODE) { + wfa_param.vdev_id = link_info->vdev_id; + wfa_param.value = nla_get_u8(tb[cmd_id]); + + if (!(wfa_param.value == FILS_DISCV_FRAMES_DISABLE || + wfa_param.value == FILS_DISCV_FRAMES_ENABLE)) { + hdd_debug("Invalid FILS_DISCV_FRAMES config %d", + wfa_param.value); + goto send_err; + } + wfa_param.cmd = WFA_FILS_DISCV_FRAMES; + hdd_info("send wfa FILS_DISCV_FRAMES TX config %d", + wfa_param.value); + ret_val = ucfg_send_wfatest_cmd(link_info->vdev, + &wfa_param); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_IGNORE_H2E_RSNXE; + if (tb[cmd_id]) { + wfa_param.vdev_id = link_info->vdev_id; + wfa_param.value = nla_get_u8(tb[cmd_id]); + + if (!(wfa_param.value == H2E_RSNXE_DEFAULT || + wfa_param.value == H2E_RSNXE_IGNORE)) { + hdd_debug("Invalid RSNXE_IGNORE config %d", + wfa_param.value); + goto send_err; + } + wfa_param.cmd = WFA_IGNORE_H2E_RSNXE; + hdd_info("send wfa WFA_IGNORE_H2E_RSNXE config %d", + wfa_param.value); + ret_val = ucfg_send_wfatest_cmd(link_info->vdev, + &wfa_param); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_11BE_EMLSR_MODE; + if (tb[cmd_id] && adapter->device_mode == QDF_STA_MODE) { + cfg_val = nla_get_u8(tb[cmd_id]); + + ret_val = hdd_test_config_emlsr_mode(hdd_ctx, cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BEAMFORMER_PERIODIC_SOUNDING; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + + set_val = cfg_val ? TX_BFER_NDP_PERIODICITY : 0; + + ret_val = wma_cli_set_command( + link_info->vdev_id, + WMI_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + set_val, PDEV_CMD); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_80MHZ; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure Tx BF < 80 MHz: %d", cfg_val); + + ret_val = sme_update_eht_caps(mac_handle, link_info->vdev_id, + cfg_val, EHT_TX_BFEE_SS_80MHZ, + adapter->device_mode); + if (ret_val) + sme_err("Failed to update EHT Tx BFEE cap"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_160MHZ; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure Tx BF for 160 MHz: %d", cfg_val); + + ret_val = sme_update_eht_caps(mac_handle, link_info->vdev_id, + cfg_val, EHT_TX_BFEE_SS_160MHZ, + adapter->device_mode); + if (ret_val) + sme_err("Failed to update EHT Tx BFEE cap"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_BEAMFORMEE_SS_320MHZ; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure Tx BF for 320 MHz: %d", cfg_val); + + ret_val = sme_update_eht_caps(mac_handle, link_info->vdev_id, + cfg_val, EHT_TX_BFEE_SS_320MHZ, + adapter->device_mode); + if (ret_val) + sme_err("Failed to update EHT Tx BFEE cap"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EXCLUDE_STA_PROF_IN_PROBE_REQ; + if (tb[cmd_id] && adapter->device_mode == QDF_STA_MODE) { + cfg_val = nla_get_u8(tb[cmd_id]); + + if (cfg_val) { + wlan_vdev_obj_lock(link_info->vdev); + wlan_vdev_mlme_cap_set( + link_info->vdev, + WLAN_VDEV_C_EXCL_STA_PROF_PRB_REQ); + wlan_vdev_obj_unlock(link_info->vdev); + } else { + wlan_vdev_obj_lock(link_info->vdev); + wlan_vdev_mlme_cap_clear( + link_info->vdev, + WLAN_VDEV_C_EXCL_STA_PROF_PRB_REQ); + wlan_vdev_obj_unlock(link_info->vdev); + } + hdd_debug("Sta profile in Probe req frame: %d", cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_SET_EHT_TESTBED_DEFAULTS; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure EHT testbed defaults %d", cfg_val); + if (!cfg_val) + sme_reset_eht_caps(hdd_ctx->mac_handle, + link_info->vdev_id); + else + sme_set_eht_testbed_def(hdd_ctx->mac_handle, + link_info->vdev_id); + + sme_set_vdev_ies_per_band(hdd_ctx->mac_handle, + link_info->vdev_id, + adapter->device_mode); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MCS; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + sme_update_eht_cap_mcs(hdd_ctx->mac_handle, link_info->vdev_id, + cfg_val); + sme_set_vdev_ies_per_band(hdd_ctx->mac_handle, + link_info->vdev_id, + adapter->device_mode); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_TB_SOUNDING_FB_RL; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure TB sounding feedback rate limit: %d", + cfg_val); + + ret_val = sme_update_eht_caps( + mac_handle, link_info->vdev_id, + cfg_val, + EHT_TX_BFEE_SOUNDING_FEEDBACK_RATELIMIT, + adapter->device_mode); + if (ret_val) + sme_err("Failed to update EHT Tx BFEE cap"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_OM_CTRL_SUPPORT; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("EHT OM control support: %d", cfg_val); + + ret_val = sme_update_he_htc_he_supp(hdd_ctx->mac_handle, + link_info->vdev_id, + true); + if (ret_val) + hdd_err("Could not set htc_he"); + + ret_val = sme_update_eht_om_ctrl_supp(hdd_ctx->mac_handle, + link_info->vdev_id, + cfg_val); + if (ret_val) + hdd_err("Could not update EHT OM control fields"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EMLSR_PADDING_DELAY; + if (tb[cmd_id] && adapter->device_mode == QDF_STA_MODE) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Configure EMLSR padding delay subfield to %d", + cfg_val); + if (cfg_val) + wlan_mlme_cfg_set_emlsr_pad_delay(hdd_ctx->psoc, + cfg_val); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_FORCE_MLO_POWER_SAVE_BCN_PERIOD; + if (tb[cmd_id] && adapter->device_mode == QDF_STA_MODE) { + uint32_t bitmap = 0; + uint32_t vdev_id, idx; + + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("Send vdev pause on ML sta vdev for %d beacon periods", + cfg_val); + bitmap = policy_mgr_get_active_vdev_bitmap(hdd_ctx->psoc); + for (idx = 0; idx < 32; idx++) { + if (bitmap & (1 << idx)) { + vdev_id = idx; + ret_val = sme_send_vdev_pause_for_bcn_period( + mac_handle, + vdev_id, cfg_val); + if (ret_val) + hdd_err("Failed to send vdev pause"); + } + } + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_STR_TX; + if (tb[cmd_id]) { + uint32_t arg[2]; + + hdd_debug("Send EHT MLO STR TX indication to FW"); + arg[0] = 676; + arg[1] = 1; + + ret_val = sme_send_unit_test_cmd(link_info->vdev_id, + 0x48, 2, arg); + + if (ret_val) + hdd_err("Failed to send STR TX indication"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_EHT_MLO_LINK_POWER_SAVE; + if (tb[cmd_id]) { + struct nlattr *curr_attr; + int len; + uint8_t link_id, timeout = 0, num_links = 0; + bool allow_ps = true; + + nla_for_each_nested(curr_attr, tb[cmd_id], len) { + if (nla_len(curr_attr) != sizeof(uint8_t)) { + hdd_err("len is not correct for idx %d", + num_links); + goto send_err; + } + link_id = nla_get_u8(curr_attr); + hdd_debug("link id[%d]: %d", num_links, link_id); + wlan_hdd_set_mlo_ps(adapter, allow_ps, timeout, + link_id); + num_links++; + } + + wlan_hdd_set_listen_interval(hdd_ctx, adapter); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MLD_ID_ML_PROBE_REQ; + if (tb[cmd_id]) { + cfg_val = nla_get_u8(tb[cmd_id]); + hdd_debug("MLD ID in ML probe request: %d", cfg_val); + ret_val = ucfg_mlme_set_eht_mld_id(hdd_ctx->psoc, cfg_val); + if (ret_val) + hdd_err("Failed to set MLD ID"); + } + + if (update_sme_cfg) + sme_update_config(mac_handle, sme_config); + +send_err: + qdf_mem_free(sme_config); + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_set_wifi_test_config() - Wifi test configuration + * vendor command + * + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX + * + * Return: EOK or other error codes. + */ +static int wlan_hdd_cfg80211_set_wifi_test_config(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_wifi_test_config(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +const struct nla_policy qca_wlan_vendor_wifi_logger_start_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL] + = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_start() - This function is used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function enables or disables the collection of packet statistics from + * the firmware + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1]; + struct sir_wifi_start_log start_log = { 0 }; + mac_handle_t mac_handle; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed, can not start logger"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_start_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]) { + hdd_err("attr ATTR failed"); + return -EINVAL; + } + start_log.ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_RING_ID]); + hdd_debug("Ring ID=%d", start_log.ring_id); + + /* Parse and fetch verbose level */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]) { + hdd_err("attr verbose_level failed"); + return -EINVAL; + } + start_log.verbose_level = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_VERBOSE_LEVEL]); + hdd_debug("verbose_level=%d", start_log.verbose_level); + + /* Parse and fetch flag */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]) { + hdd_err("attr flag failed"); + return -EINVAL; + } + start_log.is_iwpriv_command = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_FLAGS]); + + start_log.user_triggered = 1; + + /* size is buff size which can be set using iwpriv command*/ + start_log.size = 0; + start_log.is_pktlog_buff_clear = false; + + cds_set_ring_log_level(start_log.ring_id, start_log.verbose_level); + + if (start_log.ring_id == RING_ID_WAKELOCK) { + /* Start/stop wakelock events */ + if (start_log.verbose_level > WLAN_LOG_LEVEL_OFF) + cds_set_wakelock_logging(true); + else + cds_set_wakelock_logging(false); + return 0; + } + + if (start_log.ring_id == RING_ID_PER_PACKET_STATS) { + if (hdd_ctx->is_pktlog_enabled && + (start_log.verbose_level == WLAN_LOG_LEVEL_ACTIVE)) + return 0; + + if ((!hdd_ctx->is_pktlog_enabled) && + (start_log.verbose_level != WLAN_LOG_LEVEL_ACTIVE)) + return 0; + } + + mac_handle = hdd_ctx->mac_handle; + status = sme_wifi_start_logger(mac_handle, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", + status); + return -EINVAL; + } + + if (start_log.ring_id == RING_ID_PER_PACKET_STATS) { + if (start_log.verbose_level == WLAN_LOG_LEVEL_ACTIVE) + hdd_ctx->is_pktlog_enabled = true; + else + hdd_ctx->is_pktlog_enabled = false; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_start() - Wrapper function used to enable + * or disable the collection of packet statistics from the firmware + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to enable or disable the collection of packet + * statistics from the firmware + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_wifi_logger_start(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +const struct nla_policy qca_wlan_vendor_wifi_logger_get_ring_data_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID] + = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Flush per packet stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to flush or retrieve the per packet statistics from + * the driver + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + QDF_STATUS status; + uint32_t ring_id; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb + [QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1]; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX, + data, data_len, + qca_wlan_vendor_wifi_logger_get_ring_data_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + /* Parse and fetch ring id */ + if (!tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]) { + hdd_err("attr ATTR failed"); + return -EINVAL; + } + + ring_id = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_ID]); + + if (ring_id == RING_ID_PER_PACKET_STATS) { + wlan_logging_set_per_pkt_stats(); + hdd_debug("Flushing/Retrieving packet stats"); + } else if (ring_id == RING_ID_DRIVER_DEBUG) { + /* + * As part of DRIVER ring ID, flush both driver and fw logs. + * For other Ring ID's driver doesn't have any rings to flush + */ + hdd_debug("Bug report triggered by framework"); + + status = cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_UNUSED, + false, false); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to trigger bug report"); + return -EINVAL; + } + + wlan_set_chipset_stats_bit(); + + status = wlan_logging_wait_for_flush_log_completion(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("wait for flush log timed out"); + return qdf_status_to_os_return(status); + } + } else { + wlan_report_log_completion(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_REASON_CODE_UNUSED, + ring_id); + } + return 0; +} + +/** + * wlan_hdd_cfg80211_wifi_logger_get_ring_data() - Wrapper to flush packet stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to flush or retrieve the per packet statistics from + * the driver + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_wifi_logger_get_ring_data(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_wifi_logger_get_ring_data(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_map_req_id_to_pattern_id() - map request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * if the slot is available, store the request id and return pattern id + * if entry exists, return the pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_map_req_id_to_pattern_id(struct hdd_context *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + if (hdd_ctx->op_ctx.op_table[i].request_id == MAX_REQUEST_ID) { + hdd_ctx->op_ctx.op_table[i].request_id = request_id; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } else if (hdd_ctx->op_ctx.op_table[i].request_id == + request_id) { + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -ENOBUFS; +} + +/** + * hdd_unmap_req_id_to_pattern_id() - unmap request id to pattern id + * @hdd_ctx: HDD context + * @request_id: [input] request id + * @pattern_id: [output] pattern id + * + * This function loops through request id to pattern id array + * reset request id to 0 (slot available again) and + * return pattern id + * + * Return: 0 on success and errno on failure + */ +static int hdd_unmap_req_id_to_pattern_id(struct hdd_context *hdd_ctx, + uint32_t request_id, + uint8_t *pattern_id) +{ + uint32_t i; + + mutex_lock(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + if (hdd_ctx->op_ctx.op_table[i].request_id == request_id) { + hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID; + *pattern_id = hdd_ctx->op_ctx.op_table[i].pattern_id; + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return 0; + } + } + mutex_unlock(&hdd_ctx->op_ctx.op_lock); + return -EINVAL; +} + + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID +#define PARAM_CONTROL \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL +#define PARAM_IP_PACKET \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA +#define PARAM_SRC_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR +#define PARAM_DST_MAC_ADDR \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR +#define PARAM_PERIOD QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD +#define PARAM_PROTO_TYPE \ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_ETHER_PROTO_TYPE + +const struct nla_policy offloaded_packet_policy[ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SENDING_CONTROL] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_REQUEST_ID] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_IP_PACKET_DATA] = { + .type = NLA_BINARY}, + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_SRC_MAC_ADDR] = { + .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_DST_MAC_ADDR] = { + .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE }, + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_ETHER_PROTO_TYPE] = { + .type = NLA_U16}, +}; + +/** + * wlan_hdd_add_tx_ptrn() - add tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a AddTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_add_tx_ptrn(struct hdd_adapter *adapter, struct hdd_context *hdd_ctx, + struct nlattr **tb) +{ + struct sSirAddPeriodicTxPtrn *add_req; + QDF_STATUS status; + uint32_t request_id, len; + int32_t ret; + uint8_t pattern_id = 0; + struct qdf_mac_addr dst_addr; + uint16_t eth_type = htons(ETH_P_IP); + mac_handle_t mac_handle; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + add_req = qdf_mem_malloc(sizeof(*add_req)); + if (!add_req) + return -ENOMEM; + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + ret = -EINVAL; + goto fail; + } + + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == MAX_REQUEST_ID) { + hdd_err("request_id cannot be MAX"); + ret = -EINVAL; + goto fail; + } + hdd_debug("Request Id: %u", request_id); + + if (!tb[PARAM_PERIOD]) { + hdd_err("attr period failed"); + ret = -EINVAL; + goto fail; + } + + add_req->usPtrnIntervalMs = nla_get_u32(tb[PARAM_PERIOD]); + hdd_debug("Period: %u ms", add_req->usPtrnIntervalMs); + if (add_req->usPtrnIntervalMs == 0) { + hdd_err("Invalid interval zero, return failure"); + ret = -EINVAL; + goto fail; + } + + if (!tb[PARAM_SRC_MAC_ADDR]) { + hdd_err("attr source mac address failed"); + ret = -EINVAL; + goto fail; + } + nla_memcpy(add_req->mac_address.bytes, tb[PARAM_SRC_MAC_ADDR], + QDF_MAC_ADDR_SIZE); + hdd_debug("input src mac address: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_req->mac_address.bytes)); + + if (!qdf_is_macaddr_equal(&add_req->mac_address, + &adapter->mac_addr)) { + hdd_err("input src mac address and connected ap bssid are different"); + ret = -EINVAL; + goto fail; + } + + if (!tb[PARAM_DST_MAC_ADDR]) { + hdd_err("attr dst mac address failed"); + ret = -EINVAL; + goto fail; + } + nla_memcpy(dst_addr.bytes, tb[PARAM_DST_MAC_ADDR], QDF_MAC_ADDR_SIZE); + hdd_debug("input dst mac address: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dst_addr.bytes)); + + if (!tb[PARAM_IP_PACKET]) { + hdd_err("attr ip packet failed"); + ret = -EINVAL; + goto fail; + } + add_req->ucPtrnSize = nla_len(tb[PARAM_IP_PACKET]); + hdd_debug("IP packet len: %u", add_req->ucPtrnSize); + + if (add_req->ucPtrnSize < 0 || + add_req->ucPtrnSize > (PERIODIC_TX_PTRN_MAX_SIZE - + ETH_HLEN)) { + hdd_err("Invalid IP packet len: %d", + add_req->ucPtrnSize); + ret = -EINVAL; + goto fail; + } + + if (!tb[PARAM_PROTO_TYPE]) + eth_type = htons(ETH_P_IP); + else + eth_type = htons(nla_get_u16(tb[PARAM_PROTO_TYPE])); + + hdd_debug("packet proto type: %u", eth_type); + + len = 0; + qdf_mem_copy(&add_req->ucPattern[0], dst_addr.bytes, QDF_MAC_ADDR_SIZE); + len += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(&add_req->ucPattern[len], add_req->mac_address.bytes, + QDF_MAC_ADDR_SIZE); + len += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(&add_req->ucPattern[len], ð_type, 2); + len += 2; + + /* + * This is the IP packet, add 14 bytes Ethernet (802.3) header + * ------------------------------------------------------------ + * | 14 bytes Ethernet (802.3) header | IP header and payload | + * ------------------------------------------------------------ + */ + qdf_mem_copy(&add_req->ucPattern[len], + nla_data(tb[PARAM_IP_PACKET]), + add_req->ucPtrnSize); + add_req->ucPtrnSize += len; + + ret = hdd_map_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) { + hdd_err("req id to pattern id failed (ret=%d)", ret); + goto fail; + } + add_req->ucPtrnId = pattern_id; + hdd_debug("pattern id: %d", add_req->ucPtrnId); + + mac_handle = hdd_ctx->mac_handle; + status = sme_add_periodic_tx_ptrn(mac_handle, add_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_add_periodic_tx_ptrn failed (err=%d)", status); + ret = qdf_status_to_os_return(status); + goto fail; + } + + hdd_exit(); + +fail: + qdf_mem_free(add_req); + return ret; +} + +/** + * wlan_hdd_del_tx_ptrn() - delete tx pattern + * @adapter: adapter pointer + * @hdd_ctx: hdd context + * @tb: nl attributes + * + * This function reads the NL attributes and forms a DelTxPtrn message + * posts it to SME. + * + */ +static int +wlan_hdd_del_tx_ptrn(struct hdd_adapter *adapter, struct hdd_context *hdd_ctx, + struct nlattr **tb) +{ + struct sSirDelPeriodicTxPtrn *del_req; + QDF_STATUS status; + uint32_t request_id, ret; + uint8_t pattern_id = 0; + mac_handle_t mac_handle; + + /* Parse and fetch request Id */ + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + if (request_id == MAX_REQUEST_ID) { + hdd_err("request_id cannot be MAX"); + return -EINVAL; + } + + ret = hdd_unmap_req_id_to_pattern_id(hdd_ctx, request_id, &pattern_id); + if (ret) { + hdd_err("req id to pattern id failed (ret=%d)", ret); + return -EINVAL; + } + + del_req = qdf_mem_malloc(sizeof(*del_req)); + if (!del_req) + return -ENOMEM; + + qdf_copy_macaddr(&del_req->mac_address, &adapter->mac_addr); + hdd_debug(QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(del_req->mac_address.bytes)); + del_req->ucPtrnId = pattern_id; + hdd_debug("Request Id: %u Pattern id: %d", + request_id, del_req->ucPtrnId); + + mac_handle = hdd_ctx->mac_handle; + status = sme_del_periodic_tx_ptrn(mac_handle, del_req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_del_periodic_tx_ptrn failed (err=%d)", status); + goto fail; + } + + hdd_exit(); + qdf_mem_free(del_req); + return 0; + +fail: + qdf_mem_free(del_req); + return -EINVAL; +} + + +/** + * __wlan_hdd_cfg80211_offloaded_packets() - send offloaded packets + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + uint8_t control; + int ret; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) { + hdd_err("Periodic Tx Pattern Offload feature is not supported in FW!"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, + offloaded_packet_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hdd_err("attr control failed"); + return -EINVAL; + } + control = nla_get_u32(tb[PARAM_CONTROL]); + hdd_debug("Control: %d", control); + + if (control == WLAN_START_OFFLOADED_PACKETS) + return wlan_hdd_add_tx_ptrn(adapter, hdd_ctx, tb); + if (control == WLAN_STOP_OFFLOADED_PACKETS) + return wlan_hdd_del_tx_ptrn(adapter, hdd_ctx, tb); + + hdd_err("Invalid control: %d", control); + return -EINVAL; +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_offloaded_packets() + */ +#undef PARAM_MAX +#undef PARAM_REQUEST_ID +#undef PARAM_CONTROL +#undef PARAM_IP_PACKET +#undef PARAM_SRC_MAC_ADDR +#undef PARAM_DST_MAC_ADDR +#undef PARAM_PERIOD +#undef PARAM_PROTO_TYPE + +/** + * wlan_hdd_cfg80211_offloaded_packets() - Wrapper to offload packets + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_offloaded_packets(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_offloaded_packets(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#ifdef WLAN_NS_OFFLOAD +const struct nla_policy ns_offload_set_policy[ + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG] = {.type = NLA_U8}, +}; + +/** + * __wlan_hdd_cfg80211_set_ns_offload() - enable/disable NS offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_set_ns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int status; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX + 1]; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (!ucfg_pmo_is_ns_offloaded(hdd_ctx->psoc)) { + hdd_err("ND Offload not supported"); + return -EINVAL; + } + + if (!ucfg_pmo_is_active_mode_offloaded(hdd_ctx->psoc)) { + hdd_warn("Active mode offload is disabled"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX, + (struct nlattr *)data, data_len, + ns_offload_set_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG]) { + hdd_err("ND Offload flag attribute not present"); + return -EINVAL; + } + + hdd_ctx->ns_offload_enable = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_FLAG]); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + /* update ns offload in case it is already enabled/disabled */ + if (hdd_ctx->ns_offload_enable) + hdd_enable_ns_offload(adapter, vdev, + pmo_ns_offload_dynamic_update); + else + hdd_disable_ns_offload(adapter, vdev, + pmo_ns_offload_dynamic_update); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_ns_offload() - enable/disable NS offload + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int wlan_hdd_cfg80211_set_ns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_ns_offload(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif /* WLAN_NS_OFFLOAD */ + +/** + * struct weighed_pcl: Preferred channel info + * @freq: Channel frequency + * @weight: Weightage of the channel + * @flag: Validity of the channel in p2p negotiation + */ +struct weighed_pcl { + u32 freq; + u32 weight; + u32 flag; +}; + +const struct nla_policy get_preferred_freq_list_policy[ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE] = { + .type = NLA_U32}, +}; + +static uint32_t wlan_hdd_populate_weigh_pcl( + struct wlan_objmgr_psoc *psoc, + struct policy_mgr_pcl_chan_weights * + chan_weights, + struct weighed_pcl *w_pcl, + enum policy_mgr_con_mode intf_mode) +{ + u32 i, j, valid_weight; + u32 chan_idx = 0; + u32 pcl_len = chan_weights->pcl_len; + u32 conn_count = policy_mgr_get_connection_count(psoc); + + /* convert channel number to frequency */ + for (i = 0; i < chan_weights->pcl_len; i++) { + w_pcl[i].freq = chan_weights->pcl_list[i]; + w_pcl[i].weight = chan_weights->weight_list[i]; + + if (policy_mgr_is_beaconing_mode(intf_mode)) + w_pcl[i].flag = PCL_CHANNEL_SUPPORT_GO; + else + w_pcl[i].flag = PCL_CHANNEL_SUPPORT_CLI; + } + chan_idx = pcl_len; + if (!conn_count || policy_mgr_is_hw_dbs_capable(psoc) || + policy_mgr_is_interband_mcc_supported(psoc)) { + if (pcl_len && chan_weights->weight_list[pcl_len - 1] > + PCL_GROUPS_WEIGHT_DIFFERENCE) + /* + * Set non-pcl channels weight 20 point less than the + * last PCL entry + */ + valid_weight = chan_weights->weight_list[pcl_len - 1] - + PCL_GROUPS_WEIGHT_DIFFERENCE; + else + valid_weight = 1; + + /* Include rest of the valid channels */ + for (i = 0; i < chan_weights->saved_num_chan; i++) { + for (j = 0; j < chan_weights->pcl_len; j++) { + if (chan_weights->saved_chan_list[i] == + chan_weights->pcl_list[j]) + break; + } + if (j == chan_weights->pcl_len) { + w_pcl[chan_idx].freq = + chan_weights->saved_chan_list[i]; + + if (!chan_weights->weighed_valid_list[i]) { + w_pcl[chan_idx].flag = + PCL_CHANNEL_EXCLUDE_IN_GO_NEG; + w_pcl[chan_idx].weight = 0; + } else { + if (policy_mgr_is_beaconing_mode( + intf_mode)) + w_pcl[chan_idx].flag = + PCL_CHANNEL_SUPPORT_GO; + else + w_pcl[chan_idx].flag = + PCL_CHANNEL_SUPPORT_CLI; + w_pcl[chan_idx].weight = valid_weight; + } + chan_idx++; + } + } + } + return chan_idx; +} + +/** __wlan_hdd_cfg80211_get_preferred_freq_list() - get preferred frequency list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function return the preferred frequency list generated by the policy + * manager. + * + * Return: success or failure code + */ +static int __wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int i, ret = 0; + QDF_STATUS status; + uint32_t pcl_len = 0; + uint32_t pcl_len_legacy = 0; + uint32_t freq_list[NUM_CHANNELS]; + uint32_t freq_list_legacy[NUM_CHANNELS]; + enum policy_mgr_con_mode intf_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1]; + struct sk_buff *reply_skb; + struct weighed_pcl *w_pcl; + struct nlattr *nla_attr, *channel; + struct policy_mgr_pcl_chan_weights *chan_weights; + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX, + data, data_len, + get_preferred_freq_list_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]) { + hdd_err("attr interface type failed"); + return -EINVAL; + } + + intf_mode = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE]); + + if (intf_mode < PM_STA_MODE || intf_mode >= PM_MAX_NUM_OF_MODE) { + hdd_err("Invalid interface type"); + return -EINVAL; + } + + hdd_debug("Userspace requested pref freq list"); + + chan_weights = + qdf_mem_malloc(sizeof(struct policy_mgr_pcl_chan_weights)); + if (!chan_weights) + return -ENOMEM; + + status = policy_mgr_get_pcl( + hdd_ctx->psoc, intf_mode, chan_weights->pcl_list, + &chan_weights->pcl_len, chan_weights->weight_list, + QDF_ARRAY_SIZE(chan_weights->weight_list), + adapter->deflink->vdev_id); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Get pcl failed"); + qdf_mem_free(chan_weights); + return -EINVAL; + } + /* + * save the pcl in freq_list_legacy to be sent up with + * QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST. + * freq_list will carry the extended pcl in + * QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL. + */ + pcl_len_legacy = chan_weights->pcl_len; + for (i = 0; i < pcl_len_legacy; i++) + freq_list_legacy[i] = chan_weights->pcl_list[i]; + chan_weights->saved_num_chan = NUM_CHANNELS; + ucfg_mlme_get_valid_channels(hdd_ctx->psoc, + chan_weights->saved_chan_list, + &chan_weights->saved_num_chan); + policy_mgr_get_valid_chan_weights(hdd_ctx->psoc, chan_weights, + intf_mode, + adapter->deflink->vdev); + w_pcl = qdf_mem_malloc(sizeof(struct weighed_pcl) * NUM_CHANNELS); + if (!w_pcl) { + qdf_mem_free(chan_weights); + return -ENOMEM; + } + pcl_len = wlan_hdd_populate_weigh_pcl(hdd_ctx->psoc, chan_weights, + w_pcl, intf_mode); + qdf_mem_free(chan_weights); + + for (i = 0; i < pcl_len; i++) + freq_list[i] = w_pcl[i].freq; + + /* send the freq_list back to supplicant */ + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, + (sizeof(u32) + NLA_HDRLEN) + + (sizeof(u32) * pcl_len_legacy + NLA_HDRLEN) + + NLA_HDRLEN + + (NLA_HDRLEN * 4 + sizeof(u32) * 3) * pcl_len + + NLMSG_HDRLEN); + + if (!reply_skb) { + hdd_err("Allocate reply_skb failed"); + qdf_mem_free(w_pcl); + return -EINVAL; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_IFACE_TYPE, + intf_mode) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST, + sizeof(uint32_t) * pcl_len_legacy, + freq_list_legacy)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + qdf_mem_free(w_pcl); + return -EINVAL; + } + + i = QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_WEIGHED_PCL; + nla_attr = nla_nest_start(reply_skb, i); + + if (!nla_attr) { + hdd_err("nla nest start fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + qdf_mem_free(w_pcl); + return -EINVAL; + } + + for (i = 0; i < pcl_len; i++) { + channel = nla_nest_start(reply_skb, i); + if (!channel) { + hdd_err("updating pcl list failed"); + wlan_cfg80211_vendor_free_skb(reply_skb); + qdf_mem_free(w_pcl); + return -EINVAL; + } + if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_PCL_FREQ, + w_pcl[i].freq) || + nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_PCL_WEIGHT, + w_pcl[i].weight) || + nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_PCL_FLAG, + w_pcl[i].flag)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + qdf_mem_free(w_pcl); + return -EINVAL; + } + nla_nest_end(reply_skb, channel); + } + nla_nest_end(reply_skb, nla_attr); + qdf_mem_free(w_pcl); + + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +/** wlan_hdd_cfg80211_get_preferred_freq_list () - get preferred frequency list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function return the preferred frequency list generated by the policy + * manager. + * + * Return: success or failure code + */ +static int wlan_hdd_cfg80211_get_preferred_freq_list(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_preferred_freq_list(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +const struct nla_policy set_probable_oper_channel_policy[ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ] = { + .type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + enum policy_mgr_con_mode intf_mode; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX + 1]; + uint32_t ch_freq, conc_ext_flags; + + hdd_enter_dev(ndev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX, + data, data_len, + set_probable_oper_channel_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]) { + hdd_err("attr interface type failed"); + return -EINVAL; + } + + intf_mode = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_IFACE_TYPE]); + + if (intf_mode < PM_STA_MODE || intf_mode >= PM_MAX_NUM_OF_MODE) { + hdd_err("Invalid interface type"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ]) { + hdd_err("attr probable freq failed"); + return -EINVAL; + } + + ch_freq = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_FREQ]); + conc_ext_flags = policy_mgr_get_conc_ext_flags(adapter->deflink->vdev, + false); + + /* check pcl table */ + if (!policy_mgr_allow_concurrency(hdd_ctx->psoc, intf_mode, + ch_freq, HW_MODE_20_MHZ, + conc_ext_flags, + adapter->deflink->vdev_id)) { + hdd_err("Set channel hint failed due to concurrency check"); + return -EINVAL; + } + + if (QDF_P2P_GO_MODE != adapter->device_mode) + wlan_hdd_cleanup_remain_on_channel_ctx(adapter->deflink); + + if (wlan_hdd_change_hw_mode_for_given_chnl(adapter, ch_freq, + POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN)) { + hdd_err("Failed to change hw mode"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_probable_oper_channel () - set probable channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_probable_oper_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_probable_oper_channel(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static const struct +nla_policy +wlan_hdd_get_link_properties_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = { + .type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE }, +}; + +/** + * __wlan_hdd_cfg80211_get_link_properties() - Get link properties + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to get link properties like nss, rate flags and + * operating frequency for the active connection with the given peer. + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_ap_ctx *ap_ctx; + struct hdd_station_info *sta_info; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX+1]; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + struct sk_buff *reply_skb; + uint32_t rate_flags = 0; + uint8_t nss; + uint8_t final_rate_flags = 0; + uint32_t freq; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, data, + data_len, + wlan_hdd_get_link_properties_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) { + hdd_err("Attribute peerMac not provided for mode=%d", + adapter->device_mode); + return -EINVAL; + } + + if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) < QDF_MAC_ADDR_SIZE) { + hdd_err("Attribute peerMac is invalid for mode=%d", + adapter->device_mode); + return -EINVAL; + } + + qdf_mem_copy(peer_mac, nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + hdd_debug("peerMac="QDF_MAC_ADDR_FMT" for device_mode:%d", + QDF_MAC_ADDR_REF(peer_mac), adapter->device_mode); + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink) || + qdf_mem_cmp(hdd_sta_ctx->conn_info.bssid.bytes, + peer_mac, QDF_MAC_ADDR_SIZE)) { + hdd_err("Not Associated to mac "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return -EINVAL; + } + + nss = hdd_sta_ctx->conn_info.nss; + freq = hdd_sta_ctx->conn_info.chan_freq; + rate_flags = hdd_sta_ctx->conn_info.rate_flags; + } else if (adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_SAP_MODE) { + + if (QDF_IS_ADDR_BROADCAST(peer_mac)) { + hdd_err("Ignore bcast/self sta"); + return -EINVAL; + } + + sta_info = hdd_get_sta_info_by_mac( + &adapter->sta_info_list, peer_mac, + STA_INFO_CFG80211_GET_LINK_PROPERTIES); + + if (!sta_info) { + hdd_err("No active peer with mac = " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return -EINVAL; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + nss = sta_info->nss; + freq = ap_ctx->operating_chan_freq; + rate_flags = sta_info->rate_flags; + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_CFG80211_GET_LINK_PROPERTIES); + } else { + hdd_err("Not Associated! with mac "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return -EINVAL; + } + + if (!(rate_flags & TX_RATE_LEGACY)) { + if (rate_flags & TX_RATE_VHT80) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + final_rate_flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; +#endif + } else if (rate_flags & TX_RATE_VHT40) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + final_rate_flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } else if (rate_flags & TX_RATE_VHT20) { + final_rate_flags |= RATE_INFO_FLAGS_VHT_MCS; + } else if (rate_flags & + (TX_RATE_HT20 | TX_RATE_HT40)) { + final_rate_flags |= RATE_INFO_FLAGS_MCS; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + if (rate_flags & TX_RATE_HT40) + final_rate_flags |= + RATE_INFO_FLAGS_40_MHZ_WIDTH; +#endif + } + + if (rate_flags & TX_RATE_SGI) { + if (!(final_rate_flags & RATE_INFO_FLAGS_VHT_MCS)) + final_rate_flags |= RATE_INFO_FLAGS_MCS; + final_rate_flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u8) + + sizeof(u8) + + sizeof(u32) + + NLMSG_HDRLEN); + if (!reply_skb) { + hdd_err("getLinkProperties: skb alloc failed"); + return -EINVAL; + } + + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_NSS, + nss) || + nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_RATE_FLAGS, + final_rate_flags) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_FREQ, + freq)) { + hdd_err("nla_put failed"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * wlan_hdd_cfg80211_get_link_properties() - Wrapper function to get link + * properties. + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function is used to get link properties like nss, rate flags and + * operating frequency for the active connection with the given peer. + * + * Return: 0 on success and errno on failure + */ +static int wlan_hdd_cfg80211_get_link_properties(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_link_properties(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +const struct nla_policy +wlan_hdd_sap_config_policy[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST] = { + .type = NLA_BINARY}, +}; + +const struct nla_policy +wlan_hdd_set_acs_dfs_config_policy[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_acs_dfs_mode() - set ACS DFS mode and channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function parses the incoming NL vendor command data attributes and + * updates the SAP context about channel_hint and DFS mode. + * If channel_hint is set, SAP will choose that channel + * as operating channel. + * + * If DFS mode is enabled, driver will include DFS channels + * in ACS else driver will skip DFS channels. + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_acs_dfs_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX + 1]; + int ret; + struct acs_dfs_policy *acs_policy; + int mode = DFS_MODE_NONE; + uint32_t freq_hint = 0; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX, + data, data_len, + wlan_hdd_set_acs_dfs_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + acs_policy = &hdd_ctx->acs_policy; + /* + * SCM sends this attribute to restrict SAP from choosing + * DFS channels from ACS. + */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE]) + mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_DFS_MODE]); + + if (!IS_DFS_MODE_VALID(mode)) { + hdd_err("attr acs dfs mode is not valid"); + return -EINVAL; + } + acs_policy->acs_dfs_mode = mode; + + /* + * SCM sends this attribute to provide an active channel, + * to skip redundant ACS between drivers, and save driver start up time + */ + if (tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT]) { + freq_hint = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ACS_FREQUENCY_HINT]); + } else if (tb[QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT]) { + uint32_t channel_hint = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_HINT]); + + freq_hint = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, + channel_hint); + } + + if (freq_hint && !WLAN_REG_IS_24GHZ_CH_FREQ(freq_hint) && + !WLAN_REG_IS_5GHZ_CH_FREQ(freq_hint) && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(freq_hint)) { + hdd_err("acs channel frequency is not valid"); + return -EINVAL; + } + + acs_policy->acs_chan_freq = freq_hint; + + return 0; +} + +/** + * wlan_hdd_cfg80211_acs_dfs_mode() - Wrapper to set ACS DFS mode + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * This function parses the incoming NL vendor command data attributes and + * updates the SAP context about channel_hint and DFS mode. + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_acs_dfs_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_acs_dfs_mode(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_get_sta_roam_dfs_mode() - get sta roam dfs mode policy + * @mode : cfg80211 dfs mode + * + * Return: return csr sta roam dfs mode else return NONE + */ +static enum sta_roam_policy_dfs_mode wlan_hdd_get_sta_roam_dfs_mode( + enum dfs_mode mode) +{ + switch (mode) { + case DFS_MODE_ENABLE: + return STA_ROAM_POLICY_DFS_ENABLED; + case DFS_MODE_DISABLE: + return STA_ROAM_POLICY_DFS_DISABLED; + case DFS_MODE_DEPRIORITIZE: + return STA_ROAM_POLICY_DFS_DEPRIORITIZE; + default: + hdd_err("STA Roam policy dfs mode is NONE"); + return STA_ROAM_POLICY_NONE; + } +} + +uint8_t +hdd_get_sap_operating_band_by_link_info(struct wlan_hdd_link_info *link_info) +{ + uint32_t operating_chan_freq; + uint8_t sap_operating_band = 0; + struct hdd_ap_ctx *ap_ctx; + enum QDF_OPMODE opmode = link_info->adapter->device_mode; + + if (opmode != QDF_SAP_MODE && opmode != QDF_P2P_GO_MODE) + return BAND_UNKNOWN; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + operating_chan_freq = ap_ctx->operating_chan_freq; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(operating_chan_freq)) + sap_operating_band = BAND_2G; + else if (WLAN_REG_IS_5GHZ_CH_FREQ(operating_chan_freq) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(operating_chan_freq)) + sap_operating_band = BAND_5G; + else + sap_operating_band = BAND_UNKNOWN; + + return sap_operating_band; +} + +/* + * hdd_get_sap_operating_band: Get current operating channel + * for sap. + * @hdd_ctx: hdd context + * + * Return : Corresponding band for SAP operating channel + */ +uint8_t hdd_get_sap_operating_band(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + uint8_t operating_band = 0; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_SAP_OPERATING_BAND; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + + link_info = adapter->deflink; + operating_band = + hdd_get_sap_operating_band_by_link_info(link_info); + + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return operating_band; +} + +static inline QDF_STATUS +wlan_hdd_config_dp_direct_link_profile(struct hdd_adapter *adapter, + enum host_concurrent_ap_policy ap_policy) +{ + struct wlan_objmgr_vdev *vdev = adapter->deflink->vdev; + enum host_concurrent_ap_policy prev_ap_policy; + + prev_ap_policy = ucfg_mlme_get_ap_policy(vdev); + + hdd_debug("Current AP policy %d prev AP policy %d", ap_policy, + prev_ap_policy); + + switch (prev_ap_policy) { + case HOST_CONCURRENT_AP_POLICY_UNSPECIFIED: + switch (ap_policy) { + case HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: + return ucfg_dp_config_direct_link(adapter->dev, true, + false); + case HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO: + return ucfg_dp_config_direct_link(adapter->dev, true, + true); + default: + break; + } + break; + case HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO: + switch (ap_policy) { + case HOST_CONCURRENT_AP_POLICY_UNSPECIFIED: + case HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: + return ucfg_dp_config_direct_link(adapter->dev, true, + false); + default: + break; + } + break; + case HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING: + switch (ap_policy) { + case HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO: + return ucfg_dp_config_direct_link(adapter->dev, true, + true); + default: + break; + } + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +const struct nla_policy +wlan_hdd_set_sta_roam_config_policy[ +QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_sta_roam_policy() - Set params to restrict scan channels + * for station connection or roaming. + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sta_roam_policy will decide if DFS channels or unsafe + * channels needs to be skipped in scanning or not. + * If dfs_mode is disabled, driver will not scan DFS channels. + * If skip_unsafe_channels is set, driver will skip unsafe channels + * in Scanning. + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_sta_roam_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[ + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX + 1]; + int ret; + enum sta_roam_policy_dfs_mode sta_roam_dfs_mode; + enum dfs_mode mode = DFS_MODE_NONE; + bool skip_unsafe_channels = false; + QDF_STATUS status; + uint8_t sap_operating_band; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX, + data, data_len, + wlan_hdd_set_sta_roam_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + if (tb[QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE]) + mode = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_STA_DFS_MODE]); + if (!IS_DFS_MODE_VALID(mode)) { + hdd_err("attr sta roam dfs mode policy is not valid"); + return -EINVAL; + } + + sta_roam_dfs_mode = wlan_hdd_get_sta_roam_dfs_mode(mode); + + if (tb[QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL]) + skip_unsafe_channels = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_STA_SKIP_UNSAFE_CHANNEL]); + sap_operating_band = hdd_get_sap_operating_band(hdd_ctx); + mac_handle = hdd_ctx->mac_handle; + status = sme_update_sta_roam_policy(mac_handle, sta_roam_dfs_mode, + skip_unsafe_channels, + adapter->deflink->vdev_id, + sap_operating_band); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_update_sta_roam_policy (err=%d)", status); + return -EINVAL; + } + return 0; +} + +/** + * wlan_hdd_cfg80211_sta_roam_policy() - Wrapper to restrict scan channels, + * connection and roaming for station. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sta_roam_policy will decide if DFS channels or unsafe + * channels needs to be skipped in scanning or not. + * If dfs_mode is disabled, driver will not scan DFS channels. + * If skip_unsafe_channels is set, driver will skip unsafe channels + * in Scanning. + * Return: 0 on success; errno on failure + */ +static int +wlan_hdd_cfg80211_sta_roam_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_sta_roam_policy(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +const struct nla_policy +wlan_hdd_set_concurrent_session_policy[ +QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_dual_sta_policy() - Wrapper to configure the concurrent + * session policies + * @hdd_ctx: Pointer to HDD context + * @tb: parsed attribute array + * + * Configure the concurrent session policies when multiple STA ifaces are + * (getting) active. + * Return: 0 on success; errno on failure + */ +static int __wlan_hdd_cfg80211_dual_sta_policy(struct hdd_context *hdd_ctx, + struct nlattr **tb) +{ + QDF_STATUS status; + uint8_t dual_sta_config = + QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED; + + dual_sta_config = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG]); + hdd_debug("Concurrent STA policy : %d", dual_sta_config); + + if (dual_sta_config > QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED) + return -EINVAL; + + status = ucfg_mlme_set_dual_sta_policy(hdd_ctx->psoc, dual_sta_config); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to set MLME dual sta config"); + return -EINVAL; + } + + /* After SSR, the dual sta configuration is lost. As SSR is hidden from + * userland, this command will not come from userspace after a SSR. To + * restore this configuration, save this in hdd context and restore + * after re-init. + */ + hdd_ctx->dual_sta_policy.dual_sta_policy = dual_sta_config; + + return 0; +} + +/** + * __wlan_hdd_cfg80211_ap_policy() - Wrapper to configure the concurrent + * session policies + * @adapter: HDD adapter + * @tb: parsed attribute array + * + * Configure the concurrent session policies when multiple STA ifaces are + * (getting) active. + * Return: 0 on success; errno on failure + */ +static int __wlan_hdd_cfg80211_ap_policy(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + QDF_STATUS status; + uint8_t vdev_id; + int ret; + uint8_t ap_cfg_policy; + uint32_t profile = 0; + enum QDF_OPMODE device_mode; + uint8_t ap_config = + QCA_WLAN_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING; + + vdev_id = wlan_vdev_get_id(adapter->deflink->vdev); + device_mode = hdd_get_device_mode(vdev_id); + if (device_mode != QDF_SAP_MODE) { + hdd_err_rl("command not allowed in %d mode, vdev_id: %d", + device_mode, vdev_id); + return -EINVAL; + } + + ap_config = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG]); + hdd_debug("AP policy : %d", ap_config); + + if (ap_config > QCA_WLAN_CONCURRENT_AP_POLICY_XR) { + hdd_err_rl("Invalid concurrent policy ap config %d", ap_config); + return -EINVAL; + } + + ap_cfg_policy = wlan_mlme_convert_ap_policy_config(ap_config); + if (ap_cfg_policy == HOST_CONCURRENT_AP_POLICY_XR) + profile = AP_PROFILE_XR_ENABLE; + else if (ap_cfg_policy == HOST_CONCURRENT_AP_POLICY_GAMING_AUDIO || + ap_cfg_policy == + HOST_CONCURRENT_AP_POLICY_LOSSLESS_AUDIO_STREAMING) + profile = AP_PROFILE_XPAN_ENABLE; + ret = wma_cli_set_command(vdev_id, wmi_vdev_param_set_profile, + profile, VDEV_CMD); + if (ret) { + hdd_err("Failed to set profile %d", profile); + return -EINVAL; + } + status = wlan_hdd_config_dp_direct_link_profile(adapter, ap_cfg_policy); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to set DP ap config"); + return -EINVAL; + } + status = ucfg_mlme_set_ap_policy(adapter->deflink->vdev, ap_cfg_policy); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to set MLME ap config"); + return -EINVAL; + } + + wlan_mlme_ll_lt_sap_send_oce_flags_fw(adapter->deflink->vdev); + wlan_vdev_mlme_feat_ext_cap_clear(adapter->deflink->vdev, + WLAN_VDEV_FEXT_FILS_DISC_6G_SAP); + return 0; +} + +/** + * __wlan_hdd_cfg80211_concurrent_session_policy() - Wrapper to configure the + * concurrent session policies + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Configure the concurrent session policies when low latency SAP or multiple + * STA ifaces are (getting) active. + * Return: 0 on success; errno on failure + */ +static int __wlan_hdd_cfg80211_concurrent_session_policy( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX + 1]; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err_rl("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hdd_validate_adapter(adapter)) { + hdd_err_rl("Invalid adapter"); + return -EINVAL; + } + + if (wlan_hdd_validate_context(adapter->hdd_ctx)) { + hdd_err_rl("Invalid hdd context"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse( + tb, + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX, + data, data_len, + wlan_hdd_set_concurrent_session_policy)) { + hdd_err_rl("nla_parse failed"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG] && + !tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG]) { + hdd_err_rl("concurrent session policy attr not present"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_STA_CONFIG]) + __wlan_hdd_cfg80211_dual_sta_policy(adapter->hdd_ctx, tb); + + if (tb[QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_AP_CONFIG]) + __wlan_hdd_cfg80211_ap_policy(adapter, tb); + + return 0; +} + +/** + * wlan_hdd_cfg80211_concurrent_session_policy() - Wrapper to configure the + * concurrent session policies + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Configure the concurrent session policies when multiple STA ifaces are + * (getting) active. + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_concurrent_session_policy( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_concurrent_session_policy( + wiphy, wdev, data, + data_len); + + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * __wlan_hdd_cfg80211_avoid_freq() - ask driver to restart SAP if SAP + * is on unsafe channel. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * wlan_hdd_cfg80211_avoid_freq do restart the sap if sap is already + * on any of unsafe channels. + * If sap is on any of unsafe channel, hdd_unsafe_channel_restart_sap + * will send WLAN_SVC_LTE_COEX_IND indication to userspace to restart. + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct ch_avoid_ind_type *channel_list; + struct ch_avoid_ind_type avoid_freq_list; + enum QDF_GLOBAL_MODE curr_mode; + uint8_t num_args = 0; + + hdd_enter_dev(wdev->netdev); + + if (!qdf_ctx) + return -EINVAL; + + curr_mode = hdd_get_conparam(); + if (QDF_GLOBAL_FTM_MODE == curr_mode || + QDF_GLOBAL_MONITOR_MODE == curr_mode) { + hdd_err("Command not allowed in FTM/MONITOR mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + qdf_mem_zero(&avoid_freq_list, sizeof(struct ch_avoid_ind_type)); + + if (!data && data_len == 0) { + hdd_debug("Clear avoid frequency list"); + goto process_unsafe_channel; + } + if (!data || data_len < (sizeof(channel_list->ch_avoid_range_cnt) + + sizeof(struct ch_avoid_freq_type))) { + hdd_err("Avoid frequency channel list empty"); + return -EINVAL; + } + num_args = (data_len - sizeof(channel_list->ch_avoid_range_cnt)) / + sizeof(channel_list->avoid_freq_range[0].start_freq); + + + if (num_args < 2 || num_args > CH_AVOID_MAX_RANGE * 2 || + num_args % 2 != 0) { + hdd_err("Invalid avoid frequency channel list"); + return -EINVAL; + } + + channel_list = (struct ch_avoid_ind_type *)data; + if (channel_list->ch_avoid_range_cnt == 0 || + channel_list->ch_avoid_range_cnt > CH_AVOID_MAX_RANGE || + 2 * channel_list->ch_avoid_range_cnt != num_args) { + hdd_err("Invalid frequency range count %d", + channel_list->ch_avoid_range_cnt); + return -EINVAL; + } + + qdf_mem_copy(&avoid_freq_list, channel_list, data_len); + +process_unsafe_channel: + ucfg_reg_ch_avoid(hdd_ctx->psoc, &avoid_freq_list); + + return 0; +} + +/** + * wlan_hdd_cfg80211_avoid_freq() - ask driver to restart SAP if SAP + * is on unsafe channel. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * wlan_hdd_cfg80211_avoid_freq do restart the sap if sap is already + * on any of unsafe channels. + * If sap is on any of unsafe channel, hdd_unsafe_channel_restart_sap + * will send WLAN_SVC_LTE_COEX_IND indication to userspace to restart. + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_avoid_freq(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_avoid_freq(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#endif +/** + * __wlan_hdd_cfg80211_sap_configuration_set() - ask driver to restart SAP if + * SAP is on unsafe channel. + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sap_configuration_set function set SAP params to + * driver. + * QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHAN will set sap config channel and + * will initiate restart of sap. + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_sap_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *hostapd_adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX + 1]; + struct hdd_ap_ctx *ap_ctx; + int ret; + uint32_t chan_freq = 0; + bool chan_freq_present = false; + QDF_STATUS status; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + link_info = hostapd_adapter->deflink; + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX, + data, data_len, + wlan_hdd_sap_config_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY]) { + chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_FREQUENCY]); + chan_freq_present = true; + } else if (tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL]) { + uint32_t config_channel = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHANNEL]); + + chan_freq = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, + config_channel); + chan_freq_present = true; + } + + if (chan_freq_present) { + if (!test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + hdd_err("SAP is not started yet. Restart sap will be invalid"); + return -EINVAL; + } + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq) && + !WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq) && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) { + hdd_err("Channel frequency %u is invalid to restart SAP", + chan_freq); + return -ENOTSUPP; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + ap_ctx->sap_config.chan_freq = chan_freq; + ap_ctx->sap_config.ch_params.ch_width = + ap_ctx->sap_config.ch_width_orig; + ap_ctx->bss_stop_reason = BSS_STOP_DUE_TO_VENDOR_CONFIG_CHAN; + + if (sap_phymode_is_eht(ap_ctx->sap_config.SapHw_mode)) + wlan_reg_set_create_punc_bitmap( + &ap_ctx->sap_config.ch_params, true); + wlan_reg_set_channel_params_for_pwrmode( + hdd_ctx->pdev, chan_freq, + ap_ctx->sap_config.sec_ch_freq, + &ap_ctx->sap_config.ch_params, + REG_CURRENT_PWR_MODE); + + hdd_restart_sap(link_info); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST]) { + uint32_t freq_len, i; + uint32_t *freq; + + hdd_debug("setting mandatory freq/chan list"); + + freq_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST])/ + sizeof(uint32_t); + + if (freq_len > NUM_CHANNELS) { + hdd_err("insufficient space to hold channels"); + return -ENOMEM; + } + + freq = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_SAP_MANDATORY_FREQUENCY_LIST]); + + hdd_debug("freq_len=%d", freq_len); + + for (i = 0; i < freq_len; i++) { + hdd_debug("freq[%d]=%d", i, freq[i]); + } + + status = policy_mgr_set_sap_mandatory_channels( + hdd_ctx->psoc, freq, freq_len); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_sap_configuration_set() - sap configuration vendor command + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * __wlan_hdd_cfg80211_sap_configuration_set function set SAP params to + * driver. + * QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_CHAN will set sap config channel and + * will initiate restart of sap. + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_sap_configuration_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_sap_configuration_set(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_process_wake_lock_stats() - wrapper function to absract cp_stats + * or legacy get_wake_lock_stats API. + * @hdd_ctx: pointer to hdd_ctx + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_process_wake_lock_stats(struct hdd_context *hdd_ctx) +{ + return wlan_cfg80211_mc_cp_stats_get_wakelock_stats(hdd_ctx->psoc, + hdd_ctx->wiphy); +} + +/** + * __wlan_hdd_cfg80211_get_wakelock_stats() - gets wake lock stats + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * WMA copies required data and invokes callback + * wlan_hdd_cfg80211_wakelock_stats_rsp_callback to send wake lock stats. + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_get_wakelock_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + ret = wlan_hdd_process_wake_lock_stats(hdd_ctx); + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_cfg80211_get_wakelock_stats() - gets wake lock stats + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * WMA copies required data and invokes callback + * wlan_hdd_cfg80211_wakelock_stats_rsp_callback to send wake lock stats. + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_get_wakelock_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_wakelock_stats(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_get_bus_size() - Get WMI Bus size + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * This function reads wmi max bus size and fill in the skb with + * NL attributes and send up the NL event. + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_get_bus_size(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret_val; + struct sk_buff *skb; + uint32_t nl_buf_len; + + hdd_enter(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + hdd_debug("WMI Max Bus size: %d", hdd_ctx->wmi_max_len); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(hdd_ctx->wmi_max_len) + NLA_HDRLEN); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE, + hdd_ctx->wmi_max_len)) { + hdd_err("nla put failure"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + + hdd_exit(); + + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_get_bus_size() - SSR Wrapper to Get Bus size + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_get_bus_size(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_bus_size(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_get_radio_combination_matrix() - get radio matrix info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_get_radio_combination_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *reply_skb; + int ret; + int skb_len; + struct nlattr *combination, *combination_cfg, *radio, *radio_comb; + uint32_t comb_num = 0; + struct radio_combination comb[MAX_RADIO_COMBINATION]; + int comb_idx, radio_idx; + enum qca_set_band qca_band; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + ucfg_policy_mgr_get_radio_combinations(hdd_ctx->psoc, comb, + QDF_ARRAY_SIZE(comb), + &comb_num); + if (!comb_num) { + hdd_err("invalid combination 0"); + return -EINVAL; + } + + /* band and antenna */ + skb_len = nla_total_size(sizeof(uint32_t)) + + nla_total_size(sizeof(uint8_t)); + /* radio nested for max 2 MACs*/ + skb_len = nla_total_size(skb_len) * MAX_MAC; + /* one radio combination */ + skb_len = nla_total_size(nla_total_size(skb_len)); + /* total combinations */ + skb_len = nla_total_size(comb_num * nla_total_size(skb_len)); + skb_len = NLMSG_HDRLEN + skb_len; + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + if (!reply_skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed, len %d", + skb_len); + return -EINVAL; + } + + combination_cfg = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_RADIO_MATRIX_SUPPORTED_CFGS); + if (!combination_cfg) { + ret = -ENOMEM; + goto err; + } + for (comb_idx = 0; comb_idx < comb_num; comb_idx++) { + combination = nla_nest_start(reply_skb, comb_idx); + if (!combination) { + ret = -ENOMEM; + goto err; + } + radio_comb = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_RADIO_COMBINATIONS_CFGS); + if (!radio_comb) { + ret = -ENOMEM; + goto err; + } + for (radio_idx = 0; radio_idx < MAX_MAC; radio_idx++) { + if (!comb[comb_idx].band_mask[radio_idx]) + break; + radio = nla_nest_start(reply_skb, radio_idx); + if (!radio) { + ret = -ENOMEM; + goto err; + } + if (comb[comb_idx].band_mask[radio_idx] == + BIT(REG_BAND_5G)) { + qca_band = QCA_SETBAND_5G; + } else if (comb[comb_idx].band_mask[radio_idx] == + BIT(REG_BAND_6G)) { + qca_band = QCA_SETBAND_6G; + } else if (comb[comb_idx].band_mask[radio_idx] == + BIT(REG_BAND_2G)) { + qca_band = QCA_SETBAND_2G; + } else { + hdd_err("invalid band mask 0 for comb %d radio %d", + comb_idx, radio_idx); + ret = -EINVAL; + goto err; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_BAND, + qca_band)) { + ret = -ENOMEM; + goto err; + } + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_SUPPORTED_RADIO_CFG_ANTENNA, + comb[comb_idx].antenna[radio_idx])) { + ret = -ENOMEM; + goto err; + } + hdd_debug("comb[%d]:cfg[%d]: band %d, antenna %d", + comb_idx, radio_idx, qca_band, + comb[comb_idx].antenna[radio_idx]); + nla_nest_end(reply_skb, radio); + } + nla_nest_end(reply_skb, radio_comb); + nla_nest_end(reply_skb, combination); + } + nla_nest_end(reply_skb, combination_cfg); + return wlan_cfg80211_vendor_cmd_reply(reply_skb); + +err: + wlan_cfg80211_vendor_free_skb(reply_skb); + return ret; +} + +/** + * wlan_hdd_cfg80211_get_radio_combination_matrix() - get radio matrix info + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +wlan_hdd_cfg80211_get_radio_combination_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_radio_combination_matrix(wiphy, wdev, + data, + data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +const struct nla_policy setband_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SETBAND_MASK] = {.type = NLA_U32}, +}; + +/** + *__wlan_hdd_cfg80211_setband() - set band + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_setband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + int ret; + uint32_t reg_wifi_band_bitmap = 0, band_val, band_mask; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, + data, data_len, setband_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SETBAND_MASK]) { + band_mask = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_MASK]); + reg_wifi_band_bitmap = + wlan_vendor_bitmap_to_reg_wifi_band_bitmap(hdd_ctx->psoc, + band_mask); + hdd_debug("[SET BAND] set band mask:%d", reg_wifi_band_bitmap); + } else if (tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]) { + band_val = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SETBAND_VALUE]); + reg_wifi_band_bitmap = + hdd_reg_legacy_setband_to_reg_wifi_band_bitmap( + band_val); + } + + if (!reg_wifi_band_bitmap) { + hdd_err("attr SETBAND_VALUE failed"); + return -EINVAL; + } + + ret = hdd_reg_set_band(dev, reg_wifi_band_bitmap); + + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_validate_acs_channel() - validate channel frequency provided by ACS + * @link_info: Pointer to link_info in adapter + * @chan_freq: channel frequency in MHz + * @chan_bw: channel bandiodth in MHz + * + * return: QDF status based on success or failure + */ +static QDF_STATUS +wlan_hdd_validate_acs_channel(struct wlan_hdd_link_info *link_info, + uint32_t chan_freq, int chan_bw) +{ + struct hdd_context *hdd_ctx; + struct sap_context *sap_context; + + hdd_ctx = link_info->adapter->hdd_ctx; + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(hdd_ctx, chan_freq)) + return QDF_STATUS_E_FAILURE; + + sap_context = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if ((wlansap_is_channel_in_nol_list(sap_context, chan_freq, + PHY_SINGLE_CHANNEL_CENTERED))) { + hdd_info("channel %d is in nol", chan_freq); + return -EINVAL; + } + + if ((wlansap_is_channel_leaking_in_nol(sap_context, + chan_freq, chan_bw))) { + hdd_info("channel freq %d is leaking in nol", chan_freq); + return -EINVAL; + } + + return 0; + +} + +static void hdd_update_acs_sap_config(struct hdd_context *hdd_ctx, + struct sap_config *sap_config, + struct hdd_vendor_chan_info *channel_list) +{ + uint8_t ch_width; + QDF_STATUS status; + uint32_t channel_bonding_mode; + + sap_config->chan_freq = channel_list->pri_chan_freq; + + sap_config->ch_params.center_freq_seg0 = + wlan_reg_freq_to_chan(hdd_ctx->pdev, + channel_list->vht_seg0_center_chan_freq); + sap_config->ch_params.center_freq_seg1 = + wlan_reg_freq_to_chan(hdd_ctx->pdev, + channel_list->vht_seg1_center_chan_freq); + + sap_config->ch_params.sec_ch_offset = + wlan_reg_freq_to_chan(hdd_ctx->pdev, + channel_list->ht_sec_chan_freq); + + sap_config->ch_params.ch_width = + hdd_map_nl_chan_width(channel_list->chan_width); + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sap_config->chan_freq)) { + status = + ucfg_mlme_get_vht_channel_width(hdd_ctx->psoc, + &ch_width); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set channel_width"); + sap_config->ch_width_orig = ch_width; + } else { + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode); + sap_config->ch_width_orig = channel_bonding_mode ? + CH_WIDTH_40MHZ : CH_WIDTH_20MHZ; + } + sap_config->acs_cfg.pri_ch_freq = channel_list->pri_chan_freq; + sap_config->acs_cfg.ch_width = + hdd_map_nl_chan_width(channel_list->chan_width); + sap_config->acs_cfg.vht_seg0_center_ch_freq = + channel_list->vht_seg0_center_chan_freq; + sap_config->acs_cfg.vht_seg1_center_ch_freq = + channel_list->vht_seg1_center_chan_freq; + sap_config->acs_cfg.ht_sec_ch_freq = + channel_list->ht_sec_chan_freq; +} + +static int hdd_update_acs_channel(struct wlan_hdd_link_info *link_info, + uint8_t reason, uint8_t channel_cnt, + struct hdd_vendor_chan_info *channel_list) +{ + struct sap_config *sap_config; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + QDF_STATUS status = QDF_STATUS_SUCCESS; + mac_handle_t mac_handle; + uint32_t ch; + + if (!channel_list) { + hdd_err("channel_list is NULL"); + return -EINVAL; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_config = &link_info->session.ap.sap_config; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ap_ctx->vendor_acs_timer)) { + qdf_mc_timer_stop(&hdd_ap_ctx->vendor_acs_timer); + } + + if (channel_list->pri_chan_freq == 0) { + /* Check mode, set default channel */ + channel_list->pri_chan_freq = 2437; + /* + * sap_select_default_oper_chan(mac_handle, + * sap_config->acs_cfg.hw_mode); + */ + } + + mac_handle = hdd_ctx->mac_handle; + switch (reason) { + /* SAP init case */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_INIT: + hdd_update_acs_sap_config(hdd_ctx, sap_config, channel_list); + /* Update Hostapd */ + wlan_hdd_cfg80211_acs_ch_select_evt(link_info, true); + break; + + /* DFS detected on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS: + ch = wlan_reg_freq_to_chan(hdd_ctx->pdev, + channel_list->pri_chan_freq); + + wlan_sap_update_next_channel( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), (uint8_t)ch, + hdd_map_nl_chan_width(channel_list->chan_width)); + status = sme_update_new_channel_event( + mac_handle, link_info->vdev_id); + break; + + /* LTE coex event on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX: + ch = wlan_reg_freq_to_chan(hdd_ctx->pdev, + channel_list->pri_chan_freq); + sap_config->acs_cfg.pri_ch_freq = channel_list->pri_chan_freq; + sap_config->acs_cfg.ch_width = + hdd_map_nl_chan_width(channel_list->chan_width); + hdd_ap_ctx->sap_config.ch_width_orig = + sap_config->acs_cfg.ch_width; + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + link_info->vdev_id, + CSA_REASON_LTE_COEX); + hdd_switch_sap_channel(link_info, (uint8_t)ch, true); + break; + + default: + hdd_info("invalid reason for timer invoke"); + } + hdd_exit(); + return qdf_status_to_os_return(status); +} + +/* + * Define short name for vendor channel set config + */ +#define SET_CHAN_REASON QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_REASON +#define SET_CHAN_CHAN_LIST QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_LIST +#define SET_CHAN_PRIMARY_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_PRIMARY +#define SET_CHAN_SECONDARY_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_SECONDARY +#define SET_CHAN_SEG0_CENTER_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG0 +#define SET_CHAN_SEG1_CENTER_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_CENTER_SEG1 +#define SET_CHAN_CHANNEL_WIDTH \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_WIDTH + +#define SET_CHAN_FREQ_LIST QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_LIST +#define SET_CHAN_FREQUENCY_PRIMARY \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_PRIMARY +#define SET_CHAN_FREQUENCY_SECONDARY \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_SECONDARY +#define SET_CHAN_SEG0_CENTER_FREQUENCY \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG0 +#define SET_CHAN_SEG1_CENTER_FREQUENCY \ + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_FREQUENCY_CENTER_SEG1 + +#define SET_CHAN_MAX QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX +#define SET_EXT_ACS_BAND QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_BAND + +static const struct nla_policy acs_chan_config_policy[SET_CHAN_MAX + 1] = { + [SET_CHAN_REASON] = {.type = NLA_U8}, + [SET_CHAN_CHAN_LIST] = {.type = NLA_NESTED}, + [SET_CHAN_FREQ_LIST] = {.type = NLA_NESTED}, +}; + +static const struct nla_policy acs_chan_list_policy[SET_CHAN_MAX + 1] = { + [SET_CHAN_PRIMARY_CHANNEL] = {.type = NLA_U8}, + [SET_CHAN_SECONDARY_CHANNEL] = {.type = NLA_U8}, + [SET_CHAN_SEG0_CENTER_CHANNEL] = {.type = NLA_U8}, + [SET_CHAN_SEG1_CENTER_CHANNEL] = {.type = NLA_U8}, + [SET_CHAN_CHANNEL_WIDTH] = {.type = NLA_U8}, + [SET_EXT_ACS_BAND] = {.type = NLA_U8}, + + [SET_CHAN_FREQUENCY_PRIMARY] = {.type = NLA_U32}, + [SET_CHAN_FREQUENCY_SECONDARY] = {.type = NLA_U32}, + [SET_CHAN_SEG0_CENTER_FREQUENCY] = {.type = NLA_U32}, + [SET_CHAN_SEG1_CENTER_FREQUENCY] = {.type = NLA_U32}, +}; + +/** + * hdd_extract_external_acs_frequencies() - API to parse and extract vendor acs + * channel frequency (in MHz) configuration. + * @hdd_ctx: pointer to hdd context + * @list_ptr: pointer to hdd_vendor_chan_info + * @channel_cnt: channel count + * @data: data + * @data_len: data len + * + * Return: 0 on success, negative errno on failure + */ +static int +hdd_extract_external_acs_frequencies(struct hdd_context *hdd_ctx, + struct hdd_vendor_chan_info **list_ptr, + uint8_t *channel_cnt, + const void *data, int data_len) +{ + int rem; + uint32_t i = 0; + struct nlattr *tb[SET_CHAN_MAX + 1]; + struct nlattr *tb2[SET_CHAN_MAX + 1]; + struct nlattr *curr_attr; + struct hdd_vendor_chan_info *channel_list; + + if (wlan_cfg80211_nla_parse(tb, SET_CHAN_MAX, data, data_len, + acs_chan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + nla_for_each_nested(curr_attr, tb[SET_CHAN_FREQ_LIST], rem) + i++; + + if (!i) { + hdd_err_rl("Error: channel count is zero"); + return -EINVAL; + } + + if (i > NUM_CHANNELS) { + hdd_err_rl("Error: Exceeded max channels: %u", NUM_CHANNELS); + return -ENOMEM; + } + + channel_list = qdf_mem_malloc(sizeof(struct hdd_vendor_chan_info) * i); + if (!channel_list) + return -ENOMEM; + + *channel_cnt = (uint8_t)i; + i = 0; + nla_for_each_nested(curr_attr, tb[SET_CHAN_FREQ_LIST], rem) { + if (wlan_cfg80211_nla_parse_nested(tb2, SET_CHAN_MAX, + curr_attr, + acs_chan_list_policy)) { + hdd_err_rl("nla_parse failed"); + qdf_mem_free(channel_list); + *channel_cnt = 0; + return -EINVAL; + } + + if (tb2[SET_EXT_ACS_BAND]) + channel_list[i].band = + nla_get_u8(tb2[SET_EXT_ACS_BAND]); + + if (tb2[SET_CHAN_FREQUENCY_PRIMARY]) + channel_list[i].pri_chan_freq = + nla_get_u32(tb2[SET_CHAN_FREQUENCY_PRIMARY]); + + if (tb2[SET_CHAN_FREQUENCY_SECONDARY]) + channel_list[i].ht_sec_chan_freq = + nla_get_u32(tb2[SET_CHAN_FREQUENCY_SECONDARY]); + + if (tb2[SET_CHAN_SEG0_CENTER_FREQUENCY]) + channel_list[i].vht_seg0_center_chan_freq = + nla_get_u32(tb2[SET_CHAN_SEG0_CENTER_FREQUENCY]); + + if (tb2[SET_CHAN_SEG1_CENTER_FREQUENCY]) + channel_list[i].vht_seg1_center_chan_freq = + nla_get_u32(tb2[SET_CHAN_SEG1_CENTER_FREQUENCY]); + + if (tb2[SET_CHAN_CHANNEL_WIDTH]) + channel_list[i].chan_width = + nla_get_u8(tb2[SET_CHAN_CHANNEL_WIDTH]); + + hdd_debug("index %d, pri_chan_freq %u, ht_sec_chan_freq %u seg0_freq %u seg1_freq %u width %u", + i, channel_list[i].pri_chan_freq, + channel_list[i].ht_sec_chan_freq, + channel_list[i].vht_seg0_center_chan_freq, + channel_list[i].vht_seg1_center_chan_freq, + channel_list[i].chan_width); + i++; + } + *list_ptr = channel_list; + + return 0; +} + +/** + * hdd_extract_external_acs_channels() - API to parse and extract vendor acs + * channel configuration. + * @hdd_ctx: pointer to hdd context + * @list_ptr: pointer to hdd_vendor_chan_info + * @channel_cnt: channel count + * @data: data + * @data_len: data len + * + * Return: 0 on success, negative errno on failure + */ +static int +hdd_extract_external_acs_channels(struct hdd_context *hdd_ctx, + struct hdd_vendor_chan_info **list_ptr, + uint8_t *channel_cnt, + const void *data, int data_len) +{ + int rem; + uint32_t i = 0; + struct nlattr *tb[SET_CHAN_MAX + 1]; + struct nlattr *tb2[SET_CHAN_MAX + 1]; + struct nlattr *curr_attr; + struct hdd_vendor_chan_info *channel_list; + + if (wlan_cfg80211_nla_parse(tb, SET_CHAN_MAX, data, data_len, + acs_chan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + nla_for_each_nested(curr_attr, tb[SET_CHAN_CHAN_LIST], rem) + i++; + + if (!i) { + hdd_err_rl("Error: channel count is zero"); + return -EINVAL; + } + + if (i > NUM_CHANNELS) { + hdd_err_rl("Error: Exceeded max channels: %u", NUM_CHANNELS); + return -ENOMEM; + } + + channel_list = qdf_mem_malloc(sizeof(struct hdd_vendor_chan_info) * i); + if (!channel_list) + return -ENOMEM; + + *channel_cnt = (uint8_t)i; + i = 0; + nla_for_each_nested(curr_attr, tb[SET_CHAN_CHAN_LIST], rem) { + if (wlan_cfg80211_nla_parse_nested(tb2, SET_CHAN_MAX, + curr_attr, + acs_chan_list_policy)) { + hdd_err("nla_parse failed"); + qdf_mem_free(channel_list); + *channel_cnt = 0; + return -EINVAL; + } + + if (tb2[SET_EXT_ACS_BAND]) { + channel_list[i].band = + nla_get_u8(tb2[SET_EXT_ACS_BAND]); + } + + if (tb2[SET_CHAN_PRIMARY_CHANNEL]) { + uint32_t ch = + nla_get_u8(tb2[SET_CHAN_PRIMARY_CHANNEL]); + + channel_list[i].pri_chan_freq = + wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch); + } + + if (tb2[SET_CHAN_SECONDARY_CHANNEL]) { + uint32_t ch = + nla_get_u8(tb2[SET_CHAN_SECONDARY_CHANNEL]); + + channel_list[i].ht_sec_chan_freq = + wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch); + } + + if (tb2[SET_CHAN_SEG0_CENTER_CHANNEL]) { + uint32_t ch = + nla_get_u8(tb2[SET_CHAN_SEG0_CENTER_CHANNEL]); + + channel_list[i].vht_seg0_center_chan_freq = + wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch); + } + + if (tb2[SET_CHAN_SEG1_CENTER_CHANNEL]) { + uint32_t ch = + nla_get_u8(tb2[SET_CHAN_SEG1_CENTER_CHANNEL]); + + channel_list[i].vht_seg1_center_chan_freq = + wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, ch); + } + + if (tb2[SET_CHAN_CHANNEL_WIDTH]) { + channel_list[i].chan_width = + nla_get_u8(tb2[SET_CHAN_CHANNEL_WIDTH]); + } + hdd_debug("index %d, pri_chan_freq %u, ht_sec_chan_freq %u seg0_freq %u seg1_freq %u width %u", + i, channel_list[i].pri_chan_freq, + channel_list[i].ht_sec_chan_freq, + channel_list[i].vht_seg0_center_chan_freq, + channel_list[i].vht_seg1_center_chan_freq, + channel_list[i].chan_width); + i++; + } + *list_ptr = channel_list; + + return 0; +} + +/** + * hdd_parse_vendor_acs_chan_config() - API to parse vendor acs channel config + * @hdd_ctx: pointer to hdd context + * @chan_list_ptr: pointer to hdd_vendor_chan_info + * @reason: channel change reason + * @channel_cnt: channel count + * @data: data + * @data_len: data len + * + * Return: 0 on success, negative errno on failure + */ +static int +hdd_parse_vendor_acs_chan_config(struct hdd_context *hdd_ctx, + struct hdd_vendor_chan_info **chan_list_ptr, + uint8_t *reason, uint8_t *channel_cnt, + const void *data, int data_len) +{ + struct nlattr *tb[SET_CHAN_MAX + 1]; + int ret; + + if (wlan_cfg80211_nla_parse(tb, SET_CHAN_MAX, data, data_len, + acs_chan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (tb[SET_CHAN_REASON]) + *reason = nla_get_u8(tb[SET_CHAN_REASON]); + + if (!tb[SET_CHAN_FREQ_LIST] && !tb[SET_CHAN_CHAN_LIST]) { + hdd_err("Both channel list and frequency list are empty"); + return -EINVAL; + } + + if (tb[SET_CHAN_FREQ_LIST]) { + ret = hdd_extract_external_acs_frequencies(hdd_ctx, + chan_list_ptr, + channel_cnt, + data, data_len); + if (ret) { + hdd_err("Failed to extract frequencies"); + return ret; + } + + return 0; + } + + ret = hdd_extract_external_acs_channels(hdd_ctx, chan_list_ptr, + channel_cnt, data, data_len); + if (ret) + hdd_err("Failed to extract channels"); + + return ret; +} + +/* + * Undef short names for vendor set channel configuration + */ +#undef SET_CHAN_REASON +#undef SET_CHAN_CHAN_LIST +#undef SET_CHAN_PRIMARY_CHANNEL +#undef SET_CHAN_SECONDARY_CHANNEL +#undef SET_CHAN_SEG0_CENTER_CHANNEL +#undef SET_CHAN_SEG1_CENTER_CHANNEL + +#undef SET_CHAN_FREQ_LIST +#undef SET_CHAN_FREQUENCY_PRIMARY +#undef SET_CHAN_FREQUENCY_SECONDARY +#undef SET_CHAN_SEG0_CENTER_FREQUENCY +#undef SET_CHAN_SEG1_CENTER_FREQUENCY + +#undef SET_CHAN_CHANNEL_WIDTH +#undef SET_CHAN_MAX + +/** + * __wlan_hdd_cfg80211_update_vendor_channel() - update vendor channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_update_vendor_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret_val; + QDF_STATUS status; + enum phy_ch_width phy_ch_width; + uint8_t channel_cnt = 0, reason = -1; + struct hdd_vendor_chan_info *chan_list = NULL; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_vendor_chan_info *chan_list_ptr; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (test_bit(VENDOR_ACS_RESPONSE_PENDING, &link_info->link_flags)) { + clear_bit(VENDOR_ACS_RESPONSE_PENDING, &link_info->link_flags); + } else { + hdd_err("already timeout happened for acs"); + return -EINVAL; + } + + ret_val = hdd_parse_vendor_acs_chan_config(hdd_ctx, &chan_list, + &reason, &channel_cnt, data, + data_len); + chan_list_ptr = chan_list; + if (ret_val) + return ret_val; + + /* Validate channel to be set */ + while (channel_cnt && chan_list) { + phy_ch_width = hdd_map_nl_chan_width(chan_list->chan_width); + status = wlan_hdd_validate_acs_channel(link_info, + chan_list->pri_chan_freq, + phy_ch_width); + if (status == QDF_STATUS_SUCCESS) + break; + else if (channel_cnt == 1) { + hdd_err("invalid channel frequ %u received from app", + chan_list->pri_chan_freq); + chan_list->pri_chan_freq = 0; + break; + } + + channel_cnt--; + chan_list++; + } + + if ((channel_cnt <= 0) || !chan_list) { + hdd_err("no available channel/chanlist %d/%pK", channel_cnt, + chan_list); + qdf_mem_free(chan_list_ptr); + return -EINVAL; + } + + hdd_debug("received primary channel freq as %d", + chan_list->pri_chan_freq); + + ret_val = hdd_update_acs_channel(link_info, reason, + channel_cnt, chan_list); + qdf_mem_free(chan_list_ptr); + return ret_val; +} + +/** + * wlan_hdd_cfg80211_update_vendor_channel() - update vendor channel + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_update_vendor_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_update_vendor_channel(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_cfg80211_setband() - Wrapper to setband + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_setband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_setband(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + *__wlan_hdd_cfg80211_getband() - get band + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_getband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int ret; + uint32_t reg_wifi_band_bitmap, vendor_band_mask; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + sizeof(uint32_t) + + NLA_HDRLEN); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + status = ucfg_reg_get_band(hdd_ctx->pdev, ®_wifi_band_bitmap); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to get band"); + goto failure; + } + + vendor_band_mask = wlan_reg_wifi_band_bitmap_to_vendor_bitmap( + reg_wifi_band_bitmap); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SETBAND_MASK, + vendor_band_mask)) { + hdd_err("nla put failure"); + goto failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + + hdd_exit(); + + return 0; + +failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_getband() - Wrapper to getband + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_cfg80211_getband(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_getband(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static const struct +nla_policy qca_wlan_vendor_attr[QCA_WLAN_VENDOR_ATTR_MAX+1] = { + [QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = {.type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE}, +}; + +void wlan_hdd_rso_cmd_status_cb(hdd_handle_t hdd_handle, + struct rso_cmd_status *rso_status) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct wlan_hdd_link_info *link_info; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rso_status->vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + link_info->adapter->lfr_fw_status.is_disabled = rso_status->status; + complete(&link_info->adapter->lfr_fw_status.disable_lfr_event); +} + +/** + * __wlan_hdd_cfg80211_set_fast_roaming() - enable/disable roaming + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to enable/disable roaming using vendor commands + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_fast_roaming(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + uint32_t is_fast_roam_enabled; + int ret; + QDF_STATUS qdf_status; + unsigned long rc; + bool roaming_enabled; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err_rl("command not allowed in %d mode, vdev_id: %d", + adapter->device_mode, adapter->deflink->vdev_id); + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_MAX, data, data_len, + qca_wlan_vendor_attr); + if (ret) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch Enable flag */ + if (!tb[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY]) { + hdd_err("attr enable failed"); + return -EINVAL; + } + + is_fast_roam_enabled = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY]); + hdd_debug("ROAM_CONFIG: isFastRoamEnabled %d", is_fast_roam_enabled); + + if (sme_roaming_in_progress(hdd_ctx->mac_handle, + adapter->deflink->vdev_id)) { + hdd_err_rl("Roaming in progress for vdev %d", + adapter->deflink->vdev_id); + return -EAGAIN; + } + + /* + * Get current roaming state and decide whether to wait for RSO_STOP + * response or not. + */ + roaming_enabled = ucfg_is_rso_enabled(hdd_ctx->pdev, + adapter->deflink->vdev_id); + + /* Update roaming */ + qdf_status = ucfg_user_space_enable_disable_rso( + hdd_ctx->pdev, + adapter->deflink->vdev_id, + is_fast_roam_enabled); + if (QDF_IS_STATUS_ERROR(qdf_status)) + hdd_err("ROAM_CONFIG: sme_config_fast_roaming failed with status=%d", + qdf_status); + + ret = qdf_status_to_os_return(qdf_status); + + if (hdd_cm_is_vdev_associated(adapter->deflink) && + roaming_enabled && + QDF_IS_STATUS_SUCCESS(qdf_status) && !is_fast_roam_enabled) { + INIT_COMPLETION(adapter->lfr_fw_status.disable_lfr_event); + /* + * wait only for LFR disable in fw as LFR enable + * is always success + */ + rc = wait_for_completion_timeout( + &adapter->lfr_fw_status.disable_lfr_event, + msecs_to_jiffies(WAIT_TIME_RSO_CMD_STATUS)); + if (!rc) { + hdd_err("Timed out waiting for RSO CMD status"); + return -ETIMEDOUT; + } + + if (!adapter->lfr_fw_status.is_disabled) { + hdd_err("Roam disable attempt in FW fails"); + return -EBUSY; + } + } + + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_fast_roaming() - enable/disable roaming + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_set_fast_roaming() + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_set_fast_roaming(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_fast_roaming(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_SET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define STATS_SET_START \ + QCA_ATTR_NUD_STATS_SET_START +#define STATS_GW_IPV4 \ + QCA_ATTR_NUD_STATS_GW_IPV4 +#define STATS_SET_DATA_PKT_INFO \ + QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO +#define STATS_SET_MAX \ + QCA_ATTR_NUD_STATS_SET_MAX + +const struct nla_policy +qca_wlan_vendor_set_nud_stats_policy[STATS_SET_MAX + 1] = { + [STATS_SET_START] = {.type = NLA_FLAG }, + [STATS_GW_IPV4] = {.type = NLA_U32 }, + [STATS_SET_DATA_PKT_INFO] = {.type = NLA_NESTED }, +}; + +/* define short names for the global vendor params */ +#define CONNECTIVITY_STATS_SET_INVALID \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SET_INVALID +#define STATS_PKT_INFO_TYPE \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_STATS_PKT_INFO_TYPE +#define STATS_DNS_DOMAIN_NAME \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DNS_DOMAIN_NAME +#define STATS_SRC_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SRC_PORT +#define STATS_DEST_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_PORT +#define STATS_DEST_IPV4 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_IPV4 +#define STATS_DEST_IPV6 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_IPV6 +#define CONNECTIVITY_STATS_SET_MAX \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SET_MAX + +const struct nla_policy +qca_wlan_vendor_set_connectivity_check_stats[CONNECTIVITY_STATS_SET_MAX + 1] = { + [STATS_PKT_INFO_TYPE] = {.type = NLA_U32 }, + [STATS_DNS_DOMAIN_NAME] = {.type = NLA_NUL_STRING, + .len = DNS_DOMAIN_NAME_MAX_LEN }, + [STATS_SRC_PORT] = {.type = NLA_U32 }, + [STATS_DEST_PORT] = {.type = NLA_U32 }, + [STATS_DEST_IPV4] = {.type = NLA_U32 }, + [STATS_DEST_IPV6] = {.type = NLA_BINARY, + .len = ICMPv6_ADDR_LEN }, +}; + +const struct nla_policy qca_wlan_vendor_set_trace_level_policy[ + QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_PARAM] = + VENDOR_NLA_POLICY_NESTED(qca_wlan_vendor_set_trace_level_policy), + [QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MODULE_ID] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_TRACE_MASK] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_set_trace_level() - Set the trace level + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_set_trace_level(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb1[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX + 1]; + struct nlattr *apth; + int rem; + int ret = 1; + int print_idx = -1; + int module_id = -1; + int bit_mask = -1; + int status; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return -EINVAL; + + print_idx = qdf_get_pidx(); + if (print_idx < 0 || print_idx >= MAX_PRINT_CONFIG_SUPPORTED) { + hdd_err("Invalid print control object index"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb1, + QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX, + data, data_len, + qca_wlan_vendor_set_trace_level_policy)) { + hdd_err("Invalid attr"); + return -EINVAL; + } + + if (!tb1[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_PARAM]) { + hdd_err("attr trace level param failed"); + return -EINVAL; + } + + nla_for_each_nested(apth, + tb1[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_PARAM], rem) { + if (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX, + nla_data(apth), nla_len(apth), + qca_wlan_vendor_set_trace_level_policy)) { + hdd_err("Invalid attr"); + return -EINVAL; + } + + if (!tb2[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MODULE_ID]) { + hdd_err("attr Module ID failed"); + return -EINVAL; + } + module_id = nla_get_u32 + (tb2[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MODULE_ID]); + + if (!tb2[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_TRACE_MASK]) { + hdd_err("attr Verbose mask failed"); + return -EINVAL; + } + bit_mask = nla_get_u32 + (tb2[QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_TRACE_MASK]); + + status = hdd_qdf_trace_enable(module_id, bit_mask); + + if (status != 0) + hdd_err("can not set verbose mask %d for the category %d", + bit_mask, module_id); + } + + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_trace_level() - Set the trace level + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_set_trace_level() + * + * Return: 0 on success, negative errno on failure + */ + +static int wlan_hdd_cfg80211_set_trace_level(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_trace_level(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct wlan_objmgr_vdev *vdev; + int err = 0; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + if (adapter->deflink->vdev_id == WLAN_UMAC_VDEV_ID_MAX) { + hdd_err("Invalid vdev id"); + return -EINVAL; + } + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("STATS supported in only STA mode!"); + return -EINVAL; + } + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_debug("Not Associated"); + return 0; + } + + if (hdd_is_roaming_in_progress(hdd_ctx)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return -EINVAL; + + err = osif_dp_set_nud_stats(wiphy, vdev, data, data_len); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + hdd_exit(); + + return err; +} + +/** + * wlan_hdd_cfg80211_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_set_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_nud_stats(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#undef STATS_SET_INVALID +#undef STATS_SET_START +#undef STATS_GW_IPV4 +#undef STATS_SET_MAX + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_GET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define COUNT_FROM_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#define COUNT_TO_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#define RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#define COUNT_TX_SUCCESS \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#define RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#define RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#define RSP_COUNT_TO_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#define RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#define AP_LINK_ACTIVE \ + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#define AP_LINK_DAD \ + QCA_ATTR_NUD_STATS_IS_DAD +#define DATA_PKT_STATS \ + QCA_ATTR_NUD_STATS_DATA_PKT_STATS +#define STATS_GET_MAX \ + QCA_ATTR_NUD_STATS_GET_MAX + +#define CHECK_STATS_INVALID \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_INVALID +#define CHECK_STATS_PKT_TYPE \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_TYPE +#define CHECK_STATS_PKT_DNS_DOMAIN_NAME \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DNS_DOMAIN_NAME +#define CHECK_STATS_PKT_SRC_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_SRC_PORT +#define CHECK_STATS_PKT_DEST_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_PORT +#define CHECK_STATS_PKT_DEST_IPV4 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_IPV4 +#define CHECK_STATS_PKT_DEST_IPV6 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_IPV6 +#define CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV +#define CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC +#define CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC +#define CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS +#define CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC +#define CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC +#define CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV +#define CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP +#define CHECK_DATA_STATS_MAX \ + QCA_ATTR_CONNECTIVITY_CHECK_DATA_STATS_MAX + + +const struct nla_policy +qca_wlan_vendor_get_nud_stats[STATS_GET_MAX + 1] = { + [COUNT_FROM_NETDEV] = {.type = NLA_U16 }, + [COUNT_TO_LOWER_MAC] = {.type = NLA_U16 }, + [RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [COUNT_TX_SUCCESS] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_LOWER_MAC] = {.type = NLA_U16 }, + [RSP_RX_COUNT_BY_UPPER_MAC] = {.type = NLA_U16 }, + [RSP_COUNT_TO_NETDEV] = {.type = NLA_U16 }, + [RSP_COUNT_OUT_OF_ORDER_DROP] = {.type = NLA_U16 }, + [AP_LINK_ACTIVE] = {.type = NLA_FLAG }, + [AP_LINK_DAD] = {.type = NLA_FLAG }, + [DATA_PKT_STATS] = {.type = NLA_U16 }, +}; + +/** + * __wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int err = 0; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + err = hdd_validate_adapter(adapter); + if (err) + return err; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("STATS supported in only STA mode!"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return -EINVAL; + + err = osif_dp_get_nud_stats(wiphy, vdev, data, data_len); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + return err; +} + +/** + * wlan_hdd_cfg80211_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +static int wlan_hdd_cfg80211_get_nud_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_nud_stats(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#undef QCA_ATTR_NUD_STATS_SET_INVALID +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#undef QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#undef QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#undef QCA_ATTR_NUD_STATS_GET_MAX + +void hdd_bt_activity_cb(hdd_handle_t hdd_handle, uint32_t bt_activity) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + int status; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (bt_activity == WLAN_COEX_EVENT_BT_A2DP_PROFILE_ADD) + hdd_ctx->bt_a2dp_active = 1; + else if (bt_activity == WLAN_COEX_EVENT_BT_A2DP_PROFILE_REMOVE) + hdd_ctx->bt_a2dp_active = 0; + else if (bt_activity == WLAN_COEX_EVENT_BT_VOICE_PROFILE_ADD) + hdd_ctx->bt_vo_active = 1; + else if (bt_activity == WLAN_COEX_EVENT_BT_VOICE_PROFILE_REMOVE) + hdd_ctx->bt_vo_active = 0; + else if (bt_activity == WLAN_COEX_EVENT_BT_PROFILE_CONNECTED) + hdd_ctx->bt_profile_con = 1; + else if (bt_activity == WLAN_COEX_EVENT_BT_PROFILE_DISCONNECTED) + hdd_ctx->bt_profile_con = 0; + else + return; + + ucfg_scan_set_bt_activity(hdd_ctx->psoc, hdd_ctx->bt_a2dp_active); + ucfg_mlme_set_bt_profile_con(hdd_ctx->psoc, hdd_ctx->bt_profile_con); + hdd_debug("a2dp_active: %d vo_active: %d connected:%d", + hdd_ctx->bt_a2dp_active, + hdd_ctx->bt_vo_active, hdd_ctx->bt_profile_con); +} + +/** + * hdd_post_chain_rssi_rsp - send rsp to user space + * @adapter: Pointer to adapter + * @result: chain rssi result + * @update_chain_rssi: update rssi, if this flag is set + * @update_chain_evm: update evm, if this flag is set + * @update_ant_id: update antenna id, if this flag is set + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_post_chain_rssi_rsp(struct hdd_adapter *adapter, + struct chain_rssi_result *result, + bool update_chain_rssi, + bool update_chain_evm, + bool update_ant_id) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *skb; + int len = NLMSG_HDRLEN; + + len += update_chain_rssi ? + nla_total_size(sizeof(result->chain_rssi)) : 0; + len += update_chain_evm ? + nla_total_size(sizeof(result->chain_evm)) : 0; + len += update_ant_id ? + nla_total_size(sizeof(result->ant_id)) : 0; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (update_chain_rssi && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_CHAIN_RSSI, + sizeof(result->chain_rssi), + result->chain_rssi)) { + goto nla_put_failure; + } + + if (update_chain_evm && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_CHAIN_EVM, + sizeof(result->chain_evm), + result->chain_evm)) { + goto nla_put_failure; + } + + if (update_ant_id && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_ANTENNA_INFO, + sizeof(result->ant_id), + result->ant_id)) { + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +#ifdef QCA_SUPPORT_CP_STATS +/** + * hdd_process_peer_chain_rssi_req() - fetch per chain rssi of a connected peer + * @adapter: Pointer to adapter + * @peer_macaddr: mac address of desired peer or AP + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_process_peer_chain_rssi_req(struct hdd_adapter *adapter, + struct qdf_mac_addr *peer_macaddr) +{ + struct stats_event *stats; + struct wlan_objmgr_vdev *vdev; + struct chain_rssi_result chain_rssi; + int retval, index; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(vdev, + peer_macaddr->bytes, + &retval); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (retval || !stats) { + if (stats) + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + hdd_err("Unable to get chain rssi from fw"); + return retval; + } + + for (index = 0; index < WMI_MAX_CHAINS; index++) + chain_rssi.chain_rssi[index] = + stats->peer_stats_info_ext->peer_rssi_per_chain[index]; + + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + + retval = hdd_post_chain_rssi_rsp(adapter, &chain_rssi, + true, false, false); + if (retval) + hdd_err("Failed to post chain rssi"); + + return retval; +} +#else +struct chain_rssi_priv { + struct chain_rssi_result chain_rssi; +}; + +/** + * hdd_get_chain_rssi_cb() - Callback function to get chain rssi + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * @data: struct for get chain rssi + * + * This function receives the response/data from the lower layer and + * checks to see if the thread is still waiting then post the results to + * upper layer, if the request has timed out then ignore. + * + * Return: None + */ +static void hdd_get_chain_rssi_cb(void *context, + struct chain_rssi_result *data) +{ + struct osif_request *request; + struct chain_rssi_priv *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->chain_rssi = *data; + osif_request_complete(request); + osif_request_put(request); +} + +static int hdd_process_peer_chain_rssi_req(struct hdd_adapter *adapter, + struct qdf_mac_addr *peer_macaddr) +{ + mac_handle_t mac_handle; + struct osif_request *request; + struct chain_rssi_priv *priv; + struct get_chain_rssi_req_params req_msg; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int retval; + void *cookie; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + memcpy(&req_msg.peer_macaddr, peer_macaddr->bytes, QDF_MAC_ADDR_SIZE); + req_msg.session_id = adapter->deflink->vdev_id; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + mac_handle = hdd_ctx->mac_handle; + status = sme_get_chain_rssi(mac_handle, + &req_msg, + hdd_get_chain_rssi_cb, + cookie); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Unable to get chain rssi"); + retval = qdf_status_to_os_return(status); + } else { + retval = osif_request_wait_for_response(request); + if (retval) { + hdd_err("Target response timed out"); + } else { + priv = osif_request_priv(request); + retval = hdd_post_chain_rssi_rsp(adapter, + &priv->chain_rssi, + true, true, true); + if (retval) + hdd_err("Failed to post chain rssi"); + } + } + osif_request_put(request); + return retval; +} +#endif + +static const struct +nla_policy get_chain_rssi_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_MAC_ADDR] = {.type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE}, +}; + +static const struct nla_policy +get_chan_info[QCA_WLAN_VENDOR_ATTR_CHAN_INFO_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_CHAN_INFO_INVALID] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CHAN_INFO_PRIMARY_FREQ] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG0_FREQ] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG1_FREQ] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CHAN_INFO_BANDWIDTH] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_CHAN_INFO_IFACE_MODE_MASK] = {.type = NLA_U32}, +}; + +static const struct nla_policy +get_usable_channel_policy[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_INVALID] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_BAND_MASK] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_IFACE_MODE_MASK] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_CHAN_INFO] = { + .type = NLA_NESTED + }, +}; + +#ifdef WLAN_FEATURE_GET_USABLE_CHAN_LIST +static enum nl80211_chan_width +hdd_convert_phy_bw_to_nl_bw(enum phy_ch_width bw) +{ + switch (bw) { + case CH_WIDTH_20MHZ: + return NL80211_CHAN_WIDTH_20; + case CH_WIDTH_40MHZ: + return NL80211_CHAN_WIDTH_40; + case CH_WIDTH_160MHZ: + return NL80211_CHAN_WIDTH_160; + case CH_WIDTH_80MHZ: + return NL80211_CHAN_WIDTH_80; + case CH_WIDTH_80P80MHZ: + return NL80211_CHAN_WIDTH_80P80; + case CH_WIDTH_5MHZ: + return NL80211_CHAN_WIDTH_5; + case CH_WIDTH_10MHZ: + return NL80211_CHAN_WIDTH_10; +#if defined(CFG80211_11BE_BASIC) + case CH_WIDTH_320MHZ: + return NL80211_CHAN_WIDTH_320; +#else + case CH_WIDTH_320MHZ: + return NL80211_CHAN_WIDTH_20; +#endif + case CH_WIDTH_INVALID: + case CH_WIDTH_MAX: + return NL80211_CHAN_WIDTH_20; + } + + return NL80211_CHAN_WIDTH_20; +} + +/** + * hdd_fill_usable_channels_data() - Fill the data requested by userspace + * @skb: SK buffer + * @tb: List of attributes + * @res_msg: structure of usable channel info + * @count: no of usable channels + * + * Get the data corresponding to the attribute list specified in tb and + * update the same to skb by populating the same attributes. + * + * Return: 0 on success; error number on failure + */ +static int +hdd_fill_usable_channels_data(struct sk_buff *skb, struct nlattr **tb, + struct get_usable_chan_res_params *res_msg, + int count) +{ + struct nlattr *config, *chan_params; + uint8_t i, bw, j = 0; + + config = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_CHAN_INFO); + if (!config) { + hdd_err("nla nest start failure"); + return -EINVAL; + } + for (i = 0; i < count ; i++) { + if (!res_msg[i].freq) + continue; + chan_params = nla_nest_start(skb, j); + if (!chan_params) + return -EINVAL; + j++; + bw = hdd_convert_phy_bw_to_nl_bw(res_msg[i].bw); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_CHAN_INFO_PRIMARY_FREQ, + res_msg[i].freq) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG0_FREQ, + res_msg[i].seg0_freq) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_CHAN_INFO_SEG1_FREQ, + res_msg[i].seg1_freq) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_CHAN_INFO_BANDWIDTH, + bw) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_CHAN_INFO_IFACE_MODE_MASK, + res_msg[i].iface_mode_mask)) { + hdd_err("nla put failure"); + return -EINVAL; + } + + nla_nest_end(skb, chan_params); + } + nla_nest_end(skb, config); + return 0; +} + +/** + * hdd_get_usable_channel_len() - calculate the length required by skb + * @count: number of usable channels + * + * Find the required length to send usable channel data to upper layer + * + * Return: required len + */ +static uint32_t +hdd_get_usable_channel_len(uint32_t count) +{ + uint32_t len = 0; + struct get_usable_chan_res_params res_msg; + + len = nla_total_size(sizeof(res_msg.freq)) + + nla_total_size(sizeof(res_msg.seg0_freq)) + + nla_total_size(sizeof(res_msg.seg1_freq)) + + nla_total_size(sizeof(res_msg.bw)) + + nla_total_size(sizeof(res_msg.iface_mode_mask)); + + return len * count; +} + +/** + * hdd_send_usable_channel() - Send usable channels as vendor cmd reply + * @hdd_ctx: Pointer to hdd context + * @res_msg: pointer to usable channel information + * @count: number of channels + * @tb: List of attributes + * + * Parse the attributes list tb and get the data corresponding to the + * attributes specified in tb. Send them as a vendor response. + * + * Return: 0 on success; error number on failure + */ +static int +hdd_send_usable_channel(struct hdd_context *hdd_ctx, + struct get_usable_chan_res_params *res_msg, + uint32_t count, + struct nlattr **tb) +{ + struct sk_buff *skb; + uint32_t skb_len; + int status; + + skb_len = hdd_get_usable_channel_len(count); + if (!skb_len) { + hdd_err("No data requested"); + return -EINVAL; + } + + /** + * As each nesting occupies NLMSG_HDRLEN size in the skb, add + * NLMSG_HDRLEN worth space for each nesting. + */ + skb_len += NLMSG_HDRLEN * (count + 1); + + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len); + if (!skb) { + hdd_info("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + status = hdd_fill_usable_channels_data(skb, tb, res_msg, count); + if (status) + goto fail; + + return wlan_cfg80211_vendor_cmd_reply(skb); + +fail: + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(skb); + return status; +} + +/** + * hdd_get_all_band_mask() - get supported nl80211 bands + * + * Return: supported band mask + */ +static uint32_t +hdd_get_all_band_mask(void) +{ + uint32_t band_mask = 0; + + band_mask = + (1 << REG_BAND_2G) | (1 << REG_BAND_5G) | (1 << REG_BAND_6G); + + return band_mask; +} + +/** + * hdd_get_all_iface_mode_mask() - get supported nl80211 iface mode + * + * Return: supported iface mode mask + */ +static uint32_t +hdd_get_all_iface_mode_mask(void) +{ + uint32_t mode_mask = 0; + + mode_mask = (1 << NL80211_IFTYPE_STATION) | + (1 << NL80211_IFTYPE_AP) | + (1 << NL80211_IFTYPE_P2P_GO) | + (1 << NL80211_IFTYPE_P2P_CLIENT) | + (1 << NL80211_IFTYPE_P2P_DEVICE) | + (1 << NL80211_IFTYPE_NAN); + + return mode_mask; +} + +/** + * hdd_convert_nl80211_to_reg_band_mask() - convert n80211 band to reg band + * @band: nl80211 band + * + * Return: reg band value + */ + +static uint32_t +hdd_convert_nl80211_to_reg_band_mask(enum nl80211_band band) +{ + uint32_t reg_band = 0; + + if (band & 1 << NL80211_BAND_2GHZ) + reg_band |= 1 << REG_BAND_2G; + if (band & 1 << NL80211_BAND_5GHZ) + reg_band |= 1 << REG_BAND_5G; + if (band & 1 << NL80211_BAND_6GHZ) + reg_band |= 1 << REG_BAND_6G; + if (band & 1 << NL80211_BAND_60GHZ) + hdd_err("band: %d not supported", NL80211_BAND_60GHZ); + + return reg_band; +} + +/** + * __wlan_hdd_cfg80211_get_usable_channel() - get chain rssi + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_get_usable_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct get_usable_chan_req_params req_msg = {0}; + struct get_usable_chan_res_params *res_msg; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_MAX + 1]; + int ret = 0; + uint32_t count = 0; + QDF_STATUS status; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + res_msg = qdf_mem_malloc(NUM_CHANNELS * + sizeof(*res_msg)); + + if (!res_msg) { + hdd_err("res_msg invalid"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse( + tb, QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_MAX, + data, data_len, get_usable_channel_policy)) { + hdd_err("Invalid ATTR"); + ret = -EINVAL; + goto err; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_BAND_MASK]) { + hdd_err("band mask not present"); + req_msg.band_mask = hdd_get_all_band_mask(); + } else { + req_msg.band_mask = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_BAND_MASK]); + if (!req_msg.band_mask) + req_msg.band_mask = hdd_get_all_band_mask(); + else + req_msg.band_mask = + hdd_convert_nl80211_to_reg_band_mask(req_msg.band_mask); + } + if (!tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_IFACE_MODE_MASK]) { + hdd_err("iface mode mask not present"); + req_msg.iface_mode_mask = hdd_get_all_iface_mode_mask(); + } else { + req_msg.iface_mode_mask = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_IFACE_MODE_MASK]); + if (!req_msg.iface_mode_mask) + req_msg.iface_mode_mask = hdd_get_all_iface_mode_mask(); + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK]) { + hdd_err("usable channels filter mask not present"); + req_msg.filter_mask = 0; + } else { + req_msg.filter_mask = + nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_USABLE_CHANNELS_FILTER_MASK]); + } + + hdd_debug("get usable channel list for band %d mode %d filter %d", + req_msg.band_mask, req_msg.iface_mode_mask, + req_msg.filter_mask); + + status = wlan_reg_get_usable_channel(hdd_ctx->pdev, req_msg, + res_msg, &count, + REG_CURRENT_PWR_MODE); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("get usable channel failed %d", status); + ret = -EINVAL; + goto err; + } + hdd_debug("usable channel count : %d", count); + + ret = hdd_send_usable_channel(hdd_ctx, res_msg, count, tb); + if (ret) { + hdd_err("failed to send usable_channels"); + ret = -EINVAL; + goto err; + } + +err: + qdf_mem_free(res_msg); + if (ret) + return ret; + return qdf_status_to_os_return(status); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * enum roam_stats_set_params - Different types of params to set the roam stats + * @ROAM_RT_STATS_DISABLED: Roam stats feature disabled + * @ROAM_RT_STATS_ENABLED: Roam stats feature enabled + * @ROAM_RT_STATS_ENABLED_IN_SUSPEND_MODE: Roam stats enabled in suspend mode + */ +enum roam_stats_set_params { + ROAM_RT_STATS_DISABLED = 0, + ROAM_RT_STATS_ENABLED = 1, + ROAM_RT_STATS_ENABLED_IN_SUSPEND_MODE = 2, +}; + +#define EVENTS_CONFIGURE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE +#define SUSPEND_STATE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE + +static const struct nla_policy +set_roam_events_policy[QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE] = {.type = NLA_FLAG}, +}; + +/** + * __wlan_hdd_cfg80211_set_roam_events() - set roam stats + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_set_roam_events(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX + 1]; + QDF_STATUS status; + int ret; + uint8_t config, state, param = 0; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) { + hdd_err("Invalid hdd_ctx"); + return ret; + } + + ret = hdd_validate_adapter(adapter); + if (ret != 0) { + hdd_err("Invalid adapter"); + return ret; + } + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("STATS supported in only STA mode!"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX, + data, data_len, set_roam_events_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[EVENTS_CONFIGURE]) { + hdd_err("roam events configure not present"); + return -EINVAL; + } + + config = nla_get_u8(tb[EVENTS_CONFIGURE]); + hdd_debug("roam stats configured: %d", config); + + if (!tb[SUSPEND_STATE]) { + hdd_debug("suspend state not present"); + param = config ? ROAM_RT_STATS_ENABLED : ROAM_RT_STATS_DISABLED; + } else if (config == ROAM_RT_STATS_ENABLED) { + state = nla_get_flag(tb[SUSPEND_STATE]); + hdd_debug("Suspend state configured: %d", state); + param = ROAM_RT_STATS_ENABLED | + ROAM_RT_STATS_ENABLED_IN_SUSPEND_MODE; + } + + hdd_debug("roam events param: %d", param); + ucfg_cm_update_roam_rt_stats(hdd_ctx->psoc, + param, ROAM_RT_STATS_ENABLE); + + if (param == (ROAM_RT_STATS_ENABLED | + ROAM_RT_STATS_ENABLED_IN_SUSPEND_MODE)) { + ucfg_pmo_enable_wakeup_event(hdd_ctx->psoc, + adapter->deflink->vdev_id, + WOW_ROAM_STATS_EVENT); + ucfg_cm_update_roam_rt_stats(hdd_ctx->psoc, + ROAM_RT_STATS_ENABLED, + ROAM_RT_STATS_SUSPEND_MODE_ENABLE); + } else if (ucfg_cm_get_roam_rt_stats(hdd_ctx->psoc, + ROAM_RT_STATS_SUSPEND_MODE_ENABLE)) { + ucfg_pmo_disable_wakeup_event(hdd_ctx->psoc, + adapter->deflink->vdev_id, + WOW_ROAM_STATS_EVENT); + ucfg_cm_update_roam_rt_stats(hdd_ctx->psoc, + ROAM_RT_STATS_DISABLED, + ROAM_RT_STATS_SUSPEND_MODE_ENABLE); + } + + status = ucfg_cm_roam_send_rt_stats_config(hdd_ctx->pdev, + adapter->deflink->vdev_id, + param); + + return qdf_status_to_os_return(status); +} + +#undef EVENTS_CONFIGURE +#undef SUSPEND_STATE + +/** + * wlan_hdd_cfg80211_set_roam_events() - set roam stats + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_set_roam_events(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_roam_events(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +/** + * __wlan_hdd_cfg80211_get_chain_rssi() - get chain rssi + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int __wlan_hdd_cfg80211_get_chain_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct qdf_mac_addr peer_macaddr; + int retval; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return retval; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, + data, data_len, get_chain_rssi_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) { + hdd_err("attr mac addr failed"); + return -EINVAL; + } + if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR]) != QDF_MAC_ADDR_SIZE) { + hdd_err("incorrect mac size"); + return -EINVAL; + } + + qdf_copy_macaddr(&peer_macaddr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_MAC_ADDR])); + + retval = hdd_process_peer_chain_rssi_req(adapter, &peer_macaddr); + hdd_exit(); + return retval; +} + +#ifdef WLAN_FEATURE_GET_USABLE_CHAN_LIST +/** + * wlan_hdd_cfg80211_get_usable_channel() - get chain rssi + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_get_usable_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_usable_channel(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_get_usable_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + hdd_debug("get usable channel feature not supported"); + return -EPERM; +} +#endif + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +/** + * os_if_monitor_mode_configure() - Wifi monitor mode configuration + * vendor command + * @adapter: hdd adapter + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: QDF_STATUS + */ +static +QDF_STATUS os_if_monitor_mode_configure(struct hdd_adapter *adapter, + const void *data, int data_len) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = os_if_dp_set_lpc_configure(vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + return status; +} + +#endif /* WLAN_FEATURE_LOCAL_PKT_CAPTURE */ + +#if defined(WLAN_FEATURE_PKT_CAPTURE) || defined(WLAN_FEATURE_LOCAL_PKT_CAPTURE) + +/** + * __wlan_hdd_cfg80211_set_monitor_mode() - Wifi monitor mode configuration + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles . + * + * Return: 0 for Success and negative value for failure + */ +static int +__wlan_hdd_cfg80211_set_monitor_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int errno; + QDF_STATUS status; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + if (!(ucfg_pkt_capture_get_mode(hdd_ctx->psoc) || + hdd_is_pkt_capture_mon_enable(adapter) || + ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc))) + return -EPERM; + + status = os_if_monitor_mode_configure(adapter, data, data_len); + + return qdf_status_to_os_return(status); +} + +/** + * wlan_hdd_cfg80211_set_monitor_mode() - set monitor mode + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_set_monitor_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + hdd_enter_dev(wdev->netdev); + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_monitor_mode(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + hdd_exit(); + + return errno; +} +#endif + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE + +/** + * __wlan_hdd_cfg80211_get_monitor_mode() - Get wifi monitor mode configuration + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 for Success and negative value for failure + */ +static int +__wlan_hdd_cfg80211_get_monitor_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct wlan_objmgr_vdev *vdev; + int errno; + QDF_STATUS status; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + if (!ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc)) + return -EPERM; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return -EINVAL; + + status = os_if_dp_get_lpc_state(vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + return qdf_status_to_os_return(status); +} + +/** + * wlan_hdd_cfg80211_get_monitor_mode() - get monitor mode + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_get_monitor_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + hdd_enter_dev(wdev->netdev); + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_monitor_mode(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + hdd_exit(); + + return errno; +} +#endif + +/** + * wlan_hdd_cfg80211_get_chain_rssi() - get chain rssi + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_get_chain_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_chain_rssi(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_fill_intf_info() - Fill skb buffer with interface info + * @skb: Pointer to skb + * @info: mac mode info + * @index: attribute type index for nla_nest_start() + * + * Return : 0 on success and errno on failure + */ +static int wlan_hdd_fill_intf_info(struct sk_buff *skb, + struct connection_info *info, int index) +{ + struct nlattr *attr; + uint32_t freq; + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + goto error; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, info->vdev_id); + if (!link_info) + goto error; + + attr = nla_nest_start(skb, index); + if (!attr) + goto error; + + freq = sme_chn_to_freq(info->channel); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_IFINDEX, + link_info->adapter->dev->ifindex) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO_FREQ, freq)) + goto error; + + nla_nest_end(skb, attr); + + return 0; +error: + hdd_err("Fill buffer with interface info failed"); + return -EINVAL; +} + +/** + * wlan_hdd_fill_mac_info() - Fill skb buffer with mac info + * @skb: Pointer to skb + * @info: mac mode info + * @mac_id: MAC id + * @conn_count: number of current connections + * + * Return : 0 on success and errno on failure + */ +static int wlan_hdd_fill_mac_info(struct sk_buff *skb, + struct connection_info *info, uint32_t mac_id, + uint32_t conn_count) +{ + struct nlattr *attr, *intf_attr; + uint32_t band = 0, i = 0, j = 0; + bool present = false; + + while (i < conn_count) { + if (info[i].mac_id == mac_id) { + present = true; + if (info[i].channel <= SIR_11B_CHANNEL_END) + band |= 1 << NL80211_BAND_2GHZ; + else if (info[i].channel <= SIR_11A_CHANNEL_END) + band |= 1 << NL80211_BAND_5GHZ; + } + i++; + } + + if (!present) + return 0; + + i = 0; + attr = nla_nest_start(skb, mac_id); + if (!attr) + goto error; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MAC_INFO_MAC_ID, mac_id) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_MAC_INFO_BAND, band)) + goto error; + + intf_attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_MAC_IFACE_INFO); + if (!intf_attr) + goto error; + + while (i < conn_count) { + if (info[i].mac_id == mac_id) { + if (wlan_hdd_fill_intf_info(skb, &info[i], j)) + return -EINVAL; + j++; + } + i++; + } + + nla_nest_end(skb, intf_attr); + + nla_nest_end(skb, attr); + + return 0; +error: + hdd_err("Fill buffer with mac info failed"); + return -EINVAL; +} + + +int wlan_hdd_send_mode_change_event(void) +{ + int err; + struct hdd_context *hdd_ctx; + struct sk_buff *skb; + struct nlattr *attr; + struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_count, mac_id; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_WLAN_MAC_INFO_INDEX; + + hdd_enter(); + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) + return err; + + conn_count = policy_mgr_get_connection_info(hdd_ctx->psoc, info); + if (!conn_count) + return -EINVAL; + + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + (sizeof(uint32_t) * 4) * + MAX_NUMBER_OF_CONC_CONNECTIONS + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_MAC_INFO); + if (!attr) { + hdd_err("nla_nest_start failed"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + for (mac_id = 0; mac_id < MAX_MAC; mac_id++) { + if (wlan_hdd_fill_mac_info(skb, info, mac_id, conn_count)) { + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + } + + nla_nest_end(skb, attr); + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + hdd_exit(); + + return err; +} + + +/* Short name for QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS command */ + +#define EXTSCAN_CONFIG_MAX \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX +#define EXTSCAN_CONFIG_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define EXTSCAN_CONFIG_WIFI_BAND \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_WIFI_BAND +#define EXTSCAN_CONFIG_MAX_CHANNELS \ +QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_VALID_CHANNELS_CONFIG_PARAM_MAX_CHANNELS +#define EXTSCAN_RESULTS_NUM_CHANNELS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_CHANNELS +#define EXTSCAN_RESULTS_CHANNELS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CHANNELS + +static const struct nla_policy +wlan_hdd_extscan_get_valid_channels_policy[EXTSCAN_CONFIG_MAX + 1] = { + [EXTSCAN_CONFIG_REQUEST_ID] = {.type = NLA_U32}, + [EXTSCAN_CONFIG_WIFI_BAND] = {.type = NLA_U32}, + [EXTSCAN_CONFIG_MAX_CHANNELS] = {.type = NLA_U32}, +}; + +/** + * hdd_remove_passive_channels () - remove passive channels + * @wiphy: Pointer to wireless phy + * @chan_list: channel list + * @num_channels: number of channels + * + * Return: none + */ +static void hdd_remove_passive_channels(struct wiphy *wiphy, + uint32_t *chan_list, + uint8_t *num_channels) +{ + uint8_t num_chan_temp = 0; + int i, j, k; + + for (i = 0; i < *num_channels; i++) + for (j = 0; j < HDD_NUM_NL80211_BANDS; j++) { + if (!wiphy->bands[j]) + continue; + for (k = 0; k < wiphy->bands[j]->n_channels; k++) { + if ((chan_list[i] == + wiphy->bands[j]->channels[k].center_freq) + && (!(wiphy->bands[j]->channels[k].flags & + IEEE80211_CHAN_PASSIVE_SCAN)) + ) { + chan_list[num_chan_temp] = chan_list[i]; + num_chan_temp++; + } + } + } + + *num_channels = num_chan_temp; +} + +/** + * __wlan_hdd_cfg80211_extscan_get_valid_channels () - get valid channels + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_get_valid_channels(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t chan_list[CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint8_t num_channels = 0, i, buf[256] = {0}; + struct nlattr *tb[EXTSCAN_CONFIG_MAX + 1]; + uint32_t request_id, max_channels; + tWifiBand wifi_band; + QDF_STATUS status; + struct sk_buff *reply_skb; + int ret, len = 0; + + /* ENTER_DEV() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_CONFIG_MAX, data, data_len, + wlan_hdd_extscan_get_valid_channels_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + if (!tb[EXTSCAN_CONFIG_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + request_id = nla_get_u32(tb[EXTSCAN_CONFIG_REQUEST_ID]); + + /* Parse and fetch wifi band */ + if (!tb[EXTSCAN_CONFIG_WIFI_BAND]) { + hdd_err("attr wifi band failed"); + return -EINVAL; + } + wifi_band = nla_get_u32(tb[EXTSCAN_CONFIG_WIFI_BAND]); + if (!tb[EXTSCAN_CONFIG_MAX_CHANNELS]) { + hdd_err("attr max channels failed"); + return -EINVAL; + } + max_channels = nla_get_u32(tb[EXTSCAN_CONFIG_MAX_CHANNELS]); + + if (max_channels > CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("Max channels %d exceeded Valid channel list len %d", + max_channels, CFG_VALID_CHANNEL_LIST_LEN); + return -EINVAL; + } + + hdd_err("Req Id: %u Wifi band: %d Max channels: %d", request_id, + wifi_band, max_channels); + status = sme_get_valid_channels_by_band(hdd_ctx->mac_handle, + wifi_band, chan_list, + &num_channels); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_get_valid_channels_by_band failed (err=%d)", + status); + return -EINVAL; + } + + num_channels = QDF_MIN(num_channels, max_channels); + + if ((QDF_SAP_MODE == adapter->device_mode) || + !strncmp(hdd_get_fwpath(), "ap", 2)) + hdd_remove_passive_channels(wiphy, chan_list, + &num_channels); + + hdd_debug("Number of channels: %d", num_channels); + for (i = 0; i < num_channels; i++) + len += scnprintf(buf + len, sizeof(buf) - len, + "%u ", chan_list[i]); + + hdd_debug("Channels: %s", buf); + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u32) + + sizeof(u32) * + num_channels + + NLMSG_HDRLEN); + + if (reply_skb) { + if (nla_put_u32( + reply_skb, + EXTSCAN_RESULTS_NUM_CHANNELS, + num_channels) || + nla_put( + reply_skb, + EXTSCAN_RESULTS_CHANNELS, + sizeof(u32) * num_channels, chan_list)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + return ret; + } + + hdd_err("valid channels: buffer alloc fail"); + return -EINVAL; +} + +#undef EXTSCAN_CONFIG_MAX +#undef EXTSCAN_CONFIG_REQUEST_ID +#undef EXTSCAN_CONFIG_WIFI_BAND +#undef ETCAN_CONFIG_MAX_CHANNELS +#undef EXTSCAN_RESULTS_NUM_CHANNELS +#undef EXTSCAN_RESULTS_CHANNELS + +/** + * wlan_hdd_cfg80211_extscan_get_valid_channels() - get ext scan valid channels + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_cfg80211_extscan_get_valid_channels( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_get_valid_channels(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#ifdef FEATURE_RADAR_HISTORY +static uint32_t get_radar_history_evt_len(uint32_t count) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += + /* nested attribute hdr QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES */ + nla_total_size(count * + (nla_total_size( + /* channel frequency */ + nla_total_size(sizeof(uint32_t)) + + /* timestamp */ + nla_total_size(sizeof(uint64_t)) + + /* radar detected flag */ + nla_total_size(0)))); + + return data_len; +} + +/** + * __wlan_hdd_cfg80211_get_radar_history () - Get radar history + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_get_radar_history(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + QDF_STATUS status; + struct sk_buff *reply_skb = NULL; + int ret, len; + struct dfs_radar_history *radar_history = NULL; + uint32_t hist_count = 0; + int idx; + struct nlattr *ch_array, *ch_element; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + status = wlansap_query_radar_history(hdd_ctx->mac_handle, + &radar_history, &hist_count); + if (!QDF_IS_STATUS_SUCCESS(status)) + return -EINVAL; + + len = get_radar_history_evt_len(hist_count); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (!reply_skb) { + ret = -ENOMEM; + goto err; + } + + ch_array = nla_nest_start( + reply_skb, QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_ENTRIES); + if (!ch_array) { + ret = -ENOMEM; + goto err; + } + + for (idx = 0; idx < hist_count; idx++) { + ch_element = nla_nest_start(reply_skb, idx); + if (!ch_element) { + ret = -ENOMEM; + goto err; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_FREQ, + radar_history[idx].ch_freq)) { + ret = -ENOMEM; + goto err; + } + + if (wlan_cfg80211_nla_put_u64( + reply_skb, + QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_TIMESTAMP, + radar_history[idx].time)) { + ret = -ENOMEM; + goto err; + } + + if (radar_history[idx].radar_found && + nla_put_flag( + reply_skb, + QCA_WLAN_VENDOR_ATTR_RADAR_HISTORY_DETECTED)) { + ret = -ENOMEM; + goto err; + } + + nla_nest_end(reply_skb, ch_element); + } + nla_nest_end(reply_skb, ch_array); + qdf_mem_free(radar_history); + + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + hdd_debug("get radar history count %d, ret %d", hist_count, ret); + + return ret; +err: + qdf_mem_free(radar_history); + wlan_cfg80211_vendor_free_skb(reply_skb); + hdd_debug("get radar history error %d", ret); + + return ret; +} + +/** + * wlan_hdd_cfg80211_get_radar_history() - get radar history + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int wlan_hdd_cfg80211_get_radar_history(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_radar_history(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define FEATURE_RADAR_HISTORY_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RADAR_HISTORY, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_radar_history, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, +#else +#define FEATURE_RADAR_HISTORY_VENDOR_COMMANDS +#endif + +const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = { + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = is_driver_dfs_capable, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_VALID_CHANNELS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_extscan_get_valid_channels, + vendor_command_policy( + wlan_hdd_extscan_get_valid_channels_policy, + EXTSCAN_PARAM_MAX) + }, +#ifdef WLAN_FEATURE_STATS_EXT + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STATS_EXT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_stats_ext_request, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, +#endif + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_connected_chan_stats_req, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + + FEATURE_EXTSCAN_VENDOR_COMMANDS + + FEATURE_LL_STATS_VENDOR_COMMANDS + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_supported_features, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_scanning_mac_oui, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + + FEATURE_CONCURRENCY_MATRIX_VENDOR_COMMANDS + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_disable_dfs_chan_scan, + vendor_command_policy(wlan_hdd_set_no_dfs_flag_config_policy, + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WISA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_handle_wisa_cmd, + vendor_command_policy(wlan_hdd_wisa_cmd_policy, + QCA_WLAN_VENDOR_ATTR_WISA_MAX) + }, + + FEATURE_STATION_INFO_VENDOR_COMMANDS + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DO_ACS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_do_acs, + vendor_command_policy(wlan_hdd_cfg80211_do_acs_policy, + QCA_WLAN_VENDOR_ATTR_ACS_MAX) + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_features, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_keymgmt_set_key, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_wifi_info, + vendor_command_policy(qca_wlan_vendor_get_wifi_info_policy, + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_configuration_set, + vendor_command_policy(wlan_hdd_wifi_config_policy, + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_configuration_get, + vendor_command_policy(wlan_hdd_wifi_config_policy, + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX) + }, + + FEATURE_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION +#ifdef WLAN_SUPPORT_TWT + FEATURE_VENDOR_SUBCMD_WIFI_CONFIG_TWT +#endif + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ext_roam_params, + vendor_command_policy(wlan_hdd_set_roam_param_policy, + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_RATEMASK_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ratemask_config, + vendor_command_policy(wlan_hdd_set_ratemask_param_policy, + QCA_WLAN_VENDOR_ATTR_RATEMASK_PARAMS_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_wifi_logger_start, + vendor_command_policy( + qca_wlan_vendor_wifi_logger_start_policy, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, + .doit = wlan_hdd_cfg80211_wifi_logger_get_ring_data, + vendor_command_policy( + qca_wlan_vendor_wifi_logger_get_ring_data_policy, + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_preferred_freq_list, + vendor_command_policy( + get_preferred_freq_list_policy, + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_probable_oper_channel, + vendor_command_policy( + set_probable_oper_channel_policy, + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX) + }, + + FEATURE_HANDLE_TSF_VENDOR_COMMANDS + +#ifdef FEATURE_WLAN_TDLS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_CAPABILITIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_tdls_capabilities, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, +#endif +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_offloaded_packets, + vendor_command_policy(offloaded_packet_policy, + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX) + }, +#endif + FEATURE_RSSI_MONITOR_VENDOR_COMMANDS + FEATURE_OEM_DATA_VENDOR_COMMANDS + FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS + +#ifdef WLAN_NS_OFFLOAD + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_ns_offload, + vendor_command_policy(ns_offload_set_policy, + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX) + }, +#endif /* WLAN_NS_OFFLOAD */ + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_LOGGER_FEATURE_SET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_logger_supp_feature, + vendor_command_policy(get_logger_set_policy, + QCA_WLAN_VENDOR_ATTR_LOGGER_MAX) + }, + + FEATURE_TRIGGER_SCAN_VENDOR_COMMANDS + + /* Vendor abort scan */ + FEATURE_ABORT_SCAN_VENDOR_COMMANDS + + /* OCB commands */ + FEATURE_OCB_VENDOR_COMMANDS + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_link_properties, + vendor_command_policy(wlan_hdd_get_link_properties_policy, + QCA_WLAN_VENDOR_ATTR_MAX) + }, + + FEATURE_OTA_TEST_VENDOR_COMMANDS + + FEATURE_LFR_SUBNET_DETECT_VENDOR_COMMANDS + + FEATURE_TX_POWER_VENDOR_COMMANDS + + FEATURE_APF_OFFLOAD_VENDOR_COMMANDS + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_acs_dfs_mode, + vendor_command_policy(wlan_hdd_set_acs_dfs_config_policy, + QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_STA_CONNECT_ROAM_POLICY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_sta_roam_policy, + vendor_command_policy( + wlan_hdd_set_sta_roam_config_policy, + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX) + }, + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_CONCURRENT_POLICY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_concurrent_session_policy, + vendor_command_policy( + wlan_hdd_set_concurrent_session_policy, + QCA_WLAN_VENDOR_ATTR_CONCURRENT_POLICY_MAX) + }, + +#ifdef FEATURE_WLAN_CH_AVOID + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_avoid_freq, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, +#endif + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAP_CONFIG, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_sap_configuration_set, + vendor_command_policy(wlan_hdd_sap_config_policy, + QCA_WLAN_VENDOR_ATTR_SAP_CONFIG_MAX) + }, + + FEATURE_P2P_LISTEN_OFFLOAD_VENDOR_COMMANDS + + FEATURE_SAP_COND_CHAN_SWITCH_VENDOR_COMMANDS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_WAKE_REASON_STATS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_wakelock_stats, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_bus_size, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTERNAL_ACS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_update_vendor_channel, + vendor_command_policy(acs_chan_config_policy, + QCA_WLAN_VENDOR_ATTR_EXTERNAL_ACS_CHANNEL_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SETBAND, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_setband, + vendor_command_policy(setband_policy, QCA_WLAN_VENDOR_ATTR_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GETBAND, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_getband, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAMING, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_fast_roaming, + vendor_command_policy(qca_wlan_vendor_attr, + QCA_WLAN_VENDOR_ATTR_MAX) + }, + FEATURE_DISA_VENDOR_COMMANDS + FEATURE_TDLS_VENDOR_COMMANDS + FEATURE_SAR_LIMITS_VENDOR_COMMANDS + BCN_RECV_FEATURE_VENDOR_COMMANDS + FEATURE_VENDOR_SUBCMD_SET_TRACE_LEVEL +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_ll_stats_ext_set_param, + vendor_command_policy(qca_wlan_vendor_ll_ext_policy, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX) + }, +#endif + FEATURE_VENDOR_SUBCMD_NUD_STATS_SET + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_GET, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_nud_stats, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + + FEATURE_BSS_TRANSITION_VENDOR_COMMANDS + FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS + FEATURE_CFR_VENDOR_COMMANDS + FEATURE_11AX_VENDOR_COMMANDS + + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CHAIN_RSSI, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_get_chain_rssi, + vendor_command_policy(get_chain_rssi_policy, + QCA_WLAN_VENDOR_ATTR_MAX) + }, + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_USABLE_CHANNELS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_usable_channel, + vendor_command_policy(get_usable_channel_policy, + QCA_WLAN_VENDOR_ATTR_MAX) + }, + FEATURE_ACTIVE_TOS_VENDOR_COMMANDS + FEATURE_NAN_VENDOR_COMMANDS + FEATURE_FW_STATE_COMMANDS + FEATURE_COEX_CONFIG_COMMANDS + FEATURE_MPTA_HELPER_COMMANDS + FEATURE_HW_CAPABILITY_COMMANDS + FEATURE_THERMAL_VENDOR_COMMANDS + FEATURE_BTC_CHAIN_MODE_COMMANDS + FEATURE_WMM_COMMANDS + FEATURE_GPIO_CFG_VENDOR_COMMANDS + FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS + FEATURE_RADAR_HISTORY_VENDOR_COMMANDS + FEATURE_AVOID_FREQ_EXT_VENDOR_COMMANDS + FEATURE_MDNS_OFFLOAD_VENDOR_COMMANDS + + FEATURE_GREEN_AP_LOW_LATENCY_PWR_SAVE_COMMANDS + +#if defined(WLAN_FEATURE_PKT_CAPTURE) || defined(WLAN_FEATURE_LOCAL_PKT_CAPTURE) + FEATURE_MONITOR_MODE_VENDOR_COMMANDS +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV | + WIPHY_VENDOR_CMD_NEED_RUNNING, + .doit = wlan_hdd_cfg80211_set_roam_events, + vendor_command_policy(set_roam_events_policy, + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_MAX) + }, +#endif + FEATURE_ROAM_STATS_COMMANDS + FEATURE_WIFI_POS_11AZ_AUTH_COMMANDS + FEATURE_WIFI_POS_SET_SECURE_RANGING_CONTEXT_COMMANDS + FEATURE_MCC_QUOTA_VENDOR_COMMANDS + FEATURE_PEER_FLUSH_VENDOR_COMMANDS + { + .info.vendor_id = QCA_NL80211_VENDOR_ID, + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_RADIO_COMBINATION_MATRIX, + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | + WIPHY_VENDOR_CMD_NEED_NETDEV, + .doit = wlan_hdd_cfg80211_get_radio_combination_matrix, + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) + }, + FEATURE_COAP_OFFLOAD_COMMANDS + FEATURE_ML_LINK_STATE_COMMANDS + FEATURE_AFC_VENDOR_COMMANDS + FEATURE_LL_LT_SAP_VENDOR_COMMANDS + FEATURE_TX_LATENCY_STATS_COMMANDS + FEATURE_REGULATORY_TPC_INFO_VENDOR_COMMANDS +}; + +struct hdd_context *hdd_cfg80211_wiphy_alloc(void) +{ + struct wiphy *wiphy; + struct hdd_context *hdd_ctx; + + hdd_enter(); + + wiphy = wiphy_new(&wlan_hdd_cfg80211_ops, sizeof(*hdd_ctx)); + if (!wiphy) { + hdd_err("failed to allocate wiphy!"); + return NULL; + } + + hdd_ctx = wiphy_priv(wiphy); + hdd_ctx->wiphy = wiphy; + + return hdd_ctx; +} + +int wlan_hdd_cfg80211_update_band(struct hdd_context *hdd_ctx, + struct wiphy *wiphy, + enum band_info new_band) +{ + int i, j; + enum channel_state channel_state; + + hdd_enter(); + + for (i = 0; i < HDD_NUM_NL80211_BANDS; i++) { + + if (!wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + channel_state = wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, + band->channels[j].center_freq, + REG_CURRENT_PWR_MODE); + + if (HDD_NL80211_BAND_2GHZ == i && + BAND_5G == new_band) { + /* 5G only */ +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + /* Enable Social channels for P2P */ + if (WLAN_HDD_IS_SOCIAL_CHANNEL + (band->channels[j].center_freq) + && CHANNEL_STATE_ENABLE == + channel_state) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + else +#endif + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } else if (HDD_NL80211_BAND_5GHZ == i && + BAND_2G == new_band) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + + if (CHANNEL_STATE_DISABLE != channel_state) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + } + } + return 0; +} + +#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +static void wlan_hdd_cfg80211_scan_randomization_init(struct wiphy *wiphy) +{ + wiphy->features |= NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR; +} +#else +static void wlan_hdd_cfg80211_scan_randomization_init(struct wiphy *wiphy) +{ +} +#endif + +#define WLAN_HDD_MAX_NUM_CSA_COUNTERS 2 + +#if defined(CFG80211_RAND_TA_FOR_PUBLIC_ACTION_FRAME) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) +/** + * wlan_hdd_cfg80211_action_frame_randomization_init() - Randomize SA of MA + * frames + * @wiphy: Pointer to wiphy + * + * This function is used to indicate the support of source mac address + * randomization of management action frames + * + * Return: None + */ +static void +wlan_hdd_cfg80211_action_frame_randomization_init(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MGMT_TX_RANDOM_TA); +} +#else +static void +wlan_hdd_cfg80211_action_frame_randomization_init(struct wiphy *wiphy) +{ +} +#endif + +#if defined(WLAN_FEATURE_FILS_SK) && \ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) +static void wlan_hdd_cfg80211_set_wiphy_fils_feature(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_SK_OFFLOAD); +} +#else +static void wlan_hdd_cfg80211_set_wiphy_fils_feature(struct wiphy *wiphy) +{ +} +#endif + +#if defined (CFG80211_SCAN_DBS_CONTROL_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)) +static void wlan_hdd_cfg80211_set_wiphy_scan_flags(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_LOW_SPAN_SCAN); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_LOW_POWER_SCAN); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_HIGH_ACCURACY_SCAN); +} +#else +static void wlan_hdd_cfg80211_set_wiphy_scan_flags(struct wiphy *wiphy) +{ +} +#endif + +#if defined(CFG80211_BIGTK_CONFIGURATION_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +static void wlan_hdd_cfg80211_set_bigtk_flags(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); +} +#else +static void wlan_hdd_cfg80211_set_bigtk_flags(struct wiphy *wiphy) +{ +} +#endif + +#if defined(CFG80211_OCV_CONFIGURATION_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)) +static void wlan_hdd_cfg80211_set_ocv_flags(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION); +} +#else +static void wlan_hdd_cfg80211_set_ocv_flags(struct wiphy *wiphy) +{ +} +#endif + +#if defined(CFG80211_SCAN_OCE_CAPABILITY_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) +static void wlan_hdd_cfg80211_set_wiphy_oce_scan_flags(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE); + wiphy_ext_feature_set( + wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION); +} +#else +static void wlan_hdd_cfg80211_set_wiphy_oce_scan_flags(struct wiphy *wiphy) +{ +} +#endif + +#if defined(WLAN_FEATURE_SAE) && \ + (defined(CFG80211_EXTERNAL_AUTH_SUPPORT) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) +/** + * wlan_hdd_cfg80211_set_wiphy_sae_feature() - Indicates support of SAE feature + * @wiphy: Pointer to wiphy + * + * This function is used to indicate the support of SAE + * + * Return: None + */ +static void wlan_hdd_cfg80211_set_wiphy_sae_feature(struct wiphy *wiphy) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + if (ucfg_fwol_get_sae_enable(hdd_ctx->psoc)) + wiphy->features |= NL80211_FEATURE_SAE; +} +#else +static void wlan_hdd_cfg80211_set_wiphy_sae_feature(struct wiphy *wiphy) +{ +} +#endif + +#if defined(CFG80211_SAE_AUTH_TA_ADDR_SUPPORT) +static void wlan_hdd_cfg8011_sae_auth_tx_randoam_ta(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AUTH_TX_RANDOM_TA); +} +#else +static void wlan_hdd_cfg8011_sae_auth_tx_randoam_ta(struct wiphy *wiphy) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) || \ + defined(CFG80211_DFS_OFFLOAD_BACKPORT) +static void wlan_hdd_cfg80211_set_dfs_offload_feature(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD); +} +#else +static void wlan_hdd_cfg80211_set_dfs_offload_feature(struct wiphy *wiphy) +{ + wiphy->flags |= WIPHY_FLAG_DFS_OFFLOAD; +} +#endif + +#ifdef WLAN_FEATURE_DSRC +static void wlan_hdd_get_num_dsrc_ch_and_len(struct hdd_config *hdd_cfg, + int *num_ch, int *ch_len) +{ + *num_ch = QDF_ARRAY_SIZE(hdd_channels_dot11p); + *ch_len = sizeof(hdd_channels_dot11p); +} + +static void wlan_hdd_copy_dsrc_ch(char *ch_ptr, int ch_arr_len) +{ + if (!ch_arr_len) + return; + qdf_mem_copy(ch_ptr, &hdd_channels_dot11p[0], ch_arr_len); +} + +static void wlan_hdd_get_num_srd_ch_and_len(struct hdd_config *hdd_cfg, + int *num_ch, int *ch_len) +{ + *num_ch = 0; + *ch_len = 0; +} + +static void wlan_hdd_copy_srd_ch(char *ch_ptr, int ch_arr_len) +{ +} + +/** + * wlan_hdd_populate_5dot9_chan_info() - Populate 5.9 GHz chan info in hdd + * context + * @hdd_ctx: pointer to hdd context + * @index: 5.9 GHz channel beginning index in chan_info of @hdd_ctx + * + * Return: Number of 5.9 GHz channels populated + */ +static uint32_t +wlan_hdd_populate_5dot9_chan_info(struct hdd_context *hdd_ctx, uint32_t index) +{ + return 0; +} + +#else + +static void wlan_hdd_get_num_dsrc_ch_and_len(struct hdd_config *hdd_cfg, + int *num_ch, int *ch_len) +{ + *num_ch = 0; + *ch_len = 0; +} + +static void wlan_hdd_copy_dsrc_ch(char *ch_ptr, int ch_arr_len) +{ +} + +static void wlan_hdd_get_num_srd_ch_and_len(struct hdd_config *hdd_cfg, + int *num_ch, int *ch_len) +{ + *num_ch = QDF_ARRAY_SIZE(hdd_5dot9_ghz_ch); + *ch_len = sizeof(hdd_5dot9_ghz_ch); +} + +static void wlan_hdd_copy_srd_ch(char *ch_ptr, int ch_arr_len) +{ + if (!ch_arr_len) + return; + qdf_mem_copy(ch_ptr, &hdd_5dot9_ghz_ch[0], ch_arr_len); +} + +/** + * wlan_hdd_populate_5dot9_chan_info() - Populate 5.9 GHz chan info in hdd + * context + * @hdd_ctx: pointer to hdd context + * @index: 5.9 GHz channel beginning index in chan_info of @hdd_ctx + * + * Return: Number of 5.9 GHz channels populated + */ +static uint32_t +wlan_hdd_populate_5dot9_chan_info(struct hdd_context *hdd_ctx, uint32_t index) +{ + uint32_t num_5dot9_ch, i; + struct scan_chan_info *chan_info; + + num_5dot9_ch = QDF_ARRAY_SIZE(hdd_5dot9_ghz_ch); + chan_info = hdd_ctx->chan_info; + + for (i = 0; i < num_5dot9_ch; i++) + chan_info[index + i].freq = hdd_5dot9_ghz_ch[i].center_freq; + + return num_5dot9_ch; +} + +#endif + +#if defined(WLAN_FEATURE_11AX) && \ + (defined(CFG80211_SBAND_IFTYPE_DATA_BACKPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))) +#if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \ + (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)) +static QDF_STATUS +wlan_hdd_iftype_data_alloc_6ghz(struct hdd_context *hdd_ctx) +{ + hdd_ctx->iftype_data_6g = + qdf_mem_malloc(sizeof(*hdd_ctx->iftype_data_6g) * + EHT_OPMODE_SUPPORTED); + + if (!hdd_ctx->iftype_data_6g) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} + +static void +wlan_hdd_iftype_data_mem_free_6ghz(struct hdd_context *hdd_ctx) +{ + qdf_mem_free(hdd_ctx->iftype_data_6g); + hdd_ctx->iftype_data_6g = NULL; +} +#else +static inline QDF_STATUS +wlan_hdd_iftype_data_alloc_6ghz(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +wlan_hdd_iftype_data_mem_free_6ghz(struct hdd_context *hdd_ctx) +{ +} +#endif + +static QDF_STATUS +wlan_hdd_iftype_data_alloc(struct hdd_context *hdd_ctx) +{ + hdd_ctx->iftype_data_2g = + qdf_mem_malloc(sizeof(*hdd_ctx->iftype_data_2g) * + EHT_OPMODE_SUPPORTED); + + if (!hdd_ctx->iftype_data_2g) + return QDF_STATUS_E_NOMEM; + + hdd_ctx->iftype_data_5g = + qdf_mem_malloc(sizeof(*hdd_ctx->iftype_data_5g) * + EHT_OPMODE_SUPPORTED); + if (!hdd_ctx->iftype_data_5g) { + qdf_mem_free(hdd_ctx->iftype_data_2g); + hdd_ctx->iftype_data_2g = NULL; + return QDF_STATUS_E_NOMEM; + } + + if (QDF_IS_STATUS_ERROR(wlan_hdd_iftype_data_alloc_6ghz(hdd_ctx))) { + qdf_mem_free(hdd_ctx->iftype_data_5g); + qdf_mem_free(hdd_ctx->iftype_data_2g); + hdd_ctx->iftype_data_2g = NULL; + hdd_ctx->iftype_data_5g = NULL; + return QDF_STATUS_E_NOMEM; + } + + return QDF_STATUS_SUCCESS; +} + +static void +wlan_hdd_iftype_data_mem_free(struct hdd_context *hdd_ctx) +{ + wlan_hdd_iftype_data_mem_free_6ghz(hdd_ctx); + qdf_mem_free(hdd_ctx->iftype_data_5g); + qdf_mem_free(hdd_ctx->iftype_data_2g); + hdd_ctx->iftype_data_5g = NULL; + hdd_ctx->iftype_data_2g = NULL; +} +#else +static QDF_STATUS +wlan_hdd_iftype_data_alloc(struct hdd_context *hdd_ctx) + +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +wlan_hdd_iftype_data_mem_free(struct hdd_context *hdd_ctx) +{ +} +#endif + +#if defined(WLAN_FEATURE_NAN) && \ + (KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE) +static void wlan_hdd_set_nan_if_mode(struct wiphy *wiphy) +{ + wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN); +} +#else +static void wlan_hdd_set_nan_if_mode(struct wiphy *wiphy) +{ +} +#endif + +#if defined(WLAN_FEATURE_NAN) && \ + (KERNEL_VERSION(4, 14, 0) <= LINUX_VERSION_CODE) +static void wlan_hdd_set_nan_supported_bands(struct wiphy *wiphy) +{ + wiphy->nan_supported_bands = + BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ); +} +#else +static void wlan_hdd_set_nan_supported_bands(struct wiphy *wiphy) +{ +} +#endif + +#if defined(WLAN_FEATURE_NAN) && defined(WLAN_EXT_FEATURE_SECURE_NAN) +/** + * wlan_hdd_set_nan_secure_mode - Populate Secure NAN supported by driver + * @wiphy: wiphy + * + * Return: void + */ +static void wlan_hdd_set_nan_secure_mode(struct wiphy *wiphy) +{ + if (sme_is_feature_supported_by_fw(SECURE_NAN)) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SECURE_NAN); +} +#else +static void wlan_hdd_set_nan_secure_mode(struct wiphy *wiphy) +{ +} +#endif + +/** + * wlan_hdd_update_akm_suit_info() - Populate akm suits supported by driver + * @wiphy: wiphy + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) || \ + defined(CFG80211_IFTYPE_AKM_SUITES_SUPPORT) +static void +wlan_hdd_update_akm_suit_info(struct wiphy *wiphy) +{ + wiphy->iftype_akm_suites = wlan_hdd_akm_suites; + wiphy->num_iftype_akm_suites = QDF_ARRAY_SIZE(wlan_hdd_akm_suites); +} +#else +static void +wlan_hdd_update_akm_suit_info(struct wiphy *wiphy) +{ +} +#endif + +#ifdef CFG80211_CTRL_FRAME_SRC_ADDR_TA_ADDR +static void wlan_hdd_update_eapol_over_nl80211_flags(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH); +} +#else +static void wlan_hdd_update_eapol_over_nl80211_flags(struct wiphy *wiphy) +{ +} +#endif + +#ifdef WLAN_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA +/** + * wlan_hdd_set_auth_deauth_random_ta_feature_flag() - set feature flag for + * random address for auth and deauth frames to the kernel. + * @wiphy: wiphy + * + * Return: void + */ +static void wlan_hdd_set_auth_deauth_random_ta_feature_flag(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA); +} +#else +static void wlan_hdd_set_auth_deauth_random_ta_feature_flag(struct wiphy *wiphy) +{ +} +#endif + +#ifdef CFG80211_MULTI_AKM_CONNECT_SUPPORT +static void +wlan_hdd_update_max_connect_akm(struct wiphy *wiphy) +{ + wiphy->max_num_akm_suites = WLAN_CM_MAX_CONNECT_AKMS; +} +#else +static void +wlan_hdd_update_max_connect_akm(struct wiphy *wiphy) +{ +} +#endif + +#ifdef NL80211_EXT_FEATURE_PUNCT_SUPPORT +/** + * wlan_hdd_set_ext_feature_punct() - set feature flag for puncture + * @wiphy: wiphy + * + * Return: void + */ +static void wlan_hdd_set_ext_feature_punct(struct wiphy *wiphy) +{ + hdd_debug("enable puncture cap"); + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_PUNCT); +} +#else +static inline void wlan_hdd_set_ext_feature_punct(struct wiphy *wiphy) +{ +} +#endif + +/* + * FUNCTION: wlan_hdd_cfg80211_init + * This function is called by hdd_wlan_startup() + * during initialization. + * This function is used to initialize and register wiphy structure. + */ +int wlan_hdd_cfg80211_init(struct device *dev, + struct wiphy *wiphy, struct hdd_config *config) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + uint32_t *cipher_suites; + hdd_enter(); + + /* Now bind the underlying wlan device with wiphy */ + set_wiphy_dev(wiphy, dev); + + wiphy->mgmt_stypes = wlan_hdd_txrx_stypes; + wlan_hdd_update_akm_suit_info(wiphy); + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME + | WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD + | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL +#ifdef FEATURE_WLAN_STA_4ADDR_SCHEME + | WIPHY_FLAG_4ADDR_STATION +#endif + | WIPHY_FLAG_OFFCHAN_TX + | WIPHY_FLAG_NETNS_OK; + + if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_SUSPEND_WOW) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wiphy->wowlan = &wowlan_support_cfg80211_init; +#else + wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT; + wiphy->wowlan.n_patterns = WOWL_MAX_PTRNS_ALLOWED; + wiphy->wowlan.pattern_min_len = 1; + wiphy->wowlan.pattern_max_len = WOWL_PTRN_MAX_SIZE; +#endif + } + +#ifdef FEATURE_WLAN_TDLS + wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS + | WIPHY_FLAG_TDLS_EXTERNAL_SETUP; +#endif + + wlan_hdd_cfg80211_set_wiphy_scan_flags(wiphy); + + wlan_scan_cfg80211_add_connected_pno_support(wiphy); + + wiphy->max_scan_ssids = MAX_SCAN_SSID; + + wiphy->max_scan_ie_len = SIR_MAC_MAX_ADD_IE_LENGTH; + + wiphy->max_acl_mac_addrs = MAX_ACL_MAC_ADDRESS; + + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) + | BIT(NL80211_IFTYPE_P2P_CLIENT) + | BIT(NL80211_IFTYPE_P2P_GO) + | BIT(NL80211_IFTYPE_AP) + | BIT(NL80211_IFTYPE_MONITOR); + + wlan_hdd_set_nan_if_mode(wiphy); + + /* + * In case of static linked driver at the time of driver unload, + * module exit doesn't happens. Module cleanup helps in cleaning + * of static memory. + * If driver load happens statically, at the time of driver unload, + * wiphy flags don't get reset because of static memory. + * It's better not to store channel in static memory. + * The memory is for channels of struct wiphy and shouldn't be + * released during stop modules. So if it's allocated in active + * domain, the memory leak detector would catch the leak during + * stop modules. To avoid this,alloc in init domain in advance. + */ + hdd_ctx->channels_2ghz = qdf_mem_malloc(band_2_ghz_channels_size); + if (!hdd_ctx->channels_2ghz) + return -ENOMEM; + + hdd_ctx->channels_5ghz = qdf_mem_malloc(band_5_ghz_channels_size); + if (!hdd_ctx->channels_5ghz) + goto mem_fail_5g; + + if (QDF_IS_STATUS_ERROR(wlan_hdd_iftype_data_alloc(hdd_ctx))) + goto mem_fail_iftype_data; + + /*Initialise the supported cipher suite details */ + if (ucfg_fwol_get_gcmp_enable(hdd_ctx->psoc)) { + cipher_suites = qdf_mem_malloc(sizeof(hdd_cipher_suites) + + sizeof(hdd_gcmp_cipher_suits)); + if (!cipher_suites) + goto mem_fail_cipher_suites; + wiphy->n_cipher_suites = QDF_ARRAY_SIZE(hdd_cipher_suites) + + QDF_ARRAY_SIZE(hdd_gcmp_cipher_suits); + qdf_mem_copy(cipher_suites, &hdd_cipher_suites, + sizeof(hdd_cipher_suites)); + qdf_mem_copy(cipher_suites + QDF_ARRAY_SIZE(hdd_cipher_suites), + &hdd_gcmp_cipher_suits, + sizeof(hdd_gcmp_cipher_suits)); + } else { + cipher_suites = qdf_mem_malloc(sizeof(hdd_cipher_suites)); + if (!cipher_suites) + goto mem_fail_cipher_suites; + wiphy->n_cipher_suites = QDF_ARRAY_SIZE(hdd_cipher_suites); + qdf_mem_copy(cipher_suites, &hdd_cipher_suites, + sizeof(hdd_cipher_suites)); + } + wiphy->cipher_suites = cipher_suites; + cipher_suites = NULL; + /*signal strength in mBm (100*dBm) */ + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->max_remain_on_channel_duration = MAX_REMAIN_ON_CHANNEL_DURATION; + + wiphy->n_vendor_commands = ARRAY_SIZE(hdd_wiphy_vendor_commands); + wiphy->vendor_commands = hdd_wiphy_vendor_commands; + + wiphy->vendor_events = wlan_hdd_cfg80211_vendor_events; + wiphy->n_vendor_events = ARRAY_SIZE(wlan_hdd_cfg80211_vendor_events); + +#ifdef QCA_HT_2040_COEX + wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; +#endif + wiphy->features |= NL80211_FEATURE_INACTIVITY_TIMER; + + wiphy->features |= NL80211_FEATURE_VIF_TXPOWER; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) || \ + defined(CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT) + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT); +#endif + + hdd_add_channel_switch_support(&wiphy->flags); + wiphy->max_num_csa_counters = WLAN_HDD_MAX_NUM_CSA_COUNTERS; + + wlan_hdd_update_max_connect_akm(wiphy); + + wlan_hdd_cfg80211_action_frame_randomization_init(wiphy); + wlan_hdd_cfg8011_sae_auth_tx_randoam_ta(wiphy); + + wlan_hdd_set_nan_supported_bands(wiphy); + + wlan_hdd_update_eapol_over_nl80211_flags(wiphy); + + wlan_hdd_set_auth_deauth_random_ta_feature_flag(wiphy); + wlan_hdd_set_ext_feature_punct(wiphy); + + hdd_exit(); + return 0; + +mem_fail_cipher_suites: + wlan_hdd_iftype_data_mem_free(hdd_ctx); +mem_fail_iftype_data: + qdf_mem_free(hdd_ctx->channels_5ghz); + hdd_ctx->channels_5ghz = NULL; +mem_fail_5g: + hdd_err("Not enough memory to allocate channels"); + qdf_mem_free(hdd_ctx->channels_2ghz); + hdd_ctx->channels_2ghz = NULL; + + return -ENOMEM; +} + +/** + * wlan_hdd_cfg80211_deinit() - Deinit cfg80211 + * @wiphy: the wiphy to validate against + * + * this function deinit cfg80211 and cleanup the + * memory allocated in wlan_hdd_cfg80211_init also + * reset the global reg params. + * + * Return: void + */ +void wlan_hdd_cfg80211_deinit(struct wiphy *wiphy) +{ + int i; + const uint32_t *cipher_suites; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + for (i = 0; i < HDD_NUM_NL80211_BANDS; i++) { + if (wiphy->bands[i] && + (wiphy->bands[i]->channels)) + wiphy->bands[i]->channels = NULL; + } + wlan_hdd_iftype_data_mem_free(hdd_ctx); + qdf_mem_free(hdd_ctx->channels_5ghz); + qdf_mem_free(hdd_ctx->channels_2ghz); + hdd_ctx->channels_2ghz = NULL; + hdd_ctx->channels_5ghz = NULL; + + cipher_suites = wiphy->cipher_suites; + wiphy->cipher_suites = NULL; + wiphy->n_cipher_suites = 0; + qdf_mem_free((uint32_t *)cipher_suites); + cipher_suites = NULL; + hdd_reset_global_reg_params(); +} + +/** + * wlan_hdd_update_ht_cap() - update HT capabilities for supported bands + * @hdd_ctx: HDD context + * + * this function will update HT capabilities for supported bands + * + * Return: void + */ +static void wlan_hdd_update_ht_cap(struct hdd_context *hdd_ctx) +{ + struct mlme_ht_capabilities_info ht_cap_info = {0}; + QDF_STATUS status; + uint32_t channel_bonding_mode; + struct ieee80211_supported_band *band_2g; + struct ieee80211_supported_band *band_5g; + uint8_t i; + + status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, &ht_cap_info); + if (QDF_STATUS_SUCCESS != status) + hdd_err("could not get HT capability info"); + + band_2g = hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]; + band_5g = hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]; + + if (band_2g) { + if (ht_cap_info.tx_stbc) + band_2g->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; + + if (!sme_is_feature_supported_by_fw(DOT11AC)) { + band_2g->vht_cap.vht_supported = 0; + band_2g->vht_cap.cap = 0; + } + + if (!ht_cap_info.short_gi_20_mhz) + band_2g->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + + for (i = 0; i < hdd_ctx->num_rf_chains; i++) + band_2g->ht_cap.mcs.rx_mask[i] = 0xff; + + /* + * According to mcs_nss HT MCS parameters highest data rate for + * Nss = 1 is 150 Mbps + */ + band_2g->ht_cap.mcs.rx_highest = + cpu_to_le16(150 * hdd_ctx->num_rf_chains); + } + + if (band_5g) { + if (ht_cap_info.tx_stbc) + band_5g->ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC; + + if (!sme_is_feature_supported_by_fw(DOT11AC)) { + band_5g->vht_cap.vht_supported = 0; + band_5g->vht_cap.cap = 0; + } + + if (!ht_cap_info.short_gi_20_mhz) + band_5g->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_20; + + if (!ht_cap_info.short_gi_40_mhz) + band_5g->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40; + + ucfg_mlme_get_channel_bonding_5ghz(hdd_ctx->psoc, + &channel_bonding_mode); + if (!channel_bonding_mode) + band_5g->ht_cap.cap &= + ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + + for (i = 0; i < hdd_ctx->num_rf_chains; i++) + band_5g->ht_cap.mcs.rx_mask[i] = 0xff; + /* + * According to mcs_nss HT MCS parameters highest data rate for + * Nss = 1 is 150 Mbps + */ + band_5g->ht_cap.mcs.rx_highest = + cpu_to_le16(150 * hdd_ctx->num_rf_chains); + } +} + +/** + * wlan_hdd_update_band_cap_in_wiphy() - update channel flags based on band cap + * @hdd_ctx: HDD context + * + * This function updates the channel flags based on the band capability set + * in the MLME CFG + * + * Return: void + */ +static void wlan_hdd_update_band_cap_in_wiphy(struct hdd_context *hdd_ctx) +{ + int i, j; + uint32_t band_capability; + QDF_STATUS status; + struct ieee80211_supported_band *band; + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get MLME Band Capability"); + return; + } + + for (i = 0; i < HDD_NUM_NL80211_BANDS; i++) { + if (!hdd_ctx->wiphy->bands[i]) + continue; + + for (j = 0; j < hdd_ctx->wiphy->bands[i]->n_channels; j++) { + band = hdd_ctx->wiphy->bands[i]; + + if (HDD_NL80211_BAND_2GHZ == i && + BIT(REG_BAND_5G) == band_capability) { + /* 5G only */ +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY + /* Enable social channels for P2P */ + if (WLAN_HDD_IS_SOCIAL_CHANNEL + (band->channels[j].center_freq)) + band->channels[j].flags &= + ~IEEE80211_CHAN_DISABLED; + else +#endif + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } else if (HDD_NL80211_BAND_5GHZ == i && + BIT(REG_BAND_2G) == band_capability) { + /* 2G only */ + band->channels[j].flags |= + IEEE80211_CHAN_DISABLED; + continue; + } + } + } +} + +#ifdef FEATURE_WLAN_ESE +/** + * wlan_hdd_update_lfr_wiphy() - update LFR flag based on configures + * @hdd_ctx: HDD context + * + * This function updates the LFR flag based on LFR configures + * + * Return: void + */ +static void wlan_hdd_update_lfr_wiphy(struct hdd_context *hdd_ctx) +{ + bool fast_transition_enabled; + bool lfr_enabled; + bool ese_enabled; + bool roam_offload; + + ucfg_mlme_is_fast_transition_enabled(hdd_ctx->psoc, + &fast_transition_enabled); + ucfg_mlme_is_lfr_enabled(hdd_ctx->psoc, &lfr_enabled); + ucfg_mlme_is_ese_enabled(hdd_ctx->psoc, &ese_enabled); + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &roam_offload); + if (fast_transition_enabled || lfr_enabled || ese_enabled || + roam_offload) + hdd_ctx->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +} +#else +static void wlan_hdd_update_lfr_wiphy(struct hdd_context *hdd_ctx) +{ + bool fast_transition_enabled; + bool lfr_enabled; + bool roam_offload; + + ucfg_mlme_is_fast_transition_enabled(hdd_ctx->psoc, + &fast_transition_enabled); + ucfg_mlme_is_lfr_enabled(hdd_ctx->psoc, &lfr_enabled); + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &roam_offload); + if (fast_transition_enabled || lfr_enabled || roam_offload) + hdd_ctx->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM; +} +#endif + +#if defined (CFG80211_SA_QUERY_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)) +/** + * wlan_hdd_set_sa_query_offload_wiphy() - set sa query offload cap in sme cap + * @hdd_ctx: HDD context + * + * This function set sa query offload cap for ap sme capabilities in wiphy + * + * Return: void + */ +static void wlan_hdd_set_sa_query_offload_wiphy(struct hdd_context *hdd_ctx) +{ + hdd_ctx->wiphy->ap_sme_capa |= NL80211_AP_SME_SA_QUERY_OFFLOAD; +} + +/** + * wlan_hdd_update_ap_sme_cap_wiphy() - update ap sme capabilities in wiphy + * @hdd_ctx: HDD context + * + * This function update ap sme capabilities in wiphy + * + * Return: void + */ +static void wlan_hdd_update_ap_sme_cap_wiphy(struct hdd_context *hdd_ctx) +{ + wlan_hdd_set_sa_query_offload_wiphy(hdd_ctx); +} +#else +static void wlan_hdd_update_ap_sme_cap_wiphy(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +static inline +void wlan_hdd_set_mlo_wiphy_ext_feature(struct wiphy *wiphy, + struct hdd_context *hdd_ctx) +{ + bool eht_capab; + + wlan_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (!eht_capab) + return; + + wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; +} +#else +static inline +void wlan_hdd_set_mlo_wiphy_ext_feature(struct wiphy *wiphy, + struct hdd_context *hdd_ctx) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) +static inline +void wlan_hdd_set_ext_kek_kck_support(struct wiphy *wiphy) +{ + wiphy->flags |= WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK; +} +#else +static inline +void wlan_hdd_set_ext_kek_kck_support(struct wiphy *wiphy) +{ +} +#endif + +#ifdef NL80211_KCK_EXT_LEN_32 +static inline +void wlan_hdd_set_32bytes_kck_support(struct wiphy *wiphy) +{ + wiphy->flags |= WIPHY_FLAG_SUPPORTS_EXT_KCK_32; +} +#else +static inline +void wlan_hdd_set_32bytes_kck_support(struct wiphy *wiphy) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) +static void wlan_hdd_set_vlan_offload(struct hdd_context *hdd_ctx) +{ + if (ucfg_mlme_is_multipass_sap(hdd_ctx->psoc)) + wiphy_ext_feature_set(hdd_ctx->wiphy, + NL80211_EXT_FEATURE_VLAN_OFFLOAD); +} +#else +static void wlan_hdd_set_vlan_offload(struct hdd_context *hdd_ctx) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) +static void wlan_hdd_set_mfp_optional(struct wiphy *wiphy) +{ + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MFP_OPTIONAL); +} +#else +static void wlan_hdd_set_mfp_optional(struct wiphy *wiphy) +{ +} +#endif + +/** + * wlan_hdd_iface_debug_string() - This API converts IFACE type to string + * @iface_type: interface type + * + * Return: name string + */ +static char *wlan_hdd_iface_debug_string(uint32_t iface_type) +{ + if (iface_type == BIT(NL80211_IFTYPE_STATION)) + return "STA"; + else if (iface_type == BIT(NL80211_IFTYPE_AP)) + return "SAP"; + else if (iface_type == (BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO))) + return "(P2P_CLI or P2P_GO)"; + else if (iface_type == BIT(NL80211_IFTYPE_P2P_CLIENT)) + return "P2P_CLIENT"; + else if (iface_type == BIT(NL80211_IFTYPE_P2P_GO)) + return "P2P_GO"; + else if (iface_type == BIT(NL80211_IFTYPE_NAN)) + return "NAN"; + else if (iface_type == BIT(NL80211_IFTYPE_MONITOR)) + return "MONITOR"; + + return "invalid iface"; +} + +#define IFACE_DUMP_SIZE 100 +/** + * wlan_hdd_dump_iface_combinations() - This API prints the IFACE combinations + * @num: number of combinations + * @combination: pointer to iface combination structure + * + * Return: void + */ +static void wlan_hdd_dump_iface_combinations(uint32_t num, + const struct ieee80211_iface_combination *combination) +{ + int i, j, k; + char buf[IFACE_DUMP_SIZE] = {0}; + uint8_t len = 0; + + hdd_debug("max combinations %d", num); + + for (i = 0; i < num; i++) { + for (j = 0; j < combination[i].n_limits; j++) { + for (k = 0; k < combination[i].limits[j].max; k++) { + if (combination[i].limits[j].types) + len += qdf_scnprintf(buf + len, + IFACE_DUMP_SIZE - len, + k == 0 && j == 0 ? "%s" : "+%s", + wlan_hdd_iface_debug_string( + combination[i].limits[j].types)); + } + } + + hdd_nofl_debug("iface combination[%d]: %s", i, buf); + len = 0; + } +} + +/* + * In this function, wiphy structure is updated after QDF + * initialization. In wlan_hdd_cfg80211_init, only the + * default values will be initialized. The final initialization + * of all required members can be done here. + */ +void wlan_hdd_update_wiphy(struct hdd_context *hdd_ctx) +{ + int value = 0; + bool fils_enabled, mac_spoofing_enabled; + bool dfs_master_capable = true, is_oce_sta_enabled = false; + QDF_STATUS status; + struct wiphy *wiphy = hdd_ctx->wiphy; + uint8_t allow_mcc_go_diff_bi = 0, enable_mcc = 0; + bool is_bigtk_supported; + bool is_ocv_supported; + uint8_t iface_num; + bool dbs_one_by_one, dbs_two_by_two; + + if (!wiphy) { + hdd_err("Invalid wiphy"); + return; + } + ucfg_mlme_get_sap_max_peers(hdd_ctx->psoc, &value); + hdd_ctx->wiphy->max_ap_assoc_sta = value; + wlan_hdd_update_ht_cap(hdd_ctx); + wlan_hdd_update_band_cap_in_wiphy(hdd_ctx); + wlan_hdd_update_lfr_wiphy(hdd_ctx); + wlan_hdd_update_ap_sme_cap_wiphy(hdd_ctx); + + fils_enabled = 0; + status = ucfg_mlme_get_fils_enabled_info(hdd_ctx->psoc, + &fils_enabled); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not get fils enabled info"); + if (fils_enabled) + wlan_hdd_cfg80211_set_wiphy_fils_feature(wiphy); + + status = ucfg_mlme_get_dfs_master_capability(hdd_ctx->psoc, + &dfs_master_capable); + if (QDF_IS_STATUS_SUCCESS(status) && dfs_master_capable) + wlan_hdd_cfg80211_set_dfs_offload_feature(wiphy); + + + status = ucfg_mlme_get_bigtk_support(hdd_ctx->psoc, + &is_bigtk_supported); + + if (QDF_IS_STATUS_SUCCESS(status) && is_bigtk_supported) + wlan_hdd_cfg80211_set_bigtk_flags(wiphy); + + status = ucfg_mlme_get_ocv_support(hdd_ctx->psoc, + &is_ocv_supported); + if (QDF_IS_STATUS_SUCCESS(status) && is_ocv_supported) + wlan_hdd_cfg80211_set_ocv_flags(wiphy); + + status = ucfg_mlme_get_oce_sta_enabled_info(hdd_ctx->psoc, + &is_oce_sta_enabled); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not get OCE STA enable info"); + if (is_oce_sta_enabled) + wlan_hdd_cfg80211_set_wiphy_oce_scan_flags(wiphy); + + wlan_hdd_cfg80211_set_wiphy_sae_feature(wiphy); + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_allow_mcc_go_diff_bi(hdd_ctx->psoc, + &allow_mcc_go_diff_bi)) + hdd_err("can't get mcc_go_diff_bi value, use default"); + + if (QDF_STATUS_SUCCESS != + ucfg_mlme_get_mcc_feature(hdd_ctx->psoc, &enable_mcc)) + hdd_err("can't get enable_mcc value, use default"); + + if (hdd_ctx->config->advertise_concurrent_operation) { + if (enable_mcc) { + int i; + + for (i = 0; + i < ARRAY_SIZE(wlan_hdd_iface_combination); + i++) { + if (!allow_mcc_go_diff_bi) + wlan_hdd_iface_combination[i]. + beacon_int_infra_match = true; + } + } + + status = ucfg_policy_mgr_get_dbs_hw_modes(hdd_ctx->psoc, + &dbs_one_by_one, + &dbs_two_by_two); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("HW mode failure"); + return; + } + + if (!ucfg_policy_mgr_is_fw_supports_dbs(hdd_ctx->psoc)) { + /* Update IFACE combination for non-DBS target */ + wiphy->iface_combinations = + wlan_hdd_non_dbs_iface_combination; + iface_num = + ARRAY_SIZE(wlan_hdd_non_dbs_iface_combination); + } else if (dbs_one_by_one && !dbs_two_by_two) { + /* Update IFACE combination for 1x1 DBS target */ + wiphy->iface_combinations = + wlan_hdd_derived_combination; + iface_num = ARRAY_SIZE(wlan_hdd_derived_combination); + } else { + /* Update IFACE combination for DBS target */ + wiphy->iface_combinations = wlan_hdd_iface_combination; + iface_num = ARRAY_SIZE(wlan_hdd_iface_combination); + } + + wiphy->n_iface_combinations = iface_num; + + wlan_hdd_dump_iface_combinations(wiphy->n_iface_combinations, + wiphy->iface_combinations); + } + + mac_spoofing_enabled = ucfg_scan_is_mac_spoofing_enabled(hdd_ctx->psoc); + if (mac_spoofing_enabled) + wlan_hdd_cfg80211_scan_randomization_init(wiphy); + + wlan_wifi_pos_cfg80211_set_wiphy_ext_feature(wiphy, hdd_ctx->psoc); + wlan_hdd_set_mlo_wiphy_ext_feature(wiphy, hdd_ctx); + wlan_hdd_set_ext_kek_kck_support(wiphy); + wlan_hdd_set_32bytes_kck_support(wiphy); + wlan_hdd_set_nan_secure_mode(wiphy); + wlan_hdd_set_vlan_offload(hdd_ctx); + wlan_hdd_set_mfp_optional(wiphy); +} + +/** + * wlan_hdd_update_11n_mode - update 11n mode + * @hdd_ctx: hdd ccontext + * + * this function updated 11n mode in hdd cfg and UMAC + * + * Return: void + */ +void wlan_hdd_update_11n_mode(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg = hdd_ctx->config; + + if (sme_is_feature_supported_by_fw(DOT11AC)) { + hdd_debug("support 11ac"); + } else { + hdd_debug("not support 11ac"); + if ((cfg->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) || + (cfg->dot11Mode == eHDD_DOT11_MODE_11ac)) { + cfg->dot11Mode = eHDD_DOT11_MODE_11n; + ucfg_mlme_set_sap_11ac_override(hdd_ctx->psoc, 0); + ucfg_mlme_set_go_11ac_override(hdd_ctx->psoc, 0); + } + } +} + +QDF_STATUS wlan_hdd_update_wiphy_supported_band(struct hdd_context *hdd_ctx) +{ + int len_5g_ch, num_ch; + int num_dsrc_ch, len_dsrc_ch, num_srd_ch, len_srd_ch; + bool is_vht_for_24ghz = false; + QDF_STATUS status; + struct hdd_config *cfg = hdd_ctx->config; + struct wiphy *wiphy = hdd_ctx->wiphy; + + if (wiphy->registered) + return QDF_STATUS_SUCCESS; + + if (hdd_is_2g_supported(hdd_ctx)) { + if (!hdd_ctx->channels_2ghz) + return QDF_STATUS_E_NOMEM; + wiphy->bands[HDD_NL80211_BAND_2GHZ] = &wlan_hdd_band_2_4_ghz; + wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels = + hdd_ctx->channels_2ghz; + qdf_mem_copy(wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels, + &hdd_channels_2_4_ghz[0], + sizeof(hdd_channels_2_4_ghz)); + + status = ucfg_mlme_get_vht_for_24ghz(hdd_ctx->psoc, + &is_vht_for_24ghz); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not get VHT capability"); + + if (is_vht_for_24ghz && + sme_is_feature_supported_by_fw(DOT11AC) && + (cfg->dot11Mode == eHDD_DOT11_MODE_AUTO || + cfg->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY || + cfg->dot11Mode == eHDD_DOT11_MODE_11ac || + cfg->dot11Mode == eHDD_DOT11_MODE_11ax || + cfg->dot11Mode == eHDD_DOT11_MODE_11ax_ONLY)) + wlan_hdd_band_2_4_ghz.vht_cap.vht_supported = 1; + } + if (!hdd_is_5g_supported(hdd_ctx) || + (eHDD_DOT11_MODE_11b == cfg->dot11Mode) || + (eHDD_DOT11_MODE_11g == cfg->dot11Mode) || + (eHDD_DOT11_MODE_11b_ONLY == cfg->dot11Mode) || + (eHDD_DOT11_MODE_11g_ONLY == cfg->dot11Mode)) + return QDF_STATUS_SUCCESS; + + if (!hdd_ctx->channels_5ghz) + return QDF_STATUS_E_NOMEM; + wiphy->bands[HDD_NL80211_BAND_5GHZ] = &wlan_hdd_band_5_ghz; + wiphy->bands[HDD_NL80211_BAND_5GHZ]->channels = hdd_ctx->channels_5ghz; + wlan_hdd_get_num_dsrc_ch_and_len(cfg, &num_dsrc_ch, &len_dsrc_ch); + wlan_hdd_get_num_srd_ch_and_len(cfg, &num_srd_ch, &len_srd_ch); + num_ch = QDF_ARRAY_SIZE(hdd_channels_5_ghz) + num_dsrc_ch + num_srd_ch; + len_5g_ch = sizeof(hdd_channels_5_ghz); + + wiphy->bands[HDD_NL80211_BAND_5GHZ]->n_channels = num_ch; + qdf_mem_copy(wiphy->bands[HDD_NL80211_BAND_5GHZ]->channels, + &hdd_channels_5_ghz[0], len_5g_ch); + if (num_dsrc_ch) + wlan_hdd_copy_dsrc_ch((char *)wiphy->bands[ + HDD_NL80211_BAND_5GHZ]->channels + + len_5g_ch, len_dsrc_ch); + if (num_srd_ch) + wlan_hdd_copy_srd_ch((char *)wiphy->bands[ + HDD_NL80211_BAND_5GHZ]->channels + + len_5g_ch, len_srd_ch); + + if (cfg->dot11Mode != eHDD_DOT11_MODE_AUTO && + cfg->dot11Mode != eHDD_DOT11_MODE_11ac && + cfg->dot11Mode != eHDD_DOT11_MODE_11ac_ONLY && + cfg->dot11Mode != eHDD_DOT11_MODE_11ax && + cfg->dot11Mode != eHDD_DOT11_MODE_11ax_ONLY) + wlan_hdd_band_5_ghz.vht_cap.vht_supported = 0; + + if (cfg->dot11Mode == eHDD_DOT11_MODE_AUTO || + cfg->dot11Mode == eHDD_DOT11_MODE_11ax || + cfg->dot11Mode == eHDD_DOT11_MODE_11ax_ONLY) + hdd_init_6ghz(hdd_ctx); + + return QDF_STATUS_SUCCESS; +} + +/* In this function we are registering wiphy. */ +int wlan_hdd_cfg80211_register(struct wiphy *wiphy) +{ + int ret; + + hdd_enter(); + ret = wiphy_register(wiphy); + /* Register our wiphy dev with cfg80211 */ + if (ret < 0) { + hdd_err("wiphy register failed %d", ret); + return -EIO; + } + + hdd_exit(); + return 0; +} + +/* This function registers for all frame which supplicant is interested in */ +int wlan_hdd_cfg80211_register_frames(struct hdd_adapter *adapter) +{ + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + /* Register for all P2P action, public action etc frames */ + uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4); + QDF_STATUS status = QDF_STATUS_E_INVAL; + + hdd_enter(); + if (adapter->device_mode == QDF_FTM_MODE) { + hdd_info("No need to register frames in FTM mode"); + return 0; + } + + if (!mac_handle) { + hdd_err("mac_handle is NULL, failed to register frames"); + goto ret_status; + } + + /* Register frame indication call back */ + status = sme_register_mgmt_frame_ind_callback(mac_handle, + hdd_indicate_mgmt_frame); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register hdd_indicate_mgmt_frame"); + goto ret_status; + } + + /* Right now we are registering these frame when driver is getting + * initialized. Once we will move to 2.6.37 kernel, in which we have + * frame register ops, we will move this code as a part of that + */ + + /* GAS Initial Request */ + status = sme_register_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register GAS_INITIAL_REQ"); + goto ret_status; + } + + /* GAS Initial Response */ + status = sme_register_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register GAS_INITIAL_RSP"); + goto dereg_gas_initial_req; + } + + /* GAS Comeback Request */ + status = sme_register_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register GAS_COMEBACK_REQ"); + goto dereg_gas_initial_rsp; + } + + /* GAS Comeback Response */ + status = sme_register_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register GAS_COMEBACK_RSP"); + goto dereg_gas_comeback_req; + } + + /* WNM BSS Transition Request frame */ + status = sme_register_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) WNM_BSS_ACTION_FRAME, + WNM_BSS_ACTION_FRAME_SIZE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register WNM_BSS_ACTION_FRAME"); + goto dereg_gas_comeback_rsp; + } + + /* WNM-Notification */ + status = sme_register_mgmt_frame(mac_handle, + adapter->deflink->vdev_id, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to register WNM_NOTIFICATION_FRAME"); + goto dereg_wnm_bss_action_frm; + } + + return 0; + +dereg_wnm_bss_action_frm: + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) WNM_BSS_ACTION_FRAME, + WNM_BSS_ACTION_FRAME_SIZE); +dereg_gas_comeback_rsp: + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); +dereg_gas_comeback_req: + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); +dereg_gas_initial_rsp: + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); +dereg_gas_initial_req: + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); +ret_status: + return qdf_status_to_os_return(status); +} + +void wlan_hdd_cfg80211_deregister_frames(struct hdd_adapter *adapter) +{ + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + /* Deregister for all P2P action, public action etc frames */ + uint16_t type = (SIR_MAC_MGMT_FRAME << 2) | (SIR_MAC_MGMT_ACTION << 4); + + hdd_enter(); + + if (!mac_handle) { + hdd_err("mac_handle is NULL, failed to deregister frames"); + return; + } + + /* Right now we are registering these frame when driver is getting + * initialized. Once we will move to 2.6.37 kernel, in which we have + * frame register ops, we will move this code as a part of that + */ + + /* GAS Initial Request */ + + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_REQ, + GAS_INITIAL_REQ_SIZE); + + /* GAS Initial Response */ + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_INITIAL_RSP, + GAS_INITIAL_RSP_SIZE); + + /* GAS Comeback Request */ + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_REQ, + GAS_COMEBACK_REQ_SIZE); + + /* GAS Comeback Response */ + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) GAS_COMEBACK_RSP, + GAS_COMEBACK_RSP_SIZE); + + /* P2P Public Action */ + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_PUBLIC_ACTION_FRAME, + P2P_PUBLIC_ACTION_FRAME_SIZE); + + /* P2P Action */ + sme_deregister_mgmt_frame(mac_handle, SME_SESSION_ID_ANY, type, + (uint8_t *) P2P_ACTION_FRAME, + P2P_ACTION_FRAME_SIZE); + + /* WNM-Notification */ + sme_deregister_mgmt_frame(mac_handle, adapter->deflink->vdev_id, type, + (uint8_t *) WNM_NOTIFICATION_FRAME, + WNM_NOTIFICATION_FRAME_SIZE); +} + +bool wlan_hdd_is_ap_supports_immediate_power_save(uint8_t *ies, int length) +{ + const uint8_t *vendor_ie; + + if (length < 2) { + hdd_debug("bss size is less than expected"); + return true; + } + if (!ies) { + hdd_debug("invalid IE pointer"); + return true; + } + vendor_ie = wlan_get_vendor_ie_ptr_from_oui(VENDOR1_AP_OUI_TYPE, + VENDOR1_AP_OUI_TYPE_SIZE, ies, length); + if (vendor_ie) { + hdd_debug("AP can't support immediate powersave. defer it"); + return false; + } + return true; +} + +QDF_STATUS wlan_hdd_validate_operation_channel(struct hdd_context *hdd_ctx, + uint32_t ch_freq) +{ + bool value = 0; + uint32_t i; + struct regulatory_channel *cur_chan_list; + QDF_STATUS status; + + status = ucfg_mlme_get_sap_allow_all_channels(hdd_ctx->psoc, &value); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Unable to fetch sap allow all channels"); + status = QDF_STATUS_E_INVAL; + if (value) { + /* Validate the channel */ + for (i = CHAN_ENUM_2412; i < NUM_CHANNELS; i++) { + if (ch_freq == WLAN_REG_CH_TO_FREQ(i)) { + status = QDF_STATUS_SUCCESS; + break; + } + } + } else { + cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * + sizeof(struct regulatory_channel)); + if (!cur_chan_list) + return QDF_STATUS_E_NOMEM; + + if (wlan_reg_get_secondary_current_chan_list( + hdd_ctx->pdev, cur_chan_list) != QDF_STATUS_SUCCESS) { + qdf_mem_free(cur_chan_list); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + if (ch_freq != cur_chan_list[i].center_freq) + continue; + if (cur_chan_list[i].state != CHANNEL_STATE_DISABLE && + cur_chan_list[i].state != CHANNEL_STATE_INVALID) + status = QDF_STATUS_SUCCESS; + break; + } + qdf_mem_free(cur_chan_list); + } + + return status; + +} + +static int __wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + int ret = 0; + QDF_STATUS qdf_ret_status; + mac_handle_t mac_handle; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + cdp_config_param_type vdev_param; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BSS, + adapter->deflink->vdev_id, params->ap_isolate); + + hdd_debug("Device_mode %s(%d), ap_isolate = %d", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode, params->ap_isolate); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!(adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) { + return -EOPNOTSUPP; + } + + /* ap_isolate == -1 means that in change bss, upper layer doesn't + * want to update this parameter + */ + if (-1 != params->ap_isolate) { + ap_ctx->disable_intrabss_fwd = !!params->ap_isolate; + + mac_handle = hdd_ctx->mac_handle; + qdf_ret_status = sme_ap_disable_intra_bss_fwd( + mac_handle, + adapter->deflink->vdev_id, + ap_ctx->disable_intrabss_fwd); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) + ret = -EINVAL; + + ucfg_ipa_set_ap_ibss_fwd(hdd_ctx->pdev, + adapter->deflink->vdev_id, + ap_ctx->disable_intrabss_fwd); + + vdev_param.cdp_vdev_param_ap_brdg_en = + !ap_ctx->disable_intrabss_fwd; + cdp_txrx_set_vdev_param(soc, adapter->deflink->vdev_id, + CDP_ENABLE_AP_BRIDGE, vdev_param); + } + + hdd_exit(); + return ret; +} + +/** + * hdd_change_adapter_mode() - change @adapter's operating mode to @new_mode + * @adapter: the adapter to change modes on + * @new_mode: the new operating mode to change to + * + * Return: Errno + */ +static int hdd_change_adapter_mode(struct hdd_adapter *adapter, + enum QDF_OPMODE new_mode) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct net_device *netdev = adapter->dev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + hdd_enter(); + + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + adapter->device_mode = new_mode; + memset(&adapter->deflink->session, 0, + sizeof(adapter->deflink->session)); + hdd_set_station_ops(netdev); + + hdd_exit(); + + return qdf_status_to_os_return(status); +} + +static int wlan_hdd_cfg80211_change_bss(struct wiphy *wiphy, + struct net_device *dev, + struct bss_parameters *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_change_bss(wiphy, dev, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static bool hdd_is_client_mode(enum QDF_OPMODE mode) +{ + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + return true; + default: + return false; + } +} + +static bool hdd_is_ap_mode(enum QDF_OPMODE mode) +{ + switch (mode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + return true; + default: + return false; + } +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + !defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static QDF_STATUS +hdd_adapter_update_mac_on_mode_change(struct hdd_adapter *adapter) +{ + int i; + QDF_STATUS status; + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct qdf_mac_addr link_addr[WLAN_MAX_ML_BSS_LINKS] = {0}; + + status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, + &adapter->mld_addr, + &link_addr[0], + WLAN_MAX_ML_BSS_LINKS); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + qdf_copy_macaddr(&adapter->link_info[i].link_addr, + &link_addr[i]); + if (!link_adapter) + continue; + + ucfg_dp_update_intf_mac(hdd_ctx->psoc, &link_adapter->mac_addr, + &link_addr[i], + link_adapter->deflink->vdev); + qdf_copy_macaddr(&link_adapter->mac_addr, &link_addr[i]); + } + qdf_copy_macaddr(&adapter->link_info[i].link_addr, &link_addr[i]); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +hdd_adapter_update_mac_on_mode_change(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * __wlan_hdd_cfg80211_change_iface() - change interface cfg80211 op + * @wiphy: Pointer to the wiphy structure + * @ndev: Pointer to the net device + * @type: Interface type + * @flags: Flags for change interface + * @params: Pointer to change interface parameters + * + * Return: 0 for success, error number on failure. + */ +static int __wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + bool iff_up = ndev->flags & IFF_UP; + enum QDF_OPMODE new_mode; + bool ap_random_bssid_enabled; + QDF_STATUS status; + int errno; + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + bool eht_capab; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_hdd_is_mon_concurrency()) + return -EINVAL; + + wlan_hdd_lpc_handle_concurrency(hdd_ctx, false); + + if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc) && + !hdd_lpc_is_work_scheduled(hdd_ctx)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_IFACE, + link_info->vdev_id, type); + + status = hdd_nl_to_qdf_iface_type(type, &new_mode); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + /* A userspace issue leads to it sending a 'change to station mode' + * request on a "p2p" device, expecting the driver do execute a 'change + * to p2p-device mode' request instead. The (unfortunate) work around + * here is implemented by overriding the new mode if the net_device name + * starts with "p2p" and the requested mode was station. + */ + if (strnstr(ndev->name, "p2p", 3) && new_mode == QDF_STA_MODE) + new_mode = QDF_P2P_DEVICE_MODE; + + hdd_debug("Changing mode for '%s' from %s to %s", + ndev->name, + qdf_opmode_str(adapter->device_mode), + qdf_opmode_str(new_mode)); + + errno = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (errno) { + hdd_err("Failed to restart psoc; errno:%d", errno); + return -EINVAL; + } + + /* Reset the current device mode bit mask */ + policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); + + if (hdd_is_client_mode(adapter->device_mode)) { + if (adapter->device_mode == QDF_STA_MODE) + hdd_cleanup_conn_info(link_info); + + if (hdd_is_client_mode(new_mode)) { + errno = hdd_change_adapter_mode(adapter, new_mode); + if (errno) { + hdd_err("change intf mode fail %d", errno); + goto err; + } + } else if (hdd_is_ap_mode(new_mode)) { + if (new_mode == QDF_P2P_GO_MODE) + wlan_hdd_cleanup_remain_on_channel_ctx(link_info); + + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + memset(&link_info->session, 0, + sizeof(link_info->session)); + adapter->device_mode = new_mode; + + status = ucfg_mlme_get_ap_random_bssid_enable( + hdd_ctx->psoc, + &ap_random_bssid_enabled); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + if (adapter->device_mode == QDF_SAP_MODE && + ap_random_bssid_enabled) { + /* To meet Android requirements create + * a randomized MAC address of the + * form 02:1A:11:Fx:xx:xx + */ + memcpy(mac_addr, ndev->dev_addr, + QDF_MAC_ADDR_SIZE); + + get_random_bytes(&mac_addr[3], 3); + mac_addr[0] = 0x02; + mac_addr[1] = 0x1A; + mac_addr[2] = 0x11; + mac_addr[3] |= 0xF0; + memcpy(adapter->mac_addr.bytes, mac_addr, + QDF_MAC_ADDR_SIZE); + qdf_net_update_net_device_dev_addr(ndev, + mac_addr, + QDF_MAC_ADDR_SIZE); + + pr_info("wlan: Generated HotSpot BSSID " + QDF_MAC_ADDR_FMT "\n", + QDF_MAC_ADDR_REF(ndev->dev_addr)); + } + hdd_set_ap_ops(adapter->dev); + } else { + hdd_err("Changing to device mode '%s' is not supported", + qdf_opmode_str(new_mode)); + errno = -EOPNOTSUPP; + goto err; + } + } else if (hdd_is_ap_mode(adapter->device_mode)) { + if (hdd_is_client_mode(new_mode)) { + errno = hdd_change_adapter_mode(adapter, new_mode); + if (errno) { + hdd_err("change mode fail %d", errno); + goto err; + } + } else if (hdd_is_ap_mode(new_mode)) { + adapter->device_mode = new_mode; + + /* avoid starting the adapter, since it never stopped */ + iff_up = false; + } else { + hdd_err("Changing to device mode '%s' is not supported", + qdf_opmode_str(new_mode)); + errno = -EOPNOTSUPP; + goto err; + } + } else { + hdd_err("Changing from device mode '%s' is not supported", + qdf_opmode_str(adapter->device_mode)); + errno = -EOPNOTSUPP; + goto err; + } + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (eht_capab && hdd_adapter_is_ml_adapter(adapter)) { + switch (adapter->device_mode) { + case QDF_SAP_MODE: + hdd_adapter_set_sl_ml_adapter(adapter); + adapter->active_links = 0x1; + break; + case QDF_STA_MODE: + hdd_adapter_clear_sl_ml_adapter(adapter); + + status = hdd_adapter_update_mac_on_mode_change(adapter); + if (QDF_IS_STATUS_ERROR(status)) + goto err; + + adapter->active_links = + (1 << adapter->num_links_on_create) - 1; + break; + default: + hdd_adapter_clear_sl_ml_adapter(adapter); + adapter->active_links = 0x1; + break; + } + } + + /* restart the adapter if it was up before the change iface request */ + if (iff_up) { + errno = hdd_start_adapter(adapter, true); + if (errno) { + hdd_err("Failed to start adapter"); + errno = -EINVAL; + goto err; + } + } + + ndev->ieee80211_ptr->iftype = type; + hdd_lpass_notify_mode_change(link_info); +err: + /* Set bitmask based on updated value */ + policy_mgr_set_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); + + hdd_exit(); + + return errno; +} + +static int _wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *net_dev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) + goto err; + + errno = __wlan_hdd_cfg80211_change_iface(wiphy, net_dev, type, + flags, params); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +err: + /* In the SSR case, errno will be -EINVAL from + * __dsc_vdev_can_trans with qdf_is_recovering() + * is true, only change -EINVAL to -EBUSY to make + * wpa_supplicant has chance to retry mode switch. + * Meanwhile do not touch the errno from + * __wlan_hdd_cfg80211_change_iface with this + * change. + */ + if (errno && errno != -EAGAIN && errno != -EBUSY) + errno = -EBUSY; + return errno; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +/** + * wlan_hdd_cfg80211_change_iface() - change interface cfg80211 op + * @wiphy: Pointer to the wiphy structure + * @ndev: Pointer to the net device + * @type: Interface type + * @flags: Flags for change interface + * @params: Pointer to change interface parameters + * + * Return: 0 for success, error number on failure. + */ +static int wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + return _wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, + flags, params); +} +#else +static int wlan_hdd_cfg80211_change_iface(struct wiphy *wiphy, + struct net_device *ndev, + enum nl80211_iftype type, + struct vif_params *params) +{ + return _wlan_hdd_cfg80211_change_iface(wiphy, ndev, type, + ¶ms->flags, params); +} +#endif /* KERNEL_VERSION(4, 12, 0) */ + +QDF_STATUS wlan_hdd_send_sta_authorized_event( + struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + const struct qdf_mac_addr *mac_addr) +{ + struct sk_buff *vendor_event; + QDF_STATUS status; + struct nl80211_sta_flag_update sta_flags; + + hdd_enter(); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_INVAL; + } + + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &adapter->wdev, sizeof(sta_flags) + + QDF_MAC_ADDR_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_LINK_PROPERTIES_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&sta_flags, sizeof(sta_flags)); + + sta_flags.mask |= BIT(NL80211_STA_FLAG_AUTHORIZED); + sta_flags.set = true; + + status = nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_STA_FLAGS, + sizeof(struct nl80211_sta_flag_update), + &sta_flags); + if (status) { + hdd_err("STA flag put fails"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return QDF_STATUS_E_FAILURE; + } + status = nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LINK_PROPERTIES_MAC_ADDR, + QDF_MAC_ADDR_SIZE, mac_addr->bytes); + if (status) { + hdd_err("STA MAC put fails"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return QDF_STATUS_E_FAILURE; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + hdd_exit(); + return QDF_STATUS_SUCCESS; +} + +#ifdef QCA_MULTIPASS_SUPPORT +static int +wlan_hdd_set_peer_vlan_config(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + uint8_t vlan_id) +{ + ol_txrx_soc_handle soc_txrx_handle; + cdp_config_param_type val; + QDF_STATUS status; + + soc_txrx_handle = wlan_psoc_get_dp_handle(wlan_vdev_get_psoc(vdev)); + + cdp_peer_set_vlan_id(soc_txrx_handle, + wlan_vdev_get_id(vdev), + mac_addr, vlan_id); + + val.cdp_peer_param_isolation = true; + + cdp_txrx_set_peer_param(soc_txrx_handle, + wlan_vdev_get_id(vdev), + mac_addr, + CDP_CONFIG_ISOLATION, + val); + + status = ucfg_mlme_peer_config_vlan(vdev, mac_addr); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return 0; +} + +static void +wlan_hdd_set_vlan_id(struct hdd_sta_info_obj *sta_info_list, + uint8_t *mac, struct station_parameters *params) +{ + struct hdd_station_info *sta_info; + + if (!params->vlan_id) + return; + + sta_info = + hdd_get_sta_info_by_mac(sta_info_list, + mac, + STA_INFO_SOFTAP_GET_STA_INFO); + if (!sta_info) { + hdd_err("Failed to find right station MAC: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + return; + } + + sta_info->vlan_id = params->vlan_id; + + hdd_put_sta_info_ref(sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_GET_STA_INFO); +} + +static QDF_STATUS +wlan_hdd_set_vlan_config(struct hdd_adapter *adapter, + uint8_t *mac) +{ + int ret; + struct hdd_station_info *sta_info; + + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + (uint8_t *)mac, + STA_INFO_SOFTAP_GET_STA_INFO); + + if (!sta_info) { + hdd_err("Failed to find right station MAC:" + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF((uint8_t *)mac)); + return QDF_STATUS_E_INVAL; + } + + if (!sta_info->vlan_id) { + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, + true, + STA_INFO_SOFTAP_GET_STA_INFO); + return QDF_STATUS_E_INVAL; + } + + ret = wlan_hdd_set_peer_vlan_config(adapter, + adapter->deflink->vdev, + mac, + sta_info->vlan_id); + if (ret < 0) { + hdd_err("Unable to send peer vlan config"); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, + true, + STA_INFO_SOFTAP_GET_STA_INFO); + return QDF_STATUS_E_INVAL; + } + + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, + true, STA_INFO_SOFTAP_GET_STA_INFO); + + return QDF_STATUS_SUCCESS; +} +#else +static inline void +wlan_hdd_set_vlan_id(struct hdd_sta_info_obj *sta_info_list, + uint8_t *mac, struct station_parameters *params) +{ +} + +static inline QDF_STATUS +wlan_hdd_set_vlan_config(struct hdd_adapter *adapter, + uint8_t *mac) +{ + return QDF_STATUS_SUCCESS; +} +#endif +/** + * __wlan_hdd_change_station() - change station + * @wiphy: Pointer to the wiphy structure + * @dev: Pointer to the net device. + * @mac: bssid + * @params: Pointer to station parameters + * + * Return: 0 for success, error number on failure. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int __wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +#else +static int __wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac, + struct station_parameters *params) +#endif +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *sta_ctx; + struct hdd_ap_ctx *ap_ctx; + struct qdf_mac_addr sta_macaddr; + int ret; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CHANGE_STATION, + adapter->deflink->vdev_id, params->listen_interval); + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + qdf_mem_copy(sta_macaddr.bytes, mac, QDF_MAC_ADDR_SIZE); + + wlan_hdd_set_vlan_id(&adapter->sta_info_list, (uint8_t *)mac, params); + + if ((adapter->device_mode == QDF_SAP_MODE) || + (adapter->device_mode == QDF_P2P_GO_MODE)) { + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED)) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + /* + * For Encrypted SAP session, this will be done as + * part of eSAP_STA_SET_KEY_EVENT + */ + + if (ucfg_mlme_is_multipass_sap(hdd_ctx->psoc)) { + status = + wlan_hdd_set_vlan_config(adapter, + (uint8_t *)mac); + if (QDF_IS_STATUS_ERROR(status)) + return 0; + } + + if (ap_ctx->encryption_type != + eCSR_ENCRYPT_TYPE_NONE) { + hdd_debug("Encrypt type %d, not setting peer authorized now", + ap_ctx->encryption_type); + return 0; + } + + status = + hdd_softap_change_sta_state(adapter, + &sta_macaddr, + OL_TXRX_PEER_STATE_AUTH); + + if (status != QDF_STATUS_SUCCESS) { + hdd_debug("Not able to change TL state to AUTHENTICATED"); + return -EINVAL; + } + status = wlan_hdd_send_sta_authorized_event( + adapter, + hdd_ctx, + &sta_macaddr); + if (status != QDF_STATUS_SUCCESS) { + return -EINVAL; + } + } + } else if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { +#if defined(FEATURE_WLAN_TDLS) + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_tdls_update_peer(vdev, mac, params); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); +#endif + } + } + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_change_station() - cfg80211 change station handler function + * @wiphy: Pointer to the wiphy structure + * @dev: Pointer to the net device. + * @mac: bssid + * @params: Pointer to station parameters + * + * This is the cfg80211 change station handler function which invokes + * the internal function @__wlan_hdd_change_station with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) || defined(WITH_BACKPORTS) +static int wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + const u8 *mac, + struct station_parameters *params) +#else +static int wlan_hdd_change_station(struct wiphy *wiphy, + struct net_device *dev, + u8 *mac, + struct station_parameters *params) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_change_station(wiphy, dev, mac, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef FEATURE_WLAN_ESE +static bool hdd_is_krk_enc_type(uint32_t cipher_type) +{ + if (cipher_type == WLAN_CIPHER_SUITE_KRK) + return true; + + return false; +} +#else +static bool hdd_is_krk_enc_type(uint32_t cipher_type) +{ + return false; +} +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +static bool hdd_is_btk_enc_type(uint32_t cipher_type) +{ + if (cipher_type == WLAN_CIPHER_SUITE_BTK) + return true; + + return false; +} +#else +static bool hdd_is_btk_enc_type(uint32_t cipher_type) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +struct wlan_objmgr_vdev *wlan_key_get_link_vdev(struct hdd_adapter *adapter, + wlan_objmgr_ref_dbgid id, + int link_id) +{ + struct wlan_objmgr_vdev *vdev, *link_vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, id); + if (!vdev) + return NULL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return vdev; + + link_vdev = mlo_get_vdev_by_link_id(vdev, link_id, id); + hdd_objmgr_put_vdev_by_user(vdev, id); + + return link_vdev; +} + +void wlan_key_put_link_vdev(struct wlan_objmgr_vdev *link_vdev, + wlan_objmgr_ref_dbgid id) +{ + if (!wlan_vdev_mlme_is_mlo_vdev(link_vdev)) { + hdd_objmgr_put_vdev_by_user(link_vdev, id); + return; + } + + wlan_objmgr_vdev_release_ref(link_vdev, id); +} +#else +struct wlan_objmgr_vdev *wlan_key_get_link_vdev(struct hdd_adapter *adapter, + wlan_objmgr_ref_dbgid id, + int link_id) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, id); + if (!vdev) + return NULL; + + return vdev; +} + +void wlan_key_put_link_vdev(struct wlan_objmgr_vdev *link_vdev, + wlan_objmgr_ref_dbgid id) +{ + hdd_objmgr_put_vdev_by_user(link_vdev, id); +} +#endif + +/* + * FUNCTION: __wlan_hdd_cfg80211_get_key + * This function is used to get the key information + */ + +static int wlan_hdd_add_key_sap(struct wlan_hdd_link_info *link_info, + bool pairwise, u8 key_index, + enum wlan_crypto_cipher_type cipher) +{ + struct wlan_objmgr_vdev *vdev; + int errno = 0; + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + /* Do not send install key when sap restart is in progress. If there is + * critical channel request handling going on, fw will stop that request + * and will not send restart response + */ + if (wlan_vdev_is_restart_progress(vdev) == QDF_STATUS_SUCCESS) { + hdd_err("vdev: %d restart in progress", wlan_vdev_get_id(vdev)); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return -EINVAL; + } + + if (hostapd_state->bss_state == BSS_START) { + errno = + wlan_cfg80211_crypto_add_key(vdev, + (pairwise ? + WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP), + key_index, true); + if (!errno) + wma_update_set_key(link_info->vdev_id, pairwise, + key_index, cipher); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return errno; +} + +static int wlan_hdd_add_key_sta(struct wlan_objmgr_pdev *pdev, + struct wlan_hdd_link_info *link_info, + bool pairwise, u8 key_index, bool *ft_mode) +{ + struct wlan_objmgr_vdev *vdev; + int errno; + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + + /* The supplicant may attempt to set the PTK once + * pre-authentication is done. Save the key in the + * UMAC and install it after association + */ + status = ucfg_cm_check_ft_status(pdev, link_info->vdev_id); + if (status == QDF_STATUS_SUCCESS) { + *ft_mode = true; + return 0; + } + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + errno = wlan_cfg80211_crypto_add_key(vdev, (pairwise ? + WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP), + key_index, true); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + if (!errno && adapter->send_mode_change) { + wlan_hdd_send_mode_change_event(); + adapter->send_mode_change = false; + } + + return errno; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +wlan_hdd_mlo_link_free_keys(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + bool pairwise) +{ + struct qdf_mac_addr *link_addr; + uint8_t link_id; + + if (adapter->device_mode != QDF_STA_MODE) + return; + + if (pairwise && + wlan_vdev_mlme_is_mlo_link_vdev(vdev) && + mlo_roam_is_auth_status_connected(adapter->hdd_ctx->psoc, + wlan_vdev_get_id(vdev))) { + link_addr = + (struct qdf_mac_addr *)wlan_vdev_mlme_get_linkaddr(vdev); + + if (!link_addr) { + crypto_err("link_addr NULL"); + return; + } + link_id = wlan_vdev_get_link_id(vdev); + wlan_crypto_free_key_by_link_id(psoc, link_addr, link_id); + } +} + +#else + +static void +wlan_hdd_mlo_link_free_keys(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + bool pairwise) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +wlan_hdd_mlo_copy_partner_addr_from_mlie(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *partner_mac) +{ + int i; + QDF_STATUS status; + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_mlo_sta *sta_ctx; + struct mlo_link_info *partner_link_info; + struct element_info *assoc_rsp; + const uint8_t *ie_data_ptr; + size_t ie_data_len, ml_ie_len = 0; + uint8_t *ml_ie = NULL; + bool found = false; + struct mlo_partner_info partner_info = {0}; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) + return QDF_STATUS_E_INVAL; + + sta_ctx = mlo_dev_ctx->sta_ctx; + if (!sta_ctx) + return QDF_STATUS_E_INVAL; + + mlo_dev_lock_acquire(mlo_dev_ctx); + assoc_rsp = &sta_ctx->assoc_rsp; + + if (!assoc_rsp->len || !assoc_rsp->ptr || + assoc_rsp->len <= WLAN_ASSOC_RSP_IES_OFFSET) { + mlo_dev_lock_release(mlo_dev_ctx); + return QDF_STATUS_E_INVAL; + } + + ie_data_len = assoc_rsp->len - WLAN_ASSOC_RSP_IES_OFFSET; + ie_data_ptr = assoc_rsp->ptr + WLAN_ASSOC_RSP_IES_OFFSET; + status = util_find_mlie((uint8_t *)ie_data_ptr, ie_data_len, + &ml_ie, &ml_ie_len); + + if (QDF_IS_STATUS_ERROR(status) || !ml_ie) { + mlo_dev_lock_release(mlo_dev_ctx); + hdd_debug("ML IE not found %d", status); + return status; + } + + status = util_get_bvmlie_persta_partner_info(ml_ie, ml_ie_len, + &partner_info); + if (QDF_IS_STATUS_ERROR(status)) { + mlo_dev_lock_release(mlo_dev_ctx); + hdd_err("Unable to find per-sta profile in ML IE"); + return status; + } + mlo_dev_lock_release(mlo_dev_ctx); + + for (i = 0; i < partner_info.num_partner_links; i++) { + partner_link_info = &partner_info.partner_link_info[i]; + if (partner_link_info->link_id == vdev->vdev_mlme.mlo_link_id) { + qdf_copy_macaddr(partner_mac, + &partner_link_info->link_addr); + found = true; + break; + } + } + + if (!partner_info.num_partner_links || !found) + status = QDF_STATUS_E_NOENT; + + return status; +} +#endif + +#if defined(QCA_MULTIPASS_SUPPORT) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 5, 0)) +static void +wlan_hdd_set_vlan_groupkey(ol_txrx_soc_handle soc_txrx_handle, uint16_t vdev_id, + struct key_params *params, uint8_t key_index) +{ + if (params->vlan_id) + cdp_set_vlan_groupkey(soc_txrx_handle, vdev_id, + params->vlan_id, key_index); +} + +static int +wlan_hdd_add_vlan(struct wlan_objmgr_vdev *vdev, struct sap_context *sap_ctx, + struct key_params *params, uint8_t key_index, + uint8_t *vlan_key_idx) +{ + struct wlan_objmgr_psoc *psoc = NULL; + ol_txrx_soc_handle soc_txrx_handle; + uint16_t *vlan_map = sap_ctx->vlan_map; + uint8_t found = 0; + bool keyindex_valid; + int i = 0; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("Unable to get psoc"); + return -EINVAL; + } + + for (i = 0; i < (MAX_VLAN * 2); i += 2) { + if (!vlan_map[i] || !vlan_map[i + 1]) { + found = 1; + break; + } else if ((vlan_map[i] == params->vlan_id) || + (vlan_map[i + 1] == params->vlan_id)) { + vlan_map[i] = 0; + vlan_map[i + 1] = 0; + found = 1; + break; + } + } + + keyindex_valid = (i + key_index - 1) < (2 * MAX_VLAN) ? true : false; + + if (found && keyindex_valid) { + soc_txrx_handle = wlan_psoc_get_dp_handle(psoc); + vlan_map[i + key_index - 1] = params->vlan_id; + wlan_hdd_set_vlan_groupkey(soc_txrx_handle, + wlan_vdev_get_id(vdev), + params, + (i / 2) + 1); + *vlan_key_idx = (i + key_index - 1 + 8); + return 0; + } + + hdd_err("Unable to find group key mapping for vlan_id: %d", + params->vlan_id); + return -EINVAL; +} +#else +static int +wlan_hdd_add_vlan(struct wlan_objmgr_vdev *vdev, struct sap_context *sap_ctx, + struct key_params *params, uint8_t key_index, + uint8_t *vlan_key_idx) +{ + return key_index; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static void wlan_hdd_mlo_link_add_pairwise_key(struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + u8 key_index, bool pairwise, + struct key_params *params) +{ + struct mlo_link_info *mlo_link_info; + uint8_t link_info_iter = 0; + + mlo_link_info = &vdev->mlo_dev_ctx->link_ctx->links_info[0]; + for (link_info_iter = 0; link_info_iter < WLAN_MAX_ML_BSS_LINKS; + link_info_iter++, mlo_link_info++) { + if (qdf_is_macaddr_zero(&mlo_link_info->ap_link_addr) || + mlo_link_info->link_id == 0xFF) + continue; + hdd_debug(" Add pairwise key link id %d ", + mlo_link_info->link_id); + wlan_cfg80211_store_link_key( + hdd_ctx->psoc, key_index, + (pairwise ? WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP), + (uint8_t *)mlo_link_info->ap_link_addr.bytes, + params, &mlo_link_info->link_addr, + mlo_link_info->link_id); + } +} + +static bool +wlan_hdd_mlo_defer_set_keys(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_address) +{ + uint8_t link_id; + + if (!adapter) + return false; + + if (!vdev || !vdev->mlo_dev_ctx) + return false; + + link_id = wlan_vdev_get_link_id(vdev); + + if ((adapter->device_mode == QDF_STA_MODE) && + ((!wlan_cm_is_vdev_connected(vdev)) || + (wlan_vdev_mlme_is_mlo_link_vdev(vdev) && + mlo_roam_is_auth_status_connected(adapter->hdd_ctx->psoc, + wlan_vdev_get_id(vdev))))) { + hdd_debug("MLO:Defer set keys for link_id %d", link_id); + mlo_defer_set_keys(vdev, link_id, true); + return true; + } + + return false; +} + +#else + +static void wlan_hdd_mlo_link_add_pairwise_key(struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + u8 key_index, bool pairwise, + struct key_params *params) +{ +} + +static bool +wlan_hdd_mlo_defer_set_keys(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac_address) +{ + return false; +} + +#endif + +static int wlan_hdd_add_key_vdev(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev, u8 key_index, + bool pairwise, const u8 *mac_addr, + struct key_params *params, int link_id, + struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS status; + struct wlan_objmgr_peer *peer; + struct hdd_context *hdd_ctx; + struct qdf_mac_addr mac_address; + int32_t cipher_cap, ucast_cipher = 0; + int errno = 0; + enum wlan_crypto_cipher_type cipher; + bool ft_mode = false; + uint8_t keyidx; + struct hdd_ap_ctx *hdd_ap_ctx; + struct sap_context *sap_ctx; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (hdd_is_btk_enc_type(params->cipher)) + return sme_add_key_btk(mac_handle, wlan_vdev_get_id(vdev), + params->key, params->key_len); + if (hdd_is_krk_enc_type(params->cipher)) + return sme_add_key_krk(mac_handle, wlan_vdev_get_id(vdev), + params->key, params->key_len); + + if (!pairwise && ((wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE) || + (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_CLIENT_MODE))) { + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_ID); + if (peer) { + qdf_mem_copy(mac_address.bytes, + wlan_peer_get_macaddr(peer), + QDF_MAC_ADDR_SIZE); + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + } else if (wlan_vdev_mlme_is_mlo_link_vdev(vdev) && + adapter->device_mode == QDF_STA_MODE) { + status = wlan_objmgr_vdev_try_get_ref(vdev, + WLAN_OSIF_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get vdev ref"); + return qdf_status_to_os_return(status); + } + status = wlan_hdd_mlo_copy_partner_addr_from_mlie( + vdev, &mac_address); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get peer address from ML IEs"); + return qdf_status_to_os_return(status); + } + goto done; + } else { + hdd_err("Peer is null return"); + return -EINVAL; + } + + status = mlo_get_link_mac_addr_from_reassoc_rsp(vdev, + &mac_address); + if (QDF_IS_STATUS_ERROR(status)) { + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, + WLAN_OSIF_ID); + if (!peer) { + hdd_err("Peer is null return"); + return -EINVAL; + } + qdf_mem_copy(mac_address.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + } + } else { + if (mac_addr) + qdf_mem_copy(mac_address.bytes, + mac_addr, + QDF_MAC_ADDR_SIZE); + } + +done: + wlan_hdd_mlo_link_free_keys(hdd_ctx->psoc, adapter, vdev, pairwise); + if (pairwise && adapter->device_mode == QDF_STA_MODE && + wlan_vdev_mlme_is_mlo_vdev(vdev) && + !wlan_vdev_mlme_is_tdls_vdev(vdev)) { + wlan_hdd_mlo_link_add_pairwise_key(vdev, hdd_ctx, key_index, + pairwise, params); + + } else { + errno = wlan_cfg80211_store_key( + vdev, key_index, + (pairwise ? + WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP), + mac_address.bytes, params); + } + + if (wlan_hdd_mlo_defer_set_keys(adapter, vdev, &mac_address)) + return 0; + + cipher_cap = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_CIPHER_CAP); + if (errno) + return errno; + cipher = osif_nl_to_crypto_cipher_type(params->cipher); + QDF_SET_PARAM(ucast_cipher, cipher); + if (pairwise) + wma_set_peer_ucast_cipher(mac_address.bytes, + ucast_cipher, cipher_cap); + + cdp_peer_flush_frags(cds_get_context(QDF_MODULE_ID_SOC), + wlan_vdev_get_id(vdev), mac_address.bytes); + + switch (adapter->device_mode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (hdd_ap_ctx->during_auth_offload) { + hdd_err("don't need install key during auth"); + return -EINVAL; + } + + keyidx = key_index; + + if (ucfg_mlme_is_multipass_sap(hdd_ctx->psoc) && + params->vlan_id) { + sap_ctx = hdd_ap_ctx->sap_context; + errno = wlan_hdd_add_vlan(vdev, sap_ctx, params, + key_index, &keyidx); + if (errno < 0) + return errno; + } + + errno = wlan_hdd_add_key_sap(link_info, pairwise, + keyidx, cipher); + + break; + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_NAN_DISC_MODE: + errno = wlan_hdd_add_key_sta(hdd_ctx->pdev, link_info, pairwise, + key_index, &ft_mode); + if (ft_mode) + return 0; + break; + default: + break; + } + if (!errno && (adapter->device_mode != QDF_SAP_MODE)) + wma_update_set_key(wlan_vdev_get_id(vdev), pairwise, key_index, + cipher); + + hdd_exit(); + return errno; +} + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS wlan_hdd_send_key_vdev(struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + enum wlan_crypto_cipher_type cipher_type) +{ + struct wlan_objmgr_peer *peer; + struct qdf_mac_addr mac_address; + int32_t cipher_cap, ucast_cipher = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int errno; + bool ft_mode = false; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + uint8_t vdev_id; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_id = wlan_vdev_get_id(vdev); + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) { + hdd_debug("vdev opmode is not STA mode"); + return QDF_STATUS_E_INVAL; + } + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_ID); + if (!peer) { + hdd_err("Peer is null return"); + return QDF_STATUS_E_NULL_VALUE; + } + qdf_mem_copy(mac_address.bytes, + wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + + cipher_cap = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_CIPHER_CAP); + QDF_SET_PARAM(ucast_cipher, cipher_type); + if (pairwise) + wma_set_peer_ucast_cipher(mac_address.bytes, + ucast_cipher, cipher_cap); + + cdp_peer_flush_frags(cds_get_context(QDF_MODULE_ID_SOC), + vdev_id, mac_address.bytes); + + errno = wlan_hdd_add_key_sta(hdd_ctx->pdev, link_info, + pairwise, key_index, &ft_mode); + if (ft_mode) + return QDF_STATUS_SUCCESS; + + if (!errno) + wma_update_set_key(vdev_id, pairwise, key_index, cipher_type); + else + status = QDF_STATUS_E_FAILURE; + + return status; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && \ +defined(CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT) +struct wlan_objmgr_peer * +wlan_hdd_ml_sap_get_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer_mld) +{ + struct wlan_mlo_dev_context *ap_mlo_dev_ctx; + struct wlan_mlo_peer_list *mlo_peer_list; + struct wlan_mlo_peer_context *ml_peer; + struct wlan_mlo_link_peer_entry *peer_entry; + int i, pdev_id; + uint8_t *peer_mac; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer = NULL; + + if (!vdev) + return NULL; + + pdev = wlan_vdev_get_pdev(vdev); + + if (!pdev) + return NULL; + + psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) + return NULL; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + + ap_mlo_dev_ctx = vdev->mlo_dev_ctx; + mlo_dev_lock_acquire(ap_mlo_dev_ctx); + mlo_peer_list = &ap_mlo_dev_ctx->mlo_peer_list; + ml_peerlist_lock_acquire(mlo_peer_list); + ml_peer = mlo_get_mlpeer(ap_mlo_dev_ctx, + (struct qdf_mac_addr *)peer_mld); + if (!ml_peer) { + /* Peer is a legacy STA client, check peer list. + * Treat the MLD address as legacy MAC address + */ + peer = wlan_objmgr_get_peer(psoc, pdev_id, + peer_mld, WLAN_OSIF_ID); + goto out; + } + + mlo_peer_lock_acquire(ml_peer); + for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { + peer_entry = &ml_peer->peer_list[i]; + if (!peer_entry) + continue; + /* Checking for VDEV match which will + * be used for multiple VDEV case. + */ + if (vdev == wlan_peer_get_vdev(peer_entry->link_peer)) { + peer_mac = &peer_entry->link_peer->macaddr[0]; + peer = wlan_objmgr_get_peer(psoc, pdev_id, peer_mac, + WLAN_OSIF_ID); + break; + } + } + mlo_peer_lock_release(ml_peer); + +out: + ml_peerlist_lock_release(mlo_peer_list); + mlo_dev_lock_release(ap_mlo_dev_ctx); + + return peer; +} + +static int wlan_hdd_add_key_all_mlo_vdev(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params, int link_id, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; + struct wlan_objmgr_vdev *link_vdev; + struct qdf_mac_addr peer_mac; + struct wlan_objmgr_peer *peer = NULL; + int errno = 0; + uint16_t link, vdev_count = 0; + uint8_t vdev_id; + struct wlan_hdd_link_info *link_info; + + /* if vdev mlme is mlo & pairwaise is set to true set same info for + * both the links. + */ + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); + for (link = 0; link < vdev_count; link++) { + link_vdev = wlan_vdev_list[link]; + vdev_id = wlan_vdev_get_id(link_vdev); + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + mlo_release_vdev_ref(link_vdev); + continue; + } + peer = NULL; + switch (adapter->device_mode) { + case QDF_SAP_MODE: + if (wlan_vdev_mlme_is_mlo_vdev(link_vdev)) + peer = wlan_hdd_ml_sap_get_peer( + link_vdev, + mac_addr); + break; + case QDF_STA_MODE: + default: + status = mlo_get_link_mac_addr_from_reassoc_rsp(link_vdev, + &peer_mac); + if (QDF_IS_STATUS_ERROR(status)) + peer = wlan_objmgr_vdev_try_get_bsspeer(link_vdev, + WLAN_OSIF_ID); + else + goto add_key; + break; + } + + if (peer) { + qdf_mem_copy(peer_mac.bytes, + wlan_peer_get_macaddr(peer), + QDF_MAC_ADDR_SIZE); + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + + } else if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && + adapter->device_mode == QDF_STA_MODE) { + status = wlan_hdd_mlo_copy_partner_addr_from_mlie( + link_vdev, &peer_mac); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get peer address from ML IEs"); + mlo_release_vdev_ref(link_vdev); + continue; + } + } else { + hdd_err("Peer is null"); + mlo_release_vdev_ref(link_vdev); + continue; + } + +add_key: + errno = wlan_hdd_add_key_vdev(mac_handle, link_vdev, key_index, + pairwise, peer_mac.bytes, + params, link_id, link_info); + mlo_release_vdev_ref(link_vdev); + } + + return errno; +} + +static int wlan_add_key_standby_link(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + int link_id, u8 key_index, + bool pairwise, struct key_params *params) +{ + int errno = 0; + struct hdd_context *hdd_ctx; + struct mlo_link_info *mlo_link_info; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + mlo_link_info = mlo_mgr_get_ap_link_by_link_id(vdev->mlo_dev_ctx, + link_id); + if (!mlo_link_info) + return QDF_STATUS_E_FAILURE; + + errno = wlan_cfg80211_store_link_key( + hdd_ctx->psoc, key_index, + (pairwise ? WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP), + (uint8_t *)mlo_link_info->ap_link_addr.bytes, + params, + &mlo_link_info->link_addr, + link_id); + hdd_debug("ml defer set key link id %d", link_id); + mlo_defer_set_keys(vdev, link_id, true); + return errno; +} + +static int wlan_hdd_add_key_mlo_vdev(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params, int link_id, + struct hdd_adapter *adapter) +{ + int errno = 0; + struct wlan_objmgr_vdev *link_vdev; + struct hdd_context *hdd_ctx; + uint8_t vdev_id; + QDF_STATUS status; + struct wlan_hdd_link_info *link_info; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return errno; + + vdev_id = wlan_vdev_get_id(vdev); + if (pairwise && + mlo_roam_is_auth_status_connected(adapter->hdd_ctx->psoc, + vdev_id)) { + status = mlo_roam_link_connect_notify(adapter->hdd_ctx->psoc, + vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Posting of link connect request failed"); + return -EINVAL; + } + } + + link_vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (pairwise && link_id == -1 && !link_vdev) + return wlan_hdd_add_key_all_mlo_vdev(mac_handle, vdev, + key_index, pairwise, + mac_addr, params, + link_id, adapter); + + if (pairwise && link_id == -1 && link_vdev) { + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + link_info = + hdd_get_link_info_by_vdev(hdd_ctx, + wlan_vdev_get_id(link_vdev)); + link_id = wlan_vdev_get_link_id(link_vdev); + if (!link_info) { + ucfg_tdls_put_tdls_link_vdev(link_vdev, + WLAN_OSIF_TDLS_ID); + hdd_err("couldn't set tdls key, link_id %d", link_id); + return -EINVAL; + } + + errno = wlan_hdd_add_key_vdev(mac_handle, link_vdev, key_index, + pairwise, mac_addr, params, + link_id, link_info); + ucfg_tdls_put_tdls_link_vdev(link_vdev, WLAN_OSIF_TDLS_ID); + + return errno; + } + + if (link_vdev) + ucfg_tdls_put_tdls_link_vdev(link_vdev, WLAN_OSIF_TDLS_ID); + + if (wlan_vdev_get_link_id(adapter->deflink->vdev) == link_id) { + hdd_debug("add_key for same vdev: %d", + adapter->deflink->vdev_id); + return wlan_hdd_add_key_vdev(mac_handle, vdev, key_index, + pairwise, mac_addr, params, + link_id, adapter->deflink); + } + + link_vdev = wlan_key_get_link_vdev(adapter, WLAN_MLO_MGR_ID, link_id); + if (!link_vdev) { + hdd_err("couldn't get vdev for link_id :%d", link_id); + errno = wlan_add_key_standby_link(adapter, vdev, link_id, + key_index, pairwise, params); + return errno; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + link_info = hdd_get_link_info_by_vdev(hdd_ctx, + wlan_vdev_get_id(link_vdev)); + if (!link_info) { + hdd_err("couldn't set key for link_id:%d", link_id); + goto release_ref; + } + + errno = wlan_hdd_add_key_vdev(mac_handle, link_vdev, key_index, + pairwise, mac_addr, params, + link_id, link_info); + +release_ref: + wlan_key_put_link_vdev(link_vdev, WLAN_MLO_MGR_ID); + return errno; +} +#elif defined(CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV) +static int wlan_hdd_add_key_mlo_vdev(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params, int link_id, + struct hdd_adapter *adapter) +{ + return wlan_hdd_add_key_vdev(mac_handle, vdev, key_index, + pairwise, mac_addr, params, + link_id, adapter->deflink); +} +#else +static int wlan_hdd_add_key_mlo_vdev(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params, int link_id, + struct hdd_adapter *adapter) +{ + return 0; +} +#endif + +static int __wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params, int link_id) +{ + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct wlan_objmgr_vdev *vdev; + int errno; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_KEY, + adapter->deflink->vdev_id, params->key_len); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + hdd_debug("converged Device_mode %s(%d) index %d, pairwise %d link_id %d", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode, key_index, pairwise, link_id); + mac_handle = hdd_ctx->mac_handle; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + errno = wlan_hdd_add_key_vdev(mac_handle, vdev, key_index, + pairwise, mac_addr, params, + link_id, adapter->deflink); + else + errno = wlan_hdd_add_key_mlo_vdev(mac_handle, vdev, key_index, + pairwise, mac_addr, params, + link_id, adapter); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return errno; +} + +#ifdef CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +#ifdef CFG80211_SET_KEY_WITH_SRC_MAC +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index, bool pairwise, + const u8 *src_addr, + const u8 *mac_addr, + struct key_params *params) +#else +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +#endif +{ + int errno = -EINVAL; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = qdf_container_of(wdev, + struct hdd_adapter, + wdev); + /* Legacy purposes */ + int link_id = -1; + + if (!adapter || wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_add_key(wiphy, adapter->dev, key_index, + pairwise, mac_addr, params, + link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_SET_KEY_WITH_SRC_MAC) +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *src_addr, + const u8 *mac_addr, + struct key_params *params) +{ + int errno; + int link_id = -1; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise, + mac_addr, params, link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_MLO_KEY_OPERATION_SUPPORT) +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + int link_id, u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise, + mac_addr, params, link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_add_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, + struct key_params *params) +{ + int errno, link_id = -1; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_add_key(wiphy, ndev, key_index, pairwise, + mac_addr, params, link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +static int __wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + int link_id, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct key_params params; + eCsrEncryptionType enc_type; + int32_t ucast_cipher = 0; + struct wlan_objmgr_vdev *link_vdev; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + hdd_debug("Device_mode %s(%d)", + qdf_opmode_str(adapter->device_mode), adapter->device_mode); + + memset(¶ms, 0, sizeof(params)); + + if (key_index >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX + + WLAN_CRYPTO_MAXBIGTKKEYIDX)) { + hdd_err("Invalid key index: %d", key_index); + return -EINVAL; + } + + link_vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_ID, link_id); + if (!link_vdev) { + hdd_err("Invalid vdev for link_id :%d", link_id); + return -EINVAL; + } + + if (link_vdev) + ucast_cipher = wlan_crypto_get_param(link_vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + sme_fill_enc_type(&enc_type, ucast_cipher); + + switch (enc_type) { + case eCSR_ENCRYPT_TYPE_NONE: + params.cipher = IW_AUTH_CIPHER_NONE; + break; + + case eCSR_ENCRYPT_TYPE_WEP40_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP40: + params.cipher = WLAN_CIPHER_SUITE_WEP40; + break; + + case eCSR_ENCRYPT_TYPE_WEP104_STATICKEY: + case eCSR_ENCRYPT_TYPE_WEP104: + params.cipher = WLAN_CIPHER_SUITE_WEP104; + break; + + case eCSR_ENCRYPT_TYPE_TKIP: + params.cipher = WLAN_CIPHER_SUITE_TKIP; + break; + + case eCSR_ENCRYPT_TYPE_AES: + params.cipher = WLAN_CIPHER_SUITE_AES_CMAC; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP: + params.cipher = WLAN_CIPHER_SUITE_GCMP; + break; + case eCSR_ENCRYPT_TYPE_AES_GCMP_256: + params.cipher = WLAN_CIPHER_SUITE_GCMP_256; + break; + default: + params.cipher = IW_AUTH_CIPHER_NONE; + break; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_KEY, + wlan_vdev_get_id(link_vdev), params.cipher); + + params.key_len = 0; + params.seq_len = 0; + params.seq = NULL; + params.key = NULL; + callback(cookie, ¶ms); + + wlan_key_put_link_vdev(link_vdev, WLAN_OSIF_ID); + hdd_exit(); + return 0; +} + +#ifdef CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +static int wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + int errno = -EINVAL; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = qdf_container_of(wdev, + struct hdd_adapter, + wdev); + int link_id = -1; + + if (!adapter || wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_key(wiphy, adapter->dev, link_id, + key_index, + pairwise, mac_addr, cookie, + callback); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_MLO_KEY_OPERATION_SUPPORT) +static int wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + int link_id, u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_key(wiphy, ndev, link_id, key_index, + pairwise, mac_addr, cookie, + callback); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_get_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, bool pairwise, + const u8 *mac_addr, void *cookie, + void (*callback)(void *cookie, + struct key_params *) + ) +{ + int errno; + int link_id = -1; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_key(wiphy, ndev, link_id, key_index, + pairwise, mac_addr, cookie, + callback); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +/** + * __wlan_hdd_cfg80211_del_key() - Delete the encryption key for station + * @wiphy: wiphy interface context + * @ndev: pointer to net device + * @key_index: Key index used in 802.11 frames + * @pairwise: true if it is pairwise key + * @mac_addr: Peer address + * + * This function is required for cfg80211_ops API. + * It is used to delete the key information + * Underlying hardware implementation does not have API to delete the + * encryption key for normal peers. Currently delete keys are supported + * only for PASN peers. + * For other peers, it is automatically deleted when the peer is + * removed. Hence this function currently does nothing. + * Future implementation may interpret delete key operation to + * replacing the key with a random junk value, effectively making it + * useless. + * + * Return: status code, always 0. + */ + +static int __wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct wlan_objmgr_peer *peer; + struct qdf_mac_addr peer_mac; + enum wlan_peer_type peer_type; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int ret; + + hdd_enter(); + + if (!mac_addr) { + hdd_debug("Peer mac address is NULL"); + hdd_exit(); + return 0; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + qdf_mem_copy(peer_mac.bytes, mac_addr, QDF_MAC_ADDR_SIZE); + if (qdf_is_macaddr_zero(&peer_mac) || + qdf_is_macaddr_broadcast(&peer_mac)) { + hdd_err("Invalid mac address"); + ret = -EINVAL; + goto err; + } + + peer = wlan_objmgr_get_peer_by_mac(hdd_ctx->psoc, peer_mac.bytes, + WLAN_OSIF_ID); + if (peer) { + peer_type = wlan_peer_get_peer_type(peer); + if (peer_type == WLAN_PEER_RTT_PASN) { + status = wifi_pos_send_pasn_peer_deauth(hdd_ctx->psoc, + &peer_mac); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("send_pasn_peer_deauth failed"); + + ret = qdf_status_to_os_return(status); + } + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + } +err: + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_cfg80211_del_key() - cfg80211 delete key handler function + * @wiphy: Pointer to wiphy structure. + * @wdev: Pointer to wireless_dev structure. + * @key_index: key index + * @pairwise: pairwise + * @mac_addr: mac address + * + * This is the cfg80211 delete key handler function which invokes + * the internal function @__wlan_hdd_cfg80211_del_key with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +#ifdef CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + int errno = -EINVAL; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = qdf_container_of(wdev, + struct hdd_adapter, + wdev); + + if (!adapter || wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_del_key(wiphy, adapter->dev, key_index, + pairwise, mac_addr); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_MLO_KEY_OPERATION_SUPPORT) +static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *dev, + int link_id, u8 key_index, + bool pairwise, const u8 *mac_addr) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_del_key(wiphy, dev, key_index, + pairwise, mac_addr); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_del_key(struct wiphy *wiphy, + struct net_device *dev, + u8 key_index, bool pairwise, + const u8 *mac_addr) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_del_key(wiphy, dev, key_index, + pairwise, mac_addr); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif +static int __wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + int link_id, + u8 key_index, + bool unicast, bool multicast) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; + struct hdd_ap_ctx *ap_ctx; + struct wlan_crypto_key *crypto_key; + struct wlan_objmgr_vdev *vdev; + int ret; + QDF_STATUS status; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY, + adapter->deflink->vdev_id, key_index); + + hdd_debug("Device_mode %s(%d) key_index = %d", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode, key_index); + + if (key_index >= (WLAN_CRYPTO_MAXKEYIDX + WLAN_CRYPTO_MAXIGTKKEYIDX + + WLAN_CRYPTO_MAXBIGTKKEYIDX)) { + hdd_err("Invalid key index: %d", key_index); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + + if (0 != ret) + return ret; + + vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_ID, link_id); + if (!vdev) + return -EINVAL; + + crypto_key = wlan_crypto_get_key(vdev, key_index); + if (!crypto_key) { + hdd_err("Invalid NULL key info"); + ret = -EINVAL; + goto out; + } + hdd_debug("unicast %d, multicast %d cipher %d", + unicast, multicast, crypto_key->cipher_type); + if (!IS_WEP_CIPHER(crypto_key->cipher_type)) { + ret = 0; + goto out; + } + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + ret = + wlan_cfg80211_crypto_add_key(vdev, + (unicast ? + WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP), + key_index, true); + wma_update_set_key(adapter->deflink->vdev_id, unicast, + key_index, crypto_key->cipher_type); + } + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + status = wlan_cfg80211_set_default_key(vdev, key_index, + &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("ret fail status %d", ret); + ret = -EINVAL; + goto out; + } + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + ap_ctx->wep_def_key_idx = key_index; + } + +out: + wlan_key_put_link_vdev(vdev, WLAN_OSIF_ID); + return ret; +} + +#ifdef CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index, + bool unicast, bool multicast) +{ + int errno = -EINVAL; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = qdf_container_of(wdev, + struct hdd_adapter, + wdev); + int link_id = -1; + + if (!adapter || wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_default_key(wiphy, adapter->dev, + link_id, key_index, + unicast, multicast); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_MLO_KEY_OPERATION_SUPPORT) +static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + int link_id, u8 key_index, + bool unicast, bool multicast) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_default_key(wiphy, ndev, link_id, + key_index, unicast, + multicast); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_set_default_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index, + bool unicast, bool multicast) +{ + int errno; + int link_id = -1; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_default_key(wiphy, ndev, link_id, + key_index, unicast, + multicast); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#if defined (CFG80211_BIGTK_CONFIGURATION_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +static int _wlan_hdd_cfg80211_set_default_beacon_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index) +{ + hdd_enter(); + return 0; +} + +#ifdef CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +static int wlan_hdd_cfg80211_set_default_beacon_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index) +{ + int errno = -EINVAL; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = qdf_container_of(wdev, + struct hdd_adapter, + wdev); + + if (!adapter || wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = _wlan_hdd_cfg80211_set_default_beacon_key(wiphy, adapter->dev, + key_index); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_MLO_KEY_OPERATION_SUPPORT) +static int wlan_hdd_cfg80211_set_default_beacon_key(struct wiphy *wiphy, + struct net_device *ndev, + int link_id, u8 key_index) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = _wlan_hdd_cfg80211_set_default_beacon_key(wiphy, ndev, + key_index); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_set_default_beacon_key(struct wiphy *wiphy, + struct net_device *ndev, + u8 key_index) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = _wlan_hdd_cfg80211_set_default_beacon_key(wiphy, ndev, + key_index); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif +#endif + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +static +void hdd_mon_select_cbmode(struct hdd_adapter *adapter, + uint32_t op_freq, + struct ch_params *ch_params) +{ + struct hdd_station_ctx *station_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct hdd_mon_set_ch_info *ch_info = &station_ctx->ch_info; + enum hdd_dot11_mode hdd_dot11_mode; + uint8_t ini_dot11_mode = + (WLAN_HDD_GET_CTX(adapter))->config->dot11Mode; + + hdd_debug("Dot11Mode is %u", ini_dot11_mode); + switch (ini_dot11_mode) { + case eHDD_DOT11_MODE_AUTO: +#ifdef WLAN_FEATURE_11BE + case eHDD_DOT11_MODE_11be: + case eHDD_DOT11_MODE_11be_ONLY: + if (sme_is_feature_supported_by_fw(DOT11BE)) + hdd_dot11_mode = eHDD_DOT11_MODE_11be; + else +#endif + if (sme_is_feature_supported_by_fw(DOT11AX)) + hdd_dot11_mode = eHDD_DOT11_MODE_11ax; + else if (sme_is_feature_supported_by_fw(DOT11AC)) + hdd_dot11_mode = eHDD_DOT11_MODE_11ac; + else + hdd_dot11_mode = eHDD_DOT11_MODE_11n; + break; + case eHDD_DOT11_MODE_11ax: + case eHDD_DOT11_MODE_11ax_ONLY: + if (sme_is_feature_supported_by_fw(DOT11AX)) + hdd_dot11_mode = eHDD_DOT11_MODE_11ax; + else if (sme_is_feature_supported_by_fw(DOT11AC)) + hdd_dot11_mode = eHDD_DOT11_MODE_11ac; + else + hdd_dot11_mode = eHDD_DOT11_MODE_11n; + break; + case eHDD_DOT11_MODE_11ac: + case eHDD_DOT11_MODE_11ac_ONLY: + if (sme_is_feature_supported_by_fw(DOT11AC)) + hdd_dot11_mode = eHDD_DOT11_MODE_11ac; + else + hdd_dot11_mode = eHDD_DOT11_MODE_11n; + break; + case eHDD_DOT11_MODE_11n: + case eHDD_DOT11_MODE_11n_ONLY: + hdd_dot11_mode = eHDD_DOT11_MODE_11n; + break; + default: + hdd_dot11_mode = ini_dot11_mode; + break; + } + ch_info->channel_width = ch_params->ch_width; + ch_info->phy_mode = + hdd_cfg_xlate_to_csr_phy_mode(hdd_dot11_mode); + ch_info->freq = op_freq; + ch_info->cb_mode = ch_params->ch_width; + hdd_debug("ch_info width %d, phymode %d channel freq %d", + ch_info->channel_width, ch_info->phy_mode, + ch_info->freq); +} +#else +static +void hdd_mon_select_cbmode(struct hdd_adapter *adapter, + uint32_t op_freq, + struct ch_params *ch_params) +{ +} +#endif + +void hdd_select_cbmode(struct hdd_adapter *adapter, qdf_freq_t oper_freq, + qdf_freq_t sec_ch_2g_freq, struct ch_params *ch_params) +{ + uint32_t sec_ch_freq = 0; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* + * CDS api expects secondary channel for calculating + * the channel params + */ + if (ch_params->ch_width == CH_WIDTH_40MHZ && + WLAN_REG_IS_24GHZ_CH_FREQ(oper_freq)) { + if (sec_ch_2g_freq) { + sec_ch_freq = sec_ch_2g_freq; + } else { + if (oper_freq >= 2412 && oper_freq <= 2432) + sec_ch_freq = oper_freq + 20; + else if (oper_freq >= 2437 && oper_freq <= 2472) + sec_ch_freq = oper_freq - 20; + } + } + + /* This call decides required channel bonding mode */ + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, oper_freq, + sec_ch_freq, ch_params, + REG_CURRENT_PWR_MODE); + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE || + policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc)) + hdd_mon_select_cbmode(adapter, oper_freq, ch_params); +} + +/** + * wlan_hdd_cfg80211_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @ndev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(ndev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_cm_connect(wiphy, ndev, req); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_cfg80211_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_cm_disconnect(wiphy, dev, reason); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters + * @wiphy: Pointer to wiphy + * @changed: Parameters changed + * + * This function is used to set the phy parameters. RTS Threshold/FRAG + * Threshold/Retry Count etc. + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, + u32 changed) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int status; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS, + NO_SESSION, wiphy->rts_threshold); + + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + u32 rts_threshold = (wiphy->rts_threshold == -1) ? + cfg_max(CFG_RTS_THRESHOLD) : + wiphy->rts_threshold; + + if ((cfg_min(CFG_RTS_THRESHOLD) > rts_threshold) || + (cfg_max(CFG_RTS_THRESHOLD) < rts_threshold)) { + hdd_err("Invalid RTS Threshold value: %u", + rts_threshold); + return -EINVAL; + } + + if (0 != ucfg_mlme_set_rts_threshold(hdd_ctx->psoc, + rts_threshold)) { + hdd_err("mlme_set_rts_threshold failed for val %u", + rts_threshold); + return -EIO; + } + + hdd_debug("set rts threshold %u", rts_threshold); + } + + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + u16 frag_threshold = (wiphy->frag_threshold == -1) ? + cfg_max(CFG_FRAG_THRESHOLD) : + wiphy->frag_threshold; + + if ((cfg_min(CFG_FRAG_THRESHOLD) > frag_threshold) || + (cfg_max(CFG_FRAG_THRESHOLD) < frag_threshold)) { + hdd_err("Invalid frag_threshold value %hu", + frag_threshold); + return -EINVAL; + } + + if (0 != ucfg_mlme_set_frag_threshold(hdd_ctx->psoc, + frag_threshold)) { + hdd_err("mlme_set_frag_threshold failed for val %hu", + frag_threshold); + return -EIO; + } + + hdd_debug("set frag threshold %hu", frag_threshold); + } + + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_wiphy_params() - set wiphy parameters + * @wiphy: Pointer to wiphy + * @changed: Parameters changed + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_wiphy_params(wiphy, changed); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * __wlan_hdd_set_default_mgmt_key() - dummy implementation of set default mgmt + * key + * @wiphy: Pointer to wiphy + * @netdev: Pointer to network device + * @key_index: Key index + * + * Return: 0 + */ +static int __wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + hdd_enter(); + return 0; +} + +/** + * wlan_hdd_set_default_mgmt_key() - SSR wrapper for + * wlan_hdd_set_default_mgmt_key + * @wiphy: pointer to wiphy + * @wdev: pointer to wireless_device structure + * @key_index: key index + * + * Return: 0 on success, error number on failure + */ +#ifdef CFG80211_KEY_INSTALL_SUPPORT_ON_WDEV +static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct wireless_dev *wdev, + u8 key_index) +{ + int errno = -EINVAL; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = qdf_container_of(wdev, + struct hdd_adapter, + wdev); + + if (!adapter || wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_set_default_mgmt_key(wiphy, adapter->dev, key_index); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#elif defined(CFG80211_MLO_KEY_OPERATION_SUPPORT) +static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + int link_id, u8 key_index) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_set_default_mgmt_key(wiphy, netdev, key_index); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_set_default_mgmt_key(struct wiphy *wiphy, + struct net_device *netdev, + u8 key_index) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_set_default_mgmt_key(wiphy, netdev, key_index); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +/* + * Default val of cwmin, this value is used to override the + * incorrect user set value + */ +#define DEFAULT_CWMIN 15 + +/* + * Default val of cwmax, this value is used to override the + * incorrect user set value + */ +#define DEFAULT_CWMAX 1023 + +/** + * __wlan_hdd_set_txq_params() - implementation of set tx queue params + * to configure internal EDCA parameters + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @params: Pointer to tx queue parameters + * + * Return: 0 + */ +static int __wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_txq_params *params) +{ + QDF_STATUS status; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle_t mac_handle; + tSirMacEdcaParamRecord txq_edca_params; + static const uint8_t ieee_ac_to_qca_ac[] = { + [IEEE80211_AC_VO] = QCA_WLAN_AC_VO, + [IEEE80211_AC_VI] = QCA_WLAN_AC_VI, + [IEEE80211_AC_BE] = QCA_WLAN_AC_BE, + [IEEE80211_AC_BK] = QCA_WLAN_AC_BK, + }; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + mac_handle = hdd_ctx->mac_handle; + if (params->cwmin == 0 || params->cwmin > DEFAULT_CWMAX) + params->cwmin = DEFAULT_CWMIN; + + if (params->cwmax < params->cwmin || params->cwmax > DEFAULT_CWMAX) + params->cwmax = DEFAULT_CWMAX; + + txq_edca_params.cw.min = convert_cw(params->cwmin); + txq_edca_params.cw.max = convert_cw(params->cwmax); + txq_edca_params.aci.aifsn = params->aifs; + /* The txop is multiple of 32us units */ + txq_edca_params.txoplimit = params->txop; + txq_edca_params.aci.aci = + ieee_ac_to_qca_ac[params->ac]; + + status = sme_update_session_txq_edca_params(mac_handle, + adapter->deflink->vdev_id, + &txq_edca_params); + + hdd_exit(); + return qdf_status_to_os_return(status); +} + +/** + * wlan_hdd_set_txq_params() - SSR wrapper for wlan_hdd_set_txq_params + * @wiphy: pointer to wiphy + * @dev: pointer to net_device structure + * @params: pointer to ieee80211_txq_params + * + * Return: 0 on success, error number on failure + */ +static int wlan_hdd_set_txq_params(struct wiphy *wiphy, + struct net_device *dev, + struct ieee80211_txq_params *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_set_txq_params(wiphy, dev, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_softap_deauth_current_sta() - Deauth current sta + * @adapter: pointer to adapter structure + * @sta_info: pointer to the current station info structure + * @hapd_state: pointer to hostapd state structure + * @param: pointer to del sta params + * + * Return: QDF_STATUS on success, corresponding QDF failure status on failure + */ +static +QDF_STATUS hdd_softap_deauth_current_sta(struct hdd_adapter *adapter, + struct hdd_station_info *sta_info, + struct hdd_hostapd_state *hapd_state, + struct csr_del_sta_params *param) +{ + qdf_event_t *disassoc_event = &hapd_state->qdf_sta_disassoc_event; + struct hdd_context *hdd_ctx; + QDF_STATUS qdf_status; + struct hdd_station_info *tmp = NULL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + qdf_event_reset(&hapd_state->qdf_sta_disassoc_event); + + if (!qdf_is_macaddr_broadcast(¶m->peerMacAddr)) + sme_send_disassoc_req_frame(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + (uint8_t *)¶m->peerMacAddr, + param->reason_code, 0); + + qdf_status = hdd_softap_sta_deauth(adapter, param); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (qdf_is_macaddr_broadcast(&sta_info->sta_mac)) { + hdd_for_each_sta_ref_safe( + adapter->sta_info_list, + sta_info, tmp, + STA_INFO_SOFTAP_DEAUTH_CURRENT_STA) { + sta_info->is_deauth_in_progress = true; + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &sta_info, true, + STA_INFO_SOFTAP_DEAUTH_CURRENT_STA); + } + } else { + sta_info->is_deauth_in_progress = true; + } + qdf_status = qdf_wait_for_event_completion( + disassoc_event, + SME_PEER_DISCONNECT_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_warn("Deauth time expired"); + } else { + sta_info->is_deauth_in_progress = false; + hdd_debug("STA removal failed for ::" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_info->sta_mac.bytes)); + return QDF_STATUS_E_NOENT; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter, + struct hdd_hostapd_state *hapd_state, + struct csr_del_sta_params *param) +{ + QDF_STATUS status; + bool is_sap_bcast_deauth_enabled = false; + struct hdd_context *hdd_ctx; + struct hdd_station_info *sta_info, *tmp = NULL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + ucfg_mlme_get_sap_bcast_deauth_enabled(hdd_ctx->psoc, + &is_sap_bcast_deauth_enabled); + + hdd_debug("sap_bcast_deauth_enabled %d", is_sap_bcast_deauth_enabled); + + if (is_sap_bcast_deauth_enabled) { + struct hdd_station_info bcast_sta_info; + + qdf_set_macaddr_broadcast(&bcast_sta_info.sta_mac); + return hdd_softap_deauth_current_sta(adapter, &bcast_sta_info, + hapd_state, param); + } + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_SOFTAP_DEAUTH_ALL_STA) { + if (!sta_info->is_deauth_in_progress) { + hdd_debug("Delete STA with MAC:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_info->sta_mac.bytes)); + + if (QDF_IS_ADDR_BROADCAST(sta_info->sta_mac.bytes)) { + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_SOFTAP_DEAUTH_ALL_STA); + continue; + } + + qdf_mem_copy(param->peerMacAddr.bytes, + sta_info->sta_mac.bytes, + QDF_MAC_ADDR_SIZE); + status = + hdd_softap_deauth_current_sta(adapter, sta_info, + hapd_state, param); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &sta_info, true, + STA_INFO_SOFTAP_DEAUTH_ALL_STA); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_SOFTAP_DEAUTH_ALL_STA); + return status; + } + } + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_DEAUTH_ALL_STA); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * __wlan_hdd_cfg80211_del_station() - delete station v2 + * @wiphy: Pointer to wiphy + * @dev: Underlying net device + * @param: Pointer to delete station parameter + * + * Return: 0 for success, non-zero for failure + */ +static +int __wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct csr_del_sta_params *param) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct hdd_hostapd_state *hapd_state; + uint8_t *mac; + struct hdd_station_info *sta_info; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_STA, + adapter->deflink->vdev_id, adapter->device_mode); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return -EINVAL; + } + + mac = (uint8_t *) param->peerMacAddr.bytes; + + if (QDF_SAP_MODE != adapter->device_mode && + QDF_P2P_GO_MODE != adapter->device_mode) + goto fn_end; + + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + if (!hapd_state) { + hdd_err("Hostapd State is Null"); + return 0; + } + + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *)mac)) { + if (!QDF_IS_STATUS_SUCCESS(hdd_softap_deauth_all_sta(adapter, + hapd_state, + param))) + goto fn_end; + } else { + if (param->reason_code == REASON_1X_AUTH_FAILURE) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_softap_check_wait_for_tx_eap_pkt(vdev, + (struct qdf_mac_addr *)mac); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + } + + sta_info = hdd_get_sta_info_by_mac( + &adapter->sta_info_list, + mac, + STA_INFO_CFG80211_DEL_STATION); + + if (!sta_info) { + hdd_debug("Skip DEL STA as this is not used::" + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + return -ENOENT; + } + + if (sta_info->is_deauth_in_progress) { + hdd_debug("Skip DEL STA as deauth is in progress::" + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, + true, + STA_INFO_CFG80211_DEL_STATION); + return -ENOENT; + } + + hdd_debug("ucast, Delete STA with MAC:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + hdd_softap_deauth_current_sta(adapter, sta_info, hapd_state, + param); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_CFG80211_DEL_STATION); + } + +fn_end: + hdd_exit(); + return 0; +} + +#if defined(USE_CFG80211_DEL_STA_V2) +int wlan_hdd_del_station(struct hdd_adapter *adapter, const uint8_t *mac) +{ + struct station_del_parameters del_sta; + + del_sta.mac = mac; + del_sta.subtype = IEEE80211_STYPE_DEAUTH >> 4; + del_sta.reason_code = WLAN_REASON_DEAUTH_LEAVING; + + return wlan_hdd_cfg80211_del_station(adapter->wdev.wiphy, + adapter->dev, &del_sta); +} +#else +int wlan_hdd_del_station(struct hdd_adapter *adapter, const uint8_t *mac) +{ + return wlan_hdd_cfg80211_del_station(adapter->wdev.wiphy, + adapter->dev, mac); +} +#endif + +/** + * _wlan_hdd_cfg80211_del_station() - delete station entry handler + * @wiphy: Pointer to wiphy + * @dev: net_device to operate against + * @mac: binary mac address + * @reason_code: reason for the deauthorization/disassociation + * @subtype: management frame subtype to indicate removal + * + * Return: Errno + */ +static int _wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype) +{ + int errno; + struct csr_del_sta_params delStaParams; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + wlansap_populate_del_sta_params(mac, reason_code, subtype, + &delStaParams); + errno = __wlan_hdd_cfg80211_del_station(wiphy, dev, &delStaParams); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef USE_CFG80211_DEL_STA_V2 +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param) +{ + if (!param) + return -EINVAL; + + return _wlan_hdd_cfg80211_del_station(wiphy, dev, param->mac, + param->reason_code, + param->subtype); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, + const uint8_t *mac) +{ + uint16_t reason = REASON_DEAUTH_NETWORK_LEAVING; + uint8_t subtype = SIR_MAC_MGMT_DEAUTH >> 4; + + return _wlan_hdd_cfg80211_del_station(wiphy, dev, mac, reason, subtype); +} +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, + uint8_t *mac) +{ + uint16_t reason = REASON_DEAUTH_NETWORK_LEAVING; + uint8_t subtype = SIR_MAC_MGMT_DEAUTH >> 4; + + return _wlan_hdd_cfg80211_del_station(wiphy, dev, mac, reason, subtype); +} +#endif + +#ifdef CFG80211_LINK_STA_PARAMS_PRESENT +static inline +uint8_t wlan_hdd_get_link_id(struct station_parameters *params) +{ + return params->link_sta_params.link_id; +} +#else +static inline +uint8_t wlan_hdd_get_link_id(struct station_parameters *params) +{ + return 255; +} +#endif +/** + * __wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to station mac address + * @params: Pointer to add station parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +{ + int status = -EPERM; +#ifdef FEATURE_WLAN_TDLS + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + u32 mask, set; + uint8_t link_id; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_ADD_STA, + adapter->deflink->vdev_id, params->listen_interval); + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + mask = params->sta_flags_mask; + set = params->sta_flags_set; + link_id = wlan_hdd_get_link_id(params); + hdd_debug("mask 0x%x set 0x%x link_id %d " QDF_MAC_ADDR_FMT, mask, set, + link_id, QDF_MAC_ADDR_REF(mac)); + + if (mask & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + if (set & BIT(NL80211_STA_FLAG_TDLS_PEER)) { + status = wlan_cfg80211_tdls_add_peer_mlo(adapter, + mac, link_id); + } + } +#endif + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_add_station() - add station + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to station mac address + * @params: Pointer to add station parameter + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_parameters *params) +#else +static int wlan_hdd_cfg80211_add_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_parameters *params) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_add_station(wiphy, dev, mac, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#if (defined(CFG80211_CONFIG_PMKSA_TIMER_PARAMS_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))) +static inline void +hdd_fill_pmksa_lifetime(struct cfg80211_pmksa *pmksa, + struct wlan_crypto_pmksa *pmk_cache) +{ + pmk_cache->pmk_lifetime = pmksa->pmk_lifetime; + if (pmk_cache->pmk_lifetime > WLAN_CRYPTO_MAX_PMKID_LIFETIME) + pmk_cache->pmk_lifetime = WLAN_CRYPTO_MAX_PMKID_LIFETIME; + + pmk_cache->pmk_lifetime_threshold = pmksa->pmk_reauth_threshold; + if (pmk_cache->pmk_lifetime_threshold >= + WLAN_CRYPTO_MAX_PMKID_LIFETIME_THRESHOLD) + pmk_cache->pmk_lifetime_threshold = + WLAN_CRYPTO_MAX_PMKID_LIFETIME_THRESHOLD - 1; + + hdd_debug("PMKSA: lifetime:%d threshold:%d", pmk_cache->pmk_lifetime, + pmk_cache->pmk_lifetime_threshold); +} +#else +static inline void +hdd_fill_pmksa_lifetime(struct cfg80211_pmksa *pmksa, + struct wlan_crypto_pmksa *src_pmk_cache) +{} +#endif + +static QDF_STATUS wlan_hdd_set_pmksa_cache(struct hdd_adapter *adapter, + struct wlan_crypto_pmksa *pmk_cache) +{ + QDF_STATUS result; + struct wlan_crypto_pmksa *pmksa; + struct wlan_objmgr_vdev *vdev; + mac_handle_t mac_handle; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_INVAL; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_INVAL; + mac_handle = hdd_ctx->mac_handle; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + pmksa = qdf_mem_malloc(sizeof(*pmksa)); + if (!pmksa) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return QDF_STATUS_E_NOMEM; + } + + if (!pmk_cache->ssid_len) { + qdf_copy_macaddr(&pmksa->bssid, &pmk_cache->bssid); + } else { + qdf_mem_copy(pmksa->ssid, pmk_cache->ssid, pmk_cache->ssid_len); + qdf_mem_copy(pmksa->cache_id, pmk_cache->cache_id, + WLAN_CACHE_ID_LEN); + pmksa->ssid_len = pmk_cache->ssid_len; + } + qdf_mem_copy(pmksa->pmkid, pmk_cache->pmkid, PMKID_LEN); + qdf_mem_copy(pmksa->pmk, pmk_cache->pmk, pmk_cache->pmk_len); + pmksa->pmk_len = pmk_cache->pmk_len; + pmksa->pmk_entry_ts = qdf_get_system_timestamp(); + pmksa->pmk_lifetime = pmk_cache->pmk_lifetime; + pmksa->pmk_lifetime_threshold = pmk_cache->pmk_lifetime_threshold; + + result = wlan_crypto_set_del_pmksa(vdev, pmksa, true); + if (result != QDF_STATUS_SUCCESS) { + qdf_mem_zero(pmksa, sizeof(*pmksa)); + qdf_mem_free(pmksa); + } + + if (result == QDF_STATUS_SUCCESS && pmk_cache->pmk_len) { + sme_roam_set_psk_pmk(mac_handle, pmksa, + adapter->deflink->vdev_id, false); + sme_set_pmk_cache_ft(mac_handle, adapter->deflink->vdev_id, + pmk_cache); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return result; +} + +static QDF_STATUS wlan_hdd_del_pmksa_cache(struct hdd_adapter *adapter, + struct wlan_crypto_pmksa *pmk_cache) +{ + QDF_STATUS result; + struct wlan_crypto_pmksa pmksa; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + qdf_mem_zero(&pmksa, sizeof(pmksa)); + if (!pmk_cache->ssid_len) { + qdf_copy_macaddr(&pmksa.bssid, &pmk_cache->bssid); + } else { + qdf_mem_copy(pmksa.ssid, pmk_cache->ssid, pmk_cache->ssid_len); + qdf_mem_copy(pmksa.cache_id, pmk_cache->cache_id, + WLAN_CACHE_ID_LEN); + pmksa.ssid_len = pmk_cache->ssid_len; + } + + result = wlan_crypto_set_del_pmksa(vdev, &pmksa, false); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return result; +} + +QDF_STATUS wlan_hdd_flush_pmksa_cache(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS result; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + result = wlan_crypto_set_del_pmksa(vdev, NULL, false); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (QDF_IS_STATUS_ERROR(result)) + hdd_debug("Cannot flush PMKIDCache"); + + return result; +} + +#if defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) +/* + * wlan_hdd_is_pmksa_valid: API to validate pmksa + * @pmksa: pointer to cfg80211_pmksa structure + * + * Return: True if valid else false + */ +static inline bool wlan_hdd_is_pmksa_valid(struct cfg80211_pmksa *pmksa) +{ + if (!pmksa->bssid) { + hdd_warn("bssid is NULL"); + if (!pmksa->ssid || !pmksa->cache_id) { + hdd_err("either ssid or cache_id are NULL"); + return false; + } + } + return true; +} + +/* + * hdd_fill_pmksa_info: API to update tPmkidCacheInfo from cfg80211_pmksa + * @adapter: Pointer to hdd adapter + * @pmk_cache: pmk that needs to be updated + * @pmksa: pmk from supplicant + * @is_delete: Bool to decide set or delete PMK + * Return: None + */ +static void hdd_fill_pmksa_info(struct hdd_adapter *adapter, + struct wlan_crypto_pmksa *pmk_cache, + struct cfg80211_pmksa *pmksa, bool is_delete) +{ + if (pmksa->bssid) { + hdd_debug("%s PMKSA for " QDF_MAC_ADDR_FMT, + is_delete ? "Delete" : "Set", + QDF_MAC_ADDR_REF(pmksa->bssid)); + qdf_mem_copy(pmk_cache->bssid.bytes, + pmksa->bssid, QDF_MAC_ADDR_SIZE); + } else { + qdf_mem_copy(pmk_cache->ssid, pmksa->ssid, pmksa->ssid_len); + qdf_mem_copy(pmk_cache->cache_id, pmksa->cache_id, + CACHE_ID_LEN); + pmk_cache->ssid_len = pmksa->ssid_len; + hdd_debug("%s PMKSA for ssid " QDF_SSID_FMT " cache_id %x %x", + is_delete ? "Delete" : "Set", + QDF_SSID_REF(pmk_cache->ssid_len, pmk_cache->ssid), + pmk_cache->cache_id[0], + pmk_cache->cache_id[1]); + } + qdf_mem_copy(pmk_cache->pmkid, pmksa->pmkid, PMKID_LEN); + + hdd_fill_pmksa_lifetime(pmksa, pmk_cache); + + if (is_delete) + return; + + if (pmksa->pmk_len && (pmksa->pmk_len <= MAX_PMK_LEN)) { + qdf_mem_copy(pmk_cache->pmk, pmksa->pmk, pmksa->pmk_len); + pmk_cache->pmk_len = pmksa->pmk_len; + } else + hdd_err("Invalid pmk len is %zu", pmksa->pmk_len); +} +#else +/* + * wlan_hdd_is_pmksa_valid: API to validate pmksa + * @pmksa: pointer to cfg80211_pmksa structure + * + * Return: True if valid else false + */ +static inline bool wlan_hdd_is_pmksa_valid(struct cfg80211_pmksa *pmksa) +{ + if (!pmksa->bssid) { + hdd_err("both bssid is NULL %pK", pmksa->bssid); + return false; + } + return true; +} + +/* + * hdd_fill_pmksa_info: API to update struct wlan_crypto_pmksa from + * cfg80211_pmksa + * @adapter: Pointer to hdd adapter + * @pmk_cache: pmk which needs to be updated + * @pmksa: pmk from supplicant + * @is_delete: Bool to decide whether to set or delete PMK + * + * Return: None + */ +static void hdd_fill_pmksa_info(struct hdd_adapter *adapter, + struct wlan_crypto_pmksa *pmk_cache, + struct cfg80211_pmksa *pmksa, bool is_delete) +{ + mac_handle_t mac_handle; + + hdd_debug("%s PMKSA for " QDF_MAC_ADDR_FMT, is_delete ? "Delete" : "Set", + QDF_MAC_ADDR_REF(pmksa->bssid)); + qdf_mem_copy(pmk_cache->bssid.bytes, pmksa->bssid, QDF_MAC_ADDR_SIZE); + + if (is_delete) + return; + mac_handle = hdd_adapter_get_mac_handle(adapter); + sme_get_pmk_info(mac_handle, adapter->deflink->vdev_id, pmk_cache); + qdf_mem_copy(pmk_cache->pmkid, pmksa->pmkid, PMKID_LEN); +} +#endif + +/** + * __wlan_hdd_cfg80211_set_pmksa() - set pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to set pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS result = QDF_STATUS_SUCCESS; + int status; + struct wlan_crypto_pmksa *pmk_cache; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (!pmksa) { + hdd_err("pmksa is NULL"); + return -EINVAL; + } + + if (!pmksa->pmkid) { + hdd_err("pmksa->pmkid(%pK) is NULL", + pmksa->pmkid); + return -EINVAL; + } + + if (!wlan_hdd_is_pmksa_valid(pmksa)) + return -EINVAL; + + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + pmk_cache = qdf_mem_malloc(sizeof(*pmk_cache)); + if (!pmk_cache) + return -ENOMEM; + + hdd_fill_pmksa_info(adapter, pmk_cache, pmksa, false); + + /* + * Add to the PMKSA Cache in CSR + * PMKSA cache will be having following + * 1. pmkid id + * 2. pmk + * 3. bssid or cache identifier + */ + result = wlan_hdd_set_pmksa_cache(adapter, pmk_cache); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_PMKSA, + adapter->deflink->vdev_id, result); + + if (QDF_IS_STATUS_SUCCESS(result) || result == QDF_STATUS_E_EXISTS) + sme_set_del_pmkid_cache(hdd_ctx->psoc, + adapter->deflink->vdev_id, + pmk_cache, true); + + qdf_mem_zero(pmk_cache, sizeof(*pmk_cache)); + + qdf_mem_free(pmk_cache); + hdd_exit(); + + return QDF_IS_STATUS_SUCCESS(result) ? 0 : -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_pmksa() - set pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to set pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_set_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_pmksa(wiphy, dev, pmksa); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_del_pmksa() - delete pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + int status = 0; + struct wlan_crypto_pmksa *pmk_cache; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (!pmksa) { + hdd_err("pmksa is NULL"); + return -EINVAL; + } + + if (!wlan_hdd_is_pmksa_valid(pmksa)) + return -EINVAL; + + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + pmk_cache = qdf_mem_malloc(sizeof(*pmk_cache)); + if (!pmk_cache) + return -ENOMEM; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DEL_PMKSA, + adapter->deflink->vdev_id, 0); + + hdd_fill_pmksa_info(adapter, pmk_cache, pmksa, true); + + qdf_status = wlan_hdd_del_pmksa_cache(adapter, pmk_cache); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + if (!pmksa->bssid) + hdd_err("Failed to delete PMKSA for null bssid"); + else + hdd_err("Failed to delete PMKSA for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pmksa->bssid)); + status = -EINVAL; + } else { + /* clear single_pmk_info information */ + sme_clear_sae_single_pmk_info(hdd_ctx->psoc, + adapter->deflink->vdev_id, + pmk_cache); + + /* Send the delete pmkid command to firmware */ + sme_set_del_pmkid_cache(hdd_ctx->psoc, + adapter->deflink->vdev_id, + pmk_cache, false); + } + + qdf_mem_zero(pmk_cache, sizeof(*pmk_cache)); + qdf_mem_free(pmk_cache); + + hdd_exit(); + + return status; +} + +/** + * wlan_hdd_cfg80211_del_pmksa() - delete pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @pmksa: Pointer to pmksa parameter + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_del_pmksa(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_pmksa *pmksa) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_del_pmksa(wiphy, dev, pmksa); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; + +} + +/** + * __wlan_hdd_cfg80211_flush_pmksa() - flush pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int errno; + QDF_STATUS status; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + hdd_debug("Flushing PMKSA"); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + status = wlan_hdd_flush_pmksa_cache(adapter->deflink); + if (status == QDF_STATUS_E_NOSUPPORT) + errno = -EOPNOTSUPP; + else if (QDF_IS_STATUS_ERROR(status)) + errno = -EINVAL; + + sme_set_del_pmkid_cache(hdd_ctx->psoc, adapter->deflink->vdev_id, + NULL, false); + hdd_exit(); + return errno; +} + +/** + * wlan_hdd_cfg80211_flush_pmksa() - flush pmksa + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_flush_pmksa(struct wiphy *wiphy, + struct net_device *dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_flush_pmksa(wiphy, dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#if defined(KERNEL_SUPPORT_11R_CFG80211) +/** + * __wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @ftie: Pointer to fast transition ie parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int status; + + hdd_enter(); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES, + adapter->deflink->vdev_id, 0); + + /* Added for debug on reception of Re-assoc Req. */ + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Called with Ie of length = %zu when not associated", + ftie->ie_len); + hdd_err("Should be Re-assoc Req IEs"); + } + hdd_debug("called with Ie of length = %zu", ftie->ie_len); + + ucfg_cm_set_ft_ies(hdd_ctx->pdev, adapter->deflink->vdev_id, + (const u8 *)ftie->ie, ftie->ie_len); + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_update_ft_ies() - update fast transition ies + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @ftie: Pointer to fast transition ie parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_update_ft_ies(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_ft_ies_params *ftie) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_update_ft_ies(wiphy, dev, ftie); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#if defined(CFG80211_EXTERNAL_DH_UPDATE_SUPPORT) || \ +(LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0)) +/** + * __wlan_hdd_cfg80211_update_owe_info() - update OWE info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @owe_info: Pointer to OWE info + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_update_owe_info(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_update_owe_info *owe_info) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + QDF_STATUS status; + int errno; + struct sap_context *sap_ctx; + + hdd_enter_dev(dev); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + hdd_debug("owe_status %d", owe_info->status); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + status = wlansap_update_owe_info(sap_ctx, owe_info->peer, owe_info->ie, + owe_info->ie_len, owe_info->status); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update OWE info"); + errno = qdf_status_to_os_return(status); + } + + hdd_exit(); + return errno; +} + +/** + * wlan_hdd_cfg80211_update_owe_info() - update OWE info + * @wiphy: Pointer to wiphy + * @net_dev: Pointer to network device + * @owe_info: Pointer to OWE info + * + * Return: 0 for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_update_owe_info(struct wiphy *wiphy, + struct net_device *net_dev, + struct cfg80211_update_owe_info *owe_info) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_update_owe_info(wiphy, net_dev, owe_info); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +void wlan_hdd_cfg80211_update_replay_counter_cb( + void *cb_ctx, struct pmo_gtk_rsp_params *gtk_rsp_param) + +{ + struct hdd_adapter *adapter = (struct hdd_adapter *)cb_ctx; + uint8_t temp_replay_counter[8]; + int i; + uint8_t *p; + + hdd_enter(); + + if (!adapter) { + hdd_err("HDD adapter is Null"); + goto out; + } + + if (!gtk_rsp_param) { + hdd_err("gtk_rsp_param is Null"); + goto out; + } + + if (gtk_rsp_param->status_flag != QDF_STATUS_SUCCESS) { + hdd_err("wlan Failed to get replay counter value"); + goto out; + } + + hdd_debug("updated replay counter: %llu from fwr", + gtk_rsp_param->replay_counter); + /* convert little to big endian since supplicant works on big endian */ + p = (uint8_t *)>k_rsp_param->replay_counter; + for (i = 0; i < 8; i++) + temp_replay_counter[7 - i] = (uint8_t) p[i]; + + hdd_debug("gtk_rsp_param bssid "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(gtk_rsp_param->bssid.bytes)); + /* Update replay counter to NL */ + cfg80211_gtk_rekey_notify(adapter->dev, + gtk_rsp_param->bssid.bytes, + temp_replay_counter, GFP_KERNEL); +out: + hdd_exit(); + +} + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/** + * wlan_hdd_copy_gtk_kek - Copy the KEK from GTK rekey data to GTK request + * @gtk_req: Pointer to GTK request + * @data: Pointer to rekey data + * + * Return: none + */ +#if (defined(CFG80211_REKEY_DATA_KEK_LEN) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) +static +void wlan_hdd_copy_gtk_kek(struct pmo_gtk_req *gtk_req, + struct cfg80211_gtk_rekey_data *data) +{ + qdf_mem_copy(gtk_req->kek, data->kek, data->kek_len); + gtk_req->kek_len = data->kek_len; +} +#else +static +void wlan_hdd_copy_gtk_kek(struct pmo_gtk_req *gtk_req, + struct cfg80211_gtk_rekey_data *data) +{ + qdf_mem_copy(gtk_req->kek, data->kek, NL80211_KEK_LEN); + gtk_req->kek_len = NL80211_KEK_LEN; +} +#endif + +/** + * wlan_hdd_copy_gtk_kck - Copy the KCK from GTK rekey data to GTK request + * @gtk_req: Pointer to GTK request + * @data: Pointer to rekey data + * + * Return: None + */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0) +static +void wlan_hdd_copy_gtk_kck(struct pmo_gtk_req *gtk_req, + struct cfg80211_gtk_rekey_data *data) +{ + qdf_mem_copy(gtk_req->kck, data->kck, data->kck_len); + gtk_req->kck_len = data->kck_len; +} +#else +static +void wlan_hdd_copy_gtk_kck(struct pmo_gtk_req *gtk_req, + struct cfg80211_gtk_rekey_data *data) +{ + qdf_mem_copy(gtk_req->kck, data->kck, NL80211_KCK_LEN); + gtk_req->kck_len = NL80211_KCK_LEN; +} +#endif +/** + * __wlan_hdd_cfg80211_set_rekey_data() - set rekey data + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Pointer to rekey data + * + * This function is used to offload GTK rekeying job to the firmware. + * + * Return: 0 for success, non-zero for failure + */ +static +int __wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int result, i; + struct pmo_gtk_req *gtk_req = NULL; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t *buf; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + result = -EINVAL; + goto out; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) { + result = -EINVAL; + goto out; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA, + adapter->deflink->vdev_id, adapter->device_mode); + + result = wlan_hdd_validate_context(hdd_ctx); + if (0 != result) + goto out; + + gtk_req = qdf_mem_malloc(sizeof(*gtk_req)); + if (!gtk_req) { + result = -ENOMEM; + goto out; + } + + /* convert big to little endian since driver work on little endian */ + buf = (uint8_t *)>k_req->replay_counter; + for (i = 0; i < 8; i++) + buf[7 - i] = data->replay_ctr[i]; + + hdd_debug("current replay counter: %llu in user space", + gtk_req->replay_counter); + + wlan_hdd_copy_gtk_kek(gtk_req, data); + wlan_hdd_copy_gtk_kck(gtk_req, data); + + gtk_req->is_fils_connection = hdd_is_fils_connection(hdd_ctx, adapter); + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + result = -EINVAL; + goto out; + } + status = ucfg_pmo_cache_gtk_offload_req(vdev, gtk_req); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to cache GTK Offload"); + result = qdf_status_to_os_return(status); + } +out: + if (gtk_req) + qdf_mem_free(gtk_req); + hdd_exit(); + + return result; +} + +/** + * wlan_hdd_cfg80211_set_rekey_data() - set rekey data + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @data: Pointer to rekey data + * + * This function is used to offload GTK rekeying job to the firmware. + * + * Return: 0 for success, non-zero for failure + */ +static +int wlan_hdd_cfg80211_set_rekey_data(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_gtk_rekey_data *data) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_rekey_data(wiphy, dev, data); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +/** + * __wlan_hdd_cfg80211_set_mac_acl() - set access control policy + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @params: Pointer to access control parameter + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + const struct cfg80211_acl_data *params) +{ + int i; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_hostapd_state *hostapd_state; + struct sap_config *config; + struct hdd_context *hdd_ctx; + int status; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!params) { + hdd_err("params is Null"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + + if (!hostapd_state) { + hdd_err("hostapd_state is Null"); + return -EINVAL; + } + + hdd_debug("acl policy: %d num acl entries: %d", params->acl_policy, + params->n_acl_entries); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_MAC_ACL, + adapter->deflink->vdev_id, adapter->device_mode); + + if (QDF_SAP_MODE == adapter->device_mode) { + config = &adapter->deflink->session.ap.sap_config; + + /* default value */ + config->num_accept_mac = 0; + config->num_deny_mac = 0; + + /** + * access control policy + * @NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED: Deny stations which are + * listed in hostapd.deny file. + * @NL80211_ACL_POLICY_DENY_UNLESS_LISTED: Allow stations which are + * listed in hostapd.accept file. + */ + if (NL80211_ACL_POLICY_DENY_UNLESS_LISTED == params->acl_policy) { + config->SapMacaddr_acl = eSAP_DENY_UNLESS_ACCEPTED; + } else if (NL80211_ACL_POLICY_ACCEPT_UNLESS_LISTED == + params->acl_policy) { + config->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + } else { + hdd_warn("Acl Policy : %d is not supported", + params->acl_policy); + return -ENOTSUPP; + } + + if (eSAP_DENY_UNLESS_ACCEPTED == config->SapMacaddr_acl) { + config->num_accept_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hdd_debug("** Add ACL MAC entry %i in WhiletList :" + QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF( + params->mac_addrs[i].addr)); + + qdf_mem_copy(&config->accept_mac[i], + params->mac_addrs[i].addr, + QDF_MAC_ADDR_SIZE); + } + } else if (eSAP_ACCEPT_UNLESS_DENIED == config->SapMacaddr_acl) { + config->num_deny_mac = params->n_acl_entries; + for (i = 0; i < params->n_acl_entries; i++) { + hdd_debug("** Add ACL MAC entry %i in DenyList :" + QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF( + params->mac_addrs[i].addr)); + + qdf_mem_copy(&config->deny_mac[i], + params->mac_addrs[i].addr, + QDF_MAC_ADDR_SIZE); + } + } + qdf_status = wlansap_set_mac_acl( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), config); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Set Mac Acl fail"); + return -EINVAL; + } + } else { + hdd_debug("Invalid device_mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_set_mac_acl() - SSR wrapper for + * __wlan_hdd_cfg80211_set_mac_acl + * @wiphy: pointer to wiphy structure + * @dev: pointer to net_device + * @params: pointer to cfg80211_acl_data + * + * Return; 0 on success, error number otherwise + */ +static int +wlan_hdd_cfg80211_set_mac_acl(struct wiphy *wiphy, + struct net_device *dev, + const struct cfg80211_acl_data *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_mac_acl(wiphy, dev, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef WLAN_NL80211_TESTMODE +#ifdef FEATURE_WLAN_LPHB +/** + * wlan_hdd_cfg80211_lphb_ind_handler() - handle low power heart beat indication + * @hdd_ctx: Pointer to hdd context + * @lphb_ind: Pointer to low power heart beat indication parameter + * + * Return: none + */ +static void wlan_hdd_cfg80211_lphb_ind_handler(void *hdd_ctx, + struct pmo_lphb_rsp *lphb_ind) +{ + struct sk_buff *skb; + + hdd_debug("LPHB indication arrived"); + + if (0 != wlan_hdd_validate_context((struct hdd_context *) hdd_ctx)) + return; + + if (!lphb_ind) { + hdd_err("invalid argument lphbInd"); + return; + } + + skb = cfg80211_testmode_alloc_event_skb(((struct hdd_context *) hdd_ctx)-> + wiphy, sizeof(*lphb_ind), GFP_ATOMIC); + if (!skb) { + hdd_err("LPHB timeout, NL buffer alloc fail"); + return; + } + + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_CMD, WLAN_HDD_TM_CMD_WLAN_HB)) { + hdd_err("WLAN_HDD_TM_ATTR_CMD put fail"); + goto nla_put_failure; + } + if (nla_put_u32(skb, WLAN_HDD_TM_ATTR_TYPE, lphb_ind->protocol_type)) { + hdd_err("WLAN_HDD_TM_ATTR_TYPE put fail"); + goto nla_put_failure; + } + if (nla_put(skb, WLAN_HDD_TM_ATTR_DATA, sizeof(*lphb_ind), + lphb_ind)) { + hdd_err("WLAN_HDD_TM_ATTR_DATA put fail"); + goto nla_put_failure; + } + cfg80211_testmode_event(skb, GFP_ATOMIC); + return; + +nla_put_failure: + hdd_err("NLA Put fail"); + kfree_skb(skb); +} +#endif /* FEATURE_WLAN_LPHB */ + +/** + * __wlan_hdd_cfg80211_testmode() - test mode + * @wiphy: Pointer to wiphy + * @data: Data pointer + * @len: Data length + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, + void *data, int len) +{ + struct nlattr *tb[WLAN_HDD_TM_ATTR_MAX + 1]; + int err; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + hdd_enter(); + + err = wlan_hdd_validate_context(hdd_ctx); + if (err) + return err; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + err = wlan_cfg80211_nla_parse(tb, WLAN_HDD_TM_ATTR_MAX, data, + len, wlan_hdd_tm_policy); + if (err) { + hdd_err("Testmode INV ATTR"); + return err; + } + + if (!tb[WLAN_HDD_TM_ATTR_CMD]) { + hdd_err("Testmode INV CMD"); + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TESTMODE, + NO_SESSION, nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])); + + switch (nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])) { +#ifdef FEATURE_WLAN_LPHB + /* Low Power Heartbeat configuration request */ + case WLAN_HDD_TM_CMD_WLAN_HB: + { + int buf_len; + void *buf; + struct pmo_lphb_req *hb_params = NULL; + struct pmo_lphb_req *hb_params_temp = NULL; + QDF_STATUS status; + + if (!tb[WLAN_HDD_TM_ATTR_DATA]) { + hdd_err("Testmode INV DATA"); + return -EINVAL; + } + + buf = nla_data(tb[WLAN_HDD_TM_ATTR_DATA]); + buf_len = nla_len(tb[WLAN_HDD_TM_ATTR_DATA]); + if (buf_len < sizeof(*hb_params_temp)) { + hdd_err("Invalid buffer length for TM_ATTR_DATA"); + return -EINVAL; + } + + hb_params_temp = (struct pmo_lphb_req *) buf; + if ((hb_params_temp->cmd == pmo_lphb_set_tcp_pararm_indid) + && (hb_params_temp->params.lphb_tcp_params. + time_period_sec == 0)) + return -EINVAL; + + if (buf_len > sizeof(*hb_params)) { + hdd_err("buf_len=%d exceeded hb_params size limit", + buf_len); + return -ERANGE; + } + + hb_params = (struct pmo_lphb_req *)qdf_mem_malloc( + sizeof(*hb_params)); + if (!hb_params) + return -ENOMEM; + + qdf_mem_zero(hb_params, sizeof(*hb_params)); + qdf_mem_copy(hb_params, buf, buf_len); + status = ucfg_pmo_lphb_config_req( + hdd_ctx->psoc, + hb_params, (void *)hdd_ctx, + wlan_hdd_cfg80211_lphb_ind_handler); + if (status != QDF_STATUS_SUCCESS) + hdd_err("LPHB Config Fail, disable"); + + qdf_mem_free(hb_params); + return 0; + } +#endif /* FEATURE_WLAN_LPHB */ + +#if defined(QCA_WIFI_FTM) + case WLAN_HDD_TM_CMD_WLAN_FTM: + { + if (QDF_GLOBAL_FTM_MODE != hdd_get_conparam()) { + hdd_err("FTM Command not allowed in mission mode, mode %d", + hdd_get_conparam()); + return -EINVAL; + } + + err = wlan_cfg80211_ftm_testmode_cmd(hdd_ctx->pdev, + data, len); + break; + } +#endif + default: + hdd_err("command: %d not supported", + nla_get_u32(tb[WLAN_HDD_TM_ATTR_CMD])); + return -EOPNOTSUPP; + } + + hdd_exit(); + return err; +} + +/** + * wlan_hdd_cfg80211_testmode() - test mode + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device + * @data: Data pointer + * @len: Data length + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_cfg80211_testmode(struct wiphy *wiphy, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + struct wireless_dev *wdev, +#endif + void *data, int len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_testmode(wiphy, data, len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#endif /* CONFIG_NL80211_TESTMODE */ + +#ifdef QCA_HT_2040_COEX +/** + * __wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @chandef: Pointer to channel definition parameter + * + * Return: 0 for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + QDF_STATUS status; + int retval = 0; + enum nl80211_channel_type channel_type; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (!(adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) + return -EOPNOTSUPP; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + if (chandef->width < NL80211_CHAN_WIDTH_80) + channel_type = cfg80211_get_chandef_type(chandef); + else + channel_type = NL80211_CHAN_HT40PLUS; + hdd_debug("Channel width changed to %d ", channel_type); + + /* Change SAP ht2040 mode */ + status = hdd_set_sap_ht2040_mode(adapter, channel_type); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Cannot set SAP HT20/40 mode!"); + retval = -EINVAL; + } + + return retval; +} + +/** + * wlan_hdd_cfg80211_set_ap_channel_width() - set ap channel bandwidth + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @link_id: Link id for which channel width has to be applied + * @chandef: Pointer to channel definition parameter + * + * Return: 0 for success, non-zero for failure + */ +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +static int +wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + unsigned int link_id, + struct cfg80211_chan_def *chandef) +#else +static int +wlan_hdd_cfg80211_set_ap_channel_width(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_chan_def *chandef) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_ap_channel_width(wiphy, dev, chandef); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#ifdef CHANNEL_SWITCH_SUPPORTED +/** + * __wlan_hdd_cfg80211_channel_switch()- function to switch + * channel in SAP/GO + * @wiphy: wiphy pointer + * @dev: dev pointer. + * @csa_params: Change channel params + * + * This function is called to switch channel in SAP/GO + * + * Return: 0 if success else return non zero + */ +static int __wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *csa_params) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int ret; + enum phy_ch_width ch_width; + bool status; + struct hdd_hostapd_state *hostapd_state; + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + + if (0 != ret) + return ret; + + if ((QDF_P2P_GO_MODE != adapter->device_mode) && + (QDF_SAP_MODE != adapter->device_mode)) + return -ENOTSUPP; + + status = policy_mgr_is_sap_allowed_on_dfs_freq( + hdd_ctx->pdev, + adapter->deflink->vdev_id, + csa_params->chandef.chan->center_freq); + if (!status) + return -EINVAL; + + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->deflink->vdev_id, + CSA_REASON_USER_INITIATED); + + ch_width = hdd_map_nl_chan_width(csa_params->chandef.width); + hdd_debug("Freq %d width %d ch_width %d", + csa_params->chandef.chan->center_freq, + csa_params->chandef.width, ch_width); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + qdf_event_reset(&hostapd_state->qdf_event); + + ret = + hdd_softap_set_channel_change(dev, + csa_params->chandef.chan->center_freq, + ch_width, false); + if (ret) { + hdd_err("CSA failed to %d, ret %d", + csa_params->chandef.chan->center_freq, ret); + return ret; + } + + status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("wait for qdf_event failed!!"); + else + hdd_debug("csa done"); + + return ret; +} + +/** + * wlan_hdd_cfg80211_channel_switch()- function to switch + * channel in SAP/GO + * @wiphy: wiphy pointer + * @dev: dev pointer. + * @csa_params: Change channel params + * + * This function is called to switch channel in SAP/GO + * + * Return: 0 if success else return non zero + */ +static int wlan_hdd_cfg80211_channel_switch(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_csa_settings *csa_params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_channel_switch(wiphy, dev, csa_params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +int wlan_hdd_change_hw_mode_for_given_chnl(struct hdd_adapter *adapter, + uint32_t chan_freq, + enum policy_mgr_conn_update_reason reason) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + status = policy_mgr_reset_connection_update(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("clearing event failed"); + + status = policy_mgr_current_connections_update( + hdd_ctx->psoc, adapter->deflink->vdev_id, + chan_freq, reason, POLICY_MGR_DEF_REQ_ID); + switch (status) { + case QDF_STATUS_E_FAILURE: + /* + * QDF_STATUS_E_FAILURE indicates that some error has occurred + * while changing the hw mode + */ + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + + case QDF_STATUS_SUCCESS: + /* + * QDF_STATUS_SUCCESS indicates that HW mode change has been + * triggered and wait for it to finish. + */ + status = policy_mgr_wait_for_connection_update( + hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ERROR: qdf wait for event failed!!"); + return -EINVAL; + } + if (QDF_MONITOR_MODE == adapter->device_mode) + hdd_info("Monitor mode:channel freq:%d (SMM->DBS)", chan_freq); + break; + + default: + /* + * QDF_STATUS_E_NOSUPPORT indicates that no HW mode change is + * required, so caller can proceed further. + */ + break; + + } + hdd_exit(); + + return 0; +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * __wlan_hdd_cfg80211_set_mon_ch() - Set monitor mode capture channel + * @wiphy: Handle to struct wiphy to get handle to module context. + * @chandef: Contains information about the capture channel to be set. + * + * This interface is called if and only if monitor mode interface alone is + * active. + * + * Return: 0 success or error code on failure. + */ +static int __wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + struct hdd_mon_set_ch_info *ch_info; + QDF_STATUS status; + mac_handle_t mac_handle; + struct qdf_mac_addr bssid; + struct channel_change_req *req; + struct ch_params ch_params = {0}; + int ret; + enum channel_state chan_freq_state; + uint8_t max_fw_bw; + enum phy_ch_width ch_width; + qdf_freq_t sec_ch_2g_freq = 0; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (!adapter) + return -EIO; + + hdd_debug("%s: set monitor mode freq %d", + adapter->dev->name, chandef->chan->center_freq); + + /* Verify channel state before accepting this request */ + chan_freq_state = + wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, + chandef->chan->center_freq, + REG_CURRENT_PWR_MODE); + if (chan_freq_state == CHANNEL_STATE_DISABLE || + chan_freq_state == CHANNEL_STATE_INVALID) { + hdd_err("Invalid chan freq received for monitor mode aborting"); + return -EINVAL; + } + + /* Verify the BW before accepting this request */ + ch_width = hdd_map_nl_chan_width(chandef->width); + + if (ch_width > CH_WIDTH_10MHZ || + (!cds_is_sub_20_mhz_enabled() && ch_width > CH_WIDTH_160MHZ)) { + hdd_err("invalid BW received %d", ch_width); + return -EINVAL; + } + + max_fw_bw = sme_get_vht_ch_width(); + + if ((ch_width == CH_WIDTH_160MHZ && + max_fw_bw <= WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) || + (ch_width == CH_WIDTH_80P80MHZ && + max_fw_bw <= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ)) { + hdd_err("FW does not support this BW %d max BW supported %d", + ch_width, max_fw_bw); + return -EINVAL; + } + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + ch_info = &sta_ctx->ch_info; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chandef->chan->center_freq) && + chandef->width == NL80211_CHAN_WIDTH_40 && + chandef->center_freq1) { + if (chandef->center_freq1 > chandef->chan->center_freq) + sec_ch_2g_freq = chandef->chan->center_freq + 20; + else if (chandef->center_freq1 < chandef->chan->center_freq) + sec_ch_2g_freq = chandef->chan->center_freq - 20; + } + hdd_debug("set mon ch:width=%d, freq %d sec_ch_2g_freq=%d", + chandef->width, chandef->chan->center_freq, sec_ch_2g_freq); + qdf_mem_copy(bssid.bytes, adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = ch_width; + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + chandef->chan->center_freq, + sec_ch_2g_freq, &ch_params, + REG_CURRENT_PWR_MODE); + if (wlan_hdd_change_hw_mode_for_given_chnl(adapter, + chandef->chan->center_freq, + POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN)) { + hdd_err("Failed to change hw mode"); + return -EINVAL; + } + + if (adapter->monitor_mode_vdev_up_in_progress) { + hdd_err_rl("monitor mode vdev up in progress"); + return -EBUSY; + } + + status = qdf_event_reset(&adapter->qdf_monitor_mode_vdev_up_event); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("failed to reinit monitor mode vdev up event"); + return qdf_status_to_os_return(status); + } + adapter->monitor_mode_vdev_up_in_progress = true; + + qdf_mem_zero(&ch_params, sizeof(struct ch_params)); + + req = qdf_mem_malloc(sizeof(struct channel_change_req)); + if (!req) + return -ENOMEM; + + req->vdev_id = adapter->deflink->vdev_id; + req->target_chan_freq = chandef->chan->center_freq; + req->ch_width = ch_width; + + ch_params.ch_width = ch_width; + hdd_select_cbmode(adapter, chandef->chan->center_freq, sec_ch_2g_freq, + &ch_params); + + req->sec_ch_offset = ch_params.sec_ch_offset; + req->center_freq_seg0 = ch_params.center_freq_seg0; + req->center_freq_seg1 = ch_params.center_freq_seg1; + + sme_fill_channel_change_request(mac_handle, req, ch_info->phy_mode); + status = sme_send_channel_change_req(mac_handle, req); + qdf_mem_free(req); + + if (status) { + hdd_err_rl("Failed to set sme_RoamChannel for monitor mode status: %d", + status); + adapter->monitor_mode_vdev_up_in_progress = false; + ret = qdf_status_to_os_return(status); + return ret; + } + + /* block on a completion variable until vdev up success*/ + status = qdf_wait_for_event_completion( + &adapter->qdf_monitor_mode_vdev_up_event, + WLAN_MONITOR_MODE_VDEV_UP_EVT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("monitor vdev up event time out vdev id: %d", + adapter->deflink->vdev_id); + if (adapter->qdf_monitor_mode_vdev_up_event.force_set) + /* + * SSR/PDR has caused shutdown, which has + * forcefully set the event. + */ + hdd_err_rl("monitor mode vdev up event forcefully set"); + else if (status == QDF_STATUS_E_TIMEOUT) + hdd_err_rl("monitor mode vdev up timed out"); + else + hdd_err_rl("Failed monitor mode vdev up(status-%d)", + status); + + adapter->monitor_mode_vdev_up_in_progress = false; + return qdf_status_to_os_return(status); + } + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_mon_ch() - Set monitor mode capture channel + * @wiphy: Handle to struct wiphy to get handle to module context. + * @chandef: Contains information about the capture channel to be set. + * + * This interface is called if and only if monitor mode interface alone is + * active. + * + * Return: 0 success or error code on failure. + */ +static int wlan_hdd_cfg80211_set_mon_ch(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_mon_ch(wiphy, chandef); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} +#endif + +#define CNT_DIFF(cur, prev) \ + ((cur >= prev) ? (cur - prev) : (cur + (MAX_COUNT - (prev) + 1))) +#define MAX_COUNT 0xffffffff +static void hdd_update_chan_info(struct hdd_context *hdd_ctx, + struct scan_chan_info *chan, + struct scan_chan_info *info, uint32_t cmd_flag) +{ + if ((info->cmd_flag != WMI_CHAN_InFO_START_RESP) && + (info->cmd_flag != WMI_CHAN_InFO_END_RESP)) + hdd_err("cmd flag is invalid: %d", info->cmd_flag); + + mutex_lock(&hdd_ctx->chan_info_lock); + + if (info->cmd_flag == WMI_CHAN_InFO_START_RESP) + qdf_mem_zero(chan, sizeof(*chan)); + + chan->freq = info->freq; + chan->noise_floor = info->noise_floor; + chan->clock_freq = info->clock_freq; + chan->cmd_flag = info->cmd_flag; + chan->cycle_count = CNT_DIFF(info->cycle_count, chan->cycle_count); + + chan->rx_clear_count = + CNT_DIFF(info->rx_clear_count, chan->rx_clear_count); + + chan->tx_frame_count = + CNT_DIFF(info->tx_frame_count, chan->tx_frame_count); + + mutex_unlock(&hdd_ctx->chan_info_lock); + +} +#undef CNT_DIFF +#undef MAX_COUNT + +#ifndef UPDATE_ASSOC_IE +#define UPDATE_ASSOC_IE BIT(0) +#endif + +#ifndef UPDATE_FILS_ERP_INFO +#define UPDATE_FILS_ERP_INFO BIT(1) +#endif + +#ifndef UPDATE_FILS_AUTH_TYPE +#define UPDATE_FILS_AUTH_TYPE BIT(2) +#endif + +#if defined(WLAN_FEATURE_FILS_SK) &&\ + (defined(CFG80211_FILS_SK_OFFLOAD_SUPPORT) ||\ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0))) &&\ + (defined(CFG80211_UPDATE_CONNECT_PARAMS) ||\ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0))) +static inline int +hdd_update_connect_params_fils_info(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req, + uint32_t changed) +{ + uint8_t *buf; + QDF_STATUS status; + enum wlan_fils_auth_type auth_type; + struct wlan_fils_con_info *fils_info; + int ret = 0; + + fils_info = qdf_mem_malloc(sizeof(*fils_info)); + if (!fils_info) + return -EINVAL; + + fils_info->is_fils_connection = true; + if (changed & UPDATE_FILS_ERP_INFO) { + fils_info->username_len = req->fils_erp_username_len + + sizeof(char) + + req->fils_erp_realm_len; + if (fils_info->username_len > + WLAN_CM_FILS_MAX_KEYNAME_NAI_LENGTH) { + hdd_err("Key NAI Length %d", + fils_info->username_len); + ret = -EINVAL; + goto free_mem; + } + if (req->fils_erp_username_len && req->fils_erp_username) { + buf = fils_info->username; + qdf_mem_copy(buf, req->fils_erp_username, + req->fils_erp_username_len); + buf += req->fils_erp_username_len; + *buf++ = '@'; + qdf_mem_copy(buf, req->fils_erp_realm, + req->fils_erp_realm_len); + } + + fils_info->next_seq_num = req->fils_erp_next_seq_num + 1; + fils_info->rrk_len = req->fils_erp_rrk_len; + + if (fils_info->rrk_len > WLAN_CM_FILS_MAX_RRK_LENGTH) { + hdd_err("r_rk_length is invalid %d", + fils_info->rrk_len); + ret = -EINVAL; + goto free_mem; + } + + if (req->fils_erp_rrk_len && req->fils_erp_rrk) + qdf_mem_copy(fils_info->rrk, req->fils_erp_rrk, + fils_info->rrk_len); + + fils_info->realm_len = req->fils_erp_realm_len; + if (fils_info->realm_len > WLAN_CM_FILS_MAX_REALM_LEN) { + hdd_err("Invalid fils realm len %d", + fils_info->realm_len); + ret = -EINVAL; + goto free_mem; + } + if (req->fils_erp_realm_len && req->fils_erp_realm) + qdf_mem_copy(fils_info->realm, req->fils_erp_realm, + fils_info->realm_len); + } + + if (changed & UPDATE_FILS_AUTH_TYPE) { + auth_type = osif_cm_get_fils_auth_type(req->auth_type); + if (auth_type == FILS_PK_MAX) { + hdd_err("invalid auth type for fils %d", + req->auth_type); + ret = -EINVAL; + goto free_mem; + } + + fils_info->auth_type = auth_type; + } + + hdd_debug("fils conn update: changed %x is_fils %d keyname nai len %d", + changed, fils_info->is_fils_connection, + fils_info->username_len); + /* + * Update the FILS config from adapter->roam_profile to + * csr_session + */ + status = ucfg_cm_update_fils_config(hdd_ctx->psoc, + adapter->deflink->vdev_id, + fils_info); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Update FILS connect params failed %d", status); +free_mem: + qdf_mem_free(fils_info); + + return ret; +} +#else +static inline int +hdd_update_connect_params_fils_info(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req, + uint32_t changed) +{ + return -EINVAL; +} +#endif + +#if defined(CFG80211_UPDATE_CONNECT_PARAMS) ||\ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) + +/** + * __wlan_hdd_cfg80211_update_connect_params - update connect params + * @wiphy: Handle to struct wiphy to get handle to module context. + * @dev: Pointer to network device + * @req: Pointer to connect params + * @changed: Bitmap used to indicate the changed params + * + * Update the connect parameters while connected to a BSS. The updated + * parameters can be used by driver/firmware for subsequent BSS selection + * (roaming) decisions and to form the Authentication/(Re)Association + * Request frames. This call does not request an immediate disassociation + * or reassociation with the current BSS, i.e., this impacts only + * subsequent (re)associations. The bits in changed are defined in enum + * cfg80211_connect_params_changed + * + * Return: zero for success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_update_connect_params(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_connect_params *req, + uint32_t changed) +{ + int ret; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + QDF_STATUS status; + mac_handle_t mac_handle; + struct element_info assoc_ie; + + hdd_enter_dev(dev); + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + mac_handle = hdd_ctx->mac_handle; + + if (changed & UPDATE_ASSOC_IE) { + assoc_ie.len = req->ie_len; + assoc_ie.ptr = (uint8_t *)req->ie; + /* + * Update this assoc IE received from user space to + * umac. RSO command will pick up the assoc + * IEs to be sent to firmware from the umac. + */ + ucfg_cm_update_session_assoc_ie(hdd_ctx->psoc, + adapter->deflink->vdev_id, + &assoc_ie); + } + + if ((changed & UPDATE_FILS_ERP_INFO) || + (changed & UPDATE_FILS_AUTH_TYPE)) { + ret = hdd_update_connect_params_fils_info(adapter, hdd_ctx, + req, changed); + if (ret) + return -EINVAL; + + if (!hdd_ctx->is_fils_roaming_supported) { + hdd_debug("FILS roaming support %d", + hdd_ctx->is_fils_roaming_supported); + return 0; + } + } + + if (changed) { + status = sme_send_rso_connect_params(mac_handle, + adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Update connect params to fw failed %d", + status); + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_update_connect_params - SSR wrapper for + * __wlan_hdd_cfg80211_update_connect_params + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device + * @req: Pointer to connect params + * @changed: flags used to indicate the changed params + * + * Return: zero for success, non-zero for failure + */ +static int +wlan_hdd_cfg80211_update_connect_params(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_connect_params *req, + uint32_t changed) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_update_connect_params(wiphy, dev, + req, changed); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#if defined(WLAN_FEATURE_SAE) && \ + (defined(CFG80211_EXTERNAL_AUTH_SUPPORT) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) +#if (defined(CFG80211_EXTERNAL_AUTH_AP_SUPPORT) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * wlan_hdd_extauth_cache_pmkid() - Extract and cache pmkid + * @adapter: hdd vdev/net_device context + * @mac_handle: Handle to the MAC + * @params: Pointer to external auth params. + * + * Extract the PMKID and BSS from external auth params and add to the + * PMKSA Cache in CSR. + */ +static void +wlan_hdd_extauth_cache_pmkid(struct hdd_adapter *adapter, + mac_handle_t mac_handle, + struct cfg80211_external_auth_params *params) +{ + struct wlan_crypto_pmksa *pmk_cache; + QDF_STATUS result; + + if (params->pmkid) { + pmk_cache = qdf_mem_malloc(sizeof(*pmk_cache)); + if (!pmk_cache) + return; + + qdf_mem_copy(pmk_cache->bssid.bytes, params->bssid, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pmk_cache->pmkid, params->pmkid, + PMKID_LEN); + result = wlan_hdd_set_pmksa_cache(adapter, pmk_cache); + if (!QDF_IS_STATUS_SUCCESS(result)) + hdd_debug("external_auth: Failed to cache PMKID"); + + qdf_mem_free(pmk_cache); + } + +} + +/** + * wlan_hdd_extauth_copy_pmkid() - Copy the pmkid received from the + * external authentication command received from the userspace. + * @params: pointer to auth params + * @pmkid: Pointer to destination pmkid buffer to be filled + * + * The caller should ensure that destination pmkid buffer is not NULL. + * + * Return: None + */ +static void +wlan_hdd_extauth_copy_pmkid(struct cfg80211_external_auth_params *params, + uint8_t *pmkid) +{ + if (params->pmkid) + qdf_mem_copy(pmkid, params->pmkid, PMKID_LEN); +} + +#else +static void +wlan_hdd_extauth_cache_pmkid(struct hdd_adapter *adapter, + mac_handle_t mac_handle, + struct cfg80211_external_auth_params *params) +{} + +static void +wlan_hdd_extauth_copy_pmkid(struct cfg80211_external_auth_params *params, + uint8_t *pmkid) +{} +#endif +/** + * __wlan_hdd_cfg80211_external_auth() - Handle external auth + * + * @wiphy: Pointer to wireless phy + * @dev: net device + * @params: Pointer to external auth params. + * Return: 0 on success, negative errno on failure + * + * Userspace sends status of the external authentication(e.g., SAE) with a peer. + * The message carries BSSID of the peer and auth status (WLAN_STATUS_SUCCESS/ + * WLAN_STATUS_UNSPECIFIED_FAILURE) in params. + * Userspace may send PMKID in params, which can be used for + * further connections. + */ +static int +__wlan_hdd_cfg80211_external_auth(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_external_auth_params *params) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret; + mac_handle_t mac_handle; + struct qdf_mac_addr peer_mac_addr; + uint8_t pmkid[PMKID_LEN] = {0}; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_debug("external_auth status: %d peer mac: " QDF_MAC_ADDR_FMT, + params->status, QDF_MAC_ADDR_REF(params->bssid)); + mac_handle = hdd_ctx->mac_handle; + qdf_mem_copy(peer_mac_addr.bytes, params->bssid, QDF_MAC_ADDR_SIZE); + + wlan_hdd_extauth_cache_pmkid(adapter, mac_handle, params); + + wlan_hdd_extauth_copy_pmkid(params, pmkid); + sme_handle_sae_msg(mac_handle, adapter->deflink->vdev_id, + params->status, peer_mac_addr, pmkid); + + return ret; +} + +/** + * wlan_hdd_cfg80211_external_auth() - Handle external auth + * @wiphy: Pointer to wireless phy + * @dev: net device + * @params: Pointer to external auth params + * + * Return: 0 on success, negative errno on failure + */ +static int +wlan_hdd_cfg80211_external_auth(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_external_auth_params *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_external_auth(wiphy, dev, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#if defined(WLAN_FEATURE_NAN) && \ + (KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE) +static int +wlan_hdd_cfg80211_start_nan(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_nan_conf *conf) +{ + return -EOPNOTSUPP; +} + +static void +wlan_hdd_cfg80211_stop_nan(struct wiphy *wiphy, struct wireless_dev *wdev) +{ +} + +static int wlan_hdd_cfg80211_add_nan_func(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_nan_func *nan_func) +{ + return -EOPNOTSUPP; +} + +static void wlan_hdd_cfg80211_del_nan_func(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ +} + +static int wlan_hdd_cfg80211_nan_change_conf(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_nan_conf *conf, + u32 changes) +{ + return -EOPNOTSUPP; +} +#endif + +/** + * wlan_hdd_get_ch_width_from_chan_info - get ch_width as per num channel + * present in scan event + * @info: struct scan_chan_info + * + * Return: phy_ch_width. + */ +static enum phy_ch_width +wlan_hdd_get_ch_width_from_chan_info(struct scan_chan_info *info) +{ + enum phy_ch_width scanned_ch_width; + + switch (info->subband_info.num_chan) { + case 1: + scanned_ch_width = CH_WIDTH_20MHZ; + break; + case 2: + scanned_ch_width = CH_WIDTH_40MHZ; + break; + case 4: + scanned_ch_width = CH_WIDTH_80MHZ; + break; + case 8: + scanned_ch_width = CH_WIDTH_160MHZ; + break; + default: + scanned_ch_width = CH_WIDTH_INVALID; + break; + } + + return scanned_ch_width; +} + +/** + * wlan_hdd_fill_subband_scan_info - Fill subband channel info + * @hdd_ctx: hdd context + * @info: struct scan_chan_info + * @chan: scan channel info + * + * update channel info into HDD context on scan done + * + * Return: None. + */ +static void wlan_hdd_fill_subband_scan_info(struct hdd_context *hdd_ctx, + struct scan_chan_info *info, + struct scan_chan_info *chan) +{ + uint8_t idx, info_index, freq_info_num; + enum phy_ch_width scanned_ch_width; + const struct bonded_channel_freq *range = NULL; + qdf_freq_t start_freq, end_freq, sec_2g_freq; + uint8_t vdev_id = info->subband_info.vdev_id; + struct assoc_channel_info assoc_chan_info; + + scanned_ch_width = wlan_hdd_get_ch_width_from_chan_info(info); + if (scanned_ch_width == CH_WIDTH_INVALID) { + hdd_debug("vdev %d: Invalid scanned_ch_width", vdev_id); + return; + } + + if (scanned_ch_width == CH_WIDTH_20MHZ) { + start_freq = info->freq; + end_freq = info->freq; + } else if (wlan_reg_is_24ghz_ch_freq(info->freq) && + scanned_ch_width == CH_WIDTH_40MHZ) { + ucfg_cm_get_associated_ch_info(hdd_ctx->psoc, vdev_id, + scanned_ch_width, + &assoc_chan_info); + sec_2g_freq = assoc_chan_info.sec_2g_freq; + if (!sec_2g_freq) { + mlme_debug("vdev %d : Invalid sec 2g freq for freq:%d", + info->subband_info.vdev_id, info->freq); + return; + } + + hdd_debug("vdev %d :assoc freq %d sec_2g_freq:%d, bw %d", + info->subband_info.vdev_id, info->freq, + sec_2g_freq, scanned_ch_width); + if (info->freq > sec_2g_freq) { + start_freq = sec_2g_freq; + end_freq = info->freq; + } else { + start_freq = info->freq; + end_freq = sec_2g_freq; + } + } else { + range = wlan_reg_get_bonded_chan_entry(info->freq, + scanned_ch_width, 0); + if (!range) { + hdd_err("vdev %d: bonded_chan_array is NULL for freq %d, ch_width %d", + vdev_id, info->freq, scanned_ch_width); + return; + } + start_freq = range->start_freq; + end_freq = range->end_freq; + } + + freq_info_num = info->subband_info.num_chan; + info_index = 0; + + hdd_debug("vdev %d: freq :%d bw %d, range [%d-%d], num_freq:%d", + vdev_id, info->freq, scanned_ch_width, start_freq, + end_freq, freq_info_num); + + for (idx = 0; idx < NUM_CHANNELS; idx++) { + if (chan[idx].freq == 0) + continue; + + if (start_freq > end_freq || info_index >= freq_info_num || + info_index >= MAX_WIDE_BAND_SCAN_CHAN) + break; + + if (chan[idx].freq == start_freq) { + /*update channel info as per cca busy info */ + info->freq = start_freq; + info->rx_clear_count = + info->subband_info.cca_busy_subband_info[info_index]; + + hdd_update_chan_info(hdd_ctx, &chan[idx], info, + info->cmd_flag); + + hdd_debug("updated info for freq:%u rcc:%d at index:%d", + chan[idx].freq, chan[idx].rx_clear_count, + idx); + start_freq += BW_20_MHZ; + info_index++; + } + } +} + +/** + * wlan_hdd_chan_info_cb() - channel info callback + * @info: struct scan_chan_info + * + * Store channel info into HDD context + * + * Return: None. + */ +static void wlan_hdd_chan_info_cb(struct scan_chan_info *info) +{ + struct hdd_context *hdd_ctx; + struct scan_chan_info *chan; + uint8_t idx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx) != 0) + return; + + if (!hdd_ctx->chan_info) { + hdd_err("chan_info is NULL"); + return; + } + + chan = hdd_ctx->chan_info; + + if (info->subband_info.is_wide_band_scan) { + wlan_hdd_fill_subband_scan_info(hdd_ctx, info, chan); + return; + } + + for (idx = 0; idx < NUM_CHANNELS; idx++) { + if (chan[idx].freq == info->freq) { + hdd_update_chan_info(hdd_ctx, &chan[idx], info, + info->cmd_flag); + hdd_debug("cmd:%d freq:%u nf:%d cc:%u rcc:%u clk:%u cmd:%d tfc:%d index:%d", + chan[idx].cmd_flag, chan[idx].freq, + chan[idx].noise_floor, + chan[idx].cycle_count, + chan[idx].rx_clear_count, + chan[idx].clock_freq, chan[idx].cmd_flag, + chan[idx].tx_frame_count, idx); + if (chan[idx].freq == 0) + break; + + } + } +} + +/** + * wlan_hdd_init_chan_info() - init chan info in hdd context + * @hdd_ctx: HDD context pointer + * + * Return: none + */ +void wlan_hdd_init_chan_info(struct hdd_context *hdd_ctx) +{ + uint32_t num_2g, num_5g, index = 0; + mac_handle_t mac_handle; + + hdd_ctx->chan_info = NULL; + if (!ucfg_scan_is_snr_monitor_enabled(hdd_ctx->psoc)) { + hdd_debug("SNR monitoring is disabled"); + return; + } + + hdd_ctx->chan_info = + qdf_mem_malloc(sizeof(struct scan_chan_info) + * NUM_CHANNELS); + if (!hdd_ctx->chan_info) + return; + mutex_init(&hdd_ctx->chan_info_lock); + + num_2g = QDF_ARRAY_SIZE(hdd_channels_2_4_ghz); + for (; index < num_2g; index++) { + hdd_ctx->chan_info[index].freq = + hdd_channels_2_4_ghz[index].center_freq; + } + + num_5g = QDF_ARRAY_SIZE(hdd_channels_5_ghz); + for (; (index - num_2g) < num_5g; index++) + hdd_ctx->chan_info[index].freq = + hdd_channels_5_ghz[index - num_2g].center_freq; + + index = num_2g + num_5g; + index += wlan_hdd_populate_5dot9_chan_info(hdd_ctx, index); + index += wlan_hdd_populate_6g_chan_info(hdd_ctx, index); + hdd_debug("Number of channels populated : %d", index); + + mac_handle = hdd_ctx->mac_handle; + sme_set_chan_info_callback(mac_handle, &wlan_hdd_chan_info_cb); +} + +/** + * wlan_hdd_deinit_chan_info() - deinit chan info in hdd context + * @hdd_ctx: hdd context pointer + * + * Return: none + */ +void wlan_hdd_deinit_chan_info(struct hdd_context *hdd_ctx) +{ + struct scan_chan_info *chan; + + chan = hdd_ctx->chan_info; + hdd_ctx->chan_info = NULL; + if (chan) + qdf_mem_free(chan); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) || defined(CFG80211_11BE_BASIC) +#define SET_RATE_INFO_BW_320 RATE_INFO_BW_320 +#else +#define SET_RATE_INFO_BW_320 RATE_INFO_BW_160 +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) || defined(WITH_BACKPORTS) +static enum rate_info_bw hdd_map_hdd_bw_to_os(enum hdd_rate_info_bw hdd_bw) +{ + switch (hdd_bw) { + case HDD_RATE_BW_5: + return RATE_INFO_BW_5; + case HDD_RATE_BW_10: + return RATE_INFO_BW_10; + case HDD_RATE_BW_20: + return RATE_INFO_BW_20; + case HDD_RATE_BW_40: + return RATE_INFO_BW_40; + case HDD_RATE_BW_80: + return RATE_INFO_BW_80; + case HDD_RATE_BW_160: + return RATE_INFO_BW_160; + case HDD_RATE_BW_320: + return SET_RATE_INFO_BW_320; + } + + hdd_err("Unhandled HDD_RATE_BW: %d", hdd_bw); + + return RATE_INFO_BW_20; +} + +void hdd_set_rate_bw(struct rate_info *info, enum hdd_rate_info_bw hdd_bw) +{ + info->bw = hdd_map_hdd_bw_to_os(hdd_bw); +} +#else +static enum rate_info_flags hdd_map_hdd_bw_to_os(enum hdd_rate_info_bw hdd_bw) +{ + switch (hdd_bw) { + case HDD_RATE_BW_5: + case HDD_RATE_BW_10: + case HDD_RATE_BW_20: + return (enum rate_info_flags)0; + case HDD_RATE_BW_40: + return RATE_INFO_FLAGS_40_MHZ_WIDTH; + case HDD_RATE_BW_80: + return RATE_INFO_FLAGS_80_MHZ_WIDTH; + case HDD_RATE_BW_160: + return RATE_INFO_FLAGS_160_MHZ_WIDTH; + } + + hdd_err("Unhandled HDD_RATE_BW: %d", hdd_bw); + + return (enum rate_info_flags)0; +} + +void hdd_set_rate_bw(struct rate_info *info, enum hdd_rate_info_bw hdd_bw) +{ + const enum rate_info_flags all_bws = + RATE_INFO_FLAGS_40_MHZ_WIDTH | + RATE_INFO_FLAGS_80_MHZ_WIDTH | + RATE_INFO_FLAGS_80P80_MHZ_WIDTH | + RATE_INFO_FLAGS_160_MHZ_WIDTH; + + info->flags &= ~all_bws; + info->flags |= hdd_map_hdd_bw_to_os(hdd_bw); +} +#endif + +#if defined(CFG80211_EXTERNAL_DH_UPDATE_SUPPORT) || \ +(LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0)) + +#ifdef WLAN_MLD_AP_OWE_INFO_SUPPORT +static void +hdd_ml_sap_owe_fill_ml_info(struct hdd_adapter *adapter, + struct cfg80211_update_owe_info *owe_info, + uint8_t *peer_mac) +{ + bool is_mlo_vdev; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_vdev *vdev; + uint8_t *peer_mld_addr; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) + owe_info->link_id = wlan_vdev_get_link_id(vdev); + else + owe_info->link_id = -1; + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (!is_mlo_vdev) + return; + + peer = wlan_objmgr_get_peer_by_mac(adapter->hdd_ctx->psoc, + peer_mac, WLAN_OSIF_ID); + if (!peer) { + hdd_err("Peer not found with MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return; + } + + peer_mld_addr = wlan_peer_mlme_get_mldaddr(peer); + qdf_mem_copy(&owe_info->peer_mld_addr[0], peer_mld_addr, ETH_ALEN); + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); +} +#elif defined(CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT) +static void +hdd_ml_sap_owe_fill_ml_info(struct hdd_adapter *adapter, + struct cfg80211_update_owe_info *owe_info, + uint8_t *peer_mac) +{ + bool is_mlo_vdev; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_vdev *vdev; + uint8_t *peer_mld_addr; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_HDD_ID_OBJ_MGR); + if (!vdev) + return; + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (!is_mlo_vdev) { + owe_info->assoc_link_id = -1; + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + return; + } + + owe_info->assoc_link_id = wlan_vdev_get_link_id(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + peer = wlan_objmgr_get_peer_by_mac(adapter->hdd_ctx->psoc, + peer_mac, WLAN_HDD_ID_OBJ_MGR); + if (!peer) { + hdd_err("Peer not found with MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return; + } + + peer_mld_addr = wlan_peer_mlme_get_mldaddr(peer); + qdf_mem_copy(&owe_info->peer_mld_addr[0], peer_mld_addr, ETH_ALEN); + wlan_objmgr_peer_release_ref(peer, WLAN_HDD_ID_OBJ_MGR); +} +#else +static void +hdd_ml_sap_owe_fill_ml_info(struct hdd_adapter *adapter, + struct cfg80211_update_owe_info *owe_info, + uint8_t *peer_mac) +{ +} +#endif + +void hdd_send_update_owe_info_event(struct hdd_adapter *adapter, + uint8_t sta_addr[], + uint8_t *owe_ie, + uint32_t owe_ie_len) +{ + struct cfg80211_update_owe_info owe_info; + struct net_device *dev = adapter->dev; + + hdd_enter_dev(dev); + + qdf_mem_zero(&owe_info, sizeof(owe_info)); + qdf_mem_copy(owe_info.peer, sta_addr, ETH_ALEN); + hdd_ml_sap_owe_fill_ml_info(adapter, &owe_info, sta_addr); + owe_info.ie = owe_ie; + owe_info.ie_len = owe_ie_len; + + cfg80211_update_owe_info_event(dev, &owe_info, GFP_KERNEL); + + hdd_exit(); +} +#endif + +#define MAX_PDEV_TXRX_PARAMS 2 +/* params being sent: + * 1.wmi_pdev_param_tx_chain_mask + * 2.wmi_pdev_param_rx_chain_mask + */ +static int __wlan_hdd_cfg80211_set_chainmask(struct wiphy *wiphy, + uint32_t tx_mask, + uint32_t rx_mask) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + enum hdd_chain_mode chains; + struct dev_set_param setparam[MAX_PDEV_TXRX_PARAMS] = {}; + uint8_t index = 0; + uint8_t ll_lt_sap_vdev_id; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (hdd_ctx->num_rf_chains != HDD_ANTENNA_MODE_2X2 || + !ucfg_mlme_is_chain_mask_supported(hdd_ctx->psoc)) { + hdd_info_rl("Chainmask can't be configured, num of rf chain %d", + hdd_ctx->num_rf_chains); + return -ENOTSUPP; + } + chains = HDD_CHAIN_MODE_2X2; + if (!tx_mask || tx_mask > chains || !rx_mask || rx_mask > chains) { + hdd_err_rl("Invalid masks. txMask: %d rxMask: %d num_rf_chains: %d", + tx_mask, rx_mask, hdd_ctx->num_rf_chains); + + return -EINVAL; + } + + ll_lt_sap_vdev_id = + wlan_policy_mgr_get_ll_lt_sap_vdev_id(hdd_ctx->psoc); + if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) { + hdd_info_rl("LL_LT_SAP vdev %d present, chainmask config not allowed", + ll_lt_sap_vdev_id); + return -ENOTSUPP; + } + + if (sme_validate_txrx_chain_mask(wmi_pdev_param_tx_chain_mask, tx_mask)) + return -EINVAL; + + ret = mlme_check_index_setparam( + setparam, wmi_pdev_param_tx_chain_mask, + tx_mask, index++, MAX_PDEV_TXRX_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_tx_chain_mask"); + return -EINVAL; + } + + if (sme_validate_txrx_chain_mask(wmi_pdev_param_rx_chain_mask, rx_mask)) + return -EINVAL; + + ret = mlme_check_index_setparam( + setparam, wmi_pdev_param_rx_chain_mask, + rx_mask, index++, MAX_PDEV_TXRX_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_rx_chain_mask"); + return -EINVAL; + } + + ret = wma_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("failed to send TX, RX chain mask params"); + + return ret; +} + +static int wlan_hdd_cfg80211_set_chainmask(struct wiphy *wiphy, + uint32_t tx_mask, + uint32_t rx_mask) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_chainmask(wiphy, tx_mask, rx_mask); + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +static int __wlan_hdd_cfg80211_get_chainmask(struct wiphy *wiphy, + uint32_t *tx_mask, + uint32_t *rx_mask) + +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + *tx_mask = wma_cli_get_command(0, wmi_pdev_param_tx_chain_mask, + PDEV_CMD); + *rx_mask = wma_cli_get_command(0, wmi_pdev_param_rx_chain_mask, + PDEV_CMD); + + /* if 0 return max value as 0 mean no set cmnd received yet */ + if (!*tx_mask) + *tx_mask = hdd_ctx->num_rf_chains == HDD_ANTENNA_MODE_2X2 ? + HDD_CHAIN_MODE_2X2 : HDD_CHAIN_MODE_1X1; + if (!*rx_mask) + *rx_mask = hdd_ctx->num_rf_chains == HDD_ANTENNA_MODE_2X2 ? + HDD_CHAIN_MODE_2X2 : HDD_CHAIN_MODE_1X1; + hdd_debug("tx_mask: %d rx_mask: %d", *tx_mask, *rx_mask); + + return 0; +} + +static int wlan_hdd_cfg80211_get_chainmask(struct wiphy *wiphy, + uint32_t *tx_mask, + uint32_t *rx_mask) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_chainmask(wiphy, tx_mask, rx_mask); + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +enum qca_wlan_802_11_mode +hdd_convert_cfgdot11mode_to_80211mode(enum csr_cfgdot11mode mode) +{ + switch (mode) { + case eCSR_CFG_DOT11_MODE_11A: + return QCA_WLAN_802_11_MODE_11A; + case eCSR_CFG_DOT11_MODE_11B: + return QCA_WLAN_802_11_MODE_11B; + case eCSR_CFG_DOT11_MODE_11G: + return QCA_WLAN_802_11_MODE_11G; + case eCSR_CFG_DOT11_MODE_11N: + return QCA_WLAN_802_11_MODE_11N; + case eCSR_CFG_DOT11_MODE_11AC: + return QCA_WLAN_802_11_MODE_11AC; + case eCSR_CFG_DOT11_MODE_11G_ONLY: + return QCA_WLAN_802_11_MODE_11G; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + return QCA_WLAN_802_11_MODE_11N; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + return QCA_WLAN_802_11_MODE_11AC; + case eCSR_CFG_DOT11_MODE_11AX: + return QCA_WLAN_802_11_MODE_11AX; + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + return QCA_WLAN_802_11_MODE_11AX; + case eCSR_CFG_DOT11_MODE_11BE: + case eCSR_CFG_DOT11_MODE_11BE_ONLY: + return QCA_WLAN_802_11_MODE_11BE; + case eCSR_CFG_DOT11_MODE_ABG: + case eCSR_CFG_DOT11_MODE_AUTO: + default: + return QCA_WLAN_802_11_MODE_INVALID; + } +} + +enum qca_wlan_802_11_mode +hdd_convert_phymode_to_80211mode(eCsrPhyMode mode) +{ + switch (mode) { + case eCSR_DOT11_MODE_11a: + return QCA_WLAN_802_11_MODE_11A; + case eCSR_DOT11_MODE_11b: + return QCA_WLAN_802_11_MODE_11B; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + return QCA_WLAN_802_11_MODE_11G; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + return QCA_WLAN_802_11_MODE_11N; + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + return QCA_WLAN_802_11_MODE_11AC; + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + return QCA_WLAN_802_11_MODE_11AX; + case eCSR_DOT11_MODE_11be: + case eCSR_DOT11_MODE_11be_ONLY: + return QCA_WLAN_802_11_MODE_11BE; + case eCSR_DOT11_MODE_abg: + case eCSR_DOT11_MODE_AUTO: + default: + return QCA_WLAN_802_11_MODE_INVALID; + } +} + +bool hdd_is_legacy_connection(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + int connection_mode = QCA_WLAN_802_11_MODE_INVALID; + enum csr_cfgdot11mode cfgmode; + uint16_t tdls_connected_peer; + + tdls_connected_peer = hdd_get_tdls_connected_peer_count(link_info); + if (tdls_connected_peer) + return false; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + cfgmode = sta_ctx->conn_info.dot11mode; + connection_mode = hdd_convert_cfgdot11mode_to_80211mode(cfgmode); + if (connection_mode == QCA_WLAN_802_11_MODE_11A || + connection_mode == QCA_WLAN_802_11_MODE_11B || + connection_mode == QCA_WLAN_802_11_MODE_11G) + return true; + else + return false; +} + +static void +wlan_hdd_update_chandef(struct cfg80211_chan_def *chandef, + enum phy_ch_width ch_width, uint32_t ch_cfreq2, + bool is_legacy_phymode) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + if (is_legacy_phymode) + chandef->width = NL80211_CHAN_WIDTH_20_NOHT; + else + chandef->width = NL80211_CHAN_WIDTH_20; + break; + case CH_WIDTH_40MHZ: + chandef->width = NL80211_CHAN_WIDTH_40; + break; + case CH_WIDTH_80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80; + break; + case CH_WIDTH_160MHZ: + chandef->width = NL80211_CHAN_WIDTH_160; + /* Set center_freq1 to center frequency of complete 160MHz */ + chandef->center_freq1 = ch_cfreq2; + break; + case CH_WIDTH_80P80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80P80; + chandef->center_freq2 = ch_cfreq2; + break; + case CH_WIDTH_5MHZ: + chandef->width = NL80211_CHAN_WIDTH_5; + break; + case CH_WIDTH_10MHZ: + chandef->width = NL80211_CHAN_WIDTH_10; + break; + default: + chandef->width = NL80211_CHAN_WIDTH_20; + break; + } +} + +static int +wlan_hdd_cfg80211_get_channel_sap(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + struct hdd_adapter *adapter, int link_id) +{ + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + bool is_legacy_phymode = false; + uint32_t chan_freq; + struct wlan_channel *des_chan; + + if (!test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags)) + return -EINVAL; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + switch (ap_ctx->sap_config.SapHw_mode) { + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + is_legacy_phymode = false; + break; + default: + is_legacy_phymode = true; + break; + } + + vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_ID, link_id); + if (!vdev) + return -EINVAL; + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + chan_freq = des_chan->ch_freq; + chandef->center_freq1 = des_chan->ch_cfreq1; + chandef->center_freq2 = 0; + chandef->chan = ieee80211_get_channel(wiphy, chan_freq); + + wlan_hdd_update_chandef(chandef, des_chan->ch_width, + des_chan->ch_cfreq2, is_legacy_phymode); + + wlan_hdd_set_chandef_for_11be(chandef, des_chan); + + wlan_key_put_link_vdev(vdev, WLAN_OSIF_ID); + + hdd_debug("vdev: %d, freq:%d, ch_width:%d, c_freq1:%d, c_freq2:%d", + wlan_vdev_get_id(vdev), chan_freq, chandef->width, + chandef->center_freq1, chandef->center_freq2); + return 0; +} + +static qdf_freq_t hdd_get_sec_2ghz_freq(qdf_freq_t freq, + enum phy_ch_width ch_width, + qdf_freq_t freq_seg_1) +{ + /* + * In case of 2.4 GHz + 40 MHz, use the secondary channel + * to determine the exact ccfs1 + */ + if (wlan_reg_is_24ghz_ch_freq(freq) && ch_width == CH_WIDTH_40MHZ) { + if (freq < freq_seg_1) + return freq + HT40_SEC_OFFSET; + else + return freq - HT40_SEC_OFFSET; + } + + return 0; +} + +static int wlan_hdd_cfg80211_get_vdev_chan_info(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev, + int link_id, + struct wlan_channel *chan_info) +{ + struct hdd_station_ctx *sta_ctx = NULL; + struct ch_params ch_params = {0}; + struct wlan_hdd_link_info *link_info; + enum wlan_phymode peer_phymode; + uint8_t vdev_id; + struct wlan_channel *des_chan; + qdf_freq_t sec_2g_freq = 0; + + vdev_id = wlan_vdev_get_id(vdev); + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_debug("link_info is null"); + return -EBUSY; + } + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + chan_info->ch_freq = des_chan->ch_freq; + chan_info->ch_cfreq1 = des_chan->ch_cfreq1; + chan_info->ch_cfreq2 = des_chan->ch_cfreq2; + chan_info->ch_width = des_chan->ch_width; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + /* For STA/P2P CLI get the peer pymode as, in some IOT + * cases VDEV BW will not be same as peer BW + */ + mlme_get_peer_phymode(hdd_ctx->psoc, sta_ctx->conn_info.bssid.bytes, + &peer_phymode); + chan_info->ch_width = + wlan_mlme_get_ch_width_from_phymode(peer_phymode); + ch_params.ch_width = chan_info->ch_width; + + sec_2g_freq = hdd_get_sec_2ghz_freq(chan_info->ch_freq, + chan_info->ch_width, + chan_info->ch_cfreq1); + + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + chan_info->ch_freq, sec_2g_freq, + &ch_params, + REG_CURRENT_PWR_MODE); + + if (chan_info->ch_cfreq1 != ch_params.mhz_freq_seg0 || + chan_info->ch_cfreq2 != ch_params.mhz_freq_seg1) + hdd_debug("Old ccfs1 %d ccfs2 %d - New ccfs1 %d ccfs2 %d", + chan_info->ch_cfreq1, chan_info->ch_cfreq2, + ch_params.mhz_freq_seg0, ch_params.mhz_freq_seg1); + + chan_info->ch_cfreq1 = ch_params.mhz_freq_seg0; + chan_info->ch_cfreq2 = ch_params.mhz_freq_seg1; + + hdd_debug("vdev: %d, freq: %d, freq1: %d, freq2: %d, ch_width: %d, max_ch_width:%d", + vdev_id, chan_info->ch_freq, chan_info->ch_cfreq1, + chan_info->ch_cfreq2, chan_info->ch_width, + ch_params.ch_width); + + return 0; +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static int +wlan_hdd_get_standby_link_chan_info(struct hdd_adapter *adapter, int link_id, + struct wlan_channel *chan_info) +{ + struct wlan_objmgr_vdev *vdev; + int ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_debug("not a mlo vdev"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return -EINVAL; + } + + ret = mlo_mgr_get_per_link_chan_info(vdev, link_id, chan_info); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return ret; +} +#else +static inline int +wlan_hdd_get_standby_link_chan_info(struct hdd_adapter *adapter, int link_id, + struct wlan_channel *chan_info) +{ + return -EINVAL; +} +#endif + +static int +wlan_hdd_cfg80211_get_channel_sta(struct wiphy *wiphy, + struct cfg80211_chan_def *chandef, + struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, int link_id) +{ + struct hdd_station_ctx *sta_ctx = NULL; + struct wlan_objmgr_vdev *link_vdev; + bool is_legacy_phymode = false; + struct wlan_channel chan_info; + int ret = 0; + struct ch_params ch_params = {0}; + qdf_freq_t sec_2g_freq = 0; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_debug("vdev not associated"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (sta_ctx->conn_info.dot11mode < eCSR_CFG_DOT11_MODE_11N) + is_legacy_phymode = true; + + link_vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_ID, link_id); + if (!link_vdev) { + /* request is for standby link */ + ret = wlan_hdd_get_standby_link_chan_info(adapter, link_id, + &chan_info); + if (ret) + return ret; + + ch_params.ch_width = chan_info.ch_width; + ch_params.center_freq_seg1 = chan_info.ch_cfreq2; + sec_2g_freq = hdd_get_sec_2ghz_freq(chan_info.ch_freq, + chan_info.ch_width, + chan_info.ch_cfreq1); + + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + chan_info.ch_freq, + sec_2g_freq, + &ch_params, + REG_CURRENT_PWR_MODE); + chan_info.ch_cfreq1 = ch_params.mhz_freq_seg0; + chan_info.ch_cfreq2 = ch_params.mhz_freq_seg1; + hdd_debug("max allowed ch_width:%d, ap ch_width: %d", + ch_params.ch_width, chan_info.ch_width); + /* + * To take care scenarios when AP channel width and max + * supported ch_width for connection in STA may different. + * For example, a case where AP advertise beacon/probe response + * in 320 MHz and STA (configured with country code = KR) + * supports max ch_width 160 MHz. + */ + if (ch_params.ch_width < chan_info.ch_width) + chan_info.ch_width = ch_params.ch_width; + } else { + ret = wlan_hdd_cfg80211_get_vdev_chan_info(hdd_ctx, link_vdev, + link_id, &chan_info); + wlan_key_put_link_vdev(link_vdev, WLAN_OSIF_ID); + if (ret) + return ret; + } + + chandef->chan = ieee80211_get_channel(wiphy, chan_info.ch_freq); + chandef->center_freq1 = chan_info.ch_cfreq1; + chandef->center_freq2 = 0; + + wlan_hdd_update_chandef(chandef, chan_info.ch_width, + chan_info.ch_cfreq2, is_legacy_phymode); + + wlan_hdd_set_chandef_for_11be(chandef, &chan_info); + + hdd_debug("freq:%d, ch_width:%d, c_freq1:%d, c_freq2:%d", + chan_info.ch_freq, chandef->width, chandef->center_freq1, + chandef->center_freq2); + + return ret; +} + +static int __wlan_hdd_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef, + int link_id) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int ret = 0; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + hdd_debug("get channel for link id: %d, device mode: %d", link_id, + adapter->device_mode); + + switch (adapter->device_mode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + ret = wlan_hdd_cfg80211_get_channel_sap(wiphy, chandef, + adapter, link_id); + break; + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + ret = wlan_hdd_cfg80211_get_channel_sta(wiphy, chandef, hdd_ctx, + adapter, link_id); + break; + default: + return -EINVAL; + } + + return ret; +} + +/** + * wlan_hdd_cfg80211_get_channel() - API to process cfg80211 get_channel request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device + * @link_id: Channel link ID + * @chandef: Pointer to channel definition + * + * Return: 0 for success, non zero for failure + */ +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +static int wlan_hdd_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + unsigned int link_id, + struct cfg80211_chan_def *chandef) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_channel(wiphy, wdev, chandef, link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +static int wlan_hdd_cfg80211_get_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct cfg80211_chan_def *chandef) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + /* Legacy purposes */ + int link_id = -1; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_channel(wiphy, wdev, chandef, link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +static int +hdd_check_he_bitmask_for_single_rate(enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int he_rates = 0, i; + + for (i = 0; i < QDF_ARRAY_SIZE(mask->control[band].he_mcs); i++) + he_rates += qdf_get_hweight16(mask->control[band].he_mcs[i]); + + return he_rates; +} + +static void +hdd_get_he_bitrate_params_for_band(enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + uint8_t *nss, uint8_t *rate_index, + int *bit_rate) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (qdf_get_hweight16(mask->control[band].he_mcs[i]) == 1) { + *nss = i; + *rate_index = (ffs(mask->control[band].he_mcs[i]) - 1); + *bit_rate = hdd_assemble_rate_code(WMI_RATE_PREAMBLE_HE, + *nss, *rate_index); + break; + } + } +} +#else +static inline int +hdd_check_he_bitmask_for_single_rate(enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + return 0; +} + +static inline void +hdd_get_he_bitrate_params_for_band(enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + uint8_t *nss, uint8_t *rate_index, + int *bit_rate) + +{ +} +#endif + +static bool hdd_check_bitmask_for_single_rate(enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int num_rates = 0, i; + + num_rates += qdf_get_hweight32(mask->control[band].legacy); + + for (i = 0; i < QDF_ARRAY_SIZE(mask->control[band].ht_mcs); i++) + num_rates += qdf_get_hweight8(mask->control[band].ht_mcs[i]); + + for (i = 0; i < QDF_ARRAY_SIZE(mask->control[band].vht_mcs); i++) + num_rates += qdf_get_hweight16(mask->control[band].vht_mcs[i]); + + num_rates += hdd_check_he_bitmask_for_single_rate(band, mask); + + return num_rates ? true : false; +} + +static int __wlan_hdd_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +{ + enum nl80211_band band; + int errno; + struct hdd_adapter *adapter = netdev_priv(dev); + uint8_t nss, i; + int bit_rate = -1; + uint8_t rate_index; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + uint8_t vdev_id; + u8 gi_val = 0; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 0)) + uint8_t auto_rate_he_gi = 0; +#endif + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() || + QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in mode"); + return -EINVAL; + } + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + vdev_id = adapter->deflink->vdev_id; + + for (band = NL80211_BAND_2GHZ; band <= NL80211_BAND_5GHZ; band++) { + /* Support configuring only one bitrate */ + if (!hdd_check_bitmask_for_single_rate(band, mask)) { + hdd_err("Multiple bitrate set not supported for band %u", + band); + errno = -EINVAL; + continue; + } + + if (!qdf_get_hweight32(mask->control[band].legacy)) { + hdd_err("Legacy bit rate setting not supported for band %u", + band); + errno = -EINVAL; + continue; + } + + for (i = 0; + i < QDF_ARRAY_SIZE(mask->control[band].ht_mcs); i++) { + if (qdf_get_hweight8(mask->control[band].ht_mcs[i]) + == 1) { + nss = i; + rate_index = + (ffs(mask->control[band].ht_mcs[i]) - 1); + bit_rate = hdd_assemble_rate_code( + WMI_RATE_PREAMBLE_HT, + nss, rate_index); + goto configure_fw; + } + } + + for (i = 0; + i < QDF_ARRAY_SIZE(mask->control[band].vht_mcs); i++) { + if (qdf_get_hweight16(mask->control[band].vht_mcs[i]) + == 1) { + nss = i; + rate_index = + (ffs(mask->control[band].vht_mcs[i]) - 1); + bit_rate = hdd_assemble_rate_code( + WMI_RATE_PREAMBLE_VHT, + nss, rate_index); + goto configure_fw; + } + } + + if (qdf_get_hweight32(mask->control[band].legacy) == 1) { + rate_index = (ffs(mask->control[band].legacy) - 1); + nss = 0; + if (band == NL80211_BAND_5GHZ) + rate_index += 4; + if (rate_index < 4) + bit_rate = hdd_assemble_rate_code( + WMI_RATE_PREAMBLE_CCK, nss, + hdd_legacy_rates[rate_index].hw_value); + else if (rate_index >= 4 && rate_index < 12) + bit_rate = hdd_assemble_rate_code( + WMI_RATE_PREAMBLE_OFDM, nss, + hdd_legacy_rates[rate_index].hw_value); + } + + hdd_get_he_bitrate_params_for_band(band, mask, &nss, + &rate_index, &bit_rate); + +configure_fw: + if (bit_rate != -1) { + hdd_debug("wmi_vdev_param_fixed_rate val %d", bit_rate); + + errno = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + bit_rate, VDEV_CMD); + + if (errno) + hdd_err("Failed to set firmware, errno %d", + errno); + } + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(5, 10, 0)) + if (NL80211_RATE_INFO_HE_GI_0_8 == mask->control[band].he_gi) { + auto_rate_he_gi = AUTO_RATE_GI_800NS; + gi_val = 1; + } else if (NL80211_RATE_INFO_HE_GI_1_6 == + mask->control[band].he_gi) { + auto_rate_he_gi = AUTO_RATE_GI_1600NS; + gi_val = 2; + } else if (NL80211_RATE_INFO_HE_GI_3_2 == + mask->control[band].he_gi) { + auto_rate_he_gi = AUTO_RATE_GI_3200NS; + gi_val = 3; + } + if (auto_rate_he_gi) { + errno = sme_set_auto_rate_he_sgi( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + auto_rate_he_gi); + if (errno) + hdd_err("auto rate GI %d set fail, status %d", + auto_rate_he_gi, errno); + + errno = sme_update_ht_config( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + gi_val); + + if (errno) { + hdd_err("cfg set failed, value %d status %d", + gi_val, errno); + } + } else +#endif + if (mask->control[band].gi) { + if (NL80211_TXRATE_FORCE_SGI == mask->control[band].gi) + gi_val = 0; + else + gi_val = 1; + + errno = sme_update_ht_config( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + gi_val); + + if (errno) + hdd_err("cfg set failed, value %d status %d", + mask->control[band].gi, errno); + } + } + + return errno; +} + +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +static int wlan_hdd_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *netdev, + unsigned int link_id, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +#else +static int wlan_hdd_cfg80211_set_bitrate_mask(struct wiphy *wiphy, + struct net_device *netdev, + const u8 *peer, + const struct cfg80211_bitrate_mask *mask) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(netdev, &vdev_sync); + if (errno) { + hdd_err("vdev_sync_op_start failure"); + return errno; + } + + errno = __wlan_hdd_cfg80211_set_bitrate_mask(wiphy, netdev, peer, + mask); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int __wlan_hdd_cfg80211_tx_control_port(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *src, const u8 *dest, + __be16 proto, bool unencrypted, + int link_id) +{ + qdf_nbuf_t nbuf; + struct ethhdr *ehdr; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_enter(); + + nbuf = dev_alloc_skb(len + sizeof(struct ethhdr)); + if (!nbuf) + return -ENOMEM; + + skb_reserve(nbuf, sizeof(struct ethhdr)); + skb_put_data(nbuf, buf, len); + ehdr = skb_push(nbuf, sizeof(struct ethhdr)); + qdf_mem_copy(ehdr->h_dest, dest, ETH_ALEN); + + if (!src || qdf_is_macaddr_zero((struct qdf_mac_addr *)src)) + qdf_mem_copy(ehdr->h_source, adapter->mac_addr.bytes, ETH_ALEN); + else + qdf_mem_copy(ehdr->h_source, src, ETH_ALEN); + + ehdr->h_proto = proto; + + nbuf->dev = dev; + nbuf->protocol = htons(ETH_P_PAE); + skb_reset_network_header(nbuf); + skb_reset_mac_header(nbuf); + + netif_tx_lock(dev); + skb_set_queue_mapping(nbuf, hdd_wmm_select_queue(dev, nbuf)); + dev->netdev_ops->ndo_start_xmit(nbuf, dev); + netif_tx_unlock(dev); + + hdd_exit(); + return 0; +} + +static int _wlan_hdd_cfg80211_tx_control_port(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *src, const u8 *dest, + __be16 proto, bool unencrypted, + int link_id) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_tx_control_port(wiphy, dev, buf, len, src, + dest, proto, unencrypted, + link_id); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41) || \ + defined(CFG80211_TX_CONTROL_PORT_LINK_SUPPORT)) +static int wlan_hdd_cfg80211_tx_control_port(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, + size_t len, + const u8 *dest, const __be16 proto, + bool unencrypted, int link_id, + u64 *cookie) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + return _wlan_hdd_cfg80211_tx_control_port(wiphy, dev, buf, len, + adapter->mac_addr.bytes, + dest, proto, unencrypted, + link_id); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 8, 0)) +static int wlan_hdd_cfg80211_tx_control_port(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, + bool unencrypted, u64 *cookie) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + return _wlan_hdd_cfg80211_tx_control_port(wiphy, dev, buf, len, + adapter->mac_addr.bytes, + dest, proto, unencrypted, -1); +} +#else +static int wlan_hdd_cfg80211_tx_control_port(struct wiphy *wiphy, + struct net_device *dev, + const u8 *buf, size_t len, + const u8 *dest, __be16 proto, + bool unencrypted) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + return _wlan_hdd_cfg80211_tx_control_port(wiphy, dev, buf, len, + adapter->mac_addr.bytes, + dest, proto, unencrypted, -1); +} +#endif + +#if defined(CFG80211_CTRL_FRAME_SRC_ADDR_TA_ADDR) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41)) +bool wlan_hdd_cfg80211_rx_control_port(struct net_device *dev, + u8 *ta_addr, + struct sk_buff *skb, + bool unencrypted) +{ + return cfg80211_rx_control_port(dev, skb, unencrypted, -1); +} + +#else +bool wlan_hdd_cfg80211_rx_control_port(struct net_device *dev, + u8 *ta_addr, + struct sk_buff *skb, + bool unencrypted) +{ + return cfg80211_rx_control_port(dev, ta_addr, skb, unencrypted); +} +#endif + +#else +bool wlan_hdd_cfg80211_rx_control_port(struct net_device *dev, + u8 *ta_addr, + struct sk_buff *skb, + bool unencrypted) +{ + return false; +} +#endif + +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +static int +wlan_hdd_cfg80211_add_intf_link(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id) +{ + return 0; +} + +static void +wlan_hdd_cfg80211_del_intf_link(struct wiphy *wiphy, struct wireless_dev *wdev, + unsigned int link_id) +{ +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) +#if defined(WLAN_TID_LINK_MAP_SUPPORT) +#define MAX_T2LM_INFO 2 + +static void wlan_hdd_print_t2lm_info(struct cfg80211_mlo_tid_map *map) +{ + int i; + + hdd_debug("T2LM info send to userspace"); + hdd_debug("default mapping: %d", map->default_map); + for (i = 0; i < T2LM_MAX_NUM_TIDS; i++) + hdd_debug("TID[%d]: Downlink: %d Uplink: %d", + i, map->t2lmap[i].downlink, map->t2lmap[i].uplink); +} + +static void wlan_hdd_fill_bidir_t2lm(struct wlan_t2lm_info *t2lm, + struct tid_link_map *t2lmap) +{ + uint8_t tid; + + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { + t2lmap[tid].downlink = t2lm->ieee_link_map_tid[tid]; + t2lmap[tid].uplink = t2lm->ieee_link_map_tid[tid]; + } +} + +static void wlan_hdd_fill_dldir_t2lm(struct wlan_t2lm_info *t2lm, + struct tid_link_map *t2lmap) +{ + uint8_t tid; + + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) + t2lmap[tid].downlink = t2lm->ieee_link_map_tid[tid]; +} + +static void wlan_hdd_fill_uldir_t2lm(struct wlan_t2lm_info *t2lm, + struct tid_link_map *t2lmap) +{ + uint8_t tid; + + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) + t2lmap[tid].uplink = t2lm->ieee_link_map_tid[tid]; +} + +static void wlan_hdd_fill_map(struct wlan_t2lm_info *t2lm, + struct cfg80211_mlo_tid_map *map, bool *found) +{ + if (t2lm->direction == WLAN_T2LM_INVALID_DIRECTION) + return; + + map->default_map = t2lm->default_link_mapping; + + switch (t2lm->direction) { + case WLAN_T2LM_BIDI_DIRECTION: + wlan_hdd_fill_bidir_t2lm(t2lm, map->t2lmap); + *found = true; + break; + case WLAN_T2LM_DL_DIRECTION: + wlan_hdd_fill_dldir_t2lm(t2lm, map->t2lmap); + *found = true; + break; + case WLAN_T2LM_UL_DIRECTION: + wlan_hdd_fill_uldir_t2lm(t2lm, map->t2lmap); + *found = true; + break; + default: + return; + } +} + +static int wlan_hdd_fill_t2lm_response(struct wlan_t2lm_info *t2lm, + struct cfg80211_mlo_tid_map *map) +{ + uint8_t i; + bool found = false; + + for (i = 0; i < MAX_T2LM_INFO; i++) + wlan_hdd_fill_map(&t2lm[i], map, &found); + + if (!found) { + hdd_err("T2LM info not found"); + return -EINVAL; + } + + wlan_hdd_print_t2lm_info(map); + + return 0; +} + +static int +__wlan_hdd_cfg80211_get_t2lm_mapping_status(struct wiphy *wiphy, + struct net_device *net_dev, + struct cfg80211_mlo_tid_map *map) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct wlan_objmgr_vdev *vdev; + struct wlan_t2lm_info *t2lm = NULL; + int ret, i; + + hdd_enter(); + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Vdev is null return"); + return -EINVAL; + } + + if (!wlan_cm_is_vdev_connected(vdev)) { + hdd_err("Not associated!, vdev %d", wlan_vdev_get_id(vdev)); + ret = -EAGAIN; + goto vdev_release; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_err("failed due to non-ML connection"); + ret = -EINVAL; + goto vdev_release; + } + + t2lm = qdf_mem_malloc(sizeof(*t2lm) * MAX_T2LM_INFO); + if (!t2lm) { + hdd_err("mem alloc failed for t2lm"); + ret = -ENOMEM; + goto vdev_release; + } + + for (i = 0; i < MAX_T2LM_INFO; i++) + t2lm[i].direction = WLAN_T2LM_INVALID_DIRECTION; + + ret = wlan_get_t2lm_mapping_status(vdev, t2lm); + if (ret != 0) + goto t2lm_free; + + ret = wlan_hdd_fill_t2lm_response(t2lm, map); + +t2lm_free: + qdf_mem_free(t2lm); +vdev_release: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + hdd_exit(); + + return ret; +} + +static int +wlan_hdd_cfg80211_get_t2lm_mapping_status(struct wiphy *wiphy, + struct net_device *net_dev, + struct cfg80211_mlo_tid_map *map) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_t2lm_mapping_status(wiphy, net_dev, map); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +QDF_STATUS hdd_tid_to_link_map(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm, + struct net_device *dev) +{ + struct cfg80211_mlo_tid_map map; + bool found = false; + + qdf_mem_zero(&map, sizeof(map)); + wlan_hdd_fill_map(t2lm, &map, &found); + if (!found) { + hdd_debug("Failed to get t2lm info"); + return QDF_STATUS_E_FAILURE; + } + + wlan_hdd_print_t2lm_info(&map); + cfg80211_tid_to_link_map_change(dev, &map); + return QDF_STATUS_SUCCESS; +} + +#else +static void wlan_hdd_print_vendor_t2lm_info(struct wlan_t2lm_info *t2lm) +{ + int tid, value = 0; + + hdd_debug("default mapping: %d", t2lm->default_link_mapping); + + if (t2lm->direction == WLAN_T2LM_INVALID_DIRECTION) + return; + + switch (t2lm->direction) { + case WLAN_T2LM_BIDI_DIRECTION: + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { + hdd_debug("TID[%d]: Downlink: %d Uplink: %d", + tid, t2lm->ieee_link_map_tid[tid], + t2lm->ieee_link_map_tid[tid]); + } + break; + case WLAN_T2LM_DL_DIRECTION: + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { + /* Keep uplink info as 0 for downlink direction */ + hdd_debug("TID[%d]: Downlink: %d Uplink: %d", + tid, t2lm->ieee_link_map_tid[tid], value); + } + break; + case WLAN_T2LM_UL_DIRECTION: + for (tid = 0; tid < T2LM_MAX_NUM_TIDS; tid++) { + /* Keep downlinklink info as 0 for downlink direction */ + hdd_debug("TID[%d]: Downlink: %d Uplink: %d", + tid, value, t2lm->ieee_link_map_tid[tid]); + } + break; + default: + return; + } +} + +QDF_STATUS hdd_tid_to_link_map(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm, + struct net_device *dev) +{ + uint8_t ret; + + wlan_hdd_print_vendor_t2lm_info(t2lm); + ret = wlan_hdd_send_t2lm_event(vdev, t2lm); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_debug("failed to send t2lm info to userspace"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS hdd_mlo_dev_t2lm_notify_link_update(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm) +{ + struct wlan_hdd_link_info *link_info; + struct net_device *dev; + uint8_t ret; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("Invalid VDEV"); + return QDF_STATUS_E_FAILURE; + } + + dev = link_info->adapter->dev; + hdd_enter_dev(dev); + + ret = hdd_tid_to_link_map(vdev, t2lm, dev); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_debug("tid to link map change failed "); + return QDF_STATUS_E_FAILURE; + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} +#endif + +static struct cfg80211_ops wlan_hdd_cfg80211_ops = { + .add_virtual_intf = wlan_hdd_add_virtual_intf, + .del_virtual_intf = wlan_hdd_del_virtual_intf, + .change_virtual_intf = wlan_hdd_cfg80211_change_iface, + .change_station = wlan_hdd_change_station, + .start_ap = wlan_hdd_cfg80211_start_ap, + .change_beacon = wlan_hdd_cfg80211_change_beacon, + .stop_ap = wlan_hdd_cfg80211_stop_ap, + .change_bss = wlan_hdd_cfg80211_change_bss, + .add_key = wlan_hdd_cfg80211_add_key, + .get_key = wlan_hdd_cfg80211_get_key, + .del_key = wlan_hdd_cfg80211_del_key, + .set_default_key = wlan_hdd_cfg80211_set_default_key, + .scan = wlan_hdd_cfg80211_scan, + .connect = wlan_hdd_cfg80211_connect, + .disconnect = wlan_hdd_cfg80211_disconnect, + .set_wiphy_params = wlan_hdd_cfg80211_set_wiphy_params, + .set_tx_power = wlan_hdd_cfg80211_set_txpower, + .get_tx_power = wlan_hdd_cfg80211_get_txpower, + .remain_on_channel = wlan_hdd_cfg80211_remain_on_channel, + .cancel_remain_on_channel = wlan_hdd_cfg80211_cancel_remain_on_channel, + .mgmt_tx = wlan_hdd_mgmt_tx, + .mgmt_tx_cancel_wait = wlan_hdd_cfg80211_mgmt_tx_cancel_wait, + .set_default_mgmt_key = wlan_hdd_set_default_mgmt_key, +#if defined (CFG80211_BIGTK_CONFIGURATION_SUPPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) + .set_default_beacon_key = wlan_hdd_cfg80211_set_default_beacon_key, +#endif + .set_txq_params = wlan_hdd_set_txq_params, + .dump_station = wlan_hdd_cfg80211_dump_station, + .get_station = wlan_hdd_cfg80211_get_station, + .set_power_mgmt = wlan_hdd_cfg80211_set_power_mgmt, + .del_station = wlan_hdd_cfg80211_del_station, + .add_station = wlan_hdd_cfg80211_add_station, + .set_pmksa = wlan_hdd_cfg80211_set_pmksa, + .del_pmksa = wlan_hdd_cfg80211_del_pmksa, + .flush_pmksa = wlan_hdd_cfg80211_flush_pmksa, +#if defined(KERNEL_SUPPORT_11R_CFG80211) + .update_ft_ies = wlan_hdd_cfg80211_update_ft_ies, +#endif +#if defined(CFG80211_EXTERNAL_DH_UPDATE_SUPPORT) || \ +(LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0)) + .update_owe_info = wlan_hdd_cfg80211_update_owe_info, +#endif +#ifdef FEATURE_WLAN_TDLS + .tdls_mgmt = wlan_hdd_cfg80211_tdls_mgmt, + .tdls_oper = wlan_hdd_cfg80211_tdls_oper, +#endif +#ifdef WLAN_FEATURE_GTK_OFFLOAD + .set_rekey_data = wlan_hdd_cfg80211_set_rekey_data, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +#ifdef FEATURE_WLAN_SCAN_PNO + .sched_scan_start = wlan_hdd_cfg80211_sched_scan_start, + .sched_scan_stop = wlan_hdd_cfg80211_sched_scan_stop, +#endif /*FEATURE_WLAN_SCAN_PNO */ + .resume = wlan_hdd_cfg80211_resume_wlan, + .suspend = wlan_hdd_cfg80211_suspend_wlan, + .set_mac_acl = wlan_hdd_cfg80211_set_mac_acl, +#ifdef WLAN_NL80211_TESTMODE + .testmode_cmd = wlan_hdd_cfg80211_testmode, +#endif +#ifdef QCA_HT_2040_COEX + .set_ap_chanwidth = wlan_hdd_cfg80211_set_ap_channel_width, +#endif + .dump_survey = wlan_hdd_cfg80211_dump_survey, +#ifdef CHANNEL_SWITCH_SUPPORTED + .channel_switch = wlan_hdd_cfg80211_channel_switch, +#endif +#ifdef FEATURE_MONITOR_MODE_SUPPORT + .set_monitor_channel = wlan_hdd_cfg80211_set_mon_ch, +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) + .abort_scan = wlan_hdd_cfg80211_abort_scan, +#endif +#if defined(CFG80211_UPDATE_CONNECT_PARAMS) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 10, 0)) + .update_connect_params = wlan_hdd_cfg80211_update_connect_params, +#endif +#if defined(WLAN_FEATURE_SAE) && \ + (defined(CFG80211_EXTERNAL_AUTH_SUPPORT) || \ + LINUX_VERSION_CODE >= KERNEL_VERSION(4, 17, 0)) + .external_auth = wlan_hdd_cfg80211_external_auth, +#endif +#if defined(WLAN_FEATURE_NAN) && \ + (KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE) + .start_nan = wlan_hdd_cfg80211_start_nan, + .stop_nan = wlan_hdd_cfg80211_stop_nan, + .add_nan_func = wlan_hdd_cfg80211_add_nan_func, + .del_nan_func = wlan_hdd_cfg80211_del_nan_func, + .nan_change_conf = wlan_hdd_cfg80211_nan_change_conf, +#endif + .set_antenna = wlan_hdd_cfg80211_set_chainmask, + .get_antenna = wlan_hdd_cfg80211_get_chainmask, + .get_channel = wlan_hdd_cfg80211_get_channel, + .set_bitrate_mask = wlan_hdd_cfg80211_set_bitrate_mask, + .tx_control_port = wlan_hdd_cfg80211_tx_control_port, +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT + .add_intf_link = wlan_hdd_cfg80211_add_intf_link, + .del_intf_link = wlan_hdd_cfg80211_del_intf_link, +#endif +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_TID_LINK_MAP_SUPPORT) + .get_link_tid_map_status = wlan_hdd_cfg80211_get_t2lm_mapping_status, +#endif +}; diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h new file mode 100644 index 0000000000..d044c8e4f0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.h @@ -0,0 +1,1190 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_cfg80211.h + * + * WLAN host device driver cfg80211 functions declaration + */ + +#if !defined(HDD_CFG80211_H__) +#define HDD_CFG80211_H__ + +#include +#include +#include +#include +#include + +struct hdd_context; +struct wlan_hdd_link_info; + +#ifdef WLAN_FEATURE_11BE_MLO +#define EHT_OPMODE_SUPPORTED 2 +#else +#define EHT_OPMODE_SUPPORTED 1 +#endif + +/* QCA_NL80211_VENDOR_SUBCMD_ROAM policy */ +extern const struct nla_policy wlan_hdd_set_roam_param_policy[ + QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_INFO policy */ +extern const struct nla_policy qca_wlan_vendor_get_wifi_info_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_INFO_GET_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION policy */ +extern const struct nla_policy wlan_hdd_wifi_config_policy[ + QCA_WLAN_VENDOR_ATTR_CONFIG_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_WIFI_LOGGER_START policy */ +extern const struct nla_policy qca_wlan_vendor_wifi_logger_start_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_START_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_ND_OFFLOAD policy */ +extern const struct nla_policy ns_offload_set_policy[ + QCA_WLAN_VENDOR_ATTR_ND_OFFLOAD_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_GET_PREFERRED_FREQ_LIST policy */ +extern const struct nla_policy get_preferred_freq_list_policy[ + QCA_WLAN_VENDOR_ATTR_GET_PREFERRED_FREQ_LIST_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_SET_PROBABLE_OPER_CHANNEL policy */ +extern const struct nla_policy set_probable_oper_channel_policy[ + QCA_WLAN_VENDOR_ATTR_PROBABLE_OPER_CHANNEL_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG policy */ +extern const struct nla_policy wlan_hdd_set_no_dfs_flag_config_policy[ + QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_GET_RING_DATA policy */ +extern const struct nla_policy qca_wlan_vendor_wifi_logger_get_ring_data_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_LOGGER_GET_RING_DATA_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_OFFLOADED_PACKETS policy */ +extern const struct nla_policy offloaded_packet_policy[ + QCA_WLAN_VENDOR_ATTR_OFFLOADED_PACKETS_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_SETBAND policy */ +extern const struct nla_policy setband_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_ACS_POLICY policy */ +extern const struct nla_policy wlan_hdd_set_acs_dfs_config_policy[ + QCA_WLAN_VENDOR_ATTR_ACS_DFS_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_STA_CONNECT_ROAM_POLICY policy */ +extern const struct nla_policy wlan_hdd_set_sta_roam_config_policy[ + QCA_WLAN_VENDOR_ATTR_STA_CONNECT_ROAM_POLICY_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_WISA policy */ +extern const struct nla_policy wlan_hdd_wisa_cmd_policy[ + QCA_WLAN_VENDOR_ATTR_WISA_MAX + 1]; + +/* value for initial part of frames and number of bytes to be compared */ +#define GAS_INITIAL_REQ "\x04\x0a" +#define GAS_INITIAL_REQ_SIZE 2 + +#define GAS_INITIAL_RSP "\x04\x0b" +#define GAS_INITIAL_RSP_SIZE 2 + +#define GAS_COMEBACK_REQ "\x04\x0c" +#define GAS_COMEBACK_REQ_SIZE 2 + +#define GAS_COMEBACK_RSP "\x04\x0d" +#define GAS_COMEBACK_RSP_SIZE 2 + +#define P2P_PUBLIC_ACTION_FRAME "\x04\x09\x50\x6f\x9a\x09" +#define P2P_PUBLIC_ACTION_FRAME_SIZE 6 + +#define P2P_ACTION_FRAME "\x7f\x50\x6f\x9a\x09" +#define P2P_ACTION_FRAME_SIZE 5 + +#define SA_QUERY_FRAME_REQ "\x08\x00" +#define SA_QUERY_FRAME_REQ_SIZE 2 + +#define SA_QUERY_FRAME_RSP "\x08\x01" +#define SA_QUERY_FRAME_RSP_SIZE 2 + +#define WNM_BSS_ACTION_FRAME "\x0a\x07" +#define WNM_BSS_ACTION_FRAME_SIZE 2 + +#define WNM_NOTIFICATION_FRAME "\x0a\x1a" +#define WNM_NOTIFICATION_FRAME_SIZE 2 + +#define WPA_OUI_TYPE "\x00\x50\xf2\x01" +#define DENYLIST_OUI_TYPE "\x00\x50\x00\x00" +#define ALLOWLIST_OUI_TYPE "\x00\x50\x00\x01" +#define WPA_OUI_TYPE_SIZE 4 +#define WMM_OUI_TYPE "\x00\x50\xf2\x02\x01" +#define WMM_OUI_TYPE_SIZE 5 + +#define VENDOR1_AP_OUI_TYPE "\x00\xE0\x4C" +#define VENDOR1_AP_OUI_TYPE_SIZE 3 + +#define BASIC_RATE_MASK 0x80 +#define RATE_MASK 0x7f + +#ifndef NL80211_AUTHTYPE_FILS_SK +#define NL80211_AUTHTYPE_FILS_SK 5 +#endif +#ifndef NL80211_AUTHTYPE_FILS_SK_PFS +#define NL80211_AUTHTYPE_FILS_SK_PFS 6 +#endif +#ifndef NL80211_AUTHTYPE_FILS_PK +#define NL80211_AUTHTYPE_FILS_PK 7 +#endif +#ifndef WLAN_AKM_SUITE_FILS_SHA256 +#define WLAN_AKM_SUITE_FILS_SHA256 0x000FAC0E +#endif +#ifndef WLAN_AKM_SUITE_FILS_SHA384 +#define WLAN_AKM_SUITE_FILS_SHA384 0x000FAC0F +#endif +#ifndef WLAN_AKM_SUITE_FT_FILS_SHA256 +#define WLAN_AKM_SUITE_FT_FILS_SHA256 0x000FAC10 +#endif +#ifndef WLAN_AKM_SUITE_FT_FILS_SHA384 +#define WLAN_AKM_SUITE_FT_FILS_SHA384 0x000FAC11 +#endif +#ifndef WLAN_AKM_SUITE_DPP_RSN +#define WLAN_AKM_SUITE_DPP_RSN 0x506f9a02 +#endif + +#ifndef WLAN_AKM_SUITE_OWE +#define WLAN_AKM_SUITE_OWE 0x000FAC12 +#endif + +#ifndef WLAN_AKM_SUITE_EAP_SHA256 +#define WLAN_AKM_SUITE_EAP_SHA256 0x000FAC0B +#endif + +#ifndef WLAN_AKM_SUITE_EAP_SHA384 +#define WLAN_AKM_SUITE_EAP_SHA384 0x000FAC0C +#endif + +#ifndef WLAN_AKM_SUITE_SAE +#define WLAN_AKM_SUITE_SAE 0x000FAC08 +#endif + +#ifndef WLAN_AKM_SUITE_FT_SAE +#define WLAN_AKM_SUITE_FT_SAE 0x000FAC09 +#endif + +#ifndef WLAN_AKM_SUITE_FT_EAP_SHA_384 +#define WLAN_AKM_SUITE_FT_EAP_SHA_384 0x000FAC0D +#endif + +#ifndef WLAN_AKM_SUITE_SAE_EXT_KEY +#define WLAN_AKM_SUITE_SAE_EXT_KEY 0x000FAC18 +#endif + +#ifndef WLAN_AKM_SUITE_FT_SAE_EXT_KEY +#define WLAN_AKM_SUITE_FT_SAE_EXT_KEY 0x000FAC19 +#endif + +#ifdef FEATURE_WLAN_TDLS +#define WLAN_IS_TDLS_SETUP_ACTION(action) \ + ((TDLS_SETUP_REQUEST <= action) && \ + (TDLS_SETUP_CONFIRM >= action)) +#if !defined(TDLS_MGMT_VERSION2) +#define TDLS_MGMT_VERSION2 0 +#endif + +#endif + +#define HDD_SET_BIT(__param, __val) ((__param) |= (1 << (__val))) + +#define MAX_SCAN_SSID 10 + +#define IS_CHANNEL_VALID(channel) ((channel >= 0 && channel < 15) \ + || (channel >= 36 && channel <= 184)) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) \ + || defined(BACKPORTED_CHANNEL_SWITCH_PRESENT) +#define CHANNEL_SWITCH_SUPPORTED +#endif + +#if defined(CFG80211_DEL_STA_V2) || (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)) || defined(WITH_BACKPORTS) +#define USE_CFG80211_DEL_STA_V2 +#endif + +/** + * typedef eDFS_CAC_STATUS - CAC status + * + * @DFS_CAC_NEVER_DONE: CAC never done + * @DFS_CAC_IN_PROGRESS: CAC is in progress + * @DFS_CAC_ALREADY_DONE: CAC already done + */ +typedef enum { + DFS_CAC_NEVER_DONE, + DFS_CAC_IN_PROGRESS, + DFS_CAC_ALREADY_DONE, +} eDFS_CAC_STATUS; + +#define MAX_REQUEST_ID 0xFFFFFFFF + +/* Feature defines */ +#define WIFI_FEATURE_INFRA 0x0001 /* Basic infrastructure mode */ +#define WIFI_FEATURE_INFRA_5G 0x0002 /* Support for 5 GHz Band */ +#define WIFI_FEATURE_HOTSPOT 0x0004 /* Support for GAS/ANQP */ +#define WIFI_FEATURE_P2P 0x0008 /* Wifi-Direct */ +#define WIFI_FEATURE_SOFT_AP 0x0010 /* Soft AP */ +#define WIFI_FEATURE_EXTSCAN 0x0020 /* Extended Scan APIs */ +#define WIFI_FEATURE_NAN 0x0040 /* Neighbor Awareness + * Networking + */ +#define WIFI_FEATURE_D2D_RTT 0x0080 /* Device-to-device RTT */ +#define WIFI_FEATURE_D2AP_RTT 0x0100 /* Device-to-AP RTT */ +#define WIFI_FEATURE_BATCH_SCAN 0x0200 /* Batched Scan (legacy) */ +#define WIFI_FEATURE_PNO 0x0400 /* Preferred network offload */ +#define WIFI_FEATURE_ADDITIONAL_STA 0x0800 /* Support for two STAs */ +#define WIFI_FEATURE_TDLS 0x1000 /* Tunnel directed link + * setup + */ +#define WIFI_FEATURE_TDLS_OFFCHANNEL 0x2000 /* Support for TDLS off + * channel + */ +#define WIFI_FEATURE_EPR 0x4000 /* Enhanced power reporting */ +#define WIFI_FEATURE_AP_STA 0x8000 /* Support for AP STA + * Concurrency + */ +#define WIFI_FEATURE_LINK_LAYER_STATS 0x10000 /* Link layer stats */ +#define WIFI_FEATURE_LOGGER 0x20000 /* WiFi Logger */ +#define WIFI_FEATURE_HAL_EPNO 0x40000 /* WiFi PNO enhanced */ +#define WIFI_FEATURE_RSSI_MONITOR 0x80000 /* RSSI Monitor */ +#define WIFI_FEATURE_MKEEP_ALIVE 0x100000 /* WiFi mkeep_alive */ +#define WIFI_FEATURE_CONFIG_NDO 0x200000 /* ND offload configure */ +#define WIFI_FEATURE_TX_TRANSMIT_POWER 0x400000 /* Tx transmit power levels */ +#define WIFI_FEATURE_CONTROL_ROAMING 0x800000 /* Enable/Disable roaming */ +#define WIFI_FEATURE_IE_ALLOWLIST 0x1000000 /* Support Probe IE allow + * listing + */ +#define WIFI_FEATURE_SCAN_RAND 0x2000000 /* Support MAC & Probe Sequence Number randomization */ +#define WIFI_FEATURE_SET_LATENCY_MODE 0x40000000 /* Set latency mode */ +/* Support changing MAC address without iface reset(down and up) */ +#define WIFI_FEATURE_DYNAMIC_SET_MAC 0x10000000 + +/* Support Tx Power Limit setting */ +#define WIFI_FEATURE_SET_TX_POWER_LIMIT 0x4000000 + +/* Add more features here */ +#define WIFI_TDLS_SUPPORT BIT(0) +#define WIFI_TDLS_EXTERNAL_CONTROL_SUPPORT BIT(1) +#define WIFI_TDLS_OFFCHANNEL_SUPPORT BIT(2) +#define WIFI_TDLS_WIDER_BW_SUPPORT BIT(3) + +#define CFG_NON_AGG_RETRY_MAX (64) +#define CFG_AGG_RETRY_MAX (64) +#define CFG_CTRL_RETRY_MAX (31) +#define CFG_PROPAGATION_DELAY_MAX (63) +#define CFG_PROPAGATION_DELAY_BASE (64) +#define CFG_AGG_RETRY_MIN (5) +#define CFG_NON_AGG_RETRY_MIN (5) + +#define CFG_NO_SUPPORT_UL_MUMIMO (0) +#define CFG_FULL_BW_SUPPORT_UL_MUMIMO (1) +#define CFG_PARTIAL_BW_SUPPORT_UL_MUMIMO (2) +#define CFG_FULL_PARTIAL_BW_SUPPORT_UL_MUMIMO (3) + +#define PCL_CHANNEL_SUPPORT_GO BIT(0) +#define PCL_CHANNEL_SUPPORT_CLI BIT(1) +#define PCL_CHANNEL_EXCLUDE_IN_GO_NEG BIT(3) + +#define CONNECTIVITY_CHECK_SET_ARP \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ARP +#define CONNECTIVITY_CHECK_SET_DNS \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_DNS +#define CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE +#define CONNECTIVITY_CHECK_SET_ICMPV4 \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ICMPV4 +#define CONNECTIVITY_CHECK_SET_ICMPV6 \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ICMPV6 +#define CONNECTIVITY_CHECK_SET_TCP_SYN \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_SYN +#define CONNECTIVITY_CHECK_SET_TCP_SYN_ACK \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK +#define CONNECTIVITY_CHECK_SET_TCP_ACK \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_ACK + +extern const struct nla_policy +wlan_hdd_wifi_test_config_policy[ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX + 1]; + +#define RSNXE_DEFAULT 0 +#define RSNXE_OVERRIDE_1 1 +#define RSNXE_OVERRIDE_2 2 +#define CSA_DEFAULT 0 +#define CSA_IGNORE 1 +#define SA_QUERY_TIMEOUT_DEFAULT 0 +#define SA_QUERY_TIMEOUT_IGNORE 1 +#define FILS_DISCV_FRAMES_DISABLE 0 +#define FILS_DISCV_FRAMES_ENABLE 1 +#define H2E_RSNXE_DEFAULT 0 +#define H2E_RSNXE_IGNORE 1 + +#define FEATURE_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_WIFI_TEST_CONFIGURATION, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_wifi_test_config, \ + vendor_command_policy(wlan_hdd_wifi_test_config_policy, \ + QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_MAX) \ +}, + +extern const struct nla_policy + qca_wlan_vendor_set_nud_stats_policy + [QCA_ATTR_NUD_STATS_SET_MAX + 1]; + +#define FEATURE_VENDOR_SUBCMD_NUD_STATS_SET \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_NUD_STATS_SET, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_nud_stats, \ + vendor_command_policy(qca_wlan_vendor_set_nud_stats_policy, \ + QCA_ATTR_NUD_STATS_SET_MAX) \ +}, + +extern const struct nla_policy + qca_wlan_vendor_set_trace_level_policy + [QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX + 1]; + +#define FEATURE_VENDOR_SUBCMD_SET_TRACE_LEVEL \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TRACE_LEVEL, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_trace_level, \ + vendor_command_policy(qca_wlan_vendor_set_trace_level_policy, \ + QCA_WLAN_VENDOR_ATTR_SET_TRACE_LEVEL_MAX) \ +}, + +/** + * hdd_cfg80211_wiphy_alloc() - Allocate wiphy + * + * Allocate wiphy and hdd context. + * + * Return: hdd context on success and NULL on failure. + */ +struct hdd_context *hdd_cfg80211_wiphy_alloc(void); + +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +int wlan_hdd_cfg80211_init(struct device *dev, + struct wiphy *wiphy, struct hdd_config *config); + +void wlan_hdd_cfg80211_deinit(struct wiphy *wiphy); + +void wlan_hdd_update_wiphy(struct hdd_context *hdd_ctx); + +void wlan_hdd_update_11n_mode(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_update_wiphy_supported_band() - Updates wiphy band info when + * receive FW ready event + * @hdd_ctx: HDD context + * + * Updates wiphy band info + * + * Return: QDF Status + */ +QDF_STATUS wlan_hdd_update_wiphy_supported_band(struct hdd_context *hdd_ctx); + +int wlan_hdd_cfg80211_register(struct wiphy *wiphy); + +/** + * wlan_hdd_cfg80211_register_frames() - register frame types and callbacks + * with the PE. + * @adapter: pointer to adapter + * + * This function is used by HDD to register frame types which are interested + * by supplicant, callbacks for rx frame indication and ack. + * + * Return: 0 on success and non zero value on failure + */ +int wlan_hdd_cfg80211_register_frames(struct hdd_adapter *adapter); + +void wlan_hdd_cfg80211_deregister_frames(struct hdd_adapter *adapter); + +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request); + +/* + * FUNCTION: wlan_hdd_validate_operation_channel + * called by wlan_hdd_cfg80211_start_bss() and + * wlan_hdd_set_channel() + * @hdd_ctx: Global HDD context + * + * This function validates whether given channel is part of valid + * channel list. + */ +QDF_STATUS wlan_hdd_validate_operation_channel(struct hdd_context *hdd_ctx, + uint32_t ch_freq); + +/** + * hdd_select_cbmode() - select channel bonding mode + * @adapter: Pointer to adapter + * @oper_freq: Operating frequency (MHz) + * @sec_ch_2g_freq: secondary channel freq + * @ch_params: channel info struct to populate + * + * Return: none + */ +void hdd_select_cbmode(struct hdd_adapter *adapter, qdf_freq_t oper_freq, + qdf_freq_t sec_ch_2g_freq, struct ch_params *ch_params); + +/** + * wlan_hdd_is_ap_supports_immediate_power_save() - to find certain vendor APs + * which do not support immediate power-save. + * @ies: beacon IE of the AP which STA is connecting/connected to + * @length: beacon IE length only + * + * This API takes the IE of connected/connecting AP and determines that + * whether it has specific vendor OUI. If it finds then it will return false to + * notify that AP doesn't support immediate power-save. + * + * Return: true or false based on findings + */ +bool wlan_hdd_is_ap_supports_immediate_power_save(uint8_t *ies, int length); + +/** + * wlan_hdd_del_station() - delete station wrapper + * @adapter: pointer to the hdd adapter + * @mac: pointer to mac addr + * + * Return: Errno + */ +int wlan_hdd_del_station(struct hdd_adapter *adapter, const uint8_t *mac); + +#if defined(USE_CFG80211_DEL_STA_V2) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + struct station_del_parameters *param); +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac); +#else +int wlan_hdd_cfg80211_del_station(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *mac); +#endif +#endif /* USE_CFG80211_DEL_STA_V2 */ + +int wlan_hdd_send_avoid_freq_event(struct hdd_context *hdd_ctx, + struct ch_avoid_ind_type *avoid_freq_list); + +/** + * wlan_hdd_send_hang_reason_event() - Send hang reason to the userspace + * @hdd_ctx: Pointer to hdd context + * @reason: cds recovery reason + * @data: Hang Data + * @data_len: Hang Data len + * + * Return: 0 on success or failure reason + */ +int wlan_hdd_send_hang_reason_event(struct hdd_context *hdd_ctx, + uint32_t reason, uint8_t *data, + size_t data_len); + +int wlan_hdd_send_avoid_freq_for_dnbs(struct hdd_context *hdd_ctx, + qdf_freq_t op_freq); + +/** + * wlan_hdd_rso_cmd_status_cb() - HDD callback to read RSO command status + * @hdd_handle: opaque handle for the hdd context + * @rso_status: rso command status + * + * This callback function is invoked by firmware to update + * the RSO(ROAM SCAN OFFLOAD) command status. + * + * Return: None + */ +void wlan_hdd_rso_cmd_status_cb(hdd_handle_t hdd_handle, + struct rso_cmd_status *rso_status); + +/** + * wlan_hdd_cfg80211_acs_ch_select_evt: Callback function for ACS evt + * @link_info: Link info pointer in HDD adapter + * @store_acs_freq: Store current ACS frequecy flag + * + * This is a callback function on ACS procedure is completed. + * This function send the ACS selected channel information to hostapd + * + * Return: None + */ +void wlan_hdd_cfg80211_acs_ch_select_evt(struct wlan_hdd_link_info *link_info, + bool store_acs_freq); + +#ifdef WLAN_CFR_ENABLE +/* + * hdd_cfr_data_send_nl_event() - send cfr data through nl event + * @vdev_id: vdev id + * @pid: process pid to which send data event unicast way + * @data: pointer to the cfr data + * @data_len: length of data + * + * Return: void + */ +void hdd_cfr_data_send_nl_event(uint8_t vdev_id, uint32_t pid, + const void *data, uint32_t data_len); + +#define FEATURE_CFR_DATA_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG, \ +}, +#else +#define FEATURE_CFR_DATA_VENDOR_EVENTS +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * hdd_send_roam_scan_ch_list_event() - roam scan ch list event to user space + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * @buf_len: length of frequency list + * @buf: pointer to buffer of frequency list + * + * Return: None + */ +void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx, + uint8_t vdev_id, uint16_t buf_len, + uint8_t *buf); +#else +static inline +void hdd_send_roam_scan_ch_list_event(struct hdd_context *hdd_ctx, + uint8_t vdev_id, uint16_t buf_len, + uint8_t *buf) +{ +} +#endif + +/** + * wlan_hdd_cfg80211_update_apies() - update ap mode ies + * @link_info: Link info pointer in hostapd adapter + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_update_apies(struct wlan_hdd_link_info *link_info); + +int wlan_hdd_sap_cfg_dfs_override(struct hdd_adapter *adapter); + +int wlan_hdd_enable_dfs_chan_scan(struct hdd_context *hdd_ctx, + bool enable_dfs_channels); + +/** + * wlan_hdd_cfg80211_update_band() - Update band of operation + * @hdd_ctx: The global HDD context + * @wiphy: The wiphy being configured + * @new_band: The new bad of operation + * + * This function is called from the supplicant through a + * private ioctl to change the band value + * + * Return: 0 on success, else a negative errno if the operation could + * not be completed + */ +int wlan_hdd_cfg80211_update_band(struct hdd_context *hdd_ctx, + struct wiphy *wiphy, + enum band_info new_band); + +/** + * wlan_hdd_change_hw_mode_for_given_chnl() - change HW mode for given channel + * @adapter: pointer to adapter + * @chan_freq: given channel frequency + * @reason: reason for HW mode change is needed + * + * This API decides and sets hardware mode to DBS based on given channel. + * For example, some of the platforms require DBS hardware mode to operate + * in 2.4G channel + * + * Return: 0 for success and non-zero for failure + */ +int wlan_hdd_change_hw_mode_for_given_chnl(struct hdd_adapter *adapter, + uint32_t chan_freq, + enum policy_mgr_conn_update_reason reason); + +/** + * enum hdd_rate_info_bw: an HDD internal rate bandwidth representation + * @HDD_RATE_BW_5: 5MHz + * @HDD_RATE_BW_10: 10MHz + * @HDD_RATE_BW_20: 20MHz + * @HDD_RATE_BW_40: 40MHz + * @HDD_RATE_BW_80: 80MHz + * @HDD_RATE_BW_160: 160 MHz + * @HDD_RATE_BW_320: 320 MHz + */ +enum hdd_rate_info_bw { + HDD_RATE_BW_5, + HDD_RATE_BW_10, + HDD_RATE_BW_20, + HDD_RATE_BW_40, + HDD_RATE_BW_80, + HDD_RATE_BW_160, + HDD_RATE_BW_320, +}; + +/** + * enum hdd_chain_mode : Representation of Number of chains available. + * @HDD_CHAIN_MODE_1X1: Chain mask Not Configurable as only one chain available + * @HDD_CHAIN_MODE_2X2: Chain mask configurable as both chains available + */ +enum hdd_chain_mode { + HDD_CHAIN_MODE_1X1 = 1, + HDD_CHAIN_MODE_2X2 = 3, +}; + +/** + * enum hdd_ba_mode: Representation of Number to configure BA mode + * @HDD_BA_MODE_AUTO: Auto mode + * @HDD_BA_MODE_MANUAL: Manual mode + * @HDD_BA_MODE_64: For buffer size 64 + * @HDD_BA_MODE_256: For buffer size 256 + * @HDD_BA_MODE_128: placeholder, not valid + * @HDD_BA_MODE_512: For buffer size 512 + * @HDD_BA_MODE_1024: For buffer size 1024 + */ +enum hdd_ba_mode { + HDD_BA_MODE_AUTO, + HDD_BA_MODE_MANUAL, + HDD_BA_MODE_64, + HDD_BA_MODE_256, + HDD_BA_MODE_128, + HDD_BA_MODE_512, + HDD_BA_MODE_1024, +}; + +/** + * hdd_set_rate_bw(): Set the bandwidth for the given rate_info + * @info: The rate info for which the bandwidth should be set + * @hdd_bw: HDD representation of a rate info bandwidth + */ +void hdd_set_rate_bw(struct rate_info *info, enum hdd_rate_info_bw hdd_bw); + +/* + * hdd_get_sap_operating_band_by_link_info: Get operating channel of link info + * for sap. + * @link_info: Pointer to link_info in adapter + * + * Return : Corresponding band for SAP operating channel + */ + +uint8_t +hdd_get_sap_operating_band_by_link_info(struct wlan_hdd_link_info *link_info); + +/* + * hdd_get_sap_operating_band: Get current operating channel + * for sap. + * @hdd_ctx: hdd context + * + * Return : Corresponding band for SAP operating channel + */ +uint8_t hdd_get_sap_operating_band(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_merge_avoid_freqs(): Merge two tHddAvoidFreqList + * @destFreqList: Destination list in which merged frequency + * list will be available. + * @srcFreqList: Source frequency list. + * + * Merges two avoid_frequency lists + */ +int wlan_hdd_merge_avoid_freqs(struct ch_avoid_ind_type *destFreqList, + struct ch_avoid_ind_type *srcFreqList); + + +/** + * hdd_bt_activity_cb() - callback function to receive bt activity + * @hdd_handle: Opaque handle to the HDD context + * @bt_activity: specifies the kind of bt activity + * + * Return: none + */ +void hdd_bt_activity_cb(hdd_handle_t hdd_handle, uint32_t bt_activity); + +#ifdef WLAN_FEATURE_GTK_OFFLOAD +/** + * wlan_hdd_save_gtk_offload_params() - Save gtk offload parameters in STA + * context for offload operations. + * @adapter: Adapter context + * @kck_ptr: KCK buffer pointer + * @kck_len: KCK length + * @kek_ptr: KEK buffer pointer + * @kek_len: KEK length + * @replay_ctr: Pointer to 64 bit long replay counter + * @big_endian: true if replay_ctr is in big endian format + * + * Return: None + */ +void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter, + uint8_t *kck_ptr, uint8_t kck_len, + uint8_t *kek_ptr, uint32_t kek_len, + uint8_t *replay_ctr, bool big_endian); +#else +void wlan_hdd_save_gtk_offload_params(struct hdd_adapter *adapter, + uint8_t *kck_ptr, uint8_t kck_len, + uint8_t *kek_ptr, uint32_t kek_len, + uint8_t *replay_ctr, bool big_endian) +{} +#endif + + +/** + * wlan_hdd_flush_pmksa_cache() - flush pmksa cache for adapter + * @link_info: link_info pointer in adapter + * + * Return: qdf status + */ +QDF_STATUS wlan_hdd_flush_pmksa_cache(struct wlan_hdd_link_info *link_info); + +/* + * wlan_hdd_send_mode_change_event() - API to send hw mode change event to + * userspace + * + * Return : 0 on success and errno on failure + */ +int wlan_hdd_send_mode_change_event(void); + +/** + * wlan_hdd_restore_channels() - Restore the channels which were cached + * and disabled in wlan_hdd_disable_channels api. + * @hdd_ctx: Pointer to the HDD context + * + * Return: 0 on success, Error code on failure + */ +int wlan_hdd_restore_channels(struct hdd_context *hdd_ctx); + +/* + * wlan_hdd_send_sta_authorized_event: Function to send station authorized + * event to user space in case of SAP + * @adapter: Pointer to the adapter + * @hdd_ctx: HDD Context + * @mac_addr: MAC address of the STA for which the Authorized event needs to + * be sent + * This api is used to send station authorized event to user space + */ +QDF_STATUS wlan_hdd_send_sta_authorized_event( + struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + const struct qdf_mac_addr *mac_addr); + +/** + * hdd_set_dynamic_antenna_mode() - set dynamic antenna mode + * @link_info: Link info pointer in HDD adapter + * @num_rx_chains: number of chains to be used for receiving data + * @num_tx_chains: number of chains to be used for transmitting data + * + * This function will set dynamic antenna mode + * + * Return: 0 for success + */ +int hdd_set_dynamic_antenna_mode(struct wlan_hdd_link_info *link_info, + uint8_t num_rx_chains, uint8_t num_tx_chains); + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * hdd_get_multi_client_ll_support() - get multi client ll support flag + * @adapter: hdd adapter + * + * Return: none + */ +bool hdd_get_multi_client_ll_support(struct hdd_adapter *adapter); + +/** + * wlan_hdd_set_wlm_client_latency_level() - Set latency level to FW + * @adapter: pointer to network adapter + * @port_id: port id for which host sends latency level to FW + * @latency_level: level to be set in fw + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_set_wlm_client_latency_level(struct hdd_adapter *adapter, + uint32_t port_id, + uint16_t latency_level); + +/** + * wlan_hdd_set_wlm_latency_level() - Set latency level to FW + * @adapter: pointer to network adapter + * @latency_level: level to be set in fw + * @client_id_bitmap: client id bitmap + * @force_reset: flag to reset latency level in fw + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_set_wlm_latency_level(struct hdd_adapter *adapter, + uint16_t latency_level, + uint32_t client_id_bitmap, + bool force_reset); + +/** + * wlan_hdd_get_set_client_info_id() - to update client info table + * @adapter: pointer to network adapter + * @port_id: port id for which host receives set latency level vendor command + * @client_id: client id for a given port id + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_hdd_get_set_client_info_id(struct hdd_adapter *adapter, + uint32_t port_id, + uint32_t *client_id); + +/** + * wlan_hdd_get_client_id_bitmap() - to calculate client id bitmap + * @adapter: pointer to network adapter + * + * Return: client id bitmap + */ +uint8_t wlan_hdd_get_client_id_bitmap(struct hdd_adapter *adapter); + +/** + * hdd_latency_level_event_handler_cb() - Function to be invoked for low latency + * event + * @event_data: event data + * @vdev_id: vdev id + * + * Return: none + */ +void +hdd_latency_level_event_handler_cb(const struct latency_level_data *event_data, + uint8_t vdev_id); +#else +static inline +QDF_STATUS wlan_hdd_set_wlm_client_latency_level(struct hdd_adapter *adapter, + uint32_t port_id, + uint16_t latency_level) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +QDF_STATUS wlan_hdd_set_wlm_latency_level(struct hdd_adapter *adapter, + uint16_t latency_level, + uint32_t client_id_bitmap, + bool force_reset) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline uint8_t wlan_hdd_get_client_id_bitmap(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline +QDF_STATUS wlan_hdd_get_set_client_info_id(struct hdd_adapter *adapter, + uint32_t port_id, + uint32_t *client_id) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline bool hdd_get_multi_client_ll_support(struct hdd_adapter *adapter) +{ + return false; +} + +static inline void +hdd_latency_level_event_handler_cb(const void *event_data, + uint8_t vdev_id) +{ +} +#endif + +/** + * hdd_convert_cfgdot11mode_to_80211mode() - Function to convert cfg dot11 mode + * to 80211 mode + * @mode: cfg dot11 mode + * + * Return: 80211 mode + */ +enum qca_wlan_802_11_mode +hdd_convert_cfgdot11mode_to_80211mode(enum csr_cfgdot11mode mode); + +/** + * hdd_convert_phymode_to_80211mode() - Function to convert eCsrPhyMode + * to 80211 mode + * @mode: eCsrPhyMode + * + * Return: 80211 mode + */ +enum qca_wlan_802_11_mode +hdd_convert_phymode_to_80211mode(eCsrPhyMode mode); + +/** + * hdd_send_update_owe_info_event - Send update OWE info event + * @adapter: Pointer to adapter + * @sta_addr: MAC address of peer STA + * @owe_ie: OWE IE + * @owe_ie_len: Length of OWE IE + * + * Send update OWE info event to hostapd + * + * Return: none + */ +#if defined(CFG80211_EXTERNAL_DH_UPDATE_SUPPORT) || \ +(LINUX_VERSION_CODE > KERNEL_VERSION(5, 2, 0)) +void hdd_send_update_owe_info_event(struct hdd_adapter *adapter, + uint8_t sta_addr[], + uint8_t *owe_ie, + uint32_t owe_ie_len); +#else +static inline void hdd_send_update_owe_info_event(struct hdd_adapter *adapter, + uint8_t sta_addr[], + uint8_t *owe_ie, + uint32_t owe_ie_len) +{ +} +#endif + +/** + * hdd_set_phy_mode() - set phy mode + * @adapter: Handle to hdd_adapter + * @vendor_phy_mode: phy mode to set + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_phy_mode(struct hdd_adapter *adapter, + enum qca_wlan_vendor_phy_mode vendor_phy_mode); + +/** + * hdd_set_mac_chan_width() - set channel width + * @link_info: Link info in HDD adapter + * @chwidth: given channel width + * @link_id: mlo link id + * @is_restore: is restore + * + * Return: 0 on success, negative errno on failure + */ +int hdd_set_mac_chan_width(struct wlan_hdd_link_info *link_info, + enum eSirMacHTChannelWidth chwidth, + uint8_t link_id, bool is_restore); + +/** + * hdd_is_legacy_connection() - Is adapter connection is legacy + * @link_info: Pointer to link_info in hdd_adapter + * + * Return: true if connection mode is legacy, false otherwise. + */ +bool hdd_is_legacy_connection(struct wlan_hdd_link_info *link_info); + +struct hdd_hostapd_state; + +/** + * hdd_softap_deauth_all_sta() - Deauth all sta in the sta list + * @adapter: pointer to adapter structure + * @hapd_state: pointer to hostapd state structure + * @param: pointer to del sta params + * + * Return: QDF_STATUS on success, corresponding QDF failure status on failure + */ +QDF_STATUS hdd_softap_deauth_all_sta(struct hdd_adapter *adapter, + struct hdd_hostapd_state *hapd_state, + struct csr_del_sta_params *param); + +/** + * wlan_hdd_cfg80211_rx_control_port() - notification about a received control + * port frame + * + * @dev: net device pointer + * @ta_addr: transmitter address + * @skb: skbuf with the control port frame + * @unencrypted: Whether the frame is unencrypted + * + * Wrapper function for call to kernel function cfg80211_rx_control_port() + * + * Return: none + */ +bool wlan_hdd_cfg80211_rx_control_port(struct net_device *dev, + u8 *ta_addr, + struct sk_buff *skb, + bool unencrypted); + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * hdd_send_dbam_config() - send DBAM config + * @adapter: hdd adapter + * @dbam_mode: dbam mode configuration + * + * Return: 0 on success, negative errno on failure + */ +int hdd_send_dbam_config(struct hdd_adapter *adapter, + enum coex_dbam_config_mode dbam_mode); +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_hdd_send_key_vdev() - api to send vdev keys + * @vdev: vdev pointer + * @key_index: key index value + * @pairwise: pairwise keys + * @cipher_type: cipher type value + * + * Api to send vdev keys for mlo link + * + * Return: none + */ +QDF_STATUS wlan_hdd_send_key_vdev(struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + enum wlan_crypto_cipher_type cipher_type); + +/** + * wlan_hdd_mlo_copy_partner_addr_from_mlie - Copy the Partner link mac + * address from the ML IE + * @vdev: vdev pointer + * @partner_mac: pointer to the mac address to be filled + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_hdd_mlo_copy_partner_addr_from_mlie(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *partner_mac); +#else +static inline +QDF_STATUS wlan_hdd_send_key_vdev(struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + enum wlan_crypto_cipher_type cipher_type) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +wlan_hdd_mlo_copy_partner_addr_from_mlie(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *partner_mac) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +/** + * wlan_key_get_link_vdev() - get vdev per link id + * @adapter: hdd adapter object + * @id: reference dbg id + * @link_id: link id + * + * Return: pointer of wlan_objmgr_vdev or NULL if fail + */ +struct wlan_objmgr_vdev *wlan_key_get_link_vdev(struct hdd_adapter *adapter, + wlan_objmgr_ref_dbgid id, + int link_id); +/** + * wlan_key_put_link_vdev() - put link vdev reference + * @link_vdev: the pointer to link vdev + * @id: reference dbg id + * + * Return: void + */ +void wlan_key_put_link_vdev(struct wlan_objmgr_vdev *link_vdev, + wlan_objmgr_ref_dbgid id); + +#if defined(WLAN_FEATURE_11BE_MLO) +/** + * hdd_tid_to_link_map() - to get t2lm info + * @vdev: Pointer to vdev + * @t2lm: T2LM info + * @dev: Pointer to net_device structure + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_tid_to_link_map(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm, + struct net_device *dev); + +/** + * hdd_mlo_dev_t2lm_notify_link_update() - Send update T2LM info event + * @vdev: Pointer to vdev + * @t2lm: T2LM info + * + * Send update T2LM info event to userspace + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_mlo_dev_t2lm_notify_link_update(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm); +#else +static inline +QDF_STATUS hdd_mlo_dev_t2lm_notify_link_update(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** hdd_set_vdev_phy_mode() - Set vdev phy mode + * @adapter: adapter pointer + * @vendor_phy_mode: vendor phy mode + * + * Return: 0 for success + */ +int hdd_set_vdev_phy_mode(struct hdd_adapter *adapter, + enum qca_wlan_vendor_phy_mode vendor_phy_mode); + +#if defined(WLAN_FEATURE_11BE_MLO) && \ + defined(CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT) +/** + * wlan_hdd_ml_sap_get_peer - Get ML SAP peer + * @vdev: vdev pointer + * @peer_mld: Peer MLD address + * + * Return: Peer object + */ +struct wlan_objmgr_peer * +wlan_hdd_ml_sap_get_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer_mld); +#else +static inline struct wlan_objmgr_peer * +wlan_hdd_ml_sap_get_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer_mld) +{ + return NULL; +} +#endif /* WLAN_FEATURE_11BE_MLO && CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT */ + +/** + * hdd_vdev_send_sta_keep_alive_interval - Send sta keep alive interval to fw + * @link_info: Link info pointer. + * @hdd_ctx: HDD context pointer + * @keep_alive_interval: STA keep alive interval + * + * Return: 0 on success, negative on failure + */ +int hdd_vdev_send_sta_keep_alive_interval(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint16_t keep_alive_interval); + +/** + * wlan_hdd_save_sta_keep_alive_interval() - Save STA keep alive interval + * @adapter: HDD adapter pointer + * @sta_alive_interval: STA keep alive interval + * + * Return: None. + */ +void wlan_hdd_save_sta_keep_alive_interval(struct hdd_adapter *adapter, + uint16_t sta_alive_interval); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfr.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfr.c new file mode 100644 index 0000000000..3c23492984 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cfr.c @@ -0,0 +1,771 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_cfr.c + * + * WLAN Host Device Driver CFR capture Implementation + */ + +#include +#include +#include +#include +#include "wlan_hdd_includes.h" +#include "osif_sync.h" +#include "wlan_hdd_cfr.h" +#include "wlan_cfr_ucfg_api.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_cmn.h" +#include "wlan_policy_mgr_ll_sap.h" + +const struct nla_policy cfr_config_policy[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE] = {.type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK] = {.type = NLA_U64}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_ENTRY] = { + .type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID] = { + .type = NLA_U32}, +}; + +#ifdef WLAN_ENH_CFR_ENABLE +static void +wlan_hdd_transport_mode_cfg(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id, uint32_t pid, + enum qca_wlan_vendor_cfr_data_transport_modes tx_mode) +{ + struct pdev_cfr *pa; + + if (!pdev) { + hdd_err("failed to %s transport mode cb for cfr, pdev is NULL for vdev id %d", + tx_mode ? "register" : "deregister", vdev_id); + return; + } + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (!pa) { + hdd_err("cfr private obj is NULL for vdev id %d", vdev_id); + return; + } + pa->nl_cb.vdev_id = vdev_id; + pa->nl_cb.pid = pid; + if (tx_mode == QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS) + pa->nl_cb.cfr_nl_cb = hdd_cfr_data_send_nl_event; + else + pa->nl_cb.cfr_nl_cb = NULL; +} + +#define DEFAULT_CFR_NSS 0xff +#define DEFAULT_CFR_BW 0xf +static QDF_STATUS +wlan_cfg80211_cfr_set_group_config(struct wlan_objmgr_vdev *vdev, + struct nlattr *tb[]) +{ + struct cfr_wlanconfig_param params = { 0 }; + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER]) { + params.grp_id = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER]); + hdd_debug("group_id %d", params.grp_id); + } + + if (params.grp_id >= HDD_INVALID_GROUP_ID) { + hdd_err("invalid group id"); + return QDF_STATUS_E_INVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA]) { + nla_memcpy(¶ms.ta[0], + tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA], + QDF_MAC_ADDR_SIZE); + hdd_debug("ta " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(¶ms.ta[0])); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK]) { + nla_memcpy(¶ms.ta_mask[0], + tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK], + QDF_MAC_ADDR_SIZE); + hdd_debug("ta_mask " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(¶ms.ta_mask[0])); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA]) { + nla_memcpy(¶ms.ra[0], + tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA], + QDF_MAC_ADDR_SIZE); + hdd_debug("ra " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(¶ms.ra[0])); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK]) { + nla_memcpy(¶ms.ra_mask[0], + tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK], + QDF_MAC_ADDR_SIZE); + hdd_debug("ra_mask " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(¶ms.ra_mask[0])); + } + + if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ta) || + !qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ra) || + !qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ta_mask) || + !qdf_is_macaddr_zero((struct qdf_mac_addr *)¶ms.ra_mask)) { + hdd_debug("set tara config"); + ucfg_cfr_set_tara_config(vdev, ¶ms); + } + + params.nss = DEFAULT_CFR_NSS; + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS]) { + params.nss = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS]); + hdd_debug("nss %d", params.nss); + } + + params.bw = DEFAULT_CFR_BW; + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW]) { + params.bw = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW]); + hdd_debug("bw %d", params.bw); + } + + if (params.nss || params.bw) { + hdd_debug("set bw nss"); + ucfg_cfr_set_bw_nss(vdev, ¶ms); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER]) { + params.expected_mgmt_subtype = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER]); + hdd_debug("expected_mgmt_subtype %d(%x)", + params.expected_mgmt_subtype, + params.expected_mgmt_subtype); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER]) { + params.expected_ctrl_subtype = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER]); + hdd_debug("expected_mgmt_subtype %d(%x)", + params.expected_ctrl_subtype, + params.expected_ctrl_subtype); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER]) { + params.expected_data_subtype = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER]); + hdd_debug("expected_mgmt_subtype %d(%x)", + params.expected_data_subtype, + params.expected_data_subtype); + } + + if (!params.expected_mgmt_subtype || + !params.expected_ctrl_subtype || + !params.expected_data_subtype) { + hdd_debug("set frame type"); + ucfg_cfr_set_frame_type_subtype(vdev, ¶ms); + } + + return QDF_STATUS_SUCCESS; +} + +static enum capture_type convert_vendor_cfr_capture_type( + enum qca_wlan_vendor_cfr_capture_type type) +{ + switch (type) { + case QCA_WLAN_VENDOR_CFR_DIRECT_FTM: + return RCC_DIRECTED_FTM_FILTER; + case QCA_WLAN_VENDOR_CFR_ALL_FTM_ACK: + return RCC_ALL_FTM_ACK_FILTER; + case QCA_WLAN_VENDOR_CFR_DIRECT_NDPA_NDP: + return RCC_DIRECTED_NDPA_NDP_FILTER; + case QCA_WLAN_VENDOR_CFR_TA_RA: + return RCC_TA_RA_FILTER; + case QCA_WLAN_VENDOR_CFR_ALL_PACKET: + return RCC_NDPA_NDP_ALL_FILTER; + default: + hdd_err("invalid capture type"); + return RCC_DIS_ALL_MODE; + } +} + +static int +wlan_cfg80211_cfr_set_config(struct wlan_objmgr_vdev *vdev, + struct nlattr *tb[]) +{ + struct nlattr *group[QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1]; + struct nlattr *group_list; + struct cfr_wlanconfig_param params = { 0 }; + enum capture_type type; + enum qca_wlan_vendor_cfr_capture_type vendor_capture_type; + int rem = 0; + int maxtype; + int attr; + uint64_t ul_mu_user_mask = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION]) { + params.cap_dur = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION]); + ucfg_cfr_set_capture_duration(vdev, ¶ms); + hdd_debug("params.cap_dur %d", params.cap_dur); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL]) { + params.cap_intvl = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL]); + ucfg_cfr_set_capture_interval(vdev, ¶ms); + hdd_debug("params.cap_intvl %d", params.cap_intvl); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE]) { + vendor_capture_type = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE]); + if ((vendor_capture_type < QCA_WLAN_VENDOR_CFR_DIRECT_FTM) || + (vendor_capture_type > QCA_WLAN_VENDOR_CFR_ALL_PACKET)) { + hdd_err_rl("invalid capture type %d", + vendor_capture_type); + return -EINVAL; + } + type = convert_vendor_cfr_capture_type(vendor_capture_type); + ucfg_cfr_set_rcc_mode(vdev, type, 1); + hdd_debug("type %d", type); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK]) { + ul_mu_user_mask = nla_get_u64(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK]); + hdd_debug("ul_mu_user_mask_lower %d", + params.ul_mu_user_mask_lower); + } + + if (ul_mu_user_mask) { + params.ul_mu_user_mask_lower = + (uint32_t)(ul_mu_user_mask & 0xffffffff); + params.ul_mu_user_mask_lower = + (uint32_t)(ul_mu_user_mask >> 32); + hdd_debug("set ul mu user mask"); + ucfg_cfr_set_ul_mu_user_mask(vdev, ¶ms); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT]) { + params.freeze_tlv_delay_cnt_thr = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT]); + if (params.freeze_tlv_delay_cnt_thr) { + params.freeze_tlv_delay_cnt_en = 1; + ucfg_cfr_set_freeze_tlv_delay_cnt(vdev, ¶ms); + hdd_debug("freeze_tlv_delay_cnt_thr %d", + params.freeze_tlv_delay_cnt_thr); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE]) { + maxtype = QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX; + attr = QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE; + nla_for_each_nested(group_list, tb[attr], rem) { + if (wlan_cfg80211_nla_parse(group, maxtype, + nla_data(group_list), + nla_len(group_list), + cfr_config_policy)) { + hdd_err("nla_parse failed for cfr config group"); + return -EINVAL; + } + wlan_cfg80211_cfr_set_group_config(vdev, group); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE]) { + uint8_t transport_mode = 0xff; + uint32_t pid = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID]) + pid = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_RECEIVER_PID]); + else + hdd_debug("No PID received"); + + transport_mode = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_DATA_TRANSPORT_MODE]); + + hdd_debug("tx mode attr %d, pid %d", transport_mode, pid); + if (transport_mode == QCA_WLAN_VENDOR_CFR_DATA_RELAY_FS || + transport_mode == QCA_WLAN_VENDOR_CFR_DATA_NETLINK_EVENTS) { + wlan_hdd_transport_mode_cfg(vdev->vdev_objmgr.wlan_pdev, + vdev->vdev_objmgr.vdev_id, + pid, transport_mode); + } else { + hdd_debug("invalid transport mode %d for vdev id %d", + transport_mode, vdev->vdev_objmgr.vdev_id); + } + } + + return 0; +} + +static QDF_STATUS hdd_stop_enh_cfr(struct wlan_objmgr_vdev *vdev) +{ + if (!ucfg_cfr_get_rcc_enabled(vdev)) + return QDF_STATUS_SUCCESS; + + hdd_debug("cleanup rcc mode"); + wlan_objmgr_vdev_try_get_ref(vdev, WLAN_CFR_ID); + ucfg_cfr_set_rcc_mode(vdev, RCC_DIS_ALL_MODE, 0); + ucfg_cfr_subscribe_ppdu_desc(wlan_vdev_get_pdev(vdev), + false); + ucfg_cfr_committed_rcc_config(vdev); + ucfg_cfr_stop_indication(vdev); + ucfg_cfr_suspend(wlan_vdev_get_pdev(vdev)); + hdd_debug("stop indication done"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_cfr_disconnect(struct wlan_objmgr_vdev *vdev) +{ + return hdd_stop_enh_cfr(vdev); +} + +static int +wlan_cfg80211_peer_enh_cfr_capture(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct cfr_wlanconfig_param params = { 0 }; + struct wlan_objmgr_vdev *vdev; + bool is_start_capture = false; + int ret = 0; + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]) { + is_start_capture = nla_get_flag(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]); + } + + if (is_start_capture && + !tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP]) { + hdd_err("Invalid group bitmap"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CFR_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + + if (is_start_capture) { + ret = wlan_cfg80211_cfr_set_config(vdev, tb); + if (ret) { + hdd_err("set config failed"); + goto out; + } + params.en_cfg = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP]); + hdd_debug("params.en_cfg %d", params.en_cfg); + ucfg_cfr_set_en_bitmap(vdev, ¶ms); + ucfg_cfr_resume(wlan_vdev_get_pdev(vdev)); + ucfg_cfr_subscribe_ppdu_desc(wlan_vdev_get_pdev(vdev), + true); + ucfg_cfr_committed_rcc_config(vdev); + } else { + hdd_stop_enh_cfr(vdev); + } +out: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return ret; +} +#else +static int +wlan_cfg80211_peer_enh_cfr_capture(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return 0; +} +#endif + +#ifdef WLAN_CFR_ADRASTEA +static QDF_STATUS +wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct cfr_capture_params params = { 0 }; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + struct qdf_mac_addr peer_addr; + bool is_start_capture = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!tb[QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR]) { + hdd_err("peer mac addr not given"); + return QDF_STATUS_E_INVAL; + } + + nla_memcpy(peer_addr.bytes, tb[QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR], + QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]) { + is_start_capture = nla_get_flag(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]); + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CFR_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + hdd_err("failed to get pdev"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("Failed to get psoc"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_addr.bytes, WLAN_CFR_ID); + if (!peer) { + hdd_err("No peer object found"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return QDF_STATUS_E_INVAL; + } + + if (is_start_capture) { + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY]) { + params.period = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY]); + hdd_debug("params.periodicity %d", params.period); + /* Set the periodic CFR */ + if (params.period) + ucfg_cfr_set_timer(pdev, params.period); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD]) { + params.method = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD]); + /* Adrastea supports only QOS NULL METHOD */ + if (params.method != + QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL) { + hdd_err_rl("invalid capture method %d", + params.method); + status = QDF_STATUS_E_INVAL; + goto exit; + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH]) { + params.bandwidth = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH]); + /* Adrastea supports only 20Mhz bandwidth CFR capture */ + if (params.bandwidth != NL80211_CHAN_WIDTH_20_NOHT) { + hdd_err_rl("invalid capture bandwidth %d", + params.bandwidth); + status = QDF_STATUS_E_INVAL; + goto exit; + } + } + ucfg_cfr_start_capture(pdev, peer, ¶ms); + } else { + /* Disable the periodic CFR if enabled */ + if (ucfg_cfr_get_timer(pdev)) + ucfg_cfr_set_timer(pdev, 0); + + /* Disable the peer CFR capture */ + ucfg_cfr_stop_capture(pdev, peer); + } +exit: + wlan_objmgr_peer_release_ref(peer, WLAN_CFR_ID); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + + return status; +} +#elif defined(WLAN_CFR_DBR) +static enum +phy_ch_width convert_capture_bw(enum nl80211_chan_width capture_bw) +{ + switch (capture_bw) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + return CH_WIDTH_20MHZ; + case NL80211_CHAN_WIDTH_40: + return CH_WIDTH_40MHZ; + case NL80211_CHAN_WIDTH_80: + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_80P80: + return CH_WIDTH_80P80MHZ; + case NL80211_CHAN_WIDTH_160: + return CH_WIDTH_160MHZ; + case NL80211_CHAN_WIDTH_5: + return CH_WIDTH_5MHZ; + case NL80211_CHAN_WIDTH_10: + return CH_WIDTH_10MHZ; + default: + hdd_err("invalid capture bw"); + return CH_WIDTH_INVALID; + } +} + +static QDF_STATUS +wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct cfr_capture_params params = { 0 }; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + struct qdf_mac_addr peer_addr; + bool is_start_capture = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int id; + + id = QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR; + if (!tb[id]) { + hdd_err("peer mac addr not given"); + return QDF_STATUS_E_INVAL; + } + + nla_memcpy(peer_addr.bytes, tb[id], + QDF_MAC_ADDR_SIZE); + + id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE; + if (tb[id]) + is_start_capture = nla_get_flag(tb[id]); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CFR_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + hdd_err("failed to get pdev"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("Failed to get psoc"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_addr.bytes, WLAN_CFR_ID); + if (!peer) { + hdd_err("No peer object found"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + return QDF_STATUS_E_INVAL; + } + + if (is_start_capture) { + id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY; + if (tb[id]) { + params.period = nla_get_u32(tb[id]); + hdd_debug("params.periodicity %d", params.period); + /* Set the periodic CFR */ + if (params.period) + ucfg_cfr_set_timer(pdev, params.period); + } + id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD; + if (tb[id]) { + params.method = nla_get_u8(tb[id]); + /* Adrastea supports only QOS NULL METHOD */ + if (params.method != + QCA_WLAN_VENDOR_CFR_METHOD_QOS_NULL) { + hdd_err_rl("invalid capture method %d", + params.method); + status = QDF_STATUS_E_INVAL; + goto exit; + } + } + id = QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH; + if (tb[id]) { + params.bandwidth = nla_get_u8(tb[id]); + params.bandwidth = convert_capture_bw(params.bandwidth); + if (params.bandwidth > NL80211_CHAN_WIDTH_80) { + hdd_err_rl("invalid capture bandwidth %d", + params.bandwidth); + status = QDF_STATUS_E_INVAL; + goto exit; + } + } + ucfg_cfr_start_capture(pdev, peer, ¶ms); + } else { + /* Disable the periodic CFR if enabled */ + if (ucfg_cfr_get_timer(pdev)) + ucfg_cfr_set_timer(pdev, 0); + + /* Disable the peer CFR capture */ + ucfg_cfr_stop_capture(pdev, peer); + ucfg_cfr_stop_indication(vdev); + } +exit: + wlan_objmgr_peer_release_ref(peer, WLAN_CFR_ID); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CFR_ID); + + return status; +} + +#else +static QDF_STATUS +wlan_cfg80211_peer_cfr_capture_cfg_adrastea(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +static int +wlan_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, + struct hdd_adapter *adapter, + const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1]; + uint8_t version = 0; + QDF_STATUS status; + + if (wlan_cfg80211_nla_parse( + tb, + QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX, + data, + data_len, + cfr_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION]) { + version = nla_get_u8(tb[ + QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION]); + hdd_debug("version %d", version); + if (version == LEGACY_CFR_VERSION) { + status = wlan_cfg80211_peer_cfr_capture_cfg_adrastea( + adapter, tb); + return qdf_status_to_os_return(status); + } else if (version != ENHANCED_CFR_VERSION) { + hdd_err("unsupported version"); + return -EFAULT; + } + } + + return wlan_cfg80211_peer_enh_cfr_capture(adapter, tb); +} + +static int __wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + uint8_t ll_lt_sap_vdev_id; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ll_lt_sap_vdev_id = + wlan_policy_mgr_get_ll_lt_sap_vdev_id(hdd_ctx->psoc); + if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) { + hdd_info_rl("LL_LT_SAP vdev %d present, cfr cmd not allowed", + ll_lt_sap_vdev_id); + return -EINVAL; + } + + wlan_cfg80211_peer_cfr_capture_cfg(wiphy, adapter, + data, data_len); + + hdd_exit(); + + return ret; +} + +int wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_peer_cfr_capture_cfg(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_api.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_api.h new file mode 100644 index 0000000000..140dae7d32 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_api.h @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_cm_api.h + * + * WLAN host device driver connect/disconnect functions declaration + */ + +#ifndef __WLAN_HDD_CM_API_H +#define __WLAN_HDD_CM_API_H + +#include +#include "wlan_cm_public_struct.h" +#include "osif_cm_util.h" +#include "wlan_cm_roam_ucfg_api.h" + +/** + * wlan_hdd_cm_connect() - cfg80211 connect api + * @wiphy: Pointer to wiphy + * @ndev: Pointer to network device + * @req: Pointer to cfg80211 connect request + * + * This function is used to issue connect request to connection manager + * + * Context: Any context. + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cm_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req); + +/** + * wlan_hdd_cm_issue_disconnect() - initiate disconnect from osif + * @link_info: Link info pointer in HDD adapter + * @reason: Disconnect reason code + * @sync: true if wait for disconnect to complete is required. for the + * supplicant initiated disconnect or during vdev delete/change interface + * sync should be true. + * + * This function is used to issue disconnect request to connection manager + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_hdd_cm_issue_disconnect(struct wlan_hdd_link_info *link_info, + enum wlan_reason_code reason, bool sync); + +/** + * wlan_hdd_cm_disconnect() - cfg80211 disconnect api + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @reason: Disconnect reason code + * + * This function is used to issue disconnect request to connection manager + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cm_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason); + +QDF_STATUS hdd_cm_disconnect_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp, + enum osif_cb_type type); + +QDF_STATUS hdd_cm_netif_queue_control(struct wlan_objmgr_vdev *vdev, + enum netif_action_type action, + enum netif_reason_type reason); + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * hdd_cm_connect_active_notify() - Callback to HDD on connection request + * becomes active. + * @vdev_id: VDEV ID on which connection became active. + * + * The callback to make sure connection related fields are properly set + * from HDD. + * + * Returns: void + */ +void hdd_cm_connect_active_notify(uint8_t vdev_id); +#else +static inline void hdd_cm_connect_active_notify(uint8_t vdev_id) +{ +} +#endif +QDF_STATUS hdd_cm_connect_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp, + enum osif_cb_type type); + +/** + * hdd_cm_send_vdev_keys() - send vdev keys + * @vdev: Pointer to vdev + * @key_index: key index value + * @pairwise: pairwise boolean value + * @cipher_type: cipher type enum value + * + * This function is used to send vdev keys + * + * Context: Any context. + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_send_vdev_keys(struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + enum wlan_crypto_cipher_type cipher_type); + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +/** + * hdd_cm_get_vendor_handoff_params() - to get vendor handoff params from fw + * @psoc: Pointer to psoc object + * @vendor_handoff_context: Pointer to vendor handoff event rsp + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_cm_get_vendor_handoff_params(struct wlan_objmgr_psoc *psoc, + void *vendor_handoff_context); + +/** + * hdd_cm_get_handoff_param() - send get vendor handoff param request to fw + * @psoc: psoc common object + * @vdev_id: vdev id + * @param_id: param id from enum vendor_control_roam_param + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_get_handoff_param(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum vendor_control_roam_param param_id); +#endif + +/** + * hdd_cm_napi_serialize_control() - NAPI serialize hdd cb + * @action: serialize or de-serialize NAPI activities + * + * This function is for napi serialize + * + * Return: qdf status + */ +QDF_STATUS hdd_cm_napi_serialize_control(bool action); + +#ifdef WLAN_BOOST_CPU_FREQ_IN_ROAM +/** + * hdd_cm_perfd_set_cpufreq() - API to set CPU min freq + * @action: set or reset the CPU freq + * + * This function sets/resets the CPU min frequency + * by sending netlink msg to cnss-daemon, which will + * communicate to perf daemon to set/reset CPU freq. + * + * Return: qdf status + */ +QDF_STATUS hdd_cm_perfd_set_cpufreq(bool action); +#else +static inline +QDF_STATUS hdd_cm_perfd_set_cpufreq(bool action) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +/** + * hdd_cm_save_gtk() - save gtk api + * @vdev: Pointer to vdev + * @rsp: Pointer to connect rsp + * + * This function is used to save gtk in legacy mode + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_save_gtk(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); + +/** + * hdd_cm_set_hlp_data() - api to set hlp data for dhcp + * @dev: pointer to net device + * @vdev: Pointer to vdev + * @rsp: Pointer to connect rsp + * + * This function is used to set hlp data for dhcp in legacy mode + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_set_hlp_data(struct net_device *dev, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp); +#endif + +#ifdef WLAN_FEATURE_PREAUTH_ENABLE +/** + * hdd_cm_ft_preauth_complete() - send fast transition event + * @vdev: Pointer to vdev + * @rsp: Pointer to preauth rsp + * + * This function is used to send fast transition event in legacy mode + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_ft_preauth_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp); + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_cm_cckm_preauth_complete() - send cckm preauth indication to + * the supplicant via wireless custom event + * @vdev: Pointer to vdev + * @rsp: Pointer to preauth rsp + * + * This function is used to send cckm preauth indication to + * the supplicant via wireless custom event in legacy mode + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_cckm_preauth_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp); +#endif +#endif + +#ifdef WLAN_FEATURE_MSCS +/** + * reset_mscs_params() - Reset mscs parameters + * @link_info: pointer to link_info struct in adapter + * + * Reset mscs parameters whils disconnection + * + * Return: None + */ +void reset_mscs_params(struct wlan_hdd_link_info *link_info); +#else +static inline +void reset_mscs_params(struct wlan_hdd_link_info *link_info) +{ + return; +} +#endif + +/** + * hdd_handle_disassociation_event() - Handle disassociation event + * @link_info: Link info pointer in HDD adapter + * @peer_macaddr: Pointer to peer mac address + * + * Return: None + */ +void hdd_handle_disassociation_event(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *peer_macaddr); + +/** + * __hdd_cm_disconnect_handler_pre_user_update() - Handle disconnect indication + * before updating to user space + * @link_info: Link info pointer in HDD adapter + * + * Return: None + */ +void +__hdd_cm_disconnect_handler_pre_user_update(struct wlan_hdd_link_info *link_info); + +/** + * __hdd_cm_disconnect_handler_post_user_update() - Handle disconnect indication + * after updating to user space + * @link_info: Link info pointer in HDD adapter + * @vdev: vdev ptr + * @source: Disconnect source + * + * Return: None + */ +void +__hdd_cm_disconnect_handler_post_user_update(struct wlan_hdd_link_info *link_info, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_source source); + +/** + * hdd_cm_set_peer_authenticate() - set peer as authenticated + * @link_info: Link info pointer in HDD adapter + * @bssid: bssid of the connection + * @is_auth_required: is upper layer authenticatoin required + * + * Return: QDF_STATUS enumeration + */ +void hdd_cm_set_peer_authenticate(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *bssid, + bool is_auth_required); + +/** + * hdd_cm_update_rssi_snr_by_bssid() - update rsi and snr into adapter + * @link_info: Link info pointer in HDD adapter + * + * Return: None + */ +void hdd_cm_update_rssi_snr_by_bssid(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_handle_assoc_event() - Send disassociation indication to oem + * app + * @vdev: Pointer to adapter + * @peer_mac: Pointer to peer mac address + * + * Return: None + */ +void hdd_cm_handle_assoc_event(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac); + +/** + * hdd_cm_netif_queue_enable() - Enable the network queue for a + * particular adapter. + * @adapter: pointer to the adapter structure + * + * This function schedules a work to update the netdev features + * and enable the network queue if the feature "disable checksum/tso + * for legacy connections" is enabled via INI. If not, it will + * retain the existing behavior by just enabling the network queues. + * + * Returns: none + */ +void hdd_cm_netif_queue_enable(struct hdd_adapter *adapter); + +/** + * hdd_cm_clear_pmf_stats() - Clear pmf stats + * @adapter: pointer to the adapter structure + * + * Returns: None + */ +void hdd_cm_clear_pmf_stats(struct hdd_adapter *adapter); + +/** + * hdd_cm_save_connect_status() - Save connect status + * @link_info: Link info pointer in HDD adapter + * @reason_code: IEE80211 wlan status code + * + * Returns: None + */ +void hdd_cm_save_connect_status(struct wlan_hdd_link_info *link_info, + uint32_t reason_code); + +/** + * hdd_cm_is_vdev_associated() - Checks if vdev is associated or not + * @link_info: pointer to the link info structure + * + * Returns: True if vdev is associated else false + */ +bool hdd_cm_is_vdev_associated(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_is_vdev_connected() - Checks if vdev is connected or not + * @link_info: pointer to the link_info structure + * + * Returns: True if vdev is connected else false + */ +bool hdd_cm_is_vdev_connected(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_is_connecting() - Function to check connection in progress + * @link_info: pointer to the link_info structure + * + * Return: true if connecting, false otherwise + */ +bool hdd_cm_is_connecting(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_is_disconnected() - Function to check if vdev is disconnected or not + * @link_info: pointer to the link_info structure + * + * Return: true if disconnected, false otherwise + */ +bool hdd_cm_is_disconnected(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_is_vdev_roaming() - Function to check roaming in progress + * @link_info: pointer to the link_info structure + * + * Return: true if roaming, false otherwise + */ +bool hdd_cm_is_vdev_roaming(struct wlan_hdd_link_info *link_info); + +/** + * hdd_cm_get_scan_ie_params() - to get scan ie params + * @vdev: Pointer to vdev object + * @scan_ie: pointer to scan ie element struct + * @dot11mode_filter: Pointer to dot11mode_filter enum + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_cm_get_scan_ie_params(struct wlan_objmgr_vdev *vdev, + struct element_info *scan_ie, + enum dot11_mode_filter *dot11mode_filter); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * hdd_cm_save_connected_links_info() - Update connection info to station + * context. + * @self_mac: Self MAC address. + * @bssid: BSSID of link. + * @link_id: IEEE link id. + * + * It searches for link info pointer matching with @self_mac and updates + * the BSSID and link ID fields in station context's connection info. + * This will help to retrieve the link information using IEEE link ID or + * BSSID thereafter. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_cm_save_connected_links_info(struct qdf_mac_addr *self_mac, + struct qdf_mac_addr *bssid, + int32_t link_id); + +/** + * hdd_cm_set_ieee_link_id() - Set IEEE link ID in station context conn info. + * @link_info: Link info pointer in HDD adapter + * @link_id: IEEE link ID + * + * Sets IEEE link ID in connection info of @link_info's station context. + * + * Return: void + */ +void +hdd_cm_set_ieee_link_id(struct wlan_hdd_link_info *link_info, uint8_t link_id); + +/** + * hdd_cm_clear_ieee_link_id() - Clear IEEE link ID in station context + * conn info. + * @link_info: Link info pointer in HDD adapter + * + * Clear IEEE link ID in connection info of @link_info's station context. + * + * Return: void + */ +void hdd_cm_clear_ieee_link_id(struct wlan_hdd_link_info *link_info); +#else +static inline void +hdd_cm_set_ieee_link_id(struct wlan_hdd_link_info *link_info, uint8_t link_id) +{ +} + +static inline void +hdd_cm_clear_ieee_link_id(struct wlan_hdd_link_info *link_info) +{ +} + +static inline +QDF_STATUS hdd_cm_save_connected_links_info(struct qdf_mac_addr *self_mac, + struct qdf_mac_addr *bssid, + int32_t link_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_11BE_MLO */ +#endif /* __WLAN_HDD_CM_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_connect.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_connect.c new file mode 100644 index 0000000000..2b700ef0da --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_connect.c @@ -0,0 +1,2414 @@ +/* + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: hdd_cm_connect.c + * + * WLAN Host Device Driver connect APIs implementation + * + */ + +#include "wlan_hdd_main.h" +#include +#include "wlan_hdd_cm_api.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_connectivity_logging.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_crypto_global_api.h" +#include "wlan_vdev_mgr_ucfg_api.h" +#include "wlan_hdd_bootup_marker.h" +#include "sme_qos_internal.h" +#include "wlan_dlm_ucfg_api.h" +#include "wlan_hdd_scan.h" +#include "wlan_osif_priv.h" +#include +#include +#include "wlan_roam_debug.h" +#include +#include "wlan_hdd_hostapd.h" +#include +#include +#include "wlan_osif_features.h" +#include "wlan_osif_request_manager.h" +#include +#include "wlan_psoc_mlme_ucfg_api.h" +#include "wlan_action_oui_ucfg_api.h" + +bool hdd_cm_is_vdev_associated(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool is_vdev_active; + enum QDF_OPMODE opmode; + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (link_info->adapter->device_mode == QDF_NDI_MODE) + return (sta_ctx->conn_info.conn_state == + eConnectionState_NdiConnected); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) + return false; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + return false; + } + is_vdev_active = ucfg_cm_is_vdev_active(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + + return is_vdev_active; +} + +bool hdd_cm_is_vdev_connected(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool is_vdev_connected; + struct hdd_station_ctx *sta_ctx; + enum QDF_OPMODE opmode = link_info->adapter->device_mode; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (opmode == QDF_NDI_MODE) + return (sta_ctx->conn_info.conn_state == + eConnectionState_NdiConnected); + + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) + return false; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) + return false; + + is_vdev_connected = ucfg_cm_is_vdev_connected(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + + return is_vdev_connected; +} + +bool hdd_cm_is_connecting(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool is_vdev_connecting; + enum QDF_OPMODE opmode; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) + return false; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + return false; + } + is_vdev_connecting = ucfg_cm_is_vdev_connecting(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + + return is_vdev_connecting; +} + +bool hdd_cm_is_disconnected(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool is_vdev_disconnected; + enum QDF_OPMODE opmode; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) + return false; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + return false; + } + is_vdev_disconnected = ucfg_cm_is_vdev_disconnected(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + + return is_vdev_disconnected; +} + +bool hdd_cm_is_vdev_roaming(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool is_vdev_roaming; + enum QDF_OPMODE opmode; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) + return false; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + return false; + } + is_vdev_roaming = ucfg_cm_is_vdev_roaming(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + + return is_vdev_roaming; +} + +void hdd_cm_set_peer_authenticate(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *bssid, + bool is_auth_required) +{ + hdd_debug("sta: " QDF_MAC_ADDR_FMT "Changing TL state to %s", + QDF_MAC_ADDR_REF(bssid->bytes), + is_auth_required ? "CONNECTED" : "AUTHENTICATED"); + + hdd_change_peer_state(link_info, bssid->bytes, + is_auth_required ? + OL_TXRX_PEER_STATE_CONN : + OL_TXRX_PEER_STATE_AUTH); + hdd_conn_set_authenticated(link_info, !is_auth_required); + hdd_objmgr_set_peer_mlme_auth_state(link_info->vdev, + !is_auth_required); +} + +void hdd_cm_update_rssi_snr_by_bssid(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + int8_t snr = 0; + struct hdd_adapter *adapter = link_info->adapter; + mac_handle_t mac_handle; + + if (!adapter) { + hdd_err_rl("null hdd_adapter pointer"); + return; + } + + mac_handle = hdd_adapter_get_mac_handle(adapter); + + if (!mac_handle) { + hdd_err_rl("null mac_handle pointer"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + hdd_get_rssi_snr_by_bssid(mac_handle, + sta_ctx->conn_info.bssid.bytes, + &link_info->rssi, &snr); + + /* If RSSi is reported as positive then it is invalid */ + if (link_info->rssi > 0) { + hdd_debug_rl("RSSI invalid %d", link_info->rssi); + link_info->rssi = 0; + } + + hdd_debug("snr: %d, rssi: %d", snr, link_info->rssi); + + sta_ctx->conn_info.signal = link_info->rssi; + sta_ctx->conn_info.noise = sta_ctx->conn_info.signal - snr; + sta_ctx->cache_conn_info.signal = sta_ctx->conn_info.signal; + sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise; +} + +void hdd_cm_handle_assoc_event(struct wlan_objmgr_vdev *vdev, uint8_t *peer_mac) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + int ret; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + ret = hdd_objmgr_set_peer_mlme_state(link_info->vdev, + WLAN_ASSOC_STATE); + if (ret) + hdd_err("Peer object " QDF_MAC_ADDR_FMT " fail to set associated state", + QDF_MAC_ADDR_REF(peer_mac)); + ucfg_dp_add_latency_critical_client(vdev, + hdd_convert_cfgdot11mode_to_80211mode( + sta_ctx->conn_info.dot11mode)); + + ucfg_dp_bus_bw_compute_prev_txrx_stats(vdev); + ucfg_dp_bus_bw_compute_timer_start(hdd_ctx->psoc); + + if (ucfg_pkt_capture_get_pktcap_mode(hdd_ctx->psoc)) + ucfg_pkt_capture_record_channel(link_info->vdev); +} + +/** + * hdd_cm_netif_features_update_required() - Check if feature update + * is required + * @adapter: pointer to the adapter structure + * Returns: true if the connection is legacy and TSO and Checksum offload + * enabled or if the connection is not latency and TSO and Checksum + * offload are not enabled, false otherwise + */ +static bool hdd_cm_netif_features_update_required(struct hdd_adapter *adapter) +{ + bool is_legacy_connection = hdd_is_legacy_connection(adapter->deflink); + + hdd_debug("Legacy Connection: %d, TSO_CSUM Feature Enabled:%d", + is_legacy_connection, adapter->tso_csum_feature_enabled); + + if (adapter->tso_csum_feature_enabled && is_legacy_connection) + return true; + + if (!adapter->tso_csum_feature_enabled && !is_legacy_connection) + return true; + + return false; +} + +void hdd_cm_netif_queue_enable(struct hdd_adapter *adapter) +{ + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (cdp_cfg_get(soc, cfg_dp_disable_legacy_mode_csum_offload) && + hdd_cm_netif_features_update_required(adapter)) { + hdd_adapter_ops_record_event(hdd_ctx, + WLAN_HDD_ADAPTER_OPS_WORK_POST, + adapter->deflink->vdev_id); + qdf_queue_work(0, hdd_ctx->adapter_ops_wq, + &adapter->netdev_features_update_work); + } + + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); +} + +void hdd_cm_clear_pmf_stats(struct hdd_adapter *adapter) +{ + qdf_mem_zero(&adapter->deflink->hdd_stats.hdd_pmf_stats, + sizeof(adapter->deflink->hdd_stats.hdd_pmf_stats)); +} + +void hdd_cm_save_connect_status(struct wlan_hdd_link_info *link_info, + uint32_t reason_code) +{ + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + link_info->adapter->connect_req_status = reason_code; + hdd_sta_ctx->conn_info.assoc_status_code = reason_code; + hdd_sta_ctx->cache_conn_info.assoc_status_code = reason_code; +} + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS hdd_cm_save_connected_links_info(struct qdf_mac_addr *self_mac, + struct qdf_mac_addr *bssid, + int32_t link_id) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD context NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_link_addr(hdd_ctx, self_mac); + if (!link_info) { + hdd_err("No link info with MAC: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(self_mac->bytes)); + return QDF_STATUS_E_INVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + hdd_cm_set_ieee_link_id(link_info, link_id); + qdf_copy_macaddr(&sta_ctx->conn_info.bssid, bssid); + return QDF_STATUS_SUCCESS; +} + +void +hdd_cm_set_ieee_link_id(struct wlan_hdd_link_info *link_info, uint8_t link_id) +{ + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + hdd_debug("old_link_id:%d new_link_id:%d", + sta_ctx->conn_info.ieee_link_id, link_id); + sta_ctx->conn_info.ieee_link_id = link_id; +} + +void +hdd_cm_clear_ieee_link_id(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + hdd_debug("clear link id:%d", sta_ctx->conn_info.ieee_link_id); + sta_ctx->conn_info.ieee_link_id = WLAN_INVALID_LINK_ID; +} +#endif + +#ifdef FEATURE_WLAN_WAPI +static bool hdd_cm_is_wapi_sta(enum csr_akm_type auth_type) +{ + if (auth_type == eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE || + auth_type == eCSR_AUTH_TYPE_WAPI_WAI_PSK) + return true; + else + return false; +} +#else +static inline bool hdd_cm_is_wapi_sta(enum csr_akm_type auth_type) +{ + return false; +} +#endif + +static void hdd_update_scan_ie_for_connect(struct hdd_adapter *adapter, + struct osif_connect_params *params) +{ + if (adapter->device_mode == QDF_P2P_CLIENT_MODE) { + params->scan_ie.ptr = + &adapter->scan_info.scan_add_ie.addIEdata[0]; + params->scan_ie.len = adapter->scan_info.scan_add_ie.length; + } else if (adapter->scan_info.default_scan_ies) { + params->scan_ie.ptr = adapter->scan_info.default_scan_ies; + params->scan_ie.len = adapter->scan_info.default_scan_ies_len; + } else if (adapter->scan_info.scan_add_ie.length) { + params->scan_ie.ptr = adapter->scan_info.scan_add_ie.addIEdata; + params->scan_ie.len = adapter->scan_info.scan_add_ie.length; + } +} + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)) || \ + defined(CFG80211_11BE_BASIC)) && \ + defined(WLAN_FEATURE_11BE) +/** + * hdd_update_action_oui_for_connect() - Update Action OUI for 802.11be AP + * @hdd_ctx: hdd context + * @req: connect request parameter + * + * If user sets flag ASSOC_REQ_DISABLE_EHT in connect request, driver + * will send action oui "ffffff 00 01" to host mlme and also firmware + * for action id ACTION_OUI_11BE_OUI_ALLOW, so that all the AP will + * be not matched with this OUI and 802.11be mode will not be allowed, + * possibly downgrade to 11ax will happen. + * If user doesn't set ASSOC_REQ_DISABLE_EHT, driver/firmware will + * recover to default INI setting. + * + * Returns: void + */ +static void +hdd_update_action_oui_for_connect(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req) +{ + QDF_STATUS status; + uint8_t *str; + bool usr_disable_eht; + + if (!ucfg_action_oui_enabled(hdd_ctx->psoc)) + return; + + usr_disable_eht = ucfg_mlme_get_usr_disable_sta_eht(hdd_ctx->psoc); + if (req->flags & ASSOC_REQ_DISABLE_EHT || + !(req->flags & CONNECT_REQ_MLO_SUPPORT)) { + if (usr_disable_eht) { + hdd_debug("user eht is disabled already"); + return; + } + status = ucfg_action_oui_cleanup( + hdd_ctx->psoc, ACTION_OUI_11BE_OUI_ALLOW); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to cleanup oui id %d", + ACTION_OUI_11BE_OUI_ALLOW); + return; + } + status = ucfg_action_oui_parse(hdd_ctx->psoc, + ACTION_OUI_INVALID, + ACTION_OUI_11BE_OUI_ALLOW); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to parse action_oui str for id %d", + ACTION_OUI_11BE_OUI_ALLOW); + return; + } + } else { + if (!usr_disable_eht) { + hdd_debug("user eht is enabled already"); + return; + } + status = ucfg_action_oui_cleanup(hdd_ctx->psoc, + ACTION_OUI_11BE_OUI_ALLOW); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to cleanup oui id %d", + ACTION_OUI_11BE_OUI_ALLOW); + return; + } + str = ucfg_action_oui_get_config(hdd_ctx->psoc, + ACTION_OUI_11BE_OUI_ALLOW); + if (!qdf_str_len(str)) + goto send_oui; + + status = ucfg_action_oui_parse(hdd_ctx->psoc, + str, ACTION_OUI_11BE_OUI_ALLOW); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to parse action_oui str for id %d", + ACTION_OUI_11BE_OUI_ALLOW); + return; + } + } + +send_oui: + status = ucfg_action_oui_send_by_id(hdd_ctx->psoc, + ACTION_OUI_11BE_OUI_ALLOW); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send oui id %d", ACTION_OUI_11BE_OUI_ALLOW); + return; + } + ucfg_mlme_set_usr_disable_sta_eht(hdd_ctx->psoc, !usr_disable_eht); +} +#else +static void +hdd_update_action_oui_for_connect(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +static inline bool +hdd_config_is_dot11mode_11be_only(struct hdd_config *config) +{ + if (config->dot11Mode == eHDD_DOT11_MODE_11be_ONLY) + return true; + else + return false; +} +#else +static inline bool +hdd_config_is_dot11mode_11be_only(struct hdd_config *config) +{ + return false; +} +#endif + +/** + * hdd_get_dot11mode_filter() - Get dot11 mode filter + * @hdd_ctx: HDD context + * + * This function is used to get the dot11 mode filter + * + * Context: Any Context. + * Return: dot11_mode_filter + */ +static enum dot11_mode_filter +hdd_get_dot11mode_filter(struct hdd_context *hdd_ctx) +{ + struct hdd_config *config = hdd_ctx->config; + + if (config->dot11Mode == eHDD_DOT11_MODE_11n_ONLY) + return ALLOW_11N_ONLY; + else if (config->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) + return ALLOW_11AC_ONLY; + else if (config->dot11Mode == eHDD_DOT11_MODE_11ax_ONLY) + return ALLOW_11AX_ONLY; + else if (hdd_config_is_dot11mode_11be_only(config)) + return ALLOW_11BE_ONLY; + else + return ALLOW_ALL; +} + +/** + * hdd_get_sap_adapter_of_dfs - Get sap adapter on dfs channel + * @hdd_ctx: HDD context + * + * This function is used to get the sap adapter on dfs channel. + * + * Return: pointer to adapter or null + */ +static struct hdd_adapter * +hdd_get_sap_adapter_of_dfs(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + struct wlan_channel *chan; + struct ch_params ch_params = {0}; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_SAP_MODE) + goto loop_next; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + continue; + + /* + * sap is not in started state and also not under doing + * CAC, so it is fine to go ahead with sta. + */ + if (!test_bit(SOFTAP_BSS_STARTED, + &link_info->link_flags) && + hdd_ctx->dev_dfs_cac_status != DFS_CAC_IN_PROGRESS) + continue; + + wlan_objmgr_vdev_get_ref(link_info->vdev, + WLAN_HDD_ID_OBJ_MGR); + chan = wlan_vdev_get_active_channel(link_info->vdev); + if (!chan) { + hdd_debug("Can not get active channel"); + wlan_objmgr_vdev_release_ref(link_info->vdev, + WLAN_HDD_ID_OBJ_MGR); + continue; + } + + wlan_objmgr_vdev_release_ref(link_info->vdev, + WLAN_HDD_ID_OBJ_MGR); + + if (!wlan_reg_is_5ghz_ch_freq(chan->ch_freq)) + continue; + + ch_params.ch_width = chan->ch_width; + if (ch_params.ch_width == CH_WIDTH_160MHZ) + wlan_reg_set_create_punc_bitmap(&ch_params, + true); + + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + hdd_ctx->pdev, + chan->ch_freq, + &ch_params, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + + return adapter; + } + } +loop_next: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +/** + * wlan_hdd_cm_handle_sap_sta_dfs_conc() - to handle SAP STA DFS conc + * @hdd_ctx: hdd_ctx + * @req: connect req + * + * This routine will move SAP from dfs to non-dfs, if sta is coming up. + * + * Return: false if sta-sap conc is not allowed, else return true + */ +static +bool wlan_hdd_cm_handle_sap_sta_dfs_conc(struct hdd_context *hdd_ctx, + struct cfg80211_connect_params *req) +{ + struct hdd_adapter *ap_adapter; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_hostapd_state *hostapd_state; + QDF_STATUS status; + qdf_freq_t ch_freq = 0; + enum phy_ch_width ch_bw; + enum channel_state ch_state; + struct scan_filter *scan_filter; + qdf_list_t *list = NULL; + qdf_list_node_t *cur_lst = NULL; + struct scan_cache_node *cur_node = NULL; + bool is_6ghz_cap = false; + + ap_adapter = hdd_get_sap_adapter_of_dfs(hdd_ctx); + /* probably no dfs sap running, no handling required */ + if (!ap_adapter) + return true; + + /* if sap is currently doing CAC then don't allow sta to go further */ + if (hdd_ctx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS) { + hdd_err("Concurrent SAP is in CAC state, STA is not allowed"); + return false; + } + + /* + * log and return error, if we allow STA to go through, we don't + * know what is going to happen better stop sta connection + */ + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter->deflink); + if (!hdd_ap_ctx) { + hdd_err("AP context not found"); + return false; + } + + if (req->channel && req->channel->center_freq) { + ch_freq = req->channel->center_freq; + goto def_chan; + } + /* + * find out by looking in to scan cache where sta is going to + * connect by passing its ssid amd bssid. + */ + scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); + if (!scan_filter) + goto def_chan; + + if (req->bssid) { + scan_filter->num_of_bssid = 1; + qdf_mem_copy(scan_filter->bssid_list[0].bytes, req->bssid, + QDF_MAC_ADDR_SIZE); + } + if (req->ssid_len > WLAN_SSID_MAX_LEN) { + scan_filter->num_of_ssid = 0; + hdd_err("req ssid len invalid %zu", req->ssid_len); + } else { + scan_filter->num_of_ssid = 1; + scan_filter->ssid_list[0].length = req->ssid_len; + qdf_mem_copy(scan_filter->ssid_list[0].ssid, req->ssid, + scan_filter->ssid_list[0].length); + } + scan_filter->ignore_auth_enc_type = true; + list = ucfg_scan_get_result(hdd_ctx->pdev, scan_filter); + qdf_mem_free(scan_filter); + + if (!list || (list && !qdf_list_size(list))) { + hdd_debug("scan list empty"); + goto purge_list; + } + qdf_list_peek_front(list, &cur_lst); + if (!cur_lst) + goto purge_list; + + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, node); + ch_freq = cur_node->entry->channel.chan_freq; +purge_list: + if (list) + ucfg_scan_purge_results(list); +def_chan: + /* + * If the STA's channel is 2.4 GHz, then set pcl with only 2.4 GHz + * channels for roaming case. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) { + hdd_info("sap is on dfs, new sta conn on 2.4 is allowed"); + return true; + } + + if (policy_mgr_is_hw_sbs_capable(hdd_ctx->psoc) && + ch_freq && + policy_mgr_are_sbs_chan(hdd_ctx->psoc, + ch_freq, + hdd_ap_ctx->operating_chan_freq)) { + hdd_debug("sta freq %d sap freq %d in sbs mode is allowed", + ch_freq, hdd_ap_ctx->operating_chan_freq); + return true; + } + + /* + * If channel is 0 or DFS or LTE unsafe then better to call pcl and + * find out the best channel. If channel is non-dfs 5 GHz then + * better move SAP to STA's channel to make scc, so we have room + * for 3port MCC scenario. + */ + ch_bw = hdd_ap_ctx->sap_config.ch_width_orig; + if (ch_freq) + is_6ghz_cap = policy_mgr_get_ap_6ghz_capable(hdd_ctx->psoc, + ap_adapter->deflink->vdev_id, + NULL); + + if (!ch_freq || wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, ch_freq) || + !policy_mgr_is_safe_channel(hdd_ctx->psoc, ch_freq) || + wlan_reg_is_passive_for_freq(hdd_ctx->pdev, ch_freq) || + (WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq) && !is_6ghz_cap)) + ch_freq = policy_mgr_get_nondfs_preferred_channel( + hdd_ctx->psoc, PM_SAP_MODE, + true, ap_adapter->deflink->vdev_id); + + if (WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq) && + ch_bw > CH_WIDTH_20MHZ) { + struct ch_params ch_params; + + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = ch_bw; + ch_state = + wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + hdd_ctx->pdev, ch_freq, &ch_params, + REG_CURRENT_PWR_MODE); + while (ch_bw > CH_WIDTH_20MHZ && + ch_state != CHANNEL_STATE_ENABLE) { + ch_bw = + wlan_reg_get_next_lower_bandwidth(ch_bw); + ch_params.ch_width = ch_bw; + ch_state = + wlan_reg_get_5g_bonded_channel_state_for_pwrmode + (hdd_ctx->pdev, ch_freq, &ch_params, + REG_CURRENT_PWR_MODE); + } + hdd_debug("bw change from %d to %d", + hdd_ap_ctx->sap_config.ch_width_orig, + ch_bw); + } + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter->deflink); + qdf_event_reset(&hostapd_state->qdf_event); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->deflink->vdev_id, + CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS); + + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(ap_adapter->deflink), ch_freq, + ch_bw, false); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set channel with CSA IE failed, can't allow STA"); + return false; + } + + /* + * wait here for SAP to finish the channel switch. When channel + * switch happens, SAP sends few beacons with CSA_IE. After + * successfully Transmission of those beacons, it will move its + * state from started to disconnected and move to new channel. + * once it moves to new channel, sap again moves its state + * machine from disconnected to started and set this event. + * wait for 10 secs to finish this. + */ + status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + 10000); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("wait for qdf_event failed, STA not allowed!!"); + return false; + } + + return true; +} + +int wlan_hdd_cm_connect(struct wiphy *wiphy, + struct net_device *ndev, + struct cfg80211_connect_params *req) +{ + int status; + struct wlan_objmgr_vdev *vdev; + struct osif_connect_params params; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *hdd_sta_ctx; + qdf_freq_t ch_freq = 0; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CONNECT, + adapter->deflink->vdev_id, adapter->device_mode); + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_err("Device_mode %s(%d) is not supported", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + hdd_reg_wait_for_country_change(hdd_ctx); + + if (policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + !wlan_hdd_cm_handle_sap_sta_dfs_conc(hdd_ctx, req)) { + hdd_err("sap-sta conc will fail, can't allow sta"); + return -EINVAL; + } + + if (req->channel && req->channel->center_freq) + ch_freq = req->channel->center_freq; + + if (ch_freq && wlan_reg_is_6ghz_chan_freq(ch_freq) && + !wlan_reg_is_6ghz_band_set(hdd_ctx->pdev)) { + hdd_err("6 GHz band disabled"); + return -EINVAL; + } + + qdf_mem_zero(¶ms, sizeof(params)); + ucfg_dlm_dump_deny_list_ap(hdd_ctx->pdev); + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_CM_ID); + if (!vdev) + return -EINVAL; + + ucfg_pmo_flush_gtk_offload_req(vdev); + qdf_mem_zero(&hdd_sta_ctx->conn_info.conn_flag, + sizeof(hdd_sta_ctx->conn_info.conn_flag)); + + /* + * Reset the ptk, gtk status flags to avoid using old/previous + * connection status. + */ + hdd_sta_ctx->conn_info.gtk_installed = false; + hdd_sta_ctx->conn_info.ptk_installed = false; + adapter->last_disconnect_reason = 0; + + qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect); + hdd_prevent_suspend_timeout(HDD_WAKELOCK_CONNECT_COMPLETE, + WIFI_POWER_EVENT_WAKELOCK_CONNECT); + + params.force_rsne_override = hdd_ctx->force_rsne_override; + params.dot11mode_filter = hdd_get_dot11mode_filter(hdd_ctx); + + hdd_update_scan_ie_for_connect(adapter, ¶ms); + hdd_update_action_oui_for_connect(hdd_ctx, req); + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + /* + * Clear user/wpa_supplicant disabled_roaming flag for new + * connection + */ + ucfg_clear_user_disabled_roaming(hdd_ctx->psoc, + adapter->deflink->vdev_id); + } + status = osif_cm_connect(ndev, vdev, req, ¶ms); + + if (status || ucfg_cm_is_vdev_roaming(vdev)) { + /* Release suspend and wake lock for failure or roam invoke */ + if (status) + hdd_err("Vdev %d connect failed status %d", + adapter->deflink->vdev_id, status); + else + hdd_debug("Vdev %d: connect lead to roam invoke", + adapter->deflink->vdev_id); + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT); + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + return status; +} + +static void hdd_cm_rec_connect_info(struct wlan_cm_connect_resp *rsp) +{ + if (rsp->is_reassoc) + wlan_rec_conn_info(rsp->vdev_id, DEBUG_CONN_ROAMED_IND, + rsp->bssid.bytes, rsp->cm_id, 0); + else + wlan_rec_conn_info(rsp->vdev_id, DEBUG_CONN_CONNECT_RESULT, + rsp->bssid.bytes, rsp->cm_id << 16 | + rsp->reason, + rsp->status_code); +} + +static void +hdd_cm_connect_failure_pre_user_update(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + struct hdd_station_ctx *hdd_sta_ctx; + uint32_t time_buffer_size; + struct wlan_hdd_link_info *link_info; + bool is_link_switch = + wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->vdev_id); + if (!link_info) { + hdd_err("adapter is NULL vdev %d", rsp->vdev_id); + return; + } + + adapter = link_info->adapter; + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + time_buffer_size = sizeof(hdd_sta_ctx->conn_info.connect_time); + qdf_mem_zero(hdd_sta_ctx->conn_info.connect_time, time_buffer_size); + hdd_init_scan_reject_params(hdd_ctx); + hdd_cm_save_connect_status(link_info, rsp->status_code); + if (!is_link_switch) { + /* For link switch connection failure, do not clear existing + * connection info in OSIF. + */ + hdd_conn_remove_connect_info(hdd_sta_ctx); + hdd_adapter_reset_station_ctx(adapter); + } + + ucfg_dp_remove_conn_info(vdev); + hdd_cm_update_rssi_snr_by_bssid(link_info); + hdd_cm_rec_connect_info(rsp); + hdd_debug("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID); +} + +static void +hdd_cm_connect_failure_post_user_update(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + bool is_roam = rsp->is_reassoc; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->vdev_id); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", rsp->vdev_id); + return; + } + if (!is_roam) { + /* call only for connect */ + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT); + } + + adapter = link_info->adapter; + wlan_hdd_connectivity_fail_event(vdev, rsp); + hdd_clear_roam_profile_ie(adapter); + ucfg_cm_reset_key(hdd_ctx->pdev, link_info->vdev_id); + hdd_wmm_dscp_initial_state(adapter); + + /* + * If connect failure is due to link switch, do not disable the + * netdev queues as it will lead to data stall/NUD failure. + */ + if (!(rsp->cm_id & CM_ID_LSWITCH_BIT)) { + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + + ucfg_dp_periodic_sta_stats_start(vdev); + wlan_twt_concurrency_update(hdd_ctx); +} + +static void hdd_cm_connect_failure(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp, + enum osif_cb_type type) +{ + switch (type) { + case OSIF_PRE_USERSPACE_UPDATE: + hdd_cm_connect_failure_pre_user_update(vdev, rsp); + break; + case OSIF_POST_USERSPACE_UPDATE: + hdd_cm_connect_failure_post_user_update(vdev, rsp); + break; + default: + hdd_cm_connect_failure_pre_user_update(vdev, rsp); + hdd_cm_connect_failure_post_user_update(vdev, rsp); + } +} + +/** + * hdd_cm_update_prev_ap_ie() - Update the connected AP IEs + * @hdd_sta_ctx: Station context. + * @rsp: Connect response + * + * This API updates the connected ap beacon IEs to station context connection + * info. + * + * Return: None + */ +static void hdd_cm_update_prev_ap_ie(struct hdd_station_ctx *hdd_sta_ctx, + struct wlan_cm_connect_resp *rsp) +{ + struct element_info *bcn_probe_rsp = &rsp->connect_ies.bcn_probe_rsp; + struct element_info *bcn_ie; + uint32_t len; + + bcn_ie = &hdd_sta_ctx->conn_info.prev_ap_bcn_ie; + if (bcn_ie->ptr) { + qdf_mem_free(bcn_ie->ptr); + bcn_ie->ptr = NULL; + bcn_ie->len = 0; + } + + if (bcn_probe_rsp->ptr && + bcn_probe_rsp->len > sizeof(struct wlan_frame_hdr)) { + len = bcn_probe_rsp->len - sizeof(struct wlan_frame_hdr); + bcn_ie->ptr = qdf_mem_malloc(len); + if (!bcn_ie->ptr) { + bcn_ie->len = 0; + return; + } + qdf_mem_copy(bcn_ie->ptr, bcn_probe_rsp->ptr + + sizeof(struct wlan_frame_hdr), len); + bcn_ie->len = len; + } +} + +static void hdd_cm_save_bss_info(struct wlan_hdd_link_info *link_info, + struct wlan_cm_connect_resp *rsp) +{ + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *hdd_sta_ctx; + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + struct sDot11fAssocResponse *assoc_resp; + + if (!mac_handle) { + hdd_err("mac handle is null"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + assoc_resp = qdf_mem_malloc(sizeof(struct sDot11fAssocResponse)); + if (!assoc_resp) + return; + + qdf_mem_zero(&hdd_sta_ctx->conn_info.hs20vendor_ie, + sizeof(hdd_sta_ctx->conn_info.hs20vendor_ie)); + if (rsp->connect_ies.bcn_probe_rsp.ptr) + sme_get_hs20vendor_ie(mac_handle, + rsp->connect_ies.bcn_probe_rsp.ptr, + rsp->connect_ies.bcn_probe_rsp.len, + &hdd_sta_ctx->conn_info.hs20vendor_ie); + + status = sme_unpack_assoc_rsp(mac_handle, rsp, assoc_resp); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not parse assoc response"); + qdf_mem_free(assoc_resp); + return; + } + + if (assoc_resp->VHTCaps.present) { + hdd_sta_ctx->conn_info.conn_flag.vht_present = true; + hdd_copy_vht_caps(&hdd_sta_ctx->conn_info.vht_caps, + &assoc_resp->VHTCaps); + } else { + hdd_sta_ctx->conn_info.conn_flag.vht_present = false; + } + if (assoc_resp->HTCaps.present) { + hdd_sta_ctx->conn_info.conn_flag.ht_present = true; + hdd_copy_ht_caps(&hdd_sta_ctx->conn_info.ht_caps, + &assoc_resp->HTCaps); + } else { + hdd_sta_ctx->conn_info.conn_flag.ht_present = false; + } + if (rsp->is_reassoc) + hdd_sta_ctx->conn_info.roam_count++; + + if (assoc_resp->HTInfo.present) { + hdd_sta_ctx->conn_info.conn_flag.ht_op_present = true; + hdd_copy_ht_operation(hdd_sta_ctx, &assoc_resp->HTInfo); + } else { + hdd_sta_ctx->conn_info.conn_flag.ht_op_present = false; + } + if (assoc_resp->VHTOperation.present) { + hdd_sta_ctx->conn_info.conn_flag.vht_op_present = true; + hdd_copy_vht_operation(hdd_sta_ctx, &assoc_resp->VHTOperation); + } else { + hdd_sta_ctx->conn_info.conn_flag.vht_op_present = false; + } + + if (assoc_resp->he_cap.present) + hdd_sta_ctx->conn_info.conn_flag.he_present = true; + else + hdd_sta_ctx->conn_info.conn_flag.he_present = false; + + if (assoc_resp->eht_cap.present) + hdd_sta_ctx->conn_info.conn_flag.eht_present = true; + else + hdd_sta_ctx->conn_info.conn_flag.eht_present = false; + + if (assoc_resp->eht_op.present) + hdd_sta_ctx->conn_info.conn_flag.eht_op_present = true; + else + hdd_sta_ctx->conn_info.conn_flag.eht_op_present = false; + + /* + * Cache connection info only in case of station + */ + if (adapter->device_mode == QDF_STA_MODE) { + /* Cleanup already existing he info */ + hdd_cleanup_conn_info(link_info); + + hdd_copy_eht_operation(hdd_sta_ctx, &assoc_resp->eht_op); + /* Cache last connection info */ + qdf_mem_copy(&hdd_sta_ctx->cache_conn_info, + &hdd_sta_ctx->conn_info, + sizeof(hdd_sta_ctx->cache_conn_info)); + + hdd_copy_he_operation(hdd_sta_ctx, &assoc_resp->he_op); + hdd_cm_update_prev_ap_ie(hdd_sta_ctx, rsp); + } + + qdf_mem_free(assoc_resp); +} + +#ifdef FEATURE_WLAN_ESE +static bool hdd_is_ese_assoc(enum csr_akm_type auth_type, + tDot11fBeaconIEs *bcn_ie, + struct mac_context *mac_ctx) +{ + if ((csr_is_auth_type_ese(auth_type) || + (bcn_ie->ESEVersion.present && + auth_type == eCSR_AUTH_TYPE_OPEN_SYSTEM)) && + mac_ctx->mlme_cfg->lfr.ese_enabled) { + return true; + } + + return false; +} +#else +static bool hdd_is_ese_assoc(enum csr_akm_type auth_type, + tDot11fBeaconIEs *bcn_ie, + struct mac_context *mac_ctx) +{ + return false; +} +#endif + +static const uint8_t acm_mask_bit[WLAN_MAX_AC] = { + 0x4, /* SME_AC_BK */ + 0x8, /* SME_AC_BE */ + 0x2, /* SME_AC_VI */ + 0x1 /* SME_AC_VO */ +}; + +static void hdd_wmm_cm_connect(struct wlan_objmgr_vdev *vdev, + struct hdd_adapter *adapter, + tDot11fBeaconIEs *bcn_ie, + enum csr_akm_type auth_type) +{ + int ac; + bool qap; + bool qos_connection; + uint8_t acm_mask = 0; + struct vdev_mlme_obj *vdev_mlme; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (!mac_handle) { + hdd_err("mac handle is null"); + return; + } + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + hdd_err("vdev component object is NULL"); + return; + } + if (CSR_IS_QOS_BSS(bcn_ie) || bcn_ie->HTCaps.present) + /* Some HT AP's dont send WMM IE so in that case we + * assume all HT Ap's are Qos Enabled AP's + */ + qap = true; + else + qap = false; + + qos_connection = vdev_mlme->ext_vdev_ptr->connect_info.qos_enabled; + + acm_mask = sme_qos_get_acm_mask(mac_ctx, NULL, bcn_ie); + + hdd_debug("qap is %d, qos_connection is %d, acm_mask is 0x%x", + qap, qos_connection, acm_mask); + + adapter->hdd_wmm_status.qap = qap; + adapter->hdd_wmm_status.qos_connection = qos_connection; + + if (acm_mask) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)acm_mask_bit, WLAN_MAX_AC); + + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + if (qap && qos_connection && (acm_mask & acm_mask_bit[ac])) { + + /* admission is required */ + adapter->hdd_wmm_status.ac_status[ac]. + is_access_required = true; + adapter->hdd_wmm_status.ac_status[ac]. + is_access_allowed = false; + adapter->hdd_wmm_status.ac_status[ac]. + was_access_granted = false; + /* after reassoc if we have valid tspec, allow access */ + if (adapter->hdd_wmm_status.ac_status[ac]. + is_tspec_valid && + (adapter->hdd_wmm_status.ac_status[ac]. + tspec.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + adapter->hdd_wmm_status.ac_status[ac]. + is_access_allowed = true; + } + if (!sme_neighbor_roam_is11r_assoc( + mac_handle, + adapter->deflink->vdev_id) && + !hdd_is_ese_assoc(auth_type, bcn_ie, mac_ctx)) { + adapter->hdd_wmm_status.ac_status[ac]. + is_tspec_valid = false; + adapter->hdd_wmm_status.ac_status[ac]. + is_access_allowed = false; + } + } else { + /* admission is not required so access is allowed */ + adapter->hdd_wmm_status.ac_status[ac]. + is_access_required = false; + adapter->hdd_wmm_status.ac_status[ac]. + is_access_allowed = true; + } + } +} + +static void hdd_cm_save_connect_info(struct wlan_hdd_link_info *link_info, + struct wlan_cm_connect_resp *rsp) +{ + struct hdd_station_ctx *sta_ctx; + struct wlan_crypto_params *crypto_params; + struct wlan_channel *des_chan; + struct wlan_objmgr_vdev *vdev; + uint8_t *ie_field; + uint32_t ie_len, status; + tDot11fBeaconIEs *bcn_ie; + struct s_ext_cap *p_ext_cap = NULL; + struct hdd_adapter *adapter = link_info->adapter; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + uint32_t phymode; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + bcn_ie = qdf_mem_malloc(sizeof(*bcn_ie)); + if (!bcn_ie) + return; + + qdf_copy_macaddr(&sta_ctx->conn_info.bssid, &rsp->bssid); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_conn_info_set_bssid(vdev, &rsp->bssid); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + phymode = wlan_reg_get_max_phymode(adapter->hdd_ctx->pdev, + REG_PHYMODE_MAX, + rsp->freq); + + sta_ctx->reg_phymode = csr_convert_from_reg_phy_mode(phymode); + + sta_ctx->conn_info.assoc_status_code = rsp->status_code; + + crypto_params = + wlan_crypto_vdev_get_crypto_params(link_info->vdev); + + if (crypto_params) { + sme_fill_enc_type(&sta_ctx->conn_info.uc_encrypt_type, + crypto_params->ucastcipherset); + + sme_fill_auth_type(&sta_ctx->conn_info.auth_type, + crypto_params->authmodeset, + crypto_params->key_mgmt, + crypto_params->ucastcipherset); + sta_ctx->conn_info.last_auth_type = + sta_ctx->conn_info.auth_type; + } + des_chan = wlan_vdev_mlme_get_des_chan(link_info->vdev); + + sta_ctx->conn_info.chan_freq = rsp->freq; + + /* Save the ssid for the connection */ + qdf_mem_copy(&sta_ctx->conn_info.ssid.SSID.ssId, + &rsp->ssid.ssid, + rsp->ssid.length); + qdf_mem_copy(&sta_ctx->conn_info.last_ssid.SSID.ssId, + &rsp->ssid.ssid, + rsp->ssid.length); + sta_ctx->conn_info.ssid.SSID.length = rsp->ssid.length; + sta_ctx->conn_info.last_ssid.SSID.length = rsp->ssid.length; + + sta_ctx->conn_info.dot11mode = + sme_phy_mode_to_dot11mode(des_chan->ch_phymode); + + sta_ctx->conn_info.ch_width = des_chan->ch_width; + if (!rsp->connect_ies.bcn_probe_rsp.ptr || + (rsp->connect_ies.bcn_probe_rsp.len < + (sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)))) { + hdd_err("beacon len is invalid %d", + rsp->connect_ies.bcn_probe_rsp.len); + qdf_mem_free(bcn_ie); + return; + } + + ie_len = (rsp->connect_ies.bcn_probe_rsp.len - + sizeof(struct wlan_frame_hdr) - + offsetof(struct wlan_bcn_frame, ie)); + ie_field = (uint8_t *)(rsp->connect_ies.bcn_probe_rsp.ptr + + sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)); + + status = dot11f_unpack_beacon_i_es(MAC_CONTEXT(mac_handle), ie_field, + ie_len, bcn_ie, false); + + if (DOT11F_FAILED(status)) { + hdd_err("Failed to parse beacon ie"); + qdf_mem_free(bcn_ie); + return; + } + if (bcn_ie->ExtCap.present) { + p_ext_cap = (struct s_ext_cap *)bcn_ie->ExtCap.bytes; + sta_ctx->conn_info.proxy_arp_service = + p_ext_cap->proxy_arp_service; + + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (vdev) { + sta_ctx->conn_info.nss = wlan_vdev_mlme_get_nss(vdev); + ucfg_wlan_vdev_mgr_get_param(vdev, WLAN_MLME_CFG_RATE_FLAGS, + &sta_ctx->conn_info.rate_flags); + hdd_wmm_cm_connect(vdev, adapter, bcn_ie, + sta_ctx->conn_info.auth_type); + + if (p_ext_cap) + ucfg_dp_conn_info_set_arp_service(vdev, + p_ext_cap->proxy_arp_service); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + } + qdf_mem_free(bcn_ie); + + hdd_cm_save_bss_info(link_info, rsp); +} + +#ifdef WLAN_FEATURE_FILS_SK +static bool hdd_cm_is_fils_connection(struct wlan_cm_connect_resp *rsp) +{ + return rsp->is_fils_connection; +} +#else +static inline +bool hdd_cm_is_fils_connection(struct wlan_cm_connect_resp *rsp) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static bool hdd_cm_is_roam_auth_required(struct hdd_station_ctx *sta_ctx, + struct wlan_cm_connect_resp *rsp) +{ + if (!rsp->roaming_info) + return false; + + if (rsp->roaming_info->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED) + return false; + + return true; +} +#else +static bool hdd_cm_is_roam_auth_required(struct hdd_station_ctx *sta_ctx, + struct wlan_cm_connect_resp *rsp) +{ + return true; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +struct hdd_adapter *hdd_get_assoc_link_adapter(struct hdd_adapter *ml_adapter) +{ + int i; + bool eht_capab; + struct hdd_adapter *link_adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(ml_adapter); + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (!eht_capab || hdd_adapter_is_sl_ml_adapter(ml_adapter)) + return ml_adapter; + + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = ml_adapter->mlo_adapter_info.link_adapter[i]; + if (link_adapter) { + if (hdd_adapter_is_associated_with_ml_adapter( + link_adapter)) + return link_adapter; + } + } + + return NULL; +} +#endif + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +static void hdd_set_immediate_power_save(struct hdd_adapter *adapter, + bool is_immediate_powersave) +{ + struct hdd_station_ctx *sta_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + sta_ctx->ap_supports_immediate_power_save = + is_immediate_powersave; + } +} +#else +static void hdd_set_immediate_power_save(struct hdd_adapter *adapter, + bool is_immediate_powersave) +{ + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_station_ctx *sta_ctx; + int i; + + if (!hdd_adapter_is_ml_adapter(adapter)) + goto update_non_ml; + + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_adapter->deflink); + sta_ctx->ap_supports_immediate_power_save = + is_immediate_powersave; + } + +update_non_ml: + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + sta_ctx->ap_supports_immediate_power_save = is_immediate_powersave; +} +#endif +#else +static void hdd_set_immediate_power_save(struct hdd_adapter *adapter, + bool is_immediate_powersave) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + sta_ctx->ap_supports_immediate_power_save = is_immediate_powersave; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static QDF_STATUS +hdd_cm_mlme_send_standby_link_chn_width(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + uint8_t link_id = wlan_vdev_get_link_id(vdev); + uint8_t ch_width; + enum phy_ch_width connection_ch_width = CH_WIDTH_INVALID; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("Failed to get PSOC Object"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_ieee_link_id(adapter, link_id); + if (!link_info) { + hdd_err("Link info not found by linkid:%u", link_id); + return QDF_STATUS_E_INVAL; + } + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + ch_width = sta_ctx->user_cfg_chn_width; + + wlan_mlme_get_sta_ch_width(vdev, &connection_ch_width); + + if (ch_width == CH_WIDTH_INVALID) { + hdd_debug("no cached bandwidth for the link %u", link_id); + return QDF_STATUS_SUCCESS; + } + + if (ch_width == connection_ch_width) { + hdd_debug("user config max bd same as connection ch bw:%u", + ch_width); + return QDF_STATUS_SUCCESS; + } + + hdd_debug("send vdev id:%u, chwidth:%u", link_info->vdev_id, + ch_width); + + wlan_mlme_send_ch_width_update_with_notify(psoc, vdev, + link_info->vdev_id, + ch_width); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +hdd_cm_mlme_send_standby_link_chn_width(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static void +hdd_cm_connect_success_pre_user_update(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct hdd_station_ctx *sta_ctx; + struct vdev_mlme_obj *vdev_mlme; + unsigned long rc; + uint32_t ie_len; + uint8_t *ie_field; + mac_handle_t mac_handle; + bool is_auth_required = true; + bool is_roam_offload = false; + bool is_roam = rsp->is_reassoc; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t uapsd_mask = 0; + uint32_t time_buffer_size; + struct hdd_adapter *assoc_link_adapter; + bool is_immediate_power_save; + struct wlan_hdd_link_info *link_info; + QDF_STATUS status = QDF_STATUS_E_INVAL; + bool alt_pipe; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + adapter = link_info->adapter; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + mac_handle = hdd_adapter_get_mac_handle(adapter); + + wlan_hdd_ft_set_key_delay(vdev); + hdd_cm_update_rssi_snr_by_bssid(link_info); + hdd_cm_save_connect_status(link_info, rsp->status_code); + + hdd_init_scan_reject_params(hdd_ctx); + time_buffer_size = sizeof(sta_ctx->conn_info.connect_time); + qdf_mem_zero(sta_ctx->conn_info.connect_time, time_buffer_size); + qdf_get_time_of_the_day_in_hr_min_sec_usec(sta_ctx->conn_info.connect_time, + time_buffer_size); + hdd_start_tsf_sync(adapter); + hdd_cm_rec_connect_info(rsp); + + hdd_cm_save_connect_info(link_info, rsp); + if (adapter->device_mode == QDF_STA_MODE && + hdd_adapter_is_ml_adapter(adapter)) { + /* Save connection info in assoc link adapter as well */ + assoc_link_adapter = hdd_get_assoc_link_adapter(adapter); + if (assoc_link_adapter) + hdd_cm_save_connect_info(assoc_link_adapter->deflink, + rsp); + } + if (hdd_add_beacon_filter(adapter) != 0) + hdd_err("add beacon filter failed"); + + adapter->wapi_info.is_wapi_sta = hdd_cm_is_wapi_sta( + sta_ctx->conn_info.auth_type); + if (adapter->device_mode == QDF_STA_MODE && + rsp->connect_ies.bcn_probe_rsp.ptr && + (rsp->connect_ies.bcn_probe_rsp.len > + (sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)))) { + ie_len = (rsp->connect_ies.bcn_probe_rsp.len - + sizeof(struct wlan_frame_hdr) - + offsetof(struct wlan_bcn_frame, ie)); + + ie_field = (uint8_t *)(rsp->connect_ies.bcn_probe_rsp.ptr + + sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)); + is_immediate_power_save = + wlan_hdd_is_ap_supports_immediate_power_save( + ie_field, ie_len); + hdd_set_immediate_power_save(adapter, is_immediate_power_save); + hdd_debug("ap_supports_immediate_power_save flag [%d]", + sta_ctx->ap_supports_immediate_power_save); + } + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, true); + + hdd_cm_handle_assoc_event(vdev, rsp->bssid.bytes); + + if (ucfg_cm_is_link_switch_connect_resp(rsp)) { + if (hdd_cm_mlme_send_standby_link_chn_width(adapter, vdev)) + hdd_debug("send standby link chn width fail"); + } + + /* + * check update hdd_send_update_beacon_ies_event, + * hdd_send_ft_assoc_response, + */ + + wlan_hdd_set_tx_flow_info(); + hdd_place_marker(adapter, "ASSOCIATION COMPLETE", NULL); + + if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc)) { + if (hdd_ctx->miracast_value) + wlan_hdd_set_mas(adapter, hdd_ctx->miracast_value); + } + + if (!is_roam) { + /* Initialize the Linkup event completion variable */ + INIT_COMPLETION(adapter->linkup_event_var); + + /* + * Enable Linkup Event Servicing which allows the net + * device notifier to set the linkup event variable. + */ + adapter->is_link_up_service_needed = true; + + /* Switch on the Carrier to activate the device */ + wlan_hdd_netif_queue_control(adapter, WLAN_NETIF_CARRIER_ON, + WLAN_CONTROL_PATH); + + /* + * Wait for the Link to up to ensure all the queues + * are set properly by the kernel. + */ + rc = wait_for_completion_timeout( + &adapter->linkup_event_var, + msecs_to_jiffies(ASSOC_LINKUP_TIMEOUT)); + /* + * Disable Linkup Event Servicing - no more service + * required from the net device notifier call. + */ + adapter->is_link_up_service_needed = false; + } + + vdev_mlme = wlan_objmgr_vdev_get_comp_private_obj(vdev, + WLAN_UMAC_COMP_MLME); + if (vdev_mlme) + uapsd_mask = + vdev_mlme->ext_vdev_ptr->connect_info.uapsd_per_ac_bitmask; + + cdp_hl_fc_set_td_limit(soc, link_info->vdev_id, + sta_ctx->conn_info.chan_freq); + hdd_wmm_assoc(adapter, false, uapsd_mask); + + if (!rsp->is_wps_connection && + !rsp->is_osen_connection && + (sta_ctx->conn_info.auth_type == eCSR_AUTH_TYPE_NONE || + sta_ctx->conn_info.auth_type == eCSR_AUTH_TYPE_OPEN_SYSTEM || + sta_ctx->conn_info.auth_type == eCSR_AUTH_TYPE_SHARED_KEY || + hdd_cm_is_fils_connection(rsp))) + is_auth_required = false; + + if (is_roam) + /* If roaming is set check if FW roaming/LFR3 */ + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &is_roam_offload); + + if (is_roam_offload || !is_roam) { + /* For FW_ROAM/LFR3 OR connect */ + /* for LFR 3 get authenticated info from resp */ + if (is_roam) { + is_auth_required = + hdd_cm_is_roam_auth_required(sta_ctx, rsp); + if (is_auth_required) + wlan_acquire_peer_key_wakelock(hdd_ctx->pdev, + rsp->bssid.bytes); + } + hdd_debug("is_roam_offload %d, is_roam %d, is_auth_required %d", + is_roam_offload, is_roam, is_auth_required); + hdd_roam_register_sta(link_info, &rsp->bssid, is_auth_required); + } else { + /* for host roam/LFR2 */ + hdd_cm_set_peer_authenticate(link_info, + &rsp->bssid, is_auth_required); + } + + hdd_debug("Enabling queues"); + hdd_cm_netif_queue_enable(adapter); + + /* send peer status indication to oem app */ + if (vdev_mlme) { + hdd_send_peer_status_ind_to_app( + &rsp->bssid, + ePeerConnected, + vdev_mlme->ext_vdev_ptr->connect_info.timing_meas_cap, + link_info->vdev_id, + &vdev_mlme->ext_vdev_ptr->connect_info.chan_info, + adapter->device_mode); + } + + if (ucfg_ipa_is_enabled() && !is_auth_required) { + status = hdd_ipa_get_tx_pipe(hdd_ctx, link_info, &alt_pipe); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("Failed to get alternate pipe for vdev %d", + link_info->vdev_id); + alt_pipe = false; + } + + ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + link_info->vdev_id, + WLAN_IPA_STA_CONNECT, + rsp->bssid.bytes, + alt_pipe); + } + + if (adapter->device_mode == QDF_STA_MODE) + cdp_reset_rx_hw_ext_stats(soc); + + wlan_hdd_auto_shutdown_enable(hdd_ctx, false); + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + link_info->vdev_id, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC)); + + if (is_roam) + ucfg_dp_nud_indicate_roam(vdev); + /* hdd_objmgr_set_peer_mlme_auth_state */ + + if (adapter->keep_alive_interval) + hdd_vdev_send_sta_keep_alive_interval(link_info, hdd_ctx, + adapter->keep_alive_interval); +} + +static void +hdd_cm_connect_success_post_user_update(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + bool is_roam = rsp->is_reassoc; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->vdev_id); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", rsp->vdev_id); + return; + } + + if (!is_roam) { + /* call only for connect */ + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_CONNECT); + } + + adapter = link_info->adapter; + hdd_cm_clear_pmf_stats(adapter); + + if (adapter->device_mode == QDF_STA_MODE) { + /* Inform FTM TIME SYNC about the connection with AP */ + hdd_ftm_time_sync_sta_state_notify(adapter, + FTM_TIME_SYNC_STA_CONNECTED); + ucfg_mlme_init_twt_context(hdd_ctx->psoc, + &rsp->bssid, + TWT_ALL_SESSIONS_DIALOG_ID); + ucfg_twt_init_context(hdd_ctx->psoc, + &rsp->bssid, + TWT_ALL_SESSIONS_DIALOG_ID); + } + ucfg_dp_periodic_sta_stats_start(vdev); + wlan_twt_concurrency_update(hdd_ctx); + + if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev)) + hdd_send_ps_config_to_fw(adapter); +} + +static void hdd_cm_connect_success(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp, + enum osif_cb_type type) +{ + switch (type) { + case OSIF_PRE_USERSPACE_UPDATE: + hdd_cm_connect_success_pre_user_update(vdev, rsp); + break; + case OSIF_POST_USERSPACE_UPDATE: + hdd_cm_connect_success_post_user_update(vdev, rsp); + break; + default: + hdd_cm_connect_success_pre_user_update(vdev, rsp); + hdd_cm_connect_success_post_user_update(vdev, rsp); + } +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +void hdd_cm_connect_active_notify(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Link info not found for vdev %d", vdev_id); + return; + } + + if (hdd_adapter_restore_link_vdev_map(link_info->adapter, true)) + hdd_adapter_update_mlo_mgr_mac_addr(link_info->adapter); +} +#endif + +QDF_STATUS hdd_cm_connect_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp, + enum osif_cb_type type) +{ + if (QDF_IS_STATUS_ERROR(rsp->connect_status)) + hdd_cm_connect_failure(vdev, rsp, type); + else + hdd_cm_connect_success(vdev, rsp, type); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_cm_send_vdev_keys(struct wlan_objmgr_vdev *vdev, + u8 key_index, bool pairwise, + enum wlan_crypto_cipher_type cipher_type) +{ + return wlan_hdd_send_key_vdev(vdev, key_index, pairwise, cipher_type); +} + +#ifdef WLAN_VENDOR_HANDOFF_CONTROL +#define WLAN_WAIT_TIME_HANDOFF_PARAMS 1000 +QDF_STATUS hdd_cm_get_handoff_param(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum vendor_control_roam_param param_id) +{ + QDF_STATUS status; + int retval; + void *vendor_handoff_context; + struct osif_request *request; + static const struct osif_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_HANDOFF_PARAMS, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + status = QDF_STATUS_E_NOMEM; + goto error; + } + + vendor_handoff_context = osif_request_cookie(request); + + hdd_debug("sending vendor handoff param request for :0x%x", param_id); + status = ucfg_cm_roam_send_vendor_handoff_param_req(psoc, vdev_id, + param_id, + vendor_handoff_context); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get vendor handoff param"); + goto error; + } + + retval = osif_request_wait_for_response(request); + if (retval) { + hdd_err("Target response timed out"); + status = qdf_status_from_os_return(retval); + } +error: + if (request) + osif_request_put(request); + + return status; +} + +QDF_STATUS +hdd_cm_get_vendor_handoff_params(struct wlan_objmgr_psoc *psoc, + void *vendor_handoff_context) +{ + struct osif_request *request; + + hdd_debug("Received vendor handoff event from FW"); + + request = osif_request_get(vendor_handoff_context); + if (!request) { + hdd_err("Invalid request"); + return QDF_STATUS_E_FAILURE; + } + + osif_request_complete(request); + osif_request_put(request); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +hdd_cm_get_scan_ie_params(struct wlan_objmgr_vdev *vdev, + struct element_info *scan_ie, + enum dot11_mode_filter *dot11mode_filter) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct hdd_scan_info *scan_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + scan_info = &link_info->adapter->scan_info; + if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE) { + scan_ie->ptr = &scan_info->scan_add_ie.addIEdata[0]; + scan_ie->len = scan_info->scan_add_ie.length; + } else if (scan_info->default_scan_ies) { + scan_ie->ptr = scan_info->default_scan_ies; + scan_ie->len = scan_info->default_scan_ies_len; + } else if (scan_info->scan_add_ie.length) { + scan_ie->ptr = scan_info->scan_add_ie.addIEdata; + scan_ie->len = scan_info->scan_add_ie.length; + } + + *dot11mode_filter = hdd_get_dot11mode_filter(hdd_ctx); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef WLAN_FEATURE_FILS_SK +QDF_STATUS hdd_cm_save_gtk(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + uint8_t *kek; + uint32_t kek_len; + uint8_t *kck = NULL; + uint8_t kck_len = 0; + uint8_t replay_ctr_def[REPLAY_CTR_LEN] = {0}; + uint8_t *replay_ctr; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->vdev_id); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", rsp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (rsp->is_reassoc && rsp->roaming_info) { + kek = rsp->roaming_info->kek; + kek_len = rsp->roaming_info->kek_len; + kck = rsp->roaming_info->kck; + kck_len = rsp->roaming_info->kck_len; + replay_ctr = rsp->roaming_info->replay_ctr; + } else if (rsp->connect_ies.fils_ie) { + kek = rsp->connect_ies.fils_ie->kek; + kek_len = rsp->connect_ies.fils_ie->kek_len; + replay_ctr = replay_ctr_def; + } else { + return QDF_STATUS_SUCCESS; + } + wlan_hdd_save_gtk_offload_params(link_info->adapter, kck, kck_len, + kek, kek_len, replay_ctr, true); + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS hdd_cm_save_gtk(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + uint8_t *kek; + uint32_t kek_len; + uint8_t *kck = NULL; + uint8_t kck_len = 0; + uint8_t *replay_ctr; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->vdev_id); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", rsp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (rsp->is_reassoc && rsp->roaming_info) { + kek = rsp->roaming_info.kek; + kek_len = rsp->roaming_info.kek_len; + kck = rsp->roaming_info.kck; + kck_len = rsp->roaming_info.kck_len; + replay_ctr = rsp->roaming_info.replay_ctr; + } else { + return QDF_STATUS_SUCCESS; + } + wlan_hdd_save_gtk_offload_params(link_info->adapter, kck, kck_len, + kek, kek_len, replay_ctr, true); + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_FILS_SK*/ +#else +QDF_STATUS hdd_cm_save_gtk(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +static void hdd_update_hlp_info(struct net_device *dev, + struct wlan_cm_connect_resp *rsp) +{ + struct sk_buff *skb; + uint16_t skb_len; + struct llc_snap_hdr_t *llc_hdr; + QDF_STATUS status; + uint8_t *hlp_data; + uint16_t hlp_data_len; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (!rsp || !rsp->connect_ies.fils_ie) { + return; + } + + if (!rsp->connect_ies.fils_ie->hlp_data_len) { + return; + } + + hlp_data = rsp->connect_ies.fils_ie->hlp_data; + hlp_data_len = rsp->connect_ies.fils_ie->hlp_data_len; + + /* Calculate skb length */ + skb_len = (2 * ETH_ALEN) + hlp_data_len; + skb = qdf_nbuf_alloc(NULL, skb_len, 0, 4, false); + if (!skb) { + hdd_err("HLP packet nbuf alloc fails"); + return; + } + + qdf_mem_copy(skb_put(skb, ETH_ALEN), + rsp->connect_ies.fils_ie->dst_mac.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(skb_put(skb, ETH_ALEN), + rsp->connect_ies.fils_ie->src_mac.bytes, + QDF_MAC_ADDR_SIZE); + + llc_hdr = (struct llc_snap_hdr_t *)hlp_data; + if (IS_SNAP(llc_hdr)) { + hlp_data += LLC_SNAP_HDR_OFFSET_ETHERTYPE; + hlp_data_len += LLC_SNAP_HDR_OFFSET_ETHERTYPE; + } + + qdf_mem_copy(skb_put(skb, hlp_data_len), hlp_data, hlp_data_len); + + /* + * This HLP packet is formed from HLP info encapsulated + * in assoc response frame which is AEAD encrypted. + * Hence, this checksum validation can be set unnecessary. + * i.e. network layer need not worry about checksum. + */ + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* + * adapter->deflink->vdev is directly dereferenced because in per packet + * path usage of hdd_get_vdev_by_user is costly operation as it + * involves lock access. And it is guaranteed during TX/RX operations + * vdev will be active will not deleted. + */ + status = ucfg_dp_rx_packet_cbk(adapter->deflink->vdev, (qdf_nbuf_t)skb); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Sending HLP packet fails"); + return; + } + hdd_debug("send HLP packet to netif successfully"); +} + +QDF_STATUS hdd_cm_set_hlp_data(struct net_device *dev, + struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + hdd_update_hlp_info(dev, rsp); + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_PREAUTH_ENABLE +/** + * hdd_cm_get_ft_preauth_response() - get ft preauth response + * related information + * @vdev: vdev pointer + * @rsp: preauth response + * @ft_ie: ft ie + * @ft_ie_ip_len: ft ie ip length + * @ft_ie_length: ft ies length + * + * This function is used to get ft ie related information + * + * Return: none + */ +static void +hdd_cm_get_ft_preauth_response(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp, uint8_t *ft_ie, + uint32_t ft_ie_ip_len, uint16_t *ft_ie_length) +{ + struct mlme_legacy_priv *mlme_priv; + + *ft_ie_length = 0; + + if (!vdev) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + /* All or nothing - proceed only if both BSSID and FT IE fit */ + if ((QDF_MAC_ADDR_SIZE + rsp->ft_ie_length) > ft_ie_ip_len) + return; + /* + * hdd needs to pack the bssid also along with the + * auth response to supplicant + */ + qdf_mem_copy(ft_ie, rsp->pre_auth_bssid.bytes, QDF_MAC_ADDR_SIZE); + + /* Copy the auth resp FTIEs */ + qdf_mem_copy(&ft_ie[QDF_MAC_ADDR_SIZE], + rsp->ft_ie, rsp->ft_ie_length); + + *ft_ie_length = QDF_MAC_ADDR_SIZE + rsp->ft_ie_length; + + hdd_debug("Filled auth resp: %d", *ft_ie_length); +} + +#if defined(KERNEL_SUPPORT_11R_CFG80211) +QDF_STATUS hdd_cm_ft_preauth_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp) +{ + mac_handle_t mac_handle; + struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); + struct wireless_dev *wdev; + uint16_t auth_resp_len = 0; + uint32_t ric_ies_length = 0; + struct cfg80211_ft_event_params ft_event = {0}; + uint8_t ft_ie[DOT11F_IE_FTINFO_MAX_LEN] = {0}; + uint8_t ric_ies[DOT11F_IE_RICDESCRIPTOR_MAX_LEN] = {0}; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) { + hdd_err("mac_handle is null"); + return QDF_STATUS_E_INVAL; + } + + if (!osif_priv) { + hdd_err("Invalid vdev osif priv"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + hdd_err("wdev is null"); + return QDF_STATUS_E_INVAL; + } + + if (rsp->ric_ies_length && + rsp->ric_ies_length <= DOT11F_IE_RICDESCRIPTOR_MAX_LEN) { + qdf_mem_copy(ric_ies, rsp->ric_ies, rsp->ric_ies_length); + ric_ies_length = rsp->ric_ies_length; + } else { + hdd_warn("Do not send RIC IEs as length is 0"); + } + + if (ric_ies_length) { + ft_event.ric_ies = ric_ies; + ft_event.ric_ies_len = ric_ies_length; + } + hdd_debug("RIC IEs is of length %d", ric_ies_length); + + hdd_cm_get_ft_preauth_response(vdev, rsp, ft_ie, + DOT11F_IE_FTINFO_MAX_LEN, + &auth_resp_len); + if (!auth_resp_len) { + hdd_debug("AuthRsp FTIES is of length 0"); + return QDF_STATUS_E_FAILURE; + } + + ucfg_cm_set_ft_pre_auth_state(vdev, true); + + ft_event.target_ap = ft_ie; + ft_event.ies = (u8 *)(ft_ie + QDF_MAC_ADDR_SIZE); + ft_event.ies_len = auth_resp_len - QDF_MAC_ADDR_SIZE; + + hdd_debug("ftEvent.ies_len %zu", ft_event.ies_len); + hdd_debug("ftEvent.ric_ies_len %zu", ft_event.ric_ies_len); + hdd_debug("ftEvent.target_ap %2x-%2x-%2x-%2x-%2x-%2x", + ft_event.target_ap[0], ft_event.target_ap[1], + ft_event.target_ap[2], ft_event.target_ap[3], + ft_event.target_ap[4], ft_event.target_ap[5]); + + (void)cfg80211_ft_event(wdev->netdev, &ft_event); + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS hdd_cm_ft_preauth_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp) +{ + struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); + struct wireless_dev *wdev; + uint16_t auth_resp_len = 0; + uint32_t ric_ies_length = 0; + char *buff; + union iwreq_data wrqu; + uint16_t str_len; + + if (!osif_priv) { + hdd_err("Invalid vdev osif priv"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + hdd_err("wdev is null"); + return QDF_STATUS_E_INVAL; + } + + /* need to send the IEs to the supplicant */ + buff = qdf_mem_malloc(IW_CUSTOM_MAX); + if (!buff) + return QDF_STATUS_E_NOMEM; + + /* need to send the RIC IEs first */ + str_len = strlcpy(buff, "RIC=", IW_CUSTOM_MAX); + if (rsp->ric_ies_length && + (rsp->ric_ies_length <= (IW_CUSTOM_MAX - str_len))) { + qdf_mem_copy(&buff[str_len], rsp->ric_ies, + rsp->ric_ies_length); + ric_ies_length = rsp->ric_ies_length; + wrqu.data.length = str_len + ric_ies_length; + hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buff); + } else { + hdd_warn("Do not send RIC IEs as length is 0"); + } + + /* need to provide the Auth Resp */ + qdf_mem_zero(buff, IW_CUSTOM_MAX); + str_len = strlcpy(buff, "AUTH=", IW_CUSTOM_MAX); + hdd_cm_get_ft_preauth_response(vdev, rsp, &buff[str_len], + (IW_CUSTOM_MAX - str_len), + &auth_resp_len); + if (!auth_resp_len) { + qdf_mem_free(buff); + hdd_debug("AuthRsp FTIES is of length 0"); + return QDF_STATUS_E_FAILURE; + } + + wrqu.data.length = str_len + auth_resp_len; + hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buff); + + qdf_mem_free(buff); + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS hdd_cm_cckm_preauth_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_preauth_rsp *rsp) +{ + struct vdev_osif_priv *osif_priv = wlan_vdev_get_ospriv(vdev); + struct wireless_dev *wdev; + union iwreq_data wrqu; + char buf[IW_CUSTOM_MAX + 1]; + char *pos = buf; + int nbytes = 0, freebytes = IW_CUSTOM_MAX; + + if (!osif_priv) { + hdd_err("Invalid vdev osif priv"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + hdd_err("wdev is null"); + return QDF_STATUS_E_INVAL; + } + + /* create the event */ + memset(&wrqu, '\0', sizeof(wrqu)); + memset(buf, '\0', sizeof(buf)); + + /* timestamp0 is lower 32 bits and timestamp1 is upper 32 bits */ + hdd_debug("CCXPREAUTHNOTIFY=" QDF_MAC_ADDR_FMT " %d:%d", + QDF_MAC_ADDR_REF(rsp->pre_auth_bssid.bytes), + rsp->timestamp[0], rsp->timestamp[1]); + + nbytes = snprintf(pos, freebytes, "CCXPREAUTHNOTIFY="); + pos += nbytes; + freebytes -= nbytes; + + qdf_mem_copy(pos, rsp->pre_auth_bssid.bytes, QDF_MAC_ADDR_SIZE); + pos += QDF_MAC_ADDR_SIZE; + freebytes -= QDF_MAC_ADDR_SIZE; + + nbytes = snprintf(pos, freebytes, " %u:%u", + rsp->timestamp[0], rsp->timestamp[1]); + freebytes -= nbytes; + + wrqu.data.pointer = buf; + wrqu.data.length = (IW_CUSTOM_MAX - freebytes); + + /* send the event */ + hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buf); + + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_ESE */ +#endif /* WLAN_FEATURE_PREAUTH_ENABLE */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_disconnect.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_disconnect.c new file mode 100644 index 0000000000..5e955bd729 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_cm_disconnect.c @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: hdd_cm_disconnect.c + * + * WLAN Host Device Driver disconnect APIs implementation + * + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_hdd_trace.h" +#include +#include "wlan_hdd_cm_api.h" +#include "wlan_ipa_ucfg_api.h" +#include "wlan_hdd_stats.h" +#include "wlan_hdd_scan.h" +#include "sme_power_save_api.h" +#include +#include "wlan_hdd_ftm_time_sync.h" +#include "wlan_hdd_bcn_recv.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_ipa.h" +#include "wlan_hdd_green_ap.h" +#include "wlan_hdd_lpass.h" +#include "wlan_hdd_bootup_marker.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_crypto_global_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "hif.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_napi.h" +#include "wlan_hdd_cfr.h" +#include "wlan_roam_debug.h" +#include "wma_api.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_dp_ucfg_api.h" +#include "wma.h" + +void hdd_handle_disassociation_event(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *peer_macaddr) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_vdev *vdev; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, false); + + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_app(peer_macaddr, + ePeerDisconnected, 0, + link_info->vdev_id, NULL, + adapter->device_mode); + + hdd_lpass_notify_disconnect(link_info); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_del_latency_critical_client(vdev, + hdd_convert_cfgdot11mode_to_80211mode( + sta_ctx->conn_info.dot11mode)); + /* stop timer in sta/p2p_cli */ + ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + ucfg_dp_bus_bw_compute_timer_try_stop(hdd_ctx->psoc); + cdp_display_txrx_hw_info(soc); +} + +/** + * hdd_cm_print_bss_info() - print bss info + * @hdd_sta_ctx: pointer to hdd station context + * + * Return: None + */ +static void hdd_cm_print_bss_info(struct hdd_station_ctx *hdd_sta_ctx) +{ + uint32_t *ht_cap_info; + uint32_t *vht_cap_info; + struct hdd_connection_info *conn_info; + + conn_info = &hdd_sta_ctx->conn_info; + + hdd_nofl_debug("*********** WIFI DATA LOGGER **************"); + hdd_nofl_debug("freq: %d dot11mode %d AKM %d ssid: \"" QDF_SSID_FMT "\" ,roam_count %d nss %d legacy %d mcs %d signal %d noise: %d", + conn_info->chan_freq, conn_info->dot11mode, + conn_info->last_auth_type, + QDF_SSID_REF(conn_info->last_ssid.SSID.length, + conn_info->last_ssid.SSID.ssId), + conn_info->roam_count, + conn_info->txrate.nss, conn_info->txrate.legacy, + conn_info->txrate.mcs, conn_info->signal, + conn_info->noise); + ht_cap_info = (uint32_t *)&conn_info->ht_caps; + vht_cap_info = (uint32_t *)&conn_info->vht_caps; + hdd_nofl_debug("HT 0x%x VHT 0x%x ht20 info 0x%x", + conn_info->conn_flag.ht_present ? *ht_cap_info : 0, + conn_info->conn_flag.vht_present ? *vht_cap_info : 0, + conn_info->conn_flag.hs20_present ? + conn_info->hs20vendor_ie.release_num : 0); +} + +void +__hdd_cm_disconnect_handler_pre_user_update(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx; + uint32_t time_buffer_size; + struct wlan_objmgr_vdev *vdev; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + hdd_stop_tsf_sync(adapter); + time_buffer_size = sizeof(sta_ctx->conn_info.connect_time); + qdf_mem_zero(sta_ctx->conn_info.connect_time, time_buffer_size); + if (ucfg_ipa_is_enabled() && + QDF_IS_STATUS_SUCCESS(wlan_hdd_validate_mac_address( + &sta_ctx->conn_info.bssid))) + ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + link_info->vdev_id, + WLAN_IPA_STA_DISCONNECT, + sta_ctx->conn_info.bssid.bytes, + false); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_periodic_sta_stats_stop(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + link_info->vdev_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); + + hdd_wmm_dscp_initial_state(adapter); + wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID); + + hdd_place_marker(adapter, "DISCONNECTED", NULL); +} + +/** + * hdd_reset_sta_keep_alive_interval() - Reset STA keep alive interval + * @link_info: Link info pointer. + * @hdd_ctx: HDD context pointer. + * + * Return: None. + */ +static void +hdd_reset_sta_keep_alive_interval(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx) +{ + enum QDF_OPMODE device_mode = link_info->adapter->device_mode; + uint32_t keep_alive_interval; + + if (!link_info->adapter->keep_alive_interval) + return; + + if (device_mode != QDF_STA_MODE) { + hdd_debug("Not supported for device mode %s = ", + device_mode_to_string(device_mode)); + return; + } + + if (!wlan_vdev_mlme_get_is_mlo_link(hdd_ctx->psoc, + link_info->vdev_id)) + wlan_hdd_save_sta_keep_alive_interval(link_info->adapter, 0); + + ucfg_mlme_get_sta_keep_alive_period(hdd_ctx->psoc, + &keep_alive_interval); + hdd_vdev_send_sta_keep_alive_interval(link_info, hdd_ctx, + keep_alive_interval); +} + +void +__hdd_cm_disconnect_handler_post_user_update(struct wlan_hdd_link_info *link_info, + struct wlan_objmgr_vdev *vdev, + enum wlan_cm_source source) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx; + mac_handle_t mac_handle; + struct hdd_adapter *link_adapter; + struct hdd_station_ctx *link_sta_ctx; + bool is_link_switch = + wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev); + + mac_handle = hdd_ctx->mac_handle; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + /* update P2P connection status */ + ucfg_p2p_status_disconnect(vdev); + hdd_cfr_disconnect(vdev); + + hdd_wmm_adapter_clear(adapter); + ucfg_cm_ft_reset(vdev); + ucfg_cm_reset_key(hdd_ctx->pdev, link_info->vdev_id); + hdd_clear_roam_profile_ie(adapter); + + if (adapter->device_mode == QDF_STA_MODE) + wlan_crypto_reset_vdev_params(vdev); + + hdd_remove_beacon_filter(adapter); + if (sme_is_beacon_report_started(mac_handle, link_info->vdev_id)) { + hdd_debug("Sending beacon pause indication to userspace"); + hdd_beacon_recv_pause_indication((hdd_handle_t)hdd_ctx, + link_info->vdev_id, + SCAN_EVENT_TYPE_MAX, true); + } + + if (adapter->device_mode == QDF_STA_MODE && + hdd_adapter_is_ml_adapter(adapter)) { + /* Clear connection info in assoc link adapter as well */ + link_adapter = hdd_get_assoc_link_adapter(adapter); + if (link_adapter) { + link_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_adapter->deflink); + hdd_conn_remove_connect_info(link_sta_ctx); + } + } + + if (!is_link_switch && source != CM_MLO_ROAM_INTERNAL_DISCONNECT) { + /* Clear saved connection information in HDD */ + hdd_conn_remove_connect_info(sta_ctx); + + /* + * Reset the IEEE link ID to invalid when disconnect is not + * due to link switch. This API resets link id for all the + * valid link_info for the given adapter. So avoid this reset + * for Link Switch disconnect/internal disconnect + */ + hdd_adapter_reset_station_ctx(adapter); + } + + ucfg_dp_remove_conn_info(vdev); + + /* Setting the RTS profile to original value */ + if (sme_cli_set_command(link_info->vdev_id, + wmi_vdev_param_enable_rtscts, + cfg_get(hdd_ctx->psoc, + CFG_ENABLE_FW_RTS_PROFILE), + VDEV_CMD)) + hdd_debug("Failed to set RTS_PROFILE"); + + hdd_init_scan_reject_params(hdd_ctx); + ucfg_pmo_flush_gtk_offload_req(vdev); + + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode)) { + sme_ps_disable_auto_ps_timer(mac_handle, link_info->vdev_id); + adapter->send_mode_change = true; + } + wlan_hdd_clear_link_layer_stats(adapter); + + ucfg_dp_reset_cont_txtimeout_cnt(vdev); + + ucfg_dp_nud_reset_tracking(vdev); + hdd_reset_limit_off_chan(adapter); + + if (!is_link_switch) + hdd_reset_sta_keep_alive_interval(link_info, hdd_ctx); + + hdd_cm_print_bss_info(sta_ctx); +} + +#ifdef WLAN_FEATURE_MSCS +void reset_mscs_params(struct wlan_hdd_link_info *link_info) +{ + mlme_set_is_mscs_req_sent(link_info->vdev, false); + link_info->mscs_counter = 0; +} +#endif + +QDF_STATUS +wlan_hdd_cm_issue_disconnect(struct wlan_hdd_link_info *link_info, + enum wlan_reason_code reason, bool sync) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct hdd_station_ctx *sta_ctx; + struct hdd_adapter *adapter = link_info->adapter; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_CM_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + hdd_place_marker(adapter, "TRY TO DISCONNECT", NULL); + reset_mscs_params(link_info); + hdd_conn_set_authenticated(link_info, false); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + qdf_rtpm_sync_resume(); + + wlan_rec_conn_info(link_info->vdev_id, DEBUG_CONN_DISCONNECT, + sta_ctx->conn_info.bssid.bytes, 0, reason); + + if (sync) + status = osif_cm_disconnect_sync(vdev, reason); + else + status = osif_cm_disconnect(adapter->dev, vdev, reason); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_CM_ID); + + return status; +} + +int wlan_hdd_cm_disconnect(struct wiphy *wiphy, + struct net_device *dev, u16 reason) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int ret; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + if (hdd_ctx->is_wiphy_suspended) { + hdd_info_rl("wiphy is suspended retry disconnect"); + return -EAGAIN; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_DISCONNECT, + link_info->vdev_id, reason); + + hdd_print_netdev_txq_status(dev); + + if (reason == WLAN_REASON_DEAUTH_LEAVING) + qdf_dp_trace_dump_all( + WLAN_DEAUTH_DPTRACE_DUMP_COUNT, + QDF_TRACE_DEFAULT_PDEV_ID); + /* + * for Supplicant initiated disconnect always wait for complete, + * as for WPS connection or back to back connect, supplicant initiate a + * disconnect which is followed by connect and if kernel is not yet + * disconnected, this new connect will be rejected by kernel with status + * EALREADY. In case connect is rejected with EALREADY, supplicant will + * queue one more disconnect followed by connect immediately, Now if + * driver is not disconnected by this time, the kernel will again reject + * connect and thus the failing the connect req in supplicant. + * Thus we need to wait for disconnect to complete in this case, + * and thus use sync API here. + */ + status = wlan_hdd_cm_issue_disconnect(link_info, reason, true); + + return qdf_status_to_os_return(status); +} + +static QDF_STATUS +hdd_cm_disconnect_complete_pre_user_update(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + adapter = link_info->adapter; + hdd_conn_set_authenticated(link_info, false); + hdd_napi_serialize(0); + hdd_disable_and_flush_mc_addr_list(adapter, pmo_peer_disconnect); + __hdd_cm_disconnect_handler_pre_user_update(link_info); + + hdd_handle_disassociation_event(link_info, &rsp->req.req.bssid); + + wlan_rec_conn_info(link_info->vdev_id, + DEBUG_CONN_DISCONNECT_HANDLER, + rsp->req.req.bssid.bytes, + rsp->req.cm_id, + rsp->req.req.reason_code << 16 | + rsp->req.req.source); + wlan_hdd_set_tx_flow_info(); + /* + * Convert and cache internal reason code in adapter. This can be + * sent to userspace with a vendor event. + */ + adapter->last_disconnect_reason = + osif_cm_mac_to_qca_reason(rsp->req.req.reason_code); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_cm_set_default_wlm_mode - reset the default wlm mode if + * wlm_latency_reset_on_disconnect is set. + *@adapter: adapter pointer + * + * return: None. + */ +static void hdd_cm_set_default_wlm_mode(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool reset; + uint8_t def_level; + uint32_t client_id_bitmap; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + status = ucfg_mlme_cfg_get_wlm_reset(hdd_ctx->psoc, &reset); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get wlm reset flag"); + return; + } + if (!reset) + return; + + status = ucfg_mlme_cfg_get_wlm_level(hdd_ctx->psoc, &def_level); + if (QDF_IS_STATUS_ERROR(status)) + def_level = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL; + + if (hdd_get_multi_client_ll_support(adapter)) { + client_id_bitmap = wlan_hdd_get_client_id_bitmap(adapter); + hdd_debug("client_id_bitmap: 0x%x", client_id_bitmap); + status = wlan_hdd_set_wlm_latency_level(adapter, def_level, + client_id_bitmap, true); + wlan_hdd_deinit_multi_client_info_table(adapter); + } else { + status = + sme_set_wlm_latency_level(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + def_level, 0, false); + if (QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("reset wlm mode %x on disconnection", + def_level); + adapter->latency_level = def_level; + } else { + hdd_err("reset wlm mode failed: %d", status); + } + } +} + +/** + * hdd_cm_reset_udp_qos_upgrade_config() - Reset the threshold for UDP packet + * QoS upgrade. + * @adapter: adapter for which this configuration is to be applied + * + * Return: None + */ +static void hdd_cm_reset_udp_qos_upgrade_config(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool reset; + QDF_STATUS status; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + status = ucfg_mlme_cfg_get_wlm_reset(hdd_ctx->psoc, &reset); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get the wlm reset flag"); + return; + } + + if (reset) { + adapter->upgrade_udp_qos_threshold = QCA_WLAN_AC_BK; + hdd_debug("UDP packets qos upgrade to: %d", + adapter->upgrade_udp_qos_threshold); + } +} + +#ifdef WLAN_FEATURE_11BE +static inline enum eSirMacHTChannelWidth get_max_bw(void) +{ + uint32_t max_bw = wma_get_orig_eht_ch_width(); + + if (max_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) + return eHT_CHANNEL_WIDTH_320MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return eHT_CHANNEL_WIDTH_160MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + return eHT_CHANNEL_WIDTH_80P80MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + return eHT_CHANNEL_WIDTH_80MHZ; + else + return eHT_CHANNEL_WIDTH_40MHZ; +} + +static +void wlan_hdd_re_enable_320mhz_6g_conection(struct hdd_context *hdd_ctx, + enum phy_ch_width assoc_ch_width) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(hdd_ctx->psoc); + if (!mlme_obj) + return; + /* + * Initial connection was in 320 MHz and if via SET_MAX_BANDWIDTH + * command, current channel BW (des_chan->ch_width) gets modified + * to less than 320MHz, driver disables 6 GHz connection by disabling + * support_320mhz_6ghz EHT capability. So, in order to allow + * re-connection (after disconnection) in 320 MHz, also re-enable + * support_320mhz_6ghz EHT capability before disconnect complete. + */ + if (assoc_ch_width == CH_WIDTH_320MHZ) + mlme_obj->cfg.eht_caps.dot11_eht_cap.support_320mhz_6ghz = 1; +} +#else +static inline enum eSirMacHTChannelWidth get_max_bw(void) +{ + uint32_t max_bw = wma_get_vht_ch_width(); + + if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return eHT_CHANNEL_WIDTH_160MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + return eHT_CHANNEL_WIDTH_80P80MHZ; + else if (max_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + return eHT_CHANNEL_WIDTH_80MHZ; + else + return eHT_CHANNEL_WIDTH_40MHZ; +} + +static +void wlan_hdd_re_enable_320mhz_6g_conection(struct hdd_context *hdd_ctx, + enum phy_ch_width assoc_ch_width) +{ +} +#endif + +static void hdd_cm_restore_ch_width(struct wlan_objmgr_vdev *vdev, + struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct mlme_legacy_priv *mlme_priv; + enum eSirMacHTChannelWidth max_bw; + struct wlan_channel *des_chan; + uint8_t link_id = 0xFF; + int ret; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + enum phy_ch_width assoc_ch_width; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) + return; + + assoc_ch_width = mlme_priv->connect_info.assoc_chan_info.assoc_ch_width; + if (!ucfg_mlme_is_chwidth_with_notify_supported(hdd_ctx->psoc) || + assoc_ch_width == CH_WIDTH_INVALID) + return; + + cm_update_associated_ch_info(vdev, false); + + if (des_chan->ch_width != assoc_ch_width) + wlan_hdd_re_enable_320mhz_6g_conection(hdd_ctx, assoc_ch_width); + + max_bw = get_max_bw(); + ret = hdd_set_mac_chan_width(link_info, max_bw, link_id, true); + if (ret) { + hdd_err("vdev %d : fail to set max ch width", vdev_id); + return; + } + + hdd_debug("vdev %d : updated ch width to: %d on disconnection", vdev_id, + max_bw); +} + +static QDF_STATUS +hdd_cm_disconnect_complete_post_user_update(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + adapter = link_info->adapter; + if (adapter->device_mode == QDF_STA_MODE) { + /* Inform FTM TIME SYNC about the disconnection with the AP */ + hdd_ftm_time_sync_sta_state_notify( + adapter, FTM_TIME_SYNC_STA_DISCONNECTED); + } + + /* + * via the SET_MAX_BANDWIDTH command, the upper layer can update channel + * width. The host should update channel bandwidth to the max supported + * bandwidth on disconnection so that post disconnection DUT can + * connect in max BW. + */ + hdd_cm_restore_ch_width(vdev, link_info); + + /* + * same WLM configuration is applicable for all links, So no need to + * restore it while processing disconnection due to link switch. + */ + if (rsp->req.req.source != CM_MLO_LINK_SWITCH_DISCONNECT) + hdd_cm_set_default_wlm_mode(adapter); + + __hdd_cm_disconnect_handler_post_user_update(link_info, vdev, + rsp->req.req.source); + wlan_twt_concurrency_update(hdd_ctx); + hdd_cm_reset_udp_qos_upgrade_config(adapter); + ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, + vdev->vdev_objmgr.vdev_id, 0); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_RUNTIME_PM +static void +wlan_hdd_runtime_pm_wow_disconnect_handler(struct hdd_context *hdd_ctx) +{ + struct hif_opaque_softc *hif_ctx; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + hdd_err("hif_ctx is NULL"); + return; + } + + if (hdd_is_any_sta_connected(hdd_ctx)) { + hdd_debug("active connections: runtime pm prevented: %d", + hdd_ctx->runtime_pm_prevented); + return; + } + + hdd_debug("Runtime allowed : %d", hdd_ctx->runtime_pm_prevented); + qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock); + if (hdd_ctx->runtime_pm_prevented) { + qdf_rtpm_put(QDF_RTPM_PUT, QDF_RTPM_ID_PM_QOS_NOTIFY); + hdd_ctx->runtime_pm_prevented = false; + } + qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock); +} +#else +static void +wlan_hdd_runtime_pm_wow_disconnect_handler(struct hdd_context *hdd_ctx) +{ +} +#endif + +QDF_STATUS hdd_cm_disconnect_complete(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp, + enum osif_cb_type type) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + switch (type) { + case OSIF_PRE_USERSPACE_UPDATE: + return hdd_cm_disconnect_complete_pre_user_update(vdev, rsp); + case OSIF_POST_USERSPACE_UPDATE: + hdd_debug("Wifi disconnected: vdev id %d", + vdev->vdev_objmgr.vdev_id); + wlan_hdd_runtime_pm_wow_disconnect_handler(hdd_ctx); + + return hdd_cm_disconnect_complete_post_user_update(vdev, rsp); + default: + hdd_cm_disconnect_complete_pre_user_update(vdev, rsp); + hdd_cm_disconnect_complete_post_user_update(vdev, rsp); + return QDF_STATUS_SUCCESS; + } +} + +QDF_STATUS hdd_cm_netif_queue_control(struct wlan_objmgr_vdev *vdev, + enum netif_action_type action, + enum netif_reason_type reason) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (!link_info) { + hdd_err("adapter is NULL for vdev %d", wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + wlan_hdd_netif_queue_control(link_info->adapter, action, reason); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_cm_napi_serialize_control(bool action) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + hdd_napi_serialize(action); + + /* reinit scan reject params for napi off (roam abort/ho fail) */ + if (!action) + hdd_init_scan_reject_params(hdd_ctx); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_BOOST_CPU_FREQ_IN_ROAM +QDF_STATUS hdd_cm_perfd_set_cpufreq(bool action) +{ + struct wlan_core_minfreq req; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (unlikely(!hdd_ctx)) { + hdd_err("cannot get hdd_context"); + return QDF_STATUS_E_INVAL; + } + + if (action) { + req.magic = WLAN_CORE_MINFREQ_MAGIC; + req.reserved = 0; /* unused */ + req.coremask = 0x00ff;/* big and little cluster */ + req.freq = 0xfff;/* set to max freq */ + } else { + req.magic = WLAN_CORE_MINFREQ_MAGIC; + req.reserved = 0; /* unused */ + req.coremask = 0; /* not valid */ + req.freq = 0; /* reset */ + } + + hdd_debug("CPU min freq to 0x%x coremask 0x%x", req.freq, req.coremask); + /* the following service function returns void */ + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_CORE_MINFREQ, + &req, sizeof(struct wlan_core_minfreq)); + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coap.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coap.c new file mode 100644 index 0000000000..e227633a30 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coap.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_coap.c + * + * The implementation of CoAP offload configuration + * + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_coap.h" +#include "osif_sync.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_cfg80211_coap.h" + +/** + * __wlan_hdd_cfg80211_coap_offload() - configure CoAP offloading + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to netlink TLV buffer + * @data_len: the length of @data in bytes + * + * Return: An error code or 0 on success. + */ +static int +__wlan_hdd_cfg80211_coap_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int errno; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno != 0) + return errno; + + if (adapter->device_mode != QDF_STA_MODE) + return -ENOTSUPP; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_COAP_ID); + if (!vdev) + return -EINVAL; + + errno = wlan_cfg80211_coap_offload(wiphy, vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_COAP_ID); + return errno; +} + +int wlan_hdd_cfg80211_coap_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_coap_offload(wiphy, wdev, data, data_len); + osif_vdev_sync_op_stop(vdev_sync); + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coap.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coap.h new file mode 100644 index 0000000000..7c15820b4c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coap.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_coap.h + * + * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD + */ + +#ifndef __WLAN_HDD_COAP_H +#define __WLAN_HDD_COAP_H + +#ifdef WLAN_FEATURE_COAP +#include + +/** + * wlan_hdd_cfg80211_coap_offload() - configure CoAP offloading + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to netlink TLV buffer + * @data_len: the length of @data in bytes + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_coap_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +extern const struct nla_policy + coap_offload_policy[QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_MAX + 1]; + +#define FEATURE_COAP_OFFLOAD_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_COAP_OFFLOAD, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_coap_offload, \ + vendor_command_policy(coap_offload_policy, \ + QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_MAX) \ +}, +#else /* WLAN_FEATURE_COAP */ +#define FEATURE_COAP_OFFLOAD_COMMANDS +#endif /* WLAN_FEATURE_COAP */ + +#endif /* __WLAN_HDD_COAP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.c new file mode 100644 index 0000000000..02fd536cce --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_coex_config.c + * + * The implementation of coex configuration + * + */ + +#include "wlan_hdd_main.h" +#include "wmi_unified_param.h" +#include "wlan_hdd_coex_config.h" +#include "qca_vendor.h" +#include "wlan_osif_request_manager.h" +#include "osif_sync.h" +#include "wlan_fwol_ucfg_api.h" + +const struct nla_policy +coex_config_three_way_policy[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1] = { + [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE] = { + .type = NLA_U32}, + [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1] = {.type = NLA_U32}, + [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2] = {.type = NLA_U32}, + [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3] = {.type = NLA_U32}, + [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4] = {.type = NLA_U32}, +}; + +static const uint32_t +config_type_to_wmi_tbl[QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX] = { + [QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET] = + WMI_COEX_CONFIG_THREE_WAY_COEX_RESET, + [QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START] = + WMI_COEX_CONFIG_THREE_WAY_COEX_START, +}; + +/** + * __wlan_hdd_cfg80211_set_coex_config() - set coex configuration + * parameters + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1]; + uint32_t config_type; + struct coex_config_params coex_cfg_params = {0}; + struct wlan_fwol_coex_config config = {0}; + int errno; + QDF_STATUS status; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno != 0) + return errno; + + status = ucfg_fwol_get_coex_config_params(hdd_ctx->psoc, &config); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get coex config params"); + return -EINVAL; + } + if (!config.btc_three_way_coex_config_legacy_enable) { + hdd_err("Coex legacy feature should be enable first"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX, + data, data_len, + coex_config_three_way_policy)) { + hdd_err("Invalid coex config ATTR"); + return -EINVAL; + } + + if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE]) { + hdd_err("coex config - attr config_type failed"); + return -EINVAL; + } + + config_type = nla_get_u32( + tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE]); + if (config_type >= QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX) { + hdd_err("config_type value %d exceeded Max value %d", + config_type, + QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX); + return -EINVAL; + } + coex_cfg_params.config_type = config_type_to_wmi_tbl[config_type]; + if (coex_cfg_params.config_type < + WMI_COEX_CONFIG_THREE_WAY_DELAY_PARA || + coex_cfg_params.config_type > + WMI_COEX_CONFIG_THREE_WAY_COEX_START) { + hdd_err("config_type_wmi val error %d", + coex_cfg_params.config_type); + return -EINVAL; + } + + hdd_debug("config_type %d, config_type_wmi %d", + config_type, coex_cfg_params.config_type); + + if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1]) { + hdd_err("coex config - attr priority1 failed"); + return -EINVAL; + } + coex_cfg_params.config_arg1 = nla_get_u32( + tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1]); + + hdd_debug("priority1 0x%x", coex_cfg_params.config_arg1); + + if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2]) { + hdd_err("coex config - attr priority2 failed"); + return -EINVAL; + } + coex_cfg_params.config_arg2 = nla_get_u32( + tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2]); + + hdd_debug("priority2 0x%x", coex_cfg_params.config_arg2); + + if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3]) { + hdd_err("coex config - attr priority3 failed"); + return -EINVAL; + } + coex_cfg_params.config_arg3 = nla_get_u32( + tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3]); + + hdd_debug("priority3 0x%x", coex_cfg_params.config_arg3); + + if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4]) { + hdd_err("coex config - attr priority4 failed"); + return -EINVAL; + } + coex_cfg_params.config_arg4 = nla_get_u32( + tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4]); + + hdd_debug("priority4 0x%x", coex_cfg_params.config_arg4); + + coex_cfg_params.vdev_id = adapter->deflink->vdev_id; + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex config params"); + return -EINVAL; + } + + return 0; +} + +/** + * wlan_hdd_cfg80211_set_coex_config() - set coex configuration + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_coex_config(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.h new file mode 100644 index 0000000000..5dcd677de0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_coex_config.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_coex_config.h + * + * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG + */ + +#ifndef __WLAN_HDD_COEX_CONFIG_H +#define __WLAN_HDD_COEX_CONFIG_H + +#ifdef FEATURE_COEX_CONFIG +#include + +/** + * wlan_hdd_cfg80211_set_coex_config() - set coex configuration + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to limit off-channel command parameters. + * @data_len: the length in byte of limit off-channel command parameters. + * + * Return: An error code or 0 on success. + */ +int wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +extern const struct nla_policy +coex_config_three_way_policy[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1]; + +#define FEATURE_COEX_CONFIG_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_coex_config, \ + vendor_command_policy(coex_config_three_way_policy, \ + QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX) \ +}, +#else /* FEATURE_COEX_CONFIG */ +#define FEATURE_COEX_CONFIG_COMMANDS +#endif /* FEATURE_COEX_CONFIG */ + +#endif /* __WLAN_HDD_COEX_CONFIG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_concurrency_matrix.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_concurrency_matrix.c new file mode 100644 index 0000000000..d8b17be1cf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_concurrency_matrix.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_concurrency_matrix.c + * + * WLAN concurrency matrix functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include + +#define CDS_MAX_FEATURE_SET 8 +#define MAX_CONCURRENT_MATRIX \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX +#define MATRIX_CONFIG_PARAM_SET_SIZE_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_CONFIG_PARAM_SET_SIZE_MAX + +const struct nla_policy +wlan_hdd_get_concurrency_matrix_policy[MAX_CONCURRENT_MATRIX + 1] = { + [MATRIX_CONFIG_PARAM_SET_SIZE_MAX] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_get_concurrency_matrix() - to retrieve concurrency matrix + * @wiphy: pointer phy adapter + * @wdev: pointer to wireless device structure + * @data: pointer to data buffer + * @data_len: length of data + * + * This routine will give concurrency matrix + * + * Return: int status code + */ +static int +__wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t feature_set_matrix[CDS_MAX_FEATURE_SET] = {0}; + uint8_t i, feature_sets, max_feature_sets; + struct nlattr *tb[MAX_CONCURRENT_MATRIX + 1]; + struct sk_buff *reply_skb; + uint32_t skb_len = NLMSG_HDRLEN; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + + hdd_enter_dev(wdev->netdev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wlan_cfg80211_nla_parse(tb, MAX_CONCURRENT_MATRIX, data, data_len, + wlan_hdd_get_concurrency_matrix_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch max feature set */ + if (!tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]) { + hdd_err("Attr max feature set size failed"); + return -EINVAL; + } + max_feature_sets = nla_get_u32(tb[MATRIX_CONFIG_PARAM_SET_SIZE_MAX]); + hdd_debug("Max feature set size: %d", max_feature_sets); + + /* Fill feature combination matrix */ + feature_sets = 0; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_P2P; + feature_set_matrix[feature_sets++] = WIFI_FEATURE_INFRA | + WIFI_FEATURE_NAN; + /* Add more feature combinations here */ + + feature_sets = QDF_MIN(feature_sets, max_feature_sets); + hdd_debug("Number of feature sets: %d", feature_sets); + hdd_debug("Feature set matrix"); + for (i = 0; i < feature_sets; i++) + hdd_debug("[%d] 0x%02X", i, feature_set_matrix[i]); + + skb_len += sizeof(u32) + sizeof(u32) * feature_sets; + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + if (!reply_skb) { + hdd_err("Feature set matrix: buffer alloc fail"); + return -ENOMEM; + } + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE, + feature_sets) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET, + sizeof(u32) * feature_sets, + feature_set_matrix)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +#undef MAX_CONCURRENT_MATRIX +#undef MATRIX_CONFIG_PARAM_SET_SIZE_MAX + +int wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_concurrency_matrix(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_concurrency_matrix.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_concurrency_matrix.h new file mode 100644 index 0000000000..a8ec3db4bd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_concurrency_matrix.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_CONCURRENCY_MATRIX_H +#define __WLAN_HDD_CONCURRENCY_MATRIX_H + +/** + * DOC: wlan_hdd_concurrency_matrix_h + * + * WLAN Host Device Driver concurrency matrix API specification + */ + +#ifdef FEATURE_CONCURRENCY_MATRIX + +extern const struct nla_policy +wlan_hdd_get_concurrency_matrix_policy[ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX + 1]; + +/** + * wlan_hdd_cfg80211_get_concurrency_matrix() - get concurrency matrix + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Retrieves the concurrency feature set matrix + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_get_concurrency_matrix(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_CONCURRENCY_MATRIX_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX,\ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,\ + .doit = wlan_hdd_cfg80211_get_concurrency_matrix, \ + vendor_command_policy(wlan_hdd_get_concurrency_matrix_policy, \ + QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX)\ +}, +#else /* FEATURE_CONCURRENCY_MATRIX */ +#define FEATURE_CONCURRENCY_MATRIX_VENDOR_COMMANDS +#endif /* FEATURE_CONCURRENCY_MATRIX */ + +#endif /* __WLAN_HDD_CONCURRENCY_MATRIX_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_connectivity_logging.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_connectivity_logging.c new file mode 100644 index 0000000000..b6f34e3452 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_connectivity_logging.c @@ -0,0 +1,1375 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: wlan_hdd_connectivity_logging.c + * + * Implementation for the Common connectivity and roam logging api. + */ + +#include "wlan_hdd_connectivity_logging.h" + +#define GET_ATTR_OFFSET(member) \ + qdf_offsetof(struct wlan_log_record, member) + +#define ATTR_GET_VALUE(type, record, field_offset) \ + (*(type *)((uint8_t *)record + field_offset)) + +/** + * struct connectivity_log_attr - Connectivity logging attribute info + * @attribute_id: Vendor attribute ID. Defined by enum qca_wlan_vendor_attr_diag + * @attribute_type: NL type of the attribute + * @attribute_length: Length of the attribute + * @field_offset: Field offset + */ +struct connectivity_log_attr { + enum qca_wlan_vendor_attr_diag attribute_id; + uint8_t attribute_type; + uint16_t attribute_length; + uint16_t field_offset; +}; + +static const enum qca_vendor_attr_diag_event_type +hdd_connectivity_log_attr_table[WLAN_TAG_MAX] = { + [WLAN_CONNECTING] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING, + [WLAN_CONNECTING_FAIL] = + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING_FAIL, + [WLAN_AUTH_REQ] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_AUTH_REQ, + [WLAN_AUTH_RESP] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_AUTH_RESP, + [WLAN_ASSOC_REQ] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ASSOC_REQ, + [WLAN_ASSOC_RSP] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ASSOC_RESP, + [WLAN_REASSOC_REQ] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_REASSOC_REQ, + [WLAN_REASSOC_RSP] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_REASSOC_RES, + [WLAN_DEAUTH_RX] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DEAUTH_RX, + [WLAN_DEAUTH_TX] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DEAUTH_TX, + [WLAN_DISASSOC_RX] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DISASSOC_RX, + [WLAN_DISASSOC_TX] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DISASSOC_TX, + [WLAN_DISCONN_BMISS] = + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BEACON_LOSS_DISCONN, + [WLAN_ROAM_SCAN_START] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCAN_START, + [WLAN_ROAM_SCAN_DONE] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCAN_DONE, + [WLAN_ROAM_SCORE_CURR_AP] = + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCORE_CURR_AP, + [WLAN_ROAM_SCORE_CAND_AP] = + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCORE_CAND_AP, + [WLAN_ROAM_RESULT] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_RESULT, + [WLAN_ROAM_CANCEL] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_CANCEL, + [WLAN_BTM_REQ] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_REQ, + [WLAN_BTM_QUERY] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_QUERY, + [WLAN_BTM_RESP] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_RESP, + [WLAN_BTM_REQ_CANDI] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_REQ_CANDI, + [WLAN_ROAM_WTC] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_WTC, + [WLAN_DHCP_DISCOVER] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_DISCOVER, + [WLAN_DHCP_OFFER] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_OFFER, + [WLAN_DHCP_REQUEST] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_REQUEST, + [WLAN_DHCP_ACK] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_ACK, + [WLAN_DHCP_NACK] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_NACK, + [WLAN_EAPOL_M1] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M1, + [WLAN_EAPOL_M2] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M2, + [WLAN_EAPOL_M3] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M3, + [WLAN_EAPOL_M4] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M4, + [WLAN_GTK_M1] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_GTK_M1, + [WLAN_GTK_M2] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_GTK_M2, + [WLAN_EAP_REQUEST] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_REQUEST, + [WLAN_EAP_RESPONSE] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_RESPONSE, + [WLAN_EAP_SUCCESS] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_SUCCESS, + [WLAN_EAP_FAILURE] = QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_FAILURE, +}; + +#define WLAN_CONNECTIVITY_ATTR_END (QCA_WLAN_VENDOR_ATTR_DIAG_MAX + 1) + +static const struct connectivity_log_attr +connectivity_attr_table[QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_MAX + 1] + [WLAN_CONNECTIVITY_ATTR_END] = { + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SSID, NLA_BINARY, + GET_ATTR_OFFSET(conn_info.ssid_len), GET_ATTR_OFFSET(conn_info.ssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID_HINT, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(conn_info.bssid_hint)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FREQ, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(conn_info.freq)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FREQ_HINT, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(conn_info.freq_hint)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_PAIRWISE_SUITE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(conn_info.pairwise)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_AKM, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(conn_info.akm)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_GROUP_SUITE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(conn_info.group)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_GROUP_MGMT_SUITE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(conn_info.group_mgmt)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_AUTH_ALGO, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(conn_info.auth_type)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BT_COEX_ACTIVE, NLA_FLAG, sizeof(uint8_t), + GET_ATTR_OFFSET(conn_info.is_bt_coex_active)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING_FAIL] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FREQ, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(conn_info.freq)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(conn_info.conn_status)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_AUTH_REQ] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_AUTH_ALGO, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.auth_algo)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SAE_AUTH_FRAME_TYPE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.auth_type)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_STATUS_CODE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IS_RETRY_FRAME, NLA_FLAG, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.is_retry_frame)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_AUTH_RESP] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_AUTH_ALGO, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.auth_algo)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SAE_AUTH_FRAME_TYPE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.auth_type)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_STATUS_CODE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ASSOC_REQ] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IS_RETRY_FRAME, NLA_FLAG, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.is_retry_frame)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ASSOC_RESP] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_STATUS_CODE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ASSOC_ID, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.assoc_id)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_REASSOC_REQ] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IS_RETRY_FRAME, NLA_FLAG, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.is_retry_frame)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_REASSOC_RES] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_STATUS_CODE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ASSOC_ID, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.assoc_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DEAUTH_RX] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DEAUTH_TX] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DISASSOC_RX] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DISASSOC_TX] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_SEQUENCE_NUMBER, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.seq_num)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BEACON_LOSS_DISCONN] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(pkt_info.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.frame_status_code)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCAN_START] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_TRIGGER_REASON, NLA_U8, + sizeof(uint8_t), GET_ATTR_OFFSET(roam_trig.trigger_reason)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_TRIGGER_SUB_REASON, NLA_U8, + sizeof(uint8_t), GET_ATTR_OFFSET(roam_trig.trigger_sub_reason)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(roam_trig.current_rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_CU, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(roam_trig.cu_load)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_SCAN_TYPE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(roam_trig.is_full_scan)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_RSSI_THRESHOLD, NLA_S32, + sizeof(int32_t), GET_ATTR_OFFSET(roam_trig.rssi_threshold)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCAN_DONE] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_AP_COUNT, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(roam_scan.cand_ap_count)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_FREQ_LIST, NLA_NESTED, sizeof(uint16_t), + GET_ATTR_OFFSET(roam_scan.scan_freq)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BT_COEX_ACTIVE, NLA_FLAG, sizeof(uint8_t), + GET_ATTR_OFFSET(roam_scan.is_btcoex_active)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCORE_CURR_AP] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(ap.cand_bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FREQ, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(ap.freq)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(ap.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_CU, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(ap.cu_load)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_SCORE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(ap.total_score)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCORE_CAND_AP] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_AP_RANK, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(ap.idx)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_CU, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(ap.cu_load)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(ap.cand_bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FREQ, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(ap.freq)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_RSSI, NLA_S32, sizeof(int32_t), + GET_ATTR_OFFSET(ap.rssi)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_SCORE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(ap.total_score)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_AP_ETP, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(ap.etp)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_RESULT] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_SUCCESSFUL, NLA_FLAG, + sizeof(uint8_t), GET_ATTR_OFFSET(roam_result.is_roam_successful)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_CANCEL] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(roam_result.roam_fail_reason)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_QUERY] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_TOKEN, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.token)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_QUERY_REASON, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.reason)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_REQ] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_TOKEN, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.token)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_MODE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.mode)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_DISASSOC_TIMER, NLA_U16, + sizeof(uint16_t), GET_ATTR_OFFSET(btm_info.disassoc_timer)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_VALIDITY_INTERVAL, NLA_U8, + sizeof(uint8_t), GET_ATTR_OFFSET(btm_info.validity_timer)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_CANDIDATE_LIST_COUNT, NLA_U8, + sizeof(uint8_t), GET_ATTR_OFFSET(btm_info.candidate_list_count)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_WTC] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_REASON_CODE, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(btm_info.reason)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_WTC_SUB_REASON_CODE, NLA_U8, + sizeof(uint8_t), GET_ATTR_OFFSET(btm_info.sub_reason)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_WTC_DURATION, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(btm_info.wtc_duration)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_REQ_CANDI] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_AP_RANK, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_cand.idx)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BSSID, NLA_BINARY, QDF_MAC_ADDR_SIZE, + GET_ATTR_OFFSET(btm_cand.bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_PREFERENCE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_cand.preference)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_BTM_RESP] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_TOKEN, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.token)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_STATUS_CODE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.btm_status_code)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_DELAY, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(btm_info.btm_delay)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_BTM_TARGET_BSSID, NLA_BINARY, + QDF_MAC_ADDR_SIZE, GET_ATTR_OFFSET(btm_info.target_bssid)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_DISCOVER] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_OFFER] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_REQUEST] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_ACK] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_DHCP_NACK] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M1] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M2] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M3] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAPOL_M4] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_GTK_M1] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_GTK_M2] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP, NLA_U64, + sizeof(uint64_t), GET_ATTR_OFFSET(fw_timestamp_us)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_REQUEST] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_EAP_TYPE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.eap_type)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_EAP_LEN, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.eap_len)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_RESPONSE] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_EAP_TYPE, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.eap_type)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_EAP_LEN, NLA_U16, sizeof(uint16_t), + GET_ATTR_OFFSET(pkt_info.eap_len)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(pkt_info.tx_status)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_SUCCESS] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, + + [QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_EAP_FAILURE] = { + {QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, NLA_U32, sizeof(uint32_t), + GET_ATTR_OFFSET(log_subtype)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_HOST_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(timestamp_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_KERNEL_TIMESTAMP, NLA_U64, sizeof(uint64_t), + GET_ATTR_OFFSET(ktime_us)}, + {QCA_WLAN_VENDOR_ATTR_DIAG_IFINDEX, NLA_U8, sizeof(uint8_t), + GET_ATTR_OFFSET(vdev_id)}, + {WLAN_CONNECTIVITY_ATTR_END, 0, 0, 0}, + }, +}; + +#ifdef WLAN_FEATURE_CONNECTIVITY_LOGGING +static enum qca_roam_reason +wlan_hdd_convert_roam_reason(enum roam_trigger_reason roam_reason) +{ + switch (roam_reason) { + case ROAM_TRIGGER_REASON_PER: + return QCA_ROAM_REASON_PER; + case ROAM_TRIGGER_REASON_BMISS: + return QCA_ROAM_REASON_BEACON_MISS; + case ROAM_TRIGGER_REASON_LOW_RSSI: + return QCA_ROAM_REASON_POOR_RSSI; + case ROAM_TRIGGER_REASON_HIGH_RSSI: + return QCA_ROAM_REASON_BETTER_RSSI; + case ROAM_TRIGGER_REASON_PERIODIC: + return QCA_ROAM_REASON_PERIODIC_TIMER; + case ROAM_TRIGGER_REASON_DENSE: + return QCA_ROAM_REASON_CONGESTION; + case ROAM_TRIGGER_REASON_BACKGROUND: + return QCA_ROAM_REASON_BACKGROUND_SCAN; + case ROAM_TRIGGER_REASON_FORCED: + return QCA_ROAM_REASON_USER_TRIGGER; + case ROAM_TRIGGER_REASON_BTM: + return QCA_ROAM_REASON_BTM; + case ROAM_TRIGGER_REASON_BSS_LOAD: + return QCA_ROAM_REASON_BSS_LOAD; + case ROAM_TRIGGER_REASON_DEAUTH: + return QCA_ROAM_REASON_DISCONNECTION; + case ROAM_TRIGGER_REASON_IDLE: + return QCA_ROAM_REASON_IDLE; + case ROAM_TRIGGER_REASON_WTC_BTM: + return QCA_ROAM_REASON_WTC; + case ROAM_TRIGGER_REASON_BTC: + return QCA_ROAM_REASON_BT_ACTIVITY; + default: + break; + } + + return QCA_ROAM_REASON_UNKNOWN; +} + +static enum qca_roam_scan_scheme +wlan_hdd_convert_roam_scan_type(uint8_t roam_scan_type) +{ + if (roam_scan_type) + return QCA_ROAM_SCAN_SCHEME_FULL_SCAN; + + return QCA_ROAM_SCAN_SCHEME_PARTIAL_SCAN; +} + +static enum qca_roam_sub_reason +wlan_hdd_get_converted_roam_sub_reason(enum roam_trigger_sub_reason sub_reason) +{ + switch (sub_reason) { + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER: + return QCA_ROAM_SUB_REASON_PERIODIC_TIMER; + + case ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI: + return QCA_ROAM_SUB_REASON_INACTIVITY_TIMER_LOW_RSSI; + + case ROAM_TRIGGER_SUB_REASON_BTM_DI_TIMER: + return QCA_ROAM_SUB_REASON_BTM_DI_TIMER; + + case ROAM_TRIGGER_SUB_REASON_FULL_SCAN: + return QCA_ROAM_SUB_REASON_FULL_SCAN; + + case ROAM_TRIGGER_SUB_REASON_LOW_RSSI_PERIODIC: + return QCA_ROAM_SUB_REASON_LOW_RSSI_PERIODIC; + + case ROAM_TRIGGER_SUB_REASON_CU_PERIODIC: + return QCA_ROAM_SUB_REASON_CU_PERIODIC; + + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY: + return QCA_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_LOW_RSSI; + + case ROAM_TRIGGER_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU: + return QCA_ROAM_SUB_REASON_PERIODIC_TIMER_AFTER_INACTIVITY_CU; + + case ROAM_TRIGGER_SUB_REASON_INACTIVITY_TIMER_CU: + return QCA_ROAM_SUB_REASON_INACTIVITY_TIMER_CU; + + default: + break; + } + + return 0; +} + +static enum qca_wlan_vendor_tx_status +wlan_hdd_get_converted_tx_status(uint8_t tx_status) +{ + switch (tx_status) { + case QDF_TX_RX_STATUS_FW_DISCARD: + case QDF_TX_RX_STATUS_INVALID: + case QDF_TX_RX_STATUS_DROP: + case QDF_TX_RX_STATUS_DOWNLOAD_SUCC: + case QDF_TX_RX_STATUS_DEFAULT: + default: + return QCA_WLAN_VENDOR_TX_STATUS_FAIL; + case QDF_TX_RX_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TX_STATUS_NO_ACK; + case QDF_TX_RX_STATUS_OK: + return QCA_WLAN_VENDOR_TX_STATUS_ACK; + } + + return QCA_WLAN_VENDOR_TX_STATUS_FAIL; +} + +static uint16_t +wlan_hdd_get_connectivity_log_tlv_len(struct wlan_log_record *rec) +{ + uint16_t j, log_evt_type, len = 0; + enum qca_wlan_vendor_attr_diag attr_id; + + log_evt_type = hdd_connectivity_log_attr_table[rec->log_subtype]; + if (log_evt_type >= (QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_MAX + 1)) + return 0; + + for (j = 0; j < WLAN_CONNECTIVITY_ATTR_END; j++) { + attr_id = + connectivity_attr_table[log_evt_type][j].attribute_id; + if (attr_id == WLAN_CONNECTIVITY_ATTR_END) + break; + + if (log_evt_type == + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING && + attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_FREQ && + !rec->conn_info.freq) + continue; + + if (log_evt_type == + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING && + attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_FREQ_HINT && + !rec->conn_info.freq_hint) + continue; + + if (attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP && + !rec->fw_timestamp_us) + continue; + + if (log_evt_type == + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCAN_DONE && + attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_FREQ_LIST) { + len += nla_total_size( + NLMSG_HDRLEN + + (rec->roam_scan.num_scanned_freq * + sizeof(rec->roam_scan.scan_freq[0]))); + } else { + len += nla_total_size(connectivity_attr_table[ + log_evt_type][j].attribute_length); + } + } + + return len; +} + +static uint16_t +wlan_hdd_get_connectivity_log_event_len(struct wlan_log_record *rec, + uint8_t num_records) +{ + uint16_t len = 0; + uint8_t i; + + for (i = 0; i < num_records; i++) + len += wlan_hdd_get_connectivity_log_tlv_len(&rec[i]); + + return len; +} + +static QDF_STATUS +wlan_hdd_put_connectivity_logging_data(struct sk_buff *skb, + struct wlan_log_record *rec, + struct connectivity_log_attr *attribute) +{ + int errno = 0; + struct qdf_mac_addr bssid = {0}; + enum qca_wlan_vendor_attr_diag attribute_id = + attribute->attribute_id; + uint16_t field_offset = attribute->field_offset; + + switch (attribute_id) { + case QCA_WLAN_VENDOR_ATTR_DIAG_SSID: + errno = nla_put(skb, attribute_id, rec->conn_info.ssid_len, + rec->conn_info.ssid); + + break; + case QCA_WLAN_VENDOR_ATTR_DIAG_BSSID: + bssid = ATTR_GET_VALUE(struct qdf_mac_addr, rec, field_offset); + if (qdf_is_macaddr_zero(&bssid) || + qdf_is_macaddr_broadcast(&bssid)) + break; + + errno = nla_put(skb, attribute_id, QDF_MAC_ADDR_SIZE, + bssid.bytes); + break; + case QCA_WLAN_VENDOR_ATTR_DIAG_BSSID_HINT: + if (qdf_is_macaddr_zero(&rec->conn_info.bssid_hint) || + qdf_is_macaddr_broadcast(&rec->conn_info.bssid_hint)) + break; + + errno = nla_put(skb, attribute_id, QDF_MAC_ADDR_SIZE, + rec->conn_info.bssid_hint.bytes); + break; + case QCA_WLAN_VENDOR_ATTR_DIAG_BTM_TARGET_BSSID: + bssid = ATTR_GET_VALUE(struct qdf_mac_addr, rec, field_offset); + if (qdf_is_macaddr_zero(&bssid) || + qdf_is_macaddr_broadcast(&bssid)) + break; + + errno = nla_put(skb, attribute_id, QDF_MAC_ADDR_SIZE, + bssid.bytes); + break; + default: + break; + } + + if (errno) { + hdd_err_rl("Failed to put attribute_id:%d", + attribute->attribute_id); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +wlan_hdd_fill_roam_scan_frequencies(struct sk_buff *skb, + struct wlan_log_record *rec) +{ + int errno; + struct nlattr *attr, *attr1; + uint8_t i; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + attr = nla_nest_start( + skb, QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_FREQ_LIST); + if (!attr) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < rec->roam_scan.num_scanned_freq; i++) { + attr1 = nla_nest_start(skb, i); + if (!attr1) { + status = QDF_STATUS_E_FAILURE; + break; + } + + errno = nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_DIAG_FREQ, + rec->roam_scan.scan_freq[i]); + if (errno) { + status = qdf_status_from_os_return(errno); + break; + } + + nla_nest_end(skb, attr1); + } + + nla_nest_end(skb, attr); + + return status; +} + +static QDF_STATUS +wlan_hdd_fill_connectivity_logging_data(struct sk_buff *skb, + struct wlan_log_record *rec) +{ + uint8_t i, val8, attr_val8; + enum qca_wlan_vendor_attr_diag attr_id; + enum qca_vendor_attr_diag_event_type evt_type; + struct connectivity_log_attr attr; + QDF_STATUS status; + int errno; + + /* + * Continue to the next event if the Event type is invalid + */ + evt_type = hdd_connectivity_log_attr_table[rec->log_subtype]; + if (evt_type >= (QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_MAX + 1)) + return QDF_STATUS_SUCCESS; + + errno = nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE, + evt_type); + if (errno) + return QDF_STATUS_E_FAILURE; + + /* + * zeroth index in the attribute table is always + * QCA_WLAN_VENDOR_ATTR_DIAG_EVENT_TYPE. So + * start the loop from first index. + */ + for (i = 1; i < WLAN_CONNECTIVITY_ATTR_END; i++) { + attr = connectivity_attr_table[evt_type][i]; + attr_id = attr.attribute_id; + if (attr_id == WLAN_CONNECTIVITY_ATTR_END) + break; + + if (evt_type == QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING && + attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_FREQ && + !rec->conn_info.freq) + continue; + + if (evt_type == QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_CONNECTING && + attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_FREQ_HINT && + !rec->conn_info.freq_hint) + continue; + + if (attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_FIRMWARE_TIMESTAMP && + !rec->fw_timestamp_us) + continue; + + if (evt_type == + QCA_WLAN_VENDOR_DIAG_EVENT_TYPE_ROAM_SCAN_DONE && + attr_id == QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_FREQ_LIST) { + status = wlan_hdd_fill_roam_scan_frequencies(skb, rec); + if (QDF_IS_STATUS_ERROR(status)) + continue; + } + + switch (attr.attribute_type) { + case NLA_U8: + val8 = ATTR_GET_VALUE(uint8_t, rec, attr.field_offset); + attr_val8 = val8; + if (attr.attribute_id == + QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_TRIGGER_SUB_REASON) + attr_val8 = wlan_hdd_get_converted_roam_sub_reason(val8); + else if (attr.attribute_id == + QCA_WLAN_VENDOR_ATTR_DIAG_FRAME_TX_STATUS) + attr_val8 = wlan_hdd_get_converted_tx_status(val8); + else if (attr.attribute_id == + QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_TRIGGER_REASON) + attr_val8 = wlan_hdd_convert_roam_reason(val8); + else if (attr.attribute_id == + QCA_WLAN_VENDOR_ATTR_DIAG_ROAM_SCAN_TYPE) + attr_val8 = wlan_hdd_convert_roam_scan_type(val8); + + errno = nla_put_u8(skb, attr.attribute_id, attr_val8); + break; + case NLA_U16: + errno = nla_put_u16(skb, attr.attribute_id, + ATTR_GET_VALUE(uint16_t, rec, + attr.field_offset)); + break; + case NLA_U32: + errno = nla_put_u32(skb, attr.attribute_id, + ATTR_GET_VALUE(uint32_t, rec, + attr.field_offset)); + break; + case NLA_S32: + errno = nla_put_s32(skb, attr.attribute_id, + ATTR_GET_VALUE(int32_t, rec, + attr.field_offset)); + break; + case NLA_U64: + errno = wlan_cfg80211_nla_put_u64( + skb, attr.attribute_id, + ATTR_GET_VALUE(uint64_t, rec, attr.field_offset)); + break; + case NLA_FLAG: + if (ATTR_GET_VALUE(bool, rec, attr.field_offset)) + errno = nla_put_flag(skb, attr.attribute_id); + break; + case NLA_BINARY: + status = wlan_hdd_put_connectivity_logging_data( + skb, rec, &attr); + if (QDF_IS_STATUS_ERROR(status)) + return status; + break; + default: + break; + } + } + + if (errno) { + hdd_err_rl("NLA put failed for attr:%d", + attr.attribute_id); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_send_connectivity_log_to_user - Send the connectivity log buffer + * to userspace + * @rec: Pointer to the log record + * @hdd_context: HDD global context + * @num_records: Number of records + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_hdd_send_connectivity_log_to_user(struct wlan_log_record *rec, + void *hdd_context, + uint8_t num_records) +{ + struct hdd_context *hdd_ctx; + struct nlattr *attr, *attr1; + struct sk_buff *vendor_event; + uint16_t len, i = 0; + QDF_STATUS status; + + hdd_enter(); + + hdd_ctx = hdd_context; + if (wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_FAILURE; + + len = wlan_hdd_get_connectivity_log_event_len(rec, num_records); + + vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, len + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_DIAG_EVENT_INDEX, + GFP_ATOMIC); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + attr = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_DIAG_EVENT); + if (!attr) + goto failure; + + for (i = 0; i < num_records; i++) { + attr1 = nla_nest_start(vendor_event, i); + if (!attr1) + goto failure; + + status = wlan_hdd_fill_connectivity_logging_data(vendor_event, + &rec[i]); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to fill fat idx:%d subtype:%d", + i, rec[i].log_subtype); + goto failure; + } + + nla_nest_end(vendor_event, attr1); + } + + nla_nest_end(vendor_event, attr); + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +failure: + hdd_err("NLA fill failed num_records:%d", num_records); + wlan_cfg80211_vendor_free_skb(vendor_event); + + return QDF_STATUS_E_FAILURE; +} + +void wlan_hdd_start_connectivity_logging(struct hdd_context *hdd_ctx) +{ + struct wlan_cl_osif_cbks hdd_cb; + + hdd_cb.wlan_connectivity_log_send_to_usr = + wlan_hdd_send_connectivity_log_to_user; + wlan_connectivity_logging_start(hdd_ctx->psoc, &hdd_cb, hdd_ctx); +} +#endif + +#ifdef CONNECTIVITY_DIAG_EVENT +static enum wlan_diag_connect_fail_reason +wlan_hdd_convert_con_fail_reason_to_diag_reason( + enum wlan_cm_connect_fail_reason reason) +{ + switch (reason) { + case CM_NO_CANDIDATE_FOUND: + return WLAN_DIAG_NO_CANDIDATE_FOUND; + case CM_ABORT_DUE_TO_NEW_REQ_RECVD: + return WLAN_DIAG_ABORT_DUE_TO_NEW_REQ_RECVD; + case CM_BSS_SELECT_IND_FAILED: + return WLAN_DIAG_BSS_SELECT_IND_FAILED; + case CM_PEER_CREATE_FAILED: + return WLAN_DIAG_PEER_CREATE_FAILED; + case CM_JOIN_FAILED: + return WLAN_DIAG_JOIN_FAILED; + case CM_JOIN_TIMEOUT: + return WLAN_DIAG_JOIN_TIMEOUT; + case CM_AUTH_FAILED: + return WLAN_DIAG_AUTH_FAILED; + case CM_AUTH_TIMEOUT: + return WLAN_DIAG_AUTH_TIMEOUT; + case CM_ASSOC_FAILED: + return WLAN_DIAG_ASSOC_FAILED; + case CM_ASSOC_TIMEOUT: + return WLAN_DIAG_ASSOC_TIMEOUT; + case CM_HW_MODE_FAILURE: + return WLAN_DIAG_HW_MODE_FAILURE; + case CM_SER_FAILURE: + return WLAN_DIAG_SER_FAILURE; + case CM_SER_TIMEOUT: + return WLAN_DIAG_SER_TIMEOUT; + case CM_GENERIC_FAILURE: + return WLAN_DIAG_GENERIC_FAILURE; + case CM_VALID_CANDIDATE_CHECK_FAIL: + return WLAN_DIAG_VALID_CANDIDATE_CHECK_FAIL; + default: + hdd_err("Invalid connect fail reason code"); + } + + return WLAN_DIAG_UNSPECIFIC_REASON; +} + +void +wlan_hdd_connectivity_fail_event(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_connect); + + qdf_mem_zero(&wlan_diag_event, sizeof(struct wlan_diag_connect)); + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE) + return; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) || + wlan_vdev_mlme_is_mlo_link_vdev(vdev))) + return; + + wlan_diag_event.diag_cmn.vdev_id = wlan_vdev_get_id(vdev); + + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + wlan_diag_event.subtype = WLAN_CONN_DIAG_CONNECT_FAIL_EVENT; + qdf_mem_copy(wlan_diag_event.diag_cmn.bssid, rsp->bssid.bytes, + QDF_MAC_ADDR_SIZE); + + wlan_diag_event.version = DIAG_CONN_VERSION; + wlan_diag_event.freq = rsp->freq; + wlan_diag_event.reason = + wlan_hdd_convert_con_fail_reason_to_diag_reason(rsp->reason); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_CONN); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_data_stall_detection.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_data_stall_detection.c new file mode 100644 index 0000000000..db85951b5a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_data_stall_detection.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_data_stall_detection.c + * + * WLAN Host Device Driver Data Stall detection API implementation + */ + +#include +#include +#include "wlan_hdd_data_stall_detection.h" +#include "wlan_hdd_main.h" +#include "cdp_txrx_cmn.h" +#include "cdp_txrx_misc.h" +#include "ol_txrx_types.h" +#include "ol_defines.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +/** + * hdd_data_stall_send_event()- send data stall information + * @reason: data stall event subtype + * This Function sends data stall status diag event + * + * Return: void. + */ +static void hdd_data_stall_send_event(uint32_t reason) +{ + WLAN_HOST_DIAG_EVENT_DEF(sta_data_stall, + struct host_event_wlan_datastall); + qdf_mem_zero(&sta_data_stall, sizeof(sta_data_stall)); + sta_data_stall.reason = reason; + hdd_debug("Posting data stall event %x", reason); + WLAN_HOST_DIAG_EVENT_REPORT(&sta_data_stall, EVENT_WLAN_STA_DATASTALL); + + cdp_display_stats(cds_get_context(QDF_MODULE_ID_SOC), + CDP_TXRX_PATH_STATS, + QDF_STATS_VERBOSITY_LEVEL_LOW); +} +#else +static inline void hdd_data_stall_send_event(uint32_t reason) +{ +} +#endif + +/** + * hdd_data_stall_process_event() - Process data stall event + * @msg: data stall message + * + * Process data stall message + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_data_stall_process_event(struct scheduler_msg *msg) +{ + struct data_stall_event_info *data_stall_info; + + if (!msg) + return QDF_STATUS_E_FAILURE; + + data_stall_info = msg->bodyptr; + + hdd_data_stall_send_event(data_stall_info->data_stall_type); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_data_stall_process_cb() - Process data stall message + * @info: data stall message + * + * Process data stall message + * + * Return: void + */ +static void hdd_data_stall_process_cb( + struct data_stall_event_info *info) +{ + struct scheduler_msg msg = {0}; + struct data_stall_event_info *data_stall_event_info; + QDF_STATUS status; + + data_stall_event_info = qdf_mem_malloc(sizeof(*data_stall_event_info)); + if (!data_stall_event_info) + return; + + data_stall_event_info->data_stall_type = info->data_stall_type; + data_stall_event_info->indicator = info->indicator; + data_stall_event_info->pdev_id = info->pdev_id; + data_stall_event_info->recovery_type = info->recovery_type; + data_stall_event_info->vdev_id_bitmap = info->vdev_id_bitmap; + + sys_build_message_header(SYS_MSG_ID_DATA_STALL_MSG, &msg); + /* Save callback and data */ + msg.callback = hdd_data_stall_process_event; + msg.bodyptr = data_stall_event_info; + msg.bodyval = 0; + + status = scheduler_post_message(QDF_MODULE_ID_HDD, + QDF_MODULE_ID_HDD, + QDF_MODULE_ID_SYS, &msg); + + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(data_stall_event_info); +} + +int hdd_register_data_stall_detect_cb(void) +{ + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* Register the data stall callback */ + hdd_debug("Register data stall detect callback"); + status = cdp_data_stall_cb_register(soc, OL_TXRX_PDEV_ID, + hdd_data_stall_process_cb); + return qdf_status_to_os_return(status); +} + +int hdd_deregister_data_stall_detect_cb(void) +{ + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* De-Register the data stall callback */ + hdd_debug("De-Register data stall detect callback"); + status = cdp_data_stall_cb_deregister(soc, OL_TXRX_PDEV_ID, + hdd_data_stall_process_cb); + return qdf_status_to_os_return(status); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.c new file mode 100644 index 0000000000..43fcad98dd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.c @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_dcs.c + * + * DCS implementation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Time(in milliseconds) before which the AP doesn't expect a connection */ +#define HDD_DCS_AWGN_BSS_RETRY_DELAY (5 * 60 * 1000) + +/** + * hdd_dcs_add_bssid_to_reject_list() - add bssid to reject list + * @pdev: pdev ptr + * @bssid: bssid to be added + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_dcs_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *bssid) +{ + struct reject_ap_info ap_info; + + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + qdf_copy_macaddr(&ap_info.bssid, bssid); + /* set retry_delay to reject new connect requests */ + ap_info.rssi_reject_params.retry_delay = + HDD_DCS_AWGN_BSS_RETRY_DELAY; + ap_info.reject_ap_type = DRIVER_RSSI_REJECT_TYPE; + ap_info.reject_reason = REASON_STA_KICKOUT; + ap_info.source = ADDED_BY_DRIVER; + return ucfg_dlm_add_bssid_to_reject_list(pdev, &ap_info); +} + +/** + * hdd_dcs_switch_chan_cb() - hdd dcs switch channel callback + * @vdev: vdev ptr + * @tgt_freq: target channel frequency + * @tgt_width: target channel width + * + * This callback is registered with dcs component to trigger channel switch. + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_dcs_switch_chan_cb(struct wlan_objmgr_vdev *vdev, + qdf_freq_t tgt_freq, + enum phy_ch_width tgt_width) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + mac_handle_t mac_handle; + struct qdf_mac_addr *bssid; + int ret; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("Invalid vdev %d", wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + adapter = link_info->adapter; + switch (adapter->device_mode) { + case QDF_STA_MODE: + if (!hdd_cm_is_vdev_associated(link_info)) + return QDF_STATUS_E_INVAL; + + bssid = &link_info->session.station.conn_info.bssid; + + /* disconnect if got invalid freq or width */ + if (tgt_freq == 0 || tgt_width == CH_WIDTH_INVALID) { + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return QDF_STATUS_E_INVAL; + + hdd_dcs_add_bssid_to_reject_list(pdev, bssid); + wlan_hdd_cm_issue_disconnect(link_info, + REASON_UNSPEC_FAILURE, + true); + return QDF_STATUS_SUCCESS; + } + + mac_handle = hdd_context_get_mac_handle(adapter->hdd_ctx); + if (!mac_handle) + return QDF_STATUS_E_INVAL; + + status = sme_switch_channel(mac_handle, bssid, + tgt_freq, tgt_width); + break; + case QDF_SAP_MODE: + if (!test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) + return QDF_STATUS_E_INVAL; + + /* stop sap if got invalid freq or width */ + if (tgt_freq == 0 || tgt_width == CH_WIDTH_INVALID) { + schedule_work(&adapter->sap_stop_bss_work); + return QDF_STATUS_SUCCESS; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + wlan_hdd_set_sap_csa_reason(psoc, link_info->vdev_id, + CSA_REASON_DCS); + ret = hdd_softap_set_channel_change(adapter->dev, tgt_freq, + tgt_width, true); + status = qdf_status_from_os_return(ret); + break; + default: + hdd_err("OP mode %d not supported", adapter->device_mode); + break; + } + + return status; +} + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +/** + * hdd_get_bw_for_freq - get BW for provided freq + * @res_msg: resp msg with freq info + * @freq: freq for which BW is required + * @total_chan: total no of channels + * + * Return: bandwidth + */ +static enum phy_ch_width +hdd_get_bw_for_freq(struct get_usable_chan_res_params *res_msg, + uint16_t freq, uint16_t total_chan) +{ + uint16_t i; + + for (i = 0; i < total_chan; i++) { + if (res_msg[i].freq == freq) + return res_msg[i].bw; + } + return CH_WIDTH_INVALID; +} + +/** + * hdd_dcs_select_random_chan: To select random 6G channel + * for CSA + * @pdev: pdev object + * @vdev: vdevobject + * + * Return: success/failure + */ +static QDF_STATUS +hdd_dcs_select_random_chan(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + struct get_usable_chan_req_params req_msg; + struct get_usable_chan_res_params *res_msg; + enum phy_ch_width tgt_width; + uint16_t final_lst[NUM_CHANNELS] = {0}; + uint16_t intf_ch_freq = 0; + uint32_t count; + uint32_t i; + QDF_STATUS status = QDF_STATUS_E_EMPTY; + + res_msg = qdf_mem_malloc(NUM_CHANNELS * + sizeof(*res_msg)); + + if (!res_msg) { + hdd_err("res_msg invalid"); + return QDF_STATUS_E_NOMEM; + } + req_msg.band_mask = BIT(REG_BAND_6G); + req_msg.iface_mode_mask = BIT(NL80211_IFTYPE_AP); + req_msg.filter_mask = 0; + status = wlan_reg_get_usable_channel(pdev, req_msg, res_msg, &count, + REG_CURRENT_PWR_MODE); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("get usable channel failed %d", status); + qdf_mem_free(res_msg); + return QDF_STATUS_E_INVAL; + } + hdd_debug("channel count %d for band %d", count, REG_BAND_6G); + for (i = 0; i < count; i++) + final_lst[i] = res_msg[i].freq; + + intf_ch_freq = wlan_get_rand_from_lst_for_freq(final_lst, count); + if (!intf_ch_freq || intf_ch_freq > wlan_reg_max_6ghz_chan_freq()) { + hdd_debug("ch freq gt max 6g freq %d", + wlan_reg_max_6ghz_chan_freq()); + qdf_mem_free(res_msg); + return QDF_STATUS_E_INVAL; + } + tgt_width = hdd_get_bw_for_freq(res_msg, intf_ch_freq, count); + if (tgt_width >= CH_WIDTH_INVALID) { + qdf_mem_free(res_msg); + return QDF_STATUS_E_INVAL; + } + if (tgt_width > CH_WIDTH_160MHZ) { + hdd_debug("restrict max bw to 160"); + tgt_width = CH_WIDTH_160MHZ; + } + qdf_mem_free(res_msg); + return ucfg_dcs_switch_chan(vdev, intf_ch_freq, + tgt_width); +} +#else +static inline QDF_STATUS +hdd_dcs_select_random_chan(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * hdd_dcs_cb() - hdd dcs specific callback + * @psoc: psoc + * @mac_id: mac_id + * @interference_type: wlan or continuous wave interference type + * @arg: List of arguments + * + * This callback is registered with dcs component to start acs operation + * + * Return: None + */ +static void hdd_dcs_cb(struct wlan_objmgr_psoc *psoc, uint8_t mac_id, + uint8_t interference_type, void *arg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)arg; + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_ctx; + uint32_t count; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t index; + QDF_STATUS status; + + /* + * so far CAP_DCS_CWIM interference mitigation is not supported + */ + if (interference_type == WLAN_HOST_DCS_CWIM) { + hdd_debug("CW interference mitigation is not supported"); + return; + } + + if (policy_mgr_is_force_scc(psoc) && + policy_mgr_is_sta_gc_active_on_mac(psoc, mac_id)) { + ucfg_config_dcs_event_data(psoc, mac_id, true); + + hdd_debug("force scc %d, mac id %d sta gc count %d", + policy_mgr_is_force_scc(psoc), mac_id, + policy_mgr_is_sta_gc_active_on_mac(psoc, mac_id)); + return; + } + + count = policy_mgr_get_sap_go_count_on_mac(psoc, list, mac_id); + for (index = 0; index < count; index++) { + link_info = hdd_get_link_info_by_vdev(hdd_ctx, list[index]); + if (!link_info) { + hdd_err("vdev_id %u does not exist with host", + list[index]); + return; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx)) + continue; + + hdd_debug("DCS triggers ACS on vdev_id=%u, mac_id=%u", + list[index], mac_id); + /* + * Select Random channel for low latency sap as + * ACS can't select channel of same MAC from which + * CSA is triggered because same MAC frequencies + * will not be present in scan list and results and + * selecting freq of other MAC may cause MCC with + * other modes if present. + */ + if (wlan_mlme_get_ap_policy(link_info->vdev) != + HOST_CONCURRENT_AP_POLICY_UNSPECIFIED) { + status = hdd_dcs_select_random_chan(hdd_ctx->pdev, + link_info->vdev); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + } + wlan_hdd_cfg80211_start_acs(link_info); + return; + } +} + +#ifdef CONFIG_AFC_SUPPORT +/** + * hdd_dcs_afc_sel_chan_cb() - Callback to select best SAP channel/bandwidth + * after channel state update by AFC + * @arg: argument + * @vdev_id: vdev id of SAP + * @cur_freq: SAP current channel frequency + * @cur_bw: SAP current channel bandwidth + * @pref_bw: pointer to channel bandwidth prefer to set as input and output + * as target bandwidth can set + * + * Return: Target home channel frequency selected + */ +static qdf_freq_t hdd_dcs_afc_sel_chan_cb(void *arg, + uint32_t vdev_id, + qdf_freq_t cur_freq, + enum phy_ch_width cur_bw, + enum phy_ch_width *pref_bw) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)arg; + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_ctx; + qdf_freq_t target_freq; + + if (!hdd_ctx) + return 0; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) + return 0; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) + return 0; + + target_freq = sap_afc_dcs_sel_chan(sap_ctx, cur_freq, cur_bw, pref_bw); + + return target_freq; +} +#else +static inline qdf_freq_t hdd_dcs_afc_sel_chan_cb(void *arg, + uint32_t vdev_id, + qdf_freq_t cur_freq, + enum phy_ch_width cur_bw, + enum phy_ch_width *pref_bw) +{ + return 0; +} +#endif + +void hdd_dcs_register_cb(struct hdd_context *hdd_ctx) +{ + ucfg_dcs_register_cb(hdd_ctx->psoc, hdd_dcs_cb, hdd_ctx); + ucfg_dcs_register_awgn_cb(hdd_ctx->psoc, hdd_dcs_switch_chan_cb); + ucfg_dcs_register_afc_sel_chan_cb(hdd_ctx->psoc, + hdd_dcs_afc_sel_chan_cb, + hdd_ctx); +} + +QDF_STATUS hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + qdf_freq_t dcs_ch_freq) +{ + struct hdd_ap_ctx *ap_ctx; + struct sap_context *sap_ctx; + QDF_STATUS status; + uint8_t mac_id; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t conn_idx, count; + struct wlan_hdd_link_info *link_info; + uint32_t dcs_ch = wlan_reg_freq_to_chan(hdd_ctx->pdev, dcs_ch_freq); + + status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id, + &mac_id); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + return QDF_STATUS_E_INVAL; + } + count = policy_mgr_get_sap_go_count_on_mac(hdd_ctx->psoc, list, mac_id); + + /* + * Dcs can only be enabled after all vdev finish csa. + * Set vdev starting for every vdev before doing csa. + * The CSA triggered by DCS will be done in serial. + */ + for (conn_idx = 0; conn_idx < count; conn_idx++) { + link_info = hdd_get_link_info_by_vdev(hdd_ctx, list[conn_idx]); + if (!link_info) { + hdd_err("vdev_id %u does not exist with host", + list[conn_idx]); + return QDF_STATUS_E_INVAL; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (ap_ctx->operating_chan_freq != dcs_ch_freq) + wlansap_dcs_set_vdev_starting(sap_ctx, true); + else + wlansap_dcs_set_vdev_starting(sap_ctx, false); + } + for (conn_idx = 0; conn_idx < count; conn_idx++) { + link_info = hdd_get_link_info_by_vdev(hdd_ctx, list[conn_idx]); + if (!link_info) { + hdd_err("vdev_id %u does not exist with host", + list[conn_idx]); + return QDF_STATUS_E_INVAL; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (ap_ctx->operating_chan_freq == dcs_ch_freq) + continue; + + hdd_ctx->acs_policy.acs_chan_freq = AUTO_CHANNEL_SELECT; + hdd_debug("dcs triggers old ch:%d new ch:%d", + ap_ctx->operating_chan_freq, dcs_ch_freq); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + link_info->vdev_id, CSA_REASON_DCS); + status = hdd_switch_sap_channel(link_info, dcs_ch, true); + if (status == QDF_STATUS_SUCCESS) + status = QDF_STATUS_E_PENDING; + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_dcs_hostapd_enable_wlan_interference_mitigation() - enable wlan + * interference mitigation + * @hdd_ctx: hdd ctx + * @vdev_id: vdev id + * + * This function is used to enable wlan interference mitigation through + * send dcs command. + * + * Return: None + */ +static void hdd_dcs_hostapd_enable_wlan_interference_mitigation( + struct hdd_context *hdd_ctx, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint8_t mac_id; + struct wlan_hdd_link_info *link_info; + struct hdd_ap_ctx *ap_ctx; + struct sap_context *sap_ctx; + + status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("vdev_id %u does not exist with host", vdev_id); + return; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx) && + !WLAN_REG_IS_24GHZ_CH_FREQ(ap_ctx->operating_chan_freq)) + ucfg_config_dcs_event_data(hdd_ctx->psoc, mac_id, true); +} + +void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter) +{ + qdf_freq_t dcs_freq; + struct hdd_context *hdd_ctx; + uint32_t chan_freq; + struct hdd_ap_ctx *ap_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("Invalid HDD context pointer"); + return; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + dcs_freq = wlansap_dcs_get_freq(ap_ctx->sap_context); + chan_freq = ap_ctx->operating_chan_freq; + if (dcs_freq && dcs_freq != chan_freq) + hdd_dcs_hostapd_set_chan(hdd_ctx, adapter->deflink->vdev_id, + dcs_freq); + else + hdd_dcs_hostapd_enable_wlan_interference_mitigation( + hdd_ctx, adapter->deflink->vdev_id); + + qdf_atomic_set(&ap_ctx->acs_in_progress, 0); +} + +void hdd_dcs_clear(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + uint8_t mac_id; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_psoc *psoc; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct sap_context *sap_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("Invalid HDD context pointer"); + return; + } + + psoc = hdd_ctx->psoc; + + status = policy_mgr_get_mac_id_by_session_id(psoc, + adapter->deflink->vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + return; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (policy_mgr_get_sap_go_count_on_mac(psoc, list, mac_id) <= 1) { + ucfg_config_dcs_disable(psoc, mac_id, WLAN_HOST_DCS_WLANIM); + ucfg_wlan_dcs_cmd(psoc, mac_id, true); + if (wlansap_dcs_is_wlan_interference_mitigation_enabled(sap_ctx)) + ucfg_dcs_clear(psoc, mac_id); + } + + wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, false); + wlansap_dcs_set_vdev_starting(sap_ctx, false); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.h new file mode 100644 index 0000000000..5aceb2f85a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_dcs.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_dcs.h + * + * WLAN Host Device Driver dcs related implementation + * + */ + +#if !defined(WLAN_HDD_DCS_H) +#define WLAN_HDD_DCS_H + +#include + +#ifdef DCS_INTERFERENCE_DETECTION +/** + * hdd_dcs_register_cb() - register dcs callback + * @hdd_ctx: hdd ctx + * + * This function is used to register the HDD callbacks with dcs component + * + * Return: None + */ +void hdd_dcs_register_cb(struct hdd_context *hdd_ctx); + +/** + * hdd_dcs_hostapd_set_chan() - switch sap channel to dcs channel + * @hdd_ctx: hdd ctx + * @vdev_id: vdev id + * @dcs_ch_freq: dcs channel freq + * + * This function is used to switch sap channel to dcs channel using (E)CSA + * + * Return: None + */ +QDF_STATUS hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + qdf_freq_t dcs_ch_freq); + +/** + * hdd_dcs_chan_select_complete() - dcs triggered channel select + * complete handling + * @adapter: hdd adapter pointer + * + * When dcs triggered channel select complete, this function is used to do + * switch sap to new dcs channel or just to enable interference mitigation + * + * Return: None + */ +void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter); + +/** + * hdd_dcs_clear() - clear dcs information + * @adapter: hdd adapter pointer + * + * This function is used to clear sap dcs related information such as + * im stats and freq ctrl params + * + * Return: None + */ +void hdd_dcs_clear(struct hdd_adapter *adapter); +#else +static inline void hdd_dcs_register_cb(struct hdd_context *hdd_ctx) +{ +} + +static inline QDF_STATUS hdd_dcs_hostapd_set_chan(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + qdf_freq_t dcs_ch_freq) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_dcs_chan_select_complete(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_dcs_clear(struct hdd_adapter *adapter) +{ +} +#endif + +#endif /* end #if !defined(WLAN_HDD_DCS_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c new file mode 100644 index 0000000000..5e5a2fb50e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs.c @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs.c + * + * This driver currently supports the following debugfs files: + * wlan_wcnss/wow_enable to enable/disable WoWL. + * wlan_wcnss/wow_pattern to configure WoWL patterns. + * wlan_wcnss/pattern_gen to configure periodic TX patterns. + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_debugfs_unit_test.h" + + +#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8 +#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512 +#define MAX_USER_COMMAND_SIZE_FRAME 4096 + +#define MAX_DEBUGFS_WAIT_ITERATIONS 20 +#define DEBUGFS_WAIT_SLEEP_TIME 100 + +static bool hdd_periodic_pattern_map[MAXNUM_PERIODIC_TX_PTRNS]; + +static qdf_atomic_t debugfs_thread_count; + +void hdd_debugfs_thread_increment(void) +{ + qdf_atomic_inc(&debugfs_thread_count); +} + +void hdd_debugfs_thread_decrement(void) +{ + qdf_atomic_dec(&debugfs_thread_count); +} + +int hdd_return_debugfs_threads_count(void) +{ + return qdf_atomic_read(&debugfs_thread_count); +} + +bool hdd_wait_for_debugfs_threads_completion(void) +{ + int count = MAX_DEBUGFS_WAIT_ITERATIONS; + int r; + + while (count) { + r = hdd_return_debugfs_threads_count(); + if (!r) + break; + + if (--count) { + hdd_debug("Waiting for %d debugfs threads to exit", r); + qdf_sleep(DEBUGFS_WAIT_SLEEP_TIME); + } + } + + /* at least one debugfs thread is executing */ + if (!count) { + hdd_err("Timed-out waiting for debugfs threads"); + return false; + } + + return true; +} + +/** + * __wcnss_wowpattern_write() - wow_pattern debugfs handler + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_wowpattern_write(struct net_device *net_dev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1]; + char *sptr, *token; + uint8_t pattern_idx = 0; + uint8_t pattern_offset = 0; + char *pattern_buf; + char *pattern_mask; + int ret; + + hdd_enter(); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (!sme_is_feature_supported_by_fw(WOW)) { + hdd_err("Wake-on-Wireless feature is not supported in firmware!"); + return -EINVAL; + } + + if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN) { + hdd_err("Command length is larger than %d bytes", + MAX_USER_COMMAND_SIZE_WOWL_PATTERN); + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(cmd, buf, count)) + return -EFAULT; + cmd[count] = '\0'; + sptr = cmd; + + /* Get pattern idx */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + if (kstrtou8(token, 0, &pattern_idx)) + return -EINVAL; + + /* Get pattern offset */ + token = strsep(&sptr, " "); + + /* Delete pattern if no further argument */ + if (!token) { + hdd_del_wowl_ptrn_debugfs(adapter, pattern_idx); + + return count; + } + + if (kstrtou8(token, 0, &pattern_offset)) + return -EINVAL; + + /* Get pattern */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + pattern_buf = token; + + /* Get pattern mask */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + pattern_mask = token; + pattern_mask[strlen(pattern_mask) - 1] = '\0'; + + hdd_add_wowl_ptrn_debugfs(adapter, pattern_idx, pattern_offset, + pattern_buf, pattern_mask); + hdd_exit(); + return count; +} + +/** + * wcnss_wowpattern_write() - SSR wrapper for __wcnss_wowpattern_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_wowpattern_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wcnss_wowpattern_write(net_dev, buf, count, ppos); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +/** + * __wcnss_patterngen_write() - pattern_gen debugfs handler + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wcnss_patterngen_write(struct net_device *net_dev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams; + tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams; + + char *cmd, *sptr, *token; + uint8_t pattern_idx = 0; + uint8_t pattern_duration = 0; + char *pattern_buf; + uint16_t pattern_len = 0; + uint16_t i = 0; + QDF_STATUS status; + int ret; + + hdd_enter(); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) { + hdd_err("Periodic Tx Pattern Offload feature is not supported in firmware!"); + return -EINVAL; + } + + /* Get command from user */ + if (count <= MAX_USER_COMMAND_SIZE_FRAME) + cmd = qdf_mem_malloc(count + 1); + else { + hdd_err("Command length is larger than %d bytes", + MAX_USER_COMMAND_SIZE_FRAME); + + return -EINVAL; + } + + if (!cmd) { + hdd_err("Memory allocation for cmd failed!"); + return -ENOMEM; + } + + if (copy_from_user(cmd, buf, count)) { + qdf_mem_free(cmd); + return -EFAULT; + } + cmd[count] = '\0'; + sptr = cmd; + + /* Get pattern idx */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + if (kstrtou8(token, 0, &pattern_idx)) + goto failure; + + if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1)) { + hdd_err("Pattern index: %d is not in the range (0 ~ %d)", + pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1); + + goto failure; + } + + /* Get pattern duration */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + if (kstrtou8(token, 0, &pattern_duration)) + goto failure; + + /* Delete pattern using index if duration is 0 */ + if (!pattern_duration) { + if (!hdd_periodic_pattern_map[pattern_idx]) { + hdd_debug_rl("WoW pattern %d is not in the table.", + pattern_idx); + + qdf_mem_free(cmd); + return -EINVAL; + } + + delPeriodicTxPtrnParams = + qdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn)); + if (!delPeriodicTxPtrnParams) { + qdf_mem_free(cmd); + return -ENOMEM; + } + + delPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + qdf_copy_macaddr(&delPeriodicTxPtrnParams->mac_address, + &adapter->mac_addr); + + /* Delete pattern */ + status = sme_del_periodic_tx_ptrn(hdd_ctx->mac_handle, + delPeriodicTxPtrnParams); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_del_periodic_tx_ptrn() failed!"); + + qdf_mem_free(delPeriodicTxPtrnParams); + goto failure; + } + + hdd_periodic_pattern_map[pattern_idx] = false; + + qdf_mem_free(cmd); + qdf_mem_free(delPeriodicTxPtrnParams); + return count; + } + + /* + * In SAP mode allow configuration without any connection check + * In STA mode check if it's in connected state before adding + * patterns + */ + hdd_debug("device mode %d", adapter->device_mode); + if ((QDF_STA_MODE == adapter->device_mode) && + (!hdd_cm_is_vdev_associated(adapter->deflink))) { + hdd_err("Not in Connected state!"); + goto failure; + } + + /* Get pattern */ + token = strsep(&sptr, " "); + if (!token) + goto failure; + + pattern_buf = token; + pattern_buf[strlen(pattern_buf) - 1] = '\0'; + pattern_len = strlen(pattern_buf); + + /* Since the pattern is a hex string, 2 characters represent 1 byte. */ + if (pattern_len % 2) { + hdd_err("Malformed pattern!"); + + goto failure; + } else + pattern_len >>= 1; + + if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE) { + hdd_err("Not an 802.3 frame!"); + + goto failure; + } + + addPeriodicTxPtrnParams = qdf_mem_malloc(sizeof(tSirAddPeriodicTxPtrn)); + if (!addPeriodicTxPtrnParams) { + qdf_mem_free(cmd); + return -ENOMEM; + } + + addPeriodicTxPtrnParams->ucPtrnId = pattern_idx; + addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500; + addPeriodicTxPtrnParams->ucPtrnSize = pattern_len; + qdf_copy_macaddr(&addPeriodicTxPtrnParams->mac_address, + &adapter->mac_addr); + + /* Extract the pattern */ + for (i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++) { + addPeriodicTxPtrnParams->ucPattern[i] = + (hex_to_bin(pattern_buf[0]) << 4) + + hex_to_bin(pattern_buf[1]); + + /* Skip to next byte */ + pattern_buf += 2; + } + + /* Add pattern */ + status = sme_add_periodic_tx_ptrn(hdd_ctx->mac_handle, + addPeriodicTxPtrnParams); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_add_periodic_tx_ptrn() failed!"); + + qdf_mem_free(addPeriodicTxPtrnParams); + goto failure; + } + + if (!hdd_periodic_pattern_map[pattern_idx]) + hdd_periodic_pattern_map[pattern_idx] = true; + + qdf_mem_free(cmd); + qdf_mem_free(addPeriodicTxPtrnParams); + hdd_exit(); + return count; + +failure: + hdd_err("Invalid input. Input format is: ptrn_idx duration pattern"); + qdf_mem_free(cmd); + return -EINVAL; +} + +/** + * wcnss_patterngen_write() - SSR wrapper for __wcnss_patterngen_write + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: 0 on success, error number otherwise + */ +static ssize_t wcnss_patterngen_write(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wcnss_patterngen_write(net_dev, buf, count, ppos); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +/** + * __wcnss_debugfs_open() - Generic debugfs open() handler + * @net_dev: net_device context used to register the debugfs file + * + * Return: Errno + */ +static int __wcnss_debugfs_open(struct net_device *net_dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter(); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + + hdd_exit(); + + return errno; +} + +/** + * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open + * @inode: inode pointer + * @file: file pointer + * + * Return: 0 on success, error number otherwise + */ +static int wcnss_debugfs_open(struct inode *inode, struct file *file) +{ + struct net_device *net_dev = inode->i_private; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wcnss_debugfs_open(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static const struct file_operations fops_wowpattern = { + .write = wcnss_wowpattern_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static const struct file_operations fops_patterngen = { + .write = wcnss_patterngen_write, + .open = wcnss_debugfs_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +/** + * hdd_debugfs_init() - Initialize debugfs interface + * @adapter: interface adapter pointer + * + * Register support for the debugfs files supported by the driver. + * + * NB: The current implementation only supports debugfs operations + * on the primary interface, i.e. wlan0 + * + * Return: QDF_STATUS_SUCCESS if all files registered, + * QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) +{ + struct net_device *net_dev = adapter->dev; + + adapter->debugfs_phy = debugfs_create_dir(net_dev->name, 0); + + if (!adapter->debugfs_phy) { + hdd_err("debugfs: create folder %s fail", net_dev->name); + return QDF_STATUS_E_FAILURE; + } + + if (!debugfs_create_file("wow_pattern", 00400 | 00200, + adapter->debugfs_phy, net_dev, + &fops_wowpattern)) + return QDF_STATUS_E_FAILURE; + + if (!debugfs_create_file("pattern_gen", 00400 | 00200, + adapter->debugfs_phy, net_dev, + &fops_patterngen)) + return QDF_STATUS_E_FAILURE; + + if (wlan_hdd_create_mib_stats_file(adapter)) + return QDF_STATUS_E_FAILURE; + + if (wlan_hdd_create_ll_stats_file(adapter)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_debugfs_exit() - Shutdown debugfs interface + * @adapter: interface adapter pointer + * + * Unregister support for the debugfs files supported by the driver. + * + * Return: None + */ +void hdd_debugfs_exit(struct hdd_adapter *adapter) +{ + debugfs_remove_recursive(adapter->debugfs_phy); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_coex.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_coex.c new file mode 100644 index 0000000000..41c8918632 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_coex.c @@ -0,0 +1,671 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_coex.c + * + * This file currently supports the following debugfs: + * Get the following information coex information + * COEX STATE + * COEX DPWB STATE + * COEX TDM STATE + * COEX IDRX STATE + * COEX ANTENNA SHARING STATE + * + * Example to read the COEX STATE logging: + * sm6150:/ # cat /sys/kernel/debug/wlan/mws_coex_state + */ + +#include +#include +#include +#include "wmi_unified.h" +#include "wmi_unified_param.h" +#include "osif_sync.h" + +#define MWS_DEBUGFS_PERMS (QDF_FILE_USR_READ | \ + QDF_FILE_GRP_READ | \ + QDF_FILE_OTH_READ) + +/* wait time for mws coex info in milliseconds */ +#define WLAN_WAIT_TIME_MWS_COEX_INFO 800 + +struct mws_coex_state_priv { + struct mws_coex_state coex_state; +}; + +struct mws_coex_dpwb_state_priv { + struct mws_coex_dpwb_state dpwb_state; +}; + +struct mws_coex_tdm_state_priv { + struct mws_coex_tdm_state tdm_state; +}; + +struct mws_coex_idrx_state_priv { + struct mws_coex_idrx_state idrx_state; +}; + +struct mws_antenna_sharing_info_priv { + struct mws_antenna_sharing_info antenna_sharing; +}; + +static void hdd_debugfs_mws_coex_info_cb(void *coex_info_data, void *context, + wmi_mws_coex_cmd_id cmd_id) +{ + struct osif_request *request = NULL; + struct mws_coex_state_priv *coex_priv; + struct mws_coex_dpwb_state_priv *dpwb_priv; + struct mws_coex_tdm_state_priv *tdm_priv; + struct mws_coex_idrx_state_priv *idrx_priv; + struct mws_antenna_sharing_info_priv *antenna_priv; + + if (!coex_info_data) { + hdd_err("data is null"); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("obsolete request"); + return; + } + + switch (cmd_id) { + case WMI_MWS_COEX_STATE: + coex_priv = osif_request_priv(request); + qdf_mem_copy(&coex_priv->coex_state, coex_info_data, + sizeof(struct mws_coex_state)); + break; + case WMI_MWS_COEX_DPWB_STATE: + dpwb_priv = osif_request_priv(request); + qdf_mem_copy(&dpwb_priv->dpwb_state, coex_info_data, + sizeof(struct mws_coex_dpwb_state)); + break; + case WMI_MWS_COEX_TDM_STATE: + tdm_priv = osif_request_priv(request); + qdf_mem_copy(&tdm_priv->tdm_state, coex_info_data, + sizeof(struct mws_coex_tdm_state)); + break; + case WMI_MWS_COEX_IDRX_STATE: + idrx_priv = osif_request_priv(request); + qdf_mem_copy(&idrx_priv->idrx_state, coex_info_data, + sizeof(struct mws_coex_idrx_state)); + break; + case WMI_MWS_COEX_ANTENNA_SHARING_STATE: + antenna_priv = osif_request_priv(request); + qdf_mem_copy(&antenna_priv->antenna_sharing, coex_info_data, + sizeof(struct mws_antenna_sharing_info)); + break; + } + + osif_request_complete(request); + osif_request_put(request); +} + +static QDF_STATUS __hdd_debugfs_mws_coex_state_read(struct hdd_context *hdd_ctx, + qdf_debugfs_file_t file) +{ + struct hdd_adapter *adapter; + QDF_STATUS status; + int rc; + struct osif_request *request; + struct mws_coex_state *coex_state; + struct mws_coex_state_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_MWS_COEX_INFO, + }; + void *cookie; + + adapter = hdd_get_first_valid_adapter(hdd_ctx); + if (!adapter) { + hdd_err("Failed to get adapter"); + return QDF_STATUS_E_INVAL; + } + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return QDF_STATUS_E_INVAL; + } + + if (file->index > 0) + return QDF_STATUS_SUCCESS; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + cookie = osif_request_cookie(request); + + status = sme_get_mws_coex_info(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WMI_MWS_COEX_STATE, + hdd_debugfs_mws_coex_info_cb, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + rc = qdf_status_to_os_return(status); + goto exit; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + qdf_debugfs_printf(file, "Timedout while retrieving MWS coex state"); + rc = -ETIMEDOUT; + goto exit; + } + + priv = osif_request_priv(request); + coex_state = &priv->coex_state; + + qdf_debugfs_printf(file, "vdev_id = %u\n" + "coex_scheme_bitmap = %u\n" + "active_conflict_count = %u\n" + "potential_conflict_count = %u\n" + "chavd_group0_bitmap = %u\n" + "chavd_group1_bitmap = %u\n" + "chavd_group2_bitmap = %u\n" + "chavd_group3_bitmap = %u\n", + coex_state->vdev_id, + coex_state->coex_scheme_bitmap, + coex_state->active_conflict_count, + coex_state->potential_conflict_count, + coex_state->chavd_group0_bitmap, + coex_state->chavd_group1_bitmap, + coex_state->chavd_group2_bitmap, + coex_state->chavd_group3_bitmap); + +exit: + osif_request_put(request); + return qdf_status_from_os_return(rc); + } + +static QDF_STATUS hdd_debugfs_mws_coex_state_read(qdf_debugfs_file_t file, + void *arg) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = arg; + int ret; + QDF_STATUS status; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return qdf_status_from_os_return(ret); + + status = __hdd_debugfs_mws_coex_state_read(hdd_ctx, file); + + osif_psoc_sync_op_stop(psoc_sync); + return qdf_status_from_os_return(ret); +} + +static QDF_STATUS __hdd_debugfs_mws_coex_dpwb_read(struct hdd_context *hdd_ctx, + qdf_debugfs_file_t file) + { + struct hdd_adapter *adapter; + QDF_STATUS status; + int rc; + struct osif_request *request; + struct mws_coex_dpwb_state *dpwb_state; + struct mws_coex_dpwb_state_priv *dpwb_priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*dpwb_priv), + .timeout_ms = WLAN_WAIT_TIME_MWS_COEX_INFO, + }; + void *cookie; + + adapter = hdd_get_first_valid_adapter(hdd_ctx); + if (!adapter) { + hdd_err("Failed to get adapter"); + return QDF_STATUS_E_INVAL; + } + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return QDF_STATUS_E_INVAL; + } + + if (file->index > 0) + return QDF_STATUS_SUCCESS; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + cookie = osif_request_cookie(request); + + status = sme_get_mws_coex_info(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WMI_MWS_COEX_DPWB_STATE, + hdd_debugfs_mws_coex_info_cb, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + rc = qdf_status_to_os_return(status); + goto exit; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + qdf_debugfs_printf(file, "Timedout while retrieving MWS coex dpwb state"); + rc = -ETIMEDOUT; + goto exit; + } + + dpwb_priv = osif_request_priv(request); + dpwb_state = &dpwb_priv->dpwb_state; + qdf_debugfs_printf(file, "vdev_id = %u\n" + "current_dpwb_state = %d\n" + "pnp1_value = %d\n" + "lte_dutycycle = %d\n" + "sinr_wlan_on = %d\n" + "bler_count = %u\n" + "block_count = %u\n" + "wlan_rssi_level = %u\n" + "wlan_rssi = %d\n" + "is_tdm_running = %u\n", + dpwb_state->vdev_id, + dpwb_state->current_dpwb_state, + dpwb_state->pnp1_value, + dpwb_state->lte_dutycycle, + dpwb_state->sinr_wlan_on, + dpwb_state->sinr_wlan_off, + dpwb_state->bler_count, + dpwb_state->block_count, + dpwb_state->wlan_rssi_level, + dpwb_state->wlan_rssi, + dpwb_state->is_tdm_running); + +exit: + osif_request_put(request); + return qdf_status_from_os_return(rc); +} + +static QDF_STATUS hdd_debugfs_mws_coex_dpwb_read(qdf_debugfs_file_t file, + void *arg) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = arg; + int ret; + QDF_STATUS status; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return qdf_status_from_os_return(ret); + + status = __hdd_debugfs_mws_coex_dpwb_read(hdd_ctx, file); + + osif_psoc_sync_op_stop(psoc_sync); + return qdf_status_from_os_return(ret); +} + +static QDF_STATUS __hdd_debugfs_mws_tdm_state_read(struct hdd_context *hdd_ctx, + qdf_debugfs_file_t file) +{ + struct hdd_adapter *adapter; + QDF_STATUS status; + int rc; + struct mws_coex_tdm_state *tdm_state; + struct mws_coex_tdm_state_priv *tdm_priv; + struct osif_request *request; + static const struct osif_request_params params = { + .priv_size = sizeof(*tdm_priv), + .timeout_ms = WLAN_WAIT_TIME_MWS_COEX_INFO, + }; + void *cookie; + + adapter = hdd_get_first_valid_adapter(hdd_ctx); + if (!adapter) { + hdd_err("Failed to get adapter"); + return QDF_STATUS_E_INVAL; + } + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return QDF_STATUS_E_INVAL; + } + + if (file->index > 0) + return QDF_STATUS_SUCCESS; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + cookie = osif_request_cookie(request); + + status = sme_get_mws_coex_info(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WMI_MWS_COEX_TDM_STATE, + hdd_debugfs_mws_coex_info_cb, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + rc = qdf_status_to_os_return(status); + goto exit; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + qdf_debugfs_printf(file, "Timedout while retrieving MWS coex tdm state"); + rc = -ETIMEDOUT; + goto exit; + } + + tdm_priv = osif_request_priv(request); + tdm_state = &tdm_priv->tdm_state; + + qdf_debugfs_printf(file, "vdev_id = %u\n" + "tdm_policy_bitmap = %u\n" + "tdm_sf_bitmap = %u\n", + tdm_state->vdev_id, + tdm_state->tdm_policy_bitmap, + tdm_state->tdm_sf_bitmap); + +exit: + osif_request_put(request); + return qdf_status_from_os_return(rc); +} + +static QDF_STATUS hdd_debugfs_mws_tdm_state_read(qdf_debugfs_file_t file, + void *arg) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = arg; + int ret; + QDF_STATUS status; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return qdf_status_from_os_return(ret); + + status = __hdd_debugfs_mws_tdm_state_read(hdd_ctx, file); + + osif_psoc_sync_op_stop(psoc_sync); + return qdf_status_from_os_return(ret); +} + +static QDF_STATUS __hdd_debugfs_mws_coex_idrx_read(struct hdd_context *hdd_ctx, + qdf_debugfs_file_t file) +{ + struct hdd_adapter *adapter; + QDF_STATUS status; + int rc; + struct osif_request *request; + struct mws_coex_idrx_state_priv *idrx_priv; + struct mws_coex_idrx_state *idrx_state; + static const struct osif_request_params params = { + .priv_size = sizeof(*idrx_priv), + .timeout_ms = WLAN_WAIT_TIME_MWS_COEX_INFO, + }; + void *cookie; + + adapter = hdd_get_first_valid_adapter(hdd_ctx); + if (!adapter) { + hdd_err("Failed to get adapter"); + return QDF_STATUS_E_INVAL; + } + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return QDF_STATUS_E_INVAL; + } + + if (file->index > 0) + return QDF_STATUS_SUCCESS; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + cookie = osif_request_cookie(request); + + status = sme_get_mws_coex_info(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WMI_MWS_COEX_IDRX_STATE, + hdd_debugfs_mws_coex_info_cb, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + rc = qdf_status_to_os_return(status); + goto exit; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + qdf_debugfs_printf(file, "Timedout while retrieving MWS coex idrx state"); + rc = -ETIMEDOUT; + goto exit; + } + + idrx_priv = osif_request_priv(request); + idrx_state = &idrx_priv->idrx_state; + qdf_debugfs_printf(file, "vdev_id = %u\n" + "sub0_techid = %u\n" + "sub0_policy = %u\n" + "sub0_is_link_critical = %u\n" + "sub0_static_power = %u\n" + "sub0_rssi = %d\n" + "sub1_techid = %d\n" + "sub1_policy = %d\n" + "sub1_is_link_critical = %d\n" + "sub1_static_power = %u\n" + "sub1_rssi = %d\n", + idrx_state->vdev_id, + idrx_state->sub0_techid, + idrx_state->sub0_policy, + idrx_state->sub0_is_link_critical, + idrx_state->sub0_static_power, + idrx_state->sub0_rssi, + idrx_state->sub1_techid, + idrx_state->sub1_policy, + idrx_state->sub1_is_link_critical, + idrx_state->sub1_static_power, + idrx_state->sub1_rssi); + +exit: + osif_request_put(request); + return qdf_status_from_os_return(rc); +} + +static QDF_STATUS hdd_debugfs_mws_coex_idrx_read(qdf_debugfs_file_t file, + void *arg) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = arg; + int ret; + QDF_STATUS status; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return qdf_status_from_os_return(ret); + + status = __hdd_debugfs_mws_coex_idrx_read(hdd_ctx, file); + + osif_psoc_sync_op_stop(psoc_sync); + return qdf_status_from_os_return(ret); +} + +static QDF_STATUS __hdd_debugfs_mws_antenna_sharing_read(struct hdd_context + *hdd_ctx, + qdf_debugfs_file_t + file) +{ + struct hdd_adapter *adapter; + QDF_STATUS status; + int rc; + struct mws_antenna_sharing_info *antenna_sharing; + struct mws_antenna_sharing_info_priv *antenna_priv; + struct osif_request *request; + static const struct osif_request_params params = { + .priv_size = sizeof(*antenna_priv), + .timeout_ms = WLAN_WAIT_TIME_MWS_COEX_INFO, + }; + void *cookie; + + adapter = hdd_get_first_valid_adapter(hdd_ctx); + if (!adapter) { + hdd_err("Failed to get adapter"); + return QDF_STATUS_E_INVAL; + } + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return QDF_STATUS_E_INVAL; + } + + if (file->index > 0) + return QDF_STATUS_SUCCESS; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + + cookie = osif_request_cookie(request); + + status = sme_get_mws_coex_info(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + WMI_MWS_COEX_ANTENNA_SHARING_STATE, + hdd_debugfs_mws_coex_info_cb, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + rc = qdf_status_to_os_return(status); + goto exit; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + qdf_debugfs_printf(file, "Timedout while retrieving MWS coex antenna sharing state"); + rc = -ETIMEDOUT; + goto exit; + } + + antenna_priv = osif_request_priv(request); + antenna_sharing = &antenna_priv->antenna_sharing; + qdf_debugfs_printf(file, "vdev_id = %u\n" + "coex_flags = %u\n" + "coex_config = %u\n" + "tx_chain_mask = %u\n" + "rx_chain_mask = %u\n" + "rx_nss = %u\n" + "force_mrc = %u\n" + "rssi_type = %u\n" + "chain0_rssi = %d\n" + "chain1_rssi = %d\n" + "combined_rssi = %d\n" + "imbalance = %u\n" + "mrc_threshold = %d\n" + "grant_duration = %u\n", + antenna_sharing->vdev_id, + antenna_sharing->coex_flags, + antenna_sharing->coex_config, + antenna_sharing->tx_chain_mask, + antenna_sharing->rx_chain_mask, + antenna_sharing->rx_nss, + antenna_sharing->force_mrc, + antenna_sharing->rssi_type, + antenna_sharing->chain0_rssi, + antenna_sharing->chain1_rssi, + antenna_sharing->combined_rssi, + antenna_sharing->imbalance, + antenna_sharing->mrc_threshold, + antenna_sharing->grant_duration); + +exit: + osif_request_put(request); + return qdf_status_from_os_return(rc); +} + +static QDF_STATUS hdd_debugfs_mws_antenna_sharing_read(qdf_debugfs_file_t file, + void *arg) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = arg; + int ret; + QDF_STATUS status; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return qdf_status_from_os_return(ret); + + status = __hdd_debugfs_mws_antenna_sharing_read(hdd_ctx, file); + + osif_psoc_sync_op_stop(psoc_sync); + return qdf_status_from_os_return(ret); +} + +static struct qdf_debugfs_fops hdd_mws_debugfs_coex_state_fops = { + .show = hdd_debugfs_mws_coex_state_read, +}; + +static struct qdf_debugfs_fops hdd_mws_debugfs_fops_coex_dpwb_fops = { + .show = hdd_debugfs_mws_coex_dpwb_read, +}; + +static struct qdf_debugfs_fops hdd_mws_debugfs_tdm_state_fpos = { + .show = hdd_debugfs_mws_tdm_state_read, +}; + +static struct qdf_debugfs_fops hdd_mws_debugfs_idrx_state_fpos = { + .show = hdd_debugfs_mws_coex_idrx_read, +}; + +static struct qdf_debugfs_fops hdd_mws_debugfs_antenna_sharing_fpos = { + .show = hdd_debugfs_mws_antenna_sharing_read, +}; + +void hdd_debugfs_mws_coex_info_init(struct hdd_context *hdd_ctx) +{ + hdd_mws_debugfs_coex_state_fops.priv = hdd_ctx; + hdd_mws_debugfs_fops_coex_dpwb_fops.priv = hdd_ctx; + hdd_mws_debugfs_tdm_state_fpos.priv = hdd_ctx; + hdd_mws_debugfs_idrx_state_fpos.priv = hdd_ctx; + hdd_mws_debugfs_antenna_sharing_fpos.priv = hdd_ctx; + if (!qdf_debugfs_create_file("mws_coex_state", MWS_DEBUGFS_PERMS, + NULL, &hdd_mws_debugfs_coex_state_fops)) + hdd_err("Failed to create the mws coex state file"); + if (!qdf_debugfs_create_file("mws_coex_dpwb_state", MWS_DEBUGFS_PERMS, + NULL, + &hdd_mws_debugfs_fops_coex_dpwb_fops)) + hdd_err("Failed to create the mws coex dpwb file"); + if (!qdf_debugfs_create_file("mws_coex_tdm_state", MWS_DEBUGFS_PERMS, + NULL, &hdd_mws_debugfs_tdm_state_fpos)) + hdd_err("Failed to create the mws coex tdm file"); + if (!qdf_debugfs_create_file("mws_coex_idrx", MWS_DEBUGFS_PERMS, + NULL, &hdd_mws_debugfs_idrx_state_fpos)) + hdd_err("Failed to create the mws coex idrx file"); + if (!qdf_debugfs_create_file("mws_coex_antenna_sharing", + MWS_DEBUGFS_PERMS, + NULL, + &hdd_mws_debugfs_antenna_sharing_fpos)) + hdd_err("Failed to create the mws coex antenna sharing file"); +} + +void hdd_debugfs_mws_coex_info_deinit(struct hdd_context *hdd_ctx) +{ + /** + * Coex info doesn't have a directory it is removed as part of qdf remove + */ +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_config.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_config.c new file mode 100644 index 0000000000..292c95b1c0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_config.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_config.c + * + * WLAN Host Device Driver implementation to update + * debugfs with ini configs + */ + +#include "wlan_hdd_main.h" +#include "osif_psoc_sync.h" +#include "cfg_ucfg_api.h" +#include "wlan_hdd_debugfs_config.h" + +#define DEBUGFS_CONFIG_BUF_SIZE (4096 * 8) + +/** + * struct ini_config_buf - the buffer struct to save ini configs + * @len: buffer len + * @result: the pointer to buffer + */ +struct ini_config_buf { + ssize_t len; + uint8_t result[DEBUGFS_CONFIG_BUF_SIZE]; +}; + +/** + * wlan_hdd_config_update() - Update userspace with local statistics buffer + * @buf: userspace buffer (to which data is being copied into) + * @count: max data that can be copied into buf + * @pos: offset (where data should be copied into) + * @ini_config: buffer structure for ini config info + * + * This function should copies ini configs into debugfs entry. + * + * Return: number of characters copied; 0 on no-copy + */ +static ssize_t wlan_hdd_config_update(char __user *buf, size_t count, + loff_t *pos, + struct ini_config_buf *ini_config) +{ + ssize_t ret_cnt; + + ret_cnt = simple_read_from_buffer(buf, count, pos, ini_config->result, + ini_config->len); + hdd_debug("ini config read req: count: %zu, pos: %lld", count, *pos); + + return ret_cnt; +} + +/** + * wlan_hdd_config_get() - Function to save ini config to buffer + * @hdd_ctx: hdd context used to register the debugfs file + * @ini_config: buffer structure for ini config info + * + * Return: Errno + */ +static int wlan_hdd_config_get(struct hdd_context *hdd_ctx, + struct ini_config_buf *ini_config) +{ + QDF_STATUS status; + + status = ucfg_cfg_ini_config_print(hdd_ctx->psoc, ini_config->result, + &ini_config->len, + DEBUGFS_CONFIG_BUF_SIZE); + return qdf_status_to_os_return(status); +} + +/** + * __wlan_hdd_read_config_debugfs() - function to get ini conifg + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t __wlan_hdd_read_config_debugfs(struct file *file, + char __user *buf, size_t count, + loff_t *pos) +{ + struct ini_config_buf *ini_config; + ssize_t err_size; + + ini_config = (struct ini_config_buf *)file->private_data; + if (!ini_config) + return -ENOMEM; + + err_size = wlan_hdd_config_update(buf, count, pos, ini_config); + + return err_size; +} + +/** + * wlan_hdd_read_config_debugfs() - wrapper function to get ini conifg + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t wlan_hdd_read_config_debugfs(struct file *file, + char __user *buf, size_t count, + loff_t *pos) +{ + struct hdd_context *hdd_ctx = file_inode(file)->i_private; + struct osif_psoc_sync *psoc_sync; + ssize_t err_size; + + err_size = wlan_hdd_validate_context(hdd_ctx); + if (err_size) + return err_size; + + err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_read_config_debugfs(file, buf, count, pos); + + osif_psoc_sync_op_stop(psoc_sync); + + return err_size; +} + +/** + * __wlan_hdd_open_config_debugfs() - function to open config debugfs + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int __wlan_hdd_open_config_debugfs(struct inode *inode, + struct file *file) +{ + struct hdd_context *hdd_ctx = file_inode(file)->i_private; + struct ini_config_buf *ini_config; + ssize_t errno; + void *buf; + + buf = qdf_mem_malloc(sizeof(*ini_config)); + if (!buf) + return -ENOMEM; + + ini_config = (struct ini_config_buf *)buf; + hdd_nofl_debug("WLAN configuration written to debug log"); + ucfg_cfg_store_print(hdd_ctx->psoc); + errno = wlan_hdd_config_get(hdd_ctx, ini_config); + if (errno) { + qdf_mem_free(buf); + return errno; + } + + file->private_data = buf; + return 0; +} + +/** + * wlan_hdd_open_config_debugfs() - wrapper function to open config debugfs + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_open_config_debugfs(struct inode *inode, struct file *file) +{ + struct hdd_context *hdd_ctx = file_inode(file)->i_private; + struct osif_psoc_sync *psoc_sync; + ssize_t errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_open_config_debugfs(inode, file); + + osif_psoc_sync_op_stop(psoc_sync); + return errno; +} + +/** + * wlan_hdd_release_config_debugfs() - wrapper to release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_release_config_debugfs(struct inode *inode, + struct file *file) +{ + qdf_mem_free(file->private_data); + file->private_data = NULL; + + return 0; +} + +static const struct file_operations fops_config_debugfs = { + .read = wlan_hdd_read_config_debugfs, + .open = wlan_hdd_open_config_debugfs, + .release = wlan_hdd_release_config_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int hdd_debugfs_ini_config_init(struct hdd_context *hdd_ctx) +{ + if (!debugfs_create_file("ini_config", 0444, qdf_debugfs_get_root(), + hdd_ctx, &fops_config_debugfs)) + return -EINVAL; + + return 0; +} + +void hdd_debugfs_ini_config_deinit(struct hdd_context *hdd_ctx) +{ + /* + * Config ini doesn't have a directory it is removed + * as part of qdf remove + */ +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_csr.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_csr.c new file mode 100644 index 0000000000..0173fe7ba7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_csr.c @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_csr.c + * + * WLAN Host Device Driver implementation to update + * debugfs with roaming related information + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include "qwlan_version.h" +#include "wmi_unified_param.h" +#include "wlan_hdd_debugfs.h" + +ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length; + char time_buffer[HDD_TIME_STRING_LEN]; + int ret_val; + + qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buffer, + sizeof(time_buffer)); + ret_val = scnprintf(buf, buf_avail_len, + "\nTime at which this file generated = %s\n", + time_buffer); + if (ret_val < 0) + return 0; + length = ret_val; + + return length; +} + +/** + * wlan_hdd_debugfs_update_csr() - Function to update internal debugfs buffer + * and write into user-space buffer + * @hdd_ctx: hdd context + * @adapter: adapter + * @id: used to identify file for which this info has to be read + * @buf: output buffer to write + * @buf_avail_len: length of the available buffer + * + * Return: Number of bytes read on success, zero otherwise + */ +static ssize_t +wlan_hdd_debugfs_update_csr(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + enum hdd_debugfs_file_id id, + uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t len = 0; + + switch (id) { + case HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO: + /* populate roam scan stats info */ + len = wlan_hdd_debugfs_update_roam_stats(hdd_ctx, adapter, + buf, buf_avail_len); + break; + case HDD_DEBUFS_FILE_ID_OFFLOAD_INFO: + /* populate offload info */ + len = wlan_hdd_debugfs_update_filters_info(hdd_ctx, adapter, + buf, buf_avail_len); + break; + default: + hdd_err("Failed to fetch stats, unknown stats type"); + } + + return len; +} + +/** + * __wlan_hdd_read_debugfs_csr() - Function to read debug stats + * @info: buffer info allocated when the debugfs file was opened + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, zero otherwise + */ +static ssize_t +__wlan_hdd_read_debugfs_csr(struct wlan_hdd_debugfs_buffer_info *info, + char __user *buf, size_t count, loff_t *pos) +{ + struct hdd_adapter *adapter = info->adapter; + struct hdd_context *hdd_ctx; + int ret; + ssize_t length; + + hdd_enter(); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return 0; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return 0; + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return 0; + } + + if (*pos == 0) { + info->length = wlan_hdd_debugfs_update_csr(hdd_ctx, adapter, + info->id, + info->data, + info->max_buf_len); + } + + length = simple_read_from_buffer(buf, count, pos, + info->data, info->length); + hdd_debug("length written = %zu, count: %zu, pos: %lld", + length, count, *pos); + + hdd_exit(); + return length; +} + +/** + * wlan_hdd_read_debugfs_csr() - SSR wrapper function to read stats + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, zero otherwise + */ +static ssize_t +wlan_hdd_read_debugfs_csr(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct wlan_hdd_debugfs_buffer_info *info = file->private_data; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(info->adapter->dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_read_debugfs_csr(info, buf, count, pos); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +/** + * __wlan_hdd_open_debugfs_csr() - Allocates memory for private data + * @adapter: the HDD adapter to operate against + * @csr: file info used to register the debugfs file + * @file: file pointer + * + * Return: Errno + */ +static int __wlan_hdd_open_debugfs_csr(struct hdd_adapter *adapter, + struct hdd_debugfs_file_info *csr, + struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter(); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return -EINVAL; + } + + info = qdf_mem_malloc(sizeof(*info)); + if (!info) + return -ENOMEM; + + info->data = qdf_mem_malloc(csr->buf_max_size); + if (!info->data) { + qdf_mem_free(info); + return -ENOMEM; + } + info->length = 0; + info->max_buf_len = csr->buf_max_size; + info->id = csr->id; + info->adapter = adapter; + + file->private_data = info; + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_open_debugfs_csr() - SSR wrapper function to allocate memory for + * private data on file open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_open_debugfs_csr(struct inode *inode, struct file *file) +{ + struct hdd_debugfs_file_info *csr = inode->i_private; + struct hdd_adapter *adapter = qdf_container_of(csr, struct hdd_adapter, + csr_file[csr->id]); + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return errno; + + hdd_debugfs_thread_increment(); + errno = __wlan_hdd_open_debugfs_csr(adapter, csr, file); + if (errno) + hdd_debugfs_thread_decrement(); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_release_debugfs_csr() - Function to free private memory on + * release + * @file: file pointer + * + * Return: Errno + */ +static int +__wlan_hdd_release_debugfs_csr(struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info = file->private_data; + + hdd_enter(); + + file->private_data = NULL; + qdf_mem_free(info->data); + qdf_mem_free(info); + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_release_debugfs_csr() - SSR wrapper function to free + * private data on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_release_debugfs_csr(struct inode *inode, struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info = file->private_data; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(info->adapter->dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_release_debugfs_csr(file); + hdd_debugfs_thread_decrement(); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static const struct file_operations fops_csr_debugfs = { + .read = wlan_hdd_read_debugfs_csr, + .open = wlan_hdd_open_debugfs_csr, + .release = wlan_hdd_release_debugfs_csr, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter) +{ + struct hdd_debugfs_file_info *csr; + const uint32_t max_len = HDD_DEBUGFS_FILE_NAME_MAX; + + /* + * Create debugfs diagnostic files for connect, offload info + * and roam info and store in csr_file member of adapter + */ + + csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_OFFLOAD_INFO]; + if (!csr->entry) { + strlcpy(csr->name, "offload_info", max_len); + csr->id = HDD_DEBUFS_FILE_ID_OFFLOAD_INFO; + csr->buf_max_size = DEBUGFS_OFFLOAD_INFO_BUF_SIZE; + csr->entry = debugfs_create_file(csr->name, 0444, + adapter->debugfs_phy, + csr, &fops_csr_debugfs); + if (!csr->entry) + hdd_err("Failed to create generic_info debugfs file"); + } + + csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO]; + if (!csr->entry) { + strlcpy(csr->name, "roam_stats", max_len); + csr->id = HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO; + csr->buf_max_size = DEBUGFS_ROAM_SCAN_STATS_INFO_BUF_SIZE; + csr->entry = debugfs_create_file(csr->name, 0444, + adapter->debugfs_phy, + csr, &fops_csr_debugfs); + if (!csr->entry) + hdd_err("Failed to create generic_info debugfs file"); + } +} + +void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter) +{ + uint32_t i; + struct dentry *entry; + + for (i = 0; i < HDD_DEBUGFS_FILE_ID_MAX; i++) { + entry = adapter->csr_file[i].entry; + if (!entry) + continue; + + adapter->csr_file[i].entry = NULL; + debugfs_remove(entry); + entry = NULL; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_llstat.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_llstat.c new file mode 100644 index 0000000000..f066dc915e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_llstat.c @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_llstat.c + * + * WLAN Host Device Driver implementation to update + * debugfs with Link Layer statistics + */ + +#include +#include "osif_sync.h" +#include +#include +#include + +struct ll_stats_buf { + ssize_t len; + uint8_t *result; +}; + +static struct ll_stats_buf ll_stats; + +static DEFINE_MUTEX(llstats_mutex); + +void hdd_debugfs_process_iface_stats(struct wlan_hdd_link_info *link_info, + void *data, uint32_t num_peers) +{ + struct wifi_interface_stats *iface_stat; + struct wifi_interface_info *iface_info; + wmi_iface_link_stats *link_stats; + wmi_wmm_ac_stats *ac_stats; + wmi_iface_offload_stats *offload_stats; + wmi_iface_powersave_stats *powersave_stats; + uint64_t average_tsf_offset; + int i; + ssize_t len = 0; + uint8_t *buffer; + + hdd_enter(); + + mutex_lock(&llstats_mutex); + if (!ll_stats.result) { + mutex_unlock(&llstats_mutex); + hdd_err("LL statistics buffer is NULL"); + return; + } + + iface_stat = data; + buffer = ll_stats.result; + buffer += ll_stats.len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\n\n===LL_STATS_IFACE: num_peers: %d===", num_peers); + + if (!hdd_get_interface_info(link_info, &iface_stat->info)) { + mutex_unlock(&llstats_mutex); + hdd_err("hdd_get_interface_info get fail"); + return; + } + + iface_info = &iface_stat->info; + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nmode: %u, MAC_ADDR: " QDF_MAC_ADDR_FMT ", state: %u," + " roaming: %u, capabilities: %u, SSID: %s," + " BSSID_MAC: " QDF_MAC_ADDR_FMT + ", ap_country_str: %s, country_str: %s", + iface_info->mode, + QDF_MAC_ADDR_REF(&iface_info->macAddr.bytes[0]), + iface_info->state, iface_info->roaming, + iface_info->capabilities, iface_info->ssid, + QDF_MAC_ADDR_REF(&iface_info->bssid.bytes[0]), + iface_info->apCountryStr, iface_info->countryStr); + + link_stats = &iface_stat->link_stats; + average_tsf_offset = link_stats->avg_bcn_spread_offset_high; + average_tsf_offset = (average_tsf_offset << 32) | + link_stats->avg_bcn_spread_offset_low; + + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nbeacon_rx: %u, mgmt_rx: %u, mgmt_action_rx: %u, mgmt_action_tx: %u, rssi_mgmt: %d, rssi_data: %d, rssi_ack: %d, is_leaky_ap: %u, avg_rx_frms_leaked: %u, rx_leak_window: %u, average_tsf_offset: %llu, Tx RTS success count: %u, Tx RTS fail count: %u, Tx ppdu success count: %u, Tx ppdu fail count: %u, Connected duration: %u, Disconnected duration: %u, RTT ranging duration: %u, RTT responder duration: %u, Num tx probes: %u, Num beacon miss: %u, nf_cal %d\n\nNumber of AC: %d", + link_stats->beacon_rx, link_stats->mgmt_rx, + link_stats->mgmt_action_rx, link_stats->mgmt_action_tx, + link_stats->rssi_mgmt, link_stats->rssi_data, + link_stats->rssi_ack, link_stats->is_leaky_ap, + link_stats->avg_rx_frms_leaked, + link_stats->rx_leak_window, average_tsf_offset, + link_stats->tx_rts_succ_cnt, + link_stats->tx_rts_fail_cnt, + link_stats->tx_ppdu_succ_cnt, + link_stats->tx_ppdu_fail_cnt, + link_stats->connected_duration, + link_stats->disconnected_duration, + link_stats->rtt_ranging_duration, + link_stats->rtt_responder_duration, + link_stats->num_probes_tx, link_stats->num_beacon_miss, + link_stats->nf_cal_val, + link_stats->num_ac); + + for (i = 0; i < link_stats->num_ac; i++) { + ac_stats = &iface_stat->ac_stats[i]; + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nac_type: %d, tx_mpdu: %u, rx_mpdu: %u, " + "tx_mcast: %u, rx_mcast: %u, tx_ampdu: %u, " + "rx_ampdu: %u, mpdu_lost: %u, retries: %u, " + "retries_short: %u, retries_long: %u, " + "contention_time: min-%u max-%u avg-%u, " + "contention num samples: %u, " + "tx_pending_msdu: %u", + ac_stats->ac_type, + ac_stats->tx_mpdu, ac_stats->rx_mpdu, + ac_stats->tx_mcast, ac_stats->rx_mcast, + ac_stats->tx_ampdu, ac_stats->rx_ampdu, + ac_stats->mpdu_lost, ac_stats->retries, + ac_stats->retries_short, ac_stats->retries_long, + ac_stats->contention_time_min, + ac_stats->contention_time_max, + ac_stats->contention_time_avg, + ac_stats->contention_num_samples, + ac_stats->tx_pending_msdu); + } + + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\n\nNumber of offload stats: %d", + iface_stat->num_offload_stats); + + for (i = 0; i < iface_stat->num_offload_stats; i++) { + offload_stats = &iface_stat->offload_stats[i]; + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\ntype: %d, rx_count: %u, drp_count: %u, fwd_count: %u", + offload_stats->type, offload_stats->rx_count, + offload_stats->drp_count, + offload_stats->fwd_count); + } + + powersave_stats = &iface_stat->powersave_stats; + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\ntot_tim_bcn: %u tot_err_tim_bcn: %u", + powersave_stats->tot_tim_bcn, + powersave_stats->tot_err_tim_bcn); + + ll_stats.len += len; + mutex_unlock(&llstats_mutex); + hdd_exit(); +} + +void hdd_debugfs_process_peer_stats(struct hdd_adapter *adapter, void *data) +{ + struct wifi_peer_stat *peer_stat; + struct wifi_peer_info *peer_info; + struct wifi_rate_stat *rate_stat; + int i, j, num_rate; + ssize_t len = 0; + uint8_t *buffer; + + hdd_enter(); + + mutex_lock(&llstats_mutex); + if (!ll_stats.result) { + mutex_unlock(&llstats_mutex); + hdd_err("LL statistics buffer is NULL"); + return; + } + + peer_stat = data; + + buffer = ll_stats.result; + buffer += ll_stats.len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\n\n===LL_STATS_PEER_ALL : num_peers %u===", + peer_stat->num_peers); + + peer_info = peer_stat->peer_info; + for (i = 1; i <= peer_stat->num_peers; i++) { + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nType: %d, peer_mac: " QDF_MAC_ADDR_FMT + ", capabilities: %u\nnum_rates: %d", + wmi_to_sir_peer_type(peer_info->type), + QDF_MAC_ADDR_REF(&peer_info->peer_macaddr.bytes[0]), + peer_info->capabilities, peer_info->num_rate); + + num_rate = peer_info->num_rate; + for (j = 0; j < num_rate; j++) { + rate_stat = &peer_info->rate_stats[j]; + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\npreamble: %0x, nss: %0x, bw: %0x, mcs: %0x, bitrate: %0x, txmpdu: %u, rxmpdu: %u, mpdu_lost: %u, retries: %u, retries_short: %u, retries_long: %u", + rate_stat->rate.preamble, rate_stat->rate.nss, + rate_stat->rate.bw, + rate_stat->rate.rate_or_mcs_index, + rate_stat->rate.bitrate, rate_stat->tx_mpdu, + rate_stat->rx_mpdu, rate_stat->mpdu_lost, + rate_stat->retries, rate_stat->retries_short, + rate_stat->retries_long); + } + peer_info = (struct wifi_peer_info *) ((uint8_t *) + peer_stat->peer_info + (i * + sizeof(struct wifi_peer_info)) + + (num_rate * sizeof(struct wifi_rate_stat))); + } + ll_stats.len += len; + mutex_unlock(&llstats_mutex); + hdd_exit(); + +} + +void hdd_debugfs_process_radio_stats(struct hdd_adapter *adapter, + uint32_t more_data, void *data, uint32_t num_radio) +{ + int i, j; + ssize_t len = 0; + uint8_t *buffer; + struct wifi_radio_stats *radio_stat = (struct wifi_radio_stats *) data; + struct wifi_channel_stats *chan_stat; + + hdd_enter(); + + mutex_lock(&llstats_mutex); + if (!ll_stats.result) { + mutex_unlock(&llstats_mutex); + hdd_err("LL statistics buffer is NULL"); + return; + } + + buffer = ll_stats.result; + buffer += ll_stats.len; + len = scnprintf(buffer, DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\n\n===LL_STATS_RADIO: number of radios: %u===", + num_radio); + + for (i = 0; i < num_radio; i++) { + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nRadio: %u on_time: %u, tx_time: %u, rx_time: %u, on_time_scan: %u, on_time_nbd: %u, on_time_gscan: %u, on_time_roam_scan: %u, on_time_pno_scan: %u on_time_hs20: %u, on_time_host_scan: %u, on_time_lpi_scan: %u\ntotal_num_tx_pwr_levels: %u\n", + radio_stat->radio, radio_stat->on_time, + radio_stat->tx_time, radio_stat->rx_time, + radio_stat->on_time_scan, radio_stat->on_time_nbd, + radio_stat->on_time_gscan, + radio_stat->on_time_roam_scan, + radio_stat->on_time_pno_scan, + radio_stat->on_time_hs20, + radio_stat->on_time_host_scan, + radio_stat->on_time_lpi_scan, + radio_stat->total_num_tx_power_levels); + + for (j = 0; j < radio_stat->total_num_tx_power_levels; j++) { + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "%d ", radio_stat->tx_time_per_power_level[j]); + } + + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nNum channels: %d", radio_stat->num_channels); + + for (j = 0; j < radio_stat->num_channels; j++) { + chan_stat = (struct wifi_channel_stats *) + ((uint8_t *)radio_stat->channels + + (j * sizeof(struct wifi_channel_stats))); + + buffer += len; + ll_stats.len += len; + len = scnprintf(buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + "\nChan width: %u, center_freq: %u, center_freq0: %u, center_freq1: %u, on_time: %u, cca_busy_time: %u", + chan_stat->channel.width, + chan_stat->channel.center_freq, + chan_stat->channel.center_freq0, + chan_stat->channel.center_freq1, + chan_stat->on_time, chan_stat->cca_busy_time); + + if (adapter->hdd_ctx && + adapter->hdd_ctx->ll_stats_per_chan_rx_tx_time) { + buffer += len; + ll_stats.len += len; + len = scnprintf( + buffer, + DEBUGFS_LLSTATS_BUF_SIZE - ll_stats.len, + ", tx_time: %u, rx_time: %u", + chan_stat->tx_time, chan_stat->rx_time); + } + } + + radio_stat++; + } + ll_stats.len += len; + mutex_unlock(&llstats_mutex); + hdd_exit(); +} + +static inline void wlan_hdd_llstats_free_buf(void) +{ + mutex_lock(&llstats_mutex); + qdf_mem_free(ll_stats.result); + ll_stats.result = NULL; + ll_stats.len = 0; + mutex_unlock(&llstats_mutex); +} + +static int wlan_hdd_llstats_alloc_buf(void) +{ + mutex_lock(&llstats_mutex); + if (ll_stats.result) { + mutex_unlock(&llstats_mutex); + hdd_err("Buffer is already allocated"); + return 0; + } + ll_stats.len = 0; + ll_stats.result = qdf_mem_malloc(DEBUGFS_LLSTATS_BUF_SIZE); + if (!ll_stats.result) { + mutex_unlock(&llstats_mutex); + return -EINVAL; + } + mutex_unlock(&llstats_mutex); + return 0; +} + +/** + * hdd_debugfs_stats_update() - Update userspace with local statistics buffer + * @buf: userspace buffer (to which data is being copied into) + * @count: max data that can be copied into buf + * @pos: offset (where data should be copied into) + * + * This function should copies link layer statistics buffer into debugfs + * entry. + * + * Return: number of characters copied; 0 on no-copy + */ +static ssize_t hdd_debugfs_stats_update(char __user *buf, size_t count, + loff_t *pos) +{ + ssize_t ret_cnt; + + hdd_enter(); + mutex_lock(&llstats_mutex); + if (!ll_stats.result) { + mutex_unlock(&llstats_mutex); + hdd_err("Trying to read from NULL buffer"); + return 0; + } + + ret_cnt = simple_read_from_buffer(buf, count, pos, + ll_stats.result, ll_stats.len); + mutex_unlock(&llstats_mutex); + hdd_debug("LL stats read req: count: %zu, pos: %lld", count, *pos); + + hdd_exit(); + return ret_cnt; +} + +/** + * __wlan_hdd_read_ll_stats_debugfs() - API to collect LL stats from FW + * @net_dev: net_device context used to register the debugfs file + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t __wlan_hdd_read_ll_stats_debugfs(struct net_device *net_dev, + char __user *buf, size_t count, + loff_t *pos) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + ssize_t ret; + + hdd_enter(); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + /* All the events are received and buffer is populated */ + ret = hdd_debugfs_stats_update(buf, count, pos); + hdd_debug("%zu characters written into debugfs", ret); + + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_read_ll_stats_debugfs() - SSR wrapper function to read LL debugfs + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t wlan_hdd_read_ll_stats_debugfs(struct file *file, + char __user *buf, size_t count, + loff_t *pos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_read_ll_stats_debugfs(net_dev, buf, count, pos); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +/** + * __wlan_hdd_open_ll_stats_debugfs() - Function to save private on open + * @net_dev: net_device context used to register the debugfs file + * + * Return: Errno + */ +static int __wlan_hdd_open_ll_stats_debugfs(struct net_device *net_dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter(); + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = wlan_hdd_llstats_alloc_buf(); + if (errno) + return errno; + + errno = wlan_hdd_ll_stats_get(adapter->deflink, + DEBUGFS_LLSTATS_REQID, + DEBUGFS_LLSTATS_REQMASK); + if (errno) + goto free_buf; + + hdd_exit(); + + return 0; + +free_buf: + wlan_hdd_llstats_free_buf(); + + hdd_exit(); + + return errno; +} + +/** + * wlan_hdd_open_ll_stats_debugfs() - SSR wrapper function to save private + * on open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_open_ll_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = inode->i_private; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_open_ll_stats_debugfs(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_release_ll_stats_debugfs() - SSR wrapper function to save private + * on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_release_ll_stats_debugfs(struct inode *inode, + struct file *file) +{ + /* Memory allocated during open_ll_stats_debugfs is static to this file + * and not related to vdev/psoc, and hence it can be freed without DSC + * protection during release file op. + * + * Since ll_stats buffer is allocated during debugfs file open + * it needs to be freed in file release but, DSC vdev op-protection is + * not needed for releasing the ll_stats buffer. Adding DSC protection + * will lead to resource leak because DSC will reject file release + * op call if it is in the middle of vdev/psoc/driver transition. + */ + wlan_hdd_llstats_free_buf(); + + return 0; +} + +static const struct file_operations fops_ll_stats_debugfs = { + .read = wlan_hdd_read_ll_stats_debugfs, + .open = wlan_hdd_open_ll_stats_debugfs, + .release = wlan_hdd_release_ll_stats_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_create_ll_stats_file(struct hdd_adapter *adapter) +{ + if (!debugfs_create_file("ll_stats", 0444, adapter->debugfs_phy, + adapter->dev, &fops_ll_stats_debugfs)) + return -EINVAL; + + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_mibstat.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_mibstat.c new file mode 100644 index 0000000000..b713d889cc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_mibstat.c @@ -0,0 +1,363 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_mibstat.c + * + * WLAN Host Device Driver implementation to update + * debugfs with MIB statistics + */ + +#include +#include "osif_sync.h" +#include +#include +#include + +struct mib_stats_buf { + ssize_t len; + uint8_t *result; +}; + +static struct mib_stats_buf mib_stats; + +qdf_mutex_t mibstats_lock; + +void hdd_debugfs_process_mib_stats(struct hdd_adapter *adapter, + struct stats_event *stats) +{ + ssize_t len = 0; + uint8_t *buffer; + + hdd_enter(); + + qdf_mutex_acquire(&mibstats_lock); + if (!mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + hdd_err("MIB statistics buffer is NULL"); + return; + } + + buffer = mib_stats.result; + buffer += mib_stats.len; + + len = scnprintf(buffer, DEBUGFS_MIBSTATS_BUF_SIZE - mib_stats.len, + "dot11RTSSuccessCount %d " + "\ndot11RTSFailureCount %d " + "\ndot11QosFailedCount %d " + "\ndot11QosRetryCount %d " + "\ndot11QosTransmittedFrameCount %d " + "\ndot11QosMPDUsReceivedCount %d " + "\ndot11TransmittedAMPDUCount %d " + "\ndot11QosACKFailureCount %d", + stats->mib_stats->mib_mac_statistics.rts_success_cnt, + stats->mib_stats->mib_mac_statistics.rts_fail_cnt, + stats->mib_stats->mib_qos_counters.qos_failed_cnt, + stats->mib_stats->mib_qos_counters.qos_retry_cnt, + stats->mib_stats->mib_qos_counters.qos_tx_frame_cnt, + stats->mib_stats->mib_qos_counters.qos_mpdu_rx_cnt, + stats->mib_stats->mib_counters_group3.tx_ampdu_cnt, + stats->mib_stats-> + mib_qos_counters.tx_qos_ack_fail_cnt_up + ); + + buffer += len; + mib_stats.len += len; + qdf_mutex_release(&mibstats_lock); + + hdd_exit(); +} + +static inline void wlan_hdd_mibstats_free_buf(void) +{ + qdf_mutex_acquire(&mibstats_lock); + qdf_mem_free(mib_stats.result); + mib_stats.result = NULL; + mib_stats.len = 0; + qdf_mutex_release(&mibstats_lock); +} + +static int wlan_hdd_mibstats_alloc_buf(void) +{ + qdf_mutex_acquire(&mibstats_lock); + if (mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + hdd_err("Buffer is already allocated"); + return 0; + } + mib_stats.len = 0; + mib_stats.result = qdf_mem_malloc(DEBUGFS_MIBSTATS_BUF_SIZE); + if (!mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + return -EINVAL; + } + qdf_mutex_release(&mibstats_lock); + return 0; +} + +/** + * hdd_debugfs_mib_stats_update() - Update userspace with local stats buffer + * @buf: userspace buffer (to which data is being copied into) + * @count: max data that can be copied into buf in bytes + * @pos: offset (where data should be copied into) + * + * This function copies mib statistics buffer into debugfs + * entry. + * + * Return: number of characters copied; 0 on no-copy + */ +static ssize_t hdd_debugfs_mib_stats_update(char __user *buf, + size_t count, loff_t *pos) +{ + ssize_t ret_cnt; + + hdd_enter(); + qdf_mutex_acquire(&mibstats_lock); + if (!mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + hdd_err("Trying to read from NULL buffer"); + return 0; + } + + ret_cnt = simple_read_from_buffer(buf, count, pos, + mib_stats.result, + mib_stats.len); + qdf_mutex_release(&mibstats_lock); + hdd_debug("mib stats read req: count: %zu, pos: %lld", count, *pos); + + hdd_exit(); + return ret_cnt; +} + +/** + * __wlan_hdd_release_mib_stats_debugfs() - Function to free private + * memory on release + * @net_dev: net_device context used to register the debugfs file + * + * Return: Errno + */ +static int __wlan_hdd_release_mib_stats_debugfs(struct net_device *net_dev) + +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(net_dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + wlan_hdd_mibstats_free_buf(); + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_release_mib_stats_debugfs() - SSR wrapper function to free + * private memory on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_release_mib_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_release_mib_stats_debugfs(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_read_mib_stats_debugfs() - mib_stats debugfs handler + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @pos: (unused) offset into the virtual file system + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t __wlan_hdd_read_mib_stats_debugfs(struct net_device *net_dev, + char __user *buf, + size_t count, loff_t *pos) + +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + ssize_t ret; + + hdd_enter_dev(net_dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + goto free_buf; + + if (*pos == 0) { + ret = wlan_hdd_get_mib_stats(adapter); + if (ret) + goto free_buf; + } + + /* All the events are received and buffer is populated */ + ret = hdd_debugfs_mib_stats_update(buf, count, pos); + hdd_debug("%zu characters written into debugfs", ret); + + hdd_exit(); + + return ret; + +free_buf: + wlan_hdd_mibstats_free_buf(); + + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_read_mib_stats_debugfs() - SSR wrapper function to read + * mib stats + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t wlan_hdd_read_mib_stats_debugfs(struct file *file, + char __user *buf, size_t count, + loff_t *pos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_read_mib_stats_debugfs(net_dev, buf, + count, pos); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +/** + * __wlan_hdd_open_mib_stats_debugfs() - Function to save private on open + * @net_dev: net_device context used to register the debugfs file + * + * Return: Errno + */ +static int __wlan_hdd_open_mib_stats_debugfs(struct net_device *net_dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(net_dev); + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = wlan_hdd_mibstats_alloc_buf(); + if (errno) + return errno; + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_open_mib_stats_debugfs() - SSR wrapper to save private + * on open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_open_mib_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = inode->i_private; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_open_mib_stats_debugfs(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static const struct file_operations fops_mib_stats = { + .read = wlan_hdd_read_mib_stats_debugfs, + .open = wlan_hdd_open_mib_stats_debugfs, + .release = wlan_hdd_release_mib_stats_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_create_mib_stats_file(struct hdd_adapter *adapter) +{ + if (!debugfs_create_file("mib_stats", 0444, adapter->debugfs_phy, + adapter->dev, &fops_mib_stats)) + return -EINVAL; + + return 0; +} + +void wlan_hdd_create_mib_stats_lock(void) +{ + if (QDF_IS_STATUS_ERROR(qdf_mutex_create( + &mibstats_lock))) + hdd_err("mibstats lock init failed!"); +} + +void wlan_hdd_destroy_mib_stats_lock(void) +{ + qdf_mutex_destroy(&mibstats_lock); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_offload.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_offload.c new file mode 100644 index 0000000000..86ece69a74 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_offload.c @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_offload.c + * + * WLAN Host Device Driver implementation to update + * debugfs with offload information + */ + +#include +#include +#include +#include +#include "qwlan_version.h" +#include "wmi_unified_param.h" +#include "wlan_pmo_common_public_struct.h" +#include "wlan_pmo_ns_public_struct.h" +#include "wlan_pmo_mc_addr_filtering_public_struct.h" +#include "wlan_pmo_ucfg_api.h" +#include "wlan_hdd_object_manager.h" + +/* IPv6 address string */ +#define IPV6_MAC_ADDRESS_STR_LEN 47 /* Including null terminator */ + +/** + * wlan_hdd_mc_addr_list_info_debugfs() - Populate mc addr list info + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * @buf: output buffer to hold mc addr list info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_mc_addr_list_info_debugfs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret; + uint8_t i; + struct pmo_mc_addr_list mc_addr_list = {0}; + QDF_STATUS status; + + if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) { + ret = scnprintf(buf, buf_avail_len, + "\nMC addr ini is disabled\n"); + if (ret > 0) + length = ret; + return length; + } + + status = ucfg_pmo_get_mc_addr_list(hdd_ctx->psoc, + adapter->deflink->vdev_id, + &mc_addr_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ret = scnprintf(buf, buf_avail_len, + "\nMC addr list query is failed\n"); + if (ret > 0) + length = ret; + return length; + } + + if (mc_addr_list.mc_cnt == 0) { + ret = scnprintf(buf, buf_avail_len, + "\nMC addr list is empty\n"); + if (ret > 0) + length = ret; + return length; + } + + ret = scnprintf(buf, buf_avail_len, + "\nMC ADDR LIST DETAILS (mc_cnt = %u)\n", + mc_addr_list.mc_cnt); + if (ret <= 0) + return length; + length += ret; + + for (i = 0; i < mc_addr_list.mc_cnt; i++) { + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + QDF_MAC_ADDR_FMT "\n", + QDF_MAC_ADDR_REF(mc_addr_list.mc_addr[i].bytes)); + if (ret <= 0) + return length; + length += ret; + } + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + ret = scnprintf(buf + length, buf_avail_len - length, + "mc_filter_applied = %u\n", + mc_addr_list.is_filter_applied); + if (ret <= 0) + return length; + + length += ret; + return length; +} + +/** + * wlan_hdd_arp_offload_info_debugfs() - Populate arp offload info + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * @buf: output buffer to hold arp offload info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_arp_offload_info_debugfs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret_val; + struct pmo_arp_offload_params info = {0}; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) + return 0; + + status = ucfg_pmo_get_arp_offload_params(vdev, &info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ret_val = scnprintf(buf, buf_avail_len, + "\nARP OFFLOAD QUERY FAILED\n"); + goto len_adj; + } + + if (!info.is_offload_applied) + ret_val = scnprintf(buf, buf_avail_len, + "\nARP OFFLOAD: DISABLED\n"); + else + ret_val = scnprintf(buf, buf_avail_len, + "\nARP OFFLOAD: ENABLED (%u.%u.%u.%u)\n", + info.host_ipv4_addr[0], + info.host_ipv4_addr[1], + info.host_ipv4_addr[2], + info.host_ipv4_addr[3]); +len_adj: + if (ret_val <= 0) + return length; + length = ret_val; + + return length; +} + +#ifdef WLAN_NS_OFFLOAD +/** + * ipv6_addr_string() - Get IPv6 addr string from array of octets + * @buffer: output buffer to hold string, caller should ensure size of + * buffer is atleast IPV6_MAC_ADDRESS_STR_LEN + * @ipv6_addr: IPv6 address array + * + * Return: None + */ +static void ipv6_addr_string(uint8_t *buffer, uint8_t *ipv6_addr) +{ + uint8_t *a = ipv6_addr; + + scnprintf(buffer, IPV6_MAC_ADDRESS_STR_LEN, + "%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x::%02x%02x", + (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5], (a)[6], + (a)[7], (a)[8], (a)[9], (a)[10], (a)[11], (a)[12], (a)[13], + (a)[14], (a)[15]); +} + +/** + * hdd_ipv6_scope_str() - Get string for PMO NS (IPv6) Addr scope + * @scope: scope id from enum pmo_ns_addr_scope + * + * Return: Meaningful string for enum pmo_ns_addr_scope + */ +static uint8_t *hdd_ipv6_scope_str(enum pmo_ns_addr_scope scope) +{ + switch (scope) { + case PMO_NS_ADDR_SCOPE_NODELOCAL: + return "Node Local"; + case PMO_NS_ADDR_SCOPE_LINKLOCAL: + return "Link Local"; + case PMO_NS_ADDR_SCOPE_SITELOCAL: + return "Site Local"; + case PMO_NS_ADDR_SCOPE_ORGLOCAL: + return "Org Local"; + case PMO_NS_ADDR_SCOPE_GLOBAL: + return "Global"; + default: + return "Invalid"; + } +} + +/** + * wlan_hdd_ns_offload_info_debugfs() - Populate ns offload info + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * @buf: output buffer to hold ns offload info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_ns_offload_info_debugfs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret; + struct pmo_ns_offload_params info = {0}; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + uint32_t i; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) + return 0; + + status = ucfg_pmo_get_ns_offload_params(vdev, &info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (!QDF_IS_STATUS_SUCCESS(status)) { + ret = scnprintf(buf, buf_avail_len, + "\nNS OFFLOAD QUERY FAILED\n"); + if (ret <= 0) + return length; + length += ret; + + return length; + } + + ret = scnprintf(buf, buf_avail_len, + "\nNS OFFLOAD DETAILS\n"); + if (ret <= 0) + return length; + length += ret; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + if (!info.is_offload_applied) { + ret = scnprintf(buf + length, buf_avail_len - length, + "NS offload is not enabled\n"); + if (ret <= 0) + return length; + length += ret; + + return length; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + "NS offload enabled, %u ns addresses offloaded\n", + info.num_ns_offload_count); + if (ret <= 0) + return length; + length += ret; + + for (i = 0; i < info.num_ns_offload_count; i++) { + uint8_t ipv6_str[IPV6_MAC_ADDRESS_STR_LEN]; + uint8_t cast_string[12]; + uint8_t *scope_string; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + ipv6_addr_string(ipv6_str, info.target_ipv6_addr[i]); + scope_string = hdd_ipv6_scope_str(info.scope[i]); + + if (info.target_ipv6_addr_ac_type[i] == + PMO_IPV6_ADDR_AC_TYPE) + strlcpy(cast_string, "(ANY CAST)", 12); + else + strlcpy(cast_string, "(UNI CAST)", 12); + + ret = scnprintf(buf + length, buf_avail_len - length, + "%u. %s %s and scope is: %s\n", + (i + 1), ipv6_str, cast_string, + scope_string); + if (ret <= 0) + return length; + length += ret; + } + + return length; +} +#else +/** + * wlan_hdd_ns_offload_info_debugfs() - Populate ns offload info + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * @buf: output buffer to hold ns offload info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_ns_offload_info_debugfs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + return 0; +} +#endif + +#ifdef FEATURE_WLAN_APF +/** + * wlan_hdd_apf_info_debugfs() - Populate apf offload info + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * @buf: output buffer to hold apf offload info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_apf_info_debugfs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret_val; + bool apf_enabled; + + if (hdd_ctx->apf_version > 2) + apf_enabled = adapter->apf_context.apf_enabled; + else + apf_enabled = hdd_ctx->apf_enabled_v2; + + ret_val = scnprintf(buf, buf_avail_len, + "\nAPF OFFLOAD DETAILS, offload_applied: %u\n\n", + apf_enabled); + if (ret_val <= 0) + return length; + length = ret_val; + + return length; +} +#else +static ssize_t +wlan_hdd_apf_info_debugfs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + return 0; +} +#endif + +ssize_t +wlan_hdd_debugfs_update_filters_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t len; + int ret_val; + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_enter(); + + len = wlan_hdd_current_time_info_debugfs(buf, buf_avail_len); + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + if (adapter->device_mode != QDF_STA_MODE) { + ret_val = scnprintf(buf + len, buf_avail_len - len, + "Interface is not operating in STA mode\n"); + if (ret_val <= 0) + return len; + + len += ret_val; + return len; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + ret_val = scnprintf(buf + len, buf_avail_len - len, + "\nSTA is not connected\n"); + if (ret_val <= 0) + return len; + + len += ret_val; + return len; + } + + len += wlan_hdd_mc_addr_list_info_debugfs(hdd_ctx, adapter, buf + len, + buf_avail_len - len); + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + len += wlan_hdd_arp_offload_info_debugfs(hdd_ctx, adapter, buf + len, + buf_avail_len - len); + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + len += wlan_hdd_ns_offload_info_debugfs(hdd_ctx, adapter, buf + len, + buf_avail_len - len); + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + len += wlan_hdd_apf_info_debugfs(hdd_ctx, adapter, buf + len, + buf_avail_len - len); + + hdd_exit(); + + return len; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_roam.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_roam.c new file mode 100644 index 0000000000..51ca51452e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_roam.c @@ -0,0 +1,578 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_roam.c + * + * WLAN Host Device Driver implementation to update + * debugfs with roaming information + */ + +#include +#include +#include +#include +#include "qwlan_version.h" +#include "wmi_unified_param.h" +#include "wlan_osif_request_manager.h" + +/** + * hdd_roam_scan_stats_debugfs_dealloc() - Dealloc objects in hdd request mgr + * @priv: Pointer to private data of hdd request object + * + * Return: None + */ +static void hdd_roam_scan_stats_debugfs_dealloc(void *priv) +{ + struct hdd_roam_scan_stats_debugfs_priv *local_priv = priv; + struct wmi_roam_scan_stats_res *roam_scan_stats_res; + + if (!local_priv) + return; + + roam_scan_stats_res = local_priv->roam_scan_stats_res; + local_priv->roam_scan_stats_res = NULL; + + qdf_mem_free(roam_scan_stats_res); +} + +/** + * hdd_roam_scan_stats_cb() - Call back invoked from roam scan stats evt + * @context: cookie to get request object + * @res: roam scan stats response from firmware + * + * Return: None + */ +static void +hdd_roam_scan_stats_cb(void *context, struct wmi_roam_scan_stats_res *res) +{ + struct osif_request *request; + struct hdd_roam_scan_stats_debugfs_priv *priv; + struct wmi_roam_scan_stats_res *stats_res; + uint32_t total_len; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete roam scan stats request"); + return; + } + + if (!res) { + hdd_err("Invalid response"); + goto end; + } + + priv = osif_request_priv(request); + + total_len = sizeof(*res) + res->num_roam_scans * + sizeof(struct wmi_roam_scan_stats_params); + + stats_res = qdf_mem_malloc(total_len); + if (!stats_res) + goto end; + + qdf_mem_copy(stats_res, res, total_len); + priv->roam_scan_stats_res = stats_res; + +end: + osif_request_complete(request); + osif_request_put(request); + + hdd_exit(); +} + +/** + * hdd_get_roam_scan_stats() - Get roam scan stats using request manager + * @hdd_ctx: hdd context + * @adapter: pointer to adapter + * + * Return: Pointer to struct wmi_roam_scan_stats_res which contains response + * from firmware + */ +static struct +wmi_roam_scan_stats_res *hdd_get_roam_scan_stats(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wmi_roam_scan_stats_res *res; + struct wmi_roam_scan_stats_res *stats_res = NULL; + void *context; + struct osif_request *request; + struct hdd_roam_scan_stats_debugfs_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_FW_ROAM_STATS, + .dealloc = hdd_roam_scan_stats_debugfs_dealloc, + }; + QDF_STATUS status; + int ret; + uint32_t total_len; + + hdd_enter(); + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return NULL; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return NULL; + } + + context = osif_request_cookie(request); + + status = sme_get_roam_scan_stats(hdd_ctx->mac_handle, + hdd_roam_scan_stats_cb, + context, adapter->deflink->vdev_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("roam scan stats request failed"); + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("roam scan stats response time out"); + goto cleanup; + } + + priv = osif_request_priv(request); + res = priv->roam_scan_stats_res; + if (!res) { + hdd_err("Failure of roam scan stats response retrieval"); + goto cleanup; + } + + total_len = sizeof(*res) + res->num_roam_scans * + sizeof(struct wmi_roam_scan_stats_params); + + stats_res = qdf_mem_malloc(total_len); + if (!stats_res) + goto cleanup; + + qdf_mem_copy(stats_res, res, total_len); + +cleanup: + osif_request_put(request); + hdd_exit(); + + return stats_res; +} + +/** + * hdd_roam_scan_trigger_to_str() - Get string for + * enum WMI_ROAM_TRIGGER_REASON_ID + * @roam_scan_trigger: roam scan trigger ID + * + * Return: Meaningful string from enum WMI_ROAM_TRIGGER_REASON_ID + */ +static char *hdd_roam_scan_trigger_to_str(uint32_t roam_scan_trigger) +{ + switch (roam_scan_trigger) { + case WMI_ROAM_TRIGGER_REASON_PER: + return "PER"; + case WMI_ROAM_TRIGGER_REASON_BMISS: + return "BEACON MISS"; + case WMI_ROAM_TRIGGER_REASON_LOW_RSSI: + return "LOW RSSI"; + case WMI_ROAM_TRIGGER_REASON_HIGH_RSSI: + return "HIGH RSSI"; + case WMI_ROAM_TRIGGER_REASON_PERIODIC: + return "PERIODIC SCAN"; + case WMI_ROAM_TRIGGER_REASON_MAWC: + return "WMI_ROAM_TRIGGER_REASON_MAWC"; + case WMI_ROAM_TRIGGER_REASON_DENSE: + return "DENSE ENVIRONMENT"; + case WMI_ROAM_TRIGGER_REASON_BACKGROUND: + return "BACKGROUND SCAN"; + case WMI_ROAM_TRIGGER_REASON_FORCED: + return "FORCED SCAN"; + case WMI_ROAM_TRIGGER_REASON_BTM: + return "BTM TRIGGER"; + case WMI_ROAM_TRIGGER_REASON_UNIT_TEST: + return "TEST COMMAND"; + default: + return "UNKNOWN REASON"; + } + return "UNKNOWN REASON"; +} + +/** + * hdd_roam_scan_trigger_value() - Get trigger value string for + * enum WMI_ROAM_TRIGGER_REASON_ID + * @roam_scan_trigger: roam scan trigger ID + * @print: output pointer to hold whether to print trigger value + * + * Return: Meaningful string from trigger value + */ +static char *hdd_roam_scan_trigger_value(uint32_t roam_scan_trigger, + bool *print) +{ + *print = true; + + switch (roam_scan_trigger) { + case WMI_ROAM_TRIGGER_REASON_PER: + return "percentage"; + case WMI_ROAM_TRIGGER_REASON_LOW_RSSI: + return "dB"; + case WMI_ROAM_TRIGGER_REASON_HIGH_RSSI: + return "dB"; + case WMI_ROAM_TRIGGER_REASON_PERIODIC: + return "ms"; + case WMI_ROAM_TRIGGER_REASON_DENSE: + return "(1 - Rx, 2 - Tx)"; + default: + *print = false; + return NULL; + } +} + +/** + * hdd_client_id_to_str() - Helper func to get meaningful string from client id + * @client_id: Id of the client which triggered roam scan in firmware + * + * Return: Meaningful string from enum WMI_SCAN_CLIENT_ID + */ +static char *hdd_client_id_to_str(uint32_t client_id) +{ + switch (client_id) { + case WMI_SCAN_CLIENT_NLO: + return "PNO"; + case WMI_SCAN_CLIENT_EXTSCAN: + return "GSCAN"; + case WMI_SCAN_CLIENT_ROAM: + return "ROAM"; + case WMI_SCAN_CLIENT_P2P: + return "P2P"; + case WMI_SCAN_CLIENT_LPI: + return "LPI"; + case WMI_SCAN_CLIENT_NAN: + return "NAN"; + case WMI_SCAN_CLIENT_ANQP: + return "ANQP"; + case WMI_SCAN_CLIENT_OBSS: + return "OBSS"; + case WMI_SCAN_CLIENT_PLM: + return "PLM"; + case WMI_SCAN_CLIENT_HOST: + return "HOST"; + default: + return "UNKNOWN"; + } + return "UNKNOWN"; +} + +/** + * hdd_roam_scan_trigger() - Print roam scan trigger info into buffer + * @scan: roam scan event data + * @buf: buffer to write roam scan trigger info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +hdd_roam_scan_trigger(struct wmi_roam_scan_stats_params *scan, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret; + char *str; + bool print_trigger_value; + + ret = scnprintf(buf, buf_avail_len, + "Trigger reason is %s\n", + hdd_roam_scan_trigger_to_str(scan->trigger_id)); + if (ret <= 0) + return length; + + length = ret; + + str = hdd_roam_scan_trigger_value(scan->trigger_id, + &print_trigger_value); + if (!print_trigger_value || !str) + return length; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + return length; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + "Trigger value is: %u %s\n", + scan->trigger_value, str); + if (ret <= 0) + return length; + + length += ret; + return length; +} + +/** + * hdd_roam_scan_chan() - Print roam scan chan freq info into buffer + * @scan: roam scan event data + * @buf: buffer to write roam scan freq info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +hdd_roam_scan_chan(struct wmi_roam_scan_stats_params *scan, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length = 0; + uint32_t i; + int ret; + + ret = scnprintf(buf, buf_avail_len, + "Num of scan channels: %u\n" + "scan channel list:", + scan->num_scan_chans); + if (ret <= 0) + return length; + + length = ret; + + for (i = 0; i < scan->num_scan_chans; i++) { + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + return length; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + "%u ", scan->scan_freqs[i]); + if (ret <= 0) + return length; + + length += ret; + } + + return length; +} + +/** + * wlan_hdd_update_roam_stats() - Internal function to get roam scan stats + * @hdd_ctx: hdd context + * @adapter: pointer to adapter + * @buf: buffer to hold the stats + * @buf_avail_len: maximum available length in response buffer + * + * Return: Size of formatted roam scan response stats + */ +static ssize_t +wlan_hdd_update_roam_stats(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length = 0; + struct wmi_roam_scan_stats_res *roam_stats; + struct wmi_roam_scan_stats_params *scan; + int ret; + int rsi; /* roam scan iterator */ + int rci; /* roam candidate iterator */ + + roam_stats = hdd_get_roam_scan_stats(hdd_ctx, adapter); + if (!roam_stats) { + hdd_err("Couldn't get roam stats"); + ret = scnprintf(buf, buf_avail_len, + "Failed to fetch roam stats\n"); + if (ret <= 0) + return length; + length += ret; + return length; + } + + ret = scnprintf(buf, buf_avail_len, + "\n\nStats of last %u roam scans\n", + roam_stats->num_roam_scans); + if (ret <= 0) + goto free_mem; + length += ret; + + for (rsi = 0; rsi < roam_stats->num_roam_scans; rsi++) { + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + scan = &roam_stats->roam_scan[rsi]; + ret = scnprintf(buf + length, buf_avail_len - length, + "\nRoam scan[%u] details\n", rsi); + if (ret <= 0) + goto free_mem; + length += ret; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + "This scan is triggered by \"%s\" scan client\n", + hdd_client_id_to_str(scan->client_id)); + + if (ret <= 0) + goto free_mem; + length += ret; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + length += hdd_roam_scan_trigger(scan, buf + length, + buf_avail_len - length); + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + length += hdd_roam_scan_chan(scan, buf + length, + buf_avail_len - length); + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + "\nRoam Scan time: 0x%llx\n", + roam_stats->roam_scan[rsi].time_stamp); + if (ret <= 0) + goto free_mem; + length += ret; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + if (scan->is_roam_successful) { + ret = scnprintf(buf + length, + buf_avail_len - length, + "\nSTA roamed from " + QDF_MAC_ADDR_FMT " to " + QDF_MAC_ADDR_FMT "\n", + QDF_MAC_ADDR_REF(scan->old_bssid), + QDF_MAC_ADDR_REF(scan->new_bssid)); + } else { + ret = scnprintf(buf + length, + buf_avail_len - length, + "\nSTA is connected to " QDF_MAC_ADDR_FMT + " before and after scan, not roamed\n", + QDF_MAC_ADDR_REF(scan->old_bssid)); + } + if (ret <= 0) + goto free_mem; + length += ret; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + "Roam candidate details\n"); + if (ret <= 0) + goto free_mem; + length += ret; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + ret = scnprintf(buf + length, buf_avail_len - length, + " BSSID FREQ SCORE RSSI\n"); + if (ret <= 0) + goto free_mem; + length += ret; + + for (rci = 0; rci < scan->num_roam_candidates; rci++) { + uint8_t *bssid = scan->cand[rci].bssid; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + length = buf_avail_len; + goto free_mem; + } + + ret = scnprintf(buf + length, + buf_avail_len - length, + QDF_MAC_ADDR_FMT " %4u %3u %3u\n", + QDF_MAC_ADDR_REF(bssid), + scan->cand[rci].freq, + scan->cand[rci].score, + scan->cand[rci].rssi); + if (ret <= 0) + goto free_mem; + length += ret; + } + } + +free_mem: + qdf_mem_free(roam_stats); + return length; +} + +ssize_t +wlan_hdd_debugfs_update_roam_stats(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t len = 0; + int ret_val; + + hdd_enter(); + + len = wlan_hdd_current_time_info_debugfs(buf, buf_avail_len - len); + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + if (adapter->device_mode != QDF_STA_MODE) { + ret_val = scnprintf(buf + len, buf_avail_len - len, + "Interface is not in STA Mode\n"); + if (ret_val <= 0) + return len; + + len += ret_val; + return len; + } + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + len += wlan_hdd_update_roam_stats(hdd_ctx, adapter, buf + len, + buf_avail_len - len); + + hdd_exit(); + + return len; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_unit_test.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_unit_test.c new file mode 100644 index 0000000000..84636833c6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_debugfs_unit_test.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_debugfs_unit_test.c + * + * WLAN Host Device Driver implementation to create debugfs + * unit_test_host/unit_test_target/wlan_suspend/wlan_resume + */ +#include "wlan_hdd_main.h" +#include "osif_psoc_sync.h" +#include "osif_vdev_sync.h" +#include "wlan_dsc_test.h" +#include "wlan_hdd_unit_test.h" +#include "wlan_hdd_debugfs_unit_test.h" +#include "wma.h" + +#ifdef WLAN_UNIT_TEST +/* strlen("all") + 1(\n) */ +#define MIN_USER_COMMAND_SIZE_UNIT_TEST_HOST 4 +#define MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST 32 + +/** + * __wlan_hdd_write_unit_test_host_debugfs() + * - host unit test debugfs handler + * + * @hdd_ctx: HDD context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed or errno + */ +static ssize_t __wlan_hdd_write_unit_test_host_debugfs( + struct hdd_context *hdd_ctx, + const char __user *buf, size_t count, + loff_t *ppos) +{ + char name[MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST + 1]; + int ret; + + if (count < MIN_USER_COMMAND_SIZE_UNIT_TEST_HOST || + count > MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST) { + hdd_err_rl("Command length (%zu) is invalid, expected [%d, %d]", + count, + MIN_USER_COMMAND_SIZE_UNIT_TEST_HOST, + MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST); + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(name, buf, count)) + return -EFAULT; + /* default 'echo' cmd takes new line character to here*/ + if (name[count - 1] == '\n') + name[count - 1] = '\0'; + else + name[count] = '\0'; + + hdd_nofl_info("unit_test: count %zu name: %s", count, name); + + ret = wlan_hdd_unit_test(hdd_ctx, name); + if (ret != 0) + return ret; + + return count; +} + +/** + * wlan_hdd_write_unit_test_host_debugfs() + * - wrapper for __wlan_hdd_write_unit_test_host_debugfs + * + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: number of bytes processed or errno + */ +static ssize_t wlan_hdd_write_unit_test_host_debugfs( + struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct hdd_context *hdd_ctx = file_inode(file)->i_private; + struct osif_psoc_sync *psoc_sync; + ssize_t errno_size; + + errno_size = wlan_hdd_validate_context(hdd_ctx); + if (errno_size) + return errno_size; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __wlan_hdd_write_unit_test_host_debugfs( + hdd_ctx, buf, count, ppos); + if (errno_size < 0) + hdd_err_rl("err_size %zd", errno_size); + + osif_psoc_sync_op_stop(psoc_sync); + return errno_size; +} + +static const struct file_operations fops_unit_test_host_debugfs = { + .write = wlan_hdd_write_unit_test_host_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_debugfs_unit_test_host_create(struct hdd_context *hdd_ctx) +{ + if (!debugfs_create_file("unit_test_host", 00400 | 00200, + qdf_debugfs_get_root(), + hdd_ctx, &fops_unit_test_host_debugfs)) + return -EINVAL; + + return 0; +} +#endif /* WLAN_UNIT_TEST */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c new file mode 100644 index 0000000000..9539c2ae81 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c @@ -0,0 +1,491 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_disa.c + * + * WLAN Host Device Driver file for DISA certification + * + */ + +#include "wlan_hdd_disa.h" +#include "osif_sync.h" +#include "wlan_disa_ucfg_api.h" +#include "wlan_osif_request_manager.h" +#include "sme_api.h" +#include + +#define WLAN_WAIT_TIME_ENCRYPT_DECRYPT 1000 + + +/** + * struct hdd_encrypt_decrypt_msg_context - hdd encrypt/decrypt message context + * @status: status of response. 0: no error, -ENOMEM: unable to allocate + * memory for the response payload + * @request: encrypt/decrypt request + * @response: encrypt/decrypt response + */ +struct hdd_encrypt_decrypt_msg_context { + int status; + struct disa_encrypt_decrypt_req_params request; + struct disa_encrypt_decrypt_resp_params response; +}; + +/** + * hdd_encrypt_decrypt_msg_cb () - encrypt/decrypt response message handler + * @cookie: hdd request cookie + * @resp: encrypt/decrypt response parameters + * + * Return: none + */ +static void hdd_encrypt_decrypt_msg_cb(void *cookie, + struct disa_encrypt_decrypt_resp_params *resp) +{ + struct osif_request *request; + struct hdd_encrypt_decrypt_msg_context *context; + + hdd_enter(); + + if (!resp) { + hdd_err("rsp params is NULL"); + return; + } + + request = osif_request_get(cookie); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + print_hex_dump(KERN_INFO, "Data in hdd_encrypt_decrypt_msg_cb: ", + DUMP_PREFIX_NONE, 16, 1, + resp->data, + resp->data_len, 0); + + hdd_debug("vdev_id: %d status:%d data_length: %d", + resp->vdev_id, + resp->status, + resp->data_len); + + context = osif_request_priv(request); + context->response = *resp; + context->status = 0; + if (resp->data_len) { + context->response.data = + qdf_mem_malloc(sizeof(uint8_t) * + resp->data_len); + if (!context->response.data) { + context->status = -ENOMEM; + } else { + qdf_mem_copy(context->response.data, + resp->data, + resp->data_len); + } + } else { + /* make sure we don't have a rogue pointer */ + context->response.data = NULL; + } + + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); +} + +/** + * hdd_post_encrypt_decrypt_msg_rsp () - send encrypt/decrypt data to user space + * @hdd_ctx: HDD context + * @resp: encrypt/decrypt response parameters + * + * Return: none + */ +static int hdd_post_encrypt_decrypt_msg_rsp(struct hdd_context *hdd_ctx, + struct disa_encrypt_decrypt_resp_params *resp) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + + hdd_enter(); + + nl_buf_len = resp->data_len + NLA_HDRLEN; + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (resp->data_len) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA, + resp->data_len, resp->data)) { + hdd_err("put fail"); + goto nla_put_failure; + } + } + + wlan_cfg80211_vendor_cmd_reply(skb); + hdd_exit(); + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +const struct nla_policy +encrypt_decrypt_policy[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID] = { + .type = NLA_U8}, +}; + +/** + * hdd_fill_encrypt_decrypt_params () - parses data from user space + * and fills encrypt/decrypt parameters + * @encrypt_decrypt_params: encrypt/decrypt request parameters + * @adapter : adapter context + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +hdd_fill_encrypt_decrypt_params(struct disa_encrypt_decrypt_req_params + *encrypt_decrypt_params, + struct hdd_adapter *adapter, + const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1]; + uint8_t len, mac_hdr_len; + uint8_t *tmp; + uint8_t fc[2]; + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX, + data, data_len, encrypt_decrypt_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + encrypt_decrypt_params->vdev_id = adapter->deflink->vdev_id; + hdd_debug("vdev_id: %d", encrypt_decrypt_params->vdev_id); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION]) { + hdd_err("attr flag NEEDS_DECRYPTION not present"); + encrypt_decrypt_params->key_flag = WMI_ENCRYPT; + } else { + hdd_err("attr flag NEEDS_DECRYPTION present"); + encrypt_decrypt_params->key_flag = WMI_DECRYPT; + } + hdd_debug("Key flag: %d", encrypt_decrypt_params->key_flag); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]) { + hdd_err("attr key id failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_idx = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]); + hdd_debug("Key Idx: %d", encrypt_decrypt_params->key_idx); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]) { + hdd_err("attr Cipher failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_cipher = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]); + hdd_debug("key_cipher: %d", encrypt_decrypt_params->key_cipher); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]) { + hdd_err("attr TK failed"); + return -EINVAL; + } + encrypt_decrypt_params->key_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]); + if (!encrypt_decrypt_params->key_len) { + hdd_err("Invalid TK length"); + return -EINVAL; + } + hdd_debug("Key len: %d", encrypt_decrypt_params->key_len); + + if (encrypt_decrypt_params->key_len > SIR_MAC_MAX_KEY_LENGTH) + encrypt_decrypt_params->key_len = SIR_MAC_MAX_KEY_LENGTH; + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]); + + qdf_mem_copy(encrypt_decrypt_params->key_data, tmp, + encrypt_decrypt_params->key_len); + + print_hex_dump(KERN_INFO, "Key : ", DUMP_PREFIX_NONE, 16, 1, + &encrypt_decrypt_params->key_data, + encrypt_decrypt_params->key_len, 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]) { + hdd_err("attr PN failed"); + return -EINVAL; + } + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); + if (!len || len > sizeof(encrypt_decrypt_params->pn)) { + hdd_err("Invalid PN length %u", len); + return -EINVAL; + } + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]); + + qdf_mem_copy(encrypt_decrypt_params->pn, tmp, len); + + print_hex_dump(KERN_INFO, "PN received : ", DUMP_PREFIX_NONE, 16, 1, + &encrypt_decrypt_params->pn, len, 0); + + if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]) { + hdd_err("attr header failed"); + return -EINVAL; + } + len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); + if (len < MIN_MAC_HEADER_LEN) { + hdd_err("Invalid header and payload length %u", len); + return -EINVAL; + } + + hdd_debug("Header and Payload length: %d", len); + + tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]); + + print_hex_dump(KERN_INFO, "Header and Payload received: ", + DUMP_PREFIX_NONE, 16, 1, + tmp, len, 0); + + mac_hdr_len = MIN_MAC_HEADER_LEN; + + /* + * Check to find out address 4. Address 4 is present if ToDS and FromDS + * are 1 and data representation is little endian. + */ + fc[1] = *tmp; + fc[0] = *(tmp + 1); + if ((fc[0] & 0x03) == 0x03) { + hdd_err("Address 4 is present"); + mac_hdr_len += QDF_MAC_ADDR_SIZE; + } + + /* + * Check to find out Qos control field. Qos control field is present + * if msb of subtype field is 1 and data representation is + * little endian. + */ + if (fc[1] & 0x80) { + hdd_err("Qos control is present"); + mac_hdr_len += QOS_CONTROL_LEN; + } + + hdd_debug("mac_hdr_len: %d", mac_hdr_len); + + if (len < mac_hdr_len) { + hdd_err("Invalid header and payload length %u", len); + return -EINVAL; + } + qdf_mem_copy(encrypt_decrypt_params->mac_header, + tmp, mac_hdr_len); + + print_hex_dump(KERN_INFO, "Header received in request: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_params->mac_header, + mac_hdr_len, 0); + + encrypt_decrypt_params->data_len = + len - mac_hdr_len; + + hdd_debug("Payload length: %d", encrypt_decrypt_params->data_len); + + if (encrypt_decrypt_params->data_len) { + encrypt_decrypt_params->data = + qdf_mem_malloc(sizeof(uint8_t) * + encrypt_decrypt_params->data_len); + + if (!encrypt_decrypt_params->data) + return -ENOMEM; + + qdf_mem_copy(encrypt_decrypt_params->data, + tmp + mac_hdr_len, + encrypt_decrypt_params->data_len); + + print_hex_dump(KERN_INFO, "Data received in request: ", + DUMP_PREFIX_NONE, 16, 1, + encrypt_decrypt_params->data, + encrypt_decrypt_params->data_len, 0); + } + + return 0; +} + +static void hdd_encrypt_decrypt_context_dealloc(void *priv) +{ + struct hdd_encrypt_decrypt_msg_context *context = priv; + + qdf_mem_free(context->request.data); + qdf_mem_free(context->response.data); +} + +/** + * hdd_encrypt_decrypt_msg () - process encrypt/decrypt message + * @adapter : adapter context + * @hdd_ctx: hdd context + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_encrypt_decrypt_msg(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + const void *data, + int data_len) +{ + QDF_STATUS qdf_status; + int ret; + void *cookie; + struct osif_request *request; + struct hdd_encrypt_decrypt_msg_context *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*context), + .timeout_ms = WLAN_WAIT_TIME_ENCRYPT_DECRYPT, + .dealloc = hdd_encrypt_decrypt_context_dealloc, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + context = osif_request_priv(request); + + ret = hdd_fill_encrypt_decrypt_params(&context->request, adapter, + data, data_len); + if (ret) + goto cleanup; + + cookie = osif_request_cookie(request); + + qdf_status = ucfg_disa_encrypt_decrypt_req(hdd_ctx->psoc, + &context->request, + hdd_encrypt_decrypt_msg_cb, + cookie); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Unable to post encrypt/decrypt message"); + ret = -EINVAL; + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out"); + goto cleanup; + } + + ret = context->status; + if (ret) { + hdd_err("Target response processing failed"); + goto cleanup; + } + + ret = hdd_post_encrypt_decrypt_msg_rsp(hdd_ctx, &context->response); + if (ret) + hdd_err("Failed to post encrypt/decrypt message response"); + +cleanup: + osif_request_put(request); + + hdd_exit(); + return ret; +} + +/** + * __wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = NULL; + int ret; + bool is_bmps_enabled; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + ucfg_mlme_is_bmps_enabled(hdd_ctx->psoc, &is_bmps_enabled); + if (is_bmps_enabled) { + hdd_debug("DISA is not supported when PS is enabled"); + return -EINVAL; + } + + ret = hdd_encrypt_decrypt_msg(adapter, hdd_ctx, data, data_len); + + return ret; +} + +/** + * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h new file mode 100644 index 0000000000..de56337dba --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_disa.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2016-2017, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_DISA_H +#define _WLAN_HDD_DISA_H + +#include "wlan_hdd_main.h" +#include "sir_api.h" +#include "qca_vendor.h" + +#ifdef WLAN_FEATURE_DISA +extern const struct nla_policy +encrypt_decrypt_policy[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1]; + +#define FEATURE_DISA_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ENCRYPTION_TEST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_encrypt_decrypt_msg, \ + vendor_command_policy(encrypt_decrypt_policy, \ + QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX) \ +}, + +/** + * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +#else +#define FEATURE_DISA_VENDOR_COMMANDS +#endif + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c new file mode 100644 index 0000000000..ac937e7429 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_driver_ops.c @@ -0,0 +1,2390 @@ +/* + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "cds_api.h" +#include "qdf_status.h" +#include "qdf_lock.h" +#include "cds_sched.h" +#include "osdep.h" +#include "hif.h" +#include "htc.h" +#include "epping_main.h" +#include "osif_sync.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_power.h" +#include "wlan_logging_sock_svc.h" +#include "wma_api.h" +#include "wlan_hdd_napi.h" +#include "wlan_policy_mgr_api.h" +#include "qwlan_version.h" +#include "bmi.h" +#include +#include "cdp_txrx_bus.h" +#include "cdp_txrx_misc.h" +#include "pld_common.h" +#include "wlan_hdd_driver_ops.h" +#include "wlan_ipa_ucfg_api.h" +#include "wlan_hdd_debugfs.h" +#include "cfg_ucfg_api.h" +#include +#include +#include +#include "wlan_hdd_thermal.h" +#include "wlan_dp_ucfg_api.h" +#include "qdf_ssr_driver_dump.h" +#include "wlan_hdd_ioctl.h" + +#ifdef MODULE +#ifdef WLAN_WEAR_CHIPSET +#define WLAN_MODULE_NAME "wlan" +#else +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#endif +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#define SSR_MAX_FAIL_CNT 3 +static uint8_t re_init_fail_cnt, probe_fail_cnt; + +/* An atomic flag to check if SSR cleanup has been done or not */ +static qdf_atomic_t is_recovery_cleanup_done; + +/* firmware/host hang event data */ +static uint8_t g_fw_host_hang_event[QDF_HANG_EVENT_DATA_SIZE]; + +/* + * In BMI Phase we are only sending small chunk (256 bytes) of the FW image at + * a time, and wait for the completion interrupt to start the next transfer. + * During this phase, the KRAIT is entering IDLE/StandAlone(SA) Power Save(PS). + * The delay incurred for resuming from IDLE/SA PS is huge during driver load. + * So prevent APPS IDLE/SA PS durint driver load for reducing interrupt latency. + */ + +static inline void hdd_request_pm_qos(struct device *dev, int val) +{ + pld_request_pm_qos(dev, val); +} + +static inline void hdd_remove_pm_qos(struct device *dev) +{ + pld_remove_pm_qos(dev); +} + +/** + * hdd_get_bandwidth_level() - get current bandwidth level + * @data: Context + * + * Return: current bandwidth level + */ +static int hdd_get_bandwidth_level(void *data) +{ + int ret = PLD_BUS_WIDTH_NONE; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (hdd_ctx) + ret = ucfg_dp_get_current_throughput_level(hdd_ctx->psoc); + + return ret; +} + +#ifdef DP_MEM_PRE_ALLOC + +/** + * hdd_get_consistent_mem_unaligned() - API to get consistent unaligned mem + * @size: Size of memory required + * @paddr: Pointer to paddr to be filled in by API + * @ring_type: Pointer to ring type for which consistent memory is needed + * + * Return: Virtual address of consistent memory on success, else null + */ +static +void *hdd_get_consistent_mem_unaligned(size_t size, + qdf_dma_addr_t *paddr, + uint32_t ring_type) +{ + return ucfg_dp_prealloc_get_consistent_mem_unaligned(size, paddr, + ring_type); +} + +/** + * hdd_put_consistent_mem_unaligned() - API to put consistent unaligned mem + * @vaddr: Virtual address of memory + * + * Return: None + */ +static +void hdd_put_consistent_mem_unaligned(void *vaddr) +{ + ucfg_dp_prealloc_put_consistent_mem_unaligned(vaddr); +} + +/** + * hdd_dp_prealloc_get_multi_pages() - gets pre-alloc DP multi-pages memory + * @desc_type: descriptor type + * @elem_size: single element size + * @elem_num: total number of elements should be allocated + * @pages: multi page information storage + * @cacheable: coherent memory or cacheable memory + * + * Return: None + */ +static +void hdd_dp_prealloc_get_multi_pages(uint32_t desc_type, qdf_size_t elem_size, + uint16_t elem_num, + struct qdf_mem_multi_page_t *pages, + bool cacheable) +{ + ucfg_dp_prealloc_get_multi_pages(desc_type, elem_size, elem_num, pages, + cacheable); +} + +/** + * hdd_dp_prealloc_put_multi_pages() - puts back pre-alloc DP multi-pages memory + * @desc_type: descriptor type + * @pages: multi page information storage + * + * Return: None + */ +static +void hdd_dp_prealloc_put_multi_pages(uint32_t desc_type, + struct qdf_mem_multi_page_t *pages) +{ + ucfg_dp_prealloc_put_multi_pages(desc_type, pages); +} +#else +static +void *hdd_get_consistent_mem_unaligned(size_t size, + qdf_dma_addr_t *paddr, + uint32_t ring_type) +{ + hdd_err_rl("prealloc not support!"); + + return NULL; +} + +static +void hdd_put_consistent_mem_unaligned(void *vaddr) +{ + hdd_err_rl("prealloc not support!"); +} + +static inline +void hdd_dp_prealloc_get_multi_pages(uint32_t desc_type, qdf_size_t elem_size, + uint16_t elem_num, + struct qdf_mem_multi_page_t *pages, + bool cacheable) +{ +} + +static inline +void hdd_dp_prealloc_put_multi_pages(uint32_t desc_type, + struct qdf_mem_multi_page_t *pages) +{ +} +#endif + +/** + * hdd_is_driver_unloading() - API to query if driver is unloading + * @data: Private Data + * + * Return: True/False + */ +static bool hdd_is_driver_unloading(void *data) +{ + return cds_is_driver_unloading(); +} + +/** + * hdd_is_load_or_unload_in_progress() - API to query if driver is + * loading/unloading + * @data: Private Data + * + * Return: bool + */ +static bool hdd_is_load_or_unload_in_progress(void *data) +{ + return cds_is_load_or_unload_in_progress(); +} + +/** + * hdd_is_recovery_in_progress() - API to query if recovery in progress + * @data: Private Data + * + * Return: bool + */ +static bool hdd_is_recovery_in_progress(void *data) +{ + return cds_is_driver_recovering(); +} + +/** + * hdd_is_target_ready() - API to query if target is in ready state + * @data: Private Data + * + * Return: bool + */ +static bool hdd_is_target_ready(void *data) +{ + return cds_is_target_ready(); +} + +/** + * hdd_send_driver_ready_to_user() - API to indicate driver ready + * to userspace. + */ +static void hdd_send_driver_ready_to_user(void) +{ + struct sk_buff *nl_event; + struct hdd_context *hdd_ctx; + int flags = cds_get_gfp_flags(); + + hdd_enter(); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD Context is NULL"); + return; + } + + nl_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, 0, + QCA_NL80211_VENDOR_SUBCMD_DRIVER_READY_INDEX, + flags); + if (!nl_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + wlan_cfg80211_vendor_event(nl_event, flags); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_ssr_shutdown_event()- send ssr shutdown state + * + * This Function sends ssr shutdown state diag event + * + * Return: void. + */ +static void hdd_wlan_ssr_shutdown_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(ssr_shutdown, + struct host_event_wlan_ssr_shutdown); + qdf_mem_zero(&ssr_shutdown, sizeof(ssr_shutdown)); + ssr_shutdown.status = SSR_SUB_SYSTEM_SHUTDOWN; + WLAN_HOST_DIAG_EVENT_REPORT(&ssr_shutdown, + EVENT_WLAN_SSR_SHUTDOWN_SUBSYSTEM); +} +#else +static inline void hdd_wlan_ssr_shutdown_event(void) { } +#endif + +/** + * hdd_psoc_shutdown_notify() - notify the various interested parties that the + * soc is starting recovery shutdown + * @hdd_ctx: the HDD context corresponding to the soc undergoing shutdown + * + * Return: None + */ +static void hdd_psoc_shutdown_notify(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL); + + cds_shutdown_notifier_call(); + cds_shutdown_notifier_purge(); + + hdd_wlan_ssr_shutdown_event(); + hdd_exit(); +} + +/** + * hdd_soc_recovery_cleanup() - Perform SSR related cleanup activities. + * + * This function will perform cleanup activities related to when driver + * undergoes SSR. Activities include stopping idle timer and invoking shutdown + * notifier. + * + * Return: None + */ +static void hdd_soc_recovery_cleanup(void) +{ + struct hdd_context *hdd_ctx; + + hdd_enter(); + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + /* cancel/flush any pending/active idle shutdown work */ + hdd_psoc_idle_timer_stop(hdd_ctx); + ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc); + + /* nothing to do if the soc is already unloaded */ + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_info("Driver modules are already closed"); + return; + } + + if (cds_is_load_or_unload_in_progress()) { + hdd_info("Load/unload in progress, ignore SSR shutdown"); + return; + } + + hdd_psoc_shutdown_notify(hdd_ctx); + hdd_exit(); +} + +/** + * hdd_set_recovery_in_progress() - API to set recovery in progress + * @data: Context + * @val: Value to set + * + * Return: None + */ +static void hdd_set_recovery_in_progress(void *data, uint8_t val) +{ + cds_set_recovery_in_progress(val); + /* SSR can be triggred late cleanup existing queue for kernel handshake */ + if (!qdf_in_interrupt()) + hdd_soc_recovery_cleanup(); +} + +/** + * hdd_hif_init_driver_state_callbacks() - API to initialize HIF callbacks + * @data: Private Data + * @cbk: HIF Driver State callbacks + * + * HIF should be independent of CDS calls. Pass CDS Callbacks to HIF, HIF will + * call the callbacks. + * + * Return: void + */ +static void hdd_hif_init_driver_state_callbacks(void *data, + struct hif_driver_state_callbacks *cbk) +{ + cbk->context = data; + cbk->set_recovery_in_progress = hdd_set_recovery_in_progress; + cbk->is_recovery_in_progress = hdd_is_recovery_in_progress; + cbk->is_load_unload_in_progress = hdd_is_load_or_unload_in_progress; + cbk->is_driver_unloading = hdd_is_driver_unloading; + cbk->is_target_ready = hdd_is_target_ready; + cbk->get_bandwidth_level = hdd_get_bandwidth_level; + cbk->prealloc_get_consistent_mem_unaligned = + hdd_get_consistent_mem_unaligned; + cbk->prealloc_put_consistent_mem_unaligned = + hdd_put_consistent_mem_unaligned; + cbk->prealloc_get_multi_pages = + hdd_dp_prealloc_get_multi_pages; + cbk->prealloc_put_multi_pages = + hdd_dp_prealloc_put_multi_pages; +} + +#ifdef HIF_DETECTION_LATENCY_ENABLE +void hdd_hif_set_enable_detection(struct hif_opaque_softc *hif_ctx, bool value) +{ + hif_set_enable_detection(hif_ctx, value); +} +#endif + +#ifdef FORCE_WAKE +void hdd_set_hif_init_phase(struct hif_opaque_softc *hif_ctx, + bool hal_init_phase) +{ + hif_srng_init_phase(hif_ctx, hal_init_phase); +} +#endif /* FORCE_WAKE */ + +/** + * hdd_hif_set_attribute() - API to set CE attribute if memory is limited + * @hif_ctx: hif context + * + * Return: None + */ +#ifdef SLUB_MEM_OPTIMIZE +static void hdd_hif_set_attribute(struct hif_opaque_softc *hif_ctx) +{ + hif_set_attribute(hif_ctx, HIF_LOWDESC_CE_NO_PKTLOG_CFG); +} +#else +static void hdd_hif_set_attribute(struct hif_opaque_softc *hif_ctx) +{} +#endif + +/** + * hdd_hif_register_shutdown_notifier() - Register HIF shutdown notifier + * @hif_ctx: HIF Context + * + * Return: success/failure + */ +static QDF_STATUS +hdd_hif_register_shutdown_notifier(struct hif_opaque_softc *hif_ctx) +{ + return cds_shutdown_notifier_register( + hif_shutdown_notifier_cb, + hif_ctx); +} + +/** + * hdd_hif_set_ce_max_yield_time() - Wrapper API to set CE max yield time + * @hif_ctx: hif context + * @bus_type: underlying bus type + * @ce_service_max_yield_time: max yield time to be set + * + * Return: None + */ +#if defined(CONFIG_SLUB_DEBUG_ON) + +static void hdd_hif_set_ce_max_yield_time(struct hif_opaque_softc *hif_ctx, + enum qdf_bus_type bus_type, + uint32_t ce_service_max_yield_time) +{ +#define CE_SNOC_MAX_YIELD_TIME_US 2000 + + if (bus_type == QDF_BUS_TYPE_SNOC && + ce_service_max_yield_time < CE_SNOC_MAX_YIELD_TIME_US) + ce_service_max_yield_time = CE_SNOC_MAX_YIELD_TIME_US; + + hif_set_ce_service_max_yield_time(hif_ctx, ce_service_max_yield_time); +} + +#else +static void hdd_hif_set_ce_max_yield_time(struct hif_opaque_softc *hif_ctx, + enum qdf_bus_type bus_type, + uint32_t ce_service_max_yield_time) +{ + hif_set_ce_service_max_yield_time(hif_ctx, ce_service_max_yield_time); +} +#endif + +/** + * hdd_init_cds_hif_context() - API to set CDS HIF Context + * @hif: HIF Context + * + * Return: success/failure + */ +static int hdd_init_cds_hif_context(void *hif) +{ + QDF_STATUS status; + + status = cds_set_context(QDF_MODULE_ID_HIF, hif); + + if (status) + return -ENOENT; + + return 0; +} + +/** + * hdd_deinit_cds_hif_context() - API to clear CDS HIF COntext + * + * Return: None + */ +static void hdd_deinit_cds_hif_context(void) +{ + QDF_STATUS status; + + status = cds_set_context(QDF_MODULE_ID_HIF, NULL); + + if (status) + hdd_err("Failed to reset CDS HIF Context"); +} + +/** + * to_bus_type() - Map PLD bus type to low level bus type + * @bus_type: PLD bus type + * + * Map PLD bus type to low level bus type. + * + * Return: low level bus type. + */ +static enum qdf_bus_type to_bus_type(enum pld_bus_type bus_type) +{ + switch (bus_type) { + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_PCIE: + return QDF_BUS_TYPE_PCI; + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + return QDF_BUS_TYPE_SNOC; + case PLD_BUS_TYPE_SDIO: + return QDF_BUS_TYPE_SDIO; + case PLD_BUS_TYPE_USB: + return QDF_BUS_TYPE_USB; + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_IPCI: + return QDF_BUS_TYPE_IPCI; + default: + return QDF_BUS_TYPE_NONE; + } +} + +int hdd_hif_open(struct device *dev, void *bdev, const struct hif_bus_id *bid, + enum qdf_bus_type bus_type, bool reinit) +{ + QDF_STATUS status; + int ret = 0; + struct hif_opaque_softc *hif_ctx; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct hif_driver_state_callbacks cbk; + uint32_t mode = cds_get_conparam(); + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return -EFAULT; + + hdd_hif_init_driver_state_callbacks(dev, &cbk); + + hif_ctx = hif_open(qdf_ctx, mode, bus_type, &cbk, hdd_ctx->psoc); + if (!hif_ctx) { + hdd_err("hif_open error"); + return -ENOMEM; + } + + ret = hdd_init_cds_hif_context(hif_ctx); + if (ret) { + hdd_err("Failed to set global HIF CDS Context err: %d", ret); + goto err_hif_close; + } + + status = hdd_hif_register_shutdown_notifier(hif_ctx); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Shutdown notifier register failed: %d", status); + goto err_deinit_hif_context; + } + + hdd_hif_set_attribute(hif_ctx); + + status = hif_enable(hif_ctx, dev, bdev, bid, bus_type, + (reinit == true) ? HIF_ENABLE_TYPE_REINIT : + HIF_ENABLE_TYPE_PROBE); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hif_enable failed status: %d, reinit: %d", + status, reinit); + + ret = qdf_status_to_os_return(status); + goto err_deinit_hif_context; + } else { + cds_set_target_ready(true); + ret = hdd_napi_create(); + hdd_debug("hdd_napi_create returned: %d", ret); + if (ret == 0) + hdd_debug("NAPI: no instances are created"); + else if (ret < 0) { + hdd_err("NAPI creation error, rc: 0x%x, reinit: %d", + ret, reinit); + ret = -EFAULT; + goto mark_target_not_ready; + } else { + hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)ucfg_dp_get_napi_enabled(hdd_ctx->psoc)); + } + } + + hdd_hif_set_ce_max_yield_time( + hif_ctx, bus_type, + cfg_get(hdd_ctx->psoc, + CFG_DP_CE_SERVICE_MAX_YIELD_TIME)); + ucfg_pmo_psoc_set_hif_handle(hdd_ctx->psoc, hif_ctx); + ucfg_dp_set_hif_handle(hdd_ctx->psoc, hif_ctx); + hif_set_ce_service_max_rx_ind_flush(hif_ctx, + cfg_get(hdd_ctx->psoc, + CFG_DP_CE_SERVICE_MAX_RX_IND_FLUSH)); + return 0; + +mark_target_not_ready: + cds_set_target_ready(false); + +err_deinit_hif_context: + hdd_deinit_cds_hif_context(); + +err_hif_close: + hif_close(hif_ctx); + return ret; +} + +void hdd_hif_close(struct hdd_context *hdd_ctx, void *hif_ctx) +{ + if (!hdd_ctx) { + hdd_err("hdd_ctx error"); + return; + } + + if (!hif_ctx) + return; + + cds_set_target_ready(false); + hif_disable(hif_ctx, HIF_DISABLE_TYPE_REMOVE); + + hdd_napi_destroy(true); + + hdd_deinit_cds_hif_context(); + hif_close(hif_ctx); + + ucfg_pmo_psoc_set_hif_handle(hdd_ctx->psoc, NULL); +} + +/** + * hdd_init_qdf_ctx() - API to initialize global QDF Device structure + * @dev: Device Pointer + * @bdev: Bus Device pointer + * @bus_type: Underlying bus type + * @bid: Bus id passed by platform driver + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_init_qdf_ctx(struct device *dev, void *bdev, + enum qdf_bus_type bus_type, + const struct hif_bus_id *bid) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) + return -EINVAL; + + qdf_dev->dev = dev; + qdf_dev->drv_hdl = bdev; + qdf_dev->bus_type = bus_type; + qdf_dev->bid = bid; + + qdf_dma_invalid_buf_list_init(); + + if (cds_smmu_mem_map_setup(qdf_dev, ucfg_ipa_is_ready()) != + QDF_STATUS_SUCCESS) { + hdd_err("cds_smmu_mem_map_setup() failed"); + } + + return 0; +} + +/** + * hdd_deinit_qdf_ctx() - API to Deinitialize global QDF Device structure + * @domain: Debug domain + * + * Return: 0 - success, < 0 - failure + */ +int hdd_deinit_qdf_ctx(uint8_t domain) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) + return -EINVAL; + + qdf_dma_invalid_buf_free(qdf_dev->dev, domain); + + return 0; +} + +/** + * check_for_probe_defer() - API to check return value + * @ret: Return Value + * + * Return: return -EPROBE_DEFER to platform driver if return value + * is -ENOMEM. Platform driver will try to re-probe. + */ +#ifdef MODULE +static int check_for_probe_defer(int ret) +{ + return ret; +} +#else +static int check_for_probe_defer(int ret) +{ + if (ret == -ENOMEM) + return -EPROBE_DEFER; + return ret; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)) +static void hdd_abort_system_suspend(struct device *dev) +{ + qdf_pm_system_wakeup(); +} +#else +static void hdd_abort_system_suspend(struct device *dev) +{ +} +#endif + +int hdd_soc_idle_restart_lock(struct device *dev) +{ + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_RESTART); + + hdd_abort_system_suspend(dev); + + return 0; +} + +void hdd_soc_idle_restart_unlock(void) +{ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_RESTART); +} + +static void hdd_soc_load_lock(struct device *dev) +{ + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); + hdd_request_pm_qos(dev, DISABLE_KRAIT_IDLE_PS_VAL); +} + +static void hdd_soc_load_unlock(struct device *dev) +{ + hdd_remove_pm_qos(dev); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_INIT); +} + +#ifdef DP_MEM_PRE_ALLOC +/** + * hdd_init_dma_mask() - Set the DMA mask for dma memory pre-allocation + * @dev: device handle + * @bus_type: Bus type for which init is being done + * + * Return: 0 - success, non-zero on failure + */ +static int hdd_init_dma_mask(struct device *dev, enum qdf_bus_type bus_type) +{ + return hif_init_dma_mask(dev, bus_type); +} +#else +static inline int +hdd_init_dma_mask(struct device *dev, enum qdf_bus_type bus_type) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static int __hdd_soc_probe(struct device *dev, + void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type) +{ + struct hdd_context *hdd_ctx; + QDF_STATUS status; + int errno; + + hdd_info("probing driver"); + + hdd_soc_load_lock(dev); + cds_set_load_in_progress(true); + cds_set_driver_in_bad_state(false); + cds_set_recovery_in_progress(false); + + errno = hdd_init_qdf_ctx(dev, bdev, bus_type, bid); + if (errno) + goto unlock; + + errno = hdd_init_dma_mask(dev, bus_type); + if (errno) + goto unlock; + + hdd_ctx = hdd_context_create(dev); + if (IS_ERR(hdd_ctx)) { + errno = PTR_ERR(hdd_ctx); + goto assert_fail_count; + } + + status = ucfg_dp_prealloc_init((struct cdp_ctrl_objmgr_psoc *) + hdd_ctx->psoc); + + if (status != QDF_STATUS_SUCCESS) { + errno = qdf_status_to_os_return(status); + goto dp_prealloc_fail; + } + + errno = hdd_wlan_startup(hdd_ctx); + if (errno) + goto hdd_context_destroy; + + status = hdd_psoc_create_vdevs(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + errno = qdf_status_to_os_return(status); + goto wlan_exit; + } + + probe_fail_cnt = 0; + cds_set_driver_loaded(true); + cds_set_load_in_progress(false); + hdd_start_complete(0); + hdd_thermal_mitigation_register(hdd_ctx, dev); + + hdd_set_sar_init_index(hdd_ctx); + hdd_soc_load_unlock(dev); + + return 0; + +wlan_exit: + hdd_wlan_exit(hdd_ctx); + +hdd_context_destroy: + ucfg_dp_prealloc_deinit(); + +dp_prealloc_fail: + hdd_context_destroy(hdd_ctx); + +assert_fail_count: + probe_fail_cnt++; + hdd_err("consecutive probe failures:%u", probe_fail_cnt); + QDF_BUG(probe_fail_cnt < SSR_MAX_FAIL_CNT); + +unlock: + cds_set_load_in_progress(false); + hdd_soc_load_unlock(dev); + + return check_for_probe_defer(errno); +} + +/** + * hdd_soc_probe() - perform SoC probe + * @dev: kernel device being probed + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * + * A SoC probe indicates new SoC hardware has become available and needs to be + * initialized. + * + * Return: Errno + */ +static int hdd_soc_probe(struct device *dev, + void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + hdd_info("probing driver"); + + errno = osif_psoc_sync_create_and_trans(&psoc_sync); + if (errno) + return errno; + + osif_psoc_sync_register(dev, psoc_sync); + errno = __hdd_soc_probe(dev, bdev, bid, bus_type); + if (errno) + goto destroy_sync; + + osif_psoc_sync_trans_stop(psoc_sync); + + return 0; + +destroy_sync: + osif_psoc_sync_unregister(dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); + + return errno; +} + +static int __hdd_soc_recovery_reinit(struct device *dev, + void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type) +{ + int errno; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_info("re-probing driver"); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null!"); + return qdf_status_to_os_return(QDF_STATUS_E_RESOURCES); + } + + hdd_soc_load_lock(dev); + cds_set_driver_in_bad_state(false); + + errno = hdd_init_qdf_ctx(dev, bdev, bus_type, bid); + if (errno) + goto unlock; + + errno = hdd_wlan_re_init(); + if (errno) { + re_init_fail_cnt++; + goto assert_fail_count; + } + + re_init_fail_cnt = 0; + + /* + * In case of SSR within SSR we have seen the race + * where the reinit is successful and fw down is received + * which sets the recovery in progress. Now as reinit is + * successful we reset the recovery in progress here. + * So check if FW is down then don't reset the recovery + * in progress + */ + if (!qdf_is_fw_down()) { + cds_set_recovery_in_progress(false); + hdd_handle_cached_commands(); + } + + if (!hdd_is_any_interface_open(hdd_ctx)) { + hdd_debug("restarting idle shutdown timer"); + hdd_psoc_idle_timer_start(hdd_ctx); + } + + hdd_soc_load_unlock(dev); + hdd_send_driver_ready_to_user(); + + return 0; + +assert_fail_count: + hdd_err("consecutive reinit failures:%u", re_init_fail_cnt); + QDF_BUG(re_init_fail_cnt < SSR_MAX_FAIL_CNT); + +unlock: + cds_set_driver_in_bad_state(true); + hdd_soc_load_unlock(dev); + hdd_start_complete(errno); + + return check_for_probe_defer(errno); +} + +/** + * hdd_soc_recovery_reinit() - perform PDR/SSR SoC reinit + * @dev: the kernel device being re-initialized + * @bdev: bus device structure + * @bid: bus identifier for shared busses + * @bus_type: underlying bus type + * + * When communication with firmware breaks down, a SoC recovery process kicks in + * with two phases: shutdown and reinit. + * + * SSR reinit is similar to a 'probe' but happens in response to an SSR + * shutdown. The idea is to re-initialize the SoC to as close to its old, + * pre-communications-breakdown configuration as possible. This is completely + * transparent from a userspace point of view. + * + * Return: Errno + */ +static int hdd_soc_recovery_reinit(struct device *dev, + void *bdev, + const struct hif_bus_id *bid, + enum qdf_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + /* if driver is unloading, there is no need to do SSR */ + if (qdf_is_driver_unloading()) { + hdd_info("driver is unloading, avoid SSR"); + return 0; + } + + /* SSR transition is initiated at the beginning of soc shutdown */ + errno = osif_psoc_sync_trans_resume(dev, &psoc_sync); + QDF_BUG(!errno); + if (errno) + return errno; + + errno = __hdd_soc_recovery_reinit(dev, bdev, bid, bus_type); + + + osif_psoc_sync_trans_stop(psoc_sync); + hdd_start_complete(0); + + return errno; +} + +static void __hdd_soc_remove(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + QDF_BUG(hdd_ctx); + if (!hdd_ctx) + return; + + pr_info("%s: Removing driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + + qdf_rtpm_sync_resume(); + cds_set_driver_loaded(false); + cds_set_unload_in_progress(true); + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_warn("Debugfs threads are still active attempting driver unload anyway"); + + if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) { + hdd_wlan_stop_modules(hdd_ctx, false); + qdf_nbuf_deinit_replenish_timer(); + } else { + hdd_thermal_mitigation_unregister(hdd_ctx, dev); + hdd_wlan_exit(hdd_ctx); + } + + hdd_context_destroy(hdd_ctx); + + cds_set_driver_in_bad_state(false); + cds_set_unload_in_progress(false); + + ucfg_dp_prealloc_deinit(); + + pr_info("%s: Driver De-initialized\n", WLAN_MODULE_NAME); +} + +/** + * hdd_soc_remove() - perform SoC remove + * @dev: the kernel device being removed + * + * A SoC remove indicates the attached SoC hardware is about to go away and + * needs to be cleaned up. + * + * Return: void + */ +static void hdd_soc_remove(struct device *dev) +{ + __hdd_soc_remove(dev); +} + +/** + * hdd_send_hang_data() - Send hang data to userspace + * @data: Hang data + * @data_len: Length of @data + * + * Return: None + */ +static void hdd_send_hang_data(uint8_t *data, size_t data_len) +{ + enum qdf_hang_reason reason = QDF_REASON_UNSPECIFIED; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + cds_get_recovery_reason(&reason); + cds_reset_recovery_reason(); + wlan_hdd_send_hang_reason_event(hdd_ctx, reason, data, data_len); +} + +static void __hdd_soc_recovery_shutdown(void) +{ + struct hdd_context *hdd_ctx; + void *hif_ctx; + + /* recovery starts via firmware down indication; ensure we got one */ + QDF_BUG(cds_is_driver_recovering()); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + /* + * Perform SSR related cleanup if it has not already been done as a + * part of receiving the uevent. + */ + if (!qdf_atomic_read(&is_recovery_cleanup_done)) + hdd_soc_recovery_cleanup(); + else + qdf_atomic_set(&is_recovery_cleanup_done, 0); + + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_err("Debugfs threads are still pending, attempting SSR anyway"); + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return; + + /* mask the host controller interrupts */ + hif_mask_interrupt_call(hif_ctx); + + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + hif_disable_isr(hif_ctx); + hdd_wlan_shutdown(); + } +} + +/** + * hdd_soc_recovery_shutdown() - perform PDR/SSR SoC shutdown + * @dev: the device to shutdown + * + * When communication with firmware breaks down, a SoC recovery process kicks in + * with two phases: shutdown and reinit. + * + * SSR shutdown is similar to a 'remove' but without communication with + * firmware. The idea is to retain as much SoC configuration as possible, so it + * can be re-initialized to the same state after a reset. This is completely + * transparent from a userspace point of view. + * + * Return: void + */ +static void hdd_soc_recovery_shutdown(struct device *dev) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + /* if driver is unloading, there is no need to do SSR */ + if (qdf_is_driver_unloading()) { + hdd_info("driver is unloading, avoid SSR"); + return; + } + + errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync); + if (errno) + return; + + ucfg_dp_wait_complete_tasks(); + osif_psoc_sync_wait_for_ops(psoc_sync); + + __hdd_soc_recovery_shutdown(); + + /* SSR transition is concluded at the end of soc re-init */ +} + +/** + * wlan_hdd_crash_shutdown() - wlan_hdd_crash_shutdown + * + * HDD crash shutdown function: This function is called by + * platform driver's crash shutdown routine + * + * Return: void + */ +static void wlan_hdd_crash_shutdown(void) +{ + QDF_STATUS ret; + WMA_HANDLE wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return; + + /* + * When kernel panic happen, if WiFi FW is still active + * it may cause NOC errors/memory corruption, to avoid + * this, inject a fw crash first. + * send crash_inject to FW directly, because we are now + * in an atomic context, and preempt has been disabled, + * MCThread won't be scheduled at the moment, at the same + * time, TargetFailure event won't be received after inject + * crash due to the same reason. + */ + ret = wma_crash_inject(wma_handle, RECOVERY_SIM_ASSERT, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("Failed to send crash inject:%d", ret); + return; + } + + hif_crash_shutdown(cds_get_context(QDF_MODULE_ID_HIF)); +} + +/** + * wlan_hdd_notify_handler() - wlan_hdd_notify_handler + * + * This function is called by the platform driver to notify the + * COEX + * + * @state: state + * + * Return: void + */ +static void wlan_hdd_notify_handler(int state) +{ + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { + int ret; + + ret = hdd_wlan_notify_modem_power_state(state); + if (ret < 0) + hdd_err("Fail to send notify"); + } +} + +static int hdd_to_pmo_interface_pause(enum wow_interface_pause hdd_pause, + enum pmo_wow_interface_pause *pmo_pause) +{ + switch (hdd_pause) { + case WOW_INTERFACE_PAUSE_DEFAULT: + *pmo_pause = PMO_WOW_INTERFACE_PAUSE_DEFAULT; + break; + case WOW_INTERFACE_PAUSE_ENABLE: + *pmo_pause = PMO_WOW_INTERFACE_PAUSE_ENABLE; + break; + case WOW_INTERFACE_PAUSE_DISABLE: + *pmo_pause = PMO_WOW_INTERFACE_PAUSE_DISABLE; + break; + default: + hdd_err("Invalid interface pause: %d", hdd_pause); + return -EINVAL; + } + + return 0; +} + +static int hdd_to_pmo_resume_trigger(enum wow_resume_trigger hdd_trigger, + enum pmo_wow_resume_trigger *pmo_trigger) +{ + switch (hdd_trigger) { + case WOW_RESUME_TRIGGER_DEFAULT: + *pmo_trigger = PMO_WOW_RESUME_TRIGGER_DEFAULT; + break; + case WOW_RESUME_TRIGGER_HTC_WAKEUP: + *pmo_trigger = PMO_WOW_RESUME_TRIGGER_HTC_WAKEUP; + break; + case WOW_RESUME_TRIGGER_GPIO: + *pmo_trigger = PMO_WOW_RESUME_TRIGGER_GPIO; + break; + default: + hdd_err("Invalid resume trigger: %d", hdd_trigger); + return -EINVAL; + } + + return 0; +} + +static int +hdd_to_pmo_wow_enable_params(struct wow_enable_params *in_params, + struct pmo_wow_enable_params *out_params) +{ + int err; + + /* unit-test suspend */ + out_params->is_unit_test = in_params->is_unit_test; + + /* interface pause */ + err = hdd_to_pmo_interface_pause(in_params->interface_pause, + &out_params->interface_pause); + if (err) + return err; + + /* resume trigger */ + err = hdd_to_pmo_resume_trigger(in_params->resume_trigger, + &out_params->resume_trigger); + if (err) + return err; + + return 0; +} + +void __wlan_hdd_trigger_cds_recovery(enum qdf_hang_reason reason, + const char *func, const uint32_t line) +{ + __cds_trigger_recovery(reason, func, line); +} + +/** + * __wlan_hdd_bus_suspend() - handles platform suspend + * @wow_params: collection of wow enable override parameters + * @type: WoW suspend type + * + * Does precondition validation. Ensures that a subsystem restart isn't in + * progress. Ensures that no load or unload is in progress. Does: + * data path suspend + * component (pmo) suspend + * hif (bus) suspend + * + * Return: 0 for success, -EFAULT for null pointers, + * -EBUSY or -EAGAIN if another operation is in progress and + * wlan will not be ready to suspend in time. + */ +static int __wlan_hdd_bus_suspend(struct wow_enable_params wow_params, + enum qdf_suspend_type type) +{ + int err; + QDF_STATUS status; + struct hdd_context *hdd_ctx; + void *hif_ctx; + void *dp_soc; + struct pmo_wow_enable_params pmo_params; + int pending; + struct bbm_params param = {0}; + + hdd_info("starting bus suspend"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -ENODEV; + + err = wlan_hdd_validate_context(hdd_ctx); + if (0 != err) { + if (pld_is_low_power_mode(hdd_ctx->parent_dev)) + hdd_debug("low power mode (Deep Sleep/Hibernate)"); + else + return err; + } + + /* If Wifi is off, return success for system suspend */ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Module closed; skipping suspend"); + return 0; + } + + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + err = hdd_to_pmo_wow_enable_params(&wow_params, &pmo_params); + if (err) { + hdd_err("Invalid WoW enable parameters: %d", err); + return err; + } + + dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + err = qdf_status_to_os_return(ucfg_dp_bus_suspend(dp_soc, + OL_TXRX_PDEV_ID)); + if (err) { + hdd_err("Failed cdp bus suspend: %d", err); + return err; + } + + if (ucfg_ipa_is_tx_pending(hdd_ctx->pdev)) { + hdd_err("failed due to pending IPA TX comps"); + err = -EBUSY; + goto resume_dp; + } + + err = hif_bus_early_suspend(hif_ctx); + if (err) { + hdd_err("Failed hif bus early suspend"); + goto resume_dp; + } + + status = ucfg_pmo_psoc_bus_suspend_req(hdd_ctx->psoc, + type, + &pmo_params); + err = qdf_status_to_os_return(status); + if (err) { + hdd_err("Failed pmo bus suspend: %d", status); + goto late_hif_resume; + } + + hif_system_pm_set_state_suspended(hif_ctx); + + err = hif_bus_suspend(hif_ctx); + if (err) { + hdd_err("Failed hif bus suspend: %d", err); + goto resume_pmo; + } + + status = ucfg_pmo_core_txrx_suspend(hdd_ctx->psoc); + err = qdf_status_to_os_return(status); + if (err) { + hdd_err("Failed to suspend TXRX: %d", err); + goto resume_hif; + } + + pending = cdp_rx_get_pending(cds_get_context(QDF_MODULE_ID_SOC)); + if (pending) { + hdd_debug("Prevent suspend, RX frame pending %d", pending); + err = -EBUSY; + goto resume_txrx; + } + + if (hif_try_prevent_ep_vote_access(hif_ctx)) { + hdd_debug("Prevent suspend, ep work pending"); + err = -EBUSY; + goto resume_txrx; + } + + /* + * Remove bus votes at the very end, after making sure there are no + * pending bus transactions from WLAN SOC for TX/RX. + */ + param.policy = BBM_NON_PERSISTENT_POLICY; + param.policy_info.flag = BBM_APPS_SUSPEND; + ucfg_dp_bbm_apply_independent_policy(hdd_ctx->psoc, ¶m); + + hdd_info("bus suspend succeeded"); + return 0; + +resume_txrx: + status = ucfg_pmo_core_txrx_resume(hdd_ctx->psoc); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_trigger_cds_recovery(QDF_RESUME_TIMEOUT); + return qdf_status_to_os_return(status); + } + +resume_hif: + status = hif_bus_resume(hif_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_trigger_cds_recovery(QDF_RESUME_TIMEOUT); + return qdf_status_to_os_return(status); + } + +resume_pmo: + status = ucfg_pmo_psoc_bus_resume_req(hdd_ctx->psoc, + type); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_trigger_cds_recovery(QDF_RESUME_TIMEOUT); + return qdf_status_to_os_return(status); + } + +late_hif_resume: + status = hif_bus_late_resume(hif_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_trigger_cds_recovery(QDF_RESUME_TIMEOUT); + return qdf_status_to_os_return(status); + } + +resume_dp: + status = ucfg_dp_bus_resume(dp_soc, OL_TXRX_PDEV_ID); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_trigger_cds_recovery(QDF_RESUME_TIMEOUT); + return qdf_status_to_os_return(status); + } + hif_system_pm_set_state_on(hif_ctx); + return err; +} + +int wlan_hdd_bus_suspend(void) +{ + struct wow_enable_params default_params = {0}; + + return __wlan_hdd_bus_suspend(default_params, QDF_SYSTEM_SUSPEND); +} + +#ifdef WLAN_SUSPEND_RESUME_TEST +int wlan_hdd_unit_test_bus_suspend(struct wow_enable_params wow_params) +{ + return __wlan_hdd_bus_suspend(wow_params, QDF_UNIT_TEST_WOW_SUSPEND); +} +#endif + +/** + * wlan_hdd_bus_suspend_noirq() - handle .suspend_noirq callback + * + * This function is called by the platform driver to complete the + * bus suspend callback when device interrupts are disabled by kernel. + * Call HIF and WMA suspend_noirq callbacks to make sure there is no + * wake up pending from FW before allowing suspend. + * + * Return: 0 for success and -EBUSY if FW is requesting wake up + */ +int wlan_hdd_bus_suspend_noirq(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int errno; + uint32_t pending_events; + + hdd_debug("start bus_suspend_noirq"); + + if (!hdd_ctx) + return -ENODEV; + + /* If Wifi is off, return success for system suspend */ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver module closed; skip bus-noirq suspend"); + return 0; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + errno = hif_bus_suspend_noirq(hif_ctx); + if (errno) + goto done; + + errno = ucfg_pmo_psoc_is_target_wake_up_received(hdd_ctx->psoc); + if (errno == -EAGAIN) { + hdd_err("Firmware attempting wakeup, try again"); + wlan_hdd_inc_suspend_stats(hdd_ctx, + SUSPEND_FAIL_INITIAL_WAKEUP); + } + if (errno) + goto resume_hif_noirq; + + pending_events = wma_critical_events_in_flight(); + if (pending_events) { + hdd_err("%d critical event(s) in flight; try again", + pending_events); + errno = -EAGAIN; + goto resume_hif_noirq; + } + + hdd_ctx->suspend_resume_stats.suspends++; + + hdd_debug("bus_suspend_noirq done"); + return 0; + +resume_hif_noirq: + QDF_BUG(!hif_bus_resume_noirq(hif_ctx)); + +done: + hdd_err("suspend_noirq failed, status: %d", errno); + + return errno; +} + +/** + * wlan_hdd_bus_resume() - handles platform resume + * + * @type: WoW suspend type + * + * Does precondition validation. Ensures that a subsystem restart isn't in + * progress. Ensures that no load or unload is in progress. Ensures that + * it has valid pointers for the required contexts. + * Calls into hif to resume the bus operation. + * Calls into wma to handshake with firmware and notify it that the bus is up. + * Calls into ol_txrx for symmetry. + * Failures are treated as catastrophic. + * + * return: error code or 0 for success + */ +int wlan_hdd_bus_resume(enum qdf_suspend_type type) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int status; + QDF_STATUS qdf_status; + void *dp_soc; + struct bbm_params param = {0}; + + if (cds_is_driver_recovering()) + return 0; + + hdd_info("starting bus resume"); + + if (!hdd_ctx) + return -ENODEV; + + /* If Wifi is off, return success for system resume */ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Module closed; return success"); + return 0; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + /* + * Add bus votes at the beginning, before making sure there are any + * bus transactions from WLAN SOC for TX/RX. + */ + param.policy = BBM_NON_PERSISTENT_POLICY; + param.policy_info.flag = BBM_APPS_RESUME; + ucfg_dp_bbm_apply_independent_policy(hdd_ctx->psoc, ¶m); + + status = hif_bus_resume(hif_ctx); + if (status) { + hdd_err("Failed hif bus resume"); + goto out; + } + + hif_system_pm_set_state_resuming(hif_ctx); + + qdf_status = ucfg_pmo_psoc_bus_resume_req(hdd_ctx->psoc, + type); + status = qdf_status_to_os_return(qdf_status); + if (status) { + hdd_err("Failed pmo bus resume"); + goto out; + } + + qdf_status = ucfg_pmo_core_txrx_resume(hdd_ctx->psoc); + status = qdf_status_to_os_return(qdf_status); + if (status) { + hdd_err("Failed to resume TXRX"); + goto out; + } + + hif_system_pm_set_state_on(hif_ctx); + + status = hif_bus_late_resume(hif_ctx); + if (status) { + hdd_err("Failed hif bus late resume"); + goto out; + } + + dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + qdf_status = ucfg_dp_bus_resume(dp_soc, OL_TXRX_PDEV_ID); + status = qdf_status_to_os_return(qdf_status); + if (status) { + hdd_err("Failed cdp bus resume"); + goto out; + } + + hdd_info("bus resume succeeded"); + return 0; + +out: + hif_system_pm_set_state_suspended(hif_ctx); + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state() || + cds_is_fw_down()) + return 0; + + if (status != -ETIMEDOUT) + QDF_BUG(false); + + return status; +} + +/** + * wlan_hdd_bus_resume_noirq(): handle bus resume no irq + * + * This function is called by the platform driver to do bus + * resume no IRQ before calling resume callback. Call WMA and HIF + * layers to complete the resume_noirq. + * + * Return: 0 for success and negative error code for failure + */ +int wlan_hdd_bus_resume_noirq(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + void *hif_ctx; + int status; + QDF_STATUS qdf_status; + + hdd_debug("starting bus_resume_noirq"); + if (cds_is_driver_recovering()) + return 0; + + if (!hdd_ctx) + return -ENODEV; + + /* If Wifi is off, return success for system resume */ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Module closed return success"); + return 0; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + qdf_status = ucfg_pmo_psoc_clear_target_wake_up(hdd_ctx->psoc); + QDF_BUG(!qdf_status); + + status = hif_bus_resume_noirq(hif_ctx); + QDF_BUG(!status); + + hdd_debug("bus_resume_noirq done"); + + return status; +} + +/** + * wlan_hdd_bus_reset_resume() - resume wlan bus after reset + * + * This function is called to tell the driver that the device has been resumed + * and it has also been reset. The driver should redo any necessary + * initialization. It is mainly used by the USB bus + * + * Return: int 0 for success, non zero for failure + */ +static int wlan_hdd_bus_reset_resume(void) +{ + struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF); + + if (!scn) + return -EFAULT; + + return hif_bus_reset_resume(scn); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_pld_runtime_suspend_cb() - Runtime suspend callback from PMO + * + * Return: 0 on success or error value otherwise + */ +static int hdd_pld_runtime_suspend_cb(void) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) + return -EINVAL; + + return pld_auto_suspend(qdf_dev->dev); +} + +/** + * wlan_hdd_runtime_suspend() - suspend the wlan bus without apps suspend + * @dev: Driver device instance + * + * Each layer is responsible for its own suspend actions. wma_runtime_suspend + * takes care of the parts of the 802.11 suspend that we want to do for runtime + * suspend. + * + * Return: 0 or errno + */ +static int wlan_hdd_runtime_suspend(struct device *dev) +{ + int err; + QDF_STATUS status; + struct hdd_context *hdd_ctx; + qdf_time_t delta; + + hdd_debug("Starting runtime suspend"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + err = wlan_hdd_validate_context(hdd_ctx); + if (err) + return err; + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver module closed skipping runtime suspend"); + return 0; + } + + if (!hdd_is_runtime_pm_enabled(hdd_ctx)) + return 0; + + if (ucfg_scan_get_pdev_status(hdd_ctx->pdev) != + SCAN_NOT_IN_PROGRESS) { + hdd_debug("Scan in progress, ignore runtime suspend"); + return -EBUSY; + } + + if (ucfg_ipa_is_tx_pending(hdd_ctx->pdev)) { + hdd_debug("IPA TX comps pending, ignore rtpm suspend"); + return -EBUSY; + } + + if (hdd_ctx->config->runtime_pm == hdd_runtime_pm_dynamic && + wlan_hdd_is_cpu_pm_qos_in_progress(hdd_ctx)) { + hdd_debug("PM QoS Latency constraint, ignore runtime suspend"); + return -EBUSY; + } + + status = ucfg_pmo_psoc_bus_runtime_suspend(hdd_ctx->psoc, + hdd_pld_runtime_suspend_cb); + err = qdf_status_to_os_return(status); + + hdd_ctx->runtime_suspend_done_time_stamp = + qdf_get_log_timestamp_usecs(); + delta = hdd_ctx->runtime_suspend_done_time_stamp - + hdd_ctx->runtime_resume_start_time_stamp; + + if (hdd_ctx->runtime_suspend_done_time_stamp > + hdd_ctx->runtime_resume_start_time_stamp) + hdd_debug("Runtime suspend done result: %d total cxpc up time %lu microseconds", + err, delta); + + if (status == QDF_STATUS_SUCCESS) + ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc); + + hdd_debug("Runtime suspend done result: %d", err); + + return err; +} + +/** + * hdd_pld_runtime_resume_cb() - Runtime resume callback from PMO + * + * Return: 0 on success or error value otherwise + */ +static int hdd_pld_runtime_resume_cb(void) +{ + qdf_device_t qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_dev) + return -EINVAL; + + return pld_auto_resume(qdf_dev->dev); +} + +/** + * wlan_hdd_runtime_resume() - resume the wlan bus from runtime suspend + * @dev: Driver device instance + * + * Sets the runtime pm state and coordinates resume between hif wma and + * ol_txrx. + * + * Return: success since failure is a bug + */ +static int wlan_hdd_runtime_resume(struct device *dev) +{ + struct hdd_context *hdd_ctx; + QDF_STATUS status; + qdf_time_t delta; + + hdd_debug("Starting runtime resume"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + /* + * In__hdd_soc_remove, runtime_sync_resume is called before setting + * unload_in_progress flag. wlan_hdd_validate_context will cause + * resume fail, if driver load/unload in-progress, so not doing + * wlan_hdd_validate_context, have only SSR in progress check. + */ + if (!hdd_ctx) + return 0; + + if (cds_is_driver_recovering()) { + hdd_debug("Recovery in progress, state:0x%x", + cds_get_driver_state()); + return 0; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver module closed skipping runtime resume"); + return 0; + } + + if (!hdd_is_runtime_pm_enabled(hdd_ctx)) + return 0; + + hdd_ctx->runtime_resume_start_time_stamp = + qdf_get_log_timestamp_usecs(); + delta = hdd_ctx->runtime_resume_start_time_stamp - + hdd_ctx->runtime_suspend_done_time_stamp; + hdd_debug("Starting runtime resume total cxpc down time %lu microseconds", + delta); + + status = ucfg_pmo_psoc_bus_runtime_resume(hdd_ctx->psoc, + hdd_pld_runtime_resume_cb); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("PMO Runtime resume failed: %d", status); + } else { + if (policy_mgr_get_connection_count(hdd_ctx->psoc)) + ucfg_dp_bus_bw_compute_timer_try_start(hdd_ctx->psoc); + } + + hdd_debug("Runtime resume done"); + + return 0; +} +#endif + +/** + * wlan_hdd_pld_probe() - probe function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * @bdev: bus device structure + * @id: bus identifier for shared busses + * + * Return: 0 on success + */ +static int wlan_hdd_pld_probe(struct device *dev, + enum pld_bus_type pld_bus_type, + void *bdev, + void *id) +{ + enum qdf_bus_type bus_type = to_bus_type(pld_bus_type); + + if (bus_type == QDF_BUS_TYPE_NONE) { + hdd_err("Invalid bus type %d->%d", pld_bus_type, bus_type); + return -EINVAL; + } + qdf_ssr_driver_dump_register_region("hang_event_data", + g_fw_host_hang_event, + sizeof(g_fw_host_hang_event)); + + return hdd_soc_probe(dev, bdev, id, bus_type); +} + +/** + * wlan_hdd_pld_remove() - remove function registered to PLD + * @dev: device to remove + * @bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_remove(struct device *dev, enum pld_bus_type bus_type) +{ + hdd_enter(); + + hdd_soc_remove(dev); + qdf_ssr_driver_dump_unregister_region("hang_event_data"); + + hdd_exit(); +} + +static void hdd_soc_idle_shutdown_lock(struct device *dev) +{ + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN); + + hdd_abort_system_suspend(dev); +} + +static void hdd_soc_idle_shutdown_unlock(void) +{ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN); +} + +/** + * wlan_hdd_pld_idle_shutdown() - wifi module idle shutdown after interface + * inactivity timeout has triggered idle shutdown + * @dev: device to remove + * @bus_type: PLD bus type + * + * Return: 0 for success and negative error code for failure + */ +static int wlan_hdd_pld_idle_shutdown(struct device *dev, + enum pld_bus_type bus_type) +{ + int ret; + + hdd_soc_idle_shutdown_lock(dev); + + ret = hdd_psoc_idle_shutdown(dev); + + hdd_soc_idle_shutdown_unlock(); + + return ret; +} + +/** + * wlan_hdd_pld_idle_restart() - wifi module idle restart after idle shutdown + * @dev: device to remove + * @bus_type: PLD bus type + * + * Return: 0 for success and negative error code for failure + */ +static int wlan_hdd_pld_idle_restart(struct device *dev, + enum pld_bus_type bus_type) +{ + return hdd_psoc_idle_restart(dev); +} + +/** + * wlan_hdd_pld_shutdown() - shutdown function registered to PLD + * @dev: device to shutdown + * @bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_shutdown(struct device *dev, + enum pld_bus_type bus_type) +{ + hdd_enter(); + + hdd_soc_recovery_shutdown(dev); + + hdd_exit(); +} + +/** + * wlan_hdd_pld_reinit() - reinit function registered to PLD + * @dev: device + * @pld_bus_type: PLD bus type + * @bdev: bus device structure + * @id: bus identifier for shared busses + * + * Return: 0 on success + */ +static int wlan_hdd_pld_reinit(struct device *dev, + enum pld_bus_type pld_bus_type, + void *bdev, + void *id) +{ + enum qdf_bus_type bus_type = to_bus_type(pld_bus_type); + + if (bus_type == QDF_BUS_TYPE_NONE) { + hdd_err("Invalid bus type %d->%d", pld_bus_type, bus_type); + return -EINVAL; + } + + return hdd_soc_recovery_reinit(dev, bdev, id, bus_type); +} + +/** + * wlan_hdd_pld_crash_shutdown() - crash_shutdown function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * + * Return: void + */ +static void wlan_hdd_pld_crash_shutdown(struct device *dev, + enum pld_bus_type bus_type) +{ + wlan_hdd_crash_shutdown(); +} + +/** + * wlan_hdd_pld_suspend() - suspend function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * @state: PM state + * + * Return: 0 on success + */ +static int wlan_hdd_pld_suspend(struct device *dev, + enum pld_bus_type bus_type, + pm_message_t state) + +{ + struct osif_psoc_sync *psoc_sync; + int errno; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -ENODEV; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (0 != errno) { + if (pld_is_low_power_mode(hdd_ctx->parent_dev)) + hdd_debug("low power mode (Deep Sleep/Hibernate)"); + else + return errno; + } + + /* + * Flush the idle shutdown before ops start.This is done here to avoid + * the deadlock as idle shutdown waits for the dsc ops + * to complete. + */ + hdd_psoc_idle_timer_stop(hdd_ctx); + + + errno = osif_psoc_sync_op_start(dev, &psoc_sync); + if (errno) + return errno; + + errno = wlan_hdd_bus_suspend(); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_pld_resume() - resume function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(dev, &psoc_sync); + if (errno) + return errno; + + errno = wlan_hdd_bus_resume(QDF_SYSTEM_SUSPEND); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_pld_suspend_noirq() - handle suspend no irq + * @dev: device + * @bus_type: PLD bus type + * + * Complete the actions started by suspend(). Carry out any + * additional operations required for suspending the device that might be + * racing with its driver's interrupt handler, which is guaranteed not to + * run while suspend_noirq() is being executed. Make sure to resume device + * if FW has sent initial wake up message and expecting APPS to wake up. + * + * Return: 0 on success + */ +static int wlan_hdd_pld_suspend_noirq(struct device *dev, + enum pld_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(dev, &psoc_sync); + if (errno) + return errno; + + errno = wlan_hdd_bus_suspend_noirq(); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_pld_resume_noirq() - handle resume no irq + * @dev: device + * @bus_type: PLD bus type + * + * Prepare for the execution of resume() by carrying out any + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. Make sure to clear target initial + * wake up request such that next suspend can happen cleanly. + * + * Return: 0 on success + */ +static int wlan_hdd_pld_resume_noirq(struct device *dev, + enum pld_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(dev, &psoc_sync); + if (errno) + return errno; + + errno = wlan_hdd_bus_resume_noirq(); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_pld_reset_resume() - reset resume function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_reset_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(dev, &psoc_sync); + if (errno) + return errno; + + errno = wlan_hdd_bus_reset_resume(); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_pld_notify_handler() - notify_handler function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * @state: Modem power state + * + * Return: void + */ +static void wlan_hdd_pld_notify_handler(struct device *dev, + enum pld_bus_type bus_type, + int state) +{ + wlan_hdd_notify_handler(state); +} + +/** + * wlan_hdd_pld_uevent() - platform uevent handler + * @dev: device on which the uevent occurred + * @event_data: uevent parameters + * + * Return: None + */ +static void +wlan_hdd_pld_uevent(struct device *dev, struct pld_uevent_data *event_data) +{ + struct qdf_notifer_data hang_evt_data; + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + enum qdf_hang_reason reason = QDF_REASON_UNSPECIFIED; + uint8_t bus_type; + + bus_type = pld_get_bus_type(dev); + + switch (event_data->uevent) { + case PLD_SMMU_FAULT: + qdf_set_smmu_fault_state(true); + hdd_debug("Received smmu fault indication"); + break; + case PLD_FW_DOWN: + hdd_debug("Received firmware down indication"); + hdd_dump_log_buffer(NULL, NULL); + cds_set_target_ready(false); + cds_set_recovery_in_progress(true); + hdd_init_start_completion(); + + /* Notify external threads currently waiting on firmware + * by forcefully completing waiting events with a "reset" + * status. This will cause the event to fail early instead + * of timing out. + */ + qdf_complete_wait_events(); + + /* + * In case of some platforms, uevent will come to the driver in + * process context. In that case, it is safe to complete the + * SSR cleanup activities in the same context. In case of + * other platforms, it will be invoked in interrupt context. + * Performing the cleanup in interrupt context is not ideal, + * thus defer the cleanup to be done during + * hdd_soc_recovery_shutdown + */ + if (qdf_in_interrupt() || bus_type == PLD_BUS_TYPE_PCIE) + break; + + hdd_soc_recovery_cleanup(); + qdf_atomic_set(&is_recovery_cleanup_done, 1); + + break; + case PLD_FW_HANG_EVENT: + hdd_info("Received firmware hang event"); + cds_get_recovery_reason(&reason); + + if ((reason == QDF_REASON_UNSPECIFIED) && hif_ctx) { + hif_display_ctrl_traffic_pipes_state(hif_ctx); + hif_display_latest_desc_hist(hif_ctx); + } + + qdf_mem_zero(&g_fw_host_hang_event, QDF_HANG_EVENT_DATA_SIZE); + hang_evt_data.hang_data = g_fw_host_hang_event; + hang_evt_data.offset = 0; + qdf_hang_event_notifier_call(reason, &hang_evt_data); + hang_evt_data.offset = QDF_WLAN_HANG_FW_OFFSET; + if (event_data->hang_data.hang_event_data_len >= + QDF_HANG_EVENT_DATA_SIZE / 2) + event_data->hang_data.hang_event_data_len = + QDF_HANG_EVENT_DATA_SIZE / 2; + + if (event_data->hang_data.hang_event_data_len) + qdf_mem_copy((hang_evt_data.hang_data + + hang_evt_data.offset), + event_data->hang_data.hang_event_data, + event_data->hang_data.hang_event_data_len); + + hdd_send_hang_data(hang_evt_data.hang_data, + QDF_HANG_EVENT_DATA_SIZE); + break; + case PLD_BUS_EVENT: + hdd_debug("Bus event received"); + + /* Currently only link_down taken care. + * Need to extend event buffer to define more bus info, + * if need later. + */ + if (event_data->bus_data.etype == PLD_BUS_EVENT_PCIE_LINK_DOWN) + host_log_device_status(WLAN_STATUS_BUS_EXCEPTION); + break; + case PLD_SYS_REBOOT: + hdd_info("Received system reboot"); + cds_set_sys_rebooting(); + break; + default: + /* other events intentionally not handled */ + hdd_debug("Received uevent %d", event_data->uevent); + break; + } + +} + +#ifdef WLAN_FEATURE_SSR_DRIVER_DUMP +static int +wlan_hdd_pld_collect_driver_dump(struct device *dev, + enum pld_bus_type bus_type, + struct cnss_ssr_driver_dump_entry *input_array, + size_t *num_entries_loaded) +{ + QDF_STATUS status; + + status = qdf_ssr_driver_dump_retrieve_regions(input_array, + num_entries_loaded); + return qdf_status_to_os_return(status); +} +#endif + +#ifdef FEATURE_RUNTIME_PM +/** + * wlan_hdd_pld_runtime_suspend() - runtime suspend function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_runtime_suspend(struct device *dev, + enum pld_bus_type bus_type) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(dev, &psoc_sync); + if (errno) + goto out; + + errno = wlan_hdd_runtime_suspend(dev); + + osif_psoc_sync_op_stop(psoc_sync); + +out: + /* If it returns other errno to kernel, it will treat + * it as critical issue, so all the future runtime + * PM api will return error, pm runtime can't be work + * anymore. Such case found in SSR. + */ + if (errno && errno != -EAGAIN && errno != -EBUSY) + errno = -EAGAIN; + return errno; +} + +/** + * wlan_hdd_pld_runtime_resume() - runtime resume function registered to PLD + * @dev: device + * @bus_type: PLD bus type + * + * Return: 0 on success + */ +static int wlan_hdd_pld_runtime_resume(struct device *dev, + enum pld_bus_type bus_type) +{ + /* As opposite to suspend, Runtime PM resume can happen + * synchronously during driver shutdown or idle shutown, + * so remove PSOC sync protection here. + */ + return wlan_hdd_runtime_resume(dev); +} +#endif + +struct pld_driver_ops wlan_drv_ops = { + .probe = wlan_hdd_pld_probe, + .remove = wlan_hdd_pld_remove, + .idle_shutdown = wlan_hdd_pld_idle_shutdown, + .idle_restart = wlan_hdd_pld_idle_restart, + .shutdown = wlan_hdd_pld_shutdown, + .reinit = wlan_hdd_pld_reinit, + .crash_shutdown = wlan_hdd_pld_crash_shutdown, + .suspend = wlan_hdd_pld_suspend, + .resume = wlan_hdd_pld_resume, + .suspend_noirq = wlan_hdd_pld_suspend_noirq, + .resume_noirq = wlan_hdd_pld_resume_noirq, + .reset_resume = wlan_hdd_pld_reset_resume, + .modem_status = wlan_hdd_pld_notify_handler, + .uevent = wlan_hdd_pld_uevent, +#ifdef WLAN_FEATURE_SSR_DRIVER_DUMP + .collect_driver_dump = wlan_hdd_pld_collect_driver_dump, +#endif +#ifdef FEATURE_RUNTIME_PM + .runtime_suspend = wlan_hdd_pld_runtime_suspend, + .runtime_resume = wlan_hdd_pld_runtime_resume, +#endif + .set_curr_therm_cdev_state = wlan_hdd_pld_set_thermal_mitigation, +}; + +int wlan_hdd_register_driver(void) +{ + return pld_register_driver(&wlan_drv_ops); +} + +void wlan_hdd_unregister_driver(void) +{ + pld_unregister_driver(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_eht.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_eht.c new file mode 100644 index 0000000000..950c693e3b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_eht.c @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_eht.c + * + * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) + * support. + * + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_eht.h" +#include "osif_sync.h" +#include "wlan_utility.h" +#include "wlan_mlme_ucfg_api.h" +#include "qc_sap_ioctl.h" +#include "wma_api.h" +#include "wlan_osif_features.h" +#include "wlan_psoc_mlme_ucfg_api.h" + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +#define CHAN_WIDTH_SET_40MHZ_IN_2G \ + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G +#define CHAN_WIDTH_SET_40MHZ_80MHZ_IN_5G \ + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G +#define CHAN_WIDTH_SET_160MHZ_IN_5G \ + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G +#define CHAN_WIDTH_SET_80PLUS80_MHZ_IN_5G \ + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G + +void hdd_update_tgt_eht_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + tDot11fIEeht_cap eht_cap_ini = {0}; + + ucfg_mlme_update_tgt_eht_cap(hdd_ctx->psoc, cfg); + sme_update_tgt_eht_cap(hdd_ctx->mac_handle, cfg, &eht_cap_ini); +} + +/* + * Typical 802.11 Multi-Link element + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Elem ID | Elem Len |Elem ID Extn | MLink Ctrl | Common Info | Link Info | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * 1 1 1 2 Variable Len Variable Len + */ +void wlan_hdd_get_mlo_link_id(struct hdd_beacon_data *beacon, + uint8_t *link_id, uint8_t *num_link) +{ + const uint8_t *mlie, *cmn_info_ie, *link_info_ie; + uint8_t total_len, cmn_info_len, link_info_len; + uint8_t link_len; + + mlie = wlan_get_ext_ie_ptr_from_ext_id(MLO_IE_OUI_TYPE, MLO_IE_OUI_SIZE, + beacon->tail, beacon->tail_len); + if (mlie) { + hdd_debug("ML IE found in beacon data"); + *num_link = 1; + + mlie++; /* WLAN_MAC_EID_EXT */ + total_len = *mlie++; /* length */ + + cmn_info_ie = mlie + 3; + cmn_info_len = *cmn_info_ie; + + /* 802.11 Common info sub-element in Multi-link element + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |Cmn info Len |MLD MAC| Link ID | ..... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * 1 6 0/1 + */ + + *link_id = *(cmn_info_ie + 1 + QDF_MAC_ADDR_SIZE); + + /* Length of link info equal total length minus below: + * 1-Byte Extn Ele ID + * 2-Byte Multi link control + * Length of Common info sub-element + */ + + link_info_ie = cmn_info_ie + cmn_info_len; + link_info_len = total_len - cmn_info_len - 3; + while (link_info_len > 0) { + link_info_ie++; + link_info_len--; + /* length of sub element ID */ + link_len = *link_info_ie++; + link_info_len--; + link_info_ie += link_len; + link_info_len -= link_len; + (*num_link)++; + } + } else { + *num_link = 0; + hdd_debug("ML IE not found in beacon data"); + } +} + +void wlan_hdd_check_11be_support(struct hdd_beacon_data *beacon, + struct sap_config *config) +{ + const uint8_t *ie; + + ie = wlan_get_ext_ie_ptr_from_ext_id(EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE, + beacon->tail, beacon->tail_len); + if (ie) + config->SapHw_mode = eCSR_DOT11_MODE_11be; +} + +static void +hdd_update_wiphy_eht_caps_6ghz(struct hdd_context *hdd_ctx, + tDot11fIEeht_cap eht_cap) +{ + struct ieee80211_supported_band *band_6g = + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_6GHZ]; + uint8_t *phy_info = + hdd_ctx->iftype_data_6g->eht_cap.eht_cap_elem.phy_cap_info; + struct ieee80211_sband_iftype_data *iftype_sta; + struct ieee80211_sband_iftype_data *iftype_ap; + + if (!band_6g || !phy_info) { + hdd_debug("6ghz not supported in wiphy"); + return; + } + + hdd_ctx->iftype_data_6g->types_mask = + (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); + band_6g->n_iftype_data = EHT_OPMODE_SUPPORTED; + band_6g->iftype_data = hdd_ctx->iftype_data_6g; + iftype_sta = hdd_ctx->iftype_data_6g; + iftype_ap = hdd_ctx->iftype_data_6g + 1; + + + hdd_ctx->iftype_data_6g->eht_cap.has_eht = eht_cap.present; + if (hdd_ctx->iftype_data_6g->eht_cap.has_eht && + !hdd_ctx->iftype_data_6g->he_cap.has_he) { + hdd_debug("6 GHz HE caps not present"); + hdd_ctx->iftype_data_6g->eht_cap.has_eht = false; + band_6g->n_iftype_data = 1; + return; + } + + if (eht_cap.support_320mhz_6ghz) + phy_info[0] |= IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + + if (eht_cap.su_beamformer) + phy_info[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; + + if (eht_cap.su_beamformee) + phy_info[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + + qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_6g, + sizeof(struct ieee80211_supported_band)); + + iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); + iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); +} + +void hdd_update_wiphy_eht_cap(struct hdd_context *hdd_ctx) +{ + tDot11fIEeht_cap eht_cap_cfg; + struct ieee80211_supported_band *band_2g = + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]; + struct ieee80211_supported_band *band_5g = + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]; + QDF_STATUS status; + uint8_t *phy_info_5g = + hdd_ctx->iftype_data_5g->eht_cap.eht_cap_elem.phy_cap_info; + uint8_t *phy_info_2g = + hdd_ctx->iftype_data_2g->eht_cap.eht_cap_elem.phy_cap_info; + bool eht_capab; + struct ieee80211_sband_iftype_data *iftype_sta; + struct ieee80211_sband_iftype_data *iftype_ap; + + hdd_enter(); + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (!eht_capab) + return; + + status = ucfg_mlme_cfg_get_eht_caps(hdd_ctx->psoc, &eht_cap_cfg); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (band_2g) { + iftype_sta = hdd_ctx->iftype_data_2g; + iftype_ap = hdd_ctx->iftype_data_2g + 1; + hdd_ctx->iftype_data_2g->types_mask = + (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); + band_2g->n_iftype_data = EHT_OPMODE_SUPPORTED; + band_2g->iftype_data = hdd_ctx->iftype_data_2g; + + hdd_ctx->iftype_data_2g->eht_cap.has_eht = eht_cap_cfg.present; + if (hdd_ctx->iftype_data_2g->eht_cap.has_eht && + !hdd_ctx->iftype_data_2g->he_cap.has_he) { + hdd_debug("2.4 GHz HE caps not present"); + hdd_ctx->iftype_data_2g->eht_cap.has_eht = false; + band_2g->n_iftype_data = 1; + goto band_5ghz; + } + + if (eht_cap_cfg.su_beamformer) + phy_info_2g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; + + if (eht_cap_cfg.su_beamformee) + phy_info_2g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + + qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_2g, + sizeof(struct ieee80211_supported_band)); + + iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); + iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); + } + +band_5ghz: + if (band_5g) { + iftype_sta = hdd_ctx->iftype_data_5g; + iftype_ap = hdd_ctx->iftype_data_5g + 1; + hdd_ctx->iftype_data_5g->types_mask = + (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); + band_5g->n_iftype_data = EHT_OPMODE_SUPPORTED; + band_5g->iftype_data = hdd_ctx->iftype_data_5g; + + hdd_ctx->iftype_data_5g->eht_cap.has_eht = eht_cap_cfg.present; + if (hdd_ctx->iftype_data_5g->eht_cap.has_eht && + !hdd_ctx->iftype_data_5g->he_cap.has_he) { + hdd_debug("5 GHz HE caps not present"); + hdd_ctx->iftype_data_5g->eht_cap.has_eht = false; + band_5g->n_iftype_data = 1; + goto band_6ghz; + } + + if (eht_cap_cfg.su_beamformer) + phy_info_5g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER; + + if (eht_cap_cfg.su_beamformee) + phy_info_5g[0] |= IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE; + + qdf_mem_copy(iftype_ap, hdd_ctx->iftype_data_5g, + sizeof(struct ieee80211_supported_band)); + + iftype_sta->types_mask = BIT(NL80211_IFTYPE_STATION); + iftype_ap->types_mask = BIT(NL80211_IFTYPE_AP); + } + +band_6ghz: + hdd_update_wiphy_eht_caps_6ghz(hdd_ctx, eht_cap_cfg); + + hdd_exit(); +} + +int hdd_set_11be_rate_code(struct hdd_adapter *adapter, uint16_t rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int ret; + struct sap_config *sap_config = NULL; + + if (adapter->device_mode == QDF_SAP_MODE) + sap_config = &adapter->deflink->session.ap.sap_config; + + if (!sap_config) { + if (!sme_is_feature_supported_by_fw(DOT11BE)) { + hdd_err_rl("Target does not support 11be"); + return -EIO; + } + } else if (sap_config->SapHw_mode != eCSR_DOT11_MODE_11be && + sap_config->SapHw_mode != eCSR_DOT11_MODE_11be_ONLY) { + hdd_err_rl("Invalid hw mode, SAP hw_mode= 0x%x, ch_freq = %d", + sap_config->SapHw_mode, sap_config->chan_freq); + return -EIO; + } + + if ((rate_code >> 8) != WMI_RATE_PREAMBLE_EHT) { + hdd_err_rl("Invalid input: %x", rate_code); + return -EIO; + } + + rix = RC_2_RATE_IDX_11BE(rate_code); + preamble = rate_code >> 8; + nss = HT_RC_2_STREAMS_11BE(rate_code) + 1; + + hdd_debug("SET_11BE_RATE rate_code %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + + return ret; +} + +/** + * hdd_map_eht_gi_to_os() - map txrate_gi to os guard interval + * @guard_interval: guard interval get from fw rate + * + * Return: os guard interval value + */ +static inline uint8_t hdd_map_eht_gi_to_os(enum txrate_gi guard_interval) +{ + switch (guard_interval) { + case TXRATE_GI_0_8_US: + return NL80211_RATE_INFO_EHT_GI_0_8; + case TXRATE_GI_1_6_US: + return NL80211_RATE_INFO_EHT_GI_1_6; + case TXRATE_GI_3_2_US: + return NL80211_RATE_INFO_EHT_GI_3_2; + default: + return NL80211_RATE_INFO_EHT_GI_0_8; + } +} + +/** + * wlan_hdd_fill_os_eht_rateflags() - Fill EHT related rate_info + * @os_rate: rate info for os + * @rate_flags: rate flags + * @dcm: dcm from rate + * @guard_interval: guard interval from rate + * + * Return: none + */ +void wlan_hdd_fill_os_eht_rateflags(struct rate_info *os_rate, + enum tx_rate_info rate_flags, + uint8_t dcm, + enum txrate_gi guard_interval) +{ + /* as fw not yet report ofdma to host, so don't + * fill RATE_INFO_BW_EHT_RU. + */ + if (rate_flags & (TX_RATE_EHT80 | TX_RATE_EHT40 | + TX_RATE_EHT20 | TX_RATE_EHT160 | TX_RATE_EHT320)) { + if (rate_flags & TX_RATE_EHT320) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_320); + else if (rate_flags & TX_RATE_EHT160) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_160); + else if (rate_flags & TX_RATE_EHT80) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_80); + else if (rate_flags & TX_RATE_EHT40) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_40); + + os_rate->flags |= RATE_INFO_FLAGS_EHT_MCS; + } +} + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +void +wlan_hdd_refill_os_eht_rateflags(struct rate_info *os_rate, uint8_t preamble) +{ + if (preamble == DOT11_BE) + os_rate->flags |= RATE_INFO_FLAGS_EHT_MCS; +} + +void +wlan_hdd_refill_os_eht_bw(struct rate_info *os_rate, enum rx_tlv_bw bw) +{ + if (bw == RX_TLV_BW_320MHZ) + os_rate->bw = RATE_INFO_BW_320; + else + os_rate->bw = RATE_INFO_BW_20; /* Invalid bw: set 20M */ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c new file mode 100644 index 0000000000..24ba2346a2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.c @@ -0,0 +1,4008 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_ext_scan.c + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "osif_sync.h" +#include "wlan_hdd_ext_scan.h" +#include "wlan_hdd_regulatory.h" +#include "cds_utils.h" +#include "cds_sched.h" +#include +#include "wlan_extscan_ucfg_api.h" +#include "wlan_hdd_scan.h" + +/* amount of time to wait for a synchronous request/response operation */ +#define WLAN_WAIT_TIME_EXTSCAN 1000 + +/** + * struct hdd_ext_scan_context - hdd ext scan context + * @request_id: userspace-assigned ID associated with the request + * @response_event: Ext scan wait event + * @response_status: Status returned by FW in response to a request + * @ignore_cached_results: Flag to ignore cached results or not + * @context_lock: Spinlock to serialize all context accesses + * @capability_response: Ext scan capability response data from target + * @buckets_scanned: bitmask of buckets scanned in extscan cycle + */ +struct hdd_ext_scan_context { + uint32_t request_id; + int response_status; + bool ignore_cached_results; + struct completion response_event; + spinlock_t context_lock; + struct ext_scan_capabilities_response capability_response; + uint32_t buckets_scanned; +}; +static struct hdd_ext_scan_context ext_scan_context; + +const struct nla_policy +wlan_hdd_extscan_config_policy[EXTSCAN_PARAM_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CLASS] = {.type = NLA_U8}, + + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH] = { + .type = NLA_U8}, + + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_MAX] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_CHANNEL] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_SSID] = { + .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN + 1 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_LOST_SSID_SAMPLE_SIZE] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_HOTLIST_PARAMS_NUM_SSID] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_BAND] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_LOW] = { + .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_SSID_THRESHOLD_PARAM_RSSI_HIGH] = { + .type = NLA_S32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE] = { + .type = NLA_U32}, +}; + +const struct nla_policy +wlan_hdd_pno_config_policy[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID] = { + .type = NLA_BINARY, + .len = IEEE80211_MAX_SSID_LEN + 1 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS] = { + .type = NLA_U8 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT] = { + .type = NLA_U8 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID] = { + .type = NLA_U32 + }, +}; + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities_rsp() - response from target + * @hdd_ctx: Pointer to hdd context + * @data: Pointer to ext scan capabilities response from fw + * + * Return: None + */ +static void +wlan_hdd_cfg80211_extscan_get_capabilities_rsp(struct hdd_context *hdd_ctx, + struct ext_scan_capabilities_response *data) +{ + struct hdd_ext_scan_context *context; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + context = &ext_scan_context; + + spin_lock(&context->context_lock); + /* validate response received from target*/ + if (context->request_id != data->requestId) { + spin_unlock(&context->context_lock); + hdd_err("Target response id did not match. request_id: %d response_id: %d", + context->request_id, data->requestId); + return; + } + + context->capability_response = *data; + complete(&context->response_event); + spin_unlock(&context->context_lock); +} + +/* + * define short names for the global vendor params + * used by hdd_extscan_nl_fill_bss() + */ +#define PARAM_TIME_STAMP \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP +#define PARAM_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID +#define PARAM_BSSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID +#define PARAM_CHANNEL \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL +#define PARAM_RSSI \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI +#define PARAM_RTT \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT +#define PARAM_RTT_SD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD +#define PARAM_BEACON_PERIOD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD +#define PARAM_CAPABILITY \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY +#define PARAM_IE_LENGTH \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH +#define PARAM_IE_DATA \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA + +/** hdd_extscan_nl_fill_bss() - extscan nl fill bss + * @skb: socket buffer + * @ap: bss information + * @idx: nesting index + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_nl_fill_bss(struct sk_buff *skb, tSirWifiScanResult *ap, + int idx) +{ + struct nlattr *nla_ap; + + nla_ap = nla_nest_start(skb, idx); + if (!nla_ap) + return -EINVAL; + + if (hdd_wlan_nla_put_u64(skb, PARAM_TIME_STAMP, ap->ts) || + nla_put(skb, PARAM_SSID, sizeof(ap->ssid), ap->ssid) || + nla_put(skb, PARAM_BSSID, sizeof(ap->bssid), ap->bssid.bytes) || + nla_put_u32(skb, PARAM_CHANNEL, ap->channel) || + nla_put_s32(skb, PARAM_RSSI, ap->rssi) || + nla_put_u32(skb, PARAM_RTT, ap->rtt) || + nla_put_u32(skb, PARAM_RTT_SD, ap->rtt_sd) || + nla_put_u16(skb, PARAM_BEACON_PERIOD, ap->beaconPeriod) || + nla_put_u16(skb, PARAM_CAPABILITY, ap->capability) || + nla_put_u16(skb, PARAM_IE_LENGTH, ap->ieLength)) { + hdd_err("put fail"); + return -EINVAL; + } + + if (ap->ieLength) + if (nla_put(skb, PARAM_IE_DATA, ap->ieLength, ap->ieData)) { + hdd_err("put fail"); + return -EINVAL; + } + + nla_nest_end(skb, nla_ap); + + return 0; +} +/* + * done with short names for the global vendor params + * used by hdd_extscan_nl_fill_bss() + */ +#undef PARAM_TIME_STAMP +#undef PARAM_SSID +#undef PARAM_BSSID +#undef PARAM_CHANNEL +#undef PARAM_RSSI +#undef PARAM_RTT +#undef PARAM_RTT_SD +#undef PARAM_BEACON_PERIOD +#undef PARAM_CAPABILITY +#undef PARAM_IE_LENGTH +#undef PARAM_IE_DATA + +/** + * wlan_hdd_cfg80211_extscan_cached_results_ind() - get cached results + * @hdd_ctx: hdd global context + * @data: cached results + * + * This function reads the cached results %data, populated the NL + * attributes and sends the NL event to the upper layer. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_cached_results_ind(struct hdd_context *hdd_ctx, + struct extscan_cached_scan_results *data) +{ + struct sk_buff *skb = NULL; + struct hdd_ext_scan_context *context; + struct extscan_cached_scan_result *result; + tSirWifiScanResult *ap; + uint32_t i, j, nl_buf_len; + bool ignore_cached_results = false; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + ignore_cached_results = context->ignore_cached_results; + spin_unlock(&context->context_lock); + + if (ignore_cached_results) { + hdd_err("Ignore the cached results received after timeout"); + return; + } + +#define EXTSCAN_CACHED_NEST_HDRLEN NLA_HDRLEN +#define EXTSCAN_CACHED_NL_FIXED_TLV \ + ((sizeof(data->request_id) + NLA_HDRLEN) + \ + (sizeof(data->num_scan_ids) + NLA_HDRLEN) + \ + (sizeof(data->more_data) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_ID_TLV \ + ((sizeof(result->scan_id) + NLA_HDRLEN) + \ + (sizeof(result->flags) + NLA_HDRLEN) + \ + (sizeof(result->num_results) + NLA_HDRLEN))+ \ + (sizeof(result->buckets_scanned) + NLA_HDRLEN) +#define EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV \ + ((sizeof(ap->ts) + NLA_HDRLEN) + \ + (sizeof(ap->ssid) + NLA_HDRLEN) + \ + (sizeof(ap->bssid) + NLA_HDRLEN) + \ + (sizeof(ap->channel) + NLA_HDRLEN) + \ + (sizeof(ap->rssi) + NLA_HDRLEN) + \ + (sizeof(ap->rtt) + NLA_HDRLEN) + \ + (sizeof(ap->rtt_sd) + NLA_HDRLEN) + \ + (sizeof(ap->beaconPeriod) + NLA_HDRLEN) + \ + (sizeof(ap->capability) + NLA_HDRLEN) + \ + (sizeof(ap->ieLength) + NLA_HDRLEN)) +#define EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV \ + (ap->ieLength + NLA_HDRLEN) + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NL_FIXED_TLV; + if (data->num_scan_ids) { + nl_buf_len += sizeof(result->scan_id) + NLA_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + result = &data->result[0]; + for (i = 0; i < data->num_scan_ids; i++) { + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + nl_buf_len += EXTSCAN_CACHED_NL_SCAN_ID_TLV; + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + nl_buf_len += EXTSCAN_CACHED_NEST_HDRLEN; + nl_buf_len += + EXTSCAN_CACHED_NL_SCAN_RESULTS_TLV; + if (ap->ieLength) + nl_buf_len += + EXTSCAN_CACHED_NL_SCAN_RESULTS_IE_DATA_TLV; + ap++; + } + result++; + } + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + goto fail; + } + hdd_debug("Req Id %u Num_scan_ids %u More Data %u", + data->request_id, data->num_scan_ids, data->more_data); + + result = &data->result[0]; + for (i = 0; i < data->num_scan_ids; i++) { + hdd_debug("[i=%d] scan_id %u flags %u num_results %u buckets scanned %u", + i, result->scan_id, result->flags, result->num_results, + result->buckets_scanned); + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + /* + * Firmware returns timestamp from ext scan start till + * BSSID was cached (in micro seconds). Add this with + * time gap between system boot up to ext scan start + * to derive the time since boot when the + * BSSID was cached. + */ + ap->ts += hdd_ctx->ext_scan_start_since_boot; + hdd_debug("Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Beacon Period %u Capability 0x%x Ie length %d", + ap->ts, + QDF_SSID_REF(WLAN_SSID_MAX_LEN, ap->ssid), + QDF_MAC_ADDR_REF(ap->bssid.bytes), + ap->channel, ap->rssi, ap->rtt, ap->rtt_sd, + ap->beaconPeriod, ap->capability, + ap->ieLength); + ap++; + } + result++; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + data->num_scan_ids) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->more_data)) { + hdd_err("put fail"); + goto fail; + } + + if (data->num_scan_ids) { + struct nlattr *nla_results; + + result = &data->result[0]; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id)) { + hdd_err("put fail"); + goto fail; + } + nla_results = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_LIST); + if (!nla_results) + goto fail; + + for (i = 0; i < data->num_scan_ids; i++) { + struct nlattr *nla_result; + struct nlattr *nla_aps; + + nla_result = nla_nest_start(skb, i); + if (!nla_result) + goto fail; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_SCAN_ID, + result->scan_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CACHED_RESULTS_FLAGS, + result->flags) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, + result->buckets_scanned) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + result->num_results)) { + hdd_err("put fail"); + goto fail; + } + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_aps) + goto fail; + + ap = &result->ap[0]; + for (j = 0; j < result->num_results; j++) { + if (hdd_extscan_nl_fill_bss(skb, ap, j)) + goto fail; + + ap++; + } + nla_nest_end(skb, nla_aps); + nla_nest_end(skb, nla_result); + result++; + } + nla_nest_end(skb, nla_results); + } + + wlan_cfg80211_vendor_cmd_reply(skb); + + if (!data->more_data) { + spin_lock(&context->context_lock); + context->response_status = 0; + complete(&context->response_event); + spin_unlock(&context->context_lock); + } + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); + spin_lock(&context->context_lock); + context->response_status = -EINVAL; + spin_unlock(&context->context_lock); +} + +/** + * wlan_hdd_cfg80211_extscan_hotlist_match_ind() - hot list match ind + * @hdd_ctx: Pointer to hdd context + * @data: Pointer to ext scan result event + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_hotlist_match_ind(struct hdd_context *hdd_ctx, + struct extscan_hotlist_match *data) +{ + struct sk_buff *skb = NULL; + uint32_t i, index; + int flags = cds_get_gfp_flags(); + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + if (data->ap_found) + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_FOUND_INDEX; + else + index = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_HOTLIST_AP_LOST_INDEX; + + skb = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + index, flags); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + hdd_debug("Req Id: %u Num_APs: %u MoreData: %u ap_found: %u", + data->requestId, data->numOfAps, data->moreData, + data->ap_found); + + for (i = 0; i < data->numOfAps; i++) { + data->ap[i].ts = qdf_get_monotonic_boottime(); + hdd_debug("[i=%d] Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u", + i, data->ap[i].ts, + QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap[i].ssid), + QDF_MAC_ADDR_REF(data->ap[i].bssid.bytes), + data->ap[i].channel, data->ap[i].rssi, + data->ap[i].rtt, data->ap[i].rtt_sd); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + data->numOfAps)) { + hdd_err("put fail"); + goto fail; + } + + if (data->numOfAps) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + for (i = 0; i < data->numOfAps; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) + goto fail; + + if (hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + data->ap[i].ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(data->ap[i].ssid), + data->ap[i].ssid) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(data->ap[i].bssid), + data->ap[i].bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + data->ap[i].channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + data->ap[i].rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + data->ap[i].rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + data->ap[i].rtt_sd)) + goto fail; + + nla_nest_end(skb, ap); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->moreData)) + goto fail; + } + + wlan_cfg80211_vendor_event(skb, flags); + hdd_exit(); + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind() - + * significant wifi change results indication + * @hdd_ctx: Pointer to hdd context + * @data: Pointer to signif wifi change event + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind( + struct hdd_context *hdd_ctx, + tpSirWifiSignificantChangeEvent data) +{ + struct sk_buff *skb = NULL; + tSirWifiSignificantChange *ap_info; + int32_t *rssi; + uint32_t i, j; + int flags = cds_get_gfp_flags(); + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SIGNIFICANT_CHANGE_INDEX, + flags); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + hdd_debug("Req Id %u Num results %u More Data %u", + data->requestId, data->numResults, data->moreData); + + ap_info = &data->ap[0]; + for (i = 0; i < data->numResults; i++) { + hdd_debug("[i=%d] " + "Bssid (" QDF_MAC_ADDR_FMT ") " + "Channel %u " + "numOfRssi %d", + i, + QDF_MAC_ADDR_REF(ap_info->bssid.bytes), + ap_info->channel, ap_info->numOfRssi); + rssi = &(ap_info)->rssi[0]; + for (j = 0; j < ap_info->numOfRssi; j++) + hdd_debug("Rssi %d", *rssi++); + + ap_info = (tSirWifiSignificantChange *)((char *)ap_info + + ap_info->numOfRssi * sizeof(*rssi) + + sizeof(*ap_info)); + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + data->numResults)) { + hdd_err("put fail"); + goto fail; + } + + if (data->numResults) { + struct nlattr *aps; + + aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!aps) + goto fail; + + ap_info = &data->ap[0]; + for (i = 0; i < data->numResults; i++) { + struct nlattr *ap; + + ap = nla_nest_start(skb, i); + if (!ap) + goto fail; + + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_BSSID, + QDF_MAC_ADDR_SIZE, ap_info->bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_CHANNEL, + ap_info->channel) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_NUM_RSSI, + ap_info->numOfRssi) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SIGNIFICANT_CHANGE_RESULT_RSSI_LIST, + sizeof(s32) * ap_info->numOfRssi, + &(ap_info)->rssi[0])) + goto fail; + + nla_nest_end(skb, ap); + + ap_info = (tSirWifiSignificantChange *)((char *)ap_info + + ap_info->numOfRssi * sizeof(*rssi) + + sizeof(*ap_info)); + } + nla_nest_end(skb, aps); + + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->moreData)) + goto fail; + } + + wlan_cfg80211_vendor_event(skb, flags); + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); + return; + +} + +/** + * wlan_hdd_cfg80211_extscan_full_scan_result_event() - full scan result event + * @hdd_ctx: Pointer to hdd context + * @data: Pointer to full scan result event + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_full_scan_result_event(struct hdd_context *hdd_ctx, + tpSirWifiFullScanResultEvent + data) +{ + struct sk_buff *skb; + struct hdd_ext_scan_context *context; + + int flags = cds_get_gfp_flags(); + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + if ((sizeof(*data) + data->ap.ieLength) >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Frame exceeded NL size limitation, drop it!!"); + return; + } + skb = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_FULL_SCAN_RESULT_INDEX, + flags); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + data->ap.channel = cds_chan_to_freq(data->ap.channel); + + /* + * Android does not want the time stamp from the frame. + * Instead it wants a monotonic increasing value since boot + */ + data->ap.ts = qdf_get_monotonic_boottime(); + + hdd_debug("Req Id %u More Data %u", data->requestId, data->moreData); + hdd_debug("AP Info: Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d", + data->ap.ts, + QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap.ssid), + QDF_MAC_ADDR_REF(data->ap.bssid.bytes), + data->ap.channel, data->ap.rssi, data->ap.rtt, + data->ap.rtt_sd, data->ap.beaconPeriod, + data->ap.capability, data->ap.ieLength); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_TIME_STAMP, + data->ap.ts) || + nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_SSID, + sizeof(data->ap.ssid), + data->ap.ssid) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BSSID, + sizeof(data->ap.bssid), + data->ap.bssid.bytes) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CHANNEL, + data->ap.channel) || + nla_put_s32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RSSI, + data->ap.rssi) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT, + data->ap.rtt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_RTT_SD, + data->ap.rtt_sd) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_BEACON_PERIOD, + data->ap.beaconPeriod) || + nla_put_u16(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_CAPABILITY, + data->ap.capability) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_LENGTH, + data->ap.ieLength) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->moreData)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + if (data->ap.ieLength) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_IE_DATA, + data->ap.ieLength, data->ap.ieData)) + goto nla_put_failure; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_BUCKETS_SCANNED, + context->buckets_scanned)) { + spin_unlock(&context->context_lock); + hdd_debug("Failed to include buckets_scanned"); + goto nla_put_failure; + } + spin_unlock(&context->context_lock); + + wlan_cfg80211_vendor_event(skb, flags); + return; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_scan_res_available_event() - scan result event + * @hdd_ctx: Pointer to hdd context + * @data: Pointer to scan results available indication param + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_scan_res_available_event( + struct hdd_context *hdd_ctx, + tpSirExtScanResultsAvailableIndParams data) +{ + struct sk_buff *skb; + int flags = cds_get_gfp_flags(); + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_RESULTS_AVAILABLE_INDEX, + flags); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("Req Id %u Num results %u", + data->requestId, data->numResultsAvailable); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + data->numResultsAvailable)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_event(skb, flags); + hdd_exit(); + return; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_scan_progress_event() - scan progress event + * @hdd_ctx: Pointer to hdd context + * @data: Pointer to scan event indication param + * + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_scan_progress_event(struct hdd_context *hdd_ctx, + tpSirExtScanOnScanEventIndParams + data) +{ + struct sk_buff *skb; + int flags = cds_get_gfp_flags(); + struct hdd_ext_scan_context *context; + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, + NULL, + EXTSCAN_EVENT_BUF_SIZE + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SCAN_EVENT_INDEX, + flags); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("Request Id: %u Scan event type: %u Scan event status: %u buckets scanned: %u", + data->requestId, data->scanEventType, data->status, + data->buckets_scanned); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (data->scanEventType == WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT) { + context->buckets_scanned = 0; + data->scanEventType = WIFI_EXTSCAN_RESULTS_AVAILABLE; + spin_unlock(&context->context_lock); + } else if (data->scanEventType == WIFI_EXTSCAN_CYCLE_STARTED_EVENT) { + context->buckets_scanned = data->buckets_scanned; + /* No need to report to user space */ + spin_unlock(&context->context_lock); + goto nla_put_failure; + } else { + spin_unlock(&context->context_lock); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->requestId) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_EVENT_TYPE, + data->scanEventType)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_event(skb, flags); + return; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_epno_match_found() - pno match found + * @hdd_ctx: HDD context + * @data: matched network data + * + * This function reads the matched network data and fills NL vendor attributes + * and send it to upper layer. + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: 0 on success, error number otherwise + */ +static void +wlan_hdd_cfg80211_extscan_epno_match_found(struct hdd_context *hdd_ctx, + struct pno_match_found *data) +{ + struct sk_buff *skb; + uint32_t len, i; + int flags = cds_get_gfp_flags(); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_NETWORK_FOUND_INDEX; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + /* + * If the number of match found APs including IE data exceeds NL 4K size + * limitation, drop that beacon/probe rsp frame. + */ + len = sizeof(*data) + + (data->num_results + sizeof(tSirWifiScanResult)); + for (i = 0; i < data->num_results; i++) + len += data->ap[i].ieLength; + + if (len >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Frame exceeded NL size limitation, drop it!"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + EXTSCAN_EVENT_BUF_SIZE + + NLMSG_HDRLEN, + index, flags); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("Req Id %u More Data %u num_results %d", + data->request_id, data->more_data, data->num_results); + for (i = 0; i < data->num_results; i++) { + data->ap[i].channel = cds_chan_to_freq(data->ap[i].channel); + hdd_debug("AP Info: Timestamp %llu) Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d", + data->ap[i].ts, + QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap[i].ssid), + QDF_MAC_ADDR_REF(data->ap[i].bssid.bytes), + data->ap[i].channel, data->ap[i].rssi, + data->ap[i].rtt, data->ap[i].rtt_sd, + data->ap[i].beaconPeriod, data->ap[i].capability, + data->ap[i].ieLength); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_NUM_RESULTS_AVAILABLE, + data->num_results) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + data->more_data)) { + hdd_err("nla put fail"); + goto fail; + } + + if (data->num_results) { + struct nlattr *nla_aps; + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_aps) + goto fail; + + for (i = 0; i < data->num_results; i++) { + if (hdd_extscan_nl_fill_bss(skb, &data->ap[i], i)) + goto fail; + } + nla_nest_end(skb, nla_aps); + } + + wlan_cfg80211_vendor_event(skb, flags); + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); +} + +/** + * wlan_hdd_cfg80211_passpoint_match_found() - passpoint match found + * @ctx: HDD context + * @data: matched network data + * + * This function reads the match network %data and fill in the skb with + * NL attributes and send up the NL event + * This callback execute in atomic context and must not invoke any + * blocking calls. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_passpoint_match_found(void *ctx, + struct wifi_passpoint_match *data) +{ + struct hdd_context *hdd_ctx = ctx; + struct sk_buff *skb = NULL; + uint32_t len, i, num_matches = 1, more_data = 0; + struct nlattr *nla_aps, *nla_bss; + int flags = cds_get_gfp_flags(); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_PASSPOINT_NETWORK_FOUND_INDEX; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + len = sizeof(*data) + data->ap.ieLength + data->anqp_len; + if (len >= EXTSCAN_EVENT_BUF_SIZE) { + hdd_err("Result exceeded NL size limitation, drop it"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + EXTSCAN_EVENT_BUF_SIZE + + NLMSG_HDRLEN, + index, flags); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("Req Id %u Id %u ANQP length %u num_matches %u", + data->request_id, data->id, data->anqp_len, num_matches); + for (i = 0; i < num_matches; i++) { + hdd_debug("AP Info: Timestamp %llu Ssid: " QDF_SSID_FMT " Bssid (" QDF_MAC_ADDR_FMT ") Channel %u Rssi %d RTT %u RTT_SD %u Bcn Period %d Capability 0x%X IE Length %d", + data->ap.ts, + QDF_SSID_REF(WLAN_SSID_MAX_LEN, data->ap.ssid), + QDF_MAC_ADDR_REF(data->ap.bssid.bytes), + data->ap.channel, data->ap.rssi, data->ap.rtt, + data->ap.rtt_sd, data->ap.beaconPeriod, + data->ap.capability, data->ap.ieLength); + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_REQUEST_ID, + data->request_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_NETWORK_FOUND_NUM_MATCHES, + num_matches) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_SCAN_RESULT_MORE_DATA, + more_data)) { + hdd_err("nla put fail"); + goto fail; + } + + nla_aps = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_RESULT_LIST); + if (!nla_aps) + goto fail; + + for (i = 0; i < num_matches; i++) { + struct nlattr *nla_ap; + + nla_ap = nla_nest_start(skb, i); + if (!nla_ap) + goto fail; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ID, + data->id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP_LEN, + data->anqp_len)) { + goto fail; + } + + if (data->anqp_len) + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_PNO_RESULTS_PASSPOINT_MATCH_ANQP, + data->anqp_len, data->anqp)) + goto fail; + + nla_bss = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_LIST); + if (!nla_bss) + goto fail; + + if (hdd_extscan_nl_fill_bss(skb, &data->ap, 0)) + goto fail; + + nla_nest_end(skb, nla_bss); + nla_nest_end(skb, nla_ap); + } + nla_nest_end(skb, nla_aps); + + wlan_cfg80211_vendor_event(skb, flags); + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); +} + +/** + * wlan_hdd_cfg80211_extscan_generic_rsp() - + * Handle a generic ExtScan Response message + * @hdd_ctx: HDD context registered with SME + * @response: The ExtScan response from firmware + * + * This function will handle a generic ExtScan response message from + * firmware and will communicate the result to the userspace thread + * that is waiting for the response. + * + * Return: none + */ +static void +wlan_hdd_cfg80211_extscan_generic_rsp(struct hdd_context *hdd_ctx, + struct sir_extscan_generic_response *response) +{ + struct hdd_ext_scan_context *context; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx) || !response) { + hdd_err("HDD context is not valid or response(%pK) is null", + response); + return; + } + + hdd_debug("request %u status %u", + response->request_id, response->status); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + if (context->request_id == response->request_id) { + context->response_status = response->status ? -EINVAL : 0; + complete(&context->response_event); + } + spin_unlock(&context->context_lock); +} + +void wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle, + const uint16_t event_id, void *msg) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + + /* ENTER() intentionally not used in a frequently invoked API */ + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hdd_debug("Rcvd Event %d", event_id); + + switch (event_id) { + case eSIR_EXTSCAN_CACHED_RESULTS_RSP: + /* There is no need to send this response to upper layer + * Just log the message + */ + hdd_debug("Rcvd eSIR_EXTSCAN_CACHED_RESULTS_RSP"); + break; + + case eSIR_EXTSCAN_GET_CAPABILITIES_IND: + wlan_hdd_cfg80211_extscan_get_capabilities_rsp(hdd_ctx, msg); + break; + + case eSIR_EXTSCAN_HOTLIST_MATCH_IND: + wlan_hdd_cfg80211_extscan_hotlist_match_ind(hdd_ctx, msg); + break; + + case eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND: + wlan_hdd_cfg80211_extscan_signif_wifi_change_results_ind(hdd_ctx, + msg); + break; + + case eSIR_EXTSCAN_CACHED_RESULTS_IND: + wlan_hdd_cfg80211_extscan_cached_results_ind(hdd_ctx, msg); + break; + + case eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND: + wlan_hdd_cfg80211_extscan_scan_res_available_event(hdd_ctx, + msg); + break; + + case eSIR_EXTSCAN_FULL_SCAN_RESULT_IND: + wlan_hdd_cfg80211_extscan_full_scan_result_event(hdd_ctx, msg); + break; + + case eSIR_EPNO_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_extscan_epno_match_found(hdd_ctx, msg); + break; + + case eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND: + wlan_hdd_cfg80211_extscan_scan_progress_event(hdd_ctx, msg); + break; + + case eSIR_PASSPOINT_NETWORK_FOUND_IND: + wlan_hdd_cfg80211_passpoint_match_found(hdd_ctx, msg); + break; + + case eSIR_EXTSCAN_START_RSP: + case eSIR_EXTSCAN_STOP_RSP: + case eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP: + case eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP: + case eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP: + case eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP: + case eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP: + case eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP: + wlan_hdd_cfg80211_extscan_generic_rsp(hdd_ctx, msg); + break; + + default: + hdd_err("Unknown event type: %u", event_id); + break; + } +} + +/* + * define short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#define PARAM_REQUEST_ID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID +#define PARAM_STATUS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_STATUS +#define MAX_EXTSCAN_CACHE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE +#define MAX_SCAN_BUCKETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS +#define MAX_AP_CACHE_PER_SCAN \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN +#define MAX_RSSI_SAMPLE_SIZE \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE +#define MAX_SCAN_RPT_THRHOLD \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD +#define MAX_HOTLIST_BSSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS +#define MAX_SIGNIFICANT_WIFI_CHANGE_APS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS +#define MAX_BSSID_HISTORY_ENTRIES \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES +#define MAX_HOTLIST_SSIDS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS +#define MAX_NUM_EPNO_NETS \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS +#define MAX_NUM_EPNO_NETS_BY_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID +#define MAX_NUM_WHITELISTED_SSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID +#define MAX_NUM_BLACKLISTED_BSSID \ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_MAX_NUM_BLACKLISTED_BSSID +/** + * wlan_hdd_send_ext_scan_capability - send ext scan capability to user space + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 for success, non-zero for failure + */ +static int wlan_hdd_send_ext_scan_capability(struct hdd_context *hdd_ctx) +{ + int ret; + struct sk_buff *skb; + struct ext_scan_capabilities_response *data; + uint32_t nl_buf_len; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + data = &(ext_scan_context.capability_response); + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(data->requestId) + NLA_HDRLEN) + + (sizeof(data->status) + NLA_HDRLEN) + + (sizeof(data->max_scan_cache_size) + NLA_HDRLEN) + + (sizeof(data->max_scan_buckets) + NLA_HDRLEN) + + (sizeof(data->max_ap_cache_per_scan) + NLA_HDRLEN) + + (sizeof(data->max_rssi_sample_size) + NLA_HDRLEN) + + (sizeof(data->max_scan_reporting_threshold) + NLA_HDRLEN) + + (sizeof(data->max_hotlist_bssids) + NLA_HDRLEN) + + (sizeof(data->max_significant_wifi_change_aps) + NLA_HDRLEN) + + (sizeof(data->max_bssid_history_entries) + NLA_HDRLEN) + + (sizeof(data->max_hotlist_ssids) + NLA_HDRLEN) + + (sizeof(data->max_number_epno_networks) + NLA_HDRLEN) + + (sizeof(data->max_number_epno_networks_by_ssid) + NLA_HDRLEN) + + (sizeof(data->max_number_of_allow_listed_ssid) + NLA_HDRLEN) + + (sizeof(data->max_number_of_deny_listed_bssid) + NLA_HDRLEN); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + + hdd_debug("Req Id %u", data->requestId); + hdd_debug("Status %u", data->status); + hdd_debug("Scan cache size %u", + data->max_scan_cache_size); + hdd_debug("Scan buckets %u", data->max_scan_buckets); + hdd_debug("Max AP per scan %u", + data->max_ap_cache_per_scan); + hdd_debug("max_rssi_sample_size %u", + data->max_rssi_sample_size); + hdd_debug("max_scan_reporting_threshold %u", + data->max_scan_reporting_threshold); + hdd_debug("max_hotlist_bssids %u", + data->max_hotlist_bssids); + hdd_debug("max_significant_wifi_change_aps %u", + data->max_significant_wifi_change_aps); + hdd_debug("max_bssid_history_entries %u", + data->max_bssid_history_entries); + hdd_debug("max_hotlist_ssids %u", data->max_hotlist_ssids); + hdd_debug("max_number_epno_networks %u", + data->max_number_epno_networks); + hdd_debug("max_number_epno_networks_by_ssid %u", + data->max_number_epno_networks_by_ssid); + hdd_debug("max_number_of_allow_listed_ssid %u", + data->max_number_of_allow_listed_ssid); + hdd_debug("max_number_of_deny_listed_bssid (%u)", + data->max_number_of_deny_listed_bssid); + + if (nla_put_u32(skb, PARAM_REQUEST_ID, data->requestId) || + nla_put_u32(skb, PARAM_STATUS, data->status) || + nla_put_u32(skb, MAX_EXTSCAN_CACHE_SIZE, + data->max_scan_cache_size) || + nla_put_u32(skb, MAX_SCAN_BUCKETS, data->max_scan_buckets) || + nla_put_u32(skb, MAX_AP_CACHE_PER_SCAN, + data->max_ap_cache_per_scan) || + nla_put_u32(skb, MAX_RSSI_SAMPLE_SIZE, + data->max_rssi_sample_size) || + nla_put_u32(skb, MAX_SCAN_RPT_THRHOLD, + data->max_scan_reporting_threshold) || + nla_put_u32(skb, MAX_HOTLIST_BSSIDS, data->max_hotlist_bssids) || + nla_put_u32(skb, MAX_SIGNIFICANT_WIFI_CHANGE_APS, + data->max_significant_wifi_change_aps) || + nla_put_u32(skb, MAX_BSSID_HISTORY_ENTRIES, + data->max_bssid_history_entries) || + nla_put_u32(skb, MAX_HOTLIST_SSIDS, data->max_hotlist_ssids) || + nla_put_u32(skb, MAX_NUM_EPNO_NETS, + data->max_number_epno_networks) || + nla_put_u32(skb, MAX_NUM_EPNO_NETS_BY_SSID, + data->max_number_epno_networks_by_ssid) || + nla_put_u32(skb, MAX_NUM_WHITELISTED_SSID, + data->max_number_of_allow_listed_ssid) || + nla_put_u32(skb, MAX_NUM_BLACKLISTED_BSSID, + data->max_number_of_deny_listed_bssid)) { + hdd_err("nla put fail"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} +/* + * done with short names for the global vendor params + * used by wlan_hdd_send_ext_scan_capability() + */ +#undef PARAM_REQUEST_ID +#undef PARAM_STATUS +#undef MAX_EXTSCAN_CACHE_SIZE +#undef MAX_SCAN_BUCKETS +#undef MAX_AP_CACHE_PER_SCAN +#undef MAX_RSSI_SAMPLE_SIZE +#undef MAX_SCAN_RPT_THRHOLD +#undef MAX_HOTLIST_BSSIDS +#undef MAX_SIGNIFICANT_WIFI_CHANGE_APS +#undef MAX_BSSID_HISTORY_ENTRIES +#undef MAX_HOTLIST_SSIDS +#undef MAX_NUM_EPNO_NETS +#undef MAX_NUM_EPNO_NETS_BY_SSID +#undef MAX_NUM_WHITELISTED_SSID +#undef MAX_NUM_BLACKLISTED_BSSID + +/** + * __wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int id, ret; + unsigned long rc; + struct hdd_ext_scan_context *context; + struct extscan_capabilities_params params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + QDF_STATUS status; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + return -EINVAL; + } + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + params.request_id = nla_get_u32(tb[id]); + params.vdev_id = adapter->deflink->vdev_id; + hdd_debug("Req Id %d Vdev Id %d", params.request_id, params.vdev_id); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = params.request_id; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_ext_scan_get_capabilities(hdd_ctx->mac_handle, ¶ms); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_get_capabilities failed(err=%d)", + status); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hdd_err("Target response timed out"); + return -ETIMEDOUT; + } + + ret = wlan_hdd_send_ext_scan_capability(hdd_ctx); + if (ret) + hdd_err("Failed to send ext scan capability to user space"); + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_cfg80211_extscan_get_capabilities() - get ext scan capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_get_capabilities(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * Each WMI event with cached scan results data chunk results in + * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each + * data chunk is sent up the layer in wlan_cfg80211_vendor_cmd_alloc_reply_skb. + * + * If timeout happens before receiving all of the data, this function sets + * a context variable @ignore_cached_results to %true, all of the next data + * chunks are checked against this variable and dropped. + * + * Return: 0 on success; error number otherwise. + */ +static int +__wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct extscan_cached_result_params params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + int id, retval; + unsigned long rc; + + /* ENTER_DEV() intentionally not used in a frequently invoked API */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + params.request_id = nla_get_u32(tb[id]); + params.vdev_id = adapter->deflink->vdev_id; + + /* Parse and fetch flush parameter */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_GET_CACHED_SCAN_RESULTS_CONFIG_PARAM_FLUSH; + if (!tb[id]) { + hdd_err("attr flush failed"); + return -EINVAL; + } + params.flush = nla_get_u8(tb[id]); + hdd_debug("Req Id: %u Vdev Id: %d Flush: %d", + params.request_id, params.vdev_id, params.flush); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + context->request_id = params.request_id; + context->ignore_cached_results = false; + INIT_COMPLETION(context->response_event); + spin_unlock(&context->context_lock); + + status = sme_get_cached_results(hdd_ctx->mac_handle, ¶ms); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_get_cached_results failed(err=%d)", status); + return -EINVAL; + } + + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hdd_err("Target response timed out"); + retval = -ETIMEDOUT; + spin_lock(&context->context_lock); + context->ignore_cached_results = true; + spin_unlock(&context->context_lock); + } else { + spin_lock(&context->context_lock); + retval = context->response_status; + spin_unlock(&context->context_lock); + } + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_get_cached_results() - extscan get cached results + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * This function parses the incoming NL vendor command data attributes and + * invokes the SME Api and blocks on a completion variable. + * Each WMI event with cached scan results data chunk results in + * function call wlan_hdd_cfg80211_extscan_cached_results_ind and each + * data chunk is sent up the layer in wlan_cfg80211_vendor_cmd_alloc_reply_skb. + * + * If timeout happens before receiving all of the data, this function sets + * a context variable @ignore_cached_results to %true, all of the next data + * chunks are checked against this variable and dropped. + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_get_cached_results(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_parse_ap_rssi_threshold() - parse AP RSSI threshold parameters + * @attr: netlink attribute containing the AP RSSI threshold parameters + * @ap: destination buffer for the parsed parameters + * + * This function parses the BSSID, low RSSI and high RSSI values from + * the @attr netlink attribute, storing the parsed values in @ap. + * + * Return: 0 if @attr is parsed and all required attributes are + * present, otherwise a negative errno. + */ +static int hdd_parse_ap_rssi_threshold(struct nlattr *attr, + struct ap_threshold_params *ap) +{ + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + int id; + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, + nla_data(attr), nla_len(attr), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch MAC address */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_BSSID; + if (!tb[id]) { + hdd_err("attr mac address failed"); + return -EINVAL; + } + nla_memcpy(ap->bssid.bytes, tb[id], QDF_MAC_ADDR_SIZE); + hdd_debug("BSSID: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ap->bssid.bytes)); + + /* Parse and fetch low RSSI */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_LOW; + if (!tb[id]) { + hdd_err("attr low RSSI failed"); + return -EINVAL; + } + ap->low = nla_get_s32(tb[id]); + hdd_debug("RSSI low %d", ap->low); + + /* Parse and fetch high RSSI */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM_RSSI_HIGH; + if (!tb[id]) { + hdd_err("attr high RSSI failed"); + return -EINVAL; + } + ap->high = nla_get_s32(tb[id]); + hdd_debug("RSSI High %d", ap->high); + + return 0; +} + +/** + * __wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set bssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct extscan_bssid_hotlist_set_params *params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct nlattr *apth; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + uint8_t i; + int id, rem, retval; + unsigned long rc; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return -ENOMEM; + + /* assume the worst until proven otherwise */ + retval = -EINVAL; + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + goto fail; + } + + params->request_id = nla_get_u32(tb[id]); + hdd_debug("Req Id %d", params->request_id); + + /* Parse and fetch number of APs */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_NUM_AP; + if (!tb[id]) { + hdd_err("attr number of AP failed"); + goto fail; + } + + params->num_ap = nla_get_u32(tb[id]); + if (params->num_ap > WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS) { + hdd_err("Number of AP: %u exceeds max: %u", + params->num_ap, WMI_WLAN_EXTSCAN_MAX_HOTLIST_APS); + goto fail; + } + params->vdev_id = adapter->deflink->vdev_id; + hdd_debug("Number of AP %d vdev Id %d", + params->num_ap, params->vdev_id); + + /* Parse and fetch lost ap sample size */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BSSID_HOTLIST_PARAMS_LOST_AP_SAMPLE_SIZE; + if (!tb[id]) { + hdd_err("attr lost ap sample size failed"); + goto fail; + } + + params->lost_ap_sample_size = nla_get_u32(tb[id]); + hdd_debug("Lost ap sample size %d", + params->lost_ap_sample_size); + + /* Parse the AP Threshold array */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM; + if (!tb[id]) { + hdd_err("attr ap threshold failed"); + goto fail; + } + + i = 0; + nla_for_each_nested(apth, tb[id], rem) { + if (i == params->num_ap) { + hdd_warn("Ignoring excess AP"); + break; + } + + retval = hdd_parse_ap_rssi_threshold(apth, ¶ms->ap[i]); + if (retval) + goto fail; + + i++; + } + + if (i < params->num_ap) { + hdd_warn("Number of AP %u less than expected %u", + i, params->num_ap); + params->num_ap = i; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = params->request_id; + spin_unlock(&context->context_lock); + + status = sme_set_bss_hotlist(hdd_ctx->mac_handle, params); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_bss_hotlist failed(err=%d)", status); + retval = qdf_status_to_os_return(status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_set_bss_hotlist timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == params->request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + +fail: + qdf_mem_free(params); + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_set_bssid_hotlist() - set ext scan bssid hotlist + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_set_bssid_hotlist(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + + +/** + * __wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct extscan_set_sig_changereq_params *params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct nlattr *apth; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + uint8_t i; + int id, rem, retval; + unsigned long rc; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return -ENOMEM; + + /* assume the worst until proven otherwise */ + retval = -EINVAL; + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + goto fail; + } + + params->request_id = nla_get_u32(tb[id]); + hdd_debug("Req Id %d", params->request_id); + + /* Parse and fetch RSSI sample size */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_RSSI_SAMPLE_SIZE; + if (!tb[id]) { + hdd_err("attr RSSI sample size failed"); + goto fail; + } + params->rssi_sample_size = nla_get_u32(tb[id]); + hdd_debug("RSSI sample size %u", params->rssi_sample_size); + + /* Parse and fetch lost AP sample size */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_LOST_AP_SAMPLE_SIZE; + if (!tb[id]) { + hdd_err("attr lost AP sample size failed"); + goto fail; + } + params->lostap_sample_size = nla_get_u32(tb[id]); + hdd_debug("Lost AP sample size %u", params->lostap_sample_size); + + /* Parse and fetch AP min breaching */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_MIN_BREACHING; + if (!tb[id]) { + hdd_err("attr AP min breaching"); + goto fail; + } + params->min_breaching = nla_get_u32(tb[id]); + hdd_debug("AP min breaching %u", params->min_breaching); + + /* Parse and fetch number of APs */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SIGNIFICANT_CHANGE_PARAMS_NUM_AP; + if (!tb[id]) { + hdd_err("attr number of AP failed"); + goto fail; + } + params->num_ap = nla_get_u32(tb[id]); + if (params->num_ap > WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS) { + hdd_err("Number of AP %u exceeds max %u", + params->num_ap, + WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS); + goto fail; + } + + params->vdev_id = adapter->deflink->vdev_id; + hdd_debug("Number of AP %d Vdev Id %d", + params->num_ap, params->vdev_id); + + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_AP_THRESHOLD_PARAM; + if (!tb[id]) { + hdd_err("attr ap threshold failed"); + goto fail; + } + i = 0; + nla_for_each_nested(apth, tb[id], rem) { + + if (i == params->num_ap) { + hdd_warn("Ignoring excess AP"); + break; + } + + retval = hdd_parse_ap_rssi_threshold(apth, ¶ms->ap[i]); + if (retval) + goto fail; + + i++; + } + if (i < params->num_ap) { + hdd_warn("Number of AP %u less than expected %u", + i, params->num_ap); + params->num_ap = i; + } + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = params->request_id; + spin_unlock(&context->context_lock); + + status = sme_set_significant_change(hdd_ctx->mac_handle, params); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_significant_change failed(err=%d)", status); + retval = qdf_status_to_os_return(status); + goto fail; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_set_significant_change timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == params->request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + +fail: + qdf_mem_free(params); + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_set_significant_change() - set significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_set_significant_change(wiphy, wdev, + data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_extscan_update_dwell_time_limits() - update dwell times + * @req_msg: Pointer to request message + * @bkt_idx: Index of current bucket being processed + * @active_min: minimum active dwell time + * @active_max: maximum active dwell time + * @passive_min: minimum passive dwell time + * @passive_max: maximum passive dwell time + * + * Return: none + */ +static void +hdd_extscan_update_dwell_time_limits(struct wifi_scan_cmd_req_params *req_msg, + uint32_t bkt_idx, uint32_t active_min, + uint32_t active_max, uint32_t passive_min, + uint32_t passive_max) +{ + /* update per-bucket dwell times */ + if (req_msg->buckets[bkt_idx].min_dwell_time_active > + active_min) { + req_msg->buckets[bkt_idx].min_dwell_time_active = + active_min; + } + if (req_msg->buckets[bkt_idx].max_dwell_time_active < + active_max) { + req_msg->buckets[bkt_idx].max_dwell_time_active = + active_max; + } + if (req_msg->buckets[bkt_idx].min_dwell_time_passive > + passive_min) { + req_msg->buckets[bkt_idx].min_dwell_time_passive = + passive_min; + } + if (req_msg->buckets[bkt_idx].max_dwell_time_passive < + passive_max) { + req_msg->buckets[bkt_idx].max_dwell_time_passive = + passive_max; + } + /* update dwell-time across all buckets */ + if (req_msg->min_dwell_time_active > + req_msg->buckets[bkt_idx].min_dwell_time_active) { + req_msg->min_dwell_time_active = + req_msg->buckets[bkt_idx].min_dwell_time_active; + } + if (req_msg->max_dwell_time_active < + req_msg->buckets[bkt_idx].max_dwell_time_active) { + req_msg->max_dwell_time_active = + req_msg->buckets[bkt_idx].max_dwell_time_active; + } + if (req_msg->min_dwell_time_passive > + req_msg->buckets[bkt_idx].min_dwell_time_passive) { + req_msg->min_dwell_time_passive = + req_msg->buckets[bkt_idx].min_dwell_time_passive; + } + if (req_msg->max_dwell_time_passive > + req_msg->buckets[bkt_idx].max_dwell_time_passive) { + req_msg->max_dwell_time_passive = + req_msg->buckets[bkt_idx].max_dwell_time_passive; + } +} + +/** + * hdd_extscan_channel_max_reached() - channel max reached + * @req: extscan request structure + * @total_channels: total number of channels + * + * Return: true if total channels reached max, false otherwise + */ +static bool +hdd_extscan_channel_max_reached(struct wifi_scan_cmd_req_params *req, + uint8_t total_channels) +{ + if (total_channels == WMI_WLAN_EXTSCAN_MAX_CHANNELS) { + hdd_warn("max #of channels %d reached, take only first %d bucket(s)", + total_channels, req->num_buckets); + return true; + } + return false; +} + +/** + * hdd_extscan_start_fill_bucket_channel_spec() - fill bucket channel spec + * @hdd_ctx: HDD global context + * @req_msg: Pointer to request structure + * @bucket_attr: pointer to bucket attribute + * + * Return: 0 on success; error number otherwise + */ +static int hdd_extscan_start_fill_bucket_channel_spec( + struct hdd_context *hdd_ctx, + struct wifi_scan_cmd_req_params *req_msg, + struct nlattr *bucket_attr) +{ + mac_handle_t mac_handle; + struct nlattr *bucket_tb[EXTSCAN_PARAM_MAX + 1]; + struct nlattr *channel_tb[EXTSCAN_PARAM_MAX + 1]; + struct nlattr *buckets; + struct nlattr *channels; + int id, rem1, rem2; + QDF_STATUS status; + uint8_t bkt_index, j, num_channels, total_channels = 0; + uint32_t expected_buckets; + uint32_t expected_channels; + uint32_t chan_list[CFG_VALID_CHANNEL_LIST_LEN] = {0}; + uint32_t extscan_active_min_chn_time; + uint32_t min_dwell_time_active_bucket; + uint32_t max_dwell_time_active_bucket; + uint32_t min_dwell_time_passive_bucket; + uint32_t max_dwell_time_passive_bucket; + struct wifi_scan_bucket_params *bucket; + struct wifi_scan_channelspec_params *channel; + struct nlattr *channel_attr; + + ucfg_extscan_get_active_min_time(hdd_ctx->psoc, + &extscan_active_min_chn_time); + ucfg_extscan_get_active_max_time(hdd_ctx->psoc, + &max_dwell_time_active_bucket); + ucfg_extscan_get_passive_max_time(hdd_ctx->psoc, + &max_dwell_time_passive_bucket); + + min_dwell_time_active_bucket = max_dwell_time_active_bucket; + min_dwell_time_passive_bucket = max_dwell_time_passive_bucket; + + req_msg->min_dwell_time_active = + req_msg->max_dwell_time_active = max_dwell_time_active_bucket; + + req_msg->min_dwell_time_passive = + req_msg->max_dwell_time_passive = max_dwell_time_passive_bucket; + + expected_buckets = req_msg->num_buckets; + req_msg->num_buckets = 0; + bkt_index = 0; + + mac_handle = hdd_ctx->mac_handle; + nla_for_each_nested(buckets, bucket_attr, rem1) { + + if (bkt_index >= expected_buckets) { + hdd_warn("ignoring excess buckets"); + break; + } + + if (wlan_cfg80211_nla_parse(bucket_tb, EXTSCAN_PARAM_MAX, + nla_data(buckets), nla_len(buckets), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + bucket = &req_msg->buckets[bkt_index]; + + /* Parse and fetch bucket spec */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_INDEX; + if (!bucket_tb[id]) { + hdd_err("attr bucket index failed"); + return -EINVAL; + } + bucket->bucket = nla_get_u8(bucket_tb[id]); + + /* Parse and fetch wifi band */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BAND; + if (!bucket_tb[id]) { + hdd_err("attr wifi band failed"); + return -EINVAL; + } + bucket->band = nla_get_u8(bucket_tb[id]); + + /* Parse and fetch period */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_PERIOD; + if (!bucket_tb[id]) { + hdd_err("attr period failed"); + return -EINVAL; + } + bucket->period = nla_get_u32(bucket_tb[id]); + + /* Parse and fetch report events */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_REPORT_EVENTS; + if (!bucket_tb[id]) { + hdd_err("attr report events failed"); + return -EINVAL; + } + bucket->report_events = nla_get_u8(bucket_tb[id]); + + /* Parse and fetch max period */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_MAX_PERIOD; + if (!bucket_tb[id]) { + hdd_err("attr max period failed"); + return -EINVAL; + } + bucket->max_period = nla_get_u32(bucket_tb[id]); + + /* Parse and fetch base */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_BASE; + if (!bucket_tb[id]) { + hdd_err("attr base failed"); + return -EINVAL; + } + bucket->exponent = nla_get_u32(bucket_tb[id]); + + /* Parse and fetch step count */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_STEP_COUNT; + if (!bucket_tb[id]) { + hdd_err("attr step count failed"); + return -EINVAL; + } + bucket->step_count = nla_get_u32(bucket_tb[id]); + + hdd_debug("Bucket spec Index: %d Wifi band: %d period: %d report events: %d max period: %u base: %u Step count: %u", + bucket->bucket, + bucket->band, + bucket->period, + bucket->report_events, + bucket->max_period, + bucket->exponent, + bucket->step_count); + + /* start with known good values for bucket dwell times */ + bucket->min_dwell_time_active = max_dwell_time_active_bucket; + bucket->max_dwell_time_active = max_dwell_time_active_bucket; + bucket->min_dwell_time_passive = max_dwell_time_passive_bucket; + bucket->max_dwell_time_passive = max_dwell_time_passive_bucket; + + /* Framework shall pass the channel list if the input + * WiFi band is WMI_WIFI_BAND_UNSPECIFIED. If the + * input WiFi band is specified (any value other than + * WMI_WIFI_BAND_UNSPECIFIED) then driver populates + * the channel list. + */ + if (bucket->band != WMI_WIFI_BAND_UNSPECIFIED) { + if (hdd_extscan_channel_max_reached(req_msg, + total_channels)) + return 0; + + num_channels = 0; + hdd_debug("WiFi band is specified, driver to fill channel list"); + status = sme_get_valid_channels_by_band(mac_handle, + bucket->band, + chan_list, + &num_channels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_get_valid_channels_by_band failed (err=%d)", + status); + return -EINVAL; + } + hdd_debug("before trimming, num_channels: %d", + num_channels); + + bucket->num_channels = + QDF_MIN(num_channels, + (WMI_WLAN_EXTSCAN_MAX_CHANNELS - + total_channels)); + hdd_debug("Adj Num channels/bucket: %d total_channels: %d", + bucket->num_channels, total_channels); + total_channels += bucket->num_channels; + + for (j = 0; j < bucket->num_channels; j++) { + channel = &bucket->channels[j]; + + channel->channel = chan_list[j]; + channel->channel_class = 0; + if ((wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, chan_list[j], + REG_CURRENT_PWR_MODE)) != + CHANNEL_STATE_ENABLE) { + channel->passive = 1; + channel->dwell_time_ms = + max_dwell_time_passive_bucket; + /* reconfigure per-bucket dwell time */ + if (min_dwell_time_passive_bucket > + channel->dwell_time_ms) { + min_dwell_time_passive_bucket = + channel->dwell_time_ms; + } + if (max_dwell_time_passive_bucket < + channel->dwell_time_ms) { + max_dwell_time_passive_bucket = + channel->dwell_time_ms; + } + + } else { + channel->passive = 0; + channel->dwell_time_ms = + max_dwell_time_active_bucket; + /* reconfigure per-bucket dwell times */ + if (min_dwell_time_active_bucket > + channel->dwell_time_ms) { + min_dwell_time_active_bucket = + channel->dwell_time_ms; + } + if (max_dwell_time_active_bucket < + channel->dwell_time_ms) { + max_dwell_time_active_bucket = + channel->dwell_time_ms; + } + + } + + hdd_debug("Channel: %u Passive: %u Dwell time: %u ms Class: %u", + channel->channel, + channel->passive, + channel->dwell_time_ms, + channel->channel_class); + } + + hdd_extscan_update_dwell_time_limits( + req_msg, bkt_index, + min_dwell_time_active_bucket, + max_dwell_time_active_bucket, + min_dwell_time_passive_bucket, + max_dwell_time_passive_bucket); + + hdd_debug("bkt_index:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d", + bkt_index, + bucket->min_dwell_time_active, + bucket->max_dwell_time_active, + bucket->min_dwell_time_passive, + bucket->max_dwell_time_passive); + + bkt_index++; + req_msg->num_buckets++; + continue; + } + + /* Parse and fetch number of channels */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC_NUM_CHANNEL_SPECS; + if (!bucket_tb[id]) { + hdd_err("attr num channels failed"); + return -EINVAL; + } + bucket->num_channels = nla_get_u32(bucket_tb[id]); + hdd_debug("before trimming: num channels %d", + bucket->num_channels); + + bucket->num_channels = + QDF_MIN(bucket->num_channels, + (WMI_WLAN_EXTSCAN_MAX_CHANNELS - + total_channels)); + hdd_debug("Num channels/bucket: %d total_channels: %d", + bucket->num_channels, total_channels); + + if (hdd_extscan_channel_max_reached(req_msg, total_channels)) + return 0; + + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC; + channel_attr = bucket_tb[id]; + if (!channel_attr) { + hdd_err("attr channel spec failed"); + return -EINVAL; + } + + expected_channels = bucket->num_channels; + bucket->num_channels = 0; + + nla_for_each_nested(channels, channel_attr, rem2) { + if ((bucket->num_channels >= expected_channels) || + hdd_extscan_channel_max_reached(req_msg, + total_channels)) + break; + + if (wlan_cfg80211_nla_parse(channel_tb, + EXTSCAN_PARAM_MAX, + nla_data(channels), + nla_len(channels), + wlan_hdd_extscan_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + channel = &bucket->channels[bucket->num_channels]; + /* Parse and fetch channel */ + if (!channel_tb[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]) { + hdd_err("attr channel failed"); + return -EINVAL; + } + channel->channel = + nla_get_u32(channel_tb[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_CHANNEL]); + hdd_debug("channel %u", + channel->channel); + + /* Parse and fetch dwell time */ + if (!channel_tb[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]) { + hdd_err("attr dwelltime failed"); + return -EINVAL; + } + channel->dwell_time_ms = + nla_get_u32(channel_tb[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_DWELL_TIME]); + + /* Override dwell time if required */ + if (channel->dwell_time_ms < + extscan_active_min_chn_time || + channel->dwell_time_ms > + max_dwell_time_active_bucket) { + hdd_debug("WiFi band is unspecified, dwellTime:%d", + channel->dwell_time_ms); + + if ((wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, channel->channel, + REG_CURRENT_PWR_MODE)) != + CHANNEL_STATE_ENABLE) { + channel->dwell_time_ms = + max_dwell_time_passive_bucket; + } else { + channel->dwell_time_ms = + max_dwell_time_active_bucket; + } + } + + hdd_debug("New Dwell time %u ms", + channel->dwell_time_ms); + + if ((wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, channel->channel, + REG_CURRENT_PWR_MODE)) != + CHANNEL_STATE_ENABLE) { + if (min_dwell_time_passive_bucket > + channel->dwell_time_ms) { + min_dwell_time_passive_bucket = + channel->dwell_time_ms; + } + if (max_dwell_time_passive_bucket < + channel->dwell_time_ms) { + max_dwell_time_passive_bucket = + channel->dwell_time_ms; + } + } else { + if (min_dwell_time_active_bucket > + channel->dwell_time_ms) { + min_dwell_time_active_bucket = + channel->dwell_time_ms; + } + if (max_dwell_time_active_bucket < + channel->dwell_time_ms) { + max_dwell_time_active_bucket = + channel->dwell_time_ms; + } + } + + /* Parse and fetch channel spec passive */ + if (!channel_tb[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]) { + hdd_err("attr channel spec passive failed"); + return -EINVAL; + } + channel->passive = + nla_get_u8(channel_tb[ + QCA_WLAN_VENDOR_ATTR_EXTSCAN_CHANNEL_SPEC_PASSIVE]); + hdd_debug("Chnl spec passive %u", + channel->passive); + /* Override scan type if required */ + if ((wlan_reg_get_channel_state_for_pwrmode( + hdd_ctx->pdev, + channel->channel, + REG_CURRENT_PWR_MODE)) + != CHANNEL_STATE_ENABLE) { + channel->passive = true; + } else { + channel->passive = false; + } + total_channels++; + bucket->num_channels++; + } + + if (bucket->num_channels != expected_channels) + hdd_warn("channels: Expected %u got %u", + expected_channels, + bucket->num_channels); + + hdd_extscan_update_dwell_time_limits( + req_msg, bkt_index, + min_dwell_time_active_bucket, + max_dwell_time_active_bucket, + min_dwell_time_passive_bucket, + max_dwell_time_passive_bucket); + + hdd_debug("bktIndex:%d actv_min:%d actv_max:%d pass_min:%d pass_max:%d", + bkt_index, + bucket->min_dwell_time_active, + bucket->max_dwell_time_active, + bucket->min_dwell_time_passive, + bucket->max_dwell_time_passive); + + bkt_index++; + req_msg->num_buckets++; + } + + hdd_debug("Global: actv_min:%d actv_max:%d pass_min:%d pass_max:%d", + req_msg->min_dwell_time_active, + req_msg->max_dwell_time_active, + req_msg->min_dwell_time_passive, + req_msg->max_dwell_time_passive); + return 0; +} + +/* + * hdd_extscan_map_usr_drv_config_flags() - map userspace to driver config flags + * @config_flags - [input] configuration flags. + * + * This function maps user space received configuration flags to + * driver representation. + * + * Return: configuration flags + */ +static uint32_t hdd_extscan_map_usr_drv_config_flags(uint32_t config_flags) +{ + uint32_t configuration_flags = 0; + + if (config_flags & EXTSCAN_LP_EXTENDED_BATCHING) + configuration_flags |= EXTSCAN_LP_EXTENDED_BATCHING; + + return configuration_flags; +} + +/** + * __wlan_hdd_cfg80211_extscan_start() - ext scan start + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success; error number otherwise + */ +static int +__wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_scan_cmd_req_params *params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + uint32_t num_buckets; + QDF_STATUS status; + int retval, id; + unsigned long rc; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (QDF_NDI_MODE == adapter->device_mode) { + hdd_err("Command not allowed for NDI interface"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return -ENOMEM; + + /* assume the worst until proven otherwise */ + retval = -EINVAL; + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + goto fail; + } + + params->request_id = nla_get_u32(tb[id]); + params->vdev_id = adapter->deflink->vdev_id; + + /* Parse and fetch base period */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_BASE_PERIOD; + if (!tb[id]) { + hdd_err("attr base period failed"); + goto fail; + } + params->base_period = nla_get_u32(tb[id]); + + /* Parse and fetch max AP per scan */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_MAX_AP_PER_SCAN; + if (!tb[id]) { + hdd_err("attr max_ap_per_scan failed"); + goto fail; + } + params->max_ap_per_scan = nla_get_u32(tb[id]); + + /* Parse and fetch report threshold percent */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_PERCENT; + if (!tb[id]) { + hdd_err("attr report_threshold percent failed"); + goto fail; + } + params->report_threshold_percent = nla_get_u8(tb[id]); + + /* Parse and fetch report threshold num scans */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_REPORT_THRESHOLD_NUM_SCANS; + if (!tb[id]) { + hdd_err("attr report_threshold num scans failed"); + goto fail; + } + params->report_threshold_num_scans = nla_get_u8(tb[id]); + hdd_debug("Req Id: %d Vdev Id: %d Base Period: %d Max AP per Scan: %d Report Threshold percent: %d Report Threshold num scans: %d", + params->request_id, params->vdev_id, + params->base_period, params->max_ap_per_scan, + params->report_threshold_percent, + params->report_threshold_num_scans); + + /* Parse and fetch number of buckets */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SCAN_CMD_PARAMS_NUM_BUCKETS; + if (!tb[id]) { + hdd_err("attr number of buckets failed"); + goto fail; + } + num_buckets = nla_get_u8(tb[id]); + + if (num_buckets > WMI_WLAN_EXTSCAN_MAX_BUCKETS) { + hdd_warn("Exceeded MAX number of buckets: %d", + WMI_WLAN_EXTSCAN_MAX_BUCKETS); + num_buckets = WMI_WLAN_EXTSCAN_MAX_BUCKETS; + } + hdd_debug("Input: Number of Buckets %d", num_buckets); + params->num_buckets = num_buckets; + + /* This is optional attribute, if not present set it to 0 */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_CONFIGURATION_FLAGS; + if (!tb[id]) + params->configuration_flags = 0; + else + params->configuration_flags = + hdd_extscan_map_usr_drv_config_flags( + nla_get_u32(tb[id])); + + params->extscan_adaptive_dwell_mode = + ucfg_scan_get_extscan_adaptive_dwell_mode(hdd_ctx->psoc); + + hdd_debug("Configuration flags: %u", + params->configuration_flags); + + /* Parse and fetch number the array of buckets */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_BUCKET_SPEC; + if (!tb[id]) { + hdd_err("attr bucket spec failed"); + goto fail; + } + retval = hdd_extscan_start_fill_bucket_channel_spec(hdd_ctx, params, + tb[id]); + if (retval) + goto fail; + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = params->request_id; + context->buckets_scanned = 0; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_start(hdd_ctx->mac_handle, params); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_start failed(err=%d)", status); + retval = qdf_status_to_os_return(status); + goto fail; + } + + hdd_ctx->ext_scan_start_since_boot = qdf_get_monotonic_boottime(); + hdd_debug("Timestamp since boot: %llu", + hdd_ctx->ext_scan_start_since_boot); + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_ext_scan_start timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == params->request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + +fail: + qdf_mem_free(params); + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_start() - start extscan + * @wiphy: Pointer to wireless phy. + * @wdev: Pointer to wireless device. + * @data: Pointer to input data. + * @data_len: Length of @data. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_start(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + + +/** + * __wlan_hdd_cfg80211_extscan_stop() - ext scan stop + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct extscan_stop_req_params params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + int id, retval; + unsigned long rc; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + params.request_id = nla_get_u32(tb[id]); + params.vdev_id = adapter->deflink->vdev_id; + hdd_debug("Req Id %d Vdev Id %d", + params.request_id, params.vdev_id); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = params.request_id; + spin_unlock(&context->context_lock); + + status = sme_ext_scan_stop(hdd_ctx->mac_handle, ¶ms); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_ext_scan_stop failed(err=%d)", status); + return qdf_status_to_os_return(status); + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_ext_scan_stop timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == params.request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_stop() - stop extscan + * @wiphy: Pointer to wireless phy. + * @wdev: Pointer to wireless device. + * @data: Pointer to input data. + * @data_len: Length of @data. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_stop(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hotlist + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct extscan_bssid_hotlist_reset_params params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + int id, retval; + unsigned long rc; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, + data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + params.request_id = nla_get_u32(tb[id]); + params.vdev_id = adapter->deflink->vdev_id; + hdd_debug("Req Id %d vdev Id %d", params.request_id, params.vdev_id); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = params.request_id; + spin_unlock(&context->context_lock); + + status = sme_reset_bss_hotlist(hdd_ctx->mac_handle, ¶ms); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_reset_bss_hotlist failed(err=%d)", status); + return qdf_status_to_os_return(status); + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout + (&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + if (!rc) { + hdd_err("sme_reset_bss_hotlist timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == params.request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_reset_bssid_hotlist() - reset bssid hot list + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_extscan_reset_significant_change() - + * reset significant change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: none + */ +static int +__wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct extscan_capabilities_reset_params params; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[EXTSCAN_PARAM_MAX + 1]; + struct hdd_ext_scan_context *context; + QDF_STATUS status; + int id, retval; + unsigned long rc; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + retval = wlan_hdd_validate_context(hdd_ctx); + if (0 != retval) + return -EINVAL; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, EXTSCAN_PARAM_MAX, data, data_len, + wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + params.request_id = nla_get_u32(tb[id]); + params.vdev_id = adapter->deflink->vdev_id; + hdd_debug("Req Id %d Vdev Id %d", params.request_id, params.vdev_id); + + context = &ext_scan_context; + spin_lock(&context->context_lock); + INIT_COMPLETION(context->response_event); + context->request_id = params.request_id; + spin_unlock(&context->context_lock); + + status = sme_reset_significant_change(hdd_ctx->mac_handle, ¶ms); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_reset_significant_change failed(err=%d)", + status); + return -EINVAL; + } + + /* request was sent -- wait for the response */ + rc = wait_for_completion_timeout(&context->response_event, + msecs_to_jiffies(WLAN_WAIT_TIME_EXTSCAN)); + + if (!rc) { + hdd_err("sme_ResetSignificantChange timed out"); + retval = -ETIMEDOUT; + } else { + spin_lock(&context->context_lock); + if (context->request_id == params.request_id) + retval = context->response_status; + else + retval = -EINVAL; + spin_unlock(&context->context_lock); + } + hdd_exit(); + return retval; +} + +/** + * wlan_hdd_cfg80211_extscan_reset_significant_change() - reset significant + * change + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_extscan_reset_significant_change(wiphy, + wdev, + data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + + +/** + * hdd_extscan_epno_fill_network() - epno fill single network + * @network: aggregate network attribute + * @nw: epno network record to be filled + * + * This function takes a single network block NL vendor attribute from + * @network and decodes it into the internal record @nw. + * + * Return: 0 on success, error number otherwise + */ +static int +hdd_extscan_epno_fill_network(struct nlattr *network, + struct wifi_epno_network_params *nw) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + int id, ssid_len; + uint8_t *ssid; + + if (!network) { + hdd_err("attr network attr failed"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(network), + nla_len(network), + wlan_hdd_pno_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch ssid */ + id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_SSID; + if (!tb[id]) { + hdd_err("attr network ssid failed"); + return -EINVAL; + } + ssid_len = nla_len(tb[id]); + + /* nla_parse will detect overflow but not underflow */ + if (0 == ssid_len) { + hdd_err("zero ssid length"); + return -EINVAL; + } + + /* Decrement by 1, don't count null character */ + ssid_len--; + + nw->ssid.length = ssid_len; + hdd_debug("network ssid length %d", ssid_len); + ssid = nla_data(tb[id]); + qdf_mem_copy(nw->ssid.ssid, ssid, ssid_len); + hdd_debug("Ssid (" QDF_SSID_FMT ")", + QDF_SSID_REF(nw->ssid.length, nw->ssid.ssid)); + + /* Parse and fetch epno flags */ + id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_FLAGS; + if (!tb[id]) { + hdd_err("attr epno flags failed"); + return -EINVAL; + } + nw->flags = nla_get_u8(tb[id]); + hdd_debug("flags %u", nw->flags); + + /* Parse and fetch auth bit */ + id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORK_AUTH_BIT; + if (!tb[id]) { + hdd_err("attr auth bit failed"); + return -EINVAL; + } + nw->auth_bit_field = nla_get_u8(tb[id]); + hdd_debug("auth bit %u", nw->auth_bit_field); + + return 0; +} + +/** + * hdd_extscan_epno_fill_network_list() - epno fill network list + * @req_msg: request message + * @networks: aggregate network list attribute + * + * This function reads the network block NL vendor attributes from + * @networks and fills in the epno request message @req_msg. + * + * Return: 0 on success, error number otherwise + */ +static int +hdd_extscan_epno_fill_network_list(struct wifi_enhanced_pno_params *req_msg, + struct nlattr *networks) +{ + struct nlattr *network; + int rem; + uint32_t index; + uint32_t expected_networks; + struct wifi_epno_network_params *nw; + + if (!networks) { + hdd_err("attr networks list failed"); + return -EINVAL; + } + + expected_networks = req_msg->num_networks; + index = 0; + + nla_for_each_nested(network, networks, rem) { + if (index == expected_networks) { + hdd_warn("ignoring excess networks"); + break; + } + + nw = &req_msg->networks[index++]; + if (hdd_extscan_epno_fill_network(network, nw)) + return -EINVAL; + } + req_msg->num_networks = index; + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_epno_list() - epno set network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from @data and + * fills in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_enhanced_pno_params *req_msg; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + QDF_STATUS status; + uint32_t num_networks, len; + int id, ret_val; + + hdd_enter_dev(dev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (!ucfg_extscan_get_enable(hdd_ctx->psoc)) { + hdd_err("extscan not supported"); + return -ENOTSUPP; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, + data_len, wlan_hdd_pno_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch number of networks */ + id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_NUM_NETWORKS; + if (!tb[id]) { + hdd_err("attr num networks failed"); + return -EINVAL; + } + + /* + * num_networks is also used as EPNO SET/RESET request. + * if num_networks is zero then it is treated as RESET. + */ + num_networks = nla_get_u32(tb[id]); + + if (num_networks > MAX_EPNO_NETWORKS) { + hdd_debug("num of nw: %d exceeded max: %d, resetting to: %d", + num_networks, MAX_EPNO_NETWORKS, MAX_EPNO_NETWORKS); + num_networks = MAX_EPNO_NETWORKS; + } + + hdd_debug("num networks %u", num_networks); + len = sizeof(*req_msg) + + (num_networks * sizeof(req_msg->networks[0])); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) + return -ENOMEM; + + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_PNO_CONFIG_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32(tb[id]); + hdd_debug("Req Id %u", req_msg->request_id); + + req_msg->vdev_id = adapter->deflink->vdev_id; + hdd_debug("Vdev Id %d", req_msg->vdev_id); + + if (num_networks) { + /* Parse and fetch min_5ghz_rssi */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_MIN5GHZ_RSSI; + if (!tb[id]) { + hdd_err("min_5ghz_rssi id failed"); + goto fail; + } + req_msg->min_5ghz_rssi = nla_get_u32(tb[id]); + + /* Parse and fetch min_24ghz_rssi */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_MIN24GHZ_RSSI; + if (!tb[id]) { + hdd_err("min_24ghz_rssi id failed"); + goto fail; + } + req_msg->min_24ghz_rssi = nla_get_u32(tb[id]); + + /* Parse and fetch initial_score_max */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_INITIAL_SCORE_MAX; + if (!tb[id]) { + hdd_err("initial_score_max id failed"); + goto fail; + } + req_msg->initial_score_max = nla_get_u32(tb[id]); + + /* Parse and fetch current_connection_bonus */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_CURRENT_CONNECTION_BONUS; + if (!tb[id]) { + hdd_err("current_connection_bonus id failed"); + goto fail; + } + req_msg->current_connection_bonus = nla_get_u32(tb[id]); + + /* Parse and fetch same_network_bonus */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_SAME_NETWORK_BONUS; + if (!tb[id]) { + hdd_err("same_network_bonus id failed"); + goto fail; + } + req_msg->same_network_bonus = nla_get_u32(tb[id]); + + /* Parse and fetch secure_bonus */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_SECURE_BONUS; + if (!tb[id]) { + hdd_err("secure_bonus id failed"); + goto fail; + } + req_msg->secure_bonus = nla_get_u32(tb[id]); + + /* Parse and fetch band_5ghz_bonus */ + id = QCA_WLAN_VENDOR_ATTR_EPNO_BAND5GHZ_BONUS; + if (!tb[id]) { + hdd_err("band_5ghz_bonus id failed"); + goto fail; + } + req_msg->band_5ghz_bonus = nla_get_u32(tb[id]); + + hdd_debug("min_5ghz_rssi: %d min_24ghz_rssi: %d", + req_msg->min_5ghz_rssi, + req_msg->min_24ghz_rssi); + hdd_debug("initial_score_max: %d current_connection_bonus:%d", + req_msg->initial_score_max, + req_msg->current_connection_bonus); + hdd_debug("Bonuses same_network: %d secure: %d band_5ghz: %d", + req_msg->same_network_bonus, + req_msg->secure_bonus, + req_msg->band_5ghz_bonus); + + id = QCA_WLAN_VENDOR_ATTR_PNO_SET_LIST_PARAM_EPNO_NETWORKS_LIST; + networks = tb[id]; + if (hdd_extscan_epno_fill_network_list(req_msg, networks)) + goto fail; + + } + + status = sme_set_epno_list(hdd_ctx->mac_handle, req_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_epno_list failed(err=%d)", status); + goto fail; + } + + hdd_exit(); + qdf_mem_free(req_msg); + return 0; + +fail: + qdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_epno_list() - epno set network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the epno request message. + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_epno_list(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_extscan_passpoint_fill_network() - passpoint fill single network + * @network: aggregate network attribute + * @nw: passpoint network record to be filled + * + * This function takes a single network block NL vendor attribute from + * @network and decodes it into the internal record @nw. + * + * Return: 0 on success, error number otherwise + */ +static int +hdd_extscan_passpoint_fill_network(struct nlattr *network, + struct wifi_passpoint_network_param *nw) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + int id; + size_t len; + + if (!network) { + hdd_err("attr network attr failed"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, + nla_data(network), + nla_len(network), + wlan_hdd_pno_config_policy)) { + hdd_err("nla_parse failed"); + return -EINVAL; + } + + /* Parse and fetch identifier */ + id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ID; + if (!tb[id]) { + hdd_err("attr passpoint id failed"); + return -EINVAL; + } + nw->id = nla_get_u32(tb[id]); + hdd_debug("Id %u", nw->id); + + /* Parse and fetch realm */ + id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_REALM; + if (!tb[id]) { + hdd_err("attr realm failed"); + return -EINVAL; + } + len = wlan_cfg80211_nla_strscpy(nw->realm, tb[id], + WMI_PASSPOINT_REALM_LEN); + /* Don't send partial realm to firmware */ + if (len >= WMI_PASSPOINT_REALM_LEN) { + hdd_err("user passed invalid realm, len:%zu", len); + return -EINVAL; + } + + hdd_debug("realm: %s", nw->realm); + + /* Parse and fetch roaming consortium ids */ + id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_CNSRTM_ID; + if (!tb[id]) { + hdd_err("attr roaming consortium ids failed"); + return -EINVAL; + } + nla_memcpy(&nw->roaming_consortium_ids, tb[id], + sizeof(nw->roaming_consortium_ids)); + hdd_debug("roaming consortium ids"); + + /* Parse and fetch plmn */ + id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_NETWORK_PARAM_ROAM_PLMN; + if (!tb[id]) { + hdd_err("attr plmn failed"); + return -EINVAL; + } + nla_memcpy(&nw->plmn, tb[id], + WMI_PASSPOINT_PLMN_LEN); + hdd_debug("plmn %02x:%02x:%02x)", + nw->plmn[0], + nw->plmn[1], + nw->plmn[2]); + + return 0; +} + +/** + * hdd_extscan_passpoint_fill_networks() - passpoint fill network list + * @req_msg: request message + * @networks: aggregate network list attribute + * + * This function reads the network block NL vendor attributes from + * @networks and fills in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int +hdd_extscan_passpoint_fill_networks(struct wifi_passpoint_req_param *req_msg, + struct nlattr *networks) +{ + struct nlattr *network; + int rem; + uint32_t index; + uint32_t expected_networks; + struct wifi_passpoint_network_param *nw; + + if (!networks) { + hdd_err("attr networks list failed"); + return -EINVAL; + } + + expected_networks = req_msg->num_networks; + index = 0; + + nla_for_each_nested(network, networks, rem) { + if (index == expected_networks) { + hdd_warn("ignoring excess networks"); + break; + } + + nw = &req_msg->networks[index++]; + if (hdd_extscan_passpoint_fill_network(network, nw)) + return -EINVAL; + } + req_msg->num_networks = index; + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_passpoint_req_param *req_msg; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + struct nlattr *networks; + uint32_t num_networks; + QDF_STATUS status; + int id, ret; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, + data_len, wlan_hdd_pno_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Parse and fetch number of networks */ + id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NUM; + if (!tb[id]) { + hdd_err("attr num networks failed"); + return -EINVAL; + } + num_networks = nla_get_u32(tb[id]); + if (num_networks > SIR_PASSPOINT_LIST_MAX_NETWORKS) { + hdd_err("num networks %u exceeds max %u", + num_networks, SIR_PASSPOINT_LIST_MAX_NETWORKS); + return -EINVAL; + } + + hdd_debug("num networks %u", num_networks); + + req_msg = qdf_mem_malloc(sizeof(*req_msg) + + (num_networks * sizeof(req_msg->networks[0]))); + if (!req_msg) + return -ENOMEM; + + req_msg->num_networks = num_networks; + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32(tb[id]); + + req_msg->vdev_id = adapter->deflink->vdev_id; + hdd_debug("Req Id %u Vdev Id %d", + req_msg->request_id, req_msg->vdev_id); + + id = QCA_WLAN_VENDOR_ATTR_PNO_PASSPOINT_LIST_PARAM_NETWORK_ARRAY; + networks = tb[id]; + if (hdd_extscan_passpoint_fill_networks(req_msg, networks)) + goto fail; + + status = sme_set_passpoint_list(hdd_ctx->mac_handle, req_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_passpoint_list failed(err=%d)", status); + goto fail; + } + + hdd_exit(); + qdf_mem_free(req_msg); + return 0; + +fail: + qdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_set_passpoint_list() - set passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function reads the NL vendor attributes from %tb and + * fill in the passpoint request message. + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_passpoint_list(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function resets passpoint networks list + * + * Return: 0 on success, error number otherwise + */ +static int __wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct wifi_passpoint_req_param *req_msg; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + QDF_STATUS status; + int id, ret; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PNO_MAX, data, + data_len, wlan_hdd_extscan_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + return -ENOMEM; + + /* Parse and fetch request Id */ + id = QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID; + if (!tb[id]) { + hdd_err("attr request id failed"); + goto fail; + } + req_msg->request_id = nla_get_u32(tb[id]); + + req_msg->vdev_id = adapter->deflink->vdev_id; + hdd_debug("Req Id %u Vdev Id %d", + req_msg->request_id, req_msg->vdev_id); + + status = sme_reset_passpoint_list(hdd_ctx->mac_handle, req_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_reset_passpoint_list failed(err=%d)", status); + goto fail; + } + + hdd_exit(); + qdf_mem_free(req_msg); + return 0; + +fail: + qdf_mem_free(req_msg); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_reset_passpoint_list() - reset passpoint network list + * @wiphy: wiphy + * @wdev: pointer to wireless dev + * @data: data pointer + * @data_len: data length + * + * This function resets passpoint networks list + * + * Return: 0 on success, error number otherwise + */ +int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_reset_passpoint_list(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_cfg80211_extscan_init() - Initialize the ExtScan feature + * @hdd_ctx: Global HDD context + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_init(struct hdd_context *hdd_ctx) +{ + init_completion(&ext_scan_context.response_event); + spin_lock_init(&ext_scan_context.context_lock); +} + +#endif /* FEATURE_WLAN_EXTSCAN */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h new file mode 100644 index 0000000000..bf3be445f9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ext_scan.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012-2014, 2017-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_EXT_SCAN_H) +#define WLAN_HDD_EXT_SCAN_H + +/** + * DOC: wlan_hdd_ext_scan.h + * + * WLAN Host Device Driver EXT SCAN feature implementation + * + */ + +struct hdd_context; + +#define EXTSCAN_EVENT_BUF_SIZE 4096 + +#ifdef FEATURE_WLAN_EXTSCAN + +#include "wlan_hdd_main.h" + +/* + * Used to allocate the size of 4096 for the EXTScan NL data. + * The size of 4096 is considered assuming that all data per + * respective event fit with in the limit.Please take a call + * on the limit based on the data requirements. + */ + +int wlan_hdd_cfg80211_extscan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_get_capabilities(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +int wlan_hdd_cfg80211_extscan_get_cached_results(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_set_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_reset_bssid_hotlist(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_set_significant_change(struct wiphy *wiphy, + struct wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_extscan_reset_significant_change(struct wiphy + *wiphy, + struct + wireless_dev + *wdev, const void *data, + int data_len); + +int wlan_hdd_cfg80211_set_epno_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_set_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_reset_passpoint_list(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_extscan_callback() - ext scan callback + * @hdd_handle: Opaque handle to hdd context + * @event_id: Event identifier + * @msg: Pointer to message + * + * Return: none + */ +void wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle, + const uint16_t event_id, void *msg); + +void wlan_hdd_cfg80211_extscan_init(struct hdd_context *hdd_ctx); + +#else /* FEATURE_WLAN_EXTSCAN */ + +static inline +void wlan_hdd_cfg80211_extscan_callback(hdd_handle_t hdd_handle, + const uint16_t event_id, void *msg) +{ +} + +static inline void wlan_hdd_cfg80211_extscan_init(struct hdd_context *hdd_ctx) +{ +} + +#endif /* End of FEATURE_WLAN_EXTSCAN */ + +#endif /* end #if !defined(WLAN_HDD_EXT_SCAN_H) */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fips.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fips.c new file mode 100644 index 0000000000..ae5081e202 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fips.c @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_fips.c + * + * WLAN Host Device Driver FIPS Certification Feature + */ + +#include "osif_sync.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_fips.h" +#include "wlan_osif_request_manager.h" +#include "qdf_mem.h" +#include "sme_api.h" + +#define WLAN_WAIT_TIME_FIPS 5000 + +/** + * struct hdd_fips_context - hdd fips context + * @status: status of response. 0: no error, -ENOMEM: unable to allocate + * memory for the response payload + * @request: fips request + * @response: fips response + */ +struct hdd_fips_context { + int status; + struct fips_params request; + struct wmi_host_fips_event_param response; +}; + +/** + * hdd_fips_event_dup () - duplicate a fips event + * @dest: destination event + * @src: source event + * + * Make a "deep" duplicate of a FIPS event + * + * Return: 0 if the event was duplicated, otherwise an error + */ +static int hdd_fips_event_dup(struct wmi_host_fips_event_param *dest, + const struct wmi_host_fips_event_param *src) +{ + *dest = *src; + if (dest->data_len) { + dest->data = qdf_mem_malloc(dest->data_len); + if (!dest->data) + return -ENOMEM; + + qdf_mem_copy(dest->data, src->data, src->data_len); + } else { + /* make sure we don't have a rogue pointer */ + dest->data = NULL; + } + + return 0; +} + +/** + * hdd_fips_cb () - fips response message handler + * @cookie: hdd request cookie + * @response: fips response parameters + * + * Return: none + */ +static void hdd_fips_cb(void *cookie, + struct wmi_host_fips_event_param *response) +{ + struct osif_request *request; + struct hdd_fips_context *context; + + hdd_enter(); + + if (!response) { + hdd_err("response is NULL"); + return; + } + + request = osif_request_get(cookie); + if (!request) { + hdd_debug("Obsolete request"); + return; + } + + hdd_debug("pdev_id %u, status %u, data_len %u", + response->pdev_id, + response->error_status, + response->data_len); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + response->data, response->data_len); + + context = osif_request_priv(request); + if (response->error_status) { + context->status = -ETIMEDOUT; + } else { + context->status = hdd_fips_event_dup(&context->response, + response); + } + + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); +} + +static void hdd_fips_context_dealloc(void *priv) +{ + struct hdd_fips_context *context = priv; + + qdf_mem_free(context->response.data); +} + + +static int hdd_fips_validate_request(struct iw_fips_test_request *user_request, + uint32_t request_len) +{ + uint32_t expected_data_len; + + if (request_len < sizeof(*user_request)) { + hdd_debug("Request len %u is too small", request_len); + return -EINVAL; + } + + if ((user_request->key_len != FIPS_KEY_LENGTH_128) && + (user_request->key_len != FIPS_KEY_LENGTH_256)) { + hdd_debug("Invalid key len %u", user_request->key_len); + return -EINVAL; + } + + expected_data_len = request_len - sizeof(*user_request); + if (expected_data_len != user_request->data_len) { + hdd_debug("Unexpected data_len %u for request_len %u", + user_request->data_len, request_len); + return -EINVAL; + } + + if ((user_request->mode != FIPS_ENGINE_AES_CTR) && + (user_request->mode != FIPS_ENGINE_AES_MIC)) { + hdd_debug("Invalid mode %u", user_request->mode); + return -EINVAL; + } + + if ((user_request->operation != FIPS_ENCRYPT_CMD) && + (user_request->operation != FIPS_DECRYPT_CMD)) { + hdd_debug("Invalid operation %u", user_request->operation); + return -EINVAL; + } + + return 0; +} + +static int __hdd_fips_test(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct iw_fips_test_request *user_request; + struct iw_fips_test_response *user_response; + uint32_t request_len; + int ret; + QDF_STATUS qdf_status; + void *cookie; + struct osif_request *request; + struct hdd_fips_context *context; + struct fips_params *fips_request; + struct wmi_host_fips_event_param *fips_response; + static const struct osif_request_params params = { + .priv_size = sizeof(*context), + .timeout_ms = WLAN_WAIT_TIME_FIPS, + .dealloc = hdd_fips_context_dealloc, + }; + + hdd_enter_dev(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + user_request = (struct iw_fips_test_request *)extra; + request_len = wrqu->data.length; + ret = hdd_fips_validate_request(user_request, request_len); + if (ret) + return ret; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + context = osif_request_priv(request); + fips_request = &context->request; + fips_request->key = &user_request->key[0]; + fips_request->key_len = user_request->key_len; + fips_request->data = &user_request->data[0]; + fips_request->data_len = user_request->data_len; + fips_request->mode = user_request->mode; + fips_request->op = user_request->operation; + fips_request->pdev_id = WMI_PDEV_ID_1ST; + + cookie = osif_request_cookie(request); + qdf_status = sme_fips_request(hdd_ctx->mac_handle, &context->request, + hdd_fips_cb, cookie); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Unable to post fips message"); + ret = -EINVAL; + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out"); + goto cleanup; + } + + ret = context->status; + if (ret) { + hdd_err("Target response processing failed"); + goto cleanup; + } + + fips_response = &context->response; + if (fips_response->data_len != fips_request->data_len) { + hdd_err("Data length mismatch, got %u, expected %u", + fips_response->data_len, fips_request->data_len); + ret = -EINVAL; + goto cleanup; + } + user_response = (struct iw_fips_test_response *)extra; + user_response->status = context->status; + if (user_response->status) { + user_response->data_len = 0; + } else { + user_response->data_len = fips_response->data_len; + qdf_mem_copy(user_response->data, fips_response->data, + fips_response->data_len); + } + + /* + * By default wireless extensions private ioctls have either + * SET semantics (even numbered ioctls) or GET semantics (odd + * numbered ioctls). This is an even numbered ioctl so the SET + * semantics apply. This means the core kernel ioctl code took + * care of copying the request parameters from userspace to + * kernel space. However this ioctl also needs to return the + * response. Since the core kernel ioctl code doesn't support + * SET ioctls returning anything other than status, we have to + * explicitly copy the result to userspace. + */ + wrqu->data.length = sizeof(*user_response) + user_response->data_len; + if (copy_to_user(wrqu->data.pointer, user_response, wrqu->data.length)) + ret = -EFAULT; + +cleanup: + osif_request_put(request); + + hdd_exit(); + return ret; +} + +int hdd_fips_test(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_fips_test(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fips.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fips.h new file mode 100644 index 0000000000..aeb28243a3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fips.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_fips.h + * + * WLAN Host Device Driver FIPS Certification Feature + */ + +#ifndef __WLAN_HDD_FIPS_H__ +#define __WLAN_HDD_FIPS_H__ + +struct net_device; +struct iw_request_info; +union iwreq_data; +struct hdd_adapter; +void fips_test(struct hdd_adapter *adapter); + +#define FIPS_KEY_LEN 32 +struct iw_fips_test_request { + uint32_t operation; + uint32_t mode; + uint32_t key_len; + uint8_t key[FIPS_KEY_LEN]; + uint32_t data_len; + uint8_t data[]; +}; + +struct iw_fips_test_response { + uint32_t status; + uint32_t data_len; + uint8_t data[]; +}; + + +/** + * hdd_fips_test() - Perform FIPS test + * @dev: netdev upon which the FIPS test ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data structure + * @extra: extra payload for wireless extensions ioctl + * + * This API implements the FIPS test interface. Upon entry the @extra + * buffer will contain a FIPS test vector formatted as a &struct + * iw_fips_test_request. This vector will be sent to firmware where it + * will be run through the appropriate hardware. The result of the + * operation will be sent back to userspace via @extra encoded as a + * &struct iw_fips_test_response. + * + * Return: 0 if the test vector was processed, otherwise a negative + * errno. + */ + +int hdd_fips_test(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +#endif /* __WLAN_HDD_FIPS_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c new file mode 100644 index 0000000000..23135e3fc2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ftm.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_ftm.c + * + * This file contains the WLAN factory test mode implementation + */ + +#include "cds_sched.h" +#include +#include "sir_types.h" +#include "qdf_types.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "wlan_qct_sys.h" +#include "wlan_hdd_misc.h" +#include "i_cds_packet.h" +#include "cds_reg_service.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_lpass.h" +#include "qwlan_version.h" +#include "wma_types.h" + +#ifdef QCA_WIFI_FTM + +#include "wlan_hdd_cfg80211.h" +#include "hif.h" +#include +#include + +/** + * hdd_update_cds_config_ftm() - API to update cds configuration parameters + * for FTM mode. + * @hdd_ctx: HDD Context + * + * Return: 0 on success; errno on failure + */ + +int hdd_update_cds_config_ftm(struct hdd_context *hdd_ctx) +{ + struct cds_config_info *cds_cfg; + QDF_STATUS status; + bool self_recovery; + + cds_cfg = qdf_mem_malloc(sizeof(*cds_cfg)); + if (!cds_cfg) + return -ENOMEM; + + status = ucfg_mlme_get_self_recovery(hdd_ctx->psoc, &self_recovery); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get self recovery ini config"); + return -EIO; + } + + cds_cfg->driver_type = QDF_DRIVER_TYPE_MFG; + hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx); + cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE; + cds_cfg->self_recovery_enabled = self_recovery; + cds_cfg->num_vdevs = hdd_ctx->config->num_vdevs; + cds_init_ini_config(cds_cfg); + + return 0; +} + +#ifdef LINUX_QCMBR + +/** + * wlan_hdd_qcmbr_ioctl() - Standard QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @data: pointer to the raw command data in the ioctl request + * + * Return: 0 on success, non-zero on error + */ +static int wlan_hdd_qcmbr_ioctl(struct hdd_adapter *adapter, void __user *data) +{ + int ret, cmd; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (get_user(cmd, (int *)data) != 0) + return QDF_STATUS_E_FAILURE; + + ret = wlan_ioctl_ftm_testmode_cmd(hdd_ctx->pdev, cmd, + (uint8_t *)data + sizeof(cmd)); + + return ret; +} + +/** + * wlan_hdd_qcmbr_unified_ioctl() - Unified QCMBR ioctl handler + * @adapter: adapter upon which the ioctl was received + * @data: pointer to the raw command data in the ioctl request + * + * Return: 0 on success, non-zero on error + */ +int wlan_hdd_qcmbr_unified_ioctl(struct hdd_adapter *adapter, void __user *data) +{ + int ret; + + ret = wlan_hdd_qcmbr_ioctl(adapter, data); + + return ret; +} + +#endif /* LINUX_QCMBR */ +#endif /* QCA_WIFI_FTM */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ftm_time_sync.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ftm_time_sync.c new file mode 100644 index 0000000000..8b6dd11f6c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ftm_time_sync.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_hdd_ftm_time_sync.h" +#include "ftm_time_sync_ucfg_api.h" +#include "wlan_hdd_object_manager.h" + +static ssize_t hdd_ftm_time_sync_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + ssize_t size = 0; + + struct net_device *net_dev = qdf_container_of(dev, struct net_device, + dev); + + adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) + return scnprintf(buf, PAGE_SIZE, "Invalid device\n"); + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, FTM_TIME_SYNC_ID); + if (!vdev) + return -EINVAL; + + if (adapter->device_mode == QDF_STA_MODE) + size = ucfg_ftm_time_sync_show(vdev, buf); + + hdd_objmgr_put_vdev_by_user(vdev, FTM_TIME_SYNC_ID); + return size; +} + +static DEVICE_ATTR(ftm_time_sync, 0400, hdd_ftm_time_sync_show, NULL); + +void +hdd_ftm_time_sync_sta_state_notify(struct hdd_adapter *adapter, + enum ftm_time_sync_sta_state state) +{ + struct hdd_station_ctx *hdd_sta_ctx; + struct wlan_objmgr_psoc *psoc; + struct net_device *net_dev; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, FTM_TIME_SYNC_ID); + if (!vdev) + return; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + goto out; + + if (!ucfg_is_ftm_time_sync_enable(psoc)) + goto out; + + net_dev = adapter->dev; + + if (net_dev) { + if (state == FTM_TIME_SYNC_STA_CONNECTED) + device_create_file(&net_dev->dev, + &dev_attr_ftm_time_sync); + else + device_remove_file(&net_dev->dev, + &dev_attr_ftm_time_sync); + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + ucfg_ftm_time_sync_update_sta_connect_state( + vdev, state, + hdd_sta_ctx->conn_info.bssid); +out: + hdd_objmgr_put_vdev_by_user(vdev, FTM_TIME_SYNC_ID); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fw_state.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fw_state.c new file mode 100644 index 0000000000..9b42c450e9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_fw_state.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_fw_state.c + * + * The implementation for getting firmware state + */ + +#include "osif_sync.h" +#include "qca_vendor.h" +#include "wlan_hdd_fw_state.h" +#include "wlan_hdd_main.h" +#include "wlan_osif_request_manager.h" +#include "wmi_unified_param.h" + +struct fw_state { + bool fw_active; +}; + +/** + * hdd_get_fw_state_cb() - Callback function to get fw state + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * + * This function receives the response/data from the lower layer and + * checks to see if the thread is still waiting then post the results to + * upper layer, if the request has timed out then ignore. + * + * Return: None + */ +static void hdd_get_fw_state_cb(void *context) +{ + struct osif_request *request; + struct fw_state *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->fw_active = true; + osif_request_complete(request); + osif_request_put(request); +} + +/** + * hdd_post_get_fw_state_rsp - send rsp to user space + * @hdd_ctx: pointer to hdd context + * @state: true for fw active, false for fw error state + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_post_get_fw_state_rsp(struct hdd_context *hdd_ctx, + bool state) +{ + struct sk_buff *skb; + enum qca_wlan_vendor_attr_fw_state fw_state; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + sizeof(uint8_t) + + NLA_HDRLEN + + NLMSG_HDRLEN); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + if (state) + fw_state = QCA_WLAN_VENDOR_ATTR_FW_STATE_ACTIVE; + else + fw_state = QCA_WLAN_VENDOR_ATTR_FW_STATE_ERROR; + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_FW_STATE, + (uint8_t)fw_state)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_get_fw_state() - get fw state + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function sends a request to fw and waits on a timer to + * invoke the callback. if the callback is invoked then true + * will be returned or otherwise fail status will be returned. + * + * Return: 0 on success; error number otherwise. + **/ +static int __wlan_hdd_cfg80211_get_fw_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + mac_handle_t mac_handle; + QDF_STATUS status; + int retval; + void *cookie; + struct osif_request *request; + struct fw_state *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + bool state = false; + + hdd_enter_dev(wdev->netdev); + + retval = wlan_hdd_validate_context(hdd_ctx); + if (retval) + return retval; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + mac_handle = hdd_ctx->mac_handle; + status = sme_get_fw_state(mac_handle, + hdd_get_fw_state_cb, + cookie); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to get fw state"); + retval = qdf_status_to_os_return(status); + } else { + retval = osif_request_wait_for_response(request); + if (retval) { + hdd_err("Target response timed out"); + state = false; + } else { + priv = osif_request_priv(request); + state = priv->fw_active; + } + } + retval = hdd_post_get_fw_state_rsp(hdd_ctx, state); + if (retval) + hdd_err("Failed to post fw state"); + + osif_request_put(request); + + hdd_exit(); + return retval; +} + +/** + * wlan_hdd_cfg80211_get_fw_state() - get fw state + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_get_fw_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_fw_state(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_gpio.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_gpio.c new file mode 100644 index 0000000000..3dfbe38f91 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_gpio.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_main.h" +#include "cfg_ucfg_api.h" +#include + +/** + * __wlan_hdd_cfg80211_set_gpio_config() - Set the gpio configuration + * @wiphy: pointer to wiphy + * @wdev: pointer to wireless_wdev + * @data: pointer to data + * @data_len: data length + * + * __wlan_hdd_cfg80211_set_gpio_config will forward the GPIO setting to FW by + * WMI_GPIO_CONFIG/OUTPUT_CMDID + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_set_gpio_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_cfg80211_start_gpio_config(wiphy, + hdd_ctx->psoc, + data, data_len); + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_cfg80211_set_gpio_config() - Set GPIO Configuration + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +int wlan_hdd_cfg80211_set_gpio_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_gpio_config(wiphy, + wdev, + data, + data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_gpio_wakeup.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_gpio_wakeup.c new file mode 100644 index 0000000000..bd8d36ff4f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_gpio_wakeup.c @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_hdd_main.h" +#include +#include "wlan_hdd_gpio_wakeup.h" + +static int32_t gpio_wakeup_irq_num = -1; + +static uint32_t +hdd_gpio_wakeup_mode_pmo_to_linux(enum pmo_gpio_wakeup_mode mode) +{ + uint32_t irq_flag; + + switch (mode) { + case PMO_GPIO_WAKEUP_MODE_RISING: + irq_flag = IRQF_TRIGGER_RISING; + break; + case PMO_GPIO_WAKEUP_MODE_FALLING: + irq_flag = IRQF_TRIGGER_FALLING; + break; + case PMO_GPIO_WAKEUP_MODE_HIGH: + irq_flag = IRQF_TRIGGER_HIGH; + break; + case PMO_GPIO_WAKEUP_MODE_LOW: + irq_flag = IRQF_TRIGGER_LOW; + break; + default: + irq_flag = IRQF_TRIGGER_NONE; + break; + } + + return irq_flag; +} + +static irqreturn_t hdd_gpio_wakeup_isr(int irq, void *dev) +{ + hdd_debug("gpio_wakeup_isr"); + + return IRQ_HANDLED; +} + +int wlan_hdd_gpio_wakeup_init(struct hdd_context *hdd_ctx) +{ + uint32_t gpio_wakeup_pin; + enum pmo_gpio_wakeup_mode gpio_wakeup_mode; + int32_t ret; + uint32_t irq_flag; + + if (!ucfg_pmo_is_gpio_wakeup_enabled(hdd_ctx->psoc)) { + hdd_debug("gpio wakeup is not enabled"); + return 0; + } + + gpio_wakeup_pin = ucfg_pmo_get_gpio_wakeup_pin(hdd_ctx->psoc); + + ret = gpio_request(gpio_wakeup_pin, "gpio_wakeup"); + if (ret) { + hdd_err("failed to request gpio%d", gpio_wakeup_pin); + return -EIO; + } + + ret = gpio_direction_input(gpio_wakeup_pin); + if (ret) { + hdd_err("failed to set input direction"); + goto fail_free_gpio; + } + + gpio_wakeup_irq_num = gpio_to_irq(gpio_wakeup_pin); + if (gpio_wakeup_irq_num < 0) { + hdd_err("failed to get irq num"); + goto fail_free_gpio; + } + + gpio_wakeup_mode = ucfg_pmo_get_gpio_wakeup_mode(hdd_ctx->psoc); + if (gpio_wakeup_mode == PMO_GPIO_WAKEUP_MODE_INVALID) { + hdd_err("failed to get invalid wakeup mode"); + goto fail_free_gpio; + } + + irq_flag = hdd_gpio_wakeup_mode_pmo_to_linux(gpio_wakeup_mode); + ret = request_irq(gpio_wakeup_irq_num, hdd_gpio_wakeup_isr, irq_flag, + "gpio_wakeup_irq", hdd_ctx); + if (ret) { + hdd_err("failed to request irq %d", ret); + goto fail_free_gpio; + } + + ret = enable_irq_wake(gpio_wakeup_irq_num); + if (ret) { + hdd_err("failed to enable irq wake %d", ret); + goto fail_free_irq; + } + + hdd_debug("succeed to set gpio wakeup"); + + return 0; + +fail_free_irq: + free_irq(gpio_wakeup_irq_num, hdd_ctx); + gpio_wakeup_irq_num = -1; +fail_free_gpio: + gpio_free(gpio_wakeup_pin); + + return -EIO; +} + +int wlan_hdd_gpio_wakeup_deinit(struct hdd_context *hdd_ctx) +{ + uint32_t gpio_wakeup_pin; + + if (!ucfg_pmo_is_gpio_wakeup_enabled(hdd_ctx->psoc)) { + hdd_debug("gpio wakeup is not enabled"); + return 0; + } + + if (gpio_wakeup_irq_num < 0) { + hdd_debug("gpio wakeup irq is not enabled"); + return 0; + } + + free_irq(gpio_wakeup_irq_num, hdd_ctx); + gpio_wakeup_irq_num = -1; + + gpio_wakeup_pin = ucfg_pmo_get_gpio_wakeup_pin(hdd_ctx->psoc); + gpio_free(gpio_wakeup_pin); + + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c new file mode 100644 index 0000000000..6688a56b90 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.c @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_green_ap.c + * + * WLAN Host Device Driver Green AP implementation + * + */ + +#include +#include +#include +#include +#include +#include "wlan_mlme_ucfg_api.h" +#include +#include "wlan_osif_priv.h" +#include "wlan_lmac_if_def.h" + +/** + * hdd_green_ap_check_enable() - to check whether to enable green ap or not + * @hdd_ctx: hdd context + * @enable_green_ap: true - enable green ap, false - disable green ap + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_green_ap_check_enable(struct hdd_context *hdd_ctx, + bool *enable_green_ap) +{ + uint8_t num_sessions, mode; + QDF_STATUS status; + + for (mode = 0; + mode < QDF_MAX_NO_OF_MODE; + mode++) { + if (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE) + continue; + + status = policy_mgr_mode_specific_num_active_sessions( + hdd_ctx->psoc, mode, &num_sessions); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to get num sessions for mode: %d", + mode); + return -EINVAL; + } else if (num_sessions) { + *enable_green_ap = false; + hdd_debug("active sessions for mode: %d is %d disable green AP", + mode, num_sessions); + return 0; + } + } + *enable_green_ap = true; + return 0; +} + +void hdd_green_ap_add_sta(struct hdd_context *hdd_ctx) +{ + wlan_green_ap_add_sta(hdd_ctx->pdev); +} + +void hdd_green_ap_del_sta(struct hdd_context *hdd_ctx) +{ + wlan_green_ap_del_sta(hdd_ctx->pdev); +} + +int hdd_green_ap_enable_egap(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = ucfg_green_ap_enable_egap(hdd_ctx->pdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("enhance green ap is not enabled, status %d", + status); + return qdf_status_to_os_return(status); + } + + return 0; +} + +int hdd_green_ap_start_state_mc(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode, bool is_session_start) +{ + struct hdd_config *cfg; + bool enable_green_ap = false; + uint8_t num_sap_sessions = 0, num_p2p_go_sessions = 0, ret = 0; + QDF_STATUS status; + bool bval = false; + uint8_t ps_enable; + + cfg = hdd_ctx->config; + if (!cfg) { + hdd_err("NULL hdd config"); + return -EINVAL; + } + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("unable to get vht_enable2x2"); + return -EINVAL; + } + + if (!bval) { + hdd_debug(" 2x2 not enabled"); + } + + if (QDF_IS_STATUS_ERROR(ucfg_green_ap_get_ps_config(hdd_ctx->pdev, + &ps_enable))) + return 0; + + if (!ps_enable) { + hdd_debug("Green AP not enabled"); + return 0; + } + + policy_mgr_mode_specific_num_active_sessions(hdd_ctx->psoc, + QDF_SAP_MODE, + &num_sap_sessions); + policy_mgr_mode_specific_num_active_sessions(hdd_ctx->psoc, + QDF_P2P_GO_MODE, + &num_p2p_go_sessions); + + switch (mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (!num_sap_sessions && !num_p2p_go_sessions) + return 0; + + if (is_session_start) { + hdd_debug("Disabling Green AP"); + ucfg_green_ap_set_ps_config(hdd_ctx->pdev, + false); + wlan_green_ap_stop(hdd_ctx->pdev); + } else { + ret = hdd_green_ap_check_enable(hdd_ctx, + &enable_green_ap); + if (!ret) { + if (enable_green_ap) { + hdd_debug("Enabling Green AP"); + ucfg_green_ap_set_ps_config( + hdd_ctx->pdev, true); + wlan_green_ap_start(hdd_ctx->pdev); + } + } else { + hdd_err("Failed to check Green AP enable status"); + } + } + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (is_session_start) { + ret = hdd_green_ap_check_enable(hdd_ctx, + &enable_green_ap); + if (!ret) { + if (enable_green_ap) { + hdd_debug("Enabling Green AP"); + ucfg_green_ap_set_ps_config( + hdd_ctx->pdev, true); + wlan_green_ap_start(hdd_ctx->pdev); + } + } else { + hdd_err("Failed to check Green AP enable status"); + } + } else { + if (!num_sap_sessions && !num_p2p_go_sessions) { + hdd_debug("Disabling Green AP"); + ucfg_green_ap_set_ps_config(hdd_ctx->pdev, + false); + wlan_green_ap_stop(hdd_ctx->pdev); + } + } + break; + default: + break; + } + return ret; +} + +#ifdef WLAN_SUPPORT_GAP_LL_PS_MODE +const struct nla_policy +wlan_hdd_sap_low_pwr_mode[QCA_WLAN_VENDOR_ATTR_DOZED_AP_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_DOZED_AP_STATE] = {.type = NLA_U8}, +}; + +/** + * __wlan_hdd_enter_sap_low_pwr_mode() - Green AP low latency power + * save mode + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 for Success and negative value for failure + */ +static int +__wlan_hdd_enter_sap_low_pwr_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + uint8_t lp_flags, len; + uint64_t cookie_id; + QDF_STATUS status; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DOZED_AP_MAX + 1]; + struct sk_buff *skb; + + hdd_enter_dev(wdev->netdev); + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_DOZED_AP_MAX, + data, data_len, + wlan_hdd_sap_low_pwr_mode)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_DOZED_AP_STATE]) { + hdd_err("low power flag is not present"); + return -EINVAL; + } + + lp_flags = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_DOZED_AP_STATE]); + + if (lp_flags > QCA_WLAN_DOZED_AP_ENABLE) { + hdd_err("Invalid state received"); + return -EINVAL; + } + + hdd_debug("state: %s", + lp_flags == QCA_WLAN_DOZED_AP_ENABLE ? "ENABLE" : "DISABLE"); + + status = ucfg_green_ap_ll_ps( + hdd_ctx->pdev, adapter->deflink->vdev, lp_flags, + ap_ctx->sap_config.beacon_int, &cookie_id); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("unable to send low latency power save cmd"); + return -EINVAL; + } + + hdd_debug("Cookie id received : %llu", cookie_id); + + len = NLMSG_HDRLEN; + /*QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE*/ + len += nla_total_size(sizeof(u64)); + + skb = cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (!skb) { + hdd_err("skb allocation failed"); + return -ENOMEM; + } + + if (wlan_cfg80211_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE, + cookie_id)) { + hdd_err("nla_put for cookie id failed"); + goto fail; + } + + cfg80211_vendor_cmd_reply(skb); + + hdd_exit(); + + return 0; +fail: + wlan_cfg80211_vendor_free_skb(skb); + return 0; +} + +int +wlan_hdd_enter_sap_low_pwr_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_enter_sap_low_pwr_mode(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return 0; +} + +QDF_STATUS wlan_hdd_send_green_ap_ll_ps_event( + struct wlan_objmgr_vdev *vdev, + struct wlan_green_ap_ll_ps_event_param + *ll_ps_param) +{ + int index = QCA_NL80211_VENDOR_SUBCMD_DOZED_AP_INDEX; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t len; + struct vdev_osif_priv *osif_priv; + struct sk_buff *skb; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + hdd_err("OSIF priv is NULL"); + return QDF_STATUS_E_FAILURE; + } + + hdd_enter_dev(osif_priv->wdev->netdev); + + len = NLMSG_HDRLEN; + /*QCA_WLAN_VENDOR_ATTR_DOZED_AP_NEXT_TSF*/ + len += nla_total_size(sizeof(u64)); + /*QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE*/ + len += nla_total_size(sizeof(u64)); + /*QCA_WLAN_VENDOR_ATTR_DOZED_AP_BI_MULTIPLIER*/ + len += nla_total_size(sizeof(u16)); + + skb = wlan_cfg80211_vendor_event_alloc(osif_priv->wdev->wiphy, + osif_priv->wdev, len, + index, qdf_mem_malloc_flags()); + if (!skb) { + hdd_err("skb allocation failed"); + return QDF_STATUS_E_NOMEM; + } + + if (wlan_cfg80211_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_DOZED_AP_COOKIE, + ll_ps_param->dialog_token)) { + hdd_err("nla_put failed"); + status = QDF_STATUS_E_FAILURE; + goto nla_put_failure; + } + + if (wlan_cfg80211_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_DOZED_AP_NEXT_TSF, + ll_ps_param->next_tsf)) { + hdd_err("nla_put failed for next tsf"); + status = QDF_STATUS_E_FAILURE; + goto nla_put_failure; + } + + if (nla_put_u16(skb, QCA_WLAN_VENDOR_ATTR_DOZED_AP_BI_MULTIPLIER, + ll_ps_param->bcn_mult)) { + hdd_err("nla_put for BI multiplier failed"); + status = QDF_STATUS_E_FAILURE; + goto nla_put_failure; + } + + hdd_debug("next_tsf : %llu, cookie: %u beacon multiplier: %u", + ll_ps_param->next_tsf, ll_ps_param->dialog_token, + ll_ps_param->bcn_mult); + + wlan_cfg80211_vendor_event(skb, qdf_mem_malloc_flags()); + + hdd_exit(); + + return status; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return status; +} + +QDF_STATUS green_ap_register_hdd_callback(struct wlan_objmgr_pdev *pdev, + struct green_ap_hdd_callback *hdd_cback) +{ + struct wlan_pdev_green_ap_ctx *green_ap_ctx; + + green_ap_ctx = wlan_objmgr_pdev_get_comp_private_obj( + pdev, WLAN_UMAC_COMP_GREEN_AP); + + if (!green_ap_ctx) { + hdd_err("green ap context obtained is NULL"); + return QDF_STATUS_E_FAILURE; + } + + green_ap_ctx->hdd_cback = *hdd_cback; + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h new file mode 100644 index 0000000000..1ef6268145 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_green_ap.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_GREEN_AP_H) +#define WLAN_HDD_GREEN_AP_H + +#include "qdf_types.h" +#include "qca_vendor.h" +#include +#include +#include "wlan_lmac_if_def.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_green_ap_api.h" + +struct hdd_context; + +#ifdef WLAN_SUPPORT_GREEN_AP + +/** + * hdd_green_ap_add_sta() - Notify Green AP on STA association + * @hdd_ctx: Global HDD context + * + * Call this function when new node is associated + * + * Return: void + */ +void hdd_green_ap_add_sta(struct hdd_context *hdd_ctx); + +/** + * hdd_green_ap_del_sta() - Notify Green AP on STA disassociation + * @hdd_ctx: Global HDD context + * + * Call this function when new node is disassociated + * + * Return: void + */ +void hdd_green_ap_del_sta(struct hdd_context *hdd_ctx); + +/** + * hdd_green_ap_enable_egap() - Enable Enhanced Green AP + * @hdd_ctx: Global HDD context + * + * This function will enable the Enhanced Green AP feature if it is supported + * by the Green AP component. + * + * Return: 0 on success, negative errno on any failure + */ +int hdd_green_ap_enable_egap(struct hdd_context *hdd_ctx); + +/** + * hdd_green_ap_start_state_mc() - to start green AP state mc based on + * present concurrency and state of green AP state machine. + * @hdd_ctx: hdd context + * @mode: device mode + * @is_session_start: BSS start/stop + * + * Return: 0 on success, negative errno on any failure + */ +int hdd_green_ap_start_state_mc(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode, bool is_session_start); + +#else /* WLAN_SUPPORT_GREEN_AP */ +static inline +void hdd_green_ap_add_sta(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_green_ap_del_sta(struct hdd_context *hdd_ctx) +{ +} + +static inline +int hdd_green_ap_enable_egap(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static inline +int hdd_green_ap_start_state_mc(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode, bool is_session_start) +{ + return 0; +} + +#endif /* WLAN_SUPPORT_GREEN_AP */ + +#ifdef WLAN_SUPPORT_GAP_LL_PS_MODE + +extern const struct nla_policy +wlan_hdd_sap_low_pwr_mode[QCA_WLAN_VENDOR_ATTR_DOZED_AP_MAX + 1]; + +#define FEATURE_GREEN_AP_LOW_LATENCY_PWR_SAVE_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DOZED_AP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_enter_sap_low_pwr_mode, \ + vendor_command_policy(wlan_hdd_sap_low_pwr_mode, \ + QCA_WLAN_VENDOR_ATTR_MAX) \ +}, + +#define FEATURE_GREEN_AP_LOW_LATENCY_PWR_SAVE_EVENT \ +[QCA_NL80211_VENDOR_SUBCMD_DOZED_AP_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_DOZED_AP, \ +}, + +int +wlan_hdd_enter_sap_low_pwr_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +QDF_STATUS wlan_hdd_send_green_ap_ll_ps_event( + struct wlan_objmgr_vdev *vdev, + struct wlan_green_ap_ll_ps_event_param *ll_ps_event_param); + +QDF_STATUS green_ap_register_hdd_callback(struct wlan_objmgr_pdev *pdev, + struct green_ap_hdd_callback *hdd_cback); + +#else +#define FEATURE_GREEN_AP_LOW_LATENCY_PWR_SAVE_COMMANDS + +#define FEATURE_GREEN_AP_LOW_LATENCY_PWR_SAVE_EVENT +#endif + +#endif /* !defined(WLAN_HDD_GREEN_AP_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hang_event.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hang_event.c new file mode 100644 index 0000000000..81fee2be56 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hang_event.c @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include "wlan_hdd_object_manager.h" +#include + +struct hdd_hang_event_fixed_param { + uint16_t tlv_header; + uint8_t vdev_id; + uint8_t vdev_opmode; + uint8_t vdev_state; + uint8_t vdev_substate; +} qdf_packed; + +struct hdd_scan_fixed_param { + uint16_t tlv_header; + uint8_t last_scan_reject_vdev_id; + enum scan_reject_states last_scan_reject_reason; + unsigned long last_scan_reject_timestamp; + uint8_t scan_reject_cnt; +} qdf_packed; + +static int wlan_hdd_recovery_notifier_call(struct notifier_block *block, + unsigned long state, + void *data) +{ + qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block, + notif_block); + struct hdd_context *hdd_ctx; + struct qdf_notifer_data *hdd_hang_data = data; + uint8_t *hdd_buf_ptr; + struct hdd_adapter *adapter, *next_adapter = NULL; + uint32_t total_len; + struct wlan_objmgr_vdev *vdev; + struct hdd_hang_event_fixed_param *cmd; + struct hdd_scan_fixed_param *cmd_scan; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_RECOVERY_NOTIFIER_CALL; + + if (!data) + return NOTIFY_STOP_MASK; + + hdd_ctx = notif_block->priv_data; + if (!hdd_ctx) + return NOTIFY_STOP_MASK; + + if (state == QDF_SCAN_ATTEMPT_FAILURES) { + total_len = sizeof(*cmd_scan); + hdd_buf_ptr = hdd_hang_data->hang_data + hdd_hang_data->offset; + if (hdd_hang_data->offset + total_len > QDF_WLAN_HANG_FW_OFFSET) + return NOTIFY_STOP_MASK; + cmd_scan = (struct hdd_scan_fixed_param *)hdd_buf_ptr; + QDF_HANG_EVT_SET_HDR(&cmd_scan->tlv_header, + HANG_EVT_TAG_OS_IF_SCAN, + QDF_HANG_GET_STRUCT_TLVLEN(struct hdd_scan_fixed_param)); + cmd_scan->last_scan_reject_vdev_id = + hdd_ctx->last_scan_reject_vdev_id; + cmd_scan->last_scan_reject_reason = + hdd_ctx->last_scan_reject_reason; + cmd_scan->scan_reject_cnt = + hdd_ctx->scan_reject_cnt; + hdd_hang_data->offset += total_len; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_ID); + if (!vdev) { + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + total_len = sizeof(*cmd); + hdd_buf_ptr = hdd_hang_data->hang_data + hdd_hang_data->offset; + if (hdd_hang_data->offset + total_len > + QDF_WLAN_HANG_FW_OFFSET) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return NOTIFY_STOP_MASK; + } + cmd = (struct hdd_hang_event_fixed_param *)hdd_buf_ptr; + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, + HANG_EVT_TAG_OS_IF, + QDF_HANG_GET_STRUCT_TLVLEN(struct hdd_hang_event_fixed_param)); + cmd->vdev_id = wlan_vdev_get_id(vdev); + cmd->vdev_opmode = wlan_vdev_mlme_get_opmode(vdev); + cmd->vdev_state = wlan_vdev_mlme_get_state(vdev); + cmd->vdev_substate = wlan_vdev_mlme_get_substate(vdev); + hdd_hang_data->offset += total_len; + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NOTIFY_OK; +} + +static qdf_notif_block hdd_recovery_notifier = { + .notif_block.notifier_call = wlan_hdd_recovery_notifier_call, +}; + +QDF_STATUS wlan_hdd_hang_event_notifier_register(struct hdd_context *hdd_ctx) +{ + hdd_recovery_notifier.priv_data = hdd_ctx; + return qdf_hang_event_register_notifier(&hdd_recovery_notifier); +} + +QDF_STATUS wlan_hdd_hang_event_notifier_unregister(void) +{ + return qdf_hang_event_unregister_notifier(&hdd_recovery_notifier); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_he.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_he.c new file mode 100644 index 0000000000..8d097bfc1f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_he.c @@ -0,0 +1,982 @@ +/* + * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_he.c + * + * WLAN Host Device Driver file for 802.11ax (High Efficiency) support. + * + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_he.h" +#include "osif_sync.h" +#include "wma_he.h" +#include "wlan_utility.h" +#include "wlan_mlme_ucfg_api.h" +#include "spatial_reuse_ucfg_api.h" +#include "cdp_txrx_host_stats.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_hdd_object_manager.h" + +const struct nla_policy +wlan_hdd_sr_policy[QCA_WLAN_VENDOR_ATTR_SR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SR_OPERATION] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS] = {.type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_SR_STATS] = {.type = NLA_NESTED}, +}; + +static const struct nla_policy +qca_wlan_vendor_srp_param_policy[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW] = { + .type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE] = {.type = NLA_U32}, + +}; + +void hdd_update_tgt_he_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + QDF_STATUS status; + tDot11fIEhe_cap he_cap_ini = {0}; + uint8_t value = 0; + + status = ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp(hdd_ctx->psoc, + &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get tx_bfee_ant_supp"); + + he_cap_ini.bfee_sts_lt_80 = value; + sme_update_tgt_he_cap(hdd_ctx->mac_handle, cfg, &he_cap_ini); + + ucfg_mlme_update_tgt_he_cap(hdd_ctx->psoc, cfg); +} + +void wlan_hdd_check_11ax_support(struct hdd_beacon_data *beacon, + struct sap_config *config) +{ + const uint8_t *ie; + + ie = wlan_get_ext_ie_ptr_from_ext_id(HE_CAP_OUI_TYPE, HE_CAP_OUI_SIZE, + beacon->tail, beacon->tail_len); + if (ie) + config->SapHw_mode = eCSR_DOT11_MODE_11ax; +} + +int hdd_update_he_cap_in_cfg(struct hdd_context *hdd_ctx) +{ + uint32_t val; + uint32_t val1 = 0; + QDF_STATUS status; + int ret; + uint8_t enable_ul_ofdma, enable_ul_mimo; + + status = ucfg_mlme_cfg_get_he_ul_mumimo(hdd_ctx->psoc, &val); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get CFG_HE_UL_MUMIMO"); + return qdf_status_to_os_return(status); + } + + /* In val, + * Bit 1 - corresponds to UL MIMO + * Bit 2 - corresponds to UL OFDMA + */ + ret = ucfg_mlme_cfg_get_enable_ul_mimo(hdd_ctx->psoc, + &enable_ul_mimo); + if (ret) + return ret; + ret = ucfg_mlme_cfg_get_enable_ul_ofdm(hdd_ctx->psoc, + &enable_ul_ofdma); + if (ret) + return ret; + if (val & 0x1 || (val >> 1) & 0x1) + val1 = enable_ul_mimo & 0x1; + + if ((val >> 1) & 0x1) + val1 |= ((enable_ul_ofdma & 0x1) << 1); + + ret = ucfg_mlme_cfg_set_he_ul_mumimo(hdd_ctx->psoc, val1); + + return ret; +} + +/* + * __wlan_hdd_cfg80211_get_he_cap() - get HE Capabilities + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +static int +__wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + QDF_STATUS status; + struct sk_buff *reply_skb; + uint32_t nl_buf_len; + struct he_capability he_cap; + uint8_t he_supported = 0; + + hdd_enter(); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + nl_buf_len = NLMSG_HDRLEN; + if (sme_is_feature_supported_by_fw(DOT11AX)) { + he_supported = 1; + + status = wma_get_he_capabilities(&he_cap); + if (QDF_STATUS_SUCCESS != status) + return -EINVAL; + } else { + hdd_info("11AX: HE not supported, send only QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED"); + } + + if (he_supported) { + nl_buf_len += NLA_HDRLEN + sizeof(he_supported) + + NLA_HDRLEN + sizeof(he_cap.phy_cap) + + NLA_HDRLEN + sizeof(he_cap.mac_cap) + + NLA_HDRLEN + sizeof(he_cap.mcs) + + NLA_HDRLEN + sizeof(he_cap.ppet.numss_m1) + + NLA_HDRLEN + sizeof(he_cap.ppet.ru_bit_mask) + + NLA_HDRLEN + + sizeof(he_cap.ppet.ppet16_ppet8_ru3_ru0); + } else { + nl_buf_len += NLA_HDRLEN + sizeof(he_supported); + } + + hdd_info("11AX: he_supported: %d", he_supported); + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + if (!reply_skb) { + hdd_err("Allocate reply_skb failed"); + return -EINVAL; + } + + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_HE_SUPPORTED, he_supported)) + goto nla_put_failure; + + /* No need to populate other attributes if HE is not supported */ + if (0 == he_supported) + goto end; + + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_MAC_CAPAB, he_cap.mac_cap) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_HE_MCS, he_cap.mcs) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_NUM_SS, he_cap.ppet.numss_m1) || + nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_RU_IDX_MASK, + he_cap.ppet.ru_bit_mask) || + nla_put(reply_skb, + QCA_WLAN_VENDOR_ATTR_PHY_CAPAB, + sizeof(u32) * HE_MAX_PHY_CAP_SIZE, he_cap.phy_cap) || + nla_put(reply_skb, QCA_WLAN_VENDOR_ATTR_PPE_THRESHOLD, + sizeof(u32) * PSOC_HOST_MAX_NUM_SS, + he_cap.ppet.ppet16_ppet8_ru3_ru0)) + goto nla_put_failure; +end: + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + hdd_exit(); + return ret; + +nla_put_failure: + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; +} + +int wlan_hdd_cfg80211_get_he_cap(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_he_cap(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#ifdef WLAN_FEATURE_SR +static QDF_STATUS +hdd_sr_event_convert_reason_code(enum sr_osif_reason_code sr_osif_rc, + enum qca_wlan_sr_reason_code *sr_nl_rc) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (sr_osif_rc) { + case SR_REASON_CODE_ROAMING: + *sr_nl_rc = QCA_WLAN_SR_REASON_CODE_ROAMING; + break; + case SR_REASON_CODE_CONCURRENCY: + *sr_nl_rc = QCA_WLAN_SR_REASON_CODE_CONCURRENCY; + break; + default: + status = QDF_STATUS_E_INVAL; + } + + return status; +} + +static QDF_STATUS +hdd_sr_event_convert_operation(enum sr_osif_operation sr_osif_oper, + enum qca_wlan_sr_operation *sr_nl_oper) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (sr_osif_oper) { + case SR_OPERATION_SUSPEND: + *sr_nl_oper = QCA_WLAN_SR_OPERATION_SR_SUSPEND; + break; + case SR_OPERATION_RESUME: + *sr_nl_oper = QCA_WLAN_SR_OPERATION_SR_RESUME; + break; + case SR_OPERATION_UPDATE_PARAMS: + *sr_nl_oper = QCA_WLAN_SR_OPERATION_UPDATE_PARAMS; + break; + default: + status = QDF_STATUS_E_INVAL; + } + + return status; +} + +static QDF_STATUS hdd_sr_pack_suspend_resume_event( + struct sk_buff *skb, + enum qca_wlan_sr_operation sr_nl_oper, + enum qca_wlan_sr_reason_code sr_nl_rc, + uint8_t srg_max_pd_offset, + uint8_t srg_min_pd_offset, + uint8_t non_srg_max_pd_offset) +{ + struct nlattr *attr; + QDF_STATUS status = QDF_STATUS_E_FAULT; + + if (((sr_nl_rc != QCA_WLAN_SR_REASON_CODE_CONCURRENCY) && + (sr_nl_rc != QCA_WLAN_SR_REASON_CODE_ROAMING)) || + ((sr_nl_oper != QCA_WLAN_SR_OPERATION_SR_SUSPEND) && + (sr_nl_oper != QCA_WLAN_SR_OPERATION_SR_RESUME))) { + hdd_err("SR operation is invalid"); + status = QDF_STATUS_E_INVAL; + goto sr_events_end; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SR_OPERATION, sr_nl_oper)) { + hdd_err("failed to put attr SR Operation"); + goto sr_events_end; + } + + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SR_PARAMS); + if (!attr) { + hdd_err("nesting failed"); + goto sr_events_end; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE, + sr_nl_rc)) { + hdd_err("failed to put attr SR Reascon Code"); + goto sr_events_end; + } + if (sr_nl_rc == QCA_WLAN_SR_REASON_CODE_ROAMING && + sr_nl_oper == QCA_WLAN_SR_OPERATION_SR_RESUME) { + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET, + srg_min_pd_offset)) { + hdd_err("srg_pd_min_offset put fail"); + goto sr_events_end; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET, + srg_max_pd_offset)) { + hdd_err("srg_pd_min_offset put fail"); + goto sr_events_end; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET, + non_srg_max_pd_offset)) { + hdd_err("non_srg_pd_offset put fail"); + goto sr_events_end; + } + } + status = QDF_STATUS_SUCCESS; + nla_nest_end(skb, attr); + +sr_events_end: + return status; +} + +static void hdd_sr_osif_events(struct wlan_objmgr_vdev *vdev, + enum sr_osif_operation sr_osif_oper, + enum sr_osif_reason_code sr_osif_rc) +{ + struct hdd_adapter *adapter; + struct wireless_dev *wdev; + struct wiphy *wiphy; + struct sk_buff *skb; + uint32_t idx = QCA_NL80211_VENDOR_SUBCMD_SR_INDEX; + uint32_t len = NLMSG_HDRLEN; + uint8_t non_srg_max_pd_offset = 0; + uint8_t srg_max_pd_offset = 0; + uint8_t srg_min_pd_offset = 0; + QDF_STATUS status; + enum qca_wlan_sr_operation sr_nl_oper; + enum qca_wlan_sr_reason_code sr_nl_rc; + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("Null VDEV"); + return; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("Null adapter"); + return; + } + + adapter = link_info->adapter; + wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset, + &srg_min_pd_offset); + non_srg_max_pd_offset = wlan_vdev_mlme_get_non_srg_pd_offset(vdev); + status = hdd_sr_event_convert_operation(sr_osif_oper, &sr_nl_oper); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Invalid SR Operation: %d", sr_osif_oper); + return; + } + status = hdd_sr_event_convert_reason_code(sr_osif_rc, &sr_nl_rc); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Invalid SR Reason Code: %d", sr_osif_rc); + return; + } + + hdd_debug("SR Operation: %u SR Reason Code: %u", + sr_nl_oper, sr_nl_rc); + switch (sr_nl_oper) { + case QCA_WLAN_SR_OPERATION_SR_SUSPEND: + case QCA_WLAN_SR_OPERATION_SR_RESUME: + if (sr_nl_rc == QCA_WLAN_SR_REASON_CODE_CONCURRENCY || + sr_nl_rc == QCA_WLAN_SR_REASON_CODE_ROAMING) { + wiphy = adapter->hdd_ctx->wiphy; + wdev = &adapter->wdev; + /* QCA_WLAN_VENDOR_ATTR_SR_OPERATION */ + len += nla_total_size(sizeof(uint8_t)); + /* QCA_WLAN_VENDOR_ATTR_SR_PARAMS_REASON_CODE */ + len += nla_total_size(sizeof(uint32_t)); + /* QCA_WLAN_VENDOR_ATTR_SR_PARAMS */ + len += nla_total_size(0); + /* + * In case of resume due to roaming additional config + * params are required to be sent. + */ + if (sr_nl_rc == QCA_WLAN_SR_REASON_CODE_ROAMING && + sr_nl_oper == QCA_WLAN_SR_OPERATION_SR_RESUME) { + /* SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET */ + len += nla_total_size(sizeof(int32_t)); + /* SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET */ + len += nla_total_size(sizeof(int32_t)); + /* SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET */ + len += nla_total_size(sizeof(int32_t)); + } + skb = wlan_cfg80211_vendor_event_alloc(wiphy, wdev, + len, idx, + GFP_KERNEL); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + status = hdd_sr_pack_suspend_resume_event( + skb, sr_nl_oper, sr_nl_rc, + srg_max_pd_offset, srg_min_pd_offset, + non_srg_max_pd_offset); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + hdd_debug("SR cfg80211 event is sent"); + } else { + hdd_debug("SR Reason code not supported"); + } + break; + default: + hdd_debug("SR Operation not supported"); + break; + } +} + +void hdd_sr_register_callbacks(struct hdd_context *hdd_ctx) +{ + ucfg_spatial_reuse_register_cb(hdd_ctx->psoc, hdd_sr_osif_events); +} + +static int hdd_get_srp_stats_len(void) +{ + struct cdp_pdev_obss_pd_stats_tlv stats; + uint32_t len = NLMSG_HDRLEN; + + len += nla_total_size(sizeof(stats.num_srg_ppdu_success)) + + nla_total_size(sizeof(stats.num_srg_ppdu_tried)) + + nla_total_size(sizeof(stats.num_srg_opportunities)) + + nla_total_size(sizeof(stats.num_non_srg_ppdu_success)) + + nla_total_size(sizeof(stats.num_non_srg_ppdu_tried)) + + nla_total_size(sizeof(stats.num_non_srg_opportunities)); + + return len; +} + +static int hdd_get_srp_param_len(void) +{ + uint32_t len = NLMSG_HDRLEN; + + len += nla_total_size(sizeof(bool)) + + nla_total_size(sizeof(bool))+ + nla_total_size(sizeof(uint8_t))+ + nla_total_size(sizeof(uint8_t))+ + nla_total_size(sizeof(uint8_t)); + + return len; +} + +static int +hdd_add_param_info(struct sk_buff *skb, uint8_t srg_max_pd_offset, + uint8_t srg_min_pd_offset, uint8_t non_srg_pd_offset, + uint8_t sr_ctrl, int idx) +{ + struct nlattr *nla_attr; + bool non_srg_obss_pd_disallow = sr_ctrl & NON_SRG_PD_SR_DISALLOWED; + bool hesega_val_15_enable = sr_ctrl & HE_SIG_VAL_15_ALLOWED; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + hdd_debug("SR params of connected AP srg_max_pd_offset %d srg_min_pd_offset %d non_srg_pd_offset %d non_srg_obss_pd_disallow %d hesega_val_15_enable %d", + srg_max_pd_offset, srg_min_pd_offset, non_srg_pd_offset, + non_srg_obss_pd_disallow, hesega_val_15_enable); + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MIN_OFFSET, + srg_min_pd_offset)) { + hdd_err("srg_pd_min_offset put fail"); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_OBSS_PD_MAX_OFFSET, + srg_max_pd_offset)) { + hdd_err("srg_pd_min_offset put fail"); + goto fail; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_MAX_OFFSET, + non_srg_pd_offset)) { + hdd_err("non_srg_pd_offset put fail"); + goto fail; + } + if (non_srg_obss_pd_disallow && nla_put_flag( + skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_OBSS_PD_DISALLOW)) { + hdd_err("non_srg_obss_pd_disallow put fail or enabled"); + goto fail; + } + if (hesega_val_15_enable && nla_put_flag( + skb, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE)) { + hdd_err("hesega_val_15_enable put fail or disabled"); + goto fail; + } + + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} +static int +hdd_add_stats_info(struct sk_buff *skb, + struct cdp_pdev_obss_pd_stats_tlv *stats) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SR_STATS); + if (!nla_attr) + goto fail; + + hdd_debug("SR stats - srg: ppdu_success %d tried %d opportunities %d non-srg: ppdu_success %d tried %d opportunities %d", + stats->num_srg_ppdu_success, stats->num_srg_ppdu_tried, + stats->num_srg_opportunities, stats->num_non_srg_ppdu_success, + stats->num_non_srg_ppdu_tried, + stats->num_non_srg_opportunities); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_SUCCESS_COUNT, + stats->num_srg_ppdu_success)) { + hdd_err("num_srg_ppdu_success put fail"); + goto fail; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_PPDU_TRIED_COUNT, + stats->num_srg_ppdu_tried)) { + hdd_err("num_srg_ppdu_tried put fail"); + goto fail; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_STATS_SRG_TX_OPPORTUNITIES_COUNT, + stats->num_srg_opportunities)) { + hdd_err("num_srg_opportunities put fail"); + goto fail; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_SUCCESS_COUNT, + stats->num_non_srg_ppdu_success)) { + hdd_err("num_non_srg_ppdu_success put fail"); + goto fail; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_PPDU_TRIED_COUNT, + stats->num_non_srg_ppdu_tried)) { + hdd_err("num_non_srg_ppdu_tried put fail"); + goto fail; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_SR_STATS_NON_SRG_TX_OPPORTUNITIES_COUNT, + stats->num_non_srg_opportunities)) { + hdd_err("num_non_srg_opportunities put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +static int hdd_get_sr_stats(struct hdd_context *hdd_ctx, uint8_t mac_id, + struct cdp_pdev_obss_pd_stats_tlv *stats) +{ + ol_txrx_soc_handle soc; + uint8_t pdev_id; + struct cdp_txrx_stats_req req = {0}; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) { + hdd_err("invalid soc"); + return -EINVAL; + } + + req.mac_id = mac_id; + pdev_id = wlan_objmgr_pdev_get_pdev_id(hdd_ctx->pdev); + cdp_get_pdev_obss_pd_stats(soc, pdev_id, stats, &req); + if (!stats) { + hdd_err("invalid stats"); + return -EINVAL; + } + return 0; +} + +static int hdd_clear_sr_stats(struct hdd_context *hdd_ctx, uint8_t mac_id) +{ + QDF_STATUS status; + ol_txrx_soc_handle soc; + uint8_t pdev_id; + struct cdp_txrx_stats_req req = {0}; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) { + hdd_err("invalid soc"); + return -EINVAL; + } + + req.mac_id = mac_id; + pdev_id = wlan_objmgr_pdev_get_pdev_id(hdd_ctx->pdev); + status = cdp_clear_pdev_obss_pd_stats(soc, pdev_id, &req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to clear stats"); + return -EAGAIN; + } + return 0; +} + +/** + * hdd_check_mode_support_for_sr: Check if SR allowed or not + * @adapter: hdd adapter + * @sr_ctrl: sr ctrl ie + * + * Return: true if provided mode supports SR else flase + */ +static bool hdd_check_mode_support_for_sr(struct hdd_adapter *adapter, + uint8_t sr_ctrl) +{ + if ((adapter->device_mode == QDF_STA_MODE) && + (!hdd_cm_is_vdev_connected(adapter->deflink) || + ((sr_ctrl & NON_SRG_PD_SR_DISALLOWED) && + !(sr_ctrl & SRG_INFO_PRESENT)))) { + hdd_err("mode %d doesn't supports SR", adapter->device_mode); + return false; + } + return true; +} + +/** + * __wlan_hdd_cfg80211_sr_operations: To handle SR operation + * + * @wiphy: wiphy structure + * @wdev: wireless dev + * @data: vendor command data + * @data_len: data len + * + * return: success/failure code + */ +static int __wlan_hdd_cfg80211_sr_operations(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + QDF_STATUS status; + uint32_t id; + bool is_sr_enable = false; + int32_t srg_pd_threshold = 0; + int32_t non_srg_pd_threshold = 0; + uint8_t sr_he_siga_val15_allowed = true; + uint8_t mac_id, sr_ctrl, non_srg_max_pd_offset; + uint8_t srg_min_pd_offset = 0, srg_max_pd_offset = 0; + uint32_t nl_buf_len; + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct wlan_objmgr_vdev *vdev; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SR_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX + 1] = {0}; + enum qca_wlan_sr_operation sr_oper; + struct nlattr *sr_oper_attr; + struct nlattr *sr_param_attr; + struct sk_buff *skb; + struct cdp_pdev_obss_pd_stats_tlv stats; + uint8_t sr_device_modes; + + hdd_enter_dev(wdev->netdev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() || + QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM or Monitor mode"); + return -EPERM; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("Null VDEV"); + return -EINVAL; + } + /** + * Reject command if SR concurrency is not allowed and + * only STA mode is set in ini to enable SR. + **/ + ucfg_mlme_get_sr_enable_modes(hdd_ctx->psoc, &sr_device_modes); + if (!(sr_device_modes & (1 << adapter->device_mode))) { + hdd_debug("SR operation not allowed for mode %d", + adapter->device_mode); + ret = -EINVAL; + goto exit; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver Modules are closed"); + ret = -EINVAL; + goto exit; + } + if (!sme_is_feature_supported_by_fw(DOT11AX)) { + hdd_err("11AX is not supported"); + ret = -EINVAL; + goto exit; + } + status = ucfg_spatial_reuse_operation_allowed(hdd_ctx->psoc, vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("SR operations not allowed status: %u", status); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + return qdf_status_to_os_return(status); + } + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SR_MAX, data, + data_len, wlan_hdd_sr_policy)) { + hdd_err("invalid attr"); + ret = -EINVAL; + goto exit; + } + + id = QCA_WLAN_VENDOR_ATTR_SR_OPERATION; + sr_oper_attr = tb[id]; + if (!sr_oper_attr) { + hdd_err("SR operation not specified"); + ret = -EINVAL; + goto exit; + } + + sr_oper = nla_get_u8(sr_oper_attr); + hdd_debug("SR Operation 0x%x", sr_oper); + + ucfg_spatial_reuse_get_sr_config(vdev, &sr_ctrl, &non_srg_max_pd_offset, + &is_sr_enable); + + if (!hdd_check_mode_support_for_sr(adapter, sr_ctrl) && + (sr_oper != QCA_WLAN_SR_OPERATION_GET_PARAMS)) { + hdd_err("SR operation not allowed, sr_ctrl = %x, mode = %d", + sr_ctrl, adapter->device_mode); + ret = -EINVAL; + goto exit; + } + + if (sr_oper != QCA_WLAN_SR_OPERATION_SR_ENABLE && !is_sr_enable) { + hdd_err("SR operation not allowed"); + ret = -EINVAL; + goto exit; + } + + id = QCA_WLAN_VENDOR_ATTR_SR_PARAMS; + sr_param_attr = tb[id]; + if (sr_param_attr) { + ret = wlan_cfg80211_nla_parse_nested( + tb2, QCA_WLAN_VENDOR_ATTR_SR_PARAMS_MAX, + sr_param_attr, + qca_wlan_vendor_srp_param_policy); + if (ret) { + hdd_err("sr_param_attr parse failed"); + goto exit; + } + } + switch (sr_oper) { + case QCA_WLAN_SR_OPERATION_SR_ENABLE: + case QCA_WLAN_SR_OPERATION_SR_DISABLE: + if (sr_oper == QCA_WLAN_SR_OPERATION_SR_ENABLE) { + is_sr_enable = true; + } else { + is_sr_enable = false; + if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) { + hdd_debug("SR not enabled, reject disable command"); + ret = -EINVAL; + goto exit; + } + } + /** + * As per currenct implementation from userspace same + * PD threshold value is configured for both SRG and + * NON-SRG and fw will decide further based on BSS color + * So only SRG param is parsed and set as pd threshold + */ + if (is_sr_enable && + tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD]) { + srg_pd_threshold = + nla_get_s32( + tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_SRG_PD_THRESHOLD]); + wlan_vdev_mlme_set_pd_threshold_present(vdev, true); + } + + if (is_sr_enable && + tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD]) { + non_srg_pd_threshold = + nla_get_s32( + tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_NON_SRG_PD_THRESHOLD] + ); + wlan_vdev_mlme_set_pd_threshold_present(vdev, true); + } + + hdd_debug("setting sr enable %d with pd threshold srg: %d non srg: %d", + is_sr_enable, srg_pd_threshold, non_srg_pd_threshold); + /* Set the variables */ + ucfg_spatial_reuse_set_sr_enable(vdev, is_sr_enable); + status = ucfg_spatial_reuse_setup_req(vdev, hdd_ctx->pdev, + is_sr_enable, + srg_pd_threshold, + non_srg_pd_threshold); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to enable Spatial Reuse feature"); + ret = -EINVAL; + goto exit; + } + + break; + case QCA_WLAN_SR_OPERATION_GET_STATS: + status = policy_mgr_get_mac_id_by_session_id( + hdd_ctx->psoc, + adapter->deflink->vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get mac_id for vdev_id: %u", + adapter->deflink->vdev_id); { + ret = -EAGAIN; + goto exit; + } + } + if (hdd_get_sr_stats(hdd_ctx, mac_id, &stats)) { + ret = -EINVAL; + goto exit; + } + nl_buf_len = hdd_get_srp_stats_len(); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto exit; + } + if (hdd_add_stats_info(skb, &stats)) { + wlan_cfg80211_vendor_free_skb(skb); + ret = -EINVAL; + goto exit; + } + + ret = wlan_cfg80211_vendor_cmd_reply(skb); + break; + case QCA_WLAN_SR_OPERATION_CLEAR_STATS: + status = policy_mgr_get_mac_id_by_session_id( + hdd_ctx->psoc, + adapter->deflink->vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get mac_id for vdev_id: %u", + adapter->deflink->vdev_id); + ret = -EAGAIN; + goto exit; + } + if (hdd_clear_sr_stats(hdd_ctx, mac_id)) { + ret = -EAGAIN; + goto exit; + } + break; + case QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_PROHIBIT: + if (tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE]) + sr_he_siga_val15_allowed = nla_get_u8( + tb2[QCA_WLAN_VENDOR_ATTR_SR_PARAMS_HESIGA_VAL15_ENABLE] + ); + if (!sr_he_siga_val15_allowed) { + hdd_err("invalid sr_he_siga_val15_enable param"); + ret = -EINVAL; + goto exit; + } + if (!QDF_IS_STATUS_SUCCESS(ucfg_spatial_reuse_send_sr_prohibit( + vdev, sr_he_siga_val15_allowed))) { + hdd_debug("Prohibit command can not be sent"); + ret = -EINVAL; + goto exit; + } + break; + case QCA_WLAN_SR_OPERATION_PSR_AND_NON_SRG_OBSS_PD_ALLOW: + if (!QDF_IS_STATUS_SUCCESS(ucfg_spatial_reuse_send_sr_prohibit( + vdev, false))) { + hdd_debug("Prohibit command can not be sent"); + ret = -EINVAL; + goto exit; + } + break; + case QCA_WLAN_SR_OPERATION_GET_PARAMS: + wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset, + &srg_min_pd_offset); + non_srg_max_pd_offset = + wlan_vdev_mlme_get_non_srg_pd_offset(vdev); + sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev); + nl_buf_len = hdd_get_srp_param_len(); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto exit; + } + if (hdd_add_param_info(skb, srg_max_pd_offset, + srg_min_pd_offset, non_srg_max_pd_offset, + sr_ctrl, + QCA_WLAN_VENDOR_ATTR_SR_PARAMS)) { + wlan_cfg80211_vendor_free_skb(skb); + ret = -EINVAL; + goto exit; + } + + ret = wlan_cfg80211_vendor_cmd_reply(skb); + break; + default: + hdd_err("Invalid SR Operation"); + ret = -EINVAL; + break; + } + + hdd_exit(); +exit: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + return ret; +} + +int wlan_hdd_cfg80211_sr_operations(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_sr_operations(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c new file mode 100644 index 0000000000..1d0ffffaee --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.c @@ -0,0 +1,8697 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_hostapd.c + * + * WLAN Host Device Driver implementation + */ + +/* Include Files */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_p2p.h" +#include +#include "wni_cfg.h" +#include "wlan_hdd_misc.h" +#include +#include "pld_common.h" +#include "wma.h" +#ifdef WLAN_DEBUG +#include "wma_api.h" +#endif +#include "wlan_hdd_trace.h" +#include "qdf_str.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "qdf_net_if.h" +#include "wlan_hdd_cfg.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_tsf.h" +#include +#include +#include "wlan_hdd_object_manager.h" +#include +#include +#include "wlan_hdd_he.h" +#include "wlan_hdd_eht.h" +#include "wlan_dfs_tgt_api.h" +#include +#include "wlan_utility.h" +#include +#include "sir_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include "sme_api.h" +#include "wlan_hdd_regulatory.h" +#include +#include +#include "wlan_mlme_ucfg_api.h" +#include "cfg_ucfg_api.h" +#include "wlan_crypto_global_api.h" +#include "wlan_action_oui_ucfg_api.h" +#include "wlan_fwol_ucfg_api.h" +#include "nan_ucfg_api.h" +#include +#include "wlan_hdd_sta_info.h" +#include "ftm_time_sync_ucfg_api.h" +#include +#include "wlan_tdls_ucfg_api.h" +#include "wlan_mlme_twt_ucfg_api.h" +#include "wlan_if_mgr_ucfg_api.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_hdd_bootup_marker.h" +#include "wlan_hdd_medium_assess.h" +#include "wlan_hdd_scan.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include +#endif +#include "spatial_reuse_ucfg_api.h" +#include "wlan_hdd_son.h" +#include "wlan_hdd_mcc_quota.h" +#include "wlan_hdd_wds.h" +#include "wlan_hdd_pre_cac.h" +#include "wlan_osif_features.h" +#include "wlan_pre_cac_ucfg_api.h" +#include +#include "wlan_twt_ucfg_ext_cfg.h" +#include "wlan_twt_ucfg_ext_api.h" +#include "wlan_twt_ucfg_api.h" +#include "wlan_vdev_mgr_ucfg_api.h" +#include +#include "wlan_ll_sap_api.h" + +#define ACS_SCAN_EXPIRY_TIMEOUT_S 4 + +/* + * Defines the BIT position of 11bg/11abg/11abgn 802.11 support mode field + * of stainfo + */ +#define HDD_80211_MODE_ABGN 0 +/* Defines the BIT position of 11ac support mode field of stainfo */ +#define HDD_80211_MODE_AC 1 +/* Defines the BIT position of 11ax support mode field of stainfo */ +#define HDD_80211_MODE_AX 2 +/* Defines the BIT position of 11be support mode field of stainfo */ +#define HDD_80211_MODE_BE 4 + +#define HDD_MAX_CUSTOM_START_EVENT_SIZE 64 + +#ifdef NDP_SAP_CONCURRENCY_ENABLE +#define MAX_SAP_NUM_CONCURRENCY_WITH_NAN 2 +#else +#define MAX_SAP_NUM_CONCURRENCY_WITH_NAN 1 +#endif +#include "../../core/src/reg_priv_objs.h" + +#ifndef BSS_MEMBERSHIP_SELECTOR_HT_PHY +#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127 +#endif + +#ifndef BSS_MEMBERSHIP_SELECTOR_VHT_PHY +#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126 +#endif + +#ifndef BSS_MEMBERSHIP_SELECTOR_SAE_H2E +#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E 123 +#endif + +#ifndef BSS_MEMBERSHIP_SELECTOR_HE_PHY +#define BSS_MEMBERSHIP_SELECTOR_HE_PHY 122 +#endif + +/* + * 11B, 11G Rate table include Basic rate and Extended rate + * The IDX field is the rate index + * The HI field is the rate when RSSI is strong or being ignored + * (in this case we report actual rate) + * The MID field is the rate when RSSI is moderate + * (in this case we cap 11b rates at 5.5 and 11g rates at 24) + * The LO field is the rate when RSSI is low + * (in this case we don't report rates, actual current rate used) + */ +static const struct index_data_rate_type supported_data_rate[] = { + /* IDX HI HM LM LO (RSSI-based index */ + {2, { 10, 10, 10, 0} }, + {4, { 20, 20, 10, 0} }, + {11, { 55, 20, 10, 0} }, + {12, { 60, 55, 20, 0} }, + {18, { 90, 55, 20, 0} }, + {22, {110, 55, 20, 0} }, + {24, {120, 90, 60, 0} }, + {36, {180, 120, 60, 0} }, + {44, {220, 180, 60, 0} }, + {48, {240, 180, 90, 0} }, + {66, {330, 180, 90, 0} }, + {72, {360, 240, 90, 0} }, + {96, {480, 240, 120, 0} }, + {108, {540, 240, 120, 0} } +}; + +/* MCS Based rate table */ +/* HT MCS parameters with Nss = 1 */ +static const struct index_data_rate_type supported_mcs_rate_nss1[] = { + /* MCS L20 L40 S20 S40 */ + {0, { 65, 135, 72, 150} }, + {1, { 130, 270, 144, 300} }, + {2, { 195, 405, 217, 450} }, + {3, { 260, 540, 289, 600} }, + {4, { 390, 810, 433, 900} }, + {5, { 520, 1080, 578, 1200} }, + {6, { 585, 1215, 650, 1350} }, + {7, { 650, 1350, 722, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static const struct index_data_rate_type supported_mcs_rate_nss2[] = { + /* MCS L20 L40 S20 S40 */ + {0, {130, 270, 144, 300} }, + {1, {260, 540, 289, 600} }, + {2, {390, 810, 433, 900} }, + {3, {520, 1080, 578, 1200} }, + {4, {780, 1620, 867, 1800} }, + {5, {1040, 2160, 1156, 2400} }, + {6, {1170, 2430, 1300, 2700} }, + {7, {1300, 2700, 1444, 3000} } +}; + +/* MCS Based VHT rate table */ +/* MCS parameters with Nss = 1*/ +static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = { + /* MCS L80 S80 L40 S40 L20 S40*/ + {0, {293, 325}, {135, 150}, {65, 72} }, + {1, {585, 650}, {270, 300}, {130, 144} }, + {2, {878, 975}, {405, 450}, {195, 217} }, + {3, {1170, 1300}, {540, 600}, {260, 289} }, + {4, {1755, 1950}, {810, 900}, {390, 433} }, + {5, {2340, 2600}, {1080, 1200}, {520, 578} }, + {6, {2633, 2925}, {1215, 1350}, {585, 650} }, + {7, {2925, 3250}, {1350, 1500}, {650, 722} }, + {8, {3510, 3900}, {1620, 1800}, {780, 867} }, + {9, {3900, 4333}, {1800, 2000}, {780, 867} }, + {10, {4388, 4875}, {2025, 2250}, {975, 1083} }, + {11, {4875, 5417}, {2250, 2500}, {1083, 1203} } +}; + +/*MCS parameters with Nss = 2*/ +static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = { + /* MCS L80 S80 L40 S40 L20 S40*/ + {0, {585, 650}, {270, 300}, {130, 144} }, + {1, {1170, 1300}, {540, 600}, {260, 289} }, + {2, {1755, 1950}, {810, 900}, {390, 433} }, + {3, {2340, 2600}, {1080, 1200}, {520, 578} }, + {4, {3510, 3900}, {1620, 1800}, {780, 867} }, + {5, {4680, 5200}, {2160, 2400}, {1040, 1156} }, + {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, + {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, + {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, + {9, {7800, 8667}, {3600, 4000}, {1730, 1920} }, + {10, {8775, 9750}, {4050, 4500}, {1950, 2167} }, + {11, {9750, 10833}, {4500, 5000}, {2167, 2407} } +}; + +/* Function definitions */ + +/** + * hdd_sap_context_init() - Initialize SAP context. + * @hdd_ctx: HDD context. + * + * Initialize SAP context. + * + * Return: 0 on success. + */ +int hdd_sap_context_init(struct hdd_context *hdd_ctx) +{ + qdf_wake_lock_create(&hdd_ctx->sap_dfs_wakelock, "sap_dfs_wakelock"); + atomic_set(&hdd_ctx->sap_dfs_ref_cnt, 0); + + mutex_init(&hdd_ctx->sap_lock); + qdf_wake_lock_create(&hdd_ctx->sap_wake_lock, "qcom_sap_wakelock"); + + return 0; +} + +/** + * hdd_hostapd_init_sap_session() - To init the sap session completely + * @adapter: SAP/GO adapter + * @reinit: if called as part of reinit + * + * This API will do + * 1) sap_init_ctx() + * + * Return: 0 if success else non-zero value. + */ +static struct sap_context * +hdd_hostapd_init_sap_session(struct hdd_adapter *adapter, bool reinit) +{ + struct sap_context *sap_ctx; + QDF_STATUS status; + + if (!adapter) { + hdd_err("invalid adapter"); + return NULL; + } + + sap_ctx = adapter->deflink->session.ap.sap_context; + + if (!sap_ctx) { + hdd_err("can't allocate the sap_ctx"); + return NULL; + } + status = sap_init_ctx(sap_ctx, adapter->device_mode, + adapter->mac_addr.bytes, + adapter->deflink->vdev_id, reinit); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("wlansap_start failed!! status: %d", status); + adapter->deflink->session.ap.sap_context = NULL; + goto error; + } + return sap_ctx; +error: + wlansap_context_put(sap_ctx); + hdd_err("releasing the sap context for session-id:%d", + adapter->deflink->vdev_id); + + return NULL; +} + +/** + * hdd_hostapd_deinit_sap_session() - To de-init the sap session completely + * @link_info: Pointer of link_info in adapter + * + * This API will do + * 1) sap_init_ctx() + * 2) sap_destroy_ctx() + * + * Return: 0 if success else non-zero value. + */ +static int +hdd_hostapd_deinit_sap_session(struct wlan_hdd_link_info *link_info) +{ + struct sap_context *sap_ctx; + int status = 0; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + hdd_debug("sap context already released, nothing to be done"); + return 0; + } + + wlan_hdd_undo_acs(link_info); + if (!QDF_IS_STATUS_SUCCESS(sap_deinit_ctx(sap_ctx))) { + hdd_err("Error stopping the sap session"); + status = -EINVAL; + } + + if (!hdd_sap_destroy_ctx(link_info)) { + hdd_err("Error closing the sap session"); + status = -EINVAL; + } + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_debug("sap has issue closing the session"); + else + hdd_debug("sap has been closed successfully"); + + + return status; +} + +/** + * hdd_hostapd_channel_allow_suspend() - allow suspend in a channel. + * Called when, 1. bss stopped, 2. channel switch + * + * @adapter: pointer to hdd adapter + * @chan_freq: channel frequency + * @ch_params: channel params + * + * Return: None + */ +static void hdd_hostapd_channel_allow_suspend(struct hdd_adapter *adapter, + uint32_t chan_freq, + struct ch_params *ch_params) +{ + + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + struct sap_context *sap_ctx; + bool is_dfs; + + hdd_debug("bss_state: %d, chan_freq: %d, dfs_ref_cnt: %d", + hostapd_state->bss_state, chan_freq, + atomic_read(&hdd_ctx->sap_dfs_ref_cnt)); + + /* Return if BSS is already stopped */ + if (hostapd_state->bss_state == BSS_STOP) + return; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (!sap_ctx) { + hdd_err("sap ctx null"); + return; + } + + is_dfs = wlan_mlme_check_chan_param_has_dfs(hdd_ctx->pdev, + ch_params, + chan_freq); + if (!is_dfs) + return; + + /* Release wakelock when no more DFS channels are used */ + if (atomic_dec_and_test(&hdd_ctx->sap_dfs_ref_cnt)) { + hdd_err("DFS: allowing suspend (chan_freq: %d)", chan_freq); + qdf_wake_lock_release(&hdd_ctx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DFS); + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.dfs); + + } +} + +/** + * hdd_hostapd_channel_prevent_suspend() - prevent suspend in a channel. + * Called when, 1. bss started, 2. channel switch + * + * @adapter: pointer to hdd adapter + * @chan_freq: channel frequency + * @ch_params: channel params + * + * Return - None + */ +static void hdd_hostapd_channel_prevent_suspend(struct hdd_adapter *adapter, + uint32_t chan_freq, + struct ch_params *ch_params) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + struct sap_context *sap_ctx; + bool is_dfs; + + hdd_debug("bss_state: %d, chan_freq: %d, dfs_ref_cnt: %d", + hostapd_state->bss_state, chan_freq, + atomic_read(&hdd_ctx->sap_dfs_ref_cnt)); + /* Return if BSS is already started && wakelock is acquired */ + if ((hostapd_state->bss_state == BSS_START) && + (atomic_read(&hdd_ctx->sap_dfs_ref_cnt) >= 1)) + return; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (!sap_ctx) { + hdd_err("sap ctx null"); + return; + } + + is_dfs = wlan_mlme_check_chan_param_has_dfs(hdd_ctx->pdev, + &sap_ctx->ch_params, + chan_freq); + if (!is_dfs) + return; + + /* Acquire wakelock if we have at least one DFS channel in use */ + if (atomic_inc_return(&hdd_ctx->sap_dfs_ref_cnt) == 1) { + hdd_err("DFS: preventing suspend (chan_freq: %d)", chan_freq); + qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.dfs); + qdf_wake_lock_acquire(&hdd_ctx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DFS); + } +} + +/** + * hdd_sap_context_destroy() - Destroy SAP context + * + * @hdd_ctx: HDD context. + * + * Destroy SAP context. + * + * Return: None + */ +void hdd_sap_context_destroy(struct hdd_context *hdd_ctx) +{ + if (atomic_read(&hdd_ctx->sap_dfs_ref_cnt)) { + qdf_wake_lock_release(&hdd_ctx->sap_dfs_wakelock, + WIFI_POWER_EVENT_WAKELOCK_DRIVER_EXIT); + + atomic_set(&hdd_ctx->sap_dfs_ref_cnt, 0); + hdd_debug("DFS: Allowing suspend"); + } + + qdf_wake_lock_destroy(&hdd_ctx->sap_dfs_wakelock); + + mutex_destroy(&hdd_ctx->sap_lock); + qdf_wake_lock_destroy(&hdd_ctx->sap_wake_lock); +} + +/** + * __hdd_hostapd_open() - hdd open function for hostapd interface + * This is called in response to ifconfig up + * @dev: pointer to net_device structure + * + * Return - 0 for success non-zero for failure + */ +static int __hdd_hostapd_open(struct net_device *dev) +{ + struct hdd_adapter *adapter = netdev_priv(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + hdd_enter_dev(dev); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST, + NO_SESSION, 0); + + /* Nothing to be done if device is unloading */ + if (cds_is_driver_unloading()) { + hdd_err("Driver is unloading can not open the hdd"); + return -EBUSY; + } + + if (cds_is_driver_recovering()) { + hdd_err("WLAN is currently recovering; Please try again."); + return -EBUSY; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + /* ensure the physical soc is up */ + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + return ret; + } + + if (!hdd_allow_new_intf(hdd_ctx, adapter->device_mode)) + return -EOPNOTSUPP; + + ret = hdd_start_adapter(adapter, true); + if (ret) { + hdd_err("Error Initializing the AP mode: %d", ret); + return ret; + } + + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + /* Enable all Tx queues */ + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + hdd_exit(); + return 0; +} + +/** + * hdd_hostapd_open() - SSR wrapper for __hdd_hostapd_open + * @net_dev: pointer to net device + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_open(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_hostapd_open(net_dev); + if (!errno) + osif_vdev_cache_command(vdev_sync, NO_COMMAND); + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} + +int hdd_hostapd_stop_no_trans(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + hdd_enter_dev(dev); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST, + NO_SESSION, 0); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + /* + * Some tests requires to do "ifconfig down" only to bring + * down the SAP/GO without killing hostapd/wpa_supplicant. + * In such case, user will do "ifconfig up" to bring-back + * the SAP/GO session. to fulfill this requirement, driver + * needs to de-init the sap session here and re-init when + * __hdd_hostapd_open() API + */ + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + /* Stop all tx queues */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + if (!hdd_is_any_interface_open(hdd_ctx)) + hdd_psoc_idle_timer_start(hdd_ctx); + + hdd_exit(); + return 0; +} + +/** + * hdd_hostapd_stop() - SSR wrapper for__hdd_hostapd_stop + * @net_dev: pointer to net_device + * + * This is called in response to ifconfig down + * + * Return: 0 on success, error number otherwise + */ +int hdd_hostapd_stop(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) { + if (vdev_sync) + osif_vdev_cache_command(vdev_sync, INTERFACE_DOWN); + return errno; + } + + errno = hdd_hostapd_stop_no_trans(net_dev); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} + +/** + * hdd_hostapd_uninit() - hdd uninit function + * @dev: pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device. + * + * This function must be protected by a transition + * + * Return: None + */ +static void hdd_hostapd_uninit(struct net_device *dev) +{ + struct hdd_adapter *adapter = netdev_priv(dev); + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid magic"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("NULL hdd_ctx"); + return; + } + + hdd_deinit_adapter(hdd_ctx, adapter, true); + + /* after uninit our adapter structure will no longer be valid */ + adapter->magic = 0; + + hdd_exit(); +} + +/** + * __hdd_hostapd_change_mtu() - change mtu + * @dev: pointer to net_device + * @new_mtu: new mtu + * + * Return: 0 on success, error number otherwise + */ +static int __hdd_hostapd_change_mtu(struct net_device *dev, int new_mtu) +{ + hdd_enter_dev(dev); + + return 0; +} + +/** + * hdd_hostapd_change_mtu() - SSR wrapper for __hdd_hostapd_change_mtu + * @net_dev: pointer to net_device + * @new_mtu: new mtu + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_change_mtu(struct net_device *net_dev, int new_mtu) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_hostapd_change_mtu(net_dev, new_mtu); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS hdd_set_sap_ht2040_mode(struct hdd_adapter *adapter, + uint8_t channel_type) +{ + QDF_STATUS qdf_ret_status = QDF_STATUS_E_FAILURE; + mac_handle_t mac_handle; + + hdd_debug("change HT20/40 mode"); + + if (QDF_SAP_MODE == adapter->device_mode) { + mac_handle = adapter->hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("mac handle is null"); + return QDF_STATUS_E_FAULT; + } + qdf_ret_status = sme_set_ht2040_mode(mac_handle, + adapter->deflink->vdev_id, + channel_type, true); + if (qdf_ret_status == QDF_STATUS_E_FAILURE) { + hdd_err("Failed to change HT20/40 mode"); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_get_sap_ht2040_mode(struct hdd_adapter *adapter, + enum eSirMacHTChannelType *channel_type) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + mac_handle_t mac_handle; + + hdd_debug("get HT20/40 mode vdev_id %d", adapter->deflink->vdev_id); + + if (adapter->device_mode == QDF_SAP_MODE) { + mac_handle = adapter->hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("mac handle is null"); + return status; + } + status = sme_get_ht2040_mode(mac_handle, + adapter->deflink->vdev_id, + channel_type); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get HT20/40 mode"); + } + + return status; +} +#endif + +/** + * __hdd_hostapd_set_mac_address() - + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * @dev: pointer to the net device. + * @addr: pointer to the sockaddr. + * + * Return: 0 for success, non zero for failure + */ +static int __hdd_hostapd_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *psta_mac_addr = addr; + struct hdd_adapter *adapter, *adapter_temp; + struct hdd_context *hdd_ctx; + int ret = 0; + bool eht_capab; + struct qdf_mac_addr mac_addr, mld_addr; + + hdd_enter_dev(dev); + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + qdf_mem_copy(&mac_addr, psta_mac_addr->sa_data, sizeof(mac_addr)); + adapter_temp = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr.bytes); + if (adapter_temp) { + if (!qdf_str_cmp(adapter_temp->dev->name, dev->name)) + return 0; + hdd_err("%s adapter exist with same address " QDF_MAC_ADDR_FMT, + adapter_temp->dev->name, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + return -EINVAL; + } + + if (qdf_is_macaddr_zero(&mac_addr)) { + hdd_err("MAC is all zero"); + return -EINVAL; + } + + if (qdf_is_macaddr_broadcast(&mac_addr)) { + hdd_err("MAC is Broadcast"); + return -EINVAL; + } + + if (qdf_is_macaddr_group(&mac_addr)) { + hdd_err("MAC is Multicast"); + return -EINVAL; + } + + hdd_debug("Changing MAC to " QDF_MAC_ADDR_FMT " of interface %s ", + QDF_MAC_ADDR_REF(mac_addr.bytes), + dev->name); + + if (adapter->deflink->vdev) { + if (!hdd_is_dynamic_set_mac_addr_allowed(adapter)) + return -ENOTSUPP; + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (eht_capab && hdd_adapter_is_ml_adapter(adapter)) + qdf_copy_macaddr(&mld_addr, &mac_addr); + else + qdf_zero_macaddr(&mld_addr); + + ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, + mld_addr, false); + if (ret) + return ret; + } + + hdd_set_mld_address(adapter, &mac_addr); + + /* Currently for SL-ML-SAP use same MAC for both MLD and link */ + hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, &mac_addr); + ucfg_dp_update_intf_mac(hdd_ctx->psoc, &adapter->mac_addr, &mac_addr, + adapter->deflink->vdev); + memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN); + qdf_net_update_net_device_dev_addr(dev, psta_mac_addr->sa_data, + ETH_ALEN); + hdd_exit(); + return 0; +} + +/** + * hdd_hostapd_set_mac_address() - set mac address + * @net_dev: pointer to net_device + * @addr: mac address + * + * Return: 0 on success, error number otherwise + */ +static int hdd_hostapd_set_mac_address(struct net_device *net_dev, void *addr) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_hostapd_set_mac_address(net_dev, addr); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static void hdd_clear_sta(struct hdd_adapter *adapter, + struct hdd_station_info *sta_info) +{ + struct hdd_ap_ctx *ap_ctx; + struct csr_del_sta_params del_sta_params; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + + if (qdf_is_macaddr_broadcast(&sta_info->sta_mac)) + return; + + wlansap_populate_del_sta_params(sta_info->sta_mac.bytes, + REASON_DEAUTH_NETWORK_LEAVING, + SIR_MAC_MGMT_DISASSOC, + &del_sta_params); + + hdd_softap_sta_disassoc(adapter, &del_sta_params); +} + +static void hdd_clear_all_sta(struct hdd_adapter *adapter) +{ + struct hdd_station_info *sta_info, *tmp = NULL; + + hdd_enter_dev(adapter->dev); + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_HDD_CLEAR_ALL_STA) { + hdd_clear_sta(adapter, sta_info); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_HDD_CLEAR_ALL_STA); + } +} + +static int hdd_stop_bss_link(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + int errno; + QDF_STATUS status; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags)) { + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink)); + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_debug("Deleting SAP/P2P link!!!!!!"); + + clear_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->deflink->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + errno = (status == QDF_STATUS_SUCCESS) ? 0 : -EBUSY; + } + hdd_exit(); + return errno; +} + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +static void +wlan_hdd_set_chandef_320mhz(struct cfg80211_chan_def *chandef, + struct wlan_channel *chan) +{ + if (chan->ch_width != CH_WIDTH_320MHZ) + return; + + chandef->width = NL80211_CHAN_WIDTH_320; + if (chan->ch_cfreq2) + chandef->center_freq1 = chan->ch_cfreq2; +} + +static void wlan_hdd_set_chandef_width(struct cfg80211_chan_def *chandef, + enum phy_ch_width width) +{ + if (width == CH_WIDTH_320MHZ) + chandef->width = NL80211_CHAN_WIDTH_320; +} + +static inline bool wlan_hdd_is_chwidth_320mhz(enum phy_ch_width ch_width) +{ + return ch_width == CH_WIDTH_320MHZ; +} + +static uint16_t +wlan_hdd_get_puncture_bitmap(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) + return ap_ctx->reg_punc_bitmap; + + return 0; +} +#else /* !WLAN_FEATURE_11BE */ +static inline +void wlan_hdd_set_chandef_320mhz(struct cfg80211_chan_def *chandef, + struct wlan_channel *chan) +{ +} + +static inline void wlan_hdd_set_chandef_width(struct cfg80211_chan_def *chandef, + enum phy_ch_width width) +{ +} + +static inline bool wlan_hdd_is_chwidth_320mhz(enum phy_ch_width ch_width) +{ + return false; +} + +static inline uint16_t +wlan_hdd_get_puncture_bitmap(struct wlan_hdd_link_info *link_info) +{ + return 0; +} +#endif /* WLAN_FEATURE_11BE */ + +static QDF_STATUS hdd_create_chandef(struct hdd_adapter *adapter, + struct wlan_channel *wlan_chan, + struct cfg80211_chan_def *chandef) +{ + struct ieee80211_channel *chan; + enum nl80211_channel_type channel_type; + uint32_t freq; + bool legacy_phymode = true; + + freq = wlan_chan->ch_freq; + chan = ieee80211_get_channel(adapter->wdev.wiphy, freq); + if (!chan) { + hdd_err("Invalid input frequency %d for channel conversion", + freq); + return QDF_STATUS_E_FAILURE; + } + + if (IS_WLAN_PHYMODE_HT(wlan_chan->ch_phymode) || + IS_WLAN_PHYMODE_VHT(wlan_chan->ch_phymode) || + IS_WLAN_PHYMODE_HE(wlan_chan->ch_phymode) || + IS_WLAN_PHYMODE_EHT(wlan_chan->ch_phymode)) + legacy_phymode = false; + + if (legacy_phymode) { + channel_type = NL80211_CHAN_NO_HT; + } else { + if (!wlan_chan->ch_cfreq1 || + wlan_chan->ch_cfreq1 == wlan_chan->ch_freq) + channel_type = NL80211_CHAN_HT20; + else if (wlan_chan->ch_cfreq1 > wlan_chan->ch_freq) + channel_type = NL80211_CHAN_HT40PLUS; + else + channel_type = NL80211_CHAN_HT40MINUS; + } + + cfg80211_chandef_create(chandef, chan, channel_type); + + /* cfg80211_chandef_create() does update of width and center_freq1 + * only for NL80211_CHAN_NO_HT, NL80211_CHAN_HT20, NL80211_CHAN_HT40PLUS + * and NL80211_CHAN_HT40MINUS. + */ + switch (wlan_chan->ch_width) { + case CH_WIDTH_80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80; + break; + case CH_WIDTH_80P80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80P80; + if (wlan_chan->ch_cfreq2) + chandef->center_freq2 = wlan_chan->ch_cfreq2; + break; + case CH_WIDTH_160MHZ: + chandef->width = NL80211_CHAN_WIDTH_160; + if (wlan_chan->ch_cfreq2) + chandef->center_freq1 = wlan_chan->ch_cfreq2; + break; + default: + break; + } + + wlan_hdd_set_chandef_320mhz(chandef, wlan_chan); + + if (wlan_chan->ch_width == CH_WIDTH_80MHZ || + wlan_chan->ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_chan->ch_cfreq1) + chandef->center_freq1 = wlan_chan->ch_cfreq1; + } + + return QDF_STATUS_SUCCESS; +} + +static void hdd_chan_change_notify_update(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + struct wlan_objmgr_vdev *vdev; + uint16_t link_id = 0; + struct hdd_adapter *assoc_adapter; + struct wlan_channel *chan; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct net_device *dev; + struct cfg80211_chan_def chandef; + uint16_t puncture_bitmap = 0; + uint8_t vdev_id; + + if (!mac_handle) { + hdd_err("mac_handle is NULL"); + return; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return; + + dev = adapter->dev; + vdev_id = wlan_vdev_get_id(vdev); + if (hdd_adapter_is_link_adapter(adapter)) { + hdd_debug("replace link adapter dev with ml adapter dev"); + assoc_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter); + if (!assoc_adapter) { + hdd_err("Assoc adapter is NULL"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return; + } + dev = assoc_adapter->dev; + } + + mutex_lock(&dev->ieee80211_ptr->mtx); + if (wlan_vdev_mlme_is_active(vdev) != QDF_STATUS_SUCCESS) { + hdd_debug("Vdev %d mode %d not UP", vdev_id, + adapter->device_mode); + goto exit; + } + + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) && + !ucfg_cm_is_vdev_active(vdev)) { + hdd_debug("Vdev %d is not connected", vdev_id); + goto exit; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + link_id = wlan_vdev_get_link_id(vdev); + + chan = wlan_vdev_get_active_channel(vdev); + + if (!chan) + goto exit; + + status = hdd_create_chandef(adapter, chan, &chandef); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Vdev %d failed to create channel def", vdev_id); + goto exit; + } + + puncture_bitmap = wlan_hdd_get_puncture_bitmap(link_info); + + hdd_debug("notify: vdev %d chan:%d width:%d freq1:%d freq2:%d punct 0x%x", + vdev_id, chandef.chan->center_freq, chandef.width, + chandef.center_freq1, chandef.center_freq2, + puncture_bitmap); + + wlan_cfg80211_ch_switch_notify(dev, &chandef, link_id, puncture_bitmap); + +exit: + mutex_unlock(&dev->ieee80211_ptr->mtx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); +} + +void hdd_chan_change_notify_work_handler(void *data) +{ + struct wlan_hdd_link_info *link_info = + (struct wlan_hdd_link_info *)data; + + if (!link_info) + return; + + hdd_chan_change_notify_update(link_info); +} + +/** + * hdd_send_radar_event() - Function to send radar events to user space + * @hdd_context: HDD context + * @event: Type of radar event + * @dfs_info: Structure containing DFS channel and country + * @wdev: Wireless device structure + * + * This function is used to send radar events such as CAC start, CAC + * end etc., to userspace + * + * Return: Success on sending notifying userspace + * + */ +static QDF_STATUS hdd_send_radar_event(struct hdd_context *hdd_context, + eSapHddEvent event, + struct wlan_dfs_info dfs_info, + struct wireless_dev *wdev) +{ + + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index; + uint32_t freq, ret; + uint32_t data_size; + + if (!hdd_context) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_FAILURE; + } + + freq = cds_chan_to_freq(dfs_info.channel); + + switch (event) { + case eSAP_DFS_CAC_START: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED_INDEX; + data_size = sizeof(uint32_t); + break; + case eSAP_DFS_CAC_END: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED_INDEX; + data_size = sizeof(uint32_t); + break; + case eSAP_DFS_RADAR_DETECT: + index = + QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED_INDEX; + data_size = sizeof(uint32_t); + break; + default: + return QDF_STATUS_E_FAILURE; + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_context->wiphy, + wdev, + data_size + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed for %d", + index); + return QDF_STATUS_E_FAILURE; + } + + ret = nla_put_u32(vendor_event, NL80211_ATTR_WIPHY_FREQ, freq); + + if (ret) { + hdd_err("NL80211_ATTR_WIPHY_FREQ put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return QDF_STATUS_E_FAILURE; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * hdd_handle_acs_scan_event() - handle acs scan event for SAP + * @sap_event: tpSap_Event + * @adapter: struct hdd_adapter for SAP + * + * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event. + * It will update scan result to cfg80211 and start a timer to flush the + * cached acs scan result. + * + * Return: QDF_STATUS_SUCCESS on success, + * other value on failure + */ +static QDF_STATUS hdd_handle_acs_scan_event(struct sap_event *sap_event, + struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + struct sap_acs_scan_complete_event *comp_evt; + QDF_STATUS qdf_status; + int freq_list_size; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + comp_evt = &sap_event->sapevt.sap_acs_scan_comp; + hdd_ctx->skip_acs_scan_status = eSAP_SKIP_ACS_SCAN; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_freq_list); + hdd_ctx->last_acs_freq_list = NULL; + hdd_ctx->num_of_channels = 0; + /* cache the previous ACS scan channel list . + * If the following OBSS scan chan list is covered by ACS chan list, + * we can skip OBSS Scan to save SAP starting total time. + */ + if (comp_evt->num_of_channels && comp_evt->freq_list) { + freq_list_size = comp_evt->num_of_channels * + sizeof(comp_evt->freq_list[0]); + hdd_ctx->last_acs_freq_list = qdf_mem_malloc( + freq_list_size); + if (hdd_ctx->last_acs_freq_list) { + qdf_mem_copy(hdd_ctx->last_acs_freq_list, + comp_evt->freq_list, + freq_list_size); + hdd_ctx->num_of_channels = comp_evt->num_of_channels; + } + } + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + + hdd_debug("Reusing Last ACS scan result for %d sec", + ACS_SCAN_EXPIRY_TIMEOUT_S); + qdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer); + qdf_status = qdf_mc_timer_start(&hdd_ctx->skip_acs_scan_timer, + ACS_SCAN_EXPIRY_TIMEOUT_S * 1000); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to start ACS scan expiry timer"); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS hdd_handle_acs_scan_event(struct sap_event *sap_event, + struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * get_max_rate_vht() - calculate max rate for VHT mode + * @nss: num of streams + * @ch_width: channel width + * @sgi: short gi + * @vht_mcs_map: vht mcs map + * + * This function calculate max rate for VHT mode + * + * Return: max rate + */ +static int get_max_rate_vht(int nss, int ch_width, int sgi, int vht_mcs_map) +{ + const struct index_vht_data_rate_type *supported_vht_mcs_rate; + enum data_rate_11ac_max_mcs vht_max_mcs; + int maxrate = 0; + int maxidx; + + if (nss == 1) { + supported_vht_mcs_rate = supported_vht_mcs_rate_nss1; + } else if (nss == 2) { + supported_vht_mcs_rate = supported_vht_mcs_rate_nss2; + } else { + /* Not Supported */ + hdd_debug("nss %d not supported", nss); + return maxrate; + } + + vht_max_mcs = + (enum data_rate_11ac_max_mcs) + (vht_mcs_map & DATA_RATE_11AC_MCS_MASK); + + if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) { + maxidx = 7; + } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) { + maxidx = 8; + } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) { + if (ch_width == eHT_CHANNEL_WIDTH_20MHZ) + /* MCS9 is not valid for VHT20 when nss=1,2 */ + maxidx = 8; + else + maxidx = 9; + } else { + hdd_err("vht mcs map %x not supported", + vht_mcs_map & DATA_RATE_11AC_MCS_MASK); + return maxrate; + } + + if (ch_width == eHT_CHANNEL_WIDTH_20MHZ) { + maxrate = + supported_vht_mcs_rate[maxidx].supported_VHT20_rate[sgi]; + } else if (ch_width == eHT_CHANNEL_WIDTH_40MHZ) { + maxrate = + supported_vht_mcs_rate[maxidx].supported_VHT40_rate[sgi]; + } else if (ch_width == eHT_CHANNEL_WIDTH_80MHZ) { + maxrate = + supported_vht_mcs_rate[maxidx].supported_VHT80_rate[sgi]; + } else { + hdd_err("ch_width %d not supported", ch_width); + return maxrate; + } + + return maxrate; +} + +/** + * calculate_max_phy_rate() - calculate maximum phy rate (100kbps) + * @mode: phymode: Legacy, 11a/b/g, HT, VHT + * @nss: num of stream (maximum num is 2) + * @ch_width: channel width + * @sgi: short gi enabled or not + * @supp_idx: max supported idx + * @ext_idx: max extended idx + * @ht_mcs_idx: max mcs index for HT + * @vht_mcs_map: mcs map for VHT + * + * return: maximum phy rate in 100kbps + */ +static int calculate_max_phy_rate(int mode, int nss, int ch_width, + int sgi, int supp_idx, int ext_idx, + int ht_mcs_idx, int vht_mcs_map) +{ + const struct index_data_rate_type *supported_mcs_rate; + int maxidx = 12; /*default 6M mode*/ + int maxrate = 0, tmprate; + int i; + + /* check supported rates */ + if (supp_idx != 0xff && maxidx < supp_idx) + maxidx = supp_idx; + + /* check extended rates */ + if (ext_idx != 0xff && maxidx < ext_idx) + maxidx = ext_idx; + + for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) { + if (supported_data_rate[i].beacon_rate_index == maxidx) + maxrate = supported_data_rate[i].supported_rate[0]; + } + + if (mode == SIR_SME_PHY_MODE_HT) { + /* check for HT Mode */ + maxidx = ht_mcs_idx; + if (maxidx > 7) { + hdd_err("ht_mcs_idx %d is incorrect", ht_mcs_idx); + return maxrate; + } + if (nss == 1) { + supported_mcs_rate = supported_mcs_rate_nss1; + } else if (nss == 2) { + supported_mcs_rate = supported_mcs_rate_nss2; + } else { + /* Not Supported */ + hdd_err("nss %d not supported", nss); + return maxrate; + } + + if (ch_width == eHT_CHANNEL_WIDTH_20MHZ) { + tmprate = sgi ? + supported_mcs_rate[maxidx].supported_rate[2] : + supported_mcs_rate[maxidx].supported_rate[0]; + } else if (ch_width == eHT_CHANNEL_WIDTH_40MHZ) { + tmprate = sgi ? + supported_mcs_rate[maxidx].supported_rate[3] : + supported_mcs_rate[maxidx].supported_rate[1]; + } else { + hdd_err("invalid mode %d ch_width %d", + mode, ch_width); + return maxrate; + } + + if (maxrate < tmprate) + maxrate = tmprate; + } + + if (mode == SIR_SME_PHY_MODE_VHT) { + /* check for VHT Mode */ + tmprate = get_max_rate_vht(nss, ch_width, sgi, vht_mcs_map); + if (maxrate < tmprate) + maxrate = tmprate; + } + + return maxrate; +} + +#if SUPPORT_11AX +/** + * hdd_convert_11ax_phymode_to_dot11mode() - get dot11 mode from phymode + * @phymode: phymode of sta associated to SAP + * + * The function is to convert the 11ax phymode to corresponding dot11 mode + * + * Return: dot11mode. + */ +static inline enum qca_wlan_802_11_mode +hdd_convert_11ax_phymode_to_dot11mode(int phymode) +{ + switch (phymode) { + case MODE_11AX_HE20: + case MODE_11AX_HE40: + case MODE_11AX_HE80: + case MODE_11AX_HE80_80: + case MODE_11AX_HE160: + case MODE_11AX_HE20_2G: + case MODE_11AX_HE40_2G: + case MODE_11AX_HE80_2G: + return QCA_WLAN_802_11_MODE_11AX; + default: + return QCA_WLAN_802_11_MODE_INVALID; + } +} +#else +static inline enum qca_wlan_802_11_mode +hdd_convert_11ax_phymode_to_dot11mode(int phymode) +{ + return QCA_WLAN_802_11_MODE_INVALID; +} +#endif + +enum qca_wlan_802_11_mode hdd_convert_dot11mode_from_phymode(int phymode) +{ + + switch (phymode) { + + case MODE_11A: + return QCA_WLAN_802_11_MODE_11A; + + case MODE_11B: + return QCA_WLAN_802_11_MODE_11B; + + case MODE_11G: + case MODE_11GONLY: + return QCA_WLAN_802_11_MODE_11G; + + case MODE_11NA_HT20: + case MODE_11NG_HT20: + case MODE_11NA_HT40: + case MODE_11NG_HT40: + return QCA_WLAN_802_11_MODE_11N; + + case MODE_11AC_VHT20: + case MODE_11AC_VHT40: + case MODE_11AC_VHT80: + case MODE_11AC_VHT20_2G: + case MODE_11AC_VHT40_2G: + case MODE_11AC_VHT80_2G: +#ifdef CONFIG_160MHZ_SUPPORT + case MODE_11AC_VHT80_80: + case MODE_11AC_VHT160: +#endif + return QCA_WLAN_802_11_MODE_11AC; + default: + return hdd_convert_11ax_phymode_to_dot11mode(phymode); + } + +} + +/** + * hdd_fill_station_info() - fill stainfo once connected + * @adapter: pointer to hdd adapter + * @event: associate/reassociate event received + * + * The function is to update rate stats to stainfo + * + * Return: None. + */ +static void hdd_fill_station_info(struct hdd_adapter *adapter, + tSap_StationAssocReassocCompleteEvent *event) +{ + struct hdd_station_info *stainfo, *cache_sta_info; + struct hdd_station_info *oldest_disassoc_sta_info = NULL; + qdf_time_t oldest_disassoc_sta_ts = 0; + bool is_dot11_mode_abgn; + + stainfo = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + event->staMac.bytes, + STA_INFO_FILL_STATION_INFO); + + if (!stainfo) { + hdd_err("invalid stainfo"); + return; + } + + qdf_mem_copy(&stainfo->capability, &event->capability_info, + sizeof(uint16_t)); + stainfo->freq = event->chan_info.mhz; + stainfo->sta_type = event->staType; + stainfo->dot11_mode = + hdd_convert_dot11mode_from_phymode(event->chan_info.info); + + stainfo->nss = event->chan_info.nss; + stainfo->rate_flags = event->chan_info.rate_flags; + stainfo->ampdu = event->ampdu; + stainfo->sgi_enable = event->sgi_enable; + stainfo->tx_stbc = event->tx_stbc; + stainfo->rx_stbc = event->rx_stbc; + stainfo->ch_width = event->ch_width; + stainfo->mode = event->mode; + stainfo->max_supp_idx = event->max_supp_idx; + stainfo->max_ext_idx = event->max_ext_idx; + stainfo->max_mcs_idx = event->max_mcs_idx; + stainfo->max_real_mcs_idx = event->max_real_mcs_idx; + stainfo->rx_mcs_map = event->rx_mcs_map; + stainfo->tx_mcs_map = event->tx_mcs_map; + stainfo->assoc_ts = qdf_system_ticks(); + stainfo->max_phy_rate = + calculate_max_phy_rate(stainfo->mode, + stainfo->nss, + stainfo->ch_width, + stainfo->sgi_enable, + stainfo->max_supp_idx, + stainfo->max_ext_idx, + stainfo->max_mcs_idx, + stainfo->rx_mcs_map); + /* expect max_phy_rate report in kbps */ + stainfo->max_phy_rate *= 100; + + /* + * Connected Peer always supports atleast one of the + * 802.11 mode out of 11bg/11abg/11abgn, hence this field + * should always be true. + */ + is_dot11_mode_abgn = true; + stainfo->ecsa_capable = event->ecsa_capable; + stainfo->ext_cap = event->ext_cap; + stainfo->supported_band = event->supported_band; + + if (event->vht_caps.present) { + stainfo->vht_present = true; + hdd_copy_vht_caps(&stainfo->vht_caps, &event->vht_caps); + stainfo->support_mode |= + (stainfo->vht_present << HDD_80211_MODE_AC); + } + if (event->ht_caps.present) { + stainfo->ht_present = true; + hdd_copy_ht_caps(&stainfo->ht_caps, &event->ht_caps); + } + + stainfo->support_mode |= + (event->he_caps_present << HDD_80211_MODE_AX); + + if (event->he_caps_present && !(event->vht_caps.present || + event->ht_caps.present)) + is_dot11_mode_abgn = false; + + stainfo->support_mode |= + (event->eht_caps_present << HDD_80211_MODE_BE); + stainfo->support_mode |= is_dot11_mode_abgn << HDD_80211_MODE_ABGN; + /* Initialize DHCP info */ + stainfo->dhcp_phase = DHCP_PHASE_ACK; + stainfo->dhcp_nego_status = DHCP_NEGO_STOP; + + /* Save assoc request IEs */ + if (event->ies_len) { + qdf_mem_free(stainfo->assoc_req_ies.ptr); + stainfo->assoc_req_ies.len = 0; + stainfo->assoc_req_ies.ptr = qdf_mem_malloc(event->ies_len); + if (stainfo->assoc_req_ies.ptr) { + qdf_mem_copy(stainfo->assoc_req_ies.ptr, event->ies, + event->ies_len); + stainfo->assoc_req_ies.len = event->ies_len; + } + } + + qdf_mem_copy(&stainfo->mld_addr, &event->sta_mld, QDF_MAC_ADDR_SIZE); + + cache_sta_info = + hdd_get_sta_info_by_mac(&adapter->cache_sta_info_list, + event->staMac.bytes, + STA_INFO_FILL_STATION_INFO); + + if (!cache_sta_info) { + cache_sta_info = qdf_mem_malloc(sizeof(*cache_sta_info)); + if (!cache_sta_info) + goto exit; + + qdf_mem_copy(cache_sta_info, stainfo, sizeof(*cache_sta_info)); + cache_sta_info->is_attached = 0; + cache_sta_info->assoc_req_ies.ptr = + qdf_mem_malloc(event->ies_len); + if (cache_sta_info->assoc_req_ies.ptr) { + qdf_mem_copy(cache_sta_info->assoc_req_ies.ptr, + event->ies, event->ies_len); + cache_sta_info->assoc_req_ies.len = event->ies_len; + } + qdf_atomic_init(&cache_sta_info->ref_cnt); + + /* + * If cache_sta_info is not present and cache limit is not + * reached, then create and attach. Else find the cache that is + * the oldest and replace that with the new cache. + */ + if (qdf_atomic_read(&adapter->cache_sta_count) < + WLAN_MAX_STA_COUNT) { + hdd_sta_info_attach(&adapter->cache_sta_info_list, + cache_sta_info); + qdf_atomic_inc(&adapter->cache_sta_count); + } else { + struct hdd_station_info *temp_sta_info, *tmp = NULL; + struct hdd_sta_info_obj *sta_list = + &adapter->cache_sta_info_list; + + hdd_debug("reached max caching, removing oldest"); + + /* Find the oldest cached station */ + hdd_for_each_sta_ref_safe(adapter->cache_sta_info_list, + temp_sta_info, tmp, + STA_INFO_FILL_STATION_INFO) { + if (temp_sta_info->disassoc_ts && + (!oldest_disassoc_sta_ts || + qdf_system_time_after( + oldest_disassoc_sta_ts, + temp_sta_info->disassoc_ts))) { + oldest_disassoc_sta_ts = + temp_sta_info->disassoc_ts; + oldest_disassoc_sta_info = + temp_sta_info; + } + hdd_put_sta_info_ref( + sta_list, &temp_sta_info, + true, + STA_INFO_FILL_STATION_INFO); + } + + /* Remove the oldest and store the current */ + hdd_sta_info_detach(&adapter->cache_sta_info_list, + &oldest_disassoc_sta_info); + hdd_sta_info_attach(&adapter->cache_sta_info_list, + cache_sta_info); + } + } else { + qdf_copy_macaddr(&cache_sta_info->sta_mac, &event->staMac); + qdf_copy_macaddr(&cache_sta_info->mld_addr, &event->sta_mld); + hdd_put_sta_info_ref(&adapter->cache_sta_info_list, + &cache_sta_info, true, + STA_INFO_FILL_STATION_INFO); + } + + hdd_debug("cap %d %d %d %d %d %d %d %d %d %x %d", + stainfo->ampdu, + stainfo->sgi_enable, + stainfo->tx_stbc, + stainfo->rx_stbc, + stainfo->is_qos_enabled, + stainfo->ch_width, + stainfo->mode, + event->wmmEnabled, + event->chan_info.nss, + event->chan_info.rate_flags, + stainfo->max_phy_rate); + hdd_debug("rate info %d %d %d %d %d", + stainfo->max_supp_idx, + stainfo->max_ext_idx, + stainfo->max_mcs_idx, + stainfo->rx_mcs_map, + stainfo->tx_mcs_map); +exit: + hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true, + STA_INFO_FILL_STATION_INFO); + return; +} + +void hdd_stop_sap_due_to_invalid_channel(struct work_struct *work) +{ + struct hdd_adapter *sap_adapter = container_of(work, struct hdd_adapter, + sap_stop_bss_work); + struct osif_vdev_sync *vdev_sync; + struct sap_context *sap_ctx; + + if (osif_vdev_sync_op_start(sap_adapter->dev, &vdev_sync)) + return; + + hdd_debug("work started for sap session[%d]", + sap_adapter->deflink->vdev_id); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(sap_adapter->deflink); + wlan_hdd_stop_sap(sap_adapter); + wlansap_cleanup_cac_timer(sap_ctx); + hdd_debug("work finished for sap"); + + osif_vdev_sync_op_stop(vdev_sync); +} + +/** + * hdd_hostapd_apply_action_oui() - Check for action_ouis to be applied on peers + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * @event: assoc complete params + * + * This function is used to check whether aggressive tx should be disabled + * based on the soft-ap configuration and action_oui ini + * gActionOUIDisableAggressiveTX + * + * Return: None + */ +static void +hdd_hostapd_apply_action_oui(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + tSap_StationAssocReassocCompleteEvent *event) +{ + bool found; + uint32_t freq; + tSirMacHTChannelWidth ch_width; + enum sir_sme_phy_mode mode; + struct action_oui_search_attr attr = {0}; + QDF_STATUS status; + + ch_width = event->ch_width; + if (ch_width != eHT_CHANNEL_WIDTH_20MHZ) + return; + + freq = event->chan_info.mhz; + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + attr.enable_2g = true; + else if (WLAN_REG_IS_5GHZ_CH_FREQ(freq)) + attr.enable_5g = true; + else + return; + + mode = event->mode; + if (event->vht_caps.present && mode == SIR_SME_PHY_MODE_VHT) + attr.vht_cap = true; + else if (event->ht_caps.present && mode == SIR_SME_PHY_MODE_HT) + attr.ht_cap = true; + + attr.mac_addr = (uint8_t *)(&event->staMac); + + found = ucfg_action_oui_search(hdd_ctx->psoc, + &attr, + ACTION_OUI_DISABLE_AGGRESSIVE_TX); + if (!found) + return; + + status = sme_set_peer_param(attr.mac_addr, + WMI_PEER_PARAM_DISABLE_AGGRESSIVE_TX, + true, adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to disable aggregation for peer"); +} + +static void hdd_hostapd_set_sap_key(struct hdd_adapter *adapter) +{ + struct wlan_crypto_key *crypto_key; + uint8_t key_index; + + for (key_index = 0; key_index < WLAN_CRYPTO_TOTAL_KEYIDX; ++key_index) { + crypto_key = wlan_crypto_get_key(adapter->deflink->vdev, + key_index); + if (!crypto_key) + continue; + + hdd_debug("key idx %d", key_index); + ucfg_crypto_set_key_req(adapter->deflink->vdev, crypto_key, + WLAN_CRYPTO_KEY_TYPE_GROUP); + wma_update_set_key(adapter->deflink->vdev_id, false, key_index, + crypto_key->cipher_type); + } +} + +#ifdef WLAN_FEATURE_11BE +static void +hdd_fill_channel_change_puncture(struct hdd_ap_ctx *ap_ctx, + struct ch_params *sap_ch_param) +{ + ap_ctx->reg_punc_bitmap = + sap_ch_param->reg_punc_bitmap; +} +#else +static void +hdd_fill_channel_change_puncture(struct hdd_ap_ctx *ap_ctx, + struct ch_params *sap_ch_param) +{ +} +#endif + +/** + * hdd_hostapd_chan_change() - prepare new operation chan info to kernel + * @link_info: Link info pointer in HDD adapter + * @sap_event: pointer to sap_event + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_hostapd_chan_change(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event) +{ + struct ch_params sap_ch_param = {0}; + eCsrPhyMode phy_mode; + bool legacy_phymode; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sap_ch_selected_s *sap_chan_selected; + struct sap_config *sap_config = + &link_info->session.ap.sap_config; + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + if (sap_event->sapHddEventCode == eSAP_CHANNEL_CHANGE_RESP) + sap_chan_selected = + &sap_event->sapevt.sap_chan_cng_rsp.sap_ch_selected; + else + sap_chan_selected = &sap_event->sapevt.sap_ch_selected; + + sap_ch_param.ch_width = sap_chan_selected->ch_width; + sap_ch_param.mhz_freq_seg0 = + sap_chan_selected->vht_seg0_center_ch_freq; + sap_ch_param.mhz_freq_seg1 = + sap_chan_selected->vht_seg1_center_ch_freq; + + if (sap_phymode_is_eht(sap_config->SapHw_mode)) + wlan_reg_set_create_punc_bitmap(&sap_ch_param, true); + wlan_reg_set_channel_params_for_pwrmode( + hdd_ctx->pdev, + sap_chan_selected->pri_ch_freq, + sap_chan_selected->ht_sec_ch_freq, + &sap_ch_param, REG_CURRENT_PWR_MODE); + + phy_mode = wlan_sap_get_phymode( + WLAN_HDD_GET_SAP_CTX_PTR(link_info)); + + switch (phy_mode) { + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + case eCSR_DOT11_MODE_11be: + case eCSR_DOT11_MODE_11be_ONLY: + legacy_phymode = false; + break; + default: + legacy_phymode = true; + break; + } + + hdd_fill_channel_change_puncture(ap_ctx, &sap_ch_param); + qdf_sched_work(0, &link_info->chan_change_notify_work); + + return QDF_STATUS_SUCCESS; +} + +static inline void +hdd_hostapd_update_beacon_country_ie(struct hdd_adapter *adapter) +{ + struct hdd_station_info *sta_info, *tmp = NULL; + struct hdd_context *hdd_ctx; + struct hdd_ap_ctx *ap_ctx; + struct action_oui_search_attr attr = {0}; + QDF_STATUS status; + bool found = false; + + if (!adapter) { + hdd_err("invalid adapter"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_HOSTAPD_SAP_EVENT_CB) { + if (!sta_info->assoc_req_ies.len) + goto release_ref; + + qdf_mem_zero(&attr, sizeof(struct action_oui_search_attr)); + attr.ie_data = sta_info->assoc_req_ies.ptr; + attr.ie_length = sta_info->assoc_req_ies.len; + + found = ucfg_action_oui_search(hdd_ctx->psoc, + &attr, + ACTION_OUI_TAKE_ALL_BAND_INFO); + if (found) { + if (!ap_ctx->country_ie_updated) { + status = sme_update_beacon_country_ie( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + true); + if (status == QDF_STATUS_SUCCESS) + ap_ctx->country_ie_updated = true; + else + hdd_err("fail to update country ie"); + } + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + return; + } +release_ref: + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + } + + if (ap_ctx->country_ie_updated) { + status = sme_update_beacon_country_ie( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, false); + if (status == QDF_STATUS_SUCCESS) + ap_ctx->country_ie_updated = false; + else + hdd_err("fail to update country ie"); + } +} + +#ifdef WLAN_MLD_AP_STA_CONNECT_SUPPORT +static void +hdd_hostapd_sap_fill_peer_ml_info(struct hdd_adapter *adapter, + struct station_info *sta_info, + uint8_t *peer_mac) +{ + bool is_mlo_vdev; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *sta_peer; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Failed to get link id, VDEV NULL"); + return; + } + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) + sta_info->link_id = wlan_vdev_get_link_id(vdev); + else + sta_info->link_id = -1; + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (!is_mlo_vdev) + return; + + sta_peer = wlan_objmgr_get_peer_by_mac(adapter->hdd_ctx->psoc, + peer_mac, WLAN_OSIF_ID); + + if (!sta_peer) { + hdd_err("Peer not found with MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return; + } + qdf_mem_copy(sta_info->mld_addr, wlan_peer_mlme_get_mldaddr(sta_peer), + ETH_ALEN); + + status = ucfg_mlme_peer_get_assoc_rsp_ies( + sta_peer, + &sta_info->assoc_resp_ies, + &sta_info->assoc_resp_ies_len); + wlan_objmgr_peer_release_ref(sta_peer, WLAN_OSIF_ID); +} +#elif defined(CFG80211_MLD_AP_STA_CONNECT_UPSTREAM_SUPPORT) +static void +hdd_hostapd_sap_fill_peer_ml_info(struct hdd_adapter *adapter, + struct station_info *sta_info, + uint8_t *peer_mac) +{ + bool is_mlo_vdev; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *sta_peer; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("Failed to get link id, VDEV NULL"); + return; + } + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (!is_mlo_vdev) { + sta_info->assoc_link_id = -1; + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + return; + } + + sta_info->assoc_link_id = wlan_vdev_get_link_id(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + sta_peer = wlan_objmgr_get_peer_by_mac(adapter->hdd_ctx->psoc, + peer_mac, WLAN_HDD_ID_OBJ_MGR); + + if (!sta_peer) { + hdd_err("Peer not found with MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + return; + } + qdf_mem_copy(sta_info->mld_addr, wlan_peer_mlme_get_mldaddr(sta_peer), + ETH_ALEN); + + status = ucfg_mlme_peer_get_assoc_rsp_ies( + sta_peer, + &sta_info->assoc_resp_ies, + &sta_info->assoc_resp_ies_len); + wlan_objmgr_peer_release_ref(sta_peer, WLAN_HDD_ID_OBJ_MGR); + sta_info->mlo_params_valid = true; +} +#else +static void +hdd_hostapd_sap_fill_peer_ml_info(struct hdd_adapter *adapter, + struct station_info *sta_info, + uint8_t *peer_mac) +{ +} +#endif + +static void +hdd_hostapd_check_channel_post_csa(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct hdd_ap_ctx *ap_ctx; + uint8_t sta_cnt, sap_cnt; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sap_context *sap_ctx; + bool ch_valid; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (!sap_ctx) { + hdd_err("sap ctx is null"); + return; + } + + /* + * During CSA, it might be possible that ch avoidance event to + * avoid the sap frequency is received. So, check after CSA, + * whether sap frequency is safe if not restart sap to a safe + * channel. + */ + ch_valid = + wlansap_validate_channel_post_csa(hdd_ctx->mac_handle, + sap_ctx); + if (ap_ctx->sap_context->csa_reason == + CSA_REASON_UNSAFE_CHANNEL || !ch_valid) + qdf_status = hdd_unsafe_channel_restart_sap(hdd_ctx); + else if (ap_ctx->sap_context->csa_reason == CSA_REASON_DCS) + qdf_status = hdd_dcs_hostapd_set_chan( + hdd_ctx, adapter->deflink->vdev_id, + ap_ctx->operating_chan_freq); + if (qdf_status == QDF_STATUS_E_PENDING) { + hdd_debug("csa is pending with reason %d", + ap_ctx->sap_context->csa_reason); + return; + } + + /* Added the sta cnt check as we don't support sta+sap+nan + * today. But this needs to be re-visited when we start + * supporting this combo. + */ + sta_cnt = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc, + PM_STA_MODE, + NULL); + if (!sta_cnt) + qdf_status = + policy_mgr_nan_sap_post_enable_conc_check(hdd_ctx->psoc); + if (qdf_status == QDF_STATUS_E_PENDING) { + hdd_debug("csa is pending by nan sap conc"); + return; + } + + qdf_status = policy_mgr_check_sap_go_force_scc( + hdd_ctx->psoc, adapter->deflink->vdev, + ap_ctx->sap_context->csa_reason); + if (qdf_status == QDF_STATUS_E_PENDING) { + hdd_debug("csa is pending by sap go force scc"); + return; + } + + sap_cnt = policy_mgr_get_beaconing_mode_count(hdd_ctx->psoc, NULL); + if (sap_cnt > 1) + policy_mgr_check_concurrent_intf_and_restart_sap( + hdd_ctx->psoc, + ap_ctx->sap_config.acs_cfg.acs_mode); +} + +QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, + void *context) +{ + struct hdd_adapter *adapter; + struct hdd_ap_ctx *ap_ctx; + struct hdd_hostapd_state *hostapd_state; + struct net_device *dev; + eSapHddEvent event_id; + union iwreq_data wrqu; + uint8_t *we_custom_event_generic = NULL; + int we_event = 0; + uint8_t sta_id; + QDF_STATUS qdf_status; + bool bAuthRequired = true; + char *unknownSTAEvent = NULL; + char *maxAssocExceededEvent = NULL; + uint8_t *we_custom_start_event = NULL; + char *startBssEvent; + struct hdd_context *hdd_ctx; + struct iw_michaelmicfailure msg; + uint8_t ignoreCAC = 0; + bool cac_state = false; + struct hdd_config *cfg = NULL; + struct wlan_dfs_info dfs_info; + struct hdd_adapter *con_sap_adapter; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSap_StationAssocReassocCompleteEvent *event; + tSap_StationSetKeyCompleteEvent *key_complete; + int ret = 0; + tSap_StationDisassocCompleteEvent *disassoc_comp; + struct hdd_station_info *stainfo, *cache_stainfo, *tmp = NULL; + mac_handle_t mac_handle; + struct sap_config *sap_config; + struct sap_context *sap_ctx = NULL; + uint8_t pdev_id; + bool notify_new_sta = true; + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr sta_addr = {0}; + qdf_freq_t dfs_freq; + struct wlan_hdd_link_info *link_info; + bool alt_pipe; + + dev = context; + if (!dev) { + hdd_err("context is null"); + return QDF_STATUS_E_FAILURE; + } + + adapter = netdev_priv(dev); + + if ((!adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_FAILURE; + } + + link_info = adapter->deflink; + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + if (!sap_event) { + hdd_err("sap_event is null"); + return QDF_STATUS_E_FAILURE; + } + + event_id = sap_event->sapHddEventCode; + memset(&wrqu, '\0', sizeof(wrqu)); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_FAILURE; + } + + cfg = hdd_ctx->config; + + if (!cfg) { + hdd_err("HDD config is null"); + return QDF_STATUS_E_FAILURE; + } + + mac_handle = hdd_ctx->mac_handle; + dfs_info.channel = wlan_reg_freq_to_chan( + hdd_ctx->pdev, ap_ctx->operating_chan_freq); + wlan_reg_get_cc_and_src(hdd_ctx->psoc, dfs_info.country_code); + sta_id = sap_event->sapevt.sapStartBssCompleteEvent.staId; + sap_config = &ap_ctx->sap_config; + + switch (event_id) { + case eSAP_START_BSS_EVENT: + hdd_debug("BSS status = %s, channel = %u, bc sta Id = %d", + sap_event->sapevt.sapStartBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS", + sap_event->sapevt.sapStartBssCompleteEvent. + operating_chan_freq, + sap_event->sapevt.sapStartBssCompleteEvent.staId); + ap_ctx->operating_chan_freq = + sap_event->sapevt.sapStartBssCompleteEvent + .operating_chan_freq; + + link_info->vdev_id = + sap_event->sapevt.sapStartBssCompleteEvent.sessionId; + sap_config->chan_freq = + sap_event->sapevt.sapStartBssCompleteEvent. + operating_chan_freq; + sap_config->ch_params.ch_width = + sap_event->sapevt.sapStartBssCompleteEvent.ch_width; + + hdd_nofl_info("AP started vid %d freq %d BW %d", + link_info->vdev_id, + ap_ctx->operating_chan_freq, + sap_config->ch_params.ch_width); + + hdd_cp_stats_cstats_sap_go_start_event(link_info, sap_event); + + sap_config->ch_params = ap_ctx->sap_context->ch_params; + sap_config->sec_ch_freq = ap_ctx->sap_context->sec_ch_freq; + + hostapd_state->qdf_status = + sap_event->sapevt.sapStartBssCompleteEvent.status; + + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + wlansap_get_dfs_ignore_cac(mac_handle, &ignoreCAC); + if (!policy_mgr_get_dfs_master_dynamic_enabled( + hdd_ctx->psoc, link_info->vdev_id)) + ignoreCAC = true; + + wlansap_get_dfs_cac_state(mac_handle, ap_ctx->sap_context, + &cac_state); + + /* DFS requirement: DO NOT transmit during CAC. */ + + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (!wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, + ap_ctx->operating_chan_freq) || + ignoreCAC || + hdd_ctx->dev_dfs_cac_status == DFS_CAC_ALREADY_DONE || + !cac_state) + ap_ctx->dfs_cac_block_tx = false; + else + ap_ctx->dfs_cac_block_tx = true; + + ucfg_ipa_set_dfs_cac_tx(hdd_ctx->pdev, + ap_ctx->dfs_cac_block_tx); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_dfs_cac_tx(vdev, ap_ctx->dfs_cac_block_tx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + hdd_debug("The value of dfs_cac_block_tx[%d] for ApCtx[%pK]:%d", + ap_ctx->dfs_cac_block_tx, ap_ctx, + link_info->vdev_id); + + if (hostapd_state->qdf_status) { + hdd_err("startbss event failed!!"); + /* + * Make sure to set the event before proceeding + * for error handling otherwise caller thread will + * wait till 10 secs and no other connection will + * go through before that. + */ + hostapd_state->bss_state = BSS_STOP; + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_bss_state_start(vdev, false); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + qdf_event_set(&hostapd_state->qdf_event); + goto stopbss; + } else { + sme_ch_avoid_update_req(mac_handle); + + ap_ctx->broadcast_sta_id = + sap_event->sapevt.sapStartBssCompleteEvent.staId; + + cdp_hl_fc_set_td_limit( + cds_get_context(QDF_MODULE_ID_SOC), + link_info->vdev_id, + ap_ctx->operating_chan_freq); + + hdd_register_tx_flow_control(adapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb, + hdd_tx_flow_control_is_pause); + + hdd_register_hl_netdev_fc_timer( + adapter, + hdd_tx_resume_timer_expired_handler); + + /* @@@ need wep logic here to set privacy bit */ + qdf_status = + hdd_softap_register_bc_sta(link_info, + ap_ctx->privacy); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("Failed to register BC STA %d", + qdf_status); + hdd_stop_bss_link(adapter); + } + } + + if (ucfg_ipa_is_enabled()) { + status = hdd_ipa_get_tx_pipe(hdd_ctx, link_info, + &alt_pipe); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("Failed to get alt pipe for vdev %d", + link_info->vdev_id); + alt_pipe = false; + } + + status = ucfg_ipa_wlan_evt( + hdd_ctx->pdev, + adapter->dev, + adapter->device_mode, + link_info->vdev_id, + WLAN_IPA_AP_CONNECT, + adapter->dev->dev_addr, + alt_pipe); + if (status) + hdd_err("WLAN_AP_CONNECT event failed"); + } + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); +#endif + hdd_hostapd_channel_prevent_suspend(adapter, + ap_ctx->operating_chan_freq, + &sap_config->ch_params); + + hostapd_state->bss_state = BSS_START; + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_bss_state_start(vdev, true); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + hdd_start_tsf_sync(adapter); + + hdd_hostapd_set_sap_key(adapter); + + /* Fill the params for sending IWEVCUSTOM Event + * with SOFTAP.enabled + */ + we_custom_start_event = + qdf_mem_malloc(HDD_MAX_CUSTOM_START_EVENT_SIZE); + if (!we_custom_start_event) + goto stopbss; + + startBssEvent = "SOFTAP.enabled"; + memset(we_custom_start_event, '\0', + sizeof(HDD_MAX_CUSTOM_START_EVENT_SIZE)); + memcpy(we_custom_start_event, startBssEvent, + strlen(startBssEvent)); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = strlen(startBssEvent); + we_event = IWEVCUSTOM; + we_custom_event_generic = we_custom_start_event; + wlan_hdd_set_tx_flow_info(); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + hdd_err("sap ctx is null"); + return QDF_STATUS_E_FAILURE; + } + + if (sap_ctx->is_chan_change_inprogress) { + hdd_debug("check for possible hw mode change"); + status = policy_mgr_set_hw_mode_on_channel_switch( + hdd_ctx->psoc, link_info->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("set hw mode change not done"); + } + + /* + * Enable wds source port learning on the dp vdev in AP mode + * when WDS feature is enabled. + */ + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (vdev) { + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_SAP_MODE) + hdd_wds_config_dp_repeater_mode(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + } + /* + * set this event at the very end because once this events + * get set, caller thread is waiting to do further processing. + * so once this event gets set, current worker thread might get + * pre-empted by caller thread. + */ + qdf_status = qdf_event_set(&hostapd_state->qdf_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("qdf_event_set failed! status: %d", qdf_status); + goto stopbss; + } + + wlan_hdd_apply_user_mcc_quota(adapter); + break; /* Event will be sent after Switch-Case stmt */ + + case eSAP_STOP_BSS_EVENT: + hdd_debug("BSS stop status = %s", + sap_event->sapevt.sapStopBssCompleteEvent. + status ? "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + hdd_cp_stats_cstats_sap_go_stop_event(link_info, sap_event); + + hdd_hostapd_channel_allow_suspend(adapter, + ap_ctx->operating_chan_freq, + &ap_ctx->sap_context->ch_params); + + /* Invalidate the channel info. */ + ap_ctx->operating_chan_freq = 0; + + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + + /* reset the dfs_cac_status and dfs_cac_block_tx flag only when + * the last BSS is stopped + */ + con_sap_adapter = hdd_get_con_sap_adapter(adapter, true); + if (!con_sap_adapter) { + ap_ctx->dfs_cac_block_tx = true; + hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_dfs_cac_tx(vdev, + ap_ctx->dfs_cac_block_tx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + } + hdd_nofl_info("Ap stopped vid %d reason=%d", + link_info->vdev_id, + ap_ctx->bss_stop_reason); + qdf_status = + policy_mgr_get_mac_id_by_session_id( + hdd_ctx->psoc, + link_info->vdev_id, + &pdev_id); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_medium_assess_stop_timer(pdev_id, hdd_ctx); + + /* clear the reason code in case BSS is stopped + * in another place + */ + ap_ctx->bss_stop_reason = BSS_STOP_REASON_INVALID; + ap_ctx->ap_active = false; + goto stopbss; + + case eSAP_DFS_CAC_START: + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_DFS_CAC_START_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + hdd_ctx->dev_dfs_cac_status = DFS_CAC_IN_PROGRESS; + + hdd_cp_stats_cstats_log_sap_go_dfs_event(link_info, + eSAP_DFS_CAC_START); + + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(hdd_ctx, eSAP_DFS_CAC_START, + dfs_info, &adapter->wdev)) { + hdd_err("Unable to indicate CAC start NL event"); + } else { + hdd_debug("Sent CAC start to user space"); + } + + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + hdd_stop_tsf_sync(adapter); + break; + case eSAP_DFS_CAC_INTERRUPTED: + /* + * The CAC timer did not run completely and a radar was detected + * during the CAC time. This new state will keep the tx path + * blocked since we do not want any transmission on the DFS + * channel. CAC end will only be reported here since the user + * space applications are waiting on CAC end for their state + * management. + */ + hdd_cp_stats_cstats_log_sap_go_dfs_event + (link_info, eSAP_DFS_CAC_INTERRUPTED); + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(hdd_ctx, eSAP_DFS_CAC_END, + dfs_info, &adapter->wdev)) { + hdd_err("Unable to indicate CAC end (interrupted) event"); + } else { + hdd_debug("Sent CAC end (interrupted) to user space"); + } + dfs_freq = wlan_reg_chan_band_to_freq(hdd_ctx->pdev, + dfs_info.channel, + BIT(REG_BAND_5G)); + hdd_son_deliver_cac_status_event(adapter, dfs_freq, true); + break; + case eSAP_DFS_CAC_END: + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_DFS_CAC_END_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + ap_ctx->dfs_cac_block_tx = false; + ucfg_ipa_set_dfs_cac_tx(hdd_ctx->pdev, + ap_ctx->dfs_cac_block_tx); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_dfs_cac_tx(vdev, + ap_ctx->dfs_cac_block_tx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + hdd_cp_stats_cstats_log_sap_go_dfs_event(link_info, + eSAP_DFS_CAC_END); + + hdd_ctx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(hdd_ctx, eSAP_DFS_CAC_END, + dfs_info, &adapter->wdev)) { + hdd_err("Unable to indicate CAC end NL event"); + } else { + hdd_debug("Sent CAC end to user space"); + } + dfs_freq = wlan_reg_chan_band_to_freq(hdd_ctx->pdev, + dfs_info.channel, + BIT(REG_BAND_5G)); + hdd_son_deliver_cac_status_event(adapter, dfs_freq, false); + break; + case eSAP_DFS_RADAR_DETECT: + { + int i; + + hdd_cp_stats_cstats_log_sap_go_dfs_event(link_info, + eSAP_DFS_RADAR_DETECT); + hdd_dfs_indicate_radar(hdd_ctx); + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_DFS_RADAR_DETECT_IND, + &dfs_info, + sizeof(struct wlan_dfs_info)); + hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + for (i = 0; i < sap_config->channel_info_count; i++) { + if (sap_config->channel_info[i].ieee_chan_number + == dfs_info.channel) + sap_config->channel_info[i].flags |= + IEEE80211_CHAN_RADAR_DFS; + } + if (QDF_STATUS_SUCCESS != + hdd_send_radar_event(hdd_ctx, eSAP_DFS_RADAR_DETECT, + dfs_info, &adapter->wdev)) { + hdd_err("Unable to indicate Radar detect NL event"); + } else { + hdd_debug("Sent radar detected to user space"); + } + dfs_freq = wlan_reg_chan_band_to_freq(hdd_ctx->pdev, + dfs_info.channel, + BIT(REG_BAND_5G)); + hdd_son_deliver_cac_status_event(adapter, dfs_freq, true); + break; + } + + case eSAP_DFS_NO_AVAILABLE_CHANNEL: + wlan_hdd_send_svc_nlink_msg + (hdd_ctx->radio_index, + WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND, &dfs_info, + sizeof(struct wlan_dfs_info)); + break; + + case eSAP_STA_SET_KEY_EVENT: + /* TODO: + * forward the message to hostapd once implementation + * is done for now just print + */ + key_complete = &sap_event->sapevt.sapStationSetKeyCompleteEvent; + hdd_debug("SET Key: configured status = %s", + key_complete->status ? + "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + if (QDF_IS_STATUS_SUCCESS(key_complete->status)) { + hdd_softap_change_sta_state(adapter, + &key_complete->peerMacAddr, + OL_TXRX_PEER_STATE_AUTH); + status = wlan_hdd_send_sta_authorized_event( + adapter, hdd_ctx, + &key_complete->peerMacAddr); + + } + return QDF_STATUS_SUCCESS; + case eSAP_STA_MIC_FAILURE_EVENT: + { + memset(&msg, '\0', sizeof(msg)); + msg.src_addr.sa_family = ARPHRD_ETHER; + memcpy(msg.src_addr.sa_data, + &sap_event->sapevt.sapStationMICFailureEvent. + staMac, QDF_MAC_ADDR_SIZE); + hdd_debug("MIC MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(msg.src_addr.sa_data)); + if (sap_event->sapevt.sapStationMICFailureEvent. + multicast == true) + msg.flags = IW_MICFAILURE_GROUP; + else + msg.flags = IW_MICFAILURE_PAIRWISE; + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = sizeof(msg); + we_event = IWEVMICHAELMICFAILURE; + we_custom_event_generic = (uint8_t *) &msg; + } + /* inform mic failure to nl80211 */ + cfg80211_michael_mic_failure(dev, + sap_event-> + sapevt.sapStationMICFailureEvent. + staMac.bytes, + ((sap_event->sapevt. + sapStationMICFailureEvent. + multicast == + true) ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE), + sap_event->sapevt. + sapStationMICFailureEvent.keyId, + sap_event->sapevt. + sapStationMICFailureEvent.TSC, + GFP_KERNEL); + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + event = &sap_event->sapevt.sapStationAssocReassocCompleteEvent; + hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event + (link_info, sap_event); + /* Reset scan reject params on assoc */ + hdd_init_scan_reject_params(hdd_ctx); + if (eSAP_STATUS_FAILURE == event->status) { + hdd_info("assoc failure: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wrqu.addr.sa_data)); + hdd_place_marker(adapter, "CLIENT ASSOC FAILURE", + wrqu.addr.sa_data); + break; + } + + hdd_hostapd_apply_action_oui(hdd_ctx, adapter, event); + + wrqu.addr.sa_family = ARPHRD_ETHER; + memcpy(wrqu.addr.sa_data, + &event->staMac, QDF_MAC_ADDR_SIZE); + hdd_info("associated " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wrqu.addr.sa_data)); + hdd_place_marker(adapter, "CLIENT ASSOCIATED", + wrqu.addr.sa_data); + we_event = IWEVREGISTERED; + + if ((eCSR_ENCRYPT_TYPE_NONE == ap_ctx->encryption_type) || + (eCSR_ENCRYPT_TYPE_WEP40_STATICKEY == + ap_ctx->encryption_type) + || (eCSR_ENCRYPT_TYPE_WEP104_STATICKEY == + ap_ctx->encryption_type)) { + bAuthRequired = false; + } + + qdf_status = hdd_softap_register_sta(link_info, + bAuthRequired, + ap_ctx->privacy, + (struct qdf_mac_addr *) + wrqu.addr.sa_data, + event); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_fill_station_info(adapter, event); + else + hdd_err("Failed to register STA %d " + QDF_MAC_ADDR_FMT, qdf_status, + QDF_MAC_ADDR_REF(wrqu.addr.sa_data)); + + sta_id = event->staId; + + if (ucfg_ipa_is_enabled()) { + vdev = link_info->vdev; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + !qdf_is_macaddr_zero(&event->sta_mld)) + qdf_copy_macaddr(&sta_addr, &event->sta_mld); + else + qdf_copy_macaddr(&sta_addr, &event->staMac); + + status = ucfg_ipa_wlan_evt(hdd_ctx->pdev, + adapter->dev, + adapter->device_mode, + link_info->vdev_id, + WLAN_IPA_CLIENT_CONNECT_EX, + (const uint8_t *) + &sta_addr.bytes[0], + false); + if (status) + hdd_err("WLAN_CLIENT_CONNECT_EX event failed"); + } + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + link_info->vdev_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_ASSOC)); + + /* start timer in sap/p2p_go */ + if (ap_ctx->ap_active == false) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_bus_bw_compute_prev_txrx_stats(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + ucfg_dp_bus_bw_compute_timer_start(hdd_ctx->psoc); + } + ap_ctx->ap_active = true; + + hdd_hostapd_update_beacon_country_ie(adapter); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, false); +#endif + cds_host_diag_log_work(&hdd_ctx->sap_wake_lock, + HDD_SAP_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_SAP); + qdf_wake_lock_timeout_acquire(&hdd_ctx->sap_wake_lock, + HDD_SAP_WAKE_LOCK_DURATION); + { + struct station_info *sta_info; + uint32_t ies_len = event->ies_len; + + sta_info = qdf_mem_malloc(sizeof(*sta_info)); + if (!sta_info) + return QDF_STATUS_E_FAILURE; + + sta_info->assoc_req_ies = event->ies; + sta_info->assoc_req_ies_len = ies_len; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) + /* + * After Kernel 4.0, it's no longer need to set + * STATION_INFO_ASSOC_REQ_IES flag, as it + * changed to use assoc_req_ies_len length to + * check the existence of request IE. + */ + sta_info->filled |= STATION_INFO_ASSOC_REQ_IES; +#endif + /* For ML clients need to fill assoc resp IEs + * and MLD address. + * For Legacy clients MLD address will be + * NULL MAC address. + */ + hdd_hostapd_sap_fill_peer_ml_info(adapter, sta_info, + event->staMac.bytes); + + if (notify_new_sta) + cfg80211_new_sta(dev, + (const u8 *)&event-> + staMac.bytes[0], + sta_info, GFP_KERNEL); + + if (adapter->device_mode == QDF_SAP_MODE && + ucfg_mlme_get_wds_mode(hdd_ctx->psoc)) + hdd_softap_ind_l2_update(adapter, + &event->staMac); + qdf_mem_free(sta_info); + } + /* Lets abort scan to ensure smooth authentication for client */ + if (ucfg_scan_get_vdev_status(link_info->vdev) != + SCAN_NOT_IN_PROGRESS) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + link_info->vdev_id, + INVALID_SCAN_ID, false); + } + if (adapter->device_mode == QDF_P2P_GO_MODE) { + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_app( + &event->staMac, + ePeerConnected, + event->timingMeasCap, + link_info->vdev_id, + &event->chan_info, + adapter->device_mode); + } + + hdd_green_ap_add_sta(hdd_ctx); + hdd_son_deliver_assoc_disassoc_event(adapter, + event->staMac, + event->status, + ALD_ASSOC_EVENT); + break; + + case eSAP_STA_DISASSOC_EVENT: + disassoc_comp = + &sap_event->sapevt.sapStationDisassocCompleteEvent; + memcpy(wrqu.addr.sa_data, + &disassoc_comp->staMac, QDF_MAC_ADDR_SIZE); + + /* Reset scan reject params on disconnect */ + hdd_init_scan_reject_params(hdd_ctx); + cache_stainfo = hdd_get_sta_info_by_mac( + &adapter->cache_sta_info_list, + disassoc_comp->staMac.bytes, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + if (cache_stainfo) { + /* Cache the disassoc info */ + cache_stainfo->rssi = disassoc_comp->rssi; + cache_stainfo->tx_rate = disassoc_comp->tx_rate; + cache_stainfo->rx_rate = disassoc_comp->rx_rate; + cache_stainfo->rx_mc_bc_cnt = + disassoc_comp->rx_mc_bc_cnt; + cache_stainfo->rx_retry_cnt = + disassoc_comp->rx_retry_cnt; + cache_stainfo->reason_code = disassoc_comp->reason_code; + cache_stainfo->disassoc_ts = qdf_system_ticks(); + hdd_debug("Cache_stainfo rssi %d txrate %d rxrate %d reason_code %d", + cache_stainfo->rssi, + cache_stainfo->tx_rate, + cache_stainfo->rx_rate, + cache_stainfo->reason_code); + hdd_put_sta_info_ref(&adapter->cache_sta_info_list, + &cache_stainfo, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + } + hdd_nofl_info("SAP disassociated " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wrqu.addr.sa_data)); + hdd_place_marker(adapter, "CLIENT DISASSOCIATED FROM SAP", + wrqu.addr.sa_data); + + hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(link_info, + sap_event); + + qdf_status = qdf_event_set(&hostapd_state->qdf_sta_disassoc_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Station Deauth event Set failed"); + + if (sap_event->sapevt.sapStationDisassocCompleteEvent.reason == + eSAP_USR_INITATED_DISASSOC) + hdd_debug(" User initiated disassociation"); + else + hdd_debug(" MAC initiated disassociation"); + we_event = IWEVEXPIRED; + + DPTRACE(qdf_dp_trace_mgmt_pkt(QDF_DP_TRACE_MGMT_PACKET_RECORD, + link_info->vdev_id, + QDF_TRACE_DEFAULT_PDEV_ID, + QDF_PROTO_TYPE_MGMT, QDF_PROTO_MGMT_DISASSOC)); + + stainfo = hdd_get_sta_info_by_mac( + &adapter->sta_info_list, + disassoc_comp->staMac.bytes, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + if (!stainfo) { + hdd_err("Failed to find the right station"); + return QDF_STATUS_E_INVAL; + } + + if (wlan_vdev_mlme_is_mlo_vdev(link_info->vdev) && + !qdf_is_macaddr_zero(&stainfo->mld_addr)) { + qdf_copy_macaddr(&sta_addr, &stainfo->mld_addr); + } else { + /* Copy legacy MAC address on + * non-ML type client disassoc. + */ + qdf_copy_macaddr(&sta_addr, &disassoc_comp->staMac); + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_update_dhcp_state_on_disassoc(vdev, + &disassoc_comp->staMac); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + hdd_softap_deregister_sta(adapter, &stainfo); + hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + + ap_ctx->ap_active = false; + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, stainfo, + tmp, STA_INFO_HOSTAPD_SAP_EVENT_CB) { + if (!qdf_is_macaddr_broadcast( + &stainfo->sta_mac)) { + ap_ctx->ap_active = true; + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &stainfo, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + break; + } + hdd_put_sta_info_ref(&adapter->sta_info_list, + &stainfo, true, + STA_INFO_HOSTAPD_SAP_EVENT_CB); + } + + hdd_hostapd_update_beacon_country_ie(adapter); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); +#endif + + cds_host_diag_log_work(&hdd_ctx->sap_wake_lock, + HDD_SAP_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_SAP); + qdf_wake_lock_timeout_acquire(&hdd_ctx->sap_wake_lock, + HDD_SAP_CLIENT_DISCONNECT_WAKE_LOCK_DURATION); + + /* + * Don't indicate delete station event if P2P GO and + * SSR in progress. Since supplicant will change mode + * fail and down during this time. + */ + + if ((adapter->device_mode != QDF_P2P_GO_MODE) || + (!cds_is_driver_recovering())) { + cfg80211_del_sta(dev, + (const u8 *)&sta_addr.bytes[0], + GFP_KERNEL); + hdd_debug("indicate sta deletion event"); + } + + /* Update the beacon Interval if it is P2P GO */ + qdf_status = policy_mgr_change_mcc_go_beacon_interval( + hdd_ctx->psoc, link_info->vdev_id, + adapter->device_mode); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Failed to update Beacon interval status: %d", + qdf_status); + } + if (adapter->device_mode == QDF_P2P_GO_MODE) { + /* send peer status indication to oem app */ + hdd_send_peer_status_ind_to_app(&sap_event->sapevt. + sapStationDisassocCompleteEvent. + staMac, ePeerDisconnected, + 0, + link_info->vdev_id, + NULL, + adapter->device_mode); + } + + /*stop timer in sap/p2p_go */ + if (ap_ctx->ap_active == false) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + ucfg_dp_bus_bw_compute_timer_try_stop(hdd_ctx->psoc); + } + hdd_son_deliver_assoc_disassoc_event(adapter, + disassoc_comp->staMac, + disassoc_comp->reason_code, + ALD_DISASSOC_EVENT); + hdd_green_ap_del_sta(hdd_ctx); + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + hdd_debug("WPS PBC probe req"); + return QDF_STATUS_SUCCESS; + + case eSAP_UNKNOWN_STA_JOIN: + unknownSTAEvent = qdf_mem_malloc(IW_CUSTOM_MAX + 1); + if (!unknownSTAEvent) + return QDF_STATUS_E_NOMEM; + + snprintf(unknownSTAEvent, IW_CUSTOM_MAX, + "JOIN_UNKNOWN_STA-"QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sap_event->sapevt.sapUnknownSTAJoin.macaddr.bytes)); + we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */ + wrqu.data.pointer = unknownSTAEvent; + wrqu.data.length = strlen(unknownSTAEvent); + we_custom_event_generic = (uint8_t *) unknownSTAEvent; + hdd_err("%s", unknownSTAEvent); + break; + + case eSAP_MAX_ASSOC_EXCEEDED: + maxAssocExceededEvent = qdf_mem_malloc(IW_CUSTOM_MAX + 1); + if (!maxAssocExceededEvent) + return QDF_STATUS_E_NOMEM; + + snprintf(maxAssocExceededEvent, IW_CUSTOM_MAX, + "Peer "QDF_MAC_ADDR_FMT" denied" + " assoc due to Maximum Mobile Hotspot connections reached. Please disconnect" + " one or more devices to enable the new device connection", + QDF_MAC_ADDR_REF(sap_event->sapevt.sapMaxAssocExceeded.macaddr.bytes)); + we_event = IWEVCUSTOM; /* Discovered a new node (AP mode). */ + wrqu.data.pointer = maxAssocExceededEvent; + wrqu.data.length = strlen(maxAssocExceededEvent); + we_custom_event_generic = (uint8_t *) maxAssocExceededEvent; + hdd_debug("%s", maxAssocExceededEvent); + break; + case eSAP_STA_ASSOC_IND: + if (sap_event->sapevt.sapAssocIndication.owe_ie) { + hdd_send_update_owe_info_event(adapter, + sap_event->sapevt.sapAssocIndication.staMac.bytes, + sap_event->sapevt.sapAssocIndication.owe_ie, + sap_event->sapevt.sapAssocIndication.owe_ie_len); + qdf_mem_free( + sap_event->sapevt.sapAssocIndication.owe_ie); + sap_event->sapevt.sapAssocIndication.owe_ie = NULL; + sap_event->sapevt.sapAssocIndication.owe_ie_len = 0; + } + return QDF_STATUS_SUCCESS; + + case eSAP_DISCONNECT_ALL_P2P_CLIENT: + hdd_clear_all_sta(adapter); + return QDF_STATUS_SUCCESS; + + case eSAP_MAC_TRIG_STOP_BSS_EVENT: + ret = hdd_stop_bss_link(adapter); + if (ret) + hdd_warn("hdd_stop_bss_link failed %d", ret); + return QDF_STATUS_SUCCESS; + + case eSAP_CHANNEL_CHANGE_EVENT: + if (hostapd_state->bss_state != BSS_STOP) { + /* Allow suspend for old channel */ + hdd_hostapd_channel_allow_suspend(adapter, + ap_ctx->sap_context->freq_before_ch_switch, + &ap_ctx->sap_context->ch_params_before_ch_switch); + /* Prevent suspend for new channel */ + hdd_hostapd_channel_prevent_suspend(adapter, + sap_event->sapevt.sap_ch_selected.pri_ch_freq, + &ap_ctx->sap_context->ch_params); + } + /* SME/PE is already updated for new operation + * channel. So update HDD layer also here. This + * resolves issue in AP-AP mode where AP1 channel is + * changed due to RADAR then CAC is going on and + * START_BSS on new channel has not come to HDD. At + * this case if AP2 is started it needs current + * operation channel for MCC DFS restriction + */ + ap_ctx->operating_chan_freq = + sap_event->sapevt.sap_ch_selected.pri_ch_freq; + ap_ctx->sap_config.acs_cfg.pri_ch_freq = + sap_event->sapevt.sap_ch_selected.pri_ch_freq; + ap_ctx->sap_config.acs_cfg.ht_sec_ch_freq = + sap_event->sapevt.sap_ch_selected.ht_sec_ch_freq; + ap_ctx->sap_config.acs_cfg.vht_seg0_center_ch_freq = + sap_event->sapevt.sap_ch_selected.vht_seg0_center_ch_freq; + ap_ctx->sap_config.acs_cfg.vht_seg1_center_ch_freq = + sap_event->sapevt.sap_ch_selected.vht_seg1_center_ch_freq; + ap_ctx->sap_config.acs_cfg.ch_width = + sap_event->sapevt.sap_ch_selected.ch_width; + + cdp_hl_fc_set_td_limit(cds_get_context(QDF_MODULE_ID_SOC), + link_info->vdev_id, + ap_ctx->operating_chan_freq); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + hdd_err("sap ctx is null"); + return QDF_STATUS_E_FAILURE; + } + + if (sap_ctx->is_chan_change_inprogress) { + hdd_debug("check for possible hw mode change"); + status = policy_mgr_set_hw_mode_on_channel_switch( + hdd_ctx->psoc, + link_info->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("set hw mode change not done"); + } + + hdd_son_deliver_chan_change_event( + adapter, sap_event->sapevt.sap_ch_selected.pri_ch_freq); + return hdd_hostapd_chan_change(link_info, sap_event); + case eSAP_ACS_SCAN_SUCCESS_EVENT: + return hdd_handle_acs_scan_event(sap_event, adapter); + + case eSAP_ACS_CHANNEL_SELECTED: + hdd_son_deliver_acs_complete_event(adapter); + ap_ctx->sap_config.acs_cfg.pri_ch_freq = + sap_event->sapevt.sap_ch_selected.pri_ch_freq; + ap_ctx->sap_config.acs_cfg.ht_sec_ch_freq = + sap_event->sapevt.sap_ch_selected.ht_sec_ch_freq; + ap_ctx->sap_config.acs_cfg.vht_seg0_center_ch_freq = + sap_event->sapevt.sap_ch_selected.vht_seg0_center_ch_freq; + ap_ctx->sap_config.acs_cfg.vht_seg1_center_ch_freq = + sap_event->sapevt.sap_ch_selected.vht_seg1_center_ch_freq; + ap_ctx->sap_config.acs_cfg.ch_width = + sap_event->sapevt.sap_ch_selected.ch_width; + hdd_nofl_info("ACS Completed vid %d freq %d BW %d", + link_info->vdev_id, + ap_ctx->sap_config.acs_cfg.pri_ch_freq, + ap_ctx->sap_config.acs_cfg.ch_width); + + if (qdf_atomic_read(&ap_ctx->acs_in_progress) && + test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + hdd_dcs_chan_select_complete(adapter); + } else { + wlan_hdd_cfg80211_acs_ch_select_evt(link_info, true); + wlansap_dcs_set_wlan_interference_mitigation_on_band( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + &ap_ctx->sap_config); + } + + return QDF_STATUS_SUCCESS; + case eSAP_ECSA_CHANGE_CHAN_IND: + hdd_debug("Channel change indication from peer for channel freq %d", + sap_event->sapevt.sap_chan_cng_ind.new_chan_freq); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + link_info->vdev_id, + CSA_REASON_PEER_ACTION_FRAME); + if (hdd_softap_set_channel_change(dev, + sap_event->sapevt.sap_chan_cng_ind.new_chan_freq, + CH_WIDTH_MAX, false)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; + + case eSAP_DFS_NEXT_CHANNEL_REQ: + hdd_debug("Sending next channel query to userspace"); + hdd_update_acs_timer_reason(adapter, + QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS); + return QDF_STATUS_SUCCESS; + + case eSAP_STOP_BSS_DUE_TO_NO_CHNL: + hdd_debug("Stop sap session[%d]", + link_info->vdev_id); + schedule_work(&adapter->sap_stop_bss_work); + return QDF_STATUS_SUCCESS; + + case eSAP_CHANNEL_CHANGE_RESP: + /* + * Set the ch_switch_in_progress flag to zero and also enable + * roaming once channel change process (success/failure) + * is completed + */ + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + policy_mgr_set_chan_switch_complete_evt(hdd_ctx->psoc); + wlan_hdd_set_roaming_state(link_info, RSO_SAP_CHANNEL_CHANGE, + true); + + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (!wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, + ap_ctx->operating_chan_freq)) { + ap_ctx->dfs_cac_block_tx = false; + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_dfs_cac_tx(vdev, + ap_ctx->dfs_cac_block_tx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + } + + /* Check any other sap need restart */ + hdd_hostapd_check_channel_post_csa(hdd_ctx, adapter); + + qdf_status = qdf_event_set(&hostapd_state->qdf_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("qdf_event_set failed! status: %d", + qdf_status); + if (sap_event->sapevt.sap_chan_cng_rsp.ch_change_rsp_status != + eSAP_STATUS_SUCCESS) { + /* This is much more serious issue, we have to vacate + * the channel due to the presence of radar or coex + * but our channel change failed, stop the BSS operation + * completely and inform hostapd + */ + hdd_debug("SAP[vdev%d] channel switch fail, will stop", + link_info->vdev_id); + schedule_work(&adapter->sap_stop_bss_work); + return QDF_STATUS_SUCCESS; + } else { + return hdd_hostapd_chan_change(link_info, sap_event); + } + default: + hdd_debug("SAP message is not handled"); + goto stopbss; + return QDF_STATUS_SUCCESS; + } + + hdd_wext_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + qdf_mem_free(we_custom_start_event); + qdf_mem_free(unknownSTAEvent); + qdf_mem_free(maxAssocExceededEvent); + + return QDF_STATUS_SUCCESS; + +stopbss: + { + uint8_t *we_custom_event; + char *stopBssEvent = "STOP-BSS.response"; /* 17 */ + int event_len = strlen(stopBssEvent); + + hdd_debug("BSS stop status = %s", + sap_event->sapevt.sapStopBssCompleteEvent.status ? + "eSAP_STATUS_FAILURE" : "eSAP_STATUS_SUCCESS"); + + /* Change the BSS state now since, as we are shutting + * things down, we don't want interfaces to become + * re-enabled + */ + hostapd_state->bss_state = BSS_STOP; + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_set_bss_state_start(vdev, false); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + hdd_stop_tsf_sync(adapter); + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wlan_hdd_auto_shutdown_enable(hdd_ctx, true); +#endif + + /* Stop the pkts from n/w stack as we are going to free all of + * the TX WMM queues for all STAID's + */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* reclaim all resources allocated to the BSS */ + qdf_status = hdd_softap_stop_bss(adapter); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_debug("hdd_softap_stop_bss failed %d", + qdf_status); + if (ucfg_ipa_is_enabled()) { + ucfg_ipa_uc_disconnect_ap(hdd_ctx->pdev, + adapter->dev); + ucfg_ipa_cleanup_dev_iface(hdd_ctx->pdev, + adapter->dev, + link_info->vdev_id); + } + } + + we_custom_event = + qdf_mem_malloc(HDD_MAX_CUSTOM_START_EVENT_SIZE); + if (!we_custom_event) + return QDF_STATUS_E_NOMEM; + + /* notify userspace that the BSS has stopped */ + memset(we_custom_event, '\0', + sizeof(HDD_MAX_CUSTOM_START_EVENT_SIZE)); + memcpy(we_custom_event, stopBssEvent, event_len); + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = event_len; + we_event = IWEVCUSTOM; + we_custom_event_generic = we_custom_event; + hdd_wext_send_event(dev, we_event, &wrqu, + (char *)we_custom_event_generic); + + qdf_mem_free(we_custom_start_event); + qdf_mem_free(unknownSTAEvent); + qdf_mem_free(maxAssocExceededEvent); + qdf_mem_free(we_custom_event); + + /* once the event is set, structure dev/adapter should + * not be touched since they are now subject to being deleted + * by another thread + */ + if (eSAP_STOP_BSS_EVENT == event_id) { + qdf_event_set(&hostapd_state->qdf_stop_bss_event); + ucfg_dp_bus_bw_compute_timer_try_stop(hdd_ctx->psoc); + } + + wlan_hdd_set_tx_flow_info(); + } + return QDF_STATUS_SUCCESS; +} + +static int hdd_softap_unpack_ie(mac_handle_t mac_handle, + eCsrEncryptionType *encrypt_type, + eCsrEncryptionType *mc_encrypt_type, + tCsrAuthList *akm_list, + bool *mfp_capable, + bool *mfp_required, + uint16_t gen_ie_len, uint8_t *gen_ie) +{ + uint32_t ret; + uint8_t *rsn_ie; + uint16_t rsn_ie_len, i; + tDot11fIERSN dot11_rsn_ie = {0}; + tDot11fIEWPA dot11_wpa_ie = {0}; + tDot11fIEWAPI dot11_wapi_ie = {0}; + + if (!mac_handle) { + hdd_err("NULL mac Handle"); + return -EINVAL; + } + /* Validity checks */ + if ((gen_ie_len < QDF_MIN(DOT11F_IE_RSN_MIN_LEN, DOT11F_IE_WPA_MIN_LEN)) + || (gen_ie_len > + QDF_MAX(DOT11F_IE_RSN_MAX_LEN, DOT11F_IE_WPA_MAX_LEN))) + return -EINVAL; + /* Type check */ + if (gen_ie[0] == DOT11F_EID_RSN) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_RSN_MIN_LEN) || + (gen_ie_len > DOT11F_IE_RSN_MAX_LEN)) { + return QDF_STATUS_E_FAILURE; + } + /* Skip past the EID byte and length byte */ + rsn_ie = gen_ie + 2; + rsn_ie_len = gen_ie_len - 2; + /* Unpack the RSN IE */ + memset(&dot11_rsn_ie, 0, sizeof(tDot11fIERSN)); + ret = sme_unpack_rsn_ie(mac_handle, rsn_ie, rsn_ie_len, + &dot11_rsn_ie, false); + if (!DOT11F_SUCCEEDED(ret)) { + hdd_err("unpack failed, 0x%x", ret); + return -EINVAL; + } + /* Copy out the encryption and authentication types */ + hdd_debug("pairwise cipher count: %d akm count:%d", + dot11_rsn_ie.pwise_cipher_suite_count, + dot11_rsn_ie.akm_suite_cnt); + /* + * Translate akms in akm suite + */ + for (i = 0; i < dot11_rsn_ie.akm_suite_cnt; i++) + akm_list->authType[i] = + hdd_translate_rsn_to_csr_auth_type( + dot11_rsn_ie.akm_suite[i]); + akm_list->numEntries = dot11_rsn_ie.akm_suite_cnt; + /* dot11_rsn_ie.pwise_cipher_suite_count */ + *encrypt_type = + hdd_translate_rsn_to_csr_encryption_type(dot11_rsn_ie. + pwise_cipher_suites[0]); + /* dot11_rsn_ie.gp_cipher_suite_count */ + *mc_encrypt_type = + hdd_translate_rsn_to_csr_encryption_type(dot11_rsn_ie. + gp_cipher_suite); + /* Set the PMKSA ID Cache for this interface */ + *mfp_capable = 0 != (dot11_rsn_ie.RSN_Cap[0] & 0x80); + *mfp_required = 0 != (dot11_rsn_ie.RSN_Cap[0] & 0x40); + } else if (gen_ie[0] == DOT11F_EID_WPA) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_WPA_MIN_LEN) || + (gen_ie_len > DOT11F_IE_WPA_MAX_LEN)) { + return QDF_STATUS_E_FAILURE; + } + /* Skip past the EID byte and length byte and 4 byte WiFi OUI */ + rsn_ie = gen_ie + 2 + 4; + rsn_ie_len = gen_ie_len - (2 + 4); + /* Unpack the WPA IE */ + memset(&dot11_wpa_ie, 0, sizeof(tDot11fIEWPA)); + ret = dot11f_unpack_ie_wpa(MAC_CONTEXT(mac_handle), + rsn_ie, rsn_ie_len, + &dot11_wpa_ie, false); + if (!DOT11F_SUCCEEDED(ret)) { + hdd_err("unpack failed, 0x%x", ret); + return -EINVAL; + } + /* Copy out the encryption and authentication types */ + hdd_debug("WPA unicast cipher suite count: %d akm count: %d", + dot11_wpa_ie.unicast_cipher_count, + dot11_wpa_ie.auth_suite_count); + /* + * Translate akms in akm suite + */ + for (i = 0; i < dot11_wpa_ie.auth_suite_count; i++) + akm_list->authType[i] = + hdd_translate_wpa_to_csr_auth_type( + dot11_wpa_ie.auth_suites[i]); + akm_list->numEntries = dot11_wpa_ie.auth_suite_count; + /* dot11_wpa_ie.unicast_cipher_count */ + *encrypt_type = + hdd_translate_wpa_to_csr_encryption_type(dot11_wpa_ie. + unicast_ciphers[0]); + /* dot11_wpa_ie.unicast_cipher_count */ + *mc_encrypt_type = + hdd_translate_wpa_to_csr_encryption_type(dot11_wpa_ie. + multicast_cipher); + *mfp_capable = false; + *mfp_required = false; + } else if (gen_ie[0] == DOT11F_EID_WAPI) { + /* Validity checks */ + if ((gen_ie_len < DOT11F_IE_WAPI_MIN_LEN) || + (gen_ie_len > DOT11F_IE_WAPI_MAX_LEN)) + return QDF_STATUS_E_FAILURE; + + /* Skip past the EID byte and length byte */ + rsn_ie = gen_ie + 2; + rsn_ie_len = gen_ie_len - 2; + /* Unpack the WAPI IE */ + memset(&dot11_wapi_ie, 0, sizeof(tDot11fIEWPA)); + ret = dot11f_unpack_ie_wapi(MAC_CONTEXT(mac_handle), + rsn_ie, rsn_ie_len, + &dot11_wapi_ie, false); + if (!DOT11F_SUCCEEDED(ret)) { + hdd_err("unpack failed, 0x%x", ret); + return -EINVAL; + } + /* Copy out the encryption and authentication types */ + hdd_debug("WAPI unicast cipher suite count: %d akm count: %d", + dot11_wapi_ie.unicast_cipher_suite_count, + dot11_wapi_ie.akm_suite_count); + /* + * Translate akms in akm suite + */ + for (i = 0; i < dot11_wapi_ie.akm_suite_count; i++) + akm_list->authType[i] = + hdd_translate_wapi_to_csr_auth_type( + dot11_wapi_ie.akm_suites[i]); + + akm_list->numEntries = dot11_wapi_ie.akm_suite_count; + /* dot11_wapi_ie.akm_suite_count */ + *encrypt_type = + hdd_translate_wapi_to_csr_encryption_type( + dot11_wapi_ie.unicast_cipher_suites[0]); + /* dot11_wapi_ie.unicast_cipher_count */ + *mc_encrypt_type = + hdd_translate_wapi_to_csr_encryption_type( + dot11_wapi_ie.multicast_cipher_suite); + *mfp_capable = false; + *mfp_required = false; + } else { + hdd_err("gen_ie[0]: %d", gen_ie[0]); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +bool hdd_is_any_sta_connecting(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + struct hdd_station_ctx *sta_ctx; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_ANY_STA_CONNECTING; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return false; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) + goto next_adapter; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!hdd_cm_is_connecting(link_info)) + continue; + + hdd_debug("vdev_id %d: connecting", link_info->vdev_id); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, dbgid); + return true; + } +next_adapter: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return false; +} + +int hdd_softap_set_channel_change(struct net_device *dev, int target_chan_freq, + enum phy_ch_width target_bw, bool forced) +{ + QDF_STATUS status; + int ret = 0; + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_beacon_data *beacon = adapter->deflink->session.ap.beacon; + struct hdd_context *hdd_ctx = NULL; + struct hdd_adapter *sta_adapter; + struct hdd_station_ctx *sta_ctx; + struct sap_context *sap_ctx; + struct hdd_ap_ctx *ap_ctx; + uint8_t conc_rule1 = 0; + uint8_t sta_sap_scc_on_dfs_chnl; + bool is_p2p_go_session = false; + struct wlan_objmgr_vdev *vdev; + bool strict; + uint32_t sta_cnt = 0; + struct ch_params ch_params = {0}; + const u8 *rsn_ie, *rsnxe_ie; + struct wlan_crypto_params crypto_params = {0}; + bool capable, is_wps; + int32_t keymgmt; + struct wlan_hdd_link_info *link_info; + enum policy_mgr_con_mode pm_con_mode; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE) + return -EINVAL; + + link_info = adapter->deflink; + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) + return -EINVAL; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + /* + * If sta connection is in progress do not allow SAP channel change from + * user space as it may change the HW mode requirement, for which sta is + * trying to connect. + */ + if (hdd_is_any_sta_connecting(hdd_ctx)) { + hdd_err("STA connection is in progress"); + return -EBUSY; + } + + if (wlan_reg_is_6ghz_chan_freq(target_chan_freq) && + !wlan_reg_is_6ghz_band_set(hdd_ctx->pdev)) { + hdd_err("6 GHz band disabled"); + return -EINVAL; + } + + ret = hdd_validate_channel_and_bandwidth(adapter, + target_chan_freq, target_bw); + if (ret) { + hdd_err("Invalid CH and BW combo"); + return ret; + } + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(target_chan_freq)) { + rsn_ie = wlan_get_ie_ptr_from_eid(WLAN_EID_RSN, + beacon->tail, + beacon->tail_len); + rsnxe_ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, + beacon->tail, + beacon->tail_len); + if (rsn_ie) + wlan_crypto_rsnie_check(&crypto_params, rsn_ie); + + keymgmt = wlan_crypto_get_param(sap_ctx->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + if (keymgmt < 0) { + hdd_err_rl("Invalid keymgmt"); + return -EINVAL; + } + + is_wps = adapter->device_mode == QDF_P2P_GO_MODE ? true : false; + capable = wlan_cm_6ghz_allowed_for_akm(hdd_ctx->psoc, keymgmt, + crypto_params.rsn_caps, + rsnxe_ie, 0, is_wps); + if (!capable) { + hdd_err_rl("6Ghz channel switch not capable"); + return -EINVAL; + } + } + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + ucfg_policy_mgr_get_conc_rule1(hdd_ctx->psoc, &conc_rule1); + /* + * conc_custom_rule1: + * Force SCC for SAP + STA + * if STA is already connected then we shouldn't allow + * channel switch in SAP interface. + */ + if (sta_adapter && conc_rule1) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(sta_adapter->deflink); + if (hdd_cm_is_vdev_associated(sta_adapter->deflink)) { + hdd_err("Channel switch not allowed after STA connection with conc_custom_rule1 enabled"); + return -EBUSY; + } + } + + sta_cnt = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc, + PM_STA_MODE, + NULL); + /* + * For non-dbs HW, don't allow Channel switch on DFS channel if STA is + * not connected and sta_sap_scc_on_dfs_chnl is 1. + */ + status = policy_mgr_get_sta_sap_scc_on_dfs_chnl( + hdd_ctx->psoc, &sta_sap_scc_on_dfs_chnl); + if (QDF_STATUS_SUCCESS != status) { + return status; + } + + if (!policy_mgr_is_sap_go_interface_allowed_on_indoor( + hdd_ctx->pdev, + link_info->vdev_id, + target_chan_freq)) { + hdd_debug("Channel switch is not allowed to indoor frequency %d", + target_chan_freq); + return -EINVAL; + } + + if (!sta_cnt && !policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + (sta_sap_scc_on_dfs_chnl == + PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED) && + (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, target_chan_freq) || + (wlan_reg_is_5ghz_ch_freq(target_chan_freq) && + target_bw == CH_WIDTH_160MHZ))) { + hdd_debug("Channel switch not allowed for non-DBS HW on DFS channel %d width %d", target_chan_freq, target_bw); + return -EINVAL; + } + + /* + * Set the ch_switch_in_progress flag to mimic channel change + * when a radar is found. This will enable synchronizing + * SAP and HDD states similar to that of radar indication. + * Suspend the netif queues to stop queuing Tx frames + * from upper layers. netif queues will be resumed + * once the channel change is completed and SAP will + * post eSAP_START_BSS_EVENT success event to HDD. + */ + if (qdf_atomic_inc_return(&ap_ctx->ch_switch_in_progress) > 1) { + hdd_err("Channel switch in progress!!"); + return -EBUSY; + } + ch_params.ch_width = target_bw; + target_bw = wlansap_get_csa_chanwidth_from_phymode( + sap_ctx, target_chan_freq, &ch_params); + pm_con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(hdd_ctx->psoc, + adapter->device_mode, + link_info->vdev_id); + /* + * Do SAP concurrency check to cover channel switch case as following: + * There is already existing SAP+GO combination but due to upper layer + * notifying LTE-COEX event or sending command to move one connection + * to different channel. Before moving existing connection to new + * channel, check if new channel can co-exist with the other existing + * connection. For example, SAP1 is on channel-6 and SAP2 is on + * channel-36 and lets say they are doing DBS, and upper layer sends + * LTE-COEX to move SAP1 from channel-6 to channel-149. SAP1 and + * SAP2 will end up doing MCC which may not be desirable result. It + * should will be prevented. + */ + if (!policy_mgr_allow_concurrency_csa(hdd_ctx->psoc, pm_con_mode, + target_chan_freq, + policy_mgr_get_bw(target_bw), + link_info->vdev_id, forced, + sap_ctx->csa_reason)) { + hdd_err("Channel switch failed due to concurrency check failure"); + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + return -EINVAL; + } + + /* + * Reject channel change req if reassoc in progress on any adapter. + * sme_is_any_session_in_middle_of_roaming is for LFR2 and + * hdd_is_roaming_in_progress is for LFR3 + */ + if (sme_is_any_session_in_middle_of_roaming(hdd_ctx->mac_handle) || + hdd_is_roaming_in_progress(hdd_ctx)) { + hdd_info("Channel switch not allowed as reassoc in progress"); + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + return -EINVAL; + } + /* Disable Roaming on all adapters before doing channel change */ + wlan_hdd_set_roaming_state(link_info, RSO_SAP_CHANNEL_CHANGE, false); + + /* + * Post the Channel Change request to SAP. + */ + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + wlan_hdd_set_roaming_state(link_info, RSO_SAP_CHANNEL_CHANGE, + true); + return -EINVAL; + } + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_GO_MODE) + is_p2p_go_session = true; + else + forced = wlansap_override_csa_strict_for_sap( + hdd_ctx->mac_handle, sap_ctx, + target_chan_freq, forced); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + strict = is_p2p_go_session; + strict = strict || forced; + hdd_place_marker(adapter, "CHANNEL CHANGE", NULL); + status = wlansap_set_channel_change_with_csa( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + target_chan_freq, target_bw, strict); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SAP set channel failed for channel freq: %d, bw: %d", + target_chan_freq, target_bw); + /* + * If channel change command fails then clear the + * radar found flag and also restart the netif + * queues. + */ + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + + /* + * If Posting of the Channel Change request fails + * enable roaming on all adapters + */ + wlan_hdd_set_roaming_state(link_info, RSO_SAP_CHANNEL_CHANGE, + true); + + ret = -EINVAL; + } + + return ret; +} + + +#if defined(FEATURE_WLAN_CH_AVOID) && defined(FEATURE_WLAN_CH_AVOID_EXT) +/** + * wlan_hdd_get_sap_restriction_mask() - get restriction mask for sap + * after sap start + * @hdd_ctx: hdd context + * + * Return: Restriction mask + */ +static inline +uint32_t wlan_hdd_get_sap_restriction_mask(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->coex_avoid_freq_list.restriction_mask; +} + +#else +static inline +uint32_t wlan_hdd_get_sap_restriction_mask(struct hdd_context *hdd_ctx) +{ + return -EINVAL; +} +#endif + +void hdd_stop_sap_set_tx_power(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter) +{ + struct wlan_objmgr_vdev *vdev = + hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + struct wlan_objmgr_pdev *pdev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct qdf_mac_addr bssid; + struct wlan_regulatory_psoc_priv_obj *psoc_priv_obj; + int32_t set_tx_power, tx_power = 0; + struct sap_context *sap_ctx; + uint32_t restriction_mask; + int ch_loop, unsafe_chan_count; + struct unsafe_ch_list *unsafe_ch_list; + uint32_t chan_freq; + bool is_valid_txpower = false; + + if (!vdev) + return; + pdev = wlan_vdev_get_pdev(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + psoc_priv_obj = reg_get_psoc_obj(psoc); + if (!psoc_priv_obj) { + reg_err("reg psoc private obj is NULL"); + return; + } + + restriction_mask = wlan_hdd_get_sap_restriction_mask(hdd_ctx); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + chan_freq = sap_ctx->chan_freq; + unsafe_ch_list = &psoc_priv_obj->unsafe_chan_list; + + hdd_debug("Restriction_mask %d CSA reason %d ", restriction_mask, + sap_ctx->csa_reason); + + if (sap_ctx->csa_reason == CSA_REASON_UNSAFE_CHANNEL) { + if (restriction_mask & BIT(QDF_SAP_MODE)) { + schedule_work(&adapter->sap_stop_bss_work); + } else { + unsafe_chan_count = unsafe_ch_list->chan_cnt; + qdf_copy_macaddr(&bssid, &adapter->mac_addr); + set_tx_power = + wlan_reg_get_channel_reg_power_for_freq(pdev, + chan_freq); + for (ch_loop = 0; ch_loop < unsafe_chan_count; + ch_loop++) { + if (unsafe_ch_list->chan_freq_list[ch_loop] == + chan_freq) { + tx_power = + unsafe_ch_list->txpower[ch_loop]; + is_valid_txpower = + unsafe_ch_list->is_valid_txpower[ch_loop]; + break; + } + } + + if (is_valid_txpower) + set_tx_power = QDF_MIN(set_tx_power, tx_power); + + if (QDF_STATUS_SUCCESS != + sme_set_tx_power(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + bssid, adapter->device_mode, + set_tx_power)) { + hdd_err("Setting tx power failed"); + } + } + } +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +QDF_STATUS hdd_sap_restart_with_channel_switch(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *ap_adapter, + uint32_t target_chan_freq, + uint32_t target_bw, + bool forced) +{ + struct net_device *dev = ap_adapter->dev; + int ret; + + hdd_enter(); + + if (!dev) { + hdd_err("Invalid dev pointer"); + return QDF_STATUS_E_INVAL; + } + + ret = hdd_softap_set_channel_change(dev, target_chan_freq, + target_bw, forced); + if (ret && ret != -EBUSY) { + hdd_err("channel switch failed"); + hdd_stop_sap_set_tx_power(psoc, ap_adapter); + } + + return qdf_status_from_os_return(ret); +} + +QDF_STATUS hdd_sap_restart_chan_switch_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t channel_bw, bool forced) +{ + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_STATUS_E_INVAL; + } + + return hdd_sap_restart_with_channel_switch(psoc, link_info->adapter, + ch_freq, channel_bw, forced); +} + +QDF_STATUS wlan_hdd_check_cc_intf_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t *ch_freq) +{ + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_context; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_STATUS_E_FAILURE; + } + + if (!test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + hdd_err("SOFTAP_BSS_STARTED not set"); + return QDF_STATUS_E_FAILURE; + } + + sap_context = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_context) { + hdd_err("sap_context is null"); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_IS_STATUS_ERROR(wlansap_context_get(sap_context))) { + hdd_err("sap_context is invalid"); + return QDF_STATUS_E_FAILURE; + } + + *ch_freq = wlansap_check_cc_intf(sap_context); + wlansap_context_put(sap_context); + + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_set_sap_csa_reason(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason) +{ + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_ctx; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (sap_ctx) + sap_ctx->csa_reason = reason; + hdd_nofl_debug("set csa reason %d %s vdev %d", + reason, sap_get_csa_reason_str(reason), vdev_id); +} + +QDF_STATUS wlan_hdd_get_channel_for_sap_restart(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + uint32_t *ch_freq) +{ + mac_handle_t mac_handle; + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_context *hdd_ctx; + uint8_t mcc_to_scc_switch = 0; + struct ch_params ch_params = {0}; + struct hdd_adapter *ap_adapter; + struct wlan_hdd_link_info *link_info; + uint32_t sap_ch_freq, intf_ch_freq, temp_ch_freq; + struct sap_context *sap_context; + enum sap_csa_reason_code csa_reason = + CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL; + QDF_STATUS status; + bool use_sap_original_bw = false; + + if (!ch_freq) { + hdd_err("Null parameters"); + return QDF_STATUS_E_FAILURE; + } + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_STATUS_E_FAILURE; + } + + ap_adapter = link_info->adapter; + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!test_bit(SOFTAP_BSS_STARTED, &ap_adapter->deflink->link_flags)) { + hdd_err("SOFTAP_BSS_STARTED not set"); + return QDF_STATUS_E_FAILURE; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("mac_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + sap_context = hdd_ap_ctx->sap_context; + if (!sap_context) { + hdd_err("sap_context is null"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_IS_STATUS_ERROR(wlansap_context_get(sap_context))) { + hdd_err("sap_context is invalid"); + return QDF_STATUS_E_FAILURE; + } + wlan_hdd_set_sap_csa_reason(psoc, vdev_id, csa_reason); + + policy_mgr_get_original_bw_for_sap_restart(psoc, &use_sap_original_bw); + if (use_sap_original_bw) + ch_params.ch_width = sap_context->ch_width_orig; + else + ch_params.ch_width = CH_WIDTH_MAX; + + if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) { + /* + * Adding this feature flag temporarily, will remove this once + * feature flag is enabled. + */ +#ifdef WLAN_FEATURE_LL_LT_SAP + intf_ch_freq = + wlan_get_ll_lt_sap_restart_freq(hdd_ctx->pdev, + sap_context->chan_freq, + sap_context->vdev_id, + &csa_reason); +#else + intf_ch_freq = wlansap_get_chan_band_restrict(sap_context, + &csa_reason); +#endif + if (!intf_ch_freq) { + schedule_work(&ap_adapter->sap_stop_bss_work); + wlansap_context_put(sap_context); + hdd_debug("vdev %d stop ll_lt_sap, no channel found for csa", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + } else { + intf_ch_freq = wlansap_get_chan_band_restrict(sap_context, + &csa_reason); + } + if (intf_ch_freq && intf_ch_freq != sap_context->chan_freq) + goto sap_restart; + + /* + * If STA+SAP sessions are on DFS channel and STA+SAP SCC is + * enabled on DFS channel then move the SAP out of DFS channel + * as soon as STA gets disconnect. + */ + if (policy_mgr_is_sap_restart_required_after_sta_disconnect( + psoc, vdev_id, &intf_ch_freq, + !!link_info->session.ap.sap_config.acs_cfg.acs_mode)) { + hdd_debug("Move the sap (vdev %d) to user configured channel %u", + vdev_id, intf_ch_freq); + goto sap_restart; + } + + if (ap_adapter->device_mode == QDF_P2P_GO_MODE && + !policy_mgr_go_scc_enforced(psoc)) { + wlansap_context_put(sap_context); + hdd_debug("p2p go no scc required"); + return QDF_STATUS_E_FAILURE; + } + /* + * If liberal mode is enabled. If P2P-Cli is not yet connected + * Skipping CSA as this is done as part of set_key + */ + + if (ap_adapter->device_mode == QDF_P2P_GO_MODE && + policy_mgr_go_scc_enforced(psoc) && + !policy_mgr_is_go_scc_strict(psoc) && + (wlan_vdev_get_peer_count(sap_context->vdev) == 1)) { + hdd_debug("p2p go liberal mode enabled. Skipping CSA"); + wlansap_context_put(sap_context); + return QDF_STATUS_E_FAILURE; + } + + ucfg_policy_mgr_get_mcc_scc_switch(hdd_ctx->psoc, + &mcc_to_scc_switch); + policy_mgr_get_chan_by_session_id(psoc, vdev_id, &sap_ch_freq); + if (!policy_mgr_is_restart_sap_required(hdd_ctx->psoc, vdev_id, + sap_ch_freq, + mcc_to_scc_switch)) { + wlansap_context_put(sap_context); + hdd_debug("SAP needn't restart"); + return QDF_STATUS_E_FAILURE; + } + + /* + * Check if STA's channel is DFS or passive or part of LTE avoided + * channel list. In that case move SAP to other band if DBS is + * supported, return from here if DBS is not supported. + * Need to take care of 3 port cases with 2 STA iface in future. + */ + intf_ch_freq = wlansap_check_cc_intf(sap_context); + hdd_debug("sap_vdev %d intf_ch: %d, orig freq: %d", + vdev_id, intf_ch_freq, sap_ch_freq); + + temp_ch_freq = intf_ch_freq ? intf_ch_freq : sap_ch_freq; + wlansap_get_csa_chanwidth_from_phymode(sap_context, temp_ch_freq, + &ch_params); + if (QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION != + mcc_to_scc_switch) { + if (QDF_IS_STATUS_ERROR( + policy_mgr_valid_sap_conc_channel_check( + hdd_ctx->psoc, &intf_ch_freq, sap_ch_freq, vdev_id, + &ch_params))) { + schedule_work(&ap_adapter->sap_stop_bss_work); + wlansap_context_put(sap_context); + hdd_debug("can't move sap to chan(freq): %u, stopping SAP", + intf_ch_freq); + return QDF_STATUS_E_FAILURE; + } + } + +sap_restart: + if (!intf_ch_freq) { + hdd_debug("Unable to find safe channel, Hence stop the SAP or Set Tx power"); + sap_context->csa_reason = csa_reason; + hdd_stop_sap_set_tx_power(psoc, ap_adapter); + wlansap_context_put(sap_context); + return QDF_STATUS_E_FAILURE; + } else { + sap_context->csa_reason = csa_reason; + } + if (ch_params.ch_width == CH_WIDTH_MAX) + wlansap_get_csa_chanwidth_from_phymode( + sap_context, intf_ch_freq, + &ch_params); + + hdd_debug("mhz_freq_seg0: %d, ch_width: %d", + ch_params.mhz_freq_seg0, ch_params.ch_width); + if (sap_context->csa_reason == CSA_REASON_UNSAFE_CHANNEL && + (!policy_mgr_check_bw_with_unsafe_chan_freq(hdd_ctx->psoc, + ch_params.mhz_freq_seg0, + ch_params.ch_width))) { + hdd_debug("SAP bw shrink to 20M for unsafe"); + ch_params.ch_width = CH_WIDTH_20MHZ; + } + + hdd_debug("SAP restart orig chan freq: %d, new freq: %d bw %d", + hdd_ap_ctx->sap_config.chan_freq, intf_ch_freq, + ch_params.ch_width); + hdd_ap_ctx->bss_stop_reason = BSS_STOP_DUE_TO_MCC_SCC_SWITCH; + *ch_freq = intf_ch_freq; + hdd_debug("SAP channel change with CSA/ECSA"); + status = hdd_sap_restart_chan_switch_cb(psoc, vdev_id, *ch_freq, + ch_params.ch_width, false); + wlansap_context_put(sap_context); + + return status; +} + +QDF_STATUS +wlan_get_sap_acs_band(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t *acs_band) +{ + struct wlan_hdd_link_info *link_info; + struct sap_config *sap_config; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info || (link_info->adapter->device_mode != QDF_P2P_GO_MODE && + link_info->adapter->device_mode != QDF_SAP_MODE)) { + hdd_err("Invalid vdev or device mode"); + return QDF_STATUS_E_FAILURE; + } + /* + * If acs mode is false, that means acs is disabled and acs band can be + * QCA_ACS_MODE_IEEE80211ANY + */ + sap_config = &link_info->session.ap.sap_config; + if (!sap_config->acs_cfg.acs_mode) + *acs_band = QCA_ACS_MODE_IEEE80211ANY; + else + *acs_band = sap_config->acs_cfg.band; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_get_ap_prefer_conc_ch_params( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t chan_freq, + struct ch_params *ch_params) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + struct sap_context *sap_context; + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info || (link_info->adapter->device_mode != QDF_P2P_GO_MODE && + link_info->adapter->device_mode != QDF_SAP_MODE)) { + hdd_err("Invalid vdev or device mode"); + return QDF_STATUS_E_FAILURE; + } + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_context = hdd_ap_ctx->sap_context; + if (!sap_context) { + hdd_err("sap_context is null"); + return QDF_STATUS_E_FAILURE; + } + if (QDF_IS_STATUS_ERROR(wlansap_context_get(sap_context))) { + hdd_err("sap_context is invalid"); + return QDF_STATUS_E_FAILURE; + } + + wlansap_get_csa_chanwidth_from_phymode(sap_context, + chan_freq, + ch_params); + wlansap_context_put(sap_context); + + return QDF_STATUS_SUCCESS; +} + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +uint32_t hdd_get_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + int32_t keymgmt; + struct hdd_adapter *ap_adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_ap_ctx *ap_ctx; + struct sap_context *sap_context; + struct sap_config *sap_config; + uint32_t capable = 0; + enum policy_mgr_con_mode con_mode; + + if (!psoc) { + hdd_err("PSOC is NULL"); + return 0; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL %d", vdev_id); + return 0; + } + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev %d", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return 0; + } + + ap_adapter = link_info->adapter; + con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, + ap_adapter->device_mode, + vdev_id); + if (!policy_mgr_is_beaconing_mode(con_mode) || + !policy_mgr_is_6ghz_conc_mode_supported(psoc, con_mode)) { + hdd_err("unexpected device mode %d", ap_adapter->device_mode); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return 0; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_config = &ap_ctx->sap_config; + sap_context = ap_ctx->sap_context; + if (QDF_IS_STATUS_ERROR(wlansap_context_get(sap_context))) { + hdd_err("sap_context is get failed %d", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return 0; + } + /* SAP is allowed on 6GHz with explicit indication from user space: + * a. SAP is started on 6Ghz already. + * b. SAP is configured on 6Ghz fixed channel from userspace. + * c. SAP is configured by ACS range which includes any 6Ghz channel. + */ + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->deflink->link_flags)) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ( + ap_ctx->operating_chan_freq)) + capable |= CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED; + } else { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_config->chan_freq)) + capable |= CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED; + else if (sap_context && WLAN_REG_IS_6GHZ_CHAN_FREQ( + sap_context->chan_freq)) + capable |= CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED; + } + if (wlansap_is_6ghz_included_in_acs_range(sap_context)) + capable |= CONN_6GHZ_FLAG_ACS_OR_USR_ALLOWED; + + keymgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (keymgmt < 0) { + hdd_err("Invalid mgmt cipher"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + return 0; + } + + /* + * 6 GHz SAP is allowed in open mode only if the + * check_6ghz_security ini is disabled. + */ + if (!cfg_get(psoc, CFG_CHECK_6GHZ_SECURITY) && + (!keymgmt || (keymgmt & (1 << WLAN_CRYPTO_KEY_MGMT_NONE)))) + capable |= CONN_6GHZ_FLAG_SECURITY_ALLOWED; + + if ((keymgmt & (1 << WLAN_CRYPTO_KEY_MGMT_SAE | + 1 << WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B | + 1 << WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192 | + 1 << WLAN_CRYPTO_KEY_MGMT_OWE | + 1 << WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY))) { + capable |= CONN_6GHZ_FLAG_SECURITY_ALLOWED; + } + capable |= CONN_6GHZ_FLAG_VALID; + hdd_debug("vdev_id %d keymgmt 0x%08x capable 0x%x", + vdev_id, keymgmt, capable); + wlansap_context_put(sap_context); + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + + return capable; +} +#else +uint32_t hdd_get_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + return 0; +} +#endif +#endif + +#ifdef WLAN_FEATURE_TSF_PTP +static const struct ethtool_ops wlan_hostapd_ethtool_ops = { + .get_ts_info = wlan_get_ts_info, +}; +#endif + +const struct net_device_ops net_ops_struct = { + .ndo_open = hdd_hostapd_open, + .ndo_stop = hdd_hostapd_stop, + .ndo_uninit = hdd_hostapd_uninit, + .ndo_start_xmit = hdd_softap_hard_start_xmit, + .ndo_tx_timeout = hdd_softap_tx_timeout, + .ndo_get_stats = hdd_get_stats, + .ndo_set_mac_address = hdd_hostapd_set_mac_address, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) + .ndo_do_ioctl = hdd_ioctl, +#endif + .ndo_change_mtu = hdd_hostapd_change_mtu, + .ndo_select_queue = hdd_select_queue, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + .ndo_siocdevprivate = hdd_dev_private_ioctl, +#endif +}; + +#ifdef WLAN_FEATURE_TSF_PTP +void hdd_set_ap_ops(struct net_device *dev) +{ + dev->netdev_ops = &net_ops_struct; + dev->ethtool_ops = &wlan_hostapd_ethtool_ops; +} +#else +void hdd_set_ap_ops(struct net_device *dev) +{ + dev->netdev_ops = &net_ops_struct; +} +#endif + +bool hdd_sap_create_ctx(struct hdd_adapter *adapter) +{ + hdd_debug("creating sap context"); + adapter->deflink->session.ap.sap_context = sap_create_ctx(); + if (adapter->deflink->session.ap.sap_context) + return true; + + return false; +} + +bool hdd_sap_destroy_ctx(struct wlan_hdd_link_info *link_info) +{ + struct sap_context *sap_ctx = link_info->session.ap.sap_context; + + if (link_info->session.ap.beacon) { + qdf_mem_free(link_info->session.ap.beacon); + link_info->session.ap.beacon = NULL; + } + + if (!sap_ctx) { + hdd_debug("sap context is NULL"); + return true; + } + + hdd_debug("destroying sap context"); + + if (QDF_IS_STATUS_ERROR(sap_destroy_ctx(sap_ctx))) + return false; + + link_info->session.ap.sap_context = NULL; + + return true; +} + +void hdd_sap_destroy_ctx_all(struct hdd_context *hdd_ctx, bool is_ssr) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct wlan_hdd_link_info *link_info; + + /* sap_ctx is not destroyed as it will be leveraged for sap restart */ + if (is_ssr) + return; + + hdd_debug("destroying all the sap context"); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_SAP_DESTROY_CTX_ALL) { + if (adapter->device_mode == QDF_SAP_MODE) { + hdd_adapter_for_each_active_link_info(adapter, + link_info) { + hdd_sap_destroy_ctx(link_info); + } + } + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_SAP_DESTROY_CTX_ALL); + } +} + +static void +hdd_indicate_peers_deleted(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct wlan_hdd_link_info *link_info; + + if (!psoc) { + hdd_err("psoc obj is NULL"); + return; + } + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) { + hdd_err("invalid vdev or adapter"); + return; + } + + hdd_sap_indicate_disconnect_for_sta(link_info->adapter); +} + +QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, + bool reinit, + bool rtnl_held) +{ + struct hdd_hostapd_state *phostapdBuf; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sap_context *sap_ctx; + int ret; + enum dfs_mode acs_dfs_mode; + bool acs_with_more_param = 0; + uint8_t enable_sifs_burst = 0; + bool is_6g_sap_fd_enabled = 0; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + hdd_debug("SSR in progress: %d", reinit); + qdf_atomic_init(&adapter->deflink->session.ap.acs_in_progress); + + sap_ctx = hdd_hostapd_init_sap_session(adapter, reinit); + if (!sap_ctx) { + hdd_err("Invalid sap_ctx"); + goto error_release_vdev; + } + + if (!reinit) { + adapter->deflink->session.ap.sap_config.chan_freq = + hdd_ctx->acs_policy.acs_chan_freq; + acs_dfs_mode = hdd_ctx->acs_policy.acs_dfs_mode; + adapter->deflink->session.ap.sap_config.acs_dfs_mode = + wlan_hdd_get_dfs_mode(acs_dfs_mode); + } + + status = ucfg_mlme_get_acs_with_more_param(hdd_ctx->psoc, + &acs_with_more_param); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("can't get sap acs with more param, use def"); + + wlan_sap_set_acs_with_more_param(hdd_ctx->mac_handle, + acs_with_more_param); + + /* Allocate the Wireless Extensions state structure */ + phostapdBuf = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + + /* Zero the memory. This zeros the profile structure. */ + memset(phostapdBuf, 0, sizeof(struct hdd_hostapd_state)); + + status = qdf_event_create(&phostapdBuf->qdf_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Hostapd HDD qdf event init failed!!"); + goto error_deinit_sap_session; + } + + status = qdf_event_create(&phostapdBuf->qdf_stop_bss_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Hostapd HDD stop bss event init failed!!"); + goto error_deinit_sap_session; + } + + status = qdf_event_create(&phostapdBuf->qdf_sta_disassoc_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Hostapd HDD sta disassoc event init failed!!"); + goto error_deinit_sap_session; + } + + status = qdf_event_create(&phostapdBuf->qdf_sta_eap_frm_done_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Hostapd HDD sta eap frm done event init failed!!"); + goto error_deinit_sap_session; + } + + /* Register as a wireless device */ + hdd_register_hostapd_wext(adapter->dev); + + /* Cache station count initialize to zero */ + qdf_atomic_init(&adapter->cache_sta_count); + + status = hdd_wmm_adapter_init(adapter); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hdd_wmm_adapter_init() failed code: %08d [x%08x]", + status, status); + goto error_release_softap_tx_rx; + } + + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + status = ucfg_get_enable_sifs_burst(hdd_ctx->psoc, &enable_sifs_burst); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to get sifs burst value, use default"); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_pdev_param_burst_enable, + enable_sifs_burst, + PDEV_CMD); + if (0 != ret) + hdd_err("wmi_pdev_param_burst_enable set failed: %d", ret); + + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + ucfg_mlme_is_6g_sap_fd_enabled(hdd_ctx->psoc, &is_6g_sap_fd_enabled); + hdd_debug("6g sap fd enabled %d", is_6g_sap_fd_enabled); + if (is_6g_sap_fd_enabled && vdev) + wlan_vdev_mlme_feat_ext_cap_set(vdev, + WLAN_VDEV_FEXT_FILS_DISC_6G_SAP); + + if (vdev) + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + hdd_set_netdev_flags(adapter); + + if (!reinit) { + adapter->deflink->session.ap.sap_config.acs_cfg.acs_mode = + false; + wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, + false); + wlansap_dcs_set_vdev_starting(sap_ctx, false); + qdf_mem_zero(&adapter->deflink->session.ap.sap_config.acs_cfg, + sizeof(struct sap_acs_cfg)); + } + + sme_set_del_peers_ind_callback(hdd_ctx->mac_handle, + &hdd_indicate_peers_deleted); + /* rcpi info initialization */ + qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi)); + + hdd_tsf_auto_report_init(adapter); + hdd_exit(); + + return status; + +error_release_softap_tx_rx: + hdd_wext_unregister(adapter->dev, rtnl_held); +error_deinit_sap_session: + hdd_hostapd_deinit_sap_session(adapter->deflink); +error_release_vdev: + hdd_exit(); + return status; +} + +void hdd_deinit_ap_mode(struct wlan_hdd_link_info *link_info) +{ + struct hdd_ap_ctx *ap_ctx; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_enter_dev(adapter->dev); + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + qdf_atomic_set(&ap_ctx->acs_in_progress, 0); + if (qdf_atomic_read(&ap_ctx->ch_switch_in_progress)) { + qdf_atomic_set(&ap_ctx->ch_switch_in_progress, 0); + policy_mgr_set_chan_switch_complete_evt(adapter->hdd_ctx->psoc); + + /* Re-enable roaming on all connected STA vdev */ + wlan_hdd_set_roaming_state(link_info, + RSO_SAP_CHANNEL_CHANGE, true); + } + + if (hdd_hostapd_deinit_sap_session(link_info)) + hdd_err("Failed:hdd_hostapd_deinit_sap_session"); + + hdd_exit(); +} + +/** + * hdd_wlan_create_ap_dev() - create an AP-mode device + * @hdd_ctx: Global HDD context + * @mac_addr: MAC address to assign to the interface + * @name_assign_type: the name of assign type of the netdev + * @iface_name: User-visible name of the interface + * + * This function will allocate a Linux net_device and configuration it + * for an AP mode of operation. Note that the device is NOT actually + * registered with the kernel at this time. + * + * Return: A pointer to the private data portion of the net_device if + * the allocation and initialization was successful, NULL otherwise. + */ +struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr, + unsigned char name_assign_type, + uint8_t *iface_name) +{ + struct net_device *dev; + struct hdd_adapter *adapter; + + hdd_debug("iface_name = %s", iface_name); + + dev = alloc_netdev_mqs(sizeof(struct hdd_adapter), iface_name, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + name_assign_type, +#endif + ether_setup, NUM_TX_QUEUES, NUM_RX_QUEUES); + + if (!dev) + return NULL; + + adapter = netdev_priv(dev); + + /* Init the net_device structure */ + ether_setup(dev); + + /* Initialize the adapter context to zeros. */ + qdf_mem_zero(adapter, sizeof(struct hdd_adapter)); + adapter->dev = dev; + adapter->deflink = &adapter->link_info[WLAN_HDD_DEFLINK_IDX]; + adapter->hdd_ctx = hdd_ctx; + adapter->magic = WLAN_HDD_ADAPTER_MAGIC; + qdf_atomic_set_bit(WLAN_HDD_DEFLINK_IDX, &adapter->active_links); + + hdd_debug("dev = %pK, adapter = %pK, concurrency_mode=0x%x", + dev, adapter, + (int)policy_mgr_get_concurrency_mode(hdd_ctx->psoc)); + + /* Init the net_device structure */ + strlcpy(dev->name, (const char *)iface_name, IFNAMSIZ); + + hdd_set_ap_ops(dev); + + dev->watchdog_timeo = HDD_TX_TIMEOUT; + dev->mtu = HDD_DEFAULT_MTU; + dev->tx_queue_len = HDD_NETDEV_TX_QUEUE_LEN; + + qdf_net_update_net_device_dev_addr(dev, mac_addr, sizeof(tSirMacAddr)); + qdf_mem_copy(adapter->mac_addr.bytes, mac_addr, sizeof(tSirMacAddr)); + + hdd_update_dynamic_tsf_sync(adapter); + hdd_dev_setup_destructor(dev); + dev->ieee80211_ptr = &adapter->wdev; + adapter->wdev.wiphy = hdd_ctx->wiphy; + adapter->wdev.netdev = dev; + + SET_NETDEV_DEV(dev, hdd_ctx->parent_dev); + spin_lock_init(&adapter->pause_map_lock); + adapter->start_time = adapter->last_time = qdf_system_ticks(); + + qdf_atomic_init(&adapter->deflink->session.ap.ch_switch_in_progress); + + return adapter; +} + +/** + * wlan_hdd_rate_is_11g() - check if rate is 11g rate or not + * @rate: Rate to be checked + * + * Return: true if rate if 11g else false + */ +static bool wlan_hdd_rate_is_11g(u8 rate) +{ + static const u8 gRateArray[8] = {12, 18, 24, 36, 48, 72, + 96, 108}; /* actual rate * 2 */ + u8 i; + + for (i = 0; i < 8; i++) { + if (rate == gRateArray[i]) + return true; + } + return false; +} + +#ifdef QCA_HT_2040_COEX +/** + * wlan_hdd_get_sap_obss() - Get SAP OBSS enable config based on HT_CAPAB IE + * @link_info: Pointer to link info in adapter + * + * Return: HT support channel width config value + */ +static bool wlan_hdd_get_sap_obss(struct wlan_hdd_link_info *link_info) +{ + uint32_t ret; + const uint8_t *ie; + uint8_t ht_cap_ie[DOT11F_IE_HTCAPS_MAX_LEN]; + mac_handle_t mac_handle; + tDot11fIEHTCaps dot11_ht_cap_ie = {0}; + struct hdd_beacon_data *beacon = link_info->session.ap.beacon; + + mac_handle = hdd_adapter_get_mac_handle(link_info->adapter); + if (!mac_handle) { + hdd_debug("NULL MAC context"); + return false; + } + + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_HT_CAPABILITY, + beacon->tail, beacon->tail_len); + if (ie && ie[1] && (ie[1] <= DOT11F_IE_HTCAPS_MAX_LEN)) { + qdf_mem_copy(ht_cap_ie, &ie[2], ie[1]); + ret = dot11f_unpack_ie_ht_caps(MAC_CONTEXT(mac_handle), + ht_cap_ie, ie[1], + &dot11_ht_cap_ie, false); + if (DOT11F_FAILED(ret)) { + hdd_err("unpack failed, ret: 0x%x", ret); + return false; + } + return dot11_ht_cap_ie.supportedChannelWidthSet; + } + + return false; +} +#else +static inline bool wlan_hdd_get_sap_obss(struct wlan_hdd_link_info *link_info) +{ + return false; +} +#endif +/** + * wlan_hdd_set_channel() - set channel in sap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @chandef: Pointer to channel definition structure + * @channel_type: Channel type + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_set_channel(struct wiphy *wiphy, struct net_device *dev, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type channel_type) +{ + struct hdd_adapter *adapter = NULL; + uint32_t num_ch = 0; + int channel_seg2 = 0; + struct hdd_context *hdd_ctx; + int status; + mac_handle_t mac_handle; + struct sme_config_params *sme_config; + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_hdd_link_info *link_info; + + if (!dev) { + hdd_err("Called with dev = NULL"); + return -ENODEV; + } + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + link_info = adapter->deflink; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_CHANNEL, + link_info->vdev_id, channel_type); + + hdd_debug("Dev_mode %s(%d) freq %d, ch_bw %d ccfs1 %d ccfs2 %d", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode, chandef->chan->center_freq, + chandef->width, chandef->center_freq1, chandef->center_freq2); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + mac_handle = hdd_ctx->mac_handle; + + /* Check freq range */ + if ((wlan_reg_min_chan_freq() > + chandef->chan->center_freq) || + (wlan_reg_max_chan_freq() < chandef->chan->center_freq)) { + hdd_err("channel: %d is outside valid freq range", + chandef->chan->center_freq); + return -EINVAL; + } + + if (NL80211_CHAN_WIDTH_80P80 == chandef->width) { + if ((wlan_reg_min_chan_freq() > chandef->center_freq2) || + (wlan_reg_max_chan_freq() < chandef->center_freq2)) { + hdd_err("center_freq2: %d is outside valid freq range", + chandef->center_freq2); + return -EINVAL; + } + + if (chandef->center_freq2) + channel_seg2 = ieee80211_frequency_to_channel( + chandef->center_freq2); + else + hdd_err("Invalid center_freq2"); + } + + num_ch = CFG_VALID_CHANNEL_LIST_LEN; + + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(hdd_ctx, + chandef->chan->center_freq)) { + hdd_err("Invalid freq: %d", chandef->chan->center_freq); + return -EINVAL; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + sap_config = &ap_ctx->sap_config; + sap_config->chan_freq = chandef->chan->center_freq; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + sap_config->ch_params.center_freq_seg0 = + ieee80211_frequency_to_channel(chandef->center_freq1); + + if (QDF_SAP_MODE == adapter->device_mode) { + /* set channel to what hostapd configured */ + sap_config->chan_freq = chandef->chan->center_freq; + sap_config->ch_params.center_freq_seg1 = channel_seg2; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) + return -ENOMEM; + + sme_get_config_param(mac_handle, sme_config); + switch (channel_type) { + case NL80211_CHAN_HT20: + case NL80211_CHAN_NO_HT: + sme_config->csr_config.obssEnabled = false; + sap_config->sec_ch_freq = 0; + break; + case NL80211_CHAN_HT40MINUS: + sap_config->sec_ch_freq = + sap_config->chan_freq - 20; + break; + case NL80211_CHAN_HT40PLUS: + sap_config->sec_ch_freq = + sap_config->chan_freq + 20; + break; + default: + hdd_err("Error!!! Invalid HT20/40 mode !"); + qdf_mem_free(sme_config); + return -EINVAL; + } + sme_config->csr_config.obssEnabled = + wlan_hdd_get_sap_obss(link_info); + + sme_update_config(mac_handle, sme_config); + qdf_mem_free(sme_config); + } + + return status; +} + +/** + * wlan_hdd_check_11gmode() - check for 11g mode + * @ie: Pointer to IE + * @require_ht: Pointer to require ht + * @require_vht: Pointer to require vht + * @pCheckRatesfor11g: Pointer to check rates for 11g mode + * @pSapHw_mode: SAP HW mode + * + * Check for 11g rate and set proper 11g only mode + * + * Return: none + */ +static void wlan_hdd_check_11gmode(const u8 *ie, u8 *require_ht, + u8 *require_vht, u8 *pCheckRatesfor11g, + eCsrPhyMode *pSapHw_mode) +{ + u8 i, num_rates = ie[0]; + + ie += 1; + for (i = 0; i < num_rates; i++) { + if (*pCheckRatesfor11g + && (true == wlan_hdd_rate_is_11g(ie[i] & RATE_MASK))) { + /* If rate set have 11g rate than change the mode + * to 11G + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g; + if (ie[i] & BASIC_RATE_MASK) { + /* If we have 11g rate as basic rate, it + * means mode is 11g only mode. + */ + *pSapHw_mode = eCSR_DOT11_MODE_11g_ONLY; + *pCheckRatesfor11g = false; + } + } else { + if ((BASIC_RATE_MASK | + BSS_MEMBERSHIP_SELECTOR_HT_PHY) == ie[i]) + *require_ht = true; + else if ((BASIC_RATE_MASK | + BSS_MEMBERSHIP_SELECTOR_VHT_PHY) == ie[i]) + *require_vht = true; + } + } +} + +/** + * wlan_hdd_check_h2e() - check SAE/H2E require flag from support rate sets + * @rs: support rate or extended support rate set + * @require_h2e: pointer to store require h2e flag + * + * Return: none + */ +static void wlan_hdd_check_h2e(const tSirMacRateSet *rs, bool *require_h2e) +{ + uint8_t i; + + if (!rs || !require_h2e) + return; + + for (i = 0; i < rs->numRates; i++) { + if (rs->rate[i] == (BASIC_RATE_MASK | + BSS_MEMBERSHIP_SELECTOR_SAE_H2E)) + *require_h2e = true; + } +} + +#ifdef WLAN_FEATURE_11AX +/** + * wlan_hdd_add_extn_ie() - add extension IE + * @link_info: Link info pointer in adapter + * @genie: Pointer to ie to be added + * @total_ielen: Pointer to store total ie length + * @oui: Pointer to oui + * @oui_size: Size of oui + * + * Return: 0 for success non-zero for failure + */ +static int wlan_hdd_add_extn_ie(struct wlan_hdd_link_info *link_info, + uint8_t *genie, uint16_t *total_ielen, + uint8_t *oui, uint8_t oui_size) +{ + const uint8_t *ie; + uint16_t ielen = 0; + struct hdd_beacon_data *beacon = link_info->session.ap.beacon; + + ie = wlan_get_ext_ie_ptr_from_ext_id(oui, oui_size, + beacon->tail, + beacon->tail_len); + if (ie) { + ielen = ie[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + qdf_mem_copy(&genie[*total_ielen], ie, ielen); + } else { + hdd_err("**Ie Length is too big***"); + return -EINVAL; + } + *total_ielen += ielen; + } + return 0; +} +#endif + +/** + * wlan_hdd_add_hostapd_conf_vsie() - configure Vendor IE in sap mode + * @link_info: Index of link_info in HDD adapter + * @genie: Pointer to Vendor IE + * @total_ielen: Pointer to store total ie length + * + * Return: none + */ +static void wlan_hdd_add_hostapd_conf_vsie(struct wlan_hdd_link_info *link_info, + uint8_t *genie, + uint16_t *total_ielen) +{ + struct hdd_beacon_data *beacon = link_info->session.ap.beacon; + int left = beacon->tail_len; + uint8_t *ptr = beacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + bool skip_ie; + + if (!ptr || 0 == left) + return; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hdd_err("**Invalid IEs eid: %d elem_len: %d left: %d**", + elem_id, elem_len, left); + return; + } + if (WLAN_ELEMID_VENDOR == elem_id) { + /* + * skipping the Vendor IE's which we don't want to + * include or it will be included by existing code. + */ + if (elem_len >= WPS_OUI_TYPE_SIZE && + (!qdf_mem_cmp(&ptr[2], ALLOWLIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) || + !qdf_mem_cmp(&ptr[2], DENYLIST_OUI_TYPE, + WPA_OUI_TYPE_SIZE) || + !qdf_mem_cmp(&ptr[2], "\x00\x50\xf2\x02", + WPA_OUI_TYPE_SIZE) || + !qdf_mem_cmp(&ptr[2], WPA_OUI_TYPE, + WPA_OUI_TYPE_SIZE))) + skip_ie = true; + else + skip_ie = false; + + if (!skip_ie) { + ielen = ptr[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + qdf_mem_copy(&genie[*total_ielen], ptr, + ielen); + *total_ielen += ielen; + } else { + hdd_err("IE Length is too big IEs eid: %d elem_len: %d total_ie_lent: %d", + elem_id, elem_len, *total_ielen); + } + } + } + + left -= elem_len; + ptr += (elem_len + 2); + } +} + +/** + * wlan_hdd_add_extra_ie() - add extra ies in beacon + * @link_info: Pointer to link_info in adapter + * @genie: Pointer to extra ie + * @total_ielen: Pointer to store total ie length + * @temp_ie_id: ID of extra ie + * + * Return: none + */ +static void wlan_hdd_add_extra_ie(struct wlan_hdd_link_info *link_info, + uint8_t *genie, uint16_t *total_ielen, + uint8_t temp_ie_id) +{ + struct hdd_beacon_data *beacon = link_info->session.ap.beacon; + int left = beacon->tail_len; + uint8_t *ptr = beacon->tail; + uint8_t elem_id, elem_len; + uint16_t ielen = 0; + + if (!ptr || 0 == left) + return; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + hdd_err("**Invalid IEs eid: %d elem_len: %d left: %d**", + elem_id, elem_len, left); + return; + } + + if (temp_ie_id == elem_id) { + ielen = ptr[1] + 2; + if ((*total_ielen + ielen) <= MAX_GENIE_LEN) { + qdf_mem_copy(&genie[*total_ielen], ptr, ielen); + *total_ielen += ielen; + } else { + hdd_err("IE Length is too big IEs eid: %d elem_len: %d total_ie_len: %d", + elem_id, elem_len, *total_ielen); + } + } + + left -= elem_len; + ptr += (elem_len + 2); + } +} + +/** + * wlan_hdd_cfg80211_alloc_new_beacon() - alloc beacon in ap mode + * @link_info: Pointer to link_info in hostapd adapter + * @out_beacon: Location to store newly allocated beacon data + * @params: Pointer to beacon parameters + * @dtim_period: DTIM period + * + * Return: 0 for success non-zero for failure + */ +static int +wlan_hdd_cfg80211_alloc_new_beacon(struct wlan_hdd_link_info *link_info, + struct hdd_beacon_data **out_beacon, + struct cfg80211_beacon_data *params, + int dtim_period) +{ + int size; + struct hdd_beacon_data *beacon = NULL; + struct hdd_beacon_data *old = NULL; + int head_len, tail_len, proberesp_ies_len, assocresp_ies_len; + const u8 *head, *tail, *proberesp_ies, *assocresp_ies; + + hdd_enter(); + if (params->head && !params->head_len) { + hdd_err("head_len is NULL"); + return -EINVAL; + } + + old = link_info->session.ap.beacon; + if (!params->head && !old) { + hdd_err("session: %d old and new heads points to NULL", + link_info->vdev_id); + return -EINVAL; + } + + if (params->head) { + head_len = params->head_len; + head = params->head; + } else { + head_len = old->head_len; + head = old->head; + } + + if (params->tail || !old) { + tail_len = params->tail_len; + tail = params->tail; + } else { + tail_len = old->tail_len; + tail = old->tail; + } + + if (params->proberesp_ies || !old) { + proberesp_ies_len = params->proberesp_ies_len; + proberesp_ies = params->proberesp_ies; + } else { + proberesp_ies_len = old->proberesp_ies_len; + proberesp_ies = old->proberesp_ies; + } + + if (params->assocresp_ies || !old) { + assocresp_ies_len = params->assocresp_ies_len; + assocresp_ies = params->assocresp_ies; + } else { + assocresp_ies_len = old->assocresp_ies_len; + assocresp_ies = old->assocresp_ies; + } + + size = sizeof(struct hdd_beacon_data) + head_len + tail_len + + proberesp_ies_len + assocresp_ies_len; + + beacon = qdf_mem_malloc(size); + if (!beacon) + return -ENOMEM; + + if (dtim_period) + beacon->dtim_period = dtim_period; + else if (old) + beacon->dtim_period = old->dtim_period; + /* ----------------------------------------------- + * | head | tail | proberesp_ies | assocresp_ies | + * ----------------------------------------------- + */ + beacon->head = ((u8 *) beacon) + sizeof(struct hdd_beacon_data); + beacon->tail = beacon->head + head_len; + beacon->proberesp_ies = beacon->tail + tail_len; + beacon->assocresp_ies = beacon->proberesp_ies + proberesp_ies_len; + + beacon->head_len = head_len; + beacon->tail_len = tail_len; + beacon->proberesp_ies_len = proberesp_ies_len; + beacon->assocresp_ies_len = assocresp_ies_len; + + if (head && head_len) + memcpy(beacon->head, head, head_len); + if (tail && tail_len) + memcpy(beacon->tail, tail, tail_len); + if (proberesp_ies && proberesp_ies_len) + memcpy(beacon->proberesp_ies, proberesp_ies, proberesp_ies_len); + if (assocresp_ies && assocresp_ies_len) + memcpy(beacon->assocresp_ies, assocresp_ies, assocresp_ies_len); + + *out_beacon = beacon; + + link_info->session.ap.beacon = NULL; + qdf_mem_free(old); + + return 0; + +} + +#ifdef QCA_HT_2040_COEX +static void wlan_hdd_add_sap_obss_scan_ie(struct wlan_hdd_link_info *link_info, + uint8_t *ie_buf, uint16_t *ie_len) +{ + if (QDF_SAP_MODE != link_info->adapter->device_mode || + !wlan_hdd_get_sap_obss(link_info)) + return; + + wlan_hdd_add_extra_ie(link_info, ie_buf, ie_len, + WLAN_EID_OVERLAP_BSS_SCAN_PARAM); +} +#else +static inline void +wlan_hdd_add_sap_obss_scan_ie(struct wlan_hdd_link_info *link_info, + uint8_t *ie_buf, uint16_t *ie_len) +{ +} +#endif + +/** + * hdd_update_11ax_apies() - update ap mode 11ax ies + * @link_info: Pointer to link_info in adapter + * @genie: generic IE buffer + * @total_ielen: out param to update total ielen + * + * Return: 0 for success non-zero for failure + */ + +#ifdef WLAN_FEATURE_11AX +static int hdd_update_11ax_apies(struct wlan_hdd_link_info *link_info, + uint8_t *genie, uint16_t *total_ielen) +{ + if (wlan_hdd_add_extn_ie(link_info, genie, total_ielen, + HE_CAP_OUI_TYPE, HE_CAP_OUI_SIZE)) { + hdd_err("Adding HE Cap ie failed"); + return -EINVAL; + } + + if (wlan_hdd_add_extn_ie(link_info, genie, total_ielen, + HE_OP_OUI_TYPE, HE_OP_OUI_SIZE)) { + hdd_err("Adding HE Op ie failed"); + return -EINVAL; + } + + return 0; +} +#else +static int hdd_update_11ax_apies(struct wlan_hdd_link_info *link_info, + uint8_t *genie, uint16_t *total_ielen) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_11BE +static int hdd_update_11be_apies(struct wlan_hdd_link_info *link_info, + uint8_t *genie, uint16_t *total_ielen) +{ + if (wlan_hdd_add_extn_ie(link_info, genie, total_ielen, + EHT_OP_OUI_TYPE, EHT_OP_OUI_SIZE)) { + hdd_err("Adding EHT Cap IE failed"); + return -EINVAL; + } + + if (wlan_hdd_add_extn_ie(link_info, genie, total_ielen, + EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE)) { + hdd_err("Adding EHT Op IE failed"); + return -EINVAL; + } + + return 0; +} +#else +static int hdd_update_11be_apies(struct wlan_hdd_link_info *link_info, + uint8_t *genie, uint16_t *total_ielen) +{ + return 0; +} +#endif + +int +wlan_hdd_cfg80211_update_apies(struct wlan_hdd_link_info *link_info) +{ + uint8_t *genie; + uint16_t total_ielen = 0; + int ret = 0; + struct sap_config *config; + tSirUpdateIE update_ie; + struct hdd_beacon_data *beacon = NULL; + uint16_t proberesp_ies_len; + uint8_t *proberesp_ies = NULL; + mac_handle_t mac_handle; + struct hdd_adapter *adapter = link_info->adapter; + + config = &link_info->session.ap.sap_config; + beacon = link_info->session.ap.beacon; + if (!beacon) { + hdd_err("Beacon is NULL !"); + return -EINVAL; + } + + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (!mac_handle) { + hdd_debug("NULL MAC context"); + return -EINVAL; + } + + genie = qdf_mem_malloc(MAX_GENIE_LEN); + if (!genie) + return -ENOMEM; + + /* Extract and add the extended capabilities and interworking IE */ + wlan_hdd_add_extra_ie(link_info, genie, &total_ielen, + WLAN_EID_EXT_CAPABILITY); + + wlan_hdd_add_extra_ie(link_info, genie, &total_ielen, + WLAN_EID_INTERWORKING); + wlan_hdd_add_extra_ie(link_info, genie, &total_ielen, + WLAN_EID_ADVERTISEMENT_PROTOCOL); + wlan_hdd_add_extra_ie(link_info, genie, + &total_ielen, WLAN_ELEMID_RSNXE); + wlan_hdd_add_extra_ie(link_info, genie, &total_ielen, + WLAN_ELEMID_MOBILITY_DOMAIN); +#ifdef FEATURE_WLAN_WAPI + if (QDF_SAP_MODE == adapter->device_mode) { + wlan_hdd_add_extra_ie(link_info, genie, &total_ielen, + WLAN_ELEMID_WAPI); + } +#endif + /* extract and add rrm ie from hostapd */ + wlan_hdd_add_extra_ie(link_info, genie, + &total_ielen, WLAN_ELEMID_RRM); + + wlan_hdd_add_hostapd_conf_vsie(link_info, genie, + &total_ielen); + + ret = hdd_update_11ax_apies(link_info, genie, &total_ielen); + if (ret) + goto done; + + ret = hdd_update_11be_apies(link_info, genie, &total_ielen); + if (ret) + goto done; + + wlan_hdd_add_sap_obss_scan_ie(link_info, genie, &total_ielen); + + qdf_copy_macaddr(&update_ie.bssid, &adapter->mac_addr); + update_ie.vdev_id = link_info->vdev_id; + + /* Added for Probe Response IE */ + proberesp_ies = qdf_mem_malloc(beacon->proberesp_ies_len + + MAX_GENIE_LEN); + if (!proberesp_ies) { + ret = -EINVAL; + goto done; + } + qdf_mem_copy(proberesp_ies, beacon->proberesp_ies, + beacon->proberesp_ies_len); + proberesp_ies_len = beacon->proberesp_ies_len; + + wlan_hdd_add_sap_obss_scan_ie(link_info, proberesp_ies, + &proberesp_ies_len); + wlan_hdd_add_extra_ie(link_info, proberesp_ies, + &proberesp_ies_len, WLAN_ELEMID_RSNXE); + wlan_hdd_add_extra_ie(link_info, proberesp_ies, + &proberesp_ies_len, WLAN_ELEMID_MOBILITY_DOMAIN); + + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + update_ie.ieBufferlength = proberesp_ies_len; + update_ie.pAdditionIEBuffer = proberesp_ies; + update_ie.append = false; + update_ie.notify = false; + if (sme_update_add_ie(mac_handle, + &update_ie, + eUPDATE_IE_PROBE_RESP) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RESP add Ie data"); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(config, eUPDATE_IE_PROBE_RESP); + } else { + wlansap_update_sap_config_add_ie(config, + proberesp_ies, + proberesp_ies_len, + eUPDATE_IE_PROBE_RESP); + } + + /* Assoc resp Add ie Data */ + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + update_ie.ieBufferlength = beacon->assocresp_ies_len; + update_ie.pAdditionIEBuffer = (uint8_t *) beacon->assocresp_ies; + update_ie.append = false; + update_ie.notify = false; + if (sme_update_add_ie(mac_handle, + &update_ie, + eUPDATE_IE_ASSOC_RESP) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on Add Ie Assoc Response data"); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(config, eUPDATE_IE_ASSOC_RESP); + } else { + wlansap_update_sap_config_add_ie(config, + beacon->assocresp_ies, + beacon->assocresp_ies_len, + eUPDATE_IE_ASSOC_RESP); + } + + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + update_ie.ieBufferlength = total_ielen; + update_ie.pAdditionIEBuffer = genie; + update_ie.append = false; + update_ie.notify = true; + if (sme_update_add_ie(mac_handle, + &update_ie, + eUPDATE_IE_PROBE_BCN) == + QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on Add Ie probe beacon data"); + ret = -EINVAL; + goto done; + } + wlansap_reset_sap_config_add_ie(config, eUPDATE_IE_PROBE_BCN); + } else { + wlansap_update_sap_config_add_ie(config, genie, total_ielen, + eUPDATE_IE_PROBE_BCN); + } + +done: + qdf_mem_free(genie); + qdf_mem_free(proberesp_ies); + return ret; +} + +/** + * wlan_hdd_set_sap_hwmode() - set sap hw mode + * @link_info: Pointer to link_info in hostapd adapter + * + * Return: none + */ +static void wlan_hdd_set_sap_hwmode(struct wlan_hdd_link_info *link_info) +{ + struct sap_config *config = &link_info->session.ap.sap_config; + struct hdd_beacon_data *beacon = link_info->session.ap.beacon; + struct ieee80211_mgmt *mgmt_frame = + (struct ieee80211_mgmt *)beacon->head; + u8 checkRatesfor11g = true; + u8 require_ht = false, require_vht = false; + const u8 *ie; + ssize_t size; + + config->SapHw_mode = eCSR_DOT11_MODE_11b; + + size = beacon->head_len - sizeof(mgmt_frame->u.beacon) - + (sizeof(*mgmt_frame) - sizeof(mgmt_frame->u)); + + if (size <= 0) { + hdd_err_rl("Invalid length: %zu", size); + return; + } + + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_SUPP_RATES, + &mgmt_frame->u.beacon.variable[0], + size); + if (ie) { + ie += 1; + wlan_hdd_check_11gmode(ie, &require_ht, &require_vht, + &checkRatesfor11g, &config->SapHw_mode); + } + + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_EXT_SUPP_RATES, + beacon->tail, beacon->tail_len); + if (ie) { + ie += 1; + wlan_hdd_check_11gmode(ie, &require_ht, &require_vht, + &checkRatesfor11g, &config->SapHw_mode); + } + + if (WLAN_REG_IS_5GHZ_CH_FREQ(config->chan_freq)) + config->SapHw_mode = eCSR_DOT11_MODE_11a; + + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_HT_CAPABILITY, + beacon->tail, beacon->tail_len); + if (ie) { + config->SapHw_mode = eCSR_DOT11_MODE_11n; + if (require_ht) + config->SapHw_mode = eCSR_DOT11_MODE_11n_ONLY; + } + + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_VHT_CAPABILITY, + beacon->tail, beacon->tail_len); + if (ie) { + config->SapHw_mode = eCSR_DOT11_MODE_11ac; + if (require_vht) + config->SapHw_mode = eCSR_DOT11_MODE_11ac_ONLY; + } + + wlan_hdd_check_11ax_support(beacon, config); + + wlan_hdd_check_11be_support(beacon, config); + + hdd_debug("SAP hw_mode: %d", config->SapHw_mode); +} + +/** + * wlan_hdd_config_acs() - config ACS needed parameters + * @hdd_ctx: HDD context + * @adapter: Adapter pointer + * + * This function get ACS related INI parameters and populated + * sap config and smeConfig for ACS needed configurations. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS wlan_hdd_config_acs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sap_config *sap_config; + struct hdd_config *ini_config; + mac_handle_t mac_handle; + + mac_handle = hdd_ctx->mac_handle; + sap_config = &adapter->deflink->session.ap.sap_config; + ini_config = hdd_ctx->config; + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + hdd_debug("HDD_ACS_SKIP_STATUS = %d", hdd_ctx->skip_acs_scan_status); + if (hdd_ctx->skip_acs_scan_status == eSAP_SKIP_ACS_SCAN) { + struct hdd_adapter *con_sap_adapter; + struct sap_config *con_sap_config = NULL; + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, false); + + if (con_sap_adapter) + con_sap_config = + &con_sap_adapter->deflink->session.ap.sap_config; + + sap_config->acs_cfg.skip_scan_status = eSAP_DO_NEW_ACS_SCAN; + + if (con_sap_config && + con_sap_config->acs_cfg.acs_mode == true && + hdd_ctx->skip_acs_scan_status == eSAP_SKIP_ACS_SCAN && + con_sap_config->acs_cfg.hw_mode == + sap_config->acs_cfg.hw_mode) { + uint32_t con_sap_st_ch_freq, con_sap_end_ch_freq; + uint32_t cur_sap_st_ch_freq, cur_sap_end_ch_freq; + uint32_t bandStartChannel, bandEndChannel; + + con_sap_st_ch_freq = + con_sap_config->acs_cfg.start_ch_freq; + con_sap_end_ch_freq = + con_sap_config->acs_cfg.end_ch_freq; + cur_sap_st_ch_freq = + sap_config->acs_cfg.start_ch_freq; + cur_sap_end_ch_freq = + sap_config->acs_cfg.end_ch_freq; + + wlansap_extend_to_acs_range( + mac_handle, &cur_sap_st_ch_freq, + &cur_sap_end_ch_freq, + &bandStartChannel, &bandEndChannel); + + wlansap_extend_to_acs_range( + mac_handle, &con_sap_st_ch_freq, + &con_sap_end_ch_freq, + &bandStartChannel, &bandEndChannel); + + if (con_sap_st_ch_freq <= cur_sap_st_ch_freq && + con_sap_end_ch_freq >= cur_sap_end_ch_freq) { + sap_config->acs_cfg.skip_scan_status = + eSAP_SKIP_ACS_SCAN; + + } else if (con_sap_st_ch_freq >= cur_sap_st_ch_freq && + con_sap_end_ch_freq >= + cur_sap_end_ch_freq) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch_freq; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch_freq - 5; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch_freq <= cur_sap_st_ch_freq && + con_sap_end_ch_freq <= + cur_sap_end_ch_freq) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + con_sap_end_ch_freq + 5; + sap_config->acs_cfg.skip_scan_range1_endch = + cur_sap_end_ch_freq; + sap_config->acs_cfg.skip_scan_range2_stch = + 0; + sap_config->acs_cfg.skip_scan_range2_endch = + 0; + + } else if (con_sap_st_ch_freq >= cur_sap_st_ch_freq && + con_sap_end_ch_freq <= + cur_sap_end_ch_freq) { + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_PAR_ACS_SCAN; + + sap_config->acs_cfg.skip_scan_range1_stch = + cur_sap_st_ch_freq; + sap_config->acs_cfg.skip_scan_range1_endch = + con_sap_st_ch_freq - 5; + sap_config->acs_cfg.skip_scan_range2_stch = + con_sap_end_ch_freq; + sap_config->acs_cfg.skip_scan_range2_endch = + cur_sap_end_ch_freq + 5; + + } else + sap_config->acs_cfg.skip_scan_status = + eSAP_DO_NEW_ACS_SCAN; + + if (sap_config->acs_cfg.skip_scan_status == + eSAP_DO_PAR_ACS_SCAN && + (sap_config->acs_cfg.start_ch_freq > + sap_config->acs_cfg.skip_scan_range1_endch || + sap_config->acs_cfg.end_ch_freq < + sap_config->acs_cfg.skip_scan_range1_stch) && + ((!sap_config->acs_cfg.skip_scan_range2_stch && + !sap_config->acs_cfg.skip_scan_range2_endch) || + (sap_config->acs_cfg.start_ch_freq > + sap_config->acs_cfg.skip_scan_range2_endch || + sap_config->acs_cfg.end_ch_freq < + sap_config->acs_cfg.skip_scan_range2_stch))) { + hdd_debug("Skip partial scan range1/2 out of ACS"); + sap_config->acs_cfg.skip_scan_status = + eSAP_SKIP_ACS_SCAN; + } + + hdd_debug("SecAP ACS Skip=%d, ACS CH RANGE=%d-%d, %d-%d", + sap_config->acs_cfg.skip_scan_status, + sap_config->acs_cfg.skip_scan_range1_stch, + sap_config->acs_cfg.skip_scan_range1_endch, + sap_config->acs_cfg.skip_scan_range2_stch, + sap_config->acs_cfg.skip_scan_range2_endch); + } + } +#endif + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_sap_p2p_11ac_overrides: API to overwrite 11ac config in case of + * SAP or p2p go + * @ap_adapter: pointer to adapter + * + * This function overrides SAP / P2P Go configuration based on driver INI + * parameters for 11AC override and ACS. This overrides are done to support + * android legacy configuration method. + * + * NOTE: Non android platform supports concurrency and these overrides shall + * not be used. Also future driver based overrides shall be consolidated in this + * function only. Avoid random overrides in other location based on ini. + * + * Return: 0 for Success or Negative error codes. + */ +static int wlan_hdd_sap_p2p_11ac_overrides(struct hdd_adapter *ap_adapter) +{ + struct sap_config *sap_cfg = + &ap_adapter->deflink->session.ap.sap_config; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + uint8_t ch_width; + uint8_t sub_20_chan_width; + QDF_STATUS status; + bool sap_force_11n_for_11ac = 0; + bool go_force_11n_for_11ac = 0; + uint32_t channel_bonding_mode; + bool go_11ac_override = 0; + bool sap_11ac_override = 0; + + /* + * No need to override for Go/Sap on 6 GHz band + */ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_cfg->chan_freq)) + return 0; + + ucfg_mlme_get_sap_force_11n_for_11ac(hdd_ctx->psoc, + &sap_force_11n_for_11ac); + ucfg_mlme_get_go_force_11n_for_11ac(hdd_ctx->psoc, + &go_force_11n_for_11ac); + + /* Fixed channel 11AC override: + * 11AC override in qcacld is introduced for following reasons: + * 1. P2P GO also follows start_bss and since p2p GO could not be + * configured to setup VHT channel width in wpa_supplicant + * 2. Android UI does not provide advanced configuration options for SAP + * + * Default override enabled (for android). MDM shall disable this in ini + */ + /* + * sub_20 MHz channel width is incompatible with 11AC rates, hence do + * not allow 11AC rates or more than 20 MHz channel width when + * enable_sub_20_channel_width is non zero + */ + status = ucfg_mlme_get_sub_20_chan_width(hdd_ctx->psoc, + &sub_20_chan_width); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get sub_20_chan_width config"); + return -EIO; + } + + ucfg_mlme_is_go_11ac_override(hdd_ctx->psoc, + &go_11ac_override); + ucfg_mlme_is_sap_11ac_override(hdd_ctx->psoc, + &sap_11ac_override); + + if (!sub_20_chan_width && + (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ax || + sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11ax_ONLY) && + ((ap_adapter->device_mode == QDF_SAP_MODE && + !sap_force_11n_for_11ac && + sap_11ac_override) || + (ap_adapter->device_mode == QDF_P2P_GO_MODE && + !go_force_11n_for_11ac && + go_11ac_override))) { + hdd_debug("** Driver force 11AC override for SAP/Go **"); + + /* 11n only shall not be overridden since it may be on purpose*/ + if (sap_cfg->SapHw_mode == eCSR_DOT11_MODE_11n) + sap_cfg->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sap_cfg->chan_freq)) { + status = + ucfg_mlme_get_vht_channel_width(hdd_ctx->psoc, + &ch_width); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set channel_width"); + sap_cfg->ch_width_orig = ch_width; + } else { + /* + * Allow 40 Mhz in 2.4 Ghz only if indicated by + * supplicant after OBSS scan and if 2.4 Ghz channel + * bonding is set in INI + */ + ucfg_mlme_get_channel_bonding_24ghz( + hdd_ctx->psoc, &channel_bonding_mode); + if (sap_cfg->ch_width_orig >= CH_WIDTH_40MHZ && + channel_bonding_mode) + sap_cfg->ch_width_orig = + CH_WIDTH_40MHZ; + else + sap_cfg->ch_width_orig = + CH_WIDTH_20MHZ; + } + } + + return 0; +} + +/** + * wlan_hdd_setup_driver_overrides : Overrides SAP / P2P GO Params + * @ap_adapter: pointer to adapter struct + * + * This function overrides SAP / P2P Go configuration based on driver INI + * parameters for 11AC override and ACS. These overrides are done to support + * android legacy configuration method. + * + * NOTE: Non android platform supports concurrency and these overrides shall + * not be used. Also future driver based overrides shall be consolidated in this + * function only. Avoid random overrides in other location based on ini. + * + * Return: 0 for Success or Negative error codes. + */ +static int wlan_hdd_setup_driver_overrides(struct hdd_adapter *ap_adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + QDF_STATUS qdf_status; + bool is_vendor_acs_support = + cfg_default(CFG_USER_AUTO_CHANNEL_SELECTION); + + qdf_status = ucfg_mlme_get_vendor_acs_support(hdd_ctx->psoc, + &is_vendor_acs_support); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("get_vendor_acs_support failed, set default"); + + if (!is_vendor_acs_support) + return wlan_hdd_sap_p2p_11ac_overrides(ap_adapter); + else + return 0; +} + +void +hdd_check_and_disconnect_sta_on_invalid_channel(struct hdd_context *hdd_ctx, + enum wlan_reason_code reason) +{ + struct hdd_adapter *sta_adapter; + uint32_t sta_chan_freq; + struct wlan_hdd_link_info *link_info; + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + + if (!sta_adapter) { + hdd_err("STA adapter does not exist"); + return; + } + + hdd_adapter_for_each_active_link_info(sta_adapter, link_info) { + sta_chan_freq = hdd_get_link_info_home_channel(link_info); + if (!sta_chan_freq) + continue; + + hdd_err("VDEV-%d STA connected on %d", + link_info->vdev_id, sta_chan_freq); + + if (sme_is_channel_valid(hdd_ctx->mac_handle, sta_chan_freq)) + continue; + + hdd_err("chan %d not valid, issue disconnect", sta_chan_freq); + wlan_hdd_cm_issue_disconnect(link_info, reason, false); + } +} + +/** + * hdd_handle_acs_2g_preferred_sap_conc() - Handle 2G pereferred SAP + * concurrency with GO + * @psoc: soc object + * @adapter: SAP adapter + * @sap_config: sap config + * + * In GO+STA+SAP concurrency, if GO is started on 2G and SAP is doing ACS + * with 2G preferred channel list, then we will move GO to 2G SCC + * channel of STA if present. + * The purpose is to avoid SAP start failure on 2G because we don't + * support 3 home channels in same mac. + * + * Return: void + */ +void +hdd_handle_acs_2g_preferred_sap_conc(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct sap_config *sap_config) +{ + uint32_t i; + int ret; + QDF_STATUS status; + uint32_t *ch_freq_list; + struct sap_acs_cfg *acs_cfg; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_num; + uint8_t sta_vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t sta_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t sta_vdev_num; + struct hdd_hostapd_state *hostapd_state; + uint8_t go_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + qdf_freq_t go_ch_freq = 0, go_new_ch_freq = 0; + struct wlan_hdd_link_info *go_link_info; + enum phy_ch_width go_bw; + + if (adapter->device_mode != QDF_SAP_MODE) + return; + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return; + + acs_cfg = &sap_config->acs_cfg; + if (!acs_cfg->master_ch_list_count) + return; + ch_freq_list = acs_cfg->master_freq_list; + for (i = 0; i < acs_cfg->master_ch_list_count; i++) + if (!WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq_list[i])) + return; + + /* Move existing GO interface to SCC channel of 2G STA */ + vdev_num = policy_mgr_get_mode_specific_conn_info( + psoc, freq_list, vdev_id_list, + PM_P2P_GO_MODE); + if (!vdev_num || vdev_num > 1) + return; + for (i = 0; i < vdev_num; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq_list[i])) { + go_vdev_id = vdev_id_list[i]; + go_ch_freq = freq_list[i]; + break; + } + } + if (!go_ch_freq) + return; + sta_vdev_num = policy_mgr_get_mode_specific_conn_info( + psoc, sta_freq_list, sta_vdev_id_list, + PM_STA_MODE); + for (i = 0; i < sta_vdev_num; i++) { + if (go_ch_freq == sta_freq_list[i]) + return; + if (WLAN_REG_IS_24GHZ_CH_FREQ(sta_freq_list[i])) + go_new_ch_freq = sta_freq_list[i]; + } + + if (!go_new_ch_freq) + return; + + go_link_info = hdd_get_link_info_by_vdev(adapter->hdd_ctx, go_vdev_id); + if (!go_link_info || hdd_validate_adapter(go_link_info->adapter)) + return; + + wlan_hdd_set_sap_csa_reason(psoc, go_vdev_id, + CSA_REASON_SAP_ACS); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(go_link_info); + qdf_event_reset(&hostapd_state->qdf_event); + go_bw = wlansap_get_chan_width(WLAN_HDD_GET_SAP_CTX_PTR(go_link_info)); + ret = hdd_softap_set_channel_change(go_link_info->adapter->dev, + go_new_ch_freq, go_bw, + false); + if (ret) { + hdd_err("CSA failed to %d, ret %d", go_new_ch_freq, ret); + return; + } + + status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("wait for qdf_event failed!!"); +} + +/** + * hdd_handle_p2p_go_for_3rd_ap_conc() - Move P2P GO to other band if + * SAP starting + * @hdd_ctx: Global HDD context pointer + * @sap_ch_freq: sap channel frequency + * + * In GO+STA+SAP concurrency, if GO is MCC with STA, the new SAP + * will not be allowed in same MAC. FW doesn't support MCC in same + * MAC for 3 or more vdevs. Move GO to other band to avoid SAP + * starting failed. + * + * Return: true if GO is moved to other band successfully. + */ +static bool +hdd_handle_p2p_go_for_3rd_ap_conc(struct hdd_context *hdd_ctx, + uint32_t sap_ch_freq) +{ + uint32_t i; + int ret; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + uint8_t go_vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t go_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t go_vdev_num; + uint8_t sta_vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t sta_freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t sta_vdev_num; + struct hdd_hostapd_state *hostapd_state; + uint8_t go_vdev_id; + qdf_freq_t go_ch_freq, go_new_ch_freq; + struct wlan_hdd_link_info *go_link_info; + + if (!policy_mgr_is_hw_dbs_capable(psoc)) + return false; + go_vdev_num = policy_mgr_get_mode_specific_conn_info( + psoc, go_freq_list, go_vdev_id_list, + PM_P2P_GO_MODE); + if (!go_vdev_num || go_vdev_num > 1) + return false; + + if (!policy_mgr_2_freq_always_on_same_mac( + psoc, go_freq_list[0], sap_ch_freq)) + return false; + + sta_vdev_num = policy_mgr_get_mode_specific_conn_info( + psoc, sta_freq_list, sta_vdev_id_list, + PM_STA_MODE); + if (!sta_vdev_num) + return false; + for (i = 0; i < sta_vdev_num; i++) { + if (go_freq_list[0] != sta_freq_list[i] && + policy_mgr_2_freq_always_on_same_mac( + psoc, go_freq_list[0], sta_freq_list[i])) + break; + } + if (i == sta_vdev_num) + return false; + go_ch_freq = go_freq_list[0]; + go_vdev_id = go_vdev_id_list[0]; + go_new_ch_freq = + policy_mgr_get_alternate_channel_for_sap(psoc, + go_vdev_id, + go_ch_freq, + REG_BAND_UNKNOWN); + if (!go_new_ch_freq) { + hdd_debug("no alternate GO channel"); + return false; + } + if (go_new_ch_freq != sta_freq_list[i] && + policy_mgr_3_freq_always_on_same_mac( + psoc, sap_ch_freq, go_new_ch_freq, sta_freq_list[i])) { + hdd_debug("no alternate GO channel to avoid 3vif MCC"); + return false; + } + + go_link_info = hdd_get_link_info_by_vdev(hdd_ctx, go_vdev_id); + if (!go_link_info || hdd_validate_adapter(go_link_info->adapter)) + return false; + + wlan_hdd_set_sap_csa_reason(psoc, go_vdev_id, + CSA_REASON_SAP_FIX_CH_CONC_WITH_GO); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(go_link_info); + qdf_event_reset(&hostapd_state->qdf_event); + + ret = hdd_softap_set_channel_change(go_link_info->adapter->dev, + go_new_ch_freq, CH_WIDTH_80MHZ, + false); + if (ret) { + hdd_err("CSA failed to %d, ret %d", go_new_ch_freq, ret); + return false; + } + + status = qdf_wait_for_event_completion(&hostapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("wait for qdf_event failed!!"); + + return true; +} + +#ifdef DISABLE_CHANNEL_LIST +/** + * wlan_hdd_get_wiphy_channel() - Get wiphy channel + * @wiphy: Pointer to wiphy structure + * @freq: Frequency of the channel for which the wiphy hw value is required + * + * Return: wiphy channel for valid frequency else return NULL + */ +static struct ieee80211_channel *wlan_hdd_get_wiphy_channel( + struct wiphy *wiphy, + uint32_t freq) +{ + uint32_t band_num, channel_num; + struct ieee80211_channel *wiphy_channel = NULL; + + for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) { + if (!wiphy->bands[band_num]) { + hdd_debug("Band %d not part of wiphy", band_num); + continue; + } + for (channel_num = 0; channel_num < + wiphy->bands[band_num]->n_channels; + channel_num++) { + wiphy_channel = &(wiphy->bands[band_num]-> + channels[channel_num]); + if (wiphy_channel->center_freq == freq) + return wiphy_channel; + } + } + return wiphy_channel; +} + +int wlan_hdd_restore_channels(struct hdd_context *hdd_ctx) +{ + struct hdd_cache_channels *cache_chann; + struct wiphy *wiphy; + int freq, status; + int i; + struct ieee80211_channel *wiphy_channel = NULL; + + hdd_enter(); + + if (!hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + wiphy = hdd_ctx->wiphy; + if (!wiphy) { + hdd_err("Wiphy is NULL"); + return -EINVAL; + } + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + + cache_chann = hdd_ctx->original_channels; + + if (!cache_chann || !cache_chann->num_channels) { + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + hdd_nofl_debug("channel list is NULL or num channels are zero"); + return -EINVAL; + } + + for (i = 0; i < cache_chann->num_channels; i++) { + freq = cache_chann->channel_info[i].freq; + if (!freq) + continue; + + wiphy_channel = wlan_hdd_get_wiphy_channel(wiphy, freq); + if (!wiphy_channel) + continue; + /* + * Restore the original states of the channels + * only if we have cached non zero values + */ + wiphy_channel->flags = + cache_chann->channel_info[i].wiphy_status; + + hdd_debug("Restore channel_freq %d reg_stat %d wiphy_stat 0x%x", + cache_chann->channel_info[i].freq, + cache_chann->channel_info[i].reg_status, + wiphy_channel->flags); + } + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + ucfg_reg_restore_cached_channels(hdd_ctx->pdev); + status = sme_update_channel_list(hdd_ctx->mac_handle); + if (status) + hdd_err("Can't Restore channel list"); + else + /* + * Free the cache channels when the + * disabled channels are restored + */ + wlan_hdd_free_cache_channels(hdd_ctx); + hdd_exit(); + return 0; +} + +int wlan_hdd_disable_channels(struct hdd_context *hdd_ctx) +{ + struct hdd_cache_channels *cache_chann; + struct wiphy *wiphy; + int freq, status; + int i; + struct ieee80211_channel *wiphy_channel = NULL; + + hdd_enter(); + + if (!hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + wiphy = hdd_ctx->wiphy; + if (!wiphy) { + hdd_err("Wiphy is NULL"); + return -EINVAL; + } + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + cache_chann = hdd_ctx->original_channels; + + if (!cache_chann || !cache_chann->num_channels) { + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + hdd_err("channel list is NULL or num channels are zero"); + return -EINVAL; + } + + for (i = 0; i < cache_chann->num_channels; i++) { + freq = cache_chann->channel_info[i].freq; + if (!freq) + continue; + wiphy_channel = wlan_hdd_get_wiphy_channel(wiphy, freq); + if (!wiphy_channel) + continue; + /* + * Cache the current states of + * the channels + */ + cache_chann->channel_info[i].reg_status = + wlan_reg_get_channel_state_from_secondary_list_for_freq( + hdd_ctx->pdev, + freq); + cache_chann->channel_info[i].wiphy_status = + wiphy_channel->flags; + hdd_debug("Disable channel_freq %d reg_stat %d wiphy_stat 0x%x", + cache_chann->channel_info[i].freq, + cache_chann->channel_info[i].reg_status, + wiphy_channel->flags); + + wiphy_channel->flags |= IEEE80211_CHAN_DISABLED; + } + + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + ucfg_reg_disable_cached_channels(hdd_ctx->pdev); + status = sme_update_channel_list(hdd_ctx->mac_handle); + + hdd_exit(); + return status; +} +#else +int wlan_hdd_disable_channels(struct hdd_context *hdd_ctx) +{ + return 0; +} + +int wlan_hdd_restore_channels(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#ifdef DHCP_SERVER_OFFLOAD +static void +wlan_hdd_set_dhcp_server_offload(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx; + struct dhcp_offload_info_params dhcp_srv_info; + uint8_t num_entries = 0; + uint8_t *srv_ip; + uint8_t num; + uint32_t temp; + uint32_t dhcp_max_num_clients; + mac_handle_t mac_handle; + QDF_STATUS status; + + hdd_ctx = link_info->adapter->hdd_ctx; + if (!hdd_ctx->config->dhcp_server_ip.is_dhcp_server_ip_valid) + return; + + srv_ip = hdd_ctx->config->dhcp_server_ip.dhcp_server_ip; + dhcp_srv_info.vdev_id = link_info->vdev_id; + dhcp_srv_info.dhcp_offload_enabled = true; + + status = ucfg_fwol_get_dhcp_max_num_clients(hdd_ctx->psoc, + &dhcp_max_num_clients); + if (QDF_IS_STATUS_ERROR(status)) + return; + + dhcp_srv_info.dhcp_client_num = dhcp_max_num_clients; + + if ((srv_ip[0] >= 224) && (srv_ip[0] <= 239)) { + hdd_err("Invalid IP address (%d)! It could NOT be multicast IP address!", + srv_ip[0]); + return; + } + + if (srv_ip[IPADDR_NUM_ENTRIES - 1] >= 100) { + hdd_err("Invalid IP address (%d)! The last field must be less than 100!", + srv_ip[IPADDR_NUM_ENTRIES - 1]); + return; + } + + dhcp_srv_info.dhcp_srv_addr = 0; + for (num = 0; num < num_entries; num++) { + temp = srv_ip[num]; + dhcp_srv_info.dhcp_srv_addr |= (temp << (8 * num)); + } + + mac_handle = hdd_ctx->mac_handle; + status = sme_set_dhcp_srv_offload(mac_handle, &dhcp_srv_info); + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_debug("enable DHCP Server offload successfully!"); + else + hdd_err("sme_set_dhcp_srv_offload fail!"); +} + +/** + * wlan_hdd_dhcp_offload_enable: Enable DHCP offload + * @link_info: Pointer of link_info in adapter + * + * Enables the DHCP Offload feature in firmware if it has been configured. + * + * Return: None + */ +static void wlan_hdd_dhcp_offload_enable(struct wlan_hdd_link_info *link_info) +{ + bool enable_dhcp_server_offload; + QDF_STATUS status; + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + + status = ucfg_fwol_get_enable_dhcp_server_offload( + hdd_ctx->psoc, + &enable_dhcp_server_offload); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (enable_dhcp_server_offload) + wlan_hdd_set_dhcp_server_offload(link_info); +} +#else +static inline void +wlan_hdd_dhcp_offload_enable(struct wlan_hdd_link_info *link_info) +{ +} +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +static void wlan_hdd_set_sap_mcc_chnl_avoid(struct hdd_context *hdd_ctx) +{ + uint8_t sap_mcc_avoid = 0; + QDF_STATUS status; + + status = ucfg_mlme_get_sap_mcc_chnl_avoid(hdd_ctx->psoc, + &sap_mcc_avoid); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("can't get sap mcc chnl avoid, use def"); + wlan_sap_set_channel_avoidance(hdd_ctx->mac_handle, sap_mcc_avoid); +} +#else +static void wlan_hdd_set_sap_mcc_chnl_avoid(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_hdd_mlo_update() - handle mlo scenario for start bss + * @link_info: Pointer to hostapd adapter + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_hdd_mlo_update(struct wlan_hdd_link_info *link_info) +{ + bool is_ml_ap; + uint8_t link_id = 0, num_link = 0; + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + struct sap_config *config = &link_info->session.ap.sap_config; + struct hdd_beacon_data *beacon = link_info->session.ap.beacon; + + if (config->SapHw_mode == eCSR_DOT11_MODE_11be || + config->SapHw_mode == eCSR_DOT11_MODE_11be_ONLY) { + wlan_hdd_get_mlo_link_id(beacon, &link_id, &num_link); + hdd_debug("MLO SAP vdev id %d, link id %d total link %d", + link_info->vdev_id, link_id, num_link); + if (!num_link || !link_info->vdev->mlo_dev_ctx || + !link_info->vdev->mlo_dev_ctx->ap_ctx) { + hdd_debug("start 11be AP without mlo"); + return QDF_STATUS_SUCCESS; + } + if (!mlo_ap_vdev_attach(link_info->vdev, link_id, num_link)) { + hdd_err("MLO SAP attach fails"); + return QDF_STATUS_E_INVAL; + } + + config->mlo_sap = true; + config->link_id = link_id; + config->num_link = num_link; + } + + is_ml_ap = wlan_vdev_mlme_is_mlo_ap(link_info->vdev); + if (!policy_mgr_is_mlo_sap_concurrency_allowed(hdd_ctx->psoc, + is_ml_ap, + wlan_vdev_get_id(link_info->vdev))) { + hdd_err("MLO SAP concurrency check fails"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_mlo_reset(struct wlan_hdd_link_info *link_info) +{ + struct sap_config *sap_config; + + if (!wlan_vdev_mlme_is_mlo_ap(link_info->vdev)) + return; + + sap_config = &link_info->session.ap.sap_config; + sap_config->mlo_sap = false; + sap_config->link_id = 0; + sap_config->num_link = 0; + mlo_ap_vdev_detach(link_info->vdev); +} +#else +static inline QDF_STATUS +wlan_hdd_mlo_update(struct wlan_hdd_link_info *link_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static void +hdd_softap_update_pasn_vdev_params(struct hdd_context *hdd_ctx, + uint8_t vdev_id, + struct hdd_beacon_data *beacon, + bool mfp_capable, bool mfp_required) +{ + uint32_t pasn_vdev_param = 0; + const uint8_t *rsnx_ie, *rsnxe_cap; + uint8_t cap_len; + + if (mfp_capable) + pasn_vdev_param |= WLAN_CRYPTO_MFPC; + + if (mfp_required) + pasn_vdev_param |= WLAN_CRYPTO_MFPR; + + rsnx_ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, + beacon->tail, beacon->tail_len); + if (!rsnx_ie) + return; + + rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnx_ie, &cap_len); + if (rsnxe_cap && *rsnxe_cap & WLAN_CRYPTO_RSNX_CAP_URNM_MFPR) + pasn_vdev_param |= WLAN_CRYPTO_URNM_MFPR; + + wlan_crypto_vdev_set_param(hdd_ctx->psoc, vdev_id, + wmi_vdev_param_11az_security_config, + pasn_vdev_param); +} + +#ifdef QCA_MULTIPASS_SUPPORT +static void +wlan_hdd_set_multipass(struct wlan_objmgr_vdev *vdev) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + cdp_config_param_type vdev_param; + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + vdev_param.cdp_vdev_param_update_multipass = true; + cdp_txrx_set_vdev_param(soc, vdev_id, CDP_UPDATE_MULTIPASS, vdev_param); +} +#else +static void +wlan_hdd_set_multipass(struct wlan_objmgr_vdev *vdev) +{ +} +#endif + +static void wlan_hdd_update_ll_lt_sap_configs(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct sap_config *config) +{ + if (!policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) + return; + + config->SapHw_mode = eCSR_DOT11_MODE_11n; + config->ch_width_orig = CH_WIDTH_20MHZ; +} + +/** + * wlan_hdd_cfg80211_start_bss() - start bss + * @link_info: Link info pointer in HDD adapter + * @params: Pointer to start bss beacon parameters + * @ssid: Pointer ssid + * @ssid_len: Length of ssid + * @hidden_ssid: Hidden SSID parameter + * @check_for_concurrency: Flag to indicate if check for concurrency is needed + * + * Return: 0 for success non-zero for failure + */ +int wlan_hdd_cfg80211_start_bss(struct wlan_hdd_link_info *link_info, + struct cfg80211_beacon_data *params, + const u8 *ssid, size_t ssid_len, + enum nl80211_hidden_ssid hidden_ssid, + bool check_for_concurrency) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct sap_config *config; + struct hdd_beacon_data *beacon = NULL; + struct ieee80211_mgmt *mgmt_frame; + struct ieee80211_mgmt mgmt; + const uint8_t *ie = NULL; + eCsrEncryptionType rsn_encrypt_type; + eCsrEncryptionType mc_rsn_encrypt_type; + uint16_t capab_info; + int status = QDF_STATUS_SUCCESS, ret; + int qdf_status = QDF_STATUS_SUCCESS; + sap_event_cb sap_event_callback; + struct hdd_hostapd_state *hostapd_state; + mac_handle_t mac_handle; + int32_t i; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t mcc_to_scc_switch = 0, conc_rule1 = 0; + struct sme_config_params *sme_config = NULL; + bool mfp_capable = false; + bool mfp_required = false; + uint16_t prev_rsn_length = 0; + enum dfs_mode mode; + bool ignore_cac = 0; + uint8_t beacon_fixed_len, indoor_chnl_marking = 0; + bool sap_force_11n_for_11ac = 0; + bool go_force_11n_for_11ac = 0; + bool bval = false; + bool enable_dfs_scan = true; + bool deliver_start_evt = true; + enum reg_phymode reg_phy_mode, updated_phy_mode; + struct sap_context *sap_ctx; + struct wlan_objmgr_vdev *vdev; + uint32_t user_config_freq = 0; + struct hdd_ap_ctx *ap_ctx; + enum policy_mgr_con_mode pm_con_mode; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) + return -EINVAL; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + ucfg_mlme_get_sap_force_11n_for_11ac(hdd_ctx->psoc, + &sap_force_11n_for_11ac); + ucfg_mlme_get_go_force_11n_for_11ac(hdd_ctx->psoc, + &go_force_11n_for_11ac); + + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) + deliver_start_evt = false; + + if (deliver_start_evt) { + status = ucfg_if_mgr_deliver_event( + vdev, WLAN_IF_MGR_EV_AP_START_BSS, + NULL); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("start bss failed!!"); + ret = -EINVAL; + goto deliver_start_err; + } + } + + /* + * For STA+SAP/GO concurrency support from GUI, In case if + * START AP/GO request comes just before the SAE authentication + * completion on STA, SAE AUTH REQ waits for START AP RSP and + * START AP RSP waits to complete SAE AUTH REQ. + * Driver completes START AP RSP only upon SAE AUTH REQ timeout(5 sec) + * as start ap will be in serialization pending queue, and SAE auth + * sequence cannot complete as hostap thread is blocked in start ap + * cfg80211 ops. + * To avoid above deadlock until SAE timeout, abort the SAE connection + * immediately and complete START AP/GO asap so that the upper layer + * can trigger a fresh connection after START AP/GO completion. + */ + hdd_abort_ongoing_sta_sae_connection(hdd_ctx); + + mac_handle = hdd_ctx->mac_handle; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + ret = -ENOMEM; + goto free; + } + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + + config = &ap_ctx->sap_config; + if (!config->chan_freq) { + hdd_err("Invalid channel"); + ret = -EINVAL; + goto free; + } + + user_config_freq = config->chan_freq; + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_indoor_chnl_marking(hdd_ctx->psoc, + &indoor_chnl_marking)) + hdd_err("can't get indoor channel marking, using default"); + /* Mark the indoor channel (passive) to disable */ + if (indoor_chnl_marking && adapter->device_mode == QDF_SAP_MODE) { + hdd_update_indoor_channel(hdd_ctx, true); + if (QDF_IS_STATUS_ERROR( + sme_update_channel_list(mac_handle))) { + hdd_update_indoor_channel(hdd_ctx, false); + hdd_err("Can't start BSS: update channel list failed"); + ret = -EINVAL; + goto free; + } + + /* check if STA is on indoor channel*/ + if (policy_mgr_is_force_scc(hdd_ctx->psoc)) + hdd_check_and_disconnect_sta_on_invalid_channel( + hdd_ctx, + REASON_OPER_CHANNEL_DISABLED_INDOOR); + } + + beacon = ap_ctx->beacon; + + /* + * beacon_fixed_len is the fixed length of beacon + * frame which includes only mac header length and + * beacon manadatory fields like timestamp, + * beacon_int and capab_info. + * (From the reference of struct ieee80211_mgmt) + */ + beacon_fixed_len = sizeof(mgmt) - sizeof(mgmt.u) + + sizeof(mgmt.u.beacon); + if (beacon->head_len < beacon_fixed_len) { + hdd_err("Invalid beacon head len"); + ret = -EINVAL; + goto error; + } + + mgmt_frame = (struct ieee80211_mgmt *)beacon->head; + + config->beacon_int = mgmt_frame->u.beacon.beacon_int; + config->dfs_cac_offload = hdd_ctx->dfs_cac_offload; + config->dtim_period = beacon->dtim_period; + + if (config->acs_cfg.acs_mode == true) { + hdd_debug("acs_chan_freq %u, acs_dfs_mode %u", + hdd_ctx->acs_policy.acs_chan_freq, + hdd_ctx->acs_policy.acs_dfs_mode); + + if (hdd_ctx->acs_policy.acs_chan_freq) + config->chan_freq = hdd_ctx->acs_policy.acs_chan_freq; + mode = hdd_ctx->acs_policy.acs_dfs_mode; + config->acs_dfs_mode = wlan_hdd_get_dfs_mode(mode); + } + ucfg_util_vdev_mgr_set_acs_mode_for_vdev(vdev, + config->acs_cfg.acs_mode); + + ucfg_policy_mgr_get_mcc_scc_switch(hdd_ctx->psoc, &mcc_to_scc_switch); + + wlan_hdd_set_sap_beacon_protection(hdd_ctx, link_info, beacon); + + /* Overwrite second AP's channel with first only when: + * 1. If operating mode is single mac + * 2. or if 2nd AP is coming up on 5G band channel + */ + ret = 0; + if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) || + !WLAN_REG_IS_24GHZ_CH_FREQ(config->chan_freq)) { + ret = wlan_hdd_sap_cfg_dfs_override(adapter); + if (ret < 0) + goto error; + } + + config->chan_freq = wlan_ll_lt_sap_override_freq(hdd_ctx->psoc, + link_info->vdev_id, + config->chan_freq); + + if (!ret && wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, config->chan_freq)) + hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + + if (QDF_STATUS_SUCCESS != + wlan_hdd_validate_operation_channel(hdd_ctx, config->chan_freq)) { + hdd_err("Invalid Ch_freq: %d", config->chan_freq); + ret = -EINVAL; + goto error; + } + ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc, + &enable_dfs_scan); + + /* reject SAP if DFS channel scan is not allowed */ + if (!enable_dfs_scan && + CHANNEL_STATE_DFS == + wlan_reg_get_channel_state_from_secondary_list_for_freq(hdd_ctx->pdev, + config->chan_freq)) { + hdd_err("No SAP start on DFS channel"); + ret = -EOPNOTSUPP; + goto error; + } + + status = ucfg_mlme_get_dfs_ignore_cac(hdd_ctx->psoc, &ignore_cac); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("can't get ignore cac flag"); + + wlansap_set_dfs_ignore_cac(mac_handle, ignore_cac); + wlansap_set_dfs_preferred_channel_location(mac_handle); + wlan_hdd_set_sap_mcc_chnl_avoid(hdd_ctx); + + tgt_dfs_set_tx_leakage_threshold(hdd_ctx->pdev); + + capab_info = mgmt_frame->u.beacon.capab_info; + + config->privacy = (mgmt_frame->u.beacon.capab_info & + WLAN_CAPABILITY_PRIVACY) ? true : false; + + ap_ctx->privacy = config->privacy; + + /*Set wps station to configured */ + ie = wlan_hdd_get_wps_ie_ptr(beacon->tail, beacon->tail_len); + + if (ie) { + /* To access ie[15], length needs to be at least 14 */ + if (ie[1] < 14) { + hdd_err("Wps Ie Length(%hhu) is too small", + ie[1]); + ret = -EINVAL; + goto error; + } else if (memcmp(&ie[2], WPS_OUI_TYPE, WPS_OUI_TYPE_SIZE) == + 0) { + hdd_debug("WPS IE(len %d)", (ie[1] + 2)); + /* Check 15 bit of WPS IE as it contain information for + * wps state + */ + if (SAP_WPS_ENABLED_UNCONFIGURED == ie[15]) { + config->wps_state = + SAP_WPS_ENABLED_UNCONFIGURED; + } else if (SAP_WPS_ENABLED_CONFIGURED == ie[15]) { + config->wps_state = SAP_WPS_ENABLED_CONFIGURED; + } + } + } else { + config->wps_state = SAP_WPS_DISABLED; + } + + ap_ctx->encryption_type = eCSR_ENCRYPT_TYPE_NONE; + config->RSNWPAReqIELength = 0; + memset(&config->RSNWPAReqIE[0], 0, sizeof(config->RSNWPAReqIE)); + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_RSN, beacon->tail, + beacon->tail_len); + /* the RSN and WAPI are not coexisting, so we can check the + * WAPI IE if the RSN IE is not set. + */ + if (!ie) + ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_WAPI, beacon->tail, + beacon->tail_len); + + if (ie && ie[1]) { + config->RSNWPAReqIELength = ie[1] + 2; + if (config->RSNWPAReqIELength < sizeof(config->RSNWPAReqIE)) + memcpy(&config->RSNWPAReqIE[0], ie, + config->RSNWPAReqIELength); + else + hdd_err("RSN/WPA/WAPI IE MAX Length exceeded; length =%d", + config->RSNWPAReqIELength); + /* The actual processing may eventually be more extensive than + * this. Right now, just consume any PMKIDs that are sent in + * by the app. + */ + status = + hdd_softap_unpack_ie(cds_get_context + (QDF_MODULE_ID_SME), + &rsn_encrypt_type, + &mc_rsn_encrypt_type, + &config->akm_list, + &mfp_capable, + &mfp_required, + config->RSNWPAReqIE[1] + 2, + config->RSNWPAReqIE); + if (status != QDF_STATUS_SUCCESS) { + ret = -EINVAL; + goto error; + } else { + /* Now copy over all the security attributes you have + * parsed out. Use the cipher type in the RSN IE + */ + ap_ctx->encryption_type = rsn_encrypt_type; + hdd_debug("CSR Encryption: %d mcEncryption: %d num_akm_suites:%d", + rsn_encrypt_type, mc_rsn_encrypt_type, + config->akm_list.numEntries); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + config->akm_list.authType, + config->akm_list.numEntries); + + hdd_softap_update_pasn_vdev_params( + hdd_ctx, link_info->vdev_id, + beacon, mfp_capable, mfp_required); + } + } + + ie = wlan_get_vendor_ie_ptr_from_oui(WPA_OUI_TYPE, WPA_OUI_TYPE_SIZE, + beacon->tail, beacon->tail_len); + + if (ie && ie[1] && (ie[0] == DOT11F_EID_WPA)) { + if (config->RSNWPAReqIE[0]) { + /*Mixed mode WPA/WPA2 */ + prev_rsn_length = config->RSNWPAReqIELength; + config->RSNWPAReqIELength += ie[1] + 2; + if (config->RSNWPAReqIELength < + sizeof(config->RSNWPAReqIE)) + memcpy(&config->RSNWPAReqIE[0] + + prev_rsn_length, ie, ie[1] + 2); + else + hdd_err("RSNWPA IE MAX Length exceeded; length: %d", + config->RSNWPAReqIELength); + } else { + config->RSNWPAReqIELength = ie[1] + 2; + if (config->RSNWPAReqIELength < + sizeof(config->RSNWPAReqIE)) + memcpy(&config->RSNWPAReqIE[0], ie, + config->RSNWPAReqIELength); + else + hdd_err("RSNWPA IE MAX Length exceeded; length: %d", + config->RSNWPAReqIELength); + status = hdd_softap_unpack_ie + (cds_get_context(QDF_MODULE_ID_SME), + &rsn_encrypt_type, + &mc_rsn_encrypt_type, + &config->akm_list, + &mfp_capable, &mfp_required, + config->RSNWPAReqIE[1] + 2, + config->RSNWPAReqIE); + + if (status != QDF_STATUS_SUCCESS) { + ret = -EINVAL; + goto error; + } else { + ap_ctx->encryption_type = rsn_encrypt_type; + hdd_debug("CSR Encryption: %d mcEncryption: %d num_akm_suites:%d", + rsn_encrypt_type, mc_rsn_encrypt_type, + config->akm_list.numEntries); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + config->akm_list.authType, + config->akm_list.numEntries); + } + } + } + + if (config->RSNWPAReqIELength > sizeof(config->RSNWPAReqIE)) { + hdd_err("RSNWPAReqIELength is too large"); + ret = -EINVAL; + goto error; + } + + config->SSIDinfo.ssidHidden = false; + + if (ssid) { + qdf_mem_copy(config->SSIDinfo.ssid.ssId, ssid, ssid_len); + config->SSIDinfo.ssid.length = ssid_len; + + switch (hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + config->SSIDinfo.ssidHidden = eHIDDEN_SSID_NOT_IN_USE; + break; + case NL80211_HIDDEN_SSID_ZERO_LEN: + hdd_debug("HIDDEN_SSID_ZERO_LEN"); + config->SSIDinfo.ssidHidden = eHIDDEN_SSID_ZERO_LEN; + break; + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hdd_debug("HIDDEN_SSID_ZERO_CONTENTS"); + config->SSIDinfo.ssidHidden = + eHIDDEN_SSID_ZERO_CONTENTS; + break; + default: + hdd_err("Wrong hidden_ssid param: %d", hidden_ssid); + break; + } + } + + wlan_hdd_set_multipass(vdev); + + qdf_mem_copy(config->self_macaddr.bytes, + adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + /* default value */ + config->SapMacaddr_acl = eSAP_ACCEPT_UNLESS_DENIED; + config->num_accept_mac = 0; + config->num_deny_mac = 0; + status = ucfg_policy_mgr_get_conc_rule1(hdd_ctx->psoc, &conc_rule1); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("can't get ucfg_policy_mgr_get_conc_rule1, use def"); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + /* + * We don't want P2PGO to follow STA's channel + * so lets limit the logic for SAP only. + * Later if we decide to make p2pgo follow STA's + * channel then remove this check. + */ + if ((0 == conc_rule1) || + (conc_rule1 && (QDF_SAP_MODE == adapter->device_mode))) + config->cc_switch_mode = mcc_to_scc_switch; +#endif + + if (!(ssid && qdf_str_len(PRE_CAC_SSID) == ssid_len && + (0 == qdf_mem_cmp(ssid, PRE_CAC_SSID, ssid_len)))) { + uint16_t beacon_data_len; + + beacon_data_len = beacon->head_len - beacon_fixed_len; + + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_SUPP_RATES, + &mgmt_frame->u.beacon.variable[0], + beacon_data_len); + + if (ie) { + ie++; + if (ie[0] > WLAN_SUPPORTED_RATES_IE_MAX_LEN) { + hdd_err("Invalid supported rates %d", + ie[0]); + ret = -EINVAL; + goto error; + } + config->supported_rates.numRates = ie[0]; + ie++; + for (i = 0; + i < config->supported_rates.numRates; i++) { + if (ie[i]) + config->supported_rates.rate[i] = ie[i]; + } + hdd_debug("Configured Num Supported rates: %d", + config->supported_rates.numRates); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + config->supported_rates.rate, + config->supported_rates.numRates); + } + ie = wlan_get_ie_ptr_from_eid(WLAN_EID_EXT_SUPP_RATES, + beacon->tail, + beacon->tail_len); + if (ie) { + ie++; + if (ie[0] > WLAN_SUPPORTED_RATES_IE_MAX_LEN) { + hdd_err("Invalid supported rates %d", + ie[0]); + ret = -EINVAL; + goto error; + } + config->extended_rates.numRates = ie[0]; + ie++; + for (i = 0; i < config->extended_rates.numRates; i++) { + if (ie[i]) + config->extended_rates.rate[i] = ie[i]; + } + + hdd_debug("Configured Num Extended rates: %d", + config->extended_rates.numRates); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, + config->extended_rates.rate, + config->extended_rates.numRates); + } + + config->require_h2e = false; + wlan_hdd_check_h2e(&config->supported_rates, + &config->require_h2e); + wlan_hdd_check_h2e(&config->extended_rates, + &config->require_h2e); + } + + if (!cds_is_sub_20_mhz_enabled()) + wlan_hdd_set_sap_hwmode(link_info); + + qdf_status = wlan_hdd_mlo_update(link_info); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + ret = -EINVAL; + goto error; + } + + qdf_status = ucfg_mlme_get_vht_for_24ghz(hdd_ctx->psoc, &bval); + if (QDF_IS_STATUS_ERROR(qdf_status)) + hdd_err("Failed to get vht_for_24ghz"); + + if (WLAN_REG_IS_24GHZ_CH_FREQ(config->chan_freq) && bval && + (config->SapHw_mode == eCSR_DOT11_MODE_11n || + config->SapHw_mode == eCSR_DOT11_MODE_11n_ONLY)) + config->SapHw_mode = eCSR_DOT11_MODE_11ac; + + if (((adapter->device_mode == QDF_SAP_MODE) && + (sap_force_11n_for_11ac)) || + ((adapter->device_mode == QDF_P2P_GO_MODE) && + (go_force_11n_for_11ac))) { + if (config->SapHw_mode == eCSR_DOT11_MODE_11ac || + config->SapHw_mode == eCSR_DOT11_MODE_11ac_ONLY) + config->SapHw_mode = eCSR_DOT11_MODE_11n; + } + + wlan_hdd_update_ll_lt_sap_configs(hdd_ctx->psoc, + link_info->vdev_id, config); + + config->sap_orig_hw_mode = config->SapHw_mode; + reg_phy_mode = csr_convert_to_reg_phy_mode(config->SapHw_mode, + config->chan_freq); + updated_phy_mode = wlan_reg_get_max_phymode(hdd_ctx->pdev, reg_phy_mode, + config->chan_freq); + config->SapHw_mode = csr_convert_from_reg_phy_mode(updated_phy_mode); + if (config->sap_orig_hw_mode != config->SapHw_mode) + hdd_info("orig phymode %d new phymode %d", + config->sap_orig_hw_mode, config->SapHw_mode); + qdf_mem_zero(sme_config, sizeof(*sme_config)); + sme_get_config_param(mac_handle, sme_config); + /* Override hostapd.conf wmm_enabled only for 11n and 11AC configs (IOT) + * As per spec 11N/AC STA are QOS STA and may not connect or throughput + * may not be good with non QOS 11N AP + * Default: enable QOS for SAP unless WMM IE not present for 11bga + */ + sme_config->csr_config.WMMSupportMode = WMM_USER_MODE_AUTO; + ie = wlan_get_vendor_ie_ptr_from_oui(WMM_OUI_TYPE, WMM_OUI_TYPE_SIZE, + beacon->tail, beacon->tail_len); + if (!ie && (config->SapHw_mode == eCSR_DOT11_MODE_11a || + config->SapHw_mode == eCSR_DOT11_MODE_11g || + config->SapHw_mode == eCSR_DOT11_MODE_11b)) + sme_config->csr_config.WMMSupportMode = WMM_USER_MODE_NO_QOS; + sme_update_config(mac_handle, sme_config); + + if ((adapter->device_mode == QDF_SAP_MODE && sap_force_11n_for_11ac) || + (adapter->device_mode == QDF_P2P_GO_MODE && go_force_11n_for_11ac)) { + if (config->ch_width_orig > CH_WIDTH_40MHZ) + config->ch_width_orig = CH_WIDTH_40MHZ; + } + + if (wlan_hdd_setup_driver_overrides(adapter)) { + ret = -EINVAL; + goto error; + } + + config->ch_params.ch_width = config->ch_width_orig; + if (sap_phymode_is_eht(config->SapHw_mode)) + wlan_reg_set_create_punc_bitmap(&config->ch_params, true); + if ((config->ch_params.ch_width == CH_WIDTH_80P80MHZ) && + ucfg_mlme_get_restricted_80p80_bw_supp(hdd_ctx->psoc)) { + if (!((config->ch_params.center_freq_seg0 == 138 && + config->ch_params.center_freq_seg1 == 155) || + (config->ch_params.center_freq_seg1 == 138 && + config->ch_params.center_freq_seg0 == 155))) { + hdd_debug("Falling back to 80 from 80p80 as non supported freq_seq0 %d and freq_seq1 %d", + config->ch_params.mhz_freq_seg0, + config->ch_params.mhz_freq_seg1); + config->ch_params.center_freq_seg1 = 0; + config->ch_params.mhz_freq_seg1 = 0; + config->ch_width_orig = CH_WIDTH_80MHZ; + config->ch_params.ch_width = config->ch_width_orig; + } + } + + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + config->chan_freq, + config->sec_ch_freq, + &config->ch_params, + REG_CURRENT_PWR_MODE); + if (0 != wlan_hdd_cfg80211_update_apies(link_info)) { + hdd_err("SAP Not able to set AP IEs"); + ret = -EINVAL; + goto error; + } + + hdd_nofl_debug("SAP mac:" QDF_MAC_ADDR_FMT " SSID: " QDF_SSID_FMT " BCNINTV:%d Freq:%d freq_seg0:%d freq_seg1:%d ch_width:%d HW mode:%d privacy:%d akm:%d acs_mode:%d acs_dfs_mode %d dtim period:%d MFPC %d, MFPR %d", + QDF_MAC_ADDR_REF(adapter->mac_addr.bytes), + QDF_SSID_REF(config->SSIDinfo.ssid.length, + config->SSIDinfo.ssid.ssId), + (int)config->beacon_int, + config->chan_freq, config->ch_params.mhz_freq_seg0, + config->ch_params.mhz_freq_seg1, + config->ch_params.ch_width, + config->SapHw_mode, config->privacy, + config->authType, config->acs_cfg.acs_mode, + config->acs_dfs_mode, config->dtim_period, + mfp_capable, mfp_required); + + mutex_lock(&hdd_ctx->sap_lock); + if (cds_is_driver_unloading()) { + mutex_unlock(&hdd_ctx->sap_lock); + + hdd_err("The driver is unloading, ignore the bss starting"); + ret = -EINVAL; + goto error; + } + + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + mutex_unlock(&hdd_ctx->sap_lock); + + wlansap_reset_sap_config_add_ie(config, eUPDATE_IE_ALL); + /* Bss already started. just return. */ + /* TODO Probably it should update some beacon params. */ + hdd_debug("Bss Already started...Ignore the request"); + hdd_exit(); + ret = 0; + goto free; + } + pm_con_mode = policy_mgr_qdf_opmode_to_pm_con_mode(hdd_ctx->psoc, + adapter->device_mode, + link_info->vdev_id); + + if (check_for_concurrency) { + if (!policy_mgr_allow_concurrency( + hdd_ctx->psoc, + pm_con_mode, + config->chan_freq, HW_MODE_20_MHZ, + policy_mgr_get_conc_ext_flags(vdev, false), + link_info->vdev_id)) { + mutex_unlock(&hdd_ctx->sap_lock); + + hdd_err("This concurrency combination is not allowed"); + ret = -EINVAL; + goto error; + } + } + + if (!hdd_set_connection_in_progress(true)) { + mutex_unlock(&hdd_ctx->sap_lock); + + hdd_err("Can't start BSS: set connection in progress failed"); + ret = -EINVAL; + goto error; + } + + config->persona = adapter->device_mode; + + sap_event_callback = hdd_hostapd_sap_event_cb; + + ap_ctx->dfs_cac_block_tx = true; + set_bit(SOFTAP_INIT_DONE, &link_info->link_flags); + + ucfg_dp_set_dfs_cac_tx(vdev, true); + + qdf_event_reset(&hostapd_state->qdf_event); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + ret = -EINVAL; + goto error; + } + + status = wlansap_start_bss(sap_ctx, sap_event_callback, config, + adapter->dev); + if (!QDF_IS_STATUS_SUCCESS(status)) { + mutex_unlock(&hdd_ctx->sap_lock); + + hdd_set_connection_in_progress(false); + hdd_err("SAP Start Bss fail"); + ret = -EINVAL; + goto error; + } + + qdf_status = qdf_wait_single_event(&hostapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + + wlansap_reset_sap_config_add_ie(config, eUPDATE_IE_ALL); + + if (QDF_IS_STATUS_ERROR(qdf_status) || + QDF_IS_STATUS_ERROR(hostapd_state->qdf_status)) { + mutex_unlock(&hdd_ctx->sap_lock); + if (QDF_IS_STATUS_ERROR(qdf_status)) + hdd_err("Wait for start BSS failed status %d", + qdf_status); + else + hdd_err("Start BSS failed status %d", + hostapd_state->qdf_status); + hdd_set_connection_in_progress(false); + sme_get_command_q_status(mac_handle); + wlansap_stop_bss(WLAN_HDD_GET_SAP_CTX_PTR(link_info)); + if (!cds_is_driver_recovering()) + QDF_ASSERT(0); + ret = -EINVAL; + goto error; + } + /* Successfully started Bss update the state bit. */ + set_bit(SOFTAP_BSS_STARTED, &link_info->link_flags); + + mutex_unlock(&hdd_ctx->sap_lock); + + /* Initialize WMM configuration */ + hdd_wmm_dscp_initial_state(adapter); + if (hostapd_state->bss_state == BSS_START) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + adapter->device_mode, + link_info->vdev_id); + + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + true); + wlan_set_sap_user_config_freq(vdev, user_config_freq); + } + + wlan_hdd_dhcp_offload_enable(link_info); + ucfg_p2p_status_start_bss(vdev); + + /* Check and restart SAP if it is on unsafe channel */ + hdd_unsafe_channel_restart_sap(hdd_ctx); + + ucfg_ftm_time_sync_update_bss_state(vdev, + FTM_TIME_SYNC_BSS_STARTED); + + hdd_set_connection_in_progress(false); + policy_mgr_process_force_scc_for_nan(hdd_ctx->psoc); + ret = 0; + goto free; + +error: + wlan_hdd_mlo_reset(link_info); + /* Revert the indoor to passive marking if START BSS fails */ + if (indoor_chnl_marking && adapter->device_mode == QDF_SAP_MODE) { + hdd_update_indoor_channel(hdd_ctx, false); + sme_update_channel_list(mac_handle); + } + clear_bit(SOFTAP_INIT_DONE, &link_info->link_flags); + qdf_atomic_set(&ap_ctx->acs_in_progress, 0); + wlansap_reset_sap_config_add_ie(config, eUPDATE_IE_ALL); + +free: + wlan_twt_concurrency_update(hdd_ctx); + if (deliver_start_evt) { + struct if_mgr_event_data evt_data; + + evt_data.status = QDF_STATUS_SUCCESS; + if (ret < 0) + evt_data.status = QDF_STATUS_E_FAILURE; + + status = ucfg_if_mgr_deliver_event( + vdev, WLAN_IF_MGR_EV_AP_START_BSS_COMPLETE, + &evt_data); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("start bss complete failed!!"); + ret = -EINVAL; + } + } + qdf_mem_free(sme_config); +deliver_start_err: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + return ret; +} + +int hdd_destroy_acs_timer(struct hdd_adapter *adapter) +{ + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (!ap_ctx->vendor_acs_timer_initialized) + return 0; + + ap_ctx->vendor_acs_timer_initialized = false; + + clear_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->deflink->link_flags); + if (QDF_TIMER_STATE_RUNNING == ap_ctx->vendor_acs_timer.state) { + qdf_status = qdf_mc_timer_stop(&ap_ctx->vendor_acs_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to stop ACS timer"); + } + + if (ap_ctx->vendor_acs_timer.user_data) + qdf_mem_free(ap_ctx->vendor_acs_timer.user_data); + + qdf_mc_timer_destroy(&ap_ctx->vendor_acs_timer); + + return 0; +} + +/** + * __wlan_hdd_cfg80211_stop_ap() - stop soft ap + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + tSirUpdateIE update_ie; + int ret; + mac_handle_t mac_handle; + struct hdd_ap_ctx *ap_ctx; + + hdd_enter_dev(dev); + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + + ret = wlan_hdd_validate_context(hdd_ctx); + /* + * In case of SSR and other FW down cases, validate context will + * fail. But return success to upper layer so that it can clean up + * kernel variables like beacon interval. If the failure status + * is returned then next set beacon command will fail as beacon + * interval in not reset. + */ + if (ret) + goto exit; + + if (hdd_ctx->is_wiphy_suspended) { + hdd_debug("wiphy is suspended"); + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + goto exit; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; dropping request"); + goto exit; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + goto exit; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_STOP_AP, + adapter->deflink->vdev_id, adapter->device_mode); + + if (!(adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) { + hdd_err("stop ap is given on device modes other than SAP/GO. Hence return"); + goto exit; + } + + /* + * Reset sap mandatory channel list.If band is changed then + * frequencies of new selected band can be removed in pcl + * modification based on sap mandatory channel list. + */ + status = policy_mgr_reset_sap_mandatory_channels(hdd_ctx->psoc); + /* Don't go to exit in case of failure. Clean up & stop BSS */ + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to reset mandatory channels"); + + /* + * For STA+SAP/GO concurrency support from GUI, In case if + * STOP AP/GO request comes just before the SAE authentication + * completion on STA, SAE AUTH REQ waits for STOP AP RSP and + * STOP AP RSP waits to complete SAE AUTH REQ. + * Driver completes STOP AP RSP only upon SAE AUTH REQ timeout(5 sec) + * as stop ap will be in serialization pending queue, and SAE auth + * sequence cannot complete as hostap thread is blocked in stop ap + * cfg80211 ops. + * To avoid above deadlock until SAE timeout, abort the SAE connection + * immediately and complete STOP AP/GO asap so that the upper layer + * can trigger a fresh connection after STOP AP/GO completion. + */ + hdd_abort_ongoing_sta_sae_connection(hdd_ctx); + + /* Clear SOFTAP_INIT_DONE flag to mark stop_ap deinit. So that we do + * not restart SAP after SSR as SAP is already stopped from user space. + * This update is moved to start of this function to resolve stop_ap + * call during SSR case. Adapter gets cleaned up as part of SSR. + */ + clear_bit(SOFTAP_INIT_DONE, &adapter->deflink->link_flags); + hdd_debug("Event flags 0x%lx(%s) Device_mode %s(%d)", + adapter->event_flags, (adapter->dev)->name, + qdf_opmode_str(adapter->device_mode), adapter->device_mode); + + if (adapter->device_mode == QDF_SAP_MODE) { + wlan_hdd_del_station(adapter, NULL); + mac_handle = hdd_ctx->mac_handle; + status = wlan_hdd_flush_pmksa_cache(adapter->deflink); + } + + cds_flush_work(&adapter->sap_stop_bss_work); + ap_ctx->sap_config.acs_cfg.acs_mode = false; + hdd_dcs_clear(adapter); + qdf_atomic_set(&ap_ctx->acs_in_progress, 0); + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + wlan_hdd_cleanup_actionframe(adapter->deflink); + wlan_hdd_cleanup_remain_on_channel_ctx(adapter->deflink); + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags)) { + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + + hdd_place_marker(adapter, "TRY TO STOP", NULL); + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + status = wlansap_stop_bss(ap_ctx->sap_context); + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_status = + qdf_wait_single_event(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_STOP_BSS_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("qdf wait for single_event failed!!"); + hdd_place_marker(adapter, "STOP with FAILURE", + NULL); + hdd_sap_indicate_disconnect_for_sta(adapter); + QDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags); + + /*BSS stopped, clear the active sessions for this device mode*/ + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->deflink->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + wlan_twt_concurrency_update(hdd_ctx); + wlan_set_sap_user_config_freq(adapter->deflink->vdev, 0); + status = ucfg_if_mgr_deliver_event( + adapter->deflink->vdev, + WLAN_IF_MGR_EV_AP_STOP_BSS_COMPLETE, NULL); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Stopping the BSS failed"); + goto exit; + } + qdf_mem_free(ap_ctx->beacon); + ap_ctx->beacon = NULL; + } else { + hdd_debug("SAP already down"); + mutex_unlock(&hdd_ctx->sap_lock); + goto exit; + } + + mutex_unlock(&hdd_ctx->sap_lock); + + mac_handle = hdd_ctx->mac_handle; + + if (ucfg_pre_cac_is_active(hdd_ctx->psoc)) + ucfg_pre_cac_clean_up(hdd_ctx->psoc); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Stopping the BSS"); + goto exit; + } + + qdf_copy_macaddr(&update_ie.bssid, &adapter->mac_addr); + update_ie.vdev_id = adapter->deflink->vdev_id; + update_ie.ieBufferlength = 0; + update_ie.pAdditionIEBuffer = NULL; + update_ie.append = true; + update_ie.notify = true; + if (sme_update_add_ie(mac_handle, + &update_ie, + eUPDATE_IE_PROBE_BCN) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } + + if (sme_update_add_ie(mac_handle, + &update_ie, + eUPDATE_IE_ASSOC_RESP) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on ASSOC_RSP data to PE"); + } + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(adapter->deflink); + hdd_destroy_acs_timer(adapter); + + ucfg_p2p_status_stop_bss(adapter->deflink->vdev); + ucfg_ftm_time_sync_update_bss_state(adapter->deflink->vdev, + FTM_TIME_SYNC_BSS_STOPPED); + +exit: + qdf_mem_free(ap_ctx->beacon); + ap_ctx->beacon = NULL; + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_place_marker(adapter, "STOP with SUCCESS", NULL); + else + hdd_place_marker(adapter, "STOP with FAILURE", NULL); + + hdd_exit(); + + return 0; +} + +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id) +#else +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + /* + * The stop_ap can be called in the same context through + * wlan_hdd_del_virtual_intf. As vdev_trans is already taking place as + * part of the del_vitrtual_intf, this vdev_op cannot start. + * Return 0 in case op is not started so that the kernel frees the + * beacon memory properly. + */ + if (errno) + return 0; + + errno = __wlan_hdd_cfg80211_stop_ap(wiphy, dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +/* + * Beginning with 4.7 struct ieee80211_channel uses enum nl80211_band + * ieee80211_channel_band() - return channel band + * chan: channel + * + * Return: channel band + */ +static inline +enum nl80211_band ieee80211_channel_band(const struct ieee80211_channel *chan) +{ + return chan->band; +} +#else +/* + * Prior to 4.7 struct ieee80211_channel used enum ieee80211_band. However the + * ieee80211_band enum values are assigned from enum nl80211_band so we can + * safely typecast one to another. + */ +static inline +enum nl80211_band ieee80211_channel_band(const struct ieee80211_channel *chan) +{ + enum ieee80211_band band = chan->band; + + return (enum nl80211_band)band; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)) || \ + defined(CFG80211_BEACON_TX_RATE_CUSTOM_BACKPORT) +/** + * hdd_get_data_rate_from_rate_mask() - convert mask to rate + * @wiphy: Pointer to wiphy + * @band: band + * @bit_rate_mask: pointer to bit_rake_mask + * + * This function takes band and bit_rate_mask as input and + * derives the beacon_tx_rate based on the supported rates + * published as part of wiphy register. + * + * Return: data rate for success or zero for failure + */ +static uint16_t hdd_get_data_rate_from_rate_mask(struct wiphy *wiphy, + enum nl80211_band band, + struct cfg80211_bitrate_mask *bit_rate_mask) +{ + struct ieee80211_supported_band *sband = wiphy->bands[band]; + int sband_n_bitrates; + struct ieee80211_rate *sband_bitrates; + int i; + + if (sband) { + sband_bitrates = sband->bitrates; + sband_n_bitrates = sband->n_bitrates; + for (i = 0; i < sband_n_bitrates; i++) { + if (bit_rate_mask->control[band].legacy == (1 << i)) + return sband_bitrates[i].bitrate; + } + } + return 0; +} + +/** + * hdd_update_beacon_rate() - Update beacon tx rate + * @link_info: Pointer to link_info in adapter + * @wiphy: Pointer to wiphy + * @params: Pointet to cfg80211_ap_settings + * + * This function updates the beacon tx rate which is provided + * as part of cfg80211_ap_settions in to the sap_config + * structure + * + * Return: none + */ +static void +hdd_update_beacon_rate(struct wlan_hdd_link_info *link_info, + struct wiphy *wiphy, struct cfg80211_ap_settings *params) +{ + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + struct cfg80211_bitrate_mask *beacon_rate_mask; + enum nl80211_band band; + + band = ieee80211_channel_band(params->chandef.chan); + beacon_rate_mask = ¶ms->beacon_rate; + if (beacon_rate_mask->control[band].legacy) { + ap_ctx->sap_config.beacon_tx_rate = + hdd_get_data_rate_from_rate_mask(wiphy, band, + beacon_rate_mask); + hdd_debug("beacon mask value %u, rate %hu", + params->beacon_rate.control[0].legacy, + ap_ctx->sap_config.beacon_tx_rate); + } +} +#else +static inline void +hdd_update_beacon_rate(struct wlan_hdd_link_info *link_info, + struct wiphy *wiphy, struct cfg80211_ap_settings *params) +{ +} +#endif + +/** + * wlan_hdd_get_sap_ch_params() - Get channel parameters of SAP + * @hdd_ctx: HDD context pointer + * @vdev_id: vdev id + * @freq: channel frequency (MHz) + * @ch_params: pointer to channel parameters + * + * The function gets channel parameters of SAP by vdev id. + * + * Return: QDF_STATUS_SUCCESS if get channel parameters successful + */ +static QDF_STATUS +wlan_hdd_get_sap_ch_params(struct hdd_context *hdd_ctx, + uint8_t vdev_id, uint32_t freq, + struct ch_params *ch_params) +{ + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx || !ch_params) { + hdd_err("invalid hdd_ctx or ch_params"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) + return QDF_STATUS_E_INVAL; + + if (!wlan_sap_get_ch_params(WLAN_HDD_GET_SAP_CTX_PTR(link_info), + ch_params)) + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, freq, 0, + ch_params, + REG_CURRENT_PWR_MODE); + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_is_ap_ap_force_scc_override() - force Same band SCC chan override + * @link_info: Link info pointer in HDD adapter + * @chandef: SAP starting channel + * @new_chandef: new override SAP channel + * + * The function will override the second SAP chan to the first SAP's home + * channel if the FW doesn't support MCC and force SCC enabled in INI. + * + * Return: true if channel override + */ +static bool +wlan_hdd_is_ap_ap_force_scc_override(struct wlan_hdd_link_info *link_info, + struct cfg80211_chan_def *chandef, + struct cfg80211_chan_def *new_chandef) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct ch_params ch_params = {0}; + enum nl80211_channel_type channel_type; + uint8_t con_vdev_id = WLAN_INVALID_VDEV_ID; + uint32_t con_freq = 0; + struct ieee80211_channel *ieee_chan; + uint32_t freq; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE opmode; + + if (!hdd_ctx || !chandef) { + hdd_err("hdd context or chandef is NULL"); + return false; + } + freq = chandef->chan->center_freq; + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("failed to get vdev"); + return false; + } + if (policy_mgr_is_ap_ap_mcc_allow( + hdd_ctx->psoc, hdd_ctx->pdev, vdev, freq, + hdd_map_nl_chan_width(chandef->width), + &con_vdev_id, &con_freq)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return false; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (opmode == QDF_SAP_MODE && + hdd_handle_p2p_go_for_3rd_ap_conc(hdd_ctx, freq)) + return false; + if (!con_freq) + return false; + ieee_chan = ieee80211_get_channel(hdd_ctx->wiphy, + con_freq); + if (!ieee_chan) { + hdd_err("channel conversion failed"); + return false; + } + + status = wlan_hdd_get_sap_ch_params(hdd_ctx, con_vdev_id, con_freq, + &ch_params); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + switch (ch_params.sec_ch_offset) { + case PHY_SINGLE_CHANNEL_CENTERED: + channel_type = NL80211_CHAN_HT20; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + channel_type = NL80211_CHAN_HT40MINUS; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + channel_type = NL80211_CHAN_HT40PLUS; + break; + default: + channel_type = NL80211_CHAN_NO_HT; + break; + } + cfg80211_chandef_create(new_chandef, ieee_chan, channel_type); + switch (ch_params.ch_width) { + case CH_WIDTH_80MHZ: + new_chandef->width = NL80211_CHAN_WIDTH_80; + break; + case CH_WIDTH_80P80MHZ: + new_chandef->width = NL80211_CHAN_WIDTH_80P80; + if (ch_params.mhz_freq_seg1) + new_chandef->center_freq2 = ch_params.mhz_freq_seg1; + break; + case CH_WIDTH_160MHZ: + new_chandef->width = NL80211_CHAN_WIDTH_160; + break; + default: + break; + } + + wlan_hdd_set_chandef_width(new_chandef, ch_params.ch_width); + + if ((ch_params.ch_width == CH_WIDTH_80MHZ) || + (ch_params.ch_width == CH_WIDTH_80P80MHZ) || + (ch_params.ch_width == CH_WIDTH_160MHZ) || + wlan_hdd_is_chwidth_320mhz(ch_params.ch_width)) { + if (ch_params.mhz_freq_seg0) + new_chandef->center_freq1 = ch_params.mhz_freq_seg0; + } + + hdd_debug("override AP freq %d to first AP(vdev_id %d) center_freq:%d width:%d freq1:%d freq2:%d ", + freq, con_vdev_id, new_chandef->chan->center_freq, + new_chandef->width, new_chandef->center_freq1, + new_chandef->center_freq2); + return true; +} + +#ifdef NDP_SAP_CONCURRENCY_ENABLE +/** + * hdd_sap_nan_check_and_disable_unsupported_ndi: Wrapper function for + * ucfg_nan_check_and_disable_unsupported_ndi + * @psoc: pointer to psoc object + * @force: When set forces NDI disable + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +hdd_sap_nan_check_and_disable_unsupported_ndi(struct wlan_objmgr_psoc *psoc, + bool force) +{ + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +hdd_sap_nan_check_and_disable_unsupported_ndi(struct wlan_objmgr_psoc *psoc, + bool force) +{ + return ucfg_nan_check_and_disable_unsupported_ndi(psoc, force); +} +#endif + +#if defined(WLAN_SUPPORT_TWT) && \ + ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) || \ + defined(CFG80211_TWT_RESPONDER_SUPPORT)) +#ifdef WLAN_TWT_CONV_SUPPORTED +void wlan_hdd_configure_twt_responder(struct hdd_context *hdd_ctx, + bool twt_responder) +{ + bool twt_res_svc_cap, enable_twt, twt_res_cfg; + uint32_t reason; + + enable_twt = ucfg_twt_cfg_is_twt_enabled(hdd_ctx->psoc); + ucfg_twt_get_responder(hdd_ctx->psoc, &twt_res_svc_cap); + ucfg_twt_cfg_get_responder(hdd_ctx->psoc, &twt_res_cfg); + if (!twt_res_cfg && !twt_responder) { + hdd_debug("TWT responder already disable, skip"); + return; + } + ucfg_twt_cfg_set_responder(hdd_ctx->psoc, + QDF_MIN(twt_res_svc_cap, + (enable_twt && + twt_responder))); + hdd_debug("cfg80211 TWT responder:%d", twt_responder); + if (enable_twt && twt_responder) { + hdd_send_twt_responder_enable_cmd(hdd_ctx); + } else { + reason = HOST_TWT_DISABLE_REASON_NONE; + hdd_send_twt_responder_disable_cmd(hdd_ctx, reason); + } + +} + +static void +wlan_hdd_update_twt_responder(struct hdd_adapter *adapter, + struct cfg80211_ap_settings *params) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + adapter->deflink->session.ap.sap_config.cfg80211_twt_responder = + params->twt_responder; + wlan_hdd_configure_twt_responder(hdd_ctx, params->twt_responder); +} + +#else +void wlan_hdd_configure_twt_responder(struct hdd_context *hdd_ctx, + bool twt_responder) +{ + bool twt_res_svc_cap, enable_twt; + uint32_t reason; + + enable_twt = ucfg_mlme_is_twt_enabled(hdd_ctx->psoc); + ucfg_mlme_get_twt_res_service_cap(hdd_ctx->psoc, &twt_res_svc_cap); + ucfg_mlme_set_twt_responder(hdd_ctx->psoc, + QDF_MIN(twt_res_svc_cap, + (enable_twt && twt_responder))); + hdd_debug("cfg80211 TWT responder:%d", twt_responder); + if (enable_twt && twt_responder) { + hdd_send_twt_responder_enable_cmd(hdd_ctx); + } else { + reason = HOST_TWT_DISABLE_REASON_NONE; + hdd_send_twt_responder_disable_cmd(hdd_ctx, reason); + } +} + +static void +wlan_hdd_update_twt_responder(struct hdd_adapter *adapter, + struct cfg80211_ap_settings *params) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + adapter->deflink->session.ap.sap_config.cfg80211_twt_responder = + params->twt_responder; + wlan_hdd_configure_twt_responder(hdd_ctx, params->twt_responder); +} +#endif +#else +static inline void +wlan_hdd_update_twt_responder(struct hdd_adapter *adapter, + struct cfg80211_ap_settings *params) +{} + +void wlan_hdd_configure_twt_responder(struct hdd_context *hdd_ctx, + bool twt_responder) +{} +#endif + +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +static inline struct cfg80211_chan_def +wlan_util_get_chan_def(struct wireless_dev *wdev, unsigned int link_id) +{ + return wdev->links[link_id].ap.chandef; +} +#else +static inline struct cfg80211_chan_def +wlan_util_get_chan_def(struct wireless_dev *wdev, unsigned int link_id) +{ + return wdev->chandef; +} +#endif + +#if defined(WLAN_FEATURE_SR) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +/** + * hdd_update_he_obss_pd() - Enable or disable spatial reuse + * based on user space input and concurrency combination. + * @link_info: Pointer to link_info in hostapd adapter + * @params: Pointer to AP configuration from cfg80211 + * + * Return: void + */ +static void hdd_update_he_obss_pd(struct wlan_hdd_link_info *link_info, + struct cfg80211_ap_settings *params) +{ + struct wlan_objmgr_vdev *vdev; + struct ieee80211_he_obss_pd *obss_pd; + uint8_t sr_device_modes; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + ucfg_mlme_get_sr_enable_modes(hdd_ctx->psoc, &sr_device_modes); + if (!(sr_device_modes & (1 << link_info->adapter->device_mode))) { + hdd_debug("SR operation not allowed for mode %d", + link_info->adapter->device_mode); + return; + } + + if (!params || !params->he_obss_pd.enable) + return; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return; + + obss_pd = ¶ms->he_obss_pd; + ucfg_spatial_reuse_set_sr_config(vdev, obss_pd->sr_ctrl, + obss_pd->non_srg_max_offset); + ucfg_spatial_reuse_set_sr_enable(vdev, obss_pd->enable); + hdd_debug("obss_pd_enable: %d, sr_ctrl: %d, non_srg_max_offset: %d", + obss_pd->enable, obss_pd->sr_ctrl, + obss_pd->non_srg_max_offset); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); +} +#else +static inline void hdd_update_he_obss_pd(struct wlan_hdd_link_info *link_info, + struct cfg80211_ap_settings *params) +{ +} +#endif + +static void hdd_update_param_chandef(struct wlan_hdd_link_info *link_info, + struct cfg80211_chan_def *chandef) +{ + struct wlan_channel *chan; + + chan = wlan_vdev_get_active_channel(link_info->vdev); + if (!chan) + return; + + hdd_create_chandef(link_info->adapter, chan, chandef); +} + +/** + * __wlan_hdd_cfg80211_start_ap() - start soft ap mode + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to AP settings parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + enum hw_mode_bandwidth channel_width; + int status; + struct sme_sta_inactivity_timeout *sta_inactivity_timer; + uint8_t mandt_chnl_list = 0; + qdf_freq_t freq; + uint16_t sta_cnt, sap_cnt; + bool val; + struct cfg80211_chan_def new_chandef; + struct cfg80211_chan_def *chandef; + bool srd_channel_allowed, disable_nan = true; + enum QDF_OPMODE vdev_opmode; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS], i; + enum policy_mgr_con_mode intf_pm_mode; + struct wlan_objmgr_vdev *vdev; + uint16_t link_id = 0; + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + + clear_bit(SOFTAP_INIT_DONE, &link_info->link_flags); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_START_AP, + link_info->vdev_id, params->beacon_interval); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("HDD adapter magic is invalid"); + return -ENODEV; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_config = &ap_ctx->sap_config; + + hdd_nofl_info("%s(vdevid-%d): START AP: mode %s(%d) %d bw %d sub20 %d", + dev->name, link_info->vdev_id, + qdf_opmode_str(adapter->device_mode), + adapter->device_mode, + params->chandef.chan->center_freq, + params->chandef.width, + cds_is_sub_20_mhz_enabled()); + if (policy_mgr_is_hw_mode_change_in_progress(hdd_ctx->psoc)) { + status = policy_mgr_wait_for_connection_update( + hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("qdf wait for event failed!!"); + return -EINVAL; + } + } + + hdd_reg_wait_for_country_change(hdd_ctx); + + channel_width = wlan_hdd_get_channel_bw(params->chandef.width); + freq = (qdf_freq_t)params->chandef.chan->center_freq; + + if (wlan_reg_is_6ghz_chan_freq(freq) && + !wlan_reg_is_6ghz_band_set(hdd_ctx->pdev)) { + hdd_err("6 GHz band disabled."); + return -EINVAL; + } + + chandef = ¶ms->chandef; + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + wlan_hdd_is_ap_ap_force_scc_override(link_info, + chandef, &new_chandef)) { + chandef = &new_chandef; + freq = (qdf_freq_t)chandef->chan->center_freq; + channel_width = wlan_hdd_get_channel_bw(chandef->width); + } + + if (QDF_STATUS_SUCCESS != + ucfg_policy_mgr_get_sap_mandt_chnl(hdd_ctx->psoc, &mandt_chnl_list)) + hdd_err("can't get mandatory channel list"); + if (mandt_chnl_list && adapter->device_mode == QDF_SAP_MODE) + policy_mgr_init_sap_mandatory_chan(hdd_ctx->psoc, + chandef->chan->center_freq); + + sap_config->ch_params.center_freq_seg0 = + cds_freq_to_chan(chandef->center_freq1); + sap_config->ch_params.center_freq_seg1 = + cds_freq_to_chan(chandef->center_freq2); + sap_config->ch_params.mhz_freq_seg0 = chandef->center_freq1; + sap_config->ch_params.mhz_freq_seg1 = chandef->center_freq2; + + status = policy_mgr_is_sap_allowed_on_dfs_freq( + hdd_ctx->pdev, + link_info->vdev_id, + chandef->chan->center_freq); + if (!status) + return -EINVAL; + + status = policy_mgr_is_sap_go_interface_allowed_on_indoor( + hdd_ctx->pdev, + link_info->vdev_id, + chandef->chan->center_freq); + if (!status) { + hdd_debug("SAP start not allowed on indoor channel %d", + chandef->chan->center_freq); + return -EINVAL; + } + + intf_pm_mode = + policy_mgr_qdf_opmode_to_pm_con_mode(hdd_ctx->psoc, + adapter->device_mode, + adapter->deflink->vdev_id); + status = policy_mgr_is_multi_sap_allowed_on_same_band( + hdd_ctx->pdev, + intf_pm_mode, + chandef->chan->center_freq); + if (!status) + return -EINVAL; + + vdev_opmode = wlan_vdev_mlme_get_opmode(link_info->vdev); + ucfg_mlme_get_srd_master_mode_for_vdev(hdd_ctx->psoc, vdev_opmode, + &srd_channel_allowed); + + if (!srd_channel_allowed && + wlan_reg_is_etsi_srd_chan_for_freq(hdd_ctx->pdev, freq)) { + hdd_err("vdev opmode %d not allowed on SRD channel.", + vdev_opmode); + return -EINVAL; + } + if (cds_is_sub_20_mhz_enabled()) { + enum channel_state ch_state; + enum phy_ch_width sub_20_ch_width = CH_WIDTH_INVALID; + struct ch_params ch_params; + + if (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state_from_secondary_list_for_freq( + hdd_ctx->pdev, + freq)) { + hdd_err("Can't start SAP-DFS (channel=%d)with sub 20 MHz ch wd", + freq); + return -EINVAL; + } + if (channel_width != HW_MODE_20_MHZ) { + hdd_err("Hostapd (20+ MHz) conflits with config.ini (sub 20 MHz)"); + return -EINVAL; + } + if (cds_is_5_mhz_enabled()) + sub_20_ch_width = CH_WIDTH_5MHZ; + if (cds_is_10_mhz_enabled()) + sub_20_ch_width = CH_WIDTH_10MHZ; + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = sub_20_ch_width; + if (WLAN_REG_IS_5GHZ_CH_FREQ(freq)) + ch_state = + wlan_reg_get_5g_bonded_channel_state_for_pwrmode( + hdd_ctx->pdev, freq, &ch_params, + REG_CURRENT_PWR_MODE); + else + ch_state = wlan_reg_get_2g_bonded_channel_state_for_freq(hdd_ctx->pdev, freq, + sub_20_ch_width, 0); + if (CHANNEL_STATE_DISABLE == ch_state) { + hdd_err("Given ch width not supported by reg domain"); + return -EINVAL; + } + sap_config->SapHw_mode = eCSR_DOT11_MODE_abg; + } + + sta_cnt = policy_mgr_get_mode_specific_conn_info(hdd_ctx->psoc, NULL, + vdev_id_list, + PM_STA_MODE); + sap_cnt = policy_mgr_get_sap_mode_info(hdd_ctx->psoc, NULL, + &vdev_id_list[sta_cnt]); + + /* Disable NAN Disc before starting P2P GO or STA+SAP or SAP+SAP */ + if (adapter->device_mode == QDF_P2P_GO_MODE || sta_cnt || + (sap_cnt > (MAX_SAP_NUM_CONCURRENCY_WITH_NAN - 1))) { + hdd_debug("Invalid NAN concurrency. SAP: %d STA: %d P2P_GO: %d", + sap_cnt, sta_cnt, + (adapter->device_mode == QDF_P2P_GO_MODE)); + for (i = 0; i < sta_cnt + sap_cnt; i++) + if (vdev_id_list[i] == link_info->vdev_id) + disable_nan = false; + if (disable_nan) + ucfg_nan_disable_concurrency(hdd_ctx->psoc); + } + + /* NDI + SAP conditional supported */ + hdd_sap_nan_check_and_disable_unsupported_ndi(hdd_ctx->psoc, true); + + if (policy_mgr_mode_specific_connection_count(hdd_ctx->psoc, + PM_NAN_DISC_MODE, NULL) && + !policy_mgr_nan_sap_pre_enable_conc_check(hdd_ctx->psoc, + PM_SAP_MODE, freq)) + hdd_debug("NAN disabled due to concurrency constraints"); + + /* check if concurrency is allowed */ + if (!policy_mgr_allow_concurrency( + hdd_ctx->psoc, intf_pm_mode, freq, channel_width, + policy_mgr_get_conc_ext_flags(link_info->vdev, + false), + link_info->vdev_id)) { + hdd_err("Connection failed due to concurrency check failure"); + return -EINVAL; + } + + status = policy_mgr_reset_connection_update(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("ERR: clear event failed"); + + /* + * For Start Ap, the driver checks whether the SAP comes up in a + * different or same band( whether we require DBS or Not). + * If we dont require DBS, then the driver does nothing assuming + * the state would be already in non DBS mode, and just continues + * with vdev up on same MAC, by stopping the opportunistic timer, + * which results in a connection of 1x1 if already the state was in + * DBS. So first stop timer, and check the current hw mode. + * If the SAP comes up in band different from STA, DBS mode is already + * set. IF not, then well check for upgrade, and shift the connection + * back to single MAC 2x2 (if initial was 2x2). + */ + + policy_mgr_checkn_update_hw_mode_single_mac_mode(hdd_ctx->psoc, freq); + + status = policy_mgr_current_connections_update( + hdd_ctx->psoc, link_info->vdev_id, + freq, + POLICY_MGR_UPDATE_REASON_START_AP, + POLICY_MGR_DEF_REQ_ID); + if (status == QDF_STATUS_E_FAILURE) { + hdd_err("ERROR: connections update failed!!"); + return -EINVAL; + } + + if (QDF_STATUS_SUCCESS == status) { + status = policy_mgr_wait_for_connection_update(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("qdf wait for event failed!!"); + return -EINVAL; + } + } + + if (adapter->device_mode == QDF_P2P_GO_MODE) { + struct hdd_adapter *p2p_adapter; + struct wlan_hdd_link_info *p2p_link_info; + + p2p_adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_DEVICE_MODE); + if (p2p_adapter) { + hdd_debug("Cleanup active p2p device ROC before GO starting"); + p2p_link_info = p2p_adapter->deflink; + wlan_hdd_cleanup_remain_on_channel_ctx(p2p_link_info); + } + } + + if ((adapter->device_mode == QDF_SAP_MODE) + || (adapter->device_mode == QDF_P2P_GO_MODE) + ) { + struct hdd_beacon_data *old, *new; + enum nl80211_channel_type channel_type; + + old = ap_ctx->beacon; + if (old) + return -EALREADY; + + status = + wlan_hdd_cfg80211_alloc_new_beacon(link_info, &new, + ¶ms->beacon, + params->dtim_period); + + if (status != 0) { + hdd_err("Error!!! Allocating the new beacon"); + return -EINVAL; + } + ap_ctx->beacon = new; + + if (chandef->width < NL80211_CHAN_WIDTH_80) + channel_type = cfg80211_get_chandef_type(chandef); + else + channel_type = NL80211_CHAN_HT40PLUS; + + + wlan_hdd_set_channel(wiphy, dev, chandef, channel_type); + + hdd_update_beacon_rate(link_info, wiphy, params); + + /* set authentication type */ + switch (params->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + sap_config->authType = eSAP_OPEN_SYSTEM; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + sap_config->authType = eSAP_SHARED_KEY; + break; + default: + sap_config->authType = eSAP_AUTO_SWITCH; + } + sap_config->ch_width_orig = + hdd_map_nl_chan_width(chandef->width); + + /* + * Enable/disable TWT responder based on + * the twt_responder flag + */ + wlan_hdd_update_twt_responder(adapter, params); + + /* Enable/disable non-srg obss pd spatial reuse */ + hdd_update_he_obss_pd(link_info, params); + + hdd_place_marker(adapter, "TRY TO START", NULL); + status = wlan_hdd_cfg80211_start_bss(link_info, ¶ms->beacon, + params->ssid, + params->ssid_len, + params->hidden_ssid, true); + + if (status != 0) { + hdd_err("Error Start bss Failed"); + goto err_start_bss; + } + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + link_id = wlan_vdev_get_link_id(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (wlan_get_operation_chan_freq(link_info->vdev) != + params->chandef.chan->center_freq) + hdd_update_param_chandef(link_info, ¶ms->chandef); + + /* + * If Do_Not_Break_Stream enabled send avoid channel list + * to application. + */ + if (sap_config->chan_freq && + policy_mgr_is_dnsc_set(link_info->vdev)) + wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, + sap_config->chan_freq); + + ucfg_mlme_get_sap_inactivity_override(hdd_ctx->psoc, &val); + if (val) { + sta_inactivity_timer = qdf_mem_malloc( + sizeof(*sta_inactivity_timer)); + if (!sta_inactivity_timer) { + status = QDF_STATUS_E_FAILURE; + goto err_start_bss; + } + sta_inactivity_timer->session_id = + link_info->vdev_id; + sta_inactivity_timer->sta_inactivity_timeout = + params->inactivity_timeout; + sme_update_sta_inactivity_timeout(hdd_ctx->mac_handle, + sta_inactivity_timer); + qdf_mem_free(sta_inactivity_timer); + } + } + + goto success; + +err_start_bss: + hdd_place_marker(adapter, "START with FAILURE", NULL); + qdf_mem_free(ap_ctx->beacon); + ap_ctx->beacon = NULL; + +success: + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_place_marker(adapter, "START with SUCCESS", NULL); + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_start_ap() - start sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @params: Pointer to start ap configuration parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_start_ap(wiphy, dev, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_change_beacon() - change beacon for sofatap/p2p go + * @wiphy: Pointer to wiphy structure + * @dev: Pointer to net_device structure + * @params: Pointer to change beacon parameters + * + * Return: 0 for success non-zero for failure + */ +static int __wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct hdd_beacon_data *old, *new; + int status; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_CHANGE_BEACON, + link_info->vdev_id, adapter->device_mode); + + hdd_debug("Device_mode %s(%d)", + qdf_opmode_str(adapter->device_mode), adapter->device_mode); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + if (!(adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) { + return -EOPNOTSUPP; + } + + old = link_info->session.ap.beacon; + + if (!old) { + hdd_err("session id: %d beacon data points to NULL", + link_info->vdev_id); + return -EINVAL; + } + + status = wlan_hdd_cfg80211_alloc_new_beacon(link_info, &new, params, 0); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("new beacon alloc failed"); + return -EINVAL; + } + + link_info->session.ap.beacon = new; + hdd_debug("update beacon for P2P GO/SAP"); + status = wlan_hdd_cfg80211_start_bss(link_info, params, + NULL, 0, 0, false); + + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_change_beacon() - change beacon content in sap mode + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @params: Pointer to change beacon parameters + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_change_beacon(wiphy, dev, params); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_sap_indicate_disconnect_for_sta() - Indicate disconnect indication + * to supplicant, if there any clients connected to SAP interface. + * @adapter: sap adapter context + * + * Return: nothing + */ +void hdd_sap_indicate_disconnect_for_sta(struct hdd_adapter *adapter) +{ + struct sap_event sap_event; + struct sap_context *sap_ctx; + struct hdd_station_info *sta_info, *tmp = NULL; + + hdd_enter(); + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (!sap_ctx) { + hdd_err("invalid sap context"); + return; + } + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_SAP_INDICATE_DISCONNECT_FOR_STA) { + hdd_debug("sta_mac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_info->sta_mac.bytes)); + + if (qdf_is_macaddr_broadcast(&sta_info->sta_mac)) { + hdd_softap_deregister_sta(adapter, &sta_info); + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &sta_info, true, + STA_INFO_SAP_INDICATE_DISCONNECT_FOR_STA); + continue; + } + + sap_event.sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + + qdf_mem_copy( + &sap_event.sapevt.sapStationDisassocCompleteEvent.staMac, + &sta_info->sta_mac, sizeof(struct qdf_mac_addr)); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SAP_INDICATE_DISCONNECT_FOR_STA); + + sap_event.sapevt.sapStationDisassocCompleteEvent.reason = + eSAP_MAC_INITATED_DISASSOC; + sap_event.sapevt.sapStationDisassocCompleteEvent.status_code = + QDF_STATUS_E_RESOURCES; + hdd_hostapd_sap_event_cb(&sap_event, sap_ctx->user_context); + } + + hdd_exit(); +} + +bool hdd_is_peer_associated(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr) +{ + bool is_associated = false; + struct hdd_station_info *sta_info, *tmp = NULL; + + if (!adapter || !mac_addr) { + hdd_err("Invalid adapter or mac_addr"); + return false; + } + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_IS_PEER_ASSOCIATED) { + if (!qdf_mem_cmp(&sta_info->sta_mac, mac_addr, + QDF_MAC_ADDR_SIZE)) { + is_associated = true; + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_IS_PEER_ASSOCIATED); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_IS_PEER_ASSOCIATED); + break; + } + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_IS_PEER_ASSOCIATED); + } + + return is_associated; +} + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +bool hdd_sap_is_acs_in_progress(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_hdd_link_info *link_info; + bool in_progress = false; + + if (!vdev) { + hdd_err("vdev is NULL"); + return in_progress; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return in_progress; + } + + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return in_progress; + } + + in_progress = qdf_atomic_read(&link_info->session.ap.acs_in_progress); + + return in_progress; +} +#endif + +#ifdef WLAN_CHIPSET_STATS +void +hdd_cp_stats_cstats_sap_go_start_event(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event) +{ + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + struct cstats_sap_go_start stat = {0}; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + sap_config = &ap_ctx->sap_config; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_SAP_GO_START_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sap_go_start) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = + sap_event->sapevt.sapStartBssCompleteEvent.sessionId; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.status = sap_event->sapevt.sapStartBssCompleteEvent.status; + stat.operating_chan_freq = + sap_event->sapevt.sapStartBssCompleteEvent.operating_chan_freq; + stat.ch_width = sap_event->sapevt.sapStartBssCompleteEvent.ch_width; + stat.staId = sap_event->sapevt.sapStartBssCompleteEvent.staId; + + stat.ssid_len = sap_config->SSIDinfo.ssid.length; + qdf_mem_copy(stat.ssid, sap_config->SSIDinfo.ssid.ssId, + sap_config->SSIDinfo.ssid.length); + CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + wlan_cstats_host_stats(sizeof(struct cstats_sap_go_start), &stat); +} + +void hdd_cp_stats_cstats_sap_go_stop_event(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event) +{ + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + struct cstats_sap_go_stop stat = {0}; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + sap_config = &ap_ctx->sap_config; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_SAP_GO_STOP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sap_go_stop) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.status = sap_event->sapevt.sapStopBssCompleteEvent.status; + CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + wlan_cstats_host_stats(sizeof(struct cstats_sap_go_stop), &stat); +} + +void +hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(struct wlan_hdd_link_info *li, + struct sap_event *sap_evt) +{ + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + tSap_StationDisassocCompleteEvent *disassoc_comp; + struct cstats_sap_go_sta_disassoc stat = {0}; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(li); + + sap_config = &ap_ctx->sap_config; + + vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + disassoc_comp = &sap_evt->sapevt.sapStationDisassocCompleteEvent; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_SAP_GO_STA_DISASSOC_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sap_go_sta_disassoc) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.sta_id = disassoc_comp->staId; + stat.status = disassoc_comp->status; + stat.status_code = disassoc_comp->status_code; + stat.reason = disassoc_comp->reason; + stat.reason_code = disassoc_comp->reason_code; + CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes); + CSTATS_MAC_COPY(stat.sta_mac, disassoc_comp->staMac.bytes); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + wlan_cstats_host_stats(sizeof(struct cstats_sap_go_sta_disassoc), + &stat); +} + +void hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event( + struct wlan_hdd_link_info *li, struct sap_event *sap_evt) +{ + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + tSap_StationAssocReassocCompleteEvent *event; + struct cstats_sap_go_sta_assoc_reassoc stat = {0}; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(li); + + sap_config = &ap_ctx->sap_config; + + vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + event = &sap_evt->sapevt.sapStationAssocReassocCompleteEvent; + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_SAP_GO_STA_ASSOC_REASSOC_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_sap_go_sta_assoc_reassoc) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + stat.sta_id = event->staId; + stat.status = event->status; + stat.status_code = event->status_code; + CSTATS_MAC_COPY(stat.sta_mac, event->staMac.bytes); + CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_sap_go_sta_assoc_reassoc), + &stat); +} + +void hdd_cp_stats_cstats_log_sap_go_dfs_event(struct wlan_hdd_link_info *li, + eSapHddEvent event_id) +{ + struct sap_config *sap_config; + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + struct cstats_sap_go_dfs_evt stat = {0}; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(li); + + sap_config = &ap_ctx->sap_config; + + vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + if (event_id == eSAP_DFS_CAC_START) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_SAP_GO_CAC_START_EVENT_ID; + } else if (event_id == eSAP_DFS_CAC_END) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_SAP_GO_CAC_END_EVENT_ID; + } else if (event_id == eSAP_DFS_RADAR_DETECT) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_SAP_GO_RADAR_DETECTED_EVENT_ID; + } else if (event_id == eSAP_DFS_CAC_INTERRUPTED) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_SAP_GO_CAC_INTERRUPTED_EVENT_ID; + } else { + hdd_err("Invalid Event"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + return; + } + + stat.cmn.hdr.length = sizeof(struct cstats_sap_go_dfs_evt) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + CSTATS_MAC_COPY(stat.bssid, sap_config->self_macaddr.bytes); + stat.freq = ap_ctx->operating_chan_freq; + wlan_reg_get_cc_and_src(wlan_vdev_get_psoc(vdev), stat.cc); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + + wlan_cstats_host_stats(sizeof(struct cstats_sap_go_dfs_evt), &stat); +} +#endif /* WLAN_CHIPSET_STATS */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h new file mode 100644 index 0000000000..0b5409fc52 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd.h @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_HOSTAPD_H) +#define WLAN_HDD_HOSTAPD_H + +/** + * DOC: wlan_hdd_hostapd.h + * + * WLAN Host Device driver hostapd header file + */ + +/* Include files */ + +#include +#include +#include +#include +#include + +/* Preprocessor definitions and constants */ + +struct hdd_adapter *hdd_wlan_create_ap_dev(struct hdd_context *hdd_ctx, + tSirMacAddr macAddr, + unsigned char name_assign_type, + uint8_t *name); + +enum csr_akm_type +hdd_translate_rsn_to_csr_auth_type(uint8_t auth_suite[4]); + +/** + * hdd_filter_ft_info() - + * This function to filter fast BSS transition related IE + * @frame: pointer to the input frame. + * @len: input frame length. + * @ft_info_len: store the total length of FT related IE. + * + * Return: pointer to a buffer which stored the FT related IE + * This is a malloced memory that must be freed by the caller + */ + +void *hdd_filter_ft_info(const uint8_t *frame, + size_t len, uint32_t *ft_info_len); + +/** + * hdd_softap_set_channel_change() - + * This function to support SAP channel change with CSA IE + * set in the beacons. + * + * @dev: pointer to the net device. + * @target_chan_freq: target channel frequency. + * @target_bw: Target bandwidth to move. + * If no bandwidth is specified, the value is CH_WIDTH_MAX + * @forced: Force to switch channel, ignore SCC/MCC check + * + * Return: 0 for success, non zero for failure + */ +int hdd_softap_set_channel_change(struct net_device *dev, + int target_chan_freq, + enum phy_ch_width target_bw, + bool forced); +/** + * hdd_stop_sap_set_tx_power() - Function to set tx power + * for unsafe channel if restriction bit mask is set else stop the SAP. + * @psoc: PSOC object information + * @adapter: AP/SAP adapter + * + * This function set tx power/stop the SAP interface + * + * Return: + * + */ +void hdd_stop_sap_set_tx_power(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * hdd_sap_restart_with_channel_switch() - SAP channel change with E/CSA + * @psoc: psoc common object + * @ap_adapter: HDD adapter + * @target_chan_freq: Channel frequency to which switch must happen + * @target_bw: Bandwidth of the target channel + * @forced: Force to switch channel, ignore SCC/MCC check + * + * Invokes the necessary API to perform channel switch for the SAP or GO + * + * Return: QDF_STATUS_SUCCESS if successfully + */ +QDF_STATUS hdd_sap_restart_with_channel_switch(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *ap_adapter, + uint32_t target_chan_freq, + uint32_t target_bw, + bool forced); + +/** + * hdd_sap_restart_chan_switch_cb() - Function to restart SAP with + * a different channel + * @psoc: PSOC object information + * @vdev_id: vdev id + * @ch_freq: channel to switch + * @channel_bw: channel bandwidth + * @forced: Force to switch channel, ignore SCC/MCC check + * + * This function restarts SAP with a different channel + * + * Return: QDF_STATUS_SUCCESS if successfully + * + */ +QDF_STATUS hdd_sap_restart_chan_switch_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t ch_freq, + uint32_t channel_bw, bool forced); + +/** + * wlan_hdd_check_cc_intf_cb() - Check force SCC for vdev interface. + * @psoc: PSOC object information + * @vdev_id: vdev id + * @ch_freq: channel frequency to switch to + * + * This function will return a channel frequency to avoid MCC for SAP/GO. + * + * Return: QDF_STATUS_SUCCESS if successfully + * + */ +QDF_STATUS wlan_hdd_check_cc_intf_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t *ch_freq); + +/** + * wlan_hdd_get_channel_for_sap_restart() - Function to get + * suitable channel and restart SAP + * @psoc: PSOC object information + * @vdev_id: vdev id + * @ch_freq: channel to be returned + * + * This function gets the channel parameters to restart SAP + * + * Return: None + * + */ +QDF_STATUS wlan_hdd_get_channel_for_sap_restart( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t *ch_freq); + +/** + * wlan_get_sap_acs_band() - Get sap acs band + * + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @acs_band: Pointer to acs_band + * + * This function is used to get sap acs band from sap config + * + * Return: QDF_STATUS_SUCCESS if successful + */ +uint32_t +wlan_get_sap_acs_band(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint32_t *acs_band); + +/** + * wlan_get_ap_prefer_conc_ch_params() - Get prefer sap target channel + * bw parameters + * @psoc: pointer to psoc + * @vdev_id: vdev id + * @chan_freq: sap channel + * @ch_params: output channel parameters + * + * This function is used to get prefer sap target channel bw during sap force + * scc CSA. The new bw will not exceed the original bw during start ap + * request. + * + * Return: QDF_STATUS_SUCCESS if successfully + */ +QDF_STATUS +wlan_get_ap_prefer_conc_ch_params( + struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint32_t chan_freq, + struct ch_params *ch_params); + +/** + * hdd_get_ap_6ghz_capable() - Get ap vdev 6ghz capable flags + * @psoc: PSOC object information + * @vdev_id: vdev id + * + * This function gets 6ghz capable information based on hdd ap adapter + * context. + * + * Return: uint32_t, vdev 6g capable flags from enum conn_6ghz_flag + */ +uint32_t hdd_get_ap_6ghz_capable(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); +#endif + +/** + * wlan_hdd_set_sap_csa_reason() - Function to set + * sap csa reason + * @psoc: PSOC object information + * @vdev_id: vdev id + * @reason: reason to be updated + * + * This function sets the reason for SAP channel switch + * + * Return: None + * + */ +void wlan_hdd_set_sap_csa_reason(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t reason); +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); + +eCsrEncryptionType +hdd_translate_rsn_to_csr_encryption_type(uint8_t cipher_suite[4]); + +enum csr_akm_type +hdd_translate_wpa_to_csr_auth_type(uint8_t auth_suite[4]); + +eCsrEncryptionType +hdd_translate_wpa_to_csr_encryption_type(uint8_t cipher_suite[4]); + +QDF_STATUS hdd_softap_sta_deauth(struct hdd_adapter *adapter, + struct csr_del_sta_params *param); +void hdd_softap_sta_disassoc(struct hdd_adapter *adapter, + struct csr_del_sta_params *param); + +QDF_STATUS hdd_hostapd_sap_event_cb(struct sap_event *sap_event, + void *context); +/** + * hdd_init_ap_mode() - to init the AP adaptor + * @adapter: SAP/GO adapter + * @reinit: true if re-init, otherwise initial init + * @rtnl_held: true if rtnl lock is taken, otherwise false + * + * This API can be called to open the SAP session as well as + * to create and store the vdev object. It also initializes necessary + * SAP adapter related params. + */ +QDF_STATUS hdd_init_ap_mode(struct hdd_adapter *adapter, + bool reinit, + bool rtnl_held); + +/** + * hdd_deinit_ap_mode() - to deinit the AP adaptor + * @link_info: Link info pointer in HDD adapter + * + * This API can be called to close the SAP session as well as + * release the vdev object completely. It also deinitializes necessary + * SAP adapter related params. + */ +void hdd_deinit_ap_mode(struct wlan_hdd_link_info *link_info); + +void hdd_set_ap_ops(struct net_device *dev); +/** + * hdd_sap_create_ctx() - Wrapper API to create SAP context + * @adapter: pointer to adapter + * + * This wrapper API can be called to create the sap context. It will + * eventually calls SAP API to create the sap context + * + * Return: true or false based on overall success or failure + */ +bool hdd_sap_create_ctx(struct hdd_adapter *adapter); +/** + * hdd_sap_destroy_ctx() - Wrapper API to destroy SAP context + * @link_info: Pointer of link_info in adapter + * + * This wrapper API can be called to destroy the sap context. It will + * eventually calls SAP API to destroy the sap context + * + * Return: true or false based on overall success or failure + */ +bool hdd_sap_destroy_ctx(struct wlan_hdd_link_info *link_info); +/** + * hdd_sap_destroy_ctx_all() - Wrapper API to destroy all SAP context + * @hdd_ctx: pointer to HDD context + * @is_ssr: true if SSR is in progress + * + * This wrapper API can be called to destroy all the sap context. + * if is_ssr is true, it will return as sap_ctx will be used when + * restart sap. + * + * Return: none + */ +void hdd_sap_destroy_ctx_all(struct hdd_context *hdd_ctx, bool is_ssr); + +/** + * hdd_hostapd_stop_no_trans() - hdd stop function for hostapd interface + * @dev: pointer to net_device structure + * + * This is called in response to ifconfig down. Vdev sync transaction + * should be started before calling this API. + * + * Return - 0 for success non-zero for failure + */ +int hdd_hostapd_stop_no_trans(struct net_device *dev); + +int hdd_hostapd_stop(struct net_device *dev); +int hdd_sap_context_init(struct hdd_context *hdd_ctx); +void hdd_sap_context_destroy(struct hdd_context *hdd_ctx); +#ifdef QCA_HT_2040_COEX +QDF_STATUS hdd_set_sap_ht2040_mode(struct hdd_adapter *adapter, + uint8_t channel_type); + +/** + * hdd_get_sap_ht2040_mode() - get ht2040 mode + * @adapter: pointer to adapter + * @channel_type: given channel type + * + * Return: QDF_STATUS_SUCCESS if successfully + */ +QDF_STATUS hdd_get_sap_ht2040_mode(struct hdd_adapter *adapter, + enum eSirMacHTChannelType *channel_type); +#else +static inline QDF_STATUS hdd_set_sap_ht2040_mode(struct hdd_adapter *adapter, + uint8_t channel_type) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS hdd_get_sap_ht2040_mode( + struct hdd_adapter *adapter, + enum eSirMacHTChannelType *channel_type) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +#ifdef CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT +/** + * wlan_hdd_cfg80211_stop_ap() - stop sap + * @wiphy: Pointer to wiphy + * @dev: Pointer to netdev + * @link_id: Link id for which this stop_ap is received. + * + * Return: zero for success non-zero for failure + */ +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev, + unsigned int link_id); +#else +int wlan_hdd_cfg80211_stop_ap(struct wiphy *wiphy, + struct net_device *dev); +#endif + +int wlan_hdd_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params); + +int wlan_hdd_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *params); + +/** + * hdd_is_peer_associated - is peer connected to softap + * @adapter: pointer to softap adapter + * @mac_addr: address to check in peer list + * + * This function has to be invoked only when bss is started and is used + * to check whether station with specified addr is peer or not + * + * Return: true if peer mac, else false + */ +bool hdd_is_peer_associated(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr); + +int hdd_destroy_acs_timer(struct hdd_adapter *adapter); + +QDF_STATUS wlan_hdd_config_acs(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter); + +void hdd_sap_indicate_disconnect_for_sta(struct hdd_adapter *adapter); + +/** + * hdd_handle_acs_2g_preferred_sap_conc() - Handle 2G pereferred SAP + * concurrency with GO + * @psoc: soc object + * @adapter: HDD adapter context + * @sap_config: sap config + * + * In SAP+GO concurrency, if GO is started on 2G and SAP is + * doing ACS with 2G preferred channel list, then we will + * move GO to 5G band. The purpose is to have more choice + * in SAP ACS instead of starting on GO home channel for SCC. + * This API is to check such condition and move GO to 5G. + * + * Return: void + */ +void +hdd_handle_acs_2g_preferred_sap_conc(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct sap_config *sap_config); + +/** + * wlan_hdd_disable_channels() - Cache the channels + * and current state of the channels from the channel list + * received in the command and disable the channels on the + * wiphy and reg table. + * @hdd_ctx: Pointer to hdd context + * + * Return: 0 on success, Error code on failure + */ +int wlan_hdd_disable_channels(struct hdd_context *hdd_ctx); + +/* + * hdd_check_and_disconnect_sta_on_invalid_channel() - Disconnect STA if it is + * on invalid channel + * @hdd_ctx: pointer to hdd context + * @reason: Mac Disconnect reason code as per @enum wlan_reason_code + * + * STA should be disconnected before starting the SAP if it is on indoor + * channel. + * + * Return: void + */ +void +hdd_check_and_disconnect_sta_on_invalid_channel(struct hdd_context *hdd_ctx, + enum wlan_reason_code reason); + +/** + * hdd_convert_dot11mode_from_phymode() - get dot11 mode from phymode + * @phymode: phymode of sta associated to SAP + * + * The function is to convert the phymode to corresponding dot11 mode + * + * Return: dot11mode. + */ +enum qca_wlan_802_11_mode hdd_convert_dot11mode_from_phymode(int phymode); + +/** + * hdd_stop_sap_due_to_invalid_channel() - to stop sap in case of invalid chnl + * @work: pointer to work structure + * + * Let's say SAP detected RADAR and trying to select the new channel and if no + * valid channel is found due to none of the channels are available or + * regulatory restriction then SAP needs to be stopped. so SAP state-machine + * will create a work to stop the bss + * + * stop bss has to happen through worker thread because radar indication comes + * from FW through mc thread or main host thread and if same thread is used to + * do stopbss then waiting for stopbss to finish operation will halt mc thread + * to freeze which will trigger stopbss timeout. Instead worker thread can do + * the stopbss operation while mc thread waits for stopbss to finish. + * + * Return: none + */ +void hdd_stop_sap_due_to_invalid_channel(struct work_struct *work); + +/** + * hdd_is_any_sta_connecting() - check if any sta is connecting + * @hdd_ctx: hdd context + * + * Return: true if any sta is connecting + */ +bool hdd_is_any_sta_connecting(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_configure_twt_responder() - configure twt responder in sap_config + * @hdd_ctx: Pointer to hdd context + * @twt_responder: twt responder configure value + * + * Return: none + */ +void +wlan_hdd_configure_twt_responder(struct hdd_context *hdd_ctx, + bool twt_responder); +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_hdd_mlo_reset() - reset mlo configuration if start bss fails + * @link_info: Pointer to link_info in hostapd adapter + * + * Return: void + */ +void wlan_hdd_mlo_reset(struct wlan_hdd_link_info *link_info); +#else +static inline void wlan_hdd_mlo_reset(struct wlan_hdd_link_info *link_info) +{ +} +#endif /* end WLAN_FEATURE_11BE_MLO */ + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +/** + * hdd_sap_is_acs_in_progress() - API to return if ACS is in progress + * @vdev: pointer t vdev object + * + * Return: bool + */ +bool hdd_sap_is_acs_in_progress(struct wlan_objmgr_vdev *vdev); +#else +static inline +bool hdd_sap_is_acs_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif + +#ifdef WLAN_CHIPSET_STATS +/* + * hdd_cp_stats_cstats_sap_go_start_event() - chipset stats for sap/go start + * event + * + * @link_info: pointer to link_info object + * @sap_event: pointer to sap_event object + * + * Return : void + */ +void +hdd_cp_stats_cstats_sap_go_start_event(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event); + +/** + * hdd_cp_stats_cstats_sap_go_stop_event() - chipset stats for sap/go stop event + * + * @link_info: pointer to link_info object + * @sap_event: pointer to sap_event object + * + * Return : void + */ +void +hdd_cp_stats_cstats_sap_go_stop_event(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event); + +/** + * hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event() - chipset stats for + * sap/go STA disconnect event + * + * @li: pointer to link_info object + * @sap_evt: pointer to sap_event object + * + * Return : void + */ +void +hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(struct wlan_hdd_link_info *li, + struct sap_event *sap_evt); + +/** + * hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event() - chipset stats for + * sap/go STA assoc event + * + * @li: pointer to link_info object + * @sap_evt: pointer to sap_event object + * + * Return : void + */ +void +hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event + (struct wlan_hdd_link_info *li, struct sap_event *sap_evt); + +/** + * hdd_cp_stats_cstats_log_sap_go_dfs_event() - chipset stats for + * sap/go dfs event + * + * @li: pointer to link_info object + * @event_id: eSapHddEvent event + * + * Return : void + */ +void hdd_cp_stats_cstats_log_sap_go_dfs_event(struct wlan_hdd_link_info *li, + eSapHddEvent event_id); +#else +static inline void +hdd_cp_stats_cstats_sap_go_start_event(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event) +{ +} + +static inline void +hdd_cp_stats_cstats_sap_go_stop_event(struct wlan_hdd_link_info *link_info, + struct sap_event *sap_event) +{ +} + +static inline void +hdd_cp_stats_cstats_log_sap_go_sta_disassoc_event(struct wlan_hdd_link_info *li, + struct sap_event *sap_evt) +{ +} + +static inline void +hdd_cp_stats_cstats_log_sap_go_sta_assoc_reassoc_event + (struct wlan_hdd_link_info *li, struct sap_event *sap_evt) +{ +} + +static inline void +hdd_cp_stats_cstats_log_sap_go_dfs_event(struct wlan_hdd_link_info *li, + eSapHddEvent event_id) +{ +} +#endif /* WLAN_CHIPSET_STATS */ +#endif /* end #if !defined(WLAN_HDD_HOSTAPD_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd_wext.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd_wext.c new file mode 100644 index 0000000000..e885ad36e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd_wext.c @@ -0,0 +1,3347 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_hostapd_wext.c + * + * Linux Wireless Extensions Implementation + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_p2p.h" +#include "wma.h" +#ifdef WLAN_DEBUG +#include "wma_api.h" +#endif +#include "wlan_hdd_power.h" +#include "wlan_policy_mgr_ucfg.h" +#include +#include +#include "wlan_dfs_utils_api.h" +#include +#include +#include "wlan_mlme_ucfg_api.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_hdd_sta_info.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" +#include "cfg_ucfg_api.h" + +#define WE_WLAN_VERSION 1 + +/* WEXT limitation: MAX allowed buf len for any * + * IW_PRIV_TYPE_CHAR is 2Kbytes * + */ +#define WE_SAP_MAX_STA_INFO 0x7FF + +#define RC_2_RATE_IDX(_rc) ((_rc) & 0x7) +#define HT_RC_2_STREAMS(_rc) ((((_rc) & 0x78) >> 3) + 1) +#define RC_2_RATE_IDX_11AC(_rc) ((_rc) & 0xf) +#define HT_RC_2_STREAMS_11AC(_rc) ((((_rc) & 0x30) >> 4) + 1) + +static int hdd_sap_get_chan_width(struct hdd_adapter *adapter, int *value) +{ + struct sap_context *sap_ctx; + struct hdd_hostapd_state *hostapdstate; + + hdd_enter(); + hostapdstate = WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + + if (hostapdstate->bss_state != BSS_START) { + *value = -EINVAL; + return -EINVAL; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + + *value = wlansap_get_chan_width(sap_ctx); + hdd_debug("chan_width = %d", *value); + + return 0; +} + +int +static __iw_softap_get_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + hdd_debug("Printing CLD global INI Config"); + hdd_cfg_get_global_config(hdd_ctx, extra, QCSAP_IOCTL_MAX_STR_LEN); + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +int +static iw_softap_get_ini_cfg(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_get_ini_cfg(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_softap_set_two_ints_getnone() - Generic "set two integer" ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret; + int *value = (int *)extra; + int sub_cmd = value[0]; + struct hdd_context *hdd_ctx; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_txrx_stats_req req = {0}; + struct hdd_station_info *sta_info, *tmp = NULL; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (qdf_unlikely(!soc)) { + hdd_err("soc is NULL"); + return -EINVAL; + } + + switch (sub_cmd) { + case QCSAP_PARAM_SET_TXRX_STATS: + { + req.stats = value[1]; + req.mac_id = value[2]; + hdd_info("QCSAP_PARAM_SET_TXRX_STATS stats_id: %d mac_id: %d", + req.stats, req.mac_id); + + if (value[1] == CDP_TXRX_STATS_28) { + req.peer_addr = (char *)&adapter->mac_addr; + ret = cdp_txrx_stats_request(soc, + adapter->deflink->vdev_id, + &req); + + hdd_for_each_sta_ref_safe( + adapter->sta_info_list, sta_info, tmp, + STA_INFO_SAP_SET_TWO_INTS_GETNONE) { + hdd_debug("bss_id: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + sta_info->sta_mac.bytes)); + + req.peer_addr = (char *) + &sta_info->sta_mac; + ret = cdp_txrx_stats_request( + soc, adapter->deflink->vdev_id, &req); + hdd_put_sta_info_ref( + &adapter->sta_info_list, &sta_info, + true, + STA_INFO_SAP_SET_TWO_INTS_GETNONE); + } + } else { + ret = cdp_txrx_stats_request(soc, + adapter->deflink->vdev_id, + &req); + } + + break; + } + + /* Firmware debug log */ + case QCSAP_IOCTL_SET_FW_CRASH_INJECT: + ret = hdd_crash_inject(adapter, value[1], value[2]); + break; + + case QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL: + hdd_set_dump_dp_trace(value[1], value[2]); + break; + + case QCSAP_ENABLE_FW_PROFILE: + hdd_debug("QCSAP_ENABLE_FW_PROFILE: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command( + adapter->deflink->vdev_id, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + value[1], value[2], DBG_CMD); + break; + + case QCSAP_SET_FW_PROFILE_HIST_INTVL: + hdd_debug("QCSAP_SET_FW_PROFILE_HIST_INTVL: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command( + adapter->deflink->vdev_id, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + value[1], value[2], DBG_CMD); + break; + + case QCSAP_SET_WLAN_SUSPEND: + hdd_info("SAP unit-test suspend(%d, %d)", value[1], value[2]); + ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy, dev, + value[1], value[2]); + break; + + case QCSAP_SET_WLAN_RESUME: + ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy, dev); + break; + + case QCSAP_SET_BA_AGEING_TIMEOUT: + hdd_info("QCSAP_SET_BA_AGEING_TIMEOUT: AC[%d] timeout[%d]", + value[1], value[2]); + /* + * value[1] : suppose to be access class, value between[0-3] + * value[2]: suppose to be duration in seconds + */ + cdp_set_ba_timeout(soc, value[1], value[2]); + break; + + default: + hdd_err("Invalid IOCTL command: %d", sub_cmd); + break; + } + + return ret; +} + +/** + * iw_softap_set_two_ints_getnone() - Generic "set two integer" ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_softap_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_set_two_ints_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static void print_mac_list(struct qdf_mac_addr *macList, uint8_t size) +{ + int i; + uint8_t *macArray; + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + pr_info("ACL entry %i - "QDF_MAC_ADDR_FMT"\n", + i, QDF_MAC_ADDR_REF(macArray)); + } +} + +static QDF_STATUS hdd_print_acl(struct hdd_adapter *adapter) +{ + eSapMacAddrACL acl_mode; + struct qdf_mac_addr maclist[MAX_ACL_MAC_ADDRESS]; + uint16_t listnum; + struct sap_context *sap_ctx; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + qdf_mem_zero(&maclist[0], sizeof(maclist)); + if (QDF_STATUS_SUCCESS == wlansap_get_acl_mode(sap_ctx, &acl_mode)) { + pr_info("******** ACL MODE *********\n"); + switch (acl_mode) { + case eSAP_ACCEPT_UNLESS_DENIED: + pr_info("ACL Mode = ACCEPT_UNLESS_DENIED\n"); + break; + case eSAP_DENY_UNLESS_ACCEPTED: + pr_info("ACL Mode = DENY_UNLESS_ACCEPTED\n"); + break; + case eSAP_SUPPORT_ACCEPT_AND_DENY: + pr_info("ACL Mode = ACCEPT_AND_DENY\n"); + break; + case eSAP_ALLOW_ALL: + pr_info("ACL Mode = ALLOW_ALL\n"); + break; + default: + pr_info("Invalid SAP ACL Mode = %d\n", acl_mode); + return QDF_STATUS_E_FAILURE; + } + } else { + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS == wlansap_get_acl_accept_list(sap_ctx, + &maclist[0], + &listnum)) { + pr_info("******* ALLOW LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&maclist[0], listnum); + } else { + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS == wlansap_get_acl_deny_list(sap_ctx, + &maclist[0], + &listnum)) { + pr_info("******* DENY LIST ***********\n"); + if (listnum <= MAX_ACL_MAC_ADDRESS) + print_mac_list(&maclist[0], listnum); + } else { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +int +static __iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + mac_handle_t mac_handle; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + QDF_STATUS status; + int ret = 0; + struct hdd_context *hdd_ctx; + bool bval = false; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("mac handle is null"); + return -EINVAL; + } + + switch (sub_cmd) { + case QCASAP_SET_RADAR_DBG: + hdd_debug("QCASAP_SET_RADAR_DBG called with: value: %x", + set_value); + wlan_sap_enable_phy_error_logs(mac_handle, set_value); + break; + + case QCSAP_PARAM_CLR_ACL: + if (QDF_STATUS_SUCCESS != wlansap_clear_acl( + WLAN_HDD_GET_SAP_CTX_PTR(link_info))) { + ret = -EIO; + } + break; + + case QCSAP_PARAM_ACL_MODE: + if ((eSAP_ALLOW_ALL < (eSapMacAddrACL) set_value) || + (eSAP_ACCEPT_UNLESS_DENIED > (eSapMacAddrACL) set_value)) { + hdd_err("Invalid ACL Mode value: %d", set_value); + ret = -EINVAL; + } else { + wlansap_set_acl_mode( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + set_value); + } + break; + + case QCSAP_PARAM_SET_CHANNEL_CHANGE: + if ((QDF_SAP_MODE == adapter->device_mode) || + (QDF_P2P_GO_MODE == adapter->device_mode)) { + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + link_info->vdev_id, + CSA_REASON_USER_INITIATED); + hdd_debug("SET Channel Change to new channel= %d", + set_value); + if (set_value <= wlan_reg_max_5ghz_ch_num()) + set_value = wlan_reg_legacy_chan_to_freq( + hdd_ctx->pdev, + set_value); + + ret = hdd_softap_set_channel_change(dev, set_value, + CH_WIDTH_MAX, + false); + } else { + hdd_err("Channel Change Failed, Device in test mode"); + ret = -EINVAL; + } + break; + + case QCSAP_PARAM_CONC_SYSTEM_PREF: + hdd_debug("New preference: %d", set_value); + ucfg_policy_mgr_set_sys_pref(hdd_ctx->psoc, set_value); + break; + + case QCSAP_PARAM_MAX_ASSOC: + if (set_value < cfg_min(CFG_ASSOC_STA_LIMIT)) { + hdd_err("Invalid setMaxAssoc value %d", + set_value); + ret = -EINVAL; + } else { + if (set_value > cfg_max(CFG_ASSOC_STA_LIMIT)) { + hdd_warn("setMaxAssoc %d > max allowed %d.", + set_value, + cfg_max(CFG_ASSOC_STA_LIMIT)); + hdd_warn("Setting it to max allowed and continuing"); + set_value = cfg_max(CFG_ASSOC_STA_LIMIT); + } + if (ucfg_mlme_set_assoc_sta_limit(hdd_ctx->psoc, + set_value) != + QDF_STATUS_SUCCESS) { + hdd_err("CFG_ASSOC_STA_LIMIT failed"); + ret = -EIO; + } + + } + break; + + case QCSAP_PARAM_HIDE_SSID: + { + QDF_STATUS status; + + /* + * Reject hidden ssid param update if reassoc in progress on + * any adapter. sme_is_any_session_in_middle_of_roaming is for + * LFR2 and hdd_is_roaming_in_progress is for LFR3 + */ + if (hdd_is_roaming_in_progress(hdd_ctx) || + sme_is_any_session_in_middle_of_roaming(mac_handle)) { + hdd_info("Reassociation in progress"); + return -EINVAL; + } + + /* + * Disable Roaming on all adapters before start of + * start of Hidden ssid connection + */ + wlan_hdd_set_roaming_state(link_info, RSO_START_BSS, false); + + status = sme_update_session_param(mac_handle, + link_info->vdev_id, + SIR_PARAM_SSID_HIDDEN, set_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("QCSAP_PARAM_HIDE_SSID failed"); + wlan_hdd_set_roaming_state(link_info, RSO_START_BSS, + true); + return -EIO; + } + break; + } + case QCSAP_PARAM_SET_MC_RATE: + { + tSirRateUpdateInd rate_update = {0}; + + hdd_debug("MC Target rate %d", set_value); + qdf_copy_macaddr(&rate_update.bssid, + &adapter->mac_addr); + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("unable to get vht_enable2x2"); + ret = -1; + } + rate_update.nss = (bval == 0) ? 0 : 1; + + rate_update.dev_mode = adapter->device_mode; + rate_update.mcastDataRate24GHz = set_value; + rate_update.mcastDataRate24GHzTxFlag = 1; + rate_update.mcastDataRate5GHz = set_value; + rate_update.bcastDataRate = -1; + status = sme_send_rate_update_ind(mac_handle, &rate_update); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SET_MC_RATE failed"); + ret = -1; + } + break; + } + + case QCSAP_PARAM_SET_TXRX_FW_STATS: + { + hdd_debug("QCSAP_PARAM_SET_TXRX_FW_STATS val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + set_value, VDEV_CMD); + break; + } + + /* Firmware debug log */ + case QCSAP_DBGLOG_LOG_LEVEL: + { + hdd_debug("QCSAP_DBGLOG_LOG_LEVEL val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_VAP_ENABLE: + { + hdd_debug("QCSAP_DBGLOG_VAP_ENABLE val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_VAP_ENABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_VAP_DISABLE: + { + hdd_debug("QCSAP_DBGLOG_VAP_DISABLE val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_VAP_DISABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MODULE_ENABLE: + { + hdd_debug("QCSAP_DBGLOG_MODULE_ENABLE val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_MODULE_ENABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MODULE_DISABLE: + { + hdd_debug("QCSAP_DBGLOG_MODULE_DISABLE val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_MODULE_DISABLE, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_MOD_LOG_LEVEL: + { + hdd_debug("QCSAP_DBGLOG_MOD_LOG_LEVEL val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_MOD_LOG_LEVEL, + set_value, DBG_CMD); + break; + } + + case QCSAP_DBGLOG_TYPE: + { + hdd_debug("QCSAP_DBGLOG_TYPE val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_TYPE, + set_value, DBG_CMD); + break; + } + case QCSAP_DBGLOG_REPORT_ENABLE: + { + hdd_debug("QCSAP_DBGLOG_REPORT_ENABLE val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_DBGLOG_REPORT_ENABLE, + set_value, DBG_CMD); + break; + } + case QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY: + { + wlan_hdd_set_mcc_latency(adapter, set_value); + break; + } + + case QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA: + { + hdd_debug("iwpriv cmd to set MCC quota value %dms", + set_value); + ret = wlan_hdd_go_set_mcc_p2p_quota(adapter, + set_value); + break; + } + + case QCASAP_TXRX_FWSTATS_RESET: + { + hdd_debug("WE_TXRX_FWSTATS_RESET val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + set_value, VDEV_CMD); + break; + } + + case QCSAP_PARAM_RTSCTS: + { + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_enable_rtscts, + set_value, VDEV_CMD); + if (ret) { + hdd_err("FAILED TO SET RTSCTS at SAP"); + ret = -EIO; + } + break; + } + case QCASAP_SET_11N_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + struct sap_config *config = + &link_info->session.ap.sap_config; + + hdd_debug("SET_HT_RATE val %d", set_value); + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX(set_value); + if (set_value & 0x80) { + if (config->SapHw_mode == + eCSR_DOT11_MODE_11b + || config->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY + || config->SapHw_mode == + eCSR_DOT11_MODE_11g + || config->SapHw_mode == + eCSR_DOT11_MODE_11g_ONLY + || config->SapHw_mode == + eCSR_DOT11_MODE_abg + || config->SapHw_mode == + eCSR_DOT11_MODE_11a) { + hdd_err("Not valid mode for HT"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(set_value) - 1; + } else if (set_value & 0x10) { + if (config->SapHw_mode == + eCSR_DOT11_MODE_11a) { + hdd_err("Not valid for cck"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_CCK; + /* Enable Short preamble always + * for CCK except 1mbps + */ + if (rix != 0x3) + rix |= 0x4; + } else { + if (config->SapHw_mode == + eCSR_DOT11_MODE_11b + || config->SapHw_mode == + eCSR_DOT11_MODE_11b_ONLY) { + hdd_err("Not valid for OFDM"); + ret = -EIO; + break; + } + preamble = WMI_RATE_PREAMBLE_OFDM; + } + set_value = hdd_assemble_rate_code(preamble, nss, rix); + } + hdd_debug("SET_HT_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_fixed_rate, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SET_VHT_RATE: + { + uint8_t preamble = 0, nss = 0, rix = 0; + struct sap_config *config = + &link_info->session.ap.sap_config; + + if (config->SapHw_mode < eCSR_DOT11_MODE_11ac || + config->SapHw_mode == eCSR_DOT11_MODE_11ax_ONLY || + config->SapHw_mode == eCSR_DOT11_MODE_11be_ONLY) { + hdd_err("SET_VHT_RATE: SapHw_mode= 0x%x, ch_freq: %d", + config->SapHw_mode, config->chan_freq); + ret = -EIO; + break; + } + + if (set_value != 0xff) { + rix = RC_2_RATE_IDX_11AC(set_value); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(set_value) - 1; + + set_value = hdd_assemble_rate_code(preamble, nss, rix); + } + hdd_debug("SET_VHT_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_fixed_rate, + set_value, VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + hdd_debug("QCASAP_SET_SHORT_GI val %d", set_value); + ret = hdd_we_set_short_gi(link_info, set_value); + if (ret) + hdd_err("Failed to set ShortGI value ret: %d", ret); + break; + } + + case QCSAP_SET_AMPDU: + { + hdd_debug("QCSAP_SET_AMPDU %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + GEN_VDEV_PARAM_AMPDU, + set_value, GEN_CMD); + break; + } + + case QCSAP_SET_AMSDU: + { + hdd_debug("QCSAP_SET_AMSDU %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + GEN_VDEV_PARAM_AMSDU, + set_value, GEN_CMD); + break; + } + case QCSAP_GTX_HT_MCS: + { + hdd_debug("wmi_vdev_param_gtx_ht_mcs %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_ht_mcs, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_VHT_MCS: + { + hdd_debug("wmi_vdev_param_gtx_vht_mcs %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_vht_mcs, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_USRCFG: + { + hdd_debug("wmi_vdev_param_gtx_usr_cfg %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_usr_cfg, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_THRE: + { + hdd_debug("wmi_vdev_param_gtx_thre %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_thre, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_MARGIN: + { + hdd_debug("wmi_vdev_param_gtx_margin %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_margin, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_STEP: + { + hdd_debug("wmi_vdev_param_gtx_step %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_step, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_MINTPC: + { + hdd_debug("wmi_vdev_param_gtx_mintpc %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_mintpc, + set_value, GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hdd_debug("wmi_vdev_param_gtx_bw_mask%d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_gtx_bw_mask, + set_value, GTX_CMD); + break; + } + + case QCASAP_SET_TM_LEVEL: + { + hdd_debug("Set Thermal Mitigation Level %d", set_value); + (void)sme_set_thermal_level(mac_handle, set_value); + break; + } + + case QCASAP_SET_DFS_IGNORE_CAC: + { + hdd_debug("Set Dfs ignore CAC %d", set_value); + + if (adapter->device_mode != QDF_SAP_MODE) + return -EINVAL; + + ret = wlansap_set_dfs_ignore_cac(mac_handle, set_value); + break; + } + + case QCASAP_SET_DFS_TARGET_CHNL: + { + hdd_debug("Set Dfs target channel %d", set_value); + + if (adapter->device_mode != QDF_SAP_MODE) + return -EINVAL; + + ret = wlansap_set_dfs_target_chnl(mac_handle, + wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, + set_value)); + break; + } + + case QCASAP_SET_HE_BSS_COLOR: + if (adapter->device_mode != QDF_SAP_MODE) + return -EINVAL; + + status = sme_set_he_bss_color(mac_handle, + link_info->vdev_id, + set_value); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SET_HE_BSS_COLOR failed"); + return -EIO; + } + break; + case QCASAP_SET_DFS_NOL: + wlansap_set_dfs_nol( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + (eSapDfsNolType) set_value); + break; + + case QCASAP_SET_RADAR_CMD: + { + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_pdev *pdev; + struct radar_found_info radar; + + hdd_debug("Set QCASAP_SET_RADAR_CMD val %d", set_value); + + pdev = hdd_ctx->pdev; + if (!pdev) { + hdd_err("null pdev"); + return -EINVAL; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + qdf_mem_zero(&radar, sizeof(radar)); + if (wlansap_is_channel_in_nol_list(ap_ctx->sap_context, + ap_ctx->operating_chan_freq, + PHY_SINGLE_CHANNEL_CENTERED)) + hdd_debug("Ignore set radar, op ch_freq(%d) is in nol", + ap_ctx->operating_chan_freq); + else if (WLAN_UMAC_VDEV_ID_MAX != + policy_mgr_get_dfs_beaconing_session_id(hdd_ctx->psoc)) + tgt_dfs_process_radar_ind(pdev, &radar); + else + hdd_debug("Ignore set radar, op ch_freq(%d) is not dfs", + ap_ctx->operating_chan_freq); + + break; + } + case QCASAP_TX_CHAINMASK_CMD: + { + hdd_debug("QCASAP_TX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_tx_chain_mask, + set_value, PDEV_CMD); + ret = hdd_set_antenna_mode(link_info, set_value); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hdd_debug("QCASAP_RX_CHAINMASK_CMD val %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_rx_chain_mask, + set_value, PDEV_CMD); + ret = hdd_set_antenna_mode(link_info, set_value); + break; + } + + case QCASAP_NSS_CMD: + { + hdd_debug("QCASAP_NSS_CMD val %d", set_value); + hdd_update_nss(link_info, set_value, set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_nss, + set_value, VDEV_CMD); + break; + } + + case QCSAP_IPA_UC_STAT: + { + /* If input value is non-zero get stats */ + switch (set_value) { + case 1: + ucfg_ipa_uc_stat(hdd_ctx->pdev); + break; + case 2: + ucfg_ipa_uc_info(hdd_ctx->pdev); + break; + case 3: + ucfg_ipa_uc_rt_debug_host_dump(hdd_ctx->pdev); + break; + case 4: + ucfg_ipa_dump_info(hdd_ctx->pdev); + break; + default: + /* place holder for stats clean up + * Stats clean not implemented yet on FW and IPA + */ + break; + } + return ret; + } + + case QCASAP_SET_PHYMODE: + ret = hdd_we_update_phymode(link_info, set_value); + break; + + case QCASAP_DUMP_STATS: + { + hdd_debug("QCASAP_DUMP_STATS val %d", set_value); + ret = hdd_wlan_dump_stats(adapter, set_value); + break; + } + case QCASAP_CLEAR_STATS: + { + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + hdd_debug("QCASAP_CLEAR_STATS val %d", set_value); + switch (set_value) { + case CDP_HDD_STATS: + ucfg_dp_clear_net_dev_stats(adapter->dev); + memset(&link_info->hdd_stats, 0, + sizeof(link_info->hdd_stats)); + break; + case CDP_TXRX_HIST_STATS: + ucfg_wlan_dp_clear_tx_rx_histogram(hdd_ctx->psoc); + break; + case CDP_HDD_NETIF_OPER_HISTORY: + wlan_hdd_clear_netif_queue_history(hdd_ctx); + break; + case CDP_HIF_STATS: + hdd_clear_hif_stats(); + break; + default: + if (soc) + cdp_clear_stats(soc, OL_TXRX_PDEV_ID, + set_value); + } + break; + } + case QCSAP_START_FW_PROFILING: + hdd_debug("QCSAP_START_FW_PROFILING %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + set_value, DBG_CMD); + break; + case QCASAP_PARAM_LDPC: + ret = hdd_set_ldpc(link_info, set_value); + break; + case QCASAP_PARAM_TX_STBC: + ret = hdd_set_tx_stbc(link_info, set_value); + break; + case QCASAP_PARAM_RX_STBC: + ret = hdd_set_rx_stbc(link_info, set_value); + break; + case QCASAP_SET_11AX_RATE: + ret = hdd_set_11ax_rate(adapter, set_value, + &link_info->session.ap.sap_config); + break; + case QCASAP_PARAM_DCM: + hdd_debug("Set wmi_vdev_param_he_dcm_enable: %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_he_dcm_enable, + set_value, VDEV_CMD); + break; + case QCASAP_PARAM_RANGE_EXT: + hdd_debug("Set wmi_vdev_param_he_range_ext: %d", set_value); + ret = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_he_range_ext, + set_value, VDEV_CMD); + break; + case QCSAP_SET_DEFAULT_AMPDU: + hdd_debug("QCSAP_SET_DEFAULT_AMPDU val %d", set_value); + ret = wma_cli_set_command( + (int)link_info->vdev_id, + (int)wmi_pdev_param_max_mpdus_in_ampdu, + set_value, PDEV_CMD); + break; + case QCSAP_ENABLE_RTS_BURSTING: + hdd_debug("QCSAP_ENABLE_RTS_BURSTING val %d", set_value); + ret = wma_cli_set_command( + (int)link_info->vdev_id, + (int)wmi_pdev_param_enable_rts_sifs_bursting, + set_value, PDEV_CMD); + break; + case QCSAP_SET_BTCOEX_MODE: + ret = wlan_hdd_set_btcoex_mode(link_info, set_value); + break; + case QCSAP_SET_BTCOEX_LOW_RSSI_THRESHOLD: + ret = wlan_hdd_set_btcoex_rssi_threshold(link_info, set_value); + break; + default: + hdd_err("Invalid setparam command %d value %d", + sub_cmd, set_value); + ret = -EINVAL; + break; + } + hdd_exit(); + return ret; +} + +/** + * __iw_softap_get_three() - return three value to upper layer. + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/out + * + * Return: execute result + */ +static int __iw_softap_get_three(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t *value = (uint32_t *)extra; + uint32_t sub_cmd = value[0]; + int ret = 0; /* success */ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_tsf_op_response tsf_op_resp; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case QCSAP_GET_TSF: + ret = hdd_indicate_tsf(adapter, &tsf_op_resp); + if (!ret) { + value[0] = tsf_op_resp.status; + value[1] = tsf_op_resp.time & 0xffffffff; + value[2] = (tsf_op_resp.time >> 32) & 0xffffffff; + } + break; + default: + hdd_err("Invalid getparam command: %d", sub_cmd); + ret = -EINVAL; + break; + } + return ret; +} + + +/** + * iw_softap_get_three() - return three value to upper layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int iw_softap_get_three(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_get_three(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int +static iw_softap_setparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_setparam(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int +static __iw_softap_getparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case QCSAP_PARAM_MAX_ASSOC: + if (ucfg_mlme_get_assoc_sta_limit(hdd_ctx->psoc, value) != + QDF_STATUS_SUCCESS) { + hdd_err("CFG_ASSOC_STA_LIMIT failed"); + ret = -EIO; + } + + break; + + case QCSAP_PARAM_GET_WLAN_DBG: + { + qdf_trace_display(); + *value = 0; + break; + } + + case QCSAP_PARAM_RTSCTS: + { + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_enable_rtscts, + VDEV_CMD); + break; + } + + case QCASAP_SHORT_GI: + { + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_sgi, + VDEV_CMD); + break; + } + + case QCSAP_GTX_HT_MCS: + { + hdd_debug("GET wmi_vdev_param_gtx_ht_mcs"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_ht_mcs, + GTX_CMD); + break; + } + + case QCSAP_GTX_VHT_MCS: + { + hdd_debug("GET wmi_vdev_param_gtx_vht_mcs"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_vht_mcs, + GTX_CMD); + break; + } + + case QCSAP_GTX_USRCFG: + { + hdd_debug("GET wmi_vdev_param_gtx_usr_cfg"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_usr_cfg, + GTX_CMD); + break; + } + + case QCSAP_GTX_THRE: + { + hdd_debug("GET wmi_vdev_param_gtx_thre"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_thre, + GTX_CMD); + break; + } + + case QCSAP_GTX_MARGIN: + { + hdd_debug("GET wmi_vdev_param_gtx_margin"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_margin, + GTX_CMD); + break; + } + + case QCSAP_GTX_STEP: + { + hdd_debug("GET wmi_vdev_param_gtx_step"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_step, + GTX_CMD); + break; + } + + case QCSAP_GTX_MINTPC: + { + hdd_debug("GET wmi_vdev_param_gtx_mintpc"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_mintpc, + GTX_CMD); + break; + } + + case QCSAP_GTX_BWMASK: + { + hdd_debug("GET wmi_vdev_param_gtx_bw_mask"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_bw_mask, + GTX_CMD); + break; + } + + case QCASAP_GET_DFS_NOL: + { + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_pdev *pdev; + + pdev = hdd_ctx->pdev; + if (!pdev) { + hdd_err("null pdev"); + return -EINVAL; + } + + utils_dfs_print_nol_channels(pdev); + } + break; + + case QCSAP_GET_ACL: + { + hdd_debug("QCSAP_GET_ACL"); + if (hdd_print_acl(adapter) != + QDF_STATUS_SUCCESS) { + hdd_err("QCSAP_GET_ACL returned Error: not completed"); + } + *value = 0; + break; + } + + case QCASAP_TX_CHAINMASK_CMD: + { + hdd_debug("QCASAP_TX_CHAINMASK_CMD"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_tx_chain_mask, + PDEV_CMD); + break; + } + + case QCASAP_RX_CHAINMASK_CMD: + { + hdd_debug("QCASAP_RX_CHAINMASK_CMD"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_rx_chain_mask, + PDEV_CMD); + break; + } + + case QCASAP_NSS_CMD: + { + hdd_debug("QCASAP_NSS_CMD"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_nss, + VDEV_CMD); + break; + } + case QCSAP_CAP_TSF: + ret = hdd_capture_tsf(adapter, (uint32_t *)value, 1); + break; + case QCASAP_GET_TEMP_CMD: + { + hdd_debug("QCASAP_GET_TEMP_CMD"); + ret = wlan_hdd_get_temperature(adapter, value); + break; + } + case QCSAP_GET_FW_PROFILE_DATA: + hdd_debug("QCSAP_GET_FW_PROFILE_DATA"); + ret = wma_cli_set_command( + adapter->deflink->vdev_id, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, DBG_CMD); + break; + case QCASAP_PARAM_LDPC: + { + ret = hdd_get_ldpc(adapter, value); + break; + } + case QCASAP_PARAM_TX_STBC: + { + ret = hdd_get_tx_stbc(adapter, value); + break; + } + case QCASAP_PARAM_RX_STBC: + { + ret = hdd_get_rx_stbc(adapter, value); + break; + } + case QCSAP_PARAM_CHAN_WIDTH: + { + ret = hdd_sap_get_chan_width(adapter, value); + break; + } + case QCASAP_PARAM_DCM: + { + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_dcm_enable, + VDEV_CMD); + break; + } + case QCASAP_PARAM_RANGE_EXT: + { + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_range_ext, + VDEV_CMD); + break; + } + default: + hdd_err("Invalid getparam command: %d", sub_cmd); + ret = -EINVAL; + break; + + } + hdd_exit(); + return ret; +} + +int +static iw_softap_getparam(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_getparam(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/* Usage: + * DENY_LIST = 0 + * ALLOW_LIST = 1 + * ADD MAC = 0 + * REMOVE MAC = 1 + * + * mac addr will be accepted as a 6 octet mac address with each octet + * inputted in hex for e.g. 00:0a:f5:11:22:33 will be represented as + * 0x00 0x0a 0xf5 0x11 0x22 0x33 while using this ioctl + * + * Syntax: + * iwpriv softap.0 modify_acl + * <6 octet mac addr> + * + * Examples: + * eg 1. to add a mac addr 00:0a:f5:89:89:90 to the deny list + * iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 0 0 + * eg 2. to delete a mac addr 00:0a:f5:89:89:90 from allow list + * iwpriv softap.0 modify_acl 0x00 0x0a 0xf5 0x89 0x89 0x90 1 1 + */ +static +int __iw_softap_modify_acl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + uint8_t *value = (uint8_t *) extra; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + int list_type, cmd, i; + int ret; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) + peer_mac[i] = *(value + i); + + list_type = (int)(*(value + i)); + i++; + cmd = (int)(*(value + i)); + + hdd_debug("Modify ACL mac:" QDF_MAC_ADDR_FMT " type: %d cmd: %d", + QDF_MAC_ADDR_REF(peer_mac), list_type, cmd); + + qdf_status = wlansap_modify_acl( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + peer_mac, (eSapACLType) list_type, (eSapACLCmdType) cmd); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Modify ACL failed"); + ret = -EIO; + } + hdd_exit(); + return ret; +} + +static +int iw_softap_modify_acl(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_modify_acl(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int +static __iw_softap_getchannel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx; + struct hdd_ap_ctx *ap_ctx; + int *value = (int *)extra; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + *value = 0; + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags)) + *value = wlan_reg_freq_to_chan( + hdd_ctx->pdev, + ap_ctx->operating_chan_freq); + hdd_exit(); + return 0; +} + +int +static iw_softap_getchannel(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_getchannel(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int +static __iw_softap_set_max_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx; + int *value = (int *)extra; + int set_value; + int ret; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; + struct qdf_mac_addr selfMac = QDF_MAC_ADDR_BCAST_INIT; + + hdd_enter_dev(dev); + + if (!value) + return -ENOMEM; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* Assign correct self MAC address */ + qdf_copy_macaddr(&bssid, &adapter->mac_addr); + qdf_copy_macaddr(&selfMac, &adapter->mac_addr); + + set_value = value[0]; + if (QDF_STATUS_SUCCESS != + sme_set_max_tx_power(hdd_ctx->mac_handle, bssid, + selfMac, set_value)) { + hdd_err("Setting maximum tx power failed"); + return -EIO; + } + hdd_exit(); + return 0; +} + +int +static iw_softap_set_max_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_set_max_tx_power(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifndef REMOVE_PKT_LOG +int +static __iw_softap_set_pktlog(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = netdev_priv(dev); + struct hdd_context *hdd_ctx; + int *value = (int *)extra; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (wrqu->data.length < 1 || wrqu->data.length > 2) { + hdd_err("pktlog: either 1 or 2 parameters are required"); + return -EINVAL; + } + + return hdd_process_pktlog_command(hdd_ctx, value[0], value[1]); +} + +int +static iw_softap_set_pktlog(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_set_pktlog(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#else +int +static iw_softap_set_pktlog(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return -EINVAL; +} +#endif + +int +static __iw_softap_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx; + int *value = (int *)extra; + int set_value; + struct qdf_mac_addr bssid; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + qdf_copy_macaddr(&bssid, &adapter->mac_addr); + + set_value = value[0]; + if (QDF_STATUS_SUCCESS != sme_set_tx_power( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, bssid, + adapter->device_mode, set_value)) { + hdd_err("Setting tx power failed"); + return -EIO; + } + hdd_exit(); + return 0; +} + +int +static iw_softap_set_tx_power(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_set_tx_power(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int +static __iw_softap_getassoc_stamacaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_station_info *sta_info, *tmp = NULL; + struct hdd_context *hdd_ctx; + char *buf; + int left; + int ret; + /* maclist_index must be u32 to match userspace */ + u32 maclist_index; + + hdd_enter_dev(dev); + + /* + * NOTE WELL: this is a "get" ioctl but it uses an even ioctl + * number, and even numbered iocts are supposed to have "set" + * semantics. Hence the wireless extensions support in the kernel + * won't correctly copy the result to userspace, so the ioctl + * handler itself must copy the data. Output format is 32-bit + * record length, followed by 0 or more 6-byte STA MAC addresses. + * + * Further note that due to the incorrect semantics, the "iwpriv" + * userspace application is unable to correctly invoke this API, + * hence it is not registered in the hostapd_private_args. This + * API can only be invoked by directly invoking the ioctl() system + * call. + */ + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* make sure userspace allocated a reasonable buffer size */ + if (wrqu->data.length < sizeof(maclist_index)) { + hdd_err("invalid userspace buffer"); + return -EINVAL; + } + + /* allocate local buffer to build the response */ + buf = qdf_mem_malloc(wrqu->data.length); + if (!buf) + return -ENOMEM; + + /* start indexing beyond where the record count will be written */ + maclist_index = sizeof(maclist_index); + left = wrqu->data.length - maclist_index; + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_SAP_GETASSOC_STAMACADDR) { + if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) { + memcpy(&buf[maclist_index], &sta_info->sta_mac, + QDF_MAC_ADDR_SIZE); + maclist_index += QDF_MAC_ADDR_SIZE; + left -= QDF_MAC_ADDR_SIZE; + } + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SAP_GETASSOC_STAMACADDR); + } + + *((u32 *) buf) = maclist_index; + wrqu->data.length = maclist_index; + if (copy_to_user(wrqu->data.pointer, buf, maclist_index)) { + hdd_err("failed to copy response to user buffer"); + ret = -EFAULT; + } + qdf_mem_free(buf); + hdd_exit(); + return ret; +} + +int +static iw_softap_getassoc_stamacaddr(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_getassoc_stamacaddr(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/* Usage: + * mac addr will be accepted as a 6 octet mac address with each octet + * inputted in hex for e.g. 00:0a:f5:11:22:33 will be represented as + * 0x00 0x0a 0xf5 0x11 0x22 0x33 while using this ioctl + * + * Syntax: + * iwpriv softap.0 disassoc_sta <6 octet mac address> + * + * e.g. + * disassociate sta with mac addr 00:0a:f5:11:22:33 from softap + * iwpriv softap.0 disassoc_sta 0x00 0x0a 0xf5 0x11 0x22 0x33 + */ + +int +static __iw_softap_disassoc_sta(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx; + uint8_t *peer_macaddr; + int ret; + struct csr_del_sta_params del_sta_params; + + hdd_enter_dev(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* iwpriv tool or framework calls this ioctl with + * data passed in extra (less than 16 octets); + */ + peer_macaddr = (uint8_t *) (extra); + + hdd_debug("data " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_macaddr)); + wlansap_populate_del_sta_params(peer_macaddr, + REASON_DEAUTH_NETWORK_LEAVING, + SIR_MAC_MGMT_DISASSOC, + &del_sta_params); + hdd_softap_sta_disassoc(adapter, &del_sta_params); + + hdd_exit(); + return 0; +} + +int +static iw_softap_disassoc_sta(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_disassoc_sta(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_get_char_setnone() - Generic "get char" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret; + int sub_cmd = wrqu->data.flags; + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case QCSAP_GET_STATS: + hdd_wlan_get_stats(adapter->deflink, &wrqu->data.length, + extra, WE_MAX_STR_LEN); + break; + case QCSAP_LIST_FW_PROFILE: + hdd_wlan_list_fw_profile(&(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + } + + hdd_exit(); + return ret; +} + +/** + * iw_get_char_setnone() - Generic "get char" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_char_setnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int iw_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + uint32_t num_channels = 0; + uint8_t i = 0; + struct hdd_adapter *hostapd_adapter = (netdev_priv(dev)); + struct channel_list_info *channel_list = + (struct channel_list_info *)extra; + struct regulatory_channel *cur_chan_list = NULL; + struct hdd_context *hdd_ctx; + int ret; + QDF_STATUS status; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(hostapd_adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + cur_chan_list = qdf_mem_malloc(sizeof(*cur_chan_list) * NUM_CHANNELS); + if (!cur_chan_list) + return -ENOMEM; + + status = ucfg_reg_get_current_chan_list(hdd_ctx->pdev, cur_chan_list); + if (status != QDF_STATUS_SUCCESS) { + hdd_err_rl("Failed to get the current channel list"); + qdf_mem_free(cur_chan_list); + return -EIO; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + /* + * current channel list includes all channels. do not report + * disabled channels + */ + if (cur_chan_list[i].chan_flags & REGULATORY_CHAN_DISABLED) + continue; + + /* + * do not include 6 GHz channels since they are ambiguous with + * 2.4 GHz and 5 GHz channels. 6 GHz-aware applications should + * not be using this interface, but instead should be using the + * frequency-based interface + */ + if (wlan_reg_is_6ghz_chan_freq(cur_chan_list[i].center_freq)) + continue; + channel_list->channels[num_channels] = + cur_chan_list[i].chan_num; + num_channels++; + + } + + qdf_mem_free(cur_chan_list); + hdd_debug_rl("number of channels %d", num_channels); + channel_list->num_channels = num_channels; + wrqu->data.length = num_channels + 1; + hdd_exit(); + + return 0; +} + +int iw_get_channel_list_with_cc(struct net_device *dev, + mac_handle_t mac_handle, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + uint8_t i, len; + char *buf; + uint8_t ubuf[REG_ALPHA2_LEN + 1] = {0}; + uint8_t ubuf_len = REG_ALPHA2_LEN + 1; + struct channel_list_info channel_list; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + hdd_enter_dev(dev); + + memset(&channel_list, 0, sizeof(channel_list)); + + if (0 != iw_get_channel_list(dev, info, wrqu, (char *)&channel_list)) { + hdd_err_rl("GetChannelList Failed!!!"); + return -EINVAL; + } + + /* + * Maximum buffer needed = + * [4: 3 digits of num_chn + 1 space] + + * [REG_ALPHA2_LEN: REG_ALPHA2_LEN digits] + + * [4 * num_chn: (1 space + 3 digits of chn[i]) * num_chn] + + * [1: Terminator]. + * + * Check if sufficient buffer is available and then + * proceed to fill the buffer. + */ + if (WE_MAX_STR_LEN < + (4 + REG_ALPHA2_LEN + 4 * channel_list.num_channels + 1)) { + hdd_err_rl("Insufficient Buffer to populate channel list"); + return -EINVAL; + } + + buf = extra; + len = scnprintf(buf, WE_MAX_STR_LEN, "%u ", channel_list.num_channels); + wlan_reg_get_cc_and_src(mac->psoc, ubuf); + /* Printing Country code in getChannelList(break at '\0') */ + for (i = 0; i < (ubuf_len - 1) && ubuf[i] != 0; i++) + len += scnprintf(buf + len, WE_MAX_STR_LEN - len, "%c", ubuf[i]); + + for (i = 0; i < channel_list.num_channels; i++) + len += scnprintf(buf + len, WE_MAX_STR_LEN - len, " %u", + channel_list.channels[i]); + + wrqu->data.length = strlen(extra) + 1; + + hdd_exit(); + return 0; +} + +static +int __iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx; + int ret; + QDF_STATUS status; + uint32_t length = DOT11F_IE_RSN_MAX_LEN; + uint8_t genIeBytes[DOT11F_IE_RSN_MAX_LEN]; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* + * Actually retrieve the RSN IE from CSR. + * (We previously sent it down in the CSR Roam Profile.) + */ + status = wlan_sap_getstation_ie_information( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + &length, genIeBytes); + if (status == QDF_STATUS_SUCCESS) { + wrqu->data.length = length; + if (length > DOT11F_IE_RSN_MAX_LEN) { + hdd_err("Invalid buffer length: %d", length); + return -E2BIG; + } + qdf_mem_copy(extra, genIeBytes, length); + hdd_debug(" RSN IE of %d bytes returned", + wrqu->data.length); + } else { + wrqu->data.length = 0; + hdd_debug(" RSN IE failed to populate"); + } + + hdd_exit(); + return 0; +} + +static +int iw_get_genie(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_genie(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int +__iw_softap_stopbss(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + QDF_STATUS status; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags)) { + struct hdd_hostapd_state *hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + status = wlansap_stop_bss( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink)); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = qdf_wait_single_event(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_STOP_BSS_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("wait for single_event failed!!"); + QDF_ASSERT(0); + } + } + clear_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + adapter->deflink->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + ret = qdf_status_to_os_return(status); + } + hdd_exit(); + return ret; +} + +static int iw_softap_stopbss(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_stopbss(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int +__iw_softap_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = netdev_priv(dev); + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + wrqu->data.length = hdd_wlan_get_version(hdd_ctx, WE_MAX_STR_LEN, + extra); + hdd_exit(); + return 0; +} + +static int iw_softap_version(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_version(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int hdd_softap_get_sta_info(struct hdd_adapter *adapter, + uint8_t *buf, + int size) +{ + int written; + struct hdd_station_info *sta, *tmp = NULL; + + hdd_enter(); + + written = scnprintf(buf, size, "\nstaId staAddress\n"); + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta, tmp, + STA_INFO_SOFTAP_GET_STA_INFO) { + if (written >= size - 1) { + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta, true, + STA_INFO_SOFTAP_GET_STA_INFO); + if (tmp) + hdd_put_sta_info_ref(&adapter->sta_info_list, + &tmp, true, + STA_INFO_SOFTAP_GET_STA_INFO); + break; + } + + if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) { + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta, true, + STA_INFO_SOFTAP_GET_STA_INFO); + continue; + } + + written += scnprintf(buf + written, size - written, + QDF_MAC_ADDR_FMT + " ecsa=%d\n", + QDF_MAC_ADDR_REF(sta->sta_mac.bytes), + sta->ecsa_capable); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true, + STA_INFO_SOFTAP_GET_STA_INFO); + } + + hdd_exit(); + + return 0; +} + +static int __iw_softap_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int ret; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (hdd_validate_adapter(adapter)) + return -ENODEV; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + + ret = iw_get_channel_list_with_cc(dev, mac_handle, + info, wrqu, extra); + + if (0 != ret) + return -EINVAL; + + hdd_exit(); + return 0; +} + +static int iw_softap_get_channel_list(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_get_channel_list(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int __iw_softap_get_sta_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + adapter = netdev_priv(dev); + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = hdd_check_private_wext_control(hdd_ctx, info); + if (errno) + return errno; + + errno = hdd_softap_get_sta_info(adapter, extra, WE_SAP_MAX_STA_INFO); + if (errno) { + hdd_err("Failed to get sta info; errno:%d", errno); + return errno; + } + + wrqu->data.length = strlen(extra); + + hdd_exit(); + + return 0; +} + +static int iw_softap_get_sta_info(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_get_sta_info(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int __iw_softap_get_ba_timeout(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + uint32_t i; + enum qca_wlan_ac_type duration[QCA_WLAN_AC_ALL]; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + adapter = netdev_priv(dev); + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (!soc) { + hdd_err("Invalid handle"); + return -EINVAL; + } + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) + cdp_get_ba_timeout(soc, i, &duration[i]); + + snprintf(extra, WE_SAP_MAX_STA_INFO, + "\n|------------------------------|\n" + "|AC | BA aging timeout duration |\n" + "|--------------------------------|\n" + "|VO | %d |\n" + "|VI | %d |\n" + "|BK | %d |\n" + "|BE | %d |\n" + "|--------------------------------|\n", + duration[QCA_WLAN_AC_VO], duration[QCA_WLAN_AC_VI], + duration[QCA_WLAN_AC_BK], duration[QCA_WLAN_AC_BE]); + + wrqu->data.length = strlen(extra) + 1; + hdd_exit(); + + return 0; +} + +static int iw_softap_get_ba_timeout(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_softap_get_ba_timeout(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static +int __iw_get_softap_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx; + char *out_link_speed = (char *)extra; + uint32_t link_speed = 0; + int len = sizeof(uint32_t) + 1; + struct qdf_mac_addr mac_address; + char macaddr_string[MAC_ADDRESS_STR_LEN + 1]; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int rc, ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + hdd_debug("wrqu->data.length(%d)", wrqu->data.length); + + /* Linkspeed is allowed for GO/SAP mode */ + if (adapter->device_mode != QDF_P2P_GO_MODE && + adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -ENOTSUPP; + } + + if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1) { + if (copy_from_user(macaddr_string, + wrqu->data.pointer, MAC_ADDRESS_STR_LEN)) { + hdd_err("failed to copy data to user buffer"); + return -EFAULT; + } + macaddr_string[MAC_ADDRESS_STR_LEN - 1] = '\0'; + + if (!mac_pton(macaddr_string, mac_address.bytes)) { + hdd_err("String to Hex conversion Failed"); + return -EINVAL; + } + } + /* If no mac address is passed and/or its length is less than 17, + * link speed for first connected client will be returned. + */ + if (wrqu->data.length < 17 || !QDF_IS_STATUS_SUCCESS(status)) { + struct hdd_station_info *sta_info, *tmp = NULL; + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_GET_SOFTAP_LINKSPEED) { + if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) { + qdf_copy_macaddr(&mac_address, + &sta_info->sta_mac); + status = QDF_STATUS_SUCCESS; + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &sta_info, true, + STA_INFO_GET_SOFTAP_LINKSPEED); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_GET_SOFTAP_LINKSPEED); + break; + } + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_GET_SOFTAP_LINKSPEED); + } + } + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Invalid peer macaddress"); + return -EINVAL; + } + rc = wlan_hdd_get_linkspeed_for_peermac(adapter->deflink, + &mac_address, &link_speed); + if (rc) { + hdd_err("Unable to retrieve SME linkspeed"); + return rc; + } + + /* linkspeed in units of 500 kbps */ + link_speed = link_speed / 500; + wrqu->data.length = len; + rc = snprintf(out_link_speed, len, "%u", link_speed); + if ((rc < 0) || (rc >= len)) { + /* encoding or length error? */ + hdd_err("Unable to encode link speed"); + return -EIO; + } + hdd_exit(); + return 0; +} + +static int +iw_get_softap_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_softap_linkspeed(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_get_peer_rssi() - get station's rssi + * @dev: net device + * @info: iwpriv request information + * @wrqu: iwpriv command parameter + * @extra: extra data pointer + * + * This function will call wlan_cfg80211_mc_cp_stats_get_peer_rssi + * to get rssi + * + * Return: 0 on success, otherwise error value + */ +static int +__iw_get_peer_rssi(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret, i; + struct hdd_context *hddctx; + struct stats_event *rssi_info; + char macaddrarray[MAC_ADDRESS_STR_LEN]; + struct hdd_adapter *adapter = netdev_priv(dev); + struct qdf_mac_addr macaddress = QDF_MAC_ADDR_BCAST_INIT; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + hddctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hddctx); + if (ret != 0) + return ret; + + ret = hdd_check_private_wext_control(hddctx, info); + if (0 != ret) + return ret; + + hdd_debug("wrqu->data.length= %d", wrqu->data.length); + + if (wrqu->data.length >= MAC_ADDRESS_STR_LEN - 1) { + if (copy_from_user(macaddrarray, + wrqu->data.pointer, + MAC_ADDRESS_STR_LEN - 1)) { + hdd_info("failed to copy data from user buffer"); + return -EFAULT; + } + + macaddrarray[MAC_ADDRESS_STR_LEN - 1] = '\0'; + hdd_debug("%s", macaddrarray); + + if (!mac_pton(macaddrarray, macaddress.bytes)) + hdd_err("String to Hex conversion Failed"); + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_STATS_ID); + if (!vdev) + return -EINVAL; + + rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi(vdev, + macaddress.bytes, + &ret); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + if (ret || !rssi_info) { + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); + return ret; + } + + wrqu->data.length = scnprintf(extra, IW_PRIV_SIZE_MASK, "\n"); + for (i = 0; i < rssi_info->num_peer_stats; i++) + wrqu->data.length += + scnprintf(extra + wrqu->data.length, + IW_PRIV_SIZE_MASK - wrqu->data.length, + "["QDF_MAC_ADDR_FMT"] [%d]\n", + QDF_MAC_ADDR_REF(rssi_info->peer_stats[i].peer_macaddr), + rssi_info->peer_stats[i].peer_rssi); + + wrqu->data.length++; + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); + hdd_exit(); + + return 0; +} + +/** + * iw_get_peer_rssi() - get station's rssi + * @dev: net device + * @info: iwpriv request information + * @wrqu: iwpriv command parameter + * @extra: extra data pointer + * + * This function will call __iw_get_peer_rssi + * + * Return: 0 on success, otherwise error value + */ +static int +iw_get_peer_rssi(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_peer_rssi(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/* + * Note that the following ioctls were defined with semantics which + * cannot be handled by the "iwpriv" userspace application and hence + * they are not included in the hostapd_private_args array + * QCSAP_IOCTL_ASSOC_STA_MACADDR + */ + +static const struct iw_priv_args hostapd_private_args[] = { + { + QCSAP_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "setparam" + }, { + QCSAP_IOCTL_SETPARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "" + }, { + QCSAP_PARAM_MAX_ASSOC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMaxAssoc" + }, { + QCSAP_PARAM_HIDE_SSID, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hideSSID" + }, { + QCSAP_PARAM_SET_MC_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setMcRate" + }, { + QCSAP_PARAM_SET_TXRX_FW_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "txrx_fw_stats" + }, { + QCSAP_PARAM_SET_TXRX_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, + "txrx_stats" + }, { + QCSAP_PARAM_SET_MCC_CHANNEL_LATENCY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMccLatency" + }, { + QCSAP_PARAM_SET_MCC_CHANNEL_QUOTA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setMccQuota" + }, { + QCSAP_PARAM_SET_CHANNEL_CHANGE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setChanChange" + }, { + QCSAP_PARAM_CONC_SYSTEM_PREF, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, + "setConcSysPref" + }, +#ifdef FEATURE_FW_LOG_PARSING + /* Sub-cmds DBGLOG specific commands */ + { + QCSAP_DBGLOG_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_loglevel" + }, { + QCSAP_DBGLOG_VAP_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_vapon" + }, { + QCSAP_DBGLOG_VAP_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_vapoff" + }, { + QCSAP_DBGLOG_MODULE_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_modon" + }, { + QCSAP_DBGLOG_MODULE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_modoff" + }, { + QCSAP_DBGLOG_MOD_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_mod_loglevel" + }, { + QCSAP_DBGLOG_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "dl_type" + }, { + QCSAP_DBGLOG_REPORT_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dl_report" + }, +#endif /* FEATURE_FW_LOG_PARSING */ + { + + QCASAP_TXRX_FWSTATS_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "txrx_fw_st_rst" + }, { + QCSAP_PARAM_RTSCTS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enablertscts" + }, { + QCASAP_SET_11N_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set11NRates" + }, { + QCASAP_SET_VHT_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set11ACRates" + }, { + QCASAP_SHORT_GI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enable_short_gi" + }, { + QCSAP_SET_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ampdu" + }, { + QCSAP_SET_AMSDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "amsdu" + }, { + QCSAP_GTX_HT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxHTMcs" + }, { + QCSAP_GTX_VHT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxVHTMcs" + }, { + QCSAP_GTX_USRCFG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxUsrCfg" + }, { + QCSAP_GTX_THRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxThre" + }, { + QCSAP_GTX_MARGIN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxMargin" + }, { + QCSAP_GTX_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "gtxStep" + }, { + QCSAP_GTX_MINTPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxMinTpc" + }, { + QCSAP_GTX_BWMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gtxBWMask" + }, { + QCSAP_PARAM_CLR_ACL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setClearAcl" + }, { + QCSAP_PARAM_ACL_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setAclMode" + }, + { + QCASAP_SET_TM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setTmLevel" + }, { + QCASAP_SET_DFS_IGNORE_CAC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setDfsIgnoreCAC" + }, { + QCASAP_SET_DFS_NOL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setdfsnol" + }, { + QCASAP_SET_DFS_TARGET_CHNL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setNextChnl" + }, { + QCASAP_SET_RADAR_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setRadar" + }, + { + QCSAP_IPA_UC_STAT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "ipaucstat" + }, + { + QCASAP_TX_CHAINMASK_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_txchainmask" + }, { + QCASAP_RX_CHAINMASK_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_rxchainmask" + }, { + QCASAP_SET_HE_BSS_COLOR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_he_bss_clr" + }, { + QCASAP_NSS_CMD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "set_nss" + }, { + QCASAP_SET_PHYMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setphymode" + }, { + QCASAP_DUMP_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dumpStats" + }, { + QCASAP_CLEAR_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "clearStats" + }, { + QCSAP_START_FW_PROFILING, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "startProfile" + }, { + QCASAP_PARAM_LDPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "ldpc" + }, { + QCASAP_PARAM_TX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_tx_stbc" + }, { + QCASAP_PARAM_RX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_rx_stbc" + }, { + QCSAP_IOCTL_GETPARAM, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getparam" + }, { + QCSAP_IOCTL_GETPARAM, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "" + }, { + QCSAP_PARAM_MAX_ASSOC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getMaxAssoc" + }, { + QCSAP_PARAM_GET_WLAN_DBG, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getwlandbg" + }, { + QCSAP_GTX_BWMASK, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxBWMask" + }, { + QCSAP_GTX_MINTPC, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMinTpc" + }, { + QCSAP_GTX_STEP, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxStep" + }, { + QCSAP_GTX_MARGIN, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMargin" + }, { + QCSAP_GTX_THRE, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxThre" + }, { + QCSAP_GTX_USRCFG, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxUsrCfg" + }, { + QCSAP_GTX_VHT_MCS, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxVHTMcs" + }, { + QCSAP_GTX_HT_MCS, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxHTMcs" + }, { + QCASAP_SHORT_GI, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_short_gi" + }, { + QCSAP_PARAM_RTSCTS, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_rtscts" + }, { + QCASAP_GET_DFS_NOL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getdfsnol" + }, { + QCSAP_GET_ACL, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_acl_list" + }, { + QCASAP_PARAM_LDPC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ldpc" + }, { + QCASAP_PARAM_TX_STBC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tx_stbc" + }, { + QCASAP_PARAM_RX_STBC, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rx_stbc" + }, { + QCSAP_PARAM_CHAN_WIDTH, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_chwidth" + }, { + QCASAP_TX_CHAINMASK_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txchainmask" + }, { + QCASAP_RX_CHAINMASK_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rxchainmask" + }, { + QCASAP_NSS_CMD, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nss" + }, { + QCSAP_CAP_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "cap_tsf" + }, { + QCSAP_IOCTL_SET_NONE_GET_THREE, 0, IW_PRIV_TYPE_INT | + IW_PRIV_SIZE_FIXED | 3, "" + }, { + QCSAP_GET_TSF, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "get_tsf" + }, { + QCASAP_GET_TEMP_CMD, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_temp" + }, { + QCSAP_GET_FW_PROFILE_DATA, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getProfileData" + }, { + QCSAP_IOCTL_GET_STAWPAIE, + 0, IW_PRIV_TYPE_BYTE | DOT11F_IE_RSN_MAX_LEN, + "get_staWPAIE" + }, { + QCSAP_IOCTL_STOPBSS, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED, 0, + "stopbss" + }, { + QCSAP_IOCTL_VERSION, 0, IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "version" + }, { + QCSAP_IOCTL_GET_STA_INFO, 0, + IW_PRIV_TYPE_CHAR | WE_SAP_MAX_STA_INFO, "get_sta_info" + }, { + QCSAP_IOCTL_GET_CHANNEL, 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getchannel" + }, { + QCSAP_IOCTL_GET_BA_AGEING_TIMEOUT, 0, + IW_PRIV_TYPE_CHAR | WE_SAP_MAX_STA_INFO, "get_ba_timeout" + }, { + QCSAP_IOCTL_DISASSOC_STA, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 6, 0, + "disassoc_sta" + } + /* handler for main ioctl */ + , { + QCSAP_PRIV_GET_CHAR_SET_NONE, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "" + } + /* handler for sub-ioctl */ + , { + QCSAP_GET_STATS, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "getStats" + } + , { + QCSAP_LIST_FW_PROFILE, 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "listProfile" + } + , { + QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | 5, "getLinkSpeed" + } + , { + QCSAP_IOCTL_PRIV_GET_RSSI, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, "getRSSI" + } + , { + QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "" + } + , + /* handlers for sub-ioctl */ + { + WE_SET_WLAN_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "setwlandbg" + } + , +#ifdef CONFIG_DP_TRACE + /* handlers for sub-ioctl */ + { + WE_SET_DP_TRACE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, 0, "set_dp_trace" + } + , +#endif + /* handlers for main ioctl */ + { + QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "" + } + , { + WE_P2P_NOA_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, "SetP2pPs" + } + , { + WE_UNIT_TEST_CMD, IW_PRIV_TYPE_INT | MAX_VAR_ARGS, 0, + "setUnitTestCmd" + } +#ifdef WLAN_DEBUG + , + { + WE_SET_CHAN_AVOID, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "ch_avoid" + } +#endif + , + { + QCSAP_SET_BTCOEX_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_btc_mode" + } + , + { + QCSAP_SET_BTCOEX_LOW_RSSI_THRESHOLD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_btc_rssi" + } + , +#ifdef FW_THERMAL_THROTTLE_SUPPORT + { + WE_SET_THERMAL_THROTTLE_CFG, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, "set_thermal_cfg" + } + , +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + /* handlers for main ioctl */ + { + QCSAP_IOCTL_MODIFY_ACL, + IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 8, 0, "modify_acl" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_GET_CHANNEL_LIST, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getChannelList" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_SET_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "setTxPower" + } + , + /* handlers for main ioctl */ + { + QCSAP_IOCTL_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setTxMaxPower" + } + , + { + QCSAP_IOCTL_SET_PKTLOG, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, "pktlog" + } + , + /* Get HDD CFG Ini param */ + { + QCSAP_IOCTL_GET_INI_CFG, + 0, IW_PRIV_TYPE_CHAR | QCSAP_IOCTL_MAX_STR_LEN, "getConfig" + } + , + /* handlers for main ioctl */ + { + /* handlers for main ioctl */ + QCSAP_IOCTL_SET_TWO_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "" + } + , + /* handlers for sub-ioctl */ +#ifdef CONFIG_WLAN_DEBUG_CRASH_INJECT + { + QCSAP_IOCTL_SET_FW_CRASH_INJECT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "crash_inject" + } + , +#endif + { + QCASAP_SET_RADAR_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setRadarDbg" + } + , +#ifdef CONFIG_DP_TRACE + /* dump dp trace - descriptor or dp trace records */ + { + QCSAP_IOCTL_DUMP_DP_TRACE_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "dump_dp_trace" + } + , +#endif + { + QCSAP_ENABLE_FW_PROFILE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "enableProfile" + } + , + { + QCSAP_SET_FW_PROFILE_HIST_INTVL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_hist_intvl" + } + , +#ifdef WLAN_SUSPEND_RESUME_TEST + { + QCSAP_SET_WLAN_SUSPEND, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "wlan_suspend" + } + , + { + QCSAP_SET_WLAN_RESUME, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "wlan_resume" + } + , +#endif + { + QCSAP_SET_BA_AGEING_TIMEOUT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_ba_timeout" + } + , + { + QCASAP_SET_11AX_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_11ax_rate" + } + , + { + QCASAP_PARAM_DCM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "enable_dcm" + } + , + { + QCASAP_PARAM_RANGE_EXT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "range_ext" + } + , + { QCSAP_SET_DEFAULT_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "def_ampdu" + } + , + { QCSAP_ENABLE_RTS_BURSTING, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "rts_bursting" + } + , +}; + +static const iw_handler hostapd_private[] = { + /* set priv ioctl */ + [QCSAP_IOCTL_SETPARAM - SIOCIWFIRSTPRIV] = iw_softap_setparam, + /* get priv ioctl */ + [QCSAP_IOCTL_GETPARAM - SIOCIWFIRSTPRIV] = iw_softap_getparam, + [QCSAP_IOCTL_SET_NONE_GET_THREE - SIOCIWFIRSTPRIV] = + iw_softap_get_three, + /* get station genIE */ + [QCSAP_IOCTL_GET_STAWPAIE - SIOCIWFIRSTPRIV] = iw_get_genie, + /* stop bss */ + [QCSAP_IOCTL_STOPBSS - SIOCIWFIRSTPRIV] = iw_softap_stopbss, + /* get driver version */ + [QCSAP_IOCTL_VERSION - SIOCIWFIRSTPRIV] = iw_softap_version, + [QCSAP_IOCTL_GET_CHANNEL - SIOCIWFIRSTPRIV] = + iw_softap_getchannel, + [QCSAP_IOCTL_ASSOC_STA_MACADDR - SIOCIWFIRSTPRIV] = + iw_softap_getassoc_stamacaddr, + [QCSAP_IOCTL_DISASSOC_STA - SIOCIWFIRSTPRIV] = + iw_softap_disassoc_sta, + [QCSAP_PRIV_GET_CHAR_SET_NONE - SIOCIWFIRSTPRIV] = + iw_get_char_setnone, + [QCSAP_IOCTL_PRIV_SET_THREE_INT_GET_NONE - + SIOCIWFIRSTPRIV] = + iw_set_three_ints_getnone, + [QCSAP_IOCTL_PRIV_SET_VAR_INT_GET_NONE - + SIOCIWFIRSTPRIV] = + iw_set_var_ints_getnone, + [QCSAP_IOCTL_MODIFY_ACL - SIOCIWFIRSTPRIV] = + iw_softap_modify_acl, + [QCSAP_IOCTL_GET_CHANNEL_LIST - SIOCIWFIRSTPRIV] = + iw_softap_get_channel_list, + [QCSAP_IOCTL_GET_STA_INFO - SIOCIWFIRSTPRIV] = + iw_softap_get_sta_info, + [QCSAP_IOCTL_GET_BA_AGEING_TIMEOUT - SIOCIWFIRSTPRIV] = + iw_softap_get_ba_timeout, + [QCSAP_IOCTL_PRIV_GET_SOFTAP_LINK_SPEED - + SIOCIWFIRSTPRIV] = + iw_get_softap_linkspeed, + [QCSAP_IOCTL_PRIV_GET_RSSI - SIOCIWFIRSTPRIV] = + iw_get_peer_rssi, + [QCSAP_IOCTL_SET_TX_POWER - SIOCIWFIRSTPRIV] = + iw_softap_set_tx_power, + [QCSAP_IOCTL_SET_MAX_TX_POWER - SIOCIWFIRSTPRIV] = + iw_softap_set_max_tx_power, + [QCSAP_IOCTL_SET_PKTLOG - SIOCIWFIRSTPRIV] = + iw_softap_set_pktlog, + [QCSAP_IOCTL_GET_INI_CFG - SIOCIWFIRSTPRIV] = + iw_softap_get_ini_cfg, + [QCSAP_IOCTL_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_softap_set_two_ints_getnone, +}; + +const struct iw_handler_def hostapd_handler_def = { + .num_standard = 0, + .num_private = QDF_ARRAY_SIZE(hostapd_private), + .num_private_args = QDF_ARRAY_SIZE(hostapd_private_args), + .standard = NULL, + .private = (iw_handler *)hostapd_private, + .private_args = hostapd_private_args, + .get_wireless_stats = NULL, +}; + +/** + * hdd_register_hostapd_wext() - register hostapd wext context + * @dev: net device handle + * + * Registers wext interface context for a given net device + * + * Returns: 0 on success, errno on failure + */ +void hdd_register_hostapd_wext(struct net_device *dev) +{ + hdd_enter_dev(dev); + /* Register as a wireless device */ + dev->wireless_handlers = (struct iw_handler_def *)&hostapd_handler_def; + + hdd_exit(); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd_wext.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd_wext.h new file mode 100644 index 0000000000..d5d48c849d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hostapd_wext.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_HDD_HOSTAPD_WEXT_H +#define WLAN_HDD_HOSTAPD_WEXT_H + +/** + * DOC: wlan_hdd_hostapd_wext.h + * + * WLAN Host Device driver hostapd wext header file + */ + +/* Include files */ + +#include + +/* Preprocessor definitions and constants */ +#ifdef WLAN_WEXT_SUPPORT_ENABLE +void hdd_register_hostapd_wext(struct net_device *dev); +#else +static inline void hdd_register_hostapd_wext(struct net_device *dev) +{ +} +#endif + +#endif /* end #ifndef WLAN_HDD_HOSTAPD_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.c new file mode 100644 index 0000000000..e278ac3328 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_hw_capability.c + * + * The implementation of get hw capability + * + */ + +#include "wlan_hdd_main.h" +#include "wmi_unified_param.h" +#include "wlan_hdd_hw_capability.h" +#include "qca_vendor.h" +#include "wlan_osif_request_manager.h" +#include "osif_sync.h" + +/** + * hdd_get_isolation_cb - Callback function to get isolation information + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * @isolation: pointer of isolation information + * + * This function will fill isolation information to isolation priv adapter + * + * Return: None + */ +static void hdd_get_isolation_cb(struct sir_isolation_resp *isolation, + void *context) +{ + struct osif_request *request; + struct sir_isolation_resp *priv; + + if (!isolation) { + hdd_err("Bad param"); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->isolation_chain0 = isolation->isolation_chain0; + priv->isolation_chain1 = isolation->isolation_chain1; + priv->isolation_chain2 = isolation->isolation_chain2; + priv->isolation_chain3 = isolation->isolation_chain3; + + osif_request_complete(request); + osif_request_put(request); +} + +/** + * hdd_post_isolation - send rsp to user space + * @hdd_ctx: pointer to hdd context + * @isolation: antenna isolation information + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_post_isolation(struct hdd_context *hdd_ctx, + struct sir_isolation_resp *isolation) +{ + struct sk_buff *skb; + uint32_t skb_len = NLMSG_HDRLEN; + + skb_len += (sizeof(u8) + NLA_HDRLEN) + (sizeof(u8) + NLA_HDRLEN) + + (sizeof(u8) + NLA_HDRLEN) + (sizeof(u8) + NLA_HDRLEN); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -ENOMEM; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION, + isolation->isolation_chain0)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION, + isolation->isolation_chain1)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION, + isolation->isolation_chain2)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_ANTENNA_ISOLATION, + isolation->isolation_chain3)) { + hdd_err("put fail"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * __wlan_hdd_cfg80211_get_hw_capability() - get hw capability + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 on success; error number otherwise. + * + */ +static int __wlan_hdd_cfg80211_get_hw_capability(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct osif_request *request; + struct sir_isolation_resp *priv; + mac_handle_t mac_handle; + void *cookie; + QDF_STATUS status; + int ret; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_ANTENNA_ISOLATION, + }; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + + mac_handle = hdd_ctx->mac_handle; + status = sme_get_isolation(mac_handle, + cookie, + hdd_get_isolation_cb); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to retrieve isolation"); + ret = -EFAULT; + } else { + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving isolation"); + ret = -ETIMEDOUT; + } else { + priv = osif_request_priv(request); + hdd_post_isolation(hdd_ctx, priv); + ret = 0; + } + } + osif_request_put(request); + + return ret; +} + +int wlan_hdd_cfg80211_get_hw_capability(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_hw_capability(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.h new file mode 100644 index 0000000000..0e051c23ee --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_hw_capability.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_hw_capability.h + * + * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY + */ + +#ifndef __WLAN_HDD_HW_CAPABILITY_H +#define __WLAN_HDD_HW_CAPABILITY_H + +#ifdef FEATURE_HW_CAPABILITY +#include + +/** + * wlan_hdd_cfg80211_get_hw_capability() - get hardware capability + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_get_hw_capability(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_HW_CAPABILITY_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_HW_CAPABILITY, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_hw_capability, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, +#else /* FEATURE_HW_CAPABILITY */ +#define FEATURE_HW_CAPABILITY_COMMANDS +#endif /* FEATURE_HW_CAPABILITY */ + +#endif /* __WLAN_HDD_HW_CAPABILITY_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c new file mode 100644 index 0000000000..8b25d03373 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.c @@ -0,0 +1,7723 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* Include Files */ + +#include "osif_sync.h" +#include +#include +#include +#include "cfg_ucfg_api.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_regulatory.h" +#include "wlan_osif_request_manager.h" +#include "wlan_hdd_driver_ops.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_hostapd.h" +#include "scheduler_api.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_hdd_p2p.h" +#include +#include "wma.h" +#include "wlan_hdd_napi.h" +#include "wlan_mlme_ucfg_api.h" +#include "target_type.h" +#ifdef FEATURE_WLAN_ESE +#include +#include +#endif +#include "wlan_hdd_object_manager.h" +#include "hif.h" +#include "wlan_scan_ucfg_api.h" +#include "wlan_reg_ucfg_api.h" +#include "qdf_func_tracker.h" +#include "wlan_cm_roam_ucfg_api.h" +#include "wlan_tdls_api.h" + +#if defined(LINUX_QCMBR) +#define SIOCIOCTLTX99 (SIOCDEVPRIVATE+13) +#endif + +#define SIZE_OF_WIFI6E_CHAN_LIST 512 + +/* + * Size of Driver command strings from upper layer + */ +#define SIZE_OF_SETROAMMODE 11 /* size of SETROAMMODE */ +#define SIZE_OF_GETROAMMODE 11 /* size of GETROAMMODE */ +#define SIZE_OF_SETSUSPENDMODE 14 + +/* + * Size of GETCOUNTRYREV output = (sizeof("GETCOUNTRYREV") = 14) + one (space) + + * (sizeof("country_code") = 3) + + * one (NULL terminating character) + */ +#define SIZE_OF_GETCOUNTRYREV_OUTPUT 20 + +#ifdef FEATURE_WLAN_ESE +#define TID_MIN_VALUE 0 +#define TID_MAX_VALUE 15 +#endif /* FEATURE_WLAN_ESE */ + +/* + * Maximum buffer size used for returning the data back to user space + */ +#define WLAN_MAX_BUF_SIZE 1024 +#define WLAN_PRIV_DATA_MAX_LEN 8192 + +/* + * Driver miracast parameters: + * 0-Disabled + * 1-Source, 2-Sink + * 128: miracast connecting time optimization enabled. At present host + * will disable imps to reduce connection time for p2p. + * 129: miracast connecting time optimization disabled + */ +enum miracast_param { + MIRACAST_DISABLED, + MIRACAST_SOURCE, + MIRACAST_SINK, + MIRACAST_CONN_OPT_ENABLED = 128, + MIRACAST_CONN_OPT_DISABLED = 129, +}; + +/* + * When ever we need to print IBSSPEERINFOALL for more than 16 STA + * we will split the printing. + */ +#define NUM_OF_STA_DATA_TO_PRINT 16 + +/* + * The host sends the maximum channel count in RCL(Roam channel list) via a + * supplicant vendor event to notify RCL on disconnection. + */ +#define MAX_RCL_CHANNEL_COUNT 30 + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * struct enable_ext_wow_priv - Private data structure for ext wow + * @ext_wow_should_suspend: Suspend status of ext wow + */ +struct enable_ext_wow_priv { + bool ext_wow_should_suspend; +}; +#endif + +/* + * Android DRIVER command structures + */ +struct android_wifi_reassoc_params { + unsigned char bssid[18]; + int channel; +}; + +#define ANDROID_WIFI_ACTION_FRAME_SIZE 1040 +struct android_wifi_af_params { + unsigned char bssid[18]; + int channel; + int dwell_time; + int len; + unsigned char data[ANDROID_WIFI_ACTION_FRAME_SIZE]; +}; + +/* + * Define HDD driver command handling entry, each contains a command + * string and the handler. + */ +typedef int (*hdd_drv_cmd_handler_t)(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *cmd, + uint8_t cmd_name_len, + struct hdd_priv_data *priv_data); + +/** + * struct hdd_drv_cmd - Structure to store ioctl command handling info + * @cmd: Name of the command + * @handler: Command handler to be invoked + * @args: Set to true if command expects input parameters + */ +struct hdd_drv_cmd { + const char *cmd; + hdd_drv_cmd_handler_t handler; + bool args; +}; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +#define WLAN_WAIT_TIME_READY_TO_EXTWOW 2000 +#define WLAN_HDD_MAX_TCP_PORT 65535 +#endif + +/** + * drv_cmd_validate() - Validates for space in hdd driver command + * @command: pointer to input data (its a NULL terminated string) + * @len: length of command name + * + * This function checks for space after command name and if no space + * is found returns error. + * + * Return: 0 for success non-zero for failure + */ +static int drv_cmd_validate(uint8_t *command, int len) +{ + if (command[len] != ' ') + return -EINVAL; + + return 0; +} + +#ifdef FEATURE_WLAN_ESE +struct tsm_priv { + tAniTrafStrmMetrics tsm_metrics; +}; + +static void hdd_get_tsm_stats_cb(tAniTrafStrmMetrics tsm_metrics, + void *context) +{ + struct osif_request *request; + struct tsm_priv *priv; + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + priv = osif_request_priv(request); + priv->tsm_metrics = tsm_metrics; + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); + +} + +static int hdd_get_tsm_stats(struct hdd_adapter *adapter, + const uint8_t tid, + tAniTrafStrmMetrics *tsm_metrics) +{ + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *hdd_sta_ctx; + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct tsm_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (!adapter) { + hdd_err("adapter is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + status = sme_get_tsm_stats(hdd_ctx->mac_handle, hdd_get_tsm_stats_cb, + hdd_sta_ctx->conn_info.bssid, + cookie, tid); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve tsm statistics"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving tsm statistics"); + goto cleanup; + } + + priv = osif_request_priv(request); + *tsm_metrics = priv->tsm_metrics; + + cleanup: + osif_request_put(request); + + return ret; +} +#endif /*FEATURE_WLAN_ESE */ + +static void hdd_get_band_helper(struct hdd_context *hdd_ctx, int *ui_band) +{ + enum band_info band = -1; + + ucfg_reg_get_band(hdd_ctx->pdev, &band); + switch (band) { + case BAND_ALL: + *ui_band = WLAN_HDD_UI_BAND_AUTO; + break; + + case BAND_2G: + *ui_band = WLAN_HDD_UI_BAND_2_4_GHZ; + break; + + case BAND_5G: + *ui_band = WLAN_HDD_UI_BAND_5_GHZ; + break; + + default: + hdd_warn("Invalid Band %d", band); + *ui_band = -1; + break; + } +} + +/** + * hdd_check_and_fill_freq() - to validate chan and convert into freq + * @in_chan: input as channel number or freq to be checked + * @freq: frequency for input in_chan (output parameter) + * @pdev: pdev object + * + * This function checks input "in_chan" is channel number, if yes then fills + * appropriate frequency into "freq" out param. If the "in_param" is greater + * than WNI_CFG_CURRENT_CHANNEL_STAMAX then checks for valid frequencies. + * + * Return: true if "in_chan" is valid channel/frequency; false otherwise + */ +static bool hdd_check_and_fill_freq(uint32_t in_chan, qdf_freq_t *freq, + struct wlan_objmgr_pdev *pdev) +{ + if (in_chan <= WNI_CFG_CURRENT_CHANNEL_STAMAX) + *freq = wlan_reg_legacy_chan_to_freq(pdev, in_chan); + else if (WLAN_REG_IS_24GHZ_CH_FREQ(in_chan) || + WLAN_REG_IS_5GHZ_CH_FREQ(in_chan) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(in_chan)) + *freq = in_chan; + else + return false; + + return true; +} + +/** + * _hdd_parse_bssid_and_chan() - helper function to parse bssid and channel + * @data: input data + * @bssid: pointer to bssid (output parameter) + * @freq: pointer to freq (output parameter) + * @pdev: pdev object + * + * Return: 0 if parsing is successful; -EINVAL otherwise + */ +static int _hdd_parse_bssid_and_chan(const uint8_t **data, + uint8_t *bssid, qdf_freq_t *freq, + struct wlan_objmgr_pdev *pdev) +{ + const uint8_t *in_ptr; + int v = 0; + int temp_int; + uint8_t temp_buf[32]; + + /* 12 hexa decimal digits, 5 ':' and '\0' */ + uint8_t mac_addr[18]; + + if (!data || !*data) + return -EINVAL; + + in_ptr = *data; + + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + goto error; + /* no space after the command */ + else if (SPACE_ASCII_VALUE != *in_ptr) + goto error; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + goto error; + + v = sscanf(in_ptr, "%17s", mac_addr); + if (!((1 == v) && hdd_is_valid_mac_address(mac_addr))) { + hdd_err("Invalid MAC address or All hex inputs are not read (%d)", + v); + goto error; + } + + bssid[0] = hex_to_bin(mac_addr[0]) << 4 | + hex_to_bin(mac_addr[1]); + bssid[1] = hex_to_bin(mac_addr[3]) << 4 | + hex_to_bin(mac_addr[4]); + bssid[2] = hex_to_bin(mac_addr[6]) << 4 | + hex_to_bin(mac_addr[7]); + bssid[3] = hex_to_bin(mac_addr[9]) << 4 | + hex_to_bin(mac_addr[10]); + bssid[4] = hex_to_bin(mac_addr[12]) << 4 | + hex_to_bin(mac_addr[13]); + bssid[5] = hex_to_bin(mac_addr[15]) << 4 | + hex_to_bin(mac_addr[16]); + + /* point to the next argument */ + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + goto error; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + goto error; + + /* get the next argument ie the channel/freq number */ + v = sscanf(in_ptr, "%31s ", temp_buf); + if (1 != v) + goto error; + + v = kstrtos32(temp_buf, 10, &temp_int); + if (v < 0 || temp_int < 0) + goto error; + else if (!hdd_check_and_fill_freq(temp_int, freq, pdev)) + goto error; + + *data = in_ptr; + return 0; +error: + *data = in_ptr; + return -EINVAL; +} + +/** + * hdd_parse_send_action_frame_v1_data() - HDD Parse send action frame data + * @command: Pointer to input data + * @bssid: Pointer to target AP BSSID + * @freq: Pointer to the Target AP channel frequency + * @dwell_time: Pointer to the time to stay off-channel + * after transmitting action frame + * @buf: Pointer to data + * @buf_len: Pointer to data length + * @pdev: pdev object + * + * This function parses the send action frame data passed in the format + * SENDACTIONFRAME + * + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_send_action_frame_v1_data(const uint8_t *command, + uint8_t *bssid, + qdf_freq_t *freq, uint8_t *dwell_time, + uint8_t **buf, uint8_t *buf_len, + struct wlan_objmgr_pdev *pdev) +{ + const uint8_t *in_ptr = command; + const uint8_t *end_ptr; + int temp_int; + int j = 0; + int i = 0; + int v = 0; + uint8_t temp_buf[32]; + uint8_t temp_u8 = 0; + + if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq, pdev)) + return -EINVAL; + + /* point to the next argument */ + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + return -EINVAL; + + /* getting the next argument ie the dwell time */ + v = sscanf(in_ptr, "%31s ", temp_buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(temp_buf, 10, &temp_int); + if (v < 0 || temp_int < 0) + return -EINVAL; + + *dwell_time = temp_int; + + /* point to the next argument */ + in_ptr = strnchr(in_ptr, strlen(in_ptr), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + return -EINVAL; + /* removing empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + return -EINVAL; + + /* find the length of data */ + end_ptr = in_ptr; + while (('\0' != *end_ptr)) + end_ptr++; + + *buf_len = end_ptr - in_ptr; + if (*buf_len <= 0) + return -EINVAL; + + /* + * Allocate the number of bytes based on the number of input characters + * whether it is even or odd. + * if the number of input characters are even, then we need N/2 byte. + * if the number of input characters are odd, then we need do (N+1)/2 + * to compensate rounding off. + * For example, if N = 18, then (18 + 1)/2 = 9 bytes are enough. + * If N = 19, then we need 10 bytes, hence (19 + 1)/2 = 10 bytes + */ + *buf = qdf_mem_malloc((*buf_len + 1) / 2); + if (!*buf) + return -ENOMEM; + + /* the buffer received from the upper layer is character buffer, + * we need to prepare the buffer taking 2 characters in to a U8 hex + * decimal number for example 7f0000f0...form a buffer to contain 7f + * in 0th location, 00 in 1st and f0 in 3rd location + */ + for (i = 0, j = 0; j < *buf_len; j += 2) { + if (j + 1 == *buf_len) { + temp_u8 = hex_to_bin(in_ptr[j]); + } else { + temp_u8 = + (hex_to_bin(in_ptr[j]) << 4) | + (hex_to_bin(in_ptr[j + 1])); + } + (*buf)[i++] = temp_u8; + } + *buf_len = i; + return 0; +} + +/** + * hdd_parse_reassoc_command_v1_data() - HDD Parse reassoc command data + * @command: Pointer to input data (its a NULL terminated string) + * @bssid: Pointer to target Ap bssid + * @freq: Pointer to the Target AP frequency + * @pdev: pdev object + * + * This function parses the reasoc command data passed in the format + * REASSOC. + * + * If reassoc MAC from user space is broadcast MAC as: + * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0", + * user space invoked roaming candidate selection will base on firmware score + * algorithm, current connection will be kept if current AP has highest + * score. It is requirement from customer which can avoid ping-pong roaming. + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_command_v1_data(const uint8_t *command, + uint8_t *bssid, qdf_freq_t *freq, + struct wlan_objmgr_pdev *pdev) +{ + const uint8_t *in_ptr = command; + + if (_hdd_parse_bssid_and_chan(&in_ptr, bssid, freq, pdev)) + return -EINVAL; + + return 0; +} + +/** + * hdd_parse_reassoc_v1() - parse version 1 of the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 REASSOC command with the format + * + * REASSOC xx:xx:xx:xx:xx:xx CH/FREQ + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID and CH/FREQ is the ASCII representation of the channel/frequency. + * For example + * + * REASSOC 00:0a:0b:11:22:33 48 + * REASSOC 00:0a:0b:11:22:33 2412 + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v1(struct hdd_adapter *adapter, const char *command) +{ + qdf_freq_t freq = 0; + tSirMacAddr bssid; + int ret; + struct qdf_mac_addr target_bssid; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(adapter->deflink->vdev); + ret = hdd_parse_reassoc_command_v1_data(command, bssid, &freq, pdev); + if (ret) { + hdd_err("Failed to parse reassoc command data"); + return ret; + } + + qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr)); + status = ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, + adapter->deflink->vdev_id, + &target_bssid, freq, + CM_ROAMING_USER); + return qdf_status_to_os_return(status); +} + +/** + * hdd_parse_reassoc_v2() - parse version 2 of the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * @total_len: Total length of the command received + * + * This function parses the v2 REASSOC command with the format + * + * REASSOC + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc_v2(struct hdd_adapter *adapter, + const char *command, + int total_len) +{ + struct android_wifi_reassoc_params params; + tSirMacAddr bssid; + qdf_freq_t freq = 0; + int ret; + struct qdf_mac_addr target_bssid; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(adapter->deflink->vdev); + if (total_len < sizeof(params) + 8) { + hdd_err("Invalid command length"); + return -EINVAL; + } + + /* The params are located after "REASSOC " */ + memcpy(¶ms, command + 8, sizeof(params)); + + if (!mac_pton(params.bssid, (u8 *) &bssid)) { + hdd_err("MAC address parsing failed"); + ret = -EINVAL; + } else { + /* + * In Reassoc command, user can send channel number or frequency + * along with BSSID. If params.channel param of REASSOC command + * is less than WNI_CFG_CURRENT_CHANNEL_STAMAX, then host + * consider this as channel number else frequency. + */ + if (!hdd_check_and_fill_freq(params.channel, &freq, pdev)) + return -EINVAL; + + qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr)); + status = ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, + adapter->deflink->vdev_id, + &target_bssid, freq, + CM_ROAMING_USER); + ret = qdf_status_to_os_return(status); + } + + return ret; +} + +/** + * hdd_parse_reassoc() - parse the REASSOC command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * @total_len: Total length of the command received + * + * There are two different versions of the REASSOC command. Version 1 + * of the command contains a parameter list that is ASCII characters + * whereas version 2 contains a combination of ASCII and binary + * payload. Determine if a version 1 or a version 2 command is being + * parsed by examining the parameters, and then dispatch the parser + * that is appropriate for the command. + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_reassoc(struct hdd_adapter *adapter, const char *command, + int total_len) +{ + int ret; + + /* both versions start with "REASSOC " + * v1 has a bssid and channel # as an ASCII string + * REASSOC xx:xx:xx:xx:xx:xx CH/FREQ + * v2 has a C struct + * REASSOC + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * REASSOC xx:xx:xx:xx:xx:xx* + * 1111111111222222 + * 01234567890123456789012345 + */ + + if (total_len < 26) { + hdd_err("Invalid command, total_len = %d", total_len); + return -EINVAL; + } + + if (command[25]) + ret = hdd_parse_reassoc_v1(adapter, command); + else + ret = hdd_parse_reassoc_v2(adapter, command, total_len); + + return ret; +} + +/** + * hdd_sendactionframe() - send a userspace-supplied action frame + * @adapter: Adapter upon which the command was received + * @bssid: BSSID target of the action frame + * @freq: Frequency upon which to send the frame + * @dwell_time: Amount of time to dwell when the frame is sent + * @payload_len:Length of the payload + * @payload: Payload of the frame + * + * This function sends a userspace-supplied action frame + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_sendactionframe(struct hdd_adapter *adapter, const uint8_t *bssid, + const qdf_freq_t freq, const uint8_t dwell_time, + const int payload_len, const uint8_t *payload) +{ + struct ieee80211_channel chan; + int frame_len, ret = 0; + uint8_t *frame; + struct ieee80211_hdr_3addr *hdr; + u64 cookie; + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx; + tpSirMacVendorSpecificFrameHdr vendor = + (tpSirMacVendorSpecificFrameHdr) payload; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + struct cfg80211_mgmt_tx_params params; +#endif + + if (payload_len < sizeof(tSirMacVendorSpecificFrameHdr)) { + hdd_warn("Invalid payload length: %d", payload_len); + return -EINVAL; + } + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* if not associated, no need to send action frame */ + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_warn("Not associated"); + ret = -EINVAL; + goto exit; + } + + /* + * if the target bssid is different from currently associated AP, + * then no need to send action frame + */ + if (memcmp(bssid, sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE)) { + hdd_warn("STA is not associated to this AP"); + ret = -EINVAL; + goto exit; + } + + chan.center_freq = freq; + /* Check if it is specific action frame */ + if (vendor->category == + ACTION_CATEGORY_VENDOR_SPECIFIC) { + static const uint8_t oui[] = { 0x00, 0x00, 0xf0 }; + + if (!qdf_mem_cmp(vendor->Oui, oui, 3)) { + /* + * if the freq number is different from operating + * freq then no need to send action frame + */ + if (freq) { + if (freq != sta_ctx->conn_info.chan_freq) { + hdd_warn("freq(%u) is different from operating freq(%u)", + freq, + sta_ctx->conn_info.chan_freq); + ret = -EINVAL; + goto exit; + } + /* + * If channel number is specified and same + * as home channel, ensure that action frame + * is sent immediately by cancelling + * roaming scans. Otherwise large dwell times + * may cause long delays in sending action + * frames. + */ + ucfg_cm_abort_roam_scan( + hdd_ctx->pdev, + adapter->deflink->vdev_id); + } else { + /* + * 0 is accepted as current home frequency, + * delayed transmission of action frame is ok. + */ + chan.center_freq = sta_ctx->conn_info.chan_freq; + } + } + } + if (chan.center_freq == 0) { + hdd_nofl_err("Invalid freq : %d", freq); + ret = -EINVAL; + goto exit; + } + + frame_len = payload_len + 24; + frame = qdf_mem_malloc(frame_len); + if (!frame) { + ret = -ENOMEM; + goto exit; + } + + hdr = (struct ieee80211_hdr_3addr *)frame; + hdr->frame_control = + cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION); + qdf_mem_copy(hdr->addr1, bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr->addr2, adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr->addr3, bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(hdr + 1, payload, payload_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + params.chan = &chan; + params.offchan = 0; + params.wait = dwell_time; + params.buf = frame; + params.len = frame_len; + params.no_cck = 1; + params.dont_wait_for_ack = 1; + ret = wlan_hdd_mgmt_tx(NULL, &adapter->wdev, ¶ms, &cookie); +#else + ret = wlan_hdd_mgmt_tx(NULL, + &(adapter->wdev), + &chan, 0, + + dwell_time, frame, frame_len, 1, 1, &cookie); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0) */ + + qdf_mem_free(frame); +exit: + return ret; +} + +/** + * hdd_parse_sendactionframe_v1() - parse version 1 of the + * SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that was received + * + * This function parses the v1 SENDACTIONFRAME command with the format + * + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DW xxxxxx + * + * Where "xx:xx:xx:xx:xx:xx" is the Hex-ASCII representation of the + * BSSID, CH is the ASCII representation of the channel, DW is the + * ASCII representation of the dwell time, and xxxxxx is the Hex-ASCII + * payload. For example + * + * SENDACTIONFRAME 00:0a:0b:11:22:33 48 40 aabbccddee + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v1(struct hdd_adapter *adapter, const char *command) +{ + qdf_freq_t freq = 0; + uint8_t dwell_time = 0; + uint8_t payload_len = 0; + uint8_t *payload = NULL; + tSirMacAddr bssid; + int ret; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(adapter->deflink->vdev); + ret = hdd_parse_send_action_frame_v1_data(command, bssid, &freq, + &dwell_time, &payload, + &payload_len, pdev); + if (ret) { + hdd_nofl_err("Failed to parse send action frame data"); + } else { + ret = hdd_sendactionframe(adapter, bssid, freq, + dwell_time, payload_len, payload); + qdf_mem_free(payload); + } + + return ret; +} + +/** + * hdd_parse_sendactionframe_v2() - parse version 2 of the + * SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: Command that was received, ASCII command + * followed by binary data + * @total_len: Length of @command + * + * This function parses the v2 SENDACTIONFRAME command with the format + * + * SENDACTIONFRAME + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe_v2(struct hdd_adapter *adapter, + const char *command, int total_len) +{ + struct android_wifi_af_params *params; + tSirMacAddr bssid; + int ret; + int len_wo_payload = 0; + qdf_freq_t freq = 0; + struct wlan_objmgr_pdev *pdev; + + pdev = wlan_vdev_get_pdev(adapter->deflink->vdev); + + /* The params are located after "SENDACTIONFRAME " */ + total_len -= 16; + len_wo_payload = sizeof(*params) - ANDROID_WIFI_ACTION_FRAME_SIZE; + if (total_len <= len_wo_payload) { + hdd_err("Invalid command len"); + return -EINVAL; + } + + params = (struct android_wifi_af_params *)(command + 16); + + if (params->len <= 0 || params->len > ANDROID_WIFI_ACTION_FRAME_SIZE || + (params->len > (total_len - len_wo_payload))) { + hdd_err("Invalid payload length: %d", params->len); + return -EINVAL; + } + + if (!mac_pton(params->bssid, (u8 *)&bssid)) { + hdd_err("MAC address parsing failed"); + return -EINVAL; + } + + if (params->channel < 0 || + params->channel > WNI_CFG_CURRENT_CHANNEL_STAMAX) { + hdd_err("Invalid channel: %d", params->channel); + return -EINVAL; + } + + if (params->dwell_time < 0) { + hdd_err("Invalid dwell_time: %d", params->dwell_time); + return -EINVAL; + } + + if (!hdd_check_and_fill_freq(params->channel, &freq, pdev)) { + hdd_err("Invalid channel: %d", params->channel); + return -EINVAL; + } + + ret = hdd_sendactionframe(adapter, bssid, freq, params->dwell_time, + params->len, params->data); + + return ret; +} + +/** + * hdd_parse_sendactionframe() - parse the SENDACTIONFRAME command + * @adapter: Adapter upon which the command was received + * @command: Command that was received + * @total_len: Length of @command + * + * There are two different versions of the SENDACTIONFRAME command. + * Version 1 of the command contains a parameter list that is ASCII + * characters whereas version 2 contains a combination of ASCII and + * binary payload. Determine if a version 1 or a version 2 command is + * being parsed by examining the parameters, and then dispatch the + * parser that is appropriate for the version of the command. + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_sendactionframe(struct hdd_adapter *adapter, const char *command, + int total_len) +{ + int ret; + + /* + * both versions start with "SENDACTIONFRAME " + * v1 has a bssid and other parameters as an ASCII string + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx CH DWELL LEN FRAME + * v2 has a C struct + * SENDACTIONFRAME + * + * The first field in the v2 struct is also the bssid in ASCII. + * But in the case of a v2 message the BSSID is NUL-terminated. + * Hence we can peek at that offset to see if this is V1 or V2 + * SENDACTIONFRAME xx:xx:xx:xx:xx:xx* + * 111111111122222222223333 + * 0123456789012345678901234567890123 + * For both the commands, a valid command must have atleast + * first 34 length of data. + */ + if (total_len < 34) { + hdd_err("Invalid command (total_len=%d)", total_len); + return -EINVAL; + } + + if (command[33]) + ret = hdd_parse_sendactionframe_v1(adapter, command); + else + ret = hdd_parse_sendactionframe_v2(adapter, command, total_len); + + return ret; +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_parse_channellist() - HDD Parse channel list + * @hdd_ctx: hdd context + * @command: Pointer to input channel list + * @channel_freq_list: Pointer to local output array to record + * channel list + * @num_channels: Pointer to number of roam scan channels + * + * This function parses the channel list passed in the format + * SETROAMSCANCHANNELSChannel 1 + * Channel 2Channel N + * if the Number of channels (N) does not match with the actual number + * of channels passed then take the minimum of N and count of + * (Ch1, Ch2, ...Ch M). For example, if SETROAMSCANCHANNELS 3 36 40 44 48, + * only 36, 40 and 44 shall be taken. If SETROAMSCANCHANNELS 5 36 40 44 48, + * ignore 5 and take 36, 40, 44 and 48. This function does not take care of + * removing duplicate channels from the list + * + * Return: 0 for success non-zero for failure + */ +static int +hdd_parse_channellist(struct hdd_context *hdd_ctx, + const uint8_t *command, + uint32_t *channel_freq_list, + uint8_t *num_channels) +{ + const uint8_t *in_ptr = command; + int temp_int; + int j = 0; + int v = 0; + char buf[32]; + + in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + return -EINVAL; + + /* get the first argument ie the number of channels */ + v = sscanf(in_ptr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &temp_int); + if ((v < 0) || + (temp_int <= 0) || (temp_int > CFG_VALID_CHANNEL_LIST_LEN)) + return -EINVAL; + + *num_channels = temp_int; + + hdd_debug("Number of channels are: %d", *num_channels); + + for (j = 0; j < (*num_channels); j++) { + /* + * in_ptr pointing to the beginning of first space after number + * of channels + */ + in_ptr = strpbrk(in_ptr, " "); + /* no channel list after the number of channels argument */ + if (!in_ptr) { + if ((j != 0) && (*num_channels == j)) + return 0; + else + goto cnt_mismatch; + } + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* + * no channel list after the number of channels + * argument and spaces + */ + if ('\0' == *in_ptr) { + if ((j != 0) && (*num_channels == j)) + return 0; + else + goto cnt_mismatch; + } + + v = sscanf(in_ptr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtos32(buf, 10, &temp_int); + if ((v < 0) || + (temp_int <= 0) || + (temp_int > WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + return -EINVAL; + } + channel_freq_list[j] = + wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, temp_int); + + hdd_debug("Channel %d added to preferred channel list", + channel_freq_list[j]); + } + + return 0; + +cnt_mismatch: + hdd_debug("Mismatch in ch cnt: %d and num of ch: %d", *num_channels, j); + *num_channels = 0; + return -EINVAL; + +} + +/** + * hdd_parse_plm_cmd() - HDD Parse Plm command + * @command: Pointer to input data + * @req: Pointer to output struct plm_req + * + * This function parses the plm command passed in the format + * CCXPLMREQ + * + * + * + * + * + * Return: 0 for success non-zero for failure + */ +static QDF_STATUS hdd_parse_plm_cmd(uint8_t *command, + struct plm_req_params *req) +{ + uint8_t *in_ptr = NULL; + int count, content = 0, ret = 0; + char buf[32]; + + /* move to argument list */ + in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE); + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* START/STOP PLM req */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + req->enable = content; + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* Dialog token of radio meas req containing meas reqIE */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + req->diag_token = content; + hdd_debug("diag token %d", req->diag_token); + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* measurement token of meas req IE */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + req->meas_token = content; + hdd_debug("meas token %d", req->meas_token); + + hdd_debug("PLM req %s", req->enable ? "START" : "STOP"); + if (req->enable) { + + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* total number of bursts after which STA stops sending */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content < 0) + return QDF_STATUS_E_FAILURE; + + req->num_bursts = content; + hdd_debug("num bursts %d", req->num_bursts); + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* burst interval in seconds */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + req->burst_int = content; + hdd_debug("burst int %d", req->burst_int); + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* Meas dur in TU's,STA goes off-ch and transmit PLM bursts */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + req->meas_duration = content; + hdd_debug("meas duration %d", req->meas_duration); + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* burst length of PLM bursts */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + req->burst_len = content; + hdd_debug("burst len %d", req->burst_len); + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* desired tx power for transmission of PLM bursts */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content <= 0) + return QDF_STATUS_E_FAILURE; + + req->desired_tx_pwr = content; + hdd_debug("desired tx pwr %d", req->desired_tx_pwr); + + for (count = 0; count < QDF_MAC_ADDR_SIZE; count++) { + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) + && ('\0' != *in_ptr)) + in_ptr++; + + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 16, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + req->mac_addr.bytes[count] = content; + } + + hdd_debug("MAC addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(req->mac_addr.bytes)); + + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* number of channels */ + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0) + return QDF_STATUS_E_FAILURE; + + if (content < 0) + return QDF_STATUS_E_FAILURE; + + content = QDF_MIN(content, CFG_VALID_CHANNEL_LIST_LEN); + req->plm_num_ch = content; + hdd_debug("num ch: %d", req->plm_num_ch); + + /* Channel numbers */ + for (count = 0; count < req->plm_num_ch; count++) { + in_ptr = strpbrk(in_ptr, " "); + + if (!in_ptr) + return QDF_STATUS_E_FAILURE; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) + && ('\0' != *in_ptr)) + in_ptr++; + + ret = sscanf(in_ptr, "%31s ", buf); + if (1 != ret) + return QDF_STATUS_E_FAILURE; + + ret = kstrtos32(buf, 10, &content); + if (ret < 0 || content <= 0 || + content > WNI_CFG_CURRENT_CHANNEL_STAMAX) + return QDF_STATUS_E_FAILURE; + + req->plm_ch_freq_list[count] = + cds_chan_to_freq(content); + hdd_debug(" ch-freq- %d", req->plm_ch_freq_list[count]); + } + } + /* If PLM START */ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * wlan_hdd_ready_to_extwow() - Callback function for enable ext wow + * @cookie: callback context + * @is_success: suspend status of ext wow + * + * Return: none + */ +static void wlan_hdd_ready_to_extwow(void *cookie, bool is_success) +{ + struct osif_request *request = NULL; + struct enable_ext_wow_priv *priv = NULL; + + request = osif_request_get(cookie); + if (!request) { + hdd_err("obsolete request"); + return; + } + priv = osif_request_priv(request); + priv->ext_wow_should_suspend = is_success; + + osif_request_complete(request); + osif_request_put(request); +} + +static int hdd_enable_ext_wow(struct hdd_adapter *adapter, + tpSirExtWoWParams arg_params) +{ + tSirExtWoWParams params; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int rc; + struct enable_ext_wow_priv *priv = NULL; + struct osif_request *request = NULL; + void *cookie = NULL; + struct osif_request_params hdd_params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_READY_TO_EXTWOW, + }; + + qdf_mem_copy(¶ms, arg_params, sizeof(params)); + + request = osif_request_alloc(&hdd_params); + if (!request) { + hdd_err("Request Allocation Failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + status = sme_configure_ext_wow(hdd_ctx->mac_handle, ¶ms, + &wlan_hdd_ready_to_extwow, + cookie); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_configure_ext_wow returned failure %d", + status); + rc = -EPERM; + goto exit; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + hdd_err("Failed to get ready to extwow"); + rc = -EPERM; + goto exit; + } + + priv = osif_request_priv(request); + if (!priv->ext_wow_should_suspend) { + hdd_err("Received ready to ExtWoW failure"); + rc = -EPERM; + goto exit; + } + + if (ucfg_pmo_extwow_is_goto_suspend_enabled(hdd_ctx->psoc)) { + hdd_info("Received ready to ExtWoW. Going to suspend"); + + rc = wlan_hdd_cfg80211_suspend_wlan(hdd_ctx->wiphy, NULL); + if (rc < 0) { + hdd_err("wlan_hdd_cfg80211_suspend_wlan failed, error = %d", + rc); + goto exit; + } + rc = wlan_hdd_bus_suspend(); + if (rc) { + hdd_err("wlan_hdd_bus_suspend failed, status = %d", + rc); + wlan_hdd_cfg80211_resume_wlan(hdd_ctx->wiphy); + goto exit; + } + } + +exit: + osif_request_put(request); + return rc; +} + +static int hdd_enable_ext_wow_parser(struct hdd_adapter *adapter, int vdev_id, + int value) +{ + tSirExtWoWParams params; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int rc; + uint8_t pin1, pin2; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (value < EXT_WOW_TYPE_APP_TYPE1 || + value > EXT_WOW_TYPE_APP_TYPE1_2) { + hdd_err("Invalid type: %d", value); + return -EINVAL; + } + + if (value == EXT_WOW_TYPE_APP_TYPE1 && + hdd_ctx->is_extwow_app_type1_param_set) + params.type = value; + else if (value == EXT_WOW_TYPE_APP_TYPE2 && + hdd_ctx->is_extwow_app_type2_param_set) + params.type = value; + else if (value == EXT_WOW_TYPE_APP_TYPE1_2 && + hdd_ctx->is_extwow_app_type1_param_set && + hdd_ctx->is_extwow_app_type2_param_set) + params.type = value; + else { + hdd_err("Set app params before enable it value %d", + value); + return -EINVAL; + } + + params.vdev_id = vdev_id; + pin1 = ucfg_pmo_extwow_app1_wakeup_pin_num(hdd_ctx->psoc); + pin2 = ucfg_pmo_extwow_app2_wakeup_pin_num(hdd_ctx->psoc); + params.wakeup_pin_num = pin1 | (pin2 << 8); + + return hdd_enable_ext_wow(adapter, ¶ms); +} + +static int hdd_set_app_type1_params(mac_handle_t mac_handle, + tpSirAppType1Params arg_params) +{ + tSirAppType1Params params; + QDF_STATUS status; + + qdf_mem_copy(¶ms, arg_params, sizeof(params)); + + status = sme_configure_app_type1_params(mac_handle, ¶ms); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_configure_app_type1_params returned failure %d", + status); + return -EPERM; + } + + return 0; +} + +static int hdd_set_app_type1_parser(struct hdd_adapter *adapter, + char *arg, int len) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + char id[20], password[20]; + tSirAppType1Params params; + int rc; + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (2 != sscanf(arg, "%8s %16s", id, password)) { + hdd_err("Invalid Number of arguments"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(tSirAppType1Params)); + params.vdev_id = adapter->deflink->vdev_id; + qdf_copy_macaddr(¶ms.wakee_mac_addr, &adapter->mac_addr); + + params.id_length = strlen(id); + qdf_mem_copy(params.identification_id, id, params.id_length); + params.pass_length = strlen(password); + qdf_mem_copy(params.password, password, params.pass_length); + + hdd_debug("%d "QDF_MAC_ADDR_FMT" %.8s %u %.16s %u", + params.vdev_id, + QDF_MAC_ADDR_REF(params.wakee_mac_addr.bytes), + params.identification_id, params.id_length, + params.password, params.pass_length); + + return hdd_set_app_type1_params(hdd_ctx->mac_handle, ¶ms); +} + +static int hdd_set_app_type2_params(mac_handle_t mac_handle, + tpSirAppType2Params arg_params) +{ + tSirAppType2Params params; + QDF_STATUS status; + + qdf_mem_copy(¶ms, arg_params, sizeof(params)); + + status = sme_configure_app_type2_params(mac_handle, ¶ms); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_configure_app_type2_params returned failure %d", + status); + return -EPERM; + } + + return 0; +} + +static int hdd_set_app_type2_parser(struct hdd_adapter *adapter, + char *arg, int len) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + char mac_addr[20], rc4_key[20]; + unsigned int gateway_mac[QDF_MAC_ADDR_SIZE]; + tSirAppType2Params params; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + memset(¶ms, 0, sizeof(tSirAppType2Params)); + + ret = sscanf(arg, "%17s %16s %x %x %x %u %u %hu %hu %u %u %u %u %u %u", + mac_addr, rc4_key, (unsigned int *)¶ms.ip_id, + (unsigned int *)¶ms.ip_device_ip, + (unsigned int *)¶ms.ip_server_ip, + (unsigned int *)¶ms.tcp_seq, + (unsigned int *)¶ms.tcp_ack_seq, + (uint16_t *)¶ms.tcp_src_port, + (uint16_t *)¶ms.tcp_dst_port, + (unsigned int *)¶ms.keepalive_init, + (unsigned int *)¶ms.keepalive_min, + (unsigned int *)¶ms.keepalive_max, + (unsigned int *)¶ms.keepalive_inc, + (unsigned int *)¶ms.tcp_tx_timeout_val, + (unsigned int *)¶ms.tcp_rx_timeout_val); + + if (ret != 15 && ret != 7) { + hdd_err("Invalid Number of arguments"); + return -EINVAL; + } + + if (6 != sscanf(mac_addr, "%02x:%02x:%02x:%02x:%02x:%02x", + &gateway_mac[0], &gateway_mac[1], &gateway_mac[2], + &gateway_mac[3], &gateway_mac[4], &gateway_mac[5])) { + hdd_err("Invalid MacAddress Input %s", mac_addr); + return -EINVAL; + } + + if (params.tcp_src_port > WLAN_HDD_MAX_TCP_PORT || + params.tcp_dst_port > WLAN_HDD_MAX_TCP_PORT) { + hdd_err("Invalid TCP Port Number"); + return -EINVAL; + } + + qdf_mem_copy(¶ms.gateway_mac.bytes, (uint8_t *) &gateway_mac, + QDF_MAC_ADDR_SIZE); + + params.rc4_key_len = strlen(rc4_key); + qdf_mem_copy(params.rc4_key, rc4_key, params.rc4_key_len); + + params.vdev_id = adapter->deflink->vdev_id; + + if (!params.tcp_src_port) + params.tcp_src_port = + ucfg_pmo_extwow_app2_tcp_src_port(hdd_ctx->psoc); + + if (!params.tcp_dst_port) + params.tcp_dst_port = + ucfg_pmo_extwow_app2_tcp_dst_port(hdd_ctx->psoc); + + if (!params.keepalive_init) + params.keepalive_init = + ucfg_pmo_extwow_app2_init_ping_interval(hdd_ctx->psoc); + + if (!params.keepalive_min) + params.keepalive_min = + ucfg_pmo_extwow_app2_min_ping_interval(hdd_ctx->psoc); + + if (!params.keepalive_max) + params.keepalive_max = + ucfg_pmo_extwow_app2_max_ping_interval(hdd_ctx->psoc); + + if (!params.keepalive_inc) + params.keepalive_inc = + ucfg_pmo_extwow_app2_inc_ping_interval(hdd_ctx->psoc); + + if (!params.tcp_tx_timeout_val) + params.tcp_tx_timeout_val = + ucfg_pmo_extwow_app2_tcp_tx_timeout(hdd_ctx->psoc); + + if (!params.tcp_rx_timeout_val) + params.tcp_rx_timeout_val = + ucfg_pmo_extwow_app2_tcp_rx_timeout(hdd_ctx->psoc); + + hdd_debug(QDF_MAC_ADDR_FMT" %.16s %u %u %u %u %u %u %u %u %u %u %u %u %u", + QDF_MAC_ADDR_REF(gateway_mac), rc4_key, params.ip_id, + params.ip_device_ip, params.ip_server_ip, params.tcp_seq, + params.tcp_ack_seq, params.tcp_src_port, params.tcp_dst_port, + params.keepalive_init, params.keepalive_min, + params.keepalive_max, params.keepalive_inc, + params.tcp_tx_timeout_val, params.tcp_rx_timeout_val); + + return hdd_set_app_type2_params(hdd_ctx->mac_handle, ¶ms); +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +/** + * hdd_parse_setmaxtxpower_command() - HDD Parse MAXTXPOWER command + * @command: Pointer to MAXTXPOWER command + * @tx_power: Pointer to tx power + * + * This function parses the MAXTXPOWER command passed in the format + * MAXTXPOWERX(Tx power in dbm) + * + * For example input commands: + * 1) MAXTXPOWER -8 -> This is translated into set max TX power to -8 dbm + * 2) MAXTXPOWER -23 -> This is translated into set max TX power to -23 dbm + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_setmaxtxpower_command(uint8_t *command, int *tx_power) +{ + uint8_t *in_ptr = command; + int temp_int; + int v = 0; + *tx_power = 0; + + in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + return 0; + + v = kstrtos32(in_ptr, 10, &temp_int); + + /* Range checking for passed parameter */ + if ((temp_int < HDD_MIN_TX_POWER) || (temp_int > HDD_MAX_TX_POWER)) + return -EINVAL; + + *tx_power = temp_int; + + hdd_debug("SETMAXTXPOWER: %d", *tx_power); + + return 0; +} /* End of hdd_parse_setmaxtxpower_command */ + +#ifdef CONFIG_BAND_6GHZ +static int hdd_get_dwell_time_6g(struct wlan_objmgr_psoc *psoc, + uint8_t *command, char *extra, uint8_t n, + uint8_t *len) +{ + uint32_t val = 0; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (strncmp(command, "GETDWELLTIME 6G MAX", 19) == 0) { + status = ucfg_scan_cfg_get_active_6g_dwelltime(psoc, &val); + hdd_debug("active 6g dwelltime:%d", val); + if (QDF_IS_STATUS_SUCCESS(status)) + *len = scnprintf(extra, n, "GETDWELLTIME 6G MAX %u\n", + val); + } else if (strncmp(command, "GETDWELLTIME PASSIVE 6G MAX", 27) == 0) { + status = ucfg_scan_cfg_get_passive_6g_dwelltime(psoc, &val); + hdd_debug("passive 6g dwelltime:%d", val); + if (QDF_IS_STATUS_SUCCESS(status)) + *len = scnprintf(extra, n, + "GETDWELLTIME PASSIVE 6G MAX %u\n", + val); + } + + return qdf_status_to_os_return(status); +} + +static int hdd_set_dwell_time_6g(struct wlan_objmgr_psoc *psoc, + uint8_t *command) +{ + uint8_t *value = command; + int temp = 0; + uint32_t val = 0; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (strncmp(command, "SETDWELLTIME 6G MAX", 19) == 0) { + if (drv_cmd_validate(command, 19)) + return -EINVAL; + + value = value + 20; + temp = kstrtou32(value, 10, &val); + if (temp || !cfg_in_range(CFG_ACTIVE_MAX_6G_CHANNEL_TIME, + val)) { + hdd_err_rl("argument passed for SETDWELLTIME 6G MAX is incorrect"); + return -EFAULT; + } + status = ucfg_scan_cfg_set_active_6g_dwelltime(psoc, val); + } else if (strncmp(command, "SETDWELLTIME PASSIVE 6G MAX", 27) == 0) { + if (drv_cmd_validate(command, 27)) + return -EINVAL; + + value = value + 28; + temp = kstrtou32(value, 10, &val); + if (temp || !cfg_in_range(CFG_PASSIVE_MAX_6G_CHANNEL_TIME, + val)) { + hdd_err_rl("argument passed for SETDWELLTIME PASSIVE 6G MAX is incorrect"); + return -EFAULT; + } + status = ucfg_scan_cfg_set_passive_6g_dwelltime(psoc, val); + } + + return qdf_status_to_os_return(status); +} +#else +static int hdd_get_dwell_time_6g(struct wlan_objmgr_psoc *psoc, + uint8_t *command, char *extra, uint8_t n, + uint8_t *len) +{ + return -EINVAL; +} + +static int hdd_set_dwell_time_6g(struct wlan_objmgr_psoc *psoc, + uint8_t *command) +{ + return -EINVAL; +} +#endif + +static int hdd_get_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command, + char *extra, uint8_t n, uint8_t *len) +{ + uint32_t val = 0; + + if (!psoc || !command || !extra || !len) { + hdd_err("argument passed for GETDWELLTIME is incorrect"); + return -EINVAL; + } + + if (strncmp(command, "GETDWELLTIME ACTIVE MAX", 23) == 0) { + ucfg_scan_cfg_get_active_dwelltime(psoc, &val); + hdd_debug("active max dwelltime:%d", val); + *len = scnprintf(extra, n, "GETDWELLTIME ACTIVE MAX %u\n", val); + return 0; + } + if (strncmp(command, "GETDWELLTIME PASSIVE MAX", 24) == 0) { + ucfg_scan_cfg_get_passive_dwelltime(psoc, &val); + hdd_debug("passive dwelltime:%d", val); + *len = scnprintf(extra, n, "GETDWELLTIME PASSIVE MAX %u\n", + val); + return 0; + } + if (strncmp(command, "GETDWELLTIME 2G MAX", 19) == 0) { + ucfg_scan_cfg_get_active_2g_dwelltime(psoc, &val); + hdd_debug("active 2g dwelltime:%d", val); + *len = scnprintf(extra, n, "GETDWELLTIME 2G MAX %u\n", + val); + return 0; + } + if (strncmp(command, "GETDWELLTIME", 12) == 0) { + ucfg_scan_cfg_get_active_dwelltime(psoc, &val); + hdd_debug("active dwelltime:%d", val); + *len = scnprintf(extra, n, "GETDWELLTIME %u\n", val); + return 0; + } + + return hdd_get_dwell_time_6g(psoc, command, extra, n, len); +} + +static int hdd_set_dwell_time(struct wlan_objmgr_psoc *psoc, uint8_t *command) +{ + uint8_t *value = command; + int retval = 0, temp = 0; + uint32_t val = 0; + + if (!psoc) { + hdd_err("psoc is null"); + return -EINVAL; + } + + if (strncmp(command, "SETDWELLTIME ACTIVE MAX", 23) == 0) { + if (drv_cmd_validate(command, 23)) + return -EINVAL; + + value = value + 24; + temp = kstrtou32(value, 10, &val); + if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) { + hdd_err_rl("argument passed for SETDWELLTIME ACTIVE MAX is incorrect"); + return -EFAULT; + } + ucfg_scan_cfg_set_active_dwelltime(psoc, val); + } else if (strncmp(command, "SETDWELLTIME PASSIVE MAX", 24) == 0) { + if (drv_cmd_validate(command, 24)) + return -EINVAL; + + value = value + 25; + temp = kstrtou32(value, 10, &val); + if (temp || !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME, val)) { + hdd_err_rl("argument passed for SETDWELLTIME PASSIVE MAX is incorrect"); + return -EFAULT; + } + ucfg_scan_cfg_set_passive_dwelltime(psoc, val); + } else if (strncmp(command, "SETDWELLTIME 2G MAX", 19) == 0) { + if (drv_cmd_validate(command, 19)) + return -EINVAL; + + value = value + 20; + temp = kstrtou32(value, 10, &val); + if (temp || !cfg_in_range(CFG_ACTIVE_MAX_2G_CHANNEL_TIME, + val)) { + hdd_err_rl("argument passed for SETDWELLTIME 2G MAX is incorrect"); + return -EFAULT; + } + ucfg_scan_cfg_set_active_2g_dwelltime(psoc, val); + } else if (strncmp(command, "SETDWELLTIME", 12) == 0) { + if (drv_cmd_validate(command, 12)) + return -EINVAL; + + value = value + 13; + temp = kstrtou32(value, 10, &val); + if (temp || !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME, val)) { + hdd_err_rl("argument passed for SETDWELLTIME is incorrect"); + return -EFAULT; + } + ucfg_scan_cfg_set_active_dwelltime(psoc, val); + } else { + retval = hdd_set_dwell_time_6g(psoc, command); + } + + return retval; +} + +struct link_status_priv { + uint8_t link_status; +}; + +/** + * hdd_conc_set_dwell_time() - Set Concurrent dwell time parameters + * @adapter: Adapter upon which the command was received + * @command: ASCII text command that is received + * + * Driver commands: + * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MAX + * wpa_cli DRIVER CONCSETDWELLTIME ACTIVE MIN + * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MAX + * wpa_cli DRIVER CONCSETDWELLTIME PASSIVE MIN + * + * Return: 0 for success non-zero for failure + */ +static int hdd_conc_set_dwell_time(struct hdd_adapter *adapter, + uint8_t *command) +{ + u8 *value = command; + int val = 0, temp = 0; + int retval = 0; + + if (strncmp(command, "CONCSETDWELLTIME ACTIVE MAX", 27) == 0) { + if (drv_cmd_validate(command, 27)) { + hdd_err("Invalid driver command"); + return -EINVAL; + } + + value = value + 28; + temp = kstrtou32(value, 10, &val); + if (temp || + !cfg_in_range(CFG_ACTIVE_MAX_CHANNEL_TIME_CONC, val)) { + hdd_err("CONC ACTIVE MAX value %d incorrect", val); + return -EFAULT; + } + ucfg_scan_cfg_set_conc_active_dwelltime( + (WLAN_HDD_GET_CTX(adapter))->psoc, val); + } else if (strncmp(command, "CONCSETDWELLTIME PASSIVE MAX", 28) == 0) { + if (drv_cmd_validate(command, 28)) { + hdd_err("Invalid driver command"); + return -EINVAL; + } + + value = value + 29; + temp = kstrtou32(value, 10, &val); + if (temp || + !cfg_in_range(CFG_PASSIVE_MAX_CHANNEL_TIME_CONC, val)) { + hdd_err("CONC PASSIVE MAX val %d incorrect", val); + return -EFAULT; + } + ucfg_scan_cfg_set_conc_passive_dwelltime( + (WLAN_HDD_GET_CTX(adapter))->psoc, val); + } else { + retval = -EINVAL; + } + + return retval; +} + +static int hdd_enable_unit_test_commands(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx) +{ + enum pld_bus_type bus_type = pld_get_bus_type(hdd_ctx->parent_dev); + u32 arg[3]; + QDF_STATUS status; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE || + hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + return -EPERM; + + if (adapter->deflink->vdev_id >= WLAN_MAX_VDEVS) { + hdd_err_rl("Invalid vdev id"); + return -EINVAL; + } + + if (bus_type == PLD_BUS_TYPE_PCIE) { + arg[0] = 360; + arg[1] = 1; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_TX, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + arg[0] = 361; + arg[1] = 1; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_TX, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + arg[0] = 84; + arg[1] = 1; + arg[2] = 1; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_TX, + 3, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + if (hdd_ctx->target_type == TARGET_TYPE_QCA6390) { + arg[0] = 37; + arg[1] = 3000; + + status = sme_send_unit_test_cmd( + adapter->deflink->vdev_id, + WLAN_MODULE_RX, 2, arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + } + + if (hdd_ctx->target_type == TARGET_TYPE_QCA6490) { + arg[0] = 44; + arg[1] = 3000; + + status = sme_send_unit_test_cmd( + adapter->deflink->vdev_id, + WLAN_MODULE_RX, 2, arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + } + } else if (bus_type == PLD_BUS_TYPE_SNOC) { + arg[0] = 7; + arg[1] = 1; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + 0x44, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + } else { + return -EINVAL; + } + return 0; +} + +static int hdd_disable_unit_test_commands(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx) +{ + enum pld_bus_type bus_type = pld_get_bus_type(hdd_ctx->parent_dev); + u32 arg[2]; + QDF_STATUS status; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE || + hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + return -EPERM; + + if (adapter->deflink->vdev_id >= WLAN_MAX_VDEVS) { + hdd_err_rl("Invalid vdev id"); + return -EINVAL; + } + + if (bus_type == PLD_BUS_TYPE_PCIE) { + arg[0] = 360; + arg[1] = 0; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_TX, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + arg[0] = 361; + arg[1] = 0; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_TX, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + arg[0] = 44; + arg[1] = 0; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_RX, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + arg[0] = 84; + arg[1] = 0; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + WLAN_MODULE_RX, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + + } else if (bus_type == PLD_BUS_TYPE_SNOC) { + arg[0] = 7; + arg[1] = 0; + + status = sme_send_unit_test_cmd(adapter->deflink->vdev_id, + 0x44, + 2, + arg); + if (status != QDF_STATUS_SUCCESS) + return qdf_status_to_os_return(status); + } else { + return -EINVAL; + } + return 0; +} + +static void hdd_get_link_status_cb(uint8_t status, void *context) +{ + struct osif_request *request; + struct link_status_priv *priv; + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->link_status = status; + osif_request_complete(request); + osif_request_put(request); +} + +/** + * wlan_hdd_get_link_status() - get link status + * @adapter: pointer to the adapter + * + * This function sends a request to query the link status and waits + * on a timer to invoke the callback. if the callback is invoked then + * latest link status shall be returned or otherwise cached value + * will be returned. + * + * Return: On success, link status shall be returned. + * On error or not associated, link status 0 will be returned. + */ +static int wlan_hdd_get_link_status(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct link_status_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_LINK_STATUS, + }; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_warn("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return 0; + } + + if ((QDF_STA_MODE != adapter->device_mode) && + (QDF_P2P_CLIENT_MODE != adapter->device_mode)) { + hdd_warn("Unsupported in mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return 0; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + /* If not associated, then expected link status return + * value is 0 + */ + hdd_warn("Not associated!"); + return 0; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return 0; + } + cookie = osif_request_cookie(request); + + status = sme_get_link_status(adapter->hdd_ctx->mac_handle, + hdd_get_link_status_cb, + cookie, adapter->deflink->vdev_id); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve link status"); + /* return a cached value */ + } else { + /* request is sent -- wait for the response */ + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving link status"); + /* return a cached value */ + } else { + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + adapter->link_status = priv->link_status; + } + } + + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + osif_request_put(request); + + /* either callback updated adapter stats or it has cached data */ + return adapter->link_status; +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_parse_ese_beacon_req() - Parse ese beacon request + * @pdev: pdev object + * @command: Pointer to data + * @req: Output pointer to store parsed ie information + * + * This function parses the ese beacon request passed in the format + * CCXBEACONREQ + * Channel 1Scan Mode Meas DurationChannel N + * Scan Mode NMeas Duration N + * + * If the Number of bcn req fields (N) does not match with the + * actual number of fields passed then take N. + * and are treated + * as one pair. For example, CCXBEACONREQ 2 1 1 1 30 2 44 0 40. + * This function does not take care of removing duplicate channels from the + * list + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_ese_beacon_req(struct wlan_objmgr_pdev *pdev, + uint8_t *command, + tCsrEseBeaconReq *req) +{ + uint8_t *in_ptr = command; + uint8_t input = 0; + uint32_t temp_int = 0; + int j = 0, i = 0, v = 0; + char buf[32]; + + in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE); + if (!in_ptr) /* no argument after the command */ + return -EINVAL; + else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + return -EINVAL; + + /* Getting the first argument ie Number of IE fields */ + v = sscanf(in_ptr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtou8(buf, 10, &input); + if (v < 0) + return -EINVAL; + + input = QDF_MIN(input, SIR_ESE_MAX_MEAS_IE_REQS); + req->numBcnReqIe = input; + + hdd_debug("Number of Bcn Req Ie fields: %d", req->numBcnReqIe); + + for (j = 0; j < (req->numBcnReqIe); j++) { + for (i = 0; i < 4; i++) { + /* + * in_ptr pointing to the beginning of 1st space + * after number of ie fields + */ + in_ptr = strpbrk(in_ptr, " "); + /* no ie data after the number of ie fields argument */ + if (!in_ptr) + return -EINVAL; + + /* remove empty space */ + while ((SPACE_ASCII_VALUE == *in_ptr) + && ('\0' != *in_ptr)) + in_ptr++; + + /* + * no ie data after the number of ie fields + * argument and spaces + */ + if ('\0' == *in_ptr) + return -EINVAL; + + v = sscanf(in_ptr, "%31s ", buf); + if (1 != v) + return -EINVAL; + + v = kstrtou32(buf, 10, &temp_int); + if (v < 0) + return -EINVAL; + + switch (i) { + case 0: /* Measurement token */ + if (!temp_int) { + hdd_err("Invalid Measurement Token: %u", + temp_int); + return -EINVAL; + } + req->bcnReq[j].measurementToken = + temp_int; + break; + + case 1: /* Channel number */ + if (!temp_int || + (temp_int > + WNI_CFG_CURRENT_CHANNEL_STAMAX)) { + hdd_err("Invalid Channel Number: %u", + temp_int); + return -EINVAL; + } + req->bcnReq[j].ch_freq = + wlan_reg_legacy_chan_to_freq(pdev, temp_int); + break; + + case 2: /* Scan mode */ + if ((temp_int < eSIR_PASSIVE_SCAN) + || (temp_int > eSIR_BEACON_TABLE)) { + hdd_err("Invalid Scan Mode: %u Expected{0|1|2}", + temp_int); + return -EINVAL; + } + req->bcnReq[j].scanMode = temp_int; + break; + + case 3: /* Measurement duration */ + if ((!temp_int + && (req->bcnReq[j].scanMode != + eSIR_BEACON_TABLE)) || + (req->bcnReq[j].scanMode == + eSIR_BEACON_TABLE)) { + hdd_err("Invalid Measurement Duration: %u", + temp_int); + return -EINVAL; + } + req->bcnReq[j].measurementDuration = + temp_int; + break; + } + } + } + + for (j = 0; j < req->numBcnReqIe; j++) { + hdd_debug("Index: %d Measurement Token: %u ch_freq: %u Scan Mode: %u Measurement Duration: %u", + j, + req->bcnReq[j].measurementToken, + req->bcnReq[j].ch_freq, + req->bcnReq[j].scanMode, + req->bcnReq[j].measurementDuration); + } + + return 0; +} + +/** + * hdd_parse_get_cckm_ie() - HDD Parse and fetch the CCKM IE + * @command: Pointer to input data + * @cckm_ie: Pointer to output cckm Ie + * @cckm_ie_len: Pointer to output cckm ie length + * + * This function parses the SETCCKM IE command + * SETCCKMIE + * + * Return: 0 for success non-zero for failure + */ +static int hdd_parse_get_cckm_ie(uint8_t *command, uint8_t **cckm_ie, + uint8_t *cckm_ie_len) +{ + uint8_t *in_ptr = command; + uint8_t *end_ptr; + int j = 0; + int i = 0; + uint8_t temp_u8 = 0; + + in_ptr = strnchr(command, strlen(command), SPACE_ASCII_VALUE); + /* no argument after the command */ + if (!in_ptr) + return -EINVAL; + else if (SPACE_ASCII_VALUE != *in_ptr) /* no space after the command */ + return -EINVAL; + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + /* no argument followed by spaces */ + if ('\0' == *in_ptr) + return -EINVAL; + + /* find the length of data */ + end_ptr = in_ptr; + while (('\0' != *end_ptr)) { + end_ptr++; + ++(*cckm_ie_len); + } + if (*cckm_ie_len <= 0) + return -EINVAL; + /* + * Allocate the number of bytes based on the number of input characters + * whether it is even or odd. + * if the number of input characters are even, then we need N / 2 byte. + * if the number of input characters are odd, then we need do + * (N + 1) / 2 to compensate rounding off. + * For example, if N = 18, then (18 + 1) / 2 = 9 bytes are enough. + * If N = 19, then we need 10 bytes, hence (19 + 1) / 2 = 10 bytes + */ + *cckm_ie = qdf_mem_malloc((*cckm_ie_len + 1) / 2); + if (!*cckm_ie) + return -ENOMEM; + + /* + * the buffer received from the upper layer is character buffer, + * we need to prepare the buffer taking 2 characters in to a U8 hex + * decimal number for example 7f0000f0...form a buffer to contain + * 7f in 0th location, 00 in 1st and f0 in 3rd location + */ + for (i = 0, j = 0; j < *cckm_ie_len; j += 2) { + temp_u8 = (hex_to_bin(in_ptr[j]) << 4) | + (hex_to_bin(in_ptr[j + 1])); + (*cckm_ie)[i++] = temp_u8; + } + *cckm_ie_len = i; + return 0; +} +#endif /* FEATURE_WLAN_ESE */ + +int wlan_hdd_set_mc_rate(struct wlan_hdd_link_info *link_info, int target_rate) +{ + tSirRateUpdateInd rate_update = {0}; + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool bval = false; + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + if ((QDF_SAP_MODE != adapter->device_mode) && + (QDF_STA_MODE != adapter->device_mode)) { + hdd_err("Received SETMCRATE cmd in invalid mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + hdd_err("SETMCRATE cmd is allowed only in STA or SOFTAP mode"); + return -EINVAL; + } + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("unable to get vht_enable2x2"); + return -EINVAL; + } + rate_update.nss = (bval == 0) ? 0 : 1; + + rate_update.dev_mode = adapter->device_mode; + rate_update.mcastDataRate24GHz = target_rate; + rate_update.mcastDataRate24GHzTxFlag = 1; + rate_update.mcastDataRate5GHz = target_rate; + rate_update.bcastDataRate = -1; + qdf_copy_macaddr(&rate_update.bssid, &adapter->mac_addr); + hdd_debug("MC Target rate %d, mac = "QDF_MAC_ADDR_FMT", dev_mode %s(%d)", + rate_update.mcastDataRate24GHz, + QDF_MAC_ADDR_REF(rate_update.bssid.bytes), + qdf_opmode_str(adapter->device_mode), adapter->device_mode); + status = sme_send_rate_update_ind(hdd_ctx->mac_handle, &rate_update); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("SETMCRATE failed"); + return -EFAULT; + } + return 0; +} + +static int drv_cmd_p2p_dev_addr(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + struct qdf_mac_addr *addr = &hdd_ctx->p2p_device_address; + size_t user_size = qdf_min(sizeof(addr->bytes), + (size_t)priv_data->total_len); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL, + link_info->vdev_id, + (unsigned int)(*(addr->bytes + 2) << 24 | + *(addr->bytes + 3) << 16 | + *(addr->bytes + 4) << 8 | + *(addr->bytes + 5))); + + + if (copy_to_user(priv_data->buf, addr->bytes, user_size)) { + hdd_err("failed to copy data to user buffer"); + return -EFAULT; + } + + return 0; +} + +/** + * drv_cmd_p2p_set_noa() - Handler for P2P_SET_NOA driver command + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: HDD global context + * @command: Entire driver command received from userspace + * @command_len: Length of @command + * @priv_data: Pointer to ioctl private data structure + * + * This is a trivial command handler function which simply forwards the + * command to the actual command processor within the P2P module. + * + * Return: 0 on success, non-zero on failure + */ +static int drv_cmd_p2p_set_noa(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_set_p2p_noa(link_info->adapter->dev, command); +} + +/** + * drv_cmd_p2p_set_ps() - Handler for P2P_SET_PS driver command + * @link_info: Link info pointer in adapter + * @hdd_ctx: HDD global context + * @command: Entire driver command received from userspace + * @command_len: Length of @command + * @priv_data: Pointer to ioctl private data structure + * + * This is a trivial command handler function which simply forwards the + * command to the actual command processor within the P2P module. + * + * Return: 0 on success, non-zero on failure + */ +static int drv_cmd_p2p_set_ps(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_set_p2p_opps(link_info->adapter->dev, command); +} + +static int drv_cmd_set_band(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int err; + uint8_t band; + uint32_t band_bitmap; + + /* + * Parse the band value passed from userspace. The first 8 bytes + * should be "SETBAND " and the 9th byte should be a UI band value + */ + err = kstrtou8(command + command_len + 1, 10, &band); + if (err) { + hdd_err("error %d parsing userspace band parameter", err); + return err; + } + + band_bitmap = hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(band); + + return hdd_reg_set_band(link_info->adapter->dev, band_bitmap); +} + +static int drv_cmd_set_wmmps(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_wmmps_helper(link_info->adapter, command); +} + +#ifdef CONFIG_BAND_6GHZ +/** + * drv_cmd_get_wifi6e_channels() - Handler for GET_WIFI6E_CHANNELS driver + * command + * @link_info: Link info pointer in adapter + * @hdd_ctx: pointer to hdd context + * @command: command name + * @command_len: command buffer length + * @priv_data: output pointer to hold current country code + * + * Return: On success 0, negative value on error. + */ +static int drv_cmd_get_wifi6e_channels(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + uint8_t power_type; + char extra[SIZE_OF_WIFI6E_CHAN_LIST] = {0}; + int i, ret, copied_length = 0; + enum channel_state state; + struct regulatory_channel *chan_list; + size_t max_buf_len = QDF_MIN(priv_data->total_len, + SIZE_OF_WIFI6E_CHAN_LIST); + QDF_STATUS status; + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + ret = kstrtou8(command + command_len + 1, 10, &power_type); + if (ret) { + hdd_err("error %d parsing userspace 6 GHz power type parameter", + ret); + return -EINVAL; + } + + switch (power_type) { + case 0: + power_type = REG_CLI_DEF_LPI; + break; + case 1: + power_type = REG_CLI_DEF_VLP; + break; + case 2: + power_type = REG_CLI_DEF_SP; + break; + default: + hdd_err("The power type : %u, is incorrect", power_type); + return -EINVAL; + } + + chan_list = qdf_mem_malloc(NUM_CHANNELS * sizeof(*chan_list)); + if (!chan_list) + return -ENOMEM; + + status = wlan_reg_get_pwrmode_chan_list(hdd_ctx->pdev, chan_list, + power_type); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get wifi6e channel list for given power type %u", + power_type); + ret = qdf_status_to_os_return(status); + goto free; + } + + for (i = 0; i < NUM_6GHZ_CHANNELS && copied_length < max_buf_len - 1; + i++) { + state = chan_list[i + MIN_6GHZ_CHANNEL].state; + if (state == CHANNEL_STATE_INVALID || + state == CHANNEL_STATE_DISABLE) + continue; + copied_length += scnprintf(extra + copied_length, + max_buf_len - copied_length, "%u ", + chan_list[i + MIN_6GHZ_CHANNEL].chan_num); + } + + if (copied_length == 0) { + hdd_err("No Channel List found for given power type %u", + power_type); + ret = -EINVAL; + goto free; + } + + if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto free; + } + + hdd_debug("Power type = %u, Data = %s", power_type, extra); +free: + qdf_mem_free(chan_list); + return ret; +} +#endif + +static inline int __drv_cmd_country(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + char *country_code; + + country_code = strnchr(command, strlen(command), ' '); + /* no argument after the command */ + if (!country_code) + return -EINVAL; + + /* no space after the command */ + if (*country_code != SPACE_ASCII_VALUE) + return -EINVAL; + + country_code++; + + /* removing empty spaces */ + while ((*country_code == SPACE_ASCII_VALUE) && + (*country_code != '\0')) + country_code++; + + /* no or less than 2 arguments followed by spaces */ + if (*country_code == '\0' || *(country_code + 1) == '\0') + return -EINVAL; + + return hdd_reg_set_country(hdd_ctx, country_code); +} + +static inline int drv_cmd_country(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (errno) + return errno; + errno = __drv_cmd_country(link_info, hdd_ctx, command, command_len, + priv_data); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * drv_cmd_get_country() - Helper function to get current county code + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: pointer to hdd context + * @command: command name + * @command_len: command buffer length + * @priv_data: output pointer to hold current country code + * + * Return: On success 0, negative value on error. + */ +static int drv_cmd_get_country(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + uint8_t buf[SIZE_OF_GETCOUNTRYREV_OUTPUT] = {0}; + uint8_t cc[REG_ALPHA2_LEN + 1]; + int ret = 0, len; + + qdf_mem_copy(cc, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN); + cc[REG_ALPHA2_LEN] = '\0'; + + len = scnprintf(buf, sizeof(buf), "%s %s", + "GETCOUNTRYREV", cc); + hdd_debug("buf = %s", buf); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, buf, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_trigger(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + int8_t rssi = 0; + uint8_t lookup_threshold = cfg_default( + CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* Move pointer to ahead of SETROAMTRIGGER */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtos8(value, 10, &rssi); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD), + cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD, + rssi)) { + hdd_err("Neighbor lookup threshold value %d is out of range (Min: %d Max: %d)", + lookup_threshold, + cfg_min(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD), + cfg_max(CFG_LFR_NEIGHBOR_LOOKUP_RSSI_THRESHOLD)); + ret = -EINVAL; + goto exit; + } + + lookup_threshold = abs(rssi); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL, + link_info->vdev_id, lookup_threshold); + + hdd_debug("Set Roam trigger: Neighbor lookup threshold = %d", + lookup_threshold); + + status = sme_set_neighbor_lookup_rssi_threshold( + hdd_ctx->mac_handle, + link_info->vdev_id, + lookup_threshold); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to set roam trigger, try again"); + ret = -EPERM; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_roam_trigger(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t lookup_threshold; + int rssi; + char extra[32]; + uint8_t len = 0; + QDF_STATUS status; + + status = ucfg_cm_get_neighbor_lookup_rssi_threshold( + hdd_ctx->psoc, + link_info->vdev_id, + &lookup_threshold); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL, + link_info->vdev_id, lookup_threshold); + + hdd_debug("vdev_id: %u, lookup_threshold: %u", + link_info->vdev_id, lookup_threshold); + + rssi = (-1) * lookup_threshold; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_scan_period(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t roam_scan_period = 0; + uint16_t empty_scan_refresh_period; + bool flag = false, val = false; + + ucfg_mlme_get_connection_roaming_ini_present(hdd_ctx->psoc, &val); + if (val) { + flag = true; + empty_scan_refresh_period = + cfg_default(CFG_ROAM_SCAN_FIRST_TIMER) * 1000; + } else { + empty_scan_refresh_period = + cfg_default(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD); + } + + /* input refresh period is in terms of seconds */ + + /* Move pointer to ahead of SETROAMSCANPERIOD */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roam_scan_period); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + if (flag) + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + cfg_min(CFG_ROAM_SCAN_FIRST_TIMER), + cfg_max(CFG_ROAM_SCAN_FIRST_TIMER)); + else + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + (cfg_min(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000), + (cfg_max(CFG_LFR_EMPTY_SCAN_REFRESH_PERIOD) / 1000)); + ret = -EINVAL; + goto exit; + } + + if (!ucfg_mlme_validate_scan_period(hdd_ctx->psoc, + roam_scan_period * 1000)) { + ret = -EINVAL; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL, + link_info->vdev_id, roam_scan_period); + + empty_scan_refresh_period = roam_scan_period * 1000; + + hdd_debug("Received Command to Set roam scan period (Empty Scan refresh period) = %d", + roam_scan_period); + + sme_update_empty_scan_refresh_period(hdd_ctx->mac_handle, + link_info->vdev_id, + empty_scan_refresh_period); + +exit: + return ret; +} + +static int drv_cmd_get_roam_scan_period(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t empty_scan_refresh_period; + char extra[32]; + uint8_t len; + QDF_STATUS status; + + status = ucfg_cm_get_empty_scan_refresh_period( + hdd_ctx->psoc, + link_info->vdev_id, + &empty_scan_refresh_period); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_debug("vdev_id: %u, empty_scan_refresh_period: %u", + link_info->vdev_id, empty_scan_refresh_period); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL, + link_info->vdev_id, + empty_scan_refresh_period); + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANPERIOD", + (empty_scan_refresh_period / 1000)); + /* Returned value is in units of seconds */ + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int +drv_cmd_set_roam_scan_refresh_period(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + uint8_t roam_scan_refresh_period = 0; + uint16_t neighbor_scan_refresh_period = + cfg_default(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD); + + /* input refresh period is in terms of seconds */ + /* Move pointer to ahead of SETROAMSCANREFRESHPERIOD */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roam_scan_refresh_period); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed Input value may be out of range[%d - %d]", + (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD) + / 1000), + (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD) + / 1000)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD, + roam_scan_refresh_period)) { + hdd_err("Neighbor scan results refresh period value %d is out of range (Min: %d Max: %d)", + roam_scan_refresh_period, + (cfg_min(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD) + / 1000), + (cfg_max(CFG_LFR_NEIGHBOR_SCAN_RESULTS_REFRESH_PERIOD) + / 1000)); + ret = -EINVAL; + goto exit; + } + neighbor_scan_refresh_period = roam_scan_refresh_period * 1000; + + hdd_debug("Received Command to Set roam scan refresh period (Scan refresh period) = %d", + neighbor_scan_refresh_period); + + sme_set_neighbor_scan_refresh_period(hdd_ctx->mac_handle, + link_info->vdev_id, + neighbor_scan_refresh_period); + +exit: + return ret; +} + +static int +drv_cmd_get_roam_scan_refresh_period(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t value = 0; + char extra[32]; + uint8_t len; + + ucfg_cm_get_neighbor_scan_refresh_period(hdd_ctx->psoc, &value); + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANREFRESHPERIOD", + (value / 1000)); + /* Returned value is in units of seconds */ + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + mac_handle_t mac_handle; + int ret; + uint8_t *value = command; + uint8_t roam_mode = cfg_default(CFG_LFR_FEATURE_ENABLED); + + /* Move pointer to ahead of SETROAMMODE */ + value = value + SIZE_OF_SETROAMMODE + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roam_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_FEATURE_ENABLED), + cfg_max(CFG_LFR_FEATURE_ENABLED)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set Roam Mode = %d", + roam_mode); + + if (sme_roaming_in_progress(hdd_ctx->mac_handle, + link_info->vdev_id)) { + hdd_err_rl("Roaming in progress for vdev %d", + link_info->vdev_id); + return -EAGAIN; + } + + /* + * Note that + * SETROAMMODE 0 is to enable LFR while + * SETROAMMODE 1 is to disable LFR, but + * notify_is_fast_roam_ini_feature_enabled 0/1 is to + * enable/disable. So, we have to invert the value + * to call sme_update_is_fast_roam_ini_feature_enabled. + */ + if (roam_mode) { + /* Roam enable */ + roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED); + } else { + /* Roam disable */ + roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED); + } + + mac_handle = hdd_ctx->mac_handle; + if (roam_mode) { + ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc, + (bool)roam_mode); + sme_update_is_fast_roam_ini_feature_enabled( + mac_handle, link_info->vdev_id, roam_mode); + } else { + sme_update_is_fast_roam_ini_feature_enabled( + mac_handle, link_info->vdev_id, roam_mode); + ucfg_mlme_set_roam_scan_offload_enabled(hdd_ctx->psoc, + roam_mode); + } + +exit: + return ret; +} + +static int drv_cmd_set_suspend_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + struct hdd_adapter *adapter = link_info->adapter; + int errno; + uint8_t *value = command; + QDF_STATUS status; + uint8_t idle_monitor; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_debug("Non-STA interface"); + return 0; + } + + /* Move pointer to ahead of SETSUSPENDMODE */ + value = value + SIZE_OF_SETSUSPENDMODE + 1; + + /* Convert the value from ascii to integer */ + errno = kstrtou8(value, 10, &idle_monitor); + if (errno < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("Range validation failed"); + return -EINVAL; + } + + hdd_debug("idle_monitor:%d", idle_monitor); + status = ucfg_pmo_tgt_psoc_send_idle_roam_suspend_mode(hdd_ctx->psoc, + idle_monitor); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Send suspend mode to fw failed"); + return -EINVAL; + } + return 0; +} + +static int drv_cmd_get_roam_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool roam_mode = ucfg_cm_get_is_lfr_feature_enabled(hdd_ctx->psoc); + char extra[32]; + uint8_t len; + + /* + * roamMode value shall be inverted because the sementics is different. + */ + if (roam_mode) + roam_mode = cfg_min(CFG_LFR_FEATURE_ENABLED); + else + roam_mode = cfg_max(CFG_LFR_FEATURE_ENABLED); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, roam_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_delta(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + uint8_t roam_rssi_diff = cfg_default(CFG_LFR_ROAM_RSSI_DIFF); + + /* Move pointer to ahead of SETROAMDELTA */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &roam_rssi_diff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ROAM_RSSI_DIFF), + cfg_max(CFG_LFR_ROAM_RSSI_DIFF)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_ROAM_RSSI_DIFF, roam_rssi_diff)) { + hdd_err("Roam rssi diff value %d is out of range (Min: %d Max: %d)", + roam_rssi_diff, + cfg_min(CFG_LFR_ROAM_RSSI_DIFF), + cfg_max(CFG_LFR_ROAM_RSSI_DIFF)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set roam rssi diff = %d", + roam_rssi_diff); + + sme_update_roam_rssi_diff(hdd_ctx->mac_handle, + link_info->vdev_id, + roam_rssi_diff); + +exit: + return ret; +} + +static int drv_cmd_get_roam_delta(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t rssi_diff; + char extra[32]; + uint8_t len; + QDF_STATUS status; + + status = ucfg_cm_get_roam_rssi_diff(hdd_ctx->psoc, + link_info->vdev_id, + &rssi_diff); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_debug("vdev_id: %u, rssi_diff: %u", + link_info->vdev_id, rssi_diff); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMDELTA_IOCTL, + link_info->vdev_id, rssi_diff); + len = scnprintf(extra, sizeof(extra), "%s %d", + command, rssi_diff); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_band(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0, band = -1; + char extra[32]; + uint8_t len = 0; + + hdd_get_band_helper(hdd_ctx, &band); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETBAND_IOCTL, + link_info->vdev_id, band); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, band); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static bool is_roam_ch_from_fw_supported(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->roam_ch_from_fw_supported; +} + +struct roam_ch_priv { + struct roam_scan_ch_resp roam_ch; +}; + +/** + * hdd_dump_roam_scan_ch_list() - Function to dump roam scan chan list content + * @chan_list: pointer to channel list received from FW via an event + * WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID + * @num_channels: Number of channels + * + * Return: none + */ +static void +hdd_dump_roam_scan_ch_list(uint32_t *chan_list, uint16_t num_channels) +{ + uint8_t i, j; + uint8_t ch_cache_str[128] = {0}; + + /* print channel list after sorting in ascending order */ + for (i = 0, j = 0; i < num_channels; i++) { + if (j < sizeof(ch_cache_str)) + j += snprintf(ch_cache_str + j, + sizeof(ch_cache_str) - j, " %d", + chan_list[i]); + else + break; + } + + hdd_debug("No of freq:%d, freq list : %s", num_channels, ch_cache_str); +} + +/** + * hdd_sort_roam_scan_ch_list() - Function to sort roam scan channel list in + * descending order before sending it to supplicant + * @chan_list: pointer to channel list received from FW via an event + * WMI_ROAM_SCAN_CHANNEL_LIST_EVENTID + * @num_channels: Number of channels + * + * Return: none + */ +static void +hdd_sort_roam_scan_ch_list(uint32_t *chan_list, uint16_t num_channels) +{ + uint8_t i, j; + uint32_t swap = 0; + + for (i = 0; i < (num_channels - 1) && + i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + for (j = 0; j < (num_channels - i - 1); j++) { + if (chan_list[j] < chan_list[j + 1]) { + swap = chan_list[j]; + chan_list[j] = chan_list[j + 1]; + chan_list[j + 1] = swap; + } + } + } +} + +void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle, + struct roam_scan_ch_resp *roam_ch, + void *context) +{ + struct osif_request *request; + struct roam_ch_priv *priv; + uint8_t *event = NULL, i = 0; + uint32_t *freq = NULL, len; + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + + hdd_debug("roam scan ch list event received : vdev_id:%d command resp: %d", + roam_ch->vdev_id, roam_ch->command_resp); + /** + * If command response is set in the response message, then it is + * getroamscanchannels command response else this event is asynchronous + * event raised by firmware. + */ + if (!roam_ch->command_resp) { + /* + * Maximum allowed channel count is 30 in supplicant vendor + * event of RCL list. So if number of channels present in + * channel list received from FW is more than 30 channels then + * restrict it to 30 channels only. + */ + if (roam_ch->num_channels > MAX_RCL_CHANNEL_COUNT) + roam_ch->num_channels = MAX_RCL_CHANNEL_COUNT; + + len = roam_ch->num_channels * sizeof(roam_ch->chan_list[0]); + if (!len) { + hdd_err("Invalid len"); + return; + } + event = (uint8_t *)qdf_mem_malloc(len); + if (!event) + return; + + freq = (uint32_t *)event; + hdd_sort_roam_scan_ch_list(roam_ch->chan_list, + roam_ch->num_channels); + hdd_dump_roam_scan_ch_list(roam_ch->chan_list, + roam_ch->num_channels); + for (i = 0; i < roam_ch->num_channels && + i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) { + freq[i] = roam_ch->chan_list[i]; + } + + hdd_send_roam_scan_ch_list_event(hdd_ctx, roam_ch->vdev_id, + len, event); + qdf_mem_free(event); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + priv = osif_request_priv(request); + + hdd_sort_roam_scan_ch_list(roam_ch->chan_list, roam_ch->num_channels); + hdd_dump_roam_scan_ch_list(roam_ch->chan_list, roam_ch->num_channels); + + priv->roam_ch.num_channels = roam_ch->num_channels; + for (i = 0; i < priv->roam_ch.num_channels && + i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) + priv->roam_ch.chan_list[i] = roam_ch->chan_list[i]; + + osif_request_complete(request); + osif_request_put(request); +} + +static int +hdd_get_roam_chan_from_fw(struct hdd_adapter *adapter, uint32_t *chan_list, + uint8_t *num_channels) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct hdd_context *hdd_ctx; + int ret, i; + void *cookie; + struct osif_request *request; + struct roam_ch_priv *priv; + struct roam_scan_ch_resp *p_roam_ch; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv) + + sizeof(priv->roam_ch.chan_list[0]) * + WNI_CFG_VALID_CHANNEL_LIST_LEN, + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + priv = osif_request_priv(request); + p_roam_ch = &priv->roam_ch; + /** channel list starts after response structure*/ + priv->roam_ch.chan_list = (uint32_t *)(p_roam_ch + 1); + cookie = osif_request_cookie(request); + status = sme_get_roam_scan_ch(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to retrieve roam channels"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving raom channels"); + goto cleanup; + } + + priv = osif_request_priv(request); + *num_channels = priv->roam_ch.num_channels; + for (i = 0; i < *num_channels; i++) + chan_list[i] = priv->roam_ch.chan_list[i]; + +cleanup: + osif_request_put(request); + + return ret; +} + +int +hdd_get_roam_scan_freq(struct hdd_adapter *adapter, mac_handle_t mac_handle, + uint32_t *chan_list, uint8_t *num_channels) +{ + int ret = 0; + + if (!adapter || !mac_handle || !chan_list || !num_channels) { + hdd_err("failed to get roam scan channel, invalid input"); + return -EFAULT; + } + + if (is_roam_ch_from_fw_supported(adapter->hdd_ctx)) { + ret = hdd_get_roam_chan_from_fw(adapter, chan_list, + num_channels); + if (ret) { + hdd_err("failed to get roam scan channel list from FW"); + return -EFAULT; + } + + return ret; + } + + if (sme_get_roam_scan_channel_list(mac_handle, chan_list, num_channels, + adapter->deflink->vdev_id) != + QDF_STATUS_SUCCESS) { + hdd_err("failed to get roam scan channel list"); + return -EFAULT; + } + + return ret; +} +#endif + +enum host_target_comm_log { + HTC_CREDIT_HISTORY_LOG = 0, + COMMAND_LOG, + COMMAND_TX_CMP_LOG, + MGMT_COMMAND_LOG, + MGMT_COMMAND_TX_CMP_LOG, + EVENT_LOG, + RX_EVENT_LOG, + MGMT_EVENT_LOG +}; + +static int printk_adapter(void *priv, const char *fmt, ...) +{ + int ret; + va_list args; + + va_start(args, fmt); + ret = vprintk(fmt, args); + ret += printk("\n"); + va_end(args); + + return ret; +} + +void hdd_ioctl_log_buffer(int log_id, uint32_t count, qdf_abstract_print + *custom_print, + void *print_ctx) +{ + qdf_abstract_print *print; + + if (custom_print) + print = custom_print; + else + print = &printk_adapter; + switch (log_id) { + case HTC_CREDIT_HISTORY_LOG: + cds_print_htc_credit_history(count, print, print_ctx); + break; + case COMMAND_LOG: + wma_print_wmi_cmd_log(count, print, print_ctx); + break; + case COMMAND_TX_CMP_LOG: + wma_print_wmi_cmd_tx_cmp_log(count, print, print_ctx); + break; + case MGMT_COMMAND_LOG: + wma_print_wmi_mgmt_cmd_log(count, print, print_ctx); + break; + case MGMT_COMMAND_TX_CMP_LOG: + wma_print_wmi_mgmt_cmd_tx_cmp_log(count, print, print_ctx); + break; + case EVENT_LOG: + wma_print_wmi_event_log(count, print, print_ctx); + break; + case RX_EVENT_LOG: + wma_print_wmi_rx_event_log(count, print, print_ctx); + break; + case MGMT_EVENT_LOG: + wma_print_wmi_mgmt_event_log(count, print, print_ctx); + break; + default: + print(print_ctx, "Invalid Log Id %d", log_id); + break; + } +} + +#ifdef WLAN_DUMP_LOG_BUF_CNT +void hdd_dump_log_buffer(void *print_ctx, qdf_abstract_print *custom_print) +{ + int i; + + for (i = 0; i <= MGMT_EVENT_LOG; i++) + hdd_ioctl_log_buffer(i, WLAN_DUMP_LOG_BUF_CNT, custom_print, + print_ctx); +} +#endif + +static int drv_cmd_get_ccx_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool ese_mode = ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc); + char extra[32]; + uint8_t len = 0; + struct pmkid_mode_bits pmkid_modes; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + /* + * Check if the features PMKID/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (ese_mode && + (pmkid_modes.fw_okc || pmkid_modes.fw_pmksa_cache) && + ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) { + hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETCCXMODE", ese_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_okc_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + struct pmkid_mode_bits pmkid_modes; + char extra[32]; + uint8_t len = 0; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (pmkid_modes.fw_okc && + ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) && + ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) { + hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETOKCMODE", pmkid_modes.fw_okc); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_fast_roam(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool lfr_mode = ucfg_cm_get_is_lfr_feature_enabled(hdd_ctx->psoc); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTROAM", lfr_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_fast_transition(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool ft = ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETFASTTRANSITION", ft); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int +drv_cmd_set_roam_scan_channel_min_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t min_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME); + + /* Move pointer to ahead of SETROAMSCANCHANNELMINTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &min_time); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME), + cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME, min_time)) { + hdd_err("scan min channel time value %d is out of range (Min: %d Max: %d)", + min_time, + cfg_min(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME), + cfg_max(CFG_LFR_NEIGHBOR_SCAN_MIN_CHAN_TIME)); + ret = -EINVAL; + goto exit; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL, + link_info->vdev_id, min_time); + + hdd_debug("Received Command to change channel min time = %d", + min_time); + + sme_set_neighbor_scan_min_chan_time(hdd_ctx->mac_handle, + min_time, link_info->vdev_id); + +exit: + return ret; +} + +static int drv_cmd_send_action_frame(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_sendactionframe(link_info->adapter, command, + priv_data->total_len); +} + +static int +drv_cmd_get_roam_scan_channel_min_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val; + char extra[32]; + uint8_t len = 0; + + val = ucfg_cm_get_neighbor_scan_min_chan_time(hdd_ctx->psoc, + link_info->vdev_id); + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMSCANCHANNELMINTIME", val); + len = QDF_MIN(priv_data->total_len, len + 1); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL, + link_info->vdev_id, val); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_channel_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t max_time = cfg_default(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME); + + /* Move pointer to ahead of SETSCANCHANNELTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &max_time); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou16 failed range [%d - %d]", + cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME), + cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME, max_time)) { + hdd_err("lfr mode value %d is out of range (Min: %d Max: %d)", + max_time, + cfg_min(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME), + cfg_max(CFG_LFR_NEIGHBOR_SCAN_MAX_CHAN_TIME)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change channel max time = %d", + max_time); + + sme_set_neighbor_scan_max_chan_time(hdd_ctx->mac_handle, + link_info->vdev_id, + max_time); + +exit: + return ret; +} + +static int drv_cmd_get_scan_channel_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val; + char extra[32]; + uint8_t len = 0; + + val = ucfg_cm_get_neighbor_scan_max_chan_time(hdd_ctx->psoc, + link_info->vdev_id); + + hdd_debug("vdev_id: %u, scan channel time: %u", + link_info->vdev_id, val); + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETSCANCHANNELTIME", val); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_home_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t val = cfg_default(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD); + + /* Move pointer to ahead of SETSCANHOMETIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &val); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou16 failed range [%d - %d]", + cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD), + cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD, val)) { + hdd_err("scan home time value %d is out of range (Min: %d Max: %d)", + val, + cfg_min(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD), + cfg_max(CFG_LFR_NEIGHBOR_SCAN_TIMER_PERIOD)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change scan home time = %d", + val); + + sme_set_neighbor_scan_period(hdd_ctx->mac_handle, + link_info->vdev_id, val); + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val; + char extra[32]; + uint8_t len = 0; + + val = ucfg_cm_get_neighbor_scan_period(hdd_ctx->psoc, + link_info->vdev_id); + hdd_debug("vdev_id: %u, scan home time: %u", + link_info->vdev_id, val); + + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETSCANHOMETIME", val); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_roam_intra_band(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t val = cfg_default(CFG_LFR_ROAM_INTRA_BAND); + + /* Move pointer to ahead of SETROAMINTRABAND */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &val); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ROAM_INTRA_BAND), + cfg_max(CFG_LFR_ROAM_INTRA_BAND)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change intra band = %d", + val); + + ucfg_mlme_set_roam_intra_band(hdd_ctx->psoc, (bool)val); + + /* Disable roaming on Vdev before setting PCL */ + sme_stop_roaming(hdd_ctx->mac_handle, link_info->vdev_id, + REASON_DRIVER_DISABLED, RSO_SET_PCL); + + policy_mgr_set_pcl_for_existing_combo(hdd_ctx->psoc, PM_STA_MODE, + link_info->vdev_id); + + /* Enable roaming once SET pcl is done */ + sme_start_roaming(hdd_ctx->mac_handle, link_info->vdev_id, + REASON_DRIVER_ENABLED, RSO_SET_PCL); + +exit: + return ret; +} + +static int drv_cmd_get_roam_intra_band(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val = 0; + char extra[32]; + uint8_t len = 0; + + ucfg_cm_get_roam_intra_band(hdd_ctx->psoc, &val); + /* value is interms of msec */ + len = scnprintf(extra, sizeof(extra), "%s %d", + "GETROAMINTRABAND", val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_n_probes(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t nprobes = cfg_default(CFG_LFR_ROAM_SCAN_N_PROBES); + + /* Move pointer to ahead of SETSCANNPROBES */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &nprobes); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES), + cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_ROAM_SCAN_N_PROBES, nprobes)) { + hdd_err("NProbes value %d is out of range (Min: %d Max: %d)", + nprobes, + cfg_min(CFG_LFR_ROAM_SCAN_N_PROBES), + cfg_max(CFG_LFR_ROAM_SCAN_N_PROBES)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set nProbes = %d", + nprobes); + + sme_update_roam_scan_n_probes(hdd_ctx->mac_handle, + link_info->vdev_id, nprobes); + +exit: + return ret; +} + +static int drv_cmd_get_scan_n_probes(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t val; + char extra[32]; + uint8_t len = 0; + QDF_STATUS status; + + status = sme_get_roam_scan_n_probes(hdd_ctx->mac_handle, + link_info->vdev_id, &val); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_debug("vdev_id: %u, scan_n_probes: %u", + link_info->vdev_id, val); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_scan_home_away_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint16_t home_away_time = cfg_default(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME); + + /* input value is in units of msec */ + + /* Move pointer to ahead of SETSCANHOMEAWAYTIME */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou16(value, 10, &home_away_time); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME), + cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME, home_away_time)) { + hdd_err("home_away_time value %d is out of range (min: %d max: %d)", + home_away_time, + cfg_min(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME), + cfg_max(CFG_LFR_ROAM_SCAN_HOME_AWAY_TIME)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set scan away time = %d", + home_away_time); + + sme_update_roam_scan_home_away_time(hdd_ctx->mac_handle, + link_info->vdev_id, + home_away_time, true); + +exit: + return ret; +} + +static int drv_cmd_get_scan_home_away_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint16_t val; + char extra[32] = {0}; + uint8_t len = 0; + QDF_STATUS status; + + status = ucfg_cm_get_roam_scan_home_away_time(hdd_ctx->psoc, + link_info->vdev_id, + &val); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_debug("vdev_id: %u, scan home away time: %u", + link_info->vdev_id, val); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_reassoc(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_reassoc(link_info->adapter, command, + priv_data->total_len); +} + +static int drv_cmd_set_wes_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t wes_mode = cfg_default(CFG_LFR_ENABLE_WES_MODE); + + /* Move pointer to ahead of SETWESMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &wes_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ENABLE_WES_MODE), + cfg_max(CFG_LFR_ENABLE_WES_MODE)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set WES Mode rssi diff = %d", wes_mode); + + sme_update_wes_mode(hdd_ctx->mac_handle, wes_mode, link_info->vdev_id); + +exit: + return ret; +} + +static int drv_cmd_get_wes_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + bool wes_mode = ucfg_cm_get_wes_mode(hdd_ctx->psoc); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, wes_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int +drv_cmd_set_opportunistic_rssi_diff(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t diff = + cfg_default(CFG_LFR_OPPORTUNISTIC_SCAN_THRESHOLD_DIFF); + + /* Move pointer to ahead of SETOPPORTUNISTICRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &diff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed"); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set Opportunistic Threshold diff = %d", + diff); + + sme_set_roam_opportunistic_scan_threshold_diff(hdd_ctx->mac_handle, + link_info->vdev_id, + diff); + +exit: + return ret; +} + +static int +drv_cmd_get_opportunistic_rssi_diff(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + int8_t val = 0; + char extra[32]; + uint8_t len = 0; + + ucfg_cm_get_roam_opportunistic_scan_threshold_diff(hdd_ctx->psoc, &val); + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int +drv_cmd_set_roam_rescan_rssi_diff(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t rescan_rssi_diff = cfg_default(CFG_LFR_ROAM_RESCAN_RSSI_DIFF); + + /* Move pointer to ahead of SETROAMRESCANRSSIDIFF */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &rescan_rssi_diff); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed"); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set Roam Rescan RSSI Diff = %d", + rescan_rssi_diff); + + sme_set_roam_rescan_rssi_diff(hdd_ctx->mac_handle, + link_info->vdev_id, rescan_rssi_diff); + +exit: + return ret; +} + +static int +drv_cmd_get_roam_rescan_rssi_diff(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t val = 0; + char extra[32]; + uint8_t len = 0; + + ucfg_cm_get_roam_rescan_rssi_diff(hdd_ctx->psoc, &val); + len = scnprintf(extra, sizeof(extra), "%s %d", command, val); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_set_fast_roam(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t lfr_mode = cfg_default(CFG_LFR_FEATURE_ENABLED); + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &lfr_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_FEATURE_ENABLED), + cfg_max(CFG_LFR_FEATURE_ENABLED)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change lfr mode = %d", + lfr_mode); + + if (sme_roaming_in_progress(hdd_ctx->mac_handle, + link_info->vdev_id)) { + hdd_err_rl("Roaming in progress for vdev %d", + link_info->vdev_id); + return -EAGAIN; + } + + ucfg_mlme_set_lfr_enabled(hdd_ctx->psoc, (bool)lfr_mode); + sme_update_is_fast_roam_ini_feature_enabled(hdd_ctx->mac_handle, + link_info->vdev_id, + lfr_mode); + +exit: + return ret; +} + +static int drv_cmd_set_fast_transition(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ft = cfg_default(CFG_LFR_FAST_TRANSITION_ENABLED); + + /* Move pointer to ahead of SETFASTROAM */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &ft); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_FAST_TRANSITION_ENABLED), + cfg_max(CFG_LFR_FAST_TRANSITION_ENABLED)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change ft mode = %d", ft); + + ucfg_mlme_set_fast_transition_enabled(hdd_ctx->psoc, (bool)ft); + +exit: + return ret; +} + +/** + * drv_cmd_fast_reassoc() - Handler for FASTREASSOC driver command + * @link_info: Carries link specific info, which contains adapter + * @hdd_ctx: pointer to hdd context + * @command: Buffer that carries actual command data, which can be parsed by + * hdd_parse_reassoc_command_v1_data() + * @command_len: Command length + * @priv_data: to carry any priv data, FASTREASSOC doesn't have any priv + * data for now. + * + * This function parses the reasoc command data passed in the format + * FASTREASSOC + * + * If MAC from user space is broadcast MAC as: + * "wpa_cli DRIVER FASTREASSOC ff:ff:ff:ff:ff:ff 0", + * user space invoked roaming candidate selection will base on firmware score + * algorithm, current connection will be kept if current AP has highest + * score. It is requirement from customer which can avoid ping-pong roaming. + * + * If firmware fails to roam to new AP due to any reason, host to disconnect + * from current AP as it's unable to roam. + * + * Return: 0 for success non-zero for failure + */ +static int drv_cmd_fast_reassoc(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + qdf_freq_t freq = 0; + tSirMacAddr bssid; + struct qdf_mac_addr target_bssid; + struct hdd_adapter *adapter = link_info->adapter; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + /* if not associated, no need to proceed with reassoc */ + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_warn("Not associated!"); + ret = -EINVAL; + goto exit; + } + + ret = hdd_parse_reassoc_command_v1_data(value, bssid, + &freq, hdd_ctx->pdev); + if (ret) { + hdd_err("Failed to parse reassoc command data"); + goto exit; + } + + qdf_mem_copy(target_bssid.bytes, bssid, sizeof(tSirMacAddr)); + ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, link_info->vdev_id, + &target_bssid, freq, CM_ROAMING_HOST); + +exit: + return ret; +} + +static int drv_cmd_set_okc_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t okc_mode; + struct pmkid_mode_bits pmkid_modes; + uint32_t cur_pmkid_modes; + QDF_STATUS status; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + + /* + * Check if the features PMKID/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) && + pmkid_modes.fw_okc && + ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) { + hdd_warn("PMKID/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETOKCMODE */ + value = value + command_len + 1; + + /* get the current configured value */ + status = ucfg_mlme_get_pmkid_modes(hdd_ctx->psoc, &cur_pmkid_modes); + if (status != QDF_STATUS_SUCCESS) + hdd_err("get pmkid modes failed"); + + okc_mode = cur_pmkid_modes & CFG_PMKID_MODES_OKC; + + /* Convert the value from ascii to integer */ + ret = kstrtou32(value, 10, &okc_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("value out of range [0 - 1]"); + ret = -EINVAL; + goto exit; + } + + if ((okc_mode < 0) || + (okc_mode > 1)) { + hdd_err("Okc mode value %d is out of range (Min: 0 Max: 1)", + okc_mode); + ret = -EINVAL; + goto exit; + } + hdd_debug("Received Command to change okc mode = %d", okc_mode); + + if (okc_mode) + cur_pmkid_modes |= CFG_PMKID_MODES_OKC; + else + cur_pmkid_modes &= ~CFG_PMKID_MODES_OKC; + status = ucfg_mlme_set_pmkid_modes(hdd_ctx->psoc, + cur_pmkid_modes); + if (status != QDF_STATUS_SUCCESS) { + ret = -EPERM; + hdd_err("set pmkid modes failed"); + } +exit: + return ret; +} + +static int drv_cmd_bt_coex_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + char *coex_mode; + + coex_mode = command + 11; + if ('1' == *coex_mode) { + hdd_debug("BTCOEXMODE %d", *coex_mode); + hdd_ctx->bt_coex_mode_set = true; + ret = wlan_hdd_scan_abort(link_info); + if (ret < 0) { + hdd_err("Failed to abort existing scan status: %d", + ret); + } + } else if ('2' == *coex_mode) { + hdd_debug("BTCOEXMODE %d", *coex_mode); + hdd_ctx->bt_coex_mode_set = false; + } + + return ret; +} + +static int drv_cmd_scan_active(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN; + return 0; +} + +static int drv_cmd_scan_passive(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + hdd_ctx->ioctl_scan_mode = eSIR_PASSIVE_SCAN; + return 0; +} + +static int drv_cmd_get_dwell_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + char extra[32]; + uint8_t len = 0; + + memset(extra, 0, sizeof(extra)); + ret = hdd_get_dwell_time(hdd_ctx->psoc, command, extra, + sizeof(extra), &len); + len = QDF_MIN(priv_data->total_len, len + 1); + if (ret != 0 || copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + ret = len; +exit: + return ret; +} + +static int drv_cmd_set_dwell_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_set_dwell_time(hdd_ctx->psoc, command); +} + +static int drv_cmd_conc_set_dwell_time(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + u8 *command, + u8 command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_conc_set_dwell_time(link_info->adapter, command); +} + +static int drv_cmd_miracast(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + QDF_STATUS ret_status; + int ret = 0; + uint8_t filter_type = 0; + uint8_t *value; + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + value = command + 9; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &filter_type); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range"); + ret = -EINVAL; + goto exit; + } + hdd_debug("filter_type %d", filter_type); + + switch (filter_type) { + case MIRACAST_DISABLED: + case MIRACAST_SOURCE: + case MIRACAST_SINK: + break; + case MIRACAST_CONN_OPT_ENABLED: + case MIRACAST_CONN_OPT_DISABLED: + { + wma_cli_set_command( + link_info->vdev_id, + wmi_pdev_param_power_collapse_enable, + (filter_type == MIRACAST_CONN_OPT_ENABLED ? + 0 : 1), PDEV_CMD); + return 0; + } + default: + hdd_err("accepted Values: 0-Disabled, 1-Source, 2-Sink, 128,129"); + ret = -EINVAL; + goto exit; + } + + /* Filtertype value should be either 0-Disabled, 1-Source, 2-sink */ + hdd_ctx->miracast_value = filter_type; + ucfg_mlme_set_vdev_traffic_low_latency(hdd_ctx->psoc, + link_info->vdev_id, + filter_type != + MIRACAST_DISABLED); + + ret_status = sme_set_miracast(hdd_ctx->mac_handle, filter_type); + if (QDF_STATUS_SUCCESS != ret_status) { + hdd_err("Failed to set miracast"); + return -EBUSY; + } + ret_status = ucfg_scan_set_miracast(hdd_ctx->psoc, + filter_type ? true : false); + if (QDF_IS_STATUS_ERROR(ret_status)) { + hdd_err("Failed to set miracastn scan"); + return -EBUSY; + } + + if (policy_mgr_is_mcc_in_24G(hdd_ctx->psoc)) + return wlan_hdd_set_mas(link_info->adapter, filter_type); + +exit: + return ret; +} + +static int drv_cmd_tput_debug_mode_enable(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + u8 *command, + u8 command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_enable_unit_test_commands(link_info->adapter, hdd_ctx); +} + +static int drv_cmd_tput_debug_mode_disable(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + u8 *command, + u8 command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_disable_unit_test_commands(link_info->adapter, hdd_ctx); +} + +#ifdef FEATURE_WLAN_ESE +static int +drv_cmd_set_ccx_roam_scan_channels(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t num_channels = 0; + QDF_STATUS status; + mac_handle_t mac_handle; + + if (!hdd_ctx) { + hdd_err("invalid hdd ctx"); + ret = -EINVAL; + goto exit; + } + + ret = hdd_parse_channellist(hdd_ctx, value, channel_freq_list, + &num_channels); + if (ret) { + hdd_err("Failed to parse channel list information"); + goto exit; + } + if (num_channels > CFG_VALID_CHANNEL_LIST_LEN) { + hdd_err("number of channels (%d) supported exceeded max (%d)", + num_channels, CFG_VALID_CHANNEL_LIST_LEN); + ret = -EINVAL; + goto exit; + } + + mac_handle = hdd_ctx->mac_handle; + if (!sme_validate_channel_list(mac_handle, channel_freq_list, + num_channels)) { + hdd_err("List contains invalid channel(s)"); + ret = -EINVAL; + goto exit; + } + + status = ucfg_cm_set_ese_roam_scan_channel_list(hdd_ctx->pdev, + link_info->vdev_id, + channel_freq_list, + num_channels); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed to update channel list information"); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_get_tsm_stats(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + char extra[128] = { 0 }; + int len = 0; + uint8_t tid = 0; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_station_ctx *sta_ctx; + tAniTrafStrmMetrics tsm_metrics = {0}; + + if ((QDF_STA_MODE != adapter->device_mode) && + (QDF_P2P_CLIENT_MODE != adapter->device_mode)) { + hdd_warn("Unsupported in mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + /* if not associated, return error */ + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_err("Not associated!"); + ret = -EINVAL; + goto exit; + } + + /* Move pointer to ahead of GETTSMSTATS */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &tid); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + TID_MIN_VALUE, + TID_MAX_VALUE); + ret = -EINVAL; + goto exit; + } + if ((tid < TID_MIN_VALUE) || (tid > TID_MAX_VALUE)) { + hdd_err("tid value %d is out of range (Min: %d Max: %d)", + tid, TID_MIN_VALUE, TID_MAX_VALUE); + ret = -EINVAL; + goto exit; + } + hdd_debug("Received Command to get tsm stats tid = %d", + tid); + ret = hdd_get_tsm_stats(adapter, tid, &tsm_metrics); + if (ret) { + hdd_err("failed to get tsm stats"); + goto exit; + } + hdd_debug( + "UplinkPktQueueDly(%d) UplinkPktQueueDlyHist[0](%d) UplinkPktQueueDlyHist[1](%d) UplinkPktQueueDlyHist[2](%d) UplinkPktQueueDlyHist[3](%d) UplinkPktTxDly(%u) UplinkPktLoss(%d) UplinkPktCount(%d) RoamingCount(%d) RoamingDly(%d)", + tsm_metrics.UplinkPktQueueDly, + tsm_metrics.UplinkPktQueueDlyHist[0], + tsm_metrics.UplinkPktQueueDlyHist[1], + tsm_metrics.UplinkPktQueueDlyHist[2], + tsm_metrics.UplinkPktQueueDlyHist[3], + tsm_metrics.UplinkPktTxDly, + tsm_metrics.UplinkPktLoss, + tsm_metrics.UplinkPktCount, + tsm_metrics.RoamingCount, + tsm_metrics.RoamingDly); + /* + * Output TSM stats is of the format + * GETTSMSTATS [PktQueueDly] + * [PktQueueDlyHist[0]]:[PktQueueDlyHist[1]] ...[RoamingDly] + * eg., GETTSMSTATS 10 1:0:0:161 20 1 17 8 39800 + */ + len = scnprintf(extra, + sizeof(extra), + "%s %d %d:%d:%d:%d %u %d %d %d %d", + command, + tsm_metrics.UplinkPktQueueDly, + tsm_metrics.UplinkPktQueueDlyHist[0], + tsm_metrics.UplinkPktQueueDlyHist[1], + tsm_metrics.UplinkPktQueueDlyHist[2], + tsm_metrics.UplinkPktQueueDlyHist[3], + tsm_metrics.UplinkPktTxDly, + tsm_metrics.UplinkPktLoss, + tsm_metrics.UplinkPktCount, + tsm_metrics.RoamingCount, + tsm_metrics.RoamingDly); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto exit; + } + +exit: + return ret; +} + +static int drv_cmd_set_cckm_ie(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + uint8_t *cckm_ie = NULL; + uint8_t cckm_ie_len = 0; + + ret = hdd_parse_get_cckm_ie(value, &cckm_ie, &cckm_ie_len); + if (ret) { + hdd_err("Failed to parse cckm ie data"); + goto exit; + } + + if (cckm_ie_len > DOT11F_IE_RSN_MAX_LEN) { + hdd_err("CCKM Ie input length is more than max[%d]", + DOT11F_IE_RSN_MAX_LEN); + if (cckm_ie) { + qdf_mem_free(cckm_ie); + cckm_ie = NULL; + } + ret = -EINVAL; + goto exit; + } + + ucfg_cm_set_cckm_ie(hdd_ctx->psoc, link_info->vdev_id, cckm_ie, + cckm_ie_len); + if (cckm_ie) { + qdf_mem_free(cckm_ie); + cckm_ie = NULL; + } + +exit: + return ret; +} + +static int drv_cmd_ccx_beacon_req(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + tCsrEseBeaconReq req = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter = link_info->adapter; + + if (QDF_STA_MODE != adapter->device_mode) { + hdd_warn("Unsupported in mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + ret = hdd_parse_ese_beacon_req(hdd_ctx->pdev, value, &req); + if (ret) { + hdd_err("Failed to parse ese beacon req"); + goto exit; + } + + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug("Not associated"); + + if (!req.numBcnReqIe) + return -EINVAL; + + hdd_indicate_ese_bcn_report_no_results(adapter, + req.bcnReq[0].measurementToken, + 0x02, /* BIT(1) set for measurement done */ + 0); /* no BSS */ + goto exit; + } + + status = sme_set_ese_beacon_request(hdd_ctx->mac_handle, + link_info->vdev_id, + &req); + + if (QDF_STATUS_E_RESOURCES == status) { + hdd_err("sme_set_ese_beacon_request failed (%d), a request already in progress", + status); + ret = -EBUSY; + goto exit; + } else if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_set_ese_beacon_request failed (%d)", + status); + ret = -EINVAL; + goto exit; + } + +exit: + return ret; +} + +/** + * drv_cmd_ccx_plm_req() - Set ESE PLM request + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets the ESE PLM request + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_ccx_plm_req(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + QDF_STATUS status; + struct plm_req_params *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return -ENOMEM; + + status = hdd_parse_plm_cmd(command, req); + if (QDF_IS_STATUS_SUCCESS(status)) { + req->vdev_id = link_info->vdev_id; + status = sme_set_plm_request(hdd_ctx->mac_handle, req); + } + qdf_mem_free(req); + + return qdf_status_to_os_return(status); +} + +/** + * drv_cmd_set_ccx_mode() - Set ESE mode + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets ESE mode + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_set_ccx_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t ese_mode = cfg_default(CFG_LFR_ESE_FEATURE_ENABLED); + struct pmkid_mode_bits pmkid_modes; + mac_handle_t mac_handle; + + hdd_get_pmkid_modes(hdd_ctx, &pmkid_modes); + mac_handle = hdd_ctx->mac_handle; + /* + * Check if the features OKC/ESE/11R are supported simultaneously, + * then this operation is not permitted (return FAILURE) + */ + if (ucfg_cm_get_is_ese_feature_enabled(hdd_ctx->psoc) && + pmkid_modes.fw_okc && + ucfg_cm_get_is_ft_feature_enabled(hdd_ctx->psoc)) { + hdd_warn("OKC/ESE/11R are supported simultaneously hence this operation is not permitted!"); + ret = -EPERM; + goto exit; + } + + /* Move pointer to ahead of SETCCXMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &ese_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ESE_FEATURE_ENABLED), + cfg_max(CFG_LFR_ESE_FEATURE_ENABLED)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to change ese mode = %d", ese_mode); + + sme_update_is_ese_feature_enabled(mac_handle, + link_info->vdev_id, + ese_mode); + +exit: + return ret; +} +#endif /* FEATURE_WLAN_ESE */ + +static int drv_cmd_set_mc_rate(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint32_t target_rate = 0; + + /* input value is in units of hundred kbps */ + + /* Move pointer to ahead of SETMCRATE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer, decimal base */ + ret = kstrtouint(value, 10, &target_rate); + + ret = wlan_hdd_set_mc_rate(link_info, target_rate); + return ret; +} + +static int drv_cmd_max_tx_power(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + int tx_power; + QDF_STATUS status; + uint8_t *value = command; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; + struct qdf_mac_addr selfmac = QDF_MAC_ADDR_BCAST_INIT; + struct hdd_adapter *adapter = link_info->adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DRV_CMD_MAX_TX_POWER; + + ret = hdd_parse_setmaxtxpower_command(value, &tx_power); + if (ret) { + hdd_err("Invalid MAXTXPOWER command"); + return ret; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + /* Assign correct self MAC address */ + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + qdf_copy_macaddr(&bssid, &adapter->mac_addr); + } else { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + if (hdd_cm_is_vdev_associated(adapter->deflink)) + qdf_copy_macaddr(&bssid, + &sta_ctx->conn_info.bssid); + } + + qdf_copy_macaddr(&selfmac, + &adapter->mac_addr); + + hdd_debug("Device mode %d max tx power %d selfMac: " + QDF_MAC_ADDR_FMT " bssId: " QDF_MAC_ADDR_FMT, + adapter->device_mode, tx_power, + QDF_MAC_ADDR_REF(selfmac.bytes), + QDF_MAC_ADDR_REF(bssid.bytes)); + + status = sme_set_max_tx_power(hdd_ctx->mac_handle, + bssid, selfmac, tx_power); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Set max tx power failed"); + ret = -EINVAL; + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + goto exit; + } + hdd_debug("Set max tx power success"); + hdd_adapter_dev_put_debug(adapter, dbgid); + } + +exit: + return ret; +} + +static int drv_cmd_set_dfs_scan_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t *value = command; + uint8_t dfs_scan_mode = cfg_default(CFG_LFR_ROAMING_DFS_CHANNEL); + + /* Move pointer to ahead of SETDFSSCANMODE */ + value = value + command_len + 1; + + /* Convert the value from ascii to integer */ + ret = kstrtou8(value, 10, &dfs_scan_mode); + if (ret < 0) { + /* + * If the input value is greater than max value of datatype, + * then also kstrtou8 fails + */ + hdd_err("kstrtou8 failed range [%d - %d]", + cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL), + cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL)); + ret = -EINVAL; + goto exit; + } + + if (!cfg_in_range(CFG_LFR_ROAMING_DFS_CHANNEL, dfs_scan_mode)) { + hdd_err("dfs_scan_mode value %d is out of range (Min: %d Max: %d)", + dfs_scan_mode, + cfg_min(CFG_LFR_ROAMING_DFS_CHANNEL), + cfg_max(CFG_LFR_ROAMING_DFS_CHANNEL)); + ret = -EINVAL; + goto exit; + } + + hdd_debug("Received Command to Set DFS Scan Mode = %d", + dfs_scan_mode); + + /* When DFS scanning is disabled, the DFS channels need to be + * removed from the operation of device. + */ + ret = wlan_hdd_enable_dfs_chan_scan(hdd_ctx, + dfs_scan_mode != ROAMING_DFS_CHANNEL_DISABLED); + if (ret < 0) { + /* Some conditions prevented it from disabling DFS channels */ + hdd_err("disable/enable DFS channel request was denied"); + goto exit; + } + + sme_update_dfs_scan_mode(hdd_ctx->mac_handle, link_info->vdev_id, + dfs_scan_mode); + +exit: + return ret; +} + +static int drv_cmd_get_dfs_scan_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + uint8_t dfs_scan_mode = sme_get_dfs_scan_mode(hdd_ctx->mac_handle); + char extra[32]; + uint8_t len = 0; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, dfs_scan_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_link_status(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + int value = wlan_hdd_get_link_status(link_info->adapter); + char extra[32]; + uint8_t len; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, value); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +static int drv_cmd_enable_ext_wow(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + uint8_t *value = command; + int set_value; + + /* Move pointer to ahead of ENABLEEXTWOW */ + value = value + command_len; + + if (!(sscanf(value, "%d", &set_value))) { + hdd_info("No input identified"); + return -EINVAL; + } + + return hdd_enable_ext_wow_parser(link_info->adapter, + link_info->vdev_id, set_value); +} + +static int drv_cmd_set_app1_params(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + + /* Move pointer to ahead of SETAPP1PARAMS */ + value = value + command_len; + + ret = hdd_set_app_type1_parser(link_info->adapter, + value, strlen(value)); + if (ret >= 0) + hdd_ctx->is_extwow_app_type1_param_set = true; + + return ret; +} + +static int drv_cmd_set_app2_params(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + + /* Move pointer to ahead of SETAPP2PARAMS */ + value = value + command_len; + + ret = hdd_set_app_type2_parser(link_info->adapter, + value, strlen(value)); + if (ret >= 0) + hdd_ctx->is_extwow_app_type2_param_set = true; + + return ret; +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +#ifdef FEATURE_WLAN_TDLS +/** + * drv_cmd_tdls_secondary_channel_offset() - secondary tdls off channel offset + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets the secondary tdls off channel + * offset + * + * Return: 0 on success; negative errno otherwise + */ +static int +drv_cmd_tdls_secondary_channel_offset(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hdd_debug("Tdls offchannel offset:%d", set_value); + + ret = hdd_set_tdls_secoffchanneloffset(hdd_ctx, link_info->adapter, + set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel_mode() - set tdls off channel mode + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls off channel mode + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_off_channel_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hdd_debug("Tdls offchannel mode:%d", set_value); + + ret = hdd_set_tdls_offchannelmode(hdd_ctx, + link_info->adapter, set_value); + + return ret; +} + +/** + * drv_cmd_tdls_off_channel() - set tdls off channel number + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls off channel number + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_off_channel(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + int channel; + enum channel_state reg_state; + qdf_freq_t ch_freq; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &channel); + if (ret != 1) + return -EINVAL; + + ch_freq = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, channel); + reg_state = + wlan_reg_get_channel_state_for_pwrmode(hdd_ctx->pdev, ch_freq, + REG_CURRENT_PWR_MODE); + + if (reg_state == CHANNEL_STATE_DFS || + reg_state == CHANNEL_STATE_DISABLE || + reg_state == CHANNEL_STATE_INVALID) { + hdd_err("reg state of the channel %d is %d and not supported", + channel, reg_state); + return -EINVAL; + } + + hdd_debug("Tdls offchannel num: %d", channel); + + ret = hdd_set_tdls_offchannel(hdd_ctx, link_info->adapter, channel); + + return ret; +} + +/** + * drv_cmd_tdls_scan() - set tdls scan type + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to the HDD context + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Private data coming with the driver command. Unused here + * + * This function handles driver command that sets tdls scan type + * + * Return: 0 on success; negative errno otherwise + */ +static int drv_cmd_tdls_scan(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint8_t *value = command; + int set_value; + + /* Move pointer to point the string */ + value += command_len; + + ret = sscanf(value, "%d", &set_value); + if (ret != 1) + return -EINVAL; + + hdd_debug("Tdls scan type val: %d", set_value); + + ret = hdd_set_tdls_scan_type(hdd_ctx, set_value); + + return ret; +} +#endif + +static int drv_cmd_get_rssi(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret = 0; + int8_t rssi = 0; + char extra[32]; + + uint8_t len = 0; + + wlan_hdd_get_rssi(link_info, &rssi); + + len = scnprintf(extra, sizeof(extra), "%s %d", command, rssi); + len = QDF_MIN(priv_data->total_len, len + 1); + + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +/** + * drv_cmd_get_sap_go_linkspeed() - Driver command to get SAP/P2P Go peer link + * speed + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: HDD context pointer + * @command: Driver command string + * @command_len: Driver command string length + * @priv_data: Pointer to HDD private data + * + * Return: 0 if linkspeed data is available, negative errno otherwise + */ +static int drv_cmd_get_sap_go_linkspeed(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint32_t link_speed = 0; + char extra[64]; + uint8_t len = 0; + struct hdd_adapter *adapter = link_info->adapter; + + if (adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_SAP_MODE) { + ret = wlan_hdd_get_sap_go_peer_linkspeed(link_info, + &link_speed, + command, + command_len); + } else { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + ret = -ENOTSUPP; + } + + if (0 != ret) + return ret; + + len = scnprintf(extra, sizeof(extra), "%s %d\n", + "SOFT-AP LINKSPEED", link_speed); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +static int drv_cmd_get_linkspeed(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int ret; + uint32_t link_speed = 0; + char extra[32]; + uint8_t len = 0; + + ret = wlan_hdd_get_link_speed(link_info, &link_speed); + if (0 != ret) + return ret; + + len = scnprintf(extra, sizeof(extra), "%s %d", command, link_speed); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + ret = -EFAULT; + } + + return ret; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * hdd_set_rx_filter() - set RX filter + * @adapter: Pointer to adapter + * @action: Filter action + * @pattern: Address pattern + * + * Address pattern is most significant byte of address for example + * 0x01 for IPV4 multicast address + * 0x33 for IPV6 multicast address + * 0xFF for broadcast address + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_set_rx_filter(struct hdd_adapter *adapter, bool action, + uint8_t pattern) +{ + int ret; + uint8_t i, j; + tSirRcvFltMcAddrList *filter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle_t mac_handle; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) { + hdd_err("MAC Handle is NULL"); + return -EINVAL; + } + + if (!ucfg_pmo_is_mc_addr_list_enabled(hdd_ctx->psoc)) { + hdd_warn("mc addr ini is disabled"); + return -EINVAL; + } + + /* + * If action is false it means start dropping packets + * Set addr_filter_pattern which will be used when sending + * MC/BC address list to target + */ + if (!action) + adapter->addr_filter_pattern = pattern; + else + adapter->addr_filter_pattern = 0; + + if (((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) && + adapter->mc_addr_list.mc_cnt && + hdd_cm_is_vdev_associated(adapter->deflink)) { + + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return -ENOMEM; + + filter->action = action; + for (i = 0, j = 0; i < adapter->mc_addr_list.mc_cnt; i++) { + if (!memcmp(adapter->mc_addr_list.addr[i], + &pattern, 1)) { + memcpy(filter->multicastAddr[j].bytes, + adapter->mc_addr_list.addr[i], + sizeof(adapter->mc_addr_list.addr[i])); + + hdd_debug("%s RX filter : addr =" + QDF_MAC_ADDR_FMT, + action ? "setting" : "clearing", + QDF_MAC_ADDR_REF(filter->multicastAddr[j].bytes)); + j++; + } + if (j == SIR_MAX_NUM_MULTICAST_ADDRESS) + break; + } + filter->ulMulticastAddrCnt = j; + /* Set rx filter */ + sme_8023_multicast_list(mac_handle, adapter->deflink->vdev_id, + filter); + qdf_mem_free(filter); + } else { + hdd_debug("mode %d mc_cnt %d", + adapter->device_mode, adapter->mc_addr_list.mc_cnt); + } + + return 0; +} + +/** + * hdd_driver_rxfilter_command_handler() - RXFILTER driver command handler + * @command: Pointer to input string driver command + * @adapter: Pointer to adapter + * @action: Action to enable/disable filtering + * + * If action == false + * Start filtering out data packets based on type + * RXFILTER-REMOVE 0 -> Start filtering out unicast data packets + * RXFILTER-REMOVE 1 -> Start filtering out broadcast data packets + * RXFILTER-REMOVE 2 -> Start filtering out IPV4 mcast data packets + * RXFILTER-REMOVE 3 -> Start filtering out IPV6 mcast data packets + * + * if action == true + * Stop filtering data packets based on type + * RXFILTER-ADD 0 -> Stop filtering unicast data packets + * RXFILTER-ADD 1 -> Stop filtering broadcast data packets + * RXFILTER-ADD 2 -> Stop filtering IPV4 mcast data packets + * RXFILTER-ADD 3 -> Stop filtering IPV6 mcast data packets + * + * Current implementation only supports IPV4 address filtering by + * selectively allowing IPV4 multicast data packest based on + * address list received in .ndo_set_rx_mode + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_driver_rxfilter_command_handler(uint8_t *command, + struct hdd_adapter *adapter, + bool action) +{ + int ret = 0; + uint8_t *value; + uint8_t type; + + value = command; + /* Skip space after RXFILTER-REMOVE OR RXFILTER-ADD based on action */ + if (!action) + value = command + 16; + else + value = command + 13; + ret = kstrtou8(value, 10, &type); + if (ret < 0) { + hdd_err("kstrtou8 failed invalid input value"); + return -EINVAL; + } + + switch (type) { + case 2: + /* Set rx filter for IPV4 multicast data packets */ + ret = hdd_set_rx_filter(adapter, action, 0x01); + break; + default: + hdd_debug("Unsupported RXFILTER type %d", type); + break; + } + + return ret; +} + +/** + * drv_cmd_rx_filter_remove() - RXFILTER REMOVE driver command handler + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_rx_filter_remove(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_driver_rxfilter_command_handler(command, + link_info->adapter, false); +} + +/** + * drv_cmd_rx_filter_add() - RXFILTER ADD driver command handler + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_rx_filter_add(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_driver_rxfilter_command_handler(command, + link_info->adapter, true); +} +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/** + * hdd_parse_setantennamode_command() - HDD Parse SETANTENNAMODE + * command + * @value: Pointer to SETANTENNAMODE command + * + * This function parses the SETANTENNAMODE command passed in the format + * SETANTENNAMODEmode + * + * Return: parsed antenna mode + */ +static int hdd_parse_setantennamode_command(const uint8_t *value) +{ + const uint8_t *in_ptr = value; + int tmp, v; + char arg1[32]; + + in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE); + + /* no argument after the command */ + if (!in_ptr) { + hdd_err("No argument after the command"); + return -EINVAL; + } + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *in_ptr) { + hdd_err("No space after the command"); + return -EINVAL; + } + + /* remove empty spaces */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) { + hdd_err("No argument followed by spaces"); + return -EINVAL; + } + + /* get the argument i.e. antenna mode */ + v = sscanf(in_ptr, "%31s ", arg1); + if (1 != v) { + hdd_err("argument retrieval from cmd string failed"); + return -EINVAL; + } + + v = kstrtos32(arg1, 10, &tmp); + if (v < 0) { + hdd_err("argument string to int conversion failed"); + return -EINVAL; + } + + return tmp; +} + +/** + * hdd_is_supported_chain_mask_2x2() - Verify if supported chain + * mask is 2x2 mode + * @hdd_ctx: Pointer to hdd context + * + * Return: true if supported chain mask 2x2 else false + */ +static bool hdd_is_supported_chain_mask_2x2(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + bool bval = false; + +/* + * Revisit and the update logic to determine the number + * of TX/RX chains supported in the system when + * antenna sharing per band chain mask support is + * brought in + */ + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + return (bval == 0x01) ? true : false; +} + +/** + * hdd_is_supported_chain_mask_1x1() - Verify if the supported + * chain mask is 1x1 + * @hdd_ctx: Pointer to hdd context + * + * Return: true if supported chain mask 1x1 else false + */ +static bool hdd_is_supported_chain_mask_1x1(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + bool bval = false; + + /* + * Revisit and update the logic to determine the number + * of TX/RX chains supported in the system when + * antenna sharing per band chain mask support is + * brought in + */ + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + return (!bval) ? true : false; +} + +QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode) +{ + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + hdd_ctx->current_antenna_mode = mode; + /* + * Update the user requested nss in the mac context. + * This will be used in tdls protocol engine to form tdls + * Management frames. + */ + sme_update_user_configured_nss(mac_handle, + hdd_ctx->current_antenna_mode); + + hdd_debug("Successfully switched to mode: %d x %d", + hdd_ctx->current_antenna_mode, + hdd_ctx->current_antenna_mode); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_soc_set_antenna_mode_cb() - Callback for set antenna mode + * @status: Status of set antenna mode + * @context: callback context + * + * Callback on setting antenna mode + * + * Return: None + */ +static void +wlan_hdd_soc_set_antenna_mode_cb(enum set_antenna_mode_status status, + void *context) +{ + struct osif_request *request = NULL; + + hdd_debug("Status: %d", status); + + request = osif_request_get(context); + if (!request) { + hdd_err("obsolete request"); + return; + } + + /* Signal the completion of set dual mac config */ + osif_request_complete(request); + osif_request_put(request); +} + +int hdd_set_antenna_mode(struct wlan_hdd_link_info *link_info, int mode) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sir_antenna_mode_param params; + QDF_STATUS status; + int ret = 0; + struct osif_request *request = NULL; + static const struct osif_request_params request_params = { + .priv_size = 0, + .timeout_ms = SME_POLICY_MGR_CMD_TIMEOUT, + }; + + if (QDF_STATUS_SUCCESS == + wlan_is_tdls_session_present(link_info->vdev)) { + hdd_debug("TDLS session exists"); + ret = -EINVAL; + goto exit; + } + + switch (mode) { + case HDD_ANTENNA_MODE_1X1: + params.num_rx_chains = 1; + params.num_tx_chains = 1; + break; + case HDD_ANTENNA_MODE_2X2: + params.num_rx_chains = 2; + params.num_tx_chains = 2; + break; + default: + hdd_err("unsupported antenna mode"); + ret = -EINVAL; + goto exit; + } + + if (hdd_ctx->dynamic_nss_chains_support) + return hdd_set_dynamic_antenna_mode(link_info, + params.num_rx_chains, + params.num_tx_chains); + + if ((HDD_ANTENNA_MODE_2X2 == mode) && + (!hdd_is_supported_chain_mask_2x2(hdd_ctx))) { + hdd_err("System does not support 2x2 mode"); + ret = -EPERM; + goto exit; + } + + if ((HDD_ANTENNA_MODE_1X1 == mode) && + hdd_is_supported_chain_mask_1x1(hdd_ctx)) { + hdd_err("System only supports 1x1 mode"); + goto exit; + } + + /* Check TDLS status and update antenna mode */ + if ((QDF_STA_MODE == adapter->device_mode) && + policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) { + ret = wlan_hdd_tdls_antenna_switch(link_info, mode); + if (0 != ret) + goto exit; + } + + request = osif_request_alloc(&request_params); + if (!request) { + hdd_err("Request Allocation Failure"); + ret = -ENOMEM; + goto exit; + } + + params.set_antenna_mode_ctx = osif_request_cookie(request); + params.set_antenna_mode_resp = (void *)wlan_hdd_soc_set_antenna_mode_cb; + hdd_debug("Set antenna mode rx chains: %d tx chains: %d", + params.num_rx_chains, + params.num_tx_chains); + + status = sme_soc_set_antenna_mode(hdd_ctx->mac_handle, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("set antenna mode failed status : %d", status); + ret = -EFAULT; + goto request_put; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("send set antenna mode timed out"); + goto request_put; + } + + status = hdd_update_smps_antenna_mode(hdd_ctx, mode); + if (QDF_STATUS_SUCCESS != status) { + ret = -EFAULT; + goto request_put; + } + ret = 0; +request_put: + osif_request_put(request); +exit: + hdd_debug("Set antenna status: %d current mode: %d", + ret, hdd_ctx->current_antenna_mode); + + return ret; +} + +/** + * drv_cmd_set_antenna_mode() - SET ANTENNA MODE driver command + * handler + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: Command length + * @priv_data: Pointer to private data in command + */ +static int drv_cmd_set_antenna_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + int mode; + uint8_t *value = command; + + mode = hdd_parse_setantennamode_command(value); + if (mode < 0) { + hdd_err("Invalid SETANTENNA command"); + return mode; + } + + hdd_debug("Processing antenna mode switch to: %d", mode); + + return hdd_set_antenna_mode(link_info, mode); +} + +/** + * hdd_get_dynamic_antenna_mode() -get the dynamic antenna mode for vdev + * @antenna_mode: pointer to antenna mode of vdev + * @dynamic_nss_chains_support: feature support for dynamic nss chains update + * @vdev: Pointer to vdev + * + * This API will check for the num of chains configured for the vdev, and fill + * that info in the antenna mode if the dynamic chains per vdev are supported. + * + * Return: None + */ +static void +hdd_get_dynamic_antenna_mode(uint32_t *antenna_mode, + bool dynamic_nss_chains_support, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlme_nss_chains *nss_chains_dynamic_cfg; + + if (!dynamic_nss_chains_support) + return; + + nss_chains_dynamic_cfg = ucfg_mlme_get_dynamic_vdev_config(vdev); + if (!nss_chains_dynamic_cfg) { + hdd_err("nss chain dynamic config NULL"); + return; + } + /* + * At present, this command doesn't include band, so by default + * it will return the band 2ghz present rf chains. + */ + *antenna_mode = + nss_chains_dynamic_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ]; +} + +/** + * drv_cmd_get_antenna_mode() - GET ANTENNA MODE driver command + * handler + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to hdd context + * @command: Pointer to input command + * @command_len: length of the command + * @priv_data: private data coming with the driver command + * + * Return: 0 for success non-zero for failure + */ +static inline int drv_cmd_get_antenna_mode(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + uint32_t antenna_mode = 0; + char extra[32]; + uint8_t len = 0; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + antenna_mode = hdd_ctx->current_antenna_mode; + /* Overwrite this antenna mode if dynamic vdev chains are supported */ + hdd_get_dynamic_antenna_mode(&antenna_mode, + hdd_ctx->dynamic_nss_chains_support, vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + len = scnprintf(extra, sizeof(extra), "%s %d", command, + antenna_mode); + len = QDF_MIN(priv_data->total_len, len + 1); + if (copy_to_user(priv_data->buf, &extra, len)) { + hdd_err("Failed to copy data to user buffer"); + return -EFAULT; + } + + hdd_debug("Get antenna mode: %d", antenna_mode); + + return 0; +} + +/* + * dummy (no-op) hdd driver command handler + */ +static int drv_cmd_dummy(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + hdd_debug("%s: Ignoring driver command \"%s\"", + link_info->adapter->dev->name, command); + return 0; +} + +/* + * handler for any unsupported wlan hdd driver command + */ +static int drv_cmd_invalid(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_UNSUPPORTED_IOCTL, + adapter->deflink->vdev_id, 0); + + hdd_debug("%s: Unsupported driver command \"%s\"", + adapter->dev->name, command); + + return -ENOTSUPP; +} + +/** + * hdd_apply_fcc_constraint() - Set FCC constraint + * @hdd_ctx: Pointer to hdd context + * @fcc_constraint: Fcc constraint flag + * + * Return: Return 0 incase of success else return error number + */ +static int hdd_apply_fcc_constraint(struct hdd_context *hdd_ctx, + bool fcc_constraint) +{ + QDF_STATUS status; + + status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, + fcc_constraint); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update tx power for channels 12/13"); + return qdf_status_to_os_return(status); + } + + status = wlan_reg_recompute_current_chan_list(hdd_ctx->psoc, + hdd_ctx->pdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update tx power for channels 12/13"); + return qdf_status_to_os_return(status); + } + + return 0; +} + +/** + * hdd_apply_fcc_constraint_update_band() - Set FCC constraint and update band + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: Pointer to hdd context + * @fcc_constraint: FCC constraint flag + * @dis_6g_keep_sta_cli_conn: Disable 6 GHz band and keep STA, P2P client + * connection flag + * @band_bitmap: Band bitmap + * + * Return: Return 0 incase of success else return error number + */ +static int +hdd_apply_fcc_constraint_update_band(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + bool fcc_constraint, + bool dis_6g_keep_sta_cli_conn, + uint32_t band_bitmap) +{ + QDF_STATUS status; + + status = ucfg_reg_set_fcc_constraint(hdd_ctx->pdev, + fcc_constraint); + if (status) { + hdd_err("Failed to update tx power for channels 12/13"); + return qdf_status_to_os_return(status); + } + + status = ucfg_reg_set_keep_6ghz_sta_cli_connection(hdd_ctx->pdev, + dis_6g_keep_sta_cli_conn); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update keep sta cli connection"); + return qdf_status_to_os_return(status); + } + + return hdd_reg_set_band(link_info->adapter->dev, band_bitmap); +} + +/** + * drv_cmd_set_fcc_channel() - Handle fcc constraint request + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: HDD context + * @command: command ptr, SET_FCC_CHANNEL 0/1/2/-1 is the command + * @command_len: command len + * @priv_data: private data + * + * Return: status + */ +static int drv_cmd_set_fcc_channel(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + QDF_STATUS status; + QDF_STATUS status_6G = QDF_STATUS_SUCCESS; + int8_t input_value; + int err; + uint32_t band_bitmap = 0, curr_band_bitmap; + bool rf_test_mode, fcc_constraint, dis_6g_keep_sta_cli_conn; + bool modify_band = false; + + /* + * This command would be called by user-space when it detects WLAN + * ON after airplane mode is set. When APM is set, WLAN turns off. + * But it can be turned back on. Otherwise; when APM is turned back + * off, WLAN would turn back on. So at that point the command is + * expected to come down. + * a) 0 means reduce power as per fcc constraint and disable 6 GHz band + * but keep existing STA/P2P Client connections intact. + * b) 1 means reduce power as per fcc constraint and enable 6 GHz band. + * c) 2 means reset fcc constraint but disable 6 GHz band but keep + * existing STA/P2P Client connections intact. + * d) -1 means reset fcc constraint and enable 6 GHz band. + */ + + err = kstrtos8(command + command_len + 1, 10, &input_value); + if (err) { + hdd_err("error %d parsing userspace fcc parameter", err); + return err; + } + + hdd_debug("input_value = %d", input_value); + + switch (input_value) { + case -1: + fcc_constraint = false; + dis_6g_keep_sta_cli_conn = false; + break; + case 0: + fcc_constraint = true; + dis_6g_keep_sta_cli_conn = true; + break; + case 1: + fcc_constraint = true; + dis_6g_keep_sta_cli_conn = false; + break; + case 2: + fcc_constraint = false; + dis_6g_keep_sta_cli_conn = true; + break; + default: + hdd_err("Invalie input value"); + return -EINVAL; + } + + status = ucfg_mlme_is_rf_test_mode_enabled(hdd_ctx->psoc, + &rf_test_mode); + if (!QDF_IS_STATUS_SUCCESS(status_6G)) { + hdd_err("Get rf test mode failed"); + return qdf_status_to_os_return(status); + } + + if (!rf_test_mode) { + status = ucfg_reg_get_band(hdd_ctx->pdev, &curr_band_bitmap); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to get band"); + return qdf_status_to_os_return(status); + } + + if (dis_6g_keep_sta_cli_conn) { + band_bitmap |= (BIT(REG_BAND_5G) | BIT(REG_BAND_2G)); + } else { + if (wlan_reg_is_6ghz_supported(hdd_ctx->psoc)) + band_bitmap = REG_BAND_MASK_ALL; + else + band_bitmap = curr_band_bitmap; + } + + hdd_debug("Current band bitmap = %d, set band bitmap = %d", + curr_band_bitmap, + band_bitmap); + + if (band_bitmap != curr_band_bitmap) + modify_band = true; + + if (ucfg_reg_is_fcc_constraint_set(hdd_ctx->pdev) == + fcc_constraint && + ucfg_reg_get_keep_6ghz_sta_cli_connection(hdd_ctx->pdev) == + dis_6g_keep_sta_cli_conn) { + hdd_debug("Same FCC constraint and band bitmap value"); + return 0; + } else if (modify_band) { + return hdd_apply_fcc_constraint_update_band(link_info, + hdd_ctx, + fcc_constraint, + dis_6g_keep_sta_cli_conn, + band_bitmap); + } + } else { + if (ucfg_reg_is_fcc_constraint_set(hdd_ctx->pdev) == + fcc_constraint) { + hdd_debug("Same FCC constraint value"); + return 0; + } + } + + return hdd_apply_fcc_constraint(hdd_ctx, fcc_constraint); +} + +/** + * hdd_parse_set_channel_switch_command() - Parse and validate CHANNEL_SWITCH + * command + * @value: Pointer to the command + * @chan_number: Pointer to the channel number + * @chan_bw: Pointer to the channel bandwidth + * + * Parses and provides the channel number and channel width from the input + * command which is expected to be of the format: CHANNEL_SWITCH + * is channel number to move (where 1 = channel 1, 149 = channel 149, ...) + * is bandwidth to move (where 20 = BW 20, 40 = BW 40, 80 = BW 80) + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_parse_set_channel_switch_command(uint8_t *value, + uint32_t *chan_number, + uint32_t *chan_bw) +{ + const uint8_t *in_ptr = value; + int ret; + + in_ptr = strnchr(value, strlen(value), SPACE_ASCII_VALUE); + + /* no argument after the command */ + if (!in_ptr) { + hdd_err("No argument after the command"); + return -EINVAL; + } + + /* no space after the command */ + if (SPACE_ASCII_VALUE != *in_ptr) { + hdd_err("No space after the command "); + return -EINVAL; + } + + /* remove empty spaces and move the next argument */ + while ((SPACE_ASCII_VALUE == *in_ptr) && ('\0' != *in_ptr)) + in_ptr++; + + /* no argument followed by spaces */ + if ('\0' == *in_ptr) { + hdd_err("No argument followed by spaces"); + return -EINVAL; + } + + /* get the two arguments: channel number and bandwidth */ + ret = sscanf(in_ptr, "%u %u", chan_number, chan_bw); + if (ret != 2) { + hdd_err("Arguments retrieval from cmd string failed"); + return -EINVAL; + } + + return 0; +} + +/** + * drv_cmd_set_channel_switch() - Switch SAP/P2P-GO operating channel + * @link_info: Link info pointer in HDD adapter + * @hdd_ctx: HDD context + * @command: Pointer to the input command CHANNEL_SWITCH + * @command_len: Command len + * @priv_data: Private data + * + * Handles private IOCTL CHANNEL_SWITCH command to switch the operating channel + * of SAP/P2P-GO + * + * Return: 0 for success, non-zero for failure + */ +static int drv_cmd_set_channel_switch(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct net_device *dev = adapter->dev; + int status; + uint32_t chan_number = 0, chan_bw = 0; + uint8_t *value = command; + enum phy_ch_width width; + + if ((adapter->device_mode != QDF_P2P_GO_MODE) && + (adapter->device_mode != QDF_SAP_MODE)) { + hdd_err("IOCTL CHANNEL_SWITCH not supported for mode %d", + adapter->device_mode); + return -EINVAL; + } + + if (!qdf_atomic_test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + hdd_err("SAP not started"); + return -EINVAL; + } + + status = hdd_parse_set_channel_switch_command(value, + &chan_number, &chan_bw); + if (status) { + hdd_err("Invalid CHANNEL_SWITCH command"); + return status; + } + + if ((chan_bw != 20) && (chan_bw != 40) && (chan_bw != 80) && + (chan_bw != 160)) { + hdd_err("BW %d is not allowed for CHANNEL_SWITCH", chan_bw); + return -EINVAL; + } + + if (chan_bw == 160) + width = CH_WIDTH_160MHZ; + else if (chan_bw == 80) + width = CH_WIDTH_80MHZ; + else if (chan_bw == 40) + width = CH_WIDTH_40MHZ; + else + width = CH_WIDTH_20MHZ; + + hdd_debug("CH:%d BW:%d", chan_number, chan_bw); + + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, link_info->vdev_id, + CSA_REASON_USER_INITIATED); + + if (chan_number <= wlan_reg_max_5ghz_ch_num()) + chan_number = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, + chan_number); + + status = hdd_softap_set_channel_change(dev, chan_number, width, false); + if (status) { + hdd_err("Set channel change fail"); + return status; + } + + return 0; +} + +#ifdef DISABLE_CHANNEL_LIST +void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + if (!hdd_ctx->original_channels) + return; + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + hdd_ctx->original_channels->num_channels = 0; + if (hdd_ctx->original_channels->channel_info) { + qdf_mem_free(hdd_ctx->original_channels->channel_info); + hdd_ctx->original_channels->channel_info = NULL; + } + qdf_mem_free(hdd_ctx->original_channels); + hdd_ctx->original_channels = NULL; + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + hdd_exit(); +} + +/** + * hdd_alloc_chan_cache() - Allocate the memory to cache the channel + * info for the channels received in command SET_DISABLE_CHANNEL_LIST + * @hdd_ctx: Pointer to HDD context + * @num_chan: Number of channels for which memory needs to + * be allocated + * + * Return: 0 on success and error code on failure + */ +static int hdd_alloc_chan_cache(struct hdd_context *hdd_ctx, int num_chan) +{ + hdd_ctx->original_channels = + qdf_mem_malloc(sizeof(struct hdd_cache_channels)); + if (!hdd_ctx->original_channels) + return -ENOMEM; + + hdd_ctx->original_channels->num_channels = num_chan; + hdd_ctx->original_channels->channel_info = + qdf_mem_malloc(num_chan * + sizeof(struct hdd_cache_channel_info)); + if (!hdd_ctx->original_channels->channel_info) { + hdd_ctx->original_channels->num_channels = 0; + qdf_mem_free(hdd_ctx->original_channels); + hdd_ctx->original_channels = NULL; + return -ENOMEM; + } + return 0; +} + +/** + * check_disable_channels() - Check for disable channel + * @hdd_ctx: Pointer to hdd context + * @operating_freq: Current operating frequency of adapter + * + * This function checks original_channels array for a specific channel + * + * Return: 0 if channel not found, 1 if channel found + */ +static bool check_disable_channels(struct hdd_context *hdd_ctx, + qdf_freq_t operating_freq) +{ + uint32_t num_channels; + uint8_t i; + if (!hdd_ctx || !hdd_ctx->original_channels || + !hdd_ctx->original_channels->channel_info) + return false; + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + num_channels = hdd_ctx->original_channels->num_channels; + for (i = 0; i < num_channels; i++) { + if (operating_freq == + hdd_ctx->original_channels->channel_info[i].freq) { + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + return true; + } + } + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + return false; +} + +/** + * disconnect_sta_and_restart_sap() - Disconnect STA and restart SAP + * + * @hdd_ctx: Pointer to hdd context + * @reason: Disconnect reason code as per @enum wlan_reason_code + * + * Disable channels provided by user and disconnect STA if it is + * connected to any AP, restart SAP. + * + * Return: None + */ +static void disconnect_sta_and_restart_sap(struct hdd_context *hdd_ctx, + enum wlan_reason_code reason) +{ + struct hdd_adapter *adapter, *next = NULL; + QDF_STATUS status; + struct hdd_ap_ctx *ap_ctx; + uint32_t ch_list[NUM_CHANNELS]; + uint32_t ch_count = 0; + bool is_valid_chan_present = true; + + if (!hdd_ctx) + return; + + hdd_check_and_disconnect_sta_on_invalid_channel(hdd_ctx, reason); + + status = policy_mgr_get_valid_chans(hdd_ctx->psoc, ch_list, &ch_count); + if (QDF_IS_STATUS_ERROR(status) || !ch_count) { + hdd_debug("No valid channels present, stop the SAPs"); + is_valid_chan_present = false; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapter); + while (adapter && (status == QDF_STATUS_SUCCESS)) { + if (hdd_validate_adapter(adapter) || + adapter->device_mode != QDF_SAP_MODE) { + goto next_adapter; + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + if (!is_valid_chan_present) + wlan_hdd_stop_sap(adapter); + else if (check_disable_channels(hdd_ctx, + ap_ctx->operating_chan_freq)) + policy_mgr_check_sap_restart(hdd_ctx->psoc, + adapter->deflink->vdev_id); +next_adapter: + status = hdd_get_next_adapter(hdd_ctx, adapter, &next); + adapter = next; + } +} + +/** + * hdd_check_chan_and_fill_freq() - to validate chan and convert into freq + * @pdev: The physical dev to cache the channels for + * @in_chan: input as channel number or freq + * @freq: frequency for input in_chan (output parameter) + * + * This function checks input "in_chan" is channel number, if yes then fills + * appropriate frequency into "freq" out param. If the "in_param" is greater + * than MAX_5GHZ_CHANNEL then gets the valid frequencies for legacy channels + * else get the valid channel for 6Ghz frequency. + * + * Return: true if "in_chan" is valid channel/frequency; false otherwise + */ +static bool hdd_check_chan_and_fill_freq(struct wlan_objmgr_pdev *pdev, + uint32_t *in_chan, qdf_freq_t *freq) +{ + if (IS_CHANNEL_VALID(*in_chan)) { + *freq = wlan_reg_legacy_chan_to_freq(pdev, *in_chan); + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(*in_chan) || + WLAN_REG_IS_5GHZ_CH_FREQ(*in_chan) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(*in_chan)) { + *freq = *in_chan; + *in_chan = wlan_reg_freq_to_chan(pdev, *in_chan); + } else { + return false; + } + + return true; +} + +/** + * hdd_parse_disable_chan_cmd() - Parse the channel list received + * in command. + * @adapter: pointer to hdd adapter + * @ptr: Pointer to the command string + * + * This function parses the channel list/frequency received in the command. + * command should be a string having format + * SET_DISABLE_CHANNEL_LIST + * /. + * If this command has frequency as input, this function first converts into + * equivalent channel. + * If the command comes multiple times then the channels received in the + * command or channels converted from frequency will be compared with the + * channels cached in the first command, if the channel list matches with + * the cached channels, it returns success otherwise returns failure. + * + * Return: 0 on success, Error code on failure + */ + +static int hdd_parse_disable_chan_cmd(struct hdd_adapter *adapter, uint8_t *ptr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t *param; + int j, i, temp_int, ret = 0, num_channels; + qdf_freq_t *chan_freq_list = NULL; + bool is_command_repeated = false; + qdf_freq_t freq = 0; + + if (!hdd_ctx) { + hdd_err("HDD Context is NULL"); + return -EINVAL; + } + + param = strnchr(ptr, strlen(ptr), ' '); + /*no argument after the command*/ + if (!param) + return -EINVAL; + + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *param) + return -EINVAL; + + param++; + + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + /*no argument followed by spaces*/ + if ('\0' == *param) + return -EINVAL; + + /*getting the first argument ie the number of channels*/ + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("Cannot get number of channels from input"); + return -EINVAL; + } + + if (temp_int < 0 || temp_int > NUM_CHANNELS) { + hdd_err("Invalid Number of channel received"); + return -EINVAL; + } + + hdd_debug("Number of channel to disable are: %d", temp_int); + + if (!temp_int) { + /* + * Restore and Free the cache channels when the command is + * received with num channels as 0 + */ + wlan_hdd_restore_channels(hdd_ctx); + return 0; + } + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + + if (!hdd_ctx->original_channels) { + if (hdd_alloc_chan_cache(hdd_ctx, temp_int)) { + ret = -ENOMEM; + goto mem_alloc_failed; + } + } else if (hdd_ctx->original_channels->num_channels != temp_int) { + hdd_err("Invalid Number of channels"); + ret = -EINVAL; + is_command_repeated = true; + goto parse_failed; + } else { + is_command_repeated = true; + } + num_channels = temp_int; + + chan_freq_list = qdf_mem_malloc(num_channels * sizeof(qdf_freq_t)); + if (!chan_freq_list) + return -ENOMEM; + + for (j = 0; j < num_channels; j++) { + /* + * param pointing to the beginning of first space + * after number of channels + */ + param = strpbrk(param, " "); + /*no channel list after the number of channels argument*/ + if (!param) { + hdd_err("Invalid No of channel provided in the list"); + ret = -EINVAL; + goto parse_failed; + } + + param++; + + /*removing empty space*/ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + if ('\0' == *param) { + hdd_err("No channel is provided in the list"); + ret = -EINVAL; + goto parse_failed; + } + + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("Cannot read channel number"); + ret = -EINVAL; + goto parse_failed; + } + + if (!hdd_check_chan_and_fill_freq(hdd_ctx->pdev, &temp_int, + &freq)) { + hdd_err("Invalid channel number received"); + ret = -EINVAL; + goto parse_failed; + } + + hdd_debug("channel[%d] = %d Frequency[%d] = %d", j, temp_int, + j, freq); + chan_freq_list[j] = freq; + } + + /*extra arguments check*/ + param = strpbrk(param, " "); + if (param) { + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + if ('\0' != *param) { + hdd_err("Invalid argument received"); + ret = -EINVAL; + goto parse_failed; + } + } + + /* + * If command is received first time, cache the channels to + * be disabled else compare the channels received in the + * command with the cached channels, if channel list matches + * return success otherwise return failure. + */ + if (!is_command_repeated) { + for (j = 0; j < num_channels; j++) + hdd_ctx->original_channels->channel_info[j].freq = + chan_freq_list[j]; + + /* Cache the channel list in regulatory also */ + ucfg_reg_cache_channel_freq_state(hdd_ctx->pdev, + chan_freq_list, + num_channels); + } else { + for (i = 0; i < num_channels; i++) { + for (j = 0; j < num_channels; j++) + if (hdd_ctx->original_channels-> + channel_info[i].freq == + chan_freq_list[j]) + break; + if (j == num_channels) { + ret = -EINVAL; + goto parse_failed; + } + } + ret = 0; + } +mem_alloc_failed: + if (chan_freq_list) + qdf_mem_free(chan_freq_list); + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + /* Disable the channels received in command SET_DISABLE_CHANNEL_LIST */ + if (!is_command_repeated && hdd_ctx->original_channels) { + ret = wlan_hdd_disable_channels(hdd_ctx); + if (ret) + return ret; + disconnect_sta_and_restart_sap( + hdd_ctx, + REASON_OPER_CHANNEL_BAND_CHANGE); + } + + hdd_exit(); + + return ret; + +parse_failed: + if (!is_command_repeated) + wlan_hdd_free_cache_channels(hdd_ctx); + + if (chan_freq_list) + qdf_mem_free(chan_freq_list); + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + hdd_exit(); + + return ret; +} + +static int drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return hdd_parse_disable_chan_cmd(link_info->adapter, command); +} + +/** + * hdd_get_disable_ch_list() - get disable channel list + * @hdd_ctx: hdd context + * @buf: buffer to hold disable channel list + * @buf_len: buffer length + * + * Return: length of data copied to buf + */ +static int hdd_get_disable_ch_list(struct hdd_context *hdd_ctx, uint8_t *buf, + uint32_t buf_len) +{ + struct hdd_cache_channel_info *ch_list; + unsigned char i, num_ch; + int len = 0; + + qdf_mutex_acquire(&hdd_ctx->cache_channel_lock); + if (hdd_ctx->original_channels && + hdd_ctx->original_channels->num_channels && + hdd_ctx->original_channels->channel_info) { + num_ch = hdd_ctx->original_channels->num_channels; + + len = scnprintf(buf, buf_len, "%s %hhu", + "GET_DISABLE_CHANNEL_LIST", num_ch); + ch_list = hdd_ctx->original_channels->channel_info; + for (i = 0; (i < num_ch) && (len < buf_len - 1); i++) { + len += scnprintf(buf + len, buf_len - len, + " %d", + wlan_reg_freq_to_chan(hdd_ctx->pdev, + ch_list[i].freq)); + } + } + qdf_mutex_release(&hdd_ctx->cache_channel_lock); + + return len; +} + +static int drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + char extra[512] = {0}; + int max_len, copied_length; + + hdd_debug("Received Command to get disable Channels list"); + + max_len = QDF_MIN(priv_data->total_len, sizeof(extra)); + copied_length = hdd_get_disable_ch_list(hdd_ctx, extra, max_len); + if (copied_length == 0) { + hdd_err("disable channel list is not yet programmed"); + return -EINVAL; + } + + if (copy_to_user(priv_data->buf, &extra, copied_length + 1)) { + hdd_err("failed to copy data to user buffer"); + return -EFAULT; + } + + hdd_debug("data:%s", extra); + return 0; +} +#else + +static inline int +drv_cmd_set_disable_chan_list(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return 0; +} + +void wlan_hdd_free_cache_channels(struct hdd_context *hdd_ctx) +{ +} + +static inline int +drv_cmd_get_disable_chan_list(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return 0; +} +#endif + +#ifdef FEATURE_ANI_LEVEL_REQUEST +static int drv_cmd_get_ani_level(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + struct hdd_adapter *adapter = link_info->adapter; + char *extra; + int copied_length = 0, j, temp_int, ret = 0; + uint8_t *param, num_freqs, num_recv_channels; + uint32_t parsed_freqs[MAX_NUM_FREQS_FOR_ANI_LEVEL]; + struct wmi_host_ani_level_event ani[MAX_NUM_FREQS_FOR_ANI_LEVEL]; + size_t user_size = priv_data->total_len; + + hdd_debug("Received Command to get ANI level"); + + param = strnchr(command, strlen(command), ' '); + + /* No argument after the command */ + if (!param) + return -EINVAL; + + /* No space after the command */ + else if (SPACE_ASCII_VALUE != *param) + return -EINVAL; + + param++; + + /* Removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + /*no argument followed by spaces */ + if ('\0' == *param) + return -EINVAL; + + /* Getting the first argument ie the number of channels */ + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("Cannot get number of freq from input"); + return -EINVAL; + } + + if (temp_int < 0 || temp_int > MAX_NUM_FREQS_FOR_ANI_LEVEL) { + hdd_err("Invalid Number of channel received"); + return -EINVAL; + } + + hdd_debug("Number of freq to fetch ANI level are: %d", temp_int); + + if (!temp_int) + return 0; + + num_freqs = temp_int; + + for (j = 0; j < num_freqs; j++) { + /* + * Param pointing to the beginning of first space + * after number of channels. + */ + param = strpbrk(param, " "); + /*no channel list after the number of channels argument*/ + if (!param) { + hdd_err("Invalid No of freq provided in the list"); + ret = -EINVAL; + goto parse_failed; + } + + param++; + + /* Removing empty space */ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + if ('\0' == *param) { + hdd_err("No freq is provided in the list"); + ret = -EINVAL; + goto parse_failed; + } + + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("Cannot read freq number"); + ret = -EINVAL; + goto parse_failed; + } + + hdd_debug("channel_freq[%d] = %d", j, temp_int); + parsed_freqs[j] = temp_int; + } + + /* Extra arguments check */ + param = strpbrk(param, " "); + if (param) { + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + if ('\0' != *param) { + hdd_err("Invalid argument received"); + ret = -EINVAL; + goto parse_failed; + } + } + + qdf_mem_zero(ani, sizeof(ani)); + hdd_debug("num_freq: %d", num_freqs); + if (QDF_IS_STATUS_ERROR(wlan_hdd_get_ani_level(adapter, ani, + parsed_freqs, + num_freqs))) { + hdd_err("Unable to retrieve ani level"); + return -EINVAL; + } + + extra = qdf_mem_malloc(user_size); + if (!extra) { + ret = -ENOMEM; + goto parse_failed; + } + + /* + * Find the number of channels that are populated. If freq is not + * filled then stop count there + */ + for (num_recv_channels = 0; + (num_recv_channels < num_freqs && + ani[num_recv_channels].chan_freq); num_recv_channels++) + ; + + for (j = 0; j < num_recv_channels; j++) { + /* Sanity check for ANI level validity */ + if (ani[j].ani_level > MAX_ANI_LEVEL) + continue; + + copied_length += scnprintf(extra + copied_length, + user_size - copied_length, "%d:%d\n", + ani[j].chan_freq, ani[j].ani_level); + } + + if (copied_length == 0) { + hdd_err("ANI level not fetched"); + ret = -EINVAL; + goto free; + } + + hdd_debug("data: %s", extra); + + if (copy_to_user(priv_data->buf, extra, copied_length + 1)) { + hdd_err("failed to copy data to user buffer"); + ret = -EFAULT; + goto free; + } + +free: + qdf_mem_free(extra); + +parse_failed: + return ret; +} + +#else +static inline int drv_cmd_get_ani_level(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + return 0; +} +#endif + +#ifdef FUNC_CALL_MAP +static int drv_cmd_get_function_call_map(struct wlan_hdd_link_info *link_info, + struct hdd_context *hdd_ctx, + uint8_t *command, + uint8_t command_len, + struct hdd_priv_data *priv_data) +{ + char *cc_buf = qdf_mem_malloc(QDF_FUNCTION_CALL_MAP_BUF_LEN); + uint8_t *param; + int temp_int; + + param = strnchr(command, strlen(command), ' '); + /*no argument after the command*/ + if (NULL == param) + return -EINVAL; + + /*no space after the command*/ + else if (SPACE_ASCII_VALUE != *param) + return -EINVAL; + + param++; + + /*removing empty spaces*/ + while ((SPACE_ASCII_VALUE == *param) && ('\0' != *param)) + param++; + + /*no argument followed by spaces*/ + if ('\0' == *param) + return -EINVAL; + + /*getting the first argument */ + if (sscanf(param, "%d ", &temp_int) != 1) { + hdd_err("No option given"); + return -EINVAL; + } + + if (temp_int < 0 || temp_int > 1) { + hdd_err("Invalid option given"); + return -EINVAL; + } + + /* Read the buffer */ + if (temp_int) { + /* + * These logs are required as these indicates the start and end of the + * dump for the auto script to parse + */ + hdd_info("Function call map dump start"); + qdf_get_func_call_map(cc_buf); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + cc_buf, QDF_FUNCTION_CALL_MAP_BUF_LEN); + hdd_info("Function call map dump end"); + } else { + qdf_clear_func_call_map(); + hdd_info("Function call map clear"); + } + qdf_mem_free(cc_buf); + + return 0; +} +#endif + +/* + * The following table contains all supported WLAN HDD + * IOCTL driver commands and the handler for each of them. + */ +static const struct hdd_drv_cmd hdd_drv_cmds[] = { + {"P2P_DEV_ADDR", drv_cmd_p2p_dev_addr, false}, + {"P2P_SET_NOA", drv_cmd_p2p_set_noa, true}, + {"P2P_SET_PS", drv_cmd_p2p_set_ps, true}, + {"SETBAND", drv_cmd_set_band, true}, + {"SETWMMPS", drv_cmd_set_wmmps, true}, + {"COUNTRY", drv_cmd_country, true}, + {"SETCOUNTRYREV", drv_cmd_country, true}, + {"GETCOUNTRYREV", drv_cmd_get_country, false}, + {"SETSUSPENDMODE", drv_cmd_set_suspend_mode, true}, + {"SET_AP_WPS_P2P_IE", drv_cmd_dummy, false}, + {"SETROAMTRIGGER", drv_cmd_set_roam_trigger, true}, + {"GETROAMTRIGGER", drv_cmd_get_roam_trigger, false}, + {"SETROAMSCANPERIOD", drv_cmd_set_roam_scan_period, true}, + {"GETROAMSCANPERIOD", drv_cmd_get_roam_scan_period, false}, + {"SETROAMSCANREFRESHPERIOD", drv_cmd_set_roam_scan_refresh_period, + true}, + {"GETROAMSCANREFRESHPERIOD", drv_cmd_get_roam_scan_refresh_period, + false}, + {"SETROAMMODE", drv_cmd_set_roam_mode, true}, + {"GETROAMMODE", drv_cmd_get_roam_mode, false}, + {"SETROAMDELTA", drv_cmd_set_roam_delta, true}, + {"GETROAMDELTA", drv_cmd_get_roam_delta, false}, + {"GETBAND", drv_cmd_get_band, false}, + {"GETCCXMODE", drv_cmd_get_ccx_mode, false}, + {"GETOKCMODE", drv_cmd_get_okc_mode, false}, + {"GETFASTROAM", drv_cmd_get_fast_roam, false}, + {"GETFASTTRANSITION", drv_cmd_get_fast_transition, false}, + {"SETROAMSCANCHANNELMINTIME", drv_cmd_set_roam_scan_channel_min_time, + true}, + {"SENDACTIONFRAME", drv_cmd_send_action_frame, true}, + {"GETROAMSCANCHANNELMINTIME", drv_cmd_get_roam_scan_channel_min_time, + false}, + {"SETSCANCHANNELTIME", drv_cmd_set_scan_channel_time, true}, + {"GETSCANCHANNELTIME", drv_cmd_get_scan_channel_time, false}, + {"SETSCANHOMETIME", drv_cmd_set_scan_home_time, true}, + {"GETSCANHOMETIME", drv_cmd_get_scan_home_time, false}, + {"SETROAMINTRABAND", drv_cmd_set_roam_intra_band, true}, + {"GETROAMINTRABAND", drv_cmd_get_roam_intra_band, false}, + {"SETSCANNPROBES", drv_cmd_set_scan_n_probes, true}, + {"GETSCANNPROBES", drv_cmd_get_scan_n_probes, false}, + {"SETSCANHOMEAWAYTIME", drv_cmd_set_scan_home_away_time, true}, + {"GETSCANHOMEAWAYTIME", drv_cmd_get_scan_home_away_time, false}, + {"REASSOC", drv_cmd_reassoc, true}, + {"SETWESMODE", drv_cmd_set_wes_mode, true}, + {"GETWESMODE", drv_cmd_get_wes_mode, false}, + {"SETOPPORTUNISTICRSSIDIFF", drv_cmd_set_opportunistic_rssi_diff, + true}, + {"GETOPPORTUNISTICRSSIDIFF", drv_cmd_get_opportunistic_rssi_diff, + false}, + {"SETROAMRESCANRSSIDIFF", drv_cmd_set_roam_rescan_rssi_diff, true}, + {"GETROAMRESCANRSSIDIFF", drv_cmd_get_roam_rescan_rssi_diff, false}, + {"SETFASTROAM", drv_cmd_set_fast_roam, true}, + {"SETFASTTRANSITION", drv_cmd_set_fast_transition, true}, + {"FASTREASSOC", drv_cmd_fast_reassoc, true}, + {"SETOKCMODE", drv_cmd_set_okc_mode, true}, + {"BTCOEXMODE", drv_cmd_bt_coex_mode, true}, + {"SCAN-ACTIVE", drv_cmd_scan_active, false}, + {"SCAN-PASSIVE", drv_cmd_scan_passive, false}, + {"CONCSETDWELLTIME", drv_cmd_conc_set_dwell_time, true}, + {"GETDWELLTIME", drv_cmd_get_dwell_time, false}, + {"SETDWELLTIME", drv_cmd_set_dwell_time, true}, + {"MIRACAST", drv_cmd_miracast, true}, + {"TPUT_DEBUG_MODE_ENABLE", drv_cmd_tput_debug_mode_enable, false}, + {"TPUT_DEBUG_MODE_DISABLE", drv_cmd_tput_debug_mode_disable, false}, +#ifdef FEATURE_WLAN_ESE + {"SETCCXROAMSCANCHANNELS", drv_cmd_set_ccx_roam_scan_channels, true}, + {"GETTSMSTATS", drv_cmd_get_tsm_stats, true}, + {"SETCCKMIE", drv_cmd_set_cckm_ie, true}, + {"CCXBEACONREQ", drv_cmd_ccx_beacon_req, true}, + {"CCXPLMREQ", drv_cmd_ccx_plm_req, true}, + {"SETCCXMODE", drv_cmd_set_ccx_mode, true}, +#endif /* FEATURE_WLAN_ESE */ + {"SETMCRATE", drv_cmd_set_mc_rate, true}, + {"MAXTXPOWER", drv_cmd_max_tx_power, true}, + {"SETDFSSCANMODE", drv_cmd_set_dfs_scan_mode, true}, + {"GETDFSSCANMODE", drv_cmd_get_dfs_scan_mode, false}, + {"GETLINKSTATUS", drv_cmd_get_link_status, false}, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + {"ENABLEEXTWOW", drv_cmd_enable_ext_wow, true}, + {"SETAPP1PARAMS", drv_cmd_set_app1_params, true}, + {"SETAPP2PARAMS", drv_cmd_set_app2_params, true}, +#endif +#ifdef FEATURE_WLAN_TDLS + {"TDLSSECONDARYCHANNELOFFSET", drv_cmd_tdls_secondary_channel_offset, + true}, + {"TDLSOFFCHANNELMODE", drv_cmd_tdls_off_channel_mode, true}, + {"TDLSOFFCHANNEL", drv_cmd_tdls_off_channel, true}, + {"TDLSSCAN", drv_cmd_tdls_scan, true}, +#endif + {"RSSI", drv_cmd_get_rssi, false}, + {"LINKSPEED", drv_cmd_get_linkspeed, false}, +#ifdef WLAN_FEATURE_PACKET_FILTERING + {"RXFILTER-REMOVE", drv_cmd_rx_filter_remove, true}, + {"RXFILTER-ADD", drv_cmd_rx_filter_add, true}, +#endif + {"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel, true}, + {"CHANNEL_SWITCH", drv_cmd_set_channel_switch, true}, + {"SETANTENNAMODE", drv_cmd_set_antenna_mode, true}, + {"GETANTENNAMODE", drv_cmd_get_antenna_mode, false}, + {"SET_DISABLE_CHANNEL_LIST", drv_cmd_set_disable_chan_list, true}, + {"GET_DISABLE_CHANNEL_LIST", drv_cmd_get_disable_chan_list, false}, + {"GET_ANI_LEVEL", drv_cmd_get_ani_level, false}, +#ifdef FUNC_CALL_MAP + {"GET_FUNCTION_CALL_MAP", drv_cmd_get_function_call_map, true}, +#endif + {"STOP", drv_cmd_dummy, false}, + /* Deprecated commands */ + {"RXFILTER-START", drv_cmd_dummy, false}, + {"RXFILTER-STOP", drv_cmd_dummy, false}, + {"BTCOEXSCAN-START", drv_cmd_dummy, false}, + {"BTCOEXSCAN-STOP", drv_cmd_dummy, false}, + {"GET_SOFTAP_LINK_SPEED", drv_cmd_get_sap_go_linkspeed, true}, +#ifdef CONFIG_BAND_6GHZ + {"GET_WIFI6E_CHANNELS", drv_cmd_get_wifi6e_channels, true}, +#endif +}; + +/** + * hdd_drv_cmd_process() - chooses and runs the proper + * handler based on the input command + * @link_info: Link info pointer in adapter. + * @cmd: Pointer to the driver command + * @priv_data: Pointer to the data associated with the command + * + * This function parses the input hdd driver command and runs + * the proper handler + * + * Return: 0 for success non-zero for failure + */ +static int hdd_drv_cmd_process(struct wlan_hdd_link_info *link_info, + uint8_t *cmd, struct hdd_priv_data *priv_data) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx; + int i; + const int cmd_num_total = ARRAY_SIZE(hdd_drv_cmds); + uint8_t *cmd_i = NULL; + hdd_drv_cmd_handler_t handler = NULL; + int len = 0, cmd_len = 0; + uint8_t *ptr; + bool args; + + if (!cmd || !priv_data) { + hdd_err("at least 1 param is NULL"); + return -EINVAL; + } + + /* Calculate length of the first word */ + ptr = strchrnul(cmd, ' '); + cmd_len = ptr - cmd; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + for (i = 0; i < cmd_num_total; i++) { + + cmd_i = (uint8_t *)hdd_drv_cmds[i].cmd; + handler = hdd_drv_cmds[i].handler; + len = strlen(cmd_i); + args = hdd_drv_cmds[i].args; + + if (!handler) { + hdd_err("no. %d handler is NULL", i); + return -EINVAL; + } + + if (len == cmd_len && strncasecmp(cmd, cmd_i, len) == 0) { + if (args && drv_cmd_validate(cmd, len)) + return -EINVAL; + + return handler(link_info, hdd_ctx, + cmd, len, priv_data); + } + } + + return drv_cmd_invalid(adapter, hdd_ctx, cmd, len, priv_data); +} + +/** + * hdd_driver_command() - top level wlan hdd driver command handler + * @link_info: Link info pointer in HDD adapter + * @priv_data: Pointer to the raw command data + * + * This function is the top level wlan hdd driver command handler. It + * handles the command with the help of hdd_drv_cmd_process() + * + * Return: 0 for success non-zero for failure + */ +static int hdd_driver_command(struct wlan_hdd_link_info *link_info, + struct hdd_priv_data *priv_data) +{ + struct hdd_adapter *adapter = link_info->adapter; + uint8_t *command = NULL; + int ret = 0; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; command can not be processed"); + return -EINVAL; + } + + /* + * Note that valid pointers are provided by caller + */ + + /* copy to local struct to avoid numerous changes to legacy code */ + if (priv_data->total_len <= 0 || + priv_data->total_len > WLAN_PRIV_DATA_MAX_LEN) { + hdd_warn("Invalid priv_data.total_len: %d!!!", + priv_data->total_len); + ret = -EINVAL; + goto exit; + } + + /* Allocate +1 for '\0' */ + command = qdf_mem_malloc(priv_data->total_len + 1); + if (!command) { + ret = -ENOMEM; + goto exit; + } + + if (copy_from_user(command, priv_data->buf, priv_data->total_len)) { + ret = -EFAULT; + goto exit; + } + + /* Make sure the command is NUL-terminated */ + command[priv_data->total_len] = '\0'; + + hdd_debug("%s: %s", adapter->dev->name, command); + ret = hdd_drv_cmd_process(link_info, command, priv_data); + +exit: + if (command) + qdf_mem_free(command); + hdd_exit(); + return ret; +} + +#ifdef CONFIG_COMPAT +static int hdd_driver_compat_ioctl(struct wlan_hdd_link_info *link_info, + void __user *data) +{ + struct { + compat_uptr_t buf; + int used_len; + int total_len; + } compat_priv_data; + struct hdd_priv_data priv_data; + int ret = 0; + + /* + * Note that adapter and ifr have already been verified by caller, + * and HDD context has also been validated + */ + if (copy_from_user(&compat_priv_data, data, + sizeof(compat_priv_data))) { + ret = -EFAULT; + goto exit; + } + priv_data.buf = compat_ptr(compat_priv_data.buf); + priv_data.used_len = compat_priv_data.used_len; + priv_data.total_len = compat_priv_data.total_len; + ret = hdd_driver_command(link_info, &priv_data); +exit: + return ret; +} +#else /* CONFIG_COMPAT */ +static inline int hdd_driver_compat_ioctl(struct wlan_hdd_link_info *link_info, + void __user *data) +{ + /* will never be invoked */ + return 0; +} +#endif /* CONFIG_COMPAT */ + +static int hdd_driver_ioctl(struct wlan_hdd_link_info *link_info, + void __user *data) +{ + struct hdd_priv_data priv_data; + int ret = 0; + + /* + * Note that adapter and ifr have already been verified by caller, + * and HDD context has also been validated + */ + if (copy_from_user(&priv_data, data, sizeof(priv_data))) + ret = -EFAULT; + else + ret = hdd_driver_command(link_info, &priv_data); + + return ret; +} + +/** + * __hdd_ioctl() - ioctl handler for wlan network interfaces + * @dev: device upon which the ioctl was received + * @data: pointer to the raw command data in the ioctl request + * @cmd: ioctl command + * + * This function does initial processing of wlan device ioctls. + * Currently two flavors of ioctls are supported. The primary ioctl + * that is supported is the (SIOCDEVPRIVATE + 1) ioctl which is used + * for Android "DRIVER" commands. The other ioctl that is + * conditionally supported is the SIOCIOCTLTX99 ioctl which is used + * for FTM on some platforms. This function simply verifies that the + * driver is in a sane state, and that the ioctl is one of the + * supported flavors, in which case flavor-specific handlers are + * dispatched. + * + * Return: 0 on success, non-zero on error + */ +static int __hdd_ioctl(struct net_device *dev, void __user *data, int cmd) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + if (dev != adapter->dev) { + hdd_err("HDD adapter/dev inconsistency"); + ret = -ENODEV; + goto exit; + } + + if (!data) { + hdd_err("invalid data cmd: %d", cmd); + ret = -EINVAL; + goto exit; + } +#if defined(QCA_WIFI_FTM) && defined(LINUX_QCMBR) + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + if (SIOCIOCTLTX99 == cmd) { + ret = wlan_hdd_qcmbr_unified_ioctl(adapter, data); + goto exit; + } + } +#endif + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + goto exit; + + switch (cmd) { + case (SIOCDEVPRIVATE + 1): + if (in_compat_syscall()) + ret = hdd_driver_compat_ioctl(adapter->deflink, data); + else + ret = hdd_driver_ioctl(adapter->deflink, data); + break; + default: + hdd_warn("unknown ioctl %d", cmd); + ret = -EINVAL; + break; + } +exit: + hdd_exit(); + return ret; +} + +int hdd_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_ioctl(net_dev, ifr->ifr_data, cmd); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int hdd_dev_private_ioctl(struct net_device *dev, struct ifreq *ifr, + void __user *data, int cmd) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_ioctl(dev, data, cmd); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h new file mode 100644 index 0000000000..3aac522bec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ioctl.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2012-2014, 2017-2019, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_IOCTL_H) +#define WLAN_HDD_IOCTL_H + +#include +#include +#include "wlan_hdd_main.h" + +extern struct sock *cesium_nl_srv_sock; + +/** + * hdd_ioctl() - ioctl handler (wrapper) for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @cmd: ioctl command + * + * This function acts as an SSR-protecting wrapper to __hdd_ioctl() + * which is where the ioctls are really handled. + * + * Return: 0 on success, non-zero on error + */ +int hdd_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); + +/** + * hdd_dev_private_ioctl() - private ioctl handler for wlan network interfaces + * @dev: device upon which the ioctl was received + * @ifr: ioctl request information + * @data: pointer to the raw command data in the ioctl request + * @cmd: ioctl command + * + * For Kernel 5.15+, this function acts as an SSR-protecting wrapper + * to __hdd_ioctl(), which is where the ioctls are really handled. + * + * Return: 0 on success, non-zero on error + */ +int hdd_dev_private_ioctl(struct net_device *dev, struct ifreq *ifr, + void __user *data, int cmd); + +/** + * wlan_hdd_set_mc_rate() - Function to set MC rate. + * @link_info: Link info pointer in HDD adapter + * @target_rate: Target rate to set. + * + * The API sets the value in @target_rate for MC Tx + * + * Return: Non-zero value on failure. + */ +int wlan_hdd_set_mc_rate(struct wlan_hdd_link_info *link_info, int target_rate); + +/** + * hdd_update_smps_antenna_mode() - set smps and antenna mode + * @hdd_ctx: Pointer to hdd context + * @mode: antenna mode + * + * This function will set smps and antenna mode. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_update_smps_antenna_mode(struct hdd_context *hdd_ctx, int mode); + +/** + * hdd_set_antenna_mode() - SET ANTENNA MODE command handler + * @link_info: Link info pointer in HDD adapter + * @mode: new antenna mode + */ +int hdd_set_antenna_mode(struct wlan_hdd_link_info *link_info, int mode); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * hdd_get_roam_scan_ch_cb() - roam scan channel list callback handler + * @hdd_handle: Pointer to hdd context + * @roam_ch: pointer to roam scan ch event data + * @context: cookie + * + * Callback function to processes roam scan chaanel list event. If + * command response field in the response message is set that means + * event received as a response of GETROAMSCANCHANNELS command else + * event was raised by firmware upon disconnection. + * + * Return: none + */ +void hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle, + struct roam_scan_ch_resp *roam_ch, + void *context); + +/** + * hdd_get_roam_scan_freq() - roam scan freq list + * @adapter: Pointer to hdd adapter + * @mac_handle: pointer to mac_handle + * @chan_list: Pointer to hold roam scan freq list + * @num_channels: Pointer to hold num of roam scan channels in list + * + * This function gets roam scan frequencies from FW if FW is capable else + * roam scan frequencies are taken from host maintained list. + * + * Return: 0 on success else error value + */ +int +hdd_get_roam_scan_freq(struct hdd_adapter *adapter, mac_handle_t mac_handle, + uint32_t *chan_list, uint8_t *num_channels); +#else +static inline void +hdd_get_roam_scan_ch_cb(hdd_handle_t hdd_handle, + void *roam_ch, + void *context) +{ +} + +static inline int +hdd_get_roam_scan_freq(struct hdd_adapter *adapter, mac_handle_t mac_handle, + uint32_t *chan_list, uint8_t *num_channels) +{ + return -EFAULT; +} +#endif + +/** + * hdd_ioctl_log_buffer() - dump log buffer of a type + * @log_id: id of what log type to be + * @count: number of lines to be copied + * @custom_print: custom print function pointer + * @print_ctx: print context for custom print function + * + * If custom print function is NULL, will default to printk + * + * Return: None + */ +void hdd_ioctl_log_buffer(int log_id, uint32_t count, qdf_abstract_print + *custom_print, + void *print_ctx); +#ifdef WLAN_DUMP_LOG_BUF_CNT +/** + * hdd_dump_log_buffer() - dump log buffer history + * @print_ctx: print context for custom print function + * @custom_print: custom print function pointer + * + * If custom print function is NULL, will default to printk + * + * Return: None + */ +void hdd_dump_log_buffer(void *print_ctx, qdf_abstract_print *custom_print); + +#else +static inline +void hdd_dump_log_buffer(void *print_ctx, qdf_abstract_print *custom_print) +{ +} + +#endif +#endif /* end #if !defined(WLAN_HDD_IOCTL_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c new file mode 100644 index 0000000000..3fe027f394 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ipa.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_ipa.c + * + * WLAN HDD and ipa interface implementation + */ + +/* Include Files */ +#include +#include +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_ipa_ucfg_api.h" +#include +#include +#include +/* Test against msm kernel version */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) && \ + IS_ENABLED(CONFIG_SCHED_WALT) +#include +#endif +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" + +#ifdef IPA_OFFLOAD + +/** + * struct hdd_ipa_connection_info - connectio info for IPA component + * @vdev_id: vdev id + * @ch_freq: channel frequency + * @ch_width: channel width + * @wlan_80211_mode: enum qca_wlan_802_11_mode + */ +struct hdd_ipa_connection_info { + uint8_t vdev_id; + qdf_freq_t ch_freq; + enum phy_ch_width ch_width; + enum qca_wlan_802_11_mode wlan_80211_mode; +}; + +#if (defined(QCA_CONFIG_SMP) && defined(PF_WAKE_UP_IDLE)) ||\ + IS_ENABLED(CONFIG_SCHED_WALT) +/** + * hdd_ipa_get_wake_up_idle() - Get PF_WAKE_UP_IDLE flag in the task structure + * + * Get PF_WAKE_UP_IDLE flag in the task structure + * + * Return: 1 if PF_WAKE_UP_IDLE flag is set, 0 otherwise + */ +static uint32_t hdd_ipa_get_wake_up_idle(void) +{ + return sched_get_wake_up_idle(current); +} + +/** + * hdd_ipa_set_wake_up_idle() - Set PF_WAKE_UP_IDLE flag in the task structure + * @wake_up_idle: Value to set PF_WAKE_UP_IDLE flag + * + * Set PF_WAKE_UP_IDLE flag in the task structure + * This task and any task woken by this will be waken to idle CPU + * + * Return: None + */ +static void hdd_ipa_set_wake_up_idle(bool wake_up_idle) +{ + sched_set_wake_up_idle(current, wake_up_idle); +} +#else +static uint32_t hdd_ipa_get_wake_up_idle(void) +{ + return 0; +} + +static void hdd_ipa_set_wake_up_idle(bool wake_up_idle) +{ +} +#endif + +#ifdef QCA_CONFIG_SMP +/** + * hdd_ipa_send_to_nw_stack() - Check if IPA supports NAPI + * polling during RX + * @skb : data buffer sent to network stack + * + * If IPA LAN RX supports NAPI polling mechanism use + * netif_receive_skb instead of netif_rx_ni to forward the skb + * to network stack. + * + * Return: Return value from netif_rx_ni/netif_receive_skb + */ +static int hdd_ipa_send_to_nw_stack(qdf_nbuf_t skb) +{ + int result; + + if (qdf_ipa_get_lan_rx_napi()) + result = netif_receive_skb(skb); + else + result = netif_rx_ni(skb); + return result; +} +#else +static int hdd_ipa_send_to_nw_stack(qdf_nbuf_t skb) +{ + int result; + + result = netif_rx_ni(skb); + return result; +} +#endif + +#ifdef QCA_CONFIG_SMP + +/** + * hdd_ipa_aggregated_rx_ind() - Submit aggregated packets to the stack + * @skb: skb to be submitted to the stack + * + * For CONFIG_SMP systems, simply call netif_rx_ni. + * For non CONFIG_SMP systems call netif_rx till + * IPA_WLAN_RX_SOFTIRQ_THRESH. When threshold is reached call netif_rx_ni. + * In this manner, UDP/TCP packets are sent in an aggregated way to the stack. + * For IP/ICMP packets, simply call netif_rx_ni. + * + * Check if IPA supports NAPI polling then use netif_receive_skb + * instead of netif_rx_ni. + * + * Return: return value from the netif_rx_ni/netif_rx api. + */ +static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) +{ + int ret; + + ret = hdd_ipa_send_to_nw_stack(skb); + return ret; +} +#else +static int hdd_ipa_aggregated_rx_ind(qdf_nbuf_t skb) +{ + struct iphdr *ip_h; + static atomic_t softirq_mitigation_cntr = + ATOMIC_INIT(IPA_WLAN_RX_SOFTIRQ_THRESH); + int result; + + ip_h = (struct iphdr *)(skb->data); + if ((skb->protocol == htons(ETH_P_IP)) && + (ip_h->protocol == IPPROTO_ICMP)) { + result = hdd_ipa_send_to_nw_stack(skb); + } else { + /* Call netif_rx_ni for every IPA_WLAN_RX_SOFTIRQ_THRESH packets + * to avoid excessive softirq's. + */ + if (atomic_dec_and_test(&softirq_mitigation_cntr)) { + result = hdd_ipa_send_to_nw_stack(skb); + atomic_set(&softirq_mitigation_cntr, + IPA_WLAN_RX_SOFTIRQ_THRESH); + } else { + result = netif_rx(skb); + } + } + + return result; +} +#endif + +void hdd_ipa_send_nbuf_to_network(qdf_nbuf_t nbuf, qdf_netdev_t dev) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) netdev_priv(dev); + struct wlan_objmgr_vdev *vdev; + int result; + bool delivered = false; + uint32_t enabled, len = 0; + struct hdd_tx_rx_stats *stats; + struct hdd_station_ctx *sta_ctx; + bool is_eapol; + u8 *ta_addr = NULL; + + if (hdd_validate_adapter(adapter)) { + kfree_skb(nbuf); + return; + } + + if (cds_is_driver_unloading()) { + kfree_skb(nbuf); + return; + } + + stats = &adapter->deflink->hdd_stats.tx_rx_stats; + hdd_ipa_update_rx_mcbc_stats(adapter, nbuf); + + if ((adapter->device_mode == QDF_SAP_MODE) && + (qdf_nbuf_is_ipv4_dhcp_pkt(nbuf) == true)) { + /* Send DHCP Indication to FW */ + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_DP_ID); + if (vdev) { + ucfg_dp_softap_inspect_dhcp_packet(vdev, nbuf, QDF_RX); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + } + + is_eapol = qdf_nbuf_is_ipv4_eapol_pkt(nbuf); + + qdf_dp_trace_set_track(nbuf, QDF_RX); + + ucfg_dp_event_eapol_log(nbuf, QDF_RX); + qdf_dp_trace_log_pkt(adapter->deflink->vdev_id, + nbuf, QDF_RX, QDF_TRACE_DEFAULT_PDEV_ID, + adapter->device_mode); + DPTRACE(qdf_dp_trace(nbuf, + QDF_DP_TRACE_RX_HDD_PACKET_PTR_RECORD, + QDF_TRACE_DEFAULT_PDEV_ID, + qdf_nbuf_data_addr(nbuf), + sizeof(qdf_nbuf_data(nbuf)), QDF_RX)); + DPTRACE(qdf_dp_trace_data_pkt(nbuf, QDF_TRACE_DEFAULT_PDEV_ID, + QDF_DP_TRACE_RX_PACKET_RECORD, 0, + QDF_RX)); + + /* + * Set PF_WAKE_UP_IDLE flag in the task structure + * This task and any task woken by this will be waken to idle CPU + */ + enabled = hdd_ipa_get_wake_up_idle(); + if (!enabled) + hdd_ipa_set_wake_up_idle(true); + + nbuf->dev = adapter->dev; + nbuf->protocol = eth_type_trans(nbuf, nbuf->dev); + nbuf->ip_summed = CHECKSUM_NONE; + len = nbuf->len; + + /* + * Update STA RX exception packet stats. + * For SAP as part of IPA HW stats are updated. + */ + + if (is_eapol && SEND_EAPOL_OVER_NL) { + if (adapter->device_mode == QDF_SAP_MODE) { + ta_addr = adapter->mac_addr.bytes; + } else if (adapter->device_mode == QDF_STA_MODE) { + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + ta_addr = (u8 *)&sta_ctx->conn_info.peer_macaddr; + } + + if (ta_addr) { + if (wlan_hdd_cfg80211_rx_control_port(adapter->dev, + ta_addr, nbuf, + false)) + result = NET_RX_SUCCESS; + else + result = NET_RX_DROP; + } else { + result = NET_RX_DROP; + } + + dev_kfree_skb(nbuf); + } else { + result = hdd_ipa_aggregated_rx_ind(nbuf); + } + + if (result == NET_RX_SUCCESS) + delivered = true; + /* + * adapter->vdev is directly dereferenced because this is per packet + * path, hdd_get_vdev_by_user() usage will be very costly as it involves + * lock access. + * Expectation here is vdev will be present during TX/RX processing + * and also DP internally maintaining vdev ref count + */ + ucfg_dp_inc_rx_pkt_stats(adapter->deflink->vdev, + len, delivered); + /* + * Restore PF_WAKE_UP_IDLE flag in the task structure + */ + if (!enabled) + hdd_ipa_set_wake_up_idle(false); +} + +void hdd_ipa_set_mcc_mode(bool mcc_mode) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + ucfg_ipa_set_mcc_mode(hdd_ctx->pdev, mcc_mode); +} + +#ifdef IPA_WDI3_TX_TWO_PIPES +static void +hdd_ipa_fill_sta_connection_info(struct wlan_hdd_link_info *link, + struct hdd_ipa_connection_info *conn) +{ + struct hdd_station_ctx *ctx = WLAN_HDD_GET_STATION_CTX_PTR(link); + + conn->ch_freq = ctx->conn_info.chan_freq; + conn->ch_width = ctx->conn_info.ch_width; + conn->wlan_80211_mode = hdd_convert_cfgdot11mode_to_80211mode( + ctx->conn_info.dot11mode); +} + +static void +hdd_ipa_fill_sap_connection_info(struct wlan_hdd_link_info *link, + struct hdd_ipa_connection_info *conn) +{ + struct hdd_ap_ctx *ctx = WLAN_HDD_GET_AP_CTX_PTR(link); + + conn->ch_freq = ctx->operating_chan_freq; + conn->ch_width = ctx->sap_config.ch_params.ch_width; + conn->wlan_80211_mode = hdd_convert_phymode_to_80211mode( + ctx->sap_config.SapHw_mode); +} + +static void hdd_ipa_fill_connection_info(struct wlan_hdd_link_info *link, + struct hdd_ipa_connection_info *conn) +{ + struct hdd_adapter *adapter = link->adapter; + + conn->vdev_id = link->vdev_id; + + if (adapter->device_mode == QDF_STA_MODE) + hdd_ipa_fill_sta_connection_info(link, conn); + else if (adapter->device_mode == QDF_SAP_MODE) + hdd_ipa_fill_sap_connection_info(link, conn); +} + +static QDF_STATUS +hdd_ipa_get_tx_pipe_multi_conn(struct hdd_context *hdd_ctx, + struct hdd_ipa_connection_info *conn, + bool *tx_pipe) +{ + uint32_t new_freq = conn->ch_freq; + QDF_STATUS status; + uint8_t vdev_id; + bool pipe; + + if (ucfg_policy_mgr_get_vdev_same_freq_new_conn(hdd_ctx->psoc, + new_freq, + &vdev_id)) { + /* Inherit the pipe selection of the connection that has + * same freq. + */ + return ucfg_ipa_get_alt_pipe(hdd_ctx->pdev, vdev_id, tx_pipe); + } else { + if (ucfg_policy_mgr_get_vdev_diff_freq_new_conn(hdd_ctx->psoc, + new_freq, + &vdev_id)) { + status = ucfg_ipa_get_alt_pipe(hdd_ctx->pdev, vdev_id, + &pipe); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + /* Inverse the pipe selection of the connection that + * has different channel frequency. + */ + *tx_pipe = !pipe; + return QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_E_INVAL; + } + } +} + +QDF_STATUS hdd_ipa_get_tx_pipe(struct hdd_context *hdd_ctx, + struct wlan_hdd_link_info *link, + bool *tx_pipe) +{ + struct hdd_ipa_connection_info conn; + uint32_t count; + + if (qdf_unlikely(!hdd_ctx || !link || !tx_pipe)) { + hdd_debug("Invalid parameters"); + return QDF_STATUS_E_INVAL; + } + + /* If SBS not capable, use legacy DBS selection */ + if (!ucfg_policy_mgr_is_hw_sbs_capable(hdd_ctx->psoc)) { + hdd_debug("firmware is not sbs capable"); + *tx_pipe = WLAN_REG_IS_24GHZ_CH_FREQ(conn.ch_freq); + return QDF_STATUS_SUCCESS; + } + + hdd_ipa_fill_connection_info(link, &conn); + + /* Always select the primary pipe for connection that is EHT160 or + * EHT320 due to higher tput requiements. + */ + if (conn.wlan_80211_mode == QCA_WLAN_802_11_MODE_11BE && + (conn.ch_width == CH_WIDTH_160MHZ || + conn.ch_width == CH_WIDTH_320MHZ)) { + *tx_pipe = false; + return QDF_STATUS_SUCCESS; + } + + count = ucfg_policy_mgr_get_connection_count(hdd_ctx->psoc); + if (!count) { + /* For first connection that is below EHT160, select the + * alternate pipe so as to reserve the primary pipe for + * potential connections that are above EHT160. + */ + *tx_pipe = true; + return QDF_STATUS_SUCCESS; + } + + return hdd_ipa_get_tx_pipe_multi_conn(hdd_ctx, &conn, tx_pipe); +} +#else /* !IPA_WDI3_TX_TWO_PIPES */ +QDF_STATUS hdd_ipa_get_tx_pipe(struct hdd_context *hdd_ctx, + struct wlan_hdd_link_info *link, + bool *tx_pipe) +{ + if (qdf_unlikely(!tx_pipe)) + return QDF_STATUS_E_INVAL; + + /* For IPA_WDI3_TX_TWO_PIPES=n, only one tx pipe is available */ + *tx_pipe = false; + + return QDF_STATUS_SUCCESS; +} +#endif /* IPA_WDI3_TX_TWO_PIPES */ + +void hdd_ipa_set_perf_level_bw(enum hw_mode_bandwidth bw) +{ + struct hdd_context *hdd_ctx; + enum wlan_ipa_bw_level lvl; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + if (bw == HW_MODE_320_MHZ) + lvl = WLAN_IPA_BW_LEVEL_HIGH; + else if (bw == HW_MODE_160_MHZ) + lvl = WLAN_IPA_BW_LEVEL_MEDIUM; + else + lvl = WLAN_IPA_BW_LEVEL_LOW; + + hdd_debug("Vote IPA perf level to %d", lvl); + ucfg_ipa_set_perf_level_bw(hdd_ctx->pdev, lvl); +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ll_lt_sap.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ll_lt_sap.c new file mode 100644 index 0000000000..ed5d458b8b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ll_lt_sap.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_lt_sap_definitions specific to the ll_lt_sap module + */ + +#include "wlan_hdd_ll_lt_sap.h" +#include "wlan_ll_sap_ucfg_api.h" +#include "osif_sync.h" +#include "wlan_hdd_cfg80211.h" +#include "os_if_ll_sap.h" + +const struct nla_policy + wlan_hdd_ll_lt_sap_transport_switch_policy + [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS] = { + .type = NLA_U8}, +}; + +/** + * __wlan_hdd_cfg80211_ll_lt_sap_transport_switch() - Request to switch the + * transport + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +static int +__wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_objmgr_vdev *vdev; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX + 1]; + enum qca_wlan_audio_transport_switch_type transport_switch_type; + enum qca_wlan_audio_transport_switch_status transport_switch_status; + QDF_STATUS status; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (!policy_mgr_is_vdev_ll_lt_sap(hdd_ctx->psoc, + adapter->deflink->vdev_id)) { + hdd_err("Command not allowed on vdev %d", + adapter->deflink->vdev_id); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse( + tb, QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_MAX, + data, data_len, + wlan_hdd_ll_lt_sap_transport_switch_policy)) { + hdd_err("vdev %d Invalid attribute", adapter->deflink->vdev_id); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]) { + hdd_err("Vdev %d attr transport switch type failed", + adapter->deflink->vdev_id); + return -EINVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc, + adapter->deflink->vdev_id, + WLAN_LL_SAP_ID); + if (!vdev) { + hdd_err("vdev %d not found", adapter->deflink->vdev_id); + return -EINVAL; + } + + transport_switch_type = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]) { + status = osif_ll_lt_sap_request_for_audio_transport_switch( + vdev, + transport_switch_type); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); + hdd_debug("Transport switch request type %d status %d vdev %d", + transport_switch_type, status, + adapter->deflink->vdev_id); + return qdf_status_to_os_return(status); + } + + transport_switch_status = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_STATUS]); + + /* Deliver the switch response */ + status = osif_ll_lt_sap_deliver_audio_transport_switch_resp( + vdev, + transport_switch_type, + transport_switch_status); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LL_SAP_ID); + + return qdf_status_to_os_return(status); +} + +int wlan_hdd_cfg80211_ll_lt_sap_transport_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ll_lt_sap_transport_switch(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c new file mode 100644 index 0000000000..7e920773e3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.c @@ -0,0 +1,438 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_lpass.c + * + * WLAN Host Device Driver LPASS feature implementation + * + */ + +/* Include Files */ +#include "wlan_hdd_main.h" +#include "wlan_hdd_lpass.h" +#include "wlan_hdd_oemdata.h" +#include +#include "qwlan_version.h" + +/** + * wlan_hdd_get_channel_info() - Get channel info + * @hdd_ctx: HDD context + * @chan_info: Pointer to the structure that stores channel info + * @chan_freq: Channel freq + * + * Fill in the channel info to chan_info structure. + */ +static void wlan_hdd_get_channel_info(struct hdd_context *hdd_ctx, + struct svc_channel_info *chan_info, + uint32_t chan_freq) +{ + uint32_t reg_info_1; + uint32_t reg_info_2; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_get_reg_info(hdd_ctx->mac_handle, chan_freq, + ®_info_1, ®_info_2); + if (status != QDF_STATUS_SUCCESS) + return; + + chan_info->mhz = chan_freq; + chan_info->band_center_freq1 = chan_info->mhz; + chan_info->band_center_freq2 = 0; + chan_info->info = 0; + if (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state_for_pwrmode(hdd_ctx->pdev, chan_freq, + REG_CURRENT_PWR_MODE)) + WMI_SET_CHANNEL_FLAG(chan_info, + WMI_CHAN_FLAG_DFS); + hdd_update_channel_bw_info(hdd_ctx, chan_freq, + chan_info); + chan_info->reg_info_1 = reg_info_1; + chan_info->reg_info_2 = reg_info_2; +} + +/** + * wlan_hdd_gen_wlan_status_pack() - Create lpass adapter status package + * @data: Status data record to be created + * @link_info: Link info pointer in HDD adapter + * @sta_ctx: Station-specific context of @adapter + * @is_on: Is wlan driver loaded? + * @is_connected: Is @adapter connected to an AP? + * + * Generate a wlan vdev status package. The status info includes wlan + * on/off status, vdev ID, vdev mode, supported channels, etc. + * + * Return: 0 if package was created, otherwise a negative errno + */ +static int wlan_hdd_gen_wlan_status_pack(struct wlan_status_data *data, + struct wlan_hdd_link_info *link_info, + struct hdd_station_ctx *sta_ctx, + uint8_t is_on, uint8_t is_connected) +{ + struct hdd_context *hdd_ctx = NULL; + int i; + uint32_t chan_id; + uint32_t *chan_freq_list, chan_freq_len; + struct svc_channel_info *chan_info; + bool lpass_support, wls_6ghz_capable = false; + QDF_STATUS status; + struct hdd_adapter *adapter; + + if (!data) { + hdd_err("invalid data pointer"); + return -EINVAL; + } + if (!link_info) { + if (is_on) { + /* no active interface */ + data->lpss_support = 0; + data->is_on = is_on; + return 0; + } + hdd_err("invalid adapter pointer"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + adapter = link_info->adapter; + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = ucfg_mlme_get_lpass_support(hdd_ctx->psoc, &lpass_support); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get LPASS support config"); + return -EIO; + } + ucfg_mlme_get_wls_6ghz_cap(hdd_ctx->psoc, &wls_6ghz_capable); + if (hdd_ctx->lpss_support && lpass_support) + data->lpss_support = 1; + else + data->lpss_support = 0; + + chan_freq_list = + qdf_mem_malloc(sizeof(uint32_t) * WLAN_SVC_MAX_NUM_CHAN); + if (!chan_freq_list) + return -ENOMEM; + + chan_freq_len = WLAN_SVC_MAX_NUM_CHAN; + sme_get_cfg_valid_channels(chan_freq_list, &chan_freq_len); + + data->numChannels = 0; + for (i = 0; i < chan_freq_len; i++) { + if (!wls_6ghz_capable && + wlan_reg_is_6ghz_chan_freq(chan_freq_list[i])) + continue; + + chan_id = wlan_reg_freq_to_chan(hdd_ctx->pdev, + chan_freq_list[i]); + if (!chan_id) + continue; + + chan_info = &data->channel_info[data->numChannels]; + data->channel_list[data->numChannels] = chan_id; + chan_info->chan_id = chan_id; + wlan_hdd_get_channel_info(hdd_ctx, + chan_info, + chan_freq_list[i]); + data->numChannels++; + } + + qdf_mem_free(chan_freq_list); + + wlan_reg_get_cc_and_src(hdd_ctx->psoc, data->country_code); + data->is_on = is_on; + data->vdev_id = link_info->vdev_id; + data->vdev_mode = adapter->device_mode; + if (sta_ctx) { + data->is_connected = is_connected; + data->rssi = link_info->rssi; + data->freq = sta_ctx->conn_info.chan_freq; + if (WLAN_SVC_MAX_SSID_LEN >= + sta_ctx->conn_info.ssid.SSID.length) { + data->ssid_len = sta_ctx->conn_info.ssid.SSID.length; + memcpy(data->ssid, + sta_ctx->conn_info.ssid.SSID.ssId, + sta_ctx->conn_info.ssid.SSID.length); + } + if (QDF_MAC_ADDR_SIZE >= sizeof(sta_ctx->conn_info.bssid)) + memcpy(data->bssid, sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + } + return 0; +} + +/** + * wlan_hdd_gen_wlan_version_pack() - Create lpass version package + * @data: Version data record to be created + * @fw_version: Version code from firmware + * @chip_id: WLAN chip ID + * @chip_name: WLAN chip name + * + * Generate a wlan software/hw version info package. The version info + * includes wlan host driver version, wlan fw driver version, wlan hw + * chip id & wlan hw chip name. + * + * Return: 0 if package was created, otherwise a negative errno + */ +static int wlan_hdd_gen_wlan_version_pack(struct wlan_version_data *data, + uint32_t fw_version, + uint32_t chip_id, + const char *chip_name) +{ + if (!data) { + hdd_err("invalid data pointer"); + return -EINVAL; + } + + data->chip_id = chip_id; + strlcpy(data->chip_name, chip_name, WLAN_SVC_MAX_STR_LEN); + if (strncmp(chip_name, "Unknown", 7)) + strlcpy(data->chip_from, "Qualcomm", WLAN_SVC_MAX_STR_LEN); + else + strlcpy(data->chip_from, "Unknown", WLAN_SVC_MAX_STR_LEN); + strlcpy(data->host_version, QWLAN_VERSIONSTR, WLAN_SVC_MAX_STR_LEN); + scnprintf(data->fw_version, WLAN_SVC_MAX_STR_LEN, "%d.%d.%d.%d", + (fw_version & 0xf0000000) >> 28, + (fw_version & 0xf000000) >> 24, + (fw_version & 0xf00000) >> 20, (fw_version & 0x7fff)); + return 0; +} + +/** + * wlan_hdd_send_status_pkg() - Send adapter status to lpass + * @link_info: Link info pointer in HDD adapter + * @sta_ctx: Station-specific context of @adapter + * @is_on: Is @adapter enabled + * @is_connected: Is @adapter connected + * + * Generate wlan vdev status package and send it to a user space + * daemon through netlink. + * + * Return: none + */ +static void wlan_hdd_send_status_pkg(struct wlan_hdd_link_info *link_info, + struct hdd_station_ctx *sta_ctx, + uint8_t is_on, uint8_t is_connected) +{ + int ret = 0; + struct wlan_status_data *data = NULL; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return; + + if (is_on) + ret = wlan_hdd_gen_wlan_status_pack(data, link_info, + sta_ctx, is_on, + is_connected); + + if (!ret) + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_STATUS_IND, + data, sizeof(*data)); + kfree(data); +} + +/** + * wlan_hdd_send_version_pkg() - report version information to lpass + * @fw_version: Version code from firmware + * @chip_id: WLAN chip ID + * @chip_name: WLAN chip name + * + * Generate a wlan sw/hw version info package and send it to a user + * space daemon through netlink. + * + * Return: none + */ +static void wlan_hdd_send_version_pkg(uint32_t fw_version, + uint32_t chip_id, + const char *chip_name) +{ + int ret = 0; + struct wlan_version_data data; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + memset(&data, 0, sizeof(struct wlan_version_data)); + ret = wlan_hdd_gen_wlan_version_pack(&data, fw_version, chip_id, + chip_name); + if (!ret) + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_VERSION_IND, + &data, sizeof(data)); +} + +/** + * wlan_hdd_send_scan_intf_info() - report scan interfaces to lpass + * @link_info: Link info pointer in HDD adapter + * + * This function indicates adapter that supports scanning to lpass. + * + * Return: none + */ +static inline void +wlan_hdd_send_scan_intf_info(struct wlan_hdd_link_info *link_info) +{ + wlan_hdd_send_status_pkg(link_info, NULL, 1, 0); +} + +/* + * hdd_lpass_target_config() - Handle LPASS target configuration + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *target_config) +{ + hdd_ctx->lpss_support = target_config->lpss_support; +} + +/* + * hdd_lpass_populate_cds_config() - Populate LPASS configuration + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_populate_cds_config(struct cds_config_info *cds_config, + struct hdd_context *hdd_ctx) +{ + bool lpass_support = false; + QDF_STATUS status; + + status = ucfg_mlme_get_lpass_support(hdd_ctx->psoc, &lpass_support); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get LPASS support config"); + + cds_config->is_lpass_enabled = lpass_support; +} + +/* + * hdd_lpass_populate_pmo_config() - Populate LPASS configuration + * (public function documented in wlan_hdd_lpass.h) + */ +void hdd_lpass_populate_pmo_config(struct pmo_psoc_cfg *pmo_config, + struct hdd_context *hdd_ctx) +{ + bool lpass_support = false; + QDF_STATUS status; + + status = ucfg_mlme_get_lpass_support(hdd_ctx->psoc, &lpass_support); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get LPASS support config"); + + pmo_config->lpass_enable = lpass_support; +} + +void hdd_lpass_notify_connect(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + + /* only send once per connection */ + if (link_info->rssi_send) + return; + + /* don't send if driver is unloading */ + if (cds_is_driver_unloading()) + return; + + link_info->rssi_send = true; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + wlan_hdd_send_status_pkg(link_info, sta_ctx, 1, 1); +} + +void hdd_lpass_notify_disconnect(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + + link_info->rssi_send = false; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + wlan_hdd_send_status_pkg(link_info, sta_ctx, 1, 0); +} + +void hdd_lpass_notify_mode_change(struct wlan_hdd_link_info *link_info) +{ + if (link_info->adapter->device_mode != QDF_STA_MODE) + return; + + hdd_debug("Sending Lpass mode change notification"); + + wlan_hdd_send_scan_intf_info(link_info); +} + +/* + * hdd_lpass_notify_wlan_version() - Notify LPASS WLAN Host/FW version + * + * implementation note: Notify LPASS for the WLAN host/firmware version. + */ +void hdd_lpass_notify_wlan_version(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + wlan_hdd_send_version_pkg(hdd_ctx->target_fw_version, + hdd_ctx->target_hw_version, + hdd_ctx->target_hw_name); + + hdd_exit(); +} + +void hdd_lpass_notify_start(struct wlan_hdd_link_info *link_info) +{ + hdd_enter(); + + if (link_info->adapter->device_mode != QDF_STA_MODE) + return; + + hdd_debug("Sending Start Lpass notification"); + + wlan_hdd_send_scan_intf_info(link_info); + + hdd_exit(); +} + +void hdd_lpass_notify_stop(struct hdd_context *hdd_ctx) +{ + hdd_debug("Sending Lpass stop notification"); + wlan_hdd_send_status_pkg(NULL, NULL, 0, 0); +} + +/* + * hdd_lpass_is_supported() - Is lpass feature supported? + * (public function documented in wlan_hdd_lpass.h) + */ +bool hdd_lpass_is_supported(struct hdd_context *hdd_ctx) +{ + bool lpass_support = false; + QDF_STATUS status; + + status = ucfg_mlme_get_lpass_support(hdd_ctx->psoc, &lpass_support); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get LPASS support config"); + + return lpass_support; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h new file mode 100644 index 0000000000..aa998d026c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_lpass.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_LPASS_H) +#define WLAN_HDD_LPASS_H + +struct cds_config_info; +struct wma_tgt_cfg; +struct hdd_context; +struct hdd_adapter; + +#ifdef WLAN_FEATURE_LPSS +/** + * hdd_lpass_target_config() - Handle LPASS target configuration + * @hdd_ctx: HDD global context where lpass information is stored + * @target_config: Target configuration containing lpass info + * + * This function updates the HDD context with lpass-specific + * information provided by the target. + * + * Return: none + */ +void hdd_lpass_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *target_config); + +/** + * hdd_lpass_populate_cds_config() - Populate LPASS configuration + * @cds_config: CDS configuration to populate with lpass info + * @hdd_ctx: HDD global context which contains lpass information + * + * This function seeds the CDS configuration structure with + * lpass-specific information gleaned from the HDD context. + * + * Return: none + */ +void hdd_lpass_populate_cds_config(struct cds_config_info *cds_config, + struct hdd_context *hdd_ctx); + +/** + * hdd_lpass_populate_pmo_config() - Populate LPASS configuration + * @pmo_config: PMO configuration to populate with lpass info + * @hdd_ctx: HDD global context which contains lpass information + * + * This function seeds the PMO configuration structure with + * lpass-specific information gleaned from the HDD context. + * + * Return: none + */ +void hdd_lpass_populate_pmo_config(struct pmo_psoc_cfg *pmo_config, + struct hdd_context *hdd_ctx); + +/** + * hdd_lpass_notify_connect() - Notify LPASS of interface connect + * @link_info: Link info pointer in HDD adapter + * + * This function is used to notify the LPASS feature that an adapter + * has connected. + * + * Return: none + */ +void hdd_lpass_notify_connect(struct wlan_hdd_link_info *link_info); + +/** + * hdd_lpass_notify_disconnect() - Notify LPASS of interface disconnect + * @link_info: Link info pointer in HDD adapter + * + * This function is used to notify the LPASS feature that an adapter + * has disconnected. + * + * Return: none + */ +void hdd_lpass_notify_disconnect(struct wlan_hdd_link_info *link_info); + +/** + * hdd_lpass_notify_mode_change() - Notify LPASS of interface mode change + * @link_info: Link info pointer in HDD adapter + * + * This function is used to notify the LPASS feature that an adapter + * had its mode changed. + * + * Return: none + */ +void hdd_lpass_notify_mode_change(struct wlan_hdd_link_info *link_info); + +/** + * hdd_lpass_notify_start() - Notify LPASS of driver start + * @link_info: Link info pointer in HDD adapter + * + * This function is used to notify the LPASS feature that the wlan + * driver has (re-)started. + * + * Return: none + */ +void hdd_lpass_notify_start(struct wlan_hdd_link_info *link_info); + +/** + * hdd_lpass_notify_stop() - Notify LPASS of driver stop + * @hdd_ctx: The global HDD context + * + * This function is used to notify the LPASS feature that the wlan + * driver has stopped. + * + * Return: none + */ +void hdd_lpass_notify_stop(struct hdd_context *hdd_ctx); + +/** + * hdd_lpass_is_supported() - Is lpass feature supported? + * @hdd_ctx: The global HDD context + * + * Return: true if feature is enabled and supported by firmware, false + * if the feature is not enabled or not supported by firmware. + */ +bool hdd_lpass_is_supported(struct hdd_context *hdd_ctx); + +/* + * hdd_lpass_notify_wlan_version() - Notify LPASS WLAN Host/FW version + * @hdd_ctx: The global HDD context + * + * Notify LPASS for the WLAN host/firmware and hardware version. + * + * Return: none + */ +void hdd_lpass_notify_wlan_version(struct hdd_context *hdd_ctx); +#else +static inline void hdd_lpass_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *target_config) +{ +} +static inline +void hdd_lpass_populate_cds_config(struct cds_config_info *cds_config, + struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_lpass_populate_pmo_config(struct pmo_psoc_cfg *pmo_config, + struct hdd_context *hdd_ctx) +{ +} + +static inline void +hdd_lpass_notify_connect(struct wlan_hdd_link_info *link_info) +{ +} + +static inline void +hdd_lpass_notify_disconnect(struct wlan_hdd_link_info *link_info) +{ +} + +static inline void +hdd_lpass_notify_mode_change(struct wlan_hdd_link_info *link_info) +{ +} + +static inline void +hdd_lpass_notify_start(struct wlan_hdd_link_info *link_info) +{ +} + +static inline void hdd_lpass_notify_stop(struct hdd_context *hdd_ctx) { } +static inline bool hdd_lpass_is_supported(struct hdd_context *hdd_ctx) +{ + return false; +} + +static inline void hdd_lpass_notify_wlan_version(struct hdd_context *hdd_ctx) +{ +} + +#endif + +#endif /* WLAN_HDD_LPASS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_main.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_main.c new file mode 100644 index 0000000000..81a489a723 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_main.c @@ -0,0 +1,22300 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_main.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include +#include "cfg_ucfg_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include "wlan_hdd_trace.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_ftm.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_stats.h" +#include "wlan_hdd_scan.h" +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_osif_priv.h" +#include +#ifdef CONFIG_LEAK_DETECTION +#include "qdf_debug_domain.h" +#endif +#include "qdf_delayed_work.h" +#include "qdf_periodic_work.h" +#include "qdf_str.h" +#include "qdf_talloc.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "qdf_net_if.h" +#include +#include +#include +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "qdf_ssr_driver_dump.h" + +#include +#include +#include +#include +#include +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_ext_scan.h" +#include "wlan_hdd_p2p.h" +#include +#include "sap_api.h" +#include +#include +#include +#include +#include +#include + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +#include "qdf_periodic_work.h" +#endif + +#include +#include +#include +#include "qwlan_version.h" +#include "wma_types.h" +#include "wlan_hdd_tdls.h" +#ifdef FEATURE_WLAN_CH_AVOID +#include "cds_regdomain.h" +#endif /* FEATURE_WLAN_CH_AVOID */ +#include "cdp_txrx_flow_ctrl_v2.h" +#include "pld_common.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_nan.h" +#include "wlan_hdd_debugfs.h" +#include "wlan_hdd_debugfs_csr.h" +#include "wlan_hdd_driver_ops.h" +#include "epping_main.h" +#include "wlan_hdd_data_stall_detection.h" +#include "wlan_hdd_mpta_helper.h" + +#include +#include "hif.h" +#include "wma.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_tsf.h" +#include "bmi.h" +#include +#include "wlan_hdd_lpass.h" +#include "wlan_nan_api.h" +#include +#include "wlan_hdd_disa.h" +#include +#include "wlan_hdd_object_manager.h" +#include "cds_utils.h" +#include +#include +#include "wlan_pmo_ucfg_api.h" +#include "sir_api.h" +#include "os_if_wifi_pos.h" +#include "wifi_pos_api.h" +#include "wlan_hdd_oemdata.h" +#include "wlan_hdd_he.h" +#include "os_if_nan.h" +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_hdd_afc.h" +#include "wlan_afc_ucfg_api.h" +#include "wlan_dfs_ucfg_api.h" +#include "wlan_hdd_rx_monitor.h" +#include "sme_power_save_api.h" +#include "enet.h" +#include +#include "wlan_hdd_sysfs.h" +#include "wlan_disa_ucfg_api.h" +#include "wlan_disa_obj_mgmt_api.h" +#include "wlan_action_oui_ucfg_api.h" +#include "wlan_ipa_ucfg_api.h" +#include +#include "wlan_hdd_nud_tracking.h" +#include "wlan_hdd_apf.h" +#include "wlan_hdd_twt.h" +#include "qc_sap_ioctl.h" +#include "wlan_mlme_main.h" +#include "wlan_p2p_cfg_api.h" +#include "wlan_cfg80211_p2p.h" +#include "wlan_cfg80211_interop_issues_ap.h" +#include "wlan_tdls_cfg_api.h" +#include +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_twt_ucfg_api.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include "qdf_func_tracker.h" +#include "pld_common.h" +#include "wlan_hdd_pre_cac.h" + +#include "sme_api.h" + +#ifdef CNSS_GENL +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss_nl.h" +#else +#include +#endif +#endif +#include "wlan_reg_ucfg_api.h" +#include "wlan_ocb_ucfg_api.h" +#include +#include "wlan_green_ap_ucfg_api.h" +#include +#include +#include +#include +#include +#include "wlan_dlm_ucfg_api.h" +#include "ftm_time_sync_ucfg_api.h" +#include "wlan_pre_cac_ucfg_api.h" +#include "ol_txrx.h" +#include "wlan_hdd_sta_info.h" +#include "mac_init_api.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include +#include "cfg_nan_api.h" +#include "wlan_hdd_btc_chain_mode.h" +#include +#include "wlan_hdd_debugfs_unit_test.h" +#include "wlan_hdd_debugfs_mibstat.h" +#include +#include "wlan_global_lmac_if_api.h" +#include "wlan_coex_ucfg_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_cm_roam_ucfg_api.h" +#include +#include "qdf_lock.h" +#include "wlan_hdd_thermal.h" +#include "osif_cm_util.h" +#include "wlan_hdd_gpio_wakeup.h" +#include "wlan_hdd_bootup_marker.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_hdd_medium_assess.h" +#include "wlan_hdd_eht.h" +#include +#include "wlan_hdd_mlo.h" +#include +#ifdef WLAN_FEATURE_11BE_MLO +#include +#endif +#include "wlan_osif_features.h" +#include "wlan_vdev_mgr_ucfg_api.h" +#include +#include +#include "wifi_pos_ucfg_api.h" +#include "osif_vdev_mgr_util.h" +#include +#include "osif_twt_util.h" +#include "wlan_twt_ucfg_ext_api.h" +#include "wlan_hdd_mcc_quota.h" +#include "osif_pre_cac.h" +#include "wlan_hdd_pre_cac.h" +#include "wlan_osif_features.h" +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +#include +#endif +#include "wlan_dp_public_struct.h" +#include "os_if_dp.h" +#include +#include "wlan_psoc_mlme_ucfg_api.h" +#include "os_if_qmi.h" +#include "wlan_qmi_ucfg_api.h" +#include "wlan_psoc_mlme_ucfg_api.h" +#include "wlan_ll_sap_ucfg_api.h" + +#include "os_if_dp_local_pkt_capture.h" +#include +#include "cdp_txrx_mon.h" +#include "os_if_ll_sap.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_crypto_obj_mgr_i.h" + +#ifdef MULTI_CLIENT_LL_SUPPORT +#define WLAM_WLM_HOST_DRIVER_PORT_ID 0xFFFFFF +#endif + +#ifdef MODULE +#ifdef WLAN_WEAR_CHIPSET +#define WLAN_MODULE_NAME "wlan" +#else +#define WLAN_MODULE_NAME module_name(THIS_MODULE) +#endif +#else +#define WLAN_MODULE_NAME "wlan" +#endif + +#ifdef TIMER_MANAGER +#define TIMER_MANAGER_STR " +TIMER_MANAGER" +#else +#define TIMER_MANAGER_STR "" +#endif + +#ifdef MEMORY_DEBUG +#define MEMORY_DEBUG_STR " +MEMORY_DEBUG" +#else +#define MEMORY_DEBUG_STR "" +#endif + +#ifdef PANIC_ON_BUG +#define PANIC_ON_BUG_STR " +PANIC_ON_BUG" +#else +#define PANIC_ON_BUG_STR "" +#endif + +/* PCIe gen speed change idle shutdown timer 100 milliseconds */ +#define HDD_PCIE_GEN_SPEED_CHANGE_TIMEOUT_MS (100) + +#define MAX_NET_DEV_REF_LEAK_ITERATIONS 10 +#define NET_DEV_REF_LEAK_ITERATION_SLEEP_TIME_MS 10 + +#ifdef FEATURE_TSO +#define TSO_FEATURE_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_SG) +#else +#define TSO_FEATURE_FLAGS 0 +#endif + +int wlan_start_ret_val; +static DECLARE_COMPLETION(wlan_start_comp); +static qdf_atomic_t wlan_hdd_state_fops_ref; +#ifndef MODULE +static struct gwlan_loader *wlan_loader; +static ssize_t wlan_boot_cb(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); +struct gwlan_loader { + bool loaded_state; + struct kobject *boot_wlan_obj; + struct attribute_group *attr_group; +}; + +static struct kobj_attribute wlan_boot_attribute = + __ATTR(boot_wlan, 0220, NULL, wlan_boot_cb); + +static struct attribute *attrs[] = { + &wlan_boot_attribute.attr, + NULL, +}; +#define MODULE_INITIALIZED 1 + +#ifdef MULTI_IF_NAME +#define WLAN_LOADER_NAME "boot_" MULTI_IF_NAME +#else +#define WLAN_LOADER_NAME "boot_wlan" +#endif +#endif + +/* the Android framework expects this param even though we don't use it */ +#define BUF_LEN 20 +static char fwpath_buffer[BUF_LEN]; +static struct kparam_string fwpath = { + .string = fwpath_buffer, + .maxlen = BUF_LEN, +}; + +char *country_code; +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(country_code); +#endif +static int enable_11d = -1; +static int enable_dfs_chan_scan = -1; +static bool is_mode_change_psoc_idle_shutdown; + +#define WLAN_NLINK_CESIUM 30 + +static qdf_wake_lock_t wlan_wake_lock; + +/* The valid PCIe gen speeds are 1, 2, 3 */ +#define HDD_INVALID_MIN_PCIE_GEN_SPEED (0) +#define HDD_INVALID_MAX_PCIE_GEN_SPEED (4) + +#define MAX_PDEV_PRE_ENABLE_PARAMS 8 +#define FTM_MAX_PDEV_PARAMS 1 + +#define WOW_MAX_FILTER_LISTS 1 +#define WOW_MAX_FILTERS_PER_LIST 4 +#define WOW_MIN_PATTERN_SIZE 6 +#define WOW_MAX_PATTERN_SIZE 64 +#define MGMT_DEFAULT_DATA_RATE_6GHZ 0x400 /* This maps to 8.6Mbps data rate */ + +#define IS_IDLE_STOP (!cds_is_driver_unloading() && \ + !cds_is_driver_recovering() && !cds_is_driver_loading()) + +#define HDD_FW_VER_MAJOR_SPID(tgt_fw_ver) ((tgt_fw_ver & 0xf0000000) >> 28) +#define HDD_FW_VER_MINOR_SPID(tgt_fw_ver) ((tgt_fw_ver & 0xf000000) >> 24) +#define HDD_FW_VER_SIID(tgt_fw_ver) ((tgt_fw_ver & 0xf00000) >> 20) +#define HDD_FW_VER_CRM_ID(tgt_fw_ver) (tgt_fw_ver & 0x7fff) +#define HDD_FW_VER_SUB_ID(tgt_fw_ver_ext) \ +(((tgt_fw_ver_ext & 0x1c00) >> 6) | ((tgt_fw_ver_ext & 0xf0000000) >> 28)) +#define HDD_FW_VER_REL_ID(tgt_fw_ver_ext) \ +((tgt_fw_ver_ext & 0xf800000) >> 23) + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static const struct wiphy_wowlan_support wowlan_support_reg_init = { + .flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE | + WIPHY_WOWLAN_RFKILL_RELEASE, + .n_patterns = WOW_MAX_FILTER_LISTS * WOW_MAX_FILTERS_PER_LIST, + .pattern_min_len = WOW_MIN_PATTERN_SIZE, + .pattern_max_len = WOW_MAX_PATTERN_SIZE, +}; +#endif + +static const struct category_info cinfo[MAX_SUPPORTED_CATEGORY] = { + [QDF_MODULE_ID_TLSHIM] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_WMI] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_HTT] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_HDD] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SME] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_PE] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_WMA] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SYS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_QDF] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SAP] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_HDD_SOFTAP] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_HDD_DATA] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_HDD_SAP_DATA] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_HIF] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_HTC] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_TXRX] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_HAL] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_QDF_DEVICE] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_CFG] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_BMI] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_EPPING] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_QVIT] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_DP] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_TX_CAPTURE] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_INIT] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_STATS] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_HTT] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_PEER] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_HTT_TX_STATS] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_REO] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_VDEV] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_CDP] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_UMAC_RESET] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_DP_SAWF] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_SOC] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_OS_IF] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_TARGET_IF] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SCHEDULER] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_MGMT_TXRX] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_PMO] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SCAN] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_POLICY_MGR] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_P2P] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_TDLS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_REGULATORY] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SERIALIZATION] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_DFS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_OBJ_MGR] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_ROAM_DEBUG] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_GREEN_AP] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_OCB] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_IPA] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_ACTION_OUI] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_CONFIG] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_MLME] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_TARGET] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_CRYPTO] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_FWOL] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SM_ENGINE] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_CMN_MLME] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_NAN] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_CP_STATS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_DCS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_INTEROP_ISSUES_AP] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_DENYLIST_MGR] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_DIRECT_BUF_RX] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SPECTRAL] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_WIFIPOS] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_PKT_CAPTURE] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_FTM_TIME_SYNC] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_CFR] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_IFMGR] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_GPIO] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_T2LM] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_MLO] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_SON] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_TWT] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_WLAN_PRE_CAC] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_COAP] = {QDF_TRACE_LEVEL_ALL}, + [QDF_MODULE_ID_MON_FILTER] = {QDF_DATA_PATH_TRACE_LEVEL}, + [QDF_MODULE_ID_LL_SAP] = {QDF_TRACE_LEVEL_ALL}, +}; + +struct notifier_block hdd_netdev_notifier; + +struct sock *cesium_nl_srv_sock; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +static void wlan_hdd_auto_shutdown_cb(void); +#endif + +static void hdd_dp_register_callbacks(struct hdd_context *hdd_ctx); + +bool hdd_adapter_is_ap(struct hdd_adapter *adapter) +{ + if (!adapter) { + hdd_err("null adapter"); + return false; + } + + return adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE; +} + +QDF_STATUS hdd_common_roam_callback(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, session_id); + if (!link_info) + return QDF_STATUS_E_INVAL; + + adapter = link_info->adapter; + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return QDF_STATUS_E_INVAL; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_NDI_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + status = hdd_sme_roam_callback(link_info, roam_info, + roam_status, roam_result); + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + status = + wlansap_roam_callback(link_info->session.ap.sap_context, + roam_info, roam_status, + roam_result); + break; + default: + hdd_err("Wrong device mode"); + break; + } + + return status; +} + +void hdd_start_complete(int ret) +{ + wlan_start_ret_val = ret; + complete_all(&wlan_start_comp); +} + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +/** + * wlan_hdd_lpc_del_monitor_interface() - Delete monitor interface + * @hdd_ctx: hdd_ctx + * @is_virtual_iface: Is virtual interface + * + * This function takes care of deleting monitor interface + * + * Return: none + */ +static void +wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx, + bool is_virtual_iface) +{ + struct hdd_adapter *adapter; + void *soc; + bool running; + + if (!hdd_ctx) + return; + + if (!ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc)) + return; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) + return; + + running = cdp_is_local_pkt_capture_running(soc, OL_TXRX_PDEV_ID); + if (!running) + return; + + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (!adapter) { + hdd_debug("There is no monitor adapter"); + return; + } + + hdd_debug("lpc: Delete monitor interface"); + + wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); + qdf_zero_macaddr(&adapter->mac_addr); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + adapter->is_virtual_iface = is_virtual_iface; + hdd_ctx->lpc_info.mon_adapter = adapter; + + hdd_ctx->lpc_info.lpc_wk_scheduled = true; + qdf_sched_work(0, &hdd_ctx->lpc_info.lpc_wk); +} + +void wlan_hdd_lpc_handle_concurrency(struct hdd_context *hdd_ctx, + bool is_virtual_iface) +{ + wlan_hdd_lpc_del_monitor_interface(hdd_ctx, is_virtual_iface); +} + +bool hdd_lpc_is_work_scheduled(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->lpc_info.lpc_wk_scheduled; +} + +static void hdd_lpc_work_handler(void *arg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)arg; + struct hdd_adapter *adapter; + struct osif_vdev_sync *vdev_sync; + int errno; + + if (!hdd_ctx) + return; + + adapter = hdd_ctx->lpc_info.mon_adapter; + if (!adapter) { + hdd_err("There is no monitor adapter"); + return; + } + + errno = osif_vdev_sync_trans_start_wait(adapter->dev, &vdev_sync); + if (errno) + return; + + osif_vdev_sync_unregister(adapter->dev); + osif_vdev_sync_wait_for_ops(vdev_sync); + + hdd_close_adapter(hdd_ctx, adapter, true); + hdd_ctx->lpc_info.lpc_wk_scheduled = false; + + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); +} + +static inline +void hdd_lp_create_work(struct hdd_context *hdd_ctx) +{ + hdd_ctx->lpc_info.lpc_wk_scheduled = false; + qdf_create_work(0, &hdd_ctx->lpc_info.lpc_wk, hdd_lpc_work_handler, + hdd_ctx); +} + +static inline +void hdd_lpc_delete_work(struct hdd_context *hdd_ctx) +{ + qdf_flush_work(&hdd_ctx->lpc_info.lpc_wk); + hdd_ctx->lpc_info.lpc_wk_scheduled = false; + qdf_destroy_work(NULL, &hdd_ctx->lpc_info.lpc_wk); +} + +#else +static inline +void hdd_lp_create_work(struct hdd_context *hdd_ctx) +{ +} + +static inline +void hdd_lpc_delete_work(struct hdd_context *hdd_ctx) +{ +} + +static inline +void wlan_hdd_lpc_del_monitor_interface(struct hdd_context *hdd_ctx, + bool is_virtual_iface) +{ +} +#endif + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +void wlan_hdd_mod_fc_timer(struct hdd_adapter *adapter, + enum netif_action_type action) +{ + struct hdd_stats *hdd_stats; + + if (!adapter->tx_flow_timer_initialized) + return; + + hdd_stats = &adapter->deflink->hdd_stats; + if (action == WLAN_WAKE_NON_PRIORITY_QUEUE) { + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + hdd_stats->tx_rx_stats.is_txflow_paused = false; + hdd_stats->tx_rx_stats.txflow_unpause_cnt++; + } else if (action == WLAN_STOP_NON_PRIORITY_QUEUE) { + QDF_STATUS status = + qdf_mc_timer_start(&adapter->tx_flow_control_timer, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + hdd_stats->tx_rx_stats.txflow_timer_cnt++; + + hdd_stats->tx_rx_stats.txflow_pause_cnt++; + hdd_stats->tx_rx_stats.is_txflow_paused = true; + } +} +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +/** + * wlan_hdd_txrx_pause_cb() - pause callback from txrx layer + * @vdev_id: vdev_id + * @action: action type + * @reason: reason type + * + * Return: none + */ +void wlan_hdd_txrx_pause_cb(uint8_t vdev_id, + enum netif_action_type action, enum netif_reason_type reason) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) + return; + + adapter = link_info->adapter; + wlan_hdd_mod_fc_timer(adapter, action); + wlan_hdd_netif_queue_control(adapter, action, reason); +} + +/* + * Store WLAN driver version and timestamp info in global variables such that + * crash debugger can extract them from driver debug symbol and crashdump for + * post processing + */ +#ifdef BUILD_TAG +uint8_t g_wlan_driver_version[] = QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR PANIC_ON_BUG_STR "; " BUILD_TAG; +#else +uint8_t g_wlan_driver_version[] = QWLAN_VERSIONSTR TIMER_MANAGER_STR MEMORY_DEBUG_STR PANIC_ON_BUG_STR; +#endif + +int hdd_validate_channel_and_bandwidth(struct hdd_adapter *adapter, + qdf_freq_t chan_freq, + enum phy_ch_width chan_bw) +{ + struct ch_params ch_params = {0}; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return -EINVAL; + } + + if (reg_is_chan_enum_invalid( + wlan_reg_get_chan_enum_for_freq(chan_freq))) { + hdd_err("Channel freq %d not in driver's valid channel list", chan_freq); + return -EOPNOTSUPP; + } + + if ((!WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) && + (!WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) && + (!WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq))) { + hdd_err("CH %d is not in 2.4GHz or 5GHz or 6GHz", chan_freq); + return -EINVAL; + } + ch_params.ch_width = CH_WIDTH_MAX; + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params.ch_width == CH_WIDTH_MAX) { + hdd_err("failed to get max bandwdith for %d", chan_freq); + return -EINVAL; + } + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) { + if (chan_bw == CH_WIDTH_80MHZ) { + hdd_err("BW80 not possible in 2.4GHz band"); + return -EINVAL; + } + if ((chan_bw != CH_WIDTH_20MHZ) && + (chan_freq == wlan_reg_ch_to_freq(CHAN_ENUM_2484)) && + (chan_bw != CH_WIDTH_MAX) && + (ch_params.ch_width == CH_WIDTH_20MHZ)) { + hdd_err("Only BW20 possible on channel freq 2484"); + return -EINVAL; + } + } + + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) { + if ((chan_bw != CH_WIDTH_20MHZ) && + (chan_freq == wlan_reg_ch_to_freq(CHAN_ENUM_5825)) && + (chan_bw != CH_WIDTH_MAX) && + (ch_params.ch_width == CH_WIDTH_20MHZ)) { + hdd_err("Only BW20 possible on channel freq 5825"); + return -EINVAL; + } + } + + return 0; +} + +uint32_t hdd_get_link_info_home_channel(struct wlan_hdd_link_info *link_info) +{ + uint32_t home_chan_freq = 0; + enum QDF_OPMODE opmode = link_info->adapter->device_mode; + + switch (opmode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + home_chan_freq = + link_info->session.ap.operating_chan_freq; + } + break; + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (hdd_cm_is_vdev_associated(link_info)) { + home_chan_freq = + link_info->session.station.conn_info.chan_freq; + } + break; + default: + break; + } + + return home_chan_freq; +} + +enum phy_ch_width hdd_get_link_info_width(struct wlan_hdd_link_info *link_info) +{ + enum phy_ch_width width = CH_WIDTH_20MHZ; + enum QDF_OPMODE opmode = link_info->adapter->device_mode; + + switch (opmode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + struct hdd_ap_ctx *ap_ctx = + WLAN_HDD_GET_AP_CTX_PTR(link_info); + + width = ap_ctx->sap_config.ch_params.ch_width; + } + break; + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (hdd_cm_is_vdev_associated(link_info)) + width = link_info->session.station.conn_info.ch_width; + break; + default: + break; + } + + return width; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) +static inline struct net_device *hdd_net_dev_from_notifier(void *context) +{ + struct netdev_notifier_info *info = context; + + return info->dev; +} +#else +static inline struct net_device *hdd_net_dev_from_notifier(void *context) +{ + return context; +} +#endif + +static int __hdd_netdev_notifier_call(struct net_device *net_dev, + unsigned long state) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(net_dev); + + if (!net_dev->ieee80211_ptr) { + hdd_debug("ieee80211_ptr is null"); + return NOTIFY_DONE; + } + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return NOTIFY_DONE; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_debug("Driver module is closed"); + return NOTIFY_DONE; + } + + /* Make sure that this callback corresponds to our device. */ + adapter = hdd_get_adapter_by_iface_name(hdd_ctx, net_dev->name); + if (!adapter) { + hdd_debug("failed to look up adapter for '%s'", net_dev->name); + return NOTIFY_DONE; + } + + if (adapter != WLAN_HDD_GET_PRIV_PTR(net_dev)) { + hdd_err("HDD adapter mismatch!"); + return NOTIFY_DONE; + } + + if (cds_is_driver_recovering()) { + hdd_debug("Driver is recovering"); + return NOTIFY_DONE; + } + + if (cds_is_driver_in_bad_state()) { + hdd_debug("Driver is in failed recovery state"); + return NOTIFY_DONE; + } + + hdd_debug("%s New Net Device State = %lu, flags 0x%x", + net_dev->name, state, net_dev->flags); + + switch (state) { + case NETDEV_REGISTER: + break; + + case NETDEV_UNREGISTER: + break; + + case NETDEV_UP: + sme_ch_avoid_update_req(hdd_ctx->mac_handle); + break; + + case NETDEV_DOWN: + break; + + case NETDEV_CHANGE: + if (adapter->is_link_up_service_needed) + complete(&adapter->linkup_event_var); + break; + + case NETDEV_GOING_DOWN: + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SCAN_ID); + if (!vdev) + break; + if (ucfg_scan_get_vdev_status(vdev) != + SCAN_NOT_IN_PROGRESS) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->deflink->vdev_id, + INVALID_SCAN_ID, true); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID); + cds_flush_work(&adapter->scan_block_work); + /* Need to clean up blocked scan request */ + wlan_hdd_cfg80211_scan_block(adapter); + hdd_debug("Scan is not Pending from user"); + /* + * After NETDEV_GOING_DOWN, kernel calls hdd_stop.Irrespective + * of return status of hdd_stop call, kernel resets the IFF_UP + * flag after which driver does not send the cfg80211_scan_done. + * Ensure to cleanup the scan queue in NETDEV_GOING_DOWN + */ + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, net_dev); + break; + case NETDEV_FEAT_CHANGE: + hdd_debug("vdev %d netdev Feature 0x%llx\n", + adapter->deflink->vdev_id, net_dev->features); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static int hdd_netdev_notifier_bridge_intf(struct net_device *net_dev, + unsigned long state) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + + hdd_enter_dev(net_dev); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx)) + return NOTIFY_DONE; + + hdd_debug("%s New Net Device State = %lu, flags 0x%x bridge mac address: "QDF_MAC_ADDR_FMT, + net_dev->name, state, net_dev->flags, QDF_MAC_ADDR_REF(net_dev->dev_addr)); + + if (!qdf_mem_cmp(hdd_ctx->bridgeaddr, net_dev->dev_addr, + QDF_MAC_ADDR_SIZE)) + return NOTIFY_DONE; + + switch (state) { + case NETDEV_REGISTER: + case NETDEV_CHANGEADDR: + /* Update FW WoW pattern with new MAC address */ + qdf_mem_copy(hdd_ctx->bridgeaddr, net_dev->dev_addr, + QDF_MAC_ADDR_SIZE); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_SAP_MODE) + goto loop_next; + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + goto loop_next; + + status = wlan_objmgr_vdev_try_get_ref(adapter->deflink->vdev, + WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) + goto loop_next; + + ucfg_pmo_set_vdev_bridge_addr(adapter->deflink->vdev, + (struct qdf_mac_addr *)hdd_ctx->bridgeaddr); + ucfg_pmo_del_wow_pattern(adapter->deflink->vdev); + ucfg_pmo_register_wow_default_patterns(adapter->deflink->vdev); + + wlan_objmgr_vdev_release_ref(adapter->deflink->vdev, + WLAN_HDD_ID_OBJ_MGR); + +loop_next: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + break; + case NETDEV_UNREGISTER: + qdf_zero_macaddr((struct qdf_mac_addr *)hdd_ctx->bridgeaddr); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +/** + * hdd_netdev_notifier_call() - netdev notifier callback function + * @nb: pointer to notifier block + * @state: state + * @context: notifier callback context pointer + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_netdev_notifier_call(struct notifier_block *nb, + unsigned long state, + void *context) +{ + struct net_device *net_dev = hdd_net_dev_from_notifier(context); + struct osif_vdev_sync *vdev_sync; + int errno; + + if (net_dev->priv_flags & IFF_EBRIDGE) { + errno = hdd_netdev_notifier_bridge_intf(net_dev, state); + if (errno) + return NOTIFY_DONE; + } + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) { + hdd_debug("%s New Net Device State = %lu, flags 0x%x NOTIFY_DONE", + net_dev->name, state, net_dev->flags); + return NOTIFY_DONE; + } + + errno = __hdd_netdev_notifier_call(net_dev, state); + + osif_vdev_sync_op_stop(vdev_sync); + + return NOTIFY_DONE; +} + +struct notifier_block hdd_netdev_notifier = { + .notifier_call = hdd_netdev_notifier_call, +}; + +/* variable to hold the insmod parameters */ +int con_mode; +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(con_mode); +#endif + +int con_mode_ftm; +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(con_mode_ftm); +#endif +int con_mode_epping; + +static int pcie_gen_speed; + +/* Variable to hold connection mode including module parameter con_mode */ +static int curr_con_mode; + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +static enum phy_ch_width hdd_get_eht_phy_ch_width_from_target(void) +{ + uint32_t max_fw_bw = sme_get_eht_ch_width(); + + if (max_fw_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) + return CH_WIDTH_320MHZ; + else if (max_fw_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else + return CH_WIDTH_80MHZ; +} + +static bool hdd_is_target_eht_phy_ch_width_supported(enum phy_ch_width width) +{ + enum phy_ch_width max_fw_bw = hdd_get_eht_phy_ch_width_from_target(); + + if (width <= max_fw_bw) + return true; + + hdd_err("FW does not support this BW %d max BW supported %d", + width, max_fw_bw); + return false; +} + +static bool hdd_is_target_eht_160mhz_capable(void) +{ + return hdd_is_target_eht_phy_ch_width_supported(CH_WIDTH_160MHZ); +} + +static enum phy_ch_width +wlan_hdd_map_nl_chan_width(enum nl80211_chan_width width) +{ + if (width == NL80211_CHAN_WIDTH_320) { + return hdd_get_eht_phy_ch_width_from_target(); + } else { + hdd_err("Invalid channel width %d, setting to default", width); + return CH_WIDTH_INVALID; + } +} + +#else /* !WLAN_FEATURE_11BE */ +static inline bool +hdd_is_target_eht_phy_ch_width_supported(enum phy_ch_width width) +{ + return true; +} + +static inline bool hdd_is_target_eht_160mhz_capable(void) +{ + return false; +} + +static enum phy_ch_width +wlan_hdd_map_nl_chan_width(enum nl80211_chan_width width) +{ + hdd_err("Invalid channel width %d, setting to default", width); + return CH_WIDTH_INVALID; +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * hdd_map_nl_chan_width() - Map NL channel width to internal representation + * @ch_width: NL channel width + * + * Converts the NL channel width to the driver's internal representation + * + * Return: Converted channel width. In case of non matching NL channel width, + * CH_WIDTH_MAX will be returned. + */ +enum phy_ch_width hdd_map_nl_chan_width(enum nl80211_chan_width ch_width) +{ + uint8_t fw_ch_bw; + + fw_ch_bw = wma_get_vht_ch_width(); + switch (ch_width) { + case NL80211_CHAN_WIDTH_20_NOHT: + case NL80211_CHAN_WIDTH_20: + return CH_WIDTH_20MHZ; + case NL80211_CHAN_WIDTH_40: + return CH_WIDTH_40MHZ; + case NL80211_CHAN_WIDTH_80: + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_80P80: + if (fw_ch_bw == WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + return CH_WIDTH_80P80MHZ; + else if (fw_ch_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_160: + if (hdd_is_target_eht_160mhz_capable()) + return CH_WIDTH_160MHZ; + + if (fw_ch_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else + return CH_WIDTH_80MHZ; + case NL80211_CHAN_WIDTH_5: + return CH_WIDTH_5MHZ; + case NL80211_CHAN_WIDTH_10: + return CH_WIDTH_10MHZ; + default: + return wlan_hdd_map_nl_chan_width(ch_width); + } +} + +#if defined(WLAN_FEATURE_NAN) && \ + (KERNEL_VERSION(4, 9, 0) <= LINUX_VERSION_CODE) +/** + * wlan_hdd_convert_nan_type() - Convert nl type to qdf type + * @nl_type: NL80211 interface type + * @out_qdf_type: QDF type for the given nl_type + * + * Convert nl type to QDF type + * + * Return: QDF_STATUS_SUCCESS if converted, failure otherwise. + */ +static QDF_STATUS wlan_hdd_convert_nan_type(enum nl80211_iftype nl_type, + enum QDF_OPMODE *out_qdf_type) +{ + if (nl_type == NL80211_IFTYPE_NAN) { + *out_qdf_type = QDF_NAN_DISC_MODE; + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_INVAL; +} + +/** + * wlan_hdd_set_nan_if_type() - Set the NAN iftype + * @adapter: pointer to HDD adapter + * + * Set the NL80211_IFTYPE_NAN to wdev iftype. + * + * Return: None + */ +static void wlan_hdd_set_nan_if_type(struct hdd_adapter *adapter) +{ + adapter->wdev.iftype = NL80211_IFTYPE_NAN; +} + +static bool wlan_hdd_is_vdev_creation_allowed(struct wlan_objmgr_psoc *psoc) +{ + return ucfg_nan_is_vdev_creation_allowed(psoc); +} +#else +static QDF_STATUS wlan_hdd_convert_nan_type(enum nl80211_iftype nl_type, + enum QDF_OPMODE *out_qdf_type) +{ + return QDF_STATUS_E_INVAL; +} + +static void wlan_hdd_set_nan_if_type(struct hdd_adapter *adapter) +{ +} + +static bool wlan_hdd_is_vdev_creation_allowed(struct wlan_objmgr_psoc *psoc) +{ + return false; +} +#endif + +QDF_STATUS hdd_nl_to_qdf_iface_type(enum nl80211_iftype nl_type, + enum QDF_OPMODE *out_qdf_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + switch (nl_type) { + case NL80211_IFTYPE_AP: + *out_qdf_type = QDF_SAP_MODE; + break; + case NL80211_IFTYPE_MONITOR: + *out_qdf_type = QDF_MONITOR_MODE; + break; + case NL80211_IFTYPE_OCB: + *out_qdf_type = QDF_OCB_MODE; + break; + case NL80211_IFTYPE_P2P_CLIENT: + *out_qdf_type = QDF_P2P_CLIENT_MODE; + break; + case NL80211_IFTYPE_P2P_DEVICE: + *out_qdf_type = QDF_P2P_DEVICE_MODE; + break; + case NL80211_IFTYPE_P2P_GO: + *out_qdf_type = QDF_P2P_GO_MODE; + break; + case NL80211_IFTYPE_STATION: + *out_qdf_type = QDF_STA_MODE; + break; + case NL80211_IFTYPE_WDS: + *out_qdf_type = QDF_WDS_MODE; + break; + default: + status = wlan_hdd_convert_nan_type(nl_type, out_qdf_type); + if (QDF_IS_STATUS_SUCCESS(status)) + break; + hdd_err("Invalid nl80211 interface type %d", nl_type); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +uint8_t wlan_hdd_find_opclass(mac_handle_t mac_handle, uint8_t channel, + uint8_t bw_offset) +{ + uint8_t opclass = 0; + + sme_get_opclass(mac_handle, channel, bw_offset, &opclass); + return opclass; +} + +/** + * hdd_qdf_trace_enable() - configure initial QDF Trace enable + * @module_id: Module whose trace level is being configured + * @bitmask: Bitmask of log levels to be enabled + * + * Called immediately after the cfg.ini is read in order to configure + * the desired trace levels. + * + * Return: None + */ +int hdd_qdf_trace_enable(QDF_MODULE_ID module_id, uint32_t bitmask) +{ + QDF_TRACE_LEVEL level; + int qdf_print_idx = -1; + int status = -1; + /* + * if the bitmask is the default value, then a bitmask was not + * specified in cfg.ini, so leave the logging level alone (it + * will remain at the "compiled in" default value) + */ + if (CFG_QDF_TRACE_ENABLE_DEFAULT == bitmask) + return 0; + + qdf_print_idx = qdf_get_pidx(); + + /* a mask was specified. start by disabling all logging */ + status = qdf_print_set_category_verbose(qdf_print_idx, module_id, + QDF_TRACE_LEVEL_NONE, 0); + + if (QDF_STATUS_SUCCESS != status) + return -EINVAL; + /* now cycle through the bitmask until all "set" bits are serviced */ + level = QDF_TRACE_LEVEL_NONE; + while (0 != bitmask) { + if (bitmask & 1) { + status = qdf_print_set_category_verbose(qdf_print_idx, + module_id, level, 1); + if (QDF_STATUS_SUCCESS != status) + return -EINVAL; + } + + level++; + bitmask >>= 1; + } + return 0; +} + +int __wlan_hdd_validate_context(struct hdd_context *hdd_ctx, const char *func) +{ + if (!hdd_ctx) { + hdd_err("HDD context is null (via %s)", func); + return -ENODEV; + } + + if (!hdd_ctx->config) { + hdd_err("HDD config is null (via %s)", func); + return -ENODEV; + } + + if (cds_is_driver_recovering()) { + hdd_debug("Recovery in progress (via %s); state:0x%x", + func, cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_load_or_unload_in_progress()) { + hdd_debug("Load/unload in progress (via %s); state:0x%x", + func, cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_driver_in_bad_state()) { + hdd_debug("Driver in bad state (via %s); state:0x%x", + func, cds_get_driver_state()); + return -EAGAIN; + } + + if (cds_is_fw_down()) { + hdd_debug("FW is down (via %s); state:0x%x", + func, cds_get_driver_state()); + return -EAGAIN; + } + + if (hdd_ctx->is_wlan_disabled) { + hdd_debug("WLAN is disabled by user space"); + return -EAGAIN; + } + + return 0; +} + +int __hdd_validate_adapter(struct hdd_adapter *adapter, const char *func) +{ + if (!adapter) { + hdd_err("adapter is null (via %s)", func); + return -EINVAL; + } + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("bad adapter magic (via %s)", func); + return -EINVAL; + } + + if (!adapter->dev) { + hdd_err("adapter net_device is null (via %s)", func); + return -EINVAL; + } + + if (!(adapter->dev->flags & IFF_UP)) { + hdd_debug_rl("adapter '%s' is not up (via %s)", + adapter->dev->name, func); + return -EAGAIN; + } + + return __wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id, func); +} + +int __wlan_hdd_validate_vdev_id(uint8_t vdev_id, const char *func) +{ + if (vdev_id == WLAN_UMAC_VDEV_ID_MAX) { + hdd_debug_rl("adapter is not up (via %s)", func); + return -EINVAL; + } + + if (vdev_id >= WLAN_MAX_VDEVS) { + hdd_err("bad vdev Id:%u (via %s)", vdev_id, func); + return -EINVAL; + } + + return 0; +} + +QDF_STATUS __wlan_hdd_validate_mac_address(struct qdf_mac_addr *mac_addr, + const char *func) +{ + if (!mac_addr) { + hdd_err("Received NULL mac address (via %s)", func); + return QDF_STATUS_E_INVAL; + } + + if (qdf_is_macaddr_zero(mac_addr)) { + hdd_err("MAC is all zero (via %s)", func); + return QDF_STATUS_E_INVAL; + } + + if (qdf_is_macaddr_broadcast(mac_addr)) { + hdd_err("MAC is Broadcast (via %s)", func); + return QDF_STATUS_E_INVAL; + } + + if (QDF_NET_IS_MAC_MULTICAST(mac_addr->bytes)) { + hdd_err("MAC is Multicast (via %s)", func); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_validate_modules_state() - Check modules status + * @hdd_ctx: HDD context pointer + * + * Check's the driver module's state and returns true if the + * modules are enabled returns false if modules are closed. + * + * Return: True if modules are enabled or false. + */ +bool wlan_hdd_validate_modules_state(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_info("Modules not enabled, Present status: %d", + hdd_ctx->driver_status); + return false; + } + + return true; +} + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_runtime_suspend_context_init() - API to initialize HDD Runtime Contexts + * @hdd_ctx: HDD context + * + * Return: None + */ +static void hdd_runtime_suspend_context_init(struct hdd_context *hdd_ctx) +{ + struct hdd_runtime_pm_context *ctx = &hdd_ctx->runtime_context; + + qdf_runtime_lock_init(&ctx->dfs); + qdf_runtime_lock_init(&ctx->connect); + qdf_runtime_lock_init(&ctx->user); + qdf_runtime_lock_init(&ctx->monitor_mode); + qdf_runtime_lock_init(&ctx->wow_unit_test); + qdf_runtime_lock_init(&ctx->system_suspend); + qdf_runtime_lock_init(&ctx->dyn_mac_addr_update); + qdf_runtime_lock_init(&ctx->vdev_destroy); + qdf_runtime_lock_init(&ctx->oem_data_cmd); + + qdf_rtpm_register(QDF_RTPM_ID_WIPHY_SUSPEND, NULL); + qdf_rtpm_register(QDF_RTPM_ID_PM_QOS_NOTIFY, NULL); + + ctx->is_user_wakelock_acquired = false; + + wlan_scan_runtime_pm_init(hdd_ctx->pdev); +} + +/** + * hdd_runtime_suspend_context_deinit() - API to deinit HDD runtime context + * @hdd_ctx: HDD Context + * + * Return: None + */ +static void hdd_runtime_suspend_context_deinit(struct hdd_context *hdd_ctx) +{ + struct hdd_runtime_pm_context *ctx = &hdd_ctx->runtime_context; + + if (ctx->is_user_wakelock_acquired) + qdf_runtime_pm_allow_suspend(&ctx->user); + + qdf_runtime_lock_deinit(&ctx->oem_data_cmd); + qdf_runtime_lock_deinit(&ctx->dyn_mac_addr_update); + qdf_runtime_lock_deinit(&ctx->wow_unit_test); + qdf_runtime_lock_deinit(&ctx->monitor_mode); + qdf_runtime_lock_deinit(&ctx->user); + qdf_runtime_lock_deinit(&ctx->connect); + qdf_runtime_lock_deinit(&ctx->dfs); + qdf_runtime_lock_deinit(&ctx->system_suspend); + qdf_runtime_lock_deinit(&ctx->vdev_destroy); + + qdf_rtpm_deregister(QDF_RTPM_ID_WIPHY_SUSPEND); + qdf_rtpm_deregister(QDF_RTPM_ID_PM_QOS_NOTIFY); + + wlan_scan_runtime_pm_deinit(hdd_ctx->pdev); +} + +#else /* FEATURE_RUNTIME_PM */ +static void hdd_runtime_suspend_context_init(struct hdd_context *hdd_ctx) {} +static void hdd_runtime_suspend_context_deinit(struct hdd_context *hdd_ctx) {} +#endif /* FEATURE_RUNTIME_PM */ + +void hdd_update_macaddr(struct hdd_context *hdd_ctx, + struct qdf_mac_addr hw_macaddr, bool generate_mac_auto) +{ + int8_t i; + uint8_t macaddr_b3, tmp_br3; + + /* + * If "generate_mac_auto" is true, it indicates that all the + * addresses are derived addresses, else the first addresses + * is not derived address (It is provided by fw). + */ + if (!generate_mac_auto) { + qdf_mem_copy(hdd_ctx->provisioned_mac_addr[0].bytes, + hw_macaddr.bytes, QDF_MAC_ADDR_SIZE); + hdd_ctx->num_provisioned_addr++; + hdd_debug("hdd_ctx->provisioned_mac_addr[0]: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdd_ctx-> + provisioned_mac_addr[0].bytes)); + } else { + qdf_mem_copy(hdd_ctx->derived_mac_addr[0].bytes, + hw_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + hdd_ctx->num_derived_addr++; + hdd_debug("hdd_ctx->derived_mac_addr[0]: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdd_ctx->derived_mac_addr[0].bytes)); + } + for (i = hdd_ctx->num_derived_addr; i < (QDF_MAX_CONCURRENCY_PERSONA - + hdd_ctx->num_provisioned_addr); + i++) { + qdf_mem_copy(hdd_ctx->derived_mac_addr[i].bytes, + hw_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + macaddr_b3 = hdd_ctx->derived_mac_addr[i].bytes[3]; + tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + i) & + INTF_MACADDR_MASK; + macaddr_b3 += tmp_br3; + + /* XOR-ing bit-24 of the mac address. This will give enough + * mac address range before collision + */ + macaddr_b3 ^= (1 << 7); + + /* Set locally administered bit */ + hdd_ctx->derived_mac_addr[i].bytes[0] |= 0x02; + hdd_ctx->derived_mac_addr[i].bytes[3] = macaddr_b3; + hdd_debug("hdd_ctx->derived_mac_addr[%d]: " + QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF(hdd_ctx->derived_mac_addr[i].bytes)); + hdd_ctx->num_derived_addr++; + } +} + +#ifdef FEATURE_WLAN_TDLS +static int hdd_update_tdls_config(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct tdls_start_params tdls_cfg; + QDF_STATUS status; + struct wlan_mlme_nss_chains vdev_ini_cfg; + + /* Populate the nss chain params from ini for this vdev type */ + sme_populate_nss_chain_params(hdd_ctx->mac_handle, &vdev_ini_cfg, + QDF_TDLS_MODE, + hdd_ctx->num_rf_chains); + + cfg_tdls_set_vdev_nss_2g(hdd_ctx->psoc, + vdev_ini_cfg.rx_nss[NSS_CHAINS_BAND_2GHZ]); + cfg_tdls_set_vdev_nss_5g(hdd_ctx->psoc, + vdev_ini_cfg.rx_nss[NSS_CHAINS_BAND_5GHZ]); + hdd_init_tdls_config(&tdls_cfg); + tdls_cfg.tdls_del_all_peers = eWNI_SME_DEL_ALL_TDLS_PEERS; + tdls_cfg.tdls_update_dp_vdev_flags = CDP_UPDATE_TDLS_FLAGS; + tdls_cfg.tdls_event_cb = wlan_cfg80211_tdls_event_callback; + tdls_cfg.tdls_evt_cb_data = psoc; + tdls_cfg.tdls_peer_context = hdd_ctx; + tdls_cfg.tdls_reg_peer = hdd_tdls_register_peer; + tdls_cfg.tdls_wmm_cb = hdd_wmm_is_acm_allowed; + tdls_cfg.tdls_wmm_cb_data = psoc; + tdls_cfg.tdls_rx_cb = wlan_cfg80211_tdls_rx_callback; + tdls_cfg.tdls_rx_cb_data = psoc; + tdls_cfg.tdls_dp_vdev_update = hdd_update_dp_vdev_flags; + tdls_cfg.tdls_osif_init_cb = wlan_cfg80211_tdls_osif_priv_init; + tdls_cfg.tdls_osif_deinit_cb = wlan_cfg80211_tdls_osif_priv_deinit; + tdls_cfg.tdls_osif_update_cb.tdls_osif_conn_update = + hdd_check_and_set_tdls_conn_params; + tdls_cfg.tdls_osif_update_cb.tdls_osif_disconn_update = + hdd_check_and_set_tdls_disconn_params; + + status = ucfg_tdls_update_config(psoc, &tdls_cfg); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed pmo psoc configuration"); + return -EINVAL; + } + + hdd_ctx->tdls_umac_comp_active = true; + /* enable napier specific tdls data path */ + hdd_ctx->tdls_nap_active = true; + + return 0; +} +#else +static int hdd_update_tdls_config(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +void hdd_indicate_active_ndp_cnt(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t cnt) +{ + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info || !cfg_nan_is_roam_config_disabled(psoc)) + return; + + hdd_debug("vdev_id:%d%s active ndp sessions present", vdev_id, + cnt ? "" : " no more"); + if (!cnt) + wlan_hdd_set_roaming_state(link_info, RSO_NDP_CON_ON_NDI, true); + else + wlan_hdd_set_roaming_state(link_info, RSO_NDP_CON_ON_NDI, + false); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void hdd_update_roam_offload(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + bool roam_offload_enable; + + ucfg_mlme_get_roaming_offload(hdd_ctx->psoc, &roam_offload_enable); + ucfg_mlme_set_roaming_offload(hdd_ctx->psoc, + roam_offload_enable & + cfg->en_roam_offload); +} +#else +static inline void hdd_update_roam_offload(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ +} +#endif + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +static void +hdd_club_ll_stats_in_get_sta_cfg_update(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->sta_stats_cache_expiry_time = + cfg_get(psoc, CFG_STA_STATS_CACHE_EXPIRY); +} + +static void +hdd_update_feature_cfg_club_get_sta_in_ll_stats_req( + struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + hdd_ctx->is_get_station_clubbed_in_ll_stats_req = + cfg->is_get_station_clubbed_in_ll_stats_req && + cfg_get(hdd_ctx->psoc, + CFG_CLUB_LL_STA_AND_GET_STATION); +} + +static void +hdd_init_get_sta_in_ll_stats_config(struct hdd_adapter *adapter) +{ + adapter->sta_stats_cached_timestamp = 0; +} +#else +static void +hdd_club_ll_stats_in_get_sta_cfg_update(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} + +static void +hdd_update_feature_cfg_club_get_sta_in_ll_stats_req( + struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ +} + +static void +hdd_init_get_sta_in_ll_stats_config(struct hdd_adapter *adapter) +{ +} +#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */ + +#ifdef WLAN_FEATURE_11BE_MLO + +static void +hdd_init_link_state_cfg(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->link_state_cache_expiry_time = + cfg_get(psoc, CFG_LINK_STATE_CACHE_EXPIRY); +} + +static void +hdd_init_link_state_config(struct hdd_adapter *adapter) +{ + adapter->link_state_cached_timestamp = 0; +} + +#else +static void +hdd_init_link_state_cfg(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} + +static void +hdd_init_link_state_config(struct hdd_adapter *adapter) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +static void +hdd_intersect_igmp_offload_setting(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_services *cfg) +{ + bool igmp_offload_enable; + + igmp_offload_enable = + ucfg_pmo_is_igmp_offload_enabled(psoc); + ucfg_pmo_set_igmp_offload_enabled(psoc, + igmp_offload_enable & + cfg->igmp_offload_enable); + hdd_info("fw cap to handle igmp %d igmp_offload_enable ini %d", + cfg->igmp_offload_enable, igmp_offload_enable); +} +#else +static inline void +hdd_intersect_igmp_offload_setting(struct wlan_objmgr_psoc *psoc, + struct wma_tgt_services *cfg) +{} +#endif + +#ifdef FEATURE_WLAN_TDLS +static void hdd_update_fw_tdls_wideband_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + ucfg_tdls_update_fw_wideband_capability(hdd_ctx->psoc, + cfg->en_tdls_wideband_support); +} + +#ifdef WLAN_FEATURE_11BE +static void hdd_update_fw_tdls_mlo_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + ucfg_tdls_update_fw_mlo_capability(hdd_ctx->psoc, + cfg->en_tdls_mlo_support); +} +#else +static inline +void hdd_update_fw_tdls_mlo_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} +#endif + +#ifdef WLAN_FEATURE_11AX +static void hdd_update_fw_tdls_11ax_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + ucfg_tdls_update_fw_11ax_capability(hdd_ctx->psoc, + cfg->en_tdls_11ax_support); +} + +static void hdd_update_fw_tdls_6g_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + ucfg_update_fw_tdls_6g_capability(hdd_ctx->psoc, + cfg->en_tdls_6g_support); +} + +#else +static inline +void hdd_update_fw_tdls_11ax_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} +static inline +void hdd_update_fw_tdls_6g_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} +#endif +#else +static inline +void hdd_update_fw_tdls_mlo_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} + +static inline +void hdd_update_fw_tdls_11ax_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} + +static inline +void hdd_update_fw_tdls_6g_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} + +static inline +void hdd_update_fw_tdls_wideband_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{} +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +static inline void +hdd_set_dynamic_macaddr_update_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + hdd_ctx->is_vdev_macaddr_dynamic_update_supported = + cfg->dynamic_vdev_macaddr_support && + cfg_get(hdd_ctx->psoc, + CFG_DYNAMIC_MAC_ADDR_UPDATE_SUPPORTED); +} +#else +static inline void +hdd_set_dynamic_macaddr_update_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +static bool hdd_dot11Mode_support_11be(enum hdd_dot11_mode dot11Mode) +{ + if (dot11Mode != eHDD_DOT11_MODE_AUTO && + dot11Mode < eHDD_DOT11_MODE_11be) + return false; + + return true; +} + +static void +hdd_update_tid_to_link_supported(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + if (!cfg->en_mlo_tid_to_link_support) + ucfg_mlme_set_t2lm_negotiation_supported(hdd_ctx->psoc, + T2LM_NEGOTIATION_DISABLED); +} + +#else +static bool hdd_dot11Mode_support_11be(enum hdd_dot11_mode dot11Mode) +{ + return false; +} + +static inline void +hdd_update_tid_to_link_supported(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static void +hdd_update_mlo_per_link_stats_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + hdd_ctx->is_mlo_per_link_stats_supported = + cfg->is_mlo_per_link_stats_supported; +} +#else +static void +hdd_update_mlo_per_link_stats_capability(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ +} +#endif + +static void hdd_update_tgt_services(struct hdd_context *hdd_ctx, + struct wma_tgt_services *cfg) +{ + struct hdd_config *config = hdd_ctx->config; + bool arp_offload_enable; + bool mawc_enabled; +#ifdef FEATURE_WLAN_TDLS + bool tdls_support; + bool tdls_off_channel; + bool tdls_buffer_sta; + uint32_t tdls_uapsd_mask; +#endif + bool get_peer_info_enable; + + /* Set up UAPSD */ + ucfg_mlme_set_sap_uapsd_flag(hdd_ctx->psoc, cfg->uapsd); + + /* 11AX mode support */ + if ((config->dot11Mode == eHDD_DOT11_MODE_11ax || + config->dot11Mode == eHDD_DOT11_MODE_11ax_ONLY) && !cfg->en_11ax) + config->dot11Mode = eHDD_DOT11_MODE_11ac; + + /* 11AC mode support */ + if ((config->dot11Mode == eHDD_DOT11_MODE_11ac || + config->dot11Mode == eHDD_DOT11_MODE_11ac_ONLY) && !cfg->en_11ac) + config->dot11Mode = eHDD_DOT11_MODE_AUTO; + + /* 11BE mode support */ + if (cfg->en_11be && + (!hdd_dot11Mode_support_11be(config->dot11Mode) || + !wlan_reg_phybitmap_support_11be(hdd_ctx->pdev))) { + hdd_debug("dot11Mode %d override target en_11be to false", + config->dot11Mode); + cfg->en_11be = false; + } + + /* ARP offload: override user setting if invalid */ + arp_offload_enable = + ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc); + ucfg_pmo_set_arp_offload_enabled(hdd_ctx->psoc, + arp_offload_enable & cfg->arp_offload); + + /* Intersect igmp offload ini configuration and fw cap*/ + hdd_intersect_igmp_offload_setting(hdd_ctx->psoc, cfg); + +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + hdd_debug("PNO Capability in f/w = %d", cfg->pno_offload); + if (cfg->pno_offload) + ucfg_scan_set_pno_offload(hdd_ctx->psoc, true); +#endif +#ifdef FEATURE_WLAN_TDLS + cfg_tdls_get_support_enable(hdd_ctx->psoc, &tdls_support); + cfg_tdls_set_support_enable(hdd_ctx->psoc, + tdls_support & cfg->en_tdls); + + cfg_tdls_get_off_channel_enable(hdd_ctx->psoc, &tdls_off_channel); + cfg_tdls_set_off_channel_enable(hdd_ctx->psoc, + tdls_off_channel && + cfg->en_tdls_offchan); + + cfg_tdls_get_buffer_sta_enable(hdd_ctx->psoc, &tdls_buffer_sta); + cfg_tdls_set_buffer_sta_enable(hdd_ctx->psoc, + tdls_buffer_sta && + cfg->en_tdls_uapsd_buf_sta); + + cfg_tdls_get_uapsd_mask(hdd_ctx->psoc, &tdls_uapsd_mask); + if (tdls_uapsd_mask && cfg->en_tdls_uapsd_sleep_sta) + cfg_tdls_set_sleep_sta_enable(hdd_ctx->psoc, true); + else + cfg_tdls_set_sleep_sta_enable(hdd_ctx->psoc, false); +#endif + hdd_update_roam_offload(hdd_ctx, cfg); + + if (ucfg_mlme_get_sap_get_peer_info( + hdd_ctx->psoc, &get_peer_info_enable) == QDF_STATUS_SUCCESS) { + get_peer_info_enable &= cfg->get_peer_info_enabled; + ucfg_mlme_set_sap_get_peer_info(hdd_ctx->psoc, + get_peer_info_enable); + } + + ucfg_mlme_is_mawc_enabled(hdd_ctx->psoc, &mawc_enabled); + ucfg_mlme_set_mawc_enabled(hdd_ctx->psoc, + mawc_enabled & cfg->is_fw_mawc_capable); + hdd_update_tdls_config(hdd_ctx); + sme_update_tgt_services(hdd_ctx->mac_handle, cfg); + hdd_ctx->roam_ch_from_fw_supported = cfg->is_roam_scan_ch_to_host; + hdd_ctx->ll_stats_per_chan_rx_tx_time = + cfg->ll_stats_per_chan_rx_tx_time; + + hdd_update_feature_cfg_club_get_sta_in_ll_stats_req(hdd_ctx, cfg); + hdd_ctx->is_therm_cmd_supp = + cfg->is_fw_therm_throt_supp && + cfg_get(hdd_ctx->psoc, + CFG_THERMAL_MITIGATION_ENABLE); + hdd_update_fw_tdls_11ax_capability(hdd_ctx, cfg); + hdd_update_fw_tdls_mlo_capability(hdd_ctx, cfg); + hdd_set_dynamic_macaddr_update_capability(hdd_ctx, cfg); + hdd_update_fw_tdls_6g_capability(hdd_ctx, cfg); + hdd_update_fw_tdls_wideband_capability(hdd_ctx, cfg); + ucfg_psoc_mlme_set_11be_capab(hdd_ctx->psoc, cfg->en_11be); + hdd_update_mlo_per_link_stats_capability(hdd_ctx, cfg); +} + +/** + * hdd_update_vdev_nss() - sets the vdev nss + * @hdd_ctx: HDD context + * + * Sets the Nss per vdev type based on INI + * + * Return: None + */ +static void hdd_update_vdev_nss(struct hdd_context *hdd_ctx) +{ + uint8_t max_supp_nss = 1; + mac_handle_t mac_handle; + QDF_STATUS status; + bool bval; + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + if (bval && !cds_is_sub_20_mhz_enabled()) + max_supp_nss = 2; + + hdd_debug("max nss %d", max_supp_nss); + + mac_handle = hdd_ctx->mac_handle; + sme_update_vdev_type_nss(mac_handle, max_supp_nss, + NSS_CHAINS_BAND_2GHZ); + + sme_update_vdev_type_nss(mac_handle, max_supp_nss, + NSS_CHAINS_BAND_5GHZ); +} + +/** + * hdd_update_2g_wiphy_vhtcap() - Updates 2G wiphy vhtcap fields + * @hdd_ctx: HDD context + * + * Updates 2G wiphy vhtcap fields + * + * Return: None + */ +static void hdd_update_2g_wiphy_vhtcap(struct hdd_context *hdd_ctx) +{ + struct ieee80211_supported_band *band_2g = + hdd_ctx->wiphy->bands[NL80211_BAND_2GHZ]; + uint32_t value; + bool is_vht_24ghz; + + if (!band_2g) { + hdd_debug("2GHz band disabled, skipping capability population"); + return; + } + + ucfg_mlme_get_vht_for_24ghz(hdd_ctx->psoc, &is_vht_24ghz); + + if (is_vht_24ghz) { + ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc, &value); + band_2g->vht_cap.vht_mcs.tx_mcs_map = value; + } +} + +/** + * hdd_update_5g_wiphy_vhtcap() - Updates 5G wiphy vhtcap fields + * @hdd_ctx: HDD context + * + * Updates 5G wiphy vhtcap fields + * + * Return: None + */ +static void hdd_update_5g_wiphy_vhtcap(struct hdd_context *hdd_ctx) +{ + struct ieee80211_supported_band *band_5g = + hdd_ctx->wiphy->bands[NL80211_BAND_5GHZ]; + QDF_STATUS status; + uint8_t value = 0, value1 = 0; + uint32_t value2; + + if (!band_5g) { + hdd_debug("5GHz band disabled, skipping capability population"); + return; + } + + status = ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp(hdd_ctx->psoc, + &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get tx_bfee_ant_supp"); + + band_5g->vht_cap.cap |= + (value << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT); + + value1 = NUM_OF_SOUNDING_DIMENSIONS; + band_5g->vht_cap.cap |= + (value1 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT); + + hdd_debug("Updated wiphy vhtcap:0x%x, CSNAntSupp:%d, NumSoundDim:%d", + band_5g->vht_cap.cap, value, value1); + + ucfg_mlme_cfg_get_vht_rx_mcs_map(hdd_ctx->psoc, &value2); + band_5g->vht_cap.vht_mcs.rx_mcs_map = value2; + + ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc, &value2); + band_5g->vht_cap.vht_mcs.tx_mcs_map = value2; +} + +/** + * hdd_update_wiphy_vhtcap() - Updates wiphy vhtcap fields + * @hdd_ctx: HDD context + * + * Updates wiphy vhtcap fields + * + * Return: None + */ +static void hdd_update_wiphy_vhtcap(struct hdd_context *hdd_ctx) +{ + hdd_update_2g_wiphy_vhtcap(hdd_ctx); + hdd_update_5g_wiphy_vhtcap(hdd_ctx); +} + +static void hdd_update_tgt_ht_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_ht_cap *cfg) +{ + QDF_STATUS status; + qdf_size_t value_len; + uint32_t value; + uint8_t mpdu_density; + struct mlme_ht_capabilities_info ht_cap_info; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + bool b_enable1x1; + + /* get the MPDU density */ + status = ucfg_mlme_get_ht_mpdu_density(hdd_ctx->psoc, &mpdu_density); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get HT MPDU Density"); + return; + } + + /* + * MPDU density: + * override user's setting if value is larger + * than the one supported by target, + * if target value is 0, then follow user's setting. + */ + if (cfg->mpdu_density && mpdu_density > cfg->mpdu_density) { + status = ucfg_mlme_set_ht_mpdu_density(hdd_ctx->psoc, + cfg->mpdu_density); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set HT capability to CCM"); + } + + /* get the HT capability info */ + status = ucfg_mlme_get_ht_cap_info(hdd_ctx->psoc, &ht_cap_info); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("could not get HT capability info"); + return; + } + + /* check and update RX STBC */ + if (ht_cap_info.rx_stbc && !cfg->ht_rx_stbc) + ht_cap_info.rx_stbc = cfg->ht_rx_stbc; + + /* Set the LDPC capability */ + if (ht_cap_info.adv_coding_cap && !cfg->ht_rx_ldpc) + ht_cap_info.adv_coding_cap = cfg->ht_rx_ldpc; + + if (ht_cap_info.short_gi_20_mhz && !cfg->ht_sgi_20) + ht_cap_info.short_gi_20_mhz = cfg->ht_sgi_20; + + if (ht_cap_info.short_gi_40_mhz && !cfg->ht_sgi_40) + ht_cap_info.short_gi_40_mhz = cfg->ht_sgi_40; + + hdd_debug("gHtSMPS ini: %d, dynamic_smps fw cap: %d", + ht_cap_info.mimo_power_save, cfg->dynamic_smps); + if (ht_cap_info.mimo_power_save == HDD_SMPS_MODE_DYNAMIC) { + if (cfg->dynamic_smps) + ht_cap_info.mimo_power_save = HDD_SMPS_MODE_DYNAMIC; + else + ht_cap_info.mimo_power_save = HDD_SMPS_MODE_DISABLED; + } + + hdd_ctx->num_rf_chains = cfg->num_rf_chains; + hdd_ctx->ht_tx_stbc_supported = cfg->ht_tx_stbc; + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &b_enable1x1); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + b_enable1x1 = b_enable1x1 && (cfg->num_rf_chains == 2); + + status = ucfg_mlme_set_vht_enable2x2(hdd_ctx->psoc, b_enable1x1); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to set vht_enable2x2"); + + if (!b_enable1x1) + ht_cap_info.tx_stbc = 0; + + if (!(cfg->ht_tx_stbc && b_enable1x1)) + ht_cap_info.tx_stbc = 0; + + status = ucfg_mlme_set_ht_cap_info(hdd_ctx->psoc, ht_cap_info); + if (status != QDF_STATUS_SUCCESS) + hdd_err("could not set HT capability to CCM"); +#define WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES 0xff + value_len = SIZE_OF_SUPPORTED_MCS_SET; + if (ucfg_mlme_get_supported_mcs_set( + hdd_ctx->psoc, mcs_set, + &value_len) == QDF_STATUS_SUCCESS) { + hdd_debug("Read MCS rate set"); + if (cfg->num_rf_chains > SIZE_OF_SUPPORTED_MCS_SET) + cfg->num_rf_chains = SIZE_OF_SUPPORTED_MCS_SET; + + if (b_enable1x1) { + for (value = 0; value < cfg->num_rf_chains; value++) + mcs_set[value] = + WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES; + + status = ucfg_mlme_set_supported_mcs_set( + hdd_ctx->psoc, + mcs_set, + (qdf_size_t)SIZE_OF_SUPPORTED_MCS_SET); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set MCS SET to CCM"); + } + } +#undef WLAN_HDD_RX_MCS_ALL_NSTREAM_RATES +} + +static void hdd_update_tgt_vht_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_vht_cap *cfg) +{ + QDF_STATUS status; + struct wiphy *wiphy = hdd_ctx->wiphy; + struct ieee80211_supported_band *band_5g = + wiphy->bands[HDD_NL80211_BAND_5GHZ]; + uint32_t ch_width; + struct wma_caps_per_phy caps_per_phy = {0}; + bool vht_enable_2x2; + uint32_t tx_highest_data_rate; + uint32_t rx_highest_data_rate; + + if (!band_5g) { + hdd_debug("5GHz band disabled, skipping capability population"); + return; + } + + status = ucfg_mlme_update_vht_cap(hdd_ctx->psoc, cfg); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not update vht capabilities"); + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &vht_enable_2x2); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + if (vht_enable_2x2) { + tx_highest_data_rate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + rx_highest_data_rate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2; + } else { + tx_highest_data_rate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + rx_highest_data_rate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + + status = ucfg_mlme_cfg_set_vht_rx_supp_data_rate(hdd_ctx->psoc, + rx_highest_data_rate); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set rx_supp_data_rate"); + + status = ucfg_mlme_cfg_set_vht_tx_supp_data_rate(hdd_ctx->psoc, + tx_highest_data_rate); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set tx_supp_data_rate"); + + /* Update the real highest data rate to wiphy */ + if (cfg->vht_short_gi_80 & WMI_VHT_CAP_SGI_80MHZ) { + if (vht_enable_2x2) { + tx_highest_data_rate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2_SGI80; + rx_highest_data_rate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2_SGI80; + } else { + tx_highest_data_rate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1_SGI80; + rx_highest_data_rate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1_SGI80; + } + } + + if (WMI_VHT_CAP_MAX_MPDU_LEN_11454 == cfg->vht_max_mpdu) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; + else if (WMI_VHT_CAP_MAX_MPDU_LEN_7935 == cfg->vht_max_mpdu) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991; + else + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; + + + if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_80P80MHZ)) { + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; + ch_width = VHT_CAP_160_AND_80P80_SUPP; + } else if (cfg->supp_chan_width & (1 << eHT_CHANNEL_WIDTH_160MHZ)) { + band_5g->vht_cap.cap |= + IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; + ch_width = VHT_CAP_160_SUPP; + } else { + ch_width = VHT_CAP_NO_160M_SUPP; + } + + status = ucfg_mlme_set_vht_ch_width(hdd_ctx->psoc, ch_width); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set the channel width"); + else + hdd_debug("supported channel width %d", ch_width); + + if (cfg->vht_rx_ldpc & WMI_VHT_CAP_RX_LDPC) { + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; + hdd_debug("VHT RxLDPC capability is set"); + } else { + /* + * Get the RX LDPC capability for the NON DBS + * hardware mode for 5G band + */ + status = wma_get_caps_for_phyidx_hwmode(&caps_per_phy, + HW_MODE_DBS_NONE, CDS_BAND_5GHZ); + if ((QDF_IS_STATUS_SUCCESS(status)) && + (caps_per_phy.vht_5g & WMI_VHT_CAP_RX_LDPC)) { + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXLDPC; + hdd_debug("VHT RX LDPC capability is set"); + } + } + + if (cfg->vht_short_gi_80 & WMI_VHT_CAP_SGI_80MHZ) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_80; + if (cfg->vht_short_gi_160 & WMI_VHT_CAP_SGI_160MHZ) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SHORT_GI_160; + + if (vht_enable_2x2 && (cfg->vht_tx_stbc & WMI_VHT_CAP_TX_STBC)) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_TXSTBC; + + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_1SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_1; + if (vht_enable_2x2 && (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_2SS)) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_2; + if (cfg->vht_rx_stbc & WMI_VHT_CAP_RX_STBC_3SS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_RXSTBC_3; + + band_5g->vht_cap.cap |= + (cfg->vht_max_ampdu_len_exp << + IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); + + if (cfg->vht_su_bformer & WMI_VHT_CAP_SU_BFORMER) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE; + if (cfg->vht_su_bformee & WMI_VHT_CAP_SU_BFORMEE) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + if (cfg->vht_mu_bformer & WMI_VHT_CAP_MU_BFORMER) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE; + if (cfg->vht_mu_bformee & WMI_VHT_CAP_MU_BFORMEE) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + if (cfg->vht_txop_ps & WMI_VHT_CAP_TXOP_PS) + band_5g->vht_cap.cap |= IEEE80211_VHT_CAP_VHT_TXOP_PS; + + band_5g->vht_cap.vht_mcs.rx_highest = cpu_to_le16(rx_highest_data_rate); + band_5g->vht_cap.vht_mcs.tx_highest = cpu_to_le16(tx_highest_data_rate); +} + +/** + * hdd_generate_macaddr_auto() - Auto-generate mac address + * @hdd_ctx: Pointer to the HDD context + * + * Auto-generate mac address using device serial number. + * Keep the first 3 bytes of OUI as before and replace + * the last 3 bytes with the lower 3 bytes of serial number. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int hdd_generate_macaddr_auto(struct hdd_context *hdd_ctx) +{ + unsigned int serialno = 0; + struct qdf_mac_addr mac_addr = { + {0x00, 0x0A, 0xF5, 0x00, 0x00, 0x00} + }; + + serialno = pld_socinfo_get_serial_number(hdd_ctx->parent_dev); + if (serialno == 0) + return -EINVAL; + + serialno &= 0x00ffffff; + + mac_addr.bytes[3] = (serialno >> 16) & 0xff; + mac_addr.bytes[4] = (serialno >> 8) & 0xff; + mac_addr.bytes[5] = serialno & 0xff; + + hdd_update_macaddr(hdd_ctx, mac_addr, true); + return 0; +} + +static void hdd_sar_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + hdd_ctx->sar_version = cfg->sar_version; +} + +static void hdd_update_vhtcap_2g(struct hdd_context *hdd_ctx) +{ + uint64_t chip_mode = 0; + QDF_STATUS status; + bool b2g_vht_cfg = false; + bool b2g_vht_target = false; + struct wma_caps_per_phy caps_per_phy = {0}; + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(hdd_ctx->psoc); + if (!wmi_handle) { + hdd_err("wmi handle is NULL"); + return; + } + + status = ucfg_mlme_get_vht_for_24ghz(hdd_ctx->psoc, &b2g_vht_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get 2g vht mode"); + return; + } + if (wmi_service_enabled(wmi_handle, wmi_service_ext_msg)) { + status = wma_get_caps_for_phyidx_hwmode(&caps_per_phy, + HW_MODE_DBS_NONE, + CDS_BAND_2GHZ); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get phy caps"); + return; + } + if (caps_per_phy.vht_2g) + b2g_vht_target = true; + } else { + status = wlan_reg_get_chip_mode(hdd_ctx->pdev, &chip_mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get chip mode"); + return; + } + b2g_vht_target = + (chip_mode & HOST_REGDMN_MODE_11AC_VHT20_2G) ? + true : false; + } + + b2g_vht_cfg = b2g_vht_cfg && b2g_vht_target; + hdd_debug("vht 2g target: %d, cfg: %d", b2g_vht_target, b2g_vht_cfg); + status = ucfg_mlme_set_vht_for_24ghz(hdd_ctx->psoc, b2g_vht_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update 2g vht mode"); + return; + } +} + +static void hdd_extract_fw_version_info(struct hdd_context *hdd_ctx) +{ + hdd_ctx->fw_version_info.major_spid = + HDD_FW_VER_MAJOR_SPID(hdd_ctx->target_fw_version); + hdd_ctx->fw_version_info.minor_spid = + HDD_FW_VER_MINOR_SPID(hdd_ctx->target_fw_version); + hdd_ctx->fw_version_info.siid = + HDD_FW_VER_SIID(hdd_ctx->target_fw_version); + hdd_ctx->fw_version_info.crmid = + HDD_FW_VER_CRM_ID(hdd_ctx->target_fw_version); + hdd_ctx->fw_version_info.sub_id = + HDD_FW_VER_SUB_ID(hdd_ctx->target_fw_vers_ext); + hdd_ctx->fw_version_info.rel_id = + HDD_FW_VER_REL_ID(hdd_ctx->target_fw_vers_ext); +} + +#if defined(WLAN_FEATURE_11AX) && \ + (defined(CFG80211_SBAND_IFTYPE_DATA_BACKPORT) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0))) + +static void +hdd_update_wiphy_he_mcs(struct ieee80211_sband_iftype_data *iftype_data, + tDot11fIEhe_cap *he_cap_cfg) +{ + if (!iftype_data || !he_cap_cfg) { + hdd_err("Unable to update wiphy he_mcs"); + return; + } + + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80 = + he_cap_cfg->tx_he_mcs_map_lt_80; + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160 = + *((uint16_t *)he_cap_cfg->tx_he_mcs_map_160); + iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_80p80 = + *((uint16_t *)he_cap_cfg->tx_he_mcs_map_80_80); +} + +#if defined(CONFIG_BAND_6GHZ) && (defined(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START)) +static void hdd_update_wiphy_he_6ghz_capa(struct hdd_context *hdd_ctx) +{ + uint16_t he_6ghz_capa = 0; + uint8_t min_mpdu_start_spacing; + uint8_t max_ampdu_len_exp; + uint8_t max_mpdu_len; + uint8_t sm_pow_save; + + ucfg_mlme_get_ht_mpdu_density(hdd_ctx->psoc, &min_mpdu_start_spacing); + he_6ghz_capa |= FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START, + min_mpdu_start_spacing); + + ucfg_mlme_cfg_get_vht_ampdu_len_exp(hdd_ctx->psoc, &max_ampdu_len_exp); + he_6ghz_capa |= FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP, + max_ampdu_len_exp); + + ucfg_mlme_cfg_get_vht_max_mpdu_len(hdd_ctx->psoc, &max_mpdu_len); + he_6ghz_capa |= FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN, + max_mpdu_len); + + ucfg_mlme_cfg_get_ht_smps(hdd_ctx->psoc, &sm_pow_save); + he_6ghz_capa |= FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS, sm_pow_save); + + he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS; + he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS; + + hdd_ctx->iftype_data_6g->he_6ghz_capa.capa = he_6ghz_capa; +} +#else +static inline void hdd_update_wiphy_he_6ghz_capa(struct hdd_context *hdd_ctx) +{ +} +#endif + +#if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \ + (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)) +static void +hdd_update_wiphy_he_caps_6ghz(struct hdd_context *hdd_ctx, + tDot11fIEhe_cap *he_cap_cfg) +{ + struct ieee80211_supported_band *band_6g = + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_6GHZ]; + uint8_t *phy_info = + hdd_ctx->iftype_data_6g->he_cap.he_cap_elem.phy_cap_info; + uint8_t *mac_info_6g = + hdd_ctx->iftype_data_6g->he_cap.he_cap_elem.mac_cap_info; + uint8_t max_fw_bw = sme_get_vht_ch_width(); + + if (!band_6g || !phy_info) { + hdd_debug("6ghz not supported in wiphy"); + return; + } + + hdd_ctx->iftype_data_6g->types_mask = + (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); + hdd_ctx->iftype_data_6g->he_cap.has_he = true; + band_6g->n_iftype_data = 1; + + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + phy_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + phy_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + phy_info[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + + if (he_cap_cfg->twt_request) + mac_info_6g[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; + + if (he_cap_cfg->twt_responder) + mac_info_6g[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES; + + hdd_update_wiphy_he_6ghz_capa(hdd_ctx); + + hdd_update_wiphy_he_mcs(hdd_ctx->iftype_data_6g, he_cap_cfg); + + band_6g->iftype_data = hdd_ctx->iftype_data_6g; +} +#else +static inline void +hdd_update_wiphy_he_caps_6ghz(struct hdd_context *hdd_ctx, + tDot11fIEhe_cap *he_cap_cfg) +{ +} +#endif + +static void hdd_update_wiphy_he_cap(struct hdd_context *hdd_ctx) +{ + tDot11fIEhe_cap he_cap_cfg; + struct ieee80211_supported_band *band_2g = + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_2GHZ]; + struct ieee80211_supported_band *band_5g = + hdd_ctx->wiphy->bands[HDD_NL80211_BAND_5GHZ]; + QDF_STATUS status; + uint8_t *phy_info_5g = + hdd_ctx->iftype_data_5g->he_cap.he_cap_elem.phy_cap_info; + uint8_t max_fw_bw = sme_get_vht_ch_width(); + uint32_t channel_bonding_mode_2g; + uint8_t *phy_info_2g = + hdd_ctx->iftype_data_2g->he_cap.he_cap_elem.phy_cap_info; + uint8_t *mac_info_2g = + hdd_ctx->iftype_data_2g->he_cap.he_cap_elem.mac_cap_info; + uint8_t *mac_info_5g = + hdd_ctx->iftype_data_5g->he_cap.he_cap_elem.mac_cap_info; + + status = ucfg_mlme_cfg_get_he_caps(hdd_ctx->psoc, &he_cap_cfg); + + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (band_2g) { + hdd_ctx->iftype_data_2g->types_mask = + (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); + hdd_ctx->iftype_data_2g->he_cap.has_he = he_cap_cfg.present; + band_2g->n_iftype_data = 1; + hdd_update_wiphy_he_mcs(hdd_ctx->iftype_data_2g, &he_cap_cfg); + band_2g->iftype_data = hdd_ctx->iftype_data_2g; + + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode_2g); + if (channel_bonding_mode_2g) + phy_info_2g[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G; + + if (he_cap_cfg.twt_request) + mac_info_2g[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; + + if (he_cap_cfg.twt_responder) + mac_info_2g[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES; + } + if (band_5g) { + hdd_ctx->iftype_data_5g->types_mask = + (BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_AP)); + hdd_ctx->iftype_data_5g->he_cap.has_he = he_cap_cfg.present; + band_5g->n_iftype_data = 1; + hdd_update_wiphy_he_mcs(hdd_ctx->iftype_data_5g, &he_cap_cfg); + band_5g->iftype_data = hdd_ctx->iftype_data_5g; + + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + phy_info_5g[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G; + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + phy_info_5g[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) + phy_info_5g[0] |= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; + + if (he_cap_cfg.twt_request) + mac_info_5g[0] |= IEEE80211_HE_MAC_CAP0_TWT_REQ; + + if (he_cap_cfg.twt_responder) + mac_info_5g[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES; + } + + hdd_update_wiphy_he_caps_6ghz(hdd_ctx, &he_cap_cfg); +} +#else +static void hdd_update_wiphy_he_cap(struct hdd_context *hdd_ctx) +{ +} +#endif + +static void hdd_component_cfg_chan_to_freq(struct wlan_objmgr_pdev *pdev) +{ + ucfg_mlme_cfg_chan_to_freq(pdev); +} + +static uint32_t hdd_update_band_cap_from_dot11mode( + struct hdd_context *hdd_ctx, uint32_t band_capability) +{ + if (hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_AUTO) + return band_capability; + + if (hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11b || + hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11g || + hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11g_ONLY || + hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11b_ONLY) + band_capability = (band_capability & (~BIT(REG_BAND_5G))); + + if (hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11a) + band_capability = (band_capability & (~BIT(REG_BAND_2G))); + + if (hdd_ctx->config->dot11Mode != eHDD_DOT11_MODE_11ax_ONLY && + hdd_ctx->config->dot11Mode != eHDD_DOT11_MODE_11ax) + band_capability = (band_capability & (~BIT(REG_BAND_6G))); + + qdf_debug("Update band capability %x", band_capability); + return band_capability; +} + +#ifdef FEATURE_WPSS_THERMAL_MITIGATION +static inline +void hdd_update_multi_client_thermal_support(struct hdd_context *hdd_ctx) +{ + struct wmi_unified *wmi_handle; + + wmi_handle = get_wmi_unified_hdl_from_psoc(hdd_ctx->psoc); + if (!wmi_handle) + return; + + hdd_ctx->multi_client_thermal_mitigation = + wmi_service_enabled(wmi_handle, + wmi_service_thermal_multi_client_support); +} +#else +static inline +void hdd_update_multi_client_thermal_support(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE +static void hdd_lpc_enable_powersave(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *sta_adapter; + + if (!ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc)) + return; + + ucfg_fwol_configure_global_params(hdd_ctx->psoc, hdd_ctx->pdev); + + if (wma_enable_disable_imps(hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id, 1)) + hdd_err("IMPS feature enable failed"); + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_debug("STA adapter does not exist"); + return; + } + + wlan_hdd_set_powersave(sta_adapter->deflink, true, 0); +} + +static void hdd_lpc_disable_powersave(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *sta_adapter; + + if (!ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc)) + return; + + ucfg_fwol_set_ilp_config(hdd_ctx->psoc, hdd_ctx->pdev, 0); + + if (wma_enable_disable_imps(hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id, 0)) + hdd_err("IMPS feature disable failed"); + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_err("STA adapter does not exist"); + return; + } + wlan_hdd_set_powersave(sta_adapter->deflink, false, 0); +} +#else +static inline void hdd_lpc_enable_powersave(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_lpc_disable_powersave(struct hdd_context *hdd_ctx) +{ +} +#endif + +int hdd_update_tgt_cfg(hdd_handle_t hdd_handle, struct wma_tgt_cfg *cfg) +{ + int ret; + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + uint32_t temp_band_cap, band_capability; + struct cds_config_info *cds_cfg = cds_get_ini_config(); + uint8_t antenna_mode; + uint8_t sub_20_chan_width; + QDF_STATUS status; + mac_handle_t mac_handle; + bool bval = false; + uint8_t value = 0; + uint32_t fine_time_meas_cap = 0; + enum nss_chains_band_info band; + bool enable_dynamic_cfg; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return -EINVAL; + } + ret = hdd_objmgr_create_and_store_pdev(hdd_ctx); + if (ret) { + QDF_DEBUG_PANIC("Failed to create pdev; errno:%d", ret); + return -EINVAL; + } + + hdd_debug("New pdev has been created with pdev_id = %u", + hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id); + + status = dispatcher_pdev_open(hdd_ctx->pdev); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_DEBUG_PANIC("dispatcher pdev open failed; status:%d", + status); + ret = qdf_status_to_os_return(status); + goto exit; + } + + status = hdd_component_pdev_open(hdd_ctx->pdev); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_DEBUG_PANIC("hdd component pdev open failed; status:%d", + status); + ret = qdf_status_to_os_return(status); + goto dispatcher_close; + } + /* + * For 6GHz support this api is added to convert mlme cfgs + * channel numbers to frequency + */ + hdd_component_cfg_chan_to_freq(hdd_ctx->pdev); + + hdd_objmgr_update_tgt_max_vdev_psoc(hdd_ctx, cfg->max_intf_count); + + ucfg_ipa_set_dp_handle(hdd_ctx->psoc, + cds_get_context(QDF_MODULE_ID_SOC)); + ucfg_ipa_set_pdev_id(hdd_ctx->psoc, OL_TXRX_PDEV_ID); + + status = ucfg_mlme_get_sub_20_chan_width(hdd_ctx->psoc, + &sub_20_chan_width); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get sub_20_chan_width config"); + ret = qdf_status_to_os_return(status); + goto pdev_close; + } + + if (cds_cfg) { + if (sub_20_chan_width != + WLAN_SUB_20_CH_WIDTH_NONE && !cfg->sub_20_support) { + hdd_err("User requested sub 20 MHz channel width but unsupported by FW."); + cds_cfg->sub_20_channel_width = + WLAN_SUB_20_CH_WIDTH_NONE; + } else { + cds_cfg->sub_20_channel_width = sub_20_chan_width; + } + } + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get MLME band capability"); + ret = qdf_status_to_os_return(status); + goto pdev_close; + } + + band_capability = + hdd_update_band_cap_from_dot11mode(hdd_ctx, band_capability); + + /* first store the INI band capability */ + temp_band_cap = band_capability; + + band_capability = cfg->band_cap; + hdd_ctx->is_fils_roaming_supported = + cfg->services.is_fils_roaming_supported; + + hdd_ctx->config->is_11k_offload_supported = + cfg->services.is_11k_offload_supported; + + /* + * merge the target band capability with INI setting if the merge has + * at least 1 band enabled + */ + temp_band_cap &= band_capability; + if (!temp_band_cap) + hdd_warn("ini BandCapability not supported by the target"); + else + band_capability = temp_band_cap; + + status = ucfg_mlme_set_band_capability(hdd_ctx->psoc, band_capability); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set MLME Band Capability"); + ret = qdf_status_to_os_return(status); + goto pdev_close; + } + + hdd_ctx->curr_band = band_capability; + hdd_ctx->psoc->soc_nif.user_config.band_capability = hdd_ctx->curr_band; + + status = wlan_hdd_update_wiphy_supported_band(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update wiphy band info"); + goto pdev_close; + } + + status = ucfg_reg_set_band(hdd_ctx->pdev, band_capability); + if (QDF_IS_STATUS_ERROR(status)) + /* + * Continue, Do not close the pdev from here as if host fails + * to update band information if cc_list event is not received + * by this time, then also driver load should happen. + */ + hdd_err("Failed to update regulatory band info"); + + if (!cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_ctx->reg.reg_domain = cfg->reg_domain; + hdd_ctx->reg.eeprom_rd_ext = cfg->eeprom_rd_ext; + } + + /* This can be extended to other configurations like ht, vht cap... */ + status = wlan_hdd_validate_mac_address(&cfg->hw_macaddr); + if (QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_copy(&hdd_ctx->hw_macaddr, &cfg->hw_macaddr, + QDF_MAC_ADDR_SIZE); + + hdd_ctx->target_fw_version = cfg->target_fw_version; + hdd_ctx->target_fw_vers_ext = cfg->target_fw_vers_ext; + hdd_extract_fw_version_info(hdd_ctx); + + hdd_ctx->hw_bd_id = cfg->hw_bd_id; + qdf_mem_copy(&hdd_ctx->hw_bd_info, &cfg->hw_bd_info, + sizeof(cfg->hw_bd_info)); + + if (cfg->max_intf_count > WLAN_MAX_VDEVS) { + hdd_err("fw max vdevs (%u) > host max vdevs (%u); using %u", + cfg->max_intf_count, WLAN_MAX_VDEVS, WLAN_MAX_VDEVS); + hdd_ctx->max_intf_count = WLAN_MAX_VDEVS; + } else { + hdd_ctx->max_intf_count = cfg->max_intf_count; + } + + hdd_sar_target_config(hdd_ctx, cfg); + hdd_lpass_target_config(hdd_ctx, cfg); + + hdd_ctx->ap_arpns_support = cfg->ap_arpns_support; + + hdd_update_tgt_services(hdd_ctx, &cfg->services); + + hdd_update_tgt_ht_cap(hdd_ctx, &cfg->ht_cap); + + sme_update_bfer_caps_as_per_nss_chains(hdd_ctx->mac_handle, cfg); + + hdd_update_tgt_vht_cap(hdd_ctx, &cfg->vht_cap); + if (cfg->services.en_11ax && + (hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_AUTO || + hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11ax || + hdd_ctx->config->dot11Mode == eHDD_DOT11_MODE_11ax_ONLY)) { + hdd_debug("11AX: 11ax is enabled - update HDD config"); + hdd_update_tgt_he_cap(hdd_ctx, cfg); + hdd_update_wiphy_he_cap(hdd_ctx); + } + hdd_update_tgt_twt_cap(hdd_ctx, cfg); + hdd_update_tgt_eht_cap(hdd_ctx, cfg); + hdd_update_wiphy_eht_cap(hdd_ctx); + ucfg_mlme_update_tgt_mlo_cap(hdd_ctx->psoc); + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) { + sme_modify_nss_chains_tgt_cfg(hdd_ctx->mac_handle, + QDF_STA_MODE, band); + sme_modify_nss_chains_tgt_cfg(hdd_ctx->mac_handle, + QDF_SAP_MODE, band); + sme_modify_nss_chains_tgt_cfg(hdd_ctx->mac_handle, + QDF_TDLS_MODE, band); + sme_modify_nss_chains_tgt_cfg(hdd_ctx->mac_handle, + QDF_P2P_DEVICE_MODE, + band); + sme_modify_nss_chains_tgt_cfg(hdd_ctx->mac_handle, + QDF_OCB_MODE, band); + sme_modify_nss_chains_tgt_cfg(hdd_ctx->mac_handle, + QDF_TDLS_MODE, band); + } + + hdd_update_vdev_nss(hdd_ctx); + + status = + ucfg_mlme_get_enable_dynamic_nss_chains_cfg(hdd_ctx->psoc, + &enable_dynamic_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("unable to get enable dynamic config"); + hdd_ctx->dynamic_nss_chains_support = false; + } else { + hdd_ctx->dynamic_nss_chains_support = + cfg->dynamic_nss_chains_support & + enable_dynamic_cfg; + hdd_debug("Dynamic nss chain support FW %d driver %d", + cfg->dynamic_nss_chains_support, enable_dynamic_cfg); + } + + status = ucfg_mlme_update_dynamic_nss_chains_support + (hdd_ctx->psoc, hdd_ctx->dynamic_nss_chains_support); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("unable to set dynamic_nss_chains_support"); + + ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, &fine_time_meas_cap); + fine_time_meas_cap &= cfg->fine_time_measurement_cap; + status = ucfg_mlme_set_fine_time_meas_cap(hdd_ctx->psoc, + fine_time_meas_cap); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to set fine_time_meas_cap, 0x%x, ox%x", + fine_time_meas_cap, cfg->fine_time_measurement_cap); + ucfg_mlme_get_fine_time_meas_cap(hdd_ctx->psoc, + &fine_time_meas_cap); + } + + hdd_ctx->fine_time_meas_cap_target = cfg->fine_time_measurement_cap; + hdd_debug("fine_time_meas_cap: 0x%x", fine_time_meas_cap); + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + antenna_mode = (bval == 0x01) ? + HDD_ANTENNA_MODE_2X2 : HDD_ANTENNA_MODE_1X1; + hdd_update_smps_antenna_mode(hdd_ctx, antenna_mode); + hdd_debug("Init current antenna mode: %d", + hdd_ctx->current_antenna_mode); + + hdd_ctx->rcpi_enabled = cfg->rcpi_enabled; + + status = ucfg_mlme_cfg_get_vht_tx_bfee_ant_supp(hdd_ctx->psoc, + &value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("set tx_bfee_ant_supp failed"); + + status = ucfg_mlme_set_restricted_80p80_bw_supp(hdd_ctx->psoc, + cfg->restricted_80p80_bw_supp); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set MLME restircted 80p80 BW support"); + + if ((value > MLME_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF) && + !cfg->tx_bfee_8ss_enabled) { + status = ucfg_mlme_cfg_set_vht_tx_bfee_ant_supp(hdd_ctx->psoc, + MLME_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("set tx_bfee_ant_supp failed"); + } + + hdd_update_tid_to_link_supported(hdd_ctx, &cfg->services); + mac_handle = hdd_ctx->mac_handle; + + hdd_debug("txBFCsnValue %d", value); + + /* + * Update txBFCsnValue and NumSoundingDim values to vhtcap in wiphy + */ + hdd_update_wiphy_vhtcap(hdd_ctx); + + hdd_update_vhtcap_2g(hdd_ctx); + + hdd_ctx->wmi_max_len = cfg->wmi_max_len; + + wlan_config_sched_scan_plans_to_wiphy(hdd_ctx->wiphy, hdd_ctx->psoc); + /* + * This needs to be done after HDD pdev is created and stored since + * it will access the HDD pdev object lock. + */ + hdd_runtime_suspend_context_init(hdd_ctx); + + /* Configure NAN datapath features */ + hdd_nan_datapath_target_config(hdd_ctx, cfg); + ucfg_nan_set_tgt_caps(hdd_ctx->psoc, &cfg->nan_caps); + hdd_ctx->dfs_cac_offload = cfg->dfs_cac_offload; + hdd_ctx->lte_coex_ant_share = cfg->services.lte_coex_ant_share; + hdd_ctx->obss_scan_offload = cfg->services.obss_scan_offload; + ucfg_scan_set_obss_scan_offload(hdd_ctx->psoc, + hdd_ctx->obss_scan_offload); + status = ucfg_mlme_set_obss_detection_offload_enabled( + hdd_ctx->psoc, cfg->obss_detection_offloaded); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Couldn't pass WNI_CFG_OBSS_DETECTION_OFFLOAD to CFG"); + + status = ucfg_mlme_set_obss_color_collision_offload_enabled( + hdd_ctx->psoc, cfg->obss_color_collision_offloaded); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set WNI_CFG_OBSS_COLOR_COLLISION_OFFLOAD"); + + ucfg_mlme_set_bss_color_collision_det_support( + hdd_ctx->psoc, + cfg->obss_color_collision_offloaded); + if (!cfg->obss_color_collision_offloaded) { + status = ucfg_mlme_set_bss_color_collision_det_sta( + hdd_ctx->psoc, + cfg->obss_color_collision_offloaded); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set CFG_BSS_CLR_COLLISION_DET_STA"); + } + + hdd_update_score_config(hdd_ctx); + hdd_update_multi_client_thermal_support(hdd_ctx); + + ucfg_psoc_mlme_set_11be_capab(hdd_ctx->psoc, cfg->services.en_11be); + return 0; + +dispatcher_close: + dispatcher_pdev_close(hdd_ctx->pdev); +pdev_close: + hdd_component_pdev_close(hdd_ctx->pdev); +exit: + hdd_objmgr_release_and_destroy_pdev(hdd_ctx); + + return ret; +} + +bool hdd_dfs_indicate_radar(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct hdd_ap_ctx *ap_ctx; + uint32_t ap_chan; + bool dfs_disable_channel_switch = false; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_info("Couldn't get hdd_ctx"); + return true; + } + + ucfg_mlme_get_dfs_disable_channel_switch(hdd_ctx->psoc, + &dfs_disable_channel_switch); + if (dfs_disable_channel_switch) { + hdd_info("skip tx block hdd_ctx=%pK, disableDFSChSwitch=%d", + hdd_ctx, dfs_disable_channel_switch); + return true; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_DFS_INDICATE_RADAR) { + + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE) + goto next_adapter; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + ap_chan = ap_ctx->operating_chan_freq; + if (!wlan_reg_is_passive_or_disable_for_pwrmode(hdd_ctx->pdev, + ap_chan, REG_CURRENT_PWR_MODE)) + continue; + + ap_ctx->dfs_cac_block_tx = true; + hdd_info("tx blocked for vdev: %d", link_info->vdev_id); + if (link_info->vdev_id != WLAN_UMAC_VDEV_ID_MAX) + cdp_fc_vdev_flush( + cds_get_context(QDF_MODULE_ID_SOC), + link_info->vdev_id); + } +next_adapter: + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_DFS_INDICATE_RADAR); + } + + return true; +} + +bool hdd_is_valid_mac_address(const uint8_t *mac_addr) +{ + int xdigit = 0; + int separator = 0; + + while (*mac_addr) { + if (isxdigit(*mac_addr)) { + xdigit++; + } else if (':' == *mac_addr) { + if (0 == xdigit || ((xdigit / 2) - 1) != separator) + break; + + ++separator; + } else { + /* Invalid MAC found */ + return false; + } + ++mac_addr; + } + return xdigit == 12 && (separator == 5 || separator == 0); +} + +/** + * hdd_mon_mode_ether_setup() - Update monitor mode struct net_device. + * @dev: Handle to struct net_device to be updated. + * + * Return: None + */ +static void hdd_mon_mode_ether_setup(struct net_device *dev) +{ + dev->header_ops = NULL; + dev->type = ARPHRD_IEEE80211_RADIOTAP; + dev->hard_header_len = ETH_HLEN; + dev->mtu = ETH_DATA_LEN; + dev->addr_len = ETH_ALEN; + dev->tx_queue_len = 1000; /* Ethernet wants good queues */ + dev->flags = IFF_BROADCAST|IFF_MULTICAST; + dev->priv_flags |= IFF_TX_SKB_SHARING; + + memset(dev->broadcast, 0xFF, ETH_ALEN); +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * hdd_mon_turn_off_ps_and_wow() - Update monitor mode struct net_device. + * @hdd_ctx: Pointer to HDD context. + * + * Return: None + */ +static void hdd_mon_turn_off_ps_and_wow(struct hdd_context *hdd_ctx) +{ + ucfg_pmo_set_power_save_mode(hdd_ctx->psoc, + PMO_PS_ADVANCED_POWER_SAVE_DISABLE); + ucfg_pmo_set_wow_enable(hdd_ctx->psoc, PMO_WOW_DISABLE_BOTH); +} + +/** + * __hdd_mon_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_mon_open(struct net_device *dev) +{ + int ret; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct bbm_params param = {0}; + + hdd_enter_dev(dev); + + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_debug_rl("Monitor interface is already up"); + return 0; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_mon_mode_ether_setup(dev); + + if (con_mode == QDF_GLOBAL_MONITOR_MODE || + ucfg_mlme_is_sta_mon_conc_supported(hdd_ctx->psoc) || + ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc)) { + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + return ret; + } + hdd_err("hdd_wlan_start_modules() successful !"); + + if ((!test_bit(SME_SESSION_OPENED, + &adapter->deflink->link_flags)) || + (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc))) { + ret = hdd_start_adapter(adapter, true); + if (ret) { + hdd_err("Failed to start adapter :%d", + adapter->device_mode); + return ret; + } + hdd_err("hdd_start_adapters() successful !"); + } + hdd_mon_turn_off_ps_and_wow(hdd_ctx); + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + } + + if (con_mode != QDF_GLOBAL_MONITOR_MODE && + (ucfg_mlme_is_sta_mon_conc_supported(hdd_ctx->psoc) || + ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc))) { + hdd_info("Acquire wakelock for STA + monitor mode"); + + qdf_wake_lock_acquire(&hdd_ctx->monitor_mode_wakelock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + hdd_lpc_disable_powersave(hdd_ctx); + qdf_runtime_pm_prevent_suspend( + &hdd_ctx->runtime_context.monitor_mode); + } + + ret = hdd_set_mon_rx_cb(dev); + + if (!ret) + ret = hdd_enable_monitor_mode(dev); + + if (!ret) { + param.policy = BBM_DRIVER_MODE_POLICY; + param.policy_info.driver_mode = QDF_GLOBAL_MONITOR_MODE; + ucfg_dp_bbm_apply_independent_policy(hdd_ctx->psoc, ¶m); + ucfg_dp_set_current_throughput_level(hdd_ctx->psoc, + PLD_BUS_WIDTH_VERY_HIGH); + } + + return ret; +} + +/** + * hdd_mon_open() - Wrapper function for __hdd_mon_open to protect it from SSR + * @net_dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int hdd_mon_open(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_mon_open(net_dev); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} +#endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE +/** + * __hdd_pktcapture_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_pktcapture_open(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_adapter *sta_adapter; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + int ret; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_err("No station interface found"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(sta_adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + hdd_mon_mode_ether_setup(dev); + + status = ucfg_dp_register_pkt_capture_callbacks(vdev); + ret = qdf_status_to_os_return(status); + if (ret) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return ret; + } + + adapter->deflink->vdev = vdev; + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + sta_adapter->mon_adapter = adapter; + + return ret; +} + +/** + * hdd_pktcapture_open() - Wrapper function for hdd_pktcapture_open to + * protect it from SSR + * @net_dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int hdd_pktcapture_open(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_pktcapture_open(net_dev); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} + +/** + * hdd_unmap_monitor_interface_vdev() - unmap monitor interface vdev and + * deregister packet capture callbacks + * @sta_adapter: station adapter + * + * Return: void + */ +static void +hdd_unmap_monitor_interface_vdev(struct hdd_adapter *sta_adapter) +{ + struct hdd_adapter *mon_adapter = sta_adapter->mon_adapter; + + if (mon_adapter && hdd_is_interface_up(mon_adapter)) { + ucfg_pkt_capture_deregister_callbacks( + mon_adapter->deflink->vdev); + hdd_objmgr_put_vdev_by_user(mon_adapter->deflink->vdev, + WLAN_OSIF_ID); + mon_adapter->deflink->vdev = NULL; + hdd_reset_monitor_interface(sta_adapter); + } +} + +/** + * hdd_map_monitor_interface_vdev() - Map monitor interface vdev and + * register packet capture callbacks + * @sta_adapter: Station adapter + * + * Return: None + */ +static void hdd_map_monitor_interface_vdev(struct hdd_adapter *sta_adapter) +{ + struct hdd_adapter *mon_adapter; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + int ret; + + mon_adapter = hdd_get_adapter(sta_adapter->hdd_ctx, QDF_MONITOR_MODE); + if (!mon_adapter) { + hdd_debug("No monitor interface found"); + return; + } + + if (!mon_adapter || !hdd_is_interface_up(mon_adapter)) { + hdd_debug("Monitor interface is not up\n"); + return; + } + + if (!wlan_hdd_is_session_type_monitor(mon_adapter->device_mode)) + return; + + vdev = hdd_objmgr_get_vdev_by_user(sta_adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + return; + + status = ucfg_dp_register_pkt_capture_callbacks(vdev); + ret = qdf_status_to_os_return(status); + if (ret) { + hdd_err("Failed registering packet capture callbacks"); + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_OSIF_ID); + return; + } + + mon_adapter->deflink->vdev = vdev; + sta_adapter->mon_adapter = mon_adapter; +} + +void hdd_reset_monitor_interface(struct hdd_adapter *sta_adapter) +{ + sta_adapter->mon_adapter = NULL; +} + +struct hdd_adapter * +hdd_is_pkt_capture_mon_enable(struct hdd_adapter *sta_adapter) +{ + return sta_adapter->mon_adapter; +} +#else +static inline void +hdd_unmap_monitor_interface_vdev(struct hdd_adapter *sta_adapter) +{ +} + +static inline void +hdd_map_monitor_interface_vdev(struct hdd_adapter *sta_adapter) +{ +} +#endif + +static QDF_STATUS +wlan_hdd_update_dbs_scan_and_fw_mode_config(void) +{ + struct policy_mgr_dual_mac_config cfg = {0}; + QDF_STATUS status; + uint32_t chnl_sel_logic_conc = 0; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + uint8_t dual_mac_feature = DISABLE_DBS_CXN_AND_SCAN; + + if (!hdd_ctx) + return QDF_STATUS_E_FAILURE; + + /* + * ROME platform doesn't support any DBS related commands in FW, + * so if driver sends wmi command with dual_mac_config with all set to + * 0 then FW wouldn't respond back and driver would timeout on waiting + * for response. Check if FW supports DBS to eliminate ROME vs + * NON-ROME platform. + */ + if (!policy_mgr_find_if_fw_supports_dbs(hdd_ctx->psoc)) + return QDF_STATUS_SUCCESS; + + if (hdd_ctx->is_dual_mac_cfg_updated) { + hdd_debug("dual mac config has already been updated, skip"); + return QDF_STATUS_SUCCESS; + } + + cfg.scan_config = 0; + cfg.fw_mode_config = 0; + cfg.set_dual_mac_cb = policy_mgr_soc_set_dual_mac_cfg_cb; + if (policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc)) { + status = + ucfg_policy_mgr_get_chnl_select_plcy(hdd_ctx->psoc, + &chnl_sel_logic_conc); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("can't get chnl sel policy, use def"); + return status; + } + } + status = + ucfg_policy_mgr_get_dual_mac_feature(hdd_ctx->psoc, + &dual_mac_feature); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("ucfg_policy_mgr_get_dual_mac_feature failed, use def"); + return status; + } + + if (dual_mac_feature != DISABLE_DBS_CXN_AND_SCAN) { + status = policy_mgr_get_updated_scan_and_fw_mode_config( + hdd_ctx->psoc, &cfg.scan_config, + &cfg.fw_mode_config, + dual_mac_feature, + chnl_sel_logic_conc); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("wma_get_updated_scan_and_fw_mode_config failed %d", + status); + return status; + } + } + + hdd_debug("send scan_cfg: 0x%x fw_mode_cfg: 0x%x to fw", + cfg.scan_config, cfg.fw_mode_config); + + status = sme_soc_set_dual_mac_config(cfg); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("sme_soc_set_dual_mac_config failed %d", status); + return status; + } + hdd_ctx->is_dual_mac_cfg_updated = true; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_max_sta_interface_up_count_reached() - check sta/p2p_cli vdev count + * @adapter: HDD adapter + * + * Return: true if vdev limit reached + */ +static bool hdd_max_sta_interface_up_count_reached(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_adapter *temp_adapter = NULL, *next_adapter = NULL; + uint8_t intf_count = 0; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_MAX_STA_INTERFACE_UP_COUNT_REACHED; + + if (0 == CFG_TGT_DEFAULT_MAX_STA_VDEVS) + return false; + + /* + * Check for max no of supported STA/P2PCLI VDEVs before + * creating another one. + */ + hdd_for_each_adapter_dev_held_safe(hdd_ctx, temp_adapter, + next_adapter, dbgid) { + if ((temp_adapter != adapter) && + (temp_adapter->dev->flags & IFF_UP) && + ((temp_adapter->device_mode == QDF_STA_MODE) || + (temp_adapter->device_mode == QDF_P2P_CLIENT_MODE))) + intf_count++; + + hdd_adapter_dev_put_debug(temp_adapter, dbgid); + } + + if (intf_count >= CFG_TGT_DEFAULT_MAX_STA_VDEVS) { + hdd_err("Max limit reached sta vdev-current %d max %d", + intf_count, CFG_TGT_DEFAULT_MAX_STA_VDEVS); + return true; + } + return false; +} + +#if (defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC)) && \ +(defined(CFG80211_IFTYPE_MLO_LINK_SUPPORT) || \ +defined(CFG80211_SINGLE_NETDEV_MULTI_LINK_SUPPORT)) && \ +!defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static int hdd_start_link_adapter(struct hdd_adapter *sta_adapter) +{ + int i, ret = 0; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_adapter *link_adapter; + + hdd_enter_dev(sta_adapter->dev); + mlo_adapter_info = &sta_adapter->mlo_adapter_info; + + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + if (link_adapter->mlo_adapter_info.associate_with_ml_adapter) { + /* TODO have proper references here */ + qdf_spin_lock_bh(&link_adapter->deflink->vdev_lock); + link_adapter->deflink->vdev = + sta_adapter->deflink->vdev; + link_adapter->deflink->vdev_id = + sta_adapter->deflink->vdev_id; + qdf_spin_unlock_bh(&link_adapter->deflink->vdev_lock); + + sta_adapter->link_info[i].vdev_id = + sta_adapter->deflink->vdev_id; + continue; + } + ret = hdd_start_station_adapter(link_adapter); + if (!ret) { + sta_adapter->link_info[i].vdev_id = + link_adapter->deflink->vdev_id; + } + } + + hdd_adapter_update_mlo_mgr_mac_addr(sta_adapter); + + hdd_exit(); + return ret; +} + +static int hdd_stop_link_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *sta_adapter) +{ + int i, ret = 0; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_adapter *link_adapter; + + hdd_enter_dev(sta_adapter->dev); + hdd_debug("Stop adapter for link mode : %s(%d)", + qdf_opmode_str(sta_adapter->device_mode), + sta_adapter->deflink->vdev_id); + + mlo_adapter_info = &sta_adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + + if (link_adapter->mlo_adapter_info.associate_with_ml_adapter) { + /* TODO have proper references here */ + qdf_spin_lock_bh(&link_adapter->deflink->vdev_lock); + link_adapter->deflink->vdev = NULL; + link_adapter->deflink->vdev_id = 0xff; + qdf_spin_unlock_bh(&link_adapter->deflink->vdev_lock); + continue; + } + ret = hdd_stop_adapter_ext(hdd_ctx, link_adapter); + } + + hdd_exit(); + return ret; +} +#else +static int hdd_start_link_adapter(struct hdd_adapter *link_adapter) +{ + return 0; +} + +static int hdd_stop_link_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *link_adapter) +{ + return 0; +} +#endif + +/** + * hdd_start_adapter() - Wrapper function for device specific adapter + * @adapter: pointer to HDD adapter + * @rtnl_held: true if rtnl lock is taken, otherwise false + * + * This function is called to start the device specific adapter for + * the mode passed in the adapter's device_mode. + * + * Return: 0 for success; non-zero for failure + */ +int hdd_start_adapter(struct hdd_adapter *adapter, bool rtnl_held) +{ + + int ret; + enum QDF_OPMODE device_mode = adapter->device_mode; + + hdd_enter_dev(adapter->dev); + + switch (device_mode) { + case QDF_MONITOR_MODE: + ret = hdd_start_station_adapter(adapter); + if (ret) + goto err_start_adapter; + hdd_set_idle_ps_config(adapter->hdd_ctx, false); + break; + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (hdd_max_sta_interface_up_count_reached(adapter)) + goto err_start_adapter; + fallthrough; + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_NAN_DISC_MODE: + ret = hdd_start_station_adapter(adapter); + if (ret) + goto err_start_adapter; + + if (device_mode == QDF_STA_MODE) { + ret = hdd_start_link_adapter(adapter); + if (ret) + hdd_err("Failed to start link adapter:%d", ret); + } + break; + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + ret = hdd_start_ap_adapter(adapter, rtnl_held); + if (ret) + goto err_start_adapter; + break; + case QDF_FTM_MODE: + /* vdevs are dynamically managed by firmware in FTM */ + hdd_register_wext(adapter->dev); + goto exit_with_success; + default: + hdd_err("Invalid session type %d", device_mode); + QDF_ASSERT(0); + goto err_start_adapter; + } + + if (hdd_set_fw_params(adapter)) + hdd_err("Failed to set the FW params for the adapter!"); + + if (adapter->deflink->vdev_id != WLAN_UMAC_VDEV_ID_MAX) { + ret = wlan_hdd_cfg80211_register_frames(adapter); + if (ret < 0) { + hdd_err("Failed to register frames - ret %d", ret); + goto err_start_adapter; + } + } + + wlan_hdd_update_dbs_scan_and_fw_mode_config(); + +exit_with_success: + hdd_create_adapter_sysfs_files(adapter); + + hdd_exit(); + + return 0; + +err_start_adapter: + return -EINVAL; +} + +void hdd_update_hw_sw_info(struct hdd_context *hdd_ctx) +{ + void *hif_sc; + size_t target_hw_name_len; + const char *target_hw_name; + uint8_t *buf; + uint32_t buf_len; + + hif_sc = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_sc) + return; + + hif_get_hw_info(hif_sc, &hdd_ctx->target_hw_version, + &hdd_ctx->target_hw_revision, + &target_hw_name); + + qdf_mem_zero(hdd_ctx->target_hw_name, MAX_TGT_HW_NAME_LEN); + + target_hw_name_len = strlen(target_hw_name) + 1; + + if (target_hw_name_len <= MAX_TGT_HW_NAME_LEN) { + qdf_mem_copy(hdd_ctx->target_hw_name, target_hw_name, + target_hw_name_len); + } else { + hdd_err("target_hw_name_len is greater than MAX_TGT_HW_NAME_LEN"); + return; + } + + hdd_debug("target_hw_name = %s", hdd_ctx->target_hw_name); + + buf = qdf_mem_malloc(WE_MAX_STR_LEN); + if (buf) { + buf_len = hdd_wlan_get_version(hdd_ctx, WE_MAX_STR_LEN, buf); + hdd_nofl_debug("%s", buf); + qdf_mem_free(buf); + } +} + +/** + * hdd_update_cds_ac_specs_params() - update cds ac_specs params + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static void +hdd_update_cds_ac_specs_params(struct hdd_context *hdd_ctx) +{ + uint8_t tx_sched_wrr_param[TX_SCHED_WRR_PARAMS_NUM] = {0}; + qdf_size_t out_size = 0; + int i; + struct cds_context *cds_ctx; + + if (!hdd_ctx) + return; + + if (!hdd_ctx->config) { + /* Do nothing if hdd_ctx is invalid */ + hdd_err("Warning: hdd_ctx->cfg_ini is NULL"); + return; + } + + cds_ctx = cds_get_context(QDF_MODULE_ID_QDF); + if (!cds_ctx) + return; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + switch (i) { + case QCA_WLAN_AC_BE: + qdf_uint8_array_parse( + cfg_get(hdd_ctx->psoc, + CFG_DP_ENABLE_TX_SCHED_WRR_BE), + tx_sched_wrr_param, + sizeof(tx_sched_wrr_param), + &out_size); + break; + case QCA_WLAN_AC_BK: + qdf_uint8_array_parse( + cfg_get(hdd_ctx->psoc, + CFG_DP_ENABLE_TX_SCHED_WRR_BK), + tx_sched_wrr_param, + sizeof(tx_sched_wrr_param), + &out_size); + break; + case QCA_WLAN_AC_VI: + qdf_uint8_array_parse( + cfg_get(hdd_ctx->psoc, + CFG_DP_ENABLE_TX_SCHED_WRR_VI), + tx_sched_wrr_param, + sizeof(tx_sched_wrr_param), + &out_size); + break; + case QCA_WLAN_AC_VO: + qdf_uint8_array_parse( + cfg_get(hdd_ctx->psoc, + CFG_DP_ENABLE_TX_SCHED_WRR_VO), + tx_sched_wrr_param, + sizeof(tx_sched_wrr_param), + &out_size); + break; + default: + break; + } + + if (out_size == TX_SCHED_WRR_PARAMS_NUM) { + cds_ctx->ac_specs[i].wrr_skip_weight = + tx_sched_wrr_param[0]; + cds_ctx->ac_specs[i].credit_threshold = + tx_sched_wrr_param[1]; + cds_ctx->ac_specs[i].send_limit = + tx_sched_wrr_param[2]; + cds_ctx->ac_specs[i].credit_reserve = + tx_sched_wrr_param[3]; + cds_ctx->ac_specs[i].discard_weight = + tx_sched_wrr_param[4]; + } + + out_size = 0; + } +} + +uint32_t hdd_wlan_get_version(struct hdd_context *hdd_ctx, + const size_t version_len, uint8_t *version) +{ + uint32_t size; + uint8_t reg_major = 0, reg_minor = 0, bdf_major = 0, bdf_minor = 0; + struct target_psoc_info *tgt_hdl; + + if (!hdd_ctx) { + hdd_err("Invalid context, HDD context is null"); + return 0; + } + + if (!version || version_len == 0) { + hdd_err("Invalid buffer pointr or buffer len\n"); + return 0; + } + tgt_hdl = wlan_psoc_get_tgt_if_handle(hdd_ctx->psoc); + if (tgt_hdl) + target_psoc_get_version_info(tgt_hdl, ®_major, ®_minor, + &bdf_major, &bdf_minor); + + size = scnprintf(version, version_len, + "Host SW:%s, FW:%d.%d.%d.%d.%d.%d, HW:%s, Board ver: %x Ref design id: %x, Customer id: %x, Project id: %x, Board Data Rev: %x, REG DB: %u:%u, BDF REG DB: %u:%u", + QWLAN_VERSIONSTR, + hdd_ctx->fw_version_info.major_spid, + hdd_ctx->fw_version_info.minor_spid, + hdd_ctx->fw_version_info.siid, + hdd_ctx->fw_version_info.rel_id, + hdd_ctx->fw_version_info.crmid, + hdd_ctx->fw_version_info.sub_id, + hdd_ctx->target_hw_name, + hdd_ctx->hw_bd_info.bdf_version, + hdd_ctx->hw_bd_info.ref_design_id, + hdd_ctx->hw_bd_info.customer_id, + hdd_ctx->hw_bd_info.project_id, + hdd_ctx->hw_bd_info.board_data_rev, + reg_major, reg_minor, bdf_major, bdf_minor); + + return size; +} + +int hdd_set_11ax_rate(struct hdd_adapter *adapter, int set_value, + struct sap_config *sap_config) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int ret; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + + if (!sap_config) { + if (!sme_is_feature_supported_by_fw(DOT11AX)) { + hdd_err("Target does not support 11ax"); + return -EIO; + } + } else if (sap_config->SapHw_mode != eCSR_DOT11_MODE_11ax && + sap_config->SapHw_mode != eCSR_DOT11_MODE_11ax_ONLY) { + hdd_err("Invalid hw mode, SAP hw_mode= 0x%x, ch_freq = %d", + sap_config->SapHw_mode, sap_config->chan_freq); + return -EIO; + } + + if (set_value != 0xffff) { + rix = RC_2_RATE_IDX_11AX(set_value); + preamble = WMI_RATE_PREAMBLE_HE; + nss = HT_RC_2_STREAMS_11AX(set_value); + + set_value = hdd_assemble_rate_code(preamble, nss, rix); + } else { + ret = sme_set_auto_rate_he_ltf(mac_handle, + adapter->deflink->vdev_id, + QCA_WLAN_HE_LTF_AUTO); + } + + hdd_info("SET_11AX_RATE val %d rix %d preamble %x nss %d", + set_value, rix, preamble, nss); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + set_value, VDEV_CMD); + + return ret; +} + +int hdd_assemble_rate_code(uint8_t preamble, uint8_t nss, uint8_t rate) +{ + return ucfg_mlme_assemble_rate_code(preamble, nss, rate); +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static enum policy_mgr_con_mode wlan_hdd_get_mode_for_non_connected_vdev( + struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter; + enum policy_mgr_con_mode mode; + struct wlan_hdd_link_info *link_info; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return PM_MAX_NUM_OF_MODE; + } + + adapter = link_info->adapter; + mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, + adapter->device_mode, + vdev_id); + return mode; +} + +/** + * hdd_is_chan_switch_in_progress() - Check if any adapter has channel switch in + * progress + * + * Return: true, if any adapter has channel switch in + * progress else false + */ +static bool hdd_is_chan_switch_in_progress(void) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_CHAN_SWITCH_IN_PROGRESS; + struct hdd_ap_ctx *ap_ctx; + struct wlan_hdd_link_info *link_info; + bool is_restart; + struct wlan_objmgr_vdev *vdev; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE) + goto next_adapter; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_ID); + if (!vdev) + continue; + is_restart = false; + if (wlan_vdev_is_restart_progress(vdev) == + QDF_STATUS_SUCCESS) { + hdd_debug("vdev: %d restart in progress", + wlan_vdev_get_id(vdev)); + is_restart = true; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + if (is_restart || + qdf_atomic_read(&ap_ctx->ch_switch_in_progress)) { + hdd_debug("channel switch progress for vdev_id %d", + link_info->vdev_id); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return true; + } + } +next_adapter: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return false; +} + +/** + * hdd_is_cac_in_progress() - Check if any SAP connection is performing + * CAC on DFS channel + * + * Return: true, if any of existing SAP is performing CAC + * or else false + */ +static bool hdd_is_cac_in_progress(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return false; + + return (hdd_ctx->dev_dfs_cac_status == DFS_CAC_IN_PROGRESS); +} + +static QDF_STATUS +wlan_hdd_set_tx_rx_nss_cb(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + uint8_t tx_nss, uint8_t rx_nss) +{ + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return hdd_update_nss(link_info, tx_nss, rx_nss); +} + +static void hdd_register_policy_manager_callback( + struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_hdd_cbacks hdd_cbacks; + + qdf_mem_zero(&hdd_cbacks, sizeof(hdd_cbacks)); + hdd_cbacks.sap_restart_chan_switch_cb = + hdd_sap_restart_chan_switch_cb; + hdd_cbacks.wlan_hdd_get_channel_for_sap_restart = + wlan_hdd_get_channel_for_sap_restart; + hdd_cbacks.get_mode_for_non_connected_vdev = + wlan_hdd_get_mode_for_non_connected_vdev; + hdd_cbacks.hdd_get_device_mode = hdd_get_device_mode; + hdd_cbacks.hdd_is_chan_switch_in_progress = + hdd_is_chan_switch_in_progress; + hdd_cbacks.hdd_is_cac_in_progress = + hdd_is_cac_in_progress; + hdd_cbacks.wlan_hdd_set_sap_csa_reason = + wlan_hdd_set_sap_csa_reason; + hdd_cbacks.hdd_get_ap_6ghz_capable = hdd_get_ap_6ghz_capable; + hdd_cbacks.wlan_hdd_indicate_active_ndp_cnt = + hdd_indicate_active_ndp_cnt; + hdd_cbacks.wlan_get_ap_prefer_conc_ch_params = + wlan_get_ap_prefer_conc_ch_params; + hdd_cbacks.wlan_get_sap_acs_band = + wlan_get_sap_acs_band; + hdd_cbacks.wlan_check_cc_intf_cb = wlan_hdd_check_cc_intf_cb; + hdd_cbacks.wlan_set_tx_rx_nss_cb = wlan_hdd_set_tx_rx_nss_cb; + + if (QDF_STATUS_SUCCESS != + policy_mgr_register_hdd_cb(psoc, &hdd_cbacks)) { + hdd_err("HDD callback registration with policy manager failed"); + } +} +#else +static void hdd_register_policy_manager_callback( + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef WLAN_SUPPORT_GAP_LL_PS_MODE +static void hdd_register_green_ap_callback(struct wlan_objmgr_pdev *pdev) +{ + struct green_ap_hdd_callback hdd_cback; + qdf_mem_zero(&hdd_cback, sizeof(hdd_cback)); + + hdd_cback.send_event = wlan_hdd_send_green_ap_ll_ps_event; + + if (QDF_STATUS_SUCCESS != + green_ap_register_hdd_callback(pdev, &hdd_cback)) { + hdd_err("HDD callback registration for Green AP failed"); + } +} +#else +static inline void hdd_register_green_ap_callback(struct wlan_objmgr_pdev *pdev) +{ +} +#endif + +#ifdef WLAN_FEATURE_NAN +#ifdef WLAN_FEATURE_SR +static void hdd_register_sr_concurrency_cb(struct nan_callbacks *cb_obj) +{ + cb_obj->nan_sr_concurrency_update = hdd_nan_sr_concurrency_update; +} +#else +static void hdd_register_sr_concurrency_cb(struct nan_callbacks *cb_obj) +{} +#endif +static void hdd_nan_register_callbacks(struct hdd_context *hdd_ctx) +{ + struct nan_callbacks cb_obj = {0}; + + cb_obj.ndi_open = hdd_ndi_open; + cb_obj.ndi_close = hdd_ndi_close; + cb_obj.ndi_set_mode = hdd_ndi_set_mode; + cb_obj.ndi_start = hdd_ndi_start; + cb_obj.ndi_delete = hdd_ndi_delete; + cb_obj.drv_ndi_create_rsp_handler = hdd_ndi_drv_ndi_create_rsp_handler; + cb_obj.drv_ndi_delete_rsp_handler = hdd_ndi_drv_ndi_delete_rsp_handler; + + cb_obj.new_peer_ind = hdd_ndp_new_peer_handler; + cb_obj.peer_departed_ind = hdd_ndp_peer_departed_handler; + + cb_obj.nan_concurrency_update = hdd_nan_concurrency_update; + cb_obj.set_mc_list = hdd_update_multicast_list; + + hdd_register_sr_concurrency_cb(&cb_obj); + + os_if_nan_register_hdd_callbacks(hdd_ctx->psoc, &cb_obj); +} +#else +static inline void hdd_nan_register_callbacks(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef CONFIG_LEAK_DETECTION +/** + * hdd_check_for_leaks() - Perform runtime memory leak checks + * @hdd_ctx: the global HDD context + * @is_ssr: true if SSR is in progress + * + * This API triggers runtime memory leak detection. This feature enforces the + * policy that any memory allocated at runtime must also be released at runtime. + * + * Allocating memory at runtime and releasing it at unload is effectively a + * memory leak for configurations which never unload (e.g. LONU, statically + * compiled driver). Such memory leaks are NOT false positives, and must be + * fixed. + * + * Return: None + */ +static void hdd_check_for_leaks(struct hdd_context *hdd_ctx, bool is_ssr) +{ + /* DO NOT REMOVE these checks; for false positives, read above first */ + + wlan_objmgr_psoc_check_for_leaks(hdd_ctx->psoc); + + /* many adapter resources are not freed by design during SSR */ + if (is_ssr) + return; + + qdf_wake_lock_check_for_leaks(); + qdf_delayed_work_check_for_leaks(); + qdf_mc_timer_check_for_leaks(); + qdf_nbuf_map_check_for_leaks(); + qdf_periodic_work_check_for_leaks(); + qdf_mem_check_for_leaks(); +} + +/** + * hdd_debug_domain_set() - Set qdf debug domain + * @domain: debug domain to be set + * + * In the scenario of system reboot, it may have thread accessing debug domain + * for memory allocation/free, other than the one trying to change it. + * If debug domain is changed after a memory allocation but before the free, + * it will hit debug domain mismatch assertion in memory free. + * To avoid such assertion, skip debug domain transition if system reboot is + * in progress. + * + * Return: 0 if the specified debug domain has been set, -EBUSY otherwise + */ +static int hdd_debug_domain_set(enum qdf_debug_domain domain) +{ + int ret = 0; + + if (cds_sys_reboot_protect()) { + hdd_info("System is rebooting, skip debug domain transition"); + ret = -EBUSY; + } else { + qdf_debug_domain_set(domain); + } + + cds_sys_reboot_unprotect(); + + return ret; +} + +#define hdd_debug_domain_get() qdf_debug_domain_get() +#else +static void hdd_check_for_objmgr_peer_leaks(struct wlan_objmgr_psoc *psoc) +{ + uint32_t vdev_id; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + + /* get module id which cause the leak and release ref */ + wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) { + wlan_objmgr_for_each_vdev_peer(vdev, peer) { + qdf_atomic_t *ref_id_dbg; + int ref_id; + int32_t refs; + + ref_id_dbg = vdev->vdev_objmgr.ref_id_dbg; + wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) + wlan_objmgr_peer_release_ref(peer, ref_id); + } + } +} + +static void hdd_check_for_objmgr_leaks(struct hdd_context *hdd_ctx) +{ + uint32_t vdev_id, pdev_id; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + /* + * leak detection is disabled, force release the references for the wlan + * to recover cleanly. + */ + psoc = hdd_ctx->psoc; + if (!psoc) + return; + + + hdd_check_for_objmgr_peer_leaks(psoc); + + wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) { + qdf_atomic_t *ref_id_dbg; + int ref_id; + int32_t refs; + + ref_id_dbg = vdev->vdev_objmgr.ref_id_dbg; + wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) { + wlan_objmgr_vdev_release_ref(vdev, ref_id); + } + } + + wlan_objmgr_for_each_psoc_pdev(psoc, pdev_id, pdev) { + qdf_atomic_t *ref_id_dbg; + int ref_id; + int32_t refs; + + ref_id_dbg = pdev->pdev_objmgr.ref_id_dbg; + wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) + wlan_objmgr_pdev_release_ref(pdev, ref_id); + } +} + +static void hdd_check_for_leaks(struct hdd_context *hdd_ctx, bool is_ssr) +{ + hdd_check_for_objmgr_leaks(hdd_ctx); +} + +#define hdd_debug_domain_set(domain) 0 +#define hdd_debug_domain_get() DEFAULT_DEBUG_DOMAIN_INIT +#endif /* CONFIG_LEAK_DETECTION */ + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * hdd_skip_acs_scan_timer_handler() - skip ACS scan timer timeout handler + * @data: pointer to struct hdd_context + * + * This function will reset acs_scan_status to eSAP_DO_NEW_ACS_SCAN. + * Then new ACS request will do a fresh scan without reusing the cached + * scan information. + * + * Return: void + */ +static void hdd_skip_acs_scan_timer_handler(void *data) +{ + struct hdd_context *hdd_ctx = data; + mac_handle_t mac_handle; + + hdd_debug("ACS Scan result expired. Reset ACS scan skip"); + hdd_ctx->skip_acs_scan_status = eSAP_DO_NEW_ACS_SCAN; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_freq_list); + hdd_ctx->last_acs_freq_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) + return; +} + +static void hdd_skip_acs_scan_timer_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = qdf_mc_timer_init(&hdd_ctx->skip_acs_scan_timer, + QDF_TIMER_TYPE_SW, + hdd_skip_acs_scan_timer_handler, + hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to init ACS Skip timer"); + qdf_spinlock_create(&hdd_ctx->acs_skip_lock); +} + +static void hdd_skip_acs_scan_timer_deinit(struct hdd_context *hdd_ctx) +{ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->skip_acs_scan_timer)) { + qdf_mc_timer_stop(&hdd_ctx->skip_acs_scan_timer); + } + + if (!QDF_IS_STATUS_SUCCESS + (qdf_mc_timer_destroy(&hdd_ctx->skip_acs_scan_timer))) { + hdd_err("Cannot deallocate ACS Skip timer"); + } + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + qdf_mem_free(hdd_ctx->last_acs_freq_list); + hdd_ctx->last_acs_freq_list = NULL; + hdd_ctx->num_of_channels = 0; + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); +} +#else +static void hdd_skip_acs_scan_timer_init(struct hdd_context *hdd_ctx) {} +static void hdd_skip_acs_scan_timer_deinit(struct hdd_context *hdd_ctx) {} +#endif + +/** + * hdd_update_country_code - Update country code + * @hdd_ctx: HDD context + * + * Update country code based on module parameter country_code + * + * Return: 0 on success and errno on failure + */ +int hdd_update_country_code(struct hdd_context *hdd_ctx) +{ + if (!country_code || + !ucfg_reg_is_user_country_set_allowed(hdd_ctx->psoc)) + return 0; + + return hdd_reg_set_country(hdd_ctx, country_code); +} + +#ifdef WLAN_NS_OFFLOAD +/** + * hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Unregister for IPv6 address change notifications. + * + * Return: None + */ +static void hdd_wlan_unregister_ip6_notifier(struct hdd_context *hdd_ctx) +{ + unregister_inet6addr_notifier(&hdd_ctx->ipv6_notifier); +} + +/** + * hdd_wlan_register_ip6_notifier() - register IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Register for IPv6 address change notifications. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_wlan_register_ip6_notifier(struct hdd_context *hdd_ctx) +{ + int ret; + + hdd_ctx->ipv6_notifier.notifier_call = wlan_hdd_ipv6_changed; + ret = register_inet6addr_notifier(&hdd_ctx->ipv6_notifier); + if (ret) { + hdd_err("Failed to register IPv6 notifier: %d", ret); + goto out; + } + + hdd_debug("Registered IPv6 notifier"); +out: + return ret; +} +#else +/** + * hdd_wlan_unregister_ip6_notifier() - unregister IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Unregister for IPv6 address change notifications. + * + * Return: None + */ +static void hdd_wlan_unregister_ip6_notifier(struct hdd_context *hdd_ctx) +{ +} + +/** + * hdd_wlan_register_ip6_notifier() - register IPv6 change notifier + * @hdd_ctx: Pointer to hdd context + * + * Register for IPv6 address change notifications. + * + * Return: None + */ +static int hdd_wlan_register_ip6_notifier(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#ifdef FEATURE_RUNTIME_PM +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) +static int hdd_pm_qos_add_notifier(struct hdd_context *hdd_ctx) +{ + return dev_pm_qos_add_notifier(hdd_ctx->parent_dev, + &hdd_ctx->pm_qos_notifier, + DEV_PM_QOS_RESUME_LATENCY); +} + +static int hdd_pm_qos_remove_notifier(struct hdd_context *hdd_ctx) +{ + return dev_pm_qos_remove_notifier(hdd_ctx->parent_dev, + &hdd_ctx->pm_qos_notifier, + DEV_PM_QOS_RESUME_LATENCY); +} +#else +static int hdd_pm_qos_add_notifier(struct hdd_context *hdd_ctx) +{ + return pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, + &hdd_ctx->pm_qos_notifier); +} + +static int hdd_pm_qos_remove_notifier(struct hdd_context *hdd_ctx) +{ + return pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY, + &hdd_ctx->pm_qos_notifier); +} +#endif + +/** + * hdd_wlan_register_pm_qos_notifier() - register PM QOS notifier + * @hdd_ctx: Pointer to hdd context + * + * Register for PM QOS change notifications. + * + * Return: None + */ +static int hdd_wlan_register_pm_qos_notifier(struct hdd_context *hdd_ctx) +{ + int ret; + + qdf_spinlock_create(&hdd_ctx->pm_qos_lock); + + /* if gRuntimePM is 1 then feature is enabled without CXPC */ + if (hdd_ctx->config->runtime_pm != hdd_runtime_pm_dynamic) { + hdd_debug("Dynamic Runtime PM disabled"); + return 0; + } + + hdd_ctx->pm_qos_notifier.notifier_call = wlan_hdd_pm_qos_notify; + ret = hdd_pm_qos_add_notifier(hdd_ctx); + if (ret) + hdd_err("Failed to register PM_QOS notifier: %d", ret); + else + hdd_debug("PM QOS Notifier registered"); + + return ret; +} + +/** + * hdd_wlan_unregister_pm_qos_notifier() - unregister PM QOS notifier + * @hdd_ctx: Pointer to hdd context + * + * Unregister for PM QOS change notifications. + * + * Return: None + */ +static void hdd_wlan_unregister_pm_qos_notifier(struct hdd_context *hdd_ctx) +{ + int ret; + + if (hdd_ctx->config->runtime_pm != hdd_runtime_pm_dynamic) { + hdd_debug("Dynamic Runtime PM disabled"); + qdf_spinlock_destroy(&hdd_ctx->pm_qos_lock); + return; + } + + ret = hdd_pm_qos_remove_notifier(hdd_ctx); + if (ret) + hdd_warn("Failed to remove qos notifier, err = %d\n", ret); + + qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock); + + if (hdd_ctx->runtime_pm_prevented) { + hif_rtpm_put(HIF_RTPM_PUT_NOIDLE, HIF_RTPM_ID_PM_QOS_NOTIFY); + hdd_ctx->runtime_pm_prevented = false; + } + + qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock); + + qdf_spinlock_destroy(&hdd_ctx->pm_qos_lock); +} +#else +static int hdd_wlan_register_pm_qos_notifier(struct hdd_context *hdd_ctx) +{ + return 0; +} + +static void hdd_wlan_unregister_pm_qos_notifier(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_enable_power_management() - API to Enable Power Management + * @hdd_ctx: HDD context + * + * API invokes Bus Interface Layer power management functionality + * + * Return: None + */ +static void hdd_enable_power_management(struct hdd_context *hdd_ctx) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) + return; + + hif_enable_power_management(hif_ctx, cds_is_packet_log_enabled()); + hdd_wlan_register_pm_qos_notifier(hdd_ctx); +} + +/** + * hdd_disable_power_management() - API to disable Power Management + * @hdd_ctx: HDD context + * + * API disable Bus Interface Layer Power management functionality + * + * Return: None + */ +static void hdd_disable_power_management(struct hdd_context *hdd_ctx) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) + return; + + hdd_wlan_unregister_pm_qos_notifier(hdd_ctx); + hif_disable_power_management(hif_ctx); +} + +/** + * hdd_register_notifiers - Register netdev notifiers. + * @hdd_ctx: HDD context + * + * Register netdev notifiers like IPv4 and IPv6. + * + * Return: 0 on success and errno on failure + */ +static int hdd_register_notifiers(struct hdd_context *hdd_ctx) +{ + int ret; + + ret = hdd_wlan_register_ip6_notifier(hdd_ctx); + if (ret) + goto out; + + hdd_ctx->ipv4_notifier.notifier_call = wlan_hdd_ipv4_changed; + ret = register_inetaddr_notifier(&hdd_ctx->ipv4_notifier); + if (ret) { + hdd_err("Failed to register IPv4 notifier: %d", ret); + goto unregister_ip6_notifier; + } + + ret = osif_dp_nud_register_netevent_notifier(hdd_ctx->psoc); + if (ret) { + hdd_err("Failed to register netevent notifier: %d", + ret); + goto unregister_inetaddr_notifier; + } + + return 0; + +unregister_inetaddr_notifier: + unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier); +unregister_ip6_notifier: + hdd_wlan_unregister_ip6_notifier(hdd_ctx); +out: + return ret; +} + +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +static inline +void hdd_set_qmi_stats_enabled(struct hdd_context *hdd_ctx) +{ + wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(hdd_ctx->psoc); + + if (!wmi_handle) { + hdd_err("could not get wmi handle"); + return; + } + + wmi_set_qmi_stats(wmi_handle, hdd_ctx->config->is_qmi_stats_enabled); +} +#else +static inline +void hdd_set_qmi_stats_enabled(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef CONFIG_FW_LOGS_BASED_ON_INI +/** + * hdd_set_fw_log_params() - Set log parameters to FW + * @hdd_ctx: HDD Context + * @vdev_id: vdev_id + * + * This function set the FW Debug log level based on the INI. + * + * Return: None + */ +static void hdd_set_fw_log_params(struct hdd_context *hdd_ctx, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint16_t enable_fw_log_level, enable_fw_log_type; + int ret; + + if (!hdd_ctx->config->enable_fw_log) { + hdd_debug("enable_fw_log not enabled in INI"); + return; + } + + /* Enable FW logs based on INI configuration */ + status = ucfg_fwol_get_enable_fw_log_type(hdd_ctx->psoc, + &enable_fw_log_type); + if (QDF_IS_STATUS_ERROR(status)) + return; + ret = sme_cli_set_command(vdev_id, WMI_DBGLOG_TYPE, + enable_fw_log_type, DBG_CMD); + if (ret != 0) + hdd_err("Failed to enable FW log type ret %d", ret); + + status = ucfg_fwol_get_enable_fw_log_level(hdd_ctx->psoc, + &enable_fw_log_level); + if (QDF_IS_STATUS_ERROR(status)) + return; + ret = sme_cli_set_command(vdev_id, WMI_DBGLOG_LOG_LEVEL, + enable_fw_log_level, DBG_CMD); + if (ret != 0) + hdd_err("Failed to enable FW log level ret %d", ret); + + sme_enable_fw_module_log_level(hdd_ctx->mac_handle, vdev_id); +} +#else +static void hdd_set_fw_log_params(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ +} + +#endif + +/** + * hdd_features_deinit() - Deinit features + * @hdd_ctx: HDD context + * + * De-Initialize features and their feature context. + * + * Return: none. + */ +static void hdd_features_deinit(struct hdd_context *hdd_ctx) +{ + wlan_hdd_gpio_wakeup_deinit(hdd_ctx); + wlan_hdd_twt_deinit(hdd_ctx); + wlan_hdd_deinit_chan_info(hdd_ctx); + wlan_hdd_tsf_deinit(hdd_ctx); + if (cds_is_packet_log_enabled()) + hdd_pktlog_enable_disable(hdd_ctx, false, 0, 0); +} + +/** + * hdd_deconfigure_cds() -De-Configure cds + * @hdd_ctx: HDD context + * + * Deconfigure Cds modules before WLAN firmware is down. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_deconfigure_cds(struct hdd_context *hdd_ctx) +{ + QDF_STATUS qdf_status; + int ret = 0; + + hdd_enter(); + + wlan_hdd_hang_event_notifier_unregister(); + /* De-init features */ + hdd_features_deinit(hdd_ctx); + + qdf_status = policy_mgr_deregister_mode_change_cb(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_debug("Failed to deregister mode change cb with Policy Manager"); + + qdf_status = cds_disable(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to Disable the CDS Modules! :%d", + qdf_status); + ret = -EINVAL; + } + + if (ucfg_ipa_uc_ol_deinit(hdd_ctx->pdev) != QDF_STATUS_SUCCESS) { + hdd_err("Failed to disconnect pipes"); + ret = -EINVAL; + } + + hdd_exit(); + return ret; +} + +/** + * hdd_qmi_register_callbacks() - Register QMI callbacks + * @hdd_ctx: HDD context + * + * Return: None + */ +static inline void hdd_qmi_register_callbacks(struct hdd_context *hdd_ctx) +{ + struct wlan_qmi_psoc_callbacks cb_obj; + + os_if_qmi_register_callbacks(hdd_ctx->psoc, &cb_obj); +} + +/** + * hdd_set_pcie_params() - Set pcie params + * @hdd_ctx: HDD context + * @index: index value + * @param: pointer to vdev/pdev set param info + * + * Checks for pcie_config value and sets + * corresponding params + * + * Return: 0 on success and errno on failure. + */ +static int hdd_set_pcie_params(struct hdd_context *hdd_ctx, + uint8_t index, struct dev_set_param *param) +{ + int ret = 0; + uint8_t check_value = 0; + + ret = ucfg_fwol_get_pcie_config(hdd_ctx->psoc, &check_value); + if (QDF_IS_STATUS_SUCCESS(ret)) { + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + ret = mlme_check_index_setparam(param, + wmi_pdev_param_pcie_config, + (int)check_value, index++, + FTM_MAX_PDEV_PARAMS); + } else { + ret = mlme_check_index_setparam(param, + wmi_pdev_param_pcie_config, + (int)check_value, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + } + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed to set wmi_pdev_param_pcie_config"); + return ret; + } + } + return ret; +} + +#ifdef FEATURE_SET +#ifdef WLAN_FEATURE_11BE +/** + * hdd_is_cfg_dot11_mode_11be() - Check if dot11 mode is 11 be + * @dot11_mode: Input dot11_mode which needs to be checked + * + * Return: True, ifinput dot11_mode is 11be dot11 mode else return false + */ +static bool hdd_is_cfg_dot11_mode_11be(enum hdd_dot11_mode dot11_mode) +{ + return (dot11_mode == eHDD_DOT11_MODE_11be || + dot11_mode == eHDD_DOT11_MODE_11be_ONLY); +} + +/** + * hdd_is_11be_supported() - Check if 11be is supported or not + * @hdd_ctx: Pointer to hdd context + * + * Return: True, if 11be is supported else return false + */ +static bool hdd_is_11be_supported(struct hdd_context *hdd_ctx) +{ + bool mlo_capab; + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &mlo_capab); + if (!mlo_capab) + return false; + + return true; +} +#else + +static bool hdd_is_cfg_dot11_mode_11be(enum hdd_dot11_mode dot11_mode) +{ + return false; +} + +static bool hdd_is_11be_supported(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +WMI_HOST_WIFI_STANDARD +hdd_get_wifi_standard(struct hdd_context *hdd_ctx, + enum hdd_dot11_mode dot11_mode, uint32_t band_capability) +{ + WMI_HOST_WIFI_STANDARD wifi_standard = WMI_HOST_WIFI_STANDARD_4; + + if (dot11_mode == eHDD_DOT11_MODE_AUTO) { + if (hdd_is_11be_supported(hdd_ctx)) + wifi_standard = WMI_HOST_WIFI_STANDARD_7; + else if (band_capability & BIT(REG_BAND_6G)) + wifi_standard = WMI_HOST_WIFI_STANDARD_6E; + else + wifi_standard = WMI_HOST_WIFI_STANDARD_6; + } else if (hdd_is_cfg_dot11_mode_11be(dot11_mode)) { + wifi_standard = WMI_HOST_WIFI_STANDARD_7; + } else if (dot11_mode == eHDD_DOT11_MODE_11ax || + (dot11_mode == eHDD_DOT11_MODE_11ax_ONLY)) { + if (band_capability & BIT(REG_BAND_6G)) + wifi_standard = WMI_HOST_WIFI_STANDARD_6E; + else + wifi_standard = WMI_HOST_WIFI_STANDARD_6; + } else if ((dot11_mode == eHDD_DOT11_MODE_11ac) || + (dot11_mode == eHDD_DOT11_MODE_11ac_ONLY)) { + wifi_standard = WMI_HOST_WIFI_STANDARD_5; + } + + return wifi_standard; +} + +/** + * hdd_populate_feature_set_cds_config() - Populate cds feature set config + * @hdd_ctx: hdd context pointer + * + * Return: None + */ +static void hdd_populate_feature_set_cds_config(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc; + uint32_t band_capability; + QDF_STATUS status; + struct cds_config_info *cds_cfg; + + if (!hdd_ctx) + return; + + cds_cfg = cds_get_ini_config(); + if (!cds_cfg) { + hdd_err("CDS config is null."); + return; + } + + psoc = hdd_ctx->psoc; + + cds_cfg->get_wifi_features = hdd_ctx->config->get_wifi_features; + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get MLME band capability"); + + band_capability = + hdd_update_band_cap_from_dot11mode(hdd_ctx, band_capability); + + cds_cfg->cds_feature_set.wifi_standard = + hdd_get_wifi_standard(hdd_ctx, + hdd_ctx->config->dot11Mode, + band_capability); + + cds_cfg->cds_feature_set.sap_5g_supported = + band_capability & BIT(REG_BAND_5G); + + cds_cfg->cds_feature_set.sap_6g_supported = + band_capability & BIT(REG_BAND_6G); + cds_cfg->cds_feature_set.band_capability = band_capability; +} +#else +WMI_HOST_WIFI_STANDARD +hdd_get_wifi_standard(struct hdd_context *hdd_ctx, + enum hdd_dot11_mode dot11_mode, uint32_t band_capability) +{ + return WMI_HOST_WIFI_STANDARD_5; +} + +static inline void +hdd_populate_feature_set_cds_config(struct hdd_context *hdd_ctx) +{ +} +#endif + +int hdd_wlan_start_modules(struct hdd_context *hdd_ctx, bool reinit) +{ + int ret = 0; + qdf_device_t qdf_dev; + QDF_STATUS status; + bool unint = false; + void *hif_ctx; + struct target_psoc_info *tgt_hdl; + unsigned long thermal_state = 0; + uint8_t index = 0; + struct dev_set_param setparam[MAX_PDEV_PRE_ENABLE_PARAMS] = {}; + + hdd_enter(); + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + hdd_exit(); + return -EINVAL; + } + + hdd_psoc_idle_timer_stop(hdd_ctx); + + if (hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) { + hdd_debug("Driver modules already Enabled"); + hdd_exit(); + return 0; + } + + cds_set_driver_state_module_stop(false); + + switch (hdd_ctx->driver_status) { + case DRIVER_MODULES_UNINITIALIZED: + hdd_nofl_debug("Wlan transitioning (UNINITIALIZED -> CLOSED)"); + unint = true; + fallthrough; + case DRIVER_MODULES_CLOSED: + hdd_nofl_debug("Wlan transitioning (CLOSED -> ENABLED)"); + ret = hdd_debug_domain_set(QDF_DEBUG_DOMAIN_ACTIVE); + if (ret) + goto abort; + + if (!reinit && !unint) { + ret = pld_power_on(qdf_dev->dev); + if (ret) { + hdd_err("Failed to power up device; errno:%d", + ret); + goto release_lock; + } + } + + hdd_init_adapter_ops_wq(hdd_ctx); + pld_set_fw_log_mode(hdd_ctx->parent_dev, + hdd_ctx->config->enable_fw_log); + ret = hdd_hif_open(qdf_dev->dev, qdf_dev->drv_hdl, qdf_dev->bid, + qdf_dev->bus_type, + (reinit == true) ? HIF_ENABLE_TYPE_REINIT : + HIF_ENABLE_TYPE_PROBE); + if (ret) { + hdd_err("Failed to open hif; errno: %d", ret); + goto power_down; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) { + ret = -EINVAL; + goto power_down; + } + + status = ol_cds_init(qdf_dev, hif_ctx); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("No Memory to Create BMI Context; status: %d", + status); + ret = qdf_status_to_os_return(status); + goto hif_close; + } + + if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) { + status = epping_open(); + if (status) { + hdd_err("Failed to open in epping mode: %d", + status); + ret = -EINVAL; + goto cds_free; + } + + status = epping_enable(qdf_dev->dev, false); + if (status) { + hdd_err("Failed to enable in epping mode : %d", + status); + epping_close(); + goto cds_free; + } + + hdd_info("epping mode enabled"); + break; + } + + if (pld_is_ipa_offload_disabled(qdf_dev->dev)) + ucfg_ipa_set_pld_enable(false); + + ucfg_ipa_component_config_update(hdd_ctx->psoc); + + hdd_update_cds_ac_specs_params(hdd_ctx); + + hdd_dp_register_callbacks(hdd_ctx); + + hdd_qmi_register_callbacks(hdd_ctx); + + status = hdd_component_psoc_open(hdd_ctx->psoc); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to Open legacy components; status: %d", + status); + ret = qdf_status_to_os_return(status); + goto ipa_component_free; + } + + ret = hdd_update_config(hdd_ctx); + if (ret) { + hdd_err("Failed to update configuration; errno: %d", + ret); + goto ipa_component_free; + } + + status = wbuff_module_init(); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("WBUFF init unsuccessful; status: %d", status); + + status = cds_open(hdd_ctx->psoc); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to Open CDS; status: %d", status); + ret = qdf_status_to_os_return(status); + goto psoc_close; + } + + hdd_populate_feature_set_cds_config(hdd_ctx); + + hdd_set_qmi_stats_enabled(hdd_ctx); + + hdd_ctx->mac_handle = cds_get_context(QDF_MODULE_ID_SME); + + ucfg_dp_set_rx_thread_affinity(hdd_ctx->psoc); + + /* initialize components configurations after psoc open */ + ret = hdd_update_components_config(hdd_ctx); + if (ret) { + hdd_err("Failed to update component configs; errno: %d", + ret); + goto close; + } + + /* Override PS params for monitor mode */ + if (hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + hdd_override_all_ps(hdd_ctx); + + status = cds_dp_open(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to Open cds post open; status: %d", + status); + ret = qdf_status_to_os_return(status); + goto close; + } + /* Set IRQ affinity for WLAN DP and CE IRQS */ + hif_config_irq_set_perf_affinity_hint(hif_ctx); + + ret = hdd_register_cb(hdd_ctx); + if (ret) { + hdd_err("Failed to register HDD callbacks!"); + goto cds_txrx_free; + } + + ret = hdd_register_notifiers(hdd_ctx); + if (ret) + goto deregister_cb; + + /* + * NAN component requires certain operations like, open adapter, + * close adapter, etc. to be initiated by HDD, for those + * register HDD callbacks with UMAC's NAN component. + */ + hdd_nan_register_callbacks(hdd_ctx); + + hdd_son_register_callbacks(hdd_ctx); + + hdd_sr_register_callbacks(hdd_ctx); + + wlan_hdd_register_btc_chain_mode_handler(hdd_ctx->psoc); + + wlan_hdd_register_afc_pld_cb(hdd_ctx->psoc); + + status = cds_pre_enable(); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to pre-enable CDS; status: %d", status); + ret = qdf_status_to_os_return(status); + goto unregister_notifiers; + } + + hdd_register_policy_manager_callback( + hdd_ctx->psoc); + + /* + * Call this function before hdd_enable_power_management. Since + * it is required to trigger WMI_PDEV_DMA_RING_CFG_REQ_CMDID + * to FW when power save isn't enable. + */ + hdd_spectral_register_to_dbr(hdd_ctx); + + hdd_create_sysfs_files(hdd_ctx); + hdd_update_hw_sw_info(hdd_ctx); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_enable_power_management(hdd_ctx); + hdd_err("in ftm mode, no need to configure cds modules"); + hdd_info("Enable FW log in ftm mode"); + /* + * Since vdev is not created for FTM mode, + * in FW use vdev_id = 0. + */ + hdd_set_fw_log_params(hdd_ctx, 0); + ret = hdd_set_pcie_params(hdd_ctx, index, setparam); + if (QDF_IS_STATUS_ERROR(ret)) + break; + index++; + ret = sme_send_multi_pdev_vdev_set_params( + MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, index); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed to send pdev set params"); + return ret; + } + + ret = -EINVAL; + break; + } + + ret = hdd_configure_cds(hdd_ctx); + if (ret) { + hdd_err("Failed to Enable cds modules; errno: %d", ret); + goto sched_disable; + } + + if (hdd_get_conparam() == QDF_GLOBAL_MISSION_MODE) { + status = ucfg_dp_direct_link_init(hdd_ctx->psoc); + if (QDF_IS_STATUS_ERROR(status)) { + cds_err("Failed to initialize Direct Link datapath"); + ret = -EINVAL; + goto deconfigure_cds; + } + } + + hdd_enable_power_management(hdd_ctx); + + hdd_skip_acs_scan_timer_init(hdd_ctx); + + hdd_set_hif_init_phase(hif_ctx, false); + hdd_hif_set_enable_detection(hif_ctx, true); + + wlan_hdd_start_connectivity_logging(hdd_ctx); + + break; + + default: + QDF_DEBUG_PANIC("Unknown driver state:%d", + hdd_ctx->driver_status); + ret = -EINVAL; + goto release_lock; + } + + hdd_ctx->driver_status = DRIVER_MODULES_ENABLED; + hdd_nofl_debug("Wlan transitioned (now ENABLED)"); + + ucfg_ipa_reg_is_driver_unloading_cb(hdd_ctx->pdev, + cds_is_driver_unloading); + ucfg_ipa_reg_sap_xmit_cb(hdd_ctx->pdev, + hdd_softap_ipa_start_xmit); + ucfg_ipa_reg_send_to_nw_cb(hdd_ctx->pdev, + hdd_ipa_send_nbuf_to_network); + ucfg_dp_reg_ipa_rsp_ind(hdd_ctx->pdev); + + if (!pld_get_thermal_state(hdd_ctx->parent_dev, &thermal_state, + THERMAL_MONITOR_APPS)) { + if (thermal_state > QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE) + hdd_send_thermal_mitigation_val(hdd_ctx, + thermal_state, + THERMAL_MONITOR_APPS); + } + + if (!pld_get_thermal_state(hdd_ctx->parent_dev, &thermal_state, + THERMAL_MONITOR_WPSS)) { + if (thermal_state > QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE) + hdd_send_thermal_mitigation_val(hdd_ctx, thermal_state, + THERMAL_MONITOR_WPSS); + } + + hdd_exit(); + + return 0; + +deconfigure_cds: + hdd_deconfigure_cds(hdd_ctx); +sched_disable: + /* + * Disable scheduler 1st so that scheduler thread doesn't send messages + * to fw in parallel to the cleanup + */ + dispatcher_disable(); + hdd_destroy_sysfs_files(); + cds_post_disable(); +unregister_notifiers: + hdd_unregister_notifiers(hdd_ctx); + +deregister_cb: + hdd_deregister_cb(hdd_ctx); + +cds_txrx_free: + + tgt_hdl = wlan_psoc_get_tgt_if_handle(hdd_ctx->psoc); + + if (tgt_hdl && target_psoc_get_wmi_ready(tgt_hdl)) + hdd_runtime_suspend_context_deinit(hdd_ctx); + + if (hdd_ctx->pdev) { + dispatcher_pdev_close(hdd_ctx->pdev); + hdd_objmgr_release_and_destroy_pdev(hdd_ctx); + } + + cds_dp_close(hdd_ctx->psoc); + +close: + dispatcher_disable(); + hdd_ctx->driver_status = DRIVER_MODULES_CLOSED; + hdd_info("Wlan transition aborted (now CLOSED)"); + + cds_close(hdd_ctx->psoc); + +psoc_close: + hdd_component_psoc_close(hdd_ctx->psoc); + wlan_global_lmac_if_close(hdd_ctx->psoc); + cds_deinit_ini_config(); + +ipa_component_free: + ucfg_ipa_component_config_free(); + +cds_free: + ol_cds_free(); + +hif_close: + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + hdd_hif_close(hdd_ctx, hif_ctx); +power_down: + hdd_deinit_adapter_ops_wq(hdd_ctx); + if (!reinit && !unint) + pld_power_off(qdf_dev->dev); +release_lock: + cds_shutdown_notifier_purge(); + hdd_check_for_leaks(hdd_ctx, reinit); + hdd_debug_domain_set(QDF_DEBUG_DOMAIN_INIT); + +abort: + cds_set_driver_state_module_stop(true); + + hdd_exit(); + + return ret; +} + +#ifdef WIFI_POS_CONVERGED +static int hdd_activate_wifi_pos(struct hdd_context *hdd_ctx) +{ + int ret = os_if_wifi_pos_register_nl(); + + if (ret) + hdd_err("os_if_wifi_pos_register_nl failed"); + + return ret; +} + +static int hdd_deactivate_wifi_pos(void) +{ + int ret = os_if_wifi_pos_deregister_nl(); + + if (ret) + hdd_err("os_if_wifi_pos_deregister_nl failed"); + + return ret; +} + +/** + * hdd_populate_wifi_pos_cfg - populates wifi_pos parameters + * @hdd_ctx: hdd context + * + * Return: status of operation + */ +static void hdd_populate_wifi_pos_cfg(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + uint16_t neighbor_scan_max_chan_time; + uint16_t neighbor_scan_min_chan_time; + + wifi_pos_set_oem_target_type(psoc, hdd_ctx->target_type); + wifi_pos_set_oem_fw_version(psoc, hdd_ctx->target_fw_version); + wifi_pos_set_drv_ver_major(psoc, QWLAN_VERSION_MAJOR); + wifi_pos_set_drv_ver_minor(psoc, QWLAN_VERSION_MINOR); + wifi_pos_set_drv_ver_patch(psoc, QWLAN_VERSION_PATCH); + wifi_pos_set_drv_ver_build(psoc, QWLAN_VERSION_BUILD); + ucfg_mlme_get_neighbor_scan_max_chan_time(psoc, + &neighbor_scan_max_chan_time); + ucfg_mlme_get_neighbor_scan_min_chan_time(psoc, + &neighbor_scan_min_chan_time); + wifi_pos_set_dwell_time_min(psoc, neighbor_scan_min_chan_time); + wifi_pos_set_dwell_time_max(psoc, neighbor_scan_max_chan_time); +} +#else +static int hdd_activate_wifi_pos(struct hdd_context *hdd_ctx) +{ + return oem_activate_service(hdd_ctx); +} + +static int hdd_deactivate_wifi_pos(void) +{ + return oem_deactivate_service(); +} + +static void hdd_populate_wifi_pos_cfg(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * __hdd_open() - HDD Open function + * @dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int __hdd_open(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter_dev(dev); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_OPEN_REQUEST, + link_info->vdev_id, adapter->device_mode); + + /* Nothing to be done if device is unloading */ + if (cds_is_driver_unloading()) { + hdd_err("Driver is unloading can not open the hdd"); + return -EBUSY; + } + + if (cds_is_driver_recovering()) { + hdd_err("WLAN is currently recovering; Please try again."); + return -EBUSY; + } + + /* + * This scenario can be hit in cases where in the wlan driver after + * registering the netdevices and there is a failure in driver + * initialization. So return error gracefully because the netdevices + * will be de-registered as part of the load failure. + */ + + if (!cds_is_driver_loaded()) { + hdd_err("Failed to start the wlan driver!!"); + return -EIO; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + hdd_err("Can't start WLAN module, WiFi Disabled"); + return ret; + } + + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start WLAN modules return"); + return ret; + } + + if (!test_bit(SME_SESSION_OPENED, &link_info->link_flags)) { + ret = hdd_start_adapter(adapter, true); + if (ret) { + hdd_err("Failed to start adapter :%d", + adapter->device_mode); + return ret; + } + } + + set_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + if (hdd_cm_is_vdev_associated(link_info)) { + hdd_debug("Enabling Tx Queues"); + /* Enable TX queues only when we are connected */ + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + + /* Enable carrier and transmit queues for NDI */ + if (WLAN_HDD_IS_NDI(adapter)) { + hdd_debug("Enabling Tx Queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + + hdd_populate_wifi_pos_cfg(hdd_ctx); + hdd_lpass_notify_start(link_info); + + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) + hdd_map_monitor_interface_vdev(adapter); + + return 0; +} + +/** + * hdd_open() - Wrapper function for __hdd_open to protect it from SSR + * @net_dev: Pointer to net_device structure + * + * This is called in response to ifconfig up + * + * Return: 0 for success; non-zero for failure + */ +static int hdd_open(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_open(net_dev); + if (!errno) + osif_vdev_cache_command(vdev_sync, NO_COMMAND); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} + +int hdd_stop_no_trans(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_STOP_REQUEST, + adapter->deflink->vdev_id, adapter->device_mode); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + /* Nothing to be done if the interface is not opened */ + if (false == test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("NETDEV Interface is not OPENED"); + return -ENODEV; + } + + mac_handle = hdd_ctx->mac_handle; + + if (!wlan_hdd_is_session_type_monitor(adapter->device_mode) && + adapter->device_mode != QDF_FTM_MODE) { + hdd_debug("Disabling Auto Power save timer"); + sme_ps_disable_auto_ps_timer( + mac_handle, + adapter->deflink->vdev_id); + } + + /* + * Disable TX on the interface, after this hard_start_xmit() will not + * be called on that interface + */ + hdd_debug("Disabling queues, adapter device mode: %s(%d)", + qdf_opmode_str(adapter->device_mode), adapter->device_mode); + + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + if (adapter->device_mode == QDF_STA_MODE) + hdd_lpass_notify_stop(hdd_ctx); + + /* + * NAN data interface is different in some sense. The traffic on NDI is + * bursty in nature and depends on the need to transfer. The service + * layer may down the interface after the usage and up again when + * required. In some sense, the NDI is expected to be available + * (like SAP) iface until NDI delete request is issued by the service + * layer. Skip BSS termination and adapter deletion for NAN Data + * interface (NDI). + */ + if (WLAN_HDD_IS_NDI(adapter)) + goto reset_iface_opened; + + /* + * The interface is marked as down for outside world (aka kernel) + * But the driver is pretty much alive inside. The driver needs to + * tear down the existing connection on the netdev (session) + * cleanup the data pipes and wait until the control plane is stabilized + * for this interface. The call also needs to wait until the above + * mentioned actions are completed before returning to the caller. + * Notice that hdd_stop_adapter is requested not to close the session + * That is intentional to be able to scan if it is a STA/P2P interface + */ + hdd_stop_adapter(hdd_ctx, adapter); + + /* DeInit the adapter. This ensures datapath cleanup as well */ + hdd_deinit_adapter(hdd_ctx, adapter, true); + +reset_iface_opened: + /* Make sure the interface is marked as closed */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + if (!hdd_is_any_interface_open(hdd_ctx)) + hdd_psoc_idle_timer_start(hdd_ctx); + hdd_exit(); + + return 0; +} + +/** + * hdd_stop() - Wrapper function for __hdd_stop to protect it from SSR + * @net_dev: pointer to net_device structure + * + * This is called in response to ifconfig down + * + * Return: 0 for success and error number for failure + */ +static int hdd_stop(struct net_device *net_dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_trans_start(net_dev, &vdev_sync); + if (errno) { + if (vdev_sync) + osif_vdev_cache_command(vdev_sync, INTERFACE_DOWN); + return errno; + } + + errno = hdd_stop_no_trans(net_dev); + + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} + +/** + * hdd_uninit() - HDD uninit function + * @dev: Pointer to net_device structure + * + * This is called during the netdev unregister to uninitialize all data + * associated with the device + * + * This function must be protected by a transition + * + * Return: None + */ +static void hdd_uninit(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + + hdd_enter_dev(dev); + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid magic"); + goto exit; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("NULL hdd_ctx"); + goto exit; + } + + if (dev != adapter->dev) + hdd_err("Invalid device reference"); + + hdd_deinit_adapter(hdd_ctx, adapter, true); + + /* after uninit our adapter structure will no longer be valid */ + adapter->magic = 0; + +exit: + hdd_exit(); +} + +static int hdd_open_cesium_nl_sock(void) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + struct netlink_kernel_cfg cfg = { + .groups = WLAN_NLINK_MCAST_GRP_ID, + .input = NULL + }; +#endif + int ret = 0; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)) + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)) + THIS_MODULE, +#endif + &cfg); +#else + cesium_nl_srv_sock = netlink_kernel_create(&init_net, WLAN_NLINK_CESIUM, + WLAN_NLINK_MCAST_GRP_ID, + NULL, NULL, THIS_MODULE); +#endif + + if (!cesium_nl_srv_sock) { + hdd_err("NLINK: cesium netlink_kernel_create failed"); + ret = -ECONNREFUSED; + } + + return ret; +} + +static void hdd_close_cesium_nl_sock(void) +{ + if (cesium_nl_srv_sock) { + netlink_kernel_release(cesium_nl_srv_sock); + cesium_nl_srv_sock = NULL; + } +} + +void hdd_update_dynamic_mac(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *curr_mac_addr, + struct qdf_mac_addr *new_mac_addr) +{ + uint8_t i; + + hdd_enter(); + + for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + if (!qdf_mem_cmp( + curr_mac_addr->bytes, + &hdd_ctx->dynamic_mac_list[i].dynamic_mac.bytes[0], + sizeof(struct qdf_mac_addr))) { + qdf_mem_copy(&hdd_ctx->dynamic_mac_list[i].dynamic_mac, + new_mac_addr->bytes, + sizeof(struct qdf_mac_addr)); + break; + } + } + + hdd_exit(); +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + !defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +void hdd_set_mld_address(struct hdd_adapter *adapter, + const struct qdf_mac_addr *mac_addr) +{ + int i; + bool eht_capab; + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + + ucfg_psoc_mlme_get_11be_capab(adapter->hdd_ctx->psoc, &eht_capab); + if (adapter->mlo_adapter_info.is_ml_adapter && eht_capab) { + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (link_adapter) + qdf_copy_macaddr(&link_adapter->mld_addr, + mac_addr); + } + qdf_copy_macaddr(&adapter->mld_addr, mac_addr); + } +} + +/** + * hdd_get_netdev_by_vdev_mac() - Get Netdev based on MAC + * @mac_addr: Vdev MAC address + * + * Get netdev from adapter based upon Vdev MAC address. + * + * Return: netdev pointer. + */ +static qdf_netdev_t +hdd_get_netdev_by_vdev_mac(struct qdf_mac_addr *mac_addr) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct hdd_adapter *ml_adapter; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return NULL; + } + + adapter = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr->bytes); + if (!adapter) { + hdd_err("Adapter not foud for MAC " QDF_MAC_ADDR_FMT "", + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return NULL; + } + + if (adapter->mlo_adapter_info.is_link_adapter && + adapter->mlo_adapter_info.associate_with_ml_adapter) { + ml_adapter = adapter->mlo_adapter_info.ml_adapter; + adapter = ml_adapter; + } + + return adapter->dev; +} +#else +static qdf_netdev_t +hdd_get_netdev_by_vdev_mac(struct qdf_mac_addr *mac_addr) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return NULL; + } + + adapter = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr->bytes); + if (!adapter) { + hdd_err("Adapter not foud for MAC " QDF_MAC_ADDR_FMT "", + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return NULL; + } + + return adapter->dev; +} +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + !defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static void hdd_update_set_mac_addr_req_ctx(struct hdd_adapter *adapter, + void *req_ctx) +{ + adapter->set_mac_addr_req_ctx = req_ctx; + if (adapter->mlo_adapter_info.associate_with_ml_adapter) + adapter->mlo_adapter_info.ml_adapter->set_mac_addr_req_ctx = + req_ctx; +} +#else +static void hdd_update_set_mac_addr_req_ctx(struct hdd_adapter *adapter, + void *req_ctx) +{ + adapter->set_mac_addr_req_ctx = req_ctx; +} +#endif + +/** + * hdd_is_dynamic_set_mac_addr_supported() - API to check dynamic MAC address + * update is supported or not + * @hdd_ctx: Pointer to the HDD context + * + * Return: true or false + */ +static inline bool +hdd_is_dynamic_set_mac_addr_supported(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->is_vdev_macaddr_dynamic_update_supported; +} + +bool hdd_is_dynamic_set_mac_addr_allowed(struct hdd_adapter *adapter) +{ + if (!adapter->deflink->vdev) { + hdd_err("VDEV is NULL"); + return false; + } + + if (!hdd_is_dynamic_set_mac_addr_supported(adapter->hdd_ctx)) { + hdd_info_rl("On iface up, set mac address change isn't supported"); + return false; + } + + switch (adapter->device_mode) { + case QDF_STA_MODE: + if (!cm_is_vdev_disconnected(adapter->deflink->vdev)) { + hdd_info_rl("VDEV is not in disconnected state, set mac address isn't supported"); + return false; + } + return true; + case QDF_P2P_DEVICE_MODE: + return ucfg_is_p2p_device_dynamic_set_mac_addr_supported(adapter->hdd_ctx->psoc); + case QDF_SAP_MODE: + if (test_bit(SOFTAP_BSS_STARTED, + &adapter->deflink->link_flags)) { + hdd_info_rl("SAP is in up state, set mac address isn't supported"); + return false; + } else { + return true; + } + default: + hdd_info_rl("Dynamic set mac address isn't supported for opmode:%d", + adapter->device_mode); + return false; + } +} + +int hdd_dynamic_mac_address_set(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + bool update_self_peer) +{ + int ret; + void *cookie; + bool update_mld_addr; + uint32_t fw_resp_status; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct osif_request *request; + struct wlan_objmgr_vdev *vdev; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct mac_addr_set_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_SET_MAC_ADDR_TIMEOUT + }; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + if (wlan_vdev_mlme_get_opmode(vdev) != QDF_P2P_DEVICE_MODE) { + status = ucfg_vdev_mgr_cdp_vdev_detach(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to detach CDP vdev. Status:%d", status); + ret = qdf_status_to_os_return(status); + goto vdev_ref; + } + } + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("request alloc fail"); + status = QDF_STATUS_E_NOMEM; + ret = -ENOMEM; + goto status_ret; + } + + /* Host should hold a wake lock until the FW event response is received + * the WMI event would not be a wake up event. + */ + qdf_runtime_pm_prevent_suspend( + &hdd_ctx->runtime_context.dyn_mac_addr_update); + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DYN_MAC_ADDR_UPDATE); + + cookie = osif_request_cookie(request); + hdd_update_set_mac_addr_req_ctx(adapter, cookie); + + priv = (struct mac_addr_set_priv *)osif_request_priv(request); + + /* For p2p device mode, need send delete self peer cmd to F/W, + * To avoid p2p new DP vdev is created before old DP vdev deleted, + * don't create new DP vdev until both self peer delete rsp and set + * mac addr rsp received, so initialize pending_rsp_cnt as 2. + * + * For other mode like STA/SAP, don't need send delete self peer cmd + * to F/W, only need wait set mad addr rsp, so initialize + * pending_rsp_cnt as 1. + */ + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_P2P_DEVICE_MODE) + qdf_atomic_set(&priv->pending_rsp_cnt, 2); + else + qdf_atomic_set(&priv->pending_rsp_cnt, 1); + + status = sme_send_set_mac_addr(mac_addr, mld_addr, vdev); + ret = qdf_status_to_os_return(status); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_nofl_err("Failed to send set MAC address command. Status:%d", + status); + osif_request_put(request); + goto status_ret; + } else { + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Set MAC address response timed out"); + } else { + fw_resp_status = priv->fw_resp_status; + if (fw_resp_status) { + hdd_err("Set MAC address failed in FW. Status: %d", + fw_resp_status); + ret = -EAGAIN; + } + } + } + + osif_request_put(request); + + if (qdf_is_macaddr_zero(&mld_addr)) + update_mld_addr = false; + else + update_mld_addr = true; + + status = sme_update_vdev_mac_addr(vdev, mac_addr, mld_addr, + update_self_peer, update_mld_addr, + ret); + +status_ret: + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto allow_suspend; + } else if (!ret) { + status = ucfg_dp_update_link_mac_addr(vdev, &mac_addr, false); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + hdd_err("DP link MAC update failed"); + goto allow_suspend; + } + } + sme_vdev_set_data_tx_callback(vdev); + + /* Update FW WoW pattern with new MAC address */ + ucfg_pmo_del_wow_pattern(vdev); + ucfg_pmo_register_wow_default_patterns(vdev); + hdd_tx_latency_restore_config(link_info); + +allow_suspend: + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DYN_MAC_ADDR_UPDATE); + qdf_runtime_pm_allow_suspend( + &hdd_ctx->runtime_context.dyn_mac_addr_update); + +vdev_ref: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return ret; +} + +static void hdd_set_mac_addr_event_cb(uint8_t vdev_id, uint8_t status) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + struct osif_request *req; + struct mac_addr_set_priv *priv; + + osif_debug("enter"); + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("No adapter found for VDEV ID:%d", vdev_id); + return; + } + + req = osif_request_get(link_info->adapter->set_mac_addr_req_ctx); + if (!req) { + osif_err("Obsolete request for VDEV ID:%d", vdev_id); + return; + } + + priv = (struct mac_addr_set_priv *)osif_request_priv(req); + + if (qdf_atomic_dec_and_test(&priv->pending_rsp_cnt)) { + priv->fw_resp_status = status; + osif_request_complete(req); + } + + osif_request_put(req); +} +#else +static inline bool +hdd_is_dynamic_set_mac_addr_supported(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static QDF_STATUS +hdd_adapter_update_links_on_link_switch(struct wlan_hdd_link_info *cur_link_info, + struct wlan_hdd_link_info *new_link_info) +{ + unsigned long link_flags; + struct wlan_objmgr_vdev *vdev; + int cur_link_idx, new_link_idx; + uint8_t cur_old_pos, cur_new_pos; + struct vdev_osif_priv *vdev_priv; + struct hdd_adapter *adapter = cur_link_info->adapter; + + /* Update the new position of current and new link info + * in the link info array. + */ + cur_link_idx = hdd_adapter_get_index_of_link_info(cur_link_info); + new_link_idx = hdd_adapter_get_index_of_link_info(new_link_info); + + cur_old_pos = adapter->curr_link_info_map[cur_link_idx]; + cur_new_pos = adapter->curr_link_info_map[new_link_idx]; + + adapter->curr_link_info_map[new_link_idx] = cur_old_pos; + adapter->curr_link_info_map[cur_link_idx] = cur_new_pos; + + /* Move VDEV from current link info to new link info */ + qdf_atomic_clear_bit(cur_link_idx, &adapter->active_links); + qdf_spin_lock_bh(&cur_link_info->vdev_lock); + vdev = cur_link_info->vdev; + cur_link_info->vdev = NULL; + cur_link_info->vdev_id = WLAN_INVALID_VDEV_ID; + qdf_spin_unlock_bh(&cur_link_info->vdev_lock); + + qdf_spin_lock_bh(&new_link_info->vdev_lock); + new_link_info->vdev = vdev; + new_link_info->vdev_id = wlan_vdev_get_id(vdev); + qdf_spin_unlock_bh(&new_link_info->vdev_lock); + qdf_atomic_set_bit(new_link_idx, &adapter->active_links); + + /* Move the link flags between current and new link info */ + link_flags = new_link_info->link_flags; + new_link_info->link_flags = cur_link_info->link_flags; + cur_link_info->link_flags = link_flags; + + /* Update VDEV-OSIF priv pointer to new link info */ + vdev_priv = wlan_vdev_get_ospriv(new_link_info->vdev); + vdev_priv->legacy_osif_priv = new_link_info; + + return QDF_STATUS_SUCCESS; +} + +struct wlan_hdd_link_info * +hdd_get_link_info_by_ieee_link_id(struct hdd_adapter *adapter, int32_t link_id) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + if (!adapter || link_id == WLAN_INVALID_LINK_ID) { + hdd_err("NULL adapter or invalid link ID"); + return NULL; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (sta_ctx->conn_info.ieee_link_id == link_id) + return link_info; + } + + return NULL; +} + +QDF_STATUS +hdd_link_switch_vdev_mac_addr_update(int32_t ieee_old_link_id, + int32_t ieee_new_link_id, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + struct wlan_hdd_link_info *cur_link_info, *new_link_info; + struct hdd_station_ctx *sta_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) { + hdd_err("HDD ctx NULL"); + return QDF_STATUS_E_INVAL; + } + + cur_link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!cur_link_info) { + hdd_err("VDEV %d not found", vdev_id); + return status; + } + + vdev = hdd_objmgr_get_vdev_by_user(cur_link_info, WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Invalid VDEV %d", vdev_id); + return status; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(cur_link_info); + if (sta_ctx->conn_info.ieee_link_id != ieee_old_link_id) { + hdd_err("Link id %d mismatch", sta_ctx->conn_info.ieee_link_id); + goto release_ref; + } + + adapter = cur_link_info->adapter; + new_link_info = hdd_get_link_info_by_ieee_link_id(adapter, + ieee_new_link_id); + if (!new_link_info) { + hdd_err("Link id %d not found", ieee_new_link_id); + goto release_ref; + } + + status = ucfg_dp_update_link_mac_addr(vdev, &new_link_info->link_addr, + true); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("DP link MAC update failed"); + goto release_ref; + } + + status = hdd_adapter_update_links_on_link_switch(cur_link_info, + new_link_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update adapter link info"); + goto release_ref; + } + + hdd_adapter_update_mlo_mgr_mac_addr(adapter); + sme_vdev_set_data_tx_callback(vdev); + ucfg_pmo_del_wow_pattern(vdev); + ucfg_pmo_register_wow_default_patterns(vdev); + +release_ref: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + return status; +} +#endif + +/** + * __hdd_set_mac_address() - set the user specified mac address + * @dev: Pointer to the net device. + * @addr: Pointer to the sockaddr. + * + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * Return: 0 for success, non zero for failure + */ +static int __hdd_set_mac_address(struct net_device *dev, void *addr) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_adapter *adapter_temp; + struct hdd_context *hdd_ctx; + struct sockaddr *psta_mac_addr = addr; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + int ret; + struct qdf_mac_addr mac_addr; + bool net_if_running = netif_running(dev); + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (net_if_running) { + if (!hdd_is_dynamic_set_mac_addr_allowed(adapter)) + return -ENOTSUPP; + } + + qdf_mem_copy(&mac_addr, psta_mac_addr->sa_data, sizeof(mac_addr)); + adapter_temp = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr.bytes); + if (adapter_temp) { + if (!qdf_str_cmp(adapter_temp->dev->name, dev->name)) + return 0; + hdd_err("%s adapter exist with same address " QDF_MAC_ADDR_FMT, + adapter_temp->dev->name, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + return -EINVAL; + } + qdf_ret_status = wlan_hdd_validate_mac_address(&mac_addr); + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) + return -EINVAL; + + hdd_nofl_debug("Changing MAC to " + QDF_MAC_ADDR_FMT " of the interface %s ", + QDF_MAC_ADDR_REF(mac_addr.bytes), dev->name); + + if (net_if_running && adapter->deflink->vdev) { + ret = hdd_update_vdev_mac_address(adapter, mac_addr); + if (ret) + return ret; + } + + hdd_set_mld_address(adapter, &mac_addr); + + hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, &mac_addr); + ucfg_dp_update_intf_mac(hdd_ctx->psoc, &adapter->mac_addr, &mac_addr, + adapter->deflink->vdev); + memcpy(&adapter->mac_addr, psta_mac_addr->sa_data, ETH_ALEN); + qdf_net_update_net_device_dev_addr(dev, psta_mac_addr->sa_data, + ETH_ALEN); + + hdd_exit(); + return ret; +} + +/** + * hdd_set_mac_address() - Wrapper function to protect __hdd_set_mac_address() + * function from SSR + * @net_dev: pointer to net_device structure + * @addr: Pointer to the sockaddr + * + * This function sets the user specified mac address using + * the command ifconfig wlanX hw ether . + * + * Return: 0 for success. + */ +static int hdd_set_mac_address(struct net_device *net_dev, void *addr) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_set_mac_address(net_dev, addr); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static uint8_t *wlan_hdd_get_derived_intf_addr(struct hdd_context *hdd_ctx) +{ + int i, j; + + i = qdf_ffz(hdd_ctx->derived_intf_addr_mask); + if (i < 0 || i >= hdd_ctx->num_derived_addr) + return NULL; + qdf_atomic_set_bit(i, &hdd_ctx->derived_intf_addr_mask); + hdd_nofl_debug("Assigning MAC from derived list "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdd_ctx->derived_mac_addr[i].bytes)); + + /* Copy the mac in dynamic mac list at first free position */ + for (j = 0; j < QDF_MAX_CONCURRENCY_PERSONA; j++) { + if (qdf_is_macaddr_zero(&hdd_ctx-> + dynamic_mac_list[j].dynamic_mac)) + break; + } + if (j == QDF_MAX_CONCURRENCY_PERSONA) { + hdd_err("Max interfaces are up"); + return NULL; + } + + qdf_mem_copy(&hdd_ctx->dynamic_mac_list[j].dynamic_mac.bytes, + &hdd_ctx->derived_mac_addr[i].bytes, + sizeof(struct qdf_mac_addr)); + hdd_ctx->dynamic_mac_list[j].is_provisioned_mac = false; + hdd_ctx->dynamic_mac_list[j].bit_position = i; + + return hdd_ctx->derived_mac_addr[i].bytes; +} + +static uint8_t *wlan_hdd_get_provisioned_intf_addr(struct hdd_context *hdd_ctx) +{ + int i, j; + + i = qdf_ffz(hdd_ctx->provisioned_intf_addr_mask); + if (i < 0 || i >= hdd_ctx->num_provisioned_addr) + return NULL; + qdf_atomic_set_bit(i, &hdd_ctx->provisioned_intf_addr_mask); + hdd_debug("Assigning MAC from provisioned list "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdd_ctx->provisioned_mac_addr[i].bytes)); + + /* Copy the mac in dynamic mac list at first free position */ + for (j = 0; j < QDF_MAX_CONCURRENCY_PERSONA; j++) { + if (qdf_is_macaddr_zero(&hdd_ctx-> + dynamic_mac_list[j].dynamic_mac)) + break; + } + if (j == QDF_MAX_CONCURRENCY_PERSONA) { + hdd_err("Max interfaces are up"); + return NULL; + } + + qdf_mem_copy(&hdd_ctx->dynamic_mac_list[j].dynamic_mac.bytes, + &hdd_ctx->provisioned_mac_addr[i].bytes, + sizeof(struct qdf_mac_addr)); + hdd_ctx->dynamic_mac_list[j].is_provisioned_mac = true; + hdd_ctx->dynamic_mac_list[j].bit_position = i; + return hdd_ctx->provisioned_mac_addr[i].bytes; +} + +uint8_t *wlan_hdd_get_intf_addr(struct hdd_context *hdd_ctx, + enum QDF_OPMODE interface_type) +{ + uint8_t *mac_addr = NULL; + + if (qdf_atomic_test_bit(interface_type, + (unsigned long *) + (&hdd_ctx->config->provisioned_intf_pool))) + mac_addr = wlan_hdd_get_provisioned_intf_addr(hdd_ctx); + + if ((!mac_addr) && + (qdf_atomic_test_bit(interface_type, + (unsigned long *) + (&hdd_ctx->config->derived_intf_pool)))) + mac_addr = wlan_hdd_get_derived_intf_addr(hdd_ctx); + + if (!mac_addr) + hdd_err("MAC is not available in both the lists"); + return mac_addr; +} + +void wlan_hdd_release_intf_addr(struct hdd_context *hdd_ctx, + uint8_t *releaseAddr) +{ + int i; + int mac_pos_in_mask; + + for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + if (!memcmp(releaseAddr, + hdd_ctx->dynamic_mac_list[i].dynamic_mac.bytes, + QDF_MAC_ADDR_SIZE)) { + mac_pos_in_mask = + hdd_ctx->dynamic_mac_list[i].bit_position; + if (hdd_ctx->dynamic_mac_list[i].is_provisioned_mac) { + qdf_atomic_clear_bit( + mac_pos_in_mask, + &hdd_ctx-> + provisioned_intf_addr_mask); + hdd_debug("Releasing MAC from provisioned list"); + hdd_debug( + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(releaseAddr)); + } else { + qdf_atomic_clear_bit( + mac_pos_in_mask, &hdd_ctx-> + derived_intf_addr_mask); + hdd_debug("Releasing MAC from derived list"); + hdd_debug(QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(releaseAddr)); + } + qdf_zero_macaddr(&hdd_ctx-> + dynamic_mac_list[i].dynamic_mac); + hdd_ctx->dynamic_mac_list[i].is_provisioned_mac = + false; + hdd_ctx->dynamic_mac_list[i].bit_position = 0; + break; + } + + } + if (i == QDF_MAX_CONCURRENCY_PERSONA) + hdd_debug("Releasing non existing MAC " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(releaseAddr)); +} + +/** + * hdd_set_derived_multicast_list(): Add derived peer multicast address list in + * multicast list request to the FW + * @psoc: Pointer to psoc + * @adapter: Pointer to hdd adapter + * @mc_list_request: Multicast list request to the FW + * @mc_count: number of multicast addresses received from the kernel + * + * Return: None + */ +static void +hdd_set_derived_multicast_list(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct pmo_mc_addr_list_params *mc_list_request, + int *mc_count) +{ + uint8_t i = 0, j = 0, list_count = *mc_count; + struct qdf_mac_addr *peer_mc_addr_list = NULL; + uint8_t driver_mc_cnt = 0; + uint32_t max_ndp_sessions = 0; + + cfg_nan_get_ndp_max_sessions(psoc, &max_ndp_sessions); + + ucfg_nan_get_peer_mc_list(adapter->deflink->vdev, &peer_mc_addr_list); + + for (j = 0; j < max_ndp_sessions; j++) { + for (i = 0; i < list_count; i++) { + if (qdf_is_macaddr_zero(&peer_mc_addr_list[j]) || + qdf_is_macaddr_equal(&mc_list_request->mc_addr[i], + &peer_mc_addr_list[j])) + break; + } + if (i == list_count && + (list_count + driver_mc_cnt < PMO_MAX_MC_ADDR_LIST)) { + qdf_mem_copy( + &(mc_list_request->mc_addr[list_count + + driver_mc_cnt].bytes), + peer_mc_addr_list[j].bytes, ETH_ALEN); + hdd_debug("mlist[%d] = " QDF_MAC_ADDR_FMT, + list_count + driver_mc_cnt, + QDF_MAC_ADDR_REF( + mc_list_request->mc_addr[list_count + + driver_mc_cnt].bytes)); + driver_mc_cnt++; + } + } + *mc_count += driver_mc_cnt; +} + +/** + * __hdd_set_multicast_list() - set the multicast address list + * @dev: Pointer to the WLAN device. + * + * This function sets the multicast address list. + * + * Return: None + */ +static void __hdd_set_multicast_list(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int i = 0, errno; + struct netdev_hw_addr *ha; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct pmo_mc_addr_list_params *mc_list_request = NULL; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + int mc_count = 0; + + if (hdd_ctx->hdd_wlan_suspended) { + hdd_err_rl("Device is system suspended"); + return; + } + + hdd_enter_dev(dev); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return; + + errno = hdd_validate_adapter(adapter); + if (errno) + return; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_debug("Driver module is closed"); + return; + } + + mc_list_request = qdf_mem_malloc(sizeof(*mc_list_request)); + if (!mc_list_request) + return; + + qdf_spin_lock_bh(&adapter->mc_list_lock); + /* Delete already configured multicast address list */ + if (adapter->mc_addr_list.mc_cnt > 0) + hdd_disable_and_flush_mc_addr_list(adapter, + pmo_mc_list_change_notify); + + if (dev->flags & IFF_ALLMULTI) { + hdd_debug("allow all multicast frames"); + hdd_disable_and_flush_mc_addr_list(adapter, + pmo_mc_list_change_notify); + } else { + mc_count = netdev_mc_count(dev); + if (mc_count > ucfg_pmo_max_mc_addr_supported(psoc)) { + hdd_debug("Exceeded max MC filter addresses (%d). Allowing all MC frames by disabling MC address filtering", + ucfg_pmo_max_mc_addr_supported(psoc)); + hdd_disable_and_flush_mc_addr_list(adapter, + pmo_mc_list_change_notify); + adapter->mc_addr_list.mc_cnt = 0; + goto free_req; + } + netdev_for_each_mc_addr(ha, dev) { + if (i == mc_count) + break; + memset(&(mc_list_request->mc_addr[i].bytes), + 0, ETH_ALEN); + memcpy(&(mc_list_request->mc_addr[i].bytes), + ha->addr, ETH_ALEN); + hdd_debug("mlist[%d] = "QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF(mc_list_request->mc_addr[i].bytes)); + i++; + } + + if (adapter->device_mode == QDF_NDI_MODE) + hdd_set_derived_multicast_list(psoc, adapter, + mc_list_request, + &mc_count); + } + + adapter->mc_addr_list.mc_cnt = mc_count; + mc_list_request->psoc = psoc; + mc_list_request->vdev_id = adapter->deflink->vdev_id; + mc_list_request->count = mc_count; + + errno = hdd_cache_mc_addr_list(mc_list_request); + if (errno) { + hdd_debug("Failed to cache MC address list for vdev %u; errno:%d", + adapter->deflink->vdev_id, errno); + goto free_req; + } + + hdd_enable_mc_addr_filtering(adapter, pmo_mc_list_change_notify); + +free_req: + qdf_spin_unlock_bh(&adapter->mc_list_lock); + qdf_mem_free(mc_list_request); +} + +/** + * hdd_set_multicast_list() - SSR wrapper function for __hdd_set_multicast_list + * @net_dev: pointer to net_device + * + * Return: none + */ +static void hdd_set_multicast_list(struct net_device *net_dev) +{ + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) + return; + + __hdd_set_multicast_list(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); +} + +void hdd_update_multicast_list(struct wlan_objmgr_vdev *vdev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct hdd_adapter *adapter; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct net_device *net_dev; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("adapter is null for vdev_id %d", vdev_id); + return; + } + + adapter = link_info->adapter; + if (!adapter) { + hdd_err("adapter is null for vdev_id %d", vdev_id); + return; + } + + net_dev = adapter->dev; + if (!net_dev) { + hdd_err("netdev is null"); + return; + } + + __hdd_set_multicast_list(net_dev); +} + +#ifdef WLAN_FEATURE_TSF_PTP +static const struct ethtool_ops wlan_ethtool_ops = { + .get_ts_info = wlan_get_ts_info, +}; +#endif + +/** + * __hdd_fix_features - Adjust the feature flags needed to be updated + * @net_dev: Handle to net_device + * @features: Currently enabled feature flags + * + * Return: Adjusted feature flags on success, old feature on failure + */ +static netdev_features_t __hdd_fix_features(struct net_device *net_dev, + netdev_features_t features) +{ + netdev_features_t feature_change_req = features; + netdev_features_t feature_tso_csum; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + + if (!adapter->handle_feature_update) { + hdd_debug("Not triggered by hdd_netdev_update_features"); + return features; + } + + feature_tso_csum = hdd_get_tso_csum_feature_flags(); + if (hdd_is_legacy_connection(adapter->deflink)) { + /* Disable checksum and TSO */ + feature_change_req &= ~feature_tso_csum; + adapter->tso_csum_feature_enabled = 0; + } else { + /* Enable checksum and TSO */ + feature_change_req |= feature_tso_csum; + adapter->tso_csum_feature_enabled = 1; + } + hdd_debug("vdev mode %d current features 0x%llx, requesting feature change 0x%llx", + adapter->device_mode, net_dev->features, + feature_change_req); + + return feature_change_req; +} + +/** + * hdd_fix_features() - Wrapper for __hdd_fix_features to protect it from SSR + * @net_dev: Pointer to net_device structure + * @features: Updated features set + * + * Adjusts the feature request, do not update the device yet. + * + * Return: updated feature for success, incoming feature as is on failure + */ +static netdev_features_t hdd_fix_features(struct net_device *net_dev, + netdev_features_t features) +{ + int errno; + int changed_features = features; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return features; + + changed_features = __hdd_fix_features(net_dev, features); + + osif_vdev_sync_op_stop(vdev_sync); + + return changed_features; +} +/** + * __hdd_set_features - Notify device about change in features + * @net_dev: Handle to net_device + * @features: Existing + requested feature after resolving the dependency + * + * Return: 0 on success, non zero error on failure + */ +static int __hdd_set_features(struct net_device *net_dev, + netdev_features_t features) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!adapter->handle_feature_update) { + hdd_debug("Not triggered by hdd_netdev_update_features"); + return 0; + } + + if (!soc) + return 0; + + hdd_debug("vdev mode %d vdev_id %d current features 0x%llx, changed features 0x%llx", + adapter->device_mode, adapter->deflink->vdev_id, + net_dev->features, features); + + return 0; +} + +/** + * hdd_set_features() - Wrapper for __hdd_set_features to protect it from SSR + * @net_dev: Pointer to net_device structure + * @features: Updated features set + * + * Is called to update device configurations for changed features. + * + * Return: 0 for success, non-zero for failure + */ +static int hdd_set_features(struct net_device *net_dev, + netdev_features_t features) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) { + /* + * Only invoke from netdev_feature_update_work expected, + * which is from CLD inside. + * Ignore others from upper stack during loading phase, + * and return success to avoid failure print from kernel. + */ + hdd_debug("VDEV in transition, ignore set_features"); + return 0; + } + + errno = __hdd_set_features(net_dev, features); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define HDD_NETDEV_FEATURES_UPDATE_MAX_WAIT_COUNT 10 +#define HDD_NETDEV_FEATURES_UPDATE_WAIT_INTERVAL_MS 20 + +void hdd_netdev_update_features(struct hdd_adapter *adapter) +{ + struct net_device *net_dev = adapter->dev; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + bool request_feature_update = false; + int wait_count = HDD_NETDEV_FEATURES_UPDATE_MAX_WAIT_COUNT; + + if (!soc) + return; + + if (!cdp_cfg_get(soc, cfg_dp_disable_legacy_mode_csum_offload)) + return; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + if (cdp_cfg_get(soc, cfg_dp_enable_ip_tcp_udp_checksum_offload)) + request_feature_update = true; + break; + default: + break; + } + + if (request_feature_update) { + hdd_debug("Update net_dev features for device mode %d", + adapter->device_mode); + while (!adapter->delete_in_progress) { + if (rtnl_trylock()) { + adapter->handle_feature_update = true; + netdev_update_features(net_dev); + adapter->handle_feature_update = false; + rtnl_unlock(); + break; + } + + if (wait_count--) { + qdf_sleep( + HDD_NETDEV_FEATURES_UPDATE_WAIT_INTERVAL_MS); + } else { + /* + * We have failed to updated the netdev + * features for very long, so enable the queues + * now. The impact of not being able to update + * the netdev feature is lower TPUT when + * switching from legacy to non-legacy mode. + */ + hdd_err("Failed to update netdev features for device mode %d", + adapter->device_mode); + break; + } + } + } +} + +static const struct net_device_ops wlan_drv_ops = { + .ndo_open = hdd_open, + .ndo_stop = hdd_stop, + .ndo_uninit = hdd_uninit, + .ndo_start_xmit = hdd_hard_start_xmit, + .ndo_fix_features = hdd_fix_features, + .ndo_set_features = hdd_set_features, + .ndo_tx_timeout = hdd_tx_timeout, + .ndo_get_stats = hdd_get_stats, +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0) + .ndo_do_ioctl = hdd_ioctl, +#endif + .ndo_set_mac_address = hdd_set_mac_address, + .ndo_select_queue = hdd_select_queue, + .ndo_set_rx_mode = hdd_set_multicast_list, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0) + .ndo_siocdevprivate = hdd_dev_private_ioctl, +#endif +}; + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/* Monitor mode net_device_ops, does not Tx and most of operations. */ +static const struct net_device_ops wlan_mon_drv_ops = { + .ndo_open = hdd_mon_open, + .ndo_stop = hdd_stop, + .ndo_get_stats = hdd_get_stats, +}; + +/** + * hdd_set_mon_ops() - update net_device ops for monitor mode + * @dev: Handle to struct net_device to be updated. + * Return: None + */ +static void hdd_set_mon_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_mon_drv_ops; +} + +#ifdef WLAN_FEATURE_TSF_PTP +void hdd_set_station_ops(struct net_device *dev) +{ + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) { + hdd_set_mon_ops(dev); + } else { + dev->netdev_ops = &wlan_drv_ops; + dev->ethtool_ops = &wlan_ethtool_ops; + } +} +#else +void hdd_set_station_ops(struct net_device *dev) +{ + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + hdd_set_mon_ops(dev); + else + dev->netdev_ops = &wlan_drv_ops; +} + +#endif +#else +#ifdef WLAN_FEATURE_TSF_PTP +void hdd_set_station_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_drv_ops; + dev->ethtool_ops = &wlan_ethtool_ops; +} +#else +void hdd_set_station_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_drv_ops; +} +#endif +static void hdd_set_mon_ops(struct net_device *dev) +{ +} +#endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE +/* Packet Capture mode net_device_ops, does not Tx and most of operations. */ +static const struct net_device_ops wlan_pktcapture_drv_ops = { + .ndo_open = hdd_pktcapture_open, + .ndo_stop = hdd_stop, + .ndo_get_stats = hdd_get_stats, +}; + +static void hdd_set_pktcapture_ops(struct net_device *dev) +{ + dev->netdev_ops = &wlan_pktcapture_drv_ops; +} +#else +static void hdd_set_pktcapture_ops(struct net_device *dev) +{ +} +#endif + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * hdd_set_multi_client_ll_support() - set multi client ll support flag in + * allocated station hdd adapter + * @adapter: pointer to hdd adapter + * + * Return: none + */ +static void hdd_set_multi_client_ll_support(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool multi_client_ll_ini_support, multi_client_ll_caps; + + ucfg_mlme_cfg_get_multi_client_ll_ini_support(hdd_ctx->psoc, + &multi_client_ll_ini_support); + multi_client_ll_caps = + ucfg_mlme_get_wlm_multi_client_ll_caps(hdd_ctx->psoc); + + hdd_debug("fw caps: %d, ini: %d", multi_client_ll_caps, + multi_client_ll_ini_support); + if (multi_client_ll_caps && multi_client_ll_ini_support) + adapter->multi_client_ll_support = true; +} +#else +static inline void +hdd_set_multi_client_ll_support(struct hdd_adapter *adapter) +{ +} +#endif + +/** + * hdd_alloc_station_adapter() - allocate the station hdd adapter + * @hdd_ctx: global hdd context + * @mac_addr: mac address to assign to the interface + * @name_assign_type: name assignment type + * @name: User-visible name of the interface + * @session_type: interface type to be created + * + * hdd adapter pointer would point to the netdev->priv space, this function + * would retrieve the pointer, and setup the hdd adapter configuration. + * + * Return: the pointer to hdd adapter, otherwise NULL + */ +static struct hdd_adapter * +hdd_alloc_station_adapter(struct hdd_context *hdd_ctx, tSirMacAddr mac_addr, + unsigned char name_assign_type, const char *name, + uint8_t session_type) +{ + struct net_device *dev; + struct hdd_adapter *adapter; + QDF_STATUS qdf_status; + uint8_t latency_level; + + /* cfg80211 initialization and registration */ + dev = alloc_netdev_mqs(sizeof(*adapter), name, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + name_assign_type, +#endif + ((cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE || + wlan_hdd_is_session_type_monitor(session_type)) ? + hdd_mon_mode_ether_setup : ether_setup), + NUM_TX_QUEUES, NUM_RX_QUEUES); + + if (!dev) { + hdd_err("Failed to allocate new net_device '%s'", name); + return NULL; + } + + adapter = netdev_priv(dev); + + qdf_mem_zero(adapter, sizeof(*adapter)); + adapter->dev = dev; + adapter->deflink = &adapter->link_info[WLAN_HDD_DEFLINK_IDX]; + adapter->hdd_ctx = hdd_ctx; + adapter->magic = WLAN_HDD_ADAPTER_MAGIC; + qdf_atomic_set_bit(WLAN_HDD_DEFLINK_IDX, &adapter->active_links); + + qdf_status = hdd_monitor_mode_qdf_create_event(adapter, session_type); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err_rl("create monitor mode vdve up event failed"); + goto free_net_dev; + } + + hdd_update_dynamic_tsf_sync(adapter); + adapter->is_link_up_service_needed = false; + adapter->send_mode_change = true; + + /* Cache station count initialize to zero */ + qdf_atomic_init(&adapter->cache_sta_count); + + /* Init the net_device structure */ + strlcpy(dev->name, name, IFNAMSIZ); + + qdf_net_update_net_device_dev_addr(dev, mac_addr, sizeof(tSirMacAddr)); + qdf_mem_copy(adapter->mac_addr.bytes, mac_addr, sizeof(tSirMacAddr)); + dev->watchdog_timeo = HDD_TX_TIMEOUT; + + if (wlan_hdd_is_session_type_monitor(session_type)) { + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) + hdd_set_pktcapture_ops(adapter->dev); + if (ucfg_mlme_is_sta_mon_conc_supported(hdd_ctx->psoc) || + ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc)) + hdd_set_mon_ops(adapter->dev); + } else { + hdd_set_station_ops(adapter->dev); + } + + hdd_dev_setup_destructor(dev); + dev->ieee80211_ptr = &adapter->wdev; + dev->tx_queue_len = HDD_NETDEV_TX_QUEUE_LEN; + adapter->wdev.wiphy = hdd_ctx->wiphy; + adapter->wdev.netdev = dev; + qdf_status = ucfg_mlme_cfg_get_wlm_level(hdd_ctx->psoc, &latency_level); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_debug("Can't get latency level"); + latency_level = + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL; + } + adapter->latency_level = latency_level; + hdd_set_multi_client_ll_support(adapter); + + /* set dev's parent to underlying device */ + SET_NETDEV_DEV(dev, hdd_ctx->parent_dev); + spin_lock_init(&adapter->pause_map_lock); + adapter->start_time = qdf_system_ticks(); + adapter->last_time = adapter->start_time; + + qdf_atomic_init(&adapter->is_ll_stats_req_pending); + hdd_init_get_sta_in_ll_stats_config(adapter); + hdd_init_link_state_config(adapter); + + return adapter; + +free_net_dev: + free_netdev(adapter->dev); + + return NULL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) || \ + (defined CFG80211_CHANGE_NETDEV_REGISTRATION_SEMANTICS)) +static int +hdd_register_netdevice(struct hdd_adapter *adapter, struct net_device *dev, + struct hdd_adapter_create_param *params) +{ + int ret; + + if (params->is_add_virtual_iface) + ret = wlan_cfg80211_register_netdevice(dev); + else + ret = register_netdevice(dev); + + return ret; +} +#else +static int +hdd_register_netdevice(struct hdd_adapter *adapter, struct net_device *dev, + struct hdd_adapter_create_param *params) +{ + return register_netdevice(dev); +} +#endif + +static QDF_STATUS +hdd_register_interface(struct hdd_adapter *adapter, bool rtnl_held, + struct hdd_adapter_create_param *params) +{ + struct net_device *dev = adapter->dev; + int ret; + + hdd_enter(); + + if (rtnl_held) { + if (strnchr(dev->name, IFNAMSIZ - 1, '%')) { + + ret = dev_alloc_name(dev, dev->name); + if (ret < 0) { + hdd_err( + "unable to get dev name: %s, err = 0x%x", + dev->name, ret); + return QDF_STATUS_E_FAILURE; + } + } + hdd_debug("hdd_register_netdevice(%s) type:%d", dev->name, + adapter->device_mode); + ret = hdd_register_netdevice(adapter, dev, params); + if (ret) { + hdd_err("register_netdevice(%s) failed, err = 0x%x", + dev->name, ret); + return QDF_STATUS_E_FAILURE; + } + } else { + hdd_debug("register_netdev(%s) type:%d", dev->name, + adapter->device_mode); + ret = register_netdev(dev); + if (ret) { + hdd_err("register_netdev(%s) failed, err = 0x%x", + dev->name, ret); + return QDF_STATUS_E_FAILURE; + } + } + set_bit(NET_DEVICE_REGISTERED, &adapter->event_flags); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_sme_close_session_callback(uint8_t vdev_id) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return QDF_STATUS_E_FAILURE; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + adapter = link_info->adapter; + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid magic"); + return QDF_STATUS_NOT_INITIALIZED; + } + + clear_bit(SME_SESSION_OPENED, &link_info->link_flags); + qdf_spin_lock_bh(&link_info->vdev_lock); + link_info->vdev_id = WLAN_UMAC_VDEV_ID_MAX; + qdf_spin_unlock_bh(&link_info->vdev_lock); + + /* + * We can be blocked while waiting for scheduled work to be + * flushed, and the adapter structure can potentially be freed, in + * which case the magic will have been reset. So make sure the + * magic is still good, and hence the adapter structure is still + * valid, before signaling completion + */ + if (WLAN_HDD_ADAPTER_MAGIC == adapter->magic) + complete(&link_info->vdev_destroy_event); + + return QDF_STATUS_SUCCESS; +} + +int hdd_vdev_ready(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bridgeaddr) +{ + QDF_STATUS status; + + status = pmo_vdev_ready(vdev, bridgeaddr); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + status = ucfg_reg_11d_vdev_created_update(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + if (wma_capability_enhanced_mcast_filter()) + status = ucfg_pmo_enhanced_mc_filter_enable(vdev); + else + status = ucfg_pmo_enhanced_mc_filter_disable(vdev); + + return qdf_status_to_os_return(status); +} + +/** + * hdd_check_wait_for_hw_mode_completion - Check hw mode in progress + * @hdd_ctx: hdd context + * + * Check and wait for hw mode response if any hw mode change is + * in progress. Vdev delete will purge the serialization queue + * for the vdev. It will cause issues when the fw event coming + * up later and no active hw mode change req ser command in queue. + * + * Return void + */ +static void hdd_check_wait_for_hw_mode_completion(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!wlan_hdd_validate_context(hdd_ctx) && + policy_mgr_is_hw_mode_change_in_progress( + hdd_ctx->psoc)) { + status = policy_mgr_wait_for_connection_update( + hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_nofl_debug("qdf wait for hw mode event failed!!"); + } + } +} + +static void hdd_stop_last_active_connection(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev) +{ + enum policy_mgr_con_mode mode; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE op_mode; + + /* If this is the last active connection check + * and stop the opportunistic timer. + */ + psoc = wlan_vdev_get_psoc(vdev); + op_mode = wlan_vdev_mlme_get_opmode(vdev); + mode = policy_mgr_qdf_opmode_to_pm_con_mode(psoc, op_mode, + wlan_vdev_get_id(vdev)); + if ((policy_mgr_get_connection_count(psoc) == 1 && + policy_mgr_mode_specific_connection_count(psoc, + mode, NULL) == 1) || + (!policy_mgr_get_connection_count(psoc) && + !hdd_is_any_sta_connecting(hdd_ctx))) { + policy_mgr_check_and_stop_opportunistic_timer( + psoc, + wlan_vdev_get_id(vdev)); + } +} + +static int hdd_vdev_destroy_event_wait(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev) +{ + long rc; + QDF_STATUS status; + uint8_t vdev_id; + struct wlan_hdd_link_info *link_info; + struct qdf_mac_addr *mld_addr; + struct wlan_objmgr_psoc *psoc = NULL; + + vdev_id = wlan_vdev_get_id(vdev); + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + obj_mgr_err("Failed to get psoc"); + return QDF_STATUS_E_FAILURE; + } + + /* Detach DP vdev from DP MLO Device Context */ + mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + + if (!qdf_is_macaddr_zero(mld_addr)) { + /* only for MLO vdev's */ + + if (cdp_mlo_dev_ctxt_detach(wlan_psoc_get_dp_handle(psoc), + wlan_vdev_get_id(vdev), + (uint8_t *)mld_addr) + != QDF_STATUS_SUCCESS) { + obj_mgr_err("Failed to detach DP vdev from DP MLO Dev ctxt"); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + } + + /* close sme session (destroy vdev in firmware via legacy API) */ + INIT_COMPLETION(link_info->vdev_destroy_event); + status = sme_vdev_delete(hdd_ctx->mac_handle, vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("vdev %d: failed to delete with status:%d", + vdev_id, status); + return -EAGAIN; + } + + /* block on a completion variable until sme session is closed */ + rc = wait_for_completion_timeout( + &link_info->vdev_destroy_event, + msecs_to_jiffies(SME_CMD_VDEV_CREATE_DELETE_TIMEOUT)); + if (!rc) { + hdd_err("vdev %d: timed out waiting for delete", vdev_id); + clear_bit(SME_SESSION_OPENED, &link_info->link_flags); + sme_cleanup_session(hdd_ctx->mac_handle, vdev_id); + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_VDEV_DELETE_RSP_TIMED_OUT, + true, true); + return -EINVAL; + } + + hdd_nofl_info("vdev %d destroyed successfully", vdev_id); + return 0; +} + +static inline +void hdd_vdev_deinit_components(struct wlan_objmgr_vdev *vdev) +{ + ucfg_pmo_del_wow_pattern(vdev); + ucfg_son_disable_cbs(vdev); +} + +static inline +void hdd_reset_vdev_info(struct wlan_hdd_link_info *link_info) +{ + qdf_spin_lock_bh(&link_info->vdev_lock); + link_info->vdev = NULL; + qdf_spin_unlock_bh(&link_info->vdev_lock); +} + +int hdd_vdev_destroy(struct wlan_hdd_link_info *link_info) +{ + int ret; + uint8_t vdev_id; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE op_mode; + + vdev_id = link_info->vdev_id; + hdd_nofl_debug("destroying vdev %d", vdev_id); + /* vdev created sanity check */ + if (!test_bit(SME_SESSION_OPENED, &link_info->link_flags)) { + hdd_nofl_debug("vdev %u does not exist", vdev_id); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_ID); + if (!vdev) + return -EINVAL; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("invalid psoc"); + return -EINVAL; + } + op_mode = wlan_vdev_mlme_get_opmode(vdev); + + hdd_stop_last_active_connection(hdd_ctx, vdev); + hdd_check_wait_for_hw_mode_completion(hdd_ctx); + ucfg_scan_vdev_set_disable(vdev, REASON_VDEV_DOWN); + wlan_hdd_scan_abort(link_info); + hdd_vdev_deinit_components(vdev); + hdd_mlo_t2lm_unregister_callback(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + hdd_reset_vdev_info(link_info); + osif_cm_osif_priv_deinit(vdev); + + /* Release the hdd reference */ + wlan_objmgr_vdev_release_ref(vdev, WLAN_HDD_ID_OBJ_MGR); + + /* Get runtime lock to prevent runtime suspend */ + qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.vdev_destroy); + + ret = hdd_vdev_destroy_event_wait(hdd_ctx, vdev); + + ucfg_reg_11d_vdev_delete_update(psoc, op_mode, vdev_id); + + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.vdev_destroy); + return ret; +} + +void +hdd_store_nss_chains_cfg_in_vdev(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_mlme_nss_chains vdev_ini_cfg; + + /* Populate the nss chain params from ini for this vdev type */ + sme_populate_nss_chain_params(hdd_ctx->mac_handle, &vdev_ini_cfg, + wlan_vdev_mlme_get_opmode(vdev), + hdd_ctx->num_rf_chains); + + /* Store the nss chain config into the vdev */ + sme_store_nss_chains_cfg_in_vdev(vdev, &vdev_ini_cfg); +} + +bool hdd_is_vdev_in_conn_state(struct wlan_hdd_link_info *link_info) +{ + switch (link_info->adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + return hdd_cm_is_vdev_associated(link_info); + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + return (test_bit(SOFTAP_BSS_STARTED, + &link_info->link_flags)); + default: + hdd_err("Device mode %d invalid", + link_info->adapter->device_mode); + return 0; + } +} + +#define MAX_VDEV_RTT_PARAMS 2 +/* params being sent: + * wmi_vdev_param_enable_disable_rtt_responder_role + * wmi_vdev_param_enable_disable_rtt_initiator_role + */ +static QDF_STATUS +hdd_vdev_configure_rtt_params(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + uint32_t fine_time_meas_cap = 0; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct dev_set_param vdevsetparam[MAX_VDEV_RTT_PARAMS] = {}; + uint8_t index = 0; + WMI_FW_SUB_FEAT_CAPS wmi_fw_rtt_respr, wmi_fw_rtt_initr; + + switch (wlan_vdev_mlme_get_opmode(vdev)) { + case QDF_STA_MODE: + wmi_fw_rtt_respr = WMI_FW_STA_RTT_RESPR; + wmi_fw_rtt_initr = WMI_FW_STA_RTT_INITR; + break; + case QDF_SAP_MODE: + wmi_fw_rtt_respr = WMI_FW_AP_RTT_RESPR; + wmi_fw_rtt_initr = WMI_FW_AP_RTT_INITR; + break; + default: + return QDF_STATUS_SUCCESS; + } + + psoc = wlan_vdev_get_psoc(vdev); + + ucfg_mlme_get_fine_time_meas_cap(psoc, &fine_time_meas_cap); + status = mlme_check_index_setparam( + vdevsetparam, + wmi_vdev_param_enable_disable_rtt_responder_role, + (fine_time_meas_cap & wmi_fw_rtt_respr), index++, + MAX_VDEV_RTT_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = mlme_check_index_setparam( + vdevsetparam, + wmi_vdev_param_enable_disable_rtt_initiator_role, + (fine_time_meas_cap & wmi_fw_rtt_initr), index++, + MAX_VDEV_RTT_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = sme_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, vdevsetparam, + index); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set RTT_RESPONDER,INITIATOR params:%d", + status); + + return status; +} + +static void hdd_store_vdev_info(struct wlan_hdd_link_info *link_info, + struct wlan_objmgr_vdev *vdev) +{ + struct vdev_osif_priv *osif_priv; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (osif_priv) { + osif_priv->wdev = link_info->adapter->dev->ieee80211_ptr; + osif_priv->legacy_osif_priv = link_info; + } + + qdf_spin_lock_bh(&link_info->vdev_lock); + link_info->vdev_id = wlan_vdev_get_id(vdev); + link_info->vdev = vdev; + qdf_spin_unlock_bh(&link_info->vdev_lock); +} + +static void +hdd_init_station_context(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + /* Set the default operation channel freq and auth type to open */ + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + sta_ctx->conn_info.chan_freq = hdd_ctx->config->operating_chan_freq; + sta_ctx->conn_info.auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + hdd_roam_profile_init(link_info); +} + +static void hdd_vdev_set_ht_vht_ies(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + bool bval = false; + + psoc = wlan_vdev_get_psoc(vdev); + status = ucfg_mlme_get_vht_enable2x2(psoc, &bval); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("unable to get vht_enable2x2"); + + sme_set_pdev_ht_vht_ies(mac_handle, bval); + sme_set_vdev_ies_per_band(mac_handle, wlan_vdev_get_id(vdev), + wlan_vdev_mlme_get_opmode(vdev)); +} + +static void +hdd_vdev_configure_rtt_mac_randomization(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + int errno; + QDF_STATUS status; + bool bval = false; + + status = ucfg_mlme_get_rtt_mac_randomization(psoc, &bval); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("unable to get RTT MAC randomization value"); + + hdd_debug("setting RTT mac randomization param: %d", bval); + errno = sme_cli_set_command( + wlan_vdev_get_id(vdev), + wmi_vdev_param_enable_disable_rtt_initiator_random_mac, + bval, VDEV_CMD); + + if (errno) + hdd_err("RTT mac randomization param set failed %d", errno); +} + +static void +hdd_vdev_configure_max_tdls_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + uint16_t max_peer_count; + bool target_bigtk_support = false; + + /* + * Max peer can be tdls peers + self peer + bss peer + + * temp bss peer for roaming create/delete peer at same time + */ + max_peer_count = cfg_tdls_get_max_peer_count(psoc); + max_peer_count += 3; + wlan_vdev_set_max_peer_count(vdev, max_peer_count); + + ucfg_mlme_get_bigtk_support(psoc, &target_bigtk_support); + if (target_bigtk_support) + mlme_set_bigtk_support(vdev, true); +} + +static inline void +hdd_vdev_configure_nan_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + sme_cli_set_command( + wlan_vdev_get_id(vdev), + wmi_vdev_param_allow_nan_initial_discovery_of_mp0_cluster, + cfg_nan_get_support_mp0_discovery(psoc), VDEV_CMD); +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(WLAN_EXTERNAL_AUTH_MLO_SUPPORT) +static void +hdd_set_vdev_mlo_external_sae_auth_conversion(struct wlan_objmgr_vdev *vdev, + enum QDF_OPMODE mode) +{ + if (mode == QDF_STA_MODE || mode == QDF_SAP_MODE) + wlan_vdev_set_mlo_external_sae_auth_conversion(vdev, true); +} +#else +static inline void +hdd_set_vdev_mlo_external_sae_auth_conversion(struct wlan_objmgr_vdev *vdev, + enum QDF_OPMODE mode) +{ +} +#endif + +static void +hdd_vdev_configure_rtscts_enable(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev) +{ + int ret; + QDF_STATUS status; + uint16_t rts_profile = 0; + + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + return; + + status = ucfg_fwol_get_rts_profile(hdd_ctx->psoc, &rts_profile); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("FAILED TO GET RTSCTS Profile status:%d", status); + return; + } + + ret = sme_cli_set_command(wlan_vdev_get_id(vdev), + wmi_vdev_param_enable_rtscts, + rts_profile, + VDEV_CMD); + if (ret) + hdd_err("FAILED TO SET RTSCTS Profile ret:%d", ret); +} + +static void +hdd_vdev_configure_usr_ps_params(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE || !adapter) + return; + + ucfg_mlme_set_user_ps(psoc, wlan_vdev_get_id(vdev), + adapter->allow_power_save); +} + +static void +hdd_vdev_configure_opmode_params(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev, + struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + enum QDF_OPMODE opmode = wlan_vdev_mlme_get_opmode(vdev); + + switch (opmode) { + case QDF_STA_MODE: + hdd_vdev_configure_rtt_mac_randomization(psoc, vdev); + hdd_vdev_configure_max_tdls_params(psoc, vdev); + hdd_vdev_configure_usr_ps_params(psoc, vdev, link_info); + break; + case QDF_P2P_CLIENT_MODE: + hdd_vdev_configure_max_tdls_params(psoc, vdev); + hdd_vdev_configure_usr_ps_params(psoc, vdev, link_info); + break; + case QDF_NAN_DISC_MODE: + hdd_vdev_configure_nan_params(psoc, vdev); + break; + default: + break; + } + + ucfg_fwol_configure_vdev_params(psoc, vdev); + hdd_set_vdev_mlo_external_sae_auth_conversion(vdev, opmode); + hdd_store_nss_chains_cfg_in_vdev(hdd_ctx, vdev); + hdd_vdev_configure_rtscts_enable(hdd_ctx, vdev); +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static int +hdd_populate_vdev_create_params(struct wlan_hdd_link_info *link_info, + struct wlan_vdev_create_params *vdev_params) +{ + struct hdd_adapter *adapter = link_info->adapter; + + vdev_params->opmode = adapter->device_mode; + vdev_params->size_vdev_priv = sizeof(struct vdev_osif_priv); + + if (hdd_adapter_is_ml_adapter(adapter)) { + qdf_ether_addr_copy(vdev_params->mldaddr, + adapter->mac_addr.bytes); + qdf_ether_addr_copy(vdev_params->macaddr, + link_info->link_addr.bytes); + } else { + qdf_ether_addr_copy(vdev_params->macaddr, + adapter->mac_addr.bytes); + } + return 0; +} +#elif defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +static int +hdd_populate_vdev_create_params(struct wlan_hdd_link_info *link_info, + struct wlan_vdev_create_params *vdev_params) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_adapter *link_adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool eht_capab; + + hdd_enter_dev(adapter->dev); + mlo_adapter_info = &adapter->mlo_adapter_info; + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (mlo_adapter_info->is_ml_adapter && eht_capab && + adapter->device_mode == QDF_STA_MODE) { + link_adapter = hdd_get_assoc_link_adapter(adapter); + if (link_adapter) { + qdf_ether_addr_copy(vdev_params->macaddr, + link_adapter->mac_addr.bytes); + } else { + return -EINVAL; + } + } else { + qdf_ether_addr_copy(vdev_params->macaddr, + adapter->mac_addr.bytes); + } + + vdev_params->opmode = adapter->device_mode; + + if (eht_capab) { + qdf_ether_addr_copy(vdev_params->mldaddr, + adapter->mld_addr.bytes); + } + + vdev_params->size_vdev_priv = sizeof(struct vdev_osif_priv); + hdd_exit(); + + return 0; +} +#else +static int +hdd_populate_vdev_create_params(struct wlan_hdd_link_info *link_info, + struct wlan_vdev_create_params *vdev_params) +{ + struct hdd_adapter *adapter = link_info->adapter; + + vdev_params->opmode = adapter->device_mode; + qdf_ether_addr_copy(vdev_params->macaddr, adapter->mac_addr.bytes); + vdev_params->size_vdev_priv = sizeof(struct vdev_osif_priv); + return 0; +} +#endif + +int hdd_vdev_create(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS status; + int errno = 0; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_vdev_create_params vdev_params = {0}; + + hdd_nofl_debug("creating new vdev"); + + /* do vdev create via objmgr */ + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + errno = hdd_populate_vdev_create_params(link_info, &vdev_params); + if (errno) + return errno; + + vdev = sme_vdev_create(hdd_ctx->mac_handle, &vdev_params); + if (!vdev) { + hdd_err("failed to create vdev"); + return -EINVAL; + } + + if (wlan_objmgr_vdev_try_get_ref(vdev, WLAN_HDD_ID_OBJ_MGR) != + QDF_STATUS_SUCCESS) { + errno = QDF_STATUS_E_INVAL; + sme_vdev_delete(hdd_ctx->mac_handle, vdev); + return -EINVAL; + } + + hdd_store_vdev_info(link_info, vdev); + osif_cm_osif_priv_init(vdev); + + if (hdd_adapter_is_ml_adapter(adapter)) + hdd_mlo_t2lm_register_callback(vdev); + + set_bit(SME_SESSION_OPENED, &link_info->link_flags); + status = sme_vdev_post_vdev_create_setup(hdd_ctx->mac_handle, vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to setup the vdev"); + errno = qdf_status_to_os_return(status); + goto hdd_vdev_destroy_procedure; + } + + /* firmware ready for component communication, raise vdev_ready event */ + errno = hdd_vdev_ready(vdev, + (struct qdf_mac_addr *)hdd_ctx->bridgeaddr); + if (errno) { + hdd_err("failed to dispatch vdev ready event: %d", errno); + goto hdd_vdev_destroy_procedure; + } + + hdd_vdev_configure_opmode_params(hdd_ctx, vdev, link_info); + + hdd_nofl_debug("vdev %d created successfully", link_info->vdev_id); + + return errno; + +hdd_vdev_destroy_procedure: + QDF_BUG(!hdd_vdev_destroy(link_info)); + + return errno; +} + +QDF_STATUS hdd_init_station_mode(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + mac_handle_t mac_handle; + uint32_t roam_triggers; + struct wlan_objmgr_vdev *vdev; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + mac_handle = hdd_ctx->mac_handle; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_INIT_DEINIT_ID); + if (!vdev) { + status = QDF_STATUS_E_NULL_VALUE; + goto vdev_destroy; + } + + hdd_vdev_set_ht_vht_ies(mac_handle, vdev); + hdd_init_station_context(link_info); + + status = hdd_wmm_adapter_init(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("hdd_wmm_adapter_init() failed, status code %08d [x%08x]", + status, status); + goto error_wmm_init; + } + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + /* rcpi info initialization */ + qdf_mem_zero(&adapter->rcpi, sizeof(adapter->rcpi)); + + if (adapter->device_mode == QDF_STA_MODE) { + roam_triggers = ucfg_mlme_get_roaming_triggers(hdd_ctx->psoc); + mlme_set_roam_trigger_bitmap(hdd_ctx->psoc, + link_info->vdev_id, + roam_triggers); + + status = hdd_vdev_configure_rtt_params(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto error_wmm_init; + } + + hdd_tsf_auto_report_init(adapter); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + + return QDF_STATUS_SUCCESS; + +error_wmm_init: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + +vdev_destroy: + QDF_BUG(!hdd_vdev_destroy(link_info)); + + return status; +} + +static char *net_dev_ref_debug_string_from_id(wlan_net_dev_ref_dbgid dbgid) +{ + static const char *strings[] = { + "NET_DEV_HOLD_ID_RESERVED", + "NET_DEV_HOLD_GET_STA_CONNECTION_IN_PROGRESS", + "NET_DEV_HOLD_CHECK_DFS_CHANNEL_FOR_ADAPTER", + "NET_DEV_HOLD_GET_SAP_OPERATING_BAND", + "NET_DEV_HOLD_RECOVERY_NOTIFIER_CALL", + "NET_DEV_HOLD_IS_ANY_STA_CONNECTING", + "NET_DEV_HOLD_SAP_DESTROY_CTX_ALL", + "NET_DEV_HOLD_DRV_CMD_MAX_TX_POWER", + "NET_DEV_HOLD_IPA_SET_TX_FLOW_INFO", + "NET_DEV_HOLD_SET_RPS_CPU_MASK", + "NET_DEV_HOLD_DFS_INDICATE_RADAR", + "NET_DEV_HOLD_MAX_STA_INTERFACE_UP_COUNT_REACHED", + "NET_DEV_HOLD_IS_CHAN_SWITCH_IN_PROGRESS", + "NET_DEV_HOLD_STA_DESTROY_CTX_ALL", + "NET_DEV_HOLD_CHECK_FOR_EXISTING_MACADDR", + "NET_DEV_HOLD_DEINIT_ALL_ADAPTERS", + "NET_DEV_HOLD_STOP_ALL_ADAPTERS", + "NET_DEV_HOLD_RESET_ALL_ADAPTERS", + "NET_DEV_HOLD_IS_ANY_INTERFACE_OPEN", + "NET_DEV_HOLD_START_ALL_ADAPTERS", + "NET_DEV_HOLD_GET_ADAPTER_BY_RAND_MACADDR", + "NET_DEV_HOLD_GET_ADAPTER_BY_MACADDR", + "NET_DEV_HOLD_GET_ADAPTER_BY_VDEV", + "NET_DEV_HOLD_ADAPTER_GET_BY_REFERENCE", + "NET_DEV_HOLD_GET_ADAPTER_BY_IFACE_NAME", + "NET_DEV_HOLD_GET_ADAPTER", + "NET_DEV_HOLD_GET_OPERATING_CHAN_FREQ", + "NET_DEV_HOLD_UNREGISTER_WEXT_ALL_ADAPTERS", + "NET_DEV_HOLD_ABORT_MAC_SCAN_ALL_ADAPTERS", + "NET_DEV_HOLD_ABORT_SCHED_SCAN_ALL_ADAPTERS", + "NET_DEV_HOLD_GET_FIRST_VALID_ADAPTER", + "NET_DEV_HOLD_CLEAR_RPS_CPU_MASK", + "NET_DEV_HOLD_BUS_BW_WORK_HANDLER", + "NET_DEV_HOLD_DISPLAY_NETIF_QUEUE_HISTORY_COMPACT", + "NET_DEV_HOLD_DISPLAY_NETIF_QUEUE_HISTORY", + "NET_DEV_HOLD_CLEAR_NETIF_QUEUE_HISTORY", + "NET_DEV_HOLD_UNSAFE_CHANNEL_RESTART_SAP", + "NET_DEV_HOLD_INDICATE_MGMT_FRAME", + "NET_DEV_HOLD_STATE_INFO_DUMP", + "NET_DEV_HOLD_DISABLE_ROAMING", + "NET_DEV_HOLD_ENABLE_ROAMING", + "NET_DEV_HOLD_AUTO_SHUTDOWN_ENABLE", + "NET_DEV_HOLD_GET_CON_SAP_ADAPTER", + "NET_DEV_HOLD_IS_ANY_ADAPTER_CONNECTED", + "NET_DEV_HOLD_IS_ROAMING_IN_PROGRESS", + "NET_DEV_HOLD_DEL_P2P_INTERFACE", + "NET_DEV_HOLD_IS_NDP_ALLOWED", + "NET_DEV_HOLD_NDI_OPEN", + "NET_DEV_HOLD_SEND_OEM_REG_RSP_NLINK_MSG", + "NET_DEV_HOLD_PERIODIC_STA_STATS_DISPLAY", + "NET_DEV_HOLD_SUSPEND_WLAN", + "NET_DEV_HOLD_RESUME_WLAN", + "NET_DEV_HOLD_SSR_RESTART_SAP", + "NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES", + "NET_DEV_HOLD_CFG80211_SUSPEND_WLAN", + "NET_DEV_HOLD_COUNTRY_CHANGE_UPDATE_STA", + "NET_DEV_HOLD_COUNTRY_CHANGE_UPDATE_SAP", + "NET_DEV_HOLD_CACHE_STATION_STATS_CB", + "NET_DEV_HOLD_DISPLAY_TXRX_STATS", + "NET_DEV_HOLD_START_PRE_CAC_TRANS", + "NET_DEV_HOLD_IS_ANY_STA_CONNECTED", + "NET_DEV_HOLD_GET_ADAPTER_BY_BSSID", + "NET_DEV_HOLD_ALLOW_NEW_INTF", + "NET_DEV_HOLD_ID_MAX"}; + int32_t num_dbg_strings = QDF_ARRAY_SIZE(strings); + + if (dbgid >= num_dbg_strings) { + char *ret = ""; + + hdd_err("Debug string not found for debug id %d", dbgid); + return ret; + } + + return (char *)strings[dbgid]; +} + +void hdd_check_for_net_dev_ref_leak(struct hdd_adapter *adapter) +{ + int i, id; + + for (id = 0; id < NET_DEV_HOLD_ID_MAX; id++) { + for (i = 0; i < MAX_NET_DEV_REF_LEAK_ITERATIONS; i++) { + if (!qdf_atomic_read( + &adapter->net_dev_hold_ref_count[id])) + break; + hdd_info("net_dev held for debug id %s", + net_dev_ref_debug_string_from_id(id)); + qdf_sleep(NET_DEV_REF_LEAK_ITERATION_SLEEP_TIME_MS); + } + if (i == MAX_NET_DEV_REF_LEAK_ITERATIONS) { + hdd_err("net_dev hold reference leak detected for debug id: %s", + net_dev_ref_debug_string_from_id(id)); + QDF_BUG(0); + } + } +} + +/** + * hdd_deinit_station_mode() - De-initialize the station adapter + * @adapter: HDD adapter pointer + * + * This function De-initializes the STA/P2P/OCB adapter. + * + * Return: None. + */ +static void hdd_deinit_station_mode(struct hdd_adapter *adapter) +{ + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } +} + +void hdd_deinit_session(struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_MONITOR_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NDI_MODE: + case QDF_NAN_DISC_MODE: + { + hdd_deinit_station_mode(adapter); + break; + } + + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + { + hdd_adapter_for_each_active_link_info(adapter, link_info) + hdd_deinit_ap_mode(link_info); + break; + } + + default: + break; + } + + if (adapter->scan_info.default_scan_ies) { + qdf_mem_free(adapter->scan_info.default_scan_ies); + adapter->scan_info.default_scan_ies = NULL; + adapter->scan_info.default_scan_ies_len = 0; + } + + hdd_exit(); +} + +void hdd_deinit_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + hdd_enter_dev(adapter->dev); + + hdd_wext_unregister(adapter->dev, rtnl_held); + hdd_deinit_session(adapter); + hdd_exit(); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ + defined(WLAN_FEATURE_11AX) +/** + * hdd_cleanup_he_operation_info() - cleanup he operation info + * @link_info: pointer to link_info struct in adapter + * + * This function destroys he operation information + * + * Return: none + */ +static void hdd_cleanup_he_operation_info(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_debug("cleanup he operation info"); + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + if (hdd_sta_ctx->cache_conn_info.he_operation) { + qdf_mem_free(hdd_sta_ctx->cache_conn_info.he_operation); + hdd_sta_ctx->cache_conn_info.he_operation = NULL; + } +} +#else +static inline void +hdd_cleanup_he_operation_info(struct wlan_hdd_link_info *link_info) +{ +} +#endif + +/** + * hdd_cleanup_prev_ap_bcn_ie() - cleanup previous ap beacon ie + * @link_info: pointer to link_info struct in adapter + * + * This function destroys previous ap beacon information + * + * Return: none + */ +static void hdd_cleanup_prev_ap_bcn_ie(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *hdd_sta_ctx; + struct element_info *bcn_ie; + + hdd_debug("cleanup previous ap bcn ie"); + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + bcn_ie = &hdd_sta_ctx->conn_info.prev_ap_bcn_ie; + + if (bcn_ie->ptr) { + qdf_mem_free(bcn_ie->ptr); + bcn_ie->ptr = NULL; + bcn_ie->len = 0; + } +} + +void hdd_cleanup_conn_info(struct wlan_hdd_link_info *link_info) +{ + hdd_cleanup_he_operation_info(link_info); + hdd_cleanup_prev_ap_bcn_ie(link_info); +} + +/** + * hdd_sta_destroy_ctx_all() - cleanup all station contexts + * @hdd_ctx: Global HDD context + * + * This function destroys all the station contexts + * + * Return: none + */ +static void hdd_sta_destroy_ctx_all(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_STA_DESTROY_CTX_ALL) { + if (adapter->device_mode == QDF_STA_MODE) { + hdd_adapter_for_each_link_info(adapter, link_info) { + hdd_cleanup_conn_info(link_info); + } + } + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_STA_DESTROY_CTX_ALL); + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0) || \ + (defined CFG80211_CHANGE_NETDEV_REGISTRATION_SEMANTICS)) +static void +hdd_unregister_netdevice(struct hdd_adapter *adapter, struct net_device *dev) +{ + if (adapter->is_virtual_iface) { + wlan_cfg80211_unregister_netdevice(dev); + adapter->is_virtual_iface = false; + } else { + unregister_netdevice(dev); + } +} +#else +static void +hdd_unregister_netdevice(struct hdd_adapter *adapter, struct net_device *dev) +{ + unregister_netdevice(dev); +} +#endif + +static inline void hdd_adapter_destroy_vdev_info(struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + + hdd_adapter_for_each_link_info(adapter, link_info) { + qdf_event_destroy(&link_info->acs_complete_event); + qdf_spinlock_destroy(&link_info->vdev_lock); + } +} + +static void hdd_cleanup_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + struct net_device *dev = NULL; + + if (adapter) + dev = adapter->dev; + else { + hdd_err("adapter is Null"); + return; + } + + hdd_apf_context_destroy(adapter); + qdf_spinlock_destroy(&adapter->mc_list_lock); + hdd_adapter_destroy_vdev_info(adapter); + hdd_sta_info_deinit(&adapter->sta_info_list); + hdd_sta_info_deinit(&adapter->cache_sta_info_list); + + wlan_hdd_debugfs_csr_deinit(adapter); + + hdd_debugfs_exit(adapter); + + /* + * The adapter is marked as closed. When hdd_wlan_exit() call returns, + * the driver is almost closed and cannot handle either control + * messages or data. However, unregister_netdevice() call above will + * eventually invoke hdd_stop(ndo_close) driver callback, which attempts + * to close the active connections(basically excites control path) which + * is not right. Setting this flag helps hdd_stop() to recognize that + * the interface is closed and restricts any operations on that + */ + clear_bit(DEVICE_IFACE_OPENED, &adapter->event_flags); + + if (test_bit(NET_DEVICE_REGISTERED, &adapter->event_flags)) { + if (rtnl_held) { + hdd_debug("hdd_unregister_netdevice(%s) type:%d", + dev->name, adapter->device_mode); + hdd_unregister_netdevice(adapter, dev); + } else { + hdd_debug("unregister_netdev(%s) type:%d", dev->name, + adapter->device_mode); + unregister_netdev(dev); + } + /* + * Note that the adapter is no longer valid at this point + * since the memory has been reclaimed + */ + } +} + +static QDF_STATUS hdd_check_for_existing_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_CHECK_FOR_EXISTING_MACADDR; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!qdf_mem_cmp(adapter->mac_addr.bytes, + mac_addr, sizeof(tSirMacAddr))) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return QDF_STATUS_E_FAILURE; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_configure_chain_mask() - programs chain mask to firmware + * @adapter: HDD adapter + * + * Return: 0 on success or errno on failure + */ +static int hdd_configure_chain_mask(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = ucfg_mlme_configure_chain_mask(hdd_ctx->psoc, + adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + return 0; + +error: + hdd_debug("WMI PDEV set param failed"); + return -EINVAL; +} + +void hdd_adapter_update_mlo_mgr_mac_addr(struct hdd_adapter *adapter) +{ + int i = 0; + struct wlan_hdd_link_info *link_info; + struct wlan_mlo_link_mac_update link_mac = {0}; + + if (!hdd_adapter_is_ml_adapter(adapter)) + return; + + hdd_adapter_for_each_link_info(adapter, link_info) { + link_mac.link_mac_info[i].vdev_id = link_info->vdev_id; + qdf_copy_macaddr(&link_mac.link_mac_info[i++].link_mac_addr, + &link_info->link_addr); + } + + link_mac.num_mac_update = i; + mlo_mgr_update_link_info_mac_addr(adapter->deflink->vdev, &link_mac); +} + +#ifdef FEATURE_COEX +/** + * hdd_send_coex_config_params() - Send coex config params to FW + * @hdd_ctx: HDD context + * @adapter: Primary adapter context + * + * This function is used to send all coex config related params to FW + * + * Return: 0 on success and -EINVAL on failure + */ +static int hdd_send_coex_config_params(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_objmgr_vdev *vdev; + struct coex_config_params coex_cfg_params = {0}; + struct coex_multi_config *coex_multi_cfg = NULL; + struct wlan_fwol_coex_config config = {0}; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + enum coex_btc_chain_mode btc_chain_mode; + QDF_STATUS status; + uint32_t i = 0; + + if (!adapter) { + hdd_err("adapter is invalid"); + goto err; + } + + if (!psoc) { + hdd_err("HDD psoc is invalid"); + goto err; + } + + status = ucfg_fwol_get_coex_config_params(psoc, &config); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get coex config params"); + goto err; + } + + coex_multi_cfg = qdf_mem_malloc(sizeof(*coex_multi_cfg)); + if (!coex_multi_cfg) + goto err; + + coex_multi_cfg->vdev_id = adapter->deflink->vdev_id; + + coex_multi_cfg->cfg_items[i].config_type = WMI_COEX_CONFIG_TX_POWER; + coex_multi_cfg->cfg_items[i].config_arg1 = config.max_tx_power_for_btc; + + wma_nofl_debug("TXP[W][send_coex_cfg]: %d", + config.max_tx_power_for_btc); + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_HANDOVER_RSSI; + coex_multi_cfg->cfg_items[i].config_arg1 = + config.wlan_low_rssi_threshold; + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = WMI_COEX_CONFIG_BTC_MODE; + + /* Modify BTC_MODE according to BTC_CHAIN_MODE */ + status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get btc chain mode"); + btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + } + + if (btc_chain_mode <= WLAN_COEX_BTC_CHAIN_MODE_HYBRID) + coex_multi_cfg->cfg_items[i].config_arg1 = btc_chain_mode; + else + coex_multi_cfg->cfg_items[i].config_arg1 = config.btc_mode; + + hdd_debug("Configured BTC mode is %d, BTC chain mode is 0x%x, set BTC mode to %d", + config.btc_mode, btc_chain_mode, + coex_multi_cfg->cfg_items[i].config_arg1); + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_ANTENNA_ISOLATION; + coex_multi_cfg->cfg_items[i].config_arg1 = config.antenna_isolation; + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_BT_LOW_RSSI_THRESHOLD; + coex_multi_cfg->cfg_items[i].config_arg1 = config.bt_low_rssi_threshold; + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_BT_INTERFERENCE_LEVEL; + coex_multi_cfg->cfg_items[i].config_arg1 = + config.bt_interference_low_ll; + coex_multi_cfg->cfg_items[i].config_arg2 = + config.bt_interference_low_ul; + coex_multi_cfg->cfg_items[i].config_arg3 = + config.bt_interference_medium_ll; + coex_multi_cfg->cfg_items[i].config_arg4 = + config.bt_interference_medium_ul; + coex_multi_cfg->cfg_items[i].config_arg5 = + config.bt_interference_high_ll; + coex_multi_cfg->cfg_items[i].config_arg6 = + config.bt_interference_high_ul; + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + if (wlan_hdd_mpta_helper_enable(&coex_cfg_params, &config)) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_BT_SCO_ALLOW_WLAN_2G_SCAN; + coex_multi_cfg->cfg_items[i].config_arg1 = + config.bt_sco_allow_wlan_2g_scan; + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_LE_SCAN_POLICY; + coex_multi_cfg->cfg_items[i].config_arg1 = config.ble_scan_coex_policy; + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; + +#ifdef FEATURE_COEX_TPUT_SHAPING_CONFIG + coex_multi_cfg->cfg_items[i].config_type = + WMI_COEX_CONFIG_ENABLE_TPUT_SHAPING; + coex_multi_cfg->cfg_items[i].config_arg1 = + config.coex_tput_shaping_enable; + + if (++i > COEX_MULTI_CONFIG_MAX_CNT) + goto err; +#endif + + coex_multi_cfg->num_configs = i; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_COEX_ID); + if (!vdev) { + hdd_err("vdev is null"); + goto err; + } + + ucfg_coex_send_multi_config(vdev, coex_multi_cfg); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_COEX_ID); + qdf_mem_free(coex_multi_cfg); + + return 0; +err: + qdf_mem_free(coex_multi_cfg); + return -EINVAL; +} +#else +/** + * hdd_send_coex_config_params() - Send coex config params to FW + * @hdd_ctx: HDD context + * @adapter: Primary adapter context + * + * This function is used to send all coex config related params to FW + * + * Return: 0 on success and -EINVAL on failure + */ +static int hdd_send_coex_config_params(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct coex_config_params coex_cfg_params = {0}; + struct wlan_fwol_coex_config config = {0}; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + enum coex_btc_chain_mode btc_chain_mode; + QDF_STATUS status; + + if (!adapter) { + hdd_err("adapter is invalid"); + goto err; + } + + if (!psoc) { + hdd_err("HDD psoc is invalid"); + goto err; + } + + status = ucfg_fwol_get_coex_config_params(psoc, &config); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get coex config params"); + goto err; + } + + coex_cfg_params.vdev_id = adapter->deflink->vdev_id; + coex_cfg_params.config_type = WMI_COEX_CONFIG_TX_POWER; + coex_cfg_params.config_arg1 = config.max_tx_power_for_btc; + + wma_nofl_debug("TXP[W][send_coex_cfg]: %d", + config.max_tx_power_for_btc); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex Tx power"); + goto err; + } + + coex_cfg_params.config_type = WMI_COEX_CONFIG_HANDOVER_RSSI; + coex_cfg_params.config_arg1 = config.wlan_low_rssi_threshold; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex handover RSSI"); + goto err; + } + + coex_cfg_params.config_type = WMI_COEX_CONFIG_BTC_MODE; + + /* Modify BTC_MODE according to BTC_CHAIN_MODE */ + status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get btc chain mode"); + btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + } + + if (btc_chain_mode <= WLAN_COEX_BTC_CHAIN_MODE_HYBRID) + coex_cfg_params.config_arg1 = btc_chain_mode; + else + coex_cfg_params.config_arg1 = config.btc_mode; + + hdd_debug("Configured BTC mode is %d, BTC chain mode is 0x%x, set BTC mode to %d", + config.btc_mode, btc_chain_mode, + coex_cfg_params.config_arg1); + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex BTC mode"); + goto err; + } + + coex_cfg_params.config_type = WMI_COEX_CONFIG_ANTENNA_ISOLATION; + coex_cfg_params.config_arg1 = config.antenna_isolation; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex antenna isolation"); + goto err; + } + + coex_cfg_params.config_type = WMI_COEX_CONFIG_BT_LOW_RSSI_THRESHOLD; + coex_cfg_params.config_arg1 = config.bt_low_rssi_threshold; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex BT low RSSI threshold"); + goto err; + } + + coex_cfg_params.config_type = WMI_COEX_CONFIG_BT_INTERFERENCE_LEVEL; + coex_cfg_params.config_arg1 = config.bt_interference_low_ll; + coex_cfg_params.config_arg2 = config.bt_interference_low_ul; + coex_cfg_params.config_arg3 = config.bt_interference_medium_ll; + coex_cfg_params.config_arg4 = config.bt_interference_medium_ul; + coex_cfg_params.config_arg5 = config.bt_interference_high_ll; + coex_cfg_params.config_arg6 = config.bt_interference_high_ul; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex BT interference level"); + goto err; + } + + if (wlan_hdd_mpta_helper_enable(&coex_cfg_params, &config)) + goto err; + + coex_cfg_params.config_type = + WMI_COEX_CONFIG_BT_SCO_ALLOW_WLAN_2G_SCAN; + coex_cfg_params.config_arg1 = config.bt_sco_allow_wlan_2g_scan; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex BT sco allow wlan 2g scan"); + goto err; + } + + coex_cfg_params.config_type = + WMI_COEX_CONFIG_LE_SCAN_POLICY; + coex_cfg_params.config_arg1 = config.ble_scan_coex_policy; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex BLE scan policy"); + goto err; + } + +#ifdef FEATURE_COEX_TPUT_SHAPING_CONFIG + coex_cfg_params.config_type = + WMI_COEX_CONFIG_ENABLE_TPUT_SHAPING; + coex_cfg_params.config_arg1 = config.coex_tput_shaping_enable; + + status = sme_send_coex_config_cmd(&coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex traffic shaping value %d", + coex_cfg_params.config_arg1); + goto err; + } +#endif + return 0; +err: + return -EINVAL; +} +#endif + +/** + * hdd_send_coex_traffic_shaping_mode() - Send coex traffic shaping mode + * to FW + * @vdev_id: vdev ID + * @mode: traffic shaping mode + * + * This function is used to send coex traffic shaping mode to FW + * + * Return: 0 on success and -EINVAL on failure + */ +int hdd_send_coex_traffic_shaping_mode(uint8_t vdev_id, uint8_t mode) +{ + struct coex_config_params coex_cfg_params = {0}; + + coex_cfg_params.config_type = WMI_COEX_SET_TRAFFIC_SHAPING_MODE; + coex_cfg_params.config_arg1 = mode; + coex_cfg_params.vdev_id = vdev_id; + + if (QDF_IS_STATUS_ERROR(sme_send_coex_config_cmd(&coex_cfg_params))) { + hdd_err_rl("Failed to send coex traffic shaping mode"); + return -EINVAL; + } + return 0; +} + +#define MAX_PDEV_SET_FW_PARAMS 7 +/* params being sent: + * 1.wmi_pdev_param_dtim_synth + * 2.wmi_pdev_param_1ch_dtim_optimized_chain_selection + * 3.wmi_pdev_param_tx_sch_delay + * 4.wmi_pdev_param_en_update_scram_seed + * 5.wmi_pdev_param_secondary_retry_enable + * 6.wmi_pdev_param_set_sap_xlna_bypass + * 7.wmi_pdev_param_set_dfs_chan_ageout_time + */ + +/** + * hdd_set_fw_params() - Set parameters to firmware + * @adapter: HDD adapter + * + * This function Sets various parameters to fw once the + * adapter is started. + * + * Return: 0 on success or errno on failure + */ +int hdd_set_fw_params(struct hdd_adapter *adapter) +{ + int ret; + uint16_t upper_brssi_thresh, lower_brssi_thresh; + bool enable_dtim_1chrx; + QDF_STATUS status; + struct hdd_context *hdd_ctx; + bool is_lprx_enabled; + bool bval = false; + uint8_t enable_tx_sch_delay, dfs_chan_ageout_time; + uint32_t dtim_sel_diversity, enable_secondary_rate; + bool sap_xlna_bypass; + bool enable_ofdm_scrambler_seed = false; + struct dev_set_param setparam[MAX_PDEV_SET_FW_PARAMS] = { }; + uint8_t index = 0; + + hdd_enter_dev(adapter->dev); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_debug("FTM Mode is active; nothing to do"); + return 0; + } + + /* The ini gEnableLPRx is deprecated. By default, the ini + * is enabled. So, making the variable is_lprx_enabled true. + */ + is_lprx_enabled = true; + + ret = mlme_check_index_setparam(setparam, wmi_pdev_param_dtim_synth, + is_lprx_enabled, index++, + MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + + ucfg_mlme_get_dtim_selection_diversity(hdd_ctx->psoc, + &dtim_sel_diversity); + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_1ch_dtim_optimized_chain_selection, + dtim_sel_diversity, index++, MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + + if (QDF_IS_STATUS_SUCCESS(ucfg_fwol_get_enable_tx_sch_delay( + hdd_ctx->psoc, &enable_tx_sch_delay))) { + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_tx_sch_delay, + enable_tx_sch_delay, index++, + MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + } + + if (QDF_IS_STATUS_SUCCESS(ucfg_fwol_get_ofdm_scrambler_seed( + hdd_ctx->psoc, &enable_ofdm_scrambler_seed))) { + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_en_update_scram_seed, + enable_ofdm_scrambler_seed, index++, + MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + } + + if (QDF_IS_STATUS_SUCCESS(ucfg_fwol_get_enable_secondary_rate( + hdd_ctx->psoc, &enable_secondary_rate))) { + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_secondary_retry_enable, + enable_secondary_rate, index++, + MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + } + if (QDF_IS_STATUS_SUCCESS(ucfg_fwol_get_sap_xlna_bypass( + hdd_ctx->psoc, &sap_xlna_bypass))) { + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_set_sap_xlna_bypass, + sap_xlna_bypass, index++, + MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + } + wlan_mlme_get_dfs_chan_ageout_time(hdd_ctx->psoc, + &dfs_chan_ageout_time); + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_set_dfs_chan_ageout_time, + dfs_chan_ageout_time, index++, + MAX_PDEV_SET_FW_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) + goto error; + + ret = sme_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(ret)) { + goto error; + } + if (adapter->device_mode == QDF_STA_MODE) { + status = ucfg_get_upper_brssi_thresh(hdd_ctx->psoc, + &upper_brssi_thresh); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + sme_set_smps_cfg(adapter->deflink->vdev_id, + HDD_STA_SMPS_PARAM_UPPER_BRSSI_THRESH, + upper_brssi_thresh); + + status = ucfg_get_lower_brssi_thresh(hdd_ctx->psoc, + &lower_brssi_thresh); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + sme_set_smps_cfg(adapter->deflink->vdev_id, + HDD_STA_SMPS_PARAM_LOWER_BRSSI_THRESH, + lower_brssi_thresh); + + status = ucfg_get_enable_dtim_1chrx(hdd_ctx->psoc, + &enable_dtim_1chrx); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + sme_set_smps_cfg(adapter->deflink->vdev_id, + HDD_STA_SMPS_PARAM_DTIM_1CHRX_ENABLE, + enable_dtim_1chrx); + } + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + if (bval) { + hdd_debug("configuring 2x2 mode fw params"); + + ret = sme_set_cck_tx_fir_override(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + if (ret) { + hdd_err("wmi_pdev_param_enable_cck_tfir_override set failed %d", + ret); + goto error; + } + + hdd_configure_chain_mask(adapter); + } else { +#define HDD_DTIM_1CHAIN_RX_ID 0x5 +#define HDD_SMPS_PARAM_VALUE_S 29 + hdd_debug("configuring 1x1 mode fw params"); + + /* + * Disable DTIM 1 chain Rx when in 1x1, + * we are passing two value + * as param_id << 29 | param_value. + * Below param_value = 0(disable) + */ + ret = sme_cli_set_command(adapter->deflink->vdev_id, + WMI_STA_SMPS_PARAM_CMDID, + HDD_DTIM_1CHAIN_RX_ID << + HDD_SMPS_PARAM_VALUE_S, + VDEV_CMD); + if (ret) { + hdd_err("DTIM 1 chain set failed %d", ret); + goto error; + } + +#undef HDD_DTIM_1CHAIN_RX_ID +#undef HDD_SMPS_PARAM_VALUE_S + + hdd_configure_chain_mask(adapter); + } + + ret = sme_set_enable_mem_deep_sleep(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + if (ret) { + hdd_err("wmi_pdev_param_hyst_en set failed %d", ret); + goto error; + } + + if (!hdd_ctx->is_fw_dbg_log_levels_configured) { + hdd_set_fw_log_params(hdd_ctx, adapter->deflink->vdev_id); + hdd_ctx->is_fw_dbg_log_levels_configured = true; + } + + ret = hdd_send_coex_config_params(hdd_ctx, adapter); + if (ret) { + hdd_warn("Error initializing coex config params"); + goto error; + } + + hdd_exit(); + + return 0; + +error: + return -EINVAL; +} + +/** + * hdd_init_completion() - Initialize Completion Variables + * @adapter: HDD adapter + * + * This function Initialize the completion variables for + * a particular adapter + * + * Return: None + */ +static void hdd_init_completion(struct hdd_adapter *adapter) +{ + init_completion(&adapter->disconnect_comp_var); + init_completion(&adapter->linkup_event_var); + init_completion(&adapter->lfr_fw_status.disable_lfr_event); +} + +static void hdd_reset_locally_admin_bit(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr) +{ + int i; + /* + * Reset locally administered bit for dynamic_mac_list + * also as while releasing the MAC address for any + * interface mac will be compared with dynamic mac list + */ + for (i = 0; i < QDF_MAX_CONCURRENCY_PERSONA; i++) { + if (!qdf_mem_cmp( + mac_addr, + &hdd_ctx-> + dynamic_mac_list[i].dynamic_mac.bytes[0], + sizeof(struct qdf_mac_addr))) { + WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT( + hdd_ctx-> + dynamic_mac_list[i].dynamic_mac.bytes); + break; + } + } + /* + * Reset locally administered bit if the device mode is + * STA + */ + WLAN_HDD_RESET_LOCALLY_ADMINISTERED_BIT(mac_addr); + hdd_debug("locally administered bit reset in sta mode: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac_addr)); +} + +static void wlan_hdd_cfg80211_scan_block_cb(struct work_struct *work) +{ + struct hdd_adapter *adapter = + container_of(work, struct hdd_adapter, scan_block_work); + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync)) + return; + + wlan_hdd_cfg80211_scan_block(adapter); + + osif_vdev_sync_op_stop(vdev_sync); +} + +#if defined(WLAN_FEATURE_11BE_MLO) && \ + defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +static inline void +wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params, + enum QDF_OPMODE mode) +{ + if (mode != QDF_SAP_MODE) + return; + + create_params->is_ml_adapter = true; +} +#elif defined(WLAN_FEATURE_11BE_MLO) +static inline void +wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params, + enum QDF_OPMODE mode) +{ + if (mode != QDF_SAP_MODE) + return; + + create_params->is_ml_adapter = true; + create_params->is_single_link = true; +} +#else +static inline void +wlan_hdd_set_ml_cap_for_sap_intf(struct hdd_adapter_create_param *create_params, + enum QDF_OPMODE mode) +{ + create_params->is_ml_adapter = false; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +void +hdd_adapter_disable_all_links(struct hdd_adapter *adapter, bool clear_macaddr) +{ + uint8_t idx_pos; + struct wlan_hdd_link_info *link_info; + + hdd_adapter_for_each_link_info(adapter, link_info) { + if (clear_macaddr) + qdf_zero_macaddr(&link_info->link_addr); + idx_pos = hdd_adapter_get_index_of_link_info(link_info); + adapter->curr_link_info_map[idx_pos] = idx_pos; + } + + adapter->deflink = &adapter->link_info[WLAN_HDD_DEFLINK_IDX]; + adapter->active_links = (1 << adapter->num_links_on_create) - 1; +} +#endif + +static void hdd_adapter_enable_links(struct hdd_adapter *adapter, + struct hdd_adapter_create_param *params) +{ + uint8_t num, link_idx; + + /* Default link is already set on adapter allocation, only + * enable other links if requested links is greater than 1 + */ + if (params->num_sessions <= 1) { + adapter->num_links_on_create = 1; + return; + } + + num = QDF_MIN(params->num_sessions, WLAN_MAX_MLD); + for (link_idx = WLAN_HDD_DEFLINK_IDX; link_idx < num; link_idx++) + qdf_atomic_set_bit(link_idx, &adapter->active_links); + + adapter->num_links_on_create = num; +} + +static void hdd_adapter_init_link_info(struct hdd_adapter *adapter) +{ + uint8_t idx_pos; + struct wlan_hdd_link_info *link_info; + + /* Initialize each member in link info array to default values */ + hdd_adapter_for_each_link_info(adapter, link_info) { + link_info->adapter = adapter; + link_info->vdev_id = WLAN_UMAC_VDEV_ID_MAX; + qdf_spinlock_create(&link_info->vdev_lock); + init_completion(&link_info->vdev_destroy_event); + qdf_event_create(&link_info->acs_complete_event); + + idx_pos = hdd_adapter_get_index_of_link_info(link_info); + adapter->curr_link_info_map[idx_pos] = idx_pos; + qdf_create_work(0, &link_info->chan_change_notify_work, + hdd_chan_change_notify_work_handler, + link_info); + } +} + +/** + * hdd_open_adapter() - open and setup the hdd adapter + * @hdd_ctx: global hdd context + * @session_type: type of the interface to be created + * @iface_name: User-visible name of the interface + * @mac_addr: MAC address to assign to the interface + * @name_assign_type: the name of assign type of the netdev + * @rtnl_held: the rtnl lock hold flag + * @params: adapter create params + * + * This function open and setup the hdd adapter according to the device + * type request, assign the name, the mac address assigned, and then prepared + * the hdd related parameters, queue, lock and ready to start. + * + * Return: the pointer of hdd adapter, otherwise NULL. + */ +struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, + uint8_t session_type, + const char *iface_name, + tSirMacAddr mac_addr, + unsigned char name_assign_type, + bool rtnl_held, + struct hdd_adapter_create_param *params) +{ + struct net_device *ndev = NULL; + struct hdd_adapter *adapter = NULL, *sta_adapter = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t i; + bool eht_capab = 0; + + status = wlan_hdd_validate_mac_address((struct qdf_mac_addr *)mac_addr); + if (QDF_IS_STATUS_ERROR(status)) { + /* Not received valid mac_addr */ + hdd_err("Unable to add virtual intf: Not able to get valid mac address"); + return NULL; + } + + status = hdd_check_for_existing_macaddr(hdd_ctx, mac_addr); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("Duplicate MAC addr: " QDF_MAC_ADDR_FMT + " already exists", + QDF_MAC_ADDR_REF(mac_addr)); + return NULL; + } + + if (params->only_wdev_register) { + sta_adapter = hdd_get_ml_adapter(hdd_ctx); + if (!sta_adapter) { + hdd_err("not able to find the sta adapter"); + return NULL; + } + } + + switch (session_type) { + case QDF_STA_MODE: + if (!(hdd_ctx->config->mac_provision || + params->only_wdev_register)) { + hdd_reset_locally_admin_bit(hdd_ctx, mac_addr); + /* + * After resetting locally administered bit + * again check if the new mac address is already + * exists. + */ + status = hdd_check_for_existing_macaddr(hdd_ctx, + mac_addr); + if (QDF_STATUS_E_FAILURE == status) { + hdd_err("Duplicate MAC addr: " QDF_MAC_ADDR_FMT + " already exists", + QDF_MAC_ADDR_REF(mac_addr)); + return NULL; + } + } + + fallthrough; + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_OCB_MODE: + case QDF_NDI_MODE: + case QDF_MONITOR_MODE: + case QDF_NAN_DISC_MODE: + adapter = hdd_alloc_station_adapter(hdd_ctx, mac_addr, + name_assign_type, + iface_name, session_type); + + if (!adapter) { + hdd_err("failed to allocate adapter for session %d", + session_type); + return NULL; + } + + ndev = adapter->dev; + + status = ucfg_dp_create_intf(hdd_ctx->psoc, &adapter->mac_addr, + (qdf_netdev_t)adapter->dev); + if (QDF_IS_STATUS_ERROR(status)) + goto err_free_netdev; + + if (QDF_P2P_CLIENT_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT; + else if (QDF_P2P_DEVICE_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_P2P_DEVICE; + else if (QDF_MONITOR_MODE == session_type) + adapter->wdev.iftype = NL80211_IFTYPE_MONITOR; + else if (QDF_NAN_DISC_MODE == session_type) + wlan_hdd_set_nan_if_type(adapter); + else + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + + adapter->device_mode = session_type; + + + /* + * Workqueue which gets scheduled in IPv4 notification + * callback + */ + INIT_WORK(&adapter->ipv4_notifier_work, + hdd_ipv4_notifier_work_queue); + +#ifdef WLAN_NS_OFFLOAD + /* + * Workqueue which gets scheduled in IPv6 + * notification callback. + */ + INIT_WORK(&adapter->ipv6_notifier_work, + hdd_ipv6_notifier_work_queue); +#endif + if (params->only_wdev_register) { + hdd_register_wdev(sta_adapter, adapter, params); + } else { + status = hdd_register_interface(adapter, rtnl_held, + params); + if (QDF_STATUS_SUCCESS != status) + goto err_destroy_dp_intf; + /* Stop the Interface TX queue. */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + break; + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + adapter = hdd_wlan_create_ap_dev(hdd_ctx, mac_addr, + name_assign_type, + (uint8_t *) iface_name); + if (!adapter) { + hdd_err("failed to allocate adapter for session %d", + session_type); + return NULL; + } + + ndev = adapter->dev; + + status = ucfg_dp_create_intf(hdd_ctx->psoc, &adapter->mac_addr, + (qdf_netdev_t)adapter->dev); + if (QDF_IS_STATUS_ERROR(status)) + goto err_free_netdev; + + adapter->wdev.iftype = + (session_type == + QDF_SAP_MODE) ? NL80211_IFTYPE_AP : + NL80211_IFTYPE_P2P_GO; + adapter->device_mode = session_type; + + status = hdd_register_interface(adapter, rtnl_held, params); + if (QDF_STATUS_SUCCESS != status) + goto err_destroy_dp_intf; + + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* + * Workqueue which gets scheduled in IPv4 notification + * callback + */ + INIT_WORK(&adapter->ipv4_notifier_work, + hdd_ipv4_notifier_work_queue); + +#ifdef WLAN_NS_OFFLOAD + /* + * Workqueue which gets scheduled in IPv6 + * notification callback. + */ + INIT_WORK(&adapter->ipv6_notifier_work, + hdd_ipv6_notifier_work_queue); +#endif + if (!params->is_pre_cac_adapter) + wlan_hdd_set_ml_cap_for_sap_intf(params, session_type); + break; + case QDF_FTM_MODE: + adapter = hdd_alloc_station_adapter(hdd_ctx, mac_addr, + name_assign_type, + iface_name, session_type); + if (!adapter) { + hdd_err("Failed to allocate adapter for FTM mode"); + return NULL; + } + + ndev = adapter->dev; + + status = ucfg_dp_create_intf(hdd_ctx->psoc, &adapter->mac_addr, + (qdf_netdev_t)adapter->dev); + if (QDF_IS_STATUS_ERROR(status)) + goto err_free_netdev; + + adapter->wdev.iftype = NL80211_IFTYPE_STATION; + adapter->device_mode = session_type; + status = hdd_register_interface(adapter, rtnl_held, params); + if (QDF_STATUS_SUCCESS != status) + goto err_destroy_dp_intf; + + /* Stop the Interface TX queue. */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + break; + default: + hdd_err("Invalid session type %d", session_type); + QDF_ASSERT(0); + return NULL; + } + + hdd_adapter_init_link_info(adapter); + hdd_adapter_enable_links(adapter, params); + + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (params->is_ml_adapter && eht_capab) { + hdd_adapter_set_ml_adapter(adapter); + if (params->is_single_link) + hdd_adapter_set_sl_ml_adapter(adapter); + } + + status = hdd_adapter_feature_update_work_init(adapter); + if (QDF_IS_STATUS_ERROR(status)) + goto err_cleanup_adapter; + + adapter->upgrade_udp_qos_threshold = QCA_WLAN_AC_BK; + + hdd_init_completion(adapter); + INIT_WORK(&adapter->scan_block_work, wlan_hdd_cfg80211_scan_block_cb); + INIT_WORK(&adapter->sap_stop_bss_work, + hdd_stop_sap_due_to_invalid_channel); + qdf_list_create(&adapter->blocked_scan_request_q, WLAN_MAX_SCAN_COUNT); + qdf_mutex_create(&adapter->blocked_scan_request_q_lock); + qdf_spinlock_create(&adapter->mc_list_lock); + qdf_event_create(&adapter->peer_cleanup_done); + hdd_sta_info_init(&adapter->sta_info_list); + hdd_sta_info_init(&adapter->cache_sta_info_list); + + for (i = 0; i < NET_DEV_HOLD_ID_MAX; i++) + qdf_atomic_init( + &adapter->net_dev_hold_ref_count[NET_DEV_HOLD_ID_MAX]); + + /* Add it to the hdd's session list. */ + status = hdd_add_adapter_back(hdd_ctx, adapter); + if (QDF_STATUS_SUCCESS != status) + goto err_destroy_adapter_features_update_work; + + hdd_apf_context_init(adapter); + + policy_mgr_set_concurrency_mode(hdd_ctx->psoc, session_type); + + if (QDF_STATUS_SUCCESS != hdd_debugfs_init(adapter)) + hdd_err("debugfs: Interface %s init failed", + netdev_name(adapter->dev)); + + hdd_debug("%s interface created. iftype: %d", netdev_name(adapter->dev), + session_type); + + if (adapter->device_mode == QDF_STA_MODE) + wlan_hdd_debugfs_csr_init(adapter); + + return adapter; + +err_destroy_adapter_features_update_work: + hdd_adapter_feature_update_work_deinit(adapter); + +err_cleanup_adapter: + if (adapter) { + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + adapter = NULL; + } + +err_destroy_dp_intf: + ucfg_dp_destroy_intf(hdd_ctx->psoc, &adapter->mac_addr); + +err_free_netdev: + if (ndev) + free_netdev(ndev); + + return NULL; +} + +static void __hdd_close_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + struct qdf_mac_addr adapter_mac; + struct wlan_hdd_link_info *link_info; + + qdf_copy_macaddr(&adapter_mac, &adapter->mac_addr); + if (adapter->device_mode == QDF_STA_MODE) { + hdd_adapter_for_each_link_info(adapter, link_info) + hdd_cleanup_conn_info(link_info); + } + + hdd_adapter_for_each_link_info(adapter, link_info) + qdf_flush_work(&link_info->chan_change_notify_work); + + qdf_list_destroy(&adapter->blocked_scan_request_q); + qdf_mutex_destroy(&adapter->blocked_scan_request_q_lock); + policy_mgr_clear_concurrency_mode(hdd_ctx->psoc, adapter->device_mode); + qdf_event_destroy(&adapter->peer_cleanup_done); + hdd_adapter_feature_update_work_deinit(adapter); + hdd_cleanup_adapter(hdd_ctx, adapter, rtnl_held); + ucfg_dp_destroy_intf(hdd_ctx->psoc, &adapter_mac); +} + +void hdd_close_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + /* + * Stop the global bus bandwidth timer while touching the adapter list + * to avoid bad memory access by the timer handler. + */ + ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc); + + hdd_check_for_net_dev_ref_leak(adapter); + hdd_remove_adapter(hdd_ctx, adapter); + __hdd_close_adapter(hdd_ctx, adapter, rtnl_held); + + /* conditionally restart the bw timer */ + ucfg_dp_bus_bw_compute_timer_try_start(hdd_ctx->psoc); +} + +void hdd_close_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter; + struct osif_vdev_sync *vdev_sync; + QDF_STATUS qdf_status; + + hdd_enter(); + + while (QDF_IS_STATUS_SUCCESS(hdd_get_front_adapter( + hdd_ctx, &adapter))) { + /* If MLO is enabled unregister the link wdev's */ + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_SAP_MODE) { + qdf_status = hdd_wlan_unregister_mlo_interfaces(adapter, + rtnl_held); + if (QDF_IS_STATUS_ERROR(qdf_status)) + continue; + } + + hdd_check_for_net_dev_ref_leak(adapter); + hdd_remove_front_adapter(hdd_ctx, &adapter); + vdev_sync = osif_vdev_sync_unregister(adapter->dev); + if (vdev_sync) + osif_vdev_sync_wait_for_ops(vdev_sync); + + wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); + __hdd_close_adapter(hdd_ctx, adapter, rtnl_held); + + if (vdev_sync) + osif_vdev_sync_destroy(vdev_sync); + } + + hdd_exit(); +} + +void wlan_hdd_reset_prob_rspies(struct wlan_hdd_link_info *link_info) +{ + struct qdf_mac_addr *bssid = NULL; + tSirUpdateIE update_ie; + mac_handle_t mac_handle; + struct hdd_adapter *adapter = link_info->adapter; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + bssid = &sta_ctx->conn_info.bssid; + break; + } + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + { + bssid = &adapter->mac_addr; + break; + } + case QDF_FTM_MODE: + case QDF_P2P_DEVICE_MODE: + default: + /* + * wlan_hdd_reset_prob_rspies should not have been called + * for these kind of devices + */ + hdd_err("Unexpected request for the current device type %d", + adapter->device_mode); + return; + } + + qdf_copy_macaddr(&update_ie.bssid, bssid); + update_ie.vdev_id = link_info->vdev_id; + update_ie.ieBufferlength = 0; + update_ie.pAdditionIEBuffer = NULL; + update_ie.append = true; + update_ie.notify = false; + mac_handle = hdd_adapter_get_mac_handle(adapter); + if (sme_update_add_ie(mac_handle, + &update_ie, + eUPDATE_IE_PROBE_RESP) == QDF_STATUS_E_FAILURE) { + hdd_err("Could not pass on PROBE_RSP_BCN data to PE"); + } +} + +/** + * hdd_ipa_ap_disconnect_evt() - Indicate wlan ipa ap disconnect event + * @hdd_ctx: hdd context + * @adapter: hdd adapter + * + * Return: None + */ +static inline +void hdd_ipa_ap_disconnect_evt(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + + link_info = adapter->deflink; + if (ucfg_ipa_is_enabled()) { + ucfg_ipa_uc_disconnect_ap(hdd_ctx->pdev, + adapter->dev); + ucfg_ipa_cleanup_dev_iface(hdd_ctx->pdev, + adapter->dev, + link_info->vdev_id); + } +} + +#ifdef WLAN_FEATURE_NAN +/** + * hdd_ndp_state_cleanup() - API to set NDP state to Disconnected + * @psoc: pointer to psoc object + * @ndi_vdev_id: vdev_id of the NDI + * + * Return: None + */ +static void +hdd_ndp_state_cleanup(struct wlan_objmgr_psoc *psoc, uint8_t ndi_vdev_id) +{ + struct wlan_objmgr_vdev *ndi_vdev; + + ndi_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, ndi_vdev_id, + WLAN_NAN_ID); + if (!ndi_vdev) { + hdd_err("Cannot obtain NDI vdev object!"); + return; + } + + ucfg_nan_set_ndi_state(ndi_vdev, NAN_DATA_DISCONNECTED_STATE); + + wlan_objmgr_vdev_release_ref(ndi_vdev, WLAN_NAN_ID); +} + +/** + * hdd_peer_cleanup() - This API will delete NDP peer if exist and modifies + * the NDP state. + * @link_info: Link info pointer in HDD adapter + * + * Return: None + */ +static void hdd_peer_cleanup(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + + /* Check if there is any peer present on the adapter */ + if (!hdd_any_valid_peer_present(link_info)) { + /* + * No peers are connected to the NDI. So, set the NDI state to + * DISCONNECTED. If there are any peers, ucfg_nan_disable_ndi() + * would take care of cleanup all the peers and setting the + * state to DISCONNECTED. + */ + hdd_ndp_state_cleanup(hdd_ctx->psoc, link_info->vdev_id); + return; + } + + if (adapter->device_mode == QDF_NDI_MODE) + qdf_status = ucfg_nan_disable_ndi(hdd_ctx->psoc, + link_info->vdev_id); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + qdf_status = qdf_wait_for_event_completion(&adapter->peer_cleanup_done, + WLAN_WAIT_PEER_CLEANUP); + if (QDF_IS_STATUS_ERROR(qdf_status)) + hdd_debug("peer_cleanup_done wait fail"); +} +#else +static inline void +hdd_ndp_state_cleanup(struct wlan_objmgr_psoc *psoc, uint8_t ndi_vdev_id) +{ +} + +static inline void +hdd_ndp_peer_cleanup(struct hdd_context *hdd_ctx, struct hdd_adapter *adapter) +{ +} + +static inline void hdd_peer_cleanup(struct wlan_hdd_link_info *link_info) +{ +} +#endif /* WLAN_FEATURE_NAN */ + +#ifdef FUNC_CALL_MAP + +/** + * hdd_dump_func_call_map() - Dump the function call map + * + * Return: None + */ + +static void hdd_dump_func_call_map(void) +{ + char *cc_buf; + + cc_buf = qdf_mem_malloc(QDF_FUNCTION_CALL_MAP_BUF_LEN); + /* + * These logs are required as these indicates the start and end of the + * dump for the auto script to parse + */ + hdd_info("Function call map dump start"); + qdf_get_func_call_map(cc_buf); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, + QDF_TRACE_LEVEL_DEBUG, cc_buf, QDF_FUNCTION_CALL_MAP_BUF_LEN); + hdd_info("Function call map dump end"); + qdf_mem_free(cc_buf); +} +#else +static inline void hdd_dump_func_call_map(void) +{ +} +#endif + +static void hdd_reset_scan_operation(struct wlan_hdd_link_info *link_info) +{ + switch (link_info->adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NDI_MODE: + wlan_hdd_scan_abort(link_info); + wlan_hdd_cleanup_remain_on_channel_ctx(link_info); + if (link_info->adapter->device_mode == QDF_STA_MODE) { + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_SCAN_ID); + if (!vdev) + break; + + wlan_cfg80211_sched_scan_stop(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID); + } + break; + case QDF_P2P_GO_MODE: + wlan_hdd_cleanup_remain_on_channel_ctx(link_info); + break; + case QDF_SAP_MODE: + qdf_atomic_set(&link_info->session.ap.acs_in_progress, 0); + break; + default: + break; + } +} + +#ifdef WLAN_OPEN_SOURCE +void hdd_cancel_ip_notifier_work(struct hdd_adapter *adapter) +{ + cancel_work_sync(&adapter->ipv4_notifier_work); +#ifdef WLAN_NS_OFFLOAD + cancel_work_sync(&adapter->ipv6_notifier_work); +#endif +} +#endif + +void hdd_adapter_deregister_fc(struct hdd_adapter *adapter) +{ + hdd_deregister_hl_netdev_fc_timer(adapter); + hdd_deregister_tx_flow_control(adapter); +} + +static void hdd_stop_and_cleanup_ndi(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS status; + unsigned long rc; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + + hdd_destroy_adapter_sysfs_files(adapter); + /* For NDI do not use roam_profile */ + INIT_COMPLETION(adapter->disconnect_comp_var); + hdd_peer_cleanup(link_info); + status = sme_roam_ndi_stop(hdd_ctx->mac_handle, link_info->vdev_id); + if (QDF_IS_STATUS_SUCCESS(status)) { + rc = wait_for_completion_timeout( + &adapter->disconnect_comp_var, + msecs_to_jiffies(SME_CMD_STOP_BSS_TIMEOUT)); + if (!rc) + hdd_warn("disconn_comp_var wait fail"); + hdd_cleanup_ndi(link_info); + } +} + +static void +hdd_sta_disconnect_and_cleanup(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS status; + enum wlan_reason_code reason; + struct hdd_adapter *adapter = link_info->adapter; + + /* + * On vdev delete wait for disconnect to + * complete. i.e use sync API, so that the + * vdev ref of MLME are cleaned and disconnect + * complete before vdev is moved to logically + * deleted. + */ + if (cds_is_driver_recovering()) + reason = REASON_DEVICE_RECOVERY; + else + reason = REASON_IFACE_DOWN; + + status = wlan_hdd_cm_issue_disconnect(link_info, reason, true); + if (QDF_IS_STATUS_ERROR(status) && ucfg_ipa_is_enabled()) { + hdd_err("STA disconnect failed"); + ucfg_ipa_uc_cleanup_sta(adapter->hdd_ctx->pdev, adapter->dev, + link_info->vdev_id); + } +} + +static void +hdd_disable_nan_active_disc(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + enum QDF_OPMODE device_mode = adapter->device_mode; + + if ((device_mode == QDF_NAN_DISC_MODE || + (device_mode == QDF_STA_MODE && + !ucfg_nan_is_vdev_creation_allowed(hdd_ctx->psoc))) && + ucfg_is_nan_conc_control_supported(hdd_ctx->psoc) && + ucfg_is_nan_disc_active(hdd_ctx->psoc)) + ucfg_disable_nan_discovery(hdd_ctx->psoc, NULL, 0); +} + +static void +hdd_monitor_mode_release_wakelock(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (wlan_hdd_is_session_type_monitor(adapter->device_mode) && + (ucfg_mlme_is_sta_mon_conc_supported(hdd_ctx->psoc) || + ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc))) { + hdd_info("Release wakelock for STA + monitor mode!"); + os_if_dp_local_pkt_capture_stop(link_info->vdev); + qdf_runtime_pm_allow_suspend( + &hdd_ctx->runtime_context.monitor_mode); + hdd_lpc_enable_powersave(hdd_ctx); + qdf_wake_lock_release(&hdd_ctx->monitor_mode_wakelock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + } +} + +static void +hdd_monitor_mode_disable_and_delete(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + + status = hdd_disable_monitor_mode(); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("datapath reset failed for montior mode"); + hdd_set_idle_ps_config(hdd_ctx, true); + status = hdd_monitor_mode_vdev_status(adapter); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("stop failed montior mode"); + sme_delete_mon_session(hdd_ctx->mac_handle, link_info->vdev_id); +} + +static void +hdd_stop_and_close_pre_cac_adapter(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) + return; + + if (!ucfg_pre_cac_adapter_is_active(vdev)) { + ucfg_pre_cac_stop(hdd_ctx->psoc); + hdd_close_pre_cac_adapter(hdd_ctx); + } else { + if (ucfg_pre_cac_set_status(vdev, false)) + hdd_err("Failed to set is_pre_cac_on to false"); + } +} + +static void hdd_reset_ies_on_sap_stop(struct wlan_hdd_link_info *link_info) +{ + mac_handle_t mac_handle; + tSirUpdateIE update_ie; + QDF_STATUS status; + struct hdd_adapter *adapter = link_info->adapter; + + mac_handle = hdd_adapter_get_mac_handle(adapter); + update_ie.vdev_id = link_info->vdev_id; + update_ie.ieBufferlength = 0; + update_ie.pAdditionIEBuffer = NULL; + update_ie.append = false; + update_ie.notify = false; + + /* Probe bcn reset */ + status = sme_update_add_ie(mac_handle, &update_ie, + eUPDATE_IE_PROBE_BCN); + if (status == QDF_STATUS_E_FAILURE) + hdd_err("Could not pass PROBE_RSP_BCN to PE"); + + /* Assoc resp reset */ + status = sme_update_add_ie(mac_handle, &update_ie, + eUPDATE_IE_ASSOC_RESP); + if (status == QDF_STATUS_E_FAILURE) + hdd_err("Could not pass ASSOC_RSP to PE"); + + /* Reset WNI_CFG_PROBE_RSP Flags */ + wlan_hdd_reset_prob_rspies(link_info); +} + +static void hdd_stop_station_adapter(struct hdd_adapter *adapter) +{ + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE mode; + struct wlan_hdd_link_info *link_info; + + mode = adapter->device_mode; + hdd_adapter_for_each_active_link_info(adapter, link_info) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_INIT_DEINIT_ID); + if (!vdev) + continue; + + if (mode == QDF_NDI_MODE) + hdd_stop_and_cleanup_ndi(link_info); + else if (!hdd_cm_is_disconnected(link_info)) + hdd_sta_disconnect_and_cleanup(link_info); + + hdd_reset_scan_operation(link_info); + wlan_hdd_cleanup_actionframe(link_info); + wlan_hdd_flush_pmksa_cache(link_info); + + if (mode == QDF_STA_MODE) + ucfg_ipa_flush_pending_vdev_events( + wlan_vdev_get_pdev(vdev), + link_info->vdev_id); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + hdd_vdev_destroy(link_info); + } + + hdd_disable_nan_active_disc(adapter); + hdd_adapter_deregister_fc(adapter); + hdd_cancel_ip_notifier_work(adapter); +} + +static int hdd_stop_mon_adapter(struct hdd_adapter *adapter) +{ + struct wlan_objmgr_vdev *vdev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_hdd_link_info *link_info = adapter->deflink; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_INIT_DEINIT_ID); + if (wlan_hdd_is_session_type_monitor(adapter->device_mode) && + vdev && + ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + struct hdd_adapter *sta_adapter; + + ucfg_pkt_capture_deregister_callbacks(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + link_info->vdev = NULL; + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + hdd_err("No station interface found"); + return -EINVAL; + } + hdd_reset_monitor_interface(sta_adapter); + } + + hdd_monitor_mode_release_wakelock(link_info); + wlan_hdd_scan_abort(link_info); + hdd_adapter_deregister_fc(adapter); + hdd_monitor_mode_disable_and_delete(link_info); + if (vdev) + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + + hdd_vdev_destroy(link_info); + + return 0; +} + +static void hdd_stop_sap_go_adapter(struct hdd_adapter *adapter) +{ + enum QDF_OPMODE mode; + struct hdd_ap_ctx *ap_ctx; + struct sap_context *sap_ctx; + struct sap_config *sap_config; + struct hdd_hostapd_state *hostapd_state; + struct wlan_objmgr_vdev *vdev; + struct wlan_hdd_link_info *link_info = adapter->deflink; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t link_id; + + mode = adapter->device_mode; + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_INIT_DEINIT_ID); + + if (mode == QDF_SAP_MODE) { + wlan_hdd_scan_abort(link_info); + hdd_abort_ongoing_sta_connection(hdd_ctx); + /* Diassociate with all the peers before stop ap post */ + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + if (wlan_hdd_del_station(adapter, NULL)) + hdd_sap_indicate_disconnect_for_sta(adapter); + } + wlan_hdd_flush_pmksa_cache(link_info); + sap_config = &ap_ctx->sap_config; + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + hdd_stop_and_close_pre_cac_adapter(hdd_ctx, vdev); + } + wlansap_cleanup_cac_timer(sap_ctx); + cds_flush_work(&adapter->sap_stop_bss_work); + + if (qdf_atomic_read(&ap_ctx->acs_in_progress)) { + hdd_info("ACS in progress, wait for complete"); + qdf_wait_for_event_completion(&link_info->acs_complete_event, + ACS_COMPLETE_TIMEOUT); + } + + if (mode == QDF_P2P_GO_MODE) { + wlan_hdd_cleanup_remain_on_channel_ctx(link_info); + hdd_abort_ongoing_sta_connection(hdd_ctx); + } + + hdd_adapter_deregister_fc(adapter); + hdd_destroy_acs_timer(adapter); + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + status = wlansap_stop_bss(ap_ctx->sap_context); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = qdf_wait_single_event(&hostapd_state->qdf_stop_bss_event, + SME_CMD_STOP_BSS_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failure waiting for wlansap_stop_bss %d", + status); + hdd_ipa_ap_disconnect_evt(hdd_ctx, adapter); + } + } else { + hdd_err("failure in wlansap_stop_bss"); + } + + clear_bit(SOFTAP_BSS_STARTED, &link_info->link_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + adapter->device_mode, + link_info->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, adapter->device_mode, + false); + + hdd_reset_ies_on_sap_stop(link_info); + } + + /* + * Note to restart sap after SSR driver needs below information + * and is not cleared/freed on purpose in case of SAP SSR + */ + if (!cds_is_driver_recovering()) { + clear_bit(SOFTAP_INIT_DONE, &link_info->link_flags); + qdf_mem_free(ap_ctx->beacon); + ap_ctx->beacon = NULL; + + if (vdev) { + link_id = wlan_vdev_get_link_id(vdev); + ucfg_crypto_free_key_by_link_id(hdd_ctx->psoc, + &link_info->link_addr, + link_id); + } + } + /* Clear all the cached sta info */ + hdd_clear_cached_sta_info(adapter); + + if (vdev && policy_mgr_is_dnsc_set(vdev)) + wlan_hdd_send_avoid_freq_for_dnbs(hdd_ctx, 0); + + hdd_cancel_ip_notifier_work(adapter); + sap_release_vdev_ref(sap_ctx); + + if (mode == QDF_SAP_MODE) + ucfg_ipa_flush_pending_vdev_events(hdd_ctx->pdev, + link_info->vdev_id); + if (vdev) + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + hdd_vdev_destroy(link_info); + mutex_unlock(&hdd_ctx->sap_lock); + ucfg_ipa_flush(hdd_ctx->pdev); +} + +static void hdd_stop_ocb_adapter(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *sta_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_INIT_DEINIT_ID); + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + cdp_clear_peer(cds_get_context(QDF_MODULE_ID_SOC), OL_TXRX_PDEV_ID, + sta_ctx->conn_info.peer_macaddr[0]); + hdd_adapter_deregister_fc(adapter); + if (vdev) + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INIT_DEINIT_ID); + hdd_vdev_destroy(link_info); +} + +QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + hdd_destroy_adapter_sysfs_files(adapter); + + if (adapter->device_mode == QDF_STA_MODE && + hdd_is_pkt_capture_mon_enable(adapter) && + ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + hdd_unmap_monitor_interface_vdev(adapter); + } + + if (link_info->vdev_id != WLAN_UMAC_VDEV_ID_MAX) + wlan_hdd_cfg80211_deregister_frames(adapter); + + hdd_stop_tsf_sync(adapter); + cds_flush_work(&adapter->scan_block_work); + wlan_hdd_cfg80211_scan_block(adapter); + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_NDI_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NAN_DISC_MODE: + hdd_stop_station_adapter(adapter); + break; + case QDF_MONITOR_MODE: + status = hdd_stop_mon_adapter(adapter); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + hdd_stop_sap_go_adapter(adapter); + break; + case QDF_OCB_MODE: + hdd_stop_ocb_adapter(adapter); + break; + default: + break; + } + + /* Moved from vdev destroy as it is per adapter */ + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, adapter->dev); + + /* Disable all links (expect default index) in adapter. + * Set link address to NULL + */ + hdd_adapter_disable_all_links(adapter, true); + + /* This function should be invoked at the end of this api*/ + hdd_dump_func_call_map(); + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_stop_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_stop_link_adapter(hdd_ctx, adapter); + + status = hdd_stop_adapter_ext(hdd_ctx, adapter); + + return status; +} + +/** + * hdd_deinit_all_adapters - deinit all adapters + * @hdd_ctx: HDD context + * @rtnl_held: True if RTNL lock held + * + */ +void hdd_deinit_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + + hdd_enter(); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_DEINIT_ALL_ADAPTERS) { + hdd_deinit_adapter(hdd_ctx, adapter, rtnl_held); + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_DEINIT_ALL_ADAPTERS); + } + + hdd_exit(); +} + +QDF_STATUS hdd_stop_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + + hdd_enter(); + + ucfg_pre_cac_stop(hdd_ctx->psoc); + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_STOP_ALL_ADAPTERS) { + hdd_stop_adapter(hdd_ctx, adapter); + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_STOP_ALL_ADAPTERS); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +void hdd_set_netdev_flags(struct hdd_adapter *adapter) +{ + bool enable_csum = false; + bool enable_lro; + enum QDF_OPMODE device_mode; + struct hdd_context *hdd_ctx; + ol_txrx_soc_handle soc; + uint64_t temp; + + if (!adapter || !adapter->dev) { + hdd_err("invalid input!"); + return; + } + device_mode = adapter->device_mode; + + hdd_ctx = adapter->hdd_ctx; + soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc || !hdd_ctx) { + hdd_err("invalid SOC or HDD context!"); + return; + } + + /* Determine device_mode specific configuration */ + + enable_lro = !!cdp_cfg_get(soc, cfg_dp_lro_enable); + enable_csum = !!cdp_cfg_get(soc, + cfg_dp_enable_ip_tcp_udp_checksum_offload); + switch (device_mode) { + case QDF_P2P_DEVICE_MODE: + case QDF_P2P_CLIENT_MODE: + enable_csum = !!cdp_cfg_get(soc, + cfg_dp_enable_p2p_ip_tcp_udp_checksum_offload); + break; + case QDF_P2P_GO_MODE: + enable_csum = !!cdp_cfg_get(soc, + cfg_dp_enable_p2p_ip_tcp_udp_checksum_offload); + enable_lro = false; + break; + case QDF_SAP_MODE: + enable_lro = false; + break; + case QDF_NDI_MODE: + case QDF_NAN_DISC_MODE: + enable_csum = !!cdp_cfg_get(soc, + cfg_dp_enable_nan_ip_tcp_udp_checksum_offload); + break; + default: + break; + } + + /* Set netdev flags */ + + /* + * In case of USB tethering, LRO is disabled. If SSR happened + * during that time, then as part of SSR init, do not enable + * the LRO again. Keep the LRO state same as before SSR. + */ + if (enable_lro && !(qdf_atomic_read(&hdd_ctx->vendor_disable_lro_flag))) + adapter->dev->features |= NETIF_F_LRO; + + if (enable_csum) + adapter->dev->features |= + (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM); + + if (cdp_cfg_get(soc, cfg_dp_tso_enable) && enable_csum) { + adapter->dev->features |= TSO_FEATURE_FLAGS; + adapter->tso_csum_feature_enabled = 1; + } + + if (cdp_cfg_get(soc, cfg_dp_sg_enable)) + adapter->dev->features |= NETIF_F_SG; + + adapter->dev->features |= NETIF_F_RXCSUM; + temp = (uint64_t)adapter->dev->features; + + hdd_debug("adapter mode %u dev feature 0x%llx", device_mode, temp); +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_adapter_abort_tx_flow() - Abort the tx flow control + * @adapter: pointer to hdd adapter + * + * Resume tx and stop the tx flow control timer if the tx is paused + * and the flow control timer is running. This function is called by + * SSR to avoid the inconsistency of tx status before and after SSR. + * + * Return: void + */ +static void hdd_adapter_abort_tx_flow(struct hdd_adapter *adapter) +{ + if (adapter->deflink->hdd_stats.tx_rx_stats.is_txflow_paused && + QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &adapter->tx_flow_control_timer)) { + hdd_tx_resume_timer_expired_handler(adapter); + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + } +} +#else +static void hdd_adapter_abort_tx_flow(struct hdd_adapter *adapter) +{ +} +#endif + +QDF_STATUS hdd_reset_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + bool value; + struct wlan_objmgr_vdev *vdev; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + ucfg_mlme_get_sap_internal_restart(hdd_ctx->psoc, &value); + + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_RESET_ALL_ADAPTERS) { + hdd_info("[SSR] reset adapter with device mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + hdd_adapter_abort_tx_flow(adapter); + + if ((adapter->device_mode == QDF_STA_MODE) || + (adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + hdd_send_twt_del_all_sessions_to_userspace(link_info); + + /* Stop tdls timers */ + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_TDLS_ID); + if (vdev) { + hdd_notify_tdls_reset_adapter(vdev); + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_OSIF_TDLS_ID); + } + } + + if (value && + adapter->device_mode == QDF_SAP_MODE) { + hdd_medium_assess_ssr_enable_flag(); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } else { + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + + /* + * Clear fc flag if it was set before SSR to avoid + * TX queues permanently stopped after SSR. + * Here WLAN_START_ALL_NETIF_QUEUE will actually + * not start any queue since it's blocked by reason + * WLAN_CONTROL_PATH. + */ + if (adapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL)) + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + hdd_reset_scan_operation(link_info); + if (test_bit(WMM_INIT_DONE, &adapter->event_flags)) { + hdd_wmm_adapter_close(adapter); + clear_bit(WMM_INIT_DONE, &adapter->event_flags); + } + + hdd_debug("Flush any mgmt references held by peer"); + hdd_stop_adapter(hdd_ctx, adapter); + } + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_RESET_ALL_ADAPTERS); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +static bool hdd_is_any_link_opened(struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (test_bit(SME_SESSION_OPENED, &link_info->link_flags)) + return true; + } + return false; +} + +bool hdd_is_any_interface_open(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_ANY_INTERFACE_OPEN; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_info("FTM mode, don't close the module"); + return true; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags) || + hdd_is_any_link_opened(adapter)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, dbgid); + return true; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return false; +} + +bool hdd_is_interface_up(struct hdd_adapter *adapter) +{ + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) + return true; + else + return false; +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +#ifdef WLAN_FEATURE_11BE +static inline bool wlan_hdd_is_mon_channel_bw_valid(enum phy_ch_width ch_width) +{ + if (ch_width > CH_WIDTH_320MHZ || + (!cds_is_sub_20_mhz_enabled() && (ch_width == CH_WIDTH_5MHZ || + ch_width == CH_WIDTH_10MHZ))) + return false; + + return true; +} +#else +static inline bool wlan_hdd_is_mon_channel_bw_valid(enum phy_ch_width ch_width) +{ + if (ch_width > CH_WIDTH_10MHZ || + (!cds_is_sub_20_mhz_enabled() && (ch_width == CH_WIDTH_5MHZ || + ch_width == CH_WIDTH_10MHZ))) + return false; + + return true; +} +#endif + +int wlan_hdd_set_mon_chan(struct hdd_adapter *adapter, qdf_freq_t freq, + uint32_t bandwidth) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx; + struct hdd_mon_set_ch_info *ch_info; + QDF_STATUS status; + struct qdf_mac_addr bssid; + struct channel_change_req *req; + struct ch_params ch_params; + enum phy_ch_width max_fw_bw; + enum phy_ch_width ch_width; + int ret; + + if ((hdd_get_conparam() != QDF_GLOBAL_MONITOR_MODE) && + (!policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc))) { + hdd_err("Not supported, device is not in monitor mode"); + return -EINVAL; + } + + if (adapter->device_mode != QDF_MONITOR_MODE) { + hdd_err_rl("Not supported, adapter is not in monitor mode"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + ch_info = &sta_ctx->ch_info; + + /* Verify the BW before accepting this request */ + ch_width = bandwidth; + + if (!wlan_hdd_is_mon_channel_bw_valid(ch_width)) { + hdd_err("invalid BW received %d", ch_width); + return -EINVAL; + } + + max_fw_bw = sme_get_vht_ch_width(); + + hdd_debug("max fw BW %d ch width %d", max_fw_bw, ch_width); + if ((ch_width == CH_WIDTH_160MHZ && + max_fw_bw <= WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) || + (ch_width == CH_WIDTH_80P80MHZ && + max_fw_bw <= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ)) { + hdd_err("FW does not support this BW %d max BW supported %d", + ch_width, max_fw_bw); + return -EINVAL; + } + + if (!hdd_is_target_eht_phy_ch_width_supported(ch_width)) + return -EINVAL; + + ret = hdd_validate_channel_and_bandwidth(adapter, freq, bandwidth); + if (ret) { + hdd_err("Invalid CH and BW combo"); + return ret; + } + + hdd_debug("Set monitor mode frequency %d", freq); + qdf_mem_copy(bssid.bytes, adapter->mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + ch_params.ch_width = bandwidth; + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, freq, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + + if (ch_params.ch_width == CH_WIDTH_INVALID) { + hdd_err("Invalid capture channel or bandwidth for a country"); + return -EINVAL; + } + if (wlan_hdd_change_hw_mode_for_given_chnl(adapter, freq, + POLICY_MGR_UPDATE_REASON_SET_OPER_CHAN)) { + hdd_err("Failed to change hw mode"); + return -EINVAL; + } + + if (adapter->monitor_mode_vdev_up_in_progress) { + hdd_err_rl("monitor mode vdev up in progress"); + return -EBUSY; + } + + status = qdf_event_reset(&adapter->qdf_monitor_mode_vdev_up_event); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("failed to reinit monitor mode vdev up event"); + return qdf_status_to_os_return(status); + } + adapter->monitor_mode_vdev_up_in_progress = true; + + qdf_mem_zero(&ch_params, sizeof(struct ch_params)); + + req = qdf_mem_malloc(sizeof(struct channel_change_req)); + if (!req) + return -ENOMEM; + req->vdev_id = adapter->deflink->vdev_id; + req->target_chan_freq = freq; + req->ch_width = ch_width; + + ch_params.ch_width = ch_width; + hdd_select_cbmode(adapter, freq, 0, &ch_params); + + req->sec_ch_offset = ch_params.sec_ch_offset; + req->center_freq_seg0 = ch_params.center_freq_seg0; + req->center_freq_seg1 = ch_params.center_freq_seg1; + + sme_fill_channel_change_request(hdd_ctx->mac_handle, req, + ch_info->phy_mode); + status = sme_send_channel_change_req(hdd_ctx->mac_handle, req); + qdf_mem_free(req); + if (status) { + hdd_err("Status: %d Failed to set sme_roam Channel for monitor mode", + status); + adapter->monitor_mode_vdev_up_in_progress = false; + return qdf_status_to_os_return(status); + } + + adapter->mon_chan_freq = freq; + adapter->mon_bandwidth = bandwidth; + + /* block on a completion variable until vdev up success*/ + status = qdf_wait_for_event_completion( + &adapter->qdf_monitor_mode_vdev_up_event, + WLAN_MONITOR_MODE_VDEV_UP_EVT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("monitor vdev up event time out vdev id: %d", + adapter->deflink->vdev_id); + if (adapter->qdf_monitor_mode_vdev_up_event.force_set) + /* + * SSR/PDR has caused shutdown, which has + * forcefully set the event. + */ + hdd_err_rl("monitor mode vdev up event forcefully set"); + else if (status == QDF_STATUS_E_TIMEOUT) + hdd_err("monitor mode vdev up timed out"); + else + hdd_err_rl("Failed monitor mode vdev up(status-%d)", + status); + + adapter->monitor_mode_vdev_up_in_progress = false; + } + + return qdf_status_to_os_return(status); +} +#endif + +#if defined MSM_PLATFORM && (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0)) +/** + * hdd_stop_p2p_go() - call cfg80211 API to stop P2P GO + * @adapter: pointer to adapter + * + * This function calls cfg80211 API to stop P2P GO + * + * Return: None + */ +static void hdd_stop_p2p_go(struct hdd_adapter *adapter) +{ + hdd_debug("[SSR] send stop ap to supplicant"); + cfg80211_ap_stopped(adapter->dev, GFP_KERNEL); +} + +static inline void hdd_delete_sta(struct hdd_adapter *adapter) +{ +} + +#else +static void hdd_stop_p2p_go(struct hdd_adapter *adapter) +{ + hdd_debug("[SSR] send stop iface ap to supplicant"); + cfg80211_stop_iface(adapter->hdd_ctx->wiphy, &adapter->wdev, + GFP_KERNEL); +} + +/** + * hdd_delete_sta() - call cfg80211 API to delete STA + * @adapter: pointer to adapter + * + * This function calls cfg80211 API to delete STA + * + * Return: None + */ +static void hdd_delete_sta(struct hdd_adapter *adapter) +{ + struct qdf_mac_addr bcast_mac = QDF_MAC_ADDR_BCAST_INIT; + + hdd_debug("[SSR] send restart supplicant"); + /* event supplicant to restart */ + cfg80211_del_sta(adapter->dev, + (const u8 *)&bcast_mac.bytes[0], + GFP_KERNEL); +} +#endif + +QDF_STATUS hdd_start_all_adapters(struct hdd_context *hdd_ctx, bool rtnl_held) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + bool value; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_START_ALL_ADAPTERS; + int ret; + + hdd_enter(); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!hdd_is_interface_up(adapter) && + adapter->device_mode != QDF_NDI_MODE) { + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + + hdd_debug("[SSR] start adapter with device mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + + hdd_wmm_dscp_initial_state(adapter); + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_NAN_DISC_MODE: + + ret = hdd_start_station_adapter(adapter); + if (ret) { + hdd_err("[SSR] Failed to start station adapter: %d", + ret); + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + if (adapter->device_mode == QDF_STA_MODE) { + ret = hdd_start_link_adapter(adapter); + if (ret) { + hdd_err("[SSR] Failed to start link adapter: %d", + ret); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_adapter_dev_put_debug(adapter, + dbgid); + continue; + } + } + + /* Open the gates for HDD to receive Wext commands */ + adapter->is_link_up_service_needed = false; + + if ((adapter->device_mode == QDF_NAN_DISC_MODE || + (adapter->device_mode == QDF_STA_MODE && + !ucfg_nan_is_vdev_creation_allowed( + hdd_ctx->psoc))) && + cds_is_driver_recovering()) + ucfg_nan_disable_ind_to_userspace( + hdd_ctx->psoc); + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb, + hdd_tx_flow_control_is_pause); + + hdd_register_hl_netdev_fc_timer( + adapter, + hdd_tx_resume_timer_expired_handler); + + hdd_lpass_notify_start(adapter->deflink); + break; + + case QDF_SAP_MODE: + ucfg_mlme_get_sap_internal_restart(hdd_ctx->psoc, + &value); + if (value) + hdd_start_ap_adapter(adapter, rtnl_held); + + break; + + case QDF_P2P_GO_MODE: + hdd_delete_sta(adapter); + break; + case QDF_MONITOR_MODE: + if (wlan_hdd_is_session_type_monitor( + adapter->device_mode) && + ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + struct hdd_adapter *sta_adapter; + + sta_adapter = hdd_get_adapter(hdd_ctx, + QDF_STA_MODE); + if (!sta_adapter) { + hdd_err("No station interface found"); + return -EINVAL; + } + + hdd_map_monitor_interface_vdev(sta_adapter); + break; + } + hdd_start_station_adapter(adapter); + hdd_set_mon_rx_cb(adapter->dev); + + wlan_hdd_set_mon_chan( + adapter, adapter->mon_chan_freq, + adapter->mon_bandwidth); + break; + case QDF_NDI_MODE: + hdd_ndi_start(adapter->dev->name, 0); + break; + default: + break; + } + /* + * Action frame registered in one adapter which will + * applicable to all interfaces + */ + if (hdd_set_fw_params(adapter)) + hdd_err("Failed to set adapter FW params after SSR!"); + + wlan_hdd_cfg80211_register_frames(adapter); + hdd_create_adapter_sysfs_files(adapter); + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!hdd_is_interface_up(adapter)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + + if (adapter->device_mode == QDF_P2P_GO_MODE) + hdd_stop_p2p_go(adapter); + + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +void hdd_adapter_dev_hold_debug(struct hdd_adapter *adapter, + wlan_net_dev_ref_dbgid dbgid) +{ + if (dbgid >= NET_DEV_HOLD_ID_MAX) { + hdd_err("Invalid debug id: %d", dbgid); + QDF_BUG(0); + } + dev_hold(adapter->dev); + qdf_atomic_inc(&adapter->net_dev_hold_ref_count[dbgid]); +} + +void hdd_adapter_dev_put_debug(struct hdd_adapter *adapter, + wlan_net_dev_ref_dbgid dbgid) +{ + if (dbgid >= NET_DEV_HOLD_ID_MAX) { + hdd_err("Invalid debug id: %d", dbgid); + QDF_BUG(0); + } + + if (qdf_atomic_dec_return( + &adapter->net_dev_hold_ref_count[dbgid]) < 0) { + hdd_err("dev_put detected without dev_hold for debug id: %s", + net_dev_ref_debug_string_from_id(dbgid)); + QDF_BUG(0); + } + + if (adapter->dev) { + dev_put(adapter->dev); + } else { + hdd_err("adapter->dev is NULL"); + QDF_BUG(0); + } +} + +QDF_STATUS hdd_get_front_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_adapter = NULL; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_peek_front(&hdd_ctx->hdd_adapters, &node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_adapter = qdf_container_of(node, struct hdd_adapter, node); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_get_next_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *current_adapter, + struct hdd_adapter **out_adapter) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_adapter = NULL; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_peek_next(&hdd_ctx->hdd_adapters, + ¤t_adapter->node, + &node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_adapter = qdf_container_of(node, struct hdd_adapter, node); + + return status; +} + +QDF_STATUS hdd_get_front_adapter_no_lock(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_adapter = NULL; + + status = qdf_list_peek_front(&hdd_ctx->hdd_adapters, &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_adapter = qdf_container_of(node, struct hdd_adapter, node); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_get_next_adapter_no_lock(struct hdd_context *hdd_ctx, + struct hdd_adapter *current_adapter, + struct hdd_adapter **out_adapter) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + if (!current_adapter) + return QDF_STATUS_E_INVAL; + + *out_adapter = NULL; + + status = qdf_list_peek_next(&hdd_ctx->hdd_adapters, + ¤t_adapter->node, + &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_adapter = qdf_container_of(node, struct hdd_adapter, node); + + return status; +} + +QDF_STATUS hdd_remove_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_remove_node(&hdd_ctx->hdd_adapters, &adapter->node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + return status; +} + +QDF_STATUS hdd_remove_front_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter **out_adapter) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_adapter = NULL; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_remove_front(&hdd_ctx->hdd_adapters, &node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_adapter = qdf_container_of(node, struct hdd_adapter, node); + + return status; +} + +QDF_STATUS hdd_add_adapter_back(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_insert_back(&hdd_ctx->hdd_adapters, &adapter->node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + return status; +} + +QDF_STATUS hdd_add_adapter_front(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + status = qdf_list_insert_front(&hdd_ctx->hdd_adapters, &adapter->node); + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + return status; +} + +void hdd_validate_next_adapter(struct hdd_adapter **curr, + struct hdd_adapter **next, + wlan_net_dev_ref_dbgid dbg_id) +{ + if (!*curr || !*next || *curr != *next) + return; + + hdd_err("Validation failed"); + hdd_adapter_dev_put_debug(*curr, dbg_id); + *curr = NULL; + *next = NULL; +} + +QDF_STATUS hdd_adapter_iterate(hdd_adapter_iterate_cb cb, void *context) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *cache[HDD_MAX_ADAPTERS]; + struct hdd_adapter *adapter; + uint32_t n_cache = 0; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + QDF_STATUS status; + int i; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (unlikely(!hdd_ctx)) + return QDF_STATUS_E_FAILURE; + + qdf_spin_lock_bh(&hdd_ctx->hdd_adapter_lock); + for (hdd_get_front_adapter_no_lock(hdd_ctx, &adapter); adapter; + hdd_get_next_adapter_no_lock(hdd_ctx, adapter, &adapter)) { + cache[n_cache++] = adapter; + } + qdf_spin_unlock_bh(&hdd_ctx->hdd_adapter_lock); + + for (i = 0; i < n_cache; i++) { + adapter = hdd_adapter_get_by_reference(hdd_ctx, cache[i]); + if (!adapter) { + /* + * detected remove while iterating + * concurrency failure + */ + ret = QDF_STATUS_E_FAILURE; + continue; + } + hdd_adapter_for_each_active_link_info(adapter, link_info) { + status = cb(link_info, context); + if (status != QDF_STATUS_SUCCESS) { + hdd_adapter_put(adapter); + return status; + } + } + hdd_adapter_put(adapter); + } + + return ret; +} + +struct hdd_adapter *hdd_get_adapter_by_rand_macaddr( + struct hdd_context *hdd_ctx, tSirMacAddr mac_addr) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_RAND_MACADDR; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE && + adapter->device_mode != QDF_P2P_DEVICE_MODE) { + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (ucfg_p2p_check_random_mac(hdd_ctx->psoc, + link_info->vdev_id, + mac_addr)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_MACADDR; + struct qdf_mac_addr zero_mac_addr = QDF_MAC_ADDR_ZERO_INIT; + struct wlan_hdd_link_info *link_info; + + if (!qdf_mem_cmp(mac_addr, zero_mac_addr.bytes, sizeof(tSirMacAddr))) + return NULL; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!qdf_mem_cmp(adapter->mac_addr.bytes, + mac_addr, sizeof(tSirMacAddr))) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (!qdf_mem_cmp(link_info->link_addr.bytes, + mac_addr, sizeof(tSirMacAddr))) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +struct wlan_hdd_link_info * +hdd_get_link_info_by_link_addr(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *link_addr) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_MACADDR; + + if (!link_addr || qdf_is_macaddr_zero(link_addr)) + return NULL; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_link_info(adapter, link_info) { + if (qdf_is_macaddr_equal(link_addr, + &link_info->link_addr)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return link_info; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} +#else +struct hdd_adapter *hdd_get_adapter_by_macaddr(struct hdd_context *hdd_ctx, + tSirMacAddr mac_addr) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_MACADDR; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!qdf_mem_cmp(adapter->mac_addr.bytes, + mac_addr, sizeof(tSirMacAddr))) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + + if (hdd_adapter_is_sl_ml_adapter(adapter) && + !qdf_mem_cmp(adapter->mld_addr.bytes, + mac_addr, sizeof(tSirMacAddr))) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, dbgid); + return adapter; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +struct wlan_hdd_link_info * +hdd_get_link_info_by_link_addr(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *link_addr) +{ + return NULL; +} +#endif + +struct wlan_hdd_link_info * +hdd_get_link_info_by_vdev(struct hdd_context *hdd_ctx, uint32_t vdev_id) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_VDEV; + struct wlan_hdd_link_info *link_info; + + if (vdev_id == WLAN_INVALID_VDEV_ID) + return NULL; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (link_info->vdev_id == vdev_id) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return link_info; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +struct hdd_adapter *hdd_adapter_get_by_reference(struct hdd_context *hdd_ctx, + struct hdd_adapter *reference) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_ADAPTER_GET_BY_REFERENCE; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter == reference) { + dev_hold(adapter->dev); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + break; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return adapter; +} + +void hdd_adapter_put(struct hdd_adapter *adapter) +{ + dev_put(adapter->dev); +} + +struct hdd_adapter *hdd_get_adapter_by_iface_name(struct hdd_context *hdd_ctx, + const char *iface_name) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_IFACE_NAME; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!qdf_str_cmp(adapter->dev->name, iface_name)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +struct hdd_adapter *hdd_get_adapter_by_ifindex(struct hdd_context *hdd_ctx, + uint32_t if_index) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->dev->ifindex == if_index) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +/** + * hdd_get_adapter() - to get adapter matching the mode + * @hdd_ctx: hdd context + * @mode: adapter mode + * + * This routine will return the pointer to adapter matching + * with the passed mode. + * + * Return: pointer to adapter or null + */ +struct hdd_adapter *hdd_get_adapter(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode == mode) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +enum QDF_OPMODE hdd_get_device_mode(uint32_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return QDF_MAX_NO_OF_MODE; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_MAX_NO_OF_MODE; + } + + return link_info->adapter->device_mode; +} + +uint32_t hdd_get_operating_chan_freq(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + uint32_t oper_chan_freq = 0; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_OPERATING_CHAN_FREQ; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (mode == adapter->device_mode) { + oper_chan_freq = + hdd_get_link_info_home_channel(adapter->deflink); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + break; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return oper_chan_freq; +} + +static inline QDF_STATUS hdd_unregister_wext_all_adapters( + struct hdd_context *hdd_ctx, + bool rtnl_held) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_UNREGISTER_WEXT_ALL_ADAPTERS; + + hdd_enter(); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + hdd_wext_unregister(adapter->dev, rtnl_held); + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_abort_mac_scan_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_ABORT_MAC_SCAN_ALL_ADAPTERS; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + hdd_adapter_for_each_active_link_info(adapter, + link_info) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + link_info->vdev_id, + INVALID_SCAN_ID, true); + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_abort_sched_scan_all_adapters() - stops scheduled (PNO) scans for all + * adapters + * @hdd_ctx: The HDD context containing the adapters to operate on + * + * return: QDF_STATUS_SUCCESS + */ +static QDF_STATUS hdd_abort_sched_scan_all_adapters(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + int err; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_ABORT_SCHED_SCAN_ALL_ADAPTERS; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + err = wlan_hdd_sched_scan_stop(adapter->dev); + if (err) + hdd_err("Unable to stop scheduled scan"); + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_unregister_notifiers - Unregister netdev notifiers. + * @hdd_ctx: HDD context + * + * Unregister netdev notifiers like IPv4 and IPv6. + * + * Return: None. + */ +void hdd_unregister_notifiers(struct hdd_context *hdd_ctx) +{ + osif_dp_nud_unregister_netevent_notifier(hdd_ctx->psoc); + hdd_wlan_unregister_ip6_notifier(hdd_ctx); + + unregister_inetaddr_notifier(&hdd_ctx->ipv4_notifier); +} + +/** + * hdd_exit_netlink_services - Exit netlink services + * @hdd_ctx: HDD context + * + * Exit netlink services like cnss_diag, cesium netlink socket, ptt socket and + * nl service. + * + * Return: None. + */ +static void hdd_exit_netlink_services(struct hdd_context *hdd_ctx) +{ + spectral_scan_deactivate_service(); + cnss_diag_deactivate_service(); + hdd_close_cesium_nl_sock(); + ptt_sock_deactivate_svc(); + hdd_deactivate_wifi_pos(); + + nl_srv_exit(); +} + +/** + * hdd_init_netlink_services- Init netlink services + * @hdd_ctx: HDD context + * + * Init netlink services like cnss_diag, cesium netlink socket, ptt socket and + * nl service. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_init_netlink_services(struct hdd_context *hdd_ctx) +{ + int ret; + + ret = wlan_hdd_nl_init(hdd_ctx); + if (ret) { + hdd_err("nl_srv_init failed: %d", ret); + goto out; + } + cds_set_radio_index(hdd_ctx->radio_index); + + ret = hdd_activate_wifi_pos(hdd_ctx); + if (ret) { + hdd_err("hdd_activate_wifi_pos failed: %d", ret); + goto err_nl_srv; + } + + ptt_sock_activate_svc(); + + ret = hdd_open_cesium_nl_sock(); + if (ret) + hdd_err("hdd_open_cesium_nl_sock failed ret: %d", ret); + + ret = cnss_diag_activate_service(); + if (ret) { + hdd_err("cnss_diag_activate_service failed: %d", ret); + goto err_close_cesium; + } + + spectral_scan_activate_service(hdd_ctx); + + return 0; + +err_close_cesium: + hdd_close_cesium_nl_sock(); + ptt_sock_deactivate_svc(); + hdd_deactivate_wifi_pos(); +err_nl_srv: + nl_srv_exit(); +out: + return ret; +} + +#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND +static QDF_STATUS +hdd_shutdown_wlan_in_suspend_prepare(struct hdd_context *hdd_ctx) +{ +#define SHUTDOWN_IN_SUSPEND_RETRY 30 + + int count = 0; + enum pmo_suspend_mode mode; + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Modules not Enabled "); + return 0; + } + + mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc); + hdd_debug("suspend mode is %d", mode); + + if (mode == PMO_SUSPEND_NONE || mode == PMO_SUSPEND_LEGENCY) { + hdd_debug("needn't shutdown in suspend"); + return 0; + } + + if (!hdd_is_any_interface_open(hdd_ctx)) { + return pld_idle_shutdown(hdd_ctx->parent_dev, + hdd_psoc_idle_shutdown); + } else { + if (mode == PMO_SUSPEND_WOW) + return 0; + } + + /*try to wait interface down for PMO_SUSPEND_SHUTDOWN mode*/ + while (hdd_is_any_interface_open(hdd_ctx) && + count < SHUTDOWN_IN_SUSPEND_RETRY) { + count++; + hdd_debug_rl("sleep 50ms to wait adapters stopped, #%d", count); + msleep(50); + } + if (count >= SHUTDOWN_IN_SUSPEND_RETRY) { + hdd_err("some adapters not stopped"); + return -EBUSY; + } + return pld_idle_shutdown(hdd_ctx->parent_dev, hdd_psoc_idle_shutdown); +} + +static int hdd_pm_notify(struct notifier_block *b, + unsigned long event, void *p) +{ + struct hdd_context *hdd_ctx = container_of(b, struct hdd_context, + pm_notifier); + + if (wlan_hdd_validate_context(hdd_ctx) != 0) + return NOTIFY_STOP; + + hdd_debug("got PM event: %lu", event); + + switch (event) { + case PM_SUSPEND_PREPARE: + case PM_HIBERNATION_PREPARE: + if (0 != hdd_shutdown_wlan_in_suspend_prepare(hdd_ctx)) + return NOTIFY_STOP; + break; + case PM_POST_SUSPEND: + case PM_POST_HIBERNATION: + break; + } + + return NOTIFY_DONE; +} + +static void hdd_pm_notifier_init(struct hdd_context *hdd_ctx) +{ + hdd_ctx->pm_notifier.notifier_call = hdd_pm_notify; + register_pm_notifier(&hdd_ctx->pm_notifier); +} + +static void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx) +{ + unregister_pm_notifier(&hdd_ctx->pm_notifier); +} +#else +static inline void hdd_pm_notifier_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_pm_notifier_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_context_deinit() - Deinitialize HDD context + * @hdd_ctx: HDD context. + * + * Deinitialize HDD context along with all the feature specific contexts but + * do not free hdd context itself. Caller of this API is supposed to free + * HDD context. + * + * return: 0 on success and errno on failure. + */ +static int hdd_context_deinit(struct hdd_context *hdd_ctx) +{ + hdd_lpc_delete_work(hdd_ctx); + + qdf_wake_lock_destroy(&hdd_ctx->monitor_mode_wakelock); + + wlan_hdd_cfg80211_deinit(hdd_ctx->wiphy); + + ucfg_dp_bbm_context_deinit(hdd_ctx->psoc); + + hdd_sap_context_destroy(hdd_ctx); + + hdd_scan_context_destroy(hdd_ctx); + + qdf_list_destroy(&hdd_ctx->hdd_adapters); + + return 0; +} + +void hdd_context_destroy(struct hdd_context *hdd_ctx) +{ + wlan_hdd_sar_timers_deinit(hdd_ctx); + + cds_set_context(QDF_MODULE_ID_HDD, NULL); + + hdd_exit_netlink_services(hdd_ctx); + + hdd_context_deinit(hdd_ctx); + + hdd_objmgr_release_and_destroy_psoc(hdd_ctx); + + qdf_mem_free(hdd_ctx->config); + hdd_ctx->config = NULL; + cfg_release(); + + hdd_pm_notifier_deinit(hdd_ctx); + qdf_delayed_work_destroy(&hdd_ctx->psoc_idle_timeout_work); + wiphy_free(hdd_ctx->wiphy); +} + +/** + * wlan_destroy_bug_report_lock() - Destroy bug report lock + * + * This function is used to destroy bug report lock + * + * Return: None + */ +static void wlan_destroy_bug_report_lock(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("cds context is NULL"); + return; + } + + qdf_spinlock_destroy(&p_cds_context->bug_report_lock); +} + +#ifdef DISABLE_CHANNEL_LIST +static void wlan_hdd_cache_chann_mutex_destroy(struct hdd_context *hdd_ctx) +{ + qdf_mutex_destroy(&hdd_ctx->cache_channel_lock); +} +#else +static void wlan_hdd_cache_chann_mutex_destroy(struct hdd_context *hdd_ctx) +{ +} +#endif + +void hdd_wlan_exit(struct hdd_context *hdd_ctx) +{ + struct wiphy *wiphy = hdd_ctx->wiphy; + + hdd_enter(); + + ucfg_dp_wait_complete_tasks(); + wlan_hdd_destroy_mib_stats_lock(); + hdd_debugfs_ini_config_deinit(hdd_ctx); + hdd_debugfs_mws_coex_info_deinit(hdd_ctx); + hdd_psoc_idle_timer_stop(hdd_ctx); + hdd_regulatory_deinit(hdd_ctx); + + /* + * Powersave Offload Case + * Disable Idle Power Save Mode + */ + hdd_set_idle_ps_config(hdd_ctx, false); + /* clear the scan queue in all the scenarios */ + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL); + + if (hdd_ctx->driver_status != DRIVER_MODULES_CLOSED) { + hdd_unregister_wext_all_adapters(hdd_ctx, false); + /* + * Cancel any outstanding scan requests. We are about to close + * all of our adapters, but an adapter structure is what SME + * passes back to our callback function. Hence if there + * are any outstanding scan requests then there is a + * race condition between when the adapter is closed and + * when the callback is invoked. We try to resolve that + * race condition here by canceling any outstanding scans + * before we close the adapters. + * Note that the scans may be cancelled in an asynchronous + * manner, so ideally there needs to be some kind of + * synchronization. Rather than introduce a new + * synchronization here, we will utilize the fact that we are + * about to Request Full Power, and since that is synchronized, + * the expectation is that by the time Request Full Power has + * completed, all scans will be cancelled + */ + hdd_abort_mac_scan_all_adapters(hdd_ctx); + hdd_abort_sched_scan_all_adapters(hdd_ctx); + + hdd_stop_all_adapters(hdd_ctx); + hdd_deinit_all_adapters(hdd_ctx, false); + } + + unregister_netdevice_notifier(&hdd_netdev_notifier); + + qdf_dp_trace_deinit(); + + hdd_wlan_stop_modules(hdd_ctx, false); + + hdd_driver_memdump_deinit(); + + qdf_nbuf_deinit_replenish_timer(); + + if (QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { + hdd_info("Release wakelock for monitor mode!"); + qdf_wake_lock_release(&hdd_ctx->monitor_mode_wakelock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + } + + qdf_spinlock_destroy(&hdd_ctx->hdd_adapter_lock); + qdf_spinlock_destroy(&hdd_ctx->connection_status_lock); + wlan_hdd_cache_chann_mutex_destroy(hdd_ctx); + + osif_request_manager_deinit(); + + hdd_close_all_adapters(hdd_ctx, false); + + wlansap_global_deinit(); + /* + * If there is re_init failure wiphy would have already de-registered + * check the wiphy status before un-registering again + */ + if (wiphy && wiphy->registered) { + wiphy_unregister(wiphy); + wlan_hdd_cfg80211_deinit(wiphy); + hdd_lpass_notify_stop(hdd_ctx); + } + + hdd_deinit_regulatory_update_event(hdd_ctx); + hdd_exit_netlink_services(hdd_ctx); +#ifdef FEATURE_WLAN_CH_AVOID + mutex_destroy(&hdd_ctx->avoid_freq_lock); +#endif + + /* This function should be invoked at the end of this api*/ + hdd_dump_func_call_map(); +} + +/** + * hdd_wlan_notify_modem_power_state() - notify FW with modem power status + * @state: state + * + * This function notifies FW with modem power status + * + * Return: 0 if successful, error number otherwise + */ +int hdd_wlan_notify_modem_power_state(int state) +{ + int status; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) + return -EINVAL; + + qdf_status = sme_notify_modem_power_state(mac_handle, state); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("Fail to send notification with modem power state %d", + state); + return -EINVAL; + } + return 0; +} + +/** + * hdd_post_cds_enable_config() - HDD post cds start config helper + * @hdd_ctx: Pointer to the HDD + * + * Return: None + */ +QDF_STATUS hdd_post_cds_enable_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS qdf_ret_status; + + /* + * Send ready indication to the HDD. This will kick off the MAC + * into a 'running' state and should kick off an initial scan. + */ + qdf_ret_status = sme_hdd_ready_ind(hdd_ctx->mac_handle); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("sme_hdd_ready_ind() failed with status code %08d [x%08x]", + qdf_ret_status, qdf_ret_status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +struct hdd_adapter *hdd_get_first_valid_adapter(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_FIRST_VALID_ADAPTER; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +/* wake lock APIs for HDD */ +void hdd_prevent_suspend(uint32_t reason) +{ + qdf_wake_lock_acquire(&wlan_wake_lock, reason); +} + +void hdd_allow_suspend(uint32_t reason) +{ + qdf_wake_lock_release(&wlan_wake_lock, reason); +} + +void hdd_prevent_suspend_timeout(uint32_t timeout, uint32_t reason) +{ + cds_host_diag_log_work(&wlan_wake_lock, timeout, reason); + qdf_wake_lock_timeout_acquire(&wlan_wake_lock, timeout); +} + +/* Initialize channel list in sme based on the country code */ +QDF_STATUS hdd_set_sme_chan_list(struct hdd_context *hdd_ctx) +{ + return sme_init_chan_list(hdd_ctx->mac_handle, + hdd_ctx->reg.cc_src); +} + +/** + * hdd_is_5g_supported() - check if hardware supports 5GHz + * @hdd_ctx: Pointer to the hdd context + * + * HDD function to know if hardware supports 5GHz + * + * Return: true if hardware supports 5GHz + */ +bool hdd_is_5g_supported(struct hdd_context *hdd_ctx) +{ + if (!hdd_ctx) + return true; + + if (hdd_ctx->curr_band != BAND_2G) + return true; + else + return false; +} + +bool hdd_is_2g_supported(struct hdd_context *hdd_ctx) +{ + if (!hdd_ctx) + return false; + + if (hdd_ctx->curr_band != BAND_5G) + return true; + else + return false; +} + +static int hdd_wiphy_init(struct hdd_context *hdd_ctx) +{ + struct wiphy *wiphy; + int ret_val; + uint32_t channel_bonding_mode; + + wiphy = hdd_ctx->wiphy; + + /* + * The channel information in + * wiphy needs to be initialized before wiphy registration + */ + ret_val = hdd_regulatory_init(hdd_ctx, wiphy); + if (ret_val) { + hdd_err("regulatory init failed"); + return ret_val; + } + + if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_SUSPEND_WOW) { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)) + wiphy->wowlan = &wowlan_support_reg_init; +#else + wiphy->wowlan.flags = WIPHY_WOWLAN_ANY | + WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT | + WIPHY_WOWLAN_SUPPORTS_GTK_REKEY | + WIPHY_WOWLAN_GTK_REKEY_FAILURE | + WIPHY_WOWLAN_EAP_IDENTITY_REQ | + WIPHY_WOWLAN_4WAY_HANDSHAKE | + WIPHY_WOWLAN_RFKILL_RELEASE; + + wiphy->wowlan.n_patterns = (WOW_MAX_FILTER_LISTS * + WOW_MAX_FILTERS_PER_LIST); + wiphy->wowlan.pattern_min_len = WOW_MIN_PATTERN_SIZE; + wiphy->wowlan.pattern_max_len = WOW_MAX_PATTERN_SIZE; +#endif + } + + ucfg_mlme_get_channel_bonding_24ghz(hdd_ctx->psoc, + &channel_bonding_mode); + if (hdd_ctx->obss_scan_offload) { + hdd_debug("wmi_service_obss_scan supported"); + } else if (channel_bonding_mode) { + hdd_debug("enable wpa_supp obss_scan"); + wiphy->features |= NL80211_FEATURE_NEED_OBSS_SCAN; + } + + if (hdd_ctx->num_rf_chains == HDD_ANTENNA_MODE_2X2 && + ucfg_mlme_is_chain_mask_supported(hdd_ctx->psoc)) { + wiphy->available_antennas_tx = HDD_CHAIN_MODE_2X2; + wiphy->available_antennas_rx = HDD_CHAIN_MODE_2X2; + } + /* registration of wiphy dev with cfg80211 */ + ret_val = wlan_hdd_cfg80211_register(wiphy); + if (0 > ret_val) { + hdd_err("wiphy registration failed"); + return ret_val; + } + + /* Check the kernel version for upstream commit aced43ce780dc5 that + * has support for processing user cell_base hints when wiphy is + * self managed or check the backport flag for the same. + */ +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) + hdd_send_wiphy_regd_sync_event(hdd_ctx); +#endif + + pld_increment_driver_load_cnt(hdd_ctx->parent_dev); + + return ret_val; +} + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +#ifdef CLD_PM_QOS +#define PLD_REMOVE_PM_QOS(x) +#define PLD_REQUEST_PM_QOS(x, y) +#define HDD_PM_QOS_HIGH_TPUT_LATENCY_US 1 + +/** + * hdd_pm_qos_update_cpu_mask() - Prepare CPU mask for PM_qos voting + * @mask: return variable of cpumask for the TPUT + * @enable_perf_cluster: Enable PERF cluster or not + * + * By default, the function sets CPU mask for silver cluster unless + * enable_perf_cluster is set as true. + * + * Return: none + */ +static inline void hdd_pm_qos_update_cpu_mask(cpumask_t *mask, + bool enable_perf_cluster) +{ + cpumask_set_cpu(0, mask); + cpumask_set_cpu(1, mask); + cpumask_set_cpu(2, mask); + cpumask_set_cpu(3, mask); + + if (enable_perf_cluster) { + cpumask_set_cpu(4, mask); + cpumask_set_cpu(5, mask); + cpumask_set_cpu(6, mask); + } +} + +#ifdef MSM_PLATFORM +#define COPY_CPU_MASK(a, b) cpumask_copy(a, b) +#define DUMP_CPU_AFFINE() hdd_info("Set cpu_mask %*pb for affine_cores", \ + cpumask_pr_args(&hdd_ctx->pm_qos_req.cpus_affine)) +#else +#define COPY_CPU_MASK(a, b) /* no-op*/ +#define DUMP_CPU_AFFINE() /* no-op*/ +#endif + +#ifdef CLD_DEV_PM_QOS + +static inline void _hdd_pm_qos_update_request(struct hdd_context *hdd_ctx, + cpumask_t *pm_qos_cpu_mask, + unsigned int latency) +{ + int cpu; + uint32_t default_latency; + + default_latency = wlan_hdd_get_default_pm_qos_cpu_latency(); + qdf_cpumask_copy(&hdd_ctx->qos_cpu_mask, pm_qos_cpu_mask); + + if (qdf_cpumask_empty(pm_qos_cpu_mask)) { + for_each_present_cpu(cpu) { + dev_pm_qos_update_request( + &hdd_ctx->pm_qos_req[cpu], + default_latency); + } + hdd_debug("Empty mask %*pb: Set latency %u", + qdf_cpumask_pr_args(&hdd_ctx->qos_cpu_mask), + default_latency); + } else { /* Set latency to default for CPUs not included in mask */ + qdf_for_each_cpu_not(cpu, &hdd_ctx->qos_cpu_mask) { + dev_pm_qos_update_request( + &hdd_ctx->pm_qos_req[cpu], + default_latency); + } + /* Set latency for CPUs included in mask */ + qdf_for_each_cpu(cpu, &hdd_ctx->qos_cpu_mask) { + dev_pm_qos_update_request( + &hdd_ctx->pm_qos_req[cpu], + latency); + } + hdd_debug("For qos_cpu_mask %*pb set latency %u", + qdf_cpumask_pr_args(&hdd_ctx->qos_cpu_mask), + latency); + } +} + +/** + * hdd_pm_qos_update_request() - API to request for pm_qos + * @hdd_ctx: handle to hdd context + * @pm_qos_cpu_mask: cpu_mask to apply + * + * Return: none + */ +static void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx, + cpumask_t *pm_qos_cpu_mask) +{ + unsigned int latency; + + if (qdf_cpumask_empty(pm_qos_cpu_mask)) + latency = wlan_hdd_get_default_pm_qos_cpu_latency(); + else + latency = HDD_PM_QOS_HIGH_TPUT_LATENCY_US; + + _hdd_pm_qos_update_request(hdd_ctx, pm_qos_cpu_mask, latency); +} + +static inline void hdd_pm_qos_add_request(struct hdd_context *hdd_ctx) +{ + struct device *cpu_dev; + int cpu; + uint32_t default_latency = wlan_hdd_get_default_pm_qos_cpu_latency(); + + + qdf_cpumask_clear(&hdd_ctx->qos_cpu_mask); + hdd_pm_qos_update_cpu_mask(&hdd_ctx->qos_cpu_mask, false); + + for_each_present_cpu(cpu) { + cpu_dev = get_cpu_device(cpu); + dev_pm_qos_add_request(cpu_dev, &hdd_ctx->pm_qos_req[cpu], + DEV_PM_QOS_RESUME_LATENCY, + default_latency); + hdd_debug("Set qos_cpu_mask %*pb for affine_cores", + cpumask_pr_args(&hdd_ctx->qos_cpu_mask)); + } +} + +static inline void hdd_pm_qos_remove_request(struct hdd_context *hdd_ctx) +{ + int cpu; + + for_each_present_cpu(cpu) { + dev_pm_qos_remove_request(&hdd_ctx->pm_qos_req[cpu]); + hdd_debug("Remove dev_pm_qos_request for all cpus: %d", cpu); + } + qdf_cpumask_clear(&hdd_ctx->qos_cpu_mask); +} + +#else /* CLD_DEV_PM_QOS */ + +#if defined(CONFIG_SMP) && defined(MSM_PLATFORM) +/** + * hdd_set_default_pm_qos_mask() - Update PM_qos request for AFFINE_CORES + * @hdd_ctx: handle to hdd context + * + * Return: none + */ +static inline void hdd_set_default_pm_qos_mask(struct hdd_context *hdd_ctx) +{ + hdd_ctx->pm_qos_req.type = PM_QOS_REQ_AFFINE_CORES; + qdf_cpumask_clear(&hdd_ctx->pm_qos_req.cpus_affine); + hdd_pm_qos_update_cpu_mask(&hdd_ctx->pm_qos_req.cpus_affine, false); +} +#else +static inline void hdd_set_default_pm_qos_mask(struct hdd_context *hdd_ctx) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +/** + * hdd_pm_qos_update_request() - API to request for pm_qos + * @hdd_ctx: handle to hdd context + * @pm_qos_cpu_mask: cpu_mask to apply + * + * Return: none + */ +static inline void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx, + cpumask_t *pm_qos_cpu_mask) +{ + COPY_CPU_MASK(&hdd_ctx->pm_qos_req.cpus_affine, pm_qos_cpu_mask); + + if (cpumask_empty(pm_qos_cpu_mask)) + cpu_latency_qos_update_request(&hdd_ctx->pm_qos_req, + PM_QOS_DEFAULT_VALUE); + else + cpu_latency_qos_update_request(&hdd_ctx->pm_qos_req, 1); +} + +static inline void hdd_pm_qos_add_request(struct hdd_context *hdd_ctx) +{ + hdd_set_default_pm_qos_mask(hdd_ctx); + cpu_latency_qos_add_request(&hdd_ctx->pm_qos_req, PM_QOS_DEFAULT_VALUE); + DUMP_CPU_AFFINE(); +} + +static inline void hdd_pm_qos_remove_request(struct hdd_context *hdd_ctx) +{ + cpu_latency_qos_remove_request(&hdd_ctx->pm_qos_req); +} +#else +static inline void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx, + cpumask_t *pm_qos_cpu_mask) +{ + COPY_CPU_MASK(&hdd_ctx->pm_qos_req.cpus_affine, pm_qos_cpu_mask); + + if (cpumask_empty(pm_qos_cpu_mask)) + pm_qos_update_request(&hdd_ctx->pm_qos_req, + PM_QOS_DEFAULT_VALUE); + else + pm_qos_update_request(&hdd_ctx->pm_qos_req, 1); +} + +static inline void hdd_pm_qos_add_request(struct hdd_context *hdd_ctx) +{ + hdd_set_default_pm_qos_mask(hdd_ctx); + pm_qos_add_request(&hdd_ctx->pm_qos_req, PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + DUMP_CPU_AFFINE(); +} + +static inline void hdd_pm_qos_remove_request(struct hdd_context *hdd_ctx) +{ + pm_qos_remove_request(&hdd_ctx->pm_qos_req); +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) */ +#endif /* CLD_DEV_PM_QOS */ + +#else /* CLD_PM_QOS */ +#define PLD_REMOVE_PM_QOS(x) pld_remove_pm_qos(x) +#define PLD_REQUEST_PM_QOS(x, y) pld_request_pm_qos(x, y) + +static inline void hdd_pm_qos_add_request(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_pm_qos_remove_request(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_pm_qos_update_cpu_mask(cpumask_t *mask, + bool high_throughput) +{ +} + +static inline void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx, + cpumask_t *pm_qos_cpu_mask) +{ +} +#endif /* CLD_PM_QOS */ + +#if defined(CLD_PM_QOS) +#if defined(CLD_DEV_PM_QOS) +void wlan_hdd_set_pm_qos_request(struct hdd_context *hdd_ctx, + bool pm_qos_request) +{ + cpumask_t pm_qos_cpu_mask; + + cpumask_clear(&pm_qos_cpu_mask); + if (pm_qos_request) { + hdd_ctx->pm_qos_request = true; + if (!hdd_ctx->hbw_requested) { + hdd_pm_qos_update_cpu_mask(&pm_qos_cpu_mask, true); + hdd_pm_qos_update_request(hdd_ctx, &pm_qos_cpu_mask); + hdd_ctx->hbw_requested = true; + } + } else { + if (hdd_ctx->hbw_requested) { + hdd_pm_qos_update_cpu_mask(&pm_qos_cpu_mask, false); + hdd_pm_qos_update_request(hdd_ctx, &pm_qos_cpu_mask); + hdd_ctx->hbw_requested = false; + } + hdd_ctx->pm_qos_request = false; + } +} +#else /* CLD_DEV_PM_QOS */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) +void wlan_hdd_set_pm_qos_request(struct hdd_context *hdd_ctx, + bool pm_qos_request) +{ + if (pm_qos_request) { + hdd_ctx->pm_qos_request = true; + if (!hdd_ctx->hbw_requested) { + cpumask_setall(&hdd_ctx->pm_qos_req.cpus_affine); + cpu_latency_qos_update_request( + &hdd_ctx->pm_qos_req, + DISABLE_KRAIT_IDLE_PS_VAL); + hdd_ctx->hbw_requested = true; + } + } else { + if (hdd_ctx->hbw_requested) { + cpumask_clear(&hdd_ctx->pm_qos_req.cpus_affine); + cpu_latency_qos_update_request(&hdd_ctx->pm_qos_req, + PM_QOS_DEFAULT_VALUE); + hdd_ctx->hbw_requested = false; + } + hdd_ctx->pm_qos_request = false; + } +} +#else /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) */ +void wlan_hdd_set_pm_qos_request(struct hdd_context *hdd_ctx, + bool pm_qos_request) +{ + if (pm_qos_request) { + hdd_ctx->pm_qos_request = true; + if (!hdd_ctx->hbw_requested) { + cpumask_setall(&hdd_ctx->pm_qos_req.cpus_affine); + pm_qos_update_request(&hdd_ctx->pm_qos_req, + DISABLE_KRAIT_IDLE_PS_VAL); + hdd_ctx->hbw_requested = true; + } + } else { + if (hdd_ctx->hbw_requested) { + cpumask_clear(&hdd_ctx->pm_qos_req.cpus_affine); + pm_qos_update_request(&hdd_ctx->pm_qos_req, + PM_QOS_DEFAULT_VALUE); + hdd_ctx->hbw_requested = false; + } + hdd_ctx->pm_qos_request = false; + } +} +#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0)) */ +#endif /* CLD_DEV_PM_QOS*/ +#endif /* CLD_PM_QOS */ + +#define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1) + +#ifdef WLAN_FEATURE_MSCS + +static +void hdd_send_mscs_action_frame(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + uint64_t mscs_vo_pkt_delta; + unsigned long tx_vo_pkts = 0; + unsigned int cpu; + struct hdd_tx_rx_stats *stats = &link_info->hdd_stats.tx_rx_stats; + uint32_t bus_bw_compute_interval; + + /* + * To disable MSCS feature in driver set mscs_pkt_threshold = 0 + * in ini file. + */ + if (!hdd_ctx->config->mscs_pkt_threshold) + return; + + for (cpu = 0; cpu < NUM_CPUS; cpu++) + tx_vo_pkts += stats->per_cpu[cpu].tx_classified_ac[SME_AC_VO]; + + if (!link_info->mscs_counter) + link_info->mscs_prev_tx_vo_pkts = tx_vo_pkts; + + link_info->mscs_counter++; + bus_bw_compute_interval = + ucfg_dp_get_bus_bw_compute_interval(hdd_ctx->psoc); + if (link_info->mscs_counter * bus_bw_compute_interval >= + hdd_ctx->config->mscs_voice_interval * 1000) { + link_info->mscs_counter = 0; + mscs_vo_pkt_delta = + HDD_BW_GET_DIFF(tx_vo_pkts, + link_info->mscs_prev_tx_vo_pkts); + if (mscs_vo_pkt_delta > hdd_ctx->config->mscs_pkt_threshold && + !mlme_get_is_mscs_req_sent(link_info->vdev)) + sme_send_mscs_action_frame(link_info->vdev_id); + } +} +#else +static inline +void hdd_send_mscs_action_frame(struct wlan_hdd_link_info *link_info) +{ +} +#endif +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + +/** + * wlan_hdd_sta_get_dot11mode() - GET AP client count + * @context: HDD context + * @netdev: netdev + * @dot11_mode: variable in which mode need to update. + * + * Return: true on success else false + */ +static inline +bool wlan_hdd_sta_get_dot11mode(hdd_cb_handle context, qdf_netdev_t netdev, + enum qca_wlan_802_11_mode *dot11_mode) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + struct hdd_adapter *adapter; + enum csr_cfgdot11mode mode; + + hdd_ctx = hdd_cb_handle_to_context(context); + if (!hdd_ctx) + return false; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) + return false; + + link_info = adapter->deflink; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + mode = sta_ctx->conn_info.dot11mode; + *dot11_mode = hdd_convert_cfgdot11mode_to_80211mode(mode); + return true; +} + +/** + * wlan_hdd_get_ap_client_count() - GET AP client count + * @context: HDD context + * @netdev: netdev + * @client_count: variable in which number of client need to update. + * + * Return: true on success else false + */ +static inline +bool wlan_hdd_get_ap_client_count(hdd_cb_handle context, qdf_netdev_t netdev, + uint16_t *client_count) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + struct hdd_adapter *adapter; + struct hdd_ap_ctx *ap_ctx; + enum qca_wlan_802_11_mode i; + + hdd_ctx = hdd_cb_handle_to_context(context); + if (!hdd_ctx) { + hdd_err("hdd ctx is null"); + return false; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return false; + } + + link_info = adapter->deflink; + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (!ap_ctx->ap_active) + return false; + + for (i = QCA_WLAN_802_11_MODE_11B; i < QCA_WLAN_802_11_MODE_INVALID; + i++) + client_count[i] = ap_ctx->client_count[i]; + + return true; +} + +/** + * wlan_hdd_sta_ndi_connected() - Check if NDI connected + * @context: HDD context + * @netdev: netdev + * + * Return: true if NDI connected else false + */ +static inline +bool wlan_hdd_sta_ndi_connected(hdd_cb_handle context, qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + hdd_ctx = hdd_cb_handle_to_context(context); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return false; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return false; + } + + link_info = adapter->deflink; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (sta_ctx->conn_info.conn_state != eConnectionState_NdiConnected) + return false; + + return true; +} + +/** + * wlan_hdd_pktlog_enable_disable() - Enable/Disable packet logging + * @context: HDD context + * @enable_disable_flag: Flag to enable/disable + * @user_triggered: triggered through iwpriv + * @size: buffer size to be used for packetlog + * + * Return: 0 on success; error number otherwise + */ +static inline +int wlan_hdd_pktlog_enable_disable(hdd_cb_handle context, + bool enable_disable_flag, + uint8_t user_triggered, int size) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return -EINVAL; + } + return hdd_pktlog_enable_disable(hdd_ctx, enable_disable_flag, + user_triggered, size); +} + +/** + * wlan_hdd_is_roaming_in_progress() - Check if roaming is in progress + * @context: HDD context + * + * Return: true if roaming is in progress else false + */ +static inline bool wlan_hdd_is_roaming_in_progress(hdd_cb_handle context) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return false; + } + return hdd_is_roaming_in_progress(hdd_ctx); +} + +/** + * hdd_is_ap_active() - Check if AP is active + * @context: HDD context + * @netdev: netdev + * + * Return: true if AP active else false + */ +static inline bool hdd_is_ap_active(hdd_cb_handle context, qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = hdd_cb_handle_to_context(context); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return false; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return false; + } + + link_info = adapter->deflink; + return WLAN_HDD_GET_AP_CTX_PTR(link_info)->ap_active; +} + +/** + * wlan_hdd_napi_apply_throughput_policy() - Apply NAPI policy + * @context: HDD context + * @tx_packets: tx_packets + * @rx_packets: rx_packets + * + * Return: 0 on success else error code + */ +static inline +int wlan_hdd_napi_apply_throughput_policy(hdd_cb_handle context, + uint64_t tx_packets, + uint64_t rx_packets) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + int rc = 0; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return 0; + } + if (hdd_ctx->config->napi_cpu_affinity_mask) + rc = hdd_napi_apply_throughput_policy(hdd_ctx, tx_packets, + rx_packets); + return rc; +} + +/** + * hdd_is_link_adapter() - Check if adapter is link adapter + * @context: HDD context + * @vdev_id: Vdev ID + * + * Return: true if link adapter else false + */ +static inline bool hdd_is_link_adapter(hdd_cb_handle context, uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = hdd_cb_handle_to_context(context); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return false; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return false; + } + return hdd_adapter_is_link_adapter(link_info->adapter); +} + +/** + * hdd_get_pause_map() - Get pause map value + * @context: HDD context + * @netdev: netdev + * + * Return: pause map value + */ +static inline +uint32_t hdd_get_pause_map(hdd_cb_handle context, qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return 0; + } + + return adapter->pause_map; +} + +/** + * hdd_any_adapter_connected() - Check if any adapter connected. + * @context: HDD context + * + * Return: True if connected else false. + */ +static inline bool hdd_any_adapter_connected(hdd_cb_handle context) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return false; + } + + return hdd_is_any_adapter_connected(hdd_ctx); +} + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +/** + * hdd_pld_request_pm_qos() - Request PLD PM QoS request + * @context: HDD context + * + * Return: None + */ +static inline void hdd_pld_request_pm_qos(hdd_cb_handle context) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + if (!hdd_ctx->hbw_requested) { + PLD_REQUEST_PM_QOS(hdd_ctx->parent_dev, 1); + hdd_ctx->hbw_requested = true; + } +} + +/** + * hdd_pld_remove_pm_qos() - Remove PLD PM QoS request + * @context: HDD context + * + * Return: None + */ +static inline void hdd_pld_remove_pm_qos(hdd_cb_handle context) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + if (hdd_ctx->hbw_requested && + !hdd_ctx->pm_qos_request) { + PLD_REMOVE_PM_QOS(hdd_ctx->parent_dev); + hdd_ctx->hbw_requested = false; + } +} + +/** + * wlan_hdd_pm_qos_update_request() - Update PM QoS request + * @context: HDD context + * @pm_qos_cpu_mask: CPU mask + * + * Return: None + */ +static inline void +wlan_hdd_pm_qos_update_request(hdd_cb_handle context, + cpumask_t *pm_qos_cpu_mask) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + if (!hdd_ctx->pm_qos_request) + hdd_pm_qos_update_request(hdd_ctx, pm_qos_cpu_mask); +} + +/** + * wlan_hdd_pm_qos_add_request() - Add PM QoS request + * @context: HDD context + * + * Return: None + */ +static inline void wlan_hdd_pm_qos_add_request(hdd_cb_handle context) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + hdd_pm_qos_add_request(hdd_ctx); +} + +/** + * wlan_hdd_pm_qos_remove_request() - remove PM QoS request + * @context: HDD context + * + * Return: None + */ +static inline void wlan_hdd_pm_qos_remove_request(hdd_cb_handle context) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + hdd_pm_qos_remove_request(hdd_ctx); +} + +/** + * wlan_hdd_send_mscs_action_frame() - Send MSCS action frame + * @context: HDD context + * @netdev: netdev + * + * Return: None + */ +static inline void wlan_hdd_send_mscs_action_frame(hdd_cb_handle context, + qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + link_info = adapter->deflink; + hdd_send_mscs_action_frame(link_info); +} + +#else +static inline void hdd_pld_remove_pm_qos(hdd_cb_handle context) +{ +} + +static inline void hdd_pld_request_pm_qos(hdd_cb_handle context) +{ +} + +static inline void +wlan_hdd_pm_qos_update_request(hdd_cb_handle context, + cpumask_t *pm_qos_cpu_mask) +{ +} + +static inline void wlan_hdd_pm_qos_add_request(hdd_cb_handle context) +{ +} + +static inline void wlan_hdd_pm_qos_remove_request(hdd_cb_handle context) +{ +} + +static inline void wlan_hdd_send_mscs_action_frame(hdd_cb_handle context, + qdf_netdev_t netdev) +{ +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && \ +defined(FEATURE_RX_LINKSPEED_ROAM_TRIGGER) +void wlan_hdd_link_speed_update(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool is_link_speed_good) +{ + ucfg_cm_roam_link_speed_update(psoc, vdev_id, is_link_speed_good); +} +#endif + +/** + * hdd_dp_register_callbacks() - Register DP callbacks with HDD + * @hdd_ctx: HDD context + * + * Return: None + */ +static void hdd_dp_register_callbacks(struct hdd_context *hdd_ctx) +{ + struct wlan_dp_psoc_callbacks cb_obj = {0}; + + cb_obj.callback_ctx = (hdd_cb_handle)hdd_ctx; + cb_obj.wlan_dp_sta_get_dot11mode = wlan_hdd_sta_get_dot11mode; + cb_obj.wlan_dp_get_ap_client_count = wlan_hdd_get_ap_client_count; + cb_obj.wlan_dp_sta_ndi_connected = wlan_hdd_sta_ndi_connected; + cb_obj.dp_any_adapter_connected = hdd_any_adapter_connected; + cb_obj.dp_send_svc_nlink_msg = wlan_hdd_send_svc_nlink_msg; + cb_obj.dp_pld_remove_pm_qos = hdd_pld_remove_pm_qos; + cb_obj.dp_pld_request_pm_qos = hdd_pld_request_pm_qos; + cb_obj.dp_pktlog_enable_disable = wlan_hdd_pktlog_enable_disable; + cb_obj.dp_pm_qos_update_request = wlan_hdd_pm_qos_update_request; + cb_obj.dp_pm_qos_add_request = wlan_hdd_pm_qos_add_request; + cb_obj.dp_pm_qos_remove_request = wlan_hdd_pm_qos_remove_request; + cb_obj.dp_send_mscs_action_frame = wlan_hdd_send_mscs_action_frame; + cb_obj.dp_is_roaming_in_progress = wlan_hdd_is_roaming_in_progress; + cb_obj.wlan_dp_display_tx_multiq_stats = + wlan_hdd_display_tx_multiq_stats; + cb_obj.wlan_dp_display_netif_queue_history = + wlan_hdd_display_netif_queue_history; + cb_obj.dp_is_ap_active = hdd_is_ap_active; + cb_obj.dp_napi_apply_throughput_policy = + wlan_hdd_napi_apply_throughput_policy; + cb_obj.dp_is_link_adapter = hdd_is_link_adapter; + cb_obj.dp_nud_failure_work = hdd_nud_failure_work; + cb_obj.dp_get_pause_map = hdd_get_pause_map; + + cb_obj.dp_get_netdev_by_vdev_mac = + hdd_get_netdev_by_vdev_mac; + cb_obj.dp_get_tx_resource = hdd_get_tx_resource; + cb_obj.dp_get_tx_flow_low_watermark = hdd_get_tx_flow_low_watermark; + cb_obj.dp_get_tsf_time = hdd_get_tsf_time_cb; + cb_obj.dp_tsf_timestamp_rx = hdd_tsf_timestamp_rx; + cb_obj.dp_gro_rx_legacy_get_napi = hdd_legacy_gro_get_napi; + cb_obj.link_monitoring_cb = wlan_hdd_link_speed_update; + + os_if_dp_register_hdd_callbacks(hdd_ctx->psoc, &cb_obj); +} + +/** + * __hdd_adapter_param_update_work() - Gist of the work to process + * netdev feature update. + * @adapter: pointer to adapter structure + * + * This function assumes that the adapter pointer is always valid. + * So the caller should always validate adapter pointer before calling + * this function + * + * Returns: None + */ +static inline void +__hdd_adapter_param_update_work(struct hdd_adapter *adapter) +{ + /** + * This check is needed in case the work got scheduled after the + * interface got disconnected. + * Netdev features update is to be done only after the connection, + * since the connection mode plays an important role in identifying + * the features that are to be updated. + * So in case of interface disconnect skip feature update. + */ + if (!hdd_cm_is_vdev_associated(adapter->deflink)) + return; + + hdd_netdev_update_features(adapter); +} + +/** + * hdd_adapter_param_update_work() - work to process the netdev features + * update. + * @arg: private data passed to work + * + * Returns: None + */ +static void hdd_adapter_param_update_work(void *arg) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct hdd_adapter *adapter = arg; + struct osif_vdev_sync *vdev_sync; + int errno; + + if (!hdd_ctx) + return; + + hdd_adapter_ops_record_event(hdd_ctx, + WLAN_HDD_ADAPTER_OPS_WORK_SCHED, + WLAN_INVALID_VDEV_ID); + + if (hdd_validate_adapter(adapter)) + return; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return; + + __hdd_adapter_param_update_work(adapter); + + osif_vdev_sync_op_stop(vdev_sync); +} + +QDF_STATUS hdd_init_adapter_ops_wq(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + hdd_ctx->adapter_ops_wq = + qdf_alloc_high_prior_ordered_workqueue("hdd_adapter_ops_wq"); + if (!hdd_ctx->adapter_ops_wq) + return QDF_STATUS_E_NOMEM; + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +void hdd_deinit_adapter_ops_wq(struct hdd_context *hdd_ctx) +{ + hdd_enter(); + + qdf_flush_workqueue(0, hdd_ctx->adapter_ops_wq); + qdf_destroy_workqueue(0, hdd_ctx->adapter_ops_wq); + + hdd_exit(); +} + +QDF_STATUS hdd_adapter_feature_update_work_init(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + + hdd_enter(); + + status = qdf_create_work(0, &adapter->netdev_features_update_work, + hdd_adapter_param_update_work, adapter); + adapter->netdev_features_update_work_status = HDD_WORK_INITIALIZED; + + hdd_exit(); + + return status; +} + +void hdd_adapter_feature_update_work_deinit(struct hdd_adapter *adapter) +{ + hdd_enter(); + + if (adapter->netdev_features_update_work_status != + HDD_WORK_INITIALIZED) { + hdd_debug("work not yet init"); + return; + } + qdf_cancel_work(&adapter->netdev_features_update_work); + qdf_flush_work(&adapter->netdev_features_update_work); + adapter->netdev_features_update_work_status = HDD_WORK_UNINITIALIZED; + + hdd_exit(); +} + +#define HDD_DUMP_STAT_HELP(STAT_ID) \ + hdd_nofl_debug("%u -- %s", STAT_ID, (# STAT_ID)) +/** + * hdd_display_stats_help() - print statistics help + * + * Return: none + */ +static void hdd_display_stats_help(void) +{ + hdd_nofl_debug("iwpriv wlan0 dumpStats [option] - dump statistics"); + hdd_nofl_debug("iwpriv wlan0 clearStats [option] - clear statistics"); + hdd_nofl_debug("options:"); + HDD_DUMP_STAT_HELP(CDP_TXRX_PATH_STATS); + HDD_DUMP_STAT_HELP(CDP_TXRX_HIST_STATS); + HDD_DUMP_STAT_HELP(CDP_TXRX_TSO_STATS); + HDD_DUMP_STAT_HELP(CDP_HDD_NETIF_OPER_HISTORY); + HDD_DUMP_STAT_HELP(CDP_DUMP_TX_FLOW_POOL_INFO); + HDD_DUMP_STAT_HELP(CDP_TXRX_DESC_STATS); + HDD_DUMP_STAT_HELP(CDP_HIF_STATS); + HDD_DUMP_STAT_HELP(CDP_NAPI_STATS); + HDD_DUMP_STAT_HELP(CDP_DP_NAPI_STATS); + HDD_DUMP_STAT_HELP(CDP_DP_RX_THREAD_STATS); +} + +int hdd_wlan_dump_stats(struct hdd_adapter *adapter, int stats_id) +{ + int ret = 0; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_debug("stats_id %d", stats_id); + + switch (stats_id) { + case CDP_TXRX_HIST_STATS: + ucfg_wlan_dp_display_tx_rx_histogram(hdd_ctx->psoc); + break; + case CDP_HDD_NETIF_OPER_HISTORY: + wlan_hdd_display_adapter_netif_queue_history(adapter); + break; + case CDP_HIF_STATS: + hdd_display_hif_stats(); + break; + case CDP_NAPI_STATS: + if (hdd_display_napi_stats()) { + hdd_err("error displaying napi stats"); + ret = -EFAULT; + } + break; + case CDP_DP_RX_THREAD_STATS: + ucfg_dp_txrx_ext_dump_stats(cds_get_context(QDF_MODULE_ID_SOC), + CDP_DP_RX_THREAD_STATS); + break; + case CDP_DISCONNECT_STATS: + sme_display_disconnect_stats(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + break; + default: + status = cdp_display_stats(cds_get_context(QDF_MODULE_ID_SOC), + stats_id, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + if (status == QDF_STATUS_E_INVAL) { + hdd_display_stats_help(); + ret = -EINVAL; + } + break; + } + return ret; +} + +int hdd_wlan_clear_stats(struct hdd_adapter *adapter, int stats_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + hdd_debug("stats_id %d", stats_id); + + switch (stats_id) { + case CDP_HDD_STATS: + ucfg_dp_clear_net_dev_stats(adapter->dev); + memset(&adapter->deflink->hdd_stats, 0, + sizeof(adapter->deflink->hdd_stats)); + break; + case CDP_TXRX_HIST_STATS: + ucfg_wlan_dp_clear_tx_rx_histogram(adapter->hdd_ctx->psoc); + break; + case CDP_HDD_NETIF_OPER_HISTORY: + wlan_hdd_clear_netif_queue_history(adapter->hdd_ctx); + break; + case CDP_HIF_STATS: + hdd_clear_hif_stats(); + break; + case CDP_NAPI_STATS: + hdd_clear_napi_stats(); + break; + default: + status = cdp_clear_stats(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, + stats_id); + if (status != QDF_STATUS_SUCCESS) + hdd_debug("Failed to dump stats for stats_id: %d", + stats_id); + break; + } + + return qdf_status_to_os_return(status); +} + +/* length of the netif queue log needed per adapter */ +#define ADAP_NETIFQ_LOG_LEN ((20 * WLAN_REASON_TYPE_MAX) + 50) + +/** + * hdd_display_netif_queue_history_compact() - display compact netifq history + * @hdd_ctx: hdd context + * + * Return: none + */ +static void +hdd_display_netif_queue_history_compact(struct hdd_context *hdd_ctx) +{ + int adapter_num = 0; + int i; + int bytes_written; + u32 tbytes; + qdf_time_t total, pause, unpause, curr_time, delta; + char temp_str[20 * WLAN_REASON_TYPE_MAX]; + char *comb_log_str; + uint32_t comb_log_str_size; + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_DISPLAY_NETIF_QUEUE_HISTORY_COMPACT; + + comb_log_str_size = (ADAP_NETIFQ_LOG_LEN * WLAN_MAX_VDEVS) + 1; + comb_log_str = qdf_mem_malloc(comb_log_str_size); + if (!comb_log_str) + return; + + bytes_written = 0; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + curr_time = qdf_system_ticks(); + total = curr_time - adapter->start_time; + delta = curr_time - adapter->last_time; + + if (adapter->pause_map) { + pause = adapter->total_pause_time + delta; + unpause = adapter->total_unpause_time; + } else { + unpause = adapter->total_unpause_time + delta; + pause = adapter->total_pause_time; + } + + tbytes = 0; + qdf_mem_zero(temp_str, sizeof(temp_str)); + for (i = WLAN_CONTROL_PATH; i < WLAN_REASON_TYPE_MAX; i++) { + if (adapter->queue_oper_stats[i].pause_count == 0) + continue; + tbytes += + snprintf( + &temp_str[tbytes], + (tbytes >= sizeof(temp_str) ? + 0 : sizeof(temp_str) - tbytes), + "%d(%d,%d) ", + i, + adapter->queue_oper_stats[i]. + pause_count, + adapter->queue_oper_stats[i]. + unpause_count); + } + if (tbytes >= sizeof(temp_str)) + hdd_warn("log truncated"); + + bytes_written += snprintf(&comb_log_str[bytes_written], + bytes_written >= comb_log_str_size ? 0 : + comb_log_str_size - bytes_written, + "[%d %d] (%d) %u/%ums %s|", + adapter->deflink->vdev_id, adapter->device_mode, + adapter->pause_map, + qdf_system_ticks_to_msecs(pause), + qdf_system_ticks_to_msecs(total), + temp_str); + + adapter_num++; + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + /* using QDF_TRACE to avoid printing function name */ + QDF_TRACE(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_INFO_LOW, + "STATS |%s", comb_log_str); + + if (bytes_written >= comb_log_str_size) + hdd_warn("log string truncated"); + + qdf_mem_free(comb_log_str); +} + +/* Max size of a single netdev tx queue state string. e.g. "1: 0x1" */ +#define HDD_NETDEV_TX_Q_STATE_STRLEN 15 +/** + * wlan_hdd_display_adapter_netif_queue_stats() - display adapter based + * netif queue stats + * @adapter: hdd adapter + * + * Return: none + */ +static void +wlan_hdd_display_adapter_netif_queue_stats(struct hdd_adapter *adapter) +{ + int i; + qdf_time_t total, pause, unpause, curr_time, delta; + struct hdd_netif_queue_history *q_hist_ptr; + char q_status_buf[NUM_TX_QUEUES * HDD_NETDEV_TX_Q_STATE_STRLEN] = {0}; + + hdd_nofl_debug("Netif queue operation statistics:"); + hdd_nofl_debug("vdev_id %d device mode %d", + adapter->deflink->vdev_id, adapter->device_mode); + hdd_nofl_debug("Current pause_map %x", adapter->pause_map); + curr_time = qdf_system_ticks(); + total = curr_time - adapter->start_time; + delta = curr_time - adapter->last_time; + if (adapter->pause_map) { + pause = adapter->total_pause_time + delta; + unpause = adapter->total_unpause_time; + } else { + unpause = adapter->total_unpause_time + delta; + pause = adapter->total_pause_time; + } + hdd_nofl_debug("Total: %ums Pause: %ums Unpause: %ums", + qdf_system_ticks_to_msecs(total), + qdf_system_ticks_to_msecs(pause), + qdf_system_ticks_to_msecs(unpause)); + hdd_nofl_debug("reason_type: pause_cnt: unpause_cnt: pause_time"); + + for (i = WLAN_CONTROL_PATH; i < WLAN_REASON_TYPE_MAX; i++) { + qdf_time_t pause_delta = 0; + + if (adapter->pause_map & (1 << i)) + pause_delta = delta; + + /* using hdd_log to avoid printing function name */ + hdd_nofl_debug("%s: %d: %d: %ums", + hdd_reason_type_to_string(i), + adapter->queue_oper_stats[i].pause_count, + adapter->queue_oper_stats[i]. + unpause_count, + qdf_system_ticks_to_msecs( + adapter->queue_oper_stats[i]. + total_pause_time + pause_delta)); + } + + hdd_nofl_debug("Netif queue operation history: Total entries: %d current index %d(-1) time %u", + WLAN_HDD_MAX_HISTORY_ENTRY, + adapter->history_index, + qdf_system_ticks_to_msecs(qdf_system_ticks())); + + hdd_nofl_debug("%2s%20s%50s%30s%10s %s", + "#", "time(ms)", "action_type", "reason_type", + "pause_map", "netdev-queue-status"); + + for (i = 0; i < WLAN_HDD_MAX_HISTORY_ENTRY; i++) { + /* using hdd_log to avoid printing function name */ + if (adapter->queue_oper_history[i].time == 0) + continue; + q_hist_ptr = &adapter->queue_oper_history[i]; + wlan_hdd_dump_queue_history_state(q_hist_ptr, + q_status_buf, + sizeof(q_status_buf)); + hdd_nofl_debug("%2d%20u%50s%30s%10x %s", + i, qdf_system_ticks_to_msecs( + adapter->queue_oper_history[i].time), + hdd_action_type_to_string( + adapter->queue_oper_history[i]. + netif_action), + hdd_reason_type_to_string( + adapter->queue_oper_history[i]. + netif_reason), + adapter->queue_oper_history[i].pause_map, + q_status_buf); + } +} + +void +wlan_hdd_display_adapter_netif_queue_history(struct hdd_adapter *adapter) +{ + wlan_hdd_display_adapter_netif_queue_stats(adapter); +} + +/** + * wlan_hdd_display_netif_queue_history() - display netif queue history + * @context: hdd context + * @verb_lvl: verbosity level + * + * Return: none + */ +void +wlan_hdd_display_netif_queue_history(hdd_cb_handle context, + enum qdf_stats_verbosity_level verb_lvl) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(context); + wlan_net_dev_ref_dbgid dbgid = + NET_DEV_HOLD_DISPLAY_NETIF_QUEUE_HISTORY; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return; + } + + if (verb_lvl == QDF_STATS_VERBOSITY_LEVEL_LOW) { + hdd_display_netif_queue_history_compact(hdd_ctx); + return; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->deflink->vdev_id == CDP_INVALID_VDEV_ID) { + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + wlan_hdd_display_adapter_netif_queue_stats(adapter); + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +/** + * wlan_hdd_clear_netif_queue_history() - clear netif queue operation history + * @hdd_ctx: hdd context + * + * Return: none + */ +void wlan_hdd_clear_netif_queue_history(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_CLEAR_NETIF_QUEUE_HISTORY; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + qdf_mem_zero(adapter->queue_oper_stats, + sizeof(adapter->queue_oper_stats)); + qdf_mem_zero(adapter->queue_oper_history, + sizeof(adapter->queue_oper_history)); + adapter->history_index = 0; + adapter->start_time = adapter->last_time = qdf_system_ticks(); + adapter->total_pause_time = 0; + adapter->total_unpause_time = 0; + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +#ifdef WLAN_FEATURE_OFFLOAD_PACKETS +/** + * hdd_init_offloaded_packets_ctx() - Initialize offload packets context + * @hdd_ctx: hdd global context + * + * Return: none + */ +static void hdd_init_offloaded_packets_ctx(struct hdd_context *hdd_ctx) +{ + uint8_t i; + + mutex_init(&hdd_ctx->op_ctx.op_lock); + for (i = 0; i < MAXNUM_PERIODIC_TX_PTRNS; i++) { + hdd_ctx->op_ctx.op_table[i].request_id = MAX_REQUEST_ID; + hdd_ctx->op_ctx.op_table[i].pattern_id = i; + } +} +#else +static void hdd_init_offloaded_packets_ctx(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef WLAN_FEATURE_WOW_PULSE +/** + * wlan_hdd_set_wow_pulse() - call SME to send wmi cmd of wow pulse + * @hdd_ctx: struct hdd_context structure pointer + * @enable: enable or disable this behaviour + * + * Return: int + */ +static int wlan_hdd_set_wow_pulse(struct hdd_context *hdd_ctx, bool enable) +{ + struct wow_pulse_mode wow_pulse_set_info; + QDF_STATUS status; + + hdd_debug("wow pulse enable flag is %d", enable); + + if (!ucfg_pmo_is_wow_pulse_enabled(hdd_ctx->psoc)) + return 0; + + /* prepare the request to send to SME */ + if (enable == true) { + wow_pulse_set_info.wow_pulse_enable = true; + wow_pulse_set_info.wow_pulse_pin = + ucfg_pmo_get_wow_pulse_pin(hdd_ctx->psoc); + + wow_pulse_set_info.wow_pulse_interval_high = + ucfg_pmo_get_wow_pulse_interval_high(hdd_ctx->psoc); + + wow_pulse_set_info.wow_pulse_interval_low = + ucfg_pmo_get_wow_pulse_interval_low(hdd_ctx->psoc); + + wow_pulse_set_info.wow_pulse_repeat_count = + ucfg_pmo_get_wow_pulse_repeat_count(hdd_ctx->psoc); + + wow_pulse_set_info.wow_pulse_init_state = + ucfg_pmo_get_wow_pulse_init_state(hdd_ctx->psoc); + } else { + wow_pulse_set_info.wow_pulse_enable = false; + wow_pulse_set_info.wow_pulse_pin = 0; + wow_pulse_set_info.wow_pulse_interval_low = 0; + wow_pulse_set_info.wow_pulse_interval_high = 0; + wow_pulse_set_info.wow_pulse_repeat_count = 0; + wow_pulse_set_info.wow_pulse_init_state = 0; + } + hdd_debug("enable %d pin %d low %d high %d count %d init %d", + wow_pulse_set_info.wow_pulse_enable, + wow_pulse_set_info.wow_pulse_pin, + wow_pulse_set_info.wow_pulse_interval_low, + wow_pulse_set_info.wow_pulse_interval_high, + wow_pulse_set_info.wow_pulse_repeat_count, + wow_pulse_set_info.wow_pulse_init_state); + + status = sme_set_wow_pulse(&wow_pulse_set_info); + if (QDF_STATUS_E_FAILURE == status) { + hdd_debug("sme_set_wow_pulse failure!"); + return -EIO; + } + hdd_debug("sme_set_wow_pulse success!"); + return 0; +} +#else +static inline int wlan_hdd_set_wow_pulse(struct hdd_context *hdd_ctx, bool enable) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_FASTPATH + +/** + * hdd_enable_fastpath() - Enable fastpath if enabled in config INI + * @hdd_ctx: hdd context + * @context: lower layer context + * + * Return: none + */ +void hdd_enable_fastpath(struct hdd_context *hdd_ctx, + void *context) +{ + if (cfg_get(hdd_ctx->psoc, CFG_DP_ENABLE_FASTPATH)) + hif_enable_fastpath(context); +} +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) +/** + * hdd_set_thermal_level_cb() - set thermal level callback function + * @hdd_handle: opaque handle for the hdd context + * @level: thermal level + * + * Change IPA data path to SW path when the thermal throttle level greater + * than 0, and restore the original data path when throttle level is 0 + * + * Return: none + */ +static void hdd_set_thermal_level_cb(hdd_handle_t hdd_handle, u_int8_t level) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + + /* Change IPA to SW path when throttle level greater than 0 */ + if (level > THROTTLE_LEVEL_0) + ucfg_ipa_send_mcc_scc_msg(hdd_ctx->pdev, true); + else + /* restore original concurrency mode */ + ucfg_ipa_send_mcc_scc_msg(hdd_ctx->pdev, hdd_ctx->mcc_mode); +} +#else +/** + * hdd_set_thermal_level_cb() - set thermal level callback function + * @hdd_handle: opaque handle for the hdd context + * @level: thermal level + * + * Change IPA data path to SW path when the thermal throttle level greater + * than 0, and restore the original data path when throttle level is 0 + * + * Return: none + */ +static void hdd_set_thermal_level_cb(hdd_handle_t hdd_handle, u_int8_t level) +{ +} +#endif + +QDF_STATUS hdd_switch_sap_channel(struct wlan_hdd_link_info *link_info, + uint8_t channel, bool forced) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle; + struct sap_config *sap_cfg; + qdf_freq_t freq; + + mac_handle = hdd_adapter_get_mac_handle(link_info->adapter); + if (!mac_handle) { + hdd_err("invalid MAC handle"); + return QDF_STATUS_E_INVAL; + } + + freq = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, channel); + sap_cfg = &(WLAN_HDD_GET_AP_CTX_PTR(link_info)->sap_config); + hdd_debug("chan:%d width:%d", channel, sap_cfg->ch_width_orig); + + return policy_mgr_change_sap_channel_with_csa(hdd_ctx->psoc, + link_info->vdev_id, freq, + sap_cfg->ch_width_orig, + forced); +} + +QDF_STATUS hdd_switch_sap_chan_freq(struct hdd_adapter *adapter, + qdf_freq_t chan_freq, + enum phy_ch_width ch_width, + bool forced) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_context *hdd_ctx; + + if (hdd_validate_adapter(adapter)) + return QDF_STATUS_E_INVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if(wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_INVAL; + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + + hdd_debug("chan freq:%d width:%d org bw %d", + chan_freq, ch_width, hdd_ap_ctx->sap_config.ch_width_orig); + + return policy_mgr_change_sap_channel_with_csa(hdd_ctx->psoc, + adapter->deflink->vdev_id, + chan_freq, + ch_width, + forced); +} + +int hdd_update_acs_timer_reason(struct hdd_adapter *adapter, uint8_t reason) +{ + struct hdd_external_acs_timer_context *timer_context; + int status; + QDF_STATUS qdf_status; + qdf_mc_timer_t *vendor_acs_timer; + + set_bit(VENDOR_ACS_RESPONSE_PENDING, &adapter->deflink->link_flags); + + vendor_acs_timer = &adapter->deflink->session.ap.vendor_acs_timer; + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(vendor_acs_timer)) { + qdf_mc_timer_stop(vendor_acs_timer); + } + timer_context = + (struct hdd_external_acs_timer_context *)vendor_acs_timer->user_data; + timer_context->reason = reason; + qdf_status = + qdf_mc_timer_start(vendor_acs_timer, WLAN_VENDOR_ACS_WAIT_TIME); + if (qdf_status != QDF_STATUS_SUCCESS) { + hdd_err("failed to start external acs timer"); + return -ENOSPC; + } + /* Update config to application */ + status = hdd_cfg80211_update_acs_config(adapter, reason); + hdd_info("Updated ACS config to nl with reason %d", reason); + + return status; +} + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +uint32_t wlan_hdd_get_restriction_mask(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->restriction_mask; +} + +void wlan_hdd_set_restriction_mask(struct hdd_context *hdd_ctx) +{ + hdd_ctx->restriction_mask = + hdd_ctx->coex_avoid_freq_list.restriction_mask; +} +#else +uint32_t wlan_hdd_get_restriction_mask(struct hdd_context *hdd_ctx) +{ + return -EINVAL; +} + +void wlan_hdd_set_restriction_mask(struct hdd_context *hdd_ctx) +{ +} +#endif + +#if defined(FEATURE_WLAN_CH_AVOID) +/** + * hdd_store_sap_restart_channel() - store sap restart channel + * @restart_chan: restart channel + * @restart_chan_store: pointer to restart channel store + * + * The function will store new sap restart channel. + * + * Return - none + */ +static void +hdd_store_sap_restart_channel(qdf_freq_t restart_chan, qdf_freq_t *restart_chan_store) +{ + uint8_t i; + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (*(restart_chan_store + i) == restart_chan) + return; + + if (*(restart_chan_store + i)) + continue; + + *(restart_chan_store + i) = restart_chan; + return; + } +} + +/** + * hdd_check_chn_bw_boundary_unsafe() - check channel range unsafe + * @hdd_ctxt: hdd context pointer + * @adapter: hdd adapter pointer + * + * hdd_check_chn_bw_boundary_unsafe check SAP channel range with certain + * bandwidth whether cover all unsafe channel list. + * + * Return - bool + */ +static bool +hdd_check_chn_bw_boundary_unsafe(struct hdd_context *hdd_ctxt, + struct hdd_adapter *adapter) +{ + uint32_t freq; + uint32_t start_freq = 0; + uint32_t end_freq = 0; + uint32_t i; + uint8_t ch_width; + const struct bonded_channel_freq *bonded_chan_ptr_ptr = NULL; + + freq = adapter->deflink->session.ap.operating_chan_freq; + ch_width = adapter->deflink->session.ap.sap_config.acs_cfg.ch_width; + + if (ch_width > CH_WIDTH_20MHZ) + bonded_chan_ptr_ptr = + wlan_reg_get_bonded_chan_entry(freq, ch_width, 0); + + if (bonded_chan_ptr_ptr) { + start_freq = bonded_chan_ptr_ptr->start_freq; + end_freq = bonded_chan_ptr_ptr->end_freq; + } + + for (i = 0; i < hdd_ctxt->unsafe_channel_count; i++) { + if ((freq == hdd_ctxt->unsafe_channel_list[i]) || + (start_freq <= hdd_ctxt->unsafe_channel_list[i] && + hdd_ctxt->unsafe_channel_list[i] <= end_freq)) { + hdd_debug("op chn freq:%u is unsafe for chn list:%u", + freq, hdd_ctxt->unsafe_channel_list[i]); + return true; + } + } + + return false; +} + +/** + * hdd_unsafe_channel_restart_sap() - restart sap if sap is on unsafe channel + * @hdd_ctx: hdd context pointer + * + * hdd_unsafe_channel_restart_sap check all unsafe channel list + * and if ACS is enabled, driver will ask userspace to restart the + * sap. User space on LTE coex indication restart driver. + * + * Return - none + */ +QDF_STATUS hdd_unsafe_channel_restart_sap(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct hdd_ap_ctx *ap_ctx; + uint32_t i; + bool found = false; + qdf_freq_t restart_chan_store[SAP_MAX_NUM_SESSION] = {0}; + uint8_t scc_on_lte_coex = 0; + uint32_t restart_freq, ap_chan_freq; + bool value; + QDF_STATUS status; + bool is_acs_support_for_dfs_ltecoex = cfg_default(CFG_USER_ACS_DFS_LTE); + bool is_vendor_acs_support = + cfg_default(CFG_USER_AUTO_CHANNEL_SELECTION); + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_UNSAFE_CHANNEL_RESTART_SAP; + enum phy_ch_width ch_width; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_debug_rl("skip device mode:%d", + adapter->device_mode); + hdd_adapter_dev_put_debug(adapter, dbgid); + continue; + } + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (!ap_ctx->sap_config.acs_cfg.acs_mode) { + hdd_debug_rl("skip acs:%d", + ap_ctx->sap_config.acs_cfg.acs_mode); + continue; + } + + ap_chan_freq = ap_ctx->operating_chan_freq; + ch_width = ap_ctx->sap_config.ch_width_orig; + found = false; + status = + ucfg_policy_mgr_get_sta_sap_scc_lte_coex_chnl(hdd_ctx->psoc, + &scc_on_lte_coex); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("can't get scc on lte coex chnl, use def"); + /* + * If STA+SAP is doing SCC & + * g_sta_sap_scc_on_lte_coex_chan is set, + * no need to move SAP. + */ + if ((policy_mgr_is_sta_sap_scc(hdd_ctx->psoc, + ap_chan_freq) && + scc_on_lte_coex) || + policy_mgr_nan_sap_scc_on_unsafe_ch_chk(hdd_ctx->psoc, + ap_chan_freq)) + hdd_debug("SAP allowed in unsafe SCC channel"); + else + found = hdd_check_chn_bw_boundary_unsafe(hdd_ctx, + adapter); + if (!found) { + hdd_store_sap_restart_channel(ap_chan_freq, + restart_chan_store); + hdd_debug("ch freq:%d is safe. no need to change channel", + ap_chan_freq); + continue; + } + + status = ucfg_mlme_get_acs_support_for_dfs_ltecoex( + hdd_ctx->psoc, + &is_acs_support_for_dfs_ltecoex); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("get_acs_support_for_dfs_ltecoex failed,set def"); + + status = ucfg_mlme_get_vendor_acs_support( + hdd_ctx->psoc, + &is_vendor_acs_support); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("get_vendor_acs_support failed, set default"); + + if (is_vendor_acs_support && + is_acs_support_for_dfs_ltecoex) { + hdd_update_acs_timer_reason(adapter, + QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX); + continue; + } + + restart_freq = 0; + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (!restart_chan_store[i]) + continue; + + if (policy_mgr_is_force_scc(hdd_ctx->psoc) && + WLAN_REG_IS_SAME_BAND_FREQS( + restart_chan_store[i], + ap_chan_freq)) { + restart_freq = restart_chan_store[i]; + break; + } + } + if (!restart_freq) { + restart_freq = + wlansap_get_safe_channel_from_pcl_and_acs_range( + WLAN_HDD_GET_SAP_CTX_PTR(link_info), + &ch_width); + } + if (!restart_freq) { + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + link_info->vdev_id, + CSA_REASON_UNSAFE_CHANNEL); + hdd_err("Unable to find safe chan, Stop the SAP if restriction mask is set else set txpower"); + hdd_stop_sap_set_tx_power(hdd_ctx->psoc, adapter); + continue; + } + /* + * SAP restart due to unsafe channel. While + * restarting the SAP, make sure to clear + * acs_channel, channel to reset to + * 0. Otherwise these settings will override + * the ACS while restart. + */ + hdd_ctx->acs_policy.acs_chan_freq = + AUTO_CHANNEL_SELECT; + ucfg_mlme_get_sap_internal_restart(hdd_ctx->psoc, + &value); + if (value) { + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, + link_info->vdev_id, + CSA_REASON_UNSAFE_CHANNEL); + status = hdd_switch_sap_chan_freq(adapter, + restart_freq, + ch_width, + true); + if (QDF_IS_STATUS_SUCCESS(status)) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return QDF_STATUS_E_PENDING; + } else { + hdd_debug("CSA failed, check next SAP"); + } + } else { + hdd_debug("sending coex indication"); + wlan_hdd_send_svc_nlink_msg( + hdd_ctx->radio_index, + WLAN_SVC_LTE_COEX_IND, NULL, 0); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return QDF_STATUS_SUCCESS; + } + } + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_init_channel_avoidance() - Initialize channel avoidance + * @hdd_ctx: HDD global context + * + * Initialize the channel avoidance logic by retrieving the unsafe + * channel list from the platform driver and plumbing the data + * down to the lower layers. Then subscribe to subsequent channel + * avoidance events. + * + * Return: None + */ +static void hdd_init_channel_avoidance(struct hdd_context *hdd_ctx) +{ + uint16_t unsafe_channel_count; + int index; + qdf_freq_t *unsafe_freq_list; + + pld_get_wlan_unsafe_channel(hdd_ctx->parent_dev, + hdd_ctx->unsafe_channel_list, + &(hdd_ctx->unsafe_channel_count), + sizeof(uint16_t) * NUM_CHANNELS); + + hdd_debug("num of unsafe channels is %d", + hdd_ctx->unsafe_channel_count); + + unsafe_channel_count = QDF_MIN((uint16_t)hdd_ctx->unsafe_channel_count, + (uint16_t)NUM_CHANNELS); + + if (!unsafe_channel_count) + return; + + unsafe_freq_list = qdf_mem_malloc( + unsafe_channel_count * sizeof(*unsafe_freq_list)); + + if (!unsafe_freq_list) + return; + + for (index = 0; index < unsafe_channel_count; index++) { + hdd_debug("channel frequency %d is not safe", + hdd_ctx->unsafe_channel_list[index]); + unsafe_freq_list[index] = + (qdf_freq_t)hdd_ctx->unsafe_channel_list[index]; + } + + ucfg_policy_mgr_init_chan_avoidance( + hdd_ctx->psoc, + unsafe_freq_list, + unsafe_channel_count); + + qdf_mem_free(unsafe_freq_list); +} + +static void hdd_lte_coex_restart_sap(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx) +{ + uint8_t restart_chan; + uint32_t restart_freq; + + restart_freq = wlansap_get_safe_channel_from_pcl_and_acs_range( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + NULL); + + restart_chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, + restart_freq); + + if (!restart_chan) { + hdd_alert("fail to restart SAP"); + return; + } + + /* SAP restart due to unsafe channel. While restarting + * the SAP, make sure to clear acs_channel, channel to + * reset to 0. Otherwise these settings will override + * the ACS while restart. + */ + hdd_ctx->acs_policy.acs_chan_freq = AUTO_CHANNEL_SELECT; + + hdd_debug("sending coex indication"); + + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_LTE_COEX_IND, NULL, 0); + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, adapter->deflink->vdev_id, + CSA_REASON_LTE_COEX); + hdd_switch_sap_channel(adapter->deflink, restart_chan, true); +} + +int hdd_clone_local_unsafe_chan(struct hdd_context *hdd_ctx, + uint16_t **local_unsafe_list, uint16_t *local_unsafe_list_count) +{ + uint32_t size; + uint16_t *unsafe_list; + uint16_t chan_count; + + if (!hdd_ctx || !local_unsafe_list_count || !local_unsafe_list_count) + return -EINVAL; + + chan_count = QDF_MIN(hdd_ctx->unsafe_channel_count, + NUM_CHANNELS); + if (chan_count) { + size = chan_count * sizeof(hdd_ctx->unsafe_channel_list[0]); + unsafe_list = qdf_mem_malloc(size); + if (!unsafe_list) + return -ENOMEM; + qdf_mem_copy(unsafe_list, hdd_ctx->unsafe_channel_list, size); + } else { + unsafe_list = NULL; + } + + *local_unsafe_list = unsafe_list; + *local_unsafe_list_count = chan_count; + + return 0; +} + +bool hdd_local_unsafe_channel_updated( + struct hdd_context *hdd_ctx, uint16_t *local_unsafe_list, + uint16_t local_unsafe_list_count, uint32_t restriction_mask) +{ + int i, j; + + if (local_unsafe_list_count != hdd_ctx->unsafe_channel_count) + return true; + if (local_unsafe_list_count == 0) + return false; + for (i = 0; i < local_unsafe_list_count; i++) { + for (j = 0; j < local_unsafe_list_count; j++) + if (local_unsafe_list[i] == + hdd_ctx->unsafe_channel_list[j]) + break; + if (j >= local_unsafe_list_count) + break; + } + + if (ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer(hdd_ctx->psoc)) { + /* Return false if current channel list is same as previous + * and restriction mask is not altered + */ + if (i >= local_unsafe_list_count && + (restriction_mask == + wlan_hdd_get_restriction_mask(hdd_ctx))) { + hdd_info("unsafe chan list same"); + return false; + } + } else if (i >= local_unsafe_list_count) { + hdd_info("unsafe chan list same"); + return false; + } + + return true; +} +#else +static void hdd_init_channel_avoidance(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_lte_coex_restart_sap(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx) +{ + hdd_debug("Channel avoidance is not enabled; Abort SAP restart"); +} +#endif /* defined(FEATURE_WLAN_CH_AVOID) */ + +struct wlan_hdd_link_info * +wlan_hdd_get_link_info_from_objmgr(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + hdd_err("null vdev object"); + return NULL; + } + + if (vdev->vdev_nif.osdev) + return vdev->vdev_nif.osdev->legacy_osif_priv; + + return NULL; +} + +/** + * hdd_indicate_mgmt_frame() - Wrapper to indicate management frame to + * user space + * @frame_ind: Management frame data to be informed. + * + * This function is used to indicate management frame to + * user space + * + * Return: None + * + */ +void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind) +{ + struct hdd_context *hdd_ctx = NULL; + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + int i, num_adapters; + uint8_t vdev_id[WLAN_MAX_VDEVS + WLAN_MAX_ML_VDEVS]; + struct ieee80211_mgmt *mgmt = + (struct ieee80211_mgmt *)frame_ind->frameBuf; + struct wlan_objmgr_vdev *vdev; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_INDICATE_MGMT_FRAME; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (frame_ind->frame_len < ieee80211_hdrlen(mgmt->frame_control)) { + hdd_err(" Invalid frame length"); + return; + } + + if (SME_SESSION_ID_ANY == frame_ind->sessionId) { + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + link_info = hdd_get_link_info_by_vdev(hdd_ctx, i); + if (link_info) { + adapter = link_info->adapter; + break; + } + } + } else if (SME_SESSION_ID_BROADCAST == frame_ind->sessionId) { + num_adapters = 0; + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, + next_adapter, dbgid) { + hdd_adapter_for_each_active_link_info(adapter, + link_info) { + vdev_id[num_adapters] = link_info->vdev_id; + num_adapters++; + } + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + adapter = NULL; + + for (i = 0; i < num_adapters; i++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + hdd_ctx->psoc, + vdev_id[i], + WLAN_OSIF_ID); + + if (!vdev) + continue; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + wlan_objmgr_vdev_release_ref(vdev, + WLAN_OSIF_ID); + continue; + } + + hdd_indicate_mgmt_frame_to_user(link_info->adapter, + frame_ind->frame_len, + frame_ind->frameBuf, + frame_ind->frameType, + frame_ind->rx_freq, + frame_ind->rxRssi, + frame_ind->rx_flags); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); + } + + adapter = NULL; + } else { + link_info = hdd_get_link_info_by_vdev(hdd_ctx, + frame_ind->sessionId); + + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + adapter = link_info->adapter; + } + + if ((adapter) && + (WLAN_HDD_ADAPTER_MAGIC == adapter->magic)) + hdd_indicate_mgmt_frame_to_user(adapter, + frame_ind->frame_len, + frame_ind->frameBuf, + frame_ind->frameType, + frame_ind->rx_freq, + frame_ind->rxRssi, + frame_ind->rx_flags); +} + +void hdd_acs_response_timeout_handler(void *context) +{ + struct hdd_external_acs_timer_context *timer_context = + (struct hdd_external_acs_timer_context *)context; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + uint8_t reason; + struct sap_context *sap_context; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + if (!timer_context) { + hdd_err("invalid timer context"); + return; + } + adapter = timer_context->adapter; + reason = timer_context->reason; + + if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("invalid adapter or adapter has invalid magic"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + link_info = adapter->deflink; + if (!test_bit(VENDOR_ACS_RESPONSE_PENDING, &link_info->link_flags)) + return; + + clear_bit(VENDOR_ACS_RESPONSE_PENDING, &link_info->link_flags); + + hdd_err("ACS timeout happened for %s reason %d", + adapter->dev->name, reason); + + sap_context = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + switch (reason) { + /* SAP init case */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_INIT: + wlan_sap_set_vendor_acs(sap_context, false); + wlan_hdd_cfg80211_start_acs(link_info); + break; + /* DFS detected on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_DFS: + wlan_sap_update_next_channel(sap_context, 0, 0); + sme_update_new_channel_event(hdd_ctx->mac_handle, + link_info->vdev_id); + break; + /* LTE coex event on current channel */ + case QCA_WLAN_VENDOR_ACS_SELECT_REASON_LTE_COEX: + hdd_lte_coex_restart_sap(adapter, hdd_ctx); + break; + default: + hdd_info("invalid reason for timer invoke"); + } +} + +/** + * hdd_override_ini_config - Override INI config + * @hdd_ctx: HDD context + * + * Override INI config based on module parameter. + * + * Return: None + */ +static void hdd_override_ini_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (0 == enable_dfs_chan_scan || 1 == enable_dfs_chan_scan) { + ucfg_scan_cfg_set_dfs_chan_scan_allowed(hdd_ctx->psoc, + enable_dfs_chan_scan); + hdd_debug("Module enable_dfs_chan_scan set to %d", + enable_dfs_chan_scan); + } + if (0 == enable_11d || 1 == enable_11d) { + status = ucfg_mlme_set_11d_enabled(hdd_ctx->psoc, enable_11d); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set 11d_enable flag"); + } +} + +#ifdef ENABLE_MTRACE_LOG +static void hdd_set_mtrace_for_each(struct hdd_context *hdd_ctx) +{ + uint8_t module_id = 0; + int qdf_print_idx = -1; + + qdf_print_idx = qdf_get_pidx(); + for (module_id = 0; module_id < QDF_MODULE_ID_MAX; module_id++) + qdf_print_set_category_verbose( + qdf_print_idx, + module_id, QDF_TRACE_LEVEL_TRACE, + hdd_ctx->config->enable_mtrace); +} +#else +static void hdd_set_mtrace_for_each(struct hdd_context *hdd_ctx) +{ +} + +#endif + +/** + * hdd_log_level_to_bitmask() - user space log level to host log bitmask + * @user_log_level: user space log level + * + * Convert log level from user space to host log level bitmask. + * + * Return: Bitmask of log levels to be enabled + */ +static uint32_t hdd_log_level_to_bitmask(enum host_log_level user_log_level) +{ + QDF_TRACE_LEVEL host_trace_level; + uint32_t bitmask; + + switch (user_log_level) { + case HOST_LOG_LEVEL_NONE: + host_trace_level = QDF_TRACE_LEVEL_NONE; + break; + case HOST_LOG_LEVEL_FATAL: + host_trace_level = QDF_TRACE_LEVEL_FATAL; + break; + case HOST_LOG_LEVEL_ERROR: + host_trace_level = QDF_TRACE_LEVEL_ERROR; + break; + case HOST_LOG_LEVEL_WARN: + host_trace_level = QDF_TRACE_LEVEL_WARN; + break; + case HOST_LOG_LEVEL_INFO: + host_trace_level = QDF_TRACE_LEVEL_INFO_LOW; + break; + case HOST_LOG_LEVEL_DEBUG: + host_trace_level = QDF_TRACE_LEVEL_DEBUG; + break; + case HOST_LOG_LEVEL_TRACE: + host_trace_level = QDF_TRACE_LEVEL_TRACE; + break; + default: + host_trace_level = QDF_TRACE_LEVEL_TRACE; + break; + } + + bitmask = (1 << (host_trace_level + 1)) - 1; + + return bitmask; +} + +/** + * hdd_set_trace_level_for_each - Set trace level for each INI config + * @hdd_ctx: HDD context + * + * Set trace level for each module based on INI config. + * + * Return: None + */ +static void hdd_set_trace_level_for_each(struct hdd_context *hdd_ctx) +{ + uint8_t host_module_log[QDF_MODULE_ID_MAX * 2]; + qdf_size_t host_module_log_num = 0; + QDF_MODULE_ID module_id; + uint32_t bitmask; + uint32_t i; + + qdf_uint8_array_parse(cfg_get(hdd_ctx->psoc, + CFG_ENABLE_HOST_MODULE_LOG_LEVEL), + host_module_log, + QDF_MODULE_ID_MAX * 2, + &host_module_log_num); + + for (i = 0; i + 1 < host_module_log_num; i += 2) { + module_id = host_module_log[i]; + bitmask = hdd_log_level_to_bitmask(host_module_log[i + 1]); + if (module_id < QDF_MODULE_ID_MAX && + module_id >= QDF_MODULE_ID_MIN) + hdd_qdf_trace_enable(module_id, bitmask); + } + + hdd_set_mtrace_for_each(hdd_ctx); +} + +/** + * hdd_context_init() - Initialize HDD context + * @hdd_ctx: HDD context. + * + * Initialize HDD context along with all the feature specific contexts. + * + * return: 0 on success and errno on failure. + */ +static int hdd_context_init(struct hdd_context *hdd_ctx) +{ + int ret; + + hdd_ctx->ioctl_scan_mode = eSIR_ACTIVE_SCAN; + hdd_ctx->max_intf_count = WLAN_MAX_VDEVS; + + init_completion(&hdd_ctx->mc_sus_event_var); + init_completion(&hdd_ctx->ready_to_suspend); + + qdf_spinlock_create(&hdd_ctx->connection_status_lock); + qdf_spinlock_create(&hdd_ctx->hdd_adapter_lock); + + qdf_list_create(&hdd_ctx->hdd_adapters, 0); + + ret = hdd_scan_context_init(hdd_ctx); + if (ret) + goto list_destroy; + + ret = hdd_sap_context_init(hdd_ctx); + if (ret) + goto scan_destroy; + + ret = ucfg_dp_bbm_context_init(hdd_ctx->psoc); + if (ret) + goto sap_destroy; + + wlan_hdd_cfg80211_extscan_init(hdd_ctx); + + hdd_init_offloaded_packets_ctx(hdd_ctx); + + ret = wlan_hdd_cfg80211_init(hdd_ctx->parent_dev, hdd_ctx->wiphy, + hdd_ctx->config); + if (ret) + goto bbm_destroy; + + qdf_wake_lock_create(&hdd_ctx->monitor_mode_wakelock, + "monitor_mode_wakelock"); + hdd_lp_create_work(hdd_ctx); + + return 0; + +bbm_destroy: + ucfg_dp_bbm_context_deinit(hdd_ctx->psoc); + +sap_destroy: + hdd_sap_context_destroy(hdd_ctx); + +scan_destroy: + hdd_scan_context_destroy(hdd_ctx); +list_destroy: + qdf_list_destroy(&hdd_ctx->hdd_adapters); + + return ret; +} + +#ifdef SHUTDOWN_WLAN_IN_SYSTEM_SUSPEND +static void hdd_idle_timer_in_active(uint32_t timeout_ms) +{ + /* do nothing because idle shutdown will be called in system + * suspend prepare + */ +} +#else +/* ensure idle shutdown can be called/finished once timer started */ +static void hdd_idle_timer_in_active(uint32_t timeout_ms) +{ + uint32_t suspend_timeout_ms; + enum wake_lock_reason reason = + WIFI_POWER_EVENT_WAKELOCK_IFACE_CHANGE_TIMER; + + suspend_timeout_ms = timeout_ms + HDD_PSOC_IDLE_SHUTDOWN_SUSPEND_DELAY; + hdd_prevent_suspend_timeout(suspend_timeout_ms, reason); +} +#endif + +void hdd_psoc_idle_timer_start(struct hdd_context *hdd_ctx) +{ + uint32_t timeout_ms = hdd_ctx->config->iface_change_wait_time; + + if (!timeout_ms) { + hdd_info("psoc idle timer is disabled"); + return; + } + + hdd_debug("Starting psoc idle timer"); + + /* If PCIe gen speed change is requested, reduce idle shutdown + * timeout to 100 ms + */ + if (hdd_ctx->current_pcie_gen_speed) { + timeout_ms = HDD_PCIE_GEN_SPEED_CHANGE_TIMEOUT_MS; + hdd_info("pcie gen speed change requested"); + } + + qdf_delayed_work_start(&hdd_ctx->psoc_idle_timeout_work, timeout_ms); + hdd_idle_timer_in_active(timeout_ms); +} + +void hdd_psoc_idle_timer_stop(struct hdd_context *hdd_ctx) +{ + qdf_delayed_work_stop_sync(&hdd_ctx->psoc_idle_timeout_work); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_IFACE_CHANGE_TIMER); + hdd_debug("Stopped psoc idle timer"); +} + + +/** + * __hdd_psoc_idle_shutdown() - perform an idle shutdown on the given psoc + * @hdd_ctx: the hdd context which should be shutdown + * + * When no interfaces are "up" on a psoc, an idle shutdown timer is started. + * If no interfaces are brought up before the timer expires, we do an + * "idle shutdown," cutting power to the physical SoC to save power. This is + * done completely transparently from the perspective of userspace. + * + * Return: None + */ +static int __hdd_psoc_idle_shutdown(struct hdd_context *hdd_ctx) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + hdd_enter(); + + hdd_reg_wait_for_country_change(hdd_ctx); + + errno = osif_psoc_sync_trans_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) { + hdd_info("psoc busy, abort idle shutdown; errno:%d", errno); + errno = -EAGAIN; + goto exit; + } + + osif_psoc_sync_wait_for_ops(psoc_sync); + /* + * This is to handle scenario in which platform driver triggers + * idle_shutdown if Deep Sleep/Hibernate entry notification is + * received from modem subsystem in wearable devices + */ + if (hdd_is_any_interface_open(hdd_ctx)) { + hdd_err_rl("all interfaces are not down, ignore idle shutdown"); + errno = -EAGAIN; + } else { + errno = hdd_wlan_stop_modules(hdd_ctx, false); + } + + osif_psoc_sync_trans_stop(psoc_sync); + +exit: + hdd_exit(); + return errno; +} + +static int __hdd_mode_change_psoc_idle_shutdown(struct hdd_context *hdd_ctx) +{ + is_mode_change_psoc_idle_shutdown = false; + return hdd_wlan_stop_modules(hdd_ctx, true); +} + +int hdd_psoc_idle_shutdown(struct device *dev) +{ + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return -EINVAL; + + if (is_mode_change_psoc_idle_shutdown) + ret = __hdd_mode_change_psoc_idle_shutdown(hdd_ctx); + else { + ret = __hdd_psoc_idle_shutdown(hdd_ctx); + } + + return ret; +} + +static int __hdd_psoc_idle_restart(struct hdd_context *hdd_ctx) +{ + int ret; + + ret = hdd_soc_idle_restart_lock(hdd_ctx->parent_dev); + if (ret) + return ret; + + ret = hdd_wlan_start_modules(hdd_ctx, false); + + if (!qdf_is_fw_down()) + cds_set_recovery_in_progress(false); + + hdd_soc_idle_restart_unlock(); + + return ret; +} + +int hdd_psoc_idle_restart(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return -EINVAL; + + return __hdd_psoc_idle_restart(hdd_ctx); +} + +int hdd_trigger_psoc_idle_restart(struct hdd_context *hdd_ctx) +{ + int ret; + + QDF_BUG(rtnl_is_locked()); + + hdd_psoc_idle_timer_stop(hdd_ctx); + if (hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) { + hdd_nofl_debug("Driver modules already Enabled"); + return 0; + } + + ret = hdd_soc_idle_restart_lock(hdd_ctx->parent_dev); + if (ret) + return ret; + + if (hdd_ctx->current_pcie_gen_speed) { + hdd_info("request pcie gen speed change to %d", + hdd_ctx->current_pcie_gen_speed); + + /* call pld api for pcie gen speed change */ + ret = pld_set_pcie_gen_speed(hdd_ctx->parent_dev, + hdd_ctx->current_pcie_gen_speed); + if (ret) + hdd_err_rl("failed to set pcie gen speed"); + + hdd_ctx->current_pcie_gen_speed = 0; + } + + qdf_event_reset(&hdd_ctx->regulatory_update_event); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = true; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + + ret = pld_idle_restart(hdd_ctx->parent_dev, hdd_psoc_idle_restart); + hdd_soc_idle_restart_unlock(); + + return ret; +} + +/** + * hdd_psoc_idle_timeout_callback() - Handler for psoc idle timeout + * @priv: pointer to hdd context + * + * Return: None + */ +static void hdd_psoc_idle_timeout_callback(void *priv) +{ + int ret; + struct hdd_context *hdd_ctx = priv; + void *hif_ctx; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (hif_ctx) { + /* + * Trigger runtime sync resume before psoc_idle_shutdown + * such that resume can happen successfully + */ + qdf_rtpm_sync_resume(); + } + + hdd_info("Psoc idle timeout elapsed; starting psoc shutdown"); + + ret = pld_idle_shutdown(hdd_ctx->parent_dev, hdd_psoc_idle_shutdown); + if (-EAGAIN == ret || hdd_ctx->is_wiphy_suspended) { + hdd_debug("System suspend in progress. Restart idle shutdown timer"); + hdd_psoc_idle_timer_start(hdd_ctx); + } + + /* Clear the recovery flag for PCIe discrete soc after idle shutdown*/ + if (PLD_BUS_TYPE_PCIE == pld_get_bus_type(hdd_ctx->parent_dev) && + -EBUSY != ret) + cds_set_recovery_in_progress(false); +} + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +static void hdd_set_wlan_logging(struct hdd_context *hdd_ctx) +{ + wlan_set_console_log_levels(hdd_ctx->config->wlan_console_log_levels); + wlan_logging_set_active(hdd_ctx->config->wlan_logging_enable); +} +#else +static void hdd_set_wlan_logging(struct hdd_context *hdd_ctx) +{ } +#endif + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +static void hdd_init_wlan_logging_params(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->wlan_logging_enable = cfg_get(psoc, CFG_WLAN_LOGGING_SUPPORT); + + config->wlan_console_log_levels = + cfg_get(psoc, CFG_WLAN_LOGGING_CONSOLE_SUPPORT); + config->host_log_custom_nl_proto = + cfg_get(psoc, CFG_HOST_LOG_CUSTOM_NETLINK_PROTO); +} +#else +static void hdd_init_wlan_logging_params(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +static void hdd_init_wlan_auto_shutdown(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->wlan_auto_shutdown = cfg_get(psoc, CFG_WLAN_AUTO_SHUTDOWN); +} +#else +static void hdd_init_wlan_auto_shutdown(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifndef REMOVE_PKT_LOG +static void hdd_init_packet_log(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->enable_packet_log = cfg_get(psoc, CFG_ENABLE_PACKET_LOG); +} +#else +static void hdd_init_packet_log(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef ENABLE_MTRACE_LOG +static void hdd_init_mtrace_log(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->enable_mtrace = cfg_get(psoc, CFG_ENABLE_MTRACE); +} +#else +static void hdd_init_mtrace_log(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef FEATURE_RUNTIME_PM +static void hdd_init_runtime_pm(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->runtime_pm = cfg_get(psoc, CFG_ENABLE_RUNTIME_PM); +} + +bool hdd_is_runtime_pm_enabled(struct hdd_context *hdd_ctx) +{ + return hdd_ctx->config->runtime_pm != hdd_runtime_pm_disabled; +} +#else +static void hdd_init_runtime_pm(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) + +{ +} + +bool hdd_is_runtime_pm_enabled(struct hdd_context *hdd_ctx) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +static void hdd_init_qmi_stats(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->is_qmi_stats_enabled = cfg_get(psoc, CFG_ENABLE_QMI_STATS); +} +#else +static void hdd_init_qmi_stats(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) + +{ +} +#endif + +#ifdef FEATURE_WLAN_DYNAMIC_CVM +static void hdd_init_vc_mode_cfg_bitmap(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->vc_mode_cfg_bitmap = cfg_get(psoc, CFG_VC_MODE_BITMAP); +} +#else +static void hdd_init_vc_mode_cfg_bitmap(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef DHCP_SERVER_OFFLOAD +static void +hdd_init_dhcp_server_ip(struct hdd_context *hdd_ctx) +{ + uint8_t num_entries; + + hdd_ctx->config->dhcp_server_ip.is_dhcp_server_ip_valid = true; + hdd_string_to_u8_array(cfg_get(hdd_ctx->psoc, CFG_DHCP_SERVER_IP_NAME), + hdd_ctx->config->dhcp_server_ip.dhcp_server_ip, + &num_entries, IPADDR_NUM_ENTRIES); + + if (num_entries != IPADDR_NUM_ENTRIES) { + hdd_err("Incorrect IP address (%s) assigned for DHCP server!", + cfg_get(hdd_ctx->psoc, CFG_DHCP_SERVER_IP_NAME)); + hdd_config->dhcp_server_ip.is_dhcp_server_ip_valid = false; + } +} +#else +static void +hdd_init_dhcp_server_ip(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef SAR_SAFETY_FEATURE +static void hdd_sar_cfg_update(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->sar_safety_timeout = cfg_get(psoc, CFG_SAR_SAFETY_TIMEOUT); + config->sar_safety_unsolicited_timeout = + cfg_get(psoc, CFG_SAR_SAFETY_UNSOLICITED_TIMEOUT); + config->sar_safety_req_resp_timeout = + cfg_get(psoc, CFG_SAR_SAFETY_REQ_RESP_TIMEOUT); + config->sar_safety_req_resp_retry = + cfg_get(psoc, CFG_SAR_SAFETY_REQ_RESP_RETRIES); + config->sar_safety_index = cfg_get(psoc, CFG_SAR_SAFETY_INDEX); + config->sar_safety_sleep_index = + cfg_get(psoc, CFG_SAR_SAFETY_SLEEP_INDEX); + config->enable_sar_safety = + cfg_get(psoc, CFG_ENABLE_SAR_SAFETY_FEATURE); + config->config_sar_safety_sleep_index = + cfg_get(psoc, CFG_CONFIG_SAR_SAFETY_SLEEP_MODE_INDEX); +} + +void hdd_set_sar_init_index(struct hdd_context *hdd_ctx) +{ + uint32_t index, enable = 0; + + if (!hdd_ctx) { + hdd_err("hdd_ctx NULL"); + return; + } + if (hdd_ctx->sar_version == SAR_VERSION_1) { + hdd_nofl_debug("FW SAR version: %d", hdd_ctx->sar_version); + return; + } + + enable = hdd_ctx->config->enable_sar_safety; + index = hdd_ctx->config->sar_safety_index; + if (enable & SAR_SAFETY_ENABLED_INIT) + hdd_configure_sar_index(hdd_ctx, index); +} +#else +static void hdd_sar_cfg_update(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef FEATURE_SET +/** + * hdd_get_wifi_features_cfg_update() - Initialize get wifi features cfg + * @config: Pointer to HDD config + * @psoc: psoc pointer + * + * Return: None + */ +static void hdd_get_wifi_features_cfg_update(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->get_wifi_features = cfg_get(psoc, CFG_GET_WIFI_FEATURES); +} +#else +static void hdd_get_wifi_features_cfg_update(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_init_cpu_cxpc_threshold_cfg() - Initialize cpu cxpc threshold cfg + * @config: Pointer to HDD config + * @psoc: psoc pointer + * + * Return: None + */ +static void hdd_init_cpu_cxpc_threshold_cfg(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->cpu_cxpc_threshold = cfg_get(psoc, CFG_CPU_CXPC_THRESHOLD); +} +#else +static void hdd_init_cpu_cxpc_threshold_cfg(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +/** + * hdd_cfg_params_init() - Initialize hdd params in hdd_config structure + * @hdd_ctx: Pointer to HDD context + * + * Return: None + */ +static void hdd_cfg_params_init(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct hdd_config *config = hdd_ctx->config; + if (!psoc) { + hdd_err("Invalid psoc"); + return; + } + + if (!config) { + hdd_err("Invalid hdd config"); + return; + } + + config->dot11Mode = cfg_get(psoc, CFG_HDD_DOT11_MODE); + config->bug_on_reinit_failure = cfg_get(psoc, + CFG_BUG_ON_REINIT_FAILURE); + + config->is_ramdump_enabled = cfg_get(psoc, + CFG_ENABLE_RAMDUMP_COLLECTION); + + config->iface_change_wait_time = cfg_get(psoc, + CFG_INTERFACE_CHANGE_WAIT); + + config->multicast_host_fw_msgs = cfg_get(psoc, + CFG_MULTICAST_HOST_FW_MSGS); + + config->private_wext_control = cfg_get(psoc, CFG_PRIVATE_WEXT_CONTROL); + config->enablefwprint = cfg_get(psoc, CFG_ENABLE_FW_UART_PRINT); + config->enable_fw_log = cfg_get(psoc, CFG_ENABLE_FW_LOG); + config->operating_chan_freq = cfg_get(psoc, CFG_OPERATING_FREQUENCY); + config->num_vdevs = cfg_get(psoc, CFG_NUM_VDEV_ENABLE); + qdf_str_lcopy(config->enable_concurrent_sta, + cfg_get(psoc, CFG_ENABLE_CONCURRENT_STA), + CFG_CONCURRENT_IFACE_MAX_LEN); + qdf_str_lcopy(config->dbs_scan_selection, + cfg_get(psoc, CFG_DBS_SCAN_SELECTION), + CFG_DBS_SCAN_PARAM_LENGTH); + config->inform_bss_rssi_raw = cfg_get(psoc, CFG_INFORM_BSS_RSSI_RAW); + config->mac_provision = cfg_get(psoc, CFG_ENABLE_MAC_PROVISION); + config->provisioned_intf_pool = + cfg_get(psoc, CFG_PROVISION_INTERFACE_POOL); + config->derived_intf_pool = cfg_get(psoc, CFG_DERIVED_INTERFACE_POOL); + config->advertise_concurrent_operation = + cfg_get(psoc, + CFG_ADVERTISE_CONCURRENT_OPERATION); + config->is_unit_test_framework_enabled = + cfg_get(psoc, CFG_ENABLE_UNIT_TEST_FRAMEWORK); + config->disable_channel = cfg_get(psoc, CFG_ENABLE_DISABLE_CHANNEL); + config->enable_sar_conversion = cfg_get(psoc, CFG_SAR_CONVERSION); + config->nb_commands_interval = + cfg_get(psoc, CFG_NB_COMMANDS_RATE_LIMIT); + + hdd_init_vc_mode_cfg_bitmap(config, psoc); + hdd_init_runtime_pm(config, psoc); + hdd_init_wlan_auto_shutdown(config, psoc); + hdd_init_wlan_logging_params(config, psoc); + hdd_init_packet_log(config, psoc); + hdd_init_mtrace_log(config, psoc); + hdd_init_dhcp_server_ip(hdd_ctx); + hdd_dp_cfg_update(psoc, hdd_ctx); + hdd_sar_cfg_update(config, psoc); + hdd_init_qmi_stats(config, psoc); + hdd_club_ll_stats_in_get_sta_cfg_update(config, psoc); + config->read_mac_addr_from_mac_file = + cfg_get(psoc, CFG_READ_MAC_ADDR_FROM_MAC_FILE); + + hdd_get_wifi_features_cfg_update(config, psoc); + hdd_init_cpu_cxpc_threshold_cfg(config, psoc); + + config->exclude_selftx_from_cca_busy = + cfg_get(psoc, CFG_EXCLUDE_SELFTX_FROM_CCA_BUSY_TIME); + hdd_init_link_state_cfg(config, psoc); +} + +#ifdef CONNECTION_ROAMING_CFG +static QDF_STATUS hdd_cfg_parse_connection_roaming_cfg(void) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + bool is_valid; + + is_valid = cfg_valid_ini_check(WLAN_CONNECTION_ROAMING_INI_FILE); + + if (is_valid) + status = cfg_parse(WLAN_CONNECTION_ROAMING_INI_FILE); + if (QDF_IS_STATUS_ERROR(status)) { + is_valid = cfg_valid_ini_check(WLAN_CONNECTION_ROAMING_BACKUP_INI_FILE); + if (is_valid) + status = cfg_parse(WLAN_CONNECTION_ROAMING_BACKUP_INI_FILE); + } + return status; +} +#else +static inline QDF_STATUS hdd_cfg_parse_connection_roaming_cfg(void) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +struct hdd_context *hdd_context_create(struct device *dev) +{ + QDF_STATUS status; + int ret = 0; + struct hdd_context *hdd_ctx; + + hdd_enter(); + + hdd_ctx = hdd_cfg80211_wiphy_alloc(); + if (!hdd_ctx) { + ret = -ENOMEM; + goto err_out; + } + + status = qdf_delayed_work_create(&hdd_ctx->psoc_idle_timeout_work, + hdd_psoc_idle_timeout_callback, + hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto wiphy_dealloc; + } + + hdd_pm_notifier_init(hdd_ctx); + + hdd_ctx->parent_dev = dev; + hdd_ctx->last_scan_reject_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + + hdd_ctx->config = qdf_mem_malloc(sizeof(struct hdd_config)); + if (!hdd_ctx->config) { + ret = -ENOMEM; + goto err_free_hdd_context; + } + + status = cfg_parse(WLAN_INI_FILE); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to parse cfg %s; status:%d\n", + WLAN_INI_FILE, status); + /* Assert if failed to parse at least one INI parameter */ + QDF_BUG(status != QDF_STATUS_E_INVAL); + ret = qdf_status_to_os_return(status); + goto err_free_config; + } + + status = hdd_cfg_parse_connection_roaming_cfg(); + + ret = hdd_objmgr_create_and_store_psoc(hdd_ctx, DEFAULT_PSOC_ID); + if (ret) { + QDF_DEBUG_PANIC("Psoc creation fails!"); + goto err_release_store; + } + + if (QDF_IS_STATUS_SUCCESS(status)) + ucfg_mlme_set_connection_roaming_ini_present(hdd_ctx->psoc, + true); + + hdd_cfg_params_init(hdd_ctx); + + /* apply multiplier config, if not already set via module parameter */ + if (qdf_timer_get_multiplier() == 1) + qdf_timer_set_multiplier(cfg_get(hdd_ctx->psoc, + CFG_TIMER_MULTIPLIER)); + hdd_debug("set timer multiplier: %u", qdf_timer_get_multiplier()); + + cds_set_fatal_event(cfg_get(hdd_ctx->psoc, + CFG_ENABLE_FATAL_EVENT_TRIGGER)); + + hdd_override_ini_config(hdd_ctx); + + ret = hdd_context_init(hdd_ctx); + + if (ret) + goto err_hdd_objmgr_destroy; + + if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) + goto skip_multicast_logging; + + cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs); + ret = hdd_init_netlink_services(hdd_ctx); + if (ret) + goto err_deinit_hdd_context; + + hdd_set_wlan_logging(hdd_ctx); + qdf_atomic_init(&hdd_ctx->adapter_ops_history.index); + +skip_multicast_logging: + hdd_set_trace_level_for_each(hdd_ctx); + + cds_set_context(QDF_MODULE_ID_HDD, hdd_ctx); + + wlan_hdd_sar_timers_init(hdd_ctx); + + hdd_exit(); + + return hdd_ctx; + +err_deinit_hdd_context: + hdd_context_deinit(hdd_ctx); + +err_hdd_objmgr_destroy: + hdd_objmgr_release_and_destroy_psoc(hdd_ctx); + +err_release_store: + cfg_release(); + +err_free_config: + qdf_mem_free(hdd_ctx->config); + +err_free_hdd_context: + qdf_delayed_work_destroy(&hdd_ctx->psoc_idle_timeout_work); + +wiphy_dealloc: + wiphy_free(hdd_ctx->wiphy); + +err_out: + return ERR_PTR(ret); +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * wlan_hdd_init_multi_client_info_table()- Initialize the multi client info + * table + * @adapter: hdd adapter + * + * Return: none + */ +static void +wlan_hdd_init_multi_client_info_table(struct hdd_adapter *adapter) +{ + uint8_t i; + + for (i = 0; i < WLM_MAX_HOST_CLIENT; i++) { + adapter->client_info[i].client_id = i; + adapter->client_info[i].port_id = 0; + adapter->client_info[i].in_use = false; + } +} + +void wlan_hdd_deinit_multi_client_info_table(struct hdd_adapter *adapter) +{ + uint8_t i; + + hdd_debug("deinitializing the client info table"); + /* de-initialize the table for host driver client */ + for (i = 0; i < WLM_MAX_HOST_CLIENT; i++) { + if (adapter->client_info[i].in_use) { + adapter->client_info[i].port_id = 0; + adapter->client_info[i].client_id = i; + adapter->client_info[i].in_use = false; + } + } +} + +/** + * wlan_hdd_get_host_driver_port_id()- get host driver port id + * @port_id: argument to be filled + * + * Return: none + */ +static void wlan_hdd_get_host_driver_port_id(uint32_t *port_id) +{ + *port_id = WLAM_WLM_HOST_DRIVER_PORT_ID; +} + +#else +static inline void +wlan_hdd_init_multi_client_info_table(struct hdd_adapter *adapter) +{ +} + +static inline void wlan_hdd_get_host_driver_port_id(uint32_t *port_id) +{ +} +#endif + +static void +hdd_adapter_set_wlm_client_latency_level(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + bool reset; + uint32_t port_id; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx) + return; + + status = ucfg_mlme_cfg_get_wlm_reset(hdd_ctx->psoc, &reset); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get the wlm reset flag"); + reset = false; + } + + if (reset) + goto out; + + if (hdd_get_multi_client_ll_support(adapter)) { + wlan_hdd_get_host_driver_port_id(&port_id); + status = wlan_hdd_set_wlm_client_latency_level( + adapter, port_id, + adapter->latency_level); + if (QDF_IS_STATUS_ERROR(status)) + hdd_warn("Fail to set latency level:%u", status); + } else { + status = sme_set_wlm_latency_level(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + adapter->latency_level, + 0, false); + if (QDF_IS_STATUS_ERROR(status)) + hdd_warn("set wlm mode failed, %u", status); + } +out: + hdd_debug("wlm initial mode %u", adapter->latency_level); +} + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +struct qdf_mac_addr * +hdd_adapter_get_link_mac_addr(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter; + + if (!link_info) + return NULL; + + adapter = link_info->adapter; + if (!hdd_adapter_is_ml_adapter(adapter) || + qdf_is_macaddr_zero(&link_info->link_addr) || + !wlan_vdev_mlme_is_mlo_vdev(link_info->vdev)) + return &adapter->mac_addr; + + return &link_info->link_addr; +} +#else +struct qdf_mac_addr * +hdd_adapter_get_link_mac_addr(struct wlan_hdd_link_info *link_info) +{ + if (!link_info) + return NULL; + + return &link_info->adapter->mac_addr; +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +QDF_STATUS hdd_adapter_check_duplicate_session(struct hdd_adapter *adapter) +{ + int i = 0; + QDF_STATUS status; + uint8_t *addr_list[WLAN_MAX_MLD + 2] = {0}; + struct wlan_hdd_link_info *link_info; + + if (!hdd_adapter_is_ml_adapter(adapter) || + adapter->device_mode == QDF_SAP_MODE) + goto netdev_addr; + + hdd_adapter_for_each_active_link_info(adapter, link_info) + addr_list[i++] = &link_info->link_addr.bytes[0]; + +netdev_addr: + addr_list[i] = &adapter->mac_addr.bytes[0]; + status = sme_check_for_duplicate_session(adapter->hdd_ctx->mac_handle, + &addr_list[0]); + return status; +} + +QDF_STATUS hdd_adapter_fill_link_address(struct hdd_adapter *adapter) +{ + int i = 0; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum QDF_OPMODE opmode = adapter->device_mode; + struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; + struct wlan_hdd_link_info *link_info; + + if (opmode != QDF_STA_MODE && opmode != QDF_SAP_MODE) + return QDF_STATUS_SUCCESS; + + if (opmode == QDF_SAP_MODE) { + link_info = adapter->deflink; + qdf_copy_macaddr(&link_info->link_addr, &adapter->mac_addr); + return QDF_STATUS_SUCCESS; + } + + if (!hdd_adapter_is_ml_adapter(adapter)) + return QDF_STATUS_SUCCESS; + + status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, + &adapter->mac_addr, + &link_addrs[0], + WLAN_MAX_ML_BSS_LINKS); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + hdd_adapter_for_each_link_info(adapter, link_info) + qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]); + + return status; +} +#elif defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +QDF_STATUS hdd_adapter_check_duplicate_session(struct hdd_adapter *adapter) +{ + int i; + QDF_STATUS status; + uint8_t *addr_list[WLAN_MAX_MLD + 1] = {0}; + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + + if (hdd_adapter_is_ml_adapter(adapter) && + adapter->device_mode == QDF_STA_MODE) { + addr_list[0] = &adapter->mld_addr.bytes[0]; + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + if (hdd_adapter_is_associated_with_ml_adapter( + link_adapter)) { + addr_list[1] = &link_adapter->mac_addr.bytes[0]; + } + } + } else { + addr_list[0] = &adapter->mac_addr.bytes[0]; + } + + status = sme_check_for_duplicate_session(mac_handle, &addr_list[0]); + return status; +} +#else +QDF_STATUS hdd_adapter_check_duplicate_session(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + uint8_t *addr_list[2] = {0}; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + + addr_list[0] = &adapter->mac_addr.bytes[0]; + status = sme_check_for_duplicate_session(mac_handle, &addr_list[0]); + + return status; +} +#endif + +static void hdd_restore_info_for_ssr(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (cds_is_driver_recovering()) { + /* ssr happens, recover the info */ + hdd_set_vdev_phy_mode(adapter, adapter->user_phy_mode); + wlan_mlme_restore_user_set_link_num(hdd_ctx->psoc); + } else { + /* intf down/up happens, reset default info */ + hdd_set_vdev_phy_mode(adapter, QCA_WLAN_VENDOR_PHY_MODE_AUTO); + wlan_mlme_clear_user_set_link_num(hdd_ctx->psoc); + } +} + +void hdd_adapter_reset_station_ctx(struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + hdd_adapter_for_each_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + qdf_mem_zero(&sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE); + + hdd_cm_clear_ieee_link_id(link_info); + sta_ctx->user_cfg_chn_width = CH_WIDTH_INVALID; + } +} + +int hdd_start_station_adapter(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + int ret; + struct wlan_hdd_link_info *link_info; + + hdd_enter_dev(adapter->dev); + if (test_bit(SME_SESSION_OPENED, &adapter->deflink->link_flags)) { + hdd_err("session is already opened, %d", + adapter->deflink->vdev_id); + return qdf_status_to_os_return(QDF_STATUS_SUCCESS); + } + + if ((adapter->device_mode == QDF_P2P_DEVICE_MODE) || + (adapter->device_mode == QDF_NAN_DISC_MODE)) + wlan_hdd_lpc_del_monitor_interface(adapter->hdd_ctx, false); + + status = hdd_adapter_fill_link_address(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Link address derive failed"); + return qdf_status_to_os_return(status); + } + + status = hdd_adapter_check_duplicate_session(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Duplicate session is existing with same mac address"); + return qdf_status_to_os_return(status); + } + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + ret = hdd_vdev_create(link_info); + if (ret) { + hdd_err("failed to create vdev: %d", ret); + goto fail; + } + + status = hdd_init_station_mode(link_info); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error Initializing station mode: %d", status); + ret = qdf_status_to_os_return(status); + goto fail; + } + } + + hdd_adapter_reset_station_ctx(adapter); + + hdd_register_wext(adapter->dev); + hdd_set_netdev_flags(adapter); + + hdd_register_tx_flow_control(adapter, + hdd_tx_resume_timer_expired_handler, + hdd_tx_resume_cb, + hdd_tx_flow_control_is_pause); + + hdd_register_hl_netdev_fc_timer(adapter, + hdd_tx_resume_timer_expired_handler); + + if (hdd_get_multi_client_ll_support(adapter)) + wlan_hdd_init_multi_client_info_table(adapter); + + hdd_adapter_set_wlm_client_latency_level(adapter); + hdd_adapter_update_mlo_mgr_mac_addr(adapter); + hdd_restore_info_for_ssr(adapter); + + hdd_exit(); + return 0; + +fail: + hdd_adapter_for_each_active_link_info(adapter, link_info) + hdd_vdev_destroy(link_info); + + return ret; +} + +int hdd_start_ap_adapter(struct hdd_adapter *adapter, bool rtnl_held) +{ + QDF_STATUS status; + bool is_ssr = false; + int ret; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct sap_context *sap_ctx; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + + if (test_bit(SME_SESSION_OPENED, &link_info->link_flags)) { + hdd_err("session is already opened, %d", + link_info->vdev_id); + return qdf_status_to_os_return(QDF_STATUS_SUCCESS); + } + + status = hdd_adapter_fill_link_address(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Link address derive failed"); + return qdf_status_to_os_return(status); + } + + status = hdd_adapter_check_duplicate_session(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Duplicate session is existing with same mac address"); + return qdf_status_to_os_return(status); + } + + /* + * In SSR case no need to create new sap context. + * Otherwise create sap context first and then create + * vdev as while creating the vdev, driver needs to + * register SAP callback and that callback uses sap context + */ + if (WLAN_HDD_GET_SAP_CTX_PTR(link_info)) { + is_ssr = true; + } else if (!hdd_sap_create_ctx(adapter)) { + hdd_err("sap creation failed"); + return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); + } + + ret = hdd_vdev_create(link_info); + if (ret) { + hdd_err("failed to create vdev, status:%d", ret); + goto sap_destroy_ctx; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + status = sap_acquire_vdev_ref(hdd_ctx->psoc, sap_ctx, + link_info->vdev_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to get vdev ref for sap for session_id: %u", + link_info->vdev_id); + ret = qdf_status_to_os_return(status); + goto sap_vdev_destroy; + } + + if (adapter->device_mode == QDF_SAP_MODE) { + status = hdd_vdev_configure_rtt_params(sap_ctx->vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto sap_release_ref; + } + + status = hdd_init_ap_mode(adapter, is_ssr, rtnl_held); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Error Initializing the AP mode: %d", status); + ret = qdf_status_to_os_return(status); + goto sap_release_ref; + } + + hdd_register_tx_flow_control(adapter, + hdd_softap_tx_resume_timer_expired_handler, + hdd_softap_tx_resume_cb, + hdd_tx_flow_control_is_pause); + + hdd_register_hl_netdev_fc_timer(adapter, + hdd_tx_resume_timer_expired_handler); + + if (cds_is_driver_recovering()) + hdd_medium_assess_ssr_reinit(); + + hdd_exit(); + return 0; + +sap_release_ref: + sap_release_vdev_ref(sap_ctx); +sap_vdev_destroy: + hdd_vdev_destroy(link_info); +sap_destroy_ctx: + hdd_sap_destroy_ctx(link_info); + return ret; +} + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/** + * hdd_txrx_populate_cds_config() - Populate txrx cds configuration + * @cds_cfg: CDS Configuration + * @hdd_ctx: Pointer to hdd context + * + * Return: none + */ +static inline void hdd_txrx_populate_cds_config(struct cds_config_info + *cds_cfg, + struct hdd_context *hdd_ctx) +{ + cds_cfg->tx_flow_stop_queue_th = + cfg_get(hdd_ctx->psoc, CFG_DP_TX_FLOW_STOP_QUEUE_TH); + cds_cfg->tx_flow_start_queue_offset = + cfg_get(hdd_ctx->psoc, CFG_DP_TX_FLOW_START_QUEUE_OFFSET); + /* configuration for DP RX Threads */ + cds_cfg->enable_dp_rx_threads = + ucfg_dp_is_rx_threads_enabled(hdd_ctx->psoc); +} +#else +static inline void hdd_txrx_populate_cds_config(struct cds_config_info + *cds_cfg, + struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_update_cds_config() - API to update cds configuration parameters + * @hdd_ctx: HDD Context + * + * Return: 0 for Success, errno on failure + */ +static int hdd_update_cds_config(struct hdd_context *hdd_ctx) +{ + struct cds_config_info *cds_cfg; + int value; + uint8_t band_capability; + uint32_t band_bitmap; + uint8_t ito_repeat_count; + bool crash_inject; + bool self_recovery; + bool fw_timeout_crash; + QDF_STATUS status; + + cds_cfg = qdf_mem_malloc(sizeof(*cds_cfg)); + if (!cds_cfg) + return -ENOMEM; + + cds_cfg->driver_type = QDF_DRIVER_TYPE_PRODUCTION; + ucfg_mlme_get_sap_max_modulated_dtim(hdd_ctx->psoc, + &cds_cfg->sta_maxlimod_dtim); + + ucfg_mlme_get_max_modulated_dtim_ms(hdd_ctx->psoc, + &cds_cfg->sta_maxlimod_dtim_ms); + + status = ucfg_mlme_get_crash_inject(hdd_ctx->psoc, &crash_inject); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get crash inject ini config"); + goto exit; + } + + status = ucfg_mlme_get_self_recovery(hdd_ctx->psoc, &self_recovery); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get self recovery ini config"); + goto exit; + } + + status = ucfg_mlme_get_fw_timeout_crash(hdd_ctx->psoc, + &fw_timeout_crash); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get fw timeout crash ini config"); + goto exit; + } + + status = ucfg_mlme_get_ito_repeat_count(hdd_ctx->psoc, + &ito_repeat_count); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get ITO repeat count ini config"); + goto exit; + } + + cds_cfg->force_target_assert_enabled = crash_inject; + + ucfg_mlme_get_sap_max_offload_peers(hdd_ctx->psoc, &value); + cds_cfg->ap_maxoffload_peers = value; + ucfg_mlme_get_sap_max_offload_reorder_buffs(hdd_ctx->psoc, + &value); + cds_cfg->ap_maxoffload_reorderbuffs = value; + + cds_cfg->reorder_offload = DP_REORDER_OFFLOAD_SUPPORT; + + /* IPA micro controller data path offload resource config item */ + cds_cfg->uc_offload_enabled = ucfg_ipa_uc_is_enabled(); + + cds_cfg->enable_rxthread = + ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc); + ucfg_mlme_get_sap_max_peers(hdd_ctx->psoc, &value); + cds_cfg->max_station = value; + cds_cfg->sub_20_channel_width = WLAN_SUB_20_CH_WIDTH_NONE; + cds_cfg->max_msdus_per_rxinorderind = + cfg_get(hdd_ctx->psoc, CFG_DP_MAX_MSDUS_PER_RXIND); + cds_cfg->self_recovery_enabled = self_recovery; + cds_cfg->fw_timeout_crash = fw_timeout_crash; + + cds_cfg->ito_repeat_count = ito_repeat_count; + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_bitmap); + if (QDF_IS_STATUS_ERROR(status)) + goto exit; + + band_capability = wlan_reg_band_bitmap_to_band_info(band_bitmap); + cds_cfg->bandcapability = band_capability; + cds_cfg->num_vdevs = hdd_ctx->config->num_vdevs; + cds_cfg->enable_tx_compl_tsf64 = + hdd_tsf_is_tsf64_tx_set(hdd_ctx); + hdd_txrx_populate_cds_config(cds_cfg, hdd_ctx); + hdd_lpass_populate_cds_config(cds_cfg, hdd_ctx); + cds_init_ini_config(cds_cfg); + return 0; + +exit: + qdf_mem_free(cds_cfg); + return -EINVAL; +} + +/** + * hdd_update_user_config() - API to update user configuration + * parameters to obj mgr which are used by multiple components + * @hdd_ctx: HDD Context + * + * Return: 0 for Success, errno on failure + */ +static int hdd_update_user_config(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc_user_config *user_config; + uint8_t band_capability; + uint32_t band_bitmap; + QDF_STATUS status; + bool value = false; + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_bitmap); + if (QDF_IS_STATUS_ERROR(status)) + return -EIO; + + user_config = qdf_mem_malloc(sizeof(*user_config)); + if (!user_config) + return -ENOMEM; + + user_config->dot11_mode = hdd_ctx->config->dot11Mode; + status = ucfg_mlme_is_11d_enabled(hdd_ctx->psoc, &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Invalid 11d_enable flag"); + user_config->is_11d_support_enabled = value; + + value = false; + status = ucfg_mlme_is_11h_enabled(hdd_ctx->psoc, &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Invalid 11h_enable flag"); + user_config->is_11h_support_enabled = value; + band_capability = wlan_reg_band_bitmap_to_band_info(band_bitmap); + user_config->band_capability = band_capability; + wlan_objmgr_psoc_set_user_config(hdd_ctx->psoc, user_config); + + qdf_mem_free(user_config); + return 0; +} + +/** + * hdd_init_thermal_info - Initialize thermal level + * @hdd_ctx: HDD context + * + * Initialize thermal level at SME layer and set the thermal level callback + * which would be called when a configured thermal threshold is hit. + * + * Return: 0 on success and errno on failure + */ +static int hdd_init_thermal_info(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + status = sme_init_thermal_info(mac_handle); + + if (!QDF_IS_STATUS_SUCCESS(status)) + return qdf_status_to_os_return(status); + + sme_add_set_thermal_level_callback(mac_handle, + hdd_set_thermal_level_cb); + + return 0; + +} + +#if defined(CONFIG_HDD_INIT_WITH_RTNL_LOCK) +/** + * hdd_hold_rtnl_lock - Hold RTNL lock + * + * Hold RTNL lock + * + * Return: True if held and false otherwise + */ +static inline bool hdd_hold_rtnl_lock(void) +{ + rtnl_lock(); + return true; +} + +/** + * hdd_release_rtnl_lock - Release RTNL lock + * + * Release RTNL lock + * + * Return: None + */ +static inline void hdd_release_rtnl_lock(void) +{ + rtnl_unlock(); +} +#else +static inline bool hdd_hold_rtnl_lock(void) { return false; } +static inline void hdd_release_rtnl_lock(void) { } +#endif + +#if !defined(REMOVE_PKT_LOG) + +/* MAX iwpriv command support */ +#define PKTLOG_SET_BUFF_SIZE 3 +#define PKTLOG_CLEAR_BUFF 4 +/* Set Maximum pktlog file size to 64MB */ +#define MAX_PKTLOG_SIZE 64 + +/** + * hdd_pktlog_set_buff_size() - set pktlog buffer size + * @hdd_ctx: hdd context + * @set_value2: pktlog buffer size value + * + * + * Return: 0 for success or error. + */ +static int hdd_pktlog_set_buff_size(struct hdd_context *hdd_ctx, int set_value2) +{ + struct sir_wifi_start_log start_log = { 0 }; + QDF_STATUS status; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = WLAN_LOG_LEVEL_OFF; + start_log.ini_triggered = cds_is_packet_log_enabled(); + start_log.user_triggered = 1; + start_log.size = set_value2; + start_log.is_pktlog_buff_clear = false; + + status = sme_wifi_start_logger(hdd_ctx->mac_handle, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", status); + hdd_exit(); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_pktlog_clear_buff() - clear pktlog buffer + * @hdd_ctx: hdd context + * + * Return: 0 for success or error. + */ +static int hdd_pktlog_clear_buff(struct hdd_context *hdd_ctx) +{ + struct sir_wifi_start_log start_log; + QDF_STATUS status; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = WLAN_LOG_LEVEL_OFF; + start_log.ini_triggered = cds_is_packet_log_enabled(); + start_log.user_triggered = 1; + start_log.size = 0; + start_log.is_pktlog_buff_clear = true; + + status = sme_wifi_start_logger(hdd_ctx->mac_handle, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", status); + hdd_exit(); + return -EINVAL; + } + + return 0; +} + + +/** + * hdd_process_pktlog_command() - process pktlog command + * @hdd_ctx: hdd context + * @set_value: value set by user + * @set_value2: pktlog buffer size value + * + * This function process pktlog command. + * set_value2 only matters when set_value is 3 (set buff size) + * otherwise we ignore it. + * + * Return: 0 for success or error. + */ +int hdd_process_pktlog_command(struct hdd_context *hdd_ctx, uint32_t set_value, + int set_value2) +{ + int ret; + bool enable; + uint8_t user_triggered = 0; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + hdd_debug("set pktlog %d, set size %d", set_value, set_value2); + + if (set_value > PKTLOG_CLEAR_BUFF) { + hdd_err("invalid pktlog value %d", set_value); + return -EINVAL; + } + + if (set_value == PKTLOG_SET_BUFF_SIZE) { + if (set_value2 <= 0) { + hdd_err("invalid pktlog size %d", set_value2); + return -EINVAL; + } else if (set_value2 > MAX_PKTLOG_SIZE) { + hdd_err_rl("Pktlog size is large. max value is %uMB.", + MAX_PKTLOG_SIZE); + return -EINVAL; + } + return hdd_pktlog_set_buff_size(hdd_ctx, set_value2); + } else if (set_value == PKTLOG_CLEAR_BUFF) { + return hdd_pktlog_clear_buff(hdd_ctx); + } + + /* + * set_value = 0 then disable packetlog + * set_value = 1 enable packetlog forcefully + * set_value = 2 then disable packetlog if disabled through ini or + * enable packetlog with AUTO type. + */ + enable = ((set_value > 0) && cds_is_packet_log_enabled()) ? + true : false; + + if (1 == set_value) { + enable = true; + user_triggered = 1; + } + + return hdd_pktlog_enable_disable(hdd_ctx, enable, user_triggered, 0); +} + +/** + * hdd_pktlog_enable_disable() - Enable/Disable packet logging + * @hdd_ctx: HDD context + * @enable_disable_flag: Flag to enable/disable + * @user_triggered: triggered through iwpriv + * @size: buffer size to be used for packetlog + * + * Return: 0 on success; error number otherwise + */ +int hdd_pktlog_enable_disable(struct hdd_context *hdd_ctx, + bool enable_disable_flag, + uint8_t user_triggered, int size) +{ + struct sir_wifi_start_log start_log; + QDF_STATUS status; + + if (hdd_ctx->is_pktlog_enabled && enable_disable_flag) + return 0; + + if ((!hdd_ctx->is_pktlog_enabled) && (!enable_disable_flag)) + return 0; + + start_log.ring_id = RING_ID_PER_PACKET_STATS; + start_log.verbose_level = + enable_disable_flag ? + WLAN_LOG_LEVEL_ACTIVE : WLAN_LOG_LEVEL_OFF; + start_log.ini_triggered = cds_is_packet_log_enabled(); + start_log.user_triggered = user_triggered; + start_log.size = size; + start_log.is_pktlog_buff_clear = false; + /* + * Use "is_iwpriv_command" flag to distinguish iwpriv command from other + * commands. Host uses this flag to decide whether to send pktlog + * disable command to fw without sending pktlog enable command + * previously. For eg, If vendor sends pktlog disable command without + * sending pktlog enable command, then host discards the packet + * but for iwpriv command, host will send it to fw. + */ + start_log.is_iwpriv_command = 1; + + status = sme_wifi_start_logger(hdd_ctx->mac_handle, start_log); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_wifi_start_logger failed(err=%d)", status); + hdd_exit(); + return -EINVAL; + } + + hdd_ctx->is_pktlog_enabled = enable_disable_flag; + + return 0; +} +#endif /* REMOVE_PKT_LOG */ + +void hdd_free_mac_address_lists(struct hdd_context *hdd_ctx) +{ + hdd_debug("Resetting MAC address lists"); + qdf_mem_zero(hdd_ctx->provisioned_mac_addr, + sizeof(hdd_ctx->provisioned_mac_addr)); + qdf_mem_zero(hdd_ctx->derived_mac_addr, + sizeof(hdd_ctx->derived_mac_addr)); + hdd_ctx->num_provisioned_addr = 0; + hdd_ctx->num_derived_addr = 0; + hdd_ctx->provisioned_intf_addr_mask = 0; + hdd_ctx->derived_intf_addr_mask = 0; +} + +/** + * hdd_get_platform_wlan_mac_buff() - API to query platform driver + * for MAC address + * @dev: Device Pointer + * @num: Number of Valid Mac address + * + * Return: Pointer to MAC address buffer + */ +static uint8_t *hdd_get_platform_wlan_mac_buff(struct device *dev, + uint32_t *num) +{ + return pld_get_wlan_mac_address(dev, num); +} + +/** + * hdd_get_platform_wlan_derived_mac_buff() - API to query platform driver + * for derived MAC address + * @dev: Device Pointer + * @num: Number of Valid Mac address + * + * Return: Pointer to MAC address buffer + */ +static uint8_t *hdd_get_platform_wlan_derived_mac_buff(struct device *dev, + uint32_t *num) +{ + return pld_get_wlan_derived_mac_address(dev, num); +} + +/** + * hdd_populate_random_mac_addr() - API to populate random mac addresses + * @hdd_ctx: HDD Context + * @num: Number of random mac addresses needed + * + * Generate random addresses using bit manipulation on the base mac address + * + * Return: None + */ +void hdd_populate_random_mac_addr(struct hdd_context *hdd_ctx, uint32_t num) +{ + uint32_t idx = hdd_ctx->num_derived_addr; + uint32_t iter; + uint8_t *buf = NULL; + uint8_t macaddr_b3, tmp_br3; + /* + * Consider first provisioned mac address as source address to derive + * remaining addresses + */ + + uint8_t *src = hdd_ctx->provisioned_mac_addr[0].bytes; + + for (iter = 0; iter < num; ++iter, ++idx) { + buf = hdd_ctx->derived_mac_addr[idx].bytes; + qdf_mem_copy(buf, src, QDF_MAC_ADDR_SIZE); + macaddr_b3 = buf[3]; + tmp_br3 = ((macaddr_b3 >> 4 & INTF_MACADDR_MASK) + idx) & + INTF_MACADDR_MASK; + macaddr_b3 += tmp_br3; + macaddr_b3 ^= (1 << INTF_MACADDR_MASK); + buf[0] |= 0x02; + buf[3] = macaddr_b3; + hdd_debug(QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(buf)); + hdd_ctx->num_derived_addr++; + } +} + +/** + * hdd_platform_wlan_mac() - API to get mac addresses from platform driver + * @hdd_ctx: HDD Context + * + * API to get mac addresses from platform driver and update the driver + * structures and configure FW with the base mac address. + * Return: int + */ +static int hdd_platform_wlan_mac(struct hdd_context *hdd_ctx) +{ + uint32_t no_of_mac_addr, iter; + uint32_t max_mac_addr = QDF_MAX_CONCURRENCY_PERSONA; + uint32_t mac_addr_size = QDF_MAC_ADDR_SIZE; + uint8_t *addr, *buf; + struct device *dev = hdd_ctx->parent_dev; + tSirMacAddr mac_addr; + QDF_STATUS status; + + addr = hdd_get_platform_wlan_mac_buff(dev, &no_of_mac_addr); + + if (no_of_mac_addr == 0 || !addr) { + hdd_debug("No mac configured from platform driver"); + return -EINVAL; + } + + hdd_free_mac_address_lists(hdd_ctx); + + if (no_of_mac_addr > max_mac_addr) + no_of_mac_addr = max_mac_addr; + + qdf_mem_copy(&mac_addr, addr, mac_addr_size); + + for (iter = 0; iter < no_of_mac_addr; ++iter, addr += mac_addr_size) { + buf = hdd_ctx->provisioned_mac_addr[iter].bytes; + qdf_mem_copy(buf, addr, QDF_MAC_ADDR_SIZE); + hdd_info("provisioned MAC Addr [%d] "QDF_MAC_ADDR_FMT, iter, + QDF_MAC_ADDR_REF(buf)); + } + + hdd_ctx->num_provisioned_addr = no_of_mac_addr; + + if (hdd_ctx->config->mac_provision) { + addr = hdd_get_platform_wlan_derived_mac_buff(dev, + &no_of_mac_addr); + + if (no_of_mac_addr == 0 || !addr) + hdd_warn("No derived address from platform driver"); + else if (no_of_mac_addr > + (max_mac_addr - hdd_ctx->num_provisioned_addr)) + no_of_mac_addr = (max_mac_addr - + hdd_ctx->num_provisioned_addr); + + for (iter = 0; iter < no_of_mac_addr; ++iter, + addr += mac_addr_size) { + buf = hdd_ctx->derived_mac_addr[iter].bytes; + qdf_mem_copy(buf, addr, QDF_MAC_ADDR_SIZE); + hdd_debug("derived MAC Addr [%d] "QDF_MAC_ADDR_FMT, iter, + QDF_MAC_ADDR_REF(buf)); + } + hdd_ctx->num_derived_addr = no_of_mac_addr; + } + + no_of_mac_addr = hdd_ctx->num_provisioned_addr + + hdd_ctx->num_derived_addr; + if (no_of_mac_addr < max_mac_addr) + hdd_populate_random_mac_addr(hdd_ctx, max_mac_addr - + no_of_mac_addr); + + status = sme_set_custom_mac_addr(mac_addr); + if (!QDF_IS_STATUS_SUCCESS(status)) + return -EAGAIN; + + return 0; +} + +/** + * hdd_update_mac_addr_to_fw() - API to update wlan mac addresses to FW + * @hdd_ctx: HDD Context + * + * Update MAC address to FW. If MAC address passed by FW is invalid, host + * will generate its own MAC and update it to FW. + * + * Return: 0 for success + * Non-zero error code for failure + */ +static int hdd_update_mac_addr_to_fw(struct hdd_context *hdd_ctx) +{ + tSirMacAddr custom_mac_addr; + QDF_STATUS status; + + if (hdd_ctx->num_provisioned_addr) + qdf_mem_copy(&custom_mac_addr, + &hdd_ctx->provisioned_mac_addr[0].bytes[0], + sizeof(tSirMacAddr)); + else + qdf_mem_copy(&custom_mac_addr, + &hdd_ctx->derived_mac_addr[0].bytes[0], + sizeof(tSirMacAddr)); + status = sme_set_custom_mac_addr(custom_mac_addr); + if (!QDF_IS_STATUS_SUCCESS(status)) + return -EAGAIN; + return 0; +} + +/** + * hdd_initialize_mac_address() - API to get wlan mac addresses + * @hdd_ctx: HDD Context + * + * Get MAC addresses from platform driver or wlan_mac.bin. If platform driver + * is provisioned with mac addresses, driver uses it, else it will use + * wlan_mac.bin to update HW MAC addresses. + * + * Return: None + */ +static int hdd_initialize_mac_address(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + int ret; + + ret = hdd_platform_wlan_mac(hdd_ctx); + if (!ret) { + hdd_info("using MAC address from platform driver"); + return ret; + } else if (hdd_ctx->config->mac_provision) { + hdd_err("getting MAC address from platform driver failed"); + return ret; + } + + status = hdd_update_mac_config(hdd_ctx); + if (QDF_IS_STATUS_SUCCESS(status)) { + hdd_info("using MAC address from wlan_mac.bin"); + return 0; + } + + hdd_info("using default MAC address"); + + /* Use fw provided MAC */ + if (!qdf_is_macaddr_zero(&hdd_ctx->hw_macaddr)) { + hdd_update_macaddr(hdd_ctx, hdd_ctx->hw_macaddr, false); + return 0; + } else if (hdd_generate_macaddr_auto(hdd_ctx) != 0) { + struct qdf_mac_addr mac_addr; + + hdd_err("MAC failure from device serial no."); + qdf_get_random_bytes(&mac_addr, sizeof(mac_addr)); + /* + * Reset multicast bit (bit-0) and set + * locally-administered bit + */ + mac_addr.bytes[0] = 0x2; + hdd_update_macaddr(hdd_ctx, mac_addr, true); + } + + ret = hdd_update_mac_addr_to_fw(hdd_ctx); + if (ret) + hdd_err("MAC address out-of-sync, ret:%d", ret); + return ret; +} + +/* params being sent: + * wmi_pdev_param_tx_chain_mask_1ss + * wmi_pdev_param_mgmt_retry_limit + * wmi_pdev_param_default_6ghz_rate + * wmi_pdev_param_pdev_stats_tx_xretry_ext + * wmi_pdev_param_smart_chainmask_scheme + * wmi_pdev_param_alternative_chainmask_scheme + * wmi_pdev_param_ani_enable + * wmi_pdev_param_pcie_config + */ +/** + * hdd_pre_enable_configure() - Configurations prior to cds_enable + * @hdd_ctx: HDD context + * + * Pre configurations to be done at lower layer before calling cds enable. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_pre_enable_configure(struct hdd_context *hdd_ctx) +{ + int ret; + uint8_t val = 0; + uint8_t max_retry = 0; + bool enable_he_mcs0_for_6ghz_mgmt = false; + uint32_t tx_retry_multiplier; + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct dev_set_param setparam[MAX_PDEV_PRE_ENABLE_PARAMS] = {}; + bool check_value; + uint8_t index = 0; + + cdp_register_pause_cb(soc, wlan_hdd_txrx_pause_cb); + hdd_tx_latency_register_cb(soc); + + /* Register HL netdev flow control callback */ + cdp_hl_fc_register(soc, OL_TXRX_PDEV_ID, wlan_hdd_txrx_pause_cb); + /* Register rx mic error indication handler */ + ucfg_dp_register_rx_mic_error_ind_handler(soc); + + /* + * Note that the cds_pre_enable() sequence triggers the cfg download. + * The cfg download must occur before we update the SME config + * since the SME config operation must access the cfg database + */ + status = hdd_set_sme_config(hdd_ctx); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Failed hdd_set_sme_config: %d", status); + ret = qdf_status_to_os_return(status); + goto out; + } + + status = hdd_set_policy_mgr_user_cfg(hdd_ctx); + if (QDF_STATUS_SUCCESS != status) { + hdd_alert("Failed hdd_set_policy_mgr_user_cfg: %d", status); + ret = qdf_status_to_os_return(status); + goto out; + } + + status = ucfg_mlme_get_tx_chainmask_1ss(hdd_ctx->psoc, &val); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Get tx_chainmask_1ss from mlme failed"); + ret = qdf_status_to_os_return(status); + goto out; + } + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_tx_chain_mask_1ss, + val, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_tx_chain_mask_1ss"); + goto out; + + } + + wlan_mlme_get_mgmt_max_retry(hdd_ctx->psoc, &max_retry); + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_mgmt_retry_limit, + max_retry, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_mgmt_retry_limit"); + goto out; + } + + wlan_mlme_get_mgmt_6ghz_rate_support(hdd_ctx->psoc, + &enable_he_mcs0_for_6ghz_mgmt); + if (enable_he_mcs0_for_6ghz_mgmt) { + hdd_debug("HE rates for 6GHz mgmt frames are supported"); + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_default_6ghz_rate, + MGMT_DEFAULT_DATA_RATE_6GHZ, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("wmi_pdev_param_default_6ghz_rate failed %d", + ret); + goto out; + } + } + + wlan_mlme_get_tx_retry_multiplier(hdd_ctx->psoc, + &tx_retry_multiplier); + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_pdev_stats_tx_xretry_ext, + tx_retry_multiplier, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_pdev_stats_tx_xretry_ext"); + goto out; + } + + ret = ucfg_get_smart_chainmask_enabled(hdd_ctx->psoc, + &check_value); + if (QDF_IS_STATUS_SUCCESS(ret)) { + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_smart_chainmask_scheme, + (int)check_value, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed to set wmi_pdev_param_smart_chainmask_scheme"); + goto out; + } + } + + ret = ucfg_get_alternative_chainmask_enabled(hdd_ctx->psoc, + &check_value); + if (QDF_IS_STATUS_SUCCESS(ret)) { + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_alternative_chainmask_scheme, + (int)check_value, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed to set wmi_pdev_param_alternative_chainmask_scheme"); + goto out; + } + } + + ret = ucfg_fwol_get_ani_enabled(hdd_ctx->psoc, &check_value); + if (QDF_IS_STATUS_SUCCESS(ret)) { + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_ani_enable, + (int)check_value, index++, + MAX_PDEV_PRE_ENABLE_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed to set wmi_pdev_param_ani_enable"); + goto out; + } + } + + ret = hdd_set_pcie_params(hdd_ctx, index, setparam); + if (QDF_IS_STATUS_ERROR(ret)) + goto out; + else + index++; + ret = sme_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed to send pdev set params"); + goto out; + } + + /* Configure global firmware params */ + ret = ucfg_fwol_configure_global_params(hdd_ctx->psoc, hdd_ctx->pdev); + if (ret) + goto out; + + status = hdd_set_sme_chan_list(hdd_ctx); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to init channel list: %d", status); + ret = qdf_status_to_os_return(status); + goto out; + } + + if (!hdd_update_config_cfg(hdd_ctx)) { + hdd_err("config update failed"); + ret = -EINVAL; + goto out; + } + hdd_init_channel_avoidance(hdd_ctx); + +out: + return ret; +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * wlan_hdd_p2p_lo_event_callback - P2P listen offload stop event handler + * @context: context registered with sme_register_p2p_lo_event(). HDD + * always registers a hdd context pointer + * @evt:event structure pointer + * + * This is the p2p listen offload stop event handler, it sends vendor + * event back to supplicant to notify the stop reason. + * + * Return: None + */ +static void wlan_hdd_p2p_lo_event_callback(void *context, + struct sir_p2p_lo_event *evt) +{ + struct hdd_context *hdd_ctx = context; + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + if (!hdd_ctx) { + hdd_err("Invalid HDD context pointer"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, evt->vdev_id); + if (!link_info) { + hdd_err("Cannot find adapter by vdev_id = %d", + evt->vdev_id); + return; + } + + vendor_event = + wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &link_info->adapter->wdev, + sizeof(uint32_t) + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON, + evt->reason_code)) { + hdd_err("nla put failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + hdd_debug("Sent P2P_LISTEN_OFFLOAD_STOP event for vdev_id = %d", + evt->vdev_id); +} +#else +static void wlan_hdd_p2p_lo_event_callback(void *context, + struct sir_p2p_lo_event *evt) +{ +} +#endif + +#ifdef FEATURE_WLAN_DYNAMIC_CVM +static inline int hdd_set_vc_mode_config(struct hdd_context *hdd_ctx) +{ + return sme_set_vc_mode_config(hdd_ctx->config->vc_mode_cfg_bitmap); +} +#else +static inline int hdd_set_vc_mode_config(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_adaptive_dwelltime_init() - initialization for adaptive dwell time config + * @hdd_ctx: HDD context + * + * This function sends the adaptive dwell time config configuration to the + * firmware via WMA + * + * Return: 0 - success, < 0 - failure + */ +static int hdd_adaptive_dwelltime_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct adaptive_dwelltime_params dwelltime_params; + + status = ucfg_fwol_get_all_adaptive_dwelltime_params(hdd_ctx->psoc, + &dwelltime_params); + status = ucfg_fwol_set_adaptive_dwelltime_config(&dwelltime_params); + + hdd_debug("Sending Adaptive Dwelltime Configuration to fw"); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send Adaptive Dwelltime configuration!"); + return -EAGAIN; + } + return 0; +} + +int hdd_dbs_scan_selection_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct wmi_dbs_scan_sel_params dbs_scan_params; + uint32_t i = 0; + uint8_t count = 0, numentries = 0; + uint8_t dual_mac_feature; + uint8_t dbs_scan_config[CDS_DBS_SCAN_PARAM_PER_CLIENT + * CDS_DBS_SCAN_CLIENTS_MAX]; + + status = ucfg_policy_mgr_get_dual_mac_feature(hdd_ctx->psoc, + &dual_mac_feature); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("can't get dual mac feature flag"); + return -EINVAL; + } + /* check if DBS is enabled or supported */ + if ((dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) || + (dual_mac_feature == ENABLE_DBS_CXN_AND_DISABLE_DBS_SCAN)) + return -EINVAL; + + hdd_string_to_u8_array(hdd_ctx->config->dbs_scan_selection, + dbs_scan_config, &numentries, + (CDS_DBS_SCAN_PARAM_PER_CLIENT + * CDS_DBS_SCAN_CLIENTS_MAX)); + + if (!numentries) { + hdd_debug("Do not send scan_selection_config"); + return 0; + } + + /* hdd_set_fw_log_params */ + dbs_scan_params.num_clients = 0; + while (count < (numentries - 2)) { + dbs_scan_params.module_id[i] = dbs_scan_config[count]; + dbs_scan_params.num_dbs_scans[i] = dbs_scan_config[count + 1]; + dbs_scan_params.num_non_dbs_scans[i] = + dbs_scan_config[count + 2]; + dbs_scan_params.num_clients++; + hdd_debug("module:%d NDS:%d NNDS:%d", + dbs_scan_params.module_id[i], + dbs_scan_params.num_dbs_scans[i], + dbs_scan_params.num_non_dbs_scans[i]); + count += CDS_DBS_SCAN_PARAM_PER_CLIENT; + i++; + } + + dbs_scan_params.pdev_id = 0; + + hdd_debug("clients:%d pdev:%d", + dbs_scan_params.num_clients, dbs_scan_params.pdev_id); + + status = sme_set_dbs_scan_selection_config(hdd_ctx->mac_handle, + &dbs_scan_params); + hdd_debug("Sending DBS Scan Selection Configuration to fw"); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send DBS Scan selection configuration!"); + return -EAGAIN; + } + return 0; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * hdd_set_auto_shutdown_cb() - Set auto shutdown callback + * @hdd_ctx: HDD context + * + * Set auto shutdown callback to get indications from firmware to indicate + * userspace to shutdown WLAN after a configured amount of inactivity. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_set_auto_shutdown_cb(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!hdd_ctx->config->wlan_auto_shutdown) + return 0; + + status = sme_set_auto_shutdown_cb(hdd_ctx->mac_handle, + wlan_hdd_auto_shutdown_cb); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Auto shutdown feature could not be enabled: %d", + status); + + return qdf_status_to_os_return(status); +} +#else +static int hdd_set_auto_shutdown_cb(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#ifdef MWS_COEX +#define MAX_PDEV_MWSCOEX_PARAMS 4 +/* params being sent: + * wmi_pdev_param_mwscoex_4g_allow_quick_ftdm + * wmi_pdev_param_mwscoex_set_5gnr_pwr_limit + * wmi_pdev_param_mwscoex_pcc_chavd_delay + * wmi_pdev_param_mwscoex_scc_chavd_delay + */ + +/** + * hdd_init_mws_coex() - Initialize MWS coex configurations + * @hdd_ctx: HDD context + * + * This function sends MWS-COEX 4G quick FTDM and + * MWS-COEX 5G-NR power limit to FW + * + * Return: 0 on success and errno on failure. + */ +static int hdd_init_mws_coex(struct hdd_context *hdd_ctx) +{ + int ret = 0; + uint32_t mws_coex_4g_quick_tdm = 0, mws_coex_5g_nr_pwr_limit = 0; + uint32_t mws_coex_pcc_channel_avoid_delay = 0; + uint32_t mws_coex_scc_channel_avoid_delay = 0; + struct dev_set_param setparam[MAX_PDEV_MWSCOEX_PARAMS] = {}; + uint8_t index = 0; + + ucfg_mlme_get_mws_coex_4g_quick_tdm(hdd_ctx->psoc, + &mws_coex_4g_quick_tdm); + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_mwscoex_4g_allow_quick_ftdm, + mws_coex_4g_quick_tdm, index++, + MAX_PDEV_MWSCOEX_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_mwscoex_4g_allow_quick_ftdm"); + goto error; + } + + ucfg_mlme_get_mws_coex_5g_nr_pwr_limit(hdd_ctx->psoc, + &mws_coex_5g_nr_pwr_limit); + ret = mlme_check_index_setparam( + setparam, + wmi_pdev_param_mwscoex_set_5gnr_pwr_limit, + mws_coex_5g_nr_pwr_limit, index++, + MAX_PDEV_MWSCOEX_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_mwscoex_set_5gnr_pwr_limit"); + goto error; + } + + ucfg_mlme_get_mws_coex_pcc_channel_avoid_delay( + hdd_ctx->psoc, + &mws_coex_pcc_channel_avoid_delay); + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_mwscoex_pcc_chavd_delay, + mws_coex_pcc_channel_avoid_delay, + index++, MAX_PDEV_MWSCOEX_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_mwscoex_pcc_chavd_delay"); + goto error; + } + + ucfg_mlme_get_mws_coex_scc_channel_avoid_delay( + hdd_ctx->psoc, + &mws_coex_scc_channel_avoid_delay); + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_mwscoex_scc_chavd_delay, + mws_coex_scc_channel_avoid_delay, + index++, MAX_PDEV_MWSCOEX_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("failed at wmi_pdev_param_mwscoex_scc_chavd_delay"); + goto error; + } + ret = sme_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("failed to send pdev MWSCOEX set params"); +error: + return ret; +} +#else +static int hdd_init_mws_coex(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#ifdef THERMAL_STATS_SUPPORT +static void hdd_thermal_stats_cmd_init(struct hdd_context *hdd_ctx) +{ + hdd_send_get_thermal_stats_cmd(hdd_ctx, thermal_stats_init, NULL, NULL); +} +#else +static void hdd_thermal_stats_cmd_init(struct hdd_context *hdd_ctx) +{ +} +#endif + +#ifdef WLAN_FEATURE_CAL_FAILURE_TRIGGER +/** + * hdd_cal_fail_send_event()- send calibration failure information + * @cal_type: calibration type + * @reason: reason for calibration failure + * + * This Function sends calibration failure diag event + * + * Return: void. + */ +static void hdd_cal_fail_send_event(uint8_t cal_type, uint8_t reason) +{ + /* + * For now we are going with the print. Once CST APK has support to + * read the diag events then we will add the diag event here. + */ + hdd_debug("Received cal failure event with cal_type:%x reason:%x", + cal_type, reason); +} +#else +static inline void hdd_cal_fail_send_event(uint8_t cal_type, uint8_t reason) +{ +} +#endif + +/** + * hdd_features_init() - Init features + * @hdd_ctx: HDD context + * + * Initialize features and their feature context after WLAN firmware is up. + * + * Return: 0 on success and errno on failure. + */ +static int hdd_features_init(struct hdd_context *hdd_ctx) +{ + struct tx_power_limit hddtxlimit; + QDF_STATUS status; + int ret; + mac_handle_t mac_handle; + bool b_cts2self, is_imps_enabled; + bool rf_test_mode; + bool std_6ghz_conn_policy; + uint32_t fw_data_stall_evt; + bool disable_vlp_sta_conn_sp_ap; + + hdd_enter(); + + ret = hdd_init_mws_coex(hdd_ctx); + if (ret) + hdd_warn("Error initializing mws-coex"); + + /* FW capabilities received, Set the Dot11 mode */ + mac_handle = hdd_ctx->mac_handle; + sme_setdef_dot11mode(mac_handle); + + ucfg_mlme_is_imps_enabled(hdd_ctx->psoc, &is_imps_enabled); + hdd_set_idle_ps_config(hdd_ctx, is_imps_enabled); + + fw_data_stall_evt = ucfg_dp_fw_data_stall_evt_enabled(); + + /* Send Enable/Disable data stall detection cmd to FW */ + sme_cli_set_command(0, wmi_pdev_param_data_stall_detect_enable, + fw_data_stall_evt, PDEV_CMD); + + ucfg_mlme_get_go_cts2self_for_sta(hdd_ctx->psoc, &b_cts2self); + if (b_cts2self) + sme_set_cts2self_for_p2p_go(mac_handle); + + if (hdd_set_vc_mode_config(hdd_ctx)) + hdd_warn("Error in setting Voltage Corner mode config to FW"); + + if (ucfg_dp_rx_ol_init(hdd_ctx->psoc, hdd_ctx->is_wifi3_0_target)) + hdd_err("Unable to initialize Rx LRO/GRO in fw"); + + if (hdd_adaptive_dwelltime_init(hdd_ctx)) + hdd_err("Unable to send adaptive dwelltime setting to FW"); + + if (hdd_dbs_scan_selection_init(hdd_ctx)) + hdd_err("Unable to send DBS scan selection setting to FW"); + + ret = hdd_init_thermal_info(hdd_ctx); + if (ret) { + hdd_err("Error while initializing thermal information"); + return ret; + } + + /** + * In case of SSR/PDR, if pktlog was enabled manually before + * SSR/PDR, then enable it again automatically after Wlan + * device up. + * During SSR/PDR, pktlog will be disabled as part of + * hdd_features_deinit if pktlog is enabled in ini. + * Re-enable pktlog in SSR case, if pktlog is enabled in ini. + */ + if (hdd_get_conparam() != QDF_GLOBAL_MONITOR_MODE && + (cds_is_packet_log_enabled() || + (cds_is_driver_recovering() && hdd_ctx->is_pktlog_enabled))) + hdd_pktlog_enable_disable(hdd_ctx, true, 0, 0); + + hddtxlimit.txPower2g = ucfg_get_tx_power(hdd_ctx->psoc, BAND_2G); + hddtxlimit.txPower5g = ucfg_get_tx_power(hdd_ctx->psoc, BAND_5G); + status = sme_txpower_limit(mac_handle, &hddtxlimit); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Error setting txlimit in sme: %d", status); + + wlan_hdd_tsf_init(hdd_ctx); + + status = sme_enable_disable_chanavoidind_event(mac_handle, 0); + if (QDF_IS_STATUS_ERROR(status) && (status != QDF_STATUS_E_NOSUPPORT)) { + hdd_err("Failed to disable Chan Avoidance Indication"); + return -EINVAL; + } + + /* register P2P Listen Offload event callback */ + if (wma_is_p2p_lo_capable()) + sme_register_p2p_lo_event(mac_handle, hdd_ctx, + wlan_hdd_p2p_lo_event_callback); + wlan_hdd_register_mcc_quota_event_callback(hdd_ctx); + ret = hdd_set_auto_shutdown_cb(hdd_ctx); + + if (ret) + return -EINVAL; + + wlan_hdd_init_chan_info(hdd_ctx); + wlan_hdd_twt_init(hdd_ctx); + wlan_hdd_gpio_wakeup_init(hdd_ctx); + + status = ucfg_mlme_is_rf_test_mode_enabled(hdd_ctx->psoc, + &rf_test_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get rf test mode failed"); + return QDF_STATUS_E_FAILURE; + } + + if (rf_test_mode) { + wlan_cm_set_check_6ghz_security(hdd_ctx->psoc, false); + wlan_cm_set_6ghz_key_mgmt_mask(hdd_ctx->psoc, + DEFAULT_KEYMGMT_6G_MASK); + } + + status = ucfg_mlme_is_standard_6ghz_conn_policy_enabled(hdd_ctx->psoc, + &std_6ghz_conn_policy); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get 6ghz standard connection policy failed"); + return QDF_STATUS_E_FAILURE; + } + if (std_6ghz_conn_policy) + wlan_cm_set_standard_6ghz_conn_policy(hdd_ctx->psoc, true); + + status = ucfg_mlme_is_disable_vlp_sta_conn_to_sp_ap_enabled( + hdd_ctx->psoc, + &disable_vlp_sta_conn_sp_ap); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get disable vlp sta conn to sp flag failed"); + return QDF_STATUS_E_FAILURE; + } + + if (disable_vlp_sta_conn_sp_ap) + wlan_cm_set_disable_vlp_sta_conn_to_sp_ap(hdd_ctx->psoc, true); + + hdd_thermal_stats_cmd_init(hdd_ctx); + sme_set_cal_failure_event_cb(hdd_ctx->mac_handle, + hdd_cal_fail_send_event); + + hdd_exit(); + return 0; +} + +/** + * hdd_register_bcn_cb() - register scan beacon callback + * @hdd_ctx: Pointer to the HDD context + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS hdd_register_bcn_cb(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = ucfg_scan_register_bcn_cb(hdd_ctx->psoc, + wlan_cfg80211_inform_bss_frame, + SCAN_CB_TYPE_INFORM_BCN); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to register SCAN_CB_TYPE_INFORM_BCN with status code %08d [x%08x]", + status, status); + return status; + } + + status = ucfg_scan_register_bcn_cb(hdd_ctx->psoc, + wlan_cfg80211_unlink_bss_list, + SCAN_CB_TYPE_UNLINK_BSS); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to refister SCAN_CB_TYPE_FLUSH_BSS with status code %08d [x%08x]", + status, status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_v2_flow_pool_map() - Flow pool create callback when vdev is active + * @vdev_id: vdev_id, corresponds to flow_pool + * + * Return: none. + */ +static void hdd_v2_flow_pool_map(int vdev_id) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_objmgr_vdev *vdev; + + if (!hdd_ctx) { + hdd_err("HDD context null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc, vdev_id, + WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Invalid VDEV %d", vdev_id); + return; + } + + if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev) || + policy_mgr_is_set_link_in_progress(wlan_vdev_get_psoc(vdev))) { + hdd_info_rl("Link switch/set_link is ongoing, do not invoke flow pool map"); + goto release_ref; + } + + status = cdp_flow_pool_map(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, vdev_id); + /* + * For Adrastea flow control v2 is based on FW MAP events, + * so this above callback is not implemented. + * Hence this is not actual failure. Dont return failure + */ + if ((status != QDF_STATUS_SUCCESS) && + (status != QDF_STATUS_E_INVAL)) { + hdd_err("vdev_id: %d, failed to create flow pool status %d", + vdev_id, status); + } + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); +} + +/** + * hdd_v2_flow_pool_unmap() - Flow pool create callback when vdev is not active + * @vdev_id: vdev_id, corresponds to flow_pool + * + * Return: none. + */ +static void hdd_v2_flow_pool_unmap(int vdev_id) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_objmgr_vdev *vdev; + + if (!hdd_ctx) { + hdd_err("HDD context null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc, vdev_id, + WLAN_OSIF_ID); + if (!vdev) { + hdd_err("Invalid VDEV %d", vdev_id); + return; + } + + if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev)) { + hdd_info("Link switch ongoing do not invoke flow pool unmap"); + goto release_ref; + } + + cdp_flow_pool_unmap(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, vdev_id); +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_ID); +} + +static void hdd_hastings_bt_war_initialize(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->config->iface_change_wait_time) + hdd_hastings_bt_war_disable_fw(hdd_ctx); + else + hdd_hastings_bt_war_enable_fw(hdd_ctx); +} + +#define MAX_PDEV_CFG_CDS_PARAMS 8 +/* params being sent: + * wmi_pdev_param_set_iot_pattern + * wmi_pdev_param_max_mpdus_in_ampdu + * wmi_pdev_param_enable_rts_sifs_bursting + * wmi_pdev_param_peer_stats_info_enable + * wmi_pdev_param_abg_mode_tx_chain_num + * wmi_pdev_param_gcmp_support_enable + * wmi_pdev_auto_detect_power_failure + * wmi_pdev_param_fast_pwr_transition + */ + +/** + * hdd_configure_cds() - Configure cds modules + * @hdd_ctx: HDD context + * + * Enable Cds modules after WLAN firmware is up. + * + * Return: 0 on success and errno on failure. + */ +int hdd_configure_cds(struct hdd_context *hdd_ctx) +{ + int ret; + QDF_STATUS status; + int set_value; + mac_handle_t mac_handle; + bool enable_rts_sifsbursting; + uint8_t enable_phy_reg_retention; + uint8_t max_mpdus_inampdu, is_force_1x1 = 0; + uint32_t num_abg_tx_chains = 0; + uint16_t num_11b_tx_chains = 0; + uint16_t num_11ag_tx_chains = 0; + struct policy_mgr_dp_cbacks dp_cbs = {0}; + bool value; + enum pmo_auto_pwr_detect_failure_mode auto_power_fail_mode; + bool bval = false; + uint8_t max_index = MAX_PDEV_CFG_CDS_PARAMS; + struct dev_set_param setparam[MAX_PDEV_CFG_CDS_PARAMS] = {}; + uint8_t index = 0; + uint8_t next_index = 0; + mac_handle = hdd_ctx->mac_handle; + + status = ucfg_policy_mgr_get_force_1x1(hdd_ctx->psoc, &is_force_1x1); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to get force 1x1 value"); + goto out; + } + if (is_force_1x1) { + status = mlme_check_index_setparam( + setparam, + wmi_pdev_param_set_iot_pattern, + 1, index++, + max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_pdev_param_set_iot_pattern"); + goto out; + } + } + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(mac_handle, + hdd_chip_pwr_save_fail_detected_cb); + + status = ucfg_get_max_mpdus_inampdu(hdd_ctx->psoc, + &max_mpdus_inampdu); + if (status) { + hdd_err("Failed to get max mpdus in ampdu value"); + goto out; + } + + if (max_mpdus_inampdu) { + set_value = max_mpdus_inampdu; + status = mlme_check_index_setparam( + setparam, + wmi_pdev_param_max_mpdus_in_ampdu, + set_value, index++, + max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_pdev_param_max_mpdus_in_ampdu"); + goto out; + } + } + + status = ucfg_get_enable_rts_sifsbursting(hdd_ctx->psoc, + &enable_rts_sifsbursting); + if (status) { + hdd_err("Failed to get rts sifs bursting value"); + goto out; + } + + if (enable_rts_sifsbursting) { + set_value = enable_rts_sifsbursting; + status = mlme_check_index_setparam( + setparam, + wmi_pdev_param_enable_rts_sifs_bursting, + set_value, index++, + max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed at wmi_pdev_param_enable_rts_sifs_bursting"); + goto out; + } + } + + ucfg_mlme_get_sap_get_peer_info(hdd_ctx->psoc, &value); + if (value) { + set_value = value; + status = mlme_check_index_setparam( + setparam, + wmi_pdev_param_peer_stats_info_enable, + set_value, index++, + max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed at wmi_pdev_param_peer_stats_info_enable"); + goto out; + } + } + + status = ucfg_mlme_get_num_11b_tx_chains(hdd_ctx->psoc, + &num_11b_tx_chains); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to get num_11b_tx_chains"); + goto out; + } + + status = ucfg_mlme_get_num_11ag_tx_chains(hdd_ctx->psoc, + &num_11ag_tx_chains); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to get num_11ag_tx_chains"); + goto out; + } + + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + if (!bval) { + if (num_11b_tx_chains > 1) + num_11b_tx_chains = 1; + if (num_11ag_tx_chains > 1) + num_11ag_tx_chains = 1; + } + WMI_PDEV_PARAM_SET_11B_TX_CHAIN_NUM(num_abg_tx_chains, + num_11b_tx_chains); + WMI_PDEV_PARAM_SET_11AG_TX_CHAIN_NUM(num_abg_tx_chains, + num_11ag_tx_chains); + status = mlme_check_index_setparam(setparam, + wmi_pdev_param_abg_mode_tx_chain_num, + num_abg_tx_chains, index++, + max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed at wmi_pdev_param_abg_mode_tx_chain_num"); + goto out; + } + /* Send some pdev params to maintain legacy order of pdev set params + * at hdd_pre_enable_configure + */ + status = sme_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send 1st set of pdev params"); + goto out; + } + if (!ucfg_reg_is_regdb_offloaded(hdd_ctx->psoc)) + ucfg_reg_program_default_cc(hdd_ctx->pdev, + hdd_ctx->reg.reg_domain); + + ret = hdd_pre_enable_configure(hdd_ctx); + if (ret) { + hdd_err("Failed to pre-configure cds"); + goto out; + } + + /* Always get latest IPA resources allocated from cds_open and configure + * IPA module before configuring them to FW. Sequence required as crash + * observed otherwise. + */ + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + ipa_disable_register_cb(); + } else { + status = ipa_register_is_ipa_ready(hdd_ctx->pdev); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ipa_register_is_ipa_ready failed"); + goto out; + } + } + + /* + * Start CDS which starts up the SME/MAC/HAL modules and everything + * else + */ + status = cds_enable(hdd_ctx->psoc); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("cds_enable failed"); + goto out; + } + + status = hdd_post_cds_enable_config(hdd_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hdd_post_cds_enable_config failed"); + goto cds_disable; + } + status = hdd_register_bcn_cb(hdd_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("hdd_register_bcn_cb failed"); + goto cds_disable; + } + + ret = hdd_features_init(hdd_ctx); + if (ret) + goto cds_disable; + + /* + * Donot disable rx offload on concurrency for lithium and + * beryllium based targets + */ + if (!hdd_ctx->is_wifi3_0_target) + if (ucfg_dp_is_ol_enabled(hdd_ctx->psoc)) + dp_cbs.hdd_disable_rx_ol_in_concurrency = + hdd_disable_rx_ol_in_concurrency; + dp_cbs.hdd_set_rx_mode_rps_cb = ucfg_dp_set_rx_mode_rps; + dp_cbs.hdd_ipa_set_mcc_mode_cb = hdd_ipa_set_mcc_mode; + dp_cbs.hdd_v2_flow_pool_map = hdd_v2_flow_pool_map; + dp_cbs.hdd_v2_flow_pool_unmap = hdd_v2_flow_pool_unmap; + if (ucfg_ipa_set_perf_level_bw_enabled(hdd_ctx->pdev)) + dp_cbs.hdd_ipa_set_perf_level_bw = hdd_ipa_set_perf_level_bw; + status = policy_mgr_register_dp_cb(hdd_ctx->psoc, &dp_cbs); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("Failed to register DP cb with Policy Manager"); + goto cds_disable; + } + status = policy_mgr_register_mode_change_cb(hdd_ctx->psoc, + wlan_hdd_send_mode_change_event); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("Failed to register mode change cb with Policy Manager"); + goto cds_disable; + } + + if (hdd_green_ap_enable_egap(hdd_ctx)) + hdd_debug("enhance green ap is not enabled"); + + hdd_register_green_ap_callback(hdd_ctx->pdev); + + if (0 != wlan_hdd_set_wow_pulse(hdd_ctx, true)) + hdd_debug("Failed to set wow pulse"); + + max_index = max_index - index; + status = mlme_check_index_setparam( + setparam + index, + wmi_pdev_param_gcmp_support_enable, + ucfg_fwol_get_gcmp_enable(hdd_ctx->psoc), + next_index++, max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_pdev_param_gcmp_support_enable"); + goto out; + } + + auto_power_fail_mode = + ucfg_pmo_get_auto_power_fail_mode(hdd_ctx->psoc); + status = mlme_check_index_setparam( + setparam + index, + wmi_pdev_auto_detect_power_failure, + auto_power_fail_mode, + next_index++, max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_pdev_auto_detect_power_failure"); + goto out; + } + + status = ucfg_get_enable_phy_reg_retention(hdd_ctx->psoc, + &enable_phy_reg_retention); + + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + if (enable_phy_reg_retention) { + status = mlme_check_index_setparam( + setparam + index, + wmi_pdev_param_fast_pwr_transition, + enable_phy_reg_retention, + next_index++, max_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_pdev_param_fast_pwr_transition"); + goto out; + } + } + /*Send remaining pdev setparams from array*/ + status = sme_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, + setparam + index, + next_index); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to send 2nd set of pdev set params"); + goto out; + } + + hdd_hastings_bt_war_initialize(hdd_ctx); + + wlan_hdd_hang_event_notifier_register(hdd_ctx); + return 0; + +cds_disable: + cds_disable(hdd_ctx->psoc); + +out: + return -EINVAL; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static void hdd_deregister_policy_manager_callback( + struct wlan_objmgr_psoc *psoc) +{ + if (QDF_STATUS_SUCCESS != + policy_mgr_deregister_hdd_cb(psoc)) { + hdd_err("HDD callback deregister with policy manager failed"); + } +} +#else +static void hdd_deregister_policy_manager_callback( + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode) +{ + void *hif_ctx; + qdf_device_t qdf_ctx; + QDF_STATUS qdf_status; + bool is_recovery_stop = cds_is_driver_recovering(); + int ret = 0; + int debugfs_threads; + struct target_psoc_info *tgt_hdl; + struct bbm_params param = {0}; + + hdd_enter(); + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return -EINVAL; + + cds_set_driver_state_module_stop(true); + + debugfs_threads = hdd_return_debugfs_threads_count(); + + if (debugfs_threads > 0 || hdd_ctx->is_wiphy_suspended) { + hdd_warn("Debugfs threads %d, wiphy suspend %d", + debugfs_threads, hdd_ctx->is_wiphy_suspended); + + if (IS_IDLE_STOP && !ftm_mode) { + hdd_psoc_idle_timer_start(hdd_ctx); + cds_set_driver_state_module_stop(false); + + ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc); + return -EAGAIN; + } + } + + ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc); + hdd_deregister_policy_manager_callback(hdd_ctx->psoc); + + /* free user wowl patterns */ + hdd_free_user_wowl_ptrns(); + + switch (hdd_ctx->driver_status) { + case DRIVER_MODULES_UNINITIALIZED: + hdd_debug("Modules not initialized just return"); + goto done; + case DRIVER_MODULES_CLOSED: + hdd_debug("Modules already closed"); + goto done; + case DRIVER_MODULES_ENABLED: + hdd_debug("Wlan transitioning (CLOSED <- ENABLED)"); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_disable_power_management(hdd_ctx); + break; + } + + if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) + break; + + hdd_skip_acs_scan_timer_deinit(hdd_ctx); + + hdd_disable_power_management(hdd_ctx); + + if (hdd_get_conparam() == QDF_GLOBAL_MISSION_MODE) + ucfg_dp_direct_link_deinit(hdd_ctx->psoc, + is_recovery_stop); + + if (hdd_deconfigure_cds(hdd_ctx)) { + hdd_err("Failed to de-configure CDS"); + QDF_ASSERT(0); + ret = -EINVAL; + } + hdd_debug("successfully Disabled the CDS modules!"); + + break; + default: + QDF_DEBUG_PANIC("Unknown driver state:%d", + hdd_ctx->driver_status); + ret = -EINVAL; + goto done; + } + + hdd_destroy_sysfs_files(); + hdd_debug("Closing CDS modules!"); + + if (hdd_get_conparam() != QDF_GLOBAL_EPPING_MODE) { + qdf_status = cds_post_disable(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to process post CDS disable! :%d", + qdf_status); + ret = -EINVAL; + QDF_ASSERT(0); + } + + hdd_unregister_notifiers(hdd_ctx); + /* De-register the SME callbacks */ + hdd_deregister_cb(hdd_ctx); + + hdd_runtime_suspend_context_deinit(hdd_ctx); + + qdf_status = cds_dp_close(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("Failed to stop CDS DP: %d", qdf_status); + ret = -EINVAL; + QDF_ASSERT(0); + } + + hdd_component_pdev_close(hdd_ctx->pdev); + dispatcher_pdev_close(hdd_ctx->pdev); + ret = hdd_objmgr_release_and_destroy_pdev(hdd_ctx); + if (ret) { + hdd_err("Failed to destroy pdev; errno:%d", ret); + QDF_ASSERT(0); + } + + qdf_status = cds_close(hdd_ctx->psoc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_warn("Failed to stop CDS: %d", qdf_status); + ret = -EINVAL; + QDF_ASSERT(0); + } + + qdf_status = wbuff_module_deinit(); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("WBUFF de-init unsuccessful; status: %d", + qdf_status); + + hdd_component_psoc_close(hdd_ctx->psoc); + /* pdev close and destroy use tx rx ops so call this here */ + wlan_global_lmac_if_close(hdd_ctx->psoc); + } + + /* + * Reset total mac phy during module stop such that during + * next module start same psoc is used to populate new service + * ready data + */ + tgt_hdl = wlan_psoc_get_tgt_if_handle(hdd_ctx->psoc); + if (tgt_hdl) + target_psoc_set_total_mac_phy_cnt(tgt_hdl, 0); + + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + ret = -EINVAL; + + if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) { + epping_disable(); + epping_close(); + } + + wlan_connectivity_logging_stop(); + + ucfg_ipa_component_config_free(); + + hdd_hif_close(hdd_ctx, hif_ctx); + + ol_cds_free(); + + if (IS_IDLE_STOP) { + ret = pld_power_off(qdf_ctx->dev); + if (ret) + hdd_err("Failed to power down device; errno:%d", ret); + } + + /* Free the cache channels of the command SET_DISABLE_CHANNEL_LIST */ + wlan_hdd_free_cache_channels(hdd_ctx); + hdd_driver_mem_cleanup(); + + /* Free the resources allocated while storing SAR config. These needs + * to be freed only in the case when it is not SSR. As in the case of + * SSR, the values needs to be intact so that it can be restored during + * reinit path. + */ + if (!is_recovery_stop) + wlan_hdd_free_sar_config(hdd_ctx); + + hdd_sap_destroy_ctx_all(hdd_ctx, is_recovery_stop); + hdd_sta_destroy_ctx_all(hdd_ctx); + + /* + * Reset the driver mode specific bus bw level + */ + param.policy = BBM_DRIVER_MODE_POLICY; + param.policy_info.driver_mode = QDF_GLOBAL_MAX_MODE; + ucfg_dp_bbm_apply_independent_policy(hdd_ctx->psoc, ¶m); + + hdd_deinit_adapter_ops_wq(hdd_ctx); + hdd_deinit_qdf_ctx(hdd_debug_domain_get()); + + hdd_check_for_leaks(hdd_ctx, is_recovery_stop); + hdd_debug_domain_set(QDF_DEBUG_DOMAIN_INIT); + hdd_deinit_qdf_ctx(hdd_debug_domain_get()); + qdf_dma_invalid_buf_list_deinit(); + + /* Restore PS params for monitor mode */ + if (hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + hdd_restore_all_ps(hdd_ctx); + + /* Once the firmware sequence is completed reset this flag */ + hdd_ctx->imps_enabled = false; + hdd_ctx->is_dual_mac_cfg_updated = false; + hdd_ctx->driver_status = DRIVER_MODULES_CLOSED; + hdd_ctx->is_fw_dbg_log_levels_configured = false; + hdd_debug("Wlan transitioned (now CLOSED)"); + +done: + hdd_exit(); + + return ret; +} + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * hdd_state_info_dump() - prints state information of hdd layer + * @buf_ptr: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of hdd layer + * + * Return: None + */ +static void hdd_state_info_dump(char **buf_ptr, uint16_t *size) +{ + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *sta_ctx; + struct hdd_adapter *adapter, *next_adapter = NULL; + uint16_t len = 0; + char *buf = *buf_ptr; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_STATE_INFO_DUMP; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + hdd_debug("size of buffer: %d", *size); + + len += scnprintf(buf + len, *size - len, "\n is_wiphy_suspended %d", + hdd_ctx->is_wiphy_suspended); + len += scnprintf(buf + len, *size - len, "\n is_scheduler_suspended %d", + hdd_ctx->is_scheduler_suspended); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + len += + scnprintf(buf + len, *size - len, "\n device name: %s", + adapter->dev->name); + len += + scnprintf(buf + len, *size - len, "\n device_mode: %d", + adapter->device_mode); + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + len += scnprintf(buf + len, *size - len, + "\n conn_state: %d", + sta_ctx->conn_info.conn_state); + break; + default: + break; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + *size -= len; + *buf_ptr += len; +} + +/** + * hdd_register_debug_callback() - registration function for hdd layer + * to print hdd state information + * + * Return: None + */ +static void hdd_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_HDD, &hdd_state_info_dump); +} +#else /* WLAN_FEATURE_MEMDUMP_ENABLE */ +static void hdd_register_debug_callback(void) +{ +} +#endif /* WLAN_FEATURE_MEMDUMP_ENABLE */ + +/* + * wlan_init_bug_report_lock() - Initialize bug report lock + * + * This function is used to create bug report lock + * + * Return: None + */ +static void wlan_init_bug_report_lock(void) +{ + struct cds_context *p_cds_context; + + p_cds_context = cds_get_global_context(); + if (!p_cds_context) { + hdd_err("cds context is NULL"); + return; + } + + qdf_spinlock_create(&p_cds_context->bug_report_lock); +} + +#ifdef DISABLE_CHANNEL_LIST +static QDF_STATUS wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) +{ + return qdf_mutex_create(&hdd_ctx->cache_channel_lock); +} +#else +static QDF_STATUS wlan_hdd_cache_chann_mutex_create(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS hdd_open_adapter_no_trans(struct hdd_context *hdd_ctx, + enum QDF_OPMODE op_mode, + const char *iface_name, + uint8_t *mac_addr_bytes, + struct hdd_adapter_create_param *params) +{ + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter; + QDF_STATUS status; + int errno; + + QDF_BUG(rtnl_is_locked()); + + errno = osif_vdev_sync_create(hdd_ctx->parent_dev, &vdev_sync); + if (errno) + return qdf_status_from_os_return(errno); + + adapter = hdd_open_adapter(hdd_ctx, op_mode, iface_name, + mac_addr_bytes, NET_NAME_UNKNOWN, true, + params); + if (!adapter) { + status = QDF_STATUS_E_INVAL; + goto destroy_sync; + } + + osif_vdev_sync_register(adapter->dev, vdev_sync); + + return QDF_STATUS_SUCCESS; + +destroy_sync: + osif_vdev_sync_destroy(vdev_sync); + + return status; +} + +#ifdef WLAN_OPEN_P2P_INTERFACE +/** + * hdd_open_p2p_interface - Open P2P interface + * @hdd_ctx: HDD context + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_open_p2p_interface(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + bool p2p_dev_addr_admin; + bool is_p2p_locally_administered = false; + struct hdd_adapter_create_param params = {0}; + + cfg_p2p_get_device_addr_admin(hdd_ctx->psoc, &p2p_dev_addr_admin); + + if (p2p_dev_addr_admin) { + if (hdd_ctx->num_provisioned_addr && + !(hdd_ctx->provisioned_mac_addr[0].bytes[0] & 0x02)) { + hdd_ctx->p2p_device_address = + hdd_ctx->provisioned_mac_addr[0]; + + /* + * Generate the P2P Device Address. This consists of + * the device's primary MAC address with the locally + * administered bit set. + */ + + hdd_ctx->p2p_device_address.bytes[0] |= 0x02; + is_p2p_locally_administered = true; + } else if (!(hdd_ctx->derived_mac_addr[0].bytes[0] & 0x02)) { + hdd_ctx->p2p_device_address = + hdd_ctx->derived_mac_addr[0]; + /* + * Generate the P2P Device Address. This consists of + * the device's primary MAC address with the locally + * administered bit set. + */ + hdd_ctx->p2p_device_address.bytes[0] |= 0x02; + is_p2p_locally_administered = true; + } + } + if (!is_p2p_locally_administered) { + uint8_t *p2p_dev_addr; + + p2p_dev_addr = wlan_hdd_get_intf_addr(hdd_ctx, + QDF_P2P_DEVICE_MODE); + if (!p2p_dev_addr) { + hdd_err("Failed to get MAC address for new p2p device"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(hdd_ctx->p2p_device_address.bytes, + p2p_dev_addr, QDF_MAC_ADDR_SIZE); + } + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_P2P_DEVICE_MODE, + "p2p%d", + hdd_ctx->p2p_device_address.bytes, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + if (!is_p2p_locally_administered) + wlan_hdd_release_intf_addr(hdd_ctx, + hdd_ctx->p2p_device_address.bytes); + hdd_err("Failed to open p2p interface"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS hdd_open_p2p_interface(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS hdd_open_ocb_interface(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint8_t *mac_addr; + struct hdd_adapter_create_param params = {0}; + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_OCB_MODE); + if (!mac_addr) + return QDF_STATUS_E_INVAL; + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_OCB_MODE, + "wlanocb%d", mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + hdd_err("Failed to open 802.11p interface"); + } + + return status; +} + +static QDF_STATUS hdd_open_concurrent_interface(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + const char *iface_name; + uint8_t *mac_addr; + struct hdd_adapter_create_param params = {0}; + + if (qdf_str_eq(hdd_ctx->config->enable_concurrent_sta, "")) + return QDF_STATUS_SUCCESS; + + iface_name = hdd_ctx->config->enable_concurrent_sta; + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_STA_MODE); + if (!mac_addr) + return QDF_STATUS_E_INVAL; + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, + iface_name, mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + hdd_err("Failed to open concurrent station interface"); + } + + return status; +} + +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +static inline void +hdd_adapter_open_set_max_active_links(struct hdd_adapter_create_param *params) +{ + if (params->is_add_virtual_iface || !params->is_ml_adapter) + params->num_sessions = 1; + else + params->num_sessions = 2; +} +#else +static inline void +hdd_adapter_open_set_max_active_links(struct hdd_adapter_create_param *params) +{ + params->num_sessions = 1; +} +#endif + +static QDF_STATUS +hdd_open_adapters_for_mission_mode(struct hdd_context *hdd_ctx) +{ + enum dot11p_mode dot11p_mode; + QDF_STATUS status; + uint8_t *mac_addr; + struct hdd_adapter_create_param params = {0}; + bool eht_capab = 0; + + ucfg_mlme_get_dot11p_mode(hdd_ctx->psoc, &dot11p_mode); + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + + /* Create only 802.11p interface? */ + if (dot11p_mode == CFG_11P_STANDALONE) + return hdd_open_ocb_interface(hdd_ctx); + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_STA_MODE); + if (!mac_addr) + return QDF_STATUS_E_INVAL; + + if (eht_capab) { + params.is_ml_adapter = true; + hdd_adapter_open_set_max_active_links(¶ms); + } + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, + "wlan%d", mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return status; + } + + /* opening concurrent STA is best effort, continue on error */ + hdd_open_concurrent_interface(hdd_ctx); + + status = hdd_open_p2p_interface(hdd_ctx); + if (status) + goto err_close_adapters; + + /* + * Create separate interface (wifi-aware0) for NAN. All NAN commands + * should go on this new interface. + */ + if (wlan_hdd_is_vdev_creation_allowed(hdd_ctx->psoc)) { + qdf_mem_zero(¶ms, sizeof(params)); + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_NAN_DISC_MODE); + if (!mac_addr) + goto err_close_adapters; + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_NAN_DISC_MODE, + "wifi-aware%d", mac_addr, + ¶ms); + if (status) { + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + goto err_close_adapters; + } + } + /* Open 802.11p Interface */ + if (dot11p_mode == CFG_11P_CONCURRENT) { + status = hdd_open_ocb_interface(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + goto err_close_adapters; + } + + if (eht_capab) + hdd_wlan_register_mlo_interfaces(hdd_ctx); + + return QDF_STATUS_SUCCESS; + +err_close_adapters: + hdd_close_all_adapters(hdd_ctx, true); + + return status; +} + +static QDF_STATUS hdd_open_adapters_for_ftm_mode(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint8_t *mac_addr; + struct hdd_adapter_create_param params = {0}; + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_FTM_MODE); + if (!mac_addr) + return QDF_STATUS_E_INVAL; + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_FTM_MODE, + "wlan%d", mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +hdd_open_adapters_for_monitor_mode(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint8_t *mac_addr; + struct hdd_adapter_create_param params = {0}; + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_MONITOR_MODE); + if (!mac_addr) + return QDF_STATUS_E_INVAL; + + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_MONITOR_MODE, + "wlan%d", mac_addr, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS hdd_open_adapters_for_epping_mode(struct hdd_context *hdd_ctx) +{ + epping_enable_adapter(); + return QDF_STATUS_SUCCESS; +} + +typedef QDF_STATUS (*hdd_open_mode_handler)(struct hdd_context *hdd_ctx); + +static const hdd_open_mode_handler +hdd_open_mode_handlers[QDF_GLOBAL_MAX_MODE] = { + [QDF_GLOBAL_MISSION_MODE] = hdd_open_adapters_for_mission_mode, + [QDF_GLOBAL_FTM_MODE] = hdd_open_adapters_for_ftm_mode, + [QDF_GLOBAL_MONITOR_MODE] = hdd_open_adapters_for_monitor_mode, + [QDF_GLOBAL_EPPING_MODE] = hdd_open_adapters_for_epping_mode, +}; + +static QDF_STATUS hdd_open_adapters_for_mode(struct hdd_context *hdd_ctx, + enum QDF_GLOBAL_MODE driver_mode) +{ + QDF_STATUS status; + + if (driver_mode < 0 || + driver_mode >= QDF_GLOBAL_MAX_MODE || + !hdd_open_mode_handlers[driver_mode]) { + hdd_err("Driver mode %d not supported", driver_mode); + return -ENOTSUPP; + } + + hdd_hold_rtnl_lock(); + status = hdd_open_mode_handlers[driver_mode](hdd_ctx); + hdd_release_rtnl_lock(); + + return status; +} + +int hdd_wlan_startup(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + int errno; + bool is_imps_enabled; + + hdd_enter(); + + qdf_nbuf_init_replenish_timer(); + + status = wlan_hdd_cache_chann_mutex_create(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + +#ifdef FEATURE_WLAN_CH_AVOID + mutex_init(&hdd_ctx->avoid_freq_lock); +#endif + + osif_request_manager_init(); + hdd_driver_memdump_init(); + + errno = hdd_init_regulatory_update_event(hdd_ctx); + if (errno) { + hdd_err("Failed to initialize regulatory update event; errno:%d", + errno); + goto memdump_deinit; + } + + errno = hdd_wlan_start_modules(hdd_ctx, false); + if (errno) { + hdd_err("Failed to start modules; errno:%d", errno); + goto memdump_deinit; + } + + if (hdd_get_conparam() == QDF_GLOBAL_EPPING_MODE) + return 0; + + wlan_hdd_update_wiphy(hdd_ctx); + + hdd_ctx->mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!hdd_ctx->mac_handle) + goto stop_modules; + + errno = hdd_wiphy_init(hdd_ctx); + if (errno) { + hdd_err("Failed to initialize wiphy; errno:%d", errno); + goto stop_modules; + } + + errno = hdd_initialize_mac_address(hdd_ctx); + if (errno) { + hdd_err("MAC initializtion failed: %d", errno); + goto unregister_wiphy; + } + + errno = register_netdevice_notifier(&hdd_netdev_notifier); + if (errno) { + hdd_err("register_netdevice_notifier failed; errno:%d", errno); + goto unregister_wiphy; + } + + wlan_hdd_update_11n_mode(hdd_ctx); + + hdd_lpass_notify_wlan_version(hdd_ctx); + + status = wlansap_global_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto unregister_notifiers; + + ucfg_mlme_is_imps_enabled(hdd_ctx->psoc, &is_imps_enabled); + hdd_set_idle_ps_config(hdd_ctx, is_imps_enabled); + hdd_debugfs_mws_coex_info_init(hdd_ctx); + hdd_debugfs_ini_config_init(hdd_ctx); + wlan_hdd_debugfs_unit_test_host_create(hdd_ctx); + wlan_hdd_create_mib_stats_lock(); + wlan_cfg80211_init_interop_issues_ap(hdd_ctx->pdev); + + hdd_exit(); + + return 0; + +unregister_notifiers: + unregister_netdevice_notifier(&hdd_netdev_notifier); + +unregister_wiphy: + qdf_dp_trace_deinit(); + wiphy_unregister(hdd_ctx->wiphy); + +stop_modules: + hdd_wlan_stop_modules(hdd_ctx, false); + +memdump_deinit: + hdd_driver_memdump_deinit(); + osif_request_manager_deinit(); + qdf_nbuf_deinit_replenish_timer(); + + if (cds_is_fw_down()) + hdd_err("Not setting the complete event as fw is down"); + else + hdd_start_complete(errno); + + hdd_exit(); + + return errno; +} + +QDF_STATUS hdd_psoc_create_vdevs(struct hdd_context *hdd_ctx) +{ + enum QDF_GLOBAL_MODE driver_mode = hdd_get_conparam(); + QDF_STATUS status; + + status = hdd_open_adapters_for_mode(hdd_ctx, driver_mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to create vdevs; status:%d", status); + return status; + } + + ucfg_dp_try_set_rps_cpu_mask(hdd_ctx->psoc); + + if (driver_mode != QDF_GLOBAL_FTM_MODE && + driver_mode != QDF_GLOBAL_EPPING_MODE) + hdd_psoc_idle_timer_start(hdd_ctx); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wlan_update_target_info() - update target type info + * @hdd_ctx: HDD context + * @context: hif context + * + * Update target info received from firmware in hdd context + * Return:None + */ + +void hdd_wlan_update_target_info(struct hdd_context *hdd_ctx, void *context) +{ + struct hif_target_info *tgt_info = hif_get_target_info_handle(context); + + if (!tgt_info) { + hdd_err("Target info is Null"); + return; + } + + hdd_ctx->target_type = tgt_info->target_type; +} + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * hdd_md_host_evt_cb - Callback for Motion Detection Event + * @ctx: HDD context + * @event: motion detect event + * + * Callback for Motion Detection Event. Re-enables Motion + * Detection again upon event + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and + * QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS hdd_md_host_evt_cb(void *ctx, struct sir_md_evt *event) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct sme_motion_det_en motion_det; + struct wlan_hdd_link_info *link_info; + + if (!ctx || !event) + return QDF_STATUS_E_INVAL; + + hdd_ctx = (struct hdd_context *)ctx; + if (wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_INVAL; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, event->vdev_id); + if (!link_info || + WLAN_HDD_ADAPTER_MAGIC != link_info->adapter->magic) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_INVAL; + } + + adapter = link_info->adapter; + /* When motion is detected, reset the motion_det_in_progress flag */ + if (event->status) + adapter->motion_det_in_progress = false; + + hdd_debug("Motion Detection CB vdev_id=%u, status=%u", + event->vdev_id, event->status); + + if (adapter->motion_detection_mode) { + motion_det.vdev_id = event->vdev_id; + motion_det.enable = 1; + hdd_debug("Motion Detect CB -> Enable Motion Detection again"); + sme_motion_det_enable(hdd_ctx->mac_handle, &motion_det); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_md_bl_evt_cb - Callback for Motion Detection Baseline Event + * @ctx: HDD context + * @event: motion detect baseline event + * + * Callback for Motion Detection Baseline completion + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and + * QDF_STATUS_E_FAILURE on failure + */ +QDF_STATUS hdd_md_bl_evt_cb(void *ctx, struct sir_md_bl_evt *event) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + if (!ctx || !event) + return QDF_STATUS_E_INVAL; + + hdd_ctx = (struct hdd_context *)ctx; + if (wlan_hdd_validate_context(hdd_ctx)) + return QDF_STATUS_E_INVAL; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, event->vdev_id); + if (!link_info || + WLAN_HDD_ADAPTER_MAGIC != link_info->adapter->magic) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return QDF_STATUS_E_INVAL; + } + + hdd_debug("Motion Detection Baseline CB vdev id=%u, baseline val = %d", + event->vdev_id, event->bl_baseline_value); + + link_info->adapter->motion_det_baseline_value = + event->bl_baseline_value; + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +static QDF_STATUS hdd_ssr_on_pagefault_cb(struct hdd_context *hdd_ctx) +{ + uint32_t ssr_frequency_on_pagefault; + qdf_time_t curr_time, ssr_threshold; + + hdd_enter(); + + if (!hdd_ctx) + return QDF_STATUS_E_NULL_VALUE; + + ssr_frequency_on_pagefault = + ucfg_pmo_get_ssr_frequency_on_pagefault(hdd_ctx->psoc); + + curr_time = qdf_get_system_uptime(); + ssr_threshold = qdf_system_msecs_to_ticks(ssr_frequency_on_pagefault); + + if (!hdd_ctx->last_pagefault_ssr_time || + (curr_time - hdd_ctx->last_pagefault_ssr_time) >= ssr_threshold) { + hdd_info("curr_time %lu last_pagefault_ssr_time %lu ssr_frequency %lu", + curr_time, hdd_ctx->last_pagefault_ssr_time, + ssr_threshold); + hdd_ctx->last_pagefault_ssr_time = curr_time; + cds_trigger_recovery(QDF_HOST_WAKEUP_REASON_PAGEFAULT); + + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_AGAIN; +} + +#define FW_PAGE_FAULT_IDX QCA_NL80211_VENDOR_SUBCMD_FW_PAGE_FAULT_REPORT_INDEX +static QDF_STATUS hdd_send_pagefault_report_to_user(struct hdd_context *hdd_ctx, + void *buf, uint32_t buf_len) +{ + struct sk_buff *event_buf; + int flags = cds_get_gfp_flags(); + uint8_t *ev_data = buf; + uint16_t event_len = NLMSG_HDRLEN + buf_len; + + event_buf = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + event_len, + FW_PAGE_FAULT_IDX, flags); + if (!event_buf) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + + if (nla_put(event_buf, QCA_WLAN_VENDOR_ATTR_FW_PAGE_FAULT_REPORT_DATA, + buf_len, ev_data)) { + hdd_debug("Failed to fill pagefault blob data"); + wlan_cfg80211_vendor_free_skb(event_buf); + return QDF_STATUS_E_FAILURE; + } + + wlan_cfg80211_vendor_event(event_buf, flags); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS hdd_pagefault_action_cb(void *buf, uint32_t buf_len) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return QDF_STATUS_E_NULL_VALUE; + + if (wlan_pmo_enable_ssr_on_page_fault(hdd_ctx->psoc)) + return hdd_ssr_on_pagefault_cb(hdd_ctx); + + return hdd_send_pagefault_report_to_user(hdd_ctx, buf, buf_len); +} + +/** + * hdd_register_cb - Register HDD callbacks. + * @hdd_ctx: HDD context + * + * Register the HDD callbacks to CDS/SME. + * + * Return: 0 for success or Error code for failure + */ +int hdd_register_cb(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + int ret = 0; + mac_handle_t mac_handle; + + hdd_enter(); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("in ftm mode, no need to register callbacks"); + return ret; + } + + mac_handle = hdd_ctx->mac_handle; + + sme_register_oem_data_rsp_callback(mac_handle, + hdd_send_oem_data_rsp_msg); + + sme_register_mgmt_frame_ind_callback(mac_handle, + hdd_indicate_mgmt_frame); + sme_set_tsfcb(mac_handle, hdd_get_tsf_cb, hdd_ctx); + sme_stats_ext_register_callback(mac_handle, + wlan_hdd_cfg80211_stats_ext_callback); + + sme_ext_scan_register_callback(mac_handle, + wlan_hdd_cfg80211_extscan_callback); + sme_stats_ext2_register_callback(mac_handle, + wlan_hdd_cfg80211_stats_ext2_callback); + + sme_multi_client_ll_rsp_register_callback(mac_handle, + hdd_latency_level_event_handler_cb); + + sme_set_rssi_threshold_breached_cb(mac_handle, + hdd_rssi_threshold_breached); + + sme_set_link_layer_stats_ind_cb(mac_handle, + wlan_hdd_cfg80211_link_layer_stats_callback); + + sme_rso_cmd_status_cb(mac_handle, wlan_hdd_rso_cmd_status_cb); + + sme_set_link_layer_ext_cb(mac_handle, + wlan_hdd_cfg80211_link_layer_stats_ext_callback); + sme_update_hidden_ssid_status_cb(mac_handle, + hdd_hidden_ssid_enable_roaming); + + status = sme_set_lost_link_info_cb(mac_handle, + hdd_lost_link_info_cb); + + wlan_hdd_register_cp_stats_cb(hdd_ctx); + hdd_dcs_register_cb(hdd_ctx); + + hdd_thermal_register_callbacks(hdd_ctx); + /* print error and not block the startup process */ + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set lost link info callback failed"); + + ret = hdd_register_data_stall_detect_cb(); + if (ret) { + hdd_err("Register data stall detect detect callback failed."); + return ret; + } + + wlan_hdd_dcc_register_for_dcc_stats_event(hdd_ctx); + + sme_register_set_connection_info_cb(mac_handle, + hdd_set_connection_in_progress, + hdd_is_connection_in_progress); + + status = sme_set_bt_activity_info_cb(mac_handle, + hdd_bt_activity_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("set bt activity info callback failed"); + + status = sme_register_tx_queue_cb(mac_handle, + hdd_tx_queue_cb); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Register tx queue callback failed"); + +#ifdef WLAN_FEATURE_MOTION_DETECTION + sme_set_md_host_evt_cb(mac_handle, hdd_md_host_evt_cb, (void *)hdd_ctx); + sme_set_md_bl_evt_cb(mac_handle, hdd_md_bl_evt_cb, (void *)hdd_ctx); +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + + mac_register_session_open_close_cb(hdd_ctx->mac_handle, + hdd_sme_close_session_callback, + hdd_common_roam_callback); + + sme_set_roam_scan_ch_event_cb(mac_handle, hdd_get_roam_scan_ch_cb); + status = sme_set_monitor_mode_cb(mac_handle, + hdd_sme_monitor_mode_callback); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("Register monitor mode callback failed"); + + status = sme_set_beacon_latency_event_cb(mac_handle, + hdd_beacon_latency_event_cb); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("Register beacon latency event callback failed"); + + sme_async_oem_event_init(mac_handle, + hdd_oem_event_async_cb); + + sme_register_pagefault_cb(mac_handle, hdd_pagefault_action_cb); + + hdd_exit(); + + return ret; +} + +/** + * hdd_deregister_cb() - De-Register HDD callbacks. + * @hdd_ctx: HDD context + * + * De-Register the HDD callbacks to CDS/SME. + * + * Return: void + */ +void hdd_deregister_cb(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + int ret; + mac_handle_t mac_handle; + + hdd_enter(); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("in ftm mode, no need to deregister callbacks"); + return; + } + + mac_handle = hdd_ctx->mac_handle; + + sme_deregister_ssr_on_pagefault_cb(mac_handle); + + sme_async_oem_event_deinit(mac_handle); + + sme_deregister_tx_queue_cb(mac_handle); + + sme_reset_link_layer_stats_ind_cb(mac_handle); + sme_reset_rssi_threshold_breached_cb(mac_handle); + + sme_stats_ext_deregister_callback(mac_handle); + + status = sme_reset_tsfcb(mac_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to de-register tsfcb the callback:%d", + status); + + ret = hdd_deregister_data_stall_detect_cb(); + if (ret) + hdd_err("Failed to de-register data stall detect event callback"); + hdd_thermal_unregister_callbacks(hdd_ctx); + sme_deregister_oem_data_rsp_callback(mac_handle); + sme_multi_client_ll_rsp_deregister_callback(mac_handle); + + hdd_exit(); +} + +/** + * hdd_softap_sta_deauth() - handle deauth req from HDD + * @adapter: Pointer to the HDD adapter + * @param: Params to the operation + * + * This to take counter measure to handle deauth req from HDD + * + * Return: None + */ +QDF_STATUS hdd_softap_sta_deauth(struct hdd_adapter *adapter, + struct csr_del_sta_params *param) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAULT; + struct hdd_context *hdd_ctx; + bool is_sap_bcast_deauth_enabled = false; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + ucfg_mlme_get_sap_bcast_deauth_enabled(hdd_ctx->psoc, + &is_sap_bcast_deauth_enabled); + + hdd_enter(); + + hdd_debug("sap_bcast_deauth_enabled %d", is_sap_bcast_deauth_enabled); + /* Ignore request to deauth bcmc station */ + if (!is_sap_bcast_deauth_enabled) + if (param->peerMacAddr.bytes[0] & 0x1) + return qdf_status; + + qdf_status = + wlansap_deauth_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + param); + + hdd_exit(); + return qdf_status; +} + +/** + * hdd_softap_sta_disassoc() - take counter measure to handle deauth req from HDD + * @adapter: Pointer to the HDD + * @param: pointer to station deletion parameters + * + * This to take counter measure to handle deauth req from HDD + * + * Return: None + */ +void hdd_softap_sta_disassoc(struct hdd_adapter *adapter, + struct csr_del_sta_params *param) +{ + hdd_enter(); + + /* Ignore request to disassoc bcmc station */ + if (param->peerMacAddr.bytes[0] & 0x1) + return; + + wlansap_disassoc_sta(WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + param); +} + +void +wlan_hdd_set_roaming_state(struct wlan_hdd_link_info *cur_link_info, + enum wlan_cm_rso_control_requestor rso_op_requestor, + bool enab_roam) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(cur_link_info->adapter); + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DISABLE_ROAMING; + uint8_t vdev_id, cur_vdev_id = cur_link_info->vdev_id; + struct wlan_hdd_link_info *link_info; + + if (!policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) + return; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + vdev_id = link_info->vdev_id; + if (cur_vdev_id != link_info->vdev_id && + adapter->device_mode == QDF_STA_MODE && + hdd_cm_is_vdev_associated(link_info)) { + if (enab_roam) { + hdd_debug("%d Enable roaming", vdev_id); + sme_start_roaming(hdd_ctx->mac_handle, + vdev_id, + REASON_DRIVER_ENABLED, + rso_op_requestor); + } else { + hdd_debug("%d Disable roaming", + vdev_id); + sme_stop_roaming(hdd_ctx->mac_handle, + vdev_id, + REASON_DRIVER_DISABLED, + rso_op_requestor); + } + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +/** + * nl_srv_bcast_svc() - Wrapper function to send bcast msgs to SVC mcast group + * @skb: sk buffer pointer + * + * Sends the bcast message to SVC multicast group with generic nl socket + * if CNSS_GENL is enabled. Else, use the legacy netlink socket to send. + * + * Return: None + */ +static void nl_srv_bcast_svc(struct sk_buff *skb) +{ +#ifdef CNSS_GENL + nl_srv_bcast(skb, CLD80211_MCGRP_SVC_MSGS, WLAN_NL_MSG_SVC); +#else + nl_srv_bcast(skb); +#endif +} + +void wlan_hdd_send_svc_nlink_msg(int radio, int type, void *data, int len) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + void *nl_data = NULL; + int flags = GFP_KERNEL; + struct radio_index_tlv *radio_info; + int tlv_len; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), flags); + + if (!skb) + return; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_SVC; + + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = type; + + switch (type) { + case WLAN_SVC_FW_CRASHED_IND: + case WLAN_SVC_FW_SHUTDOWN_IND: + case WLAN_SVC_LTE_COEX_IND: + case WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND: + case WLAN_SVC_WLAN_AUTO_SHUTDOWN_CANCEL_IND: + ani_hdr->length = 0; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr))); + break; + case WLAN_SVC_WLAN_STATUS_IND: + case WLAN_SVC_WLAN_VERSION_IND: + case WLAN_SVC_DFS_CAC_START_IND: + case WLAN_SVC_DFS_CAC_END_IND: + case WLAN_SVC_DFS_RADAR_DETECT_IND: + case WLAN_SVC_DFS_ALL_CHANNEL_UNAVAIL_IND: + case WLAN_SVC_WLAN_TP_IND: + case WLAN_SVC_WLAN_TP_TX_IND: + case WLAN_SVC_RPS_ENABLE_IND: + case WLAN_SVC_CORE_MINFREQ: + ani_hdr->length = len; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + len)); + nl_data = (char *)ani_hdr + sizeof(tAniMsgHdr); + memcpy(nl_data, data, len); + break; + + default: + hdd_err("WLAN SVC: Attempt to send unknown nlink message %d", + type); + kfree_skb(skb); + return; + } + + /* + * Add radio index at the end of the svc event in TLV format + * to maintain the backward compatibility with userspace + * applications. + */ + + tlv_len = 0; + + if ((sizeof(*ani_hdr) + len + sizeof(struct radio_index_tlv)) + < WLAN_NL_MAX_PAYLOAD) { + radio_info = (struct radio_index_tlv *)((char *) ani_hdr + + sizeof(*ani_hdr) + len); + radio_info->type = (unsigned short) WLAN_SVC_WLAN_RADIO_INDEX; + radio_info->length = (unsigned short) sizeof(radio_info->radio); + radio_info->radio = radio; + tlv_len = sizeof(*radio_info); + hdd_debug("Added radio index tlv - radio index %d", + radio_info->radio); + } + + nlh->nlmsg_len += tlv_len; + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + len + tlv_len)); + + nl_srv_bcast_svc(skb); +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +void wlan_hdd_auto_shutdown_cb(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + hdd_debug("Wlan Idle. Sending Shutdown event.."); + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_AUTO_SHUTDOWN_IND, NULL, 0); +} + +void wlan_hdd_auto_shutdown_enable(struct hdd_context *hdd_ctx, bool enable) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + bool ap_connected = false, sta_connected = false; + mac_handle_t mac_handle; + struct wlan_hdd_link_info *link_info; + struct hdd_ap_ctx *ap_ctx; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_AUTO_SHUTDOWN_ENABLE; + + mac_handle = hdd_ctx->mac_handle; + if (!mac_handle) + return; + + if (hdd_ctx->config->wlan_auto_shutdown == 0) + return; + + if (enable == false) { + if (sme_set_auto_shutdown_timer(mac_handle, 0) != + QDF_STATUS_SUCCESS) { + hdd_err("Failed to stop wlan auto shutdown timer"); + } + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_WLAN_AUTO_SHUTDOWN_CANCEL_IND, NULL, 0); + return; + } + + /* To enable shutdown timer check conncurrency */ + if (!policy_mgr_concurrent_open_sessions_running(hdd_ctx->psoc)) + goto start_timer; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, + next_adapter, dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (adapter->device_mode == QDF_STA_MODE && + hdd_cm_is_vdev_associated(link_info)) { + sta_connected = true; + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + break; + } + + if (adapter->device_mode == QDF_SAP_MODE) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (ap_ctx->ap_active == true) { + ap_connected = true; + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + break; + } + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + +start_timer: + if (ap_connected == true || sta_connected == true) { + hdd_debug("CC Session active. Shutdown timer not enabled"); + return; + } + + if (sme_set_auto_shutdown_timer(mac_handle, + hdd_ctx->config->wlan_auto_shutdown) + != QDF_STATUS_SUCCESS) + hdd_err("Failed to start wlan auto shutdown timer"); + else + hdd_info("Auto Shutdown timer for %d seconds enabled", + hdd_ctx->config->wlan_auto_shutdown); +} +#endif + +struct hdd_adapter * +hdd_get_con_sap_adapter(struct hdd_adapter *this_sap_adapter, + bool check_start_bss) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(this_sap_adapter); + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_CON_SAP_ADAPTER; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + adapter != this_sap_adapter) { + hdd_adapter_for_each_active_link_info(adapter, + link_info) { + if (!check_start_bss) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return adapter; + } + if (test_bit(SOFTAP_BSS_STARTED, + &link_info->link_flags)) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return adapter; + } + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} + +static inline bool hdd_adapter_is_sta(struct hdd_adapter *adapter) +{ + return adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE; +} + +bool hdd_is_any_adapter_connected(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_ANY_ADAPTER_CONNECTED; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (hdd_adapter_is_sta(adapter) && + hdd_cm_is_vdev_associated(link_info)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return true; + } + + if (hdd_adapter_is_ap(adapter) && + WLAN_HDD_GET_AP_CTX_PTR(link_info)->ap_active) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return true; + } + + if (adapter->device_mode == QDF_NDI_MODE && + hdd_cm_is_vdev_associated(link_info)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return true; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return false; +} + +#if defined MSM_PLATFORM && (LINUX_VERSION_CODE <= KERNEL_VERSION(4, 19, 0)) +/** + * hdd_inform_stop_sap() - call cfg80211 API to stop SAP + * @adapter: pointer to adapter + * + * This function calls cfg80211 API to stop SAP + * + * Return: None + */ +static void hdd_inform_stop_sap(struct hdd_adapter *adapter) +{ + hdd_debug("SAP stopped due to invalid channel vdev id %d", + wlan_vdev_get_id(adapter->deflink->vdev)); + cfg80211_ap_stopped(adapter->dev, GFP_KERNEL); +} + +#else +static void hdd_inform_stop_sap(struct hdd_adapter *adapter) +{ + hdd_debug("SAP stopped due to invalid channel vdev id %d", + wlan_vdev_get_id(adapter->deflink->vdev)); + cfg80211_stop_iface(adapter->hdd_ctx->wiphy, &adapter->wdev, + GFP_KERNEL); +} +#endif + +/** + * wlan_hdd_stop_sap() - This function stops bss of SAP. + * @ap_adapter: SAP adapter + * + * This function will process the stopping of sap adapter. + * + * Return: None + */ +void wlan_hdd_stop_sap(struct hdd_adapter *ap_adapter) +{ + struct hdd_ap_ctx *hdd_ap_ctx; + struct hdd_hostapd_state *hostapd_state; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + + if (!ap_adapter) { + hdd_err("ap_adapter is NULL here"); + return; + } + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(ap_adapter->deflink); + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &ap_adapter->deflink->link_flags)) { + wlan_hdd_del_station(ap_adapter, NULL); + hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(ap_adapter->deflink); + hdd_debug("Now doing SAP STOPBSS"); + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + if (QDF_STATUS_SUCCESS == wlansap_stop_bss(hdd_ap_ctx-> + sap_context)) { + qdf_status = qdf_wait_single_event(&hostapd_state-> + qdf_stop_bss_event, + SME_CMD_STOP_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mutex_unlock(&hdd_ctx->sap_lock); + hdd_err("SAP Stop Failed"); + return; + } + } + clear_bit(SOFTAP_BSS_STARTED, &ap_adapter->deflink->link_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + ap_adapter->device_mode, + ap_adapter->deflink->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, ap_adapter->device_mode, + false); + hdd_inform_stop_sap(ap_adapter); + hdd_debug("SAP Stop Success"); + } else { + hdd_err("Can't stop ap because its not started"); + } + mutex_unlock(&hdd_ctx->sap_lock); +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * wlan_hdd_mlo_sap_reinit() - handle mlo scenario for ssr + * @link_info: Pointer of link_info in adapter + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlan_hdd_mlo_sap_reinit(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + struct sap_config *config = &link_info->session.ap.sap_config; + + if (config->mlo_sap) { + if (!mlo_ap_vdev_attach(link_info->vdev, config->link_id, + config->num_link)) { + hdd_err("SAP mlo mgr attach fail"); + return QDF_STATUS_E_INVAL; + } + } + + if (!policy_mgr_is_mlo_sap_concurrency_allowed(hdd_ctx->psoc, + config->mlo_sap, + wlan_vdev_get_id(link_info->vdev))) { + hdd_err("MLO SAP concurrency check fails"); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +wlan_hdd_mlo_sap_reinit(struct wlan_hdd_link_info *link_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void wlan_hdd_set_sap_beacon_protection(struct hdd_context *hdd_ctx, + struct wlan_hdd_link_info *link_info, + struct hdd_beacon_data *beacon) +{ + const uint8_t *ie = NULL; + struct s_ext_cap *p_ext_cap; + struct wlan_objmgr_vdev *vdev; + bool target_bigtk_support = false; + uint8_t vdev_id; + uint8_t ie_len; + + if (!beacon) { + hdd_err("beacon is null"); + return; + } + + ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_EXTCAP, beacon->tail, + beacon->tail_len); + if (!ie) { + hdd_err("IE is null"); + return; + } + + if (ie[1] > DOT11F_IE_EXTCAP_MAX_LEN || + ie[1] < DOT11F_IE_EXTCAP_MIN_LEN) { + hdd_err("Invalid IEs eid: %d elem_len: %d", ie[0], ie[1]); + return; + } + + p_ext_cap = qdf_mem_malloc(sizeof(*p_ext_cap)); + if (!p_ext_cap) + return; + + ie_len = (ie[1] > sizeof(*p_ext_cap)) ? sizeof(*p_ext_cap) : ie[1]; + + qdf_mem_copy(p_ext_cap, &ie[2], ie_len); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_HDD_ID_OBJ_MGR); + if (!vdev) { + hdd_err("vdev is null"); + goto end; + } + + vdev_id = wlan_vdev_get_id(vdev); + + hdd_debug("vdev %d beacon protection %d", vdev_id, + p_ext_cap->beacon_protection_enable); + + ucfg_mlme_get_bigtk_support(hdd_ctx->psoc, &target_bigtk_support); + + if (target_bigtk_support && p_ext_cap->beacon_protection_enable) + mlme_set_bigtk_support(vdev, true); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_HDD_ID_OBJ_MGR); + +end: + qdf_mem_free(p_ext_cap); +} + +void wlan_hdd_start_sap(struct wlan_hdd_link_info *link_info, bool reinit) +{ + struct hdd_ap_ctx *ap_ctx; + struct hdd_hostapd_state *hostapd_state; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + struct sap_config *sap_config; + struct hdd_adapter *ap_adapter = link_info->adapter; + + if (QDF_SAP_MODE != ap_adapter->device_mode) { + hdd_err("SoftAp role has not been enabled"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + sap_config = &ap_ctx->sap_config; + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) + goto end; + + if (wlan_hdd_cfg80211_update_apies(link_info)) { + hdd_err("SAP Not able to set AP IEs"); + goto end; + } + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + sap_config->chan_freq, 0, + &sap_config->ch_params, + REG_CURRENT_PWR_MODE); + qdf_status = wlan_hdd_mlo_sap_reinit(link_info); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("SAP Not able to do mlo attach"); + goto end; + } + + qdf_event_reset(&hostapd_state->qdf_event); + qdf_status = wlansap_start_bss(ap_ctx->sap_context, + hdd_hostapd_sap_event_cb, sap_config, + ap_adapter->dev); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto end; + + wlan_hdd_set_sap_beacon_protection(hdd_ctx, link_info, ap_ctx->beacon); + + hdd_debug("Waiting for SAP to start"); + qdf_status = qdf_wait_single_event(&hostapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("SAP Start failed"); + goto end; + } + hdd_info("SAP Start Success"); + + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + set_bit(SOFTAP_BSS_STARTED, &link_info->link_flags); + if (hostapd_state->bss_state == BSS_START) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + ap_adapter->device_mode, + link_info->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, ap_adapter->device_mode, + true); + } + mutex_unlock(&hdd_ctx->sap_lock); + + return; +end: + wlan_hdd_mlo_reset(link_info); + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + mutex_unlock(&hdd_ctx->sap_lock); + /* SAP context and beacon cleanup will happen during driver unload + * in hdd_stop_adapter + */ + hdd_err("SAP restart after SSR failed! Reload WLAN and try SAP again"); + /* Free the beacon memory in case of failure in the sap restart */ + qdf_mem_free(ap_ctx->beacon); + ap_ctx->beacon = NULL; +} + +#ifdef QCA_CONFIG_SMP +/** + * wlan_hdd_get_cpu() - get cpu_index + * + * Return: cpu_index + */ +int wlan_hdd_get_cpu(void) +{ + int cpu_index = get_cpu(); + + put_cpu(); + return cpu_index; +} +#endif + +/** + * hdd_get_fwpath() - get framework path + * + * This function is used to get the string written by + * userspace to start the wlan driver + * + * Return: string + */ +const char *hdd_get_fwpath(void) +{ + return fwpath.string; +} + +static inline int hdd_state_query_cb(void) +{ + return !!wlan_hdd_validate_context(cds_get_context(QDF_MODULE_ID_HDD)); +} + +static int __hdd_op_protect_cb(void **out_sync, const char *func) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return -EAGAIN; + + return __osif_psoc_sync_op_start(hdd_ctx->parent_dev, + (struct osif_psoc_sync **)out_sync, + func); +} + +static void __hdd_op_unprotect_cb(void *sync, const char *func) +{ + __osif_psoc_sync_op_stop(sync, func); +} + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE +/** + * hdd_logging_sock_init_svc() - Initialize logging sock + * + * Return: 0 for success, errno on failure + */ +static int +hdd_logging_sock_init_svc(void) +{ + return wlan_logging_sock_init_svc(); +} +#else +static inline int +hdd_logging_sock_init_svc(void) +{ + return 0; +} +#endif + +/** + * hdd_init() - Initialize Driver + * + * This function initializes CDS global context with the help of cds_init. This + * has to be the first function called after probe to get a valid global + * context. + * + * Return: 0 for success, errno on failure + */ +int hdd_init(void) +{ + QDF_STATUS status; + + status = cds_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to allocate CDS context"); + return -ENOMEM; + } + + qdf_op_callbacks_register(__hdd_op_protect_cb, __hdd_op_unprotect_cb); + + wlan_init_bug_report_lock(); + + if (hdd_logging_sock_init_svc()) { + hdd_err("logging sock init failed."); + goto err; + } + + hdd_trace_init(); + hdd_register_debug_callback(); + wlan_roam_debug_init(); + + return 0; + +err: + wlan_destroy_bug_report_lock(); + qdf_op_callbacks_register(NULL, NULL); + cds_deinit(); + return -ENOMEM; +} + +/** + * hdd_deinit() - Deinitialize Driver + * + * This function frees CDS global context with the help of cds_deinit. This + * has to be the last function call in remove callback to free the global + * context. + */ +void hdd_deinit(void) +{ + wlan_roam_debug_deinit(); + +#ifdef WLAN_LOGGING_SOCK_SVC_ENABLE + wlan_logging_sock_deinit_svc(); +#endif + + wlan_destroy_bug_report_lock(); + qdf_op_callbacks_register(NULL, NULL); + cds_deinit(); +} + +#ifdef QCA_WIFI_EMULATION +#define HDD_WLAN_START_WAIT_TIME ((CDS_WMA_TIMEOUT + 5000) * 100) +#else +#define HDD_WLAN_START_WAIT_TIME (CDS_WMA_TIMEOUT + 5000) +#endif + +void hdd_init_start_completion(void) +{ + INIT_COMPLETION(wlan_start_comp); +} + +#ifdef WLAN_CTRL_NAME +static unsigned int dev_num = 1; +static struct cdev wlan_hdd_state_cdev; +static struct class *class; +static dev_t device; + +static void hdd_set_adapter_wlm_def_level(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + int ret; + QDF_STATUS qdf_status; + uint8_t latency_level; + bool reset; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + return; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + qdf_status = ucfg_mlme_cfg_get_wlm_level(hdd_ctx->psoc, + &latency_level); + if (QDF_IS_STATUS_ERROR(qdf_status)) + adapter->latency_level = + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL; + else + adapter->latency_level = latency_level; + qdf_status = ucfg_mlme_cfg_get_wlm_reset(hdd_ctx->psoc, &reset); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("could not get the wlm reset flag"); + reset = false; + } + + if (hdd_get_multi_client_ll_support(adapter) && !reset) + wlan_hdd_deinit_multi_client_info_table(adapter); + + adapter->upgrade_udp_qos_threshold = QCA_WLAN_AC_BK; + hdd_debug("UDP packets qos reset to: %d", + adapter->upgrade_udp_qos_threshold); + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +static int wlan_hdd_state_ctrl_param_open(struct inode *inode, + struct file *file) +{ + qdf_atomic_inc(&wlan_hdd_state_fops_ref); + + return 0; +} + +static void __hdd_inform_wifi_off(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return; + + ucfg_dlm_wifi_off(hdd_ctx->pdev); + + if (rtnl_trylock()) { + wlan_hdd_lpc_del_monitor_interface(hdd_ctx, false); + rtnl_unlock(); + } +} + +static void hdd_inform_wifi_off(void) +{ + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + + if (!hdd_ctx) + return; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return; + + hdd_set_adapter_wlm_def_level(hdd_ctx); + __hdd_inform_wifi_off(); + + osif_psoc_sync_op_stop(psoc_sync); +} + +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) +static void hdd_inform_wifi_on(void) +{ + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + + hdd_nofl_debug("inform regdomain for wifi on"); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return; + if (!hdd_ctx->wiphy) + return; + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return; + if (hdd_ctx->wiphy->registered) + hdd_send_wiphy_regd_sync_event(hdd_ctx); + + osif_psoc_sync_op_stop(psoc_sync); +} +#else +static void hdd_inform_wifi_on(void) +{ +} +#endif + +static int hdd_validate_wlan_string(const char __user *user_buf) +{ + char buf[15]; + int i; + static const char * const wlan_str[] = { + [WLAN_OFF_STR] = "OFF", + [WLAN_ON_STR] = "ON", + [WLAN_ENABLE_STR] = "ENABLE", + [WLAN_DISABLE_STR] = "DISABLE", + [WLAN_WAIT_FOR_READY_STR] = "WAIT_FOR_READY", + [WLAN_FORCE_DISABLE_STR] = "FORCE_DISABLE" + }; + + if (copy_from_user(buf, user_buf, sizeof(buf))) { + pr_err("Failed to read buffer\n"); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(wlan_str); i++) { + if (qdf_str_ncmp(buf, wlan_str[i], strlen(wlan_str[i])) == 0) + return i; + } + + return -EINVAL; +} + +#ifdef FEATURE_CNSS_HW_SECURE_DISABLE +#define WIFI_DISABLE_SLEEP (10) +#define WIFI_DISABLE_MAX_RETRY_ATTEMPTS (10) +static bool g_soft_unload; + +bool hdd_get_wlan_driver_status(void) +{ + return g_soft_unload; +} + +static int hdd_wlan_soft_driver_load(void) +{ + if (!cds_is_driver_loaded()) { + hdd_debug("\nEnabling CNSS WLAN HW"); + pld_wlan_hw_enable(); + return 0; + } + + if (!g_soft_unload) { + hdd_debug_rl("Enabling WiFi\n"); + return -EINVAL; + } + + hdd_driver_load(); + g_soft_unload = false; + return 0; +} + +static void hdd_wlan_soft_driver_unload(void) +{ + if (g_soft_unload) { + hdd_debug_rl("WiFi is already disabled"); + return; + } + hdd_debug("Initiating soft driver unload\n"); + g_soft_unload = true; + hdd_driver_unload(); +} + +static int hdd_wlan_idle_shutdown(struct hdd_context *hdd_ctx) +{ + int ret; + int retries = 0; + void *hif_ctx; + + if (!hdd_ctx) { + hdd_err_rl("hdd_ctx is Null"); + return -EINVAL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN); + + while (retries < WIFI_DISABLE_MAX_RETRY_ATTEMPTS) { + if (hif_ctx) { + /* + * Trigger runtime sync resume before psoc_idle_shutdown + * such that resume can happen successfully + */ + qdf_rtpm_sync_resume(); + } + ret = pld_idle_shutdown(hdd_ctx->parent_dev, + hdd_psoc_idle_shutdown); + + if (-EAGAIN == ret || hdd_ctx->is_wiphy_suspended) { + hdd_debug("System suspend in progress.Retries done:%d", + retries); + msleep(WIFI_DISABLE_SLEEP); + retries++; + continue; + } + break; + } + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_IDLE_SHUTDOWN); + + if (retries > WIFI_DISABLE_MAX_RETRY_ATTEMPTS) { + hdd_debug("Max retries reached"); + return -EINVAL; + } + hdd_debug_rl("WiFi is disabled"); + + return 0; +} + +static int hdd_disable_wifi(struct hdd_context *hdd_ctx) +{ + int ret; + + if (hdd_ctx->is_wlan_disabled) { + hdd_err_rl("Wifi is already disabled"); + return 0; + } + + hdd_debug("Initiating WLAN idle shutdown"); + if (hdd_is_any_interface_open(hdd_ctx)) { + hdd_err("Interfaces still open, cannot process wifi disable"); + return -EAGAIN; + } + + hdd_ctx->is_wlan_disabled = true; + + ret = hdd_wlan_idle_shutdown(hdd_ctx); + if (ret) + hdd_ctx->is_wlan_disabled = false; + + return ret; +} +#else +static int hdd_wlan_soft_driver_load(void) +{ + return -EINVAL; +} + +static void hdd_wlan_soft_driver_unload(void) +{ +} + +static int hdd_disable_wifi(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif /* FEATURE_CNSS_HW_SECURE_DISABLE */ + +static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, + const char __user *user_buf, + size_t count, + loff_t *f_pos) +{ + int id, ret; + unsigned long rc; + struct hdd_context *hdd_ctx; + bool is_wait_for_ready = false; + bool is_wlan_force_disabled; + + hdd_enter(); + + id = hdd_validate_wlan_string(user_buf); + + switch (id) { + case WLAN_OFF_STR: + hdd_info("Wifi turning off from UI\n"); + hdd_inform_wifi_off(); + goto exit; + case WLAN_ON_STR: + hdd_info("Wifi Turning On from UI\n"); + break; + case WLAN_WAIT_FOR_READY_STR: + is_wait_for_ready = true; + hdd_info("Wifi wait for ready from UI\n"); + break; + case WLAN_ENABLE_STR: + hdd_nofl_debug("Received WiFi enable from framework\n"); + if (!hdd_wlan_soft_driver_load()) + goto exit; + pr_info("Enabling WiFi\n"); + break; + case WLAN_DISABLE_STR: + hdd_nofl_debug("Received WiFi disable from framework\n"); + if (!cds_is_driver_loaded()) + goto exit; + + is_wlan_force_disabled = hdd_get_wlan_driver_status(); + if (is_wlan_force_disabled) + goto exit; + pr_info("Disabling WiFi\n"); + break; + case WLAN_FORCE_DISABLE_STR: + hdd_nofl_debug("Received Force WiFi disable from framework\n"); + if (!cds_is_driver_loaded()) + goto exit; + + hdd_wlan_soft_driver_unload(); + goto exit; + default: + hdd_err_rl("Invalid value received from framework"); + return -EINVAL; + } + + hdd_info("is_driver_loaded %d is_driver_recovering %d", + cds_is_driver_loaded(), cds_is_driver_recovering()); + + if (!cds_is_driver_loaded() || cds_is_driver_recovering()) { + rc = wait_for_completion_timeout(&wlan_start_comp, + msecs_to_jiffies(HDD_WLAN_START_WAIT_TIME)); + if (!rc) { + hdd_err("Driver Loading Timed-out!!"); + ret = -EINVAL; + return ret; + } + } + + if (is_wait_for_ready) + return count; + /* + * Flush idle shutdown work for cases to synchronize the wifi on + * during the idle shutdown. + */ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (hdd_ctx) + hdd_psoc_idle_timer_stop(hdd_ctx); + + if (id == WLAN_DISABLE_STR) { + if (!hdd_ctx) { + hdd_err_rl("hdd_ctx is Null"); + goto exit; + } + + ret = hdd_disable_wifi(hdd_ctx); + if (ret) + return ret; + } + + if (id == WLAN_ENABLE_STR) { + if (!hdd_ctx) { + hdd_err_rl("hdd_ctx is Null"); + goto exit; + } + + if (!hdd_ctx->is_wlan_disabled) { + hdd_err_rl("WiFi is already enabled"); + goto exit; + } + hdd_ctx->is_wlan_disabled = false; + } + + if (id == WLAN_ON_STR) + hdd_inform_wifi_on(); +exit: + hdd_exit(); + return count; +} + +/** + * wlan_hdd_state_ctrl_param_release() - Release callback for /dev/wlan. + * + * @inode: struct inode pointer. + * @file: struct file pointer. + * + * Release callback that would be invoked when the file operations has + * completed fully. This is implemented to provide a reference count mechanism + * via which the driver can wait till all possible usage of the /dev/wlan + * file is completed. + * + * Return: Success + */ +static int wlan_hdd_state_ctrl_param_release(struct inode *inode, + struct file *file) +{ + qdf_atomic_dec(&wlan_hdd_state_fops_ref); + + return 0; +} + +const struct file_operations wlan_hdd_state_fops = { + .owner = THIS_MODULE, + .open = wlan_hdd_state_ctrl_param_open, + .write = wlan_hdd_state_ctrl_param_write, + .release = wlan_hdd_state_ctrl_param_release, +}; + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0)) +static struct class *wlan_hdd_class_create(const char *name) +{ + return class_create(THIS_MODULE, name); +} +#else +static struct class *wlan_hdd_class_create(const char *name) +{ + return class_create(name); +} +#endif + +static int wlan_hdd_state_ctrl_param_create(void) +{ + unsigned int wlan_hdd_state_major = 0; + int ret; + struct device *dev; + + init_completion(&wlan_start_comp); + qdf_atomic_init(&wlan_hdd_state_fops_ref); + + device = MKDEV(wlan_hdd_state_major, 0); + + ret = alloc_chrdev_region(&device, 0, dev_num, "qcwlanstate"); + if (ret) { + pr_err("Failed to register qcwlanstate"); + goto dev_alloc_err; + } + wlan_hdd_state_major = MAJOR(device); + class = wlan_hdd_class_create(WLAN_CTRL_NAME); + if (IS_ERR(class)) { + pr_err("wlan_hdd_state class_create error"); + goto class_err; + } + + dev = device_create(class, NULL, device, NULL, WLAN_CTRL_NAME); + if (IS_ERR(dev)) { + pr_err("wlan_hdd_statedevice_create error"); + goto err_class_destroy; + } + + cdev_init(&wlan_hdd_state_cdev, &wlan_hdd_state_fops); + + wlan_hdd_state_cdev.owner = THIS_MODULE; + + ret = cdev_add(&wlan_hdd_state_cdev, device, dev_num); + if (ret) { + pr_err("Failed to add cdev error"); + goto cdev_add_err; + } + + pr_info("wlan_hdd_state %s major(%d) initialized", + WLAN_CTRL_NAME, wlan_hdd_state_major); + + return 0; + +cdev_add_err: + device_destroy(class, device); +err_class_destroy: + class_destroy(class); +class_err: + unregister_chrdev_region(device, dev_num); +dev_alloc_err: + return -ENODEV; +} + +/* + * When multiple instances of the driver are loaded in parallel, only + * one can create and own the state ctrl param. An instance of the + * driver that creates the state ctrl param will wait for + * HDD_WLAN_START_WAIT_TIME to be probed. If it is probed, then that + * instance of the driver will stay loaded and no other instances of + * the driver can load. But if it is not probed, then that instance of + * the driver will destroy the state ctrl param and exit, and another + * instance of the driver can then create the state ctrl param. + */ + +/* max number of instances we expect (arbitrary) */ +#define WLAN_DRIVER_MAX_INSTANCES 5 + +/* max amount of time an instance has to wait for all instances */ +#define CTRL_PARAM_WAIT (WLAN_DRIVER_MAX_INSTANCES * HDD_WLAN_START_WAIT_TIME) + +/* amount of time we sleep for each retry (arbitrary) */ +#define CTRL_PARAM_SLEEP 100 + +static void wlan_hdd_state_ctrl_param_destroy(void) +{ + cdev_del(&wlan_hdd_state_cdev); + device_destroy(class, device); + class_destroy(class); + unregister_chrdev_region(device, dev_num); + + pr_info("Device node unregistered"); +} + +#else /* WLAN_CTRL_NAME */ + +static int wlan_hdd_state_ctrl_param_create(void) +{ + return 0; +} + +static void wlan_hdd_state_ctrl_param_destroy(void) +{ +} + +#endif /* WLAN_CTRL_NAME */ + +/** + * hdd_send_scan_done_complete_cb() - API to send scan done indication to upper + * layer + * @vdev_id: vdev id + * + * Return: none + */ +static void hdd_send_scan_done_complete_cb(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + struct hdd_adapter *adapter; + struct sk_buff *vendor_event; + uint32_t len; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev id:%d", vdev_id); + return; + } + + adapter = link_info->adapter; + len = NLMSG_HDRLEN; + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &adapter->wdev, len, + QCA_NL80211_VENDOR_SUBCMD_CONNECTED_CHANNEL_STATS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + hdd_debug("sending scan done ind to upper layer for vdev_id:%d", + vdev_id); + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +struct osif_vdev_mgr_ops osif_vdev_mgrlegacy_ops = { +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE + .osif_vdev_mgr_set_mac_addr_response = hdd_set_mac_addr_event_cb, +#endif + .osif_vdev_mgr_send_scan_done_complete_cb = + hdd_send_scan_done_complete_cb, + +}; + +static QDF_STATUS hdd_vdev_mgr_register_cb(void) +{ + osif_vdev_mgr_set_legacy_cb(&osif_vdev_mgrlegacy_ops); + return osif_vdev_mgr_register_cb(); +} + +static void hdd_vdev_mgr_unregister_cb(void) +{ + osif_vdev_mgr_reset_legacy_cb(); +} + +/** + * hdd_ll_sap_register_cb() - Register ll_sap osif callbacks + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_ll_sap_register_cb(void) +{ + return osif_ll_sap_register_cb(); +} + +/** + * hdd_ll_sap_unregister_cb() - Un-register ll_sap osif callbacks + * + * Return: void + */ +static void hdd_ll_sap_unregister_cb(void) +{ + osif_ll_sap_unregister_cb(); +} + +/** + * hdd_component_cb_init() - Initialize component callbacks + * + * This function initializes hdd callbacks to different + * components + * + * Context: Any context. + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_component_cb_init(void) +{ + QDF_STATUS status; + + status = hdd_cm_register_cb(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = hdd_vdev_mgr_register_cb(); + if (QDF_IS_STATUS_ERROR(status)) + goto cm_unregister_cb; + + status = osif_twt_register_cb(); + if (QDF_IS_STATUS_ERROR(status)) + goto hdd_vdev_mgr_unregister_cb; + + status = hdd_pre_cac_register_cb(); + if (QDF_IS_STATUS_ERROR(status)) + goto hdd_vdev_mgr_unregister_cb; + + status = hdd_ll_sap_register_cb(); + if (QDF_IS_STATUS_ERROR(status)) + goto pre_cac_unregister_cb; + + return QDF_STATUS_SUCCESS; + +pre_cac_unregister_cb: + hdd_pre_cac_unregister_cb(); +hdd_vdev_mgr_unregister_cb: + hdd_vdev_mgr_unregister_cb(); +cm_unregister_cb: + hdd_cm_unregister_cb(); + return status; +} + +/** + * hdd_component_cb_deinit() - De-initialize component callbacks + * + * This function de-initializes hdd callbacks with different components + * + * Context: Any context. + * Return: None` + */ +static void hdd_component_cb_deinit(void) +{ + hdd_ll_sap_unregister_cb(); + hdd_pre_cac_unregister_cb(); + hdd_vdev_mgr_unregister_cb(); + hdd_cm_unregister_cb(); +} + +/** + * hdd_component_init() - Initialize all components + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_component_init(void) +{ + QDF_STATUS status; + + /* initialize converged components */ + + status = ucfg_mlme_global_init(); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = dispatcher_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto mlme_global_deinit; + + status = target_if_init(wma_get_psoc_from_scn_handle); + if (QDF_IS_STATUS_ERROR(status)) + goto dispatcher_deinit; + + /* initialize non-converged components */ + status = ucfg_mlme_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto target_if_deinit; + + status = ucfg_fwol_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto mlme_deinit; + + status = disa_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto fwol_deinit; + + status = pmo_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto disa_deinit; + + status = ucfg_ocb_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto pmo_deinit; + + status = ipa_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto ocb_deinit; + + status = ucfg_action_oui_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto ipa_deinit; + + status = nan_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto action_oui_deinit; + + status = ucfg_p2p_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto nan_deinit; + + status = ucfg_interop_issues_ap_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto p2p_deinit; + + status = policy_mgr_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto interop_issues_ap_deinit; + + status = ucfg_tdls_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto policy_deinit; + + status = ucfg_dlm_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto tdls_deinit; + + status = ucfg_pkt_capture_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto dlm_deinit; + + status = ucfg_ftm_time_sync_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto pkt_capture_deinit; + + status = ucfg_pre_cac_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto pre_cac_deinit; + + status = ucfg_dp_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto pre_cac_deinit; + + status = ucfg_qmi_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto dp_deinit; + + status = ucfg_ll_sap_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto qmi_deinit; + + status = ucfg_afc_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto ll_sap_deinit; + + status = hdd_mlo_mgr_register_osif_ops(); + if (QDF_IS_STATUS_ERROR(status)) + goto afc_deinit; + + hdd_register_cstats_ops(); + + return QDF_STATUS_SUCCESS; + +afc_deinit: + ucfg_afc_deinit(); +ll_sap_deinit: + ucfg_ll_sap_deinit(); +qmi_deinit: + ucfg_qmi_deinit(); +dp_deinit: + ucfg_dp_deinit(); +pre_cac_deinit: + ucfg_pre_cac_deinit(); +pkt_capture_deinit: + ucfg_pkt_capture_deinit(); +dlm_deinit: + ucfg_dlm_deinit(); +tdls_deinit: + ucfg_tdls_deinit(); +policy_deinit: + policy_mgr_deinit(); +interop_issues_ap_deinit: + ucfg_interop_issues_ap_deinit(); +p2p_deinit: + ucfg_p2p_deinit(); +nan_deinit: + nan_deinit(); +action_oui_deinit: + ucfg_action_oui_deinit(); +ipa_deinit: + ipa_deinit(); +ocb_deinit: + ucfg_ocb_deinit(); +pmo_deinit: + pmo_deinit(); +disa_deinit: + disa_deinit(); +fwol_deinit: + ucfg_fwol_deinit(); +mlme_deinit: + ucfg_mlme_deinit(); +target_if_deinit: + target_if_deinit(); +dispatcher_deinit: + dispatcher_deinit(); +mlme_global_deinit: + ucfg_mlme_global_deinit(); + + return status; +} + +/** + * hdd_component_deinit() - Deinitialize all components + * + * Return: None + */ +static void hdd_component_deinit(void) +{ + /* deinitialize non-converged components */ + hdd_mlo_mgr_unregister_osif_ops(); + ucfg_afc_deinit(); + ucfg_ll_sap_deinit(); + ucfg_qmi_deinit(); + ucfg_dp_deinit(); + ucfg_pre_cac_deinit(); + ucfg_ftm_time_sync_deinit(); + ucfg_pkt_capture_deinit(); + ucfg_dlm_deinit(); + ucfg_tdls_deinit(); + policy_mgr_deinit(); + ucfg_interop_issues_ap_deinit(); + ucfg_p2p_deinit(); + nan_deinit(); + ucfg_action_oui_deinit(); + ipa_deinit(); + ucfg_ocb_deinit(); + pmo_deinit(); + disa_deinit(); + ucfg_fwol_deinit(); + ucfg_mlme_deinit(); + + /* deinitialize converged components */ + target_if_deinit(); + dispatcher_deinit(); + ucfg_mlme_global_deinit(); +} + +QDF_STATUS hdd_component_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + + status = ucfg_mlme_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = ucfg_dlm_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_dlm; + + status = ucfg_fwol_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_fwol; + + status = ucfg_pmo_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_pmo; + + status = ucfg_policy_mgr_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_plcy_mgr; + + status = ucfg_p2p_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_p2p; + + status = ucfg_tdls_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_tdls; + + status = ucfg_nan_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_nan; + + status = ucfg_twt_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_twt; + + status = ucfg_wifi_pos_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_wifi_pos; + + status = ucfg_dp_psoc_open(psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto err_dp; + + return status; + +err_dp: + ucfg_wifi_pos_psoc_close(psoc); +err_wifi_pos: + ucfg_twt_psoc_close(psoc); +err_twt: + ucfg_nan_psoc_close(psoc); +err_nan: + ucfg_tdls_psoc_close(psoc); +err_tdls: + ucfg_p2p_psoc_close(psoc); +err_p2p: + ucfg_policy_mgr_psoc_close(psoc); +err_plcy_mgr: + ucfg_pmo_psoc_close(psoc); +err_pmo: + ucfg_fwol_psoc_close(psoc); +err_fwol: + ucfg_dlm_psoc_close(psoc); +err_dlm: + ucfg_mlme_psoc_close(psoc); + + return status; +} + +void hdd_component_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + ucfg_dp_psoc_close(psoc); + ucfg_wifi_pos_psoc_close(psoc); + ucfg_twt_psoc_close(psoc); + ucfg_nan_psoc_close(psoc); + ucfg_tdls_psoc_close(psoc); + ucfg_p2p_psoc_close(psoc); + ucfg_policy_mgr_psoc_close(psoc); + ucfg_pmo_psoc_close(psoc); + ucfg_fwol_psoc_close(psoc); + ucfg_dlm_psoc_close(psoc); + ucfg_mlme_psoc_close(psoc); + + if (!cds_is_driver_recovering()) + ucfg_crypto_flush_entries(psoc); +} + +void hdd_component_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + ocb_psoc_enable(psoc); + disa_psoc_enable(psoc); + nan_psoc_enable(psoc); + p2p_psoc_enable(psoc); + ucfg_interop_issues_ap_psoc_enable(psoc); + policy_mgr_psoc_enable(psoc); + ucfg_tdls_psoc_enable(psoc); + ucfg_fwol_psoc_enable(psoc); + ucfg_action_oui_psoc_enable(psoc); + ucfg_ll_sap_psoc_enable(psoc); +} + +void hdd_component_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + ucfg_ll_sap_psoc_disable(psoc); + ucfg_action_oui_psoc_disable(psoc); + ucfg_fwol_psoc_disable(psoc); + ucfg_tdls_psoc_disable(psoc); + policy_mgr_psoc_disable(psoc); + ucfg_interop_issues_ap_psoc_disable(psoc); + p2p_psoc_disable(psoc); + nan_psoc_disable(psoc); + disa_psoc_disable(psoc); + ocb_psoc_disable(psoc); +} + +QDF_STATUS hdd_component_pdev_open(struct wlan_objmgr_pdev *pdev) +{ + return ucfg_mlme_pdev_open(pdev); +} + +void hdd_component_pdev_close(struct wlan_objmgr_pdev *pdev) +{ + ucfg_mlme_pdev_close(pdev); +} + +static QDF_STATUS hdd_qdf_print_init(void) +{ + QDF_STATUS status; + int qdf_print_idx; + + status = qdf_print_setup(); + if (QDF_IS_STATUS_ERROR(status)) { + pr_err("Failed qdf_print_setup; status:%u\n", status); + return status; + } + + qdf_print_idx = qdf_print_ctrl_register(cinfo, NULL, NULL, "MCL_WLAN"); + if (qdf_print_idx < 0) { + pr_err("Failed to register for qdf_print_ctrl\n"); + return QDF_STATUS_E_FAILURE; + } + + qdf_set_pidx(qdf_print_idx); + + return QDF_STATUS_SUCCESS; +} + +static void hdd_qdf_print_deinit(void) +{ + int qdf_pidx = qdf_get_pidx(); + + qdf_set_pidx(-1); + qdf_print_ctrl_cleanup(qdf_pidx); + + /* currently, no qdf print 'un-setup'*/ +} + +static QDF_STATUS hdd_qdf_init(void) +{ + QDF_STATUS status; + + status = hdd_qdf_print_init(); + if (QDF_IS_STATUS_ERROR(status)) + goto exit; + + status = qdf_debugfs_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init debugfs; status:%u", status); + goto print_deinit; + } + + qdf_lock_stats_init(); + qdf_mem_init(); + qdf_delayed_work_feature_init(); + qdf_periodic_work_feature_init(); + qdf_wake_lock_feature_init(); + qdf_mc_timer_manager_init(); + qdf_event_list_init(); + + status = qdf_talloc_feature_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init talloc; status:%u", status); + goto event_deinit; + } + + status = qdf_cpuhp_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init cpuhp; status:%u", status); + goto talloc_deinit; + } + + status = qdf_trace_spin_lock_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init spinlock; status:%u", status); + goto cpuhp_deinit; + } + + qdf_trace_init(); + qdf_minidump_init(); + qdf_ssr_driver_dump_init(); + qdf_register_debugcb_init(); + + return QDF_STATUS_SUCCESS; + +cpuhp_deinit: + qdf_cpuhp_deinit(); +talloc_deinit: + qdf_talloc_feature_deinit(); +event_deinit: + qdf_event_list_destroy(); + qdf_mc_timer_manager_exit(); + qdf_wake_lock_feature_deinit(); + qdf_periodic_work_feature_deinit(); + qdf_delayed_work_feature_deinit(); + qdf_mem_exit(); + qdf_lock_stats_deinit(); + qdf_debugfs_exit(); +print_deinit: + hdd_qdf_print_deinit(); + +exit: + return status; +} + +static void hdd_qdf_deinit(void) +{ + /* currently, no debugcb deinit */ + qdf_ssr_driver_dump_deinit(); + qdf_minidump_deinit(); + qdf_trace_deinit(); + + /* currently, no trace spinlock deinit */ + + qdf_cpuhp_deinit(); + qdf_talloc_feature_deinit(); + qdf_event_list_destroy(); + qdf_mc_timer_manager_exit(); + qdf_wake_lock_feature_deinit(); + qdf_periodic_work_feature_deinit(); + qdf_delayed_work_feature_deinit(); + qdf_mem_exit(); + qdf_lock_stats_deinit(); + qdf_debugfs_exit(); + hdd_qdf_print_deinit(); +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +static bool is_monitor_mode_supported(void) +{ + return true; +} +#else +static bool is_monitor_mode_supported(void) +{ + pr_err("Monitor mode not supported!"); + return false; +} +#endif + +#ifdef WLAN_FEATURE_EPPING +static bool is_epping_mode_supported(void) +{ + return true; +} +#else +static bool is_epping_mode_supported(void) +{ + pr_err("Epping mode not supported!"); + return false; +} +#endif + +#ifdef QCA_WIFI_FTM +static bool is_ftm_mode_supported(void) +{ + return true; +} +#else +static bool is_ftm_mode_supported(void) +{ + pr_err("FTM mode not supported!"); + return false; +} +#endif + +/** + * is_con_mode_valid() - check con mode is valid or not + * @mode: global con mode + * + * Return: TRUE on success FALSE on failure + */ +static bool is_con_mode_valid(enum QDF_GLOBAL_MODE mode) +{ + switch (mode) { + case QDF_GLOBAL_MONITOR_MODE: + return is_monitor_mode_supported(); + case QDF_GLOBAL_EPPING_MODE: + return is_epping_mode_supported(); + case QDF_GLOBAL_FTM_MODE: + return is_ftm_mode_supported(); + case QDF_GLOBAL_MISSION_MODE: + return true; + default: + return false; + } +} + +static void hdd_stop_present_mode(struct hdd_context *hdd_ctx, + enum QDF_GLOBAL_MODE curr_mode) +{ + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) + return; + + switch (curr_mode) { + case QDF_GLOBAL_MONITOR_MODE: + hdd_info("Release wakelock for monitor mode!"); + qdf_wake_lock_release(&hdd_ctx->monitor_mode_wakelock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + fallthrough; + case QDF_GLOBAL_MISSION_MODE: + case QDF_GLOBAL_FTM_MODE: + hdd_abort_mac_scan_all_adapters(hdd_ctx); + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL); + hdd_stop_all_adapters(hdd_ctx); + hdd_deinit_all_adapters(hdd_ctx, false); + + break; + default: + break; + } +} + +static void hdd_cleanup_present_mode(struct hdd_context *hdd_ctx, + enum QDF_GLOBAL_MODE curr_mode) +{ + switch (curr_mode) { + case QDF_GLOBAL_MISSION_MODE: + case QDF_GLOBAL_MONITOR_MODE: + case QDF_GLOBAL_FTM_MODE: + hdd_close_all_adapters(hdd_ctx, false); + break; + case QDF_GLOBAL_EPPING_MODE: + epping_disable(); + epping_close(); + break; + default: + return; + } +} + +static int +hdd_parse_driver_mode(const char *mode_str, enum QDF_GLOBAL_MODE *out_mode) +{ + QDF_STATUS status; + uint32_t mode; + + *out_mode = QDF_GLOBAL_MAX_MODE; + + status = qdf_uint32_parse(mode_str, &mode); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + if (mode >= QDF_GLOBAL_MAX_MODE) + return -ERANGE; + + *out_mode = (enum QDF_GLOBAL_MODE)mode; + + return 0; +} + +static int hdd_mode_change_psoc_idle_shutdown(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return -EINVAL; + + return hdd_wlan_stop_modules(hdd_ctx, true); +} + +static int hdd_mode_change_psoc_idle_restart(struct device *dev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + int ret; + + if (!hdd_ctx) + return -EINVAL; + ret = hdd_soc_idle_restart_lock(dev); + if (ret) + return ret; + ret = hdd_wlan_start_modules(hdd_ctx, false); + hdd_soc_idle_restart_unlock(); + + return ret; +} + +/** + * __hdd_driver_mode_change() - Handles a driver mode change + * @hdd_ctx: Pointer to the global HDD context + * @next_mode: the driver mode to transition to + * + * This function is invoked when user updates con_mode using sys entry, + * to initialize and bring-up driver in that specific mode. + * + * Return: Errno + */ +static int __hdd_driver_mode_change(struct hdd_context *hdd_ctx, + enum QDF_GLOBAL_MODE next_mode) +{ + enum QDF_GLOBAL_MODE curr_mode; + int errno; + struct bbm_params param = {0}; + + hdd_info("Driver mode changing to %d", next_mode); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (!is_con_mode_valid(next_mode)) { + hdd_err_rl("Requested driver mode is invalid"); + return -EINVAL; + } + + curr_mode = hdd_get_conparam(); + if (curr_mode == next_mode) { + hdd_err_rl("Driver is already in the requested mode"); + return 0; + } + + hdd_psoc_idle_timer_stop(hdd_ctx); + + /* ensure adapters are stopped */ + hdd_stop_present_mode(hdd_ctx, curr_mode); + + if (DRIVER_MODULES_CLOSED != hdd_ctx->driver_status) { + is_mode_change_psoc_idle_shutdown = true; + errno = pld_idle_shutdown(hdd_ctx->parent_dev, + hdd_mode_change_psoc_idle_shutdown); + if (errno) { + is_mode_change_psoc_idle_shutdown = false; + hdd_err("Stop wlan modules failed"); + return errno; + } + } + + /* Cleanup present mode before switching to new mode */ + hdd_cleanup_present_mode(hdd_ctx, curr_mode); + + hdd_set_conparam(next_mode); + pld_set_mode(next_mode); + + qdf_event_reset(&hdd_ctx->regulatory_update_event); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = true; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + + errno = pld_idle_restart(hdd_ctx->parent_dev, + hdd_mode_change_psoc_idle_restart); + if (errno) { + hdd_err("Start wlan modules failed: %d", errno); + return errno; + } + + errno = hdd_open_adapters_for_mode(hdd_ctx, next_mode); + if (errno) { + hdd_err("Failed to open adapters"); + return errno; + } + + if (next_mode == QDF_GLOBAL_MONITOR_MODE) { + struct hdd_adapter *adapter = + hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + + QDF_BUG(adapter); + if (!adapter) { + hdd_err("Failed to get monitor adapter"); + return -EINVAL; + } + + errno = hdd_start_adapter(adapter, false); + if (errno) { + hdd_err("Failed to start monitor adapter"); + return errno; + } + + hdd_info("Acquire wakelock for monitor mode"); + qdf_wake_lock_acquire(&hdd_ctx->monitor_mode_wakelock, + WIFI_POWER_EVENT_WAKELOCK_MONITOR_MODE); + } + + /* con_mode is a global module parameter */ + con_mode = next_mode; + hdd_info("Driver mode successfully changed to %d", next_mode); + + param.policy = BBM_DRIVER_MODE_POLICY; + param.policy_info.driver_mode = con_mode; + ucfg_dp_bbm_apply_independent_policy(hdd_ctx->psoc, ¶m); + + return 0; +} + +static void hdd_pre_mode_change(enum QDF_GLOBAL_MODE mode) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx; + int errno; + enum QDF_GLOBAL_MODE curr_mode; + + curr_mode = hdd_get_conparam(); + if (curr_mode != QDF_GLOBAL_MISSION_MODE) + return; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) { + hdd_err("psoc op start failed"); + return; + } + + hdd_debug("cleanup scan queue"); + if (hdd_ctx && hdd_ctx->pdev) + wlan_cfg80211_cleanup_scan_queue(hdd_ctx->pdev, NULL); + + osif_psoc_sync_op_stop(psoc_sync); +} + +static int hdd_driver_mode_change(enum QDF_GLOBAL_MODE mode) +{ + struct osif_driver_sync *driver_sync; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + int errno; + + hdd_enter(); + + hdd_pre_mode_change(mode); + + status = osif_driver_sync_trans_start_wait(&driver_sync); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to start 'mode change'; status:%u", status); + errno = qdf_status_to_os_return(status); + goto exit; + } + + osif_driver_sync_wait_for_ops(driver_sync); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto trans_stop; + + errno = __hdd_driver_mode_change(hdd_ctx, mode); + +trans_stop: + osif_driver_sync_trans_stop(driver_sync); + +exit: + hdd_exit(); + + return errno; +} + +static int hdd_set_con_mode(enum QDF_GLOBAL_MODE mode) +{ + con_mode = mode; + + return 0; +} + +static int (*hdd_set_con_mode_cb)(enum QDF_GLOBAL_MODE mode) = hdd_set_con_mode; + +static void hdd_driver_mode_change_register(void) +{ + hdd_set_con_mode_cb = hdd_driver_mode_change; +} + +static void hdd_driver_mode_change_unregister(void) +{ + hdd_set_con_mode_cb = hdd_set_con_mode; +} + +static int con_mode_handler(const char *kmessage, const struct kernel_param *kp) +{ + enum QDF_GLOBAL_MODE mode; + int errno; + + errno = hdd_parse_driver_mode(kmessage, &mode); + if (errno) { + hdd_err_rl("Failed to parse driver mode '%s'", kmessage); + return errno; + } + + return hdd_set_con_mode_cb(mode); +} + +/* + * If the wlan_hdd_register_driver will return an error + * if the wlan driver tries to register with the + * platform driver before cnss_probe is completed. + * Depending on the error code, the wlan driver waits + * and retries to register. + */ + +/* Max number of retries (arbitrary)*/ +#define HDD_MAX_PLD_REGISTER_RETRY (50) + +/* Max amount of time we sleep before each retry */ +#define HDD_PLD_REGISTER_FAIL_SLEEP_DURATION (100) + +static int hdd_register_driver_retry(void) +{ + int count = 0; + int errno; + + while (true) { + errno = wlan_hdd_register_driver(); + if (errno != -EAGAIN) + return errno; + hdd_nofl_info("Retry Platform Driver Registration; errno:%d count:%d", + errno, count); + if (++count == HDD_MAX_PLD_REGISTER_RETRY) + return errno; + msleep(HDD_PLD_REGISTER_FAIL_SLEEP_DURATION); + continue; + } + + return errno; +} + +/** + * hdd_create_wifi_feature_interface() - Create wifi feature interface + * + * Return: none + */ +static void hdd_create_wifi_feature_interface(void) +{ + hdd_sysfs_create_wifi_root_obj(); + hdd_create_wifi_feature_interface_sysfs_file(); +} + +int hdd_driver_load(void) +{ + struct osif_driver_sync *driver_sync; + QDF_STATUS status; + int errno; + bool soft_load; + + pr_info("%s: Loading driver v%s\n", WLAN_MODULE_NAME, + g_wlan_driver_version); + hdd_place_marker(NULL, "START LOADING", NULL); + + status = hdd_qdf_init(); + if (QDF_IS_STATUS_ERROR(status)) { + errno = qdf_status_to_os_return(status); + goto exit; + } + + osif_sync_init(); + + status = osif_driver_sync_create_and_trans(&driver_sync); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init driver sync; status:%u", status); + errno = qdf_status_to_os_return(status); + goto sync_deinit; + } + + errno = hdd_init(); + if (errno) { + hdd_err("Failed to init HDD; errno:%d", errno); + goto trans_stop; + } + + status = hdd_component_cb_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init component cb; status:%u", status); + errno = qdf_status_to_os_return(status); + goto hdd_deinit; + } + + status = hdd_component_init(); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to init components; status:%u", status); + errno = qdf_status_to_os_return(status); + goto comp_cb_deinit; + } + + status = qdf_wake_lock_create(&wlan_wake_lock, "wlan"); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to create wake lock; status:%u", status); + errno = qdf_status_to_os_return(status); + goto comp_deinit; + } + + hdd_set_conparam(con_mode); + + errno = pld_init(); + if (errno) { + hdd_err("Failed to init PLD; errno:%d", errno); + goto wakelock_destroy; + } + + /* driver mode pass to cnss2 platform driver*/ + errno = pld_set_mode(con_mode); + if (errno) + hdd_err("Failed to set mode in PLD; errno:%d", errno); + + hdd_driver_mode_change_register(); + + osif_driver_sync_register(driver_sync); + osif_driver_sync_trans_stop(driver_sync); + + /* psoc probe can happen in registration; do after 'load' transition */ + errno = hdd_register_driver_retry(); + if (errno) { + hdd_err("Failed to register driver; errno:%d", errno); + goto pld_deinit; + } + + /* If a soft unload of driver is done, we don't call + * wlan_hdd_state_ctrl_param_destroy() to maintain sync + * with userspace. In Symmetry, during soft load, avoid + * calling wlan_hdd_state_ctrl_param_create(). + */ + soft_load = hdd_get_wlan_driver_status(); + if (soft_load) + goto out; + + errno = wlan_hdd_state_ctrl_param_create(); + if (errno) { + hdd_err("Failed to create ctrl param; errno:%d", errno); + goto unregister_driver; + } + hdd_create_wifi_feature_interface(); +out: + hdd_debug("%s: driver loaded", WLAN_MODULE_NAME); + hdd_place_marker(NULL, "DRIVER LOADED", NULL); + + return 0; + +unregister_driver: + wlan_hdd_unregister_driver(); +pld_deinit: + status = osif_driver_sync_trans_start(&driver_sync); + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + + osif_driver_sync_unregister(); + if (driver_sync) + osif_driver_sync_wait_for_ops(driver_sync); + + hdd_driver_mode_change_unregister(); + pld_deinit(); + + hdd_start_complete(errno); + /* Wait for any ref taken on /dev/wlan to be released */ + while (qdf_atomic_read(&wlan_hdd_state_fops_ref)) + ; +wakelock_destroy: + qdf_wake_lock_destroy(&wlan_wake_lock); +comp_deinit: + hdd_component_deinit(); +comp_cb_deinit: + hdd_component_cb_deinit(); +hdd_deinit: + hdd_deinit(); +trans_stop: + if (driver_sync) { + osif_driver_sync_trans_stop(driver_sync); + osif_driver_sync_destroy(driver_sync); + } +sync_deinit: + osif_sync_deinit(); + hdd_qdf_deinit(); + +exit: + return errno; +} + +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(hdd_driver_load); +#endif + +/** + * hdd_distroy_wifi_feature_interface() - Distroy wifi feature interface + * + * Return: none + */ +static void hdd_distroy_wifi_feature_interface(void) +{ + hdd_destroy_wifi_feature_interface_sysfs_file(); + hdd_sysfs_destroy_wifi_root_obj(); +} + +void hdd_driver_unload(void) +{ + struct osif_driver_sync *driver_sync; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + void *hif_ctx; + bool soft_unload; + + soft_unload = hdd_get_wlan_driver_status(); + if (soft_unload) { + pr_info("%s: Soft Unloading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + } else { + pr_info("%s: Hard Unloading driver v%s\n", WLAN_MODULE_NAME, + QWLAN_VERSIONSTR); + } + + hdd_place_marker(NULL, "START UNLOADING", NULL); + + /* + * Wait for any trans to complete and then start the driver trans + * for the unload. This will ensure that the driver trans proceeds only + * after all trans have been completed. As a part of this trans, set + * the driver load/unload flag to further ensure that any upcoming + * trans are rejected via wlan_hdd_validate_context. + */ + status = osif_driver_sync_trans_start_wait(&driver_sync); + if (QDF_IS_STATUS_ERROR(status) && status != -ETIMEDOUT) { + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + hdd_err("Unable to unload wlan; status:%u", status); + hdd_place_marker(NULL, "UNLOAD FAILURE", NULL); + return; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (hif_ctx) { + /* + * Trigger runtime sync resume before setting unload in progress + * such that resume can happen successfully + */ + qdf_rtpm_sync_resume(); + } + + cds_set_driver_loaded(false); + cds_set_unload_in_progress(true); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (hdd_ctx) { + hdd_psoc_idle_timer_stop(hdd_ctx); + /* + * Runtime PM sync resume may have started the bus bandwidth + * periodic work hence stop it. + */ + ucfg_dp_bus_bw_compute_timer_stop(hdd_ctx->psoc); + } + + /* + * Stop the trans before calling unregister_driver as that involves a + * call to pld_remove which in itself is a psoc transaction + */ + if (driver_sync) + osif_driver_sync_trans_stop(driver_sync); + + hdd_distroy_wifi_feature_interface(); + if (!soft_unload) + wlan_hdd_state_ctrl_param_destroy(); + + /* trigger SoC remove */ + wlan_hdd_unregister_driver(); + + status = osif_driver_sync_trans_start_wait(&driver_sync); + if (QDF_IS_STATUS_ERROR(status) && status != -ETIMEDOUT) { + QDF_BUG(QDF_IS_STATUS_SUCCESS(status)); + hdd_err("Unable to unload wlan; status:%u", status); + hdd_place_marker(NULL, "UNLOAD FAILURE", NULL); + return; + } + + osif_driver_sync_unregister(); + if (driver_sync) + osif_driver_sync_wait_for_ops(driver_sync); + + hdd_driver_mode_change_unregister(); + pld_deinit(); + hdd_set_conparam(0); + qdf_wake_lock_destroy(&wlan_wake_lock); + hdd_component_deinit(); + hdd_component_cb_deinit(); + hdd_deinit(); + + if (driver_sync) { + osif_driver_sync_trans_stop(driver_sync); + osif_driver_sync_destroy(driver_sync); + } + osif_sync_deinit(); + + hdd_qdf_deinit(); + hdd_place_marker(NULL, "UNLOAD DONE", NULL); +} + +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(hdd_driver_unload); +#endif + +#ifndef MODULE +/** + * wlan_boot_cb() - Wlan boot callback + * @kobj: object whose directory we're creating the link in. + * @attr: attribute the user is interacting with + * @buf: the buffer containing the user data + * @count: number of bytes in the buffer + * + * This callback is invoked when the fs is ready to start the + * wlan driver initialization. + * + * Return: 'count' on success or a negative error code in case of failure + */ +static ssize_t wlan_boot_cb(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + + if (wlan_loader->loaded_state) { + hdd_err("wlan driver already initialized"); + return -EALREADY; + } + + if (hdd_driver_load()) + return -EIO; + + wlan_loader->loaded_state = MODULE_INITIALIZED; + + return count; +} + +/** + * hdd_sysfs_cleanup() - cleanup sysfs + * + * Return: None + * + */ +static void hdd_sysfs_cleanup(void) +{ + /* remove from group */ + if (wlan_loader->boot_wlan_obj && wlan_loader->attr_group) + sysfs_remove_group(wlan_loader->boot_wlan_obj, + wlan_loader->attr_group); + + /* unlink the object from parent */ + kobject_del(wlan_loader->boot_wlan_obj); + + /* free the object */ + kobject_put(wlan_loader->boot_wlan_obj); + + kfree(wlan_loader->attr_group); + kfree(wlan_loader); + + wlan_loader = NULL; +} + +/** + * wlan_init_sysfs() - Creates the sysfs to be invoked when the fs is + * ready + * + * This is creates the syfs entry boot_wlan. Which shall be invoked + * when the filesystem is ready. + * + * QDF API cannot be used here since this function is called even before + * initializing WLAN driver. + * + * Return: 0 for success, errno on failure + */ +static int wlan_init_sysfs(void) +{ + int ret = -ENOMEM; + + wlan_loader = kzalloc(sizeof(*wlan_loader), GFP_KERNEL); + if (!wlan_loader) + return -ENOMEM; + + wlan_loader->boot_wlan_obj = NULL; + wlan_loader->attr_group = kzalloc(sizeof(*(wlan_loader->attr_group)), + GFP_KERNEL); + if (!wlan_loader->attr_group) + goto error_return; + + wlan_loader->loaded_state = 0; + wlan_loader->attr_group->attrs = attrs; + + wlan_loader->boot_wlan_obj = kobject_create_and_add(WLAN_LOADER_NAME, + kernel_kobj); + if (!wlan_loader->boot_wlan_obj) { + hdd_err("sysfs create and add failed"); + goto error_return; + } + + ret = sysfs_create_group(wlan_loader->boot_wlan_obj, + wlan_loader->attr_group); + if (ret) { + hdd_err("sysfs create group failed; errno:%d", ret); + goto error_return; + } + + return 0; + +error_return: + hdd_sysfs_cleanup(); + + return ret; +} + +/** + * wlan_deinit_sysfs() - Removes the sysfs created to initialize the wlan + * + * Return: 0 on success or errno on failure + */ +static int wlan_deinit_sysfs(void) +{ + if (!wlan_loader) { + hdd_err("wlan_loader is null"); + return -EINVAL; + } + + hdd_sysfs_cleanup(); + return 0; +} + +#endif /* MODULE */ + +#ifdef MODULE +/** + * hdd_module_init() - Module init helper + * + * Module init helper function used by both module and static driver. + * + * Return: 0 for success, errno on failure + */ +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +static int hdd_module_init(void) +{ + return 0; +} +#else +static int hdd_module_init(void) +{ + if (hdd_driver_load()) + return -EINVAL; + + return 0; +} +#endif +#else +static int __init hdd_module_init(void) +{ + int ret = -EINVAL; + + ret = wlan_init_sysfs(); + if (ret) + hdd_err("Failed to create sysfs entry"); + + return ret; +} +#endif + + +#ifdef MODULE +/** + * hdd_module_exit() - Exit function + * + * This is the driver exit point (invoked when module is unloaded using rmmod) + * + * Return: None + */ +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +static void __exit hdd_module_exit(void) +{ +} +#else +static void __exit hdd_module_exit(void) +{ + hdd_driver_unload(); +} +#endif +#else +static void __exit hdd_module_exit(void) +{ + hdd_driver_unload(); + wlan_deinit_sysfs(); +} +#endif + +static int fwpath_changed_handler(const char *kmessage, + const struct kernel_param *kp) +{ + return param_set_copystring(kmessage, kp); +} + +static int con_mode_handler_ftm(const char *kmessage, + const struct kernel_param *kp) +{ + int ret; + + ret = param_set_int(kmessage, kp); + + if (cds_is_driver_loaded() || cds_is_load_or_unload_in_progress()) { + pr_err("Driver already loaded or load/unload in progress"); + return -ENOTSUPP; + } + + if (con_mode_ftm != QDF_GLOBAL_FTM_MODE) { + pr_err("Only FTM mode supported!"); + return -ENOTSUPP; + } + + hdd_set_conparam(con_mode_ftm); + con_mode = con_mode_ftm; + + return ret; +} + +#ifdef WLAN_FEATURE_EPPING +static int con_mode_handler_epping(const char *kmessage, + const struct kernel_param *kp) +{ + int ret; + + ret = param_set_int(kmessage, kp); + + if (con_mode_epping != QDF_GLOBAL_EPPING_MODE) { + pr_err("Only EPPING mode supported!"); + return -ENOTSUPP; + } + + hdd_set_conparam(con_mode_epping); + con_mode = con_mode_epping; + + return ret; +} +#endif + +/** + * hdd_get_conparam() - driver exit point + * + * This is the driver exit point (invoked when module is unloaded using rmmod) + * + * Return: enum QDF_GLOBAL_MODE + */ +enum QDF_GLOBAL_MODE hdd_get_conparam(void) +{ + return (enum QDF_GLOBAL_MODE) curr_con_mode; +} + +void hdd_set_conparam(int32_t con_param) +{ + curr_con_mode = con_param; +} + +/** + * hdd_svc_fw_crashed_ind() - API to send FW CRASHED IND to Userspace + * + * Return: void + */ +static void hdd_svc_fw_crashed_ind(void) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_FW_CRASHED_IND, + NULL, 0) : 0; +} + +/** + * hdd_update_ol_config - API to update ol configuration parameters + * @hdd_ctx: HDD context + * + * Return: void + */ +static void hdd_update_ol_config(struct hdd_context *hdd_ctx) +{ + struct ol_config_info cfg = {0}; + struct ol_context *ol_ctx = cds_get_context(QDF_MODULE_ID_BMI); + bool self_recovery = false; + QDF_STATUS status; + + if (!ol_ctx) + return; + + status = ucfg_mlme_get_self_recovery(hdd_ctx->psoc, &self_recovery); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get self recovery ini config"); + + cfg.enable_self_recovery = self_recovery; + cfg.enable_uart_print = hdd_ctx->config->enablefwprint; + cfg.enable_fw_log = hdd_ctx->config->enable_fw_log; + cfg.enable_ramdump_collection = hdd_ctx->config->is_ramdump_enabled; + cfg.enable_lpass_support = hdd_lpass_is_supported(hdd_ctx); + + ol_init_ini_config(ol_ctx, &cfg); + ol_set_fw_crashed_cb(ol_ctx, hdd_svc_fw_crashed_ind); +} + +#ifdef FEATURE_RUNTIME_PM +/** + * hdd_populate_runtime_cfg() - populate runtime configuration + * @hdd_ctx: hdd context + * @cfg: pointer to the configuration memory being populated + * + * Return: void + */ +static void hdd_populate_runtime_cfg(struct hdd_context *hdd_ctx, + struct hif_config_info *cfg) +{ + cfg->enable_runtime_pm = hdd_ctx->config->runtime_pm; + cfg->runtime_pm_delay = + ucfg_pmo_get_runtime_pm_delay(hdd_ctx->psoc); +} +#else +static void hdd_populate_runtime_cfg(struct hdd_context *hdd_ctx, + struct hif_config_info *cfg) +{ +} +#endif + +#ifdef FEATURE_ENABLE_CE_DP_IRQ_AFFINE +/** + * hdd_populate_ce_dp_irq_affine_cfg() - populate ce irq affine configuration + * @hdd_ctx: hdd context + * @cfg: pointer to the configuration memory being populated + * + * Return: void + */ +static void hdd_populate_ce_dp_irq_affine_cfg(struct hdd_context *hdd_ctx, + struct hif_config_info *cfg) +{ + cfg->enable_ce_dp_irq_affine = cfg_get(hdd_ctx->psoc, + CFG_ENABLE_CE_DP_IRQ_AFFINE); +} +#else +static void hdd_populate_ce_dp_irq_affine_cfg(struct hdd_context *hdd_ctx, + struct hif_config_info *cfg) +{ +} +#endif + +/** + * hdd_update_hif_config - API to update HIF configuration parameters + * @hdd_ctx: HDD Context + * + * Return: void + */ +static void hdd_update_hif_config(struct hdd_context *hdd_ctx) +{ + struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF); + struct hif_config_info cfg = {0}; + bool prevent_link_down = false; + bool self_recovery = false; + QDF_STATUS status; + + if (!scn) + return; + + status = ucfg_mlme_get_prevent_link_down(hdd_ctx->psoc, + &prevent_link_down); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get prevent_link_down config"); + + status = ucfg_mlme_get_self_recovery(hdd_ctx->psoc, &self_recovery); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get self recovery ini config"); + + cfg.enable_self_recovery = self_recovery; + hdd_populate_runtime_cfg(hdd_ctx, &cfg); + cfg.rx_softirq_max_yield_duration_ns = + ucfg_dp_get_rx_softirq_yield_duration(hdd_ctx->psoc); + hdd_populate_ce_dp_irq_affine_cfg(hdd_ctx, &cfg); + + hif_init_ini_config(scn, &cfg); + hif_set_enable_rpm(scn); + + if (prevent_link_down) + hif_vote_link_up(scn); +} + +/** + * hdd_update_dp_config() - Propagate config parameters to Lithium + * datapath + * @hdd_ctx: HDD Context + * + * Return: 0 for success/errno for failure + */ +static int hdd_update_dp_config(struct hdd_context *hdd_ctx) +{ + struct wlan_dp_user_config dp_cfg; + QDF_STATUS status; + + dp_cfg.ipa_enable = ucfg_ipa_is_enabled(); + dp_cfg.arp_connectivity_map = CONNECTIVITY_CHECK_SET_ARP; + + status = ucfg_dp_update_config(hdd_ctx->psoc, &dp_cfg); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed DP PSOC configuration update"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_update_config() - Initialize driver per module ini parameters + * @hdd_ctx: HDD Context + * + * API is used to initialize all driver per module configuration parameters + * Return: 0 for success, errno for failure + */ +int hdd_update_config(struct hdd_context *hdd_ctx) +{ + int ret; + + if (ucfg_pmo_is_ns_offloaded(hdd_ctx->psoc)) + hdd_ctx->ns_offload_enable = true; + + hdd_update_ol_config(hdd_ctx); + hdd_update_hif_config(hdd_ctx); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + ret = hdd_update_cds_config_ftm(hdd_ctx); + else + ret = hdd_update_cds_config(hdd_ctx); + ret = hdd_update_user_config(hdd_ctx); + + hdd_update_regdb_offload_config(hdd_ctx); + + return ret; +} + +/** + * hdd_update_pmo_config - API to update pmo configuration parameters + * @hdd_ctx: HDD context + * + * Return: void + */ +static int hdd_update_pmo_config(struct hdd_context *hdd_ctx) +{ + struct pmo_psoc_cfg psoc_cfg = {0}; + QDF_STATUS status; + enum pmo_wow_enable_type wow_enable; + + ucfg_pmo_get_psoc_config(hdd_ctx->psoc, &psoc_cfg); + + /* + * Value of hdd_ctx->wowEnable can be, + * 0 - Disable both magic pattern match and pattern byte match. + * 1 - Enable magic pattern match on all interfaces. + * 2 - Enable pattern byte match on all interfaces. + * 3 - Enable both magic pattern and pattern byte match on + * all interfaces. + */ + wow_enable = ucfg_pmo_get_wow_enable(hdd_ctx->psoc); + psoc_cfg.magic_ptrn_enable = (wow_enable & 0x01) ? true : false; + psoc_cfg.ptrn_match_enable_all_vdev = + (wow_enable & 0x02) ? true : false; + psoc_cfg.ap_arpns_support = hdd_ctx->ap_arpns_support; + psoc_cfg.d0_wow_supported = wma_d0_wow_is_supported(); + ucfg_mlme_get_sap_max_modulated_dtim(hdd_ctx->psoc, + &psoc_cfg.sta_max_li_mod_dtim); + + hdd_lpass_populate_pmo_config(&psoc_cfg, hdd_ctx); + + status = ucfg_pmo_update_psoc_config(hdd_ctx->psoc, &psoc_cfg); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed pmo psoc configuration; status:%d", status); + + return qdf_status_to_os_return(status); +} + +void hdd_update_ie_allowlist_attr(struct probe_req_allowlist_attr *ie_allowlist, + struct hdd_context *hdd_ctx) +{ + struct wlan_fwol_ie_allowlist allowlist = {0}; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + QDF_STATUS status; + bool is_ie_allowlist_enable = false; + uint8_t i = 0; + + status = ucfg_fwol_get_ie_allowlist(psoc, &is_ie_allowlist_enable); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get IE allowlist param"); + return; + } + + ie_allowlist->allow_list = is_ie_allowlist_enable; + if (!ie_allowlist->allow_list) + return; + + status = ucfg_fwol_get_all_allowlist_params(psoc, &allowlist); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get all allowlist params"); + return; + } + + ie_allowlist->ie_bitmap[0] = allowlist.ie_bitmap_0; + ie_allowlist->ie_bitmap[1] = allowlist.ie_bitmap_1; + ie_allowlist->ie_bitmap[2] = allowlist.ie_bitmap_2; + ie_allowlist->ie_bitmap[3] = allowlist.ie_bitmap_3; + ie_allowlist->ie_bitmap[4] = allowlist.ie_bitmap_4; + ie_allowlist->ie_bitmap[5] = allowlist.ie_bitmap_5; + ie_allowlist->ie_bitmap[6] = allowlist.ie_bitmap_6; + ie_allowlist->ie_bitmap[7] = allowlist.ie_bitmap_7; + + ie_allowlist->num_vendor_oui = allowlist.no_of_probe_req_ouis; + for (i = 0; i < ie_allowlist->num_vendor_oui; i++) + ie_allowlist->voui[i] = allowlist.probe_req_voui[i]; +} + +QDF_STATUS hdd_update_score_config(struct hdd_context *hdd_ctx) +{ + struct hdd_config *cfg = hdd_ctx->config; + eCsrPhyMode phy_mode = hdd_cfg_xlate_to_csr_phy_mode(cfg->dot11Mode); + + sme_update_score_config(hdd_ctx->mac_handle, phy_mode, + hdd_ctx->num_rf_chains); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_update_dfs_config() - API to update dfs configuration parameters. + * @hdd_ctx: HDD context + * + * Return: 0 if success else err + */ +static int hdd_update_dfs_config(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct dfs_user_config dfs_cfg = {0}; + QDF_STATUS status; + + ucfg_mlme_get_dfs_filter_offload(hdd_ctx->psoc, + &dfs_cfg.dfs_is_phyerr_filter_offload); + status = ucfg_dfs_update_config(psoc, &dfs_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed dfs psoc configuration"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_update_scan_config - API to update scan configuration parameters + * @hdd_ctx: HDD context + * + * Return: 0 if success else err + */ +int hdd_update_scan_config(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct scan_user_cfg scan_cfg; + QDF_STATUS status; + uint32_t mcast_mcc_rest_time = 0; + + qdf_mem_zero(&scan_cfg, sizeof(scan_cfg)); + status = ucfg_mlme_get_sta_miracast_mcc_rest_time(hdd_ctx->psoc, + &mcast_mcc_rest_time); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("ucfg_mlme_get_sta_miracast_mcc_rest_time, use def"); + return -EIO; + } + scan_cfg.sta_miracast_mcc_rest_time = mcast_mcc_rest_time; + hdd_update_ie_allowlist_attr(&scan_cfg.ie_allowlist, hdd_ctx); + + status = ucfg_scan_update_user_config(psoc, &scan_cfg); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed pmo psoc configuration"); + return -EINVAL; + } + + return 0; +} + +int hdd_update_components_config(struct hdd_context *hdd_ctx) +{ + int ret; + + ret = hdd_update_pmo_config(hdd_ctx); + if (ret) + return ret; + + ret = hdd_update_scan_config(hdd_ctx); + if (ret) + return ret; + + ret = hdd_update_tdls_config(hdd_ctx); + if (ret) + return ret; + + ret = hdd_update_dp_config(hdd_ctx); + if (ret) + return ret; + + ret = hdd_update_dfs_config(hdd_ctx); + if (ret) + return ret; + + ret = hdd_update_regulatory_config(hdd_ctx); + if (ret) + return ret; + + return ret; +} + +/** + * wlan_hdd_get_dfs_mode() - get ACS DFS mode + * @mode : cfg80211 DFS mode + * + * Return: return SAP ACS DFS mode else return ACS_DFS_MODE_NONE + */ +enum sap_acs_dfs_mode wlan_hdd_get_dfs_mode(enum dfs_mode mode) +{ + switch (mode) { + case DFS_MODE_ENABLE: + return ACS_DFS_MODE_ENABLE; + case DFS_MODE_DISABLE: + return ACS_DFS_MODE_DISABLE; + case DFS_MODE_DEPRIORITIZE: + return ACS_DFS_MODE_DEPRIORITIZE; + default: + hdd_debug("ACS dfs mode is NONE"); + return ACS_DFS_MODE_NONE; + } +} + +/** + * hdd_enable_disable_ca_event() - enable/disable channel avoidance event + * @hdd_ctx: pointer to hdd context + * @set_value: enable/disable + * + * When Host sends vendor command enable, FW will send *ONE* CA ind to + * Host(even though it is duplicate). When Host send vendor command + * disable,FW doesn't perform any action. Whenever any change in + * CA *and* WLAN is in SAP/P2P-GO mode, FW sends CA ind to host. + * + * return - 0 on success, appropriate error values on failure. + */ +int hdd_enable_disable_ca_event(struct hdd_context *hdd_ctx, uint8_t set_value) +{ + QDF_STATUS status; + + if (0 != wlan_hdd_validate_context(hdd_ctx)) + return -EAGAIN; + + status = sme_enable_disable_chanavoidind_event(hdd_ctx->mac_handle, + set_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to send chan avoid command to SME"); + return -EINVAL; + } + return 0; +} + +bool hdd_is_roaming_in_progress(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + uint8_t vdev_id; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_ROAMING_IN_PROGRESS; + struct wlan_hdd_link_info *link_info; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return false; + } + + if (!policy_mgr_is_sta_active_connection_exists(hdd_ctx->psoc)) + return false; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (adapter->device_mode != QDF_STA_MODE) + goto adapter_put; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + vdev_id = link_info->vdev_id; + if (test_bit(SME_SESSION_OPENED, + &link_info->link_flags) && + sme_roaming_in_progress(hdd_ctx->mac_handle, + vdev_id)) { + hdd_debug("Roaming is in progress on:vdev_id:%d", + link_info->vdev_id); + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return true; + } + } +adapter_put: + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return false; +} + +/** + * struct hdd_is_connection_in_progress_priv - adapter connection info + * @out_vdev_id: id of vdev where connection is occurring + * @out_reason: scan reject reason + * @connection_in_progress: true if connection is in progress + */ +struct hdd_is_connection_in_progress_priv { + uint8_t out_vdev_id; + enum scan_reject_states out_reason; + bool connection_in_progress; +}; + +/** + * hdd_is_connection_in_progress_iterator() - Check adapter connection based + * on device mode + * @link_info: Link info pointer in HDD adapter + * @ctx: user context supplied + * + * Check if connection is in progress for the current adapter according to the + * device mode + * + * Return: + * * QDF_STATUS_SUCCESS if iteration should continue + * * QDF_STATUS_E_ABORTED if iteration should be aborted + */ +static QDF_STATUS +hdd_is_connection_in_progress_iterator(struct wlan_hdd_link_info *link_info, + void *ctx) +{ + struct hdd_station_ctx *hdd_sta_ctx; + uint8_t *sta_mac; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + struct hdd_station_info *sta_info, *tmp = NULL; + struct hdd_is_connection_in_progress_priv *context = ctx; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return QDF_STATUS_E_ABORTED; + + mac_handle = hdd_ctx->mac_handle; + + if (!test_bit(SME_SESSION_OPENED, &link_info->link_flags) && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_SAP_MODE)) + return QDF_STATUS_SUCCESS; + + if ((QDF_STA_MODE == adapter->device_mode || + QDF_P2P_CLIENT_MODE == adapter->device_mode || + QDF_P2P_DEVICE_MODE == adapter->device_mode) && + hdd_cm_is_connecting(link_info)) { + hdd_debug("%pK(%d) mode %d Connection is in progress", + WLAN_HDD_GET_STATION_CTX_PTR(link_info), + link_info->vdev_id, adapter->device_mode); + + context->out_vdev_id = link_info->vdev_id; + context->out_reason = CONNECTION_IN_PROGRESS; + context->connection_in_progress = true; + + return QDF_STATUS_E_ABORTED; + } + + if ((QDF_STA_MODE == adapter->device_mode) && + sme_roaming_in_progress(mac_handle, link_info->vdev_id)) { + hdd_debug("%pK(%d) mode %d Reassociation in progress", + WLAN_HDD_GET_STATION_CTX_PTR(link_info), + link_info->vdev_id, adapter->device_mode); + + context->out_vdev_id = link_info->vdev_id; + context->out_reason = REASSOC_IN_PROGRESS; + context->connection_in_progress = true; + return QDF_STATUS_E_ABORTED; + } + + if ((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (QDF_P2P_DEVICE_MODE == adapter->device_mode)) { + hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (hdd_cm_is_vdev_associated(link_info) + && sme_is_sta_key_exchange_in_progress( + mac_handle, link_info->vdev_id)) { + sta_mac = (uint8_t *)&(adapter->mac_addr.bytes[0]); + hdd_debug("client " QDF_MAC_ADDR_FMT + " is in middle of WPS/EAPOL exchange.", + QDF_MAC_ADDR_REF(sta_mac)); + + context->out_vdev_id = link_info->vdev_id; + context->out_reason = EAPOL_IN_PROGRESS; + context->connection_in_progress = true; + + return QDF_STATUS_E_ABORTED; + } + } else if ((QDF_SAP_MODE == adapter->device_mode) || + (QDF_P2P_GO_MODE == adapter->device_mode)) { + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR) { + if (sta_info->peer_state != + OL_TXRX_PEER_STATE_CONN) { + hdd_put_sta_info_ref( + &adapter->sta_info_list, &sta_info, true, + STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR); + continue; + } + + sta_mac = sta_info->sta_mac.bytes; + hdd_debug("client " QDF_MAC_ADDR_FMT + " of SAP/GO is in middle of WPS/EAPOL exchange", + QDF_MAC_ADDR_REF(sta_mac)); + + context->out_vdev_id = link_info->vdev_id; + context->out_reason = SAP_EAPOL_IN_PROGRESS; + context->connection_in_progress = true; + + hdd_put_sta_info_ref( + &adapter->sta_info_list, &sta_info, true, + STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, &tmp, true, + STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR); + + return QDF_STATUS_E_ABORTED; + } + if (hdd_ctx->connection_in_progress) { + hdd_debug("AP/GO: vdev %d connection is in progress", + link_info->vdev_id); + context->out_reason = SAP_CONNECTION_IN_PROGRESS; + context->out_vdev_id = link_info->vdev_id; + context->connection_in_progress = true; + + return QDF_STATUS_E_ABORTED; + } + } + + if (ucfg_nan_is_enable_disable_in_progress(hdd_ctx->psoc)) { + context->out_reason = NAN_ENABLE_DISABLE_IN_PROGRESS; + context->out_vdev_id = NAN_PSEUDO_VDEV_ID; + context->connection_in_progress = true; + + return QDF_STATUS_E_ABORTED; + } + + return QDF_STATUS_SUCCESS; +} + +bool hdd_is_connection_in_progress(uint8_t *out_vdev_id, + enum scan_reject_states *out_reason) +{ + struct hdd_is_connection_in_progress_priv hdd_conn; + hdd_adapter_iterate_cb cb; + + hdd_conn.out_vdev_id = 0; + hdd_conn.out_reason = SCAN_REJECT_DEFAULT; + hdd_conn.connection_in_progress = false; + + cb = hdd_is_connection_in_progress_iterator; + + hdd_adapter_iterate(cb, &hdd_conn); + + if (hdd_conn.connection_in_progress && out_vdev_id && out_reason) { + *out_vdev_id = hdd_conn.out_vdev_id; + *out_reason = hdd_conn.out_reason; + } + + return hdd_conn.connection_in_progress; +} + +void hdd_restart_sap(struct wlan_hdd_link_info *link_info) +{ + struct hdd_hostapd_state *hapd_state; + QDF_STATUS status; + struct hdd_adapter *ap_adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(ap_adapter); + struct sap_config *sap_config; + void *sap_ctx; + + sap_config = + &(WLAN_HDD_GET_AP_CTX_PTR(link_info)->sap_config); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + + mutex_lock(&hdd_ctx->sap_lock); + if (test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + wlan_hdd_del_station(ap_adapter, NULL); + hapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + qdf_event_reset(&hapd_state->qdf_stop_bss_event); + if (QDF_STATUS_SUCCESS == wlansap_stop_bss(sap_ctx)) { + status = qdf_wait_single_event(&hapd_state->qdf_stop_bss_event, + SME_CMD_STOP_BSS_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("SAP Stop Failed"); + goto end; + } + } + clear_bit(SOFTAP_BSS_STARTED, &link_info->link_flags); + policy_mgr_decr_session_set_pcl(hdd_ctx->psoc, + ap_adapter->device_mode, link_info->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, ap_adapter->device_mode, + false); + hdd_err("SAP Stop Success"); + + if (0 != wlan_hdd_cfg80211_update_apies(link_info)) { + hdd_err("SAP Not able to set AP IEs"); + goto end; + } + + status = wlan_hdd_mlo_sap_reinit(link_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("SAP Not able to do mlo attach"); + goto deinit_mlo; + } + + qdf_event_reset(&hapd_state->qdf_event); + status = wlansap_start_bss(sap_ctx, hdd_hostapd_sap_event_cb, + sap_config, ap_adapter->dev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("SAP Start Bss fail"); + goto deinit_mlo; + } + + hdd_info("Waiting for SAP to start"); + status = qdf_wait_single_event(&hapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("SAP Start failed"); + goto deinit_mlo; + } + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + hdd_err("SAP Start Success"); + set_bit(SOFTAP_BSS_STARTED, &link_info->link_flags); + if (hapd_state->bss_state == BSS_START) { + policy_mgr_incr_active_session(hdd_ctx->psoc, + ap_adapter->device_mode, + link_info->vdev_id); + hdd_green_ap_start_state_mc(hdd_ctx, + ap_adapter->device_mode, + true); + } + } + mutex_unlock(&hdd_ctx->sap_lock); + return; + +deinit_mlo: + wlan_hdd_mlo_reset(link_info); +end: + wlansap_reset_sap_config_add_ie(sap_config, eUPDATE_IE_ALL); + mutex_unlock(&hdd_ctx->sap_lock); +} + +/** + * hdd_set_connection_in_progress() - to set the connection in + * progress flag + * @value: value to set + * + * This function will set the passed value to connection in progress flag. + * If value is previously being set to true then no need to set it again. + * + * Return: true if value is being set correctly and false otherwise. + */ +bool hdd_set_connection_in_progress(bool value) +{ + bool status = true; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return false; + + qdf_spin_lock(&hdd_ctx->connection_status_lock); + /* + * if the value is set to true previously and if someone is + * trying to make it true again then it could be some race + * condition being triggered. Avoid this situation by returning + * false + */ + if (hdd_ctx->connection_in_progress && value) + status = false; + else + hdd_ctx->connection_in_progress = value; + qdf_spin_unlock(&hdd_ctx->connection_status_lock); + return status; +} + +int wlan_hdd_send_mcc_vdev_quota(struct hdd_adapter *adapter, int set_value) +{ + if (!adapter) { + hdd_err("Invalid adapter"); + return -EINVAL; + } + hdd_info("send mcc vdev quota to fw: %d", set_value); + sme_cli_set_command(adapter->deflink->vdev_id, + WMA_VDEV_MCC_SET_TIME_QUOTA, + set_value, VDEV_CMD); + return 0; + +} + +int wlan_hdd_send_mcc_latency(struct hdd_adapter *adapter, int set_value) +{ + if (!adapter) { + hdd_err("Invalid adapter"); + return -EINVAL; + } + + hdd_info("Send MCC latency WMA: %d", set_value); + sme_cli_set_command(adapter->deflink->vdev_id, + WMA_VDEV_MCC_SET_TIME_LATENCY, + set_value, VDEV_CMD); + return 0; +} + +struct wlan_hdd_link_info * +wlan_hdd_get_link_info_from_vdev(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + + /* + * Currently PSOC is not being used. But this logic will + * change once we have the converged implementation of + * HDD context per PSOC in place. This would break if + * multiple vdev objects reuse the vdev id. + */ + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Get adapter by vdev id failed"); + return NULL; + } + + return link_info; +} + +int hdd_get_rssi_snr_by_bssid(mac_handle_t mac_handle, const uint8_t *bssid, + int8_t *rssi, int8_t *snr) +{ + QDF_STATUS status; + + status = sme_get_rssi_snr_by_bssid(mac_handle, bssid, rssi, snr); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("sme_get_rssi_snr_by_bssid failed"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_reset_limit_off_chan() - reset limit off-channel command parameters + * @adapter: HDD adapter + * + * Return: 0 on success and non zero value on failure + */ +int hdd_reset_limit_off_chan(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + int ret; + QDF_STATUS status; + uint8_t sys_pref = 0; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret < 0) + return ret; + + ucfg_policy_mgr_get_sys_pref(hdd_ctx->psoc, + &sys_pref); + /* set the system preferece to default */ + policy_mgr_set_cur_conc_system_pref(hdd_ctx->psoc, sys_pref); + + /* clear the bitmap */ + adapter->active_ac = 0; + + hdd_debug("reset ac_bitmap for session %hu active_ac %0x", + adapter->deflink->vdev_id, adapter->active_ac); + + status = sme_send_limit_off_channel_params(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + false, 0, 0, false); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("failed to reset limit off chan params"); + ret = -EINVAL; + } + + return ret; +} + +void hdd_hidden_ssid_enable_roaming(hdd_handle_t hdd_handle, uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct wlan_hdd_link_info *link_info; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + /* enable roaming on all adapters once hdd get hidden ssid rsp */ + wlan_hdd_set_roaming_state(link_info, RSO_START_BSS, true); +} + +#ifdef WLAN_FEATURE_PKT_CAPTURE +bool wlan_hdd_is_mon_concurrency(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return -EINVAL; + + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + if (policy_mgr_get_concurrency_mode(hdd_ctx->psoc) == + (QDF_STA_MASK | QDF_MONITOR_MASK)) { + hdd_err("STA + MON mode is UP"); + return true; + } + } + return false; +} + +void wlan_hdd_del_monitor(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool rtnl_held) +{ + wlan_hdd_release_intf_addr(hdd_ctx, adapter->mac_addr.bytes); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_close_adapter(hdd_ctx, adapter, true); + + hdd_open_p2p_interface(hdd_ctx); +} + +void +wlan_hdd_del_p2p_interface(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + struct osif_vdev_sync *vdev_sync; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_DEL_P2P_INTERFACE) { + if (adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + vdev_sync = osif_vdev_sync_unregister(adapter->dev); + if (vdev_sync) + osif_vdev_sync_wait_for_ops(vdev_sync); + + hdd_adapter_dev_put_debug( + adapter, NET_DEV_HOLD_DEL_P2P_INTERFACE); + + hdd_clean_up_interface(hdd_ctx, adapter); + + if (vdev_sync) + osif_vdev_sync_destroy(vdev_sync); + } else + hdd_adapter_dev_put_debug( + adapter, NET_DEV_HOLD_DEL_P2P_INTERFACE); + } +} + +#endif /* WLAN_FEATURE_PKT_CAPTURE */ + +bool wlan_hdd_is_session_type_monitor(uint8_t session_type) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) { + cds_err("HDD context is NULL"); + return false; + } + + if (cds_get_conparam() != QDF_GLOBAL_MONITOR_MODE && + session_type == QDF_MONITOR_MODE) + return true; + else + return false; +} + +int +wlan_hdd_add_monitor_check(struct hdd_context *hdd_ctx, + struct hdd_adapter **adapter, + const char *name, bool rtnl_held, + unsigned char name_assign_type, bool is_rx_mon) +{ + struct hdd_adapter *sta_adapter; + struct hdd_adapter *mon_adapter; + uint8_t num_open_session = 0; + QDF_STATUS status; + struct hdd_adapter_create_param params = {0}; + + sta_adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (!sta_adapter) { + hdd_err("No station adapter"); + return -EINVAL; + } + + status = policy_mgr_check_mon_concurrency(hdd_ctx->psoc); + + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + if (hdd_is_connection_in_progress(NULL, NULL)) { + hdd_err("cannot add monitor mode, Connection in progress"); + return -EINVAL; + } + + if (is_rx_mon) { + num_open_session = policy_mgr_mode_specific_connection_count( + hdd_ctx->psoc, + PM_STA_MODE, + NULL); + + if (num_open_session) { + /* Try disconnecting if already in connected state */ + wlan_hdd_cm_issue_disconnect(sta_adapter->deflink, + REASON_UNSPEC_FAILURE, + true); + } + } + + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) + wlan_hdd_del_p2p_interface(hdd_ctx); + + params.is_add_virtual_iface = 1; + + mon_adapter = hdd_open_adapter(hdd_ctx, QDF_MONITOR_MODE, name, + wlan_hdd_get_intf_addr( + hdd_ctx, + QDF_MONITOR_MODE), + name_assign_type, rtnl_held, ¶ms); + if (!mon_adapter) { + hdd_err("hdd_open_adapter failed"); + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) + hdd_open_p2p_interface(hdd_ctx); + return -EINVAL; + } + + if (mon_adapter) + hdd_set_idle_ps_config(hdd_ctx, false); + + *adapter = mon_adapter; + return 0; +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT + +void hdd_sme_monitor_mode_callback(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err_rl("NULL adapter"); + return; + } + + adapter = link_info->adapter; + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err_rl("Invalid magic"); + return; + } + + qdf_event_set(&adapter->qdf_monitor_mode_vdev_up_event); + + hdd_debug("monitor mode vdev up completed"); + adapter->monitor_mode_vdev_up_in_progress = false; +} + +QDF_STATUS hdd_monitor_mode_qdf_create_event(struct hdd_adapter *adapter, + uint8_t session_type) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (session_type == QDF_MONITOR_MODE) { + qdf_status = qdf_event_create( + &adapter->qdf_monitor_mode_vdev_up_event); + } + return qdf_status; +} + +QDF_STATUS hdd_monitor_mode_vdev_status(struct hdd_adapter *adapter) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!adapter->monitor_mode_vdev_up_in_progress) + return status; + + /* block on a completion variable until vdev up success*/ + status = qdf_wait_for_event_completion( + &adapter->qdf_monitor_mode_vdev_up_event, + WLAN_MONITOR_MODE_VDEV_UP_EVT); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("monitor mode vdev up event time out vdev id: %d", + adapter->deflink->vdev_id); + if (adapter->qdf_monitor_mode_vdev_up_event.force_set) + /* + * SSR/PDR has caused shutdown, which has + * forcefully set the event. + */ + hdd_err_rl("monitor mode vdev up event forcefully set"); + else if (status == QDF_STATUS_E_TIMEOUT) + hdd_err_rl("mode vdev up event timed out"); + else + hdd_err_rl("Failed to wait for monitor vdev up(status-%d)", + status); + + adapter->monitor_mode_vdev_up_in_progress = false; + return status; + } + + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) +void hdd_beacon_latency_event_cb(uint32_t latency_level) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + if (latency_level == + QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_ULTRALOW) + wlan_hdd_set_pm_qos_request(hdd_ctx, true); + else + wlan_hdd_set_pm_qos_request(hdd_ctx, false); +} +#endif + +#ifdef CONFIG_WLAN_DEBUG_CRASH_INJECT +int hdd_crash_inject(struct hdd_adapter *adapter, uint32_t v1, uint32_t v2) +{ + struct hdd_context *hdd_ctx; + int ret; + bool crash_inject; + QDF_STATUS status; + + hdd_debug("v1: %d v2: %d", v1, v2); + pr_err("SSR is triggered by CRASH_INJECT: %d %d\n", + v1, v2); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = ucfg_mlme_get_crash_inject(hdd_ctx->psoc, &crash_inject); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get crash inject ini config"); + return 0; + } + + if (!crash_inject) { + hdd_err("Crash Inject ini disabled, Ignore Crash Inject"); + return 0; + } + + if (v1 == 3) { + cds_trigger_recovery(QDF_REASON_UNSPECIFIED); + return 0; + } + ret = wma_cli_set2_command(adapter->deflink->vdev_id, + GEN_PARAM_CRASH_INJECT, + v1, v2, GEN_CMD); + return ret; +} +#endif + +static const struct hdd_chwidth_info chwidth_info[] = { + [NL80211_CHAN_WIDTH_20_NOHT] = { + .ch_bw = HW_MODE_20_MHZ, + .ch_bw_str = "20MHz", + .phy_chwidth = CH_WIDTH_20MHZ, + }, + [NL80211_CHAN_WIDTH_20] = { + .sir_chwidth_valid = true, + .sir_chwidth = eHT_CHANNEL_WIDTH_20MHZ, + .ch_bw = HW_MODE_20_MHZ, + .ch_bw_str = "20MHz", + .phy_chwidth = CH_WIDTH_20MHZ, + .bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE, + }, + [NL80211_CHAN_WIDTH_40] = { + .sir_chwidth_valid = true, + .sir_chwidth = eHT_CHANNEL_WIDTH_40MHZ, + .ch_bw = HW_MODE_40_MHZ, + .ch_bw_str = "40MHz", + .phy_chwidth = CH_WIDTH_40MHZ, + .bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE, + }, + [NL80211_CHAN_WIDTH_80] = { + .sir_chwidth_valid = true, + .sir_chwidth = eHT_CHANNEL_WIDTH_80MHZ, + .ch_bw = HW_MODE_80_MHZ, + .ch_bw_str = "80MHz", + .phy_chwidth = CH_WIDTH_80MHZ, + .bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE, + }, + [NL80211_CHAN_WIDTH_80P80] = { + .sir_chwidth_valid = true, + .sir_chwidth = eHT_CHANNEL_WIDTH_80P80MHZ, + .ch_bw = HW_MODE_80_PLUS_80_MHZ, + .ch_bw_str = "(80 + 80)MHz", + .phy_chwidth = CH_WIDTH_80P80MHZ, + .bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE, + }, + [NL80211_CHAN_WIDTH_160] = { + .sir_chwidth_valid = true, + .sir_chwidth = eHT_CHANNEL_WIDTH_160MHZ, + .ch_bw = HW_MODE_160_MHZ, + .ch_bw_str = "160MHz", + .phy_chwidth = CH_WIDTH_160MHZ, + .bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE, + }, + [NL80211_CHAN_WIDTH_5] = { + .ch_bw = HW_MODE_5_MHZ, + .ch_bw_str = "5MHz", + .phy_chwidth = CH_WIDTH_5MHZ, + }, + [NL80211_CHAN_WIDTH_10] = { + .ch_bw = HW_MODE_10_MHZ, + .ch_bw_str = "10MHz", + .phy_chwidth = CH_WIDTH_10MHZ, + }, +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) + [NL80211_CHAN_WIDTH_320] = { + .sir_chwidth_valid = true, + .sir_chwidth = eHT_CHANNEL_WIDTH_320MHZ, + .ch_bw = HW_MODE_320_MHZ, + .ch_bw_str = "320MHz", + .phy_chwidth = CH_WIDTH_320MHZ, + .bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE, + }, +#endif +}; + +enum eSirMacHTChannelWidth +hdd_nl80211_chwidth_to_chwidth(uint8_t nl80211_chwidth) +{ + if (nl80211_chwidth >= ARRAY_SIZE(chwidth_info) || + !chwidth_info[nl80211_chwidth].sir_chwidth_valid) { + hdd_err("Unsupported channel width %d", nl80211_chwidth); + return -EINVAL; + } + + return chwidth_info[nl80211_chwidth].sir_chwidth; +} + +uint8_t hdd_chwidth_to_nl80211_chwidth(enum eSirMacHTChannelWidth chwidth) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(chwidth_info); i++) { + if (chwidth_info[i].sir_chwidth_valid && + chwidth_info[i].sir_chwidth == chwidth) + return i; + } + + hdd_err("Unsupported channel width %d", chwidth); + return 0xFF; +} + +uint8_t hdd_phy_chwidth_to_nl80211_chwidth(enum phy_ch_width chwidth) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(chwidth_info); i++) { + if (chwidth_info[i].sir_chwidth_valid && + chwidth_info[i].phy_chwidth == chwidth) + return i; + } + + hdd_err("Unsupported channel width %d", chwidth); + return 0xFF; +} + +enum hw_mode_bandwidth wlan_hdd_get_channel_bw(enum nl80211_chan_width width) +{ + if (width >= ARRAY_SIZE(chwidth_info)) { + hdd_err("Invalid width: %d, using default 20MHz", width); + return HW_MODE_20_MHZ; + } + + return chwidth_info[width].ch_bw; +} + +uint8_t *hdd_ch_width_str(enum phy_ch_width ch_width) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(chwidth_info); i++) { + if (chwidth_info[i].phy_chwidth == ch_width) + return chwidth_info[i].ch_bw_str; + } + + return "UNKNOWN"; +} + +int hdd_we_set_ch_width(struct wlan_hdd_link_info *link_info, int ch_width) +{ + int i; + uint8_t link_id = 0xFF; + + /* updating channel bonding only on 5Ghz */ + hdd_debug("wmi_vdev_param_chwidth val %d", ch_width); + + for (i = 0; i < ARRAY_SIZE(chwidth_info); i++) { + if (!chwidth_info[i].sir_chwidth_valid || + chwidth_info[i].sir_chwidth != ch_width) + continue; + + return hdd_update_channel_width(link_info, ch_width, + chwidth_info[i].bonding_mode, + link_id, false); + } + + hdd_err("Invalid ch_width %d", ch_width); + return -EINVAL; +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +bool +wlan_hdd_is_link_switch_in_progress(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool ret = false; + + if (!link_info) { + hdd_err_rl("Invalid link info"); + return ret; + } + + if (!wlan_hdd_is_mlo_connection(link_info)) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) { + hdd_err("invalid vdev"); + return ret; + } + + ret = mlo_mgr_is_link_switch_in_progress(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return ret; +} +#endif + +bool wlan_hdd_is_mlo_connection(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + bool ret = false; + + if (!link_info) { + hdd_err("Invalid link_info"); + return ret; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) { + hdd_err("invalid vdev"); + return ret; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + ret = true; + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return ret; +} + +/* Register the module init/exit functions */ +module_init(hdd_module_init); +module_exit(hdd_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Qualcomm Atheros, Inc."); +MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER"); + +const struct kernel_param_ops con_mode_ops = { + .set = con_mode_handler, + .get = param_get_int, +}; + +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(con_mode_ops); +#endif + +const struct kernel_param_ops con_mode_ftm_ops = { + .set = con_mode_handler_ftm, + .get = param_get_int, +}; + +#ifdef FEATURE_WLAN_RESIDENT_DRIVER +EXPORT_SYMBOL(con_mode_ftm_ops); +#endif + +#ifdef WLAN_FEATURE_EPPING +static const struct kernel_param_ops con_mode_epping_ops = { + .set = con_mode_handler_epping, + .get = param_get_int, +}; +#endif + +static const struct kernel_param_ops fwpath_ops = { + .set = fwpath_changed_handler, + .get = param_get_string, +}; + +static int __pcie_set_gen_speed_handler(void) +{ + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + hdd_info_rl("Received PCIe gen speed %d", pcie_gen_speed); + if (pcie_gen_speed <= HDD_INVALID_MIN_PCIE_GEN_SPEED || + pcie_gen_speed >= HDD_INVALID_MAX_PCIE_GEN_SPEED) { + hdd_err_rl("invalid pcie gen speed %d", pcie_gen_speed); + return -EINVAL; + } + + hdd_ctx->current_pcie_gen_speed = pcie_gen_speed; + + return 0; +} + +static int pcie_set_gen_speed_handler(const char *kmessage, + const struct kernel_param *kp) +{ + struct osif_driver_sync *driver_sync; + int ret; + + ret = osif_driver_sync_op_start(&driver_sync); + if (ret) + return ret; + + ret = param_set_int(kmessage, kp); + if (ret) { + hdd_err_rl("param set int failed %d", ret); + goto out; + } + + ret = __pcie_set_gen_speed_handler(); + +out: + osif_driver_sync_op_stop(driver_sync); + + return ret; +} + +static const struct kernel_param_ops pcie_gen_speed_ops = { + .set = pcie_set_gen_speed_handler, + .get = param_get_int, +}; + +module_param_cb(con_mode, &con_mode_ops, &con_mode, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param_cb(con_mode_ftm, &con_mode_ftm_ops, &con_mode_ftm, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param_cb(pcie_gen_speed, &pcie_gen_speed_ops, &pcie_gen_speed, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +#ifdef WLAN_FEATURE_EPPING +module_param_cb(con_mode_epping, &con_mode_epping_ops, + &con_mode_epping, 0644); +#endif + +module_param_cb(fwpath, &fwpath_ops, &fwpath, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param(enable_dfs_chan_scan, int, S_IRUSR | S_IRGRP | S_IROTH); + +module_param(enable_11d, int, S_IRUSR | S_IRGRP | S_IROTH); + +module_param(country_code, charp, S_IRUSR | S_IRGRP | S_IROTH); + +static int timer_multiplier_get_handler(char *buffer, + const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%u", qdf_timer_get_multiplier()); +} + +static int timer_multiplier_set_handler(const char *kmessage, + const struct kernel_param *kp) +{ + QDF_STATUS status; + uint32_t scalar; + + status = qdf_uint32_parse(kmessage, &scalar); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + if (!cfg_in_range(CFG_TIMER_MULTIPLIER, scalar)) + return -ERANGE; + + qdf_timer_set_multiplier(scalar); + + return 0; +} + +static const struct kernel_param_ops timer_multiplier_ops = { + .get = timer_multiplier_get_handler, + .set = timer_multiplier_set_handler, +}; + +module_param_cb(timer_multiplier, &timer_multiplier_ops, NULL, 0644); diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_main_module.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_main_module.c new file mode 100644 index 0000000000..ff76ede801 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_main_module.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_main_module.c + * + * WLAN Host Device Driver module interface implementation + * + */ + +#include +#include "qwlan_version.h" +#include "wlan_hdd_main.h" + +static int __init hdd_module_init(void) +{ + return hdd_driver_load(); +} + +static void __exit hdd_module_exit(void) +{ + hdd_driver_unload(); +} + +module_init(hdd_module_init); +module_exit(hdd_module_exit); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("WLAN HOST DEVICE DRIVER"); + +module_param_cb(con_mode, &con_mode_ops, &con_mode, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param_cb(con_mode_ftm, &con_mode_ftm_ops, &con_mode_ftm, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + +module_param(country_code, charp, S_IRUSR | S_IRGRP | S_IROTH); diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mcc_quota.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mcc_quota.c new file mode 100644 index 0000000000..b68a13b61e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mcc_quota.c @@ -0,0 +1,482 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mcc_quota.c + * + * WLAN Host Device Driver MCC quota feature cfg80211 APIs implementation + * + */ + +#include +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include "sme_api.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_mcc_quota.h" +#include "wlan_hdd_trace.h" +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_policy_mgr_api.h" +#include +#include "wlan_utility.h" +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_hdd_object_manager.h" +#include "sme_api.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_osif_priv.h" +#include "wlan_p2p_mcc_quota_public_struct.h" +#include "wma.h" + +const struct nla_policy +set_mcc_quota_policy[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES] = + VENDOR_NLA_POLICY_NESTED(set_mcc_quota_policy), + [QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LOW_LATENCY_MODE_ENABLE] = { + .type = NLA_U8 }, +}; + +int wlan_hdd_set_mcc_adaptive_sched(struct wlan_objmgr_psoc *psoc, bool enable) +{ + bool enable_mcc_adaptive_sch; + + hdd_debug("enable : %d", enable); + ucfg_policy_mgr_get_mcc_adaptive_sch(psoc, &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch(psoc, enable); + if (QDF_IS_STATUS_ERROR(sme_set_mas(enable))) { + hdd_err("Fail to config mcc adaptive sched."); + return -EINVAL; + } + } + + return 0; +} + +/** + * wlan_hdd_set_mcc_fixed_quota() - Set/Clear MCC fix quota + * @hdd_ctx: hdd context + * @quota_type: quota type + * @tb: attribute information + * + * Return: 0 on success, negative errno on failure + */ +static int +wlan_hdd_set_mcc_fixed_quota(struct hdd_context *hdd_ctx, + enum qca_wlan_vendor_mcc_quota_type quota_type, + struct nlattr *tb[]) +{ + struct hdd_adapter *if_adapter; + struct nlattr *quota_entries[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1]; + struct nlattr *curr_attr; + struct wlan_objmgr_psoc *psoc; + uint32_t duty_cycle, cmd_id, rem_bytes, entries, if_idx; + struct wlan_user_mcc_quota mcc_quota; + int att_id, rc; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + psoc = hdd_ctx->psoc; + if (!psoc) + return -EINVAL; + + if (quota_type != QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED && + quota_type != QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR) { + hdd_err("Quota type is not valid %u", quota_type); + return -EINVAL; + } + + if (quota_type == QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR) { + /* Remove quota, enable MCC adaptive scheduling */ + if (wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, true)) + return -EAGAIN; + mcc_quota.op_mode = QDF_MAX_NO_OF_MODE; + mcc_quota.vdev_id = WLAN_UMAC_VDEV_ID_MAX; + ucfg_mlme_set_user_mcc_quota(psoc, &mcc_quota); + return 0; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES; + if (!tb[cmd_id]) { + hdd_err("No entries present"); + return -EINVAL; + } + + entries = 0; + nla_for_each_nested(curr_attr, tb[cmd_id], rem_bytes) { + if (entries > 0) { + hdd_debug("Only one entry permitted"); + hdd_debug("Entry (%d) for (%u) is ignored", + entries, nla_type(curr_attr)); + entries++; + continue; + } + rc = wlan_cfg80211_nla_parse_nested(quota_entries, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX, + curr_attr, + set_mcc_quota_policy); + if (rc) { + hdd_err("Entry parse error %d", rc); + return -EINVAL; + } + + att_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_IFINDEX; + if (!quota_entries[att_id]) { + hdd_err("if_index not specified"); + return -EINVAL; + } + + if_idx = nla_get_u32(quota_entries[att_id]); + if (if_idx == 0) { + hdd_debug("Invalid if_index"); + return -EINVAL; + } + if_adapter = hdd_get_adapter_by_ifindex(hdd_ctx, if_idx); + + if (!if_adapter) { + hdd_err("interface (%u) not found", if_idx); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(if_adapter->deflink->vdev_id)) + return -EINVAL; + + att_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE; + if (!quota_entries[att_id]) { + hdd_err("Quota not specified"); + return -EINVAL; + } + mcc_quota.quota = nla_get_u32(quota_entries[att_id]); + mcc_quota.vdev_id = if_adapter->deflink->vdev_id; + mcc_quota.op_mode = if_adapter->device_mode; + + entries++; + } + + if (entries == 0) { + hdd_err("No entries found"); + return -EINVAL; + } + + if (mcc_quota.op_mode != QDF_P2P_GO_MODE) { + hdd_debug("Support only P2P GO mode now"); + return -EOPNOTSUPP; + } + + ucfg_mlme_set_user_mcc_quota(psoc, &mcc_quota); + + duty_cycle = ucfg_mlme_get_user_mcc_quota_percentage(psoc); + + if (duty_cycle == 0) { + hdd_debug("Quota will be configured when MCC scenario exists"); + return 0; + } + + if (wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, false)) + return -EAGAIN; + + if (wlan_hdd_send_mcc_vdev_quota(if_adapter, duty_cycle)) + return -EINVAL; + + return 0; +} + +/** + * wlan_hdd_set_mcc_low_latency_quota() - Enable/disable MCC low latency + * mode + * @hdd_ctx: hdd context + * @wdev: wdev object + * @quota_type: quota type + * @tb: attribute information + * + * Return: 0 on success, negative errno on failure + */ +static int wlan_hdd_set_mcc_low_latency_quota( + struct hdd_context *hdd_ctx, + struct wireless_dev *wdev, + enum qca_wlan_vendor_mcc_quota_type quota_type, + struct nlattr *tb[]) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + uint32_t cmd_id; + uint8_t ll_enable; + int rc; + uint32_t ll_mode = 0; + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (quota_type != QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY) { + hdd_err("Quota type %u is not expected %d", quota_type, + QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY); + return -EINVAL; + } + cmd_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_LOW_LATENCY_MODE_ENABLE; + if (!tb[cmd_id]) { + hdd_err("No MCC LL mode attr id %d", cmd_id); + return -EINVAL; + } + ll_enable = nla_get_u8(tb[cmd_id]); + if (ll_enable) + ll_mode = 1; + hdd_debug("set conc ll mode 0x%08x", ll_mode); + rc = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_pdev_param_set_conc_low_latency_mode, + ll_mode, PDEV_CMD); + if (rc) + hdd_err("Failed to set conc low latency mode, %d", rc); + + return 0; +} + +int wlan_hdd_cfg80211_set_mcc_quota(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *attr, + int attr_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + uint32_t cmd_id, quota_type; + int rc; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + psoc = hdd_ctx->psoc; + if (!psoc) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX, + attr, attr_len, set_mcc_quota_policy)) { + hdd_err("Error parsing attributes"); + return -EINVAL; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE; + if (!tb[cmd_id]) { + hdd_err("Quota type not specified"); + return -EINVAL; + } + quota_type = nla_get_u32(tb[cmd_id]); + if (quota_type == QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_FIXED || + quota_type == QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_CLEAR) { + rc = wlan_hdd_set_mcc_fixed_quota(hdd_ctx, quota_type, tb); + } else if (quota_type == QCA_WLAN_VENDOR_MCC_QUOTA_TYPE_LOW_LATENCY) { + rc = wlan_hdd_set_mcc_low_latency_quota(hdd_ctx, wdev, + quota_type, tb); + } else { + hdd_err("Quota type is not valid %u", quota_type); + return -EINVAL; + } + + return rc; +} + +int wlan_hdd_apply_user_mcc_quota(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + uint32_t quota_val; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return -EINVAL; + + quota_val = + ucfg_mlme_get_user_mcc_quota_percentage(hdd_ctx->psoc); + + if (quota_val == 0) { + hdd_debug("no mcc/quota for mode %d, vdev_id : %u", + adapter->device_mode, adapter->deflink->vdev_id); + return 0; + } + + if (wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, false)) + return 0; + + if (wlan_hdd_send_mcc_vdev_quota(adapter, quota_val)) { + hdd_info("Could not send quota"); + wlan_hdd_set_mcc_adaptive_sched(hdd_ctx->psoc, true); + } + + return 0; +} + +/** + * wlan_cfg80211_indicate_mcc_quota() - Callback to indicate mcc quota + * event to upper layer + * @psoc: pointer to soc object + * @vdev: vdev object + * @quota_info: quota info + * + * This callback will be used to indicate mcc quota info to upper layer + * + * Return: QDF_STATUS_SUCCESS if event is indicated to OS successfully. + */ +static QDF_STATUS +wlan_cfg80211_indicate_mcc_quota(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + struct mcc_quota_info *quota_info) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + QDF_STATUS status; + struct vdev_osif_priv *vdev_osif_priv; + struct wireless_dev *wdev; + struct pdev_osif_priv *pdev_osif_priv; + struct wlan_objmgr_pdev *pdev; + uint32_t idx; + uint32_t vdev_id; + struct nlattr *quota_attrs, *quota_element; + + if (!vdev) { + hdd_debug("null vdev"); + return QDF_STATUS_E_INVAL; + } + + vdev_osif_priv = wlan_vdev_get_ospriv(vdev); + if (!vdev_osif_priv || !vdev_osif_priv->wdev) { + hdd_debug("null wdev"); + return QDF_STATUS_E_INVAL; + } + + wdev = vdev_osif_priv->wdev; + vdev_id = wlan_vdev_get_id(vdev); + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + hdd_debug("null pdev"); + return QDF_STATUS_E_INVAL; + } + + pdev_osif_priv = wlan_pdev_get_ospriv(pdev); + if (!pdev_osif_priv || !pdev_osif_priv->wiphy) { + hdd_debug("null wiphy"); + return QDF_STATUS_E_INVAL; + } + + /* nested element of QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ and + * QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE + */ + data_len = nla_total_size(nla_total_size(sizeof(uint32_t)) + + nla_total_size(sizeof(uint32_t))); + /* nested array of quota element */ + data_len = nla_total_size(data_len * quota_info->num_chan_quota); + /* QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE and NL msg header */ + data_len += nla_total_size(sizeof(uint32_t)) + NLMSG_HDRLEN; + + vendor_event = wlan_cfg80211_vendor_event_alloc(pdev_osif_priv->wiphy, + wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_debug("wlan_cfg80211_vendor_event_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_TYPE, + quota_info->type)) { + status = QDF_STATUS_E_NOMEM; + hdd_debug("add QUOTA_TYPE failed"); + goto err; + } + + quota_attrs = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_ENTRIES); + if (!quota_attrs) { + status = QDF_STATUS_E_NOMEM; + hdd_debug("add QUOTA_ENTRIES failed"); + goto err; + } + hdd_debug("mcc quota vdev %d type %d num %d", + vdev_id, quota_info->type, quota_info->num_chan_quota); + + for (idx = 0; idx < quota_info->num_chan_quota; idx++) { + quota_element = nla_nest_start(vendor_event, idx); + if (!quota_element) { + status = QDF_STATUS_E_NOMEM; + hdd_debug("add quota idx failed"); + goto err; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_FREQ, + quota_info->chan_quota[idx].chan_mhz)) { + status = QDF_STATUS_E_NOMEM; + hdd_debug("add QUOTA_CHAN_FREQ failed"); + goto err; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_CHAN_TIME_PERCENTAGE, + quota_info->chan_quota[idx].channel_time_quota)) { + status = QDF_STATUS_E_NOMEM; + hdd_debug("add QUOTA_CHAN_TIME_PERCENTAGE failed"); + goto err; + } + + nla_nest_end(vendor_event, quota_element); + hdd_debug("mcc quota vdev %d [%d] %d quota %d", + vdev_id, idx, quota_info->chan_quota[idx].chan_mhz, + quota_info->chan_quota[idx].channel_time_quota); + } + nla_nest_end(vendor_event, quota_attrs); + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + return QDF_STATUS_SUCCESS; +err: + wlan_cfg80211_vendor_free_skb(vendor_event); + + return status; +} + +/** + * wlan_hdd_register_mcc_quota_event_callback() - Register hdd callback to get + * mcc quota event to upper layer + * @hdd_ctx: pointer to hdd context + * + * Return: void + */ +void wlan_hdd_register_mcc_quota_event_callback(struct hdd_context *hdd_ctx) +{ + ucfg_p2p_register_mcc_quota_event_os_if_cb(hdd_ctx->psoc, + wlan_cfg80211_indicate_mcc_quota); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mcc_quota.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mcc_quota.h new file mode 100644 index 0000000000..739663c040 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mcc_quota.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mcc_quota.h + * + * WLAN Host Device Driver MCC quota feature interface definitions + * + */ +#ifndef WLAN_HDD_MCC_QUOTA_H +#define WLAN_HDD_MCC_QUOTA_H +#include "qdf_types.h" +#include "qdf_status.h" +#include "qca_vendor.h" +#include + +struct hdd_context; +struct hdd_adapter; +struct wlan_objmgr_psoc; + +#ifdef WLAN_FEATURE_MCC_QUOTA +extern const struct nla_policy +set_mcc_quota_policy[QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX + 1]; + +/** + * wlan_hdd_set_mcc_adaptive_sched() - Enable or disable MCC adaptive scheduling + * @psoc: psoc context + * @enable: Enable (true) or disable (false) + * + * Return: 0 for success, Non zero failure code for errors + */ +int wlan_hdd_set_mcc_adaptive_sched(struct wlan_objmgr_psoc *psoc, + bool enable); + +/** + * wlan_hdd_cfg80211_set_mcc_quota() - Set user MCC quota to the target + * @wiphy: Wireless info object + * @wdev: Wireless dev object + * @attr: Command attributes + * @attr_len: Length of attributes + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_set_mcc_quota(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *attr, + int attr_len); + +#define FEATURE_MCC_QUOTA_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | WIPHY_VENDOR_CMD_NEED_NETDEV,\ + .doit = wlan_hdd_cfg80211_set_mcc_quota, \ + vendor_command_policy(set_mcc_quota_policy, \ + QCA_WLAN_VENDOR_ATTR_MCC_QUOTA_MAX) \ +}, + +#define FEATURE_MCC_QUOTA_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MCC_QUOTA, \ +}, + +/** + * wlan_hdd_apply_user_mcc_quota() - Apply the user MCC quota to the target + * @adapter: pointer to HDD adapter object + * + * Return: 0 on success, errno for error + */ +int wlan_hdd_apply_user_mcc_quota(struct hdd_adapter *adapter); + +/** + * wlan_hdd_register_mcc_quota_event_callback() - Register hdd callback to get + * mcc quota event. + * @hdd_ctx: pointer to hdd context + * + * Return: void + */ +void wlan_hdd_register_mcc_quota_event_callback(struct hdd_context *hdd_ctx); +#else /* WLAN_FEATURE_MCC_QUOTA */ +#define FEATURE_MCC_QUOTA_VENDOR_COMMANDS +#define FEATURE_MCC_QUOTA_VENDOR_EVENTS + +static inline int wlan_hdd_apply_user_mcc_quota(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline int wlan_hdd_set_mcc_adaptive_sched(struct wlan_objmgr_psoc *psoc, + bool enable) +{ + return 0; +} + +static inline void +wlan_hdd_register_mcc_quota_event_callback(struct hdd_context *hdd_ctx) +{ +} +#endif /* WLAN_FEATURE_MCC_QUOTA */ +#endif /* WLAN_HDD_MCC_QUOTA_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mdns_offload.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mdns_offload.c new file mode 100644 index 0000000000..f2038c66b7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mdns_offload.c @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mdns_offload.c + * + * WLAN Host Device Driver MDNS offload interface implementation. + */ + +/* Include Files */ + +#include +#include "os_if_fwol.h" +#include "wlan_hdd_mdns_offload.h" +#include "wlan_hdd_main.h" + +#define MDNS_ENABLE \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENABLE +#define MDNS_TABLE \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_TABLE +#define MDNS_ENTRY \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ENTRY +#define MDNS_FQDN \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_FQDN +#define MDNS_RESOURCE_RECORDS_COUNT \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_RESOURCE_RECORDS_COUNT +#define MDNS_ANSWER_PAYLOAD \ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_ANSWER_PAYLOAD + +const struct nla_policy wlan_hdd_set_mdns_offload_policy[ + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1] = { + [MDNS_ENABLE] = {.type = NLA_FLAG}, + [MDNS_TABLE] = {.type = NLA_NESTED}, + [MDNS_ENTRY] = {.type = NLA_NESTED}, + [MDNS_FQDN] = {.type = NLA_STRING, .len = MAX_FQDN_LEN - 1 }, + [MDNS_RESOURCE_RECORDS_COUNT] = {.type = NLA_U16}, + [MDNS_ANSWER_PAYLOAD] = {.type = NLA_BINARY, .len = MAX_MDNS_RESP_LEN }, + +}; + +static int hdd_extract_mdns_attr(struct nlattr *tb[], + struct mdns_config_info *mdns_info) +{ + int len, count; + + /* Configure mDNS FQDN*/ + + if (!tb[MDNS_FQDN]) { + hdd_err_rl("mDNS_FQDN attr failed"); + return -EINVAL; + } + + len = nla_len(tb[MDNS_FQDN]); + mdns_info->fqdn_len = len; + mdns_info->fqdn_type = MDNS_FQDN_TYPE_GENERAL; + wlan_cfg80211_nla_strscpy(mdns_info->fqdn_data, tb[MDNS_FQDN], + sizeof(mdns_info->fqdn_data)); + + /* Configure mDNS Answer Payload*/ + + if (!tb[MDNS_RESOURCE_RECORDS_COUNT]) { + hdd_err_rl("mDNS_RR count attr failed"); + return -EINVAL; + } + + count = nla_get_u16(tb[MDNS_RESOURCE_RECORDS_COUNT]); + mdns_info->resource_record_count = count; + + if (!tb[MDNS_ANSWER_PAYLOAD]) { + hdd_err_rl("mDNS_Response attr failed"); + return -EINVAL; + } + + len = nla_len(tb[MDNS_ANSWER_PAYLOAD]); + mdns_info->answer_payload_len = len; + nla_memcpy(mdns_info->answer_payload_data, + nla_data(tb[MDNS_ANSWER_PAYLOAD]), + sizeof(mdns_info->answer_payload_data)); + + return 0; +} + +/** + * __wlan_hdd_cfg80211_set_mdns_offload() - mDNS Offload configuration + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX. + * + * Return: Error code. + */ +static int +__wlan_hdd_cfg80211_set_mdns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *curr_attr; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX + 1]; + struct mdns_config_info *mdns_info; + bool is_mdns_enable; + int errno, rem; + + hdd_enter_dev(dev); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err_rl("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!(adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + hdd_err_rl("mDNS is only supported in STA or P2P CLI modes!"); + return -ENOTSUPP; + } + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX, + data, data_len, + wlan_hdd_set_mdns_offload_policy)) { + hdd_err_rl("invalid attr"); + return -EINVAL; + } + + if (!tb[MDNS_ENABLE]) { + os_if_fwol_disable_mdns_offload(hdd_ctx->psoc); + hdd_debug_rl("MDNS offload is disabled"); + return 0; + } + + is_mdns_enable = nla_get_flag(tb[MDNS_ENABLE]); + + if (is_mdns_enable && !tb[MDNS_TABLE]) { + hdd_err_rl("Invalid mDNS table of records"); + return -EINVAL; + } + + mdns_info = qdf_mem_malloc(sizeof(*mdns_info)); + if (!mdns_info) + return -ENOMEM; + + mdns_info->enable = is_mdns_enable; + mdns_info->vdev_id = adapter->deflink->vdev_id; + + nla_for_each_nested(curr_attr, tb[MDNS_TABLE], rem) { + if (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX, + nla_data(curr_attr), + nla_len(curr_attr), + wlan_hdd_set_mdns_offload_policy)) { + hdd_err_rl("Failed to parse mDNS table of records"); + errno = -EINVAL; + goto out; + } + + errno = hdd_extract_mdns_attr(tb2, mdns_info); + if (errno) { + hdd_err_rl("Failed to extract MDNS nested attrs"); + goto out; + } + } + + os_if_fwol_enable_mdns_offload(hdd_ctx->psoc, mdns_info); + +out: + qdf_mem_free(mdns_info); + hdd_exit(); + + return errno; +} + +/** + * wlan_hdd_cfg80211_set_mdns_offload() - mDNS Offload configuration + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_MDNS_OFFLOAD_MAX. + * + * Return: EOK or other error codes. + */ +int wlan_hdd_cfg80211_set_mdns_offload(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_mdns_offload(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.c new file mode 100644 index 0000000000..51dc723ac1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.c @@ -0,0 +1,793 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_medium_assess.c + * + * WLAN Host Device Driver medium assess related implementation + * + */ + +#include "wlan_hdd_medium_assess.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_cmn.h" + +/* define short names for get station info attributes */ +#define MEDIUM_ASSESS_TYPE \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE +#define PERIOD \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_PERIOD +#define TOTAL_CYCLE_COUNT \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT +#define IDLE_COUNT \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT +#define IBSS_RX_COUNT \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT +#define OBSS_RX_COUNT \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT +#define MAX_IBSS_RSSI \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI +#define MIN_IBSS_RSSI \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI +#define CONGESTION_REPORT_ENABLE \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_ENABLE +#define CONGESTION_REPORT_THRESHOLD \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_THRESHOLD +#define CONGESTION_REPORT_INTERVAL \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_REPORT_INTERVAL +#define CONGESTION_PERCENTAGE \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE +#define MEDIUM_ASSESS_MAX \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX + +#define DEFAULT_CCA_PERIOD 10 /* seconds */ +#define CCA_GET_RSSI_INTERVAL 1000 /* 1 second */ + +#define REPORT_DISABLE 0 +#define REPORT_ENABLE 1 + +#define MAX_CONGESTION_THRESHOLD 100 +#define CYCLE_THRESHOLD 6400000 /* 40000us * 160M */ + +#define MEDIUM_ASSESS_TIMER_INTERVAL 1000 /* 1000ms */ +static qdf_mc_timer_t hdd_medium_assess_timer; +static bool ssr_flag; +static bool timer_enable; +struct hdd_medium_assess_info medium_assess_info[WLAN_UMAC_MAX_RP_PID]; +unsigned long stime; + +const struct nla_policy +hdd_medium_assess_policy[MEDIUM_ASSESS_MAX + 1] = { + [MEDIUM_ASSESS_TYPE] = {.type = NLA_U8}, + [PERIOD] = {.type = NLA_U32}, + [CONGESTION_REPORT_ENABLE] = {.type = NLA_U8}, + [CONGESTION_REPORT_THRESHOLD] = {.type = NLA_U8}, + [CONGESTION_REPORT_INTERVAL] = {.type = NLA_U8}, +}; + +/* + * get_cca_report_len() - Calculate length for CCA report + * to allocate skb buffer + * + * Return: skb buffer length + */ +static int get_cca_report_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE */ + data_len += nla_total_size(sizeof(uint8_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TOTAL_CYCLE_COUNT */ + data_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IDLE_COUNT */ + data_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_IBSS_RX_COUNT */ + data_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_OBSS_RX_COUNT */ + data_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX_IBSS_RSSI */ + data_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MIN_IBSS_RSSI */ + data_len += nla_total_size(sizeof(uint32_t)); + + return data_len; +} + +/** + * hdd_cca_notification_cb() - cca notification callback function + * @vdev_id: vdev id + * @stats: dcs im stats + * @status: status of cca statistics + * + * Return: None + */ +static void hdd_cca_notification_cb(uint8_t vdev_id, + struct wlan_host_dcs_im_user_stats *stats, + int status) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct sk_buff *event; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Failed to find adapter of vdev %d", vdev_id); + return; + } + + event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, &link_info->adapter->wdev, + get_cca_report_len(), + QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX, + GFP_KERNEL); + if (!event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u8(event, MEDIUM_ASSESS_TYPE, + QCA_WLAN_MEDIUM_ASSESS_CCA) || + nla_put_u32(event, TOTAL_CYCLE_COUNT, stats->cycle_count) || + nla_put_u32(event, IDLE_COUNT, + stats->cycle_count - stats->rxclr_count) || + nla_put_u32(event, IBSS_RX_COUNT, stats->my_bss_rx_cycle_count) || + nla_put_u32(event, OBSS_RX_COUNT, + stats->rx_frame_count - stats->my_bss_rx_cycle_count) || + nla_put_u32(event, MAX_IBSS_RSSI, stats->max_rssi) || + nla_put_u32(event, MIN_IBSS_RSSI, stats->min_rssi)) { + hdd_err("nla put failed"); + wlan_cfg80211_vendor_free_skb(event); + return; + } + + wlan_cfg80211_vendor_event(event, GFP_KERNEL); +} + +/** + * hdd_medium_assess_cca() - clear channel assessment + * @hdd_ctx: pointer to HDD context + * @adapter: pointer to adapter + * @tb: list of attributes + * + * Return: success(0) or reason code for failure + */ +static int hdd_medium_assess_cca(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t cca_period = DEFAULT_CCA_PERIOD; + uint8_t mac_id, dcs_enable; + QDF_STATUS status; + int errno = 0; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DCS_ID); + if (!vdev) + return -EINVAL; + + status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, + adapter->deflink->vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to get mac_id"); + errno = -EINVAL; + goto out; + } + + dcs_enable = ucfg_get_dcs_enable(hdd_ctx->psoc, mac_id); + if (!(dcs_enable & WLAN_HOST_DCS_WLANIM)) { + hdd_err_rl("DCS_WLANIM is not enabled"); + errno = -EINVAL; + goto out; + } + + if (qdf_atomic_read(&adapter->deflink->session.ap.acs_in_progress)) { + hdd_err_rl("ACS is in progress"); + errno = -EBUSY; + goto out; + } + + if (tb[PERIOD]) + cca_period = nla_get_u32(tb[PERIOD]); + if (cca_period == 0) + cca_period = DEFAULT_CCA_PERIOD; + + ucfg_dcs_reset_user_stats(hdd_ctx->psoc, mac_id); + ucfg_dcs_register_user_cb(hdd_ctx->psoc, mac_id, + adapter->deflink->vdev_id, + hdd_cca_notification_cb); + /* dcs is already enabled and dcs event is reported every second + * set the user request counter to collect user stats + */ + ucfg_dcs_set_user_request(hdd_ctx->psoc, mac_id, cca_period); + +out: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DCS_ID); + return errno; +} + +/* + * get_congestion_report_len() - Calculate length for congestion report + * to allocate skb buffer + * + * Return: skb buffer length + */ +static int get_congestion_report_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_TYPE */ + data_len += nla_total_size(sizeof(uint8_t)); + + /* QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_CONGESTION_PERCENTAGE */ + data_len += nla_total_size(sizeof(uint8_t)); + + return data_len; +} + +/** + * hdd_congestion_reset_data() - reset/invalid the previous data + * @pdev_id: pdev id + * + * Return: None + */ +static void hdd_congestion_reset_data(uint8_t pdev_id) +{ + struct hdd_medium_assess_info *mdata; + + mdata = &medium_assess_info[pdev_id]; + qdf_mem_zero(mdata->data, sizeof(mdata->data)); +} + +/** + * hdd_congestion_notification_cb() - congestion notification callback function + * @vdev_id: vdev id + * @data: medium assess data from firmware + * @last: indicate whether the callback from final WMI_STATS_EVENT in a series + * + * Return: None + */ +static void hdd_congestion_notification_cb(uint8_t vdev_id, + struct medium_assess_data *data, + bool last) +{ + struct hdd_medium_assess_info *mdata; + uint8_t i; + int32_t index; + + /* the cb should not be delay more than 40 ms or drop it */ + if (qdf_system_time_after(jiffies, stime)) { + hdd_debug("medium assess interference data drop"); + return; + } + + for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++) { + mdata = &medium_assess_info[i]; + + index = mdata->index - 1; + if (index < 0) + index = MEDIUM_ASSESS_NUM - 1; + + if (data[i].part1_valid && mdata->data[index].part1_valid) { + if (CYCLE_THRESHOLD > (data[i].cycle_count - + mdata->data[index].cycle_count)) + continue; + } + + if (data[i].part1_valid) { + mdata->data[mdata->index].part1_valid = true; + mdata->data[mdata->index].cycle_count = + data[i].cycle_count; + mdata->data[mdata->index].rx_clear_count = + data[i].rx_clear_count; + mdata->data[mdata->index].tx_frame_count = + data[i].tx_frame_count; + } + + if (data[i].part2_valid) { + mdata->data[mdata->index].part2_valid = true; + mdata->data[mdata->index].my_rx_count = + data[i].my_rx_count; + } + + if (last) { + mdata->index++; + if (mdata->index >= MEDIUM_ASSESS_NUM) + mdata->index = 0; + mdata->data[mdata->index].part1_valid = false; + mdata->data[mdata->index].part2_valid = false; + } + } +} + +/** + * hdd_congestion_notification_report() - congestion report function + * @vdev_id: vdev id + * @congestion: congestion percentage + * + * Return: None + */ +static void hdd_congestion_notification_report(uint8_t vdev_id, + uint8_t congestion) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct sk_buff *event; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Failed to find adapter of vdev %d", vdev_id); + return; + } + + event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &link_info->adapter->wdev, + get_congestion_report_len(), + index, GFP_KERNEL); + if (!event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u8(event, MEDIUM_ASSESS_TYPE, + QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT) || + nla_put_u8(event, CONGESTION_PERCENTAGE, congestion)) { + hdd_err("nla put failed"); + wlan_cfg80211_vendor_free_skb(event); + return; + } + + wlan_cfg80211_vendor_event(event, GFP_KERNEL); +} + +void hdd_medium_assess_ssr_enable_flag(void) +{ + uint8_t i; + + ssr_flag = true; + for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++) + hdd_congestion_reset_data(i); + + if (timer_enable) + qdf_mc_timer_destroy(&hdd_medium_assess_timer); +} + +void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx) +{ + struct request_info info = {0}; + bool pending = false; + uint8_t i, interval = 0; + + if (ssr_flag) + return; + + medium_assess_info[pdev_id].config.threshold = MAX_CONGESTION_THRESHOLD; + medium_assess_info[pdev_id].config.interval = 0; + medium_assess_info[pdev_id].index = 0; + medium_assess_info[pdev_id].count = 0; + hdd_congestion_reset_data(pdev_id); + + for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++) + interval += medium_assess_info[i].config.interval; + + if (!interval && timer_enable) { + ucfg_mc_cp_stats_reset_pending_req(hdd_ctx->psoc, + TYPE_CONGESTION_STATS, + &info, &pending); + qdf_mc_timer_stop(&hdd_medium_assess_timer); + hdd_debug("medium assess atimer stop"); + } else { + hdd_debug("medium assess timer already disabled"); + } +} + +/** + * hdd_congestion_notification_calculation() - medium assess congestion + * calculation. + * @info: structure hdd_medium_assess_info + * + * Return: None + */ +static void +hdd_congestion_notification_calculation(struct hdd_medium_assess_info *info) +{ + struct medium_assess_data *h_data, *t_data; + int32_t h_index, t_index; + uint32_t rx_clear_count_delta, tx_frame_count_delta; + uint32_t cycle_count_delta, my_rx_count_delta; + uint32_t congestion = 0; + uint64_t diff; + + h_index = info->index - 1; + if (h_index < 0) + h_index = MEDIUM_ASSESS_NUM - 1; + + if (h_index >= info->config.interval) + t_index = h_index - info->config.interval; + else + t_index = MEDIUM_ASSESS_NUM - info->config.interval - h_index; + + if (h_index < 0 || h_index >= MEDIUM_ASSESS_NUM || + t_index < 0 || t_index >= MEDIUM_ASSESS_NUM) { + hdd_err("medium assess index is not valid."); + return; + } + + h_data = &info->data[h_index]; + t_data = &info->data[t_index]; + + if (!(h_data->part1_valid || h_data->part2_valid || + t_data->part1_valid || t_data->part2_valid)) { + hdd_err("medium assess data is not valid."); + return; + } + + if (h_data->rx_clear_count >= t_data->rx_clear_count) { + rx_clear_count_delta = h_data->rx_clear_count - + t_data->rx_clear_count; + } else { + rx_clear_count_delta = U32_MAX - t_data->rx_clear_count; + rx_clear_count_delta += h_data->rx_clear_count; + } + + if (h_data->tx_frame_count >= t_data->tx_frame_count) { + tx_frame_count_delta = h_data->tx_frame_count - + t_data->tx_frame_count; + } else { + tx_frame_count_delta = U32_MAX - t_data->tx_frame_count; + tx_frame_count_delta += h_data->tx_frame_count; + } + + if (h_data->my_rx_count >= t_data->my_rx_count) { + my_rx_count_delta = h_data->my_rx_count - t_data->my_rx_count; + } else { + my_rx_count_delta = U32_MAX - t_data->my_rx_count; + my_rx_count_delta += h_data->my_rx_count; + } + + if (h_data->cycle_count >= t_data->cycle_count) { + cycle_count_delta = h_data->cycle_count - t_data->cycle_count; + } else { + cycle_count_delta = U32_MAX - t_data->cycle_count; + cycle_count_delta += h_data->cycle_count; + } + + if (rx_clear_count_delta > tx_frame_count_delta && + rx_clear_count_delta - tx_frame_count_delta > my_rx_count_delta) { + diff = rx_clear_count_delta - tx_frame_count_delta + - my_rx_count_delta; + if (cycle_count_delta) + congestion = qdf_do_div(diff * 100, cycle_count_delta); + + if (congestion > 100) + congestion = 100; + } + + hdd_debug("pdev: %d, rx_c %u, tx %u myrx %u cycle %u congestion: %u", + info->pdev_id, rx_clear_count_delta, tx_frame_count_delta, + my_rx_count_delta, cycle_count_delta, congestion); + if (congestion >= info->config.threshold) + hdd_congestion_notification_report(info->vdev_id, congestion); +} + +/** + * hdd_congestion_notification_report_multi() - medium assess report + * multi interface. + * @pdev_id: pdev id + * + * Return: None + */ +static void hdd_congestion_notification_report_multi(uint8_t pdev_id) +{ + struct hdd_medium_assess_info *info; + + info = &medium_assess_info[pdev_id]; + info->count++; + if (info->count % info->config.interval == 0) + hdd_congestion_notification_calculation(info); +} + +/** + * hdd_medium_assess_expire_handler() - timer callback + * @arg: argument + * + * Return: None + */ +static void hdd_medium_assess_expire_handler(void *arg) +{ + struct wlan_objmgr_vdev *vdev; + struct request_info info = {0}; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + uint8_t vdev_id = INVALID_VDEV_ID, pdev_id; + uint8_t index, i; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + for (i = 0; i < WLAN_UMAC_MAX_RP_PID; i++) + if (medium_assess_info[i].config.interval != 0) { + vdev_id = medium_assess_info[i].vdev_id; + pdev_id = medium_assess_info[i].pdev_id; + hdd_congestion_notification_report_multi(pdev_id); + + /* ensure events are reveived at the 'same' time */ + index = medium_assess_info[i].index; + medium_assess_info[i].data[index].part1_valid = false; + medium_assess_info[i].data[index].part2_valid = false; + } + + if (vdev_id == INVALID_VDEV_ID) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Failed to find adapter of vdev %d", vdev_id); + return; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_CP_STATS_ID); + if (!vdev) + return; + + info.vdev_id = vdev_id; + info.pdev_id = WMI_HOST_PDEV_ID_SOC; + info.u.congestion_notif_cb = hdd_congestion_notification_cb; + stime = jiffies + msecs_to_jiffies(40); + ucfg_mc_cp_stats_send_stats_request(vdev, + TYPE_CONGESTION_STATS, + &info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID); + qdf_mc_timer_start(&hdd_medium_assess_timer, + MEDIUM_ASSESS_TIMER_INTERVAL); +} + +/** + * hdd_medium_assess_congestion_report() - congestion report + * @hdd_ctx: pointer to HDD context + * @adapter: pointer to adapter + * @tb: list of attributes + * + * Return: success(0) or reason code for failure + */ +static int hdd_medium_assess_congestion_report(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct nlattr **tb) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + uint8_t enable, threshold, interval = 0; + uint8_t pdev_id, vdev_id; + int errno = 0; + + if (!tb[CONGESTION_REPORT_ENABLE]) { + hdd_err_rl("Congestion report enable is not present"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_CP_STATS_ID); + if (!vdev) + return -EINVAL; + + vdev_id = adapter->deflink->vdev_id; + status = policy_mgr_get_mac_id_by_session_id(hdd_ctx->psoc, vdev_id, + &pdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + goto out; + } + + medium_assess_info[pdev_id].vdev_id = vdev_id; + medium_assess_info[pdev_id].pdev_id = pdev_id; + + enable = nla_get_u8(tb[CONGESTION_REPORT_ENABLE]); + switch (enable) { + case REPORT_DISABLE: + hdd_debug("medium assess disable: pdev_id %d, vdev_id: %d", + pdev_id, vdev_id); + hdd_medium_assess_stop_timer(pdev_id, hdd_ctx); + if (timer_enable && + (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) == + QDF_TIMER_STATE_STOPPED)) { + qdf_mc_timer_destroy(&hdd_medium_assess_timer); + timer_enable = false; + } + break; + case REPORT_ENABLE: + if (!tb[CONGESTION_REPORT_THRESHOLD]) { + hdd_err_rl("Congestion threshold is not present"); + errno = -EINVAL; + goto out; + } + threshold = nla_get_u8(tb[CONGESTION_REPORT_THRESHOLD]); + if (threshold > MAX_CONGESTION_THRESHOLD) { + hdd_err_rl("Invalid threshold %d", threshold); + errno = -EINVAL; + goto out; + } + if (tb[CONGESTION_REPORT_INTERVAL]) { + interval = nla_get_u8(tb[CONGESTION_REPORT_INTERVAL]); + if (interval >= MEDIUM_ASSESS_NUM) + interval = MEDIUM_ASSESS_NUM - 1; + } else { + interval = 1; + } + + medium_assess_info[pdev_id].config.threshold = threshold; + medium_assess_info[pdev_id].config.interval = interval; + medium_assess_info[pdev_id].index = 0; + medium_assess_info[pdev_id].count = 0; + hdd_congestion_reset_data(pdev_id); + hdd_debug("medium assess enable: pdev_id %d, vdev_id: %d", + pdev_id, vdev_id); + + if (!timer_enable) { + status = + qdf_mc_timer_init(&hdd_medium_assess_timer, + QDF_TIMER_TYPE_SW, + hdd_medium_assess_expire_handler, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("medium assess init timer failed"); + errno = -EINVAL; + goto out; + } + timer_enable = true; + } + + if (qdf_mc_timer_get_current_state(&hdd_medium_assess_timer) != + QDF_TIMER_STATE_RUNNING) { + hdd_debug("medium assess atimer start"); + qdf_mc_timer_start(&hdd_medium_assess_timer, + MEDIUM_ASSESS_TIMER_INTERVAL); + } + break; + default: + hdd_err_rl("Invalid enable: %d", enable); + errno = -EINVAL; + break; + } + +out: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_CP_STATS_ID); + return errno; +} + +/** + * __hdd_cfg80211_medium_assess() - medium assess + * @wiphy: pointer to wireless phy + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Return: success(0) or reason code for failure + */ +static int __hdd_cfg80211_medium_assess(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + enum QDF_GLOBAL_MODE driver_mode = hdd_get_conparam(); + struct nlattr *tb[MEDIUM_ASSESS_MAX + 1]; + uint8_t type; + int errno; + + hdd_enter_dev(dev); + + if (driver_mode == QDF_GLOBAL_FTM_MODE || + driver_mode == QDF_GLOBAL_MONITOR_MODE) { + hdd_err_rl("Command not allowed in FTM / Monitor mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = wlan_cfg80211_nla_parse(tb, MEDIUM_ASSESS_MAX, data, data_len, + hdd_medium_assess_policy); + if (errno) { + hdd_err_rl("Invalid ATTR"); + return errno; + } + + if (!tb[MEDIUM_ASSESS_TYPE]) { + hdd_err_rl("Medium assess type is not present"); + return -EINVAL; + } + type = nla_get_u8(tb[MEDIUM_ASSESS_TYPE]); + + switch (type) { + case QCA_WLAN_MEDIUM_ASSESS_CCA: + errno = hdd_medium_assess_cca(hdd_ctx, adapter, tb); + break; + case QCA_WLAN_MEDIUM_ASSESS_CONGESTION_REPORT: + errno = hdd_medium_assess_congestion_report(hdd_ctx, adapter, + tb); + break; + default: + hdd_err_rl("Invalid medium assess type: %d", type); + return -EINVAL; + } + + hdd_exit(); + + return errno; +} + +int hdd_cfg80211_medium_assess(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_cfg80211_medium_assess(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +void hdd_medium_assess_ssr_reinit(void) +{ + QDF_STATUS status; + + if (timer_enable && ssr_flag) { + hdd_debug("medium assess init timer in ssr"); + status = qdf_mc_timer_init(&hdd_medium_assess_timer, + QDF_TIMER_TYPE_SW, + hdd_medium_assess_expire_handler, + NULL); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("medium assess init timer failed in ssr"); + return; + } + + ssr_flag = false; + qdf_mc_timer_start(&hdd_medium_assess_timer, + MEDIUM_ASSESS_TIMER_INTERVAL); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.h new file mode 100644 index 0000000000..d48d7e11ff --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_medium_assess.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_medium_assess.h + * + * WLAN Host Device Driver medium assess related implementation + * + */ + +#if !defined(__WLAN_HDD_MEDIUM_ASSESS_H) +#define __WLAN_HDD_MEDIUM_ASSESS_H + +#include +#include +#include +#include +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_MEDIUM_ASSESS +#include "wlan_cp_stats_mc_defs.h" + +#define MEDIUM_ASSESS_NUM 31 + +/** + * struct hdd_medium_assess_config: configuration from framework + * @interval: the update period to framework. An integral multiple of 1 second, + * less or equal to 30 seconds + * @threshold: threshold for congestion percentage of pdev + */ +struct hdd_medium_assess_config { + uint8_t interval; + uint8_t threshold; +}; + +/** + * struct hdd_medium_assess_info: the medium assess info for pdev + * @pdev_id: pdev id + * @vdev_id: vdev id + * @config: config info from user + * @index: the data's index + * @data: the raw info from fw + * @count: the times of timer triggered + */ +struct hdd_medium_assess_info { + uint8_t pdev_id; + uint8_t vdev_id; + struct hdd_medium_assess_config config; + + int32_t index; + struct medium_assess_data data[MEDIUM_ASSESS_NUM]; + + uint32_t count; +}; + +/* QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS */ +extern const struct nla_policy +hdd_medium_assess_policy[QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX + 1]; + +/** + * hdd_cfg80211_medium_assess() - medium assess + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: success(0) or reason code for failure + */ +int hdd_cfg80211_medium_assess(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = hdd_cfg80211_medium_assess, \ + vendor_command_policy(hdd_medium_assess_policy, \ + QCA_WLAN_VENDOR_ATTR_MEDIUM_ASSESS_MAX) \ +}, + +#define FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MEDIUM_ASSESS, \ +}, + +/** + * hdd_medium_assess_ssr_reinit() - medium assess reinit timer in ssr + * + * Return: none + */ +void hdd_medium_assess_ssr_reinit(void); + +/** + * hdd_medium_assess_stop_timer() - medium assess reset and stop timer + * @pdev_id: pdev id + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_medium_assess_stop_timer(uint8_t pdev_id, struct hdd_context *hdd_ctx); + +/** + * hdd_medium_assess_ssr_enable_flag() - medium assess set ssr enable flag + * + * Return: none + */ +void hdd_medium_assess_ssr_enable_flag(void); +#else +#define FEATURE_MEDIUM_ASSESS_VENDOR_COMMANDS +#define FEATURE_MEDIUM_ASSESS_VENDOR_EVENTS +static inline void hdd_medium_assess_ssr_reinit(void) {} +static inline void hdd_medium_assess_stop_timer(uint8_t pdev_id, + struct hdd_context *hdd_ctx) {} +static inline void hdd_medium_assess_ssr_enable_flag(void) {} +#endif +#endif /* end #if !defined(__WLAN_HDD_MEDIUM_ASSESS_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c new file mode 100644 index 0000000000..607943be2f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_memdump.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_memdump.c + * + * WLAN Host Device Driver file for dumping firmware memory + * + */ + +#include +#include +#include +#include /* Necessary because we use the proc fs */ +#include /* for copy_to_user */ +#include "osif_sync.h" +#include +#include + +#define PROCFS_DRIVER_DUMP_DIR "debugdriver" +#define PROCFS_DRIVER_DUMP_NAME "driverdump" +#define PROCFS_DRIVER_DUMP_PERM 0444 + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)) +/* + * Commit 359745d78351 ("proc: remove PDE_DATA() completely") + * Replaced PDE_DATA() with pde_data() + */ +#define pde_data(inode) PDE_DATA(inode) +#endif + +static struct proc_dir_entry *proc_file_driver, *proc_dir_driver; + +/** memdump_get_file_data() - get data available in proc file + * + * @file - handle for the proc file. + * + * This function is used to retrieve the data passed while + * creating proc file entry. + * + * Return: void pointer to hdd_context + */ +static void *memdump_get_file_data(struct file *file) +{ + void *hdd_ctx; + + hdd_ctx = pde_data(file_inode(file)); + return hdd_ctx; +} + +void hdd_driver_mem_cleanup(void) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + if (hdd_ctx->driver_dump_mem) { + qdf_mem_free(hdd_ctx->driver_dump_mem); + hdd_ctx->driver_dump_mem = NULL; + } +} + + +/** + * __hdd_driver_memdump_read() - perform read operation in driver + * memory dump proc file + * @file: handle for the proc file. + * @buf: pointer to user space buffer. + * @count: number of bytes to be read. + * @pos: offset in the from buffer. + * + * This function performs read operation for the driver memory dump proc file. + * + * Return: number of bytes read on success + * negative error code in case of failure + * 0 in case of no more data + */ +static ssize_t __hdd_driver_memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int status; + QDF_STATUS qdf_status; + struct hdd_context *hdd_ctx; + size_t no_of_bytes_read = 0; + + hdd_ctx = memdump_get_file_data(file); + + hdd_debug("Read req for size:%zu pos:%llu", count, *pos); + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + return -EINVAL; + + mutex_lock(&hdd_ctx->memdump_lock); + if (*pos < 0) { + hdd_err("Invalid start offset for memdump read"); + mutex_unlock(&hdd_ctx->memdump_lock); + return -EINVAL; + } + + if (!count || + (hdd_ctx->driver_dump_size && *pos >= hdd_ctx->driver_dump_size)) { + mutex_unlock(&hdd_ctx->memdump_lock); + hdd_debug("No more data to copy"); + return 0; + } + + if (*pos == 0 || !hdd_ctx->driver_dump_mem) { + /* Allocate memory for Driver memory dump */ + if (!hdd_ctx->driver_dump_mem) { + hdd_ctx->driver_dump_mem = + qdf_mem_malloc(DRIVER_MEM_DUMP_SIZE); + if (!hdd_ctx->driver_dump_mem) { + mutex_unlock(&hdd_ctx->memdump_lock); + return -ENOMEM; + } + } + + qdf_status = qdf_state_info_dump_all(hdd_ctx->driver_dump_mem, + DRIVER_MEM_DUMP_SIZE, + &hdd_ctx->driver_dump_size); + /* + * If qdf_status is QDF_STATUS_E_NOMEM, then memory allocated is + * insufficient to dump driver information. This print can give + * information to allocate more memory if more information from + * each layer is added in future. + */ + if (qdf_status != QDF_STATUS_SUCCESS) + hdd_err("Error in dump driver information, status %d", + qdf_status); + hdd_debug("driver_dump_size: %d", hdd_ctx->driver_dump_size); + } + + if (count > hdd_ctx->driver_dump_size - *pos) + no_of_bytes_read = hdd_ctx->driver_dump_size - *pos; + else + no_of_bytes_read = count; + + if (copy_to_user(buf, hdd_ctx->driver_dump_mem + *pos, + no_of_bytes_read)) { + hdd_err("copy to user space failed"); + mutex_unlock(&hdd_ctx->memdump_lock); + return -EFAULT; + } + + /* offset(pos) should be updated here based on the copy done */ + *pos += no_of_bytes_read; + + /* Entire driver memory dump copy completed */ + if (*pos >= hdd_ctx->driver_dump_size) + hdd_driver_mem_cleanup(); + + mutex_unlock(&hdd_ctx->memdump_lock); + + return no_of_bytes_read; +} + +/** + * hdd_driver_memdump_read() - perform read operation in driver + * memory dump proc file + * @file: handle for the proc file. + * @buf: pointer to user space buffer. + * @count: number of bytes to be read. + * @pos: offset in the from buffer. + * + * This function performs read operation for the driver memory dump proc file. + * + * Return: number of bytes read on success + * negative error code in case of failure + * 0 in case of no more data + */ +static ssize_t hdd_driver_memdump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct osif_driver_sync *driver_sync; + ssize_t err_size; + + err_size = osif_driver_sync_op_start(&driver_sync); + if (err_size) + return err_size; + + err_size = __hdd_driver_memdump_read(file, buf, count, pos); + + osif_driver_sync_op_stop(driver_sync); + + return err_size; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +static const struct proc_ops driver_dump_fops = { + .proc_read = hdd_driver_memdump_read, + .proc_lseek = default_llseek, +}; +#else +static const struct file_operations driver_dump_fops = { + .read = hdd_driver_memdump_read, +}; +#endif + +/** + * hdd_driver_memdump_procfs_init() - Initialize procfs for driver memory dump + * @hdd_ctx: Pointer to hdd context + * + * This function create file under proc file system to be used later for + * processing driver memory dump + * + * Return: 0 on success, error code otherwise. + */ +static int hdd_driver_memdump_procfs_init(struct hdd_context *hdd_ctx) +{ + proc_dir_driver = proc_mkdir(PROCFS_DRIVER_DUMP_DIR, NULL); + if (!proc_dir_driver) { + pr_debug("Could not initialize /proc/%s\n", + PROCFS_DRIVER_DUMP_DIR); + return -ENOMEM; + } + + proc_file_driver = proc_create_data(PROCFS_DRIVER_DUMP_NAME, + PROCFS_DRIVER_DUMP_PERM, proc_dir_driver, + &driver_dump_fops, hdd_ctx); + if (!proc_file_driver) { + remove_proc_entry(PROCFS_DRIVER_DUMP_NAME, proc_dir_driver); + pr_debug("Could not initialize /proc/%s\n", + PROCFS_DRIVER_DUMP_NAME); + return -ENOMEM; + } + + pr_debug("/proc/%s/%s created\n", PROCFS_DRIVER_DUMP_DIR, + PROCFS_DRIVER_DUMP_NAME); + return 0; +} + +/** + * hdd_driver_memdump_procfs_remove() - Remove file/dir under procfs + * for driver memory dump + * + * This function removes file/dir under proc file system that was + * processing driver memory dump + * + * Return: None + */ +static void hdd_driver_memdump_procfs_remove(void) +{ + if (!proc_file_driver) + return; + remove_proc_entry(PROCFS_DRIVER_DUMP_NAME, proc_dir_driver); + pr_debug("/proc/%s/%s removed\n", PROCFS_DRIVER_DUMP_DIR, + PROCFS_DRIVER_DUMP_NAME); + remove_proc_entry(PROCFS_DRIVER_DUMP_DIR, NULL); + pr_debug("/proc/%s removed\n", PROCFS_DRIVER_DUMP_DIR); +} + +/** + * hdd_driver_memdump_init() - Initialization function for driver + * memory dump feature + * + * This function creates proc file for driver memdump feature + * + * Return - 0 on success, error otherwise + */ +int hdd_driver_memdump_init(void) +{ + int status; + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + mutex_init(&hdd_ctx->memdump_lock); + + status = hdd_driver_memdump_procfs_init(hdd_ctx); + if (status) { + hdd_err("Failed to create proc file"); + return status; + } + + return 0; +} + +/** + * hdd_driver_memdump_deinit() - De initialize driver memdump feature + * + * This function removes proc file created for driver memdump feature. + * + * Return: None + */ +void hdd_driver_memdump_deinit(void) +{ + hdd_driver_memdump_procfs_remove(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mlo.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mlo.c new file mode 100644 index 0000000000..1f54394244 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mlo.c @@ -0,0 +1,1374 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mlo.c + * + * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) + * support. + * + */ +#include "wlan_hdd_main.h" +#include "wlan_hdd_mlo.h" +#include "osif_vdev_sync.h" +#include "wlan_osif_features.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_psoc_mlme_ucfg_api.h" +#include "wlan_osif_request_manager.h" +#include "wlan_hdd_object_manager.h" +#include + +/*max time in ms, caller may wait for link state request get serviced */ +#define WLAN_WAIT_TIME_LINK_STATE 3000 + +#if defined(CFG80211_11BE_BASIC) +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +#ifdef CFG80211_IFTYPE_MLO_LINK_SUPPORT + +static +void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter, + struct hdd_adapter *link_adapter) +{ + int ret; + + link_adapter->wdev.iftype = NL80211_IFTYPE_MLO_LINK; + mutex_lock(&sta_adapter->wdev.mtx); + ret = cfg80211_register_sta_mlo_link(&sta_adapter->wdev, + &link_adapter->wdev); + mutex_unlock(&sta_adapter->wdev.mtx); + + if (ret) { + hdd_err("Failed to register ml link wdev %d", ret); + return; + } +} + +static +void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter, + bool rtnl_held) +{ + if (rtnl_held) + rtnl_unlock(); + + cfg80211_unregister_wdev(&link_adapter->wdev); + + if (rtnl_held) + rtnl_lock(); +} +#else +static +void wlan_hdd_register_ml_link(struct hdd_adapter *sta_adapter, + struct hdd_adapter *link_adapter) +{ +} + +static +void wlan_hdd_unregister_ml_link(struct hdd_adapter *link_adapter, + bool rtnl_held) +{ +} +#endif + +void hdd_register_wdev(struct hdd_adapter *sta_adapter, + struct hdd_adapter *link_adapter, + struct hdd_adapter_create_param *adapter_params) +{ + int i; + + hdd_enter_dev(sta_adapter->dev); + /* Set the relation between adapters*/ + wlan_hdd_register_ml_link(sta_adapter, link_adapter); + sta_adapter->mlo_adapter_info.is_ml_adapter = true; + sta_adapter->mlo_adapter_info.is_link_adapter = false; + link_adapter->mlo_adapter_info.is_link_adapter = true; + link_adapter->mlo_adapter_info.is_ml_adapter = false; + link_adapter->mlo_adapter_info.ml_adapter = sta_adapter; + link_adapter->mlo_adapter_info.associate_with_ml_adapter = + adapter_params->associate_with_ml_adapter; + qdf_set_bit(WDEV_ONLY_REGISTERED, &link_adapter->event_flags); + + for (i = 0; i < WLAN_MAX_MLD; i++) { + if (sta_adapter->mlo_adapter_info.link_adapter[i]) + continue; + sta_adapter->mlo_adapter_info.link_adapter[i] = link_adapter; + break; + } + + qdf_mem_copy(link_adapter->mld_addr.bytes, sta_adapter->mld_addr.bytes, + QDF_MAC_ADDR_SIZE); + hdd_exit(); +} + +static +void hdd_mlo_close_adapter(struct hdd_adapter *link_adapter, bool rtnl_held) +{ + struct osif_vdev_sync *vdev_sync; + + vdev_sync = osif_vdev_sync_unregister(link_adapter->dev); + if (vdev_sync) + osif_vdev_sync_wait_for_ops(vdev_sync); + + hdd_check_for_net_dev_ref_leak(link_adapter); + policy_mgr_clear_concurrency_mode(link_adapter->hdd_ctx->psoc, + link_adapter->device_mode); + link_adapter->wdev.netdev = NULL; + + wlan_hdd_unregister_ml_link(link_adapter, rtnl_held); + free_netdev(link_adapter->dev); + + if (vdev_sync) + osif_vdev_sync_destroy(vdev_sync); +} + +QDF_STATUS hdd_wlan_unregister_mlo_interfaces(struct hdd_adapter *adapter, + bool rtnl_held) +{ + int i; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_adapter *link_adapter; + + mlo_adapter_info = &adapter->mlo_adapter_info; + + if (mlo_adapter_info->is_link_adapter) { + ucfg_dp_destroy_intf(adapter->hdd_ctx->psoc, + &adapter->mac_addr); + hdd_remove_front_adapter(adapter->hdd_ctx, &adapter); + return QDF_STATUS_E_AGAIN; + } + + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + hdd_cleanup_conn_info(link_adapter->deflink); + ucfg_dp_destroy_intf(link_adapter->hdd_ctx->psoc, + &link_adapter->mac_addr); + hdd_remove_adapter(link_adapter->hdd_ctx, link_adapter); + hdd_mlo_close_adapter(link_adapter, rtnl_held); + } + + return QDF_STATUS_SUCCESS; +} + +void hdd_wlan_register_mlo_interfaces(struct hdd_context *hdd_ctx) +{ + int i = 0; + QDF_STATUS status; + struct hdd_adapter *ml_adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_adapter_create_param params = {0}; + struct qdf_mac_addr link_addr[WLAN_MAX_ML_BSS_LINKS] = {0}; + + ml_adapter = hdd_get_ml_adapter(hdd_ctx); + if (!ml_adapter) + return; + + status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, + &ml_adapter->mld_addr, + &link_addr[0], + WLAN_MAX_ML_BSS_LINKS); + if (QDF_IS_STATUS_ERROR(status)) + return; + + /* if target supports MLO create a new dev */ + params.only_wdev_register = true; + params.associate_with_ml_adapter = true; + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null", + link_addr[0].bytes, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to register link adapter:%d", status); + + qdf_mem_zero(¶ms, sizeof(params)); + params.only_wdev_register = true; + params.associate_with_ml_adapter = false; + /* if target supports MLO create a new dev */ + status = hdd_open_adapter_no_trans(hdd_ctx, QDF_STA_MODE, "null", + link_addr[1].bytes, ¶ms); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to register link adapter:%d", status); + } else { + hdd_adapter_for_each_link_info(ml_adapter, link_info) { + qdf_copy_macaddr(&link_info->link_addr, + &link_addr[i++]); + } + } +} + +void +hdd_adapter_set_sl_ml_adapter(struct hdd_adapter *adapter) +{ + adapter->mlo_adapter_info.is_single_link_ml = true; +} + +void +hdd_adapter_clear_sl_ml_adapter(struct hdd_adapter *adapter) +{ + adapter->mlo_adapter_info.is_single_link_ml = false; +} + +struct hdd_adapter *hdd_get_ml_adapter(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_VDEV; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (hdd_adapter_is_ml_adapter(adapter)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return adapter; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return NULL; +} +#endif + +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter) +{ + adapter->mlo_adapter_info.is_ml_adapter = true; + qdf_copy_macaddr(&adapter->mld_addr, &adapter->mac_addr); +} +#else +void hdd_adapter_set_ml_adapter(struct hdd_adapter *adapter) +{ + adapter->mlo_adapter_info.is_ml_adapter = true; +} + +static struct mlo_osif_ext_ops mlo_osif_ops = { + .mlo_mgr_osif_update_bss_info = hdd_cm_save_connected_links_info, + .mlo_mgr_osif_update_mac_addr = hdd_link_switch_vdev_mac_addr_update, + .mlo_mgr_osif_link_switch_notification = + hdd_adapter_link_switch_notification, +}; + +QDF_STATUS hdd_mlo_mgr_register_osif_ops(void) +{ + struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); + + return wlan_mlo_mgr_register_osif_ext_ops(mlo_mgr_ctx, &mlo_osif_ops); +} + +QDF_STATUS hdd_mlo_mgr_unregister_osif_ops(void) +{ + struct mlo_mgr_context *mlo_mgr_ctx = wlan_objmgr_get_mlo_ctx(); + + return wlan_mlo_mgr_unregister_osif_ext_ops(mlo_mgr_ctx); +} + +QDF_STATUS hdd_adapter_link_switch_notification(struct wlan_objmgr_vdev *vdev, + uint8_t non_trans_vdev_id) +{ + bool found = false; + struct hdd_adapter *adapter; + struct vdev_osif_priv *osif_priv; + struct wlan_hdd_link_info *link_info, *iter_link_info; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + hdd_err("Invalid osif priv"); + return QDF_STATUS_E_INVAL; + } + + link_info = osif_priv->legacy_osif_priv; + adapter = link_info->adapter; + + if (link_info->vdev_id != adapter->deflink->vdev_id) { + hdd_err("Deflink VDEV %d not equals current VDEV %d", + adapter->deflink->vdev_id, link_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + hdd_adapter_for_each_link_info(adapter, iter_link_info) { + if (non_trans_vdev_id == iter_link_info->vdev_id) { + adapter->deflink = iter_link_info; + found = true; + break; + } + } + + if (!found) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#endif + +void hdd_mlo_t2lm_register_callback(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev || !vdev->mlo_dev_ctx) + return; + + wlan_register_t2lm_link_update_notify_handler( + hdd_mlo_dev_t2lm_notify_link_update, + vdev->mlo_dev_ctx); +} + +void hdd_mlo_t2lm_unregister_callback(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev || !vdev->mlo_dev_ctx) + return; + + wlan_unregister_t2lm_link_update_notify_handler(vdev->mlo_dev_ctx, 0); +} + +QDF_STATUS hdd_derive_link_address_from_mld(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *mld_addr, + struct qdf_mac_addr *link_addr_list, + uint8_t max_idx) +{ + uint8_t last_byte, temp_byte, idx, start_idx = 0; + struct qdf_mac_addr new_addr; + struct qdf_mac_addr *link_addr; + + if (!psoc || !mld_addr || !link_addr_list || !max_idx || + max_idx > WLAN_MAX_ML_BSS_LINKS || qdf_is_macaddr_zero(mld_addr)) { + hdd_err("Invalid values"); + return QDF_STATUS_E_INVAL; + } + + qdf_copy_macaddr(&new_addr, mld_addr); + /* Set locally administered bit */ + new_addr.bytes[0] |= 0x02; + + link_addr = link_addr_list; + last_byte = mld_addr->bytes[5]; + hdd_debug("MLD addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mld_addr->bytes)); + + if (wlan_mlme_get_sta_same_link_mld_addr(psoc)) { + qdf_copy_macaddr(link_addr, mld_addr); + link_addr++; + start_idx++; + } + + for (idx = start_idx; idx < max_idx; idx++) { + temp_byte = ((last_byte >> 4 & INTF_MACADDR_MASK) + idx) & + INTF_MACADDR_MASK; + new_addr.bytes[5] = last_byte + temp_byte; + new_addr.bytes[5] ^= (1 << 7); + + qdf_copy_macaddr(link_addr, &new_addr); + link_addr++; + hdd_debug("Derived link addr: " QDF_MAC_ADDR_FMT ", idx: %d", + QDF_MAC_ADDR_REF(new_addr.bytes), idx); + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +bool hdd_adapter_restore_link_vdev_map(struct hdd_adapter *adapter, + bool same_vdev_mac_map) +{ + int i; + bool mapping_changed = false; + unsigned long link_flags; + uint8_t vdev_id, cur_link_idx, temp_link_idx; + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev; + struct wlan_hdd_link_info *temp_link_info, *link_info; + struct qdf_mac_addr temp_mac; + + hdd_adapter_for_each_link_info(adapter, link_info) { + cur_link_idx = hdd_adapter_get_index_of_link_info(link_info); + /* If the current index matches the current pos in mapping + * then the link info is in same position + */ + if (adapter->curr_link_info_map[cur_link_idx] == cur_link_idx) + continue; + + /* Find the index where current link info is moved to perform + * VDEV info swap. + */ + for (i = cur_link_idx + 1; i < WLAN_MAX_ML_BSS_LINKS; i++) { + if (adapter->curr_link_info_map[i] == cur_link_idx) { + temp_link_idx = i; + break; + } + } + + if (i == WLAN_MAX_ML_BSS_LINKS) + continue; + + temp_link_info = &adapter->link_info[temp_link_idx]; + + /* Move VDEV info from current link info */ + qdf_spin_lock_bh(&temp_link_info->vdev_lock); + vdev = temp_link_info->vdev; + vdev_id = temp_link_info->vdev_id; + temp_link_info->vdev = link_info->vdev; + temp_link_info->vdev_id = link_info->vdev_id; + qdf_spin_unlock_bh(&temp_link_info->vdev_lock); + + /* Update VDEV-OSIF priv pointer to new link info. */ + if (temp_link_info->vdev) { + osif_priv = wlan_vdev_get_ospriv(temp_link_info->vdev); + if (osif_priv) + osif_priv->legacy_osif_priv = temp_link_info; + } + + /* Fill current link info's actual VDEV info */ + qdf_spin_lock_bh(&link_info->vdev_lock); + link_info->vdev = vdev; + link_info->vdev_id = vdev_id; + qdf_spin_unlock_bh(&link_info->vdev_lock); + + /* Update VDEV-OSIF priv pointer to new link info. */ + if (link_info->vdev) { + osif_priv = wlan_vdev_get_ospriv(link_info->vdev); + if (osif_priv) + osif_priv->legacy_osif_priv = link_info; + } + + /* Preserve the VDEV-MAC mapping if requested */ + if (same_vdev_mac_map) { + qdf_copy_macaddr(&temp_mac, &temp_link_info->link_addr); + qdf_copy_macaddr(&temp_link_info->link_addr, + &link_info->link_addr); + qdf_copy_macaddr(&link_info->link_addr, &temp_mac); + } + + /* Swap link flags */ + link_flags = temp_link_info->link_flags; + temp_link_info->link_flags = link_info->link_flags; + link_info->link_flags = link_flags; + + /* Update the mapping, current link info's mapping will be + * set to be proper. + */ + adapter->curr_link_info_map[temp_link_idx] = + adapter->curr_link_info_map[cur_link_idx]; + adapter->curr_link_info_map[cur_link_idx] = cur_link_idx; + + if (!mapping_changed) + mapping_changed = true; + } + + hdd_adapter_disable_all_links(adapter, !same_vdev_mac_map); + + return mapping_changed; +} + +int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + int idx, i, ret = 0; + bool update_self_peer; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_hdd_link_info *link_info; + uint8_t *addr_list[WLAN_MAX_ML_BSS_LINKS + 1] = {0}; + struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; + + /* This API is only called with is ml adapter set for STA mode adapter. + * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for + * MAC address update. + */ + + if (!hdd_adapter_is_ml_adapter(adapter)) { + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, + mld_addr, true); + return ret; + } + + status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, + &mac_addr, &link_addrs[0], + WLAN_MAX_ML_BSS_LINKS); + + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_adapter_restore_link_vdev_map(adapter, false); + + i = 0; + hdd_adapter_for_each_active_link_info(adapter, link_info) { + idx = hdd_adapter_get_index_of_link_info(link_info); + addr_list[i++] = &link_addrs[idx].bytes[0]; + } + + status = sme_check_for_duplicate_session(hdd_ctx->mac_handle, + &addr_list[0]); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + i = 0; + hdd_adapter_for_each_link_info(adapter, link_info) + qdf_copy_macaddr(&link_info->link_addr, &link_addrs[i++]); + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + idx = hdd_adapter_get_index_of_link_info(link_info); + update_self_peer = + (link_info == adapter->deflink) ? true : false; + ret = hdd_dynamic_mac_address_set(link_info, link_addrs[idx], + mac_addr, update_self_peer); + if (ret) + return ret; + + qdf_copy_macaddr(&link_info->link_addr, &link_addrs[idx]); + } + + hdd_adapter_update_mlo_mgr_mac_addr(adapter); + return ret; +} +#else +int hdd_update_vdev_mac_address(struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + int i, ret = 0; + QDF_STATUS status; + bool eht_capab, update_self_peer; + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + uint8_t *addr_list[WLAN_MAX_MLD + 1] = {0}; + struct qdf_mac_addr link_addrs[WLAN_MAX_ML_BSS_LINKS] = {0}; + + /* This API is only called with is ml adapter set for STA mode adapter. + * For SAP mode, hdd_hostapd_set_mac_address() is the entry point for + * MAC address update. + */ + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (!(eht_capab && hdd_adapter_is_ml_adapter(adapter))) { + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + ret = hdd_dynamic_mac_address_set(adapter->deflink, mac_addr, + mld_addr, true); + return ret; + } + + status = hdd_derive_link_address_from_mld(hdd_ctx->psoc, + &mac_addr, &link_addrs[0], + WLAN_MAX_ML_BSS_LINKS); + + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + for (i = 0; i < WLAN_MAX_MLD; i++) + addr_list[i] = &link_addrs[i].bytes[0]; + + status = sme_check_for_duplicate_session(hdd_ctx->mac_handle, + &addr_list[0]); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + + if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) + update_self_peer = true; + else + update_self_peer = false; + + ret = hdd_dynamic_mac_address_set(link_adapter->deflink, + link_addrs[i], mac_addr, + update_self_peer); + if (ret) + return ret; + + /* Update DP intf and new link address in link adapter + */ + ucfg_dp_update_intf_mac(hdd_ctx->psoc, &link_adapter->mac_addr, + &link_addrs[i], + link_adapter->deflink->vdev); + qdf_copy_macaddr(&link_adapter->mac_addr, &link_addrs[i]); + qdf_copy_macaddr(&adapter->link_info[i].link_addr, + &link_addrs[i]); + } + + qdf_copy_macaddr(&adapter->link_info[i].link_addr, &link_addrs[i]); + hdd_adapter_update_mlo_mgr_mac_addr(adapter); + + return ret; +} +#endif +#endif /* WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE */ + +const struct nla_policy +ml_link_state_config_policy [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE] = {.type = NLA_U32}, +}; + +const struct nla_policy +ml_link_state_request_policy[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG] = {.type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS] = { + .type = NLA_U8}, +}; + +static int +__wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret = 0; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_objmgr_vdev *vdev; + struct hdd_context *hdd_ctx = NULL; + + hdd_enter_dev(wdev->netdev); + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return -EINVAL; + + if (adapter->device_mode != QDF_STA_MODE) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + + if (!vdev) + return -EINVAL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + goto release_ref; + + ret = wlan_handle_mlo_link_state_operation(adapter, wiphy, vdev, + hdd_ctx, data, data_len); + +release_ref: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + + return ret; +} + +int wlan_hdd_cfg80211_process_ml_link_state(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_process_ml_link_state(wiphy, wdev, data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static inline void ml_link_state_resp_cb(struct ml_link_state_info_event *ev, + void *cookie) +{ + struct ml_link_state_info_event *priv; + struct osif_request *request; + + request = osif_request_get(cookie); + + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + qdf_mem_copy(priv, ev, sizeof(*priv)); + osif_request_complete(request); + osif_request_put(request); +} + +static uint32_t +hdd_get_ml_link_state_response_len(const struct ml_link_state_info_event *event) +{ + uint32_t len = 0; + uint32_t info_len = 0; + + len = NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE */ + len += NLA_HDRLEN + sizeof(u32); + + /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE */ + len += NLA_HDRLEN + sizeof(u32); + + /* nest */ + info_len = NLA_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID */ + info_len += NLA_HDRLEN + sizeof(u8); + /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE */ + info_len += NLA_HDRLEN + sizeof(u32); + + /* QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG */ + len += NLA_HDRLEN + (info_len * event->num_mlo_vdev_link_info); + + return len; +} + +static int +hdd_ml_generate_link_state_resp_nlmsg(struct sk_buff *skb, + struct wlan_objmgr_psoc *psoc, + struct ml_link_state_info_event *params, + uint32_t num_link_info) +{ + struct nlattr *nla_config_attr, *nla_config_params; + uint32_t i = 0, attr; + int errno; + uint32_t value; + + attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; + value = ucfg_mlme_get_ml_link_control_mode(psoc, params->vdev_id); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OPERATION_MODE; + + /* Default link state operation mode is only supported */ + value = QCA_WLAN_VENDOR_LINK_STATE_OPERATION_MODE_DEFAULT; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; + nla_config_attr = nla_nest_start(skb, attr); + + if (!nla_config_attr) + return -EINVAL; + + for (i = 0; i < num_link_info; i++) { + nla_config_params = nla_nest_start(skb, attr); + if (!nla_config_params) + return -EINVAL; + + attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; + value = params->link_info[i].link_id; + errno = nla_put_u8(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; + value = params->link_info[i].link_status; + errno = nla_put_u32(skb, attr, value); + + if (errno) + return errno; + + nla_nest_end(skb, nla_config_params); + } + + nla_nest_end(skb, nla_config_attr); + + return 0; +} + +static char *link_state_status_id_to_str(uint32_t status) +{ + switch (status) { + case WLAN_LINK_INFO_EVENT_SUCCESS: + return "LINK_INFO_EVENT_SUCCESS"; + case WLAN_LINK_INFO_EVENT_REJECT_FAILURE: + return "LINK_INFO_EVENT_REJECT_FAILURE"; + case WLAN_LINK_INFO_EVENT_REJECT_VDEV_NOT_UP: + return "LINK_INFO_EVENT_REJECT_VDEV_NOT_UP"; + case WLAN_LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS: + return "LINK_INFO_EVENT_REJECT_ROAMING_IN_PROGRESS"; + case WLAN_LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION: + return "LINK_INFO_EVENT_REJECT_NON_MLO_CONNECTION"; + } + return "Undefined link state status ID"; +} + +static bool +wlan_hdd_link_state_request_needed(struct hdd_adapter *adapter) +{ + qdf_time_t link_state_cached_duration = 0; + + link_state_cached_duration = + qdf_system_ticks_to_msecs(qdf_system_ticks()) - + adapter->link_state_cached_timestamp; + if (link_state_cached_duration <= + adapter->hdd_ctx->config->link_state_cache_expiry_time) + return false; + + return true; +} + +#ifdef WLAN_FEATURE_11BE_MLO + +void hdd_update_link_state_cached_timestamp(struct hdd_adapter *adapter) +{ + adapter->link_state_cached_timestamp = + qdf_system_ticks_to_msecs(qdf_system_ticks()); +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +static QDF_STATUS +wlan_hdd_cached_link_state_request(struct hdd_adapter *adapter, + struct wiphy *wiphy, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct ml_link_state_info_event link_state_event = {0}; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + int skb_len; + struct sk_buff *reply_skb = NULL; + int errno; + struct qdf_mac_addr *mld_addr; + uint8_t link_iter = 0; + struct mlo_link_info *ml_link_info; + struct wlan_mlo_dev_context *mlo_ctx; + + mlo_ctx = vdev->mlo_dev_ctx; + if (!mlo_ctx) { + hdd_err("null mlo_dev_ctx"); + return -EINVAL; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + + if (link_iter >= WLAN_MAX_ML_BSS_LINKS) { + hdd_err("Invalid number of link info"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + link_state_event.link_info[link_iter].link_id = + sta_ctx->conn_info.ieee_link_id; + link_state_event.link_info[link_iter].vdev_id = + link_info->vdev_id; + link_state_event.link_info[link_iter].chan_freq = + sta_ctx->ch_info.freq; + + if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID) + continue; + + ml_link_info = mlo_mgr_get_ap_link_by_link_id( + mlo_ctx, + sta_ctx->conn_info.ieee_link_id); + if (!ml_link_info) { + hdd_debug("link: %d info does not exist", + sta_ctx->conn_info.ieee_link_id); + return -EINVAL; + } + + link_state_event.link_info[link_iter].link_status = + ml_link_info->is_link_active; + + link_iter++; + + hdd_debug_rl("vdev id %d sta_ctx->conn_info.ieee_link_id %d is_mlo_vdev_active %d ", + link_info->vdev_id, sta_ctx->conn_info.ieee_link_id, + ml_link_info->is_link_active); + } + + link_state_event.num_mlo_vdev_link_info = link_iter; + link_state_event.vdev_id = wlan_vdev_get_id(vdev); + link_state_event.status = 0; + mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + link_state_event.mldaddr = *mld_addr; + + hdd_debug_rl("cached link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT, + link_state_event.vdev_id, link_state_event.status, + link_state_event.num_mlo_vdev_link_info, + QDF_MAC_ADDR_REF(link_state_event.mldaddr.bytes)); + + skb_len = hdd_get_ml_link_state_response_len(&link_state_event); + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + if (!reply_skb) { + hdd_err("Get stats - alloc reply_skb failed"); + status = QDF_STATUS_E_NOMEM; + return status; + } + + status = hdd_ml_generate_link_state_resp_nlmsg( + reply_skb, psoc, &link_state_event, + link_state_event.num_mlo_vdev_link_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl response"); + goto free_skb; + } + + errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); + + return qdf_status_from_os_return(errno); + +free_skb: + wlan_cfg80211_vendor_free_skb(reply_skb); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlan_hdd_link_state_request(struct hdd_adapter *adapter, + struct wiphy *wiphy, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + int errno; + int skb_len; + struct sk_buff *reply_skb = NULL; + QDF_STATUS status = QDF_STATUS_E_INVAL; + void *cookie; + struct ml_link_state_info_event *link_state_event = NULL; + struct osif_request *request; + struct ml_link_state_cmd_info info = {0}; + int num_info = 0; + static const struct osif_request_params params = { + .priv_size = sizeof(*link_state_event), + .timeout_ms = WLAN_WAIT_TIME_LINK_STATE, + .dealloc = NULL, + }; + + if (!wiphy || !vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return status; + + if (adapter->device_mode != QDF_STA_MODE) + return QDF_STATUS_SUCCESS; + + if (!wlan_hdd_link_state_request_needed(adapter)) { + hdd_debug_rl("sending cached link state request"); + status = wlan_hdd_cached_link_state_request(adapter, wiphy, + psoc, vdev); + return status; + } + + request = osif_request_alloc(¶ms); + if (!request) + return QDF_STATUS_E_NOMEM; + + cookie = osif_request_cookie(request); + link_state_event = osif_request_priv(request); + + info.request_cookie = cookie; + info.ml_link_state_resp_cb = ml_link_state_resp_cb; + + status = mlo_get_link_state_register_resp_cb(vdev, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to register resp callback: %d", status); + status = qdf_status_to_os_return(status); + goto free_event; + } + + status = ml_post_get_link_state_msg(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to post scheduler msg"); + goto free_event; + } + + status = osif_request_wait_for_response(request); + if (status) { + hdd_err("wait failed or timed out ret: %d", status); + goto free_event; + } + + hdd_debug("ml_link_state_resp: vdev id %d status %d num %d MAC addr " QDF_MAC_ADDR_FMT, + link_state_event->vdev_id, link_state_event->status, + link_state_event->num_mlo_vdev_link_info, + QDF_MAC_ADDR_REF(link_state_event->mldaddr.bytes)); + + if (QDF_IS_STATUS_ERROR(link_state_event->status)) { + hdd_debug("ml_link_state_status failed %s", + link_state_status_id_to_str(link_state_event->status)); + goto free_event; + } + + for (num_info = 0; num_info < link_state_event->num_mlo_vdev_link_info; + num_info++) { + hdd_debug("ml_link_state_resp: chan_freq %d vdev_id %d link_id %d link_status %d", + link_state_event->link_info[num_info].chan_freq, + link_state_event->link_info[num_info].vdev_id, + link_state_event->link_info[num_info].link_id, + link_state_event->link_info[num_info].link_status); + } + + hdd_update_link_state_cached_timestamp(adapter); + + skb_len = hdd_get_ml_link_state_response_len(link_state_event); + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, + skb_len); + if (!reply_skb) { + hdd_err("Get stats - alloc reply_skb failed"); + status = QDF_STATUS_E_NOMEM; + goto free_event; + } + + status = hdd_ml_generate_link_state_resp_nlmsg( + reply_skb, psoc, link_state_event, + link_state_event->num_mlo_vdev_link_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl response"); + goto free_skb; + } + + osif_request_put(request); + + errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); + + return qdf_status_from_os_return(errno); + +free_skb: + wlan_cfg80211_vendor_free_skb(reply_skb); +free_event: + osif_request_put(request); + + return status; +} + +#define MLD_MAX_SUPPORTED_LINKS 2 + +int wlan_handle_mlo_link_state_operation(struct hdd_adapter *adapter, + struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + struct hdd_context *hdd_ctx, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX + 1]; + enum qca_wlan_vendor_link_state_op_types ml_link_op; + struct nlattr *link_oper_attr, *mode_attr, *curr_attr, *num_link_attr; + int rem_len = 0, rc; + uint32_t attr_id, ml_config_state; + uint8_t ml_active_num_links, ml_link_control_mode; + uint8_t ml_config_link_id, num_links = 0; + uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; + uint8_t link_id_list[MLD_MAX_SUPPORTED_LINKS] = {0}; + uint32_t config_state_list[MLD_MAX_SUPPORTED_LINKS] = {0}; + QDF_STATUS status; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_STATE_MAX, + data, data_len, + ml_link_state_request_policy)) { + hdd_debug("vdev %d: invalid mlo link state attr", vdev_id); + return -EINVAL; + } + + attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_OP_TYPE; + link_oper_attr = tb[attr_id]; + if (!link_oper_attr) { + hdd_debug("vdev %d: link state op not specified", vdev_id); + return -EINVAL; + } + ml_link_op = nla_get_u8(link_oper_attr); + switch (ml_link_op) { + case QCA_WLAN_VENDOR_LINK_STATE_OP_GET: + status = wlan_hdd_link_state_request(adapter, wiphy, + hdd_ctx->psoc, vdev); + return qdf_status_to_os_return(status); + case QCA_WLAN_VENDOR_LINK_STATE_OP_SET: + if (policy_mgr_is_set_link_in_progress(hdd_ctx->psoc)) { + hdd_debug("vdev %d: change link already in progress", + vdev_id); + return -EBUSY; + } + + break; + default: + hdd_debug("vdev %d: Invalid op type:%d", vdev_id, ml_link_op); + return -EINVAL; + } + + attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONTROL_MODE; + mode_attr = tb[attr_id]; + if (!mode_attr) { + hdd_debug("vdev %d: ml links control mode attr not present", + vdev_id); + return -EINVAL; + } + ml_link_control_mode = nla_get_u8(mode_attr); + + switch (ml_link_control_mode) { + case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_DEFAULT: + /* clear mlo link(s) settings in fw as per driver */ + status = policy_mgr_clear_ml_links_settings_in_fw(hdd_ctx->psoc, + vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + break; + case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_USER: + attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG; + if (!tb[attr_id]) { + hdd_debug("vdev %d: state config attr not present", + vdev_id); + return -EINVAL; + } + + nla_for_each_nested(curr_attr, tb[attr_id], rem_len) { + rc = wlan_cfg80211_nla_parse_nested( + tb2, QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_MAX, + curr_attr, + ml_link_state_config_policy); + if (rc) { + hdd_debug("vdev %d: nested attr not present", + vdev_id); + return -EINVAL; + } + + attr_id = + QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_LINK_ID; + if (!tb2[attr_id]) { + hdd_debug("vdev %d: link id attr not present", + vdev_id); + return -EINVAL; + } + + ml_config_link_id = nla_get_u8(tb2[attr_id]); + + attr_id = QCA_WLAN_VENDOR_ATTR_LINK_STATE_CONFIG_STATE; + if (!tb2[attr_id]) { + hdd_debug("vdev %d: config attr not present", + vdev_id); + return -EINVAL; + } + + ml_config_state = nla_get_u32(tb2[attr_id]); + hdd_debug("vdev %d: ml_link_id %d, ml_link_state:%d", + vdev_id, ml_config_link_id, ml_config_state); + link_id_list[num_links] = ml_config_link_id; + config_state_list[num_links] = ml_config_state; + num_links++; + + if (num_links >= MLD_MAX_SUPPORTED_LINKS) + break; + } + + status = policy_mgr_update_mlo_links_based_on_linkid( + hdd_ctx->psoc, + vdev_id, num_links, + link_id_list, + config_state_list); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + break; + case QCA_WLAN_VENDOR_LINK_STATE_CONTROL_MODE_MIXED: + attr_id = + QCA_WLAN_VENDOR_ATTR_LINK_STATE_MIXED_MODE_ACTIVE_NUM_LINKS; + num_link_attr = tb[attr_id]; + if (!num_link_attr) { + hdd_debug("number of active state links not specified"); + return -EINVAL; + } + ml_active_num_links = nla_get_u8(num_link_attr); + hdd_debug("vdev %d: ml_active_num_links: %d", vdev_id, + ml_active_num_links); + if (ml_active_num_links > MLD_MAX_SUPPORTED_LINKS) + return -EINVAL; + status = policy_mgr_update_active_mlo_num_links(hdd_ctx->psoc, + vdev_id, ml_active_num_links); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + break; + default: + hdd_debug("vdev %d: invalid ml_link_control_mode: %d", vdev_id, + ml_link_control_mode); + return -EINVAL; + } + + ucfg_mlme_set_ml_link_control_mode(hdd_ctx->psoc, vdev_id, + ml_link_control_mode); + + hdd_debug("vdev: %d, processed link state command successfully", + vdev_id); + return 0; +} + +static uint32_t +hdd_get_t2lm_setup_event_len(void) +{ + uint32_t len = 0; + uint32_t info_len = 0; + + len = NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR */ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + /* nest */ + info_len = NLA_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK */ + info_len += NLA_HDRLEN + sizeof(u16); + /* QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK */ + info_len += NLA_HDRLEN + sizeof(u16); + + /* QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS */ + len += NLA_HDRLEN + (info_len * T2LM_MAX_NUM_TIDS); + + return len; +} + +static QDF_STATUS +hdd_t2lm_pack_nl_response(struct sk_buff *skb, + struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm, + struct qdf_mac_addr mld_addr) +{ + struct nlattr *config_attr, *config_params; + uint32_t i = 0, attr, attr1; + int errno; + uint32_t value; + uint8_t tid_num; + + attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR; + if (nla_put(skb, attr, QDF_MAC_ADDR_SIZE, mld_addr.bytes)) { + hdd_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + if (t2lm->default_link_mapping) { + hdd_debug("update mld addr for default mapping"); + return QDF_STATUS_SUCCESS; + } + + attr = QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS; + config_attr = nla_nest_start(skb, attr); + if (!config_attr) { + hdd_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + switch (t2lm->direction) { + case WLAN_T2LM_UL_DIRECTION: + for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { + config_params = nla_nest_start(skb, tid_num + 1); + if (!config_params) + return -EINVAL; + + attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; + value = t2lm->ieee_link_map_tid[i]; + errno = nla_put_u16(skb, attr1, value); + if (errno) + return errno; + + attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; + value = 0; + errno = nla_put_u16(skb, attr1, value); + if (errno) + return errno; + nla_nest_end(skb, config_params); + } + break; + case WLAN_T2LM_DL_DIRECTION: + for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { + config_params = nla_nest_start(skb, tid_num + 1); + if (!config_params) + return -EINVAL; + attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; + value = t2lm->ieee_link_map_tid[i]; + errno = nla_put_u16(skb, attr1, value); + if (errno) + return errno; + + attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; + value = 0; + errno = nla_put_u16(skb, attr1, value); + if (errno) + return errno; + nla_nest_end(skb, config_params); + } + break; + case WLAN_T2LM_BIDI_DIRECTION: + for (tid_num = 0; tid_num < T2LM_MAX_NUM_TIDS; tid_num++) { + config_params = nla_nest_start(skb, tid_num + 1); + if (!config_params) + return -EINVAL; + + attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK; + value = t2lm->ieee_link_map_tid[i]; + errno = nla_put_u16(skb, attr1, value); + if (errno) + return errno; + + attr1 = QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK; + value = t2lm->ieee_link_map_tid[i]; + errno = nla_put_u16(skb, attr1, value); + if (errno) + return errno; + nla_nest_end(skb, config_params); + } + break; + default: + return -EINVAL; + } + nla_nest_end(skb, config_attr); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_hdd_send_t2lm_event(struct wlan_objmgr_vdev *vdev, + struct wlan_t2lm_info *t2lm) +{ + struct sk_buff *skb; + size_t data_len; + QDF_STATUS status; + struct qdf_mac_addr mld_addr; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP_INDEX; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("Invalid VDEV"); + return QDF_STATUS_E_FAILURE; + } + + adapter = link_info->adapter; + data_len = hdd_get_t2lm_setup_event_len(); + skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy, + NULL, + data_len, + index, GFP_KERNEL); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return -EINVAL; + } + + /* get mld addr */ + status = wlan_vdev_get_bss_peer_mld_mac(vdev, &mld_addr); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get mld address"); + goto free_skb; + } + + status = hdd_t2lm_pack_nl_response(skb, vdev, t2lm, mld_addr); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl response"); + goto free_skb; + } + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + + return status; +free_skb: + wlan_cfg80211_vendor_free_skb(skb); + + return status; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mpta_helper.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mpta_helper.c new file mode 100644 index 0000000000..003df0c37a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_mpta_helper.c @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_mpta_helper.c + * + * The implementation of mpta helper configuration + */ + +#include "wlan_hdd_main.h" +#include "wmi_unified_param.h" +#include "wlan_hdd_mpta_helper.h" +#include "qca_vendor.h" +#include "wlan_osif_request_manager.h" +#include "osif_sync.h" + +const struct nla_policy +qca_wlan_vendor_mpta_helper_attr[QCA_MPTA_HELPER_VENDOR_ATTR_MAX + 1] = { + [QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE] = {.type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION] = {.type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION] = { + .type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION] = {.type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION] = { + .type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION] = {.type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION] = {.type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN] = {.type = NLA_U32 }, + [QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION] = {.type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_mpta_helper_config() - update + * tri-radio coex status by mpta helper + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 on success; error number otherwise. + * + */ +static int +__wlan_hdd_cfg80211_mpta_helper_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_MPTA_HELPER_VENDOR_ATTR_MAX + 1]; + struct coex_config_params coex_cfg_params = {0}; + int errno; + QDF_STATUS status; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_cfg80211_nla_parse(tb, QCA_MPTA_HELPER_VENDOR_ATTR_MAX, data, + data_len, + qca_wlan_vendor_mpta_helper_attr)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + /* if no attributes specified, return -EINVAL */ + errno = -EINVAL; + + if (tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE]) { + coex_cfg_params.config_type = + WMI_COEX_CONFIG_MPTA_HELPER_ZIGBEE_STATE; + coex_cfg_params.config_arg1 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE]); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set zigbee STATE"); + return -EINVAL; + } + + errno = 0; + } + + if ((tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION]) && + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION])) { + coex_cfg_params.config_type = + WMI_COEX_CONFIG_MPTA_HELPER_INT_OCS_PARAMS; + coex_cfg_params.config_arg1 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION]); + coex_cfg_params.config_arg2 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION]); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set int OCS duration"); + return -EINVAL; + } + + errno = 0; + } + + if ((tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION]) && + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION])) { + coex_cfg_params.config_type = + WMI_COEX_CONFIG_MPTA_HELPER_MON_OCS_PARAMS; + coex_cfg_params.config_arg1 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION]); + coex_cfg_params.config_arg2 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION]); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set mon OCS duration"); + return -EINVAL; + } + + errno = 0; + } + + if ((tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION]) && + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION])) { + coex_cfg_params.config_type = + WMI_COEX_CONFIG_MPTA_HELPER_INT_MON_DURATION; + coex_cfg_params.config_arg1 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION]); + coex_cfg_params.config_arg2 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION]); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set int mon duration"); + return -EINVAL; + } + + errno = 0; + } + + if (tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN]) { + coex_cfg_params.config_type = + WMI_COEX_CONFIG_MPTA_HELPER_ZIGBEE_CHANNEL; + coex_cfg_params.config_arg1 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN]); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set zigbee chan"); + return -EINVAL; + } + + errno = 0; + } + + if (tb[QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION]) { + coex_cfg_params.config_type = + WMI_COEX_CONFIG_MPTA_HELPER_WLAN_MUTE_DURATION; + coex_cfg_params.config_arg1 = nla_get_u32 + (tb[QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION]); + + status = sme_send_coex_config_cmd(&coex_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set wlan mute duration"); + return -EINVAL; + } + + errno = 0; + } + + return errno; +} + +/** + * wlan_hdd_cfg80211_mpta_helper_config() - update + * tri-radio coex status by mpta helper + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Return: 0 on success; error number otherwise. + * + */ +int +wlan_hdd_cfg80211_mpta_helper_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_mpta_helper_config( + wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_mpta_helper_enable() - enable/disable mpta helper + * according to cfg from INI + * @coex_cfg_params: pointer of coex config command params + * @config: pointer of BTC config items + * + * Return: 0 on success; error number otherwise. + * + */ +int +wlan_hdd_mpta_helper_enable(struct coex_config_params *coex_cfg_params, + struct wlan_fwol_coex_config *config) +{ + QDF_STATUS status; + + coex_cfg_params->config_type = WMI_COEX_CONFIG_MPTA_HELPER_ENABLE; + coex_cfg_params->config_arg1 = config->btc_mpta_helper_enable; + + status = sme_send_coex_config_cmd(coex_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send coex MPTA Helper Enable"); + return -EINVAL; + } + + return 0; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c new file mode 100644 index 0000000000..a2152cd02c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_nan.c + * + * WLAN Host Device Driver NAN API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_nan.h" +#include "osif_sync.h" +#include +#include "cfg_nan_api.h" +#include "os_if_nan.h" +#include "../../core/src/nan_main_i.h" +#include "spatial_reuse_api.h" +#include "wlan_nan_api.h" +#include "spatial_reuse_ucfg_api.h" + +/** + * wlan_hdd_nan_is_supported() - HDD NAN support query function + * @hdd_ctx: Pointer to hdd context + * + * This function is called to determine if NAN is supported by the + * driver and by the firmware. + * + * Return: true if NAN is supported by the driver and firmware + */ +bool wlan_hdd_nan_is_supported(struct hdd_context *hdd_ctx) +{ + return cfg_nan_get_enable(hdd_ctx->psoc) && + sme_is_feature_supported_by_fw(NAN); +} + +/** + * __wlan_hdd_cfg80211_nan_ext_request() - cfg80211 NAN extended request handler + * @wiphy: driver's wiphy struct + * @wdev: wireless device to which the request is targeted + * @data: actual request data (netlink-encapsulated) + * @data_len: length of @data + * + * Handles NAN Extended vendor commands, sends the command to NAN component + * which parses and forwards the NAN requests. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_nan_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret_val; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_enter_dev(wdev->netdev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err_rl("Command not allowed in FTM mode"); + return -EPERM; + } + + if (!wlan_hdd_nan_is_supported(hdd_ctx)) { + hdd_debug_rl("NAN is not supported"); + return -EPERM; + } + + if (hdd_is_connection_in_progress(NULL, NULL)) { + hdd_err("Connection refused: conn in progress"); + return -EAGAIN; + } + + return os_if_process_nan_req(hdd_ctx->pdev, adapter->deflink->vdev_id, + data, data_len); +} + +int wlan_hdd_cfg80211_nan_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) + +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_nan_ext_request(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +void hdd_nan_concurrency_update(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + int ret; + + hdd_enter(); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + wlan_twt_concurrency_update(hdd_ctx); + hdd_exit(); +} + +#ifdef WLAN_FEATURE_NAN +#ifdef WLAN_FEATURE_SR +void hdd_nan_sr_concurrency_update(struct nan_event_params *nan_evt) +{ + struct wlan_objmgr_vdev *sta_vdev = NULL; + uint32_t conc_vdev_id = WLAN_INVALID_VDEV_ID; + uint8_t sr_ctrl; + bool is_sr_enabled = false; + uint32_t sta_vdev_id = WLAN_INVALID_VDEV_ID; + uint8_t sta_cnt, i; + uint32_t conn_count; + uint8_t non_srg_max_pd_offset = 0; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS] = { + WLAN_INVALID_VDEV_ID}; + struct nan_psoc_priv_obj *psoc_obj = + nan_get_psoc_priv_obj(nan_evt->psoc); + struct connection_info info[MAX_NUMBER_OF_CONC_CONNECTIONS] = {0}; + uint8_t mac_id; + QDF_STATUS status; + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return; + } + conn_count = policy_mgr_get_connection_info(nan_evt->psoc, info); + if (!conn_count) + return; + sta_cnt = policy_mgr_get_mode_specific_conn_info(nan_evt->psoc, NULL, + vdev_id_list, + PM_STA_MODE); + /* + * Get all active sta vdevs. STA + STA SR concurrency is not supported + * so break whenever a first sta with SR enabled is found. + */ + for (i = 0; i < sta_cnt; i++) { + if (vdev_id_list[i] != WLAN_INVALID_VDEV_ID) { + sta_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + nan_evt->psoc, + vdev_id_list[i], + WLAN_OSIF_ID); + if (!sta_vdev) { + nan_err("sta vdev invalid for vdev id %d", + vdev_id_list[i]); + continue; + } + ucfg_spatial_reuse_get_sr_config( + sta_vdev, &sr_ctrl, + &non_srg_max_pd_offset, &is_sr_enabled); + if (is_sr_enabled) { + sta_vdev_id = vdev_id_list[i]; + break; + } + wlan_objmgr_vdev_release_ref(sta_vdev, WLAN_OSIF_ID); + } + } + if (sta_cnt && sta_vdev && + (!(sr_ctrl & NON_SRG_PD_SR_DISALLOWED) || + (sr_ctrl & SRG_INFO_PRESENT)) && + is_sr_enabled) { + if (nan_evt->evt_type == nan_event_id_enable_rsp) { + wlan_vdev_mlme_set_sr_disable_due_conc( + sta_vdev, true); + wlan_spatial_reuse_osif_event( + sta_vdev, SR_OPERATION_SUSPEND, + SR_REASON_CODE_CONCURRENCY); + } + if (nan_evt->evt_type == nan_event_id_disable_ind) { + if (conn_count > 2) { + status = + policy_mgr_get_mac_id_by_session_id( + nan_evt->psoc, sta_vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + goto exit; + } + conc_vdev_id = + policy_mgr_get_conc_vdev_on_same_mac( + nan_evt->psoc, sta_vdev_id, + mac_id); + /* + * Don't enable SR, if concurrent vdev is not + * NAN and SR concurrency on same mac is not + * allowed. + */ + if (conc_vdev_id != WLAN_INVALID_VDEV_ID && + !policy_mgr_sr_same_mac_conc_enabled( + nan_evt->psoc)) { + hdd_debug("don't enable SR in SCC/MCC"); + goto exit; + } + } + wlan_vdev_mlme_set_sr_disable_due_conc(sta_vdev, false); + wlan_spatial_reuse_osif_event( + sta_vdev, SR_OPERATION_RESUME, + SR_REASON_CODE_CONCURRENCY); + } + } +exit: + if (sta_vdev && is_sr_enabled) + wlan_objmgr_vdev_release_ref(sta_vdev, WLAN_OSIF_ID); +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c new file mode 100644 index 0000000000..a3ae3d98dd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.c @@ -0,0 +1,1303 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_nan_datapath.c + * + * WLAN Host Device Driver nan datapath API implementation + */ +#include +#include +#include +#include +#include +#include "wlan_hdd_includes.h" +#include "wlan_hdd_p2p.h" +#include "osif_sync.h" +#include "wma_api.h" +#include "wlan_hdd_assoc.h" +#include "sme_nan_datapath.h" +#include "wlan_hdd_object_manager.h" +#include +#include "os_if_nan.h" +#include "wlan_nan_api.h" +#include "nan_public_structs.h" +#include "cfg_nan_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "qdf_util.h" +#include "qdf_net_if.h" +#include +#include "wlan_fwol_ucfg_api.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_hdd_sysfs.h" +#include "wlan_hdd_stats.h" + +/** + * hdd_nan_datapath_target_config() - Configure NAN datapath features + * @hdd_ctx: Pointer to HDD context + * @tgt_cfg: Pointer to target device capability information + * + * NAN datapath functionality is enabled if it is enabled in + * .ini file and also supported on target device. + * + * Return: None + */ +void hdd_nan_datapath_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *tgt_cfg) +{ + hdd_ctx->nan_datapath_enabled = + cfg_nan_get_datapath_enable(hdd_ctx->psoc) && + tgt_cfg->nan_datapath_enabled; + hdd_debug("NAN Datapath Enable: %d (Host: %d FW: %d)", + hdd_ctx->nan_datapath_enabled, + cfg_nan_get_datapath_enable(hdd_ctx->psoc), + tgt_cfg->nan_datapath_enabled); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +/** + * hdd_close_ndi_adapter() - close the adapter + * @hdd_ctx: pointer to HDD context + * @adapter: adapter context + * @value: true or false + * + * Returns: void + */ +static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool value) +{ +} +#else +static void hdd_close_ndi_adapter(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, bool value) +{ + hdd_close_adapter(hdd_ctx, adapter, value); +} +#endif + +/** + * hdd_close_ndi() - close NAN Data interface + * @adapter: adapter context + * + * Close the adapter if start BSS fails + * + * Returns: 0 on success, negative error code otherwise + */ +static int hdd_close_ndi(struct hdd_adapter *adapter) +{ + int errno; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + /* check if the adapter is in NAN Data mode */ + if (QDF_NDI_MODE != adapter->device_mode) { + hdd_err("Interface is not in NDI mode"); + return -EINVAL; + } + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + hdd_cancel_ip_notifier_work(adapter); + hdd_adapter_deregister_fc(adapter); + + errno = hdd_vdev_destroy(adapter->deflink); + if (errno) + hdd_err("failed to destroy vdev: %d", errno); + + adapter->is_virtual_iface = true; + /* We are good to close the adapter */ + hdd_close_ndi_adapter(hdd_ctx, adapter, true); + + hdd_exit(); + return 0; +} + +/** + * hdd_is_ndp_allowed() - Indicates if NDP is allowed + * @hdd_ctx: hdd context + * + * NDP is not allowed with any other role active except STA. + * + * Return: true if allowed, false otherwise + */ +#ifdef NDP_SAP_CONCURRENCY_ENABLE +static bool hdd_is_ndp_allowed(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_NDP_ALLOWED; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + switch (adapter->device_mode) { + case QDF_P2P_GO_MODE: + if (test_bit(SOFTAP_BSS_STARTED, + &link_info->link_flags)) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return false; + } + break; + case QDF_P2P_CLIENT_MODE: + if (hdd_cm_is_vdev_associated(link_info) || + hdd_cm_is_connecting(link_info)) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return false; + } + break; + default: + break; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return true; +} +#else +static bool hdd_is_ndp_allowed(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IS_NDP_ALLOWED; + struct wlan_hdd_link_info *link_info; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + switch (adapter->device_mode) { + case QDF_P2P_GO_MODE: + case QDF_SAP_MODE: + if (test_bit(SOFTAP_BSS_STARTED, + &link_info->link_flags)) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return false; + } + break; + case QDF_P2P_CLIENT_MODE: + if (hdd_cm_is_vdev_associated(link_info) || + hdd_cm_is_connecting(link_info)) { + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return false; + } + break; + default: + break; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + return true; +} +#endif /* NDP_SAP_CONCURRENCY_ENABLE */ + +/** + * hdd_ndi_select_valid_freq() - Find the valid freq for NDI start + * @hdd_ctx: hdd context + * @freq: pointer to freq, give preference to 5745, 5220 and 2437 to keep the + * legacy behavior intact + * + * Unlike traditional device modes, where the higher application + * layer initiates connect / join / start, the NAN data + * interface does not have any such formal requests. The NDI + * create request is responsible for starting the BSS as well. + * Use the 5GHz Band NAN Social channel for BSS start if target + * supports it, since a 2.4GHz channel will require a DBS HW mode change + * first on a DBS 2x2 MAC target. Use a 2.4 GHz Band NAN Social channel + * if the target is not 5GHz capable. If both of these channels are + * not available, pick the next available channel. This would be used just to + * start the NDI. Actual channel for NDP data transfer would be negotiated with + * peer later. + * + * Return: SUCCESS if valid channel is obtained + */ +static QDF_STATUS hdd_ndi_select_valid_freq(struct hdd_context *hdd_ctx, + uint32_t *freq) +{ + static const qdf_freq_t valid_freq[] = {NAN_SOCIAL_FREQ_5GHZ_UPPER_BAND, + NAN_SOCIAL_FREQ_5GHZ_LOWER_BAND, + NAN_SOCIAL_FREQ_2_4GHZ}; + uint8_t i; + struct regulatory_channel *cur_chan_list; + QDF_STATUS status; + + for (i = 0; i < ARRAY_SIZE(valid_freq); i++) { + if (wlan_reg_is_freq_enabled(hdd_ctx->pdev, valid_freq[i], + REG_CURRENT_PWR_MODE)) { + *freq = valid_freq[i]; + return QDF_STATUS_SUCCESS; + } + } + + cur_chan_list = qdf_mem_malloc(sizeof(*cur_chan_list) * + (NUM_CHANNELS + 2)); + if (!cur_chan_list) + return QDF_STATUS_E_NOMEM; + + status = ucfg_reg_get_current_chan_list(hdd_ctx->pdev, cur_chan_list); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to get the current channel list"); + qdf_mem_free(cur_chan_list); + return QDF_STATUS_E_IO; + } + + for (i = 0; i < NUM_CHANNELS; i++) { + /* + * current channel list includes all channels. Exclude + * disabled channels + */ + if (cur_chan_list[i].chan_flags & REGULATORY_CHAN_DISABLED || + cur_chan_list[i].chan_flags & REGULATORY_CHAN_RADAR) + continue; + /* + * do not include 6 GHz channels for now as NAN would need + * 2.4 GHz and 5 GHz channels for discovery. + * Need to consider the 6GHz channels when there is a + * case where all 2GHz and 5GHz channels are disabled and + * only 6GHz channels are enabled + */ + if (wlan_reg_is_6ghz_chan_freq(cur_chan_list[i].center_freq)) + continue; + + /* extracting first valid channel from regulatory list */ + if (wlan_reg_is_freq_enabled(hdd_ctx->pdev, + cur_chan_list[i].center_freq, + REG_CURRENT_PWR_MODE)) { + *freq = cur_chan_list[i].center_freq; + qdf_mem_free(cur_chan_list); + return QDF_STATUS_SUCCESS; + } + } + + qdf_mem_free(cur_chan_list); + + return QDF_STATUS_E_FAILURE; +} + +/** + * hdd_ndi_start_bss() - Start BSS on NAN data interface + * @adapter: adapter context + * + * Return: 0 on success, error value on failure + */ +static int hdd_ndi_start_bss(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct bss_dot11_config dot11_cfg = {0}; + struct start_bss_config ndi_bss_cfg = {0}; + qdf_freq_t valid_freq = 0; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct hdd_context *hdd_ctx; + + hdd_enter(); + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!mac) { + hdd_debug("mac ctx NULL"); + return -EINVAL; + } + + status = hdd_ndi_select_valid_freq(hdd_ctx, &valid_freq); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to retrieve channel list for NAN"); + return -EINVAL; + } + + dot11_cfg.vdev_id = adapter->deflink->vdev_id; + dot11_cfg.bss_op_ch_freq = valid_freq; + dot11_cfg.phy_mode = eCSR_DOT11_MODE_AUTO; + if (!wlan_vdev_id_is_open_cipher(mac->pdev, adapter->deflink->vdev_id)) + dot11_cfg.privacy = 1; + + sme_get_network_params(mac, &dot11_cfg); + ndi_bss_cfg.vdev_id = adapter->deflink->vdev_id; + ndi_bss_cfg.oper_ch_freq = dot11_cfg.bss_op_ch_freq; + ndi_bss_cfg.nwType = dot11_cfg.nw_type; + ndi_bss_cfg.dot11mode = dot11_cfg.dot11_mode; + + if (dot11_cfg.opr_rates.numRates) { + qdf_mem_copy(ndi_bss_cfg.operationalRateSet.rate, + dot11_cfg.opr_rates.rate, + dot11_cfg.opr_rates.numRates); + ndi_bss_cfg.operationalRateSet.numRates = + dot11_cfg.opr_rates.numRates; + } + + if (dot11_cfg.ext_rates.numRates) { + qdf_mem_copy(ndi_bss_cfg.extendedRateSet.rate, + dot11_cfg.ext_rates.rate, + dot11_cfg.ext_rates.numRates); + ndi_bss_cfg.extendedRateSet.numRates = + dot11_cfg.ext_rates.numRates; + } + + status = sme_start_bss(mac_handle, adapter->deflink->vdev_id, + &ndi_bss_cfg); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("NDI sme_RoamConnect session %d failed with status %d -> NotConnected", + adapter->deflink->vdev_id, status); + /* change back to NotConnected */ + hdd_conn_set_connection_state(adapter, + eConnectionState_NotConnected); + } + + hdd_exit(); + + return 0; +} + +/** + * hdd_get_random_nan_mac_addr() - generate random non pre-existent mac address + * @hdd_ctx: hdd context pointer + * @mac_addr: mac address buffer to populate + * + * Return: status of operation + */ +static int hdd_get_random_nan_mac_addr(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *mac_addr) +{ + struct hdd_adapter *adapter; + uint8_t pos, bit_pos, byte_pos, mask; + uint8_t i, attempts, max_attempt = 16; + bool found; + + for (attempts = 0; attempts < max_attempt; attempts++) { + found = false; + /* if NDI is present next addr is required to be 1 bit apart */ + adapter = hdd_get_adapter(hdd_ctx, QDF_NDI_MODE); + if (adapter) { + hdd_debug("NDI already exists, deriving next mac"); + qdf_mem_copy(mac_addr, &adapter->mac_addr, + sizeof(*mac_addr)); + qdf_get_random_bytes(&pos, sizeof(pos)); + /* skipping byte 0, 5 leaves 8*4=32 positions */ + pos = pos % 32; + bit_pos = pos % 8; + byte_pos = pos / 8; + mask = 1 << bit_pos; + /* flip the required bit */ + mac_addr->bytes[byte_pos + 1] ^= mask; + } else { + qdf_get_random_bytes(mac_addr, sizeof(*mac_addr)); + /* + * Reset multicast bit (bit-0) and set + * locally-administered bit + */ + mac_addr->bytes[0] = 0x2; + + /* + * to avoid potential conflict with FW's generated NMI + * mac addr, host sets LSB if 6th byte to 0 + */ + mac_addr->bytes[5] &= 0xFE; + } + for (i = 0; i < hdd_ctx->num_provisioned_addr; i++) { + if ((!qdf_mem_cmp(hdd_ctx-> + provisioned_mac_addr[i].bytes, + mac_addr, sizeof(*mac_addr)))) { + found = true; + break; + } + } + + if (found) + continue; + + for (i = 0; i < hdd_ctx->num_derived_addr; i++) { + if ((!qdf_mem_cmp(hdd_ctx-> + derived_mac_addr[i].bytes, + mac_addr, sizeof(*mac_addr)))) { + found = true; + break; + } + } + if (found) + continue; + + adapter = hdd_get_adapter_by_macaddr(hdd_ctx, mac_addr->bytes); + if (!adapter) + return 0; + } + + hdd_err("unable to get non-pre-existing mac address in %d attempts", + max_attempt); + + return -EINVAL; +} + +void hdd_ndp_event_handler(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + bool success; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_NAN_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + psoc = wlan_vdev_get_psoc(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); + + if (roam_status == eCSR_ROAM_NDP_STATUS_UPDATE) { + switch (roam_result) { + case eCSR_ROAM_RESULT_NDI_CREATE_RSP: + success = (roam_info->ndp.ndi_create_params.status == + NAN_DATAPATH_RSP_STATUS_SUCCESS); + hdd_debug("posting ndi create status: %d (%s) to umac", + success, success ? "Success" : "Failure"); + os_if_nan_post_ndi_create_rsp(psoc, link_info->vdev_id, + success); + return; + case eCSR_ROAM_RESULT_NDI_DELETE_RSP: + success = (roam_info->ndp.ndi_create_params.status == + NAN_DATAPATH_RSP_STATUS_SUCCESS); + hdd_debug("posting ndi delete status: %d (%s) to umac", + success, success ? "Success" : "Failure"); + os_if_nan_post_ndi_delete_rsp(psoc, link_info->vdev_id, + success); + return; + default: + hdd_err("in correct roam_result: %d", roam_result); + return; + } + } else { + hdd_err("in correct roam_status: %d", roam_status); + return; + } +} + +/** + * __wlan_hdd_cfg80211_process_ndp_cmd() - handle NDP request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is invoked to handle vendor command + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + int ret_val; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err_rl("Command not allowed in FTM mode"); + return -EPERM; + } + + if (!WLAN_HDD_IS_NDP_ENABLED(hdd_ctx)) { + hdd_debug_rl("NAN datapath is not enabled"); + return -EPERM; + } + + return os_if_nan_process_ndp_cmd(hdd_ctx->psoc, data, data_len, + hdd_is_ndp_allowed(hdd_ctx), wdev); +} + +/** + * wlan_hdd_cfg80211_process_ndp_cmd() - handle NDP request + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * This function is called to send a NAN request to + * firmware. This is an SSR-protected wrapper function. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + /* This call is intentionally not protected by op_start/op_stop, due to + * the various protection needs of the callbacks dispatched within. + */ + return __wlan_hdd_cfg80211_process_ndp_cmd(wiphy, wdev, + data, data_len); +} + +static int update_ndi_state(struct hdd_adapter *adapter, uint32_t state) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_NAN_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + status = os_if_nan_set_ndi_state(vdev, state); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); + return status; +} + +/** + * hdd_init_nan_data_mode() - initialize nan data mode + * @adapter: adapter context + * + * Returns: 0 on success negative error code on error + */ +int hdd_init_nan_data_mode(struct hdd_adapter *adapter) +{ + struct net_device *wlan_dev = adapter->dev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int32_t ret_val; + mac_handle_t mac_handle; + bool bval = false; + uint8_t enable_sifs_burst = 0; + struct wlan_objmgr_vdev *vdev; + uint16_t rts_profile = 0; + + status = hdd_adapter_fill_link_address(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Link address derive failed"); + return qdf_status_to_os_return(status); + } + + status = hdd_adapter_check_duplicate_session(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Duplicate session is existing with same mac address"); + return qdf_status_to_os_return(status); + } + + ret_val = hdd_vdev_create(adapter->deflink); + if (ret_val) { + hdd_err("failed to create vdev: %d", ret_val); + return ret_val; + } + + mac_handle = hdd_ctx->mac_handle; + + /* Configure self HT/VHT capabilities */ + status = ucfg_mlme_get_vht_enable2x2(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("unable to get vht_enable2x2"); + + sme_set_pdev_ht_vht_ies(mac_handle, bval); + sme_set_vdev_ies_per_band(mac_handle, adapter->deflink->vdev_id, + adapter->device_mode); + + hdd_roam_profile_init(adapter->deflink); + hdd_register_wext(wlan_dev); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) { + ret_val = -EAGAIN; + goto wext_unregister; + } + + status = hdd_wmm_adapter_init(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("hdd_wmm_adapter_init() failed, status %d", status); + ret_val = -EAGAIN; + goto error_wmm_init; + } + + set_bit(WMM_INIT_DONE, &adapter->event_flags); + + /* ENABLE SIFS BURST */ + status = ucfg_get_enable_sifs_burst(hdd_ctx->psoc, &enable_sifs_burst); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to get sifs burst value, use default"); + + ret_val = wma_cli_set_command((int)adapter->deflink->vdev_id, + (int)wmi_pdev_param_burst_enable, + enable_sifs_burst, + PDEV_CMD); + if (0 != ret_val) + hdd_err("wmi_pdev_param_burst_enable set failed %d", ret_val); + + /* RTS CTS PARAM */ + status = ucfg_fwol_get_rts_profile(hdd_ctx->psoc, &rts_profile); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("FAILED TO GET RTSCTS Profile status:%d", status); + + ret_val = sme_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_enable_rtscts, rts_profile, + VDEV_CMD); + if (ret_val) + hdd_err("FAILED TO SET RTSCTS Profile ret:%d", ret_val); + + hdd_set_netdev_flags(adapter); + + hdd_tsf_auto_report_init(adapter); + update_ndi_state(adapter, NAN_DATA_NDI_CREATING_STATE); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + return ret_val; + +error_wmm_init: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + +wext_unregister: + hdd_wext_unregister(wlan_dev, true); + QDF_BUG(!hdd_vdev_destroy(adapter->deflink)); + + return ret_val; +} + +/** + * hdd_is_max_ndi_count_reached() - Check the NDI max limit + * @hdd_ctx: Pointer to HDD context + * + * This function does not allow to create more than ndi_max_support + * + * Return: false if max value not reached otherwise true + */ +static bool hdd_is_max_ndi_count_reached(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + uint8_t ndi_adapter_count = 0; + QDF_STATUS status; + uint32_t max_ndi; + + if (!hdd_ctx) + return true; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_NDI_OPEN) { + if (WLAN_HDD_IS_NDI(adapter)) + ndi_adapter_count++; + hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_NDI_OPEN); + } + + status = cfg_nan_get_max_ndi(hdd_ctx->psoc, &max_ndi); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err(" Unable to fetch Max NDI"); + return true; + } + + if (ndi_adapter_count >= max_ndi) { + hdd_err("Can't allow more than %d NDI adapters", + max_ndi); + return true; + } + + return false; +} + +int hdd_ndi_open(const char *iface_name, bool is_add_virtual_iface) +{ + struct hdd_adapter *adapter; + struct qdf_mac_addr random_ndi_mac; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + uint8_t *ndi_mac_addr; + struct hdd_adapter_create_param params = {0}; + + hdd_enter(); + + if (hdd_is_max_ndi_count_reached(hdd_ctx)) + return -EINVAL; + + params.is_add_virtual_iface = is_add_virtual_iface; + + hdd_debug("is_add_virtual_iface %d", is_add_virtual_iface); + + if (cfg_nan_get_ndi_mac_randomize(hdd_ctx->psoc)) { + if (hdd_get_random_nan_mac_addr(hdd_ctx, &random_ndi_mac)) { + hdd_err("get random mac address failed"); + return -EFAULT; + } + ndi_mac_addr = &random_ndi_mac.bytes[0]; + } else { + ndi_mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_NDI_MODE); + if (!ndi_mac_addr) { + hdd_err("get intf address failed"); + return -EFAULT; + } + } + + params.is_add_virtual_iface = 1; + adapter = hdd_open_adapter(hdd_ctx, QDF_NDI_MODE, iface_name, + ndi_mac_addr, NET_NAME_UNKNOWN, true, + ¶ms); + if (!adapter) { + if (!cfg_nan_get_ndi_mac_randomize(hdd_ctx->psoc)) + wlan_hdd_release_intf_addr(hdd_ctx, ndi_mac_addr); + hdd_err("hdd_open_adapter failed"); + return -EINVAL; + } + + hdd_exit(); + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +int hdd_ndi_set_mode(const char *iface_name) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct qdf_mac_addr random_ndi_mac; + uint8_t *ndi_mac_addr = NULL; + + hdd_enter(); + if (hdd_is_max_ndi_count_reached(hdd_ctx)) + return -EINVAL; + + adapter = hdd_get_adapter_by_iface_name(hdd_ctx, iface_name); + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + if (cfg_nan_get_ndi_mac_randomize(hdd_ctx->psoc)) { + if (hdd_get_random_nan_mac_addr(hdd_ctx, &random_ndi_mac)) { + hdd_err("get random mac address failed"); + return -EFAULT; + } + ndi_mac_addr = &random_ndi_mac.bytes[0]; + ucfg_dp_update_intf_mac(hdd_ctx->psoc, &adapter->mac_addr, + (struct qdf_mac_addr *)ndi_mac_addr, + adapter->deflink->vdev); + hdd_update_dynamic_mac(hdd_ctx, &adapter->mac_addr, + (struct qdf_mac_addr *)ndi_mac_addr); + qdf_mem_copy(&adapter->mac_addr, ndi_mac_addr, ETH_ALEN); + qdf_net_update_net_device_dev_addr(adapter->dev, + ndi_mac_addr, ETH_ALEN); + } + + adapter->device_mode = QDF_NDI_MODE; + hdd_debug("Created NDI with device mode:%d and iface_name:%s", + adapter->device_mode, iface_name); + + return 0; +} +#endif + +int hdd_ndi_start(const char *iface_name, uint16_t transaction_id) +{ + int ret; + QDF_STATUS status; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + if (!hdd_ctx) + return -EINVAL; + + adapter = hdd_get_adapter_by_iface_name(hdd_ctx, iface_name); + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + /* create nan vdev */ + status = hdd_init_nan_data_mode(adapter); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to init nan data intf, status :%d", status); + ret = -EFAULT; + goto err_handler; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_NAN_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + ret = -EINVAL; + goto err_handler; + } + + hdd_cstats_log_ndi_create_req_evt(vdev, transaction_id); + /* + * Create transaction id is required to be saved since the firmware + * does not honor the transaction id for create request + */ + ucfg_nan_set_ndp_create_transaction_id(vdev, transaction_id); + ucfg_nan_set_ndi_state(vdev, NAN_DATA_NDI_CREATING_STATE); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); + + if (hdd_ndi_start_bss(adapter)) { + hdd_err("NDI start bss failed"); + ret = -EFAULT; + goto err_handler; + } + + hdd_create_adapter_sysfs_files(adapter); + hdd_exit(); + return 0; + +err_handler: + + /* Start BSS failed, delete the interface */ + hdd_close_ndi(adapter); + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +static int hdd_delete_ndi_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = (struct hdd_context *)wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + hdd_enter_dev(dev); + + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->mac_addr.bytes); + hdd_stop_adapter(hdd_ctx, adapter); + hdd_deinit_adapter(hdd_ctx, adapter, true); + + hdd_exit(); + + return 0; +} +#else +static int hdd_delete_ndi_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int ret; + + ret = __wlan_hdd_del_virtual_intf(wiphy, wdev); + + if (ret) + hdd_err("NDI delete request failed"); + else + hdd_err("NDI delete request successfully issued"); + + return ret; +} +#endif + +int hdd_ndi_delete(uint8_t vdev_id, const char *iface_name, + uint16_t transaction_id) +{ + int ret; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_objmgr_vdev *vdev; + + if (!hdd_ctx) + return -EINVAL; + + /* check if adapter by vdev_id is valid NDI */ + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info || !WLAN_HDD_IS_NDI(link_info->adapter)) { + hdd_err("NAN data interface %s is not available", iface_name); + return -EINVAL; + } + + adapter = link_info->adapter; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_NAN_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + os_if_nan_set_ndp_delete_transaction_id(vdev, transaction_id); + os_if_nan_set_ndi_state(vdev, NAN_DATA_NDI_DELETING_STATE); + hdd_cstats_log_ndi_delete_req_evt(vdev, transaction_id); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); + + /* Delete the interface */ + adapter->is_virtual_iface = true; + ret = hdd_delete_ndi_intf(hdd_ctx->wiphy, &adapter->wdev); + + return ret; +} + +#define MAX_VDEV_NDP_PARAMS 2 +/* params being sent: + * wmi_vdev_param_ndp_inactivity_timeout + * wmi_vdev_param_ndp_keepalive_timeout + */ + +void +hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id, + struct nan_datapath_inf_create_rsp *ndi_rsp) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + struct csr_roam_info *roam_info; + uint16_t ndp_inactivity_timeout = 0; + uint16_t ndp_keep_alive_period; + struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BCAST_INIT; + struct wlan_objmgr_vdev *vdev; + struct dev_set_param setparam[MAX_VDEV_NDP_PARAMS] = {}; + uint8_t index = 0; + QDF_STATUS status; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + adapter = link_info->adapter; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + + if (ndi_rsp->status == QDF_STATUS_SUCCESS) { + hdd_alert("NDI interface successfully created"); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_NAN_ID); + if (!vdev) { + qdf_mem_free(roam_info); + hdd_err("vdev is NULL"); + return; + } + + os_if_nan_set_ndp_create_transaction_id(vdev, 0); + os_if_nan_set_ndi_state(vdev, NAN_DATA_NDI_CREATED_STATE); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); + + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + if (QDF_IS_STATUS_ERROR(cfg_nan_get_ndp_inactivity_timeout( + hdd_ctx->psoc, &ndp_inactivity_timeout))) + hdd_err("Failed to fetch inactivity timeout value"); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ndp_inactivity_timeout, + ndp_inactivity_timeout, index++, + MAX_VDEV_NDP_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_vdev_param_ndp_inactivity_timeout"); + goto error; + } + + if (QDF_IS_STATUS_SUCCESS(cfg_nan_get_ndp_keepalive_period( + hdd_ctx->psoc, + &ndp_keep_alive_period))) { + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ndp_keepalive_timeout, + ndp_keep_alive_period, index++, + MAX_VDEV_NDP_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_vdev_param_ndp_keepalive_timeout"); + goto error; + } + } + status = sme_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + link_info->vdev_id, + setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to send vdev set params"); + } else { + hdd_alert("NDI interface creation failed with reason %d", + ndi_rsp->reason /* create_reason */); + } + + hdd_cstats_log_ndi_create_resp_evt(link_info, ndi_rsp); + + hdd_save_peer(sta_ctx, &bc_mac_addr); + qdf_copy_macaddr(&roam_info->bssid, &bc_mac_addr); + hdd_roam_register_sta(link_info, + &roam_info->bssid, + roam_info->fAuthRequired); + +error: + qdf_mem_free(roam_info); +} + +void hdd_ndi_close(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + link_info->adapter->is_virtual_iface = true; + hdd_close_ndi(link_info->adapter); +} + +void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + struct qdf_mac_addr bc_mac_addr = QDF_MAC_ADDR_BCAST_INIT; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + adapter = link_info->adapter; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + hdd_delete_peer(sta_ctx, &bc_mac_addr); + + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + /* + * For NAN Data interface, the close session results in the final + * indication to the userspace + */ + if (adapter->device_mode == QDF_NDI_MODE) + hdd_ndp_session_end_handler(adapter); + + complete(&adapter->disconnect_comp_var); +} + +void hdd_ndp_session_end_handler(struct hdd_adapter *adapter) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_NAN_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + os_if_nan_ndi_session_end(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); +} + +/** + * hdd_send_obss_scan_req() - send OBSS scan request to SME layer. + * @hdd_ctx: hdd context pointer + * @val: true if new NDP peer is added and false when last peer NDP is deleted. + * + * Return: void + */ +static void hdd_send_obss_scan_req(struct hdd_context *hdd_ctx, bool val) +{ + QDF_STATUS status; + uint32_t sta_vdev_id = 0; + + status = hdd_get_first_connected_sta_vdev_id(hdd_ctx, &sta_vdev_id); + + if (QDF_IS_STATUS_SUCCESS(status)) { + hdd_debug("reconfig OBSS scan param: %d", val); + sme_reconfig_obss_scan_param(hdd_ctx->mac_handle, sta_vdev_id, + val); + } else { + hdd_debug("Connected STA not found"); + } +} + +int hdd_ndp_new_peer_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + bool first_peer) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + struct csr_roam_info *roam_info; + struct wlan_objmgr_vdev *vdev; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return -EINVAL; + } + + adapter = link_info->adapter; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + /* save peer in ndp ctx */ + if (!hdd_save_peer(sta_ctx, peer_mac_addr)) { + hdd_err("Ndp peer table full. cannot save new peer"); + return -EPERM; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return -ENOMEM; + qdf_copy_macaddr(&roam_info->bssid, peer_mac_addr); + + /* this function is called for each new peer */ + hdd_roam_register_sta(link_info, &roam_info->bssid, + roam_info->fAuthRequired); + + if (!first_peer) + goto mem_free; + + hdd_debug("Set ctx connection state to connected"); + /* Disable LRO/GRO for NDI Mode */ + if (ucfg_dp_is_ol_enabled(hdd_ctx->psoc) && + !NAN_CONCURRENCY_SUPPORTED(hdd_ctx->psoc)) { + hdd_debug("Disable LRO/GRO in NDI Mode"); + hdd_disable_rx_ol_in_concurrency(true); + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_bus_bw_compute_prev_txrx_stats(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + ucfg_dp_bus_bw_compute_timer_start(hdd_ctx->psoc); + sta_ctx->conn_info.conn_state = eConnectionState_NdiConnected; + hdd_wmm_connect(adapter, roam_info, eCSR_BSS_TYPE_NDI); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + /* + * This is called only for first peer. So, no.of NDP sessions + * are always 1 + */ + if (!NDI_CONCURRENCY_SUPPORTED(hdd_ctx->psoc)) + hdd_indicate_active_ndp_cnt(hdd_ctx->psoc, vdev_id, 1); + hdd_send_obss_scan_req(hdd_ctx, true); + +mem_free: + qdf_mem_free(roam_info); + return 0; +} + +void hdd_cleanup_ndi(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + struct wlan_objmgr_vdev *vdev; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (sta_ctx->conn_info.conn_state != eConnectionState_NdiConnected) { + hdd_debug("NDI has no NDPs"); + return; + } + sta_ctx->conn_info.conn_state = eConnectionState_NdiDisconnected; + hdd_conn_set_connection_state(adapter, + eConnectionState_NdiDisconnected); + hdd_debug("Stop netif tx queues."); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (vdev) { + ucfg_dp_bus_bw_compute_reset_prev_txrx_stats(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + ucfg_dp_bus_bw_compute_timer_try_stop(hdd_ctx->psoc); + if ((ucfg_dp_is_ol_enabled(hdd_ctx->psoc) && + !NAN_CONCURRENCY_SUPPORTED(hdd_ctx->psoc)) && + ((policy_mgr_get_connection_count(hdd_ctx->psoc) == 0) || + ((policy_mgr_get_connection_count(hdd_ctx->psoc) == 1) && + (policy_mgr_mode_specific_connection_count( + hdd_ctx->psoc, + PM_STA_MODE, + NULL) == 1)))) { + hdd_debug("Enable LRO/GRO"); + ucfg_dp_rx_handle_concurrency(hdd_ctx->psoc, false); + } +} + +void hdd_ndp_peer_departed_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, bool last_peer) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + adapter = link_info->adapter; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + hdd_delete_peer(sta_ctx, peer_mac_addr); + + ucfg_nan_clear_peer_mc_list(hdd_ctx->psoc, link_info->vdev, + peer_mac_addr); + + if (last_peer) { + hdd_debug("No more ndp peers."); + hdd_cleanup_ndi(link_info); + qdf_event_set(&adapter->peer_cleanup_done); + /* + * This is called only for last peer. So, no.of NDP sessions + * are always 0 + */ + if (!NDI_CONCURRENCY_SUPPORTED(hdd_ctx->psoc)) + hdd_indicate_active_ndp_cnt(hdd_ctx->psoc, vdev_id, 0); + hdd_send_obss_scan_req(hdd_ctx, false); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h new file mode 100644 index 0000000000..1ae8aa2966 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nan_datapath.h @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_nan_datapath.h + * + * WLAN Host Device Driver nan datapath API specification + */ +#ifndef __WLAN_HDD_NAN_DATAPATH_H +#define __WLAN_HDD_NAN_DATAPATH_H + +struct hdd_context; +struct hdd_config; +struct hdd_adapter; +struct wireless_dev; + +/* NAN Social frequencies */ +#define NAN_SOCIAL_FREQ_2_4GHZ 2437 +#define NAN_SOCIAL_FREQ_5GHZ_LOWER_BAND 5220 +#define NAN_SOCIAL_FREQ_5GHZ_UPPER_BAND 5745 + +#define NDP_BROADCAST_STAID (0) + +#ifdef WLAN_FEATURE_NAN + +#define WLAN_HDD_IS_NDI(adapter) ((adapter)->device_mode == QDF_NDI_MODE) + +#define WLAN_HDD_IS_NDI_CONNECTED(adapter) ( \ + eConnectionState_NdiConnected ==\ + (adapter)->session.station.conn_info.conn_state) + +void hdd_nan_datapath_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg); + +/** + * hdd_ndp_event_handler() - API to handle NDP create/delete events + * @link_info: Link info pointer in HDD adapter. + * @roam_info: Roam data + * @roam_status: roam status + * @roam_result: Result of roam + * + * The function performs operations based on NDP create/delete response. + * + * Return: void + */ +void hdd_ndp_event_handler(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); + +int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len); +int hdd_init_nan_data_mode(struct hdd_adapter *adapter); +void hdd_ndp_session_end_handler(struct hdd_adapter *adapter); + +/** + * hdd_cleanup_ndi() - Cleanup NDI state/resources + * @link_info: Link info pointer in HDD adapter + * + * Cleanup NDI state/resources allocated when NDPs are created on that NDI. + * + * Return: None + */ + +void hdd_cleanup_ndi(struct wlan_hdd_link_info *link_info); + +/** + * hdd_ndi_start() - Start NDI adapter and create NDI vdev + * @iface_name: NDI interface name + * @transaction_id: Transaction id given by framework to start the NDI. + * Framework expects this in the immediate response when + * the NDI is created by it. + * + * Create NDI move interface and vdev. + * + * Return: 0 upon success + */ +int hdd_ndi_start(const char *iface_name, uint16_t transaction_id); + +enum nan_datapath_state; +struct nan_datapath_inf_create_rsp; + +/** + * hdd_ndi_open() - Open NDI interface + * @iface_name: NDI interface name + * @is_add_virtual_iface: is this interface getting created through add virtual + * interface + * + * Return: 0 on success, error code on failure + */ +int hdd_ndi_open(const char *iface_name, bool is_add_virtual_iface); + +/** + * hdd_ndi_delete() - Delete NDI interface + * @vdev_id: vdev id of the NDI interface + * @iface_name: NDI interface name + * @transaction_id: Transaction id + * + * Return: 0 on success, error code on failure + */ +int hdd_ndi_delete(uint8_t vdev_id, const char *iface_name, + uint16_t transaction_id); + +/** + * hdd_ndi_close() - Close NDI interface + * @vdev_id: vdev id of the NDI interface + * + * Return: None + */ +void hdd_ndi_close(uint8_t vdev_id); + +/** + * hdd_ndi_drv_ndi_create_rsp_handler() - ndi create response handler + * @vdev_id: vdev id of the NDI interface + * @ndi_rsp: NDI create response + * + * Return: None + */ +void hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id, + struct nan_datapath_inf_create_rsp *ndi_rsp); + +/** + * hdd_ndi_drv_ndi_delete_rsp_handler() - ndi delete response handler + * @vdev_id: vdev id of the NDI interface + * + * Return: None + */ +void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id); + +/** + * hdd_ndp_new_peer_handler() - NDP new peer indication handler + * @vdev_id: vdev id + * @sta_id: STA ID + * @peer_mac_addr: MAC address of the peer + * @first_peer: Indicates if it is first peer + * + * Return: 0 on success, error code on failure + */ +int hdd_ndp_new_peer_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + bool first_peer); + +/** + * hdd_ndp_peer_departed_handler() - Handle NDP peer departed indication + * @vdev_id: vdev id + * @sta_id: STA ID + * @peer_mac_addr: MAC address of the peer + * @last_peer: Indicates if it is last peer + * + * Return: None + */ +void hdd_ndp_peer_departed_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + bool last_peer); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +/** + * hdd_ndi_set_mode() - set the adapter mode to NDI + * @iface_name: NDI interface name + * + * The adapter mode is STA while creating virtual interface. + * mode is set to NDI while creating NDI. + * + * Return: 0 upon success + */ +int hdd_ndi_set_mode(const char *iface_name); +#else +static inline int hdd_ndi_set_mode(const char *iface_name) +{ + return 0; +} +#endif /* LINUX_VERSION_CODE */ + +#else +#define WLAN_HDD_IS_NDI(adapter) (false) +#define WLAN_HDD_IS_NDI_CONNECTED(adapter) (false) + +static inline void hdd_nan_datapath_target_config(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ +} + +static inline void hdd_ndp_event_handler(struct wlan_hdd_link_info *link_info, + struct csr_roam_info *roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ +} + +static inline int wlan_hdd_cfg80211_process_ndp_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + return 0; +} +static inline int hdd_init_nan_data_mode(struct hdd_adapter *adapter) +{ + return 0; +} +static inline void hdd_ndp_session_end_handler(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_cleanup_ndi(struct wlan_hdd_link_info *link_info) +{ +} + +static inline int hdd_ndi_start(const char *iface_name, uint16_t transaction_id) +{ + return 0; +} + +static inline int hdd_ndi_set_mode(const char *iface_name) +{ + return 0; +} + +enum nan_datapath_state; +struct nan_datapath_inf_create_rsp; + +static inline int +hdd_ndi_open(const char *iface_name, bool is_add_virtual_iface) +{ + return 0; +} + +static inline int +hdd_ndi_delete(uint8_t vdev_id, const char *iface_name, uint16_t transaction_id) +{ + return 0; +} + +static inline void hdd_ndi_close(uint8_t vdev_id) +{ +} + +static inline void +hdd_ndi_drv_ndi_create_rsp_handler(uint8_t vdev_id, + struct nan_datapath_inf_create_rsp *ndi_rsp) +{ +} + +static inline void hdd_ndi_drv_ndi_delete_rsp_handler(uint8_t vdev_id) +{ +} + +static inline int hdd_ndp_new_peer_handler(uint8_t vdev_id, uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + bool first_peer) +{ + return 0; +} + +static inline void hdd_ndp_peer_departed_handler(uint8_t vdev_id, + uint16_t sta_id, + struct qdf_mac_addr *peer_mac_addr, + bool last_peer) +{ +} +#endif /* WLAN_FEATURE_NAN */ + +#endif /* __WLAN_HDD_NAN_DATAPATH_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c new file mode 100644 index 0000000000..9840d4b8f3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_napi.c @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_napi.c + * + * WLAN HDD NAPI interface implementation + */ +#include /* get_cpu */ + +#include "wlan_hdd_napi.h" +#include "cds_api.h" /* cds_get_context */ +#include "hif.h" /* hif_map_service...*/ +#include "wlan_hdd_main.h" /* hdd_err/warn... */ +#include "qdf_types.h" /* QDF_MODULE_ID_... */ +#include "ce_api.h" +#include "wlan_dp_ucfg_api.h" + +/* guaranteed to be initialized to zero/NULL by the standard */ +static struct qca_napi_data *hdd_napi_ctx; + +/** + * hdd_napi_get_all() - return the whole NAPI structure from HIF + * + * Gets to the data structure common to all NAPI instances. + * + * Return: + * NULL : probably NAPI not initialized yet. + * : the address of the whole NAPI structure + */ +struct qca_napi_data *hdd_napi_get_all(void) +{ + struct qca_napi_data *rp = NULL; + struct hif_opaque_softc *hif; + + NAPI_DEBUG("-->"); + + hif = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(!hif)) + QDF_ASSERT(hif); /* WARN */ + else + rp = hif_napi_get_all(hif); + + NAPI_DEBUG("<-- [addr=%pK]", rp); + return rp; +} + +/** + * hdd_napi_get_map() - get a copy of napi pipe map + * + * Return: + * uint32_t : copy of pipe map + */ +static uint32_t hdd_napi_get_map(void) +{ + uint32_t map = 0; + + NAPI_DEBUG("-->"); + /* cache once, use forever */ + if (!hdd_napi_ctx) + hdd_napi_ctx = hdd_napi_get_all(); + if (hdd_napi_ctx) + map = hdd_napi_ctx->ce_map; + + NAPI_DEBUG("<-- [map=0x%08x]", map); + return map; +} + +/** + * hdd_napi_create() - creates the NAPI structures for a given netdev + * + * Creates NAPI instances. This function is called + * unconditionally during initialization. It creates + * napi structures through the proper HTC/HIF calls. + * The structures are disabled on creation. + * + * Return: + * single-queue: <0: err, >0=id, 0 (should not happen) + * multi-queue: bitmap of created instances (0: none) + */ +int hdd_napi_create(void) +{ + struct hif_opaque_softc *hif_ctx; + int rc = 0; + struct hdd_context *hdd_ctx; + uint8_t feature_flags = 0; + struct qca_napi_data *napid = hdd_napi_get_all(); + + NAPI_DEBUG("-->"); + + if (!napid) { + hdd_err("unable to retrieve napi structure"); + rc = -EFAULT; + goto exit; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(!hif_ctx)) { + QDF_ASSERT(hif_ctx); + rc = -EFAULT; + goto exit; + } + + feature_flags = QCA_NAPI_FEATURE_CPU_CORRECTION | + QCA_NAPI_FEATURE_IRQ_BLACKLISTING | + QCA_NAPI_FEATURE_CORE_CTL_BOOST; + + rc = hif_napi_create(hif_ctx, hdd_napi_poll, + QCA_NAPI_BUDGET, + QCA_NAPI_DEF_SCALE, + feature_flags); + if (rc < 0) { + hdd_err("ERR(%d) creating NAPI instances", + rc); + goto exit; + } + + hdd_debug("napi instances were created. Map=0x%x", rc); + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (unlikely(!hdd_ctx)) { + QDF_ASSERT(0); + rc = -EFAULT; + goto exit; + } + + rc = hdd_napi_event(NAPI_EVT_INI_FILE, + (void *)ucfg_dp_get_napi_enabled(hdd_ctx->psoc)); + napid->user_cpu_affin_mask = + hdd_ctx->config->napi_cpu_affinity_mask; + + exit: + NAPI_DEBUG("<-- [rc=%d]", rc); + return rc; +} + +/** + * hdd_napi_destroy() - destroys the NAPI structures for a given netdev + * @force: if set, will force-disable the instance before _del'ing + * + * Destroy NAPI instances. This function is called + * unconditionally during module removal. It destroy + * napi structures through the proper HTC/HIF calls. + * + * Return: + * number of NAPI instances destroyed + */ +int hdd_napi_destroy(int force) +{ + int rc = 0; + int i; + uint32_t hdd_napi_map = hdd_napi_get_map(); + + NAPI_DEBUG("--> (force=%d)", force); + if (hdd_napi_map) { + struct hif_opaque_softc *hif_ctx; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(!hif_ctx)) + QDF_ASSERT(hif_ctx); + else + for (i = 0; i < CE_COUNT_MAX; i++) + if (hdd_napi_map & (0x01 << i)) { + if (0 <= hif_napi_destroy( + hif_ctx, + NAPI_PIPE2ID(i), force)) { + rc++; + hdd_napi_map &= ~(0x01 << i); + } else + hdd_err("cannot destroy napi %d: (pipe:%d), f=%d\n", + i, + NAPI_PIPE2ID(i), force); + } + } else { + struct hif_opaque_softc *hif_ctx; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (unlikely(!hif_ctx)) + QDF_ASSERT(hif_ctx); + else + rc = hif_napi_cpu_deinit(hif_ctx); + } + + /* if all instances are removed, it is likely that hif_context has been + * removed as well, so the cached value of the napi context also needs + * to be removed + */ + if (force) + QDF_ASSERT(hdd_napi_map == 0); + if (0 == hdd_napi_map) + hdd_napi_ctx = NULL; + + NAPI_DEBUG("<-- [rc=%d]", rc); + return rc; +} + +/** + * hdd_napi_enabled() - checks if NAPI is enabled (for a given id) + * @id: the id of the NAPI to check (any= -1) + * + * Return: + * int: 0 = false (NOT enabled) + * !0 = true (enabbled) + */ +int hdd_napi_enabled(int id) +{ + struct hif_opaque_softc *hif; + int rc = 0; /* NOT enabled */ + + hif = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(!hif)) + QDF_ASSERT(hif); /* WARN_ON; rc = 0 */ + else if (-1 == id) + rc = hif_napi_enabled(hif, id); + else + rc = hif_napi_enabled(hif, NAPI_ID2PIPE(id)); + return rc; +} + +/** + * hdd_napi_event() - relay the event detected by HDD to HIF NAPI event handler + * @event: event code + * @data : event-specific auxiliary data + * + * See function documentation in hif_napi.c::hif_napi_event for list of events + * and how each of them is handled. + * + * Return: + * < 0: error code + * = 0: event handled successfully + */ +int hdd_napi_event(enum qca_napi_event event, void *data) +{ + int rc = -EFAULT; /* assume err */ + struct hif_opaque_softc *hif; + + NAPI_DEBUG("-->(event=%d, aux=%pK)", event, data); + + hif = cds_get_context(QDF_MODULE_ID_HIF); + if (unlikely(!hif)) + QDF_ASSERT(hif); + else + rc = hif_napi_event(hif, event, data); + + NAPI_DEBUG("<--[rc=%d]", rc); + return rc; +} + +#if defined HELIUMPLUS && defined MSM_PLATFORM + +static int napi_tput_policy_delay; + +/** + * hdd_napi_perfd_cpufreq() - set/reset min CPU freq for cores + * @req_state: high/low + * + * Send a message to cnss-daemon through netlink. cnss-daemon, + * in turn, sends a message to perf-daemon. + * If freq > 0, this is a set request. It sets the min frequency of the + * cores of the specified cluster to provided freq value (in KHz). + * If freq == 0, then the freq lock is removed (and frequency returns to + * system default). + * + * Semantical Alert: + * There can be at most one lock active at a time. Each "set" request must + * be followed by a "reset" request. Perfd behaviour is undefined otherwise. + * + * Return: == 0: netlink message sent to cnss-daemon + * < 0: failure to send the message + */ +static int hdd_napi_perfd_cpufreq(enum qca_napi_tput_state req_state) +{ + int rc = 0; + struct wlan_core_minfreq req; + struct hdd_context *hdd_ctx; + + NAPI_DEBUG("-> (%d)", req_state); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (unlikely(!hdd_ctx)) { + rc = -EFAULT; + goto hnpc_ret; + } + + switch (req_state) { + case QCA_NAPI_TPUT_LO: + req.magic = WLAN_CORE_MINFREQ_MAGIC; + req.reserved = 0; /* unused */ + req.coremask = 0; /* not valid */ + req.freq = 0; /* reset */ + break; + case QCA_NAPI_TPUT_HI: + req.magic = WLAN_CORE_MINFREQ_MAGIC; + req.reserved = 0; /* unused */ + req.coremask = 0x0f0; /* perf cluster */ + req.freq = 700; /* KHz */ + break; + default: + hdd_err("invalid req_state (%d)", req_state); + rc = -EINVAL; + goto hnpc_ret; + } /* switch */ + + NAPI_DEBUG("CPU min freq to %d", + (req.freq == 0)?"Resetting":"Setting", req.freq); + /* the following service function returns void */ + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_CORE_MINFREQ, + &req, sizeof(struct wlan_core_minfreq)); +hnpc_ret: + NAPI_DEBUG("<--[rc=%d]", rc); + return rc; +} + +/** + * hdd_napi_apply_throughput_policy() - implement the throughput action policy + * @hddctx: HDD context + * @tx_packets: number of tx packets in the last interval + * @rx_packets: number of rx packets in the last interval + * + * Called by hdd_bus_bw_compute_cb, checks the number of packets in the last + * interval, and determines the desired napi throughput state (HI/LO). If + * the desired state is different from the current, then it invokes the + * event handler to switch to the desired state. + * + * The policy implementation is limited to this function and + * The current policy is: determine the NAPI mode based on the condition: + * (total number of packets > medium threshold) + * - tx packets are included because: + * a- tx-completions arrive at one of the rx CEs + * b- in TCP, a lof of TX implies ~(tx/2) rx (ACKs) + * c- so that we can use the same normalized criteria in ini file + * - medium-threshold (default: 500 packets / 10 ms), because + * we would like to be more reactive. + * + * Return: 0 : no action taken, or action return code + * !0: error, or action error code + */ +int hdd_napi_apply_throughput_policy(struct hdd_context *hddctx, + uint64_t tx_packets, + uint64_t rx_packets) +{ + int rc = 0; + uint64_t packets = tx_packets + rx_packets; + enum qca_napi_tput_state req_state; + struct qca_napi_data *napid = hdd_napi_get_all(); + int enabled; + + NAPI_DEBUG("-->(tx=%lld, rx=%lld)", tx_packets, rx_packets); + + if (unlikely(napi_tput_policy_delay < 0)) + napi_tput_policy_delay = 0; + if (napi_tput_policy_delay > 0) { + NAPI_DEBUG("delaying policy; delay-count=%d", + napi_tput_policy_delay); + napi_tput_policy_delay--; + + /* make sure the next timer call calls us */ + ucfg_dp_set_current_throughput_level(hddctx->psoc, -1); + + return rc; + } + + if (!napid) { + hdd_err("ERR: napid NULL"); + return rc; + } + + enabled = hdd_napi_enabled(HDD_NAPI_ANY); + if (!enabled) { + hdd_err("ERR: napi not enabled"); + return rc; + } + + if (packets > ucfg_dp_get_bus_bw_high_threshold(hddctx->psoc)) + req_state = QCA_NAPI_TPUT_HI; + else + req_state = QCA_NAPI_TPUT_LO; + + if (req_state != napid->napi_mode) { + /* [re]set the floor frequency of high cluster */ + rc = hdd_napi_perfd_cpufreq(req_state); + /* denylist/boost_mode on/off */ + rc = hdd_napi_event(NAPI_EVT_TPUT_STATE, (void *)req_state); + } + return rc; +} + +/** + * hdd_napi_serialize() - serialize all NAPI activities + * @is_on: 1="serialize" or 0="de-serialize" + * + * Start/stop "serial-NAPI-mode". + * NAPI serial mode describes a state where all NAPI operations are forced to be + * run serially. This is achieved by ensuring all NAPI instances are run on the + * same CPU, so forced to be serial. + * NAPI life-cycle: + * - Interrupt is received for a given CE. + * - In the ISR, the interrupt is masked and corresponding NAPI instance + * is scheduled, to be run as a bottom-half. + * - Bottom-half starts with a poll call (by the net_rx softirq). There may be + * one of more subsequent calls until the work is complete. + * - Once the work is complete, the poll handler enables the interrupt and + * the cycle re-starts. + * + * Return: <0: error-code (operation failed) + * =0: success + * >0: status (not used) + */ +int hdd_napi_serialize(int is_on) +{ + int rc; + struct hdd_context *hdd_ctx; +#define POLICY_DELAY_FACTOR (1) + rc = hif_napi_serialize(cds_get_context(QDF_MODULE_ID_HIF), is_on); + if ((rc == 0) && (is_on == 0)) { + /* apply throughput policy after one timeout */ + napi_tput_policy_delay = POLICY_DELAY_FACTOR; + + /* make sure that bus_bandwidth trigger is executed */ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (hdd_ctx) + ucfg_dp_set_current_throughput_level(hdd_ctx->psoc, + -1); + + } + return rc; +} +#endif /* HELIUMPLUS && MSM_PLATFORM */ + +/** + * hdd_napi_poll() - NAPI poll function + * @napi : pointer to NAPI struct + * @budget: the pre-declared budget + * + * Implementation of poll function. This function is called + * by kernel during softirq processing. + * + * NOTE FOR THE MAINTAINER: + * Make sure this is very close to the ce_tasklet code. + * + * Return: + * int: the amount of work done ( <= budget ) + */ +int hdd_napi_poll(struct napi_struct *napi, int budget) +{ + return hif_napi_poll(cds_get_context(QDF_MODULE_ID_HIF), napi, budget); +} + +/** + * hdd_display_napi_stats() - print NAPI stats + * + * Return: == 0: success; !=0: failure + */ +int hdd_display_napi_stats(void) +{ + int i, j, k, n; /* NAPI, CPU, bucket indices, bucket buf write index*/ + int max; + struct qca_napi_data *napid; + struct qca_napi_info *napii; + struct qca_napi_stat *napis; + /* + * Expecting each NAPI bucket item to need at max 5 numerals + space for + * formatting. For example "10000 " Thus the array needs to have + * (5 + 1) * QCA_NAPI_NUM_BUCKETS bytes of space. Leaving one space at + * the end of the "buf" array for end of string char. + */ + char buf[6 * QCA_NAPI_NUM_BUCKETS + 1] = {'\0'}; + + napid = hdd_napi_get_all(); + if (!napid) { + hdd_err("unable to retrieve napi structure"); + return -EFAULT; + } + hdd_nofl_info("[NAPI %u][BL %d]: scheds polls comps done t-lim p-lim corr max_time napi-buckets(%d)", + napid->napi_mode, + hif_napi_cpu_denylist(napid, DENYLIST_QUERY), + QCA_NAPI_NUM_BUCKETS); + + for (i = 0; i < CE_COUNT_MAX; i++) + if (napid->ce_map & (0x01 << i)) { + napii = napid->napis[i]; + if (!napii) + continue; + + for (j = 0; j < num_possible_cpus(); j++) { + napis = &(napii->stats[j]); + n = 0; + max = sizeof(buf); + for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) { + n += scnprintf( + buf + n, max - n, + " %d", + napis->napi_budget_uses[k]); + } + + if (napis->napi_schedules != 0) + hdd_nofl_info("NAPI[%2d]CPU[%d]: %7d %7d %7d %7d %5d %5d %5d %9llu %s", + i, j, + napis->napi_schedules, + napis->napi_polls, + napis->napi_completes, + napis->napi_workdone, + napis->time_limit_reached, + napis-> + rxpkt_thresh_reached, + napis->cpu_corrected, + napis->napi_max_poll_time, + buf); + } + } + + hif_napi_stats(napid); + return 0; +} + +/** + * hdd_clear_napi_stats() - clear NAPI stats + * + * Return: == 0: success; !=0: failure + */ +int hdd_clear_napi_stats(void) +{ + int i, j; + struct qca_napi_data *napid; + struct qca_napi_info *napii; + struct qca_napi_stat *napis; + + napid = hdd_napi_get_all(); + if (!napid) { + hdd_err("unable to retrieve napi structure"); + return -EFAULT; + } + + for (i = 0; i < CE_COUNT_MAX; i++) + if (napid->ce_map & (0x01 << i)) { + napii = napid->napis[i]; + for (j = 0; j < NR_CPUS; j++) { + napis = &(napii->stats[j]); + qdf_mem_zero(napis, + sizeof(struct qca_napi_stat)); + } + } + + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.c new file mode 100644 index 0000000000..91a4d566d3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nud event tracking main function definitions + */ + +#include "osif_sync.h" +#include "wlan_hdd_main.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_dlm_ucfg_api.h" +#include "hdd_dp_cfg.h" +#include +#include "wlan_cm_roam_ucfg_api.h" +#include "wlan_hdd_nud_tracking.h" + +static void +hdd_handle_nud_fail_sta(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct reject_ap_info ap_info; + struct hdd_station_ctx *sta_ctx; + struct qdf_mac_addr bssid; + + if (hdd_is_roaming_in_progress(hdd_ctx)) { + hdd_debug("Roaming already in progress, cannot trigger roam."); + return; + } + + hdd_debug("nud fail detected, try roaming to better BSSID, vdev id: %d", + adapter->deflink->vdev_id); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + ap_info.bssid = sta_ctx->conn_info.bssid; + ap_info.reject_ap_type = DRIVER_AVOID_TYPE; + ap_info.reject_reason = REASON_NUD_FAILURE; + ap_info.source = ADDED_BY_DRIVER; + ucfg_dlm_add_bssid_to_reject_list(hdd_ctx->pdev, &ap_info); + + if (roaming_offload_enabled(hdd_ctx)) { + qdf_zero_macaddr(&bssid); + ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, + adapter->deflink->vdev_id, + &bssid, 0, CM_ROAMING_NUD_FAILURE); + } +} + +static void +hdd_handle_nud_fail_non_sta(struct wlan_hdd_link_info *link_info) +{ + wlan_hdd_cm_issue_disconnect(link_info, + REASON_GATEWAY_REACHABILITY_FAILURE, + false); +} + +/** + * __hdd_nud_failure_work() - work for nud event + * @adapter: HDD adapter + * + * Return: None + */ +static void +__hdd_nud_failure_work(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + int status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + hdd_enter(); + + status = hdd_validate_adapter(adapter); + if (status) + return; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_debug("Not in Connected State"); + return; + } + + if (hdd_ctx->hdd_wlan_suspended) { + hdd_debug("wlan is suspended, ignore NUD failure event"); + return; + } + + if (soc && ucfg_dp_nud_fail_data_stall_evt_enabled()) { + hdd_dp_err("Data stall due to NUD failure"); + cdp_post_data_stall_event + (soc, + DATA_STALL_LOG_INDICATOR_HOST_DRIVER, + DATA_STALL_LOG_NUD_FAILURE, + OL_TXRX_PDEV_ID, 0XFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } + + if (adapter->device_mode == QDF_STA_MODE && + ucfg_dp_is_roam_after_nud_enabled(hdd_ctx->psoc)) { + hdd_handle_nud_fail_sta(hdd_ctx, adapter); + return; + } + hdd_handle_nud_fail_non_sta(adapter->deflink); + + hdd_exit(); +} + +void hdd_nud_failure_work(hdd_cb_handle context, qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + struct osif_vdev_sync *vdev_sync; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync)) + return; + + __hdd_nud_failure_work(adapter); + + osif_vdev_sync_op_stop(vdev_sync); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.h new file mode 100644 index 0000000000..731ff42cae --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_nud_tracking.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains nud event tracking function declarations + */ + +#ifndef _WLAN_NUD_TRACKING_H_ +#define _WLAN_NUD_TRACKING_H_ + +#ifdef WLAN_NUD_TRACKING + +/** + * hdd_nud_failure_work() - Handle NUD failuire work + * @context: HDD context pointer + * @netdev: netdev + * + * Return: None + */ +void hdd_nud_failure_work(hdd_cb_handle context, qdf_netdev_t netdev); +#else +static inline void +hdd_nud_failure_work(hdd_cb_handle context, qdf_netdev_t netdev) +{ +} +#endif /* WLAN_NUD_TRACKING */ +#endif /* end of _WLAN_NUD_TRACKING_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.c new file mode 100644 index 0000000000..3542d06116 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: HDD object manager API source file to create/destroy PSOC, + * PDEV, VDEV and PEER objects. + */ + +#include +#include +#include +#include +#include + +static void hdd_init_pdev_os_priv(struct hdd_context *hdd_ctx, + struct pdev_osif_priv *os_priv) +{ + /* Initialize the OS private structure*/ + os_priv->wiphy = hdd_ctx->wiphy; + os_priv->legacy_osif_priv = hdd_ctx; + wlan_cfg80211_scan_priv_init(hdd_ctx->pdev); + os_if_spectral_netlink_init(hdd_ctx->pdev); +} + +static void hdd_deinit_pdev_os_priv(struct wlan_objmgr_pdev *pdev) +{ + os_if_spectral_netlink_deinit(pdev); + wlan_cfg80211_scan_priv_deinit(pdev); +} +static void hdd_init_psoc_qdf_ctx(struct wlan_objmgr_psoc *psoc) +{ + qdf_device_t qdf_ctx; + + qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_ctx) + return; + + wlan_psoc_set_qdf_dev(psoc, qdf_ctx); +} + +int hdd_objmgr_create_and_store_psoc(struct hdd_context *hdd_ctx, + uint8_t psoc_id) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_objmgr_psoc_obj_create(psoc_id, WLAN_DEV_OL); + if (!psoc) + return -ENOMEM; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to acquire psoc ref; status:%d", status); + QDF_BUG(false); + goto psoc_destroy; + } + + hdd_init_psoc_qdf_ctx(psoc); + hdd_ctx->psoc = psoc; + + return 0; + +psoc_destroy: + wlan_objmgr_psoc_obj_delete(psoc); + + return qdf_status_to_os_return(status); +} + +int hdd_objmgr_release_and_destroy_psoc(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + + hdd_ctx->psoc = NULL; + + QDF_BUG(psoc); + if (!psoc) + return -EINVAL; + + wlan_objmgr_print_ref_all_objects_per_psoc(psoc); + + status = wlan_objmgr_psoc_obj_delete(psoc); + wlan_objmgr_psoc_release_ref(psoc, WLAN_HDD_ID_OBJ_MGR); + + return qdf_status_to_os_return(status); +} + +void hdd_objmgr_update_tgt_max_vdev_psoc(struct hdd_context *hdd_ctx, + uint8_t max_vdev) +{ + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + + if (!psoc) { + hdd_err("Psoc NULL"); + return; + } + + wlan_psoc_set_max_vdev_count(psoc, max_vdev); +} + +static int hdd_check_internal_netdev_state(struct net_device *netdev) +{ + struct hdd_adapter *adapter; + + if (!netdev) + return false; + + adapter = netdev_priv(netdev); + if (!adapter) + return false; + + hdd_debug("netdev name %s, netdev flags 0x%x, event_flags %lu", + netdev->name, netdev->flags, adapter->event_flags); + if (test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags) && + (netdev->flags & IFF_UP)) + return true; + else + return false; +} + +int hdd_objmgr_create_and_store_pdev(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct wlan_objmgr_pdev *pdev; + struct pdev_osif_priv *priv; + struct wlan_psoc_host_hal_reg_capabilities_ext *reg_cap_ptr; + uint32_t low_2ghz_chan = 0; + uint32_t high_2ghz_chan = 0; + uint32_t low_5ghz_chan = 0; + uint32_t high_5ghz_chan = 0; + + if (!psoc) { + hdd_err("Psoc NULL"); + return -EINVAL; + } + + priv = qdf_mem_malloc(sizeof(*priv)); + if (!priv) + return -ENOMEM; + + reg_cap_ptr = ucfg_reg_get_hal_reg_cap(psoc); + if (!reg_cap_ptr) { + hdd_err("Failed to get reg capability"); + status = QDF_STATUS_E_INVAL; + goto free_priv; + } + ucfg_mlme_get_phy_max_freq_range(psoc, &low_2ghz_chan, + &high_2ghz_chan, &low_5ghz_chan, + &high_5ghz_chan); + reg_cap_ptr->phy_id = 0; + reg_cap_ptr->low_2ghz_chan = low_2ghz_chan; + reg_cap_ptr->high_2ghz_chan = high_2ghz_chan; + reg_cap_ptr->low_5ghz_chan = low_5ghz_chan; + reg_cap_ptr->high_5ghz_chan = high_5ghz_chan; + hdd_debug("pdev freq range %d %d %d %d", reg_cap_ptr->low_2ghz_chan, + reg_cap_ptr->high_2ghz_chan, reg_cap_ptr->low_5ghz_chan, + reg_cap_ptr->high_5ghz_chan); + priv->osif_check_netdev_state = hdd_check_internal_netdev_state; + pdev = wlan_objmgr_pdev_obj_create(psoc, priv); + if (!pdev) { + hdd_err("pdev obj create failed"); + status = QDF_STATUS_E_NOMEM; + goto free_priv; + } + + + status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to acquire pdev ref; status:%d", status); + QDF_BUG(false); + goto pdev_destroy; + } + + status = target_if_alloc_pdev_tgt_info(pdev); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("pdev tgt info alloc failed"); + goto pdev_destroy; + } + + hdd_ctx->pdev = pdev; + sme_store_pdev(hdd_ctx->mac_handle, hdd_ctx->pdev); + hdd_init_pdev_os_priv(hdd_ctx, priv); + return 0; + +pdev_destroy: + wlan_objmgr_pdev_obj_delete(pdev); +free_priv: + qdf_mem_free(priv); + + return qdf_status_to_os_return(status); +} + +int hdd_objmgr_release_and_destroy_pdev(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev = hdd_ctx->pdev; + struct pdev_osif_priv *osif_priv; + + hdd_ctx->pdev = NULL; + + QDF_BUG(pdev); + if (!pdev) + return -EINVAL; + + target_if_free_pdev_tgt_info(pdev); + + hdd_deinit_pdev_os_priv(pdev); + osif_priv = wlan_pdev_get_ospriv(pdev); + wlan_pdev_reset_ospriv(pdev); + qdf_mem_free(osif_priv); + + status = wlan_objmgr_pdev_obj_delete(pdev); + wlan_objmgr_pdev_release_ref(pdev, WLAN_HDD_ID_OBJ_MGR); + + return qdf_status_to_os_return(status); +} + +int hdd_objmgr_set_peer_mlme_auth_state(struct wlan_objmgr_vdev *vdev, + bool is_authenticated) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_ID); + if (!peer) { + hdd_err("peer is null"); + return -EINVAL; + } + + wlan_peer_obj_lock(peer); + wlan_peer_mlme_set_auth_state(peer, is_authenticated); + wlan_peer_obj_unlock(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + return 0; +} + +int hdd_objmgr_set_peer_mlme_state(struct wlan_objmgr_vdev *vdev, + enum wlan_peer_state peer_state) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_ID); + if (!peer) { + hdd_err("peer is null"); + return -EINVAL; + } + + wlan_peer_obj_lock(peer); + wlan_peer_mlme_set_state(peer, WLAN_ASSOC_STATE); + wlan_peer_obj_unlock(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + return 0; +} + +#ifdef WLAN_OBJMGR_REF_ID_TRACE +struct wlan_objmgr_vdev * +__hdd_objmgr_get_vdev_by_user(struct wlan_hdd_link_info *link_info, + wlan_objmgr_ref_dbgid id, + const char *func, int line) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + qdf_spin_lock_bh(&link_info->vdev_lock); + vdev = link_info->vdev; + if (vdev) { + status = wlan_objmgr_vdev_try_get_ref_debug(vdev, id, func, + line); + if (QDF_IS_STATUS_ERROR(status)) + vdev = NULL; + } + qdf_spin_unlock_bh(&link_info->vdev_lock); + + if (!vdev) + hdd_debug("VDEV is NULL (via %s, id %d)", func, id); + + return vdev; +} +#else +struct wlan_objmgr_vdev * +__hdd_objmgr_get_vdev_by_user(struct wlan_hdd_link_info *link_info, + wlan_objmgr_ref_dbgid id, + const char *func) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + qdf_spin_lock_bh(&link_info->vdev_lock); + vdev = link_info->vdev; + if (vdev) { + status = wlan_objmgr_vdev_try_get_ref(vdev, id); + if (QDF_IS_STATUS_ERROR(status)) + vdev = NULL; + } + qdf_spin_unlock_bh(&link_info->vdev_lock); + + if (!vdev) + hdd_debug("VDEV is NULL (via %s, id %d)", func, id); + + return vdev; +} +#endif + +#ifdef WLAN_OBJMGR_REF_ID_TRACE +void +__hdd_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func, + int line) +{ + if (!vdev) { + hdd_err("VDEV is NULL (via %s, id %d)", func, id); + return; + } + + wlan_objmgr_vdev_release_ref_debug(vdev, id, func, line); +} +#else +void +__hdd_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func) +{ + if (!vdev) { + hdd_err("VDEV is NULL (via %s, id %d)", func, id); + return; + } + + wlan_objmgr_vdev_release_ref(vdev, id); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.h new file mode 100644 index 0000000000..e03d93454a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_object_manager.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_HDD_OBJECT_MANAGER_H) +#define WLAN_HDD_OBJECT_MANAGER_H +/** + * DOC: HDD object manager API file to create/destroy psoc, pdev, vdev + * and peer objects by calling object manager APIs + * + * Common object model has 1 : N mapping between PSOC and PDEV but for MCL + * PSOC and PDEV has 1 : 1 mapping. + * + * MCL object model view is: + * + * -------- + * | PSOC | + * -------- + * | + * | + * -------------------------- + * | PDEV | + * -------------------------- + * | | + * | | + * | | + * ---------- ------------- + * | vdev 0 | | vdev n | + * ---------- ------------- + * | | | | + * ---------- ---------- ---------- ---------- + * | peer 1 | | peer n | | peer 1 | | peer n | + * ---------- ---------- ---------- ----------- + * + */ +#include "wlan_hdd_main.h" +#include +#include +#include +#include +#include +#include + +/** + * hdd_objmgr_create_and_store_psoc() - Create psoc and store in hdd context + * @hdd_ctx: Hdd context + * @psoc_id: Psoc Id + * + * This API creates Psoc object with given @psoc_id and store the psoc reference + * to hdd context + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_create_and_store_psoc(struct hdd_context *hdd_ctx, + uint8_t psoc_id); + +/** + * hdd_objmgr_release_and_destroy_psoc() - Deletes the psoc object + * @hdd_ctx: Hdd context + * + * This API deletes psoc object and release its reference from hdd context + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_release_and_destroy_psoc(struct hdd_context *hdd_ctx); + +/** + * hdd_objmgr_update_tgt_max_vdev_psoc() - Update target max vdev number + * @hdd_ctx: Hdd context + * @max_vdev: Max number of supported vdevs + * + * This API update target max vdev number to psoc object + * + * Return: None + */ +void hdd_objmgr_update_tgt_max_vdev_psoc(struct hdd_context *hdd_ctx, + uint8_t max_vdev); + +/** + * hdd_objmgr_create_and_store_pdev() - Create pdev and store in hdd context + * @hdd_ctx: Hdd context + * + * This API creates the pdev object and store the pdev reference to hdd context + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_create_and_store_pdev(struct hdd_context *hdd_ctx); + +/** + * hdd_objmgr_release_and_destroy_pdev() - Deletes the pdev object + * @hdd_ctx: Hdd context + * + * This API deletes pdev object and release its reference from hdd context + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_release_and_destroy_pdev(struct hdd_context *hdd_ctx); + +/** + * hdd_objmgr_set_peer_mlme_auth_state() - set the peer mlme auth state + * @vdev: vdev pointer + * @is_authenticated: Peer mlme auth state true/false + * + * This API set the peer mlme auth state + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_set_peer_mlme_auth_state(struct wlan_objmgr_vdev *vdev, + bool is_authenticated); + +/** + * hdd_objmgr_set_peer_mlme_state() - set the peer mlme state + * @vdev: vdev pointer + * @peer_state: Peer mlme state + * + * This API set the peer mlme state + * + * Return: 0 for success, negative error code for failure + */ +int hdd_objmgr_set_peer_mlme_state(struct wlan_objmgr_vdev *vdev, + enum wlan_peer_state peer_state); + +/** + * hdd_objmgr_get_vdev_by_user() - Get reference of vdev from adapter + * with user id + * @link_info: Pointer of link_info in HDD adapter + * @dbgid: reference count dbg id + * + * Return: pointer to vdev object for success, NULL for failure + */ +#ifdef WLAN_OBJMGR_REF_ID_TRACE +#define hdd_objmgr_get_vdev_by_user(link_info, dbgid) \ + __hdd_objmgr_get_vdev_by_user(link_info, dbgid, __func__, __LINE__) +struct wlan_objmgr_vdev * +__hdd_objmgr_get_vdev_by_user(struct wlan_hdd_link_info *link_info, + wlan_objmgr_ref_dbgid id, + const char *func, + int line); +#else +#define hdd_objmgr_get_vdev_by_user(link_info, dbgid) \ + __hdd_objmgr_get_vdev_by_user(link_info, dbgid, __func__) +struct wlan_objmgr_vdev * +__hdd_objmgr_get_vdev_by_user(struct wlan_hdd_link_info *link_info, + wlan_objmgr_ref_dbgid id, + const char *func); +#endif + +/** + * hdd_objmgr_put_vdev_by_user() - Release reference of vdev object with + * user id + * @vdev: pointer to vdev object + * @dbgid: reference count dbg id + * + * This API releases vdev object reference which was acquired using + * hdd_objmgr_get_vdev_by_user(). + * + * Return: void + */ +#ifdef WLAN_OBJMGR_REF_ID_TRACE +#define hdd_objmgr_put_vdev_by_user(vdev, dbgid) \ + __hdd_objmgr_put_vdev_by_user(vdev, dbgid, __func__, __LINE__) +void +__hdd_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func, + int line); +#else +#define hdd_objmgr_put_vdev_by_user(vdev, dbgid) \ + __hdd_objmgr_put_vdev_by_user(vdev, dbgid, __func__) +void +__hdd_objmgr_put_vdev_by_user(struct wlan_objmgr_vdev *vdev, + wlan_objmgr_ref_dbgid id, const char *func); +#endif +#endif /* end #if !defined(WLAN_HDD_OBJECT_MANAGER_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c new file mode 100644 index 0000000000..f895f6518f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.c @@ -0,0 +1,2179 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "cds_sched.h" +#include "wlan_hdd_assoc.h" +#include "osif_sync.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_trace.h" +#include "wlan_osif_request_manager.h" +#include "wlan_tgt_def_config.h" +#include "sch_api.h" +#include "wma_api.h" +#include +#include +#include +#include "wlan_ocb_public_structs.h" +#include "wlan_ocb_ucfg_api.h" +#include +#include +#include +#include +#include "ol_txrx.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" + +/* Structure definitions for WLAN_SET_DOT11P_CHANNEL_SCHED */ +#define AIFSN_MIN (2) +#define AIFSN_MAX (15) +#define CW_MIN (1) +#define CW_MAX (10) + +/* Maximum time(ms) to wait for OCB operations */ +#define WLAN_WAIT_TIME_OCB_CMD 1500 + +/** + * dot11p_validate_qos_params() - Check if QoS parameters are valid + * @qos_params: Array of QoS parameters + * + * Return: 0 on success. error code on failure. + */ +static int dot11p_validate_qos_params(struct ocb_wmm_param qos_params[]) +{ + int i; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + if ((!qos_params[i].aifsn) && (!qos_params[i].cwmin) + && (!qos_params[i].cwmax)) + continue; + + /* Validate AIFSN */ + if ((qos_params[i].aifsn < AIFSN_MIN) + || (qos_params[i].aifsn > AIFSN_MAX)) { + hdd_err("Invalid QoS parameter aifsn %d", + qos_params[i].aifsn); + return -EINVAL; + } + + /* Validate CWMin */ + if ((qos_params[i].cwmin < CW_MIN) + || (qos_params[i].cwmin > CW_MAX)) { + hdd_err("Invalid QoS parameter cwmin %d", + qos_params[i].cwmin); + return -EINVAL; + } + + /* Validate CWMax */ + if ((qos_params[i].cwmax < CW_MIN) + || (qos_params[i].cwmax > CW_MAX)) { + hdd_err("Invalid QoS parameter cwmax %d", + qos_params[i].cwmax); + return -EINVAL; + } + } + + return 0; +} + +/** + * dot11p_validate_channel() - validates a DSRC channel + * @wiphy: pointer to the wiphy + * @channel_freq: the channel's center frequency + * @bandwidth: the channel's bandwidth + * @tx_power: transmit power + * @reg_power: (output) the max tx power from the regulatory domain + * @antenna_max: (output) the max antenna gain from the regulatory domain + * + * Return: 0 if the channel is valid, error code otherwise. + */ +static int dot11p_validate_channel(struct wiphy *wiphy, + uint32_t channel_freq, uint32_t bandwidth, + uint32_t tx_power, uint8_t *reg_power, + uint8_t *antenna_max) +{ + int band_idx, channel_idx; + struct ieee80211_supported_band *current_band; + struct ieee80211_channel *current_channel; + + for (band_idx = 0; band_idx < HDD_NUM_NL80211_BANDS; band_idx++) { + current_band = wiphy->bands[band_idx]; + if (!current_band) + continue; + + for (channel_idx = 0; channel_idx < current_band->n_channels; + channel_idx++) { + current_channel = ¤t_band->channels[channel_idx]; + + if (channel_freq == current_channel->center_freq) { + if (current_channel->flags & + IEEE80211_CHAN_DISABLED) + return -EINVAL; + + if (reg_power) + *reg_power = + current_channel->max_reg_power; + if (antenna_max) + *antenna_max = + current_channel-> + max_antenna_gain; + + switch (bandwidth) { + case 0: + if (current_channel->flags & + IEEE80211_CHAN_NO_10MHZ) + bandwidth = 5; + else if (current_channel->flags & + IEEE80211_CHAN_NO_20MHZ) + bandwidth = 10; + else + bandwidth = 20; + break; + case 5: + break; + case 10: + if (current_channel->flags & + IEEE80211_CHAN_NO_10MHZ) + return -EINVAL; + break; + case 20: + if (current_channel->flags & + IEEE80211_CHAN_NO_20MHZ) + return -EINVAL; + break; + default: + return -EINVAL; + } + + if (tx_power > current_channel->max_power) + return -EINVAL; + + return 0; + } + } + } + + return -EINVAL; +} + +/** + * hdd_ocb_validate_config() - Validates the config data + * @adapter: Pointer to HDD Adapter + * @config: configuration to be validated + * + * Return: 0 on success. + */ +static int hdd_ocb_validate_config(struct hdd_adapter *adapter, + struct ocb_config *config) +{ + int i; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + for (i = 0; i < config->channel_count; i++) { + if (dot11p_validate_channel(hdd_ctx->wiphy, + config->channels[i].chan_freq, + config->channels[i].bandwidth, + config->channels[i].max_pwr, + &config->channels[i].reg_pwr, + &config->channels[i].antenna_max)) { + hdd_err("Invalid channel frequency %d", + config->channels[i].chan_freq); + return -EINVAL; + } + if (dot11p_validate_qos_params(config->channels[i].qos_params)) + return -EINVAL; + } + + return 0; +} + +/** + * hdd_ocb_register_sta() - Register station with Transport Layer + * @adapter: Pointer to HDD Adapter + * + * This function should be invoked in the OCB Set Schedule callback + * to enable the data path in the TL by calling RegisterSTAClient + * + * Return: 0 on success. -1 on failure. + */ +static int hdd_ocb_register_sta(struct hdd_adapter *adapter) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type sta_desc = {0}; + struct hdd_station_ctx *sta_ctx; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_vdev *vdev; + + qdf_status = cdp_peer_register_ocb_peer(soc, + adapter->mac_addr.bytes); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Error registering OCB Self Peer!"); + return -EINVAL; + } + + WLAN_ADDR_COPY(sta_desc.peer_addr.bytes, adapter->mac_addr.bytes); + sta_desc.is_qos_enabled = 1; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return -EINVAL; + + qdf_status = ucfg_dp_ocb_register_txrx_ops(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to register tx/rx ops. Status= %d", qdf_status); + return -EINVAL; + } + + qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &sta_desc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + qdf_copy_macaddr(&sta_ctx->conn_info.peer_macaddr[0], + &adapter->mac_addr); + + return 0; +} + +/** + * hdd_ocb_config_new() - Creates a new OCB configuration + * @num_channels: the number of channels + * @num_schedule: the schedule size + * @ndl_chan_list_len: length in bytes of the NDL chan blob + * @ndl_active_state_list_len: length in bytes of the active state blob + * + * Return: A pointer to the OCB configuration struct, NULL on failure. + */ +static +struct ocb_config *hdd_ocb_config_new(uint32_t num_channels, + uint32_t num_schedule, + uint32_t ndl_chan_list_len, + uint32_t ndl_active_state_list_len) +{ + struct ocb_config *ret = 0; + uint32_t len; + void *cursor; + + if (num_channels > CFG_TGT_NUM_OCB_CHANNELS || + num_schedule > CFG_TGT_NUM_OCB_SCHEDULES) + return NULL; + + len = sizeof(*ret) + + num_channels * sizeof(struct ocb_config_chan) + + num_schedule * sizeof(struct ocb_config_schdl) + + ndl_chan_list_len + + ndl_active_state_list_len; + + cursor = qdf_mem_malloc(len); + if (!cursor) + goto fail; + + ret = cursor; + cursor += sizeof(*ret); + + ret->channel_count = num_channels; + ret->channels = cursor; + cursor += num_channels * sizeof(*ret->channels); + + ret->schedule_size = num_schedule; + ret->schedule = cursor; + cursor += num_schedule * sizeof(*ret->schedule); + + ret->dcc_ndl_chan_list = cursor; + cursor += ndl_chan_list_len; + + ret->dcc_ndl_active_state_list = cursor; + cursor += ndl_active_state_list_len; + + return ret; + +fail: + qdf_mem_free(ret); + return NULL; +} + +struct hdd_ocb_set_config_priv { + int status; +}; + + +/** + * hdd_ocb_set_config_callback() - OCB set config callback function + * @context_ptr: OCB call context + * @response_ptr: Pointer to response structure + * + * This function is registered as a callback with the lower layers + * and is used to respond with the status of a OCB set config command. + */ +static void hdd_ocb_set_config_callback(void *context_ptr, void *response_ptr) +{ + struct osif_request *request; + struct hdd_ocb_set_config_priv *priv; + struct ocb_set_config_response *response = response_ptr; + + request = osif_request_get(context_ptr); + if (!request) { + hdd_err("Obsolete request"); + return; + } + priv = osif_request_priv(request); + + if (response && response->status) + hdd_warn("Operation failed: %d", response->status); + + if (response && (response->status == OCB_CHANNEL_CONFIG_SUCCESS)) + priv->status = 0; + else + priv->status = -EINVAL; + + osif_request_complete(request); + osif_request_put(request); +} + +/** + * hdd_ocb_set_config_req() - Send an OCB set config request + * @adapter: a pointer to the adapter + * @config: a pointer to the OCB configuration + * + * Return: 0 on success. + */ +static int hdd_ocb_set_config_req(struct hdd_adapter *adapter, + struct ocb_config *config) +{ + int rc; + QDF_STATUS status; + void *cookie; + struct osif_request *request; + struct hdd_ocb_set_config_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_OCB_CMD, + }; + struct wlan_objmgr_vdev *vdev; + + if (hdd_ocb_validate_config(adapter, config)) { + hdd_err("The configuration is invalid"); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto end; + } + + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + + status = ucfg_ocb_set_channel_config(vdev, config, + hdd_ocb_set_config_callback, + cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set channel config."); + rc = qdf_status_to_os_return(status); + goto end; + } + + /* Wait for the function to complete. */ + rc = osif_request_wait_for_response(request); + if (rc) { + hdd_err("Operation timed out"); + goto end; + } + + priv = osif_request_priv(request); + rc = priv->status; + if (rc) { + hdd_err("Operation failed: %d", rc); + goto end; + } + + /* + * OCB set config command successful. + * Open the TX data path + */ + if (!hdd_ocb_register_sta(adapter)) + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + +end: + osif_request_put(request); + + return rc; +} + +#ifdef WLAN_WEXT_SUPPORT_ENABLE +/** + * __iw_set_dot11p_channel_sched() - Handler for WLAN_SET_DOT11P_CHANNEL_SCHED + * ioctl + * @dev: Pointer to net_device structure + * @info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + * + * Return: 0 on success + */ +static int __iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int rc; + struct dot11p_channel_sched *sched; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct ocb_config *config = NULL; + uint8_t *mac_addr; + int i, j; + struct ocb_config_chan *curr_chan; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + rc = wlan_hdd_validate_context(hdd_ctx); + if (0 != rc) + return rc; + + rc = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != rc) + return rc; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + sched = (struct dot11p_channel_sched *)extra; + + /* Scheduled slots same as num channels for compatibility */ + config = hdd_ocb_config_new(sched->num_channels, sched->num_channels, + 0, 0); + if (!config) { + hdd_err("Failed to allocate memory!"); + return -ENOMEM; + } + + /* Identify the vdev interface */ + config->vdev_id = adapter->deflink->vdev_id; + + /* Release all the mac addresses used for OCB */ + for (i = 0; i < adapter->ocb_mac_addr_count; i++) { + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->ocb_mac_address[i].bytes); + } + adapter->ocb_mac_addr_count = 0; + + config->channel_count = 0; + for (i = 0; i < sched->num_channels; i++) { + if (0 == sched->channels[i].channel_freq) + continue; + + curr_chan = &(config->channels[config->channel_count]); + + curr_chan->chan_freq = sched->channels[i].channel_freq; + /* + * tx_power is divided by 2 because ocb_channel.tx_power is + * in half dB increments and ocb_config_channel.max_pwr + * is in 1 dB increments. + */ + curr_chan->max_pwr = sched->channels[i].tx_power / 2; + curr_chan->bandwidth = sched->channels[i].channel_bandwidth; + /* assume 10 as default if not provided */ + if (curr_chan->bandwidth == 0) + curr_chan->bandwidth = 10; + + /* + * Setup locally administered mac addresses for each channel. + * First channel uses the adapter's address. + */ + if (i == 0) { + qdf_copy_macaddr(&curr_chan->mac_address, + &adapter->mac_addr); + } else { + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, + adapter->device_mode); + if (!mac_addr) { + hdd_err("Cannot obtain mac address"); + rc = -EINVAL; + goto fail; + } + qdf_mem_copy(config->channels[ + config->channel_count].mac_address.bytes, + mac_addr, sizeof(tSirMacAddr)); + /* Save the mac address to release later */ + qdf_mem_copy(adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count].bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + adapter->ocb_mac_addr_count++; + } + + for (j = 0; j < QCA_WLAN_AC_ALL; j++) { + curr_chan->qos_params[j].aifsn = + sched->channels[i].qos_params[j].aifsn; + curr_chan->qos_params[j].cwmin = + sched->channels[i].qos_params[j].cwmin; + curr_chan->qos_params[j].cwmax = + sched->channels[i].qos_params[j].cwmax; + } + + config->channel_count++; + } + + /* + * Scheduled slots same as num channels for compatibility with + * legacy use. + */ + for (i = 0; i < sched->num_channels; i++) { + config->schedule[i].chan_freq = sched->channels[i].channel_freq; + config->schedule[i].guard_interval = + sched->channels[i].start_guard_interval; + config->schedule[i].total_duration = + sched->channels[i].duration; + } + + rc = hdd_ocb_set_config_req(adapter, config); + if (rc) { + hdd_err("Error while setting OCB config"); + goto fail; + } + + rc = 0; + +fail: + qdf_mem_free(config); + return rc; +} + +/** + * iw_set_dot11p_channel_sched() - IOCTL interface for setting channel schedule + * @dev: Pointer to net_device structure + * @info: IW Request Info + * @wrqu: IW Request Userspace Data Pointer + * @extra: IW Request Kernel Data Pointer + * + * Return: 0 on success. + */ +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_dot11p_channel_sched(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif /* WLAN_WEXT_SUPPORT_ENABLE */ + +const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS] = { + .type = NLA_U32 + }, +}; + +const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE] = { + .type = NLA_BINARY, .len = SIZE_UTC_TIME + }, + [QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR] = { + .type = NLA_BINARY, .len = SIZE_UTC_TIME_ERROR + }, +}; + +const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE] = { + .type = NLA_U32 + }, +}; + +const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ] = { + .type = NLA_U32 + }, +}; + +static const struct nla_policy qca_wlan_vendor_ocb_get_tsf_timer_resp[] = { + [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW] = { + .type = NLA_U32 + }, +}; + +const struct nla_policy qca_wlan_vendor_dcc_get_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY] = { + .type = NLA_BINARY + }, +}; + +static const struct nla_policy qca_wlan_vendor_dcc_get_stats_resp[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY] = { + .type = NLA_BINARY + }, +}; + +const struct nla_policy qca_wlan_vendor_dcc_clear_stats[] = { + [QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP] = { + .type = NLA_U32 + }, +}; + +const struct nla_policy qca_wlan_vendor_dcc_update_ndl[ + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] = { + .type = NLA_BINARY + }, + [QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY] = { + .type = NLA_BINARY + }, +}; + +/** + * struct wlan_hdd_ocb_config_channel + * @chan_freq: frequency of the channel + * @bandwidth: bandwidth of the channel, either 10 or 20 MHz + * @flags: channel flags + * @reserved: reserved padding, set to 0 + * @qos_params: QoS parameters + * @max_pwr: maximum transmit power of the channel (1/2 dBm) + * @min_pwr: minimum transmit power of the channel (1/2 dBm) + */ +struct wlan_hdd_ocb_config_channel { + uint32_t chan_freq; + uint32_t bandwidth; + uint16_t flags; + uint8_t reserved[4]; + struct sir_qos_params qos_params[QCA_WLAN_AC_ALL]; + uint32_t max_pwr; + uint32_t min_pwr; +}; + +static void wlan_hdd_ocb_config_channel_to_ocb_config_channel( + struct ocb_config_chan *dest, + struct wlan_hdd_ocb_config_channel *src, + uint32_t channel_count) +{ + uint32_t i; + + qdf_mem_zero(dest, channel_count * sizeof(*dest)); + + for (i = 0; i < channel_count; i++) { + dest[i].chan_freq = src[i].chan_freq; + dest[i].bandwidth = src[i].bandwidth; + qdf_mem_copy(dest[i].qos_params, src[i].qos_params, + sizeof(dest[i].qos_params)); + /* + * max_pwr and min_pwr are divided by 2 because + * ocb_channel_param.max_pwr and min_pwr + * are in 1/2 dB increments and + * ocb_config_channel.max_pwr and min_pwr are in + * 1 dB increments. + */ + dest[i].max_pwr = src[i].max_pwr / 2; + dest[i].min_pwr = (src[i].min_pwr + 1) / 2; + dest[i].flags = src[i].flags; + } +} + +/** + * __wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1]; + struct nlattr *channel_array; + struct nlattr *sched_array; + struct nlattr *ndl_chan_list; + uint32_t ndl_chan_list_len; + struct nlattr *ndl_active_state_list; + uint32_t ndl_active_state_list_len; + uint32_t flags = 0; + int i; + uint32_t channel_count, schedule_size; + struct ocb_config *config; + int rc = -EINVAL; + uint8_t *mac_addr; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX, + data, data_len, + qca_wlan_vendor_ocb_set_config_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Get the number of channels in the schedule */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]) { + hdd_err("CHANNEL_COUNT is not present"); + return -EINVAL; + } + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT]); + + /* Get the size of the channel schedule */ + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]) { + hdd_err("SCHEDULE_SIZE is not present"); + return -EINVAL; + } + schedule_size = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE]); + + /* Get the ndl chan array and the ndl active state array. */ + ndl_chan_list = + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY]; + ndl_chan_list_len = (ndl_chan_list ? nla_len(ndl_chan_list) : 0); + + ndl_active_state_list = + tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY]; + ndl_active_state_list_len = (ndl_active_state_list ? + nla_len(ndl_active_state_list) : 0); + + /* Get the flags */ + if (tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]) + flags = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS]); + + config = hdd_ocb_config_new(channel_count, schedule_size, + ndl_chan_list_len, + ndl_active_state_list_len); + if (!config) { + hdd_err("Failed to allocate memory!"); + return -ENOMEM; + } + + config->channel_count = channel_count; + config->schedule_size = schedule_size; + config->flags = flags; + + /* Read the channel array */ + channel_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY]; + if (!channel_array) { + hdd_err("No channel present"); + goto fail; + } + if (nla_len(channel_array) != channel_count * + sizeof(struct wlan_hdd_ocb_config_channel)) { + hdd_err("CHANNEL_ARRAY is not the correct size"); + goto fail; + } + wlan_hdd_ocb_config_channel_to_ocb_config_channel( + config->channels, nla_data(channel_array), channel_count); + + /* Identify the vdev interface */ + config->vdev_id = adapter->deflink->vdev_id; + + /* Release all the mac addresses used for OCB */ + for (i = 0; i < adapter->ocb_mac_addr_count; i++) { + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->ocb_mac_address[i].bytes); + } + adapter->ocb_mac_addr_count = 0; + + /* + * Setup locally administered mac addresses for each channel. + * First channel uses the adapter's address. + */ + for (i = 0; i < config->channel_count; i++) { + if (i == 0) { + qdf_copy_macaddr(&config->channels[i].mac_address, + &adapter->mac_addr); + } else { + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, + adapter->device_mode); + if (!mac_addr) { + hdd_err("Cannot obtain mac address"); + goto fail; + } + qdf_mem_copy(config->channels[i].mac_address.bytes, + mac_addr, QDF_MAC_ADDR_SIZE); + /* Save the mac address to release later */ + qdf_copy_macaddr(&adapter->ocb_mac_address[ + adapter->ocb_mac_addr_count], + &config->channels[i].mac_address); + adapter->ocb_mac_addr_count++; + } + } + + /* Read the schedule array */ + sched_array = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY]; + if (!sched_array) { + hdd_err("No channel present"); + goto fail; + } + if (nla_len(sched_array) != schedule_size * sizeof(*config->schedule)) { + hdd_err("SCHEDULE_ARRAY is not the correct size"); + goto fail; + } + qdf_mem_copy(config->schedule, nla_data(sched_array), + nla_len(sched_array)); + + /* Copy the NDL chan array */ + if (ndl_chan_list_len) { + config->dcc_ndl_chan_list_len = ndl_chan_list_len; + qdf_mem_copy(config->dcc_ndl_chan_list, nla_data(ndl_chan_list), + nla_len(ndl_chan_list)); + } + + /* Copy the NDL active state array */ + if (ndl_active_state_list_len) { + config->dcc_ndl_active_state_list_len = + ndl_active_state_list_len; + qdf_mem_copy(config->dcc_ndl_active_state_list, + nla_data(ndl_active_state_list), + nla_len(ndl_active_state_list)); + } + + rc = hdd_ocb_set_config_req(adapter, config); + if (rc) + hdd_err("Error while setting OCB config: %d", rc); + +fail: + qdf_mem_free(config); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_set_config() - Interface for set config command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ocb_set_config(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for set UTC time command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1]; + struct nlattr *utc_attr; + struct nlattr *time_error_attr; + struct ocb_utc_param *utc; + struct wlan_objmgr_vdev *vdev; + int rc = -EINVAL; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX, + data, data_len, + qca_wlan_vendor_ocb_set_utc_time_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Read the UTC time */ + utc_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE]; + if (!utc_attr) { + hdd_err("UTC_TIME is not present"); + return -EINVAL; + } + if (nla_len(utc_attr) != SIZE_UTC_TIME) { + hdd_err("UTC_TIME is not the correct size"); + return -EINVAL; + } + + /* Read the time error */ + time_error_attr = tb[QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR]; + if (!time_error_attr) { + hdd_err("UTC_TIME is not present"); + return -EINVAL; + } + if (nla_len(time_error_attr) != SIZE_UTC_TIME_ERROR) { + hdd_err("UTC_TIME is not the correct size"); + return -EINVAL; + } + + utc = qdf_mem_malloc(sizeof(*utc)); + if (!utc) + return -ENOMEM; + + utc->vdev_id = adapter->deflink->vdev_id; + qdf_mem_copy(utc->utc_time, nla_data(utc_attr), SIZE_UTC_TIME); + qdf_mem_copy(utc->time_error, nla_data(time_error_attr), + SIZE_UTC_TIME_ERROR); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto out; + } + + if (ucfg_ocb_set_utc_time(vdev, utc) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while setting UTC time"); + rc = -EINVAL; + } else { + rc = 0; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); +out: + qdf_mem_free(utc); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_set_utc_time() - Interface for the set UTC time command + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ocb_set_utc_time(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for start TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1]; + struct ocb_timing_advert_param *timing_advert; + struct wlan_objmgr_vdev *vdev; + int rc = -EINVAL; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) + return -ENOMEM; + + timing_advert->vdev_id = adapter->deflink->vdev_id; + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX, + data, data_len, + qca_wlan_vendor_ocb_start_timing_advert_policy)) { + hdd_err("Invalid ATTR"); + goto fail; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]) { + hdd_err("CHANNEL_FREQ is not present"); + goto fail; + } + timing_advert->chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]) { + hdd_err("REPEAT_RATE is not present"); + goto fail; + } + timing_advert->repeat_rate = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE]); + + timing_advert->template_length = + sme_ocb_gen_timing_advert_frame(hdd_ctx->mac_handle, + *(tSirMacAddr *)&adapter->mac_addr.bytes, + &timing_advert->template_value, + &timing_advert->timestamp_offset, + &timing_advert->time_value_offset); + if (timing_advert->template_length <= 0) { + hdd_err("Error while generating the TA frame"); + goto fail; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto fail; + } + + if (ucfg_ocb_start_timing_advert(vdev, timing_advert) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while starting timing advert"); + rc = -EINVAL; + } else { + rc = 0; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + +fail: + if (timing_advert->template_value) + qdf_mem_free(timing_advert->template_value); + qdf_mem_free(timing_advert); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_start_timing_advert() - Interface for the start TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ocb_start_timing_advert(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1]; + struct ocb_timing_advert_param *timing_advert; + struct wlan_objmgr_vdev *vdev; + int rc = -EINVAL; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + timing_advert = qdf_mem_malloc(sizeof(*timing_advert)); + if (!timing_advert) + return -ENOMEM; + + timing_advert->vdev_id = adapter->deflink->vdev_id; + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX, + data, data_len, + qca_wlan_vendor_ocb_stop_timing_advert_policy)) { + hdd_err("Invalid ATTR"); + goto fail; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]) { + hdd_err("CHANNEL_FREQ is not present"); + goto fail; + } + timing_advert->chan_freq = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ]); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto fail; + } + + if (ucfg_ocb_stop_timing_advert(vdev, timing_advert) != + QDF_STATUS_SUCCESS) { + hdd_err("Error while stopping timing advert"); + rc = -EINVAL; + } else { + rc = 0; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + +fail: + qdf_mem_free(timing_advert); + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_stop_timing_advert() - Interface for the stop TA cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ocb_stop_timing_advert(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +struct hdd_ocb_get_tsf_timer_priv { + struct ocb_get_tsf_timer_response response; + int status; +}; + +/** + * hdd_ocb_get_tsf_timer_callback() - Callback to get TSF command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_ocb_get_tsf_timer_callback(void *context_ptr, + void *response_ptr) +{ + struct osif_request *request; + struct hdd_ocb_get_tsf_timer_priv *priv; + struct ocb_get_tsf_timer_response *response = response_ptr; + + request = osif_request_get(context_ptr); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + if (response) { + priv->response = *response; + priv->status = 0; + } else { + priv->status = -EINVAL; + } + osif_request_complete(request); + osif_request_put(request); +} + +static int +hdd_ocb_get_tsf_timer_reply(struct wiphy *wiphy, + struct ocb_get_tsf_timer_response *response) +{ + uint32_t nl_buf_len; + struct sk_buff *nl_resp; + int rc; + + /* Allocate the buffer for the response. */ + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += 2 * (NLA_HDRLEN + sizeof(uint32_t)); + nl_resp = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + if (!nl_resp) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + /* Populate the response. */ + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH, + response->timer_high); + if (rc) + goto end; + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW, + response->timer_low); + if (rc) + goto end; + + /* Send the response. */ + rc = wlan_cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hdd_err("wlan_cfg80211_vendor_cmd_reply failed: %d", rc); + goto end; + } +end: + wlan_cfg80211_vendor_free_skb(nl_resp); + return rc; +} + +/** + * __wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int +__wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int rc; + struct ocb_get_tsf_timer_param tsf_request = {0}; + QDF_STATUS status; + void *cookie; + struct osif_request *request; + struct hdd_ocb_get_tsf_timer_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_OCB_CMD, + }; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto end; + } + + tsf_request.vdev_id = adapter->deflink->vdev_id; + status = ucfg_ocb_get_tsf_timer(vdev, &tsf_request, + hdd_ocb_get_tsf_timer_callback, + cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get tsf timer."); + rc = qdf_status_to_os_return(status); + goto end; + } + + rc = osif_request_wait_for_response(request); + if (rc) { + hdd_err("Operation timed out"); + goto end; + } + + priv = osif_request_priv(request); + rc = priv->status; + if (rc) { + hdd_err("Operation failed: %d", rc); + goto end; + } + + hdd_debug("Got TSF timer response, high=%d, low=%d", + priv->response.timer_high, + priv->response.timer_low); + + /* Send the response. */ + rc = hdd_ocb_get_tsf_timer_reply(wiphy, &priv->response); + if (rc) { + hdd_err("hdd_ocb_get_tsf_timer_reply failed: %d", rc); + goto end; + } + +end: + osif_request_put(request); + + return rc; +} + +/** + * wlan_hdd_cfg80211_ocb_get_tsf_timer() - Interface for get TSF timer cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ocb_get_tsf_timer(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +struct hdd_dcc_stats_priv { + struct ocb_dcc_get_stats_response *response; + int status; +}; + +static void hdd_dcc_get_stats_dealloc(void *context_ptr) +{ + struct hdd_dcc_stats_priv *priv = context_ptr; + + qdf_mem_free(priv->response); + priv->response = NULL; +} + +/** + * hdd_dcc_get_stats_callback() - Callback to get stats command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_dcc_get_stats_callback(void *context_ptr, void *response_ptr) +{ + struct osif_request *request; + struct hdd_dcc_stats_priv *priv; + struct ocb_dcc_get_stats_response *response = response_ptr; + struct ocb_dcc_get_stats_response *hdd_resp; + + request = osif_request_get(context_ptr); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + if (!response) { + priv->status = -EINVAL; + goto end; + } + + priv->response = qdf_mem_malloc(sizeof(*response) + + response->channel_stats_array_len); + if (!priv->response) { + priv->status = -ENOMEM; + goto end; + } + + hdd_resp = priv->response; + *hdd_resp = *response; + hdd_resp->channel_stats_array = (void *)hdd_resp + sizeof(*hdd_resp); + qdf_mem_copy(hdd_resp->channel_stats_array, + response->channel_stats_array, + response->channel_stats_array_len); + priv->status = 0; + +end: + osif_request_complete(request); + osif_request_put(request); +} + +static int +hdd_dcc_get_stats_send_reply(struct wiphy *wiphy, + struct ocb_dcc_get_stats_response *response) +{ + uint32_t nl_buf_len; + struct sk_buff *nl_resp; + int rc; + + /* Allocate the buffer for the response. */ + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += NLA_HDRLEN + sizeof(uint32_t); + nl_buf_len += NLA_HDRLEN + response->channel_stats_array_len; + nl_resp = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + if (!nl_resp) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + /* Populate the response. */ + rc = nla_put_u32(nl_resp, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + response->num_channels); + if (rc) + goto end; + rc = nla_put(nl_resp, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + response->channel_stats_array_len, + response->channel_stats_array); + if (rc) + goto end; + + /* Send the response. */ + rc = wlan_cfg80211_vendor_cmd_reply(nl_resp); + nl_resp = NULL; + if (rc) { + hdd_err("wlan_cfg80211_vendor_cmd_reply failed: %d", rc); + goto end; + } +end: + wlan_cfg80211_vendor_free_skb(nl_resp); + return rc; +} + +/** + * __wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + uint32_t channel_count = 0; + uint32_t request_array_len = 0; + void *request_array = 0; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1]; + int rc; + struct ocb_dcc_get_stats_param dcc_request = {0}; + QDF_STATUS status; + void *cookie; + struct osif_request *request; + struct hdd_dcc_stats_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_OCB_CMD, + .dealloc = hdd_dcc_get_stats_dealloc, + }; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX, + data, data_len, + qca_wlan_vendor_dcc_get_stats)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Validate all the parameters are present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]) { + hdd_err("Parameters are not present."); + return -EINVAL; + } + + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT]); + request_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + request_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY]); + + /* Check channel count. Per 11p spec, max 2 channels allowed */ + if (!channel_count || channel_count > CFG_TGT_NUM_OCB_CHANNELS) { + hdd_err("Invalid channel_count %d", channel_count); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + dcc_request.vdev_id = adapter->deflink->vdev_id; + dcc_request.channel_count = channel_count; + dcc_request.request_array_len = request_array_len; + dcc_request.request_array = request_array; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto end; + } + + status = ucfg_ocb_dcc_get_stats(vdev, &dcc_request, + hdd_dcc_get_stats_callback, + cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get DCC stats."); + rc = qdf_status_to_os_return(status); + goto end; + } + + /* Wait for the function to complete. */ + rc = osif_request_wait_for_response(request); + if (rc) { + hdd_err("Operation timed out"); + goto end; + } + + priv = osif_request_priv(request); + rc = priv->status; + if (rc) { + hdd_err("Operation failed: %d", rc); + goto end; + } + + /* Send the response. */ + rc = hdd_dcc_get_stats_send_reply(wiphy, priv->response); + if (rc) { + hdd_err("hdd_dcc_get_stats_send_reply failed: %d", rc); + goto end; + } + +end: + osif_request_put(request); + + return rc; +} + +/** + * wlan_hdd_cfg80211_dcc_get_stats() - Interface for get dcc stats + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_dcc_get_stats(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1]; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX, + data, data_len, + qca_wlan_vendor_dcc_clear_stats)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Verify that the parameter is present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP]) { + hdd_err("Parameters are not present."); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) + return -EINVAL; + + if (ucfg_ocb_dcc_clear_stats( + vdev, adapter->deflink->vdev_id, + nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP])) != + QDF_STATUS_SUCCESS) { + hdd_err("Failed to clear DCC stats."); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + return -EINVAL; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + + return 0; +} + +/** + * wlan_hdd_cfg80211_dcc_clear_stats() - Interface for clear dcc stats cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_dcc_clear_stats(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +struct hdd_dcc_update_ndl_priv { + int status; +}; + +/** + * hdd_dcc_update_ndl_callback() - Callback to update NDL command + * @context_ptr: request context + * @response_ptr: response data + */ +static void hdd_dcc_update_ndl_callback(void *context_ptr, void *response_ptr) +{ + struct osif_request *request; + struct hdd_dcc_update_ndl_priv *priv; + struct ocb_dcc_update_ndl_response *response = response_ptr; + + request = osif_request_get(context_ptr); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + if (response && (0 == response->status)) + priv->status = 0; + else + priv->status = -EINVAL; + + osif_request_complete(request); + osif_request_put(request); +} + +/** + * __wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +static int __wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1]; + struct ocb_dcc_update_ndl_param dcc_request; + uint32_t channel_count; + uint32_t ndl_channel_array_len; + void *ndl_channel_array; + uint32_t ndl_active_state_array_len; + void *ndl_active_state_array; + int rc; + QDF_STATUS status; + void *cookie; + struct osif_request *request; + struct hdd_dcc_update_ndl_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_OCB_CMD, + }; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + rc = wlan_hdd_validate_context(hdd_ctx); + if (rc) + return rc; + + if (adapter->device_mode != QDF_OCB_MODE) { + hdd_err("Device not in OCB mode!"); + return -EINVAL; + } + + if (!wma_is_vdev_up(adapter->deflink->vdev_id)) { + hdd_err("The device has not been started"); + return -EINVAL; + } + + /* Parse the netlink message */ + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX, + data, data_len, + qca_wlan_vendor_dcc_update_ndl)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + /* Verify that the parameter is present */ + if (!tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY] || + !tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]) { + hdd_err("Parameters are not present."); + return -EINVAL; + } + + channel_count = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT]); + ndl_channel_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]); + ndl_channel_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY]); + ndl_active_state_array_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]); + ndl_active_state_array = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY]); + + /* Check channel count. Per 11p spec, max 2 channels allowed */ + if (!channel_count || channel_count > CFG_TGT_NUM_OCB_CHANNELS) { + hdd_err("Invalid channel_count %d", channel_count); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + /* Copy the parameters to the request structure. */ + dcc_request.vdev_id = adapter->deflink->vdev_id; + dcc_request.channel_count = channel_count; + dcc_request.dcc_ndl_chan_list_len = ndl_channel_array_len; + dcc_request.dcc_ndl_chan_list = ndl_channel_array; + dcc_request.dcc_ndl_active_state_list_len = ndl_active_state_array_len; + dcc_request.dcc_ndl_active_state_list = ndl_active_state_array; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_OCB_ID); + if (!vdev) { + rc = -EINVAL; + goto end; + } + + status = ucfg_ocb_dcc_update_ndl(vdev, &dcc_request, + hdd_dcc_update_ndl_callback, + cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_OCB_ID); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to update NDL."); + rc = qdf_status_to_os_return(status); + goto end; + } + + /* Wait for the function to complete. */ + rc = osif_request_wait_for_response(request); + if (rc) { + hdd_err("Operation timed out"); + goto end; + } + + priv = osif_request_priv(request); + rc = priv->status; + if (rc) { + hdd_err("Operation failed: %d", rc); + goto end; + } + +end: + osif_request_put(request); + + return rc; +} + +/** + * wlan_hdd_cfg80211_dcc_update_ndl() - Interface for update dcc cmd + * @wiphy: pointer to the wiphy + * @wdev: pointer to the wdev + * @data: The netlink data + * @data_len: The length of the netlink data in bytes + * + * Return: 0 on success. + */ +int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_dcc_update_ndl(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_dcc_stats_event_callback() - Callback to get stats event + * @context_ptr: request context + * @response_ptr: response data + */ +static void wlan_hdd_dcc_stats_event_callback(void *context_ptr, + void *response_ptr) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)context_ptr; + struct ocb_dcc_get_stats_response *resp = response_ptr; + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT_INDEX; + + hdd_enter(); + + vendor_event = + wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + sizeof(uint32_t) + + resp->channel_stats_array_len + + NLMSG_HDRLEN, + index, GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + resp->num_channels) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + resp->channel_stats_array_len, + resp->channel_stats_array)) { + hdd_err("nla put failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +/** + * wlan_hdd_dcc_register_for_dcc_stats_event() - Register for dcc stats events + * @hdd_ctx: hdd context + */ +void wlan_hdd_dcc_register_for_dcc_stats_event(struct hdd_context *hdd_ctx) +{ + int rc; + + rc = ucfg_ocb_register_for_dcc_stats_event(hdd_ctx->pdev, hdd_ctx, + wlan_hdd_dcc_stats_event_callback); + if (rc) + hdd_err("Register DCC stats callback failed: %d", rc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h new file mode 100644 index 0000000000..d9d35542ea --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ocb.h @@ -0,0 +1,513 @@ +/* + * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_OCB_H +#define __WLAN_HDD_OCB_H + +#include +#include "sir_api.h" + +#define WLAN_OCB_CHANNEL_MAX 5 + +/** + * struct ocb_qos_params - QoS Parameters for each AC + * @aifsn: Arbitration Inter-Frame Spacing + * @cwmin: Contention Window (Min) + * @cwmax: Contention Window (Max) + */ +struct ocb_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct ocb_channel - Parameters for each OCB channel + * @channel_freq: Channel Center Frequency (MHz) + * @duration: Channel Duration (ms) + * @start_guard_interval: Start Guard Interval (ms) + * @channel_bandwidth: Channel Bandwidth (MHz) + * @tx_power: Transmit Power (1/2 dBm) + * @tx_rate: Transmit Data Rate (mbit) + * @qos_params: Array of QoS Parameters + * @per_packet_rx_stats: Enable per packet RX statistics + */ +struct ocb_channel { + uint32_t channel_freq; + uint32_t duration; + uint32_t start_guard_interval; + uint32_t channel_bandwidth; + uint32_t tx_power; + uint32_t tx_rate; + struct ocb_qos_params qos_params[QCA_WLAN_AC_ALL]; + uint32_t per_packet_rx_stats; +}; + +/** + * struct dot11p_channel_sched - OCB channel schedule + * @num_channels: Number of channels + * @channels: Array of channel parameters + * @off_channel_tx: Enable off channel TX + */ +struct dot11p_channel_sched { + uint32_t num_channels; + struct ocb_channel channels[WLAN_OCB_CHANNEL_MAX]; + uint32_t off_channel_tx; +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_config - vendor subcmd to set ocb config + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT: + * number of channels in the configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE: size of the schedule + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY: array of channels + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY: + * array of channels to be scheduled + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY: + * array of NDL channel information + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY: + * array of NDL active state configuration + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS: + * flag to set the absolute expiry + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_ocb_set_config { + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_SIZE, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_SCHEDULE_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_NDL_ACTIVE_STATE_ARRAY, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_FLAGS, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_set_utc_time - vendor subcmd to set UTC time + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE: + * the UTC time as an array of 10 bytes + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR: + * the time error as an array of 5 bytes + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_ocb_set_utc_time { + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_VALUE, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_ERROR, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_start_timing_advert - vendor subcmd to start + * sending timing advert + * frames + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ: + * channel frequency on which to send the frames + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE: + * number of times the frame is sent in 5 seconds + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST: + * number of enumerators + * @QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_ocb_start_timing_advert { + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_CHANNEL_FREQ, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_REPEAT_RATE, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_stop_timing_advert - vendor subcmd to stop + * timing advert + * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ: + * the channel frequency on which to stop the timing advert + * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST: + * number of enumerators + * @QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_ocb_stop_timing_advert { + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_CHANNEL_FREQ, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_ocb_get_tsf_resp - vendor subcmd to get TSF + * timer value + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH: + * higher 32 bits of the timer + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW: + * lower 32 bits of the timer + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_ocb_get_tsf_resp { + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_HIGH, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_TIMER_LOW, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_OCB_GET_TSF_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_stats - vendor subcmd to get + * dcc stats + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT: + * the number of channels in the request array + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY: + * array of the channel and information being requested + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_dcc_get_stats { + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_REQUEST_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_get_stats_resp - response event from get + * dcc stats + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT: + * the number of channels in the request array + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY: + * array of the information being requested + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_dcc_get_stats_resp { + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_STATS_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_RESP_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_clear_stats - vendor subcmd to clear DCC stats + * @QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP: + * mask of the type of stats to be cleared + * @QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_dcc_clear_stats { + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_BITMAP, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_AFTER_LAST - 1, +}; + +/** + * enum qca_wlan_vendor_attr_dcc_update_ndl - vendor subcmd to update dcc + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_INVALID: invalid value + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT: + * number of channels in the configuration + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY: the array of NDL + * channel info + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY: the array of + * NDL active states + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST: number of enumerators + * @QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX: last enumerator + */ +enum qca_wlan_vendor_attr_dcc_update_ndl { + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_INVALID = 0, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_COUNT, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_CHANNEL_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_ACTIVE_STATE_ARRAY, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST, + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX = + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_AFTER_LAST - 1, +}; + +struct hdd_context; + +#ifdef WLAN_WEXT_SUPPORT_ENABLE + +#ifdef WLAN_FEATURE_DSRC +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra); + +extern const struct nla_policy qca_wlan_vendor_ocb_set_config_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX + 1]; +extern const struct nla_policy qca_wlan_vendor_ocb_set_utc_time_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX + 1]; +extern const struct nla_policy qca_wlan_vendor_ocb_start_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX + 1]; +extern const struct nla_policy qca_wlan_vendor_ocb_stop_timing_advert_policy[ + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX + 1]; +extern const struct nla_policy qca_wlan_vendor_dcc_get_stats[ + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX + 1]; +extern const struct nla_policy qca_wlan_vendor_dcc_clear_stats[ + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX + 1]; +extern const struct nla_policy qca_wlan_vendor_dcc_update_ndl[ + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX + 1]; + +#define FEATURE_OCB_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ocb_set_config, \ + vendor_command_policy(qca_wlan_vendor_ocb_set_config_policy, \ + QCA_WLAN_VENDOR_ATTR_OCB_SET_CONFIG_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ocb_set_utc_time, \ + vendor_command_policy(qca_wlan_vendor_ocb_set_utc_time_policy, \ + QCA_WLAN_VENDOR_ATTR_OCB_SET_UTC_TIME_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ocb_start_timing_advert, \ + vendor_command_policy( \ + qca_wlan_vendor_ocb_start_timing_advert_policy, \ + QCA_WLAN_VENDOR_ATTR_OCB_START_TIMING_ADVERT_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ocb_stop_timing_advert, \ + vendor_command_policy( \ + qca_wlan_vendor_ocb_stop_timing_advert_policy, \ + QCA_WLAN_VENDOR_ATTR_OCB_STOP_TIMING_ADVERT_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ocb_get_tsf_timer, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_dcc_get_stats, \ + vendor_command_policy(qca_wlan_vendor_dcc_get_stats, \ + QCA_WLAN_VENDOR_ATTR_DCC_GET_STATS_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_dcc_clear_stats, \ + vendor_command_policy(qca_wlan_vendor_dcc_clear_stats, \ + QCA_WLAN_VENDOR_ATTR_DCC_CLEAR_STATS_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_dcc_update_ndl, \ + vendor_command_policy(qca_wlan_vendor_dcc_update_ndl, \ + QCA_WLAN_VENDOR_ATTR_DCC_UPDATE_NDL_MAX) \ +}, + +#else +#define FEATURE_OCB_VENDOR_COMMANDS + +static inline +int iw_set_dot11p_channel_sched(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return 0; +} +#endif +#else +#define FEATURE_OCB_VENDOR_COMMANDS +#endif + +#ifdef WLAN_FEATURE_DSRC +int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void wlan_hdd_dcc_register_for_dcc_stats_event(struct hdd_context *hdd_ctx); + +void wlan_hdd_dcc_stats_event(void *context_ptr, void *response_ptr); +#else +static inline int wlan_hdd_cfg80211_ocb_set_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_set_utc_time(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_start_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_stop_timing_advert(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_ocb_get_tsf_timer(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_dcc_get_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_dcc_clear_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline int wlan_hdd_cfg80211_dcc_update_ndl(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return 0; +} + +static inline void wlan_hdd_dcc_register_for_dcc_stats_event( + struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_dcc_stats_event(void *context_ptr, + void *response_ptr) +{ +} +#endif + +#endif /* __WLAN_HDD_OCB_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c new file mode 100644 index 0000000000..5a9cec5c4a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_oemdata.c @@ -0,0 +1,1498 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_oemdata.c + * + * Support for generic OEM Data Request handling + * + */ + +#if defined(FEATURE_OEM_DATA_SUPPORT) || defined(FEATURE_OEM_DATA) +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include "qwlan_version.h" +#include "cds_utils.h" +#include "wma.h" +#include "sme_api.h" +#include "wlan_nlink_srv.h" +#include "wlan_hdd_oemdata.h" +#include "wlan_osif_request_manager.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_sysfs.h" + +#ifdef FEATURE_OEM_DATA_SUPPORT +#ifdef CNSS_GENL +#include +#endif + +static struct hdd_context *p_hdd_ctx; + +/** + * populate_oem_data_cap() - populate oem capabilities + * @adapter: device adapter + * @data_cap: pointer to populate the capabilities + * + * Return: error code + */ +static int populate_oem_data_cap(struct hdd_adapter *adapter, + struct oem_data_cap *data_cap) +{ + QDF_STATUS status; + struct hdd_config *config; + uint32_t num_chan, i; + uint32_t *chan_freq_list; + uint8_t band_capability; + uint32_t band_bitmap; + uint16_t neighbor_scan_min_chan_time; + uint16_t neighbor_scan_max_chan_time; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + config = hdd_ctx->config; + if (!config) { + hdd_err("HDD configuration is null"); + return -EINVAL; + } + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_bitmap); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get MLME band capability"); + return -EIO; + } + + band_capability = wlan_reg_band_bitmap_to_band_info(band_bitmap); + + chan_freq_list = + qdf_mem_malloc(sizeof(uint32_t) * OEM_CAP_MAX_NUM_CHANNELS); + if (!chan_freq_list) + return -ENOMEM; + + strlcpy(data_cap->oem_target_signature, OEM_TARGET_SIGNATURE, + OEM_TARGET_SIGNATURE_LEN); + data_cap->oem_target_type = hdd_ctx->target_type; + data_cap->oem_fw_version = hdd_ctx->target_fw_version; + data_cap->driver_version.major = QWLAN_VERSION_MAJOR; + data_cap->driver_version.minor = QWLAN_VERSION_MINOR; + data_cap->driver_version.patch = QWLAN_VERSION_PATCH; + data_cap->driver_version.build = QWLAN_VERSION_BUILD; + ucfg_mlme_get_neighbor_scan_max_chan_time(psoc, + &neighbor_scan_max_chan_time); + ucfg_mlme_get_neighbor_scan_min_chan_time(psoc, + &neighbor_scan_min_chan_time); + data_cap->allowed_dwell_time_min = neighbor_scan_min_chan_time; + data_cap->allowed_dwell_time_max = neighbor_scan_max_chan_time; + data_cap->curr_dwell_time_min = + ucfg_cm_get_neighbor_scan_min_chan_time( + hdd_ctx->psoc, adapter->deflink->vdev_id); + data_cap->curr_dwell_time_max = + ucfg_cm_get_neighbor_scan_max_chan_time( + hdd_ctx->psoc, adapter->deflink->vdev_id); + data_cap->supported_bands = band_capability; + + /* request for max num of channels */ + num_chan = OEM_CAP_MAX_NUM_CHANNELS; + status = sme_get_cfg_valid_channels(&chan_freq_list[0], &num_chan); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("failed to get valid channel list, status: %d", status); + qdf_mem_free(chan_freq_list); + return -EINVAL; + } + + /* make sure num channels is not more than chan list array */ + if (num_chan > OEM_CAP_MAX_NUM_CHANNELS) { + hdd_err("Num of channels-%d > length-%d of chan_freq_list", + num_chan, OEM_CAP_MAX_NUM_CHANNELS); + qdf_mem_free(chan_freq_list); + return -ENOMEM; + } + + data_cap->num_channels = num_chan; + for (i = 0; i < num_chan; i++) { + data_cap->channel_list[i] = + wlan_reg_freq_to_chan(hdd_ctx->pdev, chan_freq_list[i]); + } + + qdf_mem_free(chan_freq_list); + return 0; +} + +/** + * iw_get_oem_data_cap() - Get OEM Data Capabilities + * @dev: net device upon which the request was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl data payload + * + * This function gets the capability information for OEM Data Request + * and Response. + * + * Return: 0 for success, negative errno value on failure + */ +int iw_get_oem_data_cap(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct oem_data_cap *oem_data_cap = (void *)extra; + struct hdd_adapter *adapter = netdev_priv(dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + qdf_mem_zero(oem_data_cap, sizeof(*oem_data_cap)); + errno = populate_oem_data_cap(adapter, oem_data_cap); + if (errno) { + hdd_err("Failed to populate oem data capabilities"); + return errno; + } + + hdd_exit(); + return 0; +} + +/** + * send_oem_reg_rsp_nlink_msg() - send oem registration response + * + * This function sends oem message to registered application process + * + * Return: none + */ +static void send_oem_reg_rsp_nlink_msg(void) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *buf; + uint8_t *num_interfaces; + uint8_t *device_mode; + uint8_t *vdev_id; + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_SEND_OEM_REG_RSP_NLINK_MSG; + struct wlan_hdd_link_info *link_info; + + /* OEM msg is always to a specific process & cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + hdd_err("invalid dest pid"); + return; + } + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (!skb) + return; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_APP_REG_RSP; + + /* Fill message body: + * First byte will be number of interfaces, followed by + * two bytes for each interfaces + * - one byte for device mode + * - one byte for vdev id + */ + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + num_interfaces = buf++; + *num_interfaces = 0; + + /* Iterate through each adapter and fill device mode and vdev id */ + hdd_for_each_adapter_dev_held_safe(p_hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + device_mode = buf++; + vdev_id = buf++; + *device_mode = adapter->device_mode; + *vdev_id = link_info->vdev_id; + (*num_interfaces)++; + hdd_debug("num_interfaces: %d, device_mode: %d, vdev_id: %d", + *num_interfaces, *device_mode, *vdev_id); + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + ani_hdr->length = + sizeof(uint8_t) + (*num_interfaces) * 2 * sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + + hdd_debug("sending App Reg Response length: %d to pid: %d", + ani_hdr->length, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); +} + +/** + * send_oem_err_rsp_nlink_msg() - send oem error response + * @app_pid: PID of oem application process + * @error_code: response error code + * + * This function sends error response to oem app + * + * Return: none + */ +static void send_oem_err_rsp_nlink_msg(int32_t app_pid, uint8_t error_code) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *buf; + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (!skb) + return; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_OEM_ERROR; + ani_hdr->length = sizeof(uint8_t); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length); + + /* message body will contain one byte of error code */ + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + *buf = error_code; + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length)); + + hdd_debug("sending oem error response to pid: %d", app_pid); + + (void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT); +} + +/** + * hdd_send_oem_data_rsp_msg() - send oem data response + * @oem_data_rsp: the actual OEM Data Response message + * + * This function sends an OEM Data Response message to a registered + * application process over the netlink socket. + * + * Return: 0 for success, non zero for failure + */ +void hdd_send_oem_data_rsp_msg(struct oem_data_rsp *oem_data_rsp) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *oem_data; + + /* + * OEM message is always to a specific process and cannot be a broadcast + */ + if (p_hdd_ctx->oem_pid == 0) { + hdd_err("invalid dest pid"); + return; + } + + if (oem_data_rsp->rsp_len > OEM_DATA_RSP_SIZE) { + hdd_err("invalid length of Oem Data response"); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + OEM_DATA_RSP_SIZE), + GFP_KERNEL); + if (!skb) + return; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_OEM_DATA_RSP; + + ani_hdr->length = oem_data_rsp->rsp_len; + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + oem_data = (uint8_t *) ((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_copy(oem_data, oem_data_rsp->data, oem_data_rsp->rsp_len); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + + hdd_debug("sending Oem Data Response of len : %d to pid: %d", + oem_data_rsp->rsp_len, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); +} + +/** + * oem_process_data_req_msg() - process oem data request + * @oem_data_len: Length to OEM Data buffer + * @oem_data: Pointer to OEM Data buffer + * + * This function sends oem message to SME + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS oem_process_data_req_msg(int oem_data_len, char *oem_data) +{ + struct oem_data_req oem_data_req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* for now, STA interface only */ + if (!hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE) && + !hdd_get_adapter(p_hdd_ctx, QDF_SAP_MODE)) { + hdd_err("No adapter for STA or SAP mode"); + return QDF_STATUS_E_FAILURE; + } + + if (!oem_data) { + hdd_err("oem_data is null"); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&oem_data_req, sizeof(oem_data_req)); + + oem_data_req.data = qdf_mem_malloc(oem_data_len); + if (!oem_data_req.data) + return QDF_STATUS_E_NOMEM; + + oem_data_req.data_len = oem_data_len; + qdf_mem_copy(oem_data_req.data, oem_data, oem_data_len); + + status = sme_oem_req_cmd(p_hdd_ctx->mac_handle, &oem_data_req); + + qdf_mem_free(oem_data_req.data); + oem_data_req.data = NULL; + + return status; +} + +void hdd_update_channel_bw_info(struct hdd_context *hdd_ctx, + uint32_t chan_freq, void *chan_info) +{ + struct ch_params ch_params = {0}; + enum wlan_phymode phy_mode; + uint16_t fw_phy_mode; + uint32_t wni_dot11_mode; + struct hdd_channel_info *hdd_chan_info = chan_info; + + wni_dot11_mode = sme_get_wni_dot11_mode(hdd_ctx->mac_handle); + + /* Passing CH_WIDTH_MAX will give the max bandwidth supported */ + ch_params.ch_width = CH_WIDTH_MAX; + + wlan_reg_set_channel_params_for_pwrmode( + hdd_ctx->pdev, chan_freq, 0, &ch_params, REG_CURRENT_PWR_MODE); + if (ch_params.center_freq_seg0) + hdd_chan_info->band_center_freq1 = + cds_chan_to_freq(ch_params.center_freq_seg0); + + if (ch_params.ch_width < CH_WIDTH_INVALID) { + phy_mode = wma_chan_phy_mode(chan_freq, ch_params.ch_width, + wni_dot11_mode); + } + else + /* + * If channel width is CH_WIDTH_INVALID, It mean channel is + * invalid and should not have been received in channel info + * req. Set invalid phymode in this case. + */ + phy_mode = WLAN_PHYMODE_AUTO; + + fw_phy_mode = wmi_host_to_fw_phymode(phy_mode); + + hdd_debug("chan %d dot11_mode %d ch_width %d sec offset %d freq_seg0 %d phy_mode %d fw_phy_mode %d", + chan_freq, wni_dot11_mode, ch_params.ch_width, + ch_params.sec_ch_offset, + hdd_chan_info->band_center_freq1, phy_mode, fw_phy_mode); + + WMI_SET_CHANNEL_MODE(hdd_chan_info, fw_phy_mode); +} + +/** + * oem_process_channel_info_req_msg() - process oem channel_info request + * @numOfChannels: number of channels + * @chanList: list of channel information + * + * This function responds with channel info to oem process + * + * Return: 0 for success, non zero for failure + */ +static int oem_process_channel_info_req_msg(int numOfChannels, char *chanList) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + struct hdd_channel_info *pHddChanInfo; + struct hdd_channel_info hddChanInfo; + uint32_t reg_info_1; + uint32_t reg_info_2; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + uint8_t *buf; + uint32_t chan_freq; + + /* OEM msg is always to a specific process and cannot be a broadcast */ + if (p_hdd_ctx->oem_pid == 0) { + hdd_err("invalid dest pid"); + return -EPERM; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(uint8_t) + + numOfChannels * sizeof(*pHddChanInfo)), + GFP_KERNEL); + if (!skb) + return -ENOMEM; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_CHANNEL_INFO_RSP; + + ani_hdr->length = + sizeof(uint8_t) + numOfChannels * sizeof(*pHddChanInfo); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + + /* First byte of message body will have num of channels */ + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + *buf++ = numOfChannels; + + /* Next follows channel info struct for each channel id. + * If chan id is wrong or SME returns failure for a channel + * then fill in 0 in channel info for that particular channel + */ + for (i = 0; i < numOfChannels; i++) { + pHddChanInfo = (struct hdd_channel_info *) ((char *)buf + + i * + sizeof(*pHddChanInfo)); + + chan_freq = wlan_reg_legacy_chan_to_freq( + p_hdd_ctx->pdev, chanList[i]); + status = sme_get_reg_info(p_hdd_ctx->mac_handle, chan_freq, + ®_info_1, ®_info_2); + if (QDF_STATUS_SUCCESS == status) { + /* copy into hdd chan info struct */ + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = chan_freq; + hddChanInfo.band_center_freq1 = hddChanInfo.mhz; + hddChanInfo.band_center_freq2 = 0; + + hddChanInfo.info = 0; + if (CHANNEL_STATE_DFS == + wlan_reg_get_channel_state_for_pwrmode( + p_hdd_ctx->pdev, chan_freq, + REG_CURRENT_PWR_MODE)) + WMI_SET_CHANNEL_FLAG(&hddChanInfo, + WMI_CHAN_FLAG_DFS); + + hdd_update_channel_bw_info(p_hdd_ctx, + chan_freq, &hddChanInfo); + hddChanInfo.reg_info_1 = reg_info_1; + hddChanInfo.reg_info_2 = reg_info_2; + } else { + /* channel info is not returned, fill in zeros in + * channel info struct + */ + hdd_debug("sme_get_reg_info failed for chan: %d, fill 0s", + chan_freq); + hddChanInfo.reserved0 = 0; + hddChanInfo.mhz = chan_freq; + hddChanInfo.band_center_freq1 = 0; + hddChanInfo.band_center_freq2 = 0; + hddChanInfo.info = 0; + hddChanInfo.reg_info_1 = 0; + hddChanInfo.reg_info_2 = 0; + } + qdf_mem_copy(pHddChanInfo, &hddChanInfo, + sizeof(*pHddChanInfo)); + } + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + + hdd_debug("sending channel info resp for num channels (%d) to pid (%d)", + numOfChannels, p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + + return 0; +} + +/** + * oem_process_set_cap_req_msg() - process oem set capability request + * @oem_cap_len: Length of OEM capability + * @oem_cap: Pointer to OEM capability buffer + * @app_pid: process ID, to which rsp message is to be sent + * + * This function sends oem message to SME + * + * Return: error code + */ +static int oem_process_set_cap_req_msg(int oem_cap_len, + char *oem_cap, int32_t app_pid) +{ + QDF_STATUS status; + int error_code; + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *buf; + + if (!oem_cap) { + hdd_err("oem_cap is null"); + return -EINVAL; + } + + status = sme_oem_update_capability(p_hdd_ctx->mac_handle, + (struct sme_oem_capability *)oem_cap); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("error updating rm capability, status: %d", status); + error_code = qdf_status_to_os_return(status); + + skb = alloc_skb(NLMSG_SPACE(WLAN_NL_MAX_PAYLOAD), GFP_KERNEL); + if (!skb) + return -ENOMEM; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_SET_OEM_CAP_RSP; + /* 64 bit alignment */ + ani_hdr->length = sizeof(error_code); + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(tAniMsgHdr) + ani_hdr->length); + + /* message body will contain only status code */ + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_copy(buf, &error_code, ani_hdr->length); + + skb_put(skb, NLMSG_SPACE(sizeof(tAniMsgHdr) + ani_hdr->length)); + + hdd_debug("sending oem response to pid %d", app_pid); + + (void)nl_srv_ucast_oem(skb, app_pid, MSG_DONTWAIT); + + return error_code; +} + +/** + * oem_process_get_cap_req_msg() - process oem get capability request + * + * This function process the get capability request from OEM and responds + * with the capability. + * + * Return: error code + */ +static int oem_process_get_cap_req_msg(void) +{ + int error_code; + struct oem_get_capability_rsp *cap_rsp; + struct oem_data_cap data_cap = { {0} }; + struct sme_oem_capability oem_cap; + struct hdd_adapter *adapter; + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + uint8_t *buf; + + /* for now, STA interface only */ + adapter = hdd_get_adapter(p_hdd_ctx, QDF_STA_MODE); + if (!adapter) { + hdd_err("No adapter for STA mode"); + return -EINVAL; + } + + error_code = populate_oem_data_cap(adapter, &data_cap); + if (0 != error_code) + return error_code; + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + sizeof(*cap_rsp)), + GFP_KERNEL); + if (!skb) + return -ENOMEM; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_GET_OEM_CAP_RSP; + + ani_hdr->length = sizeof(*cap_rsp); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + + buf = (char *)((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_copy(buf, &data_cap, sizeof(data_cap)); + + buf = (char *) buf + sizeof(data_cap); + qdf_mem_zero(&oem_cap, sizeof(oem_cap)); + sme_oem_get_capability(p_hdd_ctx->mac_handle, &oem_cap); + qdf_mem_copy(buf, &oem_cap, sizeof(oem_cap)); + + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + hdd_info("send rsp to oem-pid:%d for get_capability", + p_hdd_ctx->oem_pid); + + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); + return 0; +} + +void hdd_send_peer_status_ind_to_oem_app(struct qdf_mac_addr *peer_mac, + uint8_t peer_status, + uint8_t peer_capability, + uint8_t vdev_id, + struct oem_channel_info *chan_info, + enum QDF_OPMODE dev_mode) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + tAniMsgHdr *ani_hdr; + struct peer_status_info *peer_info; + + if (!p_hdd_ctx) { + hdd_err("HDD Ctx is null"); + return; + } + + /* check if oem app has registered and pid is valid */ + if ((!p_hdd_ctx->oem_app_registered) || (p_hdd_ctx->oem_pid == 0)) { + hdd_info("OEM app is not registered(%d) or pid is invalid(%d)", + p_hdd_ctx->oem_app_registered, + p_hdd_ctx->oem_pid); + return; + } + + skb = alloc_skb(NLMSG_SPACE(sizeof(tAniMsgHdr) + + sizeof(*peer_info)), + GFP_KERNEL); + if (!skb) + return; + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; /* from kernel */ + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_OEM; + ani_hdr = NLMSG_DATA(nlh); + ani_hdr->type = ANI_MSG_PEER_STATUS_IND; + + ani_hdr->length = sizeof(*peer_info); + nlh->nlmsg_len = NLMSG_LENGTH((sizeof(tAniMsgHdr) + ani_hdr->length)); + + peer_info = (struct peer_status_info *) ((char *)ani_hdr + sizeof(tAniMsgHdr)); + qdf_mem_zero(peer_info, sizeof(*peer_info)); + qdf_mem_copy(peer_info->peer_mac_addr, peer_mac->bytes, + sizeof(peer_mac->bytes)); + peer_info->peer_status = peer_status; + peer_info->vdev_id = vdev_id; + peer_info->peer_capability = peer_capability; + /* Set 0th bit of reserved0 for STA mode */ + if (QDF_STA_MODE == dev_mode) + peer_info->reserved0 |= 0x01; + + if (chan_info) { + peer_info->peer_chan_info.reserved0 = 0; + peer_info->peer_chan_info.mhz = chan_info->mhz; + peer_info->peer_chan_info.band_center_freq1 = + chan_info->band_center_freq1; + peer_info->peer_chan_info.band_center_freq2 = + chan_info->band_center_freq2; + peer_info->peer_chan_info.info = chan_info->info; + peer_info->peer_chan_info.reg_info_1 = chan_info->reg_info_1; + peer_info->peer_chan_info.reg_info_2 = chan_info->reg_info_2; + } + skb_put(skb, NLMSG_SPACE((sizeof(tAniMsgHdr) + ani_hdr->length))); + + hdd_info("sending peer " QDF_MAC_ADDR_FMT + " status(%d), peer_capability(%d), vdev_id(%d)," + " to oem app pid(%d), center freq 1 (%d), center freq 2 (%d)," + " info (0x%x), frequency (%d),reg info 1 (0x%x)," + " reg info 2 (0x%x)", + QDF_MAC_ADDR_REF(peer_mac->bytes), + peer_status, peer_capability, + vdev_id, p_hdd_ctx->oem_pid, + peer_info->peer_chan_info.band_center_freq1, + peer_info->peer_chan_info.band_center_freq2, + peer_info->peer_chan_info.info, + peer_info->peer_chan_info.mhz, + peer_info->peer_chan_info.reg_info_1, + peer_info->peer_chan_info.reg_info_2); + + (void)nl_srv_ucast_oem(skb, p_hdd_ctx->oem_pid, MSG_DONTWAIT); +} + +/** + * oem_app_reg_req_handler() - function to handle APP registration request + * from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_app_reg_req_handler(struct hdd_context *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + char *sign_str = NULL; + + /* Registration request is only allowed for Qualcomm Application */ + hdd_debug("Received App Req Req from App pid: %d len: %d", + pid, msg_hdr->length); + + sign_str = (char *)((char *)msg_hdr + sizeof(tAniMsgHdr)); + if ((OEM_APP_SIGNATURE_LEN == msg_hdr->length) && + (0 == strncmp(sign_str, OEM_APP_SIGNATURE_STR, + OEM_APP_SIGNATURE_LEN))) { + hdd_debug("Valid App Req Req from oem app pid: %d", pid); + + hdd_ctx->oem_app_registered = true; + hdd_ctx->oem_pid = pid; + send_oem_reg_rsp_nlink_msg(); + } else { + hdd_err("Invalid signature in App Reg Req from pid: %d", pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_SIGNATURE); + return -EPERM; + } + + return 0; +} + +/** + * oem_data_req_handler() - function to handle data_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_data_req_handler(struct hdd_context *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_debug("Received Oem Data Request length: %d from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hdd_err("OEM DataReq: app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || (OEM_DATA_REQ_SIZE < msg_hdr->length)) { + hdd_err("Invalid length (%d) in Oem Data Request", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + oem_process_data_req_msg(msg_hdr->length, + (char *) ((char *)msg_hdr + + sizeof(tAniMsgHdr))); + + return 0; +} + +/** + * oem_chan_info_req_handler() - function to handle chan_info_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_chan_info_req_handler(struct hdd_context *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_debug("Received channel info request, num channel(%d) from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* either oem app is not registered yet or pid is different */ + hdd_err("Chan InfoReq: app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + /* message length contains list of channel ids */ + if ((!msg_hdr->length) || + (CFG_VALID_CHANNEL_LIST_LEN < msg_hdr->length)) { + hdd_err("Invalid length (%d) in channel info request", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + oem_process_channel_info_req_msg(msg_hdr->length, + (char *)((char *)msg_hdr + sizeof(tAniMsgHdr))); + + return 0; +} + +/** + * oem_set_cap_req_handler() - function to handle set_cap_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_set_cap_req_handler(struct hdd_context *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_info("Received set oem cap req of length:%d from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* oem app is not registered yet or pid is different */ + hdd_err("set_oem_capability : app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + if ((!msg_hdr->length) || + (sizeof(struct sme_oem_capability) < msg_hdr->length)) { + hdd_err("Invalid length (%d) in set_oem_capability", + msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + oem_process_set_cap_req_msg(msg_hdr->length, (char *) + ((char *)msg_hdr + sizeof(tAniMsgHdr)), + pid); + return 0; +} + +/** + * oem_get_cap_req_handler() - function to handle get_cap_req from userspace + * @hdd_ctx: handle to HDD context + * @msg_hdr: pointer to ANI message header + * @pid: Process ID + * + * Return: 0 if success, error code otherwise + */ +static int oem_get_cap_req_handler(struct hdd_context *hdd_ctx, + tAniMsgHdr *msg_hdr, int pid) +{ + hdd_info("Rcvd get oem capability req - length:%d from pid: %d", + msg_hdr->length, pid); + + if ((!hdd_ctx->oem_app_registered) || + (pid != hdd_ctx->oem_pid)) { + /* oem app is not registered yet or pid is different */ + hdd_err("get_oem_capability : app not registered(%d) or incorrect pid(%d)", + hdd_ctx->oem_app_registered, pid); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_APP_NOT_REGISTERED); + return -EPERM; + } + + oem_process_get_cap_req_msg(); + return 0; +} + +/** + * oem_request_dispatcher() - OEM command dispatcher API + * @msg_hdr: ANI Message Header + * @pid: process id + * + * This API is used to dispatch the command from OEM depending + * on the type of the message received. + * + * Return: None + */ +static void oem_request_dispatcher(tAniMsgHdr *msg_hdr, int pid) +{ + switch (msg_hdr->type) { + case ANI_MSG_APP_REG_REQ: + oem_app_reg_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_OEM_DATA_REQ: + oem_data_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_CHANNEL_INFO_REQ: + oem_chan_info_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_SET_OEM_CAP_REQ: + oem_set_cap_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + case ANI_MSG_GET_OEM_CAP_REQ: + oem_get_cap_req_handler(p_hdd_ctx, msg_hdr, pid); + break; + + default: + hdd_err("Received Invalid message type (%d), length (%d)", + msg_hdr->type, msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_TYPE); + } +} + +#ifdef CNSS_GENL +/** + * oem_cmd_handler() - API to handle OEM commands + * @data: Pointer to data + * @data_len: length of the received data + * @ctx: Pointer to the context + * @pid: Process id + * + * This API handles the command from OEM application from user space and + * send back event to user space if necessary. + * + * Return: None + */ +static void oem_cmd_handler(const void *data, int data_len, void *ctx, int pid) +{ + tAniMsgHdr *msg_hdr; + int msg_len; + int ret; + struct nlattr *tb[CLD80211_ATTR_MAX + 1]; + + ret = wlan_hdd_validate_context(p_hdd_ctx); + if (ret) + return; + + /* + * audit note: it is ok to pass a NULL policy here since only + * one attribute is parsed and it is explicitly validated + */ + if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, + data, data_len, NULL)) { + hdd_err("Invalid ATTR"); + return; + } + + if (!tb[CLD80211_ATTR_DATA]) { + hdd_err("attr ATTR_DATA failed"); + return; + } + + msg_len = nla_len(tb[CLD80211_ATTR_DATA]); + if (msg_len < sizeof(*msg_hdr)) { + hdd_err("runt ATTR_DATA size %d", msg_len); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_NULL_MESSAGE_HEADER); + return; + } + + msg_hdr = nla_data(tb[CLD80211_ATTR_DATA]); + if (msg_len < (sizeof(*msg_hdr) + msg_hdr->length)) { + hdd_err("Invalid nl msg len %d, msg hdr len %d", + msg_len, msg_hdr->length); + send_oem_err_rsp_nlink_msg(pid, OEM_ERR_INVALID_MESSAGE_LENGTH); + return; + } + + oem_request_dispatcher(msg_hdr, pid); +} + +int oem_activate_service(struct hdd_context *hdd_ctx) +{ + p_hdd_ctx = hdd_ctx; + register_cld_cmd_cb(WLAN_NL_MSG_OEM, oem_cmd_handler, NULL); + return 0; +} + +int oem_deactivate_service(void) +{ + deregister_cld_cmd_cb(WLAN_NL_MSG_OEM); + return 0; +} +#else + +/* + * Callback function invoked by Netlink service for all netlink + * messages (from user space) addressed to WLAN_NL_MSG_OEM + */ + +/** + * oem_msg_callback() - callback invoked by netlink service + * @skb: skb with netlink message + * + * This function gets invoked by netlink service when a message + * is received from user space addressed to WLAN_NL_MSG_OEM + * + * Return: zero on success + * On error, error number will be returned. + */ +static int oem_msg_callback(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + tAniMsgHdr *msg_hdr; + int ret; + + nlh = (struct nlmsghdr *)skb->data; + if (!nlh) { + hdd_err("Netlink header null"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(p_hdd_ctx); + if (ret) + return ret; + + msg_hdr = NLMSG_DATA(nlh); + + if (!msg_hdr) { + hdd_err("Message header null"); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_NULL_MESSAGE_HEADER); + return -EPERM; + } + + if (nlh->nlmsg_len < + NLMSG_LENGTH(sizeof(tAniMsgHdr) + msg_hdr->length)) { + hdd_err("Invalid nl msg len, nlh->nlmsg_len (%d), msg_hdr->len (%d)", + nlh->nlmsg_len, msg_hdr->length); + send_oem_err_rsp_nlink_msg(nlh->nlmsg_pid, + OEM_ERR_INVALID_MESSAGE_LENGTH); + return -EPERM; + } + + oem_request_dispatcher(msg_hdr, nlh->nlmsg_pid); + return 0; +} + +static int __oem_msg_callback(struct sk_buff *skb) +{ + struct hdd_context *hdd_ctx = p_hdd_ctx; + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return errno; + + errno = oem_msg_callback(skb); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int oem_activate_service(struct hdd_context *hdd_ctx) +{ + p_hdd_ctx = hdd_ctx; + + /* Register the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + return nl_srv_register(WLAN_NL_MSG_OEM, __oem_msg_callback); +} + +int oem_deactivate_service(void) +{ + /* Deregister the msg handler for msgs addressed to WLAN_NL_MSG_OEM */ + return nl_srv_unregister(WLAN_NL_MSG_OEM, __oem_msg_callback); +} + +#endif +#endif + +#ifdef FEATURE_OEM_DATA +const struct nla_policy +oem_data_attr_policy[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA] = { + .type = NLA_BINARY, + .len = OEM_DATA_MAX_SIZE + }, + + [QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED] = {.type = NLA_FLAG}, +}; + +/** + * hdd_copy_file_name_and_oem_data() - Copy file name and oem data + * @hdd_ctx: pointer to hdd context + * @oem_event_data: oem event data param buffe + * + * Return: none + */ +static void hdd_copy_file_name_and_oem_data( + struct hdd_context *hdd_ctx, + const struct oem_data *oem_event_data) +{ + if (!oem_event_data->data_len || !oem_event_data->file_name_len) { + hdd_err("Invalid file name or data length"); + return; + } + + if (oem_event_data->data_len > HDD_MAX_OEM_DATA_LEN || + oem_event_data->file_name_len > HDD_MAX_FILE_NAME_LEN) { + hdd_err("Invalid oem data len %zu or file name len %d", + oem_event_data->data_len, + oem_event_data->file_name_len); + return; + } + qdf_mem_zero(hdd_ctx->oem_data, HDD_MAX_OEM_DATA_LEN); + qdf_mem_zero(hdd_ctx->file_name, HDD_MAX_FILE_NAME_LEN); + + qdf_mem_copy(hdd_ctx->oem_data, oem_event_data->data, + oem_event_data->data_len); + hdd_ctx->oem_data_len = oem_event_data->data_len; + + qdf_mem_copy(hdd_ctx->file_name, oem_event_data->file_name, + oem_event_data->file_name_len); +} + +void hdd_oem_event_async_cb(const struct oem_data *oem_event_data) +{ + struct sk_buff *vendor_event; + uint32_t len; + int ret; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct wireless_dev *wdev = NULL; + + hdd_enter(); + + if (!hdd_ctx) + return; + + if (oem_event_data->file_name) { + hdd_copy_file_name_and_oem_data(hdd_ctx, oem_event_data); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, oem_event_data->vdev_id); + if (link_info) + wdev = &link_info->adapter->wdev; + + len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN; + vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, len, + QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + ret = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA, + oem_event_data->data_len, oem_event_data->data); + if (ret) { + hdd_err("OEM event put fails status %d", ret); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + hdd_exit(); +} + +void hdd_oem_event_handler_cb(const struct oem_data *oem_event_data, + uint8_t vdev_id) +{ + struct sk_buff *vendor_event; + struct osif_request *request; + uint32_t len; + int ret; + struct oem_data *oem_data; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct hdd_adapter *hdd_adapter; + struct wireless_dev *wdev = NULL; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + if (!oem_event_data || !(oem_event_data->data)) { + hdd_err("Invalid oem event data"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return; + + hdd_adapter = link_info->adapter; + if (hdd_adapter->response_expected) { + request = osif_request_get(hdd_adapter->cookie); + if (!request) { + hdd_err("Invalid request"); + return; + } + + oem_data = osif_request_priv(request); + oem_data->data_len = oem_event_data->data_len; + oem_data->data = qdf_mem_malloc(oem_data->data_len); + if (!oem_data->data) { + osif_request_put(request); + return; + } + + qdf_mem_copy(oem_data->data, oem_event_data->data, + oem_data->data_len); + oem_data->vdev_id = link_info->vdev_id; + osif_request_complete(request); + osif_request_put(request); + } else { + wdev = &(hdd_adapter->wdev); + + len = nla_total_size(oem_event_data->data_len) + NLMSG_HDRLEN; + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, len, + QCA_NL80211_VENDOR_SUBCMD_OEM_DATA_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + ret = nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA, + oem_event_data->data_len, oem_event_data->data); + if (ret) { + hdd_err("OEM event put fails status %d", ret); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + } + sme_oem_event_deinit(hdd_ctx->mac_handle); + + hdd_exit(); +} + +/** + *wlan_hdd_free_oem_data: delete data of priv data + *@priv: osif request private data + * + *Return: void + */ +static void wlan_hdd_free_oem_data(void *priv) +{ + struct oem_data *local_priv = priv; + + if (!local_priv) + return; + + if (local_priv->data) { + qdf_mem_free(local_priv->data); + local_priv->data = NULL; + } +} + +/** + * __wlan_hdd_cfg80211_oem_data_handler() - the handler for oem data + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +static int +__wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t mac_id; + int ret; + struct sk_buff *skb = NULL; + struct oem_data oem_data = {0}; + struct oem_data *get_oem_data = NULL; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX + 1]; + struct osif_request *request = NULL; + struct oem_data *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_GET_OEM_DATA, + .dealloc = wlan_hdd_free_oem_data, + }; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + if (adapter->oem_data_in_progress) { + hdd_err("oem request already in progress"); + return -EBUSY; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_MAX, + data, data_len, oem_data_attr_policy)) { + hdd_err("Invalid attributes"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]) { + hdd_err("oem data is missing!"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO]) + oem_data.pdev_vdev_flag = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO]); + + if (oem_data.pdev_vdev_flag) { + status = policy_mgr_get_mac_id_by_session_id( + hdd_ctx->psoc, + adapter->deflink->vdev_id, + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get mac id failed"); + return -EINVAL; + } + oem_data.pdev_id = mac_id; + oem_data.is_host_pdev_id = true; + } + oem_data.data_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]); + if (!oem_data.data_len) { + hdd_err("oem data len is 0!"); + return -EINVAL; + } + oem_data.vdev_id = adapter->deflink->vdev_id; + oem_data.data = nla_data(tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA]); + + if (tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED]) + adapter->response_expected = nla_get_flag( + tb[QCA_WLAN_VENDOR_ATTR_OEM_DATA_RESPONSE_EXPECTED]); + + if (adapter->response_expected) { + int skb_len = 0; + + adapter->oem_data_in_progress = true; + qdf_runtime_pm_prevent_suspend( + &hdd_ctx->runtime_context.oem_data_cmd); + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("request allocation failure"); + ret = -ENOMEM; + goto err; + } + + adapter->cookie = osif_request_cookie(request); + + status = sme_oem_data_cmd(hdd_ctx->mac_handle, + hdd_oem_event_handler_cb, + &oem_data, adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failure while sending command to fw"); + ret = -EAGAIN; + goto err; + } + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Timedout while retrieving oem get data"); + goto err; + } + + get_oem_data = osif_request_priv(request); + if (!get_oem_data || !(get_oem_data->data)) { + hdd_err("invalid get_oem_data"); + ret = -EINVAL; + goto err; + } + + skb_len = NLMSG_HDRLEN + nla_total_size(get_oem_data->data_len); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + skb_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto err; + } + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA, + get_oem_data->data_len, get_oem_data->data)) { + hdd_err("nla put failure"); + wlan_cfg80211_vendor_free_skb(skb); + ret = -EINVAL; + goto err; + } + wlan_cfg80211_vendor_cmd_reply(skb); + + } else { + status = sme_oem_data_cmd(hdd_ctx->mac_handle, + hdd_oem_event_handler_cb, + &oem_data, adapter->deflink->vdev_id); + return qdf_status_to_os_return(status); + } + +err: + if (request) + osif_request_put(request); + adapter->oem_data_in_progress = false; + adapter->response_expected = false; + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.oem_data_cmd); + + return ret; + +} + +int wlan_hdd_cfg80211_oem_data_handler(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int ret; + + ret = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (ret) + return ret; + + ret = __wlan_hdd_cfg80211_oem_data_handler(wiphy, wdev, + data, data_len); + osif_vdev_sync_op_stop(vdev_sync); + + return ret; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ota_test.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ota_test.c new file mode 100644 index 0000000000..49fd97e797 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ota_test.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_ota_test.c + * + * WLAN OTA test functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include + +const struct nla_policy qca_wlan_vendor_ota_test_policy[ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE] = {.type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_set_ota_test() - enable/disable OTA test + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1]; + uint8_t ota_enable = 0; + QDF_STATUS status; + uint32_t current_roam_state; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx) != 0) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX, + data, data_len, + qca_wlan_vendor_ota_test_policy)) { + hdd_err("invalid attr"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]) { + hdd_err("attr ota test failed"); + return -EINVAL; + } + + ota_enable = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_OTA_TEST_ENABLE]); + + hdd_debug(" OTA test enable = %d", ota_enable); + if (ota_enable != 1) { + hdd_err("Invalid value, only enable test mode is supported!"); + return -EINVAL; + } + + mac_handle = hdd_ctx->mac_handle; + current_roam_state = sme_get_current_roam_state( + mac_handle, adapter->deflink->vdev_id); + status = sme_stop_roaming(mac_handle, adapter->deflink->vdev_id, + REASON_SME_ISSUED, RSO_INVALID_REQUESTOR); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable roaming failed"); + return -EINVAL; + } + + status = sme_ps_enable_disable(mac_handle, adapter->deflink->vdev_id, + SME_PS_DISABLE); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Enable/Disable power save failed"); + /* restore previous roaming setting */ + if (current_roam_state == eCSR_ROAMING_STATE_JOINING || + current_roam_state == eCSR_ROAMING_STATE_JOINED) + status = sme_start_roaming(mac_handle, + adapter->deflink->vdev_id, + REASON_SME_ISSUED, + RSO_INVALID_REQUESTOR); + else if (current_roam_state == eCSR_ROAMING_STATE_STOP || + current_roam_state == eCSR_ROAMING_STATE_IDLE) + status = sme_stop_roaming(mac_handle, + adapter->deflink->vdev_id, + REASON_SME_ISSUED, + RSO_INVALID_REQUESTOR); + + if (status != QDF_STATUS_SUCCESS) + hdd_err("Restoring roaming state failed"); + + return -EINVAL; + } + return 0; +} + +int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_ota_test(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ota_test.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ota_test.h new file mode 100644 index 0000000000..14dbc19f8a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_ota_test.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_OTA_TEST_H +#define __WLAN_HDD_OTA_TEST_H + +/** + * DOC: wlan_hdd_ota_test_h + * + * WLAN Host Device Driver OTA test API specification + */ + +#ifdef FEATURE_OTA_TEST + +extern const struct nla_policy qca_wlan_vendor_ota_test_policy[ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX + 1]; + +/** + * wlan_hdd_cfg80211_set_ota_test () - Enable or disable OTA test + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_set_ota_test(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_OTA_TEST_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_OTA_TEST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_ota_test, \ + vendor_command_policy(qca_wlan_vendor_ota_test_policy, \ + QCA_WLAN_VENDOR_ATTR_OTA_TEST_MAX)\ +}, +#else /* FEATURE_OTA_TEST */ +#define FEATURE_OTA_TEST_VENDOR_COMMANDS +#endif /* FEATURE_OTA_TEST */ + +#endif /* __WLAN_HDD_OTA_TEST_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c new file mode 100644 index 0000000000..1c70b0e0c7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p.c @@ -0,0 +1,1640 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_p2p.c + * + * WLAN Host Device Driver implementation for P2P commands interface + */ + +#include "osif_sync.h" +#include +#include +#include +#include "sme_api.h" +#include "sme_qos_api.h" +#include "wlan_hdd_p2p.h" +#include "sap_api.h" +#include "wlan_hdd_main.h" +#include "qdf_trace.h" +#include +#include +#include +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_trace.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_sched.h" +#include "wlan_policy_mgr_api.h" +#include "cds_utils.h" +#include "wlan_p2p_public_struct.h" +#include "wlan_p2p_ucfg_api.h" +#include "wlan_cfg80211_p2p.h" +#include "wlan_p2p_cfg_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include "nan_ucfg_api.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_hdd_pre_cac.h" +#include "wlan_pre_cac_ucfg_api.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_psoc_mlme_ucfg_api.h" +#include "os_if_dp_local_pkt_capture.h" + +/* Ms to Time Unit Micro Sec */ +#define MS_TO_TU_MUS(x) ((x) * 1024) +#define MAX_MUS_VAL (INT_MAX / 1024) + +/* Clean up RoC context at hdd_stop_adapter*/ +void +wlan_hdd_cleanup_remain_on_channel_ctx(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_P2P_ID); + if (!vdev) + return; + + ucfg_p2p_cleanup_roc_by_vdev(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); +} + +void wlan_hdd_cleanup_actionframe(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_P2P_ID); + if (!vdev) + return; + ucfg_p2p_cleanup_tx_by_vdev(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); +} + +static int __wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, + u64 *cookie) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + int ret; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + wlan_hdd_lpc_handle_concurrency(hdd_ctx, false); + if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc) && + !hdd_lpc_is_work_scheduled(hdd_ctx)) + return -EINVAL; + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_P2P_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + if (!wlan_is_scan_allowed(vdev)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_P2P_ID); + return -EBUSY; + } + + /* Disable NAN Discovery if enabled */ + ucfg_nan_disable_concurrency(hdd_ctx->psoc); + + status = wlan_cfg80211_roc(vdev, chan, duration, cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); + hdd_debug("remain on channel request, status:%d, cookie:0x%llx", + status, *cookie); + + return qdf_status_to_os_return(status); +} + +int wlan_hdd_cfg80211_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + unsigned int duration, u64 *cookie) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_remain_on_channel(wiphy, wdev, chan, + duration, cookie); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int +__wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + QDF_STATUS status; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_P2P_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + status = wlan_cfg80211_cancel_roc(vdev, cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); + + hdd_debug("cancel remain on channel, status:%d", status); + + return 0; +} + +int wlan_hdd_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_cancel_remain_on_channel(wiphy, wdev, + cookie); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define WLAN_AUTH_FRAME_MIN_LEN 2 +static int __wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +{ + QDF_STATUS status; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_vdev *vdev; + uint8_t type, sub_type; + uint16_t auth_algo; + QDF_STATUS qdf_status; + int ret; + uint32_t assoc_resp_len, ft_info_len = 0; + const uint8_t *assoc_resp; + void *ft_info; + struct hdd_ap_ctx *ap_ctx; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + type = WLAN_HDD_GET_TYPE_FRM_FC(buf[0]); + sub_type = WLAN_HDD_GET_SUBTYPE_FRM_FC(buf[0]); + hdd_debug("type %d, sub_type %d", type, sub_type); + + /* When frame to be transmitted is auth mgmt, then trigger + * sme_send_mgmt_tx to send auth frame without need for policy manager. + * Where as wlan_cfg80211_mgmt_tx requires roc and requires approval + * from policy manager. + */ + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE || + adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_NAN_DISC_MODE) && + (type == SIR_MAC_MGMT_FRAME && + sub_type == SIR_MAC_MGMT_AUTH)) { + /* Request ROC for PASN authentication frame */ + if (len > (sizeof(struct wlan_frame_hdr) + + WLAN_AUTH_FRAME_MIN_LEN)) { + auth_algo = + *(uint16_t *)(buf + + sizeof(struct wlan_frame_hdr)); + if (auth_algo == eSIR_AUTH_TYPE_PASN) + goto off_chan_tx; + if ((auth_algo == eSIR_FT_AUTH) && + (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + ap_ctx->during_auth_offload = false; + } + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_SME, + TRACE_CODE_HDD_SEND_MGMT_TX, + adapter->deflink->vdev_id, 0); + + qdf_status = sme_send_mgmt_tx(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + buf, len); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + return qdf_status_to_os_return(qdf_status); + else + return -EINVAL; + } + /* Only when SAP working on Fast BSS transition mode. Driver offload + * (re)assoc request to hostapd. Here driver receive (re)assoc response + * frame from hostapd. + */ + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + (type == SIR_MAC_MGMT_FRAME) && + (sub_type == SIR_MAC_MGMT_ASSOC_RSP || + sub_type == SIR_MAC_MGMT_REASSOC_RSP)) { + assoc_resp = &((struct ieee80211_mgmt *)buf)->u.assoc_resp.variable[0]; + assoc_resp_len = len - WLAN_ASSOC_RSP_IES_OFFSET + - sizeof(struct wlan_frame_hdr); + if (!wlan_get_ie_ptr_from_eid(DOT11F_EID_FTINFO, + assoc_resp, assoc_resp_len)) { + hdd_debug("No FT info in Assoc rsp, send it directly"); + goto off_chan_tx; + } + ft_info = hdd_filter_ft_info(assoc_resp, len, &ft_info_len); + if (!ft_info || !ft_info_len) + return -EINVAL; + hdd_debug("get ft_info_len from Assoc rsp :%d", ft_info_len); + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + qdf_status = wlansap_update_ft_info(ap_ctx->sap_context, + ((struct ieee80211_mgmt *)buf)->da, + ft_info, ft_info_len, 0); + qdf_mem_free(ft_info); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + return qdf_status_to_os_return(qdf_status); + else + return -EINVAL; + } + +off_chan_tx: + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_P2P_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_OS_IF, + TRACE_CODE_HDD_SEND_MGMT_TX, + wlan_vdev_get_id(vdev), 0); + + status = wlan_cfg80211_mgmt_tx(vdev, chan, offchan, wait, buf, + len, no_cck, dont_wait_for_ack, cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); + hdd_debug("device_mode:%d type:%d sub_type:%d chan:%d wait:%d offchan:%d do_not_wait_ack:%d mgmt tx, status:%d, cookie:0x%llx", + adapter->device_mode, type, sub_type, + chan ? chan->center_freq : 0, wait, offchan, + dont_wait_for_ack, status, *cookie); + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct cfg80211_mgmt_tx_params *params, u64 *cookie) +#else +int wlan_hdd_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const u8 *buf, size_t len, bool no_cck, + bool dont_wait_for_ack, u64 *cookie) +#endif /* LINUX_VERSION_CODE */ +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) + errno = __wlan_hdd_mgmt_tx(wiphy, wdev, params->chan, params->offchan, + params->wait, params->buf, params->len, + params->no_cck, params->dont_wait_for_ack, + cookie); +#else + errno = __wlan_hdd_mgmt_tx(wiphy, wdev, chan, offchan, + wait, buf, len, no_cck, + dont_wait_for_ack, cookie); +#endif /* LINUX_VERSION_CODE */ + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, + u64 cookie) +{ + QDF_STATUS status; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_P2P_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + status = wlan_cfg80211_mgmt_tx_cancel(vdev, cookie); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); + + hdd_debug("cancel mgmt tx, status:%d", status); + + return 0; +} + +int wlan_hdd_cfg80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, + struct wireless_dev *wdev, u64 cookie) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_mgmt_tx_cancel_wait(wiphy, wdev, cookie); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_set_p2p_noa() - Handle P2P_SET_NOA command + * @dev: Pointer to net device structure + * @command: Pointer to command + * + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_NOA command from wpa_supplicant using private ioctl + * + * This function will construct the NoA Struct According to P2P Power + * save Option and Pass it to SME layer + * + * Return: 0 on success, negative errno if error + */ + +int hdd_set_p2p_noa(struct net_device *dev, uint8_t *command) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct p2p_ps_config noa = {0}; + int count, duration, interval, start = 0; + char *param; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (!param) { + hdd_err("strnchr failed to find delimiter"); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d %d", &count, &start, &duration, + &interval); + if (ret < 3) { + hdd_err("P2P_SET GO noa: fail to read params, ret=%d", + ret); + return -EINVAL; + } + + if (ret == 3) + interval = 100; + + if (start < 0 || count < 0 || interval < 0 || duration < 0 || + start > MAX_MUS_VAL || interval > MAX_MUS_VAL || + duration > MAX_MUS_VAL) { + hdd_err("Invalid NOA parameters"); + return -EINVAL; + } + hdd_debug("P2P_SET GO noa: count=%d interval=%d duration=%d start=%d", + count, interval, duration, start); + duration = MS_TO_TU_MUS(duration); + interval = MS_TO_TU_MUS(interval); + /* PS Selection + * Periodic noa (2) + * Single NOA (4) + */ + noa.opp_ps = 0; + noa.ct_window = 0; + if (count == 1) { + if (duration > interval) + duration = interval; + noa.duration = 0; + noa.single_noa_duration = duration; + noa.ps_selection = P2P_POWER_SAVE_TYPE_SINGLE_NOA; + } else { + if (count && (duration >= interval)) { + hdd_err("Duration should be less than interval"); + return -EINVAL; + } + noa.duration = duration; + noa.single_noa_duration = 0; + noa.ps_selection = P2P_POWER_SAVE_TYPE_PERIODIC_NOA; + } + + noa.start = start; + noa.interval = interval; + noa.count = count; + noa.vdev_id = adapter->deflink->vdev_id; + + hdd_debug("P2P_PS_ATTR:opp ps %d ct window %d count %d interval %d " + "duration %d start %d single noa duration %d " + "ps selection %x", noa.opp_ps, noa.ct_window, noa.count, + noa.interval, noa.duration, noa.start, + noa.single_noa_duration, noa.ps_selection); + + return wlan_hdd_set_power_save(adapter, &noa); +} + +/** + * hdd_set_p2p_opps() - Handle P2P_SET_PS command + * @dev: Pointer to net device structure + * @command: Pointer to command + * + * This function is called from hdd_hostapd_ioctl function when Driver + * get P2P_SET_PS command from wpa_supplicant using private ioctl. + * + * This function will construct the NoA Struct According to P2P Power + * save Option and Pass it to SME layer + * + * Return: 0 on success, negative errno if error + */ + +int hdd_set_p2p_opps(struct net_device *dev, uint8_t *command) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct p2p_ps_config noa = {0}; + char *param; + int legacy_ps, opp_ps, ctwindow; + int ret; + + param = strnchr(command, strlen(command), ' '); + if (!param) { + hdd_err("strnchr failed to find delimiter"); + return -EINVAL; + } + param++; + ret = sscanf(param, "%d %d %d", &legacy_ps, &opp_ps, &ctwindow); + if (ret != 3) { + hdd_err("P2P_SET GO PS: fail to read params, ret=%d", ret); + return -EINVAL; + } + + if ((opp_ps != -1) && (opp_ps != 0) && (opp_ps != 1)) { + hdd_err("Invalid opp_ps value:%d", opp_ps); + return -EINVAL; + } + + /* P2P spec: 3.3.2 Power Management and discovery: + * CTWindow should be at least 10 TU. + * P2P spec: Table 27 - CTWindow and OppPS Parameters field format: + * CTWindow and OppPS Parameters together is 8 bits. + * CTWindow uses 7 bits (0-6, Bit 7 is for OppPS) + * 0 indicates that there shall be no CTWindow + */ + if ((ctwindow != -1) && (ctwindow != 0) && + (!((ctwindow >= 10) && (ctwindow <= 127)))) { + hdd_err("Invalid CT window value:%d", ctwindow); + return -EINVAL; + } + + hdd_debug("P2P_SET GO PS: legacy_ps=%d opp_ps=%d ctwindow=%d", + legacy_ps, opp_ps, ctwindow); + + /* PS Selection + * Opportunistic Power Save (1) + */ + + /* From wpa_cli user need to use separate command to set ct_window + * and Opps when user want to set ct_window during that time other + * parameters values are coming from wpa_supplicant as -1. + * Example : User want to set ct_window with 30 then wpa_cli command : + * P2P_SET ctwindow 30 + * Command Received at hdd_hostapd_ioctl is as below: + * P2P_SET_PS -1 -1 30 (legacy_ps = -1, opp_ps = -1, ctwindow = 30) + * + * e.g., 1: P2P_SET_PS 1 1 30 + * Driver sets the Opps and CTwindow as 30 and send it to FW. + * e.g., 2: P2P_SET_PS 1 -1 15 + * Driver caches the CTwindow value but not send the command to FW. + * e.g., 3: P2P_SET_PS 1 1 -1 + * Driver sends the command to FW with Opps enabled and CT window as + * 15 (last cached CTWindow value). + * (or) : P2P_SET_PS 1 1 20 + * Driver sends the command to FW with opps enabled and CT window + * as 20. + * + * legacy_ps param remains unused until required in the future. + */ + if (ctwindow != -1) + adapter->ctw = ctwindow; + + /* Send command to FW when OppPS is either enabled(1)/disabled(0) */ + if (opp_ps != -1) { + adapter->ops = opp_ps; + noa.opp_ps = adapter->ops; + noa.ct_window = adapter->ctw; + noa.duration = 0; + noa.single_noa_duration = 0; + noa.interval = 0; + noa.count = 0; + noa.ps_selection = P2P_POWER_SAVE_TYPE_OPPORTUNISTIC; + noa.vdev_id = adapter->deflink->vdev_id; + + hdd_debug("P2P_PS_ATTR: opp ps %d ct window %d duration %d interval %d count %d single noa duration %d ps selection %x", + noa.opp_ps, noa.ct_window, + noa.duration, noa.interval, noa.count, + noa.single_noa_duration, + noa.ps_selection); + + wlan_hdd_set_power_save(adapter, &noa); + } + + return 0; +} + +int hdd_set_p2p_ps(struct net_device *dev, void *msgData) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct p2p_ps_config noa = {0}; + struct p2p_app_set_ps *pappnoa = (struct p2p_app_set_ps *) msgData; + + noa.opp_ps = pappnoa->opp_ps; + noa.ct_window = pappnoa->ct_window; + noa.duration = pappnoa->duration; + noa.interval = pappnoa->interval; + noa.count = pappnoa->count; + noa.single_noa_duration = pappnoa->single_noa_duration; + noa.ps_selection = pappnoa->ps_selection; + noa.vdev_id = adapter->deflink->vdev_id; + + return wlan_hdd_set_power_save(adapter, &noa); +} + +bool hdd_allow_new_intf(struct hdd_context *hdd_ctx, + enum QDF_OPMODE mode) +{ + struct hdd_adapter *adapter = NULL; + struct hdd_adapter *next_adapter = NULL; + uint8_t num_active_adapter = 0; + + if (mode != QDF_SAP_MODE) + return true; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_ALLOW_NEW_INTF) { + if (hdd_is_interface_up(adapter) && + adapter->device_mode == mode) + num_active_adapter++; + + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_ALLOW_NEW_INTF); + } + + if (num_active_adapter >= QDF_MAX_NO_OF_SAP_MODE) + hdd_err("sap max allowed intf %d, curr %d", + QDF_MAX_NO_OF_SAP_MODE, num_active_adapter); + + return num_active_adapter < QDF_MAX_NO_OF_SAP_MODE; +} + +/** + * __wlan_hdd_add_virtual_intf() - Add virtual interface + * @wiphy: wiphy pointer + * @name: User-visible name of the interface + * @name_assign_type: the name of assign type of the netdev + * @type: (virtual) interface types + * @flags: monitor configuration flags + * @params: virtual interface parameters (not used) + * + * Return: the pointer of wireless dev, otherwise ERR_PTR. + */ +static +struct wireless_dev *__wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = NULL; + bool p2p_dev_addr_admin = false; + enum QDF_OPMODE mode; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + int ret; + struct hdd_adapter_create_param create_params = {0}; + uint8_t *device_address = NULL; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return ERR_PTR(-EINVAL); + } + + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) { + hdd_err("Concurrency not allowed with standalone monitor mode"); + return ERR_PTR(-EINVAL); + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ERR_PTR(ret); + + status = hdd_nl_to_qdf_iface_type(type, &mode); + if (QDF_IS_STATUS_ERROR(status)) + return ERR_PTR(qdf_status_to_os_return(status)); + + if (mode == QDF_MONITOR_MODE && + !(QDF_MONITOR_FLAG_OTHER_BSS & *flags) && + !os_if_lpc_mon_intf_creation_allowed(hdd_ctx->psoc)) + return ERR_PTR(-EOPNOTSUPP); + + wlan_hdd_lpc_handle_concurrency(hdd_ctx, true); + + if (policy_mgr_is_sta_mon_concurrency(hdd_ctx->psoc) && + !hdd_lpc_is_work_scheduled(hdd_ctx)) + return ERR_PTR(-EINVAL); + + if (wlan_hdd_is_mon_concurrency()) + return ERR_PTR(-EINVAL); + + if (!hdd_allow_new_intf(hdd_ctx, mode)) + return ERR_PTR(-EOPNOTSUPP); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_ADD_VIRTUAL_INTF, + NO_SESSION, type); + + switch (mode) { + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + case QDF_P2P_CLIENT_MODE: + case QDF_STA_MODE: + case QDF_MONITOR_MODE: + break; + default: + mode = QDF_STA_MODE; + break; + } + + create_params.is_add_virtual_iface = 1; + + adapter = hdd_get_adapter(hdd_ctx, QDF_STA_MODE); + if (adapter && !wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) { + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_P2P_ID); + if (vdev) { + if (ucfg_scan_get_vdev_status(vdev) != + SCAN_NOT_IN_PROGRESS) { + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + adapter->deflink->vdev_id, + INVALID_SCAN_ID, false); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_P2P_ID); + } else { + hdd_err("vdev is NULL"); + } + } + + adapter = NULL; + if (type == NL80211_IFTYPE_MONITOR) { + bool is_rx_mon = QDF_MONITOR_FLAG_OTHER_BSS & *flags; + + /* + * if QDF_MONITOR_FLAG_OTHER_BSS bit is set in monitor flags + * driver will assume current mode as STA + Monitor Mode. + * So if QDF_MONITOR_FLAG_OTHER_BSS bit is set in monitor + * interface flag STA+MON concurrency is not supported + * reject the request. + **/ + if ((ucfg_dp_is_local_pkt_capture_enabled(hdd_ctx->psoc) && + !is_rx_mon) || + (ucfg_mlme_is_sta_mon_conc_supported(hdd_ctx->psoc) && + is_rx_mon) || + ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + ret = wlan_hdd_add_monitor_check(hdd_ctx, + &adapter, name, true, + name_assign_type, + is_rx_mon); + if (ret) + return ERR_PTR(-EINVAL); + + ucfg_dp_set_mon_conf_flags(hdd_ctx->psoc, *flags); + + if (adapter) { + hdd_exit(); + return adapter->dev->ieee80211_ptr; + } + } else { + hdd_err("Adding monitor interface not supported"); + return ERR_PTR(-EINVAL); + } + } + + adapter = NULL; + cfg_p2p_get_device_addr_admin(hdd_ctx->psoc, &p2p_dev_addr_admin); + if (p2p_dev_addr_admin && + (mode == QDF_P2P_GO_MODE || mode == QDF_P2P_CLIENT_MODE)) { + /* + * Generate the P2P Interface Address. this address must be + * different from the P2P Device Address. + */ + struct qdf_mac_addr p2p_device_address = + hdd_ctx->p2p_device_address; + p2p_device_address.bytes[4] ^= 0x80; + adapter = hdd_open_adapter(hdd_ctx, mode, name, + p2p_device_address.bytes, + name_assign_type, true, + &create_params); + } else { + if (strnstr(name, "p2p", 3) && mode == QDF_STA_MODE) { + hdd_debug("change mode to p2p device"); + mode = QDF_P2P_DEVICE_MODE; + } + + device_address = wlan_hdd_get_intf_addr(hdd_ctx, mode); + if (!device_address) + return ERR_PTR(-EINVAL); + + adapter = hdd_open_adapter(hdd_ctx, mode, name, + device_address, + name_assign_type, true, + &create_params); + if (!adapter) + wlan_hdd_release_intf_addr(hdd_ctx, device_address); + } + + if (!adapter) { + hdd_err("hdd_open_adapter failed with iftype %d", type); + return ERR_PTR(-ENOSPC); + } + + adapter->delete_in_progress = false; + + /* ensure physical soc is up */ + ret = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (ret) { + hdd_err("Failed to start the wlan_modules"); + goto close_adapter; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (vdev) { + ucfg_dp_try_send_rps_ind(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + hdd_exit(); + + return adapter->dev->ieee80211_ptr; + +close_adapter: + if (device_address) + wlan_hdd_release_intf_addr(hdd_ctx, device_address); + hdd_close_adapter(hdd_ctx, adapter, true); + + return ERR_PTR(-EINVAL); +} + +static struct wireless_dev * +_wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + struct wireless_dev *wdev; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_create_and_trans(wiphy_dev(wiphy), &vdev_sync); + if (errno) + return ERR_PTR(errno); + + wdev = __wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); + + if (IS_ERR_OR_NULL(wdev)) + goto destroy_sync; + + osif_vdev_sync_register(wdev->netdev, vdev_sync); + osif_vdev_sync_trans_stop(vdev_sync); + + return wdev; + +destroy_sync: + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); + + return wdev; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + struct vif_params *params) +{ + return _wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, ¶ms->flags, params); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)) || defined(WITH_BACKPORTS) +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + unsigned char name_assign_type, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + return _wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); +} +#else +struct wireless_dev *wlan_hdd_add_virtual_intf(struct wiphy *wiphy, + const char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) +{ + return _wlan_hdd_add_virtual_intf(wiphy, name, name_assign_type, + type, flags, params); +} +#endif + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) && \ + !defined(WLAN_HDD_MULTI_VDEV_SINGLE_NDEV) +/** + * hdd_deinit_mlo_interfaces() - De-initialize link adapters + * @hdd_ctx: Pointer to hdd context + * @adapter: Pointer to adapter + * @rtnl_held: rtnl lock + * + * Return: None + */ +static void hdd_deinit_mlo_interfaces(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ + int i; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_adapter *link_adapter; + + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + hdd_deinit_adapter(hdd_ctx, link_adapter, rtnl_held); + } +} +#else +static inline +void hdd_deinit_mlo_interfaces(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + bool rtnl_held) +{ +} +#endif + +void hdd_clean_up_interface(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + wlan_hdd_release_intf_addr(hdd_ctx, + adapter->mac_addr.bytes); + hdd_stop_adapter(hdd_ctx, adapter); + if (hdd_adapter_is_ml_adapter(adapter)) { + hdd_deinit_mlo_interfaces(hdd_ctx, adapter, true); + hdd_wlan_unregister_mlo_interfaces(adapter, true); + } + hdd_deinit_adapter(hdd_ctx, adapter, true); + hdd_close_adapter(hdd_ctx, adapter, true); +} + +int __wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int errno; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + /* + * Clear SOFTAP_INIT_DONE flag to mark SAP unload, so that we do + * not restart SAP after SSR as SAP is already stopped from user space. + */ + clear_bit(SOFTAP_INIT_DONE, &adapter->deflink->link_flags); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_DEL_VIRTUAL_INTF, + adapter->deflink->vdev_id, adapter->device_mode); + + hdd_debug("Device_mode %s(%d)", + qdf_opmode_str(adapter->device_mode), adapter->device_mode); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + /* ensure physical soc is up */ + errno = hdd_trigger_psoc_idle_restart(hdd_ctx); + if (errno) + return errno; + + if (wlan_hdd_is_session_type_monitor(adapter->device_mode)) + ucfg_dp_set_mon_conf_flags(hdd_ctx->psoc, 0); + + if (adapter->device_mode == QDF_SAP_MODE && + ucfg_pre_cac_is_active(hdd_ctx->psoc)) { + ucfg_pre_cac_clean_up(hdd_ctx->psoc); + hdd_clean_up_interface(hdd_ctx, adapter); + } else if (wlan_hdd_is_session_type_monitor( + adapter->device_mode) && + ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + wlan_hdd_del_monitor(hdd_ctx, adapter, TRUE); + } else { + hdd_clean_up_interface(hdd_ctx, adapter); + } + + if (!hdd_is_any_interface_open(hdd_ctx)) + hdd_psoc_idle_timer_start(hdd_ctx); + hdd_exit(); + + return 0; +} + +int wlan_hdd_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + + adapter->delete_in_progress = true; + errno = osif_vdev_sync_trans_start_wait(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + osif_vdev_sync_unregister(wdev->netdev); + osif_vdev_sync_wait_for_ops(vdev_sync); + + adapter->is_virtual_iface = true; + errno = __wlan_hdd_del_virtual_intf(wiphy, wdev); + + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); + + return errno; +} + +/** + * hdd_is_qos_action_frame() - check if frame is QOS action frame + * @pb_frames: frame pointer + * @frame_len: frame length + * + * Return: true if it is QOS action frame else false. + */ +static inline bool +hdd_is_qos_action_frame(uint8_t *pb_frames, uint32_t frame_len) +{ + if (frame_len <= WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1) { + hdd_debug("Not a QOS frame len: %d", frame_len); + return false; + } + + return ((pb_frames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET] == + WLAN_HDD_QOS_ACTION_FRAME) && + (pb_frames[WLAN_HDD_PUBLIC_ACTION_FRAME_OFFSET + 1] == + WLAN_HDD_QOS_MAP_CONFIGURE)); +} + +#if defined(WLAN_FEATURE_SAE) && defined(CFG80211_EXTERNAL_AUTH_AP_SUPPORT) +/** + * wlan_hdd_set_rxmgmt_external_auth_flag() - Set the EXTERNAL_AUTH flag + * @nl80211_flag: flags to be sent to nl80211 from enum nl80211_rxmgmt_flags + * + * Set the flag NL80211_RXMGMT_FLAG_EXTERNAL_AUTH if supported. + */ +static void +wlan_hdd_set_rxmgmt_external_auth_flag(enum nl80211_rxmgmt_flags *nl80211_flag) +{ + *nl80211_flag |= NL80211_RXMGMT_FLAG_EXTERNAL_AUTH; +} +#else +static void +wlan_hdd_set_rxmgmt_external_auth_flag(enum nl80211_rxmgmt_flags *nl80211_flag) +{ +} +#endif + +/** + * wlan_hdd_cfg80211_convert_rxmgmt_flags() - Convert RXMGMT value + * @nl80211_flag: Flags to be sent to nl80211 from enum nl80211_rxmgmt_flags + * @flag: flags set by driver(SME/PE) from enum rxmgmt_flags + * + * Convert driver internal RXMGMT flag value to nl80211 defined RXMGMT flag + * Return: void + */ +static void +wlan_hdd_cfg80211_convert_rxmgmt_flags(enum rxmgmt_flags flag, + enum nl80211_rxmgmt_flags *nl80211_flag) +{ + + if (flag & RXMGMT_FLAG_EXTERNAL_AUTH) { + wlan_hdd_set_rxmgmt_external_auth_flag(nl80211_flag); + } + +} + +static void +__hdd_indicate_mgmt_frame_to_user(struct hdd_adapter *adapter, + uint32_t frm_len, uint8_t *pb_frames, + uint8_t frame_type, uint32_t rx_freq, + int8_t rx_rssi, enum rxmgmt_flags rx_flags) +{ + uint8_t type = 0; + uint8_t sub_type = 0; + struct hdd_context *hdd_ctx; + uint8_t *dest_addr = NULL; + uint16_t auth_algo; + enum nl80211_rxmgmt_flags nl80211_flag = 0; + bool is_pasn_auth_frame = false; + struct hdd_adapter *assoc_adapter; + bool eht_capab; + struct hdd_ap_ctx *ap_ctx; + struct action_frm_hdr *action_hdr; + tpSirMacVendorSpecificPublicActionFrameHdr vendor_specific; + + hdd_debug("Frame Type = %d Frame Length = %d freq = %d", + frame_type, frm_len, rx_freq); + + if (!adapter) { + hdd_err("adapter is NULL"); + return; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!frm_len) { + hdd_err("Frame Length is Invalid ZERO"); + return; + } + + if (!pb_frames) { + hdd_err("pbFrames is NULL"); + return; + } + + type = WLAN_HDD_GET_TYPE_FRM_FC(pb_frames[0]); + sub_type = WLAN_HDD_GET_SUBTYPE_FRM_FC(pb_frames[0]); + if (type == SIR_MAC_MGMT_FRAME && + sub_type == SIR_MAC_MGMT_AUTH && + frm_len > (sizeof(struct wlan_frame_hdr) + + WLAN_AUTH_FRAME_MIN_LEN)) { + auth_algo = *(uint16_t *)(pb_frames + + sizeof(struct wlan_frame_hdr)); + if (auth_algo == eSIR_AUTH_TYPE_PASN) { + is_pasn_auth_frame = true; + } else if (auth_algo == eSIR_FT_AUTH && + (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE)) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + ap_ctx->during_auth_offload = true; + } + } + + if (type == WLAN_FC0_TYPE_MGMT && sub_type == WLAN_FC0_STYPE_ACTION && + frm_len >= (sizeof(struct wlan_frame_hdr) + + sizeof(*vendor_specific))) { + action_hdr = (struct action_frm_hdr *)(pb_frames + + sizeof(struct wlan_frame_hdr)); + vendor_specific = + (tpSirMacVendorSpecificPublicActionFrameHdr)action_hdr; + if (is_nan_oui(vendor_specific->Oui)) { + adapter = hdd_get_adapter(hdd_ctx, QDF_NAN_DISC_MODE); + if (!adapter) { + hdd_err("NAN adapter is null"); + return; + } + + goto check_adapter; + } + } + + /* Get adapter from Destination mac address of the frame */ + if (type == SIR_MAC_MGMT_FRAME && + sub_type != SIR_MAC_MGMT_PROBE_REQ && !is_pasn_auth_frame && + !qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)&pb_frames[WLAN_HDD_80211_FRM_DA_OFFSET])) { + dest_addr = &pb_frames[WLAN_HDD_80211_FRM_DA_OFFSET]; + adapter = hdd_get_adapter_by_macaddr(hdd_ctx, dest_addr); + if (!adapter) + adapter = hdd_get_adapter_by_rand_macaddr(hdd_ctx, + dest_addr); + if (!adapter) { + /* + * Under assumption that we don't receive any action + * frame with BCST as destination, + * we are dropping action frame + */ + hdd_err("adapter for action frame is NULL Macaddr = " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(dest_addr)); + hdd_debug("Frame Type = %d Frame Length = %d subType = %d", + frame_type, frm_len, sub_type); + /* + * We will receive broadcast management frames + * in OCB mode + */ + adapter = hdd_get_adapter(hdd_ctx, QDF_OCB_MODE); + if (!adapter || !qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)dest_addr)) { + /* + * Under assumption that we don't + * receive any action frame with BCST + * as destination, we are dropping + * action frame + */ + return; + } + } + } + +check_adapter: + if (!adapter->dev) { + hdd_err("adapter->dev is NULL"); + return; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("adapter has invalid magic"); + return; + } + + /* Channel indicated may be wrong. TODO */ + /* Indicate an action frame. */ + + if (hdd_is_qos_action_frame(pb_frames, frm_len)) + sme_update_dsc_pto_up_mapping(hdd_ctx->mac_handle, + adapter->dscp_to_up_map, + adapter->deflink->vdev_id); + + assoc_adapter = adapter; + ucfg_psoc_mlme_get_11be_capab(hdd_ctx->psoc, &eht_capab); + if (hdd_adapter_is_link_adapter(adapter) && eht_capab) { + hdd_debug("adapter is not ml adapter move to ml adapter"); + assoc_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter); + if (!assoc_adapter) { + hdd_err("Assoc adapter is NULL"); + return; + } + } + + /* Indicate Frame Over Normal Interface */ + hdd_debug("Indicate Frame over NL80211 sessionid : %d, idx :%d", + assoc_adapter->deflink->vdev_id, + assoc_adapter->dev->ifindex); + + wlan_hdd_cfg80211_convert_rxmgmt_flags(rx_flags, &nl80211_flag); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(assoc_adapter->dev->ieee80211_ptr, + rx_freq, rx_rssi * 100, pb_frames, + frm_len, NL80211_RXMGMT_FLAG_ANSWERED | nl80211_flag); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(assoc_adapter->dev->ieee80211_ptr, + rx_freq, rx_rssi * 100, pb_frames, + frm_len, NL80211_RXMGMT_FLAG_ANSWERED, + GFP_ATOMIC); +#else + cfg80211_rx_mgmt(assoc_adapter->dev->ieee80211_ptr, rx_freq, + rx_rssi * 100, + pb_frames, frm_len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +} + +void hdd_indicate_mgmt_frame_to_user(struct hdd_adapter *adapter, + uint32_t frm_len, uint8_t *pb_frames, + uint8_t frame_type, uint32_t rx_freq, + int8_t rx_rssi, enum rxmgmt_flags rx_flags) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(adapter->dev, &vdev_sync); + if (errno) + return; + + __hdd_indicate_mgmt_frame_to_user(adapter, frm_len, pb_frames, + frame_type, rx_freq, + rx_rssi, rx_flags); + osif_vdev_sync_op_stop(vdev_sync); +} + +int wlan_hdd_set_power_save(struct hdd_adapter *adapter, + struct p2p_ps_config *ps_config) +{ + struct wlan_objmgr_psoc *psoc; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + + if (!adapter || !ps_config) { + hdd_err("null param, adapter:%pK, ps_config:%pK", + adapter, ps_config); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + psoc = hdd_ctx->psoc; + if (!psoc) { + hdd_err("psoc is null"); + return -EINVAL; + } + + hdd_debug("opp ps:%d, ct window:%d, duration:%d, interval:%d, count:%d start:%d, single noa duration:%d, ps selection:%d, vdev id:%d", + ps_config->opp_ps, ps_config->ct_window, + ps_config->duration, ps_config->interval, + ps_config->count, ps_config->start, + ps_config->single_noa_duration, + ps_config->ps_selection, ps_config->vdev_id); + + status = ucfg_p2p_set_ps(psoc, ps_config); + hdd_debug("p2p set power save, status:%d", status); + + /* P2P-GO-NOA and TWT do not go hand in hand */ + if (ps_config->duration) { + hdd_send_twt_role_disable_cmd(hdd_ctx, TWT_RESPONDER); + } else { + hdd_send_twt_requestor_enable_cmd(hdd_ctx); + hdd_send_twt_responder_enable_cmd(hdd_ctx); + } + + return qdf_status_to_os_return(status); +} + +/** + * wlan_hdd_update_mcc_p2p_quota() - Function to Update P2P + * quota to FW + * @adapter: Pointer to HDD adapter + * @is_set: 0-reset, 1-set + * + * This function passes down the value of MAS to UMAC + * + * Return: none + * + */ +static void wlan_hdd_update_mcc_p2p_quota(struct hdd_adapter *adapter, + bool is_set) +{ + + hdd_info("Set/reset P2P quota: %d", is_set); + if (is_set) { + if (adapter->device_mode == QDF_STA_MODE) + wlan_hdd_set_mcc_p2p_quota(adapter, + 100 - HDD_DEFAULT_MCC_P2P_QUOTA + ); + else if (adapter->device_mode == QDF_P2P_GO_MODE) + wlan_hdd_go_set_mcc_p2p_quota(adapter, + HDD_DEFAULT_MCC_P2P_QUOTA); + else + wlan_hdd_set_mcc_p2p_quota(adapter, + HDD_DEFAULT_MCC_P2P_QUOTA); + } else { + if (adapter->device_mode == QDF_P2P_GO_MODE) + wlan_hdd_go_set_mcc_p2p_quota(adapter, + HDD_RESET_MCC_P2P_QUOTA); + else + wlan_hdd_set_mcc_p2p_quota(adapter, + HDD_RESET_MCC_P2P_QUOTA); + } +} + +int32_t wlan_hdd_set_mas(struct hdd_adapter *adapter, uint8_t mas_value) +{ + struct hdd_context *hdd_ctx; + bool enable_mcc_adaptive_sch = false; + + if (!adapter) { + hdd_err("Adapter is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + if (mas_value) { + hdd_info("Miracast is ON. Disable MAS and configure P2P quota"); + ucfg_policy_mgr_get_mcc_adaptive_sch(hdd_ctx->psoc, + &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch( + hdd_ctx->psoc, false); + + if (QDF_STATUS_SUCCESS != sme_set_mas(false)) { + hdd_err("Failed to disable MAS"); + return -EAGAIN; + } + } + + /* Config p2p quota */ + wlan_hdd_update_mcc_p2p_quota(adapter, true); + } else { + hdd_info("Miracast is OFF. Enable MAS and reset P2P quota"); + wlan_hdd_update_mcc_p2p_quota(adapter, false); + + ucfg_policy_mgr_get_mcc_adaptive_sch(hdd_ctx->psoc, + &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + ucfg_policy_mgr_set_dynamic_mcc_adaptive_sch( + hdd_ctx->psoc, true); + + if (QDF_STATUS_SUCCESS != sme_set_mas(true)) { + hdd_err("Failed to enable MAS"); + return -EAGAIN; + } + } + } + + return 0; +} + +/** + * set_first_connection_operating_channel() - Function to set + * first connection oerating channel + * @hdd_ctx: Hdd context + * @set_value: First connection operating channel + * @dev_mode: Device operating mode + * + * This function is used to set the first adapter operating + * channel + * + * Return: operating channel updated in set value + * + */ +static uint32_t set_first_connection_operating_channel( + struct hdd_context *hdd_ctx, uint32_t set_value, + enum QDF_OPMODE dev_mode) +{ + uint8_t operating_channel; + uint32_t oper_chan_freq; + + oper_chan_freq = hdd_get_operating_chan_freq(hdd_ctx, dev_mode); + if (!oper_chan_freq) { + hdd_err(" First adapter operating channel is invalid"); + return set_value; + } + operating_channel = wlan_reg_freq_to_chan(hdd_ctx->pdev, + oper_chan_freq); + + hdd_info("First connection channel No.:%d and quota:%dms", + operating_channel, set_value); + /* Move the time quota for first channel to bits 15-8 */ + set_value = set_value << 8; + + /* + * Store the channel number of 1st channel at bits 7-0 + * of the bit vector + */ + return set_value | operating_channel; +} + +/** + * set_second_connection_operating_channel() - Function to set + * second connection oerating channel + * @hdd_ctx: Hdd context + * @set_value: Second connection operating channel + * @vdev_id: vdev id + * + * This function is used to set the first adapter operating + * channel + * + * Return: operating channel updated in set value + * + */ +static uint32_t set_second_connection_operating_channel( + struct hdd_context *hdd_ctx, uint32_t set_value, + uint8_t vdev_id) +{ + uint8_t operating_channel; + + operating_channel = wlan_reg_freq_to_chan(hdd_ctx->pdev, + policy_mgr_get_mcc_operating_channel( + hdd_ctx->psoc, vdev_id)); + + if (!operating_channel) { + hdd_err("Second adapter operating channel is invalid"); + return set_value; + } + + hdd_info("Second connection channel No.:%d and quota:%dms", + operating_channel, set_value); + /* + * Now move the time quota and channel number of the + * 1st adapter to bits 23-16 and bits 15-8 of the bit + * vector, respectively. + */ + set_value = set_value << 8; + + /* + * Set the channel number for 2nd MCC vdev at bits + * 7-0 of set_value + */ + return set_value | operating_channel; +} + +/** + * wlan_hdd_set_mcc_p2p_quota() - Function to set quota for P2P + * @adapter: HDD adapter + * @set_value: Quota value for the interface + * + * This function is used to set the quota for P2P cases + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +int wlan_hdd_set_mcc_p2p_quota(struct hdd_adapter *adapter, + uint32_t set_value) +{ + int32_t ret = 0; + uint32_t concurrent_state; + struct hdd_context *hdd_ctx; + uint32_t sta_cli_bit_mask = QDF_STA_MASK | QDF_P2P_CLIENT_MASK; + uint32_t sta_go_bit_mask = QDF_STA_MASK | QDF_P2P_GO_MASK; + + if (!adapter) { + hdd_err("Invalid adapter"); + return -EFAULT; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return -EINVAL; + } + + concurrent_state = policy_mgr_get_concurrency_mode( + hdd_ctx->psoc); + /* + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than STA/P2P + */ + if (((concurrent_state & sta_cli_bit_mask) == sta_cli_bit_mask) || + ((concurrent_state & sta_go_bit_mask) == sta_go_bit_mask)) { + hdd_info("STA & P2P are both enabled"); + + /* + * The channel numbers for both adapters and the time + * quota for the 1st adapter, i.e., one specified in cmd + * are formatted as a bit vector then passed on to WMA + * +***********************************************************+ + * |bit 31-24 | bit 23-16 | bits 15-8 | bits 7-0 | + * | Unused | Quota for | chan. # for | chan. # for | + * | | 1st chan. | 1st chan. | 2nd chan. | + * +***********************************************************+ + */ + + set_value = set_first_connection_operating_channel( + hdd_ctx, set_value, adapter->device_mode); + + set_value = set_second_connection_operating_channel( + hdd_ctx, set_value, adapter->deflink->vdev_id); + + ret = wlan_hdd_send_mcc_vdev_quota(adapter, set_value); + } else { + hdd_info("MCC is not active. Exit w/o setting latency"); + } + + return ret; +} + +int wlan_hdd_go_set_mcc_p2p_quota(struct hdd_adapter *hostapd_adapter, + uint32_t set_value) +{ + return wlan_hdd_set_mcc_p2p_quota(hostapd_adapter, set_value); +} + +void wlan_hdd_set_mcc_latency(struct hdd_adapter *adapter, int set_value) +{ + uint32_t concurrent_state; + struct hdd_context *hdd_ctx; + uint32_t sta_cli_bit_mask = QDF_STA_MASK | QDF_P2P_CLIENT_MASK; + uint32_t sta_go_bit_mask = QDF_STA_MASK | QDF_P2P_GO_MASK; + + if (!adapter) { + hdd_err("Invalid adapter"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + concurrent_state = policy_mgr_get_concurrency_mode( + hdd_ctx->psoc); + /** + * Check if concurrency mode is active. + * Need to modify this code to support MCC modes other than STA/P2P + */ + if (((concurrent_state & sta_cli_bit_mask) == sta_cli_bit_mask) || + ((concurrent_state & sta_go_bit_mask) == sta_go_bit_mask)) { + hdd_info("STA & P2P are both enabled"); + /* + * The channel number and latency are formatted in + * a bit vector then passed on to WMA layer. + * +**********************************************+ + * |bits 31-16 | bits 15-8 | bits 7-0 | + * | Unused | latency - Chan. 1 | channel no. | + * +**********************************************+ + */ + set_value = set_first_connection_operating_channel( + hdd_ctx, set_value, adapter->device_mode); + + wlan_hdd_send_mcc_latency(adapter, set_value); + } else { + hdd_info("MCC is not active. Exit w/o setting latency"); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p_listen_offload.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p_listen_offload.c new file mode 100644 index 0000000000..811b0c9ae0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p_listen_offload.c @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_vendor_p2p_listen_offload.c + * + * WLAN p2p listen offload functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* P2P listen offload device types parameters length in bytes */ +#define P2P_LO_MAX_REQ_DEV_TYPE_COUNT (10) +#define P2P_LO_WPS_DEV_TYPE_LEN (8) +#define P2P_LO_DEV_TYPE_MAX_LEN \ + (P2P_LO_MAX_REQ_DEV_TYPE_COUNT * P2P_LO_WPS_DEV_TYPE_LEN) + +const struct nla_policy +p2p_listen_offload_policy[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] = { + .type = NLA_BINARY, + .len = P2P_LO_DEV_TYPE_MAX_LEN }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE] = { + .type = NLA_BINARY, + .len = MAX_GENIE_LEN }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG] = { + .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON] = { + .type = NLA_U8 }, +}; + +/** + * wlan_hdd_listen_offload_start() - hdd set listen offload start + * @adapter: adapter context + * @params: listen offload parameters + * + * This function sets listen offload start parameters. + * + * Return: 0 on success, others on failure + */ +static int wlan_hdd_listen_offload_start(struct hdd_adapter *adapter, + struct sir_p2p_lo_start *params) +{ + struct wlan_objmgr_psoc *psoc; + struct p2p_lo_start lo_start; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + + if (!adapter || !params) { + hdd_err("null param, adapter:%pK, params:%pK", + adapter, params); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + psoc = hdd_ctx->psoc; + if (!psoc) { + hdd_err("psoc is null"); + return -EINVAL; + } + + lo_start.vdev_id = params->vdev_id; + lo_start.ctl_flags = params->ctl_flags; + lo_start.freq = params->freq; + lo_start.period = params->period; + lo_start.interval = params->interval; + lo_start.count = params->count; + lo_start.device_types = params->device_types; + lo_start.dev_types_len = params->dev_types_len; + lo_start.probe_resp_tmplt = params->probe_resp_tmplt; + lo_start.probe_resp_len = params->probe_resp_len; + + status = ucfg_p2p_lo_start(psoc, &lo_start); + hdd_debug("p2p listen offload start, status:%d", status); + + return qdf_status_to_os_return(status); +} + +/** + * __wlan_hdd_cfg80211_p2p_lo_start () - start P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload start vendor + * command. It parses the input parameters and invoke WMA API to + * send the command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; + struct sir_p2p_lo_start params; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && + (adapter->device_mode != QDF_P2P_CLIENT_MODE) && + (adapter->device_mode != QDF_P2P_GO_MODE)) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX, + data, data_len, + p2p_listen_offload_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + memset(¶ms, 0, sizeof(params)); + + if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]) + params.ctl_flags = 1; /* set to default value */ + else + params.ctl_flags = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CTRL_FLAG]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES] || + !tb[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]) { + hdd_err("Attribute parsing failed"); + return -EINVAL; + } + + params.vdev_id = adapter->deflink->vdev_id; + params.freq = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_CHANNEL]); + if ((params.freq != 2412) && (params.freq != 2437) && + (params.freq != 2462)) { + hdd_err("Invalid listening channel: %d", params.freq); + return -EINVAL; + } + + params.period = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_PERIOD]); + if (!((params.period > 0) && (params.period < UINT_MAX))) { + hdd_err("Invalid period: %d", params.period); + return -EINVAL; + } + + params.interval = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_INTERVAL]); + if (!((params.interval > 0) && (params.interval < UINT_MAX))) { + hdd_err("Invalid interval: %d", params.interval); + return -EINVAL; + } + + params.count = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_COUNT]); + if (!((params.count >= 0) && (params.count < UINT_MAX))) { + hdd_err("Invalid count: %d", params.count); + return -EINVAL; + } + + params.device_types = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); + if (!params.device_types) { + hdd_err("Invalid device types"); + return -EINVAL; + } + + params.dev_types_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_DEVICE_TYPES]); + /* device type length has to be multiple of P2P_LO_WPS_DEV_TYPE_LEN */ + if (0 != (params.dev_types_len % P2P_LO_WPS_DEV_TYPE_LEN)) { + hdd_err("Invalid device type length: %d", params.dev_types_len); + return -EINVAL; + } + + params.probe_resp_tmplt = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); + if (!params.probe_resp_tmplt) { + hdd_err("Invalid probe response template"); + return -EINVAL; + } + + /* + * IEs minimum length should be 2 bytes: 1 byte for element id + * and 1 byte for element id length. + */ + params.probe_resp_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_VENDOR_IE]); + if (params.probe_resp_len < MIN_GENIE_LEN) { + hdd_err("Invalid probe resp template length: %d", + params.probe_resp_len); + return -EINVAL; + } + + hdd_debug("P2P LO params: freq=%d, period=%d, interval=%d, count=%d", + params.freq, params.period, params.interval, params.count); + + return wlan_hdd_listen_offload_start(adapter, ¶ms); +} + +int wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_p2p_lo_start(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_listen_offload_stop() - hdd set listen offload stop + * @adapter: adapter context + * + * This function sets listen offload stop parameters. + * + * Return: 0 on success, others on failure + */ +static int wlan_hdd_listen_offload_stop(struct hdd_adapter *adapter) +{ + struct wlan_objmgr_psoc *psoc; + struct hdd_context *hdd_ctx; + uint32_t vdev_id; + QDF_STATUS status; + + if (!adapter) { + hdd_err("adapter is null, adapter:%pK", adapter); + return -EINVAL; + } + + vdev_id = (uint32_t)adapter->deflink->vdev_id; + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + psoc = hdd_ctx->psoc; + if (!psoc) { + hdd_err("psoc is null"); + return -EINVAL; + } + + status = ucfg_p2p_lo_stop(psoc, vdev_id); + hdd_debug("p2p listen offload stop, status:%d", status); + + return qdf_status_to_os_return(status); +} + +/** + * __wlan_hdd_cfg80211_p2p_lo_stop () - stop P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload stop vendor + * command. It invokes WMA API to send command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_adapter *adapter; + struct net_device *dev = wdev->netdev; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if ((adapter->device_mode != QDF_P2P_DEVICE_MODE) && + (adapter->device_mode != QDF_P2P_CLIENT_MODE) && + (adapter->device_mode != QDF_P2P_GO_MODE)) { + hdd_err("Invalid device mode"); + return -EINVAL; + } + + return wlan_hdd_listen_offload_stop(adapter); +} + +int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_p2p_lo_stop(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p_listen_offload.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p_listen_offload.h new file mode 100644 index 0000000000..0784228c5b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_p2p_listen_offload.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_P2P_LISTEN_OFFLOAD_H +#define __WLAN_HDD_P2P_LISTEN_OFFLOAD_H + +/** + * DOC: wlan_hdd_p2p_listen_offload_h + * + * WLAN Host Device Driver p2p listen offload API specification + */ + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * wlan_hdd_cfg80211_p2p_lo_start() - start P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function is to process the p2p listen offload start vendor + * command. It parses the input parameters and invoke WMA API to + * send the command to firmware. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_p2p_lo_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_p2p_lo_stop() - stop P2P Listen Offload + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * This function inovkes internal __wlan_hdd_cfg80211_p2p_lo_stop() + * to process p2p listen offload stop vendor command. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_p2p_lo_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +extern const struct nla_policy +p2p_listen_offload_policy[QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX + 1]; + +#define FEATURE_P2P_LISTEN_OFFLOAD_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_START, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_p2p_lo_start, \ + vendor_command_policy(p2p_listen_offload_policy, \ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX)\ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_p2p_lo_stop, \ + vendor_command_policy(p2p_listen_offload_policy, \ + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_MAX)\ +}, +#else /* FEATURE_P2P_LISTEN_OFFLOAD */ +#define FEATURE_P2P_LISTEN_OFFLOAD_VENDOR_COMMANDS +#endif /* FEATURE_P2P_LISTEN_OFFLOAD */ + +#endif /* __WLAN_HDD_P2P_LISTEN_OFFLOAD_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c new file mode 100644 index 0000000000..f15b4d79ea --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_packet_filter.c @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_packet_filter.c + * + * WLAN Host Device Driver implementation + * + */ + +/* Include Files */ +#include "wlan_hdd_packet_filter_api.h" +#include "wlan_hdd_packet_filter_rules.h" + +int +hdd_enable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ + uint8_t filters = 0, i = 0, filter_id = 1; + + if (hdd_ctx->user_configured_pkt_filter_rules) { + hdd_info("user has defined pkt filter run hence skipping default packet filter rule"); + return 0; + } + + filters = ucfg_pmo_get_pkt_filter_bitmap(hdd_ctx->psoc); + + while (filters != 0) { + if (filters & 0x1) { + hdd_err("setting filter[%d], of id = %d", + i+1, filter_id); + packet_filter_default_rules[i].filter_id = filter_id; + wlan_hdd_set_filter(hdd_ctx, + &packet_filter_default_rules[i], + vdev_id); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} + +int +hdd_disable_default_pkt_filters(struct hdd_context *hdd_ctx, uint8_t vdev_id) +{ + uint8_t filters = 0, i = 0, filter_id = 1; + struct pkt_filter_cfg packet_filter_default_rules = {0}; + + if (hdd_ctx->user_configured_pkt_filter_rules) { + hdd_info("user has defined pkt filter run hence skipping default packet filter rule"); + return 0; + } + + filters = ucfg_pmo_get_pkt_filter_bitmap(hdd_ctx->psoc); + + while (filters != 0) { + if (filters & 0x1) { + hdd_err("Clearing filter[%d], of id = %d", + i+1, filter_id); + packet_filter_default_rules.filter_action = + HDD_RCV_FILTER_CLEAR; + packet_filter_default_rules.filter_id = filter_id; + wlan_hdd_set_filter(hdd_ctx, + &packet_filter_default_rules, + vdev_id); + filter_id++; + } + filters = filters >> 1; + i++; + } + + return 0; +} + +int wlan_hdd_set_filter(struct hdd_context *hdd_ctx, + struct pkt_filter_cfg *request, + uint8_t vdev_id) +{ + struct pmo_rcv_pkt_fltr_cfg *pmo_set_pkt_fltr_req = NULL; + struct pmo_rcv_pkt_fltr_clear_param *pmo_clr_pkt_fltr_param = NULL; + int i = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!ucfg_pmo_is_pkt_filter_enabled(hdd_ctx->psoc)) { + hdd_warn("Packet filtering disabled in ini"); + return 0; + } + + /* Debug display of request components. */ + hdd_debug("Packet Filter Request : FA %d params %d", + request->filter_action, request->num_params); + + switch (request->filter_action) { + case HDD_RCV_FILTER_SET: + hdd_debug("Set Packet Filter Request for Id: %d", + request->filter_id); + + pmo_set_pkt_fltr_req = + qdf_mem_malloc(sizeof(*pmo_set_pkt_fltr_req)); + if (!pmo_set_pkt_fltr_req) + return QDF_STATUS_E_NOMEM; + + pmo_set_pkt_fltr_req->filter_id = request->filter_id; + if (request->num_params >= HDD_MAX_CMP_PER_PACKET_FILTER) { + hdd_err("Number of Params exceed Max limit %d", + request->num_params); + status = QDF_STATUS_E_INVAL; + goto out; + } + pmo_set_pkt_fltr_req->num_params = request->num_params; + pmo_set_pkt_fltr_req->coalesce_time = 0; + pmo_set_pkt_fltr_req->filter_type = PMO_RCV_FILTER_TYPE_FILTER_PKT; + for (i = 0; i < request->num_params; i++) { + pmo_set_pkt_fltr_req->params_data[i].protocol_layer = + request->params_data[i].protocol_layer; + pmo_set_pkt_fltr_req->params_data[i].compare_flag = + request->params_data[i].compare_flag; + pmo_set_pkt_fltr_req->params_data[i].data_offset = + request->params_data[i].data_offset; + pmo_set_pkt_fltr_req->params_data[i].data_length = + request->params_data[i].data_length; + pmo_set_pkt_fltr_req->params_data[i].reserved = 0; + + if (request->params_data[i].data_offset > + SIR_MAX_FILTER_TEST_DATA_OFFSET) { + hdd_err("Invalid data offset %u for param %d (max = %d)", + request->params_data[i].data_offset, + i, + SIR_MAX_FILTER_TEST_DATA_OFFSET); + status = QDF_STATUS_E_INVAL; + goto out; + } + + if (request->params_data[i].data_length > + SIR_MAX_FILTER_TEST_DATA_LEN) { + hdd_err("Error invalid data length %d", + request->params_data[i].data_length); + status = QDF_STATUS_E_INVAL; + goto out; + } + + hdd_debug("Proto %d Comp Flag %d Filter Type %d", + request->params_data[i].protocol_layer, + request->params_data[i].compare_flag, + pmo_set_pkt_fltr_req->filter_type); + + hdd_debug("Data Offset %d Data Len %d", + request->params_data[i].data_offset, + request->params_data[i].data_length); + + if (sizeof( + pmo_set_pkt_fltr_req->params_data[i].compare_data) + < (request->params_data[i].data_length)) { + hdd_err("Error invalid data length %d", + request->params_data[i].data_length); + status = QDF_STATUS_E_INVAL; + goto out; + } + + memcpy( + &pmo_set_pkt_fltr_req->params_data[i].compare_data, + request->params_data[i].compare_data, + request->params_data[i].data_length); + memcpy(&pmo_set_pkt_fltr_req->params_data[i].data_mask, + request->params_data[i].data_mask, + request->params_data[i].data_length); + + hdd_debug("CData %d CData %d CData %d CData %d CData %d CData %d", + request->params_data[i].compare_data[0], + request->params_data[i].compare_data[1], + request->params_data[i].compare_data[2], + request->params_data[i].compare_data[3], + request->params_data[i].compare_data[4], + request->params_data[i].compare_data[5]); + + hdd_debug("MData %d MData %d MData %d MData %d MData %d MData %d", + request->params_data[i].data_mask[0], + request->params_data[i].data_mask[1], + request->params_data[i].data_mask[2], + request->params_data[i].data_mask[3], + request->params_data[i].data_mask[4], + request->params_data[i].data_mask[5]); + } + + + status= ucfg_pmo_set_pkt_filter(hdd_ctx->psoc, + pmo_set_pkt_fltr_req, + vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failure to execute Set Filter"); + status = QDF_STATUS_E_INVAL; + goto out; + } + + break; + + case HDD_RCV_FILTER_CLEAR: + hdd_debug("Clear Packet Filter Request for Id: %d", + request->filter_id); + + pmo_clr_pkt_fltr_param = qdf_mem_malloc( + sizeof(*pmo_clr_pkt_fltr_param)); + if (!pmo_clr_pkt_fltr_param) + return QDF_STATUS_E_NOMEM; + + pmo_clr_pkt_fltr_param->filter_id = request->filter_id; + status = ucfg_pmo_clear_pkt_filter(hdd_ctx->psoc, + pmo_clr_pkt_fltr_param, + vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failure to execute Clear Filter"); + status = QDF_STATUS_E_INVAL; + goto out; + } + break; + + default: + hdd_err("Packet Filter Request: Invalid %d", + request->filter_action); + return -EINVAL; + } + +out: + if (pmo_set_pkt_fltr_req) + qdf_mem_free(pmo_set_pkt_fltr_req); + if (pmo_clr_pkt_fltr_param) + qdf_mem_free(pmo_clr_pkt_fltr_param); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_peer_txq_flush.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_peer_txq_flush.c new file mode 100644 index 0000000000..e5b601ee6e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_peer_txq_flush.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_txq_flush.c + * + * WLAN Host Device Driver Peer TX queue flush configuration APIs implementation + * + */ + +#include "osif_sync.h" +#include +#include "wlan_hdd_main.h" +#include "wlan_hdd_peer_txq_flush.h" +#include +#include "wlan_hdd_object_manager.h" + +const struct nla_policy +peer_txq_flush_policy[QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PEER_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_AC] = { .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TID_MASK] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY] = { .type = NLA_U32 }, +}; + +/** + * map_txq_policy() - Map NL flush policy attribute value to DP + * @policy: NL flush policy attribute value + * + * This function maps NL flush policy attribute value to DP + * + * Return: Valid DP policy value, else invalid + */ +static enum cdp_peer_txq_flush_policy +map_txq_policy(enum qca_wlan_vendor_flush_pending_policy policy) +{ + switch (policy) { + case QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_NONE: + return CDP_PEER_TXQ_FLUSH_POLICY_NONE; + case QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_IMMEDIATE: + return CDP_PEER_TXQ_FLUSH_POLICY_IMMEDIATE; + case QCA_WLAN_VENDOR_FLUSH_PENDING_POLICY_TWT_SP_END: + return CDP_PEER_TXQ_FLUSH_POLICY_TWT_SP_END; + default: + return CDP_PEER_TXQ_FLUSH_POLICY_INVALID; + } +} + +/** + * hdd_peer_txq_flush_config() - Propagate txq flush config to DP + * @adapter: Pointer to HDD adapter structure + * @tb: NL attributes + * + * This function maps NL to DP attributes and proagates the configuration + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_peer_txq_flush_config(struct hdd_adapter *adapter, + struct nlattr *tb[]) +{ + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t addr[QDF_MAC_ADDR_SIZE]; + uint32_t ac, tid, cmd_id; + enum qca_wlan_vendor_flush_pending_policy txq_policy; + enum cdp_peer_txq_flush_policy cdp_policy; + + if (!tb || !dp_soc) { + hdd_err("Invalid attributes"); + return -EINVAL; + } + + nla_memcpy(addr, tb[QCA_WLAN_VENDOR_ATTR_PEER_ADDR], QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_TID_MASK]) { + tid = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TID_MASK]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_POLICY; + if (!tb[cmd_id]) { + hdd_err("Flush policy not provided"); + return -EINVAL; + } + txq_policy = nla_get_u32(tb[cmd_id]); + cdp_policy = map_txq_policy(txq_policy); + if (cdp_policy == CDP_PEER_TXQ_FLUSH_POLICY_INVALID) { + hdd_err("Invalid dp flush policy %d", txq_policy); + return -EINVAL; + } + ac = 0; + } else if (tb[QCA_WLAN_VENDOR_ATTR_AC]) { + ac = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_AC]); + cdp_policy = CDP_PEER_TXQ_FLUSH_POLICY_INVALID; + tid = 0; + } else { + hdd_err("No ac/tid mask"); + return -EINVAL; + } + + return cdp_set_peer_txq_flush_config(dp_soc, adapter->deflink->vdev_id, + addr, ac, tid, cdp_policy); +} + +/** + * __wlan_hdd_cfg80211_peer_txq_flush_config() - flush peer txq config + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to flush peer pending packets using vendor commands + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1]; + int ret; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX, + data, data_len, peer_txq_flush_policy)) { + hdd_err("Invalid attributes"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PEER_ADDR]) { + hdd_err("Peer mac not provided"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_AC] && + !tb[QCA_WLAN_VENDOR_ATTR_TID_MASK]) { + hdd_err("AC/TID mask not provided"); + return -EINVAL; + } + + ret = hdd_peer_txq_flush_config(adapter, tb); + + hdd_exit(); + + return ret; +} + +int wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *attr, + int attr_len) +{ + int ret; + struct osif_vdev_sync *vdev_sync; + + ret = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (ret) + return ret; + + ret = __wlan_hdd_cfg80211_peer_txq_flush_config(wiphy, wdev, + attr, attr_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return ret; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_peer_txq_flush.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_peer_txq_flush.h new file mode 100644 index 0000000000..e16871d307 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_peer_txq_flush.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_txq_flush.h + * + * WLAN Host Device Driver peer Tx queue flush config interface definitions + * + */ +#ifndef WLAN_HDD_PEER_TXQ_FLUSH_H +#define WLAN_HDD_PEER_TXQ_FLUSH_H +#include "qdf_types.h" +#include "qdf_status.h" +#include "qca_vendor.h" +#include + +#ifdef WLAN_FEATURE_PEER_TXQ_FLUSH_CONF +extern const struct nla_policy +peer_txq_flush_policy[QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX + 1]; + +/** + * wlan_hdd_cfg80211_peer_txq_flush_config() - Set peer tx queues flush config + * @wiphy: Wireless info object + * @wdev: Wireless dev object + * @attr: Command attributes + * @attr_len: Length of attributes + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_peer_txq_flush_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *attr, + int attr_len); + +#define FEATURE_PEER_FLUSH_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PEER_FLUSH_PENDING, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_peer_txq_flush_config, \ + vendor_command_policy(peer_txq_flush_policy, \ + QCA_WLAN_VENDOR_ATTR_FLUSH_PENDING_MAX) \ +}, +#else /* WLAN_FEATURE_PEER_TXQ_FLUSH_CONF */ +#define FEATURE_PEER_FLUSH_VENDOR_COMMANDS +#endif /* WLAN_FEATURE_PEER_TXQ_FLUSH_CONF */ +#endif /* WLAN_HDD_PEER_TXQ_FLUSH_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_power.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_power.c new file mode 100644 index 0000000000..79b8766d9c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_power.c @@ -0,0 +1,3719 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_power.c + * + * WLAN power management functions + * + */ + +/* Include files */ + +#include +#include +#include +#include "osif_sync.h" +#include +#if defined(CONFIG_HAS_WAKELOCK) +#include +#endif +#include "qdf_types.h" +#include "sme_api.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "hif.h" +#include "hif_unit_test_suspend.h" +#include "sme_power_save_api.h" +#include "wlan_policy_mgr_api.h" +#include "cdp_txrx_flow_ctrl_v2.h" +#include "pld_common.h" +#include "wlan_hdd_driver_ops.h" +#include +#include "scheduler_api.h" +#include "cds_utils.h" +#include "wlan_hdd_packet_filter_api.h" +#include "wlan_cfg80211_scan.h" +#include "wlan_ipa_ucfg_api.h" +#include +#include "wlan_p2p_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_osif_request_manager.h" +#include +#include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_hdd_thermal.h" +#include "wlan_hdd_object_manager.h" +#include +#include "qdf_types.h" +#include +#include +#include +#include "wlan_dp_ucfg_api.h" + +/* Preprocessor definitions and constants */ +#ifdef QCA_WIFI_EMULATION +#define HDD_SSR_BRING_UP_TIME 3000000 +#else +#define HDD_SSR_BRING_UP_TIME 30000 +#endif + +/* Type declarations */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void hdd_wlan_suspend_resume_event(uint8_t state) +{ + WLAN_HOST_DIAG_EVENT_DEF(suspend_state, struct host_event_suspend); + qdf_mem_zero(&suspend_state, sizeof(suspend_state)); + + suspend_state.state = state; + WLAN_HOST_DIAG_EVENT_REPORT(&suspend_state, EVENT_WLAN_SUSPEND_RESUME); +} + +/** + * hdd_wlan_offload_event() - send offloads event + * @type: offload type + * @state: enabled or disabled + * + * This Function send offloads enable/disable diag event + * + * Return: void. + */ + +void hdd_wlan_offload_event(uint8_t type, uint8_t state) +{ + WLAN_HOST_DIAG_EVENT_DEF(host_offload, struct host_event_offload_req); + qdf_mem_zero(&host_offload, sizeof(host_offload)); + + host_offload.offload_type = type; + host_offload.state = state; + + WLAN_HOST_DIAG_EVENT_REPORT(&host_offload, EVENT_WLAN_OFFLOAD_REQ); +} +#endif + +#ifdef WLAN_DP_LEGACY_OL_RX_THREAD + +/* timeout in msec to wait for RX_THREAD to suspend */ +#define HDD_RXTHREAD_SUSPEND_TIMEOUT 200 + +void wlan_hdd_rx_thread_resume(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->is_ol_rx_thread_suspended) { + cds_resume_rx_thread(); + hdd_ctx->is_ol_rx_thread_suspended = false; + } +} + +int wlan_hdd_rx_thread_suspend(struct hdd_context *hdd_ctx) +{ + p_cds_sched_context cds_sched_context = get_cds_sched_ctxt(); + int rc; + + if (!cds_sched_context) + return 0; + + /* Suspend tlshim rx thread */ + set_bit(RX_SUSPEND_EVENT, &cds_sched_context->ol_rx_event_flag); + wake_up_interruptible(&cds_sched_context->ol_rx_wait_queue); + rc = wait_for_completion_timeout(&cds_sched_context-> + ol_suspend_rx_event, + msecs_to_jiffies + (HDD_RXTHREAD_SUSPEND_TIMEOUT) + ); + if (!rc) { + clear_bit(RX_SUSPEND_EVENT, + &cds_sched_context->ol_rx_event_flag); + hdd_err("Failed to stop tl_shim rx thread"); + return -EINVAL; + } + hdd_ctx->is_ol_rx_thread_suspended = true; + + return 0; +} +#endif /* WLAN_DP_LEGACY_OL_RX_THREAD */ + +/** + * hdd_enable_gtk_offload() - enable GTK offload + * @vdev: VDEV objmgr pointer + * + * Central function to enable GTK offload. + * + * Return: nothing + */ +static void hdd_enable_gtk_offload(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + status = ucfg_pmo_enable_gtk_offload_in_fwr(vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_debug("Failed to enable gtk offload"); +} + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * hdd_send_igmp_offload_params() - enable igmp offload + * @adapter: pointer to the adapter + * @vdev: VDEV ojbmgr pointer + * @enable: enable/disable + * + * Return: nothing + */ +static QDF_STATUS +hdd_send_igmp_offload_params(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, bool enable) +{ + struct in_device *in_dev = adapter->dev->ip_ptr; + struct ip_mc_list *ip_list; + struct pmo_igmp_offload_req *igmp_req = NULL; + int count = 0; + QDF_STATUS status; + + if (!in_dev) { + hdd_err("in_dev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + ip_list = in_dev->mc_list; + if (!ip_list) { + hdd_debug("ip list empty"); + return QDF_STATUS_E_FAILURE; + } + + igmp_req = qdf_mem_malloc(sizeof(*igmp_req)); + if (!igmp_req) + return QDF_STATUS_E_FAILURE; + + while (ip_list && ip_list->multiaddr && enable && + count < MAX_MC_IP_ADDR) { + if (IGMP_QUERY_ADDRESS != ip_list->multiaddr) { + igmp_req->grp_ip_address[count] = ip_list->multiaddr; + count++; + } + + ip_list = ip_list->next; + } + igmp_req->enable = enable; + igmp_req->num_grp_ip_address = count; + + status = ucfg_pmo_enable_igmp_offload(vdev, igmp_req); + if (status != QDF_STATUS_SUCCESS) + hdd_debug("Failed to configure igmp offload"); + + qdf_mem_free(igmp_req); + return status; +} + +/** + * hdd_enable_igmp_offload() - enable GTK offload + * @adapter: pointer to the adapter + * @vdev: VDEV objmgr pointer + * + * Enable IGMP offload in suspended case to save power + * + * Return: nothing + */ +static void hdd_enable_igmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + status = hdd_send_igmp_offload_params(adapter, vdev, true); + if (status != QDF_STATUS_SUCCESS) + hdd_debug("Failed to enable igmp offload"); +} + +/** + * hdd_disable_igmp_offload() - disable GTK offload + * @adapter: pointer to the adapter + * @vdev: VDEV objmgr pointer + * + * Enable IGMP offload in suspended case to save power + * + * Return: nothing + */ +static void hdd_disable_igmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + status = hdd_send_igmp_offload_params(adapter, vdev, false); + if (status != QDF_STATUS_SUCCESS) + hdd_debug("Failed to disable igmp offload"); +} +#else +static inline void hdd_enable_igmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{} + +static inline QDF_STATUS +hdd_send_igmp_offload_params(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, bool enable) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void hdd_disable_igmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{} +#endif + +/** + * hdd_disable_gtk_offload() - disable GTK offload + * @adapter: pointer to the adapter + * @vdev: VDEV objmgr pointer + * + * Central function to disable GTK offload. + * + * Return: nothing + */ +static void hdd_disable_gtk_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev) +{ + struct pmo_gtk_rsp_req gtk_rsp_request; + QDF_STATUS status; + + /* ensure to get gtk rsp first before disable it*/ + gtk_rsp_request.callback = wlan_hdd_cfg80211_update_replay_counter_cb; + + /* Passing as void* as PMO does not know legacy HDD adapter type */ + gtk_rsp_request.callback_context = (void *)adapter; + + status = ucfg_pmo_get_gtk_rsp(vdev, >k_rsp_request); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to send get gtk rsp status:%d", status); + return; + } + + hdd_debug("send get_gtk_rsp successful"); + status = ucfg_pmo_disable_gtk_offload_in_fwr(vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to disable gtk offload"); +} + +#ifdef WLAN_NS_OFFLOAD +/** + * __wlan_hdd_ipv6_changed() - IPv6 notifier callback function + * @net_dev: net_device whose IP address changed + * @event: event from kernel, NETDEV_UP or NETDEV_DOWN + * + * This is a callback function that is registered with the kernel via + * register_inet6addr_notifier() which allows the driver to be + * notified when there is an IPv6 address change. + * + * Return: None + */ +static void __wlan_hdd_ipv6_changed(struct net_device *net_dev, + unsigned long event) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(net_dev); + + errno = hdd_validate_adapter(adapter); + if (errno || adapter->dev != net_dev) + goto exit; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto exit; + + /* Only need to be notified for ipv6_add_addr + * No need for ipv6_del_addr or addrconf_ifdown + */ + if (event == NETDEV_UP && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + hdd_debug("invoking sme_dhcp_done_ind"); + sme_dhcp_done_ind(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + schedule_work(&adapter->ipv6_notifier_work); + } + +exit: + hdd_exit(); +} + +int wlan_hdd_ipv6_changed(struct notifier_block *nb, + unsigned long data, void *context) +{ + struct inet6_ifaddr *ifa = context; + struct net_device *net_dev = ifa->idev->dev; + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) + return NOTIFY_DONE; + + __wlan_hdd_ipv6_changed(net_dev, data); + + osif_vdev_sync_op_stop(vdev_sync); + + return NOTIFY_DONE; +} + +/** + * hdd_fill_ipv6_uc_addr() - fill IPv6 unicast addresses + * @idev: pointer to net device + * @ipv6_uc_addr: destination array to fill IPv6 addresses + * @ipv6addr_type: IPv6 Address type + * @scope_array: scope of ipv6 addr + * @count: number of IPv6 addresses + * + * This is the IPv6 utility function to populate unicast addresses. + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_fill_ipv6_uc_addr(struct inet6_dev *idev, + uint8_t ipv6_uc_addr[][QDF_IPV6_ADDR_SIZE], + uint8_t *ipv6addr_type, + enum pmo_ns_addr_scope *scope_array, + uint32_t *count) +{ + struct inet6_ifaddr *ifa; + struct list_head *p; + uint32_t scope; + + read_lock_bh(&idev->lock); + list_for_each(p, &idev->addr_list) { + if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { + read_unlock_bh(&idev->lock); + return -EINVAL; + } + ifa = list_entry(p, struct inet6_ifaddr, if_list); + if (ifa->flags & IFA_F_DADFAILED) + continue; + scope = ipv6_addr_src_scope(&ifa->addr); + switch (scope) { + case IPV6_ADDR_SCOPE_GLOBAL: + case IPV6_ADDR_SCOPE_LINKLOCAL: + qdf_mem_copy(ipv6_uc_addr[*count], &ifa->addr.s6_addr, + sizeof(ifa->addr.s6_addr)); + ipv6addr_type[*count] = PMO_IPV6_ADDR_UC_TYPE; + scope_array[*count] = ucfg_pmo_ns_addr_scope(scope); + hdd_debug("Index %d scope = %s UC-Address: %pI6", + *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? + "LINK LOCAL" : "GLOBAL", ipv6_uc_addr[*count]); + *count += 1; + break; + default: + hdd_warn("The Scope %d is not supported", scope); + } + } + + read_unlock_bh(&idev->lock); + return 0; +} + +/** + * hdd_fill_ipv6_ac_addr() - fill IPv6 anycast addresses + * @idev: pointer to net device + * @ipv6_ac_addr: destination array to fill IPv6 addresses + * @ipv6addr_type: IPv6 Address type + * @scope_array: scope of ipv6 addr + * @count: number of IPv6 addresses + * + * This is the IPv6 utility function to populate anycast addresses. + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_fill_ipv6_ac_addr(struct inet6_dev *idev, + uint8_t ipv6_ac_addr[][QDF_IPV6_ADDR_SIZE], + uint8_t *ipv6addr_type, + enum pmo_ns_addr_scope *scope_array, + uint32_t *count) +{ + struct ifacaddr6 *ifaca; + uint32_t scope; + + read_lock_bh(&idev->lock); + for (ifaca = idev->ac_list; ifaca; ifaca = ifaca->aca_next) { + if (*count >= PMO_MAC_NUM_TARGET_IPV6_NS_OFFLOAD_NA) { + read_unlock_bh(&idev->lock); + return -EINVAL; + } + /* For anycast addr no DAD */ + scope = ipv6_addr_src_scope(&ifaca->aca_addr); + switch (scope) { + case IPV6_ADDR_SCOPE_GLOBAL: + case IPV6_ADDR_SCOPE_LINKLOCAL: + qdf_mem_copy(ipv6_ac_addr[*count], &ifaca->aca_addr, + sizeof(ifaca->aca_addr)); + ipv6addr_type[*count] = PMO_IPV6_ADDR_AC_TYPE; + scope_array[*count] = ucfg_pmo_ns_addr_scope(scope); + hdd_debug("Index %d scope = %s AC-Address: %pI6", + *count, (scope == IPV6_ADDR_SCOPE_LINKLOCAL) ? + "LINK LOCAL" : "GLOBAL", ipv6_ac_addr[*count]); + *count += 1; + break; + default: + hdd_warn("The Scope %d is not supported", scope); + } + } + + read_unlock_bh(&idev->lock); + return 0; +} + +void hdd_enable_ns_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct inet6_dev *in6_dev; + struct pmo_ns_req *ns_req; + QDF_STATUS status; + int errno; + uint8_t vdev_id; + + hdd_enter(); + + if (!psoc) { + hdd_err("psoc is NULL"); + goto out; + } + + in6_dev = __in6_dev_get(adapter->dev); + if (!in6_dev) { + hdd_err("IPv6 dev does not exist. Failed to request NSOffload"); + goto out; + } + + ns_req = qdf_mem_malloc(sizeof(*ns_req)); + if (!ns_req) + goto out; + + vdev_id = wlan_vdev_get_id(vdev); + + ns_req->psoc = psoc; + ns_req->vdev_id = vdev_id; + ns_req->trigger = trigger; + ns_req->count = 0; + + /* check if offload cache and send is required or not */ + status = ucfg_pmo_ns_offload_check(psoc, trigger, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("NS offload is not required"); + goto free_req; + } + + if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) { + hdd_debug("Dynamic arp ns offload disabled"); + ucfg_pmo_flush_ns_offload_req(vdev); + goto skip_cache_ns; + } + + /* Unicast Addresses */ + errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr, + ns_req->ipv6_addr_type, ns_req->scope, + &ns_req->count); + if (errno) { + hdd_disable_ns_offload(adapter, vdev, trigger); + hdd_debug("Max supported addresses: disabling NS offload"); + goto free_req; + } + + /* Anycast Addresses */ + errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr, + ns_req->ipv6_addr_type, ns_req->scope, + &ns_req->count); + if (errno) { + hdd_disable_ns_offload(adapter, vdev, trigger); + hdd_debug("Max supported addresses: disabling NS offload"); + goto free_req; + } + + /* cache ns request */ + status = ucfg_pmo_cache_ns_offload_req(ns_req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Failed to cache ns request; status:%d", status); + goto free_req; + } + +skip_cache_ns: + /* enable ns request */ + status = ucfg_pmo_enable_ns_offload_in_fwr(vdev, trigger); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("Failed to enable ns offload; status:%d", status); + goto free_req; + } + + hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, SIR_OFFLOAD_ENABLE); +free_req: + qdf_mem_free(ns_req); + +out: + hdd_exit(); +} + +void hdd_disable_ns_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + status = ucfg_pmo_ns_offload_check(hdd_ctx->psoc, trigger, + wlan_vdev_get_id(vdev)); + if (status != QDF_STATUS_SUCCESS) { + hdd_debug("Flushing of NS offload not required"); + goto out; + } + + status = ucfg_pmo_flush_ns_offload_req(vdev); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to flush NS Offload"); + goto out; + } + + status = ucfg_pmo_disable_ns_offload_in_fwr(vdev, trigger); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Failed to disable NS Offload"); + else + hdd_wlan_offload_event(SIR_IPV6_NS_OFFLOAD, + SIR_OFFLOAD_DISABLE); +out: + hdd_exit(); + +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + mac_handle_t mac_handle; + + if (!adapter) { + hdd_err_rl("null hdd_adapter pointer"); + return; + } + + mac_handle = hdd_adapter_get_mac_handle(adapter); + + if (!mac_handle) { + hdd_err_rl("null mac_handle pointer"); + return; + } + + hdd_adapter_for_each_active_link_info(adapter, link_info) + sme_ps_update(mac_handle, link_info->vdev_id); +} +#else +static void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter) +{ + int i; + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + mac_handle_t mac_handle; + + if (!adapter) { + hdd_err_rl("null hdd_adapter pointer"); + return; + } + + mac_handle = hdd_adapter_get_mac_handle(adapter); + + if (!mac_handle) { + hdd_err_rl("null mac_handle pointer"); + return; + } + + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + sme_ps_update(mac_handle, link_adapter->deflink->vdev_id); + } +} +#endif +#else +static inline void hdd_send_mlo_ps_to_fw(struct hdd_adapter *adapter) +{} +#endif + +void hdd_send_ps_config_to_fw(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + bool is_mlo_vdev; + + if (hdd_validate_adapter(adapter)) + return; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(adapter->deflink->vdev); + + if (!is_mlo_vdev) { + sme_ps_update(hdd_ctx->mac_handle, adapter->deflink->vdev_id); + return; + } + + hdd_send_mlo_ps_to_fw(adapter); +} + +/** + * __hdd_ipv6_notifier_work_queue() - IPv6 notification work function + * @adapter: adapter whose IP address changed + * + * This function performs the work initially triggered by a callback + * from the IPv6 netdev notifier. Since this means there has been a + * change in IPv6 state for the interface, the NS offload is + * reconfigured. + * + * Return: None + */ +static void __hdd_ipv6_notifier_work_queue(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + int errno; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + errno = hdd_validate_adapter(adapter); + if (errno) + goto exit; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto exit; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + goto exit; + + hdd_enable_ns_offload(adapter, vdev, pmo_ipv6_change_notify); + hdd_enable_icmp_offload(adapter, vdev, pmo_ipv6_change_notify); + hdd_send_ps_config_to_fw(adapter); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); +exit: + hdd_exit(); +} + +void hdd_ipv6_notifier_work_queue(struct work_struct *work) +{ + struct hdd_adapter *adapter = container_of(work, struct hdd_adapter, + ipv6_notifier_work); + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync)) + return; + + __hdd_ipv6_notifier_work_queue(adapter); + + osif_vdev_sync_op_stop(vdev_sync); +} +#endif /* WLAN_NS_OFFLOAD */ + +static void hdd_enable_hw_filter(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + hdd_enter(); + + status = ucfg_pmo_enable_hw_filter_in_fwr(vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to enable hardware filter"); + + hdd_exit(); +} + +static void hdd_disable_hw_filter(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + hdd_enter(); + + status = ucfg_pmo_disable_hw_filter_in_fwr(vdev); + if (status != QDF_STATUS_SUCCESS) + hdd_info("Failed to disable hardware filter"); + + hdd_exit(); +} + +static void hdd_enable_action_frame_patterns(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + hdd_enter(); + + status = ucfg_pmo_enable_action_frame_patterns(vdev, + QDF_SYSTEM_SUSPEND); + if (QDF_IS_STATUS_ERROR(status)) + hdd_info("Failed to enable action frame patterns"); + + hdd_exit(); +} + +static void hdd_disable_action_frame_patterns(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + + hdd_enter(); + + status = ucfg_pmo_disable_action_frame_patterns(vdev); + if (QDF_IS_STATUS_ERROR(status)) + hdd_info("Failed to disable action frame patterns"); + + hdd_exit(); +} + +void hdd_enable_host_offloads(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + goto out; + } + + if (!ucfg_pmo_is_vdev_supports_offload(vdev)) { + hdd_debug("offload is not supported on vdev opmode %d", + adapter->device_mode); + goto put_vdev; + } + + if (!ucfg_pmo_is_vdev_connected(vdev)) { + hdd_debug("offload is not supported on disconnected vdevs"); + goto put_vdev; + } + + hdd_debug("enable offloads"); + hdd_enable_gtk_offload(vdev); + hdd_enable_arp_offload(adapter, vdev, trigger); + hdd_enable_ns_offload(adapter, vdev, trigger); + hdd_enable_mc_addr_filtering(adapter, trigger); + if (adapter->device_mode == QDF_STA_MODE) + hdd_enable_igmp_offload(adapter, vdev); + + if (adapter->device_mode != QDF_NDI_MODE) + hdd_enable_hw_filter(vdev); + hdd_enable_action_frame_patterns(vdev); +put_vdev: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); +out: + hdd_exit(); + +} + +void hdd_disable_host_offloads(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + goto out; + } + + if (!ucfg_pmo_is_vdev_supports_offload(vdev)) { + hdd_info("offload is not supported on this vdev opmode: %d", + adapter->device_mode); + goto put_vdev; + } + + if (!ucfg_pmo_is_vdev_connected(vdev)) { + hdd_info("vdev is not connected"); + goto put_vdev; + } + + hdd_debug("disable offloads"); + hdd_disable_gtk_offload(adapter, vdev); + hdd_disable_arp_offload(adapter, vdev, trigger); + hdd_disable_ns_offload(adapter, vdev, trigger); + hdd_disable_mc_addr_filtering(adapter, trigger); + if (adapter->device_mode == QDF_STA_MODE) + hdd_disable_igmp_offload(adapter, vdev); + if (adapter->device_mode != QDF_NDI_MODE) + hdd_disable_hw_filter(vdev); + hdd_disable_action_frame_patterns(vdev); + +put_vdev: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); +out: + hdd_exit(); + +} + +/** + * hdd_lookup_ifaddr() - Lookup interface address data by name + * @adapter: the adapter whose name should be searched for + * + * return in_ifaddr pointer on success, NULL for failure + */ +static struct in_ifaddr *hdd_lookup_ifaddr(struct hdd_adapter *adapter) +{ + struct in_ifaddr *ifa; + struct in_device *in_dev; + + if (!adapter) { + hdd_err("adapter is null"); + return NULL; + } + + in_dev = __in_dev_get_rtnl(adapter->dev); + if (!in_dev) { + hdd_err("Failed to get in_device"); + return NULL; + } + + /* lookup address data by interface name */ + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { + if (!strcmp(adapter->dev->name, ifa->ifa_label)) + return ifa; + } + + return NULL; +} + +/** + * hdd_populate_ipv4_addr() - Populates the adapter's IPv4 address + * @adapter: the adapter whose IPv4 address is desired + * @ipv4_addr: the address of the array to copy the IPv4 address into + * + * return: zero for success; non-zero for failure + */ +static int hdd_populate_ipv4_addr(struct hdd_adapter *adapter, + uint8_t *ipv4_addr) +{ + struct in_ifaddr *ifa; + int i; + + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + if (!ipv4_addr) { + hdd_err("ipv4_addr is null"); + return -EINVAL; + } + + ifa = hdd_lookup_ifaddr(adapter); + if (!ifa || !ifa->ifa_local) { + hdd_err("ipv4 address not found"); + return -EINVAL; + } + + /* convert u32 to byte array */ + for (i = 0; i < 4; i++) + ipv4_addr[i] = (ifa->ifa_local >> i * 8) & 0xff; + + return 0; +} + +int hdd_set_grat_arp_keepalive(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + int exit_code; + struct hdd_context *hdd_ctx; + struct hdd_station_ctx *sta_ctx; + struct keep_alive_req req = { + .packetType = SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP, + .dest_macaddr = QDF_MAC_ADDR_BCAST_INIT, + }; + + if (!adapter) { + hdd_err("adapter is null"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd_ctx is null"); + return -EINVAL; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!sta_ctx) { + hdd_err("sta_ctx is null"); + return -EINVAL; + } + + exit_code = hdd_populate_ipv4_addr(adapter, req.hostIpv4Addr); + if (exit_code) { + hdd_err("Failed to populate ipv4 address"); + return exit_code; + } + + /* according to RFC5227, sender/target ip address should be the same */ + qdf_mem_copy(&req.destIpv4Addr, &req.hostIpv4Addr, + sizeof(req.destIpv4Addr)); + + qdf_copy_macaddr(&req.bssid, &sta_ctx->conn_info.bssid); + ucfg_mlme_get_sta_keep_alive_period(hdd_ctx->psoc, &req.timePeriod); + req.sessionId = adapter->deflink->vdev_id; + + hdd_debug("Setting gratuitous ARP keepalive; ipv4_addr:%u.%u.%u.%u", + req.hostIpv4Addr[0], req.hostIpv4Addr[1], + req.hostIpv4Addr[2], req.hostIpv4Addr[3]); + + status = sme_set_keep_alive(hdd_ctx->mac_handle, req.sessionId, &req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set keepalive"); + return qdf_status_to_os_return(status); + } + + return 0; +} + +/** + * __hdd_ipv4_notifier_work_queue() - IPv4 notification work function + * @adapter: adapter whose IP address changed + * + * This function performs the work initially triggered by a callback + * from the IPv4 netdev notifier. Since this means there has been a + * change in IPv4 state for the interface, the ARP offload is + * reconfigured. Also, Updates the HLP IE info with IP address info + * to fw if LFR3 is enabled + * + * Return: None + */ +static void __hdd_ipv4_notifier_work_queue(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + int errno; + struct in_ifaddr *ifa; + enum station_keepalive_method val; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + errno = hdd_validate_adapter(adapter); + if (errno) + goto exit; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto exit; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (!vdev) + goto exit; + + hdd_enable_arp_offload(adapter, vdev, pmo_ipv4_change_notify); + hdd_enable_icmp_offload(adapter, vdev, pmo_ipv4_change_notify); + + status = ucfg_mlme_get_sta_keepalive_method(hdd_ctx->psoc, &val); + if (QDF_IS_STATUS_ERROR(status)) + goto vdev_ref; + + if (val == MLME_STA_KEEPALIVE_GRAT_ARP) + hdd_set_grat_arp_keepalive(adapter); + + hdd_debug("FILS Roaming support: %d", + hdd_ctx->is_fils_roaming_supported); + + ifa = hdd_lookup_ifaddr(adapter); + if (ifa && hdd_ctx->is_fils_roaming_supported) + sme_send_hlp_ie_info(hdd_ctx->mac_handle, + wlan_vdev_get_id(vdev), + ifa->ifa_local); + hdd_send_ps_config_to_fw(adapter); + +vdev_ref: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); +exit: + hdd_exit(); +} + +void hdd_ipv4_notifier_work_queue(struct work_struct *work) +{ + struct hdd_adapter *adapter = container_of(work, struct hdd_adapter, + ipv4_notifier_work); + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(adapter->dev, &vdev_sync)) + return; + + __hdd_ipv4_notifier_work_queue(adapter); + + osif_vdev_sync_op_stop(vdev_sync); +} + +/** + * __wlan_hdd_ipv4_changed() - IPv4 notifier callback function + * @net_dev: the net_device whose IP address changed + * + * This is a callback function that is registered with the kernel via + * register_inetaddr_notifier() which allows the driver to be + * notified when there is an IPv4 address change. + * + * Return: None + */ +static void __wlan_hdd_ipv4_changed(struct net_device *net_dev) +{ + struct in_ifaddr *ifa; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(net_dev); + + errno = hdd_validate_adapter(adapter); + if (errno || adapter->dev != net_dev) + goto exit; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + goto exit; + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_debug("invoking sme_dhcp_done_ind"); + sme_dhcp_done_ind(hdd_ctx->mac_handle, + adapter->deflink->vdev_id); + + if (!ucfg_pmo_is_arp_offload_enabled(hdd_ctx->psoc)) { + hdd_debug("Offload not enabled"); + goto exit; + } + + ifa = hdd_lookup_ifaddr(adapter); + if (ifa && ifa->ifa_local) + schedule_work(&adapter->ipv4_notifier_work); + } + +exit: + hdd_exit(); +} + +int wlan_hdd_ipv4_changed(struct notifier_block *nb, + unsigned long data, void *context) +{ + struct in_ifaddr *ifa = context; + struct net_device *net_dev = ifa->ifa_dev->dev; + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) + return NOTIFY_DONE; + + __wlan_hdd_ipv4_changed(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return NOTIFY_DONE; +} + +#ifdef FEATURE_RUNTIME_PM +/* For CPU, the enter & exit latency of the deepest LPM mode(CXPC) + * is about ~10ms. so long as required QoS latency is longer than 10ms, + * CPU can enter CXPC mode. + * The vote value is in microseconds. + */ +static bool wlan_hdd_is_cpu_cxpc_allowed(struct hdd_context *hdd_ctx, + unsigned long vote) +{ + if (vote >= hdd_ctx->config->cpu_cxpc_threshold) + return true; + else + return false; +} + +int wlan_hdd_pm_qos_notify(struct notifier_block *nb, unsigned long curr_val, + void *context) +{ + struct hdd_context *hdd_ctx = container_of(nb, struct hdd_context, + pm_qos_notifier); + void *hif_ctx; + bool is_any_sta_connected = false; + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug_rl("Driver Module closed; skipping pm qos notify"); + return 0; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + is_any_sta_connected = hdd_is_any_sta_connected(hdd_ctx); + + hdd_debug("PM QOS update: runtime_pm_prevented %d Current value: %ld, is_any_sta_connected %d", + hdd_ctx->runtime_pm_prevented, curr_val, + is_any_sta_connected); + qdf_spin_lock_irqsave(&hdd_ctx->pm_qos_lock); + + if (!hdd_ctx->runtime_pm_prevented && + is_any_sta_connected && + !wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val)) { + hif_rtpm_get(HIF_RTPM_GET_NORESUME, HIF_RTPM_ID_PM_QOS_NOTIFY); + hdd_ctx->runtime_pm_prevented = true; + } else if (hdd_ctx->runtime_pm_prevented && + wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val)) { + hif_rtpm_put(HIF_RTPM_PUT_NOIDLE, HIF_RTPM_ID_PM_QOS_NOTIFY); + hdd_ctx->runtime_pm_prevented = false; + } + + qdf_spin_unlock_irqrestore(&hdd_ctx->pm_qos_lock); + + return NOTIFY_DONE; +} + +/** cpuidle_governor_latency_req() is not exported by upstream kernel **/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) && \ + defined(__ANDROID_COMMON_KERNEL__)) +bool wlan_hdd_is_cpu_pm_qos_in_progress(struct hdd_context *hdd_ctx) +{ + long long curr_val_ns; + long long curr_val_us; + int max_cpu_num; + + if (!hdd_is_any_sta_connected(hdd_ctx)) { + hdd_debug("No active wifi connections. Ignore PM QOS vote"); + return false; + } + + max_cpu_num = nr_cpu_ids - 1; + + /* Get PM QoS vote from last cpu, as no device votes on that cpu + * so by default we get global PM QoS vote from last cpu. + */ + curr_val_ns = cpuidle_governor_latency_req(max_cpu_num); + curr_val_us = curr_val_ns / NSEC_PER_USEC; + hdd_debug("PM QoS current value: %lld", curr_val_us); + if (!wlan_hdd_is_cpu_cxpc_allowed(hdd_ctx, curr_val_us)) + return true; + else + return false; +} +#endif +#endif + +/** + * hdd_get_ipv4_local_interface() - get ipv4 local interface from iface list + * @adapter: Adapter context for which ARP offload is to be configured + * + * Return: + * ifa - on successful operation, + * NULL - on failure of operation + */ +static struct in_ifaddr *hdd_get_ipv4_local_interface( + struct hdd_adapter *adapter) +{ + struct in_ifaddr **ifap = NULL; + struct in_ifaddr *ifa = NULL; + struct in_device *in_dev; + + in_dev = __in_dev_get_rtnl(adapter->dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (!strcmp(adapter->dev->name, ifa->ifa_label)) { + /* if match break */ + return ifa; + } + } + } + ifa = NULL; + + return ifa; +} + +void hdd_enable_arp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + QDF_STATUS status; + struct pmo_arp_req *arp_req; + struct in_ifaddr *ifa; + uint8_t vdev_id; + + hdd_enter(); + + arp_req = qdf_mem_malloc(sizeof(*arp_req)); + if (!arp_req) + return; + + vdev_id = wlan_vdev_get_id(vdev); + + arp_req->psoc = psoc; + arp_req->vdev_id = vdev_id; + arp_req->trigger = trigger; + + status = ucfg_pmo_check_arp_offload(psoc, trigger, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("ARP offload not required"); + goto free_req; + } + + if (ucfg_pmo_get_arp_ns_offload_dynamic_disable(vdev)) { + hdd_debug("Dynamic arp ns offload disabled"); + ucfg_pmo_flush_arp_offload_req(vdev); + goto skip_cache_arp; + } + + ifa = hdd_get_ipv4_local_interface(adapter); + if (!ifa || !ifa->ifa_local) { + hdd_info("IP Address is not assigned"); + status = QDF_STATUS_NOT_INITIALIZED; + goto free_req; + } + + arp_req->ipv4_addr = (uint32_t)ifa->ifa_local; + + status = ucfg_pmo_cache_arp_offload_req(arp_req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to cache arp offload req; status:%d", status); + goto free_req; + } + +skip_cache_arp: + status = ucfg_pmo_enable_arp_offload_in_fwr(vdev, trigger); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed arp offload config in fw; status:%d", status); + goto free_req; + } + + hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, PMO_OFFLOAD_ENABLE); + +free_req: + qdf_mem_free(arp_req); +} + +#ifdef WLAN_FEATURE_ICMP_OFFLOAD +/** + * hdd_fill_ipv4_addr() - fill IPv4 addresses + * @adapter: Adapter context for which ICMP offload is to be configured + * @pmo_icmp_req: pointer to ICMP offload request params + * + * This is the IPv4 utility function to populate address. + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_fill_ipv4_addr(struct hdd_adapter *adapter, + struct pmo_icmp_offload *pmo_icmp_req) +{ + struct in_ifaddr *ifa; + uint8_t ipv4_addr_array[QDF_IPV4_ADDR_SIZE]; + int i; + + ifa = hdd_get_ipv4_local_interface(adapter); + if (!ifa || !ifa->ifa_local) { + hdd_debug("IP Address is not assigned"); + return -EINVAL; + } + + /* converting u32 to IPv4 address */ + for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++) + ipv4_addr_array[i] = (ifa->ifa_local >> i * 8) & 0xff; + + qdf_mem_copy(pmo_icmp_req->ipv4_addr, &ipv4_addr_array, + QDF_IPV4_ADDR_SIZE); + + return 0; +} + +/** + * hdd_fill_ipv6_addr() - fill IPv6 addresses + * @adapter: Adapter context for which ICMP offload is to be configured + * @pmo_icmp_req: pointer to ICMP offload request params + * + * This is the IPv6 utility function to populate addresses. + * + * Return: 0 on success, error number otherwise. + */ +static int hdd_fill_ipv6_addr(struct hdd_adapter *adapter, + struct pmo_icmp_offload *pmo_icmp_req) +{ + struct inet6_dev *in6_dev; + struct pmo_ns_req *ns_req; + int i, errno; + + in6_dev = __in6_dev_get(adapter->dev); + if (!in6_dev) { + hdd_err_rl("IPv6 dev does not exist"); + return -EINVAL; + } + + ns_req = qdf_mem_malloc(sizeof(*ns_req)); + if (!ns_req) + return -ENOMEM; + + ns_req->count = 0; + /* Unicast Addresses */ + errno = hdd_fill_ipv6_uc_addr(in6_dev, ns_req->ipv6_addr, + ns_req->ipv6_addr_type, ns_req->scope, + &ns_req->count); + if (errno) { + hdd_debug("Reached Max IPv6 supported address %d", + ns_req->count); + goto free_req; + } + /* Anycast Addresses */ + errno = hdd_fill_ipv6_ac_addr(in6_dev, ns_req->ipv6_addr, + ns_req->ipv6_addr_type, ns_req->scope, + &ns_req->count); + if (errno) { + hdd_debug("Reached Max IPv6 supported address %d", + ns_req->count); + goto free_req; + } + + pmo_icmp_req->ipv6_count = ns_req->count; + for (i = 0; i < pmo_icmp_req->ipv6_count; i++) { + qdf_mem_copy(&pmo_icmp_req->ipv6_addr[i], &ns_req->ipv6_addr[i], + QDF_IPV6_ADDR_SIZE); + } + +free_req: + qdf_mem_free(ns_req); + return errno; +} + +void hdd_enable_icmp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + struct pmo_icmp_offload *pmo_icmp_req; + bool is_icmp_enable; + QDF_STATUS status; + uint8_t vdev_id; + + is_icmp_enable = ucfg_pmo_is_icmp_offload_enabled(psoc); + if (!is_icmp_enable) { + hdd_debug("ICMP Offload not enabled"); + return; + } + + pmo_icmp_req = qdf_mem_malloc(sizeof(*pmo_icmp_req)); + if (!pmo_icmp_req) + return; + + vdev_id = wlan_vdev_get_id(vdev); + status = ucfg_pmo_check_icmp_offload(psoc, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + goto free_req; + + pmo_icmp_req->vdev_id = vdev_id; + pmo_icmp_req->enable = is_icmp_enable; + pmo_icmp_req->trigger = trigger; + + switch (trigger) { + case pmo_ipv4_change_notify: + if (hdd_fill_ipv4_addr(adapter, pmo_icmp_req)) { + hdd_debug("Unable to populate IPv4 Address"); + goto free_req; + } + break; + case pmo_ipv6_change_notify: + if (hdd_fill_ipv6_addr(adapter, pmo_icmp_req)) { + hdd_debug("Unable to populate IPv6 Address"); + goto free_req; + } + break; + default: + QDF_DEBUG_PANIC("The trigger %d is not supported", trigger); + goto free_req; + } + + status = ucfg_pmo_config_icmp_offload(psoc, pmo_icmp_req); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("icmp offload config in fw failed: %d", status); + +free_req: + qdf_mem_free(pmo_icmp_req); +} +#endif + +void hdd_disable_arp_offload(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + enum pmo_offload_trigger trigger) +{ + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter(); + + status = ucfg_pmo_check_arp_offload(hdd_ctx->psoc, trigger, + wlan_vdev_get_id(vdev)); + if (status != QDF_STATUS_SUCCESS) { + hdd_debug("Flushing of ARP offload not required"); + return; + } + + status = ucfg_pmo_flush_arp_offload_req(vdev); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Failed to flush arp Offload"); + return; + } + + status = ucfg_pmo_disable_arp_offload_in_fwr(vdev, trigger); + if (status == QDF_STATUS_SUCCESS) + hdd_wlan_offload_event(PMO_IPV4_ARP_REPLY_OFFLOAD, + PMO_OFFLOAD_DISABLE); + else + hdd_info("fail to disable arp offload"); +} + +void hdd_enable_mc_addr_filtering(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) + return; + + status = ucfg_pmo_enable_mc_addr_filtering_in_fwr( + hdd_ctx->psoc, + adapter->deflink->vdev_id, + trigger); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("failed to enable mc list; status:%d", status); + +} + +void hdd_disable_mc_addr_filtering(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + status = ucfg_pmo_disable_mc_addr_filtering_in_fwr( + hdd_ctx->psoc, + adapter->deflink->vdev_id, + trigger); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to disable mc list; status:%d", status); +} + +int hdd_cache_mc_addr_list(struct pmo_mc_addr_list_params *mc_list_config) +{ + QDF_STATUS status; + + status = ucfg_pmo_cache_mc_addr_list(mc_list_config); + + return qdf_status_to_os_return(status); +} + +void hdd_disable_and_flush_mc_addr_list(struct hdd_adapter *adapter, + enum pmo_offload_trigger trigger) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + + /* disable mc list first because the mc list is cached in PMO */ + status = ucfg_pmo_disable_mc_addr_filtering_in_fwr( + hdd_ctx->psoc, + adapter->deflink->vdev_id, + trigger); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("failed to disable mc list; status:%d", status); + + status = ucfg_pmo_flush_mc_addr_list(hdd_ctx->psoc, + adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_debug("failed to flush mc list; status:%d", status); +} + +/** + * hdd_update_conn_state_mask() - record info needed by wma_suspend_req + * @adapter: adapter to get info from + * @conn_state_mask: mask of connection info + * + * currently only need to send connection info. + */ +static void hdd_update_conn_state_mask(struct hdd_adapter *adapter, + uint32_t *conn_state_mask) +{ + if (hdd_cm_is_vdev_associated(adapter->deflink)) + *conn_state_mask |= (1 << adapter->deflink->vdev_id); +} + +/** + * hdd_suspend_wlan() - Driver suspend function + * + * Return: 0 on success else error code. + */ +static int +hdd_suspend_wlan(void) +{ + struct hdd_context *hdd_ctx; + QDF_STATUS status; + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + uint32_t conn_state_mask = 0; + struct wlan_hdd_link_info *link_info; + + hdd_info("WLAN being suspended by OS"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!", + cds_get_driver_state()); + return -EINVAL; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_SUSPEND_WLAN) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + continue; + + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_enable_default_pkt_filters( + hdd_ctx, link_info->vdev_id); + + /* Configure supported OffLoads */ + hdd_enable_host_offloads(adapter, pmo_apps_suspend); + hdd_update_conn_state_mask(adapter, &conn_state_mask); + } + hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_SUSPEND_WLAN); + } + + status = ucfg_pmo_psoc_user_space_suspend_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + if (status != QDF_STATUS_SUCCESS) + return -EAGAIN; + + hdd_ctx->hdd_wlan_suspended = true; + + ucfg_dp_suspend_wlan(hdd_ctx->psoc); + + hdd_configure_sar_sleep_index(hdd_ctx); + + hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_SUSPEND); + + return 0; +} + +/** + * hdd_resume_wlan() - Driver resume function + * + * Return: 0 on success else error code. + */ +static int hdd_resume_wlan(void) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter, *next_adapter = NULL; + QDF_STATUS status; + struct wlan_hdd_link_info *link_info; + + hdd_info("WLAN being resumed by OS"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return -EINVAL; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!", + cds_get_driver_state()); + return -EINVAL; + } + + hdd_ctx->hdd_wlan_suspended = false; + hdd_wlan_suspend_resume_event(HDD_WLAN_EARLY_RESUME); + + /*loop through all adapters. Concurrency */ + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_RESUME_WLAN) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + continue; + + /* Disable supported OffLoads */ + hdd_disable_host_offloads(adapter, pmo_apps_resume); + + if (adapter->device_mode == QDF_STA_MODE) + status = hdd_disable_default_pkt_filters( + hdd_ctx, link_info->vdev_id); + + hdd_restart_tsf_sync_post_wlan_resume(adapter); + } + hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_RESUME_WLAN); + } + + ucfg_ipa_resume(hdd_ctx->pdev); + ucfg_dp_resume_wlan(hdd_ctx->psoc); + status = ucfg_pmo_psoc_user_space_resume_req(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + hdd_configure_sar_resume_index(hdd_ctx); + + return 0; +} + +/** + * hdd_pause_ns() - Network stack pause function + * @hdd_ctx: hdd context + * + * Return: 0 on success else error code. + */ +static int hdd_pause_ns(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + + hdd_debug("Pause NS"); + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_info("Recovery in Progress. State: 0x%x Ignore suspend!!!", + cds_get_driver_state()); + return -EINVAL; + } + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_SUSPEND_WLAN) { + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) { + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_SUSPEND_WLAN); + continue; + } + + /* stop all TX queues before suspend */ + hdd_debug("Disabling queues for dev mode %s", + qdf_opmode_str(adapter->device_mode)); + wlan_hdd_netif_queue_control(adapter, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_SUSPEND_WLAN); + } + + return 0; +} + +/** + * hdd_unpause_ns() - Network stack unpause function + * @hdd_ctx: hdd context + * + * Return: 0 on success else error code. + */ +static int hdd_unpause_ns(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + + hdd_debug("Unpause NS"); + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_info("Recovery in Progress. State: 0x%x Ignore resume!!!", + cds_get_driver_state()); + return -EINVAL; + } + + /*loop through all adapters. Concurrency */ + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_RESUME_WLAN) { + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) { + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_RESUME_WLAN); + continue; + } + + /* wake the tx queues */ + hdd_debug("Enabling queues for dev mode %s", + qdf_opmode_str(adapter->device_mode)); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + + hdd_adapter_dev_put_debug(adapter, NET_DEV_HOLD_RESUME_WLAN); + } + + return 0; +} +void hdd_svc_fw_shutdown_ind(struct device *dev) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + hdd_ctx ? wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_FW_SHUTDOWN_IND, + NULL, 0) : 0; +} + +/** + * wlan_hdd_set_twt_responder() - wrapper to configure twt responder + * in sap_config + * @hdd_ctx: Pointer to hdd context + * @adapter: Pointer to hostapd hdd adapter + * + * Return: none + */ +#if defined(WLAN_SUPPORT_TWT) && \ + ((LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)) || \ + defined(CFG80211_TWT_RESPONDER_SUPPORT)) +static void wlan_hdd_set_twt_responder(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + bool twt_responder; + + twt_responder = + adapter->deflink->session.ap.sap_config.cfg80211_twt_responder; + wlan_hdd_configure_twt_responder(hdd_ctx, twt_responder); +} +#else +static inline void wlan_hdd_set_twt_responder(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ +} +#endif + +/** + * hdd_ssr_restart_sap() - restart sap on SSR + * @hdd_ctx: hdd context + * + * Return: nothing + */ +static void hdd_ssr_restart_sap(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + + hdd_enter(); + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_SSR_RESTART_SAP) { + if (adapter->device_mode != QDF_SAP_MODE) + goto next_adapter; + + if (test_bit(SOFTAP_INIT_DONE, &adapter->deflink->link_flags)) { + hdd_debug("Restart prev SAP session, event_flags 0x%lx, link_flags 0x%lx(%s)", + adapter->event_flags, + adapter->deflink->link_flags, + adapter->dev->name); + wlan_hdd_set_twt_responder(hdd_ctx, adapter); + wlan_hdd_start_sap(adapter->deflink, true); + } +next_adapter: + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_SSR_RESTART_SAP); + } + + hdd_exit(); +} + +QDF_STATUS hdd_wlan_shutdown(void) +{ + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + hdd_info("WLAN driver shutting down!"); + + /* Get the HDD context. */ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return QDF_STATUS_E_FAILURE; + + if (ucfg_ipa_is_enabled()) { + ucfg_ipa_uc_force_pipe_shutdown(hdd_ctx->pdev); + + if (pld_is_fw_rejuvenate(hdd_ctx->parent_dev) || + pld_is_pdr(hdd_ctx->parent_dev)) + ucfg_ipa_fw_rejuvenate_send_msg(hdd_ctx->pdev); + } + + hdd_set_connection_in_progress(false); + + hdd_debug("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID); + + /* resume wlan threads before adapter reset which does vdev destroy */ + if (hdd_ctx->is_scheduler_suspended) { + scheduler_resume(); + hdd_ctx->is_scheduler_suspended = false; + hdd_ctx->is_wiphy_suspended = false; + hdd_ctx->hdd_wlan_suspended = false; + ucfg_pmo_resume_all_components(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + } + + wlan_hdd_rx_thread_resume(hdd_ctx); + + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (adapter) { + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (vdev) { + ucfg_pkt_capture_resume_mon_thread(vdev); + hdd_objmgr_put_vdev_by_user( + vdev, WLAN_OSIF_POWER_ID); + } else { + hdd_err("vdev is NULL"); + } + } + } + + hdd_reset_all_adapters(hdd_ctx); + + ucfg_ipa_uc_ssr_cleanup(hdd_ctx->pdev); + + /* Flush cached rx frame queue */ + if (soc) + cdp_flush_cache_rx_queue(soc); + + /* De-register the HDD callbacks */ + hdd_deregister_cb(hdd_ctx); + + hdd_wlan_stop_modules(hdd_ctx, false); + + hdd_lpass_notify_stop(hdd_ctx); + + qdf_set_smmu_fault_state(false); + hdd_info("WLAN driver shutdown complete"); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * hdd_wlan_ssr_reinit_event() - send ssr reinit state + * + * This Function send send ssr reinit state diag event + * + * Return: void. + */ +static void hdd_wlan_ssr_reinit_event(void) +{ + WLAN_HOST_DIAG_EVENT_DEF(ssr_reinit, struct host_event_wlan_ssr_reinit); + qdf_mem_zero(&ssr_reinit, sizeof(ssr_reinit)); + ssr_reinit.status = SSR_SUB_SYSTEM_REINIT; + WLAN_HOST_DIAG_EVENT_REPORT(&ssr_reinit, + EVENT_WLAN_SSR_REINIT_SUBSYSTEM); +} +#else +static inline void hdd_wlan_ssr_reinit_event(void) +{ + +} +#endif + +#ifdef WLAN_FEATURE_DBAM_CONFIG +/** + * hdd_restore_dbam_config() - restore and send dbam config to fw + * @hdd_ctx: HDD context + * + * This function is used to send store dbam config to fw + * in case of wlan re-init + * + * Return: void + */ +static void hdd_restore_dbam_config(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (hdd_is_interface_up(adapter) && + adapter->is_dbam_configured) + hdd_send_dbam_config(adapter, hdd_ctx->dbam_mode); + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} +#else +static inline void hdd_restore_dbam_config(struct hdd_context *hdd_ctx) +{ +} +#endif + +/** + * hdd_restore_dual_sta_config() - Restore dual sta configuration + * @hdd_ctx: pointer to struct hdd_context + * + * Return: None + */ +static void hdd_restore_dual_sta_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct hdd_dual_sta_policy *sta_policy; + + sta_policy = &hdd_ctx->dual_sta_policy; + + hdd_debug("Restore dual sta config: Primary vdev_id:%d, sta policy:%d", + sta_policy->primary_vdev_id, + sta_policy->dual_sta_policy); + + status = + ucfg_mlme_set_primary_interface(hdd_ctx->psoc, + sta_policy->primary_vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("could not set primary interface, %d", status); + + status = + ucfg_mlme_set_dual_sta_policy(hdd_ctx->psoc, + sta_policy->dual_sta_policy); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to set mlme dual sta config"); +} + +/** + * hdd_send_default_scan_ies() - send default scan ies to fw + * @hdd_ctx: HDD context + * + * This function is used to send default scan ies to fw + * in case of wlan re-init + * + * Return: void + */ +static void hdd_send_default_scan_ies(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES) { + if (hdd_is_interface_up(adapter) && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_DEVICE_MODE) && + adapter->scan_info.default_scan_ies) { + sme_set_default_scan_ie(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + adapter->scan_info.default_scan_ies, + adapter->scan_info.default_scan_ies_len); + } + hdd_adapter_dev_put_debug(adapter, + NET_DEV_HOLD_SEND_DEFAULT_SCAN_IES); + } +} + +/** + * hdd_restore_sar_config() - Restore the saved SAR config after SSR + * @hdd_ctx: HDD context + * + * Restore the SAR config that was lost during SSR. + * + * Return: None + */ +static void hdd_restore_sar_config(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!hdd_ctx->sar_cmd_params) + return; + + status = sme_set_sar_power_limits(hdd_ctx->mac_handle, + hdd_ctx->sar_cmd_params); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Unable to configured SAR after SSR"); +} + +void hdd_handle_cached_commands(void) +{ + struct net_device *net_dev; + struct hdd_adapter *adapter = NULL; + struct hdd_context *hdd_ctx; + struct osif_vdev_sync *vdev_sync_arr = osif_get_vdev_sync_arr(); + struct osif_vdev_sync *vdev_sync; + int i; + uint8_t cmd_id; + + /* Get the HDD context */ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + vdev_sync = vdev_sync_arr + i; + if (!vdev_sync || !vdev_sync->in_use) + continue; + + cmd_id = osif_vdev_get_cached_cmd(vdev_sync); + net_dev = vdev_sync->net_dev; + if (net_dev) { + adapter = WLAN_HDD_GET_PRIV_PTR( + (struct net_device *)net_dev); + if (!adapter) + continue; + } else { + continue; + } + + switch (cmd_id) { + case NO_COMMAND: + break; + case INTERFACE_DOWN: + hdd_debug("Handling cached interface down command for %s", + adapter->dev->name); + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + hdd_hostapd_stop_no_trans(net_dev); + else + hdd_stop_no_trans(net_dev); + + osif_vdev_cache_command(vdev_sync, NO_COMMAND); + break; + default: + break; + } + } +} + +QDF_STATUS hdd_wlan_re_init(void) +{ + struct hdd_context *hdd_ctx = NULL; + struct hdd_adapter *adapter; + int ret; + bool bug_on_reinit_failure = CFG_BUG_ON_REINIT_FAILURE_DEFAULT; + bool value; + + hdd_prevent_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + + /* Get the HDD context */ + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + goto err_ctx_null; + + bug_on_reinit_failure = hdd_ctx->config->bug_on_reinit_failure; + + adapter = hdd_get_first_valid_adapter(hdd_ctx); + if (!adapter) + hdd_err("Failed to get adapter"); + + ret = hdd_wlan_start_modules(hdd_ctx, true); + if (ret) { + hdd_err("Failed to start wlan after error"); + goto err_re_init; + } + + hdd_update_hw_sw_info(hdd_ctx); + + wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index, + WLAN_SVC_FW_CRASHED_IND, NULL, 0); + + /* Restart all adapters */ + hdd_start_all_adapters(hdd_ctx, false); + + hdd_init_scan_reject_params(hdd_ctx); + hdd_ctx->bt_coex_mode_set = false; + + /* Allow the phone to go to sleep */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + /* set chip power save failure detected callback */ + sme_set_chip_pwr_save_fail_cb(hdd_ctx->mac_handle, + hdd_chip_pwr_save_fail_detected_cb); + + hdd_restore_thermal_mitigation_config(hdd_ctx); + hdd_restore_sar_config(hdd_ctx); + + hdd_send_default_scan_ies(hdd_ctx); + hdd_restore_dual_sta_config(hdd_ctx); + hdd_restore_dbam_config(hdd_ctx); + hdd_info("WLAN host driver reinitiation completed!"); + + ucfg_mlme_get_sap_internal_restart(hdd_ctx->psoc, &value); + if (value) + hdd_ssr_restart_sap(hdd_ctx); + hdd_wlan_ssr_reinit_event(); + + if (hdd_ctx->is_wiphy_suspended) + hdd_ctx->is_wiphy_suspended = false; + + if (hdd_ctx->hdd_wlan_suspended) + hdd_ctx->hdd_wlan_suspended = false; + + return QDF_STATUS_SUCCESS; + +err_re_init: + qdf_dp_trace_deinit(); + +err_ctx_null: + /* Allow the phone to go to sleep */ + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DRIVER_REINIT); + if (bug_on_reinit_failure) + QDF_BUG(0); + return -EPERM; +} + +int wlan_hdd_set_powersave(struct wlan_hdd_link_info *link_info, + bool allow_power_save, uint32_t timeout) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + struct hdd_station_ctx *sta_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("hdd context is NULL"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + status = sme_ps_set_powersave( + hdd_ctx->mac_handle, link_info->vdev_id, + allow_power_save, timeout, + sta_ctx->ap_supports_immediate_power_save); + if (!allow_power_save && adapter->device_mode == QDF_STA_MODE) + hdd_twt_del_dialog_in_ps_disable(hdd_ctx, + &sta_ctx->conn_info.bssid, + link_info->vdev_id); + + return qdf_status_to_os_return(status); +} + +static void wlan_hdd_print_suspend_fail_stats(struct hdd_context *hdd_ctx) +{ + struct suspend_resume_stats *stats = &hdd_ctx->suspend_resume_stats; + + hdd_err("ipa:%d, radar:%d, roam:%d, scan:%d, initial_wakeup:%d", + stats->suspend_fail[SUSPEND_FAIL_IPA], + stats->suspend_fail[SUSPEND_FAIL_RADAR], + stats->suspend_fail[SUSPEND_FAIL_ROAM], + stats->suspend_fail[SUSPEND_FAIL_SCAN], + stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]); +} + +void wlan_hdd_inc_suspend_stats(struct hdd_context *hdd_ctx, + enum suspend_fail_reason reason) +{ + wlan_hdd_print_suspend_fail_stats(hdd_ctx); + hdd_ctx->suspend_resume_stats.suspend_fail[reason]++; + wlan_hdd_print_suspend_fail_stats(hdd_ctx); +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +static inline void +hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid) +{ + cfg80211_sched_scan_results(wiphy); +} +#else +static inline void +hdd_sched_scan_results(struct wiphy *wiphy, uint64_t reqid) +{ + cfg80211_sched_scan_results(wiphy, reqid); +} +#endif + +/** + * __wlan_hdd_cfg80211_resume_wlan() - cfg80211 resume callback + * @wiphy: Pointer to wiphy + * + * This API is called when cfg80211 driver resumes driver updates + * latest sched_scan scan result(if any) to cfg80211 database + * + * Return: integer status + */ +static int __wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + int exit_code; + + hdd_enter(); + + if (cds_is_driver_recovering()) { + hdd_debug("Driver is recovering; Skipping resume"); + exit_code = 0; + goto exit_with_code; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() || + QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in mode %d", + hdd_get_conparam()); + exit_code = -EINVAL; + goto exit_with_code; + } + + if (ucfg_pmo_get_suspend_mode(hdd_ctx->psoc) == PMO_SUSPEND_NONE) { + hdd_info_rl("Suspend is not supported"); + return -EINVAL; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver is not enabled; Skipping resume"); + exit_code = 0; + goto exit_with_code; + } + + status = hdd_resume_wlan(); + if (status != QDF_STATUS_SUCCESS) { + exit_code = 0; + goto exit_with_code; + } + /* Resume control path scheduler */ + if (hdd_ctx->is_scheduler_suspended) { + scheduler_resume(); + hdd_ctx->is_scheduler_suspended = false; + } + /* Resume all components registered to pmo */ + status = ucfg_pmo_resume_all_components(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND); + + /* Unpause NS no matter of the return value of pmo_resume */ + hdd_unpause_ns(hdd_ctx); + + if (status != QDF_STATUS_SUCCESS) { + exit_code = 0; + goto exit_with_code; + } + /* Resume tlshim Rx thread */ + if (ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc)) + wlan_hdd_rx_thread_resume(hdd_ctx); + + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (adapter) { + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (vdev) { + ucfg_pkt_capture_resume_mon_thread(vdev); + hdd_objmgr_put_vdev_by_user( + vdev, WLAN_OSIF_POWER_ID); + } else { + hdd_err("vdev is NULL"); + } + } + } + + ucfg_pmo_notify_system_resume(hdd_ctx->psoc); + wlan_hdd_resume_pmo_twt(hdd_ctx); + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_RESUME_WLAN, + NO_SESSION, hdd_ctx->is_wiphy_suspended); + + hdd_ctx->is_wiphy_suspended = false; + + hdd_ctx->suspend_resume_stats.resumes++; + exit_code = 0; + +exit_with_code: + hdd_exit(); + return exit_code; +} + +static int _wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + qdf_runtime_lock_t *suspend_lock; + int errno; + + if (!hdd_ctx) { + hdd_err_rl("hdd context is null"); + return -ENODEV; + } + + /* If Wifi is off, return success for system resume */ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Modules not Enabled "); + return 0; + } + + /* + * Return success if recovery is in progress, otherwise, linux kernel + * will shutdown all interfaces in wiphy_resume. + */ + if (cds_is_driver_recovering()) { + hdd_debug("Recovery in progress"); + return 0; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + suspend_lock = &hdd_ctx->runtime_context.system_suspend; + errno = qdf_runtime_pm_allow_suspend(suspend_lock); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_resume_wlan(wiphy); + + /* It may happen during cfg80211 suspend this timer is stopped. + * This means that if + * 1) work was queued in the workqueue, it was removed from the + * workqueue and suspend proceeded. + * 2) The work was scheduled and cfg80211 suspend waited for this + * work to complete and then suspend proceeded. + * So here in cfg80211 resume, check if no interface is up and + * the module state is enabled then trigger idle timer start. + */ + if (!hdd_is_any_interface_open(hdd_ctx) && + hdd_ctx->driver_status == DRIVER_MODULES_ENABLED) + hdd_psoc_idle_timer_start(hdd_ctx); + + return errno; +} + +int wlan_hdd_cfg80211_resume_wlan(struct wiphy *wiphy) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = _wlan_hdd_cfg80211_resume_wlan(wiphy); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +static void hdd_suspend_cb(void) +{ + struct hdd_context *hdd_ctx; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + complete(&hdd_ctx->mc_sus_event_var); +} + +/** + * __wlan_hdd_cfg80211_suspend_wlan() - cfg80211 suspend callback + * @wiphy: Pointer to wiphy + * @wow: Pointer to wow + * + * This API is called when cfg80211 driver suspends + * + * Return: integer status + */ +static int __wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter, *next_adapter = NULL; + mac_handle_t mac_handle; + struct wlan_objmgr_vdev *vdev; + enum pmo_suspend_mode mode; + int rc; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_CFG80211_SUSPEND_WLAN; + struct hdd_ap_ctx *ap_ctx; + struct hdd_hostapd_state *hapd_state; + struct csr_del_sta_params params = { + .peerMacAddr = QDF_MAC_ADDR_BCAST_INIT, + .reason_code = REASON_DEAUTH_NETWORK_LEAVING, + .subtype = SIR_MAC_MGMT_DEAUTH, + }; + struct wlan_hdd_link_info *link_info; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam() || + QDF_GLOBAL_MONITOR_MODE == hdd_get_conparam()) { + hdd_err_rl("Command not allowed in mode %d", + hdd_get_conparam()); + return -EINVAL; + } + + rc = wlan_hdd_validate_context(hdd_ctx); + if (0 != rc) { + if (pld_is_low_power_mode(hdd_ctx->parent_dev)) + hdd_debug("low power mode (Deep Sleep/Hibernate)"); + else + return rc; + } + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Modules not Enabled "); + return 0; + } + + mode = ucfg_pmo_get_suspend_mode(hdd_ctx->psoc); + if (mode == PMO_SUSPEND_NONE) { + hdd_info_rl("Suspend is not supported"); + return -EINVAL; + } else if (mode == PMO_SUSPEND_SHUTDOWN) { + hdd_info_rl("shutdown suspend should complete in prepare"); + return -EINVAL; + } + + mac_handle = hdd_ctx->mac_handle; + + /* If RADAR detection is in progress (HDD), prevent suspend. The flag + * "dfs_cac_block_tx" is set to true when RADAR is found and stay true + * until CAC is done for a SoftAP which is in started state. + */ + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + continue; + + if (QDF_SAP_MODE == adapter->device_mode) { + hapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + if (BSS_START == hapd_state->bss_state && + true == ap_ctx->dfs_cac_block_tx) { + hdd_err("RADAR detection in progress, do not allow suspend"); + wlan_hdd_inc_suspend_stats(hdd_ctx, + SUSPEND_FAIL_RADAR); + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return -EAGAIN; + } else if (!ucfg_pmo_get_enable_sap_suspend( + hdd_ctx->psoc)) { + /* return -EOPNOTSUPP if SAP + * does not support suspend + */ + hdd_err("SAP does not support suspend!!"); + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return -EOPNOTSUPP; + } else if (ucfg_pmo_get_disconnect_sap_tdls_in_wow( + hdd_ctx->psoc)) { + hdd_softap_deauth_all_sta(adapter, + hapd_state, + ¶ms); + } + } else if (QDF_P2P_GO_MODE == adapter->device_mode) { + hapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + if (!ucfg_pmo_get_enable_sap_suspend( + hdd_ctx->psoc)) { + /* return -EOPNOTSUPP if GO + * does not support suspend + */ + hdd_err("GO does not support suspend!!"); + hdd_adapter_dev_put_debug(adapter, + dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug( + next_adapter, + dbgid); + return -EOPNOTSUPP; + } else if (ucfg_pmo_get_disconnect_sap_tdls_in_wow( + hdd_ctx->psoc)) { + hdd_softap_deauth_all_sta(adapter, + hapd_state, + ¶ms); + } + } else if (QDF_TDLS_MODE == adapter->device_mode && + ucfg_pmo_get_disconnect_sap_tdls_in_wow( + hdd_ctx->psoc)) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_TDLS_NB_ID); + if (vdev) { + ucfg_tdls_teardown_links_sync(hdd_ctx->psoc, + vdev); + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_TDLS_NB_ID); + } + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + /* p2p cleanup task based on scheduler */ + ucfg_p2p_cleanup_tx_by_psoc(hdd_ctx->psoc); + ucfg_p2p_cleanup_roc_by_psoc(hdd_ctx->psoc); + + if (hdd_is_connection_in_progress(NULL, NULL)) { + hdd_err_rl("Connection is in progress, rejecting suspend"); + return -EINVAL; + } + + /* flush any pending powersave timers */ + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + continue; + + sme_ps_timer_flush_sync(mac_handle, link_info->vdev_id); + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + hdd_pause_ns(hdd_ctx); + + /* + * Suspend all components registered to pmo, abort ongoing scan and + * don't allow new scan any more before scheduler thread suspended. + */ + if (ucfg_pmo_suspend_all_components(hdd_ctx->psoc, + QDF_SYSTEM_SUSPEND)) { + hdd_err("Some components not ready to suspend!"); + return -EAGAIN; + } + + wlan_hdd_suspend_pmo_twt(hdd_ctx); + + /* + * Suspend IPA early before proceeding to suspend other entities like + * firmware to avoid any race conditions. + */ + if (ucfg_ipa_suspend(hdd_ctx->pdev)) { + hdd_err("IPA not ready to suspend!"); + wlan_hdd_inc_suspend_stats(hdd_ctx, SUSPEND_FAIL_IPA); + goto resume_all_components; + } + + /* Suspend control path scheduler */ + scheduler_register_hdd_suspend_callback(hdd_suspend_cb); + scheduler_set_event_mask(MC_SUSPEND_EVENT); + scheduler_wake_up_controller_thread(); + + /* Wait for suspend confirmation from scheduler */ + rc = wait_for_completion_timeout(&hdd_ctx->mc_sus_event_var, + msecs_to_jiffies(WLAN_WAIT_TIME_MCTHREAD_SUSPEND)); + if (!rc) { + scheduler_clear_event_mask(MC_SUSPEND_EVENT); + hdd_err("Failed to stop mc thread"); + goto resume_tx; + } + hdd_ctx->is_scheduler_suspended = true; + + if (ucfg_dp_is_rx_common_thread_enabled(hdd_ctx->psoc)) { + if (wlan_hdd_rx_thread_suspend(hdd_ctx)) + goto resume_ol_rx; + } + + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (adapter) { + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + goto resume_dp_thread; + } + if (ucfg_pkt_capture_suspend_mon_thread(vdev)) { + hdd_objmgr_put_vdev_by_user( + vdev, WLAN_OSIF_POWER_ID); + goto resume_dp_thread; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + } + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN, + NO_SESSION, hdd_ctx->is_wiphy_suspended); + + if (hdd_suspend_wlan() < 0) { + hdd_err("Failed to suspend WLAN"); + goto resume_dp_thread; + } + + hdd_ctx->is_wiphy_suspended = true; + + hdd_exit(); + return 0; + +resume_dp_thread: + /* Resume packet capture MON thread */ + if (ucfg_pkt_capture_get_mode(hdd_ctx->psoc) != + PACKET_CAPTURE_MODE_DISABLE) { + adapter = hdd_get_adapter(hdd_ctx, QDF_MONITOR_MODE); + if (adapter) { + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (vdev) { + ucfg_pkt_capture_resume_mon_thread(vdev); + hdd_objmgr_put_vdev_by_user( + vdev, WLAN_OSIF_POWER_ID); + } else { + hdd_err("vdev is NULL"); + } + } + } + +resume_ol_rx: + /* Resume tlshim Rx thread */ + wlan_hdd_rx_thread_resume(hdd_ctx); + scheduler_resume(); + hdd_ctx->is_scheduler_suspended = false; +resume_tx: + hdd_resume_wlan(); +resume_all_components: + ucfg_pmo_resume_all_components(hdd_ctx->psoc, QDF_SYSTEM_SUSPEND); + hdd_unpause_ns(hdd_ctx); + + return -ETIME; + +} + +static int _wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + void *hif_ctx; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + qdf_runtime_lock_t *suspend_lock; + int errno; + + if (!hdd_ctx) { + hdd_err_rl("hdd context is null"); + return -ENODEV; + } + + /* If Wifi is off, return success for system suspend */ + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Modules not Enabled "); + return 0; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (0 != errno) { + if (pld_is_low_power_mode(hdd_ctx->parent_dev)) + hdd_debug("low power mode (Deep Sleep/Hibernate)"); + else + return errno; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + suspend_lock = &hdd_ctx->runtime_context.system_suspend; + errno = qdf_runtime_pm_prevent_suspend_sync(suspend_lock); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); + if (errno) { + qdf_runtime_pm_allow_suspend(suspend_lock); + return errno; + } + + return errno; +} + +int wlan_hdd_cfg80211_suspend_wlan(struct wiphy *wiphy, + struct cfg80211_wowlan *wow) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (0 != errno) { + if (pld_is_low_power_mode(hdd_ctx->parent_dev)) + hdd_debug("low power mode (Deep Sleep/Hibernate)"); + else + return errno; + } + + /* + * Flush the idle shutdown before ops start.This is done here to avoid + * the deadlock as idle shutdown waits for the dsc ops + * to complete. + */ + hdd_psoc_idle_timer_stop(hdd_ctx); + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = _wlan_hdd_cfg80211_suspend_wlan(wiphy, wow); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * hdd_stop_dhcp_ind() - API to stop DHCP sequence + * @link_info: Link info pointer in HDD adapter + * @mac: mac address + * + * Release the wakelock held for DHCP process and allow + * the runtime pm to continue + * + * Return: None + */ +static void hdd_stop_dhcp_ind(struct wlan_hdd_link_info *link_info, + uint8_t *mac) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_debug("DHCP stop indicated through power save"); + sme_dhcp_stop_ind(hdd_ctx->mac_handle, adapter->device_mode, + mac, link_info->vdev_id); + hdd_allow_suspend(WIFI_POWER_EVENT_WAKELOCK_DHCP); + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.connect); +} + +/** + * hdd_start_dhcp_ind() - API to start DHCP sequence + * @link_info: Link info pointer in HDD adapter + * @mac: mac address + * + * Prevent APPS suspend and the runtime suspend during + * DHCP sequence + * + * Return: None + */ +static void +hdd_start_dhcp_ind(struct wlan_hdd_link_info *link_info, uint8_t *mac) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_debug("DHCP start indicated through power save"); + qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.connect); + hdd_prevent_suspend_timeout(HDD_WAKELOCK_TIMEOUT_CONNECT, + WIFI_POWER_EVENT_WAKELOCK_DHCP); + sme_dhcp_start_ind(hdd_ctx->mac_handle, adapter->device_mode, + mac, link_info->vdev_id); +} + +static int wlan_hdd_set_ps(struct wlan_hdd_link_info *link_info, + uint8_t *mac, bool allow_power_save, int timeout) +{ + int status; + struct hdd_adapter *adapter = link_info->adapter; + + status = wlan_hdd_set_powersave(link_info, allow_power_save, timeout); + + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug("vdev[%d] mode %d disconnected ignore dhcp protection", + link_info->vdev_id, adapter->device_mode); + return status; + } + + hdd_debug("vdev[%d] mode %d enable dhcp protection", + link_info->vdev_id, adapter->device_mode); + allow_power_save ? hdd_stop_dhcp_ind(link_info, mac) : + hdd_start_dhcp_ind(link_info, mac); + + return status; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#ifdef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter, + bool allow_power_save, int timeout, + int link_id) +{ + struct wlan_hdd_link_info *link_info; + int status = -EINVAL; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (link_id >= 0 && + wlan_vdev_get_link_id(link_info->vdev) != link_id) + continue; + + status = wlan_hdd_set_ps(link_info, + link_info->link_addr.bytes, + allow_power_save, timeout); + if (status) + break; + } + + return status; +} +#else +int wlan_hdd_set_mlo_ps(struct hdd_adapter *adapter, + bool allow_power_save, int timeout, + int link_id) +{ + struct hdd_adapter *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + int i, status = -EINVAL; + + mlo_adapter_info = &adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter) + continue; + + if (link_id >= 0 && + wlan_vdev_get_link_id(link_adapter->deflink->vdev) != + link_id) + continue; + + status = wlan_hdd_set_ps(link_adapter->deflink, + link_adapter->mac_addr.bytes, + allow_power_save, timeout); + if (status) + break; + } + + if (i == WLAN_MAX_MLD && link_id >= 0) + hdd_err("No link adapter found for link id: %d", link_id); + + return status; +} +#endif +#endif + +/** + * __wlan_hdd_cfg80211_set_power_mgmt() - set cfg80211 power management config + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @allow_power_save: is wlan allowed to go into power save mode + * @timeout: Timeout value in ms + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool allow_power_save, + int timeout) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int status; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter(); + + if (timeout < 0) { + hdd_debug("User space timeout: %d; Enter full power or power save: %d", + timeout, allow_power_save); + timeout = 0; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT, + link_info->vdev_id, timeout); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) { + hdd_debug("Driver Module not enabled return success"); + return 0; + } + + /* Flush any scheduled inet change notifier work + * This is to make sure set power save request + * sent to FW are serialized to avoid race condition + */ + flush_work(&adapter->ipv4_notifier_work); + hdd_adapter_flush_ipv6_notifier_work(adapter); + + if (hdd_adapter_is_ml_adapter(adapter)) { + status = wlan_hdd_set_mlo_ps(adapter, allow_power_save, + timeout, -1); + goto exit; + } + + status = wlan_hdd_set_ps(link_info, adapter->mac_addr.bytes, + allow_power_save, timeout); + +exit: + /* Cache the powersave state for success case */ + if (!status) + adapter->allow_power_save = allow_power_save; + + hdd_exit(); + return status; +} + +int wlan_hdd_cfg80211_set_power_mgmt(struct wiphy *wiphy, + struct net_device *dev, + bool allow_power_save, + int timeout) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_power_mgmt(wiphy, dev, allow_power_save, + timeout); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_set_txpower() - set TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @type: TX power setting type + * @mbm: TX power in mBm + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int mbm) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); + mac_handle_t mac_handle; + struct hdd_adapter *adapter; + struct qdf_mac_addr bssid = QDF_MAC_ADDR_BCAST_INIT; + struct qdf_mac_addr selfmac; + QDF_STATUS status; + int errno; + int dbm; + + hdd_enter(); + + if (!wdev) { + hdd_err("wdev is null, set tx power failed"); + return -EIO; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SET_TXPOWER, + NO_SESSION, type); + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + qdf_copy_macaddr(&bssid, &adapter->mac_addr); + } else { + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + if (hdd_cm_is_vdev_associated(adapter->deflink)) + qdf_copy_macaddr(&bssid, &sta_ctx->conn_info.bssid); + } + + qdf_copy_macaddr(&selfmac, &adapter->mac_addr); + + mac_handle = hdd_ctx->mac_handle; + + dbm = MBM_TO_DBM(mbm); + + /* + * the original implementation of this function expected power + * values in dBm instead of mBm. If the conversion from mBm to + * dBm is zero, then assume dBm was passed. + */ + if (!dbm) + dbm = mbm; + + status = ucfg_mlme_set_current_tx_power_level(hdd_ctx->psoc, dbm); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("sme_cfg_set_int failed for tx power %d, %d", + dbm, status); + return -EIO; + } + + hdd_debug("Set tx power level %d dbm", dbm); + + switch (type) { + /* Automatically determine transmit power */ + case NL80211_TX_POWER_AUTOMATIC: + case NL80211_TX_POWER_LIMITED: + /* Limit TX power by the mBm parameter */ + status = sme_set_max_tx_power(mac_handle, bssid, selfmac, dbm); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Setting maximum tx power failed, %d", status); + return -EIO; + } + break; + + case NL80211_TX_POWER_FIXED: /* Fix TX power to the mBm parameter */ + status = sme_set_tx_power(mac_handle, adapter->deflink->vdev_id, + bssid, adapter->device_mode, dbm); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Setting tx power failed, %d", status); + return -EIO; + } + break; + default: + hdd_err("Invalid power setting type %d", type); + return -EIO; + } + + hdd_exit(); + return 0; +} + +int wlan_hdd_cfg80211_set_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_tx_power_setting type, + int mbm) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_txpower(wiphy, wdev, type, mbm); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#define WLAN_HDD_TX_POWER_CACHE_EXPIRY_TIME 350 + +static QDF_STATUS +wlan_hdd_tx_power_request_needed(struct hdd_adapter *adapter) +{ + uint32_t tx_pwr_cached_duration; + + tx_pwr_cached_duration = + qdf_system_ticks_to_msecs(qdf_system_ticks()) - + adapter->tx_power.tx_pwr_cached_timestamp; + + if (tx_pwr_cached_duration <= WLAN_HDD_TX_POWER_CACHE_EXPIRY_TIME) + return QDF_STATUS_E_ALREADY; + + return QDF_STATUS_SUCCESS; +} + +static int wlan_hdd_get_tx_power(struct hdd_adapter *adapter, int *dbm) +{ + struct wlan_objmgr_vdev *vdev; + int ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_info("vdev is NULL"); + return -EINVAL; + } + + ret = wlan_cfg80211_mc_cp_stats_get_tx_power(vdev, dbm); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + hdd_debug("power: %d", *dbm); + return ret; +} + +#ifdef FEATURE_ANI_LEVEL_REQUEST +static void hdd_get_ani_level_cb(struct wmi_host_ani_level_event *ani, + uint8_t num, void *context) +{ + struct osif_request *request; + struct ani_priv *priv; + uint8_t min_recv_freqs = QDF_MIN(num, MAX_NUM_FREQS_FOR_ANI_LEVEL); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + /* propagate response back to requesting thread */ + priv = osif_request_priv(request); + priv->ani = qdf_mem_malloc(min_recv_freqs * + sizeof(struct wmi_host_ani_level_event)); + if (!priv->ani) + goto complete; + + priv->num_freq = min_recv_freqs; + qdf_mem_copy(priv->ani, ani, + min_recv_freqs * sizeof(struct wmi_host_ani_level_event)); + +complete: + osif_request_complete(request); + osif_request_put(request); +} + +/** + * wlan_hdd_get_ani_level_dealloc() - Dealloc mem allocated in priv data + * @priv: the priv data + * + * Return: None + */ +static void wlan_hdd_get_ani_level_dealloc(void *priv) +{ + struct ani_priv *ani = priv; + + if (ani->ani) + qdf_mem_free(ani->ani); +} + +QDF_STATUS wlan_hdd_get_ani_level(struct hdd_adapter *adapter, + struct wmi_host_ani_level_event *ani, + uint32_t *parsed_freqs, + uint8_t num_freqs) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + QDF_STATUS status; + void *cookie; + struct osif_request *request; + struct ani_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 1000, + .dealloc = wlan_hdd_get_ani_level_dealloc, + }; + + if (!hdd_ctx) { + hdd_err("Invalid HDD context"); + return QDF_STATUS_E_INVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_NOMEM; + } + cookie = osif_request_cookie(request); + + status = sme_get_ani_level(hdd_ctx->mac_handle, parsed_freqs, + num_freqs, hdd_get_ani_level_cb, cookie); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to retrieve ani level"); + goto complete; + } else { + /* request was sent -- wait for the response */ + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving ANI level"); + status = QDF_STATUS_E_TIMEOUT; + goto complete; + } + } + + priv = osif_request_priv(request); + + qdf_mem_copy(ani, priv->ani, sizeof(struct wmi_host_ani_level_event) * + priv->num_freq); + +complete: + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + osif_request_put(request); + + hdd_exit(); + return status; +} +#endif + +/** + * __wlan_hdd_cfg80211_get_txpower() - get TX power + * @wiphy: Pointer to wiphy + * @wdev: Pointer to network device + * @dbm: Pointer to TX power in dbm + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + + struct hdd_context *hdd_ctx = (struct hdd_context *) wiphy_priv(wiphy); + struct net_device *ndev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(ndev); + QDF_STATUS status; + int ret; + static bool is_rate_limited; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(ndev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + *dbm = 0; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + /* Validate adapter sessionId */ + ret = wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id); + if (ret) + return ret; + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (hdd_cm_is_vdev_roaming(adapter->deflink)) { + hdd_debug("Roaming is in progress, rej this req"); + return -EINVAL; + } + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_debug("Not associated"); + return 0; + } + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (!test_bit(SOFTAP_BSS_STARTED, + &adapter->deflink->link_flags)) { + hdd_debug("SAP is not started yet"); + return 0; + } + break; + default: + hdd_debug_rl("Current interface is not supported for get tx_power"); + return 0; + } + + HDD_IS_RATE_LIMIT_REQ(is_rate_limited, + hdd_ctx->config->nb_commands_interval); + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED || + is_rate_limited) { + /* Send cached data to upperlayer*/ + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + ucfg_mc_cp_stats_get_tx_power(vdev, dbm); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + hdd_debug("Modules not enabled/rate limited, cached tx power = %d", + *dbm); + return 0; + } + + status = wlan_hdd_tx_power_request_needed(adapter); + if (status == QDF_STATUS_E_ALREADY) { + /* TX_POWER is sent by STATION_STATS by firmware and + * is copied into the adapter. So, return cached value. + */ + *dbm = adapter->tx_power.tx_pwr; + hdd_nofl_debug("cached tx_power: %d", *dbm); + return 0; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_TXPOWER, + adapter->deflink->vdev_id, adapter->device_mode); + + return wlan_hdd_get_tx_power(adapter, dbm); +} + +int wlan_hdd_cfg80211_get_txpower(struct wiphy *wiphy, + struct wireless_dev *wdev, + int *dbm) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_txpower(wiphy, wdev, dbm); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * hdd_convert_opm_mode() - convert opm with equivalent wma opm + * @opm_mode: Optimized power management mode + * + * Return: enum wma_sta_ps_scheme_cfg + */ +static enum wma_sta_ps_scheme_cfg +hdd_convert_opm_mode(enum qca_wlan_vendor_opm_mode opm_mode) +{ + switch (opm_mode) { + case QCA_WLAN_VENDOR_OPM_MODE_DISABLE: + return WMA_STA_PS_OPM_CONSERVATIVE; + case QCA_WLAN_VENDOR_OPM_MODE_ENABLE: + return WMA_STA_PS_OPM_AGGRESSIVE; + case QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED: + return WMA_STA_PS_USER_DEF; + default: + hdd_err("Invalid opm_mode: %d", opm_mode); + return WMA_STA_PS_OPM_CONSERVATIVE; + } +} + +int hdd_set_power_config(struct hdd_context *hddctx, + struct hdd_adapter *adapter, + enum qca_wlan_vendor_opm_mode *opm_mode) +{ + QDF_STATUS status; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_info("Advanced power save only allowed in STA/P2P-Client modes:%d", + adapter->device_mode); + return -EINVAL; + } + + if (*opm_mode > QCA_WLAN_VENDOR_OPM_MODE_USER_DEFINED || + *opm_mode < QCA_WLAN_VENDOR_OPM_MODE_DISABLE) { + hdd_err("invalid power value: %d", *opm_mode); + return -EINVAL; + } + + if (ucfg_pmo_get_max_ps_poll(hddctx->psoc)) { + hdd_info("Disable advanced power save since max ps poll is enabled"); + *opm_mode = QCA_WLAN_VENDOR_OPM_MODE_DISABLE; + } + + status = wma_set_power_config(adapter->deflink->vdev_id, + hdd_convert_opm_mode(*opm_mode)); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to configure power: %d", status); + return -EINVAL; + } + + return 0; +} + +int hdd_set_power_config_params(struct hdd_context *hddctx, + struct hdd_adapter *adapter, + uint16_t ps_ito, uint16_t spec_wake) +{ + QDF_STATUS status; + + status = wma_set_power_config_ito(adapter->deflink->vdev_id, ps_ito); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to configure power ito: %d", status); + return -EINVAL; + } + + status = wma_set_power_config_spec_wake(adapter->deflink->vdev_id, + spec_wake); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("failed to configure power spec wake: %d", status); + return -EINVAL; + } + + return 0; +} + +#ifdef WLAN_SUSPEND_RESUME_TEST +static struct net_device *g_dev; +static struct wiphy *g_wiphy; +static enum wow_resume_trigger g_resume_trigger; + +#define HDD_FA_SUSPENDED_BIT (0) +static unsigned long fake_apps_state; + +/** + * __hdd_wlan_fake_apps_resume() - The core logic for + * hdd_wlan_fake_apps_resume() skipping the call to hif_fake_apps_resume(), + * which is only need for non-irq resume + * @wiphy: the kernel wiphy struct for the device being resumed + * @dev: the kernel net_device struct for the device being resumed + * + * Return: none, calls QDF_BUG() on failure + */ +static void __hdd_wlan_fake_apps_resume(struct wiphy *wiphy, + struct net_device *dev) +{ + struct hif_opaque_softc *hif_ctx; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + qdf_device_t qdf_dev; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!hdd_ctx->config->is_unit_test_framework_enabled) { + hdd_warn_rl("UT framework is disabled"); + return; + } + + hdd_info("Unit-test resume WLAN"); + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) { + QDF_BUG(0); + return; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return; + + if (!test_and_clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { + hdd_alert("Not unit-test suspended; Nothing to do"); + return; + } + + /* simulate kernel disable irqs */ + QDF_BUG(!hif_apps_wake_irq_disable(hif_ctx)); + + QDF_BUG(!wlan_hdd_bus_resume_noirq()); + + /* simulate kernel enable irqs */ + QDF_BUG(!hif_apps_irqs_enable(hif_ctx)); + + QDF_BUG(!wlan_hdd_bus_resume(QDF_UNIT_TEST_WOW_SUSPEND)); + + QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy)); + + if (g_resume_trigger == WOW_RESUME_TRIGGER_HTC_WAKEUP) + hif_vote_link_down(hif_ctx); + + dev->watchdog_timeo = HDD_TX_TIMEOUT; + + hdd_alert("Unit-test resume succeeded"); + + hdd_info("allow rtpm wow for wow unit test"); + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.wow_unit_test); +} + +/** + * hdd_wlan_fake_apps_resume_irq_callback() - Irq callback function for resuming + * from unit-test initiated suspend from irq wakeup signal + * + * Resume wlan after getting very 1st CE interrupt from target + * + * Return: none + */ +static void hdd_wlan_fake_apps_resume_irq_callback(void) +{ + hdd_info("Trigger unit-test resume WLAN"); + + QDF_BUG(g_wiphy); + QDF_BUG(g_dev); + __hdd_wlan_fake_apps_resume(g_wiphy, g_dev); + g_wiphy = NULL; + g_dev = NULL; +} + +int hdd_wlan_fake_apps_suspend(struct wiphy *wiphy, struct net_device *dev, + enum wow_interface_pause pause_setting, + enum wow_resume_trigger resume_setting) +{ + int errno; + qdf_device_t qdf_dev; + struct hif_opaque_softc *hif_ctx; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wow_enable_params wow_params = { + .is_unit_test = true, + .interface_pause = pause_setting, + .resume_trigger = resume_setting + }; + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->config->is_unit_test_framework_enabled) { + hdd_warn_rl("UT framework is disabled"); + return -EINVAL; + } + + hdd_info("Unit-test suspend WLAN"); + + if (pause_setting < WOW_INTERFACE_PAUSE_DEFAULT || + pause_setting >= WOW_INTERFACE_PAUSE_COUNT) { + hdd_err_rl("Invalid interface pause %d (expected range [0, 2])", + pause_setting); + return -EINVAL; + } + + if (resume_setting < WOW_RESUME_TRIGGER_DEFAULT || + resume_setting >= WOW_RESUME_TRIGGER_COUNT) { + hdd_err_rl("Invalid resume trigger %d (expected range [0, 2])", + resume_setting); + return -EINVAL; + } + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + if (!qdf_dev) + return -EINVAL; + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + if (test_and_set_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state)) { + hdd_alert("Already unit-test suspended; Nothing to do"); + return 0; + } + + hdd_info("prevent rtpm wow for wow unit test"); + qdf_runtime_pm_prevent_suspend(&hdd_ctx->runtime_context.wow_unit_test); + + /* pci link is needed to wakeup from HTC wakeup trigger */ + if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP) + hif_vote_link_up(hif_ctx); + + errno = wlan_hdd_cfg80211_suspend_wlan(wiphy, NULL); + if (errno) + goto link_down; + + errno = wlan_hdd_unit_test_bus_suspend(wow_params); + if (errno) + goto cfg80211_resume; + + /* simulate kernel disabling irqs */ + errno = hif_apps_irqs_disable(hif_ctx); + if (errno) + goto bus_resume; + + errno = wlan_hdd_bus_suspend_noirq(); + if (errno) + goto enable_irqs; + + /* pass wiphy/dev to callback via global variables */ + g_wiphy = wiphy; + g_dev = dev; + g_resume_trigger = resume_setting; + hif_ut_apps_suspend(hif_ctx, hdd_wlan_fake_apps_resume_irq_callback); + + /* re-enable wake irq */ + errno = hif_apps_wake_irq_enable(hif_ctx); + if (errno) + goto fake_apps_resume; + + /* + * Tell the kernel not to worry if TX queues aren't moving. This is + * expected since we are suspending the wifi hardware, but not APPS + */ + dev->watchdog_timeo = INT_MAX; + + hdd_alert("Unit-test suspend succeeded"); + + return 0; + +fake_apps_resume: + hif_ut_apps_resume(hif_ctx); + +enable_irqs: + QDF_BUG(!hif_apps_irqs_enable(hif_ctx)); + +bus_resume: + QDF_BUG(!wlan_hdd_bus_resume(QDF_UNIT_TEST_WOW_SUSPEND)); + +cfg80211_resume: + QDF_BUG(!wlan_hdd_cfg80211_resume_wlan(wiphy)); + +link_down: + if (resume_setting == WOW_RESUME_TRIGGER_HTC_WAKEUP) + hif_vote_link_down(hif_ctx); + + clear_bit(HDD_FA_SUSPENDED_BIT, &fake_apps_state); + hdd_err("Unit-test suspend failed: %d", errno); + + hdd_info("allow rtpm wow for wow unit test"); + qdf_runtime_pm_allow_suspend(&hdd_ctx->runtime_context.wow_unit_test); + + return errno; +} + +int hdd_wlan_fake_apps_resume(struct wiphy *wiphy, struct net_device *dev) +{ + struct hif_opaque_softc *hif_ctx; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->config->is_unit_test_framework_enabled) { + hdd_warn_rl("UT framework is disabled"); + return -EINVAL; + } + + hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_ctx) + return -EINVAL; + + hif_ut_apps_resume(hif_ctx); + __hdd_wlan_fake_apps_resume(wiphy, dev); + + return 0; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_pre_cac.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_pre_cac.c new file mode 100644 index 0000000000..958c3e6719 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_pre_cac.c @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "osif_vdev_sync.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_hdd_pre_cac.h" +#include +#include "osif_pre_cac.h" +#include "wlan_pre_cac_ucfg_api.h" +#include "wlan_ipa_ucfg_api.h" +#include "wlan_hdd_son.h" +#include "wlan_dp_ucfg_api.h" + +/** + * wlan_hdd_pre_cac_failure() - Process the pre cac failure + * @adapter: AP adapter + * + * Deletes the pre cac adapter + * + * Return: None + */ +static void wlan_hdd_pre_cac_failure(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + wlan_hdd_stop_sap(adapter); + hdd_stop_adapter(hdd_ctx, adapter); + + hdd_exit(); +} + +/** + * wlan_hdd_pre_cac_success() - Process the pre cac result + * @adapter: AP adapter + * + * Stops the pre cac adapter and moves the existing SAP to the pre cac + * channel + * + * Return: None + */ +static void wlan_hdd_pre_cac_success(struct hdd_adapter *adapter) +{ + struct hdd_adapter *ap_adapter; + int i; + struct hdd_context *hdd_ctx; + enum phy_ch_width pre_cac_ch_width; + qdf_freq_t chan_freq; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return; + } + + pre_cac_ch_width = wlansap_get_chan_width( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink)); + + hdd_stop_adapter(hdd_ctx, adapter); + + /* Prepare to switch AP from 2.4GHz channel to the pre CAC channel */ + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!ap_adapter) { + hdd_err("failed to get SAP adapter, no restart on pre CAC channel"); + return; + } + + /* + * Setting of the pre cac complete status will ensure that on channel + * switch to the pre CAC DFS channel, there is no CAC again. + */ + ucfg_pre_cac_complete_set(ap_adapter->deflink->vdev, true); + + wlan_hdd_set_sap_csa_reason(hdd_ctx->psoc, ap_adapter->deflink->vdev_id, + CSA_REASON_PRE_CAC_SUCCESS); + chan_freq = ucfg_pre_cac_get_freq(ap_adapter->deflink->vdev); + i = hdd_softap_set_channel_change(ap_adapter->dev, + chan_freq, + pre_cac_ch_width, false); + if (i) { + hdd_err("failed to change channel"); + ucfg_pre_cac_complete_set(ap_adapter->deflink->vdev, false); + } + + hdd_exit(); +} + +void hdd_close_pre_cac_adapter(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *pre_cac_adapter; + struct osif_vdev_sync *vdev_sync; + int errno; + + pre_cac_adapter = hdd_get_adapter_by_iface_name(hdd_ctx, + SAP_PRE_CAC_IFNAME); + if (!pre_cac_adapter) + return; + + ucfg_pre_cac_clear_work(hdd_ctx->psoc); + errno = osif_vdev_sync_trans_start_wait(pre_cac_adapter->dev, + &vdev_sync); + if (errno) + return; + + osif_vdev_sync_unregister(pre_cac_adapter->dev); + osif_vdev_sync_wait_for_ops(vdev_sync); + + wlan_hdd_release_intf_addr(hdd_ctx, pre_cac_adapter->mac_addr.bytes); + pre_cac_adapter->is_virtual_iface = true; + hdd_close_adapter(hdd_ctx, pre_cac_adapter, true); + + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); +} + +static int wlan_set_def_pre_cac_chan(struct hdd_context *hdd_ctx, + uint32_t pre_cac_ch_freq, + struct cfg80211_chan_def *chandef, + enum nl80211_channel_type *chantype, + enum phy_ch_width *ch_width) +{ + enum nl80211_channel_type channel_type; + struct ieee80211_channel *ieee_chan; + struct ch_params ch_params = {0}; + + ieee_chan = ieee80211_get_channel(hdd_ctx->wiphy, + pre_cac_ch_freq); + if (!ieee_chan) { + hdd_err("channel conversion failed %d", pre_cac_ch_freq); + return -EINVAL; + } + ch_params.ch_width = *ch_width; + wlan_reg_set_channel_params_for_pwrmode(hdd_ctx->pdev, + pre_cac_ch_freq, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + switch (ch_params.sec_ch_offset) { + case HIGH_PRIMARY_CH: + channel_type = NL80211_CHAN_HT40MINUS; + break; + case LOW_PRIMARY_CH: + channel_type = NL80211_CHAN_HT40PLUS; + break; + default: + channel_type = NL80211_CHAN_HT20; + break; + } + cfg80211_chandef_create(chandef, ieee_chan, channel_type); + switch (ch_params.ch_width) { + case CH_WIDTH_80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80; + break; + case CH_WIDTH_80P80MHZ: + chandef->width = NL80211_CHAN_WIDTH_80P80; + if (ch_params.mhz_freq_seg1) + chandef->center_freq2 = ch_params.mhz_freq_seg1; + break; + case CH_WIDTH_160MHZ: + chandef->width = NL80211_CHAN_WIDTH_160; + break; + default: + break; + } + if (ch_params.ch_width == CH_WIDTH_80MHZ || + ch_params.ch_width == CH_WIDTH_80P80MHZ || + ch_params.ch_width == CH_WIDTH_160MHZ) { + if (ch_params.mhz_freq_seg0) + chandef->center_freq1 = ch_params.mhz_freq_seg0; + } + *chantype = channel_type; + *ch_width = ch_params.ch_width; + hdd_debug("pre cac ch def: chan:%d width:%d freq1:%d freq2:%d", + chandef->chan->center_freq, chandef->width, + chandef->center_freq1, chandef->center_freq2); + + return 0; +} + +/** + * __wlan_hdd_request_pre_cac() - Start pre CAC in the driver + * @hdd_ctx: the HDD context to operate against + * @chan_freq: Channel frequency option provided by userspace + * @out_adapter: out parameter for the newly created pre-cac adapter + * + * Sets the driver to the required hardware mode and start an adapter for + * pre CAC which will mimic an AP. + * + * Return: Zero on success, non-zero value on error + */ +static int __wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, + uint32_t chan_freq, + struct hdd_adapter **out_adapter) +{ + uint8_t *mac_addr = NULL; + uint32_t pre_cac_chan_freq = 0; + int ret; + struct hdd_adapter *ap_adapter, *pre_cac_adapter = NULL; + struct hdd_ap_ctx *hdd_ap_ctx, *pre_cac_ap_ctx; + QDF_STATUS status; + struct wiphy *wiphy; + struct net_device *dev; + struct cfg80211_chan_def chandef; + enum nl80211_channel_type channel_type; + mac_handle_t mac_handle; + enum phy_ch_width cac_ch_width; + struct hdd_adapter_create_param params = {0}; + struct wlan_hdd_link_info *pre_cac_link_info, *link_info; + bool is_rtnl_locked = false; + + if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc)) { + hdd_debug("Pre CAC is not supported on non-dbs platforms"); + return -EINVAL; + } + + if (policy_mgr_get_connection_count(hdd_ctx->psoc) > 1) { + hdd_err("pre cac not allowed in concurrency"); + return -EINVAL; + } + + ap_adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!ap_adapter) { + hdd_err("unable to get SAP adapter"); + return -EINVAL; + } + + link_info = ap_adapter->deflink; + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + if (qdf_atomic_read(&hdd_ap_ctx->ch_switch_in_progress)) { + hdd_err("pre cac not allowed during CSA"); + return -EINVAL; + } + + mac_handle = hdd_ctx->mac_handle; + + if (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, + hdd_ap_ctx->operating_chan_freq)) { + hdd_err("SAP is already on DFS channel:%d", + hdd_ap_ctx->operating_chan_freq); + return -EINVAL; + } + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(hdd_ap_ctx->operating_chan_freq)) { + hdd_err("pre CAC allowed only when SAP is in 2.4GHz:%d", + hdd_ap_ctx->operating_chan_freq); + return -EINVAL; + } + + cac_ch_width = wlansap_get_max_bw_by_phymode(hdd_ap_ctx->sap_context); + if (cac_ch_width > DEFAULT_PRE_CAC_BANDWIDTH) + cac_ch_width = DEFAULT_PRE_CAC_BANDWIDTH; + if (chan_freq) { + qdf_mem_zero(&chandef, sizeof(struct cfg80211_chan_def)); + if (wlan_set_def_pre_cac_chan(hdd_ctx, chan_freq, &chandef, + &channel_type, &cac_ch_width)) { + hdd_err("failed to set pre_cac channel %d", chan_freq); + return -EINVAL; + } + } + hdd_debug("channel: %d bw: %d", chan_freq, cac_ch_width); + + ret = ucfg_pre_cac_validate_and_get_freq(hdd_ctx->pdev, chan_freq, + &pre_cac_chan_freq, + cac_ch_width); + if (ret != 0) { + hdd_err("can't validate pre-cac channel"); + goto release_intf_addr_and_return_failure; + } + + hdd_debug("starting pre cac SAP adapter"); + + mac_addr = wlan_hdd_get_intf_addr(hdd_ctx, QDF_SAP_MODE); + if (!mac_addr) { + hdd_err("can't add virtual intf: Not getting valid mac addr"); + return -EINVAL; + } + + /** + * Starting a SAP adapter: + * Instead of opening an adapter, we could just do a SME open + * session for AP type. But, start BSS would still need an + * adapter. So, this option is not taken. + * + * hdd open adapter is going to register this precac interface + * with user space. This interface though exposed to user space + * will be in DOWN state. Consideration was done to avoid this + * registration to the user space. But, as part of SAP + * operations multiple events are sent to user space. Some of + * these events received from unregistered interface was + * causing crashes. So, retaining the registration. + * + * So, this interface would remain registered and will remain + * in DOWN state for the CAC duration. We will add notes in the + * feature announcement to not use this temporary interface for + * any activity from user space. + */ + + params.is_add_virtual_iface = 1; + params.is_pre_cac_adapter = 1; + if (rtnl_trylock()) { + pre_cac_adapter = hdd_open_adapter(hdd_ctx, QDF_SAP_MODE, + SAP_PRE_CAC_IFNAME, + mac_addr, NET_NAME_UNKNOWN, + true, ¶ms); + rtnl_unlock(); + } + + if (!pre_cac_adapter) { + hdd_err("error opening the pre cac adapter"); + goto release_intf_addr_and_return_failure; + } + + pre_cac_link_info = pre_cac_adapter->deflink; + pre_cac_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(pre_cac_link_info); + sap_clear_global_dfs_param(mac_handle, pre_cac_ap_ctx->sap_context); + + /* + * This interface is internally created by the driver. So, no interface + * up comes for this interface from user space and hence starting + * the adapter internally. + */ + if (hdd_start_adapter(pre_cac_adapter, false)) { + hdd_err("error starting the pre cac adapter"); + goto close_pre_cac_adapter; + } + + hdd_debug("preparing for start ap/bss on the pre cac adapter"); + + wiphy = hdd_ctx->wiphy; + dev = pre_cac_adapter->dev; + + /* Since this is only a dummy interface lets us use the IEs from the + * other active SAP interface. In regular scenarios, these IEs would + * come from the user space entity + */ + pre_cac_ap_ctx->beacon = qdf_mem_malloc(sizeof(*hdd_ap_ctx->beacon)); + if (!pre_cac_ap_ctx->beacon) + goto stop_close_pre_cac_adapter; + + qdf_mem_copy(pre_cac_ap_ctx->beacon, hdd_ap_ctx->beacon, + sizeof(*pre_cac_ap_ctx->beacon)); + pre_cac_ap_ctx->sap_config.authType = hdd_ap_ctx->sap_config.authType; + pre_cac_ap_ctx->sap_config.ch_width_orig = + hdd_ap_ctx->sap_config.ch_width_orig; + + /* The original premise is that on moving from 2.4GHz to 5GHz, the SAP + * will continue to operate on the same bandwidth as that of the 2.4GHz + * operations. Only bandwidths 20MHz/40MHz are possible on 2.4GHz band. + * Now some customer request to start AP on higher BW such as 80Mhz. + * Hence use max possible supported BW based on phymode configurated + * on SAP. + */ + cac_ch_width = wlansap_get_max_bw_by_phymode(hdd_ap_ctx->sap_context); + if (cac_ch_width > DEFAULT_PRE_CAC_BANDWIDTH) + cac_ch_width = DEFAULT_PRE_CAC_BANDWIDTH; + + qdf_mem_zero(&chandef, sizeof(struct cfg80211_chan_def)); + if (wlan_set_def_pre_cac_chan(hdd_ctx, pre_cac_chan_freq, &chandef, + &channel_type, &cac_ch_width)) { + hdd_err("error set pre_cac channel %d", pre_cac_chan_freq); + goto close_pre_cac_adapter; + } + pre_cac_ap_ctx->sap_config.ch_width_orig = + hdd_map_nl_chan_width(chandef.width); + + hdd_debug("existing ap phymode:%d pre cac ch_width:%d freq:%d", + hdd_ap_ctx->sap_config.SapHw_mode, + cac_ch_width, pre_cac_chan_freq); + /* + * Doing update after opening and starting pre-cac adapter will make + * sure that driver won't do hardware mode change if there are any + * initial hick-ups or issues in pre-cac adapter's configuration. + * Since current SAP is in 2.4GHz and pre CAC channel is in 5GHz, this + * connection update should result in DBS mode + */ + status = policy_mgr_update_and_wait_for_connection_update( + hdd_ctx->psoc, + link_info->vdev_id, + pre_cac_chan_freq, + POLICY_MGR_UPDATE_REASON_PRE_CAC); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("error in moving to DBS mode"); + goto stop_close_pre_cac_adapter; + } + + ret = wlan_hdd_set_channel(wiphy, dev, &chandef, channel_type); + if (ret != 0) { + hdd_err("failed to set channel"); + goto stop_close_pre_cac_adapter; + } + + status = wlan_hdd_cfg80211_start_bss(pre_cac_link_info, + NULL, PRE_CAC_SSID, + qdf_str_len(PRE_CAC_SSID), + NL80211_HIDDEN_SSID_NOT_IN_USE, + false); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("start bss failed"); + goto stop_close_pre_cac_adapter; + } + + /* + * The pre cac status is set here. But, it would not be reset explicitly + * anywhere, since after the pre cac success/failure, the pre cac + * adapter itself would be removed. + */ + ret = ucfg_pre_cac_set_status(pre_cac_link_info->vdev, true); + if (ret != 0) { + hdd_err("failed to set pre cac status"); + goto stop_close_pre_cac_adapter; + } + + ucfg_pre_cac_set_freq_before_pre_cac(link_info->vdev, + hdd_ap_ctx->operating_chan_freq); + ucfg_pre_cac_set_freq(link_info->vdev, pre_cac_chan_freq); + ucfg_pre_cac_adapter_set(pre_cac_link_info->vdev, true); + *out_adapter = pre_cac_adapter; + + return 0; + +stop_close_pre_cac_adapter: + pre_cac_adapter->is_virtual_iface = true; + hdd_stop_adapter(hdd_ctx, pre_cac_adapter); + qdf_mem_free(pre_cac_ap_ctx->beacon); + pre_cac_ap_ctx->beacon = NULL; +close_pre_cac_adapter: + if (rtnl_trylock()) + is_rtnl_locked = true; + + hdd_close_adapter(hdd_ctx, pre_cac_adapter, true); + + if (is_rtnl_locked) + rtnl_unlock(); +release_intf_addr_and_return_failure: + /* + * Release the interface address as the adapter + * failed to start, if you don't release then next + * adapter which is trying to come wouldn't get valid + * mac address. Remember we have limited pool of mac addresses + */ + if (mac_addr) + wlan_hdd_release_intf_addr(hdd_ctx, mac_addr); + return -EINVAL; +} + +static int +wlan_hdd_start_pre_cac_trans(struct hdd_context *hdd_ctx, + struct osif_vdev_sync **out_vdev_sync, + bool *is_vdev_sync_created) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_START_PRE_CAC_TRANS; + int errno; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + if (!qdf_str_cmp(adapter->dev->name, SAP_PRE_CAC_IFNAME)) { + errno = osif_vdev_sync_trans_start(adapter->dev, + out_vdev_sync); + + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return errno; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + + errno = osif_vdev_sync_create_and_trans(hdd_ctx->parent_dev, + out_vdev_sync); + if (errno) + return errno; + + *is_vdev_sync_created = true; + return 0; +} + +int wlan_hdd_request_pre_cac(struct hdd_context *hdd_ctx, uint32_t chan_freq) +{ + struct hdd_adapter *adapter; + struct osif_vdev_sync *vdev_sync; + int errno; + bool is_vdev_sync_created = false; + + errno = wlan_hdd_start_pre_cac_trans(hdd_ctx, &vdev_sync, + &is_vdev_sync_created); + if (errno) + return errno; + + errno = __wlan_hdd_request_pre_cac(hdd_ctx, chan_freq, &adapter); + if (errno) + goto destroy_sync; + + if (is_vdev_sync_created) + osif_vdev_sync_register(adapter->dev, vdev_sync); + osif_vdev_sync_trans_stop(vdev_sync); + + return 0; + +destroy_sync: + osif_vdev_sync_trans_stop(vdev_sync); + if (is_vdev_sync_created) + osif_vdev_sync_destroy(vdev_sync); + + return errno; +} + +static void +wlan_hdd_pre_cac_conditional_freq_switch_ind(struct wlan_objmgr_vdev *vdev, + bool completed) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + uint8_t vdev_id = vdev->vdev_objmgr.vdev_id; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_ap_ctx *ap_ctx; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + adapter = link_info->adapter; + if (completed) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + ap_ctx->dfs_cac_block_tx = false; + ucfg_ipa_set_dfs_cac_tx(adapter->hdd_ctx->pdev, + ap_ctx->dfs_cac_block_tx); + ucfg_dp_set_dfs_cac_tx(vdev, ap_ctx->dfs_cac_block_tx); + adapter->hdd_ctx->dev_dfs_cac_status = DFS_CAC_ALREADY_DONE; + } else { + adapter->hdd_ctx->dev_dfs_cac_status = DFS_CAC_NEVER_DONE; + hdd_son_deliver_cac_status_event(adapter, + ucfg_pre_cac_get_freq(vdev), + true); + } +} + +static void +wlan_hdd_pre_cac_complete(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + QDF_STATUS status) +{ + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev %d", vdev_id); + return; + } + + if (QDF_IS_STATUS_SUCCESS(status)) + wlan_hdd_pre_cac_success(link_info->adapter); + else + wlan_hdd_pre_cac_failure(link_info->adapter); +} + +struct osif_pre_cac_legacy_ops pre_cac_legacy_ops = { + .conditional_csa_ind_legacy_cb = + wlan_hdd_pre_cac_conditional_freq_switch_ind, + .pre_cac_complete_legacy_cb = wlan_hdd_pre_cac_complete, +}; + +QDF_STATUS hdd_pre_cac_register_cb(void) +{ + osif_pre_cac_set_legacy_cb(&pre_cac_legacy_ops); + + return osif_pre_cac_register_cb(); +} + +void hdd_pre_cac_unregister_cb(void) +{ + osif_pre_cac_reset_legacy_cb(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c new file mode 100644 index 0000000000..b750c34528 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_regulatory.c @@ -0,0 +1,2144 @@ +/* + * Copyright (c) 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_regulatory.c + * + * hdd regulatory implementation + */ + +#include "qdf_types.h" +#include "qdf_trace.h" +#include "wlan_hdd_main.h" +#include +#include "wlan_hdd_regulatory.h" +#include +#include "cds_regdomain.h" +#include "cds_utils.h" +#include "pld_common.h" +#include +#include "wlan_policy_mgr_ucfg.h" +#include "sap_api.h" +#include "wlan_hdd_hostapd.h" +#include "osif_psoc_sync.h" +#include "wlan_osif_features.h" +#include "wlan_p2p_ucfg_api.h" + +#define REG_RULE_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 20, 0) + +#define REG_RULE_2467_2472 REG_RULE(2467-10, 2472+10, 40, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_2484 REG_RULE(2484-10, 2484+10, 20, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS | \ + NL80211_RRF_NO_OFDM) + +#define REG_RULE_5180_5320 REG_RULE(5180-10, 5320+10, 160, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_5500_5720 REG_RULE(5500-10, 5720+10, 160, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +#define REG_RULE_5745_5925 REG_RULE(5745-10, 5925+10, 80, 0, 20, \ + NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS) + +static bool init_by_driver; +static bool init_by_reg_core; + +struct regulatory_channel reg_channels[NUM_CHANNELS]; + +static const struct ieee80211_regdomain +hdd_world_regrules_60_61_62 = { + .n_reg_rules = 6, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_2484, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_63_65 = { + .n_reg_rules = 4, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_5180_5320, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_64 = { + .n_reg_rules = 3, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_5180_5320, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_66_69 = { + .n_reg_rules = 4, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +static const struct ieee80211_regdomain +hdd_world_regrules_67_68_6A_6C = { + .n_reg_rules = 5, + .alpha2 = "00", + .reg_rules = { + REG_RULE_2412_2462, + REG_RULE_2467_2472, + REG_RULE_5180_5320, + REG_RULE_5500_5720, + REG_RULE_5745_5925, + } +}; + +#define COUNTRY_CHANGE_WORK_RESCHED_WAIT_TIME 30 +/** + * hdd_get_world_regrules() - get the appropriate world regrules + * @reg: regulatory data + * + * Return: regulatory rules ptr + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) +static const struct ieee80211_regdomain *hdd_get_world_regrules( + struct regulatory *reg) +{ + struct reg_dmn_pair *regpair = + (struct reg_dmn_pair *)reg->regpair; + + switch (regpair->reg_dmn_pair) { + case 0x60: + case 0x61: + case 0x62: + return &hdd_world_regrules_60_61_62; + case 0x63: + case 0x65: + return &hdd_world_regrules_63_65; + case 0x64: + return &hdd_world_regrules_64; + case 0x66: + case 0x69: + return &hdd_world_regrules_66_69; + case 0x67: + case 0x68: + case 0x6A: + case 0x6C: + return &hdd_world_regrules_67_68_6A_6C; + default: + hdd_warn("invalid world mode in BDF"); + return &hdd_world_regrules_60_61_62; + } +} + +/** + * hdd_is_world_regdomain() - whether world regdomain + * @reg_domain: integer regulatory domain + * + * Return: bool + */ +static bool hdd_is_world_regdomain(uint32_t reg_domain) +{ + uint32_t temp_regd = reg_domain & ~WORLD_ROAMING_FLAG; + + return ((temp_regd & CTRY_FLAG) != CTRY_FLAG) && + ((temp_regd & WORLD_ROAMING_MASK) == + WORLD_ROAMING_PREFIX); +} + +/** + * hdd_update_regulatory_info() - update regulatory info + * @hdd_ctx: hdd context + * + * Return: Error Code + */ +static int hdd_update_regulatory_info(struct hdd_context *hdd_ctx) +{ + uint32_t country_code; + + country_code = cds_get_country_from_alpha2(hdd_ctx->reg.alpha2); + + hdd_ctx->reg.reg_domain = CTRY_FLAG; + hdd_ctx->reg.reg_domain |= country_code; + + return cds_fill_some_regulatory_info(&hdd_ctx->reg); + +} +#endif + +/** + * hdd_reset_global_reg_params - Reset global static reg params + * + * This function is helpful in static driver to reset + * the global params. + * + * Return: void + */ +void hdd_reset_global_reg_params(void) +{ + init_by_driver = false; + init_by_reg_core = false; +} + +/** + * hdd_update_coex_unsafe_chan_nb_user_prefer() - update coex unsafe + * nb prefer framework + * @hdd_ctx: hdd context + * @config_vars: reg config + * + * Return: void + */ +#ifdef FEATURE_WLAN_CH_AVOID_EXT +static inline +void hdd_update_coex_unsafe_chan_nb_user_prefer( + struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ + config_vars->coex_unsafe_chan_nb_user_prefer = + ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer( + hdd_ctx->psoc); +} + +static inline +void hdd_update_coex_unsafe_chan_reg_disable( + struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ + config_vars->coex_unsafe_chan_reg_disable = + ucfg_mlme_get_coex_unsafe_chan_reg_disable( + hdd_ctx->psoc); +} +#else +static inline +void hdd_update_coex_unsafe_chan_nb_user_prefer( + struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ +} + +static inline +void hdd_update_coex_unsafe_chan_reg_disable( + struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ +} +#endif + +#if defined(CONFIG_AFC_SUPPORT) && defined(CONFIG_BAND_6GHZ) +static inline +void hdd_update_afc_config(struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ + bool enable_6ghz_sp_pwrmode_supp = false; + bool afc_disable_timer_check = false; + bool afc_disable_request_id_check = false; + bool is_afc_reg_noaction = false; + + ucfg_mlme_get_enable_6ghz_sp_mode_support(hdd_ctx->psoc, + &enable_6ghz_sp_pwrmode_supp); + config_vars->enable_6ghz_sp_pwrmode_supp = enable_6ghz_sp_pwrmode_supp; + ucfg_mlme_get_afc_disable_timer_check(hdd_ctx->psoc, + &afc_disable_timer_check); + config_vars->afc_disable_timer_check = afc_disable_timer_check; + ucfg_mlme_get_afc_disable_request_id_check( + hdd_ctx->psoc, &afc_disable_request_id_check); + config_vars->afc_disable_request_id_check = + afc_disable_request_id_check; + ucfg_mlme_get_afc_reg_noaction(hdd_ctx->psoc, + &is_afc_reg_noaction); + config_vars->is_afc_reg_noaction = is_afc_reg_noaction; +} +#else +static inline +void hdd_update_afc_config(struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ +} +#endif + +static void reg_program_config_vars(struct hdd_context *hdd_ctx, + struct reg_config_vars *config_vars) +{ + uint8_t indoor_chnl_marking = 0; + uint32_t band_capability = 0, scan_11d_interval = 0; + bool indoor_chan_enabled = false; + uint32_t restart_beaconing = 0; + uint8_t enable_srd_chan; + bool enable_5dot9_ghz_chan; + QDF_STATUS status; + bool country_priority = 0; + bool value = false; + bool enable_dfs_scan = true; + + status = ucfg_mlme_get_band_capability(hdd_ctx->psoc, &band_capability); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get MLME band cap, defaulting to BAND_ALL"); + + status = ucfg_policy_mgr_get_indoor_chnl_marking(hdd_ctx->psoc, + &indoor_chnl_marking); + if (QDF_STATUS_SUCCESS != status) + hdd_err("can't get indoor channel marking, using default"); + + status = ucfg_mlme_is_11d_enabled(hdd_ctx->psoc, &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Invalid 11d_enable flag"); + config_vars->enable_11d_support = value; + + ucfg_mlme_get_nol_across_regdmn(hdd_ctx->psoc, &value); + config_vars->retain_nol_across_regdmn_update = value; + + ucfg_mlme_get_scan_11d_interval(hdd_ctx->psoc, &scan_11d_interval); + config_vars->scan_11d_interval = scan_11d_interval; + + ucfg_mlme_get_sap_country_priority(hdd_ctx->psoc, + &country_priority); + config_vars->userspace_ctry_priority = country_priority; + + ucfg_scan_cfg_get_dfs_chan_scan_allowed(hdd_ctx->psoc, + &enable_dfs_scan); + + config_vars->dfs_enabled = enable_dfs_scan; + + ucfg_mlme_get_indoor_channel_support(hdd_ctx->psoc, + &indoor_chan_enabled); + config_vars->indoor_chan_enabled = indoor_chan_enabled; + + config_vars->force_ssc_disable_indoor_channel = indoor_chnl_marking; + config_vars->band_capability = band_capability; + + ucfg_mlme_get_restart_beaconing_on_ch_avoid(hdd_ctx->psoc, + &restart_beaconing); + config_vars->restart_beaconing = restart_beaconing; + + ucfg_mlme_get_etsi_srd_chan_in_master_mode(hdd_ctx->psoc, + &enable_srd_chan); + config_vars->enable_srd_chan_in_master_mode = enable_srd_chan; + + ucfg_mlme_get_11d_in_world_mode(hdd_ctx->psoc, + &config_vars->enable_11d_in_world_mode); + + ucfg_mlme_get_5dot9_ghz_chan_in_master_mode(hdd_ctx->psoc, + &enable_5dot9_ghz_chan); + config_vars->enable_5dot9_ghz_chan_in_master_mode = + enable_5dot9_ghz_chan; + hdd_update_coex_unsafe_chan_nb_user_prefer(hdd_ctx, config_vars); + hdd_update_coex_unsafe_chan_reg_disable(hdd_ctx, config_vars); + hdd_update_afc_config(hdd_ctx, config_vars); + config_vars->sta_sap_scc_on_indoor_channel = + ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(hdd_ctx->psoc); + config_vars->p2p_indoor_ch_support = + ucfg_p2p_get_indoor_ch_support(hdd_ctx->psoc); +} + +/** + * hdd_regulatory_wiphy_init() - regulatory wiphy init + * @hdd_ctx: hdd context + * @reg: regulatory data + * @wiphy: wiphy structure + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_regulatory_wiphy_init(struct hdd_context *hdd_ctx, + struct regulatory *reg, + struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *reg_rules; + int chan_num; + struct ieee80211_channel *chan; + + if (hdd_is_world_regdomain(reg->reg_domain)) { + reg_rules = hdd_get_world_regrules(reg); + wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; + } else { + wiphy->regulatory_flags |= REGULATORY_STRICT_REG; + reg_rules = &hdd_world_regrules_60_61_62; + } + + /* + * save the original driver regulatory flags + */ + hdd_ctx->reg.reg_flags = wiphy->regulatory_flags; + wiphy_apply_custom_regulatory(wiphy, reg_rules); + + /* + * disable 2.4 Ghz channels that dont have 20 mhz bw + */ + for (chan_num = 0; + chan_num < wiphy->bands[HDD_NL80211_BAND_2GHZ]->n_channels; + chan_num++) { + chan = &(wiphy->bands[HDD_NL80211_BAND_2GHZ]->channels[chan_num]); + if (chan->flags & IEEE80211_CHAN_NO_20MHZ) + chan->flags |= IEEE80211_CHAN_DISABLED; + } + + /* + * restore the driver regulatory flags since + * wiphy_apply_custom_regulatory may have + * changed them + */ + wiphy->regulatory_flags = hdd_ctx->reg.reg_flags; + +} +#else +static void hdd_regulatory_wiphy_init(struct hdd_context *hdd_ctx, + struct regulatory *reg, + struct wiphy *wiphy) +{ + const struct ieee80211_regdomain *reg_rules; + + if (hdd_is_world_regdomain(reg->reg_domain)) { + reg_rules = hdd_get_world_regrules(reg); + wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY; + } else { + wiphy->flags |= WIPHY_FLAG_STRICT_REGULATORY; + reg_rules = &hdd_world_regrules_60_61_62; + } + + /* + * save the original driver regulatory flags + */ + hdd_ctx->reg.reg_flags = wiphy->flags; + wiphy_apply_custom_regulatory(wiphy, reg_rules); + + /* + * restore the driver regulatory flags since + * wiphy_apply_custom_regulatory may have + * changed them + */ + wiphy->flags = hdd_ctx->reg.reg_flags; + +} +#endif + +/** + * is_wiphy_custom_regulatory() - is custom regulatory defined + * @wiphy: wiphy + * + * Return: int + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static int is_wiphy_custom_regulatory(struct wiphy *wiphy) +{ + + return wiphy->regulatory_flags & REGULATORY_CUSTOM_REG; +} +#else +static int is_wiphy_custom_regulatory(struct wiphy *wiphy) +{ + return wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY; +} +#endif + +/** + * hdd_modify_wiphy() - modify wiphy + * @wiphy: wiphy + * @chan: channel structure + * + * Return: void + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) +static void hdd_modify_wiphy(struct wiphy *wiphy, + struct ieee80211_channel *chan) +{ + const struct ieee80211_reg_rule *reg_rule; + + if (is_wiphy_custom_regulatory(wiphy)) { + reg_rule = freq_reg_info(wiphy, MHZ_TO_KHZ(chan->center_freq)); + if (!IS_ERR(reg_rule)) { + chan->flags &= ~IEEE80211_CHAN_DISABLED; + + if (!(reg_rule->flags & NL80211_RRF_DFS)) { + hdd_debug("Remove dfs restriction for %u", + chan->center_freq); + chan->flags &= ~IEEE80211_CHAN_RADAR; + } + + if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN)) { + hdd_debug("Remove passive restriction for %u", + chan->center_freq); + chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN; + } + + if (!(reg_rule->flags & NL80211_RRF_NO_IBSS)) { + hdd_debug("Remove no ibss restriction for %u", + chan->center_freq); + chan->flags &= ~IEEE80211_CHAN_NO_IBSS; + } + + chan->max_power = + MBM_TO_DBM(reg_rule->power_rule.max_eirp); + } + } +} +#endif + +/** + * hdd_set_dfs_region() - set the dfs_region + * @hdd_ctx: HDD context + * @dfs_reg: the dfs_region to set + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_set_dfs_region(struct hdd_context *hdd_ctx, + enum dfs_reg dfs_reg) +{ + wlan_reg_set_dfs_region(hdd_ctx->pdev, dfs_reg); +} +#endif + +/** + * hdd_process_regulatory_data() - process regulatory data + * @hdd_ctx: hdd context + * @wiphy: wiphy + * @reset: whether to reset channel data + * + * Return: void + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 4, 0)) +static void hdd_process_regulatory_data(struct hdd_context *hdd_ctx, + struct wiphy *wiphy, + bool reset) +{ + int band_num; + int chan_num; + enum channel_enum chan_enum = CHAN_ENUM_1; + struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL; + struct regulatory_channel *cds_chan; + uint8_t band_capability, indoor_chnl_marking = 0; + bool indoor, sta_sap_con_on_indoor; + QDF_STATUS status; + + band_capability = hdd_ctx->curr_band; + + status = ucfg_policy_mgr_get_indoor_chnl_marking(hdd_ctx->psoc, + &indoor_chnl_marking); + + if (QDF_STATUS_SUCCESS != status) + hdd_err("can't get indoor channel marking, using default"); + + sta_sap_con_on_indoor = + ucfg_policy_mgr_get_sta_sap_scc_on_indoor_chnl(hdd_ctx->psoc); + + for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) { + + if (!wiphy->bands[band_num]) + continue; + + for (chan_num = 0; + chan_num < wiphy->bands[band_num]->n_channels && + chan_enum < NUM_CHANNELS; + chan_num++) { + wiphy_chan = + &(wiphy->bands[band_num]->channels[chan_num]); + cds_chan = &(reg_channels[chan_enum]); + cds_chan->chan_flags = 0; + if (CHAN_ENUM_144 == chan_enum) + wiphy_chan_144 = wiphy_chan; + + chan_enum++; + + if (!reset) + hdd_modify_wiphy(wiphy, wiphy_chan); + + if (indoor_chnl_marking && + (wiphy_chan->flags & IEEE80211_CHAN_INDOOR_ONLY)) + cds_chan->chan_flags |= + REGULATORY_CHAN_INDOOR_ONLY; + + if (wiphy_chan->flags & IEEE80211_CHAN_DISABLED) { + cds_chan->state = CHANNEL_STATE_DISABLE; + cds_chan->chan_flags |= + REGULATORY_CHAN_DISABLED; + } else if (wiphy_chan->flags & + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_PASSIVE_SCAN)) { + cds_chan->state = CHANNEL_STATE_DFS; + if (wiphy_chan->flags & IEEE80211_CHAN_RADAR) + cds_chan->chan_flags |= + REGULATORY_CHAN_RADAR; + if (wiphy_chan->flags & + IEEE80211_CHAN_PASSIVE_SCAN) + cds_chan->chan_flags |= + REGULATORY_CHAN_NO_IR; + } else if (wiphy_chan->flags & + IEEE80211_CHAN_INDOOR_ONLY) { + cds_chan->chan_flags |= + REGULATORY_CHAN_INDOOR_ONLY; + + ucfg_mlme_get_indoor_channel_support( + hdd_ctx->psoc, + &indoor); + if (!indoor) { + cds_chan->state = CHANNEL_STATE_DFS; + wiphy_chan->flags |= + IEEE80211_CHAN_PASSIVE_SCAN; + if (!sta_sap_con_on_indoor) + cds_chan->chan_flags |= + REGULATORY_CHAN_NO_IR; + } else + cds_chan->state = CHANNEL_STATE_ENABLE; + } else + cds_chan->state = CHANNEL_STATE_ENABLE; + cds_chan->tx_power = wiphy_chan->max_power; + if (wiphy_chan->flags & IEEE80211_CHAN_NO_10MHZ) + cds_chan->max_bw = 5; + else if (wiphy_chan->flags & IEEE80211_CHAN_NO_20MHZ) + cds_chan->max_bw = 10; + /* + * IEEE80211_CHAN_NO_HT40 is defined as 0x30 in kernel + * 4th BIT representing IEEE80211_CHAN_NO_HT40PLUS + * 5th BIT representing IEEE80211_CHAN_NO_HT40MINUS + * + * In order to claim no 40Mhz support value of + * wiphy_chan->flags needs to be 0x30. + * 0x20 and 0x10 values shows that either HT40+ or + * HT40- is not supported based on BIT set but they + * can support 40Mhz Operation. + */ + else if ((wiphy_chan->flags & IEEE80211_CHAN_NO_HT40) == + IEEE80211_CHAN_NO_HT40) + cds_chan->max_bw = 20; + else if (wiphy_chan->flags & IEEE80211_CHAN_NO_80MHZ) + cds_chan->max_bw = 40; + else if (wiphy_chan->flags & IEEE80211_CHAN_NO_160MHZ) + cds_chan->max_bw = 80; + else + cds_chan->max_bw = 160; + } + } + + if (0 == (hdd_ctx->reg.eeprom_rd_ext & + (1 << WMI_REG_EXT_FCC_CH_144))) { + cds_chan = &(reg_channels[CHAN_ENUM_144]); + cds_chan->state = CHANNEL_STATE_DISABLE; + if (wiphy_chan_144) + wiphy_chan_144->flags |= IEEE80211_CHAN_DISABLED; + } + + wlan_hdd_cfg80211_update_band(hdd_ctx, wiphy, band_capability); +} + +/** + * hdd_regulatory_init_no_offload() - regulatory init + * @hdd_ctx: hdd context + * @wiphy: wiphy + * + * Return: int + */ +static int hdd_regulatory_init_no_offload(struct hdd_context *hdd_ctx, + struct wiphy *wiphy) +{ + int ret_val; + struct regulatory *reg_info; + enum dfs_reg dfs_reg; + struct reg_config_vars config_vars; + + reg_info = &hdd_ctx->reg; + + ret_val = cds_fill_some_regulatory_info(reg_info); + if (ret_val) { + hdd_err("incorrect BDF regulatory data"); + return ret_val; + } + + hdd_set_dfs_region(hdd_ctx, DFS_FCC_REGION); + + hdd_regulatory_wiphy_init(hdd_ctx, reg_info, wiphy); + + hdd_process_regulatory_data(hdd_ctx, wiphy, true); + + reg_info->cc_src = SOURCE_DRIVER; + + ucfg_reg_set_default_country(hdd_ctx->psoc, reg_info->alpha2); + + cds_fill_and_send_ctl_to_fw(reg_info); + + wlan_reg_get_dfs_region(hdd_ctx->pdev, &dfs_reg); + + reg_program_config_vars(hdd_ctx, &config_vars); + ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars); + ucfg_reg_program_mas_chan_list(hdd_ctx->psoc, + reg_channels, + hdd_ctx->reg.alpha2, + dfs_reg); + + return 0; +} +#endif + +/** + * hdd_modify_indoor_channel_state_flags() - modify wiphy flags and cds state + * @hdd_ctx: HDD context + * @wiphy_chan: wiphy channel number + * @cds_chan: cds channel structure + * @chan_enum: enumerated value of the channel + * @chan_num: channel number + * @disable: Disable/enable the flags + * + * Modify wiphy flags and cds state if channel is indoor. + * + * Return: void + */ +void hdd_modify_indoor_channel_state_flags( + struct hdd_context *hdd_ctx, + struct ieee80211_channel *wiphy_chan, + struct regulatory_channel *cds_chan, + enum channel_enum chan_enum, int chan_num, bool disable) +{ + bool indoor_support; + + ucfg_mlme_get_indoor_channel_support(hdd_ctx->psoc, &indoor_support); + + /* Mark indoor channel to disable in wiphy and cds */ + if (disable) { + if (wiphy_chan->flags & IEEE80211_CHAN_INDOOR_ONLY) { + wiphy_chan->flags |= + IEEE80211_CHAN_DISABLED; + hdd_info("Mark indoor channel %d as disable", + cds_chan->center_freq); + cds_chan->state = + CHANNEL_STATE_DISABLE; + } + } else { + if (wiphy_chan->flags & IEEE80211_CHAN_INDOOR_ONLY) { + wiphy_chan->flags &= + ~IEEE80211_CHAN_DISABLED; + /* + * Indoor channels may be marked as dfs / enable + * during regulatory processing + */ + if ((wiphy_chan->flags & + (IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_PASSIVE_SCAN)) || + ((indoor_support == false) && + (wiphy_chan->flags & + IEEE80211_CHAN_INDOOR_ONLY))) + cds_chan->state = + CHANNEL_STATE_DFS; + else + cds_chan->state = + CHANNEL_STATE_ENABLE; + hdd_debug("Mark indoor channel %d as cds_chan state %d", + cds_chan->chan_num, cds_chan->state); + } + } + +} + +void hdd_update_indoor_channel(struct hdd_context *hdd_ctx, + bool disable) +{ + int band_num; + int chan_num; + enum channel_enum chan_enum = CHAN_ENUM_2412; + struct ieee80211_channel *wiphy_chan, *wiphy_chan_144 = NULL; + struct regulatory_channel *cds_chan; + uint8_t band_capability; + struct wiphy *wiphy = hdd_ctx->wiphy; + + hdd_enter(); + hdd_debug("mark indoor channel disable: %d", disable); + + band_capability = hdd_ctx->curr_band; + for (band_num = 0; band_num < HDD_NUM_NL80211_BANDS; band_num++) { + + if (!wiphy->bands[band_num]) + continue; + + for (chan_num = 0; + chan_num < wiphy->bands[band_num]->n_channels && + chan_enum < NUM_CHANNELS; + chan_num++) { + + wiphy_chan = + &(wiphy->bands[band_num]->channels[chan_num]); + cds_chan = &(reg_channels[chan_enum]); + if (chan_enum == CHAN_ENUM_5720) + wiphy_chan_144 = wiphy_chan; + + chan_enum++; + hdd_modify_indoor_channel_state_flags(hdd_ctx, + wiphy_chan, cds_chan, + chan_enum, chan_num, disable); + } + } + + /* Notify the regulatory domain to update the channel list */ + if (QDF_IS_STATUS_ERROR(ucfg_reg_notify_sap_event(hdd_ctx->pdev, + disable))) { + hdd_err("Failed to notify sap event"); + } + hdd_exit(); + +} + +/** + * hdd_program_country_code() - process channel information from country code + * @hdd_ctx: hddc context + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +void hdd_program_country_code(struct hdd_context *hdd_ctx) +{ +} +#else +void hdd_program_country_code(struct hdd_context *hdd_ctx) +{ + struct wiphy *wiphy = hdd_ctx->wiphy; + uint8_t *country_alpha2 = hdd_ctx->reg.alpha2; + + if (!init_by_reg_core && !init_by_driver) { + init_by_driver = true; + if (('0' != country_alpha2[0]) || + ('0' != country_alpha2[1])) + regulatory_hint(wiphy, country_alpha2); + } +} +#endif + +void hdd_reg_wait_for_country_change(struct hdd_context *hdd_ctx) +{ + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + if (hdd_ctx->is_regulatory_update_in_progress) { + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + hdd_debug("waiting for channel list to update"); + qdf_wait_for_event_completion(&hdd_ctx->regulatory_update_event, + CHANNEL_LIST_UPDATE_TIMEOUT); + /* In case of set country failure in FW, response never comes + * so wait the full timeout, then set in_progress to false. + * If the response comes back, in_progress will already be set + * to false anyways. + */ + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = false; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + } else { + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + } +} + +int hdd_reg_set_country(struct hdd_context *hdd_ctx, char *country_code) +{ + QDF_STATUS status; + uint8_t cc[REG_ALPHA2_LEN + 1]; + uint8_t alpha2[REG_ALPHA2_LEN + 1]; + enum country_src cc_src; + + if (!country_code) { + hdd_err("country_code is null"); + return -EINVAL; + } + + if (!ucfg_reg_is_user_country_set_allowed(hdd_ctx->psoc)) { + hdd_err("user_country is not allowed"); + return -EINVAL; + } + + qdf_mem_copy(cc, country_code, REG_ALPHA2_LEN); + cc[REG_ALPHA2_LEN] = '\0'; + + if (!qdf_mem_cmp(country_code, hdd_ctx->reg.alpha2, REG_ALPHA2_LEN)) { + cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->psoc, alpha2); + if (cc_src == SOURCE_USERSPACE || cc_src == SOURCE_CORE) { + hdd_debug("country code is the same"); + return 0; + } + } + + qdf_event_reset(&hdd_ctx->regulatory_update_event); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = true; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + + status = ucfg_reg_set_country(hdd_ctx->pdev, cc); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set country"); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = false; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + } + + hdd_reg_wait_for_country_change(hdd_ctx); + + return qdf_status_to_os_return(status); +} + +uint32_t hdd_reg_legacy_setband_to_reg_wifi_band_bitmap(uint8_t qca_setband) +{ + uint32_t band_bitmap = 0; + + switch (qca_setband) { + case QCA_SETBAND_AUTO: + band_bitmap |= REG_BAND_MASK_ALL; + break; + case QCA_SETBAND_5G: + band_bitmap |= BIT(REG_BAND_5G); + break; + case QCA_SETBAND_2G: + band_bitmap |= BIT(REG_BAND_2G); + break; + default: + hdd_err("Invalid band value %u", qca_setband); + return 0; + } + + return band_bitmap; +} + +int hdd_reg_set_band(struct net_device *dev, uint32_t band_bitmap) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + uint32_t current_band; + QDF_STATUS status; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!band_bitmap) { + hdd_err("Can't disable all bands"); + return -EINVAL; + } + + hdd_debug("change band to %u", band_bitmap); + + if (ucfg_reg_get_band(hdd_ctx->pdev, ¤t_band) != + QDF_STATUS_SUCCESS) { + hdd_debug("Failed to get current band config"); + return -EIO; + } + + /* + * If SET_FCC_CHANNEL 0 command is received first then 6 GHz band would + * be disabled and band_capability would be set to 3 but existing 6 GHz + * STA and P2P client connections won't be disconnected. + * If set band comes again for 6 GHz band disabled and band_bitmap is + * equal to band_capability, proceed to disable 6 GHz band completely. + */ + if (current_band == band_bitmap && + !ucfg_reg_get_keep_6ghz_sta_cli_connection(hdd_ctx->pdev)) { + hdd_debug("band is the same so not updating"); + return 0; + } + + hdd_ctx->curr_band = wlan_reg_band_bitmap_to_band_info(band_bitmap); + + if (QDF_IS_STATUS_ERROR(ucfg_reg_set_band(hdd_ctx->pdev, + band_bitmap))) { + hdd_err("Failed to set the band bitmap value to %u", + band_bitmap); + return -EINVAL; + } + + status = ucfg_cm_set_roam_band_update(hdd_ctx->psoc, + adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to send RSO update to fw on set band"); + + return 0; +} + +/** + * hdd_restore_custom_reg_settings() - restore custom reg settings + * @wiphy: wiphy structure + * @country_alpha2: alpha2 of the country + * @reset: whether wiphy is reset + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_restore_custom_reg_settings(struct wiphy *wiphy, + uint8_t *country_alpha2, + bool *reset) +{ +} +#else +static void hdd_restore_custom_reg_settings(struct wiphy *wiphy, + uint8_t *country_alpha2, + bool *reset) +{ + struct ieee80211_supported_band *sband; + enum nl80211_band band; + struct ieee80211_channel *chan; + int i; + + if ((country_alpha2[0] == '0') && + (country_alpha2[1] == '0') && + (wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY)) { + + for (band = 0; band < HDD_NUM_NL80211_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + for (i = 0; i < sband->n_channels; i++) { + chan = &sband->channels[i]; + chan->flags = chan->orig_flags; + chan->max_antenna_gain = chan->orig_mag; + chan->max_power = chan->orig_mpwr; + } + } + *reset = true; + } +} +#endif + +/** + * hdd_restore_reg_flags() - restore regulatory flags + * @wiphy: device wiphy + * @flags: regulatory flags + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) || defined(WITH_BACKPORTS) +static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags) +{ + wiphy->regulatory_flags = flags; +} +#else +static void hdd_restore_reg_flags(struct wiphy *wiphy, uint32_t flags) +{ + wiphy->flags = flags; +} +#endif + +/** + * hdd_reg_notifier() - regulatory notifier + * @wiphy: wiphy + * @request: regulatory request + * + * Return: void + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + char country[REG_ALPHA2_LEN + 1] = {0}; + bool update_already_in_progress = + hdd_ctx->is_regulatory_update_in_progress; + + if (cds_is_driver_unloading() || cds_is_driver_recovering() || + cds_is_driver_in_bad_state()) { + hdd_err("unloading or ssr in progress, ignore"); + return; + } + + if (hdd_ctx->is_wiphy_suspended) { + hdd_err_rl("system/cfg80211 is already suspend"); + return; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err_rl("Driver module is closed, dropping request"); + return; + } + + hdd_debug("country: %c%c, initiator %d, dfs_region: %d", + request->alpha2[0], + request->alpha2[1], + request->initiator, + request->dfs_region); + + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_USER: + + if (request->user_reg_hint_type != + NL80211_USER_REG_HINT_CELL_BASE) + return; + + qdf_event_reset(&hdd_ctx->regulatory_update_event); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = true; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + + qdf_mem_copy(country, request->alpha2, QDF_MIN( + sizeof(request->alpha2), sizeof(country))); + status = ucfg_reg_set_country(hdd_ctx->pdev, country); + break; + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_COUNTRY_IE: + case NL80211_REGDOM_SET_BY_DRIVER: + default: + break; + } + + if (QDF_IS_STATUS_ERROR(status) && !update_already_in_progress) { + hdd_err("Failed to set country"); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = false; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + } +} +#else +void hdd_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + bool reset = false; + enum dfs_reg dfs_reg; + struct reg_config_vars config_vars; + int ret_val; + + hdd_debug("country: %c%c, initiator %d, dfs_region: %d", + request->alpha2[0], + request->alpha2[1], + request->initiator, + request->dfs_region); + + if (!hdd_ctx) { + hdd_err("invalid hdd_ctx pointer"); + return; + } + + if (cds_is_driver_unloading() || cds_is_driver_recovering() || + cds_is_driver_in_bad_state()) { + hdd_err("unloading or ssr in progress, ignore"); + return; + } + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) { + hdd_err("Driver module is closed; dropping request"); + return; + } + + if (hdd_ctx->is_wiphy_suspended == true) { + hdd_err("system/cfg80211 is already suspend"); + return; + } + + if (('K' == request->alpha2[0]) && + ('R' == request->alpha2[1])) + request->dfs_region = (enum nl80211_dfs_regions)DFS_KR_REGION; + + if (('C' == request->alpha2[0]) && + ('N' == request->alpha2[1])) + request->dfs_region = (enum nl80211_dfs_regions)DFS_CN_REGION; + + /* first check if this callback is in response to the driver callback */ + switch (request->initiator) { + case NL80211_REGDOM_SET_BY_DRIVER: + case NL80211_REGDOM_SET_BY_CORE: + case NL80211_REGDOM_SET_BY_USER: + + if ((false == init_by_driver) && + (false == init_by_reg_core)) { + + if (NL80211_REGDOM_SET_BY_CORE == request->initiator) + return; + init_by_reg_core = true; + } + + if ((NL80211_REGDOM_SET_BY_DRIVER == request->initiator) && + (true == init_by_driver)) { + + /* + * restore the driver regulatory flags since + * regulatory_hint may have + * changed them + */ + hdd_restore_reg_flags(wiphy, hdd_ctx->reg.reg_flags); + } + + if (NL80211_REGDOM_SET_BY_CORE == request->initiator) { + hdd_ctx->reg.cc_src = SOURCE_CORE; + if (is_wiphy_custom_regulatory(wiphy)) + reset = true; + } else if (NL80211_REGDOM_SET_BY_DRIVER == request->initiator) { + hdd_ctx->reg.cc_src = SOURCE_DRIVER; + } else { + hdd_ctx->reg.cc_src = SOURCE_USERSPACE; + hdd_restore_custom_reg_settings(wiphy, + request->alpha2, + &reset); + } + + hdd_ctx->reg.alpha2[0] = request->alpha2[0]; + hdd_ctx->reg.alpha2[1] = request->alpha2[1]; + + ret_val = hdd_update_regulatory_info(hdd_ctx); + if (ret_val) { + hdd_err("invalid reg info, do not process"); + return; + } + + hdd_process_regulatory_data(hdd_ctx, wiphy, reset); + + sme_generic_change_country_code(hdd_ctx->mac_handle, + hdd_ctx->reg.alpha2); + + cds_fill_and_send_ctl_to_fw(&hdd_ctx->reg); + + hdd_set_dfs_region(hdd_ctx, request->dfs_region); + wlan_reg_get_dfs_region(hdd_ctx->pdev, &dfs_reg); + + reg_program_config_vars(hdd_ctx, &config_vars); + ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars); + ucfg_reg_program_mas_chan_list(hdd_ctx->psoc, + reg_channels, + hdd_ctx->reg.alpha2, + dfs_reg); + break; + + default: + break; + } +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +static void fill_wiphy_channel_320mhz(struct ieee80211_channel *wiphy_chan, + uint16_t max_bw) +{ + if (max_bw < 320) + wiphy_chan->flags |= IEEE80211_CHAN_NO_320MHZ; +} +#else +static inline +void fill_wiphy_channel_320mhz(struct ieee80211_channel *wiphy_chan, + uint16_t max_bw) +{ +} +#endif + +static void fill_wiphy_channel(struct ieee80211_channel *wiphy_chan, + struct regulatory_channel *cur_chan) +{ + + wiphy_chan->flags = 0; + wiphy_chan->max_power = cur_chan->tx_power; + + if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED) + wiphy_chan->flags |= IEEE80211_CHAN_DISABLED; + if (cur_chan->chan_flags & REGULATORY_CHAN_NO_IR) + wiphy_chan->flags |= IEEE80211_CHAN_NO_IR; + if (cur_chan->chan_flags & REGULATORY_CHAN_RADAR) + wiphy_chan->flags |= IEEE80211_CHAN_RADAR; + if (cur_chan->chan_flags & REGULATORY_CHAN_NO_OFDM) + wiphy_chan->flags |= IEEE80211_CHAN_NO_OFDM; + if (cur_chan->chan_flags & REGULATORY_CHAN_INDOOR_ONLY) + wiphy_chan->flags |= IEEE80211_CHAN_INDOOR_ONLY; + + if (cur_chan->max_bw < 10) + wiphy_chan->flags |= IEEE80211_CHAN_NO_10MHZ; + if (cur_chan->max_bw < 20) + wiphy_chan->flags |= IEEE80211_CHAN_NO_20MHZ; + if (cur_chan->max_bw < 40) + wiphy_chan->flags |= IEEE80211_CHAN_NO_HT40; + if (cur_chan->max_bw < 80) + wiphy_chan->flags |= IEEE80211_CHAN_NO_80MHZ; + if (cur_chan->max_bw < 160) + wiphy_chan->flags |= IEEE80211_CHAN_NO_160MHZ; + + fill_wiphy_channel_320mhz(wiphy_chan, cur_chan->max_bw); + + wiphy_chan->orig_flags = wiphy_chan->flags; +} + +static void fill_wiphy_band_channels(struct wiphy *wiphy, + struct regulatory_channel *cur_chan_list, + uint8_t band_id) +{ + uint32_t wiphy_num_chan, wiphy_index; + uint32_t chan_cnt; + struct ieee80211_channel *wiphy_chan; + + if (!wiphy->bands[band_id]) + return; + + wiphy_num_chan = wiphy->bands[band_id]->n_channels; + wiphy_chan = wiphy->bands[band_id]->channels; + + for (wiphy_index = 0; wiphy_index < wiphy_num_chan; wiphy_index++) { + for (chan_cnt = 0; chan_cnt < NUM_CHANNELS; chan_cnt++) { + if (wiphy_chan[wiphy_index].center_freq == + cur_chan_list[chan_cnt].center_freq) { + fill_wiphy_channel(&(wiphy_chan[wiphy_index]), + &(cur_chan_list[chan_cnt])); + break; + } + } + } +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * hdd_ch_avoid_ind() - Avoid notified channels from FW handler + * @hdd_ctxt: HDD context + * @unsafe_chan_list: Channels that are unsafe + * @avoid_freq_list: Frequencies to avoid + * + * Avoid channel notification from FW handler. + * FW will send un-safe channel list to avoid over wrapping. + * hostapd should not use notified channel + * + * Return: None + */ +void hdd_ch_avoid_ind(struct hdd_context *hdd_ctxt, + struct unsafe_ch_list *unsafe_chan_list, + struct ch_avoid_ind_type *avoid_freq_list) +{ + uint16_t *local_unsafe_list; + uint16_t local_unsafe_list_count; + uint32_t restriction_mask; + uint8_t i; + + /* Basic sanity */ + if (!hdd_ctxt) { + hdd_err("Invalid arguments"); + return; + } + + mutex_lock(&hdd_ctxt->avoid_freq_lock); + qdf_mem_copy(&hdd_ctxt->coex_avoid_freq_list, avoid_freq_list, + sizeof(struct ch_avoid_ind_type)); + mutex_unlock(&hdd_ctxt->avoid_freq_lock); + + restriction_mask = wlan_hdd_get_restriction_mask(hdd_ctxt); + if (hdd_clone_local_unsafe_chan(hdd_ctxt, + &local_unsafe_list, + &local_unsafe_list_count) != 0) { + hdd_err("failed to clone cur unsafe chan list"); + return; + } + + /* clear existing unsafe channel cache */ + hdd_ctxt->unsafe_channel_count = 0; + qdf_mem_zero(hdd_ctxt->unsafe_channel_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + + hdd_ctxt->unsafe_channel_count = unsafe_chan_list->chan_cnt; + + wlan_hdd_set_restriction_mask(hdd_ctxt); + + for (i = 0; i < unsafe_chan_list->chan_cnt; i++) { + hdd_ctxt->unsafe_channel_list[i] = + unsafe_chan_list->chan_freq_list[i]; + } + hdd_debug("number of unsafe channels is %d ", + hdd_ctxt->unsafe_channel_count); + + if (pld_set_wlan_unsafe_channel(hdd_ctxt->parent_dev, + hdd_ctxt->unsafe_channel_list, + hdd_ctxt->unsafe_channel_count)) { + hdd_err("Failed to set unsafe channel"); + + /* clear existing unsafe channel cache */ + hdd_ctxt->unsafe_channel_count = 0; + qdf_mem_zero(hdd_ctxt->unsafe_channel_list, + sizeof(hdd_ctxt->unsafe_channel_list)); + qdf_mem_free(local_unsafe_list); + return; + } + + mutex_lock(&hdd_ctxt->avoid_freq_lock); + if (hdd_ctxt->dnbs_avoid_freq_list.ch_avoid_range_cnt) + if (wlan_hdd_merge_avoid_freqs(avoid_freq_list, + &hdd_ctxt->dnbs_avoid_freq_list)) { + mutex_unlock(&hdd_ctxt->avoid_freq_lock); + hdd_debug("unable to merge avoid freqs"); + qdf_mem_free(local_unsafe_list); + return; + } + mutex_unlock(&hdd_ctxt->avoid_freq_lock); + /* + * first update the unsafe channel list to the platform driver and + * send the avoid freq event to the application + */ + wlan_hdd_send_avoid_freq_event(hdd_ctxt, avoid_freq_list); + + if (!hdd_ctxt->unsafe_channel_count) { + hdd_debug("no unsafe channels - not restarting SAP"); + qdf_mem_free(local_unsafe_list); + return; + } + if (hdd_local_unsafe_channel_updated(hdd_ctxt, + local_unsafe_list, + local_unsafe_list_count, + restriction_mask)) + hdd_unsafe_channel_restart_sap(hdd_ctxt); + qdf_mem_free(local_unsafe_list); + +} +#endif + +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) +static void map_nl_reg_rule_flags(uint16_t drv_reg_rule_flag, + uint32_t *regd_rule_flag) +{ + if (drv_reg_rule_flag & REGULATORY_CHAN_NO_IR) + *regd_rule_flag |= NL80211_RRF_NO_IR; + if (drv_reg_rule_flag & REGULATORY_CHAN_RADAR) + *regd_rule_flag |= NL80211_RRF_DFS; + if (drv_reg_rule_flag & REGULATORY_CHAN_INDOOR_ONLY) + *regd_rule_flag |= NL80211_RRF_NO_OUTDOOR; + if (drv_reg_rule_flag & REGULATORY_CHAN_NO_OFDM) + *regd_rule_flag |= NL80211_RRF_NO_OFDM; + *regd_rule_flag |= NL80211_RRF_AUTO_BW; +} + +/** + * dfs_reg_to_nl80211_dfs_regions() - convert dfs_reg to nl80211_dfs_regions + * @dfs_region: DFS region + * + * Return: nl80211_dfs_regions + */ +static enum nl80211_dfs_regions dfs_reg_to_nl80211_dfs_regions( + enum dfs_reg dfs_region) +{ + switch (dfs_region) { + case DFS_UNINIT_REGION: + return NL80211_DFS_UNSET; + case DFS_FCC_REGION: + return NL80211_DFS_FCC; + case DFS_ETSI_REGION: + return NL80211_DFS_ETSI; + case DFS_MKK_REGION: + return NL80211_DFS_JP; + default: + return NL80211_DFS_UNSET; + } +} + +/** + * hdd_set_dfs_pri_multiplier() - Set dfs_pri_multiplier for ETSI region + * @hdd_ctx: HDD context + * @dfs_region: DFS region + * + * Return: none + */ +#ifdef DFS_PRI_MULTIPLIER +static void hdd_set_dfs_pri_multiplier(struct hdd_context *hdd_ctx, + enum dfs_reg dfs_region) +{ + if (dfs_region == DFS_ETSI_REGION) + wlan_sap_set_dfs_pri_multiplier(hdd_ctx->mac_handle); +} +#else +static inline void hdd_set_dfs_pri_multiplier(struct hdd_context *hdd_ctx, + enum dfs_reg dfs_region) +{ +} +#endif + +void hdd_send_wiphy_regd_sync_event(struct hdd_context *hdd_ctx) +{ + struct ieee80211_regdomain *regd; + struct ieee80211_reg_rule *regd_rules; + struct reg_rule_info reg_rules_struct; + struct reg_rule_info *reg_rules; + QDF_STATUS status; + uint8_t i; + + if (!hdd_ctx) { + hdd_err("hdd_ctx is NULL"); + return; + } + + status = ucfg_reg_get_regd_rules(hdd_ctx->pdev, ®_rules_struct); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("could not get reg rules"); + return; + } + + reg_rules = ®_rules_struct; + if (!reg_rules->num_of_reg_rules) { + hdd_err("no reg rules %d", reg_rules->num_of_reg_rules); + return; + } + + regd = qdf_mem_malloc((reg_rules->num_of_reg_rules * + sizeof(*regd_rules) + sizeof(*regd))); + if (!regd) + return; + + regd->n_reg_rules = reg_rules->num_of_reg_rules; + qdf_mem_copy(regd->alpha2, reg_rules->alpha2, REG_ALPHA2_LEN + 1); + regd->dfs_region = + dfs_reg_to_nl80211_dfs_regions(reg_rules->dfs_region); + + hdd_set_dfs_pri_multiplier(hdd_ctx, reg_rules->dfs_region); + + regd_rules = regd->reg_rules; + hdd_debug("Regulatory Domain %s", regd->alpha2); + hdd_debug("start freq\tend freq\t@ max_bw\tant_gain\tpwr\tflags"); + for (i = 0; i < reg_rules->num_of_reg_rules; i++) { + regd_rules[i].freq_range.start_freq_khz = + reg_rules->reg_rules[i].start_freq * 1000; + regd_rules[i].freq_range.end_freq_khz = + reg_rules->reg_rules[i].end_freq * 1000; + regd_rules[i].freq_range.max_bandwidth_khz = + reg_rules->reg_rules[i].max_bw * 1000; + regd_rules[i].power_rule.max_antenna_gain = + reg_rules->reg_rules[i].ant_gain * 100; + regd_rules[i].power_rule.max_eirp = + reg_rules->reg_rules[i].reg_power * 100; + map_nl_reg_rule_flags(reg_rules->reg_rules[i].flags, + ®d_rules[i].flags); + hdd_debug("%d KHz\t%d KHz\t@ %d KHz\t%d\t\t%d\t%d", + regd_rules[i].freq_range.start_freq_khz, + regd_rules[i].freq_range.end_freq_khz, + regd_rules[i].freq_range.max_bandwidth_khz, + regd_rules[i].power_rule.max_antenna_gain, + regd_rules[i].power_rule.max_eirp, + regd_rules[i].flags); + } + + regulatory_set_wiphy_regd(hdd_ctx->wiphy, regd); + + hdd_debug("regd sync event sent with reg rules info"); + qdf_mem_free(regd); +} +#endif + +#if defined(CONFIG_BAND_6GHZ) && (defined(CFG80211_6GHZ_BAND_SUPPORTED) || \ + (KERNEL_VERSION(5, 4, 0) <= LINUX_VERSION_CODE)) +static void +fill_wiphy_6ghz_band_channels(struct wiphy *wiphy, + struct regulatory_channel *chan_list) +{ + fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_6GHZ); +} +#else +static void +fill_wiphy_6ghz_band_channels(struct wiphy *wiphy, + struct regulatory_channel *chan_list) +{ +} +#endif + +#define HDD_MAX_CHAN_INFO_LOG 192 + +/** + * hdd_regulatory_chanlist_dump() - Dump regulatory channel list info + * @chan_list: regulatory channel list + * + * Return: void + */ +static void hdd_regulatory_chanlist_dump(struct regulatory_channel *chan_list) +{ + uint32_t i; + uint8_t info[HDD_MAX_CHAN_INFO_LOG]; + int len = 0; + struct regulatory_channel *chan; + uint32_t count = 0; + int ret; + + hdd_debug("start (freq MHz, tx power dBm):"); + for (i = 0; i < NUM_CHANNELS; i++) { + chan = &chan_list[i]; + if ((chan->chan_flags & REGULATORY_CHAN_DISABLED)) + continue; + count++; + ret = scnprintf(info + len, sizeof(info) - len, "%d %d ", + chan->center_freq, chan->tx_power); + if (ret <= 0) + break; + len += ret; + if (len >= (sizeof(info) - 20)) { + hdd_debug("%s", info); + len = 0; + } + } + if (len > 0) + hdd_debug("%s", info); + hdd_debug("end total_count %d", count); +} + +#ifdef FEATURE_WLAN_CH_AVOID_EXT +/** + * hdd_country_change_bw_check() - Check if bandwidth changed + * @link_info: Link info pointer in HDD adapter + * @oper_freq: current frequency of adapter + * + * Return: true if bandwidth changed otherwise false. + */ +static bool hdd_country_change_bw_check(struct wlan_hdd_link_info *link_info, + qdf_freq_t oper_freq) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + bool width_changed = false; + enum phy_ch_width width; + uint16_t org_bw = 0; + struct regulatory_channel *cur_chan_list = NULL; + int i; + + cur_chan_list = qdf_mem_malloc(sizeof(*cur_chan_list) * NUM_CHANNELS); + if (!cur_chan_list) + return false; + + ucfg_reg_get_current_chan_list(hdd_ctx->pdev, cur_chan_list); + + width = hdd_get_link_info_width(link_info); + org_bw = wlan_reg_get_bw_value(width); + + for (i = 0; i < NUM_CHANNELS; i++) { + if (cur_chan_list[i].state == + CHANNEL_STATE_DISABLE) + continue; + + if (cur_chan_list[i].center_freq == oper_freq && + org_bw > cur_chan_list[i].max_bw) { + width_changed = true; + break; + } + } + qdf_mem_free(cur_chan_list); + return width_changed; +} +#else +static inline bool +hdd_country_change_bw_check(struct wlan_hdd_link_info *link_info, + qdf_freq_t oper_freq) +{ + return false; +} +#endif + +/** + * hdd_country_change_update_sta() - handle country code change for STA + * @hdd_ctx: Global HDD context + * + * This function handles the stop/start/restart of STA/P2P_CLI adapters when + * the country code changes + * + * Return: none + */ +static void hdd_country_change_update_sta(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + struct hdd_station_ctx *sta_ctx = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + uint32_t new_phy_mode; + bool freq_changed, phy_changed, width_changed; + qdf_freq_t oper_freq; + eCsrPhyMode csr_phy_mode; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_COUNTRY_CHANGE_UPDATE_STA; + struct wlan_hdd_link_info *link_info; + enum qca_wlan_vendor_phy_mode vendor_phy_mode = + QCA_WLAN_VENDOR_PHY_MODE_AUTO; + + pdev = hdd_ctx->pdev; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + width_changed = false; + oper_freq = hdd_get_link_info_home_channel(link_info); + if (oper_freq) + freq_changed = wlan_reg_is_disable_for_pwrmode( + pdev, oper_freq, + REG_CURRENT_PWR_MODE); + else + freq_changed = false; + + switch (adapter->device_mode) { + case QDF_P2P_CLIENT_MODE: + /* + * P2P client is the same as STA + * continue to next statement + */ + case QDF_STA_MODE: + hdd_debug("Update vdev %d CAP IE", link_info->vdev_id); + sme_set_vdev_ies_per_band(hdd_ctx->mac_handle, + link_info->vdev_id, + QDF_STA_MODE); + + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + new_phy_mode = wlan_reg_get_max_phymode(pdev, + REG_PHYMODE_MAX, + oper_freq); + csr_phy_mode = + csr_convert_from_reg_phy_mode(new_phy_mode); + phy_changed = + (sta_ctx->reg_phymode != csr_phy_mode); + + width_changed = + hdd_country_change_bw_check(link_info, + oper_freq); + + if (!hdd_is_vdev_in_conn_state(link_info)) { + hdd_set_vdev_phy_mode(adapter, + vendor_phy_mode); + continue; + } + + if (phy_changed || freq_changed || + width_changed) { + hdd_debug("changed: phy %d, freq %d, width %d", + phy_changed, freq_changed, + width_changed); + wlan_hdd_cm_issue_disconnect( + link_info, + REASON_UNSPEC_FAILURE, + false); + hdd_set_vdev_phy_mode(adapter, + vendor_phy_mode); + sta_ctx->reg_phymode = csr_phy_mode; + } else { + hdd_debug("Remain on current channel but update tx power"); + wlan_reg_update_tx_power_on_ctry_change( + pdev, + link_info->vdev_id); + } + break; + default: + break; + } + } + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +/** + * hdd_restart_sap_with_new_phymode() - restart the SAP with the new phymode + * @link_info: Link info pointer in HDD adapter. + * @sap_config: sap configuration pointer + * @csr_phy_mode: phymode to restart SAP with + * + * This function handles the stop/start/restart of SAP/P2P_GO adapters when the + * country code changes + * + * Return: none + */ +static void +hdd_restart_sap_with_new_phymode(struct wlan_hdd_link_info *link_info, + struct sap_config *sap_config, + eCsrPhyMode csr_phy_mode) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct hdd_hostapd_state *hostapd_state = NULL; + struct sap_context *sap_ctx = NULL; + QDF_STATUS status; + + hostapd_state = WLAN_HDD_GET_HOSTAP_STATE_PTR(link_info); + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + + if (!test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + sap_config->sap_orig_hw_mode = sap_config->SapHw_mode; + sap_config->SapHw_mode = csr_phy_mode; + hdd_err("Can't restart AP because it is not started"); + return; + } + + qdf_event_reset(&hostapd_state->qdf_stop_bss_event); + status = wlansap_stop_bss(sap_ctx); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("SAP Stop Bss fail"); + return; + } + status = qdf_wait_single_event(&hostapd_state->qdf_stop_bss_event, + SME_CMD_STOP_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("SAP Stop timeout"); + return; + } + + sap_config->chan_freq = + wlansap_get_safe_channel_from_pcl_and_acs_range(sap_ctx, NULL); + + sap_config->sap_orig_hw_mode = sap_config->SapHw_mode; + sap_config->SapHw_mode = csr_phy_mode; + + mutex_lock(&hdd_ctx->sap_lock); + qdf_event_reset(&hostapd_state->qdf_event); + status = wlansap_start_bss(sap_ctx, hdd_hostapd_sap_event_cb, + sap_config, adapter->dev); + if (!QDF_IS_STATUS_SUCCESS(status)) { + mutex_unlock(&hdd_ctx->sap_lock); + hdd_err("SAP Start Bss fail"); + return; + } + status = qdf_wait_single_event(&hostapd_state->qdf_event, + SME_CMD_START_BSS_TIMEOUT); + if (!QDF_IS_STATUS_SUCCESS(status)) { + mutex_unlock(&hdd_ctx->sap_lock); + hdd_err("SAP Start timeout"); + return; + } + mutex_unlock(&hdd_ctx->sap_lock); +} + +/** + * hdd_country_change_update_sap() - handle country code change for SAP + * @hdd_ctx: Global HDD context + * + * This function handles the stop/start/restart of SAP/P2P_GO adapters when the + * country code changes + * + * Return: none + */ +static void hdd_country_change_update_sap(struct hdd_context *hdd_ctx) +{ + struct hdd_adapter *adapter = NULL, *next_adapter = NULL; + struct sap_config *sap_config = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + uint32_t reg_phy_mode, new_phy_mode; + bool phy_changed; + qdf_freq_t oper_freq; + eCsrPhyMode csr_phy_mode; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_COUNTRY_CHANGE_UPDATE_SAP; + struct wlan_hdd_link_info *link_info; + + pdev = hdd_ctx->pdev; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + oper_freq = hdd_get_link_info_home_channel(link_info); + + switch (adapter->device_mode) { + case QDF_P2P_GO_MODE: + policy_mgr_check_sap_restart(hdd_ctx->psoc, + link_info->vdev_id); + break; + case QDF_SAP_MODE: + if (!test_bit(SOFTAP_INIT_DONE, + &link_info->link_flags)) { + hdd_info("AP is not started yet"); + break; + } + sap_config = &link_info->session.ap.sap_config; + reg_phy_mode = csr_convert_to_reg_phy_mode( + sap_config->sap_orig_hw_mode, + oper_freq); + new_phy_mode = wlan_reg_get_max_phymode(pdev, + reg_phy_mode, + oper_freq); + csr_phy_mode = + csr_convert_from_reg_phy_mode(new_phy_mode); + phy_changed = + (csr_phy_mode != sap_config->SapHw_mode); + + if (phy_changed) + hdd_restart_sap_with_new_phymode(link_info, + sap_config, + csr_phy_mode); + else + policy_mgr_check_sap_restart( + hdd_ctx->psoc, + link_info->vdev_id); + hdd_debug("Update tx power due to ctry change"); + wlan_reg_update_tx_power_on_ctry_change( + pdev, link_info->vdev_id); + break; + default: + break; + } + } + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +static void __hdd_country_change_work_handle(struct hdd_context *hdd_ctx) +{ + /* + * Loop over STAs first since it may lead to different channel + * selection for SAPs + */ + hdd_country_change_update_sta(hdd_ctx); + sme_generic_change_country_code(hdd_ctx->mac_handle, + hdd_ctx->reg.alpha2); + + qdf_event_set_all(&hdd_ctx->regulatory_update_event); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = false; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + + hdd_country_change_update_sap(hdd_ctx); +} + +/** + * hdd_handle_country_change_work_error() - handle country code change error + * @hdd_ctx: Global HDD context + * @errno: country code change error number + * + * This function handles error code in country code change worker + * + * Return: none + */ +static void hdd_handle_country_change_work_error(struct hdd_context *hdd_ctx, + int errno) +{ + if (errno == -EAGAIN) { + qdf_sleep(COUNTRY_CHANGE_WORK_RESCHED_WAIT_TIME); + hdd_debug("rescheduling country change work"); + qdf_sched_work(0, &hdd_ctx->country_change_work); + } else { + hdd_err("can not handle country change %d", errno); + qdf_event_set_all(&hdd_ctx->regulatory_update_event); + qdf_mutex_acquire(&hdd_ctx->regulatory_status_lock); + hdd_ctx->is_regulatory_update_in_progress = false; + qdf_mutex_release(&hdd_ctx->regulatory_status_lock); + } +} + +/** + * hdd_country_change_work_handle() - handle country code change + * @arg: Global HDD context + * + * This function handles the stop/start/restart of all adapters when the + * country code changes + * + * Return: none + */ +static void hdd_country_change_work_handle(void *arg) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)arg; + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return hdd_handle_country_change_work_error(hdd_ctx, errno); + + errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (errno) + return hdd_handle_country_change_work_error(hdd_ctx, errno); + + if (hdd_ctx->driver_status != DRIVER_MODULES_ENABLED) + hdd_err("Driver disabled, ignore country code change"); + else + __hdd_country_change_work_handle(hdd_ctx); + + osif_psoc_sync_op_stop(psoc_sync); +} + +static void hdd_regulatory_dyn_cbk(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev, + struct regulatory_channel *chan_list, + struct avoid_freq_ind_data *avoid_freq_ind, + void *arg) +{ + struct wiphy *wiphy; + struct pdev_osif_priv *pdev_priv; + struct hdd_context *hdd_ctx; + enum country_src cc_src; + uint8_t alpha2[REG_ALPHA2_LEN + 1]; + bool nb_flag; + bool reg_flag; + + pdev_priv = wlan_pdev_get_ospriv(pdev); + wiphy = pdev_priv->wiphy; + hdd_ctx = wiphy_priv(wiphy); + + nb_flag = ucfg_mlme_get_coex_unsafe_chan_nb_user_prefer_for_sap( + hdd_ctx->psoc); + reg_flag = ucfg_mlme_get_coex_unsafe_chan_reg_disable(hdd_ctx->psoc); + + if (avoid_freq_ind && nb_flag && reg_flag) + goto sync_chanlist; + + if (avoid_freq_ind) { + hdd_ch_avoid_ind(hdd_ctx, &avoid_freq_ind->chan_list, + &avoid_freq_ind->freq_list); + return; + } + +sync_chanlist: + + hdd_debug("process channel list update from regulatory"); + hdd_regulatory_chanlist_dump(chan_list); + + fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_2GHZ); + fill_wiphy_band_channels(wiphy, chan_list, NL80211_BAND_5GHZ); + fill_wiphy_6ghz_band_channels(wiphy, chan_list); + cc_src = ucfg_reg_get_cc_and_src(hdd_ctx->psoc, alpha2); + qdf_mem_copy(hdd_ctx->reg.alpha2, alpha2, REG_ALPHA2_LEN + 1); + + /* Check the kernel version for upstream commit aced43ce780dc5 that + * has support for processing user cell_base hints when wiphy is + * self managed or check the backport flag for the same. + */ +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) + if (wiphy->registered) + hdd_send_wiphy_regd_sync_event(hdd_ctx); +#endif + + hdd_config_tdls_with_band_switch(hdd_ctx); + qdf_sched_work(0, &hdd_ctx->country_change_work); +} + +int hdd_update_regulatory_config(struct hdd_context *hdd_ctx) +{ + struct reg_config_vars config_vars; + + reg_program_config_vars(hdd_ctx, &config_vars); + ucfg_reg_set_config_vars(hdd_ctx->psoc, config_vars); + return 0; +} + +int hdd_init_regulatory_update_event(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = qdf_event_create(&hdd_ctx->regulatory_update_event); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to create regulatory update event"); + goto failure; + } + status = qdf_mutex_create(&hdd_ctx->regulatory_status_lock); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to create regulatory status mutex"); + goto failure; + } + hdd_ctx->is_regulatory_update_in_progress = false; + +failure: + return qdf_status_to_os_return(status); +} + +int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy) +{ + bool offload_enabled; + struct regulatory_channel *cur_chan_list; + int ret; + + cur_chan_list = qdf_mem_malloc(sizeof(*cur_chan_list) * NUM_CHANNELS); + if (!cur_chan_list) { + return -ENOMEM; + } + + qdf_create_work(0, &hdd_ctx->country_change_work, + hdd_country_change_work_handle, hdd_ctx); + ucfg_reg_register_chan_change_callback(hdd_ctx->psoc, + hdd_regulatory_dyn_cbk, + NULL); + + ret = hdd_update_country_code(hdd_ctx); + if (ret) { + hdd_err("Failed to update country code; errno:%d", ret); + return -EINVAL; + } + + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; + /* Check the kernel version for upstream commit aced43ce780dc5 that + * has support for processing user cell_base hints when wiphy is + * self managed or check the backport flag for the same. + */ +#if defined CFG80211_USER_HINT_CELL_BASE_SELF_MANAGED || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)) + wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS; +#endif + wiphy->reg_notifier = hdd_reg_notifier; + offload_enabled = ucfg_reg_is_regdb_offloaded(hdd_ctx->psoc); + hdd_debug("regulatory offload_enabled %d", offload_enabled); + if (offload_enabled) + hdd_ctx->reg_offload = true; + else + hdd_ctx->reg_offload = false; + + ucfg_reg_get_current_chan_list(hdd_ctx->pdev, cur_chan_list); + hdd_regulatory_chanlist_dump(cur_chan_list); + fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_2GHZ); + fill_wiphy_band_channels(wiphy, cur_chan_list, NL80211_BAND_5GHZ); + fill_wiphy_6ghz_band_channels(wiphy, cur_chan_list); + qdf_mem_zero(hdd_ctx->reg.alpha2, REG_ALPHA2_LEN + 1); + + qdf_mem_free(cur_chan_list); + return 0; +} + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy) +{ + hdd_ctx->reg_offload = false; + wiphy->reg_notifier = hdd_reg_notifier; + wiphy->regulatory_flags |= REGULATORY_DISABLE_BEACON_HINTS; + wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE; + hdd_regulatory_init_no_offload(hdd_ctx, wiphy); + + return 0; +} + +#else +int hdd_regulatory_init(struct hdd_context *hdd_ctx, struct wiphy *wiphy) +{ + hdd_ctx->reg_offload = false; + wiphy->reg_notifier = hdd_reg_notifier; + wiphy->flags |= WIPHY_FLAG_DISABLE_BEACON_HINTS; + wiphy->country_ie_pref |= NL80211_COUNTRY_IE_IGNORE_CORE; + hdd_regulatory_init_no_offload(hdd_ctx, wiphy); + + return 0; +} +#endif + +void hdd_deinit_regulatory_update_event(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = qdf_event_destroy(&hdd_ctx->regulatory_update_event); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to destroy regulatory update event"); + status = qdf_mutex_destroy(&hdd_ctx->regulatory_status_lock); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to destroy regulatory status mutex"); +} + +void hdd_regulatory_deinit(struct hdd_context *hdd_ctx) +{ + qdf_flush_work(&hdd_ctx->country_change_work); + qdf_destroy_work(0, &hdd_ctx->country_change_work); +} + +void hdd_update_regdb_offload_config(struct hdd_context *hdd_ctx) +{ + bool ignore_fw_reg_offload_ind = false; + + ucfg_mlme_get_ignore_fw_reg_offload_ind(hdd_ctx->psoc, + &ignore_fw_reg_offload_ind); + if (!ignore_fw_reg_offload_ind) { + hdd_debug("regdb offload is based on firmware capability"); + return; + } + + hdd_debug("Ignore regdb offload Indication from FW"); + ucfg_set_ignore_fw_reg_offload_ind(hdd_ctx->psoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rssi_monitor.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rssi_monitor.c new file mode 100644 index 0000000000..a4b1374b97 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rssi_monitor.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_rssi_monitor.c + * + * WLAN rssi monitoring functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#define PARAM_MAX QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX +#define PARAM_REQUEST_ID QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID +#define PARAM_CONTROL QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL +#define PARAM_MIN_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI +#define PARAM_MAX_RSSI QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI + +const struct nla_policy moitor_rssi_policy[ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL] = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI] = { .type = NLA_S8 }, + [QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI] = { .type = NLA_S8 }, +}; + +/** + * __wlan_hdd_cfg80211_monitor_rssi() - monitor rssi + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[PARAM_MAX + 1]; + struct rssi_monitor_param req; + QDF_STATUS status; + int ret; + uint32_t control; + mac_handle_t mac_handle; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Not in Connected state!"); + return -ENOTSUPP; + } + + if (wlan_cfg80211_nla_parse(tb, PARAM_MAX, data, data_len, + moitor_rssi_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[PARAM_REQUEST_ID]) { + hdd_err("attr request id failed"); + return -EINVAL; + } + + if (!tb[PARAM_CONTROL]) { + hdd_err("attr control failed"); + return -EINVAL; + } + + req.request_id = nla_get_u32(tb[PARAM_REQUEST_ID]); + req.vdev_id = adapter->deflink->vdev_id; + control = nla_get_u32(tb[PARAM_CONTROL]); + + if (control == QCA_WLAN_RSSI_MONITORING_START) { + req.control = true; + if (!tb[PARAM_MIN_RSSI]) { + hdd_err("attr min rssi failed"); + return -EINVAL; + } + + if (!tb[PARAM_MAX_RSSI]) { + hdd_err("attr max rssi failed"); + return -EINVAL; + } + + req.min_rssi = nla_get_s8(tb[PARAM_MIN_RSSI]); + req.max_rssi = nla_get_s8(tb[PARAM_MAX_RSSI]); + + if (!(req.min_rssi < req.max_rssi)) { + hdd_warn("min_rssi: %d must be less than max_rssi: %d", + req.min_rssi, req.max_rssi); + return -EINVAL; + } + hdd_debug("Min_rssi: %d Max_rssi: %d", + req.min_rssi, req.max_rssi); + + } else if (control == QCA_WLAN_RSSI_MONITORING_STOP) { + req.control = false; + } else { + hdd_err("Invalid control cmd: %d", control); + return -EINVAL; + } + hdd_debug("Request Id: %u vdev id: %d Control: %d", + req.request_id, req.vdev_id, req.control); + + mac_handle = hdd_ctx->mac_handle; + status = sme_set_rssi_monitoring(mac_handle, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_set_rssi_monitoring failed(err=%d)", status); + return -EINVAL; + } + + return 0; +} + +/* + * done with short names for the global vendor params + * used by __wlan_hdd_cfg80211_monitor_rssi() + */ +#undef PARAM_MAX +#undef PARAM_CONTROL +#undef PARAM_REQUEST_ID +#undef PARAM_MAX_RSSI +#undef PARAM_MIN_RSSI + +int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_monitor_rssi(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, + struct rssi_breach_event *data) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct sk_buff *skb; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX; + + hdd_enter(); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + if (!data) { + hdd_err("data is null"); + return; + } + + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + EXTSCAN_EVENT_BUF_SIZE + + NLMSG_HDRLEN, + index, GFP_KERNEL); + + if (!skb) { + hdd_err("mem alloc failed"); + return; + } + + hdd_debug("Req Id: %u Current rssi: %d", + data->request_id, data->curr_rssi); + hdd_debug("Current BSSID: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(data->curr_bssid.bytes)); + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID, + data->request_id) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID, + sizeof(data->curr_bssid), data->curr_bssid.bytes) || + nla_put_s8(skb, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI, + data->curr_rssi)) { + hdd_err("nla put fail"); + goto fail; + } + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + return; + +fail: + wlan_cfg80211_vendor_free_skb(skb); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rssi_monitor.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rssi_monitor.h new file mode 100644 index 0000000000..4cb3dde111 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rssi_monitor.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_RSSI_MONITOR_H +#define __WLAN_HDD_RSSI_MONITOR_H + +/** + * DOC: wlan_hdd_rssi_monitor_h + * + * WLAN Host Device Driver RSSI monitoring API specification + */ + +#ifdef FEATURE_RSSI_MONITOR + +/* QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI policy */ +extern const struct nla_policy moitor_rssi_policy[ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX + 1]; + +/** + * wlan_hdd_cfg80211_monitor_rssi() - SSR wrapper to rssi monitoring + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * Return: 0 on success; errno on failure + */ +int +wlan_hdd_cfg80211_monitor_rssi(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * hdd_rssi_threshold_breached() - rssi breached NL event + * @hdd_handle: HDD handle + * @data: rssi breached event data + * + * This function reads the rssi breached event %data and fill in the skb with + * NL attributes and send up the NL event. + * + * Return: none + */ +void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, + struct rssi_breach_event *data); + +#define FEATURE_RSSI_MONITOR_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI \ +}, + +#define FEATURE_RSSI_MONITOR_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_monitor_rssi, \ + vendor_command_policy(moitor_rssi_policy, \ + QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX) \ +}, + +#else /* FEATURE_RSSI_MONITOR */ +static inline +void hdd_rssi_threshold_breached(hdd_handle_t hdd_handle, + struct rssi_breach_event *data) +{ +} + +#define FEATURE_RSSI_MONITOR_VENDOR_EVENTS +#define FEATURE_RSSI_MONITOR_VENDOR_COMMANDS +#endif /* FEATURE_RSSI_MONITOR */ + +#endif /* __WLAN_HDD_RSSI_MONITOR_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.c new file mode 100644 index 0000000000..58ef1333f8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_hdd_includes.h" +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_rx_monitor.h" +#include "ol_txrx.h" +#include "cdp_txrx_mon.h" + +int hdd_enable_monitor_mode(struct net_device *dev) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t vdev_id; + + hdd_enter_dev(dev); + + vdev_id = cdp_get_mon_vdev_from_pdev(soc, OL_TXRX_PDEV_ID); + if (vdev_id < 0) + return -EINVAL; + + return cdp_set_monitor_mode(soc, vdev_id, false); +} + +int hdd_disable_monitor_mode(void) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + return cdp_reset_monitor_mode(soc, OL_TXRX_PDEV_ID, false); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.h new file mode 100644 index 0000000000..b449a2edd9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_rx_monitor.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_RX_MONITOR_H +#define __WLAN_HDD_RX_MONITOR_H + +struct ol_txrx_ops; + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +int hdd_enable_monitor_mode(struct net_device *dev); + +/** + * hdd_disable_monitor_mode() - Disable monitor mode + * + * This function invokes cdp interface API to disable + * monitor mode configuration on the hardware. In this + * case sends HTT messages to FW to reset hardware rings + * + * Return: 0 for success; non-zero for failure + */ +int hdd_disable_monitor_mode(void); +#else +static inline int hdd_enable_monitor_mode(struct net_device *dev) +{ + return 0; +} + +static inline int hdd_disable_monitor_mode(void) +{ + return 0; +} + +#endif /* FEATURE_MONITOR_MODE_SUPPORT */ + +#endif /* __WLAN_HDD_RX_MONITOR_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sap_cond_chan_switch.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sap_cond_chan_switch.c new file mode 100644 index 0000000000..4f8ab2d4ed --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sap_cond_chan_switch.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sap_cond_chan_switch.c + * + * WLAN SAP conditional channel switch functions + * + */ + +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include "wlan_hdd_pre_cac.h" + +const struct nla_policy conditional_chan_switch_policy[ + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST] = { + .type = NLA_BINARY }, + [QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS] = { + .type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_conditional_chan_switch() - Conditional channel switch + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Processes the conditional channel switch request and invokes the helper + * APIs to process the channel switch request. + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct nlattr + *tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1]; + uint32_t freq_len, i; + uint32_t *freq; + bool is_dfs_mode_enabled = false; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_STATUS_SUCCESS != ucfg_mlme_get_dfs_master_capability( + hdd_ctx->psoc, &is_dfs_mode_enabled)) { + hdd_err("Failed to get dfs master capability"); + return -EINVAL; + } + + if (!is_dfs_mode_enabled) { + hdd_err("DFS master capability is not present in the driver"); + return -EINVAL; + } + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + + /* + * audit note: it is ok to pass a NULL policy here since only + * one attribute is parsed which is array of frequencies and + * it is explicitly validated for both under read and over read + */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX, + data, data_len, conditional_chan_switch_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]) { + hdd_err("Frequency list is missing"); + return -EINVAL; + } + + freq_len = nla_len( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST])/ + sizeof(uint32_t); + + if (freq_len > NUM_CHANNELS) { + hdd_err("insufficient space to hold channels"); + return -ENOMEM; + } + + hdd_debug("freq_len=%d", freq_len); + + freq = nla_data( + tb[QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_FREQ_LIST]); + + for (i = 0; i < freq_len; i++) + hdd_debug("freq[%d]=%d", i, freq[i]); + + /* + * The input frequency list from user space is designed to be a + * priority based frequency list. This is only to accommodate any + * future request. But, current requirement is only to perform CAC + * on a single channel. So, the first entry from the list is picked. + * + * If channel is zero, any channel in the available outdoor regulatory + * domain will be selected. + */ + ret = wlan_hdd_request_pre_cac(hdd_ctx, freq[0]); + if (ret) { + hdd_err("pre cac request failed with reason:%d", ret); + return ret; + } + + return 0; +} + +int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_conditional_chan_switch(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sap_cond_chan_switch.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sap_cond_chan_switch.h new file mode 100644 index 0000000000..004115cb9b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sap_cond_chan_switch.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_SAP_COND_CHAN_SWITCH_H +#define __WLAN_HDD_SAP_COND_CHAN_SWITCH_H + +/** + * DOC: wlan_hdd_sap_cond_chan_switch_h + * + * WLAN Host Device Driver SAP conditional channel switch API specification + */ + +#ifdef FEATURE_SAP_COND_CHAN_SWITCH + +extern const struct nla_policy conditional_chan_switch_policy[ + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX + 1]; + +/** + * wlan_hdd_cfg80211_conditional_chan_switch() - SAP conditional channel switch + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Invokes internal API __wlan_hdd_cfg80211_conditional_chan_switch() + * to process the conditional channel switch request. + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_conditional_chan_switch(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_SAP_COND_CHAN_SWITCH_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_conditional_chan_switch, \ + vendor_command_policy( \ + conditional_chan_switch_policy, \ + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_MAX) \ +}, +#else /* FEATURE_SAP_COND_CHAN_SWITCH */ +#define FEATURE_SAP_COND_CHAN_SWITCH_VENDOR_COMMANDS +#endif /* FEATURE_SAP_COND_CHAN_SWITCH */ + +#endif /* __WLAN_HDD_SAP_COND_CHAN_SWITCH_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sar_limits.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sar_limits.c new file mode 100644 index 0000000000..6ee510e5a4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sar_limits.c @@ -0,0 +1,1299 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_vendor_sar_limits.c + * + * WLAN SAR limits functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include + +#define WLAN_WAIT_TIME_SAR 5000 +/** + * struct hdd_sar_context - hdd sar context + * @event: sar limit event + */ +struct hdd_sar_context { + struct sar_limit_event event; +}; + +static u32 hdd_sar_wmi_to_nl_enable(uint32_t wmi_value) +{ + switch (wmi_value) { + default: + case WMI_SAR_FEATURE_OFF: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE; + case WMI_SAR_FEATURE_ON_SET_0: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0; + case WMI_SAR_FEATURE_ON_SET_1: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1; + case WMI_SAR_FEATURE_ON_SET_2: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2; + case WMI_SAR_FEATURE_ON_SET_3: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3; + case WMI_SAR_FEATURE_ON_SET_4: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4; + case WMI_SAR_FEATURE_ON_USER_DEFINED: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER; + case WMI_SAR_FEATURE_ON_SAR_V2_0: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0; + } +} + +static u32 hdd_sar_wmi_to_nl_band(uint32_t wmi_value) +{ + switch (wmi_value) { + default: + case WMI_SAR_2G_ID: + return HDD_NL80211_BAND_2GHZ; + case WMI_SAR_5G_ID: + return HDD_NL80211_BAND_5GHZ; + } +} + +static u32 hdd_sar_wmi_to_nl_modulation(uint32_t wmi_value) +{ + switch (wmi_value) { + default: + case WMI_SAR_MOD_CCK: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK; + case WMI_SAR_MOD_OFDM: + return QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM; + } +} + +/** + * hdd_sar_cb () - sar response message handler + * @cookie: hdd request cookie + * @event: sar response event + * + * Return: none + */ +static void hdd_sar_cb(void *cookie, + struct sar_limit_event *event) +{ + struct osif_request *request; + struct hdd_sar_context *context; + + hdd_enter(); + + if (!event) { + hdd_err("response is NULL"); + return; + } + + request = osif_request_get(cookie); + if (!request) { + hdd_debug("Obsolete request"); + return; + } + + context = osif_request_priv(request); + context->event = *event; + osif_request_complete(request); + osif_request_put(request); + + hdd_exit(); +} + +static uint32_t hdd_sar_get_response_len(const struct sar_limit_event *event) +{ + uint32_t len; + uint32_t row_len; + + len = NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE */ + len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS */ + len += NLA_HDRLEN + sizeof(u32); + + /* nest */ + row_len = NLA_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND */ + row_len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN */ + row_len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION */ + row_len += NLA_HDRLEN + sizeof(u32); + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT */ + row_len += NLA_HDRLEN + sizeof(u32); + + /* QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC */ + len += NLA_HDRLEN + (row_len * event->num_limit_rows); + + return len; +} + +static int hdd_sar_fill_response(struct sk_buff *skb, + const struct sar_limit_event *event) +{ + int errno; + u32 value; + u32 attr; + struct nlattr *nla_spec_attr; + struct nlattr *nla_row_attr; + uint32_t row; + const struct sar_limit_event_row *event_row; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE; + value = hdd_sar_wmi_to_nl_enable(event->sar_enable); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS; + value = event->num_limit_rows; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC; + nla_spec_attr = nla_nest_start(skb, attr); + if (!nla_spec_attr) + return -EINVAL; + + for (row = 0, event_row = event->sar_limit_row; + row < event->num_limit_rows; + row++, event_row++) { + nla_row_attr = nla_nest_start(skb, attr); + if (!nla_row_attr) + return -EINVAL; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND; + value = hdd_sar_wmi_to_nl_band(event_row->band_id); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN; + value = event_row->chain_id; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION; + value = hdd_sar_wmi_to_nl_modulation(event_row->mod_id); + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT; + value = event_row->limit_value; + errno = nla_put_u32(skb, attr, value); + if (errno) + return errno; + + nla_nest_end(skb, nla_row_attr); + } + nla_nest_end(skb, nla_spec_attr); + + return 0; +} + +static int hdd_sar_send_response(struct wiphy *wiphy, + const struct sar_limit_event *event) +{ + uint32_t len; + struct sk_buff *skb; + int errno; + + len = hdd_sar_get_response_len(event); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + errno = hdd_sar_fill_response(skb, event); + if (errno) { + wlan_cfg80211_vendor_free_skb(skb); + return errno; + } + + return wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * __wlan_hdd_get_sar_power_limits() - Get SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to retrieve Specific Absorption Rate limit specs. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct osif_request *request; + struct hdd_sar_context *context; + mac_handle_t mac_handle; + void *cookie; + QDF_STATUS status; + int ret; + static const struct osif_request_params params = { + .priv_size = sizeof(*context), + .timeout_ms = WLAN_WAIT_TIME_SAR, + }; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + + mac_handle = hdd_ctx->mac_handle; + status = sme_get_sar_power_limits(mac_handle, hdd_sar_cb, cookie); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Unable to post sar message"); + ret = -EINVAL; + goto cleanup; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Target response timed out"); + goto cleanup; + } + + context = osif_request_priv(request); + ret = hdd_sar_send_response(wiphy, &context->event); + +cleanup: + osif_request_put(request); + + return ret; +} + +/** + * hdd_to_nl_sar_version - Map SAR version enum from hdd to nl + * @hdd_sar_version: Current SAR version stored in hdd_ctx + * + * This function is used to map SAR version enum stored in hdd_ctx to + * nl + * + * Return - NL SAR version + */ +static u32 hdd_to_nl_sar_version(enum sar_version hdd_sar_version) +{ + switch (hdd_sar_version) { + case (SAR_VERSION_1): + return QCA_WLAN_VENDOR_SAR_VERSION_1; + case (SAR_VERSION_2): + return QCA_WLAN_VENDOR_SAR_VERSION_2; + case (SAR_VERSION_3): + return QCA_WLAN_VENDOR_SAR_VERSION_3; + case (SAR_VERSION_4): + return QCA_WLAN_VENDOR_SAR_VERSION_4; + case (SAR_VERSION_5): + return QCA_WLAN_VENDOR_SAR_VERSION_5; + case (SAR_VERSION_6): + return QCA_WLAN_VENDOR_SAR_VERSION_1; + default: + hdd_err("Unexpected SAR version received :%u, sending default to userspace", + hdd_sar_version); + return QCA_WLAN_VENDOR_SAR_VERSION_1; + } +} + +/** + * hdd_sar_fill_capability_response - Fill SAR capability + * @skb: Pointer to socket buffer + * @hdd_ctx: pointer to hdd context + * + * This function fills SAR Capability in the socket buffer + * + * Return - 0 on success, negative errno on failure + */ +static int hdd_sar_fill_capability_response(struct sk_buff *skb, + struct hdd_context *hdd_ctx) +{ + int errno; + u32 attr; + u32 value; + + attr = QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION; + value = hdd_to_nl_sar_version(hdd_ctx->sar_version); + + hdd_debug("Sending SAR Version = %u to userspace, fw_sar_version: %d", + value, hdd_ctx->sar_version); + + errno = nla_put_u32(skb, attr, value); + + return errno; +} + +/** + * hdd_sar_send_capability_response - Send SAR capability response + * @wiphy: Pointer to wireless phy + * @hdd_ctx: Pointer to hdd context + * + * This function sends SAR capability. + */ +static int hdd_sar_send_capability_response(struct wiphy *wiphy, + struct hdd_context *hdd_ctx) +{ + uint32_t len; + struct sk_buff *skb; + int errno; + + len = NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_SAR_CAPABILITY_VERSION */ + len += NLA_HDRLEN + sizeof(u32); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + errno = hdd_sar_fill_capability_response(skb, hdd_ctx); + if (errno) { + wlan_cfg80211_vendor_free_skb(skb); + return errno; + } + + return wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * __wlan_hdd_get_sar_capability - Get SAR Capabilities + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to retrieve SAR Version . + * + * Return: 0 on success, negative errno on failure + */ + +static int __wlan_hdd_get_sar_capability(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + + hdd_enter(); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE || + hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) { + hdd_err("Command not allowed in FTM/MONITOR mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + ret = hdd_sar_send_capability_response(wiphy, hdd_ctx); + + return ret; +} + +#define SAR_LIMITS_SAR_ENABLE QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE +#define SAR_LIMITS_NUM_SPECS QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_NUM_SPECS +#define SAR_LIMITS_SPEC QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC +#define SAR_LIMITS_SPEC_BAND QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_BAND +#define SAR_LIMITS_SPEC_CHAIN QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_CHAIN +#define SAR_LIMITS_SPEC_MODULATION \ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION +#define SAR_LIMITS_SPEC_POWER_LIMIT \ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT +#define SAR_LIMITS_SPEC_POWER_LIMIT_INDEX \ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_POWER_LIMIT_INDEX +#define SAR_LIMITS_MAX QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + +const struct nla_policy +wlan_hdd_sar_limits_policy[SAR_LIMITS_MAX + 1] = { + [SAR_LIMITS_SAR_ENABLE] = {.type = NLA_U32}, + [SAR_LIMITS_NUM_SPECS] = {.type = NLA_U32}, + [SAR_LIMITS_SPEC] = {.type = NLA_NESTED}, + [SAR_LIMITS_SPEC_BAND] = {.type = NLA_U32}, + [SAR_LIMITS_SPEC_CHAIN] = {.type = NLA_U32}, + [SAR_LIMITS_SPEC_MODULATION] = {.type = NLA_U32}, + [SAR_LIMITS_SPEC_POWER_LIMIT] = {.type = NLA_U32}, + [SAR_LIMITS_SPEC_POWER_LIMIT_INDEX] = {.type = NLA_U32}, +}; + +void hdd_store_sar_config(struct hdd_context *hdd_ctx, + struct sar_limit_cmd_params *sar_limit_cmd) +{ + /* Free the previously stored sar_limit_cmd */ + wlan_hdd_free_sar_config(hdd_ctx); + + hdd_ctx->sar_cmd_params = sar_limit_cmd; +} + +void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx) +{ + struct sar_limit_cmd_params *sar_limit_cmd; + + if (!hdd_ctx->sar_cmd_params) + return; + + sar_limit_cmd = hdd_ctx->sar_cmd_params; + hdd_ctx->sar_cmd_params = NULL; + qdf_mem_free(sar_limit_cmd->sar_limit_row_list); + qdf_mem_free(sar_limit_cmd); +} + +/** + * wlan_hdd_cfg80211_sar_convert_limit_set() - Convert limit set value + * @nl80211_value: Vendor command attribute value + * @wmi_value: Pointer to return converted WMI return value + * + * Convert NL80211 vendor command value for SAR limit set to WMI value + * Return: 0 on success, -1 on invalid value + */ +static int wlan_hdd_cfg80211_sar_convert_limit_set(u32 nl80211_value, + u32 *wmi_value) +{ + int ret = 0; + + switch (nl80211_value) { + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE: + *wmi_value = WMI_SAR_FEATURE_OFF; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0: + *wmi_value = WMI_SAR_FEATURE_ON_SET_0; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1: + *wmi_value = WMI_SAR_FEATURE_ON_SET_1; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2: + *wmi_value = WMI_SAR_FEATURE_ON_SET_2; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3: + *wmi_value = WMI_SAR_FEATURE_ON_SET_3; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4: + *wmi_value = WMI_SAR_FEATURE_ON_SET_4; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_USER: + *wmi_value = WMI_SAR_FEATURE_ON_USER_DEFINED; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0: + *wmi_value = WMI_SAR_FEATURE_ON_SAR_V2_0; + break; + + default: + ret = -1; + } + return ret; +} + +#ifdef WLAN_FEATURE_SARV1_TO_SARV2 +/** + * hdd_convert_sarv1_to_sarv2() - convert SAR V1 BDF reference to SAR V2 + * @hdd_ctx: The HDD global context + * @tb: The parsed array of netlink attributes + * @sar_limit_cmd: The WMI command to be filled + * + * This feature/function is designed to solve the following problem: + * 1) Userspace application was written to use SARv1 BDF entries + * 2) Product is configured with SAR V2 BDF entries + * + * So if this feature is enabled, and if the firmware is configured + * with SAR V2 support, and if the incoming request is to enable a SAR + * V1 BDF entry, then the WMI command is generated to actually + * configure a SAR V2 BDF entry. + * + * Return: true if conversion was performed and @sar_limit_cmd is + * ready to be sent to firmware. Otherwise false in which case the + * normal parsing logic should be applied. + */ + +static bool +hdd_convert_sarv1_to_sarv2(struct hdd_context *hdd_ctx, + struct nlattr *tb[], + struct sar_limit_cmd_params *sar_limit_cmd) +{ + struct nlattr *attr; + uint32_t bdf_index, set; + struct sar_limit_cmd_row *row; + + hdd_enter(); + if (hdd_ctx->sar_version == SAR_VERSION_1) { + hdd_debug("SAR version: %d", hdd_ctx->sar_version); + return false; + } + + attr = tb[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE]; + if (!attr) + return false; + + bdf_index = nla_get_u32(attr); + + if ((bdf_index >= QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0) && + (bdf_index <= QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4)) { + set = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0; + } else if (bdf_index == QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE) { + set = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE; + bdf_index = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0; + } else { + return false; + } + + /* Need two rows to hold the per-chain V2 power index + * To disable SARv2 limit, send chain, num_limits_row and + * power limit set to 0 (except power index 0xff) + */ + row = qdf_mem_malloc(2 * sizeof(*row)); + if (!row) + return false; + + if (wlan_hdd_cfg80211_sar_convert_limit_set( + set, &sar_limit_cmd->sar_enable)) { + hdd_err("Failed to convert SAR limit to WMI value"); + return false; + } + + sar_limit_cmd->commit_limits = 1; + sar_limit_cmd->num_limit_rows = 2; + sar_limit_cmd->sar_limit_row_list = row; + row[0].limit_value = bdf_index; + row[1].limit_value = row[0].limit_value; + row[0].chain_id = 0; + row[1].chain_id = 1; + row[0].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK; + row[1].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK; + + hdd_exit(); + return true; +} + +#else /* WLAN_FEATURE_SARV1_TO_SARV2 */ +static bool +hdd_convert_sarv1_to_sarv2(struct hdd_context *hdd_ctx, + struct nlattr *tb[], + struct sar_limit_cmd_params *sar_limit_cmd) +{ + return false; +} + +#endif /* WLAN_FEATURE_SARV1_TO_SARV2 */ + +/** + * wlan_hdd_cfg80211_sar_convert_band() - Convert WLAN band value + * @nl80211_value: Vendor command attribute value + * @wmi_value: Pointer to return converted WMI return value + * + * Convert NL80211 vendor command value for SAR BAND to WMI value + * Return: 0 on success, -1 on invalid value + */ +static int wlan_hdd_cfg80211_sar_convert_band(u32 nl80211_value, u32 *wmi_value) +{ + int ret = 0; + + switch (nl80211_value) { + case HDD_NL80211_BAND_2GHZ: + *wmi_value = WMI_SAR_2G_ID; + break; + case HDD_NL80211_BAND_5GHZ: + *wmi_value = WMI_SAR_5G_ID; + break; + default: + ret = -1; + } + return ret; +} + +/** + * wlan_hdd_cfg80211_sar_convert_modulation() - Convert WLAN modulation value + * @nl80211_value: Vendor command attribute value + * @wmi_value: Pointer to return converted WMI return value + * + * Convert NL80211 vendor command value for SAR Modulation to WMI value + * Return: 0 on success, -1 on invalid value + */ +static int wlan_hdd_cfg80211_sar_convert_modulation(u32 nl80211_value, + u32 *wmi_value) +{ + int ret = 0; + + switch (nl80211_value) { + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_CCK: + *wmi_value = WMI_SAR_MOD_CCK; + break; + case QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SPEC_MODULATION_OFDM: + *wmi_value = WMI_SAR_MOD_OFDM; + break; + default: + ret = -1; + } + return ret; +} + +/** + * hdd_extract_sar_nested_attrs() - Extract nested SAR attribute + * @spec: nested nla attribute + * @row: output to hold extract nested attribute + * + * This function extracts nested SAR attribute one at a time which means + * for each nested attribute this has to be invoked from + * __wlan_hdd_set_sar_power_limits(). + * + * Return: On success - 0 + * On Failure - Negative value + */ +static int hdd_extract_sar_nested_attrs(struct nlattr *spec[], + struct sar_limit_cmd_row *row) +{ + uint32_t limit; + uint32_t band; + uint32_t modulation; + int ret; + + row->validity_bitmap = 0; + + if (spec[SAR_LIMITS_SPEC_POWER_LIMIT]) { + limit = nla_get_u32(spec[SAR_LIMITS_SPEC_POWER_LIMIT]); + row->limit_value = limit; + } else if (spec[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]) { + limit = nla_get_u32(spec[SAR_LIMITS_SPEC_POWER_LIMIT_INDEX]); + row->limit_value = limit; + } else { + hdd_err("SAR Spec does not have power limit or index value"); + return -EINVAL; + } + + if (spec[SAR_LIMITS_SPEC_BAND]) { + band = nla_get_u32(spec[SAR_LIMITS_SPEC_BAND]); + ret = wlan_hdd_cfg80211_sar_convert_band(band, &row->band_id); + if (ret) { + hdd_err("Invalid SAR Band attr"); + return ret; + } + + row->validity_bitmap |= WMI_SAR_BAND_ID_VALID_MASK; + } + + if (spec[SAR_LIMITS_SPEC_CHAIN]) { + row->chain_id = nla_get_u32(spec[SAR_LIMITS_SPEC_CHAIN]); + row->validity_bitmap |= WMI_SAR_CHAIN_ID_VALID_MASK; + } + + if (spec[SAR_LIMITS_SPEC_MODULATION]) { + modulation = nla_get_u32(spec[SAR_LIMITS_SPEC_MODULATION]); + ret = wlan_hdd_cfg80211_sar_convert_modulation(modulation, + &row->mod_id); + if (ret) { + hdd_err("Invalid SAR Modulation attr"); + return ret; + } + + row->validity_bitmap |= WMI_SAR_MOD_ID_VALID_MASK; + } + + return 0; +} + +/** + * __wlan_hdd_set_sar_power_limits() - Set SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * This function is used to setup Specific Absorption Rate limit specs. + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_set_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *spec[SAR_LIMITS_MAX + 1]; + struct nlattr *tb[SAR_LIMITS_MAX + 1]; + struct nlattr *spec_list; + struct sar_limit_cmd_params *sar_limit_cmd; + int ret = -EINVAL, i = 0, rem = 0; + QDF_STATUS status; + uint32_t num_limit_rows = 0; + struct sar_limit_cmd_row *row; + uint32_t sar_enable; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, SAR_LIMITS_MAX, data, data_len, + wlan_hdd_sar_limits_policy)) { + hdd_err("Invalid SAR attributes"); + return -EINVAL; + } + + if (tb[SAR_LIMITS_SAR_ENABLE]) { + sar_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]); + + if ((sar_enable >= + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0 && + sar_enable <= + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF4) && + hdd_ctx->sar_version != SAR_VERSION_1 && + !hdd_ctx->config->enable_sar_conversion) { + hdd_err("SARV1 to SARV2 is disabled from ini"); + return -EINVAL; + } else if (sar_enable == + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_V2_0 && + hdd_ctx->sar_version == SAR_VERSION_1) { + hdd_err("FW expects SARV1 given command is SARV2"); + return -EINVAL; + } + } + + sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params)); + if (!sar_limit_cmd) + return -ENOMEM; + + wlan_hdd_sar_timers_reset(hdd_ctx); + + /* is special SAR V1 => SAR V2 logic enabled and applicable? */ + if (hdd_ctx->config->enable_sar_conversion && + (hdd_convert_sarv1_to_sarv2(hdd_ctx, tb, sar_limit_cmd))) + goto send_sar_limits; + + /* Vendor command manadates all SAR Specs in single call */ + sar_limit_cmd->commit_limits = 1; + sar_limit_cmd->sar_enable = WMI_SAR_FEATURE_NO_CHANGE; + if (tb[SAR_LIMITS_SAR_ENABLE]) { + uint32_t *sar_ptr = &sar_limit_cmd->sar_enable; + + sar_enable = nla_get_u32(tb[SAR_LIMITS_SAR_ENABLE]); + ret = wlan_hdd_cfg80211_sar_convert_limit_set(sar_enable, + sar_ptr); + if (ret) { + hdd_err("Invalid SAR Enable attr"); + goto fail; + } + } + + hdd_debug("attr sar sar_enable %d", sar_limit_cmd->sar_enable); + + if (tb[SAR_LIMITS_NUM_SPECS]) { + num_limit_rows = nla_get_u32(tb[SAR_LIMITS_NUM_SPECS]); + hdd_debug("attr sar num_limit_rows %u", num_limit_rows); + } + + if (num_limit_rows > MAX_SAR_LIMIT_ROWS_SUPPORTED) { + hdd_err("SAR Spec list exceed supported size"); + goto fail; + } + + if (num_limit_rows == 0) + goto send_sar_limits; + + row = qdf_mem_malloc(sizeof(*row) * num_limit_rows); + if (!row) + goto fail; + + sar_limit_cmd->num_limit_rows = num_limit_rows; + sar_limit_cmd->sar_limit_row_list = row; + + if (!tb[SAR_LIMITS_SPEC]) { + hdd_err("Invalid SAR specification list"); + goto fail; + } + + nla_for_each_nested(spec_list, tb[SAR_LIMITS_SPEC], rem) { + if (i == num_limit_rows) { + hdd_warn("SAR Cmd has excess SPECs in list"); + break; + } + + if (wlan_cfg80211_nla_parse(spec, + SAR_LIMITS_MAX, + nla_data(spec_list), + nla_len(spec_list), + wlan_hdd_sar_limits_policy)) { + hdd_err("nla_parse failed for SAR Spec list"); + goto fail; + } + + ret = hdd_extract_sar_nested_attrs(spec, row); + if (ret) { + hdd_err("Failed to extract SAR nested attrs"); + goto fail; + } + + hdd_debug("Spec_ID: %d, Band: %d Chain: %d Mod: %d POW_Limit: %d Validity_Bitmap: %d", + i, row->band_id, row->chain_id, row->mod_id, + row->limit_value, row->validity_bitmap); + + i++; + row++; + } + + if (i < sar_limit_cmd->num_limit_rows) { + hdd_warn("SAR Cmd has less SPECs in list"); + sar_limit_cmd->num_limit_rows = i; + } + +send_sar_limits: + status = sme_set_sar_power_limits(hdd_ctx->mac_handle, sar_limit_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set sar power limits"); + goto fail; + } + + /* After SSR, the SAR configuration is lost. As SSR is hidden from + * userland, this command will not come from userspace after a SSR. To + * restore this configuration, save this in hdd context and restore + * after re-init. + */ + hdd_store_sar_config(hdd_ctx, sar_limit_cmd); + return 0; + +fail: + if (sar_limit_cmd) { + qdf_mem_free(sar_limit_cmd->sar_limit_row_list); + qdf_mem_free(sar_limit_cmd); + } + + return ret; +} + +#undef SAR_LIMITS_SAR_ENABLE +#undef SAR_LIMITS_NUM_SPECS +#undef SAR_LIMITS_SPEC +#undef SAR_LIMITS_SPEC_BAND +#undef SAR_LIMITS_SPEC_CHAIN +#undef SAR_LIMITS_SPEC_MODULATION +#undef SAR_LIMITS_SPEC_POWER_LIMIT +#undef SAR_LIMITS_SPEC_POWER_LIMIT_INDEX +#undef SAR_LIMITS_MAX + +int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_set_sar_power_limits(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_get_sar_power_limits(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +/** + * wlan_hdd_cfg80211_get_sar_capability() - Get SAR capability + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_get_sar_capability() + * + * Return: 0 on success, negative errno on failure + */ + +int wlan_hdd_cfg80211_get_sar_capability(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_get_sar_capability(wiphy, wdev, data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +#ifdef SAR_SAFETY_FEATURE +void hdd_disable_sar(struct hdd_context *hdd_ctx) +{ + struct sar_limit_cmd_params *sar_limit_cmd; + struct sar_limit_cmd_row *row; + QDF_STATUS status; + + if (hdd_ctx->sar_version == SAR_VERSION_1) { + hdd_nofl_debug("FW SAR version: %d", hdd_ctx->sar_version); + return; + } + + sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params)); + if (!sar_limit_cmd) + return; + + /* + * Need two rows to hold the per-chain V2 power index + */ + row = qdf_mem_malloc(2 * sizeof(*row)); + if (!row) + goto config_sar_failed; + + sar_limit_cmd->sar_enable = WMI_SAR_FEATURE_OFF; + sar_limit_cmd->commit_limits = 1; + sar_limit_cmd->num_limit_rows = 2; + sar_limit_cmd->sar_limit_row_list = row; + row[0].limit_value = 0; + row[1].limit_value = 0; + row[0].chain_id = 0; + row[1].chain_id = 1; + row[0].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK; + row[1].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK; + + hdd_nofl_debug("Disable the SAR limit index for both the chains"); + + status = sme_set_sar_power_limits(hdd_ctx->mac_handle, sar_limit_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_nofl_err("Failed to set sar power limits"); + goto config_sar_failed; + } + + /* After SSR, the SAR configuration is lost. As SSR is hidden from + * userland, this command will not come from userspace after a SSR. To + * restore this configuration, save this in hdd context and restore + * after re-init. + */ + hdd_store_sar_config(hdd_ctx, sar_limit_cmd); + return; + +config_sar_failed: + + if (sar_limit_cmd) { + qdf_mem_free(sar_limit_cmd->sar_limit_row_list); + qdf_mem_free(sar_limit_cmd); + } +} + +void hdd_configure_sar_index(struct hdd_context *hdd_ctx, uint32_t sar_index) +{ + struct sar_limit_cmd_params *sar_limit_cmd; + struct sar_limit_cmd_row *row; + QDF_STATUS status; + + if (hdd_ctx->sar_version == SAR_VERSION_1) { + hdd_nofl_debug("FW SAR version: %d", hdd_ctx->sar_version); + return; + } + + sar_limit_cmd = qdf_mem_malloc(sizeof(struct sar_limit_cmd_params)); + if (!sar_limit_cmd) + return; + + /* + * Need two rows to hold the per-chain V2 power index + */ + row = qdf_mem_malloc(2 * sizeof(*row)); + if (!row) + goto config_sar_failed; + + sar_limit_cmd->sar_enable = WMI_SAR_FEATURE_ON_SAR_V2_0; + sar_limit_cmd->commit_limits = 1; + sar_limit_cmd->num_limit_rows = 2; + sar_limit_cmd->sar_limit_row_list = row; + row[0].limit_value = sar_index; + row[1].limit_value = sar_index; + row[0].chain_id = 0; + row[1].chain_id = 1; + row[0].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK; + row[1].validity_bitmap = WMI_SAR_CHAIN_ID_VALID_MASK; + + hdd_nofl_debug("Configure POW_Limit Index: %d for both the chains", + row->limit_value); + + status = sme_set_sar_power_limits(hdd_ctx->mac_handle, sar_limit_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_nofl_err("Failed to set sar power limits"); + goto config_sar_failed; + } + + /* + * After SSR, the SAR configuration is lost. As SSR is hidden from + * userland, this command will not come from userspace after a SSR. To + * restore this configuration, save this in hdd context and restore + * after re-init. + */ + hdd_store_sar_config(hdd_ctx, sar_limit_cmd); + return; + +config_sar_failed: + + if (sar_limit_cmd) { + qdf_mem_free(sar_limit_cmd->sar_limit_row_list); + qdf_mem_free(sar_limit_cmd); + } +} + +void hdd_configure_sar_sleep_index(struct hdd_context *hdd_ctx) +{ + if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER)) + return; + + if (hdd_ctx->config->config_sar_safety_sleep_index) { + hdd_nofl_debug("Configure SAR sleep index %d", + hdd_ctx->config->sar_safety_sleep_index); + hdd_configure_sar_index( + hdd_ctx, + hdd_ctx->config->sar_safety_sleep_index); + } else { + hdd_nofl_debug("Disable SAR"); + hdd_disable_sar(hdd_ctx); + } +} + +void hdd_configure_sar_resume_index(struct hdd_context *hdd_ctx) +{ + if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER)) + return; + + hdd_nofl_debug("Configure SAR safety index %d on wlan resume", + hdd_ctx->config->sar_safety_index); + hdd_configure_sar_index(hdd_ctx, + hdd_ctx->config->sar_safety_index); +} + +static void hdd_send_sar_unsolicited_event(struct hdd_context *hdd_ctx) +{ + struct sk_buff *vendor_event; + uint32_t len; + + if (!hdd_ctx) { + hdd_err_rl("hdd context is null"); + return; + } + + len = NLMSG_HDRLEN; + vendor_event = + wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, len, + QCA_NL80211_VENDOR_SUBCMD_REQUEST_SAR_LIMITS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +static void hdd_sar_unsolicited_work_cb(void *user_data) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)user_data; + uint8_t i = 0; + QDF_STATUS status; + int errno; + struct osif_psoc_sync *psoc_sync; + + hdd_nofl_debug("Sar unsolicited timer expired"); + + errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + + if (errno == -EAGAIN) { + hdd_nofl_debug("rescheduling sar unsolicited work"); + status = qdf_delayed_work_create(&hdd_ctx->sar_safety_unsolicited_work, + hdd_sar_unsolicited_work_cb, + hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to create sar safety unsolicited work"); + return; + } else if (errno) { + hdd_err("cannot handle sar unsolicited work"); + return; + } + + qdf_atomic_set(&hdd_ctx->sar_safety_req_resp_event_in_progress, 1); + + for (i = 0; i < hdd_ctx->config->sar_safety_req_resp_retry; i++) { + qdf_event_reset(&hdd_ctx->sar_safety_req_resp_event); + hdd_send_sar_unsolicited_event(hdd_ctx); + status = qdf_wait_for_event_completion( + &hdd_ctx->sar_safety_req_resp_event, + hdd_ctx->config->sar_safety_req_resp_timeout); + if (QDF_IS_STATUS_SUCCESS(status)) + break; + } + qdf_atomic_set(&hdd_ctx->sar_safety_req_resp_event_in_progress, 0); + + if (i >= hdd_ctx->config->sar_safety_req_resp_retry) + hdd_configure_sar_index(hdd_ctx, + hdd_ctx->config->sar_safety_index); + + osif_psoc_sync_op_stop(psoc_sync); +} + +static void hdd_sar_safety_timer_cb(void *user_data) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)user_data; + + hdd_nofl_debug("Sar safety timer expires"); + hdd_configure_sar_index(hdd_ctx, hdd_ctx->config->sar_safety_index); +} + +void wlan_hdd_sar_unsolicited_timer_start(struct hdd_context *hdd_ctx) +{ + if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER)) + return; + + if (qdf_atomic_read( + &hdd_ctx->sar_safety_req_resp_event_in_progress) > 0) + return; + + qdf_delayed_work_start(&hdd_ctx->sar_safety_unsolicited_work, + hdd_ctx->config->sar_safety_unsolicited_timeout); + + hdd_nofl_debug("sar safety unsolicited work started"); +} + +void wlan_hdd_sar_timers_reset(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER)) + return; + + if (hdd_ctx->sar_version == SAR_VERSION_1) + return; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->sar_safety_timer)) { + status = qdf_mc_timer_stop(&hdd_ctx->sar_safety_timer); + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_nofl_debug("sar safety timer stopped"); + } + + status = qdf_mc_timer_start(&hdd_ctx->sar_safety_timer, + hdd_ctx->config->sar_safety_timeout); + if (QDF_IS_STATUS_SUCCESS(status)) + hdd_nofl_debug("sar safety timer started"); + + qdf_event_set(&hdd_ctx->sar_safety_req_resp_event); + + qdf_delayed_work_stop_sync(&hdd_ctx->sar_safety_unsolicited_work); + hdd_nofl_debug("sar safety unsolicited work stopped"); + +} + +void wlan_hdd_sar_timers_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER)) + return; + + hdd_enter(); + + qdf_mc_timer_init(&hdd_ctx->sar_safety_timer, QDF_TIMER_TYPE_SW, + hdd_sar_safety_timer_cb, hdd_ctx); + + status = qdf_delayed_work_create(&hdd_ctx->sar_safety_unsolicited_work, + hdd_sar_unsolicited_work_cb, + hdd_ctx); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to create sar safety unsolicited work"); + goto hdd_exit; + } + + qdf_atomic_init(&hdd_ctx->sar_safety_req_resp_event_in_progress); + qdf_event_create(&hdd_ctx->sar_safety_req_resp_event); + +hdd_exit: + hdd_exit(); +} + +void wlan_hdd_sar_timers_deinit(struct hdd_context *hdd_ctx) +{ + if (!(hdd_ctx->config->enable_sar_safety & SAR_SAFETY_ENABLED_TIMER)) + return; + + hdd_enter(); + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&hdd_ctx->sar_safety_timer)) + qdf_mc_timer_stop(&hdd_ctx->sar_safety_timer); + + qdf_mc_timer_destroy(&hdd_ctx->sar_safety_timer); + + qdf_delayed_work_destroy(&hdd_ctx->sar_safety_unsolicited_work); + + qdf_event_destroy(&hdd_ctx->sar_safety_req_resp_event); + + hdd_exit(); +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sar_limits.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sar_limits.h new file mode 100644 index 0000000000..9243a34227 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sar_limits.h @@ -0,0 +1,269 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_SAR_LIMITS_H +#define __WLAN_HDD_SAR_LIMITS_H + +/** + * DOC: wlan_hdd_sar_limits_h + * + * WLAN Host Device Driver SAR limits API specification + */ + +#if defined(FEATURE_SAR_LIMITS) && defined(SAR_SAFETY_FEATURE) +/** + * wlan_hdd_sar_unsolicited_timer_start() - Start SAR unsolicited timer + * @hdd_ctx: Pointer to HDD context + * + * This function checks the state of the sar unsolicited timer, if the + * sar_unsolicited_timer is not running, it starts the timer. + * + * Return: None + */ +void wlan_hdd_sar_unsolicited_timer_start(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_sar_timers_reset() - Reset SAR timers + * @hdd_ctx: Pointer to HDD context + * + * This function checks the state of the sar safety timer, if the + * sar_safety_timer is not running, it starts the timer else it stops + * the timer and start the timer again. + * + * Return: None + */ +void wlan_hdd_sar_timers_reset(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_sar_timers_init() - Initialize SAR timers + * @hdd_ctx: Pointer to HDD context + * + * This function initializes sar timers. + * Return: None + */ +void wlan_hdd_sar_timers_init(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_sar_timers_deinit() - De-initialize SAR timers + * @hdd_ctx: Pointer to HDD context + * + * This function de-initializes sar timers. + * Return: None + */ +void wlan_hdd_sar_timers_deinit(struct hdd_context *hdd_ctx); + +/** + * hdd_configure_sar_index() - configures SAR index to the FW + * @hdd_ctx: Pointer to HDD context + * @sar_index: sar index which needs to be configured to FW + * + * This function configures SAR power index on both the chains + * for SAR version2 + * + * Return: None + */ +void hdd_configure_sar_index(struct hdd_context *hdd_ctx, uint32_t sar_index); + +/** + * hdd_disable_sar() - Disable SAR feature to FW + * @hdd_ctx: Pointer to HDD context + * + * This function Disables SAR power index on both the chains + * + * Return: None + */ +void hdd_disable_sar(struct hdd_context *hdd_ctx); + +/** + * hdd_configure_sar_sleep_index() - Configure SAR sleep index to FW + * @hdd_ctx: Pointer to HDD context + * + * This function configures SAR sleep index on both the chains + * + * Return: None + */ +void hdd_configure_sar_sleep_index(struct hdd_context *hdd_ctx); + +/** + * hdd_configure_sar_resume_index() - Configure SAR resume index to FW + * @hdd_ctx: Pointer to HDD context + * + * This function configures SAR resume index on both the chains + * + * Return: None + */ +void hdd_configure_sar_resume_index(struct hdd_context *hdd_ctx); + +#else +static inline void wlan_hdd_sar_unsolicited_timer_start( + struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_sar_timers_reset(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_sar_timers_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_sar_timers_deinit(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_configure_sar_index(struct hdd_context *hdd_ctx, + uint32_t sar_index) +{ +} + +static inline void hdd_disable_sar(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_configure_sar_sleep_index(struct hdd_context *hdd_ctx) +{ +} + +static inline void hdd_configure_sar_resume_index(struct hdd_context *hdd_ctx) +{ +} + +#endif + +#ifdef FEATURE_SAR_LIMITS +/** + * wlan_hdd_cfg80211_get_sar_power_limits() - Get SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_get_sar_power_limits() + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_get_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_set_sar_power_limits() - Set SAR power limits + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_cfg80211_set_sar_power_limits() + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_set_sar_power_limits(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +/** + * wlan_hdd_cfg80211_get_sar_capability() - Get SAR capability + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Wrapper function of __wlan_hdd_get_sar_capability() + * + * Return: 0 on success, negative errno on failure + */ + +int wlan_hdd_cfg80211_get_sar_capability(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +/** + * hdd_store_sar_config() - Store SAR config in HDD context + * @hdd_ctx: The HDD context + * @sar_limit_cmd: The sar_limit_cmd_params struct to save + * + * After SSR, the SAR configuration is lost. As SSR is hidden from + * userland, this command will not come from userspace after a SSR. To + * restore this configuration, save this in hdd context and restore + * after re-init. + * + * Return: None + */ +void hdd_store_sar_config(struct hdd_context *hdd_ctx, + struct sar_limit_cmd_params *sar_limit_cmd); + +/** + * wlan_hdd_free_sar_config() - Free the resources allocated while storing + * SAR config + * @hdd_ctx: HDD context + * + * The driver stores the SAR config values in HDD context so that it can be + * restored in the case SSR is invoked. Free those resources. + * + * Return: None + */ +void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx); + +extern const struct nla_policy +wlan_hdd_sar_limits_policy[QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX + 1]; + +#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_LIMITS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_sar_power_limits, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_sar_power_limits, \ + vendor_command_policy(wlan_hdd_sar_limits_policy, \ + QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_SAR_CAPABILITY, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_sar_capability, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, +#else /* FEATURE_SAR_LIMITS */ +#define FEATURE_SAR_LIMITS_VENDOR_COMMANDS +static inline +void hdd_store_sar_config(struct hdd_context *hdd_ctx, + struct sar_limit_cmd_params *sar_limit_cmd) +{ +} + +static inline void wlan_hdd_free_sar_config(struct hdd_context *hdd_ctx) +{ +} + +#endif /* FEATURE_SAR_LIMITS */ + +#endif /* __WLAN_HDD_SAR_LIMITS_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c new file mode 100644 index 0000000000..977a72f03e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_scan.c @@ -0,0 +1,1605 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_scan.c + * + * WLAN Host Device Driver scan implementation + */ + +#include +#include + +#include "wlan_hdd_includes.h" +#include "cds_api.h" +#include "cds_api.h" +#include "ani_global.h" +#include "dot11f.h" +#include "cds_sched.h" +#include "osif_sync.h" +#include "wlan_hdd_p2p.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_scan.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_power.h" +#include "wma_api.h" +#include "cds_utils.h" +#include "wlan_p2p_ucfg_api.h" +#include "cfg_ucfg_api.h" + +#include +#include +#include "wlan_utility.h" +#include "wlan_hdd_object_manager.h" +#include "nan_ucfg_api.h" + +#define SCAN_DONE_EVENT_BUF_SIZE 4096 +#define RATE_MASK 0x7f + +/** + * hdd_vendor_scan_callback() - Scan completed callback event + * @adapter: HDD adapter + * @req: Scan request + * @aborted: true scan aborted false scan success + * + * This function sends scan completed callback event to NL. + * + * Return: none + */ +static void hdd_vendor_scan_callback(struct hdd_adapter *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter); + struct sk_buff *skb; + struct nlattr *attr; + int i; + uint8_t scan_status; + uint64_t cookie; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_SCAN_DONE_INDEX; + + hdd_enter(); + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid adapter magic"); + qdf_mem_free(req); + return; + } + skb = wlan_cfg80211_vendor_event_alloc(hddctx->wiphy, &adapter->wdev, + SCAN_DONE_EVENT_BUF_SIZE + + 4 + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!skb) { + hdd_err("skb alloc failed"); + qdf_mem_free(req); + return; + } + + cookie = (uintptr_t)req; + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_ssids; i++) { + if (nla_put(skb, i, req->ssids[i].ssid_len, + req->ssids[i].ssid)) { + hdd_err("Failed to add ssid"); + goto nla_put_failure; + } + } + nla_nest_end(skb, attr); + attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES); + if (!attr) + goto nla_put_failure; + for (i = 0; i < req->n_channels; i++) { + if (nla_put_u32(skb, i, req->channels[i]->center_freq)) { + hdd_err("Failed to add channel"); + goto nla_put_failure; + } + } + nla_nest_end(skb, attr); + + if (req->ie && + nla_put(skb, QCA_WLAN_VENDOR_ATTR_SCAN_IE, req->ie_len, + req->ie)) { + hdd_err("Failed to add scan ie"); + goto nla_put_failure; + } + if (req->flags && + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS, req->flags)) { + hdd_err("Failed to add scan flags"); + goto nla_put_failure; + } + if (hdd_wlan_nla_put_u64(skb, + QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) { + hdd_err("Failed to add scan cookie"); + goto nla_put_failure; + } + scan_status = (aborted == true) ? VENDOR_SCAN_STATUS_ABORTED : + VENDOR_SCAN_STATUS_NEW_RESULTS; + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_SCAN_STATUS, scan_status)) { + hdd_err("Failed to add scan status"); + goto nla_put_failure; + } + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + hdd_info("scan complete event sent to NL"); + qdf_mem_free(req); + return; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + qdf_mem_free(req); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +/** + * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211 + * @adapter: Pointer to the adapter + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void hdd_cfg80211_scan_done(struct hdd_adapter *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + struct cfg80211_scan_info info = { + .aborted = aborted + }; + + if (adapter->dev->flags & IFF_UP) + cfg80211_scan_done(req, &info); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +/** + * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211 + * @adapter: Pointer to the adapter + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void hdd_cfg80211_scan_done(struct hdd_adapter *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + if (adapter->dev->flags & IFF_UP) + cfg80211_scan_done(req, aborted); +} +#else +/** + * hdd_cfg80211_scan_done() - Scan completed callback to cfg80211 + * @adapter: Pointer to the adapter + * @req : Scan request + * @aborted : true scan aborted false scan success + * + * This function notifies scan done to cfg80211 + * + * Return: none + */ +static void hdd_cfg80211_scan_done(struct hdd_adapter *adapter, + struct cfg80211_scan_request *req, + bool aborted) +{ + cfg80211_scan_done(req, aborted); +} +#endif + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * wlan_hdd_sap_skip_scan_check() - The function will check OBSS + * scan skip or not for SAP. + * @hdd_ctx: pointer to hdd context. + * @request: pointer to scan request. + * + * This function will check the scan request's chan list against the + * previous ACS scan chan list. If all the chan are covered by + * previous ACS scan, we can skip the scan and return scan complete + * to save the SAP starting time. + * + * Return: true to skip the scan, + * false to continue the scan + */ +static bool wlan_hdd_sap_skip_scan_check(struct hdd_context *hdd_ctx, + struct cfg80211_scan_request *request) +{ + int i, j; + bool skip; + + hdd_debug("HDD_ACS_SKIP_STATUS = %d", + hdd_ctx->skip_acs_scan_status); + if (hdd_ctx->skip_acs_scan_status != eSAP_SKIP_ACS_SCAN) + return false; + qdf_spin_lock(&hdd_ctx->acs_skip_lock); + if (!hdd_ctx->last_acs_freq_list || + hdd_ctx->num_of_channels == 0 || + request->n_channels == 0) { + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + return false; + } + skip = true; + for (i = 0; i < request->n_channels ; i++) { + bool find = false; + + for (j = 0; j < hdd_ctx->num_of_channels; j++) { + if (hdd_ctx->last_acs_freq_list[j] == + request->channels[i]->center_freq) { + find = true; + break; + } + } + if (!find) { + skip = false; + hdd_debug("Freq %d isn't in ACS freq list", + request->channels[i]->center_freq); + break; + } + } + qdf_spin_unlock(&hdd_ctx->acs_skip_lock); + return skip; +} +#else +static bool wlan_hdd_sap_skip_scan_check(struct hdd_context *hdd_ctx, + struct cfg80211_scan_request *request) +{ + return false; +} +#endif + +void wlan_hdd_cfg80211_scan_block(struct hdd_adapter *adapter) +{ + struct cfg80211_scan_request *request; + struct scan_req *blocked_scan_req; + qdf_list_node_t *node; + + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("HDD adapter context is invalid"); + return; + } + + qdf_mutex_acquire(&adapter->blocked_scan_request_q_lock); + + while (!qdf_list_empty(&adapter->blocked_scan_request_q)) { + qdf_list_remove_front(&adapter->blocked_scan_request_q, + &node); + blocked_scan_req = qdf_container_of(node, struct scan_req, + node); + request = blocked_scan_req->scan_request; + request->n_ssids = 0; + request->n_channels = 0; + if (blocked_scan_req->source == NL_SCAN) { + hdd_err("Scan aborted. Null result sent"); + hdd_cfg80211_scan_done(adapter, request, true); + } else { + hdd_err("Vendor scan aborted. Null result sent"); + hdd_vendor_scan_callback(adapter, request, true); + } + qdf_mem_free(blocked_scan_req); + } + + qdf_mutex_release(&adapter->blocked_scan_request_q_lock); +} + +void hdd_init_scan_reject_params(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx) { + hdd_ctx->last_scan_reject_timestamp = 0; + hdd_ctx->last_scan_reject_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + hdd_ctx->last_scan_reject_reason = 0; + hdd_ctx->scan_reject_cnt = 0; + } +} + +/* + * wlan_hdd_update_scan_ies() - API to update the scan IEs of scan request + * with already stored default scan IEs + * + * @adapter: Pointer to HDD adapter + * @scan_info: Pointer to scan info in HDD adapter + * @scan_ie: Pointer to scan IE in scan request + * @scan_ie_len: Pointer to scan IE length in scan request + * + * Return: 0 on success; error number otherwise + */ +static int wlan_hdd_update_scan_ies(struct hdd_adapter *adapter, + struct hdd_scan_info *scan_info, uint8_t *scan_ie, + uint16_t *scan_ie_len) +{ + uint16_t rem_len = scan_info->default_scan_ies_len; + uint8_t *temp_ie = scan_info->default_scan_ies; + uint8_t *current_ie; + const uint8_t *mbo_ie; + uint8_t elem_id; + uint16_t elem_len; + bool add_ie = false; + + if (!scan_info->default_scan_ies_len || !scan_info->default_scan_ies) + return 0; + + mbo_ie = wlan_get_vendor_ie_ptr_from_oui(MBO_OUI_TYPE, + MBO_OUI_TYPE_SIZE, scan_ie, + *scan_ie_len); + while (rem_len >= 2) { + current_ie = temp_ie; + elem_id = *temp_ie++; + elem_len = *temp_ie++; + rem_len -= 2; + + if (elem_len > rem_len) { + hdd_err("Invalid element len %d for elem %d", elem_len, + elem_id); + return 0; + } + + switch (elem_id) { + case DOT11F_EID_EXTCAP: + if (!wlan_get_ie_ptr_from_eid(DOT11F_EID_EXTCAP, + scan_ie, *scan_ie_len)) + add_ie = true; + break; + case WLAN_ELEMID_VENDOR: + /* Donot add MBO IE if its already present */ + if ((!mbo_ie && + 0 == qdf_mem_cmp(&temp_ie[0], MBO_OUI_TYPE, + MBO_OUI_TYPE_SIZE)) || + (0 == qdf_mem_cmp(&temp_ie[0], QCN_OUI_TYPE, + QCN_OUI_TYPE_SIZE))) + add_ie = true; + break; + } + + if (add_ie && (((*scan_ie_len) + elem_len) > + SIR_MAC_MAX_ADD_IE_LENGTH)){ + hdd_err("Not enough buffer to save default scan IE's"); + return 0; + } + + if (add_ie) { + qdf_mem_copy(scan_ie + (*scan_ie_len), + current_ie, elem_len + 2); + (*scan_ie_len) += (elem_len + 2); + add_ie = false; + } + + temp_ie += elem_len; + rem_len -= elem_len; + } + return 0; +} + +static int +wlan_hdd_enqueue_blocked_scan_request(struct net_device *dev, + struct cfg80211_scan_request *request, + uint8_t source) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct scan_req *blocked_scan_req = + qdf_mem_malloc(sizeof(*blocked_scan_req)); + int ret = 0; + + if (!blocked_scan_req) + return -EINVAL; + + blocked_scan_req->dev = dev; + blocked_scan_req->scan_request = request; + blocked_scan_req->source = source; + blocked_scan_req->scan_id = 0; + + qdf_mutex_acquire(&adapter->blocked_scan_request_q_lock); + if (qdf_list_size(&adapter->blocked_scan_request_q) < + WLAN_MAX_SCAN_COUNT) + qdf_list_insert_back(&adapter->blocked_scan_request_q, + &blocked_scan_req->node); + else + ret = -EINVAL; + qdf_mutex_release(&adapter->blocked_scan_request_q_lock); + + if (ret) { + hdd_err("Maximum number of block scan request reached!"); + qdf_mem_free(blocked_scan_req); + } + + return ret; +} + +/* Define short name to use in cds_trigger_recovery */ +#define SCAN_FAILURE QDF_SCAN_ATTEMPT_FAILURES + +/** + * __wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @request: Pointer to scan request + * @source: scan request source(NL/Vendor scan) + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to receive scan results + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + uint8_t source) +{ + struct net_device *dev = request->wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int status; + struct hdd_scan_info *scan_info = NULL; + struct hdd_adapter *con_sap_adapter; + struct hdd_ap_ctx *ap_ctx; + qdf_freq_t con_dfs_ch_freq; + uint8_t curr_vdev_id; + enum scan_reject_states curr_reason; + static uint32_t scan_ebusy_cnt; + struct scan_params params = {0}; + bool self_recovery; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS qdf_status; + bool enable_connected_scan; + enum phy_ch_width con_dfs_ch_width; + + if (cds_is_fw_down()) { + hdd_err("firmware is down, scan cmd cannot be processed"); + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_SCAN, + adapter->deflink->vdev_id, request->n_channels); + + if (!sme_is_session_id_valid(hdd_ctx->mac_handle, + adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_status = ucfg_mlme_get_self_recovery(hdd_ctx->psoc, &self_recovery); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("Failed to get self recovery ini config"); + return -EIO; + } + + enable_connected_scan = ucfg_scan_is_connected_scan_enabled( + hdd_ctx->psoc); + if (!enable_connected_scan && + hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_info("enable_connected_scan is false, Aborting scan"); + if (wlan_hdd_enqueue_blocked_scan_request(dev, request, source)) + return -EAGAIN; + schedule_work(&adapter->scan_block_work); + return 0; + } + + /* + * NDI and monitor mode don't need scan from userspace to establish + * connection and it does not support scan request either. + */ + if (QDF_NDI_MODE == adapter->device_mode || + QDF_MONITOR_MODE == adapter->device_mode) { + hdd_err("Scan not supported for %s", + qdf_opmode_str(adapter->device_mode)); + return -EINVAL; + } + + scan_info = &adapter->scan_info; + + /* Block All Scan during DFS operation and send null scan result */ + + con_sap_adapter = hdd_get_con_sap_adapter(adapter, true); + if (con_sap_adapter) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(con_sap_adapter->deflink); + con_dfs_ch_freq = ap_ctx->sap_config.chan_freq; + con_dfs_ch_width = ap_ctx->sap_config.ch_params.ch_width; + if (con_dfs_ch_freq == AUTO_CHANNEL_SELECT) + con_dfs_ch_freq = ap_ctx->operating_chan_freq; + + if (!policy_mgr_is_hw_dbs_capable(hdd_ctx->psoc) && + !policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + hdd_ctx->psoc) && + (wlan_reg_is_dfs_for_freq(hdd_ctx->pdev, con_dfs_ch_freq) || + (wlan_reg_is_5ghz_ch_freq(con_dfs_ch_freq) && + con_dfs_ch_width == CH_WIDTH_160MHZ))) { + /* Provide empty scan result during DFS operation since + * scanning not supported during DFS. Reason is + * following case: + * DFS is supported only in SCC for MBSSID Mode. + * We shall not return EBUSY or ENOTSUPP as when Primary + * AP is operating in DFS channel and secondary AP is + * started. Though we force SCC in driver, the hostapd + * issues obss scan before starting secAP. This results + * in MCC in DFS mode. Thus we return null scan result. + * If we return scan failure hostapd fails secondary AP + * startup. + */ + hdd_err("##In DFS Master mode. Scan aborted"); + if (wlan_hdd_enqueue_blocked_scan_request(dev, request, + source)) + return -EAGAIN; + schedule_work(&adapter->scan_block_work); + return 0; + } + } + + /* Check if scan is allowed at this point of time */ + if (hdd_is_connection_in_progress(&curr_vdev_id, &curr_reason)) { + scan_ebusy_cnt++; + hdd_err_rl("Scan not allowed. scan_ebusy_cnt: %d Session %d Reason %d", + scan_ebusy_cnt, curr_vdev_id, curr_reason); + if (hdd_ctx->last_scan_reject_vdev_id != curr_vdev_id || + hdd_ctx->last_scan_reject_reason != curr_reason || + !hdd_ctx->last_scan_reject_timestamp) { + hdd_ctx->last_scan_reject_vdev_id = curr_vdev_id; + hdd_ctx->last_scan_reject_reason = curr_reason; + hdd_ctx->last_scan_reject_timestamp = jiffies + + msecs_to_jiffies(SCAN_REJECT_THRESHOLD_TIME); + hdd_ctx->scan_reject_cnt = 0; + } else { + hdd_ctx->scan_reject_cnt++; + if ((hdd_ctx->scan_reject_cnt >= + SCAN_REJECT_THRESHOLD) && + qdf_system_time_after(jiffies, + hdd_ctx->last_scan_reject_timestamp)) { + hdd_err("scan reject threshold reached Session %d Reason %d count %d reject timestamp %lu jiffies %lu", + curr_vdev_id, curr_reason, + hdd_ctx->scan_reject_cnt, + hdd_ctx->last_scan_reject_timestamp, + jiffies); + hdd_ctx->last_scan_reject_timestamp = 0; + hdd_ctx->scan_reject_cnt = 0; + if (cds_is_fatal_event_enabled()) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + false, + self_recovery); + } else { + hdd_err("Triggering SSR due to scan stuck"); + cds_trigger_recovery(SCAN_FAILURE); + } + } + } + return -EBUSY; + } + + hdd_init_scan_reject_params(hdd_ctx); + + /* Check whether SAP scan can be skipped or not */ + if (adapter->device_mode == QDF_SAP_MODE && + wlan_hdd_sap_skip_scan_check(hdd_ctx, request)) { + hdd_debug("sap scan skipped"); + if (wlan_hdd_enqueue_blocked_scan_request(dev, request, source)) + return -EAGAIN; + schedule_work(&adapter->scan_block_work); + return 0; + } + + params.source = source; + params.default_ie.len = 0; + /* Store the Scan IE's in Adapter*/ + if (request->ie_len) { + if (request->ie_len > SIR_MAC_MAX_ADD_IE_LENGTH) { + hdd_debug("Invalid ie_len: %zu", request->ie_len); + return -EINVAL; + } + + /* save this for future association (join requires this) */ + memset(&scan_info->scan_add_ie, 0, sizeof(scan_info->scan_add_ie)); + memcpy(scan_info->scan_add_ie.addIEdata, request->ie, + request->ie_len); + scan_info->scan_add_ie.length = request->ie_len; + + wlan_hdd_update_scan_ies(adapter, scan_info, + scan_info->scan_add_ie.addIEdata, + &scan_info->scan_add_ie.length); + } else { + if (scan_info->default_scan_ies && + scan_info->default_scan_ies_len) { + qdf_mem_copy(scan_info->scan_add_ie.addIEdata, + scan_info->default_scan_ies, + scan_info->default_scan_ies_len); + scan_info->scan_add_ie.length = + scan_info->default_scan_ies_len; + params.default_ie.ptr = + qdf_mem_malloc(scan_info->default_scan_ies_len); + if (params.default_ie.ptr) { + qdf_mem_copy(params.default_ie.ptr, + scan_info->default_scan_ies, + scan_info->default_scan_ies_len); + params.default_ie.len = + scan_info->default_scan_ies_len; + } + } + } + + if (QDF_P2P_CLIENT_MODE == adapter->device_mode || + QDF_P2P_DEVICE_MODE == adapter->device_mode) { + /* Disable NAN Discovery if enabled */ + ucfg_nan_disable_concurrency(hdd_ctx->psoc); + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID); + if (!vdev) { + status = -EINVAL; + goto error; + } + + if ((request->n_ssids == 1) && (request->ssids) && + (request->ssids[0].ssid_len > 7) && + !qdf_mem_cmp(&request->ssids[0], "DIRECT-", 7)) + ucfg_p2p_status_scan(vdev); + + /* If this a scan on SAP adapter, use scan priority high */ + if (adapter->device_mode == QDF_SAP_MODE) + params.priority = SCAN_PRIORITY_HIGH; + else + /* Use default scan priority */ + params.priority = SCAN_PRIORITY_COUNT; + + status = ucfg_mlme_get_scan_probe_unicast_ra( + hdd_ctx->psoc, + ¶ms.scan_probe_unicast_ra); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to get unicast probe req ra cfg"); + + params.mld_id = ucfg_mlme_get_eht_mld_id(hdd_ctx->psoc); + hdd_debug("MLD ID: %d", params.mld_id); + + status = wlan_cfg80211_scan(vdev, request, ¶ms); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID); +error: + if (params.default_ie.ptr) + qdf_mem_free(params.default_ie.ptr); + + return status; +} + +#undef SCAN_FAILURE + +/** + * wlan_hdd_cfg80211_scan() - API to process cfg80211 scan request + * @wiphy: Pointer to wiphy + * @request: Pointer to scan request + * + * This API responds to scan trigger and update cfg80211 scan database + * later, scan dump command can be used to receive scan results + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(request->wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_scan(wiphy, request, NL_SCAN); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_get_rates() -API to get the rates from scan request + * @wiphy: Pointer to wiphy + * @band: Band + * @rates: array of rates + * @rate_count: number of rates + * + * Return: o for failure, rate bitmap for success + */ +static uint32_t wlan_hdd_get_rates(struct wiphy *wiphy, + enum nl80211_band band, + const u8 *rates, unsigned int rate_count) +{ + uint32_t j, count, rate_bitmap = 0; + uint32_t rate; + bool found; + + for (count = 0; count < rate_count; count++) { + rate = ((rates[count]) & RATE_MASK) * 5; + found = false; + for (j = 0; j < wiphy->bands[band]->n_bitrates; j++) { + if (wiphy->bands[band]->bitrates[j].bitrate == rate) { + found = true; + rate_bitmap |= (1 << j); + break; + } + } + if (!found) + return 0; + } + return rate_bitmap; +} + +/** + * wlan_hdd_send_scan_start_event() -API to send the scan start event + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @cookie: scan identifier + * + * Return: return 0 on success and negative error code on failure + */ +static int wlan_hdd_send_scan_start_event(struct wiphy *wiphy, + struct wireless_dev *wdev, uint64_t cookie) +{ + struct sk_buff *skb; + int ret; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_SCAN_INDEX; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, sizeof(u64) + + NLA_HDRLEN + NLMSG_HDRLEN); + if (!skb) { + hdd_err(" reply skb alloc failed"); + return -ENOMEM; + } + + if (hdd_wlan_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + ret = wlan_cfg80211_vendor_cmd_reply(skb); + + /* Send a scan started event to supplicant */ + skb = wlan_cfg80211_vendor_event_alloc(wiphy, wdev, + sizeof(u64) + 4 + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!skb) { + hdd_err("skb alloc failed"); + return -ENOMEM; + } + + if (hdd_wlan_nla_put_u64(skb, QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE, + cookie)) { + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + return ret; +} + +/** + * wlan_hdd_copy_bssid() - API to copy the bssid to vendor Scan request + * @request: Pointer to vendor scan request + * @bssid: Pointer to BSSID + * + * This API copies the specific BSSID received from Supplicant and copies it to + * the vendor Scan request + * + * Return: None + */ +#if defined(CFG80211_SCAN_BSSID) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static inline void wlan_hdd_copy_bssid(struct cfg80211_scan_request *request, + uint8_t *bssid) +{ + qdf_mem_copy(request->bssid, bssid, QDF_MAC_ADDR_SIZE); +} +#else +static inline void wlan_hdd_copy_bssid(struct cfg80211_scan_request *request, + uint8_t *bssid) +{ +} +#endif + +static void hdd_process_vendor_acs_response(struct hdd_adapter *adapter) +{ + qdf_mc_timer_t *vendor_acs_timer; + + if (!test_bit(VENDOR_ACS_RESPONSE_PENDING, + &adapter->deflink->link_flags)) { + return; + } + + vendor_acs_timer = &adapter->deflink->session.ap.vendor_acs_timer; + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(vendor_acs_timer)) { + qdf_mc_timer_stop(vendor_acs_timer); + } +} + +#if defined(CFG80211_SCAN_RANDOM_MAC_ADDR) || \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0)) +/** + * wlan_hdd_vendor_scan_random_attr() - check and fill scan randomization attrs + * @wiphy: Pointer to wiphy + * @request: Pointer to scan request + * @adapter: Pointer to hdd adapter + * @tb: Pointer to nl attributes + * + * This function is invoked to check whether vendor scan needs + * probe req source addr, if so populates mac_addr and mac_addr_mask + * in scan request with nl attrs. + * + * Return: 0 - on success, negative value on failure + */ +static int wlan_hdd_vendor_scan_random_attr(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + struct hdd_adapter *adapter, + struct nlattr **tb) +{ + uint32_t i; + int32_t len = QDF_MAC_ADDR_SIZE; + + if (!(request->flags & NL80211_SCAN_FLAG_RANDOM_ADDR)) + return 0; + + if (!(wiphy->features & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR) || + (hdd_cm_is_vdev_connected(adapter->deflink))) { + hdd_err("SCAN RANDOMIZATION not supported"); + return -EOPNOTSUPP; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC] && + !tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]) { + qdf_mem_zero(request->mac_addr, len); + qdf_mem_zero(request->mac_addr_mask, len); + request->mac_addr[0] = 0x2; + request->mac_addr_mask[0] = 0x3; + + return 0; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC] || + !tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]) + return -EINVAL; + + if ((nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC]) != len) || + (nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]) != len)) + return -EINVAL; + + qdf_mem_copy(request->mac_addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC]), len); + + qdf_mem_copy(request->mac_addr_mask, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK]), len); + + /* avoid configure on multicast address */ + if (!cds_is_group_addr(request->mac_addr_mask) || + cds_is_group_addr(request->mac_addr)) + return -EINVAL; + + for (i = 0; i < ETH_ALEN; i++) + request->mac_addr[i] &= request->mac_addr_mask[i]; + + return 0; +} +#else +static int wlan_hdd_vendor_scan_random_attr(struct wiphy *wiphy, + struct cfg80211_scan_request *request, + struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return 0; +} +#endif + +const +struct nla_policy scan_policy[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE] = {.type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_SCAN_COOKIE] = {.type = NLA_U64}, + [QCA_WLAN_VENDOR_ATTR_SCAN_IE] = {.type = NLA_BINARY, + .len = MAX_DEFAULT_SCAN_IE_LEN}, + [QCA_WLAN_VENDOR_ATTR_SCAN_MAC] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_SCAN_MAC_MASK] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES] = {.type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS] = {.type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES] = {.type = NLA_NESTED}, + [QCA_WLAN_VENDOR_ATTR_SCAN_BSSID] = {.type = NLA_BINARY}, +}; + +/** + * __wlan_hdd_cfg80211_vendor_scan() - API to process venor scan request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * API to process venor scan request. + * + * Return: return 0 on success and negative error code on failure + */ +static int __wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + struct cfg80211_scan_request *request = NULL; + struct nlattr *attr; + enum nl80211_band band; + uint32_t n_channels = 0, n_ssid = 0; + uint32_t count, j; + int tmp; + size_t len, ie_len = 0; + struct ieee80211_channel *chan; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + int ret; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + /* + * During SSR, if -EBUSY is returned then OBSS vendor scan is + * not issued immediately. + */ + if (ret == -EAGAIN) + return -EBUSY; + + return ret; + } + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_SCAN_MAX, + data, data_len, scan_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], tmp) + n_channels++; + } else { + for (band = 0; band < HDD_NUM_NL80211_BANDS; band++) + if (wiphy->bands[band]) + n_channels += wiphy->bands[band]->n_channels; + } + + if (n_channels > NUM_CHANNELS) { + hdd_err("Exceed max number of channels: %d", n_channels); + return -EINVAL; + } + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], tmp) + n_ssid++; + + if (MAX_SCAN_SSID < n_ssid) { + hdd_err("Exceed max number of SSID: %d", n_ssid); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]) + ie_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE]); + + len = sizeof(*request) + (sizeof(*request->ssids) * n_ssid) + + (sizeof(*request->channels) * n_channels) + ie_len; + + request = qdf_mem_malloc(len); + if (!request) + goto error; + if (n_ssid) + request->ssids = (void *)&request->channels[n_channels]; + request->n_ssids = n_ssid; + if (ie_len) { + if (request->ssids) + request->ie = (void *)(request->ssids + n_ssid); + else + request->ie = (void *)(request->channels + n_channels); + } + + request->ie_len = ie_len; + count = 0; + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_FREQUENCIES], + tmp) { + if (nla_len(attr) != sizeof(uint32_t)) { + hdd_err("len is not correct for frequency %d", + count); + goto error; + } + chan = ieee80211_get_channel(wiphy, nla_get_u32(attr)); + if (!chan) + goto error; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[count] = chan; + count++; + } + } else { + for (band = 0; band < HDD_NUM_NL80211_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + for (j = 0; j < wiphy->bands[band]->n_channels; + j++) { + chan = &wiphy->bands[band]->channels[j]; + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + request->channels[count] = chan; + count++; + } + } + } + + if (!count) + goto error; + + request->n_channels = count; + count = 0; + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS]) { + int ssid_length; + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_SCAN_SSIDS], + tmp) { + ssid_length = nla_len(attr); + if ((ssid_length > WLAN_SSID_MAX_LEN) || + (ssid_length < 0)) { + hdd_err("SSID Len %d is not correct for network %d", + ssid_length, count); + goto error; + } + + request->ssids[count].ssid_len = ssid_length; + memcpy(request->ssids[count].ssid, nla_data(attr), + ssid_length); + count++; + } + } + + if (ie_len) + nla_memcpy((void *)request->ie, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_IE], ie_len); + + for (count = 0; count < HDD_NUM_NL80211_BANDS; count++) + if (wiphy->bands[count]) + request->rates[count] = + (1 << wiphy->bands[count]->n_bitrates) - 1; + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES]) { + nla_for_each_nested(attr, + tb[QCA_WLAN_VENDOR_ATTR_SCAN_SUPP_RATES], + tmp) { + band = nla_type(attr); + if (band >= HDD_NUM_NL80211_BANDS) + continue; + if (!wiphy->bands[band]) + continue; + request->rates[band] = + wlan_hdd_get_rates(wiphy, + band, nla_data(attr), + nla_len(attr)); + } + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]) { + request->flags = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SCAN_FLAGS]); + if ((request->flags & NL80211_SCAN_FLAG_LOW_PRIORITY) && + !(wiphy->features & NL80211_FEATURE_LOW_PRIORITY_SCAN)) { + hdd_err("LOW PRIORITY SCAN not supported"); + goto error; + } + + if (wlan_hdd_vendor_scan_random_attr(wiphy, request, + adapter, tb)) + goto error; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]) { + if (nla_len(tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID]) < + QDF_MAC_ADDR_SIZE) { + hdd_err("invalid bssid length"); + goto error; + } + wlan_hdd_copy_bssid(request, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SCAN_BSSID])); + } + + /* Check if external acs was requested on this adapter */ + hdd_process_vendor_acs_response(adapter); + + if (tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]) + request->no_cck = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_SCAN_TX_NO_CCK_RATE]); + request->wdev = wdev; + request->wiphy = wiphy; + request->scan_start = jiffies; + + ret = __wlan_hdd_cfg80211_scan(wiphy, request, VENDOR_SCAN); + if (0 != ret) { + hdd_err("Scan Failed. Ret = %d", ret); + qdf_mem_free(request); + return ret; + } + ret = wlan_hdd_send_scan_start_event(wiphy, wdev, (uintptr_t)request); + + return ret; +error: + hdd_err("Scan Request Failed"); + qdf_mem_free(request); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_vendor_scan() -API to process venor scan request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device + * @data: Pointer to the data + * @data_len: length of the data + * + * This is called from userspace to request scan. + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_vendor_scan(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_vendor_abort_scan() - API to process vendor command for + * abort scan + * @wiphy: Pointer to wiphy + * @data: Pointer to the data + * @data_len: length of the data + * + * API to process vendor abort scan + * + * Return: zero for success and non zero for failure + */ +static int __wlan_hdd_vendor_abort_scan( + struct wiphy *wiphy, const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + wlan_vendor_abort_scan(hdd_ctx->pdev, data, data_len); + + return ret; +} + +/** + * wlan_hdd_vendor_abort_scan() - API to process vendor command for + * abort scan + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * This is called from supplicant to abort scan + * + * Return: zero for success and non zero for failure + */ +int wlan_hdd_vendor_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_vendor_abort_scan(wiphy, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int wlan_hdd_scan_abort(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + wlan_abort_scan(hdd_ctx->pdev, INVAL_PDEV_ID, + link_info->vdev_id, INVALID_SCAN_ID, true); + + return 0; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/** + * __wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * @request: Pointer to cfg80211 scheduled scan start request + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct + cfg80211_sched_scan_request + *request) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + int ret; + bool pno_offload_enabled; + uint8_t scan_backoff_multiplier; + bool enable_connected_scan; + enum QDF_GLOBAL_MODE curr_mode; + + curr_mode = hdd_get_conparam(); + + if (QDF_GLOBAL_FTM_MODE == curr_mode || + QDF_GLOBAL_MONITOR_MODE == curr_mode) { + hdd_err_rl("Command not allowed in FTM/Monitor mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_info("Sched scans only supported on STA ifaces"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + pno_offload_enabled = ucfg_scan_is_pno_offload_enabled(hdd_ctx->psoc); + if (!pno_offload_enabled) { + hdd_debug("Pno Offload is not enabled"); + return -EINVAL; + } + + enable_connected_scan = ucfg_scan_is_connected_scan_enabled( + hdd_ctx->psoc); + if (!enable_connected_scan && + hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_info("enable_connected_scan is false, Aborting scan"); + return -EBUSY; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID); + if (!vdev) + return -EINVAL; + + scan_backoff_multiplier = + ucfg_get_scan_backoff_multiplier(hdd_ctx->psoc); + ret = wlan_cfg80211_sched_scan_start(vdev, request, + scan_backoff_multiplier); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID); + + return ret; +} + +/** + * wlan_hdd_cfg80211_sched_scan_start() - cfg80211 scheduled scan(pno) start + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * @request: Pointer to cfg80211 scheduled scan start request + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request + *request) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_sched_scan_start(wiphy, dev, request); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int wlan_hdd_sched_scan_stop(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + int ret; + bool pno_offload_enabled; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("HDD context is Null"); + return -EINVAL; + } + + pno_offload_enabled = ucfg_scan_is_pno_offload_enabled(hdd_ctx->psoc); + if (!pno_offload_enabled) { + hdd_debug("PnoOffload is not enabled!!!"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_SCAN_ID); + if (!vdev) + return -EINVAL; + ret = wlan_cfg80211_sched_scan_stop(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SCAN_ID); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled scan(pno) + * @dev: Pointer network device + * + * This is a wrapper around wlan_hdd_sched_scan_stop() that returns success + * in the event that the driver is currently recovering or unloading. This + * prevents a race condition where we get a scan stop from kernel during + * a driver unload from PLD. + * + * Return: 0 for success, non zero for failure + */ +static int __wlan_hdd_cfg80211_sched_scan_stop(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int errno; + enum QDF_GLOBAL_MODE curr_mode; + + curr_mode = hdd_get_conparam(); + + if (QDF_GLOBAL_FTM_MODE == curr_mode || + QDF_GLOBAL_MONITOR_MODE == curr_mode) { + hdd_err_rl("Command not allowed in FTM/Monitor mode"); + return -EINVAL; + } + + /* The return 0 is intentional when Recovery and Load/Unload in + * progress. We did observe a crash due to a return of + * failure in sched_scan_stop , especially for a case where the unload + * of the happens at the same time. The function + * __cfg80211_stop_sched_scan was clearing rdev->sched_scan_req only + * when the sched_scan_stop returns success. If it returns a failure , + * then its next invocation due to the clean up of the second interface + * will have the dev pointer corresponding to the first one leading to + * a crash. + */ + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_info("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + return 0; + } + + if (cds_is_load_or_unload_in_progress()) { + hdd_info("Unload/Load in Progress, state: 0x%x. Ignore!!!", + cds_get_driver_state()); + return 0; + } + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_info("Sched scans only supported on STA ifaces"); + return -EINVAL; + } + + errno = wlan_hdd_validate_context(WLAN_HDD_GET_CTX(adapter)); + if (errno) + return errno; + + errno = wlan_hdd_sched_scan_stop(dev); + + return errno; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_sched_scan_stop(dev); + + osif_vdev_sync_op_stop(vdev_sync); + + /* The return 0 is intentional. We observed a crash due to a return of + * failure in sched_scan_stop , especially for a case where the unload + * of the happens at the same time. The function + * __cfg80211_stop_sched_scan was clearing rdev->sched_scan_req only + * when the sched_scan_stop returns success. If it returns a failure , + * then its next invocation due to the clean up of the second interface + * will have the dev pointer corresponding to the first one leading to + * a crash. + */ + return 0; +} +#else +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev, + uint64_t reqid) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_sched_scan_stop(dev); + + osif_vdev_sync_op_stop(vdev_sync); + + /* The return 0 is intentional. We observed a crash due to a return of + * failure in sched_scan_stop , especially for a case where the unload + * of the happens at the same time. The function + * __cfg80211_stop_sched_scan was clearing rdev->sched_scan_req only + * when the sched_scan_stop returns success. If it returns a failure , + * then its next invocation due to the clean up of the second interface + * will have the dev pointer corresponding to the first one leading to + * a crash. + */ + return 0; +} +#endif /* KERNEL_VERSION(4, 12, 0) */ +#endif /*FEATURE_WLAN_SCAN_PNO */ + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) +/** + * __wlan_hdd_cfg80211_abort_scan() - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * This function is used to abort an ongoing scan + * + * Return: None + */ +static void __wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + wlan_cfg80211_abort_scan(hdd_ctx->pdev); + + hdd_exit(); +} + +/** + * wlan_hdd_cfg80211_abort_scan - cfg80211 abort scan api + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wireless device structure + * + * Wrapper to __wlan_hdd_cfg80211_abort_scan() - + * function is used to abort an ongoing scan + * + * Return: None + */ +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return; + + __wlan_hdd_cfg80211_abort_scan(wiphy, wdev); + + osif_psoc_sync_op_stop(psoc_sync); +} +#endif + +/** + * hdd_scan_context_destroy() - Destroy scan context + * @hdd_ctx: HDD context. + * + * Destroy scan context. + * + * Return: None. + */ +void hdd_scan_context_destroy(struct hdd_context *hdd_ctx) +{ +} + +/** + * hdd_scan_context_init() - Initialize scan context + * @hdd_ctx: HDD context. + * + * Initialize scan related resources like spin lock and lists. + * + * Return: 0 on success and errno on failure. + */ +int hdd_scan_context_init(struct hdd_context *hdd_ctx) +{ + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h new file mode 100644 index 0000000000..328c3194ac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_scan.h @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_scan.h + * + * WLAN Host Device Driver scan related implementation + * + */ + +#if !defined(WLAN_HDD_SCAN_H) +#define WLAN_HDD_SCAN_H + +#include "wlan_hdd_main.h" +#include "csr_inside_api.h" +#include +#include "qca_vendor.h" + +extern const struct nla_policy scan_policy[ + QCA_WLAN_VENDOR_ATTR_SCAN_MAX + 1]; + +#define FEATURE_TRIGGER_SCAN_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TRIGGER_SCAN, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_vendor_scan, \ + vendor_command_policy(scan_policy, \ + QCA_WLAN_VENDOR_ATTR_SCAN_MAX) \ +}, + +#define EXTSCAN_PARAM_MAX QCA_WLAN_VENDOR_ATTR_EXTSCAN_SUBCMD_CONFIG_PARAM_MAX + +int hdd_scan_context_init(struct hdd_context *hdd_ctx); +void hdd_scan_context_destroy(struct hdd_context *hdd_ctx); + +int wlan_hdd_cfg80211_scan(struct wiphy *wiphy, + struct cfg80211_scan_request *request); + +#ifdef FEATURE_WLAN_SCAN_PNO +int wlan_hdd_cfg80211_sched_scan_start(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_sched_scan_request + *request); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 12, 0) +/** + * wlan_hdd_cfg80211_sched_scan_stop() - stop cfg80211 scheduled (PNO) scan + * @wiphy: Pointer to wiphy + * @dev: Pointer network device + * + * Note, this returns success if the driver is recovering or unloading to + * prevent race conditions between PLD initiating an unload and kernel + * initiating a scheduled scan stop via cfg80211. Unload is expected to stop + * any pending scheduled scans in this case. + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev); +#else +int wlan_hdd_cfg80211_sched_scan_stop(struct wiphy *wiphy, + struct net_device *dev, + uint64_t reqid); + +#endif /* KERNEL_VERSION(4, 12, 0) */ + +/** + * wlan_hdd_sched_scan_stop() - stop scheduled (PNO) scans + * @dev: Pointer network device + * + * Return: 0 for success, non zero for failure + */ +int wlan_hdd_sched_scan_stop(struct net_device *dev); +#else +static inline int wlan_hdd_sched_scan_stop(struct net_device *dev) +{ + return 0; +} +#endif /* End of FEATURE_WLAN_SCAN_PNO */ + +int wlan_hdd_cfg80211_vendor_scan(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, + int data_len); + +/** + * wlan_hdd_vendor_abort_scan() - API to process vendor command for + * abort scan + * @wiphy: Pointer to wiphy + * @wdev: Pointer to net device + * @data : Pointer to the data + * @data_len : length of the data + * + * This is called from supplicant to abort scan + * + * Return: zero for success and non zero for failure. + */ +int wlan_hdd_vendor_abort_scan( + struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)) || \ + defined(CFG80211_ABORT_SCAN) +void wlan_hdd_cfg80211_abort_scan(struct wiphy *wiphy, + struct wireless_dev *wdev); +#endif + +/** + * hdd_init_scan_reject_params() - init scan reject params + * @hdd_ctx: hdd contxt + * + * Return: None + */ +void hdd_init_scan_reject_params(struct hdd_context *hdd_ctx); + +/** + * wlan_hdd_cfg80211_scan_block() - scan block handler + * @adapter: HDD adapter to work against + * + * Return: none + */ +void wlan_hdd_cfg80211_scan_block(struct hdd_adapter *adapter); + +#ifdef FEATURE_WLAN_EXTSCAN +extern const struct nla_policy +wlan_hdd_extscan_config_policy[EXTSCAN_PARAM_MAX + 1]; +extern const struct nla_policy +wlan_hdd_pno_config_policy[QCA_WLAN_VENDOR_ATTR_PNO_MAX + 1]; + +#define FEATURE_EXTSCAN_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_START, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_start, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_STOP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_stop, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CAPABILITIES, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_get_capabilities, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_GET_CACHED_RESULTS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_get_cached_results, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_BSSID_HOTLIST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_set_bssid_hotlist, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_BSSID_HOTLIST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_reset_bssid_hotlist, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_SET_SIGNIFICANT_CHANGE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_set_significant_change, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_RESET_SIGNIFICANT_CHANGE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_extscan_reset_significant_change, \ + vendor_command_policy(wlan_hdd_extscan_config_policy, \ + EXTSCAN_PARAM_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_LIST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_epno_list, \ + vendor_command_policy(wlan_hdd_pno_config_policy, \ + QCA_WLAN_VENDOR_ATTR_PNO_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_SET_PASSPOINT_LIST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_passpoint_list, \ + vendor_command_policy(wlan_hdd_pno_config_policy, \ + QCA_WLAN_VENDOR_ATTR_PNO_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_EXTSCAN_PNO_RESET_PASSPOINT_LIST, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_reset_passpoint_list, \ + vendor_command_policy(wlan_hdd_pno_config_policy, \ + QCA_WLAN_VENDOR_ATTR_PNO_MAX) \ +}, +#else +#define FEATURE_EXTSCAN_VENDOR_COMMANDS +#endif /* FEATURE_WLAN_EXTSCAN */ + +#endif /* end #if !defined(WLAN_HDD_SCAN_H) */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c new file mode 100644 index 0000000000..d5aeca8119 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -0,0 +1,883 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* denote that this file does not allow legacy hddLog */ +#define HDD_DISALLOW_LEGACY_HDDLOG 1 + +/* Include files */ +#include +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_p2p_ucfg_api.h" +#include +#include "wlan_ipa_ucfg_api.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include +#include "wlan_hdd_sta_info.h" +#include "ol_defines.h" +#include +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_wds.h" +#include +#ifdef FEATURE_WDS +#include +#endif +#include +#include +#include +#include "wlan_hdd_stats.h" + +/* Preprocessor definitions and constants */ +#undef QCA_HDD_SAP_DUMP_SK_BUFF + +/* Type declarations */ +#ifdef FEATURE_WDS +/** + * struct l2_update_frame - Layer-2 update frame format + * @eh: ethernet header + * @l2_update_pdu: llc pdu format + * @l2_update_xid_info: xid command information field + */ +struct l2_update_frame { + struct ethhdr eh; + struct llc_pdu_un l2_update_pdu; + struct llc_xid_info l2_update_xid_info; +} qdf_packed; +#endif + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +void hdd_softap_tx_resume_timer_expired_handler(void *adapter_context) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) adapter_context; + + if (!adapter) { + hdd_err("NULL adapter"); + return; + } + + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); +} + +/** + * hdd_softap_tx_resume_false() - Resume OS TX Q false leads to queue disabling + * @adapter: pointer to hdd adapter + * @tx_resume: TX Q resume trigger + * + * + * Return: None + */ +static void +hdd_softap_tx_resume_false(struct hdd_adapter *adapter, bool tx_resume) +{ + QDF_STATUS status; + qdf_mc_timer_t *fc_timer; + + if (true == tx_resume) + return; + + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + fc_timer = &adapter->tx_flow_control_timer; + if (QDF_TIMER_STATE_STOPPED != qdf_mc_timer_get_current_state(fc_timer)) + return; + + status = qdf_mc_timer_start(fc_timer, + WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + adapter->deflink->hdd_stats.tx_rx_stats.txflow_timer_cnt++; +} + +void hdd_softap_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) adapter_context; + + if (!adapter) { + hdd_err("NULL adapter"); + return; + } + + /* Resume TX */ + if (true == tx_resume) { + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer)) { + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + } + + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + } + hdd_softap_tx_resume_false(adapter, tx_resume); +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifndef MDM_PLATFORM +void hdd_ipa_update_rx_mcbc_stats(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + struct hdd_station_info *hdd_sta_info; + struct qdf_mac_addr *src_mac; + qdf_ether_header_t *eh; + + src_mac = (struct qdf_mac_addr *)(skb->data + + QDF_NBUF_SRC_MAC_OFFSET); + + hdd_sta_info = hdd_get_sta_info_by_mac( + &adapter->sta_info_list, + src_mac->bytes, + STA_INFO_SOFTAP_IPA_RX_PKT_CALLBACK); + if (!hdd_sta_info) + return; + + if (qdf_nbuf_data_is_ipv4_mcast_pkt(skb->data)) + hdd_sta_info->rx_mc_bc_cnt++; + + eh = (qdf_ether_header_t *)qdf_nbuf_data(skb); + if (QDF_IS_ADDR_BROADCAST(eh->ether_dhost)) + hdd_sta_info->rx_mc_bc_cnt++; + + hdd_put_sta_info_ref(&adapter->sta_info_list, &hdd_sta_info, + true, STA_INFO_SOFTAP_IPA_RX_PKT_CALLBACK); +} +#else +void hdd_ipa_update_rx_mcbc_stats(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ +} +#endif + +/** + * __hdd_softap_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet (sk_buff) + * @dev: pointer to network device + * + * Function registered with the Linux OS for transmitting + * packets. This version of the function directly passes + * the packet to Datapath Layer. + * In case of any error, drop the packet. + * + * Return: None + */ +static void __hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + sme_ac_enum_type ac = SME_AC_BE; + struct hdd_adapter *adapter = (struct hdd_adapter *)netdev_priv(dev); + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct hdd_tx_rx_stats *stats = + &adapter->deflink->hdd_stats.tx_rx_stats; + int cpu = qdf_get_smp_processor_id(); + QDF_STATUS status; + + osif_dp_mark_pkt_type(skb); + hdd_tx_latency_record_ingress_ts(adapter, skb); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + ++stats->per_cpu[cpu].tx_classified_ac[ac]; + + status = ucfg_dp_softap_start_xmit((qdf_nbuf_t)skb, + adapter->deflink->vdev); + if (QDF_IS_STATUS_ERROR(status)) + ++stats->per_cpu[cpu].tx_dropped_ac[ac]; + + netif_trans_update(dev); + + wlan_hdd_sar_unsolicited_timer_start(hdd_ctx); +} + +netdev_tx_t hdd_softap_hard_start_xmit(struct sk_buff *skb, + struct net_device *net_dev) +{ + __hdd_softap_hard_start_xmit(skb, net_dev); + + return NETDEV_TX_OK; +} + +QDF_STATUS hdd_softap_ipa_start_xmit(qdf_nbuf_t nbuf, qdf_netdev_t dev) +{ + if (NETDEV_TX_OK == hdd_softap_hard_start_xmit( + (struct sk_buff *)nbuf, + (struct net_device *)dev)) + return QDF_STATUS_SUCCESS; + else + return QDF_STATUS_E_FAILURE; +} + +static void __hdd_softap_tx_timeout(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + struct netdev_queue *txq; + int i; + + DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_SOFTAP_TX_TIMEOUT, + QDF_TRACE_DEFAULT_PDEV_ID, + NULL, 0, QDF_TX)); + /* Getting here implies we disabled the TX queues for too + * long. Queues are disabled either because of disassociation + * or low resource scenarios. In case of disassociation it is + * ok to ignore this. But if associated, we have do possible + * recovery here + */ + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + QDF_TRACE(QDF_MODULE_ID_HDD_SAP_DATA, QDF_TRACE_LEVEL_ERROR, + "%s: Recovery in Progress. Ignore!!!", __func__); + return; + } + + if (hdd_ctx->hdd_wlan_suspended) { + hdd_debug("wlan is suspended, ignore timeout"); + return; + } + + TX_TIMEOUT_TRACE(dev, QDF_MODULE_ID_HDD_SAP_DATA); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, + QDF_TRACE_LEVEL_DEBUG, + "Queue: %d status: %d txq->trans_start: %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + wlan_hdd_display_adapter_netif_queue_history(adapter); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (vdev) { + ucfg_dp_softap_tx_timeout(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "carrier state: %d", netif_carrier_ok(dev)); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +void hdd_softap_tx_timeout(struct net_device *net_dev, unsigned int txqueue) +#else +void hdd_softap_tx_timeout(struct net_device *net_dev) +#endif +{ + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) + return; + + __hdd_softap_tx_timeout(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); +} + +static void +hdd_reset_sta_info_during_reattach(struct hdd_station_info *sta_info) +{ + sta_info->in_use = 0; + sta_info->sta_id = 0; + sta_info->sta_type = 0; + qdf_mem_zero(&sta_info->sta_mac, QDF_MAC_ADDR_SIZE); + sta_info->peer_state = 0; + sta_info->is_qos_enabled = 0; + sta_info->is_deauth_in_progress = 0; + sta_info->nss = 0; + sta_info->rate_flags = 0; + sta_info->ecsa_capable = 0; + sta_info->max_phy_rate = 0; + sta_info->tx_packets = 0; + sta_info->tx_bytes = 0; + sta_info->rx_packets = 0; + sta_info->rx_bytes = 0; + sta_info->last_tx_rx_ts = 0; + sta_info->assoc_ts = 0; + sta_info->disassoc_ts = 0; + sta_info->tx_rate = 0; + sta_info->rx_rate = 0; + sta_info->ampdu = 0; + sta_info->sgi_enable = 0; + sta_info->tx_stbc = 0; + sta_info->rx_stbc = 0; + sta_info->ch_width = 0; + sta_info->mode = 0; + sta_info->max_supp_idx = 0; + sta_info->max_ext_idx = 0; + sta_info->max_mcs_idx = 0; + sta_info->rx_mcs_map = 0; + sta_info->tx_mcs_map = 0; + sta_info->freq = 0; + sta_info->dot11_mode = 0; + sta_info->ht_present = 0; + sta_info->vht_present = 0; + qdf_mem_zero(&sta_info->ht_caps, sizeof(sta_info->ht_caps)); + qdf_mem_zero(&sta_info->vht_caps, sizeof(sta_info->vht_caps)); + sta_info->reason_code = 0; + sta_info->rssi = 0; + sta_info->dhcp_phase = 0; + sta_info->dhcp_nego_status = 0; + sta_info->capability = 0; + sta_info->support_mode = 0; + sta_info->rx_retry_cnt = 0; + sta_info->rx_mc_bc_cnt = 0; + + if (sta_info->assoc_req_ies.len) { + qdf_mem_free(sta_info->assoc_req_ies.ptr); + sta_info->assoc_req_ies.ptr = NULL; + sta_info->assoc_req_ies.len = 0; + } + + sta_info->pending_eap_frm_type = 0; +} + +/** + * hdd_sta_info_re_attach() - Re-Attach the station info structure into the list + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: The station info structure that is to be attached to the + * container object. + * @sta_mac: MAC address of the station + * + * This function re-attaches the station if it gets re-connect after + * disconnecting and before its all references are released. + * + * Return: QDF STATUS SUCCESS on successful attach, error code otherwise + */ +static QDF_STATUS hdd_sta_info_re_attach( + struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *sta_info, + struct qdf_mac_addr *sta_mac) +{ + if (!sta_info_container || !sta_info) { + hdd_err("Parameter(s) null"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + if (sta_info->is_attached) { + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + hdd_err("sta info is already attached"); + return QDF_STATUS_SUCCESS; + } + + hdd_reset_sta_info_during_reattach(sta_info); + /* Add one extra ref for reattach */ + hdd_take_sta_info_ref(sta_info_container, sta_info, false, + STA_INFO_ATTACH_DETACH); + qdf_mem_copy(&sta_info->sta_mac, sta_mac, sizeof(struct qdf_mac_addr)); + sta_info->is_attached = true; + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_softap_init_tx_rx_sta(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac) +{ + struct hdd_station_info *sta_info; + QDF_STATUS status; + + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + sta_mac->bytes, + STA_INFO_SOFTAP_INIT_TX_RX_STA); + + if (sta_info) { + hdd_err("Reinit of in use station " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_mac->bytes)); + status = hdd_sta_info_re_attach(&adapter->sta_info_list, + sta_info, sta_mac); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_INIT_TX_RX_STA); + return status; + } + + sta_info = qdf_mem_malloc(sizeof(struct hdd_station_info)); + if (!sta_info) + return QDF_STATUS_E_NOMEM; + + sta_info->is_deauth_in_progress = false; + qdf_mem_copy(&sta_info->sta_mac, sta_mac, sizeof(struct qdf_mac_addr)); + + status = hdd_sta_info_attach(&adapter->sta_info_list, sta_info); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to attach station: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_mac->bytes)); + qdf_mem_free(sta_info); + } + + return status; +} + +QDF_STATUS hdd_softap_deregister_sta(struct hdd_adapter *adapter, + struct hdd_station_info **sta_info) +{ + struct hdd_context *hdd_ctx; + struct qdf_mac_addr *mac_addr; + struct hdd_station_info *sta = *sta_info; + struct hdd_ap_ctx *ap_ctx; + struct wlan_objmgr_vdev *vdev; + + if (!adapter) { + hdd_err("NULL adapter"); + return QDF_STATUS_E_INVAL; + } + + if (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) { + hdd_err("Invalid adapter magic"); + return QDF_STATUS_E_INVAL; + } + + if (!sta) { + hdd_err("Invalid station"); + return QDF_STATUS_E_INVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx) { + hdd_err("HDD context is null"); + return QDF_STATUS_E_INVAL; + } + + /* + * If the address is a broadcast address then the CDP layers expects + * the self mac address of the adapter. + */ + if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) { + mac_addr = &adapter->mac_addr; + } else { + if (wlan_vdev_mlme_is_mlo_vdev(adapter->deflink->vdev) && + !qdf_is_macaddr_zero(&sta->mld_addr)) + mac_addr = &sta->mld_addr; + else + mac_addr = &sta->sta_mac; + } + + if (ucfg_ipa_is_enabled()) { + if (ucfg_ipa_wlan_evt(hdd_ctx->pdev, adapter->dev, + adapter->device_mode, + adapter->deflink->vdev_id, + WLAN_IPA_CLIENT_DISCONNECT, + mac_addr->bytes, + false) != QDF_STATUS_SUCCESS) + hdd_debug("WLAN_CLIENT_DISCONNECT event failed"); + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + ucfg_dp_del_latency_critical_client(vdev, sta->dot11_mode); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + if (!QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes) && + sta->dot11_mode < QCA_WLAN_802_11_MODE_INVALID) + ap_ctx->client_count[sta->dot11_mode]--; + + hdd_sta_info_detach(&adapter->sta_info_list, &sta); + + ucfg_mlme_update_oce_flags(hdd_ctx->pdev); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_softap_register_sta(struct wlan_hdd_link_info *link_info, + bool auth_required, bool privacy_required, + struct qdf_mac_addr *sta_mac, + tSap_StationAssocReassocCompleteEvent *event) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct ol_txrx_desc_type txrx_desc = {0}; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct ol_txrx_ops txrx_ops; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct hdd_ap_ctx *ap_ctx; + struct hdd_station_info *sta_info; + bool wmm_enabled = false; + enum qca_wlan_802_11_mode dot11mode = QCA_WLAN_802_11_MODE_INVALID; + bool is_macaddr_broadcast = false; + enum phy_ch_width ch_width; + struct wlan_objmgr_vdev *vdev; + + if (event) { + wmm_enabled = event->wmmEnabled; + dot11mode = hdd_convert_dot11mode_from_phymode(event->chan_info.info); + } + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + + /* + * If the address is a broadcast address, then provide the self mac addr + * to the data path. Else provide the mac address of the connected peer. + */ + if (qdf_is_macaddr_broadcast(sta_mac)) { + qdf_mem_copy(&txrx_desc.peer_addr, &adapter->mac_addr, + QDF_MAC_ADDR_SIZE); + is_macaddr_broadcast = true; + } else { + qdf_mem_copy(&txrx_desc.peer_addr, sta_mac, + QDF_MAC_ADDR_SIZE); + } + + qdf_status = hdd_softap_init_tx_rx_sta(adapter, sta_mac); + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + sta_mac->bytes, + STA_INFO_SOFTAP_REGISTER_STA); + + if (!sta_info) { + hdd_debug("STA not found"); + return QDF_STATUS_E_INVAL; + } + + txrx_desc.is_qos_enabled = wmm_enabled; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + ucfg_dp_add_latency_critical_client(vdev, dot11mode); + + if (is_macaddr_broadcast) { + /* + * Register the vdev transmit and receive functions once with + * CDP layer. Broadcast STA is registered only once when BSS is + * started. + */ + qdf_mem_zero(&txrx_ops, sizeof(txrx_ops)); + txrx_ops.tx.tx_classify_critical_pkt_cb = + hdd_wmm_classify_pkt_cb; + ucfg_dp_softap_register_txrx_ops(vdev, &txrx_ops); + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + ch_width = ucfg_mlme_get_peer_ch_width(adapter->hdd_ctx->psoc, + txrx_desc.peer_addr.bytes); + txrx_desc.bw = hdd_convert_ch_width_to_cdp_peer_bw(ch_width); + qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &txrx_desc); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_debug("cdp_peer_register() failed to register. Status = %d [0x%08X]", + qdf_status, qdf_status); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_REGISTER_STA); + return qdf_status; + } + + /* if ( WPA ), tell TL to go to 'connected' and after keys come to the + * driver then go to 'authenticated'. For all other authentication + * types (those that do not require upper layer authentication) we can + * put TL directly into 'authenticated' state + */ + + sta_info->is_qos_enabled = wmm_enabled; + + if (!auth_required) { + hdd_debug("open/shared auth STA MAC= " QDF_MAC_ADDR_FMT + ". Changing TL state to AUTHENTICATED at Join time", + QDF_MAC_ADDR_REF(sta_info->sta_mac.bytes)); + + /* Connections that do not need Upper layer auth, + * transition TL directly to 'Authenticated' state. + */ + qdf_status = hdd_change_peer_state(link_info, + txrx_desc.peer_addr.bytes, + OL_TXRX_PEER_STATE_AUTH); + + sta_info->peer_state = OL_TXRX_PEER_STATE_AUTH; + if (!qdf_is_macaddr_broadcast(sta_mac)) + qdf_status = wlan_hdd_send_sta_authorized_event( + adapter, hdd_ctx, + sta_mac); + } else { + + hdd_debug("ULA auth STA MAC = " QDF_MAC_ADDR_FMT + ". Changing TL state to CONNECTED at Join time", + QDF_MAC_ADDR_REF(sta_info->sta_mac.bytes)); + + qdf_status = hdd_change_peer_state(link_info, + txrx_desc.peer_addr.bytes, + OL_TXRX_PEER_STATE_CONN); + + sta_info->peer_state = OL_TXRX_PEER_STATE_CONN; + } + + if (!qdf_is_macaddr_broadcast(sta_mac) && + dot11mode < QCA_WLAN_802_11_MODE_INVALID) + ap_ctx->client_count[dot11mode]++; + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_REGISTER_STA); + + if (is_macaddr_broadcast) { + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_START_ALL_NETIF_QUEUE_N_CARRIER, + WLAN_CONTROL_PATH); + } + ucfg_mlme_update_oce_flags(hdd_ctx->pdev); + ucfg_twt_init_context(hdd_ctx->psoc, sta_mac, + TWT_ALL_SESSIONS_DIALOG_ID); + return qdf_status; +} + +QDF_STATUS +hdd_softap_register_bc_sta(struct wlan_hdd_link_info *link_info, + bool privacy_required) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct qdf_mac_addr broadcast_macaddr = QDF_MAC_ADDR_BCAST_INIT; + struct hdd_ap_ctx *ap_ctx; + uint8_t sta_id; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sta_id = ap_ctx->broadcast_sta_id; + if (sta_id >= WLAN_MAX_STA_COUNT) { + hdd_err("Error: Invalid sta_id: %u", sta_id); + return qdf_status; + } + + qdf_status = hdd_softap_register_sta(link_info, false, + privacy_required, + &broadcast_macaddr, NULL); + + return qdf_status; +} + +QDF_STATUS hdd_softap_stop_bss(struct hdd_adapter *adapter) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t indoor_chnl_marking = 0; + struct hdd_context *hdd_ctx; + struct hdd_station_info *sta_info, *tmp = NULL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + status = ucfg_policy_mgr_get_indoor_chnl_marking(hdd_ctx->psoc, + &indoor_chnl_marking); + if (QDF_STATUS_SUCCESS != status) + hdd_err("can't get indoor channel marking, using default"); + /* This is stop bss callback running in scheduler thread so do not + * driver unload in progress check otherwise it can lead to peer + * object leak + */ + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_SOFTAP_STOP_BSS) { + status = hdd_softap_deregister_sta(adapter, &sta_info); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_STOP_BSS); + } + + if (adapter->device_mode == QDF_SAP_MODE && + !hdd_ctx->config->disable_channel) + wlan_hdd_restore_channels(hdd_ctx); + + /* Mark the indoor channel (passive) to enable */ + if (indoor_chnl_marking && adapter->device_mode == QDF_SAP_MODE) { + hdd_update_indoor_channel(hdd_ctx, false); + sme_update_channel_list(hdd_ctx->mac_handle); + } + + if (ucfg_ipa_is_enabled()) { + if (ucfg_ipa_wlan_evt(hdd_ctx->pdev, + adapter->dev, + adapter->device_mode, + adapter->deflink->vdev_id, + WLAN_IPA_AP_DISCONNECT, + adapter->dev->dev_addr, + false) != QDF_STATUS_SUCCESS) + hdd_err("WLAN_AP_DISCONNECT event failed"); + } + + /* Setting the RTS profile to original value */ + if (sme_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_enable_rtscts, + cfg_get(hdd_ctx->psoc, + CFG_ENABLE_FW_RTS_PROFILE), + VDEV_CMD)) + hdd_debug("Failed to set RTS_PROFILE"); + + return status; +} + +/** + * hdd_softap_change_per_sta_state() - Change the state of a SoftAP station + * @adapter: pointer to adapter context + * @sta_mac: MAC address of the station + * @state: new state of the station + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +static QDF_STATUS hdd_softap_change_per_sta_state(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac, + enum ol_txrx_peer_state state) +{ + QDF_STATUS qdf_status; + struct hdd_station_info *sta_info; + struct qdf_mac_addr mac_addr; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(adapter->dev); + + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + sta_mac->bytes, + STA_INFO_SOFTAP_CHANGE_STA_STATE); + + if (!sta_info) { + hdd_debug("Failed to find right station MAC: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_mac->bytes)); + return QDF_STATUS_E_INVAL; + } + + if (qdf_is_macaddr_broadcast(&sta_info->sta_mac)) + qdf_mem_copy(&mac_addr, &adapter->mac_addr, QDF_MAC_ADDR_SIZE); + else + qdf_mem_copy(&mac_addr, sta_mac, QDF_MAC_ADDR_SIZE); + + qdf_status = + hdd_change_peer_state(adapter->deflink, mac_addr.bytes, state); + hdd_debug("Station " QDF_MAC_ADDR_FMT " changed to state %d", + QDF_MAC_ADDR_REF(mac_addr.bytes), state); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto put_ref; + + sta_info->peer_state = OL_TXRX_PEER_STATE_AUTH; + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_ID); + if (vdev) { + p2p_peer_authorized(vdev, sta_mac->bytes); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_ID); + } else { + hdd_err("vdev is NULL"); + } + +put_ref: + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_CHANGE_STA_STATE); + hdd_exit(); + return qdf_status; +} + +QDF_STATUS hdd_softap_change_sta_state(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac, + enum ol_txrx_peer_state state) +{ + struct qdf_mac_addr *mldaddr; + struct wlan_objmgr_peer *peer; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct hdd_context *hdd_ctx; + + status = hdd_softap_change_per_sta_state(adapter, sta_mac, state); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx) { + hdd_err("hdd ctx is null"); + return status; + } + peer = wlan_objmgr_get_peer_by_mac(hdd_ctx->psoc, + sta_mac->bytes, + WLAN_LEGACY_MAC_ID); + + if (!peer) { + hdd_debug("peer is null"); + return status; + } + mldaddr = (struct qdf_mac_addr *)wlan_peer_mlme_get_mldaddr(peer); + if (mldaddr && !qdf_is_macaddr_zero(mldaddr)) + status = hdd_softap_change_per_sta_state(adapter, mldaddr, + state); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + return status; +} + +#ifdef FEATURE_WDS +QDF_STATUS hdd_softap_ind_l2_update(struct hdd_adapter *adapter, + struct qdf_mac_addr *sta_mac) +{ + qdf_nbuf_t nbuf; + struct l2_update_frame *msg; + + nbuf = qdf_nbuf_alloc(NULL, sizeof(*msg), 0, 4, false); + if (!nbuf) + return QDF_STATUS_E_FAILURE; + + msg = (struct l2_update_frame *)qdf_nbuf_data(nbuf); + + /* 802.2 LLC XID update frame carried over 802.3 */ + ether_addr_copy(msg->eh.h_source, sta_mac->bytes); + eth_broadcast_addr(msg->eh.h_dest); + /* packet length - dummy 802.3 packet */ + msg->eh.h_proto = htons(sizeof(*msg) - sizeof(struct ethhdr)); + + /* null DSAP and a null SSAP is a way to solicit a response from any + * station (i.e., any DA) + */ + msg->l2_update_pdu.dsap = LLC_NULL_SAP; + msg->l2_update_pdu.ssap = LLC_NULL_SAP; + + /* + * unsolicited XID response frame to announce presence. + * lsb.11110101. + */ + msg->l2_update_pdu.ctrl_1 = LLC_PDU_TYPE_U | LLC_1_PDU_CMD_XID; + + /* XID information field 129.1.0 to indicate connectionless service */ + msg->l2_update_xid_info.fmt_id = LLC_XID_FMT_ID; + msg->l2_update_xid_info.type = LLC_XID_NULL_CLASS_1; + msg->l2_update_xid_info.rw = 0; + + qdf_nbuf_set_pktlen(nbuf, sizeof(*msg)); + nbuf->dev = adapter->dev; + nbuf->protocol = eth_type_trans(nbuf, adapter->dev); + qdf_net_buf_debug_release_skb(nbuf); + netif_rx_ni(nbuf); + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_son.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_son.c new file mode 100644 index 0000000000..f8689c4052 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_son.c @@ -0,0 +1,2841 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains son hdd API implementation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_cfg80211_mc_cp_stats.h" + +static const struct son_chan_width { + enum ieee80211_cwm_width son_chwidth; + enum phy_ch_width phy_chwidth; +} son_chwidth_info[] = { + { + .son_chwidth = IEEE80211_CWM_WIDTH20, + .phy_chwidth = CH_WIDTH_20MHZ, + }, + { + .son_chwidth = IEEE80211_CWM_WIDTH40, + .phy_chwidth = CH_WIDTH_40MHZ, + }, + { + .son_chwidth = IEEE80211_CWM_WIDTH80, + .phy_chwidth = CH_WIDTH_80MHZ, + }, + { + .son_chwidth = IEEE80211_CWM_WIDTH160, + .phy_chwidth = CH_WIDTH_160MHZ, + }, + { + .son_chwidth = IEEE80211_CWM_WIDTH80_80, + .phy_chwidth = CH_WIDTH_80P80MHZ, + }, +#ifdef WLAN_FEATURE_11BE + { + .son_chwidth = IEEE80211_CWM_WIDTH320, + .phy_chwidth = CH_WIDTH_320MHZ, + }, +#endif +}; + +/** + * hdd_son_is_acs_in_progress() - whether acs is in progress or not + * @vdev: vdev + * + * Return: true if acs is in progress + */ +static uint32_t hdd_son_is_acs_in_progress(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_hdd_link_info *link_info; + bool in_progress = false; + + if (!vdev) { + hdd_err("null vdev"); + return in_progress; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return in_progress; + } + + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return in_progress; + } + + in_progress = qdf_atomic_read(&link_info->session.ap.acs_in_progress); + + return in_progress; +} + +/** + * hdd_son_chan_width_to_chan_width() - translate son chan width + * to mac chan width + * @son_chwidth: son chan width + * + * Return: mac chan width + */ +static enum eSirMacHTChannelWidth hdd_son_chan_width_to_chan_width( + enum ieee80211_cwm_width son_chwidth) +{ + enum eSirMacHTChannelWidth chwidth; + + switch (son_chwidth) { + case IEEE80211_CWM_WIDTH20: + chwidth = eHT_CHANNEL_WIDTH_20MHZ; + break; + case IEEE80211_CWM_WIDTH40: + chwidth = eHT_CHANNEL_WIDTH_40MHZ; + break; + case IEEE80211_CWM_WIDTH80: + chwidth = eHT_CHANNEL_WIDTH_80MHZ; + break; + case IEEE80211_CWM_WIDTH160: + chwidth = eHT_CHANNEL_WIDTH_160MHZ; + break; + case IEEE80211_CWM_WIDTH80_80: + chwidth = eHT_CHANNEL_WIDTH_80P80MHZ; + break; + default: + chwidth = eHT_MAX_CHANNEL_WIDTH; + } + + return chwidth; +} + +/** + * hdd_son_set_chwidth() - set son chan width + * @vdev: vdev + * @son_chwidth: son chan width + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_set_chwidth(struct wlan_objmgr_vdev *vdev, + enum ieee80211_cwm_width son_chwidth) +{ + enum eSirMacHTChannelWidth chwidth; + struct wlan_hdd_link_info *link_info; + uint8_t link_id = 0xFF; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter for %d", wlan_vdev_get_id(vdev)); + return -EINVAL; + } + + chwidth = hdd_son_chan_width_to_chan_width(son_chwidth); + + return hdd_set_mac_chan_width(link_info, chwidth, link_id, false); +} + +/** + * hdd_chan_width_to_son_chwidth() - translate mac chan width + * to son chan width + * @chwidth: mac chan width + * + * Return: son chan width + */ +static enum ieee80211_cwm_width hdd_chan_width_to_son_chwidth( + enum eSirMacHTChannelWidth chwidth) +{ + enum ieee80211_cwm_width son_chwidth; + + switch (chwidth) { + case eHT_CHANNEL_WIDTH_20MHZ: + son_chwidth = IEEE80211_CWM_WIDTH20; + break; + case eHT_CHANNEL_WIDTH_40MHZ: + son_chwidth = IEEE80211_CWM_WIDTH40; + break; + case eHT_CHANNEL_WIDTH_80MHZ: + son_chwidth = IEEE80211_CWM_WIDTH80; + break; + case eHT_CHANNEL_WIDTH_160MHZ: + son_chwidth = IEEE80211_CWM_WIDTH160; + break; + case eHT_CHANNEL_WIDTH_80P80MHZ: + son_chwidth = IEEE80211_CWM_WIDTH80_80; + break; + default: + son_chwidth = IEEE80211_CWM_WIDTHINVALID; + } + + return son_chwidth; +} + +/** + * hdd_phy_chwidth_to_son_chwidth() - translate phy chan width + * to son chan width + * @chwidth: phy chan width + * + * Return: son chan width + */ +static enum ieee80211_cwm_width +hdd_phy_chwidth_to_son_chwidth(enum phy_ch_width chwidth) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(son_chwidth_info); i++) { + if (son_chwidth_info[i].phy_chwidth == chwidth) + return son_chwidth_info[i].son_chwidth; + } + + hdd_err("Unsupported channel width %d", chwidth); + return IEEE80211_CWM_WIDTHINVALID; +} + +/** + * hdd_son_get_chwidth() - get chan width + * @vdev: vdev + * + * Return: son chan width + */ +static enum ieee80211_cwm_width hdd_son_get_chwidth( + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_channel *des_chan; + + if (!vdev) { + hdd_err("null vdev"); + return IEEE80211_CWM_WIDTHINVALID; + } + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + + return hdd_phy_chwidth_to_son_chwidth(des_chan->ch_width); +} + +/** + * hdd_son_chan_ext_offset_to_chan_type() - translate son chan extend offset + * to chan type + * @son_chan_ext_offset: son chan ext offset + * + * Return: tSirMacHTChannelType + */ +static tSirMacHTChannelType hdd_son_chan_ext_offset_to_chan_type( + enum sec20_chan_offset son_chan_ext_offset) +{ + tSirMacHTChannelType chan_type; + + switch (son_chan_ext_offset) { + case EXT_CHAN_OFFSET_ABOVE: + chan_type = eHT_CHAN_HT40PLUS; + break; + case EXT_CHAN_OFFSET_BELOW: + chan_type = eHT_CHAN_HT40MINUS; + break; + default: + chan_type = eHT_CHAN_HT20; + break; + } + + return chan_type; +} + +/** + * hdd_son_set_chan_ext_offset() - set son chan extend offset + * @vdev: vdev + * @son_chan_ext_offset: son chan extend offset + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_set_chan_ext_offset( + struct wlan_objmgr_vdev *vdev, + enum sec20_chan_offset son_chan_ext_offset) +{ + enum eSirMacHTChannelType chan_type; + QDF_STATUS status; + int retval = -EINVAL; + struct hdd_adapter *adapter; + + if (!vdev) { + hdd_err("null vdev"); + return retval; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return retval; + } + + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return retval; + } + + retval = 0; + chan_type = hdd_son_chan_ext_offset_to_chan_type(son_chan_ext_offset); + status = hdd_set_sap_ht2040_mode(link_info->adapter, chan_type); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Cannot set SAP HT20/40 mode!"); + retval = -EINVAL; + } + + return retval; +} + +/** + * hdd_chan_type_to_son_chan_ext_offset() - translate tSirMacHTChannelType + * to son chan extend offset + * @chan_type: tSirMacHTChannelType + * + * Return: son chan extend offset + */ +static enum sec20_chan_offset hdd_chan_type_to_son_chan_ext_offset( + tSirMacHTChannelType chan_type) +{ + enum sec20_chan_offset son_chan_ext_offset; + + switch (chan_type) { + case eHT_CHAN_HT40PLUS: + son_chan_ext_offset = EXT_CHAN_OFFSET_ABOVE; + break; + case eHT_CHAN_HT40MINUS: + son_chan_ext_offset = EXT_CHAN_OFFSET_BELOW; + break; + default: + son_chan_ext_offset = EXT_CHAN_OFFSET_NA; + break; + } + + return son_chan_ext_offset; +} + +/** + * hdd_son_get_chan_ext_offset() - get chan extend offset + * @vdev: vdev + * + * Return: enum sec20_chan_offset + */ +static enum sec20_chan_offset hdd_son_get_chan_ext_offset( + struct wlan_objmgr_vdev *vdev) +{ + enum eSirMacHTChannelType chan_type; + QDF_STATUS status; + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("null vdev"); + return 0; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return 0; + } + + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return 0; + } + + status = hdd_get_sap_ht2040_mode(link_info->adapter, &chan_type); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Cannot set SAP HT20/40 mode!"); + return 0; + } + + return hdd_chan_type_to_son_chan_ext_offset(chan_type); +} + +/** + * hdd_son_bandwidth_to_phymode() - get new eCsrPhyMode according + * to son band width + * @son_bandwidth: son band width + * @old_phymode: old eCsrPhyMode + * @phymode: new eCsrPhyMode to get + * + * Return: void + */ +static void hdd_son_bandwidth_to_phymode(uint32_t son_bandwidth, + eCsrPhyMode old_phymode, + eCsrPhyMode *phymode) +{ + *phymode = old_phymode; + + switch (son_bandwidth) { + case HT20: + case HT40: + *phymode = eCSR_DOT11_MODE_11n; + break; + case VHT20: + case VHT40: + case VHT80: + case VHT160: + case VHT80_80: + *phymode = eCSR_DOT11_MODE_11ac; + break; + case HE20: + case HE40: + case HE80: + case HE160: + case HE80_80: + *phymode = eCSR_DOT11_MODE_11ax; + break; + default: + break; + } +} + +/** + * hdd_son_bandwidth_to_bonding_mode() - son band with to bonding mode + * @son_bandwidth: son band width + * @bonding_mode: bonding mode to get + * + * Return: void + */ +static void hdd_son_bandwidth_to_bonding_mode(uint32_t son_bandwidth, + uint32_t *bonding_mode) +{ + switch (son_bandwidth) { + case HT40: + case VHT40: + case VHT80: + case VHT160: + case VHT80_80: + case HE40: + case HE80: + case HE160: + case HE80_80: + *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + break; + default: + *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } +} + +/** + * hdd_son_set_bandwidth() - set band width + * @vdev: vdev + * @son_bandwidth: son band width + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_set_bandwidth(struct wlan_objmgr_vdev *vdev, + uint32_t son_bandwidth) +{ + eCsrPhyMode phymode; + eCsrPhyMode old_phymode; + uint8_t supported_band; + uint32_t bonding_mode; + struct wlan_hdd_link_info *link_info; + struct hdd_context *hdd_ctx; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + if (!hdd_ctx) { + hdd_err("null hdd ctx"); + return -EINVAL; + } + old_phymode = sme_get_phy_mode(hdd_ctx->mac_handle); + + hdd_son_bandwidth_to_phymode(son_bandwidth, old_phymode, &phymode); + + if (wlan_reg_is_6ghz_supported(hdd_ctx->psoc)) + supported_band = REG_BAND_MASK_ALL; + else + supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + + hdd_son_bandwidth_to_bonding_mode(son_bandwidth, &bonding_mode); + + return hdd_update_phymode(link_info->adapter, phymode, + supported_band, bonding_mode); +} + +/** + * hdd_phymode_chwidth_to_son_bandwidth() - get son bandwidth from + * phymode and chwidth + * @phymode: eCsrPhyMode + * @chwidth: eSirMacHTChannelWidth + * + * Return: son bandwidth + */ +static uint32_t hdd_phymode_chwidth_to_son_bandwidth( + eCsrPhyMode phymode, + enum eSirMacHTChannelWidth chwidth) +{ + uint32_t son_bandwidth = NONHT; + + switch (phymode) { + case eCSR_DOT11_MODE_abg: + case eCSR_DOT11_MODE_11a: + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + case eCSR_DOT11_MODE_11b_ONLY: + son_bandwidth = NONHT; + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + son_bandwidth = HT20; + if (chwidth == eHT_CHANNEL_WIDTH_40MHZ) + son_bandwidth = HT40; + break; + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + son_bandwidth = VHT20; + if (chwidth == eHT_CHANNEL_WIDTH_40MHZ) + son_bandwidth = VHT40; + else if (chwidth == eHT_CHANNEL_WIDTH_80MHZ) + son_bandwidth = VHT80; + else if (chwidth == eHT_CHANNEL_WIDTH_160MHZ) + son_bandwidth = VHT160; + else if (chwidth == eHT_CHANNEL_WIDTH_80P80MHZ) + son_bandwidth = VHT80_80; + break; + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + case eCSR_DOT11_MODE_AUTO: + son_bandwidth = HE20; + if (chwidth == eHT_CHANNEL_WIDTH_40MHZ) + son_bandwidth = HE40; + else if (chwidth == eHT_CHANNEL_WIDTH_80MHZ) + son_bandwidth = HE80; + else if (chwidth == eHT_CHANNEL_WIDTH_160MHZ) + son_bandwidth = HE160; + else if (chwidth == eHT_CHANNEL_WIDTH_80P80MHZ) + son_bandwidth = HE80_80; + break; + default: + break; + } + + return son_bandwidth; +} + +/** + * hdd_son_get_bandwidth() - get band width + * @vdev: vdev + * + * Return: band width + */ +static uint32_t hdd_son_get_bandwidth(struct wlan_objmgr_vdev *vdev) +{ + enum eSirMacHTChannelWidth chwidth; + eCsrPhyMode phymode; + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("null vdev"); + return NONHT; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return NONHT; + } + + chwidth = wma_cli_get_command(link_info->vdev_id, + wmi_vdev_param_chwidth, VDEV_CMD); + + if (chwidth < 0) { + hdd_err("Failed to get chwidth"); + return NONHT; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + if (!hdd_ctx) { + hdd_err("null hdd ctx"); + return -NONHT; + } + + phymode = sme_get_phy_mode(hdd_ctx->mac_handle); + + return hdd_phymode_chwidth_to_son_bandwidth(phymode, chwidth); +} + +/** + * hdd_son_band_to_band() - translate SON band mode to reg_wifi_band + * @band: given enum wlan_band_id + * + * Return: reg_wifi_band + */ +static enum reg_wifi_band hdd_son_band_to_band(enum wlan_band_id band) +{ + enum reg_wifi_band reg_band = REG_BAND_UNKNOWN; + + switch (band) { + case WLAN_BAND_2GHZ: + reg_band = REG_BAND_2G; + break; + case WLAN_BAND_5GHZ: + reg_band = REG_BAND_5G; + break; + case WLAN_BAND_6GHZ: + reg_band = REG_BAND_6G; + break; + default: + break; + } + + return reg_band; +} + +/** + * hdd_son_set_chan() - set chan + * @vdev: vdev + * @chan: given chan + * @son_band: given enum wlan_band_id + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_set_chan(struct wlan_objmgr_vdev *vdev, int chan, + enum wlan_band_id son_band) +{ + struct wlan_hdd_link_info *link_info; + enum reg_wifi_band band = hdd_son_band_to_band(son_band); + bool status; + qdf_freq_t freq; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return -ENOTSUPP; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + hdd_err("null pdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("null psoc"); + return -EINVAL; + } + + freq = wlan_reg_chan_band_to_freq(pdev, chan, BIT(band)); + status = policy_mgr_is_sap_allowed_on_dfs_freq(pdev, link_info->vdev_id, + freq); + if (!status) { + hdd_err("sap_allowed_on_dfs_freq check fails"); + return -EINVAL; + } + wlan_hdd_set_sap_csa_reason(psoc, link_info->vdev_id, + CSA_REASON_USER_INITIATED); + + return hdd_softap_set_channel_change(link_info->adapter->dev, freq, + CH_WIDTH_MAX, false); +} + +/** + * hdd_son_set_country() - set country code + * @vdev: vdev + * @country_code:pointer to country code + * + * Return: 0 if country code is set successfully + */ +static int hdd_son_set_country(struct wlan_objmgr_vdev *vdev, + char *country_code) +{ + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + if (!hdd_ctx) { + hdd_err("null hdd ctx"); + return -EINVAL; + } + + return hdd_reg_set_country(hdd_ctx, country_code); +} + +/** + * hdd_son_set_candidate_freq() - set candidate freq. Switch to this freq + * after radar is detected + * @vdev: vdev + * @freq: candidate frequency + * + * Return: 0 if candidate freq is set successfully. + */ +static int hdd_son_set_candidate_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_ctx; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return -EINVAL; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + hdd_err("null sap_ctx"); + return -EINVAL; + } + + sap_ctx->candidate_freq = freq; + + return 0; +} + +/** + * hdd_son_get_candidate_freq() - get candidate freq + * @vdev: vdev + * + * Return: candidate freq + */ +static qdf_freq_t hdd_son_get_candidate_freq(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_ctx; + qdf_freq_t freq = 0; + + if (!vdev) { + hdd_err("null vdev"); + return freq; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return freq; + } + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return freq; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + hdd_err("null sap_ctx"); + return freq; + } + freq = sap_ctx->candidate_freq; + + return freq; +} + +/** + * hdd_son_phy_mode_to_vendor_phy_mode() - translate son phy mode to + * vendor_phy_mode + * @mode: son phy mode + * + * Return: qca_wlan_vendor_phy_mode + */ +static enum qca_wlan_vendor_phy_mode hdd_son_phy_mode_to_vendor_phy_mode( + enum ieee80211_phymode mode) +{ + enum qca_wlan_vendor_phy_mode vendor_mode; + + switch (mode) { + case IEEE80211_MODE_AUTO: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_AUTO; + break; + case IEEE80211_MODE_11A: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11A; + break; + case IEEE80211_MODE_11B: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11B; + break; + case IEEE80211_MODE_11G: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11G; + break; + case IEEE80211_MODE_11NA_HT20: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20; + break; + case IEEE80211_MODE_11NG_HT20: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20; + break; + case IEEE80211_MODE_11NA_HT40PLUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS; + break; + case IEEE80211_MODE_11NA_HT40MINUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS; + break; + case IEEE80211_MODE_11NG_HT40PLUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS; + break; + case IEEE80211_MODE_11NG_HT40MINUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS; + break; + case IEEE80211_MODE_11NG_HT40: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40; + break; + case IEEE80211_MODE_11NA_HT40: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40; + break; + case IEEE80211_MODE_11AC_VHT20: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20; + break; + case IEEE80211_MODE_11AC_VHT40PLUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS; + break; + case IEEE80211_MODE_11AC_VHT40MINUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS; + break; + case IEEE80211_MODE_11AC_VHT40: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40; + break; + case IEEE80211_MODE_11AC_VHT80: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80; + break; + case IEEE80211_MODE_11AC_VHT160: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160; + break; + case IEEE80211_MODE_11AC_VHT80_80: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80P80; + break; + case IEEE80211_MODE_11AXA_HE20: + case IEEE80211_MODE_11AXG_HE20: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20; + break; + case IEEE80211_MODE_11AXA_HE40PLUS: + case IEEE80211_MODE_11AXG_HE40PLUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS; + break; + case IEEE80211_MODE_11AXA_HE40MINUS: + case IEEE80211_MODE_11AXG_HE40MINUS: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS; + break; + case IEEE80211_MODE_11AXA_HE40: + case IEEE80211_MODE_11AXG_HE40: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40; + break; + case IEEE80211_MODE_11AXA_HE80: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80; + break; + case IEEE80211_MODE_11AXA_HE160: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160; + break; + case IEEE80211_MODE_11AXA_HE80_80: + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80P80; + break; + default: + hdd_err("Invalid config phy mode %d, set it as auto", mode); + vendor_mode = QCA_WLAN_VENDOR_PHY_MODE_AUTO; + break; + } + + return vendor_mode; +} + +/** + * hdd_son_set_phymode() - set son phy mode + * @vdev: vdev + * @mode: son phy mode to set + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_set_phymode(struct wlan_objmgr_vdev *vdev, + enum ieee80211_phymode mode) +{ + struct wlan_hdd_link_info *link_info; + enum qca_wlan_vendor_phy_mode vendor_phy_mode; + QDF_STATUS status; + struct hdd_ap_ctx *hdd_ap_ctx; + struct sap_config *sap_config; + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("Invalid VDEV %d", wlan_vdev_get_id(vdev)); + return -EINVAL; + } + + if (!hdd_adapter_is_ap(link_info->adapter)) { + hdd_err("vdev id %d is not AP", link_info->vdev_id); + return -EINVAL; + } + + vendor_phy_mode = hdd_son_phy_mode_to_vendor_phy_mode(mode); + + hdd_ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + sap_config = &hdd_ap_ctx->sap_config; + status = wlansap_son_update_sap_config_phymode(vdev, sap_config, + vendor_phy_mode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("update son phy mode error"); + return -EINVAL; + } + + hdd_restart_sap(link_info); + + return 0; +} + +/** + * hdd_wlan_phymode_to_son_phymode() - get son phymode from wlan_phymode phymode + * @phymode: wlan_phymode phymode + * + * Return: ieee80211_phymode + */ +static enum ieee80211_phymode hdd_wlan_phymode_to_son_phymode( + enum wlan_phymode phymode) +{ + enum ieee80211_phymode son_phymode; + + switch (phymode) { + case WLAN_PHYMODE_AUTO: + son_phymode = IEEE80211_MODE_AUTO; + break; + case WLAN_PHYMODE_11A: + son_phymode = IEEE80211_MODE_11A; + break; + case WLAN_PHYMODE_11B: + son_phymode = IEEE80211_MODE_11B; + break; + case WLAN_PHYMODE_11G: + case WLAN_PHYMODE_11G_ONLY: + son_phymode = IEEE80211_MODE_11G; + break; + case WLAN_PHYMODE_11NA_HT20: + son_phymode = IEEE80211_MODE_11NA_HT20; + break; + case WLAN_PHYMODE_11NG_HT20: + son_phymode = IEEE80211_MODE_11NG_HT20; + break; + case WLAN_PHYMODE_11NA_HT40: + son_phymode = IEEE80211_MODE_11NA_HT40; + break; + case WLAN_PHYMODE_11NG_HT40PLUS: + son_phymode = IEEE80211_MODE_11NG_HT40PLUS; + break; + case WLAN_PHYMODE_11NG_HT40MINUS: + son_phymode = IEEE80211_MODE_11NG_HT40MINUS; + break; + case WLAN_PHYMODE_11NG_HT40: + son_phymode = IEEE80211_MODE_11NG_HT40; + break; + case WLAN_PHYMODE_11AC_VHT20: + case WLAN_PHYMODE_11AC_VHT20_2G: + son_phymode = IEEE80211_MODE_11AC_VHT20; + break; + case WLAN_PHYMODE_11AC_VHT40: + case WLAN_PHYMODE_11AC_VHT40_2G: + son_phymode = IEEE80211_MODE_11AC_VHT40; + break; + case WLAN_PHYMODE_11AC_VHT40PLUS_2G: + son_phymode = IEEE80211_MODE_11AC_VHT40PLUS; + break; + case WLAN_PHYMODE_11AC_VHT40MINUS_2G: + son_phymode = IEEE80211_MODE_11AC_VHT40MINUS; + break; + case WLAN_PHYMODE_11AC_VHT80: + case WLAN_PHYMODE_11AC_VHT80_2G: + son_phymode = IEEE80211_MODE_11AC_VHT80; + break; + case WLAN_PHYMODE_11AC_VHT160: + son_phymode = IEEE80211_MODE_11AC_VHT160; + break; + case WLAN_PHYMODE_11AC_VHT80_80: + son_phymode = IEEE80211_MODE_11AC_VHT80_80; + break; + case WLAN_PHYMODE_11AXA_HE20: + son_phymode = IEEE80211_MODE_11AXA_HE20; + break; + case WLAN_PHYMODE_11AXG_HE20: + son_phymode = IEEE80211_MODE_11AXG_HE20; + break; + case WLAN_PHYMODE_11AXA_HE40: + son_phymode = IEEE80211_MODE_11AXA_HE40; + break; + case WLAN_PHYMODE_11AXG_HE40PLUS: + son_phymode = IEEE80211_MODE_11AXG_HE40PLUS; + break; + case WLAN_PHYMODE_11AXG_HE40MINUS: + son_phymode = IEEE80211_MODE_11AXG_HE40MINUS; + break; + case WLAN_PHYMODE_11AXG_HE40: + case WLAN_PHYMODE_11AXG_HE80: + son_phymode = IEEE80211_MODE_11AXG_HE40; + break; + case WLAN_PHYMODE_11AXA_HE80: + son_phymode = IEEE80211_MODE_11AXA_HE80; + break; + case WLAN_PHYMODE_11AXA_HE160: + son_phymode = IEEE80211_MODE_11AXA_HE160; + break; + case WLAN_PHYMODE_11AXA_HE80_80: + son_phymode = IEEE80211_MODE_11AXA_HE80_80; + break; + default: + son_phymode = IEEE80211_MODE_AUTO; + break; + } + + return son_phymode; +} + +/** + * hdd_son_get_phymode() - get son phy mode + * @vdev: vdev + * + * Return: enum ieee80211_phymode + */ +static enum ieee80211_phymode hdd_son_get_phymode(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_channel *des_chan; + + if (!vdev) { + hdd_err("null vdev"); + return IEEE80211_MODE_AUTO; + } + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) { + hdd_err("null des_chan"); + return IEEE80211_MODE_AUTO; + } + + return hdd_wlan_phymode_to_son_phymode(des_chan->ch_phymode); +} + +/** + * hdd_son_per_sta_len() - get sta information length + * @sta_info: pointer to hdd_station_info + * + * TD: Certain IE may be provided for sta info + * + * Return: the size which is needed for given sta info + */ +static uint32_t hdd_son_per_sta_len(struct hdd_station_info *sta_info) +{ + return qdf_roundup(sizeof(struct ieee80211req_sta_info), + sizeof(uint32_t)); +} + +/** + * hdd_son_get_sta_space() - how many space are needed for given vdev + * @vdev: vdev + * + * Return: space needed for given vdev to provide sta info + */ +static uint32_t hdd_son_get_sta_space(struct wlan_objmgr_vdev *vdev) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_info *sta_info, *tmp = NULL; + uint32_t space = 0; + + if (!vdev) { + hdd_err("null vdev"); + return space; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return space; + } + + adapter = link_info->adapter; + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_SOFTAP_GET_STA_INFO) { + if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) + space += hdd_son_per_sta_len(sta_info); + + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_SOFTAP_GET_STA_INFO); + } + hdd_debug("sta list space %u", space); + + return space; +} + +/** + * hdd_son_get_sta_list() - get connected station list + * @vdev: vdev + * @si: pointer to ieee80211req_sta_info + * @space: space left + * + * Return: void + */ +static void hdd_son_get_sta_list(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_sta_info *si, + uint32_t *space) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_info *sta_info, *tmp = NULL; + uint32_t len; + qdf_time_t current_ts; + + if (!vdev) { + hdd_err("null vdev"); + return; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return; + } + + adapter = link_info->adapter; + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_SOFTAP_GET_STA_INFO) { + if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) { + len = hdd_son_per_sta_len(sta_info); + + if (len > *space) { + /* no more space if left */ + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &sta_info, true, + STA_INFO_SOFTAP_GET_STA_INFO); + + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_SOFTAP_GET_STA_INFO); + + hdd_err("space %u, length %u", *space, len); + + return; + } + + qdf_mem_copy(si->isi_macaddr, &sta_info->sta_mac, + QDF_MAC_ADDR_SIZE); + si->isi_ext_cap = sta_info->ext_cap; + si->isi_beacon_measurement_support = + !!(sta_info->capability & + WLAN_CAPABILITY_RADIO_MEASURE); + si->isi_operating_bands = sta_info->supported_band; + si->isi_assoc_time = sta_info->assoc_ts; + current_ts = qdf_system_ticks(); + jiffies_to_timespec(current_ts - sta_info->assoc_ts, + &si->isi_tr069_assoc_time); + si->isi_rssi = sta_info->rssi; + si->isi_len = len; + si->isi_ie_len = 0; + hdd_debug("sta " QDF_MAC_ADDR_FMT " ext_cap 0x%x op band %u rssi %d len %u, assoc ts %lu, curr ts %lu rrm %d", + QDF_MAC_ADDR_REF(si->isi_macaddr), + si->isi_ext_cap, si->isi_operating_bands, + si->isi_rssi, si->isi_len, sta_info->assoc_ts, + current_ts, + si->isi_beacon_measurement_support); + si = (struct ieee80211req_sta_info *)(((uint8_t *)si) + + len); + *space -= len; + } + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_SOFTAP_GET_STA_INFO); + } +} + +/** + * hdd_son_set_acl_policy() - set son acl policy + * @vdev: vdev + * @son_acl_policy: enum ieee80211_acl_cmd + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_son_set_acl_policy(struct wlan_objmgr_vdev *vdev, + ieee80211_acl_cmd son_acl_policy) +{ + struct wlan_hdd_link_info *link_info; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct sap_context *sap_context; + + if (!vdev) { + hdd_err("null vdev"); + return status; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return status; + } + + sap_context = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + switch (son_acl_policy) { + case IEEE80211_MACCMD_POLICY_OPEN: + status = wlansap_set_acl_mode(sap_context, eSAP_ALLOW_ALL); + break; + case IEEE80211_MACCMD_POLICY_ALLOW: + status = wlansap_set_acl_mode(sap_context, + eSAP_DENY_UNLESS_ACCEPTED); + break; + case IEEE80211_MACCMD_POLICY_DENY: + status = wlansap_set_acl_mode(sap_context, + eSAP_ACCEPT_UNLESS_DENIED); + break; + case IEEE80211_MACCMD_FLUSH: + case IEEE80211_MACCMD_DETACH: + status = wlansap_clear_acl(sap_context); + break; + default: + hdd_err("invalid son acl policy %d", son_acl_policy); + break; + } + + return status; +} + +/** + * hdd_acl_policy_to_son_acl_policy() - convert acl policy to son acl policy + * @acl_policy: acl policy + * + * Return: son acl policy. enum ieee80211_acl_cmd + */ +static ieee80211_acl_cmd hdd_acl_policy_to_son_acl_policy( + eSapMacAddrACL acl_policy) +{ + ieee80211_acl_cmd son_acl_policy = IEEE80211_MACCMD_DETACH; + + switch (acl_policy) { + case eSAP_ACCEPT_UNLESS_DENIED: + son_acl_policy = IEEE80211_MACCMD_POLICY_DENY; + break; + case eSAP_DENY_UNLESS_ACCEPTED: + son_acl_policy = IEEE80211_MACCMD_POLICY_ALLOW; + break; + case eSAP_ALLOW_ALL: + son_acl_policy = IEEE80211_MACCMD_POLICY_OPEN; + break; + default: + hdd_err("invalid acl policy %d", acl_policy); + break; + } + + return son_acl_policy; +} + +/** + * hdd_son_get_acl_policy() - get son acl policy + * @vdev: vdev + * + * Return: son acl policy. enum ieee80211_acl_cmd + */ +static ieee80211_acl_cmd hdd_son_get_acl_policy(struct wlan_objmgr_vdev *vdev) +{ + eSapMacAddrACL acl_policy; + struct wlan_hdd_link_info *link_info; + ieee80211_acl_cmd son_acl_policy = IEEE80211_MACCMD_DETACH; + + if (!vdev) { + hdd_err("null vdev"); + return son_acl_policy; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return son_acl_policy; + } + + wlansap_get_acl_mode(WLAN_HDD_GET_SAP_CTX_PTR(link_info), &acl_policy); + + son_acl_policy = hdd_acl_policy_to_son_acl_policy(acl_policy); + + return son_acl_policy; +} + +/** + * hdd_son_add_acl_mac() - add mac to access control list(ACL) + * @vdev: vdev + * @acl_mac: mac address to add + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_add_acl_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac) +{ + eSapACLType list_type; + QDF_STATUS qdf_status; + eSapMacAddrACL acl_policy; + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_context; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + if (!acl_mac) { + hdd_err("null acl_mac"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + sap_context = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + wlansap_get_acl_mode(sap_context, &acl_policy); + + if (acl_policy == eSAP_ACCEPT_UNLESS_DENIED) { + list_type = SAP_DENY_LIST; + } else if (acl_policy == eSAP_DENY_UNLESS_ACCEPTED) { + list_type = SAP_ALLOW_LIST; + } else { + hdd_err("Invalid ACL policy %d.", acl_policy); + return -EINVAL; + } + qdf_status = wlansap_modify_acl(sap_context, acl_mac->bytes, list_type, + ADD_STA_TO_ACL_NO_DEAUTH); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("Modify ACL failed"); + return -EIO; + } + + return 0; +} + +/** + * hdd_son_del_acl_mac() - delete mac from acl + * @vdev: vdev + * @acl_mac: mac to remove + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_del_acl_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac) +{ + eSapACLType list_type; + QDF_STATUS qdf_status; + eSapMacAddrACL acl_policy; + struct wlan_hdd_link_info *link_info; + struct sap_context *sap_ctx; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + if (!acl_mac) { + hdd_err("null acl_mac"); + return -EINVAL; + } + + lin_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (!sap_ctx) { + hdd_err("null sap ctx"); + return -EINVAL; + } + + wlansap_get_acl_mode(sap_ctx, &acl_policy); + + if (acl_policy == eSAP_ACCEPT_UNLESS_DENIED) { + list_type = SAP_DENY_LIST; + } else if (acl_policy == eSAP_DENY_UNLESS_ACCEPTED) { + list_type = SAP_ALLOW_LIST; + } else { + hdd_err("Invalid ACL policy %d.", acl_policy); + return -EINVAL; + } + qdf_status = wlansap_modify_acl(sap_ctx, acl_mac->bytes, list_type, + DELETE_STA_FROM_ACL_NO_DEAUTH); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + hdd_err("Modify ACL failed"); + return -EIO; + } + + return 0; +} + +/** + * hdd_son_kickout_mac() - kickout sta with given mac + * @vdev: vdev + * @mac: sta mac to kickout + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_kickout_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac) +{ + struct wlan_hdd_link_info *link_info; + + if (!vdev) { + hdd_err("null vdev"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + if (mac) + return wlan_hdd_del_station(link_info->adapter, mac->bytes); + else + return wlan_hdd_del_station(link_info->adapter, NULL); +} + +static uint8_t hdd_son_get_rx_nss(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_hdd_link_info *link_info; + uint8_t rx_nss = 0; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return 0; + } + + hdd_get_rx_nss(link_info->adapter, &rx_nss); + return rx_nss; +} + +static void hdd_son_deauth_sta(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool ignore_frame) +{ + struct wlan_hdd_link_info *link_info; + struct csr_del_sta_params param; + QDF_STATUS status; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return; + } + + qdf_mem_copy(param.peerMacAddr.bytes, peer_mac, QDF_MAC_ADDR_SIZE); + param.subtype = SIR_MAC_MGMT_DEAUTH; + param.reason_code = ignore_frame ? REASON_HOST_TRIGGERED_SILENT_DEAUTH + : REASON_UNSPEC_FAILURE; + hdd_debug("Peer - "QDF_MAC_ADDR_FMT" Ignore Frame - %u", + QDF_MAC_ADDR_REF(peer_mac), ignore_frame); + + status = hdd_softap_sta_deauth(link_info->adapter, ¶m); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Error in deauthenticating peer"); +} + +static void hdd_son_modify_acl(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool allow_auth) +{ + QDF_STATUS status; + struct sap_context *sap_context; + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return; + } + + hdd_debug("Peer - " QDF_MAC_ADDR_FMT " Allow Auth - %u", + QDF_MAC_ADDR_REF(peer_mac), allow_auth); + + sap_context = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + if (allow_auth) { + status = wlansap_modify_acl(sap_context, peer_mac, + SAP_DENY_LIST, DELETE_STA_FROM_ACL); + status = wlansap_modify_acl(sap_context, peer_mac, + SAP_ALLOW_LIST, ADD_STA_TO_ACL); + } else { + status = wlansap_modify_acl(sap_context, peer_mac, + SAP_ALLOW_LIST, + DELETE_STA_FROM_ACL); + status = wlansap_modify_acl(sap_context, peer_mac, + SAP_DENY_LIST, ADD_STA_TO_ACL); + } +} + +static int hdd_son_send_cfg_event(struct wlan_objmgr_vdev *vdev, + uint32_t event_id, + uint32_t event_len, + const uint8_t *event_buf) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + uint32_t len; + uint32_t idx; + struct sk_buff *skb; + + if (!event_buf) { + hdd_err("invalid event buf"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return -EINVAL; + } + + adapter = link_info->adapter; + len = nla_total_size(sizeof(event_id)) + + nla_total_size(event_len) + + NLMSG_HDRLEN; + idx = QCA_NL80211_VENDOR_SUBCMD_GET_WIFI_CONFIGURATION_INDEX; + skb = wlan_cfg80211_vendor_event_alloc(adapter->hdd_ctx->wiphy, + &adapter->wdev, + len, idx, GFP_KERNEL); + if (!skb) { + hdd_err("failed to alloc cfg80211 vendor event"); + return -EINVAL; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND, + event_id)) { + hdd_err("failed to put attr config generic command"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA, + event_len, + event_buf)) { + hdd_err("failed to put attr config generic data"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + + return 0; +} + +static int hdd_son_deliver_opmode(struct wlan_objmgr_vdev *vdev, + uint32_t event_len, + const uint8_t *event_buf) +{ + return hdd_son_send_cfg_event(vdev, + QCA_NL80211_VENDOR_SUBCMD_OPMODE_UPDATE, + event_len, + event_buf); +} + +static int hdd_son_deliver_smps(struct wlan_objmgr_vdev *vdev, + uint32_t event_len, + const uint8_t *event_buf) +{ + return hdd_son_send_cfg_event(vdev, + QCA_NL80211_VENDOR_SUBCMD_SMPS_UPDATE, + event_len, + event_buf); +} + +/** + * hdd_son_get_vdev_by_netdev() - get vdev from net device + * @dev: struct net_device dev + * + * Return: vdev on success, NULL on failure + */ +static struct wlan_objmgr_vdev * +hdd_son_get_vdev_by_netdev(struct net_device *dev) +{ + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + if (!dev) + return NULL; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (!adapter || (adapter && adapter->delete_in_progress)) + return NULL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_SON_ID); + if (!vdev) + return NULL; + + return vdev; +} + +/** + * son_trigger_vdev_obj_creation() - Trigger vdev object creation + * @psoc: psoc object + * @object: vdev object + * @arg: component id + * + * Return: void + */ +static void +son_trigger_vdev_obj_creation(struct wlan_objmgr_psoc *psoc, + void *object, void *arg) +{ + QDF_STATUS ret; + struct wlan_objmgr_vdev *vdev; + enum wlan_umac_comp_id *id; + + vdev = object; + id = arg; + + ret = wlan_objmgr_trigger_vdev_comp_priv_object_creation(vdev, *id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("vdev obj creation trigger failed"); +} + +/** + * son_trigger_pdev_obj_creation() - Trigger pdev object creation + * @psoc: psoc object + * @object: pdev object + * @arg: component id + * + * Return: void + */ +static void +son_trigger_pdev_obj_creation(struct wlan_objmgr_psoc *psoc, + void *object, void *arg) +{ + QDF_STATUS ret; + struct wlan_objmgr_pdev *pdev; + enum wlan_umac_comp_id *id; + + pdev = object; + id = arg; + + ret = wlan_objmgr_trigger_pdev_comp_priv_object_creation(pdev, *id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("pdev obj creation trigger failed"); +} + +/** + * son_trigger_pdev_obj_deletion() - Trigger pdev object deletion + * @psoc: psoc object + * @object: pdev object + * @arg: component id + * + * Return: void + */ +static void +son_trigger_pdev_obj_deletion(struct wlan_objmgr_psoc *psoc, + void *object, void *arg) +{ + QDF_STATUS ret; + struct wlan_objmgr_pdev *pdev; + enum wlan_umac_comp_id *id; + + pdev = object; + id = arg; + + ret = wlan_objmgr_trigger_pdev_comp_priv_object_deletion(pdev, *id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("pdev obj delete trigger failed"); +} + +/** + * hdd_son_trigger_objmgr_object_creation() - Trigger objmgr object creation + * @id: umac component id + * + * Return: QDF_STATUS_SUCCESS on success otherwise failure + */ +static QDF_STATUS +hdd_son_trigger_objmgr_object_creation(enum wlan_umac_comp_id id) +{ + QDF_STATUS ret; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_objmgr_get_psoc_by_id(0, WLAN_SON_ID); + if (!psoc) { + hdd_err("psoc null"); + return QDF_STATUS_E_INVAL; + } + + ret = wlan_objmgr_trigger_psoc_comp_priv_object_creation(psoc, id); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("psoc object create trigger failed"); + goto out; + } + + ret = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, + son_trigger_pdev_obj_creation, + &id, 0, id); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("pdev object create trigger failed"); + goto fail; + } + + ret = wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + son_trigger_vdev_obj_creation, + &id, 0, id); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("vdev object create trigger failed"); + goto fail1; + } + wlan_objmgr_psoc_release_ref(psoc, WLAN_SON_ID); + return ret; + +fail1: + ret = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, + son_trigger_pdev_obj_deletion, + &id, 0, id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("pdev object delete trigger failed"); +fail: + ret = wlan_objmgr_trigger_psoc_comp_priv_object_deletion(psoc, id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("psoc object delete trigger failed"); +out: + wlan_objmgr_psoc_release_ref(psoc, WLAN_SON_ID); + return ret; +} + +/** + * son_trigger_peer_obj_deletion() - Trigger peer object deletion + * @psoc: psoc object + * @object: peer object + * @arg: component id + * + * Return: void + */ +static void +son_trigger_peer_obj_deletion(struct wlan_objmgr_psoc *psoc, + void *object, void *arg) +{ + QDF_STATUS ret; + struct wlan_objmgr_peer *peer; + enum wlan_umac_comp_id *id; + + peer = object; + id = arg; + + ret = wlan_objmgr_trigger_peer_comp_priv_object_deletion(peer, *id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("peer obj delete trigger failed"); +} + +/** + * son_trigger_vdev_obj_deletion() - Trigger vdev object deletion + * @psoc: psoc object + * @object: vdev object + * @arg: component id + * + * Return: void + */ +static void +son_trigger_vdev_obj_deletion(struct wlan_objmgr_psoc *psoc, + void *object, void *arg) +{ + QDF_STATUS ret; + struct wlan_objmgr_vdev *vdev; + enum wlan_umac_comp_id *id; + + vdev = object; + id = arg; + + ret = wlan_objmgr_trigger_vdev_comp_priv_object_deletion(vdev, *id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("vdev obj deletion trigger failed"); +} + +/** + * hdd_son_trigger_objmgr_object_deletion() - Trigger objmgr object deletion + * @id: umac component id + * + * Return: QDF_STATUS_SUCCESS on success otherwise failure + */ +static QDF_STATUS +hdd_son_trigger_objmgr_object_deletion(enum wlan_umac_comp_id id) +{ + QDF_STATUS ret; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_objmgr_get_psoc_by_id(0, WLAN_SON_ID); + if (!psoc) { + hdd_err("psoc null"); + return QDF_STATUS_E_INVAL; + } + + ret = wlan_objmgr_iterate_obj_list(psoc, WLAN_PEER_OP, + son_trigger_peer_obj_deletion, + &id, 0, id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("peer object deletion trigger failed"); + + ret = wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + son_trigger_vdev_obj_deletion, + &id, 0, id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("vdev object deletion trigger failed"); + + ret = wlan_objmgr_iterate_obj_list(psoc, WLAN_PDEV_OP, + son_trigger_pdev_obj_deletion, + &id, 0, id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("pdev object delete trigger failed"); + + ret = wlan_objmgr_trigger_psoc_comp_priv_object_deletion(psoc, id); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_err("psoc object delete trigger failed"); + + wlan_objmgr_psoc_release_ref(psoc, WLAN_SON_ID); + return ret; +} + +/* + * hdd_son_init_acs_channels() -initializes acs configs + * + * @adapter: pointer to hdd adapter + * @hdd_ctx: pointer to hdd context + * @acs_cfg: pointer to acs configs + * + * Return: QDF_STATUS_SUCCESS if ACS configuration is initialized, + */ +static QDF_STATUS hdd_son_init_acs_channels(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + struct sap_acs_cfg *acs_cfg) +{ + enum policy_mgr_con_mode pm_mode; + uint32_t freq_list[NUM_CHANNELS], num_channels, i; + + if (!hdd_ctx || !acs_cfg) { + hdd_err("Null pointer!!! hdd_ctx or acs_cfg"); + return QDF_STATUS_E_INVAL; + } + if (acs_cfg->freq_list) { + hdd_debug("ACS config is already there, no need to init again"); + return QDF_STATUS_SUCCESS; + } + /* Setting ACS config */ + qdf_mem_zero(acs_cfg, sizeof(*acs_cfg)); + acs_cfg->ch_width = CH_WIDTH_20MHZ; + policy_mgr_get_valid_chans(hdd_ctx->psoc, freq_list, &num_channels); + /* convert and store channel to freq */ + if (!num_channels) { + hdd_err("No Valid channel for ACS"); + return QDF_STATUS_E_INVAL; + } + acs_cfg->freq_list = qdf_mem_malloc(sizeof(*acs_cfg->freq_list) * + num_channels); + if (!acs_cfg->freq_list) { + hdd_err("Mem-alloc failed for acs_cfg->freq_list"); + return QDF_STATUS_E_NOMEM; + } + acs_cfg->master_freq_list = + qdf_mem_malloc(sizeof(*acs_cfg->master_freq_list) * + num_channels); + if (!acs_cfg->master_freq_list) { + hdd_err("Mem-alloc failed for acs_cfg->master_freq_list"); + qdf_mem_free(acs_cfg->freq_list); + acs_cfg->freq_list = NULL; + return QDF_STATUS_E_NOMEM; + } + + pm_mode = + policy_mgr_qdf_opmode_to_pm_con_mode(hdd_ctx->psoc, + adapter->device_mode, + adapter->deflink->vdev_id); + /* convert channel to freq */ + for (i = 0; i < num_channels; i++) { + acs_cfg->freq_list[i] = freq_list[i]; + acs_cfg->master_freq_list[i] = freq_list[i]; + } + acs_cfg->ch_list_count = num_channels; + acs_cfg->master_ch_list_count = num_channels; + if (policy_mgr_is_force_scc(hdd_ctx->psoc) && + policy_mgr_get_connection_count(hdd_ctx->psoc)) { + policy_mgr_get_pcl(hdd_ctx->psoc, pm_mode, + acs_cfg->pcl_chan_freq, + &acs_cfg->pcl_ch_count, + acs_cfg->pcl_channels_weight_list, + NUM_CHANNELS, adapter->deflink->vdev_id); + wlan_hdd_trim_acs_channel_list(acs_cfg->pcl_chan_freq, + acs_cfg->pcl_ch_count, + acs_cfg->freq_list, + &acs_cfg->ch_list_count); + if (!acs_cfg->ch_list_count && acs_cfg->master_ch_list_count) + wlan_hdd_handle_zero_acs_list + (hdd_ctx, + acs_cfg->freq_list, + &acs_cfg->ch_list_count, + acs_cfg->master_freq_list, + acs_cfg->master_ch_list_count); + } + acs_cfg->start_ch_freq = acs_cfg->freq_list[0]; + acs_cfg->end_ch_freq = acs_cfg->freq_list[acs_cfg->ch_list_count - 1]; + acs_cfg->hw_mode = eCSR_DOT11_MODE_abg; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_son_start_acs() -Trigers ACS + * + * @vdev: pointer to object mgr vdev + * @enable: True to trigger ACS + * + * Return: 0 on success + */ +static int hdd_son_start_acs(struct wlan_objmgr_vdev *vdev, uint8_t enable) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct sap_config *sap_config; + struct hdd_context *hdd_ctx; + + if (!enable) { + hdd_err("ACS Start report with disabled flag"); + return -EINVAL; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("Invalid VDEV %d", wlan_vdev_get_id(vdev)); + return -EINVAL; + } + + adapter = link_info->adapter; + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("null hdd_ctx"); + return -EINVAL; + } + if (qdf_atomic_read(&link_info->session.ap.acs_in_progress)) { + hdd_err("ACS is in-progress"); + return -EAGAIN; + } + wlan_hdd_undo_acs(link_info); + sap_config = &link_info->session.ap.sap_config; + hdd_debug("ACS Config country %s hw_mode %d ACS_BW: %d START_CH: %d END_CH: %d band %d", + hdd_ctx->reg.alpha2, sap_config->acs_cfg.hw_mode, + sap_config->acs_cfg.ch_width, + sap_config->acs_cfg.start_ch_freq, + sap_config->acs_cfg.end_ch_freq, sap_config->acs_cfg.band); + sap_dump_acs_channel(&sap_config->acs_cfg); + + wlan_hdd_cfg80211_start_acs(link_info); + + return 0; +} + +#define ACS_SET_CHAN_LIST_APPEND 0xFF +#define ACS_SNR_NEAR_RANGE_MIN 60 +#define ACS_SNR_MID_RANGE_MIN 30 +#define ACS_SNR_FAR_RANGE_MIN 0 + +/** + * hdd_son_set_acs_channels() - Sets Channels for ACS + * + * @vdev: pointer to object mgr vdev + * @req: target channels + * + * Return: 0 on success + */ +static int hdd_son_set_acs_channels(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_athdbg *req) +{ + struct sap_config *sap_config; + /* Append the new channels with existing channel list */ + bool append; + /* Duplicate */ + bool dup; + uint32_t freq_list[ACS_MAX_CHANNEL_COUNT]; + uint32_t num_channels; + uint32_t chan_idx = 0; + uint32_t tmp; + uint16_t chan_start = 0; + uint16_t i, j; + uint16_t acs_chan_count = 0; + uint32_t *prev_acs_list; + struct ieee80211_chan_def *chans = req->data.user_chanlist.chans; + uint16_t nchans = req->data.user_chanlist.n_chan; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_context *hdd_ctx; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info || !req) { + hdd_err("null adapter or req"); + return -EINVAL; + } + + adapter = link_info->adapter; + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid device mode %d", adapter->device_mode); + return -EINVAL; + } + if (!nchans) { + hdd_err("No channels are sent to be set"); + return -EINVAL; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("null hdd_ctx"); + return -EINVAL; + } + sap_config = &link_info->session.ap.sap_config; + /* initialize with default channels */ + if (hdd_son_init_acs_channels(adapter, hdd_ctx, &sap_config->acs_cfg) + != QDF_STATUS_SUCCESS) { + hdd_err("Failed to start the ACS"); + return -EAGAIN; + } + append = (chans[0].chan == ACS_SET_CHAN_LIST_APPEND); + if (append) { + chan_start = 1; + acs_chan_count = sap_config->acs_cfg.ch_list_count; + } + prev_acs_list = sap_config->acs_cfg.freq_list; + for (i = chan_start; i < nchans; i++) { + tmp = wlan_reg_legacy_chan_to_freq(pdev, chans[i].chan); + if (append) { + for (j = 0; j < acs_chan_count; j++) { + if (prev_acs_list[j] == tmp) { + dup = true; + break; + } + } + } + /* Remove duplicate */ + if (!dup) { + freq_list[chan_idx] = tmp; + chan_idx++; + } else { + dup = false; + } + } + num_channels = chan_idx + acs_chan_count; + sap_config->acs_cfg.ch_list_count = num_channels; + sap_config->acs_cfg.freq_list = + qdf_mem_malloc(num_channels * + sizeof(*sap_config->acs_cfg.freq_list)); + if (!sap_config->acs_cfg.freq_list) { + hdd_err("Error in allocating memory, failed to set channels"); + sap_config->acs_cfg.freq_list = prev_acs_list; + sap_config->acs_cfg.ch_list_count = acs_chan_count; + return -ENOMEM; + } + if (append) + qdf_mem_copy(sap_config->acs_cfg.freq_list, prev_acs_list, + sizeof(uint32_t) * acs_chan_count); + qdf_mem_copy(&sap_config->acs_cfg.freq_list[acs_chan_count], freq_list, + sizeof(uint32_t) * chan_idx); + qdf_mem_free(prev_acs_list); + + return 0; +} + +static enum wlan_band_id +reg_wifi_band_to_wlan_band_id(enum reg_wifi_band reg_wifi_band) +{ + enum wlan_band_id wlan_band; + const uint32_t reg_wifi_band_to_wlan_band_id_map[] = { + [REG_BAND_2G] = WLAN_BAND_2GHZ, + [REG_BAND_5G] = WLAN_BAND_5GHZ, + [REG_BAND_6G] = WLAN_BAND_6GHZ, + [REG_BAND_UNKNOWN] = WLAN_BAND_MAX,}; + + wlan_band = reg_wifi_band_to_wlan_band_id_map[reg_wifi_band]; + if (wlan_band == WLAN_BAND_MAX) { + hdd_err("Invalid wlan_band_id %d, reg_wifi_band: %d", + wlan_band, reg_wifi_band); + return -EINVAL; + } + + return wlan_band; +} + +/** + * get_son_acs_report_values() - Gets ACS report for target channel + * + * @vdev: pointer to object mgr vdev + * @acs_r: pointer to acs_dbg + * @mac_handle: Handle to MAC + * @chan_freq: Channel frequency + * + * Return: void + */ +static void get_son_acs_report_values(struct wlan_objmgr_vdev *vdev, + struct ieee80211_acs_dbg *acs_r, + mac_handle_t mac_handle, + uint16_t chan_freq) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct scan_filter *filter = qdf_mem_malloc(sizeof(*filter)); + struct scan_cache_node *cur_node; + struct scan_cache_entry *se; + enum ieee80211_phymode phymode_se; + struct ieee80211_ie_hecap *hecap_ie; + struct ieee80211_ie_srp_extie *srp_ie; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + uint32_t srps = 0; + qdf_list_t *scan_list = NULL; + uint8_t snr_se, *hecap_phy_ie; + + if (!filter) + return; + filter->num_of_channels = 1; + filter->chan_freq_list[0] = chan_freq; + scan_list = ucfg_scan_get_result(pdev, filter); + acs_r->chan_nbss = qdf_list_size(scan_list); + + acs_r->chan_maxrssi = 0; + acs_r->chan_minrssi = 0; + acs_r->chan_nbss_near = 0; + acs_r->chan_nbss_mid = 0; + acs_r->chan_nbss_far = 0; + acs_r->chan_nbss_srp = 0; + qdf_list_peek_front(scan_list, &cur_lst); + while (cur_lst) { + qdf_list_peek_next(scan_list, cur_lst, &next_lst); + cur_node = qdf_container_of(cur_lst, + struct scan_cache_node, node); + se = cur_node->entry; + snr_se = util_scan_entry_snr(se); + hecap_ie = (struct ieee80211_ie_hecap *) + util_scan_entry_hecap(se); + srp_ie = (struct ieee80211_ie_srp_extie *) + util_scan_entry_spatial_reuse_parameter(se); + phymode_se = util_scan_entry_phymode(se); + + if (hecap_ie) { + hecap_phy_ie = &hecap_ie->hecap_phyinfo[0]; + srps = hecap_phy_ie[HECAP_PHYBYTE_IDX7] & + HECAP_PHY_SRP_SR_BITS; + } + + if (acs_r->chan_maxrssi < snr_se) + acs_r->chan_maxrssi = snr_se; + else if (acs_r->chan_minrssi > snr_se) + acs_r->chan_minrssi = snr_se; + if (snr_se > ACS_SNR_NEAR_RANGE_MIN) + acs_r->chan_nbss_near += 1; + else if (snr_se > ACS_SNR_MID_RANGE_MIN) + acs_r->chan_nbss_mid += 1; + else + acs_r->chan_nbss_far += 1; + if (srp_ie && + (!(srp_ie->sr_control & + IEEE80211_SRP_SRCTRL_OBSS_PD_DISALLOWED_MASK) || srps)) + acs_r->chan_nbss_srp++; + + cur_lst = next_lst; + next_lst = NULL; + } + acs_r->chan_80211_b_duration = sme_get_11b_data_duration(mac_handle, + chan_freq); + acs_r->chan_nbss_eff = 100 + (acs_r->chan_nbss_near * 50) + + (acs_r->chan_nbss_mid * 50) + + (acs_r->chan_nbss_far * 25); + acs_r->chan_srp_load = acs_r->chan_nbss_srp * 4; + acs_r->chan_efficiency = (1000 + acs_r->chan_grade) / + acs_r->chan_nbss_eff; + ucfg_scan_purge_results(scan_list); + + qdf_mem_free(filter); +} + +/** + * hdd_son_get_acs_report() - Gets ACS report + * + * @vdev: pointer to object mgr vdev + * @acs_report: pointer to acs_dbg + * + * Return: 0 on success + */ +static int hdd_son_get_acs_report(struct wlan_objmgr_vdev *vdev, + struct ieee80211_acs_dbg *acs_report) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + uint8_t acs_entry_id = 0; + ACS_LIST_TYPE acs_type = 0; + int ret = 0, i = 0; + struct sap_acs_cfg *acs_cfg; + struct hdd_context *hdd_ctx; + struct ieee80211_acs_dbg *acs_r = NULL; + struct sap_context *sap_ctx; + qdf_size_t not_copied; + + if (!acs_report) { + hdd_err("null acs_report"); + ret = -EINVAL; + goto end; + } + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + ret = -EINVAL; + goto end; + } + + adapter = link_info->adapter; + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Invalid device mode %d", adapter->device_mode); + ret = -EINVAL; + goto end; + } + if (hdd_son_is_acs_in_progress(vdev)) { + acs_report->nchans = 0; + hdd_err("ACS is in-progress"); + ret = -EAGAIN; + goto end; + } + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("null hdd_ctx"); + ret = -EINVAL; + goto end; + } + acs_r = qdf_mem_malloc(sizeof(*acs_r)); + if (!acs_r) { + hdd_err("Failed to allocate memory"); + ret = -ENOMEM; + goto end; + } + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(link_info); + acs_cfg = &link_info->session.ap.sap_config.acs_cfg; + if (!acs_cfg->freq_list && + (hdd_son_init_acs_channels(adapter, hdd_ctx, + acs_cfg) != QDF_STATUS_SUCCESS)) { + hdd_err("Failed to start the ACS"); + ret = -EAGAIN; + goto end_acs_r_free; + } + acs_r->nchans = acs_cfg->ch_list_count; + ret = copy_from_user(&acs_entry_id, &acs_report->entry_id, + sizeof(acs_report->entry_id)); + hdd_debug("acs entry id: %u num of channels: %u", + acs_entry_id, acs_r->nchans); + if (acs_entry_id > acs_r->nchans) { + ret = -EINVAL; + goto end_acs_r_free; + } + ret = copy_from_user(&acs_type, &acs_report->acs_type, + sizeof(acs_report->acs_type)); + + acs_r->acs_status = ACS_DEFAULT; + acs_r->chan_freq = acs_cfg->freq_list[acs_entry_id]; + acs_r->chan_band = reg_wifi_band_to_wlan_band_id + (wlan_reg_freq_to_band(acs_r->chan_freq)); + hdd_debug("acs type: %d", acs_type); + if (acs_type == ACS_CHAN_STATS) { + acs_r->ieee_chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, + acs_r->chan_freq); + acs_r->chan_width = IEEE80211_CWM_WIDTH20; + acs_r->channel_loading = 0; + acs_r->chan_availability = 100; + acs_r->chan_grade = 100; /* as hw_chan_grade is 100 in WIN 8 */ + acs_r->sec_chan = false; + acs_r->chan_radar_noise = + wlansap_is_channel_in_nol_list(sap_ctx, acs_r->chan_freq, + PHY_SINGLE_CHANNEL_CENTERED); + get_son_acs_report_values(vdev, acs_r, hdd_ctx->mac_handle, + acs_r->chan_freq); + acs_r->chan_load = 0; + acs_r->noisefloor = -254; /* NF_INVALID */ + for (i = 0; i < SIR_MAX_NUM_CHANNELS; i++) { + if (hdd_ctx->chan_info[i].freq == acs_r->chan_freq) { + acs_r->noisefloor = + hdd_ctx->chan_info[i].noise_floor; + acs_r->chan_load = + hdd_ctx->chan_info[i].rx_clear_count; + break; + } + } + not_copied = copy_to_user(acs_report, acs_r, sizeof(*acs_r)); + if (not_copied) + hdd_debug("%ul is not copied", not_copied); + } else if (acs_type == ACS_CHAN_NF_STATS) { + } else if (acs_type == ACS_NEIGHBOUR_GET_LIST_COUNT || + acs_type == ACS_NEIGHBOUR_GET_LIST) { + } +end_acs_r_free: + qdf_mem_free(acs_r); +end: + return ret; +} + +static const uint8_t wlanphymode2ieeephymode[WLAN_PHYMODE_MAX] = { + [WLAN_PHYMODE_AUTO] = IEEE80211_MODE_AUTO, + [WLAN_PHYMODE_11A] = IEEE80211_MODE_11A, + [WLAN_PHYMODE_11B] = IEEE80211_MODE_11B, + [WLAN_PHYMODE_11G] = IEEE80211_MODE_11G, + [WLAN_PHYMODE_11G_ONLY] = IEEE80211_MODE_11G, + [WLAN_PHYMODE_11NA_HT20] = IEEE80211_MODE_11NA_HT20, + [WLAN_PHYMODE_11NG_HT20] = IEEE80211_MODE_11NG_HT20, + [WLAN_PHYMODE_11NA_HT40] = IEEE80211_MODE_11NA_HT40, + [WLAN_PHYMODE_11NG_HT40PLUS] = IEEE80211_MODE_11NG_HT40PLUS, + [WLAN_PHYMODE_11NG_HT40MINUS] = IEEE80211_MODE_11NG_HT40MINUS, + [WLAN_PHYMODE_11NG_HT40] = IEEE80211_MODE_11NG_HT40, + [WLAN_PHYMODE_11AC_VHT20] = IEEE80211_MODE_11AC_VHT20, + [WLAN_PHYMODE_11AC_VHT20_2G] = IEEE80211_MODE_11AC_VHT20, + [WLAN_PHYMODE_11AC_VHT40] = IEEE80211_MODE_11AC_VHT40, + [WLAN_PHYMODE_11AC_VHT40PLUS_2G] = IEEE80211_MODE_11AC_VHT40PLUS, + [WLAN_PHYMODE_11AC_VHT40MINUS_2G] = IEEE80211_MODE_11AC_VHT40MINUS, + [WLAN_PHYMODE_11AC_VHT40_2G] = IEEE80211_MODE_11AC_VHT40, + [WLAN_PHYMODE_11AC_VHT80] = IEEE80211_MODE_11AC_VHT80, + [WLAN_PHYMODE_11AC_VHT80_2G] = IEEE80211_MODE_11AC_VHT80, + [WLAN_PHYMODE_11AC_VHT160] = IEEE80211_MODE_11AC_VHT160, + [WLAN_PHYMODE_11AC_VHT80_80] = IEEE80211_MODE_11AC_VHT80_80, + [WLAN_PHYMODE_11AXA_HE20] = IEEE80211_MODE_11AXA_HE20, + [WLAN_PHYMODE_11AXG_HE20] = IEEE80211_MODE_11AXG_HE20, + [WLAN_PHYMODE_11AXA_HE40] = IEEE80211_MODE_11AXA_HE40, + [WLAN_PHYMODE_11AXG_HE40PLUS] = IEEE80211_MODE_11AXG_HE40PLUS, + [WLAN_PHYMODE_11AXG_HE40MINUS] = IEEE80211_MODE_11AXG_HE40MINUS, + [WLAN_PHYMODE_11AXG_HE40] = IEEE80211_MODE_11AXG_HE40, + [WLAN_PHYMODE_11AXA_HE80] = IEEE80211_MODE_11AXA_HE80, + [WLAN_PHYMODE_11AXA_HE160] = IEEE80211_MODE_11AXA_HE160, + [WLAN_PHYMODE_11AXA_HE80_80] = IEEE80211_MODE_11AXA_HE80_80, +#ifdef WLAN_FEATURE_11BE + [WLAN_PHYMODE_11BEA_EHT20] = IEEE80211_MODE_11BEA_EHT20, + [WLAN_PHYMODE_11BEG_EHT20] = IEEE80211_MODE_11BEG_EHT20, + [WLAN_PHYMODE_11BEA_EHT40MINUS] = IEEE80211_MODE_11BEA_EHT40, + [WLAN_PHYMODE_11BEG_EHT40PLUS] = IEEE80211_MODE_11BEG_EHT40PLUS, + [WLAN_PHYMODE_11BEG_EHT40MINUS] = IEEE80211_MODE_11BEG_EHT40MINUS, + [WLAN_PHYMODE_11BEG_EHT40] = IEEE80211_MODE_11BEG_EHT40, + [WLAN_PHYMODE_11BEA_EHT80] = IEEE80211_MODE_11BEA_EHT80, + [WLAN_PHYMODE_11BEG_EHT80] = 0, + [WLAN_PHYMODE_11BEA_EHT160] = IEEE80211_MODE_11BEA_EHT160, + [WLAN_PHYMODE_11BEA_EHT320] = IEEE80211_MODE_11BEA_EHT320, +#endif /* WLAN_FEATURE_11BE */ +}; + +static enum ieee80211_phymode +wlan_hdd_son_get_ieee_phymode(enum wlan_phymode wlan_phymode) +{ + if (wlan_phymode >= WLAN_PHYMODE_MAX) + return IEEE80211_MODE_AUTO; + + return wlanphymode2ieeephymode[wlan_phymode]; +} + +/** + * hdd_son_get_peer_tx_rate() - Get peer tx rate from FW + * @vdev: pointer to object mgr vdev + * @peer_macaddr: peer mac address + * + * Return: tx rate in Kbps + */ +static uint32_t hdd_son_get_peer_tx_rate(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_macaddr) +{ + uint32_t tx_rate = 0; + struct stats_event *stats; + int retval = 0; + + stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(vdev, + peer_macaddr, + &retval); + if (retval || !stats) { + if (stats) + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + hdd_err("Unable to get peer tx rate from fw"); + return tx_rate; + } + + tx_rate = stats->peer_stats_info_ext->tx_rate; + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + + return tx_rate; +} + +static QDF_STATUS hdd_son_get_node_info_sta(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + wlan_node_info *node_info) +{ + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info || + wlan_hdd_validate_context(link_info->adapter->hdd_ctx)) + return QDF_STATUS_E_FAILURE; + + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug_rl("STA VDEV not connected"); + /* Still return success and framework will see default stats */ + return QDF_STATUS_SUCCESS; + } + + node_info->tx_bitrate = hdd_son_get_peer_tx_rate(vdev, mac_addr); + /* convert it to Mbps */ + node_info->tx_bitrate = qdf_do_div(node_info->tx_bitrate, 1000); + hdd_debug_rl("tx_bitrate %u", node_info->tx_bitrate); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS hdd_son_get_node_info_sap(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + wlan_node_info *node_info) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_station_info *sta_info; + enum wlan_phymode peer_phymode; + struct wlan_objmgr_psoc *psoc; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_debug("NULL adapter"); + return QDF_STATUS_E_FAILURE; + } + + adapter = link_info->adapter; + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, mac_addr, + STA_INFO_SON_GET_DATRATE_INFO); + if (!sta_info) { + hdd_err("Sta info is null"); + return QDF_STATUS_E_FAILURE; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + + node_info->tx_bitrate = hdd_son_get_peer_tx_rate(vdev, mac_addr); + /* convert it to Mbps */ + node_info->tx_bitrate = qdf_do_div(node_info->tx_bitrate, 1000); + node_info->max_chwidth = + hdd_chan_width_to_son_chwidth(sta_info->ch_width); + node_info->num_streams = sta_info->nss; + ucfg_mlme_get_peer_phymode(psoc, mac_addr, &peer_phymode); + node_info->phymode = wlan_hdd_son_get_ieee_phymode(peer_phymode); + node_info->max_txpower = ucfg_son_get_tx_power(sta_info->assoc_req_ies); + node_info->max_MCS = sta_info->max_real_mcs_idx; + if (node_info->max_MCS == INVALID_MCS_NSS_INDEX) { + hdd_err("invalid mcs"); + return QDF_STATUS_E_FAILURE; + } + if (sta_info->vht_present) + node_info->is_mu_mimo_supported = + sta_info->vht_caps.vht_cap_info + & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + if (sta_info->ht_present) + node_info->is_static_smps = ((sta_info->ht_caps.cap_info + & IEEE80211_HTCAP_C_SM_MASK) == + IEEE80211_HTCAP_C_SMPOWERSAVE_STATIC); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SON_GET_DATRATE_INFO); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS hdd_son_get_node_info(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + wlan_node_info *node_info) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_debug("NULL adapter"); + return QDF_STATUS_E_FAILURE; + } + + adapter = link_info->adapter; + if (adapter->device_mode == QDF_STA_MODE) + return hdd_son_get_node_info_sta(vdev, mac_addr, node_info); + else if (adapter->device_mode == QDF_SAP_MODE) + return hdd_son_get_node_info_sap(vdev, mac_addr, node_info); + else + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS hdd_son_get_peer_capability(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + wlan_peer_cap *peer_cap) +{ + struct hdd_station_info *sta_info; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + bool b_meas_supported; + QDF_STATUS status; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return QDF_STATUS_E_FAILURE; + } + + adapter = link_info->adapter; + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + peer->macaddr, + STA_INFO_SOFTAP_GET_STA_INFO); + if (!sta_info) { + hdd_err("sta_info NULL"); + return QDF_STATUS_E_FAILURE; + } + + hdd_info("Getting peer capability from sta_info"); + qdf_mem_copy(peer_cap->bssid, vdev->vdev_mlme.macaddr, + QDF_MAC_ADDR_SIZE); + peer_cap->is_BTM_Supported = !!(sta_info->ext_cap & + BIT(19/*BSS_TRANSITION*/)); + peer_cap->is_RRM_Supported = !!(sta_info->capability & + WLAN_CAPABILITY_RADIO_MEASURE); + + peer_cap->band_cap = sta_info->supported_band; + if (sta_info->assoc_req_ies.len) { + status = ucfg_son_get_peer_rrm_info(sta_info->assoc_req_ies, + peer_cap->rrmcaps, + &(b_meas_supported)); + if (status == QDF_STATUS_SUCCESS) + peer_cap->is_beacon_meas_supported = b_meas_supported; + } + if (sta_info->ht_present) + peer_cap->htcap = sta_info->ht_caps.cap_info; + if (sta_info->vht_present) + peer_cap->vhtcap = sta_info->vht_caps.vht_cap_info; + + qdf_mem_zero(&peer_cap->hecap, sizeof(wlan_client_he_capabilities)); + + os_if_son_get_node_datarate_info(vdev, peer->macaddr, + &peer_cap->info); + + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_GET_STA_INFO); + + return QDF_STATUS_SUCCESS; +} + +uint32_t hdd_son_get_peer_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer) +{ + uint32_t ret = 0; + struct hdd_station_info *sta_info = NULL; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + + link_info = wlan_hdd_get_link_info_from_objmgr(vdev); + if (!link_info) { + hdd_err("null adapter"); + return ret; + } + + adapter = link_info->adapter; + sta_info = hdd_get_sta_info_by_mac(&adapter->sta_info_list, + peer->macaddr, + STA_INFO_SOFTAP_GET_STA_INFO); + if (!sta_info) { + hdd_err("sta_info NULL"); + return ret; + } + + ret = sta_info->max_real_mcs_idx; + + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta_info, true, + STA_INFO_SOFTAP_GET_STA_INFO); + hdd_debug("Peer " QDF_MAC_ADDR_FMT " max MCS index: %u", + QDF_MAC_ADDR_REF(peer->macaddr), ret); + + return ret; +} + +/** + * hdd_son_get_sta_stats() - get connected sta rssi and estimated data rate + * @vdev: pointer to vdev + * @mac_addr: connected sta mac addr + * @stats: pointer to ieee80211_nodestats + * + * Return: 0 on success, negative errno on failure + */ +static int hdd_son_get_sta_stats(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + struct ieee80211_nodestats *stats) +{ + struct stats_event *stats_info; + int ret = 0; + + stats_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi( + vdev, mac_addr, &ret); + if (ret || !stats_info) { + hdd_err("get peer rssi fail"); + wlan_cfg80211_mc_cp_stats_free_stats_event(stats_info); + return ret; + } + stats->ns_rssi = stats_info->peer_stats[0].peer_rssi; + stats->ns_last_tx_rate = stats_info->peer_stats[0].tx_rate; + stats->ns_last_rx_rate = stats_info->peer_stats[0].rx_rate; + hdd_debug("sta " QDF_MAC_ADDR_FMT " rssi %d tx %u kbps, rx %u kbps", + QDF_MAC_ADDR_REF(mac_addr), stats->ns_rssi, + stats->ns_last_tx_rate, + stats->ns_last_rx_rate); + wlan_cfg80211_mc_cp_stats_free_stats_event(stats_info); + + return ret; +} + +void hdd_son_register_callbacks(struct hdd_context *hdd_ctx) +{ + struct son_callbacks cb_obj = {0}; + + cb_obj.os_if_is_acs_in_progress = hdd_son_is_acs_in_progress; + cb_obj.os_if_set_chan_ext_offset = hdd_son_set_chan_ext_offset; + cb_obj.os_if_get_chan_ext_offset = hdd_son_get_chan_ext_offset; + cb_obj.os_if_set_bandwidth = hdd_son_set_bandwidth; + cb_obj.os_if_get_bandwidth = hdd_son_get_bandwidth; + cb_obj.os_if_set_chan = hdd_son_set_chan; + cb_obj.os_if_set_acl_policy = hdd_son_set_acl_policy; + cb_obj.os_if_get_acl_policy = hdd_son_get_acl_policy; + cb_obj.os_if_add_acl_mac = hdd_son_add_acl_mac; + cb_obj.os_if_del_acl_mac = hdd_son_del_acl_mac; + cb_obj.os_if_kickout_mac = hdd_son_kickout_mac; + cb_obj.os_if_set_country_code = hdd_son_set_country; + cb_obj.os_if_set_candidate_freq = hdd_son_set_candidate_freq; + cb_obj.os_if_get_candidate_freq = hdd_son_get_candidate_freq; + cb_obj.os_if_set_phymode = hdd_son_set_phymode; + cb_obj.os_if_get_phymode = hdd_son_get_phymode; + cb_obj.os_if_get_rx_nss = hdd_son_get_rx_nss; + cb_obj.os_if_set_chwidth = hdd_son_set_chwidth; + cb_obj.os_if_get_chwidth = hdd_son_get_chwidth; + cb_obj.os_if_deauth_sta = hdd_son_deauth_sta; + cb_obj.os_if_modify_acl = hdd_son_modify_acl; + cb_obj.os_if_get_sta_list = hdd_son_get_sta_list; + cb_obj.os_if_get_sta_space = hdd_son_get_sta_space; + cb_obj.os_if_get_vdev_by_netdev = hdd_son_get_vdev_by_netdev; + cb_obj.os_if_trigger_objmgr_object_creation = + hdd_son_trigger_objmgr_object_creation; + cb_obj.os_if_trigger_objmgr_object_deletion = + hdd_son_trigger_objmgr_object_deletion; + cb_obj.os_if_start_acs = hdd_son_start_acs; + cb_obj.os_if_set_acs_channels = hdd_son_set_acs_channels; + cb_obj.os_if_get_acs_report = hdd_son_get_acs_report; + cb_obj.os_if_get_node_info = hdd_son_get_node_info; + cb_obj.os_if_get_peer_capability = hdd_son_get_peer_capability; + cb_obj.os_if_get_peer_max_mcs_idx = hdd_son_get_peer_max_mcs_idx; + cb_obj.os_if_get_sta_stats = hdd_son_get_sta_stats; + + os_if_son_register_hdd_callbacks(hdd_ctx->psoc, &cb_obj); + + ucfg_son_register_deliver_opmode_cb(hdd_ctx->psoc, + hdd_son_deliver_opmode); + ucfg_son_register_deliver_smps_cb(hdd_ctx->psoc, + hdd_son_deliver_smps); +} + +int hdd_son_deliver_acs_complete_event(struct hdd_adapter *adapter) +{ + int ret = -EINVAL; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_SON_ID); + if (!vdev) { + hdd_err("null vdev"); + return ret; + } + ret = os_if_son_deliver_ald_event(vdev, NULL, MLME_EVENT_ACS_COMPLETE, + NULL); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + return ret; +} + +int hdd_son_deliver_cac_status_event(struct hdd_adapter *adapter, + qdf_freq_t freq, bool radar_detected) +{ + int ret = -EINVAL; + struct wlan_objmgr_vdev *vdev; + struct son_ald_cac_info cac_info; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_SON_ID); + if (!vdev) { + hdd_err("null vdev"); + return ret; + } + cac_info.freq = freq; + cac_info.radar_detected = radar_detected; + ret = os_if_son_deliver_ald_event(vdev, NULL, MLME_EVENT_CAC_STATUS, + &cac_info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + + return ret; +} + +int hdd_son_deliver_assoc_disassoc_event(struct hdd_adapter *adapter, + struct qdf_mac_addr sta_mac, + uint32_t reason_code, + enum assoc_disassoc_event flag) +{ + int ret = -EINVAL; + struct son_ald_assoc_event_info info; + struct wlan_objmgr_vdev *vdev; + + qdf_mem_zero(&info, sizeof(info)); + memcpy(info.macaddr, &sta_mac.bytes, QDF_MAC_ADDR_SIZE); + info.flag = flag; + info.reason = reason_code; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_SON_ID); + if (!vdev) { + hdd_err("null vdev"); + return ret; + } + ret = os_if_son_deliver_ald_event(vdev, NULL, MLME_EVENT_ASSOC_DISASSOC, + &info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + return ret; +} + +void hdd_son_deliver_peer_authorize_event(struct wlan_hdd_link_info *link_info, + uint8_t *peer_mac) +{ + struct wlan_objmgr_peer *peer; + int ret; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + + if (link_info->adapter->device_mode != QDF_SAP_MODE) { + hdd_err("Non SAP vdev"); + return; + } + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_SON_ID); + if (!vdev) { + hdd_err("null vdev"); + return; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + hdd_err("null psoc"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + return; + } + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac, WLAN_UMAC_COMP_SON); + if (!peer) { + hdd_err("No peer object for sta" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + return; + } + + ret = os_if_son_deliver_ald_event(vdev, peer, + MLME_EVENT_CLIENT_ASSOCIATED, NULL); + if (ret) + hdd_err("ALD ASSOCIATED Event failed for" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + + wlan_objmgr_peer_release_ref(peer, WLAN_UMAC_COMP_SON); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); +} + +int hdd_son_deliver_chan_change_event(struct hdd_adapter *adapter, + qdf_freq_t freq) +{ + int ret = -EINVAL; + struct wlan_objmgr_vdev *vdev; + struct son_ald_chan_change_info chan_info; + struct wlan_objmgr_pdev *pdev; + + if (!adapter) { + hdd_err("null adapter"); + return ret; + } + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_SON_ID); + if (!vdev) { + hdd_err("null vdev"); + return ret; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + hdd_err("null pdev"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + return ret; + } + chan_info.freq = freq; + chan_info.chan_num = wlan_reg_freq_to_chan(pdev, freq); + ret = os_if_son_deliver_ald_event(vdev, NULL, + MLME_EVENT_CHAN_CHANGE, + &chan_info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_SON_ID); + + return ret; +} + +int hdd_son_send_set_wifi_generic_command(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb) +{ + return os_if_son_parse_generic_nl_cmd(wiphy, wdev, tb, + OS_IF_SON_VENDOR_SET_CMD); +} + +int hdd_son_send_get_wifi_generic_command(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb) +{ + return os_if_son_parse_generic_nl_cmd(wiphy, wdev, tb, + OS_IF_SON_VENDOR_GET_CMD); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_son.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_son.h new file mode 100644 index 0000000000..c8a59538e1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_son.h @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains son hdd API implementation + */ + +#ifndef WLAN_HDD_SON_H +#define WLAN_HDD_SON_H + +#include +#include + +/* + * Determines type of event sent for MLME_EVENT_ASSOC_DISASSOC + * @ALD_ASSOC_EVENT: event name to send assoc event + * @ALD_DISASSOC_EVENT: event name to send disassoc event + */ +enum assoc_disassoc_event { + ALD_ASSOC_EVENT, + ALD_DISASSOC_EVENT, +}; + +#ifdef WLAN_FEATURE_SON + +/** + * hdd_son_register_callbacks() - register hdd callback for son + * @hdd_ctx: hdd context + * + * Return: void + */ +void hdd_son_register_callbacks(struct hdd_context *hdd_ctx); + +/** + * hdd_son_deliver_acs_complete_event() - send acs complete event to son + * @adapter: adapter object + * + * Return: 0 if event is sent successfully + */ +int hdd_son_deliver_acs_complete_event(struct hdd_adapter *adapter); + +/** + * hdd_son_deliver_cac_status_event() - send cac status to son + * @adapter: adapter object + * @freq: the operating frequency when radar is detected + * @radar_detected: true if radar is detected else false + * + * Return: 0 if event is sent successfully + */ +int hdd_son_deliver_cac_status_event(struct hdd_adapter *adapter, + qdf_freq_t freq, bool radar_detected); + +/** + * hdd_son_deliver_assoc_disassoc_event() - send sta assoc disassoc event + * to son + * @adapter: adapter object + * @sta_mac: Mac address of the sta + * @reason_code: reason code + * @flag: determines the type of event sent(Assoc/disassoc) + * + * Return: 0 if event is sent successfully + */ +int hdd_son_deliver_assoc_disassoc_event(struct hdd_adapter *adapter, + struct qdf_mac_addr sta_mac, + uint32_t reason_code, + enum assoc_disassoc_event flag); +/** + * hdd_son_deliver_peer_authorize_event() - Deliver peer auth event to SON + * @link_info: Link info pointer in HDD adapter + * @peer_mac: Peer mac address + * + * Return: Void + */ +void hdd_son_deliver_peer_authorize_event(struct wlan_hdd_link_info *link_info, + uint8_t *peer_mac); + +/** + * hdd_son_send_set_wifi_generic_command() - Send Generic SET command to SON + * @wiphy: standard kernel wiphy + * @wdev: wireless device + * @tb: NL attributes + * + * Return: 0 on success + */ +int hdd_son_send_set_wifi_generic_command(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb); + +/** + * hdd_son_send_get_wifi_generic_command() - Send Generic GET command to SON + * @wiphy: standard kernel wiphy + * @wdev: wireless device + * @tb: NL attributes + * + * Return: 0 on success + */ +int hdd_son_send_get_wifi_generic_command(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb); + +/** + * hdd_son_get_peer_max_mcs_idx() - Get peer max mcs index + * @vdev: vdev object + * @peer: peer obj + * + * Return: number of max mcs on success or 0 on failure + */ +uint32_t hdd_son_get_peer_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer); + +/** + * hdd_son_deliver_chan_change_event() - send chan change to SON + * @adapter: pointer to adapter + * @freq: new operating channel frequency + * + * Return: 0 on success + */ +int hdd_son_deliver_chan_change_event(struct hdd_adapter *adapter, + qdf_freq_t freq); +#else + +static inline void hdd_son_register_callbacks(struct hdd_context *hdd_ctx) +{ +} + +static inline int + hdd_son_deliver_acs_complete_event(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline int + hdd_son_deliver_cac_status_event(struct hdd_adapter *adapter, + qdf_freq_t freq, bool radar_detected) +{ + return 0; +} + +static inline int + hdd_son_deliver_assoc_disassoc_event(struct hdd_adapter *adapter, + struct qdf_mac_addr sta_mac, + uint32_t reason_code, + enum assoc_disassoc_event flag) +{ + return 0; +} + +static inline void +hdd_son_deliver_peer_authorize_event(struct wlan_hdd_link_info *link_info, + uint8_t *peer_mac) +{ +} + +static inline +int hdd_son_send_set_wifi_generic_command(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb) +{ + return -EINVAL; +} + +static inline +int hdd_son_send_get_wifi_generic_command(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb) +{ + return -EINVAL; +} + +static inline +uint32_t hdd_son_get_peer_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer) +{ + return 0; +} + +static inline +int hdd_son_deliver_chan_change_event(struct hdd_adapter *adapter, + qdf_freq_t freq) +{ + return 0; +} +#endif /* WLAN_FEATURE_SON */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_spectralscan.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_spectralscan.c new file mode 100644 index 0000000000..641d1516c4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_spectralscan.c @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_spectral_scan.c + * + * WLAN Host Device Driver Spectral Scan Implementation + */ + +#include +#include +#include +#include +#include "osif_sync.h" +#include "wlan_hdd_includes.h" +#include "cds_api.h" +#include "ani_global.h" +#include "wlan_cfg80211_spectral.h" +#include "wlan_hdd_spectralscan.h" +#include +#include "wma.h" +#include "wlan_hdd_object_manager.h" +#ifdef CNSS_GENL +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss_nl.h" +#else +#include +#endif +#endif + +/** + * __wlan_hdd_cfg80211_spectral_scan_start() - start spectral scan + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function starts spectral scan + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_spectral_scan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ret = hdd_validate_adapter(adapter); + if (ret) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SPECTRAL_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + wlan_spectral_update_rx_chainmask(adapter->deflink); + ret = wlan_cfg80211_spectral_scan_config_and_start(wiphy, hdd_ctx->pdev, + vdev, data, + data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + hdd_exit(); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_spectral_scan_stop() - stop spectral scan + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function stops spectral scan + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_spectral_scan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ret = hdd_validate_adapter(adapter); + if (ret) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SPECTRAL_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + ret = wlan_cfg80211_spectral_scan_stop(wiphy, hdd_ctx->pdev, + vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + hdd_exit(); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_spectral_scan_get_config() - spectral scan get config + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function to get the spectral scan configuration + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_spectral_scan_get_config( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ret = hdd_validate_adapter(adapter); + if (ret) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SPECTRAL_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + ret = wlan_cfg80211_spectral_scan_get_config(wiphy, hdd_ctx->pdev, + vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + hdd_exit(); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_spectral_scan_get_diag_stats() - get diag stats + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets the spectral scan diag stats + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_spectral_scan_get_diag_stats( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ret = hdd_validate_adapter(adapter); + if (ret) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SPECTRAL_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + ret = wlan_cfg80211_spectral_scan_get_diag_stats( + wiphy, hdd_ctx->pdev, + vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + hdd_exit(); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_spectral_scan_get_cap_info() - get spectral caps + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets spectral scan configured capabilities + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_spectral_scan_get_cap_info( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ret = hdd_validate_adapter(adapter); + if (ret) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SPECTRAL_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + ret = wlan_cfg80211_spectral_scan_get_cap(wiphy, hdd_ctx->pdev, + vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + hdd_exit(); + + return ret; +} + +/* + * __wlan_hdd_cfg80211_spectral_scan_get_status() - get spectral scan + * status + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * This function gets current status of spectral scan + * + * Return: 0 on success and errno on failure + */ +static int __wlan_hdd_cfg80211_spectral_scan_get_status( + struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + ret = hdd_validate_adapter(adapter); + if (ret) + return ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_SPECTRAL_ID); + if (!vdev) { + hdd_err("can't get vdev"); + return -EINVAL; + } + ret = wlan_cfg80211_spectral_scan_get_status(wiphy, hdd_ctx->pdev, + vdev, data, data_len); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + hdd_exit(); + + return ret; +} + +int wlan_hdd_cfg80211_spectral_scan_start(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_spectral_scan_start(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int wlan_hdd_cfg80211_spectral_scan_stop(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_spectral_scan_stop(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int wlan_hdd_cfg80211_spectral_scan_get_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_spectral_scan_get_config(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int wlan_hdd_cfg80211_spectral_scan_get_diag_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_spectral_scan_get_diag_stats(wiphy, wdev, + data, + data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int wlan_hdd_cfg80211_spectral_scan_get_cap_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_spectral_scan_get_cap_info(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +int wlan_hdd_cfg80211_spectral_scan_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_spectral_scan_get_status(wiphy, wdev, + data, data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +void hdd_spectral_register_to_dbr(struct hdd_context *hdd_ctx) +{ + ucfg_spectral_register_to_dbr(hdd_ctx->pdev); +} + +#if defined(CNSS_GENL) && defined(WLAN_CONV_SPECTRAL_ENABLE) +static void send_spectral_scan_reg_rsp_msg(struct hdd_context *hdd_ctx) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct spectral_scan_msg_v *rsp_msg; + int err; + + skb = alloc_skb(NLMSG_SPACE(sizeof(struct spectral_scan_msg_v)), + GFP_KERNEL); + if (!skb) { + hdd_err("Skb allocation failed"); + return; + } + + nlh = (struct nlmsghdr *)skb->data; + nlh->nlmsg_pid = 0; + nlh->nlmsg_flags = 0; + nlh->nlmsg_seq = 0; + nlh->nlmsg_type = WLAN_NL_MSG_SPECTRAL_SCAN; + + rsp_msg = NLMSG_DATA(nlh); + rsp_msg->msg_type = SPECTRAL_SCAN_REGISTER_RSP; + rsp_msg->pid = hdd_ctx->sscan_pid; + ucfg_spectral_get_version(hdd_ctx->pdev, &rsp_msg->version, + &rsp_msg->sub_version); + + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct spectral_scan_msg_v)); + skb_put(skb, NLMSG_SPACE(sizeof(struct spectral_scan_msg_v))); + + hdd_info("sending App Reg Response to process pid %d", + hdd_ctx->sscan_pid); + + err = nl_srv_ucast(skb, hdd_ctx->sscan_pid, MSG_DONTWAIT, + WLAN_NL_MSG_SPECTRAL_SCAN, CLD80211_MCGRP_OEM_MSGS); + + if (err < 0) + hdd_err("SPECTRAL: failed to send to spectral scan reg" + " response"); +} + +/** + * __spectral_scan_msg_handler() - API to handle spectral scan command + * @data: Data received + * @data_len: length of the data received + * @ctx: Pointer to stored context + * @pid: Process ID + * + * API to handle spectral scan commands from user space + * + * Return: None + */ +static void __spectral_scan_msg_handler(const void *data, int data_len, + void *ctx, int pid) +{ + struct spectral_scan_msg *ss_msg = NULL; + struct nlattr *tb[CLD80211_ATTR_MAX + 1]; + struct hdd_context *hdd_ctx; + int ret; + + hdd_ctx = (struct hdd_context *)cds_get_context(QDF_MODULE_ID_HDD); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return; + + /* + * audit note: it is ok to pass a NULL policy here since only + * one attribute is parsed and it is explicitly validated + */ + if (wlan_cfg80211_nla_parse(tb, CLD80211_ATTR_MAX, data, + data_len, NULL)) { + hdd_err("nla parse fails"); + return; + } + + if (!tb[CLD80211_ATTR_DATA]) { + hdd_err("attr VENDOR_DATA fails"); + return; + } + + if (nla_len(tb[CLD80211_ATTR_DATA]) < sizeof(*ss_msg)) { + hdd_err_rl("Invalid length for ATTR_DATA"); + return; + } + + ss_msg = (struct spectral_scan_msg *)nla_data(tb[CLD80211_ATTR_DATA]); + + if (!ss_msg) { + hdd_err("data NULL"); + return; + } + + switch (ss_msg->msg_type) { + case SPECTRAL_SCAN_REGISTER_REQ: + hdd_ctx->sscan_pid = ss_msg->pid; + hdd_debug("spectral scan application registered, pid=%d", + hdd_ctx->sscan_pid); + send_spectral_scan_reg_rsp_msg(hdd_ctx); + ucfg_spectral_scan_set_ppid(hdd_ctx->pdev, + hdd_ctx->sscan_pid); + break; + default: + hdd_warn("invalid message type %d", ss_msg->msg_type); + break; + } +} + +static void spectral_scan_msg_handler(const void *data, int data_len, + void *ctx, int pid) +{ + struct device *dev = ctx; + struct osif_psoc_sync *psoc_sync; + + if (osif_psoc_sync_op_start(dev, &psoc_sync)) + return; + + __spectral_scan_msg_handler(data, data_len, ctx, pid); + + osif_psoc_sync_op_stop(psoc_sync); +} + +void spectral_scan_activate_service(struct hdd_context *hdd_ctx) +{ + register_cld_cmd_cb(WLAN_NL_MSG_SPECTRAL_SCAN, + spectral_scan_msg_handler, hdd_ctx->parent_dev); +} + +void spectral_scan_deactivate_service(void) +{ + deregister_cld_cmd_cb(WLAN_NL_MSG_SPECTRAL_SCAN); +} + +QDF_STATUS +wlan_spectral_update_rx_chainmask(struct wlan_hdd_link_info *link_info) +{ + uint32_t chainmask_2g = 0; + uint32_t chainmask_5g = 0; + uint32_t chainmask; + qdf_freq_t home_chan_freq; + uint8_t pdev_id; + struct wlan_objmgr_vdev *vdev; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + home_chan_freq = hdd_get_link_info_home_channel(link_info); + pdev_id = wlan_objmgr_pdev_get_pdev_id(hdd_ctx->pdev); + wma_get_rx_chainmask(pdev_id, &chainmask_2g, &chainmask_5g); + chainmask = chainmask_5g; + + if (wlan_reg_is_24ghz_ch_freq(home_chan_freq)) + chainmask = chainmask_2g; + + hdd_debug("chan freq %d chainmask %d", home_chan_freq, chainmask); + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_SPECTRAL_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + wlan_vdev_mlme_set_rxchainmask(vdev, chainmask); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_SPECTRAL_ID); + + return QDF_STATUS_SUCCESS; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sta_info.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sta_info.c new file mode 100644 index 0000000000..ef5114f579 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sta_info.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sta_info.c + * + * Store and manage station info structure. + * + */ + +#include +#include "wlan_hdd_sta_info.h" + +#define HDD_MAX_PEERS 32 + +char *sta_info_string_from_dbgid(wlan_sta_info_dbgid id) +{ + static const char *strings[] = { + "STA_INFO_ID_RESERVED", + "STA_INFO_CFG80211_GET_LINK_PROPERTIES", + "STA_INFO_SOFTAP_INSPECT_TX_EAP_PKT", + "STA_INFO_SOFTAP_CHECK_WAIT_FOR_TX_EAP_PKT", + "STA_INFO_SOFTAP_INSPECT_DHCP_PACKET", + "STA_INFO_SOFTAP_HARD_START_XMIT", + "STA_INFO_SOFTAP_INIT_TX_RX_STA", + "STA_INFO_SOFTAP_RX_PACKET_CBK", + "STA_INFO_SOFTAP_REGISTER_STA", + "STA_INFO_GET_CACHED_STATION_REMOTE", + "STA_INFO_HDD_GET_STATION_REMOTE", + "STA_INFO_WLAN_HDD_CFG80211_GET_STATION", + "STA_INFO_SOFTAP_DEAUTH_CURRENT_STA", + "STA_INFO_SOFTAP_DEAUTH_ALL_STA", + "STA_INFO_CFG80211_DEL_STATION", + "STA_INFO_HDD_CLEAR_ALL_STA", + "STA_INFO_FILL_STATION_INFO", + "STA_INFO_HOSTAPD_SAP_EVENT_CB", + "STA_INFO_SAP_INDICATE_DISCONNECT_FOR_STA", + "STA_INFO_IS_PEER_ASSOCIATED", + "STA_INFO_SAP_SET_TWO_INTS_GETNONE", + "STA_INFO_SAP_GETASSOC_STAMACADDR", + "STA_INFO_SOFTAP_GET_STA_INFO", + "STA_INFO_GET_SOFTAP_LINKSPEED", + "STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR", + "STA_INFO_SOFTAP_STOP_BSS", + "STA_INFO_SOFTAP_CHANGE_STA_STATE", + "STA_INFO_CLEAR_CACHED_STA_INFO", + "STA_INFO_ATTACH_DETACH", + "STA_INFO_SHOW", + "STA_INFO_SOFTAP_IPA_RX_PKT_CALLBACK", + "STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION", + "STA_INFO_SON_GET_DATRATE_INFO", + "STA_INFO_ID_MAX"}; + int32_t num_dbg_strings = QDF_ARRAY_SIZE(strings); + + if (id >= num_dbg_strings) { + char *ret = ""; + + hdd_err("Debug string not found for debug id %d", id); + return ret; + } + + return (char *)strings[id]; +} + +QDF_STATUS hdd_sta_info_init(struct hdd_sta_info_obj *sta_info_container) +{ + if (!sta_info_container) { + hdd_err("Parameter null"); + return QDF_STATUS_E_INVAL; + } + + qdf_spinlock_create(&sta_info_container->sta_obj_lock); + qdf_list_create(&sta_info_container->sta_obj, HDD_MAX_PEERS); + + return QDF_STATUS_SUCCESS; +} + +void hdd_sta_info_deinit(struct hdd_sta_info_obj *sta_info_container) +{ + if (!sta_info_container) { + hdd_err("Parameter null"); + return; + } + + qdf_list_destroy(&sta_info_container->sta_obj); + qdf_spinlock_destroy(&sta_info_container->sta_obj_lock); +} + +QDF_STATUS hdd_sta_info_attach(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *sta_info) +{ + if (!sta_info_container || !sta_info) { + hdd_err("Parameter(s) null"); + return QDF_STATUS_E_INVAL; + } + + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + hdd_take_sta_info_ref(sta_info_container, sta_info, false, + STA_INFO_ATTACH_DETACH); + qdf_list_insert_front(&sta_info_container->sta_obj, + &sta_info->sta_node); + sta_info->is_attached = true; + + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + + return QDF_STATUS_SUCCESS; +} + +void hdd_sta_info_detach(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info **sta_info) +{ + struct hdd_station_info *info; + + if (!sta_info_container || !sta_info) { + hdd_err("Parameter(s) null"); + return; + } + + info = *sta_info; + + if (!info) + return; + + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + if (info->is_attached) { + info->is_attached = false; + hdd_put_sta_info_ref(sta_info_container, sta_info, false, + STA_INFO_ATTACH_DETACH); + } else { + hdd_info("Stainfo is already detached"); + } + + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); +} + +struct hdd_station_info *hdd_get_sta_info_by_id( + struct hdd_sta_info_obj *sta_info_container, + const int idx, + wlan_sta_info_dbgid sta_info_dbgid) +{ + struct hdd_station_info *sta_info = NULL; + int i = 0; + + if (!sta_info_container) { + hdd_err("Parameter(s) null"); + return NULL; + } + + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + qdf_list_for_each(&sta_info_container->sta_obj, sta_info, sta_node) { + if (qdf_is_macaddr_broadcast(&sta_info->sta_mac)) + continue; + if (i == idx) { + hdd_take_sta_info_ref(sta_info_container, + sta_info, false, sta_info_dbgid); + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + return sta_info; + } + i++; + } + + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + + return NULL; +} + +struct hdd_station_info *hdd_get_sta_info_by_mac( + struct hdd_sta_info_obj *sta_info_container, + const uint8_t *mac_addr, + wlan_sta_info_dbgid sta_info_dbgid) +{ + struct hdd_station_info *sta_info = NULL; + + if (!mac_addr || !sta_info_container || + qdf_is_macaddr_zero((struct qdf_mac_addr *)mac_addr)) { + hdd_err("Parameter(s) null"); + return NULL; + } + + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + qdf_list_for_each(&sta_info_container->sta_obj, sta_info, sta_node) { + if (qdf_is_macaddr_equal(&sta_info->sta_mac, + (struct qdf_mac_addr *)mac_addr) || + qdf_is_macaddr_equal(&sta_info->mld_addr, + (struct qdf_mac_addr *)mac_addr)) { + hdd_take_sta_info_ref(sta_info_container, + sta_info, false, sta_info_dbgid); + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + return sta_info; + } + } + + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + + return NULL; +} + +void hdd_take_sta_info_ref(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *sta_info, + bool lock_required, + wlan_sta_info_dbgid sta_info_dbgid) +{ + if (!sta_info_container || !sta_info) { + hdd_err("Parameter(s) null"); + return; + } + + if (sta_info_dbgid >= STA_INFO_ID_MAX) { + hdd_err("Invalid sta_info debug id %d", sta_info_dbgid); + return; + } + + if (lock_required) + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + qdf_atomic_inc(&sta_info->ref_cnt); + qdf_atomic_inc(&sta_info->ref_cnt_dbgid[sta_info_dbgid]); + + if (lock_required) + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); +} + +void +hdd_put_sta_info_ref(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info **sta_info, bool lock_required, + wlan_sta_info_dbgid sta_info_dbgid) +{ + struct hdd_station_info *info; + struct qdf_mac_addr addr; + + if (!sta_info_container || !sta_info) { + hdd_err("Parameter(s) null"); + return; + } + + info = *sta_info; + + if (!info) { + hdd_err("station info NULL"); + return; + } + + if (sta_info_dbgid >= STA_INFO_ID_MAX) { + hdd_err("Invalid sta_info debug id %d", sta_info_dbgid); + return; + } + + if (lock_required) + qdf_spin_lock_bh(&sta_info_container->sta_obj_lock); + + /* + * In case the put_ref is called more than twice for a single take_ref, + * this will result in either a BUG or page fault. In both the cases, + * the root cause would be known and the buggy put_ref can be taken + * care of. + */ + if (!qdf_atomic_read(&info->ref_cnt_dbgid[sta_info_dbgid])) { + hdd_err("Sta_info ref count put is detected without get for debug id %s", + sta_info_string_from_dbgid(sta_info_dbgid)); + + QDF_BUG(0); + } + + qdf_atomic_dec(&info->ref_cnt); + qdf_atomic_dec(&info->ref_cnt_dbgid[sta_info_dbgid]); + + if (qdf_atomic_read(&info->ref_cnt)) { + if (lock_required) + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + return; + } + + qdf_copy_macaddr(&addr, &info->sta_mac); + if (info->assoc_req_ies.len) { + qdf_mem_free(info->assoc_req_ies.ptr); + info->assoc_req_ies.ptr = NULL; + info->assoc_req_ies.len = 0; + } + + qdf_list_remove_node(&sta_info_container->sta_obj, &info->sta_node); + qdf_mem_free(info); + *sta_info = NULL; + + if (lock_required) + qdf_spin_unlock_bh(&sta_info_container->sta_obj_lock); + + hdd_nofl_debug("STA_INFO: " QDF_MAC_ADDR_FMT " freed", + QDF_MAC_ADDR_REF(addr.bytes)); +} + +void hdd_clear_cached_sta_info(struct hdd_adapter *adapter) +{ + struct hdd_station_info *sta_info = NULL, *tmp = NULL; + + if (!adapter) { + hdd_err("Parameter null"); + return; + } + + hdd_for_each_sta_ref_safe(adapter->cache_sta_info_list, sta_info, tmp, + STA_INFO_CLEAR_CACHED_STA_INFO) { + hdd_sta_info_detach(&adapter->cache_sta_info_list, &sta_info); + hdd_put_sta_info_ref(&adapter->cache_sta_info_list, &sta_info, + true, STA_INFO_CLEAR_CACHED_STA_INFO); + } +} + +QDF_STATUS +hdd_get_front_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info **out_sta_info) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + *out_sta_info = NULL; + + status = qdf_list_peek_front(&sta_info_container->sta_obj, &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_sta_info = + qdf_container_of(node, struct hdd_station_info, sta_node); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +hdd_get_next_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *current_sta_info, + struct hdd_station_info **out_sta_info) +{ + QDF_STATUS status; + qdf_list_node_t *node; + + if (!current_sta_info) + return QDF_STATUS_E_INVAL; + + *out_sta_info = NULL; + + status = qdf_list_peek_next(&sta_info_container->sta_obj, + ¤t_sta_info->sta_node, + &node); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + + *out_sta_info = + qdf_container_of(node, struct hdd_station_info, sta_node); + + return QDF_STATUS_SUCCESS; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sta_info.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sta_info.h new file mode 100644 index 0000000000..8703d7c4cd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sta_info.h @@ -0,0 +1,569 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sta_info.h + * + * Store and manage station info structure. + * + */ +#if !defined(__WLAN_HDD_STA_INFO_H) +#define __WLAN_HDD_STA_INFO_H + +#include +#include "qdf_lock.h" +#include "qdf_types.h" +#include "qdf_list.h" +#include "sap_api.h" +#include "cdp_txrx_cmn_struct.h" +#include "sir_mac_prot_def.h" +#include +#include + +/* Opaque handle for abstraction */ +#define hdd_sta_info_entry qdf_list_node_t + +/** + * enum dhcp_phase - Per Peer DHCP Phases + * @DHCP_PHASE_ACK: upon receiving DHCP_ACK/NAK message in REQUEST phase or + * DHCP_DELINE message in OFFER phase + * @DHCP_PHASE_DISCOVER: upon receiving DHCP_DISCOVER message in ACK phase + * @DHCP_PHASE_OFFER: upon receiving DHCP_OFFER message in DISCOVER phase + * @DHCP_PHASE_REQUEST: upon receiving DHCP_REQUEST message in OFFER phase or + * ACK phase (Renewal process) + */ +enum dhcp_phase { + DHCP_PHASE_ACK, + DHCP_PHASE_DISCOVER, + DHCP_PHASE_OFFER, + DHCP_PHASE_REQUEST +}; + +/** + * enum dhcp_nego_status - Per Peer DHCP Negotiation Status + * @DHCP_NEGO_STOP: when the peer is in ACK phase or client disassociated + * @DHCP_NEGO_IN_PROGRESS: when the peer is in DISCOVER or REQUEST + * (Renewal process) phase + */ +enum dhcp_nego_status { + DHCP_NEGO_STOP, + DHCP_NEGO_IN_PROGRESS +}; + +/* + * Pending frame type of EAP_FAILURE, bit number used in "pending_eap_frm_type" + * of sta_info. + */ +#define PENDING_TYPE_EAP_FAILURE 0 + +/** + * enum wlan_sta_info_dbgid - sta info put/get debug id + * @STA_INFO_ID_RESERVED: Reserved + * @STA_INFO_CFG80211_GET_LINK_PROPERTIES: Get link properties + * @STA_INFO_SOFTAP_INSPECT_TX_EAP_PKT: Inspect the EAP-Failure + * @STA_INFO_SOFTAP_CHECK_WAIT_FOR_TX_EAP_PKT: Check and wait for eap failure + * pkt tx completion + * @STA_INFO_SOFTAP_INSPECT_DHCP_PACKET: Inspect DHCP packet + * @STA_INFO_SOFTAP_HARD_START_XMIT: Transmit a frame + * @STA_INFO_SOFTAP_INIT_TX_RX_STA: Initialize Tx/Rx for a softap station + * @STA_INFO_SOFTAP_RX_PACKET_CBK: Receive packet handler + * @STA_INFO_SOFTAP_REGISTER_STA: Register a SoftAP STA + * @STA_INFO_GET_CACHED_STATION_REMOTE: Get cached peer's info + * @STA_INFO_HDD_GET_STATION_REMOTE: Get remote peer's info + * @STA_INFO_WLAN_HDD_CFG80211_GET_STATION: NL80211_CMD_GET_STATION handler for + * SoftAP + * @STA_INFO_SOFTAP_DEAUTH_CURRENT_STA: Deauth current sta + * @STA_INFO_SOFTAP_DEAUTH_ALL_STA: Deauth all sta in the sta list + * @STA_INFO_CFG80211_DEL_STATION: CFG80211 del station handler + * @STA_INFO_HDD_CLEAR_ALL_STA: Clear all stations + * @STA_INFO_FILL_STATION_INFO: Fill stainfo for connected station + * @STA_INFO_HOSTAPD_SAP_EVENT_CB: SAP event handler + * @STA_INFO_SAP_INDICATE_DISCONNECT_FOR_STA: Indicating disconnect indication + * to the supplicant + * @STA_INFO_IS_PEER_ASSOCIATED: Is peer connected to softap + * @STA_INFO_SAP_SET_TWO_INTS_GETNONE: Generic "set two integer" ioctl handler + * @STA_INFO_SAP_GETASSOC_STAMACADDR: Handler to get assoc station mac address + * @STA_INFO_SOFTAP_GET_STA_INFO: Get station info handler + * @STA_INFO_GET_SOFTAP_LINKSPEED: Get link speed handler + * @STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR: Check adapter connection based on + * device mode + * @STA_INFO_SOFTAP_STOP_BSS: Stop BSS + * @STA_INFO_SOFTAP_CHANGE_STA_STATE: Change the state of a SoftAP station + * @STA_INFO_CLEAR_CACHED_STA_INFO: Clear the cached sta info + * @STA_INFO_ATTACH_DETACH: Station info attach/detach + * @STA_INFO_SHOW: Station info show + * @STA_INFO_SOFTAP_IPA_RX_PKT_CALLBACK: Update rx mcbc stats for IPA case + * @STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION: NL80211_CMD_GET_STATION dumpit + * handler for SoftAP + * @STA_INFO_SON_GET_DATRATE_INFO: gets datarate info for a SON node + * @STA_INFO_ID_MAX: Number of enumerators + */ +/* + * New value added to the enum must also be reflected in function + * sta_info_string_from_dbgid() + */ +typedef enum { + STA_INFO_ID_RESERVED = 0, + STA_INFO_CFG80211_GET_LINK_PROPERTIES = 1, + STA_INFO_SOFTAP_INSPECT_TX_EAP_PKT = 2, + STA_INFO_SOFTAP_CHECK_WAIT_FOR_TX_EAP_PKT = 3, + STA_INFO_SOFTAP_INSPECT_DHCP_PACKET = 4, + STA_INFO_SOFTAP_HARD_START_XMIT = 5, + STA_INFO_SOFTAP_INIT_TX_RX_STA = 6, + STA_INFO_SOFTAP_RX_PACKET_CBK = 7, + STA_INFO_SOFTAP_REGISTER_STA = 8, + STA_INFO_GET_CACHED_STATION_REMOTE = 9, + STA_INFO_HDD_GET_STATION_REMOTE = 10, + STA_INFO_WLAN_HDD_CFG80211_GET_STATION = 11, + STA_INFO_SOFTAP_DEAUTH_CURRENT_STA = 12, + STA_INFO_SOFTAP_DEAUTH_ALL_STA = 13, + STA_INFO_CFG80211_DEL_STATION = 14, + STA_INFO_HDD_CLEAR_ALL_STA = 15, + STA_INFO_FILL_STATION_INFO = 16, + STA_INFO_HOSTAPD_SAP_EVENT_CB = 17, + STA_INFO_SAP_INDICATE_DISCONNECT_FOR_STA = 18, + STA_INFO_IS_PEER_ASSOCIATED = 19, + STA_INFO_SAP_SET_TWO_INTS_GETNONE = 20, + STA_INFO_SAP_GETASSOC_STAMACADDR = 21, + STA_INFO_SOFTAP_GET_STA_INFO = 22, + STA_INFO_GET_SOFTAP_LINKSPEED = 23, + STA_INFO_CONNECTION_IN_PROGRESS_ITERATOR = 24, + STA_INFO_SOFTAP_STOP_BSS = 25, + STA_INFO_SOFTAP_CHANGE_STA_STATE = 26, + STA_INFO_CLEAR_CACHED_STA_INFO = 27, + STA_INFO_ATTACH_DETACH = 28, + STA_INFO_SHOW = 29, + STA_INFO_SOFTAP_IPA_RX_PKT_CALLBACK = 30, + STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION = 31, + STA_INFO_SON_GET_DATRATE_INFO = 32, + STA_INFO_ID_MAX, +} wlan_sta_info_dbgid; + +/** + * sta_info_string_from_dbgid() - Convert dbgid to respective string + * @id: debug id + * + * Debug support function to convert dbgid to string. + * Please note to add new string in the array at index equal to + * its enum value in wlan_sta_info_dbgid. + */ +char *sta_info_string_from_dbgid(wlan_sta_info_dbgid id); + +/** + * struct hdd_station_info - Per station structure kept in HDD for + * multiple station support for SoftAP + * @sta_node: The sta_info node for the station info list maintained in adapter + * @in_use: Is the station entry in use? + * @sta_id: Station ID reported back from HAL (through SAP). + * Broadcast uses station ID zero by default. + * @sta_type: Type of station i.e. p2p client or infrastructure station + * @sta_mac: MAC address of the station + * @mld_addr: MLD address of the station + * @peer_state: Current Station state so HDD knows how to deal with packet + * queue. Most recent states used to change TLSHIM STA state. + * @is_qos_enabled: Track QoS status of station + * @is_deauth_in_progress: The station entry for which Deauth is in progress + * @nss: Number of spatial streams supported + * @rate_flags: Rate Flags for this connection + * @ecsa_capable: Extended CSA capabilities + * @ext_cap: The first 4 bytes of Extended capabilities IE + * @supported_band: sta band capabilities bitmap from supporting opclass + * @max_phy_rate: Calcuated maximum phy rate based on mode, nss, mcs etc. + * @tx_packets: The number of frames from host to firmware + * @tx_bytes: Bytes send to current station + * @rx_packets: Packets received from current station + * @rx_bytes: Bytes received from current station + * @last_tx_rx_ts: Last tx/rx timestamp with current station + * @assoc_ts: Current station association timestamp + * @disassoc_ts: Current station disassociation timestamp + * @tx_rate: Tx rate with current station reported from F/W + * @rx_rate: Rx rate with current station reported from F/W + * @ampdu: Ampdu enable or not of the station + * @sgi_enable: Short GI enable or not of the station + * @guard_interval: Guard interval + * @tx_stbc: Tx Space-time block coding enable/disable + * @rx_stbc: Rx Space-time block coding enable/disable + * @ch_width: Channel Width of the connection + * @mode: Mode of the connection + * @max_supp_idx: Max supported rate index of the station + * @max_ext_idx: Max extended supported rate index of the station + * @max_mcs_idx: Max supported mcs index from ht cap of the station + * @max_real_mcs_idx: Max supported mcs index from biggest cap of the station. + * For example, if station supports HE , first check he cap, + * then vht cap and so on. + * @rx_mcs_map: VHT Rx mcs map + * @tx_mcs_map: VHT Tx mcs map + * @freq : Frequency of the current station + * @dot11_mode: 802.11 Mode of the connection + * @ht_present: HT caps present or not in the current station + * @vht_present: VHT caps present or not in the current station + * @ht_caps: HT capabilities of current station + * @vht_caps: VHT capabilities of current station + * @reason_code: Disconnection reason code for current station + * @rssi: RSSI of the current station reported from F/W + * @dhcp_phase: Current phase of DHCP + * @dhcp_nego_status: Status of DHCP negotiation + * @capability: Capability information of current station + * @support_mode: Max supported mode of a station currently + * connected to sap + * @rx_retry_cnt: Number of rx retries received from current station + * Currently this feature is not supported from FW + * @rx_mc_bc_cnt: Multicast broadcast packet count received from + * current station + * MSB of rx_mc_bc_cnt indicates whether FW supports rx_mc_bc_cnt + * feature or not, if first bit is 1 it indicates that FW supports this + * feature, if it is 0 it indicates FW doesn't support this feature + * @tx_retry_succeed: the number of frames retried but successfully transmit + * @tx_retry_exhaust: the number of frames retried but finally failed + * from host to firmware + * @tx_total_fw: the number of all frames from firmware to remote station + * @tx_retry_fw: the number of retried frames from firmware to remote station + * @tx_retry_exhaust_fw: the number of frames retried but finally failed from + * firmware to remote station + * @rx_fcs_count: the number of frames received with fcs error + * @assoc_req_ies: Assoc request IEs of the peer station + * @ref_cnt: Reference count to synchronize sta_info access + * @ref_cnt_dbgid: Reference count to debug sta_info synchronization issues + * @pending_eap_frm_type: EAP frame type in tx queue without tx completion + * @is_attached: Flag to check if the stainfo is attached/detached + * @peer_rssi_per_chain: Average value of RSSI (dbm) per chain + * @num_tx_rate_count: Num tx rate count for current peer + * @num_rx_rate_count: Num rx rate count for current peer + * @tx_pkt_per_mcs: Number of tx rate counts for each MCS + * @rx_pkt_per_mcs: Number of rx rate counts for each MCS + * @vlan_id: VLAN id + */ +struct hdd_station_info { + qdf_list_node_t sta_node; + bool in_use; + uint8_t sta_id; + eStationType sta_type; + struct qdf_mac_addr sta_mac; + struct qdf_mac_addr mld_addr; + enum ol_txrx_peer_state peer_state; + bool is_qos_enabled; + bool is_deauth_in_progress; + uint8_t nss; + uint32_t rate_flags; + uint8_t ecsa_capable; + uint32_t ext_cap; + uint8_t supported_band; + uint32_t max_phy_rate; + uint32_t tx_packets; + uint64_t tx_bytes; + uint32_t rx_packets; + uint64_t rx_bytes; + qdf_time_t last_tx_rx_ts; + qdf_time_t assoc_ts; + qdf_time_t disassoc_ts; + uint32_t tx_rate; + uint32_t rx_rate; + bool ampdu; + bool sgi_enable; + enum txrate_gi guard_interval; + bool tx_stbc; + bool rx_stbc; + tSirMacHTChannelWidth ch_width; + uint8_t mode; + uint8_t max_supp_idx; + uint8_t max_ext_idx; + uint8_t max_mcs_idx; + uint8_t max_real_mcs_idx; + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + uint32_t freq; + uint8_t dot11_mode; + bool ht_present; + bool vht_present; + struct ieee80211_ht_cap ht_caps; + struct ieee80211_vht_cap vht_caps; + uint32_t reason_code; + int8_t rssi; + enum dhcp_phase dhcp_phase; + enum dhcp_nego_status dhcp_nego_status; + uint16_t capability; + uint8_t support_mode; + uint32_t rx_retry_cnt; + uint32_t rx_mc_bc_cnt; + uint32_t tx_retry_succeed; + uint32_t tx_retry_exhaust; + uint32_t tx_total_fw; + uint32_t tx_retry_fw; + uint32_t tx_retry_exhaust_fw; + uint32_t rx_fcs_count; + struct element_info assoc_req_ies; + qdf_atomic_t ref_cnt; + qdf_atomic_t ref_cnt_dbgid[STA_INFO_ID_MAX]; + unsigned long pending_eap_frm_type; + bool is_attached; + int32_t peer_rssi_per_chain[WMI_MAX_CHAINS]; + uint32_t num_tx_rate_count; + uint32_t num_rx_rate_count; + uint32_t *tx_pkt_per_mcs; + uint32_t *rx_pkt_per_mcs; + uint16_t vlan_id; +}; + +/** + * struct hdd_sta_info_obj - Station info container structure + * @sta_obj: The sta info object that stores the sta_info + * @sta_obj_lock: Lock to protect the sta_obj read/write access + */ +struct hdd_sta_info_obj { + qdf_list_t sta_obj; + qdf_spinlock_t sta_obj_lock; +}; + +/** + * hdd_put_sta_info_ref() - Release sta_info ref for synchronization + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: Station info structure to be released. + * @lock_required: Flag to acquire lock or not + * @sta_info_dbgid: Debug ID of the caller API + * + * Return: None + */ +void hdd_put_sta_info_ref(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info **sta_info, + bool lock_required, + wlan_sta_info_dbgid sta_info_dbgid); + +/** + * hdd_take_sta_info_ref() - Increment sta info ref. + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: Station info structure to be released. + * @lock_required: Flag to acquire lock or not + * @sta_info_dbgid: Debug ID of the caller API + * + * This function has to be accompanied by hdd_put_sta_info when the work with + * the sta info is done. Failure to do so will result in a mem leak. + * + * Return: None + */ +void hdd_take_sta_info_ref(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *sta_info, + bool lock_required, + wlan_sta_info_dbgid sta_info_dbgid); + +/** + * hdd_get_front_sta_info_no_lock() - Get the first sta_info from the sta list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @out_sta_info: The station info structure that acts as the container object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_get_front_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info **out_sta_info); + +/** + * hdd_get_next_sta_info_no_lock() - Get the next sta_info from the sta list + * This API does not use any lock in it's implementation. It is the caller's + * directive to ensure concurrency safety. + * + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @current_sta_info: The station that was previously retrieved + * @out_sta_info: The station info structure that acts as the container object. + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_get_next_sta_info_no_lock(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *current_sta_info, + struct hdd_station_info **out_sta_info); + +/* Abstract wrapper to check sta_info validity */ +#define __hdd_is_station_valid(sta_info) sta_info + +/** + * __hdd_take_ref_and_fetch_front_sta_info_safe - Helper macro to lock, fetch + * front sta_info, take ref and unlock in a delete safe manner. + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: The station info structure that acts as the iterator object. + * @next_sta_info: A temporary node for maintaining del safe. + * @sta_info_dbgid: Debug ID of the caller API + */ +#define __hdd_take_ref_and_fetch_front_sta_info_safe(sta_info_container, \ + sta_info, next_sta_info, \ + sta_info_dbgid) \ + qdf_spin_lock_bh(&sta_info_container.sta_obj_lock), \ + hdd_get_front_sta_info_no_lock(&sta_info_container, &sta_info), \ + (sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \ + sta_info, false, sta_info_dbgid) : \ + (false), \ + hdd_get_next_sta_info_no_lock(&sta_info_container, sta_info, \ + &next_sta_info), \ + (next_sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \ + next_sta_info, false, \ + sta_info_dbgid) : \ + (false), \ + qdf_spin_unlock_bh(&sta_info_container.sta_obj_lock) + +/** + * __hdd_take_ref_and_fetch_next_sta_info_safe - Helper macro to lock, fetch + * next sta_info, take ref and unlock. + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: The station info structure that acts as the iterator object. + * @next_sta_info: A temporary node for maintaining del safe. + * @sta_info_dbgid: Debug ID of the caller API + */ +#define __hdd_take_ref_and_fetch_next_sta_info_safe(sta_info_container, \ + sta_info, next_sta_info, \ + sta_info_dbgid) \ + qdf_spin_lock_bh(&sta_info_container.sta_obj_lock), \ + sta_info = next_sta_info, \ + hdd_get_next_sta_info_no_lock(&sta_info_container, sta_info, \ + &next_sta_info), \ + (next_sta_info) ? hdd_take_sta_info_ref(&sta_info_container, \ + next_sta_info, false, \ + sta_info_dbgid) : \ + (false), \ + qdf_spin_unlock_bh(&sta_info_container.sta_obj_lock) + +/** + * hdd_for_each_sta_ref_safe - Iterate over each station stored in the sta info + * container in a delete safe manner + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: The station info structure that acts as the iterator object. + * @next_sta_info: A temporary node for maintaining del safe. + * @sta_info_dbgid: Debug ID of the caller API + * + * The sta_info will contain the structure that is fetched for that particular + * iteration. The next_sta_info is used to store the next station before the + * current station is deleted so as to provide a safe way to iterate the list + * while deletion is undergoing. + * + * ***** NOTE ***** + * Before the end of each iteration, hdd_put_sta_info_ref must be + * called. Not calling this will keep hold of a reference, thus preventing + * deletion of the station info + * + * Usage example: + * hdd_for_each_sta_ref_safe(sta_info_container, sta_info, next_sta_info, + * sta_info_dbgid) { + * + * + * hdd_put_sta_info_ref(sta_info_container, sta_info, true, + * sta_info_dbgid) + * } + */ +#define hdd_for_each_sta_ref_safe(sta_info_container, sta_info, next_sta_info, \ + sta_info_dbgid) \ + for (__hdd_take_ref_and_fetch_front_sta_info_safe(sta_info_container, \ + sta_info, \ + next_sta_info, \ + sta_info_dbgid); \ + __hdd_is_station_valid(sta_info); \ + __hdd_take_ref_and_fetch_next_sta_info_safe(sta_info_container, \ + sta_info, \ + next_sta_info, \ + sta_info_dbgid)) + +/** + * hdd_sta_info_init() - Initialise the wlan hdd station info container obj + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * + * Return: QDF_STATUS_SUCCESS on success, failure code otherwise + */ +QDF_STATUS hdd_sta_info_init(struct hdd_sta_info_obj *sta_info_container); + +/** + * hdd_sta_info_deinit() - Deinit the wlan hdd station info container obj + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * + * Return: None + */ +void hdd_sta_info_deinit(struct hdd_sta_info_obj *sta_info_container); + +/** + * hdd_sta_info_detach() - Detach the station info structure from the list + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: The station info structure that has to be detached from the + * container object. + * + * Return: None + */ +void hdd_sta_info_detach(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info **sta_info); + +/** + * hdd_sta_info_attach() - Attach the station info structure into the list + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @sta_info: The station info structure that is to be attached to the + * container object. + * + * Return: QDF STATUS SUCCESS on successful attach, error code otherwise + */ +QDF_STATUS hdd_sta_info_attach(struct hdd_sta_info_obj *sta_info_container, + struct hdd_station_info *sta_info); + +/** + * hdd_get_sta_info_by_id() - Find the sta_info structure by index + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @idx: The index which the sta_info has to be fetched. + * @sta_info_dbgid: Debug ID of the caller API + * + * Return: Reference-counted Pointer to the hdd_station_info structure which + * contains the mac address passed + */ +struct hdd_station_info *hdd_get_sta_info_by_id( + struct hdd_sta_info_obj *sta_info_container, + const int idx, + wlan_sta_info_dbgid sta_info_dbgid); + +/** + * hdd_get_sta_info_by_mac() - Find the sta_info structure by mac addr + * @sta_info_container: The station info container obj that stores and maintains + * the sta_info obj. + * @mac_addr: The mac addr by which the sta_info has to be fetched. + * @sta_info_dbgid: Debug ID of the caller API + * + * Return: Pointer to the hdd_station_info structure which contains the mac + * address passed + */ +struct hdd_station_info *hdd_get_sta_info_by_mac( + struct hdd_sta_info_obj *sta_info_container, + const uint8_t *mac_addr, + wlan_sta_info_dbgid sta_info_dbgid); + +/** + * hdd_clear_cached_sta_info() - Clear the cached sta info from the container + * @hdd_adapter: The adapter containing the station info container obj that + * stores and maintains the sta_info obj. + * + * Return: None + */ +void hdd_clear_cached_sta_info(struct hdd_adapter *hdd_adapter); + +#endif /* __WLAN_HDD_STA_INFO_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_station_info.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_station_info.c new file mode 100644 index 0000000000..8b56833118 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_station_info.c @@ -0,0 +1,2648 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_station_info.c + * + * WLAN station info functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_mlme_ucfg_api.h" +#include "wlan_hdd_sta_info.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_ipa_ucfg_api.h" + +#include +#include +#include +#include +#include + +#include "wlan_hdd_stats.h" + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_get_station_cmd() + */ +#define STATION_INVALID \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INVALID +#define STATION_INFO \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO +#define STATION_ASSOC_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_ASSOC_FAIL_REASON +#define STATION_REMOTE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_REMOTE +#define STATION_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + +#define STA_INFO_INVALID \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_INVALID +#define STA_INFO_BIP_MIC_ERROR_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_MIC_ERROR_COUNT +#define STA_INFO_BIP_REPLAY_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BIP_REPLAY_COUNT +#define STA_INFO_BEACON_MIC_ERROR_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_MIC_ERROR_COUNT +#define STA_INFO_BEACON_REPLAY_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_BEACON_REPLAY_COUNT +#define STA_INFO_CONNECT_FAIL_REASON_CODE \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_CONNECT_FAIL_REASON_CODE +#define STA_INFO_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + +/* define short names for get station info attributes */ +#define LINK_INFO_STANDARD_NL80211_ATTR \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_LINK_STANDARD_NL80211_ATTR +#define AP_INFO_STANDARD_NL80211_ATTR \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_STANDARD_NL80211_ATTR +#define INFO_ROAM_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT +#define INFO_AKM \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM +#define WLAN802_11_MODE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE +#define AP_INFO_HS20_INDICATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION +#define HT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION +#define VHT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION +#define HE_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HE_OPERATION +#define INFO_ASSOC_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_FAIL_REASON +#define REMOTE_MAX_PHY_RATE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_MAX_PHY_RATE +#define REMOTE_TX_PACKETS \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_PACKETS +#define REMOTE_TX_BYTES \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_BYTES +#define REMOTE_RX_PACKETS \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_PACKETS +#define REMOTE_RX_BYTES \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_BYTES +#define REMOTE_LAST_TX_RATE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_LAST_TX_RATE +#define REMOTE_LAST_RX_RATE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_LAST_RX_RATE +#define REMOTE_WMM \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_WMM +#define REMOTE_SUPPORTED_MODE \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SUPPORTED_MODE +#define REMOTE_AMPDU \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_AMPDU +#define REMOTE_TX_STBC \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_TX_STBC +#define REMOTE_RX_STBC \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_STBC +#define REMOTE_CH_WIDTH\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_CH_WIDTH +#define REMOTE_SGI_ENABLE\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_SGI_ENABLE +#define REMOTE_PAD\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_PAD +#define REMOTE_RX_RETRY_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_RETRY_COUNT +#define REMOTE_RX_BC_MC_COUNT \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_RX_BC_MC_COUNT +#define DISCONNECT_REASON \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_DRIVER_DISCONNECT_REASON +#define BEACON_IES \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_BEACON_IES +#define ASSOC_REQ_IES \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ASSOC_REQ_IES +#define REMOTE_CH_WIDTH_V2\ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_REMOTE_CH_WIDTH_V2 +#define EHT_OPERATION \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_EHT_OPERATION + +/* + * MSB of rx_mc_bc_cnt indicates whether FW supports rx_mc_bc_cnt + * feature or not, if first bit is 1 it indicates that FW supports this + * feature, if it is 0 it indicates FW doesn't support this feature + */ +#define HDD_STATION_INFO_RX_MC_BC_COUNT (1 << 31) + +/* + * Use this macro to check channel bandwidth 160MHZ + */ +#define MAX_CHANNEL_BW_160 160 + +const struct nla_policy +hdd_get_station_policy[STATION_MAX + 1] = { + [STATION_INFO] = {.type = NLA_FLAG}, + [STATION_ASSOC_FAIL_REASON] = {.type = NLA_FLAG}, + [STATION_REMOTE] = {.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE}, +}; + +const struct nla_policy +hdd_get_sta_policy[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC] = {.type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE}, +}; + +static int hdd_get_sta_congestion(struct wlan_hdd_link_info *link_info, + uint32_t *congestion) +{ + QDF_STATUS status; + struct cca_stats cca_stats; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + status = ucfg_mc_cp_stats_cca_stats_get(vdev, &cca_stats); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + *congestion = cca_stats.congestion; + return 0; +} + +/** + * hdd_get_station_assoc_fail() - Handle get station assoc fail + * @link_info: Link info pointer in HDD adaper + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION_ASSOC_FAIL. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int hdd_get_station_assoc_fail(struct wlan_hdd_link_info *link_info) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct hdd_station_ctx *hdd_sta_ctx; + uint32_t congestion; + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += sizeof(uint32_t); + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + if (nla_put_u32(skb, INFO_ASSOC_FAIL_REASON, + hdd_sta_ctx->conn_info.assoc_status_code)) { + hdd_err("put fail"); + goto fail; + } + + if (hdd_get_sta_congestion(link_info, &congestion)) + congestion = 0; + + hdd_info("congestion:%d", congestion); + if (nla_put_u32(skb, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY, + congestion)) { + hdd_err("put fail"); + goto fail; + } + + return wlan_cfg80211_vendor_cmd_reply(skb); +fail: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * hdd_convert_auth_type() - transform auth type specific to + * vendor command + * @auth_type: csr auth type + * + * Return: vendor command auth type + */ +static int hdd_convert_auth_type(uint32_t auth_type) +{ + uint32_t ret_val; + + switch (auth_type) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + ret_val = QCA_WLAN_AUTH_TYPE_OPEN; + break; + case eCSR_AUTH_TYPE_SHARED_KEY: + ret_val = QCA_WLAN_AUTH_TYPE_SHARED; + break; + case eCSR_AUTH_TYPE_WPA: + ret_val = QCA_WLAN_AUTH_TYPE_WPA; + break; + case eCSR_AUTH_TYPE_WPA_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_WPA_PSK; + break; + case eCSR_AUTH_TYPE_AUTOSWITCH: + ret_val = QCA_WLAN_AUTH_TYPE_AUTOSWITCH; + break; + case eCSR_AUTH_TYPE_WPA_NONE: + ret_val = QCA_WLAN_AUTH_TYPE_WPA_NONE; + break; + case eCSR_AUTH_TYPE_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_RSN; + break; + case eCSR_AUTH_TYPE_RSN_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_RSN_PSK; + break; + case eCSR_AUTH_TYPE_FT_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_FT; + break; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_FT_PSK; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + ret_val = QCA_WLAN_AUTH_TYPE_WAI; + break; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + ret_val = QCA_WLAN_AUTH_TYPE_WAI_PSK; + break; + case eCSR_AUTH_TYPE_CCKM_WPA: + ret_val = QCA_WLAN_AUTH_TYPE_CCKM_WPA; + break; + case eCSR_AUTH_TYPE_CCKM_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_CCKM_RSN; + break; + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SHA256_PSK; + break; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SHA256; + break; + case eCSR_AUTH_TYPE_FT_SAE: + ret_val = QCA_WLAN_AUTH_TYPE_FT_SAE; + break; + case eCSR_AUTH_TYPE_FT_SUITEB_EAP_SHA384: + ret_val = QCA_WLAN_AUTH_TYPE_FT_SUITEB_EAP_SHA384; + break; + case eCSR_AUTH_TYPE_SAE: + ret_val = QCA_WLAN_AUTH_TYPE_SAE; + break; + case eCSR_AUTH_TYPE_FILS_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_FILS_SHA256; + break; + case eCSR_AUTH_TYPE_FILS_SHA384: + ret_val = QCA_WLAN_AUTH_TYPE_FILS_SHA384; + break; + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_FT_FILS_SHA256; + break; + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + ret_val = QCA_WLAN_AUTH_TYPE_FT_FILS_SHA384; + break; + case eCSR_AUTH_TYPE_DPP_RSN: + ret_val = QCA_WLAN_AUTH_TYPE_DPP_RSN; + break; + case eCSR_AUTH_TYPE_OWE: + ret_val = QCA_WLAN_AUTH_TYPE_OWE; + break; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA256: + ret_val = QCA_WLAN_AUTH_TYPE_SUITEB_EAP_SHA256; + break; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA384: + ret_val = QCA_WLAN_AUTH_TYPE_SUITEB_EAP_SHA384; + break; + case eCSR_NUM_OF_SUPPORT_AUTH_TYPE: + case eCSR_AUTH_TYPE_FAILED: + case eCSR_AUTH_TYPE_NONE: + default: + ret_val = QCA_WLAN_AUTH_TYPE_INVALID; + break; + } + return ret_val; +} + +/** + * hdd_convert_dot11mode() - transform dot11mode type specific to + * vendor command + * @dot11mode: CSR dot11 mode + * + * Return: vendor command dot11 mode + */ +static int hdd_convert_dot11mode(uint32_t dot11mode) +{ + uint32_t ret_val; + + switch (dot11mode) { + case eCSR_CFG_DOT11_MODE_11A: + ret_val = QCA_WLAN_802_11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret_val = QCA_WLAN_802_11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret_val = QCA_WLAN_802_11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret_val = QCA_WLAN_802_11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + ret_val = QCA_WLAN_802_11_MODE_11AC; + break; + case eCSR_CFG_DOT11_MODE_11AX: + ret_val = QCA_WLAN_802_11_MODE_11AX; + break; + case eCSR_CFG_DOT11_MODE_11BE: + ret_val = QCA_WLAN_802_11_MODE_11BE; + break; + case eCSR_CFG_DOT11_MODE_AUTO: + case eCSR_CFG_DOT11_MODE_ABG: + default: + ret_val = QCA_WLAN_802_11_MODE_INVALID; + } + return ret_val; +} + +/** + * hdd_calculate_tx_bitrate_ie_size - calculate tx bitrate ie size + * + * Return: tx bitrate ie size + */ +static uint32_t hdd_calculate_tx_bitrate_ie_size(void) +{ + uint32_t nl_buf_len = nla_total_size(0); + + /* NL80211_RATE_INFO_BITRATE32 */ + nl_buf_len += nla_total_size(sizeof(uint32_t)) + + /* NL80211_RATE_INFO_BITRATE */ + nla_total_size(sizeof(uint16_t)) + + /* NL80211_RATE_INFO_VHT_NSS */ + nla_total_size(sizeof(uint8_t)); + + return nl_buf_len; +} + +/** + * hdd_add_tx_bitrate() - add tx bitrate attribute + * @skb: pointer to sk buff + * @link_info: Link info pointer in HDD adapter + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_tx_bitrate(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info, int idx) +{ + struct nlattr *nla_attr; + uint32_t bitrate, bitrate_compat; + struct hdd_station_ctx *sta_ctx; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ + if (hdd_cm_is_vdev_associated(link_info)) + bitrate = cfg80211_calculate_bitrate( + &sta_ctx->cache_conn_info.max_tx_bitrate); + else + bitrate = cfg80211_calculate_bitrate( + &sta_ctx->cache_conn_info.txrate); + /* report 16-bit bitrate only if we can */ + bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; + + if (bitrate > 0) { + if (nla_put_u32(skb, NL80211_RATE_INFO_BITRATE32, bitrate)) { + hdd_err("put fail bitrate: %u", bitrate); + goto fail; + } + } else { + hdd_err("Invalid bitrate: %u", bitrate); + } + + if (bitrate_compat > 0) { + if (nla_put_u16(skb, NL80211_RATE_INFO_BITRATE, + bitrate_compat)) { + hdd_err("put fail bitrate_compat: %u", bitrate_compat); + goto fail; + } + } else { + hdd_err("Invalid bitrate_compat: %u", bitrate_compat); + } + + if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, + sta_ctx->cache_conn_info.txrate.nss)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + + hdd_nofl_debug( + "STA Tx rate info:: bitrate:%d, bitrate_compat:%d, NSS:%d", + bitrate, bitrate_compat, + sta_ctx->cache_conn_info.txrate.nss); + + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_calculate_sta_info_ie_size - calculate sta info size + * + * Return: sta info ie size + */ +static uint32_t hdd_calculate_sta_info_ie_size(void) +{ + uint32_t nl_buf_len = nla_total_size(0); + + /* NL80211_STA_INFO_SIGNAL */ + nl_buf_len += nla_total_size(sizeof(int8_t)) + + hdd_calculate_tx_bitrate_ie_size(); + + return nl_buf_len; +} + +/** + * hdd_add_sta_info() - add station info attribute + * @skb: pointer to sk buff + * @link_info: Link info pointer in HDD adapter + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_sta_info(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info, int idx) +{ + struct nlattr *nla_attr; + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, + (hdd_sta_ctx->cache_conn_info.signal + 100))) { + hdd_err("put fail"); + goto fail; + } + + if (hdd_cm_is_vdev_associated(link_info)) + hdd_get_max_tx_bitrate(link_info); + + if (hdd_add_tx_bitrate(skb, link_info, NL80211_STA_INFO_TX_BITRATE)) { + hdd_err("hdd_add_tx_bitrate failed"); + goto fail; + } + + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_calculate_survey_info_ie_size - calculate survey info size + * + * Return: survey info ie size + */ +static uint32_t hdd_calculate_survey_info_ie_size(void) +{ + uint32_t nl_buf_len = nla_total_size(0); + + /* NL80211_SURVEY_INFO_FREQUENCY */ + nl_buf_len += nla_total_size(sizeof(uint32_t)) + + /* NL80211_SURVEY_INFO_NOISE */ + nla_total_size(sizeof(int8_t)); + + return nl_buf_len; +} + +/** + * hdd_add_survey_info() - add survey info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t hdd_add_survey_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, + hdd_sta_ctx->cache_conn_info.chan_freq) || + nla_put_u8(skb, NL80211_SURVEY_INFO_NOISE, + (hdd_sta_ctx->cache_conn_info.noise + 100))) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_calculate_link_standard_info_ie_size - calculate link standard info size + * + * Return: link standard info ie size + */ +static uint32_t hdd_calculate_link_standard_info_ie_size(void) +{ + uint32_t nl_buf_len = nla_total_size(0); + + /* NL80211_ATTR_SSID */ + nl_buf_len += nla_total_size(WLAN_SSID_MAX_LEN + 1) + + /* NL80211_ATTR_MAC */ + nla_total_size(QDF_MAC_ADDR_SIZE) + + hdd_calculate_survey_info_ie_size() + + hdd_calculate_sta_info_ie_size(); + + return nl_buf_len; +} + +/** + * hdd_add_link_standard_info() - add link info attribute + * @skb: pointer to sk buff + * @link_info: Link info pointer in HDD adapter + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_add_link_standard_info(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info, int idx) +{ + struct nlattr *nla_attr; + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!hdd_sta_ctx) { + hdd_err("Invalid sta ctx"); + goto fail; + } + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) { + hdd_err("nla_nest_start failed"); + goto fail; + } + + if (nla_put(skb, + NL80211_ATTR_SSID, + hdd_sta_ctx->cache_conn_info.last_ssid.SSID.length, + hdd_sta_ctx->cache_conn_info.last_ssid.SSID.ssId)) { + hdd_err("put fail"); + goto fail; + } + if (nla_put(skb, NL80211_ATTR_MAC, QDF_MAC_ADDR_SIZE, + hdd_sta_ctx->cache_conn_info.bssid.bytes)) { + hdd_err("put bssid failed"); + goto fail; + } + if (hdd_add_survey_info(skb, hdd_sta_ctx, NL80211_ATTR_SURVEY_INFO)) { + hdd_err("hdd_add_survey_info failed"); + goto fail; + } + + if (hdd_add_sta_info(skb, link_info, NL80211_ATTR_STA_INFO)) { + hdd_err("hdd_add_sta_info failed"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_calculate_ap_standard_info_ie_size - calculate ap standard info size + * @hdd_sta_ctx: pointer to hdd station context + * + * Return: ap standard info size + */ +static uint32_t hdd_calculate_ap_standard_info_ie_size( + struct hdd_station_ctx *hdd_sta_ctx) +{ + uint32_t nl_buf_len = nla_total_size(0); + + /* NL80211_ATTR_VHT_CAPABILITY */ + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_present) + nl_buf_len += nla_total_size(sizeof( + hdd_sta_ctx->cache_conn_info.vht_caps)); + /* NL80211_ATTR_HT_CAPABILITY */ + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_present) + nl_buf_len += nla_total_size(sizeof( + hdd_sta_ctx->cache_conn_info.ht_caps)); + + return nl_buf_len; +} + +/** + * hdd_add_ap_standard_info() - add ap info attribute + * @skb: pointer to sk buff + * @hdd_sta_ctx: pointer to hdd station context + * @idx: attribute index + * + * Return: Success(0) or reason code for failure + */ +static int32_t +hdd_add_ap_standard_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx, int idx) +{ + struct nlattr *nla_attr; + struct hdd_connection_info *conn_info; + + conn_info = &hdd_sta_ctx->cache_conn_info; + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (conn_info->conn_flag.vht_present) { + if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, + sizeof(conn_info->vht_caps), + &conn_info->vht_caps)) { + hdd_err("put fail"); + goto fail; + } + hdd_nofl_debug("STA VHT capabilities:"); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)&conn_info->vht_caps, + sizeof(conn_info->vht_caps)); + } + if (conn_info->conn_flag.ht_present) { + if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, + sizeof(conn_info->ht_caps), + &conn_info->ht_caps)) { + hdd_err("put fail"); + goto fail; + } + hdd_nofl_debug("STA HT capabilities:"); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)&conn_info->ht_caps, + sizeof(conn_info->ht_caps)); + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ + defined(WLAN_FEATURE_11AX) +static int32_t hdd_add_he_oper_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx) +{ + int32_t ret = 0; + struct hdd_connection_info *conn_info; + + conn_info = &hdd_sta_ctx->cache_conn_info; + if (!conn_info->he_oper_len || !conn_info->he_operation) + return ret; + + if (nla_put(skb, HE_OPERATION, conn_info->he_oper_len, + conn_info->he_operation)) { + ret = -EINVAL; + } else { + hdd_nofl_debug("STA HE operation:"); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)&conn_info->he_operation, + conn_info->he_oper_len); + } + + qdf_mem_free(hdd_sta_ctx->cache_conn_info.he_operation); + hdd_sta_ctx->cache_conn_info.he_operation = NULL; + hdd_sta_ctx->cache_conn_info.he_oper_len = 0; + return ret; +} + +static int32_t hdd_get_he_op_len(struct hdd_station_ctx *hdd_sta_ctx) +{ + return hdd_sta_ctx->cache_conn_info.he_oper_len; +} + +#else +static inline uint32_t hdd_add_he_oper_info( + struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx) +{ + return 0; +} + +static uint32_t hdd_get_he_op_len(struct hdd_station_ctx *hdd_sta_ctx) +{ + return 0; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)) && \ + defined(WLAN_FEATURE_11BE) +static int32_t hdd_add_eht_oper_info(struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx) +{ + int32_t ret = 0; + struct hdd_connection_info *conn_info; + + conn_info = &hdd_sta_ctx->cache_conn_info; + if (!conn_info->eht_oper_len) + return -EINVAL; + + if (nla_put(skb, EHT_OPERATION, conn_info->eht_oper_len, + &conn_info->eht_operation)) { + ret = -EINVAL; + } else { + hdd_nofl_debug("STA EHT operation:"); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)&conn_info->eht_operation, + conn_info->eht_oper_len); + } + + return ret; +} +#else +static inline int32_t hdd_add_eht_oper_info( + struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx) +{ + return 0; +} +#endif + +static uint32_t hdd_get_prev_connected_bss_ies_len( + struct hdd_station_ctx *hdd_sta_ctx) +{ + return hdd_sta_ctx->conn_info.prev_ap_bcn_ie.len; +} + +static uint32_t hdd_add_prev_connected_bss_ies( + struct sk_buff *skb, + struct hdd_station_ctx *hdd_sta_ctx) +{ + struct element_info *bcn_ie = &hdd_sta_ctx->conn_info.prev_ap_bcn_ie; + + if (bcn_ie->len) { + if (nla_put(skb, BEACON_IES, bcn_ie->len, bcn_ie->ptr)) { + hdd_err("Failed to put beacon IEs: bytes left: %d, ie_len: %u ", + skb_tailroom(skb), bcn_ie->len); + return -EINVAL; + } + + hdd_nofl_debug("Beacon IEs len: %u", bcn_ie->len); + + qdf_mem_free(bcn_ie->ptr); + bcn_ie->ptr = NULL; + bcn_ie->len = 0; + } + + return 0; +} + +/** + * hdd_calculate_station_info_ie_size - calculate bss ie size + * @hdd_sta_ctx: pointer to hdd station context + * + * Return: bss ie size + */ +static uint32_t hdd_calculate_station_info_ie_size( + struct hdd_station_ctx *hdd_sta_ctx) +{ + /* NLA_HDRLEN */ + uint32_t nl_buf_len = NLA_HDRLEN; + + nl_buf_len += hdd_calculate_link_standard_info_ie_size() + + hdd_calculate_ap_standard_info_ie_size(hdd_sta_ctx); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_ROAM_COUNT */ + nl_buf_len += nla_total_size(sizeof(uint32_t)) + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AKM */ + nla_total_size(sizeof(uint32_t)) + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_802_11_MODE */ + nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HT_OPERATION */ + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) + nl_buf_len += nla_total_size(sizeof( + hdd_sta_ctx->cache_conn_info.ht_operation)); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_VHT_OPERATION */ + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) + nl_buf_len += nla_total_size(sizeof( + hdd_sta_ctx->cache_conn_info.vht_operation)); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_HE_OPERATION */ + nl_buf_len += nla_total_size(hdd_get_he_op_len(hdd_sta_ctx)); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_AP_HS20_INDICATION */ + if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) + nl_buf_len += nla_total_size(sizeof( + hdd_sta_ctx->cache_conn_info.hs20vendor_ie) - 1); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_DRIVER_DISCONNECT_REASON */ + nl_buf_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_GET_STATION_INFO_BEACON_IES */ + if (hdd_sta_ctx->conn_info.prev_ap_bcn_ie.len) + nl_buf_len += nla_total_size( + hdd_get_prev_connected_bss_ies_len(hdd_sta_ctx)); + + return nl_buf_len; +} + +/** + * hdd_populate_station_info_skb - populate station info in skb + * @skb: pointer to socket buffer + * @link_info: Link info pointer in HDD adapter + * + * Return: QDF_STATUS_SUCCESS in case of success else failure + */ +static QDF_STATUS +hdd_populate_station_info_skb(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info) +{ + uint8_t *tmp_hs20 = NULL; + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + if (hdd_add_link_standard_info(skb, link_info, + LINK_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("link_standard_info put fail"); + return QDF_STATUS_E_FAILURE; + } + + if (hdd_add_ap_standard_info(skb, hdd_sta_ctx, + AP_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("ap standard info fail"); + return QDF_STATUS_E_FAILURE; + } + + if (nla_put_u32(skb, INFO_ROAM_COUNT, + hdd_sta_ctx->cache_conn_info.roam_count) || + nla_put_u32(skb, INFO_AKM, + hdd_convert_auth_type( + hdd_sta_ctx->cache_conn_info.last_auth_type)) || + nla_put_u32(skb, WLAN802_11_MODE, + hdd_convert_dot11mode( + hdd_sta_ctx->cache_conn_info.dot11mode))) { + hdd_err("Roam, AKM, dot11mode put fail"); + return QDF_STATUS_E_FAILURE; + } + + if (hdd_sta_ctx->cache_conn_info.conn_flag.ht_op_present) { + if (nla_put(skb, HT_OPERATION, + (sizeof(hdd_sta_ctx->cache_conn_info.ht_operation)), + &hdd_sta_ctx->cache_conn_info.ht_operation)) { + hdd_err("ht operation put fail"); + return QDF_STATUS_E_FAILURE; + } + hdd_nofl_debug("STA HT operation:"); + qdf_trace_hex_dump( + QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)&hdd_sta_ctx->cache_conn_info.ht_operation, + sizeof(hdd_sta_ctx->cache_conn_info.ht_operation)); + } + + if (hdd_sta_ctx->cache_conn_info.conn_flag.vht_op_present) { + if (nla_put(skb, VHT_OPERATION, + (sizeof(hdd_sta_ctx-> + cache_conn_info.vht_operation)), + &hdd_sta_ctx->cache_conn_info.vht_operation)) { + hdd_err("vht operation put fail"); + return QDF_STATUS_E_FAILURE; + } + hdd_nofl_debug("STA VHT operation:"); + qdf_trace_hex_dump( + QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)&hdd_sta_ctx->cache_conn_info.vht_operation, + sizeof(hdd_sta_ctx->cache_conn_info.vht_operation)); + } + + if (hdd_add_he_oper_info(skb, hdd_sta_ctx)) { + hdd_err("he operation info put fail"); + return QDF_STATUS_E_FAILURE; + } + if (hdd_sta_ctx->cache_conn_info.conn_flag.eht_op_present) { + if (hdd_add_eht_oper_info(skb, hdd_sta_ctx)) { + hdd_err("eht operation info put fail"); + return QDF_STATUS_E_FAILURE; + } + } + + if (hdd_sta_ctx->cache_conn_info.conn_flag.hs20_present) { + tmp_hs20 = + (uint8_t *)&hdd_sta_ctx->cache_conn_info.hs20vendor_ie; + if (nla_put(skb, AP_INFO_HS20_INDICATION, + (sizeof(hdd_sta_ctx->cache_conn_info.hs20vendor_ie) + - 1), + tmp_hs20 + 1)) { + hdd_err("hs20 put fail"); + return QDF_STATUS_E_FAILURE; + } + hdd_nofl_debug("STA hs20 vendor IE:"); + qdf_trace_hex_dump( + QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)(tmp_hs20 + 1), + sizeof(hdd_sta_ctx->cache_conn_info.hs20vendor_ie) - 1); + } + + if (nla_put_u32(skb, DISCONNECT_REASON, + link_info->adapter->last_disconnect_reason)) { + hdd_err("Failed to put disconnect reason"); + return QDF_STATUS_E_FAILURE; + } + + if (hdd_add_prev_connected_bss_ies(skb, hdd_sta_ctx)) { + hdd_err("disconnect_reason put fail"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_station_info() - send BSS information to supplicant + * @link_info: Link info pointer in HDD adapter + * + * Return: 0 if success else error status + */ +static int hdd_get_station_info(struct wlan_hdd_link_info *link_info) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *hdd_sta_ctx; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + if (hdd_cm_is_vdev_connected(link_info)) { + hdd_err("Station is connected, command is not supported"); + return -EINVAL; + } + + nl_buf_len = hdd_calculate_station_info_ie_size(hdd_sta_ctx); + if (!nl_buf_len) { + hdd_err("BSS ie size calculation failed"); + return -EINVAL; + } + + skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (hdd_populate_station_info_skb(skb, link_info) != QDF_STATUS_SUCCESS) + goto fail; + + hdd_nofl_debug( + "STA Info:: SSID:" QDF_SSID_FMT ", BSSID:" QDF_MAC_ADDR_FMT ", freq:%d, " + "Noise:%d, signal:%d, roam_count:%d, last_auth_type:%d, " + "dot11mode:%d, disconnect_reason:%d, ", + QDF_SSID_REF(WLAN_SSID_MAX_LEN, + hdd_sta_ctx->cache_conn_info.last_ssid.SSID.ssId), + QDF_MAC_ADDR_REF(hdd_sta_ctx->cache_conn_info.bssid.bytes), + hdd_sta_ctx->cache_conn_info.chan_freq, + (hdd_sta_ctx->cache_conn_info.noise + 100), + (hdd_sta_ctx->cache_conn_info.signal + 100), + hdd_sta_ctx->cache_conn_info.roam_count, + hdd_convert_auth_type( + hdd_sta_ctx->cache_conn_info.last_auth_type), + hdd_convert_dot11mode(hdd_sta_ctx->cache_conn_info.dot11mode), + adapter->last_disconnect_reason); + + return wlan_cfg80211_vendor_cmd_reply(skb); +fail: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)) +static inline int32_t remote_station_put_u64(struct sk_buff *skb, + int32_t attrtype, + uint64_t value) +{ + return nla_put_u64_64bit(skb, attrtype, value, REMOTE_PAD); +} +#else +static inline int32_t remote_station_put_u64(struct sk_buff *skb, + int32_t attrtype, + uint64_t value) +{ + return nla_put_u64(skb, attrtype, value); +} +#endif + +/** + * hdd_add_survey_info_sap_get_len - get data length used in + * hdd_add_survey_info_sap() + * + * This function calculates the data length used in hdd_add_survey_info_sap() + * + * Return: total data length used in hdd_add_survey_info_sap() + */ +static uint32_t hdd_add_survey_info_sap_get_len(void) +{ + return ((NLA_HDRLEN) + (sizeof(uint32_t) + NLA_HDRLEN)); +} + +/** + * hdd_add_survey_info_sap() - add survey info attribute + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds survey info attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int32_t hdd_add_survey_info_sap(struct sk_buff *skb, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (nla_put_u32(skb, NL80211_SURVEY_INFO_FREQUENCY, + stainfo->freq)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + hdd_nofl_debug("Remote STA freq: %d", stainfo->freq); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_tx_bitrate_sap_get_len - get data length used in + * hdd_add_tx_bitrate_sap() + * + * This function calculates the data length used in hdd_add_tx_bitrate_sap() + * + * Return: total data length used in hdd_add_tx_bitrate_sap() + */ +static uint32_t hdd_add_tx_bitrate_sap_get_len(void) +{ + return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN)); +} + +static uint32_t hdd_add_sta_capability_get_len(void) +{ + return nla_total_size(sizeof(uint16_t)); +} + +/** + * hdd_add_tx_bitrate_sap - add vhs nss info attribute + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds vht nss attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_tx_bitrate_sap(struct sk_buff *skb, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + if (nla_put_u8(skb, NL80211_RATE_INFO_VHT_NSS, + stainfo->nss)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + hdd_nofl_debug("Remote STA VHT NSS: %d", stainfo->nss); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_sta_info_sap_get_len - get data length used in + * hdd_add_sta_info_sap() + * + * This function calculates the data length used in hdd_add_sta_info_sap() + * + * Return: total data length used in hdd_add_sta_info_sap() + */ +static uint32_t hdd_add_sta_info_sap_get_len(void) +{ + return ((NLA_HDRLEN) + (sizeof(uint8_t) + NLA_HDRLEN) + + hdd_add_tx_bitrate_sap_get_len() + + hdd_add_sta_capability_get_len()); +} + +/** + * hdd_add_sta_info_sap - add sta signal info attribute + * @skb: pointer to response skb buffer + * @rssi: station RSSI + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds sta signal attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int32_t hdd_add_sta_info_sap(struct sk_buff *skb, int8_t rssi, + struct hdd_station_info *stainfo, int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + if (nla_put_u8(skb, NL80211_STA_INFO_SIGNAL, + rssi)) { + hdd_err("put fail"); + goto fail; + } + if (hdd_add_tx_bitrate_sap(skb, stainfo, NL80211_STA_INFO_TX_BITRATE)) + goto fail; + + nla_nest_end(skb, nla_attr); + hdd_nofl_debug("Remote STA RSSI: %d", rssi - HDD_NOISE_FLOOR_DBM); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_link_standard_info_sap_get_len - get data length used in + * hdd_add_link_standard_info_sap() + * + * This function calculates the data length used in + * hdd_add_link_standard_info_sap() + * + * Return: total data length used in hdd_add_link_standard_info_sap() + */ +static uint32_t hdd_add_link_standard_info_sap_get_len(void) +{ + return ((NLA_HDRLEN) + + hdd_add_survey_info_sap_get_len() + + hdd_add_sta_info_sap_get_len() + + (sizeof(uint32_t) + NLA_HDRLEN)); +} + +/** + * hdd_add_link_standard_info_sap - add add link info attribute + * @skb: pointer to response skb buffer + * @rssi: station RSSI + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds link info attribute to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_link_standard_info_sap(struct sk_buff *skb, int8_t rssi, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + if (hdd_add_survey_info_sap(skb, stainfo, NL80211_ATTR_SURVEY_INFO)) + goto fail; + if (hdd_add_sta_info_sap(skb, rssi, stainfo, NL80211_ATTR_STA_INFO)) + goto fail; + + if (nla_put_u32(skb, NL80211_ATTR_REASON_CODE, stainfo->reason_code)) { + hdd_err("Reason code put fail"); + goto fail; + } + if (nla_put_u16(skb, NL80211_ATTR_STA_CAPABILITY, + stainfo->capability)) { + hdd_err("put fail"); + goto fail; + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_add_ap_standard_info_sap_get_len - get data length used in + * hdd_add_ap_standard_info_sap() + * @stainfo: station information + * + * This function calculates the data length used in + * hdd_add_ap_standard_info_sap() + * + * Return: total data length used in hdd_add_ap_standard_info_sap() + */ +static uint32_t hdd_add_ap_standard_info_sap_get_len( + struct hdd_station_info *stainfo) +{ + uint32_t len; + + len = NLA_HDRLEN; + if (stainfo->vht_present) + len += (sizeof(stainfo->vht_caps) + NLA_HDRLEN); + if (stainfo->ht_present) + len += (sizeof(stainfo->ht_caps) + NLA_HDRLEN); + + return len; +} + +/** + * hdd_add_ap_standard_info_sap - add HT and VHT info attributes + * @skb: pointer to response skb buffer + * @stainfo: station information + * @idx: attribute type index for nla_next_start() + * + * This function adds HT and VHT info attributes to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_ap_standard_info_sap(struct sk_buff *skb, + struct hdd_station_info *stainfo, + int idx) +{ + struct nlattr *nla_attr; + + nla_attr = nla_nest_start(skb, idx); + if (!nla_attr) + goto fail; + + if (stainfo->vht_present) { + if (nla_put(skb, NL80211_ATTR_VHT_CAPABILITY, + sizeof(stainfo->vht_caps), + &stainfo->vht_caps)) { + hdd_err("put fail"); + goto fail; + } + + hdd_nofl_debug("Remote STA VHT capabilities len:%u", + (uint32_t)sizeof(stainfo->vht_caps)); + } + if (stainfo->ht_present) { + if (nla_put(skb, NL80211_ATTR_HT_CAPABILITY, + sizeof(stainfo->ht_caps), + &stainfo->ht_caps)) { + hdd_err("put fail"); + goto fail; + } + + hdd_nofl_debug("Remote STA HT capabilities len:%u", + (uint32_t)sizeof(stainfo->ht_caps)); + } + nla_nest_end(skb, nla_attr); + return 0; +fail: + return -EINVAL; +} + +/** + * hdd_decode_ch_width - decode channel band width based + * @ch_width: encoded enum value holding channel band width + * + * This function decodes channel band width from the given encoded enum value. + * + * Returns: decoded channel band width. + */ +static uint16_t hdd_decode_ch_width(tSirMacHTChannelWidth ch_width) +{ + switch (ch_width) { + case 0: + return 20; + case 1: + return 40; + case 2: + return 80; + case 3: + case 4: + return 160; + case 5: + return 320; + default: + hdd_debug("invalid enum: %d", ch_width); + return 20; + } +} + +/** + * hdd_get_cached_station_remote() - get cached(deleted) peer's info + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @mac_addr: mac address of requested peer + * + * This function collect and indicate the cached(deleted) peer's info + * + * Return: 0 on success, otherwise error value + */ + +static int hdd_get_cached_station_remote(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + struct hdd_station_info *stainfo; + struct sk_buff *skb = NULL; + uint32_t nl_buf_len = NLMSG_HDRLEN; + uint8_t channel_width; + uint16_t channel_width_v2; + + + stainfo = hdd_get_sta_info_by_mac(&adapter->cache_sta_info_list, + mac_addr.bytes, + STA_INFO_GET_CACHED_STATION_REMOTE); + + if (!stainfo) { + hdd_err("peer " QDF_MAC_ADDR_FMT " not found", + QDF_MAC_ADDR_REF(mac_addr.bytes)); + return -EINVAL; + } + + nl_buf_len += hdd_add_link_standard_info_sap_get_len() + + hdd_add_ap_standard_info_sap_get_len(stainfo) + + (sizeof(stainfo->dot11_mode) + NLA_HDRLEN) + + (sizeof(stainfo->ch_width) + NLA_HDRLEN) + + (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + + (sizeof(stainfo->rx_rate) + NLA_HDRLEN) + + (sizeof(stainfo->support_mode) + NLA_HDRLEN) + + (sizeof(stainfo->rx_mc_bc_cnt) + NLA_HDRLEN) + + (sizeof(stainfo->rx_retry_cnt) + NLA_HDRLEN); + if (stainfo->assoc_req_ies.len) + nl_buf_len += stainfo->assoc_req_ies.len + NLA_HDRLEN; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_put_sta_info_ref(&adapter->cache_sta_info_list, + &stainfo, true, + STA_INFO_GET_CACHED_STATION_REMOTE); + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (hdd_add_link_standard_info_sap(skb, stainfo->rssi, stainfo, + LINK_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("link standard put fail"); + goto fail; + } + + if (hdd_add_ap_standard_info_sap(skb, stainfo, + AP_INFO_STANDARD_NL80211_ATTR)) { + hdd_err("ap standard put fail"); + goto fail; + } + + /* upper layer expects decoded channel BW */ + channel_width_v2 = hdd_decode_ch_width(stainfo->ch_width); + if (channel_width_v2 > MAX_CHANNEL_BW_160) + channel_width = MAX_CHANNEL_BW_160; + else + channel_width = channel_width_v2; + + if (nla_put_u32(skb, REMOTE_SUPPORTED_MODE, + stainfo->support_mode) || + nla_put_u8(skb, REMOTE_CH_WIDTH, channel_width) || + nla_put_u16(skb, REMOTE_CH_WIDTH_V2, channel_width_v2)) { + hdd_err("remote ch put fail"); + goto fail; + } + /* Convert the data from kbps to mbps as expected by the user space */ + if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate / 1000)) { + hdd_err("tx rate put fail"); + goto fail; + } + /* Convert the data from kbps to mbps as expected by the user space */ + if (nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate / 1000)) { + hdd_err("rx rate put fail"); + goto fail; + } + if (nla_put_u32(skb, WLAN802_11_MODE, stainfo->dot11_mode)) { + hdd_err("dot11 mode put fail"); + goto fail; + } + if (!(stainfo->rx_mc_bc_cnt & HDD_STATION_INFO_RX_MC_BC_COUNT)) { + hdd_debug("rx mc bc count is not supported by FW"); + } else if (nla_put_u32(skb, REMOTE_RX_BC_MC_COUNT, + (stainfo->rx_mc_bc_cnt & + (~HDD_STATION_INFO_RX_MC_BC_COUNT)))) { + hdd_err("rx mc bc put fail"); + goto fail; + } else { + hdd_nofl_debug("Remote STA RX mc_bc_count: %d", + (stainfo->rx_mc_bc_cnt & + (~HDD_STATION_INFO_RX_MC_BC_COUNT))); + } + + /* Currently rx_retry count is not supported */ + if (stainfo->rx_retry_cnt) { + if (nla_put_u32(skb, REMOTE_RX_RETRY_COUNT, + stainfo->rx_retry_cnt)) { + hdd_err("rx retry count put fail"); + goto fail; + } + hdd_nofl_debug("Remote STA retry count: %d", + stainfo->rx_retry_cnt); + } + + if (stainfo->assoc_req_ies.len) { + if (nla_put(skb, ASSOC_REQ_IES, stainfo->assoc_req_ies.len, + stainfo->assoc_req_ies.ptr)) { + hdd_err("Failed to put assoc req IEs"); + goto fail; + } + hdd_nofl_debug("Remote STA assoc req IE len: %d", + stainfo->assoc_req_ies.len); + } + + hdd_nofl_debug( + "Remote STA Info:: freq:%d, RSSI:%d, Tx NSS:%d, Reason code:%d," + "capability:0x%x, Supported mode:%d, chan_width:%d, Tx rate:%d," + "Rx rate:%d, dot11mode:%d", + stainfo->freq, stainfo->rssi, + stainfo->nss, stainfo->reason_code, stainfo->capability, + stainfo->support_mode, channel_width, stainfo->tx_rate, + stainfo->rx_rate, stainfo->dot11_mode); + + hdd_sta_info_detach(&adapter->cache_sta_info_list, &stainfo); + hdd_put_sta_info_ref(&adapter->cache_sta_info_list, &stainfo, true, + STA_INFO_GET_CACHED_STATION_REMOTE); + qdf_atomic_dec(&adapter->cache_sta_count); + + return wlan_cfg80211_vendor_cmd_reply(skb); +fail: + hdd_put_sta_info_ref(&adapter->cache_sta_info_list, &stainfo, true, + STA_INFO_GET_CACHED_STATION_REMOTE); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * hdd_get_connected_station_info() - get connected peer's info + * @link_info: Link info pointer in HDD adapter + * @mac_addr: mac address of requested peer + * @stainfo: location to store peer info + * + * This function collect and indicate the connected peer's info + * + * Return: 0 on success, otherwise error value + */ +static int hdd_get_connected_station_info(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr mac_addr, + struct hdd_station_info *stainfo) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len; + struct stats_event *stats; + bool txrx_rate = false, value; + QDF_STATUS status; + int ret; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += (sizeof(stainfo->max_phy_rate) + NLA_HDRLEN) + + (sizeof(stainfo->tx_packets) + NLA_HDRLEN) + + (sizeof(stainfo->tx_bytes) + NLA_HDRLEN) + + (sizeof(stainfo->rx_packets) + NLA_HDRLEN) + + (sizeof(stainfo->rx_bytes) + NLA_HDRLEN) + + (sizeof(stainfo->is_qos_enabled) + NLA_HDRLEN) + + (sizeof(stainfo->mode) + NLA_HDRLEN); + + status = ucfg_mlme_get_sap_get_peer_info(hdd_ctx->psoc, &value); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Unable to fetch sap ger peer info"); + if (value) { + stats = wlan_cfg80211_mc_cp_stats_get_peer_stats( + link_info->vdev, mac_addr.bytes, + &ret); + if (ret || !stats) { + hdd_err("fail to get tx/rx rate"); + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + } else { + txrx_rate = true; + } + } + + if (txrx_rate) { + stainfo->tx_rate = stats->peer_stats_info_ext->tx_rate; + stainfo->rx_rate = stats->peer_stats_info_ext->rx_rate; + stainfo->tx_packets = stats->peer_stats_info_ext->tx_packets; + stainfo->tx_bytes = stats->peer_stats_info_ext->tx_bytes; + stainfo->rx_packets = stats->peer_stats_info_ext->rx_packets; + stainfo->rx_bytes = stats->peer_stats_info_ext->rx_bytes; + nl_buf_len += (sizeof(stainfo->tx_rate) + NLA_HDRLEN) + + (sizeof(stainfo->rx_rate) + NLA_HDRLEN); + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + } + + /* below info is only valid for HT/VHT mode */ + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) + nl_buf_len += (sizeof(stainfo->ampdu) + NLA_HDRLEN) + + (sizeof(stainfo->tx_stbc) + NLA_HDRLEN) + + (sizeof(stainfo->rx_stbc) + NLA_HDRLEN) + + (sizeof(stainfo->ch_width) + NLA_HDRLEN) + + (sizeof(stainfo->sgi_enable) + NLA_HDRLEN); + + hdd_info("buflen %d hdrlen %d", nl_buf_len, NLMSG_HDRLEN); + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + hdd_info("stainfo"); + hdd_info("maxrate %x tx_pkts %x tx_bytes %llx", + stainfo->max_phy_rate, stainfo->tx_packets, stainfo->tx_bytes); + hdd_info("rx_pkts %x rx_bytes %llx mode %x", + stainfo->rx_packets, stainfo->rx_bytes, stainfo->mode); + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { + hdd_info("ampdu %d tx_stbc %d rx_stbc %d", + stainfo->ampdu, stainfo->tx_stbc, stainfo->rx_stbc); + hdd_info("wmm %d chwidth %d sgi %d", + stainfo->is_qos_enabled, + stainfo->ch_width, stainfo->sgi_enable); + } + + if (nla_put_u32(skb, REMOTE_MAX_PHY_RATE, stainfo->max_phy_rate) || + nla_put_u32(skb, REMOTE_TX_PACKETS, stainfo->tx_packets) || + remote_station_put_u64(skb, REMOTE_TX_BYTES, stainfo->tx_bytes) || + nla_put_u32(skb, REMOTE_RX_PACKETS, stainfo->rx_packets) || + remote_station_put_u64(skb, REMOTE_RX_BYTES, stainfo->rx_bytes) || + nla_put_u8(skb, REMOTE_WMM, stainfo->is_qos_enabled) || + nla_put_u8(skb, REMOTE_SUPPORTED_MODE, stainfo->mode)) { + hdd_err("put fail"); + goto fail; + } + + if (txrx_rate) { + if (nla_put_u32(skb, REMOTE_LAST_TX_RATE, stainfo->tx_rate) || + nla_put_u32(skb, REMOTE_LAST_RX_RATE, stainfo->rx_rate)) { + hdd_err("put fail"); + goto fail; + } else { + hdd_info("tx_rate %x rx_rate %x", + stainfo->tx_rate, stainfo->rx_rate); + } + } + + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { + if (nla_put_u8(skb, REMOTE_AMPDU, stainfo->ampdu) || + nla_put_u8(skb, REMOTE_TX_STBC, stainfo->tx_stbc) || + nla_put_u8(skb, REMOTE_RX_STBC, stainfo->rx_stbc) || + nla_put_u8(skb, REMOTE_CH_WIDTH, stainfo->ch_width) || + nla_put_u8(skb, REMOTE_SGI_ENABLE, stainfo->sgi_enable)) { + hdd_err("put fail"); + goto fail; + } + } + + return wlan_cfg80211_vendor_cmd_reply(skb); + +fail: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * hdd_get_station_remote() - get remote peer's info + * @link_info: Link info pointer in HDD adapter + * @mac_addr: mac address of requested peer + * + * This function collect and indicate the remote peer's info + * + * Return: 0 on success, otherwise error value + */ +static int hdd_get_station_remote(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr mac_addr) +{ + int status = 0; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_info *stainfo = + hdd_get_sta_info_by_mac( + &adapter->sta_info_list, + mac_addr.bytes, + STA_INFO_HDD_GET_STATION_REMOTE); + + if (!stainfo) { + status = hdd_get_cached_station_remote(hdd_ctx, adapter, + mac_addr); + return status; + } + + status = hdd_get_connected_station_info(link_info, mac_addr, stainfo); + hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true, + STA_INFO_HDD_GET_STATION_REMOTE); + return status; +} + +/** + * __hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int +__hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + 1]; + int32_t status; + + hdd_enter_dev(dev); + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + status = -EPERM; + goto out; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + goto out; + + status = wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX, + data, data_len, + hdd_get_station_policy); + if (status) { + hdd_err("Invalid ATTR"); + goto out; + } + + /* Parse and fetch Command Type*/ + if (tb[STATION_INFO]) { + status = hdd_get_station_info(adapter->deflink); + } else if (tb[STATION_ASSOC_FAIL_REASON]) { + status = hdd_get_station_assoc_fail(adapter->deflink); + } else if (tb[STATION_REMOTE]) { + struct qdf_mac_addr mac_addr; + + if (adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("invalid device_mode:%d", adapter->device_mode); + status = -EINVAL; + goto out; + } + + nla_memcpy(mac_addr.bytes, tb[STATION_REMOTE], + QDF_MAC_ADDR_SIZE); + + hdd_debug("STATION_REMOTE " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + + status = hdd_get_station_remote(adapter->deflink, mac_addr); + } else { + hdd_err("get station info cmd type failed"); + status = -EINVAL; + goto out; + } + hdd_exit(); +out: + return status; +} + +int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __hdd_cfg80211_get_station_cmd(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_get_peer_stats - get peer statistics information + * @adapter: pointer to adapter + * @stainfo: station information + * + * This function gets peer statistics information. If IPA is + * enabled the Rx bcast/mcast count is updated in the + * exception callback invoked by the IPA driver. In case of + * back pressure the packets may get routed to the sw path and + * where eventually the peer mcast/bcast pkt counts are updated in + * dp rx process handling. + * + * Return : 0 on success and errno on failure + */ +static int hdd_get_peer_stats(struct hdd_adapter *adapter, + struct hdd_station_info *stainfo) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_peer_stats *peer_stats; + struct cds_vdev_dp_stats dp_stats; + struct stats_event *stats; + QDF_STATUS status; + int i, ret = 0; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) + return -ENOMEM; + + status = cdp_host_get_peer_stats(soc, adapter->deflink->vdev_id, + stainfo->sta_mac.bytes, peer_stats); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("cdp_host_get_peer_stats failed"); + qdf_mem_free(peer_stats); + return -EINVAL; + } + + stainfo->rx_retry_cnt = peer_stats->rx.rx_retries; + if (!ucfg_ipa_is_enabled()) + stainfo->rx_mc_bc_cnt = peer_stats->rx.multicast.num + + peer_stats->rx.bcast.num; + else + stainfo->rx_mc_bc_cnt += peer_stats->rx.multicast.num + + peer_stats->rx.bcast.num; + + qdf_mem_free(peer_stats); + peer_stats = NULL; + + stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(adapter->deflink->vdev, + stainfo->sta_mac.bytes, + &ret); + if (ret || !stats) { + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + hdd_err("Failed to get peer stats info"); + return -EINVAL; + } + + if (cds_dp_get_vdev_stats(adapter->deflink->vdev_id, &dp_stats)) + stainfo->tx_retry_succeed = + dp_stats.tx_mpdu_success_with_retries; + else + hdd_err("failed to get dp vdev stats"); + + /* This host counter is not supported + * since currently tx retry is not done in host side + */ + stainfo->tx_retry_exhaust = 0; + stainfo->tx_total_fw = stats->peer_stats_info_ext->tx_packets; + stainfo->tx_retry_fw = stats->peer_stats_info_ext->tx_retries; + stainfo->tx_retry_exhaust_fw = stats->peer_stats_info_ext->tx_failed; + + if (stats->peer_stats_info_ext->num_tx_rate_counts) { + stainfo->tx_pkt_per_mcs = qdf_mem_malloc( + stats->peer_stats_info_ext->num_tx_rate_counts * + sizeof(uint32_t)); + if (stainfo->tx_pkt_per_mcs) { + stainfo->num_tx_rate_count = + stats->peer_stats_info_ext->num_tx_rate_counts; + qdf_mem_copy( + stainfo->tx_pkt_per_mcs, + stats->peer_stats_info_ext->tx_pkt_per_mcs, + stainfo->num_tx_rate_count * sizeof(uint32_t)); + } + } + if (stats->peer_stats_info_ext->num_rx_rate_counts) { + stainfo->rx_pkt_per_mcs = qdf_mem_malloc( + stats->peer_stats_info_ext->num_rx_rate_counts * + sizeof(uint32_t)); + if (stainfo->rx_pkt_per_mcs) { + stainfo->num_rx_rate_count = + stats->peer_stats_info_ext->num_rx_rate_counts; + qdf_mem_copy( + stainfo->rx_pkt_per_mcs, + stats->peer_stats_info_ext->rx_pkt_per_mcs, + stainfo->num_rx_rate_count * sizeof(uint32_t)); + } + } + + /* Optional, just print logs here */ + if (!stats->num_peer_adv_stats) { + hdd_debug("Failed to get peer adv stats info"); + stainfo->rx_fcs_count = 0; + } + + for (i = 0; i < stats->num_peer_adv_stats; i++) { + if (!qdf_mem_cmp(stainfo->sta_mac.bytes, + stats->peer_adv_stats[i].peer_macaddr, + QDF_MAC_ADDR_SIZE)) { + stainfo->rx_fcs_count = stats->peer_adv_stats[i]. + fcs_count; + break; + } + } + + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + + return ret; +} + +/** + * hdd_free_tx_rx_pkts_per_mcs - Free memory for tx packets per MCS and + * rx packets per MCS + * @stainfo: station information + * + * Return: None + */ +static void hdd_free_tx_rx_pkts_per_mcs(struct hdd_station_info *stainfo) +{ + if (stainfo->tx_pkt_per_mcs) { + qdf_mem_free(stainfo->tx_pkt_per_mcs); + stainfo->tx_pkt_per_mcs = NULL; + } + if (stainfo->rx_pkt_per_mcs) { + qdf_mem_free(stainfo->rx_pkt_per_mcs); + stainfo->rx_pkt_per_mcs = NULL; + } +} + +/** + * hdd_add_peer_stats_get_len - get data length used in + * hdd_add_peer_stats() + * @stainfo: station information + * + * This function calculates the data length used in + * hdd_add_peer_stats() + * + * Return: total data length used in hdd_add_peer_stats() + */ +static uint32_t +hdd_add_peer_stats_get_len(struct hdd_station_info *stainfo) +{ + uint32_t tx_count_size = 0; + uint32_t rx_count_size = 0; + uint16_t i; + + for (i = 0; i < stainfo->num_tx_rate_count; i++) + tx_count_size += nla_attr_size(sizeof(uint32_t)); + for (i = 0; i < stainfo->num_rx_rate_count; i++) + rx_count_size += nla_attr_size(sizeof(uint32_t)); + + return (nla_attr_size(sizeof(stainfo->rx_retry_cnt)) + + nla_attr_size(sizeof(stainfo->rx_mc_bc_cnt)) + + nla_attr_size(sizeof(stainfo->tx_retry_succeed)) + + nla_attr_size(sizeof(stainfo->tx_retry_exhaust)) + + nla_attr_size(sizeof(stainfo->tx_total_fw)) + + nla_attr_size(sizeof(stainfo->tx_retry_fw)) + + nla_attr_size(sizeof(stainfo->tx_retry_exhaust_fw)) + + nla_attr_size(sizeof(stainfo->rx_fcs_count)) + + tx_count_size + rx_count_size); +} + +/** + * hdd_get_pmf_bcn_protect_stats_len() - get pmf bcn protect counters len + * @link_info: pointer to link_info struct in adapter + * + * This function calculates the data length for valid pmf bcn counters. + * + * Return: total data length used in hdd_add_peer_stats() + */ +static uint32_t +hdd_get_pmf_bcn_protect_stats_len(struct wlan_hdd_link_info *link_info) +{ + if (!link_info->hdd_stats.bcn_protect_stats.pmf_bcn_stats_valid) + return 0; + + /* 4 pmf becon protect counters each of 32 bit */ + return nla_total_size(sizeof(uint32_t)) * 4; +} + +static uint32_t +hdd_get_connect_fail_reason_code_len(struct hdd_adapter *adapter) +{ + if (adapter->connect_req_status == STATUS_SUCCESS) + return 0; + + return nla_total_size(sizeof(uint32_t)); +} + +/** + * hdd_add_pmf_bcn_protect_stats() - add pmf bcn protect counters in resp + * @skb: pointer to response skb buffer + * @link_info: Pointer to link_info holding valid bcn protect counters + * + * This function adds the pmf bcn stats in response. + * + * Return: 0 on success + */ +static int +hdd_add_pmf_bcn_protect_stats(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info) +{ + struct hdd_stats *hdd_stats = &link_info->hdd_stats; + + if (!hdd_stats->bcn_protect_stats.pmf_bcn_stats_valid) + return 0; + + hdd_stats->bcn_protect_stats.pmf_bcn_stats_valid = 0; + if (nla_put_u32(skb, STA_INFO_BIP_MIC_ERROR_COUNT, + hdd_stats->bcn_protect_stats.igtk_mic_fail_cnt) || + nla_put_u32(skb, STA_INFO_BIP_REPLAY_COUNT, + hdd_stats->bcn_protect_stats.igtk_replay_cnt) || + nla_put_u32(skb, STA_INFO_BEACON_MIC_ERROR_COUNT, + hdd_stats->bcn_protect_stats.bcn_mic_fail_cnt) || + nla_put_u32(skb, STA_INFO_BEACON_REPLAY_COUNT, + hdd_stats->bcn_protect_stats.bcn_replay_cnt)) { + hdd_err("put fail"); + return -EINVAL; + } + + return 0; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/** + * hdd_get_big_data_stats_len - get data length used in + * hdd_big_data_pack_resp_nlmsg() + * @link_info: Link info pointer in HDD adapter. + * + * This function calculates the data length used in + * hdd_big_data_pack_resp_nlmsg() + * + * Return: total data length used in hdd_big_data_pack_resp_nlmsg() + */ +static uint32_t +hdd_get_big_data_stats_len(struct wlan_hdd_link_info *link_info) +{ + uint32_t len; + struct big_data_stats_event *big_data_stats = + &link_info->big_data_stats; + + len = nla_total_size(sizeof(big_data_stats->last_tx_data_rate_kbps)) + + nla_total_size(sizeof(big_data_stats->target_power_ofdm)) + + nla_total_size(sizeof(big_data_stats->target_power_dsss)) + + nla_total_size(sizeof(big_data_stats->last_tx_data_rix)) + + nla_total_size(sizeof(big_data_stats->tsf_out_of_sync)) + + nla_total_size(sizeof(big_data_stats->ani_level)) + + nla_total_size(sizeof(big_data_stats->last_data_tx_pwr)); + + /** Add len of roam params **/ + len += nla_total_size(sizeof(uint32_t)) * 3; + + return len; +} + +/** + * hdd_big_data_pack_resp_nlmsg() - pack big data nl resp msg + * @skb: pointer to response skb buffer + * @link_info: Link info pointer in HDD adapter + * + * This function adds big data stats in response. + * + * Return: 0 on success + */ +static int hdd_big_data_pack_resp_nlmsg(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + struct big_data_stats_event *big_data_stats = + &link_info->big_data_stats; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!hdd_sta_ctx) { + hdd_err("Invalid station context"); + return -EINVAL; + } + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_RATE, + big_data_stats->last_tx_data_rate_kbps)){ + hdd_err("latest tx rate put fail"); + return -EINVAL; + } + + if (WLAN_REG_IS_5GHZ_CH_FREQ(hdd_sta_ctx->cache_conn_info.chan_freq)) { + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_5G_6MBPS, + big_data_stats->target_power_ofdm)){ + hdd_err("5G ofdm power put fail"); + return -EINVAL; + } + } else if (WLAN_REG_IS_24GHZ_CH_FREQ( + hdd_sta_ctx->cache_conn_info.chan_freq)){ + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_6MBPS, + big_data_stats->target_power_ofdm)){ + hdd_err("2.4G ofdm power put fail"); + return -EINVAL; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_POWER_24G_1MBPS, + big_data_stats->target_power_dsss)){ + hdd_err("target power dsss put fail"); + return -EINVAL; + } + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_RIX, + big_data_stats->last_tx_data_rix)){ + hdd_err("last rix rate put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TSF_OUT_OF_SYNC_COUNT, + big_data_stats->tsf_out_of_sync)){ + hdd_err("tsf out of sync put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ANI_LEVEL, + big_data_stats->ani_level)){ + hdd_err("ani level put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_LATEST_TX_POWER, + big_data_stats->last_data_tx_pwr)){ + hdd_err("last data tx power put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_TRIGGER_REASON, + wlan_cm_get_roam_states(hdd_ctx->psoc, + link_info->vdev_id, + ROAM_TRIGGER_REASON))){ + hdd_err("roam trigger reason put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_FAIL_REASON, + wlan_cm_get_roam_states(hdd_ctx->psoc, + link_info->vdev_id, + ROAM_FAIL_REASON))){ + hdd_err("roam fail reason put fail"); + return -EINVAL; + } + if (nla_put_u32( + skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_ROAM_INVOKE_FAIL_REASON, + wlan_cm_get_roam_states(hdd_ctx->psoc, + link_info->vdev_id, + ROAM_INVOKE_FAIL_REASON))){ + hdd_err("roam invoke fail reason put fail"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_reset_roam_params() - reset roam params + * @psoc: psoc + * @vdev_id: vdev id + * + * This function resets big data roam params + * + * Return: None + */ +static void +hdd_reset_roam_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{ + wlan_cm_update_roam_states(psoc, vdev_id, + 0, ROAM_TRIGGER_REASON); + wlan_cm_update_roam_states(psoc, vdev_id, + 0, ROAM_FAIL_REASON); + wlan_cm_update_roam_states(psoc, vdev_id, + 0, ROAM_INVOKE_FAIL_REASON); +} +#else +static inline int +hdd_big_data_pack_resp_nlmsg(struct sk_buff *skb, + struct wlan_hdd_link_info *link_info) +{ + return 0; +} + +static uint32_t +hdd_get_big_data_stats_len(struct wlan_hdd_link_info *link_info) +{ + return 0; +} + +static void +hdd_reset_roam_params(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id) +{} +#endif + +/** + * hdd_add_connect_fail_reason_code() - Fills connect fail reason code + * @skb: pointer to skb + * @adapter: pointer to hdd adapter + * + * Return: on success 0 else error code + */ +static int hdd_add_connect_fail_reason_code(struct sk_buff *skb, + struct hdd_adapter *adapter) +{ + uint32_t reason; + + reason = osif_cm_mac_to_qca_connect_fail_reason( + adapter->connect_req_status); + if (!reason) + return 0; + + if (nla_put_u32(skb, STA_INFO_CONNECT_FAIL_REASON_CODE, reason)) { + hdd_err("put fail"); + return -EINVAL; + } + + return 0; +} + +/** + * hdd_add_peer_stats - add peer statistics information + * @skb: pointer to response skb buffer + * @stainfo: station information + * + * This function adds peer statistics information to response skb buffer + * + * Return : 0 on success and errno on failure + */ +static int hdd_add_peer_stats(struct sk_buff *skb, + struct hdd_station_info *stainfo) +{ + struct nlattr *nla_attr; + uint8_t i; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_RETRY_COUNT, + stainfo->rx_retry_cnt)) { + hdd_err("Failed to put rx_retry_cnt"); + goto fail; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_BC_MC_COUNT, + stainfo->rx_mc_bc_cnt)) { + hdd_err("Failed to put rx_mc_bc_cnt"); + goto fail; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_SUCCEED, + stainfo->tx_retry_succeed)) { + hdd_err("Failed to put tx_retry_succeed"); + goto fail; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TX_RETRY_EXHAUSTED, + stainfo->tx_retry_exhaust)) { + hdd_err("Failed to put tx_retry_exhaust"); + goto fail; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_TOTAL, + stainfo->tx_total_fw)) { + hdd_err("Failed to put tx_total_fw"); + goto fail; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY, + stainfo->tx_retry_fw)) { + hdd_err("Failed to put tx_retry_fw"); + goto fail; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_TARGET_TX_RETRY_EXHAUSTED, + stainfo->tx_retry_exhaust_fw)) { + hdd_err("Failed to put tx_retry_exhaust_fw"); + goto fail; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_RX_FRAMES_CRC_FAIL_COUNT, + stainfo->rx_fcs_count)) { + hdd_err("Failed to put rx_fcs_count"); + goto fail; + } + + nla_attr = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS); + if (!nla_attr) { + hdd_err("nla nest start for tx packets fail"); + goto fail; + } + + for (i = 0; i < stainfo->num_tx_rate_count; i++) + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS, + stainfo->tx_pkt_per_mcs[i])) { + hdd_err("Failed to put tx_rate_count for MCS[%d]", i); + goto fail; + } + nla_nest_end(skb, nla_attr); + + nla_attr = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_RX_PACKETS); + if (!nla_attr) { + hdd_err("nla nest start for rx packets fail"); + goto fail; + } + + for (i = 0; i < stainfo->num_rx_rate_count; i++) + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_PER_MCS_TX_PACKETS, + stainfo->rx_pkt_per_mcs[i])) { + hdd_err("Failed to put rx_rate_count for MCS[%d]", i); + goto fail; + } + nla_nest_end(skb, nla_attr); + + hdd_free_tx_rx_pkts_per_mcs(stainfo); + return 0; +fail: + hdd_free_tx_rx_pkts_per_mcs(stainfo); + return -EINVAL; +} + +/** + * hdd_get_connected_station_info_ex() - get connected peer's info + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @stainfo: pointer to hdd_station_info + * + * This function collect and indicate the connected peer's info + * + * Return: 0 on success, otherwise error value + */ +static int hdd_get_connected_station_info_ex(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct hdd_station_info *stainfo) +{ + struct sk_buff *skb = NULL; + uint32_t nl_buf_len, guard_interval; + bool sap_get_peer_info; + struct nl80211_sta_flag_update sta_flags = {0}; + const uint8_t *mac_addr; + QDF_STATUS status; + + if (hdd_get_peer_stats(adapter, stainfo)) { + hdd_err_rl("hdd_get_peer_stats fail"); + return -EINVAL; + } + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += nla_attr_size(QDF_MAC_ADDR_SIZE); + status = ucfg_mlme_get_sap_get_peer_info(hdd_ctx->psoc, + &sap_get_peer_info); + if (status != QDF_STATUS_SUCCESS) + hdd_err_rl("Unable to fetch sap ger peer info"); + + if (sap_get_peer_info) + nl_buf_len += hdd_add_peer_stats_get_len(stainfo); + + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) + nl_buf_len += nla_attr_size(sizeof(sta_flags)) + + nla_attr_size(sizeof(guard_interval)); + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err_rl("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (qdf_is_macaddr_zero(&stainfo->mld_addr)) + mac_addr = &stainfo->sta_mac.bytes[0]; + else + mac_addr = &stainfo->mld_addr.bytes[0]; + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC, + QDF_MAC_ADDR_SIZE, mac_addr)) { + hdd_err_rl("Failed to put MAC address"); + goto fail; + } + + if (sap_get_peer_info && hdd_add_peer_stats(skb, stainfo)) { + hdd_err_rl("hdd_add_peer_stats fail"); + goto fail; + } + + if (stainfo->mode > SIR_SME_PHY_MODE_LEGACY) { + sta_flags.mask = QCA_VENDOR_WLAN_STA_FLAG_AMPDU | + QCA_VENDOR_WLAN_STA_FLAG_TX_STBC | + QCA_VENDOR_WLAN_STA_FLAG_RX_STBC; + + if (stainfo->ampdu) + sta_flags.set |= QCA_VENDOR_WLAN_STA_FLAG_AMPDU; + if (stainfo->tx_stbc) + sta_flags.set |= QCA_VENDOR_WLAN_STA_FLAG_TX_STBC; + if (stainfo->rx_stbc) + sta_flags.set |= QCA_VENDOR_WLAN_STA_FLAG_RX_STBC; + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_FLAGS, + sizeof(sta_flags), &sta_flags)) { + hdd_err_rl("Failed to put STA flags"); + goto fail; + } + + switch (stainfo->guard_interval) { + case TXRATE_GI_0_8_US: + guard_interval = QCA_VENDOR_WLAN_STA_GI_800_NS; + break; + case TXRATE_GI_0_4_US: + guard_interval = QCA_VENDOR_WLAN_STA_GI_400_NS; + break; + case TXRATE_GI_1_6_US: + guard_interval = QCA_VENDOR_WLAN_STA_GI_1600_NS; + break; + case TXRATE_GI_3_2_US: + guard_interval = QCA_VENDOR_WLAN_STA_GI_3200_NS; + break; + default: + hdd_err_rl("Invalid guard_interval %d", + stainfo->guard_interval); + goto fail; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_GUARD_INTERVAL, + guard_interval)) { + hdd_err_rl("Failed to put guard_interval"); + goto fail; + } + } + + return wlan_cfg80211_vendor_cmd_reply(skb); + +fail: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +/** + * hdd_get_station_remote_ex() - get remote peer's info, for SAP/GO mode only + * @hdd_ctx: hdd context + * @adapter: hostapd interface + * @mac_addr: mac address of requested peer + * + * This function collect and indicate the remote peer's info + * + * Return: 0 on success, otherwise error value + */ +static int hdd_get_station_remote_ex(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + struct qdf_mac_addr mac_addr) +{ + struct hdd_station_info *stainfo = + hdd_get_sta_info_by_mac(&adapter->sta_info_list, + mac_addr.bytes, + STA_INFO_HDD_GET_STATION_REMOTE); + int status; + + /* For now, only connected STAs are supported */ + if (!stainfo) { + hdd_err_rl("Failed to get peer STA " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + return -ENXIO; + } + + status = hdd_get_connected_station_info_ex(hdd_ctx, adapter, stainfo); + hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, true, + STA_INFO_HDD_GET_STATION_REMOTE); + + return status; +} + +/** + * hdd_get_station_info_ex() - send STA info to userspace, for STA mode only + * @link_info: Pointer of link info in HDD adapter. + * + * Return: 0 if success else error status + */ +static int hdd_get_station_info_ex(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct sk_buff *skb; + uint32_t nl_buf_len = 0, connect_fail_rsn_len; + struct hdd_station_ctx *hdd_sta_ctx; + bool big_data_stats_req = false; + bool big_data_fw_support = false; + int ret; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + ucfg_mc_cp_get_big_data_fw_support(hdd_ctx->psoc, &big_data_fw_support); + + if (hdd_cm_is_disconnected(link_info) && big_data_fw_support) + big_data_stats_req = true; + + if (wlan_hdd_get_station_stats(link_info)) + hdd_err_rl("wlan_hdd_get_station_stats fail"); + + wlan_hdd_get_peer_rx_rate_stats(link_info); + + if (big_data_stats_req) { + if (wlan_hdd_get_big_data_station_stats(link_info)) { + hdd_err_rl("wlan_hdd_get_big_data_station_stats fail"); + return -EINVAL; + } + nl_buf_len = hdd_get_big_data_stats_len(link_info); + } + + nl_buf_len += hdd_get_pmf_bcn_protect_stats_len(link_info); + connect_fail_rsn_len = hdd_get_connect_fail_reason_code_len(adapter); + nl_buf_len += connect_fail_rsn_len; + nl_buf_len += hdd_get_uplink_delay_len(adapter); + if (!nl_buf_len) { + hdd_err_rl("Failed to get bcn pmf stats"); + return -EINVAL; + } + + nl_buf_len += NLMSG_HDRLEN; + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + nl_buf_len); + if (!skb) { + hdd_err_rl("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (hdd_add_pmf_bcn_protect_stats(skb, link_info)) { + hdd_err_rl("hdd_add_pmf_bcn_protect_stats fail"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + if (connect_fail_rsn_len) { + if (hdd_add_connect_fail_reason_code(skb, adapter)) { + hdd_err_rl("hdd_add_connect_fail_reason_code fail"); + wlan_cfg80211_vendor_free_skb(skb); + return -ENOMEM; + } + } + + if (big_data_stats_req) { + if (hdd_big_data_pack_resp_nlmsg(skb, link_info)) { + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + } + + if (QDF_IS_STATUS_ERROR(hdd_add_uplink_delay(adapter, skb))) { + hdd_err_rl("hdd_add_uplink_delay fail"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + ret = wlan_cfg80211_vendor_cmd_reply(skb); + hdd_reset_roam_params(hdd_ctx->psoc, link_info->vdev_id); + return ret; +} + +/** + * __hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd + * @wiphy: pointer to wireless phy + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +static int +__hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1]; + struct qdf_mac_addr mac_addr; + int32_t status; + + hdd_enter_dev(dev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE || + hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) { + hdd_err_rl("Command not allowed in FTM / Monitor mode"); + status = -EPERM; + goto out; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + goto out; + + status = wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX, + data, data_len, + hdd_get_sta_policy); + if (status) { + hdd_err_rl("Invalid ATTR"); + goto out; + } + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + status = hdd_get_station_info_ex(adapter->deflink); + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (!tb[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC]) { + hdd_err_rl("MAC address is not present"); + status = -EINVAL; + goto out; + } + + nla_memcpy(mac_addr.bytes, + tb[QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAC], + QDF_MAC_ADDR_SIZE); + hdd_debug("STA " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + status = hdd_get_station_remote_ex(hdd_ctx, adapter, mac_addr); + break; + default: + hdd_err_rl("Invalid device_mode: %d", adapter->device_mode); + status = -EINVAL; + goto out; + } + + hdd_exit(); +out: + return status; +} + +int32_t hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_qmi_get_sync_resume(); + if (errno) { + hdd_err("qmi sync resume failed: %d", errno); + goto end; + } + + errno = __hdd_cfg80211_get_sta_info_cmd(wiphy, wdev, data, data_len); + + wlan_hdd_qmi_put_suspend(); + +end: + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_station_info.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_station_info.h new file mode 100644 index 0000000000..1de9a0e326 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_station_info.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012-2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_STATION_INFO_H +#define __WLAN_HDD_STATION_INFO_H + +/** + * DOC: wlan_hdd_station_info_h + * + * WLAN Host Device Driver STATION info API specification + */ + +#ifdef FEATURE_STATION_INFO +extern const struct nla_policy hdd_get_station_policy[ + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX + 1]; + +/** + * hdd_cfg80211_get_station_cmd() - Handle get station vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STATION. + * Validate cmd attributes and send the station info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +int32_t hdd_cfg80211_get_station_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +extern const struct nla_policy hdd_get_sta_policy[ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX + 1]; + +/** + * hdd_cfg80211_get_sta_info_cmd() - Handle get sta info vendor cmd + * @wiphy: corestack handler + * @wdev: wireless device + * @data: data + * @data_len: data length + * + * Handles QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO. + * Validate cmd attributes and send the sta info to upper layers. + * + * Return: Success(0) or reason code for failure + */ +int32_t hdd_cfg80211_get_sta_info_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_STATION_INFO_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_STATION, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = hdd_cfg80211_get_station_cmd, \ + vendor_command_policy(hdd_get_station_policy, \ + QCA_WLAN_VENDOR_ATTR_GET_STATION_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_STA_INFO, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = hdd_cfg80211_get_sta_info_cmd, \ + vendor_command_policy(hdd_get_sta_policy, \ + QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_MAX) \ +}, +#else /* FEATURE_STATION_INFO */ +#define FEATURE_STATION_INFO_VENDOR_COMMANDS +#endif /* FEATURE_STATION_INFO */ + +#endif /* __WLAN_HDD_STATION_INFO_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c new file mode 100644 index 0000000000..94f41aae0d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_stats.c @@ -0,0 +1,11775 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_stats.c + * + * WLAN Host Device Driver statistics related implementation + * + */ + +#include "wlan_hdd_stats.h" +#include "sme_api.h" +#include "cds_sched.h" +#include "osif_sync.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_lpass.h" +#include "hif.h" +#include +#include "wma_api.h" +#include "wlan_hdd_hostapd.h" +#include "wlan_osif_request_manager.h" +#include "wlan_hdd_debugfs_llstat.h" +#include "wlan_hdd_debugfs_mibstat.h" +#include "wlan_reg_services_api.h" +#include +#include "wlan_cp_stats_mc_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_hdd_sta_info.h" +#include "cdp_txrx_misc.h" +#include "cdp_txrx_host_stats.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_hdd_eht.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_cm_roam_ucfg_api.h" +#include +#include +#ifdef CNSS_GENL +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss_nl.h" +#else +#include +#endif +#endif +#include "wlan_nan_api.h" + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) && !defined(WITH_BACKPORTS) +#define HDD_INFO_SIGNAL STATION_INFO_SIGNAL +#define HDD_INFO_SIGNAL_AVG STATION_INFO_SIGNAL_AVG +#define HDD_INFO_TX_PACKETS STATION_INFO_TX_PACKETS +#define HDD_INFO_TX_RETRIES STATION_INFO_TX_RETRIES +#define HDD_INFO_TX_FAILED STATION_INFO_TX_FAILED +#define HDD_INFO_TX_BITRATE STATION_INFO_TX_BITRATE +#define HDD_INFO_RX_BITRATE STATION_INFO_RX_BITRATE +#define HDD_INFO_TX_BYTES STATION_INFO_TX_BYTES +#define HDD_INFO_CHAIN_SIGNAL_AVG STATION_INFO_CHAIN_SIGNAL_AVG +#define HDD_INFO_EXPECTED_THROUGHPUT 0 +#define HDD_INFO_RX_BYTES STATION_INFO_RX_BYTES +#define HDD_INFO_RX_PACKETS STATION_INFO_RX_PACKETS +#define HDD_INFO_TX_BYTES64 0 +#define HDD_INFO_RX_BYTES64 0 +#define HDD_INFO_INACTIVE_TIME 0 +#define HDD_INFO_CONNECTED_TIME 0 +#define HDD_INFO_STA_FLAGS 0 +#define HDD_INFO_RX_MPDUS 0 +#define HDD_INFO_FCS_ERROR_COUNT 0 +#else +#define HDD_INFO_SIGNAL BIT(NL80211_STA_INFO_SIGNAL) +#define HDD_INFO_SIGNAL_AVG BIT(NL80211_STA_INFO_SIGNAL_AVG) +#define HDD_INFO_TX_PACKETS BIT(NL80211_STA_INFO_TX_PACKETS) +#define HDD_INFO_TX_RETRIES BIT(NL80211_STA_INFO_TX_RETRIES) +#define HDD_INFO_TX_FAILED BIT(NL80211_STA_INFO_TX_FAILED) +#define HDD_INFO_TX_BITRATE BIT(NL80211_STA_INFO_TX_BITRATE) +#define HDD_INFO_RX_BITRATE BIT(NL80211_STA_INFO_RX_BITRATE) +#define HDD_INFO_TX_BYTES BIT(NL80211_STA_INFO_TX_BYTES) +#define HDD_INFO_CHAIN_SIGNAL_AVG BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG) +#define HDD_INFO_EXPECTED_THROUGHPUT BIT(NL80211_STA_INFO_EXPECTED_THROUGHPUT) +#define HDD_INFO_RX_BYTES BIT(NL80211_STA_INFO_RX_BYTES) +#define HDD_INFO_RX_PACKETS BIT(NL80211_STA_INFO_RX_PACKETS) +#define HDD_INFO_TX_BYTES64 BIT(NL80211_STA_INFO_TX_BYTES64) +#define HDD_INFO_RX_BYTES64 BIT(NL80211_STA_INFO_RX_BYTES64) +#define HDD_INFO_INACTIVE_TIME BIT(NL80211_STA_INFO_INACTIVE_TIME) +#define HDD_INFO_CONNECTED_TIME BIT(NL80211_STA_INFO_CONNECTED_TIME) +#define HDD_INFO_STA_FLAGS BIT(NL80211_STA_INFO_STA_FLAGS) +#define HDD_INFO_RX_MPDUS BIT_ULL(NL80211_STA_INFO_RX_MPDUS) +#define HDD_INFO_FCS_ERROR_COUNT BIT_ULL(NL80211_STA_INFO_FCS_ERROR_COUNT) +#endif /* kernel version less than 4.0.0 && no_backport */ + +#define HDD_LINK_STATS_MAX 5 +#define HDD_MAX_ALLOWED_LL_STATS_FAILURE 5 + +#define INVALID_PREAMBLE 0xFF + +#define MAX_RSSI_MCS_INDEX 14 + +#define MAX_HT_MCS_INDEX 7 + +/* 11B, 11G Rate table include Basic rate and Extended rate + * The IDX field is the rate index + * The HI field is the rate when RSSI is strong or being ignored + * (in this case we report actual rate) + * The MID field is the rate when RSSI is moderate + * (in this case we cap 11b rates at 5.5 and 11g rates at 24) + * The LO field is the rate when RSSI is low + * (in this case we don't report rates, actual current rate used) + */ +static const struct index_data_rate_type supported_data_rate[] = { + /* IDX HI HM LM LO (RSSI-based index */ + {2, { 10, 10, 10, 0} }, + {4, { 20, 20, 10, 0} }, + {11, { 55, 20, 10, 0} }, + {12, { 60, 55, 20, 0} }, + {18, { 90, 55, 20, 0} }, + {22, {110, 55, 20, 0} }, + {24, {120, 90, 60, 0} }, + {36, {180, 120, 60, 0} }, + {44, {220, 180, 60, 0} }, + {48, {240, 180, 90, 0} }, + {66, {330, 180, 90, 0} }, + {72, {360, 240, 90, 0} }, + {96, {480, 240, 120, 0} }, + {108, {540, 240, 120, 0} } +}; +/* MCS Based rate table HT MCS parameters with Nss = 1 */ +static const struct index_data_rate_type supported_mcs_rate_nss1[] = { +/* MCS L20 L40 S20 S40 */ + {0, {65, 135, 72, 150} }, + {1, {130, 270, 144, 300} }, + {2, {195, 405, 217, 450} }, + {3, {260, 540, 289, 600} }, + {4, {390, 810, 433, 900} }, + {5, {520, 1080, 578, 1200} }, + {6, {585, 1215, 650, 1350} }, + {7, {650, 1350, 722, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static const struct index_data_rate_type supported_mcs_rate_nss2[] = { +/* MCS L20 L40 S20 S40 */ + {0, {130, 270, 144, 300} }, + {1, {260, 540, 289, 600} }, + {2, {390, 810, 433, 900} }, + {3, {520, 1080, 578, 1200} }, + {4, {780, 1620, 867, 1800} }, + {5, {1040, 2160, 1156, 2400} }, + {6, {1170, 2430, 1300, 2700} }, + {7, {1300, 2700, 1444, 3000} } +}; + +/* MCS Based VHT rate table MCS parameters with Nss = 1*/ +static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss1[] = { +/* MCS L80 S80 L40 S40 L20 S40*/ + {0, {293, 325}, {135, 150}, {65, 72} }, + {1, {585, 650}, {270, 300}, {130, 144} }, + {2, {878, 975}, {405, 450}, {195, 217} }, + {3, {1170, 1300}, {540, 600}, {260, 289} }, + {4, {1755, 1950}, {810, 900}, {390, 433} }, + {5, {2340, 2600}, {1080, 1200}, {520, 578} }, + {6, {2633, 2925}, {1215, 1350}, {585, 650} }, + {7, {2925, 3250}, {1350, 1500}, {650, 722} }, + {8, {3510, 3900}, {1620, 1800}, {780, 867} }, + {9, {3900, 4333}, {1800, 2000}, {780, 867} }, + {10, {4388, 4875}, {2025, 2250}, {975, 1083} }, + {11, {4875, 5417}, {2250, 2500}, {1083, 1203} } +}; + +/*MCS parameters with Nss = 2*/ +static const struct index_vht_data_rate_type supported_vht_mcs_rate_nss2[] = { +/* MCS L80 S80 L40 S40 L20 S40*/ + {0, {585, 650}, {270, 300}, {130, 144} }, + {1, {1170, 1300}, {540, 600}, {260, 289} }, + {2, {1755, 1950}, {810, 900}, {390, 433} }, + {3, {2340, 2600}, {1080, 1200}, {520, 578} }, + {4, {3510, 3900}, {1620, 1800}, {780, 867} }, + {5, {4680, 5200}, {2160, 2400}, {1040, 1156} }, + {6, {5265, 5850}, {2430, 2700}, {1170, 1300} }, + {7, {5850, 6500}, {2700, 3000}, {1300, 1444} }, + {8, {7020, 7800}, {3240, 3600}, {1560, 1733} }, + {9, {7800, 8667}, {3600, 4000}, {1730, 1920} }, + {10, {8775, 9750}, {4050, 4500}, {1950, 2167} }, + {11, {9750, 10833}, {4500, 5000}, {2167, 2407} } +}; + +/*array index points to MCS and array value points respective rssi*/ +static int rssi_mcs_tbl[][MAX_RSSI_MCS_INDEX] = { +/* MCS 0 1 2 3 4 5 6 7 8 9 10 11 12 13*/ + /* 20 */ + {-82, -79, -77, -74, -70, -66, -65, -64, -59, -57, -52, -48, -46, -42}, + /* 40 */ + {-79, -76, -74, -71, -67, -63, -62, -61, -56, -54, -49, -45, -43, -39}, + /* 80 */ + {-76, -73, -71, -68, -64, -60, -59, -58, -53, -51, -46, -42, -46, -36} +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map) +{ + if (he_mcs_12_13_map) + return true; + else + return false; +} +#else +static bool wlan_hdd_is_he_mcs_12_13_supported(uint16_t he_mcs_12_13_map) +{ + return false; +} +#endif + +static bool get_station_fw_request_needed = true; + +/* + * copy_station_stats_to_adapter() - Copy station stats to adapter + * @link_info: Pointer to link_info in adapter + * @stats: Pointer to the station stats event + * + * Return: 0 if success, non-zero for failure + */ +static int copy_station_stats_to_adapter(struct wlan_hdd_link_info *link_info, + struct stats_event *stats) +{ + int ret = 0; + struct wlan_mlme_nss_chains *dynamic_cfg; + uint32_t tx_nss, rx_nss; + struct wlan_objmgr_vdev *vdev; + uint16_t he_mcs_12_13_map; + bool is_he_mcs_12_13_supported; + struct hdd_stats *hdd_stats; + struct hdd_adapter *adapter = link_info->adapter; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) + return -EINVAL; + + hdd_stats = &link_info->hdd_stats; + /* save summary stats to legacy location */ + qdf_mem_copy(hdd_stats->summary_stat.retry_cnt, + stats->vdev_summary_stats[0].stats.retry_cnt, + sizeof(hdd_stats->summary_stat.retry_cnt)); + qdf_mem_copy(hdd_stats->summary_stat.multiple_retry_cnt, + stats->vdev_summary_stats[0].stats.multiple_retry_cnt, + sizeof(hdd_stats->summary_stat.multiple_retry_cnt)); + qdf_mem_copy(hdd_stats->summary_stat.tx_frm_cnt, + stats->vdev_summary_stats[0].stats.tx_frm_cnt, + sizeof(hdd_stats->summary_stat.tx_frm_cnt)); + qdf_mem_copy(hdd_stats->summary_stat.fail_cnt, + stats->vdev_summary_stats[0].stats.fail_cnt, + sizeof(hdd_stats->summary_stat.fail_cnt)); + hdd_stats->summary_stat.snr = stats->vdev_summary_stats[0].stats.snr; + hdd_stats->summary_stat.rssi = stats->vdev_summary_stats[0].stats.rssi; + hdd_stats->summary_stat.rx_frm_cnt = + stats->vdev_summary_stats[0].stats.rx_frm_cnt; + hdd_stats->summary_stat.frm_dup_cnt = + stats->vdev_summary_stats[0].stats.frm_dup_cnt; + hdd_stats->summary_stat.rts_fail_cnt = + stats->vdev_summary_stats[0].stats.rts_fail_cnt; + hdd_stats->summary_stat.ack_fail_cnt = + stats->vdev_summary_stats[0].stats.ack_fail_cnt; + hdd_stats->summary_stat.rts_succ_cnt = + stats->vdev_summary_stats[0].stats.rts_succ_cnt; + hdd_stats->summary_stat.rx_discard_cnt = + stats->vdev_summary_stats[0].stats.rx_discard_cnt; + hdd_stats->summary_stat.rx_error_cnt = + stats->vdev_summary_stats[0].stats.rx_error_cnt; + hdd_stats->peer_stats.rx_count = stats->peer_adv_stats->rx_count; + hdd_stats->peer_stats.rx_bytes = stats->peer_adv_stats->rx_bytes; + hdd_stats->peer_stats.fcs_count = stats->peer_adv_stats->fcs_count; + adapter->tx_power.tx_pwr = stats->pdev_stats->max_pwr; + adapter->tx_power.tx_pwr_cached_timestamp = + qdf_system_ticks_to_msecs(qdf_system_ticks()); + /* Copy vdev status info sent by FW */ + if (stats->vdev_extd_stats) + link_info->is_mlo_vdev_active = + stats->vdev_extd_stats[0].is_mlo_vdev_active; + + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + hdd_err("nss chain dynamic config NULL"); + ret = -EINVAL; + goto out; + } + + switch (hdd_conn_get_connected_band(link_info)) { + case BAND_2G: + tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ]; + rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ]; + break; + case BAND_5G: + tx_nss = dynamic_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ]; + rx_nss = dynamic_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ]; + break; + default: + tx_nss = wlan_vdev_mlme_get_nss(vdev); + rx_nss = wlan_vdev_mlme_get_nss(vdev); + } + + /* Intersection of self and AP's NSS capability */ + if (tx_nss > wlan_vdev_mlme_get_nss(vdev)) + tx_nss = wlan_vdev_mlme_get_nss(vdev); + + if (rx_nss > wlan_vdev_mlme_get_nss(vdev)) + rx_nss = wlan_vdev_mlme_get_nss(vdev); + + /* save class a stats to legacy location */ + hdd_stats->class_a_stat.tx_nss = tx_nss; + hdd_stats->class_a_stat.rx_nss = rx_nss; + hdd_stats->class_a_stat.tx_rate = stats->tx_rate; + hdd_stats->class_a_stat.rx_rate = stats->rx_rate; + hdd_stats->class_a_stat.tx_rx_rate_flags = stats->tx_rate_flags; + + he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev); + is_he_mcs_12_13_supported = + wlan_hdd_is_he_mcs_12_13_supported(he_mcs_12_13_map); + hdd_stats->class_a_stat.tx_mcs_index = + sme_get_mcs_idx(stats->tx_rate, stats->tx_rate_flags, + is_he_mcs_12_13_supported, + &hdd_stats->class_a_stat.tx_nss, + &hdd_stats->class_a_stat.tx_dcm, + &hdd_stats->class_a_stat.tx_gi, + &hdd_stats->class_a_stat.tx_mcs_rate_flags); + hdd_stats->class_a_stat.rx_mcs_index = + sme_get_mcs_idx(stats->rx_rate, stats->tx_rate_flags, + is_he_mcs_12_13_supported, + &hdd_stats->class_a_stat.rx_nss, + &hdd_stats->class_a_stat.rx_dcm, + &hdd_stats->class_a_stat.rx_gi, + &hdd_stats->class_a_stat.rx_mcs_rate_flags); + + /* save per chain rssi to legacy location */ + qdf_mem_copy(hdd_stats->per_chain_rssi_stats.rssi, + stats->vdev_chain_rssi[0].chain_rssi, + sizeof(stats->vdev_chain_rssi[0].chain_rssi)); + hdd_stats->bcn_protect_stats = stats->bcn_protect_stats; +out: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return ret; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/* + * copy_station_big_data_stats_to_adapter() - Copy big data stats to adapter + * @link_info: Link info pointer in HDD adapter. + * @stats: Pointer to the big data stats event + * + * Return: 0 if success, non-zero for failure + */ +static void +copy_station_big_data_stats_to_adapter(struct wlan_hdd_link_info *link_info, + struct big_data_stats_event *stats) +{ + struct big_data_stats_event *big_data_stats = + &link_info->big_data_stats; + + big_data_stats->vdev_id = stats->vdev_id; + big_data_stats->tsf_out_of_sync = stats->tsf_out_of_sync; + big_data_stats->ani_level = stats->ani_level; + big_data_stats->last_data_tx_pwr = stats->last_data_tx_pwr; + big_data_stats->target_power_dsss = stats->target_power_dsss; + big_data_stats->target_power_ofdm = stats->target_power_ofdm; + big_data_stats->last_tx_data_rix = stats->last_tx_data_rix; + big_data_stats->last_tx_data_rate_kbps = stats->last_tx_data_rate_kbps; +} +#endif + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +static void +hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter) +{ + adapter->sta_stats_cached_timestamp = + qdf_system_ticks_to_msecs(qdf_system_ticks()); +} +#else +static void +hdd_update_station_stats_cached_timestamp(struct hdd_adapter *adapter) +{ +} +#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */ + +#ifdef WLAN_FEATURE_WMI_SEND_RECV_QMI +/** + * wlan_hdd_qmi_get_sync_resume() - Get operation to trigger RTPM + * sync resume without WoW exit + * + * call qmi_get before sending qmi, and do qmi_put after all the + * qmi response rececived from fw. so this request wlan host to + * wait for the last qmi response, if it doesn't wait, qmi put + * which cause MHI enter M3(suspend) before all the qmi response, + * and MHI will trigger a RTPM resume, this violated design of by + * sending cmd by qmi without wow resume. + * + * Returns: 0 for success, non-zero for failure + */ +int wlan_hdd_qmi_get_sync_resume(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->config->is_qmi_stats_enabled) { + hdd_debug("periodic stats over qmi is disabled"); + return 0; + } + + if (!qdf_ctx) { + hdd_err("qdf_ctx is null"); + return -EINVAL; + } + + return pld_qmi_send_get(qdf_ctx->dev); +} + +/** + * wlan_hdd_qmi_put_suspend() - Put operation to trigger RTPM suspend + * without WoW entry + * + * Returns: 0 for success, non-zero for failure + */ +int wlan_hdd_qmi_put_suspend(void) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->config->is_qmi_stats_enabled) { + hdd_debug("periodic stats over qmi is disabled"); + return 0; + } + + if (!qdf_ctx) { + hdd_err("qdf_ctx is null"); + return -EINVAL; + } + + return pld_qmi_send_put(qdf_ctx->dev); +} +#else +int wlan_hdd_qmi_get_sync_resume(void) +{ + return 0; +} + +int wlan_hdd_qmi_put_suspend(void) +{ + return 0; +} +#endif /* end if of WLAN_FEATURE_WMI_SEND_RECV_QMI */ + +static struct wlan_hdd_link_info * +hdd_get_link_info_by_bssid(struct hdd_context *hdd_ctx, const uint8_t *bssid) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct hdd_station_ctx *sta_ctx; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_GET_ADAPTER_BY_BSSID; + struct wlan_hdd_link_info *link_info; + + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)bssid)) + return NULL; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (qdf_is_macaddr_equal((struct qdf_mac_addr *)bssid, + &sta_ctx->conn_info.bssid)) { + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, + dbgid); + return link_info; + } + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } + return NULL; +} + +#define WLAN_INVALID_RSSI_VALUE -128 +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * wlan_hdd_is_per_link_stats_supported - Check if FW supports per link stats + * @hdd_ctx: Pointer to hdd context + * + * Return: true if FW supports, else False + */ +static bool +wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx) +{ + if (hdd_ctx->is_mlo_per_link_stats_supported) + return true; + + hdd_debug("mlo per link stats is not supported by FW"); + return false; +} + +/** + * wlan_hdd_get_bss_peer_mld_mac() - get bss peer mld mac address + * @link_info: Link info pointer in HDD adapter + * @mld_mac: pointer to mld mac address + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *mld_mac) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_STATS_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return QDF_STATUS_E_INVAL; + } + + status = wlan_vdev_get_bss_peer_mld_mac(vdev, mld_mac); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return status; +} + +/** + * wlan_hdd_copy_sinfo_to_link_info() - Copy sinfo to link_info + * @link_info: Pointer to the hdd link info + * @sinfo: Pointer to kernel station info struct + * + * Return: none + */ +static void +wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ + struct wlan_hdd_station_stats_info *hdd_sinfo; + struct hdd_station_ctx *sta_ctx; + uint8_t i, *link_mac; + + if (!wlan_hdd_is_mlo_connection(link_info)) + return; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + hdd_sinfo = &link_info->hdd_sinfo; + + hdd_sinfo->signal = sinfo->signal; + hdd_sinfo->signal_avg = sinfo->signal_avg; + for (i = 0; i < IEEE80211_MAX_CHAINS; i++) + hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i]; + + qdf_mem_copy(&hdd_sinfo->txrate, + &sinfo->txrate, sizeof(sinfo->txrate)); + + qdf_mem_copy(&hdd_sinfo->rxrate, + &sinfo->rxrate, sizeof(sinfo->rxrate)); + hdd_sinfo->rx_bytes = sinfo->rx_bytes; + hdd_sinfo->tx_bytes = sinfo->tx_bytes; + hdd_sinfo->rx_packets = sinfo->rx_packets; + hdd_sinfo->tx_packets = sinfo->tx_packets; + hdd_sinfo->tx_retries = sinfo->tx_retries; + hdd_sinfo->tx_failed = sinfo->tx_failed; + hdd_sinfo->rx_mpdu_count = sinfo->rx_mpdu_count; + hdd_sinfo->fcs_err_count = sinfo->fcs_err_count; + + link_mac = sta_ctx->conn_info.bssid.bytes; + hdd_nofl_debug("copied sinfo for " QDF_MAC_ADDR_FMT " into link_info", + QDF_MAC_ADDR_REF(link_mac)); +} + +/** + * wlan_hdd_copy_hdd_stats_to_sinfo() - Copy hdd station stats info to sinfo + * @sinfo: Pointer to kernel station info struct + * @hdd_sinfo: Pointer to the hdd station stats info struct + * + * Return: none + */ +static void +wlan_hdd_copy_hdd_stats_to_sinfo(struct station_info *sinfo, + struct wlan_hdd_station_stats_info *hdd_sinfo) +{ + uint8_t i; + + sinfo->signal = hdd_sinfo->signal; + sinfo->signal_avg = hdd_sinfo->signal_avg; + for (i = 0; i < IEEE80211_MAX_CHAINS; i++) + sinfo->chain_signal_avg[i] = hdd_sinfo->chain_signal_avg[i]; + + if (!hdd_sinfo->signal) { + sinfo->signal = WLAN_INVALID_RSSI_VALUE; + sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM; + for (i = 0; i < IEEE80211_MAX_CHAINS; i++) + sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE; + } + + qdf_mem_copy(&sinfo->txrate, + &hdd_sinfo->txrate, sizeof(sinfo->txrate)); + + qdf_mem_copy(&sinfo->rxrate, + &hdd_sinfo->rxrate, sizeof(sinfo->rxrate)); + sinfo->rx_bytes = hdd_sinfo->rx_bytes; + sinfo->tx_bytes = hdd_sinfo->tx_bytes; + sinfo->rx_packets = hdd_sinfo->rx_packets; + sinfo->tx_packets = hdd_sinfo->tx_packets; + sinfo->tx_retries = hdd_sinfo->tx_retries; + sinfo->tx_failed = hdd_sinfo->tx_failed; + sinfo->rx_mpdu_count = hdd_sinfo->rx_mpdu_count; + sinfo->fcs_err_count = hdd_sinfo->fcs_err_count; +} + +/** + * wlan_hdd_update_sinfo() - Function to update station info structure + * @sinfo: kernel station_info to populate + * @link_info: Pointer to the hdd link info + * + * Return: None + */ +static void wlan_hdd_update_sinfo(struct station_info *sinfo, + struct wlan_hdd_link_info *link_info) +{ + uint8_t i; + + if (!link_info) { + hdd_err("Invalid link_info"); + return; + } + + wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &link_info->hdd_sinfo); + + if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) { + sinfo->signal = WLAN_INVALID_RSSI_VALUE; + sinfo->signal_avg = WLAN_INVALID_RSSI_VALUE; + for (i = 0; i < IEEE80211_MAX_CHAINS; i++) + sinfo->chain_signal_avg[i] = WLAN_INVALID_RSSI_VALUE; + } + + sinfo->filled |= HDD_INFO_SIGNAL | HDD_INFO_SIGNAL_AVG | + HDD_INFO_CHAIN_SIGNAL_AVG | HDD_INFO_TX_PACKETS | + HDD_INFO_TX_RETRIES | HDD_INFO_TX_FAILED | + HDD_INFO_TX_BITRATE | HDD_INFO_RX_BITRATE | + HDD_INFO_TX_BYTES | HDD_INFO_RX_BYTES | + HDD_INFO_RX_PACKETS | HDD_INFO_FCS_ERROR_COUNT | + HDD_INFO_RX_MPDUS; +} + +static void +wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx = NULL; + u32 num_links = 0; + + hdd_adapter_for_each_link_info(adapter, link_info) { + if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE || + link_info->adapter->device_mode == QDF_STA_MODE) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (sta_ctx->conn_info.ieee_link_id != + WLAN_INVALID_LINK_ID) { + num_links++; + } + } else if (link_info->adapter->device_mode == QDF_SAP_MODE || + link_info->adapter->device_mode == QDF_P2P_GO_MODE) { + if (test_bit(SOFTAP_BSS_STARTED, + &link_info->link_flags)) { + num_links++; + } + } + } + + *count = num_links; +} + +#else +static inline bool +wlan_hdd_is_per_link_stats_supported(struct hdd_context *hdd_ctx) +{ + return false; +} + +static inline QDF_STATUS +wlan_hdd_get_bss_peer_mld_mac(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *mld_mac) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline void +wlan_hdd_copy_sinfo_to_link_info(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ +} + +static inline void +wlan_hdd_update_sinfo(struct station_info *sinfo, + struct wlan_hdd_link_info *link_info) +{ +} + +static inline void +wlan_hdd_get_mlo_links_count(struct hdd_adapter *adapter, uint32_t *count) +{ +} +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * struct hdd_ll_stats - buffered hdd link layer stats + * @ll_stats_node: pointer to next stats buffered in scheduler thread context + * @result_param_id: Received link layer stats ID + * @result: received stats from FW + * @more_data: if more stats are pending + * @stats_nradio_npeer: union of counts + * @stats_nradio_npeer.no_of_radios: no of radios + * @stats_nradio_npeer.no_of_peers: no of peers + */ +struct hdd_ll_stats { + qdf_list_node_t ll_stats_node; + u32 result_param_id; + void *result; + u32 more_data; + union { + u32 no_of_radios; + u32 no_of_peers; + } stats_nradio_npeer; +}; + +/** + * struct hdd_ll_stats_priv - hdd link layer stats private + * @ll_stats_q: head to different link layer stats received in scheduler + * thread context + * @request_id: userspace-assigned link layer stats request id + * @request_bitmap: userspace-assigned link layer stats request bitmap + * @ll_stats_lock: Lock to serially access request_bitmap + * @vdev_id: id of vdev handle + * @is_mlo_req: is the request for mlo link layer stats + * @mlo_vdev_id_bitmap: bitmap of all ml vdevs + */ +struct hdd_ll_stats_priv { + qdf_list_t ll_stats_q; + uint32_t request_id; + uint32_t request_bitmap; + qdf_spinlock_t ll_stats_lock; + uint8_t vdev_id; + bool is_mlo_req; + uint32_t mlo_vdev_id_bitmap; +}; + +/* + * Used to allocate the size of 4096 for the link layer stats. + * The size of 4096 is considered assuming that all data per + * respective event fit with in the limit.Please take a call + * on the limit based on the data requirements on link layer + * statistics. + */ +#define LL_STATS_EVENT_BUF_SIZE 4096 + +/** + * put_wifi_rate_stat() - put wifi rate stats + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_rate_stat(struct wifi_rate_stat *stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_PREAMBLE, + stats->rate.preamble) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_NSS, + stats->rate.nss) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BW, + stats->rate.bw) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MCS_INDEX, + stats->rate.rate_or_mcs_index) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_BIT_RATE, + stats->rate.bitrate) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_TX_MPDU, + stats->tx_mpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RX_MPDU, + stats->rx_mpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_MPDU_LOST, + stats->mpdu_lost) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES, + stats->retries) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_SHORT, + stats->retries_short) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RATE_RETRIES_LONG, + stats->retries_long)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * put_wifi_peer_rates() - put wifi peer rate info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_peer_rates(struct wifi_peer_info *stats, + struct sk_buff *vendor_event) +{ + uint32_t i; + struct wifi_rate_stat *rate_stat; + int nest_id; + struct nlattr *info; + struct nlattr *rates; + + /* no rates is ok */ + if (!stats->num_rate) + return true; + + nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO; + info = nla_nest_start(vendor_event, nest_id); + if (!info) + return false; + + for (i = 0; i < stats->num_rate; i++) { + rates = nla_nest_start(vendor_event, i); + if (!rates) + return false; + rate_stat = &stats->rate_stats[i]; + if (!put_wifi_rate_stat(rate_stat, vendor_event)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + nla_nest_end(vendor_event, rates); + } + nla_nest_end(vendor_event, info); + + return true; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * wlan_hdd_put_mlo_link_iface_info() - Send per mlo link info to framework + * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct + * @skb: Pointer to data buffer + * + * Return: True on success, False on failure + */ +static bool +wlan_hdd_put_mlo_link_iface_info(struct wlan_hdd_mlo_iface_stats_info *info, + struct sk_buff *skb) +{ + if (nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID, + info->link_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, + info->radio_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ, + info->freq)) { + hdd_err("wlan_hdd_put_mlo_link_iface_info failed"); + return false; + } + + return true; +} + +/** + * wlan_hdd_get_connected_link_info() - Get connected links' id and frequency + * @link_info: Link info pointerin adapter + * @info: Pointer to wlan_hdd_mlo_iface_stats_info struct + * + * Return: void + */ +static void +wlan_hdd_get_connected_link_info(struct wlan_hdd_link_info *link_info, + struct wlan_hdd_mlo_iface_stats_info *info) +{ + struct hdd_station_ctx *sta_ctx = NULL; + struct hdd_ap_ctx *ap_ctx = NULL; + + info->link_id = WLAN_INVALID_LINK_ID; + + if (!link_info) { + hdd_err("Invalid link_info"); + return; + } + + if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE || + link_info->adapter->device_mode == QDF_STA_MODE) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + info->link_id = sta_ctx->conn_info.ieee_link_id; + info->freq = sta_ctx->conn_info.chan_freq; + } else if ((link_info->adapter->device_mode == QDF_SAP_MODE || + link_info->adapter->device_mode == QDF_P2P_GO_MODE) && + test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(link_info); + info->link_id = ap_ctx->sap_config.link_id; + info->freq = ap_ctx->sap_config.chan_freq; + } +} +#endif + +/** + * put_wifi_peer_info() - put wifi peer info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_peer_info(struct wifi_peer_info *stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE, + wmi_to_sir_peer_type(stats->type)) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS, + QDF_MAC_ADDR_SIZE, &stats->peer_macaddr.bytes[0]) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES, + stats->capabilities) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, + stats->num_rate)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return put_wifi_peer_rates(stats, vendor_event); +} + +/** + * put_wifi_wmm_ac_stat() - put wifi wmm ac stats + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * + * Return: bool + */ +static bool put_wifi_wmm_ac_stat(wmi_wmm_ac_stats *stats, + struct sk_buff *vendor_event) +{ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_AC, + stats->ac_type) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MPDU, + stats->tx_mpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MPDU, + stats->rx_mpdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_MCAST, + stats->tx_mcast) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_MCAST, + stats->rx_mcast) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RX_AMPDU, + stats->rx_ampdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_TX_AMPDU, + stats->tx_ampdu) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_MPDU_LOST, + stats->mpdu_lost) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES, + stats->retries) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_SHORT, + stats->retries_short) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_RETRIES_LONG, + stats->retries_long) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MIN, + stats->contention_time_min) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_MAX, + stats->contention_time_max) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_TIME_AVG, + stats->contention_time_avg) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_AC_CONTENTION_NUM_SAMPLES, + stats->contention_num_samples)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * put_wifi_interface_info() - put wifi interface info + * @stats: Pointer to stats context + * @vendor_event: Pointer to vendor event + * @link_info: Pointer to link_info + * + * Return: bool + */ +static bool put_wifi_interface_info(struct wifi_interface_info *stats, + struct sk_buff *vendor_event, + struct wlan_hdd_link_info *link_info) +{ + if (link_info->adapter->device_mode == QDF_P2P_CLIENT_MODE || + link_info->adapter->device_mode == QDF_STA_MODE) { + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_STATE, + stats->state)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MODE, + stats->mode) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_MAC_ADDR, + QDF_MAC_ADDR_SIZE, stats->macAddr.bytes) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_ROAMING, + stats->roaming) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_CAPABILITIES, + stats->capabilities) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_SSID, + strlen(stats->ssid), stats->ssid) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_BSSID, + QDF_MAC_ADDR_SIZE, stats->bssid.bytes) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_AP_COUNTRY_STR, + REG_ALPHA2_LEN + 1, stats->apCountryStr) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_COUNTRY_STR, + REG_ALPHA2_LEN + 1, stats->countryStr) || + nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_INFO_TS_DUTY_CYCLE, + stats->time_slice_duty_cycle)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + return true; +} + +/** + * put_wifi_iface_stats() - put wifi interface stats + * @if_stat: Pointer to interface stats context + * @num_peers: Number of peers + * @vendor_event: Pointer to vendor event + * @link_info: Pointer to link_info + * + * Return: bool + */ +static bool put_wifi_iface_stats(struct wifi_interface_stats *if_stat, + u32 num_peers, struct sk_buff *vendor_event, + struct wlan_hdd_link_info *link_info) +{ + int i = 0; + struct nlattr *wmm_info; + struct nlattr *wmm_stats; + u64 average_tsf_offset; + wmi_iface_link_stats *link_stats = &if_stat->link_stats; + + if (!put_wifi_interface_info(&if_stat->info, vendor_event, link_info)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + + } + + average_tsf_offset = link_stats->avg_bcn_spread_offset_high; + average_tsf_offset = (average_tsf_offset << 32) | + link_stats->avg_bcn_spread_offset_low; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_IFACE) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + num_peers) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_BEACON_RX, + link_stats->beacon_rx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_RX, + link_stats->mgmt_rx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_RX, + link_stats->mgmt_action_rx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_MGMT_ACTION_TX, + link_stats->mgmt_action_tx) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_MGMT, + link_stats->rssi_mgmt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_DATA, + link_stats->rssi_data) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RSSI_ACK, + link_stats->rssi_ack) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_DETECTED, + link_stats->is_leaky_ap) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_AVG_NUM_FRAMES_LEAKED, + link_stats->avg_rx_frms_leaked) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_LEAKY_AP_GUARD_TIME, + link_stats->rx_leak_window) || + nla_put_s32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NF_CAL_VAL, + link_stats->nf_cal_val) || + hdd_wlan_nla_put_u64(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_AVERAGE_TSF_OFFSET, + average_tsf_offset) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_SUCC_CNT, + if_stat->rts_succ_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_RTS_FAIL_CNT, + if_stat->rts_fail_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_SUCC_CNT, + if_stat->ppdu_succ_cnt) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_PPDU_FAIL_CNT, + if_stat->ppdu_fail_cnt)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + + wmm_info = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_WMM_INFO); + if (!wmm_info) + return false; + + for (i = 0; i < WIFI_AC_MAX; i++) { + wmm_stats = nla_nest_start(vendor_event, i); + if (!wmm_stats) + return false; + + if (!put_wifi_wmm_ac_stat(&if_stat->ac_stats[i], + vendor_event)) { + hdd_err("put_wifi_wmm_ac_stat Fail"); + return false; + } + + nla_nest_end(vendor_event, wmm_stats); + } + nla_nest_end(vendor_event, wmm_info); + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON, + if_stat->powersave_stats.tot_tim_bcn) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TIM_BEACON_ERR, + if_stat->powersave_stats.tot_err_tim_bcn)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put powersave_stat fail"); + return false; + } + + return true; +} + +/** + * hdd_map_device_to_ll_iface_mode() - map device to link layer interface mode + * @device_mode: Device mode + * + * Return: interface mode + */ +static tSirWifiInterfaceMode hdd_map_device_to_ll_iface_mode(int device_mode) +{ + switch (device_mode) { + case QDF_STA_MODE: + return WIFI_INTERFACE_STA; + case QDF_SAP_MODE: + return WIFI_INTERFACE_SOFTAP; + case QDF_P2P_CLIENT_MODE: + return WIFI_INTERFACE_P2P_CLIENT; + case QDF_P2P_GO_MODE: + return WIFI_INTERFACE_P2P_GO; + default: + /* Return Interface Mode as STA for all the unsupported modes */ + return WIFI_INTERFACE_STA; + } +} + +bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info, + struct wifi_interface_info *info) +{ + struct hdd_station_ctx *sta_ctx; + struct sap_config *config; + struct qdf_mac_addr *mac; + struct hdd_adapter *adapter = link_info->adapter; + + info->mode = hdd_map_device_to_ll_iface_mode(adapter->device_mode); + + mac = hdd_adapter_get_link_mac_addr(link_info); + if (!mac) { + hdd_debug("Invalid HDD link info"); + return false; + } + + qdf_copy_macaddr(&info->macAddr, mac); + + if (((QDF_STA_MODE == adapter->device_mode) || + (QDF_P2P_CLIENT_MODE == adapter->device_mode) || + (QDF_P2P_DEVICE_MODE == adapter->device_mode))) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (hdd_cm_is_disconnected(link_info)) + info->state = WIFI_DISCONNECTED; + + if (hdd_cm_is_connecting(link_info)) { + hdd_debug("Session ID %d, Connection is in progress", + link_info->vdev_id); + info->state = WIFI_ASSOCIATING; + } + if (hdd_cm_is_vdev_associated(link_info) && + !sta_ctx->conn_info.is_authenticated) { + hdd_err("client " QDF_MAC_ADDR_FMT + " is in the middle of WPS/EAPOL exchange.", + QDF_MAC_ADDR_REF(mac->bytes)); + info->state = WIFI_AUTHENTICATING; + } + if (hdd_cm_is_vdev_associated(link_info) || + link_info->vdev_id == WLAN_INVALID_VDEV_ID) { + info->state = WIFI_ASSOCIATED; + qdf_copy_macaddr(&info->bssid, + &sta_ctx->conn_info.bssid); + qdf_mem_copy(info->ssid, + sta_ctx->conn_info.ssid.SSID.ssId, + sta_ctx->conn_info.ssid.SSID.length); + /* + * NULL Terminate the string + */ + info->ssid[sta_ctx->conn_info.ssid.SSID.length] = 0; + } + } + + if ((adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) && + test_bit(SOFTAP_BSS_STARTED, &link_info->link_flags)) { + config = &link_info->session.ap.sap_config; + qdf_copy_macaddr(&info->bssid, &config->self_macaddr); + } + wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->countryStr); + wlan_reg_get_cc_and_src(adapter->hdd_ctx->psoc, info->apCountryStr); + + return true; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * hdd_cache_ll_iface_stats() - Caches ll_stats received from fw + * @hdd_ctx: Pointer to hdd_context + * @if_stat: Pointer to stats data + * + * After receiving Link Layer Interface statistics from FW. + * This function caches them into wlan_hdd_link_info. + * + * Return: None + */ +static void +hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx, + struct wifi_interface_stats *if_stat) +{ + struct wlan_hdd_link_info *link_info; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, if_stat->vdev_id); + if (!link_info) { + hdd_err("Invalid link_info. Unable to cache mlo iface stats"); + return; + } + /* + * There is no need for wlan_hdd_validate_context here. This is a NB + * operation that will come with DSC synchronization. This ensures that + * no driver transition will take place as long as this operation is + * not complete. Thus the need to check validity of hdd_context is not + * required. + */ + hdd_nofl_debug("Copying iface stats for vdev_id[%u] into link_info", + link_info->vdev_id); + link_info->ll_iface_stats = *if_stat; +} + +/** + * wlan_hdd_update_wmm_ac_stats() - Populate ll_iface ac stats + * @link_info: Link info pointer of STA adapter + * @if_stat: Pointer to wifi_interface_stats structure + * @update_contention_stats: whether to update contention stats or not + * + * Return: none + */ +static void +wlan_hdd_update_wmm_ac_stats(struct wlan_hdd_link_info *link_info, + struct wifi_interface_stats *if_stat, + bool update_contention_stats) +{ + int i; + wmi_wmm_ac_stats *hdd_ac_stats, *stats; + + for (i = 0; i < WIFI_AC_MAX; i++) { + hdd_ac_stats = &link_info->ll_iface_stats.ac_stats[i]; + stats = &if_stat->ac_stats[i]; + stats->ac_type = hdd_ac_stats->ac_type; + stats->tx_mpdu += hdd_ac_stats->tx_mpdu; + stats->rx_mpdu += hdd_ac_stats->rx_mpdu; + stats->tx_mcast += hdd_ac_stats->tx_mcast; + stats->rx_mcast += hdd_ac_stats->rx_mcast; + stats->rx_ampdu += hdd_ac_stats->rx_ampdu; + stats->tx_ampdu += hdd_ac_stats->tx_ampdu; + stats->mpdu_lost += hdd_ac_stats->mpdu_lost; + stats->retries += hdd_ac_stats->retries; + stats->retries_short += hdd_ac_stats->retries_short; + stats->retries_long += hdd_ac_stats->retries_long; + if (!update_contention_stats) + continue; + stats->contention_time_min = hdd_ac_stats->contention_time_min; + stats->contention_time_max = hdd_ac_stats->contention_time_max; + stats->contention_time_avg = hdd_ac_stats->contention_time_avg; + stats->contention_num_samples = + hdd_ac_stats->contention_num_samples; + } +} + +/** + * wlan_hdd_update_iface_stats_info() - Populate ll_iface stats info + * @link_info: Link info pointer of STA adapter + * @if_stat: Pointer to wifi_interface_stats structure + * @update_stats: whether to update iface stats + * + * Return: none + */ +static void +wlan_hdd_update_iface_stats_info(struct wlan_hdd_link_info *link_info, + struct wifi_interface_stats *if_stat, + bool update_stats) +{ + wmi_iface_link_stats *hdd_stats, *stats; + + hdd_stats = &link_info->ll_iface_stats.link_stats; + stats = &if_stat->link_stats; + + if (!update_stats) { + wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats); + return; + } + + stats->beacon_rx = hdd_stats->beacon_rx; + stats->mgmt_rx = hdd_stats->mgmt_rx; + stats->mgmt_action_rx = hdd_stats->mgmt_action_rx; + stats->mgmt_action_tx = hdd_stats->mgmt_action_tx; + stats->rssi_mgmt = hdd_stats->rssi_mgmt; + stats->rssi_data = hdd_stats->rssi_data; + stats->rssi_ack = hdd_stats->rssi_ack; + stats->avg_bcn_spread_offset_low = + hdd_stats->avg_bcn_spread_offset_low; + stats->avg_bcn_spread_offset_high = + hdd_stats->avg_bcn_spread_offset_high; + stats->is_leaky_ap = hdd_stats->is_leaky_ap; + stats->avg_rx_frms_leaked = hdd_stats->avg_rx_frms_leaked; + stats->rx_leak_window = hdd_stats->rx_leak_window; + stats->nf_cal_val = hdd_stats->nf_cal_val; + stats->num_peers = hdd_stats->num_peers; + stats->num_ac = hdd_stats->num_ac; + + if_stat->rts_succ_cnt = link_info->ll_iface_stats.rts_succ_cnt; + if_stat->rts_fail_cnt = link_info->ll_iface_stats.rts_fail_cnt; + if_stat->ppdu_succ_cnt = link_info->ll_iface_stats.ppdu_succ_cnt; + if_stat->ppdu_fail_cnt = link_info->ll_iface_stats.ppdu_fail_cnt; + + if_stat->powersave_stats.tot_tim_bcn = + link_info->ll_iface_stats.powersave_stats.tot_tim_bcn; + if_stat->powersave_stats.tot_err_tim_bcn = + link_info->ll_iface_stats.powersave_stats.tot_err_tim_bcn; + + wlan_hdd_update_wmm_ac_stats(link_info, if_stat, update_stats); +} + +/** + * wlan_hdd_copy_mlo_peer_stats() - copy mlo peer stats to link_info + * @adapter: Pointer to HDD adapter + * @peer_stat: Pointer to wifi_peer_stat + * + * Return: none + */ +static void +wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter, + struct wifi_peer_stat *peer_stat) +{ + uint8_t i, j, num_rate; + struct wifi_peer_info *peer_info = NULL; + struct wifi_rate_stat *rate_stat; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + if (!peer_stat) { + hdd_err("Invalid mlo peer stats"); + return; + } + + if (!peer_stat->num_peers) { + hdd_err("No mlo peers"); + return; + } + + /* Firmware doesn't send peer stats for stanby link, but we need to + * send peer stats for stanby link as well to userspace. So, in that + * case we fill partial values for stanby link and full stats received + * from firmware for active links and set the flag stats_cached in + * the link_info->mlo_peer_info structure. + */ + + peer_info = (struct wifi_peer_info *)peer_stat->peer_info; + + hdd_adapter_for_each_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + link_info->mlo_peer_info.link_id = + sta_ctx->conn_info.ieee_link_id; + + if (link_info->mlo_peer_info.stats_cached) + continue; + + /* since for stanby link we don't have valid values from + * firmware, we just fill peer mac and link id. + */ + qdf_mem_copy(&link_info->mlo_peer_info.peer_mac, + &sta_ctx->conn_info.bssid, QDF_MAC_ADDR_SIZE); + link_info->mlo_peer_info.type = peer_info->type; + link_info->mlo_peer_info.num_rate = HDD_MAX_PER_PEER_RATES; + for (j = 0; j < HDD_MAX_PER_PEER_RATES; j++) + qdf_mem_zero(&link_info->mlo_peer_info.rate_stats[j], + sizeof(struct wifi_rate_stat)); + hdd_debug("Default values for standby link " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes)); + } + + for (i = 1; i <= peer_stat->num_peers; i++) { + link_info = hdd_get_link_info_by_bssid(adapter->hdd_ctx, + peer_info->peer_macaddr.bytes); + if (!link_info) { + hdd_err("invalid link_info"); + continue; + } + + num_rate = peer_info->num_rate; + if (num_rate > HDD_MAX_PER_PEER_RATES) { + hdd_err("For peer " QDF_MAC_ADDR_FMT " got %u rate stats, expected %d", + QDF_MAC_ADDR_REF(peer_info->peer_macaddr.bytes), + num_rate, HDD_MAX_PER_PEER_RATES); + return; + } + + link_info->mlo_peer_info.type = peer_info->type; + qdf_mem_copy(&link_info->mlo_peer_info.peer_mac, + &peer_info->peer_macaddr, QDF_MAC_ADDR_SIZE); + link_info->mlo_peer_info.capabilities = peer_info->capabilities; + link_info->mlo_peer_info.num_rate = peer_info->num_rate; + link_info->mlo_peer_info.power_saving = peer_info->power_saving; + + for (j = 0; j < num_rate; j++) { + rate_stat = &peer_info->rate_stats[j]; + qdf_mem_copy(&link_info->mlo_peer_info.rate_stats[j], + rate_stat, sizeof(struct wifi_rate_stat)); + } + + /* peer stats for active link are cached in link_info + * so set the flag stats_cahed to true. + */ + link_info->mlo_peer_info.stats_cached = true; + + peer_info = (struct wifi_peer_info *) + ((uint8_t *)peer_stat->peer_info + + (i * sizeof(struct wifi_peer_info)) + + (num_rate * sizeof(struct wifi_rate_stat))); + } + hdd_debug_rl("Copied MLO Peer stats into link_info"); +} + +/** + * wlan_hdd_put_mlo_peer_info() - send mlo peer info to userspace + * @link_info: Link info pointer of STA adapter + * @skb: Pointer to vendor event + * + * Return: none + */ +static bool wlan_hdd_put_mlo_peer_info(struct wlan_hdd_link_info *link_info, + struct sk_buff *skb) +{ + struct wifi_rate_stat *rate_stat; + struct nlattr *rate_nest, *rates; + int rate_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_RATE_INFO; + uint8_t i; + + if (!link_info) { + hdd_err("Invalid link_info"); + return false; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_TYPE, + wmi_to_sir_peer_type(link_info->mlo_peer_info.type)) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_MAC_ADDRESS, + QDF_MAC_ADDR_SIZE, + &link_info->mlo_peer_info.peer_mac.bytes[0]) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_CAPABILITIES, + link_info->mlo_peer_info.capabilities) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO_NUM_RATES, + link_info->mlo_peer_info.num_rate) || + nla_put_u8(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK_ID, + link_info->mlo_peer_info.link_id)) { + hdd_err("put mlo peer info fail"); + return false; + } + + /* no rates is ok */ + if (!link_info->mlo_peer_info.num_rate) + return true; + + rate_nest = nla_nest_start(skb, rate_nest_id); + if (!rate_nest) + return false; + + for (i = 0; i < link_info->mlo_peer_info.num_rate; i++) { + rates = nla_nest_start(skb, i); + if (!rates) + return false; + rate_stat = &link_info->mlo_peer_info.rate_stats[i]; + if (!put_wifi_rate_stat(rate_stat, skb)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return false; + } + nla_nest_end(skb, rates); + } + nla_nest_end(skb, rate_nest); + + return true; +} + +/** + * wlan_hdd_send_mlo_ll_peer_stats_to_user() - send mlo ll peer stats to userspace + * @adapter: Pointer to HDD adapter + * + * Return: none + */ +static void +wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter) +{ + struct sk_buff *skb; + struct nlattr *peers, *peer_nest; + struct wlan_hdd_link_info *link_info; + struct wlan_hdd_mlo_iface_stats_info info = {0}; + int peer_nest_id = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO; + u32 num_peers; + uint8_t i = 0; + + wlan_hdd_get_mlo_links_count(adapter, &num_peers); + + hdd_debug_rl("WMI_MLO_LINK_STATS_PEER. Num Peers: %u", num_peers); + + if (!num_peers) { + hdd_err("No mlo peers"); + return; + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(adapter->hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + adapter->hdd_ctx->more_peer_data) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + num_peers)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + + goto exit; + } + + peer_nest = nla_nest_start(skb, peer_nest_id); + if (!peer_nest) { + hdd_err("nla_nest_start failed"); + goto exit; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + wlan_hdd_get_connected_link_info(link_info, &info); + if (info.link_id == WLAN_INVALID_LINK_ID) + continue; + + peers = nla_nest_start(skb, i); + if (!peers) { + hdd_err("nla_nest_start failed"); + goto exit; + } + + if (!wlan_hdd_put_mlo_peer_info(link_info, skb)) { + hdd_err("put_wifi_peer_info fail"); + goto exit; + } + nla_nest_end(skb, peers); + i++; + } + nla_nest_end(skb, peer_nest); + + wlan_cfg80211_vendor_cmd_reply(skb); + + hdd_debug_rl("Sent %u MLO Peer stats to User Space", i); + return; +exit: + wlan_cfg80211_vendor_free_skb(skb); +} + +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +/** + * wlan_hdd_get_iface_stats() - Get ll_iface stats info from link_info + * @link_info: Link info pointer of STA adapter + * @if_stat: Pointer to wifi_interface_stats structure + * + * Return: 0 on success, error on failure + */ +static int wlan_hdd_get_iface_stats(struct wlan_hdd_link_info *link_info, + struct wifi_interface_stats *if_stat) +{ + if (!link_info || !if_stat) { + hdd_err("Invalid link_info or interface stats"); + return -EINVAL; + } + + qdf_mem_copy(if_stat, &link_info->ll_iface_stats, + sizeof(link_info->ll_iface_stats)); + + if (!hdd_get_interface_info(link_info, &if_stat->info)) { + hdd_err("Unable to get iface info for vdev[%u]", + if_stat->vdev_id); + return -EINVAL; + } + + return 0; +} + +static bool +wlan_hdd_get_mlo_iface_info(struct hdd_context *hdd_ctx, + struct wifi_interface_stats *stats, + struct wlan_hdd_mlo_iface_stats_info *info) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + if (!stats) { + hdd_err("invalid wifi interface stats"); + return false; + } + + link_info = hdd_get_link_info_by_bssid(hdd_ctx, + (const uint8_t *)stats->info.bssid.bytes); + + if (!link_info) { + hdd_err("invalid link_info"); + return false; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + info->link_id = sta_ctx->conn_info.ieee_link_id; + info->freq = sta_ctx->conn_info.chan_freq; + + return true; +} + +/** + * wlan_hdd_send_mlo_ll_iface_stats_to_user() - send mlo ll stats to userspace + * @adapter: Pointer to adapter + * + * Return: none + */ +static void +wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter) +{ + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct hdd_adapter *link_adapter, *ml_adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + u32 num_links, per_link_peers; + uint8_t i, j = 0; + int8_t rssi; + struct wifi_interface_stats cumulative_if_stat = {0}; + struct wlan_hdd_mlo_iface_stats_info info = {0}; + struct wifi_interface_stats *link_if_stat; + bool update_stats = false; + QDF_STATUS status; + struct nlattr *ml_iface_nest, *ml_iface_links; + struct sk_buff *skb; + struct wlan_hdd_link_info *link_info; + struct qdf_mac_addr *netdev_addr; + + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_err("Invalid hdd context"); + return; + } + + ml_adapter = adapter; + if (hdd_adapter_is_link_adapter(adapter)) + ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter); + + link_info = ml_adapter->deflink; + rssi = link_info->rssi; + wlan_hdd_get_mlo_links_count(adapter, &num_links); + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + link_if_stat = qdf_mem_malloc(sizeof(*link_if_stat) * num_links); + if (!link_if_stat) { + hdd_err("failed to allocate memory for link iface stat"); + goto err; + } + + hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links); + + if (!hdd_get_interface_info(link_info, &cumulative_if_stat.info)) { + hdd_err("hdd_get_interface_info get fail for ml_adapter"); + goto err; + } + + wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat, + true); + + mlo_adapter_info = &ml_adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + + if (!link_adapter) + continue; + + link_info = link_adapter->deflink; + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug_rl("vdev_id[%u] is not associated\n", + link_info->vdev_id); + continue; + } + + if (hdd_adapter_is_associated_with_ml_adapter(link_adapter)) { + if (wlan_hdd_get_iface_stats(ml_adapter->deflink, + &link_if_stat[j])) + goto err; + j++; + if (j == num_links) + break; + continue; + } + + if (wlan_hdd_get_iface_stats(link_info, &link_if_stat[j])) + goto err; + j++; + if (j == num_links) + break; + + if (rssi <= link_info->rssi) { + rssi = link_info->rssi; + update_stats = true; + } + + wlan_hdd_update_iface_stats_info(link_info, + &cumulative_if_stat, + update_stats); + } + + netdev_addr = hdd_adapter_get_netdev_mac_addr(ml_adapter); + qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr); + + status = wlan_hdd_get_bss_peer_mld_mac(ml_adapter->deflink, + &cumulative_if_stat.info.bssid); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac"); + + if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb, + ml_adapter->deflink)) { + hdd_err("put_wifi_iface_stats fail"); + goto err; + } + + ml_iface_nest = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK); + if (!ml_iface_nest) { + hdd_err("Nesting mlo iface stats info failed"); + goto err; + } + + for (i = 0; i < num_links; i++) { + ml_iface_links = nla_nest_start(skb, i); + if (!ml_iface_links) { + hdd_err("per link mlo iface stats failed"); + goto err; + } + + per_link_peers = + link_info->ll_iface_stats.link_stats.num_peers; + + if (!wlan_hdd_get_mlo_iface_info(hdd_ctx, + &link_if_stat[i], &info)) + goto err; + + if (!wlan_hdd_put_mlo_link_iface_info(&info, skb)) + goto err; + + if (!put_wifi_iface_stats(&link_if_stat[i], + per_link_peers, skb, link_info)) { + hdd_err("put_wifi_iface_stats failed for link[%u]", i); + goto err; + } + + nla_nest_end(skb, ml_iface_links); + } + nla_nest_end(skb, ml_iface_nest); + + wlan_cfg80211_vendor_cmd_reply(skb); + qdf_mem_free(link_if_stat); + hdd_nofl_debug("Sent mlo interface stats to userspace"); + return; +err: + wlan_cfg80211_vendor_free_skb(skb); + qdf_mem_free(link_if_stat); +} +#else +static void +wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + u32 num_links, per_link_peers; + uint8_t i = 0; + int8_t rssi = WLAN_INVALID_RSSI_VALUE; + struct wifi_interface_stats cumulative_if_stat = {0}; + struct wlan_hdd_mlo_iface_stats_info info = {0}; + struct wifi_interface_stats *stats; + struct wifi_interface_info *iface_info; + bool update_stats; + QDF_STATUS status; + struct nlattr *ml_iface_nest, *ml_iface_links; + struct sk_buff *skb; + struct wlan_hdd_link_info *link_info; + struct qdf_mac_addr *netdev_addr; + int8_t rssi_data; + + if (!wlan_hdd_is_mlo_connection(adapter->deflink)) + return; + + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_err("Invalid hdd context"); + return; + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + wlan_hdd_get_mlo_links_count(adapter, &num_links); + + hdd_debug("WMI_MLO_LINK_STATS_IFACE Data. Num_links = %u", num_links); + + hdd_adapter_for_each_link_info(adapter, link_info) { + wlan_hdd_get_connected_link_info(link_info, &info); + + if (info.link_id == WLAN_INVALID_LINK_ID) + continue; + + rssi_data = link_info->ll_iface_stats.link_stats.rssi_data; + + if ((link_info->adapter->device_mode == QDF_P2P_GO_MODE || + link_info->adapter->device_mode == QDF_SAP_MODE) && + rssi <= rssi_data) { + rssi = rssi_data; + update_stats = true; + if (!hdd_get_interface_info(link_info, + &cumulative_if_stat.info)) { + hdd_err("failed to get iface info for link %u", + info.link_id); + goto err; + } + } else if (rssi_data != 0 && (rssi <= rssi_data)) { + rssi = rssi_data; + update_stats = true; + if (!hdd_get_interface_info(link_info, + &cumulative_if_stat.info)) { + hdd_err("failed to get iface info for link %u", + info.link_id); + goto err; + } + } else { + update_stats = false; + } + + iface_info = &link_info->ll_iface_stats.info; + if (!hdd_get_interface_info(link_info, iface_info)) { + hdd_err("get iface info failed for link %u", info.link_id); + goto err; + } + + wlan_hdd_update_iface_stats_info(link_info, &cumulative_if_stat, + update_stats); + } + + netdev_addr = hdd_adapter_get_netdev_mac_addr(adapter); + qdf_copy_macaddr(&cumulative_if_stat.info.macAddr, netdev_addr); + + status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink, + &cumulative_if_stat.info.bssid); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("mlo_iface_stats: failed to get bss peer_mld_mac"); + + if (!put_wifi_iface_stats(&cumulative_if_stat, num_links, skb, + adapter->deflink)) { + hdd_err("put_wifi_iface_stats fail"); + goto err; + } + + ml_iface_nest = + nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_MLO_LINK); + + if (!ml_iface_nest) { + hdd_err("Nesting mlo iface stats info failed"); + goto err; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + wlan_hdd_get_connected_link_info(link_info, &info); + + if (info.link_id == WLAN_INVALID_LINK_ID) + continue; + + ml_iface_links = nla_nest_start(skb, i); + if (!ml_iface_links) { + hdd_err("per link mlo iface stats failed"); + goto err; + } + + stats = &link_info->ll_iface_stats; + per_link_peers = stats->link_stats.num_peers; + + if (!wlan_hdd_put_mlo_link_iface_info(&info, skb)) + goto err; + + if (!put_wifi_iface_stats(stats, per_link_peers, skb, + link_info)) { + hdd_err("put iface stats failed for link[%u]", info.link_id); + goto err; + } + + nla_nest_end(skb, ml_iface_links); + i++; + } + nla_nest_end(skb, ml_iface_nest); + + wlan_cfg80211_vendor_cmd_reply(skb); + hdd_nofl_debug("Sent mlo interface stats to userspace"); + return; +err: + wlan_cfg80211_vendor_free_skb(skb); +} +#endif +#else +static void +hdd_cache_ll_iface_stats(struct hdd_context *hdd_ctx, + struct wifi_interface_stats *if_stat) +{ +} + +static inline void +wlan_hdd_send_mlo_ll_iface_stats_to_user(struct hdd_adapter *adapter) +{ +} + +static inline void +wlan_hdd_send_mlo_ll_peer_stats_to_user(struct hdd_adapter *adapter) +{ +} + +static inline bool +wlan_hdd_copy_mlo_peer_stats(struct hdd_adapter *adapter, + struct wifi_peer_stat *peer_stat) +{ + return true; +} +#endif + +/** + * hdd_link_layer_process_peer_stats() - This function is called after + * @adapter: Pointer to device adapter + * @more_data: More data + * @peer_stat: Pointer to stats data + * + * Receiving Link Layer Peer statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void hdd_link_layer_process_peer_stats(struct hdd_adapter *adapter, + u32 more_data, + struct wifi_peer_stat *peer_stat) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct wifi_peer_info *peer_info; + struct sk_buff *skb; + int i, nestid; + struct nlattr *peers; + int num_rate; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if ((adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) && + wlan_hdd_is_mlo_connection(adapter->deflink)) { + wlan_hdd_copy_mlo_peer_stats(adapter, peer_stat); + return; + } + + hdd_nofl_debug("LL_STATS_PEER_ALL : num_peers %u, more data = %u", + peer_stat->num_peers, more_data); + + /* + * Allocate a size of 4096 for the peer stats comprising + * each of size = sizeof (struct wifi_peer_info) + num_rate * + * sizeof (struct wifi_rate_stat).Each field is put with an + * NL attribute.The size of 4096 is considered assuming + * that number of rates shall not exceed beyond 50 with + * the sizeof (struct wifi_rate_stat) being 32. + */ + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_PEERS) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + more_data) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_IFACE_NUM_PEERS, + peer_stat->num_peers)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + peer_info = (struct wifi_peer_info *) ((uint8_t *) + peer_stat->peer_info); + + if (peer_stat->num_peers) { + struct nlattr *peer_nest; + + nestid = QCA_WLAN_VENDOR_ATTR_LL_STATS_PEER_INFO; + peer_nest = nla_nest_start(skb, nestid); + if (!peer_nest) { + hdd_err("nla_nest_start failed"); + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + for (i = 1; i <= peer_stat->num_peers; i++) { + peers = nla_nest_start(skb, i); + if (!peers) { + hdd_err("nla_nest_start failed"); + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + num_rate = peer_info->num_rate; + + if (!put_wifi_peer_info(peer_info, skb)) { + hdd_err("put_wifi_peer_info fail"); + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + peer_info = (struct wifi_peer_info *) + ((uint8_t *)peer_stat->peer_info + + (i * sizeof(struct wifi_peer_info)) + + (num_rate * sizeof(struct wifi_rate_stat))); + nla_nest_end(skb, peers); + } + nla_nest_end(skb, peer_nest); + } + + wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * hdd_link_layer_process_iface_stats() - This function is called after + * @link_info: Link info pointer in HDD adapter + * @if_stat: Pointer to stats data + * @num_peers: Number of peers + * + * Receiving Link Layer Interface statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void +hdd_link_layer_process_iface_stats(struct wlan_hdd_link_info *link_info, + struct wifi_interface_stats *if_stat, + u32 num_peers) +{ + struct sk_buff *skb; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + if (wlan_hdd_is_mlo_connection(link_info)) { + hdd_cache_ll_iface_stats(hdd_ctx, if_stat); + return; + } + + /* + * There is no need for wlan_hdd_validate_context here. This is a NB + * operation that will come with DSC synchronization. This ensures that + * no driver transition will take place as long as this operation is + * not complete. Thus the need to check validity of hdd_context is not + * required. + */ + + /* + * Allocate a size of 4096 for the interface stats comprising + * sizeof (struct wifi_interface_stats *).The size of 4096 is considered + * assuming that all these fit with in the limit.Please take + * a call on the limit based on the data requirements on + * interface statistics. + */ + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return; + } + + hdd_debug("WMI_LINK_STATS_IFACE Data"); + + if (!hdd_get_interface_info(link_info, &if_stat->info)) { + hdd_err("hdd_get_interface_info get fail"); + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + if (!put_wifi_iface_stats(if_stat, num_peers, skb, link_info)) { + hdd_err("put_wifi_iface_stats fail"); + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * put_channel_stats_chload - put chload of channel stats + * @vendor_event: vendor event + * @channel_stats: Pointer to channel stats + * + * Return: bool + */ +static bool put_channel_stats_chload(struct sk_buff *vendor_event, + struct wifi_channel_stats *channel_stats) +{ + uint64_t txrx_time; + uint32_t chload; + + if (!channel_stats->on_time) + return true; + + txrx_time = (channel_stats->tx_time + channel_stats->rx_time) * 100; + chload = qdf_do_div(txrx_time, channel_stats->on_time); + + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_LOAD_PERCENTAGE, + chload)) + return false; + + return true; +} + +/** + * hdd_llstats_radio_fill_channels() - radio stats fill channels + * @adapter: Pointer to device adapter + * @radiostat: Pointer to stats data + * @vendor_event: vendor event + * + * Return: 0 on success; errno on failure + */ +static int hdd_llstats_radio_fill_channels(struct hdd_adapter *adapter, + struct wifi_radio_stats *radiostat, + struct sk_buff *vendor_event) +{ + struct wifi_channel_stats *channel_stats; + struct nlattr *chlist; + struct nlattr *chinfo; + int i; + + chlist = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CH_INFO); + if (!chlist) { + hdd_err("nla_nest_start failed, %u", radiostat->num_channels); + return -EINVAL; + } + + for (i = 0; i < radiostat->num_channels; i++) { + channel_stats = (struct wifi_channel_stats *) ((uint8_t *) + radiostat->channels + + (i * sizeof(struct wifi_channel_stats))); + + chinfo = nla_nest_start(vendor_event, i); + if (!chinfo) { + hdd_err("nla_nest_start failed, chan number %u", + radiostat->num_channels); + return -EINVAL; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_WIDTH, + channel_stats->channel.width) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ, + channel_stats->channel.center_freq) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ0, + channel_stats->channel.center_freq0) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_INFO_CENTER_FREQ1, + channel_stats->channel.center_freq1) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_ON_TIME, + channel_stats->on_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_CCA_BUSY_TIME, + channel_stats->cca_busy_time)) { + hdd_err("nla_put failed for channel info (%u, %d, %u)", + radiostat->num_channels, i, + channel_stats->channel.center_freq); + return -EINVAL; + } + + if (adapter->hdd_ctx && + adapter->hdd_ctx->ll_stats_per_chan_rx_tx_time) { + if (nla_put_u32( + vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_TX_TIME, + channel_stats->tx_time) || + nla_put_u32( + vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CHANNEL_RX_TIME, + channel_stats->rx_time)) { + hdd_err("nla_put failed for tx time (%u, %d)", + radiostat->num_channels, i); + return -EINVAL; + } + + if (!put_channel_stats_chload(vendor_event, + channel_stats)) { + hdd_err("nla_put failed for chload (%u, %d)", + radiostat->num_channels, i); + return -EINVAL; + } + } + + nla_nest_end(vendor_event, chinfo); + } + nla_nest_end(vendor_event, chlist); + + return 0; +} + +/** + * hdd_llstats_free_radio_stats() - free wifi_radio_stats member pointers + * @radiostat: Pointer to stats data + * + * Return: void + */ +static void hdd_llstats_free_radio_stats(struct wifi_radio_stats *radiostat) +{ + if (radiostat->total_num_tx_power_levels && + radiostat->tx_time_per_power_level) { + qdf_mem_free(radiostat->tx_time_per_power_level); + radiostat->tx_time_per_power_level = NULL; + } + if (radiostat->num_channels && radiostat->channels) { + qdf_mem_free(radiostat->channels); + radiostat->channels = NULL; + } +} + +/** + * hdd_llstats_post_radio_stats() - post radio stats + * @adapter: Pointer to device adapter + * @more_data: More data + * @radiostat: Pointer to stats data + * @num_radio: Number of radios + * + * Return: void + */ +static void hdd_llstats_post_radio_stats(struct hdd_adapter *adapter, + u32 more_data, + struct wifi_radio_stats *radiostat, + u32 num_radio) +{ + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + /* + * Allocate a size of 4096 for the Radio stats comprising + * sizeof (struct wifi_radio_stats) + num_channels * sizeof + * (struct wifi_channel_stats).Each channel data is put with an + * NL attribute.The size of 4096 is considered assuming that + * number of channels shall not exceed beyond 60 with the + * sizeof (struct wifi_channel_stats) being 24 bytes. + */ + + vendor_event = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + hdd_ctx->wiphy, + LL_STATS_EVENT_BUF_SIZE); + + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + hdd_llstats_free_radio_stats(radiostat); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_TYPE, + QCA_NL80211_VENDOR_SUBCMD_LL_STATS_TYPE_RADIO) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RESULTS_MORE_DATA, + more_data) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_NUM_RADIOS, + num_radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ID, + radiostat->radio) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME, + radiostat->on_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME, + radiostat->tx_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_RX_TIME, + radiostat->rx_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_SCAN, + radiostat->on_time_scan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_NBD, + radiostat->on_time_nbd) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_GSCAN, + radiostat->on_time_gscan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_ROAM_SCAN, + radiostat->on_time_roam_scan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_PNO_SCAN, + radiostat->on_time_pno_scan) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_ON_TIME_HS20, + radiostat->on_time_hs20) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_TX_LEVELS, + radiostat->total_num_tx_power_levels) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_NUM_CHANNELS, + radiostat->num_channels)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + hdd_llstats_free_radio_stats(radiostat); + + goto failure; + } + + if (radiostat->total_num_tx_power_levels) { + ret = + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_RADIO_TX_TIME_PER_LEVEL, + sizeof(u32) * + radiostat->total_num_tx_power_levels, + radiostat->tx_time_per_power_level); + if (ret) { + hdd_err("nla_put fail"); + goto failure; + } + } + + if (radiostat->num_channels) { + ret = hdd_llstats_radio_fill_channels(adapter, radiostat, + vendor_event); + if (ret) + goto failure; + } + + wlan_cfg80211_vendor_cmd_reply(vendor_event); + hdd_llstats_free_radio_stats(radiostat); + return; + +failure: + wlan_cfg80211_vendor_free_skb(vendor_event); + hdd_llstats_free_radio_stats(radiostat); +} + +/** + * hdd_link_layer_process_radio_stats() - This function is called after + * @adapter: Pointer to device adapter + * @more_data: More data + * @radio_stat: Pointer to stats data + * @num_radio: Number of radios + * + * Receiving Link Layer Radio statistics from FW.This function converts + * the firmware data to the NL data and sends the same to the kernel/upper + * layers. + * + * Return: None + */ +static void +hdd_link_layer_process_radio_stats(struct hdd_adapter *adapter, + u32 more_data, + struct wifi_radio_stats *radio_stat, + u32 num_radio) +{ + int i, nr; + struct wifi_radio_stats *radio_stat_save = radio_stat; + + /* + * There is no need for wlan_hdd_validate_context here. This is a NB + * operation that will come with DSC synchronization. This ensures that + * no driver transition will take place as long as this operation is + * not complete. Thus the need to check validity of hdd_context is not + * required. + */ + + for (i = 0; i < num_radio; i++) { + hdd_nofl_debug("LL_STATS_RADIO" + " radio: %u on_time: %u tx_time: %u rx_time: %u" + " on_time_scan: %u on_time_nbd: %u" + " on_time_gscan: %u on_time_roam_scan: %u" + " on_time_pno_scan: %u on_time_hs20: %u" + " num_channels: %u total_num_tx_pwr_levels: %u" + " on_time_host_scan: %u, on_time_lpi_scan: %u", + radio_stat->radio, radio_stat->on_time, + radio_stat->tx_time, radio_stat->rx_time, + radio_stat->on_time_scan, radio_stat->on_time_nbd, + radio_stat->on_time_gscan, + radio_stat->on_time_roam_scan, + radio_stat->on_time_pno_scan, + radio_stat->on_time_hs20, + radio_stat->num_channels, + radio_stat->total_num_tx_power_levels, + radio_stat->on_time_host_scan, + radio_stat->on_time_lpi_scan); + radio_stat++; + } + + radio_stat = radio_stat_save; + for (nr = 0; nr < num_radio; nr++) { + hdd_llstats_post_radio_stats(adapter, more_data, + radio_stat, num_radio); + radio_stat++; + } + + hdd_exit(); +} + +static void hdd_process_ll_stats(tSirLLStatsResults *results, + struct osif_request *request) +{ + struct hdd_ll_stats_priv *priv = osif_request_priv(request); + struct hdd_ll_stats *stats = NULL; + size_t stat_size = 0; + + qdf_spin_lock(&priv->ll_stats_lock); + + if (!(priv->request_bitmap & results->paramId)) { + qdf_spin_unlock(&priv->ll_stats_lock); + return; + } + + if (results->paramId & WMI_LINK_STATS_RADIO) { + struct wifi_radio_stats *rs_results, *stat_result; + u64 channel_size = 0, pwr_lvl_size = 0; + int i; + + if (!results->num_radio) + goto exit; + + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + goto exit; + + stat_size = sizeof(struct wifi_radio_stats) * + results->num_radio; + stats->result_param_id = WMI_LINK_STATS_RADIO; + stat_result = qdf_mem_malloc(stat_size); + if (!stat_result) { + qdf_mem_free(stats); + goto exit; + } + stats->result = stat_result; + rs_results = (struct wifi_radio_stats *)results->results; + qdf_mem_copy(stats->result, results->results, stat_size); + for (i = 0; i < results->num_radio; i++) { + channel_size = rs_results->num_channels * + sizeof(struct wifi_channel_stats); + pwr_lvl_size = sizeof(uint32_t) * + rs_results->total_num_tx_power_levels; + + if (rs_results->total_num_tx_power_levels && + rs_results->tx_time_per_power_level) { + stat_result->tx_time_per_power_level = + qdf_mem_malloc(pwr_lvl_size); + if (!stat_result->tx_time_per_power_level) { + while (i-- > 0) { + stat_result--; + qdf_mem_free(stat_result-> + tx_time_per_power_level); + qdf_mem_free(stat_result-> + channels); + } + qdf_mem_free(stat_result); + qdf_mem_free(stats); + goto exit; + } + qdf_mem_copy(stat_result->tx_time_per_power_level, + rs_results->tx_time_per_power_level, + pwr_lvl_size); + } + if (channel_size) { + stat_result->channels = + qdf_mem_malloc(channel_size); + if (!stat_result->channels) { + qdf_mem_free(stat_result-> + tx_time_per_power_level); + while (i-- > 0) { + stat_result--; + qdf_mem_free(stat_result-> + tx_time_per_power_level); + qdf_mem_free(stat_result-> + channels); + } + qdf_mem_free(stats->result); + qdf_mem_free(stats); + goto exit; + } + qdf_mem_copy(stat_result->channels, + rs_results->channels, + channel_size); + } + rs_results++; + stat_result++; + } + stats->stats_nradio_npeer.no_of_radios = results->num_radio; + stats->more_data = results->moreResultToFollow; + if (!results->moreResultToFollow) + priv->request_bitmap &= ~stats->result_param_id; + } else if (results->paramId & WMI_LINK_STATS_IFACE) { + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + goto exit; + + stats->result_param_id = WMI_LINK_STATS_IFACE; + stats->stats_nradio_npeer.no_of_peers = results->num_peers; + stats->result = qdf_mem_malloc(sizeof(struct + wifi_interface_stats)); + if (!stats->result) { + qdf_mem_free(stats); + goto exit; + } + qdf_mem_copy(stats->result, results->results, + sizeof(struct wifi_interface_stats)); + + /* Firmware doesn't send peerstats event if no peers are + * connected. HDD should not wait for any peerstats in + * this case and return the status to middleware after + * receiving iface stats + */ + if (!results->num_peers) + priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + priv->request_bitmap &= ~stats->result_param_id; + + /* Firmware sends interface stats based on vdev_id_bitmap + * So, clear the mlo_vdev_id_bitmap in the host accordingly + */ + if (priv->is_mlo_req) + priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId); + } else if (results->paramId & WMI_LINK_STATS_ALL_PEER) { + struct wifi_peer_stat *peer_stat = (struct wifi_peer_stat *) + results->results; + struct wifi_peer_info *peer_info = NULL; + u64 num_rate = 0, peers, rates; + int i; + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + goto exit; + + peer_info = (struct wifi_peer_info *)peer_stat->peer_info; + for (i = 1; i <= peer_stat->num_peers; i++) { + num_rate += peer_info->num_rate; + peer_info = (struct wifi_peer_info *)((uint8_t *) + peer_info + sizeof(struct wifi_peer_info) + + (peer_info->num_rate * + sizeof(struct wifi_rate_stat))); + } + + peers = sizeof(struct wifi_peer_info) * peer_stat->num_peers; + rates = sizeof(struct wifi_rate_stat) * num_rate; + stat_size = sizeof(struct wifi_peer_stat) + peers + rates; + stats->result_param_id = WMI_LINK_STATS_ALL_PEER; + + stats->result = qdf_mem_malloc(stat_size); + if (!stats->result) { + qdf_mem_free(stats); + goto exit; + } + + qdf_mem_copy(stats->result, results->results, stat_size); + stats->more_data = results->moreResultToFollow; + if (!results->moreResultToFollow) + priv->request_bitmap &= ~stats->result_param_id; + } else { + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + } + /* send indication to caller thread */ + if (stats) + qdf_list_insert_back(&priv->ll_stats_q, &stats->ll_stats_node); + + if (!priv->request_bitmap) { + if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap) + goto out; +exit: + qdf_spin_unlock(&priv->ll_stats_lock); + + /* Thread which invokes this function has allocated memory in + * WMA for radio stats, that memory should be freed from the + * same thread to avoid any race conditions between two threads + */ + sme_radio_tx_mem_free(); + osif_request_complete(request); + return; + } +out: + qdf_spin_unlock(&priv->ll_stats_lock); +} + +static void hdd_debugfs_process_ll_stats(struct wlan_hdd_link_info *link_info, + tSirLLStatsResults *results, + struct osif_request *request) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_ll_stats_priv *priv = osif_request_priv(request); + + if (results->paramId & WMI_LINK_STATS_RADIO) { + hdd_debugfs_process_radio_stats(adapter, + results->moreResultToFollow, + results->results, + results->num_radio); + if (!results->moreResultToFollow) + priv->request_bitmap &= ~(WMI_LINK_STATS_RADIO); + } else if (results->paramId & WMI_LINK_STATS_IFACE) { + hdd_debugfs_process_iface_stats(link_info, results->results, + results->num_peers); + + /* Firmware doesn't send peerstats event if no peers are + * connected. HDD should not wait for any peerstats in + * this case and return the status to middleware after + * receiving iface stats + */ + + if (!results->num_peers) + priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + + priv->request_bitmap &= ~(WMI_LINK_STATS_IFACE); + + /* Firmware sends interface stats based on vdev_id_bitmap + * So, clear the mlo_vdev_id_bitmap in the host accordingly + */ + if (priv->is_mlo_req) + priv->mlo_vdev_id_bitmap &= ~(1 << results->ifaceId); + } else if (results->paramId & WMI_LINK_STATS_ALL_PEER) { + hdd_debugfs_process_peer_stats(adapter, results->results); + if (!results->moreResultToFollow) + priv->request_bitmap &= ~(WMI_LINK_STATS_ALL_PEER); + } else { + hdd_err("INVALID LL_STATS_NOTIFY RESPONSE"); + } + + if (!priv->request_bitmap) { + if (priv->is_mlo_req && priv->mlo_vdev_id_bitmap) + return; + /* Thread which invokes this function has allocated memory in + * WMA for radio stats, that memory should be freed from the + * same thread to avoid any race conditions between two threads + */ + sme_radio_tx_mem_free(); + osif_request_complete(request); + } + +} + +static void +wlan_hdd_update_ll_stats_request_bitmap(struct hdd_context *hdd_ctx, + struct osif_request *request, + tSirLLStatsResults *results) +{ + struct hdd_ll_stats_priv *priv = osif_request_priv(request); + bool is_mlo_link; + + if (!wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc, priv->vdev_id)) { + hdd_nofl_debug("Can't update req_bitmap for non MLO case"); + return; + } + + is_mlo_link = wlan_vdev_mlme_get_is_mlo_link(hdd_ctx->psoc, + results->ifaceId); + /* In case of MLO Connection, set the request_bitmap */ + if (is_mlo_link && results->paramId == WMI_LINK_STATS_IFACE) { + /* Set the request_bitmap for MLO link vdev iface stats */ + if (!(priv->request_bitmap & results->paramId)) + priv->request_bitmap |= results->paramId; + + hdd_nofl_debug("MLO_LL_STATS set request_bitmap = 0x%x", + priv->request_bitmap); + } +} + +void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle, + int indication_type, + tSirLLStatsResults *results, + void *cookie) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct hdd_ll_stats_priv *priv; + struct wlan_hdd_link_info *link_info; + int status; + struct osif_request *request; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + switch (indication_type) { + case SIR_HAL_LL_STATS_RESULTS_RSP: + { + hdd_nofl_debug("LL_STATS RESP paramID = 0x%x, ifaceId = %u, respId= %u , moreResultToFollow = %u, num radio = %u result = %pK", + results->paramId, results->ifaceId, + results->rspId, results->moreResultToFollow, + results->num_radio, results->results); + + request = osif_request_get(cookie); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + /* validate response received from target */ + if (priv->request_id != results->rspId) { + hdd_err("Request id %d response id %d request bitmap 0x%x response bitmap 0x%x", + priv->request_id, results->rspId, + priv->request_bitmap, results->paramId); + osif_request_put(request); + return; + } + + link_info = + hdd_get_link_info_by_vdev(hdd_ctx, results->ifaceId); + if (!link_info) { + hdd_debug_rl("invalid vdev_id %d sent by FW", + results->ifaceId); + /* for peer stats FW doesn't update the vdev_id info*/ + link_info = hdd_get_link_info_by_vdev(hdd_ctx, + priv->vdev_id); + if (!link_info) { + hdd_err("invalid vdev %d", priv->vdev_id); + osif_request_put(request); + return; + } + } + wlan_hdd_update_ll_stats_request_bitmap(hdd_ctx, request, + results); + if (results->rspId == DEBUGFS_LLSTATS_REQID) { + hdd_debugfs_process_ll_stats(link_info, + results, request); + } else { + hdd_process_ll_stats(results, request); + } + + osif_request_put(request); + break; + } + default: + hdd_warn("invalid event type %d", indication_type); + break; + } +} + +void hdd_lost_link_info_cb(hdd_handle_t hdd_handle, + struct sir_lost_link_info *lost_link_info) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + int status; + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *sta_ctx; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + if (!lost_link_info) { + hdd_err("lost_link_info is NULL"); + return; + } + + if (lost_link_info->rssi == 0) { + hdd_debug_rl("Invalid rssi on disconnect sent by FW"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, lost_link_info->vdev_id); + if (!link_info) { + hdd_err("invalid vdev"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + link_info->rssi_on_disconnect = lost_link_info->rssi; + hdd_debug("rssi on disconnect %d", link_info->rssi_on_disconnect); + + sta_ctx->cache_conn_info.signal = lost_link_info->rssi; +} + +const struct nla_policy qca_wlan_vendor_ll_set_policy[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD] + = { .type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING] + = { .type = NLA_U32 }, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_set() - set link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int status; + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1]; + tSirLLStatsSetReq req; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return -EINVAL; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_SAP_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE && + adapter->device_mode != QDF_P2P_GO_MODE) { + hdd_debug("Cannot set LL_STATS for device mode %d", + adapter->device_mode); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb_vendor, + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX, + (struct nlattr *)data, data_len, + qca_wlan_vendor_ll_set_policy)) { + hdd_err("maximum attribute not present"); + return -EINVAL; + } + + if (!tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]) { + hdd_err("MPDU size Not present"); + return -EINVAL; + } + + if (!tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]) { + hdd_err("Stats Gathering Not Present"); + return -EINVAL; + } + + /* Shall take the request Id if the Upper layers pass. 1 For now. */ + req.reqId = 1; + + req.mpduSizeThreshold = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_MPDU_SIZE_THRESHOLD]); + + req.aggressiveStatisticsGathering = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_CONFIG_AGGRESSIVE_STATS_GATHERING]); + + req.staId = adapter->deflink->vdev_id; + + hdd_debug("LL_STATS_SET reqId = %d, staId = %d, mpduSizeThreshold = %d, Statistics Gathering = %d", + req.reqId, req.staId, + req.mpduSizeThreshold, + req.aggressiveStatisticsGathering); + + if (QDF_STATUS_SUCCESS != sme_ll_stats_set_req(hdd_ctx->mac_handle, + &req)) { + hdd_err("sme_ll_stats_set_req Failed"); + return -EINVAL; + } + + adapter->is_link_layer_stats_set = true; + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_set() - set ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ll_stats_set(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +const struct nla_policy qca_wlan_vendor_ll_get_policy[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1] = { + /* Unsigned 32bit value provided by the caller issuing the GET stats + * command. When reporting + * the stats results, the driver uses the same value to indicate + * which GET request the results + * correspond to. + */ + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID] = {.type = NLA_U32}, + + /* Unsigned 32bit value . bit mask to identify what statistics are + * requested for retrieval + */ + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK] = {.type = NLA_U32} +}; + +static void wlan_hdd_handle_ll_stats(struct wlan_hdd_link_info *link_info, + struct hdd_ll_stats *stats, int ret) +{ + struct hdd_adapter *adapter = link_info->adapter; + + switch (stats->result_param_id) { + case WMI_LINK_STATS_RADIO: + { + struct wifi_radio_stats *radio_stat = stats->result; + int i, num_radio = stats->stats_nradio_npeer.no_of_radios; + + if (ret == -ETIMEDOUT) { + for (i = 0; i < num_radio; i++) { + if (radio_stat->num_channels) + qdf_mem_free(radio_stat->channels); + if (radio_stat->total_num_tx_power_levels) + qdf_mem_free(radio_stat-> + tx_time_per_power_level); + radio_stat++; + } + return; + } + hdd_link_layer_process_radio_stats(adapter, stats->more_data, + radio_stat, num_radio); + } + break; + case WMI_LINK_STATS_IFACE: + hdd_link_layer_process_iface_stats(link_info, + stats->result, + stats->stats_nradio_npeer. + no_of_peers); + break; + case WMI_LINK_STATS_ALL_PEER: + hdd_link_layer_process_peer_stats(adapter, + stats->more_data, + stats->result); + break; + default: + hdd_err("not requested event"); + } +} + +static void wlan_hdd_dealloc_ll_stats(void *priv) +{ + struct hdd_ll_stats_priv *ll_stats_priv = priv; + struct hdd_ll_stats *stats = NULL; + QDF_STATUS status; + qdf_list_node_t *ll_node; + + if (!ll_stats_priv) + return; + + qdf_spin_lock(&ll_stats_priv->ll_stats_lock); + status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q, &ll_node); + qdf_spin_unlock(&ll_stats_priv->ll_stats_lock); + while (QDF_IS_STATUS_SUCCESS(status)) { + stats = qdf_container_of(ll_node, struct hdd_ll_stats, + ll_stats_node); + + if (stats->result_param_id == WMI_LINK_STATS_RADIO) { + struct wifi_radio_stats *radio_stat = stats->result; + int i; + int num_radio = stats->stats_nradio_npeer.no_of_radios; + + for (i = 0; i < num_radio; i++) { + if (radio_stat->num_channels) + qdf_mem_free(radio_stat->channels); + if (radio_stat->total_num_tx_power_levels) + qdf_mem_free(radio_stat-> + tx_time_per_power_level); + radio_stat++; + } + } + + qdf_mem_free(stats->result); + qdf_mem_free(stats); + qdf_spin_lock(&ll_stats_priv->ll_stats_lock); + status = qdf_list_remove_front(&ll_stats_priv->ll_stats_q, + &ll_node); + qdf_spin_unlock(&ll_stats_priv->ll_stats_lock); + } + qdf_list_destroy(&ll_stats_priv->ll_stats_q); +} + +static QDF_STATUS +wlan_hdd_set_ll_stats_request_pending(struct hdd_adapter *adapter) +{ + if (qdf_atomic_read(&adapter->is_ll_stats_req_pending)) { + hdd_nofl_debug("Previous ll_stats request is in progress"); + return QDF_STATUS_E_ALREADY; + } + + qdf_atomic_set(&adapter->is_ll_stats_req_pending, 1); + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +/** + * cache_station_stats_cb() - cache_station_stats_cb callback function + * @ev: station stats buffer + * @cookie: cookie that contains the address of the adapter corresponding to + * the request + * + * Return: None + */ +static void cache_station_stats_cb(struct stats_event *ev, void *cookie) +{ + struct hdd_adapter *adapter = cookie, *next_adapter = NULL; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + uint8_t vdev_id; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_DISPLAY_TXRX_STATS; + struct wlan_hdd_link_info *link_info; + + if (!ev->vdev_summary_stats || !ev->vdev_chain_rssi || + !ev->peer_adv_stats || !ev->pdev_stats) { + hdd_debug("Invalid stats"); + return; + } + + vdev_id = ev->vdev_summary_stats->vdev_id; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (link_info->vdev_id != vdev_id) + continue; + + copy_station_stats_to_adapter(link_info, ev); + wlan_hdd_get_peer_rx_rate_stats(link_info); + + /* dev_put has to be done here */ + hdd_adapter_dev_put_debug(adapter, dbgid); + if (next_adapter) + hdd_adapter_dev_put_debug(next_adapter, dbgid); + return; + } + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter, + struct request_info *req_info, + tSirLLStatsGetReq *req) +{ + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc; + struct mlo_stats_vdev_params *info = &req_info->ml_vdev_info; + int i; + uint32_t bmap = 0; + QDF_STATUS status; + + req->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev( + psoc, adapter->deflink->vdev_id); + status = mlo_get_mlstats_vdev_params(psoc, info, + adapter->deflink->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + return status; + for (i = 0; i < info->ml_vdev_count; i++) { + bmap |= (1 << info->ml_vdev_id[i]); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + info->ml_vdev_id[i], + WLAN_OSIF_STATS_ID); + if (!vdev) { + hdd_err("vdev object is NULL for vdev %d", + info->ml_vdev_id[i]); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, + WLAN_OSIF_STATS_ID); + if (!peer) { + hdd_err("peer is null"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(&(req_info->ml_peer_mac_addr[i][0]), peer->macaddr, + QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + } + req->mlo_vdev_id_bitmap = bmap; + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +wlan_hdd_get_mlo_vdev_params(struct hdd_adapter *adapter, + struct request_info *req_info, + tSirLLStatsGetReq *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS +wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info, + tSirLLStatsGetReq *req) +{ + struct wlan_objmgr_peer *peer; + struct request_info info = {0}; + struct wlan_objmgr_vdev *vdev; + struct hdd_adapter *adapter = link_info->adapter; + struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc; + bool is_mlo_vdev = false; + QDF_STATUS status; + + if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) + return QDF_STATUS_E_INVAL; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + info.cookie = adapter; + info.u.get_station_stats_cb = cache_station_stats_cb; + info.vdev_id = link_info->vdev_id; + is_mlo_vdev = wlan_vdev_mlme_get_is_mlo_vdev(psoc, link_info->vdev_id); + if (is_mlo_vdev) { + status = wlan_hdd_get_mlo_vdev_params(adapter, &info, req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("unable to get vdev params for mlo stats"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return status; + } + } + + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_OSIF_STATS_ID); + if (!peer) { + osif_err("peer is null"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID); + + ucfg_mc_cp_stats_set_pending_req(psoc, TYPE_STATION_STATS, &info); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return QDF_STATUS_SUCCESS; +} + +static void +wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter) +{ + QDF_STATUS status; + struct request_info last_req = {0}; + bool pending = false; + + if (!adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) + return; + + status = ucfg_mc_cp_stats_get_pending_req(psoc, TYPE_STATION_STATS, + &last_req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("ucfg_mc_cp_stats_get_pending_req failed"); + return; + } + + ucfg_mc_cp_stats_reset_pending_req(psoc, TYPE_STATION_STATS, + &last_req, &pending); +} + +static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter) +{ + if (adapter->device_mode != QDF_STA_MODE) + return QDF_STATUS_SUCCESS; + + if (!adapter->hdd_ctx->config) { + hdd_err("Invalid hdd config"); + return QDF_STATUS_E_INVAL; + } + + if (adapter->hdd_ctx->is_get_station_clubbed_in_ll_stats_req) { + uint32_t stats_cached_duration; + + stats_cached_duration = + qdf_system_ticks_to_msecs(qdf_system_ticks()) - + adapter->sta_stats_cached_timestamp; + if (qdf_atomic_read(&adapter->is_ll_stats_req_pending) || + (stats_cached_duration <= + adapter->hdd_ctx->config->sta_stats_cache_expiry_time)) + return QDF_STATUS_E_ALREADY; + } + + return QDF_STATUS_SUCCESS; +} + +#else +static inline QDF_STATUS +wlan_hdd_set_station_stats_request_pending(struct wlan_hdd_link_info *link_info, + tSirLLStatsGetReq *req) +{ + return QDF_STATUS_SUCCESS; +} + +static void +wlan_hdd_reset_station_stats_request_pending(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter) +{ +} + +static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */ + +static void wlan_hdd_send_mlo_ll_stats_to_user(struct hdd_adapter *adapter) +{ + if (!wlan_hdd_is_mlo_connection(adapter->deflink)) + return; + + wlan_hdd_send_mlo_ll_iface_stats_to_user(adapter); + wlan_hdd_send_mlo_ll_peer_stats_to_user(adapter); +} + +static int wlan_hdd_send_ll_stats_req(struct wlan_hdd_link_info *link_info, + tSirLLStatsGetReq *req) +{ + int ret = 0; + struct hdd_ll_stats_priv *priv; + struct hdd_ll_stats *stats = NULL; + struct osif_request *request; + qdf_list_node_t *ll_node; + QDF_STATUS status, vdev_req_status; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + void *cookie; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_LL_STATS, + .dealloc = wlan_hdd_dealloc_ll_stats, + }; + + hdd_enter_dev(adapter->dev); + + status = wlan_hdd_set_ll_stats_request_pending(adapter); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + vdev_req_status = wlan_hdd_set_station_stats_request_pending(link_info, + req); + if (QDF_IS_STATUS_ERROR(vdev_req_status)) + hdd_nofl_debug("Requesting LL_STATS only"); + + /* + * FW can send radio stats with multiple events and for the first event + * host allocates memory in wma and processes the events, there is a + * possibility that host receives first event and gets timed out, on + * time out host frees the allocated memory. now if host receives + * remaining events it will again allocate memory and processes the + * stats, since this is not an allocation for new command, this will + * lead to out of order processing of the next event and this memory + * might not be freed, so free the already allocated memory from WMA + * before issuing any new ll stats request free memory allocated for + * previous command + */ + sme_radio_tx_mem_free(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request Allocation Failure"); + wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc, + adapter); + return -ENOMEM; + } + + cookie = osif_request_cookie(request); + + priv = osif_request_priv(request); + + priv->request_id = req->reqId; + priv->request_bitmap = req->paramIdMask; + priv->vdev_id = link_info->vdev_id; + priv->is_mlo_req = wlan_vdev_mlme_get_is_mlo_vdev(hdd_ctx->psoc, + link_info->vdev_id); + if (priv->is_mlo_req) + priv->mlo_vdev_id_bitmap = req->mlo_vdev_id_bitmap; + + qdf_spinlock_create(&priv->ll_stats_lock); + qdf_list_create(&priv->ll_stats_q, HDD_LINK_STATS_MAX); + + status = sme_ll_stats_get_req(hdd_ctx->mac_handle, req, cookie); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("sme_ll_stats_get_req Failed"); + ret = qdf_status_to_os_return(status); + goto exit; + } + ret = osif_request_wait_for_response(request); + if (ret) { + adapter->ll_stats_failure_count++; + hdd_err("Target response timed out request id %d request bitmap 0x%x ll_stats failure count %d", + priv->request_id, priv->request_bitmap, + adapter->ll_stats_failure_count); + qdf_spin_lock(&priv->ll_stats_lock); + priv->request_bitmap = 0; + qdf_spin_unlock(&priv->ll_stats_lock); + sme_radio_tx_mem_free(); + ret = -ETIMEDOUT; + } else { + if (QDF_IS_STATUS_SUCCESS(vdev_req_status)) { + hdd_update_station_stats_cached_timestamp(adapter); + hdd_update_link_state_cached_timestamp(adapter); + } + + adapter->ll_stats_failure_count = 0; + } + + qdf_spin_lock(&priv->ll_stats_lock); + status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node); + qdf_spin_unlock(&priv->ll_stats_lock); + while (QDF_IS_STATUS_SUCCESS(status)) { + stats = qdf_container_of(ll_node, struct hdd_ll_stats, + ll_stats_node); + wlan_hdd_handle_ll_stats(link_info, stats, ret); + qdf_mem_free(stats->result); + qdf_mem_free(stats); + qdf_spin_lock(&priv->ll_stats_lock); + status = qdf_list_remove_front(&priv->ll_stats_q, &ll_node); + qdf_spin_unlock(&priv->ll_stats_lock); + } + qdf_list_destroy(&priv->ll_stats_q); + + if (!ret && req->reqId != DEBUGFS_LLSTATS_REQID) + wlan_hdd_send_mlo_ll_stats_to_user(adapter); + +exit: + qdf_atomic_set(&adapter->is_ll_stats_req_pending, 0); + wlan_hdd_reset_station_stats_request_pending(hdd_ctx->psoc, adapter); + hdd_exit(); + osif_request_put(request); + + if (adapter->ll_stats_failure_count >= + HDD_MAX_ALLOWED_LL_STATS_FAILURE) { + cds_trigger_recovery(QDF_STATS_REQ_TIMEDOUT); + adapter->ll_stats_failure_count = 0; + } + + return ret; +} + +int wlan_hdd_ll_stats_get(struct wlan_hdd_link_info *link_info, + uint32_t req_id, uint32_t req_mask) +{ + int errno; + tSirLLStatsGetReq get_req; + struct hdd_adapter *adapter = link_info->adapter; + + hdd_enter_dev(adapter->dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("Command not allowed in FTM mode"); + return -EPERM; + } + + if (hdd_cm_is_vdev_roaming(link_info)) { + hdd_debug("Roaming in progress, cannot process the request"); + return -EBUSY; + } + + if (!adapter->is_link_layer_stats_set) { + hdd_info("LL_STATs not set"); + return -EINVAL; + } + + get_req.reqId = req_id; + get_req.paramIdMask = req_mask; + get_req.staId = link_info->vdev_id; + + rtnl_lock(); + errno = wlan_hdd_send_ll_stats_req(link_info, &get_req); + rtnl_unlock(); + if (errno) + hdd_err("Send LL stats req failed, id:%u, mask:%d, session:%d", + req_id, req_mask, link_info->vdev_id); + + hdd_exit(); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_ll_stats_get() - get link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int ret; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1]; + tSirLLStatsGetReq LinkLayerStatsGetReq; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (!adapter->is_link_layer_stats_set) { + hdd_nofl_debug("is_link_layer_stats_set: %d", + adapter->is_link_layer_stats_set); + return -EINVAL; + } + + if (hdd_cm_is_vdev_roaming(link_info)) { + hdd_debug("Roaming in progress, cannot process the request"); + return -EBUSY; + } + + if (wlan_hdd_is_link_switch_in_progress(link_info)) { + hdd_debug("Link Switch in progress, can't process the request"); + return -EBUSY; + } + + if (wlan_cfg80211_nla_parse(tb_vendor, + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX, + (struct nlattr *)data, data_len, + qca_wlan_vendor_ll_get_policy)) { + hdd_err("max attribute not present"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]) { + hdd_err("Request Id Not present"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]) { + hdd_err("Req Mask Not present"); + return -EINVAL; + } + + LinkLayerStatsGetReq.reqId = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_ID]); + LinkLayerStatsGetReq.paramIdMask = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_CONFIG_REQ_MASK]); + + LinkLayerStatsGetReq.staId = link_info->vdev_id; + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_send_ll_stats_req(link_info, &LinkLayerStatsGetReq); + if (0 != ret) { + hdd_err("Failed to send LL stats request (id:%u)", + LinkLayerStatsGetReq.reqId); + return ret; + } + + hdd_exit(); + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_get() - get ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (0 != errno) + return -EINVAL; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_qmi_get_sync_resume(); + if (errno) { + hdd_err("qmi sync resume failed: %d", errno); + goto end; + } + + errno = __wlan_hdd_cfg80211_ll_stats_get(wiphy, wdev, data, data_len); + + wlan_hdd_qmi_put_suspend(); + +end: + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +const struct +nla_policy + qca_wlan_vendor_ll_clr_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ] = {.type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP] = {.type = NLA_U8}, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1]; + tSirLLStatsClearReq LinkLayerStatsClearReq; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + u32 statsClearReqMask; + u8 stopReq; + int errno; + QDF_STATUS status; + struct sk_buff *skb; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + if (!adapter->is_link_layer_stats_set) { + hdd_warn("is_link_layer_stats_set : %d", + adapter->is_link_layer_stats_set); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb_vendor, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX, + (struct nlattr *)data, data_len, + qca_wlan_vendor_ll_clr_policy)) { + hdd_err("STATS_CLR_MAX is not present"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK] || + !tb_vendor[QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]) { + hdd_err("Error in LL_STATS CLR CONFIG PARA"); + return -EINVAL; + } + + statsClearReqMask = LinkLayerStatsClearReq.statsClearReqMask = + nla_get_u32(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_REQ_MASK]); + + stopReq = LinkLayerStatsClearReq.stopReq = + nla_get_u8(tb_vendor + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_REQ]); + + /* + * Shall take the request Id if the Upper layers pass. 1 For now. + */ + LinkLayerStatsClearReq.reqId = 1; + + LinkLayerStatsClearReq.staId = adapter->deflink->vdev_id; + + hdd_debug("LL_STATS_CLEAR reqId = %d, staId = %d, statsClearReqMask = 0x%X, stopReq = %d", + LinkLayerStatsClearReq.reqId, + LinkLayerStatsClearReq.staId, + LinkLayerStatsClearReq.statsClearReqMask, + LinkLayerStatsClearReq.stopReq); + + status = sme_ll_stats_clear_req(hdd_ctx->mac_handle, + &LinkLayerStatsClearReq); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("stats clear request failed, %d", status); + return -EINVAL; + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + 2 * sizeof(u32) + + 2 * NLMSG_HDRLEN); + if (!skb) { + hdd_err("skb allocation failed"); + return -ENOMEM; + } + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_RSP_MASK, + statsClearReqMask) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_CONFIG_STOP_RSP, + stopReq)) { + hdd_err("LL_STATS_CLR put fail"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + /* If the ask is to stop the stats collection + * as part of clear (stopReq = 1), ensure + * that no further requests of get go to the + * firmware by having is_link_layer_stats_set set + * to 0. However it the stopReq as part of + * the clear request is 0, the request to get + * the statistics are honoured as in this case + * the firmware is just asked to clear the + * statistics. + */ + if (stopReq == 1) + adapter->is_link_layer_stats_set = false; + + hdd_exit(); + + return wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * wlan_hdd_cfg80211_ll_stats_clear() - clear ll stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 if success, non-zero for failure + */ +int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ll_stats_clear(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_clear_link_layer_stats() - clear link layer stats + * @adapter: pointer to adapter + * + * Wrapper function to clear link layer stats. + * return - void + */ +void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter) +{ + tSirLLStatsClearReq link_layer_stats_clear_req; + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + + link_layer_stats_clear_req.statsClearReqMask = WIFI_STATS_IFACE_AC | + WIFI_STATS_IFACE_ALL_PEER | WIFI_STATS_IFACE_CONTENTION; + link_layer_stats_clear_req.stopReq = 0; + link_layer_stats_clear_req.reqId = 1; + link_layer_stats_clear_req.staId = adapter->deflink->vdev_id; + sme_ll_stats_clear_req(mac_handle, &link_layer_stats_clear_req); +} + +/** + * hdd_populate_per_peer_ps_info() - populate per peer sta's PS info + * @wifi_peer_info: peer information + * @vendor_event: buffer for vendor event + * + * Return: 0 success + */ +static inline int +hdd_populate_per_peer_ps_info(struct wifi_peer_info *wifi_peer_info, + struct sk_buff *vendor_event) +{ + if (!wifi_peer_info) { + hdd_err("Invalid pointer to peer info."); + return -EINVAL; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE, + wifi_peer_info->power_saving) || + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS, + QDF_MAC_ADDR_SIZE, &wifi_peer_info->peer_macaddr)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail."); + return -EINVAL; + } + return 0; +} + +/** + * hdd_populate_wifi_peer_ps_info() - populate peer sta's power state + * @data: stats for peer STA + * @vendor_event: buffer for vendor event + * + * Return: 0 success + */ +static int hdd_populate_wifi_peer_ps_info(struct wifi_peer_stat *data, + struct sk_buff *vendor_event) +{ + uint32_t peer_num, i; + struct wifi_peer_info *wifi_peer_info; + struct nlattr *peer_info, *peers; + + if (!data) { + hdd_err("Invalid pointer to Wifi peer stat."); + return -EINVAL; + } + + peer_num = data->num_peers; + if (peer_num == 0) { + hdd_err("Peer number is zero."); + return -EINVAL; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM, + peer_num)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; + } + + peer_info = nla_nest_start(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG); + if (!peer_info) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < peer_num; i++) { + wifi_peer_info = &data->peer_info[i]; + peers = nla_nest_start(vendor_event, i); + + if (!peers) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + if (hdd_populate_per_peer_ps_info(wifi_peer_info, vendor_event)) + return -EINVAL; + + nla_nest_end(vendor_event, peers); + } + nla_nest_end(vendor_event, peer_info); + + return 0; +} + +/** + * hdd_populate_tx_failure_info() - populate TX failure info + * @tx_fail: TX failure info + * @skb: buffer for vendor event + * + * Return: 0 Success + */ +static inline int +hdd_populate_tx_failure_info(struct sir_wifi_iface_tx_fail *tx_fail, + struct sk_buff *skb) +{ + int status = 0; + + if (!tx_fail || !skb) + return -EINVAL; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID, + tx_fail->tid) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU, + tx_fail->msdu_num) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS, + tx_fail->status)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + status = -EINVAL; + } + + return status; +} + +/** + * hdd_populate_wifi_channel_cca_info() - put channel cca info to vendor event + * @cca: cca info array for all channels + * @vendor_event: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_channel_cca_info(struct sir_wifi_chan_cca_stats *cca, + struct sk_buff *vendor_event) +{ + /* There might be no CCA info for a channel */ + if (!cca) + return 0; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME, + cca->idle_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME, + cca->tx_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME, + cca->rx_in_bss_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME, + cca->rx_out_bss_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY, + cca->rx_busy_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD, + cca->rx_in_bad_cond_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD, + cca->tx_in_bad_cond_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL, + cca->wlan_not_avail_time) || + nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID, + cca->vdev_id)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; + } + return 0; +} + +/** + * hdd_populate_wifi_signal_info - put chain signal info + * @peer_signal: RF chain signal info + * @skb: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_signal_info(struct sir_wifi_peer_signal_stats *peer_signal, + struct sk_buff *skb) +{ + uint32_t i, chain_count; + struct nlattr *chains, *att; + + /* There might be no signal info for a peer */ + if (!peer_signal) + return 0; + + chain_count = peer_signal->num_chain < WIFI_MAX_CHAINS ? + peer_signal->num_chain : WIFI_MAX_CHAINS; + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM, + chain_count)) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; + } + + att = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL); + if (!att) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < chain_count; i++) { + chains = nla_nest_start(skb, i); + + if (!chains) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + hdd_debug("SNR=%d, NF=%d, Rx=%d, Tx=%d", + peer_signal->per_ant_snr[i], + peer_signal->nf[i], + peer_signal->per_ant_rx_mpdus[i], + peer_signal->per_ant_tx_mpdus[i]); + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR, + peer_signal->per_ant_snr[i]) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF, + peer_signal->nf[i]) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU, + peer_signal->per_ant_rx_mpdus[i]) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU, + peer_signal->per_ant_tx_mpdus[i])) { + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; + } + nla_nest_end(skb, chains); + } + nla_nest_end(skb, att); + + return 0; +} + +/** + * hdd_populate_wifi_wmm_ac_tx_info() - put AC TX info + * @tx_stats: tx info + * @skb: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_wmm_ac_tx_info(struct sir_wifi_tx *tx_stats, + struct sk_buff *skb) +{ + uint32_t *agg_size, *succ_mcs, *fail_mcs, *delay; + + /* There might be no TX info for a peer */ + if (!tx_stats) + return 0; + + agg_size = tx_stats->mpdu_aggr_size; + succ_mcs = tx_stats->success_mcs; + fail_mcs = tx_stats->fail_mcs; + delay = tx_stats->delay; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU, + tx_stats->msdus) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU, + tx_stats->mpdus) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU, + tx_stats->ppdus) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES, + tx_stats->bytes) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP, + tx_stats->drops) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES, + tx_stats->drop_bytes) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY, + tx_stats->retries) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK, + tx_stats->failed) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM, + tx_stats->aggr_len) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM, + tx_stats->success_mcs_len) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM, + tx_stats->fail_mcs_len) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE, + tx_stats->delay_len)) + goto put_attr_fail; + + if (agg_size) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR, + tx_stats->aggr_len, agg_size)) + goto put_attr_fail; + } + + if (succ_mcs) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS, + tx_stats->success_mcs_len, succ_mcs)) + goto put_attr_fail; + } + + if (fail_mcs) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS, + tx_stats->fail_mcs_len, fail_mcs)) + goto put_attr_fail; + } + + if (delay) { + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY, + tx_stats->delay_len, delay)) + goto put_attr_fail; + } + return 0; + +put_attr_fail: + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; +} + +/** + * hdd_populate_wifi_wmm_ac_rx_info() - put AC RX info + * @rx_stats: rx info + * @skb: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_wmm_ac_rx_info(struct sir_wifi_rx *rx_stats, + struct sk_buff *skb) +{ + uint32_t *mcs, *aggr; + + /* There might be no RX info for a peer */ + if (!rx_stats) + return 0; + + aggr = rx_stats->mpdu_aggr; + mcs = rx_stats->mcs; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU, + rx_stats->mpdus) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES, + rx_stats->bytes) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU, + rx_stats->ppdus) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES, + rx_stats->ppdu_bytes) || + nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST, + rx_stats->mpdu_lost) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY, + rx_stats->mpdu_retry) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP, + rx_stats->mpdu_dup) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD, + rx_stats->mpdu_discard) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM, + rx_stats->aggr_len) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM, + rx_stats->mcs_len)) + goto put_attr_fail; + + if (aggr) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR, + rx_stats->aggr_len, aggr)) + goto put_attr_fail; + } + + if (mcs) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS, + rx_stats->mcs_len, mcs)) + goto put_attr_fail; + } + + return 0; + +put_attr_fail: + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; +} + +/** + * hdd_populate_wifi_wmm_ac_info() - put WMM AC info + * @ac_stats: per AC stats + * @skb: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_wmm_ac_info(struct sir_wifi_ll_ext_wmm_ac_stats *ac_stats, + struct sk_buff *skb) +{ + struct nlattr *wmm; + + wmm = nla_nest_start(skb, ac_stats->type); + if (!wmm) + goto nest_start_fail; + + if (hdd_populate_wifi_wmm_ac_tx_info(ac_stats->tx_stats, skb) || + hdd_populate_wifi_wmm_ac_rx_info(ac_stats->rx_stats, skb)) + goto put_attr_fail; + + nla_nest_end(skb, wmm); + return 0; + +nest_start_fail: + hdd_err("nla_nest_start failed"); + return -EINVAL; + +put_attr_fail: + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; +} + +/** + * hdd_populate_wifi_ll_ext_peer_info() - put per peer info + * @peers: peer stats + * @skb: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_ll_ext_peer_info(struct sir_wifi_ll_ext_peer_stats *peers, + struct sk_buff *skb) +{ + uint32_t i; + struct nlattr *wmm_ac; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID, + peers->peer_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID, + peers->vdev_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES, + peers->sta_ps_inds) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION, + peers->sta_ps_durs) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ, + peers->rx_probe_reqs) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT, + peers->rx_oth_mgmts) || + nla_put(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS, + QDF_MAC_ADDR_SIZE, peers->mac_address) || + hdd_populate_wifi_signal_info(&peers->peer_signal_stats, skb)) { + hdd_err("put peer signal attr failed"); + return -EINVAL; + } + + wmm_ac = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS); + if (!wmm_ac) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < WLAN_MAX_AC; i++) { + if (hdd_populate_wifi_wmm_ac_info(&peers->ac_stats[i], skb)) { + hdd_err("put WMM AC attr failed"); + return -EINVAL; + } + } + + nla_nest_end(skb, wmm_ac); + return 0; +} + +/** + * hdd_populate_wifi_ll_ext_stats() - put link layer extension stats + * @stats: link layer stats + * @skb: vendor event buffer + * + * Return: 0 Success, EINVAL failure + */ +static int +hdd_populate_wifi_ll_ext_stats(struct sir_wifi_ll_ext_stats *stats, + struct sk_buff *skb) +{ + uint32_t i; + struct nlattr *peer, *peer_info, *channels, *channel_info; + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE, + stats->trigger_cond_id) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP, + stats->cca_chgd_bitmap) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP, + stats->sig_chgd_bitmap) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP, + stats->tx_chgd_bitmap) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP, + stats->rx_chgd_bitmap) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM, + stats->channel_num) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM, + stats->peer_num)) { + goto put_attr_fail; + } + + channels = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS); + if (!channels) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < stats->channel_num; i++) { + channel_info = nla_nest_start(skb, i); + if (!channel_info) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + if (hdd_populate_wifi_channel_cca_info(&stats->cca[i], skb)) + goto put_attr_fail; + nla_nest_end(skb, channel_info); + } + nla_nest_end(skb, channels); + + peer_info = nla_nest_start(skb, + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER); + if (!peer_info) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + for (i = 0; i < stats->peer_num; i++) { + peer = nla_nest_start(skb, i); + if (!peer) { + hdd_err("nla_nest_start failed"); + return -EINVAL; + } + + if (hdd_populate_wifi_ll_ext_peer_info(&stats->peer_stats[i], + skb)) + goto put_attr_fail; + nla_nest_end(skb, peer); + } + + nla_nest_end(skb, peer_info); + return 0; + +put_attr_fail: + hdd_err("QCA_WLAN_VENDOR_ATTR put fail"); + return -EINVAL; +} + +/** + * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext + * @ctx: HDD context + * @rsp: msg from FW + * + * This function is an extension of + * wlan_hdd_cfg80211_link_layer_stats_callback. It converts + * monitoring parameters offloaded to NL data and send the same to the + * kernel/upper layers. + * + * Return: None + */ +void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx, + tSirLLStatsResults *rsp) +{ + struct hdd_context *hdd_ctx; + struct sk_buff *skb; + uint32_t param_id, index; + struct wlan_hdd_link_info *link_info; + struct wifi_peer_stat *peer_stats; + uint8_t *results; + int status; + + hdd_enter(); + + if (!rsp) { + hdd_err("Invalid result."); + return; + } + + hdd_ctx = hdd_handle_to_context(ctx); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, rsp->ifaceId); + if (!link_info) { + hdd_err("vdev_id %d does not exist with host.", rsp->ifaceId); + return; + } + + index = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT_INDEX; + skb = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + LL_STATS_EVENT_BUF_SIZE + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!skb) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed."); + return; + } + + results = rsp->results; + param_id = rsp->paramId; + hdd_info("LL_STATS RESP paramID = 0x%x, ifaceId = %u, result = %pK", + rsp->paramId, rsp->ifaceId, rsp->results); + if (param_id & WMI_LL_STATS_EXT_PS_CHG) { + peer_stats = (struct wifi_peer_stat *)results; + status = hdd_populate_wifi_peer_ps_info(peer_stats, skb); + } else if (param_id & WMI_LL_STATS_EXT_TX_FAIL) { + struct sir_wifi_iface_tx_fail *tx_fail; + + tx_fail = (struct sir_wifi_iface_tx_fail *)results; + status = hdd_populate_tx_failure_info(tx_fail, skb); + } else if (param_id & WMI_LL_STATS_EXT_MAC_COUNTER) { + hdd_info("MAC counters stats"); + status = hdd_populate_wifi_ll_ext_stats( + (struct sir_wifi_ll_ext_stats *) + rsp->results, skb); + } else { + hdd_info("Unknown link layer stats"); + status = -EINVAL; + } + + if (status == 0) + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); + else + wlan_cfg80211_vendor_free_skb(skb); + hdd_exit(); +} + +const struct nla_policy +qca_wlan_vendor_ll_ext_policy[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_CHG] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TID] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NUM_MSDU] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_STATUS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_STATE] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_MAC_ADDRESS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_EVENT_MODE] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_ID] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ID] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CHANNEL_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_DELAY_ARRAY_SIZE] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_TIME] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_ANT_NUM] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_SIGNAL] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_RSSI_BEACON] = { + .type = NLA_U32 + }, + [QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IFACE_SNR_BEACON] = { + .type = NLA_U32 + }, +}; + +/** + * __wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters + * @wiphy: wiphy handle + * @wdev: wdev handle + * @data: user layer input + * @data_len: length of user layer input + * + * this function is called in ssr protected environment. + * + * return: 0 success, none zero for failure + */ +static int __wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + QDF_STATUS status; + int errno; + uint32_t period; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sir_ll_ext_stats_threshold thresh = {0,}; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1]; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("command not allowed in ftm mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EPERM; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX, + (struct nlattr *)data, data_len, + qca_wlan_vendor_ll_ext_policy)) { + hdd_err("maximum attribute not present"); + return -EPERM; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]) { + period = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_PERIOD]); + + if (period != 0 && period < LL_STATS_MIN_PERIOD) + period = LL_STATS_MIN_PERIOD; + + /* + * Only enable/disable counters. + * Keep the last threshold settings. + */ + goto set_period; + } + + /* global thresh is not enabled */ + if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]) { + thresh.global = false; + hdd_warn("global thresh is not set"); + } else { + thresh.global_threshold = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CFG_THRESHOLD]); + thresh.global = true; + hdd_debug("globle thresh is %d", thresh.global_threshold); + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]) { + thresh.global = false; + hdd_warn("global thresh is not enabled"); + } else { + thresh.global = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_GLOBAL]); + hdd_debug("global is %d", thresh.global); + } + + thresh.enable_bitmap = false; + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]) { + thresh.tx_bitmap = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BITMAP]); + thresh.enable_bitmap = true; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]) { + thresh.rx_bitmap = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BITMAP]); + thresh.enable_bitmap = true; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]) { + thresh.cca_bitmap = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_CCA_BSS_BITMAP]); + thresh.enable_bitmap = true; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]) { + thresh.signal_bitmap = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_SIGNAL_BITMAP]); + thresh.enable_bitmap = true; + } + + if (!thresh.global && !thresh.enable_bitmap) { + hdd_warn("threshold will be disabled."); + thresh.enable = false; + + /* Just disable threshold */ + goto set_thresh; + } else { + thresh.enable = true; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]) { + thresh.tx.msdu = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MSDU]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]) { + thresh.tx.mpdu = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_MPDU]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]) { + thresh.tx.ppdu = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_PPDU]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]) { + thresh.tx.bytes = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BYTES]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]) { + thresh.tx.msdu_drop = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]) { + thresh.tx.byte_drop = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DROP_BYTES]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]) { + thresh.tx.mpdu_retry = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_RETRY]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]) { + thresh.tx.mpdu_fail = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_ACK]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]) { + thresh.tx.ppdu_fail = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_NO_BACK]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]) { + thresh.tx.aggregation = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_AGGR]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]) { + thresh.tx.succ_mcs = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_SUCC_MCS]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]) { + thresh.tx.fail_mcs = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_FAIL_MCS]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]) { + thresh.tx.delay = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_DELAY]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]) { + thresh.rx.mpdu = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]) { + thresh.rx.bytes = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_BYTES]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]) { + thresh.rx.ppdu = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]) { + thresh.rx.ppdu_bytes = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PPDU_BYTES]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]) { + thresh.rx.mpdu_lost = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_LOST]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]) { + thresh.rx.mpdu_retry = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_RETRY]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]) { + thresh.rx.mpdu_dup = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DUP]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]) { + thresh.rx.mpdu_discard = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MPDU_DISCARD]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]) { + thresh.rx.aggregation = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_AGGR]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]) { + thresh.rx.mcs = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MCS]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]) { + thresh.rx.ps_inds = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_TIMES]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]) { + thresh.rx.ps_durs = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_PEER_PS_DURATION]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]) { + thresh.rx.probe_reqs = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_PROBE_REQ]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]) { + thresh.rx.other_mgmt = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_MGMT]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]) { + thresh.cca.idle_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IDLE_TIME]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]) { + thresh.cca.tx_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_TIME]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]) { + thresh.cca.rx_in_bss_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_IN_BSS_TIME]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]) { + thresh.cca.rx_out_bss_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_OUT_BSS_TIME]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]) { + thresh.cca.rx_busy_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BUSY]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]) { + thresh.cca.rx_in_bad_cond_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_RX_BAD]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]) { + thresh.cca.tx_in_bad_cond_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_TX_BAD]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]) { + thresh.cca.wlan_not_avail_time = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_NO_AVAIL]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]) { + thresh.signal.snr = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_SNR]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]) { + thresh.signal.nf = nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_ANT_NF]); + } + +set_thresh: + hdd_info("send thresh settings to target"); + status = sme_ll_stats_set_thresh(hdd_ctx->mac_handle, &thresh); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("sme_ll_stats_set_thresh failed."); + return -EINVAL; + } + return 0; + +set_period: + hdd_info("send period to target"); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_pdev_param_stats_observation_period, + period, PDEV_CMD); + if (errno) { + hdd_err("wma_cli_set_command set_period failed."); + return -EINVAL; + } + return 0; +} + +/** + * wlan_hdd_cfg80211_ll_stats_ext_set_param - config monitor parameters + * @wiphy: wiphy handle + * @wdev: wdev handle + * @data: user layer input + * @data_len: length of user layer input + * + * return: 0 success, einval failure + */ +int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_ll_stats_ext_set_param(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#else +static QDF_STATUS wlan_hdd_stats_request_needed(struct hdd_adapter *adapter) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * __wlan_hdd_cfg80211_connected_chan_stats_request() - stats request for + * currently connected channel + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int +__wlan_hdd_cfg80211_connected_chan_stats_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + bool is_vdev_connected; + enum QDF_OPMODE mode; + QDF_STATUS status; + + is_vdev_connected = hdd_cm_is_vdev_connected(adapter->deflink); + mode = adapter->device_mode; + + if (mode != QDF_STA_MODE || !is_vdev_connected) { + hdd_debug("vdev %d: reject chan stats req, mode:%d, conn:%d", + adapter->deflink->vdev_id, mode, is_vdev_connected); + return -EPERM; + } + + status = ucfg_mlme_connected_chan_stats_request(hdd_ctx->psoc, + adapter->deflink->vdev_id); + return qdf_status_to_os_return(status); +} + +int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_connected_chan_stats_request(wiphy, wdev, + data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * __wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +static int __wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + tStatsExtRequestReq stats_ext_req; + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int ret_val; + QDF_STATUS status; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_txrx_stats_req txrx_req = {0}; + + hdd_enter_dev(dev); + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + /** + * HTT_DBG_EXT_STATS_PDEV_RX + */ + txrx_req.stats = 2; + /* default value of secondary parameter is 0(mac_id) */ + txrx_req.mac_id = 0; + status = cdp_txrx_stats_request(soc, adapter->deflink->vdev_id, + &txrx_req); + if (QDF_STATUS_SUCCESS != status) { + hdd_err_rl("Failed to get hw stats: %u", status); + ret_val = -EINVAL; + } + + stats_ext_req.request_data_len = data_len; + stats_ext_req.request_data = (void *)data; + + status = cdp_request_rx_hw_stats(soc, adapter->deflink->vdev_id); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err_rl("Failed to get hw stats: %u", status); + ret_val = -EINVAL; + } + + status = sme_stats_ext_request(adapter->deflink->vdev_id, + &stats_ext_req); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err_rl("Failed to get fw stats: %u", status); + ret_val = -EINVAL; + } + + return ret_val; +} + +/** + * wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_stats_ext_request(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle, + struct stats_ext_event *data) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct sk_buff *vendor_event; + int status; + int ret_val; + struct wlan_hdd_link_info *link_info; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX; + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, data->vdev_id); + if (!link_info) { + hdd_err("vdev_id %d does not exist with host", data->vdev_id); + return; + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + data->event_data_len + + sizeof(uint32_t) + + NLMSG_HDRLEN + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + ret_val = nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_IFINDEX, + link_info->adapter->dev->ifindex); + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_IFINDEX put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + + return; + } + + ret_val = nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_STATS_EXT, + data->event_data_len, data->event_data); + + if (ret_val) { + hdd_err("QCA_WLAN_VENDOR_ATTR_STATS_EXT put fail"); + wlan_cfg80211_vendor_free_skb(vendor_event); + + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + +} + +void +wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle, + struct sir_sme_rx_aggr_hole_ind *pmsg) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + int status; + uint32_t data_size, hole_info_size; + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_STATS_EXT_INDEX; + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return; + + if (!pmsg) { + hdd_err("msg received here is null"); + return; + } + + hole_info_size = (pmsg->hole_cnt)*sizeof(pmsg->hole_info_array[0]); + data_size = sizeof(struct sir_sme_rx_aggr_hole_ind) + hole_info_size; + + vendor_event = wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + data_size + + NLMSG_HDRLEN + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!vendor_event) { + hdd_err("vendor_event_alloc failed for STATS_EXT2"); + return; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM, + pmsg->hole_cnt)) { + hdd_err("%s put fail", + "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_NUM"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO, + hole_info_size, + (void *)(pmsg->hole_info_array))) { + hdd_err("%s put fail", + "QCA_WLAN_VENDOR_ATTR_RX_AGGREGATION_STATS_HOLES_INFO"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +#else +void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle, + struct stats_ext_event *data) +{ +} + +void +wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle, + struct sir_sme_rx_aggr_hole_ind *pmsg) +{ +} +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * enum roam_event_rt_info_reset - Reset the notif param value of struct + * roam_event_rt_info to 0 + * @ROAM_EVENT_RT_INFO_RESET: Reset the value to 0 + */ +enum roam_event_rt_info_reset { + ROAM_EVENT_RT_INFO_RESET = 0, +}; + +/** + * struct roam_ap - Roamed/Failed AP info + * @num_cand: number of candidate APs + * @bssid: BSSID of roamed/failed AP + * @rssi: RSSI of roamed/failed AP + * @freq: Frequency of roamed/failed AP + */ +struct roam_ap { + uint32_t num_cand; + struct qdf_mac_addr bssid; + int8_t rssi; + uint16_t freq; +}; + +/** + * hdd_get_roam_rt_stats_event_len() - calculate length of skb required for + * sending roam events stats. + * @roam_stats: pointer to roam_stats_event structure + * @idx: TLV index of roam stats event + * + * Return: length of skb + */ +static uint32_t +hdd_get_roam_rt_stats_event_len(struct roam_stats_event *roam_stats, + uint8_t idx) +{ + uint32_t len = 0; + uint8_t i = 0, num_cand = 0; + + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON */ + if (roam_stats->trigger[idx].present) + len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON */ + if (roam_stats->roam_event_param.roam_invoke_fail_reason) + len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE */ + if (roam_stats->roam_event_param.roam_scan_state) + len += nla_total_size(sizeof(uint8_t)); + + if (roam_stats->scan[idx].present) { + if (roam_stats->scan[idx].num_chan && + roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL) + for (i = 0; i < roam_stats->scan[idx].num_chan;) + i++; + + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST */ + len += (nla_total_size(sizeof(uint32_t)) * i); + + if (roam_stats->result[idx].present && + roam_stats->result[idx].fail_reason) { + num_cand++; + } else if (roam_stats->trigger[idx].present) { + for (i = 0; i < roam_stats->scan[idx].num_ap; i++) { + if (roam_stats->scan[idx].ap[i].type == 2) + num_cand++; + } + } + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO */ + len += NLA_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID */ + len += (nla_total_size(QDF_MAC_ADDR_SIZE) * num_cand); + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI */ + len += (nla_total_size(sizeof(int32_t)) * num_cand); + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ */ + len += (nla_total_size(sizeof(uint32_t)) * num_cand); + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON */ + len += (nla_total_size(sizeof(uint32_t)) * num_cand); + } + + /* QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE */ + if (len) + len += nla_total_size(sizeof(uint32_t)); + + return len; +} + +#define SUBCMD_ROAM_EVENTS_INDEX \ + QCA_NL80211_VENDOR_SUBCMD_ROAM_EVENTS_INDEX +#define ROAM_SCAN_FREQ_LIST \ + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_FREQ_LIST +#define ROAM_INVOKE_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON +#define ROAM_SCAN_STATE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE +#define ROAM_EVENTS_CANDIDATE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO +#define CANDIDATE_BSSID \ + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_BSSID +#define CANDIDATE_RSSI \ + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_RSSI +#define CANDIDATE_FREQ \ + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FREQ +#define ROAM_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CANDIDATE_INFO_FAIL_REASON + +/** + * roam_rt_stats_fill_scan_freq() - Fill the scan frequency list from the + * roam stats event. + * @vendor_event: pointer to sk_buff structure + * @idx: TLV index of roam stats event + * @roam_stats: pointer to roam_stats_event structure + * + * Return: none + */ +static void +roam_rt_stats_fill_scan_freq(struct sk_buff *vendor_event, uint8_t idx, + struct roam_stats_event *roam_stats) +{ + struct nlattr *nl_attr; + uint8_t i; + + nl_attr = nla_nest_start(vendor_event, ROAM_SCAN_FREQ_LIST); + if (!nl_attr) { + hdd_err("nla nest start fail"); + kfree_skb(vendor_event); + return; + } + if (roam_stats->scan[idx].num_chan && + roam_stats->scan[idx].type == ROAM_STATS_SCAN_TYPE_PARTIAL) { + for (i = 0; i < roam_stats->scan[idx].num_chan; i++) { + if (nla_put_u32(vendor_event, i, + roam_stats->scan[idx].chan_freq[i])) { + hdd_err("failed to put freq at index %d", i); + kfree_skb(vendor_event); + return; + } + } + } + nla_nest_end(vendor_event, nl_attr); +} + +/** + * roam_rt_stats_fill_cand_info() - Fill the roamed/failed AP info from the + * roam stats event. + * @vendor_event: pointer to sk_buff structure + * @idx: TLV index of roam stats event + * @roam_stats: pointer to roam_stats_event structure + * + * Return: none + */ +static void +roam_rt_stats_fill_cand_info(struct sk_buff *vendor_event, uint8_t idx, + struct roam_stats_event *roam_stats) +{ + struct nlattr *nl_attr, *nl_array; + struct roam_ap cand_ap = {0}; + uint8_t i, num_cand = 0; + + if (roam_stats->result[idx].present && + roam_stats->result[idx].fail_reason && + roam_stats->result[idx].fail_reason != ROAM_FAIL_REASON_UNKNOWN) { + num_cand++; + for (i = 0; i < roam_stats->scan[idx].num_ap; i++) { + if (roam_stats->scan[idx].ap[i].type == 0 && + qdf_is_macaddr_equal(&roam_stats-> + result[idx].fail_bssid, + &roam_stats-> + scan[idx].ap[i].bssid)) { + qdf_copy_macaddr(&cand_ap.bssid, + &roam_stats-> + scan[idx].ap[i].bssid); + cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi; + cand_ap.freq = roam_stats->scan[idx].ap[i].freq; + } + } + } else if (roam_stats->trigger[idx].present) { + for (i = 0; i < roam_stats->scan[idx].num_ap; i++) { + if (roam_stats->scan[idx].ap[i].type == 2) { + num_cand++; + qdf_copy_macaddr(&cand_ap.bssid, + &roam_stats-> + scan[idx].ap[i].bssid); + cand_ap.rssi = roam_stats->scan[idx].ap[i].rssi; + cand_ap.freq = roam_stats->scan[idx].ap[i].freq; + } + } + } + + nl_array = nla_nest_start(vendor_event, ROAM_EVENTS_CANDIDATE); + if (!nl_array) { + hdd_err("nl array nest start fail"); + kfree_skb(vendor_event); + return; + } + for (i = 0; i < num_cand; i++) { + nl_attr = nla_nest_start(vendor_event, i); + if (!nl_attr) { + hdd_err("nl attr nest start fail"); + kfree_skb(vendor_event); + return; + } + if (nla_put(vendor_event, CANDIDATE_BSSID, + sizeof(cand_ap.bssid), cand_ap.bssid.bytes)) { + hdd_err("%s put fail", + "ROAM_EVENTS_CANDIDATE_INFO_BSSID"); + kfree_skb(vendor_event); + return; + } + if (nla_put_s32(vendor_event, CANDIDATE_RSSI, cand_ap.rssi)) { + hdd_err("%s put fail", + "ROAM_EVENTS_CANDIDATE_INFO_RSSI"); + kfree_skb(vendor_event); + return; + } + if (nla_put_u32(vendor_event, CANDIDATE_FREQ, cand_ap.freq)) { + hdd_err("%s put fail", + "ROAM_EVENTS_CANDIDATE_INFO_FREQ"); + kfree_skb(vendor_event); + return; + } + if (roam_stats->result[idx].present && + roam_stats->result[idx].fail_reason) { + if (nla_put_u32(vendor_event, ROAM_FAIL_REASON, + roam_stats->result[idx].fail_reason)) { + hdd_err("%s put fail", + "ROAM_EVENTS_CANDIDATE_FAIL_REASON"); + kfree_skb(vendor_event); + return; + } + } + nla_nest_end(vendor_event, nl_attr); + } + nla_nest_end(vendor_event, nl_array); +} + +static void +wlan_hdd_cfg80211_typical_roam_events_callback(struct wlan_hdd_link_info *link_info, + struct roam_stats_event *roam_stats, + uint8_t idx) +{ + uint32_t data_size, roam_event_type = 0; + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_err("Invalid hdd_ctx"); + return; + } + + data_size = hdd_get_roam_rt_stats_event_len(roam_stats, idx); + if (!data_size) { + hdd_err("No data requested"); + return; + } + + data_size += NLMSG_HDRLEN; + vendor_event = + wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &link_info->adapter->wdev, + data_size, + SUBCMD_ROAM_EVENTS_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + hdd_err("vendor_event_alloc failed for ROAM_EVENTS_STATS"); + return; + } + + if (roam_stats->scan[idx].present && roam_stats->trigger[idx].present) { + roam_rt_stats_fill_scan_freq(vendor_event, idx, roam_stats); + roam_rt_stats_fill_cand_info(vendor_event, idx, roam_stats); + } + + if (roam_stats->roam_event_param.roam_scan_state) { + roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_ROAM_SCAN_STATE; + if (nla_put_u8(vendor_event, ROAM_SCAN_STATE, + roam_stats->roam_event_param.roam_scan_state)) { + hdd_err("%s put fail", + "VENDOR_ATTR_ROAM_EVENTS_ROAM_SCAN_STATE"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + roam_stats->roam_event_param.roam_scan_state = + ROAM_EVENT_RT_INFO_RESET; + } + if (roam_stats->trigger[idx].present) { + roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_TRIGGER_REASON; + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON, + roam_stats->trigger[idx].trigger_reason)) { + hdd_err("%s put fail", + "VENDOR_ATTR_ROAM_EVENTS_TRIGGER_REASON"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + } + if (roam_stats->roam_event_param.roam_invoke_fail_reason) { + roam_event_type |= + QCA_WLAN_VENDOR_ROAM_EVENT_INVOKE_FAIL_REASON; + if (nla_put_u32(vendor_event, ROAM_INVOKE_FAIL_REASON, + roam_stats-> + roam_event_param.roam_invoke_fail_reason)) { + hdd_err("%s put fail", + "VENDOR_ATTR_ROAM_EVENTS_INVOKE_FAIL_REASON"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + roam_stats->roam_event_param.roam_invoke_fail_reason = + ROAM_EVENT_RT_INFO_RESET; + } + if (roam_stats->result[idx].present && + roam_stats->result[idx].fail_reason) + roam_event_type |= QCA_WLAN_VENDOR_ROAM_EVENT_FAIL_REASON; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE, + roam_event_type)) { + hdd_err("%s put fail", "QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_TYPE"); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} + +#undef SUBCMD_ROAM_EVENTS_INDEX +#undef ROAM_SCAN_FREQ_LIST +#undef ROAM_INVOKE_FAIL_REASON +#undef ROAM_SCAN_STATE +#undef ROAM_EVENTS_CANDIDATE +#undef CANDIDATE_BSSID +#undef CANDIDATE_RSSI +#undef CANDIDATE_FREQ +#undef ROAM_FAIL_REASON +#endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef LINKSPEED_DEBUG_ENABLED +#define linkspeed_dbg(format, args...) pr_info(format, ## args) +#else +#define linkspeed_dbg(format, args...) +#endif /* LINKSPEED_DEBUG_ENABLED */ + +static void +wlan_hdd_fill_per_link_summary_stats(tCsrSummaryStatsInfo *stats, + struct station_info *info, + struct wlan_hdd_link_info *link_info) +{ + uint8_t i; + uint32_t orig_cnt; + uint32_t orig_fail_cnt; + QDF_STATUS status; + uint8_t *peer_mac; + ol_txrx_soc_handle soc; + struct cdp_peer_stats *peer_stats; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) + return; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) + return; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + peer_mac = link_info->session.station.conn_info.bssid.bytes; + status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id, + peer_mac, peer_stats, + CDP_WILD_PEER_TYPE, + WLAN_MAX_MLD); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to get per link peer stats for the peer: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_mac)); + goto exit; + } + + info->tx_retries = 0; + info->tx_failed = 0; + + for (i = 0; i < WIFI_MAX_AC; ++i) { + info->tx_retries += stats->multiple_retry_cnt[i]; + info->tx_failed += stats->fail_cnt[i]; + } + + orig_cnt = info->tx_retries; + orig_fail_cnt = info->tx_failed; + info->tx_retries = peer_stats->tx.retries_mpdu; + info->tx_failed += peer_stats->tx.mpdu_success_with_retries; + hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx retries adjust from %d to %d", + QDF_MAC_ADDR_REF(peer_mac), orig_cnt, info->tx_retries); + hdd_debug("for peer: " QDF_MAC_ADDR_FMT "tx failed adjust from %d to %d", + QDF_MAC_ADDR_REF(peer_mac), orig_fail_cnt, info->tx_failed); +exit: + qdf_mem_free(peer_stats); +} + +/** + * wlan_hdd_fill_summary_stats() - populate station_info summary stats + * @stats: summary stats to use as a source + * @info: kernel station_info struct to use as a destination + * @vdev_id: stats get from which vdev id + * + * Return: None + */ +static void wlan_hdd_fill_summary_stats(tCsrSummaryStatsInfo *stats, + struct station_info *info, + uint8_t vdev_id) +{ + int i; + struct cds_vdev_dp_stats dp_stats; + uint32_t orig_cnt; + uint32_t orig_fail_cnt; + + info->rx_packets = stats->rx_frm_cnt; + info->tx_packets = 0; + info->tx_retries = 0; + info->tx_failed = 0; + + for (i = 0; i < WIFI_MAX_AC; ++i) { + info->tx_packets += stats->tx_frm_cnt[i]; + info->tx_retries += stats->multiple_retry_cnt[i]; + info->tx_failed += stats->fail_cnt[i]; + } + + if (cds_dp_get_vdev_stats(vdev_id, &dp_stats)) { + orig_cnt = info->tx_retries; + orig_fail_cnt = info->tx_failed; + info->tx_retries = dp_stats.tx_retries_mpdu; + info->tx_failed += dp_stats.tx_mpdu_success_with_retries; + hdd_debug("vdev %d tx retries adjust from %d to %d", + vdev_id, orig_cnt, info->tx_retries); + hdd_debug("tx failed adjust from %d to %d", + orig_fail_cnt, info->tx_failed); + } + + info->filled |= HDD_INFO_TX_PACKETS | + HDD_INFO_TX_RETRIES | + HDD_INFO_TX_FAILED; +} + +/** + * wlan_hdd_get_sap_stats() - get aggregate SAP stats + * @link_info: Link info pointer in HDD adapter + * @info: kernel station_info struct to populate + * + * Fetch the vdev-level aggregate stats for the given SAP adapter. This is to + * support "station dump" and "station get" for SAP vdevs, even though they + * aren't technically stations. + * + * Return: errno + */ +static int wlan_hdd_get_sap_stats(struct wlan_hdd_link_info *link_info, + struct station_info *info) +{ + int ret; + + ret = wlan_hdd_get_station_stats(link_info); + if (ret) { + hdd_err("Failed to get SAP stats; status:%d", ret); + return ret; + } + + wlan_hdd_fill_summary_stats(&link_info->hdd_stats.summary_stat, + info, link_info->vdev_id); + + return 0; +} + +/** + * hdd_get_max_rate_legacy() - get max rate for legacy mode + * @stainfo: stainfo pointer + * @rssidx: rssi index + * + * This function will get max rate for legacy mode + * + * Return: max rate on success, otherwise 0 + */ +static uint32_t hdd_get_max_rate_legacy(struct hdd_station_info *stainfo, + uint8_t rssidx) +{ + uint32_t maxrate = 0; + /*Minimum max rate, 6Mbps*/ + int maxidx = 12; + int i; + + /* check supported rates */ + if (stainfo->max_supp_idx != 0xff && + maxidx < stainfo->max_supp_idx) + maxidx = stainfo->max_supp_idx; + + /* check extended rates */ + if (stainfo->max_ext_idx != 0xff && + maxidx < stainfo->max_ext_idx) + maxidx = stainfo->max_ext_idx; + + for (i = 0; i < QDF_ARRAY_SIZE(supported_data_rate); i++) { + if (supported_data_rate[i].beacon_rate_index == maxidx) + maxrate = + supported_data_rate[i].supported_rate[rssidx]; + } + + hdd_debug("maxrate %d", maxrate); + + return maxrate; +} + +/** + * hdd_get_max_rate_ht() - get max rate for ht mode + * @stainfo: stainfo pointer + * @stats: fw txrx status pointer + * @rate_flags: rate flags + * @nss: number of streams + * @maxrate: returned max rate buffer pointer + * @max_mcs_idx: max mcs idx + * @report_max: report max rate or actual rate + * + * This function will get max rate for ht mode + * + * Return: None + */ +static void hdd_get_max_rate_ht(struct hdd_station_info *stainfo, + struct hdd_fw_txrx_stats *stats, + uint32_t rate_flags, + uint8_t nss, + uint32_t *maxrate, + uint8_t *max_mcs_idx, + bool report_max) +{ + struct index_data_rate_type *supported_mcs_rate; + uint32_t tmprate; + uint8_t flag = 0, mcsidx; + int8_t rssi = stats->rssi; + int mode; + int i; + + if (rate_flags & TX_RATE_HT40) + mode = 1; + else + mode = 0; + + if (rate_flags & TX_RATE_HT40) + flag |= 1; + if (rate_flags & TX_RATE_SGI) + flag |= 2; + + supported_mcs_rate = (struct index_data_rate_type *) + ((nss == 1) ? &supported_mcs_rate_nss1 : + &supported_mcs_rate_nss2); + + if (stainfo->max_mcs_idx == 0xff) { + hdd_err("invalid max_mcs_idx"); + /* report real mcs idx */ + mcsidx = stats->tx_rate.mcs; + } else { + mcsidx = stainfo->max_mcs_idx; + } + + if (!report_max) { + for (i = 0; i < MAX_HT_MCS_INDEX && i < mcsidx; i++) { + if (rssi <= rssi_mcs_tbl[mode][i]) { + mcsidx = i; + break; + } + } + if (mcsidx < stats->tx_rate.mcs && + stats->tx_rate.mcs <= MAX_HT_MCS_INDEX) + mcsidx = stats->tx_rate.mcs; + } + + if (mcsidx > MAX_HT_MCS_INDEX) + mcsidx = MAX_HT_MCS_INDEX; + tmprate = supported_mcs_rate[mcsidx].supported_rate[flag]; + + hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx); + + *maxrate = tmprate; + *max_mcs_idx = mcsidx; +} + +/** + * hdd_get_max_rate_vht() - get max rate for vht mode + * @stainfo: stainfo pointer + * @stats: fw txrx status pointer + * @rate_flags: rate flags + * @nss: number of streams + * @maxrate: returned max rate buffer pointer + * @max_mcs_idx: max mcs idx + * @report_max: report max rate or actual rate + * + * This function will get max rate for vht mode + * + * Return: None + */ +static void hdd_get_max_rate_vht(struct hdd_station_info *stainfo, + struct hdd_fw_txrx_stats *stats, + uint32_t rate_flags, + uint8_t nss, + uint32_t *maxrate, + uint8_t *max_mcs_idx, + bool report_max) +{ + struct index_vht_data_rate_type *supported_vht_mcs_rate; + uint32_t tmprate = 0; + uint32_t vht_max_mcs; + uint8_t flag = 0, mcsidx = INVALID_MCS_IDX; + int8_t rssi = stats->rssi; + int mode; + int i; + + supported_vht_mcs_rate = (struct index_vht_data_rate_type *) + ((nss == 1) ? + &supported_vht_mcs_rate_nss1 : + &supported_vht_mcs_rate_nss2); + + if (rate_flags & TX_RATE_VHT80) + mode = 2; + else if (rate_flags & TX_RATE_VHT40) + mode = 1; + else + mode = 0; + + if (rate_flags & + (TX_RATE_VHT20 | TX_RATE_VHT40 | TX_RATE_VHT80)) { + vht_max_mcs = + (enum data_rate_11ac_max_mcs) + (stainfo->tx_mcs_map & DATA_RATE_11AC_MCS_MASK); + if (rate_flags & TX_RATE_SGI) + flag |= 1; + + if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_7) { + mcsidx = 7; + } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_8) { + mcsidx = 8; + } else if (vht_max_mcs == DATA_RATE_11AC_MAX_MCS_9) { + /* + * 'IEEE_P802.11ac_2013.pdf' page 325, 326 + * - MCS9 is valid for VHT20 when Nss = 3 or Nss = 6 + * - MCS9 is not valid for VHT20 when Nss = 1,2,4,5,7,8 + */ + if ((rate_flags & TX_RATE_VHT20) && + (nss != 3 && nss != 6)) + mcsidx = 8; + else + mcsidx = 9; + } else { + hdd_err("invalid vht_max_mcs"); + /* report real mcs idx */ + mcsidx = stats->tx_rate.mcs; + } + + if (!report_max) { + for (i = 0; i <= mcsidx && i < MAX_RSSI_MCS_INDEX; i++) { + if (rssi <= rssi_mcs_tbl[mode][i]) { + mcsidx = i; + break; + } + } + if (mcsidx < stats->tx_rate.mcs) + mcsidx = stats->tx_rate.mcs; + } + + if (rate_flags & TX_RATE_VHT80) + tmprate = + supported_vht_mcs_rate[mcsidx].supported_VHT80_rate[flag]; + else if (rate_flags & TX_RATE_VHT40) + tmprate = + supported_vht_mcs_rate[mcsidx].supported_VHT40_rate[flag]; + else if (rate_flags & TX_RATE_VHT20) + tmprate = + supported_vht_mcs_rate[mcsidx].supported_VHT20_rate[flag]; + } + + hdd_debug("tmprate %d mcsidx %d", tmprate, mcsidx); + + *maxrate = tmprate; + *max_mcs_idx = mcsidx; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +static bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info, + enum tx_rate_info rate_flags, + uint8_t mcsidx, + uint8_t nss, + uint8_t rate_info_flag) +{ + if (rate_info_flag == RATE_INFO_FLAGS_EHT_MCS) { + rate_info->nss = nss; + rate_info->mcs = mcsidx; + rate_info->flags |= RATE_INFO_FLAGS_EHT_MCS; + if (rate_flags & TX_RATE_EHT320) + rate_info->bw = RATE_INFO_BW_320; + else if (rate_flags & TX_RATE_EHT160) + rate_info->bw = RATE_INFO_BW_160; + else if (rate_flags & TX_RATE_EHT80) + rate_info->bw = RATE_INFO_BW_80; + else if (rate_flags & TX_RATE_EHT40) + rate_info->bw = RATE_INFO_BW_40; + else if (rate_flags & TX_RATE_EHT20) + rate_info->bw = RATE_INFO_BW_20; + + return true; + } + + return false; +} +#else +static inline bool hdd_fill_eht_bw_mcs(struct rate_info *rate_info, + enum tx_rate_info rate_flags, + uint8_t mcsidx, + uint8_t nss, + uint8_t rate_info_flag) +{ + return false; +} +#endif +/** + * hdd_fill_bw_mcs() - fill ch width and mcs flags + * @rate_info: pointer to struct rate_info + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * @rate_info_flag: rate info flags + * + * This function will fill ch width and mcs flags + * + * Return: None + */ +static void hdd_fill_bw_mcs(struct rate_info *rate_info, + enum tx_rate_info rate_flags, + uint8_t mcsidx, + uint8_t nss, + uint8_t rate_info_flag) +{ + if (hdd_fill_eht_bw_mcs(rate_info, rate_flags, mcsidx, nss, + rate_info_flag)) + return; + + if (rate_info_flag == RATE_INFO_FLAGS_HE_MCS) { + rate_info->nss = nss; + rate_info->mcs = mcsidx; + rate_info->flags |= RATE_INFO_FLAGS_HE_MCS; + if (rate_flags & TX_RATE_HE160) + rate_info->bw = RATE_INFO_BW_160; + else if (rate_flags & TX_RATE_HE80) + rate_info->bw = RATE_INFO_BW_80; + else if (rate_flags & TX_RATE_HE40) + rate_info->bw = RATE_INFO_BW_40; + else if (rate_flags & TX_RATE_HE20) + rate_info->bw = RATE_INFO_BW_20; + } else if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) { + rate_info->nss = nss; + rate_info->mcs = mcsidx; + rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & TX_RATE_VHT160) + rate_info->bw = RATE_INFO_BW_160; + else if (rate_flags & TX_RATE_VHT80) + rate_info->bw = RATE_INFO_BW_80; + else if (rate_flags & TX_RATE_VHT40) + rate_info->bw = RATE_INFO_BW_40; + else if (rate_flags & TX_RATE_VHT20) + rate_info->bw = RATE_INFO_BW_20; + } else { + rate_info->mcs = (nss - 1) << 3; + rate_info->mcs |= mcsidx; + rate_info->flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & TX_RATE_HT40) + rate_info->bw = RATE_INFO_BW_40; + } +} +#else +/** + * hdd_fill_bw_mcs() - fill ch width and mcs flags + * @rate_info: pointer to struct rate_info + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * @rate_info_flag: rate info flags + * + * This function will fill ch width and mcs flags + * + * Return: None + */ +static void hdd_fill_bw_mcs(struct rate_info *rate_info, + enum tx_rate_info rate_flags, + uint8_t mcsidx, + uint8_t nss, + uint8_t rate_info_flag) +{ + if (rate_info_flag == RATE_INFO_FLAGS_VHT_MCS) { + rate_info->nss = nss; + rate_info->mcs = mcsidx; + rate_info->flags |= RATE_INFO_FLAGS_VHT_MCS; + if (rate_flags & TX_RATE_VHT80) + rate_info->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH; + else if (rate_flags & TX_RATE_VHT40) + rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + else if (rate_flags & TX_RATE_VHT20) + rate_info->bw = RATE_INFO_BW_20; + } else { + rate_info->mcs = (nss - 1) << 3; + rate_info->mcs |= mcsidx; + rate_info->flags |= RATE_INFO_FLAGS_MCS; + if (rate_flags & TX_RATE_HT40) + rate_info->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + } +} +#endif + +#if defined(WLAN_FEATURE_11BE) && defined(CFG80211_11BE_BASIC) +static void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info, + uint32_t rate_flags, uint8_t mcsidx, + uint8_t nss) +{ + if (rate_flags & + (TX_RATE_EHT320 | + TX_RATE_EHT160 | + TX_RATE_EHT80 | + TX_RATE_EHT40 | + TX_RATE_EHT20)) { + hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss, + RATE_INFO_FLAGS_EHT_MCS); + } +} +#else +static inline void hdd_fill_sinfo_eht_rate_info(struct rate_info *rate_info, + uint32_t rate_flags, + uint8_t mcsidx, + uint8_t nss) +{ +} +#endif + +/** + * hdd_fill_sinfo_rate_info() - fill rate info of sinfo struct + * @sinfo: pointer to struct station_info + * @rate_flags: HDD rate flags + * @mcsidx: mcs index + * @nss: number of streams + * @rate: data rate (kbps) + * @is_tx: flag to indicate whether it is tx or rx + * + * This function will fill rate info of sinfo struct + * + * Return: None + */ +static void hdd_fill_sinfo_rate_info(struct station_info *sinfo, + uint32_t rate_flags, + uint8_t mcsidx, + uint8_t nss, + uint32_t rate, + bool is_tx) +{ + struct rate_info *rate_info; + + if (is_tx) + rate_info = &sinfo->txrate; + else + rate_info = &sinfo->rxrate; + + if (rate_flags & TX_RATE_LEGACY) { + /* provide to the UI in units of 100kbps */ + rate_info->legacy = rate; + } else { + /* must be MCS */ + hdd_fill_sinfo_eht_rate_info(rate_info, rate_flags, mcsidx, + nss); + + if (rate_flags & + (TX_RATE_HE160 | + TX_RATE_HE80 | + TX_RATE_HE40 | + TX_RATE_HE20)) { + hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss, + RATE_INFO_FLAGS_HE_MCS); + } + if (rate_flags & + (TX_RATE_VHT160 | + TX_RATE_VHT80 | + TX_RATE_VHT40 | + TX_RATE_VHT20)) { + hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss, + RATE_INFO_FLAGS_VHT_MCS); + } + if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) { + hdd_fill_bw_mcs(rate_info, rate_flags, mcsidx, nss, + RATE_INFO_FLAGS_MCS); + } + if (rate_flags & TX_RATE_SGI) { + if (!(rate_info->flags & RATE_INFO_FLAGS_VHT_MCS)) + rate_info->flags |= RATE_INFO_FLAGS_MCS; + rate_info->flags |= RATE_INFO_FLAGS_SHORT_GI; + } + } + + hdd_debug("flag %x mcs %d legacy %d nss %d", + rate_info->flags, + rate_info->mcs, + rate_info->legacy, + rate_info->nss); + + if (is_tx) + sinfo->filled |= HDD_INFO_TX_BITRATE; + else + sinfo->filled |= HDD_INFO_RX_BITRATE; +} + +/** + * hdd_fill_sta_flags() - fill sta flags of sinfo + * @sinfo: station_info struct pointer + * @stainfo: stainfo pointer + * + * This function will fill sta flags of sinfo + * + * Return: None + */ +static void hdd_fill_sta_flags(struct station_info *sinfo, + struct hdd_station_info *stainfo) +{ + sinfo->sta_flags.mask = NL80211_STA_FLAG_WME; + + if (stainfo->is_qos_enabled) + sinfo->sta_flags.set |= NL80211_STA_FLAG_WME; + else + sinfo->sta_flags.set &= ~NL80211_STA_FLAG_WME; + + sinfo->filled |= HDD_INFO_STA_FLAGS; +} + +/** + * hdd_fill_per_chain_avg_signal() - fill per chain avg rssi of sinfo + * @sinfo: station_info struct pointer + * @stainfo: stainfo pointer + * + * This function will fill per chain avg rssi of sinfo + * + * Return: None + */ +static void hdd_fill_per_chain_avg_signal(struct station_info *sinfo, + struct hdd_station_info *stainfo) +{ + bool rssi_stats_valid = false; + uint8_t i; + + sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM; + for (i = 0; i < IEEE80211_MAX_CHAINS; i++) { + sinfo->chain_signal_avg[i] = stainfo->peer_rssi_per_chain[i]; + sinfo->chains |= 1 << i; + if (sinfo->chain_signal_avg[i] > sinfo->signal_avg && + sinfo->chain_signal_avg[i] != 0) + sinfo->signal_avg = sinfo->chain_signal_avg[i]; + + if (sinfo->chain_signal_avg[i]) + rssi_stats_valid = true; + } + + if (rssi_stats_valid) { + sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG; + sinfo->filled |= HDD_INFO_SIGNAL_AVG; + } +} + +/** + * hdd_fill_rate_info() - fill rate info of sinfo + * @psoc: psoc context + * @sinfo: station_info struct pointer + * @stainfo: stainfo pointer + * @stats: fw txrx status pointer + * + * This function will fill rate info of sinfo + * + * Return: None + */ +static void hdd_fill_rate_info(struct wlan_objmgr_psoc *psoc, + struct station_info *sinfo, + struct hdd_station_info *stainfo, + struct hdd_fw_txrx_stats *stats) +{ + enum tx_rate_info rate_flags; + uint8_t mcsidx = 0xff; + uint32_t tx_rate, rx_rate, maxrate, tmprate; + int rssidx; + int nss = 1; + int link_speed_rssi_high = 0; + int link_speed_rssi_mid = 0; + int link_speed_rssi_low = 0; + uint32_t link_speed_rssi_report = 0; + + ucfg_mlme_stats_get_cfg_values(psoc, + &link_speed_rssi_high, + &link_speed_rssi_mid, + &link_speed_rssi_low, + &link_speed_rssi_report); + + hdd_debug("reportMaxLinkSpeed %d", link_speed_rssi_report); + + /* convert to 100kbps expected in rate table */ + tx_rate = stats->tx_rate.rate / 100; + rate_flags = stainfo->rate_flags; + if (!(rate_flags & TX_RATE_LEGACY)) { + nss = stainfo->nss; + if (ucfg_mlme_stats_is_link_speed_report_actual(psoc)) { + /* Get current rate flags if report actual */ + if (stats->tx_rate.rate_flags) + rate_flags = + stats->tx_rate.rate_flags; + nss = stats->tx_rate.nss; + } + + if (stats->tx_rate.mcs == INVALID_MCS_IDX) + rate_flags = TX_RATE_LEGACY; + } + + if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) { + /* we do not want to necessarily report the current speed */ + if (ucfg_mlme_stats_is_link_speed_report_max(psoc)) { + /* report the max possible speed */ + rssidx = 0; + } else if (ucfg_mlme_stats_is_link_speed_report_max_scaled( + psoc)) { + /* report the max possible speed with RSSI scaling */ + if (stats->rssi >= link_speed_rssi_high) { + /* report the max possible speed */ + rssidx = 0; + } else if (stats->rssi >= link_speed_rssi_mid) { + /* report middle speed */ + rssidx = 1; + } else if (stats->rssi >= link_speed_rssi_low) { + /* report low speed */ + rssidx = 2; + } else { + /* report actual speed */ + rssidx = 3; + } + } else { + /* unknown, treat as eHDD_LINK_SPEED_REPORT_MAX */ + hdd_err("Invalid value for reportMaxLinkSpeed: %u", + link_speed_rssi_report); + rssidx = 0; + } + + maxrate = hdd_get_max_rate_legacy(stainfo, rssidx); + + /* + * Get MCS Rate Set -- + * Only if we are connected in non legacy mode and not + * reporting actual speed + */ + if ((rssidx != 3) && + !(rate_flags & TX_RATE_LEGACY)) { + hdd_get_max_rate_vht(stainfo, + stats, + rate_flags, + nss, + &tmprate, + &mcsidx, + rssidx == 0); + + if (maxrate < tmprate && + mcsidx != INVALID_MCS_IDX) + maxrate = tmprate; + + if (mcsidx == INVALID_MCS_IDX) + hdd_get_max_rate_ht(stainfo, + stats, + rate_flags, + nss, + &tmprate, + &mcsidx, + rssidx == 0); + + if (maxrate < tmprate && + mcsidx != INVALID_MCS_IDX) + maxrate = tmprate; + } else if (!(rate_flags & TX_RATE_LEGACY)) { + maxrate = tx_rate; + mcsidx = stats->tx_rate.mcs; + } + + /* + * make sure we report a value at least as big as our + * current rate + */ + if (maxrate < tx_rate || maxrate == 0) { + maxrate = tx_rate; + if (!(rate_flags & TX_RATE_LEGACY)) { + mcsidx = stats->tx_rate.mcs; + /* + * 'IEEE_P802.11ac_2013.pdf' page 325, 326 + * - MCS9 is valid for VHT20 when Nss = 3 or + * Nss = 6 + * - MCS9 is not valid for VHT20 when + * Nss = 1,2,4,5,7,8 + */ + if ((rate_flags & TX_RATE_VHT20) && + (mcsidx > 8) && + (nss != 3 && nss != 6)) + mcsidx = 8; + } + } + } else { + /* report current rate instead of max rate */ + maxrate = tx_rate; + if (!(rate_flags & TX_RATE_LEGACY)) + mcsidx = stats->tx_rate.mcs; + } + + hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss, + maxrate, true); + + /* convert to 100kbps expected in rate table */ + rx_rate = stats->rx_rate.rate / 100; + + /* report current rx rate*/ + rate_flags = stainfo->rate_flags; + if (!(rate_flags & TX_RATE_LEGACY)) { + if (stats->rx_rate.rate_flags) + rate_flags = stats->rx_rate.rate_flags; + nss = stats->rx_rate.nss; + if (stats->rx_rate.mcs == INVALID_MCS_IDX) + rate_flags = TX_RATE_LEGACY; + } + if (!(rate_flags & TX_RATE_LEGACY)) + mcsidx = stats->rx_rate.mcs; + + hdd_fill_sinfo_rate_info(sinfo, rate_flags, mcsidx, nss, + rx_rate, false); + + sinfo->expected_throughput = stainfo->max_phy_rate; + sinfo->filled |= HDD_INFO_EXPECTED_THROUGHPUT; +} + +/** + * wlan_hdd_fill_station_info() - fill station_info struct + * @psoc: psoc context + * @adapter: The HDD adapter structure + * @sinfo: station_info struct pointer + * @stainfo: stainfo pointer + * @stats: fw txrx status pointer + * + * This function will fill station_info struct + * + * Return: None + */ +static void wlan_hdd_fill_station_info(struct wlan_objmgr_psoc *psoc, + struct hdd_adapter *adapter, + struct station_info *sinfo, + struct hdd_station_info *stainfo, + struct hdd_fw_txrx_stats *stats) +{ + qdf_time_t curr_time, dur; + struct cdp_peer_stats *peer_stats; + QDF_STATUS status; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) + return; + + status = + cdp_host_get_peer_stats(cds_get_context(QDF_MODULE_ID_SOC), + adapter->deflink->vdev_id, + stainfo->sta_mac.bytes, + peer_stats); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("cdp_host_get_peer_stats failed. error: %u", status); + qdf_mem_free(peer_stats); + return; + } + + stainfo->last_tx_rx_ts = + peer_stats->tx.last_tx_ts > peer_stats->rx.last_rx_ts ? + peer_stats->tx.last_tx_ts : peer_stats->rx.last_rx_ts; + + qdf_mem_free(peer_stats); + + curr_time = qdf_system_ticks(); + dur = curr_time - stainfo->assoc_ts; + sinfo->connected_time = qdf_system_ticks_to_msecs(dur) / 1000; + sinfo->filled |= HDD_INFO_CONNECTED_TIME; + dur = curr_time - stainfo->last_tx_rx_ts; + sinfo->inactive_time = qdf_system_ticks_to_msecs(dur); + sinfo->filled |= HDD_INFO_INACTIVE_TIME; + sinfo->signal = stats->rssi; + sinfo->filled |= HDD_INFO_SIGNAL; + sinfo->tx_bytes = stats->tx_bytes; + sinfo->filled |= HDD_INFO_TX_BYTES | HDD_INFO_TX_BYTES64; + sinfo->tx_packets = stats->tx_packets; + sinfo->filled |= HDD_INFO_TX_PACKETS; + sinfo->rx_bytes = stats->rx_bytes; + sinfo->filled |= HDD_INFO_RX_BYTES | HDD_INFO_RX_BYTES64; + sinfo->rx_packets = stats->rx_packets; + sinfo->filled |= HDD_INFO_RX_PACKETS; + sinfo->tx_failed = stats->tx_failed; + sinfo->filled |= HDD_INFO_TX_FAILED; + sinfo->tx_retries = stats->tx_retries; + + /* sta flags */ + hdd_fill_sta_flags(sinfo, stainfo); + + /* per chain avg rssi */ + hdd_fill_per_chain_avg_signal(sinfo, stainfo); + + /* tx / rx rate info */ + hdd_fill_rate_info(psoc, sinfo, stainfo, stats); + + /* assoc req ies */ + sinfo->assoc_req_ies = stainfo->assoc_req_ies.ptr; + sinfo->assoc_req_ies_len = stainfo->assoc_req_ies.len; + + /* dump sta info*/ + hdd_debug("dump stainfo"); + hdd_debug("con_time %d inact_time %d tx_pkts %d rx_pkts %d", + sinfo->connected_time, sinfo->inactive_time, + sinfo->tx_packets, sinfo->rx_packets); + hdd_debug("failed %d retries %d tx_bytes %lld rx_bytes %lld", + sinfo->tx_failed, sinfo->tx_retries, + sinfo->tx_bytes, sinfo->rx_bytes); + hdd_debug("rssi %d tx mcs %d legacy %d nss %d flags %x", + sinfo->signal, sinfo->txrate.mcs, + sinfo->txrate.legacy, sinfo->txrate.nss, + sinfo->txrate.flags); + hdd_debug("rx mcs %d legacy %d nss %d flags %x", + sinfo->rxrate.mcs, sinfo->rxrate.legacy, + sinfo->rxrate.nss, sinfo->rxrate.flags); +} + +/** + * hdd_get_rate_flags_ht() - get HT rate flags based on rate, nss and mcs + * @rate: Data rate (100 kbps) + * @nss: Number of streams + * @mcs: HT mcs index + * + * This function is used to construct HT rate flag with rate, nss and mcs + * + * Return: rate flags for success, 0 on failure. + */ +static uint8_t hdd_get_rate_flags_ht(uint32_t rate, + uint8_t nss, + uint8_t mcs) +{ + struct index_data_rate_type *mcs_rate; + uint8_t flags = 0; + + mcs_rate = (struct index_data_rate_type *) + ((nss == 1) ? &supported_mcs_rate_nss1 : + &supported_mcs_rate_nss2); + + if (rate == mcs_rate[mcs].supported_rate[0]) { + flags |= TX_RATE_HT20; + } else if (rate == mcs_rate[mcs].supported_rate[1]) { + flags |= TX_RATE_HT40; + } else if (rate == mcs_rate[mcs].supported_rate[2]) { + flags |= TX_RATE_HT20; + flags |= TX_RATE_SGI; + } else if (rate == mcs_rate[mcs].supported_rate[3]) { + flags |= TX_RATE_HT40; + flags |= TX_RATE_SGI; + } else { + hdd_err("invalid params rate %d nss %d mcs %d", + rate, nss, mcs); + } + + return flags; +} + +/** + * hdd_get_rate_flags_vht() - get VHT rate flags based on rate, nss and mcs + * @rate: Data rate (100 kbps) + * @nss: Number of streams + * @mcs: VHT mcs index + * + * This function is used to construct VHT rate flag with rate, nss and mcs + * + * Return: rate flags for success, 0 on failure. + */ +static uint8_t hdd_get_rate_flags_vht(uint32_t rate, + uint8_t nss, + uint8_t mcs) +{ + struct index_vht_data_rate_type *mcs_rate; + uint8_t flags = 0; + + if (mcs >= ARRAY_SIZE(supported_vht_mcs_rate_nss1)) { + hdd_err("Invalid mcs index %d", mcs); + return flags; + } + + mcs_rate = (struct index_vht_data_rate_type *) + ((nss == 1) ? + &supported_vht_mcs_rate_nss1 : + &supported_vht_mcs_rate_nss2); + + if (rate == mcs_rate[mcs].supported_VHT80_rate[0]) { + flags |= TX_RATE_VHT80; + } else if (rate == mcs_rate[mcs].supported_VHT80_rate[1]) { + flags |= TX_RATE_VHT80; + flags |= TX_RATE_SGI; + } else if (rate == mcs_rate[mcs].supported_VHT40_rate[0]) { + flags |= TX_RATE_VHT40; + } else if (rate == mcs_rate[mcs].supported_VHT40_rate[1]) { + flags |= TX_RATE_VHT40; + flags |= TX_RATE_SGI; + } else if (rate == mcs_rate[mcs].supported_VHT20_rate[0]) { + flags |= TX_RATE_VHT20; + } else if (rate == mcs_rate[mcs].supported_VHT20_rate[1]) { + flags |= TX_RATE_VHT20; + flags |= TX_RATE_SGI; + } else { + hdd_err("invalid params rate %d nss %d mcs %d", + rate, nss, mcs); + } + + return flags; +} + +/** + * hdd_get_rate_flags() - get HT/VHT rate flags based on rate, nss and mcs + * @rate: Data rate (100 kbps) + * @mode: Tx/Rx mode + * @nss: Number of streams + * @mcs: Mcs index + * + * This function is used to construct rate flag with rate, nss and mcs + * + * Return: rate flags for success, 0 on failure. + */ +static uint8_t hdd_get_rate_flags(uint32_t rate, + uint8_t mode, + uint8_t nss, + uint8_t mcs) +{ + uint8_t flags = 0; + + if (mode == SIR_SME_PHY_MODE_HT) + flags = hdd_get_rate_flags_ht(rate, nss, mcs); + else if (mode == SIR_SME_PHY_MODE_VHT) + flags = hdd_get_rate_flags_vht(rate, nss, mcs); + else + hdd_debug("invalid mode param %d", mode); + + return flags; +} + +/** + * wlan_hdd_fill_rate_info() - fill HDD rate info from peer info + * @txrx_stats: pointer to txrx stats to be filled with rate info + * @peer_info: peer info pointer + * + * This function is used to fill HDD rate info from peer info + * + * Return: None + */ +static void wlan_hdd_fill_rate_info(struct hdd_fw_txrx_stats *txrx_stats, + struct peer_stats_info_ext_event *peer_info) +{ + uint8_t flags; + uint32_t rate_code; + + /* tx rate info */ + txrx_stats->tx_rate.rate = peer_info->tx_rate; + rate_code = peer_info->tx_rate_code; + + if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) == + WMI_RATE_PREAMBLE_HT) + txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_HT; + else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) == + WMI_RATE_PREAMBLE_VHT) + txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_VHT; + else + txrx_stats->tx_rate.mode = SIR_SME_PHY_MODE_LEGACY; + + txrx_stats->tx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1; + txrx_stats->tx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code); + + flags = hdd_get_rate_flags(txrx_stats->tx_rate.rate / 100, + txrx_stats->tx_rate.mode, + txrx_stats->tx_rate.nss, + txrx_stats->tx_rate.mcs); + + txrx_stats->tx_rate.rate_flags = flags; + + hdd_debug("tx: mode %d nss %d mcs %d rate_flags %x flags %x", + txrx_stats->tx_rate.mode, + txrx_stats->tx_rate.nss, + txrx_stats->tx_rate.mcs, + txrx_stats->tx_rate.rate_flags, + flags); + + /* rx rate info */ + txrx_stats->rx_rate.rate = peer_info->rx_rate; + rate_code = peer_info->rx_rate_code; + + if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) == + WMI_RATE_PREAMBLE_HT) + txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_HT; + else if ((WMI_GET_HW_RATECODE_PREAM_V1(rate_code)) == + WMI_RATE_PREAMBLE_VHT) + txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_VHT; + else + txrx_stats->rx_rate.mode = SIR_SME_PHY_MODE_LEGACY; + + txrx_stats->rx_rate.nss = WMI_GET_HW_RATECODE_NSS_V1(rate_code) + 1; + txrx_stats->rx_rate.mcs = WMI_GET_HW_RATECODE_RATE_V1(rate_code); + + flags = hdd_get_rate_flags(txrx_stats->rx_rate.rate / 100, + txrx_stats->rx_rate.mode, + txrx_stats->rx_rate.nss, + txrx_stats->rx_rate.mcs); + + txrx_stats->rx_rate.rate_flags = flags; + + hdd_info("rx: mode %d nss %d mcs %d rate_flags %x flags %x", + txrx_stats->rx_rate.mode, + txrx_stats->rx_rate.nss, + txrx_stats->rx_rate.mcs, + txrx_stats->rx_rate.rate_flags, + flags); +} + +/** + * wlan_hdd_get_station_remote() - NL80211_CMD_GET_STATION handler for SoftAP + * @wiphy: pointer to wiphy + * @dev: pointer to net_device structure + * @stainfo: request peer station info + * @sinfo: pointer to station_info struct + * + * This function will get remote peer info from fw and fill sinfo struct + * + * Return: 0 on success, otherwise error value + */ +static int wlan_hdd_get_station_remote(struct wiphy *wiphy, + struct net_device *dev, + struct hdd_station_info *stainfo, + struct station_info *sinfo) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hddctx = wiphy_priv(wiphy); + struct stats_event *stats; + struct hdd_fw_txrx_stats txrx_stats; + int i, status; + + stats = wlan_cfg80211_mc_cp_stats_get_peer_stats(adapter->deflink->vdev, + stainfo->sta_mac.bytes, + &status); + if (status || !stats) { + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + hdd_err("fail to get peer info from fw"); + return -EPERM; + } + + for (i = 0; i < WMI_MAX_CHAINS; i++) + stainfo->peer_rssi_per_chain[i] = + stats->peer_stats_info_ext->peer_rssi_per_chain[i]; + + qdf_mem_zero(&txrx_stats, sizeof(txrx_stats)); + txrx_stats.tx_packets = stats->peer_stats_info_ext->tx_packets; + txrx_stats.tx_bytes = stats->peer_stats_info_ext->tx_bytes; + txrx_stats.rx_packets = stats->peer_stats_info_ext->rx_packets; + txrx_stats.rx_bytes = stats->peer_stats_info_ext->rx_bytes; + txrx_stats.tx_retries = stats->peer_stats_info_ext->tx_retries; + txrx_stats.tx_failed = stats->peer_stats_info_ext->tx_failed; + txrx_stats.tx_succeed = stats->peer_stats_info_ext->tx_succeed; + txrx_stats.rssi = stats->peer_stats_info_ext->rssi; + wlan_hdd_fill_rate_info(&txrx_stats, stats->peer_stats_info_ext); + wlan_hdd_fill_station_info(hddctx->psoc, adapter, + sinfo, stainfo, &txrx_stats); + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + + return status; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ + defined(WLAN_FEATURE_11AX) +/** + * hdd_map_he_gi_to_os() - map txrate_gi to os guard interval + * @guard_interval: guard interval get from fw rate + * + * Return: os guard interval value + */ +static inline uint8_t hdd_map_he_gi_to_os(enum txrate_gi guard_interval) +{ + switch (guard_interval) { + case TXRATE_GI_0_8_US: + return NL80211_RATE_INFO_HE_GI_0_8; + case TXRATE_GI_1_6_US: + return NL80211_RATE_INFO_HE_GI_1_6; + case TXRATE_GI_3_2_US: + return NL80211_RATE_INFO_HE_GI_3_2; + default: + return NL80211_RATE_INFO_HE_GI_0_8; + } +} + +/** + * wlan_hdd_fill_os_he_rateflags() - Fill HE related rate_info + * @os_rate: rate info for os + * @rate_flags: rate flags + * @dcm: dcm from rate + * @guard_interval: guard interval from rate + * + * Return: none + */ +static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate, + enum tx_rate_info rate_flags, + uint8_t dcm, + enum txrate_gi guard_interval) +{ + /* as fw not yet report ofdma to host, so we doesn't + * fill RATE_INFO_BW_HE_RU. + */ + if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 | + TX_RATE_HE20 | TX_RATE_HE160)) { + if (rate_flags & TX_RATE_HE160) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_160); + else if (rate_flags & TX_RATE_HE80) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_80); + else if (rate_flags & TX_RATE_HE40) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_40); + + os_rate->flags |= RATE_INFO_FLAGS_HE_MCS; + + os_rate->he_gi = hdd_map_he_gi_to_os(guard_interval); + os_rate->he_dcm = dcm; + } +} +#else +static void wlan_hdd_fill_os_he_rateflags(struct rate_info *os_rate, + enum tx_rate_info rate_flags, + uint8_t dcm, + enum txrate_gi guard_interval) +{} +#endif + +/** + * wlan_hdd_fill_os_rate_info() - Fill os related rate_info + * @rate_flags: rate flags + * @legacy_rate: 802.11abg rate + * @os_rate: rate info for os + * @mcs_index: mcs + * @nss: number of spatial streams + * @dcm: dcm from rate + * @guard_interval: guard interval from rate + * + * Return: none + */ +static void wlan_hdd_fill_os_rate_info(enum tx_rate_info rate_flags, + uint16_t legacy_rate, + struct rate_info *os_rate, + uint8_t mcs_index, uint8_t nss, + uint8_t dcm, + enum txrate_gi guard_interval) +{ + os_rate->nss = nss; + if (rate_flags & TX_RATE_LEGACY) { + os_rate->legacy = legacy_rate; + hdd_debug("Reporting legacy rate %d", os_rate->legacy); + return; + } + + /* assume basic BW. anything else will override this later */ + hdd_set_rate_bw(os_rate, HDD_RATE_BW_20); + os_rate->mcs = mcs_index; + + wlan_hdd_fill_os_eht_rateflags(os_rate, rate_flags, dcm, + guard_interval); + wlan_hdd_fill_os_he_rateflags(os_rate, rate_flags, dcm, guard_interval); + + if (rate_flags & (TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 | + TX_RATE_VHT20)) { + if (rate_flags & TX_RATE_VHT160) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_160); + else if (rate_flags & TX_RATE_VHT80) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_80); + else if (rate_flags & TX_RATE_VHT40) + hdd_set_rate_bw(os_rate, HDD_RATE_BW_40); + os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS; + } + + if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) { + if (rate_flags & TX_RATE_HT40) + hdd_set_rate_bw(os_rate, + HDD_RATE_BW_40); + os_rate->flags |= RATE_INFO_FLAGS_MCS; + } + + if (rate_flags & TX_RATE_SGI) + os_rate->flags |= RATE_INFO_FLAGS_SHORT_GI; +} + +void hdd_get_max_tx_bitrate(struct wlan_hdd_link_info *link_info) +{ + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + struct station_info sinfo; + enum tx_rate_info tx_rate_flags; + uint8_t tx_mcs_index, tx_nss = 1; + uint16_t my_tx_rate; + struct hdd_station_ctx *hdd_sta_ctx; + struct wlan_objmgr_vdev *vdev; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + qdf_mem_zero(&sinfo, sizeof(struct station_info)); + + sinfo.signal = link_info->rssi; + tx_mcs_index = link_info->hdd_stats.class_a_stat.tx_mcs_index; + my_tx_rate = link_info->hdd_stats.class_a_stat.tx_rate; + tx_rate_flags = link_info->hdd_stats.class_a_stat.tx_rx_rate_flags; + + if (!(tx_rate_flags & TX_RATE_LEGACY)) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_STATS_ID); + if (vdev) { + /* + * Take static NSS for reporting max rates. + * NSS from FW is not reliable as it changes + * as per the environment quality. + */ + tx_nss = wlan_vdev_mlme_get_nss(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + } else { + tx_nss = link_info->hdd_stats.class_a_stat.tx_nss; + } + hdd_check_and_update_nss(hdd_ctx, &tx_nss, NULL); + + if (tx_mcs_index == INVALID_MCS_IDX) + tx_mcs_index = 0; + } + + if (hdd_report_max_rate(link_info, hdd_ctx->mac_handle, &sinfo.txrate, + sinfo.signal, tx_rate_flags, tx_mcs_index, + my_tx_rate, tx_nss)) { + hdd_sta_ctx->cache_conn_info.max_tx_bitrate = sinfo.txrate; + hdd_debug("Reporting max tx rate flags %d mcs %d nss %d bw %d", + sinfo.txrate.flags, sinfo.txrate.mcs, + sinfo.txrate.nss, sinfo.txrate.bw); + } +} + +bool hdd_report_max_rate(struct wlan_hdd_link_info *link_info, + mac_handle_t mac_handle, + struct rate_info *rate, + int8_t signal, + enum tx_rate_info rate_flags, + uint8_t mcs_index, + uint16_t fw_rate, uint8_t nss) +{ + uint8_t i, j, rssidx = 0; + uint16_t max_rate = 0; + uint32_t vht_mcs_map; + bool is_vht20_mcs9 = false; + uint16_t he_mcs_12_13_map = 0; + uint16_t current_rate = 0; + qdf_size_t or_leng; + uint8_t operational_rates[CSR_DOT11_SUPPORTED_RATES_MAX]; + uint8_t extended_rates[CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX]; + qdf_size_t er_leng; + uint8_t mcs_rates[SIZE_OF_BASIC_MCS_SET]; + qdf_size_t mcs_len; + struct index_data_rate_type *supported_mcs_rate; + enum data_rate_11ac_max_mcs vht_max_mcs; + uint8_t max_mcs_idx = 0; + uint8_t max_ht_mcs_idx; + uint8_t rate_flag = 1; + int mode = 0, max_ht_idx; + QDF_STATUS stat = QDF_STATUS_E_FAILURE; + struct hdd_context *hdd_ctx; + int link_speed_rssi_high = 0; + int link_speed_rssi_mid = 0; + int link_speed_rssi_low = 0; + uint32_t link_speed_rssi_report = 0; + struct wlan_objmgr_vdev *vdev; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return false; + + ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc, + &link_speed_rssi_high, + &link_speed_rssi_mid, + &link_speed_rssi_low, + &link_speed_rssi_report); + + if (ucfg_mlme_stats_is_link_speed_report_max_scaled(hdd_ctx->psoc)) { + /* report the max possible speed with RSSI scaling */ + if (signal >= link_speed_rssi_high) { + /* report the max possible speed */ + rssidx = 0; + } else if (signal >= link_speed_rssi_mid) { + /* report middle speed */ + rssidx = 1; + } else if (signal >= link_speed_rssi_low) { + /* report middle speed */ + rssidx = 2; + } else { + /* report actual speed */ + rssidx = 3; + } + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) { + hdd_err("failed to get vdev"); + return false; + } + + /* Get Basic Rate Set */ + or_leng = ucfg_mlme_get_opr_rate(vdev, operational_rates, + sizeof(operational_rates)); + for (i = 0; i < or_leng; i++) { + for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) { + /* Validate Rate Set */ + if (supported_data_rate[j].beacon_rate_index == + (operational_rates[i] & 0x7F)) { + current_rate = + supported_data_rate[j]. + supported_rate[rssidx]; + break; + } + } + /* Update MAX rate */ + max_rate = (current_rate > max_rate) ? current_rate : max_rate; + } + + /* Get Extended Rate Set */ + er_leng = ucfg_mlme_get_ext_opr_rate(vdev, extended_rates, + sizeof(extended_rates)); + he_mcs_12_13_map = wlan_vdev_mlme_get_he_mcs_12_13_map(vdev); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + for (i = 0; i < er_leng; i++) { + for (j = 0; j < ARRAY_SIZE(supported_data_rate); j++) { + if (supported_data_rate[j].beacon_rate_index == + (extended_rates[i] & 0x7F)) { + current_rate = supported_data_rate[j]. + supported_rate[rssidx]; + break; + } + } + /* Update MAX rate */ + max_rate = (current_rate > max_rate) ? current_rate : max_rate; + } + /* Get MCS Rate Set -- + * Only if we are connected in non legacy mode and not reporting + * actual speed + */ + if ((3 != rssidx) && !(rate_flags & TX_RATE_LEGACY)) { + rate_flag = 0; + if (rate_flags & (TX_RATE_VHT80 | TX_RATE_HE80 | + TX_RATE_HE160 | TX_RATE_VHT160 | + TX_RATE_EHT80 | TX_RATE_EHT160 | + TX_RATE_EHT320)) + mode = 2; + else if (rate_flags & (TX_RATE_HT40 | + TX_RATE_VHT40 | TX_RATE_HE40 | TX_RATE_EHT40)) + mode = 1; + else + mode = 0; + + if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 | + TX_RATE_VHT80 | TX_RATE_HE20 | TX_RATE_HE40 | + TX_RATE_HE80 | TX_RATE_HE160 | TX_RATE_VHT160 | + TX_RATE_EHT20 | TX_RATE_EHT40 | TX_RATE_EHT80 | + TX_RATE_EHT160 | TX_RATE_EHT320)) { + stat = ucfg_mlme_cfg_get_vht_tx_mcs_map(hdd_ctx->psoc, + &vht_mcs_map); + if (QDF_IS_STATUS_ERROR(stat)) + hdd_err("failed to get tx_mcs_map"); + + stat = ucfg_mlme_get_vht20_mcs9(hdd_ctx->psoc, + &is_vht20_mcs9); + if (QDF_IS_STATUS_ERROR(stat)) + hdd_err("Failed to get VHT20 MCS9 enable val"); + + vht_max_mcs = (enum data_rate_11ac_max_mcs) + (vht_mcs_map & DATA_RATE_11AC_MCS_MASK); + if (rate_flags & TX_RATE_SGI) + rate_flag |= 1; + + if (DATA_RATE_11AC_MAX_MCS_7 == vht_max_mcs) { + max_mcs_idx = 7; + } else if (DATA_RATE_11AC_MAX_MCS_8 == vht_max_mcs) { + max_mcs_idx = 8; + } else if (DATA_RATE_11AC_MAX_MCS_9 == vht_max_mcs) { + /* + * If the ini enable_vht20_mcs9 is disabled, + * then max mcs index should not be set to 9 + * for TX_RATE_VHT20 + */ + if (!is_vht20_mcs9 && + (rate_flags & TX_RATE_VHT20)) + max_mcs_idx = 8; + else + max_mcs_idx = 9; + } + + if (rate_flags & (TX_RATE_EHT20 | TX_RATE_EHT40 | + TX_RATE_EHT80 | TX_RATE_EHT160 | TX_RATE_EHT320)) + max_mcs_idx = 13; + + if (rate_flags & (TX_RATE_HE20 | TX_RATE_HE40 | + TX_RATE_HE80 | TX_RATE_HE160)) { + max_mcs_idx = 11; + if (he_mcs_12_13_map) + max_mcs_idx = 13; + } + + if (rssidx != 0) { + for (i = 0; i <= max_mcs_idx; i++) { + if (signal <= rssi_mcs_tbl[mode][i]) { + max_mcs_idx = i; + break; + } + } + } + + max_mcs_idx = (max_mcs_idx > mcs_index) ? + max_mcs_idx : mcs_index; + } else { + mcs_len = ucfg_mlme_get_mcs_rate(link_info->vdev, + mcs_rates, + sizeof(mcs_rates)); + if (!mcs_len) { + hdd_err("Failed to get current mcs rate set"); + /*To keep GUI happy */ + return false; + } + + if (rate_flags & TX_RATE_HT40) + rate_flag |= 1; + if (rate_flags & TX_RATE_SGI) + rate_flag |= 2; + + supported_mcs_rate = + (struct index_data_rate_type *) + ((nss == 1) ? &supported_mcs_rate_nss1 : + &supported_mcs_rate_nss2); + max_ht_mcs_idx = + QDF_ARRAY_SIZE(supported_mcs_rate_nss1); + max_ht_idx = max_ht_mcs_idx; + if (rssidx != 0) { + for (i = 0; i < max_ht_mcs_idx; i++) { + if (signal <= rssi_mcs_tbl[mode][i]) { + max_ht_idx = i + 1; + break; + } + } + } + + for (i = 0; i < mcs_len; i++) { + for (j = 0; j < max_ht_idx; j++) { + if (supported_mcs_rate[j]. + beacon_rate_index == + mcs_rates[i]) { + current_rate = + supported_mcs_rate[j]. + supported_rate + [rate_flag]; + max_mcs_idx = + supported_mcs_rate[j]. + beacon_rate_index; + break; + } + } + + if ((j < max_ht_mcs_idx) && + (current_rate > max_rate)) + max_rate = current_rate; + } + + if (nss == 2) + max_mcs_idx += max_ht_mcs_idx; + max_mcs_idx = (max_mcs_idx > mcs_index) ? + max_mcs_idx : mcs_index; + } + } + + else if (!(rate_flags & TX_RATE_LEGACY)) { + max_rate = fw_rate; + max_mcs_idx = mcs_index; + } + /* report a value at least as big as current rate */ + if ((max_rate < fw_rate) || (0 == max_rate)) { + max_rate = fw_rate; + } + hdd_debug("RLMS %u, rate_flags 0x%x, max_rate %d mcs %d nss %d", + link_speed_rssi_report, rate_flags, + max_rate, max_mcs_idx, nss); + wlan_hdd_fill_os_rate_info(rate_flags, max_rate, rate, + max_mcs_idx, nss, 0, 0); + + return true; +} + +/** + * hdd_report_actual_rate() - Fill the actual rate stats. + * @rate_flags: The rate flags computed from rate + * @my_rate: The rate from fw stats + * @rate: The station_info struct member struct rate_info to be filled + * @mcs_index: The mcs index computed from rate + * @nss: The NSS from fw stats + * @dcm: the dcm computed from rate + * @guard_interval: the guard interval computed from rate + * + * Return: None + */ +static void hdd_report_actual_rate(enum tx_rate_info rate_flags, + uint16_t my_rate, + struct rate_info *rate, uint8_t mcs_index, + uint8_t nss, uint8_t dcm, + enum txrate_gi guard_interval) +{ + /* report current rate instead of max rate */ + wlan_hdd_fill_os_rate_info(rate_flags, my_rate, rate, + mcs_index, nss, dcm, guard_interval); +} + +/** + * hdd_wlan_fill_per_chain_rssi_stats() - Fill per chain rssi stats + * + * @sinfo: The station_info structure to be filled. + * @link_info: pointer to link_info struct in adapter + * + * Return: None + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +static void +hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo, + struct wlan_hdd_link_info *link_info) +{ + bool rssi_stats_valid = false; + uint8_t i; + + sinfo->signal_avg = WLAN_HDD_TGT_NOISE_FLOOR_DBM; + for (i = 0; i < NUM_CHAINS_MAX; i++) { + sinfo->chain_signal_avg[i] = + link_info->hdd_stats.per_chain_rssi_stats.rssi[i]; + sinfo->chains |= 1 << i; + if (sinfo->chain_signal_avg[i] > sinfo->signal_avg && + sinfo->chain_signal_avg[i] != 0) + sinfo->signal_avg = sinfo->chain_signal_avg[i]; + + hdd_debug("RSSI for chain %d, vdev_id %d is %d", + i, link_info->vdev_id, sinfo->chain_signal_avg[i]); + + if (!rssi_stats_valid && sinfo->chain_signal_avg[i]) + rssi_stats_valid = true; + } + + if (rssi_stats_valid) { + sinfo->filled |= HDD_INFO_CHAIN_SIGNAL_AVG; + sinfo->filled |= HDD_INFO_SIGNAL_AVG; + } +} +#else +static inline void +hdd_wlan_fill_per_chain_rssi_stats(struct station_info *sinfo, + struct wlan_hdd_link_info *link_info) +{ +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)) || \ + defined(CFG80211_RX_FCS_ERROR_REPORTING_SUPPORT) +static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ + sinfo->rx_mpdu_count = link_info->hdd_stats.peer_stats.rx_count; + sinfo->fcs_err_count = link_info->hdd_stats.peer_stats.fcs_count; + hdd_debug("RX mpdu count %d fcs_err_count %d", + sinfo->rx_mpdu_count, sinfo->fcs_err_count); + sinfo->filled |= HDD_INFO_FCS_ERROR_COUNT | HDD_INFO_RX_MPDUS; +} +#else +static void hdd_fill_fcs_and_mpdu_count(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ +} +#endif + +void hdd_check_and_update_nss(struct hdd_context *hdd_ctx, + uint8_t *tx_nss, uint8_t *rx_nss) +{ + if (tx_nss && (*tx_nss > 1) && + policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) && + !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) { + hdd_debug("Hw mode is DBS, Reduce tx nss(%d) to 1", *tx_nss); + (*tx_nss)--; + } + + if (rx_nss && (*rx_nss > 1) && + policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc) && + !policy_mgr_is_hw_dbs_2x2_capable(hdd_ctx->psoc)) { + hdd_debug("Hw mode is DBS, Reduce rx nss(%d) to 1", *rx_nss); + (*rx_nss)--; + } +} + +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +static void +wlan_hdd_refill_os_bw(struct rate_info *os_rate, enum rx_tlv_bw bw) +{ + if (bw == RX_TLV_BW_20MHZ) + os_rate->bw = RATE_INFO_BW_20; + else if (bw == RX_TLV_BW_40MHZ) + os_rate->bw = RATE_INFO_BW_40; + else if (bw == RX_TLV_BW_80MHZ) + os_rate->bw = RATE_INFO_BW_80; + else if (bw == RX_TLV_BW_160MHZ) + os_rate->bw = RATE_INFO_BW_160; + else + wlan_hdd_refill_os_eht_bw(os_rate, bw); +} + +static void +wlan_hdd_refill_os_rateflags(struct rate_info *os_rate, uint8_t preamble) +{ + if (preamble == DOT11_N) + os_rate->flags |= RATE_INFO_FLAGS_MCS; + else if (preamble == DOT11_AC) + os_rate->flags |= RATE_INFO_FLAGS_VHT_MCS; + else if (preamble == DOT11_AX) + os_rate->flags |= RATE_INFO_FLAGS_HE_MCS; + else + wlan_hdd_refill_os_eht_rateflags(os_rate, preamble); +} + +/** + * wlan_hdd_refill_actual_rate() - Refill actual rates info stats + * @sinfo: kernel station_info struct to populate + * @link_info: pointer to link_info struct in adapter, + * where hdd_stats is located in this struct + * + * This function is to replace RX rates which was previously filled by fw. + * + * Return: None + */ +static void +wlan_hdd_refill_actual_rate(struct station_info *sinfo, + struct wlan_hdd_link_info *link_info) +{ + uint8_t preamble = link_info->hdd_stats.class_a_stat.rx_preamble; + + sinfo->rxrate.nss = link_info->hdd_stats.class_a_stat.rx_nss; + if (preamble == DOT11_A || preamble == DOT11_B) { + /* Clear rxrate which may have been set previously */ + qdf_mem_zero(&sinfo->rxrate, sizeof(sinfo->rxrate)); + sinfo->rxrate.legacy = + link_info->hdd_stats.class_a_stat.rx_rate; + hdd_debug("Reporting legacy rate %d", sinfo->rxrate.legacy); + return; + } else if (qdf_unlikely(preamble == INVALID_PREAMBLE)) { + /* + * If preamble is invalid, it means that DP has not received + * a data frame since assoc or roaming so there is no rates. + * In this case, using FW rates which was set previously. + */ + hdd_debug("Driver failed to get rate, reporting FW rate"); + return; + } + + wlan_hdd_refill_os_rateflags(&sinfo->rxrate, preamble); + + sinfo->rxrate.mcs = link_info->hdd_stats.class_a_stat.rx_mcs_index; + + wlan_hdd_refill_os_bw(&sinfo->rxrate, + link_info->hdd_stats.class_a_stat.rx_bw); + /* Fill out gi and dcm in HE mode */ + sinfo->rxrate.he_gi = + hdd_map_he_gi_to_os(link_info->hdd_stats.class_a_stat.rx_gi); + sinfo->rxrate.he_dcm = 0; + + if (link_info->hdd_stats.class_a_stat.rx_gi == TXRATE_GI_0_4_US) + sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + + hdd_debug("sgi=%d, preamble=%d, bw=%d, mcs=%d, nss=%d, rate_flag=0x%x", + link_info->hdd_stats.class_a_stat.rx_gi, preamble, + link_info->hdd_stats.class_a_stat.rx_bw, + link_info->hdd_stats.class_a_stat.rx_mcs_index, + link_info->hdd_stats.class_a_stat.rx_nss, + sinfo->rxrate.flags); +} +#else +static inline void +wlan_hdd_refill_actual_rate(struct station_info *sinfo, + struct wlan_hdd_link_info *link_info) +{ +} +#endif + +static void wlan_hdd_update_rssi(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ + struct hdd_station_ctx *sta_ctx; + int8_t snr; + mac_handle_t mac_handle; + + mac_handle = hdd_adapter_get_mac_handle(link_info->adapter); + if (!mac_handle) { + hdd_err("mac ctx NULL"); + return; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + link_info->rssi = link_info->hdd_stats.summary_stat.rssi; + link_info->snr = link_info->hdd_stats.summary_stat.snr; + snr = link_info->snr; + + /* for new connection there might be no valid previous RSSI */ + if (!link_info->rssi) { + hdd_get_rssi_snr_by_bssid(mac_handle, + sta_ctx->conn_info.bssid.bytes, + &link_info->rssi, &snr); + } + + /* If RSSi is reported as positive then it is invalid */ + if (link_info->rssi >= 0) { + hdd_debug_rl("Invalid RSSI %d, reset to -1", link_info->rssi); + link_info->rssi = -1; + link_info->hdd_stats.summary_stat.rssi = -1; + } + + sinfo->signal = link_info->rssi; + hdd_debug("snr: %d, rssi: %d", + link_info->hdd_stats.summary_stat.snr, + link_info->hdd_stats.summary_stat.rssi); + sta_ctx->conn_info.signal = sinfo->signal; + sta_ctx->conn_info.noise = sta_ctx->conn_info.signal - snr; + sta_ctx->cache_conn_info.signal = sinfo->signal; + sta_ctx->cache_conn_info.noise = sta_ctx->conn_info.noise; + sinfo->filled |= HDD_INFO_SIGNAL; +} + +static void +wlan_hdd_update_mlo_peer_stats(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ + ol_txrx_soc_handle soc; + uint8_t *peer_mac; + struct cdp_peer_stats *peer_stats; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_err("invalid hdd_ctx"); + return; + } + + soc = cds_get_context(QDF_MODULE_ID_SOC); + peer_mac = link_info->session.station.conn_info.bssid.bytes; + + if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) + return; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) { + hdd_err("Failed to allocated memory for peer_stats"); + return; + } + + ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id, + peer_mac, peer_stats, + CDP_WILD_PEER_TYPE, + WLAN_MAX_MLD); + + sinfo->tx_bytes = peer_stats->tx.tx_success.bytes; + sinfo->rx_bytes = peer_stats->rx.rcvd.bytes; + sinfo->rx_packets = peer_stats->rx.rcvd.num; + + hdd_nofl_debug("Updated sinfo with per peer stats"); + qdf_mem_free(peer_stats); +} + +static int wlan_hdd_update_rate_info(struct wlan_hdd_link_info *link_info, + struct station_info *sinfo) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct hdd_station_ctx *sta_ctx; + mac_handle_t mac_handle; + struct wlan_objmgr_vdev *vdev; + enum tx_rate_info rate_flags, tx_rate_flags, rx_rate_flags; + enum txrate_gi tx_gi, rx_gi; + uint32_t link_speed_rssi_report = 0; + int link_speed_rssi_high = 0; + int link_speed_rssi_mid = 0; + int link_speed_rssi_low = 0; + uint16_t my_tx_rate, my_rx_rate; + uint8_t tx_mcs_index, rx_mcs_index; + uint8_t tx_nss = 1, rx_nss = 1, tx_dcm, rx_dcm; + qdf_net_dev_stats stats = {0}; + struct hdd_stats *hdd_stats; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + ucfg_mlme_stats_get_cfg_values(hdd_ctx->psoc, + &link_speed_rssi_high, + &link_speed_rssi_mid, + &link_speed_rssi_low, + &link_speed_rssi_report); + + hdd_stats = &link_info->hdd_stats; + rate_flags = hdd_stats->class_a_stat.tx_rx_rate_flags; + tx_rate_flags = rx_rate_flags = rate_flags; + + tx_mcs_index = hdd_stats->class_a_stat.tx_mcs_index; + rx_mcs_index = hdd_stats->class_a_stat.rx_mcs_index; + mac_handle = hdd_ctx->mac_handle; + + /* convert to the UI units of 100kbps */ + my_tx_rate = hdd_stats->class_a_stat.tx_rate; + my_rx_rate = hdd_stats->class_a_stat.rx_rate; + + tx_dcm = hdd_stats->class_a_stat.tx_dcm; + rx_dcm = hdd_stats->class_a_stat.rx_dcm; + tx_gi = hdd_stats->class_a_stat.tx_gi; + rx_gi = hdd_stats->class_a_stat.rx_gi; + + if (!(rate_flags & TX_RATE_LEGACY)) { + tx_nss = hdd_stats->class_a_stat.tx_nss; + rx_nss = hdd_stats->class_a_stat.rx_nss; + + hdd_check_and_update_nss(hdd_ctx, &tx_nss, &rx_nss); + + if (ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) { + /* Get current rate flags if report actual */ + /* WMA fails to find mcs_index for legacy tx rates */ + if (tx_mcs_index == INVALID_MCS_IDX && my_tx_rate) + tx_rate_flags = TX_RATE_LEGACY; + else + tx_rate_flags = + hdd_stats->class_a_stat.tx_mcs_rate_flags; + + if (rx_mcs_index == INVALID_MCS_IDX && my_rx_rate) + rx_rate_flags = TX_RATE_LEGACY; + else + rx_rate_flags = + hdd_stats->class_a_stat.rx_mcs_rate_flags; + } + + if (tx_mcs_index == INVALID_MCS_IDX) + tx_mcs_index = 0; + if (rx_mcs_index == INVALID_MCS_IDX) + rx_mcs_index = 0; + } + + hdd_debug("[RSSI %d, RLMS %u, rssi high %d, rssi mid %d, rssi low %d]-" + "[Rate info: TX: %d, RX: %d]-[Rate flags: TX: 0x%x, RX: 0x%x]" + "-[MCS Index: TX: %d, RX: %d]-[NSS: TX: %d, RX: %d]-" + "[dcm: TX: %d, RX: %d]-[guard interval: TX: %d, RX: %d", + sinfo->signal, link_speed_rssi_report, + link_speed_rssi_high, link_speed_rssi_mid, + link_speed_rssi_low, my_tx_rate, my_rx_rate, + (int)tx_rate_flags, (int)rx_rate_flags, (int)tx_mcs_index, + (int)rx_mcs_index, (int)tx_nss, (int)rx_nss, + (int)tx_dcm, (int)rx_dcm, (int)tx_gi, (int)rx_gi); + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + + if (!vdev) { + hdd_nofl_debug("vdev object NULL"); + return -EINVAL; + } + + if (sinfo->signal == WLAN_INVALID_RSSI_VALUE) { + hdd_debug("don't fill tx rx rate for inactive link"); + } else if (!ucfg_mlme_stats_is_link_speed_report_actual(hdd_ctx->psoc)) { + bool tx_rate_calc, rx_rate_calc; + uint8_t tx_nss_max, rx_nss_max; + + /* + * Take static NSS for reporting max rates. NSS from the FW + * is not reliable as it changes as per the environment + * quality. + */ + tx_nss_max = wlan_vdev_mlme_get_nss(vdev); + rx_nss_max = wlan_vdev_mlme_get_nss(vdev); + + hdd_check_and_update_nss(hdd_ctx, &tx_nss_max, &rx_nss_max); + + tx_rate_calc = hdd_report_max_rate(link_info, mac_handle, + &sinfo->txrate, + sinfo->signal, + tx_rate_flags, + tx_mcs_index, + my_tx_rate, + tx_nss_max); + + rx_rate_calc = hdd_report_max_rate(link_info, mac_handle, + &sinfo->rxrate, + sinfo->signal, + rx_rate_flags, + rx_mcs_index, + my_rx_rate, + rx_nss_max); + + if (!tx_rate_calc || !rx_rate_calc) { + hdd_report_actual_rate(tx_rate_flags, my_tx_rate, + &sinfo->txrate, tx_mcs_index, + tx_nss, tx_dcm, tx_gi); + + hdd_report_actual_rate(rx_rate_flags, my_rx_rate, + &sinfo->rxrate, rx_mcs_index, + rx_nss, rx_dcm, rx_gi); + } + } else { + /* Fill TX stats */ + hdd_report_actual_rate(tx_rate_flags, my_tx_rate, + &sinfo->txrate, tx_mcs_index, + tx_nss, tx_dcm, tx_gi); + + /* Fill RX stats */ + hdd_report_actual_rate(rx_rate_flags, my_rx_rate, + &sinfo->rxrate, rx_mcs_index, + rx_nss, rx_dcm, rx_gi); + + /* Using driver RX rate to replace the FW RX rate */ + wlan_hdd_refill_actual_rate(sinfo, link_info); + } + + wlan_hdd_fill_summary_stats(&hdd_stats->summary_stat, + sinfo, link_info->vdev_id); + + wlan_hdd_fill_per_link_summary_stats(&hdd_stats->summary_stat, + sinfo, link_info); + + ucfg_dp_get_net_dev_stats(vdev, &stats); + sinfo->tx_bytes = stats.tx_bytes; + sinfo->rx_bytes = stats.rx_bytes; + sinfo->rx_packets = stats.rx_packets; + wlan_hdd_update_mlo_peer_stats(link_info, sinfo); + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + + qdf_mem_copy(&sta_ctx->conn_info.txrate, + &sinfo->txrate, sizeof(sinfo->txrate)); + qdf_mem_copy(&sta_ctx->cache_conn_info.txrate, + &sinfo->txrate, sizeof(sinfo->txrate)); + + qdf_mem_copy(&sta_ctx->conn_info.rxrate, + &sinfo->rxrate, sizeof(sinfo->rxrate)); + + sinfo->filled |= HDD_INFO_TX_BITRATE | + HDD_INFO_RX_BITRATE | + HDD_INFO_TX_BYTES | + HDD_INFO_RX_BYTES | + HDD_INFO_RX_PACKETS; + + if (tx_rate_flags & TX_RATE_LEGACY) { + hdd_debug("[TX: Reporting legacy rate %d pkt cnt %d]-" + "[RX: Reporting legacy rate %d pkt cnt %d]", + sinfo->txrate.legacy, sinfo->tx_packets, + sinfo->rxrate.legacy, sinfo->rx_packets); + } else { + hdd_debug("[TX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]-" + "[RX: Reporting MCS rate %d, flags 0x%x pkt cnt %d, nss %d, bw %d]", + sinfo->txrate.mcs, sinfo->txrate.flags, + sinfo->tx_packets, sinfo->txrate.nss, + sinfo->txrate.bw, sinfo->rxrate.mcs, + sinfo->rxrate.flags, sinfo->rx_packets, + sinfo->rxrate.nss, sinfo->rxrate.bw); + } + + return 0; +} + +/** + * wlan_hdd_get_sta_stats() - get aggregate STA stats + * @link_info: Link info pointer of STA adapter to get stats for + * @mac: mac address of sta + * @sinfo: kernel station_info struct to populate + * + * Fetch the vdev-level aggregate stats for the given STA adapter. This is to + * support "station dump" and "station get" for STA vdevs + * + * Return: errno + */ +static int wlan_hdd_get_sta_stats(struct wlan_hdd_link_info *link_info, + const uint8_t *mac, + struct station_info *sinfo) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx; + uint8_t *link_mac; + int32_t rcpi_value; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_GET_STA, + link_info->vdev_id, 0); + + if (link_info->vdev_id == WLAN_UMAC_VDEV_ID_MAX) { + wlan_hdd_update_sinfo(sinfo, link_info); + hdd_debug_rl("Sending Cached stats for standby link"); + return 0; + } + + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug("Not associated"); + /*To keep GUI happy */ + return 0; + } + + if (hdd_is_roam_sync_in_progress(hdd_ctx, link_info->vdev_id)) { + hdd_debug("Roam sync is in progress, cannot continue with this request"); + /* + * supplicant reports very low rssi to upper layer + * and handover happens to cellular. + * send the cached rssi when get_station + */ + sinfo->signal = link_info->rssi; + sinfo->filled |= HDD_INFO_SIGNAL; + return 0; + } + + if (hdd_ctx->rcpi_enabled) + wlan_hdd_get_rcpi(adapter, (uint8_t *)mac, &rcpi_value, + RCPI_MEASUREMENT_TYPE_AVG_MGMT); + + wlan_hdd_get_station_stats(link_info); + + wlan_hdd_get_peer_rx_rate_stats(link_info); + + wlan_hdd_update_rssi(link_info, sinfo); + + /* + * we notify connect to lpass here instead of during actual + * connect processing because rssi info is not accurate during + * actual connection. lpass will ensure the notification is + * only processed once per association. + */ + hdd_lpass_notify_connect(link_info); + + if (wlan_hdd_update_rate_info(link_info, sinfo)) + /* Keep GUI happy */ + return 0; + + hdd_fill_fcs_and_mpdu_count(link_info, sinfo); + + hdd_wlan_fill_per_chain_rssi_stats(sinfo, link_info); + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + link_mac = sta_ctx->conn_info.bssid.bytes; + hdd_nofl_debug("Sending station stats for link " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(link_mac)); + + wlan_hdd_copy_sinfo_to_link_info(link_info, sinfo); + + hdd_exit(); + + return 0; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/* + * wlan_hdd_update_mlo_rate_info() - Populate mlo station stats rate info + * @hdd_sinfo: Pointer to hdd stats station info struct + * @sinfo: Pointer to kernel station info struct + * + * Return: none + */ +static void +wlan_hdd_update_mlo_rate_info(struct wlan_hdd_station_stats_info *hdd_sinfo, + struct station_info *sinfo) +{ + uint8_t i; + + hdd_sinfo->signal = sinfo->signal; + hdd_sinfo->signal_avg = sinfo->signal_avg; + for (i = 0; i < IEEE80211_MAX_CHAINS; i++) + hdd_sinfo->chain_signal_avg[i] = sinfo->chain_signal_avg[i]; + + qdf_mem_copy(&hdd_sinfo->txrate, + &sinfo->txrate, sizeof(sinfo->txrate)); + + qdf_mem_copy(&hdd_sinfo->rxrate, + &sinfo->rxrate, sizeof(sinfo->rxrate)); +} + +/* + * wlan_hdd_update_mlo_sinfo() - Populate mlo stats station info + * @link_info: Link info pointer of STA adapter + * @hdd_sinfo: Pointer to hdd stats station info struct + * @sinfo: Pointer to kernel station info struct + * + * Return: none + */ +static void +wlan_hdd_update_mlo_sinfo(struct wlan_hdd_link_info *link_info, + struct wlan_hdd_station_stats_info *hdd_sinfo, + struct station_info *sinfo) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + if (!link_info->is_mlo_vdev_active) + hdd_nofl_debug("vdev_id[%d] is inactive", link_info->vdev_id); + + /* Update the rate info for link with best RSSI */ + if (sinfo->signal > hdd_sinfo->signal) { + hdd_nofl_debug("Updating rates for link_id %d", + sta_ctx->conn_info.ieee_link_id); + wlan_hdd_update_mlo_rate_info(hdd_sinfo, sinfo); + } + + /* Send cumulative Tx/Rx packets and bytes data + * of all active links to userspace + */ + hdd_sinfo->rx_bytes += sinfo->rx_bytes; + hdd_sinfo->tx_bytes += sinfo->tx_bytes; + hdd_sinfo->rx_packets += sinfo->rx_packets; + hdd_sinfo->tx_packets += sinfo->tx_packets; + hdd_sinfo->tx_retries += sinfo->tx_retries; + hdd_sinfo->tx_failed += sinfo->tx_failed; + hdd_sinfo->rx_mpdu_count += sinfo->rx_mpdu_count; + hdd_sinfo->fcs_err_count += sinfo->fcs_err_count; +} + +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +/** + * wlan_hdd_get_mlo_sta_stats - get aggregate STA stats for MLO + * @adapter: HDD adapter + * @mac: mac address + * @sinfo: kernel station_info struct to populate + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter, + const uint8_t *mac, + struct station_info *sinfo) +{ + struct hdd_adapter *ml_adapter, *link_adapter; + struct hdd_mlo_adapter_info *mlo_adapter_info; + struct wlan_hdd_station_stats_info hdd_sinfo = {0}; + uint8_t i; + + /* Initialize the signal value to a default RSSI of -128dBm */ + hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE; + + ml_adapter = adapter; + if (hdd_adapter_is_link_adapter(ml_adapter)) + ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter); + + wlan_hdd_get_sta_stats(ml_adapter->deflink, mac, sinfo); + wlan_hdd_update_mlo_sinfo(ml_adapter->deflink, &hdd_sinfo, sinfo); + + mlo_adapter_info = &ml_adapter->mlo_adapter_info; + for (i = 0; i < WLAN_MAX_MLD; i++) { + link_adapter = mlo_adapter_info->link_adapter[i]; + if (!link_adapter || + hdd_adapter_is_associated_with_ml_adapter(link_adapter)) + continue; + + wlan_hdd_get_sta_stats(link_adapter->deflink, mac, sinfo); + wlan_hdd_update_mlo_sinfo(link_adapter->deflink, &hdd_sinfo, + sinfo); + } + + wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo); + hdd_nofl_debug("Sending aggregated mlo station stats"); + + hdd_exit(); + + return 0; +} +#else +static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter, + const uint8_t *mac, + struct station_info *sinfo) +{ + struct wlan_hdd_link_info *link_info; + struct wlan_hdd_station_stats_info hdd_sinfo = {0}; + struct hdd_station_ctx *sta_ctx; + + /* Initialize the signal value to a default RSSI of -128dBm */ + hdd_sinfo.signal = WLAN_INVALID_RSSI_VALUE; + + hdd_adapter_for_each_link_info(adapter, link_info) { + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID) + continue; + wlan_hdd_get_sta_stats(link_info, mac, sinfo); + wlan_hdd_update_mlo_sinfo(link_info, &hdd_sinfo, sinfo); + } + + wlan_hdd_copy_hdd_stats_to_sinfo(sinfo, &hdd_sinfo); + hdd_nofl_debug("Sending aggregated mlo station stats"); + + hdd_exit(); + + return 0; +} +#endif +#else +static int wlan_hdd_get_mlo_sta_stats(struct hdd_adapter *adapter, + const uint8_t *mac, + struct station_info *sinfo) +{ + return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo); +} +#endif + +/* + * wlan_is_mlo_aggregated_stats_allowed() - Is aggregated stats requested + * @adapter: HDD adapter + * @mac: mac address + * + * Return: True if req is on mld_mac and FW supports per link stats, else False + */ +static bool +wlan_is_mlo_aggregated_stats_allowed(struct hdd_adapter *adapter, + const uint8_t *mac) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + bool is_mld_req = false; + bool per_link_stats_cap = false; + struct qdf_mac_addr peer_mld_mac; + QDF_STATUS status; + + if (!hdd_ctx) { + hdd_err("invalid hdd_ctx"); + return false; + } + + status = wlan_hdd_get_bss_peer_mld_mac(adapter->deflink, &peer_mld_mac); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("mlo_vdev_stats: failed to get bss peer mld mac"); + return false; + } + + is_mld_req = qdf_is_macaddr_equal(&peer_mld_mac, + (struct qdf_mac_addr *)mac); + per_link_stats_cap = wlan_hdd_is_per_link_stats_supported(hdd_ctx); + + if (is_mld_req && per_link_stats_cap) { + hdd_debug_rl("Fetching Aggregated station stats"); + return true; + } + + return false; +} + +/** + * wlan_hdd_send_mlo_station_stats() - send station stats to userspace + * @adapter: Pointer to hdd adapter + * @hdd_ctx: Pointer to hdd context + * @mac: mac address + * @sinfo: kernel station_info struct to populate + * + * Return: 0 on success; errno on failure + */ +static int wlan_hdd_send_mlo_station_stats(struct hdd_adapter *adapter, + struct hdd_context *hdd_ctx, + const uint8_t *mac, + struct station_info *sinfo) +{ + struct wlan_hdd_link_info *link_info; + + if (!wlan_hdd_is_mlo_connection(adapter->deflink)) { + hdd_nofl_debug("Fetching station stats for legacy connection"); + return wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo); + } + + link_info = hdd_get_link_info_by_bssid(hdd_ctx, mac); + if (!link_info) { + if (wlan_is_mlo_aggregated_stats_allowed(adapter, mac)) + return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo); + + hdd_debug_rl("Invalid bssid"); + return -EINVAL; + } + return wlan_hdd_get_sta_stats(link_info, mac, sinfo); +} + +/** + * __wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_info *sinfo) +{ + int errno; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_station_info *stainfo; + bool get_peer_info_enable; + QDF_STATUS qdf_status; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return -EINVAL; + + hdd_nofl_debug("Stats request on MAC: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + + if (!mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mac)) { + hdd_err("Invalid MAC addr"); + return -EINVAL; + } + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + qdf_status = ucfg_mlme_get_sap_get_peer_info( + hdd_ctx->psoc, &get_peer_info_enable); + if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) { + stainfo = hdd_get_sta_info_by_mac( + &adapter->sta_info_list, mac, + STA_INFO_WLAN_HDD_CFG80211_GET_STATION); + if (!stainfo) { + hdd_debug("Peer " QDF_MAC_ADDR_FMT " not found", + QDF_MAC_ADDR_REF(mac)); + return -EINVAL; + } + + errno = wlan_hdd_get_station_remote(wiphy, dev, + stainfo, sinfo); + hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, + true, + STA_INFO_WLAN_HDD_CFG80211_GET_STATION + ); + if (!errno) + return 0; + } + return wlan_hdd_get_sap_stats(link_info, sinfo); + } + + return wlan_hdd_send_mlo_station_stats(adapter, hdd_ctx, mac, sinfo); +} + +/** + * _wlan_hdd_cfg80211_get_station() - get station statistics + * + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * This API tries runtime PM suspend right away after getting station + * statistics. + * + * Return: 0 for success, non-zero for failure + */ +static int _wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *mac, + struct station_info *sinfo) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int errno; + QDF_STATUS status; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) { + hdd_debug("Link Switch in progress, can't process request"); + return -EBUSY; + } + + status = wlan_hdd_stats_request_needed(adapter); + if (QDF_IS_STATUS_ERROR(status)) { + if (status == QDF_STATUS_E_ALREADY) + get_station_fw_request_needed = false; + else + return -EINVAL; + } + + if (get_station_fw_request_needed) { + errno = wlan_hdd_qmi_get_sync_resume(); + if (errno) { + hdd_err("qmi sync resume failed: %d", errno); + return errno; + } + } + + errno = __wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); + + if (get_station_fw_request_needed) + wlan_hdd_qmi_put_suspend(); + + get_station_fw_request_needed = true; + + return errno; +} + +/** + * wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = _wlan_hdd_cfg80211_get_station(wiphy, dev, mac, sinfo); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to station index, kernel iterate all stations over idx + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + int errno; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_station_info *stainfo; + bool get_peer_info_enable; + QDF_STATUS qdf_status; + + hdd_debug("idx: %d", idx); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + if (wlan_hdd_is_link_switch_in_progress(adapter->deflink)) { + hdd_debug("Link Switch in progress, can't process request"); + return -EBUSY; + } + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + qdf_status = ucfg_mlme_get_sap_get_peer_info( + hdd_ctx->psoc, &get_peer_info_enable); + if (qdf_status == QDF_STATUS_SUCCESS && get_peer_info_enable) { + stainfo = hdd_get_sta_info_by_id( + &adapter->sta_info_list, + idx, + STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION + ); + if (!stainfo) { + hdd_err("peer idx %d NOT FOUND", idx); + return -ENOENT; + } + + qdf_mem_copy(mac, &stainfo->sta_mac.bytes, + QDF_MAC_ADDR_SIZE); + errno = wlan_hdd_get_station_remote(wiphy, dev, + stainfo, sinfo); + hdd_put_sta_info_ref(&adapter->sta_info_list, &stainfo, + true, + STA_INFO_WLAN_HDD_CFG80211_DUMP_STATION + ); + } else { + errno = -EINVAL; + hdd_err("sap get peer info disabled!"); + } + } else { + if (idx != 0) + return -ENOENT; + + qdf_mem_copy(mac, dev->dev_addr, QDF_MAC_ADDR_SIZE); + + if (wlan_hdd_is_mlo_connection(adapter->deflink) && + wlan_hdd_is_per_link_stats_supported(hdd_ctx)) + return wlan_hdd_get_mlo_sta_stats(adapter, mac, sinfo); + + hdd_nofl_debug("Sending Assoc Link stats"); + errno = wlan_hdd_get_sta_stats(adapter->deflink, mac, sinfo); + } + return errno; +} + +/** + * wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_qmi_get_sync_resume(); + if (errno) { + hdd_err("qmi sync resume failed: %d", errno); + goto end; + } + + errno = __wlan_hdd_cfg80211_dump_station(wiphy, dev, idx, mac, sinfo); + + wlan_hdd_qmi_put_suspend(); + +end: + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_get_stats() - Function to retrieve interface statistics + * @dev: pointer to network device + * + * This function is the ndo_get_stats method for all netdevs + * registered with the kernel + * + * Return: pointer to net_device_stats structure + */ +struct net_device_stats *hdd_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)ucfg_dp_get_dev_stats(dev); +} + +/* + * FW sends value of cycle_count, rx_clear_count and tx_frame_count in usec. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)) +static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq, + struct scan_chan_info *chan_info, + struct ieee80211_channel *channels) +{ + if (channels->center_freq != (uint16_t)chan_info->freq) + return false; + + survey->channel = channels; + survey->noise = chan_info->noise_floor; + survey->filled = 0; + + if (chan_info->noise_floor) + survey->filled |= SURVEY_INFO_NOISE_DBM; + + if (opfreq == chan_info->freq) + survey->filled |= SURVEY_INFO_IN_USE; + + survey->time = chan_info->cycle_count; + survey->time_busy = chan_info->rx_clear_count; + survey->time_tx = chan_info->tx_frame_count; + + survey->filled |= SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_TX; + return true; +} +#else +static bool wlan_fill_survey_result(struct survey_info *survey, int opfreq, + struct scan_chan_info *chan_info, + struct ieee80211_channel *channels) +{ + if (channels->center_freq != (uint16_t)chan_info->freq) + return false; + + survey->channel = channels; + survey->noise = chan_info->noise_floor; + survey->filled = 0; + + if (chan_info->noise_floor) + survey->filled |= SURVEY_INFO_NOISE_DBM; + + if (opfreq == chan_info->freq) + survey->filled |= SURVEY_INFO_IN_USE; + + survey->channel_time = chan_info->cycle_count; + survey->channel_time_busy = chan_info->rx_clear_count; + survey->channel_time_tx = chan_info->tx_frame_count; + + survey->filled |= SURVEY_INFO_CHANNEL_TIME | + SURVEY_INFO_CHANNEL_TIME_BUSY | + SURVEY_INFO_CHANNEL_TIME_TX; + return true; +} +#endif + +static bool wlan_hdd_update_survey_info(struct wiphy *wiphy, + struct hdd_adapter *adapter, + struct survey_info *survey, int idx) +{ + bool filled = false; + int i, j = 0; + uint32_t opfreq = 0; /* Initialization Required */ + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + sme_get_operation_channel(hdd_ctx->mac_handle, &opfreq, + adapter->deflink->vdev_id); + + mutex_lock(&hdd_ctx->chan_info_lock); + + for (i = 0; i < HDD_NUM_NL80211_BANDS && !filled; i++) { + if (!wiphy->bands[i]) + continue; + + for (j = 0; j < wiphy->bands[i]->n_channels && !filled; j++) { + struct ieee80211_supported_band *band = wiphy->bands[i]; + + filled = wlan_fill_survey_result(survey, opfreq, + &hdd_ctx->chan_info[idx], + &band->channels[j]); + } + } + mutex_unlock(&hdd_ctx->chan_info_lock); + + return filled; +} + +/** + * __wlan_hdd_cfg80211_dump_survey() - get survey related info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: Index + * @survey: Pointer to survey info + * + * Return: 0 for success, non-zero for failure + */ +static int __wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int status; + bool filled = false; + + if (idx > NUM_CHANNELS - 1) + return -ENOENT; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return status; + + if (!hdd_ctx->chan_info) { + hdd_debug("chan_info is NULL"); + return -EINVAL; + } + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!ucfg_scan_is_snr_monitor_enabled(hdd_ctx->psoc)) + return -ENONET; + + if (hdd_cm_is_vdev_roaming(adapter->deflink)) { + hdd_debug("Roaming in progress, hence return"); + return -ENONET; + } + + filled = wlan_hdd_update_survey_info(wiphy, adapter, survey, idx); + + if (!filled) + return -ENOENT; + + return 0; +} + +/** + * wlan_hdd_cfg80211_dump_survey() - get survey related info + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: Index + * @survey: Pointer to survey info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_dump_survey(wiphy, dev, idx, survey); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_display_hif_stats() - display hif stats + * + * Return: none + * + */ +void hdd_display_hif_stats(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) + return; + + hif_display_stats(hif_ctx); +} + +/** + * hdd_clear_hif_stats() - clear hif stats + * + * Return: none + */ +void hdd_clear_hif_stats(void) +{ + void *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + + if (!hif_ctx) + return; + hif_clear_stats(hif_ctx); +} + +/** + * hdd_is_rcpi_applicable() - validates RCPI request + * @adapter: adapter upon which the measurement is requested + * @mac_addr: peer addr for which measurement is requested + * @rcpi_value: pointer to where the RCPI should be returned + * @reassoc: used to return cached RCPI during reassoc + * + * Return: true for success, false for failure + */ + +static bool hdd_is_rcpi_applicable(struct hdd_adapter *adapter, + struct qdf_mac_addr *mac_addr, + int32_t *rcpi_value, + bool *reassoc) +{ + struct hdd_station_ctx *hdd_sta_ctx; + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) + return false; + + if (hdd_cm_is_vdev_roaming(adapter->deflink)) { + /* return the cached rcpi, if mac addr matches */ + hdd_debug("Roaming in progress, return cached RCPI"); + if (!qdf_mem_cmp(&adapter->rcpi.mac_addr, + mac_addr, sizeof(*mac_addr))) { + *rcpi_value = adapter->rcpi.rcpi; + *reassoc = true; + return true; + } + return false; + } + + if (qdf_mem_cmp(mac_addr, &hdd_sta_ctx->conn_info.bssid, + sizeof(*mac_addr))) { + hdd_err("mac addr is different from bssid connected"); + return false; + } + } else if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + if (!test_bit(SOFTAP_BSS_STARTED, + &adapter->deflink->link_flags)) { + hdd_err("Invalid rcpi request, softap not started"); + return false; + } + + /* check if peer mac addr is associated to softap */ + if (!hdd_is_peer_associated(adapter, mac_addr)) { + hdd_err("invalid peer mac-addr: not associated"); + return false; + } + } else { + hdd_err("Invalid rcpi request"); + return false; + } + + *reassoc = false; + return true; +} + +/** + * wlan_hdd_get_rcpi_cb() - callback function for rcpi response + * @context: Pointer to rcpi context + * @mac_addr: peer MAC address + * @rcpi: RCPI response + * @status: QDF_STATUS of the request + * + * Return: None + */ +static void wlan_hdd_get_rcpi_cb(void *context, struct qdf_mac_addr mac_addr, + int32_t rcpi, QDF_STATUS status) +{ + struct osif_request *request; + struct rcpi_info *priv; + + if (!context) { + hdd_err("No rcpi context"); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete RCPI request"); + return; + } + + priv = osif_request_priv(request); + priv->mac_addr = mac_addr; + + if (!QDF_IS_STATUS_SUCCESS(status)) { + priv->rcpi = 0; + hdd_err("Error in computing RCPI"); + } else { + priv->rcpi = rcpi; + } + + osif_request_complete(request); + osif_request_put(request); +} + +/** + * wlan_hdd_get_rcpi() - local function to get RCPI + * @adapter: adapter upon which the measurement is requested + * @mac: peer addr for which measurement is requested + * @rcpi_value: pointer to where the RCPI should be returned + * @measurement_type: type of rcpi measurement + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, + uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type) +{ + struct hdd_context *hdd_ctx; + int status = 0, ret = 0; + struct qdf_mac_addr mac_addr; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sme_rcpi_req *rcpi_req; + void *cookie; + struct rcpi_info *priv; + struct osif_request *request; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_RCPI, + }; + bool reassoc; + + hdd_enter(); + + /* initialize the rcpi value to zero, useful in error cases */ + *rcpi_value = 0; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (!adapter) { + hdd_warn("adapter context is NULL"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return -EINVAL; + + if (!hdd_ctx->rcpi_enabled) { + hdd_debug("RCPI not supported"); + return -EINVAL; + } + + if (!mac) { + hdd_warn("RCPI peer mac-addr is NULL"); + return -EINVAL; + } + + qdf_mem_copy(&mac_addr, mac, QDF_MAC_ADDR_SIZE); + + if (!hdd_is_rcpi_applicable(adapter, &mac_addr, rcpi_value, &reassoc)) + return -EINVAL; + if (reassoc) + return 0; + + rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req)); + if (!rcpi_req) + return -EINVAL; + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + qdf_mem_free(rcpi_req); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + rcpi_req->mac_addr = mac_addr; + rcpi_req->session_id = adapter->deflink->vdev_id; + rcpi_req->measurement_type = measurement_type; + rcpi_req->rcpi_callback = wlan_hdd_get_rcpi_cb; + rcpi_req->rcpi_context = cookie; + + qdf_status = sme_get_rcpi(hdd_ctx->mac_handle, rcpi_req); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Unable to retrieve RCPI"); + status = qdf_status_to_os_return(qdf_status); + goto out; + } + + /* request was sent -- wait for the response */ + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving RCPI"); + status = -EINVAL; + goto out; + } + + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + adapter->rcpi.mac_addr = priv->mac_addr; + adapter->rcpi.rcpi = priv->rcpi; + if (qdf_mem_cmp(&mac_addr, &priv->mac_addr, sizeof(mac_addr))) { + hdd_err("mis match of mac addr from call-back"); + status = -EINVAL; + goto out; + } + + *rcpi_value = adapter->rcpi.rcpi; + hdd_debug("RCPI = %d", *rcpi_value); +out: + qdf_mem_free(rcpi_req); + osif_request_put(request); + + hdd_exit(); + return status; +} + +#ifdef WLAN_FEATURE_MIB_STATS +QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter) +{ + int ret = 0; + struct stats_event *stats; + struct wlan_objmgr_vdev *vdev; + + if (!adapter) { + hdd_err("Invalid context, adapter"); + return QDF_STATUS_E_FAULT; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_STATS_ID); + if (!vdev) + return QDF_STATUS_E_FAULT; + + stats = wlan_cfg80211_mc_cp_stats_get_mib_stats(vdev, &ret); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + if (ret || !stats) { + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + return ret; + } + + hdd_debugfs_process_mib_stats(adapter, stats); + + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + return ret; +} +#endif + +QDF_STATUS wlan_hdd_get_rssi(struct wlan_hdd_link_info *link_info, + int8_t *rssi_value) +{ + int ret = 0, i; + struct hdd_station_ctx *sta_ctx; + struct stats_event *rssi_info; + struct wlan_objmgr_vdev *vdev; + + if (cds_is_driver_recovering() || cds_is_driver_in_bad_state()) { + hdd_err("Recovery in Progress. State: 0x%x Ignore!!!", + cds_get_driver_state()); + /* return a cached value */ + *rssi_value = link_info->rssi; + return QDF_STATUS_SUCCESS; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug("Not associated!, rssi on disconnect %d", + link_info->rssi_on_disconnect); + *rssi_value = link_info->rssi_on_disconnect; + return QDF_STATUS_SUCCESS; + } + + if (hdd_cm_is_vdev_roaming(link_info)) { + hdd_debug("Roaming in progress, return cached RSSI"); + *rssi_value = link_info->rssi; + return QDF_STATUS_SUCCESS; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) { + *rssi_value = link_info->rssi; + return QDF_STATUS_SUCCESS; + } + + rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi( + vdev, + sta_ctx->conn_info.bssid.bytes, + &ret); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + if (ret || !rssi_info) { + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); + return ret; + } + + for (i = 0; i < rssi_info->num_peer_stats; i++) { + if (!qdf_mem_cmp(rssi_info->peer_stats[i].peer_macaddr, + sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE)) { + *rssi_value = rssi_info->peer_stats[i].peer_rssi; + hdd_debug("RSSI = %d", *rssi_value); + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); + return QDF_STATUS_SUCCESS; + } + } + + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); + hdd_err("bss peer not present in returned result"); + return QDF_STATUS_E_FAULT; +} + +struct snr_priv { + int8_t snr; +}; + +/** + * hdd_get_snr_cb() - "Get SNR" callback function + * @snr: Current SNR of the station + * @context: opaque context originally passed to SME. HDD always passes + * a cookie for the request context + * + * Return: None + */ +static void hdd_get_snr_cb(int8_t snr, void *context) +{ + struct osif_request *request; + struct snr_priv *priv; + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + /* propagate response back to requesting thread */ + priv = osif_request_priv(request); + priv->snr = snr; + osif_request_complete(request); + osif_request_put(request); +} + +QDF_STATUS wlan_hdd_get_snr(struct wlan_hdd_link_info *link_info, int8_t *snr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct hdd_station_ctx *sta_ctx; + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct snr_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return QDF_STATUS_E_FAULT; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return QDF_STATUS_E_FAULT; + } + cookie = osif_request_cookie(request); + + status = sme_get_snr(hdd_ctx->mac_handle, hdd_get_snr_cb, + sta_ctx->conn_info.bssid, cookie); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve RSSI"); + /* we'll returned a cached value below */ + } else { + /* request was sent -- wait for the response */ + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving SNR"); + /* we'll now returned a cached value below */ + } else { + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + link_info->snr = priv->snr; + } + } + + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + osif_request_put(request); + + *snr = link_info->snr; + hdd_exit(); + return QDF_STATUS_SUCCESS; +} + +struct linkspeed_priv { + struct link_speed_info linkspeed_info; +}; + +static void +hdd_get_link_speed_cb(struct link_speed_info *linkspeed_info, void *context) +{ + struct osif_request *request; + struct linkspeed_priv *priv; + + if (!linkspeed_info) { + hdd_err("NULL linkspeed"); + return; + } + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->linkspeed_info = *linkspeed_info; + osif_request_complete(request); + osif_request_put(request); +} + +int wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *mac_address, + uint32_t *linkspeed) +{ + int ret; + QDF_STATUS status; + void *cookie; + struct link_speed_info *linkspeed_info; + struct osif_request *request; + struct linkspeed_priv *priv; + struct hdd_adapter *adapter = link_info->adapter; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + if (!linkspeed) { + hdd_err("NULL argument"); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + ret = -ENOMEM; + goto return_cached_value; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + linkspeed_info = &priv->linkspeed_info; + qdf_copy_macaddr(&linkspeed_info->peer_macaddr, mac_address); + status = sme_get_link_speed(adapter->hdd_ctx->mac_handle, + linkspeed_info, + cookie, hdd_get_link_speed_cb); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Unable to retrieve statistics for link speed"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving link speed"); + goto cleanup; + } + link_info->estimated_linkspeed = linkspeed_info->estLinkSpeed; + +cleanup: + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + osif_request_put(request); + +return_cached_value: + *linkspeed = link_info->estimated_linkspeed; + + return ret; +} + +static uint32_t +wlan_hdd_get_per_link_speed(struct wlan_hdd_link_info *link_info) +{ + uint32_t link_speed; + struct qdf_mac_addr bssid; + + if (!hdd_cm_is_vdev_associated(link_info)) { + /* we are not connected so we don't have a classAstats */ + hdd_debug("Not connected"); + return 0; + } + qdf_copy_macaddr(&bssid, + &link_info->session.station.conn_info.bssid); + + if (wlan_hdd_get_linkspeed_for_peermac(link_info, + &bssid, &link_speed)) { + hdd_err("Unable to retrieve SME linkspeed"); + return 0; + } + hdd_debug("linkspeed = %d", link_speed); + return link_speed; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +#ifndef WLAN_HDD_MULTI_VDEV_SINGLE_NDEV +static uint32_t +wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter) +{ + struct hdd_adapter *ml_adapter = NULL; + struct hdd_adapter *link_adapter = NULL; + struct hdd_mlo_adapter_info *mlo_adapter_info = NULL; + uint32_t link_speed = 0; + uint32_t per_speed; + uint8_t link_id; + + ml_adapter = adapter; + if (hdd_adapter_is_link_adapter(ml_adapter)) + ml_adapter = hdd_adapter_get_mlo_adapter_from_link(adapter); + + mlo_adapter_info = &ml_adapter->mlo_adapter_info; + for (link_id = 0; link_id < WLAN_MAX_MLD; link_id++) { + link_adapter = mlo_adapter_info->link_adapter[link_id]; + if (qdf_unlikely(!link_adapter)) { + hdd_err("link_adapter[%d] is Null", link_id); + continue; + } + per_speed = wlan_hdd_get_per_link_speed(ml_adapter->deflink); + link_speed += per_speed; + hdd_debug("Link%d speed=%d, total speed=%d", + link_id, per_speed, link_speed); + } + return link_speed; +} +#else +static uint32_t +wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info = NULL; + uint32_t link_speed = 0; + uint32_t per_speed; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + per_speed = wlan_hdd_get_per_link_speed(link_info); + link_speed += per_speed; + hdd_debug("per_speed=%d, link_speed=%d", per_speed, link_speed); + } + return link_speed; +} +#endif + +#else +static uint32_t +wlan_hdd_get_mlo_link_speed(struct hdd_adapter *adapter) +{ + uint32_t link_speed = wlan_hdd_get_per_link_speed(adapter->deflink); + + hdd_debug("Not support MLO, linkspeed = %d", link_speed); + return link_speed; +} +#endif + +int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info, + uint32_t *link_speed) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter); + int ret; + + ret = wlan_hdd_validate_context(hddctx); + if (ret) + return ret; + + /* Linkspeed is allowed for CLIENT/STA mode */ + if (adapter->device_mode != QDF_P2P_CLIENT_MODE && + adapter->device_mode != QDF_STA_MODE) { + hdd_err("Link Speed is not allowed in Device mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -ENOTSUPP; + } + + if (wlan_hdd_is_mlo_connection(link_info)) + *link_speed = wlan_hdd_get_mlo_link_speed(adapter); + else + *link_speed = wlan_hdd_get_per_link_speed(link_info); + + /* linkspeed in units of 500 kbps */ + *link_speed = (*link_speed) / 500; + return 0; +} + +int wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info *link_info, + uint32_t *link_speed, + uint8_t *command, + uint8_t command_len) +{ + int ret; + struct qdf_mac_addr mac_address; + char macaddr_string[MAC_ADDRESS_STR_LEN + 1]; + uint8_t *value = command; + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_station_info *sta_info, *tmp = NULL; + + value = value + command_len; + ret = sscanf(value, "%17s", macaddr_string); + + if (ret != 1) + return -EINVAL; + + macaddr_string[MAC_ADDRESS_STR_LEN - 1] = '\0'; + if (!mac_pton(macaddr_string, mac_address.bytes)) { + hdd_err("String to Hex conversion Failed"); + return -EINVAL; + } + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta_info, tmp, + STA_INFO_GET_SOFTAP_LINKSPEED) { + if (!qdf_is_macaddr_broadcast(&sta_info->sta_mac)) { + if (qdf_is_macaddr_equal(&mac_address, + &sta_info->sta_mac)) { + ret = wlan_hdd_get_linkspeed_for_peermac( + adapter->deflink, + &mac_address, + link_speed); + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &sta_info, true, + STA_INFO_GET_SOFTAP_LINKSPEED); + if (tmp) + hdd_put_sta_info_ref( + &adapter->sta_info_list, + &tmp, true, + STA_INFO_GET_SOFTAP_LINKSPEED); + break; + } + } + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta_info, true, + STA_INFO_GET_SOFTAP_LINKSPEED); + } + + if (ret) { + hdd_err("Unable to retrieve SAP/GO linkspeed"); + return ret; + } + + *link_speed = (*link_speed) / 500; + return 0; +} +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * wlan_hdd_get_per_peer_stats - get per peer stats if supported by FW + * @link_info: Link info pointer of STA adapter to get stats for + * @peer_stats: Pointer to peer_stats + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wlan_hdd_get_per_peer_stats(struct wlan_hdd_link_info *link_info, + struct cdp_peer_stats *peer_stats) +{ + QDF_STATUS status; + ol_txrx_soc_handle soc; + uint8_t *peer_mac; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + if (wlan_hdd_validate_context(hdd_ctx)) { + hdd_err("invalid hdd_ctx"); + return QDF_STATUS_E_FAILURE; + } + + soc = cds_get_context(QDF_MODULE_ID_SOC); + peer_mac = link_info->session.station.conn_info.bssid.bytes; + + if (!wlan_hdd_is_per_link_stats_supported(hdd_ctx)) { + hdd_debug("mlo per link stats is not supported by FW"); + status = cdp_host_get_peer_stats(soc, link_info->vdev_id, + peer_mac, peer_stats); + return status; + } + + status = ucfg_dp_get_per_link_peer_stats(soc, link_info->vdev_id, + peer_mac, peer_stats, + CDP_WILD_PEER_TYPE, + WLAN_MAX_MLD); + return status; +} + +void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info) +{ + struct cdp_peer_stats *peer_stats; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + struct hdd_stats *hdd_stats = &link_info->hdd_stats; + + psoc = link_info->adapter->hdd_ctx->psoc; + if (!ucfg_mlme_stats_is_link_speed_report_actual(psoc)) + return; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) { + hdd_err("Failed to malloc peer_stats"); + return; + } + + /* + * If failed to get RX rates info, assign an invalid value to the + * preamble, used to tell driver to report max rates. The rx_rate + * and rx_mcs_index are also assigned with tx_rate and tx_mcs_index + * if they are invalid after ASSOC/REASSOC/ROAMING + */ + status = wlan_hdd_get_per_peer_stats(link_info, peer_stats); + if (qdf_unlikely(QDF_IS_STATUS_ERROR(status)) || + qdf_unlikely(peer_stats->rx.last_rx_rate == 0)) { + hdd_debug("Driver failed to get rx rates, rx mcs=%d, status=%d", + hdd_stats->class_a_stat.rx_mcs_index, status); + hdd_stats->class_a_stat.rx_preamble = INVALID_PREAMBLE; + if (hdd_stats->class_a_stat.rx_mcs_index == INVALID_MCS_IDX) { + hdd_stats->class_a_stat.rx_rate = + hdd_stats->class_a_stat.tx_rate; + hdd_stats->class_a_stat.rx_mcs_index = + hdd_stats->class_a_stat.tx_mcs_index; + } + qdf_mem_free(peer_stats); + return; + } + + /* + * The linkspeed calculated by driver is in kbps so we + * convert it in units of 100 kbps expected by userspace + */ + hdd_stats->class_a_stat.rx_rate = peer_stats->rx.last_rx_rate / 100; + hdd_stats->class_a_stat.rx_mcs_index = peer_stats->rx.mcs_info; + hdd_stats->class_a_stat.rx_nss = peer_stats->rx.nss_info; + hdd_stats->class_a_stat.rx_gi = peer_stats->rx.gi_info; + hdd_stats->class_a_stat.rx_preamble = peer_stats->rx.preamble_info; + hdd_stats->class_a_stat.rx_bw = peer_stats->rx.bw_info; + + qdf_mem_free(peer_stats); +} +#endif + +int wlan_hdd_get_station_stats(struct wlan_hdd_link_info *link_info) +{ + int ret = 0; + struct stats_event *stats; + struct wlan_objmgr_vdev *vdev; + + if (!get_station_fw_request_needed) { + hdd_debug("return cached get_station stats"); + return 0; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) + return -EINVAL; + + stats = wlan_cfg80211_mc_cp_stats_get_station_stats(vdev, &ret); + if (ret || !stats) { + hdd_err("Invalid stats"); + goto out; + } + + if (!stats->vdev_summary_stats || !stats->vdev_chain_rssi || + !stats->peer_adv_stats || !stats->pdev_stats) { + hdd_err("Invalid:%s%s%s%s", + stats->vdev_summary_stats ? "" : " vdev_summary_stats", + stats->vdev_chain_rssi ? "" : " vdev_chain_rssi", + stats->peer_adv_stats ? "" : " peer_adv_stats", + stats->pdev_stats ? "" : " pdev_stats"); + ret = -EINVAL; + goto out; + } + + /* update get stats cached time stamp */ + hdd_update_station_stats_cached_timestamp(link_info->adapter); + hdd_update_link_state_cached_timestamp(link_info->adapter); + copy_station_stats_to_adapter(link_info, stats); +out: + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return ret; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +int wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info *link_info) +{ + int ret = 0; + struct big_data_stats_event *big_data_stats; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) + return -EINVAL; + + big_data_stats = wlan_cfg80211_mc_cp_get_big_data_stats(vdev, &ret); + if (ret || !big_data_stats) + goto out; + + copy_station_big_data_stats_to_adapter(link_info, big_data_stats); +out: + if (big_data_stats) + wlan_cfg80211_mc_cp_stats_free_big_data_stats_event( + big_data_stats); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + return ret; +} +#endif + +struct temperature_priv { + int temperature; +}; + +/** + * hdd_get_temperature_cb() - "Get Temperature" callback function + * @temperature: measured temperature + * @context: callback context + * + * This function is passed to sme_get_temperature() as the callback + * function to be invoked when the temperature measurement is + * available. + * + * Return: None + */ +static void hdd_get_temperature_cb(int temperature, void *context) +{ + struct osif_request *request; + struct temperature_priv *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->temperature = temperature; + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); +} + +int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature) +{ + QDF_STATUS status; + int ret; + void *cookie; + struct osif_request *request; + struct temperature_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + + hdd_enter(); + if (!adapter) { + hdd_err("adapter is NULL"); + return -EPERM; + } + + if (!wlan_psoc_nif_fw_ext_cap_get(adapter->hdd_ctx->psoc, + WLAN_SOC_CEXT_TT_SUPPORT)) { + hdd_err("WMI_SERVICE_THERM_THROT service from FW is disable"); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + status = sme_get_temperature(adapter->hdd_ctx->mac_handle, cookie, + hdd_get_temperature_cb); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("Unable to retrieve temperature"); + } else { + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("SME timed out while retrieving temperature"); + } else { + /* update the adapter with the fresh results */ + priv = osif_request_priv(request); + if (priv->temperature) + adapter->temperature = priv->temperature; + } + } + + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + osif_request_put(request); + + *temperature = adapter->temperature; + hdd_exit(); + return 0; +} + +#ifdef TX_MULTIQ_PER_AC +void wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context, + qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + struct hdd_tx_rx_stats *stats; + uint32_t total_inv_sk_and_skb_hash = 0; + uint32_t total_qselect_existing_skb_hash = 0; + uint32_t total_qselect_sk_tx_map = 0; + uint32_t total_qselect_skb_hash = 0; + unsigned int i; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) { + hdd_err("adapter is null"); + return; + } + + link_info = adapter->deflink; + + stats = &link_info->hdd_stats.tx_rx_stats; + + for (i = 0; i < NUM_CPUS; i++) { + total_inv_sk_and_skb_hash += + stats->per_cpu[i].inv_sk_and_skb_hash; + total_qselect_existing_skb_hash += + stats->per_cpu[i].qselect_existing_skb_hash; + total_qselect_sk_tx_map += stats->per_cpu[i].qselect_sk_tx_map; + total_qselect_skb_hash += + stats->per_cpu[i].qselect_skb_hash_calc; + } + + hdd_debug("TX_MULTIQ: INV %u skb_hash %u sk_tx_map %u skb_hash_calc %u", + total_inv_sk_and_skb_hash, total_qselect_existing_skb_hash, + total_qselect_sk_tx_map, total_qselect_skb_hash); +} +#endif + +#ifdef QCA_SUPPORT_CP_STATS +/** + * hdd_lost_link_cp_stats_info_cb() - callback function to get lost + * link information + * @stats_ev: Stats event pointer + * FW sends vdev stats on vdev down, this callback is registered + * with cp_stats component to get the last available vdev stats + * From the FW. + * + * Return: None + */ + +static void hdd_lost_link_cp_stats_info_cb(void *stats_ev) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct stats_event *ev = stats_ev; + uint8_t i, vdev_id; + int8_t rssi; + struct hdd_station_ctx *sta_ctx; + struct wlan_hdd_link_info *link_info; + struct qdf_mac_addr *mac_addr; + + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + for (i = 0; i < ev->num_summary_stats; i++) { + vdev_id = ev->vdev_summary_stats[i].vdev_id; + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_debug("invalid vdev %d", vdev_id); + continue; + } + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + + rssi = ev->vdev_summary_stats[i].stats.rssi; + if (rssi == 0) { + hdd_debug_rl("Invalid RSSI value sent by FW"); + return; + } + link_info->rssi_on_disconnect = rssi; + sta_ctx->cache_conn_info.signal = rssi; + + mac_addr = hdd_adapter_get_link_mac_addr(link_info); + if (!mac_addr) + return; + + hdd_debug("rssi %d for " QDF_MAC_ADDR_FMT, + link_info->rssi_on_disconnect, + QDF_MAC_ADDR_REF(&mac_addr->bytes[0])); + + } +} + +void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx) +{ + ucfg_mc_cp_stats_register_lost_link_info_cb( + hdd_ctx->psoc, + hdd_lost_link_cp_stats_info_cb); +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_ROAM_INFO_STATS) +#define ROAM_CACHED_STATS_MAX QCA_WLAN_VENDOR_ATTR_ROAM_CACHED_STATS_MAX + +#define EVENTS_CONFIGURE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_CONFIGURE +#define SUSPEND_STATE QCA_WLAN_VENDOR_ATTR_ROAM_EVENTS_SUSPEND_STATE + +#define ROAM_STATS_ROAM_TRIGGER_TIMESTAMP \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_TRIGGER_TIMESTAMP +#define ROAM_STATS_TRIGGER_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TRIGGER_REASON +#define ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT +#define ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT +#define ROAM_STATS_FINAL_BMISS_CNT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FINAL_BMISS_CNT +#define ROAM_STATS_CONSECUTIVE_BMISS_CNT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONSECUTIVE_BMISS_CNT +#define ROAM_STATS_BMISS_QOS_NULL_SUCCESS \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BMISS_QOS_NULL_SUCCESS +#define ROAM_STATS_POOR_RSSI_CURRENT_RSSI \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_CURRENT_RSSI +#define ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD +#define ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS +#define ROAM_STATS_BETTER_RSSI_CURRENT_RSSI \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_CURRENT_RSSI +#define ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD +#define ROAM_STATS_CONGESTION_RX_TPUT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_RX_TPUT +#define ROAM_STATS_CONGESTION_TX_TPUT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_TX_TPUT +#define ROAM_STATS_CONGESTION_ROAMABLE_CNT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_CONGESTION_ROAMABLE_CNT +#define ROAM_STATS_USER_TRIGGER_INVOKE_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_USER_TRIGGER_INVOKE_REASON +#define ROAM_STATS_BTM_REQUEST_MODE \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQUEST_MODE +#define ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME +#define ROAM_STATS_BTM_VALID_INTERNAL \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_VALID_INTERNAL +#define ROAM_STATS_BTM_CANDIDATE_LIST_CNT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_CANDIDATE_LIST_CNT +#define ROAM_STATS_BTM_RESPONSE_STATUS_CODE \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_RESPONSE_STATUS_CODE +#define ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT +#define ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT +#define ROAM_STATS_BTM_REQ_DIALOG_TOKEN \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BTM_REQ_DIALOG_TOKEN +#define ROAM_STATS_BSS_CU_LOAD \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BSS_CU_LOAD +#define ROAM_STATS_DISCONNECTION_TYPE \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_TYPE +#define ROAM_STATS_DISCONNECTION_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DISCONNECTION_REASON +#define ROAM_STATS_PERIODIC_TIMER_MS \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_PERIODIC_TIMER_MS +#define ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI +#define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI +#define ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_THRESH +#define ROAM_STATS_TX_FAILURES_THRESHOLD \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_THRESHOLD +#define ROAM_STATS_TX_FAILURES_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TX_FAILURES_REASON +#define ROAM_STATS_ABORT_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ABORT_REASON +#define ROAM_STATS_DATA_RSSI \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI +#define ROAM_STATS_DATA_RSSI_THRESHOLD \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RSSI_THRESHOLD +#define ROAM_STATS_DATA_RX_LINKSPEED_STATUS \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_DATA_RX_LINKSPEED_STATUS +#define ROAM_STATS_SCAN_TYPE \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_TYPE +#define ROAM_STATS_ROAM_STATUS \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAM_STATUS +#define ROAM_STATS_FAIL_REASON \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FAIL_REASON +#define ROAM_STATS_SCAN_CHAN_INFO \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHAN_INFO +#define ROAM_STATS_TOTAL_SCAN_TIME \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_TOTAL_SCAN_TIME +#define ROAM_STATS_FRAME_INFO \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_INFO +#define ROAM_STATS_SCAN_CHANNEL_FREQ \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_CHANNEL_FREQ +#define ROAM_STATS_SCAN_DWELL_TYPE \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_SCAN_DWELL_TYPE +#define ROAM_STATS_MAX_DWELL_TIME \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_MAX_DWELL_TIME +#define ROAM_STATS_FRAME_SUBTYPE \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_SUBTYPE +#define ROAM_STATS_FRAME_STATUS \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_STATUS +#define ROAM_STATS_FRAME_TIMESTAMP \ + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_TIMESTAMP +#define ROAM_STATS_EVENT_INDEX \ + QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS_INDEX + +static enum qca_roam_reason +hdd_convert_roam_trigger_reason(enum roam_trigger_reason reason) +{ + switch (reason) { + case ROAM_TRIGGER_REASON_NONE: + return QCA_ROAM_REASON_UNKNOWN; + case ROAM_TRIGGER_REASON_PER: + return QCA_ROAM_REASON_PER; + case ROAM_TRIGGER_REASON_BMISS: + return QCA_ROAM_REASON_BEACON_MISS; + case ROAM_TRIGGER_REASON_LOW_RSSI: + return QCA_ROAM_REASON_POOR_RSSI; + case ROAM_TRIGGER_REASON_HIGH_RSSI: + return QCA_ROAM_REASON_BETTER_RSSI; + case ROAM_TRIGGER_REASON_PERIODIC: + return QCA_ROAM_REASON_PERIODIC_TIMER; + case ROAM_TRIGGER_REASON_DENSE: + return QCA_ROAM_REASON_CONGESTION; + case ROAM_TRIGGER_REASON_BACKGROUND: + return QCA_ROAM_REASON_BACKGROUND_SCAN; + case ROAM_TRIGGER_REASON_FORCED: + return QCA_ROAM_REASON_USER_TRIGGER; + case ROAM_TRIGGER_REASON_BTM: + return QCA_ROAM_REASON_BTM; + case ROAM_TRIGGER_REASON_BSS_LOAD: + return QCA_ROAM_REASON_BSS_LOAD; + case ROAM_TRIGGER_REASON_DEAUTH: + return QCA_ROAM_REASON_DISCONNECTION; + case ROAM_TRIGGER_REASON_STA_KICKOUT: + return QCA_ROAM_REASON_STA_KICKOUT; + default: + hdd_err("Invalid invoke reason received: %d", reason); + break; + } + + return QCA_ROAM_REASON_UNKNOWN; +} + +static enum qca_wlan_roam_stats_invoke_reason +hdd_convert_roam_invoke_reason(enum roam_invoke_reason invoke) +{ + switch (invoke) { + case WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED: + return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED; + case WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE: + return QCA_WLAN_ROAM_STATS_INVOKE_REASON_NUD_FAILURE; + case WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE: + return QCA_WLAN_ROAM_STATS_INVOKE_REASON_USER_SPACE; + default: + hdd_err("Invalid invoke reason received: %d", invoke); + break; + } + + return QCA_WLAN_ROAM_STATS_INVOKE_REASON_UNDEFINED; +} + +static enum qca_wlan_roam_stats_tx_failures_reason +hdd_convert_roam_tx_failures_reason(enum roam_tx_failures_reason tx_failures) +{ + switch (tx_failures) { + case WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED; + case WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_XRETRY; + case WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_INACTIVITY; + case WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_IBSS_DISCONNECT; + case WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_TDLS_DISCONNECT; + case WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_SA_QUERY_TIMEOUT; + case WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT: + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_ROAMING_EVENT; + default: + hdd_err("Invalid tx_failures reason received: %d", tx_failures); + break; + } + + return QCA_WLAN_ROAM_STATS_KICKOUT_REASON_UNSPECIFIED; +} + +static enum qca_wlan_roam_stats_abort_reason +hdd_convert_roam_abort_reason(enum roam_abort_reason abort) +{ + switch (abort) { + case WLAN_ROAM_STATS_ABORT_UNSPECIFIED: + return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED; + case WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH: + return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_DATA_RSSI_HIGH; + case WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD: + return QCA_WLAN_ROAM_STATS_ABORT_LOWRSSI_LINK_SPEED_GOOD; + case WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH: + return QCA_WLAN_ROAM_STATS_ABORT_BG_DATA_RSSI_HIGH; + case WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD: + return QCA_WLAN_ROAM_STATS_ABORT_BG_RSSI_ABOVE_THRESHOLD; + default: + hdd_err("Invalid abort reason received: %d", abort); + break; + } + + return QCA_WLAN_ROAM_STATS_ABORT_UNSPECIFIED; +} + +static enum qca_wlan_roam_stats_scan_type +hdd_convert_roam_scan_type(enum roam_stats_scan_type type) +{ + switch (type) { + case ROAM_STATS_SCAN_TYPE_PARTIAL: + return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL; + case ROAM_STATS_SCAN_TYPE_FULL: + return QCA_WLAN_ROAM_STATS_SCAN_TYPE_FULL; + case ROAM_STATS_SCAN_TYPE_NO_SCAN: + return QCA_WLAN_ROAM_STATS_SCAN_TYPE_NO_SCAN; + case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ: + return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_5GHZ_6GHZ; + case ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ: + return QCA_WLAN_ROAM_STATS_SCAN_TYPE_HIGHER_BAND_6GHZ; + default: + hdd_err("Invalid roam scan type received: %d", type); + break; + } + + return QCA_WLAN_ROAM_STATS_SCAN_TYPE_PARTIAL; +} + +static enum qca_wlan_roam_stats_scan_dwell_type +hdd_convert_roam_chn_dwell_type(enum roam_scan_dwell_type type) +{ + switch (type) { + case WLAN_ROAM_DWELL_TYPE_UNSPECIFIED: + return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED; + case WLAN_ROAM_DWELL_ACTIVE_TYPE: + return QCA_WLAN_ROAM_STATS_DWELL_TYPE_ACTIVE; + case WLAN_ROAM_DWELL_PASSIVE_TYPE: + return QCA_WLAN_ROAM_STATS_DWELL_TYPE_PASSIVE; + default: + hdd_err("Invalid abort reason received: %d", type); + break; + } + + return QCA_WLAN_ROAM_STATS_DWELL_TYPE_UNSPECIFIED; +} + +static enum qca_wlan_roam_stats_frame_subtype +hdd_convert_roam_frame_type(enum eroam_frame_subtype type) +{ + switch (type) { + case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_RESP; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_REQ; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_REASSOC_RESP; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M1; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M2; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M3; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_M4; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M1; + case WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2: + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_EAPOL_GTK_M2; + default: + hdd_err_rl("Invalid roam frame type received: %d", type); + break; + } + + return QCA_WLAN_ROAM_STATS_FRAME_SUBTYPE_AUTH_REQ; +}; + +static enum qca_wlan_roam_stats_frame_status +hdd_convert_roam_frame_status(enum eroam_frame_status status) +{ + switch (status) { + case WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS: + return QCA_WLAN_ROAM_STATS_FRAME_STATUS_SUCCESS; + case WLAN_ROAM_STATS_FRAME_STATUS_FAIL: + return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL; + default: + hdd_err("Invalid roam frame status received: %d", status); + break; + } + + return QCA_WLAN_ROAM_STATS_FRAME_STATUS_FAIL; +}; + +static enum qca_vendor_roam_fail_reasons +hdd_convert_roam_failures_reason(enum wlan_roam_failure_reason_code fail) +{ + switch (fail) { + case ROAM_FAIL_REASON_NO_SCAN_START: + return QCA_ROAM_FAIL_REASON_SCAN_NOT_ALLOWED; + case ROAM_FAIL_REASON_NO_AP_FOUND: + return QCA_ROAM_FAIL_REASON_NO_AP_FOUND; + case ROAM_FAIL_REASON_NO_CAND_AP_FOUND: + return QCA_ROAM_FAIL_REASON_NO_CAND_AP_FOUND; + case ROAM_FAIL_REASON_HOST: + return QCA_ROAM_FAIL_REASON_HOST; + case ROAM_FAIL_REASON_AUTH_SEND: + return QCA_ROAM_FAIL_REASON_AUTH_SEND; + case ROAM_FAIL_REASON_NO_AUTH_RESP: + return QCA_ROAM_FAIL_REASON_NO_AUTH_RESP; + case ROAM_FAIL_REASON_AUTH_RECV: + return QCA_ROAM_FAIL_REASON_AUTH_RECV; + case ROAM_FAIL_REASON_REASSOC_SEND: + return QCA_ROAM_FAIL_REASON_REASSOC_SEND; + case ROAM_FAIL_REASON_REASSOC_RECV: + return QCA_ROAM_FAIL_REASON_REASSOC_RECV; + case ROAM_FAIL_REASON_NO_REASSOC_RESP: + return QCA_ROAM_FAIL_REASON_NO_REASSOC_RESP; + case ROAM_FAIL_REASON_EAPOL_TIMEOUT: + return QCA_ROAM_FAIL_REASON_EAPOL_M1_TIMEOUT; + case ROAM_FAIL_REASON_SCAN_START: + return QCA_ROAM_FAIL_REASON_SCAN_FAIL; + case ROAM_FAIL_REASON_AUTH_NO_ACK: + return QCA_ROAM_FAIL_REASON_AUTH_NO_ACK; + case ROAM_FAIL_REASON_AUTH_INTERNAL_DROP: + return QCA_ROAM_FAIL_REASON_AUTH_INTERNAL_DROP; + case ROAM_FAIL_REASON_REASSOC_NO_ACK: + return QCA_ROAM_FAIL_REASON_REASSOC_NO_ACK; + case ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP: + return QCA_ROAM_FAIL_REASON_REASSOC_INTERNAL_DROP; + case ROAM_FAIL_REASON_EAPOL_M2_SEND: + return QCA_ROAM_FAIL_REASON_EAPOL_M2_SEND; + case ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP: + return QCA_ROAM_FAIL_REASON_EAPOL_M2_INTERNAL_DROP; + case ROAM_FAIL_REASON_EAPOL_M2_NO_ACK: + return QCA_ROAM_FAIL_REASON_EAPOL_M2_NO_ACK; + case ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT: + return QCA_ROAM_FAIL_REASON_EAPOL_M3_TIMEOUT; + case ROAM_FAIL_REASON_EAPOL_M4_SEND: + return QCA_ROAM_FAIL_REASON_EAPOL_M4_SEND; + case ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP: + return QCA_ROAM_FAIL_REASON_EAPOL_M4_INTERNAL_DROP; + case ROAM_FAIL_REASON_EAPOL_M4_NO_ACK: + return QCA_ROAM_FAIL_REASON_EAPOL_M4_NO_ACK; + case ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BMISS: + return QCA_ROAM_FAIL_REASON_NO_SCAN_FOR_FINAL_BEACON_MISS; + case ROAM_FAIL_REASON_DISCONNECT: + return QCA_ROAM_FAIL_REASON_DISCONNECT; + case ROAM_FAIL_REASON_SYNC: + return QCA_ROAM_FAIL_REASON_RESUME_ABORT; + case ROAM_FAIL_REASON_SAE_INVALID_PMKID: + return QCA_ROAM_FAIL_REASON_SAE_INVALID_PMKID; + case ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT: + return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_TIMEOUT; + case ROAM_FAIL_REASON_SAE_PREAUTH_FAIL: + return QCA_ROAM_FAIL_REASON_SAE_PREAUTH_FAIL; + case ROAM_FAIL_REASON_CURR_AP_STILL_OK: + return QCA_ROAM_FAIL_REASON_CURR_AP_STILL_OK; + case ROAM_FAIL_REASON_MLME: + case ROAM_FAIL_REASON_INTERNAL_ABORT: + case ROAM_FAIL_REASON_UNABLE_TO_START_ROAM_HO: + case ROAM_FAIL_REASON_NO_AP_FOUND_AND_FINAL_BMISS_SENT: + case ROAM_FAIL_REASON_NO_CAND_AP_FOUND_AND_FINAL_BMISS_SENT: + case ROAM_FAIL_REASON_SCAN_CANCEL: + case ROAM_FAIL_REASON_SCREEN_ACTIVITY: + case ROAM_FAIL_REASON_OTHER_PRIORITY_ROAM_SCAN: + case ROAM_FAIL_REASON_UNKNOWN: + hdd_err("Invalid roam failures reason"); + break; + } + + return QCA_ROAM_FAIL_REASON_NONE; +} + +/** + * hdd_get_roam_stats_individual_record_len() - calculates the required length + * of an individual record of roaming stats + * + * @roam_info: pointer to roam info + * @index: index of roam info cached in driver + * + * Return: required length of an individual record of roaming stats + */ +static uint32_t +hdd_get_roam_stats_individual_record_len(struct enhance_roam_info *roam_info, + uint32_t index) +{ + struct enhance_roam_info *info; + enum qca_roam_reason vendor_trigger_reason; + uint32_t len, i; + + if (!roam_info) { + hdd_err("invalid param"); + return 0; + } + + info = &roam_info[index]; + vendor_trigger_reason = + hdd_convert_roam_trigger_reason(info->trigger.trigger_reason); + + len = 0; + /* ROAM_STATS_ROAM_TRIGGER_TIMESTAMP */ + len += nla_total_size_64bit(sizeof(uint64_t)); + /* ROAM_STATS_TRIGGER_REASON */ + len += nla_total_size(sizeof(uint32_t)); + + switch (vendor_trigger_reason) { + case QCA_ROAM_REASON_PER: + /* ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_BEACON_MISS: + /* ROAM_STATS_FINAL_BMISS_CNT */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_CONSECUTIVE_BMISS_CNT */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_BMISS_QOS_NULL_SUCCESS */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_POOR_RSSI: + /* ROAM_STATS_POOR_RSSI_CURRENT_RSSI */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_BETTER_RSSI: + /* ROAM_STATS_BETTER_RSSI_CURRENT_RSSI */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD */ + len += nla_total_size(sizeof(int8_t)); + break; + case QCA_ROAM_REASON_PERIODIC_TIMER: + /* ROAM_STATS_PERIODIC_TIMER_MS */ + len += nla_total_size(sizeof(uint32_t)); + break; + case QCA_ROAM_REASON_CONGESTION: + /* ROAM_STATS_CONGESTION_RX_TPUT */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_CONGESTION_TX_TPUT */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_CONGESTION_ROAMABLE_CNT */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_BACKGROUND_SCAN: + /* ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH */ + len += nla_total_size(sizeof(int8_t)); + break; + case QCA_ROAM_REASON_USER_TRIGGER: + /* ROAM_STATS_USER_TRIGGER_INVOKE_REASON */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_BTM: + /* ROAM_STATS_BTM_REQUEST_MODE */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_BTM_VALID_INTERNAL */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_BTM_CANDIDATE_LIST_CNT */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_BTM_RESPONSE_STATUS_CODE */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_BTM_REQ_DIALOG_TOKEN */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_BSS_LOAD: + /* ROAM_STATS_BSS_CU_LOAD */ + len += nla_total_size(sizeof(uint8_t)); + break; + case QCA_ROAM_REASON_DISCONNECTION: + /* ROAM_STATS_DISCONNECTION_TYPE */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_DISCONNECTION_REASON */ + len += nla_total_size(sizeof(uint16_t)); + break; + case QCA_ROAM_REASON_STA_KICKOUT: + /* ROAM_STATS_TX_FAILURES_THRESHOLD */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_TX_FAILURES_REASON */ + len += nla_total_size(sizeof(uint8_t)); + break; + default: + break; + } + + /* ROAM_STATS_SCAN_TYPE */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_ROAM_STATUS */ + len += nla_total_size(sizeof(uint8_t)); + + if (info->trigger.roam_status) { + /* ROAM_STATS_FAIL_REASON */ + len += nla_total_size(sizeof(uint8_t)); + if (info->trigger.abort.abort_reason_code) { + /* ROAM_STATS_ABORT_REASON */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_DATA_RSSI */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_DATA_RSSI_THRESHOLD */ + len += nla_total_size(sizeof(int8_t)); + /* ROAM_STATS_DATA_RX_LINKSPEED_STATUS */ + len += nla_total_size(sizeof(uint8_t)); + } + } + + /* ROAM_STATS_SCAN_CHAN_INFO */ + len += nla_total_size(0); + for (i = 0; i < info->scan.num_channels; i++) { + /* nest attribute */ + len += nla_total_size(0); + /* ROAM_STATS_SCAN_CHANNEL_FREQ */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_SCAN_DWELL_TYPE */ + len += nla_total_size(sizeof(uint32_t)); + /* ROAM_STATS_MAX_DWELL_TIME */ + len += nla_total_size(sizeof(uint32_t)); + } + + /* ROAM_STATS_TOTAL_SCAN_TIME */ + len += nla_total_size(sizeof(uint32_t)); + + /* ROAM_STATS_FRAME_INFO */ + len += nla_total_size(0); + for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) { + /* nest attribute */ + len += nla_total_size(0); + /* ROAM_STATS_FRAME_SUBTYPE */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_FRAME_STATUS */ + len += nla_total_size(sizeof(uint8_t)); + /* ROAM_STATS_FRAME_TIMESTAMP */ + len += nla_total_size_64bit(sizeof(uint64_t)); + } + + return len; +} + +/** + * hdd_get_roam_stats_info_len() - calculate the length required by skb + * @roam_info: pointer to roam info + * @roam_cache_num: roam cache number + * + * Calculate the required length to send roam stats to upper layer + * + * Return: required len + */ +static uint32_t +hdd_get_roam_stats_info_len(struct enhance_roam_info *roam_info, + uint8_t roam_cache_num) +{ + uint32_t len, i; + + len = 0; + /* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */ + len += nla_total_size(0); + for (i = 0; i < roam_cache_num; i++) { + /* nest attribute */ + len += nla_total_size(0); + len += hdd_get_roam_stats_individual_record_len(roam_info, i); + } + + return len; +} + +/** + * hdd_nla_put_roam_stats_info() - put roam statistics info attribute + * values to userspace + * + * @skb: pointer to sk buff + * @roam_info: pointer to roam info + * @index: index of roam info cached in driver + * + * Return: 0 if success else error status + */ +static int hdd_nla_put_roam_stats_info(struct sk_buff *skb, + struct enhance_roam_info *roam_info, + uint32_t index) +{ + struct nlattr *roam_chn_info, *roam_chn; + struct nlattr *roam_frame_info, *roam_frame; + struct enhance_roam_info *info; + enum roam_invoke_reason driver_invoke_reason; + enum qca_wlan_roam_stats_invoke_reason vendor_invoke_reason; + enum roam_tx_failures_reason driver_tx_failures_reason; + enum qca_wlan_roam_stats_tx_failures_reason vendor_tx_failures_reason; + enum roam_abort_reason driver_abort_reason; + enum qca_wlan_roam_stats_abort_reason vendor_abort_reason; + enum qca_wlan_roam_stats_scan_type vendor_scan_type; + enum roam_scan_dwell_type driver_dwell_type; + enum qca_wlan_roam_stats_scan_dwell_type vendor_dwell_type; + enum eroam_frame_subtype driver_frame_type; + enum qca_wlan_roam_stats_frame_subtype vendor_frame_type; + enum eroam_frame_status driver_frame_status; + enum qca_wlan_roam_stats_frame_status vendor_frame_status; + enum qca_roam_reason vendor_trigger_reason; + enum qca_vendor_roam_fail_reasons vendor_fail_reason; + uint32_t i; + int ret; + + if (!roam_info) { + hdd_err("invalid param"); + return -EINVAL; + } + info = &roam_info[index]; + + vendor_trigger_reason = + hdd_convert_roam_trigger_reason(info->trigger.trigger_reason); + + if (wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_ROAM_TRIGGER_TIMESTAMP, + info->trigger.timestamp)) { + hdd_err("timestamp put fail"); + return -EINVAL; + } + + if (nla_put_u32(skb, ROAM_STATS_TRIGGER_REASON, vendor_trigger_reason)) { + hdd_err(" put fail"); + return -EINVAL; + } + + switch (vendor_trigger_reason) { + case QCA_ROAM_REASON_PER: + if (nla_put_u8(skb, ROAM_STATS_PER_RXRATE_THRESHOLD_PERCENT, + info->trigger.condition.roam_per.rx_rate_thresh_percent)) { + hdd_err("roam_per.rx_rate_thresh_percent put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_PER_TXRATE_THRESHOLD_PERCENT, + info->trigger.condition.roam_per.tx_rate_thresh_percent)) { + hdd_err("roam_per.rx_rate_thresh_percent put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_BEACON_MISS: + if (nla_put_u32(skb, ROAM_STATS_FINAL_BMISS_CNT, + info->trigger.condition.roam_bmiss.final_bmiss_cnt)) { + hdd_err("roam_bmiss.final_bmiss_cnt put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_CONSECUTIVE_BMISS_CNT, + info->trigger.condition.roam_bmiss.consecutive_bmiss_cnt)) { + hdd_err("roam_bmiss.consecutive_bmiss_cnt put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_BMISS_QOS_NULL_SUCCESS, + info->trigger.condition.roam_bmiss.qos_null_success)) { + hdd_err("roam_bmiss.qos_null_success put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_POOR_RSSI: + if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_CURRENT_RSSI, + info->trigger.condition.roam_poor_rssi.current_rssi)) { + hdd_err("roam_poor_rssi.current_rssi put fail"); + return -EINVAL; + } + if (nla_put_s8(skb, ROAM_STATS_POOR_RSSI_ROAM_RSSI_THRESHOLD, + info->trigger.condition.roam_poor_rssi.roam_rssi_threshold)) { + hdd_err("roam_poor_rssi.roam_rssi_threshold put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_POOR_RSSI_RX_LINKSPEED_STATUS, + info->trigger.condition.roam_poor_rssi.rx_linkspeed_status)) { + hdd_err("roam_poor_rssi.rx_linkspeed_status put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_BETTER_RSSI: + if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_CURRENT_RSSI, + info->trigger.condition.roam_better_rssi.current_rssi)) { + hdd_err("roam_better_rssi.current_rssi put fail"); + return -EINVAL; + } + if (nla_put_s8(skb, ROAM_STATS_BETTER_RSSI_HIGH_RSSI_THRESHOLD, + info->trigger.condition.roam_better_rssi.hi_rssi_threshold)) { + hdd_err("roam_better_rssi.hi_rssi_threshold put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_PERIODIC_TIMER: + if (nla_put_u32(skb, ROAM_STATS_PERIODIC_TIMER_MS, + info->trigger.condition.roam_periodic.periodic_timer_ms)) { + hdd_err("roam_periodic.periodic_timer_ms put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_CONGESTION: + if (nla_put_u32(skb, ROAM_STATS_CONGESTION_RX_TPUT, + info->trigger.condition.roam_congestion.rx_tput)) { + hdd_err("roam_congestion.rx_tput put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_CONGESTION_TX_TPUT, + info->trigger.condition.roam_congestion.tx_tput)) { + hdd_err("roam_congestion.tx_tput put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_CONGESTION_ROAMABLE_CNT, + info->trigger.condition.roam_congestion.roamable_count)) { + hdd_err("roam_congestion.roamable_count put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_BACKGROUND_SCAN: + if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_CURRENT_RSSI, + info->trigger.condition.roam_background.current_rssi)) { + hdd_err("roam_background.current_rssi put fail"); + return -EINVAL; + } + if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI, + info->trigger.condition.roam_background.data_rssi)) { + hdd_err("roam_background.data_rssi put fail"); + return -EINVAL; + } + if (nla_put_s8(skb, ROAM_STATS_BACKGROUND_SCAN_DATA_RSSI_TH, + info->trigger.condition.roam_background.data_rssi_threshold)) { + hdd_err("roam_background.data_rssi_threshold put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_USER_TRIGGER: + driver_invoke_reason = + info->trigger.condition.roam_user_trigger.invoke_reason; + vendor_invoke_reason = hdd_convert_roam_invoke_reason(driver_invoke_reason); + if (nla_put_u8(skb, ROAM_STATS_USER_TRIGGER_INVOKE_REASON, + vendor_invoke_reason)) { + hdd_err("roam_user_trigger.invoke_reason put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_BTM: + if (nla_put_u8(skb, ROAM_STATS_BTM_REQUEST_MODE, + info->trigger.condition.roam_btm.btm_request_mode)) { + hdd_err("roam_btm.btm_request_mode put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_BTM_DISASSOC_IMMINENT_TIME, + info->trigger.condition.roam_btm.disassoc_imminent_timer)) { + hdd_err("roam_btm.disassoc_imminent_timer put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_BTM_VALID_INTERNAL, + info->trigger.condition.roam_btm.validity_internal)) { + hdd_err("roam_btm.validity_internal put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_BTM_CANDIDATE_LIST_CNT, + info->trigger.condition.roam_btm.candidate_list_count)) { + hdd_err("roam_btm.candidate_list_count put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_BTM_RESPONSE_STATUS_CODE, + info->trigger.condition.roam_btm.btm_response_status_code)) { + hdd_err("roam_btm.btm_response_status_code put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_BTM_BSS_TERMINATION_TIMEOUT, + info->trigger.condition.roam_btm.btm_bss_termination_timeout)) { + hdd_err("roam btm_bss_termination_timeout put fail"); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_BTM_MBO_ASSOC_RETRY_TIMEOUT, + info->trigger.condition.roam_btm.btm_mbo_assoc_retry_timeout)) { + hdd_err("roam btm_mbo_assoc_retry_timeout put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_BTM_REQ_DIALOG_TOKEN, + info->trigger.condition.roam_btm.btm_req_dialog_token)) { + hdd_err("roam_btm.btm_req_dialog_token put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_BSS_LOAD: + if (nla_put_u8(skb, ROAM_STATS_BSS_CU_LOAD, + info->trigger.condition.roam_bss_load.cu_load)) { + hdd_err("roam_bss_load.cu_load put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_DISCONNECTION: + if (nla_put_u8(skb, ROAM_STATS_DISCONNECTION_TYPE, + info->trigger.condition.roam_disconnection.deauth_type)) { + hdd_err("roam_disconnection.deauth_type put fail"); + return -EINVAL; + } + if (nla_put_u16(skb, ROAM_STATS_DISCONNECTION_REASON, + info->trigger.condition.roam_disconnection.deauth_reason)) { + hdd_err("roam_disconnection.deauth_reason put fail"); + return -EINVAL; + } + break; + case QCA_ROAM_REASON_STA_KICKOUT: + driver_tx_failures_reason = + info->trigger.condition.roam_tx_failures.kickout_threshold; + vendor_tx_failures_reason = + hdd_convert_roam_tx_failures_reason(driver_tx_failures_reason); + if (nla_put_u32(skb, ROAM_STATS_TX_FAILURES_THRESHOLD, + vendor_tx_failures_reason)) { + hdd_err("roam_tx_failures.kickout_threshold put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_TX_FAILURES_REASON, + info->trigger.condition.roam_tx_failures.kickout_reason)) { + hdd_err("roam_tx_failures.kickout_reason put fail"); + return -EINVAL; + } + break; + default: + break; + } + + vendor_scan_type = hdd_convert_roam_scan_type(info->trigger.roam_scan_type); + if (nla_put_u8(skb, ROAM_STATS_SCAN_TYPE, vendor_scan_type)) { + hdd_err("roam_scan_type put fail"); + return -EINVAL; + } + + if (nla_put_u8(skb, ROAM_STATS_ROAM_STATUS, + info->trigger.roam_status)) { + hdd_err("roam_status put fail"); + return -EINVAL; + } + + if (info->trigger.roam_status) { + vendor_fail_reason = hdd_convert_roam_failures_reason(info->trigger.roam_fail_reason); + if (nla_put_u8(skb, ROAM_STATS_FAIL_REASON, + vendor_fail_reason)) { + hdd_err("roam_fail_reason put fail"); + return -EINVAL; + } + + driver_abort_reason = info->trigger.abort.abort_reason_code; + vendor_abort_reason = hdd_convert_roam_abort_reason(driver_abort_reason); + if (info->trigger.abort.abort_reason_code) { + if (nla_put_u8(skb, ROAM_STATS_ABORT_REASON, vendor_abort_reason)) { + hdd_err("abort.abort_reason_code put fail"); + return -EINVAL; + } + if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI, + info->trigger.abort.data_rssi)) { + hdd_err("abort.data_rssi put fail"); + return -EINVAL; + } + if (nla_put_s8(skb, ROAM_STATS_DATA_RSSI_THRESHOLD, + info->trigger.abort.data_rssi_threshold)) { + hdd_err("abort.data_rssi_threshold put fail"); + return -EINVAL; + } + if (nla_put_u8(skb, ROAM_STATS_DATA_RX_LINKSPEED_STATUS, + info->trigger.abort.rx_linkspeed_status)) { + hdd_err("abort.rx_linkspeed_status put fail"); + return -EINVAL; + } + } + } + + roam_chn_info = nla_nest_start(skb, ROAM_STATS_SCAN_CHAN_INFO); + if (!roam_chn_info) { + hdd_err("nla_nest_start fail"); + return -EINVAL; + } + + for (i = 0; i < info->scan.num_channels; i++) { + roam_chn = nla_nest_start(skb, i); + if (!roam_chn) { + hdd_err("nla_nest_start fail"); + return -EINVAL; + } + + if (nla_put_u32(skb, ROAM_STATS_SCAN_CHANNEL_FREQ, + info->scan.roam_chn[i].chan_freq)) { + hdd_err("roam_chn[%u].chan_freq put fail", i); + return -EINVAL; + } + + driver_dwell_type = info->scan.roam_chn[i].dwell_type; + vendor_dwell_type = hdd_convert_roam_chn_dwell_type(driver_dwell_type); + if (nla_put_u32(skb, ROAM_STATS_SCAN_DWELL_TYPE, + vendor_dwell_type)) { + hdd_err("roam_chn[%u].dwell_type put fail", i); + return -EINVAL; + } + if (nla_put_u32(skb, ROAM_STATS_MAX_DWELL_TIME, + info->scan.roam_chn[i].max_dwell_time)) { + hdd_err("roam_chn[%u].max_dwell_time put fail", i); + return -EINVAL; + } + nla_nest_end(skb, roam_chn); + } + nla_nest_end(skb, roam_chn_info); + + if (nla_put_u32(skb, ROAM_STATS_TOTAL_SCAN_TIME, + info->scan.total_scan_time)) { + hdd_err("roam_scan total_scan_time put fail"); + return -EINVAL; + } + + roam_frame_info = nla_nest_start(skb, ROAM_STATS_FRAME_INFO); + if (!roam_frame_info) { + hdd_err("nla_nest_start fail"); + return -EINVAL; + } + + for (i = 0; i < WLAN_ROAM_MAX_FRAME_INFO; i++) { + if (info->timestamp[i].frame_type == + WLAN_ROAM_STATS_FRAME_SUBTYPE_INVALID) + break; + roam_frame = nla_nest_start(skb, i); + if (!roam_frame) { + hdd_err("nla_nest_start fail"); + return -EINVAL; + } + driver_frame_type = info->timestamp[i].frame_type; + vendor_frame_type = hdd_convert_roam_frame_type(driver_frame_type); + ret = nla_put_u8(skb, ROAM_STATS_FRAME_SUBTYPE, + vendor_frame_type); + if (ret) { + hdd_err("roam_frame[%u].type put fail %d", i, ret); + return -EINVAL; + } + driver_frame_status = info->timestamp[i].status; + vendor_frame_status = hdd_convert_roam_frame_status(driver_frame_status); + ret = nla_put_u8(skb, ROAM_STATS_FRAME_STATUS, + vendor_frame_status); + if (ret) { + hdd_err("frame[%u].status put fail %d", i, ret); + return -EINVAL; + } + ret = wlan_cfg80211_nla_put_u64(skb, ROAM_STATS_FRAME_TIMESTAMP, + info->timestamp[i].timestamp); + if (ret) { + hdd_err("frame[%u].timestamp put fail %d", i, ret); + return -EINVAL; + } + ret = nla_put(skb, + QCA_WLAN_VENDOR_ATTR_ROAM_STATS_FRAME_BSSID, + QDF_MAC_ADDR_SIZE, + info->timestamp[i].bssid.bytes); + if (ret) { + hdd_err("roam candidate AP bssid put fail"); + return -EINVAL; + } + + nla_nest_end(skb, roam_frame); + } + nla_nest_end(skb, roam_frame_info); + + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ORIGINAL_BSSID, + QDF_MAC_ADDR_SIZE, info->scan.original_bssid.bytes)) { + hdd_err("roam original AP bssid put fail"); + return -EINVAL; + } + if (!info->trigger.roam_status) { + if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_ROAMED_BSSID, + QDF_MAC_ADDR_SIZE, info->scan.roamed_bssid.bytes)) { + hdd_err("roam roamed AP bssid put fail"); + return -EINVAL; + } + } + + return 0; +} + +/** + * hdd_get_roam_stats_info() - get roam statistics info to userspace, + * for STA mode only + * @skb: pointer to sk buff + * @hdd_ctx: pointer to hdd context + * @roam_info: pointer to roam info + * @roam_cache_num: roam cache number + * + * Return: 0 if success else error status + */ +static int hdd_get_roam_stats_info(struct sk_buff *skb, + struct hdd_context *hdd_ctx, + struct enhance_roam_info *roam_info, + uint32_t roam_cache_num) +{ + struct nlattr *config, *roam_params; + uint32_t i; + int ret; + + config = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO); + if (!config) { + hdd_err("nla nest start failure"); + return -EINVAL; + } + + /* Send all driver cached roam info to user space one time, + * and don't flush them, since they will be cover by + * new roam event info. + */ + for (i = 0; i < roam_cache_num; i++) { + roam_params = nla_nest_start(skb, i); + if (!roam_params) + return -EINVAL; + + ret = hdd_nla_put_roam_stats_info(skb, roam_info, i); + if (ret) { + hdd_err("nla put failure"); + return -EINVAL; + } + + nla_nest_end(skb, roam_params); + } + nla_nest_end(skb, config); + + return 0; +} + +/** + * hdd_get_roam_stats() - send roam statistics info to userspace + * @hdd_ctx: pointer to hdd context + * @adapter: pointer to adapter + * + * Return: 0 if success else error status + */ +static int +hdd_get_roam_stats(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sk_buff *skb; + uint32_t skb_len; + int ret = 0; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + struct enhance_roam_info *roam_info = NULL; + uint32_t roam_num = 0; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_STATS_ID); + if (!vdev) + return -EINVAL; + + status = ucfg_cm_roam_stats_info_get(vdev, &roam_info, &roam_num); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get roam info : %d", status); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID); + return qdf_status_to_os_return(status); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID); + + skb_len = hdd_get_roam_stats_info_len(roam_info, roam_num); + if (!skb_len) { + hdd_err("No data requested"); + ucfg_cm_roam_stats_info_put(roam_info); + return -EINVAL; + } + + skb_len += NLMSG_HDRLEN; + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, skb_len); + if (!skb) { + hdd_info("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + ucfg_cm_roam_stats_info_put(roam_info); + return -ENOMEM; + } + + ret = hdd_get_roam_stats_info(skb, hdd_ctx, roam_info, roam_num); + if (ret) { + hdd_info("get roam stats fail"); + wlan_cfg80211_vendor_free_skb(skb); + ucfg_cm_roam_stats_info_put(roam_info); + return -ENOMEM; + } + + ucfg_cm_roam_stats_info_put(roam_info); + + return wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * __wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +static int +__wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int32_t status; + + hdd_enter_dev(dev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE || + hdd_get_conparam() == QDF_GLOBAL_MONITOR_MODE) { + hdd_err_rl("Command not allowed in FTM / Monitor mode"); + status = -EPERM; + goto out; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status != 0) + goto out; + + if (adapter->device_mode == QDF_STA_MODE) { + status = hdd_get_roam_stats(hdd_ctx, adapter); + } else { + hdd_err_rl("Invalid device_mode: %d", adapter->device_mode); + status = -EINVAL; + } + + hdd_exit(); +out: + return status; +} + +/** + * wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_roam_stats(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef WLAN_FEATURE_ROAM_INFO_STATS +static void +wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info *link_info, + struct roam_stats_event *roam_stats, + uint8_t idx) +{ + int status; + uint32_t data_size = 0; + struct sk_buff *vendor_event; + struct wlan_objmgr_vdev *vdev = NULL; + struct enhance_roam_info *roam_info = NULL; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + hdd_err("Invalid hdd_ctx"); + return; + } + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_STATS_ID); + if (!vdev) + return; + ucfg_cm_roam_info_get(vdev, &roam_info, idx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_STATS_ID); + + /* QCA_WLAN_VENDOR_ATTR_ROAM_STATS_INFO */ + data_size += nla_total_size(0); + /* nest attribute */ + data_size += nla_total_size(0); + + data_size += hdd_get_roam_stats_individual_record_len(roam_info, idx); + + data_size += NLMSG_HDRLEN; + + vendor_event = + wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &link_info->adapter->wdev, + data_size, + ROAM_STATS_EVENT_INDEX, + GFP_KERNEL); + + if (hdd_nla_put_roam_stats_info(vendor_event, roam_info, 0)) { + wlan_cfg80211_vendor_free_skb(vendor_event); + hdd_err("nla put failure"); + return; + } + + roam_stats->enhance_roam_rt_event = false; + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +} +#else +static void +wlan_hdd_cfg80211_enhance_roam_events_callback(struct wlan_hdd_link_info *link_info, + struct roam_stats_event *roam_stats, + uint8_t idx) +{ +} +#endif +void +wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event *roam_stats, + uint8_t idx) +{ + int status; + struct wlan_hdd_link_info *link_info; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) { + hdd_err("Invalid hdd_ctx"); + return; + } + + if (!roam_stats) { + hdd_err("msg received here is null"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, roam_stats->vdev_id); + if (!link_info) { + hdd_err("vdev_id %d does not exist with host", + roam_stats->vdev_id); + return; + } + if (roam_stats->enhance_roam_rt_event) + wlan_hdd_cfg80211_enhance_roam_events_callback(link_info, + roam_stats, idx); + else + wlan_hdd_cfg80211_typical_roam_events_callback(link_info, + roam_stats, idx); +} +#endif + +#ifdef WLAN_FEATURE_TX_LATENCY_STATS +#define TX_LATENCY_BUCKET_DISTRIBUTION_LEN \ + (sizeof(uint32_t) * CDP_TX_LATENCY_TYPE_MAX) + +#define TX_LATENCY_ATTR(_name) QCA_WLAN_VENDOR_ATTR_TX_LATENCY_ ## _name + +static const struct nla_policy +tx_latency_bucket_policy[TX_LATENCY_ATTR(BUCKET_MAX) + 1] = { + [TX_LATENCY_ATTR(BUCKET_TYPE)] = {.type = NLA_U8}, + [TX_LATENCY_ATTR(BUCKET_GRANULARITY)] = {.type = NLA_U32}, + [TX_LATENCY_ATTR(BUCKET_AVERAGE)] = {.type = NLA_U32}, + [TX_LATENCY_ATTR(BUCKET_DISTRIBUTION)] = { + .type = NLA_BINARY, .len = TX_LATENCY_BUCKET_DISTRIBUTION_LEN}, +}; + +static const struct nla_policy +tx_latency_link_policy[TX_LATENCY_ATTR(LINK_MAX) + 1] = { + [TX_LATENCY_ATTR(LINK_MAC_REMOTE)] = { + .type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE}, + [TX_LATENCY_ATTR(LINK_STAT_BUCKETS)] = + VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy), +}; + +const struct nla_policy +tx_latency_policy[TX_LATENCY_ATTR(MAX) + 1] = { + [TX_LATENCY_ATTR(ACTION)] = {.type = NLA_U32}, + [TX_LATENCY_ATTR(PERIODIC_REPORT)] = {.type = NLA_FLAG}, + [TX_LATENCY_ATTR(PERIOD)] = {.type = NLA_U32 }, + [TX_LATENCY_ATTR(BUCKETS)] = + VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_bucket_policy), + [TX_LATENCY_ATTR(LINKS)] = + VENDOR_NLA_POLICY_NESTED_ARRAY(tx_latency_link_policy), +}; + +/** + * struct tx_latency_link_node - Link info of remote peer + * @node: list node for membership in the link list + * @vdev_id: Unique value to identify VDEV + * @mac_remote: link MAC address of the remote peer + */ +struct tx_latency_link_node { + qdf_list_node_t node; + uint8_t vdev_id; + struct qdf_mac_addr mac_remote; +}; + +/** + * hdd_tx_latency_set_for_link() - set tx latency stats config for a link + * @link_info: link specific information + * @config: pointer to tx latency stats config + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +hdd_tx_latency_set_for_link(struct wlan_hdd_link_info *link_info, + struct cdp_tx_latency_config *config) +{ + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) + return QDF_STATUS_E_INVAL; + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return QDF_STATUS_SUCCESS; + + status = cdp_host_tx_latency_stats_config(soc, + link_info->vdev_id, + config); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("failed to %s for vdev id %d, status %d", + config->enable ? "enable" : "disable", + link_info->vdev_id, status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_tx_latency_restore_config() - restore tx latency stats config for a link + * @link_info: link specific information + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_tx_latency_restore_config(struct wlan_hdd_link_info *link_info) +{ + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_tx_latency_config *config; + + if (!soc) + return QDF_STATUS_E_INVAL; + + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + return QDF_STATUS_SUCCESS; + + config = &link_info->adapter->tx_latency_cfg; + status = cdp_host_tx_latency_stats_config(soc, + link_info->vdev_id, + config); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("failed to %s for vdev id %d, status %d", + config->enable ? "enable" : "disable", + link_info->vdev_id, status); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_tx_latency_set() - restore tx latency stats config for a link + * @adapter: pointer to hdd vdev/net_device context + * @config: pointer to tx latency stats config + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_set(struct hdd_adapter *adapter, + struct cdp_tx_latency_config *config) +{ + int ret; + struct wlan_hdd_link_info *link_info; + QDF_STATUS status = QDF_STATUS_E_NOENT; + + ret = hdd_set_tsf_auto_report(adapter, config->enable, + HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY); + if (ret) { + hdd_err_rl("failed to %s tsf auto report, ret %d", + config->enable ? "enable" : "disable", ret); + return ret; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + status = hdd_tx_latency_set_for_link(link_info, config); + if (QDF_IS_STATUS_ERROR(status)) + break; + } + + /* restore TSF auto report config on failure */ + if (QDF_IS_STATUS_ERROR(status)) + hdd_set_tsf_auto_report(adapter, !config->enable, + HDD_TSF_AUTO_RPT_SOURCE_TX_LATENCY); + else + qdf_mem_copy(&adapter->tx_latency_cfg, config, + sizeof(*config)); + hdd_debug("enable %d status %d", config->enable, status); + return qdf_status_to_os_return(status); +} + +/** + * hdd_tx_latency_fill_link_stats() - fill tx latency statistics info skb + * @skb: skb to be filled + * @latency: per link tx latency statistics + * @idx: index of the nested attribute + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_fill_link_stats(struct sk_buff *skb, + struct cdp_tx_latency *latency, int idx) +{ + struct nlattr *link, *link_stat_buckets, *link_stat_bucket; + uint32_t type; + int ret = 0; + + link = nla_nest_start(skb, idx); + if (!link) { + ret = -ENOMEM; + goto err; + } + + if (nla_put(skb, TX_LATENCY_ATTR(LINK_MAC_REMOTE), + QDF_MAC_ADDR_SIZE, latency->mac_remote.bytes)) { + ret = -ENOMEM; + goto err; + } + + hdd_debug_rl("idx %d link mac " QDF_MAC_ADDR_FMT, + idx, QDF_MAC_ADDR_REF(latency->mac_remote.bytes)); + link_stat_buckets = + nla_nest_start(skb, TX_LATENCY_ATTR(LINK_STAT_BUCKETS)); + for (type = 0; type < CDP_TX_LATENCY_TYPE_MAX; type++) { + link_stat_bucket = nla_nest_start(skb, type); + if (!link_stat_bucket) { + ret = -ENOMEM; + goto err; + } + + if (nla_put_u8(skb, TX_LATENCY_ATTR(BUCKET_TYPE), type)) { + ret = -ENOMEM; + goto err; + } + + if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_GRANULARITY), + latency->stats[type].granularity)) { + ret = -ENOMEM; + goto err; + } + + if (nla_put_u32(skb, TX_LATENCY_ATTR(BUCKET_AVERAGE), + latency->stats[type].average)) { + ret = -ENOMEM; + goto err; + } + + if (nla_put(skb, TX_LATENCY_ATTR(BUCKET_DISTRIBUTION), + TX_LATENCY_BUCKET_DISTRIBUTION_LEN, + latency->stats[type].distribution)) { + ret = -ENOMEM; + goto err; + } + + nla_nest_end(skb, link_stat_bucket); + hdd_debug_rl(" type %u granularity %u average %u", + type, latency->stats[type].granularity, + latency->stats[type].average); + } + + nla_nest_end(skb, link_stat_buckets); + nla_nest_end(skb, link); + +err: + if (ret) + hdd_err("failed for link " QDF_MAC_ADDR_FMT " ret: %d", + QDF_MAC_ADDR_REF(latency->mac_remote.bytes), ret); + return ret; +} + +/** + * hdd_tx_latency_get_skb_len() - get required skb length for vendor command + * response/async event + * @num: required number of entries + * + * Return: the required skb length + */ +static uint32_t hdd_tx_latency_get_skb_len(uint32_t num) +{ + int32_t peer_stat_sz = 0, per_bucket_len = 0, len; + + if (!num) + return 0; + + /* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_TYPE */ + per_bucket_len += nla_total_size(sizeof(uint8_t)); + /* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_GRANULARITY */ + per_bucket_len += nla_total_size(sizeof(uint32_t)); + /* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKET_DISTRIBUTION */ + per_bucket_len += nla_total_size(TX_LATENCY_BUCKET_DISTRIBUTION_LEN); + /* Nested attr */ + per_bucket_len = nla_total_size(per_bucket_len); + + /* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_MAC_REMOTE */ + peer_stat_sz += nla_total_size(QDF_MAC_ADDR_SIZE); + /* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINK_STAT_BUCKETS */ + peer_stat_sz += + nla_total_size(per_bucket_len * CDP_TX_LATENCY_TYPE_MAX); + /* Nested attr */ + peer_stat_sz = nla_total_size(peer_stat_sz); + + /* QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS */ + len = nla_total_size(peer_stat_sz * num); + len += NLMSG_HDRLEN; + return len; +} + +/** + * hdd_tx_latency_link_list_free() - free all the nodes in the list + * @list: list of the nodes for link info + * + * Return: None + */ +static void hdd_tx_latency_link_list_free(qdf_list_t *list) +{ + struct tx_latency_link_node *entry, *next; + + qdf_list_for_each_del(list, entry, next, node) { + qdf_list_remove_node(list, &entry->node); + qdf_mem_free(entry); + } +} + +/** + * hdd_tx_latency_link_list_add() - add a new node to the list for tx latency + * links + * @list: list of the nodes for link info + * @vdev_id: Unique value to identify VDEV + * @mac: link mac address of the remote peer + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_link_list_add(qdf_list_t *list, uint8_t vdev_id, uint8_t *mac) +{ + struct tx_latency_link_node *link; + + link = (struct tx_latency_link_node *)qdf_mem_malloc(sizeof(*link)); + if (!link) + return -ENOMEM; + + qdf_mem_copy(link->mac_remote.bytes, mac, QDF_MAC_ADDR_SIZE); + link->vdev_id = vdev_id; + qdf_list_insert_back(list, &link->node); + return 0; +} + +/** + * hdd_tx_latency_get_links_from_attr() - parse information of the links from + * attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS + * @adapter: pointer to hdd vdev/net_device context + * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS + * @list: list of the nodes for link info + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_get_links_from_attr(struct hdd_adapter *adapter, + struct nlattr *links_attr, + qdf_list_t *list) +{ + struct nlattr *attr, *link_mac_remote_attr; + struct nlattr *tb[TX_LATENCY_ATTR(LINK_MAX) + 1]; + int ret = 0, rem; + uint8_t vdev_id, *mac; + + if (!links_attr || !list) + return -EINVAL; + + /* links for MLO STA are attached to different vdevs */ + vdev_id = (adapter->device_mode == QDF_STA_MODE ? + CDP_VDEV_ALL : adapter->deflink->vdev_id); + + nla_for_each_nested(attr, links_attr, rem) { + ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(LINK_MAX), + nla_data(attr), nla_len(attr), + tx_latency_link_policy); + if (ret) { + hdd_err("Attribute parse failed, ret %d", ret); + ret = -EINVAL; + goto out; + } + + link_mac_remote_attr = tb[TX_LATENCY_ATTR(LINK_MAC_REMOTE)]; + if (!link_mac_remote_attr) { + hdd_err("Missing link mac remote attribute"); + ret = -EINVAL; + goto out; + } + + if (nla_len(link_mac_remote_attr) < QDF_MAC_ADDR_SIZE) { + hdd_err("Attribute link mac remote is invalid"); + ret = -EINVAL; + goto out; + } + + mac = (uint8_t *)nla_data(link_mac_remote_attr); + ret = hdd_tx_latency_link_list_add(list, vdev_id, mac); + if (ret) + goto out; + } + +out: + if (ret) + hdd_tx_latency_link_list_free(list); + + return ret; +} + +/** + * hdd_tx_latency_get_links_for_sap() - get all the active links for SAP mode + * @adapter: pointer to hdd vdev/net_device context + * @list: list of the nodes for link info + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_get_links_for_sap(struct hdd_adapter *adapter, qdf_list_t *list) +{ + struct hdd_station_info *sta, *tmp = NULL; + int ret = 0; + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta, tmp, + STA_INFO_SOFTAP_GET_STA_INFO) { + if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) { + hdd_put_sta_info_ref(&adapter->sta_info_list, + &sta, true, + STA_INFO_SOFTAP_GET_STA_INFO); + continue; + } + + ret = hdd_tx_latency_link_list_add(list, + adapter->deflink->vdev_id, + sta->sta_mac.bytes); + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true, + STA_INFO_SOFTAP_GET_STA_INFO); + if (ret) + goto out; + } + +out: + if (ret) + hdd_tx_latency_link_list_free(list); + + return ret; +} + +/** + * hdd_tx_latency_get_links_for_sta() - get all the active links for station + * mode + * @adapter: pointer to hdd vdev/net_device context + * @list: list of the nodes for link info + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_get_links_for_sta(struct hdd_adapter *adapter, qdf_list_t *list) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *ctx; + int ret = 0; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + if (wlan_hdd_validate_vdev_id(link_info->vdev_id)) + continue; + + ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!hdd_cm_is_vdev_associated(link_info)) + continue; + + ret = hdd_tx_latency_link_list_add(list, link_info->vdev_id, + ctx->conn_info.bssid.bytes); + if (ret) + goto out; + } + +out: + if (ret) + hdd_tx_latency_link_list_free(list); + + return ret; +} + +/** + * hdd_tx_latency_get_links() - get all the active links + * @adapter: pointer to hdd vdev/net_device context + * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS + * @list: list of the nodes for link info + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_get_links(struct hdd_adapter *adapter, + struct nlattr *links_attr, qdf_list_t *list) +{ + if (!list) + return -EINVAL; + + if (links_attr) + return hdd_tx_latency_get_links_from_attr(adapter, + links_attr, list); + + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) + return hdd_tx_latency_get_links_for_sap(adapter, list); + else if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) + return hdd_tx_latency_get_links_for_sta(adapter, list); + else + return -ENOTSUPP; +} + +/** + * hdd_tx_latency_populate_links() - get per link tx latency stats and fill + * into skb + * @soc: pointer to soc context + * @skb: skb for vendor command response/async event + * @list: list of the nodes for link info + * + * Return: 0 on success; error number otherwise. + */ +static inline int +hdd_tx_latency_populate_links(void *soc, struct sk_buff *skb, qdf_list_t *list) +{ + struct nlattr *links; + struct tx_latency_link_node *entry, *next; + struct cdp_tx_latency latency = {0}; + int ret, idx = 0; + uint8_t *mac; + QDF_STATUS status; + + links = nla_nest_start(skb, TX_LATENCY_ATTR(LINKS)); + if (!links) + return -ENOMEM; + + qdf_list_for_each_del(list, entry, next, node) { + qdf_list_remove_node(list, &entry->node); + mac = entry->mac_remote.bytes; + status = cdp_host_tx_latency_stats_fetch(soc, entry->vdev_id, + mac, &latency); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(entry); + return qdf_status_to_os_return(status); + } + + ret = hdd_tx_latency_fill_link_stats(skb, &latency, idx); + qdf_mem_free(entry); + if (ret) + return ret; + + idx++; + } + + nla_nest_end(skb, links); + return 0; +} + +/** + * hdd_tx_latency_get() - get per link tx latency stats + * @wiphy: pointer to wiphy + * @adapter: pointer to hdd vdev/net_device context + * @links_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_LINKS + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_get(struct wiphy *wiphy, + struct hdd_adapter *adapter, struct nlattr *links_attr) +{ + int ret; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct sk_buff *reply_skb = NULL; + uint32_t skb_len, links_num = 0; + qdf_list_t links_list; + + if (!soc) + return -EINVAL; + + qdf_list_create(&links_list, 0); + ret = hdd_tx_latency_get_links(adapter, links_attr, &links_list); + if (ret) + goto out; + + links_num = qdf_list_size(&links_list); + if (!links_num) { + hdd_err_rl("no valid peers"); + ret = -EINVAL; + goto out; + } + + skb_len = hdd_tx_latency_get_skb_len(links_num); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + if (!reply_skb) { + ret = -ENOMEM; + goto out; + } + + ret = hdd_tx_latency_populate_links(soc, reply_skb, &links_list); + if (ret) + goto free_skb; + + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + /* skb has been consumed regardless of the return value */ + goto out; + +free_skb: + wlan_cfg80211_vendor_free_skb(reply_skb); + hdd_tx_latency_link_list_free(&links_list); +out: + qdf_list_destroy(&links_list); + hdd_debug_rl("get stats with ret %d", ret); + return ret; +} + +/** + * hdd_tx_latency_enable() - enable per link tx latency stats + * @adapter: pointer to hdd vdev/net_device context + * @period: statistical period for transmit latency + * @periodic_report: whether driver needs to report transmit latency + * statistics at the end of each period + * @buckets_attr: pointer to attribute QCA_WLAN_VENDOR_ATTR_TX_LATENCY_BUCKETS + * + * Return: 0 on success; error number otherwise. + */ +static int +hdd_tx_latency_enable(struct hdd_adapter *adapter, uint32_t period, + bool periodic_report, struct nlattr *buckets_attr) +{ + struct nlattr *tb[TX_LATENCY_ATTR(BUCKET_MAX) + 1]; + struct nlattr *attr, *bucket_type_attr, *bucket_granularity_attr; + int rem, ret; + uint8_t bucket_type; + struct cdp_tx_latency_config config = {0}; + + nla_for_each_nested(attr, buckets_attr, rem) { + ret = wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(BUCKET_MAX), + nla_data(attr), nla_len(attr), + tx_latency_bucket_policy); + if (ret) { + hdd_err_rl("Attribute parse failed, ret %d", ret); + return -EINVAL; + } + + bucket_type_attr = tb[TX_LATENCY_ATTR(BUCKET_TYPE)]; + if (!bucket_type_attr) { + hdd_err_rl("Missing bucket type attribute"); + return -EINVAL; + } + + bucket_granularity_attr = + tb[TX_LATENCY_ATTR(BUCKET_GRANULARITY)]; + if (!bucket_granularity_attr) { + hdd_err_rl("Missing bucket granularity attribute"); + return -EINVAL; + } + + bucket_type = nla_get_u8(bucket_type_attr); + if (bucket_type >= CDP_TX_LATENCY_TYPE_MAX) { + hdd_err_rl("Invalid bucket type %u", bucket_type); + return -EINVAL; + } + + config.granularity[bucket_type] = + nla_get_u32(bucket_granularity_attr); + if (!config.granularity[bucket_type]) { + hdd_err_rl("Invalid granularity for type %d", + bucket_type); + return -EINVAL; + } + } + + for (rem = 0; rem < CDP_TX_LATENCY_TYPE_MAX; rem++) { + if (config.granularity[rem]) + continue; + + hdd_err_rl("Invalid granularity for type %d", rem); + return -EINVAL; + } + + config.enable = true; + config.report = periodic_report; + config.period = period; + return hdd_tx_latency_set(adapter, &config); +} + +/** + * hdd_tx_latency_disable() - disable per link tx latency stats + * @adapter: pointer to hdd vdev/net_device context + * + * Return: 0 on success; error number otherwise. + */ +static int hdd_tx_latency_disable(struct hdd_adapter *adapter) +{ + struct cdp_tx_latency_config config = {0}; + + return hdd_tx_latency_set(adapter, &config); +} + +/** + * __wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit + * latency statistics + * @wiphy: wiphy handle + * @wdev: wdev handle + * @data: user layer input + * @data_len: length of user layer input + * + * this function is called in ssr protected environment. + * + * return: 0 success, none zero for failure + */ +static int +__wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy, struct wireless_dev *wdev, + const void *data, int data_len) +{ + int ret; + uint32_t action, period; + struct nlattr *period_attr, *buckets_attr, *links_attr; + + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[TX_LATENCY_ATTR(MAX) + 1]; + bool periodic_report; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_warn("command not allowed in ftm mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, TX_LATENCY_ATTR(MAX), + data, data_len, + tx_latency_policy)) { + hdd_err_rl("invalid attribute"); + return -EINVAL; + } + + if (!tb[TX_LATENCY_ATTR(ACTION)]) { + hdd_err_rl("no attr action"); + return -EINVAL; + } + + action = nla_get_u32(tb[TX_LATENCY_ATTR(ACTION)]); + switch (action) { + case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_DISABLE: + if (!adapter->tx_latency_cfg.enable) { + ret = 0; + break; + } + + ret = hdd_tx_latency_disable(adapter); + break; + case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_ENABLE: + period_attr = tb[TX_LATENCY_ATTR(PERIOD)]; + if (!period_attr) { + hdd_err_rl("no attr period"); + return -EINVAL; + } + + buckets_attr = tb[TX_LATENCY_ATTR(BUCKETS)]; + if (!buckets_attr) { + hdd_err_rl("no attr buckets"); + return -EINVAL; + } + + period = nla_get_u32(period_attr); + if (!period) { + hdd_err_rl("invalid period"); + return -EINVAL; + } + + periodic_report = + nla_get_flag(tb[TX_LATENCY_ATTR(PERIODIC_REPORT)]); + ret = hdd_tx_latency_enable(adapter, period, + periodic_report, buckets_attr); + break; + case QCA_WLAN_VENDOR_TX_LATENCY_ACTION_GET: + if (!adapter->tx_latency_cfg.enable) { + hdd_err_rl("please enable the feature first"); + ret = -EINVAL; + break; + } + + links_attr = tb[TX_LATENCY_ATTR(LINKS)]; + ret = hdd_tx_latency_get(wiphy, adapter, links_attr); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/** + * wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit latency + * statistics + * @wiphy: wiphy handle + * @wdev: wdev handle + * @data: user layer input + * @data_len: length of user layer input + * + * return: 0 success, einval failure + */ +int wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_tx_latency(wiphy, wdev, data, data_len); + osif_vdev_sync_op_stop(vdev_sync); + return errno; +} + +/** + * hdd_tx_latency_stats_cb() - callback function for transmit latency stats + * @vdev_id: Unique value to identify VDEV + * @stats_list: list of the nodes for per-link transmit latency statistics + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_tx_latency_stats_cb(uint8_t vdev_id, qdf_list_t *stats_list) +{ + uint32_t len, stats_cnt; + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct wlan_hdd_link_info *link_info; + struct cdp_tx_latency *entry, *next; + struct nlattr *links; + int ret, idx = 0, flags = cds_get_gfp_flags(); + int event_idx = QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY_INDEX; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL"); + return QDF_STATUS_E_FAULT; + } + + if (!stats_list || qdf_list_empty(stats_list)) { + hdd_err("invalid stats list"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("adapter NULL for vdev id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + stats_cnt = qdf_list_size(stats_list); + len = hdd_tx_latency_get_skb_len(stats_cnt); + hdd_debug_rl("vdev id %d stats cnt %d", vdev_id, stats_cnt); + vendor_event = + wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, + &link_info->adapter->wdev, + len, event_idx, flags); + if (!vendor_event) { + hdd_err("event alloc failed vdev id %d, len %d", + vdev_id, len); + return QDF_STATUS_E_NOMEM; + } + + links = nla_nest_start(vendor_event, TX_LATENCY_ATTR(LINKS)); + if (!links) { + wlan_cfg80211_vendor_free_skb(vendor_event); + hdd_err("failed to put peers"); + return QDF_STATUS_E_NOMEM; + } + + qdf_list_for_each_del(stats_list, entry, next, node) { + qdf_list_remove_node(stats_list, &entry->node); + ret = hdd_tx_latency_fill_link_stats(vendor_event, entry, idx); + qdf_mem_free(entry); + if (ret) { + hdd_err("failed to populate stats for idx %d", idx); + wlan_cfg80211_vendor_free_skb(vendor_event); + return QDF_STATUS_E_NOMEM; + } + + idx++; + } + + nla_nest_end(vendor_event, links); + wlan_cfg80211_vendor_event(vendor_event, flags); + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_tx_latency_register_cb() - register callback function for transmit + * latency stats + * @soc: pointer to soc context + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_tx_latency_register_cb(void *soc) +{ + hdd_debug("Register tx latency callback"); + return cdp_host_tx_latency_stats_register_cb(soc, + hdd_tx_latency_stats_cb); +} +#endif + +#ifdef WLAN_CHIPSET_STATS +#ifdef CNSS_GENL +static int nl_srv_bcast_cstats(struct sk_buff *skb) +{ + return nl_srv_bcast(skb, CLD80211_MCGRP_HOST_LOGS, ANI_NL_MSG_LOG); +} +#else +static int nl_srv_bcast_cstats(struct sk_buff *skb) +{ + return nl_srv_bcast(skb); +} +#endif + +int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len, + enum cstats_types type) +{ + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; + tAniNlHdr *wnl; + static int nlmsg_seq; + int tot_msg_len; + int ret = -1; + + if (type == CSTATS_HOST_TYPE) { + *(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_HOST_LOG_TYPE; + *(unsigned short *)(buff + 2) = len - sizeof(tAniHdr); + } else if (type == CSTATS_FW_TYPE) { + *(unsigned short *)(buff) = ANI_NL_MSG_CSTATS_FW_LOG_TYPE; + *(unsigned short *)(buff + 2) = len - sizeof(tAniHdr); + } + + skb = dev_alloc_skb(MAX_CSTATS_NODE_LENGTH); + if (!skb) { + qdf_err("dev_alloc_skb() failed"); + return -ENOMEM; + } + + tot_msg_len = NLMSG_SPACE(len + sizeof(wnl->radio)); + + nlh = nlmsg_put(skb, 0, nlmsg_seq++, + ANI_NL_MSG_LOG, + len + sizeof(wnl->radio), NLM_F_REQUEST); + if (!nlh) { + qdf_err("nlmsg_put() failed for msg size[%d]", tot_msg_len); + dev_kfree_skb(skb); + return -EINVAL; + } + + wnl = (tAniNlHdr *)nlh; + wnl->radio = 0; + + memcpy(nlmsg_data(nlh) + sizeof(wnl->radio), buff, len); + + ret = nl_srv_bcast_cstats(skb); + if (ret < 0) + qdf_err("Send Failed %d", ret); + + return ret; +} + +struct cstats_tx_rx_ops cstats_ops = { + .cstats_send_data_to_usr = hdd_cstats_send_data_to_userspace, +}; + +void hdd_register_cstats_ops(void) +{ + ucfg_cp_stats_cstats_register_tx_rx_ops(&cstats_ops); +} + +void +hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev, + uint16_t transaction_id) +{ + struct cstats_nan_ndi_delete_req stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.transaction_id = transaction_id; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_req), &stat); +} + +void +hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li, + struct nan_datapath_inf_create_rsp *ndi_rsp) +{ + struct cstats_nan_ndi_create_resp stat = {0}; + struct wlan_objmgr_vdev *vdev; + struct nan_vdev_priv_obj *priv_obj; + + vdev = hdd_objmgr_get_vdev_by_user(li, WLAN_OSIF_NAN_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return; + } + + priv_obj = nan_get_vdev_priv_obj(vdev); + if (!priv_obj) { + hdd_err("priv_obj is null"); + return; + } + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.status = ndi_rsp->status; + stat.reason = ndi_rsp->reason; + qdf_spin_lock_bh(&priv_obj->lock); + stat.transaction_id = priv_obj->ndp_create_transaction_id; + qdf_spin_unlock_bh(&priv_obj->lock); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_NAN_ID); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_resp), + &stat); +} + +void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev, + uint16_t transaction_id) +{ + struct cstats_nan_ndi_create_req stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_CREATE_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_create_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.transaction_id = transaction_id; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_create_req), &stat); +} +#endif /* WLAN_CHIPSET_STATS */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h new file mode 100644 index 0000000000..7992b0a4ff --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_stats.h @@ -0,0 +1,897 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_stats.h + * + * WLAN Host Device Driver statistics related implementation + * + */ + +#if !defined(WLAN_HDD_STATS_H) +#define WLAN_HDD_STATS_H + +#include "wlan_hdd_main.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_cmn.h" +#endif +#include + +#define INVALID_MCS_IDX 255 + +#define DATA_RATE_11AC_MCS_MASK 0x03 + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +/* LL stats get request time out value */ +#define WLAN_WAIT_TIME_LL_STATS 3300 +#else +#define WLAN_WAIT_TIME_LL_STATS 800 +#endif + +#define WLAN_HDD_TGT_NOISE_FLOOR_DBM (-128) + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +extern const struct nla_policy qca_wlan_vendor_ll_ext_policy[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_EXT_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR */ +extern const struct nla_policy qca_wlan_vendor_ll_clr_policy[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET */ +extern const struct nla_policy qca_wlan_vendor_ll_set_policy[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET */ +extern const struct nla_policy qca_wlan_vendor_ll_get_policy[ + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX + 1]; + +#define FEATURE_LL_STATS_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ll_stats_clear, \ + vendor_command_policy(qca_wlan_vendor_ll_clr_policy, \ + QCA_WLAN_VENDOR_ATTR_LL_STATS_CLR_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ll_stats_set, \ + vendor_command_policy(qca_wlan_vendor_ll_set_policy, \ + QCA_WLAN_VENDOR_ATTR_LL_STATS_SET_MAX) \ +}, \ + \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_ll_stats_get, \ + vendor_command_policy(qca_wlan_vendor_ll_get_policy, \ + QCA_WLAN_VENDOR_ATTR_LL_STATS_GET_MAX) \ +}, +#else +#define FEATURE_LL_STATS_VENDOR_COMMANDS +#endif + +/** + * struct index_vht_data_rate_type - vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_VHT80_rate: VHT80 rate + * @supported_VHT40_rate: VHT40 rate + * @supported_VHT20_rate: VHT20 rate + */ +struct index_vht_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_VHT80_rate[2]; + uint16_t supported_VHT40_rate[2]; + uint16_t supported_VHT20_rate[2]; +}; + +/** + * enum data_rate_11ac_max_mcs - possible VHT max MCS values + * @DATA_RATE_11AC_MAX_MCS_7: MCS7 rate + * @DATA_RATE_11AC_MAX_MCS_8: MCS8 rate + * @DATA_RATE_11AC_MAX_MCS_9: MCS9 rate + * @DATA_RATE_11AC_MAX_MCS_NA: Not applicable + */ +enum data_rate_11ac_max_mcs { + DATA_RATE_11AC_MAX_MCS_7, + DATA_RATE_11AC_MAX_MCS_8, + DATA_RATE_11AC_MAX_MCS_9, + DATA_RATE_11AC_MAX_MCS_NA +}; + +/** + * struct index_data_rate_type - non vht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_rate: Supported rate table + */ +struct index_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_rate[4]; +}; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +/** + * wlan_hdd_cfg80211_ll_stats_set() - set link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_set(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_ll_stats_get() - get link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_get(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + + +/** + * wlan_hdd_cfg80211_ll_stats_clear() - clear link layer stats + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_ll_stats_clear(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +void wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter); + +static inline bool hdd_link_layer_stats_supported(void) +{ + return true; +} + +/** + * wlan_hdd_cfg80211_ll_stats_ext_set_param() - config monitor parameters + * @wiphy: wiphy handle + * @wdev: wdev handle + * @data: user layer input + * @data_len: length of user layer input + * + * return: 0 success, einval failure + */ +int wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +/** + * hdd_get_interface_info() - get interface info + * @link_info: Link info pointer in HDD adapter + * @info: Pointer to interface info + * + * Return: bool + */ +bool hdd_get_interface_info(struct wlan_hdd_link_info *link_info, + struct wifi_interface_info *info); + +/** + * wlan_hdd_ll_stats_get() - Get Link Layer statistics from FW + * @link_info: Link info pointer in HDD adapter + * @req_id: request id + * @req_mask: bitmask used by FW for the request + * + * Return: 0 on success and error code otherwise + */ +int wlan_hdd_ll_stats_get(struct wlan_hdd_link_info *link_info, + uint32_t req_id, uint32_t req_mask); + +/** + * wlan_hdd_cfg80211_link_layer_stats_callback() - This function is called + * @hdd_handle: Handle to HDD context + * @indication_type: Indication type + * @results: Pointer to results + * @cookie: Callback context + * + * After receiving Link Layer indications from FW.This callback converts the + * firmware data to the NL data and send the same to the kernel/upper layers. + * + * Return: None + */ +void wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle, + int indication_type, + tSirLLStatsResults *results, + void *cookie); + +/** + * wlan_hdd_cfg80211_link_layer_stats_ext_callback() - Callback for LL ext + * @ctx: HDD context + * @rsp: msg from FW + * + * This function is an extension of + * wlan_hdd_cfg80211_link_layer_stats_callback. It converts + * monitoring parameters offloaded to NL data and send the same to the + * kernel/upper layers. + * + * Return: None. + */ +void wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx, + tSirLLStatsResults *rsp); + +/** + * hdd_lost_link_info_cb() - callback function to get lost link information + * @hdd_handle: Opaque handle for the HDD context + * @lost_link_info: lost link information + * + * Return: none + */ +void hdd_lost_link_info_cb(hdd_handle_t hdd_handle, + struct sir_lost_link_info *lost_link_info); + +#else /* WLAN_FEATURE_LINK_LAYER_STATS */ + +static inline bool hdd_link_layer_stats_supported(void) +{ + return false; +} + +static inline int +wlan_hdd_cfg80211_ll_stats_ext_set_param(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + return -EINVAL; +} + +static inline int +wlan_hdd_ll_stats_get(struct wlan_hdd_link_info *link_info, + uint32_t req_id, uint32_t req_mask) +{ + return -EINVAL; +} + +static inline void +wlan_hdd_clear_link_layer_stats(struct hdd_adapter *adapter) +{ +} + +static inline void +wlan_hdd_cfg80211_link_layer_stats_callback(hdd_handle_t hdd_handle, + int indication_type, + tSirLLStatsResults *results, + void *cookie) +{ +} + +static inline void +wlan_hdd_cfg80211_link_layer_stats_ext_callback(hdd_handle_t ctx, + tSirLLStatsResults *rsp) +{ +} + +static inline void +hdd_lost_link_info_cb(hdd_handle_t hdd_handle, + struct sir_lost_link_info *lost_link_info) +{ +} + +#endif /* End of WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wlan_hdd_cfg80211_stats_ext_request() - ext stats request + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_stats_ext_request(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#endif /* End of WLAN_FEATURE_STATS_EXT */ + +/** + * wlan_hdd_cfg80211_connected_chan_stats_req() - get currently connected + * channel statistics from driver/firmware + * @wiphy: Pointer to wiphy + * @wdev: Pointer to wdev + * @data: Pointer to data + * @data_len: Data length + * + * Return: int + */ +int wlan_hdd_cfg80211_connected_chan_stats_req(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_get_station() - get station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *mac, + struct station_info *sinfo); +#else +int wlan_hdd_cfg80211_get_station(struct wiphy *wiphy, + struct net_device *dev, uint8_t *mac, + struct station_info *sinfo); +#endif + +/** + * wlan_hdd_cfg80211_dump_station() - dump station statistics + * @wiphy: Pointer to wiphy + * @dev: Pointer to network device + * @idx: variable to determine whether to get stats or not + * @mac: Pointer to mac + * @sinfo: Pointer to station info + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_cfg80211_dump_station(struct wiphy *wiphy, + struct net_device *dev, + int idx, u8 *mac, + struct station_info *sinfo); + +struct net_device_stats *hdd_get_stats(struct net_device *dev); + +int wlan_hdd_cfg80211_dump_survey(struct wiphy *wiphy, + struct net_device *dev, + int idx, struct survey_info *survey); + +void hdd_display_hif_stats(void); +void hdd_clear_hif_stats(void); + +/** + * wlan_hdd_cfg80211_stats_ext_callback() - ext stats callback + * @hdd_handle: Opaque handle to HDD context + * @data: ext stats payload + * + * Return: nothing + */ +void wlan_hdd_cfg80211_stats_ext_callback(hdd_handle_t hdd_handle, + struct stats_ext_event *data); + +/** + * wlan_hdd_cfg80211_stats_ext2_callback() - stats_ext2_callback + * @hdd_handle: opaque handle to the hdd context + * @pmsg: sir_sme_rx_aggr_hole_ind + * + * Return: void + */ +void +wlan_hdd_cfg80211_stats_ext2_callback(hdd_handle_t hdd_handle, + struct sir_sme_rx_aggr_hole_ind *pmsg); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wlan_hdd_cfg80211_roam_events_callback() - roam_events_callback + * @roam_stats: roam events stats + * @idx: TLV index in roam stats event + * + * Return: void + */ +void +wlan_hdd_cfg80211_roam_events_callback(struct roam_stats_event *roam_stats, + uint8_t idx); +#endif /* End of WLAN_FEATURE_ROAM_OFFLOAD */ + +/** + * wlan_hdd_get_rcpi() - Wrapper to get current RCPI + * @adapter: adapter upon which the measurement is requested + * @mac: peer addr for which measurement is requested + * @rcpi_value: pointer to where the RCPI should be returned + * @measurement_type: type of rcpi measurement + * + * This is a wrapper function for getting RCPI, invoke this function only + * when rcpi support is enabled in firmware + * + * Return: 0 for success, non-zero for failure + */ +int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac, + int32_t *rcpi_value, + enum rcpi_measurement_type measurement_type); + +#ifdef WLAN_FEATURE_MIB_STATS +/** + * wlan_hdd_get_mib_stats() - Get the mib statistics + * @adapter: adapter upon which the measurement is requested + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter); +#endif + +/** + * wlan_hdd_get_rssi() - Get the current RSSI + * @link_info: Link info pointer in HDD adapter + * @rssi_value: pointer to where the RSSI should be returned + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_get_rssi(struct wlan_hdd_link_info *link_info, + int8_t *rssi_value); + +/** + * wlan_hdd_get_snr() - Get the current SNR + * @link_info: Link info pointer in HDD adapter + * @snr: pointer to where the SNR should be returned + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_get_snr(struct wlan_hdd_link_info *link_info, int8_t *snr); + +/** + * wlan_hdd_get_linkspeed_for_peermac() - Get link speed for a peer + * @link_info: Link info pointer in adapter + * @mac_address: MAC address of the peer + * @linkspeed: pointer to memory where returned link speed is to be placed + * + * This function will send a query to SME for the linkspeed of the + * given peer, and then wait for the callback to be invoked. + * + * Return: 0 if linkspeed data is available, negative errno otherwise + */ +int wlan_hdd_get_linkspeed_for_peermac(struct wlan_hdd_link_info *link_info, + struct qdf_mac_addr *mac_address, + uint32_t *linkspeed); + +/** + * wlan_hdd_get_link_speed() - get link speed + * @link_info: Link info pointer in HDD adapter + * @link_speed: pointer to link speed + * + * This function fetches per bssid link speed. + * + * Return: if associated, link speed shall be returned. + * if not associated, link speed of 0 is returned. + * On error, error number will be returned. + */ +int wlan_hdd_get_link_speed(struct wlan_hdd_link_info *link_info, + uint32_t *link_speed); + +/** + * wlan_hdd_get_sap_go_peer_linkspeed() - Get SAP/GO peer link speed + * @link_info: Link info pointer in HDD adapter + * @link_speed: Pointer to link speed + * @command: Driver command string + * @command_len: Driver command string length + * + * Return: 0 if linkspeed data is available, negative errno otherwise + */ +int wlan_hdd_get_sap_go_peer_linkspeed(struct wlan_hdd_link_info *link_info, + uint32_t *link_speed, + uint8_t *command, + uint8_t command_len); +#ifdef FEATURE_RX_LINKSPEED_ROAM_TRIGGER +/** + * wlan_hdd_get_peer_rx_rate_stats() - STA gets rx rate stats + * @link_info: Link info pointer in HDD adapter + * + * STA gets rx rate stats through using the existed API + * cdp_host_get_peer_stats. The reason that we make this + * function is to avoid being disrupted by the flag + * "get_station_fw_request_needed" + * + * Return: void + */ +void wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info); +#else +static inline void +wlan_hdd_get_peer_rx_rate_stats(struct wlan_hdd_link_info *link_info) +{ +} +#endif + +/** + * wlan_hdd_get_station_stats() - Get station statistics + * @link_info: Link info pointer in HDD adapter. + * + * Return: status of operation + */ +int wlan_hdd_get_station_stats(struct wlan_hdd_link_info *link_info); + +int wlan_hdd_qmi_get_sync_resume(void); +int wlan_hdd_qmi_put_suspend(void); + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +/** + * wlan_hdd_get_big_data_station_stats() - Get big data station statistics + * @link_info: Link info pointer in HDD adapter + * + * Return: status of operation + */ +int wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info *link_info); + +/** + * wlan_cfg80211_mc_cp_get_big_data_stats() - API to get big data + * statistics from firmware + * @vdev: Pointer to vdev + * @errno: error type in case of failure + * + * Return: big data stats buffer on success, Null on failure + */ +struct big_data_stats_event * +wlan_cfg80211_mc_cp_get_big_data_stats(struct wlan_objmgr_vdev *vdev, + int *errno); + +/** + * wlan_cfg80211_mc_cp_stats_free_big_data_stats_event() - API to release big + * data statistics buffer + * @info: pointer to object to populate with big data stats + * + * Return: None + */ +void wlan_cfg80211_mc_cp_stats_free_big_data_stats_event( + struct big_data_stats_event *info); +#else +static inline int +wlan_hdd_get_big_data_station_stats(struct wlan_hdd_link_info *link_info) +{ + return 0; +} + +static inline struct big_data_stats_event * +wlan_cfg80211_mc_cp_get_big_data_stats(struct wlan_objmgr_vdev *vdev, + int *errno) +{ + return 0; +} + +static inline +void wlan_cfg80211_mc_cp_stats_free_big_data_stats_event( + struct big_data_stats_event *info) +{ +} +#endif + +/** + * wlan_hdd_get_temperature() - get current device temperature + * @adapter: device upon which the request was made + * @temperature: pointer to where the temperature is to be returned + * + * Return: 0 if a temperature value (either current or cached) was + * returned, otherwise a negative errno is returned. + * + */ +int wlan_hdd_get_temperature(struct hdd_adapter *adapter, int *temperature); + +/** + * hdd_get_max_tx_bitrate() - Get the max tx bitrate of the AP + * @link_info: pointer to link_info struct in adapter + * + * This function gets the MAX supported rate by AP and cache + * it into connection info structure + * + * Return: None + */ +void hdd_get_max_tx_bitrate(struct wlan_hdd_link_info *link_info); + +#ifdef TX_MULTIQ_PER_AC +/** + * wlan_hdd_display_tx_multiq_stats() - display Tx multi queue stats + * @context: hdd context + * @netdev: netdev + * + * Return: none + */ +void wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context, + qdf_netdev_t netdev); +#else +static inline +void wlan_hdd_display_tx_multiq_stats(hdd_cb_handle context, + qdf_netdev_t netdev) +{ +} +#endif + +/** + * hdd_report_max_rate() - Fill the max rate stats in the station info structure + * to be sent to the userspace. + * @link_info: pointer to link_info struct in adapter + * @mac_handle: The mac handle + * @rate: The station_info tx/rx rate to be filled + * @signal: signal from station_info + * @rate_flags: TX/RX rate flags computed from tx/rx rate + * @mcs_index: The TX/RX mcs index computed from tx/rx rate + * @fw_rate: The tx/rx rate from fw stats + * @nss: The TX/RX NSS from fw stats + * + * Return: True if fill is successful + */ +bool hdd_report_max_rate(struct wlan_hdd_link_info *link_info, + mac_handle_t mac_handle, + struct rate_info *rate, + int8_t signal, + enum tx_rate_info rate_flags, + uint8_t mcs_index, + uint16_t fw_rate, uint8_t nss); + +/** + * hdd_check_and_update_nss() - Check and update NSS as per DBS capability + * @hdd_ctx: HDD Context pointer + * @tx_nss: pointer to variable storing the tx_nss + * @rx_nss: pointer to variable storing the rx_nss + * + * The parameters include the NSS obtained from the FW or static NSS. This NSS + * could be invalid in the case the current HW mode is DBS where the connection + * are 1x1. Rectify these NSS values as per the current HW mode. + * + * Return: none + */ +void hdd_check_and_update_nss(struct hdd_context *hdd_ctx, + uint8_t *tx_nss, uint8_t *rx_nss); +#ifdef QCA_SUPPORT_CP_STATS +/** + * wlan_hdd_register_cp_stats_cb() - Register hdd stats specific + * callbacks to the cp stats component + * @hdd_ctx: hdd context + * + * Return: none + */ + +void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx); +#else +static inline void wlan_hdd_register_cp_stats_cb(struct hdd_context *hdd_ctx) {} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_ROAM_INFO_STATS) +#define FEATURE_ROAM_STATS_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_roam_stats, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ + }, \ + +#define FEATURE_ROAM_STATS_EVENTS \ + [QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_ROAM_STATS, \ + }, \ + +/** + * wlan_hdd_cfg80211_get_roam_stats() - get roam statstics information + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +int wlan_hdd_cfg80211_get_roam_stats(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); +#else +#define FEATURE_ROAM_STATS_COMMANDS +#define FEATURE_ROAM_STATS_EVENTS +#endif + +#ifdef WLAN_FEATURE_TX_LATENCY_STATS +/** + * hdd_tx_latency_register_cb() - register callback function for transmit + * latency stats + * @soc: pointer to soc context + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_tx_latency_register_cb(void *soc); + +/** + * hdd_tx_latency_restore_config() - restore tx latency stats config for a link + * @link_info: link specific information + * + * Return: QDF_STATUS + */ +QDF_STATUS +hdd_tx_latency_restore_config(struct wlan_hdd_link_info *link_info); + +/** + * wlan_hdd_cfg80211_tx_latency - configure/retrieve per-link transmit latency + * statistics + * @wiphy: wiphy handle + * @wdev: wdev handle + * @data: user layer input + * @data_len: length of user layer input + * + * return: 0 success, einval failure + */ +int wlan_hdd_cfg80211_tx_latency(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * hdd_tx_latency_record_ingress_ts() - Record driver ingress timestamp in CB + * @adapter: pointer to hdd vdev/net_device context + * @skb: sk buff + * + * Return: None + */ +static inline void +hdd_tx_latency_record_ingress_ts(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + if (adapter->tx_latency_cfg.enable) + qdf_nbuf_set_tx_ts(skb); +} + +extern const struct nla_policy + tx_latency_policy[QCA_WLAN_VENDOR_ATTR_TX_LATENCY_MAX + 1]; + +#define FEATURE_TX_LATENCY_STATS_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_tx_latency, \ + vendor_command_policy(tx_latency_policy, \ + QCA_WLAN_VENDOR_ATTR_TX_LATENCY_MAX) \ + }, \ + +#define FEATURE_TX_LATENCY_STATS_EVENTS \ + [QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_TX_LATENCY, \ + }, \ + +#else +static inline QDF_STATUS hdd_tx_latency_register_cb(void *soc) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +hdd_tx_latency_restore_config(struct wlan_hdd_link_info *link_info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +hdd_tx_latency_record_ingress_ts(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ +} + +#define FEATURE_TX_LATENCY_STATS_COMMANDS +#define FEATURE_TX_LATENCY_STATS_EVENTS +#endif + +#ifdef WLAN_CHIPSET_STATS +/** + * hdd_cstats_send_data_to_userspace() - Send chipsset stats to userspace + * + * @buff: Buffer to be sent + * @len: length of the buffer + * @type: Chipset stats type + * + * Return: 0 on success -ve value on error + */ +int hdd_cstats_send_data_to_userspace(char *buff, unsigned int len, + enum cstats_types type); + +/** + * hdd_register_cstats_ops() - Register chipset stats ops + * + * Return: void + */ +void hdd_register_cstats_ops(void); + +/** + * hdd_cstats_log_ndi_delete_req_evt() - Chipset stats for ndi delete + * + * @vdev: pointer to vdev object + * @transaction_id: transaction ID + * + * Return : void + */ +void hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev, + uint16_t transaction_id); + +/** + * hdd_cstats_log_ndi_create_resp_evt() - Chipset stats for ndi create + * response + * @li: pointer link_info object + * @ndi_rsp: pointer to nan_datapath_inf_create_rsp object + * + * Return : void + */ +void +hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li, + struct nan_datapath_inf_create_rsp *ndi_rsp); + +/** + * hdd_cstats_log_ndi_create_req_evt() - Chipset stats for ndi create + * request + * + * @vdev: pointer vdve object + * @transaction_id : Transaction ID + * + * Return : void + */ +void hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev, + uint16_t transaction_id); +#else +static inline void hdd_register_cstats_ops(void) +{ +} + +static inline int +hdd_cstats_send_data_to_userspace(char *buff, unsigned int len, + enum cstats_types type) +{ + return 0; +} + +static inline void +hdd_cstats_log_ndi_delete_req_evt(struct wlan_objmgr_vdev *vdev, + uint16_t transaction_id) +{ +} + +static inline void +hdd_cstats_log_ndi_create_resp_evt(struct wlan_hdd_link_info *li, + struct nan_datapath_inf_create_rsp *ndi_rsp) +{ +} + +static inline void +hdd_cstats_log_ndi_create_req_evt(struct wlan_objmgr_vdev *vdev, + uint16_t transaction_id) +{ +} +#endif /* WLAN_CHIPSET_STATS */ +#endif /* end #if !defined(WLAN_HDD_STATS_H) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c new file mode 100644 index 0000000000..a60d3fe449 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_subnet_detect.c + * + * WLAN Host Device Driver subnet detect API implementation + */ + +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "osif_sync.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_subnet_detect.h" +#include +#include "wlan_dp_ucfg_api.h" +#include "wlan_hdd_object_manager.h" + +/* + * define short names for the global vendor params + * used by __wlan_hdd_cfg80211_set_gateway_params() + */ +#define PARAM_MAC_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR +#define PARAM_IPV4_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR +#define PARAM_IPV6_ADDR QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR + +const struct nla_policy subnet_detect_policy[ + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_GW_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV4_ADDR] = + VENDOR_NLA_POLICY_IPV4_ADDR, + [QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_IPV6_ADDR] = + VENDOR_NLA_POLICY_IPV6_ADDR, +}; + +/** + * __wlan_hdd_cfg80211_set_gateway_params() - set gateway params + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1]; + struct gateway_update_req_param req = { 0 }; + int ret; + QDF_STATUS status; + bool subnet_detection_enabled; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + /* user may have disabled the feature in INI */ + ucfg_mlme_is_subnet_detection_enabled(hdd_ctx->psoc, + &subnet_detection_enabled); + if (!subnet_detection_enabled) { + hdd_debug("LFR Subnet Detection disabled in INI"); + return -ENOTSUPP; + } + + /* The gateway parameters are only valid in the STA persona + * and only in the connected state. + */ + if (QDF_STA_MODE != adapter->device_mode) { + hdd_debug("Received GW param update for non-STA mode adapter"); + return -ENOTSUPP; + } + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_debug("Received GW param update in disconnected state!"); + return -ENOTSUPP; + } + + /* Extract NL parameters + * mac_addr: 6 bytes + * ipv4 addr: 4 bytes + * ipv6 addr: 16 bytes + */ + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX, + data, data_len, subnet_detect_policy)) { + hdd_err("Invalid ATTR list"); + return -EINVAL; + } + + if (!tb[PARAM_MAC_ADDR]) { + hdd_err("request mac addr failed"); + return -EINVAL; + } + nla_memcpy(req.gw_mac_addr.bytes, tb[PARAM_MAC_ADDR], + QDF_MAC_ADDR_SIZE); + + /* req ipv4_addr_type and ipv6_addr_type are initially false due + * to zeroing the struct + */ + if (tb[PARAM_IPV4_ADDR]) { + nla_memcpy(req.ipv4_addr, tb[PARAM_IPV4_ADDR], + QDF_IPV4_ADDR_SIZE); + req.ipv4_addr_type = true; + } + + if (tb[PARAM_IPV6_ADDR]) { + nla_memcpy(&req.ipv6_addr, tb[PARAM_IPV6_ADDR], + QDF_IPV6_ADDR_SIZE); + req.ipv6_addr_type = true; + } + + if (!req.ipv4_addr_type && !req.ipv6_addr_type) { + hdd_err("invalid ipv4 or ipv6 gateway address"); + return -EINVAL; + } + + req.max_retries = 3; + req.timeout = 100; /* in milliseconds */ + req.vdev_id = adapter->deflink->vdev_id; + + hdd_debug("Configuring gateway for session %d", req.vdev_id); + hdd_debug("mac:"QDF_MAC_ADDR_FMT", ipv4:%pI4 (type %d), ipv6:%pI6c (type %d)", + QDF_MAC_ADDR_REF(req.gw_mac_addr.bytes), + req.ipv4_addr, req.ipv4_addr_type, + req.ipv6_addr, req.ipv6_addr_type); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (vdev) { + ucfg_dp_nud_set_gateway_addr(vdev, req.gw_mac_addr); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } + + status = sme_gateway_param_update(hdd_ctx->mac_handle, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("sme_gateway_param_update failed(err=%d)", status); + ret = -EINVAL; + } + + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_gateway_params() - set gateway parameters + * @wiphy: wiphy structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of @data + * + * The API is invoked by the user space to set the gateway parameters + * such as mac address and the IP address which is used for detecting + * the IP subnet change + * + * Return: 0 on success; errno on failure + */ +int wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_gateway_params(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#undef PARAM_MAC_ADDR +#undef PARAM_IPV4_ADDR +#undef PARAM_IPV6_ADDR diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h new file mode 100644 index 0000000000..5605ca5c8b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_subnet_detect.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2015,2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_SUBNET_DETECT_H +#define __WLAN_HDD_SUBNET_DETECT_H + +/** + * DOC: wlan_hdd_subnet_detect.h + * + * WLAN Host Device Driver subnet detect API specification + */ + +#ifdef FEATURE_LFR_SUBNET_DETECTION +struct wiphy; +struct wireless_dev; + +/* QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG policy */ +extern const struct nla_policy subnet_detect_policy[ + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX + 1]; + +#define FEATURE_LFR_SUBNET_DETECT_VENDOR_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GW_PARAM_CONFIG, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_gateway_params, \ + vendor_command_policy(subnet_detect_policy, \ + QCA_WLAN_VENDOR_ATTR_GW_PARAM_CONFIG_MAX)\ + }, + +int wlan_hdd_cfg80211_set_gateway_params(struct wiphy *wiphy, + struct wireless_dev *wdev, const void *data, int data_len); +#endif /* FEATURE_LFR_SUBNET_DETECTION */ +#endif /* __WLAN_HDD_SUBNET_DETECT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs.c new file mode 100644 index 0000000000..ccf3656cd5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs.c @@ -0,0 +1,1273 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs.c + * + * WLAN Host Device Driver implementation + * + */ + +#include +#include +#include +#include +#include "wlan_hdd_includes.h" +#include "wlan_hdd_sysfs.h" +#include "qwlan_version.h" +#include "cds_api.h" +#include +#include +#ifdef WLAN_POWER_DEBUG +#include +#endif +#include "osif_sync.h" +#include "wlan_hdd_sysfs_sta_info.h" +#include "wlan_hdd_sysfs_channel.h" +#include +#include +#include +#include "wlan_hdd_sysfs_crash_inject.h" +#include "wlan_hdd_sysfs_suspend_resume.h" +#include "wlan_hdd_sysfs_unit_test.h" +#include "wlan_hdd_sysfs_modify_acl.h" +#include "wlan_hdd_sysfs_connect_info.h" +#include +#include "wlan_hdd_sysfs_dcm.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wma_api.h" +#include "wlan_hdd_eht.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_module_ids.h" +#include + +#define MAX_PSOC_ID_SIZE 10 + +#ifdef MULTI_IF_NAME +#define DRIVER_NAME MULTI_IF_NAME +#else +#define DRIVER_NAME "wifi" +#endif + +static struct kobject *wlan_kobject; +static struct kobject *driver_kobject; +static struct kobject *fw_kobject; +static struct kobject *psoc_kobject; +static struct kobject *wifi_kobject; + +int +hdd_sysfs_validate_and_copy_buf(char *dest_buf, size_t dest_buf_size, + char const *source_buf, size_t source_buf_size) +{ + if (source_buf_size > (dest_buf_size - 1)) { + hdd_err_rl("Command length is larger than %zu bytes", + dest_buf_size); + return -EINVAL; + } + + /* sysfs already provides kernel space buffer so copy from user + * is not needed. Doing this extra copy operation just to ensure + * the local buf is properly null-terminated. + */ + strlcpy(dest_buf, source_buf, dest_buf_size); + /* default 'echo' cmd takes new line character to here */ + if (dest_buf[source_buf_size - 1] == '\n') + dest_buf[source_buf_size - 1] = '\0'; + + return 0; +} + +static ssize_t __show_driver_version(char *buf) +{ + return scnprintf(buf, PAGE_SIZE, QWLAN_VERSIONSTR); +} + +static ssize_t show_driver_version(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + ssize_t length; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return errno; + + length = __show_driver_version(buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return length; +} + +static ssize_t __show_fw_version(struct hdd_context *hdd_ctx, + char *buf) +{ + hdd_debug("Rcvd req for FW version"); + + return scnprintf(buf, PAGE_SIZE, + "FW:%d.%d.%d.%d.%d.%d HW:%s Board version: %x Ref design id: %x Customer id: %x Project id: %x Board Data Rev: %x\n", + hdd_ctx->fw_version_info.major_spid, + hdd_ctx->fw_version_info.minor_spid, + hdd_ctx->fw_version_info.siid, + hdd_ctx->fw_version_info.rel_id, + hdd_ctx->fw_version_info.crmid, + hdd_ctx->fw_version_info.sub_id, + hdd_ctx->target_hw_name, + hdd_ctx->hw_bd_info.bdf_version, + hdd_ctx->hw_bd_info.ref_design_id, + hdd_ctx->hw_bd_info.customer_id, + hdd_ctx->hw_bd_info.project_id, + hdd_ctx->hw_bd_info.board_data_rev); +} + +static ssize_t show_fw_version(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + ssize_t length; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return errno; + + length = __show_fw_version(hdd_ctx, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return length; +}; + +#ifdef WLAN_POWER_DEBUG +struct power_stats_priv { + struct power_stats_response power_stats; +}; + +static void hdd_power_debugstats_dealloc(void *priv) +{ + struct power_stats_priv *stats = priv; + + qdf_mem_free(stats->power_stats.debug_registers); + stats->power_stats.debug_registers = NULL; +} + +static void hdd_power_debugstats_cb(struct power_stats_response *response, + void *context) +{ + struct osif_request *request; + struct power_stats_priv *priv; + uint32_t *debug_registers; + uint32_t debug_registers_len; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + /* copy fixed-sized data */ + priv->power_stats = *response; + + /* copy variable-size data */ + if (response->num_debug_register) { + debug_registers_len = (sizeof(response->debug_registers[0]) * + response->num_debug_register); + debug_registers = qdf_mem_malloc(debug_registers_len); + priv->power_stats.debug_registers = debug_registers; + if (debug_registers) { + qdf_mem_copy(debug_registers, + response->debug_registers, + debug_registers_len); + } else { + hdd_err("Power stats memory alloc fails!"); + priv->power_stats.num_debug_register = 0; + } + } + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); +} + +static ssize_t __show_device_power_stats(struct hdd_context *hdd_ctx, + char *buf) +{ + QDF_STATUS status; + struct power_stats_response *chip_power_stats; + ssize_t ret_cnt = 0; + int j; + void *cookie; + struct osif_request *request; + struct power_stats_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + .dealloc = hdd_power_debugstats_dealloc, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + status = sme_power_debug_stats_req(hdd_ctx->mac_handle, + hdd_power_debugstats_cb, + cookie); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("chip power stats request failed"); + ret_cnt = qdf_status_to_os_return(status); + goto cleanup; + } + + ret_cnt = osif_request_wait_for_response(request); + if (ret_cnt) { + hdd_err("Target response timed out Power stats"); + sme_reset_power_debug_stats_cb(hdd_ctx->mac_handle); + ret_cnt = -ETIMEDOUT; + goto cleanup; + } + priv = osif_request_priv(request); + chip_power_stats = &priv->power_stats; + + ret_cnt += scnprintf(buf, PAGE_SIZE, + "POWER DEBUG STATS\n=================\n" + "cumulative_sleep_time_ms: %d\n" + "cumulative_total_on_time_ms: %d\n" + "deep_sleep_enter_counter: %d\n" + "last_deep_sleep_enter_tstamp_ms: %d\n" + "debug_register_fmt: %d\n" + "num_debug_register: %d\n", + chip_power_stats->cumulative_sleep_time_ms, + chip_power_stats->cumulative_total_on_time_ms, + chip_power_stats->deep_sleep_enter_counter, + chip_power_stats->last_deep_sleep_enter_tstamp_ms, + chip_power_stats->debug_register_fmt, + chip_power_stats->num_debug_register); + + for (j = 0; j < chip_power_stats->num_debug_register; j++) { + if ((PAGE_SIZE - ret_cnt) > 0) + ret_cnt += scnprintf(buf + ret_cnt, + PAGE_SIZE - ret_cnt, + "debug_registers[%d]: 0x%x\n", j, + chip_power_stats->debug_registers[j]); + else + j = chip_power_stats->num_debug_register; + } + +cleanup: + osif_request_put(request); + hdd_exit(); + return ret_cnt; +} + +static ssize_t show_device_power_stats(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + ssize_t length; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return errno; + + length = __show_device_power_stats(hdd_ctx, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return length; +} +#endif + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +struct beacon_reception_stats_priv { + struct bcn_reception_stats_rsp beacon_stats; +}; + +static void hdd_beacon_debugstats_cb(struct bcn_reception_stats_rsp + *response, + void *context) +{ + struct osif_request *request; + struct beacon_reception_stats_priv *priv; + + hdd_enter(); + + request = osif_request_get(context); + if (!request) { + hdd_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + /* copy fixed-sized data */ + priv->beacon_stats = *response; + + osif_request_complete(request); + osif_request_put(request); + hdd_exit(); +} + +static ssize_t __show_beacon_reception_stats(struct net_device *net_dev, + char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct bcn_reception_stats_rsp *beacon_stats; + int ret_val, j; + void *cookie; + struct osif_request *request; + struct beacon_reception_stats_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_STATS, + }; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + QDF_STATUS status; + + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (ret_val) + return ret_val; + + if (!adapter || adapter->magic != WLAN_HDD_ADAPTER_MAGIC) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return -EINVAL; + } + + if (!(adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) { + hdd_err("Beacon Reception Stats only supported in STA or P2P CLI modes!"); + return -ENOTSUPP; + } + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Adapter is not in connected state"); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + status = sme_beacon_debug_stats_req(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + hdd_beacon_debugstats_cb, + cookie); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("chip power stats request failed"); + ret_val = -EINVAL; + goto cleanup; + } + + ret_val = osif_request_wait_for_response(request); + if (ret_val) { + hdd_err("Target response timed out Power stats"); + ret_val = -ETIMEDOUT; + goto cleanup; + } + priv = osif_request_priv(request); + beacon_stats = &priv->beacon_stats; + + ret_val += scnprintf(buf, PAGE_SIZE, + "BEACON RECEPTION STATS\n=================\n" + "vdev id: %u\n" + "Total Beacon Count: %u\n" + "Total Beacon Miss Count: %u\n", + beacon_stats->vdev_id, + beacon_stats->total_bcn_cnt, + beacon_stats->total_bmiss_cnt); + + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + "Beacon Miss Bit map "); + + for (j = 0; j < MAX_BCNMISS_BITMAP; j++) { + if ((PAGE_SIZE - ret_val) > 0) { + ret_val += scnprintf(buf + ret_val, + PAGE_SIZE - ret_val, + "[0x%x] ", + beacon_stats->bmiss_bitmap[j]); + } + } + + if ((PAGE_SIZE - ret_val) > 0) + ret_val += scnprintf(buf + ret_val, + PAGE_SIZE - ret_val, + "\n"); +cleanup: + osif_request_put(request); + hdd_exit(); + return ret_val; +} + +static ssize_t show_beacon_reception_stats(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __show_beacon_reception_stats(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(beacon_stats, 0444, + show_beacon_reception_stats, NULL); +#endif + +static struct kobj_attribute dr_ver_attribute = + __ATTR(driver_version, 0440, show_driver_version, NULL); +static struct kobj_attribute fw_ver_attribute = + __ATTR(version, 0440, show_fw_version, NULL); +#ifdef WLAN_POWER_DEBUG +static struct kobj_attribute power_stats_attribute = + __ATTR(power_stats, 0444, show_device_power_stats, NULL); +#endif + +static void hdd_sysfs_create_version_interface(struct wlan_objmgr_psoc *psoc) +{ + int error = 0; + uint32_t psoc_id; + char buf[MAX_PSOC_ID_SIZE]; + + if (!driver_kobject || !wlan_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + + error = sysfs_create_file(wlan_kobject, &dr_ver_attribute.attr); + if (error) { + hdd_err("could not create wlan sysfs file"); + return; + } + + fw_kobject = kobject_create_and_add("fw", wlan_kobject); + if (!fw_kobject) { + hdd_err("could not allocate fw kobject"); + goto free_fw_kobj; + } + + psoc_id = wlan_psoc_get_nif_phy_version(psoc); + scnprintf(buf, PAGE_SIZE, "%d", psoc_id); + + psoc_kobject = kobject_create_and_add(buf, fw_kobject); + if (!psoc_kobject) { + hdd_err("could not allocate psoc kobject"); + goto free_fw_kobj; + } + + error = sysfs_create_file(psoc_kobject, &fw_ver_attribute.attr); + if (error) { + hdd_err("could not create fw sysfs file"); + goto free_psoc_kobj; + } + + return; + +free_psoc_kobj: + kobject_put(psoc_kobject); + psoc_kobject = NULL; + +free_fw_kobj: + kobject_put(fw_kobject); + fw_kobject = NULL; +} + +static void hdd_sysfs_destroy_version_interface(void) +{ + if (psoc_kobject) { + kobject_put(psoc_kobject); + psoc_kobject = NULL; + kobject_put(fw_kobject); + fw_kobject = NULL; + } +} + +#ifdef WLAN_POWER_DEBUG +static void hdd_sysfs_create_powerstats_interface(void) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + + error = sysfs_create_file(driver_kobject, &power_stats_attribute.attr); + if (error) + hdd_err("could not create power_stats sysfs file"); +} + +static void hdd_sysfs_destroy_powerstats_interface(void) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &power_stats_attribute.attr); +} +#else +static void hdd_sysfs_create_powerstats_interface(void) +{ +} + +static void hdd_sysfs_destroy_powerstats_interface(void) +{ +} +#endif + +static ssize_t +hdd_sysfs_wakeup_logs_to_console_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + int ret, value; + char *sptr, *token; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + wma_set_wakeup_logs_to_console(value); + + return count; +} + +static struct kobj_attribute wakeup_logs_to_console_attribute = + __ATTR(wakeup_logs_to_console, 0220, NULL, + hdd_sysfs_wakeup_logs_to_console_store); + +static void hdd_sysfs_create_wakeup_logs_to_console(void) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + + error = sysfs_create_file(driver_kobject, + &wakeup_logs_to_console_attribute.attr); + if (error) + hdd_err("could not create power_stats sysfs file"); +} + +static void hdd_sysfs_destroy_wakeup_logs_to_console(void) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, + &wakeup_logs_to_console_attribute.attr); +} + +static void hdd_sysfs_create_driver_root_obj(void) +{ + driver_kobject = kobject_create_and_add(DRIVER_NAME, kernel_kobj); + if (!driver_kobject) { + hdd_err("could not allocate driver kobject"); + return; + } + + wlan_kobject = kobject_create_and_add("wlan", driver_kobject); + if (!wlan_kobject) { + hdd_err("could not allocate wlan kobject"); + kobject_put(driver_kobject); + driver_kobject = NULL; + } +} + +static void hdd_sysfs_destroy_driver_root_obj(void) +{ + if (wlan_kobject) { + kobject_put(wlan_kobject); + wlan_kobject = NULL; + } + + if (driver_kobject) { + kobject_put(driver_kobject); + driver_kobject = NULL; + } +} + +void hdd_sysfs_create_wifi_root_obj(void) +{ + if (wifi_kobject) { + hdd_debug("wifi kobj already created"); + return; + } + wifi_kobject = pld_get_wifi_kobj(NULL); + if (wifi_kobject) { + hdd_debug("wifi_kobject created by platform"); + return; + } + wifi_kobject = kobject_create_and_add("wifi", NULL); + if (!wifi_kobject) + hdd_err("could not allocate wifi kobject"); +} + +void hdd_sysfs_destroy_wifi_root_obj(void) +{ + if (pld_get_wifi_kobj(NULL)) { + hdd_debug("wifi_kobject created by platform"); + wifi_kobject = NULL; + return; + } + + if (!wifi_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + kobject_put(wifi_kobject); + wifi_kobject = NULL; +} + +void hdd_create_wifi_feature_interface_sysfs_file(void) +{ + hdd_sysfs_create_wifi_feature_interface(wifi_kobject); +} + +void hdd_destroy_wifi_feature_interface_sysfs_file(void) +{ + hdd_sysfs_destroy_wifi_feature_interface(wifi_kobject); +} + +int hdd_sysfs_print(void *ctx, const char *fmt, ...) +{ + va_list args; + int ret = -1; + struct hdd_sysfs_print_ctx *p_ctx = ctx; + + va_start(args, fmt); + + if (ctx) { + ret = vscnprintf(p_ctx->buf + p_ctx->idx, + PAGE_SIZE - p_ctx->idx, fmt, args); + p_ctx->idx += ret; + if (p_ctx->new_line) { + ret += scnprintf(p_ctx->buf + p_ctx->idx, + PAGE_SIZE - p_ctx->idx, + "\n"); + p_ctx->idx += ret; + } + } + + va_end(args); + return ret; +} + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +static int hdd_sysfs_create_bcn_reception_interface(struct hdd_adapter + *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_beacon_stats); + if (error) + hdd_err("could not create beacon stats sysfs file"); + + return error; +} + +static void hdd_sysfs_destroy_bcn_reception_interface(struct hdd_adapter + *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_beacon_stats); +} +#else /* !WLAN_FEATURE_BEACON_RECEPTION_STATS */ +static inline int +hdd_sysfs_create_bcn_reception_interface(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_destroy_bcn_reception_interface(struct hdd_adapter *adapter) +{ +} + +#endif /* WLAN_FEATURE_BEACON_RECEPTION_STATS */ + +#define MAX_USER_COMMAND_SIZE_LOGGING_CONFIG 256 +#define MAX_SYS_LOGGING_CONFIG_COEX_NUM 7 +/** + * __hdd_sysfs_logging_config_store() - This API will store the values in local + * buffer. + * @hdd_ctx: hdd context + * @buf: input buffer + * @count: size fo buffer + * + * Return: local buffer count for success case, otherwise error + */ +static ssize_t __hdd_sysfs_logging_config_store(struct hdd_context *hdd_ctx, + const char *buf, size_t count) +{ + char buf_local[MAX_USER_COMMAND_SIZE_LOGGING_CONFIG + 1]; + char *sptr, *token; + uint32_t apps_args[WMI_UNIT_TEST_MAX_NUM_ARGS]; + int module_id, args_num, ret, i; + QDF_STATUS status; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + hdd_nofl_info("logging_config: count %zu buf_local:(%s)", count, + buf_local); + + sptr = buf_local; + /* Get module_id */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &module_id)) + return -EINVAL; + + if (module_id < WLAN_MODULE_ID_MIN || + module_id >= WLAN_MODULE_ID_MAX) { + hdd_err_rl("Invalid MODULE ID %d", module_id); + return -EINVAL; + } + + /* Get args_num */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &args_num)) + return -EINVAL; + + if (args_num > WMI_UNIT_TEST_MAX_NUM_ARGS) { + hdd_err_rl("Too many args %d", args_num); + return -EINVAL; + } + + for (i = 0; i < args_num; i++) { + token = strsep(&sptr, " "); + if (!token) { + hdd_err_rl("not enough args(%d), expected args_num:%d", + i, args_num); + return -EINVAL; + } + if (kstrtou32(token, 0, &apps_args[i])) + return -EINVAL; + } + + switch (module_id) { + case WLAN_MODULE_COEX: + if (args_num > MAX_SYS_LOGGING_CONFIG_COEX_NUM) { + hdd_err_rl("arg num %d exceeds max limit %d", args_num, + MAX_SYS_LOGGING_CONFIG_COEX_NUM); + return -EINVAL; + } + + status = ucfg_coex_send_logging_config(hdd_ctx->psoc, + &apps_args[0]); + if (status != QDF_STATUS_SUCCESS) { + hdd_err_rl("ucfg_coex_send_logging_config returned %d", + status); + return -EINVAL; + } + break; + + default: + hdd_debug_rl("module id not recognized"); + break; + } + + return count; +} + +/** + * hdd_sysfs_logging_config_store() - This API will store the values in local + * buffer. + * @kobj: sysfs wifi kobject + * @attr: pointer to kobj_attribute structure + * @buf: input buffer + * @count: size fo buffer + * + * Return: local buffer count for success case, otherwise error + */ +static ssize_t hdd_sysfs_logging_config_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_logging_config_store(hdd_ctx, buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute logging_config_attribute = + __ATTR(logging_config, 0220, NULL, hdd_sysfs_logging_config_store); + +/** + * hdd_sysfs_create_logging_config_interface() - API to create logging config + * sysfs file + * @driver_kobject: sysfs driver kobject + * + * Return: None + */ +static void +hdd_sysfs_create_logging_config_interface(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + + error = sysfs_create_file(driver_kobject, + &logging_config_attribute.attr); + if (error) + hdd_err("could not create logging config sysfs file"); +} + +/** + * hdd_sysfs_destroy_logging_config_interface() - API to destroy logging config + * sysfs file + * @driver_kobject: sysfs driver kobject + * + * Return: None + */ +static void +hdd_sysfs_destroy_logging_config_interface(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + + sysfs_remove_file(driver_kobject, &logging_config_attribute.attr); +} + +static void +hdd_sysfs_create_sta_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_create_bcn_reception_interface(adapter); + hdd_sysfs_reassoc_create(adapter); + hdd_sysfs_crash_inject_create(adapter); + hdd_sysfs_suspend_create(adapter); + hdd_sysfs_resume_create(adapter); + hdd_sysfs_unit_test_target_create(adapter); + hdd_sysfs_connect_info_interface_create(adapter); + hdd_sysfs_dcm_create(adapter); + hdd_sysfs_wowl_add_ptrn_create(adapter); + hdd_sysfs_wowl_del_ptrn_create(adapter); + hdd_sysfs_tx_stbc_create(adapter); + hdd_sysfs_txrx_fw_st_rst_create(adapter); + hdd_sysfs_gtx_bw_mask_create(adapter); + hdd_sysfs_rts_cts_create(adapter); + hdd_sysfs_stats_create(adapter); + hdd_sysfs_txrx_fw_stats_create(adapter); + hdd_sysfs_txrx_stats_create(adapter); + hdd_sysfs_tdls_peers_interface_create(adapter); + hdd_sysfs_temperature_create(adapter); + hdd_sysfs_motion_detection_create(adapter); + hdd_sysfs_range_ext_create(adapter); + hdd_sysfs_dl_modes_create(adapter); + hdd_sysfs_11be_rate_create(adapter); + hdd_sysfs_bmiss_create(adapter); + hdd_sysfs_dp_tx_delay_stats_create(adapter); + hdd_sysfs_direct_link_ut_cmd_create(adapter); + hdd_sysfs_sta_bitrates_create(adapter); +} + +static void +hdd_sysfs_destroy_sta_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_sta_bitrates_destroy(adapter); + hdd_sysfs_direct_link_ut_destroy(adapter); + hdd_sysfs_dp_tx_delay_stats_destroy(adapter); + hdd_sysfs_bmiss_destroy(adapter); + hdd_sysfs_11be_rate_destroy(adapter); + hdd_sysfs_dl_modes_destroy(adapter); + hdd_sysfs_range_ext_destroy(adapter); + hdd_sysfs_motion_detection_destroy(adapter); + hdd_sysfs_temperature_destroy(adapter); + hdd_sysfs_tdls_peers_interface_destroy(adapter); + hdd_sysfs_txrx_stats_destroy(adapter); + hdd_sysfs_txrx_fw_stats_destroy(adapter); + hdd_sysfs_stats_destroy(adapter); + hdd_sysfs_rts_cts_destroy(adapter); + hdd_sysfs_gtx_bw_mask_destroy(adapter); + hdd_sysfs_txrx_fw_st_rst_destroy(adapter); + hdd_sysfs_tx_stbc_destroy(adapter); + hdd_sysfs_wowl_del_ptrn_destroy(adapter); + hdd_sysfs_wowl_add_ptrn_destroy(adapter); + hdd_sysfs_dcm_destroy(adapter); + hdd_sysfs_connect_info_interface_destroy(adapter); + hdd_sysfs_unit_test_target_destroy(adapter); + hdd_sysfs_resume_destroy(adapter); + hdd_sysfs_suspend_destroy(adapter); + hdd_sysfs_crash_inject_destroy(adapter); + hdd_sysfs_reassoc_destroy(adapter); + hdd_sysfs_destroy_bcn_reception_interface(adapter); +} + +static void +hdd_sysfs_create_sap_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_channel_interface_create(adapter); + hdd_sysfs_sta_info_interface_create(adapter); + hdd_sysfs_crash_inject_create(adapter); + hdd_sysfs_suspend_create(adapter); + hdd_sysfs_resume_create(adapter); + hdd_sysfs_unit_test_target_create(adapter); + hdd_sysfs_modify_acl_create(adapter); + hdd_sysfs_connect_info_interface_create(adapter); + hdd_sysfs_tx_stbc_create(adapter); + hdd_sysfs_txrx_fw_st_rst_create(adapter); + hdd_sysfs_gtx_bw_mask_create(adapter); + hdd_sysfs_dcm_create(adapter); + hdd_sysfs_radar_create(adapter); + hdd_sysfs_rts_cts_create(adapter); + hdd_sysfs_stats_create(adapter); + hdd_sysfs_he_bss_color_create(adapter); + hdd_sysfs_txrx_fw_stats_create(adapter); + hdd_sysfs_txrx_stats_create(adapter); + hdd_sysfs_temperature_create(adapter); + hdd_sysfs_range_ext_create(adapter); + hdd_sysfs_ipa_create(adapter); + hdd_sysfs_dl_modes_create(adapter); + hdd_sysfs_11be_rate_create(adapter); + hdd_sysfs_dp_tx_delay_stats_create(adapter); + hdd_sysfs_dp_traffic_end_indication_create(adapter); + hdd_sysfs_direct_link_ut_cmd_create(adapter); + hdd_sysfs_dfsnol_create(adapter); + hdd_sysfs_sap_bitrates_create(adapter); +} + +static void +hdd_sysfs_destroy_sap_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_sap_bitrates_destroy(adapter); + hdd_sysfs_dfsnol_destroy(adapter); + hdd_sysfs_direct_link_ut_destroy(adapter); + hdd_sysfs_dp_traffic_end_indication_destroy(adapter); + hdd_sysfs_dp_tx_delay_stats_destroy(adapter); + hdd_sysfs_11be_rate_destroy(adapter); + hdd_sysfs_dl_modes_destroy(adapter); + hdd_sysfs_ipa_destroy(adapter); + hdd_sysfs_range_ext_destroy(adapter); + hdd_sysfs_temperature_destroy(adapter); + hdd_sysfs_txrx_stats_destroy(adapter); + hdd_sysfs_txrx_fw_stats_destroy(adapter); + hdd_sysfs_he_bss_color_destroy(adapter); + hdd_sysfs_stats_destroy(adapter); + hdd_sysfs_rts_cts_destroy(adapter); + hdd_sysfs_radar_destroy(adapter); + hdd_sysfs_dcm_destroy(adapter); + hdd_sysfs_gtx_bw_mask_destroy(adapter); + hdd_sysfs_txrx_fw_st_rst_destroy(adapter); + hdd_sysfs_tx_stbc_destroy(adapter); + hdd_sysfs_connect_info_interface_destroy(adapter); + hdd_sysfs_modify_acl_destroy(adapter); + hdd_sysfs_unit_test_target_destroy(adapter); + hdd_sysfs_resume_destroy(adapter); + hdd_sysfs_suspend_destroy(adapter); + hdd_sysfs_crash_inject_destroy(adapter); + hdd_sysfs_sta_info_interface_destroy(adapter); + hdd_sysfs_channel_interface_destroy(adapter); +} + +static void +hdd_sysfs_create_monitor_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_monitor_mode_channel_create(adapter); +} + +static void +hdd_sysfs_destroy_monitor_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_monitor_mode_channel_destroy(adapter); +} + +void hdd_create_sysfs_files(struct hdd_context *hdd_ctx) +{ + hdd_sysfs_create_driver_root_obj(); + hdd_sysfs_create_version_interface(hdd_ctx->psoc); + hdd_sysfs_mem_stats_create(wlan_kobject); + if (QDF_GLOBAL_MISSION_MODE == hdd_get_conparam()) { + hdd_sysfs_create_powerstats_interface(); + hdd_sysfs_create_dump_in_progress_interface(wifi_kobject); + hdd_sysfs_fw_mode_config_create(driver_kobject); + hdd_sysfs_scan_disable_create(driver_kobject); + hdd_sysfs_wow_ito_create(driver_kobject); + hdd_sysfs_wlan_dbg_create(driver_kobject); + hdd_sysfs_scan_config_create(driver_kobject); + hdd_sysfs_dp_trace_create(driver_kobject); + hdd_sysfs_thermal_cfg_create(driver_kobject); + hdd_sysfs_pktlog_create(driver_kobject); + hdd_sysfs_pm_cinfo_create(driver_kobject); + hdd_sysfs_pm_pcl_create(driver_kobject); + hdd_sysfs_dp_aggregation_create(driver_kobject); + hdd_sysfs_dp_swlm_create(driver_kobject); + hdd_sysfs_create_wakeup_logs_to_console(); + hdd_sysfs_dp_txrx_stats_sysfs_create(driver_kobject); + hdd_sysfs_get_valid_freq_for_power_create(driver_kobject); + hdd_sysfs_dp_pkt_add_ts_create(driver_kobject); + hdd_sysfs_runtime_pm_create(driver_kobject); + hdd_sysfs_log_buffer_create(driver_kobject); + hdd_sysfs_wds_mode_create(driver_kobject); + hdd_sysfs_roam_trigger_bitmap_create(driver_kobject); + hdd_sysfs_rf_test_mode_create(driver_kobject); + hdd_sysfs_create_logging_config_interface(driver_kobject); + } +} + +void hdd_destroy_sysfs_files(void) +{ + if (QDF_GLOBAL_MISSION_MODE == hdd_get_conparam()) { + hdd_sysfs_destroy_logging_config_interface(driver_kobject); + hdd_sysfs_rf_test_mode_destroy(driver_kobject); + hdd_sysfs_roam_trigger_bitmap_destroy(driver_kobject); + hdd_sysfs_wds_mode_destroy(driver_kobject); + hdd_sysfs_log_buffer_destroy(driver_kobject); + hdd_sysfs_runtime_pm_destroy(driver_kobject); + hdd_sysfs_dp_pkt_add_ts_destroy(driver_kobject); + hdd_sysfs_get_valid_freq_for_power_destroy(driver_kobject); + hdd_sysfs_dp_txrx_stats_sysfs_destroy(driver_kobject); + hdd_sysfs_destroy_wakeup_logs_to_console(); + hdd_sysfs_dp_swlm_destroy(driver_kobject); + hdd_sysfs_dp_aggregation_destroy(driver_kobject); + hdd_sysfs_pm_pcl_destroy(driver_kobject); + hdd_sysfs_pm_cinfo_destroy(driver_kobject); + hdd_sysfs_pktlog_destroy(driver_kobject); + hdd_sysfs_thermal_cfg_destroy(driver_kobject); + hdd_sysfs_dp_trace_destroy(driver_kobject); + hdd_sysfs_scan_config_destroy(driver_kobject); + hdd_sysfs_wlan_dbg_destroy(driver_kobject); + hdd_sysfs_wow_ito_destroy(driver_kobject); + hdd_sysfs_scan_disable_destroy(driver_kobject); + hdd_sysfs_fw_mode_config_destroy(driver_kobject); + hdd_sysfs_destroy_dump_in_progress_interface(wifi_kobject); + hdd_sysfs_destroy_powerstats_interface(); + } + hdd_sysfs_mem_stats_destroy(wlan_kobject); + hdd_sysfs_destroy_version_interface(); + hdd_sysfs_destroy_driver_root_obj(); +} + +static +void hdd_sysfs_create_ftm_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_unit_test_target_create(adapter); +} + +static void +hdd_sysfs_create_ndi_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_unit_test_target_create(adapter); + hdd_sysfs_11be_rate_create(adapter); +} + +static void +hdd_sysfs_destroy_ndi_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_11be_rate_destroy(adapter); + hdd_sysfs_unit_test_target_destroy(adapter); +} + +void hdd_create_adapter_sysfs_files(struct hdd_adapter *adapter) +{ + int device_mode = adapter->device_mode; + + if (hdd_adapter_is_link_adapter(adapter)) { + hdd_err("link adapter returning!!"); + return; + } + + switch (device_mode){ + case QDF_STA_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_P2P_CLIENT_MODE: + hdd_sysfs_create_sta_adapter_root_obj(adapter); + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + hdd_sysfs_create_sap_adapter_root_obj(adapter); + break; + case QDF_MONITOR_MODE: + hdd_sysfs_create_monitor_adapter_root_obj(adapter); + break; + case QDF_FTM_MODE: + hdd_sysfs_create_ftm_adapter_root_obj(adapter); + break; + case QDF_NDI_MODE: + hdd_sysfs_create_ndi_adapter_root_obj(adapter); + break; + default: + break; + } +} + +static +void hdd_sysfs_destroy_ftm_adapter_root_obj(struct hdd_adapter *adapter) +{ + hdd_sysfs_unit_test_target_destroy(adapter); +} + +void hdd_destroy_adapter_sysfs_files(struct hdd_adapter *adapter) +{ + int device_mode = adapter->device_mode; + + if (hdd_adapter_is_link_adapter(adapter)) { + hdd_err("link adapter returning!!"); + return; + } + switch (device_mode){ + case QDF_STA_MODE: + case QDF_P2P_DEVICE_MODE: + case QDF_P2P_CLIENT_MODE: + hdd_sysfs_destroy_sta_adapter_root_obj(adapter); + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + hdd_sysfs_destroy_sap_adapter_root_obj(adapter); + break; + case QDF_MONITOR_MODE: + hdd_sysfs_destroy_monitor_adapter_root_obj(adapter); + break; + case QDF_FTM_MODE: + hdd_sysfs_destroy_ftm_adapter_root_obj(adapter); + break; + case QDF_NDI_MODE: + hdd_sysfs_destroy_ndi_adapter_root_obj(adapter); + break; + default: + break; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_add_timestamp.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_add_timestamp.c new file mode 100644 index 0000000000..015793cbab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_add_timestamp.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_add_timestamp.c + * + * Implementation for creating sysfs files: + * + * dp_pkt_add_ts + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "qdf_trace.h" + +#define MAX_USER_COMMAND_SIZE_TIMESTAMP 512 + +static int hdd_set_dp_pkt_add_ts_info(char *in_str) +{ + char *str, *token, *substr, *subtoken; + enum qdf_pkt_supported_proto proto; + uint16_t port, offset; + int ret; + + str = in_str; + while (1) { + token = strsep(&str, ","); + if (!token) + break; + + substr = token; + + /* get protocol */ + subtoken = strsep(&substr, ":"); + if (!subtoken) + return -EINVAL; + + if (strncmp(subtoken, "TCP", 3) == 0) { + proto = QDF_PKT_PROTO_TCP; + } else if (strncmp(subtoken, "UDP", 3) == 0) { + proto = QDF_PKT_PROTO_UDP; + } else { + hdd_err("protocol not supported"); + return -EINVAL; + } + + /* get destination port value */ + subtoken = strsep(&substr, ":"); + if (!subtoken) + return -EINVAL; + + ret = kstrtou16(subtoken, 0, &port); + if (ret) { + hdd_err("Invalid port value ret %d", ret); + return -EINVAL; + } + + if (port < 1 || port > 65535) { + hdd_err("port not valid"); + return -EINVAL; + } + + /* get offset */ + subtoken = strsep(&substr, ":"); + if (!subtoken) + return -EINVAL; + + ret = kstrtou16(subtoken, 0, &offset); + if (ret) { + hdd_err("Invalid offset value ret %d", ret); + return -EINVAL; + } + + ret = qdf_set_dp_pkt_add_ts_info(proto, port, offset); + if (ret) { + hdd_err("pkt info set failed"); + return -EINVAL; + } + } + return 0; +} + +static ssize_t +__hdd_sysfs_dp_pkt_add_ts_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + char buf_local[MAX_USER_COMMAND_SIZE_TIMESTAMP + 1]; + char *str; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + str = skip_spaces(buf_local); + if (strlen(str) == 0) { + qdf_clear_dp_pkt_add_ts_info(); + return count; + } + + qdf_clear_dp_pkt_add_ts_info(); + ret = hdd_set_dp_pkt_add_ts_info(str); + if (ret) + hdd_err("all protocol do not set successfully"); + return count; +} + +static ssize_t hdd_sysfs_dp_pkt_add_ts_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_pkt_add_ts_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dp_pkt_add_ts_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, char *buf) +{ + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + return qdf_show_dp_pkt_add_ts_info(buf, PAGE_SIZE); +} + +static ssize_t hdd_sysfs_dp_pkt_add_ts_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_pkt_add_ts_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dp_pkt_add_ts_attribute = + __ATTR(dp_pkt_add_ts, 0660, hdd_sysfs_dp_pkt_add_ts_show, + hdd_sysfs_dp_pkt_add_ts_store); + +int hdd_sysfs_dp_pkt_add_ts_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &dp_pkt_add_ts_attribute.attr); + if (error) + hdd_err("could not create dp_pkt_add_ts sysfs file"); + + return error; +} + +void +hdd_sysfs_dp_pkt_add_ts_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &dp_pkt_add_ts_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_add_timestamp.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_add_timestamp.h new file mode 100644 index 0000000000..96db3e2b3a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_add_timestamp.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_add_timestamp.h + * + * Implementation for creating sysfs files: + * + * dp_pkt_add_ts + */ + +#ifndef _WLAN_HDD_SYSFS_DP_PKT_ADD_TIMESTAMP_H +#define _WLAN_HDD_SYSFS_DP_PKT_ADD_TIMESTAMP_H + +#include + +#if defined(WLAN_SYSFS) && defined(CONFIG_DP_PKT_ADD_TIMESTAMP) + +/** + * hdd_sysfs_dp_pkt_add_ts_create() - API to create dp trace related files + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/dp_pkt_add_ts + * + * usage: + * :: + * echo "TCP:5210:50,UDP:5110:50" > dp_pkt_add_ts (add protocol) + * echo "" > dp_pkt_add_ts (clear protocol) + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_dp_pkt_add_ts_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_dp_pkt_add_ts_destroy() - API to destroy dp trace related files + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_dp_pkt_add_ts_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_dp_pkt_add_ts_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_dp_pkt_add_ts_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DP_PKT_ADD_TIMESTAMP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bitrates.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bitrates.c new file mode 100644 index 0000000000..a32c680913 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bitrates.c @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_sta_bitrates.c + * + * implementation for creating sysfs file sta_bitrates and sap_bitrates + */ + +#include +#include +#include +#include "osif_psoc_sync.h" +#include "osif_vdev_sync.h" +#include "sme_api.h" +#include "qc_sap_ioctl.h" +#include "wma_api.h" + +static int wlan_hdd_sta_set_11n_rate(struct hdd_adapter *adapter, int rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int ret; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + enum wlan_phymode peer_phymode; + uint8_t *peer_mac = adapter->deflink->session.station.conn_info.bssid.bytes; + + hdd_debug("Rate code %d", rate_code); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (rate_code != 0xffff) { + rix = RC_2_RATE_IDX(rate_code); + if (rate_code & 0x80) { + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(rate_code) - 1; + } else { + status = ucfg_mlme_get_peer_phymode(hdd_ctx->psoc, + peer_mac, + &peer_phymode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set rate"); + return -EINVAL; + } + if (IS_WLAN_PHYMODE_HE(peer_phymode)) { + hdd_err("Do not set legacy rate %d in HE mode", + rate_code); + return -EINVAL; + } + nss = 0; + rix = RC_2_RATE_IDX(rate_code); + if (rate_code & 0x10) { + preamble = WMI_RATE_PREAMBLE_CCK; + if (rix != 0x3) + /* Enable Short preamble + * always for CCK except 1mbps + */ + rix |= 0x4; + } else { + preamble = WMI_RATE_PREAMBLE_OFDM; + } + } + rate_code = hdd_assemble_rate_code(preamble, nss, rix); + } + + hdd_debug("wmi_vdev_param_fixed_rate val %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + + return ret; +} + +static int wlan_hdd_sta_set_vht_rate(struct hdd_adapter *adapter, int rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int ret; + + hdd_debug("Rate code %d", rate_code); + + if (rate_code != 0xffff) { + rix = RC_2_RATE_IDX_11AC(rate_code); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(rate_code) - 1; + rate_code = hdd_assemble_rate_code(preamble, nss, rix); + } + + hdd_debug("wmi_vdev_param_fixed_rate val %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + + return ret; +} + +static int wlan_hdd_sta_set_11ax_rate(struct hdd_adapter *adapter, int rate) +{ + return hdd_set_11ax_rate(adapter, rate, NULL); +} + +static int wlan_hdd_sap_set_11n_rate(struct hdd_adapter *adapter, int rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + struct sap_config *config = &adapter->deflink->session.ap.sap_config; + int ret; + + hdd_debug("SET_HT_RATE val %d", rate_code); + + if (rate_code != 0xff) { + rix = RC_2_RATE_IDX(rate_code); + if (rate_code & 0x80) { + if (config->SapHw_mode == eCSR_DOT11_MODE_11b || + config->SapHw_mode == eCSR_DOT11_MODE_11b_ONLY || + config->SapHw_mode == eCSR_DOT11_MODE_11g || + config->SapHw_mode == eCSR_DOT11_MODE_11g_ONLY || + config->SapHw_mode == eCSR_DOT11_MODE_abg || + config->SapHw_mode == eCSR_DOT11_MODE_11a) { + hdd_err("Not valid mode for HT"); + ret = -EIO; + return ret; + } + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(rate_code) - 1; + } else if (rate_code & 0x10) { + if (config->SapHw_mode == eCSR_DOT11_MODE_11a) { + hdd_err("Not valid for cck"); + ret = -EIO; + return ret; + } + preamble = WMI_RATE_PREAMBLE_CCK; + /* Enable Short preamble always for CCK except 1mbps */ + if (rix != 0x3) + rix |= 0x4; + } else { + if (config->SapHw_mode == eCSR_DOT11_MODE_11b || + config->SapHw_mode == eCSR_DOT11_MODE_11b_ONLY) { + hdd_err("Not valid for OFDM"); + ret = -EIO; + return ret; + } + preamble = WMI_RATE_PREAMBLE_OFDM; + } + hdd_debug("SET_HT_RATE val %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + return ret; + } + + return -EINVAL; +} + +static int wlan_hdd_sap_set_vht_rate(struct hdd_adapter *adapter, int rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int ret; + struct sap_config *config = &adapter->deflink->session.ap.sap_config; + + if (config->SapHw_mode < eCSR_DOT11_MODE_11ac || + config->SapHw_mode == eCSR_DOT11_MODE_11ax_ONLY || + config->SapHw_mode == eCSR_DOT11_MODE_11be_ONLY) { + hdd_err("SET_VHT_RATE: SapHw_mode= 0x%x, ch_freq: %d", + config->SapHw_mode, config->chan_freq); + ret = -EIO; + return ret; + } + + if (rate_code != 0xff) { + rix = RC_2_RATE_IDX_11AC(rate_code); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(rate_code) - 1; + + rate_code = hdd_assemble_rate_code(preamble, nss, rix); + } + hdd_debug("SET_VHT_RATE val %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + + return ret; +} + +static int +wlan_hdd_sap_set_11ax_rate(struct hdd_adapter *adapter, int rate_code) +{ + struct sap_config *config = &adapter->deflink->session.ap.sap_config; + + return hdd_set_11ax_rate(adapter, rate_code, config); +} + +static ssize_t +__hdd_sysfs_sta_bitrates_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + int ret, rate, rate_code; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("sta_bitrates: count %zu buf_local:(%s)", count, buf_local); + + /* Get rate_type */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtoint(token, 0, &rate)) + return -EINVAL; + + /* Get rate */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtoint(token, 0, &rate_code)) + return -EINVAL; + + switch (rate) { + case SET_11N_RATES: + ret = wlan_hdd_sta_set_11n_rate(adapter, rate_code); + if (ret) { + hdd_err_rl("failed to set 11n rates"); + return ret; + } + break; + case SET_11AC_RATES: + ret = wlan_hdd_sta_set_vht_rate(adapter, rate_code); + if (ret) { + hdd_err_rl("failed to set 11ac rates"); + return ret; + } + break; + case SET_11AX_RATES: + ret = wlan_hdd_sta_set_11ax_rate(adapter, rate_code); + if (ret) { + hdd_err_rl("failed to set 11ax rates"); + return ret; + } + break; + default: + hdd_err("Invalid rate mode %u", rate); + return -EINVAL; + } + + return count; +} + +static ssize_t +__hdd_sysfs_sap_bitrates_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + int ret, rate, rate_code; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("sta_bitrates: count %zu buf_local:(%s)", count, buf_local); + + /* Get rate_type */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtoint(token, 0, &rate)) + return -EINVAL; + + /* Get rate */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtoint(token, 0, &rate_code)) + return -EINVAL; + + switch (rate) { + case SET_11N_RATES: + ret = wlan_hdd_sap_set_11n_rate(adapter, rate_code); + if (ret) { + hdd_err_rl("failed to set 11n rates"); + return ret; + } + break; + case SET_11AC_RATES: + ret = wlan_hdd_sap_set_vht_rate(adapter, rate_code); + if (ret) { + hdd_err_rl("failed to set 11ac rates"); + return ret; + } + break; + case SET_11AX_RATES: + ret = wlan_hdd_sap_set_11ax_rate(adapter, rate_code); + if (ret) { + hdd_err_rl("failed to set 11ax rates"); + return ret; + } + break; + default: + hdd_err("Invalid rate mode %u", rate); + return -EINVAL; + } + + return count; +} + +static ssize_t +hdd_sysfs_sap_bitrates_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_sap_bitrates_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static ssize_t +hdd_sysfs_sta_bitrates_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_sta_bitrates_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(sta_bitrates, 0220, + NULL, hdd_sysfs_sta_bitrates_store); + +static DEVICE_ATTR(sap_bitrates, 0220, + NULL, hdd_sysfs_sap_bitrates_store); + +int hdd_sysfs_sta_bitrates_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_sta_bitrates); + if (error) + hdd_err("could not create sta_bitrates sysfs file"); + + return error; +} + +int hdd_sysfs_sap_bitrates_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_sap_bitrates); + if (error) + hdd_err("could not create sap_bitrates sysfs file"); + + return error; +} +void hdd_sysfs_sta_bitrates_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_sta_bitrates); +} + +void hdd_sysfs_sap_bitrates_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_sap_bitrates); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bitrates.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bitrates.h new file mode 100644 index 0000000000..aa2f9eeaac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bitrates.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_bitrates.h + * + * implementation for creating sysfs file bitrates + * file path: /sys/class/net/wlanxx/sta_bitrates + * file path: /sys/class/net/wlanxx/sap_bitrates + * + * usage: + * echo [arg_0] [arg_1] > sta_bitrates + * echo [arg_0] [arg_1] > sap_bitrates + */ + +#ifndef _WLAN_HDD_SYSFS_BITRATES_H +#define _WLAN_HDD_SYSFS_BITRATES_H + +#define SET_11N_RATES 0 +#define SET_11AC_RATES 1 +#define SET_11AX_RATES 2 + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_BITRATES) +/** + * hdd_sysfs_sta_bitrates_create() - API to create sta_bitrates + * @adapter: hdd adapter + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_sta_bitrates_create(struct hdd_adapter *adapter); +/** + * hdd_sysfs_sap_bitrates_create() - API to create sap_bitrates + * @adapter: hdd adapter + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_sap_bitrates_create(struct hdd_adapter *adapter); +/** + * hdd_sysfs_sta_bitrates_destroy() - API to destroy sta_bitrates + * @adapter: hdd adapter + * + * Return: none + */ +void +hdd_sysfs_sta_bitrates_destroy(struct hdd_adapter *adapter); +/** + * hdd_sysfs_sap_bitrates_destroy() - API to destroy sap_bitrates + * @adapter: hdd adapter + * + * Return: none + */ +void +hdd_sysfs_sap_bitrates_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_sta_bitrates_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline int +hdd_sysfs_sap_bitrates_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_sta_bitrates_destroy(struct hdd_adapter *adapter) +{ +} + +static inline void +hdd_sysfs_sap_bitrates_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_BITRATES_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bmiss.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bmiss.c new file mode 100644 index 0000000000..c266df76b7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bmiss.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_bmiss.c + * + * Implementation for creating sysfs file bmiss + */ + +#include +#include +#include "osif_vdev_sync.h" +#include +#include +#include + +static struct infra_cp_stats_event* +wlan_hdd_get_bmiss(struct hdd_adapter *adapter) +{ + struct hdd_station_ctx *hdd_sta_ctx; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + int errno; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_sta_ctx) { + hdd_debug("hdd_sta_ctx received NULL"); + return NULL; + } + qdf_mem_copy(peer_mac, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + return wlan_cfg80211_mc_bmiss_get_infra_cp_stats(adapter->deflink->vdev, + peer_mac, &errno); +} + +static ssize_t +__hdd_sysfs_bmiss_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct infra_cp_stats_event *ev_ptr; + ssize_t ret = 0; + int idx = 0; + + adapter = netdev_priv(net_dev); + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ev_ptr = wlan_hdd_get_bmiss(adapter); + if (!ev_ptr) { + hdd_err_rl("GET_BMISS failed"); + return ret; + } + + ret = scnprintf(buf, PAGE_SIZE, "num_pre_bmiss:%u\n", + ev_ptr->bmiss_infra_cp_stats->num_pre_bmiss); + if (ret <= 0) + return ret; + + for (idx = 0; idx < BMISS_STATS_RSSI_SAMPLES_MAX; idx++) { + if ((PAGE_SIZE - ret) <= 0) + return ret; + + ret += scnprintf( + buf + ret, PAGE_SIZE - ret, + "rssi_sample%d-rssi:%d\n", idx, + ev_ptr->bmiss_infra_cp_stats->rssi_samples[idx].rssi); + if ((PAGE_SIZE - ret) <= 0) + return ret; + + ret += scnprintf( + buf + ret, PAGE_SIZE - ret, + "rssi_sample%d-sample_time:%u\n", idx, + ev_ptr->bmiss_infra_cp_stats->rssi_samples[idx].sample_time); + } + if ((PAGE_SIZE - ret) <= 0) + return ret; + + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + "rssi_sample_curr_index:%u\n" + "num_first_bmiss:%u\n" + "num_final_bmiss:%u\n" + "num_null_sent_in_first_bmiss:%u\n" + "num_null_failed_in_first_bmiss:%u\n" + "num_null_sent_in_final_bmiss:%u\n" + "num_null_failed_in_final_bmiss:%u\n" + "cons_bmiss_stats.num_of_bmiss_sequences:%u\n" + "cons_bmiss_stats.num_bitmask_wraparound:%u\n" + "cons_bmiss_stats.num_bcn_hist_lost:%u\n", + ev_ptr->bmiss_infra_cp_stats->rssi_sample_curr_index, + ev_ptr->bmiss_infra_cp_stats->num_first_bmiss, + ev_ptr->bmiss_infra_cp_stats->num_final_bmiss, + ev_ptr->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss, + ev_ptr->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss, + ev_ptr->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss, + ev_ptr->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss, + ev_ptr->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences, + ev_ptr->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound, + ev_ptr->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost); + + qdf_mem_free(ev_ptr->bmiss_infra_cp_stats); + qdf_mem_free(ev_ptr); + return ret; +} + +static ssize_t +hdd_sysfs_bmiss_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + net_dev = container_of(dev, struct net_device, dev); + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_bmiss_show(net_dev, buf); + osif_vdev_sync_op_stop(vdev_sync); + return err_size; +} + +static DEVICE_ATTR(bmiss, 0440, hdd_sysfs_bmiss_show, NULL); + +int hdd_sysfs_bmiss_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_bmiss); + if (!error) + hdd_err("could not create bmiss sysfs file"); + return error; +} + +void hdd_sysfs_bmiss_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_bmiss); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bmiss.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bmiss.h new file mode 100644 index 0000000000..9895bb2a7b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_bmiss.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_bmiss.h + * + * implementation for creating sysfs file bmiss + */ + +#ifndef _WLAN_HDD_SYSFS_BMISS_H +#define _WLAN_HDD_SYSFS_BMISS_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_BMISS) +/** + * hdd_sysfs_bmiss_create() - API to create bmiss + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/bmiss + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/bmiss + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_bmiss_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_bmiss_destroy() - API to destroy bmiss sysfs file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_bmiss_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_bmiss_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_bmiss_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_BMISS_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_channel.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_channel.c new file mode 100644 index 0000000000..80cf1e6f46 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_channel.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_channel.c + * + * implementation for creating sysfs file channel + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_sysfs_channel.h" + +static ssize_t __show_channel_number(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + struct hdd_ap_ctx *ap_ctx; + int chan_num = 0; + int ret_val; + + hdd_enter_dev(net_dev); + + ret_val = hdd_validate_adapter(adapter); + if (0 != ret_val) + goto exit; + + if (adapter->device_mode != QDF_SAP_MODE) + goto exit; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret_val) + goto exit; + + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + if (test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags)) { + chan_num = wlan_reg_freq_to_chan(hdd_ctx->pdev, + ap_ctx->operating_chan_freq); + ret_val = scnprintf(buf, PAGE_SIZE, "%s getchannel:%d\n", + net_dev->name, chan_num); + } + +exit: + hdd_exit(); + return ret_val; +} + +static ssize_t show_channel_number(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __show_channel_number(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(channel, 0444, show_channel_number, NULL); + +void hdd_sysfs_channel_interface_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_channel); + if (error) + hdd_err("Could not create channel sysfs file"); +} + +void hdd_sysfs_channel_interface_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_channel); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_connect_info.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_connect_info.c new file mode 100644 index 0000000000..64d5b2dc57 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_connect_info.c @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_connect_info.c + * + * WLAN Host Device Driver implementation to update sysfs with connect + * information + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_sysfs_connect_info.h" +#include "qwlan_version.h" + +/** + * wlan_hdd_version_info() - Populate driver, FW and HW version + * @hdd_ctx: pointer to hdd context + * @buf: output buffer to hold version info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_version_info(struct hdd_context *hdd_ctx, uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret_val; + + ret_val = scnprintf(buf, buf_avail_len, + "\nVERSION DETAILS\n"); + if (ret_val <= 0) + return length; + length += ret_val; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + ret_val = scnprintf(buf + length, buf_avail_len - length, + "Host Driver Version: %s\n" + "Firmware Version: %d.%d.%d.%d.%d.%d\n" + "Hardware Version: %s\n", + QWLAN_VERSIONSTR, + hdd_ctx->fw_version_info.major_spid, + hdd_ctx->fw_version_info.minor_spid, + hdd_ctx->fw_version_info.siid, + hdd_ctx->fw_version_info.rel_id, + hdd_ctx->fw_version_info.crmid, + hdd_ctx->fw_version_info.sub_id, + hdd_ctx->target_hw_name); + if (ret_val <= 0) + return length; + + length += ret_val; + + return length; +} + +/** + * wlan_hdd_add_nss_info() - Populate NSS info + * @conn_info: station connection information + * @buf: output buffer to hold version info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_add_nss_info(struct hdd_connection_info *conn_info, + uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length = 0; + int ret_val; + + if (!conn_info->conn_flag.ht_present && + !conn_info->conn_flag.vht_present) + return length; + + ret_val = scnprintf(buf, buf_avail_len, + "nss = %u\n", + conn_info->txrate.nss); + if (ret_val <= 0) + return length; + + length = ret_val; + return length; +} + +/** + * wlan_hdd_add_ht_cap_info() - Populate HT info + * @conn_info: station connection information + * @buf: output buffer to hold version info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_add_ht_cap_info(struct hdd_connection_info *conn_info, + uint8_t *buf, ssize_t buf_avail_len) +{ + struct ieee80211_ht_cap *ht_caps; + ssize_t length = 0; + int ret; + + if (!conn_info->conn_flag.ht_present) + return length; + + ht_caps = &conn_info->ht_caps; + ret = scnprintf(buf, buf_avail_len, + "ht_cap_info = %x\n" + "ampdu_params_info = %x\n" + "extended_ht_cap_info = %x\n" + "tx_BF_cap_info = %x\n" + "antenna_selection_info = %x\n" + "ht_rx_higest = %x\n" + "ht_tx_params = %x\n", + ht_caps->cap_info, + ht_caps->ampdu_params_info, + ht_caps->extended_ht_cap_info, + ht_caps->tx_BF_cap_info, + ht_caps->antenna_selection_info, + ht_caps->mcs.rx_highest, + ht_caps->mcs.tx_params); + if (ret <= 0) + return length; + + length = ret; + return length; +} + +/** + * wlan_hdd_add_vht_cap_info() - Populate VHT info + * @conn_info: station connection information + * @buf: output buffer to hold version info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t +wlan_hdd_add_vht_cap_info(struct hdd_connection_info *conn_info, + uint8_t *buf, ssize_t buf_avail_len) +{ + struct ieee80211_vht_cap *vht_caps; + ssize_t length = 0; + int ret; + + if (!conn_info->conn_flag.vht_present) + return length; + + vht_caps = &conn_info->vht_caps; + ret = scnprintf(buf, buf_avail_len, + "vht_cap_info = %x\n" + "rx_mcs_map = %x\n" + "rx_highest = %x\n" + "tx_mcs_map = %x\n" + "tx_highest = %x\n", + vht_caps->vht_cap_info, + vht_caps->supp_mcs.rx_mcs_map, + vht_caps->supp_mcs.rx_highest, + vht_caps->supp_mcs.tx_mcs_map, + vht_caps->supp_mcs.tx_highest); + if (ret <= 0) + return length; + + length = ret; + return length; +} + +/** + * hdd_auth_type_str() - Get string for enum csr auth type + * @auth_type: authentication id + * + * Return: Meaningful string for enum csr auth type + */ +static +uint8_t *hdd_auth_type_str(uint32_t auth_type) +{ + switch (auth_type) { + case eCSR_AUTH_TYPE_OPEN_SYSTEM: + return "OPEN SYSTEM"; + case eCSR_AUTH_TYPE_SHARED_KEY: + return "SHARED KEY"; + case eCSR_AUTH_TYPE_SAE: + return "SAE"; + case eCSR_AUTH_TYPE_AUTOSWITCH: + return "AUTO SWITCH"; + case eCSR_AUTH_TYPE_WPA: + return "WPA"; + case eCSR_AUTH_TYPE_WPA_PSK: + return "WPA PSK"; + case eCSR_AUTH_TYPE_WPA_NONE: + return "WPA NONE"; + + case eCSR_AUTH_TYPE_RSN: + return "RSN"; + case eCSR_AUTH_TYPE_RSN_PSK: + return "RSN PSK"; + case eCSR_AUTH_TYPE_FT_RSN: + return "FT RSN"; + case eCSR_AUTH_TYPE_FT_RSN_PSK: + return "FT RSN PSK"; +#ifdef FEATURE_WLAN_WAPI + case eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE: + return "WAPI WAI CERTIFICATE"; + case eCSR_AUTH_TYPE_WAPI_WAI_PSK: + return "WAPI WAI PSK"; +#endif /* FEATURE_WLAN_WAPI */ + case eCSR_AUTH_TYPE_CCKM_WPA: + return "CCKM WPA"; + case eCSR_AUTH_TYPE_CCKM_RSN: + return "CCKM RSN"; + case eCSR_AUTH_TYPE_RSN_PSK_SHA256: + return "RSN PSK SHA256"; + case eCSR_AUTH_TYPE_RSN_8021X_SHA256: + return "RSN 8021X SHA256"; + case eCSR_AUTH_TYPE_FILS_SHA256: + return "FILS SHA256"; + case eCSR_AUTH_TYPE_FILS_SHA384: + return "FILS SHA384"; + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return "FT FILS SHA256"; + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return "FT FILS SHA384"; + case eCSR_AUTH_TYPE_DPP_RSN: + return "DPP RSN"; + case eCSR_AUTH_TYPE_OWE: + return "OWE"; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA256: + return "SUITEB EAP SHA256"; + case eCSR_AUTH_TYPE_SUITEB_EAP_SHA384: + return "SUITEB EAP SHA384"; + case eCSR_AUTH_TYPE_OSEN: + return "OSEN"; + case eCSR_AUTH_TYPE_FT_SAE: + return "FT SAE"; + case eCSR_AUTH_TYPE_FT_SUITEB_EAP_SHA384: + return "FT Suite B SHA384"; + case eCSR_NUM_OF_SUPPORT_AUTH_TYPE: + return "NUM OF SUPPORT AUTH TYPE"; + case eCSR_AUTH_TYPE_FAILED: + return "FAILED"; + case eCSR_AUTH_TYPE_NONE: + return "NONE"; + } + + return "UNKNOWN"; +} + +/** + * hdd_dot11_mode_str() - Get string for enum csr dot11 mode + * @dot11mode: dot11 mode ID + * + * Return: Meaningful string for enum csr dot11 mode + */ +static +uint8_t *hdd_dot11_mode_str(uint32_t dot11mode) +{ + switch (dot11mode) { + case eCSR_CFG_DOT11_MODE_11A: + return "DOT11 MODE 11A"; + case eCSR_CFG_DOT11_MODE_11B: + return "DOT11 MODE 11B"; + case eCSR_CFG_DOT11_MODE_11G: + return "DOT11 MODE 11G"; + case eCSR_CFG_DOT11_MODE_11N: + return "DOT11 MODE 11N"; + case eCSR_CFG_DOT11_MODE_11AC: + return "DOT11 MODE 11AC"; + case eCSR_CFG_DOT11_MODE_AUTO: + return "DOT11 MODE AUTO"; + case eCSR_CFG_DOT11_MODE_ABG: + return "DOT11 MODE 11ABG"; + case eCSR_CFG_DOT11_MODE_11AX: + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + return "DOT11_MODE_11AX"; + case eCSR_CFG_DOT11_MODE_11BE: + case eCSR_CFG_DOT11_MODE_11BE_ONLY: + return "DOT11_MODE_11BE"; + } + + return "UNKNOWN"; +} + +#if defined(WLAN_FEATURE_11BE_MLO) && defined(CFG80211_11BE_BASIC) +/** + * wlan_hdd_connect_info() - Populate connect info + * @adapter: pointer to sta adapter for which connect info is required + * @buf: output buffer to hold version info + * @buf_avail_len: available buffer length + * + * Return: No.of bytes populated by this function in buffer + */ +static ssize_t wlan_hdd_connect_info(struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_station_ctx *hdd_sta_ctx; + uint32_t len = 0; + ssize_t length = 0; + struct hdd_connection_info *conn_info; + uint32_t tx_bit_rate, rx_bit_rate; + bool is_legacy = false; + bool is_standby = false; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + len = scnprintf(buf, buf_avail_len, + "STA is not connected\n"); + if (len >= 0) + return length; + } + + len = scnprintf(buf, buf_avail_len, + "CONNECTION DETAILS\n"); + if (len <= 0) + return length; + + length += len; + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (adapter->deflink == &adapter->link_info[0] && + hdd_sta_ctx->conn_info.ieee_link_id == WLAN_INVALID_LINK_ID) { + len = scnprintf(buf + length, buf_avail_len - length, + "CONNECTION DETAILS: Non-ML connection\n"); + is_legacy = true; + } else { + len = scnprintf(buf + length, buf_avail_len - length, + "CONNECTION DETAILS: ML connection\n"); + } + + if (len <= 0) + return length; + + length += len; + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + len = scnprintf(buf + length, buf_avail_len - length, + "ssid: %s\n" + "bssid: " QDF_MAC_ADDR_FMT "\n" + "connect_time: %s\n" + "auth_time: %s\n" + "last_auth_type: %s\n" + "dot11mode: %s\n", + hdd_sta_ctx->conn_info.last_ssid.SSID.ssId, + QDF_MAC_ADDR_REF(hdd_sta_ctx->conn_info.bssid.bytes), + hdd_sta_ctx->conn_info.connect_time, + hdd_sta_ctx->conn_info.auth_time, + hdd_auth_type_str(hdd_sta_ctx->conn_info.last_auth_type), + hdd_dot11_mode_str(hdd_sta_ctx->conn_info.dot11mode)); + if (len <= 0) + return length; + length += len; + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + conn_info = &hdd_sta_ctx->conn_info; + + if(!is_legacy && conn_info->ieee_link_id == WLAN_INVALID_LINK_ID) + continue; + + if (hdd_cm_is_vdev_roaming(link_info)) { + len = scnprintf(buf + length, buf_avail_len - length, + "Roaming is in progress"); + if (len <= 0) + return length; + + length += len; + } + + tx_bit_rate = cfg80211_calculate_bitrate(&conn_info->txrate); + rx_bit_rate = cfg80211_calculate_bitrate(&conn_info->rxrate); + + if (!is_legacy) { + len = scnprintf(buf + length, buf_avail_len - length, + "\nlink_id: %d\n", + conn_info->ieee_link_id); + if (len <= 0) + return length; + + length += len; + if (length >= buf_avail_len) { + hdd_debug("No sufficient buf_avail_len"); + return buf_avail_len; + } + + if (link_info->vdev_id == WLAN_INVALID_VDEV_ID && + conn_info->ieee_link_id != WLAN_INVALID_LINK_ID) + is_standby = true; + + len = scnprintf(buf + length, buf_avail_len - length, + "stand-by link: %d\n", + is_standby); + if (len <= 0) + return length; + + length += len; + if (length >= buf_avail_len) { + hdd_debug("No sufficient buf_avail_len"); + return buf_avail_len; + } + } + + len = scnprintf(buf + length, buf_avail_len - length, + "freq: %u\n" + "ch_width: %s\n" + "signal: %ddBm\n" + "tx_bit_rate: %u\n" + "rx_bit_rate: %u\n" + "last_auth_type: %s\n" + "dot11mode: %s\n", + conn_info->chan_freq, + hdd_ch_width_str(conn_info->ch_width), + conn_info->signal, + tx_bit_rate, + rx_bit_rate, + hdd_auth_type_str(conn_info->last_auth_type), + hdd_dot11_mode_str(conn_info->dot11mode)); + + if (len <= 0) + return length; + + length += len; + if (length >= buf_avail_len) { + hdd_debug("No sufficient buf_avail_len"); + return buf_avail_len; + } + + length += wlan_hdd_add_nss_info(conn_info, buf + length, + buf_avail_len - length); + if (length >= buf_avail_len) { + hdd_debug("No sufficient buf_avail_len"); + return buf_avail_len; + } + + length += wlan_hdd_add_ht_cap_info(conn_info, buf + length, + buf_avail_len - length); + if (length >= buf_avail_len) { + hdd_debug("No sufficient buf_avail_len"); + return buf_avail_len; + } + + length += wlan_hdd_add_vht_cap_info(conn_info, buf + length, + buf_avail_len - length); + if (is_legacy) + return length; + } + + return length; +} +#else +static ssize_t wlan_hdd_connect_info(struct hdd_adapter *adapter, uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t length = 0; + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_connection_info *conn_info; + uint32_t tx_bit_rate, rx_bit_rate; + int ret_val; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + ret_val = scnprintf(buf, buf_avail_len, + "\nSTA is not connected\n"); + if (ret_val >= 0) + length = ret_val; + return length; + } + + ret_val = scnprintf(buf, buf_avail_len, + "\nCONNECTION DETAILS\n"); + if (ret_val <= 0) + return length; + length += ret_val; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + if (hdd_cm_is_vdev_roaming(adapter->deflink)) { + ret_val = scnprintf(buf + length, buf_avail_len - length, + "Roaming is in progress"); + if (ret_val <= 0) + return length; + length += ret_val; + } + + conn_info = &hdd_sta_ctx->conn_info; + tx_bit_rate = cfg80211_calculate_bitrate(&conn_info->txrate); + rx_bit_rate = cfg80211_calculate_bitrate(&conn_info->rxrate); + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + ret_val = scnprintf(buf + length, buf_avail_len - length, + "ssid = %s\n" + "bssid = " QDF_MAC_ADDR_FMT "\n" + "connect_time = %s\n" + "auth_time = %s\n" + "freq = %u\n" + "ch_width = %s\n" + "signal = %ddBm\n" + "tx_bit_rate = %u\n" + "rx_bit_rate = %u\n" + "last_auth_type = %s\n" + "dot11mode = %s\n", + conn_info->last_ssid.SSID.ssId, + QDF_MAC_ADDR_REF(conn_info->bssid.bytes), + conn_info->connect_time, + conn_info->auth_time, + conn_info->chan_freq, + hdd_ch_width_str(conn_info->ch_width), + conn_info->signal, + tx_bit_rate, + rx_bit_rate, + hdd_auth_type_str(conn_info->last_auth_type), + hdd_dot11_mode_str(conn_info->dot11mode)); + + if (ret_val <= 0) + return length; + length += ret_val; + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + length += wlan_hdd_add_nss_info(conn_info, buf + length, + buf_avail_len - length); + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + + length += wlan_hdd_add_ht_cap_info(conn_info, buf + length, + buf_avail_len - length); + + if (length >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + return buf_avail_len; + } + length += wlan_hdd_add_vht_cap_info(conn_info, buf + length, + buf_avail_len - length); + return length; +} +#endif + +static ssize_t +wlan_hdd_current_time_info(uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length; + char time_buffer[HDD_TIME_STRING_LEN]; + int ret_val; + + qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buffer, + sizeof(time_buffer)); + ret_val = scnprintf(buf, buf_avail_len, + "\nTime at which this file generated = %s\n", + time_buffer); + if (ret_val < 0) + return 0; + length = ret_val; + + return length; +} + +static ssize_t __show_connect_info(struct net_device *net_dev, char *buf, + ssize_t buf_avail_len) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + ssize_t len; + int ret_val; + + hdd_enter_dev(net_dev); + + len = wlan_hdd_current_time_info(buf, buf_avail_len); + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + len = buf_avail_len; + goto exit; + } + + ret_val = hdd_validate_adapter(adapter); + if (0 != ret_val) + return len; + + if (adapter->device_mode != QDF_STA_MODE) { + ret_val = scnprintf(buf + len, buf_avail_len - len, + "Interface is not operating STA Mode\n"); + if (ret_val <= 0) + goto exit; + + len += ret_val; + goto exit; + } + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + len = buf_avail_len; + goto exit; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret_val) + goto exit; + + len += wlan_hdd_version_info(hdd_ctx, buf + len, buf_avail_len - len); + + if (len >= buf_avail_len) { + hdd_err("No sufficient buf_avail_len"); + len = buf_avail_len; + goto exit; + } + len += wlan_hdd_connect_info(adapter, buf + len, buf_avail_len - len); + +exit: + hdd_exit(); + return len; +} + +static ssize_t show_connect_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + ssize_t buf_avail_len = SYSFS_CONNECT_INFO_BUF_SIZE; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __show_connect_info(net_dev, buf, buf_avail_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(connect_info, 0444, show_connect_info, NULL); + +void hdd_sysfs_connect_info_interface_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_connect_info); + if (error) + hdd_err("could not create connect_info sysfs file"); +} + +void hdd_sysfs_connect_info_interface_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_connect_info); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_crash_inject.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_crash_inject.c new file mode 100644 index 0000000000..0d73cab249 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_crash_inject.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_crash_inject.c + * + * implementation for creating sysfs file crash_inject + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_sysfs.h" +#include "wlan_hdd_sysfs_crash_inject.h" + +static ssize_t __hdd_sysfs_crash_inject_store( + struct net_device *net_dev, + const char *buf, size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t val1, val2; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + hdd_nofl_info("crash_inject: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + sptr = buf_local; + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val2)) + return -EINVAL; + + ret = hdd_crash_inject(adapter, val1, val2); + if (ret != 0) { + hdd_err_rl("hdd_crash_inject returned %d", ret); + return -EINVAL; + } + + return count; +} + +static ssize_t hdd_sysfs_crash_inject_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_crash_inject_store( + net_dev, buf, count); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(crash_inject, 0220, + NULL, hdd_sysfs_crash_inject_store); + +int hdd_sysfs_crash_inject_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_crash_inject); + if (error) + hdd_err("could not create crash_inject sysfs file"); + + return error; +} + +void hdd_sysfs_crash_inject_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_crash_inject); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_crash_inject.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_crash_inject.h new file mode 100644 index 0000000000..767d07b975 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_crash_inject.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_crash_inject.h + * + * implementation for creating sysfs file crash_inject + */ + +#ifndef _WLAN_HDD_SYSFS_CRASH_INJECT_H +#define _WLAN_HDD_SYSFS_CRASH_INJECT_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_DEBUG_CRASH_INJECT) +/** + * hdd_sysfs_crash_inject_create() - API to create crash_inject + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlan_xx/crash_inject + * (wlan_xx is adapter name) + * usage: + * echo [arg_0] [arg_1] > crash_inject + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_crash_inject_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_crash_inject_destroy() - + * API to destroy crash_inject sys file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_crash_inject_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_crash_inject_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_crash_inject_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_CRASH_INJECT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dcm.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dcm.c new file mode 100644 index 0000000000..3ea8aac62e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dcm.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dcm.c + * + * implementation for creating sysfs file dcm + */ + +#include +#include "osif_vdev_sync.h" +#include +#include "wlan_hdd_sysfs_dcm.h" +#include + +static ssize_t +__wlan_hdd_sysfs_dcm_store(struct net_device *net_dev, char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int value, ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("dcm %d", value); + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_dcm_enable, + value, VDEV_CMD); + if (ret) { + hdd_err_rl("Failed to set dcm, errno %d", ret); + return ret; + } + + return count; +} + +static ssize_t wlan_hdd_sysfs_dcm_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_sysfs_dcm_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static ssize_t +__wlan_hdd_sysfs_dcm_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int ret, value; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_dcm_enable, + VDEV_CMD); + + hdd_debug("dcm %d", value); + + ret = scnprintf(buf, PAGE_SIZE, "%d", value); + + return ret; +} + +static ssize_t wlan_hdd_sysfs_dcm_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_sysfs_dcm_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(dcm, 0664, wlan_hdd_sysfs_dcm_show, + wlan_hdd_sysfs_dcm_store); + +int hdd_sysfs_dcm_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dcm); + if (error) + hdd_err("could not create dcm sysfs file"); + + return error; +} + +void hdd_sysfs_dcm_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dcm); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dcm.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dcm.h new file mode 100644 index 0000000000..6ddf5a9d8a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dcm.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dcm.h + * + * implementation for creating sysfs file dcm + */ + +#ifndef _WLAN_HDD_SYSFS_DCM_H +#define _WLAN_HDD_SYSFS_DCM_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_DCM) +/** + * hdd_sysfs_dcm_create() - API to create dcm + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/dcm + * where wlanxx is adapter name + * + * usage: + * echo [0/1] > dcm + * cat dcm + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_dcm_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_dcm_destroy() - + * API to destroy dcm + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_dcm_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_dcm_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_dcm_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DCM_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dfsnol.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dfsnol.c new file mode 100644 index 0000000000..4e343a444c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dfsnol.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dfsnol.c + * + * Implementation for creating sysfs file dfsnol + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_dfs_utils_api.h" +#include +#include + +static ssize_t +__hdd_sysfs_dfsnol_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_pdev *pdev; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + pdev = hdd_ctx->pdev; + if (!pdev) { + hdd_err("null pdev"); + return -EINVAL; + } + + utils_dfs_print_nol_channels(pdev); + return scnprintf(buf, PAGE_SIZE, "DFS NOL Info written to dmesg log\n"); +} + +static ssize_t +hdd_sysfs_dfsnol_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dfsnol_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dfsnol_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + struct sap_context *sap_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + eSapDfsNolType set_value; + int ret; + QDF_STATUS status; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + sap_ctx = WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink); + if (!sap_ctx) { + hdd_err_rl("Null SAP Context"); + return -EINVAL; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_nofl_debug("set_dfsnol: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get set_value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &set_value)) + return -EINVAL; + + status = wlansap_set_dfs_nol(sap_ctx, set_value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Unable to set_dfsnol val %d", set_value); + return -EINVAL; + } + + return count; +} + +static ssize_t +hdd_sysfs_dfsnol_store(struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dfsnol_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(dfsnol, 0660, hdd_sysfs_dfsnol_show, + hdd_sysfs_dfsnol_store); + +int hdd_sysfs_dfsnol_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dfsnol); + if (error) + hdd_err_rl("could not create dfsnol sysfs file"); + + return error; +} + +void hdd_sysfs_dfsnol_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dfsnol); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dfsnol.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dfsnol.h new file mode 100644 index 0000000000..b24466ca98 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dfsnol.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dfsnol.h + * + * implementation for creating sysfs file dfsnol + */ + +#ifndef _WLAN_HDD_SYSFS_DFSNOL_H +#define _WLAN_HDD_SYSFS_DFSNOL_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_DFSNOL) +/** + * hdd_sysfs_dfsnol_create() - API to create dfsnol sysfs file + * (for sap mode only) + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/dfsnol + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > /sys/class/net/wlanxx/dfsnol + * cat /sys/class/net/wlanxx/dfsnol + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_dfsnol_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_dfsnol_destroy() - API to destroy dfsnol sysfs file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_dfsnol_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_dfsnol_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_dfsnol_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DFSNOL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c new file mode 100644 index 0000000000..41f70f5e99 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_vdev_sync.h" +#include "os_if_qmi.h" +#include "cfg_ucfg_api.h" +#include "wlan_hdd_object_manager.h" +#include +#include "wlan_hdd_sysfs_direct_link_ut_cmd.h" + +#define MAX_SYSFS_DIRECT_LNK_UT_USER_COMMAND_LENGTH 512 + +static ssize_t __hdd_sysfs_direct_link_ut_cmd_store(struct net_device *net_dev, + char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct os_if_qmi_wfds_ut_cmd_info cmd_info; + char buf_local[MAX_SYSFS_DIRECT_LNK_UT_USER_COMMAND_LENGTH + 1]; + char *sptr, *token; + int ret; + QDF_STATUS status; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + ret = wlan_hdd_validate_context(adapter->hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err("invalid input"); + return ret; + } + + sptr = buf_local; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, (uint32_t *)&cmd_info.cmd)) + return -EINVAL; + + if (cmd_info.cmd >= WFDS_CMD_MAX) + return -EINVAL; + + if (cmd_info.cmd == WFDS_STOP_TRAFFIC || cmd_info.cmd == WFDS_GET_STATS) + goto send_request; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &cmd_info.duration)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &cmd_info.flush_period)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &cmd_info.num_pkts)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &cmd_info.buf_size)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &cmd_info.ether_type)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + qdf_mac_parse(token, &cmd_info.dest_mac); + + if (cmd_info.cmd == WFDS_START_WHC) { + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + qdf_mac_parse(token, &cmd_info.src_mac); + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + qdf_ipv4_parse(token, &cmd_info.dest_ip); + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + qdf_ipv4_parse(token, &cmd_info.src_ip); + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &cmd_info.dest_port)) + return -EINVAL; + } else if (cmd_info.cmd == WFDS_START_TRAFFIC) { + qdf_copy_macaddr(&cmd_info.src_mac, &adapter->mac_addr); + } + +send_request: + status = os_if_qmi_wfds_send_ut_cmd_req_msg(&cmd_info); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to send command %d", status); + + return count; +} + +static ssize_t hdd_sysfs_direct_link_ut_cmd_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_direct_link_ut_cmd_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(direct_link_ut_cmd, 0660, NULL, + hdd_sysfs_direct_link_ut_cmd_store); + +int hdd_sysfs_direct_link_ut_cmd_create(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + int error; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL!"); + return -EINVAL; + } + + if (cfg_get(hdd_ctx->psoc, CFG_ENABLE_DIRECT_LINK_UT_CMD) == false) + return -EINVAL; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_direct_link_ut_cmd); + if (error) + hdd_err("could not create traffic_end_indication sysfs file"); + + return error; +} + +void hdd_sysfs_direct_link_ut_destroy(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + + if (!hdd_ctx) { + hdd_err("HDD context is NULL!"); + return; + } + + if (cfg_get(hdd_ctx->psoc, CFG_ENABLE_DIRECT_LINK_UT_CMD) == false) + return; + + device_remove_file(&adapter->dev->dev, + &dev_attr_direct_link_ut_cmd); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.h new file mode 100644 index 0000000000..aca859ef87 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_DIRECT_LINK_UT_CMD_H +#define _WLAN_HDD_SYSFS_DIRECT_LINK_UT_CMD_H + +#if defined(WLAN_SYSFS) && defined(FEATURE_DIRECT_LINK) +/** + * hdd_sysfs_direct_link_ut_cmd_create() - API to create direct link unit test + * command sysfs entry + * @adapter: HDD adapter + * + * file path: /sys/class/net/wlanxx/direct_link_ut_cmd + * This sysfs entry is created per adapter + * + * usage: + * echo [0/1] > file path + * + * Return: 0 on success + */ +int hdd_sysfs_direct_link_ut_cmd_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_direct_link_ut_destroy() - API to destroy direct link unit test + * command sysfs entry + * @adapter: HDD adapter + * + * Return: None + */ +void hdd_sysfs_direct_link_ut_destroy(struct hdd_adapter *adapter); +#else +static inline +int hdd_sysfs_direct_link_ut_cmd_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline +void hdd_sysfs_direct_link_ut_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dl_modes.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dl_modes.c new file mode 100644 index 0000000000..d5ca3fc044 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dl_modes.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dl_modes.c + * + * implementation for creating sysfs file dl_modes + */ + +#include +#include +#include "osif_vdev_sync.h" +#include +#include +#include "wmi_unified_param.h" +#include "wma_api.h" + +static int hdd_sysfs_set_dbg(struct hdd_adapter *adapter, + int id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, DBG_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_sysfs_set_dbg(adapter, id, value) \ + hdd_sysfs_set_dbg(adapter, id, #id, value) + +static ssize_t +__hdd_sysfs_dl_loglevel_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_loglevel: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_LOG_LEVEL, value); + + if (ret) { + hdd_err_rl("failed dl_loglevel: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_loglevel_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_loglevel_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_mod_loglevel_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_mod_loglevel: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_MOD_LOG_LEVEL, value); + + if (ret) { + hdd_err_rl("failed dl_mod_loglevel: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_mod_loglevel_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_mod_loglevel_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_modoff_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_modoff: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_MODULE_DISABLE, value); + + if (ret) { + hdd_err_rl("failed dl_modoff: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_modoff_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_modoff_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_modon_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_modon: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_MODULE_ENABLE, value); + + if (ret) { + hdd_err_rl("failed dl_modon: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_modon_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_modon_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_report_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_report: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_REPORT_ENABLE, value); + + if (ret) { + hdd_err_rl("failed dl_report: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_report_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_report_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_type_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_type: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_TYPE, value); + + if (ret) { + hdd_err_rl("failed dl_type: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_type_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_type_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_vapoff_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_vapoff: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_VAP_DISABLE, value); + + if (ret) { + hdd_err_rl("failed dl_vapoff: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_vapoff_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_vapoff_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dl_vapon_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("dl_vapon: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_dbg(adapter, WMI_DBGLOG_VAP_ENABLE, value); + + if (ret) { + hdd_err_rl("failed dl_vapon: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_dl_vapon_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dl_vapon_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(dl_loglevel, 0220, + NULL, hdd_sysfs_dl_loglevel_store); + +static DEVICE_ATTR(dl_mod_loglevel, 0220, + NULL, hdd_sysfs_dl_mod_loglevel_store); + +static DEVICE_ATTR(dl_modoff, 0220, + NULL, hdd_sysfs_dl_modoff_store); + +static DEVICE_ATTR(dl_modon, 0220, + NULL, hdd_sysfs_dl_modon_store); + +static DEVICE_ATTR(dl_report, 0220, + NULL, hdd_sysfs_dl_report_store); + +static DEVICE_ATTR(dl_type, 0220, + NULL, hdd_sysfs_dl_type_store); + +static DEVICE_ATTR(dl_vapoff, 0220, + NULL, hdd_sysfs_dl_vapoff_store); + +static DEVICE_ATTR(dl_vapon, 0220, + NULL, hdd_sysfs_dl_vapon_store); + +static int hdd_sysfs_dl_loglevel_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_loglevel); + if (error) + hdd_err("could not create dl_loglevel sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_loglevel_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_loglevel); +} + +static int hdd_sysfs_dl_mod_loglevel_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_dl_mod_loglevel); + if (error) + hdd_err("could not create dl_mod_loglevel sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_mod_loglevel_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_mod_loglevel); +} + +static int hdd_sysfs_dl_modoff_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_modoff); + if (error) + hdd_err("could not create dl_modoff sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_modoff_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_modoff); +} + +static int hdd_sysfs_dl_modon_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_modon); + if (error) + hdd_err("could not create dl_modon sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_modon_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_modon); +} + +static int hdd_sysfs_dl_report_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_report); + if (error) + hdd_err("could not create dl_report sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_report_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_report); +} + +static int hdd_sysfs_dl_type_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_type); + if (error) + hdd_err("could not create dl_type sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_type_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_type); +} + +static int hdd_sysfs_dl_vapoff_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_vapoff); + if (error) + hdd_err("could not create dl_vapoff sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_vapoff_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_vapoff); +} + +static int hdd_sysfs_dl_vapon_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dl_vapon); + if (error) + hdd_err("could not create dl_vapon sysfs file"); + + return error; +} + +static void hdd_sysfs_dl_vapon_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dl_vapon); +} + +void hdd_sysfs_dl_modes_create(struct hdd_adapter *adapter) +{ + hdd_sysfs_dl_loglevel_create(adapter); + hdd_sysfs_dl_mod_loglevel_create(adapter); + hdd_sysfs_dl_modoff_create(adapter); + hdd_sysfs_dl_modon_create(adapter); + hdd_sysfs_dl_report_create(adapter); + hdd_sysfs_dl_type_create(adapter); + hdd_sysfs_dl_vapoff_create(adapter); + hdd_sysfs_dl_vapon_create(adapter); +} + +void hdd_sysfs_dl_modes_destroy(struct hdd_adapter *adapter) +{ + hdd_sysfs_dl_vapon_destroy(adapter); + hdd_sysfs_dl_vapoff_destroy(adapter); + hdd_sysfs_dl_type_destroy(adapter); + hdd_sysfs_dl_report_destroy(adapter); + hdd_sysfs_dl_modon_destroy(adapter); + hdd_sysfs_dl_modoff_destroy(adapter); + hdd_sysfs_dl_mod_loglevel_destroy(adapter); + hdd_sysfs_dl_loglevel_destroy(adapter); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dl_modes.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dl_modes.h new file mode 100644 index 0000000000..145b7e11e0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dl_modes.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dl_modes.h + * + * implementation for creating sysfs file dl_modes + */ + +#ifndef _WLAN_HDD_SYSFS_DL_MODES_H +#define _WLAN_HDD_SYSFS_DL_MODES_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_DL_MODES) +/** + * hdd_sysfs_dl_modes_create() - API to create motion + * detection sysfs attributes + * @adapter: hdd adapter + * + * This API creates the following sysfs attributes: + * 1. dl_loglevel + * 2. dl_mod_loglevel + * 3. dl_modoff + * 4. dl_modon + * 5. dl_report + * 6. dl_type + * 7. dl_vapoff + * 8. dl_vapon + * + * dl_loglevel: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_loglevel + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_loglevel + * + * dl_mod_loglevel: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_mod_loglevel + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_mod_loglevel + * + * dl_modoff: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_modoff + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > mt_config + * + * dl_modon: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_modon + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_modon + * + * dl_report: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_report + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_report + * + * dl_type: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_type + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_type + * + * dl_vapoff: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_vapoff + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_vapoff + * + * dl_vapon: this file is created per adapter. + * file path: /sys/class/net/wlanxx/dl_vapon + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > dl_vapon + * + * Return: None + */ +void hdd_sysfs_dl_modes_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_dl_modes_destroy() - + * API to destroy dl mode sysfs attributes + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_dl_modes_destroy(struct hdd_adapter *adapter); + +#else +static inline void +hdd_sysfs_dl_modes_create(struct hdd_adapter *adapter) +{ +} + +static inline void +hdd_sysfs_dl_modes_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DL_MODES_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c new file mode 100644 index 0000000000..ac4bc45214 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_aggregation.c + * + * implementation for creating sysfs files: + * + * dp_aggregation + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "wlan_dp_ucfg_api.h" + +static ssize_t +__hdd_sysfs_dp_aggregation_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, char *buf) +{ + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + hdd_debug("dp_aggregation: %d", + ucfg_dp_get_rx_aggregation_val(hdd_ctx->psoc)); + + return 0; +} + +static ssize_t hdd_sysfs_dp_aggregation_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_aggregation_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dp_aggregation_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("dp_aggregation: %d", value); + + ucfg_dp_rx_skip_fisa(value); + ucfg_dp_set_rx_aggregation_val(hdd_ctx->psoc, !!value); + + return count; +} + +static ssize_t +hdd_sysfs_dp_aggregation_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_aggregation_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dp_aggregation_attribute = + __ATTR(dp_aggregation, 0664, hdd_sysfs_dp_aggregation_show, + hdd_sysfs_dp_aggregation_store); + +int hdd_sysfs_dp_aggregation_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &dp_aggregation_attribute.attr); + if (error) + hdd_err("could not create dp_aggregation sysfs file"); + + return error; +} + +void +hdd_sysfs_dp_aggregation_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + + sysfs_remove_file(driver_kobject, &dp_aggregation_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h new file mode 100644 index 0000000000..a17a56cc7d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_aggregation.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_aggregation.h + * + * implementation for creating sysfs files: + * + * dp_aggregation + */ + +#ifndef _WLAN_HDD_SYSFS_DP_AGGREGATION_H +#define _WLAN_HDD_SYSFS_DP_AGGREGATION_H + +#if defined(WLAN_SYSFS) +/** + * hdd_sysfs_dp_aggregation_create() - API to create dp aggregation + * related sysfs entry + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/dp_aggregation + * + * usage: + * echo [0/1] > dp_aggregation + * + * Return: 0 on success and errno on failure + */ +int +hdd_sysfs_dp_aggregation_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_dp_aggregation_destroy() - API to destroy dp aggregation + * related sysfs entry + * @driver_kobject: sysfs driver kobject + * + * Return: None + */ +void +hdd_sysfs_dp_aggregation_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_dp_aggregation_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_dp_aggregation_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DP_AGGREGATION_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_trace.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_trace.c new file mode 100644 index 0000000000..a29012dffd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_trace.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_trace.c + * + * Implementation for creating sysfs files: + * + * dp_trace + * dump_dp_trace + * clear_dp_trace + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "qdf_trace.h" + +static ssize_t +__hdd_sysfs_dp_trace_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t val1; + uint8_t val2, val3; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("set_dp_trace: count %zu buf_local:(%s)", + count, buf_local); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &val2)) + return -EINVAL; + + /* Get val3 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &val3)) + return -EINVAL; + + qdf_dp_trace_set_value(val1, val2, val3); + + return count; +} + +static ssize_t +hdd_sysfs_dp_trace_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_trace_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dp_trace_attribute = + __ATTR(dp_trace, 0220, NULL, + hdd_sysfs_dp_trace_store); + +static uint32_t dump_dp_trace_count = 0; + +static ssize_t +__hdd_sysfs_dump_dp_trace_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int value, ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("dump_dp_trace %d", value); + + switch (value) { + case HDD_SYSFS_DISABLE_DP_TRACE_LIVE_MODE: + qdf_dp_trace_disable_live_mode(); + break; + case HDD_SYSFS_ENABLE_DP_TRACE_LIVE_MODE: + qdf_dp_trace_enable_live_mode(); + break; + case HDD_SYSFS_DUMP_DP_TRACE: + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &dump_dp_trace_count)) + return -EINVAL; + break; + default: + hdd_err_rl("invalid input"); + return -EINVAL; + } + + return count; +} + +static ssize_t hdd_sysfs_dump_dp_trace_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dump_dp_trace_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dump_dp_trace_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, char *buf) +{ + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + qdf_dp_trace_dump_all(dump_dp_trace_count, QDF_TRACE_DEFAULT_PDEV_ID); + + return 0; +} + +static ssize_t hdd_sysfs_dump_dp_trace_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dump_dp_trace_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dump_dp_trace_attribute = + __ATTR(dump_dp_trace, 0660, hdd_sysfs_dump_dp_trace_show, + hdd_sysfs_dump_dp_trace_store); + +static ssize_t +__hdd_sysfs_clear_dp_trace_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int value, ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("clear_dp_trace %d", value); + + qdf_dp_trace_clear_buffer(); + + return count; +} + +static ssize_t +hdd_sysfs_clear_dp_trace_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_clear_dp_trace_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute clear_dp_trace_attribute = + __ATTR(clear_dp_trace, 0220, NULL, + hdd_sysfs_clear_dp_trace_store); + +int hdd_sysfs_dp_trace_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &dp_trace_attribute.attr); + if (error) + hdd_err("could not create dp_trace sysfs file"); + + error = sysfs_create_file(driver_kobject, + &dump_dp_trace_attribute.attr); + if (error) + hdd_err("could not create dump_dp_trace sysfs file"); + + error = sysfs_create_file(driver_kobject, + &clear_dp_trace_attribute.attr); + if (error) + hdd_err("could not create clear_dp_trace sysfs file"); + + return error; +} + +void +hdd_sysfs_dp_trace_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &clear_dp_trace_attribute.attr); + sysfs_remove_file(driver_kobject, &dump_dp_trace_attribute.attr); + sysfs_remove_file(driver_kobject, &dp_trace_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_trace.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_trace.h new file mode 100644 index 0000000000..186b8a3f98 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_trace.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_trace.h + * + * Implementation for creating sysfs files: + * + * dp_trace + * dump_dp_trace + * clear_dp_trace + */ + +#ifndef _WLAN_HDD_SYSFS_DP_TRACE_H +#define _WLAN_HDD_SYSFS_DP_TRACE_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_DP_TRACE) + +#define HDD_SYSFS_DISABLE_DP_TRACE_LIVE_MODE 0 +#define HDD_SYSFS_ENABLE_DP_TRACE_LIVE_MODE 1 +#define HDD_SYSFS_DUMP_DP_TRACE 2 + +/** + * hdd_sysfs_dp_trace_create() - API to create dp trace related files + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/dp_trace + * /sys/kernel/wifi/dump_dp_trace + * /sys/kernel/wifi/clear_dp_trace + * + * usage: + * echo [arg_0] [arg_1] [arg_2]> dp_trace + * echo [0/1] > dump_dp_trace + * echo 2 [count] > dump_dp_trace + * cat dump_dp_trace + * echo 1 > clear_dp_trace + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_dp_trace_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_dp_trace_destroy() - API to destroy dp trace related files + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_dp_trace_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_dp_trace_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_dp_trace_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_DP_TRACE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.c new file mode 100644 index 0000000000..df0c892c37 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_traffic_end_indication.c + * + * implementation for creating sysfs files: + * + * dp_traffic_end_indication + */ +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_object_manager.h" +#include +#include +#include + +static ssize_t +__hdd_sysfs_dp_traffic_end_indication_show(struct net_device *net_dev, + char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct wlan_objmgr_vdev *vdev; + struct dp_traffic_end_indication info = {0}; + QDF_STATUS status; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + ret = wlan_hdd_validate_context(adapter->hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx)) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return -EINVAL; + + status = ucfg_dp_traffic_end_indication_get(vdev, &info); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + if (!QDF_IS_STATUS_SUCCESS(status)) + return -EINVAL; + + hdd_debug("vdev_id:%u traffic end indication:%u defdscp:%u spldscp:%u", + adapter->deflink->vdev_id, info.enabled, + info.def_dscp, info.spl_dscp); + + ret = scnprintf(buf, PAGE_SIZE, "%u %u %u\n", + info.enabled, info.def_dscp, info.def_dscp); + return ret; +} + +static ssize_t +hdd_sysfs_dp_traffic_end_indication_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_dp_traffic_end_indication_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static ssize_t +__hdd_sysfs_dp_traffic_end_indication_store(struct net_device *net_dev, + const char *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct dp_traffic_end_indication info = {0}; + struct wlan_objmgr_vdev *vdev; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint8_t value, defdscp, spldscp; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + ret = wlan_hdd_validate_context(adapter->hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err("invalid input"); + return ret; + } + + sptr = buf_local; + /* Enable/disable traffic end indication*/ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &value)) + return -EINVAL; + + /* Default DSCP Value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &defdscp)) + return -EINVAL; + + /* Special DSCP Value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &spldscp)) + return -EINVAL; + + if ((defdscp > 63) || (spldscp > 63)) { + hdd_err("invalid dscp value"); + return -EINVAL; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return -EINVAL; + + info.enabled = !!value; + adapter->traffic_end_ind_en = info.enabled; + if (info.enabled) { + info.def_dscp = defdscp; + info.spl_dscp = spldscp; + } else { + info.def_dscp = 0; + info.spl_dscp = 0; + } + + hdd_debug("vdev_id:%u traffic end indication:%u defdscp:%u spldscp:%u", + adapter->deflink->vdev_id, value, defdscp, spldscp); + + ucfg_dp_traffic_end_indication_set(vdev, info); + wlan_objmgr_vdev_release_ref(vdev, WLAN_DP_ID); + + return count; +} + +static ssize_t +hdd_sysfs_dp_traffic_end_indication_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_traffic_end_indication_store(net_dev, + buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(dp_traffic_end_indication, 0660, + hdd_sysfs_dp_traffic_end_indication_show, + hdd_sysfs_dp_traffic_end_indication_store); + +int hdd_sysfs_dp_traffic_end_indication_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_dp_traffic_end_indication); + if (error) + hdd_err("could not create traffic_end_indication sysfs file"); + + return error; +} + +void +hdd_sysfs_dp_traffic_end_indication_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, + &dev_attr_dp_traffic_end_indication); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.h new file mode 100644 index 0000000000..0acf4bd0f8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_traffic_end_indication.h + * + * implementation for creating sysfs files: + * + * dp_traffic_end_indication + */ + +#ifndef _WLAN_HDD_SYSFS_DP_TRAFFIC_END_INDICATION_H +#define _WLAN_HDD_SYSFS_DP_TRAFFIC_END_INDICATION_H + +#ifdef DP_TRAFFIC_END_INDICATION +/** + * hdd_sysfs_dp_traffic_end_indication_create() - API to create dp tx data end + * indication related sysfs entry + * @adapter: hdd adapter + * + * file path: /sys/class/net/wlanxx/dp_traffic_end_indication + * This sysfs entry is created per adapter + * + * usage: + * echo <0/1> > dp_traffic_end_indication + * + * Return: 0 on success and errno on failure + */ +int +hdd_sysfs_dp_traffic_end_indication_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_dp_traffic_end_indication_destroy() - API to destroy dp traffic end + * indication related sysfs entry + * @adapter: hdd adapter + * + * Return: None + */ +void +hdd_sysfs_dp_traffic_end_indication_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_dp_traffic_end_indication_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_dp_traffic_end_indication_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.c new file mode 100644 index 0000000000..c5590fe725 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.c @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_tx_delay_stats.c + * + * implementation for creating sysfs files: + * + * dp_tx_delay_stats + */ +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_object_manager.h" +#include +#include +#include + +static ssize_t +__hdd_sysfs_dp_tx_delay_stats_show(struct net_device *net_dev, + char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + ol_txrx_soc_handle dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t value; + int ret; + + if (hdd_validate_adapter(adapter) || !dp_soc) + return -EINVAL; + + ret = wlan_hdd_validate_context(adapter->hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx)) + return -EINVAL; + + value = cdp_vdev_is_tx_delay_stats_enabled(dp_soc, + adapter->deflink->vdev_id); + + hdd_debug("vdev_id: %d tx_delay_stats: %d", + adapter->deflink->vdev_id, value); + + return scnprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static ssize_t hdd_sysfs_dp_tx_delay_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_dp_tx_delay_stats_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static ssize_t +__hdd_sysfs_dp_tx_delay_stats_store(struct net_device *net_dev, const char *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + ol_txrx_soc_handle dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + char *sptr, *token; + uint8_t value; + int ret; + + if (hdd_validate_adapter(adapter) || !dp_soc) + return -EINVAL; + + ret = wlan_hdd_validate_context(adapter->hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(adapter->hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &value)) + return -EINVAL; + + hdd_debug("vdev_id: %d tx_delay_stats: %d", + adapter->deflink->vdev_id, value); + + cdp_enable_disable_vdev_tx_delay_stats(dp_soc, + adapter->deflink->vdev_id, + value); + + return count; +} + +static ssize_t +hdd_sysfs_dp_tx_delay_stats_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_tx_delay_stats_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(dp_tx_delay_stats, 0660, + hdd_sysfs_dp_tx_delay_stats_show, + hdd_sysfs_dp_tx_delay_stats_store); + +int hdd_sysfs_dp_tx_delay_stats_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_dp_tx_delay_stats); + if (error) + hdd_err("could not create dp_tx_delay_stats sysfs file"); + + return error; +} + +void +hdd_sysfs_dp_tx_delay_stats_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dp_tx_delay_stats); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.h new file mode 100644 index 0000000000..2b57716951 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dp_tx_delay_stats.h + * + * implementation for creating sysfs files: + * + * dp_tx_delay_stats + */ + +#ifndef _WLAN_HDD_SYSFS_DP_TX_DELAY_STATS_H +#define _WLAN_HDD_SYSFS_DP_TX_DELAY_STATS_H + +#if defined(WLAN_SYSFS) && defined(HW_TX_DELAY_STATS_ENABLE) +/** + * hdd_sysfs_dp_tx_delay_stats_create() - API to create dp tx delay stats + * related sysfs entry + * @adapter: hdd adapter + * + * file path: /sys/class/net/wlanxx/dp_tx_delay_stats + * This sysfs entry is created per adapter + * + * usage: + * echo [0/1] > dp_tx_delay_stats + * + * Return: 0 on success and errno on failure + */ +int +hdd_sysfs_dp_tx_delay_stats_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_dp_tx_delay_stats_destroy() - API to destroy dp tx delay stats + * related sysfs entry + * @adapter: hdd adapter + * + * Return: None + */ +void +hdd_sysfs_dp_tx_delay_stats_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_dp_tx_delay_stats_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_dp_tx_delay_stats_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dump_in_progress.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dump_in_progress.c new file mode 100644 index 0000000000..b02232f110 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_dump_in_progress.c @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. +* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_dump_in_progress.c + * + * Dump in progress sysfs implementation + */ + +#include + +#include "wlan_hdd_includes.h" +#include "wlan_hdd_sysfs_dump_in_progress.h" +#include "wlan_hdd_sysfs.h" +#include "osif_sync.h" + +static ssize_t +__hdd_sysfs_dump_in_progress_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int value, ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug_rl("dump in progress %d", value); + if (value < 0 || value > 1) + return -EINVAL; + + hdd_ctx->dump_in_progress = value; + + return count; +} + +static ssize_t hdd_sysfs_dump_in_progress_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dump_in_progress_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t __hdd_sysfs_dump_in_progress_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char *buf) +{ + ssize_t ret_val; + + hdd_debug_rl("dump in progress %d", hdd_ctx->dump_in_progress); + ret_val = scnprintf(buf, PAGE_SIZE, "%d\n", hdd_ctx->dump_in_progress); + + return ret_val; +} + +static ssize_t hdd_sysfs_dump_in_progress_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dump_in_progress_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dump_in_progress_attribute = + __ATTR(dump_in_progress, 0660, hdd_sysfs_dump_in_progress_show, + hdd_sysfs_dump_in_progress_store); + +void hdd_sysfs_create_dump_in_progress_interface(struct kobject *wifi_kobject) +{ + int error; + + if (!wifi_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + error = sysfs_create_file(wifi_kobject, + &dump_in_progress_attribute.attr); + if (error) + hdd_err("could not create dump in progress sysfs file"); +} + +void hdd_sysfs_destroy_dump_in_progress_interface(struct kobject *wifi_kobject) +{ + if (!wifi_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + + sysfs_remove_file(wifi_kobject, + &dump_in_progress_attribute.attr); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_eht_rate.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_eht_rate.c new file mode 100644 index 0000000000..105dcd8f13 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_eht_rate.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_eht_rate.c + * + * implementation for creating sysfs file 11be_rate + * + */ + +#include "wlan_hdd_main.h" +#include "wlan_hdd_eht.h" +#include "wlan_hdd_sysfs.h" +#include "wlan_hdd_sysfs_eht_rate.h" +#include "osif_sync.h" + +static ssize_t +__hdd_sysfs_set_11be_fixed_rate(struct net_device *net_dev, char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + int ret; + uint16_t rate_code; + char *sptr, *token; + + if (hdd_validate_adapter(adapter)) { + hdd_err_rl("invalid adapter"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + hdd_err_rl("invalid hdd context"); + return ret; + } + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) { + hdd_err_rl("invalid module state"); + return -EINVAL; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token || kstrtou16(token, 0, &rate_code)) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + hdd_set_11be_rate_code(adapter, rate_code); + + return count; +} + +static ssize_t hdd_sysfs_set_11be_fixed_rate( + struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_set_11be_fixed_rate(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(11be_rate, 0220, NULL, hdd_sysfs_set_11be_fixed_rate); + +void hdd_sysfs_11be_rate_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_11be_rate); + if (error) + hdd_err("could not create sysfs file to set 11be rate"); +} + +void hdd_sysfs_11be_rate_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_11be_rate); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_eht_rate.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_eht_rate.h new file mode 100644 index 0000000000..2558da987d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_eht_rate.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_eht_rate.h + * + * implementation for creating sysfs file 11be_rate + */ + +#ifndef _WLAN_HDD_SYSFS_EHT_RATE_H +#define _WLAN_HDD_SYSFS_EHT_RATE_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_EHT_RATE) + +/** + * hdd_sysfs_11be_rate_create() - Create sysfs entry to configure 11be rate + * @adapter: net device adapter + * + * Return: None + */ +void hdd_sysfs_11be_rate_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_11be_rate_destroy() - Destroy sysfs entry to configure 11be rate + * @adapter: net device adapter + * + * Return: None + */ +void hdd_sysfs_11be_rate_destroy(struct hdd_adapter *adapter); +#else +static inline void hdd_sysfs_11be_rate_create(struct hdd_adapter *adapter) +{ +} + +static inline void hdd_sysfs_11be_rate_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* _WLAN_HDD_SYSFS_EHT_RATE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_fw_mode_config.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_fw_mode_config.c new file mode 100644 index 0000000000..d9b0f46baa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_fw_mode_config.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_fw_mode_config.c + * + * Implementation for creating sysfs file fw_mode_config + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "wlan_policy_mgr_ucfg.h" + +static ssize_t +__wlan_hdd_store_fw_mode_config_sysfs(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + uint8_t dual_mac_feature = DISABLE_DBS_CXN_AND_SCAN; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t val1, val2; + QDF_STATUS status; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + hdd_debug("set_fw_mode_cfg: count %zu buf_local:(%s)", + count, buf_local); + + sptr = buf_local; + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val2)) + return -EINVAL; + + hdd_debug("Sysfs to set dual fw mode config"); + status = ucfg_policy_mgr_get_dual_mac_feature(hdd_ctx->psoc, + &dual_mac_feature); + if (status != QDF_STATUS_SUCCESS) + hdd_err_rl("can't get dual mac feature val, use def"); + if (dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) { + hdd_err_rl("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d", val1, val2); + policy_mgr_set_dual_mac_fw_mode_config(hdd_ctx->psoc, + val1, val2); + + return count; +} + +static ssize_t +wlan_hdd_store_fw_mode_config_sysfs(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __wlan_hdd_store_fw_mode_config_sysfs(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute set_fw_mode_cfg_attribute = + __ATTR(fw_mode_config, 0220, NULL, + wlan_hdd_store_fw_mode_config_sysfs); + +int hdd_sysfs_fw_mode_config_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &set_fw_mode_cfg_attribute.attr); + if (error) + hdd_err("could not create fw_mode_config sysfs file"); + + return error; +} + +void +hdd_sysfs_fw_mode_config_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &set_fw_mode_cfg_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_fw_mode_config.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_fw_mode_config.h new file mode 100644 index 0000000000..f78e03bb6d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_fw_mode_config.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_fw_mode_config.h + * + * Implementation for creating sysfs file fw_mode_config + */ + +#ifndef _WLAN_HDD_SYSFS_FW_MODE_CONFIG_H +#define _WLAN_HDD_SYSFS_FW_MODE_CONFIG_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_FW_MODE_CFG) +/** + * hdd_sysfs_fw_mode_config_create() - API to create fw_mode_config sysfs file + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/fw_mode_config + * + * usage: + * echo [arg_0] [arg_1] > fw_mode_config + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_fw_mode_config_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_fw_mode_config_destroy() - API to destroy fw_mode_config sysfs file + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_fw_mode_config_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_fw_mode_config_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_fw_mode_config_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_FW_MODE_CONFIG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.c new file mode 100644 index 0000000000..2dee1b5682 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_get_freq_for_pwr.c + * + * implementation for creating sysfs file valid_freq + */ + +#include +#include "osif_vdev_sync.h" +#include +#include "wlan_hdd_sysfs_get_freq_for_pwr.h" +#include "osif_psoc_sync.h" +#include "reg_services_public_struct.h" +#include + +static ssize_t +__hdd_sysfs_power_level_store(struct hdd_context *hdd_ctx, + char const *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + + if (!strncasecmp(token, "VLP", strlen("VLP"))) + hdd_ctx->power_type = REG_VERY_LOW_POWER_AP; + else if (!strncasecmp(token, "LP", strlen("LP"))) + hdd_ctx->power_type = REG_INDOOR_AP; + else if (!strncasecmp(token, "SP", strlen("SP"))) + hdd_ctx->power_type = REG_STANDARD_POWER_AP; + else + hdd_ctx->power_type = REG_MAX_SUPP_AP_TYPE; + + hdd_debug("power level %s(%d)", token, + hdd_ctx->power_type); + + return count; +} + +static ssize_t +wlan_hdd_sysfs_power_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t err_size; + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_power_level_store(hdd_ctx, buf, count); + osif_psoc_sync_op_stop(psoc_sync); + + return err_size; +} + +static ssize_t +__wlan_hdd_sysfs_freq_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, char *buf) +{ + int ret = 0; + struct regulatory_channel *chan_list; + uint32_t len_6g = + NUM_6GHZ_CHANNELS * sizeof(struct regulatory_channel); + QDF_STATUS status; + uint32_t i; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = scnprintf(buf, PAGE_SIZE, "freq list for power type %s\n", + wlan_reg_get_power_string(hdd_ctx->power_type)); + + if (!strcmp(wlan_reg_get_power_string(hdd_ctx->power_type), "INVALID")) + return -EINVAL; + + chan_list = qdf_mem_malloc(len_6g); + if (!chan_list) + return -ENOMEM; + + status = wlan_reg_get_6g_ap_master_chan_list( + hdd_ctx->pdev, + hdd_ctx->power_type, + chan_list); + + for (i = 0; i < NUM_6GHZ_CHANNELS; i++) { + if ((chan_list[i].state != CHANNEL_STATE_DISABLE) && + !(chan_list[i].chan_flags & REGULATORY_CHAN_DISABLED)) { + if ((PAGE_SIZE - ret) <= 0) + goto err; + ret += scnprintf(buf + ret, PAGE_SIZE - ret, + "%d ", chan_list[i].center_freq); + } + } + +err: + qdf_mem_free(chan_list); + return ret; +} + +static ssize_t wlan_hdd_sysfs_freq_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t err_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_sysfs_freq_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return err_size; +} + +static struct kobj_attribute valid_freq_attribute = +__ATTR(valid_freq, 0664, wlan_hdd_sysfs_freq_show, wlan_hdd_sysfs_power_store); + +int hdd_sysfs_get_valid_freq_for_power_create(struct kobject *driver_kobject) +{ + int error; + + error = sysfs_create_file(driver_kobject, &valid_freq_attribute.attr); + if (error) + hdd_err("could not create valid_freq sysfs file"); + + return error; +} + +void +hdd_sysfs_get_valid_freq_for_power_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &valid_freq_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.h new file mode 100644 index 0000000000..c57976b466 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_get_freq_for_pwr.h + * + * implementation for creating sysfs file valid_freq that contains + * valid freq list for provided power type + */ +#ifndef _WLAN_HDD_SYSFS_FREQ_FOR_PWR_H +#define _WLAN_HDD_SYSFS_FREQ_FOR_PWR_H +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_FREQ_LIST) +/** + * hdd_sysfs_get_valid_freq_for_power_create() - API to create get_valid_freq + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/valid_freq + * + * usage: + * echo "VLP"/"LP"/"SP" > valid_freq + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_get_valid_freq_for_power_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_get_valid_freq_for_power_destroy() - + * API to destroy get_valid_freq sysfs + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_get_valid_freq_for_power_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_get_valid_freq_for_power_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_get_valid_freq_for_power_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.c new file mode 100644 index 0000000000..a315f478cd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.c @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_gtx_bw_mask.c + * + * implementation for creating sysfs file gtx_bw_mask + */ + +#include +#include "osif_vdev_sync.h" +#include +#include +#include "wma.h" +#include "wma_api.h" + +static int hdd_sysfs_set_green_tx_param(struct hdd_adapter *adapter, + green_tx_param id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, GTX_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_sysfs_set_green_tx_param(adapter, id, value) \ + hdd_sysfs_set_green_tx_param(adapter, id, #id, value) + +static int hdd_sysfs_get_green_tx_param(struct hdd_adapter *adapter, + green_tx_param id, + const char *id_string) +{ + int value; + + value = wma_cli_get_command(adapter->deflink->vdev_id, id, GTX_CMD); + + hdd_debug("%s %d", id_string, value); + + return value; +} + +#define hdd_sysfs_get_green_tx_param(adapter, id) \ + hdd_sysfs_get_green_tx_param(adapter, id, #id) + +static ssize_t +__hdd_sysfs_gtx_bw_mask_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("gtx_bw_mask: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_green_tx_param(adapter, + wmi_vdev_param_gtx_bw_mask, + value); + + if (ret) { + hdd_err_rl("failed to set green tx BW Mask: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_gtx_bw_mask_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_gtx_bw_mask_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_gtx_bw_mask_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int ret, value; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + value = hdd_sysfs_get_green_tx_param(adapter, + wmi_vdev_param_gtx_bw_mask); + if (value < 0) { + hdd_err_rl("failed to get green tx BW Mask"); + return -EINVAL; + } + + return scnprintf(buf, PAGE_SIZE, "%d", value); +} + +static ssize_t +hdd_sysfs_gtx_bw_mask_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_gtx_bw_mask_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(gtx_bw_mask, 0660, hdd_sysfs_gtx_bw_mask_show, + hdd_sysfs_gtx_bw_mask_store); + +int hdd_sysfs_gtx_bw_mask_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_gtx_bw_mask); + if (error) + hdd_err("could not create gtx_bw_mask sysfs file"); + + return error; +} + +void hdd_sysfs_gtx_bw_mask_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_gtx_bw_mask); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.h new file mode 100644 index 0000000000..c8ec5ed118 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_gtx_bw_mask.h + * + * implementation for creating sysfs file gtx_bw_mask + */ + +#ifndef _WLAN_HDD_SYSFS_GTX_BW_MASK_H +#define _WLAN_HDD_SYSFS_GTX_BW_MASK_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_GTX_BW_MASK) +/** + * hdd_sysfs_gtx_bw_mask_create() - API to create gtx_bw_mask + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/gtx_bw_mask + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > gtx_bw_mask + * cat gtx_bw_mask + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_gtx_bw_mask_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_gtx_bw_mask_destroy() - API to destroy gtx_bw_mask + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_gtx_bw_mask_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_gtx_bw_mask_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_gtx_bw_mask_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_GTX_BW_MASK_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_he_bss_color.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_he_bss_color.c new file mode 100644 index 0000000000..81ece2e6f1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_he_bss_color.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_he_bss_color.c + * + * implementation for creating sysfs file he_bss_color + */ + +#include +#include "osif_vdev_sync.h" +#include +#include "wlan_hdd_sysfs_he_bss_color.h" +#include + +static ssize_t +__hdd_sysfs_he_bss_color_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + QDF_STATUS status; + int value, ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + status = sme_set_he_bss_color(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to set HE BSS color, status %d", status); + return -EINVAL; + } + + return count; +} + +static ssize_t +hdd_sysfs_he_bss_color_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_he_bss_color_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(he_bss_color, 0220, + NULL, hdd_sysfs_he_bss_color_store); + +int hdd_sysfs_he_bss_color_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_he_bss_color); + if (error) + hdd_err("could not create he_bss_color sysfs file"); + + return error; +} + +void hdd_sysfs_he_bss_color_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_he_bss_color); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_he_bss_color.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_he_bss_color.h new file mode 100644 index 0000000000..bfca7b3107 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_he_bss_color.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_he_bss_color.h + * + * implementation for creating sysfs file he_bss_color + */ + +#ifndef _WLAN_HDD_SYSFS_HE_BSS_COLOR_H +#define _WLAN_HDD_SYSFS_HE_BSS_COLOR_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_HE_BSS_COLOR) + +/** + * hdd_sysfs_he_bss_color_create() - API to create he_bss_color + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/he_bss_color + * (wlanxx is adapter name) + * usage: + * echo [value] > he_bss_color + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_he_bss_color_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_he_bss_color_destroy() - API to destroy he_bss_color + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_he_bss_color_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_he_bss_color_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_he_bss_color_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_HE_BSS_COLOR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_ipa.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_ipa.c new file mode 100644 index 0000000000..042b444d71 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_ipa.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "osif_sync.h" + +#ifdef IPA_OFFLOAD +#define MAX_USER_COMMAND_SIZE_IPAUCSTAT 4 + +static ssize_t __hdd_sysfs_ipaucstate_store(struct net_device *net_dev, + const char __user *buf, + size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + uint8_t cmd[MAX_USER_COMMAND_SIZE_IPAUCSTAT] = {0}; + int ret; + char *sptr, *token; + uint8_t set_value = 0; + + hdd_enter(); + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (!ucfg_ipa_is_enabled()) + return -EINVAL; + + if (adapter->device_mode != QDF_SAP_MODE) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(cmd, sizeof(cmd), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = cmd; + /* Get set_value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &set_value)) + return -EINVAL; + + /* If input value is non-zero get stats */ + switch (set_value) { + case IPA_UC_STAT: + ucfg_ipa_uc_stat(hdd_ctx->pdev); + break; + case IPA_UC_INFO: + ucfg_ipa_uc_info(hdd_ctx->pdev); + break; + case IPA_UC_RT_DEBUG_HOST_DUMP: + ucfg_ipa_uc_rt_debug_host_dump(hdd_ctx->pdev); + break; + case IPA_DUMP_INFO: + ucfg_ipa_dump_info(hdd_ctx->pdev); + break; + default: + /* place holder for stats clean up + * Stats clean not implemented yet on FW and IPA + */ + break; + } + hdd_exit(); + return count; +} + +static ssize_t hdd_sysfs_ipaucstate_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_ipaucstate_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + return err_size; +} + +static DEVICE_ATTR(ipaucstat, 0220, + NULL, hdd_sysfs_ipaucstate_store); + +void hdd_sysfs_ipa_create(struct hdd_adapter *adapter) +{ + if (device_create_file(&adapter->dev->dev, &dev_attr_ipaucstat)) + hdd_err("could not create wlan sysfs file"); +} + +void hdd_sysfs_ipa_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_ipaucstat); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_log_buffer.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_log_buffer.c new file mode 100644 index 0000000000..51f172f1b9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_log_buffer.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include + +static ssize_t hdd_sysfs_log_buffer_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_sysfs_print_ctx ctx; + + ctx.buf = buf; + ctx.idx = 0; + ctx.new_line = true; + hdd_dump_log_buffer(&ctx, &hdd_sysfs_print); + return ctx.idx; +} + +static struct kobj_attribute log_buffer_attribute = + __ATTR(log_buffer, 0440, hdd_sysfs_log_buffer_show, + NULL); + +int hdd_sysfs_log_buffer_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &log_buffer_attribute.attr); + if (error) + hdd_err("could not create log_buffer sysfs file"); + + return error; +} + +void +hdd_sysfs_log_buffer_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &log_buffer_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_log_buffer.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_log_buffer.h new file mode 100644 index 0000000000..2de81244e0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_log_buffer.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_LOG_BUFFER_H +#define _WLAN_HDD_SYSFS_LOG_BUFFER_H + +#if defined(WLAN_SYSFS) && defined(FEATURE_SYSFS_LOG_BUFFER) + +/** + * hdd_sysfs_log_buffer_create() - API to create log_buffer sysfs file + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/kiwi_v2/log_buffer + * + * usage: + * cat log_buffer + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_log_buffer_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_log_buffer_destroy(): destroy hdd log buffer sysfs node + * @driver_kobject: pointer to driver kobject + * + * Return: void + * + */ +void +hdd_sysfs_log_buffer_destroy(struct kobject *driver_kobject); + +#else + +static inline int +hdd_sysfs_log_buffer_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_log_buffer_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_mem_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_mem_stats.c new file mode 100644 index 0000000000..421c170aaf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_mem_stats.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_mem_stats.c + * + * Implementation to add sysfs node wlan_mem_stats + * + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include + +static ssize_t __hdd_wlan_mem_stats_show(char *buf) +{ + return scnprintf(buf, PAGE_SIZE, + "DMA = %d HEAP = %d SKB = %d SKB_MAX = %d\n", + qdf_dma_mem_stats_read(), + qdf_heap_mem_stats_read(), + qdf_skb_total_mem_stats_read(), + qdf_skb_max_mem_stats_read()); +} + +static ssize_t __hdd_wlan_dp_mem_stats_show(char *buf) +{ + int32_t len = 0; + + len += scnprintf(buf + len, PAGE_SIZE, + "TX_NBUF_MEM = %d MAX_TX_NBUF_MEM = %d " + "RX_NBUF_MEM = %d MAX_RX_NBUF_MEM = %d " + "TX_NBUF_CNT = %d MAX_TX_NBUF_CNT = %d " + "RX_NBUF_CNT = %d MAX_RX_NBUF_CNT = %d " + "PENDING_TX_DESCS = %d MAX_PENDING_TX_DESCS = %d\n", + qdf_dp_tx_skb_mem_stats_read(), + qdf_dp_tx_skb_max_mem_stats_read(), + qdf_dp_rx_skb_mem_stats_read(), + qdf_dp_rx_skb_max_mem_stats_read(), + qdf_mem_dp_tx_skb_cnt_read(), + qdf_mem_dp_tx_skb_max_cnt_read(), + qdf_mem_dp_rx_skb_cnt_read(), + qdf_mem_dp_rx_skb_max_cnt_read(), + qdf_mem_tx_desc_cnt_read(), + qdf_mem_tx_desc_max_read()); + return len; +} + +static ssize_t hdd_wlan_mem_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + ssize_t length; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return errno; + + length = __hdd_wlan_mem_stats_show(buf); + if (psoc_sync) + osif_psoc_sync_op_stop(psoc_sync); + + return length; +} + +static ssize_t hdd_wlan_dp_mem_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync; + ssize_t length; + int errno; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return errno; + + length = __hdd_wlan_dp_mem_stats_show(buf); + if (psoc_sync) + osif_psoc_sync_op_stop(psoc_sync); + + return length; +} + +static struct kobj_attribute mem_stats_attribute = + __ATTR(wlan_mem_stats, 0440, hdd_wlan_mem_stats_show, NULL); + +static struct kobj_attribute mem_dp_stats_attribute = + __ATTR(wlan_dp_mem_stats, 0440, hdd_wlan_dp_mem_stats_show, NULL); + +int hdd_sysfs_mem_stats_create(struct kobject *wlan_kobject) +{ + int error; + + if (!wlan_kobject) { + hdd_err("Could not get wlan kobject!"); + return -EINVAL; + } + error = sysfs_create_file(wlan_kobject, &mem_stats_attribute.attr); + if (error) { + hdd_err("Failed to create sysfs file wlan_mem_stats"); + return -EINVAL; + } + error = sysfs_create_file(wlan_kobject, &mem_dp_stats_attribute.attr); + if (error) { + hdd_err("Failed to create sysfs file wlan_dp_mem_stats"); + sysfs_remove_file(wlan_kobject, &mem_stats_attribute.attr); + return -EINVAL; + } + + qdf_mem_stats_init(); + + return error; +} + +void hdd_sysfs_mem_stats_destroy(struct kobject *wlan_kobject) +{ + if (!wlan_kobject) { + hdd_err("Could not get wlan kobject!"); + return; + } + sysfs_remove_file(wlan_kobject, &mem_dp_stats_attribute.attr); + sysfs_remove_file(wlan_kobject, &mem_stats_attribute.attr); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_mem_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_mem_stats.h new file mode 100644 index 0000000000..2d4a0f33ca --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_mem_stats.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_mem_stats.h + * + * Implementation to add sysfs node wlan_mem_stats + */ + +#ifndef _WLAN_HDD_SYSFS_MEM_STATS +#define _WLAN_HDD_SYSFS_MEM_STATS + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_MEM_STATS) +/** + * hdd_sysfs_mem_stats_create() - Function to create + * wlan_mem_stats sysfs node to capture host driver memory usage + * @wlan_kobject: sysfs wlan kobject + * + * file path: /sys/kernel/wifi/wlan/wlan_mem_stats + * + * usage: cat /sys/kernel/wifi/wlan/wlan_mem_stats + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_mem_stats_create(struct kobject *wlan_kobject); + +/** + * hdd_sysfs_mem_stats_destroy() - API to destroy wlan_mem_stats + * @wlan_kobject: sysfs wlan kobject + * + * Return: none + */ +void hdd_sysfs_mem_stats_destroy(struct kobject *wlan_kobject); +#else +static inline int +hdd_sysfs_mem_stats_create(struct kobject *wlan_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_mem_stats_destroy(struct kobject *wlan_kobject) +{ +} +#endif /* WLAN_SYSFS && CONFIG_WLAN_SYSFS_MEM_STATS */ +#endif /* _WLAN_HDD_SYSFS_MEM_STATS */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_modify_acl.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_modify_acl.c new file mode 100644 index 0000000000..bfc7ba028d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_modify_acl.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_modify_acl.c + * + * implementation for creating sysfs file modify_acl + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_sysfs.h" +#include "wlan_hdd_sysfs_modify_acl.h" + +#define MAX_USER_COMMAND_SIZE_MODIFY_ACL 64 + +static ssize_t __hdd_sysfs_modify_acl_store( + struct net_device *net_dev, + const char *buf, size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_USER_COMMAND_SIZE_MODIFY_ACL + 1]; + char *sptr, *token; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + eSapACLType list_type; + eSapACLCmdType cmd_type; + int ret, i; + QDF_STATUS qdf_status; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_SAP_MODE) { + hdd_err_rl("Command only allowed in sap mode"); + return -EINVAL; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + hdd_debug("modify_acl: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + sptr = buf_local; + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &peer_mac[i])) + return -EINVAL; + } + + /* Get list_type */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &list_type)) + return -EINVAL; + + /* Get cmd_type */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &cmd_type)) + return -EINVAL; + + hdd_debug("Modify ACL mac:" QDF_MAC_ADDR_FMT " type: %d cmd: %d", + QDF_MAC_ADDR_REF(peer_mac), list_type, cmd_type); + + qdf_status = wlansap_modify_acl( + WLAN_HDD_GET_SAP_CTX_PTR(adapter->deflink), + peer_mac, list_type, cmd_type); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Modify ACL failed"); + return -EIO; + } + + return count; +} + +static ssize_t hdd_sysfs_modify_acl_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_modify_acl_store( + net_dev, buf, count); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(modify_acl, 0220, + NULL, hdd_sysfs_modify_acl_store); + +int hdd_sysfs_modify_acl_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_modify_acl); + if (error) + hdd_err("could not create modify_acl sysfs file"); + + return error; +} + +void hdd_sysfs_modify_acl_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_modify_acl); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_modify_acl.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_modify_acl.h new file mode 100644 index 0000000000..1247a29dd7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_modify_acl.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_modify_acl.h + * + * implementation for creating sysfs file modify_acl + */ + +#ifndef _WLAN_HDD_SYSFS_MODIFY_ACL_H +#define _WLAN_HDD_SYSFS_MODIFY_ACL_H + +#if defined(WLAN_SYSFS) +/** + * hdd_sysfs_modify_acl_create() - API to create modify_acl + * @adapter: hdd adapter + * + * this file is created for sap adapter. + * file path: /sys/class/net/wlan_xx/modify_acl + * (wlan_xx is adapter name) + * usage: + * echo <6 octet mac addr> > modify_acl + * eg: echo 0x00 0x11 0x22 0x33 0x44 0x55 0 0 >modify_acls + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_modify_acl_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_modify_acl_destroy() - + * API to destroy modify_acl sys file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_modify_acl_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_modify_acl_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_modify_acl_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_MODIFY_ACL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.c new file mode 100644 index 0000000000..d0f585c917 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.c @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_monitor_mode_channel.c + * + * Implementation for creating sysfs file monitor_mode_channel + */ + +#include +#include "osif_vdev_sync.h" +#include +#include + +static ssize_t +__hdd_sysfs_monitor_mode_channel_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t val1, val2; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("set_mon_chan: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val2)) + return -EINVAL; + + if (val1 > 256) + ret = wlan_hdd_set_mon_chan(adapter, val1, val2); + else + ret = wlan_hdd_set_mon_chan(adapter, + wlan_reg_legacy_chan_to_freq( + hdd_ctx->pdev, val1), + val2); + + return count; +} + +static ssize_t +hdd_sysfs_monitor_mode_channel_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_monitor_mode_channel_store(net_dev, + buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(monitor_mode_channel, 0220, + NULL, hdd_sysfs_monitor_mode_channel_store); + +int hdd_sysfs_monitor_mode_channel_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_monitor_mode_channel); + if (error) + hdd_err("could not create monitor_mode_channel sysfs file"); + + return error; +} + +void hdd_sysfs_monitor_mode_channel_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_monitor_mode_channel); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.h new file mode 100644 index 0000000000..a62ee3c0eb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_monitor_mode_channel.h + * + * Implementation for creating sysfs file monitor_mode_channel + */ + +#ifndef _WLAN_HDD_SYSFS_MONITOR_MODE_CHANNEL_H +#define _WLAN_HDD_SYSFS_MONITOR_MODE_CHANNEL_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL) +/** + * hdd_sysfs_monitor_mode_channel_create() - + * API to create monitor_mode_channel + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/monitor_mode_channel + * (wlanxx is adapter name) + * usage: + * echo [arg_0] [arg_1] > monitor_mode_channel + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_monitor_mode_channel_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_monitor_mode_channel_destroy() - + * API to destroy monitor_mode_channel sysfs file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_monitor_mode_channel_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_monitor_mode_channel_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_monitor_mode_channel_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_MONITOR_MODE_CHANNEL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_motion_detection.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_motion_detection.c new file mode 100644 index 0000000000..bb54bc535c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_motion_detection.c @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_motion_detection.c + * + * implementation for creating sysfs file motion_detection + */ + +#include +#include +#include "osif_vdev_sync.h" +#include +#include +#include "sme_api.h" + +#define HDD_SYSFS_MT_CONFIG_UINT32_ARGS (10) +#define HDD_SYSFS_MT_CONFIG_UINT8_ARGS (5) +#define HDD_SYSFS_MT_CONFIG_NUM_ARGS (15) +#define HDD_SYSFS_MT_CONFIG_UINT8_INDEX (11) +#define MAX_SYSFS_MT_USER_COMMAND_SIZE_LENGTH (64) + +static ssize_t +__hdd_sysfs_mt_bl_config_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct sme_motion_det_base_line_cfg motion_det_base_line_cfg; + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t bl_time_t, bl_packet_gap, bl_n, bl_num_meas; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("mt_bl_config: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &bl_time_t)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &bl_packet_gap)) + return -EINVAL; + + /* Get val3 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &bl_n)) + return -EINVAL; + + /* Get val4 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &bl_num_meas)) + return -EINVAL; + + motion_det_base_line_cfg.vdev_id = adapter->deflink->vdev_id; + motion_det_base_line_cfg.bl_time_t = bl_time_t; + motion_det_base_line_cfg.bl_packet_gap = bl_packet_gap; + motion_det_base_line_cfg.bl_n = bl_n; + motion_det_base_line_cfg.bl_num_meas = bl_num_meas; + sme_motion_det_base_line_config(hdd_ctx->mac_handle, + &motion_det_base_line_cfg); + + return count; +} + +static ssize_t +hdd_sysfs_mt_bl_config_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_mt_bl_config_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_mt_bl_start_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct sme_motion_det_base_line_en motion_det_base_line; + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + QDF_STATUS status; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + /* Do not send baselining start/stop during motion detection phase */ + if (adapter->motion_det_in_progress) { + hdd_err("Motion detection still in progress, try later"); + return -EAGAIN; + } + + sptr = buf_local; + hdd_debug("mt_bl_start: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + if (value < 0 || value > 1) { + hdd_err("Invalid value %d in mt_bl_start", value); + return -EINVAL; + } + + motion_det_base_line.vdev_id = adapter->deflink->vdev_id; + motion_det_base_line.enable = value; + status = sme_motion_det_base_line_enable(hdd_ctx->mac_handle, + &motion_det_base_line); + + if (status != QDF_STATUS_SUCCESS) + hdd_err("can't enable md baselining msg to scheduler"); + + return count; +} + +static ssize_t +hdd_sysfs_mt_bl_start_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_mt_bl_start_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_mt_config_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct sme_motion_det_cfg motion_det_cfg; + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_MT_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint8_t val_8[HDD_SYSFS_MT_CONFIG_UINT8_ARGS]; + uint32_t val_32[HDD_SYSFS_MT_CONFIG_UINT32_ARGS]; + int i, ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("mt_config: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + for (i = 0; i < HDD_SYSFS_MT_CONFIG_NUM_ARGS; i++) { + token = strsep(&sptr, " "); + if (!token) { + hdd_err_rl("mt_config: not enough args(%d), expected args_num: 15", + i); + return -EINVAL; + } + if ( i >= HDD_SYSFS_MT_CONFIG_UINT8_INDEX) { + if (kstrtou8(token, 0, + &val_8[i - HDD_SYSFS_MT_CONFIG_UINT8_INDEX])) + return -EINVAL; + } else { + if (kstrtou32(token, 0, &val_32[i])) + return -EINVAL; + } + } + + motion_det_cfg.vdev_id = adapter->deflink->vdev_id; + motion_det_cfg.time_t1 = val_32[0]; + motion_det_cfg.time_t2 = val_32[1]; + motion_det_cfg.n1 = val_32[2]; + motion_det_cfg.n2 = val_32[3]; + motion_det_cfg.time_t1_gap = val_32[4]; + motion_det_cfg.time_t2_gap = val_32[5]; + motion_det_cfg.coarse_K = val_32[6]; + motion_det_cfg.fine_K = val_32[7]; + motion_det_cfg.coarse_Q = val_32[8]; + motion_det_cfg.fine_Q = val_32[9]; + motion_det_cfg.md_coarse_thr_high = val_8[0]; + motion_det_cfg.md_fine_thr_high = val_8[1]; + motion_det_cfg.md_coarse_thr_low = val_8[2]; + motion_det_cfg.md_fine_thr_low = val_8[3]; + adapter->motion_detection_mode = val_8[4]; + sme_motion_det_config(hdd_ctx->mac_handle, &motion_det_cfg); + adapter->motion_det_cfg = true; + + return count; +} + +static ssize_t +hdd_sysfs_mt_config_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_mt_config_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_mt_start_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct sme_motion_det_en motion_det; + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("mt_start: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + if (value < 0 || value > 1) { + hdd_err("Invalid value %d in mt_start", value); + return -EINVAL; + } + + if (!adapter->motion_det_cfg) { + hdd_err("Motion Detection config values not available"); + return -EINVAL; + } + + if (!adapter->motion_det_baseline_value) { + hdd_err("Motion Detection Baselining not started/completed"); + return -EAGAIN; + } + + motion_det.vdev_id = adapter->deflink->vdev_id; + motion_det.enable = value; + + if (value) { + /* For motion detection start, set motion_det_in_progress */ + adapter->motion_det_in_progress = true; + } else { + /* For motion detection stop, reset motion_det_in_progress */ + adapter->motion_det_in_progress = false; + adapter->motion_detection_mode = 0; + } + + sme_motion_det_enable(hdd_ctx->mac_handle, &motion_det); + + return count; +} + +static ssize_t +hdd_sysfs_mt_start_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_mt_start_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(mt_bl_config, 0220, + NULL, hdd_sysfs_mt_bl_config_store); + +static DEVICE_ATTR(mt_bl_start, 0220, + NULL, hdd_sysfs_mt_bl_start_store); + +static DEVICE_ATTR(mt_config, 0220, + NULL, hdd_sysfs_mt_config_store); + +static DEVICE_ATTR(mt_start, 0220, + NULL, hdd_sysfs_mt_start_store); + +static int hdd_sysfs_mt_bl_config_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_mt_bl_config); + if (error) + hdd_err("could not create mt_bl_config sysfs file"); + + return error; +} + +static void hdd_sysfs_mt_bl_config_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_mt_bl_config); +} + +static int hdd_sysfs_mt_bl_start_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_mt_bl_start); + if (error) + hdd_err("could not create mt_bl_start sysfs file"); + + return error; +} + +static void hdd_sysfs_mt_bl_start_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_mt_bl_start); +} + +static int hdd_sysfs_mt_config_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_mt_config); + if (error) + hdd_err("could not create mt_config sysfs file"); + + return error; +} + +static void hdd_sysfs_mt_config_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_mt_config); +} + +static int hdd_sysfs_mt_start_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_mt_start); + if (error) + hdd_err("could not create mt_start sysfs file"); + + return error; +} + +static void hdd_sysfs_mt_start_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_mt_start); +} + +void hdd_sysfs_motion_detection_create(struct hdd_adapter *adapter) +{ + hdd_sysfs_mt_bl_config_create(adapter); + hdd_sysfs_mt_bl_start_create(adapter); + hdd_sysfs_mt_config_create(adapter); + hdd_sysfs_mt_start_create(adapter); +} + +void hdd_sysfs_motion_detection_destroy(struct hdd_adapter *adapter) +{ + hdd_sysfs_mt_start_destroy(adapter); + hdd_sysfs_mt_config_destroy(adapter); + hdd_sysfs_mt_bl_start_destroy(adapter); + hdd_sysfs_mt_bl_config_destroy(adapter); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_motion_detection.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_motion_detection.h new file mode 100644 index 0000000000..172a8fef55 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_motion_detection.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_motion_detection.h + * + * implementation for creating sysfs file motion_detection + */ + +#ifndef _WLAN_HDD_SYSFS_MOTION_DETECTION_H +#define _WLAN_HDD_SYSFS_MOTION_DETECTION_H + +#if defined(WLAN_SYSFS) && defined(WLAN_FEATURE_MOTION_DETECTION) +/** + * hdd_sysfs_motion_detection_create() - API to create motion + * detection sysfs attributes + * @adapter: hdd adapter + * + * This API creates the following sysfs attributes: + * 1. mt_bl_config + * 2. mt_bl_start + * 3. mt_config + * 4. mt_start + * + * mt_bl_config: this file is created per adapter. + * file path: /sys/class/net/wlanxx/mt_bl_config + * (wlanxx is adapter name) + * usage: + * echo [arg_0] [arg_1] [arg_2] [arg_3] > mt_bl_config + * + * mt_bl_start: this file is created per adapter. + * file path: /sys/class/net/wlanxx/mt_bl_start + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > mt_bl_start + * + * mt_config: this file is created per adapter. + * file path: /sys/class/net/wlanxx/mt_config + * (wlanxx is adapter name) + * usage: + * echo [arg_0] [arg_1] [arg_2] [arg_4] [arg_5] [arg_6] [arg_7] [arg_8] + * [arg_9] [arg_10] [arg_11] [arg_12] [arg_13] [arg_14] > mt_config + * + * mt_start: this file is created per adapter. + * file path: /sys/class/net/wlanxx/mt_start + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > mt_start + * + * Return: None + */ +void hdd_sysfs_motion_detection_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_motion_detection_destroy() - + * API to destroy motion detection sysfs attributes + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_motion_detection_destroy(struct hdd_adapter *adapter); + +#else +static inline void +hdd_sysfs_motion_detection_create(struct hdd_adapter *adapter) +{ +} + +static inline void +hdd_sysfs_motion_detection_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_MOTION_DETECTION_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_pktlog.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_pktlog.c new file mode 100644 index 0000000000..69ed330c85 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_pktlog.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "osif_sync.h" + +#define MAX_USER_COMMAND_SIZE_PKT_LOG_CMD 4 + +static ssize_t __hdd_sysfs_pkt_log_cmd_store(struct hdd_context *hdd_ctx, + const char *buf, size_t count) +{ + char buf_local[MAX_USER_COMMAND_SIZE_PKT_LOG_CMD + 1]; + char *sptr, *token; + uint32_t val1, val2; + int ret; + + hdd_enter(); + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) + return -EINVAL; + + sptr = buf_local; + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + sptr = buf_local; + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val2)) + return -EINVAL; + + ret = hdd_process_pktlog_command(hdd_ctx, val1, val2); + + hdd_exit(); + return count; +} + +static ssize_t hdd_sysfs_pkt_log_cmd_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t err_size; + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_pkt_log_cmd_store(hdd_ctx, buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + return err_size; +} + +static struct kobj_attribute pktlog_attribute = + __ATTR(pktlog, 0220, NULL, + hdd_sysfs_pkt_log_cmd_store); + +void hdd_sysfs_pktlog_create(struct kobject *driver_kobject) +{ + if (sysfs_create_file(driver_kobject, &pktlog_attribute.attr)) + hdd_err("Failed to create pktlog sysfs entry"); +} + +void hdd_sysfs_pktlog_destroy(struct kobject *driver_kobject) +{ + sysfs_remove_file(driver_kobject, &pktlog_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_policy_mgr.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_policy_mgr.c new file mode 100644 index 0000000000..00cde5aa26 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_policy_mgr.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include + +static ssize_t hdd_pm_cinfo_show(struct hdd_context *hdd_ctx) +{ + struct policy_mgr_conc_connection_info *conn_info; + uint32_t i = 0, len = 0; + + hdd_enter(); + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + conn_info = policy_mgr_get_conn_info(&len); + pr_info("+--------------------------+\n"); + for (i = 0; i < len; i++) { + if (!conn_info->in_use) + continue; + + pr_info("|table_index[%d]\t\t\n", i); + pr_info("|\t|vdev_id - %-10d|\n", conn_info->vdev_id); + pr_info("|\t|freq - %-10d|\n", conn_info->freq); + pr_info("|\t|bw - %-10d|\n", conn_info->bw); + pr_info("|\t|mode - %-10d|\n", conn_info->mode); + pr_info("|\t|mac_id - %-10d|\n", conn_info->mac); + pr_info("|\t|in_use - %-10d|\n", conn_info->in_use); + pr_info("+--------------------------+\n"); + conn_info++; + } + + pr_info("|\t|current state dbs - %-10d, sbs - %-10d|\n", + policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc), + policy_mgr_is_current_hwmode_sbs(hdd_ctx->psoc)); + + hdd_exit(); + return 0; +} + +static ssize_t hdd_sysfs_pm_cminfo_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t err_size; + + if (wlan_hdd_validate_context(hdd_ctx)) + return 0; + + err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (err_size) + return err_size; + + err_size = hdd_pm_cinfo_show(hdd_ctx); + + osif_psoc_sync_op_stop(psoc_sync); + return err_size; +} + +static ssize_t +__hdd_sysfs_pm_pcl_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + uint8_t weight_list[NUM_CHANNELS] = {0}; + uint32_t pcl[NUM_CHANNELS] = {0}; + uint32_t pcl_len = 0, val, i = 0; + char *sptr, *token; + QDF_STATUS status; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("pm_pcl: count %zu buf_local:(%s)", + count, buf_local); + + /* Get val */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val)) + return -EINVAL; + + if (!hdd_ctx->config->is_unit_test_framework_enabled) { + hdd_warn_rl("UT framework is disabled"); + return -EINVAL; + } + + status = policy_mgr_get_pcl(hdd_ctx->psoc, val, + pcl, &pcl_len, + weight_list, QDF_ARRAY_SIZE(weight_list), + WLAN_INVALID_VDEV_ID); + + if (status != QDF_STATUS_SUCCESS) + hdd_err("can't get pcl policy manager"); + + hdd_debug("PCL Freq list for role[%d] is {", val); + for (i = 0 ; i < pcl_len; i++) + hdd_debug(" %d, ", pcl[i]); + hdd_debug("}--------->\n"); + + return count; +} + +static ssize_t +hdd_sysfs_pm_pcl_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_pm_pcl_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute pm_pcl_attribute = + __ATTR(pm_pcl, 0220, NULL, + hdd_sysfs_pm_pcl_store); + +static struct kobj_attribute pm_cinfo_attribute = + __ATTR(pm_cinfo, 0440, + hdd_sysfs_pm_cminfo_show, NULL); + +int hdd_sysfs_pm_pcl_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &pm_pcl_attribute.attr); + if (error) + hdd_err("could not create pm_pcl sysfs file"); + + return error; +} + +void +hdd_sysfs_pm_pcl_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &pm_pcl_attribute.attr); +} + +void hdd_sysfs_pm_cinfo_create(struct kobject *driver_kobject) +{ + if (sysfs_create_file(driver_kobject, &pm_cinfo_attribute.attr)) + hdd_err("Failed to create pktlog sysfs entry"); +} + +void hdd_sysfs_pm_cinfo_destroy(struct kobject *driver_kobject) +{ + sysfs_remove_file(driver_kobject, &pm_cinfo_attribute.attr); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_radar.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_radar.c new file mode 100644 index 0000000000..0415dea341 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_radar.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_radar.c + * + * Implementation for creating sysfs file radar + */ + +#include +#include "osif_vdev_sync.h" +#include +#include +#include "wlan_dfs_tgt_api.h" + +static ssize_t +__hdd_sysfs_radar_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_ap_ctx *ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct wlan_objmgr_pdev *pdev; + struct radar_found_info radar; + struct hdd_context *hdd_ctx; + char *sptr, *token; + int set_value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("set_radar: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get set_value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &set_value)) + return -EINVAL; + + hdd_debug("Set QCASAP_SET_RADAR_CMD val %d", set_value); + + pdev = hdd_ctx->pdev; + if (!pdev) { + hdd_err("null pdev"); + return -EINVAL; + } + + qdf_mem_zero(&radar, sizeof(radar)); + if (policy_mgr_get_dfs_beaconing_session_id(hdd_ctx->psoc) != + WLAN_UMAC_VDEV_ID_MAX) + tgt_dfs_process_radar_ind(pdev, &radar); + else + hdd_debug("Ignore set radar, op ch_freq(%d) is not dfs", + ap_ctx->operating_chan_freq); + + return count; +} + +static ssize_t +hdd_sysfs_radar_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_radar_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(radar, 0220, + NULL, hdd_sysfs_radar_store); + +int hdd_sysfs_radar_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_radar); + if (error) + hdd_err("could not create radar sysfs file"); + + return error; +} + +void hdd_sysfs_radar_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_radar); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_radar.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_radar.h new file mode 100644 index 0000000000..ab241e709d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_radar.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_radar.h + * + * implementation for creating sysfs file radar + */ + +#ifndef _WLAN_HDD_SYSFS_RADAR_H +#define _WLAN_HDD_SYSFS_RADAR_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_RADAR) +/** + * hdd_sysfs_radar_create() - API to create radar sysfs file + * (for sap mode only) + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/radar + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > radar + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_radar_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_radar_destroy() - + * API to destroy radar sysfs file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_radar_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_radar_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_radar_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_RADAR_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_range_ext.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_range_ext.c new file mode 100644 index 0000000000..af13064a78 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_range_ext.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_range_ext.c + * + * implementation for creating sysfs file range_ext + */ + +#include +#include "osif_vdev_sync.h" +#include +#include "wma_api.h" +#include "wlan_hdd_sysfs_range_ext.h" + +static ssize_t +__hdd_sysfs_range_ext_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + hdd_debug("GET wmi_vdev_param_he_range_ext"); + value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_range_ext, VDEV_CMD); + + return scnprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static ssize_t +hdd_sysfs_range_ext_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_range_ext_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static ssize_t __hdd_sysfs_range_ext_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret, errno; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("range_ext: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("wmi_vdev_param_he_range_ext %d", value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_range_ext, + value, VDEV_CMD); + if (errno) + hdd_err("Failed to set he_range_ext firmware param, errno %d", + errno); + + return count; +} + +static ssize_t +hdd_sysfs_range_ext_store(struct device *dev, struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_range_ext_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(range_ext, 0660, hdd_sysfs_range_ext_show, + hdd_sysfs_range_ext_store); + +void hdd_sysfs_range_ext_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_range_ext); + if (error) + hdd_err("could not create range_ext sysfs file"); +} + +void hdd_sysfs_range_ext_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_range_ext); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_reassoc.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_reassoc.c new file mode 100644 index 0000000000..2928a135e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_reassoc.c @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_reassoc.c + * + * implementation for creating sysfs file reassoc + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_sysfs_reassoc.h" +#include "wlan_cm_roam_ucfg_api.h" + +static ssize_t +__wlan_hdd_store_reassoc_sysfs(struct net_device *net_dev, char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + uint32_t operating_ch; + int ret; + struct qdf_mac_addr target_bssid; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + mac_handle = hdd_ctx->mac_handle; + operating_ch = wlan_get_operation_chan_freq(adapter->deflink->vdev); + wlan_mlme_get_bssid_vdev_id(hdd_ctx->pdev, adapter->deflink->vdev_id, + &target_bssid); + hdd_debug("reassoc: net_devname %s", net_dev->name); + ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, adapter->deflink->vdev_id, + &target_bssid, operating_ch, CM_ROAMING_USER); + + return count; +} + +static ssize_t wlan_hdd_store_reassoc_sysfs(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_store_reassoc_sysfs(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(reassoc, 0220, + NULL, wlan_hdd_store_reassoc_sysfs); + +int hdd_sysfs_reassoc_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_reassoc); + if (error) + hdd_err("could not create reassoc sysfs file"); + + return error; +} + +void hdd_sysfs_reassoc_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_reassoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_reassoc.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_reassoc.h new file mode 100644 index 0000000000..c7940b9740 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_reassoc.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_reassoc.h + * + * implementation for creating sysfs file reassoc + */ + +#ifndef _WLAN_HDD_SYSFS_REASSOC_H +#define _WLAN_HDD_SYSFS_REASSOC_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_REASSOC) +/** + * hdd_sysfs_reassoc_create() - API to create reassoc + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/reassoc + * where wlanxx is adapter name + * + * usage: + * echo [arg_0] > reassoc + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_reassoc_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_reassoc_destroy() - + * API to destroy reassoc + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_reassoc_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_reassoc_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_reassoc_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_REASSOC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rf_test_mode.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rf_test_mode.c new file mode 100644 index 0000000000..b0064af87c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rf_test_mode.c @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_psoc_sync.h" +#include +#include + +#define RF_TEST_MODE_ENABLE 1 + +static ssize_t __hdd_sysfs_rf_test_mode_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char *buf) +{ + int ret = 0; + bool value; + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err_rl("invalid input"); + return ret; + } + + ret = scnprintf(buf, PAGE_SIZE, "0x%x", + ucfg_mlme_is_rf_test_mode_enabled(hdd_ctx->psoc, + &value)); + + return ret; +} + +static ssize_t hdd_sysfs_rf_test_mode_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + if (!hdd_ctx) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_rf_test_mode_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_rf_test_mode_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret = 0; + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err_rl("invalid hdd ctx"); + return ret; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("rf_test_mode: 0x%x", value); + + /* + * To enable rf_test_mode if value set is greater than one + * adjust this value as one by default + */ + if (value > RF_TEST_MODE_ENABLE) + value = RF_TEST_MODE_ENABLE; + + ucfg_mlme_set_rf_test_mode_enabled(hdd_ctx->psoc, value); + + return count; +} + +static ssize_t +hdd_sysfs_rf_test_mode_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + if (!hdd_ctx) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_rf_test_mode_store(hdd_ctx, attr, buf, + count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute rf_test_mode_attribute = + __ATTR(rf_test_mode, 0664, hdd_sysfs_rf_test_mode_show, + hdd_sysfs_rf_test_mode_store); + +int hdd_sysfs_rf_test_mode_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &rf_test_mode_attribute.attr); + if (error) + hdd_err("could not create rf_test_mode sysfs file"); + + return error; +} + +void +hdd_sysfs_rf_test_mode_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &rf_test_mode_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rf_test_mode.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rf_test_mode.h new file mode 100644 index 0000000000..c4ffa92653 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rf_test_mode.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_RF_TEST_MODE_H +#define _WLAN_HDD_SYSFS_RF_TEST_MODE_H + +#if defined(WLAN_SYSFS) && defined(FEATURE_SYSFS_RF_TEST_MODE) + +/** + * hdd_sysfs_rf_test_mode_create() - API to create rf_test_mode sysfs file + * + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel//rf_test_mode + * + * usage: + * echo [arg_0] > rf_test_mode + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_rf_test_mode_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_rf_test_mode_destroy() - destroy hdd rf_test_mode sysfs node + * + * @driver_kobject: pointer to driver kobject + * + * Return: void + * + */ +void +hdd_sysfs_rf_test_mode_destroy(struct kobject *driver_kobject); + +#else + +static inline int +hdd_sysfs_rf_test_mode_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_rf_test_mode_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.c new file mode 100644 index 0000000000..f42bb9f143 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_psoc_sync.h" +#include +#include + +static ssize_t __hdd_sysfs_roam_trigger_bitmap_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char *buf) +{ + int ret = 0; + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err_rl("invalid input"); + return ret; + } + + ret = scnprintf(buf, PAGE_SIZE, "0x%x", + ucfg_mlme_get_roaming_triggers(hdd_ctx->psoc)); + + return ret; +} + +static ssize_t hdd_sysfs_roam_trigger_bitmap_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + if (!hdd_ctx) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_roam_trigger_bitmap_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_roam_trigger_bitmap_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret = 0; + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err_rl("invalid hdd ctx"); + return ret; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("roam_trigger_bitmap: 0x%x", value); + + ucfg_mlme_set_roaming_triggers(hdd_ctx->psoc, value); + + return count; +} + +static ssize_t +hdd_sysfs_roam_trigger_bitmap_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + if (!hdd_ctx) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_roam_trigger_bitmap_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute roam_trigger_bitmap_attribute = + __ATTR(roam_trigger_bitmap, 0664, hdd_sysfs_roam_trigger_bitmap_show, + hdd_sysfs_roam_trigger_bitmap_store); + +int hdd_sysfs_roam_trigger_bitmap_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &roam_trigger_bitmap_attribute.attr); + if (error) + hdd_err("could not create roam_trigger_bitmap sysfs file"); + + return error; +} + +void +hdd_sysfs_roam_trigger_bitmap_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &roam_trigger_bitmap_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.h new file mode 100644 index 0000000000..ab089e6a72 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_ROAM_TRIGGER_BITMAP_H +#define _WLAN_HDD_SYSFS_ROAM_TRIGGER_BITMAP_H + +#if defined(WLAN_SYSFS) && defined(FEATURE_SYSFS_ROAM_TRIGGER_BITMAP) + +/** + * hdd_sysfs_roam_trigger_bitmap_create() - API to create roam_trigger_bitmap + * sysfs file + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/kiwi_v2/roam_trigger_bitmap + * + * usage: + * echo [arg_0] > roam_trigger_bitmap + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_roam_trigger_bitmap_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_roam_trigger_bitmap_destroy() - destroy hdd roam_trigger_bitmap + * sysfs node + * @driver_kobject: pointer to driver kobject + * + * Return: void + * + */ +void +hdd_sysfs_roam_trigger_bitmap_destroy(struct kobject *driver_kobject); + +#else + +static inline int +hdd_sysfs_roam_trigger_bitmap_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_roam_trigger_bitmap_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rts_cts.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rts_cts.c new file mode 100644 index 0000000000..8c731d847d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rts_cts.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_rts_cts.c + * + * implementation for creating sysfs file rts_cts + */ + +#include +#include "osif_vdev_sync.h" +#include +#include "wlan_hdd_sysfs_rts_cts.h" +#include +#include +#include +#include + +static ssize_t +__hdd_sysfs_rts_cts_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t rts_threshold; + QDF_STATUS status; + int value, ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + switch (value) { + case HDD_SYSFS_RTS_CTS_ENABLE: + status = ucfg_mlme_get_rts_threshold(hdd_ctx->psoc, + &rts_threshold); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Get rts threshold failed, status %d", + status); + return -EINVAL; + } + break; + case HDD_SYSFS_RTS_CTS_DISABLE: + case HDD_SYSFS_CTS_ENABLE: + rts_threshold = cfg_max(CFG_RTS_THRESHOLD); + break; + default: + hdd_err_rl("invalid value %d", value); + return -EINVAL; + } + + ret = wma_cli_set_command(adapter->deflink->vdev_id, + wmi_vdev_param_enable_rtscts, + value, VDEV_CMD); + if (ret) { + hdd_err_rl("Failed to set firmware, ret %d", ret); + return ret; + } + + status = ucfg_mlme_set_rts_threshold(hdd_ctx->psoc, rts_threshold); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Set rts threshold failed, status %d", status); + return -EINVAL; + } + + return count; +} + +static ssize_t +hdd_sysfs_rts_cts_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_rts_cts_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(rts_cts, 0220, + NULL, hdd_sysfs_rts_cts_store); + +int hdd_sysfs_rts_cts_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_rts_cts); + if (error) + hdd_err("could not create rts_cts sysfs file"); + + return error; +} + +void hdd_sysfs_rts_cts_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_rts_cts); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rts_cts.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rts_cts.h new file mode 100644 index 0000000000..b7edd9494b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_rts_cts.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_rts_cts.h + * + * implementation for creating sysfs file rts_cts + */ + +#ifndef _WLAN_HDD_SYSFS_RTS_CTS_H +#define _WLAN_HDD_SYSFS_RTS_CTS_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_RTS_CTS) + +#define HDD_SYSFS_RTS_CTS_DISABLE 0 +#define HDD_SYSFS_RTS_CTS_ENABLE 1 +#define HDD_SYSFS_CTS_ENABLE 2 + +/** + * hdd_sysfs_rts_cts_create() - API to create rts_cts + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/rts_cts + * (wlanxx is adapter name) + * usage: + * echo [value] > rts_cts + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_rts_cts_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_rts_cts_destroy() - API to destroy rts_cts + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_rts_cts_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_rts_cts_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_rts_cts_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_RTS_CTS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_runtime_pm.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_runtime_pm.c new file mode 100644 index 0000000000..d621ddeec7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_runtime_pm.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "hif.h" +#include "hif_runtime_pm.h" + +static ssize_t hdd_sysfs_runtime_pm_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return hif_rtpm_log_debug_stats(buf, HIF_RTPM_FILL_TYPE_SYSFS); +} + +static struct kobj_attribute runtime_pm_attribute = + __ATTR(runtime_pm, 0440, hdd_sysfs_runtime_pm_show, + NULL); + +int hdd_sysfs_runtime_pm_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &runtime_pm_attribute.attr); + if (error) + hdd_err("could not create runtime_pm sysfs file"); + + return error; +} + +void +hdd_sysfs_runtime_pm_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &runtime_pm_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_runtime_pm.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_runtime_pm.h new file mode 100644 index 0000000000..578359d8a1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_runtime_pm.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_RUNTIME_PM_H +#define _WLAN_HDD_SYSFS_RUNTIME_PM_H + +#if defined(WLAN_SYSFS) && defined(FEATURE_RUNTIME_PM) + +/** + * hdd_sysfs_runtime_pm_create(): create runtime pm WoW stats sysfs node + * @driver_kobject: pointer to driver kobject + * + * Return: 0 for success and non zero error code for failure + * + */ +int hdd_sysfs_runtime_pm_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_runtime_pm_destroy(): destroy runtime pm WoW stats sysfs node + * @driver_kobject: pointer to driver kobject + * + * Return: void + * + */ +void +hdd_sysfs_runtime_pm_destroy(struct kobject *driver_kobject); + +#else + +static inline int +hdd_sysfs_runtime_pm_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_runtime_pm_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_config.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_config.c new file mode 100644 index 0000000000..9d9c09eb72 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_config.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_scan_config.c + * + * Implementation for creating sysfs file scan_config + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "wlan_policy_mgr_ucfg.h" + +static ssize_t +__hdd_sysfs_scan_config_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + uint8_t dual_mac_feature = DISABLE_DBS_CXN_AND_SCAN; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint8_t val1, val2, val3; + QDF_STATUS status; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("set_scan_cfg: count %zu buf_local:(%s)", + count, buf_local); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &val2)) + return -EINVAL; + + /* Get val3 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &val3)) + return -EINVAL; + + hdd_debug("Sysfs to set dual mac scan config"); + status = ucfg_policy_mgr_get_dual_mac_feature(hdd_ctx->psoc, + &dual_mac_feature); + if (status != QDF_STATUS_SUCCESS) + hdd_err("can't get dual mac feature val, use def"); + if (dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d %d", val1, val2, val3); + policy_mgr_set_dual_mac_scan_config(hdd_ctx->psoc, + val1, val2, val3); + + return count; +} + +static ssize_t +hdd_sysfs_scan_config_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_scan_config_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute set_scan_cfg_attribute = + __ATTR(scan_config, 0220, NULL, + hdd_sysfs_scan_config_store); + +int hdd_sysfs_scan_config_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &set_scan_cfg_attribute.attr); + if (error) + hdd_err("could not create scan_config sysfs file"); + + return error; +} + +void +hdd_sysfs_scan_config_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &set_scan_cfg_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_config.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_config.h new file mode 100644 index 0000000000..6344a8f0c2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_config.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_scan_config.h + * + * implementation for creating sysfs file scan_config + */ + +#ifndef _WLAN_HDD_SYSFS_SCAN_CONFIG_H +#define _WLAN_HDD_SYSFS_SCAN_CONFIG_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_SCAN_CFG) +/** + * hdd_sysfs_scan_config_create() - API to create scan_config sysfs file + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/scan_config + * + * usage: + * echo [arg_0] [arg_1] [arg_2]> scan_config + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_scan_config_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_scan_config_destroy() - API to destroy scan_config sysfs file + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_scan_config_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_scan_config_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_scan_config_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_SCAN_CONFIG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_disable.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_disable.c new file mode 100644 index 0000000000..ba9f82e182 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_disable.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_scan_disable.c + * + * implementation for creating sysfs scan_disable + */ + +#include +#include "osif_psoc_sync.h" +#include +#include + +static ssize_t +__hdd_sysfs_scan_disable_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->psoc) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("scan_disable: count %zu buf_local:(%s)", + count, buf_local); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("%d", value); + + if (value) + ucfg_scan_psoc_set_disable(hdd_ctx->psoc, REASON_USER_SPACE); + else + ucfg_scan_psoc_set_enable(hdd_ctx->psoc, REASON_USER_SPACE); + + return count; +} + +static ssize_t +hdd_sysfs_scan_disable_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_scan_disable_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute scan_disable_attribute = + __ATTR(scan_disable, 0220, NULL, + hdd_sysfs_scan_disable_store); + +int hdd_sysfs_scan_disable_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &scan_disable_attribute.attr); + if (error) + hdd_err("could not create scan_disable sysfs file"); + + return error; +} + +void +hdd_sysfs_scan_disable_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &scan_disable_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_disable.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_disable.h new file mode 100644 index 0000000000..44b933ae39 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_scan_disable.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_scan_disable.h + * + * implementation for creating sysfs file scan_disable + */ + +#ifndef _WLAN_HDD_SYSFS_SCAN_DISABLE_H +#define _WLAN_HDD_SYSFS_SCAN_DISABLE_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SCAN_DISABLE) +/** + * hdd_sysfs_scan_disable_create() - API to create scan_disable + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/scan_disable + * + * usage: + * echo [arg_0] > scan_disable + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_scan_disable_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_scan_disable_destroy() - API to destroy scan_disable + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_scan_disable_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_scan_disable_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_scan_disable_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_SCAN_DISABLE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_sta_info.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_sta_info.c new file mode 100644 index 0000000000..b7df0fbfca --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_sta_info.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_sta_info.c + * + * implementation for creating sysfs file sta_info + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_sysfs_sta_info.h" + +static ssize_t __show_sta_info(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + struct hdd_station_info *sta, *tmp = NULL; + int ret_val; + + hdd_enter_dev(net_dev); + + ret_val = hdd_validate_adapter(adapter); + if (0 != ret_val) + goto exit; + + if (adapter->device_mode != QDF_SAP_MODE) + goto exit; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret_val = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret_val) + goto exit; + + ret_val = scnprintf(buf, PAGE_SIZE, + "%s get_sta_info:\nstaAddress\n", + net_dev->name); + + hdd_for_each_sta_ref_safe(adapter->sta_info_list, sta, tmp, + STA_INFO_SHOW) { + if (QDF_IS_ADDR_BROADCAST(sta->sta_mac.bytes)) { + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, + true, STA_INFO_SHOW); + continue; + } + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + QDF_MAC_ADDR_FMT " ecsa=%d\n", + QDF_MAC_ADDR_REF(sta->sta_mac.bytes), + sta->ecsa_capable); + + hdd_put_sta_info_ref(&adapter->sta_info_list, &sta, true, + STA_INFO_SHOW); + } + +exit: + hdd_exit(); + return ret_val; +} + +static ssize_t show_sta_info(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __show_sta_info(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(sta_info, 0444, show_sta_info, NULL); + +void hdd_sysfs_sta_info_interface_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_sta_info); + if (error) + hdd_err("Could not create sta_info sysfs file"); +} + +void hdd_sysfs_sta_info_interface_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_sta_info); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_stats.c new file mode 100644 index 0000000000..724f63e6a5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_stats.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_stats.c + * + * Implementation for creating sysfs files: + * + * stats + * dump_stats + * clear_stats + */ + +#include +#include "osif_vdev_sync.h" +#include +#include "wlan_hdd_sysfs_stats.h" +#include "cdp_txrx_stats.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" + +static int stats_id = -1; + +static void hdd_sysfs_get_stats(struct hdd_adapter *adapter, ssize_t *length, + char *buffer, size_t buf_len) +{ + struct hdd_tx_rx_stats *stats = + &adapter->deflink->hdd_stats.tx_rx_stats; + struct dp_tx_rx_stats *dp_stats; + uint32_t len = 0; + uint32_t total_rx_pkt = 0, total_rx_dropped = 0; + uint32_t total_rx_delv = 0, total_rx_refused = 0; + uint32_t total_tx_pkt = 0; + uint32_t total_tx_dropped = 0; + uint32_t total_tx_orphaned = 0; + uint32_t total_tx_classified_ac[WLAN_MAX_AC] = {0}; + uint32_t total_tx_dropped_ac[WLAN_MAX_AC] = {0}; + int i = 0; + uint8_t ac, rx_ol_con = 0, rx_ol_low_tput = 0; + struct hdd_context *hdd_ctx = adapter->hdd_ctx; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) + return; + + dp_stats = qdf_mem_malloc(sizeof(*dp_stats)); + if (!dp_stats) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + return; + } + + if (ucfg_dp_get_txrx_stats(vdev, dp_stats)) { + hdd_err("Unable to get stats from DP component"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + qdf_mem_free(dp_stats); + return; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + ucfg_dp_get_disable_rx_ol_val(hdd_ctx->psoc, + &rx_ol_con, &rx_ol_low_tput); + + for (; i < NUM_CPUS; i++) { + total_rx_pkt += dp_stats->per_cpu[i].rx_packets; + total_rx_dropped += dp_stats->per_cpu[i].rx_dropped; + total_rx_delv += dp_stats->per_cpu[i].rx_delivered; + total_rx_refused += dp_stats->per_cpu[i].rx_refused; + total_tx_pkt += dp_stats->per_cpu[i].tx_called; + total_tx_dropped += dp_stats->per_cpu[i].tx_dropped; + total_tx_orphaned += dp_stats->per_cpu[i].tx_orphaned; + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + total_tx_classified_ac[ac] += + stats->per_cpu[i].tx_classified_ac[ac]; + total_tx_dropped_ac[ac] += + stats->per_cpu[i].tx_dropped_ac[ac]; + } + } + + len = scnprintf(buffer, buf_len, + "\nTransmit[%lu] - " + "called %u, dropped %u orphan %u," + "\n[dropped] BK %u, BE %u, VI %u, VO %u" + "\n[classified] BK %u, BE %u, VI %u, VO %u" + "\n\nReceive[%lu] - " + "packets %u, dropped %u, unsolict_arp_n_mcast_drp %u, delivered %u, refused %u\n" + "GRO - agg %u non-agg %u flush_skip %u low_tput_flush %u disabled(conc %u low-tput %u)\n", + qdf_system_ticks(), + total_tx_pkt, + total_tx_dropped, + total_tx_orphaned, + total_tx_dropped_ac[SME_AC_BK], + total_tx_dropped_ac[SME_AC_BE], + total_tx_dropped_ac[SME_AC_VI], + total_tx_dropped_ac[SME_AC_VO], + total_tx_classified_ac[SME_AC_BK], + total_tx_classified_ac[SME_AC_BE], + total_tx_classified_ac[SME_AC_VI], + total_tx_classified_ac[SME_AC_VO], + qdf_system_ticks(), + total_rx_pkt, total_rx_dropped, + qdf_atomic_read(&dp_stats->rx_usolict_arp_n_mcast_drp), + total_rx_delv, + total_rx_refused, + dp_stats->rx_aggregated, dp_stats->rx_non_aggregated, + dp_stats->rx_gro_flush_skip, + dp_stats->rx_gro_low_tput_flush, + rx_ol_con, + rx_ol_low_tput); + + for (i = 0; i < NUM_CPUS; i++) { + if (dp_stats->per_cpu[i].rx_packets == 0) + continue; + len += scnprintf(buffer + len, buf_len - len, + "Rx CPU[%d]:" + "packets %u, dropped %u, delivered %u, refused %u\n", + i, dp_stats->per_cpu[i].rx_packets, + dp_stats->per_cpu[i].rx_dropped, + dp_stats->per_cpu[i].rx_delivered, + dp_stats->per_cpu[i].rx_refused); + } + + len += scnprintf(buffer + len, buf_len - len, + "\nTX_FLOW" + "\nCurrent status: %s" + "\ntx-flow timer start count %u" + "\npause count %u, unpause count %u", + (stats->is_txflow_paused == true ? "PAUSED" : "UNPAUSED"), + stats->txflow_timer_cnt, + stats->txflow_pause_cnt, + stats->txflow_unpause_cnt); + + len += cdp_stats(cds_get_context(QDF_MODULE_ID_SOC), + adapter->deflink->vdev_id, &buffer[len], + (buf_len - len)); + *length = len + 1; + qdf_mem_free(dp_stats); +} + +static ssize_t +__hdd_sysfs_stats_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int ret; + ssize_t length = 0; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + hdd_sysfs_get_stats(adapter, &length, buf, PAGE_SIZE); + + return length; +} + +static ssize_t +hdd_sysfs_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_stats_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(stats, 0440, + hdd_sysfs_stats_show, NULL); + +static ssize_t +__wlan_hdd_sysfs_dump_stats_store(struct net_device *net_dev, char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int value, ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("dump_stats %d", value); + + stats_id = value; + + return count; +} + +static ssize_t wlan_hdd_sysfs_dump_stats_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_sysfs_dump_stats_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static ssize_t +__wlan_hdd_sysfs_dump_stats_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_wlan_dump_stats(adapter, stats_id); + + return ret; +} + +static ssize_t wlan_hdd_sysfs_dump_stats_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_sysfs_dump_stats_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(dump_stats, 0660, wlan_hdd_sysfs_dump_stats_show, + wlan_hdd_sysfs_dump_stats_store); + +static ssize_t +__wlan_hdd_sysfs_clear_stats_store(struct net_device *net_dev, char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int value, ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("clear_stats %d", value); + + ret = hdd_wlan_clear_stats(adapter, value); + if (ret) { + hdd_err_rl("Failed to clear stats"); + return ret; + } + + return count; +} + +static ssize_t wlan_hdd_sysfs_clear_stats_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_sysfs_clear_stats_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(clear_stats, 0220, NULL, + wlan_hdd_sysfs_clear_stats_store); + +int hdd_sysfs_stats_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_dump_stats); + if (error) + hdd_err("could not create dump_stats sysfs file"); + + error = device_create_file(&adapter->dev->dev, &dev_attr_clear_stats); + if (error) + hdd_err("could not create clear_stats sysfs file"); + + error = device_create_file(&adapter->dev->dev, &dev_attr_stats); + if (error) + hdd_err("could not create stats sysfs file"); + + return error; +} + +void hdd_sysfs_stats_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_dump_stats); + device_remove_file(&adapter->dev->dev, &dev_attr_clear_stats); + device_remove_file(&adapter->dev->dev, &dev_attr_stats); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_stats.h new file mode 100644 index 0000000000..00ade11975 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_stats.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2011-2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_stats.h + * + * Implementation for creating sysfs files: + * + * stats + * dump_stats + * clear_stats + */ + +#ifndef _WLAN_HDD_SYSFS_STATS_H +#define _WLAN_HDD_SYSFS_STATS_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SYSFS_STATS) +/** + * hdd_sysfs_stats_create() - API to create stats files + * @adapter: pointer to adapter + * + * these files are created per adapter. + * file path: + * /sys/class/net/wlanxx/dump_stats + * /sys/class/net/wlanxx/clear_stats + * /sys/class/net/wlanxx/stats + * where wlanxx is adapter name + * + * usage: + * echo [stats_id] > dump_stats + * cat dump_stats + * echo [stats_id] > clear_stats + * cat /sys/class/net/wlanxx/stats + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_stats_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_stats_destroy() - + * API to destroy stats + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_stats_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_stats_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_stats_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_STATS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_suspend_resume.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_suspend_resume.c new file mode 100644 index 0000000000..f8fdb59443 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_suspend_resume.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_suspend_resume.c + * + * implementation for creating sysfs file wlan_suspend/wlan_resume + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_power.h" +#include "wlan_hdd_sysfs.h" +#include "wlan_hdd_sysfs_suspend_resume.h" + +static ssize_t __hdd_sysfs_suspend_store( + struct net_device *net_dev, + const char *buf, size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + int ret, pause_setting, resume_setting; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + hdd_nofl_info("wlan_suspend: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + sptr = buf_local; + /* Get pause_setting */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &pause_setting)) + return -EINVAL; + + /* Get resume_setting */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &resume_setting)) + return -EINVAL; + + hdd_nofl_info("wlan_suspend: pause_setting %d, resume_setting %d", + pause_setting, resume_setting); + ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy, net_dev, + pause_setting, resume_setting); + if (ret != 0) { + hdd_err_rl("suspend test failed"); + return -EINVAL; + } + + return count; +} + +static ssize_t hdd_sysfs_suspend_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_suspend_store( + net_dev, buf, count); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(wlan_suspend, 0220, + NULL, hdd_sysfs_suspend_store); + +int hdd_sysfs_suspend_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_wlan_suspend); + if (error) + hdd_err("could not create wlan_suspend sysfs file"); + + return error; +} + +void hdd_sysfs_suspend_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_wlan_suspend); +} + +static ssize_t __hdd_sysfs_resume_store( + struct net_device *net_dev, + const char *buf, size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy, net_dev); + if (ret != 0) { + hdd_err_rl("resume test failed"); + return -EINVAL; + } + + return count; +} + +static ssize_t hdd_sysfs_resume_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_resume_store( + net_dev, buf, count); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(wlan_resume, 0220, + NULL, hdd_sysfs_resume_store); + +int hdd_sysfs_resume_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_wlan_resume); + if (error) + hdd_err("could not create wlan_resume sysfs file"); + + return error; +} + +void hdd_sysfs_resume_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_wlan_resume); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_suspend_resume.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_suspend_resume.h new file mode 100644 index 0000000000..09db3fe597 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_suspend_resume.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_suspend_resume.h + * + * implementation for creating sysfs file crash_inject + */ + +#ifndef _WLAN_HDD_SYSFS_SUSPEND_RESUME_H +#define _WLAN_HDD_SYSFS_SUSPEND_RESUME_H + +#if defined(WLAN_SYSFS) && defined(WLAN_SUSPEND_RESUME_TEST) +/** + * hdd_sysfs_suspend_create() - API to create wlan_suspend + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlan_xx/wlan_suspend + * (wlan_xx is adapter name) + * usage: + * echo [arg_0] [arg_1] > wlan_suspend + * arg_0 from enum wow_interface_pause + * arg_1 from enum wow_resume_trigger + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_suspend_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_suspend_destroy() - + * API to destroy wlan_suspend sys file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_suspend_destroy(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_resume_create() - API to create wlan_resume + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlan_xx/wlan_resume + * (wlan_xx is adapter name) + * usage: + * echo > wlan_resume + * + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_resume_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_resume_destroy() - + * API to destroy wlan_resume sys file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_resume_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_suspend_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_suspend_destroy(struct hdd_adapter *adapter) +{ +} + +static inline int +hdd_sysfs_resume_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_resume_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_SUSPEND_RESUME_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_swlm.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_swlm.c new file mode 100644 index 0000000000..f47657bd58 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_swlm.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +static ssize_t +__hdd_sysfs_dp_swlm_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, char *buf) +{ + ol_txrx_soc_handle soc_hdl = cds_get_context(QDF_MODULE_ID_SOC); + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + return scnprintf(buf, PAGE_SIZE, "dp_swlm enable: %d\n", + cdp_soc_is_swlm_enabled(soc_hdl)); +} + +static ssize_t hdd_sysfs_dp_swlm_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_swlm_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_dp_swlm_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret; + ol_txrx_soc_handle dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!wlan_hdd_validate_modules_state(hdd_ctx) || !dp_soc) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("dp_swlm: %d", value); + + cdp_soc_set_swlm_enable(dp_soc, value); + + return count; +} + +static ssize_t +hdd_sysfs_dp_swlm_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_dp_swlm_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute dp_swlm_attribute = + __ATTR(dp_swlm, 0664, hdd_sysfs_dp_swlm_show, + hdd_sysfs_dp_swlm_store); + +int hdd_sysfs_dp_swlm_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &dp_swlm_attribute.attr); + if (error) + hdd_err("could not create dp_swlm sysfs file"); + + return error; +} + +void hdd_sysfs_dp_swlm_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + + sysfs_remove_file(driver_kobject, &dp_swlm_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tdls_peers.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tdls_peers.c new file mode 100644 index 0000000000..b70d3ab0b5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tdls_peers.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_tdls_peers.c + * + * Implementation for creating sysfs file tdls_peers + */ + +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_hdd_sysfs_tdls_peers.h" + +/** + * __show_tdls_all_peers() - dump all TDLS peer info into output string + * @net_dev: net device + * @buf: output string buffer to hold the peer info + * + * Return: The size (in bytes) of the valid peer info in the output buffer + */ +static int __show_tdls_all_peers(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + int ret_val; + + hdd_enter_dev(net_dev); + + ret_val = scnprintf(buf, PAGE_SIZE, "%s getTdlsPeers:", + net_dev->name); + + if (hdd_validate_adapter(adapter)) { + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + "\nHDD adapter is not valid\n"); + goto exit; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + "\nHDD context is not valid\n"); + goto exit; + } + + if ((QDF_STA_MODE != adapter->device_mode) && + (QDF_P2P_CLIENT_MODE != adapter->device_mode)) { + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + "\nNo TDLS support for this adapter\n"); + goto exit; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (!vdev) { + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + "\nVDEV is NULL\n"); + goto exit; + } + ret_val += wlan_cfg80211_tdls_get_all_peers(vdev, buf + ret_val, + PAGE_SIZE - ret_val); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + +exit: + if ((PAGE_SIZE - ret_val) > 0) + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, "\n"); + + hdd_exit(); + return ret_val; +} + +static ssize_t show_tdls_all_peers(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __show_tdls_all_peers(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(tdls_peers, 0444, show_tdls_all_peers, NULL); + +void hdd_sysfs_tdls_peers_interface_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_tdls_peers); + if (error) + hdd_err("could not create tdls_peers sysfs file"); +} + +void hdd_sysfs_tdls_peers_interface_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_tdls_peers); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_temperature.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_temperature.c new file mode 100644 index 0000000000..41d84bf67d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_temperature.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_temperature.c + * + * Implementation for creating sysfs file temperature + */ + +#include +#include +#include "osif_vdev_sync.h" +#include +#include + +static ssize_t +__hdd_sysfs_temperature_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + hdd_debug("SYSFS_GET_TEMPERATURE"); + ret = wlan_hdd_get_temperature(adapter, &value); + + if (ret) { + hdd_err_rl("GET_TEMP failed: %d", ret); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static ssize_t +hdd_sysfs_temperature_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_temperature_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(temperature, 0440, + hdd_sysfs_temperature_show, NULL); + +int hdd_sysfs_temperature_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_temperature); + if (error) + hdd_err("could not create temperature sysfs file"); + + return error; +} + +void hdd_sysfs_temperature_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_temperature); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_temperature.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_temperature.h new file mode 100644 index 0000000000..19e110e73b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_temperature.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_temperature.h + * + * Implementation for creating sysfs file temperature + */ + +#ifndef _WLAN_HDD_SYSFS_TEMPERATURE_H +#define _WLAN_HDD_SYSFS_TEMPERATURE_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_TEMPERATURE) +/** + * hdd_sysfs_temperature_create() - API to create temperature sysfs file + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/temperature + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/temperature + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_temperature_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_temperature_destroy() - + * API to destroy temperature sysfs file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_temperature_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_temperature_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_temperature_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_TEMPERATURE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_thermal_cfg.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_thermal_cfg.c new file mode 100644 index 0000000000..f500a21a6d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_thermal_cfg.c @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_thermal_cfg.c + * + * implementation for creating sysfs file thermal_cfg + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "qdf_trace.h" +#include "sme_api.h" +#include "qdf_status.h" +#include +#include "wlan_hdd_thermal.h" +#include + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +#ifndef QCN7605_SUPPORT +static QDF_STATUS hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle, + uint16_t lower_thresh_deg, + uint16_t higher_thresh_deg) +{ + return sme_set_thermal_mgmt(mac_handle, lower_thresh_deg, + higher_thresh_deg); +} +#else +static QDF_STATUS hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle, + uint16_t lower_thresh_deg, + uint16_t higher_thresh_deg) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + +static ssize_t +__hdd_sysfs_thermal_cfg_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t val1, val2, val3, val4, val7; + uint16_t val5, val6; + QDF_STATUS status; + int ret; + struct thermal_mitigation_params therm_cfg_params; + struct wlan_fwol_thermal_temp thermal_temp = {0}; + + status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, &thermal_temp); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to get fwol thermal obj"); + return status; + } + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("thermal_cfg: count %zu buf_local:(%s)", + count, buf_local); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val2)) + return -EINVAL; + + /* Get val3 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val3)) + return -EINVAL; + + /* Get val4 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val4)) + return -EINVAL; + + /* Get val5 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &val5)) + return -EINVAL; + + /* Get val6 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &val6)) + return -EINVAL; + + /* Get val7 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val7)) + return -EINVAL; + + /* Check for valid inputs */ + if (val1 < 0 || val1 > 1 || val2 < 0 || val3 < 0 || val3 > 100 || + val4 < 0 || val4 > 3 || val5 < 0 || val6 < 0 || val7 < 0 || + val6 <= val5) + return -EINVAL; + + therm_cfg_params.enable = val1; + therm_cfg_params.dc = val2; + therm_cfg_params.levelconf[0].dcoffpercent = val3; + therm_cfg_params.levelconf[0].priority = val4; + therm_cfg_params.levelconf[0].tmplwm = val7; + hdd_thermal_fill_clientid_priority(hdd_ctx, THERMAL_MONITOR_APPS, + thermal_temp.priority_apps, + thermal_temp.priority_wpps, + &therm_cfg_params); + + status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle, + &therm_cfg_params); + + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + if (!val7) { + status = hdd_send_thermal_mgmt_cmd(hdd_ctx->mac_handle, + val5, val6); + + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + } + + return count; +} + +static ssize_t +hdd_sysfs_thermal_cfg_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_thermal_cfg_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute thermal_cfg_attribute = + __ATTR(thermal_cfg, 0220, NULL, + hdd_sysfs_thermal_cfg_store); + +int hdd_sysfs_thermal_cfg_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &thermal_cfg_attribute.attr); + if (error) + hdd_err("could not create thermal_cfg sysfs file"); + + return error; +} + +void +hdd_sysfs_thermal_cfg_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &thermal_cfg_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_thermal_cfg.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_thermal_cfg.h new file mode 100644 index 0000000000..bdc2929b2f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_thermal_cfg.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_thermal_cfg.h + * + * implementation for creating sysfs file thermal_cfg + */ + +#ifndef _WLAN_HDD_SYSFS_THERMAL_CFG_H +#define _WLAN_HDD_SYSFS_THERMAL_CFG_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_THERMAL_CFG) +/** + * hdd_sysfs_thermal_cfg_create() - API to create thermal_cfg + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/thermal_cfg + * + * usage: + * echo [arg_0] [arg_1] [arg_2] [arg_3] [arg_4] [arg_5] [arg_6] + * > thermal_cfg + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_thermal_cfg_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_thermal_cfg_destroy() - API to destroy thermal_cfg + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_thermal_cfg_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_thermal_cfg_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_thermal_cfg_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_THERMAL_CFG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tx_stbc.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tx_stbc.c new file mode 100644 index 0000000000..f8cfa4516e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tx_stbc.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_tx_stbc.c + * + * implementation for creating sysfs file tx_stbc + */ + +#include +#include +#include "osif_vdev_sync.h" +#include "sme_api.h" +#include + +static int hdd_sysfs_get_tx_stbc(struct hdd_adapter *adapter, int *value) +{ + mac_handle_t mac_handle = adapter->hdd_ctx->mac_handle; + int ret; + + hdd_enter(); + ret = sme_get_ht_config(mac_handle, adapter->deflink->vdev_id, + WNI_CFG_HT_CAP_INFO_TX_STBC); + if (ret < 0) { + hdd_err("Failed to get TX STBC value"); + } else { + *value = ret; + ret = 0; + } + + return ret; +} + +static ssize_t +__hdd_sysfs_tx_stbc_show(struct net_device *net_dev, char *buf) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + int ret; + int value; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_get_tx_stbc(adapter, &value); + if (ret) { + hdd_err_rl("Get_TX_STBC failed %d", ret); + return ret; + } + + return scnprintf(buf, PAGE_SIZE, "%d\n", value); +} + +static ssize_t +hdd_sysfs_tx_stbc_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_tx_stbc_show(net_dev, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(tx_stbc, 0440, + hdd_sysfs_tx_stbc_show, NULL); + +int hdd_sysfs_tx_stbc_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_tx_stbc); + if (error) + hdd_err("could not create tx_stbc sysfs file"); + + return error; +} + +void hdd_sysfs_tx_stbc_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_tx_stbc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tx_stbc.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tx_stbc.h new file mode 100644 index 0000000000..3c7ccc011d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_tx_stbc.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_tx_stbc.h + * + * Implementation for creating sysfs file tx_stbc + */ + +#ifndef _WLAN_HDD_SYSFS_TX_STBC_H +#define _WLAN_HDD_SYSFS_TX_STBC_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_TX_STBC) +/** + * hdd_sysfs_tx_stbc_create() - API to create tx_stbc sysfs file + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/tx_stbc + * where wlanxx is adapter name + * + * usage: + * cat /sys/class/net/wlanxx/tx_stbc + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_tx_stbc_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_tx_stbc_destroy() - + * API to destroy tx_stbc sysfs file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_tx_stbc_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_tx_stbc_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_tx_stbc_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_TX_STBC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.c new file mode 100644 index 0000000000..83c5003e8e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_fw_st_rst.c + * + * implementation for creating sysfs file txrx_fw_st_rst + */ + +#include +#include "osif_vdev_sync.h" +#include +#include +#include "wma.h" +#include "wma_api.h" + +static int hdd_sysfs_set_vdev(struct hdd_adapter *adapter, + int id, const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, VDEV_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_sysfs_set_vdev(adapter, id, value) \ + hdd_sysfs_set_vdev(adapter, id, #id, value) + +static ssize_t +__hdd_sysfs_txrx_fw_st_rst_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("txrx_fw_st_rst: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_vdev(adapter, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, value); + + if (ret) { + hdd_err_rl("failed to set txrx fw stats reset: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_txrx_fw_st_rst_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_txrx_fw_st_rst_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(txrx_fw_st_rst, 0220, + NULL, hdd_sysfs_txrx_fw_st_rst_store); + +int hdd_sysfs_txrx_fw_st_rst_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_txrx_fw_st_rst); + if (error) + hdd_err("could not create txrx_fw_st_rst sysfs file"); + + return error; +} + +void hdd_sysfs_txrx_fw_st_rst_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_txrx_fw_st_rst); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.h new file mode 100644 index 0000000000..9d831274ef --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_fw_st_rst.h + * + * implementation for creating sysfs file txrx_fw_st_rst + */ + +#ifndef _WLAN_HDD_SYSFS_TXRX_FW_ST_RST_H +#define _WLAN_HDD_SYSFS_TXRX_FW_ST_RST_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_TXRX_FW_ST_RST) +/** + * hdd_sysfs_txrx_fw_st_rst_create() - API to create txrx_fw_st_rst + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/txrx_fw_st_rst + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > txrx_fw_st_rst + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_txrx_fw_st_rst_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_txrx_fw_st_rst_destroy() - + * API to destroy txrx_fw_st_rst + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_txrx_fw_st_rst_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_txrx_fw_st_rst_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_txrx_fw_st_rst_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_TXRX_FW_ST_RST_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.c new file mode 100644 index 0000000000..ed033994ff --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_fw_stats.c + * + * implementation for creating sysfs file txrx_fw_stats + */ + +#include +#include "osif_vdev_sync.h" +#include +#include +#include "wma.h" +#include "wma_api.h" + +static int hdd_sysfs_set_vdev(struct hdd_adapter *adapter, + int id, const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, VDEV_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_sysfs_set_vdev(adapter, id, value) \ + hdd_sysfs_set_vdev(adapter, id, #id, value) + +static ssize_t +__hdd_sysfs_txrx_fw_stats_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t value; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("txrx_fw_stats: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + ret = hdd_sysfs_set_vdev(adapter, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, value); + + if (ret) { + hdd_err_rl("failed to set txrx fw stats: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_txrx_fw_stats_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_txrx_fw_stats_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(txrx_fw_stats, 0220, + NULL, hdd_sysfs_txrx_fw_stats_store); + +int hdd_sysfs_txrx_fw_stats_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_txrx_fw_stats); + if (error) + hdd_err("could not create txrx_fw_stats sysfs file"); + + return error; +} + +void hdd_sysfs_txrx_fw_stats_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_txrx_fw_stats); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.h new file mode 100644 index 0000000000..5ea96ae7cd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_fw_stats.h + * + * implementation for creating sysfs file txrx_fw_stats + */ + +#ifndef _WLAN_HDD_SYSFS_TXRX_FW_STATS_H +#define _WLAN_HDD_SYSFS_TXRX_FW_STATS_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_TXRX_FW_STATS) +/** + * hdd_sysfs_txrx_fw_stats_create() - API to create txrx_fw_stats + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/txrx_fw_stats + * (wlanxx is adapter name) + * usage: + * echo [arg_0] > txrx_fw_stats + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_txrx_fw_stats_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_txrx_fw_stats_destroy() - + * API to destroy txrx_fw_stats + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_txrx_fw_stats_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_txrx_fw_stats_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_txrx_fw_stats_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_TXRX_FW_STATS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats.c new file mode 100644 index 0000000000..954c666a4f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_stats.c + * + * implementation for creating sysfs file txrx_stats + */ + +#include +#include +#include "osif_vdev_sync.h" +#include +#include +#include "cds_api.h" +#include "cdp_txrx_cmn_struct.h" +#include "cdp_txrx_cmn.h" + +static ssize_t +__hdd_sysfs_txrx_stats_store(struct net_device *net_dev, + char const *buf, size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_txrx_stats_req req = {0}; + struct hdd_station_ctx *sta_ctx; + struct hdd_context *hdd_ctx; + char *sptr, *token; + uint32_t val1; + uint8_t val2; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("txrx_stats: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &val2)) + return -EINVAL; + + req.stats = val1; + /* default value of secondary parameter is 0(mac_id) */ + req.mac_id = val2; + + hdd_debug("WE_SET_TXRX_STATS stats cmd: %d mac_id: %d", + req.stats, req.mac_id); + if (qdf_unlikely(!soc)) + return -EINVAL; + + if (val1 == CDP_TXRX_STATS_28) { + if (sta_ctx->conn_info.is_authenticated) { + hdd_debug("ap mac addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(&sta_ctx->conn_info.bssid.bytes[0])); + req.peer_addr = + (char *)&sta_ctx->conn_info.bssid; + } + } + ret = cdp_txrx_stats_request(soc, adapter->deflink->vdev_id, &req); + + if (ret) { + hdd_err_rl("failed to set txrx stats: %d", ret); + return ret; + } + + return count; +} + +static ssize_t +hdd_sysfs_txrx_stats_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_txrx_stats_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(txrx_stats, 0220, + NULL, hdd_sysfs_txrx_stats_store); + +int hdd_sysfs_txrx_stats_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, &dev_attr_txrx_stats); + if (error) + hdd_err("could not create txrx_stats sysfs file"); + + return error; +} + +void hdd_sysfs_txrx_stats_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_txrx_stats); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats.h new file mode 100644 index 0000000000..300b56a6cb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_stats.h + * + * implementation for creating sysfs file txrx_stats + */ + +#ifndef _WLAN_HDD_SYSFS_TXRX_STATS_H +#define _WLAN_HDD_SYSFS_TXRX_STATS_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_TXRX_STATS) +/** + * hdd_sysfs_txrx_stats_create() - API to create txrx_stats + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/txrx_stats + * (wlanxx is adapter name) + * usage: + * echo [arg_0] [arg_1] > txrx_stats + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_txrx_stats_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_txrx_stats_destroy() - API to destroy txrx_stats + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_txrx_stats_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_txrx_stats_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_txrx_stats_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_TXRX_STATS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.c new file mode 100644 index 0000000000..21d979b02d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.c @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_stats_console.c + * + * implementation for creating sysfs files: + * + * txrx_stats + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include +#include + +#ifdef WLAN_SYSFS_DP_STATS + +#define HDD_WLAN_SYSFS_TXRX_STATS_USER_CMD_SIZE (10) +#define SYSFS_INPUT_BUF_SIZE PAGE_SIZE + +/* + * __hdd_wlan_txrx_stats_store() - Calls into dp layer to + * update the sysfs config values. + * @hdd_ctx: hdd context + * @buf: input buffer from user space + * @count: input buffer size + * + * Return: Return the size of input buffer. + */ +static ssize_t +__hdd_wlan_txrx_stats_store(struct hdd_context *hdd_ctx, + const char *buf, size_t count) +{ + char buf_local[HDD_WLAN_SYSFS_TXRX_STATS_USER_CMD_SIZE + 1]; + char *sptr, *token; + uint32_t stat_type_requested; + uint32_t mac_id; + int ret; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + hdd_err_rl("soc is NULL"); + return -EINVAL; + } + + if (count > HDD_WLAN_SYSFS_TXRX_STATS_USER_CMD_SIZE) + return -EINVAL; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) + return -EINVAL; + + sptr = buf_local; + /* get mac id */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &stat_type_requested)) + return -EINVAL; + + /* get stat type requested */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &mac_id)) + return -EINVAL; + + if (!soc->ops->cmn_drv_ops->txrx_sysfs_set_stat_type) { + hdd_err("txrx_sysfs_set_stat_type is NULL"); + return -EINVAL; + } + + soc->ops->cmn_drv_ops->txrx_sysfs_set_stat_type(soc, + stat_type_requested, + mac_id); + + return count; +} + +/* + * __hdd_wlan_txrx_stats_show() - Calls into dp to fill stats. + * @buf: output buffer + * + * Return: output buffer size. + */ +static ssize_t +__hdd_wlan_txrx_stats_show(char *buf) +{ + uint32_t size_of_output = 0; + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + hdd_err_rl("hdd dp_soc cds_get_context returned NULL"); + return -EINVAL; + } + + if (!soc->ops->cmn_drv_ops->txrx_sysfs_fill_stats) { + hdd_err_rl("txrx_sysfs_fill_stats is NULL"); + return -EINVAL; + } + soc->ops->cmn_drv_ops->txrx_sysfs_fill_stats(soc, + buf, + SYSFS_INPUT_BUF_SIZE); + size_of_output = strlen(buf); + return size_of_output; +} + +/* + * hdd_sysfs_dp_txrx_stats_show() - Registered as sysfs show function. + * @kobj: kernel object + * @att: kobject attribute + * @buf: output buffer to be filled + * + * Return: Returns the length of the output buffer. + */ +static ssize_t +hdd_sysfs_dp_txrx_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync = NULL; + ssize_t length = 0; + ssize_t errno = 0; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (errno) + return errno; + + length = __hdd_wlan_txrx_stats_show(buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return length; +} + +/* + * hdd_sysfs_dp_txrx_stats_store() - Registered as sysfs write function. + * @kobj: kernel object + * @att: kobject attribute + * @buf: input buffer from user space + * @count: size of the input buffer + * + * Return: Returns the length of the input buffer. + */ +static ssize_t +hdd_sysfs_dp_txrx_stats_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + struct osif_psoc_sync *psoc_sync = NULL; + ssize_t errno = 0; + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __hdd_wlan_txrx_stats_store(hdd_ctx, buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +static struct kobj_attribute dp_txrx_stats_attribute = + __ATTR(txrx_stats, 0664, hdd_sysfs_dp_txrx_stats_show, + hdd_sysfs_dp_txrx_stats_store); + +/* + * hdd_sysfs_dp_txrx_stats_sysfs_create() - Initialize sysfs file. + * @driver_kobject: driver kobject + * + * Return: return sysfs int val. + */ +int hdd_sysfs_dp_txrx_stats_sysfs_create(struct kobject *driver_kobject) +{ + int error = 0; + + if (!driver_kobject) { + hdd_err("could not get driver kobject"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &dp_txrx_stats_attribute.attr); + + if (error) + hdd_err("failed to create txrx_stats sysfs file"); + + return error; +} + +/* + * hdd_sysfs_dp_txrx_stats_sysfs_destroy() - Sysfs deinitialize. + * @driver_kobject: driver kobject + * + * Return: void + */ +void +hdd_sysfs_dp_txrx_stats_sysfs_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("failed to get driver kobject"); + return; + } + + sysfs_remove_file(driver_kobject, &dp_txrx_stats_attribute.attr); +} +#endif /* WLAN_SYSFS_DP_STATS */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.h new file mode 100644 index 0000000000..24e0c5cc12 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_txrx_stats + * + * implementation for creating sysfs files: + * + * txrx_stats + */ + +int +hdd_sysfs_dp_txrx_stats_sysfs_create(struct kobject *drv_kobj); + +void +hdd_sysfs_dp_txrx_stats_sysfs_destroy(struct kobject *drv_kobj); + +#ifdef WLAN_SYSFS_DP_STATS + +/** + * hdd_sysfs_dp_txrx_stats_sysfs_create() - API to create txrx stats related + * sysfs entry. + * @drv_kobj: sysfs driver kobject + * + * file path: /sys/kernel/wifi/txrx_stats + * + * Return: 0 on success and errno on failure + */ + +int +hdd_sysfs_dp_txrx_stats_sysfs_create(struct kobject *drv_kobj); + +/** + * hdd_sysfs_dp_txrx_stats_sysfs_destroy() - API to destroy txrx stats + * related sysfs entry. + * @drv_kobj: sysfs driver kobject + * + * Return: None + */ + +void +hdd_sysfs_dp_txrx_stats_sysfs_destroy(struct kobject *drv_kobj); + +#else /* WLAN_SYSFS_DP_STATS */ + +int +hdd_sysfs_dp_txrx_stats_sysfs_create(struct kobject *drv_kobj) +{ + return 0; +} + +void +hdd_sysfs_dp_txrx_stats_sysfs_destroy(struct kobject *drv_kobj) +{ +} + +#endif /* WLAN_SYSFS_DP_STATS */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_unit_test.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_unit_test.c new file mode 100644 index 0000000000..02b4590bf7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_unit_test.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_unit_test.c + * + * WLAN Host Device Driver implementation to create sysfs + * unit_test_target + */ +#include "wlan_hdd_main.h" +#include "osif_psoc_sync.h" +#include "osif_vdev_sync.h" +#include "wlan_dsc_test.h" +#include "wlan_hdd_sysfs.h" +#include "wlan_hdd_sysfs_unit_test.h" +#include "wlan_module_ids.h" +#include "wma.h" + +#define MAX_USER_COMMAND_SIZE_UNIT_TEST_TARGET 256 + +static ssize_t __hdd_sysfs_unit_test_target_store( + struct net_device *net_dev, + const char __user *buf, size_t count) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_USER_COMMAND_SIZE_UNIT_TEST_TARGET + 1]; + char *sptr, *token; + uint32_t apps_args[WMI_UNIT_TEST_MAX_NUM_ARGS]; + int module_id, args_num, ret, i; + uint8_t vdev_id = 0; + QDF_STATUS status; + + if (!adapter) { + hdd_err("Adapter is null"); + return -EINVAL; + } else if (adapter->device_mode != QDF_FTM_MODE && + hdd_validate_adapter(adapter)) { + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->config->is_unit_test_framework_enabled) { + hdd_warn_rl("UT framework is disabled"); + return -EINVAL; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + hdd_nofl_info("unit_test_target: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + sptr = buf_local; + /* Get module_id */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &module_id)) + return -EINVAL; + + /* Get args_num */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &args_num)) + return -EINVAL; + + if (module_id < WLAN_MODULE_ID_MIN || + module_id >= WLAN_MODULE_ID_MAX) { + hdd_err_rl("Invalid MODULE ID %d", module_id); + return -EINVAL; + } + if (args_num > WMI_UNIT_TEST_MAX_NUM_ARGS) { + hdd_err_rl("Too many args %d", args_num); + return -EINVAL; + } + + for (i = 0; i < args_num; i++) { + token = strsep(&sptr, " "); + if (!token) { + hdd_err_rl("not enough args(%d), expected args_num:%d", + i, args_num); + return -EINVAL; + } + if (kstrtou32(token, 0, &apps_args[i])) + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + vdev_id = 0; + else + vdev_id = adapter->deflink->vdev_id; + + status = sme_send_unit_test_cmd(vdev_id, + module_id, + args_num, + &apps_args[0]); + if (status != QDF_STATUS_SUCCESS) { + hdd_err_rl("sme_send_unit_test_cmd returned %d", status); + return -EINVAL; + } + + return count; +} + +static ssize_t hdd_sysfs_unit_test_target_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_unit_test_target_store( + net_dev, buf, count); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static DEVICE_ATTR(unit_test_target, 0220, + NULL, hdd_sysfs_unit_test_target_store); + +int hdd_sysfs_unit_test_target_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_unit_test_target); + if (error) + hdd_err("could not create unit_test_target sysfs file"); + + return error; +} + +void hdd_sysfs_unit_test_target_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_unit_test_target); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_unit_test.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_unit_test.h new file mode 100644 index 0000000000..0d74a0ebe7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_unit_test.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_unit_test.h + * + * implementation for creating sysfs file unit_test_target + */ + +#ifndef _WLAN_HDD_SYSFS_UNIT_TEST_H +#define _WLAN_HDD_SYSFS_UNIT_TEST_H + +#if defined(WLAN_SYSFS) +/** + * hdd_sysfs_unit_test_target_create() - API to create unit_test_target file + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlan_xx/unit_test_target + * (wlan_xx is adapter name) + * usage: + * echo [module_id] [arg_num] [arg_0] [arg_xx] ... >unit_test_target + * echo 5 2 2 1 >unit_test_target + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_unit_test_target_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_unit_test_target_destroy() - + * API to destroy unit_test_target sys file + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_unit_test_target_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_unit_test_target_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_unit_test_target_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_UNIT_TEST_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wds_mode.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wds_mode.c new file mode 100644 index 0000000000..97ba8c2983 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wds_mode.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_psoc_sync.h" +#include +#include + +static ssize_t __hdd_sysfs_wds_mode_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char *buf) +{ + int ret = 0; + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err_rl("invalid input"); + return ret; + } + + ret = scnprintf(buf, PAGE_SIZE, "%d", + ucfg_mlme_get_wds_mode(hdd_ctx->psoc)); + + return ret; +} + +static ssize_t hdd_sysfs_wds_mode_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + if (!hdd_ctx) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_wds_mode_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static ssize_t +__hdd_sysfs_wds_mode_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, const char *buf, + size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t value; + int ret = 0; + + if (!hdd_ctx || !hdd_ctx->psoc) { + hdd_err_rl("invalid hdd ctx"); + return ret; + } + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &value)) + return -EINVAL; + + hdd_debug("wds_mode: %d", value); + + ucfg_mlme_set_wds_mode(hdd_ctx->psoc, value); + + return count; +} + +static ssize_t +hdd_sysfs_wds_mode_store(struct kobject *kobj, + struct kobj_attribute *attr, + char const *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + + if (!hdd_ctx) { + hdd_err_rl("invalid input"); + return -EINVAL; + } + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_wds_mode_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute wds_mode_attribute = + __ATTR(wds_mode, 0664, hdd_sysfs_wds_mode_show, + hdd_sysfs_wds_mode_store); + +int hdd_sysfs_wds_mode_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &wds_mode_attribute.attr); + if (error) + hdd_err("could not create wds_mode sysfs file"); + + return error; +} + +void +hdd_sysfs_wds_mode_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &wds_mode_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wds_mode.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wds_mode.h new file mode 100644 index 0000000000..3e5c6ff604 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wds_mode.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_SYSFS_WDS_MODE_H +#define _WLAN_HDD_SYSFS_WDS_MODE_H + +#if defined(WLAN_SYSFS) && defined(FEATURE_SYSFS_WDS_MODE) + +/** + * hdd_sysfs_wds_mode_create() - API to create wds mode sysfs file + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/kiwi_v2/wds_mode + * + * usage: + * echo [arg_0] > wds_mode + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_wds_mode_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_wds_mode_destroy() - destroy hdd wds mode sysfs node + * @driver_kobject: pointer to driver kobject + * + * Return: void + * + */ +void +hdd_sysfs_wds_mode_destroy(struct kobject *driver_kobject); + +#else + +static inline int +hdd_sysfs_wds_mode_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_wds_mode_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wifi_features.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wifi_features.c new file mode 100644 index 0000000000..0e885cb300 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wifi_features.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wifi_features.c + * + * Wifi Feature sysfs implementation + */ + +#include + +#include "wlan_hdd_includes.h" +#include "wlan_hdd_sysfs_wifi_features.h" +#include "wlan_hdd_sysfs.h" +#include "osif_sync.h" + +static ssize_t __hdd_sysfs_feature_set_show(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + char *buf) +{ + ssize_t ret_val = 0; + uint8_t i = 0; + char const *solution_provider = "QCT"; + + if (!hdd_ctx->oem_data_len) { + hdd_debug("Feature info is not available"); + return 0; + } + + for (i = 0; i < hdd_ctx->oem_data_len; i++) { + /* The Solution Provider Info is from index 2 to 4 */ + if (i == 2) { + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, + "%s", solution_provider); + i = i + 2; + continue; + } + ret_val += scnprintf(buf + ret_val, PAGE_SIZE - ret_val, "%.2X", + hdd_ctx->oem_data[i]); + } + + buf[ret_val] = '\n'; + + return ret_val; +} + +static ssize_t hdd_sysfs_feature_set_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_feature_set_show(hdd_ctx, attr, buf); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute feature_set_attribute = + __ATTR(feature, 0660, hdd_sysfs_feature_set_show, NULL); + +void hdd_sysfs_create_wifi_feature_interface(struct kobject *wifi_kobject) +{ + int error; + + if (!wifi_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + + error = sysfs_create_file(wifi_kobject, + &feature_set_attribute.attr); + if (error) + hdd_err("could not create dump in progress sysfs file"); +} + +void hdd_sysfs_destroy_wifi_feature_interface(struct kobject *wifi_kobject) +{ + if (!wifi_kobject) { + hdd_err("could not get wifi kobject!"); + return; + } + + sysfs_remove_file(wifi_kobject, + &feature_set_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wlan_dbg.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wlan_dbg.c new file mode 100644 index 0000000000..051be36434 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wlan_dbg.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wlan_dbg.c + * + * Implementation for creating sysfs file wlan_dbg + */ + +#include +#include "osif_psoc_sync.h" +#include +#include + +static ssize_t +__hdd_sysfs_wlan_dbg_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint32_t val1, val2, val3; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("set_wlan_dbg: count %zu buf_local:(%s)", + count, buf_local); + + /* Get val1 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val1)) + return -EINVAL; + + /* Get val2 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val2)) + return -EINVAL; + + /* Get val3 */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &val3)) + return -EINVAL; + + qdf_print_set_category_verbose(qdf_get_pidx(), val1, val2, val3); + + return count; +} + +static ssize_t +hdd_sysfs_wlan_dbg_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_wlan_dbg_store(hdd_ctx, attr, + buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute set_wlan_dbg_attribute = + __ATTR(wlan_dbg, 0220, NULL, + hdd_sysfs_wlan_dbg_store); + +int hdd_sysfs_wlan_dbg_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &set_wlan_dbg_attribute.attr); + if (error) + hdd_err("could not create wlan_dbg sysfs file"); + + return error; +} + +void +hdd_sysfs_wlan_dbg_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &set_wlan_dbg_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wlan_dbg.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wlan_dbg.h new file mode 100644 index 0000000000..2ea2b497af --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wlan_dbg.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wlan_dbg.h + * + * Implementation for creating sysfs file wlan_dbg + */ + +#ifndef _WLAN_HDD_SYSFS_WLAN_DBG_H +#define _WLAN_HDD_SYSFS_WLAN_DBG_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_SYSFS_WLAN_DBG) +/** + * hdd_sysfs_wlan_dbg_create() - API to create wlan_dbg sysfs file + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/wlan_dbg + * + * usage: + * echo [arg_0] [arg_1] [arg_2] > wlan_dbg + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_wlan_dbg_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_wlan_dbg_destroy() - API to destroy wlan_dbg sysfs file + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_wlan_dbg_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_wlan_dbg_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_wlan_dbg_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_WLAN_DBG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wow_ito.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wow_ito.c new file mode 100644 index 0000000000..2470f89e75 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wow_ito.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wow_ito.c + * + * implementation for creating sysfs wow_ito + */ + +#include +#include "osif_psoc_sync.h" +#include +#include +#include "wlan_pmo_ucfg_api.h" +#include "cfg_ucfg_api.h" + +static ssize_t +__hdd_sysfs_wow_ito_store(struct hdd_context *hdd_ctx, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1]; + char *sptr, *token; + uint8_t value; + int ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (!hdd_ctx->psoc) + return -EINVAL; + + ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local), + buf, count); + if (ret) { + hdd_err_rl("invalid input"); + return ret; + } + + sptr = buf_local; + hdd_debug("wow_ito: count %zu buf_local:(%s)", + count, buf_local); + + /* Get value */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &value)) + return -EINVAL; + + if (!cfg_in_range(CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT, value)) { + hdd_err_rl("Invalid value %d", value); + return -EINVAL; + } + + ucfg_pmo_set_wow_data_inactivity_timeout(hdd_ctx->psoc, value); + + return count; +} + +static ssize_t +hdd_sysfs_wow_ito_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + struct osif_psoc_sync *psoc_sync; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + ssize_t errno_size; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __hdd_sysfs_wow_ito_store(hdd_ctx, attr, buf, count); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno_size; +} + +static struct kobj_attribute wow_ito_attribute = + __ATTR(wow_ito, 0220, NULL, + hdd_sysfs_wow_ito_store); + +int hdd_sysfs_wow_ito_create(struct kobject *driver_kobject) +{ + int error; + + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return -EINVAL; + } + + error = sysfs_create_file(driver_kobject, + &wow_ito_attribute.attr); + if (error) + hdd_err("could not create wow_ito sysfs file"); + + return error; +} + +void +hdd_sysfs_wow_ito_destroy(struct kobject *driver_kobject) +{ + if (!driver_kobject) { + hdd_err("could not get driver kobject!"); + return; + } + sysfs_remove_file(driver_kobject, &wow_ito_attribute.attr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wow_ito.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wow_ito.h new file mode 100644 index 0000000000..9e4d0e7242 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wow_ito.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wow_ito.h + * + * implementation for creating sysfs file wow_ito + */ + +#ifndef _WLAN_HDD_SYSFS_WOW_ITO_H +#define _WLAN_HDD_SYSFS_WOW_ITO_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_WOW_ITO) +/** + * hdd_sysfs_wow_ito_create() - API to create wow_ito + * @driver_kobject: sysfs driver kobject + * + * file path: /sys/kernel/wifi/wow_ito + * + * usage: + * echo [arg_0] > wow_ito + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_wow_ito_create(struct kobject *driver_kobject); + +/** + * hdd_sysfs_wow_ito_destroy() - API to destroy wow_ito + * @driver_kobject: sysfs driver kobject + * + * Return: none + */ +void +hdd_sysfs_wow_ito_destroy(struct kobject *driver_kobject); +#else +static inline int +hdd_sysfs_wow_ito_create(struct kobject *driver_kobject) +{ + return 0; +} + +static inline void +hdd_sysfs_wow_ito_destroy(struct kobject *driver_kobject) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_WOW_ITO_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.c new file mode 100644 index 0000000000..ade988076b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wowl_add_ptrn.c + * + * implementation for creating sysfs file wowl_add_ptrn + */ + +#include +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_wowl.h" +#include + +static ssize_t +__hdd_sysfs_wowl_add_ptrn_store(struct net_device *net_dev, + char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + char *buf_local = NULL; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (count > MAX_CMD_INPUT) + return -EINVAL; + + buf_local = (char *)qdf_mem_malloc(sizeof(char) * count); + if (!buf_local) + return -EINVAL; + + strlcpy(buf_local, buf, count); + + buf_local[count - 1] = '\0'; + + hdd_debug("wowl_add_ptrn: count %zu buf_local:(%s)", + count, buf_local); + + if (!hdd_add_wowl_ptrn(adapter, buf_local)) { + hdd_err_rl("Failed to add wowl ptrn"); + qdf_mem_free(buf_local); + return -EINVAL; + } + + qdf_mem_free(buf_local); + return count; +} + +static ssize_t +hdd_sysfs_wowl_add_ptrn_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_wowl_add_ptrn_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(wowl_add_ptrn, 0220, + NULL, hdd_sysfs_wowl_add_ptrn_store); + +int hdd_sysfs_wowl_add_ptrn_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_wowl_add_ptrn); + if (error) + hdd_err("could not create wowl_add_ptrn sysfs file"); + + return error; +} + +void hdd_sysfs_wowl_add_ptrn_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_wowl_add_ptrn); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.h new file mode 100644 index 0000000000..5e35955d88 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wowl_add_ptrn.h + * + * implementation for creating sysfs file wowl_add_ptrn + */ + +#ifndef _WLAN_HDD_SYSFS_WOWL_ADD_PTRN_H +#define _WLAN_HDD_SYSFS_WOWL_ADD_PTRN_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_WOWL_ADD_PTRN) +/** + * hdd_sysfs_wowl_add_ptrn_create() - API to create wowl_add_ptrn + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/wowl_add_ptrn + * where wlanxx is adapter name + * + * usage: + * echo 08:01:FFFFFFFFFFFF0000:FC > wowl_add_ptrn + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_wowl_add_ptrn_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_wowl_add_ptrn_destroy() - + * API to destroy wowl_add_ptrn + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_wowl_add_ptrn_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_wowl_add_ptrn_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_wowl_add_ptrn_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_WOWL_ADD_PTRN_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.c new file mode 100644 index 0000000000..e81eccb11c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wowl_del_ptrn.c + * + * implementation for creating sysfs file wowl_del_ptrn + */ + +#include +#include +#include "osif_vdev_sync.h" +#include "wlan_hdd_wowl.h" +#include + +static ssize_t +__hdd_sysfs_wowl_del_ptrn_store(struct net_device *net_dev, + char const *buf, + size_t count) +{ + struct hdd_adapter *adapter = netdev_priv(net_dev); + struct hdd_context *hdd_ctx; + char *buf_local = NULL; + int ret; + + if (hdd_validate_adapter(adapter)) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (count > MAX_CMD_INPUT) + return -EINVAL; + + buf_local = (char *)qdf_mem_malloc(sizeof(char) * count); + if (!buf_local) + return -EINVAL; + + strlcpy(buf_local, buf, count); + + buf_local[count - 1] = '\0'; + + hdd_debug("wowl_del_ptrn: count %zu buf_local:(%s)", + count, buf_local); + + if (!hdd_del_wowl_ptrn(adapter, buf_local)) { + hdd_err_rl("Failed to delete wowl ptrn"); + qdf_mem_free(buf_local); + return -EINVAL; + } + + qdf_mem_free(buf_local); + return count; +} + +static ssize_t +hdd_sysfs_wowl_del_ptrn_store(struct device *dev, + struct device_attribute *attr, + char const *buf, size_t count) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_sysfs_wowl_del_ptrn_store(net_dev, buf, count); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(wowl_del_ptrn, 0220, + NULL, hdd_sysfs_wowl_del_ptrn_store); + +int hdd_sysfs_wowl_del_ptrn_create(struct hdd_adapter *adapter) +{ + int error; + + error = device_create_file(&adapter->dev->dev, + &dev_attr_wowl_del_ptrn); + if (error) + hdd_err("could not create wowl_del_ptrn sysfs file"); + + return error; +} + +void hdd_sysfs_wowl_del_ptrn_destroy(struct hdd_adapter *adapter) +{ + device_remove_file(&adapter->dev->dev, &dev_attr_wowl_del_ptrn); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.h new file mode 100644 index 0000000000..adcced9ae8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_sysfs_wowl_del_ptrn.h + * + * implementation for creating sysfs file wowl_del_ptrn + */ + +#ifndef _WLAN_HDD_SYSFS_WOWL_DEL_PTRN_H +#define _WLAN_HDD_SYSFS_WOWL_DEL_PTRN_H + +#if defined(WLAN_SYSFS) && defined(CONFIG_WLAN_WOWL_DEL_PTRN) +/** + * hdd_sysfs_wowl_del_ptrn_create() - API to create wowl_del_ptrn + * @adapter: pointer to adapter + * + * this file is created per adapter. + * file path: /sys/class/net/wlanxx/wowl_del_ptrn + * where wlanxx is adapter name + * + * usage: + * echo 08:01:FFFFFFFFFFFF0000:FC > wowl_del_ptrn + * + * Return: 0 on success and errno on failure + */ +int hdd_sysfs_wowl_del_ptrn_create(struct hdd_adapter *adapter); + +/** + * hdd_sysfs_wowl_del_ptrn_destroy() - + * API to destroy wowl_del_ptrn + * @adapter: pointer to adapter + * + * Return: none + */ +void hdd_sysfs_wowl_del_ptrn_destroy(struct hdd_adapter *adapter); +#else +static inline int +hdd_sysfs_wowl_del_ptrn_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void +hdd_sysfs_wowl_del_ptrn_destroy(struct hdd_adapter *adapter) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_SYSFS_WOWL_DEL_PTRN_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c new file mode 100644 index 0000000000..042fe43414 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tdls.c @@ -0,0 +1,1393 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_tdls.c + * + * WLAN Host Device Driver implementation for TDLS + */ + +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_tdls.h" +#include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_assoc.h" +#include "sme_api.h" +#include "cds_sched.h" +#include "wma_types.h" +#include "wlan_policy_mgr_api.h" +#include +#include "wlan_tdls_cfg_api.h" +#include "wlan_hdd_object_manager.h" +#include +#include "wlan_tdls_api.h" + +/** + * enum qca_wlan_vendor_tdls_trigger_mode_hdd_map: Maps the user space TDLS + * trigger mode in the host driver. + * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and + * disconnection handled by user space. + * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and + * disconnection controlled by host driver based on data traffic. + * @WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and + * disconnection jointly controlled by user space and host driver. + */ +enum qca_wlan_vendor_tdls_trigger_mode_hdd_map { + WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT, + WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT, + WLAN_HDD_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = + ((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT | + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1), +}; + +/** + * wlan_hdd_tdls_get_all_peers() - dump all TDLS peer info into output string + * @adapter: HDD adapter + * @buf: output string buffer to hold the peer info + * @buflen: the size of output string buffer + * + * Return: The size (in bytes) of the valid peer info in the output buffer + */ +int wlan_hdd_tdls_get_all_peers(struct hdd_adapter *adapter, + char *buf, int buflen) +{ + int len; + struct hdd_context *hdd_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *link_vdev; + int ret; + + hdd_enter(); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (0 != (wlan_hdd_validate_context(hdd_ctx))) { + len = scnprintf(buf, buflen, + "\nHDD context is not valid\n"); + return len; + } + + if ((QDF_STA_MODE != adapter->device_mode) && + (QDF_P2P_CLIENT_MODE != adapter->device_mode)) { + len = scnprintf(buf, buflen, + "\nNo TDLS support for this adapter\n"); + return len; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (!vdev) { + len = scnprintf(buf, buflen, "\nVDEV is NULL\n"); + return len; + } + + link_vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (link_vdev) { + ret = wlan_cfg80211_tdls_get_all_peers(link_vdev, buf, buflen); + ucfg_tdls_put_tdls_link_vdev(link_vdev, WLAN_OSIF_TDLS_ID); + } else { + ret = wlan_cfg80211_tdls_get_all_peers(vdev, buf, buflen); + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + + return ret; +} + +static const struct nla_policy + wlan_hdd_tdls_config_enable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_GLOBAL_OPERATING_CLASS] = {.type = + NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MAX_LATENCY_MS] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_ENABLE_MIN_BANDWIDTH_KBPS] = {.type = + NLA_U32}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_disable_policy[QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_DISABLE_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, +}; +static const struct nla_policy + wlan_hdd_tdls_config_state_change_policy[QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAX + + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_NEW_STATE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_REASON] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_STATE_GLOBAL_OPERATING_CLASS] = {.type = + NLA_U32}, +}; +static const struct nla_policy + wlan_hdd_tdls_config_get_status_policy +[QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_STATE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_REASON] = {.type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_CHANNEL] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_GLOBAL_OPERATING_CLASS] = { + .type = NLA_U32}, +}; + +const struct nla_policy + wlan_hdd_tdls_disc_rsp_policy + [QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK] = { + .type = NLA_U8}, +}; + +const struct nla_policy + wlan_hdd_tdls_mode_configuration_policy + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_STATS_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TX_THRESHOLD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_DISCOVERY_PERIOD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX_DISCOVERY_ATTEMPT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_TIMEOUT] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_IDLE_PACKET_THRESHOLD] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_SETUP_RSSI_THRESHOLD] = { + .type = NLA_S32}, + [QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TEARDOWN_RSSI_THRESHOLD] = { + .type = NLA_S32}, +}; + +static bool wlan_hdd_is_tdls_allowed(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev) +{ + bool tdls_support; + struct wlan_hdd_link_info *link_info; + + if ((cfg_tdls_get_support_enable(hdd_ctx->psoc, &tdls_support) == + QDF_STATUS_SUCCESS) && !tdls_support) { + hdd_debug("TDLS feature not Enabled or Not supported in FW"); + return false; + } + + if (!wlan_cm_is_vdev_connected(vdev)) { + hdd_debug("Failed due to Not associated"); + return false; + } + + if (wlan_cm_roaming_in_progress(hdd_ctx->pdev, + wlan_vdev_get_id(vdev))) { + hdd_debug("Failed due to Roaming is in progress"); + return false; + } + + if (!ucfg_tdls_check_is_tdls_allowed(vdev)) { + hdd_debug("TDLS is not allowed"); + return false; + } + + if (ucfg_mlme_get_tdls_prohibited(vdev)) { + hdd_debug("TDLS is prohobited by AP"); + return false; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, wlan_vdev_get_id(vdev)); + if (wlan_hdd_is_link_switch_in_progress(link_info)) { + hdd_debug("vdev:%d Link switch in progress", + wlan_vdev_get_id(vdev)); + return false; + } + + return true; +} + +static bool wlan_hdd_get_tdls_allowed(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + struct wlan_objmgr_vdev *vdev; + bool is_tdls_avail = false; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_TDLS_NB_ID); + if (!vdev) + return false; + + is_tdls_avail = wlan_hdd_is_tdls_allowed(hdd_ctx, vdev); + + /* Return is_tdls_avail for non-MLO case */ + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TDLS_NB_ID); + return is_tdls_avail; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TDLS_NB_ID); + + if (is_tdls_avail) + return is_tdls_avail; + } + + return false; +} + +/** + * __wlan_hdd_cfg80211_exttdls_get_status() - handle get status cfg80211 command + * @wiphy: wiphy + * @wdev: wireless dev + * @data: netlink buffer with the mac address of the peer to get the status for + * @data_len: length of data in bytes + */ +static int +__wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sk_buff *skb; + uint32_t connected_peer_count = 0; + int status; + bool is_tdls_avail = true; + int ret = 0; + int attr; + + hdd_enter_dev(wdev->netdev); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return -EINVAL; + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + sizeof(u32) + sizeof(bool) + + NLMSG_HDRLEN); + + if (!skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_debug("Failed to get TDLS info due to opmode:%d", + adapter->device_mode); + ret = -EOPNOTSUPP; + goto fail; + } + + connected_peer_count = cfg_tdls_get_connected_peer_count(hdd_ctx->psoc); + is_tdls_avail = wlan_hdd_get_tdls_allowed(hdd_ctx, adapter); + + if (connected_peer_count >= + cfg_tdls_get_max_peer_count(hdd_ctx->psoc)) { + hdd_debug("Failed due to max no. of connected peer:%d reached", + connected_peer_count); + is_tdls_avail = false; + } + + hdd_debug("Send TDLS_available: %d, no. of connected peer:%d to userspace", + is_tdls_avail, connected_peer_count); + + attr = QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_NUM_SESSIONS; + if (nla_put_u32(skb, attr, connected_peer_count)) { + hdd_err("nla put fail"); + ret = -EINVAL; + goto fail; + } + + attr = QCA_WLAN_VENDOR_ATTR_TDLS_GET_STATUS_AVAILABLE; + if (is_tdls_avail && nla_put_flag(skb, attr)) { + hdd_err("nla put fail"); + ret = -EINVAL; + goto fail; + } + + return wlan_cfg80211_vendor_cmd_reply(skb); +fail: + wlan_cfg80211_vendor_free_skb(skb); + return ret; +} + +static int +__wlan_hdd_cfg80211_exttdls_set_link_id(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX + 1]; + int ret; + uint32_t link_id; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (!adapter) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_MAX, + data, data_len, + wlan_hdd_tdls_disc_rsp_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK]) { + hdd_err("attr tdls link id failed"); + return -EINVAL; + } + + link_id = + nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_TDLS_DISC_RSP_EXT_TX_LINK]); + hdd_debug("TDLS link id %d", link_id); + + ret = cfg_tdls_set_link_id(hdd_ctx->psoc, link_id); + + return ret; +} + +/** + * __wlan_hdd_cfg80211_configure_tdls_mode() - configure the tdls mode + * @wiphy: wiphy + * @wdev: wireless dev + * @data: netlink buffer + * @data_len: length of data in bytes + * + * Return 0 for success and error code for failure + */ +static int +__wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX + 1]; + int ret; + uint32_t trigger_mode; + struct wlan_objmgr_vdev *vdev; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return -EINVAL; + + if (!adapter) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_MAX, + data, data_len, + wlan_hdd_tdls_mode_configuration_policy)) { + hdd_err("Invalid attribute"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE]) { + hdd_err("attr tdls trigger mode failed"); + return -EINVAL; + } + trigger_mode = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_TDLS_CONFIG_TRIGGER_MODE]); + hdd_debug("TDLS trigger mode %d", trigger_mode); + + if (!hdd_ctx->tdls_umac_comp_active) + return -EINVAL; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + + ret = wlan_cfg80211_tdls_configure_mode(vdev, trigger_mode); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + return ret; +} + +/** + * wlan_hdd_cfg80211_configure_tdls_mode() - configure tdls mode + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_configure_tdls_mode(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_configure_tdls_mode(wiphy, wdev, data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_cfg80211_exttdls_get_status() - get ext tdls status + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_get_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_exttdls_get_status(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int wlan_hdd_cfg80211_exttdls_set_link_id(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_exttdls_set_link_id(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int wlan_hdd_tdls_enable(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + struct wlan_objmgr_vdev *vdev; + bool tdls_chan_switch_prohibited; + bool tdls_prohibited; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_TDLS_NB_ID); + if (!vdev) + return -EINVAL; + + tdls_chan_switch_prohibited = + ucfg_mlme_get_tdls_chan_switch_prohibited(vdev); + tdls_prohibited = ucfg_mlme_get_tdls_prohibited(vdev); + + ucfg_tdls_set_user_tdls_enable(vdev, true); + + wlan_tdls_notify_sta_connect(wlan_vdev_get_id(vdev), + tdls_chan_switch_prohibited, + tdls_prohibited, vdev); + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TDLS_NB_ID); + return 0; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TDLS_NB_ID); + } + + return 0; +} + +/** + * __wlan_hdd_cfg80211_exttdls_enable() - enable an externally controllable + * TDLS peer and set parameters + * @wiphy: pointer to wireless wiphy structure. + * @wdev: wireless dev pointer + * @data: netlink buffer with peer MAC address and configuration parameters + * @data_len: size of data in bytes + * + * This function sets channel, operation class, maximum latency and minimal + * bandwidth parameters on a TDLS peer that's externally controllable. + * + * Return: 0 for success; negative errno otherwise + */ +static int +__wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + + hdd_enter_dev(wdev->netdev); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_debug("Failed to get TDLS info due to opmode:%d", + adapter->device_mode); + return -EOPNOTSUPP; + } + + ret = wlan_hdd_tdls_enable(hdd_ctx, adapter); + + return ret; +} + +/** + * wlan_hdd_cfg80211_exttdls_enable() - enable ext tdls + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_enable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_exttdls_enable(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int wlan_hdd_tdls_disable(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct wlan_hdd_link_info *link_info; + struct wlan_objmgr_vdev *vdev; + bool tdls_chan_switch_prohibited; + + hdd_adapter_for_each_active_link_info(adapter, link_info) { + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_TDLS_NB_ID); + if (!vdev) + return -EINVAL; + + tdls_chan_switch_prohibited = + ucfg_mlme_get_tdls_chan_switch_prohibited(vdev); + + wlan_tdls_notify_sta_disconnect(wlan_vdev_get_id(vdev), + tdls_chan_switch_prohibited, + true, vdev); + + ucfg_tdls_set_user_tdls_enable(vdev, false); + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TDLS_NB_ID); + return 0; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TDLS_NB_ID); + } + + return 0; +} + +/** + * __wlan_hdd_cfg80211_exttdls_disable() - disable an externally controllable + * TDLS peer + * @wiphy: wiphy + * @wdev: wireless dev pointer + * @data: netlink buffer with peer MAC address + * @data_len: size of data in bytes + * + * This function disables an externally controllable TDLS peer + * + * Return: 0 for success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int ret = 0; + + hdd_enter_dev(wdev->netdev); + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + hdd_debug("Failed to get TDLS info due to opmode:%d", + adapter->device_mode); + return -EOPNOTSUPP; + } + + ret = wlan_hdd_tdls_disable(hdd_ctx, adapter); + + return ret; +} + +/** + * wlan_hdd_cfg80211_exttdls_disable() - disable ext tdls + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: Pointer to the data to be passed via vendor interface + * @data_len:Length of the data to be passed + * + * Return: Return the Success or Failure code. + */ +int wlan_hdd_cfg80211_exttdls_disable(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_exttdls_disable(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef TDLS_MGMT_VERSION5 +static int wlan_hdd_get_tdls_link_id(struct hdd_context *hdd_ctx, int id) +{ + return id; +} +#else +static int wlan_hdd_get_tdls_link_id(struct hdd_context *hdd_ctx, int id) +{ + int link_id; + + link_id = cfg_tdls_get_link_id(hdd_ctx->psoc); + + return link_id; +} +#endif + +#ifdef TDLS_MGMT_VERSION5 +/** + * __wlan_hdd_cfg80211_tdls_mgmt() - handle management actions on a given peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @peer_capability: peer capability + * @initiator: tdls initiator flag + * @buf: additional IE to include + * @len: length of buf in bytes + * @link_id: link id for mld device + * + * Return: 0 if success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len, int link_id) + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + bool initiator, const u8 *buf, + size_t len) + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + bool initiator, const uint8_t *buf, + size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || defined(TDLS_MGMT_VERSION2) +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len) +#else +static int __wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, const uint8_t *buf, + size_t len) +#endif +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + bool tdls_support; +#if !defined(TDLS_MGMT_VERSION5) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(6, 5, 0)) + int link_id = -1; +#endif +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 15, 0)) +#if !(TDLS_MGMT_VERSION2) + u32 peer_capability; + + peer_capability = 0; +#endif +#endif + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_MGMT, + adapter->deflink->vdev_id, action_code); + + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + cfg_tdls_get_support_enable(hdd_ctx->psoc, &tdls_support); + if (!tdls_support) { + hdd_debug("TDLS Disabled in INI OR not enabled in FW. " + "Cannot process TDLS commands"); + return -ENOTSUPP; + } + + if (hdd_ctx->tdls_umac_comp_active) { + int ret; + + link_id = wlan_hdd_get_tdls_link_id(hdd_ctx, link_id); + ret = wlan_cfg80211_tdls_mgmt_mlo(adapter, peer, + action_code, dialog_token, + status_code, peer_capability, + buf, len, link_id); + return ret; + } + + return -EINVAL; +} + +#ifdef TDLS_MGMT_VERSION5 +/** + * wlan_hdd_cfg80211_tdls_mgmt() - cfg80211 tdls mgmt handler function + * @wiphy: Pointer to wiphy structure. + * @dev: Pointer to net_device structure. + * @peer: peer address + * @action_code: action code + * @dialog_token: dialog token + * @status_code: status code + * @peer_capability: peer capability + * @initiator: tdls initiator flag + * @buf: buffer + * @len: Length of @buf + * @link_id: link id for mld device + * + * This is the cfg80211 tdls mgmt handler function which invokes + * the internal function @__wlan_hdd_cfg80211_tdls_mgmt with + * SSR protection. + * + * Return: 0 for success, error number on failure. + */ +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len, int link_id) + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, int link_id, + u8 action_code, u8 dialog_token, + u16 status_code, u32 peer_capability, + bool initiator, const u8 *buf, + size_t len) + +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, bool initiator, + const u8 *buf, size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + const u8 *peer, u8 action_code, + u8 dialog_token, u16 status_code, + u32 peer_capability, const u8 *buf, + size_t len) +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || defined(TDLS_MGMT_VERSION2) +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, u32 peer_capability, + const u8 *buf, size_t len) +#else +int wlan_hdd_cfg80211_tdls_mgmt(struct wiphy *wiphy, + struct net_device *dev, + u8 *peer, u8 action_code, + u8 dialog_token, + u16 status_code, const u8 *buf, + size_t len) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + +#ifdef TDLS_MGMT_VERSION5 + errno = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, initiator, + buf, len, link_id); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 5, 0)) + errno = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, link_id, + action_code, dialog_token, + status_code, peer_capability, + initiator, buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)) || defined(WITH_BACKPORTS) + errno = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, initiator, + buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) + errno = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)) || defined(TDLS_MGMT_VERSION2) + errno = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + peer_capability, buf, len); +#else + errno = __wlan_hdd_cfg80211_tdls_mgmt(wiphy, dev, peer, action_code, + dialog_token, status_code, + buf, len); +#endif + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static bool +hdd_is_sta_legacy(struct wlan_hdd_link_info *link_info) +{ + struct hdd_station_ctx *sta_ctx; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!sta_ctx) + return false; + + if ((sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || + (sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_11N) || + (sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_11AC) || + (sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_11N_ONLY) || + (sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) || + (sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_11AX) || + (sta_ctx->conn_info.dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY)) + return false; + + return true; +} + +uint16_t +hdd_get_tdls_connected_peer_count(struct wlan_hdd_link_info *link_info) +{ + struct wlan_objmgr_vdev *vdev; + uint16_t peer_count; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_TDLS_ID); + if (!vdev) { + hdd_err("Invalid vdev"); + return -EINVAL; + } + + peer_count = ucfg_get_tdls_conn_peer_count(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_TDLS_ID); + + return peer_count; +} + +void +hdd_check_and_set_tdls_conn_params(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + enum hdd_dot11_mode selfdot11mode; + struct wlan_hdd_link_info *link_info; + struct wlan_objmgr_psoc *psoc; + struct hdd_context *hdd_ctx; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + /* + * Only need to set this if STA link is in legacy mode + */ + vdev_id = wlan_vdev_get_id(vdev); + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info || !hdd_is_sta_legacy(link_info)) + return; + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + if (!hdd_ctx) + return; + + selfdot11mode = hdd_ctx->config->dot11Mode; + /* + * When STA connection is made in legacy mode (11a, 11b and 11g) and + * selfdot11Mode is either 11ax, 11ac or 11n, TDLS connection can be + * made upto supporting selfdot11mode. Since, TDLS shares same netdev + * that of STA, checksum/TSO will be disabled during STA connection. + * For better TDLS throughput, enable checksum/TSO which were already + * disabled during STA connection. + */ + if (selfdot11mode == eHDD_DOT11_MODE_AUTO || + selfdot11mode == eHDD_DOT11_MODE_11ax || + selfdot11mode == eHDD_DOT11_MODE_11ax_ONLY || + selfdot11mode == eHDD_DOT11_MODE_11ac_ONLY || + selfdot11mode == eHDD_DOT11_MODE_11ac || + selfdot11mode == eHDD_DOT11_MODE_11n || + selfdot11mode == eHDD_DOT11_MODE_11n_ONLY) + hdd_cm_netif_queue_enable(link_info->adapter); +} + +void +hdd_check_and_set_tdls_disconn_params(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + struct wlan_hdd_link_info *link_info; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + /* + * Only need to set this if STA link is in legacy mode + */ + vdev_id = wlan_vdev_get_id(vdev); + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info || !hdd_is_sta_legacy(link_info)) + return; + + hdd_cm_netif_queue_enable(link_info->adapter); +} + +/** + * __wlan_hdd_cfg80211_tdls_oper() - helper function to handle cfg80211 operation + * on an TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +static int __wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + int status; + bool tdls_support; + struct wlan_objmgr_vdev *vdev; + + hdd_enter(); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EINVAL; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + cfg_tdls_get_support_enable(hdd_ctx->psoc, &tdls_support); + if (!tdls_support) { + hdd_debug("TDLS Disabled in INI OR not enabled in FW. " + "Cannot process TDLS commands"); + return -ENOTSUPP; + } + + qdf_mtrace(QDF_MODULE_ID_HDD, QDF_MODULE_ID_HDD, + TRACE_CODE_HDD_CFG80211_TDLS_OPER, + adapter->deflink->vdev_id, oper); + + if (!peer) { + hdd_err("Invalid arguments"); + return -EINVAL; + } + + status = wlan_hdd_validate_context(hdd_ctx); + + if (0 != status) + return status; + + if (!hdd_ctx->tdls_umac_comp_active) { + status = -EINVAL; + goto exit; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + status = wlan_cfg80211_tdls_oper(vdev, peer, oper); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + +exit: + hdd_exit(); + return status; +} + +/** + * wlan_hdd_cfg80211_tdls_oper() - handle cfg80211 operation on an TDLS peer + * @wiphy: wiphy + * @dev: net device + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)) +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +#else +int wlan_hdd_cfg80211_tdls_oper(struct wiphy *wiphy, + struct net_device *dev, + uint8_t *peer, + enum nl80211_tdls_operation oper) +#endif +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_tdls_oper(wiphy, dev, peer, oper); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int hdd_set_tdls_offchannel(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + int offchannel) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!hdd_ctx->tdls_umac_comp_active) + return qdf_status_to_os_return(status); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (vdev) { + status = ucfg_set_tdls_offchannel(vdev, offchannel); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + } + return qdf_status_to_os_return(status); +} + +int hdd_set_tdls_secoffchanneloffset(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + int offchanoffset) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!hdd_ctx->tdls_umac_comp_active) + return qdf_status_to_os_return(status); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (vdev) { + status = ucfg_set_tdls_secoffchanneloffset(vdev, offchanoffset); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + } + return qdf_status_to_os_return(status); +} + +int hdd_set_tdls_offchannelmode(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + int offchanmode) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool tdls_off_ch; + + if (cfg_tdls_get_off_channel_enable( + hdd_ctx->psoc, &tdls_off_ch) != + QDF_STATUS_SUCCESS) { + hdd_err("cfg get tdls off ch failed"); + return qdf_status_to_os_return(status); + } + if (!tdls_off_ch) { + hdd_debug("tdls off ch is false, do nothing"); + return qdf_status_to_os_return(status); + } + + if (!hdd_ctx->tdls_umac_comp_active) + return qdf_status_to_os_return(status); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (vdev) { + status = ucfg_set_tdls_offchan_mode(vdev, offchanmode); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + } + return qdf_status_to_os_return(status); +} + +/** + * hdd_set_tdls_scan_type - set scan during active tdls session + * @hdd_ctx: ptr to hdd context. + * @val: scan type value: 0 or 1. + * + * Set scan type during tdls session. If set to 1, that means driver + * shall maintain tdls link and allow scan regardless if tdls peer is + * buffer sta capable or not and/or if device is sleep sta capable or + * not. If tdls peer is not buffer sta capable then during scan there + * will be loss of Rx packets and Tx would stop when device moves away + * from tdls channel. If set to 0, then driver shall teardown tdls link + * before initiating scan if peer is not buffer sta capable and device + * is not sleep sta capable. By default, scan type is set to 0. + * + * Return: success (0) or failure (errno value) + */ +int hdd_set_tdls_scan_type(struct hdd_context *hdd_ctx, int val) +{ + if ((val != 0) && (val != 1)) { + hdd_err("Incorrect value of tdls scan type: %d", val); + return -EINVAL; + } + + cfg_tdls_set_scan_enable(hdd_ctx->psoc, (bool)val); + + return 0; +} + +int wlan_hdd_tdls_antenna_switch(struct wlan_hdd_link_info *link_info, + uint32_t mode) +{ + int ret; + struct wlan_objmgr_vdev *vdev; + + if (!link_info->adapter->hdd_ctx->tdls_umac_comp_active) + return 0; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + + ret = wlan_tdls_antenna_switch(vdev, mode); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + return ret; +} + +QDF_STATUS hdd_tdls_register_peer(void *userdata, uint32_t vdev_id, + const uint8_t *mac, uint8_t qos) +{ + struct hdd_context *hddctx; + struct wlan_hdd_link_info *link_info; + + hddctx = userdata; + if (!hddctx) { + hdd_err("Invalid hddctx"); + return QDF_STATUS_E_INVAL; + } + + link_info = hdd_get_link_info_by_vdev(hddctx, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return QDF_STATUS_E_FAILURE; + } + + return hdd_roam_register_tdlssta(link_info->adapter, mac, qos); +} + +void hdd_init_tdls_config(struct tdls_start_params *tdls_cfg) +{ + tdls_cfg->tdls_send_mgmt_req = eWNI_SME_TDLS_SEND_MGMT_REQ; + tdls_cfg->tdls_add_sta_req = eWNI_SME_TDLS_ADD_STA_REQ; + tdls_cfg->tdls_del_sta_req = eWNI_SME_TDLS_DEL_STA_REQ; + tdls_cfg->tdls_update_peer_state = WMA_UPDATE_TDLS_PEER_STATE; +} + +void hdd_config_tdls_with_band_switch(struct hdd_context *hdd_ctx) +{ + struct wlan_objmgr_vdev *tdls_obj_vdev; + int offchmode; + uint32_t current_band; + bool tdls_off_ch; + + if (!hdd_ctx) { + hdd_err("Invalid hdd_ctx"); + return; + } + + if (ucfg_reg_get_band(hdd_ctx->pdev, ¤t_band) != + QDF_STATUS_SUCCESS) { + hdd_err("Failed to get current band config"); + return; + } + + /** + * If all bands are supported, in below condition off channel enable + * orig is false and nothing is need to do + * 1. band switch does not happen. + * 2. band switch happens and it already restores + * 3. tdls off channel is disabled by default. + * If 2g or 5g is not supported. Disable tdls off channel only when + * tdls off channel is enabled currently. + */ + if ((current_band & BIT(REG_BAND_2G)) && + (current_band & BIT(REG_BAND_5G))) { + if (cfg_tdls_get_off_channel_enable_orig( + hdd_ctx->psoc, &tdls_off_ch) != + QDF_STATUS_SUCCESS) { + hdd_err("cfg get tdls off ch orig failed"); + return; + } + if (!tdls_off_ch) { + hdd_debug("tdls off ch orig is false, do nothing"); + return; + } + offchmode = ENABLE_CHANSWITCH; + cfg_tdls_restore_off_channel_enable(hdd_ctx->psoc); + } else { + if (cfg_tdls_get_off_channel_enable( + hdd_ctx->psoc, &tdls_off_ch) != + QDF_STATUS_SUCCESS) { + hdd_err("cfg get tdls off ch failed"); + return; + } + if (!tdls_off_ch) { + hdd_debug("tdls off ch is false, do nothing"); + return; + } + offchmode = DISABLE_CHANSWITCH; + cfg_tdls_store_off_channel_enable(hdd_ctx->psoc); + cfg_tdls_set_off_channel_enable(hdd_ctx->psoc, false); + } + tdls_obj_vdev = ucfg_get_tdls_vdev(hdd_ctx->psoc, WLAN_TDLS_NB_ID); + if (tdls_obj_vdev) { + ucfg_set_tdls_offchan_mode(tdls_obj_vdev, offchmode); + wlan_objmgr_vdev_release_ref(tdls_obj_vdev, WLAN_TDLS_NB_ID); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.c new file mode 100644 index 0000000000..530a729490 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.c @@ -0,0 +1,789 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_thermal.c + * + * WLAN Host Device Driver implementation for thermal mitigation handling + */ + +#include +#include +#include "wlan_osif_priv.h" +#include "qdf_trace.h" +#include "wlan_hdd_main.h" +#include "osif_sync.h" +#include +#include +#include "sme_api.h" +#include "wlan_hdd_thermal.h" +#include "wlan_hdd_cfg80211.h" +#include +#include "wlan_fwol_ucfg_api.h" +#include +#include "wlan_hdd_stats.h" +#include "os_if_fwol.h" +#include "wlan_osif_request_manager.h" +#include "wlan_fwol_public_structs.h" + +#define DC_OFF_PERCENT_WPPS 50 +#define WLAN_WAIT_TIME_GET_THERM_LVL 1000 + +const struct nla_policy + wlan_hdd_thermal_mitigation_policy + [QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_THERMAL_STATS] = {.type = NLA_NESTED}, +}; + +#ifdef FEATURE_WPSS_THERMAL_MITIGATION +void +hdd_thermal_fill_clientid_priority(struct hdd_context *hdd_ctx, uint8_t mon_id, + uint8_t priority_apps, uint8_t priority_wpps, + struct thermal_mitigation_params *params) +{ + if (hdd_ctx->multi_client_thermal_mitigation) { + if (mon_id == THERMAL_MONITOR_APPS) { + params->priority = priority_apps; + params->client_id = mon_id; + hdd_debug("Thermal client:%d priority_apps: %d", mon_id, + priority_apps); + } else if (mon_id == THERMAL_MONITOR_WPSS) { + params->priority = priority_wpps; + params->client_id = mon_id; + /* currently hardcoded, + * can be changed based on requirement. + */ + params->levelconf[0].dcoffpercent = DC_OFF_PERCENT_WPPS; + hdd_debug("Thermal client:%d priority_wpps: %d", mon_id, + priority_wpps); + } + } +} +#endif + +QDF_STATUS +hdd_send_thermal_mitigation_val(struct hdd_context *hdd_ctx, uint32_t level, + uint8_t mon_id) +{ + uint32_t dc, dc_off_percent; + uint32_t prio = 0, target_temp = 0; + struct wlan_fwol_thermal_temp thermal_temp = {0}; + QDF_STATUS status; + bool enable = true; + struct thermal_mitigation_params therm_cfg_params = {0}; + + status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, &thermal_temp); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to get fwol thermal obj"); + return status; + } + + switch (level) { + case QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY: + dc_off_percent = thermal_temp.throttle_dutycycle_level[5]; + break; + case QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL: + dc_off_percent = thermal_temp.throttle_dutycycle_level[4]; + break; + case QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE: + dc_off_percent = thermal_temp.throttle_dutycycle_level[3]; + break; + case QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE: + dc_off_percent = thermal_temp.throttle_dutycycle_level[2]; + break; + case QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT: + dc_off_percent = thermal_temp.throttle_dutycycle_level[1]; + break; + case QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE: + enable = false; + dc_off_percent = thermal_temp.throttle_dutycycle_level[0]; + break; + default: + hdd_debug("Invalid thermal state"); + return QDF_STATUS_E_INVAL; + } + + dc = thermal_temp.thermal_sampling_time; + therm_cfg_params.enable = enable; + therm_cfg_params.dc = dc; + therm_cfg_params.levelconf[0].dcoffpercent = dc_off_percent; + therm_cfg_params.levelconf[0].priority = prio; + therm_cfg_params.levelconf[0].tmplwm = target_temp; + therm_cfg_params.num_thermal_conf = 1; + therm_cfg_params.pdev_id = 0; + + hdd_thermal_fill_clientid_priority(hdd_ctx, mon_id, + thermal_temp.priority_apps, + thermal_temp.priority_wpps, + &therm_cfg_params); + + hdd_debug("dc %d dc_off_per %d", dc, dc_off_percent); + + status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle, + &therm_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("Failed to set throttle configuration %d", status); + + else + /* + * After SSR, the thermal mitigation level is lost. + * As SSR is hidden from userland, this command will not come + * from userspace after a SSR. To restore this configuration, + * save this in hdd context and restore after re-init. + */ + hdd_ctx->dutycycle_off_percent = dc_off_percent; + + return QDF_STATUS_SUCCESS; +} + +/** + * convert_level_to_vendor_thermal_level() - convert internal thermal level + * to vendor command attribute enum qca_wlan_vendor_thermal_level + * @level: driver internal thermal level + * + * Return: vendor thermal level + */ +static enum qca_wlan_vendor_thermal_level +convert_level_to_vendor_thermal_level(enum thermal_throttle_level level) +{ + if (level == THERMAL_FULLPERF) + return QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE; + else if (level == THERMAL_MITIGATION) + return QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE; + else if (level == THERMAL_SHUTOFF) + return QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL; + else + return QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY; +} + +/** + * hdd_get_curr_thermal_throttle_level_val() - Indicate current target + * thermal throttle level to upper layer upon query level + * @hdd_ctx: hdd context + * + * Return: 0 for success + */ +static int +hdd_get_curr_thermal_throttle_level_val(struct hdd_context *hdd_ctx) +{ + struct sk_buff *reply_skb; + uint32_t data_len; + enum thermal_throttle_level level = THERMAL_FULLPERF; + enum qca_wlan_vendor_thermal_level vendor_level; + QDF_STATUS status; + + status = ucfg_fwol_thermal_get_target_level(hdd_ctx->psoc, &level); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("get_thermal level: fail get target level"); + return -EINVAL; + } + vendor_level = convert_level_to_vendor_thermal_level(level); + data_len = NLMSG_HDRLEN + nla_total_size(sizeof(uint32_t)); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + data_len); + if (!reply_skb) { + hdd_err("get_thermal level: buffer alloc fail"); + return -ENOMEM; + } + if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL, + vendor_level)) { + hdd_err("get_thermal level: nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + hdd_debug("get_thermal level: %d vendor level %d", level, + vendor_level); + + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +/** + * hdd_get_curr_thermal_temperature_val() - Indicate current target + * thermal temperature to upper layer when handing temperature + * query vendor command + * @hdd_ctx: hdd context + * @adapter: adapter context + * + * Return: 0 for success + */ +static int +hdd_get_curr_thermal_temperature_val(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter) +{ + struct sk_buff *reply_skb; + int ret; + uint32_t data_len; + int temperature = 0; + + ret = wlan_hdd_get_temperature(adapter, &temperature); + if (ret) + return ret; + data_len = NLMSG_HDRLEN + nla_total_size(sizeof(uint32_t)); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + data_len); + if (!reply_skb) { + hdd_err("get_thermal temperature: buffer alloc fail"); + return -ENOMEM; + } + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_DATA, + temperature)) { + hdd_err("get_thermal temperature: nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return -EINVAL; + } + hdd_debug("get_thermal temperature: %d", temperature); + + return wlan_cfg80211_vendor_cmd_reply(reply_skb); +} + +#ifdef THERMAL_STATS_SUPPORT +QDF_STATUS +hdd_send_get_thermal_stats_cmd(struct hdd_context *hdd_ctx, + enum thermal_stats_request_type request_type, + void (*callback)(void *context, + struct thermal_throttle_info *response), + void *context) +{ + int ret; + + if (!hdd_ctx->psoc) { + hdd_err_rl("NULL pointer for psoc"); + return QDF_STATUS_E_INVAL; + } + + + /* Send Get Thermal Stats cmd to FW */ + ret = os_if_fwol_get_thermal_stats_req(hdd_ctx->psoc, request_type, + callback, context); + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_get_thermal_stats_cb() - Get thermal stats callback + * @context: Call context + * @response: Pointer to response structure + * + * Return: void + */ +static void +hdd_get_thermal_stats_cb(void *context, + struct thermal_throttle_info *response) +{ + struct osif_request *request; + struct thermal_throttle_info *priv; + + request = osif_request_get(context); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + qdf_mem_copy(priv, response, sizeof(struct thermal_throttle_info)); + + osif_request_complete(request); + osif_request_put(request); +} + +#define THERMAL_MIN_TEMP QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MIN_TEMPERATURE +#define THERMAL_MAX_TEMP QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MAX_TEMPERATURE +#define THERMAL_DWELL_TIME QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_DWELL_TIME +#define THERMAL_LVL_COUNT QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_TEMP_LEVEL_COUNTER + +/** + * hdd_get_curr_thermal_stats_val() - Indicate thermal stats + * to upper layer when query vendor command + * @wiphy: Pointer to wireless phy + * @hdd_ctx: hdd context + * + * Return: 0 for success + */ +static int +hdd_get_curr_thermal_stats_val(struct wiphy *wiphy, + struct hdd_context *hdd_ctx) +{ + int ret = 0; + uint8_t i = 0; + struct osif_request *request = NULL; + int skb_len = 0; + struct thermal_throttle_info *priv; + struct thermal_throttle_info *get_tt_stats = NULL; + struct sk_buff *skb = NULL; + void *cookie; + struct nlattr *therm_attr; + struct nlattr *tt_levels; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_GET_THERM_LVL, + .dealloc = NULL, + }; + + if (hdd_ctx->is_therm_stats_in_progress) { + hdd_err("request already in progress"); + return -EINVAL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + hdd_ctx->is_therm_stats_in_progress = true; + ret = hdd_send_get_thermal_stats_cmd(hdd_ctx, thermal_stats_req, + hdd_get_thermal_stats_cb, + cookie); + if (QDF_IS_STATUS_ERROR(ret)) { + hdd_err("Failure while sending command to fw"); + ret = -EAGAIN; + goto completed; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("Timed out while retrieving thermal stats"); + ret = -EAGAIN; + goto completed; + } + + get_tt_stats = osif_request_priv(request); + if (!get_tt_stats) { + hdd_err("invalid get_tt_stats"); + ret = -EINVAL; + goto completed; + } + + skb_len = NLMSG_HDRLEN + (get_tt_stats->therm_throt_levels) * + (NLA_HDRLEN + (NLA_HDRLEN + + sizeof(get_tt_stats->level_info[i].start_temp_level) + + NLA_HDRLEN + + sizeof(get_tt_stats->level_info[i].end_temp_level) + + NLA_HDRLEN + + sizeof(get_tt_stats->level_info[i].total_time_ms_lo) + + NLA_HDRLEN + + sizeof(get_tt_stats->level_info[i].num_entry))); + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + skb_len); + if (!skb) { + hdd_err_rl("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + ret = -ENOMEM; + goto completed; + } + + therm_attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_THERMAL_STATS); + if (!therm_attr) { + hdd_err_rl("nla_nest_start failed for attr failed"); + ret = -EINVAL; + goto nla_failed; + } + + for (i = 0; i < get_tt_stats->therm_throt_levels; i++) { + tt_levels = nla_nest_start(skb, i); + if (!tt_levels) { + hdd_err_rl("nla_nest_start failed for thermal level %d", + i); + ret = -EINVAL; + goto nla_failed; + } + + hdd_debug("level %d, Temp Range: %d - %d, Dwell time %d, Counter %d", + i, get_tt_stats->level_info[i].start_temp_level, + get_tt_stats->level_info[i].end_temp_level, + get_tt_stats->level_info[i].total_time_ms_lo, + get_tt_stats->level_info[i].num_entry); + + if (nla_put_u32(skb, THERMAL_MIN_TEMP, + get_tt_stats->level_info[i].start_temp_level) || + nla_put_u32(skb, THERMAL_MAX_TEMP, + get_tt_stats->level_info[i].end_temp_level) || + nla_put_u32(skb, THERMAL_DWELL_TIME, + (get_tt_stats->level_info[i].total_time_ms_lo)) || + nla_put_u32(skb, THERMAL_LVL_COUNT, + get_tt_stats->level_info[i].num_entry)) { + hdd_err("nla put failure"); + ret = -EINVAL; + goto nla_failed; + } + nla_nest_end(skb, tt_levels); + } + nla_nest_end(skb, therm_attr); + wlan_cfg80211_vendor_cmd_reply(skb); + goto completed; + +nla_failed: + wlan_cfg80211_vendor_free_skb(skb); +completed: + hdd_ctx->is_therm_stats_in_progress = false; + osif_request_put(request); + + return ret; +} + +#undef THERMAL_MIN_TEMP +#undef THERMAL_MAX_TEMP +#undef THERMAL_DWELL_TIME +#undef THERMAL_LVL_COUNT + +static QDF_STATUS +hdd_send_thermal_stats_clear_cmd(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + status = hdd_send_get_thermal_stats_cmd(hdd_ctx, + thermal_stats_clear, NULL, + NULL); + + return status; +} +#else +static int +hdd_get_curr_thermal_stats_val(struct wiphy *wiphy, + struct hdd_context *hdd_ctx) +{ + return -EINVAL; +} + +static QDF_STATUS +hdd_send_thermal_stats_clear_cmd(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* THERMAL_STATS_SUPPORT */ + +/** + * __wlan_hdd_cfg80211_set_thermal_mitigation_policy() - Set the thermal policy + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Length of @data + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX + 1]; + uint32_t level, cmd_type; + QDF_STATUS status; + int ret; + + hdd_enter(); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err_rl("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX, + (struct nlattr *)data, data_len, + wlan_hdd_thermal_mitigation_policy)) { + hdd_err_rl("Invalid attribute"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE]) { + hdd_err_rl("attr thermal cmd value failed"); + return -EINVAL; + } + + cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE]); + switch (cmd_type) { + case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL: + if (!tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]) { + hdd_err_rl("attr thermal throttle set failed"); + return -EINVAL; + } + level = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]); + + hdd_debug("thermal mitigation level from userspace %d", level); + status = hdd_send_thermal_mitigation_val(hdd_ctx, level, + THERMAL_MONITOR_APPS); + ret = qdf_status_to_os_return(status); + break; + case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL: + ret = hdd_get_curr_thermal_throttle_level_val(hdd_ctx); + break; + case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE: + ret = hdd_get_curr_thermal_temperature_val(hdd_ctx, adapter); + break; + case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS: + ret = hdd_get_curr_thermal_stats_val(wiphy, hdd_ctx); + break; + case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_CLEAR_THERMAL_STATS: + status = hdd_send_thermal_stats_clear_cmd(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failure while sending command to fw"); + ret = -EINVAL; + } + break; + default: + ret = -EINVAL; + } + + hdd_exit(); + return ret; +} + +/** + * wlan_hdd_cfg80211_set_thermal_mitigation_policy() - set thermal + * mitigation policy + * @wiphy: wiphy pointer + * @wdev: pointer to struct wireless_dev + * @data: pointer to incoming NL vendor data + * @data_len: length of @data + * + * Return: 0 on success; error number otherwise. + */ +int +wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int errno; + + errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_thermal_mitigation_policy(wiphy, wdev, + data, + data_len); + + osif_psoc_sync_op_stop(psoc_sync); + + return errno; +} + +bool wlan_hdd_thermal_config_support(void) +{ + return true; +} + +QDF_STATUS hdd_restore_thermal_mitigation_config(struct hdd_context *hdd_ctx) +{ + bool enable = true; + uint32_t dc, dc_off_percent = 0; + uint32_t prio = 0, target_temp = 0; + struct wlan_fwol_thermal_temp thermal_temp = {0}; + QDF_STATUS status; + struct thermal_mitigation_params therm_cfg_params = {0}; + + status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, &thermal_temp); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to get fwol thermal obj"); + return status; + } + + dc_off_percent = hdd_ctx->dutycycle_off_percent; + dc = thermal_temp.thermal_sampling_time; + + if (!dc_off_percent) + enable = false; + + therm_cfg_params.enable = enable; + therm_cfg_params.dc = dc; + therm_cfg_params.levelconf[0].dcoffpercent = dc_off_percent; + therm_cfg_params.levelconf[0].priority = prio; + therm_cfg_params.levelconf[0].tmplwm = target_temp; + therm_cfg_params.num_thermal_conf = 1; + therm_cfg_params.client_id = THERMAL_MONITOR_APPS; + therm_cfg_params.priority = 0; + + hdd_debug("dc %d dc_off_per %d enable %d", dc, dc_off_percent, enable); + + status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle, + &therm_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("Failed to set throttle configuration %d", status); + + return status; +} + +static int +__wlan_hdd_pld_set_thermal_mitigation(struct device *dev, unsigned long state, + int mon_id) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + QDF_STATUS status; + int ret; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED) + return -EINVAL; + + status = hdd_send_thermal_mitigation_val(hdd_ctx, state, mon_id); + + return qdf_status_to_os_return(status); +} + +int wlan_hdd_pld_set_thermal_mitigation(struct device *dev, unsigned long state, + int mon_id) +{ + struct osif_psoc_sync *psoc_sync; + int ret; + + hdd_enter(); + + ret = osif_psoc_sync_op_start(dev, &psoc_sync); + if (ret) + return ret; + + ret = __wlan_hdd_pld_set_thermal_mitigation(dev, state, mon_id); + + osif_psoc_sync_op_stop(psoc_sync); + hdd_exit(); + + return ret; +} + +#ifdef FEATURE_WPSS_THERMAL_MITIGATION +inline void hdd_thermal_mitigation_register_wpps(struct hdd_context *hdd_ctx, + struct device *dev) +{ + if (hdd_ctx->multi_client_thermal_mitigation) + pld_thermal_register(dev, HDD_THERMAL_STATE_LIGHT, + THERMAL_MONITOR_WPSS); +} + +inline void hdd_thermal_mitigation_unregister_wpps(struct hdd_context *hdd_ctx, + struct device *dev) +{ + if (hdd_ctx->multi_client_thermal_mitigation) + pld_thermal_unregister(dev, THERMAL_MONITOR_WPSS); +} +#else +static inline +void hdd_thermal_mitigation_register_wpps(struct hdd_context *hdd_ctx, + struct device *dev) +{ +} + +static inline +void hdd_thermal_mitigation_unregister_wpps(struct hdd_context *hdd_ctx, + struct device *dev) +{ +} +#endif +void hdd_thermal_mitigation_register(struct hdd_context *hdd_ctx, + struct device *dev) +{ + pld_thermal_register(dev, HDD_THERMAL_STATE_EMERGENCY, + THERMAL_MONITOR_APPS); + hdd_thermal_mitigation_register_wpps(hdd_ctx, dev); +} + +void hdd_thermal_mitigation_unregister(struct hdd_context *hdd_ctx, + struct device *dev) +{ + hdd_thermal_mitigation_unregister_wpps(hdd_ctx, dev); + pld_thermal_unregister(dev, THERMAL_MONITOR_APPS); +} + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +/** + * hdd_notify_thermal_throttle_handler() - Thermal throttle event handler + * @psoc: psoc object + * @info: thermal throttle information from target + * + * Return: QDF_STATUS_SUCCESS for success. + */ +static QDF_STATUS +hdd_notify_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc, + struct thermal_throttle_info *info) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + int ret; + enum qca_wlan_vendor_thermal_level level; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return QDF_STATUS_E_FAILURE; + + /* TX will be throttled completely if above MITIGATION level. + * So report additional DIAG event to notify user-space explicitly. + */ + if (info->level == THERMAL_SHUTOFF || + info->level == THERMAL_SHUTDOWN_TARGET) + host_log_device_status(WLAN_STATUS_DEVICE_TEMPERATURE_HIGH); + + data_len = NLMSG_HDRLEN + nla_total_size(sizeof(uint32_t)); + vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, NULL, data_len, + QCA_NL80211_VENDOR_SUBCMD_THERMAL_INDEX, + GFP_KERNEL); + if (!vendor_event) { + hdd_err("wlan_cfg80211_vendor_event_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + level = convert_level_to_vendor_thermal_level(info->level); + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL, + level)) { + wlan_cfg80211_vendor_free_skb(vendor_event); + return QDF_STATUS_E_INVAL; + } + hdd_debug("thermal_throttle:level %d vendor level %d", info->level, + level); + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + return QDF_STATUS_SUCCESS; +} + +void hdd_thermal_register_callbacks(struct hdd_context *hdd_ctx) +{ + struct fwol_thermal_callbacks cb_obj = {0}; + + cb_obj.notify_thermal_throttle_handler = + hdd_notify_thermal_throttle_handler; + ucfg_fwol_thermal_register_callbacks(hdd_ctx->psoc, &cb_obj); +} + +void hdd_thermal_unregister_callbacks(struct hdd_context *hdd_ctx) +{ + ucfg_fwol_thermal_unregister_callbacks(hdd_ctx->psoc); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.h new file mode 100644 index 0000000000..01f64ce4b5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.h @@ -0,0 +1,270 @@ +/* + * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __HDD_THERMAL_H +#define __HDD_THERMAL_H +/** + * DOC: wlan_hdd_thermal.h + * WLAN Host Device Driver thermal mitigation include file + */ + +#include +#include +#include + + +/** + * enum hdd_thermal_states - The various thermal states as supported by WLAN + * @HDD_THERMAL_STATE_NONE: The normal working state + * @HDD_THERMAL_STATE_LIGHT: Intermediate states, WLAN must perform partial + * mitigation + * @HDD_THERMAL_STATE_MODERATE: Intermediate states, WLAN must perform partial + * mitigation + * @HDD_THERMAL_STATE_SEVERE: Intermediate states, WLAN must perform partial + * mitigation + * @HDD_THERMAL_STATE_CRITICAL: Intermediate states, WLAN must perform partial + * mitigation + * @HDD_THERMAL_STATE_EMERGENCY: The highest state, WLAN must enter forced + * IMPS and will disconnect any active STA + * connection + * @HDD_THERMAL_STATE_INVAL: Placeholder for invalid/unknown state + */ +enum hdd_thermal_states { + HDD_THERMAL_STATE_NONE = 0, + HDD_THERMAL_STATE_LIGHT = 1, + HDD_THERMAL_STATE_MODERATE = 2, + HDD_THERMAL_STATE_SEVERE = 3, + HDD_THERMAL_STATE_CRITICAL = 4, + HDD_THERMAL_STATE_EMERGENCY = 5, + HDD_THERMAL_STATE_INVAL = 0xFF, +}; + +/* + * thermal_monitor_id: enum of thermal client + * @THERMAL_MONITOR_APPS: Thermal monitor client of APPS + * @THERMAL_MONITOR_WPSS: Thermal monitor client for WPSS + */ +enum thermal_monitor_id { + THERMAL_MONITOR_APPS = 1, + THERMAL_MONITOR_WPSS, +}; + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +int +wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); + +/** + * wlan_hdd_thermal_config_support() - thermal mitigation support + * + * Return: true if thermal mitigation support enabled otherwise false + */ +bool wlan_hdd_thermal_config_support(void); + +/** + * hdd_restore_thermal_mitigation_config - Restore the saved thermal config + * @hdd_ctx: HDD context + * + * Restore the thermal mitigation config after SSR. + * + * Return: QDF_STATUS + */ +QDF_STATUS hdd_restore_thermal_mitigation_config(struct hdd_context *hdd_ctx); + +extern const struct nla_policy + wlan_hdd_thermal_mitigation_policy + [QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX + 1]; + +#define FEATURE_THERMAL_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV, \ + .doit = wlan_hdd_cfg80211_set_thermal_mitigation_policy, \ + vendor_command_policy(wlan_hdd_thermal_mitigation_policy, \ + QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX) \ +}, + +#define FEATURE_THERMAL_VENDOR_EVENTS \ +[QCA_NL80211_VENDOR_SUBCMD_THERMAL_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_THERMAL_EVENT, \ +}, + +/** + * hdd_thermal_mitigation_register() - Register for platform specific thermal + * mitigation support + * @hdd_ctx: Pointer to Hdd context + * @dev: Pointer to the device + * + * Register to the platform specific thermal mitigation support + * Return: None + */ +void hdd_thermal_mitigation_register(struct hdd_context *hdd_ctx, + struct device *dev); + +/** + * hdd_thermal_mitigation_unregister() - Unregister for platform specific + * thermal mitigation support + * @hdd_ctx: Pointer to Hdd context + * @dev: Pointer to the device + * + * Unregister to the platform specific thermal mitigation support + * Return: None + */ +void hdd_thermal_mitigation_unregister(struct hdd_context *hdd_ctx, + struct device *dev); + +/** + * wlan_hdd_pld_set_thermal_mitigation() - send the suggested thermal value + * to the firmware + * @dev: Pointer to the device + * @state: Thermal state to set + * @mon_id: Thermal monitor id ie.. apps or wpss + * + * Send the requested thermal mitigation value to the firmware * for the + * requested thermal monitor id. + * + * Return: 0 for success or errno for failure. + */ +int wlan_hdd_pld_set_thermal_mitigation(struct device *dev, + unsigned long state, int mon_id); +/** + * hdd_send_thermal_mitigation_val() - send the suggested thermal value + * to the firmware + * @hdd_ctx: pointer to hdd context + * @level: Thermal mitigation level to set + * @mon_id: Thermal monitor id ie.. apps or wpss + * + * Send the requested thermal mitigation value to the firmware * for the + * requested thermal monitor id. + * + * Return: 0 for success or errno for failure. + */ +QDF_STATUS +hdd_send_thermal_mitigation_val(struct hdd_context *hdd_ctx, uint32_t level, + uint8_t mon_id); +#ifdef FEATURE_WPSS_THERMAL_MITIGATION +/** + * hdd_thermal_fill_clientid_priority() - fill the client id/priority + * @hdd_ctx: pointer to hdd context structure + * @mon_id: Thermal monitor id ie.. apps or wpss + * @priority_apps: Priority of the apps client to be considered + * @priority_wpps: Priority of the wpps client to be considered + * @params: pointer to thermal mitigation parameters + * + * Fill the clientid/priority for the firmwaire to consider. + * + * Return: none + */ +void +hdd_thermal_fill_clientid_priority(struct hdd_context *hdd_ctx, uint8_t mon_id, + uint8_t priority_apps, uint8_t priority_wpps, + struct thermal_mitigation_params *params); +#else +static inline void +hdd_thermal_fill_clientid_priority(struct hdd_context *hdd_ctx, uint8_t mon_id, + uint8_t priority_apps, uint8_t priority_wpps, + struct thermal_mitigation_params *params) +{ +} +#endif + +/** + * hdd_thermal_register_callbacks() - register thermal event callback + * to be called by fwol thermal layer + * @hdd_ctx: hdd context + * + * The callback will be invoked by fwol thermal layer when the target + * indicate thermal throttle level changed. Host will report the new + * level to upper layer by vendor command event. + * + * Return: none + */ +void hdd_thermal_register_callbacks(struct hdd_context *hdd_ctx); + +/** + * hdd_thermal_unregister_callbacks() - unregister thermal event callback + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_thermal_unregister_callbacks(struct hdd_context *hdd_ctx); +#else +#define FEATURE_THERMAL_VENDOR_COMMANDS +#define FEATURE_THERMAL_VENDOR_EVENTS + +static inline bool wlan_hdd_thermal_config_support(void) +{ + return false; +} + +static inline +QDF_STATUS hdd_restore_thermal_mitigation_config(struct hdd_context *hdd_ctx) +{ + return false; +} + +static inline +void hdd_thermal_mitigation_register(struct hdd_context *hdd_ctx, + struct device *dev) +{ +} + +static inline +void hdd_thermal_mitigation_unregister(struct hdd_context *hdd_ctx, + struct device *dev) +{ +} + +static inline +int wlan_hdd_pld_set_thermal_mitigation(struct device *dev, + unsigned long state, int mon_id) +{ + return 0; +} + +static inline void +hdd_thermal_register_callbacks(struct hdd_context *hdd_ctx) +{ +} + +static inline void +hdd_thermal_unregister_callbacks(struct hdd_context *hdd_ctx) +{ +} + +static inline QDF_STATUS +hdd_send_thermal_mitigation_val(struct hdd_context *hdd_ctx, uint32_t level, + uint8_t mon_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_THERMAL_VENDOR_COMMANDS */ + +#ifdef THERMAL_STATS_SUPPORT +QDF_STATUS +hdd_send_get_thermal_stats_cmd(struct hdd_context *hdd_ctx, + enum thermal_stats_request_type request_type, + void (*callback)(void *context, + struct thermal_throttle_info *response), + void *context); +#endif /* THERMAL_STATS_SUPPORT */ +#endif /* __HDD_THERMAL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c new file mode 100644 index 0000000000..39b8377d9b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_trace.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HDD_TRACE_RECORD + +/** + * DOC: wlan_hdd_trace.c + * + * WLAN Host Device Driver trace implementation + * + */ + +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_hdd_trace.h" +#include "wlan_hdd_main.h" + +/** + * hdd_trace_dump() - Dump an HDD-specific trace record + * @mac: (unused) global MAC handle + * @record: trace record that was previously recorded + * @index: index of the trace record + * + * Return: none + */ +static void +hdd_trace_dump(void *mac, tp_qdf_trace_record record, uint16_t index) +{ + if (TRACE_CODE_HDD_RX_SME_MSG == record->code) + hdd_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + index, record->qtime, record->time, + record->session, "RX SME MSG:", + get_e_roam_cmd_status_str(record->data), + record->data); + else + hdd_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + index, record->qtime, record->time, + record->session, "HDD Event:", + hdd_trace_event_string(record->code), + record->data); +} + +/** + * hdd_trace_init() - HDD trace subsystem initialization + * + * Registers HDD with the debug trace subsystem + * + * Return: none + */ +void hdd_trace_init(void) +{ + qdf_trace_register(QDF_MODULE_ID_HDD, hdd_trace_dump); +} + +#endif /* ifdef HDD_TRACE_RECORD */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c new file mode 100644 index 0000000000..c6eb0f72fe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tsf.c @@ -0,0 +1,3510 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_tsf.c - WLAN Host Device Driver tsf related implementation + */ + +#include "osif_sync.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_tsf.h" +#include "wma_api.h" +#include "wlan_fwol_ucfg_api.h" +#include +#include +#if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \ + defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) || \ + defined(WLAN_FEATURE_TSF_ACCURACY) +#include +#endif + +#include "ol_txrx_api.h" +#ifdef WLAN_FEATURE_TSF_AUTO_REPORT +#include +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +#if !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \ + !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \ + !defined(WLAN_FEATURE_TSF_TIMER_SYNC) +static int tsf_gpio_irq_num = -1; +#endif +#endif +static qdf_event_t tsf_sync_get_completion_evt; +#define WLAN_TSF_SYNC_GET_TIMEOUT 2000 +#define WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS 500 +#define WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS 100 +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +#define WLAN_HDD_SOFTAP_INTERVAL_TIMES 1 +#else +#define WLAN_HDD_SOFTAP_INTERVAL_TIMES 100 +#endif +#define OUTPUT_HIGH 1 +#define OUTPUT_LOW 0 + +#ifdef WLAN_FEATURE_TSF_PLUS +#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \ + defined(WLAN_FEATURE_TSF_TIMER_SYNC) +static void hdd_update_timestamp(struct hdd_adapter *adapter); +#else +static void +hdd_update_timestamp(struct hdd_adapter *adapter, + uint64_t target_time, uint64_t host_time); +#endif +#endif + +#ifdef QCA_GET_TSF_VIA_REG +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf); + +/** + * struct hdd_tsf_report - TSF report filled in by DP layer + * @vdev_id: vdev id for which TSF values is to be read + * @tsf_id: tsf if used to read TSF report + * @mac_id: lmac_id for which TSF values are read + * @tsf: 64 bit tsf value as read from scratch registers + * @tsf_sync_soc_time: host qtimer time when scratch registers are read + * + * The structure is used by the upper layers to pass vdev_id, tsf_id and mac_id + * information to DP layer and get tsf time and host time when TSF was read. + */ +struct hdd_tsf_report { + uint32_t vdev_id; + uint32_t tsf_id; + uint32_t mac_id; + uint64_t tsf; + uint64_t tsf_sync_soc_time; +}; +#endif + +/** + * enum hdd_tsf_op_result - result of tsf operation + * @HDD_TSF_OP_SUCC: succeed + * @HDD_TSF_OP_FAIL: fail + */ +enum hdd_tsf_op_result { + HDD_TSF_OP_SUCC, + HDD_TSF_OP_FAIL +}; + +#ifdef WLAN_FEATURE_TSF_PLUS +#ifdef WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC +#define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 1 +#else +#define WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL 9 +#endif +static inline void hdd_set_th_sync_status(struct hdd_adapter *adapter, + bool initialized) +{ + qdf_atomic_set(&adapter->tsf.tsf_sync_ready_flag, + (initialized ? 1 : 0)); +} + +static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter) +{ + return qdf_atomic_read(&adapter->tsf.tsf_sync_ready_flag) != 0; +} + +#else +static inline bool hdd_get_th_sync_status(struct hdd_adapter *adapter) +{ + return true; +} +#endif + +static +enum hdd_tsf_get_state hdd_tsf_check_conn_state(struct hdd_adapter *adapter) +{ + enum QDF_OPMODE mode; + enum hdd_tsf_get_state ret = TSF_RETURN; + + mode = adapter->device_mode; + + if (!test_bit(SOFTAP_BSS_STARTED, &adapter->deflink->link_flags) && + (mode == QDF_SAP_MODE || mode == QDF_P2P_GO_MODE)) { + hdd_err("Soft AP / P2p GO not beaconing"); + ret = TSF_SAP_NOT_STARTED_NO_TSF; + } else if (!hdd_cm_is_vdev_associated(adapter->deflink) && + (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE)) { + hdd_err("failed to cap tsf, not connect with ap"); + ret = TSF_STA_NOT_CONNECTED_NO_TSF; + } + + return ret; +} + +static bool hdd_tsf_is_initialized(struct hdd_adapter *adapter) +{ + struct hdd_context *hddctx; + + if (!adapter) { + hdd_err("invalid adapter"); + return false; + } + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return false; + } + + if (!qdf_atomic_read(&hddctx->tsf.tsf_ready_flag) || + !hdd_get_th_sync_status(adapter)) { + hdd_err("TSF is not initialized"); + return false; + } + + return true; +} + +#if (defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) && \ + defined(WLAN_FEATURE_TSF_PLUS)) || \ + defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) || \ + defined(WLAN_FEATURE_TSF_TIMER_SYNC) +/** + * hdd_tsf_reset_gpio() - Reset TSF GPIO used for host timer sync + * @adapter: pointer to adapter + * + * This function send WMI command to reset GPIO configured in FW after + * TSF get operation. + * + * Return: TSF_RETURN on Success, TSF_RESET_GPIO_FAIL on failure + */ +static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) +{ + /* No GPIO Host timer sync for integrated WIFI Device */ + return TSF_RETURN; +} + +/** + * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync + * @hdd_ctx: pointer to hdd context + * + * This function is a dummy function for adrastea arch + * + * Return: QDF_STATUS_SUCCESS on Success + */ + +static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#else +static int hdd_tsf_reset_gpio(struct hdd_adapter *adapter) +{ + int ret; + + ret = wma_cli_set_command((int)adapter->deflink->vdev_id, + (int)GEN_PARAM_RESET_TSF_GPIO, + adapter->deflink->vdev_id, + GEN_CMD); + + if (ret != 0) { + hdd_err("tsf reset GPIO fail "); + ret = TSF_RESET_GPIO_FAIL; + } else { + ret = TSF_RETURN; + } + return ret; +} + +/** + * hdd_tsf_set_gpio() - Set TSF GPIO used for host timer sync + * @hdd_ctx: pointer to hdd context + * + * This function check GPIO and set GPIO as IRQ to FW side on + * none Adrastea arch + * + * Return: QDF_STATUS_SUCCESS on Success, others on Failure. + */ +static QDF_STATUS hdd_tsf_set_gpio(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t tsf_gpio_pin = TSF_GPIO_PIN_INVALID; + + status = ucfg_fwol_get_tsf_gpio_pin(hdd_ctx->psoc, &tsf_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (tsf_gpio_pin == TSF_GPIO_PIN_INVALID) + return QDF_STATUS_E_INVAL; + + status = sme_set_tsf_gpio(hdd_ctx->mac_handle, + tsf_gpio_pin); + + return status; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd) +{ + uint32_t tsf_ptp_options; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) + return !!tsf_ptp_options; + else + return false; +} + +bool hdd_tsf_is_tx_set(struct hdd_context *hdd) +{ + uint32_t tsf_ptp_options; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) + return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TX; + else + return false; +} + +bool hdd_tsf_is_rx_set(struct hdd_context *hdd) +{ + uint32_t tsf_ptp_options; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) + return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RX; + else + return false; +} + +bool hdd_tsf_is_raw_set(struct hdd_context *hdd) +{ + uint32_t tsf_ptp_options; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) + return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_RAW; + else + return false; +} + +bool hdd_tsf_is_dbg_fs_set(struct hdd_context *hdd) +{ + uint32_t tsf_ptp_options; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) + return tsf_ptp_options & CFG_SET_TSF_DBG_FS; + else + return false; +} + +bool hdd_tsf_is_tsf64_tx_set(struct hdd_context *hdd) +{ + uint32_t tsf_ptp_options; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd->psoc, &tsf_ptp_options))) + return tsf_ptp_options & CFG_SET_TSF_PTP_OPT_TSF64_TX; + else + return false; +} + +bool hdd_tsf_is_time_sync_enabled_cfg(struct hdd_context *hdd_ctx) +{ + uint32_t tsf_ptp_options; + + if (hdd_ctx && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_ptp_options(hdd_ctx->psoc, &tsf_ptp_options))) + return tsf_ptp_options & CFG_SET_TSF_PTP_SYNC_PERIOD; + else + return false; +} + +static bool hdd_is_tsf_sync_enabled(struct hdd_context *hdd) +{ + bool is_tsf_sync_enable; + + if (hdd && QDF_IS_STATUS_SUCCESS( + ucfg_fwol_get_tsf_sync_enable(hdd->psoc, &is_tsf_sync_enable))) + return is_tsf_sync_enable; + else + return false; +} + +void hdd_update_dynamic_tsf_sync(struct hdd_adapter *adapter) +{ + adapter->tsf.enable_dynamic_tsf_sync = + hdd_is_tsf_sync_enabled(adapter->hdd_ctx); +} +#else + +static bool hdd_tsf_is_ptp_enabled(struct hdd_context *hdd) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS +static inline +uint64_t hdd_get_monotonic_host_time(struct hdd_context *hdd_ctx) +{ + return hdd_tsf_is_raw_set(hdd_ctx) ? + ktime_get_ns() : ktime_get_real_ns(); +} +#endif + +#if defined(WLAN_FEATURE_TSF_PLUS) && \ + defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) +#define MAX_CONTINUOUS_RETRY_CNT 10 +static uint32_t +hdd_wlan_retry_tsf_cap(struct hdd_adapter *adapter) +{ + struct hdd_context *hddctx; + int count = adapter->tsf.continuous_cap_retry_count; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (count == MAX_CONTINUOUS_RETRY_CNT) { + hdd_debug("Max retry count reached"); + return 0; + } + qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0); + count++; + adapter->tsf.continuous_cap_retry_count = count; + return (count * WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS); +} + +static void +hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter) +{ + struct hdd_context *hddctx; + int count = adapter->tsf.continuous_cap_retry_count; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (count == MAX_CONTINUOUS_RETRY_CNT) { + hdd_debug("Restart TSF CAP"); + qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0); + adapter->tsf.continuous_cap_retry_count = 0; + qdf_mc_timer_start(&adapter->tsf.host_target_sync_timer, + WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS); + } +} + +static void +hdd_update_host_time(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + u64 host_time; + char *name = NULL; + + hdd_ctx = adapter->hdd_ctx; + + if (!hdd_tsf_is_initialized(adapter)) { + hdd_err("tsf is not init, exit"); + return; + } + + host_time = hdd_get_monotonic_host_time(hdd_ctx); + hdd_update_timestamp(adapter, 0, host_time); + name = adapter->dev->name; + + hdd_debug("iface: %s - host_time: %llu", + (!name ? "none" : name), host_time); +} + +static +void hdd_tsf_ext_gpio_sync_work(void *data) +{ + QDF_STATUS status; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID; + + adapter = data; + hdd_ctx = adapter->hdd_ctx; + status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc, + &tsf_sync_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("tsf sync gpio host pin error"); + return; + } + gpio_set_value(tsf_sync_gpio_pin, OUTPUT_HIGH); + hdd_update_host_time(adapter); + usleep_range(50, 100); + gpio_set_value(tsf_sync_gpio_pin, OUTPUT_LOW); + + status = wma_cli_set_command((int)adapter->deflink->vdev_id, + (int)GEN_PARAM_CAPTURE_TSF, + adapter->deflink->vdev_id, GEN_CMD); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("cap tsf fail"); + qdf_mc_timer_stop(&adapter->tsf.host_capture_req_timer); + } +} + +static void +hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter) +{ + qdf_create_work(0, &adapter->tsf.gpio_tsf_sync_work, + hdd_tsf_ext_gpio_sync_work, adapter); +} + +static void +hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter) +{ + qdf_destroy_work(0, &adapter->tsf.gpio_tsf_sync_work); +} + +static void +hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter) +{ + qdf_cancel_work(&adapter->tsf.gpio_tsf_sync_work); +} + +static void +hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter) +{ + qdf_sched_work(0, &adapter->tsf.gpio_tsf_sync_work); +} + +static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter) +{ + hdd_tsf_start_ext_gpio_sync(adapter); + return true; +} +#elif defined(WLAN_FEATURE_TSF_PLUS) && \ + !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) +static void +hdd_wlan_restart_tsf_cap(struct hdd_adapter *adapter) +{ +} + +static void +hdd_tsf_gpio_sync_work_init(struct hdd_adapter *adapter) +{ +} + +static void +hdd_tsf_gpio_sync_work_deinit(struct hdd_adapter *adapter) +{ +} + +static void +hdd_tsf_stop_ext_gpio_sync(struct hdd_adapter *adapter) +{ +} + +static void +hdd_tsf_start_ext_gpio_sync(struct hdd_adapter *adapter) +{ +} + +static bool +hdd_tsf_cap_sync_send(struct hdd_adapter *adapter) +{ + hdd_tsf_start_ext_gpio_sync(adapter); + return false; +} + +#else +static bool hdd_tsf_cap_sync_send(struct hdd_adapter *adapter) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_TSF_TIMER_SYNC +/** + * hdd_convert_qtime_to_us() - convert qtime to us + * @time: QTIMER ticks for adrastea and us for Lithium + * + * This function converts qtime to us. + * + * Return: Time in microseconds + */ +static inline uint64_t +hdd_convert_qtime_to_us(uint64_t time) +{ + return time; +} + +#else +static inline uint64_t +hdd_convert_qtime_to_us(uint64_t time) +{ + return qdf_log_timestamp_to_usecs(time); +} +#endif + +/** + * hdd_capture_tsf_internal_via_wmi() - convert qtime to us + * @adapter: pointer to adapter + * @buf: in case of failure update with fail + * @len: buffer length + * + * Return: result of tsf operation + */ +static enum hdd_tsf_op_result +hdd_capture_tsf_internal_via_wmi(struct hdd_adapter *adapter, uint32_t *buf, + int len) +{ + int ret; + struct hdd_context *hddctx = adapter->hdd_ctx; + + ret = wma_cli_set_command((int)adapter->deflink->vdev_id, + (int)GEN_PARAM_CAPTURE_TSF, + adapter->deflink->vdev_id, GEN_CMD); + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("cap tsf fail"); + buf[0] = TSF_CAPTURE_FAIL; + hddctx->tsf.cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0); + qdf_mc_timer_stop(&adapter->tsf.host_capture_req_timer); + } + return HDD_TSF_OP_SUCC; +} + +#ifndef QCA_GET_TSF_VIA_REG +static inline +enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter, + uint32_t *buf, int len) +{ + return hdd_capture_tsf_internal_via_wmi(adapter, buf, len); +} + +static inline void wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, + struct stsf *ptsf) +{ +} +#else + +static inline int hdd_tsf_reg_is_details_valid(struct hdd_adapter *adapter) +{ + return qdf_atomic_read(&adapter->tsf.tsf_details_valid); +} + +static inline void +wlan_hdd_tsf_reg_update_details(struct hdd_adapter *adapter, struct stsf *ptsf) +{ + if (ptsf->tsf_id_valid) { + adapter->tsf.tsf_id = ptsf->tsf_id; + adapter->tsf.tsf_mac_id = ptsf->mac_id; + qdf_atomic_set(&adapter->tsf.tsf_details_valid, 1); + } + hdd_debug("vdev_id %u tsf_id %u tsf_id_valid %u mac_id %u", + adapter->deflink->vdev_id, ptsf->tsf_id, ptsf->tsf_id_valid, + ptsf->mac_id); +} + +static inline +QDF_STATUS wlan_hdd_tsf_reg_get(struct hdd_adapter *adapter, + struct hdd_tsf_report *tsf_report) +{ + ol_txrx_soc_handle soc = cds_get_context(QDF_MODULE_ID_SOC); + uint64_t tsf_time = 0; + uint64_t tsf_sync_soc_time = 0; + + if (qdf_unlikely(!soc)) + return QDF_STATUS_E_INVAL; + + cdp_get_tsf_time(soc, tsf_report->tsf_id, tsf_report->mac_id, + &tsf_time, &tsf_sync_soc_time); + + /* fill in the report */ + tsf_report->tsf = tsf_time; + tsf_report->tsf_sync_soc_time = tsf_sync_soc_time; + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_hdd_tsf_reg_process_report() - Process tsf report + * @adapter: pointer to the adapter + * @tsf_report: pointer to tsf report + * + * This function process the tsf report received and update tsf + * value received via scratch register read to adapter + * + * Return: 0 for success or 1 in case of failure + */ +static enum hdd_tsf_op_result +wlan_hdd_tsf_reg_process_report(struct hdd_adapter *adapter, + struct hdd_tsf_report *tsf_report) +{ + struct hdd_vdev_tsf *tsf; + QDF_TIMER_STATE capture_req_timer_status; + qdf_mc_timer_t *capture_timer; + + if (!tsf_report->tsf && !tsf_report->tsf_sync_soc_time) { + hdd_err("Invalid TSF report"); + return HDD_TSF_OP_FAIL; + } + + if (!hdd_tsf_is_initialized(adapter)) { + hdd_err("tsf is not init, ignore tsf event"); + return HDD_TSF_OP_FAIL; + } + + hdd_debug("device_mode is %d", adapter->device_mode); + + tsf = &adapter->tsf; + capture_timer = &tsf->host_capture_req_timer; + capture_req_timer_status = + qdf_mc_timer_get_current_state(capture_timer); + if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) { + hdd_warn("invalid timer status"); + return HDD_TSF_OP_FAIL; + } + + qdf_mc_timer_stop(capture_timer); + tsf->cur_target_time = tsf_report->tsf; + tsf->cur_tsf_sync_soc_time = tsf_report->tsf_sync_soc_time * + NSEC_PER_USEC; + + qdf_event_set(&tsf_sync_get_completion_evt); + hdd_update_tsf(adapter, tsf->cur_target_time); + hdd_debug("vdev id=%u, tsf=%llu", adapter->deflink->vdev_id, + tsf_report->tsf); + return HDD_TSF_OP_SUCC; +} + +static enum hdd_tsf_op_result +hdd_capture_tsf_internal_via_reg(struct hdd_adapter *adapter, uint32_t *buf, + int len) +{ + struct hdd_tsf_report tsf_report; + + if (!hdd_tsf_reg_is_details_valid(adapter)) { + hdd_warn("TSF reg details are not valid!"); + return HDD_TSF_OP_FAIL; + } + + qdf_mem_zero(&tsf_report, sizeof(tsf_report)); + tsf_report.vdev_id = adapter->deflink->vdev_id; + tsf_report.tsf_id = adapter->tsf.tsf_id; + tsf_report.mac_id = adapter->tsf.tsf_mac_id; + + if (wlan_hdd_tsf_reg_get(adapter, &tsf_report)) { + hdd_warn("Unable to get tsf report"); + return HDD_TSF_OP_FAIL; + } + + return wlan_hdd_tsf_reg_process_report(adapter, &tsf_report); +} + +static inline +enum hdd_tsf_op_result _hdd_capture_tsf_internal(struct hdd_adapter *adapter, + uint32_t *buf, int len) +{ + if (!qdf_atomic_read(&adapter->tsf.tsf_details_valid)) + return hdd_capture_tsf_internal_via_wmi(adapter, buf, len); + else + return hdd_capture_tsf_internal_via_reg(adapter, buf, len); +} + +#endif /* QCA_GET_TSF_VIA_REG */ + +static enum hdd_tsf_op_result hdd_capture_tsf_internal( + struct hdd_adapter *adapter, uint32_t *buf, int len) +{ + enum hdd_tsf_op_result ret; + struct hdd_context *hddctx; + qdf_mc_timer_t *cap_timer; + + if (!adapter || !buf) { + hdd_err("invalid pointer"); + return HDD_TSF_OP_FAIL; + } + + if (len != 1) + return HDD_TSF_OP_FAIL; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } + + if (wlan_hdd_validate_context(hddctx)) { + hdd_err("hdd context validation failed"); + return HDD_TSF_OP_FAIL; + } + + if (!hdd_tsf_is_initialized(adapter)) { + buf[0] = TSF_NOT_READY; + return HDD_TSF_OP_SUCC; + } + + buf[0] = hdd_tsf_check_conn_state(adapter); + if (buf[0] != TSF_RETURN) + return HDD_TSF_OP_SUCC; + + if (qdf_atomic_inc_return(&hddctx->tsf.cap_tsf_flag) > 1) { + hdd_err("current in capture state"); + buf[0] = TSF_CURRENT_IN_CAP_STATE; + return HDD_TSF_OP_SUCC; + } + + /* record adapter for cap_tsf_irq_handler */ + hddctx->tsf.cap_tsf_context = adapter; + + hdd_debug("+ioctl issue cap tsf cmd"); + cap_timer = &adapter->tsf.host_capture_req_timer; + qdf_mc_timer_start(cap_timer, WLAN_HDD_CAPTURE_TSF_REQ_TIMEOUT_MS); + + /* Reset TSF value for new capture */ + adapter->tsf.cur_target_time = 0; + + buf[0] = TSF_RETURN; + + if (hdd_tsf_cap_sync_send(adapter)) + return HDD_TSF_OP_SUCC; + + ret = _hdd_capture_tsf_internal(adapter, buf, len); + hdd_debug("-ioctl return cap tsf cmd"); + + return ret; +} + +static enum hdd_tsf_op_result hdd_indicate_tsf_internal( + struct hdd_adapter *adapter, struct hdd_tsf_op_response *tsf_op_resp) +{ + int ret; + struct hdd_context *hddctx; + + if (!adapter || !tsf_op_resp) { + hdd_err("invalid pointer"); + return HDD_TSF_OP_FAIL; + } + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } + + memset(tsf_op_resp, 0, sizeof(*tsf_op_resp)); + if (!hdd_tsf_is_initialized(adapter)) { + tsf_op_resp->status = TSF_NOT_READY; + return HDD_TSF_OP_SUCC; + } + + tsf_op_resp->status = hdd_tsf_check_conn_state(adapter); + if (tsf_op_resp->status != TSF_RETURN) + return HDD_TSF_OP_SUCC; + + if (adapter->tsf.cur_target_time == 0) { + hdd_info("TSF value not received"); + tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW; + return HDD_TSF_OP_SUCC; + } + + tsf_op_resp->status = TSF_RETURN; + tsf_op_resp->time = adapter->tsf.cur_target_time; + tsf_op_resp->soc_time = adapter->tsf.cur_tsf_sync_soc_time; + + if (!qdf_atomic_read(&hddctx->tsf.cap_tsf_flag)) { + hdd_debug("old: status=%u, tsf_time=%llu, tsf_soc_time=%llu", + tsf_op_resp->status, + tsf_op_resp->time, + tsf_op_resp->soc_time); + return HDD_TSF_OP_SUCC; + } + + ret = hdd_tsf_reset_gpio(adapter); + if (0 != ret) { + hdd_err("reset tsf gpio fail"); + tsf_op_resp->status = TSF_RESET_GPIO_FAIL; + return HDD_TSF_OP_SUCC; + } + hddctx->tsf.cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0); + hdd_debug("get tsf cmd,status=%u, tsf_time=%llu, tsf_soc_time=%llu", + tsf_op_resp->status, + tsf_op_resp->time, + tsf_op_resp->soc_time); + + return HDD_TSF_OP_SUCC; +} + +#ifdef WLAN_FEATURE_TSF_PLUS +/* unit for target time: us; host time: ns */ +#define HOST_TO_TARGET_TIME_RATIO NSEC_PER_USEC +#define MAX_ALLOWED_DEVIATION_NS (100 * NSEC_PER_USEC) +#define MAX_CONTINUOUS_ERROR_CNT 3 + +/* to distinguish 32-bit overflow case, this interval should: + * equal or less than (1/2 * OVERFLOW_INDICATOR32 us) + */ +#if defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) || \ + defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) +#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 2 +#else +#define WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC 4 +#endif +#define OVERFLOW_INDICATOR32 (((int64_t)0x1) << 32) +#define CAP_TSF_TIMER_FIX_SEC 1 + +/** + * enum hdd_ts_status - timestamp status + * @HDD_TS_STATUS_WAITING: one of the stamp-pair is not updated + * @HDD_TS_STATUS_READY: valid tstamp-pair + * @HDD_TS_STATUS_INVALID: invalid tstamp-pair + */ +enum hdd_ts_status { + HDD_TS_STATUS_WAITING, + HDD_TS_STATUS_READY, + HDD_TS_STATUS_INVALID +}; + +static +enum hdd_tsf_op_result __hdd_start_tsf_sync(struct hdd_adapter *adapter) +{ + QDF_STATUS ret; + + if (!hdd_get_th_sync_status(adapter)) { + hdd_err("Host Target sync has not initialized"); + return HDD_TSF_OP_FAIL; + } + + hdd_tsf_gpio_sync_work_init(adapter); + ret = qdf_mc_timer_start(&adapter->tsf.host_target_sync_timer, + WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS); + if (ret != QDF_STATUS_SUCCESS && ret != QDF_STATUS_E_ALREADY) { + hdd_err("Failed to start timer, ret: %d", ret); + return HDD_TSF_OP_FAIL; + } + return HDD_TSF_OP_SUCC; +} + +static +enum hdd_tsf_op_result __hdd_stop_tsf_sync(struct hdd_adapter *adapter) +{ + QDF_STATUS ret; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } + + if (!hdd_get_th_sync_status(adapter)) { + hdd_debug("Host Target sync has not initialized"); + return HDD_TSF_OP_SUCC; + } + + ret = qdf_mc_timer_stop(&adapter->tsf.host_target_sync_timer); + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("Failed to stop target timer, ret: %d", ret); + return HDD_TSF_OP_FAIL; + } + + ret = qdf_mc_timer_stop(&adapter->tsf.host_capture_req_timer); + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("Failed to stop capture timer, ret: %d", ret); + return HDD_TSF_OP_FAIL; + } + + hdd_tsf_stop_ext_gpio_sync(adapter); + hdd_tsf_gpio_sync_work_deinit(adapter); + return HDD_TSF_OP_SUCC; +} + +static inline void hdd_reset_timestamps(struct hdd_adapter *adapter) +{ + struct hdd_vdev_tsf *tsf = &adapter->tsf; + + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + tsf->cur_host_time = 0; + tsf->cur_target_time = 0; + tsf->last_host_time = 0; + tsf->last_target_time = 0; + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); +} + +/** + * hdd_check_timestamp_status() - return the tstamp status + * @last_target_time: the last saved target time + * @last_sync_time: the last saved sync time + * @cur_target_time: new target time + * @cur_sync_time: new sync time + * @force_sync: flag to force new timestamp-pair as valid + * + * This function check the new timstamp-pair(cur_host_time/cur_target_time)or + * (cur_qtime_time/cur_target_time) + * Return: + * HDD_TS_STATUS_WAITING: cur_sync_time or cur_sync_time is 0 + * HDD_TS_STATUS_READY: cur_target_time/cur_host_time is a valid pair, + * and can be saved + * HDD_TS_STATUS_INVALID: cur_target_time/cur_sync_time is a invalid pair, + * should be discard + */ +static +enum hdd_ts_status hdd_check_timestamp_status( + uint64_t last_target_time, + uint64_t last_sync_time, + uint64_t cur_target_time, + uint64_t cur_sync_time, + bool force_sync) +{ + uint64_t delta_ns, delta_target_time, delta_sync_time; + + /* one or more are not updated, need to wait */ + if (cur_target_time == 0 || cur_sync_time == 0) + return HDD_TS_STATUS_WAITING; + + /* init value, it's the first time to update the pair */ + if (last_target_time == 0 && last_sync_time == 0) + return HDD_TS_STATUS_READY; + + /* the new values should be greater than the saved values */ + if ((cur_target_time <= last_target_time) || + (cur_sync_time <= last_sync_time)) { + hdd_err("Invalid timestamps!last_target_time: %llu;" + "last_sync_time: %llu; cur_target_time: %llu;" + "cur_sync_time: %llu", + last_target_time, last_sync_time, + cur_target_time, cur_sync_time); + return HDD_TS_STATUS_INVALID; + } + + delta_target_time = (cur_target_time - last_target_time) * + NSEC_PER_USEC; + delta_sync_time = cur_sync_time - last_sync_time; + + /* + * DO NOT use abs64() , a big uint64 value might be turned to + * a small int64 value + */ + delta_ns = ((delta_target_time > delta_sync_time) ? + (delta_target_time - delta_sync_time) : + (delta_sync_time - delta_target_time)); + hdd_debug("timestamps deviation - delta: %llu ns", delta_ns); + /* the deviation should be smaller than a threshold */ + if (!force_sync && delta_ns > MAX_ALLOWED_DEVIATION_NS) { + hdd_debug("Invalid timestamps - delta: %llu ns", delta_ns); + return HDD_TS_STATUS_INVALID; + } + return HDD_TS_STATUS_READY; +} + +static inline bool hdd_tsf_is_in_cap(struct hdd_adapter *adapter) +{ + struct hdd_context *hddctx; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) + return false; + + return qdf_atomic_read(&hddctx->tsf.cap_tsf_flag) > 0; +} + +/* define 64bit plus/minus to deal with overflow */ +static inline int hdd_64bit_plus(uint64_t x, int64_t y, uint64_t *ret) +{ + if ((y < 0 && (-y) > x) || + (y > 0 && (y > U64_MAX - x))) { + *ret = 0; + return -EINVAL; + } + + *ret = x + y; + return 0; +} + +static inline int hdd_uint64_plus(uint64_t x, uint64_t y, uint64_t *ret) +{ + if (!ret) + return -EINVAL; + + if (x > (U64_MAX - y)) { + *ret = 0; + return -EINVAL; + } + + *ret = x + y; + return 0; +} + +static inline int hdd_uint64_minus(uint64_t x, uint64_t y, uint64_t *ret) +{ + if (!ret) + return -EINVAL; + + if (x < y) { + *ret = 0; + return -EINVAL; + } + + *ret = x - y; + return 0; +} + +static inline int32_t hdd_get_hosttime_from_targettime( + struct hdd_adapter *adapter, uint64_t target_time, + uint64_t *host_time) +{ + struct hdd_vdev_tsf *tsf; + int32_t ret = -EINVAL; + int64_t delta32_target; + bool in_cap_state; + int64_t normal_interval_target; + + in_cap_state = hdd_tsf_is_in_cap(adapter); + tsf = &adapter->tsf; + + /* + * To avoid check the lock when it's not capturing tsf + * (the tstamp-pair won't be changed) + */ + if (in_cap_state) + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + + hdd_wlan_restart_tsf_cap(adapter); + /* at present, target_time is only 32bit in fact */ + delta32_target = (int64_t)((target_time & U32_MAX) - + (tsf->last_target_time & U32_MAX)); + + normal_interval_target = WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC * + qdf_do_div(NSEC_PER_SEC, HOST_TO_TARGET_TIME_RATIO); + + if (delta32_target < + (normal_interval_target - OVERFLOW_INDICATOR32)) + delta32_target += OVERFLOW_INDICATOR32; + else if (delta32_target > + (OVERFLOW_INDICATOR32 - normal_interval_target)) + delta32_target -= OVERFLOW_INDICATOR32; + + ret = hdd_64bit_plus(tsf->last_host_time, + HOST_TO_TARGET_TIME_RATIO * delta32_target, + host_time); + + if (in_cap_state) + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + return ret; +} + +static inline int32_t hdd_get_targettime_from_hosttime( + struct hdd_adapter *adapter, uint64_t host_time, + uint64_t *target_time) +{ + struct hdd_vdev_tsf *tsf; + int32_t ret = -EINVAL; + bool in_cap_state; + + if (!adapter || host_time == 0) + return ret; + + tsf = &adapter->tsf; + in_cap_state = hdd_tsf_is_in_cap(adapter); + if (in_cap_state) + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + + if (host_time < tsf->last_host_time) + ret = hdd_uint64_minus(tsf->last_target_time, + qdf_do_div(tsf->last_host_time - + host_time, + HOST_TO_TARGET_TIME_RATIO), + target_time); + else + ret = hdd_uint64_plus(tsf->last_target_time, + qdf_do_div(host_time - + tsf->last_host_time, + HOST_TO_TARGET_TIME_RATIO), + target_time); + + if (in_cap_state) + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + return ret; +} + +/** + * hdd_get_soctime_from_tsf64time() - return get status + * + * @adapter: Adapter pointer + * @tsf64_time: current tsf64time, us + * @soc_time: current soc time(qtime), ns + * + * This function get current soc time from current tsf64 time + * Returun int32_t value to tell get success or fail. + * + * Return: + * 0: success + * other: fail + * + */ +static inline int32_t hdd_get_soctime_from_tsf64time( + struct hdd_adapter *adapter, uint64_t tsf64_time, + uint64_t *soc_time) +{ + struct hdd_vdev_tsf *tsf; + int32_t ret = -EINVAL; + uint64_t delta64_tsf64time; + uint64_t delta64_soctime; + bool in_cap_state; + + in_cap_state = hdd_tsf_is_in_cap(adapter); + tsf = &adapter->tsf; + + /* + * To avoid check the lock when it's not capturing tsf + * (the tstamp-pair won't be changed) + */ + if (in_cap_state) + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + + /* at present, target_time is 64bit (g_tsf64), us*/ + if (tsf64_time > tsf->last_target_global_tsf_time) { + delta64_tsf64time = tsf64_time - + tsf->last_target_global_tsf_time; + delta64_soctime = delta64_tsf64time * NSEC_PER_USEC; + + /* soc_time (ns)*/ + ret = hdd_uint64_plus(tsf->last_tsf_sync_soc_time, + delta64_soctime, soc_time); + } else { + delta64_tsf64time = tsf->last_target_global_tsf_time - + tsf64_time; + delta64_soctime = delta64_tsf64time * NSEC_PER_USEC; + + /* soc_time (ns)*/ + ret = hdd_uint64_minus(tsf->last_tsf_sync_soc_time, + delta64_soctime, soc_time); + } + + if (in_cap_state) + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + return ret; +} + +/** + * hdd_get_tsftime_from_qtime() + * + * @adapter: Adapter pointer + * @qtime: current qtime, us + * @tsf_time: current tsf time(qtime), us + * + * This function determines current tsf time + * using current qtime + * + * Return: 0 for success or non-zero negative failure code + */ +static inline int32_t +hdd_get_tsftime_from_qtime(struct hdd_adapter *adapter, uint64_t qtime, + uint64_t *tsf_time) +{ + struct hdd_vdev_tsf *tsf; + int32_t ret = -EINVAL; + uint64_t delta64_tsf64time, tsf_sync_qtime; + bool in_cap_state; + + in_cap_state = hdd_tsf_is_in_cap(adapter); + tsf = &adapter->tsf; + + /* + * To avoid check the lock when it's not capturing tsf + * (the tstamp-pair won't be changed) + */ + if (in_cap_state) + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + + tsf_sync_qtime = tsf->last_tsf_sync_soc_time; + tsf_sync_qtime = qdf_do_div(tsf_sync_qtime, NSEC_PER_USEC); + + if (qtime > tsf_sync_qtime) { + delta64_tsf64time = qtime - tsf_sync_qtime; + ret = hdd_uint64_plus(tsf->last_target_time, + delta64_tsf64time, tsf_time); + } else { + delta64_tsf64time = tsf_sync_qtime - qtime; + ret = hdd_uint64_minus(tsf->last_target_time, + delta64_tsf64time, tsf_time); + } + + if (in_cap_state) + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + return ret; +} + +QDF_STATUS hdd_get_tsf_time(void *adapter_ctx, uint64_t input_time, + uint64_t *tsf_time) +{ + struct hdd_adapter *adapter; + uint64_t qtime; + + /* Sanity check on inputs */ + if (unlikely((!adapter_ctx) || (!input_time))) { + hdd_err("Invalid param passed"); + return QDF_STATUS_E_FAILURE; + } + + adapter = (struct hdd_adapter *)adapter_ctx; + if (unlikely(adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + hdd_err("Magic cookie(%x) for adapter sanity verification is invalid", + adapter->magic); + return QDF_STATUS_E_FAILURE; + } + + qtime = qdf_log_timestamp_to_usecs(input_time); + hdd_get_tsftime_from_qtime(adapter, qtime, tsf_time); + return QDF_STATUS_SUCCESS; +} + +static void hdd_capture_tsf_timer_expired_handler(void *arg) +{ + uint32_t tsf_op_resp; + struct hdd_adapter *adapter; + + if (!arg) + return; + + adapter = (struct hdd_adapter *)arg; + hdd_capture_tsf_internal(adapter, &tsf_op_resp, 1); +} + +#ifdef WLAN_FEATURE_TSF_ACCURACY +#define WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC 50 +#define WLAN_HDD_TOGGLE_GPIO_BACKOFF_MAX_USEC 200 +#define WLAN_HDD_PULSE_WIDTH_MSEC 1 + +/** + * hdd_get_tsf_accuracy_context() - Return the TSF Accuracy config params + * @adapter: Pointer to adapter + * + * This function validates feature config parameters + * + * Return: Pointer to TSF Accuracy feature configs + */ +static struct wlan_fwol_tsf_accuracy_configs * +hdd_get_tsf_accuracy_context(struct hdd_adapter *adapter) +{ + struct wlan_fwol_tsf_accuracy_configs *configs = NULL; + struct hdd_context *hddctx; + int status; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return NULL; + } + + if (hddctx->tsf.tsf_accuracy_context && + hddctx->tsf.tsf_accuracy_context != adapter) + return NULL; + + status = ucfg_fwol_get_tsf_accuracy_configs(hddctx->psoc, &configs); + if (status == QDF_STATUS_E_FAILURE) + return NULL; + + if (!configs || !configs->enable || + (configs->periodic_pulse_gpio == TSF_GPIO_PIN_INVALID && + configs->sync_gpio == TSF_GPIO_PIN_INVALID)) + return NULL; + + return configs; +} + +/** + * hdd_tsf_gpio_pulse() - Raise pulse of WLAN_HDD_PULSE_WIDTH_MSEC on gpio + * @gpio_num: GPIO number + * + * Return: None + */ +static void hdd_tsf_gpio_pulse(uint32_t gpio_num) +{ + if (gpio_num == TSF_GPIO_PIN_INVALID) + return; + + gpio_set_value(gpio_num, OUTPUT_HIGH); + udelay(WLAN_HDD_PULSE_WIDTH_MSEC * USEC_PER_MSEC); + gpio_set_value(gpio_num, OUTPUT_LOW); +} + +/** + * hdd_tsf_gpio_timer_expired_handler() - Handle periodic TSF periodic expiry + * @arg: Pointer to qdf_hrtimer_data_t + * + * Raise GPIO pulse on TSF time cycle completion and schedules hrtimer for + * next cycle. Also, monitors drift between Host time and TSF time. + * This data will be used for scheduling hrtimer expiry. + * + * Return: + * QDF_HRTIMER_RESTART - On completion of TSF cycle processing + * QDF_HRTIMER_NORESTART - On error + */ +static enum qdf_hrtimer_restart_status +hdd_tsf_gpio_timer_expired_handler(qdf_hrtimer_data_t *arg) +{ + struct hdd_adapter *adapter; + struct hdd_vdev_tsf *tsf; + struct wlan_fwol_tsf_accuracy_configs *configs; + qdf_ktime_t cur_qtime, spin_until, next_ktime; + uint64_t qtime; + uint64_t tsf_time_us; + uint32_t elapsed_time_us; + uint32_t remaining_time_us; + uint32_t delta_interval_us; + + tsf = qdf_container_of(arg, struct hdd_vdev_tsf, + host_trigger_gpio_timer); + if (!tsf) + return QDF_HRTIMER_NORESTART; + + adapter = qdf_container_of(tsf, struct hdd_adapter, tsf); + + configs = hdd_get_tsf_accuracy_context(adapter); + if (!configs) + return QDF_HRTIMER_NORESTART; + + /* Get current System and TSF mapping */ + qtime = qdf_log_timestamp_to_usecs(qdf_get_log_timestamp()); + hdd_get_tsftime_from_qtime(adapter, qtime, &tsf_time_us); + elapsed_time_us = (uint32_t) + (tsf_time_us % (configs->pulse_interval_ms * USEC_PER_MSEC)); + remaining_time_us = + (configs->pulse_interval_ms * USEC_PER_MSEC) - elapsed_time_us; + + /* Skip raising GPIO pulse in case of TSF cycle already completed */ + if (elapsed_time_us < remaining_time_us) { + next_ktime = qdf_ns_to_ktime(NSEC_PER_USEC * + ((configs->pulse_interval_ms * USEC_PER_MSEC) - + WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC - + elapsed_time_us)); + hdd_debug("TSF_Accuracy: skip GPIO pulse tsf_time_us:%llu", + tsf_time_us); + goto end; + } + + if (remaining_time_us > WLAN_HDD_TOGGLE_GPIO_BACKOFF_MAX_USEC) + goto skip; + /* + * Expect WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC seconds of backoff always + * for TSF time to complete a cycle of given interval. + * Hence run backoff busy wait and then trigger GPIO + */ + cur_qtime = qdf_ns_to_ktime(qtime * NSEC_PER_USEC); + spin_until = qdf_ktime_add(cur_qtime, + qdf_ns_to_ktime(remaining_time_us * + NSEC_PER_USEC)); + do { + qtime = qdf_log_timestamp_to_usecs(qdf_get_log_timestamp()); + cur_qtime = qdf_ns_to_ktime(qtime * NSEC_PER_USEC); + } while (ktime_compare(cur_qtime, spin_until) < 0); + + /* Toggle GPIO */ + hdd_tsf_gpio_pulse(configs->periodic_pulse_gpio); + + /* Check current system and TSF mapping for logging */ + hdd_get_tsftime_from_qtime(adapter, qtime, &tsf_time_us); + + hdd_debug("TSF_Accuracy: GPIO toggled log_time_us:%llu, tsf_time_us:%llu, slept_us:%d", + qtime, tsf_time_us, remaining_time_us); + + /* + * Schedule next GPIO toggle by adding to last expiry. Monitor drift + * and adjust next expiry time based on system and TSF clock + * difference. + */ +skip: + if (remaining_time_us > WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC) { + delta_interval_us = remaining_time_us - + WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC; + next_ktime = qdf_ns_to_ktime(NSEC_PER_USEC * + ((configs->pulse_interval_ms * + USEC_PER_MSEC) + + delta_interval_us)); + } else { + next_ktime = configs->pulse_interval_ms; + } +end: + qdf_hrtimer_add_expires(&adapter->tsf.host_trigger_gpio_timer, + next_ktime); + + return QDF_HRTIMER_RESTART; +} + +/** + * hdd_tsf_setup_gpio_toggle() - Schedules hrtimer for TSF periodic processing. + * @adapter: Pointer to adapter + * + * Schedule a TSF time domain periodic pulse handling and also indicate a + * TSF sync done by toggling GPIO. + * + * Return: None + */ +static void hdd_tsf_setup_gpio_toggle(struct hdd_adapter *adapter) +{ + static uint32_t gpio_state = OUTPUT_LOW; + uint64_t tsf_time_us; + uint64_t qtime; + uint32_t elapsed_time_us; + uint32_t remaining_time_us; + qdf_ktime_t cur_ktime, next_ktime; + struct wlan_fwol_tsf_accuracy_configs *configs; + qdf_hrtimer_data_t *gtimer; + + configs = hdd_get_tsf_accuracy_context(adapter); + if (!configs) + return; + + gtimer = &adapter->tsf.host_trigger_gpio_timer; + + /* Get current System and TSF mapping */ + cur_ktime = qdf_ktime_get(); + qtime = qdf_log_timestamp_to_usecs(qdf_get_log_timestamp()); + hdd_get_tsftime_from_qtime(adapter, qtime, &tsf_time_us); + + if (configs->sync_gpio != TSF_GPIO_PIN_INVALID) { + if (gpio_state == OUTPUT_LOW) + gpio_state = OUTPUT_HIGH; + else + gpio_state = OUTPUT_LOW; + gpio_set_value(configs->sync_gpio, gpio_state); + } + + hdd_debug("TSF_Accuracy: TSF sync done system_time_us:%llu, log_time_us:%llu, tsf_time_us:%llu", + qdf_ktime_to_us(cur_ktime), qtime, tsf_time_us); + + /* Start timer if it is not scheduled yet */ + if (!(qdf_hrtimer_is_queued(gtimer) || + qdf_hrtimer_callback_running(gtimer))) { + /* + * Take out WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC as backoff timer + * which is taken care by hrtimer handler + */ + elapsed_time_us = (uint32_t)(tsf_time_us % USEC_PER_SEC); + remaining_time_us = USEC_PER_SEC - elapsed_time_us; + if (remaining_time_us <= WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC) + return; + next_ktime = qdf_ktime_add(cur_ktime, + qdf_ns_to_ktime((remaining_time_us - + WLAN_HDD_TOGGLE_GPIO_BACKOFF_USEC) * NSEC_PER_USEC)); + qdf_hrtimer_start(gtimer, next_ktime, QDF_HRTIMER_MODE_ABS); + } +} + +/** + * hdd_tsf_regular_gpio_pulse_init() - Initialize TSF Accuracy feature + * @adapter: Pointer to adapter + * + * Return: None + */ +static void hdd_tsf_regular_gpio_pulse_init(struct hdd_adapter *adapter) +{ + struct wlan_fwol_tsf_accuracy_configs *configs; + struct hdd_context *hddctx; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return; + } + + configs = hdd_get_tsf_accuracy_context(adapter); + if (!configs) + goto fail; + + qdf_hrtimer_init(&adapter->tsf.host_trigger_gpio_timer, + hdd_tsf_gpio_timer_expired_handler, + QDF_CLOCK_MONOTONIC, QDF_HRTIMER_MODE_ABS, + QDF_CONTEXT_HARDWARE); + + if (configs->periodic_pulse_gpio != TSF_GPIO_PIN_INVALID) { + if (gpio_request(configs->periodic_pulse_gpio, + "tsf_periodic_pulse")) + goto fail; + if (gpio_direction_output(configs->periodic_pulse_gpio, + OUTPUT_LOW)) + goto fail_free_pulse_gpio; + } + + if (configs->sync_gpio != TSF_GPIO_PIN_INVALID) { + if (gpio_request(configs->sync_gpio, "tsf_sync_toggle")) + goto fail_free_pulse_gpio; + if (gpio_direction_output(configs->sync_gpio, OUTPUT_LOW)) + goto fail_free_gpio; + } + + hddctx->tsf.tsf_accuracy_context = adapter; + hdd_debug("TSF_Accuracy: Feature initialization success"); + return; + +fail_free_gpio: + gpio_free(configs->sync_gpio); +fail_free_pulse_gpio: + if (configs->periodic_pulse_gpio != TSF_GPIO_PIN_INVALID) + gpio_free(configs->periodic_pulse_gpio); +fail: + hdd_err("TSF_Accuracy: Feature init failed"); +} + +/** + * hdd_tsf_regular_gpio_pulse_deinit() - Deactivate TSF Accuracy feature + * @adapter: Pointer to adapter + * + * Return: None + */ +static void hdd_tsf_regular_gpio_pulse_deinit(struct hdd_adapter *adapter) +{ + struct wlan_fwol_tsf_accuracy_configs *configs = NULL; + struct hdd_context *hddctx; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return; + } + + if (hddctx->tsf.tsf_accuracy_context != adapter) + return; + + configs = hdd_get_tsf_accuracy_context(adapter); + if (!configs) + return; + + qdf_hrtimer_cancel(&adapter->tsf.host_trigger_gpio_timer); + + if (configs->periodic_pulse_gpio != TSF_GPIO_PIN_INVALID) + gpio_free(configs->periodic_pulse_gpio); + if (configs->sync_gpio != TSF_GPIO_PIN_INVALID) { + gpio_set_value(configs->sync_gpio, OUTPUT_LOW); + gpio_free(configs->sync_gpio); + } + + hddctx->tsf.tsf_accuracy_context = NULL; +} +#else +static void hdd_tsf_setup_gpio_toggle(struct hdd_adapter *adapter) +{ +} + +static void hdd_tsf_regular_gpio_pulse_init(struct hdd_adapter *adapter) +{ +} + +static void hdd_tsf_regular_gpio_pulse_deinit(struct hdd_adapter *adapter) +{ +} +#endif + +#ifndef WLAN_FEATURE_TSF_PLUS_NOIRQ +#if !defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) && \ + !defined(WLAN_FEATURE_TSF_TIMER_SYNC) + +static irqreturn_t hdd_tsf_captured_irq_handler(int irq, void *arg) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + uint64_t host_time; + char *name = NULL; + + if (!arg) + return IRQ_NONE; + + if (irq != tsf_gpio_irq_num) + return IRQ_NONE; + + hdd_ctx = (struct hdd_context *)arg; + host_time = hdd_get_monotonic_host_time(hdd_ctx); + + adapter = hdd_ctx->tsf.cap_tsf_context; + if (!adapter) + return IRQ_HANDLED; + + if (!hdd_tsf_is_initialized(adapter)) { + hdd_err("tsf is not init, ignore irq"); + return IRQ_HANDLED; + } + + hdd_update_timestamp(adapter, 0, host_time); + if (adapter->dev) + name = adapter->dev->name; + + hdd_debug("irq: %d - iface: %s - host_time: %llu", + irq, (!name ? "none" : name), host_time); + + return IRQ_HANDLED; +} +#endif +#endif + +void hdd_capture_req_timer_expired_handler(void *arg) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + struct hdd_vdev_tsf *tsf; + QDF_TIMER_STATE capture_req_timer_status; + qdf_mc_timer_t *sync_timer; + int interval; + int ret; + + if (!arg) + return; + adapter = (struct hdd_adapter *)arg; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) { + hdd_warn("invalid hdd context"); + return; + } + tsf = &adapter->tsf; + if (!hdd_tsf_is_initialized(adapter)) { + hdd_warn("tsf not init"); + return; + } + + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + tsf->cur_host_time = 0; + tsf->cur_target_time = 0; + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + ret = hdd_tsf_reset_gpio(adapter); + if (0 != ret) + hdd_info("reset tsf gpio fail"); + + hdd_ctx->tsf.cap_tsf_context = NULL; + qdf_atomic_set(&hdd_ctx->tsf.cap_tsf_flag, 0); + + sync_timer = &tsf->host_target_sync_timer; + capture_req_timer_status = + qdf_mc_timer_get_current_state(sync_timer); + + if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) { + hdd_warn("invalid timer status"); + return; + } + + interval = WLAN_HDD_CAPTURE_TSF_RESYNC_INTERVAL * MSEC_PER_SEC; + qdf_mc_timer_start(sync_timer, interval); +} + +#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) || \ + defined(WLAN_FEATURE_TSF_TIMER_SYNC) +static void hdd_update_timestamp(struct hdd_adapter *adapter) +{ + int interval = 0; + enum hdd_ts_status sync_status; + struct hdd_vdev_tsf *tsf; + + if (!adapter) + return; + + tsf = &adapter->tsf; + /* on ADREASTEA ach, Qtime is used to sync host and tsf time as a + * intermedia there is no IRQ to sync up TSF-HOST, so host time in ns + * and target in us will be updated at the same time in WMI command + * callback + */ + + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + sync_status = + hdd_check_timestamp_status(tsf->last_target_time, + tsf->last_tsf_sync_soc_time, + tsf->cur_target_time, + tsf->cur_tsf_sync_soc_time, + tsf->host_target_sync_force); + if (tsf->host_target_sync_force) + tsf->host_target_sync_force = false; + + hdd_debug("sync_status %d", sync_status); + switch (sync_status) { + case HDD_TS_STATUS_INVALID: + if (++tsf->continuous_error_count < + MAX_CONTINUOUS_ERROR_CNT) { + interval = + WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS; + tsf->cur_target_time = 0; + tsf->cur_tsf_sync_soc_time = 0; + break; + } + hdd_debug("Reach the max continuous error count"); + + /* If reach MAX_CONTINUOUS_ERROR_CNT, treat it as valid pair */ + fallthrough; + case HDD_TS_STATUS_READY: + tsf->last_target_time = tsf->cur_target_time; + tsf->last_target_global_tsf_time = + tsf->cur_target_global_tsf_time; + tsf->last_tsf_sync_soc_time = + tsf->cur_tsf_sync_soc_time; + tsf->cur_target_time = 0; + tsf->cur_target_global_tsf_time = 0; + tsf->cur_tsf_sync_soc_time = 0; + hdd_debug("ts-pair updated: target: %llu; g_target:%llu, Qtime: %llu", + tsf->last_target_time, + tsf->last_target_global_tsf_time, + tsf->last_tsf_sync_soc_time); + + /* + * TSF-HOST need to be updated in at most + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved + * if the timer interval is also + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or + * schedule delay. So deduct several seconds from + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC. + * Without this change, hdd_get_hosttime_from_targettime() will + * get wrong host time when it's longer than + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last + * TSF-HOST update. + */ + + if (tsf->dynamic_tsf_sync_interval) + interval = tsf->dynamic_tsf_sync_interval; + else + interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC - + CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC; + + tsf->continuous_error_count = 0; + tsf->continuous_cap_retry_count = 0; + hdd_debug("ts-pair updated: interval: %d", + interval); + break; + case HDD_TS_STATUS_WAITING: + interval = 0; + hdd_warn("TS status is waiting due to one or more pair not updated"); + break; + } + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + hdd_tsf_setup_gpio_toggle(adapter); + + if (interval > 0) + qdf_mc_timer_start(&tsf->host_target_sync_timer, + interval); +} + +static ssize_t __hdd_wlan_tsf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + uint64_t tsf_sync_qtime, host_time, reg_qtime, qtime, target_time; + ssize_t size; + uint8_t *mac; + + struct net_device *net_dev = container_of(dev, struct net_device, dev); + + adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) + return scnprintf(buf, PAGE_SIZE, "Invalid device\n"); + + if (!hdd_get_th_sync_status(adapter)) + return scnprintf(buf, PAGE_SIZE, + "TSF sync is not initialized\n"); + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink) && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) + return scnprintf(buf, PAGE_SIZE, "NOT connected\n"); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (!hdd_ctx) + return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n"); + + reg_qtime = qdf_get_log_timestamp(); + host_time = hdd_get_monotonic_host_time(hdd_ctx); + + qtime = qdf_log_timestamp_to_usecs(reg_qtime); + do_div(host_time, NSEC_PER_USEC); + hdd_get_tsftime_from_qtime(adapter, qtime, &target_time); + tsf_sync_qtime = adapter->tsf.last_tsf_sync_soc_time; + do_div(tsf_sync_qtime, NSEC_PER_USEC); + + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + mac = hdd_sta_ctx->conn_info.bssid.bytes; + size = scnprintf(buf, PAGE_SIZE, + "%s%llu %llu " QDF_MAC_ADDR_FMT + " %llu %llu %llu\n", + buf, adapter->tsf.last_target_time, + tsf_sync_qtime, + QDF_MAC_ADDR_REF(mac), + qtime, host_time, target_time); + } else { + mac = adapter->mac_addr.bytes; + size = scnprintf(buf, PAGE_SIZE, + "%s%llu %llu " QDF_MAC_ADDR_FMT + " %llu %llu %llu\n", + buf, adapter->tsf.last_target_time, + tsf_sync_qtime, + QDF_MAC_ADDR_REF(mac), + qtime, host_time, target_time); + } + + return size; +} + +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) +{ + struct hdd_tsf_op_response tsf_op_resp; + + hdd_indicate_tsf_internal(adapter, &tsf_op_resp); + hdd_update_timestamp(adapter); +} +#else +static void hdd_update_timestamp(struct hdd_adapter *adapter, + uint64_t target_time, uint64_t host_time) +{ + int interval = 0; + enum hdd_ts_status sync_status; + struct hdd_vdev_tsf *tsf; + if (!adapter) + return; + tsf = &adapter->tsf; + /* host time is updated in IRQ context, it's always before target time, + * and so no need to try update last_host_time at present; + * since the interval of capturing TSF + * (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC) is long enough, host and target + * time are updated in pairs, and one by one, we can return here to + * avoid requiring spin lock, and to speed up the IRQ processing. + */ + if (host_time > 0) + tsf->cur_host_time = host_time; + + qdf_spin_lock_bh(&tsf->host_target_sync_lock); + if (target_time > 0) + tsf->cur_target_time = target_time; + + sync_status = + hdd_check_timestamp_status(tsf->last_target_time, + tsf->last_host_time, + tsf->cur_target_time, + tsf->cur_host_time, + tsf->host_target_sync_force); + if (tsf->host_target_sync_force) + tsf->host_target_sync_force = false; + + hdd_debug("sync_status %d", sync_status); + switch (sync_status) { + case HDD_TS_STATUS_INVALID: + if (++tsf->continuous_error_count < + MAX_CONTINUOUS_ERROR_CNT) { + interval = + WLAN_HDD_CAPTURE_TSF_INIT_INTERVAL_MS; + tsf->cur_target_time = 0; + tsf->cur_host_time = 0; + break; + } + hdd_warn("Reach the max continuous error count"); + /* + * fall through: + * If reach MAX_CONTINUOUS_ERROR_CNT, treat it as a + * valid pair + */ + case HDD_TS_STATUS_READY: + tsf->last_target_time = tsf->cur_target_time; + tsf->last_host_time = tsf->cur_host_time; + tsf->cur_target_time = 0; + tsf->cur_host_time = 0; + hdd_debug("ts-pair updated: target: %llu; host: %llu", + tsf->last_target_time, + tsf->last_host_time); + + /* + * TSF-HOST need to be updated in at most + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, it couldn't be achieved + * if the timer interval is also + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC, due to processing or + * schedule delay. So deduct several seconds from + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC. + * Without this change, hdd_get_hosttime_from_targettime() will + * get wrong host time when it's longer than + * WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC from last + * TSF-HOST update. + */ + interval = (WLAN_HDD_CAPTURE_TSF_INTERVAL_SEC - + CAP_TSF_TIMER_FIX_SEC) * MSEC_PER_SEC; + if (adapter->device_mode == QDF_SAP_MODE || + adapter->device_mode == QDF_P2P_GO_MODE) { + interval *= WLAN_HDD_SOFTAP_INTERVAL_TIMES; + } + + tsf->continuous_error_count = 0; + tsf->continuous_cap_retry_count = 0; + hdd_debug("ts-pair updated: interval: %d", + interval); + break; + case HDD_TS_STATUS_WAITING: + interval = 0; + hdd_warn("TS status is waiting due to one or more pair not updated"); + + if (!target_time && !host_time) + interval = hdd_wlan_retry_tsf_cap(adapter); + break; + } + qdf_spin_unlock_bh(&tsf->host_target_sync_lock); + + if (interval > 0) + qdf_mc_timer_start(&tsf->host_target_sync_timer, + interval); +} + +static ssize_t __hdd_wlan_tsf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct hdd_station_ctx *hdd_sta_ctx; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + ssize_t size; + uint64_t host_time, target_time; + uint8_t *mac; + + struct net_device *net_dev = container_of(dev, struct net_device, dev); + + adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); + if (adapter->magic != WLAN_HDD_ADAPTER_MAGIC) + return scnprintf(buf, PAGE_SIZE, "Invalid device\n"); + + if (!hdd_get_th_sync_status(adapter)) + return scnprintf(buf, PAGE_SIZE, + "TSF sync is not initialized\n"); + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink) && + (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE)) + return scnprintf(buf, PAGE_SIZE, "NOT connected\n"); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_ctx) + return scnprintf(buf, PAGE_SIZE, "Invalid HDD context\n"); + + host_time = hdd_get_monotonic_host_time(hdd_ctx); + + if (hdd_get_targettime_from_hosttime(adapter, host_time, + &target_time)) { + size = scnprintf(buf, PAGE_SIZE, "Invalid timestamp\n"); + } else { + if (adapter->device_mode == QDF_STA_MODE || + adapter->device_mode == QDF_P2P_CLIENT_MODE) { + mac = hdd_sta_ctx->conn_info.bssid.bytes; + size = scnprintf(buf, PAGE_SIZE, + "%s%llu %llu " QDF_MAC_ADDR_FMT "\n", + buf, target_time, host_time, + QDF_MAC_ADDR_REF(mac)); + } else { + mac = adapter->mac_addr.bytes; + size = scnprintf(buf, PAGE_SIZE, + "%s%llu %llu " QDF_MAC_ADDR_FMT "\n", + buf, target_time, host_time, + QDF_MAC_ADDR_REF(mac)); + } + } + + return size; +} + +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) +{ + struct hdd_tsf_op_response tsf_op_resp; + + hdd_indicate_tsf_internal(adapter, &tsf_op_resp); + hdd_update_timestamp(adapter, tsf, 0); +} +#endif + +static ssize_t hdd_wlan_tsf_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct net_device *net_dev = container_of(dev, struct net_device, dev); + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __hdd_wlan_tsf_show(dev, attr, buf); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +static DEVICE_ATTR(tsf, 0444, hdd_wlan_tsf_show, NULL); + +static enum hdd_tsf_op_result hdd_tsf_sync_init(struct hdd_adapter *adapter) +{ + QDF_STATUS ret; + struct hdd_context *hddctx; + struct net_device *net_dev; + uint64_t host_time, qtime; + + if (!adapter) + return HDD_TSF_OP_FAIL; + + hddctx = WLAN_HDD_GET_CTX(adapter); + if (!hddctx) { + hdd_err("invalid hdd context"); + return HDD_TSF_OP_FAIL; + } + + if (!qdf_atomic_read(&hddctx->tsf.tsf_ready_flag)) { + hdd_err("TSF feature has NOT been initialized"); + return HDD_TSF_OP_FAIL; + } + + if (!adapter->tsf.enable_dynamic_tsf_sync) { + hdd_debug("TSF sync feature not enabled"); + return HDD_TSF_OP_FAIL; + } + + if (hdd_get_th_sync_status(adapter)) { + hdd_err("Host Target sync has been initialized!!"); + return HDD_TSF_OP_SUCC; + } + + qdf_spinlock_create(&adapter->tsf.host_target_sync_lock); + + hdd_reset_timestamps(adapter); + + ret = qdf_mc_timer_init(&adapter->tsf.host_target_sync_timer, + QDF_TIMER_TYPE_SW, + hdd_capture_tsf_timer_expired_handler, + (void *)adapter); + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("Failed to init target timer, ret: %d", ret); + goto fail; + } + + ret = qdf_mc_timer_init(&adapter->tsf.host_capture_req_timer, + QDF_TIMER_TYPE_SW, + hdd_capture_req_timer_expired_handler, + (void *)adapter); + if (ret != QDF_STATUS_SUCCESS) { + hdd_err("Failed to init capture timer, ret: %d", ret); + qdf_mc_timer_destroy(&adapter->tsf.host_target_sync_timer); + goto fail; + } + + hdd_tsf_regular_gpio_pulse_init(adapter); + + net_dev = adapter->dev; + if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) + device_create_file(&net_dev->dev, &dev_attr_tsf); + hdd_set_th_sync_status(adapter, true); + + qtime = qdf_get_log_timestamp(); + host_time = hdd_get_monotonic_host_time(hddctx); + + qtime = qdf_log_timestamp_to_usecs(qtime); + do_div(host_time, NSEC_PER_USEC); + + adapter->delta_qtime = (qtime - host_time) * NSEC_PER_USEC; + + return HDD_TSF_OP_SUCC; +fail: + hdd_set_th_sync_status(adapter, false); + return HDD_TSF_OP_FAIL; +} + +static enum hdd_tsf_op_result hdd_tsf_sync_deinit(struct hdd_adapter *adapter) +{ + QDF_STATUS ret; + struct hdd_context *hddctx; + struct net_device *net_dev; + + if (!adapter) + return HDD_TSF_OP_FAIL; + + if (!hdd_get_th_sync_status(adapter)) + return HDD_TSF_OP_SUCC; + + hdd_set_th_sync_status(adapter, false); + + hdd_tsf_regular_gpio_pulse_deinit(adapter); + + ret = qdf_mc_timer_destroy(&adapter->tsf.host_target_sync_timer); + if (ret != QDF_STATUS_SUCCESS) + hdd_err("Failed to destroy target timer, ret: %d", ret); + + ret = qdf_mc_timer_destroy(&adapter->tsf.host_capture_req_timer); + if (ret != QDF_STATUS_SUCCESS) + hdd_err("Failed to destroy capture timer, ret: %d", ret); + + hddctx = WLAN_HDD_GET_CTX(adapter); + + /* reset the cap_tsf flag and gpio if needed */ + if (hddctx && qdf_atomic_read(&hddctx->tsf.cap_tsf_flag) && + hddctx->tsf.cap_tsf_context == adapter) { + int reset_ret = hdd_tsf_reset_gpio(adapter); + + if (reset_ret) + hdd_err("Failed to reset tsf gpio, ret:%d", + reset_ret); + hddctx->tsf.cap_tsf_context = NULL; + qdf_atomic_set(&hddctx->tsf.cap_tsf_flag, 0); + } + + hdd_reset_timestamps(adapter); + + net_dev = adapter->dev; + if (net_dev && hdd_tsf_is_dbg_fs_set(hddctx)) { + struct device *dev = &net_dev->dev; + + device_remove_file(dev, &dev_attr_tsf); + } + return HDD_TSF_OP_SUCC; +} + +int hdd_start_tsf_sync(struct hdd_adapter *adapter) +{ + enum hdd_tsf_op_result ret; + + if (!adapter) + return -EINVAL; + + ret = hdd_tsf_sync_init(adapter); + if (ret != HDD_TSF_OP_SUCC) + return -EINVAL; + + return (__hdd_start_tsf_sync(adapter) == + HDD_TSF_OP_SUCC) ? 0 : -EINVAL; +} + +void hdd_restart_tsf_sync_post_wlan_resume(struct hdd_adapter *adapter) +{ + QDF_STATUS status; + qdf_mc_timer_t *sync_timer; + + if (!hdd_get_th_sync_status(adapter)) { + hdd_err("Host TSF sync is not initialized!!"); + return; + } + + sync_timer = &adapter->tsf.host_target_sync_timer; + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(sync_timer)) { + status = qdf_mc_timer_stop_sync(sync_timer); + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Couldn't stop Host TSF sync running timer!!"); + return; + } + + adapter->tsf.host_target_sync_force = true; + status = qdf_mc_timer_start(sync_timer, 10); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Host TSF sync timer restart failed"); + + hdd_debug("Host TSF sync timer restarted post wlan resume"); + } +} + +int hdd_stop_tsf_sync(struct hdd_adapter *adapter) +{ + enum hdd_tsf_op_result ret; + + if (!adapter) + return -EINVAL; + + ret = __hdd_stop_tsf_sync(adapter); + if (ret != HDD_TSF_OP_SUCC) + return -EINVAL; + + ret = hdd_tsf_sync_deinit(adapter); + if (ret != HDD_TSF_OP_SUCC) { + hdd_err("Failed to deinit tsf sync, ret: %d", ret); + return -EINVAL; + } + return 0; +} + +static inline int __hdd_capture_tsf(struct hdd_adapter *adapter, + uint32_t *buf, int len) +{ + if (!adapter || !buf) { + hdd_err("invalid pointer"); + return -EINVAL; + } + + if (len != 1) + return -EINVAL; + + buf[0] = TSF_DISABLED_BY_TSFPLUS; + + return 0; +} + +/** + * hdd_handle_tsf_dynamic_start() + * @adapter: Adapter pointer + * @attr: TSF sync interval from NL interface + * + * This function enables TSF sync if capture mode is Dynamic set from ini + * + * Return: 0 for success or non-zero negative failure code + */ +static int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter, + struct nlattr *attr) +{ + struct hdd_context *hdd_ctx; + struct hdd_vdev_tsf *tsf; + uint32_t dynamic_tsf_sync_interval = 0; + + if (!adapter) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (attr) + dynamic_tsf_sync_interval = nla_get_u32(attr); + + tsf = &adapter->tsf; + + if (tsf->enable_dynamic_tsf_sync) { + if (dynamic_tsf_sync_interval == + tsf->dynamic_tsf_sync_interval) { + return -EALREADY; + } + tsf->dynamic_tsf_sync_interval = + dynamic_tsf_sync_interval; + return 0; + } + + tsf->dynamic_tsf_sync_interval = dynamic_tsf_sync_interval; + tsf->enable_dynamic_tsf_sync = true; + if (hdd_tsf_is_time_sync_enabled_cfg(hdd_ctx)) + pld_set_tsf_sync_period(hdd_ctx->parent_dev, + dynamic_tsf_sync_interval); + + return hdd_start_tsf_sync(adapter); +} + +/** + * hdd_handle_tsf_dynamic_stop() + * @adapter: Adapter pointer + * + * This function disable TSF sync if capture mode is Dynamic set from ini + * + * Return: 0 for success or non-zero negative failure code + */ +static int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx; + + if (!adapter) + return -EINVAL; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return -EINVAL; + + if (!adapter->tsf.enable_dynamic_tsf_sync) + return -EALREADY; + + adapter->tsf.enable_dynamic_tsf_sync = false; + adapter->tsf.dynamic_tsf_sync_interval = 0; + if (hdd_tsf_is_time_sync_enabled_cfg(hdd_ctx)) + pld_reset_tsf_sync_period(hdd_ctx->parent_dev); + + return hdd_stop_tsf_sync(adapter); +} + +#if defined(WLAN_FEATURE_TSF_TIMER_SYNC) +static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter, + struct hdd_tsf_op_response + *tsf_op_resp) +{ + if (!adapter || !tsf_op_resp) { + hdd_err("invalid pointer"); + return HDD_TSF_OP_FAIL; + } + + memset(tsf_op_resp, 0, sizeof(*tsf_op_resp)); + if (!hdd_tsf_is_initialized(adapter)) { + tsf_op_resp->status = TSF_NOT_READY; + return HDD_TSF_OP_SUCC; + } + + tsf_op_resp->status = hdd_tsf_check_conn_state(adapter); + if (tsf_op_resp->status != TSF_RETURN) + return HDD_TSF_OP_SUCC; + + if (adapter->tsf.last_target_time == 0) { + hdd_info("TSF value not received"); + tsf_op_resp->status = TSF_NOT_RETURNED_BY_FW; + return HDD_TSF_OP_SUCC; + } + + tsf_op_resp->time = adapter->tsf.last_target_time; + tsf_op_resp->soc_time = adapter->tsf.last_tsf_sync_soc_time; + + return HDD_TSF_OP_SUCC; +} + +#else +static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter, + struct hdd_tsf_op_response + *tsf_op_resp) +{ + if (!adapter || !tsf_op_resp) { + hdd_err("invalid pointer"); + return HDD_TSF_OP_FAIL; + } + + tsf_op_resp->status = TSF_DISABLED_BY_TSFPLUS; + tsf_op_resp->time = 0; + tsf_op_resp->soc_time = 0; + + return HDD_TSF_OP_SUCC; +} +#endif + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +#ifdef CONFIG_HL_SUPPORT +static inline +enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf, + uint64_t target_time) +{ + struct hdd_adapter *adapter; + struct net_device *net_dev = netbuf->dev; + + if (!net_dev) + return HDD_TSF_OP_FAIL; + + adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); + if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC && + hdd_get_th_sync_status(adapter)) { + uint64_t host_time; + int32_t ret = hdd_get_hosttime_from_targettime(adapter, + target_time, &host_time); + if (!ret) { + netbuf->tstamp = ns_to_ktime(host_time); + return HDD_TSF_OP_SUCC; + } + } + + return HDD_TSF_OP_FAIL; +} + +#else +static inline +enum hdd_tsf_op_result hdd_netbuf_timestamp(qdf_nbuf_t netbuf, + uint64_t target_time) +{ + struct hdd_adapter *adapter; + struct net_device *net_dev = netbuf->dev; + struct skb_shared_hwtstamps hwtstamps; + + if (!net_dev) + return HDD_TSF_OP_FAIL; + + adapter = (struct hdd_adapter *)(netdev_priv(net_dev)); + if (adapter && adapter->magic == WLAN_HDD_ADAPTER_MAGIC && + hdd_get_th_sync_status(adapter)) { + uint64_t tsf64_time = target_time; + uint64_t soc_time = 0;/*ns*/ + int32_t ret = hdd_get_soctime_from_tsf64time(adapter, + tsf64_time, &soc_time); + if (!ret) { + /* Adjust delta_qtime to soc_time(Qtime), so that + * System Monotonic time and Qtime are in sync. + */ + if (soc_time > (adapter->delta_qtime)) { + hwtstamps.hwtstamp = + soc_time - (adapter->delta_qtime); + *skb_hwtstamps(netbuf) = hwtstamps; + netbuf->tstamp = ktime_set(0, 0); + return HDD_TSF_OP_SUCC; + } else { + return HDD_TSF_OP_FAIL; + } + } + } + + return HDD_TSF_OP_FAIL; +} +#endif + +/** + * hdd_tx_timestamp() - time stamp TX netbuf + * @status: TX status + * @netbuf: pointer to a TX netbuf + * @target_time: TX time for the netbuf + * + * This function get corresponding host time from target time, + * and time stamp the TX netbuf with this time + * + * Return: Describe the execute result of this routine + */ +static int hdd_tx_timestamp(enum htt_tx_status status, + qdf_nbuf_t netbuf, uint64_t target_time) +{ + struct sock *sk = netbuf->sk; + + if (!sk) + return -EINVAL; + + if ((skb_shinfo(netbuf)->tx_flags & SKBTX_HW_TSTAMP) && + !(skb_shinfo(netbuf)->tx_flags & SKBTX_IN_PROGRESS)) { + struct sock_exterr_skb *serr; + qdf_nbuf_t new_netbuf; + int err; + + if (hdd_netbuf_timestamp(netbuf, target_time) != + HDD_TSF_OP_SUCC) + return -EINVAL; + + new_netbuf = qdf_nbuf_clone(netbuf); + if (!new_netbuf) + return -ENOMEM; + + serr = SKB_EXT_ERR(new_netbuf); + memset(serr, 0, sizeof(*serr)); + + switch (status) { + case htt_tx_status_ok: + serr->ee.ee_errno = ENOMSG; + break; + case htt_tx_status_discard: + serr->ee.ee_errno = ENOBUFS; + break; + case htt_tx_status_no_ack: + serr->ee.ee_errno = EREMOTEIO; + break; + default: + serr->ee.ee_errno = ENOMSG; + break; + } + + hdd_debug("packet status %d, sock ee_errno %d", + status, serr->ee.ee_errno); + + serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; + + err = sock_queue_err_skb(sk, new_netbuf); + if (err) { + qdf_nbuf_free(new_netbuf); + return err; + } + + return 0; + } + return -EINVAL; +} + +int hdd_rx_timestamp(qdf_nbuf_t netbuf, uint64_t target_time) +{ + if (hdd_netbuf_timestamp(netbuf, target_time) == + HDD_TSF_OP_SUCC) + return 0; + + /* reset tstamp when failed */ + netbuf->tstamp = ktime_set(0, 0); + return -EINVAL; +} + +static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx) +{ + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_register_timestamp_callback(hdd_tx_timestamp); +} + +static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx) +{ + if (hdd_tsf_is_tx_set(hdd_ctx)) + ol_deregister_timestamp_callback(); +} +#else +static inline void wlan_hdd_tsf_plus_sock_ts_init(struct hdd_context *hdd_ctx) +{ +} + +static inline void wlan_hdd_tsf_plus_sock_ts_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif /* WLAN_FEATURE_TSF_PLUS_SOCK_TS */ + +#if defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + + wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); + return HDD_TSF_OP_SUCC; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); + return HDD_TSF_OP_SUCC; +} + +#elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_SYNC) +static +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + int ret; + QDF_STATUS status; + uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID; + + status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc, + &tsf_sync_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("tsf gpio irq host pin error"); + goto fail; + } + + if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) { + hdd_err("gpio host pin is invalid"); + goto fail; + } + + ret = gpio_request(tsf_sync_gpio_pin, "wlan_tsf"); + if (ret) { + hdd_err("gpio host pin is invalid"); + goto fail; + } + + ret = gpio_direction_output(tsf_sync_gpio_pin, OUTPUT_LOW); + if (ret) { + hdd_err("gpio host pin is invalid"); + goto fail_free_gpio; + } + + wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); + + return HDD_TSF_OP_SUCC; + +fail_free_gpio: + gpio_free(tsf_sync_gpio_pin); +fail: + return HDD_TSF_OP_FAIL; +} + +static +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t tsf_sync_gpio_pin = TSF_GPIO_PIN_INVALID; + + status = ucfg_fwol_get_tsf_sync_host_gpio_pin(hdd_ctx->psoc, + &tsf_sync_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (tsf_sync_gpio_pin == TSF_GPIO_PIN_INVALID) + return QDF_STATUS_E_INVAL; + + wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); + + gpio_free(tsf_sync_gpio_pin); + return HDD_TSF_OP_SUCC; +} + +#elif defined(WLAN_FEATURE_TSF_PLUS_EXT_GPIO_IRQ) +static +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + int ret; + QDF_STATUS status; + uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID; + + status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc, + &tsf_irq_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("tsf gpio irq host pin error"); + goto fail; + } + + if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) { + hdd_err("gpio host pin is invalid"); + goto fail; + } + + ret = gpio_request(tsf_irq_gpio_pin, "wlan_tsf"); + if (ret) { + hdd_err("gpio host pin is invalid"); + goto fail; + } + + ret = gpio_direction_input(tsf_irq_gpio_pin); + if (ret) { + hdd_err("gpio host pin is invalid"); + goto fail_free_gpio; + } + + tsf_gpio_irq_num = gpio_to_irq(tsf_irq_gpio_pin); + if (tsf_gpio_irq_num < 0) { + hdd_err("fail to get irq: %d", tsf_gpio_irq_num); + goto fail_free_gpio; + } + + ret = request_irq(tsf_gpio_irq_num, hdd_tsf_captured_irq_handler, + IRQF_SHARED | IRQF_TRIGGER_RISING, "wlan_tsf", + hdd_ctx); + + if (ret) { + hdd_err("Failed to register irq handler: %d", ret); + goto fail_free_gpio; + } + + wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); + + return HDD_TSF_OP_SUCC; + +fail_free_gpio: + gpio_free(tsf_irq_gpio_pin); +fail: + tsf_gpio_irq_num = -1; + return HDD_TSF_OP_FAIL; +} + +static +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + uint32_t tsf_irq_gpio_pin = TSF_GPIO_PIN_INVALID; + + status = ucfg_fwol_get_tsf_irq_host_gpio_pin(hdd_ctx->psoc, + &tsf_irq_gpio_pin); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (tsf_irq_gpio_pin == TSF_GPIO_PIN_INVALID) + return QDF_STATUS_E_INVAL; + + wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); + + if (tsf_gpio_irq_num >= 0) { + free_irq(tsf_gpio_irq_num, hdd_ctx); + tsf_gpio_irq_num = -1; + gpio_free(tsf_irq_gpio_pin); + } + + return HDD_TSF_OP_SUCC; +} + +#elif defined(WLAN_FEATURE_TSF_TIMER_SYNC) +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + return HDD_TSF_OP_SUCC; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + return HDD_TSF_OP_SUCC; +} +#else +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + int ret; + + ret = cnss_common_register_tsf_captured_handler( + hdd_ctx->parent_dev, + hdd_tsf_captured_irq_handler, + (void *)hdd_ctx); + if (ret != 0) { + hdd_err("Failed to register irq handler: %d", ret); + return HDD_TSF_OP_FAIL; + } + + wlan_hdd_tsf_plus_sock_ts_init(hdd_ctx); + return HDD_TSF_OP_SUCC; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + int ret; + + wlan_hdd_tsf_plus_sock_ts_deinit(hdd_ctx); + + ret = cnss_common_unregister_tsf_captured_handler( + hdd_ctx->parent_dev, + (void *)hdd_ctx); + if (ret != 0) { + hdd_err("Failed to unregister irq handler, ret:%d", + ret); + ret = HDD_TSF_OP_FAIL; + } + + return HDD_TSF_OP_SUCC; +} +#endif +#else +static inline void hdd_update_tsf(struct hdd_adapter *adapter, uint64_t tsf) +{ +} + +static enum hdd_tsf_op_result __hdd_indicate_tsf(struct hdd_adapter *adapter, + struct hdd_tsf_op_response + *tsf_op_resp) +{ + return hdd_indicate_tsf_internal(adapter, tsf_op_resp); +} + +static inline int __hdd_capture_tsf(struct hdd_adapter *adapter, + uint32_t *buf, int len) +{ + return (hdd_capture_tsf_internal(adapter, buf, len) == + HDD_TSF_OP_SUCC) ? 0 : -EINVAL; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_init(struct hdd_context *hdd_ctx) +{ + return HDD_TSF_OP_SUCC; +} + +static inline +enum hdd_tsf_op_result wlan_hdd_tsf_plus_deinit(struct hdd_context *hdd_ctx) +{ + return HDD_TSF_OP_SUCC; +} + +static inline int hdd_handle_tsf_dynamic_start(struct hdd_adapter *adapter, + struct nlattr *attr) +{ + return -ENOTSUPP; +} + +static inline int hdd_handle_tsf_dynamic_stop(struct hdd_adapter *adapter) +{ + return -ENOTSUPP; +} +#endif /* WLAN_FEATURE_TSF_PLUS */ + +int hdd_capture_tsf(struct hdd_adapter *adapter, uint32_t *buf, int len) +{ + return __hdd_capture_tsf(adapter, buf, len); +} + +int hdd_indicate_tsf(struct hdd_adapter *adapter, + struct hdd_tsf_op_response *tsf_op_resp) +{ + if (__hdd_indicate_tsf(adapter, tsf_op_resp) == HDD_TSF_OP_FAIL) + return -EINVAL; + + switch (tsf_op_resp->status) { + case TSF_RETURN: + return 0; + case TSF_NOT_RETURNED_BY_FW: + return -EINPROGRESS; + case TSF_STA_NOT_CONNECTED_NO_TSF: + case TSF_SAP_NOT_STARTED_NO_TSF: + return -EPERM; + default: + return -EINVAL; + } +} + +#ifdef WLAN_FEATURE_TSF_PTP +int wlan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) + +{ + struct hdd_adapter *adapter = netdev_priv(dev); + struct osif_vdev_sync *vdev_sync; + struct hdd_context *hdd_ctx; + int errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return -EAGAIN; + + info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + if (hdd_ctx->tsf.ptp_clock) + info->phc_index = ptp_clock_index(hdd_ctx->tsf.ptp_clock); + else + info->phc_index = -1; + + osif_vdev_sync_op_stop(vdev_sync); + return 0; +} + +#if (KERNEL_VERSION(4, 1, 0) > LINUX_VERSION_CODE) +/** + * wlan_ptp_gettime() - return fw ts info to uplayer + * @ptp: pointer to ptp_clock_info. + * @ts: pointer to timespec. + * + * Return: Describe the execute result of this routine + */ +static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + uint64_t host_time, target_time = 0; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct osif_psoc_sync *psoc_sync; + int errno, status = 0; + + hdd_ctx = = cds_get_context(QDF_MODULE_ID_HDD); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return -EAGAIN; + + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!adapter) + adapter = hdd_get_adapter(hdd_ctx, + QDF_STA_MODE); + if (!adapter) { + status = -EOPNOTSUPP; + goto end; + } + } + } + + host_time = hdd_get_monotonic_host_time(hdd_ctx); + if (hdd_get_targettime_from_hosttime(adapter, host_time, + &target_time)) { + hdd_err("get invalid target timestamp"); + status = -EINVAL; + goto end; + } + *ts = ns_to_timespec(target_time * NSEC_PER_USEC); + +end: + osif_psoc_sync_op_stop(psoc_sync); + return status; +} + +/** + * wlan_hdd_phc_init() - phc init + * @hdd_ctx: pointer to the hdd_context. + * + * Return: NULL + */ +static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) +{ + hdd_ctx->tsf.ptp_cinfo.gettime = wlan_ptp_gettime; + + hdd_ctx->tsf.ptp_clock = ptp_clock_register(&hdd_ctx->tsf.ptp_cinfo, + hdd_ctx->parent_dev); +} + +/** + * wlan_hdd_phc_deinit() - phc deinit + * @hdd_ctx: pointer to the hdd_context. + * + * Return: NULL + */ +static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) +{ + hdd_ctx->tsf.ptp_cinfo.gettime = NULL; + + if (hdd_ctx->tsf.ptp_clock) { + ptp_clock_unregister(hdd_ctx->tsf.ptp_clock); + hdd_ctx->tsf.ptp_clock = NULL; + } +} + +#else +static int wlan_ptp_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts) +{ + uint64_t host_time, target_time = 0; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter; + struct osif_psoc_sync *psoc_sync; + int errno, status = 0; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return -EINVAL; + + errno = osif_psoc_sync_op_start(hdd_ctx->parent_dev, &psoc_sync); + if (errno) + return -EAGAIN; + + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_GO_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_P2P_CLIENT_MODE); + if (!adapter) { + adapter = hdd_get_adapter(hdd_ctx, QDF_SAP_MODE); + if (!adapter) + adapter = hdd_get_adapter(hdd_ctx, + QDF_STA_MODE); + if (!adapter) { + status = -EOPNOTSUPP; + goto end; + } + } + } + + host_time = hdd_get_monotonic_host_time(hdd_ctx); + if (hdd_get_targettime_from_hosttime(adapter, host_time, + &target_time)) { + hdd_err("get invalid target timestamp"); + status = -EINVAL; + goto end; + } + *ts = ns_to_timespec64(target_time * NSEC_PER_USEC); + +end: + osif_psoc_sync_op_stop(psoc_sync); + return status; +} + +static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) +{ + hdd_ctx->tsf.ptp_cinfo.gettime64 = wlan_ptp_gettime; + hdd_ctx->tsf.ptp_clock = ptp_clock_register(&hdd_ctx->tsf.ptp_cinfo, + hdd_ctx->parent_dev); +} + +static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) +{ + hdd_ctx->tsf.ptp_cinfo.gettime64 = NULL; + + if (hdd_ctx->tsf.ptp_clock) { + ptp_clock_unregister(hdd_ctx->tsf.ptp_clock); + hdd_ctx->tsf.ptp_clock = NULL; + } +} + +#endif +#else + +static void wlan_hdd_phc_init(struct hdd_context *hdd_ctx) +{ +} + +static void wlan_hdd_phc_deinit(struct hdd_context *hdd_ctx) +{ +} +#endif /* WLAN_FEATURE_TSF_PTP */ + +#ifdef WLAN_FEATURE_TSF_AUTO_REPORT +void hdd_tsf_auto_report_init(struct hdd_adapter *adapter) +{ + adapter->tsf.auto_rpt_src = 0; +} + +int +hdd_set_tsf_auto_report(struct hdd_adapter *adapter, bool ena, + enum hdd_tsf_auto_rpt_source source) +{ + int ret = 0; + bool enabled; + + enabled = !!adapter->tsf.auto_rpt_src; + if (enabled == ena) { + hdd_debug_rl("source %d current %d and no action is required", + source, enabled); + goto set_src; + } + + ret = wma_cli_set_command((int)adapter->deflink->vdev_id, + ena ? (int)GEN_PARAM_TSF_AUTO_REPORT_ENABLE : + (int)GEN_PARAM_TSF_AUTO_REPORT_DISABLE, + ena, GEN_CMD); + if (ret) { + hdd_err_rl("source %d enable %d failed: %d", source, ena, ret); + ret = -EINPROGRESS; + goto out; + } + +set_src: + if (ena) + qdf_atomic_set_bit(source, &adapter->tsf.auto_rpt_src); + else + qdf_atomic_clear_bit(source, &adapter->tsf.auto_rpt_src); + +out: + return ret; +} + +/** + * hdd_tsf_auto_report_enabled() - get current state of tsf auto report + * for an adapter + * @adapter: pointer to Adapter context + * + * Return: true for enabled, false for disabled + */ +static inline bool hdd_tsf_auto_report_enabled(struct hdd_adapter *adapter) +{ + return !!adapter->tsf.auto_rpt_src; +} + +/** + * hdd_set_delta_tsf() - calculate and save the time difference between + * TQM clock and TSF clock + * @adapter: pointer to Adapter context + * @ptsf: pointer to tsf information + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter, + struct stsf *ptsf) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t delta_tsf; + + /* A tsf report event with mac_id_valid equals to 1 represents + * for tsf auto report, that's what we need to handle in this + * function; otherwise, return failure here so that legacy BSS + * TSF logic can be continued. + */ + if (!ptsf->mac_id_valid) { + hdd_debug_rl("Not TSF auto report"); + return QDF_STATUS_E_FAILURE; + } + + if (!hdd_tsf_auto_report_enabled(adapter)) { + hdd_debug_rl("adapter %u tsf_auto_report disabled", + adapter->deflink->vdev_id); + goto exit_with_success; + } + + delta_tsf = ptsf->tsf_low - ptsf->soc_timer_low; + hdd_debug("vdev %u tsf_low %u qtimer_low %u delta_tsf %u", + ptsf->vdev_id, ptsf->tsf_low, ptsf->soc_timer_low, delta_tsf); + + /* Pass delta_tsf to DP layer to calculate hw delay + * on a per vdev basis + */ + cdp_set_delta_tsf(soc, adapter->deflink->vdev_id, delta_tsf); + +exit_with_success: + return QDF_STATUS_SUCCESS; +} +#else /* !WLAN_FEATURE_TSF_AUTO_REPORT */ +static inline QDF_STATUS hdd_set_delta_tsf(struct hdd_adapter *adapter, + struct stsf *ptsf) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool hdd_tsf_auto_report_enabled(struct hdd_adapter *adapter) +{ + return false; +} +#endif /* WLAN_FEATURE_TSF_AUTO_REPORT */ + +#ifdef WLAN_FEATURE_TSF_UPLINK_DELAY +/** + * hdd_set_tsf_ul_delay_report() - enable or disable tsf uplink delay report + * for an adapter + * @adapter: pointer to Adapter context + * @ena: requesting state (true or false) + * + * Return: 0 for success or non-zero negative failure code + */ +static int +hdd_set_tsf_ul_delay_report(struct hdd_adapter *adapter, bool ena) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + + status = cdp_set_tsf_ul_delay_report(soc, + adapter->deflink->vdev_id, + ena); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Set tsf report uplink delay failed"); + return -EPERM; + } + + return 0; +} + +uint32_t hdd_get_uplink_delay_len(struct hdd_adapter *adapter) +{ + if (adapter->device_mode != QDF_STA_MODE) + return 0; + + return nla_total_size(sizeof(uint32_t)); +} + +QDF_STATUS hdd_add_uplink_delay(struct hdd_adapter *adapter, + struct sk_buff *skb) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + uint32_t ul_delay; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) + return QDF_STATUS_SUCCESS; + + if (hdd_tsf_auto_report_enabled(adapter)) { + status = cdp_get_uplink_delay(soc, adapter->deflink->vdev_id, + &ul_delay); + if (QDF_IS_STATUS_ERROR(status)) + ul_delay = 0; + } else { + ul_delay = 0; + } + + if (nla_put_u32(skb, QCA_WLAN_VENDOR_ATTR_GET_STA_INFO_UPLINK_DELAY, + ul_delay)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#else +static inline int +hdd_set_tsf_ul_delay_report(struct hdd_adapter *adapter, bool ena) +{ + return -ENOTSUPP; +} +#endif /* WLAN_FEATURE_TSF_UPLINK_DELAY */ + +/** + * hdd_get_tsf_cb() - handle tsf callback + * @pcb_cxt: pointer to the hdd_contex + * @ptsf: pointer to struct stsf + * + * This function handle the event that reported by firmware at first. + * The event contains the vdev_id, current tsf value of this vdev, + * tsf value is 64bits, discripted in two variable tsf_low and tsf_high. + * These two values each is uint32. + * + * Return: 0 for success or non-zero negative failure code + */ +int hdd_get_tsf_cb(void *pcb_cxt, struct stsf *ptsf) +{ + struct hdd_context *hddctx; + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + int ret; + uint64_t tsf_sync_soc_time; + QDF_TIMER_STATE capture_req_timer_status; + qdf_mc_timer_t *capture_timer; + struct hdd_vdev_tsf *tsf; + + if (!pcb_cxt || !ptsf) { + hdd_err("HDD context is not valid"); + return -EINVAL; + } + + hddctx = (struct hdd_context *)pcb_cxt; + ret = wlan_hdd_validate_context(hddctx); + if (0 != ret) + return -EINVAL; + + link_info = hdd_get_link_info_by_vdev(hddctx, ptsf->vdev_id); + if (!link_info) { + hdd_err("failed to find adapter"); + return -EINVAL; + } + + adapter = link_info->adapter; + /* Intercept tsf report and check if it is for auto report. + * If yes, return in advance and skip the legacy BSS TSF + * report. Otherwise continue on to the legacy BSS TSF + * report logic. + */ + if (QDF_IS_STATUS_SUCCESS(hdd_set_delta_tsf(adapter, ptsf))) + return 0; + + if (!hdd_tsf_is_initialized(adapter)) { + hdd_err("tsf is not init, ignore tsf event"); + return -EINVAL; + } + + hdd_debug("tsf cb handle event, device_mode is %d", + adapter->device_mode); + + wlan_hdd_tsf_reg_update_details(adapter, ptsf); + + tsf = &adapter->tsf; + capture_timer = &tsf->host_capture_req_timer; + capture_req_timer_status = + qdf_mc_timer_get_current_state(capture_timer); + if (capture_req_timer_status == QDF_TIMER_STATE_UNUSED) { + hdd_warn("invalid timer status"); + return -EINVAL; + } + + qdf_mc_timer_stop(capture_timer); + tsf->cur_target_time = ((uint64_t)ptsf->tsf_high << 32 | + ptsf->tsf_low); + + tsf->cur_target_global_tsf_time = + ((uint64_t)ptsf->global_tsf_high << 32 | + ptsf->global_tsf_low); + tsf_sync_soc_time = ((uint64_t)ptsf->soc_timer_high << 32 | + ptsf->soc_timer_low); + tsf->cur_tsf_sync_soc_time = + hdd_convert_qtime_to_us(tsf_sync_soc_time) * NSEC_PER_USEC; + + qdf_event_set(&tsf_sync_get_completion_evt); + hdd_update_tsf(adapter, tsf->cur_target_time); + hdd_debug("Vdev=%u, tsf_low=%u, tsf_high=%u ptsf->soc_timer_low=%u ptsf->soc_timer_high=%u", + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high, + ptsf->soc_timer_low, ptsf->soc_timer_high); + return 0; +} + +const struct nla_policy tsf_policy[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TSF_CMD] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL] = {.type = NLA_U32}, +}; + +/** + * __wlan_hdd_cfg80211_handle_tsf_cmd(): Setup TSF operations + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Handle TSF SET / GET operation from userspace + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_MAX + 1]; + struct hdd_tsf_op_response tsf_op_resp; + struct nlattr *attr; + enum hdd_tsf_get_state value; + int status; + QDF_STATUS ret; + struct sk_buff *reply_skb; + uint32_t tsf_cmd; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_TSF_INDEX; + bool enable_auto_rpt; + enum hdd_tsf_auto_rpt_source source = + HDD_TSF_AUTO_RPT_SOURCE_UPLINK_DELAY; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + status = wlan_hdd_validate_context(hdd_ctx); + if (0 != status) + return -EINVAL; + + if (wlan_cfg80211_nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_TSF_MAX, + data, data_len, tsf_policy)) { + hdd_err("Invalid TSF cmd"); + return -EINVAL; + } + + if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]) { + hdd_err("Invalid TSF cmd"); + return -EINVAL; + } + tsf_cmd = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_CMD]); + + /* Intercept tsf_cmd for TSF auto report enable or disable subcmds, + * and treat as trigger for uplink delay report. + */ + if (tsf_cmd == QCA_TSF_AUTO_REPORT_DISABLE || + tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE) { + enable_auto_rpt = (tsf_cmd == QCA_TSF_AUTO_REPORT_ENABLE); + status = hdd_set_tsf_auto_report(adapter, + enable_auto_rpt, + source); + if (status) + goto end; + + hdd_set_tsf_ul_delay_report(adapter, enable_auto_rpt); + goto end; + } + + ret = qdf_event_reset(&tsf_sync_get_completion_evt); + if (QDF_IS_STATUS_ERROR(ret)) + hdd_warn("failed to reset tsf_sync_get_completion_evt"); + + if (tsf_cmd == QCA_TSF_CAPTURE || tsf_cmd == QCA_TSF_SYNC_GET) { + hdd_capture_tsf(adapter, &value, 1); + switch (value) { + case TSF_RETURN: + status = 0; + break; + case TSF_CURRENT_IN_CAP_STATE: + status = -EALREADY; + break; + case TSF_STA_NOT_CONNECTED_NO_TSF: + case TSF_SAP_NOT_STARTED_NO_TSF: + status = -EPERM; + break; + default: + case TSF_CAPTURE_FAIL: + status = -EINVAL; + break; + } + } else if (tsf_cmd == QCA_TSF_SYNC_START) { + attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_TSF_SYNC_INTERVAL]; + status = hdd_handle_tsf_dynamic_start(adapter, attr); + } else if (tsf_cmd == QCA_TSF_SYNC_STOP) { + status = hdd_handle_tsf_dynamic_stop(adapter); + } else { + status = 0; + } + + if (status < 0) + goto end; + + if (tsf_cmd == QCA_TSF_SYNC_GET) { + ret = qdf_wait_single_event(&tsf_sync_get_completion_evt, + WLAN_TSF_SYNC_GET_TIMEOUT); + if (QDF_IS_STATUS_ERROR(ret)) { + status = -ETIMEDOUT; + goto end; + } + } + + if (tsf_cmd == QCA_TSF_GET || tsf_cmd == QCA_TSF_SYNC_GET) { + status = hdd_indicate_tsf(adapter, &tsf_op_resp); + if (status != 0) + goto end; + + reply_skb = + wlan_cfg80211_vendor_event_alloc(hdd_ctx->wiphy, NULL, + sizeof(uint64_t) * 2 + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!reply_skb) { + hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + status = -ENOMEM; + goto end; + } + if (hdd_wlan_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TSF_TIMER_VALUE, + tsf_op_resp.time) || + hdd_wlan_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TSF_SOC_TIMER_VALUE, + tsf_op_resp.soc_time)) { + hdd_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(reply_skb); + status = -EINVAL; + goto end; + } + status = wlan_cfg80211_vendor_cmd_reply(reply_skb); + } + +end: + hdd_info("TSF operation %d status: %d", tsf_cmd, status); + return status; +} + +int wlan_hdd_cfg80211_handle_tsf_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_handle_tsf_cmd(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * wlan_hdd_tsf_init() - set callback to handle tsf value. + * @hdd_ctx: pointer to the struct hdd_context + * + * This function set the callback to sme module, the callback will be + * called when a tsf event is reported by firmware + * + * Return: none + */ +void wlan_hdd_tsf_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!hdd_ctx) + return; + + if (qdf_atomic_inc_return(&hdd_ctx->tsf.tsf_ready_flag) > 1) { + hdd_err("TSF ready flag already set"); + return; + } + + qdf_atomic_init(&hdd_ctx->tsf.cap_tsf_flag); + + status = qdf_event_create(&tsf_sync_get_completion_evt); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to create tsf_sync_get_completion_evt"); + goto fail; + } + + status = hdd_tsf_set_gpio(hdd_ctx); + + if (QDF_STATUS_SUCCESS != status) { + hdd_err("set tsf GPIO failed, status: %d", status); + goto fail; + } + + if (wlan_hdd_tsf_plus_init(hdd_ctx) != HDD_TSF_OP_SUCC) { + hdd_err("TSF plus init failed"); + goto fail; + } + + if (hdd_tsf_is_ptp_enabled(hdd_ctx)) + wlan_hdd_phc_init(hdd_ctx); + + return; + +fail: + qdf_atomic_set(&hdd_ctx->tsf.tsf_ready_flag, 0); +} + +void wlan_hdd_tsf_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + if (!hdd_ctx) + return; + + status = qdf_event_destroy(&tsf_sync_get_completion_evt); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("failed to destroy tsf_sync_get_completion_evt"); + + if (!qdf_atomic_read(&hdd_ctx->tsf.tsf_ready_flag)) { + hdd_err("ready flag not set"); + return; + } + + if (hdd_tsf_is_ptp_enabled(hdd_ctx)) + wlan_hdd_phc_deinit(hdd_ctx); + wlan_hdd_tsf_plus_deinit(hdd_ctx); + qdf_atomic_set(&hdd_ctx->tsf.tsf_ready_flag, 0); + qdf_atomic_set(&hdd_ctx->tsf.cap_tsf_flag, 0); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c new file mode 100644 index 0000000000..01e4c30a18 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_twt.c @@ -0,0 +1,5078 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_twt.c + * + * WLAN Host Device Driver file for TWT (Target Wake Time) support. + * + */ + +#include "wmi.h" +#include "wmi_unified_priv.h" +#include "wmi_unified_twt_param.h" +#include "wlan_hdd_twt.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_cfg.h" +#include "wlan_hdd_hostapd.h" +#include "sme_api.h" +#include "wma_twt.h" +#include "osif_sync.h" +#include "wlan_osif_request_manager.h" +#include "cfg_ucfg_api.h" +#include +#include +#include +#include "wlan_hdd_object_manager.h" +#include "osif_twt_ext_req.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_twt_ucfg_ext_api.h" +#include "wlan_twt_ucfg_ext_cfg.h" +#include "osif_twt_internal.h" + +const struct nla_policy +wlan_hdd_wifi_twt_config_policy[ + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION] = { + .type = NLA_U8}, + [QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS] = { + .type = NLA_NESTED}, +}; + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return ucfg_twt_cfg_get_requestor(psoc, val); +} + +QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return ucfg_twt_cfg_get_responder(psoc, val); +} + +void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + ucfg_twt_update_psoc_config(hdd_ctx->psoc); +} + +QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + + osif_twt_send_responder_enable_cmd(hdd_ctx->psoc, pdev_id); + return QDF_STATUS_SUCCESS; +} + +void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx) +{ + if (wlan_hdd_is_twt_pmo_allowed(hdd_ctx)) + qdf_sched_work(0, &hdd_ctx->twt_en_dis_work); +} + +void hdd_twt_update_work_handler(void *data) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)data; + struct osif_psoc_sync *psoc_sync; + int ret; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + if (ret) + return; + + osif_twt_concurrency_update_handler(hdd_ctx->psoc, hdd_ctx->pdev); + + osif_psoc_sync_op_stop(psoc_sync); +} + +QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + + osif_twt_send_requestor_enable_cmd(hdd_ctx->psoc, pdev_id); + return QDF_STATUS_SUCCESS; +} + +void hdd_twt_del_dialog_in_ps_disable(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id) +{ + return osif_twt_teardown_in_ps_disable(hdd_ctx->psoc, mac_addr, + vdev_id); +} + +void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx, + enum twt_role role) +{ + uint32_t reason; + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + + reason = HOST_TWT_DISABLE_REASON_NONE; + osif_twt_send_responder_disable_cmd(hdd_ctx->psoc, pdev_id, reason); +} + +int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return 0; +} + +void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ + qdf_flush_work(&hdd_ctx->twt_en_dis_work); + qdf_destroy_work(NULL, &hdd_ctx->twt_en_dis_work); +} + +void +hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info *link_info) +{ +} + +int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + return 0; +} + +QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + + osif_twt_send_responder_disable_cmd(hdd_ctx->psoc, pdev_id, reason); + return QDF_STATUS_SUCCESS; +} + +void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ + osif_twt_send_requestor_enable_cmd(hdd_ctx->psoc, 0); + qdf_create_work(0, &hdd_ctx->twt_en_dis_work, + hdd_twt_update_work_handler, hdd_ctx); +} + +/** + * hdd_twt_terminate_session - Process TWT terminate + * operation in the received vendor command and + * send it to firmware + * @adapter: adapter pointer + * @vdev: associated vdev object + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_TERMINATE + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_terminate_session(struct hdd_adapter *adapter, + struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + enum QDF_OPMODE device_mode = adapter->device_mode; + + switch (device_mode) { + case QDF_STA_MODE: + return osif_twt_sta_teardown_req(vdev, twt_param_attr); + case QDF_SAP_MODE: + return osif_twt_sap_teardown_req(vdev, twt_param_attr); + default: + hdd_err_rl("TWT terminate is not supported on %s", + qdf_opmode_str(adapter->device_mode)); + return -EOPNOTSUPP; + } +} + +static int hdd_twt_configure(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + enum qca_wlan_twt_operation twt_oper; + struct nlattr *twt_oper_attr; + struct nlattr *twt_param_attr; + uint32_t id; + int ret = 0; + struct wlan_objmgr_vdev *vdev; + + id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION; + twt_oper_attr = tb[id]; + + if (!twt_oper_attr) { + hdd_err("TWT operation NOT specified"); + return -EINVAL; + } + + twt_oper = nla_get_u8(twt_oper_attr); + + id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS; + twt_param_attr = tb[id]; + + if (!twt_param_attr && + twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES && + twt_oper != QCA_WLAN_TWT_SUSPEND) { + hdd_err("TWT parameters NOT specified"); + return -EINVAL; + } + + hdd_debug("TWT Operation 0x%x", twt_oper); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_TWT_ID); + if (!vdev) { + hdd_err("vdev is NULL"); + return -EINVAL; + } + + switch (twt_oper) { + case QCA_WLAN_TWT_SET: + ret = osif_twt_setup_req(vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_GET: + ret = osif_twt_get_session_req(vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_TERMINATE: + ret = hdd_twt_terminate_session(adapter, vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_SUSPEND: + ret = osif_twt_pause_req(vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_RESUME: + ret = osif_twt_resume_req(vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_NUDGE: + ret = osif_twt_nudge_req(vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_GET_CAPABILITIES: + ret = osif_twt_get_capabilities(vdev); + break; + case QCA_WLAN_TWT_GET_STATS: + ret = osif_twt_get_session_traffic_stats(vdev, twt_param_attr); + break; + case QCA_WLAN_TWT_CLEAR_STATS: + ret = osif_twt_clear_session_traffic_stats(vdev, + twt_param_attr); + break; + case QCA_WLAN_TWT_SET_PARAM: + ret = osif_twt_set_param(vdev, twt_param_attr); + break; + default: + hdd_err("Invalid TWT Operation"); + ret = -EINVAL; + break; + } + + hdd_objmgr_put_vdev_by_user(vdev, WLAN_TWT_ID); + return ret; +} +#elif defined(WLAN_SUPPORT_TWT) + +#define TWT_DISABLE_COMPLETE_TIMEOUT 1000 +#define TWT_ENABLE_COMPLETE_TIMEOUT 1000 +#define TWT_ACK_COMPLETE_TIMEOUT 1000 +#define TWT_WORK_RESCHED_WAIT_TIME 30 + +#define TWT_FLOW_TYPE_ANNOUNCED 0 +#define TWT_FLOW_TYPE_UNANNOUNCED 1 + +#define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX 0xFFFF +#define TWT_SETUP_WAKE_DURATION_MAX 0xFFFF +#define TWT_SETUP_WAKE_INTVL_EXP_MAX 31 +#define TWT_WAKE_INTVL_MULTIPLICATION_FACTOR 1024 +#define TWT_WAKE_DURATION_MULTIPLICATION_FACTOR 256 +#define TWT_MAX_NEXT_TWT_SIZE 3 + +static const struct nla_policy +qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF] = {.type = NLA_U64 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT] = {.type = NLA_U32 }, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 }, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 }, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_set_param_policy[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE] = {.type = NLA_U8 }, +}; + +static +int hdd_send_twt_del_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_del_dialog_param *twt_params); + +/** + * hdd_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd + * @req_type: twt setup request type + * @twt_cmd: pointer to store twt command + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_setup_req_type_to_cmd(u8 req_type, enum WMI_HOST_TWT_COMMAND *twt_cmd) +{ + if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST) { + *twt_cmd = WMI_HOST_TWT_COMMAND_REQUEST_TWT; + } else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST) { + *twt_cmd = WMI_HOST_TWT_COMMAND_SUGGEST_TWT; + } else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND) { + *twt_cmd = WMI_HOST_TWT_COMMAND_DEMAND_TWT; + } else { + hdd_err_rl("Invalid TWT_SETUP_REQ_TYPE %d", req_type); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_get_add_dialog_values() - Get TWT add dialog parameter + * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS + * @tb: nl attributes + * @params: wmi twt add dialog parameters + * + * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + * + * Return: 0 or -EINVAL. + */ +static +int hdd_twt_get_add_dialog_values(struct nlattr **tb, + struct wmi_twt_add_dialog_param *params) +{ + uint32_t wake_intvl_exp, result; + int cmd_id; + QDF_STATUS qdf_status; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[cmd_id]) { + params->dialog_id = nla_get_u8(tb[cmd_id]); + if (params->dialog_id > TWT_MAX_DIALOG_ID) { + hdd_err_rl("Flow id (%u) invalid", params->dialog_id); + return -EINVAL; + } + } else { + params->dialog_id = 0; + hdd_debug("TWT_SETUP_FLOW_ID not specified. set to zero"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (!tb[cmd_id]) { + hdd_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must"); + return -EINVAL; + } + wake_intvl_exp = nla_get_u8(tb[cmd_id]); + if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) { + hdd_err_rl("Invalid wake_intvl_exp %u > %u", + wake_intvl_exp, + TWT_SETUP_WAKE_INTVL_EXP_MAX); + return -EINVAL; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + params->flag_bcast = nla_get_flag(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID; + if (tb[cmd_id]) { + params->dialog_id = nla_get_u8(tb[cmd_id]); + hdd_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION; + if (tb[cmd_id]) { + params->b_twt_recommendation = nla_get_u8(tb[cmd_id]); + hdd_debug("TWT_SETUP_BCAST_RECOMM %d", + params->b_twt_recommendation); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE; + if (tb[cmd_id]) { + params->b_twt_persistence = nla_get_u8(tb[cmd_id]); + hdd_debug("TWT_SETUP_BCAST_PERSIS %d", + params->b_twt_persistence); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE; + if (!tb[cmd_id]) { + hdd_err_rl("TWT_SETUP_REQ_TYPE is must"); + return -EINVAL; + } + qdf_status = hdd_twt_setup_req_type_to_cmd(nla_get_u8(tb[cmd_id]), + ¶ms->twt_cmd); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status_to_os_return(qdf_status); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + params->flag_trigger = nla_get_flag(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (!tb[cmd_id]) { + hdd_err_rl("TWT_SETUP_FLOW_TYPE is must"); + return -EINVAL; + } + params->flag_flow_type = nla_get_u8(tb[cmd_id]); + if (params->flag_flow_type != TWT_FLOW_TYPE_ANNOUNCED && + params->flag_flow_type != TWT_FLOW_TYPE_UNANNOUNCED) + return -EINVAL; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + params->flag_protection = nla_get_flag(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME; + if (tb[cmd_id]) + params->sp_offset_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + if (!tb[cmd_id]) { + hdd_err_rl("TWT_SETUP_WAKE_DURATION is must"); + return -EINVAL; + } + params->wake_dura_us = TWT_WAKE_DURATION_MULTIPLICATION_FACTOR * + nla_get_u32(tb[cmd_id]); + if (params->wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) { + hdd_err_rl("Invalid wake_dura_us %u", + params->wake_dura_us); + return -EINVAL; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION; + if (tb[cmd_id]) + params->min_wake_dura_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION; + if (tb[cmd_id]) + params->max_wake_dura_us = nla_get_u32(tb[cmd_id]); + + if (params->min_wake_dura_us > params->max_wake_dura_us) { + hdd_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero", + params->min_wake_dura_us, params->max_wake_dura_us); + params->min_wake_dura_us = 0; + params->max_wake_dura_us = 0; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (!tb[cmd_id]) { + hdd_err_rl("SETUP_WAKE_INTVL_MANTISSA is must"); + return -EINVAL; + } + params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]); + + /* + * If mantissa in microsecond is present then take precedence over + * mantissa in TU. And send mantissa in microsecond to firmware. + */ + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA; + if (tb[cmd_id]) { + params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]); + } + + if (params->wake_intvl_mantis > + TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) { + hdd_err_rl("Invalid wake_intvl_mantis %u", + params->wake_intvl_mantis); + return -EINVAL; + } + + if (wake_intvl_exp && params->wake_intvl_mantis) { + result = 2 << (wake_intvl_exp - 1); + if (result > + (UINT_MAX / params->wake_intvl_mantis)) { + hdd_err_rl("Invalid exp %d mantissa %d", + wake_intvl_exp, + params->wake_intvl_mantis); + return -EINVAL; + } + params->wake_intvl_us = + params->wake_intvl_mantis * result; + } else { + params->wake_intvl_us = params->wake_intvl_mantis; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL; + if (tb[cmd_id]) + params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL; + if (tb[cmd_id]) + params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]); + + if (params->min_wake_intvl_us > params->max_wake_intvl_us) { + hdd_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero", + params->min_wake_intvl_us, + params->max_wake_intvl_us); + params->min_wake_dura_us = 0; + params->max_wake_dura_us = 0; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (tb[cmd_id]) + params->wake_time_tsf = nla_get_u64(tb[cmd_id]); + else + params->wake_time_tsf = 0; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT; + if (tb[cmd_id]) + params->announce_timeout_us = nla_get_u32(tb[cmd_id]); + else + params->announce_timeout_us = 0; + + hdd_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d", + params->dialog_id, params->vdev_id, params->wake_intvl_us, + params->min_wake_intvl_us, params->max_wake_intvl_us, + params->wake_intvl_mantis); + + hdd_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d", + params->wake_dura_us, params->min_wake_dura_us, + params->max_wake_dura_us, params->sp_offset_us, + params->twt_cmd); + hdd_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d wake_tsf 0x%llx", + params->flag_bcast, params->flag_trigger, + params->flag_flow_type, + params->flag_protection, + params->wake_time_tsf); + hdd_debug("twt: peer mac_addr " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params->peer_macaddr)); + hdd_debug("twt: announce timeout(in us) %u", + params->announce_timeout_us); + + return 0; +} + +int hdd_test_config_twt_setup_session(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct nlattr *twt_session; + int tmp, rc; + struct hdd_station_ctx *hdd_sta_ctx = NULL; + struct wmi_twt_add_dialog_param params = {0}; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + uint32_t congestion_timeout = 0; + int ret = 0; + int cmd_id; + QDF_STATUS qdf_status; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + return -EOPNOTSUPP; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err_rl("Invalid state, vdev %d mode %d", + adapter->deflink->vdev_id, adapter->device_mode); + return -EINVAL; + } + + qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->deflink->vdev_id; + + cmd_id = QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_TWT_SETUP; + nla_for_each_nested(twt_session, tb[cmd_id], tmp) { + rc = wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + nla_data(twt_session), + nla_len(twt_session), + qca_wlan_vendor_twt_add_dialog_policy); + if (rc) { + hdd_err_rl("Invalid twt ATTR"); + return -EINVAL; + } + + ret = hdd_twt_get_add_dialog_values(tb2, ¶ms); + if (ret) + return ret; + + ucfg_mlme_get_twt_congestion_timeout(adapter->hdd_ctx->psoc, + &congestion_timeout); + if (congestion_timeout) { + ret = qdf_status_to_os_return( + hdd_send_twt_requestor_disable_cmd(adapter->hdd_ctx, + 0)); + if (ret) { + hdd_err("Failed to disable TWT"); + return ret; + } + + ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0); + + qdf_status = hdd_send_twt_requestor_enable_cmd( + adapter->hdd_ctx); + + ret = qdf_status_to_os_return(qdf_status); + if (ret) { + hdd_err("Failed to Enable TWT"); + return ret; + } + } + + ret = qdf_status_to_os_return(sme_test_config_twt_setup(¶ms)); + } + return ret; +} + +int hdd_test_config_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct hdd_station_ctx *hdd_sta_ctx = NULL; + struct wmi_twt_del_dialog_param params = {0}; + int ret_val; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + return -EOPNOTSUPP; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err_rl("Invalid state, vdev %d mode %d", + adapter->deflink->vdev_id, adapter->device_mode); + return -EINVAL; + } + + qdf_mem_copy(params.peer_macaddr, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->deflink->vdev_id; + params.dialog_id = 0; + hdd_debug("twt_terminate: vdev_id %d", params.vdev_id); + + ret_val = qdf_status_to_os_return(sme_test_config_twt_terminate(¶ms)); + return ret_val; +} + +static +QDF_STATUS hdd_twt_check_all_twt_support(struct wlan_objmgr_psoc *psoc, + uint32_t dialog_id) +{ + bool is_all_twt_tgt_cap_enabled = false; + QDF_STATUS status; + + /* Cap check is check NOT required if id is for a single session*/ + if (dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) + return QDF_STATUS_SUCCESS; + + status = ucfg_mlme_get_twt_all_twt_tgt_cap( + psoc, + &is_all_twt_tgt_cap_enabled); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_INVAL; + + if (!is_all_twt_tgt_cap_enabled) { + hdd_debug("All TWT sessions not supported by target"); + return QDF_STATUS_E_NOSUPPORT; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_get_params_resp_len() - Calculates the length + * of twt get_params nl response + * @params: twt session stats parameters + * + * Return: Length of get params nl response + */ +static uint32_t +hdd_twt_get_params_resp_len(struct wmi_host_twt_session_stats_info *params) +{ + uint32_t len = nla_total_size(0); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR */ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA */ + len += nla_total_size(sizeof(u32)); + + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF */ + len += nla_total_size(sizeof(u64)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */ + if (params->pm_responder_bit_valid) + len += nla_total_size(sizeof(u8)); + + return len; +} + +/** + * hdd_get_converted_twt_state() - Convert the internal twt state + * to qca_wlan_twt_setup_state type. + * @state: Internal TWT state to be converted. + * + * Return: qca_wlan_twt_setup_state type state + */ +static enum qca_wlan_twt_setup_state +hdd_get_converted_twt_state(enum wlan_twt_session_state state) +{ + switch (state) { + case WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED: + return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + case WLAN_TWT_SETUP_STATE_ACTIVE: + return QCA_WLAN_TWT_SETUP_STATE_ACTIVE; + case WLAN_TWT_SETUP_STATE_SUSPEND: + return QCA_WLAN_TWT_SETUP_STATE_SUSPEND; + default: + return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } +} + +/** + * hdd_twt_pack_get_params_resp_nlmsg()- Packs and sends twt get_params response + * @psoc: Pointer to Global psoc + * @reply_skb: pointer to response skb buffer + * @params: Pointer to twt peer session parameters + * @num_twt_session: total number of valid twt session + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_pack_get_params_resp_nlmsg( + struct wlan_objmgr_psoc *psoc, + struct sk_buff *reply_skb, + struct wmi_host_twt_session_stats_info *params, + int num_twt_session) +{ + struct nlattr *config_attr, *nla_params; + enum wlan_twt_session_state state; + enum qca_wlan_twt_setup_state converted_state; + uint64_t tsf_val; + uint32_t wake_duration; + uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu; + int i, attr; + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("TWT: get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_twt_session; i++) { + if (params[i].event_type != HOST_TWT_SESSION_SETUP && + params[i].event_type != HOST_TWT_SESSION_UPDATE) + continue; + + nla_params = nla_nest_start(reply_skb, i); + if (!nla_params) { + hdd_err("TWT: get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params[i].peer_mac)) { + hdd_err("TWT: get_params failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + hdd_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[i].peer_mac)); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) { + hdd_err("TWT: get_params failed to put dialog_id"); + return QDF_STATUS_E_INVAL; + } + + if (params[i].bcast) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("TWT: get_params fail to put bcast"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].trig) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("TWT: get_params fail to put Trigger"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].announ) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("TWT: get_params fail to put Announce"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].protection) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("TWT: get_params fail to put Protect"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].pm_responder_bit_valid) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE; + if (nla_put_u8(reply_skb, attr, + params[i].pm_responder_bit)) { + hdd_err("TWT: fail to put pm responder mode"); + return QDF_STATUS_E_INVAL; + } + } + + if (!params[i].info_frame_disabled) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("TWT: get_params put Info Enable fail"); + return QDF_STATUS_E_INVAL; + } + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + wake_duration = (params[i].wake_dura_us / + TWT_WAKE_DURATION_MULTIPLICATION_FACTOR); + if (nla_put_u32(reply_skb, attr, wake_duration)) { + hdd_err("TWT: get_params failed to put Wake duration"); + return QDF_STATUS_E_INVAL; + } + + wake_intvl_mantis_us = params[i].wake_intvl_us; + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_us)) { + hdd_err("TWT: get_params failed to put Wake Interval in us"); + return QDF_STATUS_E_INVAL; + } + wake_intvl_mantis_tu = params[i].wake_intvl_us / + TWT_WAKE_INTVL_MULTIPLICATION_FACTOR; + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) { + hdd_err("TWT: get_params failed to put Wake Interval"); + return QDF_STATUS_E_INVAL; + } + + hdd_debug("TWT: Send mantissa_us:%d, mantissa_tu:%d to userspace", + wake_intvl_mantis_us, wake_intvl_mantis_tu); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (nla_put_u8(reply_skb, attr, 0)) { + hdd_err("TWT: get_params put Wake Interval Exp failed"); + return QDF_STATUS_E_INVAL; + } + + tsf_val = ((uint64_t)params[i].sp_tsf_us_hi << 32) | + params[i].sp_tsf_us_lo; + + hdd_debug("TWT: get_params dialog_id %d TSF = 0x%llx", + params[i].dialog_id, tsf_val); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (hdd_wlan_nla_put_u64(reply_skb, attr, tsf_val)) { + hdd_err("TWT: get_params failed to put TSF Value"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE; + state = ucfg_mlme_get_twt_session_state( + psoc, (struct qdf_mac_addr *)params[i].peer_mac, + params[i].dialog_id); + converted_state = hdd_get_converted_twt_state(state); + if (nla_put_u32(reply_skb, attr, converted_state)) { + hdd_err("TWT: get_params failed to put TWT state"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, nla_params); + } + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_pack_get_params_resp()- Obtains twt session parameters of a peer + * and sends response to the user space via nl layer + * @hdd_ctx: hdd context + * @params: Pointer to store twt peer session parameters + * @num_twt_session: number of twt session + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_pack_get_params_resp(struct hdd_context *hdd_ctx, + struct wmi_host_twt_session_stats_info *params, + int num_twt_session) +{ + struct sk_buff *reply_skb; + uint32_t skb_len = NLMSG_HDRLEN, i; + QDF_STATUS qdf_status; + + /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */ + skb_len += NLA_HDRLEN; + + /* Length of twt session parameters */ + for (i = 0; i < num_twt_session; i++) { + if (params[i].event_type == HOST_TWT_SESSION_SETUP || + params[i].event_type == HOST_TWT_SESSION_UPDATE) + skb_len += hdd_twt_get_params_resp_len(params + i); + } + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + skb_len); + if (!reply_skb) { + hdd_err("TWT: get_params alloc reply skb failed"); + return QDF_STATUS_E_NOMEM; + } + + qdf_status = hdd_twt_pack_get_params_resp_nlmsg(hdd_ctx->psoc, + reply_skb, params, + num_twt_session); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto fail; + + if (wlan_cfg80211_vendor_cmd_reply(reply_skb)) + qdf_status = QDF_STATUS_E_INVAL; + return qdf_status; + +fail: + wlan_cfg80211_vendor_free_skb(reply_skb); + return qdf_status; +} + +static int hdd_is_twt_command_allowed(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) + return -EOPNOTSUPP; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err_rl("Invalid state, vdev %d mode %d", + adapter->deflink->vdev_id, adapter->device_mode); + return -EAGAIN; + } + + if (hdd_is_roaming_in_progress(hdd_ctx)) + return -EBUSY; + + if (ucfg_scan_get_pdev_status(hdd_ctx->pdev)) { + hdd_err_rl("Scan in progress"); + return -EBUSY; + } + + return 0; +} + +/** + * hdd_send_inactive_session_reply - Send session state as inactive for + * dialog ID for which setup is not done. + * @adapter: hdd_adapter + * @params: TWT session parameters + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_send_inactive_session_reply(struct hdd_adapter *adapter, + struct wmi_host_twt_session_stats_info *params) +{ + QDF_STATUS qdf_status; + int num_twt_session = 0; + + params[num_twt_session].event_type = HOST_TWT_SESSION_UPDATE; + num_twt_session++; + + qdf_status = hdd_twt_pack_get_params_resp(adapter->hdd_ctx, params, + num_twt_session); + + return qdf_status; +} + +/** + * hdd_twt_get_peer_session_params() - Obtains twt session parameters of a peer + * and sends response to the user space + * @hdd_ctx: hdd context + * @params: Pointer to store twt peer session parameters + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_get_peer_session_params(struct hdd_context *hdd_ctx, + struct wmi_host_twt_session_stats_info *params) +{ + int num_twt_session = 0; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + + if (!hdd_ctx || !params) + return qdf_status; + num_twt_session = ucfg_twt_get_peer_session_params(hdd_ctx->psoc, + params); + if (num_twt_session) + qdf_status = hdd_twt_pack_get_params_resp(hdd_ctx, params, + num_twt_session); + + return qdf_status; +} + +/** + * hdd_sap_twt_get_session_params() - Parses twt nl attributes, obtains twt + * session parameters based on dialog_id and returns to user via nl layer + * @adapter: hdd_adapter + * @twt_param_attr: twt nl attributes + * + * Return: 0 on success, negative value on failure + */ +static int hdd_sap_twt_get_session_params(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + int max_num_peer; + struct wmi_host_twt_session_stats_info *params; + int ret, id, id1; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + struct qdf_mac_addr mac_addr; + bool is_associated; + + ret = wlan_cfg80211_nla_parse_nested( + tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + max_num_peer = hdd_ctx->wiphy->max_ap_assoc_sta; + params = qdf_mem_malloc(TWT_PEER_MAX_SESSIONS * max_num_peer * + sizeof(*params)); + + if (!params) + return -ENOMEM; + + params[0].vdev_id = adapter->deflink->vdev_id; + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + + if (tb[id] && tb[id1]) { + params[0].dialog_id = nla_get_u8(tb[id]); + nla_memcpy(params[0].peer_mac, tb[id1], QDF_MAC_ADDR_SIZE); + } else { + hdd_err_rl("TWT: get_params dialog_id or mac_addr is missing"); + goto done; + } + + if (QDF_IS_ADDR_BROADCAST(params[0].peer_mac) && + params[0].dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + hdd_err_rl("TWT: get_params dialog_is is invalid"); + goto done; + } + + if (!params[0].dialog_id) + params[0].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + + qdf_mem_copy(mac_addr.bytes, params[0].peer_mac, QDF_MAC_ADDR_SIZE); + + if (!qdf_is_macaddr_broadcast(&mac_addr)) { + is_associated = hdd_is_peer_associated(adapter, &mac_addr); + if (!is_associated) { + hdd_err("TWT: Association doesn't exist for STA: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(&mac_addr)); + goto done; + } + } + + hdd_debug("TWT: get_params dialog_id %d and mac_addr " QDF_MAC_ADDR_FMT, + params[0].dialog_id, QDF_MAC_ADDR_REF(params[0].peer_mac)); + + qdf_status = hdd_twt_get_peer_session_params(adapter->hdd_ctx, + ¶ms[0]); +done: + qdf_mem_free(params); + return qdf_status_to_os_return(qdf_status); +} + +/** + * hdd_sta_twt_get_session_params() - Parses twt nl attributes, obtains twt + * session parameters based on dialog_id and returns to user via nl layer + * @adapter: hdd_adapter + * @twt_param_attr: twt nl attributes + * + * Return: 0 on success, negative value on failure + */ +static int hdd_sta_twt_get_session_params(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wmi_host_twt_session_stats_info + params[TWT_PSOC_MAX_SESSIONS] = { {0} }; + int ret, id; + QDF_STATUS qdf_status; + struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + params[0].vdev_id = adapter->deflink->vdev_id; + /* + * Currently twt_get_params nl cmd is sending only dialog_id(STA), fill + * mac_addr of STA in params and call hdd_twt_get_peer_session_params. + * When twt_get_params passes mac_addr and dialog_id of STA/SAP, update + * both mac_addr and dialog_id in params before calling + * hdd_twt_get_peer_session_params. dialog_id if not received, + * dialog_id of value 0 will be used as default. + */ + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) + params[0].dialog_id = (uint32_t)nla_get_u8(tb[id]); + else + params[0].dialog_id = 0; + + if (params[0].dialog_id <= TWT_MAX_DIALOG_ID) { + qdf_mem_copy(params[0].peer_mac, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + hdd_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[0].peer_mac)); + } else { + qdf_mem_copy(params[0].peer_mac, &bcast_addr, + QDF_MAC_ADDR_SIZE); + } + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params[0].dialog_id)) { + hdd_debug("vdev%d: TWT session %d setup incomplete", + adapter->deflink->vdev_id, params[0].dialog_id); + qdf_status = hdd_send_inactive_session_reply(adapter, params); + + return qdf_status_to_os_return(qdf_status); + } + + hdd_debug("TWT: get_params dialog_id %d and mac_addr " QDF_MAC_ADDR_FMT, + params[0].dialog_id, QDF_MAC_ADDR_REF(params[0].peer_mac)); + + qdf_status = hdd_twt_get_peer_session_params(adapter->hdd_ctx, + ¶ms[0]); + + return qdf_status_to_os_return(qdf_status); +} + +/** + * hdd_twt_get_session_params() - Parses twt nl attributes, obtains twt + * session parameters based on dialog_id and returns to user via nl layer + * @adapter: hdd_adapter + * @twt_param_attr: twt nl attributes + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_get_session_params(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + enum QDF_OPMODE device_mode = adapter->device_mode; + + switch (device_mode) { + case QDF_STA_MODE: + return hdd_sta_twt_get_session_params(adapter, twt_param_attr); + case QDF_SAP_MODE: + return hdd_sap_twt_get_session_params(adapter, twt_param_attr); + default: + hdd_err_rl("TWT get session params is not supported on %s", + qdf_opmode_str(adapter->device_mode)); + } + + return -EOPNOTSUPP; +} + +/** + * hdd_get_twt_setup_event_len() - Calculates the length of twt + * setup nl response + * @ev_params: event parameters, contains info that what parameters need + * to send in twt setup response. + * + * Return: Length of twt setup nl response + */ +static uint32_t +hdd_get_twt_setup_event_len(struct wma_twt_add_dialog_complete_event *ev_params) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + + /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */ + len += NLA_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + + if (!ev_params->params.num_additional_twt_params) + return len; + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE */ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION*/ + len += nla_total_size(sizeof(u32)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA*/ + len += nla_total_size(sizeof(u32)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF*/ + len += nla_total_size(sizeof(u64)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME*/ + len += nla_total_size(sizeof(u32)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + if (ev_params->additional_params.pm_responder_bit_valid) + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */ + len += nla_total_size(sizeof(u8)); + + return len; +} + +/** + * wmi_twt_resume_status_to_vendor_twt_status() - convert from + * WMI_HOST_RESUME_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_RESUME_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +wmi_twt_resume_status_to_vendor_twt_status(enum WMI_HOST_RESUME_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_RESUME_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_RESUME_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case WMI_HOST_RESUME_TWT_STATUS_NOT_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED; + case WMI_HOST_RESUME_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_RESUME_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_RESUME_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case WMI_HOST_RESUME_TWT_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case WMI_HOST_RESUME_TWT_STATUS_ROAM_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS; + case WMI_HOST_RESUME_TWT_STATUS_SCAN_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * wmi_twt_pause_status_to_vendor_twt_status() - convert from + * WMI_HOST_PAUSE_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_PAUSE_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +wmi_twt_pause_status_to_vendor_twt_status(enum WMI_HOST_PAUSE_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_PAUSE_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_PAUSE_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case WMI_HOST_PAUSE_TWT_STATUS_ALREADY_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED; + case WMI_HOST_PAUSE_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_PAUSE_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_PAUSE_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case WMI_HOST_PAUSE_TWT_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case WMI_HOST_PAUSE_TWT_STATUS_ROAM_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * wmi_twt_nudge_status_to_vendor_twt_status() - convert from + * WMI_HOST_NUDGE_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_NUDGE_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +wmi_twt_nudge_status_to_vendor_twt_status(enum WMI_HOST_NUDGE_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_NUDGE_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_NUDGE_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case WMI_HOST_NUDGE_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_NUDGE_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_NUDGE_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case WMI_HOST_NUDGE_TWT_STATUS_ALREADY_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED; + case WMI_HOST_NUDGE_TWT_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * wmi_twt_add_cmd_to_vendor_twt_resp_type() - convert from + * WMI_HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type + * @type: WMI_HOST_TWT_COMMAND value from firmware + * + * Return: qca_wlan_vendor_twt_setup_resp_type values for valid + * WMI_HOST_TWT_COMMAND value and -EINVAL for invalid value + */ +static +int wmi_twt_add_cmd_to_vendor_twt_resp_type(enum WMI_HOST_TWT_COMMAND type) +{ + switch (type) { + case WMI_HOST_TWT_COMMAND_ACCEPT_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_ACCEPT; + case WMI_HOST_TWT_COMMAND_ALTERNATE_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE; + case WMI_HOST_TWT_COMMAND_DICTATE_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_DICTATE; + case WMI_HOST_TWT_COMMAND_REJECT_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_REJECT; + default: + return -EINVAL; + } +} + +/** + * wmi_twt_del_status_to_vendor_twt_status() - convert from + * WMI_HOST_DEL_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_DEL_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static +int wmi_twt_del_status_to_vendor_twt_status(enum WMI_HOST_DEL_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_DEL_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_DEL_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case WMI_HOST_DEL_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_DEL_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case WMI_HOST_DEL_TWT_STATUS_PEER_INIT_TEARDOWN: + return QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE; + case WMI_HOST_DEL_TWT_STATUS_ROAMING: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE; + case WMI_HOST_DEL_TWT_STATUS_CONCURRENCY: + return QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE; + case WMI_HOST_DEL_TWT_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case WMI_HOST_DEL_TWT_STATUS_SCAN_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS; + case WMI_HOST_DEL_TWT_STATUS_PS_DISABLE_TEARDOWN: + return QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * wmi_twt_add_status_to_vendor_twt_status() - convert from + * WMI_HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: WMI_HOST_ADD_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to WMI_HOST_ADD_TWT_STATUS. + */ +static enum qca_wlan_vendor_twt_status +wmi_twt_add_status_to_vendor_twt_status(enum WMI_HOST_ADD_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_ADD_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED: + return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED; + case WMI_HOST_ADD_TWT_STATUS_USED_DIALOG_ID: + return QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID; + case WMI_HOST_ADD_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case WMI_HOST_ADD_TWT_STATUS_NOT_READY: + return QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY; + case WMI_HOST_ADD_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case WMI_HOST_ADD_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case WMI_HOST_ADD_TWT_STATUS_NO_RESPONSE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE; + case WMI_HOST_ADD_TWT_STATUS_DENIED: + return QCA_WLAN_VENDOR_TWT_STATUS_DENIED; + case WMI_HOST_ADD_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case WMI_HOST_ADD_TWT_STATUS_AP_PARAMS_NOT_IN_RANGE: + return QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE; + case WMI_HOST_ADD_TWT_STATUS_AP_IE_VALIDATION_FAILED: + return QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID; + case WMI_HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS; + case WMI_HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case WMI_HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * hdd_twt_setup_pack_resp_nlmsg() - pack nlmsg response for setup + * @reply_skb: pointer to the response skb structure + * @event: twt event buffer with firmware response + * + * Pack the nl response with parameters and additional parameters + * received from firmware. + * Firmware sends additional parameters only for 2 conditions + * 1) TWT Negotiation is accepted by AP - Firmware sends + * QCA_WLAN_VENDOR_TWT_STATUS_OK with appropriate response type + * in additional parameters + * 2) AP has proposed Alternate values - In this case firmware sends + * QCA_WLAN_VENDOR_TWT_STATUS_DENIED with appropriate response type + * in additional parameters + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +static QDF_STATUS +hdd_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wma_twt_add_dialog_complete_event *event) +{ + struct nlattr *config_attr; + uint64_t sp_offset_tsf; + enum qca_wlan_vendor_twt_status vendor_status; + int response_type, attr; + uint32_t wake_duration; + uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu; + + hdd_enter(); + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_SET)) { + hdd_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + sp_offset_tsf = event->additional_params.sp_tsf_us_hi; + sp_offset_tsf = (sp_offset_tsf << 32) | + event->additional_params.sp_tsf_us_lo; + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, event->params.dialog_id)) { + hdd_err("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = wmi_twt_add_status_to_vendor_twt_status( + event->params.status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + hdd_err("Failed to put setup status"); + return QDF_STATUS_E_FAILURE; + } + + if (event->params.num_additional_twt_params == 0) { + nla_nest_end(reply_skb, config_attr); + return QDF_STATUS_SUCCESS; + } + + response_type = wmi_twt_add_cmd_to_vendor_twt_resp_type( + event->additional_params.twt_cmd); + if (response_type == -EINVAL) { + hdd_err("Invalid response type from firmware"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE; + if (nla_put_u8(reply_skb, attr, response_type)) { + hdd_err("Failed to put setup response type"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (nla_put_u8(reply_skb, attr, event->additional_params.announce)) { + hdd_err("Failed to put setup flow type"); + return QDF_STATUS_E_FAILURE; + } + + hdd_debug("wake_dur_us %d", event->additional_params.wake_dur_us); + wake_duration = (event->additional_params.wake_dur_us / + TWT_WAKE_DURATION_MULTIPLICATION_FACTOR); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, wake_duration)) { + hdd_err("Failed to put wake duration"); + return QDF_STATUS_E_FAILURE; + } + + wake_intvl_mantis_us = event->additional_params.wake_intvl_us; + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA, + wake_intvl_mantis_us)) { + hdd_err("Failed to put wake interval mantissa in us"); + return QDF_STATUS_E_FAILURE; + } + + wake_intvl_mantis_tu = (event->additional_params.wake_intvl_us / + TWT_WAKE_INTVL_MULTIPLICATION_FACTOR); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) { + hdd_err("Failed to put wake interval mantissa in tu"); + return QDF_STATUS_E_FAILURE; + } + hdd_debug("Send mantissa_us:%d, mantissa_tu:%d to userspace", + wake_intvl_mantis_us, wake_intvl_mantis_tu); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (nla_put_u8(reply_skb, attr, 0)) { + hdd_err("Failed to put wake interval exp"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (wlan_cfg80211_nla_put_u64(reply_skb, attr, sp_offset_tsf)) { + hdd_err("Failed to put sp_offset_tsf"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME; + if (nla_put_u32(reply_skb, attr, + event->additional_params.sp_offset_us)) { + hdd_err("Failed to put sp_offset_us"); + return QDF_STATUS_E_FAILURE; + } + + if (event->additional_params.trig_en) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("Failed to put trig type"); + return QDF_STATUS_E_FAILURE; + } + } + + if (event->additional_params.protection) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("Failed to put protection flag"); + return QDF_STATUS_E_FAILURE; + } + } + + if (event->additional_params.bcast) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("Failed to put bcast flag"); + return QDF_STATUS_E_FAILURE; + } + } + if (event->additional_params.pm_responder_bit_valid) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE; + if (nla_put_u8(reply_skb, attr, + event->additional_params.pm_responder_bit)) { + hdd_err("Failed to put pm responder mode"); + return QDF_STATUS_E_FAILURE; + } + } + + if (!event->additional_params.info_frame_disabled) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED; + if (nla_put_flag(reply_skb, attr)) { + hdd_err("Failed to put twt info enable flag"); + return QDF_STATUS_E_FAILURE; + } + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + event->params.peer_macaddr)) { + hdd_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_send_twt_setup_response - Send TWT setup response to userspace + * @adapter: Pointer to HDD adapter. This pointer is expected to + * be validated by the caller. + * @add_dialog_comp_ev_params: Add dialog completion event structure + * + * Return: QDF_STATUS + */ +static QDF_STATUS hdd_send_twt_setup_response( + struct hdd_adapter *adapter, + struct wma_twt_add_dialog_complete_event *add_dialog_comp_ev_params) +{ + struct hdd_context *hdd_ctx; + struct sk_buff *twt_vendor_event; + struct wireless_dev *wdev = adapter->dev->ieee80211_ptr; + size_t data_len; + QDF_STATUS status; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + data_len = hdd_get_twt_setup_event_len(add_dialog_comp_ev_params); + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("TWT: Alloc setup resp skb fail"); + return QDF_STATUS_E_NOMEM; + } + + status = hdd_twt_setup_pack_resp_nlmsg(twt_vendor_event, + add_dialog_comp_ev_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl add dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + return status; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + return status; +} + +/** + * hdd_twt_handle_renego_failure() - Upon re-nego failure send TWT teardown + * + * @adapter: Adapter pointer + * @add_dialog_event: Pointer to Add dialog complete event structure + * + * Upon re-negotiation failure, this function constructs TWT teardown + * message to the target. + * + * Return: None + */ +static void +hdd_twt_handle_renego_failure(struct hdd_adapter *adapter, + struct wma_twt_add_dialog_complete_event *add_dialog_event) +{ + struct wmi_twt_del_dialog_param params = {0}; + + if (!add_dialog_event) + return; + + qdf_mem_copy(params.peer_macaddr, + add_dialog_event->params.peer_macaddr, + QDF_MAC_ADDR_SIZE); + params.vdev_id = add_dialog_event->params.vdev_id; + params.dialog_id = add_dialog_event->params.dialog_id; + + hdd_debug("renego: twt_terminate: vdev_id:%d dialog_id:%d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + hdd_send_twt_del_dialog_cmd(adapter->hdd_ctx, ¶ms); +} + +/** + * hdd_twt_ack_comp_cb() - TWT ack complete event callback + * @params: TWT parameters + * @context: Context + * + * Return: None + */ +static void +hdd_twt_ack_comp_cb(struct wmi_twt_ack_complete_event_param *params, + void *context) +{ + struct osif_request *request = NULL; + struct twt_ack_info_priv *status_priv; + + request = osif_request_get(context); + if (!request) { + hdd_err("obsolete request"); + return; + } + + status_priv = osif_request_priv(request); + if (!status_priv) { + hdd_err("obsolete status_priv"); + return; + } + + if (status_priv->twt_cmd_ack == params->twt_cmd_ack) { + status_priv->vdev_id = params->vdev_id; + qdf_copy_macaddr(&status_priv->peer_macaddr, + ¶ms->peer_macaddr); + status_priv->dialog_id = params->dialog_id; + status_priv->status = params->status; + osif_request_complete(request); + } else { + hdd_err("Invalid ack for twt command"); + } + + osif_request_put(request); +} + +/** + * hdd_twt_ack_wait_response: TWT wait for ack event if it's supported + * @hdd_ctx: HDD context + * @request: OSIF request cookie + * @twt_cmd: TWT command for which ack event come + * + * Return: None + */ +static QDF_STATUS +hdd_twt_ack_wait_response(struct hdd_context *hdd_ctx, + struct osif_request *request, int twt_cmd) +{ + struct target_psoc_info *tgt_hdl; + struct twt_ack_info_priv *ack_priv; + int ret = 0; + bool twt_ack_cap; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(hdd_ctx->psoc); + if (!tgt_hdl) { + hdd_err("tgt_hdl is NULL"); + return QDF_STATUS_E_FAILURE; + } + target_psoc_get_twt_ack_cap(tgt_hdl, &twt_ack_cap); + + if (!twt_ack_cap) { + hdd_err("TWT ack bit is not supported. No need to wait"); + return QDF_STATUS_SUCCESS; + } + + ack_priv = osif_request_priv(request); + ack_priv->twt_cmd_ack = twt_cmd; + + ret = osif_request_wait_for_response(request); + if (ret) { + hdd_err("TWT setup response timed out"); + return QDF_STATUS_E_FAILURE; + } + + ack_priv = osif_request_priv(request); + hdd_debug("TWT ack info: vdev_id %d dialog_id %d twt_cmd %d status %d peer_macaddr " + QDF_MAC_ADDR_FMT, ack_priv->vdev_id, ack_priv->dialog_id, + ack_priv->twt_cmd_ack, ack_priv->status, + QDF_MAC_ADDR_REF(ack_priv->peer_macaddr.bytes)); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_add_dialog_comp_cb() - HDD callback for twt add dialog + * complete event + * @psoc: Pointer to global psoc + * @add_dialog_event: Pointer to Add dialog complete event structure + * @renego_fail: Flag to indicate if its re-negotiation failure case + * + * Return: None + */ +static void +hdd_twt_add_dialog_comp_cb(struct wlan_objmgr_psoc *psoc, + struct wma_twt_add_dialog_complete_event *add_dialog_event, + bool renego_fail) +{ + struct hdd_adapter *adapter; + struct wlan_hdd_link_info *link_info; + uint8_t vdev_id = add_dialog_event->params.vdev_id; + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + adapter = link_info->adapter; + hdd_debug("TWT: add dialog_id:%d, status:%d vdev_id:%d renego_fail:%d peer mac_addr " + QDF_MAC_ADDR_FMT, add_dialog_event->params.dialog_id, + add_dialog_event->params.status, vdev_id, renego_fail, + QDF_MAC_ADDR_REF(add_dialog_event->params.peer_macaddr)); + + hdd_send_twt_setup_response(adapter, add_dialog_event); + + if (renego_fail) + hdd_twt_handle_renego_failure(adapter, add_dialog_event); +} + +/** + * hdd_send_twt_add_dialog_cmd() - Send TWT add dialog command to target + * @hdd_ctx: HDD Context + * @twt_params: Pointer to Add dialog cmd params structure + * + * Return: 0 for Success and negative value for failure + */ +static +int hdd_send_twt_add_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_add_dialog_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_info_priv *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -EINVAL; + } + + context = osif_request_cookie(request); + + status = sme_add_dialog_cmd(hdd_ctx->mac_handle, + hdd_twt_add_dialog_comp_cb, + twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send add dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = WMI_HOST_TWT_ADD_DIALOG_CMDID; + + status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd); + + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status) { + hdd_err("Received TWT ack error. Reset twt command"); + ucfg_mlme_reset_twt_active_cmd( + hdd_ctx->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + ucfg_mlme_init_twt_context( + hdd_ctx->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + switch (ack_priv->status) { + case WMI_HOST_ADD_TWT_STATUS_INVALID_PARAM: + case WMI_HOST_ADD_TWT_STATUS_UNKNOWN_ERROR: + case WMI_HOST_ADD_TWT_STATUS_USED_DIALOG_ID: + ret = -EINVAL; + break; + case WMI_HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS: + case WMI_HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS: + case WMI_HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + case WMI_HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED: + ret = -EOPNOTSUPP; + break; + case WMI_HOST_ADD_TWT_STATUS_NOT_READY: + ret = -EAGAIN; + break; + case WMI_HOST_ADD_TWT_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + default: + ret = -EAGAIN; + break; + } + } + +cleanup: + osif_request_put(request); + hdd_exit(); + + return ret; +} + +static bool hdd_twt_setup_conc_allowed(struct hdd_context *hdd_ctx, + uint8_t vdev_id) +{ + return policy_mgr_current_concurrency_is_mcc(hdd_ctx->psoc) || + policy_mgr_is_scc_with_this_vdev_id(hdd_ctx->psoc, vdev_id); +} + +/** + * hdd_twt_setup_session() - Process TWT setup operation in the + * received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_SET + * + * Return: 0 for Success and negative value for failure + * + * If the setup request is received: + * before the host driver receiving the setup response event from + * firmware for the previous setup request, then return -EINPROGRESS + * + * after the host driver received the setup response event from + * firmware for the previous setup request, then setup_done is + * set to true and this new setup request is sent to firmware + * for parameter re-negotiation. + */ +static int hdd_twt_setup_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct wmi_twt_add_dialog_param params = {0}; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + uint32_t congestion_timeout = 0; + int ret = 0; + + ret = hdd_is_twt_command_allowed(adapter); + if (ret) + return ret; + + if (hdd_twt_setup_conc_allowed(hdd_ctx, adapter->deflink->vdev_id)) { + hdd_err_rl("TWT setup reject: SCC or MCC concurrency exists"); + return -EAGAIN; + } + + qdf_mem_copy(params.peer_macaddr, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->deflink->vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb2, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + ret = hdd_twt_get_add_dialog_values(tb2, ¶ms); + if (ret) + return ret; + + if (params.flag_bcast && !ucfg_mlme_get_twt_peer_bcast_capabilities( + adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid)) { + hdd_err_rl("TWT setup reject: TWT Broadcast not supported"); + return -EOPNOTSUPP; + } else if (!params.flag_bcast && + !ucfg_mlme_get_twt_peer_responder_capabilities( + adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid)) { + hdd_err_rl("TWT setup reject: TWT responder not supported"); + return -EOPNOTSUPP; + } + + ucfg_mlme_get_twt_congestion_timeout(adapter->hdd_ctx->psoc, + &congestion_timeout); + + if (congestion_timeout) { + ret = qdf_status_to_os_return( + hdd_send_twt_requestor_disable_cmd(adapter->hdd_ctx, + 0)); + if (ret) { + hdd_err("Failed to disable TWT"); + return ret; + } + + ucfg_mlme_set_twt_congestion_timeout(adapter->hdd_ctx->psoc, 0); + + ret = qdf_status_to_os_return( + hdd_send_twt_requestor_enable_cmd(adapter->hdd_ctx)); + if (ret) { + hdd_err("Failed to Enable TWT"); + return ret; + } + } + + if (ucfg_mlme_is_max_twt_sessions_reached(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params.dialog_id)) { + hdd_err_rl("TWT add failed(dialog_id:%d), another TWT already exists (max reached)", + params.dialog_id); + return -EAGAIN; + } + + if (ucfg_mlme_is_twt_setup_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params.dialog_id)) { + hdd_err_rl("TWT setup is in progress for dialog_id:%d", + params.dialog_id); + return -EINPROGRESS; + } + + ret = hdd_send_twt_add_dialog_cmd(adapter->hdd_ctx, ¶ms); + if (ret < 0) + return ret; + + return ret; +} + +/** + * hdd_twt_add_ac_config() - Get TWT AC parameter + * value from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS + * @adapter: adapter pointer + * @twt_ac_param: AC parameter + * + * Handles QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE + * + * Return: 0 on success, negative value on failure. + */ +static int hdd_twt_add_ac_config(struct hdd_adapter *adapter, + enum qca_wlan_ac_type twt_ac_param) +{ + bool is_responder_en; + int ret = 0; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (twt_ac_param < QCA_WLAN_AC_BE || twt_ac_param > QCA_WLAN_AC_VO) { + hdd_err_rl("Invalid AC parameter. Value: %d", twt_ac_param); + return -EINVAL; + } + + ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &is_responder_en); + + if (adapter->device_mode == QDF_SAP_MODE && is_responder_en) { + ret = sme_cli_set_command(adapter->deflink->vdev_id, + wmi_pdev_param_twt_ac_config, + twt_ac_param, PDEV_CMD); + } else { + hdd_err_rl("Undesired device mode. Mode: %d and responder: %d", + adapter->device_mode, is_responder_en); + return -EINVAL; + } + + return ret; +} + +/** + * hdd_twt_set_param - Process TWT set parameter operation + * in the received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_SET_PARAM + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_set_param(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1]; + int ret; + int cmd_id; + uint8_t twt_ac_param; + + ret = wlan_cfg80211_nla_parse_nested + (tb, + QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX, + twt_param_attr, + qca_wlan_vendor_twt_set_param_policy); + if (ret) + return ret; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE; + + if (tb[cmd_id]) { + twt_ac_param = nla_get_u8(tb[cmd_id]); + hdd_debug("TWT_AC_CONFIG_VALUE: %d", twt_ac_param); + ret = hdd_twt_add_ac_config(adapter, twt_ac_param); + + if (ret) { + hdd_err("Fail to set TWT AC parameter, errno %d", + ret); + return ret; + } + } + + return ret; +} + +/** + * hdd_get_twt_get_stats_event_len() - calculate length of skb + * required for sending twt get statistics command responses. + * + * Return: length of skb + */ +static uint32_t hdd_get_twt_get_stats_event_len(void) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + + return len; +} + +/** + * hdd_get_twt_event_len() - calculate length of skb + * required for sending twt terminate, pause and resume + * command responses. + * + * Return: length of skb + */ +static uint32_t hdd_get_twt_event_len(void) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + return len; +} + +/** + * hdd_twt_terminate_pack_resp_nlmsg() - pack the skb with + * firmware response for twt terminate command + * @reply_skb: skb to store the response + * @params: Pointer to del dialog complete event buffer + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_terminate_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wmi_twt_del_dialog_complete_event_param *params) +{ + struct nlattr *config_attr; + int vendor_status, attr; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_TERMINATE)) { + hdd_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params->dialog_id)) { + hdd_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = wmi_twt_del_status_to_vendor_twt_status(params->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + hdd_err("Failed to put QCA_WLAN_TWT_TERMINATE"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params->peer_macaddr)) { + hdd_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_del_dialog_comp_cb() - callback function + * to get twt terminate command complete event + * @psoc: Pointer to global psoc + * @params: Pointer to del dialog complete event buffer + * + * Return: None + */ +static void +hdd_twt_del_dialog_comp_cb(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_del_dialog_complete_event_param *params) +{ + struct wlan_hdd_link_info *link_info; + struct wireless_dev *wdev; + struct hdd_context *hdd_ctx; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + + hdd_enter(); + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + if (!hdd_ctx || cds_is_load_or_unload_in_progress()) + return; + + wdev = &link_info->adapter->wdev; + + data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8)); + data_len += NLA_HDRLEN; + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("Del dialog skb alloc failed"); + return; + } + + hdd_debug("del dialog_id:%d, status:%d vdev_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params->dialog_id, + params->status, params->vdev_id, + QDF_MAC_ADDR_REF(params->peer_macaddr)); + + status = hdd_twt_terminate_pack_resp_nlmsg(twt_vendor_event, params); + if (QDF_IS_STATUS_ERROR(status)) { + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + return; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + hdd_exit(); + + return; +} + +void +hdd_send_twt_del_all_sessions_to_userspace(struct wlan_hdd_link_info *link_info) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc; + struct hdd_station_ctx *hdd_sta_ctx = NULL; + struct wmi_twt_del_dialog_complete_event_param params; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + if (!hdd_cm_is_vdev_associated(link_info)) { + hdd_debug("Not associated, vdev %d mode %d", + link_info->vdev_id, adapter->device_mode); + return; + } + + if (!ucfg_mlme_is_twt_setup_done(psoc, + &hdd_sta_ctx->conn_info.bssid, + TWT_ALL_SESSIONS_DIALOG_ID)) { + hdd_debug("No active TWT sessions, vdev_id: %d dialog_id: %d", + link_info->vdev_id, + TWT_ALL_SESSIONS_DIALOG_ID); + return; + } + + qdf_mem_zero(¶ms, sizeof(params)); + params.vdev_id = link_info->vdev_id; + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + params.status = WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR; + qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + + hdd_twt_del_dialog_comp_cb(psoc, ¶ms); +} + +/** + * hdd_send_twt_del_dialog_cmd() - Send TWT del dialog command to target + * @hdd_ctx: HDD Context + * @twt_params: Pointer to del dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static +int hdd_send_twt_del_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_del_dialog_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_info_priv *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -EINVAL; + } + + context = osif_request_cookie(request); + + status = sme_del_dialog_cmd(hdd_ctx->mac_handle, + hdd_twt_del_dialog_comp_cb, + twt_params, context); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send del dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = WMI_HOST_TWT_DEL_DIALOG_CMDID; + + status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd); + + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status) { + hdd_err("Received TWT ack error. Reset twt command"); + ucfg_mlme_reset_twt_active_cmd( + hdd_ctx->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + switch (ack_priv->status) { + case WMI_HOST_DEL_TWT_STATUS_INVALID_PARAM: + case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_NOT_EXIST: + ret = -EAGAIN; + break; + case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case WMI_HOST_DEL_TWT_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case WMI_HOST_DEL_TWT_STATUS_ROAMING: + case WMI_HOST_DEL_TWT_STATUS_CHAN_SW_IN_PROGRESS: + case WMI_HOST_DEL_TWT_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + case WMI_HOST_DEL_TWT_STATUS_CONCURRENCY: + ret = -EAGAIN; + break; + default: + ret = -EAGAIN; + break; + } + } +cleanup: + osif_request_put(request); + hdd_exit(); + + return ret; +} + +/** + * hdd_send_sap_twt_del_dialog_cmd() - Send SAP TWT del dialog command + * @hdd_ctx: HDD Context + * @twt_params: Pointer to del dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static +int hdd_send_sap_twt_del_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_del_dialog_param *twt_params) +{ + QDF_STATUS status; + int ret = 0; + + status = sme_sap_del_dialog_cmd(hdd_ctx->mac_handle, + hdd_twt_del_dialog_comp_cb, + twt_params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send del dialog command"); + ret = qdf_status_to_os_return(status); + } + + return ret; +} + + +static int hdd_sap_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wmi_twt_del_dialog_param params = {0}; + QDF_STATUS status; + int id, id1, ret; + bool is_associated; + struct qdf_mac_addr mac_addr; + + params.vdev_id = adapter->deflink->vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (tb[id] && tb[id1]) { + params.dialog_id = nla_get_u8(tb[id]); + nla_memcpy(params.peer_macaddr, tb[id1], QDF_MAC_ADDR_SIZE); + } else if (!tb[id] && !tb[id1]) { + struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT; + + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + qdf_mem_copy(params.peer_macaddr, bcast_addr.bytes, + QDF_MAC_ADDR_SIZE); + } else { + hdd_err_rl("get_params dialog_id or mac_addr is missing"); + return -EINVAL; + } + + if (!params.dialog_id) + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + + if (params.dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + QDF_IS_ADDR_BROADCAST(params.peer_macaddr)) { + hdd_err("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d", + TWT_ALL_SESSIONS_DIALOG_ID, params.dialog_id); + return -EINVAL; + } + + status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, + params.dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + qdf_mem_copy(mac_addr.bytes, params.peer_macaddr, QDF_MAC_ADDR_SIZE); + + if (!qdf_is_macaddr_broadcast(&mac_addr)) { + is_associated = hdd_is_peer_associated(adapter, &mac_addr); + if (!is_associated) { + hdd_err_rl("Association doesn't exist for STA: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + /* + * Return success, since STA is not associated and + * there is no TWT session. + */ + return 0; + } + } + + hdd_debug("vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + ret = hdd_send_sap_twt_del_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + +static int hdd_sta_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = NULL; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wmi_twt_del_dialog_param params = {0}; + QDF_STATUS status; + int id, ret; + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err_rl("Invalid state, vdev %d mode %d", + adapter->deflink->vdev_id, adapter->device_mode); + + /* + * Return success, since STA is not associated and there is + * no TWT session. + */ + return 0; + } + + if (hdd_is_roaming_in_progress(hdd_ctx)) + return -EBUSY; + + if (ucfg_scan_get_pdev_status(hdd_ctx->pdev)) { + hdd_err_rl("Scan in progress"); + return -EBUSY; + } + + qdf_mem_copy(params.peer_macaddr, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->deflink->vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) { + params.dialog_id = nla_get_u8(tb[id]); + } else { + params.dialog_id = 0; + hdd_debug("TWT_TERMINATE_FLOW_ID not specified. set to zero"); + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID; + if (tb[id]) { + params.dialog_id = nla_get_u8(tb[id]); + hdd_debug("TWT_SETUP_BCAST_ID %d", params.dialog_id); + } + + status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, + params.dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params.dialog_id)) { + hdd_debug("vdev%d: TWT session %d setup incomplete", + params.vdev_id, params.dialog_id); + return -EAGAIN; + } + + hdd_debug("vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + ret = hdd_send_twt_del_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + +/** + * hdd_twt_terminate_session - Process TWT terminate + * operation in the received vendor command and + * send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_TERMINATE + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_terminate_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + enum QDF_OPMODE device_mode = adapter->device_mode; + + switch (device_mode) { + case QDF_STA_MODE: + return hdd_sta_twt_terminate_session(adapter, twt_param_attr); + case QDF_SAP_MODE: + return hdd_sap_twt_terminate_session(adapter, twt_param_attr); + default: + hdd_err_rl("TWT terminate is not supported on %s", + qdf_opmode_str(adapter->device_mode)); + return -EOPNOTSUPP; + } +} + +/** + * hdd_twt_nudge_pack_resp_nlmsg() - pack the skb with + * firmware response for twt nudge command + * @reply_skb: skb to store the response + * @params: Pointer to nudge dialog complete event buffer + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_nudge_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wmi_twt_nudge_dialog_complete_event_param *params) +{ + struct nlattr *config_attr; + int vendor_status, attr; + uint64_t tsf_val; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_NUDGE)) { + hdd_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID, + params->dialog_id)) { + hdd_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + tsf_val = params->next_twt_tsf_us_hi; + tsf_val = (tsf_val << 32) | params->next_twt_tsf_us_lo; + if (hdd_wlan_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF, + tsf_val)) { + hdd_err("get_params failed to put TSF Value"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = + wmi_twt_nudge_status_to_vendor_twt_status(params->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + hdd_err("Failed to put QCA_WLAN_TWT_NUDGE status"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params->peer_macaddr)) { + hdd_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/* + * hdd_twt_nudge_dialog_comp_cb() - callback function + * to get twt nudge command complete event + * @psoc: Pointer to global psoc + * @params: Pointer to nudge dialog complete event buffer + * + * Return: None + */ +static void hdd_twt_nudge_dialog_comp_cb( + struct wlan_objmgr_psoc *psoc, + struct wmi_twt_nudge_dialog_complete_event_param *params) +{ + + struct wlan_hdd_link_info *link_info; + struct wireless_dev *wdev; + struct hdd_context *hdd_ctx; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + + hdd_enter(); + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return; + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + wdev = &link_info->adapter->wdev; + + hdd_debug("Nudge dialog_id:%d, status:%d vdev_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params->dialog_id, + params->status, params->vdev_id, + QDF_MAC_ADDR_REF(params->peer_macaddr)); + + data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8)) + + nla_total_size(sizeof(u64)); + data_len += NLA_HDRLEN; + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, + data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("Nudge dialog alloc skb failed"); + return; + } + + status = hdd_twt_nudge_pack_resp_nlmsg(twt_vendor_event, params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl nudge dialog response %d", status); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + hdd_exit(); +} + +/** + * hdd_twt_pause_pack_resp_nlmsg() - pack the skb with + * firmware response for twt pause command + * @reply_skb: skb to store the response + * @params: Pointer to pause dialog complete event buffer + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wmi_twt_pause_dialog_complete_event_param *params) +{ + struct nlattr *config_attr; + int vendor_status, attr; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_SUSPEND)) { + hdd_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params->dialog_id)) { + hdd_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = wmi_twt_pause_status_to_vendor_twt_status(params->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + hdd_err("Failed to put QCA_WLAN_TWT_PAUSE status"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params->peer_macaddr)) { + hdd_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/* + * hdd_twt_pause_dialog_comp_cb() - callback function + * to get twt pause command complete event + * @psoc: pointer to global psoc + * @params: Pointer to pause dialog complete event buffer + * + * Return: None + */ +static void +hdd_twt_pause_dialog_comp_cb( + struct wlan_objmgr_psoc *psoc, + struct wmi_twt_pause_dialog_complete_event_param *params) +{ + struct wlan_hdd_link_info *link_info; + struct wireless_dev *wdev; + struct hdd_context *hdd_ctx; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + + hdd_enter(); + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return; + + wdev = &link_info->adapter->wdev; + + hdd_debug("pause dialog_id:%d, status:%d vdev_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params->dialog_id, + params->status, params->vdev_id, + QDF_MAC_ADDR_REF(params->peer_macaddr)); + + data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8)); + data_len += NLA_HDRLEN; + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("pause dialog alloc skb failed"); + return; + } + + status = hdd_twt_pause_pack_resp_nlmsg(twt_vendor_event, params); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl pause dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + hdd_exit(); +} + +/** + * hdd_send_twt_pause_dialog_cmd() - Send TWT pause dialog command to target + * @hdd_ctx: HDD Context + * @twt_params: Pointer to pause dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static +int hdd_send_twt_pause_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_pause_dialog_cmd_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_info_priv *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -EINVAL; + } + + context = osif_request_cookie(request); + + status = sme_pause_dialog_cmd(hdd_ctx->mac_handle, + twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send pause dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = WMI_HOST_TWT_PAUSE_DIALOG_CMDID; + + status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd); + + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status) { + hdd_err("Received TWT ack error. Reset twt command"); + ucfg_mlme_reset_twt_active_cmd( + hdd_ctx->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + switch (ack_priv->status) { + case WMI_HOST_PAUSE_TWT_STATUS_INVALID_PARAM: + case WMI_HOST_PAUSE_TWT_STATUS_ALREADY_PAUSED: + case WMI_HOST_PAUSE_TWT_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_NOT_EXIST: + ret = -EAGAIN; + break; + case WMI_HOST_PAUSE_TWT_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case WMI_HOST_PAUSE_TWT_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case WMI_HOST_PAUSE_TWT_STATUS_CHAN_SW_IN_PROGRESS: + case WMI_HOST_PAUSE_TWT_STATUS_ROAM_IN_PROGRESS: + case WMI_HOST_PAUSE_TWT_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + default: + ret = -EAGAIN; + break; + } + } +cleanup: + osif_request_put(request); + hdd_exit(); + + return ret; +} + +/** + * hdd_twt_pause_session - Process TWT pause operation + * in the received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_SUSPEND + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_pause_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wmi_twt_pause_dialog_cmd_param params = {0}; + QDF_STATUS status; + int id; + int ret; + + ret = hdd_is_twt_command_allowed(adapter); + if (ret) + return ret; + + qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->deflink->vdev_id; + params.dialog_id = 0; + + if (twt_param_attr) { + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) { + hdd_debug("command parsing failed"); + return ret; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) + params.dialog_id = nla_get_u8(tb[id]); + else + hdd_debug("TWT: FLOW_ID not specified. set to zero"); + } else { + hdd_debug("TWT param not present. flow id set to zero"); + } + + status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, + params.dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params.dialog_id)) { + hdd_debug("vdev%d: TWT session %d setup incomplete", + params.vdev_id, params.dialog_id); + return -EAGAIN; + } + + hdd_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + ret = hdd_send_twt_pause_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + +/** + * hdd_send_twt_nudge_dialog_cmd() - Send TWT nudge dialog command to target + * @hdd_ctx: HDD Context + * @twt_params: Pointer to nudge dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static +int hdd_send_twt_nudge_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_nudge_dialog_cmd_param *twt_params) +{ + QDF_STATUS status; + int twt_cmd, ret = 0; + struct osif_request *request; + struct twt_ack_info_priv *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -EINVAL; + } + + context = osif_request_cookie(request); + + status = sme_nudge_dialog_cmd(hdd_ctx->mac_handle, twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send nudge dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = WMI_HOST_TWT_NUDGE_DIALOG_CMDID; + + status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd); + + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status) { + hdd_err("Received TWT ack error. Reset twt command"); + ucfg_mlme_reset_twt_active_cmd( + hdd_ctx->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + switch (ack_priv->status) { + case WMI_HOST_NUDGE_TWT_STATUS_INVALID_PARAM: + case WMI_HOST_NUDGE_TWT_STATUS_ALREADY_PAUSED: + case WMI_HOST_NUDGE_TWT_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_NOT_EXIST: + ret = -EAGAIN; + break; + case WMI_HOST_NUDGE_TWT_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case WMI_HOST_NUDGE_TWT_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case WMI_HOST_NUDGE_TWT_STATUS_CHAN_SW_IN_PROGRESS: + case WMI_HOST_NUDGE_TWT_STATUS_ROAM_IN_PROGRESS: + case WMI_HOST_NUDGE_TWT_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + default: + ret = -EAGAIN; + break; + } + } +cleanup: + osif_request_put(request); + hdd_exit(); + + return ret; +} + +/** + * hdd_twt_nudge_session - Process TWT nudge operation + * in the received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_NUDGE + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_nudge_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1]; + struct wmi_twt_nudge_dialog_cmd_param params = {0}; + QDF_STATUS status; + int id, ret; + bool is_nudge_tgt_cap_enabled; + + ret = hdd_is_twt_command_allowed(adapter); + if (ret) + return ret; + + ucfg_mlme_get_twt_nudge_tgt_cap(adapter->hdd_ctx->psoc, + &is_nudge_tgt_cap_enabled); + if (!is_nudge_tgt_cap_enabled) { + hdd_debug("Nudge not supported by target"); + return -EOPNOTSUPP; + } + + params.vdev_id = adapter->deflink->vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX, + twt_param_attr, + qca_wlan_vendor_twt_nudge_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR; + if (tb[id]) { + nla_memcpy(params.peer_macaddr, tb[id], QDF_MAC_ADDR_SIZE); + hdd_debug("peer mac_addr "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + } else { + qdf_mem_copy(params.peer_macaddr, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID; + if (!tb[id]) { + hdd_debug("TWT: FLOW_ID not specified"); + return -EINVAL; + } + params.dialog_id = nla_get_u8(tb[id]); + + status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, + params.dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME; + if (!tb[id]) { + hdd_debug("TWT: WAKE_TIME not specified"); + return -EINVAL; + } + params.suspend_duration = nla_get_u32(tb[id]); + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE; + if (!tb[id]) { + hdd_debug("TWT: NEXT_TWT_SIZE not specified."); + return -EINVAL; + } + params.next_twt_size = nla_get_u32(tb[id]); + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params.dialog_id)) { + hdd_debug("vdev%d: TWT session %d setup incomplete", + params.vdev_id, params.dialog_id); + return -EAGAIN; + } + + hdd_debug("twt_nudge: vdev_id %d dialog_id %d ", params.vdev_id, + params.dialog_id); + hdd_debug("twt_nudge: suspend_duration %d next_twt_size %d", + params.suspend_duration, params.next_twt_size); + + ret = hdd_send_twt_nudge_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + +/** + * hdd_twt_resume_pack_resp_nlmsg() - pack the skb with + * firmware response for twt resume command + * @reply_skb: skb to store the response + * @params: Pointer to resume dialog complete event buffer + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_resume_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct wmi_twt_resume_dialog_complete_event_param *params) +{ + struct nlattr *config_attr; + int vendor_status, attr; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_RESUME)) { + hdd_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID, + params->dialog_id)) { + hdd_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = wmi_twt_resume_status_to_vendor_twt_status(params->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + hdd_err("Failed to put QCA_WLAN_TWT_RESUME status"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params->peer_macaddr)) { + hdd_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_resume_dialog_comp_cb() - callback function + * to get twt resume command complete event + * @psoc: Pointer to global psoc + * @params: Pointer to resume dialog complete event buffer + * + * Return: None + */ +static void hdd_twt_resume_dialog_comp_cb( + struct wlan_objmgr_psoc *psoc, + struct wmi_twt_resume_dialog_complete_event_param *params) +{ + struct wlan_hdd_link_info *link_info; + struct hdd_context *hdd_ctx; + struct wireless_dev *wdev; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + + hdd_enter(); + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id); + if (!link_info) { + hdd_err("Invalid vdev"); + return; + } + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) + return; + + wdev = &link_info->adapter->wdev; + + hdd_debug("TWT: resume dialog_id:%d status:%d vdev_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params->dialog_id, + params->status, params->vdev_id, + QDF_MAC_ADDR_REF(params->peer_macaddr)); + + data_len = hdd_get_twt_event_len() + nla_total_size(sizeof(u8)); + data_len += NLA_HDRLEN; + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + hdd_ctx->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("TWT: skb alloc failed"); + return; + } + + status = hdd_twt_resume_pack_resp_nlmsg(twt_vendor_event, params); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to pack nl resume dialog response"); + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + hdd_exit(); +} + +/** + * hdd_send_twt_resume_dialog_cmd() - Send TWT resume dialog command to target + * @hdd_ctx: HDD Context + * @twt_params: Pointer to resume dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static int +hdd_send_twt_resume_dialog_cmd(struct hdd_context *hdd_ctx, + struct wmi_twt_resume_dialog_cmd_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_info_priv *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + hdd_enter(); + + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -EINVAL; + } + + context = osif_request_cookie(request); + + status = sme_resume_dialog_cmd(hdd_ctx->mac_handle, + twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to send resume dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = WMI_HOST_TWT_RESUME_DIALOG_CMDID; + + status = hdd_twt_ack_wait_response(hdd_ctx, request, twt_cmd); + + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status) { + hdd_err("Received TWT ack error. Reset twt command"); + ucfg_mlme_reset_twt_active_cmd( + hdd_ctx->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + switch (ack_priv->status) { + case WMI_HOST_RESUME_TWT_STATUS_INVALID_PARAM: + case WMI_HOST_RESUME_TWT_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_NOT_EXIST: + case WMI_HOST_RESUME_TWT_STATUS_NOT_PAUSED: + ret = -EAGAIN; + break; + case WMI_HOST_RESUME_TWT_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case WMI_HOST_RESUME_TWT_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case WMI_HOST_RESUME_TWT_STATUS_CHAN_SW_IN_PROGRESS: + case WMI_HOST_RESUME_TWT_STATUS_ROAM_IN_PROGRESS: + case WMI_HOST_RESUME_TWT_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + default: + ret = -EAGAIN; + break; + } + } +cleanup: + osif_request_put(request); + hdd_exit(); + + return ret; +} + +/** + * hdd_twt_pack_get_capabilities_resp - TWT pack and send response to + * userspace for get capabilities command + * @adapter: Pointer to hdd adapter + * + * Return: QDF_STATUS + */ +static QDF_STATUS +hdd_twt_pack_get_capabilities_resp(struct hdd_adapter *adapter) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *config_attr; + struct sk_buff *reply_skb; + size_t skb_len = NLMSG_HDRLEN; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + uint8_t connected_band; + uint8_t peer_cap = 0, self_cap = 0; + bool twt_req = false, twt_bcast_req = false; + bool is_twt_24ghz_allowed = true; + int ret; + + /* + * Length of attribute QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF & + * QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER + */ + skb_len += 2 * nla_total_size(sizeof(u16)) + NLA_HDRLEN; + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, + skb_len); + if (!reply_skb) { + hdd_err("TWT: get_caps alloc reply skb failed"); + return QDF_STATUS_E_NOMEM; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("TWT: nla_nest_start error"); + qdf_status = QDF_STATUS_E_FAILURE; + goto free_skb; + } + + /* + * Userspace will query the TWT get capabilities before + * issuing a get capabilities request. For legacy connection, + * if the STA is connected, then check the "enable_twt_24ghz" + * ini value to advertise the TWT requestor capability. + * For MLO connection, TWT requestor capabilities are advertised + * irrespective of connected band. + */ + if (!mlo_is_mld_sta(adapter->deflink->vdev)) { + connected_band = hdd_conn_get_connected_band(adapter->deflink); + if (connected_band == BAND_2G && + !ucfg_mlme_is_24ghz_twt_enabled(hdd_ctx->psoc)) + is_twt_24ghz_allowed = false; + } else { + is_twt_24ghz_allowed = true; + } + + /* fill the self_capability bitmap */ + ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &twt_req); + if (twt_req && is_twt_24ghz_allowed) + self_cap |= QCA_WLAN_TWT_CAPA_REQUESTOR; + + ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc, + &twt_bcast_req); + self_cap |= (twt_bcast_req ? QCA_WLAN_TWT_CAPA_BROADCAST : 0); + + if (ucfg_mlme_is_flexible_twt_enabled(hdd_ctx->psoc)) + self_cap |= QCA_WLAN_TWT_CAPA_FLEXIBLE; + + /* Fill the Peer capability bitmap */ + peer_cap = ucfg_mlme_get_twt_peer_capabilities( + hdd_ctx->psoc, + (struct qdf_mac_addr *)sta_ctx->conn_info.bssid.bytes); + + if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF, + self_cap)) { + hdd_err("TWT: Failed to fill capabilities"); + qdf_status = QDF_STATUS_E_FAILURE; + goto free_skb; + } + + if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER, + peer_cap)) { + hdd_err("TWT: Failed to fill capabilities"); + qdf_status = QDF_STATUS_E_FAILURE; + goto free_skb; + } + + nla_nest_end(reply_skb, config_attr); + + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + return qdf_status_from_os_return(ret); + +free_skb: + wlan_cfg80211_vendor_free_skb(reply_skb); + return qdf_status; +} + +/** + * hdd_twt_get_capabilities() - Process TWT get capabilities + * in the received vendor command. + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_GET_CAPABILITIES + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_get_capabilities(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + int ret = 0; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret < 0) + return -EINVAL; + + if (adapter->device_mode != QDF_STA_MODE && + adapter->device_mode != QDF_P2P_CLIENT_MODE) { + return -EOPNOTSUPP; + } + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err_rl("vdev %d not in connected state, mode %d", + adapter->deflink->vdev_id, adapter->device_mode); + return -EAGAIN; + } + + if (hdd_is_roaming_in_progress(hdd_ctx)) + return -EBUSY; + + status = hdd_twt_pack_get_capabilities_resp(adapter); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err_rl("TWT: Get capabilities failed"); + + return qdf_status_to_os_return(status); +} + +/** + * hdd_twt_resume_session - Process TWT resume operation + * in the received vendor command and send it to firmware + * @adapter: adapter pointer + * @twt_param_attr: nl attributes + * + * Handles QCA_WLAN_TWT_RESUME + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_resume_session(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1]; + struct wmi_twt_resume_dialog_cmd_param params = {0}; + QDF_STATUS status; + int id, id2; + int ret; + + ret = hdd_is_twt_command_allowed(adapter); + if (ret) + return ret; + + qdf_mem_copy(params.peer_macaddr, hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + params.vdev_id = adapter->deflink->vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX, + twt_param_attr, + qca_wlan_vendor_twt_resume_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID; + if (tb[id]) { + params.dialog_id = nla_get_u8(tb[id]); + } else { + params.dialog_id = 0; + hdd_debug("TWT_RESUME_FLOW_ID not specified. set to zero"); + } + + status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, + params.dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + params.dialog_id)) { + hdd_debug("vdev%d: TWT session %d setup incomplete", + params.vdev_id, params.dialog_id); + return -EAGAIN; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT; + id2 = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT; + if (tb[id2]) + params.sp_offset_us = nla_get_u32(tb[id2]); + else if (tb[id]) + params.sp_offset_us = nla_get_u8(tb[id]); + else + params.sp_offset_us = 0; + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE; + if (tb[id]) { + params.next_twt_size = nla_get_u32(tb[id]); + } else { + hdd_err_rl("TWT_RESUME NEXT_TWT_SIZE is must"); + return -EINVAL; + } + if (params.next_twt_size > TWT_MAX_NEXT_TWT_SIZE) + return -EINVAL; + + hdd_debug("twt_resume: vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr)); + + ret = hdd_send_twt_resume_dialog_cmd(adapter->hdd_ctx, ¶ms); + + return ret; +} + +static uint32_t get_session_wake_duration(struct hdd_context *hdd_ctx, + uint32_t dialog_id, + struct qdf_mac_addr *peer_macaddr) +{ + struct wmi_host_twt_session_stats_info params = {0}; + int num_twt_session = 0; + + params.dialog_id = dialog_id; + qdf_mem_copy(params.peer_mac, + peer_macaddr->bytes, + QDF_MAC_ADDR_SIZE); + hdd_debug("Get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params.peer_mac)); + + num_twt_session = ucfg_twt_get_peer_session_params(hdd_ctx->psoc, + ¶ms); + if (num_twt_session) + return params.wake_dura_us; + + return 0; +} + +static int +wmi_twt_get_stats_status_to_vendor_twt_status(enum WMI_HOST_GET_STATS_TWT_STATUS status) +{ + switch (status) { + case WMI_HOST_GET_STATS_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case WMI_HOST_GET_STATS_TWT_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case WMI_HOST_GET_STATS_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * hdd_twt_pack_get_stats_resp_nlmsg()- Packs and sends twt get stats response + * @hdd_ctx: pointer to the hdd context + * @reply_skb: pointer to response skb buffer + * @params: Pointer to twt session parameter buffer + * @num_session_stats: number of twt statistics + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_pack_get_stats_resp_nlmsg(struct hdd_context *hdd_ctx, + struct sk_buff *reply_skb, + struct twt_infra_cp_stats_event *params, + uint32_t num_session_stats) +{ + struct nlattr *config_attr, *nla_params; + int i, attr; + int vendor_status; + uint32_t duration; + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + hdd_err("get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_session_stats; i++) { + + nla_params = nla_nest_start(reply_skb, i); + if (!nla_params) { + hdd_err("get_stats nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params[i].peer_macaddr.bytes)) { + hdd_err("get_stats failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + hdd_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[i].peer_macaddr.bytes)); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) { + hdd_err("get_stats failed to put dialog_id"); + return QDF_STATUS_E_INVAL; + } + + duration = get_session_wake_duration(hdd_ctx, + params[i].dialog_id, + ¶ms[i].peer_macaddr); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, duration)) { + hdd_err("get_params failed to put Wake duration"); + return QDF_STATUS_E_INVAL; + } + hdd_debug("dialog_id %d wake duration %d num sp cycles %d", + params[i].dialog_id, duration, + params[i].num_sp_cycles); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS; + if (nla_put_u32(reply_skb, attr, params[i].num_sp_cycles)) { + hdd_err("get_params failed to put num_sp_cycles"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].avg_sp_dur_us)) { + hdd_err("get_params failed to put avg_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].min_sp_dur_us)) { + hdd_err("get_params failed to put min_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].max_sp_dur_us)) { + hdd_err("get_params failed to put max_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU; + if (nla_put_u32(reply_skb, attr, params[i].tx_mpdu_per_sp)) { + hdd_err("get_params failed to put tx_mpdu_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU; + if (nla_put_u32(reply_skb, attr, params[i].rx_mpdu_per_sp)) { + hdd_err("get_params failed to put rx_mpdu_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE; + if (nla_put_u32(reply_skb, attr, params[i].tx_bytes_per_sp)) { + hdd_err("get_params failed to put tx_bytes_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE; + if (nla_put_u32(reply_skb, attr, params[i].rx_bytes_per_sp)) { + hdd_err("get_params failed to put rx_bytes_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS; + vendor_status = wmi_twt_get_stats_status_to_vendor_twt_status(params[i].status); + if (nla_put_u32(reply_skb, attr, vendor_status)) { + hdd_err("get_params failed to put status"); + return QDF_STATUS_E_INVAL; + } + nla_nest_end(reply_skb, nla_params); + } + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_clear_session_traffic_stats() - Parses twt nl attributes and + * sends clear twt stats request for a single or all sessions + * @adapter: hdd_adapter + * @twt_param_attr: twt nl attributes + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_clear_session_traffic_stats(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1]; + int ret, id; + uint32_t dialog_id; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + bool is_stats_tgt_cap_enabled; + QDF_STATUS status; + + ret = wlan_cfg80211_nla_parse_nested( + tb, + QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX, + twt_param_attr, + qca_wlan_vendor_twt_stats_dialog_policy); + if (ret) + return ret; + + ucfg_mlme_get_twt_statistics_tgt_cap(adapter->hdd_ctx->psoc, + &is_stats_tgt_cap_enabled); + if (!is_stats_tgt_cap_enabled) { + hdd_debug("TWT Stats not supported by target"); + return -EOPNOTSUPP; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (!tb[id]) { + hdd_err_rl("TWT Clear stats - dialog id param is must"); + return -EINVAL; + } + + dialog_id = (uint32_t)nla_get_u8(tb[id]); + + qdf_mem_copy(peer_mac, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + hdd_debug("dialog_id %d peer mac_addr " QDF_MAC_ADDR_FMT, + dialog_id, QDF_MAC_ADDR_REF(peer_mac)); + + status = hdd_twt_check_all_twt_support(adapter->hdd_ctx->psoc, + dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + if (ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_STATISTICS, NULL) || + ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_CLEAR_STATISTICS, + NULL)) { + hdd_warn("Already TWT statistics or clear statistics exists"); + return -EALREADY; + } + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + dialog_id)) { + hdd_debug("TWT session %d setup incomplete", dialog_id); + return -EAGAIN; + } + + ret = wlan_cfg80211_mc_twt_clear_infra_cp_stats(adapter->deflink->vdev, + dialog_id, peer_mac); + + return ret; +} + +/** + * hdd_twt_request_session_traffic_stats() - Obtains twt session + * traffic statistics and sends response to the user space + * @adapter: hdd_adapter + * @dialog_id: dialog id of the twt session + * @peer_mac: Mac address of the peer + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +hdd_twt_request_session_traffic_stats(struct hdd_adapter *adapter, + uint32_t dialog_id, uint8_t *peer_mac) +{ + int errno; + int skb_len; + struct sk_buff *reply_skb; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct infra_cp_stats_event *event; + + if (!adapter || !peer_mac) + return status; + + event = wlan_cfg80211_mc_twt_get_infra_cp_stats(adapter->deflink->vdev, + dialog_id, + peer_mac, + &errno); + if (!event) + return qdf_status_from_os_return(errno); + + skb_len = hdd_get_twt_get_stats_event_len(); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + adapter->hdd_ctx->wiphy, + skb_len); + if (!reply_skb) { + hdd_err("Get stats - alloc reply_skb failed"); + status = QDF_STATUS_E_NOMEM; + goto free_event; + } + + status = hdd_twt_pack_get_stats_resp_nlmsg( + adapter->hdd_ctx, + reply_skb, + event->twt_infra_cp_stats, + event->num_twt_infra_cp_stats); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get stats - Failed to pack nl response"); + goto free_skb; + } + + qdf_mem_free(event->twt_infra_cp_stats); + qdf_mem_free(event); + + errno = wlan_cfg80211_vendor_cmd_reply(reply_skb); + return qdf_status_from_os_return(errno); + +free_skb: + wlan_cfg80211_vendor_free_skb(reply_skb); + +free_event: + qdf_mem_free(event->twt_infra_cp_stats); + qdf_mem_free(event); + + return status; +} + +/** + * hdd_twt_get_session_traffic_stats() - Parses twt nl attributes, obtains twt + * session parameters based on dialog_id and returns to user via nl layer + * @adapter: hdd_adapter + * @twt_param_attr: twt nl attributes + * + * Return: 0 on success, negative value on failure + */ +static int hdd_twt_get_session_traffic_stats(struct hdd_adapter *adapter, + struct nlattr *twt_param_attr) +{ + struct hdd_station_ctx *hdd_sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1]; + int ret, id; + QDF_STATUS qdf_status; + uint32_t dialog_id; + uint8_t peer_mac[QDF_MAC_ADDR_SIZE]; + bool is_stats_tgt_cap_enabled; + + ret = wlan_cfg80211_nla_parse_nested( + tb, + QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX, + twt_param_attr, + qca_wlan_vendor_twt_stats_dialog_policy); + if (ret) + return ret; + + ucfg_mlme_get_twt_statistics_tgt_cap(adapter->hdd_ctx->psoc, + &is_stats_tgt_cap_enabled); + if (!is_stats_tgt_cap_enabled) { + hdd_debug("TWT Stats not supported by target"); + return -EOPNOTSUPP; + } + + if (ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_STATISTICS, NULL) || + ucfg_mlme_twt_is_command_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_CLEAR_STATISTICS, + NULL)) { + hdd_warn("Already TWT statistics or clear statistics exists"); + return -EALREADY; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (tb[id]) + dialog_id = (uint32_t)nla_get_u8(tb[id]); + else + dialog_id = 0; + + hdd_debug("get_stats dialog_id %d", dialog_id); + + qdf_mem_copy(peer_mac, + hdd_sta_ctx->conn_info.bssid.bytes, + QDF_MAC_ADDR_SIZE); + hdd_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac)); + + if (!ucfg_mlme_is_twt_setup_done(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + dialog_id)) { + hdd_debug("TWT session %d setup incomplete", dialog_id); + return -EAGAIN; + } + + ucfg_mlme_set_twt_command_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + dialog_id, + WLAN_TWT_STATISTICS); + qdf_status = hdd_twt_request_session_traffic_stats(adapter, + dialog_id, peer_mac); + ucfg_mlme_set_twt_command_in_progress(adapter->hdd_ctx->psoc, + &hdd_sta_ctx->conn_info.bssid, + dialog_id, + WLAN_TWT_NONE); + + return qdf_status_to_os_return(qdf_status); +} + +/** + * hdd_twt_notify_pack_nlmsg() - pack the skb with + * twt notify event from firmware + * @reply_skb: skb to store the response + * + * Return: QDF_STATUS_SUCCESS on Success, QDF_STATUS_E_FAILURE + * on failure + */ +static QDF_STATUS +hdd_twt_notify_pack_nlmsg(struct sk_buff *reply_skb) +{ + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_SETUP_READY_NOTIFY)) { + hdd_err("Failed to put TWT notify operation"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_twt_notify_cb() - callback function + * to get twt notify event + * @psoc: Pointer to global psoc + * @params: Pointer to notify param event buffer + * + * Return: None + */ +static void +hdd_twt_notify_cb(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_notify_event_param *params) +{ + struct wlan_hdd_link_info *link_info; + struct wireless_dev *wdev; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + + hdd_enter(); + + link_info = wlan_hdd_get_link_info_from_vdev(psoc, params->vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return; + + wdev = &link_info->adapter->wdev; + + data_len = NLA_HDRLEN; + data_len += nla_total_size(sizeof(u8)); + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, + data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + hdd_err("Notify skb alloc failed"); + return; + } + + hdd_debug("Notify vdev_id %d", params->vdev_id); + + status = hdd_twt_notify_pack_nlmsg(twt_vendor_event); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to pack nl notify event"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + return; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + + hdd_exit(); +} + +/** + * hdd_twt_configure - Process the TWT + * operation in the received vendor command + * @adapter: adapter pointer + * @tb: nl attributes + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION + * + * Return: 0 for Success and negative value for failure + */ +static int hdd_twt_configure(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + enum qca_wlan_twt_operation twt_oper; + struct nlattr *twt_oper_attr; + struct nlattr *twt_param_attr; + uint32_t id; + int ret = 0; + + id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION; + twt_oper_attr = tb[id]; + + if (!twt_oper_attr) { + hdd_err("TWT operation NOT specified"); + return -EINVAL; + } + + twt_oper = nla_get_u8(twt_oper_attr); + + id = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS; + twt_param_attr = tb[id]; + + if (!twt_param_attr && + twt_oper != QCA_WLAN_TWT_GET_CAPABILITIES && + twt_oper != QCA_WLAN_TWT_SUSPEND) { + hdd_err("TWT parameters NOT specified"); + return -EINVAL; + } + + hdd_debug("TWT Operation 0x%x", twt_oper); + + switch (twt_oper) { + case QCA_WLAN_TWT_SET: + ret = hdd_twt_setup_session(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_GET: + ret = hdd_twt_get_session_params(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_TERMINATE: + ret = hdd_twt_terminate_session(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_SUSPEND: + ret = hdd_twt_pause_session(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_RESUME: + ret = hdd_twt_resume_session(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_NUDGE: + ret = hdd_twt_nudge_session(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_GET_CAPABILITIES: + ret = hdd_twt_get_capabilities(adapter, twt_param_attr); + break; + case QCA_WLAN_TWT_GET_STATS: + ret = hdd_twt_get_session_traffic_stats(adapter, + twt_param_attr); + break; + case QCA_WLAN_TWT_CLEAR_STATS: + ret = hdd_twt_clear_session_traffic_stats(adapter, + twt_param_attr); + break; + case QCA_WLAN_TWT_SET_PARAM: + ret = hdd_twt_set_param(adapter, twt_param_attr); + break; + default: + hdd_err("Invalid TWT Operation"); + ret = -EINVAL; + break; + } + + return ret; +} + +void hdd_update_tgt_twt_cap(struct hdd_context *hdd_ctx, + struct wma_tgt_cfg *cfg) +{ + struct wma_tgt_services *services = &cfg->services; + bool twt_bcast_req; + bool twt_bcast_res; + bool twt_req, twt_res, enable_twt; + + enable_twt = ucfg_mlme_is_twt_enabled(hdd_ctx->psoc); + + ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &twt_req); + + ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &twt_res); + + ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc, + &twt_bcast_req); + + ucfg_mlme_get_twt_bcast_responder(hdd_ctx->psoc, + &twt_bcast_res); + + hdd_debug("ini: enable_twt=%d, bcast_req=%d, bcast_res=%d", + enable_twt, twt_bcast_req, twt_bcast_res); + hdd_debug("ini: twt_req=%d, twt_res=%d", twt_req, twt_res); + hdd_debug("svc: req=%d, res=%d, bcast_req=%d, bcast_res=%d legacy_bcast_twt:%d", + services->twt_requestor, services->twt_responder, + cfg->twt_bcast_req_support, cfg->twt_bcast_res_support, + cfg->legacy_bcast_twt_support); + + /* + * Set the twt fw responder service capability + */ + ucfg_mlme_set_twt_res_service_cap(hdd_ctx->psoc, + services->twt_responder); + /* + * The HE cap IE in frame will have intersection of + * "enable_twt" ini, twt requestor fw service cap and + * "twt_requestor" ini requestor bit after this + * set operation. + */ + ucfg_mlme_set_twt_requestor(hdd_ctx->psoc, + QDF_MIN(services->twt_requestor, + (enable_twt && twt_req))); + + /* + * The HE cap IE in frame will have intersection of + * "enable_twt" ini, twt responder fw service cap and + * "twt_responder" ini responder bit after this + * set operation. + */ + ucfg_mlme_set_twt_responder(hdd_ctx->psoc, + QDF_MIN(services->twt_responder, + (enable_twt && twt_res))); + /* + * The HE cap IE in frame will have intersection of + * "enable_twt" ini, twt requestor fw service cap and + * "twt_bcast_req_resp_config" ini requestor bit after this + * set operation. + */ + ucfg_mlme_set_twt_bcast_requestor( + hdd_ctx->psoc, + QDF_MIN((cfg->twt_bcast_req_support || + cfg->legacy_bcast_twt_support), + (enable_twt && twt_bcast_req))); + + /* + * The HE cap IE in frame will have intersection of + * "enable_twt" ini, twt responder fw service cap and + * "twt_bcast_req_resp_config" ini responder bit after this + * set operation. + */ + ucfg_mlme_set_twt_bcast_responder( + hdd_ctx->psoc, + QDF_MIN((cfg->twt_bcast_res_support || + cfg->legacy_bcast_twt_support), + (enable_twt && twt_bcast_res))); + + ucfg_mlme_set_twt_nudge_tgt_cap(hdd_ctx->psoc, cfg->twt_nudge_enabled); + ucfg_mlme_set_twt_all_twt_tgt_cap(hdd_ctx->psoc, + cfg->all_twt_enabled); + ucfg_mlme_set_twt_statistics_tgt_cap(hdd_ctx->psoc, + cfg->twt_stats_enabled); +} + +QDF_STATUS hdd_send_twt_requestor_enable_cmd(struct hdd_context *hdd_ctx) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + struct twt_enable_disable_conf twt_en_dis = {0}; + bool is_requestor_en, twt_bcast_requestor = false; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + ucfg_mlme_get_twt_requestor(hdd_ctx->psoc, &is_requestor_en); + ucfg_mlme_get_twt_bcast_requestor(hdd_ctx->psoc, &twt_bcast_requestor); + twt_en_dis.bcast_en = twt_bcast_requestor; + + ucfg_mlme_get_twt_congestion_timeout(hdd_ctx->psoc, + &twt_en_dis.congestion_timeout); + hdd_debug("TWT mlme cfg:req: %d, bcast:%d, cong:%d, pdev:%d", + is_requestor_en, twt_en_dis.bcast_en, + twt_en_dis.congestion_timeout, pdev_id); + + /* The below code takes care of the following : + * If user wants to separately enable requestor role, and also the + * broadcast TWT capabilities separately for each role. This is done + * by reusing the INI configuration to indicate the user preference + * and sending the command accordingly. + * Legacy targets did not provide this. Newer targets provide this. + * + * 1. The MLME config holds the intersection of fw cap and user config + * 2. This may result in two enable commands sent for legacy, but + * that's fine, since the firmware returns harmlessly for the + * second command. + * 3. The new two parameters in the enable command are ignored + * by legacy targets, and honored by new targets. + */ + + /* If requestor configured, send requestor bcast/ucast config */ + if (is_requestor_en) { + twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR; + twt_en_dis.ext_conf_present = true; + if (twt_bcast_requestor) + twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST; + else + twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL; + + ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, true); + qdf_event_reset(&hdd_ctx->twt_enable_comp_evt); + + wma_send_twt_enable_cmd(pdev_id, &twt_en_dis); + status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt, + TWT_ENABLE_COMPLETE_TIMEOUT); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_warn("TWT Requestor Enable timedout"); + ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, false); + } + } + + return status; +} + +QDF_STATUS hdd_send_twt_responder_enable_cmd(struct hdd_context *hdd_ctx) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + struct twt_enable_disable_conf twt_en_dis = {0}; + bool is_responder_en, twt_bcast_responder = false; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + ucfg_mlme_get_twt_responder(hdd_ctx->psoc, &is_responder_en); + ucfg_mlme_get_twt_bcast_responder(hdd_ctx->psoc, &twt_bcast_responder); + twt_en_dis.bcast_en = twt_bcast_responder; + + hdd_debug("TWT responder mlme cfg:res:%d, bcast:%d, pdev:%d", + is_responder_en, twt_en_dis.bcast_en, pdev_id); + + /* The below code takes care of the following : + * If user wants to separately enable responder roles, and also the + * broadcast TWT capabilities separately for each role. This is done + * by reusing the INI configuration to indicate the user preference + * and sending the command accordingly. + * Legacy targets did not provide this. Newer targets provide this. + * + * 1. The MLME config holds the intersection of fw cap and user config + * 2. This may result in two enable commands sent for legacy, but + * that's fine, since the firmware returns harmlessly for the + * second command. + * 3. The new two parameters in the enable command are ignored + * by legacy targets, and honored by new targets. + */ + + /* If responder configured, send responder bcast/ucast config */ + if (is_responder_en) { + twt_en_dis.role = WMI_TWT_ROLE_RESPONDER; + twt_en_dis.ext_conf_present = true; + if (twt_bcast_responder) + twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST; + else + twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL; + + ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, true); + qdf_event_reset(&hdd_ctx->twt_enable_comp_evt); + wma_send_twt_enable_cmd(pdev_id, &twt_en_dis); + status = qdf_wait_single_event(&hdd_ctx->twt_enable_comp_evt, + TWT_ENABLE_COMPLETE_TIMEOUT); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_warn("TWT Responder Enable timedout"); + ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, false); + } + } + + return status; +} + +QDF_STATUS hdd_send_twt_requestor_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + struct twt_enable_disable_conf twt_en_dis = {0}; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + hdd_debug("TWT requestor disable cmd: pdev:%d", pdev_id); + + /* Set MLME TWT flag */ + ucfg_mlme_set_twt_requestor_flag(hdd_ctx->psoc, false); + + /* One disable should be fine, with extended configuration + * set to false, and extended arguments will be ignored by target + */ + twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR; + hdd_ctx->twt_state = TWT_DISABLE_REQUESTED; + twt_en_dis.ext_conf_present = true; + qdf_event_reset(&hdd_ctx->twt_disable_comp_evt); + + wma_send_twt_disable_cmd(pdev_id, &twt_en_dis); + + status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt, + TWT_DISABLE_COMPLETE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) + goto timeout; + + return status; + +timeout: + hdd_warn("TWT Requestor disable timedout"); + return status; +} + +QDF_STATUS hdd_send_twt_responder_disable_cmd(struct hdd_context *hdd_ctx, + uint32_t reason) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + struct twt_enable_disable_conf twt_en_dis = {0}; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + hdd_debug("TWT responder disable cmd: pdev:%d", pdev_id); + + /* Set MLME TWT flag */ + ucfg_mlme_set_twt_responder_flag(hdd_ctx->psoc, false); + + /* One disable should be fine, with extended configuration + * set to false, and extended arguments will be ignored by target + */ + twt_en_dis.role = WMI_TWT_ROLE_RESPONDER; + hdd_ctx->twt_state = TWT_DISABLE_REQUESTED; + twt_en_dis.ext_conf_present = true; + qdf_event_reset(&hdd_ctx->twt_disable_comp_evt); + wma_send_twt_disable_cmd(pdev_id, &twt_en_dis); + + status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt, + TWT_DISABLE_COMPLETE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) + goto timeout; + + return status; + +timeout: + hdd_warn("TWT Responder disable timedout"); + return status; +} + +/** + * hdd_twt_enable_comp_cb() - TWT enable complete event callback + * @hdd_handle: Pointer to opaque HDD handle + * @params: Pointer to TWT enable completion parameters + * + * Return: None + */ +static void +hdd_twt_enable_comp_cb(hdd_handle_t hdd_handle, + struct wmi_twt_enable_complete_event_param *params) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + enum twt_status prev_state; + QDF_STATUS status; + + prev_state = hdd_ctx->twt_state; + if (params->status == WMI_HOST_ENABLE_TWT_STATUS_OK || + params->status == WMI_HOST_ENABLE_TWT_STATUS_ALREADY_ENABLED) { + switch (prev_state) { + case TWT_FW_TRIGGER_ENABLE_REQUESTED: + hdd_ctx->twt_state = TWT_FW_TRIGGER_ENABLED; + break; + case TWT_HOST_TRIGGER_ENABLE_REQUESTED: + hdd_ctx->twt_state = TWT_HOST_TRIGGER_ENABLED; + break; + default: + break; + } + } + + if (params->status == WMI_HOST_ENABLE_TWT_INVALID_PARAM || + params->status == WMI_HOST_ENABLE_TWT_STATUS_UNKNOWN_ERROR) + hdd_ctx->twt_state = TWT_INIT; + + hdd_debug("TWT: pdev ID:%d, status:%d State transitioned from %d to %d", + params->pdev_id, params->status, + prev_state, hdd_ctx->twt_state); + + status = qdf_event_set(&hdd_ctx->twt_enable_comp_evt); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to set twt_enable_comp_evt"); +} + +/** + * hdd_twt_disable_comp_cb() - TWT disable complete event callback + * @hdd_handle: opaque handle for the global HDD Context + * + * Return: None + */ +static void +hdd_twt_disable_comp_cb(hdd_handle_t hdd_handle) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + enum twt_status prev_state; + QDF_STATUS status; + + prev_state = hdd_ctx->twt_state; + /* Do not change the state for role specific disables */ + if (hdd_ctx->twt_state == TWT_DISABLE_REQUESTED) + hdd_ctx->twt_state = TWT_DISABLED; + + hdd_debug("TWT: State transitioned from %d to %d", + prev_state, hdd_ctx->twt_state); + + status = qdf_event_set(&hdd_ctx->twt_disable_comp_evt); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set twt_disable_comp_evt"); +} + +void hdd_send_twt_role_disable_cmd(struct hdd_context *hdd_ctx, + enum twt_role role) +{ + uint8_t pdev_id = hdd_ctx->pdev->pdev_objmgr.wlan_pdev_id; + struct twt_enable_disable_conf twt_en_dis = {0}; + QDF_STATUS status; + + hdd_debug("TWT disable cmd :pdev:%d : %d", pdev_id, role); + + if ((role == TWT_REQUESTOR) || (role == TWT_REQUESTOR_INDV)) { + twt_en_dis.ext_conf_present = true; + twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR; + twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL; + wma_send_twt_disable_cmd(pdev_id, &twt_en_dis); + } + + if (role == TWT_REQUESTOR_BCAST) { + twt_en_dis.ext_conf_present = true; + twt_en_dis.role = WMI_TWT_ROLE_REQUESTOR; + twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST; + wma_send_twt_disable_cmd(pdev_id, &twt_en_dis); + } + + if ((role == TWT_RESPONDER) || (role == TWT_RESPONDER_INDV)) { + twt_en_dis.ext_conf_present = true; + twt_en_dis.role = WMI_TWT_ROLE_RESPONDER; + twt_en_dis.oper = WMI_TWT_OPERATION_INDIVIDUAL; + wma_send_twt_disable_cmd(pdev_id, &twt_en_dis); + } + + if (role == TWT_RESPONDER_BCAST) { + twt_en_dis.ext_conf_present = true; + twt_en_dis.role = WMI_TWT_ROLE_RESPONDER; + twt_en_dis.oper = WMI_TWT_OPERATION_BROADCAST; + wma_send_twt_disable_cmd(pdev_id, &twt_en_dis); + } + + status = qdf_wait_single_event(&hdd_ctx->twt_disable_comp_evt, + TWT_DISABLE_COMPLETE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_warn("TWT request disable timedout"); + return; + } +} + +void hdd_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct twt_conc_arg *twt_arg = arg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + hdd_debug("Concurrency exist on SAP vdev"); + status = hdd_send_twt_responder_disable_cmd(twt_arg->hdd_ctx, + 0); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("TWT responder disable cmd to firmware failed"); + return; + } + sme_twt_update_beacon_template(twt_arg->hdd_ctx->mac_handle); + } + + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + hdd_debug("Concurrency exist on STA vdev"); + status = hdd_send_twt_requestor_disable_cmd(twt_arg->hdd_ctx, + 0); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("TWT requestor disable cmd to firmware failed"); + return; + } + } +} + +void hdd_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct twt_conc_arg *twt_arg = arg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + hdd_debug("Concurrency exist on SAP vdev"); + status = hdd_send_twt_responder_disable_cmd(twt_arg->hdd_ctx, + 0); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("TWT responder disable cmd to firmware failed"); + return; + } + sme_twt_update_beacon_template(twt_arg->hdd_ctx->mac_handle); + } + + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + hdd_debug("Concurrency exist on STA vdev"); + status = hdd_send_twt_requestor_disable_cmd(twt_arg->hdd_ctx, + 0); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("TWT requestor disable cmd to firmware failed"); + return; + } + } +} + +void hdd_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct twt_conc_arg *twt_arg = arg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + hdd_debug("SAP vdev exist"); + status = hdd_send_twt_responder_enable_cmd(twt_arg->hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("TWT responder enable cmd to firmware failed"); + return; + } + sme_twt_update_beacon_template(twt_arg->hdd_ctx->mac_handle); + } + + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + hdd_debug("STA vdev exist"); + status = hdd_send_twt_requestor_enable_cmd(twt_arg->hdd_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("TWT requestor enable cmd to firmware failed"); + return; + } + } +} + +void __hdd_twt_update_work_handler(struct hdd_context *hdd_ctx) +{ + struct twt_conc_arg twt_arg; + uint32_t num_connections = 0, sap_count = 0, sta_count = 0; + int ret; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) { + hdd_err("Invalid HDD context"); + return; + } + num_connections = policy_mgr_get_connection_count(hdd_ctx->psoc); + sta_count = policy_mgr_mode_specific_connection_count(hdd_ctx->psoc, + PM_STA_MODE, + NULL); + sap_count = policy_mgr_get_sap_mode_count(hdd_ctx->psoc, NULL); + twt_arg.hdd_ctx = hdd_ctx; + + hdd_debug("Total connection %d, sta_count %d, sap_count %d", + num_connections, sta_count, sap_count); + switch (num_connections) { + case 0: + break; + case 1: + if (sta_count == 1) { + hdd_send_twt_requestor_enable_cmd(hdd_ctx); + } else if (sap_count == 1) { + hdd_send_twt_responder_enable_cmd(hdd_ctx); + sme_twt_update_beacon_template(hdd_ctx->mac_handle); + } + break; + case 2: + if (policy_mgr_current_concurrency_is_scc(hdd_ctx->psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + hdd_ctx->pdev, + WLAN_VDEV_OP, + hdd_twt_concurrency_update_on_scc, + &twt_arg, 0, + WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("2port concurrency,SAP/STA not in SCC"); + return; + } + } else if (policy_mgr_current_concurrency_is_mcc( + hdd_ctx->psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + hdd_ctx->pdev, + WLAN_VDEV_OP, + hdd_twt_concurrency_update_on_mcc, + &twt_arg, 0, + WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("2port concurrency,SAP/STA not in MCC"); + return; + } + } else if (policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + hdd_ctx->pdev, + WLAN_VDEV_OP, + hdd_twt_concurrency_update_on_dbs, + &twt_arg, 0, + WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("2port concurrency,SAP/STA not in DBS"); + return; + } + } + break; + case 3: + if (policy_mgr_current_concurrency_is_scc(hdd_ctx->psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + hdd_ctx->pdev, + WLAN_VDEV_OP, + hdd_twt_concurrency_update_on_scc, + &twt_arg, 0, + WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("3port concurrency,SAP/STA not in SCC"); + return; + } + } + if (policy_mgr_current_concurrency_is_mcc(hdd_ctx->psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + hdd_ctx->pdev, + WLAN_VDEV_OP, + hdd_twt_concurrency_update_on_mcc, + &twt_arg, 0, + WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("3port concurrency,SAP/STA not in MCC"); + return; + } + } + break; + default: + hdd_debug("Unexpected number of connection"); + break; + } +} + +void hdd_twt_update_work_handler(void *data) +{ + struct hdd_context *hdd_ctx = (struct hdd_context *)data; + struct osif_psoc_sync *psoc_sync; + int ret; + + ret = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), &psoc_sync); + + if (ret == -EAGAIN) { + qdf_sleep(TWT_WORK_RESCHED_WAIT_TIME); + hdd_debug("rescheduling TWT work"); + wlan_twt_concurrency_update(hdd_ctx); + return; + } else if (ret) { + hdd_err("can not handle TWT update %d", ret); + return; + } + + __hdd_twt_update_work_handler(hdd_ctx); + + osif_psoc_sync_op_stop(psoc_sync); +} + +void wlan_twt_concurrency_update(struct hdd_context *hdd_ctx) +{ + qdf_sched_work(0, &hdd_ctx->twt_en_dis_work); +} + +void hdd_twt_del_dialog_in_ps_disable(struct hdd_context *hdd_ctx, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id) +{ + struct wmi_twt_del_dialog_param params = {0}; + int ret; + + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + params.vdev_id = vdev_id; + qdf_mem_copy(params.peer_macaddr, mac_addr->bytes, QDF_MAC_ADDR_SIZE); + + if (ucfg_mlme_is_twt_setup_done(hdd_ctx->psoc, mac_addr, + params.dialog_id)) { + hdd_debug("vdev%d: Terminate existing TWT session %d due to ps disable", + params.vdev_id, params.dialog_id); + ret = hdd_send_twt_del_dialog_cmd(hdd_ctx, ¶ms); + if (ret) + hdd_debug("TWT teardown is failed on vdev: %d", vdev_id); + } +} + +void wlan_hdd_twt_init(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + struct twt_callbacks twt_cb; + + hdd_ctx->twt_state = TWT_INIT; + + sme_clear_twt_complete_cb(hdd_ctx->mac_handle); + twt_cb.twt_enable_cb = hdd_twt_enable_comp_cb; + twt_cb.twt_disable_cb = hdd_twt_disable_comp_cb; + twt_cb.twt_add_dialog_cb = hdd_twt_add_dialog_comp_cb; + twt_cb.twt_del_dialog_cb = hdd_twt_del_dialog_comp_cb; + twt_cb.twt_pause_dialog_cb = hdd_twt_pause_dialog_comp_cb; + twt_cb.twt_resume_dialog_cb = hdd_twt_resume_dialog_comp_cb; + twt_cb.twt_notify_cb = hdd_twt_notify_cb; + twt_cb.twt_nudge_dialog_cb = hdd_twt_nudge_dialog_comp_cb; + twt_cb.twt_ack_comp_cb = hdd_twt_ack_comp_cb; + + status = sme_register_twt_callbacks(hdd_ctx->mac_handle, &twt_cb); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Register twt enable complete failed"); + return; + } + + status = qdf_event_create(&hdd_ctx->twt_enable_comp_evt); + if (QDF_IS_STATUS_ERROR(status)) { + sme_clear_twt_complete_cb(hdd_ctx->mac_handle); + hdd_err("twt_enable_comp_evt init failed"); + return; + } + + status = qdf_event_create(&hdd_ctx->twt_disable_comp_evt); + if (QDF_IS_STATUS_ERROR(status)) { + sme_clear_twt_complete_cb(hdd_ctx->mac_handle); + hdd_err("twt_disable_comp_evt init failed"); + return; + } + + hdd_send_twt_requestor_enable_cmd(hdd_ctx); + qdf_create_work(0, &hdd_ctx->twt_en_dis_work, + hdd_twt_update_work_handler, hdd_ctx); +} + +void wlan_hdd_twt_deinit(struct hdd_context *hdd_ctx) +{ + QDF_STATUS status; + + qdf_flush_work(&hdd_ctx->twt_en_dis_work); + qdf_destroy_work(NULL, &hdd_ctx->twt_en_dis_work); + + status = qdf_event_destroy(&hdd_ctx->twt_disable_comp_evt); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to destroy twt_disable_comp_evt"); + + status = qdf_event_destroy(&hdd_ctx->twt_enable_comp_evt); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to destroy twt_enable_comp_evt"); + + status = sme_clear_twt_complete_cb(hdd_ctx->mac_handle); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("De-register of twt disable cb failed: %d", status); + + hdd_ctx->twt_state = TWT_CLOSED; +} + +QDF_STATUS hdd_get_twt_requestor(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return ucfg_mlme_get_twt_requestor(psoc, val); +} + +QDF_STATUS hdd_get_twt_responder(struct wlan_objmgr_psoc *psoc, bool *val) +{ + return ucfg_mlme_get_twt_responder(psoc, val); +} + +#endif + +/** + * __wlan_hdd_cfg80211_wifi_twt_config() - Wifi TWT configuration + * vendor command + * @wiphy: wiphy device pointer + * @wdev: wireless device pointer + * @data: Vendor command data buffer + * @data_len: Buffer length + * + * Handles QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX. + * + * Return: 0 for Success and negative value for failure + */ +static int +__wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX + 1]; + int errno; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_MAX, + data, + data_len, + wlan_hdd_wifi_twt_config_policy)) { + hdd_err("invalid twt attr"); + return -EINVAL; + } + + errno = hdd_twt_configure(adapter, tb); + + return errno; +} + +int wlan_hdd_cfg80211_wifi_twt_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_wifi_twt_config(wiphy, wdev, data, + data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +void wlan_hdd_resume_pmo_twt(struct hdd_context *hdd_ctx) +{ + wlan_twt_concurrency_update(hdd_ctx); +} + +void wlan_hdd_suspend_pmo_twt(struct hdd_context *hdd_ctx) +{ + qdf_flush_work(&hdd_ctx->twt_en_dis_work); +} + +bool wlan_hdd_is_twt_pmo_allowed(struct hdd_context *hdd_ctx) +{ + bool twt_pmo_allowed = false; + + twt_pmo_allowed = ucfg_twt_get_pmo_allowed(hdd_ctx->psoc); + hdd_debug("twt_disabled_allowed %d ", twt_pmo_allowed); + + return twt_pmo_allowed; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_power.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_power.c new file mode 100644 index 0000000000..3790592ca1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_power.c @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_tx_power.c + * + * WLAN tx power setting functions + * + */ + +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_object_manager.h" + +#define MAX_TXPOWER_SCALE 4 + +const struct nla_policy +txpower_scale_policy[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE] = { .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int __wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + int ret; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1]; + uint8_t scale_value; + QDF_STATUS status; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX, + data, data_len, txpower_scale_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]) { + hdd_err("attr tx power scale failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE]); + + if (scale_value > MAX_TXPOWER_SCALE) { + hdd_err("Invalid tx power scale level"); + return -EINVAL; + } + + status = wma_set_tx_power_scale(adapter->deflink->vdev_id, scale_value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Set tx power scale failed"); + return -EINVAL; + } + + return 0; +} + +int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_txpower_scale(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +const struct nla_policy txpower_scale_decr_db_policy +[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB] = { .type = NLA_U8 }, +}; + +/** + * __wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +static int +__wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + int ret; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1]; + uint8_t scale_value; + QDF_STATUS status; + + hdd_enter_dev(dev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX, + data, data_len, + txpower_scale_decr_db_policy)) { + hdd_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]) { + hdd_err("attr tx power decrease db value failed"); + return -EINVAL; + } + + scale_value = nla_get_u8(tb + [QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB]); + + status = wma_set_tx_power_scale_decr_db(adapter->deflink->vdev_id, + scale_value); + + if (status != QDF_STATUS_SUCCESS) { + hdd_err("Set tx power decrease db failed"); + return -EINVAL; + } + + return 0; +} + +int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_txpower_scale_decr_db(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static uint32_t get_default_tpc_info_vendor_sbk_len(void) +{ + uint32_t skb_len; + + /* QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY */ + skb_len = nla_total_size(sizeof(u32)); + /* QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_TX_POWER */ + skb_len += nla_total_size(sizeof(s8)); + skb_len = nla_total_size(skb_len) * MAX_NUM_PWR_LEVEL; + skb_len = nla_total_size(skb_len); + + /* QCA_WLAN_VENDOR_ATTR_TPC_BSSID */ + skb_len += nla_total_size(QDF_MAC_ADDR_SIZE); + /* QCA_WLAN_VENDOR_ATTR_TPC_PSD_POWER */ + skb_len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TPC_EIRP_POWER */ + skb_len += nla_total_size(sizeof(s8)); + /* QCA_WLAN_VENDOR_ATTR_TPC_POWER_TYPE_6GHZ */ + skb_len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TPC_AP_CONSTRAINT_POWER */ + skb_len += nla_total_size(sizeof(u8)); + + skb_len = nla_total_size(skb_len) * WLAN_MAX_ML_BSS_LINKS; + skb_len = nla_total_size(skb_len) + NLMSG_HDRLEN; + + return skb_len; +} + +static int +__wlan_hdd_cfg80211_get_reg_tpc_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter; + int ret; + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + int num_of_links = 0; + struct qdf_mac_addr link_bssid[WLAN_MAX_ML_BSS_LINKS]; + struct reg_tpc_power_info reg_tpc_info[WLAN_MAX_ML_BSS_LINKS]; + struct sk_buff *reply_skb = NULL; + uint32_t skb_len, i, j; + struct wlan_hdd_link_info *link_info; + struct nlattr *tpc_links_attr, *tpc_attr, *levels_attr, *tpc_level; + int attr_id; + struct chan_power_info *chan_power_info; + + hdd_enter_dev(dev); + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + adapter = WLAN_HDD_GET_PRIV_PTR(dev); + if (!adapter) { + hdd_err("adapter null"); + return -EPERM; + } + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("device mode %d not support", adapter->device_mode); + return -EPERM; + } + + hdd_adapter_for_each_link_info(adapter, link_info) { + if (num_of_links >= WLAN_MAX_ML_BSS_LINKS) + break; + if (link_info->vdev_id == WLAN_INVALID_VDEV_ID) + continue; + if (!hdd_cm_is_vdev_connected(link_info)) + continue; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, + WLAN_OSIF_POWER_ID); + if (!vdev) + continue; + + status = wlan_vdev_get_bss_peer_mac(vdev, + &link_bssid[num_of_links]); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get bssid for vdev %d", + link_info->vdev_id); + goto next_link; + } + + status = + ucfg_wlan_mlme_get_reg_tpc_info(vdev, + ®_tpc_info[num_of_links]); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed to get tpc info for vdev %d", + link_info->vdev_id); + goto next_link; + } + + num_of_links++; +next_link: + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + } + + if (!num_of_links) { + hdd_err("get tpc info failed - nun of links 0"); + return -EINVAL; + } + + skb_len = get_default_tpc_info_vendor_sbk_len(); + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + wiphy, + skb_len); + if (!reply_skb) { + hdd_err("alloc reply_skb failed"); + status = QDF_STATUS_E_NOMEM; + goto free_skb; + } + + tpc_links_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_TPC_LINKS); + if (!tpc_links_attr) { + hdd_err("failed to add QCA_WLAN_VENDOR_ATTR_TPC_LINKS"); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + for (i = 0; i < num_of_links; i++) { + tpc_attr = nla_nest_start(reply_skb, i); + if (!tpc_attr) { + hdd_err("tpc_attr null, %d", i); + continue; + } + if (nla_put(reply_skb, QCA_WLAN_VENDOR_ATTR_TPC_BSSID, + QDF_MAC_ADDR_SIZE, &link_bssid[i])) { + hdd_err("failed to put mac_addr"); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + if (reg_tpc_info[i].is_psd_power && + nla_put_flag(reply_skb, + QCA_WLAN_VENDOR_ATTR_TPC_PSD_POWER)) { + osif_err("failed to put psd flag"); + return QDF_STATUS_E_INVAL; + } + + if (nla_put_s8(reply_skb, + QCA_WLAN_VENDOR_ATTR_TPC_EIRP_POWER, + reg_tpc_info[i].reg_max[0])) { + hdd_err("failed to put eirp_power"); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + chan_power_info = ®_tpc_info[i].chan_power_info[0]; + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_power_info->chan_cfreq) && + nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_TPC_POWER_TYPE_6GHZ, + reg_tpc_info[i].power_type_6g)) { + hdd_err("failed to put power_type_6g"); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + if (nla_put_u8(reply_skb, + QCA_WLAN_VENDOR_ATTR_TPC_AP_CONSTRAINT_POWER, + reg_tpc_info[i].ap_constraint_power)) { + hdd_err("failed to put ap_constraint_power"); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + hdd_debug("%d tpc for bssid "QDF_MAC_ADDR_FMT" is_psd %d reg power %d 6ghz pwr type %d ap_constraint_power %d", + i, QDF_MAC_ADDR_REF(link_bssid[i].bytes), + reg_tpc_info[i].is_psd_power, + reg_tpc_info[i].reg_max[0], + reg_tpc_info[i].power_type_6g, + reg_tpc_info[i].ap_constraint_power); + + levels_attr = nla_nest_start( + reply_skb, QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL); + if (!levels_attr) { + hdd_err("failed to add QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL"); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + for (j = 0; j < reg_tpc_info[i].num_pwr_levels; j++) { + tpc_level = nla_nest_start(reply_skb, j); + if (!tpc_level) { + hdd_err("tpc_level null. level %d", j); + continue; + } + chan_power_info = ®_tpc_info[i].chan_power_info[j]; + + attr_id = QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_FREQUENCY; + if (nla_put_u32(reply_skb, + attr_id, + chan_power_info->chan_cfreq)) { + hdd_err("failed to put chan_cfreq %d", + chan_power_info->chan_cfreq); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + attr_id = QCA_WLAN_VENDOR_ATTR_TPC_PWR_LEVEL_TX_POWER; + if (nla_put_s8(reply_skb, + attr_id, + chan_power_info->tx_power)) { + hdd_err("failed to put tx_power %d", + chan_power_info->tx_power); + status = QDF_STATUS_E_INVAL; + goto free_skb; + } + + hdd_debug("%d cfreq %d tx_power %d", j, + chan_power_info->chan_cfreq, + chan_power_info->tx_power); + + nla_nest_end(reply_skb, tpc_level); + } + nla_nest_end(reply_skb, levels_attr); + + nla_nest_end(reply_skb, tpc_attr); + } + + nla_nest_end(reply_skb, tpc_links_attr); + + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + + hdd_exit(); + + return ret; +free_skb: + if (reply_skb) + wlan_cfg80211_vendor_free_skb(reply_skb); + hdd_exit(); + return qdf_status_to_os_return(status); +} + +int wlan_hdd_cfg80211_get_reg_tpc_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_get_reg_tpc_info(wiphy, wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_power.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_power.h new file mode 100644 index 0000000000..4a73d544d6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_power.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_HDD_TX_POWER_H +#define __WLAN_HDD_TX_POWER_H + +/** + * DOC: wlan_hdd_tx_power_h + * + * WLAN Host Device Driver TX power setting API specification + */ + +#ifdef FEATURE_TX_POWER + +extern const struct nla_policy txpower_scale_policy[ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX + 1]; + +extern const struct nla_policy txpower_scale_decr_db_policy[ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX + 1]; + +/** + * wlan_hdd_cfg80211_txpower_scale () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_txpower_scale(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_txpower_scale_decr_db () - txpower scaling + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_txpower_scale_decr_db(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +/** + * wlan_hdd_cfg80211_get_reg_tpc_info () - get regulatory tpc information of + * connected AP + * @wiphy: Pointer to wireless phy + * @wdev: Pointer to wireless device + * @data: Pointer to data + * @data_len: Data length + * + * Return: 0 on success, negative errno on failure + */ +int wlan_hdd_cfg80211_get_reg_tpc_info(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len); + +#define FEATURE_TX_POWER_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_txpower_scale, \ + vendor_command_policy(txpower_scale_policy, \ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_MAX) \ +}, \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = \ + QCA_NL80211_VENDOR_SUBCMD_SET_TXPOWER_SCALE_DECR_DB, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_txpower_scale_decr_db, \ + vendor_command_policy(txpower_scale_decr_db_policy, \ + QCA_WLAN_VENDOR_ATTR_TXPOWER_SCALE_DECR_DB_MAX) \ +}, + +#define FEATURE_REGULATORY_TPC_INFO_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_REGULATORY_TPC_INFO, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_reg_tpc_info, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ +}, + +#else /* FEATURE_TX_POWER */ +#define FEATURE_TX_POWER_VENDOR_COMMANDS +#define FEATURE_REGULATORY_TPC_INFO_VENDOR_COMMANDS +#endif /* FEATURE_TX_POWER */ + +#endif /* __WLAN_HDD_TX_POWER_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c new file mode 100644 index 0000000000..daf500f106 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c @@ -0,0 +1,1704 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_tx_rx.c + * + * Linux HDD Tx/RX APIs + */ + +/* denote that this file does not allow legacy hddLog */ +#define HDD_DISALLOW_LEGACY_HDDLOG 1 +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "sap_api.h" +#include "wlan_hdd_wmm.h" +#include +#include +#include +#include +#include "wlan_hdd_power.h" +#include "wlan_hdd_cfg80211.h" +#include +#include + +#include +#include "cfg_ucfg_api.h" +#include "target_type.h" +#include "wlan_hdd_object_manager.h" +#include +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" +#include "os_if_dp.h" +#include "wlan_ipa_ucfg_api.h" +#include "wlan_hdd_stats.h" + +#ifdef TX_MULTIQ_PER_AC +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/* + * Mapping Linux AC interpretation to SME AC. + * Host has 4 queues per access category (4 AC) and 1 high priority queue. + * 16 flow-controlled queues for regular traffic and one non-flow + * controlled queue for high priority control traffic(EOPOL, DHCP). + * The seventeenth queue is mapped to AC_VO to allow for proper prioritization. + */ +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VO, + SME_AC_VO, + SME_AC_VO, + SME_AC_VI, + SME_AC_VI, + SME_AC_VI, + SME_AC_VI, + SME_AC_BE, + SME_AC_BE, + SME_AC_BE, + SME_AC_BE, + SME_AC_BK, + SME_AC_BK, + SME_AC_BK, + SME_AC_BK, + SME_AC_VO, +}; + +#else +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VO, + SME_AC_VO, + SME_AC_VO, + SME_AC_VI, + SME_AC_VI, + SME_AC_VI, + SME_AC_VI, + SME_AC_BE, + SME_AC_BE, + SME_AC_BE, + SME_AC_BE, + SME_AC_BK, + SME_AC_BK, + SME_AC_BK, + SME_AC_BK, +}; + +#endif +#else +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/* + * Mapping Linux AC interpretation to SME AC. + * Host has 5 tx queues, 4 flow-controlled queues for regular traffic and + * one non-flow-controlled queue for high priority control traffic(EOPOL, DHCP). + * The fifth queue is mapped to AC_VO to allow for proper prioritization. + */ +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VI, + SME_AC_BE, + SME_AC_BK, + SME_AC_VO, +}; + +#else +const uint8_t hdd_qdisc_ac_to_tl_ac[] = { + SME_AC_VO, + SME_AC_VI, + SME_AC_BE, + SME_AC_BK, +}; + +#endif +#endif + +#ifdef QCA_HL_NETDEV_FLOW_CONTROL +void hdd_register_hl_netdev_fc_timer(struct hdd_adapter *adapter, + qdf_mc_timer_callback_t timer_callback) +{ + if (!adapter->tx_flow_timer_initialized) { + qdf_mc_timer_init(&adapter->tx_flow_control_timer, + QDF_TIMER_TYPE_SW, timer_callback, adapter); + adapter->tx_flow_timer_initialized = true; + } +} + +/** + * hdd_deregister_hl_netdev_fc_timer() - Deregister HL Flow Control Timer + * @adapter: adapter handle + * + * Return: none + */ +void hdd_deregister_hl_netdev_fc_timer(struct hdd_adapter *adapter) +{ + if (adapter->tx_flow_timer_initialized) { + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + qdf_mc_timer_destroy(&adapter->tx_flow_control_timer); + adapter->tx_flow_timer_initialized = false; + } +} + +/** + * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * Return: None + */ +void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *)adapter_context; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + u32 p_qpaused; + u32 np_qpaused; + + if (!adapter) { + hdd_err("invalid adapter context"); + return; + } + + cdp_display_stats(soc, CDP_DUMP_TX_FLOW_POOL_INFO, + QDF_STATS_VERBOSITY_LEVEL_LOW); + wlan_hdd_display_adapter_netif_queue_history(adapter); + hdd_debug("Enabling queues"); + spin_lock_bh(&adapter->pause_map_lock); + p_qpaused = adapter->pause_map & BIT(WLAN_DATA_FLOW_CONTROL_PRIORITY); + np_qpaused = adapter->pause_map & BIT(WLAN_DATA_FLOW_CONTROL); + spin_unlock_bh(&adapter->pause_map_lock); + + if (p_qpaused) { + wlan_hdd_netif_queue_control(adapter, + WLAN_NETIF_PRIORITY_QUEUE_ON, + WLAN_DATA_FLOW_CONTROL_PRIORITY); + cdp_hl_fc_set_os_queue_status(soc, + adapter->deflink->vdev_id, + WLAN_NETIF_PRIORITY_QUEUE_ON); + } + if (np_qpaused) { + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_NON_PRIORITY_QUEUE, + WLAN_DATA_FLOW_CONTROL); + cdp_hl_fc_set_os_queue_status(soc, + adapter->deflink->vdev_id, + WLAN_WAKE_NON_PRIORITY_QUEUE); + } +} + +#endif /* QCA_HL_NETDEV_FLOW_CONTROL */ + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_tx_resume_timer_expired_handler() - TX Q resume timer handler + * @adapter_context: pointer to vdev adapter + * + * If Blocked OS Q is not resumed during timeout period, to prevent + * permanent stall, resume OS Q forcefully. + * + * Return: None + */ +void hdd_tx_resume_timer_expired_handler(void *adapter_context) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) adapter_context; + + if (!adapter) { + /* INVALID ARG */ + return; + } + + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); +} + +/** + * hdd_tx_resume_false() - Resume OS TX Q false leads to queue disabling + * @adapter: pointer to hdd adapter + * @tx_resume: TX Q resume trigger + * + * + * Return: None + */ +static void +hdd_tx_resume_false(struct hdd_adapter *adapter, bool tx_resume) +{ + QDF_STATUS status; + qdf_mc_timer_t *fc_timer; + + if (true == tx_resume) + return; + + /* Pause TX */ + hdd_debug("Disabling queues"); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + fc_timer = &adapter->tx_flow_control_timer; + if (QDF_TIMER_STATE_STOPPED != qdf_mc_timer_get_current_state(fc_timer)) + goto update_stats; + + + status = qdf_mc_timer_start(fc_timer, + WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME); + + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to start tx_flow_control_timer"); + else + adapter->deflink->hdd_stats.tx_rx_stats.txflow_timer_cnt++; + +update_stats: + adapter->deflink->hdd_stats.tx_rx_stats.txflow_pause_cnt++; + adapter->deflink->hdd_stats.tx_rx_stats.is_txflow_paused = true; +} + +/** + * hdd_tx_resume_cb() - Resume OS TX Q. + * @adapter_context: pointer to vdev apdapter + * @tx_resume: TX Q resume trigger + * + * Q was stopped due to WLAN TX path low resource condition + * + * Return: None + */ +void hdd_tx_resume_cb(void *adapter_context, bool tx_resume) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) adapter_context; + struct hdd_station_ctx *hdd_sta_ctx = NULL; + + if (!adapter) { + /* INVALID ARG */ + return; + } + + hdd_sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + /* Resume TX */ + if (true == tx_resume) { + if (QDF_TIMER_STATE_STOPPED != + qdf_mc_timer_get_current_state(&adapter-> + tx_flow_control_timer)) { + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + } + hdd_debug("Enabling queues"); + wlan_hdd_netif_queue_control(adapter, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + adapter->deflink->hdd_stats.tx_rx_stats.is_txflow_paused = + false; + adapter->deflink->hdd_stats.tx_rx_stats.txflow_unpause_cnt++; + } + hdd_tx_resume_false(adapter, tx_resume); +} + +bool hdd_tx_flow_control_is_pause(void *adapter_context) +{ + struct hdd_adapter *adapter = (struct hdd_adapter *) adapter_context; + + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + /* INVALID ARG */ + hdd_err("invalid adapter %pK", adapter); + return false; + } + + return adapter->pause_map & (1 << WLAN_DATA_FLOW_CONTROL); +} + +void hdd_register_tx_flow_control(struct hdd_adapter *adapter, + qdf_mc_timer_callback_t timer_callback, + ol_txrx_tx_flow_control_fp flow_control_fp, + ol_txrx_tx_flow_control_is_pause_fp flow_control_is_pause_fp) +{ + if (adapter->tx_flow_timer_initialized == false) { + qdf_mc_timer_init(&adapter->tx_flow_control_timer, + QDF_TIMER_TYPE_SW, + timer_callback, + adapter); + adapter->tx_flow_timer_initialized = true; + } + cdp_fc_register(cds_get_context(QDF_MODULE_ID_SOC), + adapter->deflink->vdev_id, flow_control_fp, adapter, + flow_control_is_pause_fp); +} + +/** + * hdd_deregister_tx_flow_control() - Deregister TX Flow control + * @adapter: adapter handle + * + * Return: none + */ +void hdd_deregister_tx_flow_control(struct hdd_adapter *adapter) +{ + cdp_fc_deregister(cds_get_context(QDF_MODULE_ID_SOC), + adapter->deflink->vdev_id); + if (adapter->tx_flow_timer_initialized == true) { + qdf_mc_timer_stop(&adapter->tx_flow_control_timer); + qdf_mc_timer_destroy(&adapter->tx_flow_control_timer); + adapter->tx_flow_timer_initialized = false; + } +} + +void hdd_get_tx_resource(uint8_t vdev_id, + struct qdf_mac_addr *mac_addr) +{ + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + uint16_t timer_value = WLAN_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME; + struct wlan_hdd_link_info *link_info; + qdf_mc_timer_t *fc_timer; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) + return; + + adapter = link_info->adapter; + if (adapter->device_mode == QDF_P2P_GO_MODE || + adapter->device_mode == QDF_SAP_MODE) + timer_value = WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME; + + if (cdp_fc_get_tx_resource(cds_get_context(QDF_MODULE_ID_SOC), + OL_TXRX_PDEV_ID, *mac_addr, + adapter->tx_flow_low_watermark, + adapter->tx_flow_hi_watermark_offset)) + return; + + hdd_debug("Disabling queues lwm %d hwm offset %d", + adapter->tx_flow_low_watermark, + adapter->tx_flow_hi_watermark_offset); + wlan_hdd_netif_queue_control(adapter, WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_DATA_FLOW_CONTROL); + + fc_timer = &adapter->tx_flow_control_timer; + if ((adapter->tx_flow_timer_initialized == true) && + (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(fc_timer))) { + qdf_mc_timer_start(fc_timer, timer_value); + link_info->hdd_stats.tx_rx_stats.txflow_timer_cnt++; + link_info->hdd_stats.tx_rx_stats.txflow_pause_cnt++; + link_info->hdd_stats.tx_rx_stats.is_txflow_paused = true; + } +} + +unsigned int +hdd_get_tx_flow_low_watermark(hdd_cb_handle cb_ctx, qdf_netdev_t netdev) +{ + struct hdd_adapter *adapter; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) + return 0; + + return adapter->tx_flow_low_watermark; +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#ifdef RECEIVE_OFFLOAD +qdf_napi_struct +*hdd_legacy_gro_get_napi(qdf_nbuf_t nbuf, bool enable_rxthread) +{ + struct qca_napi_info *qca_napii; + struct qca_napi_data *napid; + struct napi_struct *napi_to_use; + + napid = hdd_napi_get_all(); + if (unlikely(!napid)) + return NULL; + + qca_napii = hif_get_napi(QDF_NBUF_CB_RX_CTX_ID(nbuf), napid); + if (unlikely(!qca_napii)) + return NULL; + + /* + * As we are breaking context in Rxthread mode, there is rx_thread NAPI + * corresponds each hif_napi. + */ + if (enable_rxthread) + napi_to_use = &qca_napii->rx_thread_napi; + else + napi_to_use = &qca_napii->napi; + + return (qdf_napi_struct *)napi_to_use; +} +#else +qdf_napi_struct +*hdd_legacy_gro_get_napi(qdf_nbuf_t nbuf, bool enable_rxthread) +{ + return NULL; +} +#endif + +int hdd_set_udp_qos_upgrade_config(struct hdd_adapter *adapter, + uint8_t priority) +{ + if (adapter->device_mode != QDF_STA_MODE) { + hdd_info_rl("Data priority upgrade only allowed in STA mode:%d", + adapter->device_mode); + return -EINVAL; + } + + if (priority >= QCA_WLAN_AC_ALL) { + hdd_err_rl("Invalid data priority: %d", priority); + return -EINVAL; + } + + adapter->upgrade_udp_qos_threshold = priority; + + hdd_debug("UDP packets qos upgrade to: %d", priority); + + return 0; +} + +#ifdef QCA_WIFI_FTM +static inline bool +hdd_drop_tx_packet_on_ftm(struct sk_buff *skb) +{ + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + kfree_skb(skb); + return true; + } + return false; +} +#else +static inline bool +hdd_drop_tx_packet_on_ftm(struct sk_buff *skb) +{ + return false; +} +#endif + +/** + * __hdd_hard_start_xmit() - Transmit a frame + * @skb: pointer to OS packet (sk_buff) + * @dev: pointer to network device + * + * Function registered with the Linux OS for transmitting + * packets. This version of the function directly passes + * the packet to Transport Layer. + * In case of any packet drop or error, log the error with + * INFO HIGH/LOW/MEDIUM to avoid excessive logging in kmsg. + * + * Return: None + */ +static void __hdd_hard_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_tx_rx_stats *stats = + &adapter->deflink->hdd_stats.tx_rx_stats; + struct hdd_station_ctx *sta_ctx = &adapter->deflink->session.station; + int cpu = qdf_get_smp_processor_id(); + bool granted; + sme_ac_enum_type ac; + enum sme_qos_wmmuptype up; + QDF_STATUS status; + + if (hdd_drop_tx_packet_on_ftm(skb)) + return; + + osif_dp_mark_pkt_type(skb); + hdd_tx_latency_record_ingress_ts(adapter, skb); + + /* Get TL AC corresponding to Qdisc queue index/AC. */ + ac = hdd_qdisc_ac_to_tl_ac[skb->queue_mapping]; + + /* + * user priority from IP header, which is already extracted and set from + * select_queue call back function + */ + up = skb->priority; + + ++stats->per_cpu[cpu].tx_classified_ac[ac]; +#ifdef HDD_WMM_DEBUG + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Classified as ac %d up %d", __func__, ac, up); +#endif /* HDD_WMM_DEBUG */ + + if (HDD_PSB_CHANGED == adapter->psb_changed) { + /* + * Function which will determine acquire admittance for a + * WMM AC is required or not based on psb configuration done + * in the framework + */ + hdd_wmm_acquire_access_required(adapter, ac); + } + /* + * Make sure we already have access to this access category + * or it is EAPOL or WAPI frame during initial authentication which + * can have artificially boosted higher qos priority. + */ + + if (((adapter->psb_changed & (1 << ac)) && + likely(adapter->hdd_wmm_status.ac_status[ac]. + is_access_allowed)) || + ((!sta_ctx->conn_info.is_authenticated) && + (QDF_NBUF_CB_PACKET_TYPE_EAPOL == + QDF_NBUF_CB_GET_PACKET_TYPE(skb) || + QDF_NBUF_CB_PACKET_TYPE_WAPI == + QDF_NBUF_CB_GET_PACKET_TYPE(skb)))) { + granted = true; + } else { + status = hdd_wmm_acquire_access(adapter, ac, &granted); + adapter->psb_changed |= (1 << ac); + } + + if (!granted) { + bool is_default_ac = false; + /* + * ADDTS request for this AC is sent, for now + * send this packet through next available lower + * Access category until ADDTS negotiation completes. + */ + while (!likely + (adapter->hdd_wmm_status.ac_status[ac]. + is_access_allowed)) { + switch (ac) { + case SME_AC_VO: + ac = SME_AC_VI; + up = SME_QOS_WMM_UP_VI; + break; + case SME_AC_VI: + ac = SME_AC_BE; + up = SME_QOS_WMM_UP_BE; + break; + case SME_AC_BE: + ac = SME_AC_BK; + up = SME_QOS_WMM_UP_BK; + break; + default: + ac = SME_AC_BK; + up = SME_QOS_WMM_UP_BK; + is_default_ac = true; + break; + } + if (is_default_ac) + break; + } + skb->priority = up; + skb->queue_mapping = hdd_linux_up_to_ac_map[up]; + } + + /* + * vdev in link_info is directly dereferenced because this is per + * packet path, hdd_get_vdev_by_user() usage will be very costly + * as it involves lock access. + * Expectation here is vdev will be present during TX/RX processing + * and also DP internally maintaining vdev ref count + */ + status = ucfg_dp_start_xmit((qdf_nbuf_t)skb, adapter->deflink->vdev); + if (QDF_IS_STATUS_SUCCESS(status)) { + netif_trans_update(dev); + wlan_hdd_sar_unsolicited_timer_start(adapter->hdd_ctx); + } else { + ++stats->per_cpu[cpu].tx_dropped_ac[ac]; + } +} + +/** + * hdd_hard_start_xmit() - Wrapper function to protect + * __hdd_hard_start_xmit from SSR + * @skb: pointer to OS packet + * @net_dev: pointer to net_device structure + * + * Function called by OS if any packet needs to transmit. + * + * Return: Always returns NETDEV_TX_OK + */ +netdev_tx_t hdd_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) +{ + __hdd_hard_start_xmit(skb, net_dev); + + return NETDEV_TX_OK; +} + +/** + * __hdd_tx_timeout() - TX timeout handler + * @dev: pointer to network device + * + * This function is registered as a netdev ndo_tx_timeout method, and + * is invoked by the kernel if the driver takes too long to transmit a + * frame. + * + * Return: None + */ +static void __hdd_tx_timeout(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + struct netdev_queue *txq; + struct wlan_objmgr_vdev *vdev; + int i = 0; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (hdd_ctx->hdd_wlan_suspended) { + hdd_debug("Device is suspended, ignore WD timeout"); + return; + } + + TX_TIMEOUT_TRACE(dev, QDF_MODULE_ID_HDD_DATA); + DPTRACE(qdf_dp_trace(NULL, QDF_DP_TRACE_HDD_TX_TIMEOUT, + QDF_TRACE_DEFAULT_PDEV_ID, + NULL, 0, QDF_TX)); + + /* Getting here implies we disabled the TX queues for too + * long. Queues are disabled either because of disassociation + * or low resource scenarios. In case of disassociation it is + * ok to ignore this. But if associated, we have do possible + * recovery here + */ + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + hdd_debug("Queue: %d status: %d txq->trans_start: %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } + + hdd_debug("carrier state: %d", netif_carrier_ok(dev)); + + wlan_hdd_display_adapter_netif_queue_history(adapter); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (vdev) { + ucfg_dp_tx_timeout(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)) +void hdd_tx_timeout(struct net_device *net_dev, unsigned int txqueue) +#else +void hdd_tx_timeout(struct net_device *net_dev) +#endif +{ + struct osif_vdev_sync *vdev_sync; + + if (osif_vdev_sync_op_start(net_dev, &vdev_sync)) + return; + + __hdd_tx_timeout(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); +} + +#ifdef RECEIVE_OFFLOAD +void hdd_disable_rx_ol_in_concurrency(bool disable) +{ + struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + + if (!hdd_ctx) + return; + + ucfg_dp_rx_handle_concurrency(hdd_ctx->psoc, disable); +} +#else /* RECEIVE_OFFLOAD */ +void hdd_disable_rx_ol_in_concurrency(bool disable) +{ +} +#endif /* RECEIVE_OFFLOAD */ + +#ifdef WLAN_FEATURE_TSF_PLUS_SOCK_TS +void hdd_tsf_timestamp_rx(hdd_cb_handle ctx, qdf_nbuf_t netbuf) +{ + struct hdd_context *hdd_ctx = hdd_cb_handle_to_context(ctx); + + if (!hdd_tsf_is_rx_set(hdd_ctx)) + return; + + hdd_rx_timestamp(netbuf, ktime_to_us(netbuf->tstamp)); +} + +void hdd_get_tsf_time_cb(qdf_netdev_t netdev, uint64_t input_time, + uint64_t *tsf_time) +{ + struct hdd_adapter *adapter; + + adapter = WLAN_HDD_GET_PRIV_PTR(netdev); + if (!adapter) + return; + + hdd_get_tsf_time(adapter, input_time, tsf_time); +} +#endif + +/** + * hdd_reason_type_to_string() - return string conversion of reason type + * @reason: reason type + * + * This utility function helps log string conversion of reason type. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_reason_type_to_string(enum netif_reason_type reason) +{ + switch (reason) { + CASE_RETURN_STRING(WLAN_CONTROL_PATH); + CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL); + CASE_RETURN_STRING(WLAN_FW_PAUSE); + CASE_RETURN_STRING(WLAN_TX_ABORT); + CASE_RETURN_STRING(WLAN_VDEV_STOP); + CASE_RETURN_STRING(WLAN_PEER_UNAUTHORISED); + CASE_RETURN_STRING(WLAN_THERMAL_MITIGATION); + CASE_RETURN_STRING(WLAN_DATA_FLOW_CONTROL_PRIORITY); + default: + return "Invalid"; + } +} + +/** + * hdd_action_type_to_string() - return string conversion of action type + * @action: action type + * + * This utility function helps log string conversion of action_type. + * + * Return: string conversion of device mode, if match found; + * "Unknown" otherwise. + */ +const char *hdd_action_type_to_string(enum netif_action_type action) +{ + + switch (action) { + CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_WAKE_ALL_NETIF_QUEUE); + CASE_RETURN_STRING(WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER); + CASE_RETURN_STRING(WLAN_START_ALL_NETIF_QUEUE_N_CARRIER); + CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE); + CASE_RETURN_STRING(WLAN_NETIF_TX_DISABLE_N_CARRIER); + CASE_RETURN_STRING(WLAN_NETIF_CARRIER_ON); + CASE_RETURN_STRING(WLAN_NETIF_CARRIER_OFF); + CASE_RETURN_STRING(WLAN_NETIF_PRIORITY_QUEUE_ON); + CASE_RETURN_STRING(WLAN_NETIF_PRIORITY_QUEUE_OFF); + CASE_RETURN_STRING(WLAN_NETIF_VO_QUEUE_ON); + CASE_RETURN_STRING(WLAN_NETIF_VO_QUEUE_OFF); + CASE_RETURN_STRING(WLAN_NETIF_VI_QUEUE_ON); + CASE_RETURN_STRING(WLAN_NETIF_VI_QUEUE_OFF); + CASE_RETURN_STRING(WLAN_NETIF_BE_BK_QUEUE_ON); + CASE_RETURN_STRING(WLAN_NETIF_BE_BK_QUEUE_OFF); + CASE_RETURN_STRING(WLAN_WAKE_NON_PRIORITY_QUEUE); + CASE_RETURN_STRING(WLAN_STOP_NON_PRIORITY_QUEUE); + default: + return "Invalid"; + } +} + +/** + * wlan_hdd_update_queue_oper_stats - update queue operation statistics + * @adapter: adapter handle + * @action: action type + * @reason: reason type + */ +static void wlan_hdd_update_queue_oper_stats(struct hdd_adapter *adapter, + enum netif_action_type action, enum netif_reason_type reason) +{ + switch (action) { + case WLAN_STOP_ALL_NETIF_QUEUE: + case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: + case WLAN_NETIF_BE_BK_QUEUE_OFF: + case WLAN_NETIF_VI_QUEUE_OFF: + case WLAN_NETIF_VO_QUEUE_OFF: + case WLAN_NETIF_PRIORITY_QUEUE_OFF: + case WLAN_STOP_NON_PRIORITY_QUEUE: + adapter->queue_oper_stats[reason].pause_count++; + break; + case WLAN_START_ALL_NETIF_QUEUE: + case WLAN_WAKE_ALL_NETIF_QUEUE: + case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: + case WLAN_NETIF_BE_BK_QUEUE_ON: + case WLAN_NETIF_VI_QUEUE_ON: + case WLAN_NETIF_VO_QUEUE_ON: + case WLAN_NETIF_PRIORITY_QUEUE_ON: + case WLAN_WAKE_NON_PRIORITY_QUEUE: + adapter->queue_oper_stats[reason].unpause_count++; + break; + default: + break; + } +} + +/** + * hdd_netdev_queue_is_locked() + * @txq: net device tx queue + * + * For SMP system, always return false and we could safely rely on + * __netif_tx_trylock(). + * + * Return: true locked; false not locked + */ +#ifdef QCA_CONFIG_SMP +static inline bool hdd_netdev_queue_is_locked(struct netdev_queue *txq) +{ + return false; +} +#else +static inline bool hdd_netdev_queue_is_locked(struct netdev_queue *txq) +{ + return txq->xmit_lock_owner != -1; +} +#endif + +/** + * wlan_hdd_update_txq_timestamp() - update txq timestamp + * @dev: net device + * + * Return: none + */ +static void wlan_hdd_update_txq_timestamp(struct net_device *dev) +{ + struct netdev_queue *txq; + int i; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(dev, i); + + /* + * On UP system, kernel will trigger watchdog bite if spinlock + * recursion is detected. Unfortunately recursion is possible + * when it is called in dev_queue_xmit() context, where stack + * grabs the lock before calling driver's ndo_start_xmit + * callback. + */ + if (!hdd_netdev_queue_is_locked(txq)) { + if (__netif_tx_trylock(txq)) { + txq_trans_update(txq); + __netif_tx_unlock(txq); + } + } + } +} + +/** + * wlan_hdd_update_unpause_time() - update unpause time + * @adapter: adapter handle + * + * Return: none + */ +static void wlan_hdd_update_unpause_time(struct hdd_adapter *adapter) +{ + qdf_time_t curr_time = qdf_system_ticks(); + + adapter->total_unpause_time += curr_time - adapter->last_time; + adapter->last_time = curr_time; +} + +/** + * wlan_hdd_update_pause_time() - update pause time + * @adapter: adapter handle + * @temp_map: pause map + * + * Return: none + */ +static void wlan_hdd_update_pause_time(struct hdd_adapter *adapter, + uint32_t temp_map) +{ + qdf_time_t curr_time = qdf_system_ticks(); + uint8_t i; + qdf_time_t pause_time; + + pause_time = curr_time - adapter->last_time; + adapter->total_pause_time += pause_time; + adapter->last_time = curr_time; + + for (i = 0; i < WLAN_REASON_TYPE_MAX; i++) { + if (temp_map & (1 << i)) { + adapter->queue_oper_stats[i].total_pause_time += + pause_time; + break; + } + } + +} + +uint32_t +wlan_hdd_dump_queue_history_state(struct hdd_netif_queue_history *queue_history, + char *buf, uint32_t size) +{ + unsigned int i; + unsigned int index = 0; + + for (i = 0; i < NUM_TX_QUEUES; i++) { + index += qdf_scnprintf(buf + index, + size - index, + "%u:0x%lx ", + i, queue_history->tx_q_state[i]); + } + + return index; +} + +/** + * wlan_hdd_update_queue_history_state() - Save a copy of dev TX queues state + * @dev: interface netdev + * @q_hist: adapter queue history + * + * Save netdev TX queues state into adapter queue history. + * + * Return: None + */ +static void +wlan_hdd_update_queue_history_state(struct net_device *dev, + struct hdd_netif_queue_history *q_hist) +{ + unsigned int i = 0; + uint32_t num_tx_queues = 0; + struct netdev_queue *txq = NULL; + + num_tx_queues = qdf_min(dev->num_tx_queues, (uint32_t)NUM_TX_QUEUES); + + for (i = 0; i < num_tx_queues; i++) { + txq = netdev_get_tx_queue(dev, i); + q_hist->tx_q_state[i] = txq->state; + } +} + +/** + * wlan_hdd_stop_non_priority_queue() - stop non priority queues + * @adapter: adapter handle + * + * Return: None + */ +static inline void wlan_hdd_stop_non_priority_queue(struct hdd_adapter *adapter) +{ + uint8_t i; + + for (i = 0; i < TX_QUEUES_PER_AC; i++) { + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_VO, i)); + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_VI, i)); + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_BE, i)); + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_BK, i)); + } +} + +/** + * wlan_hdd_wake_non_priority_queue() - wake non priority queues + * @adapter: adapter handle + * + * Return: None + */ +static inline void wlan_hdd_wake_non_priority_queue(struct hdd_adapter *adapter) +{ + uint8_t i; + + for (i = 0; i < TX_QUEUES_PER_AC; i++) { + netif_wake_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_VO, i)); + netif_wake_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_VI, i)); + netif_wake_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_BE, i)); + netif_wake_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_BK, i)); + } +} + +static inline +void hdd_wake_queues_for_ac(struct net_device *dev, enum hdd_wmm_linuxac ac) +{ + uint8_t i; + + for (i = 0; i < TX_QUEUES_PER_AC; i++) + netif_wake_subqueue(dev, TX_GET_QUEUE_IDX(ac, i)); +} + +static inline +void hdd_stop_queues_for_ac(struct net_device *dev, enum hdd_wmm_linuxac ac) +{ + uint8_t i; + + for (i = 0; i < TX_QUEUES_PER_AC; i++) + netif_stop_subqueue(dev, TX_GET_QUEUE_IDX(ac, i)); +} + +/** + * wlan_hdd_netif_queue_control() - Use for netif_queue related actions + * @adapter: adapter handle + * @action: action type + * @reason: reason type + * + * This is single function which is used for netif_queue related + * actions like start/stop of network queues and on/off carrier + * option. + * + * Return: None + */ +void wlan_hdd_netif_queue_control(struct hdd_adapter *adapter, + enum netif_action_type action, enum netif_reason_type reason) +{ + uint32_t temp_map; + uint8_t index; + struct hdd_netif_queue_history *txq_hist_ptr; + + if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic) || + (!adapter->dev)) { + hdd_err("adapter is invalid"); + return; + } + + if (hdd_adapter_is_link_adapter(adapter)) + return; + + hdd_debug_rl("netif_control's vdev_id: %d, action: %d, reason: %d", + adapter->deflink->vdev_id, action, reason); + + switch (action) { + + case WLAN_NETIF_CARRIER_ON: + netif_carrier_on(adapter->dev); + break; + + case WLAN_NETIF_CARRIER_OFF: + netif_carrier_off(adapter->dev); + break; + + case WLAN_STOP_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + netif_tx_stop_all_queues(adapter->dev); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_STOP_NON_PRIORITY_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + wlan_hdd_stop_non_priority_queue(adapter); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_PRIORITY_QUEUE_ON: + spin_lock_bh(&adapter->pause_map_lock); + if (reason == WLAN_DATA_FLOW_CTRL_PRI) { + temp_map = adapter->subqueue_pause_map; + adapter->subqueue_pause_map &= ~(1 << reason); + } else { + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + } + if (!adapter->pause_map) { + netif_wake_subqueue(adapter->dev, + HDD_LINUX_AC_HI_PRIO * TX_QUEUES_PER_AC); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_PRIORITY_QUEUE_OFF: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + netif_stop_subqueue(adapter->dev, + HDD_LINUX_AC_HI_PRIO * TX_QUEUES_PER_AC); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + if (reason == WLAN_DATA_FLOW_CTRL_PRI) + adapter->subqueue_pause_map |= (1 << reason); + else + adapter->pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_BE_BK_QUEUE_OFF: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + hdd_stop_queues_for_ac(adapter->dev, HDD_LINUX_AC_BK); + hdd_stop_queues_for_ac(adapter->dev, HDD_LINUX_AC_BE); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->subqueue_pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_BE_BK_QUEUE_ON: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->subqueue_pause_map; + adapter->subqueue_pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + hdd_wake_queues_for_ac(adapter->dev, HDD_LINUX_AC_BK); + hdd_wake_queues_for_ac(adapter->dev, HDD_LINUX_AC_BE); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_VI_QUEUE_OFF: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + hdd_stop_queues_for_ac(adapter->dev, HDD_LINUX_AC_VI); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->subqueue_pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_VI_QUEUE_ON: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->subqueue_pause_map; + adapter->subqueue_pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + hdd_wake_queues_for_ac(adapter->dev, HDD_LINUX_AC_VI); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_VO_QUEUE_OFF: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + hdd_stop_queues_for_ac(adapter->dev, HDD_LINUX_AC_VO); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->subqueue_pause_map |= (1 << reason); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_VO_QUEUE_ON: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->subqueue_pause_map; + adapter->subqueue_pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + hdd_wake_queues_for_ac(adapter->dev, HDD_LINUX_AC_VO); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_START_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + netif_tx_start_all_queues(adapter->dev); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_WAKE_ALL_NETIF_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + netif_tx_wake_all_queues(adapter->dev); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_WAKE_NON_PRIORITY_QUEUE: + spin_lock_bh(&adapter->pause_map_lock); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + wlan_hdd_wake_non_priority_queue(adapter); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_STOP_ALL_NETIF_QUEUE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + if (!adapter->pause_map) { + netif_tx_stop_all_queues(adapter->dev); + wlan_hdd_update_txq_timestamp(adapter->dev); + wlan_hdd_update_unpause_time(adapter); + } + adapter->pause_map |= (1 << reason); + netif_carrier_off(adapter->dev); + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_START_ALL_NETIF_QUEUE_N_CARRIER: + spin_lock_bh(&adapter->pause_map_lock); + netif_carrier_on(adapter->dev); + temp_map = adapter->pause_map; + adapter->pause_map &= ~(1 << reason); + if (!adapter->pause_map) { + netif_tx_start_all_queues(adapter->dev); + wlan_hdd_update_pause_time(adapter, temp_map); + } + spin_unlock_bh(&adapter->pause_map_lock); + break; + + case WLAN_NETIF_ACTION_TYPE_NONE: + break; + + default: + hdd_err("unsupported action %d", action); + } + + spin_lock_bh(&adapter->pause_map_lock); + if (adapter->pause_map & (1 << WLAN_PEER_UNAUTHORISED)) + wlan_hdd_process_peer_unauthorised_pause(adapter); + + index = adapter->history_index++; + if (adapter->history_index == WLAN_HDD_MAX_HISTORY_ENTRY) + adapter->history_index = 0; + spin_unlock_bh(&adapter->pause_map_lock); + + wlan_hdd_update_queue_oper_stats(adapter, action, reason); + + adapter->queue_oper_history[index].time = qdf_system_ticks(); + adapter->queue_oper_history[index].netif_action = action; + adapter->queue_oper_history[index].netif_reason = reason; + if (reason >= WLAN_DATA_FLOW_CTRL_BE_BK) + adapter->queue_oper_history[index].pause_map = + adapter->subqueue_pause_map; + else + adapter->queue_oper_history[index].pause_map = + adapter->pause_map; + + txq_hist_ptr = &adapter->queue_oper_history[index]; + + wlan_hdd_update_queue_history_state(adapter->dev, txq_hist_ptr); +} + +void hdd_print_netdev_txq_status(struct net_device *dev) +{ + unsigned int i; + + if (!dev) + return; + + for (i = 0; i < dev->num_tx_queues; i++) { + struct netdev_queue *txq = netdev_get_tx_queue(dev, i); + + hdd_debug("netdev tx queue[%u] state:0x%lx", + i, txq->state); + } +} + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * hdd_set_mon_rx_cb() - Set Monitor mode Rx callback + * @dev: Pointer to net_device structure + * + * Return: 0 for success; non-zero for failure + */ +int hdd_set_mon_rx_cb(struct net_device *dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + int ret; + QDF_STATUS qdf_status; + struct ol_txrx_desc_type sta_desc = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_vdev *vdev; + + WLAN_ADDR_COPY(sta_desc.peer_addr.bytes, adapter->mac_addr.bytes); + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_DP_ID); + if (!vdev) { + hdd_err("failed to get vdev"); + return -EINVAL; + } + + qdf_status = ucfg_dp_mon_register_txrx_ops(vdev); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("failed to register txrx ops. Status= %d [0x%08X]", + qdf_status, qdf_status); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + goto exit; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + /* peer is created wma_vdev_attach->wma_create_peer */ + qdf_status = cdp_peer_register(soc, OL_TXRX_PDEV_ID, &sta_desc); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("cdp_peer_register() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + goto exit; + } + + qdf_status = sme_create_mon_session(hdd_ctx->mac_handle, + adapter->mac_addr.bytes, + adapter->deflink->vdev_id); + if (QDF_STATUS_SUCCESS != qdf_status) { + hdd_err("sme_create_mon_session() failed to register. Status= %d [0x%08X]", + qdf_status, qdf_status); + } + +exit: + ret = qdf_status_to_os_return(qdf_status); + return ret; +} +#endif + +void hdd_tx_queue_cb(hdd_handle_t hdd_handle, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason) +{ + struct hdd_context *hdd_ctx = hdd_handle_to_context(hdd_handle); + struct wlan_hdd_link_info *link_info; + + /* + * Validating the context is not required here. + * if there is a driver unload/SSR in progress happening in a + * different context and it has been scheduled to run and + * driver got a firmware event of sta kick out, then it is + * good to disable the Tx Queue to stop the influx of traffic. + */ + if (!hdd_ctx) { + hdd_err("Invalid context passed"); + return; + } + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + hdd_err("vdev_id %d does not exist with host", vdev_id); + return; + } + hdd_debug("Tx Queue action %d on vdev %d", action, vdev_id); + + wlan_hdd_netif_queue_control(link_info->adapter, action, reason); +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_ini_tx_flow_control() - Initialize INIs concerned about tx flow control + * @config: pointer to hdd config + * @psoc: pointer to psoc obj + * + * Return: none + */ +static void hdd_ini_tx_flow_control(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->tx_flow_low_watermark = + cfg_get(psoc, CFG_DP_LL_TX_FLOW_LWM); + config->tx_flow_hi_watermark_offset = + cfg_get(psoc, CFG_DP_LL_TX_FLOW_HWM_OFFSET); + config->tx_flow_max_queue_depth = + cfg_get(psoc, CFG_DP_LL_TX_FLOW_MAX_Q_DEPTH); + config->tx_lbw_flow_low_watermark = + cfg_get(psoc, CFG_DP_LL_TX_LBW_FLOW_LWM); + config->tx_lbw_flow_hi_watermark_offset = + cfg_get(psoc, CFG_DP_LL_TX_LBW_FLOW_HWM_OFFSET); + config->tx_lbw_flow_max_queue_depth = + cfg_get(psoc, CFG_DP_LL_TX_LBW_FLOW_MAX_Q_DEPTH); + config->tx_hbw_flow_low_watermark = + cfg_get(psoc, CFG_DP_LL_TX_HBW_FLOW_LWM); + config->tx_hbw_flow_hi_watermark_offset = + cfg_get(psoc, CFG_DP_LL_TX_HBW_FLOW_HWM_OFFSET); + config->tx_hbw_flow_max_queue_depth = + cfg_get(psoc, CFG_DP_LL_TX_HBW_FLOW_MAX_Q_DEPTH); +} +#else +static void hdd_ini_tx_flow_control(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +#ifdef WLAN_FEATURE_MSCS +/** + * hdd_ini_mscs_params() - Initialize INIs related to MSCS feature + * @config: pointer to hdd config + * @psoc: pointer to psoc obj + * + * Return: none + */ +static void hdd_ini_mscs_params(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ + config->mscs_pkt_threshold = + cfg_get(psoc, CFG_VO_PKT_COUNT_THRESHOLD); + config->mscs_voice_interval = + cfg_get(psoc, CFG_MSCS_VOICE_INTERVAL); +} + +#else +static inline void hdd_ini_mscs_params(struct hdd_config *config, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +void hdd_dp_cfg_update(struct wlan_objmgr_psoc *psoc, + struct hdd_context *hdd_ctx) +{ + struct hdd_config *config; + + config = hdd_ctx->config; + + config->napi_cpu_affinity_mask = + cfg_get(psoc, CFG_DP_NAPI_CE_CPU_MASK); + config->cfg_wmi_credit_cnt = cfg_get(psoc, CFG_DP_HTC_WMI_CREDIT_CNT); + + hdd_ini_tx_flow_control(config, psoc); + hdd_ini_mscs_params(config, psoc); +} + +#ifdef QCA_LL_LEGACY_TX_FLOW_CONTROL +/** + * hdd_set_tx_flow_info() - To set TX flow info + * @adapter: pointer to adapter + * @pre_adp_ctx: pointer to pre-adapter + * @target_channel: target channel + * @pre_adp_channel: pre-adapter channel + * @dbgid: Debug IDs + * + * This routine is called to set TX flow info + * + * Return: None + */ +static void hdd_set_tx_flow_info(struct hdd_adapter *adapter, + struct hdd_adapter **pre_adp_ctx, + uint8_t target_channel, + uint8_t *pre_adp_channel, + wlan_net_dev_ref_dbgid dbgid) +{ + struct hdd_context *hdd_ctx; + uint8_t channel24; + uint8_t channel5; + struct hdd_adapter *adapter2_4 = NULL; + struct hdd_adapter *adapter5 = NULL; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + if (!target_channel) + return; + + /* + * This is first adapter detected as active + * set as default for none concurrency case + */ + if (!(*pre_adp_channel)) { + /* If IPA UC data path is enabled, + * target should reserve extra tx descriptors + * for IPA data path. + * Then host data path should allow less TX + * packet pumping in case IPA + * data path enabled + */ + if (ucfg_ipa_uc_is_enabled() && + adapter->device_mode == QDF_SAP_MODE) { + adapter->tx_flow_low_watermark = + hdd_ctx->config->tx_flow_low_watermark + + WLAN_TFC_IPAUC_TX_DESC_RESERVE; + } else { + adapter->tx_flow_low_watermark = + hdd_ctx->config->tx_flow_low_watermark; + } + adapter->tx_flow_hi_watermark_offset = + hdd_ctx->config->tx_flow_hi_watermark_offset; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter->deflink->vdev_id, + hdd_ctx->config->tx_flow_max_queue_depth); + hdd_debug("MODE %d,CH %d,LWM %d,HWM %d,TXQDEP %d", + adapter->device_mode, + target_channel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter->tx_flow_hi_watermark_offset, + hdd_ctx->config->tx_flow_max_queue_depth); + *pre_adp_channel = target_channel; + *pre_adp_ctx = adapter; + } else { + /* + * SCC, disable TX flow control for both + * SCC each adapter cannot reserve dedicated + * channel resource, as a result, if any adapter + * blocked OS Q by flow control, + * blocked adapter will lost chance to recover + */ + if (*pre_adp_channel == target_channel) { + /* Current adapter */ + adapter->tx_flow_low_watermark = 0; + adapter->tx_flow_hi_watermark_offset = 0; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter->deflink->vdev_id, + hdd_ctx->config->tx_hbw_flow_max_queue_depth); + hdd_debug("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode, + target_channel, + adapter->tx_flow_low_watermark, + adapter->tx_flow_low_watermark + + adapter->tx_flow_hi_watermark_offset, + hdd_ctx->config->tx_hbw_flow_max_queue_depth); + + if (!(*pre_adp_ctx)) { + hdd_err("SCC: Previous adapter context NULL"); + hdd_adapter_dev_put_debug(adapter, dbgid); + return; + } + + /* Previous adapter */ + (*pre_adp_ctx)->tx_flow_low_watermark = 0; + (*pre_adp_ctx)->tx_flow_hi_watermark_offset = 0; + cdp_fc_ll_set_tx_pause_q_depth(soc, + (*pre_adp_ctx)->deflink->vdev_id, + hdd_ctx->config->tx_hbw_flow_max_queue_depth); + hdd_debug("SCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + qdf_opmode_str((*pre_adp_ctx)->device_mode), + (*pre_adp_ctx)->device_mode, + target_channel, + (*pre_adp_ctx)->tx_flow_low_watermark, + (*pre_adp_ctx)->tx_flow_low_watermark + + (*pre_adp_ctx)->tx_flow_hi_watermark_offset, + hdd_ctx->config->tx_hbw_flow_max_queue_depth); + } else { + /* + * MCC, each adapter will have dedicated + * resource + */ + /* current channel is 2.4 */ + if (target_channel <= + WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH) { + channel24 = target_channel; + channel5 = *pre_adp_channel; + adapter2_4 = adapter; + adapter5 = *pre_adp_ctx; + } else { + /* Current channel is 5 */ + channel24 = *pre_adp_channel; + channel5 = target_channel; + adapter2_4 = *pre_adp_ctx; + adapter5 = adapter; + } + + if (!adapter5) { + hdd_err("MCC: 5GHz adapter context NULL"); + hdd_adapter_dev_put_debug(adapter, dbgid); + return; + } + adapter5->tx_flow_low_watermark = + hdd_ctx->config->tx_hbw_flow_low_watermark; + adapter5->tx_flow_hi_watermark_offset = + hdd_ctx->config->tx_hbw_flow_hi_watermark_offset; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter5->deflink->vdev_id, + hdd_ctx->config->tx_hbw_flow_max_queue_depth); + hdd_debug("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + qdf_opmode_str(adapter5->device_mode), + adapter5->device_mode, + channel5, + adapter5->tx_flow_low_watermark, + adapter5->tx_flow_low_watermark + + adapter5->tx_flow_hi_watermark_offset, + hdd_ctx->config->tx_hbw_flow_max_queue_depth); + + if (!adapter2_4) { + hdd_err("MCC: 2.4GHz adapter context NULL"); + hdd_adapter_dev_put_debug(adapter, dbgid); + return; + } + adapter2_4->tx_flow_low_watermark = + hdd_ctx->config->tx_lbw_flow_low_watermark; + adapter2_4->tx_flow_hi_watermark_offset = + hdd_ctx->config->tx_lbw_flow_hi_watermark_offset; + cdp_fc_ll_set_tx_pause_q_depth(soc, + adapter2_4->deflink->vdev_id, + hdd_ctx->config->tx_lbw_flow_max_queue_depth); + hdd_debug("MCC: MODE %s(%d), CH %d, LWM %d, HWM %d, TXQDEP %d", + qdf_opmode_str(adapter2_4->device_mode), + adapter2_4->device_mode, + channel24, + adapter2_4->tx_flow_low_watermark, + adapter2_4->tx_flow_low_watermark + + adapter2_4->tx_flow_hi_watermark_offset, + hdd_ctx->config->tx_lbw_flow_max_queue_depth); + } + } +} + +void wlan_hdd_set_tx_flow_info(void) +{ + struct hdd_adapter *adapter, *next_adapter = NULL; + struct hdd_station_ctx *sta_ctx; + struct hdd_ap_ctx *ap_ctx; + struct hdd_hostapd_state *hostapd_state; + uint8_t sta_chan = 0, ap_chan = 0; + uint32_t chan_freq; + struct hdd_context *hdd_ctx; + uint8_t target_channel = 0; + uint8_t pre_adp_channel = 0; + struct hdd_adapter *pre_adp_ctx = NULL; + wlan_net_dev_ref_dbgid dbgid = NET_DEV_HOLD_IPA_SET_TX_FLOW_INFO; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + hdd_for_each_adapter_dev_held_safe(hdd_ctx, adapter, next_adapter, + dbgid) { + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + sta_ctx = + WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (hdd_cm_is_vdev_associated(adapter->deflink)) { + chan_freq = sta_ctx->conn_info.chan_freq; + sta_chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, + chan_freq); + target_channel = sta_chan; + } + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + ap_ctx = WLAN_HDD_GET_AP_CTX_PTR(adapter->deflink); + hostapd_state = + WLAN_HDD_GET_HOSTAP_STATE_PTR(adapter->deflink); + if (hostapd_state->bss_state == BSS_START && + hostapd_state->qdf_status == QDF_STATUS_SUCCESS) { + chan_freq = ap_ctx->operating_chan_freq; + ap_chan = wlan_reg_freq_to_chan(hdd_ctx->pdev, + chan_freq); + target_channel = ap_chan; + } + break; + default: + break; + } + + hdd_set_tx_flow_info(adapter, + &pre_adp_ctx, + target_channel, + &pre_adp_channel, + dbgid); + target_channel = 0; + + hdd_adapter_dev_put_debug(adapter, dbgid); + } +} +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_unit_test.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_unit_test.c new file mode 100644 index 0000000000..30081923bf --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_unit_test.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_unit_test.c + * + * config wlan_hdd_unit_test which will be used by wext and + * debugfs unit_test_host + */ +#include "wlan_hdd_main.h" +#include "qdf_delayed_work_test.h" +#include "qdf_hashtable_test.h" +#include "qdf_periodic_work_test.h" +#include "qdf_ptr_hash_test.h" +#include "qdf_slist_test.h" +#include "qdf_talloc_test.h" +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_tracker_test.h" +#include "qdf_types_test.h" +#include "wlan_dsc_test.h" +#include "wlan_hdd_unit_test.h" + +typedef uint32_t (*hdd_ut_callback)(void); + +struct hdd_ut_entry { + const hdd_ut_callback callback; + const char *name; +}; + +struct hdd_ut_entry hdd_ut_entries[] = { + { .name = "dsc", .callback = dsc_unit_test }, + { .name = "qdf_delayed_work", .callback = qdf_delayed_work_unit_test }, + { .name = "qdf_ht", .callback = qdf_ht_unit_test }, + { .name = "qdf_periodic_work", + .callback = qdf_periodic_work_unit_test }, + { .name = "qdf_ptr_hash", .callback = qdf_ptr_hash_unit_test }, + { .name = "qdf_slist", .callback = qdf_slist_unit_test }, + { .name = "qdf_talloc", .callback = qdf_talloc_unit_test }, + { .name = "qdf_tracker", .callback = qdf_tracker_unit_test }, + { .name = "qdf_types", .callback = qdf_types_unit_test }, +}; + +#define hdd_for_each_ut_entry(cursor) \ + for (cursor = hdd_ut_entries; \ + cursor < hdd_ut_entries + ARRAY_SIZE(hdd_ut_entries); \ + cursor++) + +static struct hdd_ut_entry *hdd_ut_lookup(const char *name) +{ + struct hdd_ut_entry *entry; + + hdd_for_each_ut_entry(entry) { + if (qdf_str_eq(entry->name, name)) + return entry; + } + + return NULL; +} + +static uint32_t hdd_ut_single(const struct hdd_ut_entry *entry) +{ + uint32_t errors; + + hdd_nofl_info("START: '%s'", entry->name); + + errors = entry->callback(); + if (errors) + hdd_nofl_err("FAIL: '%s' with %u errors", entry->name, errors); + else + hdd_nofl_info("PASS: '%s'", entry->name); + + return errors; +} + +int wlan_hdd_unit_test(struct hdd_context *hdd_ctx, const char *name) +{ + struct hdd_ut_entry *entry; + uint32_t errors = 0; + + hdd_nofl_info("Unit tests begin"); + + if (!name || !name[0] || qdf_str_eq(name, "all")) { + hdd_for_each_ut_entry(entry) + errors += hdd_ut_single(entry); + } else { + entry = hdd_ut_lookup(name); + if (entry) { + errors += hdd_ut_single(entry); + } else { + hdd_nofl_err("Unit test '%s' not found", name); + return -EINVAL; + } + } + + hdd_nofl_info("Unit tests complete"); + + return errors ? -EPERM : 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_unit_test.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_unit_test.h new file mode 100644 index 0000000000..b20e1d204e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_unit_test.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_unit_test.h + * + * config wlan_hdd_unit_test + */ + +#ifndef _WLAN_HDD_UNIT_TEST_H +#define _WLAN_HDD_UNIT_TEST_H + +#ifdef WLAN_UNIT_TEST +/** + * wlan_hdd_unit_test() - API to begin unit test on host side + * @hdd_ctx: hdd context + * @name: test item name + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_unit_test(struct hdd_context *hdd_ctx, const char *name); +#else +static inline int +wlan_hdd_unit_test(struct hdd_context *hdd_ctx, const char *name) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* _WLAN_HDD_UNIT_TEST_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wds.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wds.c new file mode 100644 index 0000000000..d946bb0531 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wds.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_wds.c + * + * WLAN Host Device Driver file for wds (4 address frame header when + * SA and TA are different) support. + * + */ + +/* Include Files */ +#include +#include +#include "wlan_hdd_wds.h" + +void hdd_wds_config_dp_repeater_mode(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + ol_txrx_soc_handle soc; + cdp_config_param_type vdev_param; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) + return; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) + return; + + if (!wlan_mlme_get_wds_mode(psoc)) + return; + + soc = wlan_psoc_get_dp_handle(psoc); + + vdev_param.cdp_vdev_param_wds = true; + if (cdp_txrx_set_vdev_param(soc, vdev->vdev_objmgr.vdev_id, + CDP_ENABLE_WDS, + vdev_param)) + hdd_debug("Failed to set WDS param on DP vdev"); +} + +void +hdd_wds_replace_peer_mac(void *soc, struct hdd_adapter *adapter, + uint8_t *mac_addr) +{ + struct cdp_ast_entry_info ast_entry_info = {0}; + cdp_config_param_type val; + QDF_STATUS status; + + if (!cdp_find_peer_exist(soc, OL_TXRX_PDEV_ID, mac_addr)) { + status = cdp_txrx_get_vdev_param(soc, adapter->deflink->vdev_id, + CDP_ENABLE_WDS, &val); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + + if (!val.cdp_vdev_param_wds) + return; + + if (!cdp_peer_get_ast_info_by_soc(soc, mac_addr, + &ast_entry_info)) + return; + + qdf_mem_copy(mac_addr, ast_entry_info.peer_mac_addr, + QDF_MAC_ADDR_SIZE); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wds.h b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wds.h new file mode 100644 index 0000000000..1e22f1f052 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wds.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_wds.h + * + * WLAN Host Device Driver file for wds (4 address format in mac header when + * SA and TA are not same) support. + * + */ + +#if !defined(WLAN_HDD_WDS_H) +#define WLAN_HDD_WDS_H + +struct wlan_objmgr_vdev; +struct hdd_adapter; + +#ifdef FEATURE_WDS +/** + * hdd_wds_config_dp_repeater_mode - Function to enable wds on the AP vdev + * @vdev: object manager vdev context + * + * Set the wds_enabled flag for dp vdev. The wds source port learning + * is triggered when this flag is enabled and AST entry for the remote + * station(wds node) is added to the AST list. + * + * Return: None + */ +void hdd_wds_config_dp_repeater_mode(struct wlan_objmgr_vdev *vdev); + +/** + * hdd_wds_replace_peer_mac() - Replace the mac address for the wds next hop + * @soc: SOC TXRX handle + * @adapter: the pointer to adapter + * @mac_addr: mac address of the peer or wds station + * + * The wds stations are reachable through a directly connected peer. + * Replace the destination address with the mac address of the next + * hop peer to reach the wds station, if the destination is not a + * directly connected peer. + * + * Return: None + */ +void hdd_wds_replace_peer_mac(void *soc, struct hdd_adapter *adapter, + uint8_t *mac_addr); +#else +static inline +void hdd_wds_config_dp_repeater_mode(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +void hdd_wds_replace_peer_mac(void *soc, struct hdd_adapter *adapter, + uint8_t *mac_addr) +{ +} +#endif /* FEATURE_WDS*/ +#endif /* if !defined(WLAN_HDD_WDS_H)*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c new file mode 100644 index 0000000000..2a75a97c66 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c @@ -0,0 +1,9860 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_wext.c + * + * Linux Wireless Extensions Implementation + */ + +#include +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include "scheduler_api.h" +#include +#include +#include +#include "sir_params.h" +#include "csr_api.h" +#include "csr_inside_api.h" +#include "sme_rrm_internal.h" +#include +#include "dot11f.h" +#include +#include +#include +#include "utils_api.h" +#include "wlan_hdd_p2p.h" +#ifdef FEATURE_WLAN_TDLS +#include "wlan_hdd_tdls.h" +#endif + +#include "cds_ieee80211_common.h" +#include "ol_if_athvar.h" +#include "dbglog_host.h" +#include "wma.h" + +#include + +#include "wlan_hdd_power.h" +#include "qwlan_version.h" +#include "wlan_hdd_host_offload.h" + +#include +#include + +#include "wlan_hdd_misc.h" + +#include "qc_sap_ioctl.h" +#include "sme_api.h" +#include "wma_types.h" +#include "wlan_hdd_assoc.h" +#include "wlan_hdd_ioctl.h" +#include "wlan_hdd_scan.h" +#include "sme_power_save_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_fips.h" +#include "wlan_hdd_tsf.h" +#include "wlan_hdd_ocb.h" +#include "wlan_hdd_napi.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "wlan_hdd_nan_datapath.h" +#include "wlan_hdd_stats.h" +#ifdef WLAN_SUSPEND_RESUME_TEST +#include "wlan_hdd_driver_ops.h" +#include "hif.h" +#endif +#include "pld_common.h" +#include "cds_utils.h" +#include "wlan_osif_request_manager.h" +#include "os_if_wifi_pos.h" +#include +#include +#include "wlan_dsc_test.h" +#include +#include "wlan_hdd_regulatory.h" +#include "wlan_reg_ucfg_api.h" +#include "wlan_hdd_packet_filter_api.h" +#include "wlan_cp_stats_mc_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "cfg_mlme_sta.h" +#include "wlan_mlme_public_struct.h" +#include "cfg_ucfg_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_mlme_public_struct.h" +#include "cfg_ucfg_api.h" +#include "cfg_mlme_threshold.h" +#include "wlan_pmo_cfg.h" +#include "wlan_pmo_ucfg_api.h" +#include "wlan_dp_rx_thread.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_hdd_unit_test.h" +#include "wlan_hdd_thermal.h" +#include "wlan_cm_roam_ucfg_api.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_dp_ucfg_api.h" + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_INT_GET_NONE (SIOCIWFIRSTPRIV + 0) +#define WE_SET_11D_STATE 1 +#define WE_WOWL 2 +#define WE_SET_POWER 3 +/* + * + * setMaxAssoc - Sets the maximum number of associated stations + * + * @INPUT: 1 to 32 + * + * @OUTPUT: None + * + * This IOTCL sets the maximum number of associated stations + * + * @E.g: iwpriv wlan0 setMaxAssoc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MAX_ASSOC 4 +/* + * + * scan_disable - Disable scan + * + * @INPUT: set_value + * + * @OUTPUT: None + * + * This IOCTL is used to set disable scan + * + * @E.g: iwpriv wlan0 scan_disable 1 + * + * Supported Feature: Scan + * + * Usage: Internal/External + * + * + */ +#define WE_SET_SCAN_DISABLE 5 +/* + * + * inactivityTO - sets the timeout value for inactivity data while + * in power save mode + * + * @INPUT: int1…..int255 + * + * @OUTPUT: None + * + * This IOCTL set the timeout value for inactivity data in power save mode + * + * @E.g: iwpriv wlan0 inactivityTO 20 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DATA_INACTIVITY_TO 6 +/* + * + * setMaxTxPower - Dynamically sets the maximum transmission power + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL dynamically sets the maximum transmission power + * This setting does not persist over reboots + * + * @E.g: iwpriv wlan0 setMaxTxPower + */ +#define WE_SET_MAX_TX_POWER 7 + +#ifdef HASTINGS_BT_WAR +/* Temporary WAR for Hastings 1.1 only */ +#define WE_SET_HASTINGS_BT_WAR 8 +#endif + +#define WE_SET_TM_LEVEL 9 + +/* + * + * setphymode - Set the phymode dynamically + * + * @INPUT: 0 IEEE80211_MODE_AUTO to 22 IEEE80211_MODE_11AGN + * + * @OUTPUT: None + * + * This IOCTL sets the phymode dynamically + * + * @E.g: iwpriv wlan0 setphymode 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_PHYMODE 10 +/* + * + * nss - Set the number of spatial streams + * + * @INPUT: int1…..int3 + * + * @OUTPUT: None + * + * This IOCTL sets the number of spatial streams. Supported values are 1 and 2 + * + * @E.g: iwpriv wlan0 nss 2 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_NSS 11 +/* + * + * ldpc - Enables or disables LDPC + * + * @INPUT: 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOCTL enables or disables LDPC + * + * @E.g: iwpriv wlan0 ldpc 1 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_LDPC 12 +/* + * + * tx_stbc - Enables or disables tx_stbc + * + * @INPUT: Int 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOTCL used to enables or disables tx_stbc + * + * @E.g: iwpriv wlan0 tx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TX_STBC 13 +/* + * + * rx_stbc - Set the rx_stbc parameter + * + * @INPUT: Int 0 – Disable, 1 - Enable + * + * @OUTPUT: None + * + * This IOTCL used to set rx_stbc parameter + * + * @E.g: iwpriv wlan0 rx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_RX_STBC 14 +/* + * + * shortgi - Sets the short-guard interval + * + * @INPUT: Fixed Rate: 0 - 400ns, 1 - 800ns, 2 - 1600ns, 3 - 3200us + * Auto Rate: 8 - 400ns, 9 - 800ns, 10 - 1600ns, 11 - 3200us + * + * @OUTPUT: None + * + * This IOCTL sets the short-guard interval. + * + * @E.g: iwpriv wlan0 shortgi + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_SHORT_GI 15 +/* + * + * enablertscts - enables or disables rts/cts. + * + * @INPUT: 1-Enable , 0-Disable + * + * @OUTPUT: None + * + * This IOCTL enables or disables rts/cts. + * + * @E.g: iwpriv wlan0 enablertscts + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_RTSCTS 16 +/* + * + * chwidth - Set the channel bandwidth + * + * @INPUT: 0-20mhz to 3-160mhz + * + * @OUTPUT: None + * + * This IOTCL used to set the channel bandwidth + * + * @E.g: iwpriv wlan0 chwidth 1 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_CHWIDTH 17 +#define WE_SET_ANI_EN_DIS 18 +#define WE_SET_ANI_POLL_PERIOD 19 +#define WE_SET_ANI_LISTEN_PERIOD 20 +#define WE_SET_ANI_OFDM_LEVEL 21 +#define WE_SET_ANI_CCK_LEVEL 22 +/* + * + * cwmenable - Enables or disables the dynamic channel bandwidth + * + * @INPUT: 0-Disable, 1-Enable + * + * @OUTPUT: None + * + * This IOTCL used to enables or disables the dynamic channel bandwidth + * + * @E.g: iwpriv wlan0 cwmenable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DYNAMIC_BW 23 +/* + * + * txchainmask - This IOCTL sets the current Tx chain mask + * + * @INPUT: Mask Value + * + * @OUTPUT: None + * + * This IOCTL sets the current Tx chain mask + * + * @E.g: iwpriv wlan0 txchainmask 1 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TX_CHAINMASK 24 +/* + * + * rxchainmask - Sets the current Rx chain mask + * + * @INPUT: Mask Value + * + * @OUTPUT: None + * + * This IOCTL sets the current Rx chain mask. This command is the + * equivalent to setting in gSetRxChainmask1x1 in WCNSS_qcom_cfg.ini. + * + * @E.g: iwpriv wlan0 rxchainmask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_RX_CHAINMASK 25 +/* + * + * set11NRates - Fixes the Tx data rate of the 11N mode. + * + * @INPUT: 0x1b to 0x8f + * + * @OUTPUT: None + * + * This IOCTL fixes the Tx data rate of the 11N mode. + * + * @E.g: iwpriv wlan0 set11NRates 0x85 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_11N_RATE 26 +/* + * + * ampdu - Set the the maximum subframe of ampdu + * + * @INPUT: int 1 to int 63 + * + * @OUTPUT: None + * + * This IOCTL sets the maximum subframe of ampdu. + * + * @E.g: iwpriv wlan0 ampdu 9 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_AMPDU 27 +/* + * + * amsdu - Sets the maximum subframe of amsdu. + * + * @INPUT: int 1 to int 31 + * + * @OUTPUT: None + * + * This IOCTL sets the maximum subframe of amsdu. + * + * @E.g: iwpriv wlan0 amsdu 9 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_AMSDU 28 +/* + * + * txpow2g - current 2 GHz Tx power setting + * + * @INPUT: Tx power in dBm + * + * @OUTPUT: None + * + * This IOTCL used to set 2 ghz tx power + * + * @E.g: iwpriv wlan0 txpow2g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TXPOW_2G 29 +/* + * + * txpow5g - Current 5 GHz tx power setting + * + * @INPUT: Tx power in dBm + * + * @OUTPUT: None + * + * This IOTCL used to set the 5 ghz txpower + * + * @E.g: iwpriv wlan0 txpow5g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TXPOW_5G 30 +/* Private ioctl for firmware debug log */ +#define WE_DBGLOG_LOG_LEVEL 31 +#define WE_DBGLOG_VAP_ENABLE 32 +#define WE_DBGLOG_VAP_DISABLE 33 +#define WE_DBGLOG_MODULE_ENABLE 34 +#define WE_DBGLOG_MODULE_DISABLE 35 +#define WE_DBGLOG_MOD_LOG_LEVEL 36 +#define WE_DBGLOG_TYPE 37 +#define WE_SET_TXRX_FWSTATS 38 +/* + * + * set11ACRates - Fixes the Tx data rate of 11AC + * + * @INPUT: 0x1 to 0x9 + * + * @OUTPUT: None + * + * This IOCTL fixes the Tx data rate of 11AC. + * + * @E.g: iwpriv wlan0 set11ACRates 0x9 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_VHT_RATE 39 +#define WE_DBGLOG_REPORT_ENABLE 40 +#define WE_TXRX_FWSTATS_RESET 41 +/* + * + * setTxMaxPower2G - Set the maximum transmit power for the 2.4-GHz band + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL sets the maximum transmit power for the 2.4-GHz band + * This setting does not persist over reboots + * + * @E.g: iwpriv wlan0 setTxMaxPower2G 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MAX_TX_POWER_2_4 42 +/* + * + * setTxMaxPower5G - Set the maximum transmit power for the 5-GHz band + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL sets the maximum transmit power for the 5-GHz band + * This setting does not persist over reboots + * + * @E.g: iwpriv wlan0 setTxMaxPower5G 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MAX_TX_POWER_5_0 43 +#define WE_SET_PKTLOG 44 +/* Private ioctl for packet power save */ +#define WE_PPS_PAID_MATCH 45 +#define WE_PPS_GID_MATCH 46 +#define WE_PPS_EARLY_TIM_CLEAR 47 +#define WE_PPS_EARLY_DTIM_CLEAR 48 +#define WE_PPS_EOF_PAD_DELIM 49 +#define WE_PPS_MACADDR_MISMATCH 50 +#define WE_PPS_DELIM_CRC_FAIL 51 +#define WE_PPS_GID_NSTS_ZERO 52 +/* + * + * rssi_chk - Check the rssi + * + * @INPUT: One argument as input + * + * @OUTPUT: rssi + * wlan0 rssi_chk:56 + * + * This IOTCL used to check rssi + * + * @E.g: iwpriv wlan0 rssi_chk + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_PPS_RSSI_CHECK 53 +/* + * + * htsmps - Sets the htsmps + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL used to set htsmps + * + * @E.g: iwpriv wlan0 htsmps + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_HTSMPS 55 +/* Private ioctl for QPower */ +#define WE_SET_QPOWER_MAX_PSPOLL_COUNT 56 +#define WE_SET_QPOWER_MAX_TX_BEFORE_WAKE 57 +#define WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 58 +#define WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 59 +/* GTX Commands */ +/* + * + * gtxHTMcs - Set the tx HTM value + * + * @INPUT: Atleast one int orgument + * + * @OUTPUT: None + * + * This IOTCL sets htm tx value + * + * @E.g: iwpriv wlan0 gtxHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_HT_MCS 62 +/* + * + * gtxVHTMcs - Set gtxVHTMcs value + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL used to set gtxVHTMcs value + * + * @E.g: iwpriv wlan0 gtxVHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_VHT_MCS 63 +/* + * + * gtxUsrCfg - Host request for GTX mask + * + * @INPUT: Atleast one int orgument + * + * @OUTPUT: None + * + * This IOTCL used send the host request for GTX mask + * + * @E.g: iwpriv wlan0 gtxUsrCfg + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_USRCFG 64 +/* + * + * gtxThre - Set the tx threshold + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL used to set tx threshold + * + * @E.g: iwpriv wlan0 gtxThre + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_THRE 65 +/* + * + * gtxMargin - Set the gtxMargin + * + * @INPUT: 1 to 32 + * + * @OUTPUT: None + * + * This IOTCL use dto set gtxMargin + * + * @E.g: iwpriv wlan0 gtxMargini + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_MARGIN 66 +/* + * + * gtxStep - Set the gtxStep + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOTCL used to sets gtxStep + * + * @E.g: iwpriv wlan0 gtxStep + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_STEP 67 +/* + * + * gtxMinTpc - Sets the gtxMinTpc + * + * @INPUT: Atleast one int argument + * + * @OUTPUT: None + * + * This IOTCL sets the tx MinTpc + * + * @E.g: iwpriv wlan0 gtxMinTpc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_GTX_MINTPC 68 +/* + * + * gtxBWMask - Sets the BW mask (20/40/80/160 Mhz) + * + * @INPUT: Mask value + * + * @OUTPUT: None + * + * This IOTCL used to set gtxBWMask + * + * @E.g: iwpriv wlan0 gtxBWMask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define WE_SET_GTX_BWMASK 69 +/* + * + * setMccLatency - Sets the MCC latency value during STA-P2P concurrency + * + * @INPUT: set_value + * + * @OUTPUT: None + * + * This IOCTL is used to set the MCC latency value in milliseconds + * during STA-P2P concurrency. + * + * If 0ms latency is provided, then FW will set to a default. + * Otherwise, latency must be at least 30ms. + * + * @E.g: iwpriv wlan0 setMccLatency 40 + * + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define WE_MCC_CONFIG_LATENCY 70 + +/* + * + * setMccQuota- Set the quota for P2P cases + * + * @INPUT: set_value [0,100] + * + * @OUTPUT: None + * + * This IOCTL is used to set the quota in milliseconds for P2P_GO/STA. + * + * Currently used to set time quota for 2 MCC vdevs/adapters using + * (operating channel, quota) for each mode. + * The info is provided run time using iwpriv command: + * iwpriv setMccQuota . + * Note: the quota provided in command is for the same mode in cmd. + * HDD checks if MCC mode is active, gets the second mode and its + * operating chan. + * Quota for the 2nd role is calculated as 100 - quota of first mode. + * + * @E.g: iwpriv wlan0 setMccQuota 50 + * iwpriv p2p0 setMccQuota 50 + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define WE_MCC_CONFIG_QUOTA 71 +/* Private IOCTL for debug connection issues */ +#define WE_SET_DEBUG_LOG 72 +#ifdef WE_SET_TX_POWER +#undef WE_SET_TX_POWER +#endif + +/* + * + * setTxPower - Set the current transmit power + * + * @INPUT: Transmission power in dBm + * + * @OUTPUT: None + * + * This IOCTL sets the current transmit power. + * This setting does not persist over reboots. + * + * @E.g: iwpriv wlan0 setTxPower 10 + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_TX_POWER 74 +/* Private ioctl for earlyrx power save feature */ +#define WE_SET_EARLY_RX_ADJUST_ENABLE 75 +#define WE_SET_EARLY_RX_TGT_BMISS_NUM 76 +#define WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE 77 +#define WE_SET_EARLY_RX_SLOP_STEP 78 +#define WE_SET_EARLY_RX_INIT_SLOP 79 +#define WE_SET_EARLY_RX_ADJUST_PAUSE 80 +/* + * + * setMcRate - Set the data rate for multicast data + * + * @INPUT: 1 to 32 + * + * @OUTPUT: None + * + * This IOCTL sets the data rate for multicast data. Note that this command + * is allowed only in STA or QCMobileAP mode + * + * @E.g: iwpriv wlan0 setMcRate + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MC_RATE 81 +#define WE_SET_EARLY_RX_DRIFT_SAMPLE 82 +/* Private ioctl for packet power save */ +/* + * + * 5g_ebt - Sets the 5g_ebt + * + * @INPUT: + * + * @OUTPUT: None + * + * This IOTCL used to set 5g_ebt + * + * @E.g: iwpriv wlan0 5g_ebt + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_PPS_5G_EBT 83 +/* + * + * cts_cbw - Set CTS channel BW for dynamic BW adjustment + * + * @INPUT: 20 t0 160 + * + * @OUTPUT: None + * + * This IOTCL used to set CTS channel BW for dynamic BW adjustment + * + * @E.g: iwpriv wlan0 cts_cbw + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_CTS_CBW 84 +#define WE_DUMP_STATS 85 +#define WE_CLEAR_STATS 86 +/* Private sub ioctl for starting/stopping the profiling */ +#define WE_START_FW_PROFILE 87 + +/* + * + * setChanChange - Initiate channel change + * + * @INPUT: channel number to switch to. + * + * @OUTPUT: None + * + * This IOCTL is used to initiate a channel change. + * If called on STA/CLI interface it will send the + * ECSA action frame to the connected SAP/GO asking to + * initiate the ECSA, if supported. + * If called on SAP/GO interface it will initiate + * ECSA and ask connected peers to move to new channel. + * + * @E.g: iwpriv wlan0 setChanChange + * iwpriv wlan0 setChanChange 1 + * + * Supported Feature: ECSA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_CHANNEL 88 +#define WE_SET_CONC_SYSTEM_PREF 89 + +/* + * + * set_11ax_rate - set 11ax rates to FW + * + * @INPUT: rate code + * + * @OUTPUT: None + * + * This IOCTL fixes the Tx data rate of 11AX. + * + * @E.g: iwpriv wlan0 set_11ax_rate + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ +#define WE_SET_11AX_RATE 91 + +/* + * + * enable_dcm - enable Dual Carrier Modulation(DCM) + * + * @INPUT: 0/1 + * + * @OUTPUT: None + * + * This IOCTL enables/disables DCM. + * + * @E.g: iwpriv wlan0 enable_dcm <0/1> + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ +#define WE_SET_DCM 92 + +/* + * + * range_ext - enable Range extension + * + * @INPUT: 0/1 + * + * @OUTPUT: None + * + * This IOCTL enables/disables Range extension. + * + * @E.g: iwpriv wlan0 range_ext <1/0> + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ +#define WE_SET_RANGE_EXT 93 + +/* + * + * wow_ito - sets the timeout value for inactivity data while + * in power save mode during wow + * + * @INPUT: int + * + * @OUTPUT: None + * + * This IOCTL set the timeout value for inactivity data in power save mode + * + * @E.g: iwpriv wlan0 wow_ito 20 + * + * Supported Feature: STA + * + * Usage: External + * + * + */ +#define WE_SET_WOW_DATA_INACTIVITY_TO 94 + +/* + * + * pdev_reset - reset the pdev + * + * @INPUT: Reset command to initiate: + * TX_FLUSH = 1 + * WARM_RESET = 2 + * COLD_RESET = 3 + * WARM_RESET_RESTORE_CAL = 4 + * COLD_RESET_RESTORE_CAL = 5 + * + * @OUTPUT: None + * + * This IOCTL is used to reset the pdev. The primary use is + * for internal testing. It is not expected that this will + * be used on a production device. + * + * @E.g: iwpriv wlan0 pdev_reset + * iwpriv wlan0 pdev_reset 1 + * + * Supported Feature: None + * + * Usage: Internal + * + * + */ +#define WE_SET_PDEV_RESET 95 + +/* + * setModDTIM - Change Modulated DTIM + * + * @INPUT: set_value. + * + * @OUTPUT: None + * + * This IOCTL is used to change modulated DTIM + * value without WIFI OFF/ON. + * + * @E.g: iwpriv wlan0 setModDTIM + * iwpriv wlan0 setModDTIM 2 + * + * Supported Feature: N/A + * + * Usage: Internal/External + * + * + */ +#define WE_SET_MODULATED_DTIM 96 + +#ifdef WLAN_FEATURE_MOTION_DETECTION +#define WE_MOTION_DET_START_STOP 97 +#define WE_MOTION_DET_BASE_LINE_START_STOP 98 +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +/* + * set_btc_mode Set BTCoexMode + * + * @INPUT: set_value. + * + * @OUTPUT: None + * + * This IOCTL is used to set the BT COex operating mode + * Allowed values are 0(TDD), 1(FDD), 2(Hybrid) + * + * @E.g: iwpriv wlan0 set_btc_mode + * iwpriv wlan0 set_btc_mode 2 + * + * Supported Feature: N/A + * + * Usage: Internal/External + * + * + */ +#define WE_SET_BTCOEX_MODE 99 + +/* + * set_btc_rssi- Set WLAN low RSSI threshold for BTCOex + * + * @INPUT: set_value. + * + * @OUTPUT: None + * + * This IOCTL is used to modify the threshold at which + * the COex mode changes from TDD to Hybrid mode + * Allowed values are from -100 to 0 + * + * @E.g: iwpriv wlan0 set_btc_rssi + * iwpriv wlan0 set_btc_rssi -70 + * + * Supported Feature: N/A + * + * Usage: Internal/External + * + * + */ +#define WE_SET_BTCOEX_RSSI_THRESHOLD 100 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_NONE_GET_INT (SIOCIWFIRSTPRIV + 1) +#define WE_GET_11D_STATE 1 +#define WE_GET_WLAN_DBG 4 +#define WE_GET_MAX_ASSOC 6 +/* 7 is unused */ +#define WE_GET_SAP_AUTO_CHANNEL_SELECTION 8 + +/* + * + * getconcurrency - Get concurrency mode + * + * @INPUT: None + * + * @OUTPUT: It shows concurrency value + * Bit 0:STA 1:SAP 2:P2P_Client 3:P2P_GO + * 4:FTM 5:IBSS 6:Monitor 7:P2P_Device + * 8:OCB 9:EPPING 10:QVIT 11:NDI + * + * This IOCTL is used to retrieve concurrency mode. + * + * @E.g: iwpriv wlan0 getconcurrency + * wlan0 getconcurrency:5 + * Above value shows STA+P2P_Client + * + * Supported Feature: Concurrency + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CONCURRENCY_MODE 9 +/* + * + * get_nss - Get the number of spatial STBC streams (NSS) + * + * @INPUT: None + * + * @OUTPUT: NSS + * wlan0 get_nss:2 + * + * This IOTCL used to get the number of spatial STBC streams + * + * @E.g: iwpriv wlan0 get_nss + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_NSS 11 +/* + * + * get_ldpc - This IOCTL gets the low density parity check (LDPC) + * + * @INPUT: None + * + * @OUTPUT: ldpc + * wlan0 get_ldpc:1 + * + * This IOTCL used to gets the low density parity check (LDPC) + * + * @E.g: iwpriv wlan0 get_ldpc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_LDPC 12 +/* + * + * get_tx_stbc - Get the value of the current Tx space time block code (STBC) + * + * @INPUT: None + * + * @OUTPUT: TXSTBC + * wlan0 get_tx_stbc:1 + * + * This IOTCL get the value of the current Tx space time block code (STBC) + * + * @E.g: iwpriv wlan0 get_tx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TX_STBC 13 +/* + * + * get_rx_stbc - Gets the value of the current Rx STBC + * + * @INPUT: None + * + * @OUTPUT: Rx STBC + * wlan0 get_rx_stbc:1 + * + * This IOTCL used to get the value of the current Rx STBC + * + * @E.g: iwpriv wlan0 get_rx_stbc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RX_STBC 14 +/* + * + * get_shortgi - Get the value of the current short GI setting + * + * @INPUT: None + * + * @OUTPUT: Enable/disable of shortgi + * wlan0 get_shortgi:1 + * + * This IOCTL gets the value of the current short GI setting + * + * @E.g: iwpriv wlan0 get_shortgi + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_SHORT_GI 15 +/* + * + * get_rtscts - Get the value of the current RTS/CTS setting. + * + * @INPUT: None + * + * @OUTPUT: Enable/disable of RTS/CTS + * wlan0 get_rtscts:33 + * + * This IOTCL get the value of the current RTS/CTS setting. + * + * @E.g: iwpriv wlan0 get_rtscts + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RTSCTS 16 +/* + * + * get_chwidth - Get the current channel width setting + * + * @INPUT: None + * + * @OUTPUT: channel width + * wlan0 get_chwidth:0 + * + * This IOTCL get the current channel width setting. + * + * @E.g: iwpriv wlan0 get_chwidth + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CHWIDTH 17 +/* + * + * get_anienable - Get the anienable + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_anienable:0 + * + * This IOTCL get the anienable + * + * @E.g: iwpriv wlan0 get_anienable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_EN_DIS 18 +/* + * + * get_aniplen - Get the aniplen + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_aniplen:0 + * + * This IOTCL get the aniplen + * + * @E.g: iwpriv wlan0 get_aniplen + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_POLL_PERIOD 19 +/* + * + * get_anilislen- Get the anilislen + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_anilislen:0 + * + * This IOTCL used to get anilislen + * + * @E.g: iwpriv wlan0 get_anilislen + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_LISTEN_PERIOD 20 +/* + * + * get_aniofdmlvl - Get the OFDM level + * + * @INPUT: None + * + * @OUTPUT: OFDM + * wlan0 get_aniofdmlvl:0 + * + * This IOTCL used to get ofdm level + * + * @E.g: iwpriv wlan0 get_aniofdmlvl + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_OFDM_LEVEL 21 +/* + * + * get_aniccklvl - Get the cck level + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 get_aniccklvl:0 + * + * This IOTCL used to get cck level + * + * @E.g: iwpriv wlan0 get_aniccklvl + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_ANI_CCK_LEVEL 22 +/* + * + * get_cwmenable - Get the value of the dynamic channel bandwidth setting + * + * @INPUT: None + * + * @OUTPUT: Enable/disable dynamic channel bandwidth + * wlan0 get_cwmenable:0 + * + * This IOTCL get the value of the dynamic channel bandwidth setting + * + * @E.g: iwpriv wlan0 get_cwmenable + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_DYNAMIC_BW 23 +/* + * + * get_txchainmask - Get the txchainmask that was set + * + * @INPUT: None + * + * @OUTPUT: txchainmask + * wlan0 get_txchainmask:1 + * + * This IOCTL gets the txchainmask that was set + * This command is useful if it was previously set + * + * @E.g: iwpriv wlan0 get_txchainmask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TX_CHAINMASK 24 +/* + * + * get_rxchainmask - Get the rxchainmask that was set + * + * @INPUT: None + * + * @OUTPUT: rxchainmask + * wlan0 get_rxchainmask:1 + * + * This IOCTL gets the rxchainmask that was set + * This command is useful only if it was previously set. + * + * @E.g: iwpriv wlan0 get_rxchainmask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RX_CHAINMASK 25 +/* + * + * get_11nrate - Get the fixed Tx data rate + * + * @INPUT: None + * + * @OUTPUT: Using this command does not return the same value as set + * wlan0 get_11nrate:0 + * + * This IOCTL gets the fixed Tx data rate + * This command is useful only if setting the fixed Tx rate. + * + * @E.g: iwpriv wlan0 get_11nrate + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_11N_RATE 26 +/* + * + * get_ampdu - Get the maximum subframe of ampdu + * + * @INPUT: None + * + * @OUTPUT: Maximum subframe of ampdu + * wlan0 get_ampdu:1 + * + * This IOCTL gets the maximum subframe of ampdu + * This command is useful only if setting ampdu. + * + * @E.g: iwpriv wlan0 get_ampdu + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_AMPDU 27 +/* + * + * get_amsdu - Get the maximum subframe of amsdu + * + * @INPUT: None + * + * @OUTPUT: Maximum subframe of amsdu + * wlan0 get_amsdu:1 + * + * This IOCTL gets the maximum subframe of amsdu. + * This command is useful only if setting amsdu + * + * @E.g: iwpriv wlan0 get_amsdu + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_AMSDU 28 +/* + * + * get_txpow2g - Get the current 2 GHz Tx power setting + * + * @INPUT: None + * + * @OUTPUT: Tx Power in dbm + * wlan0 get_txpow2g:0 + * + * This IOCTL gets the current 2 GHz Tx power setting + * This command is useful if setting Tx power + * + * @E.g: iwpriv wlan0 get_txpow2g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TXPOW_2G 29 +/* + * + * get_txpow5g - Get the current 5 GHz Tx power setting + * + * @INPUT: None + * + * @OUTPUT: Tx Power in dbm + * wlan0 get_txpow5g:0 + * + * This IOCTL gets the current 5 GHz Tx power setting + * This command is useful if setting Tx power + * + * @E.g: iwpriv wlan0 get_txpow5g + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TXPOW_5G 30 +/* 31 is unused */ +#define WE_GET_PPS_PAID_MATCH 32 +#define WE_GET_PPS_GID_MATCH 33 +#define WE_GET_PPS_EARLY_TIM_CLEAR 34 +#define WE_GET_PPS_EARLY_DTIM_CLEAR 35 +#define WE_GET_PPS_EOF_PAD_DELIM 36 +#define WE_GET_PPS_MACADDR_MISMATCH 37 +#define WE_GET_PPS_DELIM_CRC_FAIL 38 +#define WE_GET_PPS_GID_NSTS_ZERO 39 +#define WE_GET_PPS_RSSI_CHECK 40 +/* Private ioctl for QPower */ +#define WE_GET_QPOWER_MAX_PSPOLL_COUNT 41 +#define WE_GET_QPOWER_MAX_TX_BEFORE_WAKE 42 +#define WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL 43 +#define WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL 44 +/* GTX Commands */ +/* + * + * get_gtxHTMcs - Get the tx HTM + * + * @INPUT: None + * + * @OUTPUT: HTM + * wlan0 get_gtxHTMcs:32896 + * + * This IOTCL used to get HTM + * + * @E.g: iwpriv wlan0 get_gtxHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_HT_MCS 47 +/* + * + * get_gtxVHTMcs - Get the VHTM + * + * @INPUT: None + * + * @OUTPUT: VHTM + * wlan0 get_gtxVHTMcs:524800 + * + * This IOTCL used to get the VHTM + * + * @E.g: iwpriv wlan0 get_gtxVHTMcs + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_VHT_MCS 48 +/* + * + * get_gtxUsrCfg - Get the tx cfg + * + * @INPUT: None + * + * @OUTPUT: TXCFG + * wlan0 get_gtxUsrCfg:32 + * + * This IOTCL used to get the tx cfg + * + * @E.g: iwpriv wlan0 get_gtxUsrCfg + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_USRCFG 49 +/* + * + * get_gtxThre - Get the tx threshold + * + * @INPUT: None + * + * @OUTPUT: Threshold + * wlan0 get_gtxThre:3 + * + * This IOCTL is used to get tx threshold + * + * @E.g: iwpriv wlan0 get_gtxThre + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_THRE 50 +/* + * + * get_gtxMargin - Get the tx margin + * + * @INPUT: None + * + * @OUTPUT: GTXMARGIN + * wlan0 get_gtxMargin:2 + * + * This IOCTL is used to set tx margin + * + * @E.g: iwpriv wlan0 get_gtxMargin + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_MARGIN 51 +/* + * + * get_gtxStep - Get the tx step + * + * @INPUT: None + * + * @OUTPUT: GTXSTEP + * wlan0 get_gtxStep:0 + * + * This IOCTL is used to get the gtx step + * + * @E.g: iwpriv wlan0 get_gtxStep + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_STEP 52 +/* + * + * get_gtxMinTpc - Get the tx miminum tpc + * + * @INPUT: None + * + * @OUTPUT: TPC + * wlan0 get_gtxMinTpc:0 + * + * This IOCTL is used to get tx miminum tpc + * + * @E.g: iwpriv wlan0 get_gtxMinTpc + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_MINTPC 53 +/* + * + * get_gtxBWMask - Get the tx BW MASK + * + * @INPUT: None + * + * @OUTPUT: MASK + * wlan0 get_gtxBWMask:15 + * + * This IOCTL is used get gtx bw mask + * + * @E.g: iwpriv wlan0 get_gtxBWMask + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_GTX_BWMASK 54 +#define WE_GET_TEMPERATURE 56 +#define WE_CAP_TSF 58 +#define WE_GET_ROAM_SYNCH_DELAY 59 + +/* + * + * get_dcm - Get dcm enablement value + * + * @INPUT: None + * + * @OUTPUT: 0/1 + * wlan0 get_dcm + * + * This IOCTL is used get dcm value + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ +#define WE_GET_DCM 60 + +/* + * + * get_dcm - Get range extension enablement value + * + * @INPUT: None + * + * @OUTPUT: 0/1 + * wlan0 get_range_ext + * + * This IOCTL is used get range_extension value + * + * Supported Feature: STA/SAP + * + * Usage: Internal + * + * + */ +#define WE_GET_RANGE_EXT 61 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_INT_GET_INT (SIOCIWFIRSTPRIV + 2) + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_CHAR_GET_NONE (SIOCIWFIRSTPRIV + 3) +#define WE_WOWL_ADD_PTRN 1 +#define WE_WOWL_DEL_PTRN 2 +/* + * + * neighbor - Send neighbor report request + * + * @INPUT: string + * + * @OUTPUT: None + * + * This IOCTL create a Neighbor report request and send it to peer + * + * @E.g: iwpriv wlan0 neighbor "SSID" + * + * Supported Feature: 11k + * + * Usage: Internal/External + * + * + */ +#define WE_NEIGHBOR_REPORT_REQUEST 3 +/* + * + * set_ap_wps_ie - Set the P2P IE of the probe response + * + * @INPUT: string + * + * @OUTPUT: None + * + * This IOCTL sets the P2P IE of the probe response + * + * @E.g: iwpriv wlan0 set_ap_wps_ie abcd + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_SET_AP_WPS_IE 4 + +/* 5 is unused */ + +/* + * + * unit_test - execute component-level unit tests + * + * @INPUT: string - the name of the component to test. + * All tests are executed if unspecified + * @OUTPUT: None + * + * Usage: Internal only + * + */ +#define WE_UNIT_TEST 6 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_THREE_INT_GET_NONE (SIOCIWFIRSTPRIV + 4) +#define WE_SET_WLAN_DBG 1 +#define WE_SET_DP_TRACE 2 +#define WE_SET_FW_TEST 4 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_GET_CHAR_SET_NONE (SIOCIWFIRSTPRIV + 5) +#define WE_WLAN_VERSION 1 +#define WE_GET_STATS 2 +/* + * + * getConfig - gets the values of all configurations listed in WCNSS + * + * @INPUT: None + * + * @OUTPUT: Current configuration to the sys log + * wlan0 getConfig: WLAN configuration written to system log + * + * This IOCTL gets the values of all configurations listed in WCNSS + * + * @E.g: iwpriv wlan0 getConfig + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CFG 3 +#define WE_GET_WMM_STATUS 4 +/* + * + * getChannelList - Get the available channel list while in QCMobileAP + * + * @INPUT: None + * + * @OUTPUT: Channel list + * wlan0 getChannelList:36 US 1..165 + * + * This IOCTL gets the available channel list while in QCMobileAP + * + * @E.g: iwpriv wlan0 getChannelList + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_CHANNEL_LIST 5 +/* + * + * getRSSI - Get the Received Signal Strength Indicator + * + * @INPUT: None + * + * @OUTPUT: RSSI + * wlan0 getRSSI:rsssi=-32 + * + * This IOCTL gets the Received Signal Strength Indicator (RSSI) + * + * @E.g: iwpriv wlan0 getRSSI + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_RSSI 6 + +/* + * + * getSuspendStats - Get suspend/resume stats + * + * @INPUT: None + * + * @OUTPUT: character string containing formatted suspend/resume stats + * + * This ioctl is used to get suspend/resume stats formatted for display. + * Currently it includes suspend/resume counts, wow wake up reasons, and + * suspend fail reasons. + * + * @E.g: iwpriv wlan0 getSuspendStats + * iwpriv wlan0 getSuspendStats + * + * Supported Feature: suspend/resume + * + * Usage: Internal + * + * + */ +#define WE_GET_SUSPEND_RESUME_STATS 7 +#ifdef FEATURE_WLAN_TDLS +/* + * + * getTdlsPeers - Get all TDLS peers. + * + * @INPUT: None + * + * @OUTPUT: Returns the MAC address of all the TDLS peers + * wlan0 getTdlsPeers: + * MAC Id cap up RSSI + * --------------------------------- + * 00:0a:f5:0e:bd:18 2 Y Y -44 + * 00:0a:f5:bf:0e:12 0 N N 0 + * + * This IOCTL is used to get all TDLS peers. + * + * @E.g: iwpriv wlan0 getTdlsPeers + * + * Supported Feature: TDLS + * + * Usage: Internal/External + * + * + */ +#define WE_GET_TDLS_PEERS 8 +#endif +/* + * + * getPMFInfo - get the PMF info of the connected session + * + * @INPUT: None + * + * @OUTPUT: + * wlan0 getPMFInfo: + * BSSID E4:F4:C6:0A:E0:36, Is PMF Assoc? 0 + * Number of Unprotected Disassocs 0 + * Number of Unprotected Deauths 0 + * + * This IOCTL is used to get the PMF stats/status of the current + * connection. + * + * @e.g:iwpriv wlan0 getPMFInfo + * + * Supported Feature: PMF + * + * Usage: Internal/External + * + * + */ +#define WE_GET_11W_INFO 9 +#define WE_GET_STATES 10 +/* + * + * getphymode - Get the current phymode. + * + * @INPUT: None + * + * @OUTPUT: In phymode + * wlan0 getphymode:AUTO MODE + * + * This IOCTL used to gets the current phymode. + * + * @E.g: iwpriv wlan0 getphymode + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WE_GET_PHYMODE 12 + +/* + * + * getOemDataCap - Get the oem data caps. + * + * @INPUT: None + * + * @OUTPUT: oem data capability + * + * This IOCTL used to gets the current oem data cap. + * + * @E.g: iwpriv wlan0 getOemDataCap + * + * Usage: Internal/External + * + * + */ +#define WE_GET_OEM_DATA_CAP 13 + +/* + * + * getSNR - Enable SNR Monitoring + * + * @INPUT: None + * + * @OUTPUT: Signal strength/ratio + * wlan0 getSNR:1 + * + * This IOCTL is used to get ibss sta info + * + * @E.g: iwpriv wlan0 getSNR + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ + +#define WE_GET_SNR 14 +#define WE_LIST_FW_PROFILE 15 + +/* + * + * + * get_ba_timeout - to get timeout for each AC + * + * @INPUT: None + * + * @OUTPUT: displays timeout value for each access class + * + * @E.g.: iwpriv wlan0 get_ba_timeout + * + * Usage: Internal + * + * + */ +#define WE_GET_BA_AGEING_TIMEOUT 16 + +/* + * + * + * sta_cxn_info - STA connection information + * + * @INPUT: none + * + * @OUTPUT: STA's connection information + * + * This IOCTL is used to get connection's information. + * + * @E.g: iwpriv wlan0 get_cxn_info + * + * Usage: Internal + * + * + */ +#define WE_GET_STA_CXN_INFO 17 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_NONE_GET_NONE (SIOCIWFIRSTPRIV + 6) + +/* + * + * reassoc - Trigger STA re-association to the connected AP + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to trigger STA reassociation to the connected AP. + * + * @E.g: iwpriv wlan0 reassoc + * + * Supported Feature: Roaming + * + * Usage: Internal + * + * + */ +#define WE_SET_REASSOC_TRIGGER 8 + +/* Sub ioctls 11 to 16 are not used */ +#define WE_GET_FW_PROFILE_DATA 18 +/* + * + * stop_obss_scan - Stop obss scan + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to stop obss scan + * + * @E.g: iwpriv wlan0 stop_obss_scan + * + * Supported Feature: Scan + * + * Usage: Internal/External + * + * + */ +#define WE_STOP_OBSS_SCAN 19 + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_VAR_INT_GET_NONE (SIOCIWFIRSTPRIV + 7) + +#define WE_P2P_NOA_CMD 2 +/* subcommands 3 is unused */ + +#define WE_MAC_PWR_DEBUG_CMD 4 + +/* subcommand 5 is unused */ +/* subcommand 6 is unused */ + +#define WE_UNIT_TEST_CMD 7 + +#define WE_MTRACE_DUMP_CMD 8 +#define WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD 9 + + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +#define WE_LED_FLASHING_PARAM 10 +#endif + + +/* + * Sequence Numbers 11-14, 16, 17-20 are not in use. + */ + +/* + * + * pm_cinfo - Shows the concurrent connection list. + * + * @INPUT: None + * + * @OUTPUT: None + * + * This IOCTL is used to show the concurrent connection list. + * + * @E.g: iwpriv wlan0 pm_cinfo + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_POLICY_MANAGER_CINFO_CMD 15 + +/* + * + * ch_avoid - unit test SAP channel avoidance + * + * @INPUT: chan avoid ranges + * + * @OUTPUT: none + * + * This IOCTL is used to fake a channel avoidance event. + * To test SAP/GO chan switch during chan avoid event process. + * + * @E.g: iwpriv wlan0 ch_avoid 2452 2462 + * + * Supported Feature: SAP chan avoidance. + * + * Usage: Internal + * + * + */ +#define WE_SET_CHAN_AVOID 21 + +/* + * + * set_scan_cfg - Set dual MAC scan config parameters. + * + * @INPUT: dbs, dbs_plus_agile_scan, single_mac_scan_with_dbs + * @dbs: Value of DBS bit + * @dbs_plus_agile_scan: Value of DBS plus agile scan bit + * @single_mac_scan_with_dbs: Value of Single MAC scan with DBS + * + * @OUTPUT: None + * + * This IOCTL is used to set the dual MAC scan config. + * + * @E.g: iwpriv wlan0 set_scan_cfg dbs dbs_plus_agile_scan + * single_mac_scan_with_dbs + * iwpriv wlan0 set_scan_cfg 1 0 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DUAL_MAC_SCAN_CONFIG 21 + +/* + * + * set_fw_mode_cfg - Sets the dual mac FW mode config + * + * @INPUT: dbs, dfs + * @dbs: DBS bit + * @dfs: Agile DFS bit + * + * @OUTPUT: None + * + * This IOCTL is used to set the dual mac FW mode config. + * + * @E.g: iwpriv wlan0 set_fw_mode_cfg dbs dfs + * iwpriv wlan0 set_fw_mode_cfg 1 1 + * + * Supported Feature: DBS + * + * Usage: Internal/External + * + * + */ +#define WE_SET_DUAL_MAC_FW_MODE_CONFIG 22 +#define WE_SET_MON_MODE_CHAN 23 +/* + * + * txrx_stats - TXRX statistics query + * + * @INPUT: query category, mac id (default mac id is 0) + * + * @OUTPUT: TXRX statistics result + * + * This IOCTL is used to get TXRX statistics counters. + * + * @E.g: iwpriv wlan0 txrx_stats 21 0 + * iwpriv wlan0 txrx_stats 21 1 + * + * Usage: Internal + * + * + */ +#define WE_SET_TXRX_STATS 24 + + +#ifdef FEATURE_WLAN_TDLS +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 11 +#else +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 9 +#endif + +#ifdef WLAN_FEATURE_MOTION_DETECTION +#undef MAX_VAR_ARGS +#define MAX_VAR_ARGS 15 +#endif /* WLAN_FEATURE_MOTION_DETECTION */ +#define WE_MOTION_DET_CONFIG_PARAM 25 +#define WE_MOTION_DET_BASE_LINE_CONFIG_PARAM 26 + +#define WE_SET_THERMAL_THROTTLE_CFG 27 +/* + * + * fips_test - Perform a FIPS test + * + * @INPUT: Binary representation of the following packed structure + * + * @OUTPUT: Binary representation of the following packed structure + * + * This IOCTL is used to perform FIPS certification testing + * + * @E.g: iwpriv wlan0 fips_test + * + * iwpriv wlan0 fips_test + * + * Supported Feature: FIPS + * + * Usage: Internal + * + * + */ +#define WLAN_PRIV_FIPS_TEST (SIOCIWFIRSTPRIV + 8) + +/* Private ioctls (with no sub-ioctls) */ +/* note that they must be odd so that they have "get" semantics */ +/* + * + * addTspec - Add TSPEC for each AC + * + * @INPUT: 19 TSPEC params + * @[arg0]: handle + * @[arg1]: tid + * @[arg2]: dir + * @[arg3]: psb + * @[arg4]: up + * @[arg5]: nomMsduSize + * @[arg6]: maxMsduSize + * @[arg7]: minDataRate + * @[arg8]: meanDataRate + * @[arg9]: peakDataRate + * @[arg10]: maxBurstSize + * @[arg11]: minPhyRate + * @[arg12]: sba + * @[arg13]: minServiceIntv + * @[arg14]: suspendIntv + * @[arg15]: burstSizeDefn + * @[arg16]: ackPolicy + * @[arg17]: inactivityPeriod + * @[arg18]: maxServiceIntv + * + * @OUTPUT: Success/Failure + * + * This IOCTL is used to add TSPEC for each AC. + * + * @E.g: iwpriv wlan0 addTspec + * + * + * + * + * + * iwpriv wlan0 addTspec 7001 6 2 1 6 0x80D0 0x80D0 0x14500 0x14500 0x14500 + * 0 0x5B8D80 0x2001 20 2000 0 0 0 2000 + * wlan0 addTspec:3 + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define WLAN_PRIV_ADD_TSPEC (SIOCIWFIRSTPRIV + 9) +/* + * + * delTspec - Delete TSPEC entry for each AC + * + * @INPUT: 1 TSPEC param + * @[arg0]: handle + * + * @OUTPUT: Success/Failure + * + * This IOCTL is used to delete TSPEC entry for each AC. + * + * @E.g: iwpriv wlan0 delTspec + * iwpriv wlan0 delTspec 7001 + * wlan0 delTspec:16 + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define WLAN_PRIV_DEL_TSPEC (SIOCIWFIRSTPRIV + 11) +/* + * + * getTspec - Get TSPEC entry for each AC + * + * @INPUT: 1 TSPEC param + * @[arg0]: handle + * + * @OUTPUT: Success/Failure + * + * This IOCTL is used to get TSPEC entry for each AC. + * + * @E.g: iwpriv wlan0 getTspec + * iwpriv wlan0 getTspec 7001 + * wlan0 delTspec:18 + * + * Supported Feature: WMM + * + * Usage: Internal/External + * + * + */ +#define WLAN_PRIV_GET_TSPEC (SIOCIWFIRSTPRIV + 13) + +/* (SIOCIWFIRSTPRIV + 10) is currently unused */ +/* (SIOCIWFIRSTPRIV + 12) is currently unused */ +/* (SIOCIWFIRSTPRIV + 14) is currently unused */ +#define WLAN_PRIV_SET_NONE_GET_THREE_INT (SIOCIWFIRSTPRIV + 15) +#define WE_GET_TSF 1 +/* (SIOCIWFIRSTPRIV + 16) is currently unused */ + +#ifdef FEATURE_WLM_STATS +/* + * + * + * get_wlm_stats - Get stats from FW for game latency + * + * @INPUT: BITMASK inform of decimal number + * + * @OUTPUT: HEX string given by FW + * + * This IOCTL is used to get game latency related STATS from FW + * + * @E.g.: iwpriv wlan0 get_wlm_stats 1 + * + * Usage: internal + * + * + */ +#define WLAN_GET_WLM_STATS (SIOCIWFIRSTPRIV + 17) +#endif + +/* (SIOCIWFIRSTPRIV + 19) is currently unused */ + +#define WLAN_PRIV_SET_FTIES (SIOCIWFIRSTPRIV + 20) + +/* Private ioctl for setting the host offload feature */ +#define WLAN_PRIV_SET_HOST_OFFLOAD (SIOCIWFIRSTPRIV + 18) + +/* Private ioctl to get the statistics */ +#define WLAN_GET_WLAN_STATISTICS (SIOCIWFIRSTPRIV + 21) + +/* Private ioctl to set the Keep Alive Params */ +/* + * + * setKeepAlive - Set the keep alive feature + * + * @INPUT: 28 bytes of information in the order of packet type, time period + * host IPv4 address, destination IPv4 address, destination MAC address, bssID + * + * @OUTPUT: None + * + * This IOCTL sets the keep alive feature to send either NULL + * or unsolicited ARP response packets + * + * @E.g: iwpriv wlan0 setKeepAlive + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WLAN_SET_KEEPALIVE_PARAMS (SIOCIWFIRSTPRIV + 22) + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/* Private ioctl to set the packet filtering params */ +#define WLAN_SET_PACKET_FILTER_PARAMS (SIOCIWFIRSTPRIV + 23) +#endif + + +#ifdef FEATURE_WLAN_SCAN_PNO +/* Private ioctl to get the statistics */ +#define WLAN_SET_PNO (SIOCIWFIRSTPRIV + 24) +#endif +/* + * + * SETBAND - Set the operational band + * + * @INPUT: 0 to Auto, 1 to 5 GHz and 2 to 2.4 GHz + * + * @OUTPUT: None + * + * This IOCTL Set the operational band If the new band is different from the + * current operational band, it aborts the pending scan requests, flushes + * the existing scan results, and then change * the band capability + * + * @E.g: iwpriv wlan0 SETBAND + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WLAN_SET_BAND_CONFIG (SIOCIWFIRSTPRIV + 25) + +#define WLAN_PRIV_SET_MCBC_FILTER (SIOCIWFIRSTPRIV + 26) +/* (SIOCIWFIRSTPRIV + 27) is currently unused */ + +/* Private ioctls and their sub-ioctls */ +#define WLAN_PRIV_SET_TWO_INT_GET_NONE (SIOCIWFIRSTPRIV + 28) +#define WE_SET_SMPS_PARAM 1 +#define WE_SET_FW_CRASH_INJECT 2 +#define WE_DUMP_DP_TRACE_LEVEL 3 +/* Private sub ioctl for enabling and setting histogram interval of profiling */ +#define WE_ENABLE_FW_PROFILE 4 +#define WE_SET_FW_PROFILE_HIST_INTVL 5 + +/* Private sub-ioctl for initiating WoW suspend without Apps suspend */ +#define WE_SET_WLAN_SUSPEND 6 +#define WE_SET_WLAN_RESUME 7 + +/* + * + * log_buffer - prints host/target related communication logs via dmesg + * + * @INPUT: Log Id, Count + * + * Log Id: + * 0) HTC_CREDIT_HISTORY_LOG + * 1) COMMAND_LOG, + * 2) COMMAND_TX_CMP_LOG, + * 3) MGMT_COMMAND_LOG, + * 4) MGMT_COMMAND_TX_CMP_LOG, + * 5) EVENT_LOG, + * 6) RX_EVENT_LOG, + * 7) MGMT_EVENT_LOG + * + * @OUTPUT: None + * + * @E.g: + * # print up to 10 of the most recent records from HTC Credit History + * iwpriv wlan0 log_buffer 0 10 + * # print up to 3 of the most recent records from Event Log + * iwpriv wlan0 log_buffer 5 3 + * + * Supported Feature: WLAN Trace + * + * Usage: Internal/External + * + * + */ +#define WE_LOG_BUFFER 8 + +/* + * + * set_ba_timeout - sets Block ACK aging timeout value for each Access class + * + * @INPUT: Access Class [0:BK, 1:BE, 2:VI, 3:VO], Timeout value + * + * @OUTPUT: None + * + * @E.g.: + * # to set duration of 2 seconds for BE + * iwpriv wlan0 set_ba_timeout 1 2 + * # to set duration of 3 seconds for VO + * iwpriv wlan0 set_ba_timeout 3 3 + * + * Usage: Internal + * + * + */ +#define WE_SET_BA_AGEING_TIMEOUT 9 + +/* (SIOCIWFIRSTPRIV + 29) is currently unused */ + +/* 802.11p IOCTL */ +#define WLAN_SET_DOT11P_CHANNEL_SCHED (SIOCIWFIRSTPRIV + 30) + +/* + * + * getLinkSpeed - Gets the current link speed in Mbps + * + * @INPUT: None + * + * @OUTPUT: linkspeed in mbps + * wlan0 getLinkSpeed:7 + * + * This IOCTL is used get the current link speed in Mbps + * + * @E.g: iwpriv wlan0 getLinkSpeed + * + * Supported Feature: STA + * + * Usage: Internal/External + * + * + */ +#define WLAN_GET_LINK_SPEED (SIOCIWFIRSTPRIV + 31) + +#define WLAN_STATS_INVALID 0 +#define WLAN_STATS_RETRY_CNT 1 +#define WLAN_STATS_MUL_RETRY_CNT 2 +#define WLAN_STATS_TX_FRM_CNT 3 +#define WLAN_STATS_RX_FRM_CNT 4 +#define WLAN_STATS_FRM_DUP_CNT 5 +#define WLAN_STATS_FAIL_CNT 6 +#define WLAN_STATS_RTS_FAIL_CNT 7 +#define WLAN_STATS_ACK_FAIL_CNT 8 +#define WLAN_STATS_RTS_SUC_CNT 9 +#define WLAN_STATS_RX_DISCARD_CNT 10 +#define WLAN_STATS_RX_ERROR_CNT 11 +#define WLAN_STATS_TX_BYTE_CNT 12 + +#define WLAN_STATS_RX_BYTE_CNT 13 +#define WLAN_STATS_RX_RATE 14 +#define WLAN_STATS_TX_RATE 15 + +#define WLAN_STATS_RX_UC_BYTE_CNT 16 +#define WLAN_STATS_RX_MC_BYTE_CNT 17 +#define WLAN_STATS_RX_BC_BYTE_CNT 18 +#define WLAN_STATS_TX_UC_BYTE_CNT 19 +#define WLAN_STATS_TX_MC_BYTE_CNT 20 +#define WLAN_STATS_TX_BC_BYTE_CNT 21 + +#define FILL_TLV(__p, __type, __size, __val, __tlen) do { \ + if ((__tlen + __size + 2) < WE_MAX_STR_LEN) { \ + *__p++ = __type; \ + *__p++ = __size; \ + memcpy(__p, __val, __size); \ + __p += __size; \ + __tlen += __size + 2; \ + } else { \ + hdd_err("FILL_TLV Failed!!!"); \ + } \ + } while (0) + +#define TX_PER_TRACKING_DEFAULT_RATIO 5 +#define TX_PER_TRACKING_MAX_RATIO 10 +#define TX_PER_TRACKING_DEFAULT_WATERMARK 5 + +#define WLAN_ADAPTER 0 +#define P2P_ADAPTER 1 + +/** + * mem_alloc_copy_from_user_helper - copy from user helper + * @wrqu_data: wireless extensions request data + * @len: length of @wrqu_data + * + * Helper function to allocate buffer and copy user data. + * + * Return: On success return a pointer to a kernel buffer containing a + * copy of the userspace data (with an additional NUL character + * appended for safety). On failure return %NULL. + */ +void *mem_alloc_copy_from_user_helper(const __user void *wrqu_data, size_t len) +{ + u8 *ptr = NULL; + + /* in order to protect the code, an extra byte is post + * appended to the buffer and the null termination is added. + * However, when allocating (len+1) byte of memory, we need to + * make sure that there is no uint overflow when doing + * addition. In theory check len < UINT_MAX protects the uint + * overflow. For wlan private ioctl, the buffer size is much + * less than UINT_MAX, as a good guess, now, it is assumed + * that the private command buffer size is no greater than 4K + * (4096 bytes). So we use 4096 as the upper boundary for now. + */ + if (len > MAX_USER_COMMAND_SIZE) { + hdd_err("Invalid length: %zu max: %u", + len, MAX_USER_COMMAND_SIZE); + return NULL; + } + + ptr = qdf_mem_malloc(len + 1); + if (!ptr) + return NULL; + + if (copy_from_user(ptr, wrqu_data, len)) { + hdd_err("failed to copy data to user buffer"); + qdf_mem_free(ptr); + return NULL; + } + ptr[len] = '\0'; + return ptr; +} + +/** + * hdd_priv_get_data() - Get pointer to ioctl private data + * @p_priv_data: pointer to iw_point struct to be filled + * @wrqu: Pointer to IOCTL Data received from userspace + * + * Helper function to get compatible struct iw_point passed to ioctl + * + * Return - 0 if p_priv_data successfully filled, error otherwise + */ +int hdd_priv_get_data(struct iw_point *p_priv_data, union iwreq_data *wrqu) +{ + if ((!p_priv_data) || (!wrqu)) + return -EINVAL; + +#ifdef CONFIG_COMPAT + if (in_compat_syscall()) { + struct compat_iw_point *p_compat_priv_data; + + /* Compat task: + * typecast to compat structure and copy the members. + */ + p_compat_priv_data = (struct compat_iw_point *)&wrqu->data; + + p_priv_data->pointer = compat_ptr(p_compat_priv_data->pointer); + p_priv_data->length = p_compat_priv_data->length; + p_priv_data->flags = p_compat_priv_data->flags; + } else { +#endif /* #ifdef CONFIG_COMPAT */ + + /* Non compat task: directly copy the structure. */ + memcpy(p_priv_data, &wrqu->data, sizeof(struct iw_point)); + +#ifdef CONFIG_COMPAT + } +#endif /* #ifdef CONFIG_COMPAT */ + + return 0; +} + +static int hdd_check_wext_control(enum hdd_wext_control wext_control, + struct iw_request_info *info) +{ + switch (wext_control) { + default: + case hdd_wext_disabled: + hdd_err_rl("Rejecting disabled ioctl %x", info->cmd); + return -ENOTSUPP; + case hdd_wext_deprecated: + hdd_nofl_debug("Using deprecated ioctl %x", info->cmd); + return 0; + case hdd_wext_enabled: + return 0; + } +} + +int hdd_check_private_wext_control(struct hdd_context *hdd_ctx, + struct iw_request_info *info) +{ + return hdd_check_wext_control(hdd_ctx->config->private_wext_control, + info); +} + +void hdd_wlan_get_stats(struct wlan_hdd_link_info *link_info, uint16_t *length, + char *buffer, uint16_t buf_len) +{ + struct hdd_tx_rx_stats *stats = &link_info->hdd_stats.tx_rx_stats; + struct dp_tx_rx_stats *dp_stats; + uint32_t len = 0; + uint32_t total_rx_pkt = 0, total_rx_dropped = 0; + uint32_t total_rx_delv = 0, total_rx_refused = 0; + uint32_t total_tx_pkt = 0; + uint32_t total_tx_dropped = 0; + uint32_t total_tx_orphaned = 0; + uint32_t total_tx_classified_ac[WLAN_MAX_AC] = {0}; + uint32_t total_tx_dropped_ac[WLAN_MAX_AC] = {0}; + int i = 0; + uint8_t ac, rx_ol_con = 0, rx_ol_low_tput = 0; + struct hdd_context *hdd_ctx = link_info->adapter->hdd_ctx; + struct wlan_objmgr_vdev *vdev; + + vdev = hdd_objmgr_get_vdev_by_user(link_info, WLAN_DP_ID); + if (!vdev) + return; + + dp_stats = qdf_mem_malloc(sizeof(*dp_stats)); + if (!dp_stats) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + return; + } + + if (ucfg_dp_get_txrx_stats(vdev, dp_stats)) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + hdd_err("Unable to get stats from DP component"); + qdf_mem_free(dp_stats); + return; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_DP_ID); + + ucfg_dp_get_disable_rx_ol_val(hdd_ctx->psoc, + &rx_ol_con, &rx_ol_low_tput); + + for (; i < NUM_CPUS; i++) { + total_rx_pkt += dp_stats->per_cpu[i].rx_packets; + total_rx_dropped += dp_stats->per_cpu[i].rx_dropped; + total_rx_delv += dp_stats->per_cpu[i].rx_delivered; + total_rx_refused += dp_stats->per_cpu[i].rx_refused; + total_tx_pkt += dp_stats->per_cpu[i].tx_called; + total_tx_dropped += dp_stats->per_cpu[i].tx_dropped; + total_tx_orphaned += dp_stats->per_cpu[i].tx_orphaned; + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + total_tx_classified_ac[ac] += + stats->per_cpu[i].tx_classified_ac[ac]; + total_tx_dropped_ac[ac] += + stats->per_cpu[i].tx_dropped_ac[ac]; + } + } + + len = scnprintf(buffer, buf_len, + "\nTransmit[%lu] - " + "called %u, dropped %u orphan %u," + "\n[dropped] BK %u, BE %u, VI %u, VO %u" + "\n[classified] BK %u, BE %u, VI %u, VO %u" + "\n\nReceive[%lu] - " + "packets %u, dropped %u, unsolict_arp_n_mcast_drp %u, delivered %u, refused %u\n" + "GRO - agg %u non-agg %u flush_skip %u low_tput_flush %u disabled(conc %u low-tput %u)\n", + qdf_system_ticks(), + total_tx_pkt, + total_tx_dropped, + total_tx_orphaned, + total_tx_dropped_ac[SME_AC_BK], + total_tx_dropped_ac[SME_AC_BE], + total_tx_dropped_ac[SME_AC_VI], + total_tx_dropped_ac[SME_AC_VO], + total_tx_classified_ac[SME_AC_BK], + total_tx_classified_ac[SME_AC_BE], + total_tx_classified_ac[SME_AC_VI], + total_tx_classified_ac[SME_AC_VO], + qdf_system_ticks(), + total_rx_pkt, total_rx_dropped, + qdf_atomic_read(&dp_stats->rx_usolict_arp_n_mcast_drp), + total_rx_delv, + total_rx_refused, + dp_stats->rx_aggregated, dp_stats->rx_non_aggregated, + dp_stats->rx_gro_flush_skip, + dp_stats->rx_gro_low_tput_flush, + rx_ol_con, + rx_ol_low_tput); + + for (i = 0; i < NUM_CPUS; i++) { + if (dp_stats->per_cpu[i].rx_packets == 0) + continue; + len += scnprintf(buffer + len, buf_len - len, + "Rx CPU[%d]:" + "packets %u, dropped %u, delivered %u, refused %u\n", + i, dp_stats->per_cpu[i].rx_packets, + dp_stats->per_cpu[i].rx_dropped, + dp_stats->per_cpu[i].rx_delivered, + dp_stats->per_cpu[i].rx_refused); + } + + len += scnprintf(buffer + len, buf_len - len, + "\nTX_FLOW" + "\nCurrent status: %s" + "\ntx-flow timer start count %u" + "\npause count %u, unpause count %u", + (stats->is_txflow_paused == true ? "PAUSED" : "UNPAUSED"), + stats->txflow_timer_cnt, + stats->txflow_pause_cnt, + stats->txflow_unpause_cnt); + + len += cdp_stats(cds_get_context(QDF_MODULE_ID_SOC), + link_info->vdev_id, &buffer[len], + (buf_len - len)); + *length = len + 1; + qdf_mem_free(dp_stats); +} + +/** + * wlan_hdd_write_suspend_resume_stats() - Writes suspend/resume stats to buffer + * @hdd_ctx: The Hdd context owning the stats to be written + * @buffer: The char buffer to write to + * @max_len: The maximum number of chars to write + * + * This assumes hdd_ctx has already been validated, and buffer is not NULL. + * + * Return - length of written content, negative number on error + */ +static int wlan_hdd_write_suspend_resume_stats(struct hdd_context *hdd_ctx, + char *buffer, uint16_t max_len) +{ + int ret; + QDF_STATUS status; + struct suspend_resume_stats *sr_stats; + + sr_stats = &hdd_ctx->suspend_resume_stats; + ret = scnprintf(buffer, max_len, + "\n" + "Suspends: %u\n" + "Resumes: %u\n" + "\n" + "Suspend Fail Reasons\n" + "\tIPA: %u\n" + "\tRadar: %u\n" + "\tRoam: %u\n" + "\tScan: %u\n" + "\tInitial Wakeup: %u\n" + "\n", + sr_stats->suspends, sr_stats->resumes, + sr_stats->suspend_fail[SUSPEND_FAIL_IPA], + sr_stats->suspend_fail[SUSPEND_FAIL_RADAR], + sr_stats->suspend_fail[SUSPEND_FAIL_ROAM], + sr_stats->suspend_fail[SUSPEND_FAIL_SCAN], + sr_stats->suspend_fail[SUSPEND_FAIL_INITIAL_WAKEUP]); + + status = ucfg_mc_cp_stats_write_wow_stats(hdd_ctx->psoc, + &buffer[ret], max_len - ret, + &ret); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get WoW stats"); + return qdf_status_to_os_return(status); + } + + return ret; +} + +/** + * hdd_wlan_list_fw_profile() - Get fw profiling points + * @length: Size of the data copied + * @buffer: Pointer to char buffer. + * @buf_len: Length of the char buffer. + * + * This function called when the "iwpriv wlan0 listProfile" command is given. + * It is used to get the supported profiling points in FW. + * + * Return - none + */ +void hdd_wlan_list_fw_profile(uint16_t *length, + char *buffer, uint16_t buf_len) +{ + uint32_t len = 0; + + len = scnprintf(buffer, buf_len, + "PROF_CPU_IDLE: %u\n" + "PROF_PPDU_PROC: %u\n" + "PROF_PPDU_POST: %u\n" + "PROF_HTT_TX_INPUT: %u\n" + "PROF_MSDU_ENQ: %u\n" + "PROF_PPDU_POST_HAL: %u\n" + "PROF_COMPUTE_TX_TIME: %u\n", + PROF_CPU_IDLE, + PROF_PPDU_PROC, + PROF_PPDU_POST, + PROF_HTT_TX_INPUT, + PROF_MSDU_ENQ, + PROF_PPDU_POST_HAL, + PROF_COMPUTE_TX_TIME); + + *length = len + 1; +} + +static int hdd_we_dump_stats(struct wlan_hdd_link_info *link_info, int value) +{ + return hdd_wlan_dump_stats(link_info->adapter, value); +} + +/** + * __iw_get_linkspeed() - Get current link speed ioctl + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: extra ioctl buffer + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + char *out_link_speed = (char *)extra; + int len = sizeof(uint32_t) + 1; + uint32_t link_speed = 0; + struct hdd_context *hdd_ctx; + int ret, rc; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + ret = wlan_hdd_get_link_speed(adapter->deflink, &link_speed); + if (0 != ret) + return ret; + + wrqu->data.length = len; + /* return the linkspeed as a string */ + rc = snprintf(out_link_speed, len, "%u", link_speed); + if ((rc < 0) || (rc >= len)) { + /* encoding or length error? */ + hdd_err("Unable to encode link speed"); + return -EIO; + } + + hdd_exit(); + /* a value is being successfully returned */ + return 0; +} + +/** + * iw_get_linkspeed() - Get current link speed ioctl + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: extra ioctl buffer + * + * Return: 0 on success, non-zero on error + */ +static int iw_get_linkspeed(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_linkspeed(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef FEATURE_WLM_STATS +static void wlan_get_wlm_stats_cb(void *cookie, const char *data) +{ + struct osif_request *request; + char *priv; + + request = osif_request_get(cookie); + if (!request) { + hdd_err("Obsolete request"); + return; + } + priv = osif_request_priv(request); + strlcpy(priv, data, WE_MAX_STR_LEN); + osif_request_complete(request); + osif_request_put(request); +} + +static int wlan_get_wlm_stats(struct hdd_adapter *adapter, uint32_t bitmask, + char *response) +{ + struct osif_request *request; + void *cookie; + int errno; + char *priv; + static const struct osif_request_params params = { + .priv_size = WE_MAX_STR_LEN, + .timeout_ms = 2000, + }; + + if (!adapter) { + hdd_err("NULL argument"); + return -EINVAL; + } + request = osif_request_alloc(¶ms); + if (!request) { + hdd_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + errno = wma_wlm_stats_req(adapter->deflink->vdev_id, bitmask, + params.priv_size, + wlan_get_wlm_stats_cb, cookie); + if (errno) { + hdd_err("Request failed be sent, %d", errno); + goto cleanup; + } + errno = osif_request_wait_for_response(request); + if (errno) { + hdd_err("Timeout happened, can't complete the req"); + goto cleanup; + } + priv = osif_request_priv(request); + strlcpy(response, priv, params.priv_size); + +cleanup: + osif_request_put(request); + + return errno; +} + +/* + * Due to a limitation in iwpriv the "get_wlm_stats" ioctl is defined + * to take as input a variable-length string as opposed to taking a + * single integer "bitmask" value. Hence we must have a buffer large + * enough to hold a string representing the largest possible + * value. MAX_INT = 2,147,483,647 which can be fit in 10 chars. + * Round up to 12 to hold the trailing NUL and be a multiple of 4. + */ +#define WLM_USER_DATA_SIZE 12 + +static int __iw_get_wlm_stats(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct iw_point priv_data; + char user_data[WLM_USER_DATA_SIZE] = {0}; + uint32_t bitmask = 0; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + /* + * Since this is GETTER iwpriv ioctl, driver needs to + * copy SET data from user space to kernel space. + * Helper function to get iwreq_data with compat handling. + */ + if (hdd_priv_get_data(&priv_data, wrqu)) + return -EINVAL; + + /* + * priv_data.pointer should be pointing to data given + * to iwpriv command. + * + * For example "iwpriv wlan0 get_wlm_stats 1234" + * + * priv_data.pointer should be pointing to "1234" + * priv_data.length should be zero as this GETTER iwpriv ioctl + */ + if (!priv_data.pointer) { + hdd_err("NULL data pointer"); + return -EINVAL; + } + + /* + * ideally driver should have used priv_data.length to copy + * data from priv_data.pointer but this iwpriv IOCTL has been + * declared as GETTER in nature which makes length field zero + * for input arguments but priv_data.pointer still points to + * user's input argument (just doesn't pass the length of the + * argument) + */ + if (copy_from_user(user_data, priv_data.pointer, + sizeof(user_data) - 1)) { + hdd_err("failed to copy data from user buffer"); + return -EFAULT; + } + + /* + * user data is given in ascii, convert ascii to integer + */ + if (kstrtou32(user_data, 0, &bitmask)) { + hdd_err("failed to parse input %s", user_data); + return -EFAULT; + } + + if (wlan_get_wlm_stats(adapter, bitmask, extra)) { + hdd_err("returning failure"); + return -EFAULT; + } + wrqu->data.length = strlen(extra) + 1; + + return 0; +} + +static int iw_get_wlm_stats(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_wlm_stats(net_dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif /* FEATURE_WLM_STATS */ + +static int hdd_we_ieee_to_phymode(int ieee_mode, eCsrPhyMode *csr_phy_mode) +{ + switch (ieee_mode) { + case IEEE80211_MODE_AUTO: + case IEEE80211_MODE_2G_AUTO: + case IEEE80211_MODE_5G_AUTO: + *csr_phy_mode = eCSR_DOT11_MODE_AUTO; + break; + case IEEE80211_MODE_11A: + *csr_phy_mode = eCSR_DOT11_MODE_11a; + break; + case IEEE80211_MODE_11B: + *csr_phy_mode = eCSR_DOT11_MODE_11b; + break; + case IEEE80211_MODE_11G: + *csr_phy_mode = eCSR_DOT11_MODE_11g; + break; + case IEEE80211_MODE_11NA_HT20: + case IEEE80211_MODE_11NA_HT40: + case IEEE80211_MODE_11NG_HT20: + case IEEE80211_MODE_11NG_HT40: + case IEEE80211_MODE_11AGN: + *csr_phy_mode = eCSR_DOT11_MODE_11n; + break; + case IEEE80211_MODE_11AC_VHT20: + case IEEE80211_MODE_11AC_VHT40: + case IEEE80211_MODE_11AC_VHT80: + *csr_phy_mode = eCSR_DOT11_MODE_11ac; + break; + default: + hdd_err("Not supported mode %d", ieee_mode); + return -EINVAL; + } + + return 0; +} + +static int hdd_we_ieee_to_band(int ieee_mode, uint8_t *supported_band) +{ + switch (ieee_mode) { + case IEEE80211_MODE_AUTO: + case IEEE80211_MODE_11AC_VHT20: + case IEEE80211_MODE_11AC_VHT40: + case IEEE80211_MODE_11AC_VHT80: + case IEEE80211_MODE_11AGN: + *supported_band = BIT(REG_BAND_2G) | BIT(REG_BAND_5G); + break; + case IEEE80211_MODE_11A: + case IEEE80211_MODE_11NA_HT20: + case IEEE80211_MODE_11NA_HT40: + case IEEE80211_MODE_5G_AUTO: + *supported_band = BIT(REG_BAND_5G); + break; + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + case IEEE80211_MODE_11NG_HT20: + case IEEE80211_MODE_11NG_HT40: + case IEEE80211_MODE_2G_AUTO: + *supported_band = BIT(REG_BAND_2G); + break; + default: + hdd_err("Not supported mode %d", ieee_mode); + return -EINVAL; + } + + return 0; +} + +static int hdd_we_ieee_to_bonding_mode(int ieee_mode, uint32_t *bonding_mode) +{ + switch (ieee_mode) { + case IEEE80211_MODE_AUTO: + case IEEE80211_MODE_11NA_HT40: + case IEEE80211_MODE_11NG_HT40: + case IEEE80211_MODE_11AC_VHT40: + case IEEE80211_MODE_11AC_VHT80: + case IEEE80211_MODE_2G_AUTO: + case IEEE80211_MODE_5G_AUTO: + case IEEE80211_MODE_11AGN: + *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + break; + case IEEE80211_MODE_11A: + case IEEE80211_MODE_11B: + case IEEE80211_MODE_11G: + case IEEE80211_MODE_11NA_HT20: + case IEEE80211_MODE_11NG_HT20: + case IEEE80211_MODE_11AC_VHT20: + *bonding_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + break; + default: + hdd_err("Not supported mode %d", ieee_mode); + return -EINVAL; + } + + return 0; +} + +int hdd_we_update_phymode(struct wlan_hdd_link_info *link_info, + int new_phymode) +{ + eCsrPhyMode phymode; + uint8_t supported_band; + uint32_t bonding_mode; + int ret; + + ret = hdd_we_ieee_to_phymode(new_phymode, &phymode); + if (ret < 0) + return -EINVAL; + + ret = hdd_we_ieee_to_band(new_phymode, &supported_band); + if (ret < 0) + return ret; + + ret = hdd_we_ieee_to_bonding_mode(new_phymode, &bonding_mode); + if (ret < 0) + return ret; + + return hdd_update_phymode(link_info->adapter, phymode, supported_band, + bonding_mode); +} + +static int hdd_validate_pdev_reset(int value) +{ + if ((value < 1) || (value > 5)) { + hdd_warn(" Invalid value %d: Use any one of the below values\n" + " TX_FLUSH = 1\n" + " WARM_RESET = 2\n" + " COLD_RESET = 3\n" + " WARM_RESET_RESTORE_CAL = 4\n" + " COLD_RESET_RESTORE_CAL = 5", value); + + return -EINVAL; + } + + return 0; +} + +static int hdd_handle_pdev_reset(struct wlan_hdd_link_info *link_info, + int value) +{ + int ret; + + hdd_debug("%d", value); + + ret = hdd_validate_pdev_reset(value); + if (ret) + return ret; + + ret = wma_cli_set_command(link_info->vdev_id, + wmi_pdev_param_pdev_reset, + value, PDEV_CMD); + + return ret; +} + +static int hdd_we_set_11d_state(struct wlan_hdd_link_info *link_info, + int state_11d) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + bool enable_11d; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + QDF_STATUS status; + + if (!mac_handle) + return -EINVAL; + + switch (state_11d) { + case ENABLE_11D: + enable_11d = true; + break; + case DISABLE_11D: + enable_11d = false; + break; + default: + return -EINVAL; + } + + status = ucfg_mlme_set_11d_enabled(hdd_ctx->psoc, enable_11d); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Invalid 11d_enable flag"); + + hdd_debug("11D state=%d", enable_11d); + + return 0; +} + +static int hdd_we_set_power(struct wlan_hdd_link_info *link_info, int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + if (!mac_handle) + return -EINVAL; + + switch (value) { + case 1: + /* Enable PowerSave */ + sme_ps_set_powersave(hdd_ctx->mac_handle, + link_info->vdev_id, + true, 0, true); + return 0; + case 2: + /* Disable PowerSave */ + sme_ps_set_powersave(hdd_ctx->mac_handle, + link_info->vdev_id, + false, 0, true); + return 0; + case 3: + /* Enable UASPD */ + sme_ps_uapsd_enable(mac_handle, link_info->vdev_id); + return 0; + case 4: + /* Disable UASPD */ + sme_ps_uapsd_disable(mac_handle, link_info->vdev_id); + return 0; + default: + hdd_err("Invalid value %d", value); + return -EINVAL; + } +} + +static int hdd_we_set_max_assoc(struct wlan_hdd_link_info *link_info, int value) +{ + struct hdd_context *hdd_ctx; + QDF_STATUS status; + + hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + status = ucfg_mlme_set_assoc_sta_limit(hdd_ctx->psoc, value); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", value, status); + + return qdf_status_to_os_return(status); +} + +static inline int +hdd_we_set_data_inactivity_timeout(struct wlan_hdd_link_info *link_info, + int inactivity_timeout) +{ + /* data inactivity timeout is no longer supported and is not used */ + return -ENOTSUPP; +} + +static int +hdd_we_set_wow_data_inactivity_timeout(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + if (!mac_handle) + return -EINVAL; + + if (!cfg_in_range(CFG_PMO_WOW_DATA_INACTIVITY_TIMEOUT, value)) { + hdd_err_rl("Invalid value %d", value); + return -EINVAL; + } + + ucfg_pmo_set_wow_data_inactivity_timeout(hdd_ctx->psoc, (uint8_t)value); + + return 0; +} + +static int hdd_we_set_tx_power(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_station_ctx *sta_ctx; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + QDF_STATUS status; + + if (!mac_handle) + return -EINVAL; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + status = sme_set_tx_power(mac_handle, link_info->vdev_id, + sta_ctx->conn_info.bssid, + adapter->device_mode, value); + + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", value, status); + + return qdf_status_to_os_return(status); +} + +static int hdd_we_set_max_tx_power(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + struct hdd_station_ctx *sta_ctx; + mac_handle_t mac_handle = hdd_ctx->mac_handle; + QDF_STATUS status; + + if (!mac_handle) + return -EINVAL; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(link_info); + status = sme_set_max_tx_power(mac_handle, + sta_ctx->conn_info.bssid, + sta_ctx->conn_info.bssid, + value); + + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", value, status); + + return qdf_status_to_os_return(status); +} + +static int hdd_we_set_max_tx_power_2_4(struct wlan_hdd_link_info *link_info, + int power) +{ + QDF_STATUS status; + + hdd_debug("power %d dBm", power); + status = sme_set_max_tx_power_per_band(BAND_2G, power); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", power, status); + + return qdf_status_to_os_return(status); +} + +static int hdd_we_set_max_tx_power_5_0(struct wlan_hdd_link_info *link_info, + int power) +{ + QDF_STATUS status; + + hdd_debug("power %d dBm", power); + status = sme_set_max_tx_power_per_band(BAND_5G, power); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", power, status); + + return qdf_status_to_os_return(status); +} + +#ifdef HASTINGS_BT_WAR + +static bool hdd_hastings_bt_war_applicable(struct hdd_context *hdd_ctx) +{ + struct pld_soc_info info; + int errno; + + errno = pld_get_soc_info(hdd_ctx->parent_dev, &info); + if (errno) + return false; + + /* check for HST 1.1 values */ + + if (info.device_version.family_number != 0x04) + return false; + + if (info.device_version.device_number != 0x0A) + return false; + + if (info.device_version.major_version != 0x01) + return false; + + return true; +} + +/* + * replicate logic: + * iwpriv wlan0 setUnitTestCmd 19 2 23 1 => enable WAR + * iwpriv wlan0 setUnitTestCmd 19 2 23 0 => disable WAR + */ + +#define HASTINGS_WAR_FW_PARAM_ID 23 + +static int hdd_hastings_bt_war_set_fw(struct hdd_context *hdd_ctx, + uint32_t value) +{ + uint32_t vdev_id = 0; /* not used */ + uint32_t module_id = WLAN_MODULE_WAL; + uint32_t arg_count = 2; + uint32_t arg[2] = {HASTINGS_WAR_FW_PARAM_ID, value}; + QDF_STATUS status; + + if (!hdd_hastings_bt_war_applicable(hdd_ctx)) + return 0; + + status = wma_form_unit_test_cmd_and_send(vdev_id, module_id, + arg_count, arg); + + return qdf_status_to_os_return(status); +} + +int hdd_hastings_bt_war_enable_fw(struct hdd_context *hdd_ctx) +{ + return hdd_hastings_bt_war_set_fw(hdd_ctx, 1); +} + +int hdd_hastings_bt_war_disable_fw(struct hdd_context *hdd_ctx) +{ + return hdd_hastings_bt_war_set_fw(hdd_ctx, 0); +} + +/* value to restore the config when the WAR is disabled */ +static uint32_t iface_change_wait_time_checkpoint; +static void checkpoint_iface_change_wait_time(struct hdd_context *hdd_ctx) +{ + struct hdd_config *config = hdd_ctx->config; + + /* did we already checkpoint a value ? */ + if (iface_change_wait_time_checkpoint) + return; + + /* checkpoint current value */ + iface_change_wait_time_checkpoint = config->iface_change_wait_time; + + /* was the timer enabled when we checkpointed? */ + if (iface_change_wait_time_checkpoint) + return; + + /* WAR was enabled at boot, use default when disable */ + iface_change_wait_time_checkpoint = + cfg_default(CFG_INTERFACE_CHANGE_WAIT); +} + +static int hdd_hastings_war_enable(struct hdd_context *hdd_ctx) +{ + struct hdd_config *config = hdd_ctx->config; + + config->iface_change_wait_time = 0; + + return hdd_hastings_bt_war_enable_fw(hdd_ctx); +} + +static int hdd_hastings_war_disable(struct hdd_context *hdd_ctx) +{ + struct hdd_config *config = hdd_ctx->config; + + config->iface_change_wait_time = iface_change_wait_time_checkpoint; + + return hdd_hastings_bt_war_disable_fw(hdd_ctx); +} + +static int hdd_we_set_hastings_bt_war(struct wlan_hdd_link_info *link_info, + int enable) +{ + int errno; + struct hdd_context *hdd_ctx; + struct hdd_adapter *adapter = link_info->adapter; + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (!hdd_hastings_bt_war_applicable(hdd_ctx)) + return 0; + + checkpoint_iface_change_wait_time(hdd_ctx); + + return enable ? + hdd_hastings_war_enable(hdd_ctx) : + hdd_hastings_war_disable(hdd_ctx); +} +#endif + +static int hdd_we_set_tm_level(struct wlan_hdd_link_info *link_info, int level) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + QDF_STATUS status; + + if (!mac_handle) + return -EINVAL; + + hdd_debug("Thermal Mitigation Level %d", level); + status = sme_set_thermal_level(mac_handle, level); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", level, status); + + return qdf_status_to_os_return(status); +} + +static int hdd_we_set_nss(struct wlan_hdd_link_info *link_info, int nss) +{ + QDF_STATUS status; + + hdd_debug("NSS %d", nss); + + if ((nss > 2) || (nss <= 0)) { + hdd_err("Invalid NSS: %d", nss); + return -EINVAL; + } + + status = hdd_update_nss(link_info, nss, nss); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("cfg set failed, value %d status %d", nss, status); + + return qdf_status_to_os_return(status); +} + +int hdd_we_set_short_gi(struct wlan_hdd_link_info *link_info, int sgi) +{ + int errno; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + + hdd_debug("Short GI %d", sgi); + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + if (sgi & HDD_AUTO_RATE_SGI) + errno = sme_set_auto_rate_he_sgi(mac_handle, + link_info->vdev_id, + sgi); + else + errno = sme_update_ht_config(mac_handle, + link_info->vdev_id, + WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ, + sgi); + if (errno) + hdd_err("cfg set failed, value %d status %d", sgi, errno); + + return errno; +} + +static int hdd_we_set_rtscts(struct wlan_hdd_link_info *link_info, int rtscts) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + uint32_t value; + uint32_t rts_threshold_val; + QDF_STATUS status; + int errno; + + hdd_debug("RTSCTS %d", rtscts); + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + status = ucfg_mlme_get_rts_threshold(hdd_ctx->psoc, + &rts_threshold_val); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get rts threshold failed, status %d", status); + return -EINVAL; + } + + if ((rtscts & HDD_RTSCTS_EN_MASK) == HDD_RTSCTS_ENABLE) { + value = rts_threshold_val; + } else if (((rtscts & HDD_RTSCTS_EN_MASK) == 0) || + ((rtscts & HDD_RTSCTS_EN_MASK) == HDD_CTS_ENABLE)) { + value = cfg_max(CFG_RTS_THRESHOLD); + } else { + hdd_err_rl("Invalid value %d", rtscts); + return -EINVAL; + } + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_enable_rtscts, + rtscts, VDEV_CMD); + if (errno) { + hdd_err("Failed to set firmware, errno %d", errno); + return errno; + } + + status = ucfg_mlme_set_rts_threshold(hdd_ctx->psoc, value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Set rts threshold failed, status %d", status); + return -EINVAL; + } + + return 0; +} + +static int hdd_we_set_11n_rate(struct wlan_hdd_link_info *link_info, + int rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int errno; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + enum wlan_phymode peer_phymode; + uint8_t *peer_mac; + + peer_mac = link_info->session.station.conn_info.bssid.bytes; + + hdd_debug("Rate code %d", rate_code); + + if (rate_code != 0xffff) { + rix = RC_2_RATE_IDX(rate_code); + if (rate_code & 0x80) { + preamble = WMI_RATE_PREAMBLE_HT; + nss = HT_RC_2_STREAMS(rate_code) - 1; + } else { + status = ucfg_mlme_get_peer_phymode(hdd_ctx->psoc, + peer_mac, + &peer_phymode); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set rate"); + return 0; + } + if (IS_WLAN_PHYMODE_HE(peer_phymode)) { + hdd_err("Do not set legacy rate %d in HE mode", + rate_code); + return 0; + } + nss = 0; + rix = RC_2_RATE_IDX(rate_code); + if (rate_code & 0x10) { + preamble = WMI_RATE_PREAMBLE_CCK; + if (rix != 0x3) + /* Enable Short preamble + * always for CCK except 1mbps + */ + rix |= 0x4; + } else { + preamble = WMI_RATE_PREAMBLE_OFDM; + } + } + rate_code = hdd_assemble_rate_code(preamble, nss, rix); + } + + hdd_debug("wmi_vdev_param_fixed_rate val %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +static int hdd_we_set_vht_rate(struct wlan_hdd_link_info *link_info, + int rate_code) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + int errno; + + hdd_debug("Rate code %d", rate_code); + + if (rate_code != 0xffff) { + rix = RC_2_RATE_IDX_11AC(rate_code); + preamble = WMI_RATE_PREAMBLE_VHT; + nss = HT_RC_2_STREAMS_11AC(rate_code) - 1; + rate_code = hdd_assemble_rate_code(preamble, nss, rix); + } + + hdd_debug("wmi_vdev_param_fixed_rate val %d rix %d preamble %x nss %d", + rate_code, rix, preamble, nss); + + errno = wma_cli_set_command(link_info->vdev_id, + wmi_vdev_param_fixed_rate, + rate_code, VDEV_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +static int hdd_we_set_ampdu(struct wlan_hdd_link_info *link_info, int ampdu) +{ + hdd_debug("AMPDU %d", ampdu); + return wma_cli_set_command(link_info->vdev_id, + GEN_VDEV_PARAM_AMPDU, + ampdu, GEN_CMD); +} + +static int hdd_we_set_amsdu(struct wlan_hdd_link_info *link_info, int amsdu) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + mac_handle_t mac_handle = hdd_ctx->mac_handle; + int errno; + QDF_STATUS status; + + hdd_debug("AMSDU %d", amsdu); + + if (!mac_handle) { + hdd_err("NULL Mac handle"); + return -EINVAL; + } + + status = ucfg_mlme_set_max_amsdu_num(hdd_ctx->psoc, amsdu); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to set Max AMSDU Num to cfg"); + return -EINVAL; + } + + if (amsdu > 1) + sme_set_amsdu(mac_handle, true); + else + sme_set_amsdu(mac_handle, false); + + errno = wma_cli_set_command(link_info->vdev_id, GEN_VDEV_PARAM_AMSDU, + amsdu, GEN_CMD); + if (errno) { + hdd_err("Failed to set firmware, errno %d", errno); + return errno; + } + + return 0; +} + +static int hdd_we_clear_stats(struct wlan_hdd_link_info *link_info, int option) +{ + return hdd_wlan_clear_stats(link_info->adapter, option); +} + +static int hdd_we_set_green_tx_param(struct hdd_adapter *adapter, + green_tx_param id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, GTX_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_we_set_green_tx_param(adapter, id, value) \ + hdd_we_set_green_tx_param(adapter, id, #id, value) + +static int hdd_we_set_gtx_ht_mcs(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_ht_mcs, + value); +} + +static int hdd_we_set_gtx_vht_mcs(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_vht_mcs, + value); +} + +static int hdd_we_set_gtx_usrcfg(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_usr_cfg, + value); +} + +static int hdd_we_set_gtx_thre(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_thre, + value); +} + +static int hdd_we_set_gtx_margin(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_margin, + value); +} + +static int hdd_we_set_gtx_step(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_step, + value); +} + +static int hdd_we_set_gtx_mintpc(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_mintpc, + value); +} + +static int hdd_we_set_gtx_bwmask(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_green_tx_param(link_info->adapter, + wmi_vdev_param_gtx_bw_mask, + value); +} + +static int hdd_we_packet_power_save(struct hdd_adapter *adapter, + packet_power_save id, + const char *id_string, + int value) +{ + int errno; + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err_rl("Not supported in mode %d", adapter->device_mode); + return -EINVAL; + } + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, PPS_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_we_packet_power_save(adapter, id, value) \ + hdd_we_packet_power_save(adapter, id, #id, value) + +static int hdd_we_pps_paid_match(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_PAID_MATCH, + value); +} + +static int hdd_we_pps_gid_match(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_GID_MATCH, + value); +} + +static int hdd_we_pps_early_tim_clear(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + value); +} + +static int hdd_we_pps_early_dtim_clear(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + value); +} + +static int hdd_we_pps_eof_pad_delim(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_EOF_PAD_DELIM, + value); +} + +static int hdd_we_pps_macaddr_mismatch(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_MACADDR_MISMATCH, + value); +} + +static int hdd_we_pps_delim_crc_fail(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + value); +} + +static int hdd_we_pps_gid_nsts_zero(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_GID_NSTS_ZERO, + value); +} + +static int hdd_we_pps_rssi_check(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_RSSI_CHECK, + value); +} + +static int hdd_we_pps_5g_ebt(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_packet_power_save(link_info->adapter, + WMI_VDEV_PPS_5G_EBT, + value); +} + +static int hdd_we_set_qpower(struct hdd_adapter *adapter, + enum wmi_sta_powersave_param id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, QPOWER_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_we_set_qpower(adapter, id, value) \ + hdd_we_set_qpower(adapter, id, #id, value) + +static int +hdd_we_set_qpower_max_pspoll_count(struct wlan_hdd_link_info *link_info, + int value) +{ + enum wmi_sta_powersave_param id = + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT; + + return hdd_we_set_qpower(link_info->adapter, id, value); +} + +static int +hdd_we_set_qpower_max_tx_before_wake(struct wlan_hdd_link_info *link_info, + int value) +{ + enum wmi_sta_powersave_param id = + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE; + + return hdd_we_set_qpower(link_info->adapter, id, value); +} + +static int +hdd_we_set_qpower_spec_pspoll_wake_interval(struct wlan_hdd_link_info *link_info, + int value) +{ + enum wmi_sta_powersave_param id = + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL; + + return hdd_we_set_qpower(link_info->adapter, id, value); +} + +static int +hdd_we_set_qpower_spec_max_spec_nodata_pspoll(struct wlan_hdd_link_info *link_info, + int value) +{ + enum wmi_sta_powersave_param id = + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL; + + return hdd_we_set_qpower(link_info->adapter, id, value); +} + +static int hdd_we_set_pdev(struct hdd_adapter *adapter, + wmi_conv_pdev_params_id id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, PDEV_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_we_set_pdev(adapter, id, value) \ + hdd_we_set_pdev(adapter, id, #id, value) + +static int hdd_we_set_ani_en_dis(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_ani_enable, + value); +} + +static int hdd_we_set_ani_poll_period(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_ani_poll_period, + value); +} + +static int hdd_we_set_ani_listen_period(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_ani_listen_period, + value); +} + +static int hdd_we_set_ani_ofdm_level(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_ani_ofdm_level, + value); +} + +static int hdd_we_set_ani_cck_level(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_ani_cck_level, + value); +} + +static int hdd_we_set_dynamic_bw(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_dynamic_bw, + value); +} + +static int hdd_we_set_cts_cbw(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_cts_cbw, + value); +} + +static int hdd_we_set_tx_chainmask(struct wlan_hdd_link_info *link_info, + int value) +{ + int errno; + + errno = hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_tx_chain_mask, + value); + if (errno) + return errno; + + return hdd_set_antenna_mode(link_info, value); +} + +static int hdd_we_set_rx_chainmask(struct wlan_hdd_link_info *link_info, + int value) +{ + int errno; + + errno = hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_rx_chain_mask, + value); + if (errno) + return errno; + + return hdd_set_antenna_mode(link_info, value); +} + +static int hdd_we_set_txpow_2g(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_txpower_limit2g, + value); +} + +static int hdd_we_set_txpow_5g(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_pdev(link_info->adapter, + wmi_pdev_param_txpower_limit5g, + value); +} + +static int hdd_we_set_vdev(struct hdd_adapter *adapter, + int id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, VDEV_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_we_set_vdev(adapter, id, value) \ + hdd_we_set_vdev(adapter, id, #id, value) + +static int hdd_we_set_txrx_fwstats(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID, + value); +} + +static int hdd_we_txrx_fwstats_reset(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + value); +} + +static int hdd_we_set_htsmps(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + WMI_STA_SMPS_FORCE_MODE_CMDID, + value); +} + +static int +hdd_we_set_early_rx_adjust_enable(struct wlan_hdd_link_info *link_info, + int value) +{ + if ((value != 0) && (value != 1)) + return -EINVAL; + + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_adjust_enable, + value); +} + +static int +hdd_we_set_early_rx_tgt_bmiss_num(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_tgt_bmiss_num, + value); +} + +static int +hdd_we_set_early_rx_bmiss_sample_cycle(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_bmiss_sample_cycle, + value); +} + +static int hdd_we_set_early_rx_slop_step(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_slop_step, + value); +} + +static int hdd_we_set_early_rx_init_slop(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_init_slop, + value); +} + +static int +hdd_we_set_early_rx_adjust_pause(struct wlan_hdd_link_info *link_info, + int value) +{ + if ((value != 0) && (value != 1)) + return -EINVAL; + + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_adjust_pause, + value); +} + +static int +hdd_we_set_early_rx_drift_sample(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_early_rx_drift_sample, + value); +} + +static int hdd_we_set_dcm(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_vdev(link_info->adapter, + wmi_vdev_param_he_dcm_enable, + value); +} + +#define MAX_VDEV_HE_RANGE_PARAMS 2 +/* params being sent: + * wmi_vdev_param_he_range_ext + * wmi_vdev_param_non_data_he_range_ext + */ + +static int hdd_we_set_range_ext(struct wlan_hdd_link_info *link_info, + int value) +{ + int status; + struct dev_set_param setparam[MAX_VDEV_HE_RANGE_PARAMS] = {}; + uint8_t index = 0; + + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_he_range_ext, + value, index++, + MAX_VDEV_HE_RANGE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_vdev_param_he_range_ext"); + goto error; + } + + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_non_data_he_range_ext, + value, index++, + MAX_VDEV_HE_RANGE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("failed at wmi_vdev_param_non_data_he_range_ext"); + goto error; + } + + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + link_info->vdev_id, + setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to send vdev set params"); + +error: + return status; +} + +static int hdd_we_set_dbg(struct hdd_adapter *adapter, + int id, + const char *id_string, + int value) +{ + int errno; + + hdd_debug("%s %d", id_string, value); + errno = wma_cli_set_command(adapter->deflink->vdev_id, + id, value, DBG_CMD); + if (errno) + hdd_err("Failed to set firmware, errno %d", errno); + + return errno; +} + +#define hdd_we_set_dbg(adapter, id, value) \ + hdd_we_set_dbg(adapter, id, #id, value) + +static int hdd_we_dbglog_log_level(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_LOG_LEVEL, + value); +} + +static int hdd_we_dbglog_vap_enable(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_VAP_ENABLE, + value); +} + +static int hdd_we_dbglog_vap_disable(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_VAP_DISABLE, + value); +} + +static int hdd_we_dbglog_module_enable(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_MODULE_ENABLE, + value); +} + +static int hdd_we_dbglog_module_disable(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_MODULE_DISABLE, + value); +} + +static int hdd_we_dbglog_mod_log_level(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_MOD_LOG_LEVEL, + value); +} + +static int hdd_we_dbglog_type(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_TYPE, + value); +} + +static int hdd_we_dbglog_report_enable(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_DBGLOG_REPORT_ENABLE, + value); +} + +static int hdd_we_start_fw_profile(struct wlan_hdd_link_info *link_info, + int value) +{ + return hdd_we_set_dbg(link_info->adapter, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + value); +} + +static int hdd_we_set_channel(struct wlan_hdd_link_info *link_info, + int channel) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + qdf_freq_t ch_freq; + QDF_STATUS status; + + hdd_debug("Set Channel %d Session ID %d mode %d", channel, + link_info->vdev_id, adapter->device_mode); + + if (!hdd_ctx->mac_handle) + return -EINVAL; + + switch (adapter->device_mode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + /* supported */ + break; + default: + hdd_err("change channel not supported for device mode %d", + adapter->device_mode); + return -EINVAL; + } + ch_freq = wlan_reg_legacy_chan_to_freq(hdd_ctx->pdev, + channel); + status = sme_ext_change_freq(hdd_ctx->mac_handle, ch_freq, + link_info->vdev_id); + if (status != QDF_STATUS_SUCCESS) + hdd_err("Error in change channel status %d", status); + + return qdf_status_to_os_return(status); +} + +static int hdd_we_mcc_config_latency(struct wlan_hdd_link_info *link_info, + int latency) +{ + hdd_debug("MCC latency %d", latency); + + wlan_hdd_set_mcc_latency(link_info->adapter, latency); + + return 0; +} + +static int hdd_we_mcc_config_quota(struct wlan_hdd_link_info *link_info, + int quota) +{ + hdd_debug("MCC quota %dms", quota); + + return wlan_hdd_set_mcc_p2p_quota(link_info->adapter, quota); +} + +static int hdd_we_set_debug_log(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + if (!hdd_ctx->mac_handle) + return -EINVAL; + + sme_update_connect_debug(hdd_ctx->mac_handle, value); + + return 0; +} + +static int hdd_we_set_scan_disable(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + hdd_debug("%d", value); + + if (!hdd_ctx->psoc) + return -EINVAL; + + if (value) + ucfg_scan_psoc_set_disable(hdd_ctx->psoc, REASON_USER_SPACE); + else + ucfg_scan_psoc_set_enable(hdd_ctx->psoc, REASON_USER_SPACE); + + return 0; +} + +static int hdd_we_set_conc_system_pref(struct wlan_hdd_link_info *link_info, + int preference) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + hdd_debug("%d", preference); + + if (!hdd_ctx->psoc) + return -EINVAL; + + ucfg_policy_mgr_set_sys_pref(hdd_ctx->psoc, preference); + + return 0; +} + +static int hdd_we_set_11ax_rate(struct wlan_hdd_link_info *link_info, + int rate) +{ + return hdd_set_11ax_rate(link_info->adapter, rate, NULL); +} + +static int hdd_we_set_modulated_dtim(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(link_info->adapter); + + hdd_debug("%d", value); + + if (!hdd_ctx->psoc) + return -EINVAL; + + if ((value < cfg_min(CFG_PMO_ENABLE_MODULATED_DTIM)) || + (value > cfg_max(CFG_PMO_ENABLE_MODULATED_DTIM))) { + hdd_err("Invalid value %d", value); + return -EINVAL; + } + + ucfg_policy_mgr_set_sys_pref(hdd_ctx->psoc, value); + + return 0; +} + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * hdd_we_motion_det_start_stop - start/stop motion detection + * @link_info: Link info pointer in HDD adapter + * @value: start/stop value to set + * + * Return: 0 on success, error on failure + */ +static int hdd_we_motion_det_start_stop(struct wlan_hdd_link_info *link_info, + int value) +{ + struct sme_motion_det_en motion_det; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (value < 0 || value > 1) { + hdd_err("Invalid value %d in mt_start", value); + return -EINVAL; + } + + if (!adapter->motion_det_cfg) { + hdd_err("Motion Detection config values not available"); + return -EINVAL; + } + + if (!adapter->motion_det_baseline_value) { + hdd_err("Motion Detection Baselining not started/completed"); + return -EAGAIN; + } + + motion_det.vdev_id = link_info->vdev_id; + motion_det.enable = value; + + if (value) { + /* For motion detection start, set motion_det_in_progress */ + adapter->motion_det_in_progress = true; + } else { + /* For motion detection stop, reset motion_det_in_progress */ + adapter->motion_det_in_progress = false; + adapter->motion_detection_mode = 0; + } + + sme_motion_det_enable(hdd_ctx->mac_handle, &motion_det); + + return 0; +} + +/** + * hdd_we_motion_det_base_line_start_stop - start/stop md baselining + * @link_info: Link info pointer in HDD adapter + * @value: start/stop value to set + * + * Return: 0 on success, error on failure + */ +static int +hdd_we_motion_det_base_line_start_stop(struct wlan_hdd_link_info *link_info, + int value) +{ + struct hdd_adapter *adapter = link_info->adapter; + struct sme_motion_det_base_line_en motion_det_base_line; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (value < 0 || value > 1) { + hdd_err("Invalid value %d in mt_bl_start", value); + return -EINVAL; + } + + /* Do not send baselining start/stop during motion detection phase */ + if (adapter->motion_det_in_progress) { + hdd_err("Motion detection still in progress, try later"); + return -EAGAIN; + } + + motion_det_base_line.vdev_id = link_info->vdev_id; + motion_det_base_line.enable = value; + sme_motion_det_base_line_enable(hdd_ctx->mac_handle, + &motion_det_base_line); + + return 0; +} +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +int wlan_hdd_set_btcoex_mode(struct wlan_hdd_link_info *link_info, int value) +{ + struct coex_config_params coex_cfg_params = {0}; + + coex_cfg_params.config_type = WMI_COEX_CONFIG_BTC_MODE; + coex_cfg_params.config_arg1 = value; + coex_cfg_params.vdev_id = link_info->vdev_id; + + if (value < cfg_min(CFG_BTC_MODE) || value > cfg_max(CFG_BTC_MODE)) { + hdd_err_rl("Invalid value %d", value); + return -EINVAL; + } + + if (QDF_IS_STATUS_ERROR(sme_send_coex_config_cmd(&coex_cfg_params))) { + hdd_err_rl("Failed to send coex BTC mode"); + return -EINVAL; + } + + return 0; +} + +int wlan_hdd_set_btcoex_rssi_threshold(struct wlan_hdd_link_info *link_info, + int value) +{ + struct coex_config_params coex_cfg_params = {0}; + + coex_cfg_params.config_type = WMI_COEX_CONFIG_BT_LOW_RSSI_THRESHOLD; + coex_cfg_params.config_arg1 = value; + coex_cfg_params.vdev_id = link_info->vdev_id; + + if (value < cfg_min(CFG_WLAN_LOW_RSSI_THRESHOLD) || + value > cfg_max(CFG_WLAN_LOW_RSSI_THRESHOLD)) { + hdd_err_rl("Invalid value %d", value); + return -EINVAL; + } + + if (QDF_IS_STATUS_ERROR(sme_send_coex_config_cmd(&coex_cfg_params))) { + hdd_err_rl("Failed to send coex BTC RSSI Threshold"); + return -EINVAL; + } + return 0; +} + +typedef int (*setint_getnone_fn)(struct wlan_hdd_link_info *link_info, + int value); +static const setint_getnone_fn setint_getnone_cb[] = { + [WE_SET_11D_STATE] = hdd_we_set_11d_state, + [WE_SET_POWER] = hdd_we_set_power, + [WE_SET_MAX_ASSOC] = hdd_we_set_max_assoc, + [WE_SET_DATA_INACTIVITY_TO] = hdd_we_set_data_inactivity_timeout, + [WE_SET_WOW_DATA_INACTIVITY_TO] = + hdd_we_set_wow_data_inactivity_timeout, + [WE_SET_MC_RATE] = wlan_hdd_set_mc_rate, + [WE_SET_TX_POWER] = hdd_we_set_tx_power, + [WE_SET_MAX_TX_POWER] = hdd_we_set_max_tx_power, + [WE_SET_MAX_TX_POWER_2_4] = hdd_we_set_max_tx_power_2_4, + [WE_SET_MAX_TX_POWER_5_0] = hdd_we_set_max_tx_power_5_0, +#ifdef HASTINGS_BT_WAR + [WE_SET_HASTINGS_BT_WAR] = hdd_we_set_hastings_bt_war, +#endif + [WE_SET_TM_LEVEL] = hdd_we_set_tm_level, + [WE_SET_PHYMODE] = hdd_we_update_phymode, + [WE_SET_NSS] = hdd_we_set_nss, + [WE_SET_GTX_HT_MCS] = hdd_we_set_gtx_ht_mcs, + [WE_SET_GTX_VHT_MCS] = hdd_we_set_gtx_vht_mcs, + [WE_SET_GTX_USRCFG] = hdd_we_set_gtx_usrcfg, + [WE_SET_GTX_THRE] = hdd_we_set_gtx_thre, + [WE_SET_GTX_MARGIN] = hdd_we_set_gtx_margin, + [WE_SET_GTX_STEP] = hdd_we_set_gtx_step, + [WE_SET_GTX_MINTPC] = hdd_we_set_gtx_mintpc, + [WE_SET_GTX_BWMASK] = hdd_we_set_gtx_bwmask, + [WE_SET_LDPC] = hdd_set_ldpc, + [WE_SET_TX_STBC] = hdd_set_tx_stbc, + [WE_SET_RX_STBC] = hdd_set_rx_stbc, + [WE_SET_SHORT_GI] = hdd_we_set_short_gi, + [WE_SET_RTSCTS] = hdd_we_set_rtscts, + [WE_SET_CHWIDTH] = hdd_we_set_ch_width, + [WE_SET_ANI_EN_DIS] = hdd_we_set_ani_en_dis, + [WE_SET_ANI_POLL_PERIOD] = hdd_we_set_ani_poll_period, + [WE_SET_ANI_LISTEN_PERIOD] = hdd_we_set_ani_listen_period, + [WE_SET_ANI_OFDM_LEVEL] = hdd_we_set_ani_ofdm_level, + [WE_SET_ANI_CCK_LEVEL] = hdd_we_set_ani_cck_level, + [WE_SET_DYNAMIC_BW] = hdd_we_set_dynamic_bw, + [WE_SET_CTS_CBW] = hdd_we_set_cts_cbw, + [WE_SET_11N_RATE] = hdd_we_set_11n_rate, + [WE_SET_VHT_RATE] = hdd_we_set_vht_rate, + [WE_SET_AMPDU] = hdd_we_set_ampdu, + [WE_SET_AMSDU] = hdd_we_set_amsdu, + [WE_SET_TX_CHAINMASK] = hdd_we_set_tx_chainmask, + [WE_SET_RX_CHAINMASK] = hdd_we_set_rx_chainmask, + [WE_SET_TXPOW_2G] = hdd_we_set_txpow_2g, + [WE_SET_TXPOW_5G] = hdd_we_set_txpow_5g, + [WE_DBGLOG_LOG_LEVEL] = hdd_we_dbglog_log_level, + [WE_DBGLOG_VAP_ENABLE] = hdd_we_dbglog_vap_enable, + [WE_DBGLOG_VAP_DISABLE] = hdd_we_dbglog_vap_disable, + [WE_DBGLOG_MODULE_ENABLE] = hdd_we_dbglog_module_enable, + [WE_DBGLOG_MODULE_DISABLE] = hdd_we_dbglog_module_disable, + [WE_DBGLOG_MOD_LOG_LEVEL] = hdd_we_dbglog_mod_log_level, + [WE_DBGLOG_TYPE] = hdd_we_dbglog_type, + [WE_DBGLOG_REPORT_ENABLE] = hdd_we_dbglog_report_enable, + [WE_SET_TXRX_FWSTATS] = hdd_we_set_txrx_fwstats, + [WE_TXRX_FWSTATS_RESET] = hdd_we_txrx_fwstats_reset, + [WE_DUMP_STATS] = hdd_we_dump_stats, + [WE_CLEAR_STATS] = hdd_we_clear_stats, + [WE_PPS_PAID_MATCH] = hdd_we_pps_paid_match, + [WE_PPS_GID_MATCH] = hdd_we_pps_gid_match, + [WE_PPS_EARLY_TIM_CLEAR] = hdd_we_pps_early_tim_clear, + [WE_PPS_EARLY_DTIM_CLEAR] = hdd_we_pps_early_dtim_clear, + [WE_PPS_EOF_PAD_DELIM] = hdd_we_pps_eof_pad_delim, + [WE_PPS_MACADDR_MISMATCH] = hdd_we_pps_macaddr_mismatch, + [WE_PPS_DELIM_CRC_FAIL] = hdd_we_pps_delim_crc_fail, + [WE_PPS_GID_NSTS_ZERO] = hdd_we_pps_gid_nsts_zero, + [WE_PPS_RSSI_CHECK] = hdd_we_pps_rssi_check, + [WE_PPS_5G_EBT] = hdd_we_pps_5g_ebt, + [WE_SET_HTSMPS] = hdd_we_set_htsmps, + [WE_SET_QPOWER_MAX_PSPOLL_COUNT] = hdd_we_set_qpower_max_pspoll_count, + [WE_SET_QPOWER_MAX_TX_BEFORE_WAKE] = + hdd_we_set_qpower_max_tx_before_wake, + [WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL] = + hdd_we_set_qpower_spec_pspoll_wake_interval, + [WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL] = + hdd_we_set_qpower_spec_max_spec_nodata_pspoll, + [WE_MCC_CONFIG_LATENCY] = hdd_we_mcc_config_latency, + [WE_MCC_CONFIG_QUOTA] = hdd_we_mcc_config_quota, + [WE_SET_DEBUG_LOG] = hdd_we_set_debug_log, + [WE_SET_EARLY_RX_ADJUST_ENABLE] = hdd_we_set_early_rx_adjust_enable, + [WE_SET_EARLY_RX_TGT_BMISS_NUM] = hdd_we_set_early_rx_tgt_bmiss_num, + [WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE] = + hdd_we_set_early_rx_bmiss_sample_cycle, + [WE_SET_EARLY_RX_SLOP_STEP] = hdd_we_set_early_rx_slop_step, + [WE_SET_EARLY_RX_INIT_SLOP] = hdd_we_set_early_rx_init_slop, + [WE_SET_EARLY_RX_ADJUST_PAUSE] = hdd_we_set_early_rx_adjust_pause, + [WE_SET_EARLY_RX_DRIFT_SAMPLE] = hdd_we_set_early_rx_drift_sample, + [WE_SET_SCAN_DISABLE] = hdd_we_set_scan_disable, + [WE_START_FW_PROFILE] = hdd_we_start_fw_profile, + [WE_SET_CHANNEL] = hdd_we_set_channel, + [WE_SET_CONC_SYSTEM_PREF] = hdd_we_set_conc_system_pref, + [WE_SET_11AX_RATE] = hdd_we_set_11ax_rate, + [WE_SET_DCM] = hdd_we_set_dcm, + [WE_SET_RANGE_EXT] = hdd_we_set_range_ext, + [WE_SET_PDEV_RESET] = hdd_handle_pdev_reset, + [WE_SET_MODULATED_DTIM] = hdd_we_set_modulated_dtim, +#ifdef WLAN_FEATURE_MOTION_DETECTION + [WE_MOTION_DET_START_STOP] = hdd_we_motion_det_start_stop, + [WE_MOTION_DET_BASE_LINE_START_STOP] = + hdd_we_motion_det_base_line_start_stop, +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + [WE_SET_BTCOEX_MODE] = wlan_hdd_set_btcoex_mode, + [WE_SET_BTCOEX_RSSI_THRESHOLD] = wlan_hdd_set_btcoex_rssi_threshold, +}; + +static setint_getnone_fn hdd_get_setint_getnone_cb(int param) +{ + if (param < 0) + return NULL; + + if (param >= QDF_ARRAY_SIZE(setint_getnone_cb)) + return NULL; + + return setint_getnone_cb[param]; +} + +/** + * __iw_setint_getnone() - Generic "set integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + setint_getnone_fn cb; + int *value = (int *)extra; + int sub_cmd = value[0]; + int set_value = value[1]; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (ret) + return ret; + + cb = hdd_get_setint_getnone_cb(sub_cmd); + if (!cb) { + hdd_debug("Invalid sub command %d", sub_cmd); + return -EINVAL; + } + + ret = cb(adapter->deflink, set_value); + + hdd_exit(); + + return ret; +} + +/** + * iw_setint_getnone() - Generic "set integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_setint_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_setint_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_setnone_get_threeint() - return three value to up layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int __iw_setnone_get_threeint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret = 0; /* success */ + uint32_t *value = (int *)extra; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_tsf_op_response tsf_op_resp; + + hdd_enter_dev(dev); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + hdd_debug("param = %d", value[0]); + switch (value[0]) { + case WE_GET_TSF: + ret = hdd_indicate_tsf(adapter, &tsf_op_resp); + if (!ret) { + value[0] = tsf_op_resp.status; + value[1] = tsf_op_resp.time & 0xffffffff; + value[2] = (tsf_op_resp.time >> 32) & 0xffffffff; + } + break; + default: + hdd_err("Invalid IOCTL get_value command %d", value[0]); + break; + } + return ret; +} + +/** + * iw_setnone_get_threeint() - return three value to up layer. + * + * @dev: pointer of net_device of this wireless card + * @info: meta data about Request sent + * @wrqu: include request info + * @extra: buf used for in/Output + * + * Return: execute result + */ +static int iw_setnone_get_threeint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_setnone_get_threeint(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_setchar_getnone() - Generic "set string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int sub_cmd; + int ret; + char *str_arg = NULL; + struct hdd_adapter *adapter = (netdev_priv(dev)); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct iw_point s_priv_data; + bool neighbor_report_req_support = false; + + hdd_enter_dev(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) + return -EINVAL; + + /* make sure all params are correctly passed to function */ + if ((!s_priv_data.pointer) || (0 == s_priv_data.length)) + return -EINVAL; + + sub_cmd = s_priv_data.flags; + + /* ODD number is used for set, copy data using copy_from_user */ + str_arg = mem_alloc_copy_from_user_helper(s_priv_data.pointer, + s_priv_data.length); + if (!str_arg) { + hdd_err("mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + hdd_debug("Received length: %d data: %s", + s_priv_data.length, str_arg); + + switch (sub_cmd) { + case WE_WOWL_ADD_PTRN: + hdd_debug("ADD_PTRN"); + if (!hdd_add_wowl_ptrn(adapter, str_arg)) + ret = -EINVAL; + break; + case WE_WOWL_DEL_PTRN: + hdd_debug("DEL_PTRN"); + if (!hdd_del_wowl_ptrn(adapter, str_arg)) + ret = -EINVAL; + break; + case WE_NEIGHBOR_REPORT_REQUEST: + { + tRrmNeighborReq request; + tRrmNeighborRspCallbackInfo callback; + bool rrm_enabled = false; + + ucfg_wlan_mlme_get_rrm_enabled(hdd_ctx->psoc, + &rrm_enabled); + + if (rrm_enabled) { + request.neighbor_report_offload = false; + request.no_ssid = + (s_priv_data.length - 1) ? false : true; + hdd_debug("Neighbor Request ssid present %d", + request.no_ssid); + if (!request.no_ssid) { + request.ssid.length = + (s_priv_data.length - 1) > + 32 ? 32 : (s_priv_data.length - 1); + qdf_mem_copy(request.ssid.ssId, + str_arg, + request.ssid.length); + } + + /* + * If 11k offload is supported by FW and enabled + * in the ini, set the offload to true + */ + if (QDF_IS_STATUS_ERROR( + ucfg_fwol_is_neighbor_report_req_supported( + hdd_ctx->psoc, &neighbor_report_req_support))) + hdd_err("Neighbor report req bit get fail"); + + if (hdd_ctx->config->is_11k_offload_supported && + neighbor_report_req_support) { + hdd_debug("Neighbor report offloaded to FW"); + request.neighbor_report_offload = true; + } + + callback.neighborRspCallback = NULL; + callback.neighborRspCallbackContext = NULL; + callback.timeout = 5000; /* 5 seconds */ + sme_neighbor_report_request( + hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + &request, + &callback); + } else { + hdd_err("Ignoring neighbor request as RRM not enabled"); + ret = -EINVAL; + } + } + break; + case WE_SET_AP_WPS_IE: + hdd_debug("Received WE_SET_AP_WPS_IE, won't process"); + break; + case WE_UNIT_TEST: + ret = wlan_hdd_unit_test(hdd_ctx, str_arg); + break; + default: + { + hdd_err("Invalid sub command %d", sub_cmd); + ret = -EINVAL; + break; + } + } + + qdf_mem_free(str_arg); + hdd_exit(); + + return ret; +} + +/** + * iw_setchar_getnone() - Generic "set string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_setchar_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_setchar_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_setnone_getint() - Generic "get integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + mac_handle_t mac_handle; + int *value = (int *)extra; + int ret; + struct sme_config_params *sme_config; + struct hdd_context *hdd_ctx; + QDF_STATUS status; + bool bval = false; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) + return -ENOMEM; + + mac_handle = hdd_ctx->mac_handle; + switch (value[0]) { + case WE_GET_11D_STATE: + { + status = ucfg_mlme_is_11d_enabled(hdd_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Invalid 11d_enable flag"); + *value = bval; + hdd_debug("11D state=%d!!", *value); + + break; + } + + case WE_GET_WLAN_DBG: + { + qdf_trace_display(); + *value = 0; + break; + } + case WE_GET_MAX_ASSOC: + { + if (ucfg_mlme_get_assoc_sta_limit(hdd_ctx->psoc, value) != + QDF_STATUS_SUCCESS) { + hdd_err("CFG_ASSOC_STA_LIMIT failed"); + ret = -EIO; + } + + break; + } + + case WE_GET_CONCURRENCY_MODE: + { + *value = policy_mgr_get_concurrency_mode(hdd_ctx->psoc); + + hdd_debug("concurrency mode=%d", *value); + break; + } + + case WE_GET_NSS: + { + uint8_t nss; + + status = hdd_get_nss(adapter, &nss); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("unable to get vht_enable2x2"); + ret = -EIO; + break; + } + *value = nss; + + hdd_debug("GET_NSS: Current NSS:%d", *value); + break; + } + + case WE_GET_GTX_HT_MCS: + { + hdd_debug("GET wmi_vdev_param_gtx_ht_mcs"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_ht_mcs, + GTX_CMD); + break; + } + + case WE_GET_GTX_VHT_MCS: + { + hdd_debug("GET wmi_vdev_param_gtx_vht_mcs"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_vht_mcs, + GTX_CMD); + break; + } + + case WE_GET_GTX_USRCFG: + { + hdd_debug("GET wmi_vdev_param_gtx_usr_cfg"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_usr_cfg, + GTX_CMD); + break; + } + + case WE_GET_GTX_THRE: + { + hdd_debug("GET wmi_vdev_param_gtx_thre"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_thre, + GTX_CMD); + break; + } + + case WE_GET_GTX_MARGIN: + { + hdd_debug("GET wmi_vdev_param_gtx_margin"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_margin, + GTX_CMD); + break; + } + + case WE_GET_GTX_STEP: + { + hdd_debug("GET wmi_vdev_param_gtx_step"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_step, + GTX_CMD); + break; + } + + case WE_GET_GTX_MINTPC: + { + hdd_debug("GET wmi_vdev_param_gtx_mintpc"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_mintpc, + GTX_CMD); + break; + } + + case WE_GET_GTX_BWMASK: + { + hdd_debug("GET wmi_vdev_param_gtx_bw_mask"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_gtx_bw_mask, + GTX_CMD); + break; + } + + case WE_GET_LDPC: + { + ret = hdd_get_ldpc(adapter, value); + break; + } + + case WE_GET_TX_STBC: + { + ret = hdd_get_tx_stbc(adapter, value); + break; + } + + case WE_GET_RX_STBC: + { + ret = hdd_get_rx_stbc(adapter, value); + break; + } + + case WE_GET_SHORT_GI: + { + hdd_debug("GET wmi_vdev_param_sgi"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_sgi, + VDEV_CMD); + break; + } + + case WE_GET_RTSCTS: + { + hdd_debug("GET wmi_vdev_param_enable_rtscts"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_enable_rtscts, + VDEV_CMD); + break; + } + + case WE_GET_CHWIDTH: + { + hdd_debug("GET wmi_vdev_param_chwidth"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_chwidth, + VDEV_CMD); + break; + } + + case WE_GET_ANI_EN_DIS: + { + hdd_debug("GET wmi_pdev_param_ani_enable"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_ani_enable, + PDEV_CMD); + break; + } + + case WE_GET_ANI_POLL_PERIOD: + { + hdd_debug("GET wmi_pdev_param_ani_poll_period"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_ani_poll_period, + PDEV_CMD); + break; + } + + case WE_GET_ANI_LISTEN_PERIOD: + { + hdd_debug("GET wmi_pdev_param_ani_listen_period"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_ani_listen_period, + PDEV_CMD); + break; + } + + case WE_GET_ANI_OFDM_LEVEL: + { + hdd_debug("GET wmi_pdev_param_ani_ofdm_level"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_ani_ofdm_level, + PDEV_CMD); + break; + } + + case WE_GET_ANI_CCK_LEVEL: + { + hdd_debug("GET wmi_pdev_param_ani_cck_level"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_ani_cck_level, + PDEV_CMD); + break; + } + + case WE_GET_DYNAMIC_BW: + { + hdd_debug("GET wmi_pdev_param_ani_cck_level"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_dynamic_bw, + PDEV_CMD); + break; + } + + case WE_GET_11N_RATE: + { + hdd_debug("GET wmi_vdev_param_fixed_rate"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_fixed_rate, + VDEV_CMD); + break; + } + + case WE_GET_AMPDU: + { + hdd_debug("GET AMPDU"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + GEN_VDEV_PARAM_AMPDU, + GEN_CMD); + break; + } + + case WE_GET_AMSDU: + { + hdd_debug("GET AMSDU"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + GEN_VDEV_PARAM_AMSDU, + GEN_CMD); + break; + } + + case WE_GET_ROAM_SYNCH_DELAY: + { + hdd_debug("GET ROAM SYNCH DELAY"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + GEN_VDEV_ROAM_SYNCH_DELAY, + GEN_CMD); + break; + } + + case WE_GET_TX_CHAINMASK: + { + hdd_debug("GET wmi_pdev_param_tx_chain_mask"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_tx_chain_mask, + PDEV_CMD); + break; + } + + case WE_GET_RX_CHAINMASK: + { + hdd_debug("GET wmi_pdev_param_rx_chain_mask"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_rx_chain_mask, + PDEV_CMD); + break; + } + + case WE_GET_TXPOW_2G: + { + uint8_t txpow2g = 0; + + hdd_debug("GET wmi_pdev_param_txpower_limit2g"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_txpower_limit2g, + PDEV_CMD); + ucfg_mlme_get_current_tx_power_level(hdd_ctx->psoc, &txpow2g); + hdd_debug("2G tx_power %d", txpow2g); + break; + } + + case WE_GET_TXPOW_5G: + { + uint8_t txpow5g = 0; + + hdd_debug("GET wmi_pdev_param_txpower_limit5g"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_pdev_param_txpower_limit5g, + PDEV_CMD); + ucfg_mlme_get_current_tx_power_level(hdd_ctx->psoc, &txpow5g); + hdd_debug("5G tx_power %d", txpow5g); + break; + } + + case WE_GET_PPS_PAID_MATCH: + { + hdd_debug("GET WMI_VDEV_PPS_PAID_MATCH"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_PAID_MATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_GID_MATCH: + { + hdd_debug("GET WMI_VDEV_PPS_GID_MATCH"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_GID_MATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_EARLY_TIM_CLEAR: + { + hdd_debug("GET WMI_VDEV_PPS_EARLY_TIM_CLEAR"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_EARLY_TIM_CLEAR, + PPS_CMD); + break; + } + + case WE_GET_PPS_EARLY_DTIM_CLEAR: + { + hdd_debug("GET WMI_VDEV_PPS_EARLY_DTIM_CLEAR"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR, + PPS_CMD); + break; + } + + case WE_GET_PPS_EOF_PAD_DELIM: + { + hdd_debug("GET WMI_VDEV_PPS_EOF_PAD_DELIM"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_EOF_PAD_DELIM, + PPS_CMD); + break; + } + + case WE_GET_PPS_MACADDR_MISMATCH: + { + hdd_debug("GET WMI_VDEV_PPS_MACADDR_MISMATCH"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_MACADDR_MISMATCH, + PPS_CMD); + break; + } + + case WE_GET_PPS_DELIM_CRC_FAIL: + { + hdd_debug("GET WMI_VDEV_PPS_DELIM_CRC_FAIL"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_DELIM_CRC_FAIL, + PPS_CMD); + break; + } + + case WE_GET_PPS_GID_NSTS_ZERO: + { + hdd_debug("GET WMI_VDEV_PPS_GID_NSTS_ZERO"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_GID_NSTS_ZERO, + PPS_CMD); + break; + } + + case WE_GET_PPS_RSSI_CHECK: + { + + hdd_debug("GET WMI_VDEV_PPS_RSSI_CHECK"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_VDEV_PPS_RSSI_CHECK, + PPS_CMD); + break; + } + + case WE_GET_QPOWER_MAX_PSPOLL_COUNT: + { + hdd_debug("WE_GET_QPOWER_MAX_PSPOLL_COUNT"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_MAX_TX_BEFORE_WAKE: + { + hdd_debug("WE_GET_QPOWER_MAX_TX_BEFORE_WAKE"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + { + hdd_debug("WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + QPOWER_CMD); + break; + } + + case WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + { + hdd_debug("WE_GET_QPOWER_MAX_PSPOLL_COUNT"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + QPOWER_CMD); + break; + } + case WE_CAP_TSF: + ret = hdd_capture_tsf(adapter, (uint32_t *)value, 1); + break; + case WE_GET_TEMPERATURE: + { + hdd_debug("WE_GET_TEMPERATURE"); + ret = wlan_hdd_get_temperature(adapter, value); + break; + } + case WE_GET_DCM: + hdd_debug("GET wmi_vdev_param_he_dcm"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_dcm_enable, + VDEV_CMD); + break; + case WE_GET_RANGE_EXT: + hdd_debug("GET wmi_vdev_param_he_range_ext"); + *value = wma_cli_get_command(adapter->deflink->vdev_id, + wmi_vdev_param_he_range_ext, + VDEV_CMD); + break; + default: + { + hdd_err("Invalid IOCTL get_value command %d", + value[0]); + break; + } + } + hdd_exit(); + qdf_mem_free(sme_config); + return ret; +} + +/** + * iw_setnone_getint() - Generic "get integer" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_setnone_getint(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_setnone_getint(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static int hdd_set_fwtest(int argc, int cmd, int value) +{ + struct set_fwtest_params *fw_test; + + /* check for max number of arguments */ + if (argc > WMI_UNIT_TEST_MAX_NUM_ARGS || + argc != HDD_FWTEST_PARAMS) { + hdd_err("Too Many args %d", argc); + return -EINVAL; + } + /* + * check if number of arguments are 3 then, check + * then set the default value for sounding interval. + */ + if (HDD_FWTEST_PARAMS == argc) { + if (HDD_FWTEST_SU_PARAM_ID == cmd && 0 == value) + value = HDD_FWTEST_SU_DEFAULT_VALUE; + if (HDD_FWTEST_MU_PARAM_ID == cmd && 0 == value) + value = HDD_FWTEST_MU_DEFAULT_VALUE; + } + /* check sounding interval value should not exceed to max */ + if (value > HDD_FWTEST_MAX_VALUE) { + hdd_err("Invalid arguments value should not exceed max: %d", + value); + return -EINVAL; + } + fw_test = qdf_mem_malloc(sizeof(*fw_test)); + if (!fw_test) + return -ENOMEM; + + fw_test->arg = cmd; + fw_test->value = value; + if (QDF_STATUS_SUCCESS != sme_set_fw_test(fw_test)) { + qdf_mem_free(fw_test); + hdd_err("Not able to post FW_TEST_CMD message to WMA"); + return -EINVAL; + } + return 0; +} + +/** + * __iw_set_three_ints_getnone() - Generic "set 3 params" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + uint8_t dual_mac_feature = DISABLE_DBS_CXN_AND_SCAN; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + + hdd_enter_dev(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + switch (sub_cmd) { + + case WE_SET_WLAN_DBG: + qdf_print_set_category_verbose(qdf_get_pidx(), value[1], + value[2], value[3]); + break; + case WE_SET_DP_TRACE: + qdf_dp_trace_set_value(value[1], value[2], value[3]); + break; + + case WE_SET_DUAL_MAC_SCAN_CONFIG: + hdd_debug("Ioctl to set dual mac scan config"); + status = + ucfg_policy_mgr_get_dual_mac_feature(hdd_ctx->psoc, + &dual_mac_feature); + if (status != QDF_STATUS_SUCCESS) + hdd_err("can't get dual mac feature val, use def"); + if (dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d %d", value[1], value[2], value[3]); + policy_mgr_set_dual_mac_scan_config(hdd_ctx->psoc, + value[1], value[2], value[3]); + break; + case WE_SET_FW_TEST: + { + ret = hdd_set_fwtest(value[1], value[2], value[3]); + if (ret) { + hdd_err("Not able to set fwtest %d", ret); + return ret; + } + } + break; + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + + } + hdd_exit(); + return ret; +} + +/** + * iw_set_three_ints_getnone() - Generic "set 3 params" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +int iw_set_three_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_three_ints_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_connection_state_string() - Get connection state string + * @connection_state: enum to be converted to a string + * + * Return: the string equivalent of @connection_state + */ +static const char * +hdd_connection_state_string(eConnectionState connection_state) +{ + switch (connection_state) { + CASE_RETURN_STRING(eConnectionState_NotConnected); + CASE_RETURN_STRING(eConnectionState_NdiDisconnected); + CASE_RETURN_STRING(eConnectionState_NdiConnected); + default: + return "UNKNOWN"; + } +} + +#if defined(FEATURE_OEM_DATA_SUPPORT) +/** + * iw_get_oem_data_cap_wrapper() - wrapper function to call legacy or new + * wifi_pos api to get oem data caps + * @dev: net device upon which the request was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl data payload + * + * Return: 0 for success, negative errno value on failure + */ +static inline int iw_get_oem_data_cap_wrapper(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return iw_get_oem_data_cap(dev, info, wrqu, extra); +} +#elif defined(WIFI_POS_CONVERGED) +static inline int iw_get_oem_data_cap_wrapper(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + return os_if_wifi_pos_populate_caps(hdd_ctx->psoc, + (struct wifi_pos_driver_caps *)extra); +} +#else +static inline int iw_get_oem_data_cap_wrapper(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + return -ENOTSUPP; +} +#endif + +#ifdef WLAN_UNIT_TEST +static int hdd_get_sta_cxn_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + char *extra) +{ + QDF_STATUS status; + + status = sme_get_sta_cxn_info(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, + extra, WE_MAX_STR_LEN); + if (status != QDF_STATUS_SUCCESS) + qdf_scnprintf(extra, WE_MAX_STR_LEN, + "\nNo active connection"); + + return 0; +} +#else +static int hdd_get_sta_cxn_info(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + char *extra) +{ + qdf_scnprintf(extra, WE_MAX_STR_LEN, + "\nNot supported"); + return -ENOTSUPP; +} +#endif + +/** + * __iw_get_char_setnone() - Generic "get string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int sub_cmd = wrqu->data.flags; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + int ret; + QDF_STATUS status; + uint8_t value; + struct wlan_hdd_link_info *link_info = adapter->deflink; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + switch (sub_cmd) { + case WE_WLAN_VERSION: + { + wrqu->data.length = hdd_wlan_get_version(hdd_ctx, + WE_MAX_STR_LEN, extra); + break; + } + + case WE_GET_STATS: + { + hdd_wlan_get_stats(link_info, &wrqu->data.length, + extra, WE_MAX_STR_LEN); + break; + } + + case WE_GET_SUSPEND_RESUME_STATS: + { + ret = wlan_hdd_write_suspend_resume_stats(hdd_ctx, extra, + WE_MAX_STR_LEN); + if (ret >= 0) { + wrqu->data.length = ret; + ret = 0; + } + + break; + } + + case WE_LIST_FW_PROFILE: + hdd_wlan_list_fw_profile(&(wrqu->data.length), + extra, WE_MAX_STR_LEN); + break; + + /* The case prints the current state of the HDD, SME, CSR, PE, + * TL it can be extended for WDI Global State as well. And + * currently it only checks P2P_CLIENT adapter. P2P_DEVICE + * and P2P_GO have not been added as of now. + */ + case WE_GET_STATES: + { + int buf = 0, len = 0; + int adapter_num = 0; + int count = 0, check = 1; + uint8_t stat_vdev_id; + struct hdd_station_ctx *sta_ctx = NULL; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + struct hdd_adapter *stat_adapter = NULL; + struct wlan_hdd_link_info *stat_link_info; + + /* Print wlan0 or p2p0 states based on the adapter_num + * by using the correct adapter + */ + while (adapter_num < 2) { + if (WLAN_ADAPTER == adapter_num) { + stat_adapter = adapter; + buf = scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n\n wlan0 States:-"); + len += buf; + } else if (P2P_ADAPTER == adapter_num) { + buf = scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n\n p2p0 States:-"); + len += buf; + + if (!hdd_ctx) { + buf = scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n hdd_ctx is NULL"); + len += buf; + break; + } + + /* Printing p2p0 states only in the + * case when the device is configured + * as a p2p_client + */ + stat_adapter = + hdd_get_adapter(hdd_ctx, + QDF_P2P_CLIENT_MODE); + if (!stat_adapter) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n Device not configured as P2P_CLIENT."); + len += buf; + break; + } + } + + if (!mac_handle) { + buf = scnprintf(extra + len, + WE_MAX_STR_LEN - len, + "\n mac_handle is NULL"); + len += buf; + break; + } + stat_link_info = stat_adapter->deflink; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(stat_link_info); + + stat_vdev_id = stat_link_info->vdev_id; + buf = scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n HDD Conn State - %s \n\n SME State:\n CSR State - %s\n CSR Substate - %s", + hdd_connection_state_string + (sta_ctx->conn_info.conn_state), + mac_trace_getcsr_roam_state + (sme_get_current_roam_state + (mac_handle, stat_vdev_id)), + mac_trace_getcsr_roam_sub_state + (sme_get_current_roam_sub_state + (mac_handle, stat_vdev_id)) + ); + len += buf; + adapter_num++; + } + + if (mac_handle) { + /* Printing Lim State starting with global lim states */ + buf = + scnprintf(extra + len, WE_MAX_STR_LEN - len, + "\n\n LIM STATES:-" + "\n Global Sme State - %s " + "\n Global mlm State - %s " "\n", + mac_trace_get_lim_sme_state + (sme_get_lim_sme_state(mac_handle)), + mac_trace_get_lim_mlm_state + (sme_get_lim_mlm_state(mac_handle)) + ); + len += buf; + + while (check < 3 && count < 255) { + if (sme_is_lim_session_valid(mac_handle, count)) { + buf = + scnprintf(extra + len, + WE_MAX_STR_LEN - + len, + "\n Lim Valid Session %d:-" + "\n PE Sme State - %s " + "\n PE Mlm State - %s " + "\n", check, + mac_trace_get_lim_sme_state + (sme_get_lim_sme_session_state + (mac_handle, count)), + mac_trace_get_lim_mlm_state + (sme_get_lim_mlm_session_state + (mac_handle, count)) + ); + + len += buf; + check++; + } + count++; + } + } + + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_CFG: + { + hdd_debug("Printing CLD global INI Config"); + hdd_cfg_get_global_config(WLAN_HDD_GET_CTX(adapter), + extra, + QCSAP_IOCTL_MAX_STR_LEN); + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_RSSI: + { + int8_t s7Rssi = 0; + + wlan_hdd_get_rssi(link_info, &s7Rssi); + snprintf(extra, WE_MAX_STR_LEN, "rssi=%d", s7Rssi); + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_WMM_STATUS: + { + snprintf(extra, WE_MAX_STR_LEN, + "\nDir: 0=up, 1=down, 3=both\n" + "|------------------------|\n" + "|AC | ACM |Admitted| Dir |\n" + "|------------------------|\n" + "|VO | %d | %3s | %d |\n" + "|VI | %d | %3s | %d |\n" + "|BE | %d | %3s | %d |\n" + "|BK | %d | %3s | %d |\n" + "|------------------------|\n", + adapter->hdd_wmm_status. + ac_status[SME_AC_VO].is_access_required, + adapter->hdd_wmm_status. + ac_status[SME_AC_VO]. + is_access_allowed ? "YES" : "NO", + adapter->hdd_wmm_status. + ac_status[SME_AC_VO].tspec. + ts_info.direction, + adapter->hdd_wmm_status. + ac_status[SME_AC_VI].is_access_required, + adapter->hdd_wmm_status. + ac_status[SME_AC_VI]. + is_access_allowed ? "YES" : "NO", + adapter->hdd_wmm_status. + ac_status[SME_AC_VI].tspec. + ts_info.direction, + adapter->hdd_wmm_status. + ac_status[SME_AC_BE].is_access_required, + adapter->hdd_wmm_status. + ac_status[SME_AC_BE]. + is_access_allowed ? "YES" : "NO", + adapter->hdd_wmm_status. + ac_status[SME_AC_BE].tspec. + ts_info.direction, + adapter->hdd_wmm_status. + ac_status[SME_AC_BK].is_access_required, + adapter->hdd_wmm_status. + ac_status[SME_AC_BK]. + is_access_allowed ? "YES" : "NO", + adapter->hdd_wmm_status. + ac_status[SME_AC_BK].tspec. + ts_info.direction); + + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_BA_AGEING_TIMEOUT: + { + uint32_t i; + enum qca_wlan_ac_type duration[QCA_WLAN_AC_ALL]; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) + break; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) + cdp_get_ba_timeout(soc, i, &duration[i]); + + snprintf(extra, WE_MAX_STR_LEN, + "\n|------------------------------|\n" + "|AC | BA aging timeout duration |\n" + "|--------------------------------|\n" + "|VO | %d |\n" + "|VI | %d |\n" + "|BK | %d |\n" + "|BE | %d |\n" + "|--------------------------------|\n", + duration[QCA_WLAN_AC_VO], duration[QCA_WLAN_AC_VI], + duration[QCA_WLAN_AC_BK], duration[QCA_WLAN_AC_BE]); + + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_CHANNEL_LIST: + { + if (0 != + iw_get_channel_list_with_cc(dev, mac_handle, + info, wrqu, extra)) + return -EINVAL; + break; + } +#ifdef FEATURE_WLAN_TDLS + case WE_GET_TDLS_PEERS: + { + wrqu->data.length = + wlan_hdd_tdls_get_all_peers(adapter, extra, + WE_MAX_STR_LEN) + 1; + break; + } +#endif + case WE_GET_11W_INFO: + { + struct qdf_mac_addr connected_bssid; + + wlan_mlme_get_bssid_vdev_id(hdd_ctx->pdev, + link_info->vdev_id, + &connected_bssid); + snprintf(extra, WE_MAX_STR_LEN, + "\n BSSID %02X:%02X:%02X:%02X:%02X:%02X" + "\n Number of Unprotected Disassocs %d" + "\n Number of Unprotected Deauths %d", + connected_bssid.bytes[0], + connected_bssid.bytes[1], + connected_bssid.bytes[2], + connected_bssid.bytes[3], + connected_bssid.bytes[4], + connected_bssid.bytes[5], + link_info->hdd_stats.hdd_pmf_stats. + num_unprot_disassoc_rx, + link_info->hdd_stats.hdd_pmf_stats. + num_unprot_deauth_rx); + + wrqu->data.length = strlen(extra) + 1; + break; + } + case WE_GET_PHYMODE: + { + bool ch_bond24 = false, ch_bond5g = false; + struct hdd_context *hddctx = WLAN_HDD_GET_CTX(adapter); + eCsrPhyMode phymode; + enum band_info current_band; + struct sme_config_params *sme_config; + + sme_config = qdf_mem_malloc(sizeof(*sme_config)); + if (!sme_config) { + ret = -ENOMEM; + break; + } + + sme_get_config_param(mac_handle, sme_config); + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_config->csr_config.channelBondingMode24GHz) + ch_bond24 = true; + + if (WNI_CFG_CHANNEL_BONDING_MODE_DISABLE != + sme_config->csr_config.channelBondingMode5GHz) + ch_bond5g = true; + + qdf_mem_free(sme_config); + + phymode = sme_get_phy_mode(mac_handle); + if ((QDF_STATUS_SUCCESS != + ucfg_reg_get_band(hddctx->pdev, ¤t_band))) { + hdd_err("Failed to get current band config"); + return -EIO; + } + + switch (phymode) { + case eCSR_DOT11_MODE_AUTO: + snprintf(extra, WE_MAX_STR_LEN, "AUTO MODE"); + break; + case eCSR_DOT11_MODE_11n: + case eCSR_DOT11_MODE_11n_ONLY: + if (current_band == BAND_2G) { + if (ch_bond24) + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NGHT20"); + } else if (current_band == BAND_5G) { + if (ch_bond5g) + snprintf(extra, WE_MAX_STR_LEN, + "11NAHT40"); + else + snprintf(extra, WE_MAX_STR_LEN, + "11NAHT20"); + } else { + snprintf(extra, WE_MAX_STR_LEN, "11N"); + } + break; + case eCSR_DOT11_MODE_abg: + snprintf(extra, WE_MAX_STR_LEN, "11ABG"); + break; + case eCSR_DOT11_MODE_11a: + snprintf(extra, WE_MAX_STR_LEN, "11A"); + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + snprintf(extra, WE_MAX_STR_LEN, "11B"); + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + snprintf(extra, WE_MAX_STR_LEN, "11G"); + break; + case eCSR_DOT11_MODE_11ac: + case eCSR_DOT11_MODE_11ac_ONLY: + status = + ucfg_mlme_get_vht_channel_width(hddctx->psoc, + &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set channel_width"); + if (value == eHT_CHANNEL_WIDTH_20MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT20"); + else if (value == eHT_CHANNEL_WIDTH_40MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT40"); + else if (value == eHT_CHANNEL_WIDTH_80MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT80"); + else if (value == eHT_CHANNEL_WIDTH_160MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11ACVHT160"); + break; + case eCSR_DOT11_MODE_11ax: + case eCSR_DOT11_MODE_11ax_ONLY: + status = + ucfg_mlme_get_vht_channel_width(hddctx->psoc, + &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_err("Failed to set channel_width"); + + /* currently using vhtChannelWidth */ + if (value == eHT_CHANNEL_WIDTH_20MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_20"); + else if (value == eHT_CHANNEL_WIDTH_40MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_40"); + else if (value == eHT_CHANNEL_WIDTH_80MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_80"); + else if (value == eHT_CHANNEL_WIDTH_160MHZ) + snprintf(extra, WE_MAX_STR_LEN, + "11AX_HE_160"); + break; + default: + break; + } + + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_OEM_DATA_CAP: + return iw_get_oem_data_cap_wrapper(dev, info, wrqu, extra); + case WE_GET_SNR: + { + int8_t s7snr = 0; + int status = 0; + bool enable_snr_monitoring; + struct hdd_context *hdd_ctx; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + status = wlan_hdd_validate_context(hdd_ctx); + if (status) + return status; + + enable_snr_monitoring = + ucfg_scan_is_snr_monitor_enabled(hdd_ctx->psoc); + if (!enable_snr_monitoring || + !hdd_cm_is_vdev_associated(link_info)) { + hdd_err("getSNR failed: Enable SNR Monitoring-%d", + enable_snr_monitoring); + return -ENONET; + } + wlan_hdd_get_snr(link_info, &s7snr); + snprintf(extra, WE_MAX_STR_LEN, "snr=%d", s7snr); + wrqu->data.length = strlen(extra) + 1; + break; + } + + case WE_GET_STA_CXN_INFO: + ret = hdd_get_sta_cxn_info(hdd_ctx, adapter, extra); + wrqu->data.length = strlen(extra) + 1; + break; + + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + } + + hdd_exit(); + return ret; +} + +/** + * iw_get_char_setnone() - Generic "get string" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_get_char_setnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_char_setnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_setnone_getnone() - Generic "action" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + int ret; + int sub_cmd; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + +#ifdef CONFIG_COMPAT + /* this ioctl is a special case where a sub-ioctl is used and both + * the number of get and set args is 0. in this specific case the + * logic in iwpriv places the sub_cmd in the data.flags portion of + * the iwreq. unfortunately the location of this field will be + * different between 32-bit and 64-bit userspace, and the standard + * compat support in the kernel does not handle this case. so we + * need to explicitly handle it here. + */ + if (in_compat_syscall()) { + struct compat_iw_point *compat_iw_point = + (struct compat_iw_point *)&wrqu->data; + sub_cmd = compat_iw_point->flags; + } else { + sub_cmd = wrqu->data.flags; + } +#else + sub_cmd = wrqu->data.flags; +#endif + + mac_handle = hdd_ctx->mac_handle; + switch (sub_cmd) { + case WE_GET_FW_PROFILE_DATA: + ret = wma_cli_set_command( + adapter->deflink->vdev_id, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, DBG_CMD); + break; + + case WE_SET_REASSOC_TRIGGER: + { + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + qdf_freq_t chan_freq = + wlan_get_operation_chan_freq(adapter->deflink->vdev); + struct qdf_mac_addr target_bssid; + + wlan_mlme_get_bssid_vdev_id(hdd_ctx->pdev, + adapter->deflink->vdev_id, + &target_bssid); + ucfg_wlan_cm_roam_invoke(hdd_ctx->pdev, + adapter->deflink->vdev_id, + &target_bssid, chan_freq, + CM_ROAMING_USER); + return 0; + } + + case WE_STOP_OBSS_SCAN: + /* + * 1.OBSS Scan is mandatory while operating in 2.4GHz + * 2.OBSS scan is stopped by Firmware during the disassociation + * 3.OBSS stop command is added for debugging purpose + */ + if (!mac_handle) { + hdd_err("mac_handle context is NULL"); + return -EINVAL; + } + sme_ht40_stop_obss_scan(mac_handle, adapter->deflink->vdev_id); + break; + + default: + hdd_err("unknown ioctl %d", sub_cmd); + break; + } + hdd_exit(); + return ret; +} + +/** + * iw_setnone_getnone() - Generic "action" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_setnone_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_setnone_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * hdd_ch_avoid_unit_cmd - unit test ch avoidance + * @hdd_ctx: hdd_context + * @num_args: input args number + * @apps_args: args data ptr + * + * This is to inject a ch avoid event to do unit test SAP chan avoidance. + * + * Return: void + */ +#ifdef WLAN_DEBUG +static void hdd_ch_avoid_unit_cmd(struct hdd_context *hdd_ctx, + int num_args, int *apps_args) +{ + struct ch_avoid_ind_type ch_avoid; + int cnt = 0, i; + + if (num_args < 2 || num_args > CH_AVOID_MAX_RANGE * 2 || + num_args % 2 != 0) + return; + hdd_info("simulate ch avoid num_args %d", num_args); + for (i = 0; i < num_args && i < CH_AVOID_MAX_RANGE * 2; i++) { + ch_avoid.avoid_freq_range[cnt].start_freq = + apps_args[i]; + ch_avoid.avoid_freq_range[cnt].end_freq = + apps_args[++i]; + + hdd_info("simulate ch avoid [%d %d]", + ch_avoid.avoid_freq_range[cnt].start_freq, + ch_avoid.avoid_freq_range[cnt].end_freq); + cnt++; + } + ch_avoid.ch_avoid_range_cnt = cnt; + ucfg_reg_unit_simulate_ch_avoid(hdd_ctx->psoc, &ch_avoid); +} +#else +static void hdd_ch_avoid_unit_cmd(struct hdd_context *hdd_ctx, + int num_args, int *apps_args) +{ +} +#endif + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +/** + * hdd_send_thermal_mgmt_cmd - Send thermal management params + * @mac_handle: Opaque handle to the global MAC context + * @lower_thresh_deg: Lower threshold value of Temperature + * @higher_thresh_deg: Higher threshold value of Temperature + * + * Return: QDF_STATUS + */ +#ifndef QCN7605_SUPPORT +static QDF_STATUS hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle, + uint16_t lower_thresh_deg, + uint16_t higher_thresh_deg) +{ + return sme_set_thermal_mgmt(mac_handle, lower_thresh_deg, + higher_thresh_deg); +} +#else +static QDF_STATUS hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle, + uint16_t lower_thresh_deg, + uint16_t higher_thresh_deg) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + +/** + * __iw_set_var_ints_getnone - Generic "set many" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This is an SSR-protected generic handler for private ioctls which + * take multiple arguments. Note that this implementation is also + * somewhat unique in that it is shared by both STA-mode and SAP-mode + * interfaces. + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + mac_handle_t mac_handle; + struct hdd_station_ctx *sta_ctx; + int sub_cmd; + int *apps_args = (int *) extra; + struct hdd_context *hdd_ctx; + int ret, num_args; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct cdp_txrx_stats_req req = {0}; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + mac_handle = hdd_ctx->mac_handle; + sub_cmd = wrqu->data.flags; + num_args = wrqu->data.length; + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + + hdd_debug("Received length %d", wrqu->data.length); + + switch (sub_cmd) { + case WE_P2P_NOA_CMD: + { + struct p2p_app_set_ps p2p_noa; + + if (adapter->device_mode != QDF_P2P_GO_MODE) { + hdd_err("Setting NoA is not allowed in Device mode %s(%d)", + qdf_opmode_str(adapter->device_mode), + adapter->device_mode); + return -EINVAL; + } + + p2p_noa.opp_ps = apps_args[0]; + p2p_noa.ct_window = apps_args[1]; + p2p_noa.duration = apps_args[2]; + p2p_noa.interval = apps_args[3]; + p2p_noa.count = apps_args[4]; + p2p_noa.single_noa_duration = apps_args[5]; + p2p_noa.ps_selection = apps_args[6]; + + hdd_debug("P2P_NOA_ATTR:opp ps %d ct window %d duration %d interval %d count %d single noa duration %d ps selection %x", + apps_args[0], apps_args[1], apps_args[2], + apps_args[3], apps_args[4], + apps_args[5], apps_args[6]); + + hdd_set_p2p_ps(dev, &p2p_noa); + + } + break; + + case WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD: + { + hdd_debug("SELECTIVE_MODULE_LOG %d arg1 %d arg2", + apps_args[0], apps_args[1]); + qdf_trace_enable(apps_args[0], apps_args[1]); + } + break; + + case WE_MTRACE_DUMP_CMD: + { + hdd_debug("MTRACE_DUMP code %d session %d count %d bitmask_of_module %d ", + apps_args[0], apps_args[1], + apps_args[2], apps_args[3]); + qdf_trace_dump_all((void *)mac_handle, apps_args[0], + apps_args[1], apps_args[2], + apps_args[3]); + + } + break; + + case WE_POLICY_MANAGER_CINFO_CMD: + { + struct policy_mgr_conc_connection_info *conn_info; + uint32_t i = 0, len = 0; + + hdd_info(" is called"); + conn_info = policy_mgr_get_conn_info(&len); + pr_info("+--------------------------+\n"); + for (i = 0; i < len; i++) { + if (!conn_info->in_use) + continue; + + pr_info("|table_index[%d]\t\t\n", i); + pr_info("|\t|vdev_id - %-10d|\n", conn_info->vdev_id); + pr_info("|\t|freq - %-10d|\n", conn_info->freq); + pr_info("|\t|bw - %-10d|\n", conn_info->bw); + pr_info("|\t|mode - %-10d|\n", conn_info->mode); + pr_info("|\t|mac_id - %-10d|\n", conn_info->mac); + pr_info("|\t|in_use - %-10d|\n", conn_info->in_use); + pr_info("+--------------------------+\n"); + conn_info++; + } + + pr_info("|\t|current state dbs - %-10d, sbs - %-10d|\n", + policy_mgr_is_current_hwmode_dbs(hdd_ctx->psoc), + policy_mgr_is_current_hwmode_sbs(hdd_ctx->psoc)); + } + break; + + case WE_UNIT_TEST_CMD: + { + QDF_STATUS status; + uint8_t vdev_id = 0; + + if ((apps_args[0] < WLAN_MODULE_ID_MIN) || + (apps_args[0] >= WLAN_MODULE_ID_MAX)) { + hdd_err_rl("Invalid MODULE ID %d", apps_args[0]); + return -EINVAL; + } + if (apps_args[1] > WMI_UNIT_TEST_MAX_NUM_ARGS || + apps_args[1] < 0) { + hdd_err_rl("Too Many/Few args %d", apps_args[1]); + return -EINVAL; + } + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) + vdev_id = 0; + else + vdev_id = adapter->deflink->vdev_id; + + if (vdev_id >= WLAN_MAX_VDEVS) { + hdd_err_rl("Invalid vdev id %d", vdev_id); + return -EINVAL; + } + + status = sme_send_unit_test_cmd(vdev_id, + apps_args[0], + apps_args[1], + &apps_args[2]); + if (QDF_STATUS_SUCCESS != status) { + hdd_err("sme_send_unit_test_cmd returned %d", status); + return -EINVAL; + } + } + break; +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + case WE_LED_FLASHING_PARAM: + { + int i; + + if (num_args != 4) { + hdd_err("gpio_control: 4 parameters are required"); + return -EINVAL; + } + for (i = 0; i < num_args; i++) { + if (apps_args[i] >= 0x7fffffff) { + hdd_err("gpio_control: parameter should be less than 0x7fffffff"); + return -EINVAL; + } + } + sme_set_led_flashing(mac_handle, + 0, apps_args[0], apps_args[1]); + sme_set_led_flashing(mac_handle, + 1, apps_args[2], apps_args[3]); + } + break; +#endif + case WE_SET_PKTLOG: + { + int ret; + + if (num_args < 1 || num_args > 2) { + hdd_err("pktlog: either 1 or 2 parameters are required"); + return -EINVAL; + } + + ret = hdd_process_pktlog_command(hdd_ctx, apps_args[0], + apps_args[1]); + if (ret) + return ret; + break; + } + case WE_MAC_PWR_DEBUG_CMD: + { + struct sir_mac_pwr_dbg_cmd mac_pwr_dbg_args; + int i, j; + + if (num_args < 3) { + hdd_err("number of arguments can't be null %d", + num_args); + return -EINVAL; + } + if (num_args - 3 != apps_args[2]) { + hdd_err("arg list of size %d doesn't match num_args %d", + num_args-3, apps_args[2]); + return -EINVAL; + } + if ((apps_args[1] < WLAN_MODULE_ID_MIN) || + (apps_args[1] >= WLAN_MODULE_ID_MAX)) { + hdd_err("Invalid MODULE ID %d", apps_args[1]); + return -EINVAL; + } + if (apps_args[2] > (MAX_POWER_DBG_ARGS_SUPPORTED)) { + hdd_err("Too Many args %d", apps_args[2]); + return -EINVAL; + } + mac_pwr_dbg_args.pdev_id = apps_args[0]; + mac_pwr_dbg_args.module_id = apps_args[1]; + mac_pwr_dbg_args.num_args = apps_args[2]; + + for (i = 0, j = 3; i < mac_pwr_dbg_args.num_args; i++, j++) + mac_pwr_dbg_args.args[i] = apps_args[j]; + + if (QDF_STATUS_SUCCESS != + sme_process_mac_pwr_dbg_cmd(mac_handle, + adapter->deflink->vdev_id, + &mac_pwr_dbg_args)) { + return -EINVAL; + } + } + break; + case WE_SET_CHAN_AVOID: + { + hdd_ch_avoid_unit_cmd(hdd_ctx, num_args, apps_args); + } + break; + case WE_SET_TXRX_STATS: + { + req.stats = apps_args[0]; + /* default value of secondary parameter is 0(mac_id) */ + req.mac_id = apps_args[1]; + + hdd_debug("WE_SET_TXRX_STATS stats cmd: %d mac_id: %d", + req.stats, req.mac_id); + if (qdf_unlikely(!soc)) { + hdd_err("soc is NULL"); + return -EINVAL; + } + + if (apps_args[0] == CDP_TXRX_STATS_28) { + if (sta_ctx->conn_info.is_authenticated) { + hdd_debug("ap mac addr: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_ctx->conn_info.bssid.bytes)); + req.peer_addr = + (char *)&sta_ctx->conn_info.bssid; + } + } + ret = cdp_txrx_stats_request(soc, adapter->deflink->vdev_id, + &req); + break; + } +#ifdef WLAN_FEATURE_MOTION_DETECTION + case WE_MOTION_DET_CONFIG_PARAM: + { + struct sme_motion_det_cfg motion_det_cfg; + + if (num_args != 15) { + hdd_err_rl("mt_config: Invalid no of args"); + return -EINVAL; + } + + motion_det_cfg.vdev_id = adapter->deflink->vdev_id; + motion_det_cfg.time_t1 = apps_args[0]; + motion_det_cfg.time_t2 = apps_args[1]; + motion_det_cfg.n1 = apps_args[2]; + motion_det_cfg.n2 = apps_args[3]; + motion_det_cfg.time_t1_gap = apps_args[4]; + motion_det_cfg.time_t2_gap = apps_args[5]; + motion_det_cfg.coarse_K = apps_args[6]; + motion_det_cfg.fine_K = apps_args[7]; + motion_det_cfg.coarse_Q = apps_args[8]; + motion_det_cfg.fine_Q = apps_args[9]; + motion_det_cfg.md_coarse_thr_high = apps_args[10]; + motion_det_cfg.md_fine_thr_high = apps_args[11]; + motion_det_cfg.md_coarse_thr_low = apps_args[12]; + motion_det_cfg.md_fine_thr_low = apps_args[13]; + adapter->motion_detection_mode = apps_args[14]; + sme_motion_det_config(hdd_ctx->mac_handle, &motion_det_cfg); + adapter->motion_det_cfg = true; + } + break; + case WE_MOTION_DET_BASE_LINE_CONFIG_PARAM: + { + struct sme_motion_det_base_line_cfg motion_det_base_line_cfg; + + if (num_args != 4) { + hdd_err_rl("mt_bl_config: Invalid no of args"); + return -EINVAL; + } + + motion_det_base_line_cfg.vdev_id = adapter->deflink->vdev_id; + motion_det_base_line_cfg.bl_time_t = apps_args[0]; + motion_det_base_line_cfg.bl_packet_gap = apps_args[1]; + motion_det_base_line_cfg.bl_n = apps_args[2]; + motion_det_base_line_cfg.bl_num_meas = apps_args[3]; + sme_motion_det_base_line_config(hdd_ctx->mac_handle, + &motion_det_base_line_cfg); + } + break; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ +#ifdef FW_THERMAL_THROTTLE_SUPPORT + case WE_SET_THERMAL_THROTTLE_CFG: + { + QDF_STATUS status; + struct thermal_mitigation_params therm_cfg_params; + struct wlan_fwol_thermal_temp thermal_temp = {0}; + if (num_args != 7) { + hdd_err_rl("set_thermal_cfg: Invalid no of args"); + return -EINVAL; + } + status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, + &thermal_temp); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err_rl("Failed to get fwol thermal obj"); + return qdf_status_to_os_return(status); + } + + /* Check for valid inputs */ + if (apps_args[0] < 0 || apps_args[0] > 1 || apps_args[1] < 0 || + apps_args[2] < 0 || apps_args[2] > 100 || + apps_args[3] < 0 || apps_args[3] > 3 || apps_args[4] < 0 || + apps_args[5] < 0 || apps_args[6] < 0 || + apps_args[5] <= apps_args[4]) + return -EINVAL; + + therm_cfg_params.enable = apps_args[0]; + therm_cfg_params.dc = apps_args[1]; + therm_cfg_params.levelconf[0].dcoffpercent = apps_args[2]; + therm_cfg_params.levelconf[0].priority = apps_args[3]; + therm_cfg_params.levelconf[0].tmplwm = apps_args[6]; + hdd_thermal_fill_clientid_priority(hdd_ctx, + THERMAL_MONITOR_APPS, + thermal_temp.priority_apps, + thermal_temp.priority_wpps, + &therm_cfg_params); + therm_cfg_params.num_thermal_conf = 1; + status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle, + &therm_cfg_params); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + if (!apps_args[6]) { + status = hdd_send_thermal_mgmt_cmd(hdd_ctx->mac_handle, + apps_args[4], + apps_args[5]); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + } + break; + } +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + default: + { + hdd_err("Invalid IOCTL command %d", sub_cmd); + } + break; + } + hdd_exit(); + return 0; +} + +/** + * iw_hdd_set_var_ints_getnone() - set var ints getnone callback + * @dev: pointer to net_device structure + * @info: pointer to iw_request_info structure + * @wrqu: pointer to iwreq_data + * @extra: extra + * + * Return: 0 on success, error number otherwise + * + */ +static int iw_hdd_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + union iwreq_data u_priv_wrqu; + int apps_args[MAX_VAR_ARGS] = {0}; + int errno, num_args; + struct osif_vdev_sync *vdev_sync; + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + /* Helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&u_priv_wrqu.data, wrqu)) + return -EINVAL; + + if (!u_priv_wrqu.data.pointer) { + hdd_err("NULL data pointer"); + return -EINVAL; + } + + num_args = u_priv_wrqu.data.length; + if (num_args > MAX_VAR_ARGS) + num_args = MAX_VAR_ARGS; + + if (copy_from_user(apps_args, u_priv_wrqu.data.pointer, + sizeof(int) * num_args)) { + hdd_err("failed to copy data from user buffer"); + return -EFAULT; + } + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_var_ints_getnone(dev, info, &u_priv_wrqu, + (char *)&apps_args); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * iw_set_var_ints_getnone - Generic "set many" private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This is a generic handler for private ioctls which take multiple + * arguments. Note that this implementation is also somewhat unique + * in that it is shared by both STA-mode and SAP-mode interfaces. + * + * Return: 0 on success, non-zero on error + */ +int iw_set_var_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_var_ints_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_add_tspec - Add TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_add_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + hdd_wlan_wmm_status_e *wmm_status = (hdd_wlan_wmm_status_e *) extra; + int params[HDD_WLAN_WMM_PARAM_COUNT]; + struct sme_qos_wmmtspecinfo tspec; + uint32_t handle; + struct iw_point s_priv_data; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* make sure the application is sufficiently privileged */ + /* note that the kernel will do this for "set" ioctls, but since */ + /* this ioctl wants to return status to user space it must be */ + /* defined as a "get" ioctl */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* we must be associated in order to add a tspec */ + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* since we are defined to be a "get" ioctl, and since the number */ + /* of params exceeds the number of params that wireless extensions */ + /* will pass down in the iwreq_data, we must copy the "set" params. */ + /* We must handle the compat for iwreq_data in 32U/64K environment. */ + + /* helper function to get iwreq_data with compat handling. */ + if (hdd_priv_get_data(&s_priv_data, wrqu)) { + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* make sure all params are correctly passed to function */ + if ((!s_priv_data.pointer) || + (HDD_WLAN_WMM_PARAM_COUNT != s_priv_data.length)) { + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* from user space ourselves */ + if (copy_from_user(¶ms, s_priv_data.pointer, sizeof(params))) { + /* hmmm, can't get them */ + return -EIO; + } + /* clear the tspec */ + memset(&tspec, 0, sizeof(tspec)); + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + /* validate the TID */ + if (params[HDD_WLAN_WMM_PARAM_TID] > 7) { + /* out of range */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + tspec.ts_info.tid = params[HDD_WLAN_WMM_PARAM_TID]; + + /* validate the direction */ + switch (params[HDD_WLAN_WMM_PARAM_DIRECTION]) { + case HDD_WLAN_WMM_DIRECTION_UPSTREAM: + tspec.ts_info.direction = SME_QOS_WMM_TS_DIR_UPLINK; + break; + + case HDD_WLAN_WMM_DIRECTION_DOWNSTREAM: + tspec.ts_info.direction = SME_QOS_WMM_TS_DIR_DOWNLINK; + break; + + case HDD_WLAN_WMM_DIRECTION_BIDIRECTIONAL: + tspec.ts_info.direction = SME_QOS_WMM_TS_DIR_BOTH; + break; + + default: + /* unknown */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + tspec.ts_info.psb = params[HDD_WLAN_WMM_PARAM_APSD]; + + /* validate the user priority */ + if (params[HDD_WLAN_WMM_PARAM_USER_PRIORITY] >= SME_QOS_WMM_UP_MAX) { + /* out of range */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + tspec.ts_info.up = params[HDD_WLAN_WMM_PARAM_USER_PRIORITY]; + if (0 > tspec.ts_info.up || SME_QOS_WMM_UP_MAX < tspec.ts_info.up) { + hdd_err("***ts_info.up out of bounds***"); + return 0; + } + + hdd_debug("TS_INFO PSB %d UP %d !!!", + tspec.ts_info.psb, tspec.ts_info.up); + + tspec.nominal_msdu_size = params[HDD_WLAN_WMM_PARAM_NOMINAL_MSDU_SIZE]; + tspec.maximum_msdu_size = params[HDD_WLAN_WMM_PARAM_MAXIMUM_MSDU_SIZE]; + tspec.min_data_rate = params[HDD_WLAN_WMM_PARAM_MINIMUM_DATA_RATE]; + tspec.mean_data_rate = params[HDD_WLAN_WMM_PARAM_MEAN_DATA_RATE]; + tspec.peak_data_rate = params[HDD_WLAN_WMM_PARAM_PEAK_DATA_RATE]; + tspec.max_burst_size = params[HDD_WLAN_WMM_PARAM_MAX_BURST_SIZE]; + tspec.min_phy_rate = params[HDD_WLAN_WMM_PARAM_MINIMUM_PHY_RATE]; + tspec.surplus_bw_allowance = + params[HDD_WLAN_WMM_PARAM_SURPLUS_BANDWIDTH_ALLOWANCE]; + tspec.min_service_interval = + params[HDD_WLAN_WMM_PARAM_SERVICE_INTERVAL]; + tspec.max_service_interval = + params[HDD_WLAN_WMM_PARAM_MAX_SERVICE_INTERVAL]; + tspec.suspension_interval = + params[HDD_WLAN_WMM_PARAM_SUSPENSION_INTERVAL]; + tspec.inactivity_interval = + params[HDD_WLAN_WMM_PARAM_INACTIVITY_INTERVAL]; + + tspec.ts_info.burst_size_defn = + params[HDD_WLAN_WMM_PARAM_BURST_SIZE_DEFN]; + + /* validate the ts info ack policy */ + switch (params[HDD_WLAN_WMM_PARAM_ACK_POLICY]) { + case TS_INFO_ACK_POLICY_NORMAL_ACK: + tspec.ts_info.ack_policy = SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *wmm_status = hdd_wmm_addts(adapter, handle, &tspec); + hdd_exit(); + return 0; +} + +/** + * iw_add_tspec - Add TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_add_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_add_tspec(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_del_tspec - Delete TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_del_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int *params = (int *)extra; + hdd_wlan_wmm_status_e *wmm_status = (hdd_wlan_wmm_status_e *) extra; + uint32_t handle; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* make sure the application is sufficiently privileged */ + /* note that the kernel will do this for "set" ioctls, but since */ + /* this ioctl wants to return status to user space it must be */ + /* defined as a "get" ioctl */ + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + /* although we are defined to be a "get" ioctl, the params we require */ + /* will fit in the iwreq_data, therefore unlike iw_add_tspec() there */ + /* is no need to copy the params from user space */ + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *wmm_status = hdd_wmm_delts(adapter, handle); + hdd_exit(); + return 0; +} + +/** + * iw_del_tspec - Delete TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_del_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_del_tspec(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_get_tspec - Get TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_get_tspec(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int *params = (int *)extra; + hdd_wlan_wmm_status_e *wmm_status = (hdd_wlan_wmm_status_e *) extra; + uint32_t handle; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + /* although we are defined to be a "get" ioctl, the params we require */ + /* will fit in the iwreq_data, therefore unlike iw_add_tspec() there */ + /* is no need to copy the params from user space */ + + /* validate the handle */ + handle = params[HDD_WLAN_WMM_PARAM_HANDLE]; + if (HDD_WMM_HANDLE_IMPLICIT == handle) { + /* that one is reserved */ + *wmm_status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + return 0; + } + + *wmm_status = hdd_wmm_checkts(adapter, handle); + hdd_exit(); + return 0; +} + +/** + * iw_get_tspec - Get TSpec private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_get_tspec(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_get_tspec(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_set_fties - Set FT IEs private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Each time the supplicant has the auth_request or reassoc request + * IEs ready they are pushed to the driver. The driver will in turn + * use it to send out the auth req and reassoc req for 11r FT Assoc. + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_fties(struct net_device *dev, struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (!wrqu->data.length) { + hdd_err("called with 0 length IEs"); + return -EINVAL; + } + if (!wrqu->data.pointer) { + hdd_err("called with NULL IE"); + return -EINVAL; + } + /* Added for debug on reception of Re-assoc Req. */ + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_debug("Called with Ie of length = %d when not associated", + wrqu->data.length); + hdd_debug("Should be Re-assoc Req IEs"); + } + hdd_debug("called with Ie of length = %d", wrqu->data.length); + + /* Pass the received FT IEs to SME */ + ucfg_cm_set_ft_ies(hdd_ctx->pdev, adapter->deflink->vdev_id, + extra, wrqu->data.length); + hdd_exit(); + return 0; +} + +/** + * iw_set_fties - Set FT IEs private ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Each time the supplicant has the auth_request or reassoc request + * IEs ready they are pushed to the driver. The driver will in turn + * use it to send out the auth req and reassoc req for 11r FT Assoc. + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_fties(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_fties(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * iw_set_dynamic_mcbc_filter() - Set Dynamic MCBC Filter ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This IOCTL is OBSOLETE as of Jan 30, 2017. We are leaving it here for the + * time being to provide guidance in migrating to standard APIs. + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_dynamic_mcbc_filter(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + hdd_err("\n" + "setMCBCFilter is obsolete. Use the following instead:\n" + "Configure multicast filtering via the ‘ip’ command.\n" + "\tip maddr add 11:22:33:44:55:66 dev wlan0 # allow traffic to address\n" + "\tip maddr del 11:22:33:44:55:66 dev wlan0 # undo allow\n" + "Configure broadcast filtering via ini item, 'g_enable_non_arp_bc_hw_filter.'\n" + "\tg_enable_non_arp_bc_hw_filter=1 # drop all non-ARP broadcast traffic\n" + "\tg_enable_non_arp_bc_hw_filter=0 # allow all broadcast traffic"); + return -EINVAL; +} + +/** + * __iw_set_host_offload - Set host offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct host_offload_req *user_request = + (struct host_offload_req *) extra; + struct sir_host_offload_req offload_request; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("dev is not in CONNECTED state, ignore!!!"); + return -EINVAL; + } + + /* Debug display of request components. */ + switch (user_request->offloadType) { + case WLAN_IPV4_ARP_REPLY_OFFLOAD: + hdd_debug("Host offload request: ARP reply"); + switch (user_request->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hdd_debug(" disable"); + break; + case WLAN_OFFLOAD_ARP_AND_BC_FILTER_ENABLE: + hdd_debug(" BC Filtering enable"); + fallthrough; + case WLAN_OFFLOAD_ENABLE: + hdd_debug(" ARP offload enable"); + hdd_debug(" IP address: %pI4", + user_request->params.hostIpv4Addr); + } + break; + + case WLAN_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD: + hdd_debug("Host offload request: neighbor discovery"); + switch (user_request->enableOrDisable) { + case WLAN_OFFLOAD_DISABLE: + hdd_debug(" disable"); + break; + case WLAN_OFFLOAD_ENABLE: + hdd_debug(" enable"); + hdd_debug(" IP address: %pI6c", + user_request->params.hostIpv6Addr); + } + } + + qdf_mem_zero(&offload_request, sizeof(offload_request)); + offload_request.offloadType = user_request->offloadType; + offload_request.enableOrDisable = user_request->enableOrDisable; + qdf_mem_copy(&offload_request.params, &user_request->params, + sizeof(user_request->params)); + qdf_mem_copy(&offload_request.bssid, &user_request->bssId.bytes, + QDF_MAC_ADDR_SIZE); + + if (QDF_STATUS_SUCCESS != + sme_set_host_offload(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, &offload_request)) { + hdd_err("Failure to execute host offload request"); + return -EINVAL; + } + hdd_exit(); + return 0; +} + +/** + * iw_set_host_offload - Set host offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_host_offload(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_host_offload(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __iw_set_keepalive_params - Set keepalive params ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct keep_alive_req *request = (struct keep_alive_req *)extra; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (wrqu->data.length != sizeof(*request)) { + hdd_err("Invalid length %d", wrqu->data.length); + return -EINVAL; + } + + if (request->timePeriod > cfg_max(CFG_INFRA_STA_KEEP_ALIVE_PERIOD)) { + hdd_err("Value of timePeriod %d exceed Max limit %d", + request->timePeriod, + cfg_max(CFG_INFRA_STA_KEEP_ALIVE_PERIOD)); + return -EINVAL; + } + + /* Debug display of request components. */ + hdd_debug("Set Keep Alive Request : TimePeriod %d size %zu", + request->timePeriod, sizeof(struct keep_alive_req)); + + switch (request->packetType) { + case WLAN_KEEP_ALIVE_NULL_PKT: + hdd_debug("Keep Alive Request: Tx NULL"); + break; + + case WLAN_KEEP_ALIVE_UNSOLICIT_ARP_RSP: + hdd_debug("Keep Alive Request: Tx UnSolicited ARP RSP"); + + hdd_debug("Host IP address: %d.%d.%d.%d", + request->hostIpv4Addr[0], request->hostIpv4Addr[1], + request->hostIpv4Addr[2], request->hostIpv4Addr[3]); + + hdd_debug("Dest IP address: %d.%d.%d.%d", + request->destIpv4Addr[0], request->destIpv4Addr[1], + request->destIpv4Addr[2], request->destIpv4Addr[3]); + + hdd_debug("Dest MAC address: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(request->dest_macaddr.bytes)); + break; + } + + hdd_debug("Keep alive period %d", request->timePeriod); + + if (QDF_STATUS_SUCCESS != + sme_set_keep_alive(hdd_ctx->mac_handle, + adapter->deflink->vdev_id, request)) { + hdd_err("Failure to execute Keep Alive"); + return -EINVAL; + } + hdd_exit(); + return 0; +} + +/** + * iw_set_keepalive_params - Set keepalive params ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_keepalive_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_keepalive_params(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +/** + * validate_packet_filter_params_size() - Validate the size of the params rcvd + * @request: Pointer to the struct containing the copied data from user space + * @length: length of the request + * + * Return: False on invalid length, true otherwise + */ +static bool validate_packet_filter_params_size(struct pkt_filter_cfg *request, + uint16_t length) +{ + int max_params_size, rcvd_params_size; + + max_params_size = HDD_MAX_CMP_PER_PACKET_FILTER * + sizeof(struct pkt_filter_param_cfg); + + if (length < sizeof(struct pkt_filter_cfg) - max_params_size) { + hdd_err("Less than minimum number of arguments needed"); + return false; + } + + rcvd_params_size = request->num_params * + sizeof(struct pkt_filter_param_cfg); + + if (length != sizeof(struct pkt_filter_cfg) - + max_params_size + rcvd_params_size) { + hdd_err("Arguments do not match the number of params provided"); + return false; + } + + return true; +} + +/** + * __iw_set_packet_filter_params() - set packet filter parameters in target + * @dev: Pointer to netdev + * @info: Pointer to iw request info + * @wrqu: Pointer to data + * @extra: Pointer to extra data + * + * Return: 0 on success, non-zero on error + */ +static int __iw_set_packet_filter_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + struct hdd_context *hdd_ctx; + struct iw_point priv_data; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct pkt_filter_cfg *request = NULL; + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + if (hdd_priv_get_data(&priv_data, wrqu)) { + hdd_err("failed to get priv data"); + return -EINVAL; + } + + if ((!priv_data.pointer) || (0 == priv_data.length)) { + hdd_err("invalid priv data %pK or invalid priv data length %d", + priv_data.pointer, priv_data.length); + return -EINVAL; + } + + if (adapter->device_mode != QDF_STA_MODE) { + hdd_err("Packet filter not supported for this mode :%d", + adapter->device_mode); + return -ENOTSUPP; + } + + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + hdd_err("Packet filter not supported in disconnected state"); + return -ENOTSUPP; + } + + /* copy data using copy_from_user */ + request = mem_alloc_copy_from_user_helper(priv_data.pointer, + priv_data.length); + + if (!request) { + hdd_err("mem_alloc_copy_from_user_helper fail"); + return -ENOMEM; + } + + if (!validate_packet_filter_params_size(request, priv_data.length)) { + hdd_err("Invalid priv data length %d", priv_data.length); + qdf_mem_free(request); + return -EINVAL; + } + + if (request->filter_action == HDD_RCV_FILTER_SET) + hdd_ctx->user_configured_pkt_filter_rules |= + 1 << request->filter_id; + else if (request->filter_action == HDD_RCV_FILTER_CLEAR) + hdd_ctx->user_configured_pkt_filter_rules &= + ~(1 << request->filter_id); + + ret = wlan_hdd_set_filter(hdd_ctx, request, adapter->deflink->vdev_id); + + qdf_mem_free(request); + hdd_exit(); + return ret; +} + +/** + * iw_set_packet_filter_params() - set packet filter parameters in target + * @dev: Pointer to netdev + * @info: Pointer to iw request info + * @wrqu: Pointer to data + * @extra: Pointer to extra data + * + * Return: 0 on success, non-zero on error + */ +static int iw_set_packet_filter_params(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_packet_filter_params(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif + +static int hdd_get_wlan_stats(struct hdd_adapter *adapter) +{ + int stats = wlan_hdd_get_station_stats(adapter->deflink); + + wlan_hdd_get_peer_rx_rate_stats(adapter->deflink); + + return stats; +} + +static int __iw_get_statistics(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int ret; + char *p; + int tlen; + struct hdd_station_ctx *sta_ctx; + tCsrSummaryStatsInfo *summary_stats; + tCsrGlobalClassAStatsInfo *class_a_stats; + tCsrGlobalClassDStatsInfo *class_d_stats; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + sta_ctx = WLAN_HDD_GET_STATION_CTX_PTR(adapter->deflink); + if (!hdd_cm_is_vdev_associated(adapter->deflink)) { + wrqu->data.length = 0; + return 0; + } + + hdd_get_wlan_stats(adapter); + + summary_stats = &adapter->deflink->hdd_stats.summary_stat; + class_a_stats = &adapter->deflink->hdd_stats.class_a_stat; + class_d_stats = &adapter->deflink->hdd_stats.class_d_stat; + + p = extra; + tlen = 0; + + FILL_TLV(p, WLAN_STATS_RETRY_CNT, + sizeof(summary_stats->retry_cnt), + &(summary_stats->retry_cnt[0]), tlen); + + FILL_TLV(p, WLAN_STATS_MUL_RETRY_CNT, + sizeof(summary_stats->multiple_retry_cnt), + &(summary_stats->multiple_retry_cnt[0]), tlen); + + FILL_TLV(p, WLAN_STATS_TX_FRM_CNT, + sizeof(summary_stats->tx_frm_cnt), + &(summary_stats->tx_frm_cnt[0]), tlen); + + FILL_TLV(p, WLAN_STATS_RX_FRM_CNT, + sizeof(summary_stats->rx_frm_cnt), + &(summary_stats->rx_frm_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_FRM_DUP_CNT, + sizeof(summary_stats->frm_dup_cnt), + &(summary_stats->frm_dup_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_FAIL_CNT, + sizeof(summary_stats->fail_cnt), + &(summary_stats->fail_cnt[0]), tlen); + + FILL_TLV(p, WLAN_STATS_RTS_FAIL_CNT, + sizeof(summary_stats->rts_fail_cnt), + &(summary_stats->rts_fail_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_ACK_FAIL_CNT, + sizeof(summary_stats->ack_fail_cnt), + &(summary_stats->ack_fail_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_RTS_SUC_CNT, + sizeof(summary_stats->rts_succ_cnt), + &(summary_stats->rts_succ_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_RX_DISCARD_CNT, + sizeof(summary_stats->rx_discard_cnt), + &(summary_stats->rx_discard_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_RX_ERROR_CNT, + sizeof(summary_stats->rx_error_cnt), + &(summary_stats->rx_error_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_TX_BYTE_CNT, + sizeof(class_d_stats->tx_uc_byte_cnt[0]), + &(class_d_stats->tx_uc_byte_cnt[0]), tlen); + + FILL_TLV(p, WLAN_STATS_RX_BYTE_CNT, + sizeof(class_d_stats->rx_byte_cnt), + &(class_d_stats->rx_byte_cnt), tlen); + + FILL_TLV(p, WLAN_STATS_RX_RATE, + sizeof(class_d_stats->rx_rate), + &(class_d_stats->rx_rate), tlen); + + /* Transmit rate, in units of 500 kbit/sec */ + FILL_TLV(p, WLAN_STATS_TX_RATE, + sizeof(class_a_stats->tx_rate), + &(class_a_stats->tx_rate), tlen); + + FILL_TLV(p, WLAN_STATS_RX_UC_BYTE_CNT, + sizeof(class_d_stats->rx_uc_byte_cnt[0]), + &(class_d_stats->rx_uc_byte_cnt[0]), tlen); + FILL_TLV(p, WLAN_STATS_RX_MC_BYTE_CNT, + sizeof(class_d_stats->rx_mc_byte_cnt), + &(class_d_stats->rx_mc_byte_cnt), tlen); + FILL_TLV(p, WLAN_STATS_RX_BC_BYTE_CNT, + sizeof(class_d_stats->rx_bc_byte_cnt), + &(class_d_stats->rx_bc_byte_cnt), tlen); + FILL_TLV(p, WLAN_STATS_TX_UC_BYTE_CNT, + sizeof(class_d_stats->tx_uc_byte_cnt[0]), + &(class_d_stats->tx_uc_byte_cnt[0]), tlen); + FILL_TLV(p, WLAN_STATS_TX_MC_BYTE_CNT, + sizeof(class_d_stats->tx_mc_byte_cnt), + &(class_d_stats->tx_mc_byte_cnt), tlen); + FILL_TLV(p, WLAN_STATS_TX_BC_BYTE_CNT, + sizeof(class_d_stats->tx_bc_byte_cnt), + &(class_d_stats->tx_bc_byte_cnt), tlen); + + wrqu->data.length = tlen; + + hdd_exit(); + + return 0; +} + +static int iw_get_statistics(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_qmi_get_sync_resume(); + if (errno) { + hdd_err("qmi sync resume failed: %d", errno); + goto end; + } + + errno = __iw_get_statistics(dev, info, wrqu, extra); + + wlan_hdd_qmi_put_suspend(); + +end: + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#ifdef FEATURE_WLAN_SCAN_PNO +/*Max Len for PNO notification*/ +#define MAX_PNO_NOTIFY_LEN 100 +static void found_pref_network_cb(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *args) +{ + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + union iwreq_data wrqu; + char buf[MAX_PNO_NOTIFY_LEN + 1]; + + wlan_vdev_obj_lock(vdev); + osif_priv = wlan_vdev_get_ospriv(vdev); + wlan_vdev_obj_unlock(vdev); + if (!osif_priv) { + hdd_err("osif_priv is null"); + return; + } + + wdev = osif_priv->wdev; + if (!wdev) { + hdd_err("wdev is null"); + return; + } + + hdd_debug("A preferred network was found"); + + /* create the event */ + qdf_mem_zero(&wrqu, sizeof(wrqu)); + qdf_mem_zero(buf, sizeof(buf)); + + snprintf(buf, MAX_PNO_NOTIFY_LEN, + "QCOM: Found preferred network:"); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* send the event */ + + hdd_wext_send_event(wdev->netdev, IWEVCUSTOM, &wrqu, buf); +} + +/** + * __iw_set_pno() - Preferred Network Offload ioctl handler + * @dev: device upon which the ioctl was received + * @info: ioctl request information + * @wrqu: ioctl request data + * @extra: ioctl extra data + * + * This function parses a Preferred Network Offload command + * Input is string based and expected to be of the form: + * + * + * when enabling: + * + * for each network: + * + * + * + * + * + * + * e.g: + * 1 2 4 test 0 0 3 1 6 11 2 40 5 test2 4 4 6 1 2 3 4 5 6 1 0 5 2 1 + * + * this translates into: + * ----------------------------- + * enable PNO + * 2 networks + * Network 1: + * test - with authentication type 0 and encryption type 0, + * search on 3 channels: 1 6 and 11, + * SSID bcast type is unknown (directed probe will be sent if + * AP not found) and must meet -40dBm RSSI + * Network 2: + * test2 - with authentication type 4 and encryption type 4, + * search on 6 channels 1, 2, 3, 4, 5 and 6 + * bcast type is non-bcast (directed probe will be sent) + * and must not meet any RSSI threshold + * scan every 5 seconds 2 times + * enable on suspend + */ +static int __iw_set_pno(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + uint8_t value; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + int ret = 0; + int offset; + char *ptr, *data; + uint8_t i, j, params; + QDF_STATUS status; + size_t len; + + /* request is a large struct, so we make it static to avoid + * stack overflow. This API is only invoked via ioctl, so it + * is serialized by the kernel rtnl_lock and hence does not + * need to be reentrant + */ + static struct pno_scan_req_params req; + + hdd_enter_dev(dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(hdd_ctx->pdev, + dev->dev_addr, + WLAN_OSIF_SCAN_ID); + if (!vdev) { + hdd_err("vdev object is NULL"); + return -EIO; + } + + /* making sure argument string ends with '\0' */ + len = (wrqu->data.length + 1); + data = qdf_mem_malloc(len); + if (!data) { + ret = -EINVAL; + goto exit; + } + + qdf_mem_copy(data, extra, (len-1)); + ptr = data; + + hdd_debug("PNO data len %d data %s", wrqu->data.length, data); + + if (1 != sscanf(ptr, " %hhu %n", &value, &offset)) { + hdd_err("PNO enable input is not valid %s", ptr); + ret = -EINVAL; + goto exit; + } + + if (!value) { + status = ucfg_scan_pno_stop(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to disabled PNO"); + ret = -EINVAL; + } else { + hdd_debug("PNO scan disabled"); + } + goto exit; + } + + if (ucfg_scan_get_pno_in_progress(vdev)) { + hdd_debug("pno is already in progress"); + ret = -EBUSY; + goto exit; + } + + ptr += offset; + + if (1 != sscanf(ptr, " %hhu %n", &value, &offset)) { + hdd_err("PNO count input not valid %s", ptr); + ret = -EINVAL; + goto exit; + } + req.networks_cnt = value; + + hdd_debug("PNO enable networks count %d offset %d", + req.networks_cnt, offset); + + if ((0 == req.networks_cnt) || + (req.networks_cnt > SCAN_PNO_MAX_SUPP_NETWORKS)) { + hdd_err("Network count %d invalid", + req.networks_cnt); + ret = -EINVAL; + goto exit; + } + + ptr += offset; + + for (i = 0; i < req.networks_cnt; i++) { + + req.networks_list[i].ssid.length = 0; + + params = sscanf(ptr, " %hhu %n", + &(req.networks_list[i].ssid.length), + &offset); + + if (1 != params) { + hdd_err("PNO ssid length input is not valid %s", ptr); + ret = -EINVAL; + goto exit; + } + + if ((0 == req.networks_list[i].ssid.length) || + (req.networks_list[i].ssid.length > 32)) { + hdd_err("SSID Len %d is not correct for network %d", + req.networks_list[i].ssid.length, i); + ret = -EINVAL; + goto exit; + } + + /* Advance to SSID */ + ptr += offset; + + memcpy(req.networks_list[i].ssid.ssid, ptr, + req.networks_list[i].ssid.length); + ptr += req.networks_list[i].ssid.length; + + params = sscanf(ptr, " %u %u %hhu %n", + &(req.networks_list[i].authentication), + &(req.networks_list[i].encryption), + &(req.networks_list[i].pno_chan_list.num_chan), + &offset); + + if (3 != params) { + hdd_err("Incorrect cmd %s", ptr); + ret = -EINVAL; + goto exit; + } + + hdd_debug("PNO ssid " QDF_SSID_FMT " auth %d encry %d channel count %d offset %d", + QDF_SSID_REF(req.networks_list[i].ssid.length, + req.networks_list[i].ssid.ssid), + req.networks_list[i].authentication, + req.networks_list[i].encryption, + req.networks_list[i].pno_chan_list.num_chan, offset); + + /* Advance to channel list */ + ptr += offset; + + if (SCAN_PNO_MAX_NETW_CHANNELS_EX < + req.networks_list[i].pno_chan_list.num_chan) { + hdd_err("Incorrect number of channels"); + ret = -EINVAL; + goto exit; + } + + if (0 != req.networks_list[i].pno_chan_list.num_chan) { + for (j = 0; + j < req.networks_list[i].pno_chan_list.num_chan; + j++) { + if (1 != sscanf(ptr, " %hhu %n", &value, + &offset)) { + hdd_err("PNO network channel is not valid %s", + ptr); + ret = -EINVAL; + goto exit; + } + if (!IS_CHANNEL_VALID(value)) { + hdd_err("invalid channel: %hhu", value); + ret = -EINVAL; + goto exit; + } + req.networks_list[i].pno_chan_list.chan[j].freq = + cds_chan_to_freq(value); + /* Advance to next channel number */ + ptr += offset; + } + } + + if (1 != sscanf(ptr, " %u %n", + &(req.networks_list[i].bc_new_type), + &offset)) { + hdd_err("PNO broadcast network type is not valid %s", + ptr); + ret = -EINVAL; + goto exit; + } + if (req.networks_list[i].bc_new_type > 2) { + hdd_err("invalid bcast nw type: %u", + req.networks_list[i].bc_new_type); + ret = -EINVAL; + goto exit; + } + + hdd_debug("PNO bcastNetwType %d offset %d", + req.networks_list[i].bc_new_type, offset); + + /* Advance to rssi Threshold */ + ptr += offset; + if (1 != sscanf(ptr, " %d %n", + &(req.networks_list[i].rssi_thresh), + &offset)) { + hdd_err("PNO rssi threshold input is not valid %s", + ptr); + ret = -EINVAL; + goto exit; + } + hdd_debug("PNO rssi %d offset %d", + req.networks_list[i].rssi_thresh, offset); + /* Advance to next network */ + ptr += offset; + } /* For ucNetworkCount */ + + req.fast_scan_period = 0; + if (sscanf(ptr, " %u %n", &(req.fast_scan_period), &offset) > 0) { + req.fast_scan_period *= MSEC_PER_SEC; + ptr += offset; + } + if (req.fast_scan_period == 0) { + hdd_err("invalid fast scan period %u", + req.fast_scan_period); + ret = -EINVAL; + goto exit; + } + + req.fast_scan_max_cycles = 0; + if (sscanf(ptr, " %hhu %n", &value, + &offset) > 0) + ptr += offset; + req.fast_scan_max_cycles = value; + + wlan_pdev_obj_lock(hdd_ctx->pdev); + psoc = wlan_pdev_get_psoc(hdd_ctx->pdev); + wlan_pdev_obj_unlock(hdd_ctx->pdev); + ucfg_scan_register_pno_cb(psoc, + found_pref_network_cb, NULL); + + ucfg_scan_get_pno_def_params(vdev, &req); + status = ucfg_scan_pno_start(vdev, &req); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to enable PNO"); + ret = -EINVAL; + } + +exit: + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_SCAN_ID); + + qdf_mem_free(data); + return ret; +} + +static int iw_set_pno(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_pno(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +static int __iw_set_band_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct hdd_context *hdd_ctx; + int ret; + int *value = (int *)extra; + + hdd_enter_dev(dev); + + if (!capable(CAP_NET_ADMIN)) { + hdd_err("permission check failed"); + return -EPERM; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + return hdd_reg_set_band(dev, value[0]); +} + +static int iw_set_band_config(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_band_config(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + + + +#ifdef CONFIG_DP_TRACE +void hdd_set_dump_dp_trace(uint16_t cmd_type, uint16_t count) +{ + hdd_debug("WE_DUMP_DP_TRACE_LEVEL: %d %d", + cmd_type, count); + if (cmd_type == DUMP_DP_TRACE) + qdf_dp_trace_dump_all(count, QDF_TRACE_DEFAULT_PDEV_ID); + else if (cmd_type == ENABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_enable_live_mode(); + else if (cmd_type == CLEAR_DP_TRACE_BUFFER) + qdf_dp_trace_clear_buffer(); + else if (cmd_type == DISABLE_DP_TRACE_LIVE_MODE) + qdf_dp_trace_disable_live_mode(); +} +#endif + +static int __iw_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + int *value = (int *)extra; + int sub_cmd = value[0]; + int ret; + uint8_t dual_mac_feature = DISABLE_DBS_CXN_AND_SCAN; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + + hdd_enter_dev(dev); + + ret = wlan_hdd_validate_context(hdd_ctx); + if (0 != ret) + return ret; + + ret = hdd_check_private_wext_control(hdd_ctx, info); + if (0 != ret) + return ret; + + switch (sub_cmd) { + case WE_SET_SMPS_PARAM: + hdd_debug("WE_SET_SMPS_PARAM val %d %d", value[1], value[2]); + ret = wma_cli_set_command(adapter->deflink->vdev_id, + WMI_STA_SMPS_PARAM_CMDID, + value[1] << WMA_SMPS_PARAM_VALUE_S + | value[2], + VDEV_CMD); + break; + case WE_SET_FW_CRASH_INJECT: + ret = hdd_crash_inject(adapter, value[1], value[2]); + break; + case WE_ENABLE_FW_PROFILE: + hdd_err("WE_ENABLE_FW_PROFILE: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command( + adapter->deflink->vdev_id, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + value[1], value[2], DBG_CMD); + break; + case WE_SET_FW_PROFILE_HIST_INTVL: + hdd_err("WE_SET_FW_PROFILE_HIST_INTVL: %d %d", + value[1], value[2]); + ret = wma_cli_set2_command( + adapter->deflink->vdev_id, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + value[1], value[2], DBG_CMD); + break; + case WE_SET_DUAL_MAC_FW_MODE_CONFIG: + hdd_debug("Ioctl to set dual fw mode config"); + status = + ucfg_policy_mgr_get_dual_mac_feature(hdd_ctx->psoc, + &dual_mac_feature); + if (status != QDF_STATUS_SUCCESS) + hdd_err("can't get dual mac feature val, use def"); + if (dual_mac_feature == DISABLE_DBS_CXN_AND_SCAN) { + hdd_err("Dual mac feature is disabled from INI"); + return -EPERM; + } + hdd_debug("%d %d", value[1], value[2]); + policy_mgr_set_dual_mac_fw_mode_config(hdd_ctx->psoc, + value[1], value[2]); + break; + case WE_DUMP_DP_TRACE_LEVEL: + hdd_set_dump_dp_trace(value[1], value[2]); + break; + case WE_SET_MON_MODE_CHAN: + if (value[1] > 256) + ret = wlan_hdd_set_mon_chan(adapter, value[1], + value[2]); + else + ret = wlan_hdd_set_mon_chan( + adapter, + wlan_reg_legacy_chan_to_freq( + hdd_ctx->pdev, value[1]), + value[2]); + break; + case WE_SET_WLAN_SUSPEND: + ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy, dev, + value[1], value[2]); + break; + case WE_SET_WLAN_RESUME: + ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy, dev); + break; + case WE_LOG_BUFFER: { + int log_id = value[1]; + uint32_t count = value[2] < 0 ? 0 : value[2]; + + hdd_ioctl_log_buffer(log_id, count, NULL, NULL); + + break; + } + case WE_SET_BA_AGEING_TIMEOUT: + { + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) + break; + + cdp_set_ba_timeout(soc, value[1], value[2]); + break; + } + default: + hdd_err("Invalid IOCTL command %d", sub_cmd); + break; + } + + return ret; +} + +static int iw_set_two_ints_getnone(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(dev, &vdev_sync); + if (errno) + return errno; + + errno = __iw_set_two_ints_getnone(dev, info, wrqu, extra); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/* Define the Wireless Extensions to the Linux Network Device structure */ + +static const iw_handler we_private[] = { + + [WLAN_PRIV_SET_INT_GET_NONE - SIOCIWFIRSTPRIV] = iw_setint_getnone, + [WLAN_PRIV_SET_NONE_GET_INT - SIOCIWFIRSTPRIV] = iw_setnone_getint, + [WLAN_PRIV_SET_CHAR_GET_NONE - SIOCIWFIRSTPRIV] = iw_setchar_getnone, + [WLAN_PRIV_SET_THREE_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_set_three_ints_getnone, + [WLAN_PRIV_GET_CHAR_SET_NONE - SIOCIWFIRSTPRIV] = iw_get_char_setnone, + [WLAN_PRIV_SET_NONE_GET_NONE - SIOCIWFIRSTPRIV] = iw_setnone_getnone, + [WLAN_PRIV_SET_VAR_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_hdd_set_var_ints_getnone, + [WLAN_PRIV_SET_NONE_GET_THREE_INT - SIOCIWFIRSTPRIV] = + iw_setnone_get_threeint, +#ifdef WLAN_FEATURE_FIPS + [WLAN_PRIV_FIPS_TEST - SIOCIWFIRSTPRIV] = hdd_fips_test, +#endif + [WLAN_PRIV_ADD_TSPEC - SIOCIWFIRSTPRIV] = iw_add_tspec, + [WLAN_PRIV_DEL_TSPEC - SIOCIWFIRSTPRIV] = iw_del_tspec, + [WLAN_PRIV_GET_TSPEC - SIOCIWFIRSTPRIV] = iw_get_tspec, + [WLAN_PRIV_SET_FTIES - SIOCIWFIRSTPRIV] = iw_set_fties, + [WLAN_PRIV_SET_HOST_OFFLOAD - SIOCIWFIRSTPRIV] = iw_set_host_offload, + [WLAN_GET_WLAN_STATISTICS - SIOCIWFIRSTPRIV] = iw_get_statistics, + [WLAN_SET_KEEPALIVE_PARAMS - SIOCIWFIRSTPRIV] = + iw_set_keepalive_params, +#ifdef WLAN_FEATURE_PACKET_FILTERING + [WLAN_SET_PACKET_FILTER_PARAMS - SIOCIWFIRSTPRIV] = + iw_set_packet_filter_params, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + [WLAN_SET_PNO - SIOCIWFIRSTPRIV] = iw_set_pno, +#endif + [WLAN_SET_BAND_CONFIG - SIOCIWFIRSTPRIV] = iw_set_band_config, + [WLAN_PRIV_SET_MCBC_FILTER - SIOCIWFIRSTPRIV] = + iw_set_dynamic_mcbc_filter, + [WLAN_GET_LINK_SPEED - SIOCIWFIRSTPRIV] = iw_get_linkspeed, +#ifdef FEATURE_WLM_STATS + [WLAN_GET_WLM_STATS - SIOCIWFIRSTPRIV] = iw_get_wlm_stats, +#endif + [WLAN_PRIV_SET_TWO_INT_GET_NONE - SIOCIWFIRSTPRIV] = + iw_set_two_ints_getnone, + [WLAN_SET_DOT11P_CHANNEL_SCHED - SIOCIWFIRSTPRIV] = + iw_set_dot11p_channel_sched, +}; + +/*Maximum command length can be only 15 */ +static const struct iw_priv_args we_private_args[] = { + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_SET_11D_STATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11Dstate"}, + + {WE_WOWL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "wowl"}, + + {WE_SET_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setPower"}, + + {WE_SET_MAX_ASSOC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMaxAssoc"}, + + {WE_SET_SCAN_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "scan_disable"}, + + {WE_SET_DATA_INACTIVITY_TO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "inactivityTO"}, + + {WE_SET_WOW_DATA_INACTIVITY_TO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "wow_ito"}, + + {WE_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMaxTxPower"}, + + {WE_SET_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxPower"}, + + {WE_SET_MC_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setMcRate"}, + + {WE_SET_MAX_TX_POWER_2_4, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower2G"}, + + {WE_SET_MAX_TX_POWER_5_0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower5G"}, + +#ifndef REMOVE_PKT_LOG + {WE_SET_PKTLOG, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pktlog"}, +#endif + + /* SAP has TxMax whereas STA has MaxTx, adding TxMax for STA + * as well to keep same syntax as in SAP. Now onwards, STA + * will support both + */ + {WE_SET_MAX_TX_POWER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTxMaxPower"}, + +#ifdef HASTINGS_BT_WAR + {WE_SET_HASTINGS_BT_WAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "hastings_bt_war"}, +#endif + + {WE_SET_TM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setTmLevel"}, + + {WE_SET_PHYMODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "setphymode"}, + + {WE_SET_NSS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "nss"}, + + {WE_SET_LDPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "ldpc"}, + + {WE_SET_TX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "tx_stbc"}, + + {WE_SET_RX_STBC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "rx_stbc"}, + + {WE_SET_SHORT_GI, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "shortgi"}, + + {WE_SET_RTSCTS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "enablertscts"}, + + {WE_SET_CHWIDTH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "chwidth"}, + + {WE_SET_ANI_EN_DIS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "anienable"}, + + {WE_SET_ANI_POLL_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniplen"}, + + {WE_SET_ANI_LISTEN_PERIOD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "anilislen"}, + + {WE_SET_ANI_OFDM_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniofdmlvl"}, + + {WE_SET_ANI_CCK_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "aniccklvl"}, + + {WE_SET_DYNAMIC_BW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "cwmenable"}, + + {WE_SET_CTS_CBW, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "cts_cbw" }, + + {WE_SET_GTX_HT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxHTMcs"}, + + {WE_SET_GTX_VHT_MCS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxVHTMcs"}, + + {WE_SET_GTX_USRCFG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxUsrCfg"}, + + {WE_SET_GTX_THRE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxThre"}, + + {WE_SET_GTX_MARGIN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxMargin"}, + + {WE_SET_GTX_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxStep"}, + + {WE_SET_GTX_MINTPC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxMinTpc"}, + + {WE_SET_GTX_BWMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "gtxBWMask"}, + + {WE_SET_TX_CHAINMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txchainmask"}, + + {WE_SET_RX_CHAINMASK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "rxchainmask"}, + + {WE_SET_11N_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11NRates"}, + + {WE_SET_VHT_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set11ACRates"}, + + {WE_SET_AMPDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "ampdu"}, + + {WE_SET_AMSDU, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "amsdu"}, + + {WE_SET_TXPOW_2G, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txpow2g"}, + + {WE_SET_TXPOW_5G, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txpow5g"}, + +#ifdef FEATURE_FW_LOG_PARSING + /* Sub-cmds DBGLOG specific commands */ + {WE_DBGLOG_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_loglevel"}, + + {WE_DBGLOG_VAP_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_vapon"}, + + {WE_DBGLOG_VAP_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_vapoff"}, + + {WE_DBGLOG_MODULE_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_modon"}, + + {WE_DBGLOG_MODULE_DISABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_modoff"}, + + {WE_DBGLOG_MOD_LOG_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_mod_loglevel"}, + + {WE_DBGLOG_TYPE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_type"}, + + {WE_DBGLOG_REPORT_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "dl_report"}, +#endif /* FEATURE_FW_LOG_PARSING */ + + {WE_SET_TXRX_FWSTATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txrx_fw_stats"}, + + {WE_SET_TXRX_STATS, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "txrx_stats"}, +#ifdef FW_THERMAL_THROTTLE_SUPPORT + {WE_SET_THERMAL_THROTTLE_CFG, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "set_thermal_cfg"}, +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + {WE_SET_BTCOEX_MODE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_btc_mode" }, + {WE_SET_BTCOEX_RSSI_THRESHOLD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_btc_rssi" }, + {WE_TXRX_FWSTATS_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "txrx_fw_st_rst"}, + + {WE_PPS_PAID_MATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "paid_match"}, + + {WE_PPS_GID_MATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "gid_match"}, + + {WE_PPS_EARLY_TIM_CLEAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "tim_clear"}, + + {WE_PPS_EARLY_DTIM_CLEAR, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dtim_clear"}, + + {WE_PPS_EOF_PAD_DELIM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "eof_delim"}, + + {WE_PPS_MACADDR_MISMATCH, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "mac_match"}, + + {WE_PPS_DELIM_CRC_FAIL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "delim_fail"}, + + {WE_PPS_GID_NSTS_ZERO, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "nsts_zero"}, + + {WE_PPS_RSSI_CHECK, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "rssi_chk"}, + + {WE_PPS_5G_EBT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "5g_ebt"}, + + {WE_SET_HTSMPS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "htsmps"}, + + {WE_SET_QPOWER_MAX_PSPOLL_COUNT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qpspollcnt"}, + + {WE_SET_QPOWER_MAX_TX_BEFORE_WAKE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qtxwake"}, + + {WE_SET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qwakeintv"}, + + {WE_SET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "set_qnodatapoll"}, + + /* handlers for MCC time quota and latency sub ioctls */ + {WE_MCC_CONFIG_LATENCY, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setMccLatency"}, + + {WE_MCC_CONFIG_QUOTA, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setMccQuota"}, + + {WE_SET_DEBUG_LOG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setDbgLvl"}, + + /* handlers for early_rx power save */ + {WE_SET_EARLY_RX_ADJUST_ENABLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_enable"}, + + {WE_SET_EARLY_RX_TGT_BMISS_NUM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_bmiss_val"}, + + {WE_SET_EARLY_RX_BMISS_SAMPLE_CYCLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_bmiss_smpl"}, + + {WE_SET_EARLY_RX_SLOP_STEP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_slop_step"}, + + {WE_SET_EARLY_RX_INIT_SLOP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_init_slop"}, + + {WE_SET_EARLY_RX_ADJUST_PAUSE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_adj_pause"}, + + {WE_SET_EARLY_RX_DRIFT_SAMPLE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "erx_dri_sample"}, + + {WE_DUMP_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "dumpStats"}, + + {WE_CLEAR_STATS, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "clearStats"}, + + {WE_START_FW_PROFILE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "startProfile"}, + + {WE_SET_CHANNEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setChanChange" }, + + {WE_SET_CONC_SYSTEM_PREF, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setConcSysPref" }, + + {WE_SET_PDEV_RESET, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "pdev_reset" }, + + {WE_SET_MODULATED_DTIM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, "setModDTIM" }, + + {WLAN_PRIV_SET_NONE_GET_INT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + ""}, + + /* handlers for sub-ioctl */ + {WE_GET_11D_STATE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get11Dstate"}, + + {WE_GET_WLAN_DBG, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getwlandbg"}, + + {WE_GET_MAX_ASSOC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getMaxAssoc"}, + + {WE_GET_SAP_AUTO_CHANNEL_SELECTION, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getAutoChannel"}, + + {WE_GET_CONCURRENCY_MODE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getconcurrency"}, + + {WE_GET_NSS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nss"}, + + {WE_GET_LDPC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ldpc"}, + + {WE_GET_TX_STBC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tx_stbc"}, + + {WE_GET_RX_STBC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rx_stbc"}, + + {WE_GET_SHORT_GI, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_shortgi"}, + + {WE_GET_RTSCTS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rtscts"}, + + {WE_GET_CHWIDTH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_chwidth"}, + + {WE_GET_ANI_EN_DIS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_anienable"}, + + {WE_GET_ANI_POLL_PERIOD, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniplen"}, + + {WE_GET_ANI_LISTEN_PERIOD, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_anilislen"}, + + {WE_GET_ANI_OFDM_LEVEL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniofdmlvl"}, + + {WE_GET_ANI_CCK_LEVEL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_aniccklvl"}, + + {WE_GET_DYNAMIC_BW, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_cwmenable"}, + + {WE_GET_GTX_HT_MCS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxHTMcs"}, + + {WE_GET_GTX_VHT_MCS, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxVHTMcs"}, + + {WE_GET_GTX_USRCFG, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxUsrCfg"}, + + {WE_GET_GTX_THRE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxThre"}, + + {WE_GET_GTX_MARGIN, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMargin"}, + + {WE_GET_GTX_STEP, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxStep"}, + + {WE_GET_GTX_MINTPC, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxMinTpc"}, + + {WE_GET_GTX_BWMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gtxBWMask"}, + + {WE_GET_TX_CHAINMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txchainmask"}, + + {WE_GET_RX_CHAINMASK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rxchainmask"}, + + {WE_GET_11N_RATE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_11nrate"}, + + {WE_GET_AMPDU, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_ampdu"}, + + {WE_GET_AMSDU, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_amsdu"}, + + {WE_GET_TXPOW_2G, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txpow2g"}, + + {WE_GET_TXPOW_5G, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_txpow5g"}, + + {WE_GET_PPS_PAID_MATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_paid_match"}, + + {WE_GET_PPS_GID_MATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_gid_match"}, + + {WE_GET_PPS_EARLY_TIM_CLEAR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_tim_clear"}, + + {WE_GET_PPS_EARLY_DTIM_CLEAR, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_dtim_clear"}, + + {WE_GET_PPS_EOF_PAD_DELIM, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_eof_delim"}, + + {WE_GET_PPS_MACADDR_MISMATCH, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_mac_match"}, + + {WE_GET_PPS_DELIM_CRC_FAIL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_delim_fail"}, + + {WE_GET_PPS_GID_NSTS_ZERO, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_nsts_zero"}, + + {WE_GET_PPS_RSSI_CHECK, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_rssi_chk"}, + + {WE_GET_QPOWER_MAX_PSPOLL_COUNT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qpspollcnt"}, + + {WE_GET_QPOWER_MAX_TX_BEFORE_WAKE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qtxwake"}, + + {WE_GET_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qwakeintv"}, + + {WE_GET_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_qnodatapoll"}, + + {WE_CAP_TSF, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "cap_tsf"}, + + {WE_GET_TEMPERATURE, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_temp"}, + + {WE_GET_DCM, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_dcm"}, + + {WE_GET_RANGE_EXT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "get_range_ext"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_CHAR_GET_NONE, + IW_PRIV_TYPE_CHAR | 512, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_WOWL_ADD_PTRN, + IW_PRIV_TYPE_CHAR | 512, + 0, + "wowlAddPtrn"}, + + {WE_WOWL_DEL_PTRN, + IW_PRIV_TYPE_CHAR | 512, + 0, + "wowlDelPtrn"}, + + /* handlers for sub-ioctl */ + {WE_NEIGHBOR_REPORT_REQUEST, + IW_PRIV_TYPE_CHAR | 512, + 0, + "neighbor"}, + + {WE_SET_AP_WPS_IE, + IW_PRIV_TYPE_CHAR | 512, + 0, + "set_ap_wps_ie"}, + +#ifdef WLAN_UNIT_TEST + {WE_UNIT_TEST, + IW_PRIV_TYPE_CHAR | 512, + 0, + "unit_test"}, +#endif + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_THREE_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + ""}, + + /* handlers for sub-ioctl */ + {WE_SET_WLAN_DBG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "setwlandbg"}, + +#ifdef CONFIG_DP_TRACE + /* handlers for sub-ioctl */ + {WE_SET_DP_TRACE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "set_dp_trace"}, +#endif + + {WE_SET_FW_TEST, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, "fw_test"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_THREE_INT, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + ""}, + + {WE_GET_TSF, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + "get_tsf"}, + + {WE_SET_DUAL_MAC_SCAN_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 3, + 0, + "set_scan_cfg"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_GET_CHAR_SET_NONE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + ""}, + + /* handlers for sub-ioctl */ + {WE_WLAN_VERSION, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "version"}, + + {WE_GET_STATS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getStats"}, + + {WE_GET_SUSPEND_RESUME_STATS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getSuspendStats"}, + + {WE_LIST_FW_PROFILE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "listProfile"}, + + {WE_GET_STATES, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getHostStates"}, + + {WE_GET_CFG, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getConfig"}, + + {WE_GET_RSSI, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getRSSI"}, + + {WE_GET_WMM_STATUS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getWmmStatus"}, + + {WE_GET_CHANNEL_LIST, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getChannelList"}, +#ifdef FEATURE_WLAN_TDLS + {WE_GET_TDLS_PEERS, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getTdlsPeers"}, +#endif + {WE_GET_11W_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getPMFInfo"}, + + {WE_GET_STA_CXN_INFO, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "get_cxn_info" }, + + {WE_GET_PHYMODE, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getphymode"}, +#if defined(FEATURE_OEM_DATA_SUPPORT) || defined(WIFI_POS_CONVERGED) + {WE_GET_OEM_DATA_CAP, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getOemDataCap"}, +#endif + {WE_GET_SNR, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "getSNR"}, + + {WE_GET_BA_AGEING_TIMEOUT, + 0, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "get_ba_timeout"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_NONE_GET_NONE, + 0, + 0, + ""}, + + {WE_GET_FW_PROFILE_DATA, + 0, + 0, + "getProfileData"}, + + {WE_SET_REASSOC_TRIGGER, + 0, + 0, + "reassoc"}, + + {WE_STOP_OBSS_SCAN, + 0, + 0, + "stop_obss_scan"}, + /* handlers for main ioctl */ + {WLAN_PRIV_SET_VAR_INT_GET_NONE, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + ""}, + +#ifdef TRACE_RECORD + /* handlers for sub-ioctl */ + {WE_MTRACE_SELECTIVE_MODULE_LOG_ENABLE_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setdumplog"}, + + {WE_MTRACE_DUMP_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "dumplog"}, +#endif + + {WE_POLICY_MANAGER_CINFO_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "pm_cinfo"}, + + {WE_UNIT_TEST_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "setUnitTestCmd"}, + + {WE_MAC_PWR_DEBUG_CMD, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "halPwrDebug"}, +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + {WE_LED_FLASHING_PARAM, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "gpio_control"}, +#endif +#ifdef WLAN_DEBUG + {WE_SET_CHAN_AVOID, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "ch_avoid"}, +#endif + /* handlers for main ioctl */ + {WLAN_PRIV_FIPS_TEST, + IW_PRIV_TYPE_BYTE | WE_MAX_STR_LEN, + IW_PRIV_TYPE_BYTE | WE_MAX_STR_LEN, + "fips_test"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_ADD_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | HDD_WLAN_WMM_PARAM_COUNT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "addTspec"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_DEL_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "delTspec"}, + + /* handlers for main ioctl */ + {WLAN_PRIV_GET_TSPEC, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "getTspec"}, + + /* handlers for main ioctl - host offload */ + {WLAN_PRIV_SET_HOST_OFFLOAD, + IW_PRIV_TYPE_BYTE | sizeof(struct host_offload_req), + 0, + "setHostOffload"}, + + {WLAN_GET_WLAN_STATISTICS, + 0, + IW_PRIV_TYPE_BYTE | WE_MAX_STR_LEN, + "getWlanStats"}, + + {WLAN_SET_KEEPALIVE_PARAMS, + IW_PRIV_TYPE_BYTE | sizeof(struct keep_alive_req) | + IW_PRIV_SIZE_FIXED, + 0, + "setKeepAlive"}, +#ifdef WLAN_FEATURE_PACKET_FILTERING + {WLAN_SET_PACKET_FILTER_PARAMS, + IW_PRIV_TYPE_BYTE | + sizeof(struct pkt_filter_cfg), + 0, + "setPktFilter"}, +#endif +#ifdef FEATURE_WLAN_SCAN_PNO + {WLAN_SET_PNO, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + 0, + "setpno"}, +#endif + {WLAN_SET_BAND_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "SETBAND"}, + + {WLAN_PRIV_SET_MCBC_FILTER, + 0, + 0, + "setMCBCFilter"}, + + {WLAN_GET_LINK_SPEED, + IW_PRIV_TYPE_CHAR | 18, + IW_PRIV_TYPE_CHAR | 5, + "getLinkSpeed"}, + +#ifdef FEATURE_WLM_STATS + {WLAN_GET_WLM_STATS, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + IW_PRIV_TYPE_CHAR | WE_MAX_STR_LEN, + "get_wlm_stats"}, +#endif + + /* handlers for main ioctl */ + {WLAN_PRIV_SET_TWO_INT_GET_NONE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, + ""}, + + {WE_SET_SMPS_PARAM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_smps_param"}, + + {WLAN_SET_DOT11P_CHANNEL_SCHED, + IW_PRIV_TYPE_BYTE | sizeof(struct dot11p_channel_sched), + 0, "set_dot11p" }, + +#ifdef CONFIG_WLAN_DEBUG_CRASH_INJECT + {WE_SET_FW_CRASH_INJECT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "crash_inject"}, + +#endif +#if defined(WMI_INTERFACE_EVENT_LOGGING) || defined(FEATURE_HTC_CREDIT_HISTORY) + {WE_LOG_BUFFER, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "log_buffer"}, + +#endif + {WE_SET_BA_AGEING_TIMEOUT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_ba_timeout"}, + +#ifdef WLAN_SUSPEND_RESUME_TEST + {WE_SET_WLAN_SUSPEND, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "wlan_suspend"}, + + {WE_SET_WLAN_RESUME, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "wlan_resume"}, +#endif + {WE_ENABLE_FW_PROFILE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "enableProfile"}, + + {WE_SET_FW_PROFILE_HIST_INTVL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_hist_intvl"}, + + {WE_SET_DUAL_MAC_FW_MODE_CONFIG, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "set_fw_mode_cfg"}, +#ifdef CONFIG_DP_TRACE + {WE_DUMP_DP_TRACE_LEVEL, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "dump_dp_trace"}, +#endif +#ifdef FEATURE_MONITOR_MODE_SUPPORT + {WE_SET_MON_MODE_CHAN, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, + 0, "setMonChan"}, +#endif + {WE_GET_ROAM_SYNCH_DELAY, + 0, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + "hostroamdelay"}, + + {WE_SET_11AX_RATE, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "set_11ax_rate"}, + + {WE_SET_DCM, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "enable_dcm"}, + + {WE_SET_RANGE_EXT, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "range_ext"}, + + {WLAN_PRIV_SET_FTIES, + IW_PRIV_TYPE_CHAR | MAX_FTIE_SIZE, + 0, + "set_ft_ies"}, + +#ifdef WLAN_FEATURE_MOTION_DETECTION + {WE_MOTION_DET_START_STOP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "mt_start"}, + + {WE_MOTION_DET_BASE_LINE_START_STOP, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + 0, + "mt_bl_start"}, + + {WE_MOTION_DET_CONFIG_PARAM, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "mt_config"}, + + {WE_MOTION_DET_BASE_LINE_CONFIG_PARAM, + IW_PRIV_TYPE_INT | MAX_VAR_ARGS, + 0, + "mt_bl_config"}, +#endif /* WLAN_FEATURE_MOTION_DETECTION */ +}; + +const struct iw_handler_def we_handler_def = { + .num_standard = 0, + .num_private = QDF_ARRAY_SIZE(we_private), + .num_private_args = QDF_ARRAY_SIZE(we_private_args), + + .standard = NULL, + .private = (iw_handler *) we_private, + .private_args = we_private_args, + .get_wireless_stats = NULL, +}; + +void hdd_register_wext(struct net_device *dev) +{ + hdd_enter_dev(dev); + + dev->wireless_handlers = &we_handler_def; + + hdd_exit(); +} + +void hdd_wext_unregister(struct net_device *dev, + bool rtnl_held) +{ + if (!dev) + return; + + if (!rtnl_held) + rtnl_lock(); + dev->wireless_handlers = NULL; + if (!rtnl_held) + rtnl_unlock(); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wifi_pos_pasn.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wifi_pos_pasn.c new file mode 100644 index 0000000000..0d1e4f8325 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wifi_pos_pasn.c @@ -0,0 +1,678 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/** + * DOC: wlan_hdd_wifi_pos_pasn.c + * + * WLAN Host Device Driver WIFI POSITION PASN authentication APIs implementation + */ + +#include +#include +#include +#include +#include "osif_sync.h" +#include +#include +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_hdd_wifi_pos_pasn.h" +#include "wifi_pos_pasn_api.h" +#include "wifi_pos_ucfg_i.h" +#include "wlan_crypto_global_api.h" +#include "wifi_pos_ucfg_i.h" +#include "wlan_nl_to_crypto_params.h" +#include "wlan_mlo_mgr_sta.h" + +const struct nla_policy +wifi_pos_pasn_auth_status_policy[QCA_WLAN_VENDOR_ATTR_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PASN_ACTION] = {.type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_PASN_PEERS] = {.type = NLA_NESTED}, +}; + +const struct nla_policy +wifi_pos_pasn_auth_policy[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS] = {.type = NLA_FLAG}, + [QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED] = { + .type = NLA_FLAG}, +}; + +const struct nla_policy +wifi_pos_pasn_set_ranging_ctx_policy[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SHA_TYPE] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK] = { + .type = NLA_BINARY, .len = MAX_PMK_LEN}, + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER] = { + .type = NLA_U32}, + [QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED] = { + .type = NLA_BINARY, .len = MAX_PMK_LEN}, +}; + +static int +wlan_hdd_cfg80211_send_pasn_auth_status(struct wiphy *wiphy, + struct net_device *dev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_pasn_auth_status *pasn_data; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1]; + struct nlattr *curr_attr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool is_pasn_success = false; + int ret, i = 0, rem; + + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_MAX, + data, data_len, + wifi_pos_pasn_auth_status_policy)) { + hdd_err_rl("Invalid PASN auth status attributes"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS]) { + hdd_err_rl("No PASN peer"); + return -EINVAL; + } + + pasn_data = qdf_mem_malloc(sizeof(*pasn_data)); + if (!pasn_data) + return -ENOMEM; + + pasn_data->vdev_id = adapter->deflink->vdev_id; + nla_for_each_nested(curr_attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], + rem) { + if (wlan_cfg80211_nla_parse_nested( + tb2, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX, curr_attr, + wifi_pos_pasn_auth_policy)) { + hdd_err_rl("nla_parse failed"); + qdf_mem_free(pasn_data); + return -EINVAL; + } + + is_pasn_success = nla_get_flag( + tb2[QCA_WLAN_VENDOR_ATTR_PASN_PEER_STATUS_SUCCESS]); + if (!is_pasn_success) + pasn_data->auth_status[i].status = + WLAN_PASN_AUTH_STATUS_PASN_FAILED; + + hdd_debug("PASN auth status:%d", + pasn_data->auth_status[i].status); + + if (tb2[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR]) { + nla_memcpy(pasn_data->auth_status[i].peer_mac.bytes, + tb2[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR], + QDF_MAC_ADDR_SIZE); + hdd_debug("Peer mac[%d]: " QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF( + pasn_data->auth_status[i].peer_mac.bytes)); + } + + if (tb2[QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR]) { + nla_memcpy(pasn_data->auth_status[i].self_mac.bytes, + tb2[QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR], + QDF_MAC_ADDR_SIZE); + hdd_debug("Src addr[%d]: " QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF( + pasn_data->auth_status[i].self_mac.bytes)); + } + + i++; + pasn_data->num_peers++; + if (pasn_data->num_peers >= WLAN_MAX_11AZ_PEERS) { + hdd_err_rl("Invalid num_peers:%d", + pasn_data->num_peers); + qdf_mem_free(pasn_data); + return -EINVAL; + } + } + + status = wifi_pos_send_pasn_auth_status(hdd_ctx->psoc, pasn_data); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Send pasn auth status failed"); + + qdf_mem_free(pasn_data); + ret = qdf_status_to_os_return(status); + + return ret; +} + +int wlan_hdd_wifi_pos_send_pasn_auth_status(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = wlan_hdd_cfg80211_send_pasn_auth_status(wiphy, wdev->netdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +#define WLAN_PASN_AUTH_KEY_INDEX 0 + +static int wlan_cfg80211_set_pasn_key(struct hdd_adapter *adapter, + struct nlattr **tb) +{ + struct wlan_crypto_key *crypto_key; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc = + adapter->hdd_ctx->psoc; + struct qdf_mac_addr peer_mac = {0}; + struct wlan_pasn_auth_status *pasn_status; + bool is_ltf_keyseed_required; + QDF_STATUS status; + int ret = 0; + int cipher_len; + uint32_t cipher; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_WIFI_POS_CORE_ID); + if (!vdev) { + hdd_err("Key params is NULL"); + return -EINVAL; + } + + crypto_key = qdf_mem_malloc(sizeof(*crypto_key)); + if (!crypto_key) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_WIFI_POS_CORE_ID); + return -ENOMEM; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER]) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_WIFI_POS_CORE_ID); + qdf_mem_free(crypto_key); + return -EINVAL; + } + + cipher = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_CIPHER]); + crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(cipher); + + cipher_len = osif_nl_to_crypto_cipher_len(cipher); + crypto_key->keylen = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK]); + if (cipher_len < 0 || crypto_key->keylen < cipher_len || + (crypto_key->keylen > + (WLAN_CRYPTO_KEYBUF_SIZE + WLAN_CRYPTO_MICBUF_SIZE))) { + hdd_err_rl("Invalid key length %d", crypto_key->keylen); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_WIFI_POS_CORE_ID); + qdf_mem_free(crypto_key); + return -EINVAL; + } + + crypto_key->keyix = WLAN_PASN_AUTH_KEY_INDEX; + qdf_mem_copy(&crypto_key->keyval[0], + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK]), + crypto_key->keylen); + + if (!tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]) { + hdd_err_rl("BSSID is not present"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_WIFI_POS_CORE_ID); + qdf_mem_free(crypto_key); + return -EINVAL; + } + + qdf_mem_copy(crypto_key->macaddr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(peer_mac.bytes, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + + hdd_debug("PASN unicast key opmode %d, key_len %d", + vdev->vdev_mlme.vdev_opmode, + crypto_key->keylen); + + status = ucfg_crypto_set_key_req(vdev, crypto_key, + WLAN_CRYPTO_KEY_TYPE_UNICAST); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("PASN set_key failed"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_WIFI_POS_CORE_ID); + qdf_mem_free(crypto_key); + return -EFAULT; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_WIFI_POS_CORE_ID); + qdf_mem_free(crypto_key); + + peer = wlan_objmgr_get_peer_by_mac(psoc, peer_mac.bytes, + WLAN_WIFI_POS_CORE_ID); + if (!peer) { + hdd_err("PASN peer is not found"); + return -EFAULT; + } + + /* + * If LTF key seed is not required for the peer, then update + * the source mac address for that peer by sending PASN auth + * status command. + * If LTF keyseed is required, then PASN Auth status command + * will be sent after LTF keyseed command. + */ + is_ltf_keyseed_required = + ucfg_wifi_pos_is_ltf_keyseed_required_for_peer(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_WIFI_POS_CORE_ID); + if (is_ltf_keyseed_required) + return 0; + + pasn_status = qdf_mem_malloc(sizeof(*pasn_status)); + if (!pasn_status) + return -ENOMEM; + + pasn_status->vdev_id = adapter->deflink->vdev_id; + pasn_status->num_peers = 1; + + qdf_mem_copy(pasn_status->auth_status[0].peer_mac.bytes, + peer_mac.bytes, QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR]) + qdf_mem_copy(pasn_status->auth_status[0].self_mac.bytes, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR]), + QDF_MAC_ADDR_SIZE); + + status = wifi_pos_send_pasn_auth_status(psoc, pasn_status); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Send PASN auth status failed"); + + ret = qdf_status_to_os_return(status); + + qdf_mem_free(pasn_status); + + return ret; +} + +#define MLO_ALL_VDEV_LINK_ID -1 + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +wlan_hdd_cfg80211_send_set_ltf_keyseed_mlo_vdev(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev, + struct hdd_adapter *adapter, + struct wlan_crypto_ltf_keyseed_data *data, + int link_id) +{ + struct wlan_objmgr_vdev *link_vdev; + struct wlan_objmgr_peer *peer; + uint16_t link, vdev_count = 0; + struct qdf_mac_addr peer_link_mac; + struct qdf_mac_addr original_mac; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS] = {0}; + QDF_STATUS status; + uint8_t vdev_id; + struct wlan_hdd_link_info *link_info; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + return QDF_STATUS_SUCCESS; + + qdf_copy_macaddr(&peer_link_mac, &data->peer_mac_addr); + qdf_copy_macaddr(&original_mac, &data->peer_mac_addr); + mlo_sta_get_vdev_list(vdev, &vdev_count, wlan_vdev_list); + + for (link = 0; link < vdev_count; link++) { + link_vdev = wlan_vdev_list[link]; + vdev_id = wlan_vdev_get_id(link_vdev); + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info) { + mlo_release_vdev_ref(link_vdev); + continue; + } + + peer = NULL; + switch (adapter->device_mode) { + case QDF_SAP_MODE: + if (wlan_vdev_mlme_is_mlo_vdev(link_vdev)) + peer = wlan_hdd_ml_sap_get_peer( + link_vdev, + peer_link_mac.bytes); + break; + case QDF_STA_MODE: + default: + peer = wlan_objmgr_vdev_try_get_bsspeer(link_vdev, + WLAN_OSIF_ID); + break; + } + + if (peer) { + qdf_mem_copy(peer_link_mac.bytes, + wlan_peer_get_macaddr(peer), + QDF_MAC_ADDR_SIZE); + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_ID); + + } else if (wlan_vdev_mlme_is_mlo_link_vdev(link_vdev) && + adapter->device_mode == QDF_STA_MODE) { + status = wlan_hdd_mlo_copy_partner_addr_from_mlie( + link_vdev, &peer_link_mac); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Failed to get peer address from ML IEs"); + mlo_release_vdev_ref(link_vdev); + continue; + } + } else { + hdd_err("Peer is null"); + mlo_release_vdev_ref(link_vdev); + continue; + } + + qdf_copy_macaddr(&data->peer_mac_addr, &peer_link_mac); + data->vdev_id = wlan_vdev_get_id(link_vdev); + + status = wlan_crypto_set_ltf_keyseed(hdd_ctx->psoc, data); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Set LTF Keyseed failed vdev:%d for peer: " + QDF_MAC_ADDR_FMT, data->vdev_id, + QDF_MAC_ADDR_REF(data->peer_mac_addr.bytes)); + mlo_release_vdev_ref(link_vdev); + continue; + } + + mlo_release_vdev_ref(link_vdev); + } + qdf_copy_macaddr(&data->peer_mac_addr, &original_mac); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +wlan_hdd_cfg80211_send_set_ltf_keyseed_mlo_vdev(struct hdd_context *hdd_ctx, + struct wlan_objmgr_vdev *vdev, + struct hdd_adapter *adapter, + struct wlan_crypto_ltf_keyseed_data *data, + int link_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static int +wlan_hdd_cfg80211_send_set_ltf_keyseed(struct wiphy *wiphy, + struct net_device *dev, + struct nlattr **tb) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct wlan_pasn_auth_status *pasn_auth_status; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_vdev *vdev; + struct wlan_crypto_ltf_keyseed_data *data; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool is_ltf_keyseed_required; + enum wlan_peer_type peer_type; + int ret; + + hdd_enter(); + if (hdd_get_conparam() == QDF_GLOBAL_FTM_MODE) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + if (wlan_hdd_validate_vdev_id(adapter->deflink->vdev_id)) + return -EINVAL; + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return ret; + + data = qdf_mem_malloc(sizeof(*data)); + if (!data) + return -ENOMEM; + + data->vdev_id = adapter->deflink->vdev_id; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(hdd_ctx->psoc, + data->vdev_id, + WLAN_WIFI_POS_OSIF_ID); + if (!vdev) { + hdd_err_rl("Vdev is not found for id:%d", data->vdev_id); + ret = -EINVAL; + goto err; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_OSIF_ID); + hdd_err_rl("BSSID is not present"); + ret = -EINVAL; + goto err; + } + + qdf_mem_copy(data->peer_mac_addr.bytes, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR]) + qdf_mem_copy(data->src_mac_addr.bytes, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_SRC_ADDR]), + QDF_MAC_ADDR_SIZE); + + data->key_seed_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED]); + if (!data->key_seed_len || + data->key_seed_len < WLAN_MIN_SECURE_LTF_KEYSEED_LEN || + data->key_seed_len > WLAN_MAX_SECURE_LTF_KEYSEED_LEN) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_OSIF_ID); + hdd_err_rl("Invalid key seed length:%d", data->key_seed_len); + ret = -EINVAL; + goto err; + } + + qdf_mem_copy(data->key_seed, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED]), + data->key_seed_len); + + /* + * For MLO vdev send set LTF keyseed command on each link for the link + * peer address similar to install key command + */ + if (wlan_vdev_mlme_is_mlo_vdev(vdev)) + status = wlan_hdd_cfg80211_send_set_ltf_keyseed_mlo_vdev( + hdd_ctx, vdev, adapter, + data, MLO_ALL_VDEV_LINK_ID); + else + status = wlan_crypto_set_ltf_keyseed(hdd_ctx->psoc, data); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_OSIF_ID); + + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Set LTF Keyseed failed vdev_id:%d", data->vdev_id); + ret = qdf_status_to_os_return(status); + goto err; + } + + peer = wlan_objmgr_get_peer_by_mac(hdd_ctx->psoc, + data->peer_mac_addr.bytes, + WLAN_WIFI_POS_CORE_ID); + if (!peer) { + hdd_err_rl("PASN peer is not found"); + /* + * Auth status need not be sent for the BSS PASN + * peer. So, return if peer is not found + */ + ret = 0; + goto err; + } + + /* + * PASN auth status command need not be sent for associated peer. + * It should be sent only for PASN peer type. + */ + peer_type = wlan_peer_get_peer_type(peer); + if (peer_type != WLAN_PEER_RTT_PASN) { + wlan_objmgr_peer_release_ref(peer, WLAN_WIFI_POS_CORE_ID); + ret = 0; + goto err; + } + + /* + * If LTF key seed is not required for the peer, then update + * the source mac address for that peer by sending PASN auth + * status command. + * If LTF keyseed is required, then PASN Auth status command + * will be sent after LTF keyseed command. + */ + is_ltf_keyseed_required = + ucfg_wifi_pos_is_ltf_keyseed_required_for_peer(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_WIFI_POS_CORE_ID); + + if (!is_ltf_keyseed_required) { + ret = 0; + goto err; + } + + /* + * Send PASN Auth status followed by SET LTF keyseed command to + * set the peer as authorized at firmware and firmware will start + * ranging after this. + */ + pasn_auth_status = qdf_mem_malloc(sizeof(*pasn_auth_status)); + if (!pasn_auth_status) { + ret = -ENOMEM; + goto err; + } + + pasn_auth_status->vdev_id = adapter->deflink->vdev_id; + pasn_auth_status->num_peers = 1; + qdf_mem_copy(pasn_auth_status->auth_status[0].peer_mac.bytes, + data->peer_mac_addr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pasn_auth_status->auth_status[0].self_mac.bytes, + data->src_mac_addr.bytes, QDF_MAC_ADDR_SIZE); + + hdd_debug("vdev:%d Send pasn auth status", pasn_auth_status->vdev_id); + status = wifi_pos_send_pasn_auth_status(hdd_ctx->psoc, + pasn_auth_status); + qdf_mem_free(pasn_auth_status); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Send PASN auth status failed"); + + ret = qdf_status_to_os_return(status); +err: + qdf_mem_free(data); + hdd_exit(); + + return ret; +} + +static int +__wlan_hdd_cfg80211_set_secure_ranging_context(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + int errno = 0; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX + 1]; + struct qdf_mac_addr peer_mac; + + hdd_enter(); + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_MAX, + data, data_len, + wifi_pos_pasn_set_ranging_ctx_policy)) { + hdd_err_rl("Invalid PASN auth status attributes"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION]) { + hdd_err_rl("Action attribute is missing"); + return -EINVAL; + } + + if (nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION]) == + QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_ADD) { + if (tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK] && + nla_len(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_TK])) { + hdd_debug("Sec ranging CTX TK"); + errno = wlan_cfg80211_set_pasn_key(adapter, tb); + if (errno) + return errno; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED] && + nla_len(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_LTF_KEYSEED])) { + hdd_debug("Set LTF keyseed"); + errno = wlan_hdd_cfg80211_send_set_ltf_keyseed(wiphy, + wdev->netdev, tb); + if (errno) + return errno; + } + } else if (nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_ACTION]) == + QCA_WLAN_VENDOR_SECURE_RANGING_CTX_ACTION_DELETE) { + if (!tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]) { + hdd_err_rl("Peer mac address attribute is missing"); + return -EINVAL; + } + + qdf_mem_copy(peer_mac.bytes, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_SECURE_RANGING_CTX_PEER_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + hdd_debug("Delete PASN peer" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac.bytes)); + wifi_pos_send_pasn_peer_deauth(hdd_ctx->psoc, &peer_mac); + } + + hdd_exit(); + + return errno; +} + +int +wlan_hdd_cfg80211_set_secure_ranging_context(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_set_secure_ranging_context(wiphy, + wdev, + data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c new file mode 100644 index 0000000000..2dd068c460 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wmm.c @@ -0,0 +1,3263 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: HDD WMM + * + * This module (wlan_hdd_wmm.h interface + wlan_hdd_wmm.c implementation) + * houses all the logic for WMM in HDD. + * + * On the control path, it has the logic to setup QoS, modify QoS and delete + * QoS (QoS here refers to a TSPEC). The setup QoS comes in two flavors: an + * explicit application invoked and an internal HDD invoked. The implicit QoS + * is for applications that do NOT call the custom QCT WLAN OIDs for QoS but + * which DO mark their traffic for priortization. It also has logic to start, + * update and stop the U-APSD trigger frame generation. It also has logic to + * read WMM related config parameters from the registry. + * + * On the data path, it has the logic to figure out the WMM AC of an egress + * packet and when to signal TL to serve a particular AC queue. It also has the + * logic to retrieve a packet based on WMM priority in response to a fetch from + * TL. + * + * The remaining functions are utility functions for information hiding. + */ + +/* Include files */ +#include +#include +#include +#include +#include +#include +#include +#include "osif_sync.h" +#include "os_if_fwol.h" +#include +#include +#include +#include +#include +#include +#include "sme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "cfg_ucfg_api.h" +#include "wlan_hdd_object_manager.h" +#include "wlan_hdd_cm_api.h" +#include "wlan_dp_ucfg_api.h" + +#define HDD_WMM_UP_TO_AC_MAP_SIZE 8 +#define DSCP(x) x +#define MIN_HANDLE_VALUE 5000 +#define MAX_HANDLE_VALUE 6000 + +const uint8_t hdd_wmm_up_to_ac_map[] = { + SME_AC_BE, + SME_AC_BK, + SME_AC_BK, + SME_AC_BE, + SME_AC_VI, + SME_AC_VI, + SME_AC_VO, + SME_AC_VO +}; + +#define CONFIG_TSPEC_OPERATION \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_OPERATION +#define CONFIG_TSPEC_TSID \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_TSID +#define CONFIG_TSPEC_DIRECTION \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_DIRECTION +#define CONFIG_TSPEC_APSD \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_APSD +#define CONFIG_TSPEC_USER_PRIORITY \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_USER_PRIORITY +#define CONFIG_TSPEC_ACK_POLICY \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_ACK_POLICY +#define CONFIG_TSPEC_NOMINAL_MSDU_SIZE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_NOMINAL_MSDU_SIZE +#define CONFIG_TSPEC_MAXIMUM_MSDU_SIZE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAXIMUM_MSDU_SIZE +#define CONFIG_TSPEC_MIN_SERVICE_INTERVAL \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MIN_SERVICE_INTERVAL +#define CONFIG_TSPEC_MAX_SERVICE_INTERVAL \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX_SERVICE_INTERVAL +#define CONFIG_TSPEC_INACTIVITY_INTERVAL \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_INACTIVITY_INTERVAL +#define CONFIG_TSPEC_SUSPENSION_INTERVAL \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SUSPENSION_INTERVAL +#define CONFIG_TSPEC_MINIMUM_DATA_RATE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_DATA_RATE +#define CONFIG_TSPEC_MEAN_DATA_RATE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MEAN_DATA_RATE +#define CONFIG_TSPEC_PEAK_DATA_RATE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_PEAK_DATA_RATE +#define CONFIG_TSPEC_BURST_SIZE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_BURST_SIZE +#define CONFIG_TSPEC_MINIMUM_PHY_RATE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MINIMUM_PHY_RATE +#define CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE \ + QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE + +const struct nla_policy +config_tspec_policy[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1] = { + [CONFIG_TSPEC_OPERATION] = {.type = NLA_U8}, + [CONFIG_TSPEC_TSID] = {.type = NLA_U8}, + [CONFIG_TSPEC_DIRECTION] = {.type = NLA_U8}, + [CONFIG_TSPEC_APSD] = {.type = NLA_FLAG}, + [CONFIG_TSPEC_USER_PRIORITY] = {.type = NLA_U8}, + [CONFIG_TSPEC_ACK_POLICY] = {.type = NLA_U8}, + [CONFIG_TSPEC_NOMINAL_MSDU_SIZE] = {.type = NLA_U16}, + [CONFIG_TSPEC_MAXIMUM_MSDU_SIZE] = {.type = NLA_U16}, + [CONFIG_TSPEC_MIN_SERVICE_INTERVAL] = {.type = NLA_U32}, + [CONFIG_TSPEC_MAX_SERVICE_INTERVAL] = {.type = NLA_U32}, + [CONFIG_TSPEC_INACTIVITY_INTERVAL] = {.type = NLA_U32}, + [CONFIG_TSPEC_SUSPENSION_INTERVAL] = {.type = NLA_U32}, + [CONFIG_TSPEC_MINIMUM_DATA_RATE] = {.type = NLA_U32}, + [CONFIG_TSPEC_MEAN_DATA_RATE] = {.type = NLA_U32}, + [CONFIG_TSPEC_PEAK_DATA_RATE] = {.type = NLA_U32}, + [CONFIG_TSPEC_BURST_SIZE] = {.type = NLA_U32}, + [CONFIG_TSPEC_MINIMUM_PHY_RATE] = {.type = NLA_U32}, + [CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE] = {.type = NLA_U16}, +}; + +#ifdef QCA_LL_TX_FLOW_CONTROL_V2 +void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter) +{ + uint8_t i; + + netif_wake_subqueue(adapter->dev, + HDD_LINUX_AC_HI_PRIO * TX_QUEUES_PER_AC); + + for (i = 0; i < TX_QUEUES_PER_AC; i++) { + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_VO, i)); + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_VI, i)); + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_BE, i)); + netif_stop_subqueue(adapter->dev, + TX_GET_QUEUE_IDX(HDD_LINUX_AC_BK, i)); + } +} +#else +void wlan_hdd_process_peer_unauthorised_pause(struct hdd_adapter *adapter) +{ +} +#endif + +/* Linux based UP -> AC Mapping */ +const uint8_t hdd_linux_up_to_ac_map[HDD_WMM_UP_TO_AC_MAP_SIZE] = { + HDD_LINUX_AC_BE, + HDD_LINUX_AC_BK, + HDD_LINUX_AC_BK, + HDD_LINUX_AC_BE, + HDD_LINUX_AC_VI, + HDD_LINUX_AC_VI, + HDD_LINUX_AC_VO, + HDD_LINUX_AC_VO +}; + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_enable_tl_uapsd() - function which decides whether and + * how to update UAPSD parameters in TL + * + * @qos_context: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_enable_tl_uapsd(struct hdd_wmm_qos_context *qos_context) +{ + struct hdd_adapter *adapter = qos_context->adapter; + sme_ac_enum_type ac_type = qos_context->ac_type; + struct hdd_wmm_ac_status *ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + QDF_STATUS status; + uint32_t service_interval; + uint32_t suspension_interval; + enum sme_qos_wmm_dir_type direction; + bool psb; + uint32_t delayed_trgr_frm_int; + + /* The TSPEC must be valid */ + if (ac->is_tspec_valid == false) { + hdd_err("Invoked with invalid TSPEC"); + return; + } + /* determine the service interval */ + if (ac->tspec.min_service_interval) { + service_interval = ac->tspec.min_service_interval; + } else if (ac->tspec.max_service_interval) { + service_interval = ac->tspec.max_service_interval; + } else { + /* no service interval is present in the TSPEC */ + /* this is OK, there just won't be U-APSD */ + hdd_debug("No service interval supplied"); + service_interval = 0; + } + + /* determine the suspension interval & direction */ + suspension_interval = ac->tspec.suspension_interval; + direction = ac->tspec.ts_info.direction; + psb = ac->tspec.ts_info.psb; + + /* if we have previously enabled U-APSD, have any params changed? */ + if ((ac->is_uapsd_info_valid) && + (ac->uapsd_service_interval == service_interval) && + (ac->uapsd_suspension_interval == suspension_interval) && + (ac->uapsd_direction == direction) && + (ac->is_uapsd_enabled == psb)) { + hdd_debug("No change in U-APSD parameters"); + return; + } + + ucfg_mlme_get_tl_delayed_trgr_frm_int(hdd_ctx->psoc, + &delayed_trgr_frm_int); + /* everything is in place to notify TL */ + status = + sme_enable_uapsd_for_ac(ac_type, ac->tspec.ts_info.tid, + ac->tspec.ts_info.up, + service_interval, suspension_interval, + direction, psb, + adapter->deflink->vdev_id, + delayed_trgr_frm_int); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to enable U-APSD for AC=%d", ac_type); + return; + } + /* stash away the parameters that were used */ + ac->is_uapsd_info_valid = true; + ac->uapsd_service_interval = service_interval; + ac->uapsd_suspension_interval = suspension_interval; + ac->uapsd_direction = direction; + ac->is_uapsd_enabled = psb; + + hdd_debug("Enabled UAPSD in TL srv_int=%d susp_int=%d dir=%d AC=%d", + service_interval, suspension_interval, direction, ac_type); + +} + +/** + * hdd_wmm_disable_tl_uapsd() - function which decides whether + * to disable UAPSD parameters in TL + * + * @qos_context: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_disable_tl_uapsd(struct hdd_wmm_qos_context *qos_context) +{ + struct hdd_adapter *adapter = qos_context->adapter; + sme_ac_enum_type ac_type = qos_context->ac_type; + struct hdd_wmm_ac_status *ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + QDF_STATUS status; + + /* have we previously enabled UAPSD? */ + if (ac->is_uapsd_info_valid == true) { + status = sme_disable_uapsd_for_ac(ac_type, + adapter->deflink->vdev_id); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Failed to disable U-APSD for AC=%d", ac_type); + } else { + /* TL no longer has valid UAPSD info */ + ac->is_uapsd_info_valid = false; + hdd_debug("Disabled UAPSD in TL for AC=%d", ac_type); + } + } +} + +#endif + +/** + * hdd_wmm_free_context() - function which frees a QoS context + * + * @qos_context: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_free_context(struct hdd_wmm_qos_context *qos_context) +{ + struct hdd_adapter *adapter; + + hdd_debug("Entered, context %pK", qos_context); + + if (unlikely((!qos_context) || + (HDD_WMM_CTX_MAGIC != qos_context->magic))) { + /* must have been freed in another thread */ + return; + } + /* get pointer to the adapter context */ + adapter = qos_context->adapter; + + /* take the mutex since we're manipulating the context list */ + mutex_lock(&adapter->hdd_wmm_status.mutex); + + /* make sure nobody thinks this is a valid context */ + qos_context->magic = 0; + + /* unlink the context */ + list_del(&qos_context->node); + + /* done manipulating the list */ + mutex_unlock(&adapter->hdd_wmm_status.mutex); + + /* reclaim memory */ + qdf_mem_free(qos_context); + +} + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/** + * hdd_wmm_notify_app() - function which notifies an application + * of changes in state of it flow + * + * @qos_context: [in] the pointer the QoS instance control block + * + * Return: None + */ +static void hdd_wmm_notify_app(struct hdd_wmm_qos_context *qos_context) +{ +#define MAX_NOTIFY_LEN 50 + struct hdd_adapter *adapter; + union iwreq_data wrqu; + char buf[MAX_NOTIFY_LEN + 1]; + + hdd_debug("Entered, context %pK", qos_context); + + if (unlikely((!qos_context) || + (HDD_WMM_CTX_MAGIC != qos_context->magic))) { + hdd_err("Invalid QoS Context"); + return; + } + + /* create the event */ + memset(&wrqu, 0, sizeof(wrqu)); + memset(buf, 0, sizeof(buf)); + + snprintf(buf, MAX_NOTIFY_LEN, "QCOM: TS change[%u: %u]", + (unsigned int)qos_context->handle, + (unsigned int)qos_context->status); + + wrqu.data.pointer = buf; + wrqu.data.length = strlen(buf); + + /* get pointer to the adapter */ + adapter = qos_context->adapter; + + /* send the event */ + hdd_debug("Sending [%s]", buf); + hdd_wext_send_event(adapter->dev, IWEVCUSTOM, &wrqu, buf); +} + +#ifdef FEATURE_WLAN_ESE +/** + * hdd_wmm_inactivity_timer_cb() - inactivity timer callback function + * + * @user_data: opaque user data registered with the timer. In the + * case of this timer, the associated wmm QoS context is registered. + * + * This timer handler function is called for every inactivity interval + * per AC. This function gets the current transmitted packets on the + * given AC, and checks if there was any TX activity from the previous + * interval. If there was no traffic then it would delete the TS that + * was negotiated on that AC. + * + * Return: None + */ +static void hdd_wmm_inactivity_timer_cb(void *user_data) +{ + struct hdd_wmm_qos_context *qos_context = user_data; + struct hdd_adapter *adapter; + struct hdd_wmm_ac_status *ac; + hdd_wlan_wmm_status_e status; + QDF_STATUS qdf_status; + uint32_t traffic_count = 0; + sme_ac_enum_type ac_type; + unsigned int cpu; + struct hdd_tx_rx_stats *tx_rx_stats; + + if (!qos_context) { + hdd_err("invalid user data"); + return; + } + ac_type = qos_context->ac_type; + + adapter = qos_context->adapter; + if ((!adapter) || + (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) { + hdd_err("invalid adapter: %pK", adapter); + return; + } + + ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + tx_rx_stats = &adapter->deflink->hdd_stats.tx_rx_stats; + /* Get the Tx stats for this AC. */ + for (cpu = 0; cpu < NUM_CPUS; cpu++) + traffic_count += + tx_rx_stats->per_cpu[cpu].tx_classified_ac[qos_context->ac_type]; + + hdd_warn("WMM inactivity check for AC=%d, count=%u, last=%u", + ac_type, traffic_count, ac->last_traffic_count); + if (ac->last_traffic_count == traffic_count) { + /* there is no traffic activity, delete the TSPEC for this AC */ + status = hdd_wmm_delts(adapter, qos_context->handle); + hdd_warn("Deleted TS on AC %d, due to inactivity with status = %d!!!", + ac_type, status); + } else { + ac->last_traffic_count = traffic_count; + if (ac->inactivity_timer.state == QDF_TIMER_STATE_STOPPED) { + /* Restart the timer */ + qdf_status = + qdf_mc_timer_start(&ac->inactivity_timer, + ac->inactivity_time); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Restarting inactivity timer failed on AC %d", + ac_type); + } + } else { + QDF_ASSERT(qdf_mc_timer_get_current_state + (&ac->inactivity_timer) == + QDF_TIMER_STATE_STOPPED); + } + } +} + +/** + * hdd_wmm_enable_inactivity_timer() - + * function to enable the traffic inactivity timer for the given AC + * + * @qos_context: [in] pointer to qos_context + * @inactivity_time: [in] value of the inactivity interval in millisecs + * + * When a QoS-Tspec is successfully setup, if the inactivity interval + * time specified in the AddTS parameters is non-zero, this function + * is invoked to start a traffic inactivity timer for the given AC. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_wmm_enable_inactivity_timer(struct hdd_wmm_qos_context *qos_context, + uint32_t inactivity_time) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct hdd_adapter *adapter = qos_context->adapter; + sme_ac_enum_type ac_type = qos_context->ac_type; + struct hdd_wmm_ac_status *ac; + unsigned int cpu; + struct hdd_tx_rx_stats *tx_rx_stats; + + adapter = qos_context->adapter; + ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + + qdf_status = qdf_mc_timer_init(&ac->inactivity_timer, + QDF_TIMER_TYPE_SW, + hdd_wmm_inactivity_timer_cb, + qos_context); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Initializing inactivity timer failed on AC %d", + ac_type); + return qdf_status; + } + /* Start the inactivity timer */ + qdf_status = qdf_mc_timer_start(&ac->inactivity_timer, + inactivity_time); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Starting inactivity timer failed on AC %d", + ac_type); + qdf_status = qdf_mc_timer_destroy(&ac->inactivity_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to destroy inactivity timer"); + + return qdf_status; + } + ac->inactivity_time = inactivity_time; + + ac->last_traffic_count = 0; + /* Initialize the current tx traffic count on this AC */ + tx_rx_stats = &adapter->deflink->hdd_stats.tx_rx_stats; + for (cpu = 0; cpu < NUM_CPUS; cpu++) { + ac->last_traffic_count += + tx_rx_stats->per_cpu[cpu].tx_classified_ac[qos_context->ac_type]; + } + qos_context->is_inactivity_timer_running = true; + return qdf_status; +} + +/** + * hdd_wmm_disable_inactivity_timer() - + * function to disable the traffic inactivity timer for the given AC. + * + * @qos_context: [in] pointer to qos_context + * + * This function is invoked to disable the traffic inactivity timer + * for the given AC. This is normally done when the TS is deleted. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS +hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *qos_context) +{ + struct hdd_adapter *adapter = qos_context->adapter; + sme_ac_enum_type ac_type = qos_context->ac_type; + struct hdd_wmm_ac_status *ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + /* Clear the timer and the counter */ + ac->inactivity_time = 0; + ac->last_traffic_count = 0; + + if (qos_context->is_inactivity_timer_running == true) { + qos_context->is_inactivity_timer_running = false; + qdf_status = qdf_mc_timer_stop(&ac->inactivity_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + hdd_err("Failed to stop inactivity timer"); + return qdf_status; + } + qdf_status = qdf_mc_timer_destroy(&ac->inactivity_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + hdd_err("Failed to destroy inactivity timer:Timer started"); + } + + return qdf_status; +} +#else + +static QDF_STATUS +hdd_wmm_disable_inactivity_timer(struct hdd_wmm_qos_context *qos_context) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_ESE */ + +/** + * hdd_wmm_sme_callback() - callback for QoS notifications + * + * @mac_handle: [in] the MAC handle + * @context : [in] the HDD callback context + * @tspec_info : [in] the TSPEC params + * @sme_status : [in] the QoS related SME status + * @flow_id: [in] the unique identifier of the flow + * + * This callback is registered by HDD with SME for receiving QoS + * notifications. Even though this function has a static scope it + * gets called externally through some function pointer magic (so + * there is a need for rigorous parameter checking). + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS hdd_wmm_sme_callback(mac_handle_t mac_handle, + void *context, + struct sme_qos_wmmtspecinfo *tspec_info, + enum sme_qos_statustype sme_status, + uint32_t flow_id) +{ + struct hdd_wmm_qos_context *qos_context = context; + struct hdd_adapter *adapter; + sme_ac_enum_type ac_type; + struct hdd_wmm_ac_status *ac; + + hdd_debug("Entered, context %pK", qos_context); + + if (unlikely((!qos_context) || + (HDD_WMM_CTX_MAGIC != qos_context->magic))) { + hdd_err("Invalid QoS Context"); + return QDF_STATUS_E_FAILURE; + } + + adapter = qos_context->adapter; + ac_type = qos_context->ac_type; + ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + + hdd_debug("status %d flowid %d info %pK", + sme_status, flow_id, tspec_info); + + switch (sme_status) { + + case SME_QOS_STATUS_SETUP_SUCCESS_IND: + hdd_debug("Setup is complete"); + + /* there will always be a TSPEC returned with this + * status, even if a TSPEC is not exchanged OTA + */ + if (tspec_info) { + ac->is_tspec_valid = true; + memcpy(&ac->tspec, + tspec_info, sizeof(ac->tspec)); + } + ac->is_access_allowed = true; + ac->was_access_granted = true; + ac->is_access_pending = false; + ac->has_access_failed = false; + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; + hdd_wmm_notify_app(qos_context); + } + +#ifdef FEATURE_WLAN_ESE + /* Check if the inactivity interval is specified */ + if (tspec_info && tspec_info->inactivity_interval) { + hdd_debug("Inactivity timer value = %d for AC=%d", + tspec_info->inactivity_interval, ac_type); + hdd_wmm_enable_inactivity_timer(qos_context, + tspec_info-> + inactivity_interval); + } +#endif /* FEATURE_WLAN_ESE */ + + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(qos_context); + + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + hdd_debug("Setup is complete (U-APSD set previously)"); + + ac->is_access_allowed = true; + ac->was_access_granted = true; + ac->is_access_pending = false; + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(qos_context); + } + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + hdd_err("Setup failed"); + /* QoS setup failed */ + + ac->is_access_pending = false; + ac->has_access_failed = true; + ac->is_access_allowed = false; + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_FAILED; + + hdd_wmm_notify_app(qos_context); + } + + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + + /* Setting up QoS Failed, QoS context can be released. + * SME is releasing this flow information and if HDD + * doesn't release this context, next time if + * application uses the same handle to set-up QoS, HDD + * (as it has QoS context for this handle) will issue + * Modify QoS request to SME but SME will reject as now + * it has no information for this flow. + */ + hdd_wmm_free_context(qos_context); + break; + + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + hdd_err("Setup Invalid Params, notify TL"); + /* QoS setup failed */ + ac->is_access_allowed = false; + + if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) { + + /* we note the failure, but we also mark + * access as allowed so that the packets will + * flow. Note that the MAC will "do the right + * thing" + */ + ac->is_access_pending = false; + ac->has_access_failed = true; + ac->is_access_allowed = true; + + } else { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + hdd_err("Setup failed, not a QoS AP"); + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + hdd_info("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + hdd_debug("Setup pending"); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_SETUP_MODIFIED_IND: + hdd_debug("Setup modified"); + if (tspec_info) { + /* update the TSPEC */ + ac->is_tspec_valid = true; + memcpy(&ac->tspec, + tspec_info, sizeof(ac->tspec)); + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFIED; + hdd_wmm_notify_app(qos_context); + } + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(qos_context); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) { + + /* this was triggered by implicit QoS so we + * know packets are pending + */ + ac->is_access_pending = false; + ac->was_access_granted = true; + ac->is_access_allowed = true; + + } else { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + /* nothing to do for now */ + break; + + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED: + hdd_err("Setup successful but U-APSD failed"); + + if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) { + + /* QoS setup was successful but setting U=APSD + * failed. Since the OTA part of the request + * was successful, we don't mark this as a + * failure. the packets will flow. Note that + * the MAC will "do the right thing" + */ + ac->was_access_granted = true; + ac->is_access_allowed = true; + ac->has_access_failed = false; + ac->is_access_pending = false; + + } else { + hdd_info("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED; + hdd_wmm_notify_app(qos_context); + } + + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(qos_context); + + break; + + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + hdd_debug("Release is complete"); + + if (tspec_info) { + hdd_debug("flows still active"); + + /* there is still at least one flow active for + * this AC so update the AC state + */ + memcpy(&ac->tspec, + tspec_info, sizeof(ac->tspec)); + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_enable_tl_uapsd(qos_context); + } else { + hdd_debug("last flow"); + + /* this is the last flow active for this AC so + * update the AC state + */ + ac->is_tspec_valid = false; + + /* DELTS is successful, do not allow */ + ac->is_access_allowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(qos_context); + } + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + hdd_wmm_notify_app(qos_context); + } + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + + /* we are done with this flow */ + hdd_wmm_free_context(qos_context); + break; + + case SME_QOS_STATUS_RELEASE_FAILURE_RSP: + hdd_debug("Release failure"); + + /* we don't need to update our state or TL since + * nothing has changed + */ + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + hdd_wmm_notify_app(qos_context); + } + + break; + + case SME_QOS_STATUS_RELEASE_QOS_LOST_IND: + hdd_debug("QOS Lost indication received"); + + /* current TSPEC is no longer valid */ + ac->is_tspec_valid = false; + /* AP has sent DELTS, do not allow */ + ac->is_access_allowed = false; + + /* need to tell TL to update its UAPSD handling */ + hdd_wmm_disable_tl_uapsd(qos_context); + + if (HDD_WMM_HANDLE_IMPLICIT == qos_context->handle) { + /* we no longer have implicit access granted */ + ac->was_access_granted = false; + ac->has_access_failed = false; + } else { + hdd_debug("Explicit Qos, notifying user space"); + + /* this was triggered by an application */ + qos_context->status = HDD_WLAN_WMM_STATUS_LOST; + hdd_wmm_notify_app(qos_context); + } + + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + + /* we are done with this flow */ + hdd_wmm_free_context(qos_context); + break; + + case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: + hdd_debug("Release pending"); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: + hdd_err("Release Invalid Params"); + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND: + hdd_debug("Modification is complete, notify TL"); + + /* there will always be a TSPEC returned with this + * status, even if a TSPEC is not exchanged OTA + */ + if (tspec_info) { + ac->is_tspec_valid = true; + memcpy(&ac->tspec, + tspec_info, sizeof(ac->tspec)); + } + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS; + hdd_wmm_notify_app(qos_context); + } + /* notify TL to enable trigger frames if necessary */ + hdd_wmm_enable_tl_uapsd(qos_context); + + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: + /* the flow modification failed so we'll leave in + * place whatever existed beforehand + */ + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: + hdd_debug("modification pending"); + /* not a callback status -- ignore if we get it */ + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + /* the flow modification was successful but no QoS + * changes required + */ + + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + /* invalid params -- notify the application */ + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + hdd_wmm_notify_app(qos_context); + } + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING: + /* nothing to do for now. when APSD is established we'll have work to do */ + break; + + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED: + hdd_err("Modify successful but U-APSD failed"); + + /* QoS modification was successful but setting U=APSD + * failed. This will always be an explicit QoS + * instance, so all we can do is notify the + * application and let it clean up. + */ + if (HDD_WMM_HANDLE_IMPLICIT != qos_context->handle) { + /* this was triggered by an application */ + qos_context->status = + HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED; + hdd_wmm_notify_app(qos_context); + } + /* Since U-APSD portion failed disabled trigger frame + * generation + */ + hdd_wmm_disable_tl_uapsd(qos_context); + + break; + + case SME_QOS_STATUS_HANDING_OFF: + /* no roaming so we won't see this */ + break; + + case SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND: + /* need to tell TL to stop trigger frame generation */ + hdd_wmm_disable_tl_uapsd(qos_context); + break; + + case SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND: + /* need to tell TL to start sending trigger frames again */ + hdd_wmm_enable_tl_uapsd(qos_context); + break; + + default: + hdd_err("unexpected SME Status=%d", sme_status); + QDF_ASSERT(0); + } + + /* if Tspec only allows downstream traffic then access is not + * allowed + */ + if (ac->is_tspec_valid && + (ac->tspec.ts_info.direction == + SME_QOS_WMM_TS_DIR_DOWNLINK)) { + ac->is_access_allowed = false; + } + /* if we have valid Tpsec or if ACM bit is not set, allow access */ + if ((ac->is_tspec_valid && + (ac->tspec.ts_info.direction != + SME_QOS_WMM_TS_DIR_DOWNLINK)) || !ac->is_access_required) { + ac->is_access_allowed = true; + } + + hdd_debug("complete, access for TL AC %d is%sallowed", + ac_type, ac->is_access_allowed ? " " : " not "); + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_wmmps_helper() - Function to set uapsd psb dynamically + * + * @adapter: [in] pointer to adapter structure + * @ptr: [in] pointer to command buffer + * + * Return: Zero on success, appropriate error on failure. + */ +int hdd_wmmps_helper(struct hdd_adapter *adapter, uint8_t *ptr) +{ + if (!adapter) { + hdd_err("adapter is NULL"); + return -EINVAL; + } + if (!ptr) { + hdd_err("ptr is NULL"); + return -EINVAL; + } + /* convert ASCII to integer */ + adapter->configured_psb = ptr[9] - '0'; + adapter->psb_changed = HDD_PSB_CHANGED; + + return 0; +} + +/** + * __hdd_wmm_do_implicit_qos() - Function which will attempt to setup + * QoS for any AC requiring it. + * @qos_context: the QoS context to operate against + * + * Return: none + */ +static void __hdd_wmm_do_implicit_qos(struct hdd_wmm_qos_context *qos_context) +{ + struct hdd_adapter *adapter; + sme_ac_enum_type ac_type; + struct hdd_wmm_ac_status *ac; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + enum sme_qos_statustype sme_status; +#endif + struct sme_qos_wmmtspecinfo tspec; + struct hdd_context *hdd_ctx; + mac_handle_t mac_handle; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t dir_ac, mask = 0; + uint16_t nom_msdu_size_ac = 0; + uint32_t rate_ac = 0; + uint16_t sba_ac = 0; + uint32_t uapsd_value = 0; + bool is_ts_burst_enable; + enum mlme_ts_info_ack_policy ack_policy; + + hdd_debug("Entered, context %pK", qos_context); + + adapter = qos_context->adapter; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + if (wlan_hdd_validate_context(hdd_ctx)) + return; + + mac_handle = hdd_ctx->mac_handle; + + ac_type = qos_context->ac_type; + ac = &adapter->hdd_wmm_status.ac_status[ac_type]; + + hdd_debug("adapter %pK ac_type %d", adapter, ac_type); + + if (!ac->is_access_needed) { + hdd_err("AC %d doesn't need service", ac_type); + qos_context->magic = 0; + qdf_mem_free(qos_context); + return; + } + + ac->is_access_pending = true; + ac->is_access_needed = false; + + memset(&tspec, 0, sizeof(tspec)); + + tspec.ts_info.psb = adapter->configured_psb; + + switch (ac_type) { + case SME_AC_VO: + tspec.ts_info.up = SME_QOS_WMM_UP_VO; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { + status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc, + &mask); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_mask failed"); + return; + } + tspec.ts_info.psb = (mask & SME_QOS_UAPSD_VO) ? 1 : 0; + } + status = ucfg_mlme_get_wmm_dir_ac_vo(hdd_ctx->psoc, + &dir_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get infra_dir_ac_vo failed"); + return; + } + tspec.ts_info.direction = dir_ac; + + tspec.ts_info.tid = 255; + + status = ucfg_mlme_get_wmm_uapsd_vo_srv_intv(hdd_ctx->psoc, + &uapsd_value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get uapsd_srv_intv failed"); + return; + } + tspec.min_service_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_uapsd_vo_sus_intv(hdd_ctx->psoc, + &uapsd_value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get uapsd_vo_sus_intv failed"); + return; + } + tspec.suspension_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_mean_data_rate_ac_vo(hdd_ctx->psoc, + &rate_ac); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get mean_data_rate_ac_vo failed"); + return; + } + tspec.mean_data_rate = rate_ac; + + status = ucfg_mlme_get_wmm_min_phy_rate_ac_vo(hdd_ctx->psoc, + &rate_ac); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get min_phy_rate_ac_vo failed"); + return; + } + tspec.min_phy_rate = rate_ac; + + status = ucfg_mlme_get_wmm_nom_msdu_size_ac_vo(hdd_ctx->psoc, + &nom_msdu_size_ac); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get nom_msdu_size_ac_vo failed"); + return; + } + tspec.nominal_msdu_size = nom_msdu_size_ac; + + status = ucfg_mlme_get_wmm_sba_ac_vo(hdd_ctx->psoc, + &sba_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get sba_ac_vo failed"); + return; + } + tspec.surplus_bw_allowance = sba_ac; + + break; + case SME_AC_VI: + tspec.ts_info.up = SME_QOS_WMM_UP_VI; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { + status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc, + &mask); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_mask failed"); + return; + } + tspec.ts_info.psb = (mask & SME_QOS_UAPSD_VI) ? 1 : 0; + } + status = ucfg_mlme_get_wmm_dir_ac_vi( + hdd_ctx->psoc, &dir_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get infra_dir_ac_vi failed"); + return; + } + tspec.ts_info.direction = dir_ac; + + tspec.ts_info.tid = 255; + status = ucfg_mlme_get_wmm_uapsd_vi_srv_intv( + hdd_ctx->psoc, &uapsd_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_vi_srv_intv failed"); + return; + } + tspec.min_service_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_uapsd_vi_sus_intv( + hdd_ctx->psoc, &uapsd_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_vi_sus_intv failed"); + return; + } + tspec.suspension_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_mean_data_rate_ac_vi( + hdd_ctx->psoc, &rate_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get mean_data_rate_ac_vi failed"); + return; + } + tspec.mean_data_rate = rate_ac; + + status = ucfg_mlme_get_wmm_min_phy_rate_ac_vi( + hdd_ctx->psoc, &rate_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get min_phy_rate_ac_vi failed"); + return; + } + tspec.min_phy_rate = rate_ac; + + status = ucfg_mlme_get_wmm_nom_msdu_size_ac_vi( + hdd_ctx->psoc, &nom_msdu_size_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get nom_msdu_size_ac_vi failed"); + return; + } + tspec.nominal_msdu_size = nom_msdu_size_ac; + + status = ucfg_mlme_get_wmm_sba_ac_vi( + hdd_ctx->psoc, &sba_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get sba_ac_vi failed"); + return; + } + tspec.surplus_bw_allowance = sba_ac; + + break; + default: + case SME_AC_BE: + tspec.ts_info.up = SME_QOS_WMM_UP_BE; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { + status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc, + &mask); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_mask failed"); + return; + } + tspec.ts_info.psb = (mask & SME_QOS_UAPSD_BE) ? 1 : 0; + } + status = ucfg_mlme_get_wmm_dir_ac_be(hdd_ctx->psoc, &dir_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get infra_dir_ac_be failed"); + return; + } + tspec.ts_info.direction = dir_ac; + + tspec.ts_info.tid = 255; + status = ucfg_mlme_get_wmm_uapsd_be_srv_intv(hdd_ctx->psoc, + &uapsd_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_vi_srv_intv failed"); + return; + } + tspec.min_service_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_uapsd_be_sus_intv(hdd_ctx->psoc, + &uapsd_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_vi_sus_intv failed"); + return; + } + tspec.suspension_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_mean_data_rate_ac_be(hdd_ctx->psoc, + &rate_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get mean_data_rate_ac_be failed"); + return; + } + tspec.mean_data_rate = rate_ac; + + status = ucfg_mlme_get_wmm_min_phy_rate_ac_be(hdd_ctx->psoc, + &rate_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get min_phy_rate_ac_be failed"); + return; + } + tspec.min_phy_rate = rate_ac; + + status = ucfg_mlme_get_wmm_nom_msdu_size_ac_be(hdd_ctx->psoc, + &nom_msdu_size_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get nom_msdu_size_ac_be failed"); + return; + } + tspec.nominal_msdu_size = nom_msdu_size_ac; + + status = ucfg_mlme_get_wmm_sba_ac_be(hdd_ctx->psoc, &sba_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get sba_ac_be failed"); + return; + } + tspec.surplus_bw_allowance = sba_ac; + + break; + case SME_AC_BK: + tspec.ts_info.up = SME_QOS_WMM_UP_BK; + /* Check if there is any valid configuration from framework */ + if (HDD_PSB_CFG_INVALID == adapter->configured_psb) { + status = ucfg_mlme_get_wmm_uapsd_mask(hdd_ctx->psoc, + &mask); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_mask failed"); + return; + } + tspec.ts_info.psb = (mask & SME_QOS_UAPSD_BK) ? 1 : 0; + } + + status = ucfg_mlme_get_wmm_dir_ac_bk(hdd_ctx->psoc, &dir_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get infra_dir_ac_bk failed"); + return; + } + tspec.ts_info.direction = dir_ac; + + tspec.ts_info.tid = 255; + status = ucfg_mlme_get_wmm_uapsd_bk_srv_intv(hdd_ctx->psoc, + &uapsd_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_bk_srv_intv failed"); + return; + } + tspec.min_service_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_uapsd_bk_sus_intv(hdd_ctx->psoc, + &uapsd_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_bk_sus_intv failed"); + return; + } + tspec.suspension_interval = uapsd_value; + + status = ucfg_mlme_get_wmm_mean_data_rate_ac_bk(hdd_ctx->psoc, + &rate_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get mean_data_rate_ac_bk failed"); + return; + } + tspec.mean_data_rate = rate_ac; + + status = ucfg_mlme_get_wmm_min_phy_rate_ac_bk(hdd_ctx->psoc, + &rate_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get min_phy_rate_ac_bk failed"); + return; + } + tspec.min_phy_rate = rate_ac; + + status = + ucfg_mlme_get_wmm_nom_msdu_size_ac_bk(hdd_ctx->psoc, + &nom_msdu_size_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get nom_msdu_size_ac_bk failed"); + return; + } + tspec.nominal_msdu_size = nom_msdu_size_ac; + + status = ucfg_mlme_get_wmm_sba_ac_bk(hdd_ctx->psoc, &sba_ac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get sba_ac_bk failed"); + return; + } + tspec.surplus_bw_allowance = sba_ac; + + break; + } +#ifdef FEATURE_WLAN_ESE + ucfg_mlme_get_inactivity_interval(hdd_ctx->psoc, &uapsd_value); + tspec.inactivity_interval = uapsd_value; +#endif + ucfg_mlme_get_is_ts_burst_size_enable(hdd_ctx->psoc, + &is_ts_burst_enable); + tspec.ts_info.burst_size_defn = is_ts_burst_enable; + + ucfg_mlme_get_ts_info_ack_policy(hdd_ctx->psoc, &ack_policy); + switch (ack_policy) { + case TS_INFO_ACK_POLICY_NORMAL_ACK: + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + + case TS_INFO_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK: + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + + default: + /* unknown */ + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + + if (tspec.ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { + if (!sme_qos_is_ts_info_ack_policy_valid( + mac_handle, &tspec, + adapter->deflink->vdev_id)) { + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + } + } + + mutex_lock(&adapter->hdd_wmm_status.mutex); + list_add(&qos_context->node, &adapter->hdd_wmm_status.context_list); + mutex_unlock(&adapter->hdd_wmm_status.mutex); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_status = sme_qos_setup_req(mac_handle, + adapter->deflink->vdev_id, + &tspec, + hdd_wmm_sme_callback, + qos_context, + tspec.ts_info.up, + &qos_context->flow_id); + + hdd_debug("sme_qos_setup_req returned %d flowid %d", + sme_status, qos_context->flow_id); + + /* need to check the return values and act appropriately */ + switch (sme_status) { + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + /* setup is pending, so no more work to do now. all + * further work will be done in hdd_wmm_sme_callback() + */ + hdd_debug("Setup is pending, no further work"); + + break; + + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encountered an internal error. in either case SME + * won't ever reference this context so free the + * record + */ + hdd_wmm_free_context(qos_context); + /* start packets flowing */ + fallthrough; + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + /* no ACM in effect, no need to setup U-APSD */ + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + /* no ACM in effect, U-APSD is desired but was already setup */ + + /* for these cases everything is already setup so we + * can signal TL that it has work to do + */ + hdd_debug("Setup is complete, notify TL"); + + ac->is_access_allowed = true; + ac->was_access_granted = true; + ac->is_access_pending = false; + + break; + + default: + hdd_err("unexpected SME Status=%d", sme_status); + QDF_ASSERT(0); + } +#endif + +} + +/** + * hdd_wmm_do_implicit_qos() - SSR wrapper function for hdd_wmm_do_implicit_qos + * @work: pointer to work_struct + * + * Return: none + */ +static void hdd_wmm_do_implicit_qos(struct work_struct *work) +{ + struct hdd_wmm_qos_context *qos_ctx = + container_of(work, struct hdd_wmm_qos_context, + implicit_qos_work); + struct osif_vdev_sync *vdev_sync; + + if (qos_ctx->magic != HDD_WMM_CTX_MAGIC) { + hdd_err("Invalid QoS Context"); + return; + } + + if (osif_vdev_sync_op_start(qos_ctx->adapter->dev, &vdev_sync)) + return; + + __hdd_wmm_do_implicit_qos(qos_ctx); + + osif_vdev_sync_op_stop(vdev_sync); +} + +QDF_STATUS hdd_send_dscp_up_map_to_fw(struct hdd_adapter *adapter) +{ + uint32_t *dscp_to_up_map = adapter->dscp_to_up_map; + struct wlan_objmgr_vdev *vdev; + int ret; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_FWOL_NB_ID); + + if (vdev) { + /* Send DSCP to TID map table to FW */ + ret = os_if_fwol_send_dscp_up_map_to_fw(vdev, dscp_to_up_map); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_FWOL_NB_ID); + if (ret && ret != -EOPNOTSUPP) + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_fill_dscp_to_up_map() - Fill up dscp_to_up_map table with default values + * @dscp_to_up_map: Array of DSCP-to-UP map + * + * This function will fill up the DSCP-to-UP map table with default values. + * + * Return: QDF_STATUS enumeration + */ +static inline void hdd_fill_dscp_to_up_map( + enum sme_qos_wmmuptype *dscp_to_up_map) +{ + uint8_t dscp; + + /* + * DSCP to User Priority Lookup Table + * By default use the 3 Precedence bits of DSCP as the User Priority + * + * In case of changing the default map values, need to take care of + * hdd_custom_dscp_up_map as well. + */ + for (dscp = 0; dscp <= WLAN_MAX_DSCP; dscp++) + dscp_to_up_map[dscp] = dscp >> 3; + + /* Special case for Expedited Forwarding (DSCP 46) in default mapping */ + dscp_to_up_map[DSCP(46)] = SME_QOS_WMM_UP_VO; +} + +#ifdef WLAN_CUSTOM_DSCP_UP_MAP +/** + * hdd_custom_dscp_up_map() - Customize dscp_to_up_map based on RFC8325 + * @dscp_to_up_map: Array of DSCP-to-UP map + * + * This function will customize the DSCP-to-UP map table based on RFC8325.. + * + * Return: QDF_STATUS enumeration + */ +static inline QDF_STATUS hdd_custom_dscp_up_map( + enum sme_qos_wmmuptype *dscp_to_up_map) +{ + /* + * Customizing few of DSCP to UP mapping based on RFC8325, + * those are different from default hdd_fill_dscp_to_up_map values. + * So, below changes are always relative to hdd_fill_dscp_to_up_map. + */ + dscp_to_up_map[DSCP(10)] = SME_QOS_WMM_UP_BE; + dscp_to_up_map[DSCP(12)] = SME_QOS_WMM_UP_BE; + dscp_to_up_map[DSCP(14)] = SME_QOS_WMM_UP_BE; + dscp_to_up_map[DSCP(16)] = SME_QOS_WMM_UP_BE; + + dscp_to_up_map[DSCP(18)] = SME_QOS_WMM_UP_EE; + dscp_to_up_map[DSCP(20)] = SME_QOS_WMM_UP_EE; + dscp_to_up_map[DSCP(22)] = SME_QOS_WMM_UP_EE; + + dscp_to_up_map[DSCP(24)] = SME_QOS_WMM_UP_CL; + dscp_to_up_map[DSCP(26)] = SME_QOS_WMM_UP_CL; + dscp_to_up_map[DSCP(28)] = SME_QOS_WMM_UP_CL; + dscp_to_up_map[DSCP(30)] = SME_QOS_WMM_UP_CL; + + dscp_to_up_map[DSCP(44)] = SME_QOS_WMM_UP_VO; + + dscp_to_up_map[DSCP(48)] = SME_QOS_WMM_UP_NC; + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS hdd_custom_dscp_up_map( + enum sme_qos_wmmuptype *dscp_to_up_map) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_CUSTOM_DSCP_UP_MAP */ + +/** + * hdd_wmm_dscp_initial_state() - initialize the WMM DSCP configuration + * @adapter : [in] pointer to Adapter context + * + * This function will initialize the WMM DSCP configuration of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs or via QoS Map sent OTA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_dscp_initial_state(struct hdd_adapter *adapter) +{ + enum sme_qos_wmmuptype *dscp_to_up_map = adapter->dscp_to_up_map; + struct wlan_objmgr_psoc *psoc = adapter->hdd_ctx->psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!psoc) { + hdd_err("Invalid psoc handle"); + return QDF_STATUS_E_FAILURE; + } + + hdd_fill_dscp_to_up_map(dscp_to_up_map); + + if (hdd_custom_dscp_up_map(dscp_to_up_map) == QDF_STATUS_SUCCESS) { + /* Send DSCP to TID map table to FW */ + status = hdd_send_dscp_up_map_to_fw(adapter); + } + + return status; +} + +/** + * hdd_wmm_adapter_init() - initialize the WMM configuration of an adapter + * @adapter: [in] pointer to Adapter context + * + * This function will initialize the WMM configuration and status of an + * adapter to an initial state. The configuration can later be + * overwritten via application APIs + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_init(struct hdd_adapter *adapter) +{ + struct hdd_wmm_ac_status *ac_status; + sme_ac_enum_type ac_type; + + hdd_enter(); + + hdd_wmm_dscp_initial_state(adapter); + + adapter->hdd_wmm_status.qap = false; + INIT_LIST_HEAD(&adapter->hdd_wmm_status.context_list); + mutex_init(&adapter->hdd_wmm_status.mutex); + + for (ac_type = 0; ac_type < WLAN_MAX_AC; ac_type++) { + ac_status = &adapter->hdd_wmm_status.ac_status[ac_type]; + ac_status->is_access_required = false; + ac_status->is_access_needed = false; + ac_status->is_access_pending = false; + ac_status->has_access_failed = false; + ac_status->was_access_granted = false; + ac_status->is_access_allowed = false; + ac_status->is_tspec_valid = false; + ac_status->is_uapsd_info_valid = false; + } + /* Invalid value(0xff) to indicate psb not configured through + * framework initially. + */ + adapter->configured_psb = HDD_PSB_CFG_INVALID; + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_clear() - Function which will clear the WMM status + * for all the ACs + * + * @adapter: [in] pointer to Adapter context + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_clear(struct hdd_adapter *adapter) +{ + struct hdd_wmm_ac_status *ac_status; + sme_ac_enum_type ac_type; + + hdd_enter(); + for (ac_type = 0; ac_type < WLAN_MAX_AC; ac_type++) { + ac_status = &adapter->hdd_wmm_status.ac_status[ac_type]; + ac_status->is_access_required = false; + ac_status->is_access_needed = false; + ac_status->is_access_pending = false; + ac_status->has_access_failed = false; + ac_status->was_access_granted = false; + ac_status->is_access_allowed = false; + ac_status->is_tspec_valid = false; + ac_status->is_uapsd_info_valid = false; + } + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_adapter_close() - WMM close function + * @adapter: [in] pointer to adapter context + * + * Function which will perform any necessary work to to clean up the + * WMM functionality prior to the kernel module unload. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_adapter_close(struct hdd_adapter *adapter) +{ + struct hdd_wmm_qos_context *qos_context; + + hdd_enter(); + + /* free any context records that we still have linked */ + while (!list_empty(&adapter->hdd_wmm_status.context_list)) { + qos_context = + list_first_entry(&adapter->hdd_wmm_status.context_list, + struct hdd_wmm_qos_context, node); + + hdd_wmm_disable_inactivity_timer(qos_context); + + if (qos_context->handle == HDD_WMM_HANDLE_IMPLICIT + && qos_context->magic == HDD_WMM_CTX_MAGIC) + cds_flush_work(&qos_context->implicit_qos_work); + + hdd_wmm_free_context(qos_context); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_check_upgrade_vo_vi_qos() - Check and upgrade QOS for UDP packets + * based on request type received + * @adapter: [in] pointer to the adapter context (Should not be invalid) + * @user_pri: [out] priority set for this packet + * + * This function checks for the request type and upgrade based on request type + * + * UDP_QOS_UPGRADE_ALL: Upgrade QoS of all UDP packets if the current set + * priority is below the pre-configured threshold for upgrade. + * + * UDP_QOS_UPGRADE_BK_BE: Upgrade QoS of all UDP packets if the current set + * priority is below the AC VI. + */ +static inline void +hdd_check_upgrade_vo_vi_qos(struct hdd_adapter *adapter, + enum sme_qos_wmmuptype *user_pri) +{ + switch (adapter->udp_qos_upgrade_type) { + case UDP_QOS_UPGRADE_ALL: + if (*user_pri < + qca_wlan_ac_to_sme_qos(adapter->upgrade_udp_qos_threshold)) + *user_pri = qca_wlan_ac_to_sme_qos( + adapter->upgrade_udp_qos_threshold); + break; + case UDP_QOS_UPGRADE_BK_BE: + if (*user_pri < qca_wlan_ac_to_sme_qos(QCA_WLAN_AC_VI)) + *user_pri = qca_wlan_ac_to_sme_qos( + adapter->upgrade_udp_qos_threshold); + break; + default: + break; + } +} + +/** + * hdd_check_and_upgrade_udp_qos() - Check and upgrade the qos for UDP packets + * if the current set priority is below the + * pre-configured threshold for upgrade. + * @adapter: [in] pointer to the adapter context (Should not be invalid) + * @skb: [in] pointer to the packet to be transmitted + * @user_pri: [out] priority set for this packet + * + * This function checks if the packet is a UDP packet and upgrades its + * priority if its below the pre-configured upgrade threshold. + * The upgrade order is as below: + * BK -> BE -> VI -> VO + * + * Return: none + */ +static inline void +hdd_check_and_upgrade_udp_qos(struct hdd_adapter *adapter, + qdf_nbuf_t skb, + enum sme_qos_wmmuptype *user_pri) +{ + /* Upgrade UDP pkt priority alone */ + if (!(qdf_nbuf_is_ipv4_udp_pkt(skb) || qdf_nbuf_is_ipv6_udp_pkt(skb))) + return; + + switch (adapter->upgrade_udp_qos_threshold) { + case QCA_WLAN_AC_BK: + break; + case QCA_WLAN_AC_BE: + if (*user_pri == qca_wlan_ac_to_sme_qos(QCA_WLAN_AC_BK)) + *user_pri = qca_wlan_ac_to_sme_qos(QCA_WLAN_AC_BE); + + break; + case QCA_WLAN_AC_VI: + case QCA_WLAN_AC_VO: + hdd_check_upgrade_vo_vi_qos(adapter, user_pri); + break; + default: + break; + } +} + +/** + * hdd_wmm_classify_critical_pkt() - Function checks and classifies critical skb + * @skb: pointer to network buffer + * @user_pri: user priority of the OS packet to be determined + * @is_critical: pointer to be marked true for a critical packet + * + * Function checks if the packet is one of the critical packets and determines + * 'user_pri' for it. EAPOL, ARP, DHCP(v4,v6), NS, NA are considered critical. + * + * Note that wlan_hdd_mark_critical_pkt is used to mark packet type in CB for + * these critical packets. This is done as skb->cb amay be overwritten between + * _select_queue and_hard_start_xmit functions. hdd_wmm_classify_critical_pkt + * and wlan_hdd_mark_critical_pkt should be in sync w.r.t packet types. + * + * Return: None + */ +static +void hdd_wmm_classify_critical_pkt(struct sk_buff *skb, + enum sme_qos_wmmuptype *user_pri, + bool *is_critical) +{ + enum qdf_proto_subtype proto_subtype; + + /* Send EAPOL on TID 6(VO). Rest are sent on TID 0(BE). */ + + if (qdf_nbuf_is_ipv4_eapol_pkt(skb)) { + *is_critical = true; + *user_pri = SME_QOS_WMM_UP_VO; + } else if (qdf_nbuf_is_ipv4_arp_pkt(skb)) { + *is_critical = true; + *user_pri = SME_QOS_WMM_UP_BE; + } else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb)) { + *is_critical = true; + *user_pri = SME_QOS_WMM_UP_BE; + } else if (qdf_nbuf_is_ipv6_dhcp_pkt(skb)) { + *is_critical = true; + *user_pri = SME_QOS_WMM_UP_BE; + } else if (qdf_nbuf_is_icmpv6_pkt(skb)) { + proto_subtype = qdf_nbuf_get_icmpv6_subtype(skb); + switch (proto_subtype) { + case QDF_PROTO_ICMPV6_NA: + case QDF_PROTO_ICMPV6_NS: + *is_critical = true; + *user_pri = SME_QOS_WMM_UP_BE; + break; + default: + break; + } + } +} + +#ifdef DP_TRAFFIC_END_INDICATION +/** + * hdd_wmm_traffic_end_indication_is_enable() - Get feature enable/disable + * status + * @adapter: hdd adapter handle + * + * Return: true if feature is enable else false + */ +static inline bool +hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter *adapter) +{ + return qdf_unlikely(adapter->traffic_end_ind_en); +} +#else +static inline bool +hdd_wmm_traffic_end_indication_is_enable(struct hdd_adapter *adapter) +{ + return false; +} +#endif + +static +void hdd_wmm_get_user_priority_from_ip_tos(struct hdd_adapter *adapter, + struct sk_buff *skb, + enum sme_qos_wmmuptype *user_pri) + +{ + unsigned char dscp; + unsigned char tos; + union generic_ethhdr *eth_hdr; + struct iphdr *ip_hdr; + struct ipv6hdr *ipv6hdr; + unsigned char *pkt; + struct wlan_objmgr_psoc *psoc; + + /* this code is executed for every packet therefore + * all debug code is kept conditional + */ + +#ifdef HDD_WMM_DEBUG + hdd_enter(); +#endif /* HDD_WMM_DEBUG */ + + pkt = skb->data; + eth_hdr = (union generic_ethhdr *)pkt; + +#ifdef HDD_WMM_DEBUG + hdd_debug("proto is 0x%04x", skb->protocol); +#endif /* HDD_WMM_DEBUG */ + + if (eth_hdr->eth_II.h_proto == htons(ETH_P_IP)) { + /* case 1: Ethernet II IP packet */ + ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_II)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_debug("Ethernet II IP Packet, tos is %d", tos); +#endif /* HDD_WMM_DEBUG */ + + } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_IPV6)) { + ipv6hdr = ipv6_hdr(skb); + tos = ntohs(*(const __be16 *)ipv6hdr) >> 4; +#ifdef HDD_WMM_DEBUG + hdd_debug("Ethernet II IPv6 Packet, tos is %d", tos); +#endif /* HDD_WMM_DEBUG */ + } else if ((ntohs(eth_hdr->eth_II.h_proto) < WLAN_MIN_PROTO) && + (eth_hdr->eth_8023.h_snap.dsap == WLAN_SNAP_DSAP) && + (eth_hdr->eth_8023.h_snap.ssap == WLAN_SNAP_SSAP) && + (eth_hdr->eth_8023.h_snap.ctrl == WLAN_SNAP_CTRL) && + (eth_hdr->eth_8023.h_proto == htons(ETH_P_IP))) { + /* case 2: 802.3 LLC/SNAP IP packet */ + ip_hdr = (struct iphdr *)&pkt[sizeof(eth_hdr->eth_8023)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_debug("802.3 LLC/SNAP IP Packet, tos is %d", tos); +#endif /* HDD_WMM_DEBUG */ + } else if (eth_hdr->eth_II.h_proto == htons(ETH_P_8021Q)) { + /* VLAN tagged */ + + if (eth_hdr->eth_IIv.h_vlan_encapsulated_proto == + htons(ETH_P_IP)) { + /* case 3: Ethernet II vlan-tagged IP packet */ + ip_hdr = + (struct iphdr *) + &pkt[sizeof(eth_hdr->eth_IIv)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_debug("Ether II VLAN tagged IP Packet, tos is %d", + tos); +#endif /* HDD_WMM_DEBUG */ + } else if ((ntohs(eth_hdr->eth_IIv.h_vlan_encapsulated_proto) + < WLAN_MIN_PROTO) && + (eth_hdr->eth_8023v.h_snap.dsap == + WLAN_SNAP_DSAP) + && (eth_hdr->eth_8023v.h_snap.ssap == + WLAN_SNAP_SSAP) + && (eth_hdr->eth_8023v.h_snap.ctrl == + WLAN_SNAP_CTRL) + && (eth_hdr->eth_8023v.h_proto == + htons(ETH_P_IP))) { + /* case 4: 802.3 LLC/SNAP vlan-tagged IP packet */ + ip_hdr = + (struct iphdr *) + &pkt[sizeof(eth_hdr->eth_8023v)]; + tos = ip_hdr->tos; +#ifdef HDD_WMM_DEBUG + hdd_debug("802.3 LLC/SNAP VLAN tagged IP Packet, tos is %d", + tos); +#endif /* HDD_WMM_DEBUG */ + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + hdd_warn("VLAN tagged Unhandled Protocol, using default tos"); +#endif /* HDD_WMM_DEBUG */ + tos = 0; + } + } else { + /* default */ +#ifdef HDD_WMM_DEBUG + hdd_warn("Unhandled Protocol, using default tos"); +#endif /* HDD_WMM_DEBUG */ + /* Give the highest priority to 802.1x packet */ + if (eth_hdr->eth_II.h_proto == + htons(HDD_ETHERTYPE_802_1_X)) { + tos = 0xC0; + } else + tos = 0; + } + + dscp = (tos >> 2) & 0x3f; + if (hdd_wmm_traffic_end_indication_is_enable(adapter)) { + psoc = adapter->hdd_ctx->psoc; + ucfg_dp_traffic_end_indication_update_dscp( + psoc, adapter->deflink->vdev_id, &dscp); + } + *user_pri = adapter->dscp_to_up_map[dscp]; + +#ifdef HDD_WMM_DEBUG + hdd_debug("tos is %d, dscp is %d, up is %d", tos, dscp, *user_pri); +#endif /* HDD_WMM_DEBUG */ +} + +/** + * hdd_wmm_classify_pkt() - Function to classify skb into WMM AC based on DSCP + * + * @adapter: adapter upon which the packet is being transmitted + * @skb: pointer to network buffer + * @user_pri: user priority of the OS packet + * @is_critical: pointer to be marked true for a critical packet + * + * Function checks if the packet is one of the critical packets and determines + * 'user_pri' for it. Else it uses IP TOS value to determine 'user_pri'. + * It is the responsibility of caller to set the user_pri to skb->priority. + * Return: None + */ +static +void hdd_wmm_classify_pkt(struct hdd_adapter *adapter, + struct sk_buff *skb, + enum sme_qos_wmmuptype *user_pri, + bool *is_critical) +{ + hdd_wmm_classify_critical_pkt(skb, user_pri, is_critical); + + if (false == *is_critical) { + hdd_wmm_get_user_priority_from_ip_tos(adapter, skb, user_pri); + hdd_check_and_upgrade_udp_qos(adapter, skb, user_pri); + } +} + +#ifdef QCA_SUPPORT_TX_MIN_RATES_FOR_SPECIAL_FRAMES +void hdd_wmm_classify_pkt_cb(void *adapter, + struct sk_buff *skb) +{ + enum sme_qos_wmmuptype user_pri = SME_QOS_WMM_UP_BE; + bool is_critical = false; + + hdd_wmm_classify_critical_pkt(skb, &user_pri, &is_critical); + + if (is_critical) { + skb->priority = user_pri; + QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL(skb) = true; + } +} +#endif + +#ifdef TX_MULTIQ_PER_AC +/** + * hdd_get_tx_queue_for_ac() - Get the netdev tx queue index + * based on access category + * @adapter: adapter upon which the packet is being transmitted + * @skb: pointer to network buffer + * @ac: access category + * + * Return: tx queue index + */ +static +uint16_t hdd_get_tx_queue_for_ac(struct hdd_adapter *adapter, + struct sk_buff *skb, uint16_t ac) +{ + struct sock *sk = skb->sk; + int new_index; + int cpu = qdf_get_smp_processor_id(); + struct hdd_tx_rx_stats *stats = + &adapter->deflink->hdd_stats.tx_rx_stats; + + if (qdf_unlikely(ac == HDD_LINUX_AC_HI_PRIO)) + return TX_GET_QUEUE_IDX(HDD_LINUX_AC_HI_PRIO, 0); + + if (!sk) { + /* + * Neither valid socket nor skb_hash so default to the + * first queue for the access category. + */ + if (qdf_unlikely(!skb->sw_hash && !skb->l4_hash)) { + ++stats->per_cpu[cpu].inv_sk_and_skb_hash; + + return TX_GET_QUEUE_IDX(ac, 0); + } + ++stats->per_cpu[cpu].qselect_existing_skb_hash; + + return TX_GET_QUEUE_IDX(ac, + reciprocal_scale(skb->hash, + TX_QUEUES_PER_AC)); + } + + if (sk->sk_tx_queue_mapping != NO_QUEUE_MAPPING && + sk->sk_tx_queue_mapping < NUM_TX_QUEUES) { + ++stats->per_cpu[cpu].qselect_sk_tx_map; + return sk->sk_tx_queue_mapping; + } + + ++stats->per_cpu[cpu].qselect_skb_hash_calc; + new_index = TX_GET_QUEUE_IDX(ac, + reciprocal_scale(skb_get_hash(skb), + TX_QUEUES_PER_AC)); + + if (sk_fullsock(sk) && rcu_access_pointer(sk->sk_dst_cache)) + sk_tx_queue_set(sk, new_index); + + return new_index; +} +#else +static inline +uint16_t hdd_get_tx_queue_for_ac(struct hdd_adapter *adapter, + struct sk_buff *skb, uint16_t ac) { + return ac; +} +#endif + +/** + * __hdd_get_queue_index() - get queue index + * @up: user priority + * + * Return: queue_index + */ +static uint16_t __hdd_get_queue_index(uint16_t up) +{ + if (qdf_unlikely(up >= ARRAY_SIZE(hdd_linux_up_to_ac_map))) + return HDD_LINUX_AC_BE; + return hdd_linux_up_to_ac_map[up]; +} + +#if defined(QCA_LL_TX_FLOW_CONTROL_V2) || \ + defined(QCA_HL_NETDEV_FLOW_CONTROL) || \ + defined(QCA_LL_PDEV_TX_FLOW_CONTROL) +/** + * hdd_get_queue_index() - get queue index + * @up: user priority + * @is_critical: is_critical flag + * + * Return: queue_index + */ +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_critical) +{ + if (qdf_unlikely(is_critical)) + return HDD_LINUX_AC_HI_PRIO; + return __hdd_get_queue_index(up); +} +#else +static +uint16_t hdd_get_queue_index(uint16_t up, bool is_critical) +{ + return __hdd_get_queue_index(up); +} +#endif + +#ifdef DP_TX_PACKET_INSPECT_FOR_ILP +/** + * hdd_update_pkt_priority_with_inspection() - update TX packets priority + * @skb: network buffer + * @up: user priority + * + * Update TX packets priority, if some special TX packets like TCP ack, + * reuse skb->priority upper 8 bits(bit24 ~ 31) to mark them. + * + * Return: None + */ +static inline +void hdd_update_pkt_priority_with_inspection(struct sk_buff *skb, + enum sme_qos_wmmuptype up) +{ + skb->priority = up; + + if (qdf_unlikely(qdf_nbuf_is_ipv4_v6_pure_tcp_ack(skb))) + qdf_nbuf_set_priority_pkt_type( + skb, QDF_NBUF_PRIORITY_PKT_TCP_ACK); +} +#else +static inline +void hdd_update_pkt_priority_with_inspection(struct sk_buff *skb, + enum sme_qos_wmmuptype up) +{ + skb->priority = up; +} +#endif + +static uint16_t __hdd_wmm_select_queue(struct net_device *dev, + struct sk_buff *skb) +{ + enum sme_qos_wmmuptype up = SME_QOS_WMM_UP_BE; + uint16_t index; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + bool is_critical = false; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + if (qdf_unlikely(!hdd_ctx || cds_is_driver_transitioning())) { + hdd_debug_rl("driver is transitioning! Using default(BE) queue."); + skb->priority = SME_QOS_WMM_UP_BE; + return TX_GET_QUEUE_IDX(HDD_LINUX_AC_BE, 0); + } + + /* Get the user priority from IP header */ + hdd_wmm_classify_pkt(adapter, skb, &up, &is_critical); + + hdd_update_pkt_priority_with_inspection(skb, up); + + index = hdd_get_queue_index(up, is_critical); + + return hdd_get_tx_queue_for_ac(adapter, skb, index); +} + +uint16_t hdd_wmm_select_queue(struct net_device *dev, + struct sk_buff *skb) +{ + uint16_t q_index; + + q_index = __hdd_wmm_select_queue(dev, skb); + + return q_index; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev) +{ + return hdd_wmm_select_queue(dev, skb); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + struct net_device *sb_dev, + select_queue_fallback_t fallback) +{ + return hdd_wmm_select_queue(dev, skb); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + return hdd_wmm_select_queue(dev, skb); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)) +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) +{ + return hdd_wmm_select_queue(dev, skb); +} +#else +uint16_t hdd_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + return hdd_wmm_select_queue(dev, skb); +} +#endif + + +/** + * hdd_wmm_acquire_access_required() - Function which will determine + * acquire admittance for a WMM AC is required or not based on psb configuration + * done in framework + * + * @adapter: [in] pointer to adapter structure + * @ac_type: [in] WMM AC type of OS packet + * + * Return: void + */ +void hdd_wmm_acquire_access_required(struct hdd_adapter *adapter, + sme_ac_enum_type ac_type) +{ + /* Each bit in the LSB nibble indicates 1 AC. + * Clearing the particular bit in LSB nibble to indicate + * access required + */ + switch (ac_type) { + case SME_AC_BK: + /* clear first bit */ + adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BK_CHANGED_MASK; + break; + case SME_AC_BE: + /* clear second bit */ + adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_BE_CHANGED_MASK; + break; + case SME_AC_VI: + /* clear third bit */ + adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VI_CHANGED_MASK; + break; + case SME_AC_VO: + /* clear fourth bit */ + adapter->psb_changed &= ~SME_QOS_UAPSD_CFG_VO_CHANGED_MASK; + break; + default: + hdd_err("Invalid AC Type"); + break; + } +} + +/** + * hdd_wmm_acquire_access() - Function which will attempt to acquire + * admittance for a WMM AC + * + * @adapter: [in] pointer to adapter context + * @ac_type: [in] WMM AC type of OS packet + * @granted: [out] pointer to bool flag when indicates if access + * has been granted or not + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_acquire_access(struct hdd_adapter *adapter, + sme_ac_enum_type ac_type, bool *granted) +{ + struct hdd_wmm_qos_context *qos_context; + struct hdd_context *hdd_ctx; + /* The ini ImplicitQosIsEnabled is deprecated. By default, the ini + * value is disabled. So, setting the variable is_implicit_qos_enabled + * value to false. + */ + bool is_implicit_qos_enabled = false; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Entered for AC %d", __func__, ac_type); + + if (!hdd_wmm_is_active(adapter) || !(is_implicit_qos_enabled) || + !adapter->hdd_wmm_status.ac_status[ac_type].is_access_required) { + /* either we don't want QoS or the AP doesn't support + * QoS or we don't want to do implicit QoS + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: QoS not configured on both ends ", __func__); + + *granted = + adapter->hdd_wmm_status.ac_status[ac_type]. + is_access_allowed; + + return QDF_STATUS_SUCCESS; + } + /* do we already have an implicit QoS request pending for this AC? */ + if ((adapter->hdd_wmm_status.ac_status[ac_type].is_access_needed) || + (adapter->hdd_wmm_status.ac_status[ac_type].is_access_pending)) { + /* request already pending so we need to wait for that + * response + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Implicit QoS for TL AC %d already scheduled", + __func__, ac_type); + + *granted = false; + return QDF_STATUS_SUCCESS; + } + /* did we already fail to establish implicit QoS for this AC? + * (if so, access should have been granted when the failure + * was handled) + */ + if (adapter->hdd_wmm_status.ac_status[ac_type].has_access_failed) { + /* request previously failed + * allow access, but we'll be downgraded + */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Implicit QoS for TL AC %d previously failed", + __func__, ac_type); + + if (!adapter->hdd_wmm_status.ac_status[ac_type]. + is_access_required) { + adapter->hdd_wmm_status.ac_status[ac_type]. + is_access_allowed = true; + *granted = true; + } else { + adapter->hdd_wmm_status.ac_status[ac_type]. + is_access_allowed = false; + *granted = false; + } + + return QDF_STATUS_SUCCESS; + } + /* we need to establish implicit QoS */ + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Need to schedule implicit QoS for TL AC %d, adapter is %pK", + __func__, ac_type, adapter); + + adapter->hdd_wmm_status.ac_status[ac_type].is_access_needed = true; + + qos_context = qdf_mem_malloc(sizeof(*qos_context)); + if (!qos_context) { + /* no memory for QoS context. Nothing we can do but + * let data flow + */ + adapter->hdd_wmm_status.ac_status[ac_type].is_access_allowed = + true; + *granted = true; + return QDF_STATUS_SUCCESS; + } + + qos_context->ac_type = ac_type; + qos_context->adapter = adapter; + qos_context->flow_id = 0; + qos_context->handle = HDD_WMM_HANDLE_IMPLICIT; + qos_context->magic = HDD_WMM_CTX_MAGIC; + qos_context->is_inactivity_timer_running = false; + + INIT_WORK(&qos_context->implicit_qos_work, hdd_wmm_do_implicit_qos); + + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, + "%s: Scheduling work for AC %d, context %pK", + __func__, ac_type, qos_context); + + schedule_work(&qos_context->implicit_qos_work); + + /* caller will need to wait until the work takes place and + * TSPEC negotiation completes + */ + *granted = false; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS hdd_wmm_assoc(struct hdd_adapter *adapter, + bool is_reassoc, uint8_t uapsd_mask) +{ + QDF_STATUS status; + uint32_t srv_value = 0; + uint32_t sus_value = 0; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint32_t delayed_trgr_frm_int; + + /* when we associate we need to notify TL if it needs to + * enable UAPSD for any access categories + */ + + hdd_enter(); + + if (is_reassoc) { + /* when we reassociate we should continue to use + * whatever parameters were previously established. + * if we are reassociating due to a U-APSD change for + * a particular Access Category, then the change will + * be communicated to HDD via the QoS callback + * associated with the given flow, and U-APSD + * parameters will be updated there + */ + + hdd_debug("Reassoc so no work, Exiting"); + + return QDF_STATUS_SUCCESS; + } + + hdd_debug("U-APSD mask is 0x%02x", (int)uapsd_mask); + + ucfg_mlme_get_tl_delayed_trgr_frm_int(hdd_ctx->psoc, + &delayed_trgr_frm_int); + + if (uapsd_mask & HDD_AC_VO) { + status = ucfg_mlme_get_wmm_uapsd_vo_srv_intv(hdd_ctx->psoc, + &srv_value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get uapsd_srv_intv failed"); + return QDF_STATUS_SUCCESS; + } + status = ucfg_mlme_get_wmm_uapsd_vo_sus_intv(hdd_ctx->psoc, + &sus_value); + if (QDF_IS_STATUS_ERROR(status)) { + hdd_err("Get uapsd_vo_sus_intv failed"); + return QDF_STATUS_SUCCESS; + } + + status = sme_enable_uapsd_for_ac( + SME_AC_VO, 7, 7, srv_value, sus_value, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->deflink->vdev_id, + delayed_trgr_frm_int); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsd_mask & HDD_AC_VI) { + status = ucfg_mlme_get_wmm_uapsd_vi_srv_intv( + hdd_ctx->psoc, &srv_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_vi_srv_intv failed"); + return QDF_STATUS_SUCCESS; + } + status = ucfg_mlme_get_wmm_uapsd_vi_sus_intv( + hdd_ctx->psoc, &sus_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_vi_sus_intv failed"); + return QDF_STATUS_SUCCESS; + } + + status = sme_enable_uapsd_for_ac( + SME_AC_VI, 5, 5, srv_value, sus_value, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->deflink->vdev_id, + delayed_trgr_frm_int); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsd_mask & HDD_AC_BK) { + status = ucfg_mlme_get_wmm_uapsd_bk_srv_intv(hdd_ctx->psoc, + &srv_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_bk_srv_intv failed"); + return QDF_STATUS_SUCCESS; + } + status = ucfg_mlme_get_wmm_uapsd_bk_sus_intv(hdd_ctx->psoc, + &sus_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_bk_sus_intv failed"); + return QDF_STATUS_SUCCESS; + } + + status = sme_enable_uapsd_for_ac( + SME_AC_BK, 2, 2, srv_value, sus_value, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->deflink->vdev_id, + delayed_trgr_frm_int); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + if (uapsd_mask & HDD_AC_BE) { + status = ucfg_mlme_get_wmm_uapsd_be_srv_intv(hdd_ctx->psoc, + &srv_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_be_srv_intv failed"); + return QDF_STATUS_SUCCESS; + } + status = ucfg_mlme_get_wmm_uapsd_be_sus_intv(hdd_ctx->psoc, + &sus_value); + if (!QDF_IS_STATUS_SUCCESS(status)) { + hdd_err("Get uapsd_be_sus_intv failed"); + return QDF_STATUS_SUCCESS; + } + + status = sme_enable_uapsd_for_ac( + SME_AC_BE, 3, 3, srv_value, sus_value, + SME_QOS_WMM_TS_DIR_BOTH, 1, + adapter->deflink->vdev_id, + delayed_trgr_frm_int); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(status)); + } + + status = sme_update_dsc_pto_up_mapping(hdd_ctx->mac_handle, + adapter->dscp_to_up_map, + adapter->deflink->vdev_id); + + if (!QDF_IS_STATUS_SUCCESS(status)) + hdd_wmm_dscp_initial_state(adapter); + + hdd_exit(); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_connect() - Function which will handle the housekeeping + * required by WMM when a connection is established + * + * @adapter : [in] pointer to adapter context + * @roam_info: [in] pointer to roam information + * @bss_type : [in] type of BSS + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS hdd_wmm_connect(struct hdd_adapter *adapter, + struct csr_roam_info *roam_info, + eCsrRoamBssType bss_type) +{ + int ac; + bool qap = true; + bool qos_connection = true; + uint8_t acm_mask = 0x0; + + hdd_debug("qap is %d, qos_connection is %d, acm_mask is 0x%x", + qap, qos_connection, acm_mask); + + adapter->hdd_wmm_status.qap = qap; + adapter->hdd_wmm_status.qos_connection = qos_connection; + + for (ac = 0; ac < WLAN_MAX_AC; ac++) { + /* admission is not required so access is allowed */ + adapter->hdd_wmm_status.ac_status[ac].is_access_required = false; + adapter->hdd_wmm_status.ac_status[ac].is_access_allowed = true; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_wmm_is_active() - Function which will determine if WMM is + * active on the current connection + * + * @adapter: [in] pointer to adapter context + * + * Return: true if WMM is enabled, false if WMM is not enabled + */ +bool hdd_wmm_is_active(struct hdd_adapter *adapter) +{ + if ((!adapter->hdd_wmm_status.qos_connection) || + (!adapter->hdd_wmm_status.qap)) { + return false; + } else { + return true; + } +} + +bool hdd_wmm_is_acm_allowed(uint8_t vdev_id) +{ + struct hdd_adapter *adapter; + struct hdd_wmm_ac_status *wmm_ac_status; + struct hdd_context *hdd_ctx; + struct wlan_hdd_link_info *link_info; + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return false; + + link_info = hdd_get_link_info_by_vdev(hdd_ctx, vdev_id); + if (!link_info || hdd_validate_adapter(link_info->adapter)) + return false; + + adapter = link_info->adapter; + wmm_ac_status = adapter->hdd_wmm_status.ac_status; + + if (hdd_wmm_is_active(adapter) && + !(wmm_ac_status[QCA_WLAN_AC_VI].is_access_allowed)) + return false; + return true; +} + +hdd_wlan_wmm_status_e hdd_wmm_addts(struct hdd_adapter *adapter, + uint32_t handle, + struct sme_qos_wmmtspecinfo *tspec) +{ + struct hdd_wmm_qos_context *qos_context = NULL; + struct hdd_wmm_qos_context *cur_entry; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + enum sme_qos_statustype sme_status; +#endif + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); + + hdd_debug("Entered with handle 0x%x", handle); + + /* see if a context already exists with the given handle */ + mutex_lock(&adapter->hdd_wmm_status.mutex); + list_for_each_entry(cur_entry, + &adapter->hdd_wmm_status.context_list, node) { + if (cur_entry->handle == handle) { + qos_context = cur_entry; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.mutex); + if (qos_context) { + /* record with that handle already exists */ + hdd_err("Record already exists with handle 0x%x", handle); + + /* Application is trying to modify some of the Tspec + * params. Allow it + */ + sme_status = sme_qos_modify_req(mac_handle, + tspec, qos_context->flow_id); + + /* need to check the return value and act appropriately */ + switch (sme_status) { + case SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_PENDING; + break; + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_NO_UAPSD; + break; + case SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY: + status = + HDD_WLAN_WMM_STATUS_MODIFY_SUCCESS_NO_ACM_UAPSD_EXISTING; + break; + case SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM; + break; + case SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP: + status = HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + break; + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + break; + default: + /* we didn't get back one of the + * SME_QOS_STATUS_MODIFY_* status codes + */ + hdd_err("unexpected SME Status=%d", + sme_status); + QDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_MODIFY_FAILED; + } + + /* we were successful, save the status */ + mutex_lock(&adapter->hdd_wmm_status.mutex); + if (qos_context->magic == HDD_WMM_CTX_MAGIC) + qos_context->status = status; + mutex_unlock(&adapter->hdd_wmm_status.mutex); + + return status; + } + + qos_context = qdf_mem_malloc(sizeof(*qos_context)); + if (!qos_context) { + /* no memory for QoS context. Nothing we can do */ + return HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE; + } + /* we assume the tspec has already been validated by the caller */ + + qos_context->handle = handle; + if (tspec->ts_info.up < HDD_WMM_UP_TO_AC_MAP_SIZE) + qos_context->ac_type = hdd_wmm_up_to_ac_map[tspec->ts_info.up]; + else { + hdd_err("ts_info.up (%d) larger than max value (%d), use default ac_type (%d)", + tspec->ts_info.up, + HDD_WMM_UP_TO_AC_MAP_SIZE - 1, hdd_wmm_up_to_ac_map[0]); + qos_context->ac_type = hdd_wmm_up_to_ac_map[0]; + } + qos_context->adapter = adapter; + qos_context->flow_id = 0; + qos_context->ts_id = tspec->ts_info.tid; + qos_context->magic = HDD_WMM_CTX_MAGIC; + qos_context->is_inactivity_timer_running = false; + + hdd_debug("Setting up QoS, context %pK", qos_context); + + mutex_lock(&adapter->hdd_wmm_status.mutex); + list_add(&qos_context->node, &adapter->hdd_wmm_status.context_list); + mutex_unlock(&adapter->hdd_wmm_status.mutex); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_status = sme_qos_setup_req(mac_handle, + adapter->deflink->vdev_id, + tspec, + hdd_wmm_sme_callback, + qos_context, + tspec->ts_info.up, + &qos_context->flow_id); + + hdd_debug("sme_qos_setup_req returned %d flowid %d", + sme_status, qos_context->flow_id); + + /* need to check the return value and act appropriately */ + switch (sme_status) { + case SME_QOS_STATUS_SETUP_REQ_PENDING_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP: + status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_NO_UAPSD; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY: + status = + HDD_WLAN_WMM_STATUS_SETUP_SUCCESS_NO_ACM_UAPSD_EXISTING; + break; + case SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING: + status = HDD_WLAN_WMM_STATUS_SETUP_PENDING; + break; + case SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP: + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + hdd_wmm_free_context(qos_context); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM; + case SME_QOS_STATUS_SETUP_FAILURE_RSP: + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + /* we can't tell the difference between when a request + * fails because AP rejected it versus when SME + * encountered an internal error + */ + hdd_wmm_free_context(qos_context); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + case SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP: + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + hdd_wmm_free_context(qos_context); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM; + default: + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + /* we didn't get back one of the + * SME_QOS_STATUS_SETUP_* status codes + */ + hdd_wmm_free_context(qos_context); + hdd_err("unexpected SME Status=%d", sme_status); + QDF_ASSERT(0); + return HDD_WLAN_WMM_STATUS_SETUP_FAILED; + } +#endif + + /* we were successful, save the status */ + mutex_lock(&adapter->hdd_wmm_status.mutex); + if (qos_context->magic == HDD_WMM_CTX_MAGIC) + qos_context->status = status; + mutex_unlock(&adapter->hdd_wmm_status.mutex); + + return status; +} + +/** + * hdd_wmm_delts() - Function which will delete a traffic spec at the + * request of an application + * + * @adapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_delts(struct hdd_adapter *adapter, + uint32_t handle) +{ + struct hdd_wmm_qos_context *qos_context = NULL; + struct hdd_wmm_qos_context *cur_entry; + sme_ac_enum_type ac_type = 0; + uint32_t flow_id = 0; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_SETUP_SUCCESS; +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + enum sme_qos_statustype sme_status; + mac_handle_t mac_handle = hdd_adapter_get_mac_handle(adapter); +#endif + + hdd_debug("Entered with handle 0x%x", handle); + + /* locate the context with the given handle */ + mutex_lock(&adapter->hdd_wmm_status.mutex); + list_for_each_entry(cur_entry, + &adapter->hdd_wmm_status.context_list, node) { + if (cur_entry->handle == handle) { + qos_context = cur_entry; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.mutex); + + if (!qos_context) { + /* we didn't find the handle, tid is already freed */ + hdd_info("tid already freed for handle 0x%x", handle); + return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + } + + ac_type = qos_context->ac_type; + flow_id = qos_context->flow_id; + + hdd_debug("found handle 0x%x, flow %d, AC %d", + handle, flow_id, ac_type); + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + sme_status = sme_qos_release_req(mac_handle, adapter->deflink->vdev_id, + flow_id); + + hdd_debug("SME flow %d released, SME status %d", flow_id, sme_status); + + switch (sme_status) { + case SME_QOS_STATUS_RELEASE_SUCCESS_RSP: + /* this flow is the only one on that AC, so go ahead + * and update our TSPEC state for the AC + */ + adapter->hdd_wmm_status.ac_status[ac_type].is_tspec_valid = + false; + adapter->hdd_wmm_status.ac_status[ac_type].is_access_allowed = + false; + + /* need to tell TL to stop trigger timer, etc */ + hdd_wmm_disable_tl_uapsd(qos_context); + + /* disable the inactivity timer */ + hdd_wmm_disable_inactivity_timer(qos_context); + + /* we are done with this context */ + hdd_wmm_free_context(qos_context); + + /* SME must not fire any more callbacks for this flow + * since the context is no longer valid + */ + + return HDD_WLAN_WMM_STATUS_RELEASE_SUCCESS; + + case SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP: + /* do nothing as we will get a response from SME */ + status = HDD_WLAN_WMM_STATUS_RELEASE_PENDING; + break; + + case SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP: + /* nothing we can do with the existing flow except leave it */ + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM; + break; + + case SME_QOS_STATUS_RELEASE_FAILURE_RSP: + /* nothing we can do with the existing flow except leave it */ + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + break; + + default: + /* we didn't get back one of the + * SME_QOS_STATUS_RELEASE_* status codes + */ + hdd_err("unexpected SME Status=%d", sme_status); + QDF_ASSERT(0); + status = HDD_WLAN_WMM_STATUS_RELEASE_FAILED; + } + +#endif + mutex_lock(&adapter->hdd_wmm_status.mutex); + if (qos_context->magic == HDD_WMM_CTX_MAGIC) + qos_context->status = status; + mutex_unlock(&adapter->hdd_wmm_status.mutex); + + return status; +} + +/** + * hdd_wmm_checkts() - Function which will return the status of a traffic + * spec at the request of an application + * + * @adapter: [in] pointer to adapter context + * @handle: [in] handle to uniquely identify a TS + * + * Return: HDD_WLAN_WMM_STATUS_* + */ +hdd_wlan_wmm_status_e hdd_wmm_checkts(struct hdd_adapter *adapter, uint32_t handle) +{ + struct hdd_wmm_qos_context *qos_context; + hdd_wlan_wmm_status_e status = HDD_WLAN_WMM_STATUS_LOST; + + hdd_debug("Entered with handle 0x%x", handle); + + /* locate the context with the given handle */ + mutex_lock(&adapter->hdd_wmm_status.mutex); + list_for_each_entry(qos_context, + &adapter->hdd_wmm_status.context_list, node) { + if (qos_context->handle == handle) { + hdd_debug("found handle 0x%x, context %pK", + handle, qos_context); + + status = qos_context->status; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.mutex); + return status; +} + +/** + * hdd_get_handle_from_ts_id() - get handle from ts id + * @adapter : hdd adapter + * @ts_id: ts_id + * @del_tspec_handle: handle to delete the request + * + * Return: None + */ +static void +hdd_get_handle_from_ts_id(struct hdd_adapter *adapter, uint8_t ts_id, + uint32_t *del_tspec_handle) +{ + struct hdd_wmm_qos_context *cur_entry; + + hdd_debug("Entered with ts_id 0x%x", ts_id); + + mutex_lock(&adapter->hdd_wmm_status.mutex); + list_for_each_entry(cur_entry, + &adapter->hdd_wmm_status.context_list, node) { + if (cur_entry->ts_id == ts_id) { + *del_tspec_handle = cur_entry->handle; + break; + } + } + mutex_unlock(&adapter->hdd_wmm_status.mutex); +} + +/** + * __wlan_hdd_cfg80211_config_tspec() - config tspec + * @wiphy: pointer to wireless wiphy structure. + * @wdev: pointer to wireless_dev structure. + * @data: pointer to config tspec command parameters. + * @data_len: the length in byte of config tspec command parameters. + * + * Return: An error code or 0 on success. + */ +static int __wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, + int data_len) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); + struct hdd_context *hdd_ctx = wiphy_priv(wiphy); + struct sme_qos_wmmtspecinfo tspec; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX + 1]; + uint8_t oper, ts_id; + static uint32_t add_tspec_handle = MIN_HANDLE_VALUE; + uint32_t del_tspec_handle = 0; + hdd_wlan_wmm_status_e status; + int ret; + + hdd_enter_dev(wdev->netdev); + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + ret = wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_CONFIG_TSPEC_MAX, + data, data_len, config_tspec_policy); + if (ret) { + hdd_err_rl("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[CONFIG_TSPEC_OPERATION] || !tb[CONFIG_TSPEC_TSID]) { + hdd_err_rl("Mandatory attributes are not present"); + return -EINVAL; + } + + memset(&tspec, 0, sizeof(tspec)); + + oper = nla_get_u8(tb[CONFIG_TSPEC_OPERATION]); + ts_id = nla_get_u8(tb[CONFIG_TSPEC_TSID]); + + switch (oper) { + case QCA_WLAN_TSPEC_ADD: + + tspec.ts_info.tid = ts_id; + + /* Mandatory attributes */ + if (tb[CONFIG_TSPEC_DIRECTION]) { + uint8_t direction = nla_get_u8( + tb[CONFIG_TSPEC_DIRECTION]); + + switch (direction) { + case QCA_WLAN_TSPEC_DIRECTION_UPLINK: + tspec.ts_info.direction = + SME_QOS_WMM_TS_DIR_UPLINK; + break; + case QCA_WLAN_TSPEC_DIRECTION_DOWNLINK: + tspec.ts_info.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + break; + case QCA_WLAN_TSPEC_DIRECTION_BOTH: + tspec.ts_info.direction = + SME_QOS_WMM_TS_DIR_BOTH; + break; + default: + hdd_err_rl("Invalid direction %d", direction); + return -EINVAL; + } + } else { + hdd_err_rl("Direction is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_APSD]) + tspec.ts_info.psb = 1; + + if (tb[CONFIG_TSPEC_ACK_POLICY]) { + uint8_t ack_policy = nla_get_u8( + tb[CONFIG_TSPEC_ACK_POLICY]); + + switch (ack_policy) { + case QCA_WLAN_TSPEC_NORMAL_ACK: + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK; + break; + case QCA_WLAN_TSPEC_BLOCK_ACK: + tspec.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + break; + default: + hdd_err_rl("Invalid ack policy %d", ack_policy); + return -EINVAL; + } + } else { + hdd_err_rl("ACK policy is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_NOMINAL_MSDU_SIZE]) { + tspec.nominal_msdu_size = nla_get_u16( + tb[CONFIG_TSPEC_NOMINAL_MSDU_SIZE]); + } else { + hdd_err_rl("Nominal msdu size is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_MAXIMUM_MSDU_SIZE]) { + tspec.maximum_msdu_size = nla_get_u16( + tb[CONFIG_TSPEC_MAXIMUM_MSDU_SIZE]); + } else { + hdd_err_rl("Maximum msdu size is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_MIN_SERVICE_INTERVAL]) { + tspec.min_service_interval = nla_get_u32( + tb[CONFIG_TSPEC_MIN_SERVICE_INTERVAL]); + } else { + hdd_err_rl("Min service interval is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_MAX_SERVICE_INTERVAL]) { + tspec.max_service_interval = nla_get_u32( + tb[CONFIG_TSPEC_MAX_SERVICE_INTERVAL]); + } else { + hdd_err_rl("Max service interval is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_INACTIVITY_INTERVAL]) { + tspec.inactivity_interval = nla_get_u32( + tb[CONFIG_TSPEC_INACTIVITY_INTERVAL]); + } else { + hdd_err_rl("Inactivity interval is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_SUSPENSION_INTERVAL]) { + tspec.suspension_interval = nla_get_u32( + tb[CONFIG_TSPEC_SUSPENSION_INTERVAL]); + } else { + hdd_err_rl("Suspension interval is not present"); + return -EINVAL; + } + + if (tb[CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE]) { + tspec.surplus_bw_allowance = nla_get_u16( + tb[CONFIG_TSPEC_SURPLUS_BANDWIDTH_ALLOWANCE]); + } else { + hdd_err_rl("Surplus bw allowance is not present"); + return -EINVAL; + } + + /* Optional attributes */ + if (tb[CONFIG_TSPEC_USER_PRIORITY]) + tspec.ts_info.up = nla_get_u8( + tb[CONFIG_TSPEC_USER_PRIORITY]); + + if (tb[CONFIG_TSPEC_MINIMUM_DATA_RATE]) + tspec.min_data_rate = nla_get_u32( + tb[CONFIG_TSPEC_MINIMUM_DATA_RATE]); + + if (tb[CONFIG_TSPEC_MEAN_DATA_RATE]) + tspec.mean_data_rate = nla_get_u32( + tb[CONFIG_TSPEC_MEAN_DATA_RATE]); + + if (tb[CONFIG_TSPEC_PEAK_DATA_RATE]) + tspec.peak_data_rate = nla_get_u32( + tb[CONFIG_TSPEC_PEAK_DATA_RATE]); + + if (tb[CONFIG_TSPEC_BURST_SIZE]) + tspec.max_burst_size = nla_get_u32( + tb[CONFIG_TSPEC_BURST_SIZE]); + + if (tspec.max_burst_size) + tspec.ts_info.burst_size_defn = 1; + + if (tb[CONFIG_TSPEC_MINIMUM_PHY_RATE]) + tspec.min_phy_rate = nla_get_u32( + tb[CONFIG_TSPEC_MINIMUM_PHY_RATE]); + /* + * ts_id send by upper layer is always same as handle and host + * doesn't add new TS entry for same handle. To avoid this + * issue host modifies handle internally. + */ + status = hdd_wmm_addts(adapter, add_tspec_handle, &tspec); + if (status == HDD_WLAN_WMM_STATUS_SETUP_FAILED || + status == HDD_WLAN_WMM_STATUS_SETUP_FAILED_BAD_PARAM || + status == HDD_WLAN_WMM_STATUS_SETUP_FAILED_NO_WMM || + status == HDD_WLAN_WMM_STATUS_MODIFY_FAILED || + status == HDD_WLAN_WMM_STATUS_MODIFY_FAILED_BAD_PARAM || + status == HDD_WLAN_WMM_STATUS_SETUP_UAPSD_SET_FAILED || + status == HDD_WLAN_WMM_STATUS_MODIFY_UAPSD_SET_FAILED || + status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) { + hdd_err_rl("hdd_wmm_addts failed %d", status); + return -EINVAL; + } + + add_tspec_handle++; + if (add_tspec_handle >= MAX_HANDLE_VALUE) + add_tspec_handle = MIN_HANDLE_VALUE; + break; + + case QCA_WLAN_TSPEC_DEL: + /* + * Host modifies handle internally. So, always + * delete the entry for provided ts_id. + */ + hdd_get_handle_from_ts_id(adapter, ts_id, &del_tspec_handle); + if (!del_tspec_handle) { + hdd_err_rl("ts_id is already freed %d", ts_id); + break; + } + status = hdd_wmm_delts(adapter, del_tspec_handle); + if (status == HDD_WLAN_WMM_STATUS_RELEASE_FAILED || + status == HDD_WLAN_WMM_STATUS_RELEASE_FAILED_BAD_PARAM || + status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) { + hdd_err_rl("hdd_wmm_delts failed %d", status); + return -EINVAL; + } + break; + + case QCA_WLAN_TSPEC_GET: + + status = hdd_wmm_checkts(adapter, ts_id); + if (status == HDD_WLAN_WMM_STATUS_LOST || + status == HDD_WLAN_WMM_STATUS_INTERNAL_FAILURE) { + hdd_err_rl("hdd_wmm_checkts failed %d", status); + return -EINVAL; + } + break; + + default: + hdd_err_rl("Invalid operation %d", oper); + return -EINVAL; + } + + hdd_exit(); + + return 0; +} + +int wlan_hdd_cfg80211_config_tspec(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + int errno; + struct osif_vdev_sync *vdev_sync; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_cfg80211_config_tspec(wiphy, wdev, data, data_len); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c new file mode 100644 index 0000000000..61b0d6a12e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/hdd/src/wlan_hdd_wowl.c @@ -0,0 +1,498 @@ +/* + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_hdd_wowl.c + * + * wake up on WLAN API file + */ + +/* Include Files */ + +#include "qdf_str.h" +#include +#include +#include +#include "wlan_hdd_object_manager.h" + +/* Preprocessor Definitions and Constants */ +#define WOWL_INTER_PTRN_TOKENIZER ';' +#define WOWL_INTRA_PTRN_TOKENIZER ':' + +/* Type Declarations */ + +static char *g_hdd_wowl_ptrns[WOWL_MAX_PTRNS_ALLOWED]; +static bool g_hdd_wowl_ptrns_debugfs[WOWL_MAX_PTRNS_ALLOWED] = { 0 }; + +static uint8_t g_hdd_wowl_ptrns_count; + +static inline int find_ptrn_len(const char *ptrn) +{ + int len = 0; + + while (*ptrn != '\0' && *ptrn != WOWL_INTER_PTRN_TOKENIZER) { + len++; + ptrn++; + } + return len; +} + +/** + * dump_hdd_wowl_ptrn() - log wow patterns + * @ptrn: pointer to wow pattern + * + * Return: none + */ +static void dump_hdd_wowl_ptrn(struct pmo_wow_add_pattern *ptrn) +{ + hdd_debug("Dumping WOW pattern"); + hdd_nofl_debug("Pattern Id = 0x%x", ptrn->pattern_id); + hdd_nofl_debug("Pattern Byte Offset = 0x%x", ptrn->pattern_byte_offset); + hdd_nofl_debug("Pattern_size = 0x%x", ptrn->pattern_size); + hdd_nofl_debug("Pattern_mask_size = 0x%x", ptrn->pattern_mask_size); + hdd_nofl_debug("Pattern: "); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + ptrn->pattern, ptrn->pattern_size); + hdd_nofl_debug("pattern_mask: "); + qdf_trace_hex_dump(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + ptrn->pattern_mask, ptrn->pattern_mask_size); +} + +static QDF_STATUS +hdd_get_num_wow_filters(struct hdd_context *hdd_ctx, uint8_t *num_filters) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc = hdd_ctx->psoc; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_HDD_ID_OBJ_MGR); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + *num_filters = 0; + else + *num_filters = ucfg_pmo_get_num_wow_filters(hdd_ctx->psoc); + + wlan_objmgr_psoc_release_ref(psoc, WLAN_HDD_ID_OBJ_MGR); + + return QDF_STATUS_SUCCESS; +} + +/** + * hdd_add_wowl_ptrn() - Function which will add the WoWL pattern to be + * used when PBM filtering is enabled + * @adapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be added + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn(struct hdd_adapter *adapter, const char *ptrn) +{ + struct pmo_wow_add_pattern wow_pattern; + int i, empty_slot, len, offset; + QDF_STATUS status; + const char *temp; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t num_filters; + bool invalid_ptrn = false; + struct wlan_objmgr_vdev *vdev; + + status = hdd_get_num_wow_filters(hdd_ctx, &num_filters); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + /* There has to have at least 1 byte for each field (pattern + * size, mask size, pattern, mask) e.g. PP:QQ:RR:SS ==> 11 + * chars + */ + len = find_ptrn_len(ptrn); + while (len >= 11) { + empty_slot = -1; + + /* check if pattern is already configured */ + for (i = num_filters - 1; i >= 0; i--) { + if (!g_hdd_wowl_ptrns[i]) { + empty_slot = i; + continue; + } + + if (strlen(g_hdd_wowl_ptrns[i]) == len) { + if (!memcmp(ptrn, g_hdd_wowl_ptrns[i], len)) { + hdd_err("WoWL pattern '%s' already configured", + g_hdd_wowl_ptrns[i]); + ptrn += len; + goto next_ptrn; + } + } + } + + /* Maximum number of patterns have been configured already */ + if (empty_slot == -1) { + hdd_err("Max WoW patterns (%u) reached", num_filters); + return false; + } + + /* Validate the pattern */ + if (ptrn[2] != WOWL_INTRA_PTRN_TOKENIZER || + ptrn[5] != WOWL_INTRA_PTRN_TOKENIZER) { + hdd_err("Malformed pattern string. Skip!"); + invalid_ptrn = true; + ptrn += len; + goto next_ptrn; + } + + /* Extract the pattern size */ + wow_pattern.pattern_size = + (hex_to_bin(ptrn[0]) * 0x10) + hex_to_bin(ptrn[1]); + + /* Extract the pattern mask size */ + wow_pattern.pattern_mask_size = + (hex_to_bin(ptrn[3]) * 0x10) + hex_to_bin(ptrn[4]); + + if (wow_pattern.pattern_size > PMO_WOWL_BCAST_PATTERN_MAX_SIZE + || wow_pattern.pattern_mask_size > + WOWL_PTRN_MASK_MAX_SIZE) { + hdd_err("Invalid length specified. Skip!"); + invalid_ptrn = true; + ptrn += len; + goto next_ptrn; + } + + /* compute the offset of tokenizer after the pattern */ + offset = 5 + 2 * wow_pattern.pattern_size + 1; + if ((offset >= len) || + (ptrn[offset] != WOWL_INTRA_PTRN_TOKENIZER)) { + hdd_err("Malformed pattern string..skip!"); + invalid_ptrn = true; + ptrn += len; + goto next_ptrn; + } + + /* compute the end of pattern string */ + offset = offset + 2 * wow_pattern.pattern_mask_size; + if (offset + 1 != len) { + /* offset begins with 0 */ + hdd_err("Malformed pattern string...skip!"); + invalid_ptrn = true; + ptrn += len; + goto next_ptrn; + } + + temp = ptrn; + + /* Now advance to where pattern begins */ + ptrn += 6; + + /* Extract the pattern */ + for (i = 0; i < wow_pattern.pattern_size; i++) { + wow_pattern.pattern[i] = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + ptrn += 2; /* skip to next byte */ + } + + /* Skip over the ':' separator after the pattern */ + ptrn++; + + /* Extract the pattern Mask */ + for (i = 0; i < wow_pattern.pattern_mask_size; i++) { + wow_pattern.pattern_mask[i] = + (hex_to_bin(ptrn[0]) * 0x10) + + hex_to_bin(ptrn[1]); + ptrn += 2; /* skip to next byte */ + } + + /* All is good. Store the pattern locally */ + g_hdd_wowl_ptrns[empty_slot] = qdf_mem_malloc(len + 1); + if (!g_hdd_wowl_ptrns[empty_slot]) + return false; + + memcpy(g_hdd_wowl_ptrns[empty_slot], temp, len); + g_hdd_wowl_ptrns[empty_slot][len] = '\0'; + wow_pattern.pattern_id = empty_slot; + wow_pattern.pattern_byte_offset = 0; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) { + hdd_err("vdev is null"); + qdf_mem_free(g_hdd_wowl_ptrns[empty_slot]); + g_hdd_wowl_ptrns[empty_slot] = NULL; + return false; + } + /* Register the pattern downstream */ + status = ucfg_pmo_add_wow_user_pattern(vdev, &wow_pattern); + if (QDF_IS_STATUS_ERROR(status)) { + /* Add failed, so invalidate the local storage */ + hdd_err("sme_wowl_add_bcast_pattern failed with error code (%d)", + status); + qdf_mem_free(g_hdd_wowl_ptrns[empty_slot]); + g_hdd_wowl_ptrns[empty_slot] = NULL; + } + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + dump_hdd_wowl_ptrn(&wow_pattern); + +next_ptrn: + if (*ptrn == WOWL_INTER_PTRN_TOKENIZER) { + /* move past the tokenizer */ + ptrn += 1; + len = find_ptrn_len(ptrn); + continue; + } else { + break; + } + } + + if (invalid_ptrn) + return false; + + return true; +} + +/** + * hdd_del_wowl_ptrn() - Function which will remove a WoWL pattern + * @adapter: pointer to the adapter + * @ptrn: pointer to the pattern string to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn(struct hdd_adapter *adapter, const char *ptrn) +{ + uint8_t id; + bool patternFound = false; + QDF_STATUS status; + struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); + uint8_t num_filters; + struct wlan_objmgr_vdev *vdev; + + status = hdd_get_num_wow_filters(hdd_ctx, &num_filters); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + /* lookup pattern */ + for (id = 0; id < num_filters; id++) { + if (!g_hdd_wowl_ptrns[id]) + continue; + + if (qdf_str_eq(ptrn, g_hdd_wowl_ptrns[id])) { + patternFound = true; + break; + } + } + + /* If pattern present, remove it from downstream */ + if (!patternFound) + return false; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) + return false; + + status = ucfg_pmo_del_wow_user_pattern(vdev, id); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + /* Remove from local storage as well */ + hdd_err("Deleted pattern with id %d [%s]", id, g_hdd_wowl_ptrns[id]); + + qdf_mem_free(g_hdd_wowl_ptrns[id]); + g_hdd_wowl_ptrns[id] = NULL; + + return true; +} + +/** + * hdd_add_wowl_ptrn_debugfs() - Function which will add a WoW pattern + * sent from debugfs interface + * @adapter: pointer to the adapter + * @pattern_idx: index of the pattern to be added + * @pattern_offset: offset of the pattern in the frame payload + * @pattern_buf: pointer to the pattern hex string to be added + * @pattern_mask: pointer to the pattern mask hex string + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_add_wowl_ptrn_debugfs(struct hdd_adapter *adapter, uint8_t pattern_idx, + uint8_t pattern_offset, char *pattern_buf, + char *pattern_mask) +{ + struct pmo_wow_add_pattern wow_pattern; + QDF_STATUS qdf_ret_status; + uint16_t pattern_len, mask_len, i; + struct wlan_objmgr_vdev *vdev; + + if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) { + hdd_err("WoW pattern index %d is out of range (0 ~ %d)", + pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1); + + return false; + } + + pattern_len = strlen(pattern_buf); + + /* Since the pattern is a hex string, 2 characters represent 1 byte. */ + if (pattern_len % 2) { + hdd_err("Malformed WoW pattern!"); + + return false; + } + + pattern_len >>= 1; + if (!pattern_len || pattern_len > WOWL_PTRN_MAX_SIZE) { + hdd_err("WoW pattern length %d is out of range (1 ~ %d).", + pattern_len, WOWL_PTRN_MAX_SIZE); + + return false; + } + + wow_pattern.pattern_id = pattern_idx; + wow_pattern.pattern_byte_offset = pattern_offset; + wow_pattern.pattern_size = pattern_len; + + if (wow_pattern.pattern_size > PMO_WOWL_BCAST_PATTERN_MAX_SIZE) { + hdd_err("WoW pattern size (%d) greater than max (%d)", + wow_pattern.pattern_size, + PMO_WOWL_BCAST_PATTERN_MAX_SIZE); + return false; + } + /* Extract the pattern */ + for (i = 0; i < wow_pattern.pattern_size; i++) { + wow_pattern.pattern[i] = + (hex_to_bin(pattern_buf[0]) << 4) + + hex_to_bin(pattern_buf[1]); + + /* Skip to next byte */ + pattern_buf += 2; + } + + /* Get pattern mask size by pattern length */ + wow_pattern.pattern_mask_size = pattern_len >> 3; + if (pattern_len % 8) + wow_pattern.pattern_mask_size += 1; + + mask_len = strlen(pattern_mask); + if ((mask_len % 2) + || (wow_pattern.pattern_mask_size != (mask_len >> 1))) { + hdd_err("Malformed WoW pattern mask!"); + + return false; + } + if (wow_pattern.pattern_mask_size > WOWL_PTRN_MASK_MAX_SIZE) { + hdd_err("WoW pattern mask size (%d) greater than max (%d)", + wow_pattern.pattern_mask_size, + WOWL_PTRN_MASK_MAX_SIZE); + return false; + } + /* Extract the pattern mask */ + for (i = 0; i < wow_pattern.pattern_mask_size; i++) { + wow_pattern.pattern_mask[i] = + (hex_to_bin(pattern_mask[0]) << 4) + + hex_to_bin(pattern_mask[1]); + + /* Skip to next byte */ + pattern_mask += 2; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) + return false; + + /* Register the pattern downstream */ + qdf_ret_status = ucfg_pmo_add_wow_user_pattern(vdev, &wow_pattern); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("pmo_wow_user_pattern failed with error code (%d).", + qdf_ret_status); + + return false; + } + + /* All is good. */ + if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) { + g_hdd_wowl_ptrns_debugfs[pattern_idx] = 1; + g_hdd_wowl_ptrns_count++; + } + + dump_hdd_wowl_ptrn(&wow_pattern); + + return true; +} + +/** + * hdd_del_wowl_ptrn_debugfs() - Function which will remove a WoW pattern + * sent from debugfs interface + * @adapter: pointer to the adapter + * @pattern_idx: index of the pattern to be removed + * + * Return: false if any errors encountered, true otherwise + */ +bool hdd_del_wowl_ptrn_debugfs(struct hdd_adapter *adapter, + uint8_t pattern_idx) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS qdf_ret_status; + + if (pattern_idx > (WOWL_MAX_PTRNS_ALLOWED - 1)) { + hdd_err("WoW pattern index %d is not in the range (0 ~ %d).", + pattern_idx, WOWL_MAX_PTRNS_ALLOWED - 1); + + return false; + } + + if (!g_hdd_wowl_ptrns_debugfs[pattern_idx]) { + hdd_err("WoW pattern %d is not in the table.", + pattern_idx); + + return false; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_OSIF_POWER_ID); + if (!vdev) + return false; + + qdf_ret_status = ucfg_pmo_del_wow_user_pattern(vdev, pattern_idx); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_POWER_ID); + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) { + hdd_err("sme_wowl_del_bcast_pattern failed with error code (%d).", + qdf_ret_status); + + return false; + } + + g_hdd_wowl_ptrns_debugfs[pattern_idx] = 0; + g_hdd_wowl_ptrns_count--; + + return true; +} + +void hdd_free_user_wowl_ptrns(void) +{ + int i; + + for (i = 0; i < WOWL_MAX_PTRNS_ALLOWED; ++i) { + if (g_hdd_wowl_ptrns[i]) { + qdf_mem_free(g_hdd_wowl_ptrns[i]); + g_hdd_wowl_ptrns[i] = NULL; + } + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/ani_global.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/ani_global.h new file mode 100644 index 0000000000..cf9855fc9b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/ani_global.h @@ -0,0 +1,773 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ANIGLOBAL_H +#define _ANIGLOBAL_H + +#include "qdf_types.h" +#include "sir_common.h" +#include "ani_system_defs.h" +#include "sys_def.h" +#include "dph_global.h" +#include "lim_global.h" +#include "sch_global.h" +#include "sys_global.h" +#include "sir_api.h" + +#include "csr_api.h" +#include "csr_support.h" +#include "sme_internal.h" +#include "sap_api.h" +#include "csr_internal.h" + +#include "sme_rrm_internal.h" +#include "rrm_global.h" + +#include +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_mlme_public_struct.h" + +/** + * MAC_CONTEXT() - Convert an opaque mac handle into a mac context + * @handle: MAC handle to be converted + * + * Given an opaque mac handle this function will return the mac + * context that is associated with that handle. + * + * This is the inverse function of MAC_HANDLE() + * + * Return: mac context for @handle + */ +static inline struct mac_context *MAC_CONTEXT(mac_handle_t handle) +{ + return (struct mac_context *)handle; +} + +/** + * MAC_HANDLE() - Convert a mac context into an opaque mac handle + * @mac: MAC context to be converted + * + * Given a mac context this function will return the opaque mac handle + * that is associated with that handle. + * + * This is the inverse function of MAC_CONTEXT() + * + * Return: opaque handle for @mac + */ +static inline mac_handle_t MAC_HANDLE(struct mac_context *mac) +{ + return (mac_handle_t)mac; +} + +#define ANI_DRIVER_TYPE(mac) (((struct mac_context *)(mac))->gDriverType) + +/* ------------------------------------------------------------------- */ +/* Bss Qos Caps bit map definition */ +#define LIM_BSS_CAPS_OFFSET_HCF 0 +#define LIM_BSS_CAPS_OFFSET_WME 1 +#define LIM_BSS_CAPS_OFFSET_WSM 2 + +#define LIM_BSS_CAPS_HCF (1 << LIM_BSS_CAPS_OFFSET_HCF) +#define LIM_BSS_CAPS_WME (1 << LIM_BSS_CAPS_OFFSET_WME) +#define LIM_BSS_CAPS_WSM (1 << LIM_BSS_CAPS_OFFSET_WSM) + +/* cap should be one of HCF/WME/WSM */ +#define LIM_BSS_CAPS_GET(cap, val) (((val) & (LIM_BSS_CAPS_ ## cap)) >> LIM_BSS_CAPS_OFFSET_ ## cap) +#define LIM_BSS_CAPS_SET(cap, val) ((val) |= (LIM_BSS_CAPS_ ## cap)) +#define LIM_BSS_CAPS_CLR(cap, val) ((val) &= (~(LIM_BSS_CAPS_ ## cap))) + +#define SPACE_ASCII_VALUE 32 + +#define WLAN_HOST_SEQ_NUM_MIN 2048 +#define WLAN_HOST_SEQ_NUM_MAX 4095 +#define LOW_SEQ_NUM_MASK 0x000F +#define HIGH_SEQ_NUM_MASK 0x0FF0 +#define HIGH_SEQ_NUM_OFFSET 4 +#define DEF_HE_AUTO_SGI_LTF 0x0F07 + +#define PMF_WEP_DISABLE 2 +#define PMF_INCORRECT_KEY 1 +#define PMF_CORRECT_KEY 0 + +/** + * enum log_event_type - Type of event initiating bug report + * @WLAN_LOG_TYPE_NON_FATAL: Non fatal event + * @WLAN_LOG_TYPE_FATAL: Fatal event + * + * Enum indicating the type of event that is initiating the bug report + */ +enum log_event_type { + WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_TYPE_FATAL, +}; + +/** + * enum log_event_indicator - Module triggering bug report + * @WLAN_LOG_INDICATOR_UNUSED: Unused + * @WLAN_LOG_INDICATOR_FRAMEWORK: Framework triggers bug report + * @WLAN_LOG_INDICATOR_HOST_DRIVER: Host driver triggers bug report + * @WLAN_LOG_INDICATOR_FIRMWARE: FW initiates bug report + * @WLAN_LOG_INDICATOR_HOST_ONLY: Host triggers fatal event bug report + * + * Enum indicating the module that triggered the bug report + */ +enum log_event_indicator { + WLAN_LOG_INDICATOR_UNUSED, + WLAN_LOG_INDICATOR_FRAMEWORK, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_INDICATOR_FIRMWARE, + WLAN_LOG_INDICATOR_HOST_ONLY, +}; + +/** + * enum log_event_host_reason_code - Reason code for bug report + * @WLAN_LOG_REASON_CODE_UNUSED: Unused + * @WLAN_LOG_REASON_ROAM_FAIL: Driver initiated roam has failed + * @WLAN_LOG_REASON_DATA_STALL: Unable to send/receive data due to low resource + * scenario for a prolonged period + * @WLAN_LOG_REASON_SME_COMMAND_STUCK: SME command is stuck in SME active queue + * @WLAN_LOG_REASON_QUEUE_FULL: Defer queue becomes full for a prolonged period + * @WLAN_LOG_REASON_POWER_COLLAPSE_FAIL: Unable to allow apps power collapse + * for a prolonged period + * @WLAN_LOG_REASON_MALLOC_FAIL: Memory allocation Fails + * @WLAN_LOG_REASON_VOS_MSG_UNDER_RUN: VOS Core runs out of message wrapper + * @WLAN_LOG_REASON_HDD_TIME_OUT: Wait for event Timeout in HDD layer + @WLAN_LOG_REASON_SME_OUT_OF_CMD_BUFL sme out of cmd buffer + * @WLAN_LOG_REASON_NO_SCAN_RESULTS: no scan results to report from HDD + * This enum contains the different reason codes for bug report + * @WLAN_LOG_REASON_SCAN_NOT_ALLOWED: scan not allowed due to connection states + * @WLAN_LOG_REASON_HB_FAILURE: station triggered heart beat failure with AP + * @WLAN_LOG_REASON_ROAM_HO_FAILURE: Handover failed during LFR3 roaming + * @WLAN_LOG_REASON_DISCONNECT: Disconnect because of some failure + * @WLAN_LOG_REASON_VDEV_DELETE_RSP_TIMED_OUT: vdev delete rsp time out + */ +enum log_event_host_reason_code { + WLAN_LOG_REASON_CODE_UNUSED, + WLAN_LOG_REASON_ROAM_FAIL, + WLAN_LOG_REASON_DATA_STALL, + WLAN_LOG_REASON_SME_COMMAND_STUCK, + WLAN_LOG_REASON_QUEUE_FULL, + WLAN_LOG_REASON_POWER_COLLAPSE_FAIL, + WLAN_LOG_REASON_MALLOC_FAIL, + WLAN_LOG_REASON_VOS_MSG_UNDER_RUN, + WLAN_LOG_REASON_HDD_TIME_OUT, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + WLAN_LOG_REASON_NO_SCAN_RESULTS, + WLAN_LOG_REASON_SCAN_NOT_ALLOWED, + WLAN_LOG_REASON_HB_FAILURE, + WLAN_LOG_REASON_ROAM_HO_FAILURE, + WLAN_LOG_REASON_DISCONNECT, + WLAN_LOG_REASON_VDEV_DELETE_RSP_TIMED_OUT +}; + + +/** + * enum userspace_log_level - Log level at userspace + * @LOG_LEVEL_NO_COLLECTION: verbose_level 0 corresponds to no collection + * @LOG_LEVEL_NORMAL_COLLECT: verbose_level 1 correspond to normal log level, + * with minimal user impact. this is the default value + * @LOG_LEVEL_ISSUE_REPRO: verbose_level 2 are enabled when user is lazily + * trying to reproduce a problem, wifi performances and power can be impacted + * but device should not otherwise be significantly impacted + * @LOG_LEVEL_ACTIVE: verbose_level 3+ are used when trying to + * actively debug a problem + * + * Various log levels defined in the userspace for logging applications + */ +enum userspace_log_level { + LOG_LEVEL_NO_COLLECTION, + LOG_LEVEL_NORMAL_COLLECT, + LOG_LEVEL_ISSUE_REPRO, + LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_driver_log_level - Log level defined in the driver for logging + * @WLAN_LOG_LEVEL_OFF: No logging + * @WLAN_LOG_LEVEL_NORMAL: Default logging + * @WLAN_LOG_LEVEL_REPRO: Normal debug level + * @WLAN_LOG_LEVEL_ACTIVE: Active debug level + * + * Log levels defined for logging by the wifi driver + */ +enum wifi_driver_log_level { + WLAN_LOG_LEVEL_OFF, + WLAN_LOG_LEVEL_NORMAL, + WLAN_LOG_LEVEL_REPRO, + WLAN_LOG_LEVEL_ACTIVE, +}; + +/** + * enum wifi_logging_ring_id - Ring id of logging entities + * @RING_ID_WAKELOCK: Power events ring id + * @RING_ID_CONNECTIVITY: Connectivity event ring id + * @RING_ID_PER_PACKET_STATS: Per packet statistic ring id + * @RING_ID_DRIVER_DEBUG: Driver debug messages ring id + * @RING_ID_FIRMWARE_DEBUG: Firmware debug messages ring id + * + * This enum has the ring id values of logging rings + */ +enum wifi_logging_ring_id { + RING_ID_WAKELOCK, + RING_ID_CONNECTIVITY, + RING_ID_PER_PACKET_STATS, + RING_ID_DRIVER_DEBUG, + RING_ID_FIRMWARE_DEBUG, +}; + +/* ------------------------------------------------------------------- */ +/* Change channel generic scheme */ +typedef void (*CHANGE_CHANNEL_CALLBACK)(struct mac_context *mac, QDF_STATUS status, + uint32_t *data, + struct pe_session *pe_session); + +typedef struct sDialogueToken { + /* bytes 0-3 */ + uint16_t assocId; + uint8_t token; + uint8_t rsvd1; + /* Bytes 4-7 */ + uint16_t tid; + uint8_t rsvd2[2]; + + struct sDialogueToken *next; +} tDialogueToken, *tpDialogueToken; + +typedef struct sLimTimers { + /* TIMERS IN LIM ARE NOT SUPPOSED TO BE ZEROED OUT DURING RESET. */ + /* DURING lim_initialize DONOT ZERO THEM OUT. */ + +/* STA SPECIFIC TIMERS */ + + TX_TIMER gLimPreAuthClnupTimer; + + /* Association related timers */ + TX_TIMER gLimAssocFailureTimer; + TX_TIMER gLimReassocFailureTimer; + + /* Authentication related timers */ + TX_TIMER gLimAuthFailureTimer; + + /* Join Failure timeout on STA */ + TX_TIMER gLimJoinFailureTimer; + + /* CNF_WAIT timer */ + TX_TIMER *gpLimCnfWaitTimer; + + TX_TIMER gLimAddtsRspTimer; /* max wait for a response */ + + /* Update OLBC Cache Timer */ + TX_TIMER gLimUpdateOlbcCacheTimer; + + TX_TIMER gLimFTPreAuthRspTimer; + + TX_TIMER gLimPeriodicJoinProbeReqTimer; + TX_TIMER gLimDisassocAckTimer; + TX_TIMER gLimDeauthAckTimer; + TX_TIMER g_lim_periodic_auth_retry_timer; + + /* SAE authentication related timer */ + TX_TIMER sae_auth_timer; + + /* RRM sta stats response related timer */ + TX_TIMER rrm_sta_stats_resp_timer; +/* ********************TIMER SECTION ENDS************************************************** */ +/* ALL THE FIELDS BELOW THIS CAN BE ZEROED OUT in lim_initialize */ +/* **************************************************************************************** */ + +} tLimTimers; + +typedef struct { + void *pMlmDisassocReq; + void *pMlmDeauthReq; +} tLimDisassocDeauthCnfReq; + +struct lim_context { + /* //////////////////////////////////// TIMER RELATED START /////////////////////////////////////////// */ + + tLimTimers lim_timers; + /* / Flag to track if LIM timers are created or not */ + uint32_t gLimTimersCreated; + + /* //////////////////////////////////// TIMER RELATED END /////////////////////////////////////////// */ + + uint8_t gLimCurrentBssUapsd; + /* //////////////////////////////////////// BSS RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATS/COUNTER RELATED START /////////////////////////////////////////// */ + + uint16_t maxStation; + uint16_t maxBssId; + + /* / Variable to keep track of number of currently associated STAs */ + uint16_t gLimNumOfAniSTAs; /* count of ANI peers */ + + tSirMacAddr gLimHeartBeatApMac[2]; + uint8_t gLimHeartBeatApMacIndex; + + /* //////////////////////////////////////// STATS/COUNTER RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// STATES RELATED START /////////////////////////////////////////// */ + /* Counts Heartbeat failures */ + uint8_t gLimHBfailureCntInLinkEstState; + uint8_t gLimProbeFailureAfterHBfailedCnt; + uint8_t gLimHBfailureCntInOtherStates; + + /** + * This variable indicates whether LIM module need to + * send response to host. Used to identify whether a request + * is generated internally within LIM module or by host + */ + uint8_t gLimRspReqd; + + /* / Previous SME State */ + tLimSmeStates gLimPrevSmeState; + + /* / MLM State visible across all Sirius modules */ + tLimMlmStates gLimMlmState; + + /* / Previous MLM State */ + tLimMlmStates gLimPrevMlmState; + + /* Can be set to invalid channel. If it is invalid, HAL */ + /* should move to previous valid channel or stay in the */ + /* current channel. CB state goes along with channel to resume to */ + uint16_t gResumeChannel; + ePhyChanBondState gResumePhyCbState; + + /* Change channel generic scheme */ + CHANGE_CHANNEL_CALLBACK gpchangeChannelCallback; + uint32_t *gpchangeChannelData; + + /* / SME State visible across all Sirius modules */ + tLimSmeStates gLimSmeState; + /* / This indicates whether we're an AP, STA in BSS/IBSS */ + tLimSystemRole gLimSystemRole; + + /* Number of STAs that do not support short preamble */ + tLimNoShortParams gLimNoShortParams; + + /* Number of STAs that do not support short slot time */ + tLimNoShortSlotParams gLimNoShortSlotParams; + + /* */ + /* ---------------- DPH ----------------------- */ + uint32_t gLimPhyMode; + + /* ---------------- DPH ----------------------- */ + + /* //////////////////////////////////////// STATES RELATED END /////////////////////////////////////////// */ + + /* //////////////////////////////////////// MISC RELATED START /////////////////////////////////////////// */ + + /* Deferred Queue Parameters */ + tLimDeferredMsgQParams gLimDeferredMsgQ; + + /* addts request if any - only one can be outstanding at any time */ + tSirAddtsReq gLimAddtsReq; + uint8_t gLimAddtsSent; + uint8_t gLimAddtsRspTimerCount; + + /* protection related config cache */ + tCfgProtection cfgProtection; + + uint8_t gLimProtectionControl; + /* This flag will remain to be set except while LIM is waiting for specific response messages */ + /* from HAL. e.g when LIM issues ADD_STA req it will clear this flag and when it will receive */ + /* the response the flag will be set. */ + uint8_t gLimProcessDefdMsgs; + + /* UAPSD flag used on AP */ + uint8_t gUapsdEnable; + + /* Used on STA for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That particular AC is not admitted + * If bit is set to 1: That particular AC is admitted + */ + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + /* dialogue token List head/tail for Action frames request sent. */ + tpDialogueToken pDialogueTokenHead; + tpDialogueToken pDialogueTokenTail; + + tLimTspecInfo tspecInfo[LIM_NUM_TSPEC_MAX]; + + /* admission control policy information */ + tLimAdmitPolicyInfo admitPolicyInfo; +#ifdef FEATURE_WLAN_TDLS + uint8_t gLimTDLSBufStaEnabled; + uint8_t gLimTDLSUapsdMask; + uint8_t gLimTDLSOffChannelEnabled; + uint8_t gLimTDLSWmmMode; +#endif + /* //////////////////////////////////////// MISC RELATED END /////////////////////////////////////////// */ + + /* ASSOC RELATED START */ + + /* Place holder for current authentication request */ + /* being handled */ + tLimMlmAuthReq *gpLimMlmAuthReq; + + /* Reason code to determine the channel change context while sending */ + /* WMA_CHNL_SWITCH_REQ message to HAL */ + uint32_t channelChangeReasonCode; + + /* / MAC level Pre-authentication related globals */ + tSirMacChanNum gLimPreAuthChannelNumber; + tAniAuthType gLimPreAuthType; + tSirMacAddr gLimPreAuthPeerAddr; + uint32_t gLimNumPreAuthContexts; + tLimPreAuthTable gLimPreAuthTimerTable; + + /* Place holder for Pre-authentication node list */ + struct tLimPreAuthNode *pLimPreAuthList; + + /* Assoc or ReAssoc Response Data/Frame */ + void *gLimAssocResponseData; + + /* One cache for each overlap and associated case. */ + tCacheParams protStaOverlapCache[LIM_PROT_STA_OVERLAP_CACHE_SIZE]; + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + /* Peer RSSI value */ + int8_t bss_rssi; + + /* ASSOC RELATED END */ + + /* ////////////////////////////// HT RELATED ////////////////////////////////////////// */ + /* */ + /* The following global LIM variables maintain/manage */ + /* the runtime configurations related to 802.11n */ + + /* 802.11n Station detected HT capability in Beacon Frame */ + uint8_t htCapabilityPresentInBeacon; + + /* 802.11 HT capability: Enabled or Disabled */ + uint8_t htCapability; + + uint8_t gHTGreenfield; + + uint8_t gHTShortGI40Mhz; + uint8_t gHTShortGI20Mhz; + + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t gHTMaxAmsduLength; + + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t gHTDsssCckRate40MHzSupport; + + /* PSMP Support: Enabled 1 or Disabled 0 */ + uint8_t gHTPSMPSupport; + + /* L-SIG TXOP Protection used only if peer support available */ + uint8_t gHTLsigTXOPProtection; + + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState gHTMIMOPSState; + + /* */ + /* A-MPDU Density */ + /* 000 - No restriction */ + /* 001 - 1/8 usec */ + /* 010 - 1/4 usec */ + /* 011 - 1/2 usec */ + /* 100 - 1 usec */ + /* 101 - 2 usec */ + /* 110 - 4 usec */ + /* 111 - 8 usec */ + /* */ + uint8_t gHTAMpduDensity; + + bool gMaxAmsduSizeEnabled; + /* Maximum Tx/Rx A-MPDU factor */ + uint8_t gHTMaxRxAMpduFactor; + + /* */ + /* Scheduled PSMP related - Service Interval Granularity */ + /* 000 - 5 ms */ + /* 001 - 10 ms */ + /* 010 - 15 ms */ + /* 011 - 20 ms */ + /* 100 - 25 ms */ + /* 101 - 30 ms */ + /* 110 - 35 ms */ + /* 111 - 40 ms */ + /* */ + uint8_t gHTServiceIntervalGranularity; + + /* Indicates whether an AP wants to associate PSMP enabled Stations */ + uint8_t gHTControlledAccessOnly; + + /* OBss Mode . set when we have Non HT STA is associated or with in overlap bss */ + uint8_t gHTObssMode; + + /* Identifies the current Operating Mode */ + tSirMacHTOperatingMode gHTOperMode; + + /* Indicates if PCO is activated in the BSS */ + uint8_t gHTPCOActive; + + /* */ + /* If PCO is active, indicates which PCO phase to use */ + /* 0 - switch to 20 MHz phase */ + /* 1 - switch to 40 MHz phase */ + /* */ + uint8_t gHTPCOPhase; + + /* */ + /* Used only in beacons. For PR, this is set to 0 */ + /* 0 - Primary beacon */ + /* 1 - Secondary beacon */ + /* */ + uint8_t gHTSecondaryBeacon; + + /* */ + /* Dual CTS Protection */ + /* 0 - Use RTS/CTS */ + /* 1 - Dual CTS Protection is used */ + /* */ + uint8_t gHTDualCTSProtection; + + /* */ + /* Identifies a single STBC MCS that shall ne used for */ + /* STBC control frames and STBC beacons */ + /* */ + uint8_t gHTSTBCBasicMCS; + + uint8_t gHTNonGFDevicesPresent; + + /* HT RELATED END */ + + /* wsc info required to form the wsc IE */ + tLimWscIeInfo wscIeInfo; + struct pe_session *gpSession; /* Pointer to session table */ + uint8_t max_sta_of_pe_session; + + qdf_mutex_t lim_frame_register_lock; + qdf_list_t gLimMgmtFrameRegistratinQueue; + uint32_t tdls_frm_session_id; + + struct pe_session *pe_session; + uint8_t reAssocRetryAttempt; + tLimDisassocDeauthCnfReq limDisassocDeauthCnfReq; + uint8_t deferredMsgCnt; + uint8_t deauthMsgCnt; + uint8_t disassocMsgCnt; + uint8_t gLimIbssStaLimit; + + QDF_STATUS(*sme_msg_callback) + (struct mac_context *mac, struct scheduler_msg *msg); + stop_roaming_fn_t stop_roaming_callback; + uint8_t retry_packet_cnt; + uint8_t beacon_probe_rsp_cnt_per_scan; + wlan_scan_requester req_id; + QDF_STATUS (*sme_bcn_rcv_callback)(hdd_handle_t hdd_handle, + struct wlan_beacon_report *beacon_report); +}; + +struct mgmt_frm_reg_info { + qdf_list_node_t node; /* MUST be first element */ + uint16_t frameType; + uint16_t matchLen; + uint16_t sessionId; + QDF_FLEX_ARRAY(uint8_t, matchData); +}; + +typedef struct sRrmContext { + struct rrm_config_param rrmConfig; + tRrmSMEContext rrmSmeContext[MAX_MEASUREMENT_REQUEST]; + tRrmPEContext rrmPEContext; +} tRrmContext, *tpRrmContext; + +/** + * enum tx_ack_status - Indicate TX status + * @LIM_ACK_NOT_RCD: Default status while waiting for ack status. + * @LIM_ACK_RCD_SUCCESS: Ack is received. + * @LIM_ACK_RCD_FAILURE: No Ack received. + * @LIM_TX_FAILED: Failed to TX + * + * Indicate if driver is waiting for ACK status of auth or ACK received for AUTH + * OR NO ACK is received for the auth sent. + */ +enum tx_ack_status { + LIM_ACK_NOT_RCD, + LIM_ACK_RCD_SUCCESS, + LIM_ACK_RCD_FAILURE, + LIM_TX_FAILED, +}; + +/** + * struct vdev_type_nss - vdev type nss structure + * @sta: STA Nss value. + * @sap: SAP Nss value. + * @p2p_go: P2P GO Nss value. + * @p2p_cli: P2P CLI Nss value. + * @p2p_dev: P2P device Nss value. + * @ibss: IBSS Nss value. + * @tdls: TDLS Nss value. + * @ocb: OCB Nss value. + * @nan: NAN Nss value. + * + * Holds the Nss values of different vdev types. + */ +struct vdev_type_nss { + uint8_t sta; + uint8_t sap; + uint8_t p2p_go; + uint8_t p2p_cli; + uint8_t p2p_dev; + uint8_t ibss; + uint8_t tdls; + uint8_t ocb; + uint8_t nan; + uint8_t ndi; +}; + +/** + * struct mgmt_beacon_probe_filter + * @num_sta_sessions: Number of active PE STA sessions + * @sta_bssid: Array of PE STA session's peer BSSIDs + * @num_sap_session: Number of active PE SAP sessions + * @sap_channel: Array of PE SAP session's channels + * + * Used to filter the STA/IBSS/SAP beacons/probes required in PE and + * drop other unwanted beacon/probe response frames + */ +struct mgmt_beacon_probe_filter { + uint8_t num_sta_sessions; + tSirMacAddr sta_bssid[WLAN_MAX_VDEVS]; + uint8_t num_sap_sessions; + uint8_t sap_channel[WLAN_MAX_VDEVS]; +}; + +#ifdef FEATURE_ANI_LEVEL_REQUEST +struct ani_level_params { + void (*ani_level_cb)(struct wmi_host_ani_level_event *ani, uint8_t num, + void *context); + void *context; +}; +#endif + +/** + * struct mac_context - Global MAC context + */ +struct mac_context { + enum qdf_driver_type gDriverType; + struct wlan_mlme_chain_cfg fw_chain_cfg; + struct wlan_mlme_cfg *mlme_cfg; + struct lim_context lim; + struct sch_context sch; + tAniSirSys sys; + + /* PAL/HDD handle */ + hdd_handle_t hdd_handle; + + struct sme_context sme; + tSapStruct sap; + struct csr_scanstruct scan; + struct csr_roamstruct roam; + tRrmContext rrm; + uint8_t beacon_offload; + bool pmf_offload; + uint32_t f_sta_miracast_mcc_rest_time_val; +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + csr_readyToExtWoWCallback readyToExtWoWCallback; + void *readyToExtWoWContext; +#endif + struct vdev_type_nss vdev_type_nss_2g; + struct vdev_type_nss vdev_type_nss_5g; + + uint16_t mgmtSeqNum; + sir_mgmt_frame_ind_callback mgmt_frame_ind_cb; + qdf_atomic_t global_cmd_id; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + void (*chan_info_cb)(struct scan_chan_info *chan_info); + void (*del_peers_ind_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id); + uint32_t rx_packet_drop_counter; + enum tx_ack_status auth_ack_status; + enum tx_ack_status assoc_ack_status; + uint8_t user_configured_nss; + uint32_t peer_rssi; + uint32_t peer_txrate; + uint32_t peer_rxrate; + uint32_t rx_retry_cnt; + uint32_t rx_mc_bc_cnt; + /* 11k Offload Support */ + bool is_11k_offload_supported; + uint8_t reject_addba_req; + uint16_t usr_cfg_ba_buff_size; + bool is_usr_cfg_amsdu_enabled; + uint8_t no_ack_policy_cfg[QCA_WLAN_AC_ALL]; + uint32_t he_sgi_ltf_cfg_bit_mask; + uint8_t usr_cfg_tx_bfee_nsts; + struct mgmt_beacon_probe_filter bcn_filter; + tSirMacEdcaParamRecord usr_mu_edca_params[QCA_WLAN_AC_ALL]; + bool usr_cfg_mu_edca_params; + bool he_om_ctrl_cfg_bw_set; + uint8_t he_om_ctrl_cfg_bw; + bool he_om_ctrl_cfg_nss_set; + uint8_t he_om_ctrl_cfg_nss; + bool he_om_ctrl_cfg_ul_mu_dis; + bool he_om_ctrl_cfg_tx_nsts_set; + uint8_t he_om_ctrl_cfg_tx_nsts; + bool he_om_ctrl_ul_mu_data_dis; + uint8_t usr_cfg_disable_rsp_tx; + uint8_t is_usr_cfg_pmf_wep; + uint8_t usr_cfg_ru_242_tone_tx; + bool usr_eht_testbed_cfg; +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_cap_2g; + tDot11fIEhe_cap he_cap_5g; + tDot11fIEhe_cap he_cap_2g_orig; + tDot11fIEhe_cap he_cap_5g_orig; +#endif + bool obss_scan_offload; + bool bcn_reception_stats; + csr_session_close_cb session_close_cb; + csr_roam_complete_cb session_roam_complete_cb; +#ifdef FEATURE_ANI_LEVEL_REQUEST + struct ani_level_params ani_params; +#endif +#ifdef WLAN_FEATURE_11BE + tDot11fIEeht_cap eht_cap_2g; + tDot11fIEeht_cap eht_cap_5g; + tDot11fIEeht_cap eht_cap_2g_orig; + tDot11fIEeht_cap eht_cap_5g_orig; +#endif +#ifdef WLAN_FEATURE_CAL_FAILURE_TRIGGER + void (*cal_failure_event_cb)(uint8_t cal_type, uint8_t reason); +#endif +}; + +#ifdef FEATURE_WLAN_TDLS + +#define RFC1042_HDR_LENGTH (6) +#define GET_BE16(x) ((uint16_t) (((x)[0] << 8) | (x)[1])) +#define ETH_TYPE_89_0d (0x890d) +#define ETH_TYPE_LEN (2) +#define PAYLOAD_TYPE_TDLS_SIZE (1) +#define PAYLOAD_TYPE_TDLS (2) + +#endif + +#endif /* _ANIGLOBAL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/ani_system_defs.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/ani_system_defs.h new file mode 100644 index 0000000000..24fd38213b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/ani_system_defs.h @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2011-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file ani_system_defs.h contains definitions used by + * various ANI entities + * Author: Chandra Modumudi + * Date: 09/18/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __ANI_SYSTEM_DEFS_H +#define __ANI_SYSTEM_DEFS_H + +#include "sir_types.h" +#include "sir_mac_prot_def.h" +#include "wlan_crypto_global_def.h" + +/* This is to force compiler to use the maximum of an int for enum */ +#define SIR_MAX_ENUM_SIZE 0x7FFFFFFF + +#ifndef false +#undef false +#define false 0 +#endif +#ifndef true +#undef true +#define true 1 +#endif + +/* / Authentication type enum used with peer */ +typedef enum eAniAuthType { + eSIR_OPEN_SYSTEM, + eSIR_SHARED_KEY, + eSIR_FT_AUTH, + eSIR_AUTH_TYPE_SAE = 3, +#if defined FEATURE_WLAN_ESE + eSIR_LEAP_AUTH = 0x80, +#endif + SIR_FILS_SK_WITHOUT_PFS = 4, + SIR_FILS_SK_WITH_PFS = 5, + SIR_FILS_PK_AUTH = 6, + eSIR_AUTH_TYPE_PASN = 7, + eSIR_AUTH_TYPE_OWE, + eSIR_AUTO_SWITCH, + eSIR_DONOT_USE_AUTH_TYPE = SIR_MAX_ENUM_SIZE +} tAniAuthType; + +enum ani_akm_type { + ANI_AKM_TYPE_NONE, + ANI_AKM_TYPE_RSN, + ANI_AKM_TYPE_RSN_PSK, + ANI_AKM_TYPE_FT_RSN, + ANI_AKM_TYPE_FT_RSN_PSK, + ANI_AKM_TYPE_RSN_PSK_SHA256, + ANI_AKM_TYPE_RSN_8021X_SHA256, + ANI_AKM_TYPE_SAE, + ANI_AKM_TYPE_FT_SAE, + ANI_AKM_TYPE_SUITEB_EAP_SHA256, + ANI_AKM_TYPE_SUITEB_EAP_SHA384, + ANI_AKM_TYPE_FT_SUITEB_EAP_SHA384, + ANI_AKM_TYPE_FILS_SHA256, + ANI_AKM_TYPE_FILS_SHA384, + ANI_AKM_TYPE_FT_FILS_SHA256, + ANI_AKM_TYPE_FT_FILS_SHA384, + ANI_AKM_TYPE_OWE, + ANI_AKM_TYPE_CCKM, + ANI_AKM_TYPE_OSEN, + ANI_AKM_TYPE_DPP_RSN, + ANI_AKM_TYPE_WPA, + ANI_AKM_TYPE_WPA_PSK, + ANI_AKM_TYPE_SAE_EXT_KEY, + ANI_AKM_TYPE_FT_SAE_EXT_KEY, + ANI_NUM_OF_SUPPORT_AKM_TYPE, + ANI_AKM_TYPE_UNKNOWN = 0xff, +}; + +/* / Encryption type enum used with peer */ +typedef enum eAniEdType { + eSIR_ED_NONE, + eSIR_ED_WEP40, + eSIR_ED_WEP104, + eSIR_ED_TKIP, + eSIR_ED_CCMP, +#if defined(FEATURE_WLAN_WAPI) + eSIR_ED_WPI, +#endif + /*DPU HW treats encryption mode 4 plus RMF bit set in TX BD as BIP. + Thus while setting BIP encryption mode in corresponding DPU Desc + eSIR_ED_AES_128_CMAC should be set to eSIR_ED_CCMP */ + eSIR_ED_AES_128_CMAC, + /* Firmware uses key length to find GCMP 128 or 256 */ + eSIR_ED_GCMP, + eSIR_ED_GCMP_256, + eSIR_ED_AES_GMAC_128, + eSIR_ED_AES_GMAC_256, + eSIR_ED_NOT_IMPLEMENTED = SIR_MAX_ENUM_SIZE +} tAniEdType; + +typedef struct sAniSSID { + uint8_t length; + uint8_t ssId[WLAN_SSID_MAX_LEN]; +} tAniSSID, *tpAniSSID; + +/* / RSN IE information */ +typedef struct sSirRSNie { + uint16_t length; + uint8_t rsnIEdata[WLAN_MAX_IE_LEN + 2]; +} tSirRSNie, *tpSirRSNie; + +typedef struct sSirWAPIie { + uint16_t length; + uint8_t wapiIEdata[WLAN_MAX_IE_LEN + 2]; +} tSirWAPIie, *tpSirWAPIie; +/* / Additional IE information : */ +/* / This can include WSC IE, P2P IE, and/or FTIE from upper layer. */ +/* / MAC layer transparently convey these IE info between peer STA and upper layer, */ +/* / but never requires to parse it. */ +typedef struct sSirAddie { + uint16_t length; + uint8_t addIEdata[SIR_MAC_MAX_ADD_IE_LENGTH + 2]; +} tSirAddie, *tpSirAddie; + +#define SIR_CIPHER_SEQ_CTR_SIZE 6 +/* / Definition for MIC failure indication */ +typedef struct sSirMicFailureInfo { + tSirMacAddr srcMacAddr; /* address used to compute MIC */ + tSirMacAddr taMacAddr; /* transmitter address */ + tSirMacAddr dstMacAddr; + bool multicast; + uint8_t IV1; /* first byte of IV */ + uint8_t keyId; /* second byte of IV */ + uint8_t TSC[SIR_CIPHER_SEQ_CTR_SIZE]; /* sequence number */ + tSirMacAddr rxMacAddr; /* receive address */ + +} tSirMicFailureInfo, *tpSirMicFailureInfo; + +typedef struct sTrafStrmMetrics { + uint8_t RoamingCount; + uint16_t RoamingDly; +} qdf_packed tTrafStrmMetrics, *tpTrafStrmMetrics; + +typedef struct sBcnReportFields { + uint8_t ChanNum; + uint8_t Spare; + uint16_t MeasDuration; + uint8_t PhyType; + uint8_t RecvSigPower; + tSirMacAddr Bssid; + uint32_t ParentTsf; + uint32_t TargetTsf[2]; + uint16_t BcnInterval; + uint16_t CapabilityInfo; +} qdf_packed tBcnReportFields, *tpBcnReportFields; + +#endif /* __ANI_SYSTEM_DEFS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/mac_init_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/mac_init_api.h new file mode 100644 index 0000000000..37345a6bce --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/mac_init_api.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * mac_init_api.c - Header file for mac level init functions + * Author: Dinesh Upadhyay + * Date: 04/23/2007 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ +#ifndef __MAC_INIT_API_H +#define __MAC_INIT_API_H + +#include "ani_global.h" +#include "sir_types.h" + +/** + * struct mac_start_params - parameters needed when starting the MAC + * @driver_type: Operating mode of the driver + */ +struct mac_start_params { + enum qdf_driver_type driver_type; +}; + +/** + * mac_start() - Start all MAC modules + * @mac_handle: Opaque handle to the MAC context + * @params: Parameters needed to start the MAC + * + * This function is called to start MAC. This function will start all + * the mac modules. + * + * Return: QDF_STATUS_SUCCESS if the MAC was successfully started. Any + * other value means that there was an issue with starting the + * MAC and the MAC should not be considered operational. + */ +QDF_STATUS mac_start(mac_handle_t mac_handle, + struct mac_start_params *params); + +/** + * mac_stop() - Stop all MAC modules + * @mac_handle: Opaque handle to the MAC context + * + * This function is called to stop MAC. This function will stop all + * the mac modules. + * + * Return: QDF_STATUS_SUCCESS if the MAC was successfully stopped. Any + * other value means that there was an issue with stopping the + * MAC, but the caller should still consider the MAC to be + * stopped. + */ +QDF_STATUS mac_stop(mac_handle_t mac_handle); + +/** + * mac_open() - Open the MAC + * @psoc: SOC global object + * @mac_handle: Pointer to where the MAC handle is to be stored + * @hdd_handle: Opaque handle to the HDD context + * @cds_cfg: Initial configuration + * + * This function will be called during init. This function is suppose + * to allocate all the memory with the global context will be + * allocated here. + * + * Return: QDF_STATUS_SUCCESS if the MAC was successfully opened and a + * MAC handle was returned to the caller. Any other value + * means the MAC was not opened. + */ +QDF_STATUS mac_open(struct wlan_objmgr_psoc *psoc, mac_handle_t *mac_handle, + hdd_handle_t hdd_handle, struct cds_config_info *cds_cfg); + +/** + * mac_close() - close the MAC + * @mac_handle: Opaque handle to the MAC context returned by mac_open() + * + * This function will be called in shutdown sequence from HDD. All the + * allocated memory with global context will be freed here. + * + * Return: QDF_STATUS_SUCCESS if the MAC was successfully closed. Any + * other value means that there was an issue with closing the + * MAC, but the caller should still consider the MAC to be + * closed. + */ +QDF_STATUS mac_close(mac_handle_t mac_handle); + +/** + * mac_register_session_open_close_cb() - register open/close session cb + * @mac_handle: Opaque handle to the MAC context + * @close_session: callback to be registered with SME for closing the session + * @callback: Common callback to hdd for all modes + */ +void mac_register_session_open_close_cb(mac_handle_t mac_handle, + csr_session_close_cb close_session, + csr_roam_complete_cb callback); + +#ifdef WLAN_BCN_RECV_FEATURE +/** + * mac_register_bcn_report_send_cb() - Register bcn receive start + * indication handler callback + * @mac: Pointer to Global MAC structure + * @cb: A pointer to store the callback + * + * Once driver gets QCA_NL80211_VENDOR_SUBCMD_BEACON_REPORTING vendor + * command with attribute for start only. MAC layer register a sme + * callback through this function. + * + * Return: None. + */ +void mac_register_bcn_report_send_cb(struct mac_context *mac, + beacon_report_cb cb); +#endif /* WLAN_BCN_RECV_FEATURE */ +#endif /* __MAC_INIT_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/mac_trace.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/mac_trace.h new file mode 100644 index 0000000000..1e9324a2a9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/mac_trace.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013-2016, 2018-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + * \file mac_trace.h + + * \brief definition for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __MAC_TRACE_H +#define __MAC_TRACE_H + +#include "ani_global.h" +#include "qdf_trace.h" + +#define MAC_TRACE_GET_MODULE_ID(data) ((data >> 8) & 0xff) +#define MAC_TRACE_GET_MSG_ID(data) (data & 0xffff) + +/** + * mac_trace() - Main function used for MAC Trace + * @mac_ctx: Global MAC context + * @code: trace code + * @session: session id + * @data: data to be traced. + * + * Return: None + */ +static inline void mac_trace(struct mac_context *mac_ctx, uint16_t code, + uint16_t session, uint32_t data) +{ + qdf_trace(QDF_MODULE_ID_PE, code, session, data); +} + +#ifdef TRACE_RECORD + +#define eLOG_NODROP_MISSED_BEACON_SCENARIO 0 +#define eLOG_PROC_DEAUTH_FRAME_SCENARIO 1 + +uint8_t *mac_trace_get_lim_msg_string(uint16_t limMsg); +uint8_t *mac_trace_get_sme_msg_string(uint16_t smeMsg); +uint8_t *mac_trace_get_info_log_string(uint16_t infoLog); + +#endif +uint8_t *mac_trace_get_wma_msg_string(uint16_t wmaMsg); +uint8_t *mac_trace_getcsr_roam_state(uint16_t csr_roamState); +uint8_t *mac_trace_getcsr_roam_sub_state(uint16_t csr_roamSubState); +uint8_t *mac_trace_get_lim_sme_state(uint16_t limState); +uint8_t *mac_trace_get_lim_mlm_state(uint16_t mlmState); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/qwlan_version.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/qwlan_version.h new file mode 100644 index 0000000000..3ab34b013f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/qwlan_version.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef QWLAN_VERSION_H +#define QWLAN_VERSION_H +/*=========================================================================== + + FILE: + qwlan_version.h + + BRIEF DESCRIPTION: + WLAN Host Version file. + Build number automatically updated by build scripts. + + ===========================================================================*/ + +#define QWLAN_VERSION_MAJOR 5 +#define QWLAN_VERSION_MINOR 2 +#define QWLAN_VERSION_PATCH 1 +#define QWLAN_VERSION_EXTRA "C" +#define QWLAN_VERSION_BUILD 93 + +#define QWLAN_VERSIONSTR "5.2.1.93C" + +#endif /* QWLAN_VERSION_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_api.h new file mode 100644 index 0000000000..31be571a28 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_api.h @@ -0,0 +1,5032 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file sir_api.h contains definitions exported by + * Sirius software. + * Author: Chandra Modumudi + * Date: 04/16/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIR_API_H +#define __SIR_API_H + +/* legacy definition */ +typedef void *tpAniSirGlobal; + +struct mac_context; +#include "qdf_types.h" +#include "cds_regdomain.h" +#include "sir_types.h" +#include "sir_mac_prot_def.h" +#include "ani_system_defs.h" +#include "sir_params.h" +#include "cds_regdomain.h" +#include "wmi_unified.h" +#include "wmi_unified_param.h" +#include "ol_txrx_htt_api.h" +#include "wlan_reg_services_api.h" +#include +#include "wlan_policy_mgr_api.h" +#include "wlan_tdls_public_structs.h" +#include "qca_vendor.h" +#include "wlan_cp_stats_mc_defs.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include "wlan_mlo_mgr_public_structs.h" +#endif + +#define OFFSET_OF(structType, fldName) (&((structType *)0)->fldName) +#define WLAN_DOT11_BASIC_RATE_MASK (0x80) +#define BITS_ON(_Field, _Bitmask) ((_Field) |= (_Bitmask)) +#define BITS_OFF(_Field, _Bitmask) ((_Field) &= ~(_Bitmask)) + +/* / Max supported channel list */ +#define SIR_MAX_SUPPORTED_CHANNEL_LIST 96 + +#define SIR_MDIE_SIZE 3 /* MD ID(2 bytes), Capability(1 byte) */ + +#define SIR_MAX_ELEMENT_ID 255 + +#define SIR_BCN_REPORT_MAX_BSS_DESC 8 + +#define SIR_NUM_11B_RATES 4 /* 1,2,5.5,11 */ +#define SIR_NUM_11A_RATES 8 /* 6,9,12,18,24,36,48,54 */ + +typedef uint8_t tSirIpv4Addr[QDF_IPV4_ADDR_SIZE]; + +#define SIR_VERSION_STRING_LEN 1024 +typedef uint8_t tSirVersionString[SIR_VERSION_STRING_LEN]; + +/* Periodic Tx pattern offload feature */ +#define PERIODIC_TX_PTRN_MAX_SIZE 1536 +#ifndef MAXNUM_PERIODIC_TX_PTRNS +#define MAXNUM_PERIODIC_TX_PTRNS 6 +#endif + +/* FW response timeout values in milli seconds */ +#define SIR_PEER_ASSOC_TIMEOUT (4000) /* 4 seconds */ + +#ifdef FEATURE_RUNTIME_PM +/* Add extra PMO_RESUME_TIMEOUT for runtime PM resume timeout */ +#define SIR_PEER_CREATE_RESPONSE_TIMEOUT (4000 + PMO_RESUME_TIMEOUT) +#define SIR_DELETE_STA_TIMEOUT (4000 + PMO_RESUME_TIMEOUT) +#define SIR_VDEV_PLCY_MGR_TIMEOUT (4000 + PMO_RESUME_TIMEOUT) +#else +#define SIR_PEER_CREATE_RESPONSE_TIMEOUT (4000) +#define SIR_DELETE_STA_TIMEOUT (4000) /* 4 seconds */ +#define SIR_VDEV_PLCY_MGR_TIMEOUT (4000) +#endif + +#define MAX_POWER_DBG_ARGS_SUPPORTED 8 +#define QOS_MAP_MAX_EX 21 +#define QOS_MAP_RANGE_NUM 8 +#define QOS_MAP_LEN_MIN (QOS_MAP_RANGE_NUM * 2) +#define QOS_MAP_LEN_MAX \ + (QOS_MAP_LEN_MIN + 2 * QOS_MAP_MAX_EX) +#define NUM_CHAINS_MAX 2 + +/* Maximum number of realms present in fils indication element */ +#define SIR_MAX_REALM_COUNT 7 +/* Realm length */ +#define SIR_REALM_LEN 2 +/* Cache ID length */ +#define CACHE_ID_LEN 2 + +/* Maximum peer station number query one time */ +#define MAX_PEER_STA 12 + +/* Maximum number of peers for SAP */ +#ifndef SIR_SAP_MAX_NUM_PEERS +#define SIR_SAP_MAX_NUM_PEERS 32 +#endif + +#define SIR_KEK_KEY_LEN 16 +#define SIR_KEK_KEY_LEN_FILS 64 + +#define SIR_FILS_HLP_OUI_TYPE "\x5" +#define SIR_FILS_HLP_OUI_LEN 1 +#define SIR_FILS_HLP_IE_LEN 2048 + +#define SIR_REPLAY_CTR_LEN 8 +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define SIR_UAPSD_BITOFFSET_ACVO 0 +#define SIR_UAPSD_BITOFFSET_ACVI 1 +#define SIR_UAPSD_BITOFFSET_ACBK 2 +#define SIR_UAPSD_BITOFFSET_ACBE 3 + +#define SIR_UAPSD_FLAG_ACVO (1 << SIR_UAPSD_BITOFFSET_ACVO) +#define SIR_UAPSD_FLAG_ACVI (1 << SIR_UAPSD_BITOFFSET_ACVI) +#define SIR_UAPSD_FLAG_ACBK (1 << SIR_UAPSD_BITOFFSET_ACBK) +#define SIR_UAPSD_FLAG_ACBE (1 << SIR_UAPSD_BITOFFSET_ACBE) +#define SIR_UAPSD_GET(ac, mask) (((mask) & (SIR_UAPSD_FLAG_ ## ac)) >> SIR_UAPSD_BITOFFSET_ ## ac) + +#endif + +/* Maximum management packet data unit length */ +#define MAX_MGMT_MPDU_LEN 2304 + +struct scheduler_msg; + +/** + * enum sir_roam_op_code - Operation to be done by the callback. + * @SIR_ROAM_SYNCH_PROPAGATION: Propagate the new BSS info after roaming. + * @SIR_ROAMING_DEREGISTER_STA: Deregister the old STA after roaming. + * @SIR_ROAMING_START: Firmware started roaming operation + * @SIR_ROAMING_ABORT: Firmware aborted roaming operation, still connected. + * @SIR_ROAM_SYNCH_COMPLETE: Roam sync propagation is complete. + * @SIR_ROAMING_INVOKE_FAIL: Firmware roaming failed. + * @SIR_ROAMING_DEAUTH: Firmware indicates deauth. + */ +enum sir_roam_op_code { + SIR_ROAM_SYNCH_PROPAGATION = 1, + SIR_ROAMING_DEREGISTER_STA, + SIR_ROAMING_START, + SIR_ROAMING_ABORT, + SIR_ROAM_SYNCH_COMPLETE, + SIR_ROAM_SYNCH_NAPI_OFF, + SIR_ROAMING_INVOKE_FAIL, + SIR_ROAMING_DEAUTH, +}; + +/** + * enum ps_state - State of the power save + * @FULL_POWER_MODE: for Full power mode + * @LEGACY_POWER_SAVE_MODE: For Legacy Power Save mode + * @UAPSD_MODE: for UAPSD power save + */ +enum ps_state { + FULL_POWER_MODE, + LEGACY_POWER_SAVE_MODE, + UAPSD_MODE +}; + +/** + * \var g_phy_rates_suppt + * + * \brief Rate support lookup table + * + * + * This is a lookup table indexing rates & configuration parameters to + * support. Given a rate (in unites of 0.5Mpbs) & three bools (MIMO + * Enabled, Channel Bonding Enabled, & Concatenation Enabled), one can + * determine whether the given rate is supported by computing two + * indices. The first maps the rate to table row as indicated below + * (i.e. eHddSuppRate_6Mbps maps to row zero, eHddSuppRate_9Mbps to row + * 1, and so on). Index two can be computed like so: + * + * \code + * idx2 = ( fEsf ? 0x4 : 0x0 ) | + * ( fCb ? 0x2 : 0x0 ) | + * ( fMimo ? 0x1 : 0x0 ); + * \endcode + * + * + * Given that: + * + * \code + * fSupported = g_phy_rates_suppt[idx1][idx2]; + * \endcode + * + * + * This table is based on the document "PHY Supported Rates.doc". This + * table is permissive in that a rate is reflected as being supported + * even when turning off an enabled feature would be required. For + * instance, "PHY Supported Rates" lists 42Mpbs as unsupported when CB, + * ESF, & MIMO are all on. However, if we turn off either of CB or + * MIMO, it then becomes supported. Therefore, we mark it as supported + * even in index 7 of this table. + * + * + */ + +static const bool g_phy_rates_suppt[24][8] = { + + /* SSF SSF SSF SSF ESF ESF ESF ESF */ + /* SIMO MIMO SIMO MIMO SIMO MIMO SIMO MIMO */ + /* No CB No CB CB CB No CB No CB CB CB */ + {true, true, true, true, true, true, true, true}, /* 6Mbps */ + {true, true, true, true, true, true, true, true}, /* 9Mbps */ + {true, true, true, true, true, true, true, true}, /* 12Mbps */ + {true, true, true, true, true, true, true, true}, /* 18Mbps */ + {false, false, true, true, false, false, true, true}, /* 20Mbps */ + {true, true, true, true, true, true, true, true}, /* 24Mbps */ + {true, true, true, true, true, true, true, true}, /* 36Mbps */ + {false, false, true, true, false, true, true, true}, /* 40Mbps */ + {false, false, true, true, false, true, true, true}, /* 42Mbps */ + {true, true, true, true, true, true, true, true}, /* 48Mbps */ + {true, true, true, true, true, true, true, true}, /* 54Mbps */ + {false, true, true, true, false, true, true, true}, /* 72Mbps */ + {false, false, true, true, false, true, true, true}, /* 80Mbps */ + {false, false, true, true, false, true, true, true}, /* 84Mbps */ + {false, true, true, true, false, true, true, true}, /* 96Mbps */ + {false, true, true, true, false, true, true, true}, /* 108Mbps */ + {false, false, true, true, false, true, true, true}, /* 120Mbps */ + {false, false, true, true, false, true, true, true}, /* 126Mbps */ + {false, false, false, true, false, false, false, true}, /* 144Mbps */ + {false, false, false, true, false, false, false, true}, /* 160Mbps */ + {false, false, false, true, false, false, false, true}, /* 168Mbps */ + {false, false, false, true, false, false, false, true}, /* 192Mbps */ + {false, false, false, true, false, false, false, true}, /* 216Mbps */ + {false, false, false, true, false, false, false, true}, /* 240Mbps */ +}; + +typedef enum { + /* 11b rates */ + SUPP_RATE_1_MBPS = 1 * 2, + SUPP_RATE_2_MBPS = 2 * 2, + SUPP_RATE_5_MBPS = 11, + SUPP_RATE_11_MBPS = 11 * 2, + + /* 11a / 11g rates */ + SUPP_RATE_6_MBPS = 6 * 2, + SUPP_RATE_9_MBPS = 9 * 2, + SUPP_RATE_12_MBPS = 12 * 2, + SUPP_RATE_18_MBPS = 18 * 2, + SUPP_RATE_24_MBPS = 24 * 2, + SUPP_RATE_36_MBPS = 36 * 2, + SUPP_RATE_48_MBPS = 48 * 2, + SUPP_RATE_54_MBPS = 54 * 2, + + /* Airgo prop. rates */ + SUPP_RATE_20_MBPS = 20 * 2, + SUPP_RATE_40_MBPS = 40 * 2, + SUPP_RATE_42_MBPS = 42 * 2, + SUPP_RATE_72_MBPS = 72 * 2, + SUPP_RATE_80_MBPS = 80 * 2, + SUPP_RATE_84_MBPS = 84 * 2, + SUPP_RATE_96_MBPS = 96 * 2, + SUPP_RATE_108_MBPS = 108 * 2, + SUPP_RATE_120_MBPS = 120 * 2, + SUPP_RATE_126_MBPS = 126 * 2, + SUPP_RATE_144_MBPS = 144 * 2, + SUPP_RATE_160_MBPS = 160 * 2, + SUPP_RATE_168_MBPS = 168 * 2, + SUPP_RATE_192_MBPS = 192 * 2, + SUPP_RATE_216_MBPS = 216 * 2, + SUPP_RATE_240_MBPS = 240 * 2 +} eCsrSupportedRates; + +/** + * struct ps_params - maintain power save state and USAPD params + * @mac_ctx: mac_ctx + * @session_id: Session Id. + * @ps_state : State of the power save + * @uapsd_per_ac_trigger_enable_mask: dynamic UPASD mask setting + * derived from AddTS Rsp and DelTS frame. + * If a particular AC bit is set, it means AC is trigger enabled. + * @uapsd_per_ac_delivery_enable_mask: dynamic UPASD mask setting + * derived from AddTS Rsp and DelTs frame. + * If a particular AC bit is set, it means AC is delivery enabled. + * @ac_admit_mask: used for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That particular AC is not admitted + * If bit is set to 1: That particular AC is admitted + * @uapsd_per_ac_bit_mask: This is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. + * If a particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + * @auto_ps_enable_timer: Upon expiration of this timer Power Save Offload + * module will try to enable sta mode ps + */ + +struct ps_params { + void *mac_ctx; + uint32_t session_id; + enum ps_state ps_state; + uint8_t uapsd_per_ac_trigger_enable_mask; + uint8_t uapsd_per_ac_delivery_enable_mask; + uint8_t ac_admit_mask[SIR_MAC_DIRECTION_DIRECT]; + uint8_t uapsd_per_ac_bit_mask; + qdf_mc_timer_t auto_ps_enable_timer; +}; + +/* Type declarations used by Firmware and Host software */ + +/* Scan type enum used in scan request */ +typedef enum eSirScanType { + eSIR_PASSIVE_SCAN, + eSIR_ACTIVE_SCAN, + eSIR_BEACON_TABLE, +} tSirScanType; + +/** + * struct roam_scan_ch_resp - roam scan chan list response to userspace + * @vdev_id: vdev id + * @num_channels: number of roam scan channels + * @command_resp: command response or async event + * @chan_list: list of roam scan channels + */ +struct roam_scan_ch_resp { + uint16_t vdev_id; + uint16_t num_channels; + uint32_t command_resp; + uint32_t *chan_list; +}; + +/** + * struct wlan_beacon_report - Beacon info to be send to userspace + * @vdev_id: vdev id + * @ssid: ssid present in beacon + * @bssid: bssid present in beacon + * @frequency: channel frequency in MHz + * @beacon_interval: Interval between two consecutive beacons + * @time_stamp: time stamp at which beacon received from AP + * @boot_time: Boot time when beacon received + */ +struct wlan_beacon_report { + uint8_t vdev_id; + struct wlan_ssid ssid; + struct qdf_mac_addr bssid; + uint32_t frequency; + uint16_t beacon_interval; + qdf_time_t time_stamp; + qdf_time_t boot_time; +}; + + +/* / Result codes Firmware return to Host SW */ +typedef enum eSirResultCodes { + eSIR_SME_SUCCESS, + eSIR_LOGE_EXCEPTION, + eSIR_SME_INVALID_PARAMETERS = 500, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE, + eSIR_SME_RESOURCES_UNAVAILABLE, + /* Unable to find a BssDescription */ + eSIR_SME_SCAN_FAILED, + /* matching requested scan criteria */ + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED, + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE, + eSIR_SME_REFUSED, + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA, + eSIR_SME_JOIN_TIMEOUT_RESULT_CODE, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE, + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, + eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED, + eSIR_SME_AUTH_REFUSED, + eSIR_SME_INVALID_WEP_DEFAULT_KEY, + eSIR_SME_NO_KEY_MAPPING_KEY_FOR_PEER, + eSIR_SME_ASSOC_REFUSED, + eSIR_SME_REASSOC_REFUSED, + /* Recvd Deauth while join/pre-auth */ + eSIR_SME_DEAUTH_WHILE_JOIN, + eSIR_SME_STA_NOT_AUTHENTICATED, + eSIR_SME_STA_NOT_ASSOCIATED, + eSIR_SME_ALREADY_JOINED_A_BSS, + /* Given in SME_SCAN_RSP msg */ + eSIR_SME_MORE_SCAN_RESULTS_FOLLOW, + /* that more SME_SCAN_RSP */ + /* messages are following. */ + /* SME_SCAN_RSP message with */ + /* eSIR_SME_SUCCESS status */ + /* code is the last one. */ + /* Sent in SME_JOIN/REASSOC_RSP */ + eSIR_SME_INVALID_ASSOC_RSP_RXED, + /* messages upon receiving */ + /* invalid Re/Assoc Rsp frame. */ + /* STOP BSS triggered by MIC failures: MAC software to + * disassoc all stations + */ + eSIR_SME_MIC_COUNTER_MEASURES, + /* with MIC_FAILURE reason code and perform the stop bss operation */ + /* didn't get rsp from peer within timeout interval */ + eSIR_SME_ADDTS_RSP_TIMEOUT, + /* didn't get success rsp from HAL */ + eSIR_SME_ADDTS_RSP_FAILED, + /* failed to send ch switch act frm */ + eSIR_SME_CHANNEL_SWITCH_FAIL, + eSIR_SME_INVALID_STATE, + /* SIR_HAL_SIR_HAL_INIT_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_INIT_FAILED, + /* SIR_HAL_END_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_END_FAILED, + /* SIR_HAL_FINISH_SCAN_RSP returned failed status */ + eSIR_SME_HAL_SCAN_FINISH_FAILED, + /* Failed to send a message to HAL */ + eSIR_SME_HAL_SEND_MESSAGE_FAIL, + /* Failed to stop the bss */ + eSIR_SME_STOP_BSS_FAILURE, + eSIR_SME_WOWL_ENTER_REQ_FAILED, + eSIR_SME_WOWL_EXIT_REQ_FAILED, + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE, + eSIR_SME_FT_REASSOC_FAILURE, + eSIR_SME_SEND_ACTION_FAIL, + eSIR_SME_DEAUTH_STATUS, + eSIR_PNO_SCAN_SUCCESS, + eSIR_SME_INVALID_SESSION, + eSIR_DONOT_USE_RESULT_CODE = SIR_MAX_ENUM_SIZE +} tSirResultCodes; + +#ifdef WLAN_FEATURE_FILS_SK +struct fils_join_rsp_params { + uint8_t *fils_pmk; + uint8_t fils_pmk_len; + uint8_t fils_pmkid[PMKID_LEN]; + uint8_t kek[MAX_KEK_LEN]; + uint8_t kek_len; + uint8_t tk[MAX_TK_LEN]; + uint8_t tk_len; + uint8_t gtk_len; + uint8_t gtk[MAX_GTK_LEN]; + struct qdf_mac_addr dst_mac; + struct qdf_mac_addr src_mac; + uint16_t hlp_data_len; + uint8_t hlp_data[FILS_MAX_HLP_DATA_LEN]; +}; +#endif + +#define RMENABLEDCAP_MAX_LEN 5 + +struct rrm_config_param { + uint8_t rrm_enabled; + bool sap_rrm_enabled; + uint8_t max_randn_interval; + uint8_t rm_capability[RMENABLEDCAP_MAX_LEN]; +}; + +const char *lim_bss_type_to_string(const uint16_t bss_type); +/** + * struct supported_rates - stores rates/MCS supported + * @llbRates: 11b rates in unit of 500kbps + * @llaRates: 11a rates in unit of 500kbps + * @supportedMCSSet: supported basic MCS, 0-76 bits used, remaining reserved + * bits 0-15 and 32 should be set. + * @rxHighestDataRate: RX Highest Supported Data Rate defines the highest data + * rate that the STA is able to receive, in unites of 1Mbps + * This value is derived from "Supported MCS Set field" + * inside the HT capability element. + * @vhtRxMCSMap: Indicates the Maximum MCS(VHT) that can be received for each + * number of spacial streams + * @vhtRxHighestDataRate: Indicate the highest VHT data rate that the STA is + * able to receive + * @vhtTxMCSMap: Indicates the Maximum MCS(VHT) that can be transmitted for + * each number of spacial streams + * @vhtTxHighestDataRate: Indicate the highest VHT data rate that the STA is + * able to transmit + * @he_rx_mcs: Indicates the Maximum MCS(HE) that can be received for each + * number of spacial streams + * @he_tx_mcs: Indicates the Maximum MCS(HE) that can be transmitted for each + * number of spacial streams + * @bw_20_rx_max_nss_for_mcs_0_to_7: Indicates MAX RX NSS for MCS from 0 to 7 + * @bw_20_tx_max_nss_for_mcs_0_to_7: Indicates MAX TX NSS for MCS from 0 to 7 + * @bw_20_rx_max_nss_for_mcs_8_and_9: Indicates MAX RX NSS for MCS from 8 9 + * @bw_20_tx_max_nss_for_mcs_8_and_9: Indicates MAX TX NSS for MCS from 8 9 + * @bw_20_rx_max_nss_for_mcs_10_and_11:Indicates MAX RX NSS for MCS from 10 11 + * @bw_20_tx_max_nss_for_mcs_10_and_11: Indicates MAX TX NSS for MCS from 10 11 + * @bw_20_rx_max_nss_for_mcs_12_and_13: Indicates MAX RX NSS for MCS from 12 13 + * @bw_20_tx_max_nss_for_mcs_12_and_13: Indicates MAX TX NSS for MCS from 12 13 + * @bw_le_80_rx_max_nss_for_mcs_0_to_7: Indicates MAX RX NSS for MCS from 0 to 7 + * @bw_le_80_tx_max_nss_for_mcs_0_to_7: Indicates MAX TX NSS for MCS from 0 to 7 + * @bw_le_80_rx_max_nss_for_mcs_8_and_9: Indicates MAX RX NSS for MCS from 8 9 + * @bw_le_80_tx_max_nss_for_mcs_8_and_9: Indicates MAX TX NSS for MCS from 8 9 + * @bw_le_80_rx_max_nss_for_mcs_10_and_11:Indicates MAX RX NSS for MCS from + * 10 11 + * @bw_le_80_tx_max_nss_for_mcs_10_and_11: Indicates MAX TX NSS for MCS from + * 10 11 + * @bw_le_80_rx_max_nss_for_mcs_12_and_13: Indicates MAX RX NSS for MCS from + * 12 13 + * @bw_le_80_tx_max_nss_for_mcs_12_and_13: Indicates MAX TX NSS for MCS from + * 12 13 + * @bw_160_rx_max_nss_for_mcs_0_to_7: Indicates MAX RX NSS for MCS from 0 to 7 + * @bw_160_tx_max_nss_for_mcs_0_to_7: Indicates MAX TX NSS for MCS from 0 to 7 + * @bw_160_rx_max_nss_for_mcs_8_and_9: Indicates MAX RX NSS for MCS from 8 9 + * @bw_160_tx_max_nss_for_mcs_8_and_9: Indicates MAX TX NSS for MCS from 8 9 + * @bw_160_rx_max_nss_for_mcs_10_and_11:Indicates MAX RX NSS for MCS from + * 10 11 + * @bw_160_tx_max_nss_for_mcs_10_and_11: Indicates MAX TX NSS for MCS from + * 10 11 + * @bw_160_rx_max_nss_for_mcs_12_and_13: Indicates MAX RX NSS for MCS from + * 12 13 + * @bw_160_tx_max_nss_for_mcs_12_and_13: Indicates MAX TX NSS for MCS from + * 12 13 + * @bw_320_rx_max_nss_for_mcs_0_to_7: Indicates MAX RX NSS for MCS from 0 to 7 + * @bw_320_tx_max_nss_for_mcs_0_to_7: Indicates MAX TX NSS for MCS from 0 to 7 + * @bw_320_rx_max_nss_for_mcs_8_and_9: Indicates MAX RX NSS for MCS from 8 9 + * @bw_320_tx_max_nss_for_mcs_8_and_9: Indicates MAX TX NSS for MCS from 8 9 + * @bw_320_rx_max_nss_for_mcs_10_and_11:Indicates MAX RX NSS for MCS from + * 10 11 + * @bw_320_tx_max_nss_for_mcs_10_and_11: Indicates MAX TX NSS for MCS from + * 10 11 + * @bw_320_rx_max_nss_for_mcs_12_and_13: Indicates MAX RX NSS for MCS from + * 12 13 + * @bw_320_tx_max_nss_for_mcs_12_and_13: Indicates MAX TX NSS for MCS from + * 12 13 + */ +struct supported_rates { + uint16_t llbRates[SIR_NUM_11B_RATES]; + uint16_t llaRates[SIR_NUM_11A_RATES]; + uint8_t supportedMCSSet[SIR_MAC_MAX_SUPPORTED_MCS_SET]; + uint16_t rxHighestDataRate; + uint16_t vhtRxMCSMap; + uint16_t vhtRxHighestDataRate; + uint16_t vhtTxMCSMap; + uint16_t vhtTxHighestDataRate; +#ifdef WLAN_FEATURE_11AX + uint16_t rx_he_mcs_map_lt_80; + uint16_t tx_he_mcs_map_lt_80; + uint16_t rx_he_mcs_map_160; + uint16_t tx_he_mcs_map_160; + uint16_t rx_he_mcs_map_80_80; + uint16_t tx_he_mcs_map_80_80; +#endif +#ifdef WLAN_FEATURE_11BE + uint32_t bw_20_rx_max_nss_for_mcs_0_to_7:4; + uint32_t bw_20_tx_max_nss_for_mcs_0_to_7:4; + uint32_t bw_20_rx_max_nss_for_mcs_8_and_9:4; + uint32_t bw_20_tx_max_nss_for_mcs_8_and_9:4; + uint32_t bw_20_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_20_tx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_20_rx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_20_tx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_le_80_rx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_le_80_tx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_le_80_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_le_80_tx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_le_80_rx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_le_80_tx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_160_rx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_160_tx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_160_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_160_tx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_160_rx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_160_tx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_320_rx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_320_tx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_320_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_320_tx_max_nss_for_mcs_10_and_11:4; + uint8_t bw_320_rx_max_nss_for_mcs_12_and_13:4; + uint8_t bw_320_tx_max_nss_for_mcs_12_and_13:4; +#endif +}; + +struct register_mgmt_frame { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + bool registerFrame; + uint16_t frameType; + uint16_t matchLen; + QDF_FLEX_ARRAY(uint8_t, matchData); +}; + +/* / Generic type for sending a response message */ +/* / with result code to host software */ +typedef struct sSirSmeRsp { + uint16_t messageType; /* eWNI_SME_*_RSP */ + uint16_t length; + uint8_t vdev_id; + tSirResultCodes status_code; + struct wlan_objmgr_psoc *psoc; +} tSirSmeRsp, *tpSirSmeRsp; + +struct bss_description; +struct roam_offload_synch_ind; +struct roam_pmkid_req_event; + +/** + * typedef pe_roam_synch_fn_t - PE roam synch callback routine pointer + * @mac_ctx: Global MAC context + * @vdev_id: vdev id + * @roam_sync_ind_ptr: Structure with roam synch parameters + * @ie_len: ie length + * @reason: Reason for calling the callback + * + * This type is for callbacks registered with WMA to complete the roam synch + * propagation at PE level. It also fills the BSS descriptor, which will be + * helpful to complete the roam synch propagation. + * + * Return: Success or Failure. + */ +typedef QDF_STATUS +(*pe_roam_synch_fn_t)(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *roam_sync_ind_ptr, + uint16_t ie_len, + enum sir_roam_op_code reason); + +/** + * typedef stop_roaming_fn_t - Stop roaming routine pointer + * @mac_handle: Pointer to opaque mac handle + * @session_id: Session Identifier + * @reason: Reason for calling the callback + * @requestor: Requestor for disabling roaming in driver + * + * This type is for callbacks registered with WMA to stop roaming on the given + * session ID + * + * Return: Success or Failure. + */ +typedef QDF_STATUS +(*stop_roaming_fn_t)(mac_handle_t mac_handle, + uint8_t session_id, uint8_t reason, + enum wlan_cm_rso_control_requestor requestor); + +/** + * typedef set_ies_fn_t - Set IEs routine pointer + * @mac_ctx: Global MAC context + * @vdev_id: vdev id + * @dot11_mode: dot11 mode + * @opmode: device opmode + * + * This type is for callbacks registered with WMA to set the IEs for a + * given vdev id to the firmware. + * + * Return: Success or Failure + */ +typedef QDF_STATUS +(*set_ies_fn_t)(struct mac_context *mac_ctx, uint8_t vdev_id, + uint16_t dot11_mode, enum QDF_OPMODE device_mode); + +/* / Definition for indicating all modules ready on STA */ +struct sme_ready_req { + uint16_t messageType; /* eWNI_SME_SYS_READY_IND */ + uint16_t length; + QDF_STATUS (*csr_roam_auth_event_handle_cb)(struct mac_context *mac, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm); + pe_roam_synch_fn_t pe_roam_synch_cb; + stop_roaming_fn_t stop_roaming_cb; + QDF_STATUS (*sme_msg_cb)(struct mac_context *mac, + struct scheduler_msg *msg); + QDF_STATUS (*pe_disconnect_cb) (struct mac_context *mac, + uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code); + set_ies_fn_t pe_roam_set_ie_cb; +}; + +/** + * struct s_sir_set_hw_mode - Set HW mode request + * @messageType: Message type + * @length: Length of the message + * @set_hw: Params containing the HW mode index and callback + */ +struct s_sir_set_hw_mode { + uint16_t messageType; + uint16_t length; + struct policy_mgr_hw_mode set_hw; +}; + +/** + * struct sir_set_dual_mac_cfg - Set Dual mac config request + * @message_type: Message type + * @length: Length of the message + * @set_dual_mac: Params containing the dual mac config and callback + */ +struct sir_set_dual_mac_cfg { + uint16_t message_type; + uint16_t length; + struct policy_mgr_dual_mac_config set_dual_mac; +}; + +/** + * struct sir_antenna_mode_param - antenna mode param + * @num_tx_chains: Number of TX chains + * @num_rx_chains: Number of RX chains + * @set_antenna_mode_resp: callback to set antenna mode command + * @set_antenna_mode_ctx: callback context to set antenna mode command + */ +struct sir_antenna_mode_param { + uint32_t num_tx_chains; + uint32_t num_rx_chains; + void *set_antenna_mode_resp; + void *set_antenna_mode_ctx; +}; + +/** + * struct sir_set_antenna_mode - Set antenna mode request + * @message_type: Message type + * @length: Length of the message + * @set_antenna_mode: Params containing antenna mode params + */ +struct sir_set_antenna_mode { + uint16_t message_type; + uint16_t length; + struct sir_antenna_mode_param set_antenna_mode; +}; + +/** + * enum bss_type - Enum for BSS type used in scanning/joining etc. + * + * @eSIR_INFRASTRUCTURE_MODE: Infrastructure station + * @eSIR_INFRA_AP_MODE: softAP mode + * @eSIR_AUTO_MODE: Auto role + * @eSIR_MONITOR_MODE: Monitor mode + * @eSIR_NDI_MODE: NAN datapath mode + */ +enum bss_type { + eSIR_INFRASTRUCTURE_MODE, + eSIR_INFRA_AP_MODE, + eSIR_AUTO_MODE, + eSIR_MONITOR_MODE, + eSIR_NDI_MODE, + eSIR_DONOT_USE_BSS_TYPE = SIR_MAX_ENUM_SIZE +}; + +/* / Power Capability info used in 11H */ +struct power_cap_info { + uint8_t minTxPower; + uint8_t maxTxPower; +}; + +/* / Supported Channel info used in 11H */ +struct supported_channels { + uint8_t numChnl; + uint8_t channelList[SIR_MAX_SUPPORTED_CHANNEL_LIST]; +}; + +typedef enum eSirNwType { + eSIR_11A_NW_TYPE, + eSIR_11B_NW_TYPE, + eSIR_11G_NW_TYPE, + eSIR_11N_NW_TYPE, + eSIR_11AC_NW_TYPE, + eSIR_11AX_NW_TYPE, + eSIR_11BE_NW_TYPE, + eSIR_DONOT_USE_NW_TYPE = SIR_MAX_ENUM_SIZE +} tSirNwType; + +struct add_ie_params { + uint16_t probeRespDataLen; + uint8_t *probeRespData_buff; + uint16_t assocRespDataLen; + uint8_t *assocRespData_buff; + uint16_t probeRespBCNDataLen; + uint8_t *probeRespBCNData_buff; +}; + +#define GET_IE_LEN_IN_BSS(lenInBss) (lenInBss + sizeof(lenInBss) - \ + ((uintptr_t)OFFSET_OF(struct bss_description,\ + ieFields))) + +#define WSCIE_PROBE_RSP_LEN (317 + 2) + +#ifdef WLAN_FEATURE_FILS_SK +/* struct fils_ind_elements: elements parsed from fils indication present + * in beacon/probe resp + * @realm_cnt: number of realm present + * @realm: realms + * @is_fils_sk_supported: if FILS SK supported + * @is_cache_id_present: if cache id present + * @cache_id: cache id + */ +struct fils_ind_elements { + uint16_t realm_cnt; + uint8_t realm[SIR_MAX_REALM_COUNT][SIR_REALM_LEN]; + bool is_fils_sk_supported; + bool is_cache_id_present; + uint8_t cache_id[CACHE_ID_LEN]; +}; +#endif + +struct bss_description { + /* offset of the ieFields from bssId. */ + uint16_t length; + tSirMacAddr bssId; + uint32_t timeStamp[2]; + uint16_t beaconInterval; + uint16_t capabilityInfo; + tSirNwType nwType; /* Indicates 11a/b/g */ + int8_t rssi; + int8_t rssi_raw; + /* channel frequency what peer sent in beacon/probersp. */ + uint32_t chan_freq; + /* Based on system time, not a relative time. */ + uint32_t parentTSF; + uint32_t startTSF[2]; + uint8_t mdiePresent; + /* MDIE for 11r, picked from the beacons */ + uint8_t mdie[SIR_MDIE_SIZE]; + /* whether it is from a probe rsp */ + uint8_t fProbeRsp; + struct scan_mbssid_info mbssid_info; +#ifdef WLAN_FEATURE_FILS_SK + struct fils_ind_elements fils_info_element; +#endif + uint32_t adaptive_11r_ap; + uint32_t mbo_oce_enabled_ap; +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) + uint32_t is_single_pmk; +#endif + uint32_t is_ml_ap; + /* Please keep the structure 4 bytes aligned above the ieFields */ + QDF_FLEX_ARRAY(uint32_t, ieFields); +}; + +/* / Definition for response message to previously */ +/* / issued start BSS request */ +/* / MAC ---> */ +struct start_bss_rsp { + uint8_t vdev_id; + tSirResultCodes status_code; + uint32_t staId; /* Station ID for Self */ +}; + +struct report_channel_list { + uint8_t num_channels; + uint32_t chan_freq_lst[SIR_ESE_MAX_MEAS_IE_REQS]; +}; + +#ifdef FEATURE_OEM_DATA_SUPPORT +struct oem_data_req { + uint32_t data_len; + uint8_t *data; +}; + +struct oem_data_rsp { + uint32_t rsp_len; + uint8_t *data; +}; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +#ifdef FEATURE_WLAN_ESE +typedef struct ese_wmm_tspec_ie { + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t tsinfo_rsvd:7; + uint8_t burst_size_defn:1; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} qdf_packed ese_wmm_tspec_ie; + +typedef struct sTspecInfo { + uint8_t valid; + struct mac_tspec_ie tspec; +} tTspecInfo; + +typedef struct sESETspecTspecInfo { + uint8_t numTspecs; + tTspecInfo tspec[ESE_MAX_TSPEC_IES]; +} tESETspecInfo; + +struct tsm_ie { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +}; + +struct tsm_ie_ind { + struct tsm_ie tsm_ie; + uint8_t sessionId; +}; + +typedef struct sAniTrafStrmMetrics { + uint16_t UplinkPktQueueDly; + uint16_t UplinkPktQueueDlyHist[4]; + uint32_t UplinkPktTxDly; + uint16_t UplinkPktLoss; + uint16_t UplinkPktCount; + uint8_t RoamingCount; + uint16_t RoamingDly; +} tAniTrafStrmMetrics, *tpAniTrafStrmMetrics; + +typedef struct sAniGetTsmStatsReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t tid; /* traffic id */ + struct qdf_mac_addr bssId; + void *tsmStatsCallback; + void *pDevContext; /* device context */ +} tAniGetTsmStatsReq, *tpAniGetTsmStatsReq; + +typedef struct sAniGetTsmStatsRsp { + /* Common for all types are responses */ + uint16_t msgType; /* + * message type is same as + * the request type + */ + uint16_t msgLen; /* + * length of the entire request, + * includes the pStatsBuf length too + */ + uint8_t sessionId; + uint32_t rc; /* success/failure */ + struct qdf_mac_addr bssid; /* bssid to get the tsm stats for */ + tAniTrafStrmMetrics tsmMetrics; + void *tsmStatsReq; /* tsm stats request backup */ +} tAniGetTsmStatsRsp, *tpAniGetTsmStatsRsp; + +struct ese_bcn_report_bss_info { + tBcnReportFields bcnReportFields; + uint8_t ieLen; + uint8_t *pBuf; +}; + +struct ese_bcn_report_rsp { + uint16_t measurementToken; + uint8_t flag; /* Flag to report measurement done and more data */ + uint8_t numBss; + struct ese_bcn_report_bss_info + bcnRepBssInfo[SIR_BCN_REPORT_MAX_BSS_DESC]; +}; + +#define TSRS_11AG_RATE_6MBPS 0xC +#define TSRS_11B_RATE_5_5MBPS 0xB + +struct ese_tsrs_ie { + uint8_t tsid; + uint8_t rates[8]; +}; + +struct ese_tsm_ie { + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +}; + +typedef struct sTSMStats { + uint8_t tid; + struct qdf_mac_addr bssid; + tTrafStrmMetrics tsmMetrics; +} tTSMStats, *tpTSMStats; +typedef struct sEseTSMContext { + uint8_t tid; + struct ese_tsm_ie tsmInfo; + tTrafStrmMetrics tsmMetrics; +} tEseTSMContext, *tpEseTSMContext; +typedef struct sEsePEContext { + tEseTSMContext tsm; +} tEsePEContext, *tpEsePEContext; + +#endif /* FEATURE_WLAN_ESE */ + +/* Warning Do not add any new param in this struct */ +struct join_req { + tSirRSNie rsnIE; + tSirAddie addIEScan; + tSirAddie addIEAssoc; +#ifdef WLAN_FEATURE_11BE_MLO + struct mlo_partner_info partner_info; + uint8_t assoc_link_id; + bool is_ml_probe_req_sent; +#endif + /* Warning:::::::::::: Do not add any new param in this struct */ + /* Pls make this as last variable in struct */ + struct bss_description bssDescription; + /* + * WARNING: Pls make bssDescription as last variable in struct + * join_req as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +}; + +struct oem_channel_info { + uint32_t mhz; + uint32_t band_center_freq1; + uint32_t band_center_freq2; + uint32_t info; + uint32_t reg_info_1; + uint32_t reg_info_2; + uint8_t nss; + uint32_t rate_flags; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; +}; + +enum sir_sme_phy_mode { + SIR_SME_PHY_MODE_LEGACY = 0, + SIR_SME_PHY_MODE_HT = 1, + SIR_SME_PHY_MODE_VHT = 2 +}; + +/* / Definition for Association indication from peer */ +/* / MAC ---> */ +struct assoc_ind { + uint16_t messageType; /* eWNI_SME_ASSOC_IND */ + uint16_t length; + uint8_t sessionId; + tSirMacAddr peerMacAddr; + uint16_t aid; + tSirMacAddr bssId; /* Self BSSID */ + uint16_t staId; /* Station ID for peer */ + tAniAuthType authType; + enum ani_akm_type akm_type; + tAniSSID ssId; /* SSID used by STA to associate */ + tSirWAPIie wapiIE; /* WAPI IE received from peer */ + tSirRSNie rsnIE; /* RSN IE received from peer */ + /* Additional IE received from peer, which possibly include + * WSC IE and/or P2P IE + */ + tSirAddie addIE; + + /* powerCap & supportedChannels are present only when */ + /* spectrumMgtIndicator flag is set */ + bool spectrumMgtIndicator; + struct power_cap_info powerCap; + struct supported_channels supportedChannels; + bool wmmEnabledSta; /* if present - STA is WMM enabled */ + bool reassocReq; + /* Required for indicating the frames to upper layer */ + uint32_t assocReqLength; + uint8_t *assocReqPtr; + + /* Timing measurement capability */ + uint8_t timingMeasCap; + struct oem_channel_info chan_info; + bool ampdu; + bool sgi_enable; + bool tx_stbc; + bool rx_stbc; + tSirMacHTChannelWidth ch_width; + enum sir_sme_phy_mode mode; + uint8_t max_supp_idx; + uint8_t max_ext_idx; + uint8_t max_mcs_idx; + uint8_t max_real_mcs_idx; + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + /* Extended CSA capability of station */ + uint8_t ecsa_capable; + uint32_t ext_cap; + uint8_t supported_band; + tDot11fIEHTCaps HTCaps; + tDot11fIEVHTCaps VHTCaps; + bool he_caps_present; + bool eht_caps_present; + tSirMacCapabilityInfo capability_info; + bool is_sae_authenticated; + const uint8_t *owe_ie; + uint32_t owe_ie_len; + uint16_t owe_status; + const uint8_t *ft_ie; + uint32_t ft_ie_len; + uint16_t ft_status; + bool need_assoc_rsp_tx_cb; + tSirMacAddr peer_mld_addr; +}; + +/** + * struct owe_assoc_ind - owe association indication + * @node : List entry element + * @assoc_ind: pointer to assoc ind + */ +struct owe_assoc_ind { + qdf_list_node_t node; + struct assoc_ind *assoc_ind; +}; + +/** + * struct ft_assoc_ind - ft association indication + * @node: List entry element + * @assoc_ind: pointer to assoc ind + */ +struct ft_assoc_ind { + qdf_list_node_t node; + struct assoc_ind *assoc_ind; +}; + +/* / Definition for Association confirm */ +/* / ---> MAC */ +struct assoc_cnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + tSirResultCodes status_code; + struct qdf_mac_addr bssid; /* Self BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t aid; + enum wlan_status_code mac_status_code; + uint8_t *owe_ie; + uint32_t owe_ie_len; + uint8_t *ft_ie; + uint32_t ft_ie_len; + bool need_assoc_rsp_tx_cb; +}; + +/** + * Table below indicates what information is passed for each of + * the Wireless Media status change notifications: + * + * Status Change code Status change info + * ---------------------------------------------------------------------- + * eSIR_SME_DEAUTH_FROM_PEER Reason code received in DEAUTH frame + * eSIR_SME_DISASSOC_FROM_PEER Reason code received in DISASSOC frame + * eSIR_SME_LOST_LINK_WITH_PEER None + * eSIR_SME_CHANNEL_SWITCH New channel number + * eSIR_SME_RADAR_DETECTED Indicates that radar is detected + * eSIR_SME_AP_CAPS_CHANGED Indicates that capabilities of the AP + * that STA is currently associated with + * have changed. + */ + +/* Definition for Disassociation request */ +struct disassoc_req { + uint16_t messageType; /* eWNI_SME_DISASSOC_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + struct qdf_mac_addr bssid; /* Peer BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; + /* This flag tells LIM whether to send the disassoc OTA or not */ + /* This will be set in while handing off from one AP to other */ + uint8_t doNotSendOverTheAir; + bool process_ho_fail; +}; + +/* / Definition for Disassociation response */ +struct disassoc_rsp { + uint16_t messageType; /* eWNI_SME_DISASSOC_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirResultCodes status_code; + struct qdf_mac_addr peer_macaddr; + uint16_t staId; +}; + +/* / Definition for Disassociation indication from peer */ +struct disassoc_ind { + uint16_t messageType; /* eWNI_SME_DISASSOC_IND */ + uint16_t length; + uint8_t vdev_id; + tSirResultCodes status_code; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; + struct qdf_mac_addr peer_mld_addr; + uint16_t staId; + uint32_t reasonCode; + bool from_ap; +}; + +/* / Definition for Disassociation confirm */ +/* / MAC ---> */ +struct disassoc_cnf { + uint16_t messageType; /* eWNI_SME_DISASSOC_CNF */ + uint16_t length; + uint8_t vdev_id; + tSirResultCodes status_code; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; +}; + +/** + * struct sir_sme_discon_done_ind - disconnect done indiaction + * @message_type: msg type + * @length: length of msg + * @session_id: session id of the indication + * @reason_code: reason for disconnect indication + * @peer_mac: peer mac + */ +struct sir_sme_discon_done_ind { + uint16_t message_type; + uint16_t length; + uint8_t session_id; + tSirResultCodes reason_code; + tSirMacAddr peer_mac; +}; + +/* / Definition for Deauthetication request */ +struct deauth_req { + uint16_t messageType; /* eWNI_SME_DEAUTH_REQ */ + uint16_t length; + uint8_t vdev_id; /* Session ID */ + struct qdf_mac_addr bssid; /* AP BSSID */ + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; +}; + +/** + * struct deauth_retry_params - deauth retry params + * @peer_mac: peer mac + * @reason_code: reason for disconnect indication + * @retry_cnt: retry count + */ +struct deauth_retry_params { + struct qdf_mac_addr peer_macaddr; + uint16_t reason_code; + uint8_t retry_cnt; +}; + +/* / Definition for Deauthetication response */ +struct deauth_rsp { + uint16_t messageType; /* eWNI_SME_DEAUTH_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirResultCodes status_code; + struct qdf_mac_addr peer_macaddr; +}; + +/* / Definition for Deauthetication indication from peer */ +struct deauth_ind { + uint16_t messageType; /* eWNI_SME_DEAUTH_IND */ + uint16_t length; + uint8_t vdev_id; + tSirResultCodes status_code; + struct qdf_mac_addr bssid; /* AP BSSID */ + struct qdf_mac_addr peer_macaddr; + struct qdf_mac_addr peer_mld_addr; + + uint16_t staId; + uint32_t reasonCode; + int8_t rssi; + bool from_ap; +}; + +/* / Definition for Deauthetication confirm */ +struct deauth_cnf { + uint16_t messageType; /* eWNI_SME_DEAUTH_CNF */ + uint16_t length; + uint8_t vdev_id; + tSirResultCodes status_code; + struct qdf_mac_addr bssid; + struct qdf_mac_addr peer_macaddr; +}; + +struct stop_bss_req { + uint8_t vdev_id; + uint32_t cmd_id; +}; + +struct stop_bss_rsp { + uint8_t vdev_id; + tSirResultCodes status_code; +}; + +/* / Definition for Channel Switch indication for station */ +/* / MAC ---> */ +struct switch_channel_ind { + uint16_t messageType; /* eWNI_SME_SWITCH_CHL_IND */ + uint16_t length; + uint8_t sessionId; + uint32_t freq; + struct ch_params chan_params; + struct qdf_mac_addr bssid; /* BSSID */ + QDF_STATUS status; + enum wlan_phymode ch_phymode; +}; + +/* / Definition for MIC failure indication */ +/* / MAC ---> */ +/* / MAC reports this each time a MIC failure occurs on Rx TKIP packet */ +struct mic_failure_ind { + uint16_t messageType; /* eWNI_SME_MIC_FAILURE_IND */ + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr bssId; + tSirMicFailureInfo info; +}; + +struct missed_beacon_ind { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bss_idx; + int32_t rssi; +}; + +/* / Definition for Set Context response */ +/* / MAC ---> */ +struct set_context_rsp { + uint16_t messageType; /* eWNI_SME_SET_CONTEXT_RSP */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + tSirResultCodes status_code; + struct qdf_mac_addr peer_macaddr; +}; + +typedef struct sAniGetSnrReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + void *snrCallback; + void *pDevContext; /* device context */ + int8_t snr; +} tAniGetSnrReq, *tpAniGetSnrReq; + +/* generic country code change request MSG structure */ +typedef struct sAniGenericChangeCountryCodeReq { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t countryCode[REG_ALPHA2_LEN + 1]; /* 3 char country code */ +} tAniGenericChangeCountryCodeReq, *tpAniGenericChangeCountryCodeReq; + +/** + * struct sAniDHCPStopInd - DHCP Stop indication message + * @msgType: message type is same as the request type + * @msgLen: length of the entire request + * @device_mode: Mode of the device(ex:STA, AP) + * @adapterMacAddr: MAC address of the adapter + * @peerMacAddr: MAC address of the connected peer + */ +typedef struct sAniDHCPStopInd { + uint16_t msgType; + uint16_t msgLen; + uint8_t device_mode; + struct qdf_mac_addr adapterMacAddr; + struct qdf_mac_addr peerMacAddr; +} tAniDHCPInd, *tpAniDHCPInd; + +/**********************PE Statistics end*************************/ + +typedef struct sSirP2PNoaAttr { +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t index:8; + uint32_t oppPsFlag:1; + uint32_t ctWin:7; + uint32_t rsvd1:16; +#else + uint32_t rsvd1:16; + uint32_t ctWin:7; + uint32_t oppPsFlag:1; + uint32_t index:8; +#endif + +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t uNoa1IntervalCnt:8; + uint32_t rsvd2:24; +#else + uint32_t rsvd2:24; + uint32_t uNoa1IntervalCnt:8; +#endif + uint32_t uNoa1Duration; + uint32_t uNoa1Interval; + uint32_t uNoa1StartTime; + +#ifdef ANI_BIG_BYTE_ENDIAN + uint32_t uNoa2IntervalCnt:8; + uint32_t rsvd3:24; +#else + uint32_t rsvd3:24; + uint32_t uNoa2IntervalCnt:8; +#endif + uint32_t uNoa2Duration; + uint32_t uNoa2Interval; + uint32_t uNoa2StartTime; +} tSirP2PNoaAttr, *tpSirP2PNoaAttr; + +typedef struct sSirTclasInfo { + tSirMacTclasIE tclas; + uint8_t version; /* applies only for classifier type ip */ + union { + tSirMacTclasParamEthernet eth; + tSirMacTclasParamIPv4 ipv4; + tSirMacTclasParamIPv6 ipv6; + tSirMacTclasParam8021dq t8021dq; + } qdf_packed tclasParams; +} qdf_packed tSirTclasInfo; + +typedef struct sSirAddtsReqInfo { + uint8_t dialogToken; + struct mac_tspec_ie tspec; + + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; +#if defined(FEATURE_WLAN_ESE) + struct ese_tsrs_ie tsrsIE; + uint8_t tsrsPresent:1; +#endif + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; + uint8_t tclasProcPresent:1; +} tSirAddtsReqInfo, *tpSirAddtsReqInfo; + +typedef struct sSirAddtsRspInfo { + uint8_t dialogToken; + enum wlan_status_code status; + tSirMacTsDelayIE delay; + + struct mac_tspec_ie tspec; + uint8_t numTclas; /* number of Tclas elements */ + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + tSirMacScheduleIE schedule; +#ifdef FEATURE_WLAN_ESE + struct ese_tsm_ie tsmIE; + uint8_t tsmPresent:1; +#endif + uint8_t wmeTspecPresent:1; + uint8_t wsmTspecPresent:1; + uint8_t lleTspecPresent:1; + uint8_t tclasProcPresent:1; + uint8_t schedulePresent:1; +} tSirAddtsRspInfo, *tpSirAddtsRspInfo; + +/* / Add a tspec as defined */ +typedef struct sSirAddtsReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + struct qdf_mac_addr bssid; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAddtsReqInfo req; +} tSirAddtsReq, *tpSirAddtsReq; + +typedef struct sSirAddtsRsp { + uint16_t messageType; /* eWNI_SME_ADDTS_RSP */ + uint16_t length; + uint8_t sessionId; /* sme sessionId Added for BT-AMP support */ + uint32_t rc; /* return code */ + tSirAddtsRspInfo rsp; +} tSirAddtsRsp, *tpSirAddtsRsp; + +typedef struct sSirDeltsReq { + uint16_t messageType; /* eWNI_SME_DELTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + struct qdf_mac_addr bssid; /* BSSID */ + uint16_t aid; /* use 0 if macAddr is being specified */ + struct qdf_mac_addr macaddr; /* only on AP to specify the STA */ + uint8_t rspReqd; + struct delts_req_info req; +} tSirDeltsReq, *tpSirDeltsReq; + +typedef struct sSirDeltsRsp { + uint16_t messageType; /* eWNI_SME_DELTS_RSP */ + uint16_t length; + uint8_t sessionId; + uint32_t rc; + uint16_t aid; /* use 0 if macAddr is being specified */ + struct qdf_mac_addr macaddr; /* only on AP to specify the STA */ + struct delts_req_info rsp; +} tSirDeltsRsp, *tpSirDeltsRsp; + +typedef struct sSirAggrQosReqInfo { + uint16_t tspecIdx; + tSirAddtsReqInfo aggrAddTsInfo[QCA_WLAN_AC_ALL]; +} tSirAggrQosReqInfo, *tpSirAggrQosReqInfo; + +typedef struct sSirAggrQosReq { + uint16_t messageType; /* eWNI_SME_ADDTS_REQ */ + uint16_t length; + uint8_t sessionId; /* Session ID */ + struct qdf_mac_addr bssid; /* BSSID */ + uint32_t timeout; /* in ms */ + uint8_t rspReqd; + tSirAggrQosReqInfo aggrInfo; +} tSirAggrQosReq; + +typedef struct sSirAggrQosRspInfo { + uint16_t tspecIdx; + tSirAddtsRspInfo aggrRsp[QCA_WLAN_AC_ALL]; +} tSirAggrQosRspInfo, *tpSirAggrQosRspInfo; + +typedef struct sSirAggrQosRsp { + uint16_t messageType; + uint16_t length; + uint8_t sessionId; + tSirAggrQosRspInfo aggrInfo; +} tSirAggrQosRsp, *tpSirAggrQosRsp; + + +struct qos_map_set { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[QOS_MAP_MAX_EX][2]; + uint8_t dscp_range[QOS_MAP_RANGE_NUM][2]; +}; + +typedef struct sSmeMaxAssocInd { + uint16_t mesgType; /* eWNI_SME_MAX_ASSOC_EXCEEDED */ + uint16_t mesgLen; + uint8_t sessionId; + /* the new peer that got rejected max assoc limit reached */ + struct qdf_mac_addr peer_mac; +} tSmeMaxAssocInd, *tpSmeMaxAssocInd; + +#define SIR_MAX_NAME_SIZE 64 +#define SIR_MAX_TEXT_SIZE 32 + +typedef struct sSirName { + uint8_t num_name; + uint8_t name[SIR_MAX_NAME_SIZE]; +} tSirName; + +typedef struct sSirText { + uint8_t num_text; + uint8_t text[SIR_MAX_TEXT_SIZE]; +} tSirText; + +#define SIR_WPS_PROBRSP_VER_PRESENT 0x00000001 +#define SIR_WPS_PROBRSP_STATE_PRESENT 0x00000002 +#define SIR_WPS_PROBRSP_APSETUPLOCK_PRESENT 0x00000004 +#define SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT 0x00000008 +#define SIR_WPS_PROBRSP_DEVICEPASSWORDID_PRESENT 0x00000010 +#define SIR_WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT 0x00000040 +#define SIR_WPS_PROBRSP_UUIDE_PRESENT 0x00000080 +#define SIR_WPS_PROBRSP_MANUFACTURE_PRESENT 0x00000100 +#define SIR_WPS_PROBRSP_MODELNAME_PRESENT 0x00000200 +#define SIR_WPS_PROBRSP_MODELNUMBER_PRESENT 0x00000400 +#define SIR_WPS_PROBRSP_SERIALNUMBER_PRESENT 0x00000800 +#define SIR_WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT 0x00001000 +#define SIR_WPS_PROBRSP_DEVICENAME_PRESENT 0x00002000 +#define SIR_WPS_PROBRSP_CONFIGMETHODS_PRESENT 0x00004000 +#define SIR_WPS_PROBRSP_RF_BANDS_PRESENT 0x00008000 + +typedef struct sSirWPSProbeRspIE { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* + * BOOL: indicates if the user has recently activated a Registrar to + * add an Enrollee. + */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t ResponseType; /* Response type */ + uint8_t UUID_E[16]; /* Unique identifier of the AP. */ + tSirName Manufacture; + tSirText ModelName; + tSirText ModelNumber; + tSirText SerialNumber; + /* Device Category ID: 1Computer, 2Input Device, ... */ + uint32_t PrimaryDeviceCategory; + /* Vendor specific OUI for Device Sub Category */ + uint8_t PrimaryDeviceOUI[4]; + /* + Device Sub Category ID: 1-PC, 2-Server if Device Category ID + * is computer + */ + uint32_t DeviceSubCategory; + tSirText DeviceName; + uint16_t ConfigMethod; /* Configuration method */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSirWPSProbeRspIE; + +#define SIR_WPS_BEACON_VER_PRESENT 0x00000001 +#define SIR_WPS_BEACON_STATE_PRESENT 0x00000002 +#define SIR_WPS_BEACON_APSETUPLOCK_PRESENT 0x00000004 +#define SIR_WPS_BEACON_SELECTEDREGISTRA_PRESENT 0x00000008 +#define SIR_WPS_BEACON_DEVICEPASSWORDID_PRESENT 0x00000010 +#define SIR_WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT 0x00000020 +#define SIR_WPS_BEACON_UUIDE_PRESENT 0x00000080 +#define SIR_WPS_BEACON_RF_BANDS_PRESENT 0x00000100 +#define SIR_WPS_UUID_LEN 16 + +typedef struct sSirWPSBeaconIE { + uint32_t FieldPresent; + uint32_t Version; /* Version. 0x10 = version 1.0, 0x11 = etc. */ + uint32_t wpsState; /* 1 = unconfigured, 2 = configured. */ + bool APSetupLocked; /* Must be included if value is true */ + /* + * BOOL: indicates if the user has recently activated a Registrar to + * add an Enrollee. + */ + bool SelectedRegistra; + uint16_t DevicePasswordID; /* Device Password ID */ + /* Selected Registrar config method */ + uint16_t SelectedRegistraCfgMethod; + uint8_t UUID_E[SIR_WPS_UUID_LEN]; /* Unique identifier of the AP. */ + uint8_t RFBand; /* RF bands available on the AP */ +} tSirWPSBeaconIE; + +typedef struct sSirAPWPSIEs { + tSirWPSProbeRspIE SirWPSProbeRspIE; /*WPS Set Probe Response IE */ + tSirWPSBeaconIE SirWPSBeaconIE; /*WPS Set Beacon IE */ +} tSirAPWPSIEs, *tpSiriAPWPSIEs; + +struct update_config { + uint16_t messageType; /* eWNI_SME_UPDATE_CONFIG */ + uint16_t length; + uint8_t vdev_id; + uint16_t capab; + uint32_t value; +}; + +/* + * enum sir_update_session_param_type - session param type + * @SIR_PARAM_SSID_HIDDEN: ssidHidden parameter + */ +enum sir_update_session_param_type { + SIR_PARAM_SSID_HIDDEN, +}; + +/* + * struct sir_update_session_param + * @message_type: SME message type + * @length: size of struct sir_update_session_param + * @vdev_id: vdev ID + * @param_type: parameter to be updated + * @param_val: Parameter value to update + */ +struct sir_update_session_param { + uint16_t message_type; + uint16_t length; + uint8_t vdev_id; + uint32_t param_type; + uint32_t param_val; +}; + +/** + * struct sir_set_he_bss_color + * @message_type: SME message type + * @length: size of struct sir_set_he_bss_color + * @vdev_id: vdev ID + * @bss_color: bss color value + */ +struct sir_set_he_bss_color { + uint16_t message_type; + uint16_t length; + uint8_t vdev_id; + uint8_t bss_color; +}; + +/** + * struct sir_cfg_obss_scan + * @message_type: SME message type + * @length: size of struct sir_cfg_obss_scan + * @vdev_id: vdev ID + * @is_scan_reconfig: true for NDP session + */ +struct sir_cfg_obss_scan { + uint16_t message_type; + uint16_t length; + uint8_t vdev_id; + bool is_scan_reconfig; +}; + +/** + * struct sir_create_session - Used for creating session in monitor mode + * @type: SME host message type. + * @msg_len: Length of the message. + * @bss_id: bss_id for creating the session. + */ +struct sir_create_session { + uint16_t type; + uint16_t msg_len; + uint8_t vdev_id; + struct qdf_mac_addr bss_id; +}; + +/** + * struct sir_delete_session - Used for deleting session in monitor mode + * @type: SME host message type. + * @msg_len: Length of the message. + * @vdev_id: vdev id. + */ +struct sir_delete_session { + uint16_t type; + uint16_t msg_len; + uint8_t vdev_id; +}; + +#ifdef QCA_HT_2040_COEX +struct set_ht2040_mode { + uint16_t messageType; + uint16_t length; + uint8_t cbMode; + bool obssEnabled; + struct qdf_mac_addr bssid; + uint8_t sessionId; /* Session ID */ +}; +#endif + +#define SIR_WPS_PBC_WALK_TIME 120 /* 120 Second */ + +typedef struct sSirWPSPBCSession { + struct sSirWPSPBCSession *next; + struct qdf_mac_addr addr; + uint8_t uuid_e[SIR_WPS_UUID_LEN]; + uint32_t timestamp; +} tSirWPSPBCSession; + +typedef struct sSirWPSPBCProbeReq { + struct qdf_mac_addr peer_macaddr; + uint16_t probeReqIELen; + uint8_t probeReqIE[512]; +} tSirWPSPBCProbeReq, *tpSirWPSPBCProbeReq; + +/* probereq from peer, when wsc is enabled */ +typedef struct sSirSmeProbeReqInd { + uint16_t messageType; /* eWNI_SME_WPS_PBC_PROBE_REQ_IND */ + uint16_t length; + uint8_t sessionId; + struct qdf_mac_addr bssid; + tSirWPSPBCProbeReq WPSPBCProbeReq; +} tSirSmeProbeReqInd, *tpSirSmeProbeReqInd; + +#define SIR_ROAM_SCAN_MAX_PB_REQ_SIZE 450 +/* Occupied channel list remains static */ +#define CHANNEL_LIST_STATIC 1 +/* Occupied channel list can be dynamic */ +#define CHANNEL_LIST_DYNAMIC 2 + +/* SME -> HAL - This is the host offload request. */ +#define SIR_IPV6_NS_OFFLOAD 2 +#define SIR_OFFLOAD_DISABLE 0 +#define SIR_OFFLOAD_ENABLE 1 + +struct sir_host_offload_req { + uint8_t offloadType; + uint8_t enableOrDisable; + uint32_t num_ns_offload_count; + union { + uint8_t hostIpv4Addr[QDF_IPV4_ADDR_SIZE]; + uint8_t hostIpv6Addr[QDF_IPV6_ADDR_SIZE]; + } params; + struct qdf_mac_addr bssid; +}; + +/* Packet Types. */ +#define SIR_KEEP_ALIVE_NULL_PKT 1 +#define SIR_KEEP_ALIVE_UNSOLICIT_ARP_RSP 2 +#define SIR_KEEP_ALIVE_MGMT_FRAME 5 + +/* Keep Alive request. */ +struct keep_alive_req { + uint8_t packetType; + uint32_t timePeriod; + tSirIpv4Addr hostIpv4Addr; + tSirIpv4Addr destIpv4Addr; + struct qdf_mac_addr dest_macaddr; + struct qdf_mac_addr bssid; + uint8_t sessionId; +}; + +/** + * enum rxmgmt_flags - flags for received management frame. + * @RXMGMT_FLAG_NONE: Default value to indicate no flags are set. + * @RXMGMT_FLAG_EXTERNAL_AUTH: frame can be used for external authentication + * by upper layers. + */ +enum rxmgmt_flags { + RXMGMT_FLAG_NONE, + RXMGMT_FLAG_EXTERNAL_AUTH = 1 << 1, +}; + +typedef struct sSirSmeMgmtFrameInd { + uint16_t frame_len; + uint32_t rx_freq; + uint8_t sessionId; + uint8_t frameType; + int8_t rxRssi; + enum rxmgmt_flags rx_flags; + QDF_FLEX_ARRAY(uint8_t, frameBuf); +} tSirSmeMgmtFrameInd, *tpSirSmeMgmtFrameInd; + +typedef void (*sir_mgmt_frame_ind_callback)(tSirSmeMgmtFrameInd *frame_ind); +/** + * struct sir_sme_mgmt_frame_cb_req - Register a + * management frame callback req + * + * @message_type: message id + * @length: msg length + * @callback: callback for management frame indication + */ +struct sir_sme_mgmt_frame_cb_req { + uint16_t message_type; + uint16_t length; + sir_mgmt_frame_ind_callback callback; +}; + +typedef struct sSirSmeUnprotMgmtFrameInd { + uint8_t sessionId; + uint8_t frameType; + uint8_t frameLen; + QDF_FLEX_ARRAY(uint8_t, frameBuf); +} tSirSmeUnprotMgmtFrameInd, *tpSirSmeUnprotMgmtFrameInd; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + +typedef enum ext_wow_type { + EXT_WOW_TYPE_APP_TYPE1, /* wow type: only enable wakeup for app type1 */ + EXT_WOW_TYPE_APP_TYPE2, /* wow type: only enable wakeup for app type2 */ + EXT_WOW_TYPE_APP_TYPE1_2, /* wow type: enable wakeup for app type1&2 */ +} EXT_WOW_TYPE; + +typedef struct { + uint8_t vdev_id; + EXT_WOW_TYPE type; + uint32_t wakeup_pin_num; +} tSirExtWoWParams, *tpSirExtWoWParams; + +typedef struct { + uint8_t vdev_id; + struct qdf_mac_addr wakee_mac_addr; + uint8_t identification_id[8]; + uint8_t password[16]; + uint32_t id_length; + uint32_t pass_length; +} tSirAppType1Params, *tpSirAppType1Params; + +typedef struct { + uint8_t vdev_id; + + uint8_t rc4_key[16]; + uint32_t rc4_key_len; + + /** ip header parameter */ + uint32_t ip_id; /* NC id */ + uint32_t ip_device_ip; /* NC IP address */ + uint32_t ip_server_ip; /* Push server IP address */ + + /** tcp header parameter */ + uint16_t tcp_src_port; /* NC TCP port */ + uint16_t tcp_dst_port; /* Push server TCP port */ + uint32_t tcp_seq; + uint32_t tcp_ack_seq; + + uint32_t keepalive_init; /* Initial ping interval */ + uint32_t keepalive_min; /* Minimum ping interval */ + uint32_t keepalive_max; /* Maximum ping interval */ + uint32_t keepalive_inc; /* Increment of ping interval */ + + struct qdf_mac_addr gateway_mac; + uint32_t tcp_tx_timeout_val; + uint32_t tcp_rx_timeout_val; +} tSirAppType2Params, *tpSirAppType2Params; +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +typedef struct { + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t reserved:4; +} tSirAcUapsd, *tpSirAcUapsd; +#endif + +/** + * struct pmkid_mode_bits - Bit flags for PMKID usage in RSN IE + * @fw_okc: Opportunistic key caching enable in firmware + * @fw_pmksa_cache: PMKSA caching enable in firmware, remember previously + * visited BSSID/PMK pairs + */ +struct pmkid_mode_bits { + uint32_t fw_okc:1; + uint32_t fw_pmksa_cache:1; + uint32_t unused:30; +}; + +/** + * struct roam_init_params - Firmware roam module initialization parameters + * @vdev_id: vdev for which the roaming has to be enabled/disabled + * @enable: flag to init/deinit roam module + */ +struct roam_init_params { + uint8_t vdev_id; + uint8_t enable; +}; + +/** + * struct roam_sync_timeout_timer_info - Info related to roam sync timer + * @vdev_id: Vdev id for which host waiting roam sync ind from fw + */ +struct roam_sync_timeout_timer_info { + uint8_t vdev_id; +}; + +struct roam_offload_scan_rsp { + uint8_t sessionId; + uint32_t reason; +}; + +/*--------------------------------------------------------------------------- + Packet Filtering Parameters + ---------------------------------------------------------------------------*/ +#define SIR_MAX_FILTER_TEST_DATA_LEN 8 +#define SIR_MAX_FILTER_TEST_DATA_OFFSET 200 +#define SIR_MAX_NUM_MULTICAST_ADDRESS 240 + +/* */ +/* Multicast Address List Parameters */ +/* */ +typedef struct sSirRcvFltMcAddrList { + uint32_t ulMulticastAddrCnt; + struct qdf_mac_addr multicastAddr[SIR_MAX_NUM_MULTICAST_ADDRESS]; + struct qdf_mac_addr self_macaddr; + struct qdf_mac_addr bssid; + uint8_t action; +} tSirRcvFltMcAddrList, *tpSirRcvFltMcAddrList; + +/** + * struct sir_wifi_start_log - Structure to store the params sent to start/ + * stop logging + * @name: Attribute which indicates the type of logging like per packet + * statistics, connectivity etc. + * @verbose_level: Verbose level which can be 0,1,2,3 + * @is_iwpriv_command: Set 1 for iwpriv command + * @ini_triggered: triggered using ini + * @user_triggered: triggered by user + * @size: pktlog buffer size + * @is_pktlog_buff_clear: clear the pktlog buffer + */ +struct sir_wifi_start_log { + uint32_t ring_id; + uint32_t verbose_level; + uint32_t is_iwpriv_command; + bool ini_triggered; + uint8_t user_triggered; + int size; + bool is_pktlog_buff_clear; +}; + + +/** + * struct sir_pcl_list - Format of PCL + * @pcl_list: List of preferred channels + * @weight_list: Weights of the PCL + * @pcl_len: Number of channels in the PCL + */ +struct sir_pcl_list { + uint32_t pcl_len; + uint8_t pcl_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; +}; + +/** + * struct sir_pcl_chan_weights - Params to get the valid weighed list + * @pcl_list: Preferred channel list already sorted in the order of preference + * @pcl_len: Length of the PCL + * @saved_chan_list: Valid channel list updated as part of + * WMA_UPDATE_CHAN_LIST_REQ + * @saved_num_chan: Length of the valid channel list + * @weighed_valid_list: Weights of the valid channel list. This will have one + * to one mapping with valid_chan_list. FW expects channel order and size to be + * as per the list provided in WMI_SCAN_CHAN_LIST_CMDID. + * @weight_list: Weights assigned by policy manager + */ +struct sir_pcl_chan_weights { + uint8_t pcl_list[NUM_CHANNELS]; + uint32_t pcl_len; + uint8_t saved_chan_list[NUM_CHANNELS]; + uint32_t saved_num_chan; + uint8_t weighed_valid_list[NUM_CHANNELS]; + uint8_t weight_list[NUM_CHANNELS]; +}; + +/** + * struct sir_hw_mode_params - HW mode params + * @mac0_tx_ss: MAC0 Tx spatial stream + * @mac0_rx_ss: MAC0 Rx spatial stream + * @mac1_tx_ss: MAC1 Tx spatial stream + * @mac1_rx_ss: MAC1 Rx spatial stream + * @mac0_bw: MAC0 bandwidth + * @mac1_bw: MAC1 bandwidth + * @dbs_cap: DBS capabality + * @agile_dfs_cap: Agile DFS capabality + */ +struct sir_hw_mode_params { + uint8_t mac0_tx_ss; + uint8_t mac0_rx_ss; + uint8_t mac1_tx_ss; + uint8_t mac1_rx_ss; + uint8_t mac0_bw; + uint8_t mac1_bw; + uint8_t dbs_cap; + uint8_t agile_dfs_cap; + uint8_t sbs_cap; +}; + +/** + * struct sir_set_hw_mode_resp - HW mode response + * @status: Status + * @cfgd_hw_mode_index: Configured HW mode index + * @num_vdev_mac_entries: Number of vdev-mac id entries + * @vdev_mac_map: vdev id-mac id map + */ +struct sir_set_hw_mode_resp { + uint32_t status; + uint32_t cfgd_hw_mode_index; + uint32_t num_vdev_mac_entries; + struct policy_mgr_vdev_mac_map vdev_mac_map[MAX_VDEV_SUPPORTED]; +}; + +/** + * struct sir_dual_mac_config_resp - Dual MAC config response + * @status: Status of setting the dual mac configuration + */ +struct sir_dual_mac_config_resp { + uint32_t status; +}; + +/** + * enum set_antenna_mode_status - Status of set antenna mode + * command + * @SET_ANTENNA_MODE_STATUS_OK: command successful + * @SET_ANTENNA_MODE_STATUS_EINVAL: invalid antenna mode + * @SET_ANTENNA_MODE_STATUS_ECANCELED: mode change cancelled + * @SET_ANTENNA_MODE_STATUS_ENOTSUP: mode not supported + */ +enum set_antenna_mode_status { + SET_ANTENNA_MODE_STATUS_OK, + SET_ANTENNA_MODE_STATUS_EINVAL, + SET_ANTENNA_MODE_STATUS_ECANCELED, + SET_ANTENNA_MODE_STATUS_ENOTSUP, +}; + +/** + * struct sir_antenna_mode_resp - set antenna mode response + * @status: Status of setting the antenna mode + */ +struct sir_antenna_mode_resp { + enum set_antenna_mode_status status; +}; + +typedef struct sSirWlanExcludeUnencryptParam { + bool excludeUnencrypt; + struct qdf_mac_addr bssid; +} tSirWlanExcludeUnencryptParam, *tpSirWlanExcludeUnencryptParam; + +typedef enum { + P2P_SCAN_TYPE_SEARCH = 1, /* P2P Search */ + P2P_SCAN_TYPE_LISTEN /* P2P Listen */ +} tSirP2pScanType; + +typedef struct sAniHandoffReq { + /* Common for all types are requests */ + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t sessionId; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint32_t ch_freq; + uint8_t handoff_src; +} tAniHandoffReq, *tpAniHandoffReq; + +/** + * sir_scan_event_type - scan event types used in LIM + * @SIR_SCAN_EVENT_STARTED - scan command accepted by FW + * @SIR_SCAN_EVENT_COMPLETED - scan has been completed by FW + * @SIR_SCAN_EVENT_BSS_CHANNEL - FW is going to move to HOME channel + * @SIR_SCAN_EVENT_FOREIGN_CHANNEL - FW is going to move to FOREIGN channel + * @SIR_SCAN_EVENT_DEQUEUED - scan request got dequeued + * @SIR_SCAN_EVENT_PREEMPTED - preempted by other high priority scan + * @SIR_SCAN_EVENT_START_FAILED - scan start failed + * @SIR_SCAN_EVENT_RESTARTED - scan restarted + * @SIR_SCAN_EVENT_MAX - max value for event type +*/ +enum sir_scan_event_type { + SIR_SCAN_EVENT_STARTED = 0x1, + SIR_SCAN_EVENT_COMPLETED = 0x2, + SIR_SCAN_EVENT_BSS_CHANNEL = 0x4, + SIR_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, + SIR_SCAN_EVENT_DEQUEUED = 0x10, + SIR_SCAN_EVENT_PREEMPTED = 0x20, + SIR_SCAN_EVENT_START_FAILED = 0x40, + SIR_SCAN_EVENT_RESTARTED = 0x80, + SIR_SCAN_EVENT_MAX = 0x8000 +}; + +typedef struct sSirScanOffloadEvent { + enum sir_scan_event_type event; + tSirResultCodes reasonCode; + uint32_t chanFreq; + uint32_t requestor; + uint32_t scanId; + tSirP2pScanType p2pScanType; + uint8_t sessionId; +} tSirScanOffloadEvent, *tpSirScanOffloadEvent; + +/** + * struct sSirUpdateChanParam - channel parameters + * @freq: Frequency of the channel + * @pwr: power level + * @dfsSet: is dfs supported or not + * @half_rate: is the channel operating at 10MHz + * @quarter_rate: is the channel operating at 5MHz + * @nan_disabled: is NAN disabled on @freq + */ +typedef struct sSirUpdateChanParam { + uint32_t freq; + uint8_t pwr; + bool dfsSet; + bool half_rate; + bool quarter_rate; + bool nan_disabled; +} tSirUpdateChanParam, *tpSirUpdateChanParam; + +typedef struct sSirUpdateChan { + uint8_t numChan; + uint8_t ht_en; + uint8_t vht_en; + uint8_t vht_24_en; + bool he_en; + bool eht_en; + QDF_FLEX_ARRAY(tSirUpdateChanParam, chanParam); +} tSirUpdateChanList, *tpSirUpdateChanList; + +typedef enum eSirAddonPsReq { + eSIR_ADDON_NOTHING, + eSIR_ADDON_ENABLE_UAPSD, + eSIR_ADDON_DISABLE_UAPSD +} tSirAddonPsReq; + +#ifdef FEATURE_WLAN_CH_AVOID +typedef struct sSirChAvoidUpdateReq { + uint32_t reserved_param; +} tSirChAvoidUpdateReq; +#endif /* FEATURE_WLAN_CH_AVOID */ + +struct link_speed_info { + /* MAC Address for the peer */ + struct qdf_mac_addr peer_macaddr; + uint32_t estLinkSpeed; /* Linkspeed from firmware */ +}; + +/** + * struct sir_isolation_resp - isolation info related structure + * @isolation_chain0: isolation value for chain 0 + * @isolation_chain1: isolation value for chain 1 + * @isolation_chain2: isolation value for chain 2 + * @isolation_chain3: isolation value for chain 3 + */ +struct sir_isolation_resp { + uint32_t isolation_chain0:8, + isolation_chain1:8, + isolation_chain2:8, + isolation_chain3:8; +}; + +typedef struct sSirAddPeriodicTxPtrn { + /* MAC Address for the adapter */ + struct qdf_mac_addr mac_address; + uint8_t ucPtrnId; /* Pattern ID */ + uint16_t ucPtrnSize; /* Pattern size */ + uint32_t usPtrnIntervalMs; /* In msec */ + uint8_t ucPattern[PERIODIC_TX_PTRN_MAX_SIZE]; /* Pattern buffer */ +} tSirAddPeriodicTxPtrn, *tpSirAddPeriodicTxPtrn; + +typedef struct sSirDelPeriodicTxPtrn { + /* MAC Address for the adapter */ + struct qdf_mac_addr mac_address; + uint8_t ucPtrnId; /* Pattern ID */ +} tSirDelPeriodicTxPtrn, *tpSirDelPeriodicTxPtrn; + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +typedef struct { + uint16_t mesgType; + uint16_t mesgLen; + bool status; +} tSirReadyToExtWoWInd, *tpSirReadyToExtWoWInd; +#endif +typedef struct sSirRateUpdateInd { + uint8_t nss; /* 0: 1x1, 1: 2x2 */ + struct qdf_mac_addr bssid; + enum QDF_OPMODE dev_mode; + int32_t bcastDataRate; /* bcast rate unit Mbpsx10, -1:not used */ + + /* + * 0 implies MCAST RA, positive value implies fixed rate, + * -1 implies ignore this param + */ + int32_t reliableMcastDataRate; /* unit Mbpsx10 */ + + /* TX flag to differentiate between HT20, HT40 etc */ + enum tx_rate_info reliableMcastDataRateTxFlag; + + /* + * MCAST(or BCAST) fixed data rate in 2.4 GHz, unit Mbpsx10, + * 0 implies ignore + */ + uint32_t mcastDataRate24GHz; + + /* TX flag to differentiate between HT20, HT40 etc */ + enum tx_rate_info mcastDataRate24GHzTxFlag; + + /* + * MCAST(or BCAST) fixed data rate in 5 GHz, + * unit Mbpsx10, 0 implies ignore + */ + uint32_t mcastDataRate5GHz; + + /* TX flag to differentiate between HT20, HT40 etc */ + enum tx_rate_info mcastDataRate5GHzTxFlag; + +} tSirRateUpdateInd, *tpSirRateUpdateInd; + +#define SIR_DFS_MAX_20M_SUB_CH 8 +#define SIR_80MHZ_START_CENTER_CH_DIFF 6 + +typedef struct sSirSmeDfsChannelList { + uint32_t nchannels; + /* Ch num including bonded channels on which the RADAR is present */ + uint8_t channels[SIR_DFS_MAX_20M_SUB_CH]; +} tSirSmeDfsChannelList, *tpSirSmeDfsChannelList; + +typedef struct sSirChanChangeResponse { + uint8_t sessionId; + uint32_t new_op_freq; + uint8_t channelChangeStatus; +} tSirChanChangeResponse, *tpSirChanChangeResponse; + +typedef struct sSirStartBeaconIndication { + uint16_t messageType; + uint16_t messageLen; + uint8_t beaconStartStatus; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; +} tSirStartBeaconIndication, *tpSirStartBeaconIndication; + +/* additional IE type */ +typedef enum tUpdateIEsType { + eUPDATE_IE_NONE, + eUPDATE_IE_PROBE_BCN, + eUPDATE_IE_PROBE_RESP, + eUPDATE_IE_ASSOC_RESP, + + /* Add type above this line */ + /* this is used to reset all buffer */ + eUPDATE_IE_ALL, + eUPDATE_IE_MAX +} eUpdateIEsType; + +/* Modify particular IE in addition IE for prob resp Bcn */ +typedef struct sSirModifyIE { + struct qdf_mac_addr bssid; + uint16_t vdev_id; + bool notify; + uint8_t ieID; + uint8_t ieIDLen; /*ie length as per spec */ + uint16_t ieBufferlength; + uint8_t *pIEBuffer; + int32_t oui_length; + +} tSirModifyIE, *tpSirModifyIE; + +struct send_add_ba_req { + uint8_t mac_addr[QDF_MAC_ADDR_SIZE]; + struct addba_send_params param; +}; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirModifyIEsInd { + uint16_t msgType; + uint16_t msgLen; + tSirModifyIE modifyIE; + eUpdateIEsType updateType; +} tSirModifyIEsInd, *tpSirModifyIEsInd; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirUpdateIE { + struct qdf_mac_addr bssid; + uint16_t vdev_id; + bool append; + bool notify; + uint16_t ieBufferlength; + uint8_t *pAdditionIEBuffer; +} tSirUpdateIE, *tpSirUpdateIE; + +/* Message format for Update IE message sent to PE */ +typedef struct sSirUpdateIEsInd { + uint16_t msgType; + uint16_t msgLen; + tSirUpdateIE updateIE; + eUpdateIEsType updateType; +} tSirUpdateIEsInd, *tpSirUpdateIEsInd; + +/* Message format for requesting channel switch announcement to lower layers */ +typedef struct sSirDfsCsaIeRequest { + uint16_t msgType; + uint16_t msgLen; + uint32_t target_chan_freq; + uint8_t csaIeRequired; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + struct ch_params ch_params; + uint8_t ch_switch_beacon_cnt; + uint8_t ch_switch_mode; + uint8_t dfs_ch_switch_disable; + uint32_t new_chan_cac_ms; +} tSirDfsCsaIeRequest, *tpSirDfsCsaIeRequest; + +/* Indication from lower layer indicating the completion of first beacon send + * after the beacon template update + */ +typedef struct sSirFirstBeaconTxCompleteInd { + uint16_t messageType; /* eWNI_SME_MISSED_BEACON_IND */ + uint16_t length; + uint8_t bss_idx; +} tSirFirstBeaconTxCompleteInd, *tpSirFirstBeaconTxCompleteInd; + +typedef struct sSirSmeCSAIeTxCompleteRsp { + uint8_t sessionId; + uint8_t chanSwIeTxStatus; +} tSirSmeCSAIeTxCompleteRsp, *tpSirSmeCSAIeTxCompleteRsp; + +/* Thermal Mitigation*/ + +typedef struct { + uint16_t minTempThreshold; + uint16_t maxTempThreshold; +} t_thermal_level_info, *tp_thermal_level_info; + +typedef enum { + WLAN_WMA_THERMAL_LEVEL_0, + WLAN_WMA_THERMAL_LEVEL_1, + WLAN_WMA_THERMAL_LEVEL_2, + WLAN_WMA_THERMAL_LEVEL_3, + WLAN_WMA_THERMAL_LEVEL_4, + WLAN_WMA_THERMAL_LEVEL_5, + WLAN_WMA_MAX_THERMAL_LEVELS +} t_thermal_level; + +#define WLAN_THROTTLE_DUTY_CYCLE_LEVEL_MAX (6) + +typedef struct { + /* Array of thermal levels */ + t_thermal_level_info thermalLevels[WLAN_WMA_MAX_THERMAL_LEVELS]; + uint8_t thermalCurrLevel; + uint8_t thermalMgmtEnabled; + uint32_t throttlePeriod; + uint8_t throttle_duty_cycle_tbl[WLAN_THROTTLE_DUTY_CYCLE_LEVEL_MAX]; + enum thermal_mgmt_action_code thermal_action; +} t_thermal_mgmt, *tp_thermal_mgmt; + +struct tx_power_limit { + /* Thermal limits for 2g and 5g */ + uint32_t txPower2g; + uint32_t txPower5g; +}; + +enum bad_peer_thresh_levels { + WLAN_WMA_IEEE80211_B_LEVEL = 0, + WLAN_WMA_IEEE80211_AG_LEVEL, + WLAN_WMA_IEEE80211_N_LEVEL, + WLAN_WMA_IEEE80211_AC_LEVEL, + WLAN_WMA_IEEE80211_AX_LEVEL, + WLAN_WMA_IEEE80211_MAX_LEVEL, +}; + +#define NUM_OF_RATE_THRESH_MAX (4) +struct t_bad_peer_info { + uint32_t cond; + uint32_t delta; + uint32_t percentage; + uint32_t thresh[NUM_OF_RATE_THRESH_MAX]; + uint32_t txlimit; +}; + +struct t_bad_peer_txtcl_config { + /* Array of thermal levels */ + struct t_bad_peer_info threshold[WLAN_WMA_IEEE80211_MAX_LEVEL]; + uint32_t enable; + uint32_t period; + uint32_t txq_limit; + uint32_t tgt_backoff; + uint32_t tgt_report_prd; +}; + +/* notify MODEM power state to FW */ +typedef struct { + uint32_t param; +} tSirModemPowerStateInd, *tpSirModemPowerStateInd; + +#ifdef WLAN_FEATURE_STATS_EXT +typedef struct { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +} tSirStatsExtEvent, *tpSirStatsExtEvent; +#endif + +/** + * struct sir_wisa_params - WISA Mode Parameters + * @mode: WISA mode + * @session_id: Session ID of vdev + */ +struct sir_wisa_params { + bool mode; + uint8_t vdev_id; +}; + +/** + * typedef enum wifi_scan_flags - wifi scan flags + * @WIFI_SCAN_FLAG_INTERRUPTED: Indicates that scan results are not complete + * because probes were not sent on some channels + */ +typedef enum { + WIFI_SCAN_FLAG_INTERRUPTED = 1, +} wifi_scan_flags; + +typedef enum { + WIFI_BAND_UNSPECIFIED, + WIFI_BAND_BG = 1, /* 2.4 GHz */ + WIFI_BAND_A = 2, /* 5 GHz without DFS */ + WIFI_BAND_ABG = 3, /* 2.4 GHz + 5 GHz; no DFS */ + WIFI_BAND_A_DFS_ONLY = 4, /* 5 GHz DFS only */ + /* 5 is reserved */ + WIFI_BAND_A_WITH_DFS = 6, /* 5 GHz with DFS */ + WIFI_BAND_ABG_WITH_DFS = 7, /* 2.4 GHz + 5 GHz with DFS */ + + /* Keep it last */ + WIFI_BAND_MAX +} tWifiBand; + +#ifdef FEATURE_WLAN_EXTSCAN + +#define WLAN_EXTSCAN_MAX_CHANNELS 36 +#define WLAN_EXTSCAN_MAX_BUCKETS 16 +#define WLAN_EXTSCAN_MAX_SIGNIFICANT_CHANGE_APS 64 + +typedef enum { + eSIR_EXTSCAN_INVALID, + eSIR_EXTSCAN_START_RSP, + eSIR_EXTSCAN_STOP_RSP, + eSIR_EXTSCAN_CACHED_RESULTS_RSP, + eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP, + eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP, + eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP, + eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP, + + eSIR_EXTSCAN_GET_CAPABILITIES_IND, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, + eSIR_EXTSCAN_FULL_SCAN_RESULT_IND, + eSIR_EPNO_NETWORK_FOUND_IND, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP, + eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP, + + /* Keep this last */ + eSIR_EXTSCAN_CALLBACK_TYPE_MAX, +} tSirExtScanCallbackType; + +/** + * enum wifi_extscan_event_type - extscan event type + * @WIFI_EXTSCAN_RESULTS_AVAILABLE: reported when REPORT_EVENTS_EACH_SCAN is set + * and a scan cycle completes. WIFI_SCAN_THRESHOLD_NUM_SCANS or + * WIFI_SCAN_THRESHOLD_PERCENT can be reported instead if the + * reason for the event is available; however, at most one of + * these events should be reported per scan. + * @WIFI_EXTSCAN_THRESHOLD_NUM_SCANS: can be reported when + * REPORT_EVENTS_EACH_SCAN is not set and + * report_threshold_num_scans is reached. + * @WIFI_EXTSCAN_THRESHOLD_PERCENT: can be reported when REPORT_EVENTS_EACH_SCAN + * is not set and report_threshold_percent is reached. + * @WIFI_SCAN_DISABLED: reported when currently executing gscans are disabled + * start_gscan will need to be called again in order to continue + * scanning. + * @WIFI_EXTSCAN_BUCKET_STARTED_EVENT: Bucket started event + * This event is consumed in driver only. + * @WIFI_EXTSCAN_CYCLE_STARTED_EVENT: Cycle started event. + * This event is consumed in driver only. + * @WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT: Cycle complete event. This event + * triggers @WIFI_EXTSCAN_RESULTS_AVAILABLE to the user space. + */ +enum wifi_extscan_event_type { + WIFI_EXTSCAN_RESULTS_AVAILABLE, + WIFI_EXTSCAN_THRESHOLD_NUM_SCANS, + WIFI_EXTSCAN_THRESHOLD_PERCENT, + WIFI_SCAN_DISABLED, + + WIFI_EXTSCAN_BUCKET_STARTED_EVENT = 0x10, + WIFI_EXTSCAN_CYCLE_STARTED_EVENT, + WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT, +}; + +/** + * enum extscan_configuration_flags - extscan config flags + * @EXTSCAN_LP_EXTENDED_BATCHING: extended batching + */ +enum extscan_configuration_flags { + EXTSCAN_LP_EXTENDED_BATCHING = 0x00000001, +}; + +/** + * struct ext_scan_capabilities_response - extscan capabilities response data + * @requestId: request identifier + * @status: status + * @max_scan_cache_size: total space allocated for scan (in bytes) + * @max_scan_buckets: maximum number of channel buckets + * @max_ap_cache_per_scan: maximum number of APs that can be stored per scan + * @max_rssi_sample_size: number of RSSI samples used for averaging RSSI + * @ax_scan_reporting_threshold: max possible report_threshold + * @max_hotlist_bssids: maximum number of entries for hotlist APs + * @max_significant_wifi_change_aps: maximum number of entries for + * significant wifi change APs + * @max_bssid_history_entries: number of BSSID/RSSI entries that device can hold + * @max_hotlist_ssids: maximum number of entries for hotlist SSIDs + * @max_number_epno_networks: max number of epno entries + * @max_number_epno_networks_by_ssid: max number of epno entries + * if ssid is specified, that is, epno entries for + * which an exact match is required, + * or entries corresponding to hidden ssids + * @max_number_of_allow_listed_ssid: max number of allow listed SSIDs + * @max_number_of_deny_listed_bssid: max number of deny listed BSSIDs + */ +struct ext_scan_capabilities_response { + uint32_t requestId; + uint32_t status; + + uint32_t max_scan_cache_size; + uint32_t max_scan_buckets; + uint32_t max_ap_cache_per_scan; + uint32_t max_rssi_sample_size; + uint32_t max_scan_reporting_threshold; + + uint32_t max_hotlist_bssids; + uint32_t max_significant_wifi_change_aps; + + uint32_t max_bssid_history_entries; + uint32_t max_hotlist_ssids; + uint32_t max_number_epno_networks; + uint32_t max_number_epno_networks_by_ssid; + uint32_t max_number_of_allow_listed_ssid; + uint32_t max_number_of_deny_listed_bssid; +}; + +typedef struct { + /* Time of discovery */ + uint64_t ts; + + /* Null terminated SSID */ + uint8_t ssid[WLAN_SSID_MAX_LEN + 1]; + + struct qdf_mac_addr bssid; + + /* Frequency in MHz */ + uint32_t channel; + + /* RSSI in dBm */ + int32_t rssi; + + /* RTT in nanoseconds */ + uint32_t rtt; + + /* Standard deviation in rtt */ + uint32_t rtt_sd; + + /* Period advertised in the beacon */ + uint16_t beaconPeriod; + + /* Capabilities advertised in the beacon */ + uint16_t capability; + + uint16_t ieLength; + + uint8_t ieData[]; +} tSirWifiScanResult, *tpSirWifiScanResult; + +/** + * struct extscan_hotlist_match - extscan hotlist match + * @requestId: request identifier + * @numOfAps: number of bssids retrieved by the scan + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @ap: wifi scan result + */ +struct extscan_hotlist_match { + uint32_t requestId; + bool moreData; + bool ap_found; + uint32_t numOfAps; + tSirWifiScanResult ap[]; +}; + +/** + * struct extscan_cached_scan_result - extscan cached scan result + * @scan_id: a unique identifier for the scan unit + * @flags: a bitmask with additional information about scan + * @num_results: number of bssids retrieved by the scan + * @buckets_scanned: bitmask of buckets scanned in current extscan cycle + * @ap: wifi scan bssid results info + */ +struct extscan_cached_scan_result { + uint32_t scan_id; + uint32_t flags; + uint32_t num_results; + uint32_t buckets_scanned; + tSirWifiScanResult *ap; +}; + +/** + * struct extscan_cached_scan_results - extscan cached scan results + * @request_id: request identifier + * @more_data: 0 - for last fragment + * 1 - still more fragment(s) coming + * @num_scan_ids: number of scan ids + * @result: wifi scan result + */ +struct extscan_cached_scan_results { + uint32_t request_id; + bool more_data; + uint32_t num_scan_ids; + struct extscan_cached_scan_result *result; +}; + + +/** + * struct tSirWifiFullScanResultEvent - extscan full scan event + * @request_id: request identifier + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @ap: bssid info + * + * Reported when each probe response is received, if report_events + * enabled in struct wifi_scan_cmd_req_params + */ +typedef struct { + uint32_t requestId; + bool moreData; + tSirWifiScanResult ap; +} tSirWifiFullScanResultEvent, *tpSirWifiFullScanResultEvent; + +/** + * struct pno_match_found - epno match found + * @request_id: request identifier + * @moreData: 0 - for last fragment + * 1 - still more fragment(s) coming + * @num_results: number of bssids, driver sends this event to upper layer + * for every beacon, hence %num_results is always set to 1. + * @ap: bssid info + * + * Reported when each beacon probe response is received with + * epno match found tag. + */ +struct pno_match_found { + uint32_t request_id; + bool more_data; + uint32_t num_results; + tSirWifiScanResult ap[]; +}; + +/** + * struct sir_extscan_generic_response - + * Generic ExtScan Response structure + * @request_id: ID of the request + * @status: operation status returned by firmware + */ +struct sir_extscan_generic_response { + uint32_t request_id; + uint32_t status; +}; + +typedef struct { + struct qdf_mac_addr bssid; + uint32_t channel; + uint32_t numOfRssi; + + /* Rssi history in db */ + int32_t rssi[]; +} tSirWifiSignificantChange, *tpSirWifiSignificantChange; + +typedef struct { + uint32_t requestId; + + bool moreData; + uint32_t numResults; + tSirWifiSignificantChange ap[]; +} tSirWifiSignificantChangeEvent, *tpSirWifiSignificantChangeEvent; + +typedef struct { + uint32_t requestId; + uint32_t numResultsAvailable; +} tSirExtScanResultsAvailableIndParams, *tpSirExtScanResultsAvailableIndParams; + +typedef struct { + uint32_t requestId; + uint32_t status; + uint8_t scanEventType; + uint32_t buckets_scanned; +} tSirExtScanOnScanEventIndParams, *tpSirExtScanOnScanEventIndParams; + +#define MAX_EPNO_NETWORKS 64 + +#define SIR_PASSPOINT_LIST_MAX_NETWORKS 8 + +/** + * struct wifi_passpoint_match - wifi passpoint network match + * @id: network block identifier for the matched network + * @anqp_len: length of ANQP blob + * @ap: scan result, with channel and beacon information + * @anqp: ANQP data, in the information_element format + */ +struct wifi_passpoint_match { + uint32_t request_id; + uint32_t id; + uint32_t anqp_len; + tSirWifiScanResult ap; + uint8_t anqp[]; +}; +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +struct auto_shutdown_cmd { + uint32_t timer_val; +}; +#endif + +#ifdef WLAN_POWER_DEBUG +/** + * struct power_stats_response - Power stats response + * @cumulative_sleep_time_ms: cumulative sleep time in ms + * @cumulative_total_on_time_ms: total awake time in ms + * @deep_sleep_enter_counter: deep sleep enter counter + * @last_deep_sleep_enter_tstamp_ms: last deep sleep enter timestamp + * @debug_register_fmt: debug registers format + * @num_debug_register: number of debug registers + * @debug_registers: Pointer to the debug registers buffer + */ +struct power_stats_response { + uint32_t cumulative_sleep_time_ms; + uint32_t cumulative_total_on_time_ms; + uint32_t deep_sleep_enter_counter; + uint32_t last_deep_sleep_enter_tstamp_ms; + uint32_t debug_register_fmt; + uint32_t num_debug_register; + uint32_t *debug_registers; +}; +#endif + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +#define MAX_BCNMISS_BITMAP 8 +/** + * struct bcn_reception_stats_rsp - beacon stats response + * @total_bcn_cnt: total beacon count (tbtt instances) + * @total_bmiss_cnt: Total beacon miss count in last 255 beacons, max 255 + * @bmiss_bitmap: This bitmap indicates the status of the last 255 beacons. + * If a bit is set, that means the corresponding beacon was missed. + * Bit 0 of bmiss_bitmap[0] represents the most recent beacon. + * The total_bcn_cnt field indicates how many bits within bmiss_bitmap + * are valid. + */ +struct bcn_reception_stats_rsp { + uint32_t vdev_id; + uint32_t total_bcn_cnt; + uint32_t total_bmiss_cnt; + uint32_t bmiss_bitmap[MAX_BCNMISS_BITMAP]; +}; +#endif + +/** + * struct lfr_firmware_status - LFR status in firmware + * @is_disabled: Is LFR disabled in FW + * @disable_lfr_event: Disable attempt done in FW + */ +struct lfr_firmware_status { + uint32_t is_disabled; + struct completion disable_lfr_event; +}; + +/** + * struct rso_cmd_status - RSO Command status + * @vdev_id: Vdev ID for which RSO command sent + * @status: Status of RSO command sent to FW + */ +struct rso_cmd_status { + uint32_t vdev_id; + bool status; +}; + +enum { + SIR_AP_RX_DATA_OFFLOAD = 0x00, + SIR_STA_RX_DATA_OFFLOAD = 0x01, +}; + +/** + * struct sir_set_vdev_ies_per_band + * @msg_type: message type + * @len: message length + * @vdev_id: vdev id + * + * Message wrapper structure for eWNI_SME_SET_VDEV_IES_PER_BAND. + */ +struct sir_set_vdev_ies_per_band { + uint16_t msg_type; + uint16_t len; + uint32_t vdev_id; + uint16_t dot11_mode; + enum QDF_OPMODE device_mode; +}; + +/** + * struct sir_set_ht_vht_cfg - ht, vht IE config + * @msg_type: message type + * @len: message length + * @pdev_id: pdev id + * @nss: Nss value + * @dot11mode: Dot11 mode. + * + * Message wrapper structure for set HT/VHT IE req. + */ +struct sir_set_ht_vht_cfg { + uint16_t msg_type; + uint16_t len; + uint32_t pdev_id; + uint32_t nss; + uint32_t dot11mode; +}; + +#define WIFI_INVALID_PEER_ID (-1) +#define WIFI_INVALID_VDEV_ID (-1) +#define WIFI_MAX_AC (4) +#define RATE_STAT_MCS_MASK (0xFF00) +#define RATE_STAT_GET_MCS_INDEX(x) (((x) & RATE_STAT_MCS_MASK) >> 8) + +typedef struct { + uint32_t paramId; + uint8_t ifaceId; + uint32_t rspId; + uint32_t moreResultToFollow; + uint32_t nr_received; + union { + uint32_t num_peers; + uint32_t num_radio; + }; + + uint32_t peer_event_number; + /* Variable length field - Do not add anything after this */ + uint8_t results[]; +} tSirLLStatsResults, *tpSirLLStatsResults; + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +/*--------------------------------------------------------------------------- + WLAN_HAL_LL_NOTIFY_STATS + ---------------------------------------------------------------------------*/ + +/******************************LINK LAYER Statistics**********************/ + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t mpduSizeThreshold; + uint32_t aggressiveStatisticsGathering; +} tSirLLStatsSetReq, *tpSirLLStatsSetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t paramIdMask; + bool is_mlo_req; + uint32_t mlo_vdev_id_bitmap; +} tSirLLStatsGetReq, *tpSirLLStatsGetReq; + +typedef struct { + uint32_t reqId; + uint8_t staId; + uint32_t statsClearReqMask; + uint8_t stopReq; +} tSirLLStatsClearReq, *tpSirLLStatsClearReq; + +typedef enum { + WIFI_DISCONNECTED = 0, + WIFI_AUTHENTICATING = 1, + WIFI_ASSOCIATING = 2, + WIFI_ASSOCIATED = 3, + WIFI_EAPOL_STARTED = 4, /* if done by firmware/driver */ + WIFI_EAPOL_COMPLETED = 5, /* if done by firmware/driver */ +} tSirWifiConnectionState; + +typedef enum { + WIFI_ROAMING_IDLE = 0, + WIFI_ROAMING_ACTIVE = 1, +} tSirWifiRoamState; + +typedef enum { + WIFI_INTERFACE_STA = 0, + WIFI_INTERFACE_SOFTAP = 1, + WIFI_INTERFACE_IBSS = 2, + WIFI_INTERFACE_P2P_CLIENT = 3, + WIFI_INTERFACE_P2P_GO = 4, + WIFI_INTERFACE_NAN = 5, + WIFI_INTERFACE_MESH = 6, + WIFI_INTERFACE_NDI = 7, +} tSirWifiInterfaceMode; + +/* set for QOS association */ +#define WIFI_CAPABILITY_QOS 0x00000001 +/* set for protected assoc (802.11 beacon frame control protected bit set) */ +#define WIFI_CAPABILITY_PROTECTED 0x00000002 +/* set if 802.11 Extended Capabilities element interworking bit is set */ +#define WIFI_CAPABILITY_INTERWORKING 0x00000004 +/* set for HS20 association */ +#define WIFI_CAPABILITY_HS20 0x00000008 +/* set is 802.11 Extended Capabilities element UTF-8 SSID bit is set */ +#define WIFI_CAPABILITY_SSID_UTF8 0x00000010 +/* set is 802.11 Country Element is present */ +#define WIFI_CAPABILITY_COUNTRY 0x00000020 + +struct wifi_interface_info { + /* tSirWifiInterfaceMode */ + /* interface mode */ + uint8_t mode; + /* interface mac address (self) */ + struct qdf_mac_addr macAddr; + /* tSirWifiConnectionState */ + /* connection state (valid for STA, CLI only) */ + uint8_t state; + /* tSirWifiRoamState */ + /* roaming state */ + uint32_t roaming; + /* WIFI_CAPABILITY_XXX (self) */ + uint32_t capabilities; + /* null terminated SSID */ + uint8_t ssid[33]; + /* bssid */ + struct qdf_mac_addr bssid; + /* country string advertised by AP */ + uint8_t apCountryStr[REG_ALPHA2_LEN + 1]; + /* country string for this association */ + uint8_t countryStr[REG_ALPHA2_LEN + 1]; + uint8_t time_slice_duty_cycle; +}; + +/** + * struct wifi_channel_info - channel information + * @width: channel width (20, 40, 80, 80+80, 160) + * @center_freq: primary 20 MHz channel + * @center_freq0: center frequency (MHz) first segment + * @center_freq1: center frequency (MHz) second segment + */ +struct wifi_channel_info { + enum phy_ch_width width; + uint32_t center_freq; + uint32_t center_freq0; + uint32_t center_freq1; +}; + +/** + * struct wifi_rate_info - wifi rate information + * @preamble: 0:OFDM, 1:CCK, 2:HT 3:VHT 4..7 reserved + * @nss: 0:1x1, 1:2x2, 3:3x3, 4:4x4 + * @bw: 0:20MHz, 1:40Mhz, 2:80Mhz, 3:160Mhz + * @rate_or_mcs_index: + * * OFDM/CCK: rate code per ieee std in units of 0.5mbps + * * HT/VHT: mcs index + * @reserved: reserved + * @bitrate: bitrate units of 100 Kbps + */ +struct wifi_rate_info { + uint32_t preamble:3; + uint32_t nss:2; + uint32_t bw:3; + uint32_t rate_or_mcs_index:8; + uint32_t reserved:16; + uint32_t bitrate; +}; + +/** + * struct wifi_channel_stats - channel statistics + * @channel: channel for which the stats are applicable + * @on_time: msecs the radio is awake + * @cca_busy_time: secs the CCA register is busy excluding own tx_time + * @tx_time: msecs the radio is transmitting on this channel + * @rx_time: msecs the radio is in active receive on this channel + */ +struct wifi_channel_stats { + struct wifi_channel_info channel; + uint32_t on_time; + uint32_t cca_busy_time; + uint32_t tx_time; + uint32_t rx_time; + +}; + +/** + * struct wifi_radio_stats - per-radio statistics + * @radio: wifi radio for which the stats are applicable + * @on_time: msecs the radio is awake + * @tx_time: msecs the radio is transmitting + * @rx_time: msecs the radio is in active receive + * @on_time_scan: msecs the radio is awake due to all scan + * @on_time_nbd: msecs the radio is awake due to NAN + * @on_time_gscan: msecs the radio is awake due to Gscan + * @on_time_roam_scan: msecs the radio is awake due to roam scan + * @on_time_pno_scan: msecs the radio is awake due to PNO scan + * @on_time_hs20: msecs the radio is awake due to HS2.0 scans and GAS exchange + * @on_time_host_scan: msecs the radio is awake due to Host initiated scan + * @on_time_lpi_scan: msecs the radio is awake due to LPI scan + * @total_num_tx_power_levels: @tx_time_per_power_level record count + * @tx_time_per_power_level: tx time (in milliseconds) per TPC level (0.5 dBm) + * @more_channels: If more channels are there and will come in next event + * @num_channels: @channels record count + * @channels: per-channel statistics + */ +struct wifi_radio_stats { + uint32_t radio; + uint32_t on_time; + uint32_t tx_time; + uint32_t rx_time; + uint32_t on_time_scan; + uint32_t on_time_nbd; + uint32_t on_time_gscan; + uint32_t on_time_roam_scan; + uint32_t on_time_pno_scan; + uint32_t on_time_hs20; + uint32_t on_time_host_scan; + uint32_t on_time_lpi_scan; + uint32_t total_num_tx_power_levels; + uint32_t *tx_time_per_power_level; + uint32_t more_channels; + uint32_t num_channels; + struct wifi_channel_stats *channels; +}; + +/** + * struct wifi_rate_stat - per rate statistics + * @rate: rate information + * @tx_mpdu: number of successfully transmitted data pkts (ACK rcvd) + * @rx_mpdu: number of received data pkts + * @mpdu_lost: number of data packet losses (no ACK) + * @retries: total number of data pkt retries * + * @retries_short: number of short data pkt retries + * @retries_long: number of long data pkt retries + */ +struct wifi_rate_stat { + struct wifi_rate_info rate; + uint32_t tx_mpdu; + uint32_t rx_mpdu; + uint32_t mpdu_lost; + uint32_t retries; + uint32_t retries_short; + uint32_t retries_long; +}; + +/* wifi peer type */ +typedef enum { + WIFI_PEER_STA, + WIFI_PEER_AP, + WIFI_PEER_P2P_GO, + WIFI_PEER_P2P_CLIENT, + WIFI_PEER_NAN, + WIFI_PEER_TDLS, + WIFI_PEER_INVALID, +} tSirWifiPeerType; + +/** + * struct wifi_peer_info - per peer information + * @type: peer type (AP, TDLS, GO etc.) + * @peer_macaddr: mac address + * @capabilities: peer WIFI_CAPABILITY_XXX + * @power_saving: peer power saving mode + * @num_rate: number of rates + * @rate_stats: per rate statistics, number of entries = @num_rate + */ +struct wifi_peer_info { + enum wmi_peer_type type; + struct qdf_mac_addr peer_macaddr; + uint32_t capabilities; + union { + uint32_t power_saving; + uint32_t num_rate; + }; + struct wifi_rate_stat rate_stats[]; +}; + +/** + * struct wifi_interface_stats - Interface statistics + * @info: struct containing the current state of the interface + * @rts_succ_cnt: number of RTS/CTS sequence success + * @rts_fail_cnt: number of RTS/CTS sequence failures + * @ppdu_succ_cnt: number of PPDUs transmitted + * @ppdu_fail_cnt: number of PPDUs that failed to transmit + * @link_stats: link-level statistics + * @ac_stats: per-Access Category statistics + * @num_offload_stats: @offload_stats record count + * @offload_stats: per-offload statistics + * @powersave_stats: powersave statistics + * @vdev_id: vdev id + * + * Statistics corresponding to 2nd most LSB in wifi statistics bitmap + * for getting statistics + */ +struct wifi_interface_stats { + struct wifi_interface_info info; + uint32_t rts_succ_cnt; + uint32_t rts_fail_cnt; + uint32_t ppdu_succ_cnt; + uint32_t ppdu_fail_cnt; + wmi_iface_link_stats link_stats; + wmi_wmm_ac_stats ac_stats[WIFI_AC_MAX]; + uint32_t num_offload_stats; + wmi_iface_offload_stats offload_stats[WMI_OFFLOAD_STATS_TYPE_MAX]; + wmi_iface_powersave_stats powersave_stats; + uint8_t vdev_id; +}; + +/** + * struct wifi_peer_stat - peer statistics + * @num_peers: number of peers + * @peer_info: per peer statistics + * + * Peer statistics - corresponding to 3rd most LSB in + * wifi statistics bitmap for getting statistics + */ +struct wifi_peer_stat { + uint32_t num_peers; + struct wifi_peer_info peer_info[]; +}; + +/* wifi statistics bitmap for getting statistics */ +#define WMI_LINK_STATS_RADIO 0x00000001 +#define WMI_LINK_STATS_IFACE 0x00000002 +#define WMI_LINK_STATS_ALL_PEER 0x00000004 +#define WMI_LINK_STATS_PER_PEER 0x00000008 + +/* wifi statistics bitmap for clearing statistics */ +/* all radio statistics */ +#define WIFI_STATS_RADIO 0x00000001 +/* cca_busy_time (within radio statistics) */ +#define WIFI_STATS_RADIO_CCA 0x00000002 +/* all channel statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_CHANNELS 0x00000004 +/* all scan statistics (within radio statistics) */ +#define WIFI_STATS_RADIO_SCAN 0x00000008 +/* all interface statistics */ +#define WIFI_STATS_IFACE 0x00000010 +/* all tx rate statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_TXRATE 0x00000020 +/* all ac statistics (within interface statistics) */ +#define WIFI_STATS_IFACE_AC 0x00000040 +/* all contention (min, max, avg) statistics (within ac statistics) */ +#define WIFI_STATS_IFACE_CONTENTION 0x00000080 +/* All peer stats on this interface */ +#define WIFI_STATS_IFACE_ALL_PEER 0x00000100 +/* Clear particular peer stats depending on the peer_mac */ +#define WIFI_STATS_IFACE_PER_PEER 0x00000200 + +/** + * struct sir_wifi_iface_tx_fail - TX failure event + * @tid: TX TID + * @msdu_num: TX MSDU failed counter + * @status: TX status from HTT message. + * Only failure status will be involved. + */ +struct sir_wifi_iface_tx_fail { + uint8_t tid; + uint16_t msdu_num; + enum htt_tx_status status; +}; + +/** + * struct sir_wifi_chan_cca_stats - channal CCA stats + * @vdev_id: vdev ID + * @idle_time: percentage of idle time, no TX, no RX, no interference + * @tx_time: percentage of time transmitting packets + * @rx_in_bss_time: percentage of time receiving packets in current BSS + * @rx_out_bss_time: percentage of time receiving packets not in current BSS + * @rx_busy_time: percentage of time interference detected + * @rx_in_bad_cond_time: percentage of time receiving packets with errors + * or packets flagged as retransmission or seqnum discontinued. + * @tx_in_bad_cond_time: percentage of time the device transmitted packets + * that haven't been ACKed. + * @wlan_not_avail_time: percentage of time the chip is unable to + * work in normal conditions. + */ +struct sir_wifi_chan_cca_stats { + uint32_t vdev_id; + uint32_t idle_time; + uint32_t tx_time; + uint32_t rx_in_bss_time; + uint32_t rx_out_bss_time; + uint32_t rx_busy_time; + uint32_t rx_in_bad_cond_time; + uint32_t tx_in_bad_cond_time; + uint32_t wlan_not_avail_time; +}; + +#define WIFI_MAX_CHAINS 8 + +/** + * struct sir_wifi_peer_signal_stats - peer signal stats + * @vdev_id: vdev ID + * @peer_id: peer ID + * @per_ant_snr: per antenna SNR + * @nf: peer background noise + * @per_ant_rx_mpdus: MPDUs received per antenna + * @per_ant_tx_mpdus: MPDUs transferred per antenna + * @num_chain: valid chain count + */ +struct sir_wifi_peer_signal_stats { + uint32_t vdev_id; + uint32_t peer_id; + + /* per antenna SNR in current bss */ + int32_t per_ant_snr[WIFI_MAX_CHAINS]; + + /* Background noise */ + int32_t nf[WIFI_MAX_CHAINS]; + + uint32_t per_ant_rx_mpdus[WIFI_MAX_CHAINS]; + uint32_t per_ant_tx_mpdus[WIFI_MAX_CHAINS]; + uint32_t num_chain; +}; + +#define WIFI_VDEV_NUM 4 +#define WFIF_MCS_NUM 10 +#define WIFI_AGGR_NUM 8 +#define WIFI_DELAY_SIZE 11 + +/** + * struct sir_wifi_tx - per AC tx stats + * @msdus: number of totoal MSDUs on MAC layer in the period + * @mpdus: number of totoal MPDUs on MAC layer in the period + * @ppdus: number of totoal PPDUs on PHY layer in the period + * @bytes: bytes of tx data on MAC layer in the period + * @drops: number of TX packets cancelled due to any reason in the period, + * such as WMM limitation/bandwidth limitation/radio congestion + * @drop_bytes: bytes of dropped TX packets in the period + * @retries: number of unacked transmissions of MPDUs + * @failed: number of packets have not been ACKed despite retried + * @aggr_len: length of the MPDU aggregation size buffer + * @mpdu_aggr_size: histogram of MPDU aggregation size + * @success_mcs_len: length of success mcs buffer + * @success_mcs: histogram of successful received MPDUs encoding rate + * @fail_mcs_len: length of failed mcs buffer + * @fail_mcs: histogram of failed received MPDUs encoding rate + * @delay_len: length of the delay histofram buffer + * @delay: histogram of delays on MAC layer + */ +struct sir_wifi_tx { + uint32_t msdus; + uint32_t mpdus; + uint32_t ppdus; + uint32_t bytes; + uint32_t drops; + uint32_t drop_bytes; + uint32_t retries; + uint32_t failed; + uint32_t aggr_len; + uint32_t *mpdu_aggr_size; + uint32_t success_mcs_len; + uint32_t *success_mcs; + uint32_t fail_mcs_len; + uint32_t *fail_mcs; + uint32_t delay_len; + uint32_t *delay; +}; + +/** + * struct sir_wifi_rx - per AC rx stats + * @mpdus: number of RX packets on MAC layer + * @bytes: bytes of RX packets on MAC layer + * @ppdus: number of RX packets on PHY layer + * @ppdu_bytes: bytes of RX packets on PHY layer + * @mpdu_lost: number of discontinuity in seqnum + * @mpdu_retry: number of RX packets flagged as retransmissions + * @mpdu_dup: number of RX packets identified as duplicates + * @mpdu_discard: number of RX packets discarded + * @aggr_len: length of MPDU aggregation histogram buffer + * @mpdu_aggr: histogram of MPDU aggregation size + * @mcs_len: length of mcs histogram buffer + * @mcs: histogram of encoding rate. + */ +struct sir_wifi_rx { + uint32_t mpdus; + uint32_t bytes; + uint32_t ppdus; + uint32_t ppdu_bytes; + uint32_t mpdu_lost; + uint32_t mpdu_retry; + uint32_t mpdu_dup; + uint32_t mpdu_discard; + uint32_t aggr_len; + uint32_t *mpdu_aggr; + uint32_t mcs_len; + uint32_t *mcs; +}; + +/** + * struct sir_wifi_ll_ext_wmm_ac_stats - stats for WMM AC + * @type: WMM AC type + * @tx_stats: pointer to TX stats + * @rx_stats: pointer to RX stats + */ +struct sir_wifi_ll_ext_wmm_ac_stats { + uint32_t type; + struct sir_wifi_tx *tx_stats; + struct sir_wifi_rx *rx_stats; +}; + +/** + * struct sir_wifi_ll_ext_peer_stats - per peer stats + * @peer_id: peer ID + * @vdev_id: VDEV ID + * @mac_address: MAC address + * @sta_ps_inds: how many times STAs go to sleep + * @sta_ps_durs: total sleep time of STAs (units in ms) + * @rx_probe_reqs: number of probe requests received + * @rx_oth_mgmts: number of other management frames received, + * not including probe requests + * @peer_signal_stat: signal stats + * @ac_stats: WMM BE/BK/VI/VO stats + */ +struct sir_wifi_ll_ext_peer_stats { + uint32_t peer_id; + uint32_t vdev_id; + tSirMacAddr mac_address; + uint32_t sta_ps_inds; + uint32_t sta_ps_durs; + uint32_t rx_probe_reqs; + uint32_t rx_oth_mgmts; + struct sir_wifi_peer_signal_stats peer_signal_stats; + struct sir_wifi_ll_ext_wmm_ac_stats ac_stats[WIFI_MAX_AC]; +}; + +/** + * struct sir_wifi_ll_ext_stats - link layer stats report + * @trigger_cond_id: Indicate what triggered this event. + * 1: timeout. 2: threshold + * @cca_chgd_bitmap: Bitmap to indicate changed channel CCA stats + * which exceeded the thresholds + * @sig_chgd_bitmap: Bitmap to indicate changed peer signal stats + * which exceeded the thresholds + * @tx_chgd_bitmap: Bitmap to indicate changed TX counters + * which exceeded the thresholds + * @rx_chgd_bitmap: Bitmap to indicate changed RX counters + * which exceeded the thresholds + * @chan_cca_stats: channel CCA stats + * @peer_signal_stats: peer signal stats + * @tx_mpdu_aggr_array_len: length of TX MPDU aggregation buffer + * @tx_succ_mcs_array_len: length of mcs buffer for ACKed MPDUs + * @tx_fail_mcs_array_len: length of mcs buffer for no-ACKed MPDUs + * @tx_delay_array_len: length of delay stats buffer + * @rx_mpdu_aggr_array_len: length of RX MPDU aggregation buffer + * @rx_mcs_array_len: length of RX mcs stats buffer + * @peer_stats: peer stats + * @cca: physical channel CCA stats + * @stats: pointer to stats data buffer. + * + * Structure of the whole statistics is like this: + * --------------------------------- + * | trigger_cond_i | + * +-------------------------------+ + * | cca_chgd_bitmap | + * +-------------------------------+ + * | sig_chgd_bitmap | + * +-------------------------------+ + * | tx_chgd_bitmap | + * +-------------------------------+ + * | rx_chgd_bitmap | + * +-------------------------------+ + * | peer_num | + * +-------------------------------+ + * | channel_num | + * +-------------------------------+ + * | tx_mpdu_aggr_array_len | + * +-------------------------------+ + * | tx_succ_mcs_array_len | + * +-------------------------------+ + * | tx_fail_mcs_array_len | + * +-------------------------------+ + * | tx_delay_array_len | + * +-------------------------------+ + * | rx_mpdu_aggr_array_len | + * +-------------------------------+ + * | rx_mcs_array_len | + * +-------------------------------+ + * | pointer to CCA stats | + * +-------------------------------+ + * | pointer to peer stats | + * +-------------------------------+ + * | CCA stats | + * +-------------------------------+ + * | peer_stats |----+ + * +-------------------------------+ | + * | per peer signals stats |<---+ + * | peer0 ~ peern | | + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | configurable for user layer. |<-+ | + * +-------------------------------+ | | + * | per peer tx stats |--+ | + * | BE | <--+ + * | BK | | + * | VI | | + * | VO | | + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | configurable for user layer. |<-+ | + * +-------------------------------+ | | + * | peer peer rx stats |--+ | + * | BE | <--+ + * | BE | + * | BK | + * | VI | + * | VO | + * --------------------------------- + */ +struct sir_wifi_ll_ext_stats { + uint32_t trigger_cond_id; + uint32_t cca_chgd_bitmap; + uint32_t sig_chgd_bitmap; + uint32_t tx_chgd_bitmap; + uint32_t rx_chgd_bitmap; + uint8_t peer_num; + uint8_t channel_num; + uint32_t tx_mpdu_aggr_array_len; + uint32_t tx_succ_mcs_array_len; + uint32_t tx_fail_mcs_array_len; + uint32_t tx_delay_array_len; + uint32_t rx_mpdu_aggr_array_len; + uint32_t rx_mcs_array_len; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + struct sir_wifi_chan_cca_stats *cca; + uint8_t stats[]; +}; + +/** + * struct sir_channel_cca_threshold - threshold for channel CCA + * @idle_time: idle time, no TX, no RX, no interference + * @tx_time: time transmitting packets + * @rx_in_bss_time: time receiving packets in current BSSs + * @rx_out_bss_time: time receiving packets not in current BSSs + * @rx_busy_time: time interference detected + * @rx_in_bad_cond_time: receiving packets with errors + * @tx_in_bad_cond_time: time transmitted packets not been ACKed + * @wlan_not_avail_time: wlan card cannot work + */ +struct sir_channel_cca_threshold { + uint32_t idle_time; + uint32_t tx_time; + uint32_t rx_in_bss_time; + uint32_t rx_out_bss_time; + uint32_t rx_busy_time; + uint32_t rx_in_bad_cond_time; + uint32_t tx_in_bad_cond_time; + uint32_t wlan_not_avail_time; +}; + +/** + * struct sir_signal_threshold - threshold for per peer sigbal + * @snr: signal to noise rate + * @nf: noise floor + */ +struct sir_signal_threshold { + uint32_t snr; + uint32_t nf; +}; + +/** + * struct sir_tx_threshold - threshold for TX + * @msdu: TX MSDUs on MAC layer + * @mpdu: TX MPDUs on MAC layer + * @ppdu: TX PPDUs on MAC layer + * @bytes: TX bytes on MAC layer + * @msdu_drop: drooped MSDUs + * @byte_drop: dropped Bytes + * @mpdu_retry: MPDU not acked + * @ppdu_fail: PPDUs which received no block ack + * @aggregation: aggregation size + * @succ_mcs: histogram of encoding rate for acked PPDUs + * @fail_mcs: histogram of encoding rate for no-acked PPDUs + */ +struct sir_tx_threshold { + uint32_t msdu; + uint32_t mpdu; + uint32_t ppdu; + uint32_t bytes; + uint32_t msdu_drop; + uint32_t byte_drop; + uint32_t mpdu_retry; + uint32_t mpdu_fail; + uint32_t ppdu_fail; + uint32_t aggregation; + uint32_t succ_mcs; + uint32_t fail_mcs; + uint32_t delay; +}; + +/** + * struct sir_rx_threshold - threshold for RX + * @mpdu: RX MPDUs on MAC layer + * @bytes: RX bytes on MAC layer + * @ppdu: RX PPDU on PHY layer + * @ppdu_bytes: RX bytes on PHY layer + * @disorder: discontinuity in seqnum + * @mpdu_retry: MPDUs flagged as retry + * @mpdu_dup: MPDUs identified as duplicated + * @aggregation: aggregation size + * @mcs: histogram of encoding rate for PPDUs + * @ps_inds: power save indication + * @ps_durs: total time in power save + * @probe_reqs: probe request received + * @other_mgmt: other MGMT frames received + */ +struct sir_rx_threshold { + uint32_t mpdu; + uint32_t bytes; + uint32_t ppdu; + uint32_t ppdu_bytes; + uint32_t disorder; + uint32_t mpdu_lost; + uint32_t mpdu_retry; + uint32_t mpdu_dup; + uint32_t mpdu_discard; + uint32_t aggregation; + uint32_t mcs; + uint32_t ps_inds; + uint32_t ps_durs; + uint32_t probe_reqs; + uint32_t other_mgmt; +}; + +/** + * struct sir_wifi_ll_ext_stats_threshold - Threshold for stats update + * @period: MAC counter indication period (unit in ms) + * @enable: if threshold mechanism is enabled or disabled + * @enable_bitmap: whether dedicated threshold is enabed. + * Every MAC counter has a dedicated threshold. If the dedicated + * threshold is not set in the bitmap, global threshold will take + * effect. + * @global: whether clobal threshold is enabled. + * When both global and dedicated threshold are disabled, MAC counter + * will indicate stats periodically. + * @global_threshold: global threshold value + * @cca_bitmap: bitmap for CCA. + * Bit0: idle time + * Bit1: tx time + * Bit2: RX in BSS + * Bit3: RX out of BSS + * Bit4: medium busy + * Bit5: RX bad + * Bit6: TX bad + * Bit7: WLAN card not available + * @signal_bitmap: + * Bit0: Per channel SNR counter + * Bit1: Per channel noise floor counter + * @tx_bitmap: bitmap for TX counters + * Bit0: TX counter unit in MSDU + * Bit1: TX counter unit in MPDU + * Bit2: TX counter unit in PPDU + * Bit3: TX counter unit in byte + * Bit4: Dropped MSDUs + * Bit5: Dropped Bytes + * Bit6: MPDU retry counter + * Bit7: MPDU failure counter + * Bit8: PPDU failure counter + * Bit9: MPDU aggregation counter + * Bit10: MCS counter for ACKed MPDUs + * Bit11: MCS counter for Failed MPDUs + * Bit12: TX Delay counter + * @rx_bitmap:bitmap for RX counters + * Bit0: MAC RX counter unit in MPDU + * Bit1: MAC RX counter unit in byte + * Bit2: PHY RX counter unit in PPDU + * Bit3: PHY RX counter unit in byte + * Bit4: Disorder counter + * Bit5: Retry counter + * Bit6: Duplication counter + * Bit7: Discard counter + * Bit8: MPDU aggregation size counter + * Bit9: MCS counter + * Bit10: Peer STA power state change (wake to sleep) counter + * Bit11: Peer STA power save counter, total time in PS mode + * Bit12: Probe request counter + * Bit13: Other management frames counter + * @cca_thresh: CCA threshold + * @signal_thresh: signal threshold + * @tx_thresh: TX threshold + * @rx_thresh: RX threshold + * + * Generally, Link layer statistics is reported periodically. But if the + * variation of one stats of compared to the previous notification exceeds + * a threshold, FW will report the new stats immediately. + * This structure contains threshold for different counters. + */ +struct sir_ll_ext_stats_threshold { + uint32_t period; + uint32_t enable; + uint32_t enable_bitmap; + uint32_t global; + uint32_t global_threshold; + uint32_t cca_bitmap; + uint32_t signal_bitmap; + uint32_t tx_bitmap; + uint32_t rx_bitmap; + struct sir_channel_cca_threshold cca; + struct sir_signal_threshold signal; + struct sir_tx_threshold tx; + struct sir_rx_threshold rx; +}; + +#define LL_STATS_MIN_PERIOD 10 +#define LL_STATS_INVALID_PERIOD 0xFFFFFFFF + +/* Result ID for LL stats extension */ +#define WMI_LL_STATS_EXT_PS_CHG 0x00000100 +#define WMI_LL_STATS_EXT_TX_FAIL 0x00000200 +#define WMI_LL_STATS_EXT_MAC_COUNTER 0x00000400 +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +typedef struct sAniGetLinkStatus { + uint16_t msgType; /* message type is same as the request type */ + uint16_t msgLen; /* length of the entire request */ + uint8_t linkStatus; + uint8_t sessionId; +} tAniGetLinkStatus, *tpAniGetLinkStatus; + +/** + * struct sir_lost_link_info - lost link information structure. + * + * @vdev_id: vdev_id from WMA. some modules call sessionId. + * @rssi: rssi at disconnection time. + * + * driver uses this structure to communicate information collected at + * disconnection time. + */ +struct sir_lost_link_info { + uint32_t vdev_id; + int32_t rssi; +}; + +/* find the size of given member within a structure */ +#ifndef member_size +#define member_size(type, member) (sizeof(((type *)0)->member)) +#endif + +#define RTT_INVALID 0x00 +#define RTT_TIMING_MEAS_CAPABILITY 0x01 +#define RTT_FINE_TIME_MEAS_INITIATOR_CAPABILITY 0x02 +#define RTT_FINE_TIME_MEAS_RESPONDER_CAPABILITY 0x03 + +/* number of neighbor reports that we can handle in Neighbor Report Response */ +#define MAX_SUPPORTED_NEIGHBOR_RPT 15 + +/** + * struct sir_stats_avg_factor + * @vdev_id: session id + * @stats_avg_factor: average factor + */ +struct sir_stats_avg_factor { + uint8_t vdev_id; + uint16_t stats_avg_factor; +}; + +/** + * struct sir_guard_time_request + * @vdev_id: session id + * @guard_time: guard time + */ +struct sir_guard_time_request { + uint8_t vdev_id; + uint32_t guard_time; +}; + +/* Max number of rates allowed in Supported Rates IE */ +#define MAX_NUM_SUPPORTED_RATES (8) + +/** + * struct rssi_breach_event - rssi breached event structure + * @request_id: request id + * @session_id: session id + * @curr_rssi: current rssi + * @curr_bssid: current bssid + */ +struct rssi_breach_event { + uint32_t request_id; + uint32_t session_id; + int8_t curr_rssi; + struct qdf_mac_addr curr_bssid; +}; + +/** + * struct chip_pwr_save_fail_detected_params - chip power save failure detected + * event params + * @failure_reason_code:failure reason code + * @wake_lock_bitmap:bitmap for modules voting against sleep for long duration. + */ +struct chip_pwr_save_fail_detected_params { + uint32_t failure_reason_code; + uint32_t wake_lock_bitmap[4]; +}; + +#define MAX_NUM_FW_SEGMENTS 4 + +/** + * DEFAULT_SCAN_IE_ID - Identifier for the collection of IE's added + * by default to the probe request + */ +#define DEFAULT_SCAN_IE_ID 256 + + /* MAX_DEFAULT_SCAN_IE_LEN - Maximum length of Default Scan IE's */ +#define MAX_DEFAULT_SCAN_IE_LEN 2048 + + /* Extended Capabilities IE header(IE Id + IE Length) length */ +#define EXT_CAP_IE_HDR_LEN 2 + +/** + * struct hdd_default_scan_ie - HDD default scan IE structure + * @message_type: message type to be set with eWNI_SME_DEFAULT_SCAN_IE + * @length: length of the struct hdd_default_scan_ie + * @vdev_id: vdev_id + * @ie_len: Default scan IE length + * @ie_data: Pointer to default scan IE data + */ +struct hdd_default_scan_ie { + uint16_t message_type; + uint16_t length; + uint16_t vdev_id; + uint16_t ie_len; + uint8_t ie_data[MAX_DEFAULT_SCAN_IE_LEN]; +}; + +/** + * struct vdev_ie_info - IE info + * @vdev_id - vdev for which the IE is being sent + * @ie_id - ID of the IE + * @length - length of the IE data + * @band - indicates IE is intended for which band + * @data - IE data + * + * This structure is used to store the IE information. + */ +struct vdev_ie_info { + uint32_t vdev_id; + uint32_t ie_id; + uint32_t length; + uint32_t band; + uint8_t *data; +}; + +/** + * struct send_extcap_ie - used to pass send_extcap_ie msg from SME to PE + * @type - MSG type + * @length - length of the message + * @seesion_id - session_id for which the message is intended for + * + * This structure is used to pass send_extcap_ie msg from SME to PE + */ +struct send_extcap_ie { + uint16_t msg_type; /* eWNI_SME_SET_IE_REQ */ + uint16_t length; + uint8_t session_id; +}; + +typedef void (*antenna_mode_cb)(uint32_t status, void *context); + +/** + * struct cfg_action_frm_tb_ppdu - action frame TB PPDU cfg + * @vdev_id - vdev id + * @cfg - enable/disable + * @frm_len - frame length + * @data - frame data + * + * This structure is used to cfg action frame tb ppdu. + */ +struct cfg_action_frm_tb_ppdu { + uint8_t vdev_id; + uint8_t cfg; + uint8_t frm_len; + uint8_t *data; +}; + +/** + * struct sir_nss_update_request + * @msgType: nss update msg type + * @msgLen: length of the msg + * @new_nss: new spatial stream value + * @ch_width: channel width - optional + * @vdev_id: session id + */ +struct sir_nss_update_request { + uint16_t msgType; + uint16_t msgLen; + uint8_t new_nss; + uint8_t ch_width; + uint32_t vdev_id; +}; + +/** + * struct sir_sap_ch_width_update + * @msgType: ch_width update msg type + * @msgLen: length of the msg + * @ch_width: channel width + * @vdev_id: vdev id + */ +struct sir_sap_ch_width_update { + uint16_t msgType; + uint16_t msgLen; + enum phy_ch_width ch_width; + uint32_t vdev_id; +}; + +/** + * enum sir_bcn_update_reason: bcn update reason + * @REASON_DEFAULT: reason default + * @REASON_NSS_UPDATE: If NSS is updated + * @REASON_CONFIG_UPDATE: Config update + * @REASON_SET_HT2040: HT2040 update + * @REASON_COLOR_CHANGE: Color change + * @REASON_CHANNEL_SWITCH: channel switch + * @REASON_MLO_IE_UPDATE: mlo ie update + * @REASON_RNR_UPDATE: SAP is changed, notify co-located SAP + */ +enum sir_bcn_update_reason { + REASON_DEFAULT = 0, + REASON_NSS_UPDATE = 1, + REASON_CONFIG_UPDATE = 2, + REASON_SET_HT2040 = 3, + REASON_COLOR_CHANGE = 4, + REASON_CHANNEL_SWITCH = 5, + REASON_MLO_IE_UPDATE = 6, + REASON_RNR_UPDATE = 7, + REASON_CH_WIDTH_UPDATE = 8, +}; + +/** + * struct sir_bcn_update_rsp + * + * @vdev_id: session for which bcn was updated + * @reason: bcn update reason + * @status: status of the beacon sent to FW + */ +struct sir_bcn_update_rsp { + uint8_t vdev_id; + enum sir_bcn_update_reason reason; + QDF_STATUS status; +}; + +struct sir_qos_params { + uint8_t aifsn; + uint8_t cwmin; + uint8_t cwmax; +}; + +/** + * struct sir_sme_ext_change_chan_req - channel change request + * @message_type: message id + * @length: msg length + * @new_channel: new channel + * @vdev_id: vdev id + */ +struct sir_sme_ext_cng_chan_req { + uint16_t message_type; /* eWNI_SME_EXT_CHANGE_CHANNEL */ + uint16_t length; + uint32_t new_ch_freq; + uint8_t vdev_id; +}; + +#define IGNORE_NUD_FAIL 0 +#define DISCONNECT_AFTER_NUD_FAIL 1 +#define ROAM_AFTER_NUD_FAIL 2 +#define DISCONNECT_AFTER_ROAM_FAIL 3 + +/** + * struct sir_sme_ext_change_chan_ind. + * @session_id: session id + * @new_chan_freq: new channel frequency to change to + */ +struct sir_sme_ext_cng_chan_ind { + uint8_t session_id; + uint32_t new_chan_freq; +}; + +/** + * struct stsf - the basic stsf structure + * + * @vdev_id: vdev id + * @tsf_low: low 32bits of tsf + * @tsf_high: high 32bits of tsf + * @soc_timer_low: low 32bits of synced SOC timer value + * @soc_timer_high: high 32bits of synced SOC timer value + * @global_tsf_low: low 32bits of tsf64 + * @global_tsf_high: high 32bits of tsf64 + * @mac_id: MAC identifier + * @mac_id_valid: Indicate if mac_id is valid or not + * @tsf_id: TSF-ID corresponding to the TSF value + * @tsf_id_valid: flag indicating whether TSD-ID is valid + * + * Driver uses this structure to store the tsf information. + */ +struct stsf { + uint32_t vdev_id; + uint32_t tsf_low; + uint32_t tsf_high; + uint32_t soc_timer_low; + uint32_t soc_timer_high; + uint32_t global_tsf_low; + uint32_t global_tsf_high; + uint32_t mac_id; + uint32_t mac_id_valid; + uint32_t tsf_id; + uint32_t tsf_id_valid; +}; + +/* ie + extn ie */ +#define SIR_BCN_FLT_MAX_ELEMS_IE_LIST (8 + 8) +/** + * struct beacon_filter_param - parameters for beacon filtering + * @vdev_id: vdev id + * @ie_map: bitwise map of IEs that needs to be filtered + * + */ +struct beacon_filter_param { + uint32_t vdev_id; + uint32_t ie_map[SIR_BCN_FLT_MAX_ELEMS_IE_LIST]; +}; + +/** + * struct adaptive_dwelltime_params - the adaptive dwelltime params + * @vdev_id: vdev id + * @is_enabled: Adaptive dwell time is enabled/disabled + * @dwelltime_mode: global default adaptive dwell mode + * @lpf_weight: weight to calculate the average low pass + * filter for channel congestion + * @passive_mon_intval: intval to monitor wifi activity in passive scan in msec + * @wifi_act_threshold: % of wifi activity used in passive scan 0-100 + * + */ +struct adaptive_dwelltime_params { + uint32_t vdev_id; + bool is_enabled; + uint8_t dwelltime_mode; + uint8_t lpf_weight; + uint8_t passive_mon_intval; + uint8_t wifi_act_threshold; +}; + +/** + * enum obss_ht40_scancmd_type - obss scan command type + * @HT40_OBSS_SCAN_PARAM_START: OBSS scan start + * @HT40_OBSS_SCAN_PARAM_UPDATE: OBSS scan param update + */ +enum obss_ht40_scancmd_type { + HT40_OBSS_SCAN_PARAM_START, + HT40_OBSS_SCAN_PARAM_UPDATE +}; + +/** + * struct sme_obss_ht40_scanind_msg - sme obss scan params + * @msg_type: message type + * @length: message length + * @mac_addr: mac address + */ +struct sme_obss_ht40_scanind_msg { + uint16_t msg_type; + uint16_t length; + struct qdf_mac_addr mac_addr; +}; + +/** + * struct obss_ht40_scanind - ht40 obss scan request + * @cmd: message type + * @scan_type: message length + * @obss_passive_dwelltime: obss passive dwelltime + * @obss_active_dwelltime: obss active dwelltime + * @obss_width_trigger_interval: scan interval + * @obss_passive_total_per_channel: total passive scan time per channel + * @obss_active_total_per_channel: total active scan time per channel + * @bsswidth_ch_trans_delay: OBSS transition delay time + * @obss_activity_threshold: OBSS activity threshold + * @self_sta_idx: self sta identification + * @bss_id: BSS index + * @fortymhz_intolerent: Ht40mhz intolerance + * @channel_count: channel count + * @chan_freq_list: List of channel frequencies in MHz + * @current_operatingclass: operating class + * @iefield_len: ie's length + * @iefiled: ie's information + */ +struct obss_ht40_scanind { + enum obss_ht40_scancmd_type cmd; + enum eSirScanType scan_type; + /* In TUs */ + uint16_t obss_passive_dwelltime; + uint16_t obss_active_dwelltime; + /* In seconds */ + uint16_t obss_width_trigger_interval; + /* In TU's */ + uint16_t obss_passive_total_per_channel; + uint16_t obss_active_total_per_channel; + uint16_t bsswidth_ch_trans_delay; + uint16_t obss_activity_threshold; + uint8_t self_sta_idx; + uint8_t bss_id; + uint8_t fortymhz_intolerent; + uint8_t channel_count; + uint32_t chan_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t current_operatingclass; + uint16_t iefield_len; + uint8_t iefield[SIR_ROAM_SCAN_MAX_PB_REQ_SIZE]; +}; + +/** + * struct obss_scanparam - OBSS scan parameters + * @obss_passive_dwelltime: message type + * @obss_active_dwelltime: message length + * @obss_width_trigger_interval: obss passive dwelltime + * @obss_passive_total_per_channel: obss passive total scan time + * @obss_active_total_per_channel: obss active total scan time + * @bsswidth_ch_trans_delay: OBSS transition delay time + * @obss_activity_threshold: OBSS activity threshold + */ +struct obss_scanparam { + uint16_t obss_passive_dwelltime; + uint16_t obss_active_dwelltime; + uint16_t obss_width_trigger_interval; + uint16_t obss_passive_total_per_channel; + uint16_t obss_active_total_per_channel; + uint16_t bsswidth_ch_trans_delay; + uint16_t obss_activity_threshold; +}; + +/** + * struct sir_apf_set_offload - set apf filter instructions + * @session_id: session identifier + * @version: host apf version + * @filter_id: Filter ID for APF filter + * @total_length: The total length of the full instruction + * total_length equal to 0 means reset + * @current_offset: current offset, 0 means start a new setting + * @current_length: Length of current @program + * @program: APF instructions + */ +struct sir_apf_set_offload { + uint8_t session_id; + uint32_t version; + uint32_t filter_id; + uint32_t total_length; + uint32_t current_offset; + uint32_t current_length; + uint8_t *program; +}; + +/** + * struct sir_apf_offload_capabilities - get apf Capabilities + * @apf_version: fw's implement version + * @max_apf_filters: max filters that fw supports + * @max_bytes_for_apf_inst: the max bytes that can be used as apf instructions + */ +struct sir_apf_get_offload { + uint32_t apf_version; + uint32_t max_apf_filters; + uint32_t max_bytes_for_apf_inst; +}; + +#ifdef WLAN_FEATURE_NAN +/** + * enum ndp_end_type - NDP end type + * @NDP_END_TYPE_UNSPECIFIED: type is unspecified + * @NDP_END_TYPE_PEER_UNAVAILABLE: type is peer unavailable + * @NDP_END_TYPE_OTA_FRAME: NDP end frame received from peer + * + */ +enum ndp_end_type { + NDP_END_TYPE_UNSPECIFIED = 0x00, + NDP_END_TYPE_PEER_UNAVAILABLE = 0x01, + NDP_END_TYPE_OTA_FRAME = 0x02, +}; + +/** + * enum ndp_end_reason_code - NDP end reason code + * @NDP_END_REASON_UNSPECIFIED: reason is unspecified + * @NDP_END_REASON_INACTIVITY: reason is peer inactivity + * @NDP_END_REASON_PEER_DATA_END: data end indication received from peer + * + */ +enum ndp_end_reason_code { + NDP_END_REASON_UNSPECIFIED = 0x00, + NDP_END_REASON_INACTIVITY = 0x01, + NDP_END_REASON_PEER_DATA_END = 0x02, +}; + +/** + * enum nan_status_type - NDP status type + * @NDP_RSP_STATUS_SUCCESS: request was successful + * @NDP_RSP_STATUS_ERROR: request failed + */ +enum nan_status_type { + NDP_RSP_STATUS_SUCCESS = 0x00, + NDP_RSP_STATUS_ERROR = 0x01, +}; + +/** + * enum nan_reason_code - NDP command rsp reason code value + * @NDP_UNSUPPORTED_CONCURRENCY: Will be used in unsupported concurrency cases + * @NDP_NAN_DATA_IFACE_CREATE_FAILED: ndi create failed + * @NDP_NAN_DATA_IFACE_DELETE_FAILED: ndi delete failed + * @NDP_DATA_INITIATOR_REQ_FAILED: data initiator request failed + * @NDP_DATA_RESPONDER_REQ_FAILED: data responder request failed + * @NDP_INVALID_SERVICE_INSTANCE_ID: invalid service instance id + * @NDP_INVALID_NDP_INSTANCE_ID: invalid ndp instance id + * @NDP_INVALID_RSP_CODE: invalid response code in ndp responder request + * @NDP_INVALID_APP_INFO_LEN: invalid app info length + * @NDP_NMF_REQ_FAIL: OTA nan mgmt frame failure for data request + * @NDP_NMF_RSP_FAIL: OTA nan mgmt frame failure for data response + * @NDP_NMF_CNF_FAIL: OTA nan mgmt frame failure for confirm + * @NDP_END_FAILED: ndp end failed + * @NDP_NMF_END_REQ_FAIL: OTA nan mgmt frame failure for data end + * @NDP_VENDOR_SPECIFIC_ERROR: other vendor specific failures + */ +enum nan_reason_code { + NDP_UNSUPPORTED_CONCURRENCY = 9000, + NDP_NAN_DATA_IFACE_CREATE_FAILED = 9001, + NDP_NAN_DATA_IFACE_DELETE_FAILED = 9002, + NDP_DATA_INITIATOR_REQ_FAILED = 9003, + NDP_DATA_RESPONDER_REQ_FAILED = 9004, + NDP_INVALID_SERVICE_INSTANCE_ID = 9005, + NDP_INVALID_NDP_INSTANCE_ID = 9006, + NDP_INVALID_RSP_CODE = 9007, + NDP_INVALID_APP_INFO_LEN = 9008, + NDP_NMF_REQ_FAIL = 9009, + NDP_NMF_RSP_FAIL = 9010, + NDP_NMF_CNF_FAIL = 9011, + NDP_END_FAILED = 9012, + NDP_NMF_END_REQ_FAIL = 9013, + /* 9500 onwards vendor specific error codes */ + NDP_VENDOR_SPECIFIC_ERROR = 9500, +}; + +/** + * struct ndi_create_rsp - ndi create response params + * @status: request status + * @reason: reason if any + * + */ +struct ndi_create_rsp { + uint32_t status; + uint32_t reason; + uint8_t sta_id; +}; + +/** + * struct ndi_delete_rsp - ndi delete response params + * @status: request status + * @reason: reason if any + * + */ +struct ndi_delete_rsp { + uint32_t status; + uint32_t reason; +}; + +/** + * struct peer_ndp_map - mapping of NDP instances to peer to VDEV + * @vdev_id: session id of the interface over which ndp is being created + * @peer_ndi_mac_addr: peer NDI mac address + * @num_active_ndp_sessions: number of active NDP sessions on the peer + * @type: NDP end indication type + * @reason_code: NDP end indication reason code + * @ndp_instance_id: NDP instance ID + * + */ +struct peer_ndp_map { + uint32_t vdev_id; + struct qdf_mac_addr peer_ndi_mac_addr; + uint32_t num_active_ndp_sessions; + enum ndp_end_type type; + enum ndp_end_reason_code reason_code; + uint32_t ndp_instance_id; +}; + +#endif /* WLAN_FEATURE_NAN */ + +/** + * struct sir_p2p_lo_start - p2p listen offload start + * @vdev_id: vdev identifier + * @ctl_flags: control flag + * @freq: p2p listen frequency + * @period: listen offload period + * @interval: listen offload interval + * @count: number listen offload intervals + * @device_types: device types + * @dev_types_len: device types length + * @probe_resp_tmplt: probe response template + * @probe_resp_len: probe response template length + */ +struct sir_p2p_lo_start { + uint32_t vdev_id; + uint32_t ctl_flags; + uint32_t freq; + uint32_t period; + uint32_t interval; + uint32_t count; + uint8_t *device_types; + uint32_t dev_types_len; + uint8_t *probe_resp_tmplt; + uint32_t probe_resp_len; +}; + +/** + * struct sir_p2p_lo_event - P2P listen offload stop event + * @vdev_id: vdev identifier + * @reason_code: P2P listen offload stop reason + */ +struct sir_p2p_lo_event { + uint32_t vdev_id; + uint32_t reason_code; +}; + +/** + * struct sir_hal_pwr_dbg_cmd - unit test command parameters + * @pdev_id: pdev id + * @module_id: module id + * @num_args: number of arguments + * @args: arguments + */ +struct sir_mac_pwr_dbg_cmd { + uint32_t pdev_id; + uint32_t module_id; + uint32_t num_args; + uint32_t args[MAX_POWER_DBG_ARGS_SUPPORTED]; +}; + +/** + * struct sme_send_disassoc_frm_req - send disassoc request frame + * @msg_type: message type + * @length: length of message + * @vdev_id: vdev id + * @peer_mac: peer mac address + * @reason: reason for disassoc + * @wait_for_ack: wait for acknowledgment + **/ + struct sme_send_disassoc_frm_req { + uint16_t msg_type; + uint16_t length; + uint8_t vdev_id; + uint8_t peer_mac[6]; + uint16_t reason; + uint8_t wait_for_ack; + }; + +/** + * struct sme_update_access_policy_vendor_ie - update vendor ie and access + * policy + * @msg_type: message id + * @msg_len: message length + * @vdev_id: vdev id + * @ie: vendor ie + * @access_policy: access policy for vendor ie + */ +struct sme_update_access_policy_vendor_ie { + uint16_t msg_type; + uint16_t length; + uint32_t vdev_id; + uint8_t ie[WLAN_MAX_IE_LEN + 2]; + uint8_t access_policy; +}; + +/** + * struct sme_tx_fail_cnt_threshold - tx failure count for disconnect to fw + * @session_id: Session id + * @tx_fail_cnt_threshold: Tx failure count to do disconnect + */ +struct sme_tx_fail_cnt_threshold { + uint8_t session_id; + uint32_t tx_fail_cnt_threshold; +}; + +/** + * struct sme_short_retry_limit - transmission retry limit for short frames. + * @session_id: Session id + * @short_retry_limit: transmission retry limit for short frame. + * + */ +struct sme_short_retry_limit { + uint8_t session_id; + uint32_t short_retry_limit; +}; + +/** + * struct sme_long_retry_limit - transmission retry limit for long frames + * @session_id: Session id + * @short_retry_limit: transmission retry limit for long frames. + * + */ +struct sme_long_retry_limit { + uint8_t session_id; + uint32_t long_retry_limit; +}; + +/** + * struct sme_addba_accept - Allow/reject the addba request frame + * @session_id: Session id + * @addba_accept: Allow/reject the addba request frame + */ +struct sme_addba_accept { + uint8_t session_id; + uint8_t addba_accept; +}; + +/** + * struct sme_sta_inactivity_timeout - set sta_inactivity_timeout + * @session_id: session Id. + * @sta_inactivity_timeout: Timeout to disconnect STA after there + * is no activity. + */ +struct sme_sta_inactivity_timeout { + uint8_t session_id; + uint32_t sta_inactivity_timeout; +}; + +/** + * struct sme_vdev_pause - Pause vdev for a defined time interval + * @session_id: Session id + * @vdev_pause_duration: vdev pause duration + */ +struct sme_vdev_pause { + uint8_t session_id; + uint8_t vdev_pause_duration; +}; + +/* + * struct wow_pulse_mode - WoW Pulse set cmd struct + * @wow_pulse_enable: enable or disable this feature + * @wow_pulse_pin: GPIO PIN for Pulse + * @wow_pulse_interval_low: Pulse interval low + * @wow_pulse_interval_high: Pulse interval high + * @wow_pulse_repeat_count: Pulse repeat count + * @wow_pulse_init_state: Pulse init level + * + * SME uses this structure to configure wow pulse info + * and send it to WMA + */ +struct wow_pulse_mode { + bool wow_pulse_enable; + uint8_t wow_pulse_pin; + uint16_t wow_pulse_interval_high; + uint16_t wow_pulse_interval_low; + uint32_t wow_pulse_repeat_count; + uint32_t wow_pulse_init_state; +}; + + +/** + * umac_send_mb_message_to_mac(): post message to umac + * @msg: opaque message pointer + * + * Return: QDF status + */ +QDF_STATUS umac_send_mb_message_to_mac(void *msg); + +/** + * struct scan_chan_info - channel info + * @freq: radio frequence + * @cmd flag: cmd flag + * @noise_floor: noise floor + * @cycle_count: cycle count + * @rx_clear_count: rx clear count + * @tx_frame_count: TX frame count + * @clock_freq: clock frequence MHZ + * @cca_busy_subband_info: CCA busy for each possible 20Mhz subbands + * of the wideband scan channel + */ +struct scan_chan_info { + uint32_t freq; + uint32_t cmd_flag; + uint32_t noise_floor; + uint32_t cycle_count; + uint32_t rx_clear_count; + uint32_t tx_frame_count; + uint32_t clock_freq; + struct wide_band_scan_chan_info subband_info; +}; + +/** + * enum wow_resume_trigger - resume trigger override setting values + * @WOW_RESUME_TRIGGER_DEFAULT: fw to use platform default resume trigger + * @WOW_RESUME_TRIGGER_HTC_WAKEUP: force fw to use HTC Wakeup to resume + * @WOW_RESUME_TRIGGER_GPIO: force fw to use GPIO to resume + * @WOW_RESUME_TRIGGER_COUNT: number of resume trigger options + */ +enum wow_resume_trigger { + /* always first */ + WOW_RESUME_TRIGGER_DEFAULT = 0, + WOW_RESUME_TRIGGER_HTC_WAKEUP, + WOW_RESUME_TRIGGER_GPIO, + /* always last */ + WOW_RESUME_TRIGGER_COUNT +}; + +/** + * enum wow_interface_pause - interface pause override setting values + * @WOW_INTERFACE_PAUSE_DEFAULT: use platform default interface pause setting + * @WOW_INTERFACE_PAUSE_ENABLE: force interface pause setting to enabled + * @WOW_INTERFACE_PAUSE_DISABLE: force interface pause setting to disabled + * @WOW_INTERFACE_PAUSE_COUNT: number of interface pause options + */ +enum wow_interface_pause { + /* always first */ + WOW_INTERFACE_PAUSE_DEFAULT = 0, + WOW_INTERFACE_PAUSE_ENABLE, + WOW_INTERFACE_PAUSE_DISABLE, + /* always last */ + WOW_INTERFACE_PAUSE_COUNT +}; + +/** + * struct wow_enable_params - A collection of wow enable override parameters + * @is_unit_test: true to notify fw this is a unit-test suspend + * @interface_pause: used to override the interface pause indication sent to fw + * @resume_trigger: used to force fw to use a particular resume method + */ +struct wow_enable_params { + bool is_unit_test; + enum wow_interface_pause interface_pause; + enum wow_resume_trigger resume_trigger; +}; + +#define HE_LTF_1X 0 +#define HE_LTF_2X 1 +#define HE_LTF_4X 2 + +#define HE_LTF_ALL 0x7 +#define HE_SGI_MASK 0xFF00 + +#define AUTO_RATE_GI_400NS 8 +#define AUTO_RATE_GI_800NS 9 +#define AUTO_RATE_GI_1600NS 10 +#define AUTO_RATE_GI_3200NS 11 + +#define AUTO_RATE_LDPC_DIS_BIT 16 + +#define SET_AUTO_RATE_SGI_VAL(set_val, bit_mask) \ + (set_val = (set_val & HE_LTF_ALL) | bit_mask) + +#define SET_AUTO_RATE_HE_LTF_VAL(set_val, bit_mask) \ + (set_val = (set_val & HE_SGI_MASK) | bit_mask) + +#define MSCS_OUI_TYPE "\x58" +#define MSCS_OUI_SIZE 1 + +#ifdef WLAN_FEATURE_11AX +#define HE_CAP_OUI_TYPE "\x23" +#define HE_CAP_OUI_SIZE 1 +#define HE_OP_OUI_TYPE "\x24" +#define HE_OP_OUI_SIZE 1 + +#define HE_RU_ALLOC_INDX0_MASK (0x01 << 0) +#define HE_RU_ALLOC_INDX1_MASK (0x01 << 1) +#define HE_RU_ALLOC_INDX2_MASK (0x01 << 2) +#define HE_RU_ALLOC_INDX3_MASK (0x01 << 3) + +/* 3 bits for NSS and 4 bits for RU Index */ +#define HE_PPET_NSS_LEN 3 +#define HE_PEPT_RU_IDX_LEN 4 +#define HE_PPET_NSS_RU_LEN (HE_PPET_NSS_LEN + HE_PEPT_RU_IDX_LEN) +#define HE_PPET_SIZE 3 +#define HE_BYTE_SIZE 8 + +struct ppet_hdr { + uint8_t nss:3; + uint8_t ru_idx_mask:4; + uint8_t remaining:1; +}; + +/* MAX PPET size = 7 bits + (max_nss X max_ru_number X 6) = 25 bytes */ +#define HE_MAX_PPET_SIZE WNI_CFG_HE_PPET_LEN + +#define HE_MAX_PHY_CAP_SIZE 3 + +#define HE_CH_WIDTH_GET_BIT(ch_wd, bit) (((ch_wd) >> (bit)) & 1) +#define HE_CH_WIDTH_COMBINE(b0, b1, b2, b3, b4, b5, b6) \ + ((uint8_t)(b0) | ((b1) << 1) | ((b2) << 2) | ((b3) << 3) | \ + ((b4) << 4) | ((b5) << 5) | ((b6) << 6)) +#define HE_CH_WIDTH_CLR_BIT(ch_wd, bit) (((ch_wd) >> (bit)) & ~1) + +/* + * MCS values are interpreted as in IEEE 11ax-D1.4 spec onwards + * +-----------------------------------------------------+ + * | SS8 | SS7 | SS6 | SS5 | SS4 | SS3 | SS2 | SS1 | + * +-----------------------------------------------------+ + * | 15-14 | 13-12 | 11-10 | 9-8 | 7-6 | 5-4 | 3-2 | 1-0 | + * +-----------------------------------------------------+ + */ +#define HE_MCS_NSS_SHIFT(nss) (((nss) - 1) << 1) +#define HE_MCS_MSK_4_NSS(nss) (3 << HE_MCS_NSS_SHIFT(nss)) +#define HE_MCS_INV_MSK_4_NSS(nss) (~HE_MCS_MSK_4_NSS(nss)) +#define HE_GET_MCS_4_NSS(mcs_set, nss) \ + (((mcs_set) >> HE_MCS_NSS_SHIFT(nss)) & 3) +#define HE_SET_MCS_4_NSS(mcs_set, mcs, nss) \ + (((mcs_set) & HE_MCS_INV_MSK_4_NSS(nss)) | \ + ((mcs) << HE_MCS_NSS_SHIFT(nss))) +#define HE_MCS_IS_NSS_ENABLED(mcs_set, nss) \ + ((HE_MCS_MSK_4_NSS(nss) & (mcs_set)) != HE_MCS_MSK_4_NSS(nss)) + +#define HE_MCS_ALL_DISABLED 0xFFFF + +#define HE_MCS_0_7 0x0 +#define HE_MCS_0_9 0x1 +#define HE_MCS_0_11 0x2 +#define HE_MCS_DISABLE 0x3 + +#define HE_6G_MIN_MPDU_START_SAPCE_BIT_POS 0 +#define HE_6G_MAX_AMPDU_LEN_EXP_BIT_POS 3 +#define HE_6G_MAX_MPDU_LEN_BIT_POS 6 +#define HE_6G_SMPS_BIT_POS 9 +#define HE_6G_RD_RESP_BIT_POS 11 +#define HE_6G_RX_ANT_PATTERN_BIT_POS 12 +#define HE_6G_TX_ANT_PATTERN_BIT_POS 13 + +/* + * Following formuala has been arrived at using karnaugh map and unit tested + * with sample code. Take MCS for each NSS as 2 bit value first and solve for + * 2 bit intersection of NSS. Use following table/Matrix as guide for solving + * K-Maps + * MCS 1\MCS 2 00 01 10 11 + * 00 00 00 00 11 + * 01 00 01 01 11 + * 10 00 01 10 11 + * 11 11 11 11 11 + * if output MCS is o1o0, then as per K-map reduction: + * o0 = m1.m0 | n1.n0 | (~m1).m0.(n1^n0) | (~n1).n0.(m1^m0) + * o1 = m1.m0 | n1.n0 | m1.(~m0).n1.(~n0) + * + * Please note: Calculating MCS intersection is 80211 protocol specific and + * should be implemented in PE. WMA can use this macro rather than calling any + * lim API to do the intersection. + */ +#define HE_INTERSECT_MCS_BITS_PER_NSS(m1, m0, n1, n0) \ + (((m1 & m0) | (n1 & n0) | (((~m1) & m0) & (n1 ^ n0)) | \ + (((~n1) & n0) & (m1 ^ m0))) | (((m1 & m0) | (n1 & n0) | \ + (m1 & ~m0 & n1 & ~n0)) << 1)) + +/* following takes MCS as 2 bits */ +#define HE_INTERSECT_MCS_PER_NSS(mcs_1, mcs_2) \ + HE_INTERSECT_MCS_BITS_PER_NSS((mcs_1 >> 1), (mcs_1 & 1), \ + (mcs_2 >> 1), (mcs_2 & 1)) + +/* following takes MCS as 16 bits */ +#define HE_INTERSECT_MCS(mcs_1, mcs_2) ( \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 1), \ + HE_GET_MCS_4_NSS(mcs_2, 1)) << HE_MCS_NSS_SHIFT(1) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 2), \ + HE_GET_MCS_4_NSS(mcs_2, 2)) << HE_MCS_NSS_SHIFT(2) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 3), \ + HE_GET_MCS_4_NSS(mcs_2, 3)) << HE_MCS_NSS_SHIFT(3) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 4), \ + HE_GET_MCS_4_NSS(mcs_2, 4)) << HE_MCS_NSS_SHIFT(4) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 5), \ + HE_GET_MCS_4_NSS(mcs_2, 5)) << HE_MCS_NSS_SHIFT(5) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 6), \ + HE_GET_MCS_4_NSS(mcs_2, 6)) << HE_MCS_NSS_SHIFT(6) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 7), \ + HE_GET_MCS_4_NSS(mcs_2, 7)) << HE_MCS_NSS_SHIFT(7) | \ + HE_INTERSECT_MCS_PER_NSS(HE_GET_MCS_4_NSS(mcs_1, 8), \ + HE_GET_MCS_4_NSS(mcs_2, 8)) << HE_MCS_NSS_SHIFT(8)) + +/** + * struct he_capability - to store 11ax HE capabilities + * @phy_cap: HE PHY capabilities + * @mac_cap: HE MAC capabilities + * @mcs: HE MCS + * @ppet: HE PPE threshold + */ +struct he_capability { + uint32_t phy_cap[HE_MAX_PHY_CAP_SIZE]; + uint32_t mac_cap; + uint32_t mcs; + struct wlan_psoc_host_ppe_threshold ppet; +}; +#endif + +#define HE_GET_NSS(mcs, nss) \ + do { \ + (nss) = 0; \ + while ((((mcs) >> ((nss)*2)) & 3) != 3 && nss < 8) \ + (nss)++; \ + } while (0) + +#ifdef WLAN_FEATURE_11BE +#define EHT_MAX_PHY_CAP_SIZE 3 +#define EHT_OP_OUI_TYPE "\x6a" +#define EHT_OP_OUI_SIZE 1 + +#define MLO_IE_OUI_TYPE "\x6b" +#define MLO_IE_OUI_SIZE 1 + +#define EHT_CAP_OUI_TYPE "\x6c" +#define EHT_CAP_OUI_SIZE 1 + +/** + * struct eht_capability - to store 11be EHT capabilities + * @phy_cap: EHT PHY capabilities + * @mac_cap: EHT MAC capabilities + * @mcs: EHT MCS + */ +struct eht_capability { + uint32_t phy_cap[EHT_MAX_PHY_CAP_SIZE]; + uint32_t mac_cap; + uint32_t mcs; +}; +#endif +/** + * struct rsp_stats - arp packet stats + * @arp_req_enqueue: fw tx count + * @arp_req_tx_success: tx ack count + * @arp_req_tx_failure: tx ack fail count + * @arp_rsp_recvd: rx fw count + * @out_of_order_arp_rsp_drop_cnt: out of order count + * @dad_detected: dad detected + * @connect_status: connection status + * @ba_session_establishment_status: BA session status + * @connect_stats_present: connectivity stats present or not + * @tcp_ack_recvd: tcp syn ack's count + * @icmpv4_rsp_recvd: icmpv4 responses count + */ +struct rsp_stats { + uint32_t vdev_id; + uint32_t arp_req_enqueue; + uint32_t arp_req_tx_success; + uint32_t arp_req_tx_failure; + uint32_t arp_rsp_recvd; + uint32_t out_of_order_arp_rsp_drop_cnt; + uint32_t dad_detected; + uint32_t connect_status; + uint32_t ba_session_establishment_status; + bool connect_stats_present; + uint32_t tcp_ack_recvd; + uint32_t icmpv4_rsp_recvd; +}; + +/** + * struct set_arp_stats_params - set/reset arp stats + * @vdev_id: session id + * @flag: enable/disable stats + * @pkt_type: type of packet(1 - arp) + * @ip_addr: subnet ipv4 address in case of encrypted packets + * @pkt_type_bitmap: pkt bitmap + * @tcp_src_port: tcp src port for pkt tracking + * @tcp_dst_port: tcp dst port for pkt tracking + * @icmp_ipv4: target ipv4 address to track ping packets + * @reserved: reserved + */ +struct set_arp_stats_params { + uint32_t vdev_id; + uint8_t flag; + uint8_t pkt_type; + uint32_t ip_addr; + uint32_t pkt_type_bitmap; + uint32_t tcp_src_port; + uint32_t tcp_dst_port; + uint32_t icmp_ipv4; + uint32_t reserved; +}; + +/** + * struct get_arp_stats_params - get arp stats from firmware + * @pkt_type: packet type(1 - ARP) + * @vdev_id: session id + */ +struct get_arp_stats_params { + uint8_t pkt_type; + uint32_t vdev_id; +}; + +typedef void (*sme_rcpi_callback)(void *context, struct qdf_mac_addr mac_addr, + int32_t rcpi, QDF_STATUS status); +/** + * struct sme_rcpi_req - structure for querying rcpi info + * @session_id: session for which rcpi is required + * @measurement_type: type of measurement from enum rcpi_measurement_type + * @rcpi_callback: callback function to be invoked for rcpi response + * @rcpi_context: context info for rcpi callback + * @mac_addr: peer addr for which rcpi is required + */ +struct sme_rcpi_req { + uint32_t session_id; + enum rcpi_measurement_type measurement_type; + sme_rcpi_callback rcpi_callback; + void *rcpi_context; + struct qdf_mac_addr mac_addr; +}; + +/* + * @SCAN_REJECT_DEFAULT: default value + * @CONNECTION_IN_PROGRESS: connection is in progress + * @REASSOC_IN_PROGRESS: reassociation is in progress + * @EAPOL_IN_PROGRESS: STA/P2P-CLI is in middle of EAPOL/WPS exchange + * @SAP_EAPOL_IN_PROGRESS: SAP/P2P-GO is in middle of EAPOL/WPS exchange + * @SAP_CONNECTION_IN_PROGRESS: SAP/P2P-GO is in middle of connection. + * @NAN_ENABLE_DISABLE_IN_PROGRESS: NAN is in middle of enable/disable discovery + */ +enum scan_reject_states { + SCAN_REJECT_DEFAULT = 0, + CONNECTION_IN_PROGRESS, + REASSOC_IN_PROGRESS, + EAPOL_IN_PROGRESS, + SAP_EAPOL_IN_PROGRESS, + SAP_CONNECTION_IN_PROGRESS, + NAN_ENABLE_DISABLE_IN_PROGRESS, +}; + +/** + * sir_sme_rx_aggr_hole_ind - sme rx aggr hole indication + * @hole_cnt: num of holes detected + * @hole_info_array: hole info + */ +struct sir_sme_rx_aggr_hole_ind { + uint32_t hole_cnt; + uint32_t hole_info_array[]; +}; + +/** + * struct sir_set_rx_reorder_timeout_val - rx reorder timeout + * @rx_timeout_pri: reorder timeout for AC + * rx_timeout_pri[0] : AC_VO + * rx_timeout_pri[1] : AC_VI + * rx_timeout_pri[2] : AC_BE + * rx_timeout_pri[3] : AC_BK + */ +struct sir_set_rx_reorder_timeout_val { + uint32_t rx_timeout_pri[4]; +}; + +/** + * struct sir_peer_set_rx_blocksize - set rx blocksize + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @rx_block_ack_win_limit: windows size limitation + */ +struct sir_peer_set_rx_blocksize { + uint32_t vdev_id; + struct qdf_mac_addr peer_macaddr; + uint32_t rx_block_ack_win_limit; +}; + +/** + * struct sir_rssi_disallow_lst - Structure holding Rssi based avoid candidate + * list + * @node: Node pointer + * @bssid: BSSID of the AP + * @retry_delay: Retry delay received during last rejection in ms + * @ expected_rssi: RSSI at which STA can initiate + * @time_during_rejection: Timestamp during last rejection in millisec + * @reject_reason: reason to add the BSSID to DLM + * @source: Source of adding the BSSID to DLM + * @original_timeout: original timeout sent by the AP + * @received_time: Timestamp when the AP was added to the Denylist + */ +struct sir_rssi_disallow_lst { + qdf_list_node_t node; + struct qdf_mac_addr bssid; + uint32_t retry_delay; + int8_t expected_rssi; + qdf_time_t time_during_rejection; + enum dlm_reject_ap_reason reject_reason; + enum dlm_reject_ap_source source; + uint32_t original_timeout; + qdf_time_t received_time; +}; + +/** + * struct chain_rssi_result - chain rssi result + * num_chains_valid: valid chain num + * @chain_rssi: chain rssi result as dBm unit + * @chain_evm: error vector magnitude + * @ant_id: antenna id + */ +#define CHAIN_MAX_NUM 8 +struct chain_rssi_result { + uint32_t num_chains_valid; + uint32_t chain_rssi[CHAIN_MAX_NUM]; + int32_t chain_evm[CHAIN_MAX_NUM]; + uint32_t ant_id[CHAIN_MAX_NUM]; +}; + +/** + * struct get_chain_rssi_req_params - get chain rssi req params + * @peer_macaddr: specific peer mac address + * @session_id: session id + */ +struct get_chain_rssi_req_params { + struct qdf_mac_addr peer_macaddr; + uint8_t session_id; +}; + +/* + * struct sir_limit_off_chan - limit off-channel command parameters + * @vdev_id: vdev id + * @is_tos_active: status of the traffic (active/inactive) + * @max_off_chan_time: max allowed off channel time + * @rest_time: home channel time + * @skip_dfs_chans: skip dfs channels during scan + */ +struct sir_limit_off_chan { + uint8_t vdev_id; + bool is_tos_active; + uint32_t max_off_chan_time; + uint32_t rest_time; + bool skip_dfs_chans; +}; + +typedef void (*roam_scan_stats_cb)(void *context, + struct wmi_roam_scan_stats_res *res); + +/** + * struct sir_roam_scan_stats - Stores roam scan context + * @vdev_id: vdev id + * @cb: callback to be invoked for roam scan stats response + * @context: context of callback + */ +struct sir_roam_scan_stats { + uint32_t vdev_id; + roam_scan_stats_cb cb; + void *context; +}; + +/** + * struct sae_info - SAE info used for commit/confirm messages + * @msg_type: Message type + * @msg_len: length of message + * @vdev_id: vdev id + * @peer_mac_addr: peer MAC address + * @ssid: SSID + * @akm: key mgmt suite used + */ +struct sir_sae_info { + uint16_t msg_type; + uint16_t msg_len; + uint32_t vdev_id; + struct qdf_mac_addr peer_mac_addr; + tSirMacSSid ssid; + uint32_t akm; +}; + +/** + * struct sir_sae_msg - SAE msg used for message posting + * @message_type: message type + * @length: message length + * @vdev_id: vdev id + * @sae_status: SAE status, 0: Success, Non-zero: Failure. + * @pmkid: PMKID derived as part of SAE authentication + * @peer_mac_addr: peer MAC address + * @result_code: This carries the reason of the SAE auth failure. + * Currently, SAE authentication failure may happen due to + * 1. Authentication failure detected as part of SAE auth frame + * exchanges and validation. + * 2. Deauth received from AP while SAE authentication is in + * progress. + */ +struct sir_sae_msg { + uint16_t message_type; + uint16_t length; + uint16_t vdev_id; + uint8_t pmkid[PMKID_LEN]; + uint8_t sae_status; + tSirMacAddr peer_mac_addr; + tSirResultCodes result_code; +}; + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * struct sir_md_evt - motion detection event status + * @vdev_id: vdev id + * @status: md event status + */ +struct sir_md_evt { + uint8_t vdev_id; + uint32_t status; +}; + +/** + * struct sir_md_bl_evt - motion detection baseline event values + * @vdev_id: vdev id + * @bl_baseline_value: baseline correlation value calculated during baselining + * @bl_max_corr_reserved: max corr value obtained during baselining phase in % + * @bl_min_corr_reserved: min corr value obtained during baselining phase in % + */ +struct sir_md_bl_evt { + uint8_t vdev_id; + uint32_t bl_baseline_value; + uint32_t bl_max_corr_reserved; + uint32_t bl_min_corr_reserved; +}; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +#ifdef WLAN_MWS_INFO_DEBUGFS +/** + * struct sir_get_mws_coex_info - Get MWS coex info + * @vdev_id: vdev id + * @cmd_id: wmi mws-coex command IDs + */ +struct sir_get_mws_coex_info { + uint32_t vdev_id; + uint32_t cmd_id; +}; +#endif /* WLAN_MWS_INFO_DEBUGFS */ + +/* + * struct sir_update_session_txq_edca_param + * @message_type: SME message type + * @length: size of struct sir_update_session_txq_edca_param + * @vdev_id: vdev ID + * @txq_edca_params: txq edca parameter to update + */ +struct sir_update_session_txq_edca_param { + uint16_t message_type; + uint16_t length; + uint8_t vdev_id; + tSirMacEdcaParamRecord txq_edca_params; +}; + +/* struct channel_change_req - Change channel + * request for SAP + * @vdev_id: vdev id + * @target_chan_freq: New channel frequency + * @sec_ch_offset: second channel offset + * @center_freq_seg0: channel center freq 0 + * @center_freq_seg1: channel center freq 1 + * @target_punc_bitmap: New channel puncturing bitmap + * @dot11mode: dot11 mode + * @nw_type: nw type + * @cac_duration_ms: cac duration in ms + * @dfs_regdomain: dfs regdomain + * @opr_rates: operational rates + * @ext_rates: extended rates + */ +struct channel_change_req { + uint8_t vdev_id; + uint32_t target_chan_freq; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; +#ifdef WLAN_FEATURE_11BE + uint16_t target_punc_bitmap; +#endif + uint32_t dot11mode; + tSirNwType nw_type; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; + tSirMacRateSet opr_rates; + tSirMacRateSet ext_rates; +}; + +/* struct start_bss_config - Start BSS + * request configurations + * @vdev_id: vdev id + * @cmd_id: serialization command id + * @ssId: ssid + * @dtimPeriod: dtim period + * @ssidHidden: hidden ssid parameter + * @privacy: ssid privacy + * @authType: authentication type + * @rsnIE: RSN IE of the AP + * @add_ie_params: additional IEs + * @oper_ch_freq: operating frequency + * @vht_channel_width: channel width + * @center_freq_seg0: channel center freq 0 + * @center_freq_seg1: channel center freq 1 + * @sec_ch_offset: secondary channel offset + * @wps_state: wps config + * @dot11mode: dot11 mode + * @nwType: nw type + * @operationalRateSet: operational rates + * @extendedRateSet: extended rates + * @beacon_tx_rate: Tx rate for beacon + * @cac_duration_ms: cac duration in ms + * @dfs_regdomain: dfs regdomain + */ +struct start_bss_config { + uint8_t vdev_id; + uint32_t cmd_id; + tSirMacSSid ssId; + uint16_t beaconInterval; + uint32_t dtimPeriod; + uint8_t ssidHidden; + + uint8_t privacy; + tAniAuthType authType; + tSirRSNie rsnIE; + struct add_ie_params add_ie_params; + + uint32_t oper_ch_freq; + uint8_t vht_channel_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + uint8_t sec_ch_offset; + + uint8_t wps_state; + uint8_t dot11mode; + tSirNwType nwType; + + tSirMacRateSet operationalRateSet; + tSirMacRateSet extendedRateSet; + uint16_t beacon_tx_rate; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +}; + +#endif /* __SIR_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h new file mode 100644 index 0000000000..5ff941bc6f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_mac_prop_exts.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2011-2015, 2017-2019, 2021 The Linux Foundation. + * All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sir_mac_prop_exts.h contains the MAC protocol + * extensions to support ANI feature set. + * Author: Chandra Modumudi + * Date: 11/27/02 + */ +#ifndef __MAC_PROP_EXTS_H +#define __MAC_PROP_EXTS_H + +#include "sir_types.h" +#include "sir_api.h" +#include "ani_system_defs.h" + +/* / EID (Element ID) definitions */ + +#define PROP_CAPABILITY_GET(bitname, value) \ + (((value) >> SIR_MAC_PROP_CAPABILITY_ ## bitname) & 1) + +#define IS_DOT11_MODE_HT(dot11Mode) \ + (((dot11Mode == MLME_DOT11_MODE_11N) || \ + (dot11Mode == MLME_DOT11_MODE_11N_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_11AC) || \ + (dot11Mode == MLME_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_11AX) || \ + (dot11Mode == MLME_DOT11_MODE_11AX_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_11BE) || \ + (dot11Mode == MLME_DOT11_MODE_11BE_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_VHT(dot11Mode) \ + (((dot11Mode == MLME_DOT11_MODE_11AC) || \ + (dot11Mode == MLME_DOT11_MODE_11AC_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_11AX) || \ + (dot11Mode == MLME_DOT11_MODE_11AX_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_11BE) || \ + (dot11Mode == MLME_DOT11_MODE_11BE_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_HE(dot11Mode) \ + (((dot11Mode == MLME_DOT11_MODE_11AX) || \ + (dot11Mode == MLME_DOT11_MODE_11AX_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_11BE) || \ + (dot11Mode == MLME_DOT11_MODE_11BE_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_EHT(dot11Mode) \ + (((dot11Mode == MLME_DOT11_MODE_11BE) || \ + (dot11Mode == MLME_DOT11_MODE_11BE_ONLY) || \ + (dot11Mode == MLME_DOT11_MODE_ALL)) ? true:false) + +#define IS_DOT11_MODE_11B(dot11Mode) \ + ((dot11Mode == MLME_DOT11_MODE_11B) ? true:false) + +#define IS_BSS_VHT_CAPABLE(vhtCaps) \ + ((vhtCaps).present && \ + ((vhtCaps).rxMCSMap != 0xFFFF) && \ + ((vhtCaps).txMCSMap != 0xFFFF)) + +#define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ 0 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ 1 +#define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ 2 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3 + +#ifdef WLAN_FEATURE_11BE +#define WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ 4 +#endif + +#endif /* __MAC_PROP_EXTS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h new file mode 100644 index 0000000000..c5b25746b0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_mac_prot_def.h @@ -0,0 +1,1996 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file sir_mac_prot_def.h contains the MAC/PHY protocol + * definitions used across various projects. + */ + +#ifndef __MAC_PROT_DEFS_H +#define __MAC_PROT_DEFS_H + +#include + +#include "cds_api.h" +#include "sir_types.h" +#include "wni_cfg.h" +#include + +/* /Capability information related */ +#define CAPABILITY_INFO_DELAYED_BA_BIT 14 +#define CAPABILITY_INFO_IMMEDIATE_BA_BIT 15 + +/* / 11h MAC defaults */ +#define SIR_11A_CHANNEL_BEGIN 34 +#define SIR_11A_CHANNEL_END 165 +#define SIR_11B_CHANNEL_BEGIN 1 +#define SIR_11B_CHANNEL_END 14 +#define SIR_11A_FREQUENCY_OFFSET 4 +#define SIR_11B_FREQUENCY_OFFSET 1 +#define SIR_11P_CHANNEL_BEGIN 170 +#define SIR_11P_CHANNEL_END 184 + +/* / Current version of 802.11 */ +#define SIR_MAC_PROTOCOL_VERSION 0 + +/* Frame Type definitions */ + +#define SIR_MAC_MGMT_FRAME 0x0 +#define SIR_MAC_CTRL_FRAME 0x1 +#define SIR_MAC_DATA_FRAME 0x2 + +/* Data frame subtype definitions */ +#define SIR_MAC_DATA_DATA 0 +#define SIR_MAC_DATA_DATA_ACK 1 +#define SIR_MAC_DATA_DATA_POLL 2 +#define SIR_MAC_DATA_DATA_ACK_POLL 3 +#define SIR_MAC_DATA_NULL 4 +#define SIR_MAC_DATA_NULL_ACK 5 +#define SIR_MAC_DATA_NULL_POLL 6 +#define SIR_MAC_DATA_NULL_ACK_POLL 7 +#define SIR_MAC_DATA_QOS_DATA 8 +#define SIR_MAC_DATA_QOS_DATA_ACK 9 +#define SIR_MAC_DATA_QOS_DATA_POLL 10 +#define SIR_MAC_DATA_QOS_DATA_ACK_POLL 11 +#define SIR_MAC_DATA_QOS_NULL 12 +#define SIR_MAC_DATA_QOS_NULL_ACK 13 +#define SIR_MAC_DATA_QOS_NULL_POLL 14 +#define SIR_MAC_DATA_QOS_NULL_ACK_POLL 15 + +#define SIR_MAC_DATA_QOS_MASK 8 +#define SIR_MAC_DATA_NULL_MASK 4 +#define SIR_MAC_DATA_POLL_MASK 2 +#define SIR_MAC_DATA_ACK_MASK 1 + +/* Management frame subtype definitions */ + +#define SIR_MAC_MGMT_ASSOC_REQ 0x0 +#define SIR_MAC_MGMT_ASSOC_RSP 0x1 +#define SIR_MAC_MGMT_REASSOC_REQ 0x2 +#define SIR_MAC_MGMT_REASSOC_RSP 0x3 +#define SIR_MAC_MGMT_PROBE_REQ 0x4 +#define SIR_MAC_MGMT_PROBE_RSP 0x5 +#define SIR_MAC_MGMT_TIME_ADVERT 0x6 +#define SIR_MAC_MGMT_BEACON 0x8 +#define SIR_MAC_MGMT_ATIM 0x9 +#define SIR_MAC_MGMT_DISASSOC 0xA +#define SIR_MAC_MGMT_AUTH 0xB +#define SIR_MAC_MGMT_DEAUTH 0xC +#define SIR_MAC_MGMT_ACTION 0xD +#define SIR_MAC_MGMT_RESERVED15 0xF + +#define SIR_MAC_ACTION_TX 1 + +#define SIR_MAC_BA_POLICY_IMMEDIATE 1 +#define SIR_MAC_BA_DEFAULT_BUFF_SIZE 64 + +#define MAX_BA_BUFF_SIZE 256 +#define MAX_EHT_BA_BUFF_SIZE 1024 + +#ifdef ANI_SUPPORT_11H +#define SIR_MAC_BASIC_MEASUREMENT_TYPE 0 +#define SIR_MAC_CCA_MEASUREMENT_TYPE 1 +#define SIR_MAC_RPI_MEASUREMENT_TYPE 2 +#endif /* ANI_SUPPORT_11H */ + +/* RRM related. */ +/* Refer IEEE Std 802.11k-2008, Section 7.3.2.21, table 7.29 */ +#define SIR_MAC_RRM_CHANNEL_LOAD_TYPE 3 +#define SIR_MAC_RRM_NOISE_HISTOGRAM_BEACON 4 +#define SIR_MAC_RRM_BEACON_TYPE 5 +#define SIR_MAC_RRM_FRAME_TYPE 6 +#define SIR_MAC_RRM_STA_STATISTICS_TYPE 7 +#define SIR_MAC_RRM_LCI_TYPE 8 +#define SIR_MAC_RRM_TSM_TYPE 9 +#define SIR_MAC_RRM_LOCATION_CIVIC_TYPE 11 +#define SIR_MAC_RRM_FINE_TIME_MEAS_TYPE 16 + +#define SIR_MAC_VHT_OPMODE_SIZE 3 + +#define NUM_OF_SOUNDING_DIMENSIONS 1 /*Nss - 1, (Nss = 2 for 2x2)*/ + +/* ----------------------------------------------------------------------------- */ +/* EID (Element ID) definitions */ +/* and their min/max lengths */ +/* ----------------------------------------------------------------------------- */ + +#define SIR_MAC_TIM_EID_MIN 3 + +#define SIR_MAC_WPA_EID 221 + +#define SIR_MAC_MAX_SUPPORTED_MCS_SET 16 + +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1 390 +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2 780 + +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1_SGI80 433 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1_SGI80 433 +#define VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_2_2_SGI80 866 +#define VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_2_2_SGI80 866 + +#define VHT_CAP_NO_160M_SUPP 0 +#define VHT_CAP_160_SUPP 1 +#define VHT_CAP_160_AND_80P80_SUPP 2 + +#define VHT_NO_EXTD_NSS_BW_SUPP 0 +#define VHT_EXTD_NSS_80_HALF_NSS_160 1 +#define VHT_EXTD_NSS_80_HALF_NSS_80P80 2 +#define VHT_EXTD_NSS_80_3QUART_NSS_80P80 3 +#define VHT_EXTD_NSS_160_HALF_NSS_80P80 1 +#define VHT_EXTD_NSS_160_3QUART_NSS_80P80 2 +#define VHT_EXTD_NSS_2X_NSS_160_1X_NSS_80P80 3 +#define VHT_EXTD_NSS_2X_NSS_80_1X_NSS_80P80 3 + +#define VHT_MAX_NSS 8 + +#define VHT_MCS_1x1 0xFFFC +#define VHT_MCS_2x2 0xFFF3 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define SIR_MAC_QCOM_VENDOR_EID 200 +#define SIR_MAC_QCOM_VENDOR_OUI "\x00\xA0\xC6" +#define SIR_MAC_QCOM_VENDOR_SIZE 3 +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#define SIR_MAC_MAX_ADD_IE_LENGTH 2048 + +/* / Minimum length of each IE */ +#define SIR_MAC_RSN_IE_MIN_LENGTH 2 +#define SIR_MAC_WPA_IE_MIN_LENGTH 6 + +#ifdef FEATURE_WLAN_ESE +#define ESE_VERSION_4 4 +#define ESE_VERSION_SUPPORTED ESE_VERSION_4 + +/* When station sends Radio Management Cap. */ +/* State should be normal=1 */ +/* Mbssid Mask should be 0 */ +#define RM_STATE_NORMAL 1 +#endif + +#define SIR_MAC_OUI_VERSION_1 1 + +/* OWE DH Parameter element https://tools.ietf.org/html/rfc8110 */ +#define SIR_DH_PARAMETER_ELEMENT_EXT_EID 32 + +#define SIR_MSCS_ELEMENT_EXT_EID 88 + +/* OUI and type definition for WPA IE in network byte order */ +#define SIR_MAC_WPA_OUI 0x01F25000 +#define SIR_MAC_WSC_OUI "\x00\x50\xf2\x04" +#define SIR_MAC_WSC_OUI_SIZE 4 +#define SIR_MAC_P2P_OUI "\x50\x6f\x9a\x09" +#define SIR_MAC_P2P_OUI_SIZE 4 +#define SIR_P2P_NOA_ATTR 12 +#define SIR_MAX_NOA_ATTR_LEN 31 +#define SIR_P2P_IE_HEADER_LEN 6 + +#define SIR_MAC_CISCO_OUI "\x00\x40\x96" +#define SIR_MAC_CISCO_OUI_SIZE 3 + +#define SIR_MAC_QCN_OUI_TYPE "\x8c\xfd\xf0\x01" +#define SIR_MAC_QCN_OUI_TYPE_SIZE 4 + +/* MBO OUI definitions */ +#define SIR_MAC_MBO_OUI "\x50\x6f\x9a\x16" +#define SIR_MAC_MBO_OUI_SIZE 4 +#define SIR_MBO_ELEM_OFFSET (2 + SIR_MAC_MBO_OUI_SIZE) + +/* min size of wme oui header: oui(3) + type + subtype + version */ +#define SIR_MAC_OUI_WME_HDR_MIN 6 + +/* ----------------------------------------------------------------------------- */ + +/* OFFSET definitions for fixed fields in Management frames */ + +/* Beacon/Probe Response offsets */ +#define SIR_MAC_B_PR_CAPAB_OFFSET 10 +#define SIR_MAC_B_PR_SSID_OFFSET 12 + +/* Association/Reassociation offsets */ +#define SIR_MAC_REASSOC_REQ_SSID_OFFSET 10 +#define SIR_MAC_ASSOC_RSP_STATUS_CODE_OFFSET 2 + +/* Association Request offsets */ +#define SIR_MAC_ASSOC_REQ_SSID_OFFSET 4 + +/* / Transaction sequence number definitions (used in Authentication frames) */ +#define SIR_MAC_AUTH_FRAME_1 1 +#define SIR_MAC_AUTH_FRAME_2 2 +#define SIR_MAC_AUTH_FRAME_3 3 +#define SIR_MAC_AUTH_FRAME_4 4 + +/* / Protocol defined MAX definitions */ +#define SIR_MAC_MAX_NUMBER_OF_RATES 12 +#define SIR_MAC_KEY_LENGTH 13 /* WEP Maximum key length size */ +#define SIR_MAC_AUTH_CHALLENGE_LENGTH 253 +#define SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH 128 +#define SIR_MAC_WEP_IV_LENGTH 4 +#define SIR_MAC_WEP_ICV_LENGTH 4 +#define SIR_MAC_CHALLENGE_ID_LEN 2 + +/* 2 bytes each for auth algo number, transaction number and status code */ +#define SIR_MAC_AUTH_FRAME_INFO_LEN 6 +/* 2 bytes for ID and length + SIR_MAC_AUTH_CHALLENGE_LENGTH */ +#define SIR_MAC_AUTH_CHALLENGE_BODY_LEN (SIR_MAC_CHALLENGE_ID_LEN + \ + SIR_MAC_AUTH_CHALLENGE_LENGTH) + +/* / MAX key length when ULA is used */ +#define SIR_MAC_MAX_KEY_LENGTH 32 + +/* / Macro definitions for get/set on FC fields */ +#define SIR_MAC_GET_PROT_VERSION(x) ((((uint16_t) x) & 0x0300) >> 8) +#define SIR_MAC_GET_FRAME_TYPE(x) ((((uint16_t) x) & 0x0C00) >> 8) +#define SIR_MAC_GET_FRAME_SUB_TYPE(x) ((((uint16_t) x) & 0xF000) >> 12) +#define SIR_MAC_GET_WEP_BIT_IN_FC(x) (((uint16_t) x) & 0x0040) +#define SIR_MAC_SET_PROT_VERSION(x) ((uint16_t) x) +#define SIR_MAC_SET_FRAME_TYPE(x) (((uint16_t) x) << 2) +#define SIR_MAC_SET_FRAME_SUB_TYPE(x) (((uint16_t) x) << 4) +#define SIR_MAC_SET_WEP_BIT_IN_FC(x) (((uint16_t) x) << 14) + +/* / Macro definitions for get/set on capabilityInfo bits */ +#define SIR_MAC_GET_ESS(x) (((uint16_t) x) & 0x0001) +#define SIR_MAC_GET_IBSS(x) ((((uint16_t) x) & 0x0002) >> 1) +#define SIR_MAC_GET_CF_POLLABLE(x) ((((uint16_t) x) & 0x0004) >> 2) +#define SIR_MAC_GET_CF_POLL_REQ(x) ((((uint16_t) x) & 0x0008) >> 3) +#define SIR_MAC_GET_PRIVACY(x) ((((uint16_t) x) & 0x0010) >> 4) +#define SIR_MAC_GET_SHORT_PREAMBLE(x) ((((uint16_t) x) & 0x0020) >> 5) +#define SIR_MAC_GET_SPECTRUM_MGMT(x) ((((uint16_t) x) & 0x0100) >> 8) +#define SIR_MAC_GET_QOS(x) ((((uint16_t) x) & 0x0200) >> 9) +#define SIR_MAC_GET_SHORT_SLOT_TIME(x) ((((uint16_t) x) & 0x0400) >> 10) +#define SIR_MAC_GET_APSD(x) ((((uint16_t) x) & 0x0800) >> 11) +#define SIR_MAC_GET_RRM(x) ((((uint16_t) x) & 0x1000) >> 12) +#define SIR_MAC_GET_BLOCK_ACK(x) ((((uint16_t) x) & 0xc000) >> CAPABILITY_INFO_DELAYED_BA_BIT) +#define SIR_MAC_SET_ESS(x) (((uint16_t) x) | 0x0001) +#define SIR_MAC_SET_IBSS(x) (((uint16_t) x) | 0x0002) +#define SIR_MAC_SET_CF_POLLABLE(x) (((uint16_t) x) | 0x0004) +#define SIR_MAC_SET_CF_POLL_REQ(x) (((uint16_t) x) | 0x0008) +#define SIR_MAC_SET_PRIVACY(x) (((uint16_t) x) | 0x0010) +#define SIR_MAC_SET_SHORT_PREAMBLE(x) (((uint16_t) x) | 0x0020) +#define SIR_MAC_SET_SPECTRUM_MGMT(x) (((uint16_t) x) | 0x0100) +#define SIR_MAC_SET_QOS(x) (((uint16_t) x) | 0x0200) +#define SIR_MAC_SET_SHORT_SLOT_TIME(x) (((uint16_t) x) | 0x0400) +#define SIR_MAC_SET_APSD(x) (((uint16_t) x) | 0x0800) +#define SIR_MAC_SET_RRM(x) (((uint16_t) x) | 0x1000) +#define SIR_MAC_SET_GROUP_ACK(x) (((uint16_t) x) | 0x4000) + +#define SIR_MAC_GET_VHT_MAX_AMPDU_EXPO(x) ((((uint32_t) x) & 0x03800000) >> 23) + +/* bitname must be one of the above, eg ESS, CF_POLLABLE, etc. */ +#define SIR_MAC_CLEAR_CAPABILITY(u16value, bitname) \ + ((u16value) &= (~(SIR_MAC_SET_ ## bitname(0)))) + +#define IS_WES_MODE_ENABLED(x) \ + ((x)->mlme_cfg->lfr.wes_mode_enabled) + +#define SIR_MAC_VENDOR_AP_1_OUI "\x00\x0C\x43" +#define SIR_MAC_VENDOR_AP_1_OUI_LEN 3 + +#define SIR_MAC_VENDOR_AP_3_OUI "\x00\x03\x7F" +#define SIR_MAC_VENDOR_AP_3_OUI_LEN 3 + +#define SIR_MAC_VENDOR_AP_4_OUI "\x8C\xFD\xF0" +#define SIR_MAC_VENDOR_AP_4_OUI_LEN 3 + +#define SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI "\x00\x14\x6C" +#define SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI_LEN 3 + +#define SIR_MAC_BAD_HTC_HE_VENDOR_OUI1 "\x00\x50\xF2\x11" +#define SIR_MAC_BAD_HTC_HE_VENDOR_OUI2 "\x00\x50\xF2\x12" +#define SIR_MAC_BAD_HTC_HE_VENDOR_OUI_LEN 4 + +/* Maximum allowable size of a beacon,probe rsp and fils discovery frame */ +#define SIR_MAX_BEACON_SIZE 512 +#define SIR_MAX_PROBE_RESP_SIZE 512 +#define SIR_MAX_FD_TMPL_SIZE 512 + + +/* / Frame control field format (2 bytes) */ +typedef struct sSirMacFrameCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t subType:4; + uint8_t type:2; + uint8_t protVer:2; + + uint8_t order:1; + uint8_t wep:1; + uint8_t moreData:1; + uint8_t powerMgmt:1; + uint8_t retry:1; + uint8_t moreFrag:1; + uint8_t fromDS:1; + uint8_t toDS:1; + +#else + + uint8_t protVer:2; + uint8_t type:2; + uint8_t subType:4; + + uint8_t toDS:1; + uint8_t fromDS:1; + uint8_t moreFrag:1; + uint8_t retry:1; + uint8_t powerMgmt:1; + uint8_t moreData:1; + uint8_t wep:1; + uint8_t order:1; + +#endif + +} qdf_packed tSirMacFrameCtl, *tpSirMacFrameCtl; + +/* / Sequence control field */ +typedef struct sSirMacSeqCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t seqNumLo:4; + uint8_t fragNum:4; + + uint8_t seqNumHi:8; + +#else + + uint8_t fragNum:4; + uint8_t seqNumLo:4; + uint8_t seqNumHi:8; + +#endif +} qdf_packed tSirMacSeqCtl, *tpSirMacSeqCtl; + +/* / QoS control field */ +typedef struct sSirMacQosCtl { + +#ifndef ANI_LITTLE_BIT_ENDIAN + + uint8_t rsvd:1; + uint8_t ackPolicy:2; + uint8_t esop_txopUnit:1; + uint8_t tid:4; + + uint8_t txop:8; + +#else + + uint8_t tid:4; + uint8_t esop_txopUnit:1; + uint8_t ackPolicy:2; + uint8_t rsvd:1; + + uint8_t txop:8; + +#endif +} qdf_packed tSirMacQosCtl, *tpSirMacQosCtl; + +/* / Length (in bytes) of MAC header in 3 address format */ +#define SIR_MAC_HDR_LEN_3A 24 + +typedef uint8_t tSirMacAddr[ETH_ALEN]; + +/* / 3 address MAC data header format (24/26 bytes) */ +typedef struct sSirMacDot3Hdr { + tSirMacAddr da; + tSirMacAddr sa; + uint16_t length; +} qdf_packed tSirMacDot3Hdr, *tpSirMacDot3Hdr; + +/* / 3 address MAC data header format (24/26 bytes) */ +typedef struct sSirMacDataHdr3a { + tSirMacFrameCtl fc; + uint8_t durationLo; + uint8_t durationHi; + tSirMacAddr addr1; + tSirMacAddr addr2; + tSirMacAddr addr3; + tSirMacSeqCtl seqControl; + tSirMacQosCtl qosControl; +} qdf_packed tSirMacDataHdr3a, *tpSirMacDataHdr3a; + +/* / Management header format */ +typedef struct sSirMacMgmtHdr { + tSirMacFrameCtl fc; + uint8_t durationLo; + uint8_t durationHi; + tSirMacAddr da; + tSirMacAddr sa; + tSirMacAddr bssId; + tSirMacSeqCtl seqControl; +} qdf_packed tSirMacMgmtHdr, *tpSirMacMgmtHdr; + +/* / ERP information field */ +typedef struct sSirMacErpInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:5; + uint8_t barkerPreambleMode:1; + uint8_t useProtection:1; + uint8_t nonErpPresent:1; +#else + uint8_t nonErpPresent:1; + uint8_t useProtection:1; + uint8_t barkerPreambleMode:1; + uint8_t reserved:5; +#endif +} qdf_packed tSirMacErpInfo, *tpSirMacErpInfo; + +/* / Capability information field */ +typedef struct sSirMacCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t immediateBA:1; + uint16_t delayedBA:1; + uint16_t dsssOfdm:1; + uint16_t rrm:1; + uint16_t apsd:1; + uint16_t shortSlotTime:1; + uint16_t qos:1; + uint16_t spectrumMgt:1; + uint16_t channelAgility:1; + uint16_t criticalUpdateFlag:1; + uint16_t shortPreamble:1; + uint16_t privacy:1; + uint16_t cfPollReq:1; + uint16_t cfPollable:1; + uint16_t ibss:1; + uint16_t ess:1; +#else + uint16_t ess:1; + uint16_t ibss:1; + uint16_t cfPollable:1; + uint16_t cfPollReq:1; + uint16_t privacy:1; + uint16_t shortPreamble:1; + uint16_t criticalUpdateFlag:1; + uint16_t channelAgility:1; + uint16_t spectrumMgt:1; + uint16_t qos:1; + uint16_t shortSlotTime:1; + uint16_t apsd:1; + uint16_t rrm:1; + uint16_t dsssOfdm:1; + uint16_t delayedBA:1; + uint16_t immediateBA:1; +#endif +} qdf_packed tSirMacCapabilityInfo, *tpSirMacCapabilityInfo; + +typedef struct sSirMacCfParamSet { + uint8_t cfpCount; + uint8_t cfpPeriod; + uint16_t cfpMaxDuration; + uint16_t cfpDurRemaining; +} qdf_packed tSirMacCfParamSet; + +typedef struct sSirMacTim { + uint8_t dtimCount; + uint8_t dtimPeriod; + uint8_t bitmapControl; + uint8_t bitmapLength; + uint8_t bitmap[251]; +} qdf_packed tSirMacTim; + +/* 12 Bytes long because this structure can be used to represent rate */ +/* and extended rate set IEs */ +/* The parser assume this to be at least 12 */ +typedef struct sSirMacRateSet { + uint8_t numRates; + uint8_t rate[SIR_MAC_MAX_NUMBER_OF_RATES]; +} qdf_packed tSirMacRateSet; + +/** struct merged_mac_rate_set - merged mac rate set + * @num_rates: num of rates + * @rate: rate list + */ +struct merged_mac_rate_set { + uint8_t num_rates; + uint8_t rate[2 * WLAN_SUPPORTED_RATES_IE_MAX_LEN]; +}; + +/* Reserve 1 byte for NULL character in the SSID name field to print in %s */ +typedef struct sSirMacSSid { + uint8_t length; + uint8_t ssId[WLAN_SSID_MAX_LEN +1]; +} qdf_packed tSirMacSSid; + +typedef struct sSirMacWpaInfo { + uint8_t length; + uint8_t info[WLAN_MAX_IE_LEN]; +} qdf_packed tSirMacWpaInfo, *tpSirMacWpaInfo, +tSirMacRsnInfo, *tpSirMacRsnInfo; + +typedef struct sSirMacWapiInfo { + uint8_t length; + uint8_t info[WLAN_MAX_IE_LEN]; +} qdf_packed tSirMacWapiInfo, *tpSirMacWapiInfo; + +typedef struct sSirMacFHParamSet { + uint16_t dwellTime; + uint8_t hopSet; + uint8_t hopPattern; + uint8_t hopIndex; +} tSirMacFHParamSet, *tpSirMacFHParamSet; + +typedef struct sSirMacIBSSParams { + uint16_t atim; +} tSirMacIBSSParams, *tpSirMacIBSSParams; + +typedef struct sSirMacRRMEnabledCap { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:6; + uint8_t AntennaInformation:1; + uint8_t BSSAvailAdmission:1; + uint8_t BssAvgAccessDelay:1; + uint8_t RSNIMeasurement:1; + uint8_t RCPIMeasurement:1; + uint8_t NeighborTSFOffset:1; + uint8_t MeasurementPilotEnabled:1; + uint8_t MeasurementPilot:3; + uint8_t nonOperatinChanMax:3; + uint8_t operatingChanMax:3; + uint8_t RRMMIBEnabled:1; + uint8_t APChanReport:1; + uint8_t triggeredTCM:1; + uint8_t TCMCapability:1; + uint8_t LCIAzimuth:1; + uint8_t LCIMeasurement:1; + uint8_t statistics:1; + uint8_t NoiseHistogram:1; + uint8_t ChannelLoad:1; + uint8_t FrameMeasurement:1; + uint8_t BeaconRepCond:1; + uint8_t BeaconTable:1; + uint8_t BeaconActive:1; + uint8_t BeaconPassive:1; + uint8_t repeated:1; + uint8_t parallel:1; + uint8_t NeighborRpt:1; + uint8_t LinkMeasurement:1; + uint8_t present; +#else + uint8_t present; + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatinChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t reserved:6; +#endif +} tSirMacRRMEnabledCap, *tpSirMacRRMEnabledCap; + +#define MU_EDCA_DEF_AIFSN 0 +#define MU_EDCA_DEF_CW_MAX 15 +#define MU_EDCA_DEF_CW_MIN 15 +#define MU_EDCA_DEF_TIMER 255 +/* access category record */ +typedef struct sSirMacAciAifsn { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t rsvd:1; + uint8_t aci:2; + uint8_t acm:1; + uint8_t aifsn:4; +#else + uint8_t aifsn:4; + uint8_t acm:1; + uint8_t aci:2; + uint8_t rsvd:1; +#endif +} qdf_packed tSirMacAciAifsn; + +/* contention window size */ +typedef struct sSirMacCW { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t max:4; + uint8_t min:4; +#else + uint8_t min:4; + uint8_t max:4; +#endif +} qdf_packed tSirMacCW; + +typedef struct sSirMacEdcaParamRecord { + tSirMacAciAifsn aci; + tSirMacCW cw; + union { + uint16_t txoplimit; + uint16_t mu_edca_timer; + }; + uint8_t no_ack; +} qdf_packed tSirMacEdcaParamRecord; + +typedef struct sSirMacQosInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t uapsd:1; + uint8_t txopreq:1; + uint8_t qreq:1; + uint8_t qack:1; + uint8_t count:4; +#else + uint8_t count:4; + uint8_t qack:1; + uint8_t qreq:1; + uint8_t txopreq:1; + uint8_t uapsd:1; +#endif +} qdf_packed tSirMacQosInfo; + +typedef struct sSirMacQosInfoStation { +#ifdef ANI_LITTLE_BIT_ENDIAN + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t qack:1; + uint8_t maxSpLen:2; + uint8_t moreDataAck:1; +#else + uint8_t moreDataAck:1; + uint8_t maxSpLen:2; + uint8_t qack:1; + uint8_t acbe_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acvo_uapsd:1; +#endif +} qdf_packed tSirMacQosInfoStation, *tpSirMacQosInfoStation; + +typedef struct sSirMacEdcaParamSetIE { + uint8_t type; + uint8_t length; + tSirMacQosInfo qosInfo; + uint8_t rsvd; + tSirMacEdcaParamRecord acbe; /* best effort */ + tSirMacEdcaParamRecord acbk; /* background */ + tSirMacEdcaParamRecord acvi; /* video */ + tSirMacEdcaParamRecord acvo; /* voice */ +} qdf_packed tSirMacEdcaParamSetIE; + +/* ts info direction field can take any of these values */ +#define SIR_MAC_DIRECTION_UPLINK 0 +#define SIR_MAC_DIRECTION_DNLINK 1 +#define SIR_MAC_DIRECTION_DIRECT 2 +#define SIR_MAC_DIRECTION_BIDIR 3 + +/* access policy */ +/* reserved 0 */ +#define SIR_MAC_ACCESSPOLICY_EDCA 1 +#define SIR_MAC_ACCESSPOLICY_HCCA 2 +#define SIR_MAC_ACCESSPOLICY_BOTH 3 + +/* frame classifier types */ +#define SIR_MAC_TCLASTYPE_ETHERNET 0 +#define SIR_MAC_TCLASTYPE_TCPUDPIP 1 +#define SIR_MAC_TCLASTYPE_8021DQ 2 +/* reserved 3-255 */ + +typedef struct sSirMacTclasParamEthernet { + tSirMacAddr srcAddr; + tSirMacAddr dstAddr; + uint16_t type; +} qdf_packed tSirMacTclasParamEthernet; + +typedef struct sSirMacTclasParamIPv4 { + uint8_t version; + uint8_t srcIpAddr[4]; + uint8_t dstIpAddr[4]; + uint16_t srcPort; + uint16_t dstPort; + uint8_t dscp; + uint8_t protocol; + uint8_t rsvd; +} qdf_packed tSirMacTclasParamIPv4; + +#define SIR_MAC_TCLAS_IPV4 4 + +typedef struct sSirMacTclasParamIPv6 { + uint8_t version; + uint8_t srcIpAddr[16]; + uint8_t dstIpAddr[16]; + uint16_t srcPort; + uint16_t dstPort; + uint8_t flowLabel[3]; +} qdf_packed tSirMacTclasParamIPv6; + +typedef struct sSirMacTclasParam8021dq { + uint16_t tag; +} qdf_packed tSirMacTclasParam8021dq; + +typedef struct sSirMacTclasIE { + uint8_t type; + uint8_t length; + uint8_t userPrio; + uint8_t classifierType; + uint8_t classifierMask; +} qdf_packed tSirMacTclasIE; + +typedef struct sSirMacTsDelayIE { + uint8_t type; + uint8_t length; + uint32_t delay; +} qdf_packed tSirMacTsDelayIE; + +typedef struct sSirMacScheduleInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t rsvd:9; + uint16_t direction:2; + uint16_t tsid:4; + uint16_t aggregation:1; +#else + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t rsvd:9; +#endif +} qdf_packed tSirMacScheduleInfo; + +typedef struct sSirMacScheduleIE { + uint8_t type; + uint8_t length; + tSirMacScheduleInfo info; + uint32_t svcStartTime; + uint32_t svcInterval; + uint16_t maxSvcDuration; + uint16_t specInterval; +} qdf_packed tSirMacScheduleIE; + +typedef struct sSirMacQosCapabilityIE { + uint8_t type; + uint8_t length; + tSirMacQosInfo qosInfo; +} qdf_packed tSirMacQosCapabilityIE; + +typedef struct sSirMacQosCapabilityStaIE { + uint8_t type; + uint8_t length; + tSirMacQosInfoStation qosInfo; +} qdf_packed tSirMacQosCapabilityStaIE; + +typedef uint32_t tSirMacTimeStamp[2]; + +typedef uint16_t tSirMacBeaconInterval; + +typedef uint16_t tSirMacListenInterval; + +typedef uint8_t tSirMacChanNum; + +/* IE definitions */ +typedef struct sSirMacSSidIE { + uint8_t type; + tSirMacSSid ssId; +} qdf_packed tSirMacSSidIE; + +typedef struct sSirMacRateSetIE { + uint8_t type; + tSirMacRateSet supportedRateSet; +} qdf_packed tSirMacRateSetIE; + +typedef struct sSirMacDsParamSetIE { + uint8_t type; + uint8_t length; + tSirMacChanNum channelNumber; +} qdf_packed tSirMacDsParamSetIE; + +typedef struct sSirMacCfParamSetIE { + uint8_t type; + uint8_t length; + tSirMacCfParamSet cfParams; +} qdf_packed tSirMacCfParamSetIE; + +typedef struct sSirMacNonErpPresentIE { + uint8_t type; + uint8_t length; + uint8_t erp; +} qdf_packed tSirMacNonErpPresentIE; + +typedef struct sSirMacPowerCapabilityIE { + uint8_t type; + uint8_t length; + uint8_t minTxPower; + uint8_t maxTxPower; +} tSirMacPowerCapabilityIE; + +typedef struct sSirMacSupportedChannelIE { + uint8_t type; + uint8_t length; + uint8_t supportedChannels[96]; +} tSirMacSupportedChannelIE; + +typedef struct sSirMacMeasReqField { + uint8_t channelNumber; + uint8_t measStartTime[8]; + uint16_t measDuration; +} tSirMacMeasReqField, *tpSirMacMeasReqField; + +typedef struct sSirMacMeasReqIE { + uint8_t type; + uint8_t length; + uint8_t measToken; + uint8_t measReqMode; + uint8_t measType; + tSirMacMeasReqField measReqField; +} tSirMacMeasReqIE, *tpSirMacMeasReqIE; + +/* VHT Capabilities Info */ +typedef struct sSirMacVHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t extended_nss_bw_supp:2; + uint32_t txAntPattern:1; + uint32_t rxAntPattern:1; + uint32_t vhtLinkAdaptCap:2; + uint32_t maxAMPDULenExp:3; + uint32_t htcVHTCap:1; + uint32_t vhtTXOPPS:1; + uint32_t muBeamformeeCap:1; + uint32_t muBeamformerCap:1; + uint32_t numSoundingDim:3; + uint32_t csnofBeamformerAntSup:3; + uint32_t suBeamformeeCap:1; + uint32_t suBeamFormerCap:1; + uint32_t rxSTBC:3; + uint32_t txSTBC:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t shortGI80MHz:1; + uint32_t ldpcCodingCap:1; + uint32_t supportedChannelWidthSet:2; + uint32_t maxMPDULen:2; +#else + uint32_t maxMPDULen:2; + uint32_t supportedChannelWidthSet:2; + uint32_t ldpcCodingCap:1; + uint32_t shortGI80MHz:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t txSTBC:1; + uint32_t rxSTBC:3; + uint32_t suBeamFormerCap:1; + uint32_t suBeamformeeCap:1; + uint32_t csnofBeamformerAntSup:3; + uint32_t numSoundingDim:3; + uint32_t muBeamformerCap:1; + uint32_t muBeamformeeCap:1; + uint32_t vhtTXOPPS:1; + uint32_t htcVHTCap:1; + uint32_t maxAMPDULenExp:3; + uint32_t vhtLinkAdaptCap:2; + uint32_t rxAntPattern:1; + uint32_t txAntPattern:1; + uint32_t extended_nss_bw_supp:2; +#endif +} qdf_packed tSirMacVHTCapabilityInfo; + +typedef struct sSirMacVHTTxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:2; + uint16_t vht_extended_nss_bw_cap:1; + uint16_t txSupDataRate:13; +#else + uint16_t txSupDataRate:13; + uint16_t vht_extended_nss_bw_cap:1; + uint16_t reserved:2; +#endif +} qdf_packed tSirMacVHTTxSupDataRateInfo; + +typedef struct sSirMacVHTRxSupDataRateInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t max_nsts_total:3; + uint16_t rxSupDataRate:13; +#else + uint16_t rxSupDataRate:13; + uint16_t max_nsts_total:3; +#endif +} qdf_packed tSirMacVHTRxSupDataRateInfo; + +/** + * struct sSirVhtMcsInfo - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams + * @rx_highest: Indicates highest long GI VHT PPDU data rate + * STA can receive. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams + * @tx_highest: Indicates highest long GI VHT PPDU data rate + * STA can transmit. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest TX data rate supported. + */ +typedef struct sSirVhtMcsInfo { + uint16_t rxMcsMap; + uint16_t rxHighest; + uint16_t txMcsMap; + uint16_t txHighest; +} tSirVhtMcsInfo; + +/** + * struct sSirVHtCap - VHT capabilities + * + * This structure is the "VHT capabilities element" as + * described in 802.11ac D3.0 8.4.2.160 + * @vht_cap_info: VHT capability info + * @supp_mcs: VHT MCS supported rates + */ +typedef struct sSirVHtCap { + uint32_t vhtCapInfo; + tSirVhtMcsInfo suppMcs; +} tSirVHTCap; + +/* */ +/* Determines the current operating mode of the 802.11n STA */ +/* */ + +typedef enum eSirMacHTOperatingMode { + eSIR_HT_OP_MODE_PURE, /* No Protection */ + eSIR_HT_OP_MODE_OVERLAP_LEGACY, /* Overlap Legacy device present, protection is optional */ + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT, /* No legacy device, but 20 MHz HT present */ + eSIR_HT_OP_MODE_MIXED /* Protetion is required */ +} tSirMacHTOperatingMode; + +/* Spatial Multiplexing(SM) Power Save mode */ +typedef enum eSirMacHTMIMOPowerSaveState { + eSIR_HT_MIMO_PS_STATIC = 0, /* Static SM Power Save mode */ + eSIR_HT_MIMO_PS_DYNAMIC = 1, /* Dynamic SM Power Save mode */ + eSIR_HT_MIMO_PS_NA = 2, /* reserved */ + eSIR_HT_MIMO_PS_NO_LIMIT = 3 /* SM Power Save disabled */ +} tSirMacHTMIMOPowerSaveState; + +typedef enum eSirMacHTChannelWidth { + eHT_CHANNEL_WIDTH_20MHZ = 0, + eHT_CHANNEL_WIDTH_40MHZ = 1, + eHT_CHANNEL_WIDTH_80MHZ = 2, + eHT_CHANNEL_WIDTH_160MHZ = 3, + eHT_CHANNEL_WIDTH_80P80MHZ = 4, + eHT_CHANNEL_WIDTH_320MHZ = 5, + eHT_MAX_CHANNEL_WIDTH +} tSirMacHTChannelWidth; + +typedef enum eSirMacHTChannelType { + eHT_CHAN_NO_HT = 0, + eHT_CHAN_HT20 = 1, + eHT_CHAN_HT40MINUS = 2, + eHT_CHAN_HT40PLUS = 3 +} tSirMacHTChannelType; + +/* Packet struct for HT capability */ +typedef struct sHtCaps { + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved1:3; + uint8_t supportedMCSSet[16]; + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved2:5; + uint16_t mcsFeedback:2; + uint16_t reserved3:6; + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved4:7; + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved5:1; + +} qdf_packed tHtCaps; + +/* Supported MCS set */ +#define SIZE_OF_SUPPORTED_MCS_SET 16 +#define SIZE_OF_BASIC_MCS_SET 16 +#define VALID_MCS_SIZE 77 /* 0-76 */ +#define MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET 10 +#define VALID_MAX_MCS_INDEX 8 + +/* */ +/* The following enums will be used to get the "current" HT Capabilities of */ +/* the local STA in a generic fashion. In other words, the following enums */ +/* identify the HT capabilities that can be queried or set. */ +/* */ +typedef enum eHTCapability { + eHT_LSIG_TXOP_PROTECTION, + eHT_STBC_CONTROL_FRAME, + eHT_PSMP, + eHT_DSSS_CCK_MODE_40MHZ, + eHT_MAX_AMSDU_LENGTH, + eHT_MAX_AMSDU_NUM, + eHT_RX_STBC, + eHT_TX_STBC, + eHT_SHORT_GI_40MHZ, + eHT_SHORT_GI_20MHZ, + eHT_GREENFIELD, + eHT_MIMO_POWER_SAVE, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + eHT_ADVANCED_CODING, + eHT_MAX_RX_AMPDU_FACTOR, + eHT_MPDU_DENSITY, + eHT_PCO, + eHT_TRANSITION_TIME, + eHT_MCS_FEEDBACK, + eHT_TX_BEAMFORMING, + eHT_ANTENNA_SELECTION, + /* The following come under Additional HT Capabilities */ + eHT_SI_GRANULARITY, + eHT_CONTROLLED_ACCESS, + eHT_RIFS_MODE, + eHT_RECOMMENDED_TX_WIDTH_SET, + eHT_EXTENSION_CHANNEL_OFFSET, + eHT_OP_MODE, + eHT_BASIC_STBC_MCS, + eHT_DUAL_CTS_PROTECTION, + eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT, + eHT_PCO_ACTIVE, + eHT_PCO_PHASE +} tHTCapability; + +/* HT Parameters Info */ +typedef struct sSirMacHTParametersInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved:3; + uint8_t mpduDensity:3; /* Dynamic state */ + uint8_t maxRxAMPDUFactor:2; /* Dynamic state */ +#else + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved:3; +#endif +} qdf_packed tSirMacHTParametersInfo; + +/* Extended HT Capabilities Info */ +typedef struct sSirMacExtendedHTCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved2:6; + uint16_t mcsFeedback:2; /* Static via CFG */ + uint16_t reserved1:5; + uint16_t transitionTime:2; /* Static via CFG */ + uint16_t pco:1; /* Static via CFG */ +#else + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved1:5; + uint16_t mcsFeedback:2; + uint16_t reserved2:6; +#endif +} qdf_packed tSirMacExtendedHTCapabilityInfo; + +/* IEEE 802.11n/D7.0 - 7.3.2.57.4 */ +/* Part of the "supported MCS set field" */ +typedef struct sSirMacRxHighestSupportRate { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint16_t reserved:6; + uint16_t rate:10; +#else + uint16_t rate:10; + uint16_t reserved:6; +#endif +} qdf_packed tSirMacRxHighestSupportRate, *tpSirMacRxHighestSupportRate; + +/* Transmit Beam Forming Capabilities Info */ +typedef struct sSirMacTxBFCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t reserved:7; + uint32_t compressedSteeringMatrixBFAntennae:2; /* Static via CFG */ + /* Static via CFG */ + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t csiNumBFAntennae:2; /* Static via CFG */ + /* Static via CFG */ + uint32_t explicitCompressedSteeringMatrixFeedback:3; + /* Static via CFG */ + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitBFCSIFeedback:3; /* Static via CFG */ + uint32_t explicitUncompressedSteeringMatrix:1; /* Static via CFG */ + uint32_t explicitCSITxBF:1; /* Static via CFG */ + uint32_t calibration:2; /* Static via CFG */ + uint32_t implicitTxBF:1; /* Static via CFG */ + uint32_t txZLF:1; /* Static via CFG */ + uint32_t rxZLF:1; /* Static via CFG */ + uint32_t txStaggeredSounding:1; /* Static via CFG */ + uint32_t rxStaggeredSounding:1; /* Static via CFG */ + uint32_t txBF:1; /* Static via CFG */ +#else + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved:7; +#endif +} qdf_packed tSirMacTxBFCapabilityInfo; + +/* Antenna Selection Capability Info */ +typedef struct sSirMacASCapabilityInfo { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t reserved2:1; + uint8_t txSoundingPPDUs:1; /* Static via CFG */ + uint8_t rxAS:1; /* Static via CFG */ + uint8_t antennaIndicesFeedback:1; /* Static via CFG */ + uint8_t explicitCSIFeedback:1; /* Static via CFG */ + uint8_t antennaIndicesFeedbackTx:1; /* Static via CFG */ + uint8_t explicitCSIFeedbackTx:1; /* Static via CFG */ + uint8_t antennaSelection:1; /* Static via CFG */ +#else + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved2:1; +#endif +} qdf_packed tSirMacASCapabilityInfo; + +typedef struct sSirMacAuthFrameBody { + uint16_t authAlgoNumber; + uint16_t authTransactionSeqNumber; + uint16_t authStatusCode; + uint8_t type; /* = WLAN_ELEMID_CHALLENGE */ + uint8_t length; /* = SIR_MAC_AUTH_CHALLENGE_LENGTH */ + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; +#ifdef WLAN_FEATURE_FILS_SK + tSirMacRsnInfo rsn_ie; + struct mac_ft_ie ft_ie; + uint8_t assoc_delay_info; + uint8_t session[SIR_FILS_SESSION_LENGTH]; + uint8_t wrapped_data_len; + uint8_t wrapped_data[SIR_FILS_WRAPPED_DATA_MAX_SIZE]; + uint8_t nonce[SIR_FILS_NONCE_LENGTH]; +#endif + bool is_mlo_ie_present; + struct qdf_mac_addr peer_mld; +} qdf_packed tSirMacAuthFrameBody, *tpSirMacAuthFrameBody; + +/* / Common header for all action frames */ +typedef struct sSirMacActionFrameHdr { + uint8_t category; + uint8_t actionID; +} qdf_packed tSirMacActionFrameHdr, *tpSirMacActionFrameHdr; + +typedef struct sSirMacVendorSpecificFrameHdr { + uint8_t category; + uint8_t Oui[4]; +} qdf_packed tSirMacVendorSpecificFrameHdr, +*tpSirMacVendorSpecificFrameHdr; + +typedef struct sSirMacVendorSpecificPublicActionFrameHdr { + uint8_t category; + uint8_t actionID; + uint8_t Oui[4]; + uint8_t OuiSubType; + uint8_t dialogToken; +} qdf_packed tSirMacVendorSpecificPublicActionFrameHdr, +*tpSirMacVendorSpecificPublicActionFrameHdr; + +typedef struct sSirMacMeasActionFrameHdr { + uint8_t category; + uint8_t actionID; + uint8_t dialogToken; +} tSirMacMeasActionFrameHdr, *tpSirMacMeasActionFrameHdr; + +#ifdef ANI_SUPPORT_11H +typedef struct sSirMacTpcReqActionFrame { + tSirMacMeasActionFrameHdr actionHeader; + uint8_t type; + uint8_t length; +} tSirMacTpcReqActionFrame, *tpSirMacTpcReqActionFrame; +typedef struct sSirMacMeasReqActionFrame { + tSirMacMeasActionFrameHdr actionHeader; + tSirMacMeasReqIE measReqIE; +} tSirMacMeasReqActionFrame, *tpSirMacMeasReqActionFrame; +#endif + +typedef struct sSirMacNeighborReportReq { + uint8_t dialogToken; + uint8_t ssid_present; + tSirMacSSid ssid; +} tSirMacNeighborReportReq, *tpSirMacNeighborReportReq; + +typedef struct sSirMacLinkReport { + uint8_t dialogToken; + uint8_t txPower; + uint8_t rxAntenna; + uint8_t txAntenna; + uint8_t rcpi; + uint8_t rsni; +} tSirMacLinkReport, *tpSirMacLinkReport; + +#define BEACON_REPORT_MAX_IES 215 +/* Max number of beacon reports per channel supported in the driver */ +#define MAX_BEACON_REPORTS 32 +/* Offset of IEs after Fixed Fields in Beacon Frame */ +#define BEACON_FRAME_IES_OFFSET 12 + +/** + * struct bcn_report_frame_body_frag_id - beacon report reported frame body + * fragment ID sub element params + * @id: report ID + * @frag_id: fragment ID + * @more_frags: more frags present or not present + */ +struct bcn_report_frame_body_frag_id { + uint8_t id; + uint8_t frag_id; + bool more_frags; +}; + +/** + * struct sSirMacBeaconReport - Beacon Report Structure + * @regClass: Regulatory Class + * @channel: Channel for which the current report is being sent + * @measStartTime: RRM scan start time for this report + * @measDuration: Scan duration for the current channel + * @phyType: Condensed Phy Type + * @bcnProbeRsp: Beacon or probe response being reported + * @rsni: Received signal-to-noise indication + * @rcpi: Received Channel Power indication + * @bssid: BSSID of the AP requesting the beacon report + * @antennaId: Number of Antennas used for measurement + * @parentTSF: measuring STA's TSF timer value + * @numIes: Number of IEs included in the beacon frames + * @last_bcn_report_ind_support: Support for Last beacon report indication + * @is_last_bcn_report: Is the current report last or more reports present + * @frame_body_frag_id: Reported Frame Body Frag Id sub-element params + * @Ies: IEs included in the beacon report + */ +typedef struct sSirMacBeaconReport { + uint8_t regClass; + uint8_t channel; + uint8_t measStartTime[8]; + uint8_t measDuration; + uint8_t phyType; + uint8_t bcnProbeRsp; + uint8_t rsni; + uint8_t rcpi; + tSirMacAddr bssid; + uint8_t antennaId; + uint32_t parentTSF; + uint8_t numIes; + uint8_t last_bcn_report_ind_support; + uint8_t is_last_bcn_report; + struct bcn_report_frame_body_frag_id frame_body_frag_id; + uint8_t Ies[BEACON_REPORT_MAX_IES]; + +} tSirMacBeaconReport, *tpSirMacBeaconReport; + +/** + * struct sir_mac_bw_ind_element - Contains info for Bandwidth Indication IE + * present in channel load request received from AP + * @is_wide_bw_chan_switch: to check Bandwidth Indication optional IE present + * @channel_width: channel width + * @center_chan_freq0: center freq segment 0 for 320 MHz request + * @center_chan_freq1: center freq segment 1 for 320 MHz request + */ +struct sir_mac_bw_ind_element { + bool is_bw_ind_element; + uint8_t channel_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; +}; + +/** + * struct sir_mac_wide_bw_chan_switch - Contains info for Wide Bandwidth Channel + * Switch IE present in channel load request received from AP + * @is_wide_bw_chan_switch: to check Bandwidth Indication optional IE present + * @channel_width: channel width + * @center_chan_freq0: center freq segment 0 for till 160 MHz request + * @center_chan_freq1: center freq segment 1 for till 160 MHz request + */ +struct sir_mac_wide_bw_chan_switch { + uint8_t is_wide_bw_chan_switch; + uint8_t channel_width; + uint8_t center_chan_freq0; + uint8_t center_chan_freq1; +}; + +/** + * struct chan_load_report - channel load Report Structure + * @op_class: Regulatory Class + * @channel: Channel for which the current report is being sent + * @rrm_scan_tsf: RRM scan start time for this report + * @meas_duration: Scan duration for the current channel + * @chan_load: channel utilization measurement + * @bw_ind: Contains info for Bandwidth Indication IE + * @wide_bw: Contains info for Wide Bandwidth Channel IE + */ +struct chan_load_report { + uint8_t op_class; + uint8_t channel; + qdf_time_t rrm_scan_tsf; + uint8_t meas_duration; + uint8_t chan_load; + struct sir_mac_bw_ind_element bw_ind; + struct sir_mac_wide_bw_chan_switch wide_bw; +}; + +/** + * sta_statistics_group_id - RRM STA STATISTICS TYPE related Refer IEEE + * P802.11-REVme/D2.1, January 2023, Table 9-144 + * @STA_STAT_GROUP_ID_COUNTER_STATS: group id for counter stats + * @STA_STAT_GROUP_ID_MAC_STATS: group id for mac stats + * @STA_STAT_GROUP_ID_QOS_STATS: group id for qos stats + * @STA_STAT_GROUP_ID_DELAY_STATS: group id delay stats + */ +enum sta_statistics_group_id { + STA_STAT_GROUP_ID_COUNTER_STATS = 0, + STA_STAT_GROUP_ID_MAC_STATS = 1, + STA_STAT_GROUP_ID_QOS_STATS = 2, + STA_STAT_GROUP_ID_DELAY_STATS = 10, +}; + +/** + * counter_stats - structure to hold stats of group id 0 + * @transmitted_fragment_count: transmitted fragment count + * @group_transmitted_frame_count: group transmitted frame count + * @failed_count: failed count + * @group_received_frame_count: group received frame count + * @fcs_error_count: face error count + * @transmitted_frame_count: transmitted frame count + * @received_fragment_count: received fragment count + */ +struct counter_stats { + uint32_t transmitted_fragment_count; + uint32_t group_transmitted_frame_count; + uint32_t failed_count; + uint32_t group_received_frame_count; + uint32_t fcs_error_count; + uint32_t transmitted_frame_count; + uint32_t received_fragment_count; +}; + +/** + * mac_stats - struct to hold group id 1 stats + * @retry_count: retry count + * @multiple_retry_count: multiple retry count + * @frame_duplicate_count: frame duplicate count + * @rts_success_count: rts success count + * @rts_failure_count: rts failure count + * @ack_failure_count: ack failure count + */ +struct mac_stats { + uint32_t retry_count; + uint32_t multiple_retry_count; + uint32_t frame_duplicate_count; + uint32_t rts_success_count; + uint32_t rts_failure_count; + uint32_t ack_failure_count; +}; + +/** + * struct access_delay_stats - struct for group id 10 stats + * @ap_average_access_delay: ap average access delay + * @average_access_delay_besteffort: access delay best effort + * @average_access_delay_background: average access delay background + * @average_access_delay_video: average access delay video + * @average_access_delay_voice: average access delay voice + * station_count: station count + * channel_utilization: channel utilization + */ +struct access_delay_stats { + uint8_t ap_average_access_delay; + uint8_t average_access_delay_besteffort; + uint8_t average_access_delay_background; + uint8_t average_access_delay_video; + uint8_t average_access_delay_voice; + uint16_t station_count; + uint8_t channel_utilization; +}; + +/** + * union stats_group_data - stats data for provided group id + * @counter stats - stats for group id 0 + * @mac_stats - stats for group id 1 + */ +union stats_group_data { + struct counter_stats counter_stats; + struct mac_stats mac_stats; + struct access_delay_stats access_delay_stats; +}; + +/** + * struct statistics_report - To store sta statistics report + * @meas_duration: measurement duration + * @group id: stats group id + * @group stats: stats data + */ +struct statistics_report { + uint8_t meas_duration; + uint8_t group_id; + union stats_group_data group_stats; +}; + +typedef struct sSirMacRadioMeasureReport { + uint8_t token; + uint8_t refused; + uint8_t incapable; + uint8_t type; + union { + tSirMacBeaconReport beaconReport; + struct chan_load_report channel_load_report; + struct statistics_report statistics_report; + } report; + +} tSirMacRadioMeasureReport, *tpSirMacRadioMeasureReport; + +#ifdef WLAN_FEATURE_11AX +struct he_cap_network_endian { + uint32_t htc_he:1; + uint32_t twt_request:1; + uint32_t twt_responder:1; + uint32_t fragmentation:2; + uint32_t max_num_frag_msdu_amsdu_exp:3; + uint32_t min_frag_size:2; + uint32_t trigger_frm_mac_pad:2; + uint32_t multi_tid_aggr_rx_supp:3; + uint32_t he_link_adaptation:2; + uint32_t all_ack:1; + uint32_t trigd_rsp_sched:1; + uint32_t a_bsr:1; + uint32_t broadcast_twt:1; + uint32_t ba_32bit_bitmap:1; + uint32_t mu_cascade:1; + uint32_t ack_enabled_multitid:1; + uint32_t reserved:1; + uint32_t omi_a_ctrl:1; + uint32_t ofdma_ra:1; + uint32_t max_ampdu_len_exp_ext:2; + uint32_t amsdu_frag:1; + uint32_t flex_twt_sched:1; + uint32_t rx_ctrl_frame:1; + + uint16_t bsrp_ampdu_aggr:1; + uint16_t qtp:1; + uint16_t a_bqr:1; + uint16_t spatial_reuse_param_rspder:1; + uint16_t ndp_feedback_supp:1; + uint16_t ops_supp:1; + uint16_t amsdu_in_ampdu:1; + uint16_t multi_tid_aggr_tx_supp:3; + uint16_t he_sub_ch_sel_tx_supp:1; + uint16_t ul_2x996_tone_ru_supp:1; + uint16_t om_ctrl_ul_mu_data_dis_rx:1; + uint16_t he_dynamic_smps:1; + uint16_t punctured_sounding_supp:1; + uint16_t ht_vht_trg_frm_rx_supp:1; + + uint32_t reserved2:1; + uint32_t chan_width:7; + uint32_t rx_pream_puncturing:4; + uint32_t device_class:1; + uint32_t ldpc_coding:1; + uint32_t he_1x_ltf_800_gi_ppdu:1; + uint32_t midamble_tx_rx_max_nsts:2; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t tb_ppdu_tx_stbc_lt_80mhz:1; + uint32_t rx_stbc_lt_80mhz:1; + uint32_t doppler:2; + uint32_t ul_mu:2; + uint32_t dcm_enc_tx:3; + uint32_t dcm_enc_rx:3; + uint32_t ul_he_mu:1; + uint32_t su_beamformer:1; + + uint32_t su_beamformee:1; + uint32_t mu_beamformer:1; + uint32_t bfee_sts_lt_80:3; + uint32_t bfee_sts_gt_80:3; + uint32_t num_sounding_lt_80:3; + uint32_t num_sounding_gt_80:3; + uint32_t su_feedback_tone16:1; + uint32_t mu_feedback_tone16:1; + uint32_t codebook_su:1; + uint32_t codebook_mu:1; + uint32_t beamforming_feedback:3; + uint32_t he_er_su_ppdu:1; + uint32_t dl_mu_mimo_part_bw:1; + uint32_t ppet_present:1; + uint32_t srp:1; + uint32_t power_boost:1; + uint32_t he_ltf_800_gi_4x:1; + uint32_t max_nc:3; + uint32_t tb_ppdu_tx_stbc_gt_80mhz:1; + uint32_t rx_stbc_gt_80mhz:1; + + uint16_t er_he_ltf_800_gi_4x:1; + uint16_t he_ppdu_20_in_40Mhz_2G:1; + uint16_t he_ppdu_20_in_160_80p80Mhz:1; + uint16_t he_ppdu_80_in_160_80p80Mhz:1; + uint16_t er_1x_he_ltf_gi:1; + uint16_t midamble_tx_rx_1x_he_ltf:1; + uint16_t dcm_max_bw:2; + uint16_t longer_than_16_he_sigb_ofdm_sym:1; + uint16_t non_trig_cqi_feedback:1; + uint16_t tx_1024_qam_lt_242_tone_ru:1; + uint16_t rx_1024_qam_lt_242_tone_ru:1; + uint16_t rx_full_bw_su_he_mu_compress_sigb:1; + uint16_t rx_full_bw_su_he_mu_non_cmpr_sigb:1; + uint16_t reserved3:2; + + uint8_t reserved4; + + uint16_t rx_he_mcs_map_lt_80; + uint16_t tx_he_mcs_map_lt_80; + uint16_t rx_he_mcs_map_160; + uint16_t tx_he_mcs_map_160; + uint16_t rx_he_mcs_map_80_80; + uint16_t tx_he_mcs_map_80_80; +} qdf_packed; + +struct he_ops_network_endian { + uint16_t default_pe:3; + uint16_t twt_required:1; + uint16_t txop_rts_threshold:10; + uint16_t vht_oper_present:1; + uint16_t co_located_bss:1; + uint8_t er_su_disable:1; + uint8_t reserved1:7; + uint8_t bss_color:6; + uint8_t partial_bss_col:1; + uint8_t bss_col_disabled:1; + uint8_t basic_mcs_nss[2]; + union { + struct { + uint8_t chan_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + } info; /* vht_oper_present = 1 */ + } vht_oper; + union { + struct { + uint8_t data; + } info; /* co_located_bss = 1 */ + } maxbssid_ind; +} qdf_packed; + +/* HE Capabilities Info */ +struct he_capability_info { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint32_t rx_ctrl_frame:1; + uint32_t flex_twt_sched:1; + uint32_t amsdu_frag:1; + uint32_t max_ampdu_len_exp_ext:2; + uint32_t ofdma_ra:1; + uint32_t omi_a_ctrl:1; + uint32_t reserved:1; + uint32_t ack_enabled_multitid:1; + uint32_t mu_cascade:1; + uint32_t ba_32bit_bitmap:1; + uint32_t broadcast_twt:1; + uint32_t a_bsr:1; + uint32_t trigd_rsp_sched:1; + uint32_t all_ack:1; + uint32_t he_link_adaptation:2; + uint32_t multi_tid_aggr_rx_supp:3; + uint32_t trigger_frm_mac_pad:2; + uint32_t min_frag_size:2; + uint32_t max_num_frag_msdu_amsdu_exp:3; + uint32_t fragmentation:2; + uint32_t twt_responder:1; + uint32_t twt_request:1; + uint32_t htc_he:1; + + uint16_t ht_vht_trg_frm_rx_supp:1; + uint16_t punctured_sounding_supp:1; + uint16_t he_dynamic_smps:1; + uint16_t om_ctrl_ul_mu_data_dis_rx:1; + uint16_t ul_2x996_tone_ru_supp:1; + uint16_t he_sub_ch_sel_tx_supp:1; + uint16_t multi_tid_aggr_tx_supp:3; + uint16_t amsdu_in_ampdu:1; + uint16_t ops_supp:1; + uint16_t ndp_feedback_supp:1; + uint16_t spatial_reuse_param_rspder:1; + uint16_t a_bqr:1; + uint16_t qtp:1; + uint16_t bsrp_ampdu_aggr:1; + + uint32_t su_beamformer:1; + uint32_t ul_he_mu:1; + uint32_t dcm_enc_rx:3; + uint32_t dcm_enc_tx:3; + uint32_t ul_mu:2; + uint32_t doppler:2; + uint32_t rx_stbc_lt_80mhz:1; + uint32_t tb_ppdu_tx_stbc_lt_80mhz:1; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t midamble_tx_rx_max_nsts:2; + uint32_t he_1x_ltf_800_gi_ppdu:1; + uint32_t ldpc_coding:1; + uint32_t device_class:1; + uint32_t rx_pream_puncturing:4; + uint32_t chan_width:7; + uint32_t reserved2:1; + + uint32_t rx_stbc_gt_80mhz:1; + uint32_t tb_ppdu_tx_stbc_gt_80mhz:1; + uint32_t max_nc:3; + uint32_t he_ltf_800_gi_4x:1; + uint32_t power_boost:1; + uint32_t srp:1; + uint32_t ppet_present:1; + uint32_t dl_mu_mimo_part_bw:1; + uint32_t he_er_su_ppdu:1; + uint32_t beamforming_feedback:3; + uint32_t codebook_mu:1; + uint32_t codebook_su:1; + uint32_t mu_feedback_tone16:1; + uint32_t su_feedback_tone16:1; + uint32_t num_sounding_gt_80:3; + uint32_t num_sounding_lt_80:3; + uint32_t bfee_sts_gt_80:3; + uint32_t bfee_sts_lt_80:3; + uint32_t mu_beamformer:1; + uint32_t su_beamformee:1; + + uint16_t reserved3:2; + uint16_t rx_full_bw_su_he_mu_non_cmpr_sigb:1; + uint16_t rx_full_bw_su_he_mu_compress_sigb:1; + uint16_t rx_1024_qam_lt_242_tone_ru:1; + uint16_t tx_1024_qam_lt_242_tone_ru:1; + uint16_t non_trig_cqi_feedback:1; + uint16_t longer_than_16_he_sigb_ofdm_sym:1; + uint16_t dcm_max_bw:2; + uint16_t midamble_tx_rx_1x_he_ltf:1; + uint16_t er_1x_he_ltf_gi:1; + uint16_t he_ppdu_80_in_160_80p80Mhz:1; + uint16_t he_ppdu_20_in_160_80p80Mhz:1; + uint16_t he_ppdu_20_in_40Mhz_2G:1; + uint16_t er_he_ltf_800_gi_4x:1; + + uint8_t reserved4; + + uint16_t tx_he_mcs_map_80_80; + uint16_t rx_he_mcs_map_80_80; + uint16_t tx_he_mcs_map_160; + uint16_t rx_he_mcs_map_160; + uint16_t tx_he_mcs_map_lt_80; + uint16_t rx_he_mcs_map_lt_80; +#else + uint32_t htc_he:1; + uint32_t twt_request:1; + uint32_t twt_responder:1; + uint32_t fragmentation:2; + uint32_t max_num_frag_msdu_amsdu_exp:3; + uint32_t min_frag_size:2; + uint32_t trigger_frm_mac_pad:2; + uint32_t multi_tid_aggr_rx_supp:3; + uint32_t he_link_adaptation:2; + uint32_t all_ack:1; + uint32_t trigd_rsp_sched:1; + uint32_t a_bsr:1; + uint32_t broadcast_twt:1; + uint32_t ba_32bit_bitmap:1; + uint32_t mu_cascade:1; + uint32_t ack_enabled_multitid:1; + uint32_t reserved:1; + uint32_t omi_a_ctrl:1; + uint32_t ofdma_ra:1; + uint32_t max_ampdu_len_exp_ext:2; + uint32_t amsdu_frag:1; + uint32_t flex_twt_sched:1; + uint32_t rx_ctrl_frame:1; + + uint16_t bsrp_ampdu_aggr:1; + uint16_t qtp:1; + uint16_t a_bqr:1; + uint16_t spatial_reuse_param_rspder:1; + uint16_t ndp_feedback_supp:1; + uint16_t ops_supp:1; + uint16_t amsdu_in_ampdu:1; + uint16_t multi_tid_aggr_tx_supp:3; + uint16_t he_sub_ch_sel_tx_supp:1; + uint16_t ul_2x996_tone_ru_supp:1; + uint16_t om_ctrl_ul_mu_data_dis_rx:1; + uint16_t he_dynamic_smps:1; + uint16_t punctured_sounding_supp:1; + uint16_t ht_vht_trg_frm_rx_supp:1; + + uint32_t reserved2:1; + uint32_t chan_width:7; + uint32_t rx_pream_puncturing:4; + uint32_t device_class:1; + uint32_t ldpc_coding:1; + uint32_t he_1x_ltf_800_gi_ppdu:1; + uint32_t midamble_tx_rx_max_nsts:2; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t tb_ppdu_tx_stbc_lt_80mhz:1; + uint32_t rx_stbc_lt_80mhz:1; + uint32_t doppler:2; + uint32_t ul_mu:2; + uint32_t dcm_enc_tx:3; + uint32_t dcm_enc_rx:3; + uint32_t ul_he_mu:1; + uint32_t su_beamformer:1; + + uint32_t su_beamformee:1; + uint32_t mu_beamformer:1; + uint32_t bfee_sts_lt_80:3; + uint32_t bfee_sts_gt_80:3; + uint32_t num_sounding_lt_80:3; + uint32_t num_sounding_gt_80:3; + uint32_t su_feedback_tone16:1; + uint32_t mu_feedback_tone16:1; + uint32_t codebook_su:1; + uint32_t codebook_mu:1; + uint32_t beamforming_feedback:3; + uint32_t he_er_su_ppdu:1; + uint32_t dl_mu_mimo_part_bw:1; + uint32_t ppet_present:1; + uint32_t srp:1; + uint32_t power_boost:1; + uint32_t he_ltf_800_gi_4x:1; + uint32_t max_nc:3; + uint32_t tb_ppdu_tx_stbc_gt_80mhz:1; + uint32_t rx_stbc_gt_80mhz:1; + + uint16_t er_he_ltf_800_gi_4x:1; + uint16_t he_ppdu_20_in_40Mhz_2G:1; + uint16_t he_ppdu_20_in_160_80p80Mhz:1; + uint16_t he_ppdu_80_in_160_80p80Mhz:1; + uint16_t er_1x_he_ltf_gi:1; + uint16_t midamble_tx_rx_1x_he_ltf:1; + uint16_t dcm_max_bw:2; + uint16_t longer_than_16_he_sigb_ofdm_sym:1; + uint16_t non_trig_cqi_feedback:1; + uint16_t tx_1024_qam_lt_242_tone_ru:1; + uint16_t rx_1024_qam_lt_242_tone_ru:1; + uint16_t rx_full_bw_su_he_mu_compress_sigb:1; + uint16_t rx_full_bw_su_he_mu_non_cmpr_sigb:1; + uint16_t reserved3:2; + + uint8_t reserved4; + + uint16_t rx_he_mcs_map_lt_80; + uint16_t tx_he_mcs_map_lt_80; + uint16_t rx_he_mcs_map_160; + uint16_t tx_he_mcs_map_160; + uint16_t rx_he_mcs_map_80_80; + uint16_t tx_he_mcs_map_80_80; +#endif +} qdf_packed; + +struct he_6ghz_capability_info { + uint16_t min_mpdu_start_spacing:3; + uint16_t max_ampdu_len_exp:3; + uint16_t max_mpdu_len:2; + + uint16_t reserved:1; + uint16_t sm_pow_save:2; + uint16_t rd_responder:1; + uint16_t rx_ant_pattern_consistency:1; + uint16_t tx_ant_pattern_consistency:1; + uint16_t reserved2:2; +} qdf_packed; +#endif + +/* + * frame parser does not include optional 160 and 80+80 mcs set for MIN IE len + */ +#define SIR_MAC_HE_CAP_MIN_LEN (DOT11F_IE_HE_CAP_MIN_LEN) +#define HE_CAP_160M_MCS_MAP_LEN 4 +#define HE_CAP_80P80_MCS_MAP_LEN 4 +#define HE_CAP_OUI_LEN 3 + +/* QOS action frame definitions */ + +/* max number of possible tclas elements in any frame */ +#define SIR_MAC_TCLASIE_MAXNUM 2 + +/* 11b rate encoding in MAC format */ + +#define SIR_MAC_RATE_1 0x02 +#define SIR_MAC_RATE_2 0x04 +#define SIR_MAC_RATE_5_5 0x0B +#define SIR_MAC_RATE_11 0x16 + +/* 11a/g rate encoding in MAC format */ + +#define SIR_MAC_RATE_6 0x0C +#define SIR_MAC_RATE_9 0x12 +#define SIR_MAC_RATE_12 0x18 +#define SIR_MAC_RATE_18 0x24 +#define SIR_MAC_RATE_24 0x30 +#define SIR_MAC_RATE_36 0x48 +#define SIR_MAC_RATE_48 0x60 +#define SIR_MAC_RATE_54 0x6C + +/* ANI legacy supported rates */ +#define SIR_MAC_RATE_72 0x01 +#define SIR_MAC_RATE_96 0x03 +#define SIR_MAC_RATE_108 0x05 + +/* ANI enhanced rates */ +#define SIR_MAC_RATE_42 1000 +#define SIR_MAC_RATE_84 1001 +#define SIR_MAC_RATE_126 1002 +#define SIR_MAC_RATE_144 1003 +#define SIR_MAC_RATE_168 1004 +#define SIR_MAC_RATE_192 1005 +#define SIR_MAC_RATE_216 1006 +#define SIR_MAC_RATE_240 1007 + +#define SIR_MAC_RATE_1_BITMAP (1<<0) +#define SIR_MAC_RATE_2_BITMAP (1<<1) +#define SIR_MAC_RATE_5_5_BITMAP (1<<2) +#define SIR_MAC_RATE_11_BITMAP (1<<3) +#define SIR_MAC_RATE_6_BITMAP (1<<4) +#define SIR_MAC_RATE_9_BITMAP (1<<5) +#define SIR_MAC_RATE_12_BITMAP (1<<6) +#define SIR_MAC_RATE_18_BITMAP (1<<7) +#define SIR_MAC_RATE_24_BITMAP (1<<8) +#define SIR_MAC_RATE_36_BITMAP (1<<9) +#define SIR_MAC_RATE_48_BITMAP (1<<10) +#define SIR_MAC_RATE_54_BITMAP (1<<11) + +#define sirIsArate(x) ((((uint8_t)x) == SIR_MAC_RATE_6) || \ + (((uint8_t)x) == SIR_MAC_RATE_9) || \ + (((uint8_t)x) == SIR_MAC_RATE_12) || \ + (((uint8_t)x) == SIR_MAC_RATE_18) || \ + (((uint8_t)x) == SIR_MAC_RATE_24) || \ + (((uint8_t)x) == SIR_MAC_RATE_36) || \ + (((uint8_t)x) == SIR_MAC_RATE_48) || \ + (((uint8_t)x) == SIR_MAC_RATE_54)) + +#define sirIsBrate(x) ((((uint8_t)x) == SIR_MAC_RATE_1) || \ + (((uint8_t)x) == SIR_MAC_RATE_2) || \ + (((uint8_t)x) == SIR_MAC_RATE_5_5) || \ + (((uint8_t)x) == SIR_MAC_RATE_11)) + +#define sirIsGrate(x) ((((uint8_t)x) == SIR_MAC_RATE_1) || \ + (((uint8_t)x) == SIR_MAC_RATE_2) || \ + (((uint8_t)x) == SIR_MAC_RATE_5_5) || \ + (((uint8_t)x) == SIR_MAC_RATE_11) || \ + (((uint8_t)x) == SIR_MAC_RATE_6) || \ + (((uint8_t)x) == SIR_MAC_RATE_9) || \ + (((uint8_t)x) == SIR_MAC_RATE_12) || \ + (((uint8_t)x) == SIR_MAC_RATE_18) || \ + (((uint8_t)x) == SIR_MAC_RATE_24) || \ + (((uint8_t)x) == SIR_MAC_RATE_36) || \ + (((uint8_t)x) == SIR_MAC_RATE_48) || \ + (((uint8_t)x) == SIR_MAC_RATE_54)) + +#define SIR_MAC_MIN_IE_LEN 2 /* Minimum IE length for IE validation */ + +#define SIR_MAC_TI_TYPE_ASSOC_COMEBACK 3 + +#define SIR_MAC_VHT_CAP_MAX_MPDU_LEN 0 +#define SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET 2 +#define SIR_MAC_VHT_CAP_LDPC_CODING_CAP 4 +#define SIR_MAC_VHT_CAP_SHORTGI_80MHZ 5 +#define SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ 6 +#define SIR_MAC_VHT_CAP_TXSTBC 7 +#define SIR_MAC_VHT_CAP_RXSTBC 8 +#define SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP 11 +#define SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP 12 +#define SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP 13 +#define SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM 16 +#define SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP 19 +#define SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP 20 +#define SIR_MAC_VHT_CAP_TXOPPS 21 +#define SIR_MAC_VHT_CAP_HTC_CAP 22 +#define SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO 23 +#define SIR_MAC_VHT_CAP_LINK_ADAPT_CAP 26 +#define SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN 28 +#define SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN 29 +#define SIR_MAC_VHT_CAP_EXTD_NSS_BW 30 + +#define SIR_MAC_HT_CAP_ADVCODING_S 0 +#define SIR_MAC_HT_CAP_CHWIDTH40_S 1 +#define SIR_MAC_HT_CAP_SMPOWERSAVE_DYNAMIC_S 2 +#define SIR_MAC_HT_CAP_SM_RESERVED_S 3 +#define SIR_MAC_HT_CAP_GREENFIELD_S 4 +#define SIR_MAC_HT_CAP_SHORTGI20MHZ_S 5 +#define SIR_MAC_HT_CAP_SHORTGI40MHZ_S 6 +#define SIR_MAC_HT_CAP_TXSTBC_S 7 +#define SIR_MAC_HT_CAP_RXSTBC_S 8 +#define SIR_MAC_HT_CAP_DELAYEDBLKACK_S 10 +#define SIR_MAC_HT_CAP_MAXAMSDUSIZE_S 11 +#define SIR_MAC_HT_CAP_DSSSCCK40_S 12 +#define SIR_MAC_HT_CAP_PSMP_S 13 +#define SIR_MAC_HT_CAP_INTOLERANT40_S 14 +#define SIR_MAC_HT_CAP_LSIGTXOPPROT_S 15 + +#define SIR_MAC_TXSTBC 1 +#define SIR_MAC_RXSTBC 1 + +#define SIR_MAC_RSNX_CAP_MIN_LEN 1 +#define SIR_MAC_RSNX_CAP_MAX_LEN 16 + +#define SIR_MAC_IE_TYPE_OFFSET 0 +#define SIR_MAC_IE_LEN_OFFSET 1 +#define SIR_MAC_IE_TYPE_LEN_SIZE 2 +#endif /* __MAC_PROT_DEFS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_types.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_types.h new file mode 100644 index 0000000000..531c3d8aa8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/sir_types.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2011-2016,2018-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sir_types.h contains the common types + * + * Author: V. K. Kandarpa + * Date: 04/12/2002 + */ + +#ifndef __SIR_TYPES_H +#define __SIR_TYPES_H + +#include +#include + +/** + * typedef mac_handle_t - MAC Handle + * + * Handle to the MAC. The MAC handle is returned to the HDD from the + * UMAC on Open. The MAC handle is an input to all UMAC function + * calls and represents an opaque handle to the UMAC instance that is + * tied to the HDD instance + * + * The UMAC must be able to derive it's internal instance structure + * pointer through this handle. + */ +/* + * NOTE WELL: struct opaque_mac_handle is not defined anywhere. This + * reference is used to help ensure that a mac_handle_t is never used + * where a different handle type is expected + */ +struct opaque_mac_handle; +typedef struct opaque_mac_handle *mac_handle_t; + +/** + * typedef hdd_handle_t - HDD Handle + * + * Handle to the HDD. The HDD handle is given to the UMAC from the + * HDD on Open. The HDD handle is an input to all HDD/PAL function + * calls and represents an opaque handle to the HDD instance that is + * tied to the UMAC instance + * + * The HDD must be able to derive it's internal instance structure + * pointer through this handle. + */ +/* + * NOTE WELL: struct opaque_hdd_handle is not defined anywhere. This + * reference is used to help ensure that a hdd_handle_t is never used + * where a different handle type is expected + */ +struct opaque_hdd_handle; +typedef struct opaque_hdd_handle *hdd_handle_t; + +#ifndef WLAN_MAX_CLIENTS_ALLOWED +#define HAL_NUM_ASSOC_STA 32 +#define HAL_NUM_STA 41 +#else +#define HAL_NUM_ASSOC_STA WLAN_MAX_CLIENTS_ALLOWED +/* + * Sync with OL_TXRX_NUM_LOCAL_PEER_IDS definition. + * Each AP will occupy one ID, so it will occupy two IDs for AP-AP mode. + * Clients will be assigned max 64 IDs. + * STA(associated)/P2P DEV(self-PEER) will get one ID. + */ +#define HAL_NUM_STA (WLAN_MAX_CLIENTS_ALLOWED + 1 + 1 + 1) +#endif + +#endif /* __SIR_TYPES_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wlan_tgt_def_config.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wlan_tgt_def_config.h new file mode 100644 index 0000000000..76979e8b12 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wlan_tgt_def_config.h @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2011, 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021 Qualcomm Innovation Center, Inc. All rights reserved. + * + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_TGT_DEF_CONFIG_H__ +#define __WLAN_TGT_DEF_CONFIG_H__ + +/* + * set of default target config , that can be over written by platform + */ + +/* + * default limit of 8 VAPs per device. + */ +/* Rome PRD support 4 vdevs */ +#define CFG_TGT_NUM_VDEV 4 + +/* + * We would need 1 AST entry per peer. Scale it by a + * factor of 2 to minimize hash collisions. + * TODO: This scaling factor would be taken care inside the WAL in the future. + */ +#define CFG_TGT_NUM_PEER_AST 2 + +/* # of WDS entries to support. + */ +#define CFG_TGT_WDS_ENTRIES 0 + +/* MAC DMA burst size. 0: 128B - default, 1: 256B, 2: 64B + */ +#define CFG_TGT_DEFAULT_DMA_BURST_SIZE 0 + +/* Fixed delimiters to be inserted after every MPDU + */ +#define CFG_TGT_DEFAULT_MAC_AGGR_DELIM 0 + +/* + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_AST_SKID_LIMIT 16 + +/* + * total number of peers per device. + */ +#define CFG_TGT_NUM_PEERS 14 + +/* + * In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers supported by target in offload mode + */ + +/* + * The current firmware implementation requires the number of offload peers + * should be (number of vdevs + 1). + + * The reason for this is the firmware clubbed the self peer and offload peer + * in the same pool. So if the firmware wanted to support n vdevs then the + * number of offload peer must be n+1 of which n buffers will be used for + * self peer and the remaining 1 is used for offload peer to support chatter + * mode for single STA. + + * Technically the macro should be 1 however the current firmware requires n+1. + + * TODO: This MACRO need to be modified in the future, if the firmware modified + * to allocate buffers for self peer and offload peer independently. + */ + +#define CFG_TGT_NUM_OFFLOAD_PEERS (CFG_TGT_NUM_VDEV + 1) + +/* + * Number of reorder buffers used in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS 4 + +/* + * keys per peer node + */ +#define CFG_TGT_NUM_PEER_KEYS 2 +/* + * total number of data TX and RX TIDs + */ +#define CFG_TGT_NUM_TIDS (2 * (CFG_TGT_NUM_PEERS + CFG_TGT_NUM_VDEV + 2)) +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + */ +#define CFG_TGT_DEFAULT_TX_CHAIN_MASK 0x7 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + */ +#define CFG_TGT_DEFAULT_RX_CHAIN_MASK 0x7 +/* 100 ms for video, best-effort, and background */ +#define CFG_TGT_RX_TIMEOUT_LO_PRI 100 +/* 40 ms for voice*/ +#define CFG_TGT_RX_TIMEOUT_HI_PRI 40 + +/* AR9888 unified is default in ethernet mode */ +#define CFG_TGT_RX_DECAP_MODE (0x2) +/* Decap to native Wifi header */ +#define CFG_TGT_RX_DECAP_MODE_NWIFI (0x1) +/* Decap to raw mode header */ +#define CFG_TGT_RX_DECAP_MODE_RAW (0x0) + +/* maximum number of pending scan requests */ +#define CFG_TGT_DEFAULT_SCAN_MAX_REQS 0x4 + +/* maximum number of VDEV that could use BMISS offload */ +#ifndef CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x3 +#endif + +/* maximum number of VDEV offload Roaming to support */ +#ifndef CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV 0x3 +#endif + +/* maximum number of STA VDEVs */ +#ifndef CFG_TGT_DEFAULT_MAX_STA_VDEVS +#define CFG_TGT_DEFAULT_MAX_STA_VDEVS 0 +#endif + +/* maximum number of AP profiles pushed to offload Roaming */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES 0x8 + +/* maximum number of VDEV offload GTK to support */ +#ifndef CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV 0x3 +#endif + +/* default: mcast->ucast disabled if ATH_SUPPORT_MCAST2UCAST not defined */ +#ifndef ATH_SUPPORT_MCAST2UCAST +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 0 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 0 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 0 /* disabled */ +#else +/* (for testing) small multicast group membership table enabled */ +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 4 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 16 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 2 +#endif + +#define CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES 32 +/* + * Specify how much memory the target should allocate for a debug log of + * tx PPDU meta-information (how large the PPDU was, when it was sent, + * whether it was successful, etc.) + * The size of the log records is configurable, from a minimum of 28 bytes + * to a maximum of about 300 bytes. A typical configuration would result + * in each log record being about 124 bytes. + * Thus, 1KB of log space can hold about 30 small records, 3 large records, + * or about 8 typical-sized records. + */ +#define CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE 1024 /* bytes */ + +/* target based fragment timeout and MPDU duplicate detection */ +#define CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0 + +/* Default VoW configuration + */ +#define CFG_TGT_DEFAULT_VOW_CONFIG 0 + +/* + * total number of descriptors to use in the target + */ +#ifndef CFG_TGT_NUM_MSDU_DESC +#define CFG_TGT_NUM_MSDU_DESC (1024 + 32) +#endif + +/* + * Maximum number of frag table entries + */ +#define CFG_TGT_MAX_FRAG_TABLE_ENTRIES 10 + +/* + * Maximum number of VDEV that beacon tx offload will support + */ +#ifndef CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 3 +#endif + +/* + * number of vdevs that can support tdls + */ +#define CFG_TGT_NUM_TDLS_VDEVS 1 + +/* + * number of peers that each Tdls vdev can track + */ +#ifndef CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES 8 +#endif + +/* + * number of TDLS concurrent sleep STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS 1 + +/* + * number of TDLS concurrent buffer STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS 1 + +/* + * ht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_HT_MASK 0x8080 +/* + * vht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_VHT_MASK 0x80200 +/* + * threshold to enable GTX + */ +#define CFG_TGT_DEFAULT_GTX_PER_THRESHOLD 3 +/* + * margin to move back when per > margin + threshold + */ +#define CFG_TGT_DEFAULT_GTX_PER_MARGIN 2 +/* + * step for every move + */ +#define CFG_TGT_DEFAULT_GTX_TPC_STEP 1 +/* + * lowest TPC + */ +#define CFG_TGT_DEFAULT_GTX_TPC_MIN 0 +/* + * enable all BW 20/40/80/160 + */ +#define CFG_TGT_DEFAULT_GTX_BW_MASK 0xf + +/* + * number of vdevs that can support OCB + */ +#define CFG_TGT_NUM_OCB_VDEVS 1 + +/* + * maximum number of channels that can do OCB + */ +#define CFG_TGT_NUM_OCB_CHANNELS 2 + +/* + * maximum number of channels in an OCB schedule + */ +#define CFG_TGT_NUM_OCB_SCHEDULES 2 + +/* + * Default TWT AP STA Count + */ +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_SAP_STA_COUNT) +#define CFG_TGT_DEFAULT_TWT_AP_STA_COUNT WLAN_TWT_SAP_STA_COUNT +#else +#define CFG_TGT_DEFAULT_TWT_AP_STA_COUNT 0 +#endif /* WLAN_SUPPORT_TWT && WLAN_TWT_SAP_STA_COUNT */ + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wlan_tgt_def_config_hl.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wlan_tgt_def_config_hl.h new file mode 100644 index 0000000000..88b1ba72e8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wlan_tgt_def_config_hl.h @@ -0,0 +1,311 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WLAN_TGT_DEF_CONFIG_H__ +#define __WLAN_TGT_DEF_CONFIG_H__ + +/* + * TODO: please help to consider if we need a separate config file from LL case. + */ + +/* + * set of default target config , that can be over written by platform + */ + +#ifdef QCA_SUPPORT_INTEGRATED_SOC +#define CFG_TGT_NUM_VDEV 3 /*STA, P2P device, P2P GO/Cli*/ +#else +/* + * default limit of VAPs per device. + */ +#define CFG_TGT_NUM_VDEV 3 +#endif +/* + * We would need 1 AST entry per peer. Scale it by a factor of 2 to minimize + * hash collisions. + * TODO: This scaling factor would be taken care inside the WAL in the future. + */ +#define CFG_TGT_NUM_PEER_AST 2 + +/* # of WDS entries to support. + */ +#define CFG_TGT_WDS_ENTRIES 2 + +/* MAC DMA burst size. 0: 128B - default, 1: 256B, 2: 64B + */ +#define CFG_TGT_DEFAULT_DMA_BURST_SIZE 0 + +/* Fixed delimiters to be inserted after every MPDU + */ +#define CFG_TGT_DEFAULT_MAC_AGGR_DELIM 0 + +/* + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#ifndef CFG_TGT_AST_SKID_LIMIT +#define CFG_TGT_AST_SKID_LIMIT 6 +#endif +/* + * total number of peers per device. + * currently set to 8 to bring up IP3.9 for memory size problem + */ +#define CFG_TGT_NUM_PEERS 8 +/* + * max number of peers per device. + */ +#define CFG_TGT_NUM_PEERS_MAX 8 +/* + * In offload mode target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. This determines + * maximum number of peers supported by target in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_PEERS 0 +/* + * Number of reorder buffers used in offload mode + */ +#define CFG_TGT_NUM_OFFLOAD_REORDER_BUFFS 0 +/* + * keys per peer node + */ +#define CFG_TGT_NUM_PEER_KEYS 2 +/* + * total number of TX/RX data TIDs + */ +#define CFG_TGT_NUM_TIDS (2 * (CFG_TGT_NUM_PEERS + \ + CFG_TGT_NUM_VDEV)) +/* + * max number of Tx TIDS + */ +#define CFG_TGT_NUM_TIDS_MAX (2 * (CFG_TGT_NUM_PEERS_MAX + \ + CFG_TGT_NUM_VDEV)) +/* + * number of multicast keys. + */ +#define CFG_TGT_NUM_MCAST_KEYS 8 +/* + * A value of 3 would probably suffice - one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_PDEV_HANDLERS 8 +/* + * A value of 3 would probably suffice - one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_VDEV_HANDLERS 4 +/* + * set this to 8: + * one for WAL internals (connection pause) + * one for the control stack, + * one for the data stack + * and one for debugging + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_HANDLERS 14 +/* + * set this to 3: one for the control stack, one for + * the data stack, and one for debugging. + * This value may need to be fine tuned, but a constant value will + * probably always be appropriate; it is probably not necessary to + * determine this value dynamically. + */ +#define CFG_TGT_NUM_PEER_HANDLERS 32 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + * this is rome + */ +#define CFG_TGT_DEFAULT_TX_CHAIN_MASK 0x3 +/* + * set this to 0x7 (Peregrine = 3 chains). + * need to be set dynamically based on the HW capability. + * this is rome + */ +#define CFG_TGT_DEFAULT_RX_CHAIN_MASK 0x3 +/* 100 ms for video, best-effort, and background */ +#define CFG_TGT_RX_TIMEOUT_LO_PRI 100 +/* 40 ms for voice*/ +#define CFG_TGT_RX_TIMEOUT_HI_PRI 40 + +/* AR9888 unified is default in ethernet mode */ +#define CFG_TGT_RX_DECAP_MODE (0x2) +/* Decap to native Wifi header */ +#define CFG_TGT_RX_DECAP_MODE_NWIFI (0x1) + +/* Decap to raw mode header */ +#define CFG_TGT_RX_DECAP_MODE_RAW (0x0) + +/* maximum number of pending scan requests */ +#define CFG_TGT_DEFAULT_SCAN_MAX_REQS 0x4 + +/* maximum number of scan event handlers */ +#define CFG_TGT_DEFAULT_SCAN_MAX_HANDLERS 0x4 + +/* maximum number of VDEV that could use BMISS offload */ +#ifndef CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV 0x2 +#endif + +/* maximum number of VDEV offload Roaming to support */ +#ifndef CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV 0x2 +#endif + +/* maximum number of STA VDEVs */ +#ifndef CFG_TGT_DEFAULT_MAX_STA_VDEVS +#define CFG_TGT_DEFAULT_MAX_STA_VDEVS 0 +#endif + +/* maximum number of AP profiles pushed to offload Roaming */ +#define CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES 0x8 + +/* maximum number of VDEV offload GTK to support */ +#ifndef CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV +#define CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV 0x2 +#endif +/* default: mcast->ucast disabled */ + +#define CFG_TGT_DEFAULT_NUM_MCAST_GROUPS 0 +#define CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS 0 +#define CFG_TGT_DEFAULT_MCAST2UCAST_MODE 0 /* disabled */ + +/* + * Specify how much memory the target should allocate for a debug log of + * tx PPDU meta-information (how large the PPDU was, when it was sent, + * whether it was successful, etc.) + * The size of the log records is configurable, from a minimum of 28 bytes + * to a maximum of about 300 bytes. A typical configuration would result + * in each log record being about 124 bytes. + * Thus, 1KB of log space can hold about 30 small records, 3 large records, + * or about 8 typical-sized records. + */ +#define CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE 1024 /* bytes */ + +/* target based fragment timeout and MPDU duplicate detection */ +#define CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 0 +/* Default VoW configuration + */ +#define CFG_TGT_DEFAULT_VOW_CONFIG 0 + +/* + * total number of descriptors to use in the target + */ +#ifndef CFG_TGT_NUM_MSDU_DESC +#define CFG_TGT_NUM_MSDU_DESC (32) +#endif +/* + * Maximum number of frag table entries + */ +#define CFG_TGT_MAX_FRAG_TABLE_ENTRIES 2 + +/* + * number of vdevs that can support tdls + */ +#define CFG_TGT_NUM_TDLS_VDEVS 1 + +/* + * number of peers that each Tdls vdev can track + */ +#ifndef CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES +#define CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES 8 +#endif +/* + * number of TDLS concurrent sleep STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS 1 + +/* + * number of TDLS concurrent buffer STAs + */ +#define CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS 1 + +#define CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES 16 + +/* + * Maximum number of VDEV that beacon tx offload will support + */ +#ifndef CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV +/* For Naples/Rome/Tufello */ +#ifdef HIF_SDIO +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 2 +#else +#define CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV 1 +#endif +#endif /* CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV */ + +/* + * ht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_HT_MASK 0x8080 +/* + * vht enable highest MCS by default + */ +#define CFG_TGT_DEFAULT_GTX_VHT_MASK 0x80200 +/* + * threshold to enable GTX + */ +#define CFG_TGT_DEFAULT_GTX_PER_THRESHOLD 3 +/* + * margin to move back when per > margin + threshold + */ +#define CFG_TGT_DEFAULT_GTX_PER_MARGIN 2 +/* + * step for every move + */ +#define CFG_TGT_DEFAULT_GTX_TPC_STEP 1 +/* + * lowest TPC + */ +#define CFG_TGT_DEFAULT_GTX_TPC_MIN 0 +/* + * enable all BW 20/40/80/160 + */ +#define CFG_TGT_DEFAULT_GTX_BW_MASK 0xf + +/* + * number of vdevs that can support OCB + */ +#define CFG_TGT_NUM_OCB_VDEVS 1 + +/* + * maximum number of channels that can do OCB + */ +#define CFG_TGT_NUM_OCB_CHANNELS 2 + +/* + * maximum number of channels in an OCB schedule + */ +#define CFG_TGT_NUM_OCB_SCHEDULES 2 + +/* + * Default TWT AP STA Count + */ +#define CFG_TGT_DEFAULT_TWT_AP_STA_COUNT 0 + +#endif /*__WLAN_TGT_DEF_CONFIG_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wni_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wni_api.h new file mode 100644 index 0000000000..b67e3646c1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wni_api.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file wni_api.h contains message definitions exported by + * Sirius software modules. + * NOTE: See projects/sirius/include/sir_api.h for structure + * definitions of the host/FW messages. + * + * Author: Chandra Modumudi + * Date: 04/11/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __WNI_API_H +#define __WNI_API_H + +#include "sir_api.h" + +#define SIR_SME_MSG_TYPES_BEGIN (SIR_SME_MODULE_ID << 8) + +enum eWniMsgTypes { + eWNI_SME_MSG_TYPES_BEGIN = SIR_SME_MSG_TYPES_BEGIN, + eWNI_SME_SYS_READY_IND = SIR_SME_MSG_TYPES_BEGIN + 1, + eWNI_SME_JOIN_REQ = SIR_SME_MSG_TYPES_BEGIN + 2, + eWNI_SME_JOIN_RSP = SIR_SME_MSG_TYPES_BEGIN + 3, + eWNI_SME_SETCONTEXT_RSP = SIR_SME_MSG_TYPES_BEGIN + 5, + eWNI_SME_REASSOC_REQ = SIR_SME_MSG_TYPES_BEGIN + 6, + eWNI_SME_REASSOC_RSP = SIR_SME_MSG_TYPES_BEGIN + 7, + eWNI_SME_DISASSOC_REQ = SIR_SME_MSG_TYPES_BEGIN + 8, + eWNI_SME_DISASSOC_RSP = SIR_SME_MSG_TYPES_BEGIN + 9, + eWNI_SME_DISASSOC_IND = SIR_SME_MSG_TYPES_BEGIN + 10, + eWNI_SME_DISASSOC_CNF = SIR_SME_MSG_TYPES_BEGIN + 11, + eWNI_SME_DEAUTH_REQ = SIR_SME_MSG_TYPES_BEGIN + 12, + eWNI_SME_DEAUTH_RSP = SIR_SME_MSG_TYPES_BEGIN + 13, + eWNI_SME_DEAUTH_IND = SIR_SME_MSG_TYPES_BEGIN + 14, + eWNI_SME_DISCONNECT_DONE_IND = SIR_SME_MSG_TYPES_BEGIN + 15, + eWNI_SME_START_BSS_REQ = SIR_SME_MSG_TYPES_BEGIN + 19, + eWNI_SME_START_BSS_RSP = SIR_SME_MSG_TYPES_BEGIN + 20, + eWNI_SME_ASSOC_IND = SIR_SME_MSG_TYPES_BEGIN + 21, + eWNI_SME_ASSOC_CNF = SIR_SME_MSG_TYPES_BEGIN + 22, + eWNI_SME_SWITCH_CHL_IND = SIR_SME_MSG_TYPES_BEGIN + 23, + eWNI_SME_STOP_BSS_REQ = SIR_SME_MSG_TYPES_BEGIN + 24, + eWNI_SME_STOP_BSS_RSP = SIR_SME_MSG_TYPES_BEGIN + 25, + eWNI_SME_DEAUTH_CNF = SIR_SME_MSG_TYPES_BEGIN + 26, + eWNI_SME_MIC_FAILURE_IND = SIR_SME_MSG_TYPES_BEGIN + 27, + eWNI_SME_ADDTS_REQ = SIR_SME_MSG_TYPES_BEGIN + 28, + eWNI_SME_ADDTS_RSP = SIR_SME_MSG_TYPES_BEGIN + 29, + eWNI_SME_DELTS_REQ = SIR_SME_MSG_TYPES_BEGIN + 30, + eWNI_SME_DELTS_RSP = SIR_SME_MSG_TYPES_BEGIN + 31, + eWNI_SME_DELTS_IND = SIR_SME_MSG_TYPES_BEGIN + 32, + eWNI_SME_MSCS_REQ = SIR_SME_MSG_TYPES_BEGIN + 33, + eWNI_SME_RECONFIG_OBSS_SCAN_PARAM = SIR_SME_MSG_TYPES_BEGIN + 34, + + /* unused SIR_SME_MSG_TYPES_BEGIN + 35 */ + + eWNI_SME_ASSOC_IND_UPPER_LAYER = SIR_SME_MSG_TYPES_BEGIN + 36, + eWNI_SME_WPS_PBC_PROBE_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 37, + eWNI_SME_UPPER_LAYER_ASSOC_CNF = SIR_SME_MSG_TYPES_BEGIN + 38, + eWNI_SME_SESSION_UPDATE_PARAM = SIR_SME_MSG_TYPES_BEGIN + 39, + eWNI_SME_CHNG_MCC_BEACON_INTERVAL = SIR_SME_MSG_TYPES_BEGIN + 40, + eWNI_SME_GET_SNR_REQ = SIR_SME_MSG_TYPES_BEGIN + 41, + + eWNI_SME_RRM_MSG_TYPE_BEGIN = SIR_SME_MSG_TYPES_BEGIN + 42, + + eWNI_SME_NEIGHBOR_REPORT_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 43, + eWNI_SME_NEIGHBOR_REPORT_IND = SIR_SME_MSG_TYPES_BEGIN + 44, + eWNI_SME_BEACON_REPORT_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 45, + eWNI_SME_BEACON_REPORT_RESP_XMIT_IND = SIR_SME_MSG_TYPES_BEGIN + 46, + eWNI_SME_CHAN_LOAD_REQ_IND = SIR_SME_MSG_TYPES_BEGIN + 47, + eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND = SIR_SME_MSG_TYPES_BEGIN + 48, + eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ = SIR_SME_MSG_TYPES_BEGIN + 49, + eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP = SIR_SME_MSG_TYPES_BEGIN + 50, + + /* unused SIR_SME_MSG_TYPES_BEGIN + 51 */ + eWNI_SME_FT_AGGR_QOS_REQ = SIR_SME_MSG_TYPES_BEGIN + 52, + eWNI_SME_FT_AGGR_QOS_RSP = SIR_SME_MSG_TYPES_BEGIN + 53, + +#if defined FEATURE_WLAN_ESE + eWNI_SME_ESE_ADJACENT_AP_REPORT = SIR_SME_MSG_TYPES_BEGIN + 54, +#endif + + eWNI_SME_REGISTER_MGMT_FRAME_REQ = SIR_SME_MSG_TYPES_BEGIN + 55, + eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE = SIR_SME_MSG_TYPES_BEGIN + 56, + eWNI_SME_MAX_ASSOC_EXCEEDED = SIR_SME_MSG_TYPES_BEGIN + 57, +#ifdef FEATURE_WLAN_TDLS + eWNI_SME_TDLS_SEND_MGMT_REQ = SIR_SME_MSG_TYPES_BEGIN + 58, + eWNI_SME_TDLS_SEND_MGMT_RSP = SIR_SME_MSG_TYPES_BEGIN + 59, + eWNI_SME_TDLS_ADD_STA_REQ = SIR_SME_MSG_TYPES_BEGIN + 60, + eWNI_SME_TDLS_ADD_STA_RSP = SIR_SME_MSG_TYPES_BEGIN + 61, + eWNI_SME_TDLS_DEL_STA_REQ = SIR_SME_MSG_TYPES_BEGIN + 62, + eWNI_SME_TDLS_DEL_STA_RSP = SIR_SME_MSG_TYPES_BEGIN + 63, + eWNI_SME_TDLS_DEL_STA_IND = SIR_SME_MSG_TYPES_BEGIN + 64, + eWNI_SME_TDLS_DEL_ALL_PEER_IND = SIR_SME_MSG_TYPES_BEGIN + 65, + eWNI_SME_MGMT_FRM_TX_COMPLETION_IND = SIR_SME_MSG_TYPES_BEGIN + 66, + eWNI_SME_TDLS_LINK_ESTABLISH_REQ = SIR_SME_MSG_TYPES_BEGIN + 67, + eWNI_SME_TDLS_LINK_ESTABLISH_RSP = SIR_SME_MSG_TYPES_BEGIN + 68, + eWNI_SME_TDLS_SHOULD_DISCOVER = SIR_SME_MSG_TYPES_BEGIN + 69, + eWNI_SME_TDLS_SHOULD_TEARDOWN = SIR_SME_MSG_TYPES_BEGIN + 70, + eWNI_SME_TDLS_PEER_DISCONNECTED = SIR_SME_MSG_TYPES_BEGIN + 71, +#endif + eWNI_SME_UNPROT_MGMT_FRM_IND = SIR_SME_MSG_TYPES_BEGIN + 74, +#ifdef WLAN_FEATURE_GTK_OFFLOAD + eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP = SIR_SME_MSG_TYPES_BEGIN + 75, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + eWNI_SME_GET_TSM_STATS_REQ = SIR_SME_MSG_TYPES_BEGIN + 80, + eWNI_SME_GET_TSM_STATS_RSP = SIR_SME_MSG_TYPES_BEGIN + 81, + eWNI_SME_TSM_IE_IND = SIR_SME_MSG_TYPES_BEGIN + 82, + + /* DFS EVENTS */ + /* RADAR found indication from DFS */ + eWNI_SME_DFS_RADAR_FOUND = SIR_SME_MSG_TYPES_BEGIN + 83, + /* Channel Change Request from SAP */ + eWNI_SME_CHANNEL_CHANGE_REQ = SIR_SME_MSG_TYPES_BEGIN + 84, + /* Channel Change Response from WMA */ + eWNI_SME_CHANNEL_CHANGE_RSP = SIR_SME_MSG_TYPES_BEGIN + 85, + /* Start Beacon Transmission. */ + eWNI_SME_START_BEACON_REQ = SIR_SME_MSG_TYPES_BEGIN + 86, + /* Transmit CSA IE in beacons */ + eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ = SIR_SME_MSG_TYPES_BEGIN + 87, + /* To indicate completion of CSA IE */ + eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND = SIR_SME_MSG_TYPES_BEGIN + 88, + /* update in beacons/probe rsp */ + eWNI_SME_STATS_EXT_EVENT = SIR_SME_MSG_TYPES_BEGIN + 89, + /* Unused SIR_SME_MSG_TYPES_BEGIN + 90 */ + eWNI_SME_GET_PEER_INFO_EXT_IND = SIR_SME_MSG_TYPES_BEGIN + 91, + /* indicates Additional IE from hdd to PE */ + eWNI_SME_UPDATE_ADDITIONAL_IES = SIR_SME_MSG_TYPES_BEGIN + 93, + /* To indicate IE modify from hdd to PE */ + eWNI_SME_MODIFY_ADDITIONAL_IES = SIR_SME_MSG_TYPES_BEGIN + 94, +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + eWNI_SME_AUTO_SHUTDOWN_IND = SIR_SME_MSG_TYPES_BEGIN + 95, +#endif +#ifdef QCA_HT_2040_COEX + eWNI_SME_SET_HT_2040_MODE = SIR_SME_MSG_TYPES_BEGIN + 96, +#endif +#ifdef WLAN_FEATURE_NAN + eWNI_SME_NAN_EVENT = SIR_SME_MSG_TYPES_BEGIN + 98, +#endif + eWNI_SME_LINK_STATUS_IND = SIR_SME_MSG_TYPES_BEGIN + 99, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + eWNI_SME_READY_TO_EXTWOW_IND = SIR_SME_MSG_TYPES_BEGIN + 100, +#endif + eWNI_SME_MSG_GET_TEMPERATURE_IND = SIR_SME_MSG_TYPES_BEGIN + 101, + eWNI_SME_SNR_IND = SIR_SME_MSG_TYPES_BEGIN + 102, +#ifdef FEATURE_WLAN_EXTSCAN + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND = SIR_SME_MSG_TYPES_BEGIN + 103, + eWNI_SME_EPNO_NETWORK_FOUND_IND = SIR_SME_MSG_TYPES_BEGIN + 104, +#endif + eWNI_SME_SET_HW_MODE_REQ = SIR_SME_MSG_TYPES_BEGIN + 105, + eWNI_SME_SET_HW_MODE_RESP = SIR_SME_MSG_TYPES_BEGIN + 106, + eWNI_SME_HW_MODE_TRANS_IND = SIR_SME_MSG_TYPES_BEGIN + 107, + eWNI_SME_NSS_UPDATE_REQ = SIR_SME_MSG_TYPES_BEGIN + 108, + eWNI_SME_NSS_UPDATE_RSP = SIR_SME_MSG_TYPES_BEGIN + 109, + eWNI_SME_OCB_SET_CONFIG_RSP = SIR_SME_MSG_TYPES_BEGIN + 110, + eWNI_SME_OCB_GET_TSF_TIMER_RSP = SIR_SME_MSG_TYPES_BEGIN + 111, + eWNI_SME_DCC_GET_STATS_RSP = SIR_SME_MSG_TYPES_BEGIN + 112, + eWNI_SME_DCC_UPDATE_NDL_RSP = SIR_SME_MSG_TYPES_BEGIN + 113, + eWNI_SME_DCC_STATS_EVENT = SIR_SME_MSG_TYPES_BEGIN + 114, + eWNI_SME_SET_DUAL_MAC_CFG_REQ = SIR_SME_MSG_TYPES_BEGIN + 115, + eWNI_SME_SET_DUAL_MAC_CFG_RESP = SIR_SME_MSG_TYPES_BEGIN + 116, + eWNI_SME_SET_THERMAL_LEVEL_IND = SIR_SME_MSG_TYPES_BEGIN + 117, + eWNI_SME_SET_IE_REQ = SIR_SME_MSG_TYPES_BEGIN + 118, + eWNI_SME_EXT_CHANGE_CHANNEL = SIR_SME_MSG_TYPES_BEGIN + 119, + eWNI_SME_EXT_CHANGE_CHANNEL_IND = SIR_SME_MSG_TYPES_BEGIN + 120, + eWNI_SME_REGISTER_MGMT_FRAME_CB = SIR_SME_MSG_TYPES_BEGIN + 121, + /* START and UPDATE OBSS SCAN Indication*/ + eWNI_SME_HT40_OBSS_SCAN_IND = SIR_SME_MSG_TYPES_BEGIN + 122, + eWNI_SME_SET_ANTENNA_MODE_REQ = SIR_SME_MSG_TYPES_BEGIN + 123, + eWNI_SME_SET_ANTENNA_MODE_RESP = SIR_SME_MSG_TYPES_BEGIN + 124, + eWNI_SME_TSF_EVENT = SIR_SME_MSG_TYPES_BEGIN + 125, + eWNI_SME_MON_INIT_SESSION = SIR_SME_MSG_TYPES_BEGIN + 126, + eWNI_SME_PDEV_SET_HT_VHT_IE = SIR_SME_MSG_TYPES_BEGIN + 127, + eWNI_SME_SET_VDEV_IES_PER_BAND = SIR_SME_MSG_TYPES_BEGIN + 128, + eWNI_SME_SEND_DISASSOC_FRAME = SIR_SME_MSG_TYPES_BEGIN + 129, + eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE = SIR_SME_MSG_TYPES_BEGIN + 130, + eWNI_SME_DEFAULT_SCAN_IE = SIR_SME_MSG_TYPES_BEGIN + 131, + /* 133 unused */ + eWNI_SME_LOST_LINK_INFO_IND = SIR_SME_MSG_TYPES_BEGIN + 134, + eWNI_SME_DEL_ALL_TDLS_PEERS = SIR_SME_MSG_TYPES_BEGIN + 135, + eWNI_SME_RSO_CMD_STATUS_IND = SIR_SME_MSG_TYPES_BEGIN + 136, + eWMI_SME_LL_STATS_IND = SIR_SME_MSG_TYPES_BEGIN + 137, + eWNI_SME_DFS_CAC_COMPLETE = SIR_SME_MSG_TYPES_BEGIN + 138, + eWNI_SME_UPDATE_CONFIG = SIR_SME_MSG_TYPES_BEGIN + 139, + eWNI_SME_BT_ACTIVITY_INFO_IND = SIR_SME_MSG_TYPES_BEGIN + 140, + eWNI_SME_SET_HE_BSS_COLOR = SIR_SME_MSG_TYPES_BEGIN + 141, + eWNI_SME_TRIGGER_SAE = SIR_SME_MSG_TYPES_BEGIN + 142, + eWNI_SME_SEND_MGMT_FRAME_TX = SIR_SME_MSG_TYPES_BEGIN + 143, + eWNI_SME_SEND_SAE_MSG = SIR_SME_MSG_TYPES_BEGIN + 144, + eWNI_SME_SET_ADDBA_ACCEPT = SIR_SME_MSG_TYPES_BEGIN + 145, + eWNI_SME_UPDATE_EDCA_PROFILE = SIR_SME_MSG_TYPES_BEGIN + 146, + WNI_SME_UPDATE_MU_EDCA_PARAMS = SIR_SME_MSG_TYPES_BEGIN + 147, + eWNI_SME_CSA_RESTART_REQ = SIR_SME_MSG_TYPES_BEGIN + 148, + eWNI_SME_CSA_RESTART_RSP = SIR_SME_MSG_TYPES_BEGIN + 149, + WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU = SIR_SME_MSG_TYPES_BEGIN + 150, + /* To indicate Hidden ssid start complition to upper layer */ + eWNI_SME_HIDDEN_SSID_RESTART_RSP = SIR_SME_MSG_TYPES_BEGIN + 151, + eWNI_SME_FW_STATUS_IND = SIR_SME_MSG_TYPES_BEGIN + 152, + eWNI_SME_STA_CSA_CONTINUE_REQ = SIR_SME_MSG_TYPES_BEGIN + 153, + /* 154 unused */ + eWNI_SME_ANTENNA_ISOLATION_RSP = SIR_SME_MSG_TYPES_BEGIN + 155, + eWNI_SME_MON_DEINIT_SESSION = SIR_SME_MSG_TYPES_BEGIN + 156, + eWNI_SME_VDEV_DELETE_RSP = SIR_SME_MSG_TYPES_BEGIN + 157, + /* 158, 159 unused */ + eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT = + SIR_SME_MSG_TYPES_BEGIN + 160, + eWNI_SME_MONITOR_MODE_VDEV_UP = SIR_SME_MSG_TYPES_BEGIN + 161, + eWNI_SME_UPDATE_SESSION_EDCA_TXQ_PARAMS = SIR_SME_MSG_TYPES_BEGIN + 162, + /* 164 unused */ + eWNI_SME_TWT_ADD_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 165, + eWNI_SME_TWT_DEL_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 166, + eWNI_SME_TWT_PAUSE_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 167, + eWNI_SME_TWT_RESUME_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 168, + eWNI_SME_TWT_NUDGE_DIALOG_EVENT = SIR_SME_MSG_TYPES_BEGIN + 169, + eWNI_SME_TWT_NOTIFY_EVENT = SIR_SME_MSG_TYPES_BEGIN + 170, + CM_BSS_PEER_CREATE_REQ = SIR_SME_MSG_TYPES_BEGIN + 171, + CM_CONNECT_REQ = SIR_SME_MSG_TYPES_BEGIN + 172, + CM_DISCONNECT_REQ = SIR_SME_MSG_TYPES_BEGIN + 173, + CM_REASSOC_REQ = SIR_SME_MSG_TYPES_BEGIN + 174, + CM_PREAUTH_REQ = SIR_SME_MSG_TYPES_BEGIN + 175, + eWNI_SME_CSA_REQ = SIR_SME_MSG_TYPES_BEGIN + 176, + CM_ABORT_CONN_TIMER = SIR_SME_MSG_TYPES_BEGIN + 177, + WIFI_POS_PASN_PEER_DELETE_ALL = SIR_SME_MSG_TYPES_BEGIN + 178, + eWNI_SME_CHAN_INFO_EVENT = SIR_SME_MSG_TYPES_BEGIN + 179, + eWNI_SME_MSG_TYPES_END = SIR_SME_MSG_TYPES_BEGIN + 180, + eWNI_SME_VDEV_PAUSE_IND = SIR_SME_MSG_TYPES_BEGIN + 181 +}; + +typedef struct sAniCfgTxRateCtrs { +/* add the rate counters here */ + unsigned long TxFrames_1Mbps; + unsigned long TxFrames_2Mbps; + unsigned long TxFrames_5_5Mbps; + unsigned long TxFrames_6Mbps; + unsigned long TxFrames_9Mbps; + unsigned long TxFrames_11Mbps; + unsigned long TxFrames_12Mbps; + unsigned long TxFrames_18Mbps; + unsigned long TxFrames_24Mbps; + unsigned long TxFrames_36Mbps; + unsigned long TxFrames_48Mbps; + unsigned long TxFrames_54Mbps; + unsigned long TxFrames_72Mbps; + unsigned long TxFrames_96Mbps; + unsigned long TxFrames_108Mbps; + +} tAniCfgTxRateCtrs, *tpAniCfgTxRateCtrs; +#endif /* __WNI_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wni_cfg.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wni_cfg.h new file mode 100644 index 0000000000..0b978a5c70 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/inc/wni_cfg.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WNICFG_H +#define __WNICFG_H + +/* + * String parameter lengths + */ + +#define WNI_CFG_VALID_CHANNEL_LIST_LEN 100 +#define WNI_CFG_COUNTRY_CODE_LEN 3 +#define WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN 255 +#define WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN 255 +#define WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN 255 +#define WNI_CFG_WPS_UUID_LEN 16 +#define WNI_CFG_HE_PPET_LEN 25 + +/* + * Integer parameter min/max/default values + */ +#define WNI_CFG_PHY_MODE_11A 0 +#define WNI_CFG_PHY_MODE_11B 1 +#define WNI_CFG_PHY_MODE_11G 2 +#define WNI_CFG_PHY_MODE_NONE 3 + +#define WNI_CFG_CURRENT_CHANNEL_STAMIN 0 +#define WNI_CFG_CURRENT_CHANNEL_STAMAX 173 + +#define WNI_CFG_EDCA_PROFILE_ANI 0 +#define WNI_CFG_EDCA_PROFILE_WMM 1 +#define WNI_CFG_EDCA_PROFILE_ETSI_EUROPE 3 +#define WNI_CFG_EDCA_PROFILE_MAX 4 + +#define WNI_CFG_ADMIT_POLICY_ADMIT_ALL 0 +#define WNI_CFG_ADMIT_POLICY_REJECT_ALL 1 +#define WNI_CFG_ADMIT_POLICY_BW_FACTOR 2 + +#define WNI_CFG_CHANNEL_BONDING_MODE_DISABLE 0 +#define WNI_CFG_CHANNEL_BONDING_MODE_ENABLE 1 + +#define WNI_CFG_BLOCK_ACK_ENABLED_DELAYED 0 +#define WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE 1 + +#define WNI_CFG_HT_CAP_INFO_ADVANCE_CODING 0 +#define WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ 5 +#define WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ 6 +#define WNI_CFG_HT_CAP_INFO_TX_STBC 7 +#define WNI_CFG_HT_CAP_INFO_RX_STBC 8 + +#define WNI_CFG_GREENFIELD_CAPABILITY_DISABLE 0 + +/* + * WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF + 1 is + * assumed to be the default fw supported BF antennas, if fw + * says it supports 8 antennas in rx ready event and if + * gTxBFCsnValue INI value is configured above 3, set + * the same to WNI_CFG_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED. + * Otherwise, fall back and set fw default value[3]. + */ + +#define WNI_CFG_WPS_ENABLE_AP 1 + +#define WNI_CFG_REMOVE_TIME_SYNC_CMD_STAMIN 0 +#define WNI_CFG_REMOVE_TIME_SYNC_CMD_STAMAX 1 +#define WNI_CFG_REMOVE_TIME_SYNC_CMD_STADEF 0 + +#define CFG_STA_MAGIC_DWORD 0xbeefbeef + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms new file mode 100644 index 0000000000..aaa6df3597 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/cfg/cfgUtil/dot11f.frms @@ -0,0 +1,5135 @@ +/* + * Copyright (c) 2006-2007, 2014-2018, 2020-2021 The Linux Foundation. + * All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * \file dot11f.frms + * + * \brief Primary 'frames' file for the MAC parser + * + * + * This file defines several 802.11 frames (along with their associated + * constituents) in a little language called "frames". When run through the + * 'framesc' program, it will generate C code for working with these frames: + * C structs representing the 802.11 frame together with functions for + * packing & unpacking them. + * + * For more information on the "frames" language, run 'framesc --help'... + * + * + */ + + +// Tell framesc what types to use for... +%8-bit-type uint8_t // 8, +%16-bit-type uint16_t // 16, +%32-bit-type uint32_t // & 32-bit unsigned integral types. These can also + // be specified on the command line. + +// Define some mnemonic constants; these are just for our use with the frames +// files we're compiling. IOW, they won't result in any C code being +// emitted. + +const EID_SSID = 0; +const EID_SUPP_RATES = 1; +const EID_FH_PARAM_SET = 2; +const EID_DS_PARAM_SET = 3; +const EID_CF_PARAM_SET = 4; +const EID_TIM = 5; +const EID_IBSS_PARAM_SET = 6; +const EID_COUNTRY = 7; +const EID_FH_PATTERN = 8; +const EID_FH_PATT_TABLE = 9; +const EID_REQUEST = 10; +const EID_QBSS_LOAD = 11; +const EID_EDCA_PARAM_SET = 12; +const EID_TSPEC = 13; +const EID_TCLAS = 14; +const EID_SCHEDULE = 15; +const EID_CHALLENGE_TEXT = 16; +const EID_POWER_CONSTRAINTS = 32; +const EID_POWER_CAPABILITY = 33; +const EID_TPC_REQUEST = 34; +const EID_TPC_REPORT = 35; +const EID_SUPPORTED_CHANNELS = 36; +const EID_CHANNEL_SWITCH_ANN = 37; +const EID_MEAS_REQUEST = 38; +const EID_MEAS_REPORT = 39; +const EID_QUIET = 40; +const EID_ERP_INFO = 42; +const EID_TS_DELAY = 43; +const EID_TCLASS_PROC = 44; +const EID_HT_CAPABILITIES = 45; +const EID_QOS_CAPABILITY = 46; +const EID_RSN = 48; +const EID_EXT_SUPP_RATES = 50; +const EID_AP_CHAN_REPORT = 51; +const EID_NEIGHBOR_REPORT = 52; +const EID_RCPI = 53; +const EID_FT_MOBILITY_DOMAIN = 54; +const EID_FT_INFO = 55; +const EID_TIMEOUT_INTERVAL = 56; +const EID_FT_RIC_DATA = 57; +const EID_SUPPORTED_OPER_CLASSES = 59; +const EID_EXT_CHAN_SWITCH = 60; +const EID_HT_INFO = 61; +const EID_SEC_CHAN_OFFSET = 62; +const EID_RSNI = 65; +const EID_RRM_MEAS_PILOT_TX_INFO = 66; +const EID_WAPI = 68; +const EID_TIME_ADVERTISEMENT = 69; +const EID_RRM_ENABLED_CAPS = 70; +const EID_MULTIPLE_BSSID = 71; +const EID_20_40_BSS_COEXISTENCE = 72; +const EID_20_40_BSS_INTOLERANT_REPORT= 73; +const EID_OBSS_SCAN_PARAMETERS = 74; +const EID_FT_RIC_DESCRIPTOR = 75; +const EID_MSCS_STATUS = 76; +const EID_BSS_MAX_IDLE_PERIOD = 90; +const EID_LINK_IDENTIFIER = 101; +const EID_PTI_CONTROL = 105; +const EID_PU_BUFFER_STATUS = 106; +const EID_QOS_MAP_SET = 110; +const EID_ESE_SPECIFIC = 150; +const EID_ESE_CCKM_SPECIFIC = 156; +const EID_ADDBA_EXTN_ELEMENT = 159; +const EID_VHT_CAPABILITIES = 191; +const EID_VHT_OPERATION_ELEMENT = 192; +const EID_VHT_EXT_BSS_LOAD = 193; +const EID_AID = 197; +const EID_EXT_CAP = 127; +const EID_OPERATING_MODE = 199; +const EID_WIDER_BW_CHANNEL_SWITCH_ANN= 194; +const EID_TRANSMIT_POWER_ENVELOPE = 195; +const EID_CHANNEL_SWITCH_WRAPPER = 196; +const EID_RNR_IE = 201; +const EID_VENDOR_SPECIFIC = 221; +const EID_FILS_INDICATION = 240; +const EID_FRAGMENT_IE = 242; +/** + * Extended Element ID + * + * As part of IEEE-802.11-2016 spec, extended element ID is introduced(9.4.2.1) + * Elements are defined to have a common general format consisting of a 1 octet + * Element ID field, a 1 octet Length field, an optional 1 octet Element ID + * Extension field, and a variable-length element-specific Information field. + * Each element is identified by the contents of the Element ID and, when + * present, Element ID Extension fields as defined in this standard. An Extended + * Element ID is a combination of an Element ID and an Element ID Extension for + * those elements that have a defined Element ID Extension. The Length field + * specifies the number of octets following the Length field. The presence of + * the Element ID Extension field is determined by the Element ID field having + * value of 255 + */ +const EID_EXTN_ID_ELEMENT = 255; + +const SIR_MAC_PROP_EXT_RATES_TYPE = 0; +const SIR_MAC_PROP_AP_NAME_TYPE = 1; +const SIR_MAC_PROP_HCF_TYPE = 2; +const SIR_MAC_PROP_WDS_TYPE = 3; +const SIR_MAC_PROP_BP_IND_TYPE = 4; +const SIR_MAC_PROP_NEIGHBOR_BSS_TYPE = 5; +const SIR_MAC_PROP_LOAD_INFO_TYPE = 6; +const SIR_MAC_PROP_ASSOC_TYPE = 7; +const SIR_MAC_PROP_LOAD_BALANCE_TYPE = 8; +const SIR_MAC_PROP_LL_ATTR_TYPE = 9; +const SIR_MAC_PROP_CAPABILITY = 10; +const SIR_MAC_PROP_VERSION = 11; +const SIR_MAC_PROP_EDCAPARAMS = 12; +const SIR_MAC_PROP_CHANNEL_SWITCH = 15; +const SIR_MAC_PROP_QUIET_BSS = 16; +const SIR_MAC_PROP_TRIG_STA_BK_SCAN = 17; + +const ANI_WDS_INFO_MAX_LENGTH = 64; +const SIR_MAC_MAX_NUMBER_OF_RATES = 12; +const HT_MAX_SUPPORTED_MCS_SET = 16; +const MAX_SUPPORTED_NEIGHBOR_RPT = 15; +const MAX_QOS_DSCP_DATA_LEN = 58; +const QOS_DSCP_RANGE_LEN = 16; + +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Protected Setup TLV Identifiers // +// WSC Version 2.0.0 Table 28 // +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Simple Configuration TLV Identifiers // +// WFA Vendor Extension Subelements // +///////////////////////////////////////////////////////////////////////////// +const TLV_VERSION2 = 0; +const TLV_AUTHORIZED_MAC = 1; +const TLV_NETWORK_KEY_SHAREABLE = 2; +const TLV_REQUEST_TO_ENROLL = 3; +const TLV_SETTINGS_DELAY_TIME = 4; + +const TLV_VERSION = 0x104A; +const TLV_WI_FI_SIMPLE_CONFIG_STATE = 0x1044; +const TLV_AP_SETUP_LOCKED = 0x1057; +const TLV_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053; +const TLV_DEVICE_PASSWORD_ID = 0x1012; +const TLV_UUID_E = 0x1047; +const TLV_UUID_R = 0x1048; +const TLV_RF_BANDS = 0x103C; +const TLV_REQUEST_TYPE = 0x103A; +const TLV_RESPONSE_TYPE = 0x103B; +const TLV_CONFIG_METHODS = 0x1008; +const TLV_PRIMARY_DEVICE_TYPE = 0x1054; +const TLV_ASSOCIATION_STATE = 0x1002; +const TLV_CONFIGURATION_ERROR = 0x1009; +const TLV_MANUFACTURER = 0x1021; +const TLV_MODEL_NAME = 0x1023; +const TLV_MODEL_NUMBER = 0x1024; +const TLV_SERIAL_NUMBER = 0x1042; +const TLV_DEVICE_NAME = 0x1011; +const TLV_SELECTED_REGISTRAR = 0x1041; +const TLV_VENDOR_EXTENSION = 0x1049; +const TLV_REQUESTED_DEVICE_TYPE = 0x106A; + +///////////////////////////////////////////////////////////////////////////// +// Wi-Fi Direct/P2P TLV Identifiers // +///////////////////////////////////////////////////////////////////////////// +const TLV_P2P_STATUS = 0; +const TLV_MINOR_REASON_CODE = 1; +const TLV_P2P_CAPABILITY = 2; +const TLV_P2P_DEVICE_ID = 3; +const TLV_P2P_GROUP_OWNER_INTENT = 4; +const TLV_CONFIGURATION_TIMEOUT = 5; +const TLV_LISTEN_CHANNEL = 6; +const TLV_P2P_GROUP_BSSID = 7; +const TLV_EXTENDED_LISTEN_TIMING = 8; +const TLV_INTENDED_P2P_INTERFACE_ADDRESS = 9; +const TLV_P2P_MANAGEABILITY = 10; +const TLV_CHANNEL_LIST = 11; +const TLV_NOTICE_OF_ABSENCE = 12; +const TLV_P2P_DEVICE_INFO = 13; +const TLV_P2P_GROUP_INFO = 14; +const TLV_P2P_GROUP_ID = 15; +const TLV_P2P_INTERFACE = 16; +const TLV_OPERATING_CHANNEL = 17; +const TLV_INVITATION_FLAGS = 18; +const TLV_P2P_VENDOR_SPECIFIC = 221; + + +///////////////////////////////////////////////////////////////////////////// +// MBO-OCE Attributes (0, 151-255: Reserved) // +///////////////////////////////////////////////////////////////////////////// +const TLV_MBO_AP_CAP_ATTR = 1; +const TLV_NON_PREFERRED_CHAN_REPORT_ATTR = 2; +const TLV_CELLULAR_DATA_CAP_ATTR = 3; +const TLV_ASSOC_DISSALLOWED_ATTR = 4; +const TLV_CELLULAR_DATA_CON_PREF_ATTR = 5; +const TLV_TRANSITION_REASON_CODE_ATTR = 6; +const TLV_TRANSITION_REJECT_REASON_CODE_ATTR = 7; +const TLV_ASSOC_RETRY_DELAY_ATTR = 8; + +// 9-100 : Reserved for MBO // + +// OCE ATTRIBUTES // +const TLV_OCE_CAP_IND_ATTR = 101; +const TLV_RSSI_ASSOC_REJ_ATTR = 102; +const TLV_REDUCED_WAN_METRICS_ATTR = 103; +// 104-150 : Reserved for OCE + + + +///////////////////////////////////////////////////////////////////////////// +// Fixed Fields + +FF AuthAlgo (2) // C.f. Sec. 7.3.1.1 +{ + algo, 2; +} + +FF AuthSeqNo (2) // 7.3.1.2 +{ + no, 2; +} + +FF BeaconInterval (2) // 7.3.1.3 +{ + interval, 2; +} + +FF Capabilities (2) // 7.3.1.4 +{ + { + ess: 1; + ibss: 1; + cfPollable: 1; + cfPollReq: 1; + privacy: 1; + shortPreamble: 1; + criticalUpdateFlag: 1; + channelAgility: 1; + spectrumMgt: 1; + qos: 1; + shortSlotTime: 1; + apsd: 1; + rrm: 1; + dsssOfdm: 1; + delayedBA: 1; + immediateBA: 1; + } +} + +FF CurrentAPAddress(6) // 7.3.1.5 +{ + mac[6]; +} + +FF ListenInterval (2) // 7.3.1.6 +{ + interval, 2; +} + +FF Reason (2) // 7.3.1.7 +{ + code, 2; +} + +FF AID (2) // 7.3.1.8 +{ + associd, 2; +} + +FF Status (2) // 7.3.1.9 +{ + status, 2; +} + +FF TimeStamp (8) // 7.3.1.10 +{ + timestamp, 8; +} + +FF Category (1) // 7.3.1.11 +{ + category, 1; +} + +FF Action (1) // 7.3.1.11 +{ + action, 1; +} + +FF TransactionId (2) // 7.3.1.11 +{ + transId[2]; +} + +FF DialogToken (1) // 7.3.1.12 +{ + token, 1; +} + +FF StatusCode (1) // WMM Spec 2.2.10 +{ + statusCode, 1; +} + +FF p2p_action_oui (4) +{ + oui_data[4]; +} + +FF p2p_action_subtype (1) +{ + subtype, 1; +} + +FF OperatingMode (1) +{ + { + //Operating Mode field + chanWidth: 2; + reserved: 2; + rxNSS: 3; + rxNSSType: 1; + } +} + +FF SMPowerModeSet (1) //7.3.1.25 +{ + { + PowerSave_En: 1; + Mode: 1; + reserved: 6; + } +} + +FF TSInfo (3) // 7.3.2.30 +{ + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + schedule: 1; + unused: 15; + } +} + +FF NumOfRepetitions (2) +{ + repetitions, 2; +} + +FF TxPower (1) +{ + txPower, 1; +} + +FF MaxTxPower (1) +{ + maxTxPower, 1; +} +FF TPCEleID (1) +{ + TPCId, 1; +} +FF TPCEleLen (1) +{ + TPCLen, 1; +} +FF LinkMargin (1) +{ + linkMargin, 1; +} +FF RxAntennaId (1) +{ + antennaId, 1; +} +FF TxAntennaId (1) +{ + antennaId, 1; +} +FF RCPI (1) +{ + rcpi, 1; +} +FF RSNI (1) +{ + rsni, 1; +} + +FF VhtMembershipStatusArray(8) // 8.4.1.51 +{ + membershipStatusArray[8]; +} + +FF VhtUserPositionArray(16) // 8.4.1.52 +{ + userPositionArray[16]; +} + +FF ext_chan_switch_ann_action(4) +{ + { + switch_mode: 8; + op_class: 8; + new_channel: 8; + switch_count: 8; + } +} + +FF addba_param_set(2) +{ + { + amsdu_supp: 1; + policy: 1; + tid: 4; + buff_size: 10; + } +} + +FF ba_timeout(2) +{ + timeout, 2; +} + +FF ba_start_seq_ctrl(2) +{ + { + frag_number: 4; + ssn: 12; + } +} + +FF vendor_oui (3) +{ + oui_data[3]; +} + +FF vendor_action_subtype (1) +{ + subtype, 1; +} + +IE addba_extn_element(EID_ADDBA_EXTN_ELEMENT) +{ + { + no_fragmentation: 1; + he_frag_operation: 2; + reserved: 2; + extd_buff_size: 3; + } +} + +FF delba_param_set(2) +{ + { + reserved: 11; + initiator: 1; + tid: 4; + } +} + +///////////////////////////////////////////////////////////////////////////// +// TLVs // +///////////////////////////////////////////////////////////////////////////// + +/** + * \brief Version + * + * WPS 1.0h + * Version specifies the Easy Setup version. The one-byte field is broken + * into a four-bit major part using the top MSBs and four-bit minor part + * using the LSBs. As an example, version 3.2 would be 0x32. + * + * WSC 2.0.0 + * Deprecated Version mechanism. This attribute is always set to value 0x10 + * (version 1.0) for backwards compatibility. Version 1.0h of the specification + * did not fully describe the version negotiation mechanism and version 2.0 + * introduced a new subelement (Version2) for indicating the version number + * to avoid potential interoperability issues with deployed 1.0h-based devices. + * + */ + +TLV Version( TLV_VERSION ) ( 2 : 2 ) MSB +{ + { + minor: 4; + major: 4; + } +} + +/// Wi-Fi Protected Setup State +TLV WPSState( TLV_WI_FI_SIMPLE_CONFIG_STATE ) ( 2 : 2 ) MSB +{ + state, 1; +} + +/** + * \brief AP Setup Locked + * + * + * This variable indicates that the AP has entered a state in which it will + * refuse to allow an external Registrar to attempt to run the Registration + * Protocol using the AP?s PIN (with the AP acting as Enrollee). The AP + * should enter this state if it believes a brute force attack is underway + * against the AP?s PIN. + * + * When the AP is in this state, it MUST continue to allow other Enrollees to + * connect and run the Registration Protocol with any external Registrars or + * the AP's built-in Registrar (if any). It is only the use of the AP' PIN + * for adding external Registrars that is disabled in this state. + * + * The AP Setup Locked state can be reset to FALSE through an authenticated + * call to SetAPSettings. APs may provide other implementation-specific + * methods of resetting the AP Setup Locked state as well. + * + * + */ + +TLV APSetupLocked( TLV_AP_SETUP_LOCKED ) ( 2 : 2 ) MSB +{ + fLocked, 1; +} + +/** + * \brief Selected Registrar Config Methods + * + * + * This attribute has the same values that Config Methods have. It is used in + * Probe Response messages to convey the Config Methods of the selected + * Registrar. + * + * + */ + +TLV SelectedRegistrarConfigMethods ( TLV_SELECTED_REGISTRAR_CONFIG_METHODS ) ( 2 : 2 ) MSB +{ + methods, 2; +} + +/** + * \brief UUID-E + * + * + * The universally unique identifier (UUID) element is a unique GUID + * generated by the Enrollee. It uniquely identifies an operational device + * and should survive reboots and resets. The UUID is provided in binary + * format. If the device also supports UPnP, then the UUID corresponds to the + * UPnP UUID. + * + * + */ + +TLV UUID_E ( TLV_UUID_E ) ( 2 : 2 ) MSB +{ + uuid[ 16 ]; +} + +/** + * \brief UUID-R + * + * + * The universally unique identifier (UUID) element is a unique GUID + * generated by the Registrar. It uniquely identifies an operational device + * and should survive reboots and resets. The UUID is provided in binary + * format. If the device also supports UPnP, then the UUID corresponds to the + * UPnP UUID. + * + * + */ + +TLV UUID_R ( TLV_UUID_R ) ( 2 : 2 ) MSB +{ + uuid[ 16 ]; +} + +/** + * \brief RF Bands + * + * + \code + + 0x01 2.4GHz + 0x02 5.0GHz + + \endcode + * + * + */ + +TLV RFBands ( TLV_RF_BANDS ) ( 2 : 2 ) MSB +{ + bands, 1; +} + + +/** + * \brief Selected Registrar + * + * + * This field indicates that a Registrar has been selected by a user and that + * an Enrollee should proceed with setting up an 802.1X uncontrolled data + * port with the Registrar. + * + * + */ + +TLV SelectedRegistrar ( TLV_SELECTED_REGISTRAR ) ( 2 : 2 ) MSB +{ + selected, 1; +} + +/** + * \brief Config Methods + * + * + * The Config Methods Data component lists the configuration methods the + * Enrollee or Registrar supports. The list is a bitwise OR of values from + * the table below. In addition to Config Methods, APs and STAs that support + * the UPnP Management Interface must support the Permitted Config Methods + * attribute, which is used to control the Config Methods that are enabled on + * that AP. + * + \code + + Value Hardware Interface + 0x0001 USBA (Flash Drive) + 0x0002 Ethernet + 0x0004 Label + 0x0008 Display + 0x0010 External NFC Token + 0x0020 Integrated NFC Token + 0x0040 NFC Interface + 0x0080 PushButton + 0x0100 Keypad + + \endcode + * + * + */ + +TLV ConfigMethods ( TLV_CONFIG_METHODS ) ( 2 : 2 ) MSB +{ + methods, 2; +} + +/** + * \brief Association State + * + * + * The Association State component shows the configuration and previous + * association state of the wireless station when sending a Discovery + * request. + * + \code + + Association State Description + 0 Not Associated + 1 Connection Success + 2 Configuration Failure + 3 Association Failure + 4 IP Failure + + \endcode + * + * + */ + +TLV AssociationState ( TLV_ASSOCIATION_STATE ) ( 2 : 2 ) MSB +{ + state, 2; +} + +/** + * \brief Configuration Error + * + * + * The Configuration Error component shows the result of the device + * attempting to configure itself and to associate with the WLAN. + * + \code + + Configuration Error Description + 0 No Error + 1 OOB Interface Read Error + 2 Decryption CRC Failure + 3 2.4 channel not supported + 4 5.0 channel not supported + 5 Signal too weak + 6 Network auth failure + 7 Network association failure + 8 No DHCP response + 9 Failed DHCP config + 10 IP address conflict + 11 Couldn't connect to Registrar + 12 Multiple PBC sessions detected + 13 Rogue activity suspected + 14 Device busy + 15 Setup locked + 16 Message Timeout + 17 Registration Session Timeout + 18 Device Password Auth Failure + + \endcode + * + * The Device busy error is returned if the sending device is unable to + * respond to the request due to some internal conflict or resource + * contention issue. For example, if a device is only capable of performing a + * single instance of the Registration Protocol at a time, it may return this + * error in response to attempts to start another instance in the middle of + * an active session. + * + * + */ + +TLV ConfigurationError ( TLV_CONFIGURATION_ERROR ) ( 2 : 2 ) MSB +{ + error, 2; +} + +TLV Manufacturer ( TLV_MANUFACTURER ) ( 2 : 2 ) MSB +{ + name[ 0..64 ]; +} + +TLV ModelName ( TLV_MODEL_NAME ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV ModelNumber ( TLV_MODEL_NUMBER ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV SerialNumber ( TLV_SERIAL_NUMBER ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +TLV DeviceName ( TLV_DEVICE_NAME ) ( 2 : 2 ) MSB +{ + text[ 0..32 ]; +} + +/** + * \brief Device Password ID + * + * + * This attribute is used to identify a device password. There are six + * predefined values and ten reserved values. If the Device Password ID is + * Default, the Enrollee should use its PIN password (from the label or + * display). This password may correspond to the label, display, or a + * user-defined password that has been configured to replace the original + * device password. + * + * User-specified indicates that the user has overridden the password with a + * manually selected value. Machine-specified indicates that the original + * PIN password has been overridden by a strong, machinegenerated device + * password value. The Rekey value indicates that the device's 256-bit + * rekeying password will be used. The PushButton value indicates that the + * PIN is the all-zero value reserved for the PushButton Configuration + * method. + * + * The Registrar-specified value indicates a PIN that has been obtained from + * the Registrar (via a display or other out-of-band method). This value may + * be further augmented with the optional 'Identity' attribute in M1. This + * augmentation is useful when multiple predefined UserID/PIN pairs have been + * established by a Registrar such as an authenticator used for Hotspot + * access. If the Device Password ID in M1 is not one of the predefined or + * reserved values, it corresponds to a password given to the Registrar as an + * OOB Device Password. + * + \code + + Value Description + + 0x0000 Default (PIN) + 0x0001 User-specified + 0x0002 Machine-specified + 0x0003 Rekey + 0x0004 PushButton + 0x0005 Registrar-specified + 0x0006 - 0x000F Reserved + + \endcode + * + * + */ + +TLV DevicePasswordID ( TLV_DEVICE_PASSWORD_ID ) ( 2 : 2 ) MSB +{ + id, 2; +} + + +/** + * \brief Primary Device Type + * + * + * This attribute contains the primary type of the device. Its format + * follows: + * + \code + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Attribute ID | Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Category ID | OUI (1-2) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OUI (3-4) | Sub Category ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + \endcode + * + * Vendor-specific sub-categories are designated by setting the OUI to the + * value associated with that vendor. Note that a four-byte subdivided OUI + * is used. For the predefined values, the Wi-Fi Alliance OUI of 00 50 F2 04 + * is used. The predefined values for Category ID and Sub Category ID are + * provided in the next table. There is no way to indicate a vendor-specific + * main device category. The OUI applies only to the interpretation of the + * Sub Category. If a vendor does not use sub categories for their OUI, the + * three-byte OUI occupies the first three bytes of the OUI field and the + * fourth byte is set to zero. + * + * + \code + + Category ID Value Sub Category ID Value + Computer 1 PC 1 + Server 2 + Media Center 3 + Input Device 2 + Printers, Scanners, Printer 1 + Faxes and Copiers 3 Scanner 2 + Camera 4 Digital Still Camera 1 + Storage 5 NAS 1 + Network AP 1 + Infrastructure 6 Router 2 + Switch 3 + Displays 7 Television 1 + Electronic Picture Frame 2 + Projector 3 + Multimedia Devices 8 DAR 1 + PVR 2 + MCX 3 + Gaming Devices 9 Xbox 1 + Xbox360 2 + Playstation 3 + Telephone 10 Windows Mobile 1 + + \endcode + * + * + */ + +TLV PrimaryDeviceType ( TLV_PRIMARY_DEVICE_TYPE ) ( 2 : 2 ) MSB +{ + primary_category, 2; + oui[ 4 ]; + sub_category, 2; +} + + +/** + * \brief Request Type + * + * + * The Request Type component specifies the mode in which the device will + * operate in for this setup exchange. If the device is an Enrollee, it may + * send only discovery messages or it may also request that the Registrar + * proceed with opening a data connection. This protocol allows Enrollees to + * more efficiently discover devices on the network. + + * If the device indicates that it intends to engage setup either as a + * Registrar or an Enrollee, the Access Point continues to indicate that it + * will operate as an AP in the response. The Request Type attribute is + * carried throughout the 802.1X data channel setup process in the Wi-Fi + * Protected Setup IE. There are two sub-types of Registrars: WLAN Manager + * Registrar indicates that this Registrar intends to manage the AP or STA + * settings using UPnP. It will derive a UPnP AP or STA Management key. The + * ordinary Registrar type indicates that this Registrar does not intend to + * subsequently manage the Enrollee's settings. APs must not derive AP + * Management Keys for an ordinary Registrar. If a Registrar does not intend + * to be a WLAN Manager Registrar, it should set the Request Type to + * Registrar. Doing so avoids needlessly consuming resources on the AP. + + \code + + Request Type Value Description + 0x00 Enrollee, Info only + 0x01 Enrollee, open 802.1X + 0x02 Registrar + 0x03 WLAN Manager Registrar + + \endcode + * + * + */ + +TLV RequestType ( TLV_REQUEST_TYPE ) ( 2 : 2 ) MSB +{ + reqType, 1; +} + +/** + * \brief Response Type + * + * + * The Response Type component specifies the operational mode of the + * device for this setup exchange. The Response Type IE is carried + * throughout the 802.1X data channel setup process. + + \code + + Response Type Value Description + 0x00 Enrollee, Info only + 0x01 Enrollee, open 802.1X + 0x02 Registrar + 0x03 AP + +\endcode + * + * + */ + +TLV ResponseType ( TLV_RESPONSE_TYPE ) ( 2 : 2 ) MSB +{ + resType, 1; +} + + +/////////////////////////////////////////////////////////////////////////// +// WiFi Direct/P2P TLVs // +/////////////////////////////////////////////////////////////////////////// + +/** + * \brief P2P Status Attribute + */ + +TLV P2PStatus ( TLV_P2P_STATUS ) ( 1 : 2 ) LSB +{ + status, 1; +} + + +/** + * \brief Minor Reason Code Attribute + */ + +TLV MinorReasonCode ( TLV_MINOR_REASON_CODE ) ( 1 : 2 ) LSB +{ + minorReasonCode, 1; +} + + +/** + * \brief P2P Capability Attribute + */ + +TLV P2PCapability ( TLV_P2P_CAPABILITY ) ( 1 : 2 ) LSB +{ + deviceCapability, 1; + groupCapability, 1; +} + + +/** + * \brief P2P Device Id Attribute + */ + +TLV P2PDeviceId ( TLV_P2P_DEVICE_ID ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; +} + +/** + * \brief Listen Channel Attribute + */ + +TLV ListenChannel ( TLV_LISTEN_CHANNEL ) ( 1 : 2 ) LSB +{ + countryString[3]; + regulatoryClass, 1; + channel, 1; +} + +/** + * \brief Extended Listen Attribute + */ + +TLV ExtendedListenTiming ( TLV_EXTENDED_LISTEN_TIMING ) ( 1 : 2 ) LSB +{ + availibilityPeriod, 2; + availibilityInterval, 2; +} + + +/** + * \brief P2P Manageability Attribute + */ + +TLV P2PManageability ( TLV_P2P_MANAGEABILITY ) ( 1 : 2 ) LSB +{ + manageability, 1; +} + + +/** + * \brief Notice of Absence + */ + +TLV NoticeOfAbsence ( TLV_NOTICE_OF_ABSENCE ) ( 1 : 2 ) LSB +{ + index, 1; + CTSWindowOppPS, 1; + NoADesc[0..36]; +} + +/** + * \brief P2P Device Info Attribute + */ + +TLV P2PDeviceInfo ( TLV_P2P_DEVICE_INFO ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; + configMethod, 2 , FLIPBYTEORDER; + primaryDeviceType[8]; + MANDATORYTLV DeviceName; +} + + +/** + * \brief P2P Group Info Attribute + */ + +TLV P2PGroupInfo ( TLV_P2P_GROUP_INFO ) ( 1 : 2 ) LSB +{ + P2PClientInfoDesc[0..1024]; +} + + +/** + * \brief P2P Interface Attribute + */ + +TLV P2PInterface ( TLV_P2P_INTERFACE ) ( 1 : 2 ) LSB +{ + P2PDeviceAddress[6]; +} + + +/** + * \brief Operating Channel Attribute + */ + +TLV OperatingChannel ( TLV_OPERATING_CHANNEL ) ( 1 : 2 ) LSB +{ + countryString[3]; + regulatoryClass, 1; + channel, 1; +} + +/////////////////////////////////////////////////////////////////////////// +// MBO-OCE ATTR TLVs // +/////////////////////////////////////////////////////////////////////////// + +TLV mbo_ap_cap ( TLV_MBO_AP_CAP_ATTR ) ( 1 : 1 ) LSB +{ + mbo_cap_ind, 1; +} + +TLV non_prefferd_chan_rep ( TLV_NON_PREFERRED_CHAN_REPORT_ATTR ) ( 1 : 1 ) LSB +{ + oper_class, 1; + channel_report[3..254]; +} + +TLV cellular_data_cap ( TLV_CELLULAR_DATA_CAP_ATTR ) ( 1 : 1 ) LSB +{ + cellular_connectivity, 1; +} + +TLV assoc_disallowed ( TLV_ASSOC_DISSALLOWED_ATTR ) ( 1 : 1 ) LSB +{ + reason_code, 1; +} + +TLV cellular_data_con_pref ( TLV_CELLULAR_DATA_CON_PREF_ATTR ) ( 1 : 1 ) LSB +{ + cellular_preference, 1; +} + +TLV transition_reason ( TLV_TRANSITION_REASON_CODE_ATTR ) ( 1 : 1 ) LSB +{ + transition_reason_code, 1; +} + +TLV transition_reject_reason ( TLV_TRANSITION_REJECT_REASON_CODE_ATTR ) ( 1 : 1 ) LSB +{ + transition_reject_code, 1; +} + +TLV assoc_retry_delay ( TLV_ASSOC_RETRY_DELAY_ATTR ) ( 1 : 1 ) LSB +{ + delay, 2; +} + +// OCE Attributes // + +TLV oce_cap ( TLV_OCE_CAP_IND_ATTR ) ( 1 : 1 ) LSB +{ + { + oce_release: 3; + is_sta_cfon : 1; + non_oce_ap_present : 1; + reserved: 3; + } +} + +TLV rssi_assoc_rej ( TLV_RSSI_ASSOC_REJ_ATTR ) ( 1 : 1 ) LSB +{ + delta_rssi, 1; + retry_delay, 1; +} + +TLV reduced_wan_metrics ( TLV_REDUCED_WAN_METRICS_ATTR ) ( 1 : 1 ) LSB +{ + { + downlink_av_cap: 4; + uplink_av_cap : 4; + } +} + +/** + * \brief Vendor Extension + * + * This variable permits vendor extensions in the Wi-Fi Simple + * Configuration TLV framework. The Vendor Extension figure + * illustrates the implementation of vendor extensions. Vendor + * ID is the SMI network management private enterprise code + * + * +-----------+----------------------+ + * | Vendor ID | Vendor Data | + * +-----------+----------------------+ + * |<--- 3 --->|<----- 1 - 1021 ----->| + * + */ + +TLV VendorExtension ( TLV_VENDOR_EXTENSION ) ( 2 : 2 ) MSB +{ + /* + * vendorId is the SMI network management private enterprise code. + * WFA Vendor ID 0x00372A + * + */ + vendorId[ 3 ]; + + /** + * \brief Version2 + * + * The Version2 field specifies the version Wi-Fi Simple + * Configuration implemented by the device sending this attribute. + * The one-byte field is broken into a four-bit major part using + * the top MSBs and four-bit minor part using the LSBs. As an example, + * version 3.2 would be 0x32. This subelement was added in the + * specification version 2.0 and if the subelement is not included + * in a message, the transmitter of the message is assumed to + * use version 1.0. + * + */ + OPTIONALTLV TLV Version2 ( TLV_VERSION2 ) ( 1 : 1 ) MSB + { + { + minor: 4; + major: 4; + } + } + /** + * \brief AuthorizedMACs + * + * This subelement contains a list of Enrollee MAC addresses (each + * being six bytes in length) that have been registered to start WSC. + * The AP includes this field in Beacon and Probe Response frames so + * Enrollees can tell if they have been registered to start WSC. There + * may be multiple Enrollees active on the network, but not all of them have + * been registered to start WSC. This element allows an Enrollee to detect + * if they should start WSC with the AP. The AuthorizedMACs field augments + * the use of the Selected Registrar. + * + */ + OPTIONALTLV TLV AuthorizedMACs ( TLV_AUTHORIZED_MAC ) ( 1 : 1 ) MSB + { + mac[6]; + } + + /** + * \brief Request to Enroll + * + * This optional subelement in the WSC IE in Probe Request or M1 indicates + * the desire to enroll in the network by setting its value to TRUE. If the + * Registrar gets this subelement it can use this as a trigger that a device + * wants to enroll (maybe an indication can be shown to the user). The device + * must set it to FALSE after the registration protocol completion. + * + */ + OPTIONALTLV TLV RequestToEnroll( TLV_REQUEST_TO_ENROLL ) ( 1 : 1 ) MSB + { + req, 1; + } +} + +/** + * \brief Requested Device Type + * + * This attribute contains the requested device type of a Wi-Fi + * Direct device. + * + * This attribute allows a device to specify the Primary Device Type + * or the Secondary Device Type of other devices it is interested in. + * Only a device that receives a Probe Request containing a WSC IE with + * this attribute and with a Primary Device Type or Secondary Device Type + * that matches the Requested Device Type will respond with a Probe Response. + * + * Its format and contents is identical to the 'Primary Device Type'. + * + * Both the Category ID and Sub Category ID can be used as a filter. If only + * looking for devices with a certain Category ID, the OUI and Sub Category ID + * fields will have to be set to zero. + * + */ +TLV RequestDeviceType ( TLV_REQUESTED_DEVICE_TYPE ) ( 2 : 2 ) MSB +{ + primary_category, 2; + oui[ 4 ]; + sub_category, 2; +} + +///////////////////////////////////////////////////////////////////////////// +// Information Elements + +IE SSID (EID_SSID) // C.f. Sec. 7.3.2.1 +{ + ssid[0..32]; +} + +IE SuppRates (EID_SUPP_RATES) // 7.3.2.2 +{ + rates[0..SIR_MAC_MAX_NUMBER_OF_RATES]; +} + +IE FHParamSet (EID_FH_PARAM_SET) // 7.3.2.3 +{ + dwell_time, 2; + hop_set, 1; + hop_pattern, 1; + hop_index, 1; +} + +IE DSParams (EID_DS_PARAM_SET) // 7.3.2.4 +{ + curr_channel, 1; +} + +IE CFParams (EID_CF_PARAM_SET) // 7.3.2.5 +{ + cfp_count, 1; + cfp_period, 1; + cfp_maxduration, 2; + cfp_durremaining, 2; +} + +IE TIM (EID_TIM) // 7.3.2.6 +{ + dtim_count, 1; + dtim_period, 1; + bmpctl, 1; + vbmp[1..251]; +} + +IE ChallengeText (EID_CHALLENGE_TEXT) // 7.3.2.8 +{ + text[1..253]; +} + +IE RequestedInfo (EID_REQUEST) // 7.3.2.12 +{ + requested_eids[0..255]; +} + +const EID_BCN_REQ_EXTENDED_INFO = 11; +IE ExtRequestedInfo (EID_BCN_REQ_EXTENDED_INFO) +{ + req_element_id, 1; + req_element_id_ext[0..255]; +} + +IE Country (EID_COUNTRY) // 7.3.2.9 +{ + country[3]; + first_triplet[3]; + OPTIONAL more_triplets[3][0..80]; +} + +IE FHParams (EID_FH_PATTERN) // 7.3.2.10 +{ + radix, 1; + nchannels, 1; +} + +IE FHPattTable (EID_FH_PATT_TABLE) // 7.3.2.11 +{ + flag, 1; + nsets, 1; + modulus, 1; + offset, 1; + randtable[0..251]; +} + +IE ERPInfo (EID_ERP_INFO) // 7.3.2.13 +{ + { + non_erp_present : 1; + use_prot: 1; + barker_preamble: 1; + unused: 5; + } +} + +IE ExtSuppRates (EID_EXT_SUPP_RATES) // 7.3.2.14 +{ + rates[1..SIR_MAC_MAX_NUMBER_OF_RATES]; +} + +IE PowerConstraints (EID_POWER_CONSTRAINTS) // 7.3.2.15 +{ + localPowerConstraints, 1; +} + +IE PowerCaps (EID_POWER_CAPABILITY) // 7.3.2.16 +{ + minTxPower, 1; + maxTxPower, 1; +} + +IE TPCRequest (EID_TPC_REQUEST) // 7.3.2.17 +{ } + +IE TPCReport (EID_TPC_REPORT) // 7.3.2.18 +{ + tx_power, 1; + link_margin, 1; +} + +IE SuppChannels (EID_SUPPORTED_CHANNELS) // 7.2.3.19 +{ + bands[2][0..48]; +} + +IE SuppOperatingClasses (EID_SUPPORTED_OPER_CLASSES) +{ + classes[1..32]; +} + +IE ChanSwitchAnn (EID_CHANNEL_SWITCH_ANN) // 7.3.2.20 +{ + switchMode, 1; + newChannel, 1; + switchCount, 1; +} + +IE ext_chan_switch_ann (EID_EXT_CHAN_SWITCH) // 8.4.2.55 +{ + switch_mode, 1; + new_reg_class, 1; + new_channel, 1; + switch_count, 1; +} + +IE max_chan_switch_time (EID_EXTN_ID_ELEMENT) OUI (0x34) +{ + switch_time[3]; +} + +IE sec_chan_offset_ele (EID_SEC_CHAN_OFFSET) // 7.3.2.20a +{ + secondaryChannelOffset, 1; +} + +IE Quiet (EID_QUIET) // 7.3.2.23 +{ + count, 1; + period, 1; + duration, 2; + offset, 2; +} + +IE RSN (EID_RSN) // 7.3.2.25 +{ + // The version is 2 octets, and we only support version 1. + version, 2 MUSTBE 1; + // The next four octets will be the Optional Group Cipher Suite + OPTIONAL gp_cipher_suite[4]; + // The IE *may* stop here; if there's any more, we should see two more + // octets giving the number of Pairwise Cipher Suites + OPTIONAL pwise_cipher_suite_count, 2; + // I don't see anything in the Standard limiting the number of Pairwise + // Cypher Suites, other than the maximum length of an IE, which limits us + // to 61. However, that seems needlessly wasteful of space. + pwise_cipher_suites[4][0..6] COUNTIS pwise_cipher_suite_count; + // Optional count of AKM suite selectors + OPTIONAL akm_suite_cnt, 2; + // Again, I see nothing in the Standard explicitly limiting the number of + // AKM suite selectors other than the maximum size of an IE. + akm_suite[4][0..6] COUNTIS akm_suite_cnt; + OPTIONAL RSN_Cap[2]; + // Finally, the IE may contain zero or more PMKIDs: + OPTIONAL pmkid_count, 2; + pmkid[16][0..4] COUNTIS pmkid_count; + OPTIONAL gp_mgmt_cipher_suite[4]; +} + +IE RSNOpaque (EID_RSN) // 7.3.2.25 +{ + data[ 0..253 ]; +} + +IE WAPI (EID_WAPI) // 7.3.2.25 +{ + // The version is 2 octets, and we only support version 1. + version, 2 MUSTBE 1; + // count of AKM suite selectors + akm_suite_count, 2; + // Again, I see nothing in the Standard explicitly limiting the number of + // AKM suite selectors other than the maximum size of an IE. + akm_suites[4][0..4] COUNTIS akm_suite_count; + // we should see two more + // octets giving the number of Unicast Cipher Suites + unicast_cipher_suite_count, 2; + // I don't see anything in the Standard limiting the number of Pairwise + // Cypher Suites, other than the maximum length of an IE, which limits us + // to 61. However, that seems needlessly wasteful of space. + unicast_cipher_suites[4][0..4] COUNTIS unicast_cipher_suite_count; + // The next four octets will be the Multicast Cipher Suite + multicast_cipher_suite[4]; + // WAPI capabilities + { + preauth: 1; + reserved: 15; + } + // Finally, the IE may contain zero or more BKIDs: + OPTIONAL bkid_count, 2; + bkid[16][0..4] COUNTIS bkid_count; +} + +IE WAPIOpaque (EID_WAPI) // 7.3.2.25 +{ + data[ 6..253 ]; +} + +IE QBSSLoad (EID_QBSS_LOAD) // 7.3.2.28 +{ + stacount, 2; + chautil, 1; + avail, 2; +} + +IE EDCAParamSet (EID_EDCA_PARAM_SET) // 7.3.2.29 +{ + qos, 1; // ToDo: This is a bitfield whose format + // depends on whether this is from an AP + // or a STA, information which I'm not + // sure we have at parse time... + reserved, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_txoplimit, 2; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_txoplimit, 2; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_txoplimit, 2; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_txoplimit, 2; +} + +IE TSPEC (EID_TSPEC) // 7.3.2.30 +{ + + // TS Info + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + } + { + schedule: 1; + unused: 7; + } + + // Nominal MSDU Size + { + size: 15; + fixed: 1; + } + + max_msdu_size, 2; + min_service_int, 4; + max_service_int, 4; + inactivity_int, 4; + suspension_int, 4; + service_start_time, 4; + min_data_rate, 4; + mean_data_rate, 4; + peak_data_rate, 4; + burst_size, 4; + delay_bound, 4; + min_phy_rate, 4; + surplus_bw_allowance, 2; + medium_time, 2; + +} // End IE TSPEC. + +IE TCLAS (EID_TCLAS) // 7.3.2.31 +{ + user_priority, 1; + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + EthParams (classifier_type IS 0) + { + source[6]; + dest[6]; + type, 2; + } + IpParams (classifier_type IS 1) + { + version, 1; + UNION params (DISCRIMINATOR version) + { + IpV4Params (version IS 4) + { + source[4]; + dest[4]; + src_port, 2; + dest_port, 2; + DSCP, 1; + proto, 1; + reserved, 1; + } + IpV6Params (version IS 6) + { + source[16]; + dest[16]; + src_port, 2; + dest_port, 2; + flow_label[3]; + } + }; + } + Params8021dq (classifier_type IS 2) + { + tag_type, 2; + } + }; +} // End IE TCLASS + +const EID_BCN_REPORT_FRAME_BODY = 1; +IE BeaconReportFrmBody (EID_BCN_REPORT_FRAME_BODY) +{ + reportedFields[0..224]; +} + +const EID_BCN_REPORT_FRAME_BODY_FRAGMENT_ID = 2; +IE beacon_report_frm_body_fragment_id (EID_BCN_REPORT_FRAME_BODY_FRAGMENT_ID) +{ + // Data + { + beacon_report_id: 8; + fragment_id_number: 7; + more_fragments: 1; + } +} + +const EID_BCN_REPORT_LAST_BEACON_REPORT_INDICATION = 164; +IE last_beacon_report_indication (EID_BCN_REPORT_LAST_BEACON_REPORT_INDICATION) +{ + last_fragment, 1; +} + +const EID_REPORTING_REASON = 1; +IE reporting_reason (EID_REPORTING_REASON) +{ + { + failed_count: 1; + fcs_error: 1; + multiple_retry: 1; + frame_duplicate: 1; + rts_failure: 1; + ack_failure: 1; + retry: 1; + reserved: 1; + } +} + +const SUB_EID_BANDWIDTH_INDICATION = 164; +IE bw_indication (SUB_EID_BANDWIDTH_INDICATION) +{ + { + reserved: 1; + disabled_sub_chan_bitmap_present: 1; + reserved_1: 6; + } + { + channel_width: 3; + reserved_2: 5; + } + ccfs0, 1; + ccfs1, 1; + disabled_sub_chan_bitmap[2][0..1] COUNTIS disabled_sub_chan_bitmap_present; +} + +const SUB_EID_WIDE_BW_CHANNEL_SWITCH = 163; +IE wide_bw_chan_switch (SUB_EID_WIDE_BW_CHANNEL_SWITCH) +{ + new_chan_width, 1; + new_center_chan_freq0, 1; + new_center_chan_freq1, 1; +} + +IE MeasurementReport (EID_MEAS_REPORT) // 7.3.2.22 +{ + token, 1; + // Measurement Report Mode + { + late: 1; + incapable: 1; + refused: 1; + unused: 5; + } + type, 1; + OPTIONAL UNION report (DISCRIMINATOR type) + { + Basic (type IS 0) // 7.3.2.22.1 + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + // Map + { + bss: 1; + ofdm_preamble: 1; + unid_signal: 1; + rader: 1; + unmeasured: 1; + unused: 3; + } + } + CCA (type IS 1) + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + cca_busy_fraction, 1; + } + RPIHistogram (type IS 2) + { + channel, 1; + meas_start_time, 8; + meas_duration, 2; + rpi0_density, 1; + rpi1_density, 1; + rpi2_density, 1; + rpi3_density, 1; + rpi4_density, 1; + rpi5_density, 1; + rpi6_density, 1; + rpi7_density, 1; + } + channel_load_report (type IS 3) + { + op_class, 1; + channel, 1; + meas_start_time, 8; + meas_duration, 2; + chan_load, 1; + OPTIE wide_bw_chan_switch; + OPTIE bw_indication; + } + Beacon (type IS 5) + { + regClass, 1; + channel, 1; + meas_start_time, 8; + meas_duration, 2; + // reported_frame_info, + { + condensed_PHY: 7; + reported_frame_type: 1; + } + RCPI, 1; + RSNI, 1; + BSSID[6]; + antenna_id, 1; + parent_TSF, 4; + OPTIE BeaconReportFrmBody; + OPTIE beacon_report_frm_body_fragment_id; + OPTIE last_beacon_report_indication; + //IE vendor_specific + } + sta_stats (type IS 7) + { + meas_duration, 2; + group_id, 1; + UNION statsgroupdata (DISCRIMINATOR group_id) + { + dot11_counter_stats (group_id IS 0) + { + transmitted_fragment_count, 4; + group_transmitted_frame_count, 4; + failed_count, 4; + received_fragment_count, 4; + group_received_frame_count, 4; + fcs_error_count, 4; + transmitted_frame_count, 4; + } + dot11_mac_stats (group_id IS 1) + { + retry_count, 4; + multiple_retry_count, 4; + frame_duplicate_count, 4; + rts_success_count, 4; + rts_failure_count, 4; + ack_failure_count, 4; + } + dot11_qos_counter (group_id IS 2) + { + qos_transmitted_fragment_count, 4; + qos_failed_count, 4; + qos_retry_count, 4; + qos_multiple_retry_count, 4; + qos_frame_duplicate_count, 4; + qos_rts_success_count, 4; + qos_rts_failure_count, 4; + qos_ack_failure_count, 4; + qos_received_fragment_count, 4; + qos_transmitted_frame_count, 4; + qos_discarded_frame_count, 4; + qos_mpdus_received_count, 4; + qos_retries_received_count, 4; + } + dot11_bss_average_access_delay (group_id IS 10) + { + ap_average_access_delay, 1; + average_access_delay_besteffort, 1; + average_access_delay_background, 1; + average_access_delay_video, 1; + average_access_delay_voice, 1; + station_count, 2; + channel_utilization, 1; + } + }; + OPTIE reporting_reason; + } + + }; +} + +IE TSDelay (EID_TS_DELAY) // 7.3.2.32 +{ + delay, 4; +} + +IE TCLASSPROC (EID_TCLASS_PROC) // 7.3.2.33 +{ + processing, 1; +} + +IE Schedule (EID_SCHEDULE) // 7.3.2.34 +{ + { + aggregation: 1; + tsid: 4; + direction: 2; + reserved: 9; + } + service_start_time, 4; + service_interval, 4; + max_service_dur, 2; + spec_interval, 2; +} + +IE QOSCapsAp (EID_QOS_CAPABILITY) // 7.3.2.35 +{ + { + count: 4; + qack: 1; + qreq: 1; + txopreq: 1; + reserved: 1; + } +} + +IE QOSCapsStation (EID_QOS_CAPABILITY) // 7.3.2.35 +{ + { + acvo_uapsd: 1; + acvi_uapsd: 1; + acbk_uapsd: 1; + acbe_uapsd: 1; + qack: 1; + max_sp_length: 2; + more_data_ack: 1; + } +} + +IE LinkIdentifier (EID_LINK_IDENTIFIER) // 7.3.2.62 +{ + bssid[6]; + InitStaAddr[6]; + RespStaAddr[6]; +} + +IE WPA (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x01) +{ + // This IE's first two octets should be interpreted as a version number; + // we only support version 1. + version, 2 MUSTBE 1; + // A four-octet Multicast Cipher may or may not appear next (hence the + // OPTIONAL keyword) + OPTIONAL multicast_cipher[4]; + // Optional Unicast Cipher count + OPTIONAL unicast_cipher_count, 2; + // Next comes an array of four-octet Cipher Suite selectors; the COUNTIS + // clause indicates that the actual number of selectors seen is in the + // member 'unicast_cipher_count'. + unicast_ciphers[4][0..4] COUNTIS unicast_cipher_count; + // (Optional) Authentication suites: + OPTIONAL auth_suite_count, 2; + auth_suites[4][0..4] COUNTIS auth_suite_count; + // This field is declared optional as per bugs 15234, 14755, & 14991. + OPTIONAL caps, 2; +} + +IE WPAOpaque (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x01) +{ + data[ 2..249 ]; +} + +IE WMMInfoStation (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x00) +{ + // This IE contains the QoS Info field when sent from WMM Station + version, 1; + { + acvo_uapsd: 1; + acvi_uapsd: 1; + acbk_uapsd: 1; + acbe_uapsd: 1; + reserved1: 1; + max_sp_length: 2; + reserved2: 1; + } +} + +IE WMMInfoAp (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x00) +{ + // This IE contains the QoS Info field when sent from WMM AP + version, 1; + { + param_set_count: 4; + reserved: 3; + uapsd: 1; + } +} + + +IE WMMParams (EID_VENDOR_SPECIFIC) OUI(0x00, 0x50, 0xF2, 0x02, 0x01) +{ + version, 1 MUSTBE 1; + qosInfo, 1; // ToDo: This is actually a + // bitfield, but it's format + // varies depending on whether + // the sender is a STA or AP... + reserved2, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_txoplimit, 2; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_txoplimit, 2; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_txoplimit, 2; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_txoplimit, 2; +} + +IE WMMTSPEC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xf2, 0x02, 0x02) +{ + version, 1 MUSTBE 1; + + // TS Info + { + traffic_type: 1; + tsid: 4; + direction: 2; + access_policy: 2; + aggregation: 1; + psb: 1; + user_priority: 3; + tsinfo_ack_pol: 2; + } + { + tsinfo_rsvd: 7; + burst_size_defn: 1; + } + + // Nominal MSDU Size + { + size: 15; + fixed: 1; + } + + max_msdu_size, 2; + min_service_int, 4; + max_service_int, 4; + inactivity_int, 4; + suspension_int, 4; + service_start_time, 4; + min_data_rate, 4; + mean_data_rate, 4; + peak_data_rate, 4; + burst_size, 4; + delay_bound, 4; + min_phy_rate, 4; + surplus_bw_allowance, 2; + medium_time, 2; + +} // End IE WMMTSpec. + +IE WMMCaps (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x05) +{ + version, 1 MUSTBE 1; + { + reserved: 4; + qack: 1; + queue_request: 1; + txop_request: 1; + more_ack: 1; + } +} + +IE WMMTCLAS (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x06) +{ + version, 1 MUSTBE 1; + + user_priority, 1; + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + EthParams (classifier_type IS 0) + { + source[6]; + dest[6]; + type, 2; + } + IpParams (classifier_type IS 1) + { + version, 1; + UNION params (DISCRIMINATOR version) + { + IpV4Params (version IS 4) + { + source[4]; + dest[4]; + src_port, 2; + dest_port, 2; + DSCP, 1; + proto, 1; + reserved, 1; + } + IpV6Params (version IS 6) + { + source[16]; + dest[16]; + src_port, 2; + dest_port, 2; + flow_label[3]; + } + }; + } + Params8021dq (classifier_type IS 2) + { + tag_type, 2; + } + }; + +} + +IE WMMTCLASPROC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x07) +{ + version, 1 MUSTBE 1; + processing, 1; +} + +IE WMMTSDelay (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x08) +{ + version, 1 MUSTBE 1; + delay, 4; +} + +IE WMMSchedule (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x02, 0x09) +{ + version, 1 MUSTBE 1; + + { + aggregation: 1; + tsid: 4; + direction: 2; + reserved: 9; + } + + service_start_time, 4; + service_interval, 4; + max_service_dur, 2; + spec_interval, 2; +} + +IE ESERadMgmtCap (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x01) +{ + + mgmt_state, 1; + + { + mbssid_mask: 3; + reserved: 5; + } + +} + +IE Vendor1IE (EID_VENDOR_SPECIFIC) OUI (0x00, 0x10, 0x18) +{ +} + +IE Vendor3IE (EID_VENDOR_SPECIFIC) OUI (0x00, 0x16, 0x32) +{ +} + +IE hs20vendor_ie (EID_VENDOR_SPECIFIC) OUI (0x50, 0x6F, 0x9A, 0x10) +{ + /* hotspot_configurations */ + { + dgaf_dis: 1; + hs_id_present: 2; + reserved: 1; + release_num: 4; + } + OPTIONAL UNION hs_id (DISCRIMINATOR hs_id_present) + { + pps_mo (hs_id_present IS 1) + { + pps_mo_id, 2; + } + anqp_domain (hs_id_present IS 2) + { + anqp_domain_id, 2; + } + }; +} + +IE osen_ie (EID_VENDOR_SPECIFIC) OUI (0x50, 0x6F, 0x9A, 0x12) +{ + data[0..255]; +} + +IE roaming_consortium_sel (EID_VENDOR_SPECIFIC) OUI (0x50, 0x6F, 0x9A, 0x1d) +{ + data[0..255]; +} + +IE QComVendorIE (EID_VENDOR_SPECIFIC) OUI (0x00, 0xA0, 0xC6) +{ + type, 1; + channel, 1; +} + +IE ESETrafStrmMet (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x07) +{ + tsid, 1; + state, 1; + msmt_interval, 2; +} + +IE ESETrafStrmRateSet (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x08) +{ + tsid, 1; + tsrates[0..8]; +} + +IE ESEVersion (EID_VENDOR_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x03) +{ + version, 1; +} + +IE ESETxmitPower (EID_ESE_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x00) +{ + power_limit, 1; + reserved, 1; +} + +IE ESECckmOpaque (EID_ESE_CCKM_SPECIFIC) OUI (0x00, 0x40, 0x96, 0x00) +{ + data[ 6..20 ]; +} + +IE RRMEnabledCap (EID_RRM_ENABLED_CAPS) +{ + //Capability bitmap + { + LinkMeasurement: 1; + NeighborRpt: 1; + parallel: 1; + repeated: 1; + BeaconPassive: 1; + BeaconActive: 1; + BeaconTable: 1; + BeaconRepCond: 1; + } + { + FrameMeasurement: 1; + ChannelLoad: 1; + NoiseHistogram: 1; + statistics: 1; + LCIMeasurement: 1; + LCIAzimuth: 1; + TCMCapability: 1; + triggeredTCM: 1; + } + { + APChanReport: 1; + RRMMIBEnabled: 1; + operatingChanMax: 3; + nonOperatinChanMax: 3; + } + { + MeasurementPilot: 3; + MeasurementPilotEnabled: 1; + NeighborTSFOffset: 1; + RCPIMeasurement: 1; + RSNIMeasurement: 1; + BssAvgAccessDelay: 1; + } + { + BSSAvailAdmission: 1; + AntennaInformation: 1; + fine_time_meas_rpt: 1; + lci_capability: 1; + reserved: 4; + } +} + +IE MeasurementPilot (EID_RRM_MEAS_PILOT_TX_INFO) +{ + measurementPilot, 1; + vendorSpecific[0..255]; //Should be an IE. But currently only one level of nesting allowed. Can ignore for now. +} + +IE MultiBssid (EID_MULTIPLE_BSSID) +{ + maxBSSIDIndicator, 1; + vendorSpecific[0..255]; +} + +IE OBSSScanParameters (EID_OBSS_SCAN_PARAMETERS) +{ + obssScanPassiveDwell, 2; + obssScanActiveDwell, 2; + bssChannelWidthTriggerScanInterval, 2; + obssScanPassiveTotalPerChannel, 2; + obssScanActiveTotalPerChannel, 2; + bssWidthChannelTransitionDelayFactor, 2; + obssScanActivityThreshold, 2; +} + +IE ht2040_bss_coexistence (EID_20_40_BSS_COEXISTENCE) +{ + // 20/40 BSS Coexistence Information + { + info_request: 1; + forty_mhz_intolerant: 1; + twenty_mhz_bsswidth_req: 1; + obss_scan_exemption_req: 1; + obss_scan_exemption_grant: 1; + unused: 3; + } +} + +IE ht2040_bss_intolerant_report (EID_20_40_BSS_INTOLERANT_REPORT) +{ + operating_class, 1; + channel_list[0..50]; +} + +const EID_RRM_NBR_RPT_TSF = 1; +const EID_RRM_NBR_CD_COUNTRY = 2; + +IE TSFInfo (EID_RRM_NBR_RPT_TSF) +{ + TsfOffset, 2; + BeaconIntvl, 2; +} +IE CondensedCountryStr (EID_RRM_NBR_CD_COUNTRY) +{ + countryStr[2]; +} + +IE NeighborReport (EID_NEIGHBOR_REPORT) +{ + bssid[6]; + //Bssid Info + { + APReachability: 2; + Security: 1; + KeyScope: 1; + //Capabilities + SpecMgmtCap: 1; + QosCap: 1; + apsd: 1; + rrm: 1; + } + //Capabilities contd. + { + DelayedBA: 1; + ImmBA: 1; + //Capabilities end. + MobilityDomain: 1; + reserved: 5; + } + + reserved1, 2; //part of BSSID Info. + + regulatoryClass, 1; + channel, 1; + PhyType, 1; + OPTIE IE TSFInfo; + OPTIE IE CondensedCountryStr; + OPTIE IE MeasurementPilot; + OPTIE IE RRMEnabledCap; + OPTIE IE MultiBssid; + //Ignoring vendor specific. +} + +IE RCPIIE (EID_RCPI) +{ + rcpi, 1; +} + +IE RSNIIE (EID_RSNI) +{ + rsni, 1; +} + +IE WFATPC (EID_VENDOR_SPECIFIC) OUI (0x00, 0x50, 0xF2, 0x08, 0x00) +{ + txPower, 1; + linkMargin, 1; +} + +IE MobilityDomain (EID_FT_MOBILITY_DOMAIN) +{ + MDID, 2; + //FT Capability and policy + { + overDSCap: 1; + resourceReqCap: 1; + reserved: 6; + } +} +const SUB_EID_FT_R1KH_ID = 1; +const SUB_EID_FT_GTK = 2; +const SUB_EID_FT_R0KH_ID = 3; +const SUB_EID_FT_IGTK = 4; +IE FTInfo (EID_FT_INFO) +{ + // MicControl, 2; + { + reserved: 8; + IECount: 8; + } + MIC[16]; + Anonce[32]; + Snonce[32]; + + OPTIE IE R1KH_ID (SUB_EID_FT_R1KH_ID) + { + PMK_R1_ID[6]; + } + + OPTIE IE GTK (SUB_EID_FT_GTK) + { + //Key Info + { + keyId: 2; + reserved: 14; + } + keyLength, 1; + RSC[8]; + key[5..32]; + } + + OPTIE IE R0KH_ID (SUB_EID_FT_R0KH_ID) + { + PMK_R0_ID[1..48]; + } + + OPTIE IE IGTK (SUB_EID_FT_IGTK) + { + //Key Info + keyID[2]; + IPN[6]; + keyLength, 1; + key[24]; + } +} + +IE TimeoutInterval (EID_TIMEOUT_INTERVAL) +{ + timeoutType, 1; + timeoutValue, 4; +} + +//TODO: need to define this properly. +IE RICData (EID_FT_RIC_DATA) +{ + Identifier, 1; + resourceDescCount, 1; + statusCode, 2; +} + +IE RICDescriptor (EID_FT_RIC_DESCRIPTOR) +{ + resourceType, 1; + variableData[0..255]; //Block ack param set...TODO: +} + +IE WscIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x00, 0x50, 0xF2, 0x04 ) +{ + data[ 2..249 ]; +} + +IE P2PIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x09 ) +{ + data[ 2..249 ]; +} + +IE WFDIEOpaque (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x0A ) +{ + data[ 2..249 ]; +} + +IE PTIControl (EID_PTI_CONTROL) // 7.3.2.65 +{ + tid, 1; + sequence_control, 2; +} + +IE oci (EID_EXTN_ID_ELEMENT) OUI ( 0x36 ) +{ + op_class, 1; + prim_ch_num, 1; + freq_seg_1_ch_num, 1; +} + +IE PUBufferStatus (EID_PU_BUFFER_STATUS) // 7.3.2.66 +{ + { + ac_bk_traffic_aval: 1; + ac_be_traffic_aval: 1; + ac_vi_traffic_aval: 1; + ac_vo_traffic_aval: 1; + reserved: 4; + } +} + + +IE bss_max_idle_period (EID_BSS_MAX_IDLE_PERIOD) +{ + max_idle_period, 2; + { + prot_keep_alive_reqd: 1; + reserved: 7; + } +} + +IE VHTCaps (EID_VHT_CAPABILITIES) +{ + //VHT Capability Info + { + maxMPDULen: 2; + supportedChannelWidthSet: 2; + ldpcCodingCap: 1; + shortGI80MHz: 1; + shortGI160and80plus80MHz: 1; + txSTBC: 1; + rxSTBC: 3; + suBeamFormerCap: 1; + suBeamformeeCap: 1; + csnofBeamformerAntSup: 3; + numSoundingDim: 3; + muBeamformerCap: 1; + muBeamformeeCap: 1; + vhtTXOPPS: 1; + htcVHTCap: 1; + maxAMPDULenExp: 3; + vhtLinkAdaptCap: 2; + rxAntPattern: 1; + txAntPattern: 1; + extended_nss_bw_supp: 2; + } + rxMCSMap, 2; + { + rxHighSupDataRate: 13; + max_nsts_total: 3; + } + txMCSMap, 2; + { + txSupDataRate: 13; + vht_extended_nss_bw_cap: 1; + reserved: 2; + } +} + +IE VHTOperation (EID_VHT_OPERATION_ELEMENT) +{ + chanWidth, 1; + chan_center_freq_seg0, 1; + chan_center_freq_seg1, 1; + basicMCSSet, 2; +} + +IE VHTExtBssLoad (EID_VHT_EXT_BSS_LOAD) +{ + muMIMOCapStaCount, 1; + ssUnderUtil, 1; + FortyMHzUtil, 1; + EightyMHzUtil, 1; + OneSixtyMHzUtil, 1; +} + +IE AID (EID_AID) +{ + assocId, 2; +} + +IE WiderBWChanSwitchAnn (EID_WIDER_BW_CHANNEL_SWITCH_ANN) +{ + newChanWidth, 1; + newCenterChanFreq0, 1; + newCenterChanFreq1, 1; +} + +IE transmit_power_env (EID_TRANSMIT_POWER_ENVELOPE) +{ + { + max_tx_pwr_count: 3; + max_tx_pwr_interpret: 3; + max_tx_pwr_category: 2; + } + tx_power[1..8]; + OPTIONAL UNION ext_max_tx_power (DISCRIMINATOR max_tx_pwr_interpret) + { + ext_max_tx_power_local_eirp (max_tx_pwr_interpret IS 0) { + max_tx_power_for_320, 1; + } + ext_max_tx_power_local_psd (max_tx_pwr_interpret IS 1) { + //ext_transmit_psd_info, 1; + { + ext_count: 4; + reserved: 4; + } + max_tx_psd_power[8]; + } + ext_max_tx_power_reg_eirp (max_tx_pwr_interpret IS 2) { + max_tx_power_for_320, 1; + } + ext_max_tx_power_reg_psd (max_tx_pwr_interpret IS 3) { + //ext_transmit_psd_info, 1; + { + ext_count: 4; + reserved: 4; + } + max_tx_psd_power[8]; + } + + }; +} + +IE bw_ind_element (EID_EXTN_ID_ELEMENT) OUI (0x87) +{ + { + reserved: 1; + disabled_sub_chan_bitmap_present: 1; + reserved_1: 6; + } + { + channel_width: 3; + reserved_2: 5; + } + ccfs0, 1; + ccfs1, 1; + disabled_sub_chan_bitmap[2][0..1] COUNTIS disabled_sub_chan_bitmap_present; +} + +IE ChannelSwitchWrapper (EID_CHANNEL_SWITCH_WRAPPER) +{ + OPTIE IE WiderBWChanSwitchAnn; + OPTIE IE transmit_power_env; + OPTIE IE bw_ind_element; +} + +IE reduced_neighbor_report (EID_RNR_IE) +{ + // TBTT Information Header + { + tbtt_type: 2; + filtered_neighbor_ap: 1; + reserved: 1; + tbtt_info_count: 4; + tbtt_info_len: 8; + } + op_class, 1; + channel_num, 1; + // TBTT information field + UNION tbtt_info (DISCRIMINATOR tbtt_info_len) + { + tbtt_info_1 (tbtt_info_len IS 1) + { + tbtt_offset, 1; + } + tbtt_info_2 (tbtt_info_len IS 2) + { + tbtt_offset, 1; + bss_params, 1; + } + tbtt_info_5 (tbtt_info_len IS 5) + { + tbtt_offset, 1; + short_ssid, 4; + } + tbtt_info_6 (tbtt_info_len IS 6) + { + tbtt_offset, 1; + short_ssid, 4; + bss_params, 1; + } + tbtt_info_7 (tbtt_info_len IS 7) + { + tbtt_offset, 1; + bssid[6]; + } + tbtt_info_8 (tbtt_info_len IS 8) + { + tbtt_offset, 1; + bssid[6]; + bss_params, 1; + } + tbtt_info_9 (tbtt_info_len IS 9) + { + tbtt_offset, 1; + bssid[6]; + bss_params, 1; + psd_20mhz, 1; + } + tbtt_info_11 (tbtt_info_len IS 11) + { + tbtt_offset, 1; + bssid[6]; + short_ssid, 4; + } + tbtt_info_12 (tbtt_info_len IS 12) + { + tbtt_offset, 1; + bssid[6]; + short_ssid, 4; + bss_params, 1; + } + tbtt_info_13 (tbtt_info_len IS 13) + { + tbtt_offset, 1; + bssid[6]; + short_ssid, 4; + bss_params, 1; + psd_20mhz, 1; + } + tbtt_info_16 (tbtt_info_len IS 16) + { + tbtt_offset, 1; + bssid[6]; + short_ssid, 4; + bss_params, 1; + psd_20mhz, 1; + mld_id, 1; + { + link_id: 4; + bss_param_change_cnt: 8; + all_updates_included: 1; + reserved: 3; + } + } + }; +} + +IE ExtCap (EID_EXT_CAP) +{ + bytes[1..15]; +} + +IE HTCaps (EID_HT_CAPABILITIES) +{ + // HT Capability Info + { + advCodingCap: 1; + supportedChannelWidthSet: 1; + mimoPowerSave: 2; + greenField: 1; + shortGI20MHz: 1; + shortGI40MHz: 1; + txSTBC: 1; + rxSTBC: 2; + delayedBA: 1; + maximalAMSDUsize: 1; + dsssCckMode40MHz: 1; + psmp: 1; + stbcControlFrame: 1; + lsigTXOPProtection: 1; + } + // HT Parameters Info; + { + maxRxAMPDUFactor: 2; + mpduDensity: 3; + reserved1: 3; + } + + supportedMCSSet[ HT_MAX_SUPPORTED_MCS_SET ]; + + // Extended HT Capability Info + { + pco: 1; + transitionTime: 2; + reserved2: 5; + mcsFeedback: 2; + reserved3: 6; + } + // TXBF Capability Info + { + txBF: 1; + rxStaggeredSounding: 1; + txStaggeredSounding: 1; + rxZLF: 1; + txZLF: 1; + implicitTxBF: 1; + calibration: 2; + explicitCSITxBF: 1; + explicitUncompressedSteeringMatrix: 1; + explicitBFCSIFeedback: 3; + explicitUncompressedSteeringMatrixFeedback: 3; + explicitCompressedSteeringMatrixFeedback: 3; + csiNumBFAntennae: 2; + uncompressedSteeringMatrixBFAntennae: 2; + compressedSteeringMatrixBFAntennae: 2; + reserved4: 7; + } + // AS Capability Info + { + antennaSelection: 1; + explicitCSIFeedbackTx: 1; + antennaIndicesFeedbackTx: 1; + explicitCSIFeedback: 1; + antennaIndicesFeedback: 1; + rxAS: 1; + txSoundingPPDUs: 1; + reserved5: 1; + } + //TODO: take it out when generic fix to remove extra bytes in IE is available. + //This is required to interop with Dlink AP which is sending 2 bytes extra in HTInfo IE. + rsvd[0..32]; + +} // End IE HTCaps. + +IE HTInfo (EID_HT_INFO) +{ + primaryChannel, 1; + + // ahtInfoField1 + { + secondaryChannelOffset: 2; + recommendedTxWidthSet: 1; + rifsMode: 1; + controlledAccessOnly: 1; + serviceIntervalGranularity: 3; + } + + // ahtInfoField2 + + + // ahtInfoField2 + { + opMode: 2; + nonGFDevicesPresent: 1; + transmitBurstLimit: 1; + obssNonHTStaPresent:1; + chan_center_freq_seg2:8; + reserved: 3; + } + + + // ahtInfoField3 + { + basicSTBCMCS: 7; + dualCTSProtection: 1; + secondaryBeacon: 1; + lsigTXOPProtectionFullSupport: 1; + pcoActive: 1; + pcoPhase: 1; + reserved2: 4; + } + + basicMCSSet[ HT_MAX_SUPPORTED_MCS_SET ]; + + //TODO: take it out when generic fix to remove extra bytes in IE is available. + //This is required to interop with Dlink AP which is sending 2 bytes extra in HTInfo IE. + rsvd[0..32]; + +} // End IE HTInfo. + + +IE OperatingMode (EID_OPERATING_MODE) +{ + { //Operating Mode field + chanWidth: 2; + vht_160_80p80_supp: 1; + no_ldpc: 1; + rxNSS: 3; + rxNSSType: 1; + } +} + +IE QosMapSet (EID_QOS_MAP_SET) +{ + dscp_exceptions[QOS_DSCP_RANGE_LEN..MAX_QOS_DSCP_DATA_LEN]; +} + +CONTAINERIE RICDataDesc +{ + MANDIE RICData; + OPTIE RICDescriptor; + OPTIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + OPTIE TSDelay; + OPTIE Schedule; + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE WMMTSDelay; + OPTIE WMMSchedule; +} + +IE TimeAdvertisement (EID_TIME_ADVERTISEMENT) // 8.4.2.63 +{ + timing_capabilities, 1; + time_value[10]; + time_error[5]; +} + +/** + * This all attributes are defined under qcn_attribute_id enum of + * cmn code in wlan_cmn_ieee80211.h file. + */ +const TLV_VERSION_ATTR_ID = 1; +const TLV_VHT_MCS_10_11_ATTR_ID = 2; +const TLV_HE_400NS_SGI_SUPP_ATTR_ID = 3; +const TLV_HE_2XLTF_160_80P80_SUPP_ATTR_ID = 4; +const TLV_HE_DL_OFDMA_SUPPP_ATTR_ID = 5; +const TLV_TRANSITION_REASONP_ATTR_ID = 6; +const TLV_TRANSITION_REJECTIONP_ATTR_ID = 7; +const TLV_HE_DL_MUMIMO_SUPPP_ATTR_ID = 8; +const TLV_HE_MCS_11_12_ATTR_ID = 9; +const TLV_EDCA_PIFS_PARAM_ATTR_ID = 13; +const TLV_ECSA_TARGET_TSF_INFO_ATTR_ID = 14; + +TLV qcn_version(TLV_VERSION_ATTR_ID) ( 1 : 1 ) LSB +{ + version, 1; + sub_version, 1; +} +TLV vht_mcs11_attr (TLV_VHT_MCS_10_11_ATTR_ID) ( 1 : 1 ) LSB +{ + vht_mcs_10_11_supp, 1; +} +TLV he_400ns_sgi_attr (TLV_HE_400NS_SGI_SUPP_ATTR_ID) ( 1 : 1 ) LSB +{ + he_ltf1x_400ns_sgi, 1; + he_ltf2x_400ns_sgi, 1; + he_ltf4x_400ns_sgi, 1; +} + +TLV he_2xltf_160mhz_supp (TLV_HE_2XLTF_160_80P80_SUPP_ATTR_ID) ( 1 : 1 ) LSB +{ + he_2xltf_160MHz_supp, 1; +} + +TLV he_dl_ofdma_attr (TLV_HE_DL_OFDMA_SUPPP_ATTR_ID) ( 1 : 1 ) LSB +{ + he_dl_ofdma_supp, 1; +} + +TLV trans_reasonp_attr (TLV_TRANSITION_REASONP_ATTR_ID) ( 1 : 1 ) LSB +{ + transition_reasonp, 1; +} + +TLV trans_rejectp_attr (TLV_TRANSITION_REJECTIONP_ATTR_ID) ( 1 : 1 ) LSB +{ + transition_rejp, 1; +} + +TLV he_dl_mumimo_attr (TLV_HE_DL_MUMIMO_SUPPP_ATTR_ID) ( 1 : 1 ) LSB +{ + he_dl_mumimo_supp, 1; +} + +TLV he_mcs13_attr (TLV_HE_MCS_11_12_ATTR_ID) ( 1 : 1 ) LSB +{ + he_mcs_12_13_supp_80, 1; + he_mcs_12_13_supp_160, 1; +} + +TLV edca_pifs_param_attr (TLV_EDCA_PIFS_PARAM_ATTR_ID) ( 1 : 1 ) LSB +{ + // Configure EDCA or PIFS param based on edca_param_type + edca_param_type, 1; + data[3..4]; +} + +TLV ecsa_target_tsf_info_attr (TLV_ECSA_TARGET_TSF_INFO_ATTR_ID) ( 1 : 1 ) LSB +{ + twt_ch_sw_mode, 1; + target_tsf, 8; +} + +MULTIIE qcn_ie (EID_VENDOR_SPECIFIC) OUI ( 0x8C, 0xFD, 0xF0, 0x01 ) +{ + OPTIONALTLV qcn_version; + OPTIONALTLV vht_mcs11_attr; + OPTIONALTLV he_400ns_sgi_attr; + OPTIONALTLV he_2xltf_160mhz_supp; + OPTIONALTLV he_dl_ofdma_attr; + OPTIONALTLV trans_reasonp_attr; + OPTIONALTLV trans_rejectp_attr; + OPTIONALTLV he_dl_mumimo_attr; + OPTIONALTLV he_mcs13_attr; + OPTIONALTLV edca_pifs_param_attr; + OPTIONALTLV ecsa_target_tsf_info_attr; +} + +IE esp_information (EID_EXTN_ID_ELEMENT) OUI ( 0x0B ) +{ + data[0..96]; +} +IE fils_indication (EID_FILS_INDICATION) +{ + // FILS Information element + { + public_key_identifiers_cnt : 3; + realm_identifiers_cnt : 3; + is_ip_config_supported : 1; + is_cache_id_present : 1; + is_hessid_present : 1; + is_fils_sk_auth_supported : 1; + is_fils_sk_auth_pfs_supported : 1; + is_pk_auth_supported : 1; + reserved : 4; + } + // other FILS elements + variable_data[2..255]; +} + +IE fils_assoc_delay_info (EID_EXTN_ID_ELEMENT) OUI ( 0x01 ) +{ + assoc_delay_info, 1; +} + +IE fils_key_confirmation (EID_EXTN_ID_ELEMENT) OUI ( 0x03 ) +{ + key_auth[0..255]; +} + +IE fils_session (EID_EXTN_ID_ELEMENT) OUI ( 0x04 ) +{ + session[8]; +} + +IE fils_hlp_container (EID_EXTN_ID_ELEMENT) OUI ( 0x05 ) +{ + dest_mac[6]; + src_mac[6]; + hlp_packet[0..255]; +} + +IE fils_kde (EID_EXTN_ID_ELEMENT) OUI ( 0x07 ) +{ + key_rsc[8]; + kde_list[0..255]; +} + +IE fils_wrapped_data (EID_EXTN_ID_ELEMENT) OUI ( 0x08 ) +{ + wrapped_data[0..255]; +} + +IE fils_public_key (EID_EXTN_ID_ELEMENT) OUI ( 0x0C ) +{ + key_type, 1; + public_key[0..255]; +} + +IE fils_nonce (EID_EXTN_ID_ELEMENT) OUI ( 0x0D ) +{ + nonce[16]; +} + +IE fragment_ie (EID_FRAGMENT_IE) +{ + data[0..255]; +} + +IE dh_parameter_element (EID_EXTN_ID_ELEMENT) OUI ( 0x20 ) +{ + group[2]; + public_key[0..255]; +} + +const EID_RRM_REPORTING = 1; +const EID_RRM_BCN_REPORTING_DETAIL = 2; + +const SUB_EID_AZIMUTH_REQ = 1; +const SUB_EID_REQ_MAC_ADDR = 2; +const SUB_EID_TGT_MAC_ADDR = 3; +const SUB_EID_MAX_AGE = 4; +const SUB_EID_NEIGHBOR_RPT = 52; +//const SUB_EID_TRIGGERED_REPORTING = 1; + +IE rrm_reporting (EID_RRM_REPORTING) +{ + reporting_condition, 1; + threshold, 1; +} + +IE BcnReportingDetail (EID_RRM_BCN_REPORTING_DETAIL) +{ + reportingDetail, 1; +} + +IE APChannelReport (EID_AP_CHAN_REPORT) +{ + regulatoryClass, 1; + channelList[0..50]; +} + +IE azimuth_req (SUB_EID_AZIMUTH_REQ) +{ + request, 1; +} + +IE req_mac_addr (SUB_EID_REQ_MAC_ADDR) +{ + addr[6]; +} + +IE tgt_mac_addr (SUB_EID_TGT_MAC_ADDR) +{ + addr[6]; +} + +IE max_age (SUB_EID_MAX_AGE) +{ + max_age, 2; +} + +IE neighbor_rpt (SUB_EID_NEIGHBOR_RPT) +{ + bssid[6]; + //Bssid Info + { + APReachability: 2; + Security: 1; + KeyScope: 1; + //Capabilities + SpecMgmtCap: 1; + QosCap: 1; + apsd: 1; + rrm: 1; + } + //Capabilities contd. + { + DelayedBA: 1; + ImmBA: 1; + //Capabilities end. + MobilityDomain: 1; + reserved: 5; + } + reserved1, 2; //part of BSSID Info. + regulatoryClass, 1; + channel, 1; + PhyType, 1; + OPTIE IE TSFInfo; + OPTIE IE CondensedCountryStr; + OPTIE IE MeasurementPilot; + OPTIE IE RRMEnabledCap; + OPTIE IE MultiBssid; +} + +IE MeasurementRequest (EID_MEAS_REQUEST) // 7.3.2.21 +{ + measurement_token, 1; + + // Measurement Request Mode + { + parallel: 1; + enable: 1; + request: 1; + report: 1; + durationMandatory: 1; + unused: 3; + } + + measurement_type, 1; + UNION measurement_request (DISCRIMINATOR measurement_type) + { + Basic (measurement_type IS 0) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + CCA (measurement_type IS 1) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + RPIHistogram (measurement_type IS 2) + { + channel_no, 1; + meas_start_time[8]; + meas_duration, 2; + } + channel_load (measurement_type IS 3) + { + op_class, 1; + channel, 1; + randomization_intv, 2; + meas_duration, 2; + OPTIE rrm_reporting; + OPTIE wide_bw_chan_switch; + OPTIE bw_indication; + } + Beacon (measurement_type IS 5) + { + regClass, 1; + channel, 1; + randomization, 2; + meas_duration, 2; + meas_mode, 1; + BSSID[6]; + OPTIE SSID; + OPTIE rrm_reporting; + OPTIE BcnReportingDetail; + OPTIE RequestedInfo; + OPTIE ExtRequestedInfo; + OPTIE APChannelReport[0..2]; + OPTIE last_beacon_report_indication; + //OPTIONAL vendor_specific[1..239]; + } + lci (measurement_type IS 8) + { + loc_subject, 1; + OPTIE azimuth_req; + OPTIE req_mac_addr; + OPTIE tgt_mac_addr; + OPTIE max_age; + } + ftmrr (measurement_type IS 16) + { + random_interval, 2; + min_ap_count, 1; + + OPTIE neighbor_rpt; + OPTIE max_age; + } + sta_stats (measurement_type IS 7) + { + peer_mac_addr[6]; + randomization, 2; + meas_duration, 2; + group_identity, 1; + //OPTIE triggered_reporting; + //OPTIONAL vendor_specific; + } + + }; +} + +IE tclas_mask (EID_EXTN_ID_ELEMENT) OUI (0x59) +{ + classifier_type, 1; + classifier_mask, 1; + UNION info (DISCRIMINATOR classifier_type) + { + ip_param (classifier_type IS 4) + { + reserved[16]; + } + }; +} + +IE mscs_status (EID_MSCS_STATUS) +{ + status_code, 1; +} + +IE descriptor_element (EID_EXTN_ID_ELEMENT) OUI (0x58) +{ + request_type, 1; + user_priority_control, 2; + stream_timeout, 4; + OPTIE IE tclas_mask; + OPTIE IE mscs_status; + //Optional Vendor specific IEs ... ignoring +} + +IE he_cap (EID_EXTN_ID_ELEMENT) OUI (0x23) +{ + { + htc_he:1; + twt_request:1; + twt_responder:1; + fragmentation:2; + max_num_frag_msdu_amsdu_exp:3; + min_frag_size:2; + trigger_frm_mac_pad:2; + multi_tid_aggr_rx_supp:3; + he_link_adaptation:2; + all_ack:1; + trigd_rsp_sched:1; + a_bsr:1; + broadcast_twt:1; + ba_32bit_bitmap:1; + mu_cascade:1; + ack_enabled_multitid:1; + reserved:1; + omi_a_ctrl:1; + ofdma_ra:1; + max_ampdu_len_exp_ext:2; + amsdu_frag:1; + flex_twt_sched:1; + rx_ctrl_frame:1; + } + { + bsrp_ampdu_aggr:1; + qtp:1; + a_bqr:1; + spatial_reuse_param_rspder:1; + ndp_feedback_supp:1; + ops_supp:1; + amsdu_in_ampdu:1; + multi_tid_aggr_tx_supp:3; + he_sub_ch_sel_tx_supp:1; + ul_2x996_tone_ru_supp:1; + om_ctrl_ul_mu_data_dis_rx:1; + he_dynamic_smps:1; + punctured_sounding_supp:1; + ht_vht_trg_frm_rx_supp:1; + } + { + reserved2:1; + chan_width_0:1; + chan_width_1:1; + chan_width_2:1; + chan_width_3:1; + chan_width_4:1; + chan_width_5:1; + chan_width_6:1; + rx_pream_puncturing:4; + device_class:1; + ldpc_coding:1; + he_1x_ltf_800_gi_ppdu:1; + midamble_tx_rx_max_nsts:2; + he_4x_ltf_3200_gi_ndp:1; + tb_ppdu_tx_stbc_lt_80mhz:1; + rx_stbc_lt_80mhz:1; + doppler:2; + ul_mu:2; + dcm_enc_tx:3; + dcm_enc_rx:3; + ul_he_mu:1; + su_beamformer:1; + } + { + su_beamformee:1; + mu_beamformer:1; + bfee_sts_lt_80:3; + bfee_sts_gt_80:3; + num_sounding_lt_80:3; + num_sounding_gt_80:3; + su_feedback_tone16:1; + mu_feedback_tone16:1; + codebook_su:1; + codebook_mu:1; + beamforming_feedback:3; + he_er_su_ppdu:1; + dl_mu_mimo_part_bw:1; + ppet_present:1; + srp:1; + power_boost:1; + he_ltf_800_gi_4x:1; + max_nc:3; + tb_ppdu_tx_stbc_gt_80mhz:1; + rx_stbc_gt_80mhz:1; + } + { + er_he_ltf_800_gi_4x:1; + he_ppdu_20_in_40Mhz_2G:1; + he_ppdu_20_in_160_80p80Mhz:1; + he_ppdu_80_in_160_80p80Mhz:1; + er_1x_he_ltf_gi:1; + midamble_tx_rx_1x_he_ltf:1; + dcm_max_bw:2; + longer_than_16_he_sigb_ofdm_sym:1; + non_trig_cqi_feedback:1; + tx_1024_qam_lt_242_tone_ru:1; + rx_1024_qam_lt_242_tone_ru:1; + rx_full_bw_su_he_mu_compress_sigb:1; + rx_full_bw_su_he_mu_non_cmpr_sigb:1; + reserved3:2; + } + reserved4, 1; + rx_he_mcs_map_lt_80, 2; + tx_he_mcs_map_lt_80, 2; + rx_he_mcs_map_160[2][0..1] COUNTIS chan_width_2; + tx_he_mcs_map_160[2][0..1] COUNTIS chan_width_2; + rx_he_mcs_map_80_80[2][0..1] COUNTIS chan_width_3; + tx_he_mcs_map_80_80[2][0..1] COUNTIS chan_width_3; + OPTIONAL UNION ppet (DISCRIMINATOR ppet_present) + { + ppe_threshold (ppet_present IS 1) + { + ppe_th[1..25]; + } + }; +} + +IE he_op (EID_EXTN_ID_ELEMENT) OUI (0x24) +{ + { + default_pe: 3; + twt_required: 1; + txop_rts_threshold: 10; + vht_oper_present: 1; + co_located_bss: 1; + } + { + er_su_disable: 1; + oper_info_6g_present: 1; + reserved2: 6; + } + { + bss_color:6; + partial_bss_col:1; + bss_col_disabled:1; + } + basic_mcs_nss[2]; + OPTIONAL UNION vht_oper (DISCRIMINATOR vht_oper_present) + { + info (vht_oper_present IS 1) + { + chan_width, 1; + center_freq_seg0, 1; + center_freq_seg1, 1; + } + }; + OPTIONAL UNION maxbssid_ind (DISCRIMINATOR co_located_bss) + { + info (co_located_bss IS 1) + { + data, 1; + } + }; + OPTIONAL UNION oper_info_6g (DISCRIMINATOR oper_info_6g_present) + { + info (oper_info_6g_present IS 1) + { + primary_ch, 1; + { // control + ch_width: 2; + dup_bcon: 1; + reg_info: 3; + reserved: 2; + } + center_freq_seg0, 1; + center_freq_seg1, 1; + min_rate, 1; + } + }; +} + +IE spatial_reuse (EID_EXTN_ID_ELEMENT) OUI (0x27) +{ + { + psr_disallow: 1; + non_srg_pd_sr_disallow: 1; + non_srg_offset_present: 1; + srg_info_present: 1; + sr_value15_allow: 1; + reserved: 3; + } + OPTIONAL UNION non_srg_offset (DISCRIMINATOR non_srg_offset_present) + { + info (non_srg_offset_present IS 1) + { + non_srg_pd_max_offset, 1; + } + }; + OPTIONAL UNION srg_info (DISCRIMINATOR srg_info_present) + { + info (srg_info_present IS 1) + { + srg_pd_min_offset, 1; + srg_pd_max_offset, 1; + srg_color[8]; + srg_partial_bssid[8]; + } + }; +} + +IE he_6ghz_band_cap (EID_EXTN_ID_ELEMENT) OUI (0x3B) +{ + { // capabilities_information + min_mpdu_start_spacing :3; + max_ampdu_len_exp: 3; + max_mpdu_len: 3; + sm_pow_save: 2; + rd_responder: 1; + rx_ant_pattern_consistency: 1; + tx_ant_pattern_consistency: 1; + reserved: 2; + } +} + +IE eht_cap (EID_EXTN_ID_ELEMENT) OUI (0x6C) +{ + { + epcs_pri_access: 1; + eht_om_ctl: 1; + triggered_txop_sharing_mode1: 1; + triggered_txop_sharing_mode2: 1; + restricted_twt: 1; + scs_traffic_desc: 1; + max_mpdu_len: 2; + max_a_mpdu_len_exponent_ext: 1; + eht_trs_support: 1; + txop_return_support_txop_share_m2: 1; + two_bqrs_support: 1; + eht_link_adaptation_support: 2; + reserved: 2; + } + { + reserved2: 1; + support_320mhz_6ghz: 1; + ru_242tone_wt_20mhz: 1; + ndp_4x_eht_ltf_3dot2_us_gi: 1; + partial_bw_mu_mimo: 1; + su_beamformer: 1; + su_beamformee: 1; + bfee_ss_le_80mhz: 3; + bfee_ss_160mhz: 3; + bfee_ss_320mhz: 3; + num_sounding_dim_le_80mhz: 3; + num_sounding_dim_160mhz: 3; + num_sounding_dim_320mhz: 3; + ng_16_su_feedback: 1; + ng_16_mu_feedback: 1; + cb_sz_4_2_su_feedback: 1; + cb_sz_7_5_su_feedback: 1; + trig_su_bforming_feedback: 1; + trig_mu_bforming_partial_bw_feedback: 1; + triggered_cqi_feedback: 1; + } + { + partial_bw_dl_mu_mimo: 1; + psr_based_sr: 1; + power_boost_factor: 1; + eht_mu_ppdu_4x_ltf_0_8_us_gi: 1; + max_nc: 4; + non_trig_cqi_feedback: 1; + tx_1024_4096_qam_lt_242_tone_ru: 1; + rx_1024_4096_qam_lt_242_tone_ru: 1; + ppet_present: 1; + common_nominal_pkt_padding: 2; + max_num_eht_ltf: 5; + mcs_15: 4; + eht_dup_6ghz: 1; + op_sta_rx_ndp_wider_bw_20mhz: 1; + non_ofdma_ul_mu_mimo_le_80mhz: 1; + non_ofdma_ul_mu_mimo_160mhz: 1; + non_ofdma_ul_mu_mimo_320mhz: 1; + mu_bformer_le_80mhz: 1; + mu_bformer_160mhz: 1; + mu_bformer_320mhz: 1; + tb_sounding_feedback_rl: 1; + } + { + rx_1k_qam_in_wider_bw_dl_ofdma: 1; + rx_4k_qam_in_wider_bw_dl_ofdma: 1; + limited_cap_support_20mhz: 1; + triggered_mu_bf_full_bw_fb_and_dl_mumimo: 1; + mru_support_20mhz: 1; + reserved3: 3; + } + { + bw_20_rx_max_nss_for_mcs_0_to_7: 4; + bw_20_tx_max_nss_for_mcs_0_to_7: 4; + bw_20_rx_max_nss_for_mcs_8_and_9: 4; + bw_20_tx_max_nss_for_mcs_8_and_9: 4; + bw_20_rx_max_nss_for_mcs_10_and_11: 4; + bw_20_tx_max_nss_for_mcs_10_and_11: 4; + bw_20_rx_max_nss_for_mcs_12_and_13: 4; + bw_20_tx_max_nss_for_mcs_12_and_13: 4; + + } + { + bw_le_80_rx_max_nss_for_mcs_0_to_9: 4; + bw_le_80_tx_max_nss_for_mcs_0_to_9: 4; + bw_le_80_rx_max_nss_for_mcs_10_and_11: 4; + bw_le_80_tx_max_nss_for_mcs_10_and_11: 4; + bw_le_80_rx_max_nss_for_mcs_12_and_13: 4; + bw_le_80_tx_max_nss_for_mcs_12_and_13: 4; + bw_160_rx_max_nss_for_mcs_0_to_9: 4; + bw_160_tx_max_nss_for_mcs_0_to_9: 4; + } + { + bw_160_rx_max_nss_for_mcs_10_and_11: 4; + bw_160_tx_max_nss_for_mcs_10_and_11: 4; + bw_160_rx_max_nss_for_mcs_12_and_13: 4; + bw_160_tx_max_nss_for_mcs_12_and_13: 4; + bw_320_rx_max_nss_for_mcs_0_to_9: 4; + bw_320_tx_max_nss_for_mcs_0_to_9: 4; + bw_320_rx_max_nss_for_mcs_10_and_11: 4; + bw_320_tx_max_nss_for_mcs_10_and_11: 4; + } + { + bw_320_rx_max_nss_for_mcs_12_and_13: 4; + bw_320_tx_max_nss_for_mcs_12_and_13: 4; + } + OPTIONAL UNION ppet (DISCRIMINATOR ppet_present) + { + ppe_threshold (ppet_present IS 1) + { + ppe_th[2..62]; + } + }; +} + +IE eht_op (EID_EXTN_ID_ELEMENT) OUI (0x6A) +{ + { + eht_op_information_present: 1; + disabled_sub_chan_bitmap_present: 1; + eht_default_pe_duration: 1; + group_addr_bu_indication_limit: 1; + group_addr_bu_indication_exponent: 2; + reserved: 2; + } + { + basic_rx_max_nss_for_mcs_0_to_7: 4; + basic_tx_max_nss_for_mcs_0_to_7: 4; + basic_rx_max_nss_for_mcs_8_and_9: 4; + basic_tx_max_nss_for_mcs_8_and_9: 4; + basic_rx_max_nss_for_mcs_10_and_11: 4; + basic_tx_max_nss_for_mcs_10_and_11: 4; + basic_rx_max_nss_for_mcs_12_and_13: 4; + basic_tx_max_nss_for_mcs_12_and_13: 4; + } + { + channel_width: 3; + reserved_1: 5; + } + ccfs0, 1; + ccfs1, 1; + disabled_sub_chan_bitmap[2][0..1] COUNTIS disabled_sub_chan_bitmap_present; +} + +IE mu_edca_param_set (EID_EXTN_ID_ELEMENT) OUI (0x26) +{ + qos, 1; + { + acbe_aifsn: 4; + acbe_acm: 1; + acbe_aci: 2; + unused1: 1; + } + { + acbe_acwmin: 4; + acbe_acwmax: 4; + } + acbe_muedca_timer, 1; + { + acbk_aifsn: 4; + acbk_acm: 1; + acbk_aci: 2; + unused2: 1; + } + { + acbk_acwmin: 4; + acbk_acwmax: 4; + } + acbk_muedca_timer, 1; + { + acvi_aifsn: 4; + acvi_acm: 1; + acvi_aci: 2; + unused3: 1; + } + { + acvi_acwmin: 4; + acvi_acwmax: 4; + } + acvi_muedca_timer, 1; + { + acvo_aifsn: 4; + acvo_acm: 1; + acvo_aci: 2; + unused4: 1; + } + { + acvo_acwmin: 4; + acvo_acwmax: 4; + } + acvo_muedca_timer, 1; +} + +IE bss_color_change (EID_EXTN_ID_ELEMENT) OUI (0x2A) +{ + countdown, 1; + { + new_color: 6; + reserved: 2; + } +} + +///////////////////////////////////////////////////////////////////////////// +// MULTIIEs // +///////////////////////////////////////////////////////////////////////////// + +MULTIIE WSC ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // Must be 0x10 + OPTIONALTLV WPSState; + OPTIONALTLV APSetupLocked; + OPTIONALTLV SelectedRegistrarConfigMethods; + OPTIONALTLV UUID_E; + OPTIONALTLV UUID_R; + OPTIONALTLV RFBands; + OPTIONALTLV SelectedRegistrar; + OPTIONALTLV ConfigMethods; + OPTIONALTLV AssociationState; + OPTIONALTLV ConfigurationError; + OPTIONALTLV Manufacturer; + OPTIONALTLV ModelName; + OPTIONALTLV ModelNumber; + OPTIONALTLV SerialNumber; + OPTIONALTLV DeviceName; + OPTIONALTLV DevicePasswordID; + OPTIONALTLV PrimaryDeviceType; + OPTIONALTLV RequestType; + OPTIONALTLV ResponseType; + OPTIONALTLV VendorExtension; + OPTIONALTLV RequestDeviceType; +} + +MULTIIE WscBeacon ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + OPTIONALTLV UUID_E; // The AP's UUID is provided + // only when the AP is a + // dual-band AP in push + // button mode and + // indicating push button + // mode on both radios + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // End Multi-IE WscBeacon. + +MULTIIE WscAssocReq ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV RequestType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscAssocReq. + + +MULTIIE WscAssocRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV ResponseType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscAssocRes. + +MULTIIE WscReassocRes ( 221 ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV ResponseType; // + // + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 + +} // End Multi-IE WscReassocRes + +MULTIIE WscProbeReq ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV RequestType; // + // + MANDATORYTLV ConfigMethods; // Configuration methods the + // Enrollee or Registrar + // supports + MANDATORYTLV UUID_E; // unique GUID generated by + // the Enrollee. + MANDATORYTLV PrimaryDeviceType; + MANDATORYTLV RFBands; // Specific RF bands used + // for this message + MANDATORYTLV AssociationState; // Configuration and previous + // association state + MANDATORYTLV ConfigurationError; + MANDATORYTLV DevicePasswordID; + + // WSC 2.0 + OPTIONALTLV Manufacturer; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV ModelName; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV ModelNumber; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV DeviceName; // Must be included in ver 2.0 + // or higher. + OPTIONALTLV VendorExtension; // Version2 and RequestToEntroll + + OPTIONALTLV RequestDeviceType; // When a device receives a Probe + // Request containing this type, + // It will only respond if Primary + // or Secondary Device Type matches. + +} // End Multi-IE WscProbeReq. + +MULTIIE WscProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + MANDATORYTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + MANDATORYTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + MANDATORYTLV ResponseType; + MANDATORYTLV UUID_E; // unique identifier of AP + MANDATORYTLV Manufacturer; + MANDATORYTLV ModelName; + MANDATORYTLV ModelNumber; + MANDATORYTLV SerialNumber; + MANDATORYTLV PrimaryDeviceType; + MANDATORYTLV DeviceName; // User-friendly description + // of device + MANDATORYTLV ConfigMethods; // Config Methods corresponds + // to the methods the AP + // supports as an Enrollee + // for adding external + // Registrars. + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // WscProbeRes. + +// This MULTIIE combines the fields from the WSC IEs as they appear in +// Beacons *and* in Probe Responses, with the difference that they're all +// optional. In our device drivers, we combine Probe Responses and Beacons +// into one list, and parse their IEs later (c.f. frame BeaconIEs). Because +// the WSC IE differs in those two frames, we'd often see warning messages +// about either unexpected fields showing up (if we thought we were parsing a +// Beacon, and we in fact had data from a Probe Response) or mandatory fields +// missing (if we thought we were parsing a Probe Response, and in fact had +// data from a Beacon). + +// I created this MULTIIE to stuff into the BeaconIEs frames to avoid this. +// It's intended to be used on unpack only, and to do so in a very forgiving +// way. + +MULTIIE WscBeaconProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x00, 0x50, 0xF2, 0x04 ) +{ + OPTIONALTLV Version; // 0x10 = version 1.0, 0x11 + // = version 1.1, etc. + OPTIONALTLV WPSState; // 1 = unconfigured, 2 = + // configured + OPTIONALTLV APSetupLocked; // Must be included if value + // is TRUE + OPTIONALTLV SelectedRegistrar; // BOOL: indicates if the + // user has recently + // activated a Registrar to + // add an Enrollee. + OPTIONALTLV DevicePasswordID; // Device Password ID + // indicates the method or + // identifies the specific + // password that the + // selected Registrar + // intends to use. + OPTIONALTLV SelectedRegistrarConfigMethods; // This attribute contains + // the config methods active + // on the selected + // Registrar. + OPTIONALTLV ResponseType; + OPTIONALTLV UUID_E; // unique identifier of AP + OPTIONALTLV Manufacturer; + OPTIONALTLV ModelName; + OPTIONALTLV ModelNumber; + OPTIONALTLV SerialNumber; + OPTIONALTLV PrimaryDeviceType; + OPTIONALTLV DeviceName; // User-friendly description + // of device + OPTIONALTLV ConfigMethods; // Config Methods corresponds + // to the methods the AP + // supports as an Enrollee + // for adding external + // Registrars. + OPTIONALTLV RFBands; // Indicates all RF bands + // available on the AP. A + // dual-band AP must provide + // this attribute. + // WSC 2.0 + OPTIONALTLV VendorExtension; // Version2 and AuthorizedMACs + +} // WscProbeRes. +///////////////////////////////////////////////////////////////////////////// +// MULTIIEs // +///////////////////////////////////////////////////////////////////////////// + +MULTIIE P2PBeacon ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; // Contains P2P Device + // and P2P Group Capability + MANDATORYTLV P2PDeviceId; // Contains P2P Device + // Address + OPTIONALTLV NoticeOfAbsence; // Indicates Notice of + // Absence schedule and + // CT Window + +} // End P2PBeacon + + +MULTIIE P2PAssocReq ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; // Contains P2P Device + // and P2P Group Capability + OPTIONALTLV ExtendedListenTiming; + MANDATORYTLV P2PDeviceInfo; + +} // End P2PAssocReq + + +MULTIIE P2PAssocRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PStatus; + OPTIONALTLV ExtendedListenTiming; + +} // End P2PAssocRes + + +MULTIIE P2PProbeReq ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; + OPTIONALTLV P2PDeviceId; + MANDATORYTLV ListenChannel; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV OperatingChannel; +} // End P2PProbeReq + + +MULTIIE P2PProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV P2PCapability; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV NoticeOfAbsence; + MANDATORYTLV P2PDeviceInfo; + OPTIONALTLV P2PGroupInfo; + +} // End P2PProbeRes + + +MULTIIE P2PBeaconProbeRes ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + OPTIONALTLV P2PCapability; + OPTIONALTLV P2PDeviceId; + OPTIONALTLV ExtendedListenTiming; + OPTIONALTLV NoticeOfAbsence; + OPTIONALTLV P2PDeviceInfo; + OPTIONALTLV P2PGroupInfo; + +} // End P2PBeaconProbeRes + + +MULTIIE P2PDeAuth ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV MinorReasonCode; +} + + +MULTIIE P2PDisAssoc ( EID_VENDOR_SPECIFIC ) OUI( 0x50, 0x6F, 0x9A, 0x09 ) +{ + MANDATORYTLV MinorReasonCode; +} + +MULTIIE MBO_IE (EID_VENDOR_SPECIFIC) OUI ( 0x50, 0x6F, 0x9A, 0x16 ) +{ + OPTIONALTLV mbo_ap_cap; + OPTIONALTLV non_prefferd_chan_rep; + OPTIONALTLV cellular_data_cap ; + OPTIONALTLV assoc_disallowed; + OPTIONALTLV cellular_data_con_pref; + OPTIONALTLV transition_reason; + OPTIONALTLV transition_reject_reason; + OPTIONALTLV assoc_retry_delay; + OPTIONALTLV oce_cap; + OPTIONALTLV rssi_assoc_rej; + OPTIONALTLV reduced_wan_metrics; +} + +IE vendor_vht_ie (EID_VENDOR_SPECIFIC) OUI (0x00, 0x90, 0x4c, 0x04) +{ + sub_type, 1; + OPTIE IE VHTCaps; + OPTIE IE VHTOperation; +} + +IE non_inheritance (EID_EXTN_ID_ELEMENT) OUI (0x38) +{ + data[0..255]; +} + +IE mlo_ie (EID_EXTN_ID_ELEMENT) OUI (0x6B) +{ + data[9..255]; +} + +IE t2lm_ie (EID_EXTN_ID_ELEMENT) OUI (0x6D) +{ + data[3..255]; +} + +///////////////////////////////////////////////////////////////////////////// +// Frames + +FRAME Beacon // C.f. Sec. 7.2.3.1 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE OBSSScanParameters; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE transmit_power_env[0..8]; + OPTIE ChannelSwitchWrapper; + OPTIE VHTExtBssLoad; + OPTIE OperatingMode; + OPTIE fils_indication; + OPTIE max_chan_switch_time; + OPTIE esp_information; + OPTIE he_cap; + OPTIE he_op; + OPTIE spatial_reuse; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE he_6ghz_band_cap; + + OPTIE sec_chan_offset_ele; + OPTIE WAPI; + OPTIE ESETxmitPower; + OPTIE WiderBWChanSwitchAnn; + OPTIE eht_cap; + OPTIE eht_op; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPA; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESEVersion; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE WscBeacon; + OPTIE P2PBeacon; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE QComVendorIE; + OPTIE MBO_IE; + OPTIE qcn_ie; + OPTIE reduced_neighbor_report; +} // End frame Beacon. + +// Ok, here's the story on Beacon1 & Beacon2. We presumably beacon a lot +// more than we change configuration. So it makes sense to keep the beacon +// we plan to send next in serialized format. We do this in struct schMisc. +// Whenever our config changes in a way that would affect our beacons, we +// just update our internal datastructures & re-generate the serialized +// beacon. + +// The problem is that there are *some* fields that need to be updated at +// send time, specifically the CF Param Set & the TIM. So, what we do is +// this: whenever our config changes, call schSetFixedBeaconFields. There, +// we serialize the following Beacon fields into gSchBeaconFrameBegin (after +// the power template & MAC header): TimeStamp, BeaconInterval, Capabilities, +// SSID, SuppRates, DSParams. It sets gSchBeaconOffsetBegin to +// the length of this buffer (incl. power template & MAC header). + +// Next, it serializes the following fields into gSchBeaconFrameEnd: Country, +// EDCAParamSet, PowerConstraints, TPCReport, ChannelSwitchAnn, Quiet, +// ERPInfo, HTCaps, HTInfo, ExtSuppRates, WPA, RSN, WMMInfo, +// WMMParams, WMMCaps. +// The length of *this* buffer is kept in gSchBeaconOffsetEnd. + +// Then, in 'schBeaconInterruptHandler', we write CFParams & TIM at the end +// of gSchBeaconFrameBegin, keeping track of the (new) size of this buffer in +// the local 'beaconSize'. + +// After that, we call 'specialBeaconProcessing'. Note that this may +// actually call schSetFixedBeaconFields repeatedly! The comments say they +// try to avoid this, but... + +// Finally, we call writeBeaconToTFP, where the first thing we do is copy the +// gSchBeaconFrameEnd buffer after the end of gSchBeaconFrameBegin. + +FRAME Beacon1 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE DSParams; +} + +FRAME Beacon2 +{ + OPTIE Country; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE EDCAParamSet; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE OBSSScanParameters; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE transmit_power_env[0..8]; + OPTIE ChannelSwitchWrapper; + OPTIE VHTExtBssLoad; + OPTIE OperatingMode; + OPTIE fils_indication; + OPTIE max_chan_switch_time; + OPTIE esp_information; + OPTIE he_cap; + OPTIE he_op; + OPTIE spatial_reuse; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE he_6ghz_band_cap; + + OPTIE sec_chan_offset_ele; + OPTIE WAPI; + OPTIE ESETxmitPower; + OPTIE WiderBWChanSwitchAnn; + OPTIE eht_cap; + OPTIE eht_op; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPA; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE WscBeacon; + OPTIE P2PBeacon; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE QComVendorIE; + OPTIE ESEVersion; + OPTIE qcn_ie; + OPTIE reduced_neighbor_report; +} + +// This frame is just Beacon with its Fixed Fields stripped out. It's handy +// for use with struct 'tSirBssDescription', which has members corresponding +// to some fixed fields, but keeps its IEs in un-parsed format. + +// Note that it also includes the IE 'WscBeaconProbeRes'. + +FRAME BeaconIEs +{ + + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE TIM; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSN; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE QOSCapsAp; + OPTIE APChannelReport; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE OBSSScanParameters; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE transmit_power_env[0..8]; + OPTIE ChannelSwitchWrapper; + OPTIE VHTExtBssLoad; + OPTIE OperatingMode; + OPTIE fils_indication; + OPTIE max_chan_switch_time; + OPTIE esp_information; + OPTIE he_cap; + OPTIE he_op; + OPTIE spatial_reuse; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE he_6ghz_band_cap; + + OPTIE sec_chan_offset_ele; + OPTIE WAPI; + OPTIE ESETxmitPower; + OPTIE WiderBWChanSwitchAnn; + OPTIE eht_cap; + OPTIE eht_op; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPA; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESEVersion; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE WscBeaconProbeRes; + OPTIE P2PBeaconProbeRes; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE QComVendorIE; + OPTIE MBO_IE; + OPTIE qcn_ie; + OPTIE reduced_neighbor_report; +} // End frame BeaconIEs. + +FRAME Disassociation // 7.3.3.3 +{ + FF Reason; + OPTIE P2PDisAssoc; +} + +FRAME AssocRequest // 7.2.3.4 +{ + FF Capabilities; + FF ListenInterval; + MANDIE SSID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE RSNOpaque; + OPTIE QOSCapsStation; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE SuppOperatingClasses; + OPTIE HTCaps; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE OperatingMode; + OPTIE fils_session; + OPTIE fils_public_key; + OPTIE fils_key_confirmation; + OPTIE fils_hlp_container; + OPTIE bss_max_idle_period; + OPTIE FTInfo; + OPTIE he_cap; + OPTIE he_6ghz_band_cap; + + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE QosMapSet; + OPTIE fragment_ie; + OPTIE dh_parameter_element; + OPTIE eht_cap; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPAOpaque; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE vendor_vht_ie; + OPTIE hs20vendor_ie; + OPTIE qcn_ie; + OPTIE osen_ie; + OPTIE roaming_consortium_sel; +} // End frame AssocRequest. + +FRAME AssocResponse // 7.2.3.5 +{ + FF Capabilities; + FF Status; + FF AID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE EDCAParamSet; + OPTIE RCPIIE; + OPTIE RSNIIE; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE OBSSScanParameters; + OPTIE ExtCap; + OPTIE bss_max_idle_period; + OPTIE QosMapSet; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE OperatingMode; + OPTIE fils_session; + OPTIE fils_public_key; + OPTIE fils_key_confirmation; + OPTIE fils_hlp_container; + OPTIE he_cap; + OPTIE he_op; + OPTIE spatial_reuse; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE he_6ghz_band_cap; + + OPTIE RICDataDesc[2]; + OPTIE ESETxmitPower; + OPTIE fragment_ie; + OPTIE fils_kde; + OPTIE eht_cap; + OPTIE eht_op; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPA; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE WMMTSPEC[0..4]; + OPTIE WscAssocRes; + OPTIE P2PAssocRes; + OPTIE vendor_vht_ie; + OPTIE qcn_ie; + OPTIE MBO_IE; + OPTIE reduced_neighbor_report; +} // End frame AssocResponse. + +FRAME ReAssocRequest // 7.2.3.6 +{ + FF Capabilities; + FF ListenInterval; + FF CurrentAPAddress; + MANDIE SSID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE PowerCaps; + OPTIE SuppChannels; + OPTIE RSNOpaque; + OPTIE QOSCapsStation; + OPTIE RRMEnabledCap; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE SuppOperatingClasses; + OPTIE HTCaps; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE OperatingMode; + OPTIE bss_max_idle_period; + OPTIE he_cap; + OPTIE he_6ghz_band_cap; + + OPTIE WAPIOpaque; + OPTIE WAPI; + OPTIE QosMapSet; + OPTIE ESECckmOpaque; + OPTIE eht_cap; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPAOpaque; + OPTIE WMMCaps; + OPTIE WMMInfoStation; + OPTIE WscIEOpaque; + OPTIE ESERadMgmtCap; + OPTIE ESEVersion; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE P2PIEOpaque; + OPTIE WFDIEOpaque; + OPTIE vendor_vht_ie; + OPTIE hs20vendor_ie; +} // End frame ReAssocRequest. + +FRAME ReAssocResponse // 7.2.3.7 +{ + FF Capabilities; + FF Status; + FF AID; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE EDCAParamSet; + OPTIE RCPIIE; + OPTIE RSNIIE; + OPTIE RRMEnabledCap; + OPTIE RSNOpaque; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE RICDataDesc[2]; + OPTIE TimeoutInterval; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE OBSSScanParameters; + OPTIE ExtCap; + OPTIE bss_max_idle_period; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE OperatingMode; + OPTIE he_cap; + OPTIE he_op; + OPTIE spatial_reuse; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE he_6ghz_band_cap; + + OPTIE QosMapSet; + OPTIE ESETxmitPower; + OPTIE eht_cap; + OPTIE eht_op; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPA; + OPTIE WMMParams; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE WMMTSPEC[0..4]; + OPTIE ESETrafStrmRateSet; + OPTIE WscReassocRes; + OPTIE P2PAssocRes; + OPTIE vendor_vht_ie; + OPTIE MBO_IE; + OPTIE reduced_neighbor_report; +} // End frame ReAssocResponse. + +FRAME ProbeRequest // 7.2.3.8 +{ + MANDIE SSID; + MANDIE SuppRates; + OPTIE RequestedInfo; + OPTIE ExtSuppRates; + OPTIE DSParams; + OPTIE HTCaps; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE he_cap; + OPTIE he_6ghz_band_cap; + + OPTIE eht_cap; + OPTIE mlo_ie; + + OPTIE WscProbeReq; + OPTIE WFATPC; + OPTIE P2PProbeReq; + OPTIE qcn_ie; +} // End frame ProbeRequest. + +FRAME ProbeResponse // 7.2.3.9 +{ + FF TimeStamp; + FF BeaconInterval; + FF Capabilities; + MANDIE SSID; + MANDIE SuppRates; + OPTIE FHParamSet; + OPTIE DSParams; + OPTIE CFParams; + OPTIE Country; + OPTIE FHParams; + OPTIE FHPattTable; + OPTIE PowerConstraints; + OPTIE ChanSwitchAnn; + OPTIE Quiet; + OPTIE TPCReport; + OPTIE ERPInfo; + OPTIE ExtSuppRates; + OPTIE RSNOpaque; + OPTIE QBSSLoad; + OPTIE EDCAParamSet; + OPTIE RRMEnabledCap; + OPTIE APChannelReport; + OPTIE MobilityDomain; + OPTIE ext_chan_switch_ann; + OPTIE SuppOperatingClasses; + OPTIE HTCaps; + OPTIE HTInfo; + OPTIE OBSSScanParameters; + OPTIE ExtCap; + OPTIE VHTCaps; + OPTIE VHTOperation; + OPTIE transmit_power_env[0..8]; + OPTIE ChannelSwitchWrapper; + OPTIE VHTExtBssLoad; + OPTIE fils_indication; + OPTIE max_chan_switch_time; + OPTIE esp_information; + OPTIE he_cap; + OPTIE he_op; + OPTIE spatial_reuse; + OPTIE bss_color_change; + OPTIE mu_edca_param_set; + OPTIE he_6ghz_band_cap; + + OPTIE sec_chan_offset_ele; + OPTIE WAPI; + OPTIE ESETxmitPower; + OPTIE eht_cap; + OPTIE eht_op; + OPTIE mlo_ie; + OPTIE t2lm_ie[0..2]; + + OPTIE WPA; + OPTIE WMMInfoAp; + OPTIE WMMParams; + OPTIE WMMCaps; + OPTIE ESEVersion; + OPTIE ESERadMgmtCap; + OPTIE ESETrafStrmMet; + OPTIE WscProbeRes; + OPTIE P2PProbeRes; + OPTIE Vendor1IE; + OPTIE vendor_vht_ie; + OPTIE Vendor3IE; + OPTIE hs20vendor_ie; + OPTIE QComVendorIE; + OPTIE MBO_IE; + OPTIE qcn_ie; + OPTIE reduced_neighbor_report; +} // End frame ProbeResponse. + +FRAME Authentication // 7.2.3.10 +{ + FF AuthAlgo; + FF AuthSeqNo; + FF Status; + OPTIE ChallengeText; + OPTIE RSNOpaque; + OPTIE MobilityDomain; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICDataDesc[2]; + OPTIE fils_nonce; + OPTIE fils_session; + OPTIE fils_wrapped_data; + OPTIE fils_assoc_delay_info; + OPTIE mlo_ie; +} // End frame Auth. + +FRAME DeAuth // 7.2.3.11 +{ + FF Reason; + OPTIE P2PDeAuth; +} + + +FRAME AddTSRequest // 7.4.2.1 +{ + + FF Category; + FF Action; + FF DialogToken; + MANDIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + + // These IEs aren't in the spec, but our extant code *will* parse them if + // they're present. I included them to preserve that capability + + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE ESETrafStrmRateSet; + +} // End frame AddTSRequest. + +FRAME WMMAddTSRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + MANDIE WMMTSPEC; + OPTIE ESETrafStrmRateSet; +} // End Frame WMMAddTSRequest + +FRAME AddTSResponse // 7.4.2.2 +{ + + FF Category; + FF Action; + FF DialogToken; + FF Status; + MANDIE TSDelay; + MANDIE TSPEC; + OPTIE TCLAS[0..2]; + OPTIE TCLASSPROC; + OPTIE Schedule; + + // These IEs aren't in the spec, but our extant code *will* parse them if + // they're present. I included them to preserve that capability + OPTIE WMMTSDelay; + OPTIE WMMSchedule; + OPTIE WMMTSPEC; + OPTIE WMMTCLAS[0..2]; + OPTIE WMMTCLASPROC; + OPTIE ESETrafStrmMet; + +} // End frame AddTSResponse. + +FRAME WMMAddTSResponse +{ + + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + OPTIE WMMTSPEC; + OPTIE ESETrafStrmMet; + +} // End frame WMMAddTSResponse. + +FRAME DelTS // 7.4.2.3 +{ + FF Category; + FF Action; + FF TSInfo; + FF Reason; +} + +FRAME WMMDelTS +{ + FF Category; + FF Action; + FF DialogToken; + FF StatusCode; + MANDIE WMMTSPEC; +} + +FRAME TPCRequest +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE TPCRequest; +} + +FRAME TPCReport +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE TPCReport; +} + +FRAME ChannelSwitch +{ + FF Category; + FF Action; + MANDIE ChanSwitchAnn; + OPTIE sec_chan_offset_ele; + OPTIE WiderBWChanSwitchAnn; +} + +FRAME MeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE MeasurementRequest[1..4]; +} + +FRAME MeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE MeasurementReport; +} + +FRAME SMPowerSave +{ + FF Category; + FF Action; + FF SMPowerModeSet; +} + +FRAME RadioMeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF NumOfRepetitions; + //Measurement Request IE. + MANDIE MeasurementRequest[1..5]; +} + +FRAME RadioMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + //Measurement Report elements. + MANDIE MeasurementReport[1]; +} + +FRAME LinkMeasurementRequest +{ + FF Category; + FF Action; + FF DialogToken; + FF TxPower; + FF MaxTxPower; + //Optional Sub Ies +} + +FRAME LinkMeasurementReport +{ + FF Category; + FF Action; + FF DialogToken; + FF TPCEleID; + FF TPCEleLen; + FF TxPower; + FF LinkMargin; + FF RxAntennaId; + FF TxAntennaId; + FF RCPI; + FF RSNI; + //Optional Vendor specific IEs ... ignoring +} + +FRAME NeighborReportRequest +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE SSID; + //Optional vendor specific IE...ignoring. +} + +FRAME NeighborReportResponse +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE NeighborReport[1..MAX_SUPPORTED_NEIGHBOR_RPT]; +} + +FRAME OperatingMode +{ + FF Category; + FF Action; + //Operating Mode field + FF OperatingMode; +} + +FRAME TDLSDisReq +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; +} + +FRAME TDLSDisRsp +{ + FF Category; + FF Action; + FF DialogToken; + FF Capabilities; + MANDIE SuppRates; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE SuppOperatingClasses; + OPTIE RSN; + OPTIE ExtCap; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + MANDIE LinkIdentifier; + OPTIE VHTCaps; + OPTIE he_cap; +} + +FRAME TDLSSetupReq +{ + FF Category; + FF Action; + FF DialogToken; + FF Capabilities; + MANDIE SuppRates; + OPTIE Country; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE RSN; + OPTIE ExtCap; + OPTIE SuppOperatingClasses; + OPTIE QOSCapsStation; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + MANDIE LinkIdentifier; + OPTIE WMMInfoStation; + OPTIE AID; + OPTIE VHTCaps; + OPTIE he_cap; + OPTIE he_6ghz_band_cap; +} + +FRAME TDLSSetupRsp +{ + FF Category; + FF Action; + FF Status; + FF DialogToken; + FF Capabilities ; + OPTIE SuppRates; + OPTIE Country; + OPTIE ExtSuppRates; + OPTIE SuppChannels; + OPTIE RSN; + OPTIE ExtCap; + OPTIE SuppOperatingClasses; + OPTIE QOSCapsStation; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE RICData; + OPTIE HTCaps; + OPTIE ht2040_bss_coexistence; + OPTIE LinkIdentifier; + OPTIE WMMInfoStation; + OPTIE AID; + OPTIE VHTCaps; + OPTIE OperatingMode; + OPTIE he_cap; + OPTIE he_6ghz_band_cap; +} + +FRAME TDLSSetupCnf +{ + FF Category; + FF Action; + FF Status; + FF DialogToken; + OPTIE RSN; + OPTIE EDCAParamSet; + OPTIE FTInfo; + OPTIE TimeoutInterval; + OPTIE HTInfo; + OPTIE LinkIdentifier; + OPTIE WMMParams; + OPTIE VHTOperation; + OPTIE OperatingMode; + OPTIE he_op; +} +FRAME TDLSTeardown +{ + FF Category; + FF Action; + FF Reason; + OPTIE FTInfo; + MANDIE LinkIdentifier; +} + +FRAME TDLSPeerTrafficInd +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; + OPTIE PTIControl; + MANDIE PUBufferStatus; +} + +FRAME TDLSPeerTrafficRsp +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE LinkIdentifier; +} + +FRAME SaQueryReq +{ + FF Category; + FF Action; + FF TransactionId; + OPTIE oci; +} + +FRAME SaQueryRsp +{ + FF Category; + FF Action; + FF TransactionId; + OPTIE oci; +} + +FRAME QosMapConfigure +{ + FF Category; + FF Action; + MANDIE QosMapSet; +} + +FRAME VHTGidManagementActionFrame +{ + FF Category; + FF Action; + FF VhtMembershipStatusArray; + FF VhtUserPositionArray; +} + +FRAME ht2040_bss_coexistence_mgmt_action_frame +{ + FF Category; + FF Action; + MANDIE ht2040_bss_coexistence; + MANDIE ht2040_bss_intolerant_report; +} + +FRAME TimingAdvertisementFrame // 8.3.3.15 +{ + FF TimeStamp; + FF Capabilities; + OPTIE Country; + OPTIE PowerConstraints; + OPTIE TimeAdvertisement; + OPTIE ExtCap; + OPTIE Vendor1IE; + OPTIE Vendor3IE; +} + +FRAME ext_channel_switch_action_frame +{ + FF Category; + FF Action; + FF ext_chan_switch_ann_action; + OPTIE WiderBWChanSwitchAnn; + OPTIE qcn_ie; + OPTIE bw_ind_element; +} + +FRAME p2p_oper_chan_change_confirm +{ + FF Category; + FF p2p_action_oui; + FF p2p_action_subtype; + FF DialogToken; + OPTIE HTCaps; + OPTIE VHTCaps; + OPTIE OperatingMode; +} + +FRAME addba_req +{ + FF Category; + FF Action; + FF DialogToken; + FF addba_param_set; + FF ba_timeout; + FF ba_start_seq_ctrl; + OPTIE addba_extn_element; +} + +FRAME addba_rsp +{ + FF Category; + FF Action; + FF DialogToken; + FF Status; + FF addba_param_set; + FF ba_timeout; + OPTIE addba_extn_element; +} + +FRAME delba_req +{ + FF Category; + FF Action; + FF delba_param_set; + FF Reason; +} + +FRAME t2lm_neg_req +{ + FF Category; + FF Action; + FF DialogToken; + OPTIE t2lm_ie[0..2]; +} + +FRAME t2lm_neg_rsp +{ + FF Category; + FF Action; + FF DialogToken; + FF Status; +} + +FRAME t2lm_teardown +{ + FF Category; + FF Action; +} + +FRAME vendor_action_frame +{ + FF Category; + FF vendor_oui; + FF vendor_action_subtype; +} + +FRAME mscs_request_action_frame +{ + FF Category; + FF Action; + FF DialogToken; + MANDIE descriptor_element; +} + +FRAME epcs_neg_req +{ + FF Category; + FF Action; + FF DialogToken; +} + +FRAME epcs_neg_rsp +{ + FF Category; + FF Action; + FF DialogToken; + FF Status; +} + +FRAME epcs_teardown +{ + FF Category; + FF Action; +} + +// Local Variables: +// mode: c++ +// fill-column: 77 +// comment-column: 42 +// indent-tabs-mode: nil +// show-trailing-whitespace: t +// End: + +// parser.frms ends here. diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/dph/dph_hash_table.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/dph/dph_hash_table.c new file mode 100644 index 0000000000..0058e30c9c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/dph/dph_hash_table.c @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file dph_hash_table.cc implements the member functions of + * DPH hash table class. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "sch_api.h" +#include "dph_global.h" +#include "lim_api.h" +#include "wma_if.h" +#include "wlan_mlme_api.h" + +void dph_hash_table_init(struct mac_context *mac, + struct dph_hash_table *hash_table) +{ + uint16_t i; + + for (i = 0; i < hash_table->size; i++) { + hash_table->pHashTable[i] = 0; + } + + for (i = 0; i < hash_table->size; i++) { + hash_table->pDphNodeArray[i].valid = 0; + hash_table->pDphNodeArray[i].added = 0; + hash_table->pDphNodeArray[i].assocId = i; + } + +} + +/* --------------------------------------------------------------------- */ +/** + * hash_function + * + * FUNCTION: + * Hashing function + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @return None + */ + +static uint16_t hash_function(struct mac_context *mac, uint8_t staAddr[], + uint16_t numSta) +{ + int i; + uint16_t sum = 0; + + for (i = 0; i < 6; i++) + sum += staAddr[i]; + + return sum % numSta; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_hash_entry + * + * FUNCTION: + * Look up an entry in hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param pStaId pointer to the Station ID assigned to the station + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_lookup_hash_entry(struct mac_context *mac, uint8_t staAddr[], + uint16_t *pAssocId, + struct dph_hash_table *hash_table) +{ + tpDphHashNode ptr = NULL; + uint16_t index = hash_function(mac, staAddr, hash_table->size); + + if (!hash_table->pHashTable) { + pe_err("pHashTable is NULL"); + return ptr; + } + + for (ptr = hash_table->pHashTable[index]; ptr; ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) { + *pAssocId = ptr->assocId; + break; + } + } + return ptr; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/* --------------------------------------------------------------------- */ +/** + * dph_lookup_hash_entry_by_mld_addr + * + * FUNCTION: + * Look up an entry in hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param mld_addr MLD MAC address of the station + * @param pStaId pointer to the Station ID assigned to the station + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_lookup_hash_entry_by_mld_addr( + struct mac_context *mac, + uint8_t mld_addr[], + uint16_t *pAssocId, + struct dph_hash_table *hash_table) +{ + tpDphHashNode ptr = NULL; + uint16_t i = 0; + + if (!hash_table->pHashTable) { + pe_err("pHashTable is NULL"); + return ptr; + } + + for (i = 0; i < hash_table->size; i++) { + for (ptr = hash_table->pHashTable[i]; ptr; ptr = ptr->next) { + if (dph_compare_mac_addr(mld_addr, ptr->mld_addr)) { + *pAssocId = ptr->assocId; + return ptr; + } + } + } + return ptr; +} +#endif + +/* --------------------------------------------------------------------- */ +/** + * dph_get_hash_entry + * + * FUNCTION: + * Get a pointer to the hash node + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staId Station ID + * @return pointer to STA hash entry if lookup was a success \n + * NULL if lookup was a failure + */ + +tpDphHashNode dph_get_hash_entry(struct mac_context *mac, uint16_t peerIdx, + struct dph_hash_table *hash_table) +{ + if (peerIdx < hash_table->size) { + if (hash_table->pDphNodeArray[peerIdx].added) + return &hash_table->pDphNodeArray[peerIdx]; + else + return NULL; + } else + return NULL; + +} + +static inline tpDphHashNode get_node(struct mac_context *mac, uint8_t assocId, + struct dph_hash_table *hash_table) +{ + return &hash_table->pDphNodeArray[assocId]; +} + +/** ------------------------------------------------------------- + \fn dph_init_sta_state + \brief Initialize STA state. this function saves the staId from the current entry in the DPH table with given assocId + \ if validStaIdx flag is set. Otherwise it sets the staId to invalid. + \param struct mac_context * mac + \param tSirMacAddr staAddr + \param uint16_t assocId + \param uint8_t validStaIdx - true ==> the staId in the DPH entry with given assocId is valid and restore it back. + \ false ==> set the staId to invalid. + \return tpDphHashNode - DPH hash node if found. + -------------------------------------------------------------*/ + +tpDphHashNode dph_init_sta_state(struct mac_context *mac, tSirMacAddr staAddr, + uint16_t assocId, + struct dph_hash_table *hash_table) +{ + tpDphHashNode sta, pnext; + + if (assocId >= hash_table->size) { + pe_err("Invalid Assoc Id %d", assocId); + return NULL; + } + + sta = get_node(mac, (uint8_t) assocId, hash_table); + pnext = sta->next; + + /* Clear the STA node except for the next pointer */ + qdf_mem_zero((uint8_t *)sta, sizeof(tDphHashNode)); + sta->next = pnext; + + /* Initialize the assocId */ + sta->assocId = assocId; + + /* Initialize STA mac address */ + qdf_mem_copy(sta->staAddr, staAddr, sizeof(tSirMacAddr)); + + sta->added = 1; + sta->is_disassoc_deauth_in_progress = 0; + sta->sta_deletion_in_progress = false; + sta->valid = 1; + sta->is_key_installed = 0; + return sta; +} + +/* --------------------------------------------------------------------- */ +/** + * dph_add_hash_entry + * + * FUNCTION: + * Add entry to hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param staId Station ID assigned to the station + * @return Pointer to STA hash entry + */ + +tpDphHashNode dph_add_hash_entry(struct mac_context *mac, tSirMacAddr staAddr, + uint16_t assocId, + struct dph_hash_table *hash_table) +{ + tpDphHashNode ptr, node; + uint16_t index = hash_function(mac, staAddr, hash_table->size); + + pe_debug("assocId: %d index: %d STA addr: "QDF_MAC_ADDR_FMT, + assocId, index, QDF_MAC_ADDR_REF(staAddr)); + + if (assocId >= hash_table->size) { + pe_err("invalid STA id %d", assocId); + return NULL; + } + + if (hash_table->pDphNodeArray[assocId].added) { + pe_err("already added STA %d", assocId); + return NULL; + } + + for (ptr = hash_table->pHashTable[index]; ptr; ptr = ptr->next) { + if (ptr == ptr->next) { + pe_err("Infinite Loop"); + return NULL; + } + + if (dph_compare_mac_addr(staAddr, ptr->staAddr) + || ptr->assocId == assocId) + break; + } + + if (ptr) { + /* Duplicate entry */ + pe_err("assocId %d hashIndex %d entry exists", + assocId, index); + return NULL; + } else { + if (dph_init_sta_state + (mac, staAddr, assocId, hash_table) == NULL) { + pe_err("could not Init STA id: %d", assocId); + return NULL; + } + /* Add the node to the link list */ + hash_table->pDphNodeArray[assocId].next = + hash_table->pHashTable[index]; + hash_table->pHashTable[index] = + &hash_table->pDphNodeArray[assocId]; + + node = hash_table->pHashTable[index]; + return node; + } +} + +/* --------------------------------------------------------------------- */ +/** + * dph_delete_hash_entry + * + * FUNCTION: + * Delete entry from hash table + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param staAddr MAC address of the station + * @param staId Station ID assigned to the station + * @return QDF_STATUS_SUCCESS if successful, + * QDF_STATUS_E_FAILURE otherwise + */ + +QDF_STATUS dph_delete_hash_entry(struct mac_context *mac, tSirMacAddr staAddr, + uint16_t assocId, + struct dph_hash_table *hash_table) +{ + tpDphHashNode ptr, prev; + uint16_t index = hash_function(mac, staAddr, hash_table->size); + + pe_debug("assocId: %d index: %d STA addr: "QDF_MAC_ADDR_FMT, + assocId, index, QDF_MAC_ADDR_REF(staAddr)); + + if (assocId >= hash_table->size) { + pe_err("invalid STA id %d", assocId); + return QDF_STATUS_E_FAILURE; + } + + if (hash_table->pDphNodeArray[assocId].added == 0) { + pe_err("STA %d never added", assocId); + return QDF_STATUS_E_FAILURE; + } + + for (prev = 0, ptr = hash_table->pHashTable[index]; + ptr; prev = ptr, ptr = ptr->next) { + if (dph_compare_mac_addr(staAddr, ptr->staAddr)) + break; + if (prev == ptr) { + pe_err("Infinite Loop"); + return QDF_STATUS_E_FAILURE; + } + } + + if (ptr) { + /* / Delete the entry after invalidating it */ + ptr->valid = 0; + memset(ptr->staAddr, 0, sizeof(ptr->staAddr)); + if (prev == 0) + hash_table->pHashTable[index] = ptr->next; + else + prev->next = ptr->next; + ptr->added = 0; + ptr->is_disassoc_deauth_in_progress = 0; + ptr->sta_deletion_in_progress = false; + ptr->ocv_enabled = 0; + ptr->last_ocv_done_freq = 0; + ptr->next = 0; + } else { + pe_err("Entry not present STA addr: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(staAddr)); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/dph/dph_hash_table.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/dph/dph_hash_table.h new file mode 100644 index 0000000000..7bcc3d35a8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/dph/dph_hash_table.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011-2015, 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file dph_hash_table.h contains the definition of the scheduler class. + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __DPH_HASH_TABLE_H__ +#define __DPH_HASH_TABLE_H__ + +#include "ani_global.h" +/* Compare MAC addresses, return true if same */ +static inline uint8_t dph_compare_mac_addr(uint8_t addr1[], uint8_t addr2[]) +{ + return (addr1[0] == addr2[0]) && + (addr1[1] == addr2[1]) && + (addr1[2] == addr2[2]) && + (addr1[3] == addr2[3]) && + (addr1[4] == addr2[4]) && (addr1[5] == addr2[5]); +} + +/** + * struct dph_hash_table - DPH hash table + * @pHashTable: The actual hash table + * @pDphNodeArray: The state array + * @size: The size of the hash table + */ +struct dph_hash_table { + tpDphHashNode *pHashTable; + tDphHashNode *pDphNodeArray; + uint16_t size; +}; + +tpDphHashNode dph_lookup_hash_entry(struct mac_context *mac, uint8_t staAddr[], + uint16_t *pStaId, + struct dph_hash_table *hash_table); + +#ifdef WLAN_FEATURE_11BE_MLO +tpDphHashNode dph_lookup_hash_entry_by_mld_addr( + struct mac_context *mac, + uint8_t staAddr[], + uint16_t *pStaId, + struct dph_hash_table *hash_table); +#else +static inline +tpDphHashNode dph_lookup_hash_entry_by_mld_addr( + struct mac_context *mac, + uint8_t staAddr[], + uint16_t *pStaId, + struct dph_hash_table *hash_table) +{ + return NULL; +} +#endif + +/* Get a pointer to the hash node */ +tpDphHashNode dph_get_hash_entry(struct mac_context *mac, uint16_t staId, + struct dph_hash_table *hash_table); + +/* Add an entry to the hash table */ +tpDphHashNode dph_add_hash_entry(struct mac_context *mac, + tSirMacAddr staAddr, + uint16_t staId, + struct dph_hash_table *hash_table); + +/* Delete an entry from the hash table */ +QDF_STATUS dph_delete_hash_entry(struct mac_context *mac, + tSirMacAddr staAddr, uint16_t staId, + struct dph_hash_table *hash_table); + +/** + * dph_hash_table_init - Initialize a DPH Hash Table + * @mac: Global MAC Context + * @hash_table: Pointer to the Hash Table to initialize + */ +void dph_hash_table_init(struct mac_context *mac, + struct dph_hash_table *hash_table); + +/* Initialize STA state */ +tpDphHashNode dph_init_sta_state(struct mac_context *mac, + tSirMacAddr staAddr, + uint16_t staId, + struct dph_hash_table *hash_table); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/dot11f.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/dot11f.h new file mode 100644 index 0000000000..fbdfebac1f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/dot11f.h @@ -0,0 +1,13051 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DOT11F_H +#define DOT11F_H +/* + * \file dot11f.h + * + * \brief Structures, function prototypes & definitions + * for working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Fri Nov 10 10:07:33 2023 from the following file(s): + * + * dot11f.frms + * + * PLEASE DON'T EDIT THIS FILE BY HAND! + * + * Instead, please update the input files & re-run + * 'framesc' For more information on 'framesc' & the + * frames language, run 'framesc --help'. + * + */ + +typedef uint32_t tDOT11F_U64[2]; + +#if defined (_MSC_VER) +#pragma warning (disable:4214) /* nonstandard extension used */ +#endif /* Microsoft C/C++ bit field types other than int */ + +#if !defined __must_check +#define __must_check +#endif + +#if !defined unlikely +#define unlikely(x) (x) +#endif + +/* + * Frames Return Codes: + * + * Success is indicated by a return value of zero. Failure is indicated + * by the presence of the high bit. Warnings encountered in the course + * of a successful parse are indicated by various bits in the lower 31 + * being turned on. + * + * For instance, a return value of 0x0000000a would indicate that the + * parse succeeded, but that a mandatory IE wasn't present, and some IE + * was found to be corrupt. + * + * + */ + +#define DOT11F_PARSE_SUCCESS (0x00000000) +#define DOT11F_UNKNOWN_IES (0x00000001) +#define DOT11F_MANDATORY_IE_MISSING (0x00000002) +#define DOT11F_INCOMPLETE_IE (0x00000004) +#define DOT11F_SKIPPED_BAD_IE (0x00000008) +#define DOT11F_LAST_IE_TOO_LONG (0x00000010) +#define DOT11F_DUPLICATE_IE (0x00000020) +#define DOT11F_BAD_FIXED_VALUE (0x00000040) +#define DOT11F_INCOMPLETE_TLV (0x00000080) +#define DOT11F_INVALID_TLV_LENGTH (0x00000100) +#define DOT11F_SKIPPED_BAD_TLV (0x00000200) +#define DOT11F_UNKNOWN_TLVS (0x00000400) +#define DOT11F_LAST_TLV_TOO_LONG (0x00000800) +#define DOT11F_MANDATORY_TLV_MISSING (0x00001000) +#define DOT11F_INTERNAL_ERROR (0x10000001) +#define DOT11F_MISSING_FIXED_FIELD (0x10000002) +#define DOT11F_BAD_INPUT_BUFFER (0x10000003) +#define DOT11F_BAD_OUTPUT_BUFFER (0x10000004) +#define DOT11F_BUFFER_OVERFLOW (0x10000005) +#define DOT11F_FAILED(code) ((code) & 0x10000000) +#define DOT11F_SUCCEEDED(code) ((code) == 0) +#define DOT11F_WARNED(code) (!DOT11F_SUCCEEDED(code) && !DOT11F_FAILED(code)) + +/********************************************************************* + * Fixed Fields * + ********************************************************************/ + +typedef struct sDot11fFfAID { + uint16_t associd; +} tDot11fFfAID; + +#define DOT11F_FF_AID_LEN (2) + +void dot11f_unpack_ff_AID(tpAniSirGlobal, uint8_t *, tDot11fFfAID *); + +void dot11f_pack_ff_aid(tpAniSirGlobal, tDot11fFfAID *, uint8_t *); + +typedef struct sDot11fFfAction { + uint8_t action; +} tDot11fFfAction; + +#define DOT11F_FF_ACTION_LEN (1) + +void dot11f_unpack_ff_action(tpAniSirGlobal, uint8_t *, tDot11fFfAction *); + +void dot11f_pack_ff_action(tpAniSirGlobal, tDot11fFfAction *, uint8_t *); + +typedef struct sDot11fFfAuthAlgo { + uint16_t algo; +} tDot11fFfAuthAlgo; + +#define DOT11F_FF_AUTHALGO_LEN (2) + +void dot11f_unpack_ff_AuthAlgo(tpAniSirGlobal, uint8_t *, + tDot11fFfAuthAlgo *); + +void dot11f_pack_ff_auth_algo(tpAniSirGlobal, tDot11fFfAuthAlgo *, uint8_t *); + +typedef struct sDot11fFfAuthSeqNo { + uint16_t no; +} tDot11fFfAuthSeqNo; + +#define DOT11F_FF_AUTHSEQNO_LEN (2) + +void dot11f_unpack_ff_AuthSeqNo(tpAniSirGlobal, uint8_t *, + tDot11fFfAuthSeqNo *); + +void dot11f_pack_ff_auth_seq_no(tpAniSirGlobal, tDot11fFfAuthSeqNo *, + uint8_t *); + +typedef struct sDot11fFfBeaconInterval { + uint16_t interval; +} tDot11fFfBeaconInterval; + +#define DOT11F_FF_BEACONINTERVAL_LEN (2) + +void dot11f_unpack_ff_BeaconInterval(tpAniSirGlobal, uint8_t *, + tDot11fFfBeaconInterval *); + +void dot11f_pack_ff_beacon_interval(tpAniSirGlobal, tDot11fFfBeaconInterval *, + uint8_t *); + +typedef struct sDot11fFfCapabilities { + uint16_t ess:1; + uint16_t ibss:1; + uint16_t cfPollable:1; + uint16_t cfPollReq:1; + uint16_t privacy:1; + uint16_t shortPreamble:1; + uint16_t criticalUpdateFlag:1; + uint16_t channelAgility:1; + uint16_t spectrumMgt:1; + uint16_t qos:1; + uint16_t shortSlotTime:1; + uint16_t apsd:1; + uint16_t rrm:1; + uint16_t dsssOfdm:1; + uint16_t delayedBA:1; + uint16_t immediateBA:1; +} tDot11fFfCapabilities; + +#define DOT11F_FF_CAPABILITIES_LEN (2) + +void dot11f_unpack_ff_capabilities(tpAniSirGlobal, uint8_t *, + tDot11fFfCapabilities *); + +void dot11f_pack_ff_capabilities(tpAniSirGlobal, tDot11fFfCapabilities *, + uint8_t *); + +#define CAPABILITIES_ESS_OFFSET 0 +#define CAPABILITIES_ESS_WIDTH 1 +#define CAPABILITIES_IBSS_OFFSET 1 +#define CAPABILITIES_IBSS_WIDTH 1 +#define CAPABILITIES_CFPOLLABLE_OFFSET 2 +#define CAPABILITIES_CFPOLLABLE_WIDTH 1 +#define CAPABILITIES_CFPOLLREQ_OFFSET 3 +#define CAPABILITIES_CFPOLLREQ_WIDTH 1 +#define CAPABILITIES_PRIVACY_OFFSET 4 +#define CAPABILITIES_PRIVACY_WIDTH 1 +#define CAPABILITIES_SHORTPREAMBLE_OFFSET 5 +#define CAPABILITIES_SHORTPREAMBLE_WIDTH 1 +#define CAPABILITIES_CRITICALUPDATEFLAG_OFFSET 6 +#define CAPABILITIES_CRITICALUPDATEFLAG_WIDTH 1 +#define CAPABILITIES_CHANNELAGILITY_OFFSET 7 +#define CAPABILITIES_CHANNELAGILITY_WIDTH 1 +#define CAPABILITIES_SPECTRUMMGT_OFFSET 8 +#define CAPABILITIES_SPECTRUMMGT_WIDTH 1 +#define CAPABILITIES_QOS_OFFSET 9 +#define CAPABILITIES_QOS_WIDTH 1 +#define CAPABILITIES_SHORTSLOTTIME_OFFSET 10 +#define CAPABILITIES_SHORTSLOTTIME_WIDTH 1 +#define CAPABILITIES_APSD_OFFSET 11 +#define CAPABILITIES_APSD_WIDTH 1 +#define CAPABILITIES_RRM_OFFSET 12 +#define CAPABILITIES_RRM_WIDTH 1 +#define CAPABILITIES_DSSSOFDM_OFFSET 13 +#define CAPABILITIES_DSSSOFDM_WIDTH 1 +#define CAPABILITIES_DELAYEDBA_OFFSET 14 +#define CAPABILITIES_DELAYEDBA_WIDTH 1 +#define CAPABILITIES_IMMEDIATEBA_OFFSET 15 +#define CAPABILITIES_IMMEDIATEBA_WIDTH 1 + +typedef struct sDot11fFfCategory { + uint8_t category; +} tDot11fFfCategory; + +#define DOT11F_FF_CATEGORY_LEN (1) + +void dot11f_unpack_ff_category(tpAniSirGlobal, uint8_t *, + tDot11fFfCategory *); + +void dot11f_pack_ff_category(tpAniSirGlobal, tDot11fFfCategory *, uint8_t *); + +typedef struct sDot11fFfCurrentAPAddress { + uint8_t mac[6]; +} tDot11fFfCurrentAPAddress; + +#define DOT11F_FF_CURRENTAPADDRESS_LEN (6) + +void dot11f_unpack_ff_current_ap_address(tpAniSirGlobal, uint8_t *, + tDot11fFfCurrentAPAddress *); + +void dot11f_pack_ff_current_ap_address(tpAniSirGlobal, + tDot11fFfCurrentAPAddress *, + uint8_t *); + + +typedef struct sDot11fFfDialogToken { + uint8_t token; +} tDot11fFfDialogToken; + +#define DOT11F_FF_DIALOGTOKEN_LEN (1) + +void dot11f_unpack_ff_dialog_token(tpAniSirGlobal, uint8_t *, + tDot11fFfDialogToken *); + +void dot11f_pack_ff_dialog_token(tpAniSirGlobal, tDot11fFfDialogToken *, + uint8_t *); + +typedef struct sDot11fFfLinkMargin { + uint8_t linkMargin; +} tDot11fFfLinkMargin; + +#define DOT11F_FF_LINKMARGIN_LEN (1) + +void dot11f_unpack_ff_link_margin(tpAniSirGlobal, uint8_t *, + tDot11fFfLinkMargin *); + +void dot11f_pack_ff_link_margin(tpAniSirGlobal, tDot11fFfLinkMargin *, + uint8_t *); + +typedef struct sDot11fFfListenInterval { + uint16_t interval; +} tDot11fFfListenInterval; + +#define DOT11F_FF_LISTENINTERVAL_LEN (2) + +void dot11f_unpack_ff_ListenInterval(tpAniSirGlobal, uint8_t *, + tDot11fFfListenInterval *); + +void dot11f_pack_ff_listen_interval(tpAniSirGlobal, tDot11fFfListenInterval *, + uint8_t *); + +typedef struct sDot11fFfMaxTxPower { + uint8_t maxTxPower; +} tDot11fFfMaxTxPower; + +#define DOT11F_FF_MAXTXPOWER_LEN (1) + +void dot11f_unpack_ff_max_tx_power(tpAniSirGlobal, uint8_t *, + tDot11fFfMaxTxPower *); + +void dot11f_pack_ff_max_tx_power(tpAniSirGlobal, tDot11fFfMaxTxPower *, + uint8_t *); + +typedef struct sDot11fFfNumOfRepetitions { + uint16_t repetitions; +} tDot11fFfNumOfRepetitions; + +#define DOT11F_FF_NUMOFREPETITIONS_LEN (2) + +void dot11f_unpack_ff_num_of_repetitions(tpAniSirGlobal, uint8_t *, + tDot11fFfNumOfRepetitions *); + +void dot11f_pack_ff_num_of_repetitions(tpAniSirGlobal, + tDot11fFfNumOfRepetitions *, + uint8_t *); + + +typedef struct sDot11fFfOperatingMode { + uint8_t chanWidth:2; + uint8_t reserved:2; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tDot11fFfOperatingMode; + +#define DOT11F_FF_OPERATINGMODE_LEN (1) + +void dot11f_unpack_ff_operating_mode(tpAniSirGlobal, uint8_t *, + tDot11fFfOperatingMode *); + +void dot11f_pack_ff_operating_mode(tpAniSirGlobal, tDot11fFfOperatingMode *, + uint8_t *); + +#define OPERATINGMODE_CHANWIDTH_OFFSET 0 +#define OPERATINGMODE_CHANWIDTH_WIDTH 2 +#define OPERATINGMODE_RESERVED_OFFSET 2 +#define OPERATINGMODE_RESERVED_WIDTH 2 +#define OPERATINGMODE_RXNSS_OFFSET 4 +#define OPERATINGMODE_RXNSS_WIDTH 3 +#define OPERATINGMODE_RXNSSTYPE_OFFSET 7 +#define OPERATINGMODE_RXNSSTYPE_WIDTH 1 + +typedef struct sDot11fFfRCPI { + uint8_t rcpi; +} tDot11fFfRCPI; + +#define DOT11F_FF_RCPI_LEN (1) + +void dot11f_unpack_ff_rcpi(tpAniSirGlobal, uint8_t *, tDot11fFfRCPI *); + +void dot11f_pack_ff_rcpi(tpAniSirGlobal, tDot11fFfRCPI *, uint8_t *); + +typedef struct sDot11fFfRSNI { + uint8_t rsni; +} tDot11fFfRSNI; + +#define DOT11F_FF_RSNI_LEN (1) + +void dot11f_unpack_ff_rsni(tpAniSirGlobal, uint8_t *, tDot11fFfRSNI *); + +void dot11f_pack_ff_rsni(tpAniSirGlobal, tDot11fFfRSNI *, uint8_t *); + +typedef struct sDot11fFfReason { + uint16_t code; +} tDot11fFfReason; + +#define DOT11F_FF_REASON_LEN (2) + +void dot11f_unpack_ff_Reason(tpAniSirGlobal, uint8_t *, tDot11fFfReason *); + +void dot11f_pack_ff_reason(tpAniSirGlobal, tDot11fFfReason *, uint8_t *); + +typedef struct sDot11fFfRxAntennaId { + uint8_t antennaId; +} tDot11fFfRxAntennaId; + +#define DOT11F_FF_RXANTENNAID_LEN (1) + +void dot11f_unpack_ff_rx_antenna_id(tpAniSirGlobal, uint8_t *, + tDot11fFfRxAntennaId *); + +void dot11f_pack_ff_rx_antenna_id(tpAniSirGlobal, tDot11fFfRxAntennaId *, + uint8_t *); + +typedef struct sDot11fFfSMPowerModeSet { + uint8_t PowerSave_En:1; + uint8_t Mode:1; + uint8_t reserved:6; +} tDot11fFfSMPowerModeSet; + +#define DOT11F_FF_SMPOWERMODESET_LEN (1) + +void dot11f_unpack_ff_sm_power_mode_set(tpAniSirGlobal, uint8_t *, + tDot11fFfSMPowerModeSet *); + +void dot11f_pack_ff_sm_power_mode_set(tpAniSirGlobal, tDot11fFfSMPowerModeSet *, + uint8_t *); + +#define SMPOWERMODESET_POWERSAVE_EN_OFFSET 0 +#define SMPOWERMODESET_POWERSAVE_EN_WIDTH 1 +#define SMPOWERMODESET_MODE_OFFSET 1 +#define SMPOWERMODESET_MODE_WIDTH 1 +#define SMPOWERMODESET_RESERVED_OFFSET 2 +#define SMPOWERMODESET_RESERVED_WIDTH 6 + +typedef struct sDot11fFfStatus { + uint16_t status; +} tDot11fFfStatus; + +#define DOT11F_FF_STATUS_LEN (2) + +void dot11f_unpack_ff_Status(tpAniSirGlobal, uint8_t *, tDot11fFfStatus *); + +void dot11f_pack_ff_status(tpAniSirGlobal, tDot11fFfStatus *, uint8_t *); + +typedef struct sDot11fFfStatusCode { + uint8_t statusCode; +} tDot11fFfStatusCode; + +#define DOT11F_FF_STATUSCODE_LEN (1) + +void dot11f_unpack_ff_status_code(tpAniSirGlobal, uint8_t *, + tDot11fFfStatusCode *); + +void dot11f_pack_ff_status_code(tpAniSirGlobal, tDot11fFfStatusCode *, + uint8_t *); + +typedef struct sDot11fFfTPCEleID { + uint8_t TPCId; +} tDot11fFfTPCEleID; + +#define DOT11F_FF_TPCELEID_LEN (1) + +void dot11f_unpack_ff_tpc_ele_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTPCEleID *); + +void dot11f_pack_ff_tpc_ele_id(tpAniSirGlobal, tDot11fFfTPCEleID *, uint8_t *); + +typedef struct sDot11fFfTPCEleLen { + uint8_t TPCLen; +} tDot11fFfTPCEleLen; + +#define DOT11F_FF_TPCELELEN_LEN (1) + +void dot11f_unpack_ff_tpc_ele_len(tpAniSirGlobal, uint8_t *, + tDot11fFfTPCEleLen *); + +void dot11f_pack_ff_tpc_ele_len(tpAniSirGlobal, tDot11fFfTPCEleLen *, + uint8_t *); + +typedef struct sDot11fFfTSInfo { + uint32_t traffic_type:1; + uint32_t tsid:4; + uint32_t direction:2; + uint32_t access_policy:2; + uint32_t aggregation:1; + uint32_t psb:1; + uint32_t user_priority:3; + uint32_t tsinfo_ack_pol:2; + uint32_t schedule:1; + uint32_t unused:15; +} tDot11fFfTSInfo; + +#define DOT11F_FF_TSINFO_LEN (3) + +void dot11f_unpack_ff_ts_info(tpAniSirGlobal, uint8_t *, tDot11fFfTSInfo *); + +void dot11f_pack_ff_ts_info(tpAniSirGlobal, tDot11fFfTSInfo *, uint8_t *); + +#define TSINFO_TRAFFIC_TYPE_OFFSET 0 +#define TSINFO_TRAFFIC_TYPE_WIDTH 1 +#define TSINFO_TSID_OFFSET 1 +#define TSINFO_TSID_WIDTH 4 +#define TSINFO_DIRECTION_OFFSET 5 +#define TSINFO_DIRECTION_WIDTH 2 +#define TSINFO_ACCESS_POLICY_OFFSET 7 +#define TSINFO_ACCESS_POLICY_WIDTH 2 +#define TSINFO_AGGREGATION_OFFSET 9 +#define TSINFO_AGGREGATION_WIDTH 1 +#define TSINFO_PSB_OFFSET 10 +#define TSINFO_PSB_WIDTH 1 +#define TSINFO_USER_PRIORITY_OFFSET 11 +#define TSINFO_USER_PRIORITY_WIDTH 3 +#define TSINFO_TSINFO_ACK_POL_OFFSET 14 +#define TSINFO_TSINFO_ACK_POL_WIDTH 2 +#define TSINFO_SCHEDULE_OFFSET 16 +#define TSINFO_SCHEDULE_WIDTH 1 +#define TSINFO_UNUSED_OFFSET 17 +#define TSINFO_UNUSED_WIDTH 15 + +typedef struct sDot11fFfTimeStamp { + tDOT11F_U64 timestamp; +} tDot11fFfTimeStamp; + +#define DOT11F_FF_TIMESTAMP_LEN (8) + +void dot11f_unpack_ff_time_stamp(tpAniSirGlobal, uint8_t *, + tDot11fFfTimeStamp *); + +void dot11f_pack_ff_time_stamp(tpAniSirGlobal, tDot11fFfTimeStamp *, + uint8_t *); + +typedef struct sDot11fFfTransactionId { + uint8_t transId[2]; +} tDot11fFfTransactionId; + +#define DOT11F_FF_TRANSACTIONID_LEN (2) + +void dot11f_unpack_ff_transaction_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTransactionId *); + +void dot11f_pack_ff_transaction_id(tpAniSirGlobal, tDot11fFfTransactionId *, + uint8_t *); + +typedef struct sDot11fFfTxAntennaId { + uint8_t antennaId; +} tDot11fFfTxAntennaId; + +#define DOT11F_FF_TXANTENNAID_LEN (1) + +void dot11f_unpack_ff_tx_antenna_id(tpAniSirGlobal, uint8_t *, + tDot11fFfTxAntennaId *); + +void dot11f_pack_ff_tx_antenna_id(tpAniSirGlobal, tDot11fFfTxAntennaId *, + uint8_t *); + +typedef struct sDot11fFfTxPower { + uint8_t txPower; +} tDot11fFfTxPower; + +#define DOT11F_FF_TXPOWER_LEN (1) + +void dot11f_unpack_ff_tx_power(tpAniSirGlobal, uint8_t *, + tDot11fFfTxPower *); + +void dot11f_pack_ff_tx_power(tpAniSirGlobal, tDot11fFfTxPower *, uint8_t *); + +typedef struct sDot11fFfVhtMembershipStatusArray { + uint8_t membershipStatusArray[8]; +} tDot11fFfVhtMembershipStatusArray; + +#define DOT11F_FF_VHTMEMBERSHIPSTATUSARRAY_LEN (8) + +void dot11f_unpack_ff_vht_membership_status_array(tpAniSirGlobal, uint8_t *, + tDot11fFfVhtMembershipStatusArray *); + +void dot11f_pack_ff_vht_membership_status_array(tpAniSirGlobal, + tDot11fFfVhtMembershipStatusArray *, + uint8_t *); + + +typedef struct sDot11fFfVhtUserPositionArray { + uint8_t userPositionArray[16]; +} tDot11fFfVhtUserPositionArray; + +#define DOT11F_FF_VHTUSERPOSITIONARRAY_LEN (16) + +void dot11f_unpack_ff_vht_user_position_array(tpAniSirGlobal, uint8_t *, + tDot11fFfVhtUserPositionArray *); + +void dot11f_pack_ff_vht_user_position_array(tpAniSirGlobal, + tDot11fFfVhtUserPositionArray *, + uint8_t *); + + +typedef struct sDot11fFfaddba_param_set { + uint16_t amsdu_supp:1; + uint16_t policy:1; + uint16_t tid:4; + uint16_t buff_size:10; +} tDot11fFfaddba_param_set; + +#define DOT11F_FF_ADDBA_PARAM_SET_LEN (2) + +void dot11f_unpack_ff_addba_param_set(tpAniSirGlobal, uint8_t *, + tDot11fFfaddba_param_set *); + +void dot11f_pack_ff_addba_param_set(tpAniSirGlobal, tDot11fFfaddba_param_set *, + uint8_t *); + +#define ADDBA_PARAM_SET_AMSDU_SUPP_OFFSET 0 +#define ADDBA_PARAM_SET_AMSDU_SUPP_WIDTH 1 +#define ADDBA_PARAM_SET_POLICY_OFFSET 1 +#define ADDBA_PARAM_SET_POLICY_WIDTH 1 +#define ADDBA_PARAM_SET_TID_OFFSET 2 +#define ADDBA_PARAM_SET_TID_WIDTH 4 +#define ADDBA_PARAM_SET_BUFF_SIZE_OFFSET 6 +#define ADDBA_PARAM_SET_BUFF_SIZE_WIDTH 10 + +typedef struct sDot11fFfba_start_seq_ctrl { + uint16_t frag_number:4; + uint16_t ssn:12; +} tDot11fFfba_start_seq_ctrl; + +#define DOT11F_FF_BA_START_SEQ_CTRL_LEN (2) + +void dot11f_unpack_ff_ba_start_seq_ctrl(tpAniSirGlobal, uint8_t *, + tDot11fFfba_start_seq_ctrl *); + +void dot11f_pack_ff_ba_start_seq_ctrl(tpAniSirGlobal, + tDot11fFfba_start_seq_ctrl *, + uint8_t *); + + +#define BA_START_SEQ_CTRL_FRAG_NUMBER_OFFSET 0 +#define BA_START_SEQ_CTRL_FRAG_NUMBER_WIDTH 4 +#define BA_START_SEQ_CTRL_SSN_OFFSET 4 +#define BA_START_SEQ_CTRL_SSN_WIDTH 12 + +typedef struct sDot11fFfba_timeout { + uint16_t timeout; +} tDot11fFfba_timeout; + +#define DOT11F_FF_BA_TIMEOUT_LEN (2) + +void dot11f_unpack_ff_ba_timeout(tpAniSirGlobal, uint8_t *, + tDot11fFfba_timeout *); + +void dot11f_pack_ff_ba_timeout(tpAniSirGlobal, tDot11fFfba_timeout *, + uint8_t *); + +typedef struct sDot11fFfdelba_param_set { + uint16_t reserved:11; + uint16_t initiator:1; + uint16_t tid:4; +} tDot11fFfdelba_param_set; + +#define DOT11F_FF_DELBA_PARAM_SET_LEN (2) + +void dot11f_unpack_ff_delba_param_set(tpAniSirGlobal, uint8_t *, + tDot11fFfdelba_param_set *); + +void dot11f_pack_ff_delba_param_set(tpAniSirGlobal, tDot11fFfdelba_param_set *, + uint8_t *); + +#define DELBA_PARAM_SET_RESERVED_OFFSET 0 +#define DELBA_PARAM_SET_RESERVED_WIDTH 11 +#define DELBA_PARAM_SET_INITIATOR_OFFSET 11 +#define DELBA_PARAM_SET_INITIATOR_WIDTH 1 +#define DELBA_PARAM_SET_TID_OFFSET 12 +#define DELBA_PARAM_SET_TID_WIDTH 4 + +typedef struct sDot11fFfext_chan_switch_ann_action { + uint32_t switch_mode:8; + uint32_t op_class:8; + uint32_t new_channel:8; + uint32_t switch_count:8; +} tDot11fFfext_chan_switch_ann_action; + +#define DOT11F_FF_EXT_CHAN_SWITCH_ANN_ACTION_LEN (4) + +void dot11f_unpack_ff_ext_chan_switch_ann_action(tpAniSirGlobal, uint8_t *, + tDot11fFfext_chan_switch_ann_action *); + +void dot11f_pack_ff_ext_chan_switch_ann_action(tpAniSirGlobal, + tDot11fFfext_chan_switch_ann_action *, + uint8_t *); + + +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_MODE_OFFSET 0 +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_MODE_WIDTH 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_OP_CLASS_OFFSET 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_OP_CLASS_WIDTH 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_NEW_CHANNEL_OFFSET 16 +#define EXT_CHAN_SWITCH_ANN_ACTION_NEW_CHANNEL_WIDTH 8 +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_COUNT_OFFSET 24 +#define EXT_CHAN_SWITCH_ANN_ACTION_SWITCH_COUNT_WIDTH 8 + +typedef struct sDot11fFfp2p_action_oui { + uint8_t oui_data[4]; +} tDot11fFfp2p_action_oui; + +#define DOT11F_FF_P2P_ACTION_OUI_LEN (4) + +void dot11f_unpack_ff_p2p_action_oui(tpAniSirGlobal, uint8_t *, + tDot11fFfp2p_action_oui *); + +void dot11f_pack_ff_p2p_action_oui(tpAniSirGlobal, tDot11fFfp2p_action_oui *, + uint8_t *); + +typedef struct sDot11fFfp2p_action_subtype { + uint8_t subtype; +} tDot11fFfp2p_action_subtype; + +#define DOT11F_FF_P2P_ACTION_SUBTYPE_LEN (1) + +void dot11f_unpack_ff_p2p_action_subtype(tpAniSirGlobal, uint8_t *, + tDot11fFfp2p_action_subtype *); + +void dot11f_pack_ff_p2p_action_subtype(tpAniSirGlobal, + tDot11fFfp2p_action_subtype *, + uint8_t *); + + +typedef struct sDot11fFfvendor_action_subtype { + uint8_t subtype; +} tDot11fFfvendor_action_subtype; + +#define DOT11F_FF_VENDOR_ACTION_SUBTYPE_LEN (1) + +void dot11f_unpack_ff_vendor_action_subtype(tpAniSirGlobal, uint8_t *, + tDot11fFfvendor_action_subtype *); + +void dot11f_pack_ff_vendor_action_subtype(tpAniSirGlobal, + tDot11fFfvendor_action_subtype *, + uint8_t *); + + +typedef struct sDot11fFfvendor_oui { + uint8_t oui_data[3]; +} tDot11fFfvendor_oui; + +#define DOT11F_FF_VENDOR_OUI_LEN (3) + +void dot11f_unpack_ff_vendor_oui(tpAniSirGlobal, uint8_t *, + tDot11fFfvendor_oui *); + +void dot11f_pack_ff_vendor_oui(tpAniSirGlobal, tDot11fFfvendor_oui *, + uint8_t *); + +/********************************************************************* + * TLVs * + ********************************************************************/ + + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVAuthorizedMACs { + uint8_t present; + uint8_t mac[6]; +} tDot11fTLVAuthorizedMACs; + +#define DOT11F_TLV_AUTHORIZEDMACS (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_AUTHORIZEDMACS_MIN_LEN (6) + +#define DOT11F_TLV_AUTHORIZEDMACS_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_authorized_ma_cs( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAuthorizedMACs*); + +uint32_t dot11f_pack_tlv_authorized_ma_cs( + tpAniSirGlobal, + tDot11fTLVAuthorizedMACs *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_AuthorizedMACs( + tpAniSirGlobal, + tDot11fTLVAuthorizedMACs *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVRequestToEnroll { + uint8_t present; + uint8_t req; +} tDot11fTLVRequestToEnroll; + +#define DOT11F_TLV_REQUESTTOENROLL (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTTOENROLL_MIN_LEN (1) + +#define DOT11F_TLV_REQUESTTOENROLL_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RequestToEnroll( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestToEnroll*); + +uint32_t dot11f_pack_tlv_request_to_enroll( + tpAniSirGlobal, + tDot11fTLVRequestToEnroll *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestToEnroll( + tpAniSirGlobal, + tDot11fTLVRequestToEnroll *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 0 (0x0000) */ +typedef struct sDot11fTLVVersion2 { + uint8_t present; + uint8_t minor:4; + uint8_t major:4; +} tDot11fTLVVersion2; + +#define DOT11F_TLV_VERSION2 (0) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VERSION2_MIN_LEN (1) + +#define DOT11F_TLV_VERSION2_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_version2( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVersion2*); + +uint32_t dot11f_pack_tlv_version2( + tpAniSirGlobal, + tDot11fTLVVersion2 *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Version2( + tpAniSirGlobal, + tDot11fTLVVersion2 *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4183 (0x1057) */ +typedef struct sDot11fTLVAPSetupLocked { + uint8_t present; + uint8_t fLocked; +} tDot11fTLVAPSetupLocked; + +#define DOT11F_TLV_APSETUPLOCKED (4183) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_APSETUPLOCKED_MIN_LEN (3) + +#define DOT11F_TLV_APSETUPLOCKED_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_APSetupLocked( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAPSetupLocked*); + +uint32_t dot11f_pack_tlv_ap_setup_locked( + tpAniSirGlobal, + tDot11fTLVAPSetupLocked *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_APSetupLocked( + tpAniSirGlobal, + tDot11fTLVAPSetupLocked *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4098 (0x1002) */ +typedef struct sDot11fTLVAssociationState { + uint8_t present; + uint16_t state; +} tDot11fTLVAssociationState; + +#define DOT11F_TLV_ASSOCIATIONSTATE (4098) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_ASSOCIATIONSTATE_MIN_LEN (4) + +#define DOT11F_TLV_ASSOCIATIONSTATE_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_AssociationState( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVAssociationState*); + +uint32_t dot11f_pack_tlv_association_state( + tpAniSirGlobal, + tDot11fTLVAssociationState *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_AssociationState( + tpAniSirGlobal, + tDot11fTLVAssociationState *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4104 (0x1008) */ +typedef struct sDot11fTLVConfigMethods { + uint8_t present; + uint16_t methods; +} tDot11fTLVConfigMethods; + +#define DOT11F_TLV_CONFIGMETHODS (4104) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CONFIGMETHODS_MIN_LEN (4) + +#define DOT11F_TLV_CONFIGMETHODS_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ConfigMethods( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVConfigMethods*); + +uint32_t dot11f_pack_tlv_config_methods( + tpAniSirGlobal, + tDot11fTLVConfigMethods *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ConfigMethods( + tpAniSirGlobal, + tDot11fTLVConfigMethods *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4105 (0x1009) */ +typedef struct sDot11fTLVConfigurationError { + uint8_t present; + uint16_t error; +} tDot11fTLVConfigurationError; + +#define DOT11F_TLV_CONFIGURATIONERROR (4105) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CONFIGURATIONERROR_MIN_LEN (4) + +#define DOT11F_TLV_CONFIGURATIONERROR_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ConfigurationError( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVConfigurationError*); + +uint32_t dot11f_pack_tlv_configuration_error( + tpAniSirGlobal, + tDot11fTLVConfigurationError *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ConfigurationError( + tpAniSirGlobal, + tDot11fTLVConfigurationError *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4113 (0x1011) */ +typedef struct sDot11fTLVDeviceName { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVDeviceName; + +#define DOT11F_TLV_DEVICENAME (4113) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_DEVICENAME_MIN_LEN (2) + +#define DOT11F_TLV_DEVICENAME_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_device_name( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVDeviceName*); + +uint32_t dot11f_pack_tlv_device_name( + tpAniSirGlobal, + tDot11fTLVDeviceName *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_DeviceName( + tpAniSirGlobal, + tDot11fTLVDeviceName *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4114 (0x1012) */ +typedef struct sDot11fTLVDevicePasswordID { + uint8_t present; + uint16_t id; +} tDot11fTLVDevicePasswordID; + +#define DOT11F_TLV_DEVICEPASSWORDID (4114) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_DEVICEPASSWORDID_MIN_LEN (4) + +#define DOT11F_TLV_DEVICEPASSWORDID_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_DevicePasswordID( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVDevicePasswordID*); + +uint32_t dot11f_pack_tlv_device_password_id( + tpAniSirGlobal, + tDot11fTLVDevicePasswordID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_DevicePasswordID( + tpAniSirGlobal, + tDot11fTLVDevicePasswordID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 8 (0x0008) */ +typedef struct sDot11fTLVExtendedListenTiming { + uint8_t present; + uint16_t availibilityPeriod; + uint16_t availibilityInterval; +} tDot11fTLVExtendedListenTiming; + +#define DOT11F_TLV_EXTENDEDLISTENTIMING (8) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_EXTENDEDLISTENTIMING_MIN_LEN (5) + +#define DOT11F_TLV_EXTENDEDLISTENTIMING_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_extended_listen_timing( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVExtendedListenTiming*); + +uint32_t dot11f_pack_tlv_extended_listen_timing( + tpAniSirGlobal, + tDot11fTLVExtendedListenTiming *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ExtendedListenTiming( + tpAniSirGlobal, + tDot11fTLVExtendedListenTiming *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 6 (0x0006) */ +typedef struct sDot11fTLVListenChannel { + uint8_t present; + uint8_t countryString[3]; + uint8_t regulatoryClass; + uint8_t channel; +} tDot11fTLVListenChannel; + +#define DOT11F_TLV_LISTENCHANNEL (6) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_LISTENCHANNEL_MIN_LEN (6) + +#define DOT11F_TLV_LISTENCHANNEL_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_listen_channel( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVListenChannel*); + +uint32_t dot11f_pack_tlv_listen_channel( + tpAniSirGlobal, + tDot11fTLVListenChannel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ListenChannel( + tpAniSirGlobal, + tDot11fTLVListenChannel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4129 (0x1021) */ +typedef struct sDot11fTLVManufacturer { + uint8_t present; + uint8_t num_name; + uint8_t name[64]; +} tDot11fTLVManufacturer; + +#define DOT11F_TLV_MANUFACTURER (4129) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MANUFACTURER_MIN_LEN (2) + +#define DOT11F_TLV_MANUFACTURER_MAX_LEN (66) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_manufacturer( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVManufacturer*); + +uint32_t dot11f_pack_tlv_manufacturer( + tpAniSirGlobal, + tDot11fTLVManufacturer *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Manufacturer( + tpAniSirGlobal, + tDot11fTLVManufacturer *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVMinorReasonCode { + uint8_t present; + uint8_t minorReasonCode; +} tDot11fTLVMinorReasonCode; + +#define DOT11F_TLV_MINORREASONCODE (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MINORREASONCODE_MIN_LEN (2) + +#define DOT11F_TLV_MINORREASONCODE_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_MinorReasonCode( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVMinorReasonCode*); + +uint32_t dot11f_pack_tlv_minor_reason_code( + tpAniSirGlobal, + tDot11fTLVMinorReasonCode *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_MinorReasonCode( + tpAniSirGlobal, + tDot11fTLVMinorReasonCode *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4131 (0x1023) */ +typedef struct sDot11fTLVModelName { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVModelName; + +#define DOT11F_TLV_MODELNAME (4131) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MODELNAME_MIN_LEN (2) + +#define DOT11F_TLV_MODELNAME_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_model_name( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVModelName*); + +uint32_t dot11f_pack_tlv_model_name( + tpAniSirGlobal, + tDot11fTLVModelName *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ModelName( + tpAniSirGlobal, + tDot11fTLVModelName *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4132 (0x1024) */ +typedef struct sDot11fTLVModelNumber { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVModelNumber; + +#define DOT11F_TLV_MODELNUMBER (4132) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MODELNUMBER_MIN_LEN (2) + +#define DOT11F_TLV_MODELNUMBER_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_model_number( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVModelNumber*); + +uint32_t dot11f_pack_tlv_model_number( + tpAniSirGlobal, + tDot11fTLVModelNumber *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ModelNumber( + tpAniSirGlobal, + tDot11fTLVModelNumber *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 12 (0x000c) */ +typedef struct sDot11fTLVNoticeOfAbsence { + uint8_t present; + uint8_t index; + uint8_t CTSWindowOppPS; + uint8_t num_NoADesc; + uint8_t NoADesc[36]; +} tDot11fTLVNoticeOfAbsence; + +#define DOT11F_TLV_NOTICEOFABSENCE (12) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_NOTICEOFABSENCE_MIN_LEN (3) + +#define DOT11F_TLV_NOTICEOFABSENCE_MAX_LEN (39) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_notice_of_absence( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVNoticeOfAbsence*); + +uint32_t dot11f_pack_tlv_notice_of_absence( + tpAniSirGlobal, + tDot11fTLVNoticeOfAbsence *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_NoticeOfAbsence( + tpAniSirGlobal, + tDot11fTLVNoticeOfAbsence *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 17 (0x0011) */ +typedef struct sDot11fTLVOperatingChannel { + uint8_t present; + uint8_t countryString[3]; + uint8_t regulatoryClass; + uint8_t channel; +} tDot11fTLVOperatingChannel; + +#define DOT11F_TLV_OPERATINGCHANNEL (17) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_OPERATINGCHANNEL_MIN_LEN (6) + +#define DOT11F_TLV_OPERATINGCHANNEL_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_operating_channel( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVOperatingChannel*); + +uint32_t dot11f_pack_tlv_operating_channel( + tpAniSirGlobal, + tDot11fTLVOperatingChannel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_OperatingChannel( + tpAniSirGlobal, + tDot11fTLVOperatingChannel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 2 (0x0002) */ +typedef struct sDot11fTLVP2PCapability { + uint8_t present; + uint8_t deviceCapability; + uint8_t groupCapability; +} tDot11fTLVP2PCapability; + +#define DOT11F_TLV_P2PCAPABILITY (2) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PCAPABILITY_MIN_LEN (3) + +#define DOT11F_TLV_P2PCAPABILITY_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_capability( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PCapability*); + +uint32_t dot11f_pack_tlv_p2_p_capability( + tpAniSirGlobal, + tDot11fTLVP2PCapability *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PCapability( + tpAniSirGlobal, + tDot11fTLVP2PCapability *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVP2PDeviceId { + uint8_t present; + uint8_t P2PDeviceAddress[6]; +} tDot11fTLVP2PDeviceId; + +#define DOT11F_TLV_P2PDEVICEID (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PDEVICEID_MIN_LEN (7) + +#define DOT11F_TLV_P2PDEVICEID_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_device_id( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PDeviceId*); + +uint32_t dot11f_pack_tlv_p2_p_device_id( + tpAniSirGlobal, + tDot11fTLVP2PDeviceId *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PDeviceId( + tpAniSirGlobal, + tDot11fTLVP2PDeviceId *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 13 (0x000d) */ +typedef struct sDot11fTLVP2PDeviceInfo { + uint8_t present; + uint8_t P2PDeviceAddress[6]; + uint16_t configMethod; + uint8_t primaryDeviceType[8]; + tDot11fTLVDeviceName DeviceName; +} tDot11fTLVP2PDeviceInfo; + +#define DOT11F_TLV_P2PDEVICEINFO (13) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PDEVICEINFO_MIN_LEN (17) + +#define DOT11F_TLV_P2PDEVICEINFO_MAX_LEN (53) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_device_info( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PDeviceInfo*); + +uint32_t dot11f_pack_tlv_p2_p_device_info( + tpAniSirGlobal, + tDot11fTLVP2PDeviceInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PDeviceInfo( + tpAniSirGlobal, + tDot11fTLVP2PDeviceInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 14 (0x000e) */ +typedef struct sDot11fTLVP2PGroupInfo { + uint8_t present; + uint8_t num_P2PClientInfoDesc; + uint8_t P2PClientInfoDesc[1024]; +} tDot11fTLVP2PGroupInfo; + +#define DOT11F_TLV_P2PGROUPINFO (14) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PGROUPINFO_MIN_LEN (1) + +#define DOT11F_TLV_P2PGROUPINFO_MAX_LEN (1025) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_group_info( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PGroupInfo*); + +uint32_t dot11f_pack_tlv_p2_p_group_info( + tpAniSirGlobal, + tDot11fTLVP2PGroupInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PGroupInfo( + tpAniSirGlobal, + tDot11fTLVP2PGroupInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 0 (0x0000) */ +typedef struct sDot11fTLVP2PStatus { + uint8_t present; + uint8_t status; +} tDot11fTLVP2PStatus; + +#define DOT11F_TLV_P2PSTATUS (0) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PSTATUS_MIN_LEN (2) + +#define DOT11F_TLV_P2PSTATUS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_P2PStatus( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PStatus*); + +uint32_t dot11f_pack_tlv_p2_p_status( + tpAniSirGlobal, + tDot11fTLVP2PStatus *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PStatus( + tpAniSirGlobal, + tDot11fTLVP2PStatus *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4180 (0x1054) */ +typedef struct sDot11fTLVPrimaryDeviceType { + uint8_t present; + uint16_t primary_category; + uint8_t oui[4]; + uint16_t sub_category; +} tDot11fTLVPrimaryDeviceType; + +#define DOT11F_TLV_PRIMARYDEVICETYPE (4180) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_PRIMARYDEVICETYPE_MIN_LEN (10) + +#define DOT11F_TLV_PRIMARYDEVICETYPE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_primary_device_type( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVPrimaryDeviceType*); + +uint32_t dot11f_pack_tlv_primary_device_type( + tpAniSirGlobal, + tDot11fTLVPrimaryDeviceType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_PrimaryDeviceType( + tpAniSirGlobal, + tDot11fTLVPrimaryDeviceType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4156 (0x103c) */ +typedef struct sDot11fTLVRFBands { + uint8_t present; + uint8_t bands; +} tDot11fTLVRFBands; + +#define DOT11F_TLV_RFBANDS (4156) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RFBANDS_MIN_LEN (3) + +#define DOT11F_TLV_RFBANDS_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RFBands( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRFBands*); + +uint32_t dot11f_pack_tlv_rf_bands( + tpAniSirGlobal, + tDot11fTLVRFBands *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RFBands( + tpAniSirGlobal, + tDot11fTLVRFBands *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4202 (0x106a) */ +typedef struct sDot11fTLVRequestDeviceType { + uint8_t present; + uint16_t primary_category; + uint8_t oui[4]; + uint16_t sub_category; +} tDot11fTLVRequestDeviceType; + +#define DOT11F_TLV_REQUESTDEVICETYPE (4202) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTDEVICETYPE_MIN_LEN (10) + +#define DOT11F_TLV_REQUESTDEVICETYPE_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_request_device_type( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestDeviceType*); + +uint32_t dot11f_pack_tlv_request_device_type( + tpAniSirGlobal, + tDot11fTLVRequestDeviceType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestDeviceType( + tpAniSirGlobal, + tDot11fTLVRequestDeviceType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4154 (0x103a) */ +typedef struct sDot11fTLVRequestType { + uint8_t present; + uint8_t reqType; +} tDot11fTLVRequestType; + +#define DOT11F_TLV_REQUESTTYPE (4154) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REQUESTTYPE_MIN_LEN (3) + +#define DOT11F_TLV_REQUESTTYPE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_RequestType( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVRequestType*); + +uint32_t dot11f_pack_tlv_request_type( + tpAniSirGlobal, + tDot11fTLVRequestType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_RequestType( + tpAniSirGlobal, + tDot11fTLVRequestType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4155 (0x103b) */ +typedef struct sDot11fTLVResponseType { + uint8_t present; + uint8_t resType; +} tDot11fTLVResponseType; + +#define DOT11F_TLV_RESPONSETYPE (4155) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RESPONSETYPE_MIN_LEN (3) + +#define DOT11F_TLV_RESPONSETYPE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ResponseType( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVResponseType*); + +uint32_t dot11f_pack_tlv_response_type( + tpAniSirGlobal, + tDot11fTLVResponseType *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ResponseType( + tpAniSirGlobal, + tDot11fTLVResponseType *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4161 (0x1041) */ +typedef struct sDot11fTLVSelectedRegistrar { + uint8_t present; + uint8_t selected; +} tDot11fTLVSelectedRegistrar; + +#define DOT11F_TLV_SELECTEDREGISTRAR (4161) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SELECTEDREGISTRAR_MIN_LEN (3) + +#define DOT11F_TLV_SELECTEDREGISTRAR_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_SelectedRegistrar( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSelectedRegistrar*); + +uint32_t dot11f_pack_tlv_selected_registrar( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrar *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SelectedRegistrar( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrar *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4179 (0x1053) */ +typedef struct sDot11fTLVSelectedRegistrarConfigMethods { + uint8_t present; + uint16_t methods; +} tDot11fTLVSelectedRegistrarConfigMethods; + +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS (4179) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS_MIN_LEN (4) + +#define DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_SelectedRegistrarConfigMethods( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSelectedRegistrarConfigMethods*); + +uint32_t dot11f_pack_tlv_selected_registrar_config_methods( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrarConfigMethods *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SelectedRegistrarConfigMethods( + tpAniSirGlobal, + tDot11fTLVSelectedRegistrarConfigMethods *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4162 (0x1042) */ +typedef struct sDot11fTLVSerialNumber { + uint8_t present; + uint8_t num_text; + uint8_t text[32]; +} tDot11fTLVSerialNumber; + +#define DOT11F_TLV_SERIALNUMBER (4162) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_SERIALNUMBER_MIN_LEN (2) + +#define DOT11F_TLV_SERIALNUMBER_MAX_LEN (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_serial_number( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVSerialNumber*); + +uint32_t dot11f_pack_tlv_serial_number( + tpAniSirGlobal, + tDot11fTLVSerialNumber *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_SerialNumber( + tpAniSirGlobal, + tDot11fTLVSerialNumber *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4167 (0x1047) */ +typedef struct sDot11fTLVUUID_E { + uint8_t present; + uint8_t uuid[16]; +} tDot11fTLVUUID_E; + +#define DOT11F_TLV_UUID_E (4167) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_UUID_E_MIN_LEN (18) + +#define DOT11F_TLV_UUID_E_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_uuid_e( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVUUID_E*); + +uint32_t dot11f_pack_tlv_uuid_e( + tpAniSirGlobal, + tDot11fTLVUUID_E *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_UUID_E( + tpAniSirGlobal, + tDot11fTLVUUID_E *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4168 (0x1048) */ +typedef struct sDot11fTLVUUID_R { + uint8_t present; + uint8_t uuid[16]; +} tDot11fTLVUUID_R; + +#define DOT11F_TLV_UUID_R (4168) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_UUID_R_MIN_LEN (18) + +#define DOT11F_TLV_UUID_R_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_uuid_r( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVUUID_R*); + +uint32_t dot11f_pack_tlv_uuid_r( + tpAniSirGlobal, + tDot11fTLVUUID_R *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_UUID_R( + tpAniSirGlobal, + tDot11fTLVUUID_R *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4169 (0x1049) */ +typedef struct sDot11fTLVVendorExtension { + uint8_t present; + uint8_t vendorId[3]; + tDot11fTLVVersion2 Version2; + tDot11fTLVAuthorizedMACs AuthorizedMACs; + tDot11fTLVRequestToEnroll RequestToEnroll; +} tDot11fTLVVendorExtension; + +#define DOT11F_TLV_VENDOREXTENSION (4169) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VENDOREXTENSION_MIN_LEN (5) + +#define DOT11F_TLV_VENDOREXTENSION_MAX_LEN (19) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_vendor_extension( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVendorExtension*); + +uint32_t dot11f_pack_tlv_vendor_extension( + tpAniSirGlobal, + tDot11fTLVVendorExtension *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_VendorExtension( + tpAniSirGlobal, + tDot11fTLVVendorExtension *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4170 (0x104a) */ +typedef struct sDot11fTLVVersion { + uint8_t present; + uint8_t minor:4; + uint8_t major:4; +} tDot11fTLVVersion; + +#define DOT11F_TLV_VERSION (4170) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VERSION_MIN_LEN (3) + +#define DOT11F_TLV_VERSION_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_version( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVVersion*); + +uint32_t dot11f_pack_tlv_version( + tpAniSirGlobal, + tDot11fTLVVersion *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_Version( + tpAniSirGlobal, + tDot11fTLVVersion *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4164 (0x1044) */ +typedef struct sDot11fTLVWPSState { + uint8_t present; + uint8_t state; +} tDot11fTLVWPSState; + +#define DOT11F_TLV_WPSSTATE (4164) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_WPSSTATE_MIN_LEN (3) + +#define DOT11F_TLV_WPSSTATE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_WPSState( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVWPSState*); + +uint32_t dot11f_pack_tlv_wps_state( + tpAniSirGlobal, + tDot11fTLVWPSState *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_WPSState( + tpAniSirGlobal, + tDot11fTLVWPSState *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4 (0x0004) */ +typedef struct sDot11fTLVassoc_disallowed { + uint8_t present; + uint8_t reason_code; +} tDot11fTLVassoc_disallowed; + +#define DOT11F_TLV_ASSOC_DISALLOWED (4) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_ASSOC_DISALLOWED_MIN_LEN (1) + +#define DOT11F_TLV_ASSOC_DISALLOWED_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_assoc_disallowed( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVassoc_disallowed*); + +uint32_t dot11f_pack_tlv_assoc_disallowed( + tpAniSirGlobal, + tDot11fTLVassoc_disallowed *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_assoc_disallowed( + tpAniSirGlobal, + tDot11fTLVassoc_disallowed *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 8 (0x0008) */ +typedef struct sDot11fTLVassoc_retry_delay { + uint8_t present; + uint16_t delay; +} tDot11fTLVassoc_retry_delay; + +#define DOT11F_TLV_ASSOC_RETRY_DELAY (8) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_ASSOC_RETRY_DELAY_MIN_LEN (2) + +#define DOT11F_TLV_ASSOC_RETRY_DELAY_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_assoc_retry_delay( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVassoc_retry_delay*); + +uint32_t dot11f_pack_tlv_assoc_retry_delay( + tpAniSirGlobal, + tDot11fTLVassoc_retry_delay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_assoc_retry_delay( + tpAniSirGlobal, + tDot11fTLVassoc_retry_delay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVcellular_data_cap { + uint8_t present; + uint8_t cellular_connectivity; +} tDot11fTLVcellular_data_cap; + +#define DOT11F_TLV_CELLULAR_DATA_CAP (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CELLULAR_DATA_CAP_MIN_LEN (1) + +#define DOT11F_TLV_CELLULAR_DATA_CAP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_cellular_data_cap( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVcellular_data_cap*); + +uint32_t dot11f_pack_tlv_cellular_data_cap( + tpAniSirGlobal, + tDot11fTLVcellular_data_cap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_cellular_data_cap( + tpAniSirGlobal, + tDot11fTLVcellular_data_cap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 5 (0x0005) */ +typedef struct sDot11fTLVcellular_data_con_pref { + uint8_t present; + uint8_t cellular_preference; +} tDot11fTLVcellular_data_con_pref; + +#define DOT11F_TLV_CELLULAR_DATA_CON_PREF (5) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_CELLULAR_DATA_CON_PREF_MIN_LEN (1) + +#define DOT11F_TLV_CELLULAR_DATA_CON_PREF_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_cellular_data_con_pref( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVcellular_data_con_pref*); + +uint32_t dot11f_pack_tlv_cellular_data_con_pref( + tpAniSirGlobal, + tDot11fTLVcellular_data_con_pref *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_cellular_data_con_pref( + tpAniSirGlobal, + tDot11fTLVcellular_data_con_pref *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 14 (0x000e) */ +typedef struct sDot11fTLVecsa_target_tsf_info_attr { + uint8_t present; + uint8_t twt_ch_sw_mode; + tDOT11F_U64 target_tsf; +} tDot11fTLVecsa_target_tsf_info_attr; + +#define DOT11F_TLV_ECSA_TARGET_TSF_INFO_ATTR (14) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_ECSA_TARGET_TSF_INFO_ATTR_MIN_LEN (9) + +#define DOT11F_TLV_ECSA_TARGET_TSF_INFO_ATTR_MAX_LEN (9) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_ecsa_target_tsf_info_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVecsa_target_tsf_info_attr*); + +uint32_t dot11f_pack_tlv_ecsa_target_tsf_info_attr( + tpAniSirGlobal, + tDot11fTLVecsa_target_tsf_info_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_ecsa_target_tsf_info_attr( + tpAniSirGlobal, + tDot11fTLVecsa_target_tsf_info_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 13 (0x000d) */ +typedef struct sDot11fTLVedca_pifs_param_attr { + uint8_t present; + uint8_t edca_param_type; + uint8_t num_data; + uint8_t data[4]; +} tDot11fTLVedca_pifs_param_attr; + +#define DOT11F_TLV_EDCA_PIFS_PARAM_ATTR (13) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_EDCA_PIFS_PARAM_ATTR_MIN_LEN (4) + +#define DOT11F_TLV_EDCA_PIFS_PARAM_ATTR_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_edca_pifs_param_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVedca_pifs_param_attr*); + +uint32_t dot11f_pack_tlv_edca_pifs_param_attr( + tpAniSirGlobal, + tDot11fTLVedca_pifs_param_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_edca_pifs_param_attr( + tpAniSirGlobal, + tDot11fTLVedca_pifs_param_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 4 (0x0004) */ +typedef struct sDot11fTLVhe_2xltf_160mhz_supp { + uint8_t present; + uint8_t he_2xltf_160MHz_supp; +} tDot11fTLVhe_2xltf_160mhz_supp; + +#define DOT11F_TLV_HE_2XLTF_160MHZ_SUPP (4) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_HE_2XLTF_160MHZ_SUPP_MIN_LEN (1) + +#define DOT11F_TLV_HE_2XLTF_160MHZ_SUPP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_he_2xltf_160mhz_supp( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVhe_2xltf_160mhz_supp*); + +uint32_t dot11f_pack_tlv_he_2xltf_160mhz_supp( + tpAniSirGlobal, + tDot11fTLVhe_2xltf_160mhz_supp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_he_2xltf_160mhz_supp( + tpAniSirGlobal, + tDot11fTLVhe_2xltf_160mhz_supp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 3 (0x0003) */ +typedef struct sDot11fTLVhe_400ns_sgi_attr { + uint8_t present; + uint8_t he_ltf1x_400ns_sgi; + uint8_t he_ltf2x_400ns_sgi; + uint8_t he_ltf4x_400ns_sgi; +} tDot11fTLVhe_400ns_sgi_attr; + +#define DOT11F_TLV_HE_400NS_SGI_ATTR (3) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_HE_400NS_SGI_ATTR_MIN_LEN (3) + +#define DOT11F_TLV_HE_400NS_SGI_ATTR_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_he_400ns_sgi_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVhe_400ns_sgi_attr*); + +uint32_t dot11f_pack_tlv_he_400ns_sgi_attr( + tpAniSirGlobal, + tDot11fTLVhe_400ns_sgi_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_he_400ns_sgi_attr( + tpAniSirGlobal, + tDot11fTLVhe_400ns_sgi_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 8 (0x0008) */ +typedef struct sDot11fTLVhe_dl_mumimo_attr { + uint8_t present; + uint8_t he_dl_mumimo_supp; +} tDot11fTLVhe_dl_mumimo_attr; + +#define DOT11F_TLV_HE_DL_MUMIMO_ATTR (8) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_HE_DL_MUMIMO_ATTR_MIN_LEN (1) + +#define DOT11F_TLV_HE_DL_MUMIMO_ATTR_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_he_dl_mumimo_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVhe_dl_mumimo_attr*); + +uint32_t dot11f_pack_tlv_he_dl_mumimo_attr( + tpAniSirGlobal, + tDot11fTLVhe_dl_mumimo_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_he_dl_mumimo_attr( + tpAniSirGlobal, + tDot11fTLVhe_dl_mumimo_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 5 (0x0005) */ +typedef struct sDot11fTLVhe_dl_ofdma_attr { + uint8_t present; + uint8_t he_dl_ofdma_supp; +} tDot11fTLVhe_dl_ofdma_attr; + +#define DOT11F_TLV_HE_DL_OFDMA_ATTR (5) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_HE_DL_OFDMA_ATTR_MIN_LEN (1) + +#define DOT11F_TLV_HE_DL_OFDMA_ATTR_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_he_dl_ofdma_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVhe_dl_ofdma_attr*); + +uint32_t dot11f_pack_tlv_he_dl_ofdma_attr( + tpAniSirGlobal, + tDot11fTLVhe_dl_ofdma_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_he_dl_ofdma_attr( + tpAniSirGlobal, + tDot11fTLVhe_dl_ofdma_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 9 (0x0009) */ +typedef struct sDot11fTLVhe_mcs13_attr { + uint8_t present; + uint8_t he_mcs_12_13_supp_80; + uint8_t he_mcs_12_13_supp_160; +} tDot11fTLVhe_mcs13_attr; + +#define DOT11F_TLV_HE_MCS13_ATTR (9) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_HE_MCS13_ATTR_MIN_LEN (2) + +#define DOT11F_TLV_HE_MCS13_ATTR_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_he_mcs13_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVhe_mcs13_attr*); + +uint32_t dot11f_pack_tlv_he_mcs13_attr( + tpAniSirGlobal, + tDot11fTLVhe_mcs13_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_he_mcs13_attr( + tpAniSirGlobal, + tDot11fTLVhe_mcs13_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVmbo_ap_cap { + uint8_t present; + uint8_t mbo_cap_ind; +} tDot11fTLVmbo_ap_cap; + +#define DOT11F_TLV_MBO_AP_CAP (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_MBO_AP_CAP_MIN_LEN (1) + +#define DOT11F_TLV_MBO_AP_CAP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_mbo_ap_cap( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVmbo_ap_cap*); + +uint32_t dot11f_pack_tlv_mbo_ap_cap( + tpAniSirGlobal, + tDot11fTLVmbo_ap_cap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_mbo_ap_cap( + tpAniSirGlobal, + tDot11fTLVmbo_ap_cap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 2 (0x0002) */ +typedef struct sDot11fTLVnon_prefferd_chan_rep { + uint8_t present; + uint8_t oper_class; + uint8_t num_channel_report; + uint8_t channel_report[254]; +} tDot11fTLVnon_prefferd_chan_rep; + +#define DOT11F_TLV_NON_PREFFERD_CHAN_REP (2) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_NON_PREFFERD_CHAN_REP_MIN_LEN (4) + +#define DOT11F_TLV_NON_PREFFERD_CHAN_REP_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_non_prefferd_chan_rep( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVnon_prefferd_chan_rep*); + +uint32_t dot11f_pack_tlv_non_prefferd_chan_rep( + tpAniSirGlobal, + tDot11fTLVnon_prefferd_chan_rep *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_non_prefferd_chan_rep( + tpAniSirGlobal, + tDot11fTLVnon_prefferd_chan_rep *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 101 (0x0065) */ +typedef struct sDot11fTLVoce_cap { + uint8_t present; + uint8_t oce_release:3; + uint8_t is_sta_cfon:1; + uint8_t non_oce_ap_present:1; + uint8_t reserved:3; +} tDot11fTLVoce_cap; + +#define DOT11F_TLV_OCE_CAP (101) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_OCE_CAP_MIN_LEN (1) + +#define DOT11F_TLV_OCE_CAP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_oce_cap( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVoce_cap*); + +uint32_t dot11f_pack_tlv_oce_cap( + tpAniSirGlobal, + tDot11fTLVoce_cap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_oce_cap( + tpAniSirGlobal, + tDot11fTLVoce_cap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 1 (0x0001) */ +typedef struct sDot11fTLVqcn_version { + uint8_t present; + uint8_t version; + uint8_t sub_version; +} tDot11fTLVqcn_version; + +#define DOT11F_TLV_QCN_VERSION (1) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_QCN_VERSION_MIN_LEN (2) + +#define DOT11F_TLV_QCN_VERSION_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_qcn_version( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVqcn_version*); + +uint32_t dot11f_pack_tlv_qcn_version( + tpAniSirGlobal, + tDot11fTLVqcn_version *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_qcn_version( + tpAniSirGlobal, + tDot11fTLVqcn_version *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 103 (0x0067) */ +typedef struct sDot11fTLVreduced_wan_metrics { + uint8_t present; + uint8_t downlink_av_cap:4; + uint8_t uplink_av_cap:4; +} tDot11fTLVreduced_wan_metrics; + +#define DOT11F_TLV_REDUCED_WAN_METRICS (103) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_REDUCED_WAN_METRICS_MIN_LEN (1) + +#define DOT11F_TLV_REDUCED_WAN_METRICS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_reduced_wan_metrics( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVreduced_wan_metrics*); + +uint32_t dot11f_pack_tlv_reduced_wan_metrics( + tpAniSirGlobal, + tDot11fTLVreduced_wan_metrics *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_reduced_wan_metrics( + tpAniSirGlobal, + tDot11fTLVreduced_wan_metrics *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 102 (0x0066) */ +typedef struct sDot11fTLVrssi_assoc_rej { + uint8_t present; + uint8_t delta_rssi; + uint8_t retry_delay; +} tDot11fTLVrssi_assoc_rej; + +#define DOT11F_TLV_RSSI_ASSOC_REJ (102) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_RSSI_ASSOC_REJ_MIN_LEN (2) + +#define DOT11F_TLV_RSSI_ASSOC_REJ_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_rssi_assoc_rej( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVrssi_assoc_rej*); + +uint32_t dot11f_pack_tlv_rssi_assoc_rej( + tpAniSirGlobal, + tDot11fTLVrssi_assoc_rej *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_rssi_assoc_rej( + tpAniSirGlobal, + tDot11fTLVrssi_assoc_rej *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 6 (0x0006) */ +typedef struct sDot11fTLVtrans_reasonp_attr { + uint8_t present; + uint8_t transition_reasonp; +} tDot11fTLVtrans_reasonp_attr; + +#define DOT11F_TLV_TRANS_REASONP_ATTR (6) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_TRANS_REASONP_ATTR_MIN_LEN (1) + +#define DOT11F_TLV_TRANS_REASONP_ATTR_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_trans_reasonp_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVtrans_reasonp_attr*); + +uint32_t dot11f_pack_tlv_trans_reasonp_attr( + tpAniSirGlobal, + tDot11fTLVtrans_reasonp_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_trans_reasonp_attr( + tpAniSirGlobal, + tDot11fTLVtrans_reasonp_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 7 (0x0007) */ +typedef struct sDot11fTLVtrans_rejectp_attr { + uint8_t present; + uint8_t transition_rejp; +} tDot11fTLVtrans_rejectp_attr; + +#define DOT11F_TLV_TRANS_REJECTP_ATTR (7) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_TRANS_REJECTP_ATTR_MIN_LEN (1) + +#define DOT11F_TLV_TRANS_REJECTP_ATTR_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_trans_rejectp_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVtrans_rejectp_attr*); + +uint32_t dot11f_pack_tlv_trans_rejectp_attr( + tpAniSirGlobal, + tDot11fTLVtrans_rejectp_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_trans_rejectp_attr( + tpAniSirGlobal, + tDot11fTLVtrans_rejectp_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 6 (0x0006) */ +typedef struct sDot11fTLVtransition_reason { + uint8_t present; + uint8_t transition_reason_code; +} tDot11fTLVtransition_reason; + +#define DOT11F_TLV_TRANSITION_REASON (6) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_TRANSITION_REASON_MIN_LEN (1) + +#define DOT11F_TLV_TRANSITION_REASON_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_transition_reason( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVtransition_reason*); + +uint32_t dot11f_pack_tlv_transition_reason( + tpAniSirGlobal, + tDot11fTLVtransition_reason *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_transition_reason( + tpAniSirGlobal, + tDot11fTLVtransition_reason *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 7 (0x0007) */ +typedef struct sDot11fTLVtransition_reject_reason { + uint8_t present; + uint8_t transition_reject_code; +} tDot11fTLVtransition_reject_reason; + +#define DOT11F_TLV_TRANSITION_REJECT_REASON (7) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_TRANSITION_REJECT_REASON_MIN_LEN (1) + +#define DOT11F_TLV_TRANSITION_REJECT_REASON_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_transition_reject_reason( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVtransition_reject_reason*); + +uint32_t dot11f_pack_tlv_transition_reject_reason( + tpAniSirGlobal, + tDot11fTLVtransition_reject_reason *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_transition_reject_reason( + tpAniSirGlobal, + tDot11fTLVtransition_reject_reason *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 2 (0x0002) */ +typedef struct sDot11fTLVvht_mcs11_attr { + uint8_t present; + uint8_t vht_mcs_10_11_supp; +} tDot11fTLVvht_mcs11_attr; + +#define DOT11F_TLV_VHT_MCS11_ATTR (2) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_VHT_MCS11_ATTR_MIN_LEN (1) + +#define DOT11F_TLV_VHT_MCS11_ATTR_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_vht_mcs11_attr( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVvht_mcs11_attr*); + +uint32_t dot11f_pack_tlv_vht_mcs11_attr( + tpAniSirGlobal, + tDot11fTLVvht_mcs11_attr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_vht_mcs11_attr( + tpAniSirGlobal, + tDot11fTLVvht_mcs11_attr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 16 (0x0010) */ +typedef struct sDot11fTLVP2PInterface { + uint8_t present; + uint8_t P2PDeviceAddress[6]; +} tDot11fTLVP2PInterface; + +#define DOT11F_TLV_P2PINTERFACE (16) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PINTERFACE_MIN_LEN (7) + +#define DOT11F_TLV_P2PINTERFACE_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_p2_p_interface( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PInterface*); + +uint32_t dot11f_pack_tlv_p2_p_interface( + tpAniSirGlobal, + tDot11fTLVP2PInterface *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PInterface( + tpAniSirGlobal, + tDot11fTLVP2PInterface *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* ID 10 (0x000a) */ +typedef struct sDot11fTLVP2PManageability { + uint8_t present; + uint8_t manageability; +} tDot11fTLVP2PManageability; + +#define DOT11F_TLV_P2PMANAGEABILITY (10) + +/* N.B. These #defines do *not* include the ID & length */ +#define DOT11F_TLV_P2PMANAGEABILITY_MIN_LEN (2) + +#define DOT11F_TLV_P2PMANAGEABILITY_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +uint32_t dot11f_unpack_tlv_P2PManageability( + tpAniSirGlobal, + uint8_t *, + uint16_t, + tDot11fTLVP2PManageability*); + +uint32_t dot11f_pack_tlv_p2_p_manageability( + tpAniSirGlobal, + tDot11fTLVP2PManageability *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_tlv_P2PManageability( + tpAniSirGlobal, + tDot11fTLVP2PManageability *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ +/********************************************************************* + * Information Elements * + ********************************************************************/ + + +/* EID 2 (0x02) */ +typedef struct sDot11fIEGTK { + uint8_t present; + uint16_t keyId:2; + uint16_t reserved:14; + uint8_t keyLength; + uint8_t RSC[8]; + uint8_t num_key; + uint8_t key[32]; +} tDot11fIEGTK; + +#define DOT11F_EID_GTK (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_GTK_MIN_LEN (16) + +#define DOT11F_IE_GTK_MAX_LEN (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_gtk( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEGTK*, + bool); + +uint32_t dot11f_pack_ie_gtk( + tpAniSirGlobal, + tDot11fIEGTK *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_GTK( + tpAniSirGlobal, + tDot11fIEGTK *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIEIGTK { + uint8_t present; + uint8_t keyID[2]; + uint8_t IPN[6]; + uint8_t keyLength; + uint8_t key[24]; +} tDot11fIEIGTK; + +#define DOT11F_EID_IGTK (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_IGTK_MIN_LEN (33) + +#define DOT11F_IE_IGTK_MAX_LEN (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_igtk( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEIGTK*, + bool); + +uint32_t dot11f_pack_ie_igtk( + tpAniSirGlobal, + tDot11fIEIGTK *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_IGTK( + tpAniSirGlobal, + tDot11fIEIGTK *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIER0KH_ID { + uint8_t present; + uint8_t num_PMK_R0_ID; + uint8_t PMK_R0_ID[48]; +} tDot11fIER0KH_ID; + +#define DOT11F_EID_R0KH_ID (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_R0KH_ID_MIN_LEN (1) + +#define DOT11F_IE_R0KH_ID_MAX_LEN (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_r0_kh_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIER0KH_ID*, + bool); + +uint32_t dot11f_pack_ie_r0_kh_id( + tpAniSirGlobal, + tDot11fIER0KH_ID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_R0KH_ID( + tpAniSirGlobal, + tDot11fIER0KH_ID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIER1KH_ID { + uint8_t present; + uint8_t PMK_R1_ID[6]; +} tDot11fIER1KH_ID; + +#define DOT11F_EID_R1KH_ID (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_R1KH_ID_MIN_LEN (6) + +#define DOT11F_IE_R1KH_ID_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_r1_kh_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIER1KH_ID*, + bool); + +uint32_t dot11f_pack_ie_r1_kh_id( + tpAniSirGlobal, + tDot11fIER1KH_ID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_R1KH_ID( + tpAniSirGlobal, + tDot11fIER1KH_ID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 51 (0x33) */ +typedef struct sDot11fIEAPChannelReport { + uint8_t present; + uint8_t regulatoryClass; + uint8_t num_channelList; + uint8_t channelList[50]; +} tDot11fIEAPChannelReport; + +#define DOT11F_EID_APCHANNELREPORT (51) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_APCHANNELREPORT_MIN_LEN (1) + +#define DOT11F_IE_APCHANNELREPORT_MAX_LEN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ap_channel_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEAPChannelReport*, + bool); + +uint32_t dot11f_pack_ie_ap_channel_report( + tpAniSirGlobal, + tDot11fIEAPChannelReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_APChannelReport( + tpAniSirGlobal, + tDot11fIEAPChannelReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEBcnReportingDetail { + uint8_t present; + uint8_t reportingDetail; +} tDot11fIEBcnReportingDetail; + +#define DOT11F_EID_BCNREPORTINGDETAIL (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BCNREPORTINGDETAIL_MIN_LEN (1) + +#define DOT11F_IE_BCNREPORTINGDETAIL_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_bcn_reporting_detail( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBcnReportingDetail*, + bool); + +uint32_t dot11f_pack_ie_bcn_reporting_detail( + tpAniSirGlobal, + tDot11fIEBcnReportingDetail *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BcnReportingDetail( + tpAniSirGlobal, + tDot11fIEBcnReportingDetail *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEBeaconReportFrmBody { + uint8_t present; + uint8_t num_reportedFields; + uint8_t reportedFields[224]; +} tDot11fIEBeaconReportFrmBody; + +#define DOT11F_EID_BEACONREPORTFRMBODY (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACONREPORTFRMBODY_MIN_LEN (0) + +#define DOT11F_IE_BEACONREPORTFRMBODY_MAX_LEN (224) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_beacon_report_frm_body( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEBeaconReportFrmBody*, + bool); + +uint32_t dot11f_pack_ie_beacon_report_frm_body( + tpAniSirGlobal, + tDot11fIEBeaconReportFrmBody *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_BeaconReportFrmBody( + tpAniSirGlobal, + tDot11fIEBeaconReportFrmBody *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIECondensedCountryStr { + uint8_t present; + uint8_t countryStr[2]; +} tDot11fIECondensedCountryStr; + +#define DOT11F_EID_CONDENSEDCOUNTRYSTR (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CONDENSEDCOUNTRYSTR_MIN_LEN (2) + +#define DOT11F_IE_CONDENSEDCOUNTRYSTR_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_condensed_country_str( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECondensedCountryStr*, + bool); + +uint32_t dot11f_pack_ie_condensed_country_str( + tpAniSirGlobal, + tDot11fIECondensedCountryStr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_CondensedCountryStr( + tpAniSirGlobal, + tDot11fIECondensedCountryStr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 11 (0x0b) */ +typedef struct sDot11fIEExtRequestedInfo { + uint8_t present; + uint8_t req_element_id; + uint8_t num_req_element_id_ext; + uint8_t req_element_id_ext[255]; +} tDot11fIEExtRequestedInfo; + +#define DOT11F_EID_EXTREQUESTEDINFO (11) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTREQUESTEDINFO_MIN_LEN (1) + +#define DOT11F_IE_EXTREQUESTEDINFO_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ExtRequestedInfo( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtRequestedInfo*, + bool); + +uint32_t dot11f_pack_ie_ExtRequestedInfo( + tpAniSirGlobal, + tDot11fIEExtRequestedInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtRequestedInfo( + tpAniSirGlobal, + tDot11fIEExtRequestedInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 66 (0x42) */ +typedef struct sDot11fIEMeasurementPilot { + uint8_t present; + uint8_t measurementPilot; + uint8_t num_vendorSpecific; + uint8_t vendorSpecific[255]; +} tDot11fIEMeasurementPilot; + +#define DOT11F_EID_MEASUREMENTPILOT (66) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTPILOT_MIN_LEN (1) + +#define DOT11F_IE_MEASUREMENTPILOT_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_measurement_pilot( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementPilot*, + bool); + +uint32_t dot11f_pack_ie_measurement_pilot( + tpAniSirGlobal, + tDot11fIEMeasurementPilot *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MeasurementPilot( + tpAniSirGlobal, + tDot11fIEMeasurementPilot *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 71 (0x47) */ +typedef struct sDot11fIEMultiBssid { + uint8_t present; + uint8_t maxBSSIDIndicator; + uint8_t num_vendorSpecific; + uint8_t vendorSpecific[255]; +} tDot11fIEMultiBssid; + +#define DOT11F_EID_MULTIBSSID (71) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MULTIBSSID_MIN_LEN (1) + +#define DOT11F_IE_MULTIBSSID_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_multi_bssid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMultiBssid*, + bool); + +uint32_t dot11f_pack_ie_multi_bssid( + tpAniSirGlobal, + tDot11fIEMultiBssid *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MultiBssid( + tpAniSirGlobal, + tDot11fIEMultiBssid *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 57 (0x39) */ +typedef struct sDot11fIERICData { + uint8_t present; + uint8_t Identifier; + uint8_t resourceDescCount; + uint16_t statusCode; +} tDot11fIERICData; + +#define DOT11F_EID_RICDATA (57) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDATA_MIN_LEN (4) + +#define DOT11F_IE_RICDATA_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ric_data( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICData*, + bool); + +uint32_t dot11f_pack_ie_ric_data( + tpAniSirGlobal, + tDot11fIERICData *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RICData( + tpAniSirGlobal, + tDot11fIERICData *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 75 (0x4b) */ +typedef struct sDot11fIERICDescriptor { + uint8_t present; + uint8_t resourceType; + uint8_t num_variableData; + uint8_t variableData[255]; +} tDot11fIERICDescriptor; + +#define DOT11F_EID_RICDESCRIPTOR (75) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDESCRIPTOR_MIN_LEN (1) + +#define DOT11F_IE_RICDESCRIPTOR_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ric_descriptor( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICDescriptor*, + bool); + +uint32_t dot11f_pack_ie_ric_descriptor( + tpAniSirGlobal, + tDot11fIERICDescriptor *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RICDescriptor( + tpAniSirGlobal, + tDot11fIERICDescriptor *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 70 (0x46) */ +typedef struct sDot11fIERRMEnabledCap { + uint8_t present; + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatinChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t fine_time_meas_rpt:1; + uint8_t lci_capability:1; + uint8_t reserved:4; +} tDot11fIERRMEnabledCap; + +#define DOT11F_EID_RRMENABLEDCAP (70) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RRMENABLEDCAP_MIN_LEN (5) + +#define DOT11F_IE_RRMENABLEDCAP_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_rrm_enabled_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERRMEnabledCap*, + bool); + +uint32_t dot11f_pack_ie_rrm_enabled_cap( + tpAniSirGlobal, + tDot11fIERRMEnabledCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RRMEnabledCap( + tpAniSirGlobal, + tDot11fIERRMEnabledCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 10 (0x0a) */ +typedef struct sDot11fIERequestedInfo { + uint8_t present; + uint8_t num_requested_eids; + uint8_t requested_eids[255]; +} tDot11fIERequestedInfo; + +#define DOT11F_EID_REQUESTEDINFO (10) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REQUESTEDINFO_MIN_LEN (0) + +#define DOT11F_IE_REQUESTEDINFO_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_requested_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERequestedInfo*, + bool); + +uint32_t dot11f_pack_ie_requested_info( + tpAniSirGlobal, + tDot11fIERequestedInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RequestedInfo( + tpAniSirGlobal, + tDot11fIERequestedInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 0 (0x00) */ +typedef struct sDot11fIESSID { + uint8_t present; + uint8_t num_ssid; + uint8_t ssid[32]; +} tDot11fIESSID; + +#define DOT11F_EID_SSID (0) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SSID_MIN_LEN (0) + +#define DOT11F_IE_SSID_MAX_LEN (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ssid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESSID*, + bool); + +uint32_t dot11f_pack_ie_ssid( + tpAniSirGlobal, + tDot11fIESSID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SSID( + tpAniSirGlobal, + tDot11fIESSID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 15 (0x0f) */ +typedef struct sDot11fIESchedule { + uint8_t present; + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t reserved:9; + uint32_t service_start_time; + uint32_t service_interval; + uint16_t max_service_dur; + uint16_t spec_interval; +} tDot11fIESchedule; + +#define DOT11F_EID_SCHEDULE (15) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SCHEDULE_MIN_LEN (14) + +#define DOT11F_IE_SCHEDULE_MAX_LEN (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_schedule( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESchedule*, + bool); + +uint32_t dot11f_pack_ie_schedule( + tpAniSirGlobal, + tDot11fIESchedule *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Schedule( + tpAniSirGlobal, + tDot11fIESchedule *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 14 (0x0e) */ +typedef struct sDot11fIETCLAS { + uint8_t present; + uint8_t user_priority; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t source[6]; + uint8_t dest[6]; + uint16_t type; + } EthParams; /* classifier_type = 0 */ + struct { + uint8_t version; + union { + struct { + uint8_t source[4]; + uint8_t dest[4]; + uint16_t src_port; + uint16_t dest_port; + uint8_t DSCP; + uint8_t proto; + uint8_t reserved; + } IpV4Params; /* version = 4 */ + struct { + uint8_t source[16]; + uint8_t dest[16]; + uint16_t src_port; + uint16_t dest_port; + uint8_t flow_label[3]; + } IpV6Params; /* version = 6 */ + } params; + } IpParams; /* classifier_type = 1 */ + struct { + uint16_t tag_type; + } Params8021dq; /* classifier_type = 2 */ + } info; +} tDot11fIETCLAS; + +#define DOT11F_EID_TCLAS (14) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLAS_MIN_LEN (5) + +#define DOT11F_IE_TCLAS_MAX_LEN (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tclas( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETCLAS*, + bool); + +uint32_t dot11f_pack_ie_tclas( + tpAniSirGlobal, + tDot11fIETCLAS *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ietclas( + tpAniSirGlobal, + tDot11fIETCLAS *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 44 (0x2c) */ +typedef struct sDot11fIETCLASSPROC { + uint8_t present; + uint8_t processing; +} tDot11fIETCLASSPROC; + +#define DOT11F_EID_TCLASSPROC (44) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLASSPROC_MIN_LEN (1) + +#define DOT11F_IE_TCLASSPROC_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tclasSPROC( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETCLASSPROC*, + bool); + +uint32_t dot11f_pack_ie_tclassproc( + tpAniSirGlobal, + tDot11fIETCLASSPROC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ietclasSPROC( + tpAniSirGlobal, + tDot11fIETCLASSPROC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 43 (0x2b) */ +typedef struct sDot11fIETSDelay { + uint8_t present; + uint32_t delay; +} tDot11fIETSDelay; + +#define DOT11F_EID_TSDELAY (43) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSDELAY_MIN_LEN (4) + +#define DOT11F_IE_TSDELAY_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ts_delay( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSDelay*, + bool); + +uint32_t dot11f_pack_ie_ts_delay( + tpAniSirGlobal, + tDot11fIETSDelay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSDelay( + tpAniSirGlobal, + tDot11fIETSDelay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIETSFInfo { + uint8_t present; + uint16_t TsfOffset; + uint16_t BeaconIntvl; +} tDot11fIETSFInfo; + +#define DOT11F_EID_TSFINFO (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSFINFO_MIN_LEN (4) + +#define DOT11F_IE_TSFINFO_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tsf_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSFInfo*, + bool); + +uint32_t dot11f_pack_ie_tsf_info( + tpAniSirGlobal, + tDot11fIETSFInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSFInfo( + tpAniSirGlobal, + tDot11fIETSFInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 13 (0x0d) */ +typedef struct sDot11fIETSPEC { + uint8_t present; + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t schedule:1; + uint8_t unused:7; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} tDot11fIETSPEC; + +#define DOT11F_EID_TSPEC (13) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TSPEC_MIN_LEN (55) + +#define DOT11F_IE_TSPEC_MAX_LEN (55) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tspec( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETSPEC*, + bool); + +uint32_t dot11f_pack_ie_tspec( + tpAniSirGlobal, + tDot11fIETSPEC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TSPEC( + tpAniSirGlobal, + tDot11fIETSPEC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 191 (0xbf) */ +typedef struct sDot11fIEVHTCaps { + uint8_t present; + uint32_t maxMPDULen:2; + uint32_t supportedChannelWidthSet:2; + uint32_t ldpcCodingCap:1; + uint32_t shortGI80MHz:1; + uint32_t shortGI160and80plus80MHz:1; + uint32_t txSTBC:1; + uint32_t rxSTBC:3; + uint32_t suBeamFormerCap:1; + uint32_t suBeamformeeCap:1; + uint32_t csnofBeamformerAntSup:3; + uint32_t numSoundingDim:3; + uint32_t muBeamformerCap:1; + uint32_t muBeamformeeCap:1; + uint32_t vhtTXOPPS:1; + uint32_t htcVHTCap:1; + uint32_t maxAMPDULenExp:3; + uint32_t vhtLinkAdaptCap:2; + uint32_t rxAntPattern:1; + uint32_t txAntPattern:1; + uint32_t extended_nss_bw_supp:2; + uint16_t rxMCSMap; + uint16_t rxHighSupDataRate:13; + uint16_t max_nsts_total:3; + uint16_t txMCSMap; + uint16_t txSupDataRate:13; + uint16_t vht_extended_nss_bw_cap:1; + uint16_t reserved:2; +} tDot11fIEVHTCaps; + +#define DOT11F_EID_VHTCAPS (191) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTCAPS_MIN_LEN (12) + +#define DOT11F_IE_VHTCAPS_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vht_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTCaps*, + bool); + +uint32_t dot11f_pack_ie_vht_caps( + tpAniSirGlobal, + tDot11fIEVHTCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTCaps( + tpAniSirGlobal, + tDot11fIEVHTCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 192 (0xc0) */ +typedef struct sDot11fIEVHTOperation { + uint8_t present; + uint8_t chanWidth; + uint8_t chan_center_freq_seg0; + uint8_t chan_center_freq_seg1; + uint16_t basicMCSSet; +} tDot11fIEVHTOperation; + +#define DOT11F_EID_VHTOPERATION (192) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTOPERATION_MIN_LEN (5) + +#define DOT11F_IE_VHTOPERATION_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vht_operation( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTOperation*, + bool); + +uint32_t dot11f_pack_ie_vht_operation( + tpAniSirGlobal, + tDot11fIEVHTOperation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTOperation( + tpAniSirGlobal, + tDot11fIEVHTOperation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x09} */ +typedef struct sDot11fIEWMMSchedule { + uint8_t present; + uint8_t version /* Must be 1! */; + uint16_t aggregation:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t reserved:9; + uint32_t service_start_time; + uint32_t service_interval; + uint16_t max_service_dur; + uint16_t spec_interval; +} tDot11fIEWMMSchedule; + +#define DOT11F_EID_WMMSCHEDULE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMSCHEDULE_MIN_LEN (20) + +#define DOT11F_IE_WMMSCHEDULE_MAX_LEN (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmm_schedule( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMSchedule*, + bool); + +uint32_t dot11f_pack_ie_wmm_schedule( + tpAniSirGlobal, + tDot11fIEWMMSchedule *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMSchedule( + tpAniSirGlobal, + tDot11fIEWMMSchedule *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x06} */ +typedef struct sDot11fIEWMMTCLAS { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t user_priority; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t source[6]; + uint8_t dest[6]; + uint16_t type; + } EthParams; /* classifier_type = 0 */ + struct { + uint8_t version; + union { + struct { + uint8_t source[4]; + uint8_t dest[4]; + uint16_t src_port; + uint16_t dest_port; + uint8_t DSCP; + uint8_t proto; + uint8_t reserved; + } IpV4Params; /* version = 4 */ + struct { + uint8_t source[16]; + uint8_t dest[16]; + uint16_t src_port; + uint16_t dest_port; + uint8_t flow_label[3]; + } IpV6Params; /* version = 6 */ + } params; + } IpParams; /* classifier_type = 1 */ + struct { + uint16_t tag_type; + } Params8021dq; /* classifier_type = 2 */ + } info; +} tDot11fIEWMMTCLAS; + +#define DOT11F_EID_WMMTCLAS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTCLAS_MIN_LEN (11) + +#define DOT11F_IE_WMMTCLAS_MAX_LEN (49) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmmtclas( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTCLAS*, + bool); + +uint32_t dot11f_pack_ie_wmmtclas( + tpAniSirGlobal, + tDot11fIEWMMTCLAS *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewmmtclas( + tpAniSirGlobal, + tDot11fIEWMMTCLAS *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x07} */ +typedef struct sDot11fIEWMMTCLASPROC { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t processing; +} tDot11fIEWMMTCLASPROC; + +#define DOT11F_EID_WMMTCLASPROC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTCLASPROC_MIN_LEN (7) + +#define DOT11F_IE_WMMTCLASPROC_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmmtclasproc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTCLASPROC*, + bool); + +uint32_t dot11f_pack_ie_wmmtclasproc( + tpAniSirGlobal, + tDot11fIEWMMTCLASPROC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewmmtclasPROC( + tpAniSirGlobal, + tDot11fIEWMMTCLASPROC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x08} */ +typedef struct sDot11fIEWMMTSDelay { + uint8_t present; + uint8_t version /* Must be 1! */; + uint32_t delay; +} tDot11fIEWMMTSDelay; + +#define DOT11F_EID_WMMTSDELAY (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTSDELAY_MIN_LEN (10) + +#define DOT11F_IE_WMMTSDELAY_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmmts_delay( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTSDelay*, + bool); + +uint32_t dot11f_pack_ie_wmmts_delay( + tpAniSirGlobal, + tDot11fIEWMMTSDelay *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMTSDelay( + tpAniSirGlobal, + tDot11fIEWMMTSDelay *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x02} */ +typedef struct sDot11fIEWMMTSPEC { + uint8_t present; + uint8_t version /* Must be 1! */; + uint16_t traffic_type:1; + uint16_t tsid:4; + uint16_t direction:2; + uint16_t access_policy:2; + uint16_t aggregation:1; + uint16_t psb:1; + uint16_t user_priority:3; + uint16_t tsinfo_ack_pol:2; + uint8_t tsinfo_rsvd:7; + uint8_t burst_size_defn:1; + uint16_t size:15; + uint16_t fixed:1; + uint16_t max_msdu_size; + uint32_t min_service_int; + uint32_t max_service_int; + uint32_t inactivity_int; + uint32_t suspension_int; + uint32_t service_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +} tDot11fIEWMMTSPEC; + +#define DOT11F_EID_WMMTSPEC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMTSPEC_MIN_LEN (61) + +#define DOT11F_IE_WMMTSPEC_MAX_LEN (61) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmmtspec( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMTSPEC*, + bool); + +uint32_t dot11f_pack_ie_wmmtspec( + tpAniSirGlobal, + tDot11fIEWMMTSPEC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMTSPEC( + tpAniSirGlobal, + tDot11fIEWMMTSPEC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 194 (0xc2) */ +typedef struct sDot11fIEWiderBWChanSwitchAnn { + uint8_t present; + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tDot11fIEWiderBWChanSwitchAnn; + +#define DOT11F_EID_WIDERBWCHANSWITCHANN (194) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WIDERBWCHANSWITCHANN_MIN_LEN (3) + +#define DOT11F_IE_WIDERBWCHANSWITCHANN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wider_bw_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWiderBWChanSwitchAnn*, + bool); + +uint32_t dot11f_pack_ie_wider_bw_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEWiderBWChanSwitchAnn *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WiderBWChanSwitchAnn( + tpAniSirGlobal, + tDot11fIEWiderBWChanSwitchAnn *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEazimuth_req { + uint8_t present; + uint8_t request; +} tDot11fIEazimuth_req; + +#define DOT11F_EID_AZIMUTH_REQ (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_AZIMUTH_REQ_MIN_LEN (1) + +#define DOT11F_IE_AZIMUTH_REQ_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_azimuth_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEazimuth_req*, + bool); + +uint32_t dot11f_pack_ie_azimuth_req( + tpAniSirGlobal, + tDot11fIEazimuth_req *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_azimuth_req( + tpAniSirGlobal, + tDot11fIEazimuth_req *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEbeacon_report_frm_body_fragment_id { + uint8_t present; + uint16_t beacon_report_id:8; + uint16_t fragment_id_number:7; + uint16_t more_fragments:1; +} tDot11fIEbeacon_report_frm_body_fragment_id; + +#define DOT11F_EID_BEACON_REPORT_FRM_BODY_FRAGMENT_ID (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BEACON_REPORT_FRM_BODY_FRAGMENT_ID_MIN_LEN (2) + +#define DOT11F_IE_BEACON_REPORT_FRM_BODY_FRAGMENT_ID_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_beacon_report_frm_body_fragment_id( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEbeacon_report_frm_body_fragment_id*, + bool); + +uint32_t dot11f_pack_ie_beacon_report_frm_body_fragment_id( + tpAniSirGlobal, + tDot11fIEbeacon_report_frm_body_fragment_id *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_beacon_report_frm_body_fragment_id( + tpAniSirGlobal, + tDot11fIEbeacon_report_frm_body_fragment_id *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 135 (0x87) */ +typedef struct sDot11fIEbw_ind_element { + uint8_t present; + uint8_t reserved:1; + uint8_t disabled_sub_chan_bitmap_present:1; + uint8_t reserved_1:6; + uint8_t channel_width:3; + uint8_t reserved_2:5; + uint8_t ccfs0; + uint8_t ccfs1; + uint8_t disabled_sub_chan_bitmap[1][2]; +} tDot11fIEbw_ind_element; + +#define DOT11F_EID_BW_IND_ELEMENT (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BW_IND_ELEMENT_MIN_LEN (4) + +#define DOT11F_IE_BW_IND_ELEMENT_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_bw_ind_element( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEbw_ind_element*, + bool); + +uint32_t dot11f_pack_ie_bw_ind_element( + tpAniSirGlobal, + tDot11fIEbw_ind_element *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_bw_ind_element( + tpAniSirGlobal, + tDot11fIEbw_ind_element *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 164 (0xa4) */ +typedef struct sDot11fIEbw_indication { + uint8_t present; + uint8_t reserved:1; + uint8_t disabled_sub_chan_bitmap_present:1; + uint8_t reserved_1:6; + uint8_t channel_width:3; + uint8_t reserved_2:5; + uint8_t ccfs0; + uint8_t ccfs1; + uint8_t disabled_sub_chan_bitmap[1][2]; +} tDot11fIEbw_indication; + +#define DOT11F_EID_BW_INDICATION (164) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BW_INDICATION_MIN_LEN (4) + +#define DOT11F_IE_BW_INDICATION_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_bw_indication( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEbw_indication*, + bool); + +uint32_t dot11f_pack_ie_bw_indication( + tpAniSirGlobal, + tDot11fIEbw_indication *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_bw_indication( + tpAniSirGlobal, + tDot11fIEbw_indication *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 164 (0xa4) */ +typedef struct sDot11fIElast_beacon_report_indication { + uint8_t present; + uint8_t last_fragment; +} tDot11fIElast_beacon_report_indication; + +#define DOT11F_EID_LAST_BEACON_REPORT_INDICATION (164) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_LAST_BEACON_REPORT_INDICATION_MIN_LEN (1) + +#define DOT11F_IE_LAST_BEACON_REPORT_INDICATION_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_last_beacon_report_indication( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIElast_beacon_report_indication*, + bool); + +uint32_t dot11f_pack_ie_last_beacon_report_indication( + tpAniSirGlobal, + tDot11fIElast_beacon_report_indication *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_last_beacon_report_indication( + tpAniSirGlobal, + tDot11fIElast_beacon_report_indication *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIEmax_age { + uint8_t present; + uint16_t max_age; +} tDot11fIEmax_age; + +#define DOT11F_EID_MAX_AGE (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MAX_AGE_MIN_LEN (2) + +#define DOT11F_IE_MAX_AGE_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_max_age( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEmax_age*, + bool); + +uint32_t dot11f_pack_ie_max_age( + tpAniSirGlobal, + tDot11fIEmax_age *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_max_age( + tpAniSirGlobal, + tDot11fIEmax_age *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 76 (0x4c) */ +typedef struct sDot11fIEmscs_status { + uint8_t present; + uint8_t status_code; +} tDot11fIEmscs_status; + +#define DOT11F_EID_MSCS_STATUS (76) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MSCS_STATUS_MIN_LEN (1) + +#define DOT11F_IE_MSCS_STATUS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_mscs_status( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEmscs_status*, + bool); + +uint32_t dot11f_pack_ie_mscs_status( + tpAniSirGlobal, + tDot11fIEmscs_status *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_mscs_status( + tpAniSirGlobal, + tDot11fIEmscs_status *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 52 (0x34) */ +typedef struct sDot11fIEneighbor_rpt { + uint8_t present; + uint8_t bssid[6]; + uint8_t APReachability:2; + uint8_t Security:1; + uint8_t KeyScope:1; + uint8_t SpecMgmtCap:1; + uint8_t QosCap:1; + uint8_t apsd:1; + uint8_t rrm:1; + uint8_t DelayedBA:1; + uint8_t ImmBA:1; + uint8_t MobilityDomain:1; + uint8_t reserved:5; + uint16_t reserved1; + uint8_t regulatoryClass; + uint8_t channel; + uint8_t PhyType; + tDot11fIETSFInfo TSFInfo; + tDot11fIECondensedCountryStr CondensedCountryStr; + tDot11fIEMeasurementPilot MeasurementPilot; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMultiBssid MultiBssid; +} tDot11fIEneighbor_rpt; + +#define DOT11F_EID_NEIGHBOR_RPT (52) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_NEIGHBOR_RPT_MIN_LEN (13) + +#define DOT11F_IE_NEIGHBOR_RPT_MAX_LEN (546) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_neighbor_rpt( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEneighbor_rpt*, + bool); + +uint32_t dot11f_pack_ie_neighbor_rpt( + tpAniSirGlobal, + tDot11fIEneighbor_rpt *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_neighbor_rpt( + tpAniSirGlobal, + tDot11fIEneighbor_rpt *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIEreporting_reason { + uint8_t present; + uint8_t failed_count:1; + uint8_t fcs_error:1; + uint8_t multiple_retry:1; + uint8_t frame_duplicate:1; + uint8_t rts_failure:1; + uint8_t ack_failure:1; + uint8_t retry:1; + uint8_t reserved:1; +} tDot11fIEreporting_reason; + +#define DOT11F_EID_REPORTING_REASON (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REPORTING_REASON_MIN_LEN (1) + +#define DOT11F_IE_REPORTING_REASON_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_reporting_reason( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEreporting_reason*, + bool); + +uint32_t dot11f_pack_ie_reporting_reason( + tpAniSirGlobal, + tDot11fIEreporting_reason *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_reporting_reason( + tpAniSirGlobal, + tDot11fIEreporting_reason *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEreq_mac_addr { + uint8_t present; + uint8_t addr[6]; +} tDot11fIEreq_mac_addr; + +#define DOT11F_EID_REQ_MAC_ADDR (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REQ_MAC_ADDR_MIN_LEN (6) + +#define DOT11F_IE_REQ_MAC_ADDR_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_req_mac_addr( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEreq_mac_addr*, + bool); + +uint32_t dot11f_pack_ie_req_mac_addr( + tpAniSirGlobal, + tDot11fIEreq_mac_addr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_req_mac_addr( + tpAniSirGlobal, + tDot11fIEreq_mac_addr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIErrm_reporting { + uint8_t present; + uint8_t reporting_condition; + uint8_t threshold; +} tDot11fIErrm_reporting; + +#define DOT11F_EID_RRM_REPORTING (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RRM_REPORTING_MIN_LEN (2) + +#define DOT11F_IE_RRM_REPORTING_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_rrm_reporting( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIErrm_reporting*, + bool); + +uint32_t dot11f_pack_ie_rrm_reporting( + tpAniSirGlobal, + tDot11fIErrm_reporting *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_rrm_reporting( + tpAniSirGlobal, + tDot11fIErrm_reporting *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 89 (0x59) */ +typedef struct sDot11fIEtclas_mask { + uint8_t present; + uint8_t classifier_type; + uint8_t classifier_mask; + union { + struct { + uint8_t reserved[16]; + } ip_param; /* classifier_type = 4 */ + } info; +} tDot11fIEtclas_mask; + +#define DOT11F_EID_TCLAS_MASK (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TCLAS_MASK_MIN_LEN (18) + +#define DOT11F_IE_TCLAS_MASK_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tclas_mask( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEtclas_mask*, + bool); + +uint32_t dot11f_pack_ie_tclas_mask( + tpAniSirGlobal, + tDot11fIEtclas_mask *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_tclas_mask( + tpAniSirGlobal, + tDot11fIEtclas_mask *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIEtgt_mac_addr { + uint8_t present; + uint8_t addr[6]; +} tDot11fIEtgt_mac_addr; + +#define DOT11F_EID_TGT_MAC_ADDR (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TGT_MAC_ADDR_MIN_LEN (6) + +#define DOT11F_IE_TGT_MAC_ADDR_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tgt_mac_addr( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEtgt_mac_addr*, + bool); + +uint32_t dot11f_pack_ie_tgt_mac_addr( + tpAniSirGlobal, + tDot11fIEtgt_mac_addr *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_tgt_mac_addr( + tpAniSirGlobal, + tDot11fIEtgt_mac_addr *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 195 (0xc3) */ +typedef struct sDot11fIEtransmit_power_env { + uint8_t present; + uint8_t max_tx_pwr_count:3; + uint8_t max_tx_pwr_interpret:3; + uint8_t max_tx_pwr_category:2; + uint8_t num_tx_power; + uint8_t tx_power[8]; + union { + struct { + uint8_t max_tx_power_for_320; + } ext_max_tx_power_local_eirp; /* max_tx_pwr_interpret = 0 */ + struct { + uint8_t ext_count:4; + uint8_t reserved:4; + uint8_t max_tx_psd_power[8]; + } ext_max_tx_power_local_psd; /* max_tx_pwr_interpret = 1 */ + struct { + uint8_t max_tx_power_for_320; + } ext_max_tx_power_reg_eirp; /* max_tx_pwr_interpret = 2 */ + struct { + uint8_t ext_count:4; + uint8_t reserved:4; + uint8_t max_tx_psd_power[8]; + } ext_max_tx_power_reg_psd; /* max_tx_pwr_interpret = 3 */ + } ext_max_tx_power; +} tDot11fIEtransmit_power_env; + +#define DOT11F_EID_TRANSMIT_POWER_ENV (195) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TRANSMIT_POWER_ENV_MIN_LEN (2) + +#define DOT11F_IE_TRANSMIT_POWER_ENV_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_transmit_power_env( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEtransmit_power_env*, + bool); + +uint32_t dot11f_pack_ie_transmit_power_env( + tpAniSirGlobal, + tDot11fIEtransmit_power_env *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_transmit_power_env( + tpAniSirGlobal, + tDot11fIEtransmit_power_env *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 163 (0xa3) */ +typedef struct sDot11fIEwide_bw_chan_switch { + uint8_t present; + uint8_t new_chan_width; + uint8_t new_center_chan_freq0; + uint8_t new_center_chan_freq1; +} tDot11fIEwide_bw_chan_switch; + +#define DOT11F_EID_WIDE_BW_CHAN_SWITCH (163) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WIDE_BW_CHAN_SWITCH_MIN_LEN (3) + +#define DOT11F_IE_WIDE_BW_CHAN_SWITCH_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wide_bw_chan_switch( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEwide_bw_chan_switch*, + bool); + +uint32_t dot11f_pack_ie_wide_bw_chan_switch( + tpAniSirGlobal, + tDot11fIEwide_bw_chan_switch *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wide_bw_chan_switch( + tpAniSirGlobal, + tDot11fIEwide_bw_chan_switch *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 197 (0xc5) */ +typedef struct sDot11fIEAID { + uint8_t present; + uint16_t assocId; +} tDot11fIEAID; + +#define DOT11F_EID_AID (197) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_AID_MIN_LEN (2) + +#define DOT11F_IE_AID_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_aid( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEAID*, + bool); + +uint32_t dot11f_pack_ie_aid( + tpAniSirGlobal, + tDot11fIEAID *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_AID( + tpAniSirGlobal, + tDot11fIEAID *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 4 (0x04) */ +typedef struct sDot11fIECFParams { + uint8_t present; + uint8_t cfp_count; + uint8_t cfp_period; + uint16_t cfp_maxduration; + uint16_t cfp_durremaining; +} tDot11fIECFParams; + +#define DOT11F_EID_CFPARAMS (4) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CFPARAMS_MIN_LEN (6) + +#define DOT11F_IE_CFPARAMS_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_cf_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECFParams*, + bool); + +uint32_t dot11f_pack_ie_cf_params( + tpAniSirGlobal, + tDot11fIECFParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_CFParams( + tpAniSirGlobal, + tDot11fIECFParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 16 (0x10) */ +typedef struct sDot11fIEChallengeText { + uint8_t present; + uint8_t num_text; + uint8_t text[253]; +} tDot11fIEChallengeText; + +#define DOT11F_EID_CHALLENGETEXT (16) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHALLENGETEXT_MIN_LEN (1) + +#define DOT11F_IE_CHALLENGETEXT_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_challenge_text( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChallengeText*, + bool); + +uint32_t dot11f_pack_ie_challenge_text( + tpAniSirGlobal, + tDot11fIEChallengeText *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ChallengeText( + tpAniSirGlobal, + tDot11fIEChallengeText *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 37 (0x25) */ +typedef struct sDot11fIEChanSwitchAnn { + uint8_t present; + uint8_t switchMode; + uint8_t newChannel; + uint8_t switchCount; +} tDot11fIEChanSwitchAnn; + +#define DOT11F_EID_CHANSWITCHANN (37) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHANSWITCHANN_MIN_LEN (3) + +#define DOT11F_IE_CHANSWITCHANN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChanSwitchAnn*, + bool); + +uint32_t dot11f_pack_ie_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEChanSwitchAnn *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ChanSwitchAnn( + tpAniSirGlobal, + tDot11fIEChanSwitchAnn *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 196 (0xc4) */ +typedef struct sDot11fIEChannelSwitchWrapper { + uint8_t present; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEtransmit_power_env transmit_power_env; + tDot11fIEbw_ind_element bw_ind_element; +} tDot11fIEChannelSwitchWrapper; + +#define DOT11F_EID_CHANNELSWITCHWRAPPER (196) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_CHANNELSWITCHWRAPPER_MIN_LEN (0) + +#define DOT11F_IE_CHANNELSWITCHWRAPPER_MAX_LEN (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_channel_switch_wrapper( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEChannelSwitchWrapper*, + bool); + +uint32_t dot11f_pack_ie_channel_switch_wrapper( + tpAniSirGlobal, + tDot11fIEChannelSwitchWrapper *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_channel_switch_wrapper( + tpAniSirGlobal, + tDot11fIEChannelSwitchWrapper *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 7 (0x07) */ +typedef struct sDot11fIECountry { + uint8_t present; + uint8_t country[3]; + uint8_t first_triplet[3]; + uint8_t num_more_triplets; + uint8_t more_triplets[80][3]; +} tDot11fIECountry; + +#define DOT11F_EID_COUNTRY (7) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_COUNTRY_MIN_LEN (6) + +#define DOT11F_IE_COUNTRY_MAX_LEN (246) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_country( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIECountry*, + bool); + +uint32_t dot11f_pack_ie_country( + tpAniSirGlobal, + tDot11fIECountry *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_country( + tpAniSirGlobal, + tDot11fIECountry *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 3 (0x03) */ +typedef struct sDot11fIEDSParams { + uint8_t present; + uint8_t curr_channel; +} tDot11fIEDSParams; + +#define DOT11F_EID_DSPARAMS (3) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_DSPARAMS_MIN_LEN (1) + +#define DOT11F_IE_DSPARAMS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_DSParams( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEDSParams*, + bool); + +uint32_t dot11f_pack_ie_ds_params( + tpAniSirGlobal, + tDot11fIEDSParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_DSParams( + tpAniSirGlobal, + tDot11fIEDSParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 12 (0x0c) */ +typedef struct sDot11fIEEDCAParamSet { + uint8_t present; + uint8_t qos; + uint8_t reserved; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint16_t acbe_txoplimit; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint16_t acbk_txoplimit; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint16_t acvi_txoplimit; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint16_t acvo_txoplimit; +} tDot11fIEEDCAParamSet; + +#define DOT11F_EID_EDCAPARAMSET (12) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EDCAPARAMSET_MIN_LEN (18) + +#define DOT11F_IE_EDCAPARAMSET_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_edca_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEEDCAParamSet*, + bool); + +uint32_t dot11f_pack_ie_edca_param_set( + tpAniSirGlobal, + tDot11fIEEDCAParamSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_EDCAParamSet( + tpAniSirGlobal, + tDot11fIEEDCAParamSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 42 (0x2a) */ +typedef struct sDot11fIEERPInfo { + uint8_t present; + uint8_t non_erp_present:1; + uint8_t use_prot:1; + uint8_t barker_preamble:1; + uint8_t unused:5; +} tDot11fIEERPInfo; + +#define DOT11F_EID_ERPINFO (42) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ERPINFO_MIN_LEN (1) + +#define DOT11F_IE_ERPINFO_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_erp_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEERPInfo*, + bool); + +uint32_t dot11f_pack_ie_erp_info( + tpAniSirGlobal, + tDot11fIEERPInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ERPInfo( + tpAniSirGlobal, + tDot11fIEERPInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 156 (0x9c) {OUI 0x00, 0x40, 0x96, 0x00} */ +typedef struct sDot11fIEESECckmOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[20]; +} tDot11fIEESECckmOpaque; + +#define DOT11F_EID_ESECCKMOPAQUE (156) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESECCKMOPAQUE_MIN_LEN (10) + +#define DOT11F_IE_ESECCKMOPAQUE_MAX_LEN (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ese_cckm_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESECckmOpaque*, + bool); + +uint32_t dot11f_pack_ie_ese_cckm_opaque( + tpAniSirGlobal, + tDot11fIEESECckmOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESECckmOpaque( + tpAniSirGlobal, + tDot11fIEESECckmOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x01} */ +typedef struct sDot11fIEESERadMgmtCap { + uint8_t present; + uint8_t mgmt_state; + uint8_t mbssid_mask:3; + uint8_t reserved:5; +} tDot11fIEESERadMgmtCap; + +#define DOT11F_EID_ESERADMGMTCAP (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESERADMGMTCAP_MIN_LEN (6) + +#define DOT11F_IE_ESERADMGMTCAP_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ese_rad_mgmt_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESERadMgmtCap*, + bool); + +uint32_t dot11f_pack_ie_ese_rad_mgmt_cap( + tpAniSirGlobal, + tDot11fIEESERadMgmtCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESERadMgmtCap( + tpAniSirGlobal, + tDot11fIEESERadMgmtCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x07} */ +typedef struct sDot11fIEESETrafStrmMet { + uint8_t present; + uint8_t tsid; + uint8_t state; + uint16_t msmt_interval; +} tDot11fIEESETrafStrmMet; + +#define DOT11F_EID_ESETRAFSTRMMET (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETRAFSTRMMET_MIN_LEN (8) + +#define DOT11F_IE_ESETRAFSTRMMET_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ese_traf_strm_met( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETrafStrmMet*, + bool); + +uint32_t dot11f_pack_ie_ese_traf_strm_met( + tpAniSirGlobal, + tDot11fIEESETrafStrmMet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETrafStrmMet( + tpAniSirGlobal, + tDot11fIEESETrafStrmMet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x08} */ +typedef struct sDot11fIEESETrafStrmRateSet { + uint8_t present; + uint8_t tsid; + uint8_t num_tsrates; + uint8_t tsrates[8]; +} tDot11fIEESETrafStrmRateSet; + +#define DOT11F_EID_ESETRAFSTRMRATESET (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETRAFSTRMRATESET_MIN_LEN (5) + +#define DOT11F_IE_ESETRAFSTRMRATESET_MAX_LEN (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ese_traf_strm_rate_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETrafStrmRateSet*, + bool); + +uint32_t dot11f_pack_ie_ese_traf_strm_rate_set( + tpAniSirGlobal, + tDot11fIEESETrafStrmRateSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETrafStrmRateSet( + tpAniSirGlobal, + tDot11fIEESETrafStrmRateSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 150 (0x96) {OUI 0x00, 0x40, 0x96, 0x00} */ +typedef struct sDot11fIEESETxmitPower { + uint8_t present; + uint8_t power_limit; + uint8_t reserved; +} tDot11fIEESETxmitPower; + +#define DOT11F_EID_ESETXMITPOWER (150) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESETXMITPOWER_MIN_LEN (6) + +#define DOT11F_IE_ESETXMITPOWER_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ese_txmit_power( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESETxmitPower*, + bool); + +uint32_t dot11f_pack_ie_ese_txmit_power( + tpAniSirGlobal, + tDot11fIEESETxmitPower *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESETxmitPower( + tpAniSirGlobal, + tDot11fIEESETxmitPower *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x40, 0x96, 0x03} */ +typedef struct sDot11fIEESEVersion { + uint8_t present; + uint8_t version; +} tDot11fIEESEVersion; + +#define DOT11F_EID_ESEVERSION (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESEVERSION_MIN_LEN (5) + +#define DOT11F_IE_ESEVERSION_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ese_version( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEESEVersion*, + bool); + +uint32_t dot11f_pack_ie_ese_version( + tpAniSirGlobal, + tDot11fIEESEVersion *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ESEVersion( + tpAniSirGlobal, + tDot11fIEESEVersion *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 127 (0x7f) */ +typedef struct sDot11fIEExtCap { + uint8_t present; + uint8_t num_bytes; + uint8_t bytes[15]; +} tDot11fIEExtCap; + +#define DOT11F_EID_EXTCAP (127) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTCAP_MIN_LEN (1) + +#define DOT11F_IE_EXTCAP_MAX_LEN (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ext_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtCap*, + bool); + +uint32_t dot11f_pack_ie_ext_cap( + tpAniSirGlobal, + tDot11fIEExtCap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtCap( + tpAniSirGlobal, + tDot11fIEExtCap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 50 (0x32) */ +typedef struct sDot11fIEExtSuppRates { + uint8_t present; + uint8_t num_rates; + uint8_t rates[12]; +} tDot11fIEExtSuppRates; + +#define DOT11F_EID_EXTSUPPRATES (50) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXTSUPPRATES_MIN_LEN (1) + +#define DOT11F_IE_EXTSUPPRATES_MAX_LEN (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ext_supp_rates( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEExtSuppRates*, + bool); + +uint32_t dot11f_pack_ie_ext_supp_rates( + tpAniSirGlobal, + tDot11fIEExtSuppRates *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ExtSuppRates( + tpAniSirGlobal, + tDot11fIEExtSuppRates *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 2 (0x02) */ +typedef struct sDot11fIEFHParamSet { + uint8_t present; + uint16_t dwell_time; + uint8_t hop_set; + uint8_t hop_pattern; + uint8_t hop_index; +} tDot11fIEFHParamSet; + +#define DOT11F_EID_FHPARAMSET (2) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPARAMSET_MIN_LEN (5) + +#define DOT11F_IE_FHPARAMSET_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fh_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHParamSet*, + bool); + +uint32_t dot11f_pack_ie_fh_param_set( + tpAniSirGlobal, + tDot11fIEFHParamSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHParamSet( + tpAniSirGlobal, + tDot11fIEFHParamSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 8 (0x08) */ +typedef struct sDot11fIEFHParams { + uint8_t present; + uint8_t radix; + uint8_t nchannels; +} tDot11fIEFHParams; + +#define DOT11F_EID_FHPARAMS (8) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPARAMS_MIN_LEN (2) + +#define DOT11F_IE_FHPARAMS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fh_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHParams*, + bool); + +uint32_t dot11f_pack_ie_fh_params( + tpAniSirGlobal, + tDot11fIEFHParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHParams( + tpAniSirGlobal, + tDot11fIEFHParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 9 (0x09) */ +typedef struct sDot11fIEFHPattTable { + uint8_t present; + uint8_t flag; + uint8_t nsets; + uint8_t modulus; + uint8_t offset; + uint8_t num_randtable; + uint8_t randtable[251]; +} tDot11fIEFHPattTable; + +#define DOT11F_EID_FHPATTTABLE (9) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FHPATTTABLE_MIN_LEN (4) + +#define DOT11F_IE_FHPATTTABLE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fh_patt_table( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFHPattTable*, + bool); + +uint32_t dot11f_pack_ie_fh_patt_table( + tpAniSirGlobal, + tDot11fIEFHPattTable *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_FHPattTable( + tpAniSirGlobal, + tDot11fIEFHPattTable *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 55 (0x37) */ +typedef struct sDot11fIEFTInfo { + uint8_t present; + uint16_t reserved:8; + uint16_t IECount:8; + uint8_t MIC[16]; + uint8_t Anonce[32]; + uint8_t Snonce[32]; + tDot11fIER1KH_ID R1KH_ID; + tDot11fIEGTK GTK; + tDot11fIER0KH_ID R0KH_ID; + tDot11fIEIGTK IGTK; +} tDot11fIEFTInfo; + +#define DOT11F_EID_FTINFO (55) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FTINFO_MIN_LEN (82) + +#define DOT11F_IE_FTINFO_MAX_LEN (220) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ft_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEFTInfo*, + bool); + +uint32_t dot11f_pack_ie_ft_info( + tpAniSirGlobal, + tDot11fIEFTInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ieft_info( + tpAniSirGlobal, + tDot11fIEFTInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 45 (0x2d) */ +typedef struct sDot11fIEHTCaps { + uint8_t present; + uint16_t advCodingCap:1; + uint16_t supportedChannelWidthSet:1; + uint16_t mimoPowerSave:2; + uint16_t greenField:1; + uint16_t shortGI20MHz:1; + uint16_t shortGI40MHz:1; + uint16_t txSTBC:1; + uint16_t rxSTBC:2; + uint16_t delayedBA:1; + uint16_t maximalAMSDUsize:1; + uint16_t dsssCckMode40MHz:1; + uint16_t psmp:1; + uint16_t stbcControlFrame:1; + uint16_t lsigTXOPProtection:1; + uint8_t maxRxAMPDUFactor:2; + uint8_t mpduDensity:3; + uint8_t reserved1:3; + uint8_t supportedMCSSet[16]; + uint16_t pco:1; + uint16_t transitionTime:2; + uint16_t reserved2:5; + uint16_t mcsFeedback:2; + uint16_t reserved3:6; + uint32_t txBF:1; + uint32_t rxStaggeredSounding:1; + uint32_t txStaggeredSounding:1; + uint32_t rxZLF:1; + uint32_t txZLF:1; + uint32_t implicitTxBF:1; + uint32_t calibration:2; + uint32_t explicitCSITxBF:1; + uint32_t explicitUncompressedSteeringMatrix:1; + uint32_t explicitBFCSIFeedback:3; + uint32_t explicitUncompressedSteeringMatrixFeedback:3; + uint32_t explicitCompressedSteeringMatrixFeedback:3; + uint32_t csiNumBFAntennae:2; + uint32_t uncompressedSteeringMatrixBFAntennae:2; + uint32_t compressedSteeringMatrixBFAntennae:2; + uint32_t reserved4:7; + uint8_t antennaSelection:1; + uint8_t explicitCSIFeedbackTx:1; + uint8_t antennaIndicesFeedbackTx:1; + uint8_t explicitCSIFeedback:1; + uint8_t antennaIndicesFeedback:1; + uint8_t rxAS:1; + uint8_t txSoundingPPDUs:1; + uint8_t reserved5:1; + uint8_t num_rsvd; + uint8_t rsvd[32]; +} tDot11fIEHTCaps; + +#define DOT11F_EID_HTCAPS (45) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HTCAPS_MIN_LEN (26) + +#define DOT11F_IE_HTCAPS_MAX_LEN (58) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ht_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEHTCaps*, + bool); + +uint32_t dot11f_pack_ie_ht_caps( + tpAniSirGlobal, + tDot11fIEHTCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_HTCaps( + tpAniSirGlobal, + tDot11fIEHTCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 61 (0x3d) */ +typedef struct sDot11fIEHTInfo { + uint8_t present; + uint8_t primaryChannel; + uint8_t secondaryChannelOffset:2; + uint8_t recommendedTxWidthSet:1; + uint8_t rifsMode:1; + uint8_t controlledAccessOnly:1; + uint8_t serviceIntervalGranularity:3; + uint16_t opMode:2; + uint16_t nonGFDevicesPresent:1; + uint16_t transmitBurstLimit:1; + uint16_t obssNonHTStaPresent:1; + uint16_t chan_center_freq_seg2:8; + uint16_t reserved:3; + uint16_t basicSTBCMCS:7; + uint16_t dualCTSProtection:1; + uint16_t secondaryBeacon:1; + uint16_t lsigTXOPProtectionFullSupport:1; + uint16_t pcoActive:1; + uint16_t pcoPhase:1; + uint16_t reserved2:4; + uint8_t basicMCSSet[16]; + uint8_t num_rsvd; + uint8_t rsvd[32]; +} tDot11fIEHTInfo; + +#define DOT11F_EID_HTINFO (61) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HTINFO_MIN_LEN (22) + +#define DOT11F_IE_HTINFO_MAX_LEN (54) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ht_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEHTInfo*, + bool); + +uint32_t dot11f_pack_ie_ht_info( + tpAniSirGlobal, + tDot11fIEHTInfo *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_HTInfo( + tpAniSirGlobal, + tDot11fIEHTInfo *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 101 (0x65) */ +typedef struct sDot11fIELinkIdentifier { + uint8_t present; + uint8_t bssid[6]; + uint8_t InitStaAddr[6]; + uint8_t RespStaAddr[6]; +} tDot11fIELinkIdentifier; + +#define DOT11F_EID_LINKIDENTIFIER (101) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_LINKIDENTIFIER_MIN_LEN (18) + +#define DOT11F_IE_LINKIDENTIFIER_MAX_LEN (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_link_identifier( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIELinkIdentifier*, + bool); + +uint32_t dot11f_pack_ie_link_identifier( + tpAniSirGlobal, + tDot11fIELinkIdentifier *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_LinkIdentifier( + tpAniSirGlobal, + tDot11fIELinkIdentifier *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x16} (Multi-IE) */ +typedef struct sDot11fIEMBO_IE { + uint8_t present; + tDot11fTLVmbo_ap_cap mbo_ap_cap; + tDot11fTLVnon_prefferd_chan_rep non_prefferd_chan_rep; + tDot11fTLVcellular_data_cap cellular_data_cap; + tDot11fTLVassoc_disallowed assoc_disallowed; + tDot11fTLVcellular_data_con_pref cellular_data_con_pref; + tDot11fTLVtransition_reason transition_reason; + tDot11fTLVtransition_reject_reason transition_reject_reason; + tDot11fTLVassoc_retry_delay assoc_retry_delay; + tDot11fTLVoce_cap oce_cap; + tDot11fTLVrssi_assoc_rej rssi_assoc_rej; + tDot11fTLVreduced_wan_metrics reduced_wan_metrics; +} tDot11fIEMBO_IE; + +#define DOT11F_EID_MBO_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MBO_IE_MIN_LEN (4) + +#define DOT11F_IE_MBO_IE_MAX_LEN (293) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_MBO_IE( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMBO_IE*, + bool); + +uint32_t dot11f_pack_ie_MBO_IE( + tpAniSirGlobal, + tDot11fIEMBO_IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MBO_IE( + tpAniSirGlobal, + tDot11fIEMBO_IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 39 (0x27) */ +typedef struct sDot11fIEMeasurementReport { + uint8_t present; + uint8_t token; + uint8_t late:1; + uint8_t incapable:1; + uint8_t refused:1; + uint8_t unused:5; + uint8_t type; + union { + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t bss:1; + uint8_t ofdm_preamble:1; + uint8_t unid_signal:1; + uint8_t rader:1; + uint8_t unmeasured:1; + uint8_t unused:3; + } Basic; /* type = 0 */ + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t cca_busy_fraction; + } CCA; /* type = 1 */ + struct { + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t rpi0_density; + uint8_t rpi1_density; + uint8_t rpi2_density; + uint8_t rpi3_density; + uint8_t rpi4_density; + uint8_t rpi5_density; + uint8_t rpi6_density; + uint8_t rpi7_density; + } RPIHistogram; /* type = 2 */ + struct { + uint8_t op_class; + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t chan_load; + tDot11fIEwide_bw_chan_switch wide_bw_chan_switch; + tDot11fIEbw_indication bw_indication; + } channel_load_report; /* type = 3 */ + struct { + uint8_t regClass; + uint8_t channel; + tDOT11F_U64 meas_start_time; + uint16_t meas_duration; + uint8_t condensed_PHY:7; + uint8_t reported_frame_type:1; + uint8_t RCPI; + uint8_t RSNI; + uint8_t BSSID[6]; + uint8_t antenna_id; + uint32_t parent_TSF; + tDot11fIEBeaconReportFrmBody BeaconReportFrmBody; + tDot11fIEbeacon_report_frm_body_fragment_id beacon_report_frm_body_fragment_id; + tDot11fIElast_beacon_report_indication last_beacon_report_indication; + } Beacon; /* type = 5 */ + struct { + uint16_t meas_duration; + uint8_t group_id; + union { + struct { + uint32_t transmitted_fragment_count; + uint32_t group_transmitted_frame_count; + uint32_t failed_count; + uint32_t received_fragment_count; + uint32_t group_received_frame_count; + uint32_t fcs_error_count; + uint32_t transmitted_frame_count; + } dot11_counter_stats; /* group_id = 0 */ + struct { + uint32_t retry_count; + uint32_t multiple_retry_count; + uint32_t frame_duplicate_count; + uint32_t rts_success_count; + uint32_t rts_failure_count; + uint32_t ack_failure_count; + } dot11_mac_stats; /* group_id = 1 */ + struct { + uint32_t qos_transmitted_fragment_count; + uint32_t qos_failed_count; + uint32_t qos_retry_count; + uint32_t qos_multiple_retry_count; + uint32_t qos_frame_duplicate_count; + uint32_t qos_rts_success_count; + uint32_t qos_rts_failure_count; + uint32_t qos_ack_failure_count; + uint32_t qos_received_fragment_count; + uint32_t qos_transmitted_frame_count; + uint32_t qos_discarded_frame_count; + uint32_t qos_mpdus_received_count; + uint32_t qos_retries_received_count; + } dot11_qos_counter; /* group_id = 2 */ + struct { + uint8_t ap_average_access_delay; + uint8_t average_access_delay_besteffort; + uint8_t average_access_delay_background; + uint8_t average_access_delay_video; + uint8_t average_access_delay_voice; + uint16_t station_count; + uint8_t channel_utilization; + } dot11_bss_average_access_delay; /* group_id = 10 */ + } statsgroupdata; + tDot11fIEreporting_reason reporting_reason; + } sta_stats; /* type = 7 */ + } report; +} tDot11fIEMeasurementReport; + +#define DOT11F_EID_MEASUREMENTREPORT (39) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTREPORT_MIN_LEN (3) + +#define DOT11F_IE_MEASUREMENTREPORT_MAX_LEN (58) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_measurement_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementReport*, + bool); + +uint32_t dot11f_pack_ie_measurement_report( + tpAniSirGlobal, + tDot11fIEMeasurementReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_measurement_report( + tpAniSirGlobal, + tDot11fIEMeasurementReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 38 (0x26) */ +typedef struct sDot11fIEMeasurementRequest { + uint8_t present; + uint8_t measurement_token; + uint8_t parallel:1; + uint8_t enable:1; + uint8_t request:1; + uint8_t report:1; + uint8_t durationMandatory:1; + uint8_t unused:3; + uint8_t measurement_type; + union { + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } Basic; /* measurement_type = 0 */ + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } CCA; /* measurement_type = 1 */ + struct { + uint8_t channel_no; + uint8_t meas_start_time[8]; + uint16_t meas_duration; + } RPIHistogram; /* measurement_type = 2 */ + struct { + uint8_t op_class; + uint8_t channel; + uint16_t randomization_intv; + uint16_t meas_duration; + tDot11fIErrm_reporting rrm_reporting; + tDot11fIEwide_bw_chan_switch wide_bw_chan_switch; + tDot11fIEbw_indication bw_indication; + } channel_load; /* measurement_type = 3 */ + struct { + uint8_t regClass; + uint8_t channel; + uint16_t randomization; + uint16_t meas_duration; + uint8_t meas_mode; + uint8_t BSSID[6]; + tDot11fIESSID SSID; + tDot11fIErrm_reporting rrm_reporting; + tDot11fIEBcnReportingDetail BcnReportingDetail; + tDot11fIERequestedInfo RequestedInfo; + tDot11fIEExtRequestedInfo ExtRequestedInfo; + uint16_t num_APChannelReport; + tDot11fIEAPChannelReport APChannelReport[2]; + tDot11fIElast_beacon_report_indication last_beacon_report_indication; + } Beacon; /* measurement_type = 5 */ + struct { + uint8_t loc_subject; + tDot11fIEazimuth_req azimuth_req; + tDot11fIEreq_mac_addr req_mac_addr; + tDot11fIEtgt_mac_addr tgt_mac_addr; + tDot11fIEmax_age max_age; + } lci; /* measurement_type = 8 */ + struct { + uint16_t random_interval; + uint8_t min_ap_count; + tDot11fIEneighbor_rpt neighbor_rpt; + tDot11fIEmax_age max_age; + } ftmrr; /* measurement_type = 16 */ + struct { + uint8_t peer_mac_addr[6]; + uint16_t randomization; + uint16_t meas_duration; + uint8_t group_identity; + } sta_stats; /* measurement_type = 7 */ + } measurement_request; +} tDot11fIEMeasurementRequest; + +#define DOT11F_EID_MEASUREMENTREQUEST (38) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MEASUREMENTREQUEST_MIN_LEN (4) + +#define DOT11F_IE_MEASUREMENTREQUEST_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_measurement_request( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMeasurementRequest*, + bool); + +uint32_t dot11f_pack_ie_measurement_request( + tpAniSirGlobal, + tDot11fIEMeasurementRequest *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_measurement_request( + tpAniSirGlobal, + tDot11fIEMeasurementRequest *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 54 (0x36) */ +typedef struct sDot11fIEMobilityDomain { + uint8_t present; + uint16_t MDID; + uint8_t overDSCap:1; + uint8_t resourceReqCap:1; + uint8_t reserved:6; +} tDot11fIEMobilityDomain; + +#define DOT11F_EID_MOBILITYDOMAIN (54) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MOBILITYDOMAIN_MIN_LEN (3) + +#define DOT11F_IE_MOBILITYDOMAIN_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_mobility_domain( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEMobilityDomain*, + bool); + +uint32_t dot11f_pack_ie_mobility_domain( + tpAniSirGlobal, + tDot11fIEMobilityDomain *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_MobilityDomain( + tpAniSirGlobal, + tDot11fIEMobilityDomain *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 52 (0x34) */ +typedef struct sDot11fIENeighborReport { + uint8_t present; + uint8_t bssid[6]; + uint8_t APReachability:2; + uint8_t Security:1; + uint8_t KeyScope:1; + uint8_t SpecMgmtCap:1; + uint8_t QosCap:1; + uint8_t apsd:1; + uint8_t rrm:1; + uint8_t DelayedBA:1; + uint8_t ImmBA:1; + uint8_t MobilityDomain:1; + uint8_t reserved:5; + uint16_t reserved1; + uint8_t regulatoryClass; + uint8_t channel; + uint8_t PhyType; + tDot11fIETSFInfo TSFInfo; + tDot11fIECondensedCountryStr CondensedCountryStr; + tDot11fIEMeasurementPilot MeasurementPilot; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMultiBssid MultiBssid; +} tDot11fIENeighborReport; + +#define DOT11F_EID_NEIGHBORREPORT (52) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_NEIGHBORREPORT_MIN_LEN (13) + +#define DOT11F_IE_NEIGHBORREPORT_MAX_LEN (546) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_neighbor_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIENeighborReport*, + bool); + +uint32_t dot11f_pack_ie_neighbor_report( + tpAniSirGlobal, + tDot11fIENeighborReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_neighbor_report( + tpAniSirGlobal, + tDot11fIENeighborReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 74 (0x4a) */ +typedef struct sDot11fIEOBSSScanParameters { + uint8_t present; + uint16_t obssScanPassiveDwell; + uint16_t obssScanActiveDwell; + uint16_t bssChannelWidthTriggerScanInterval; + uint16_t obssScanPassiveTotalPerChannel; + uint16_t obssScanActiveTotalPerChannel; + uint16_t bssWidthChannelTransitionDelayFactor; + uint16_t obssScanActivityThreshold; +} tDot11fIEOBSSScanParameters; + +#define DOT11F_EID_OBSSSCANPARAMETERS (74) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OBSSSCANPARAMETERS_MIN_LEN (14) + +#define DOT11F_IE_OBSSSCANPARAMETERS_MAX_LEN (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_obss_scan_parameters( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEOBSSScanParameters*, + bool); + +uint32_t dot11f_pack_ie_obss_scan_parameters( + tpAniSirGlobal, + tDot11fIEOBSSScanParameters *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_OBSSScanParameters( + tpAniSirGlobal, + tDot11fIEOBSSScanParameters *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 199 (0xc7) */ +typedef struct sDot11fIEOperatingMode { + uint8_t present; + uint8_t chanWidth:2; + uint8_t vht_160_80p80_supp:1; + uint8_t no_ldpc:1; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tDot11fIEOperatingMode; + +#define DOT11F_EID_OPERATINGMODE (199) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OPERATINGMODE_MIN_LEN (1) + +#define DOT11F_IE_OPERATINGMODE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_operating_mode( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEOperatingMode*, + bool); + +uint32_t dot11f_pack_ie_operating_mode( + tpAniSirGlobal, + tDot11fIEOperatingMode *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_OperatingMode( + tpAniSirGlobal, + tDot11fIEOperatingMode *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PAssocReq { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; +} tDot11fIEP2PAssocReq; + +#define DOT11F_EID_P2PASSOCREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PASSOCREQ_MIN_LEN (4) + +#define DOT11F_IE_P2PASSOCREQ_MAX_LEN (71) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_assoc_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PAssocReq*, + bool); + +uint32_t dot11f_pack_ie_p2_p_assoc_req( + tpAniSirGlobal, + tDot11fIEP2PAssocReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_assoc_req( + tpAniSirGlobal, + tDot11fIEP2PAssocReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PAssocRes { + uint8_t present; + tDot11fTLVP2PStatus P2PStatus; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; +} tDot11fIEP2PAssocRes; + +#define DOT11F_EID_P2PASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_P2PASSOCRES_MAX_LEN (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_assoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PAssocRes*, + bool); + +uint32_t dot11f_pack_ie_p2_p_assoc_res( + tpAniSirGlobal, + tDot11fIEP2PAssocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_assoc_res( + tpAniSirGlobal, + tDot11fIEP2PAssocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PBeacon { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; +} tDot11fIEP2PBeacon; + +#define DOT11F_EID_P2PBEACON (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PBEACON_MIN_LEN (4) + +#define DOT11F_IE_P2PBEACON_MAX_LEN (59) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_beacon( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PBeacon*, + bool); + +uint32_t dot11f_pack_ie_p2_p_beacon( + tpAniSirGlobal, + tDot11fIEP2PBeacon *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_beacon( + tpAniSirGlobal, + tDot11fIEP2PBeacon *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PBeaconProbeRes { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; + tDot11fTLVP2PGroupInfo P2PGroupInfo; +} tDot11fIEP2PBeaconProbeRes; + +#define DOT11F_EID_P2PBEACONPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PBEACONPROBERES_MIN_LEN (4) + +#define DOT11F_IE_P2PBEACONPROBERES_MAX_LEN (1148) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_beacon_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PBeaconProbeRes*, + bool); + +uint32_t dot11f_pack_ie_p2_p_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEP2PBeaconProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEP2PBeaconProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PDeAuth { + uint8_t present; + tDot11fTLVMinorReasonCode MinorReasonCode; +} tDot11fIEP2PDeAuth; + +#define DOT11F_EID_P2PDEAUTH (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PDEAUTH_MIN_LEN (4) + +#define DOT11F_IE_P2PDEAUTH_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_de_auth( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PDeAuth*, + bool); + +uint32_t dot11f_pack_ie_p2_p_de_auth( + tpAniSirGlobal, + tDot11fIEP2PDeAuth *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_de_auth( + tpAniSirGlobal, + tDot11fIEP2PDeAuth *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PDisAssoc { + uint8_t present; + tDot11fTLVMinorReasonCode MinorReasonCode; +} tDot11fIEP2PDisAssoc; + +#define DOT11F_EID_P2PDISASSOC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PDISASSOC_MIN_LEN (4) + +#define DOT11F_IE_P2PDISASSOC_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_dis_assoc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PDisAssoc*, + bool); + +uint32_t dot11f_pack_ie_p2_p_dis_assoc( + tpAniSirGlobal, + tDot11fIEP2PDisAssoc *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_dis_assoc( + tpAniSirGlobal, + tDot11fIEP2PDisAssoc *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} */ +typedef struct sDot11fIEP2PIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEP2PIEOpaque; + +#define DOT11F_EID_P2PIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_P2PIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_pie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PIEOpaque*, + bool); + +uint32_t dot11f_pack_ie_p2_pie_opaque( + tpAniSirGlobal, + tDot11fIEP2PIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_P2PIEOpaque( + tpAniSirGlobal, + tDot11fIEP2PIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PProbeReq { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVP2PDeviceId P2PDeviceId; + tDot11fTLVListenChannel ListenChannel; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVOperatingChannel OperatingChannel; +} tDot11fIEP2PProbeReq; + +#define DOT11F_EID_P2PPROBEREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PPROBEREQ_MIN_LEN (4) + +#define DOT11F_IE_P2PPROBEREQ_MAX_LEN (41) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_probe_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PProbeReq*, + bool); + +uint32_t dot11f_pack_ie_p2_p_probe_req( + tpAniSirGlobal, + tDot11fIEP2PProbeReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_probe_req( + tpAniSirGlobal, + tDot11fIEP2PProbeReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x09} (Multi-IE) */ +typedef struct sDot11fIEP2PProbeRes { + uint8_t present; + tDot11fTLVP2PCapability P2PCapability; + tDot11fTLVExtendedListenTiming ExtendedListenTiming; + tDot11fTLVNoticeOfAbsence NoticeOfAbsence; + tDot11fTLVP2PDeviceInfo P2PDeviceInfo; + tDot11fTLVP2PGroupInfo P2PGroupInfo; +} tDot11fIEP2PProbeRes; + +#define DOT11F_EID_P2PPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_P2PPROBERES_MIN_LEN (4) + +#define DOT11F_IE_P2PPROBERES_MAX_LEN (1139) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_p2_p_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEP2PProbeRes*, + bool); + +uint32_t dot11f_pack_ie_p2_p_probe_res( + tpAniSirGlobal, + tDot11fIEP2PProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iep2_p_probe_res( + tpAniSirGlobal, + tDot11fIEP2PProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 105 (0x69) */ +typedef struct sDot11fIEPTIControl { + uint8_t present; + uint8_t tid; + uint16_t sequence_control; +} tDot11fIEPTIControl; + +#define DOT11F_EID_PTICONTROL (105) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_PTICONTROL_MIN_LEN (3) + +#define DOT11F_IE_PTICONTROL_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_pti_control( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPTIControl*, + bool); + +uint32_t dot11f_pack_ie_pti_control( + tpAniSirGlobal, + tDot11fIEPTIControl *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PTIControl( + tpAniSirGlobal, + tDot11fIEPTIControl *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 106 (0x6a) */ +typedef struct sDot11fIEPUBufferStatus { + uint8_t present; + uint8_t ac_bk_traffic_aval:1; + uint8_t ac_be_traffic_aval:1; + uint8_t ac_vi_traffic_aval:1; + uint8_t ac_vo_traffic_aval:1; + uint8_t reserved:4; +} tDot11fIEPUBufferStatus; + +#define DOT11F_EID_PUBUFFERSTATUS (106) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_PUBUFFERSTATUS_MIN_LEN (1) + +#define DOT11F_IE_PUBUFFERSTATUS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_pu_buffer_status( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPUBufferStatus*, + bool); + +uint32_t dot11f_pack_ie_pu_buffer_status( + tpAniSirGlobal, + tDot11fIEPUBufferStatus *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PUBufferStatus( + tpAniSirGlobal, + tDot11fIEPUBufferStatus *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 33 (0x21) */ +typedef struct sDot11fIEPowerCaps { + uint8_t present; + uint8_t minTxPower; + uint8_t maxTxPower; +} tDot11fIEPowerCaps; + +#define DOT11F_EID_POWERCAPS (33) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_POWERCAPS_MIN_LEN (2) + +#define DOT11F_IE_POWERCAPS_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_power_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPowerCaps*, + bool); + +uint32_t dot11f_pack_ie_power_caps( + tpAniSirGlobal, + tDot11fIEPowerCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PowerCaps( + tpAniSirGlobal, + tDot11fIEPowerCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 32 (0x20) */ +typedef struct sDot11fIEPowerConstraints { + uint8_t present; + uint8_t localPowerConstraints; +} tDot11fIEPowerConstraints; + +#define DOT11F_EID_POWERCONSTRAINTS (32) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_POWERCONSTRAINTS_MIN_LEN (1) + +#define DOT11F_IE_POWERCONSTRAINTS_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_power_constraints( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEPowerConstraints*, + bool); + +uint32_t dot11f_pack_ie_power_constraints( + tpAniSirGlobal, + tDot11fIEPowerConstraints *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_PowerConstraints( + tpAniSirGlobal, + tDot11fIEPowerConstraints *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 11 (0x0b) */ +typedef struct sDot11fIEQBSSLoad { + uint8_t present; + uint16_t stacount; + uint8_t chautil; + uint16_t avail; +} tDot11fIEQBSSLoad; + +#define DOT11F_EID_QBSSLOAD (11) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QBSSLOAD_MIN_LEN (5) + +#define DOT11F_IE_QBSSLOAD_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_qbss_load( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQBSSLoad*, + bool); + +uint32_t dot11f_pack_ie_qbss_load( + tpAniSirGlobal, + tDot11fIEQBSSLoad *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QBSSLoad( + tpAniSirGlobal, + tDot11fIEQBSSLoad *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0xa0, 0xc6} */ +typedef struct sDot11fIEQComVendorIE { + uint8_t present; + uint8_t type; + uint8_t channel; +} tDot11fIEQComVendorIE; + +#define DOT11F_EID_QCOMVENDORIE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QCOMVENDORIE_MIN_LEN (5) + +#define DOT11F_IE_QCOMVENDORIE_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_QComVendorIE( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQComVendorIE*, + bool); + +uint32_t dot11f_pack_ie_QComVendorIE( + tpAniSirGlobal, + tDot11fIEQComVendorIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QComVendorIE( + tpAniSirGlobal, + tDot11fIEQComVendorIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 46 (0x2e) */ +typedef struct sDot11fIEQOSCapsAp { + uint8_t present; + uint8_t count:4; + uint8_t qack:1; + uint8_t qreq:1; + uint8_t txopreq:1; + uint8_t reserved:1; +} tDot11fIEQOSCapsAp; + +#define DOT11F_EID_QOSCAPSAP (46) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSCAPSAP_MIN_LEN (1) + +#define DOT11F_IE_QOSCAPSAP_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_qos_caps_ap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQOSCapsAp*, + bool); + +uint32_t dot11f_pack_ie_qos_caps_ap( + tpAniSirGlobal, + tDot11fIEQOSCapsAp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QOSCapsAp( + tpAniSirGlobal, + tDot11fIEQOSCapsAp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 46 (0x2e) */ +typedef struct sDot11fIEQOSCapsStation { + uint8_t present; + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t qack:1; + uint8_t max_sp_length:2; + uint8_t more_data_ack:1; +} tDot11fIEQOSCapsStation; + +#define DOT11F_EID_QOSCAPSSTATION (46) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSCAPSSTATION_MIN_LEN (1) + +#define DOT11F_IE_QOSCAPSSTATION_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_qos_caps_station( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQOSCapsStation*, + bool); + +uint32_t dot11f_pack_ie_qos_caps_station( + tpAniSirGlobal, + tDot11fIEQOSCapsStation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QOSCapsStation( + tpAniSirGlobal, + tDot11fIEQOSCapsStation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 110 (0x6e) */ +typedef struct sDot11fIEQosMapSet { + uint8_t present; + uint8_t num_dscp_exceptions; + uint8_t dscp_exceptions[58]; +} tDot11fIEQosMapSet; + +#define DOT11F_EID_QOSMAPSET (110) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QOSMAPSET_MIN_LEN (16) + +#define DOT11F_IE_QOSMAPSET_MAX_LEN (58) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_qos_map_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQosMapSet*, + bool); + +uint32_t dot11f_pack_ie_qos_map_set( + tpAniSirGlobal, + tDot11fIEQosMapSet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_QosMapSet( + tpAniSirGlobal, + tDot11fIEQosMapSet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 40 (0x28) */ +typedef struct sDot11fIEQuiet { + uint8_t present; + uint8_t count; + uint8_t period; + uint16_t duration; + uint16_t offset; +} tDot11fIEQuiet; + +#define DOT11F_EID_QUIET (40) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QUIET_MIN_LEN (6) + +#define DOT11F_IE_QUIET_MAX_LEN (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_quiet( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEQuiet*, + bool); + +uint32_t dot11f_pack_ie_quiet( + tpAniSirGlobal, + tDot11fIEQuiet *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Quiet( + tpAniSirGlobal, + tDot11fIEQuiet *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 53 (0x35) */ +typedef struct sDot11fIERCPIIE { + uint8_t present; + uint8_t rcpi; +} tDot11fIERCPIIE; + +#define DOT11F_EID_RCPIIE (53) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RCPIIE_MIN_LEN (1) + +#define DOT11F_IE_RCPIIE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_rcpiie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERCPIIE*, + bool); + +uint32_t dot11f_pack_ie_rcpiie( + tpAniSirGlobal, + tDot11fIERCPIIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_RCPIIE( + tpAniSirGlobal, + tDot11fIERCPIIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 57 (0x39) */ +typedef struct sDot11fIERICDataDesc { + uint8_t present; + tDot11fIERICData RICData; + tDot11fIERICDescriptor RICDescriptor; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIETSDelay TSDelay; + tDot11fIESchedule Schedule; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEWMMTSDelay WMMTSDelay; + tDot11fIEWMMSchedule WMMSchedule; +} tDot11fIERICDataDesc; + +#define DOT11F_EID_RICDATADESC (57) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RICDATADESC_MIN_LEN (0) + +#define DOT11F_IE_RICDATADESC_MAX_LEN (548) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ric_data_desc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERICDataDesc*, + bool); + +uint32_t dot11f_pack_ie_ric_data_desc( + tpAniSirGlobal, + tDot11fIERICDataDesc *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ieric_data_desc( + tpAniSirGlobal, + tDot11fIERICDataDesc *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 48 (0x30) */ +typedef struct sDot11fIERSN { + uint8_t present; + uint16_t version /* Must be 1! */; + uint8_t gp_cipher_suite_present; + uint8_t gp_cipher_suite[4]; + uint16_t pwise_cipher_suite_count; + uint8_t pwise_cipher_suites[6][4]; + uint16_t akm_suite_cnt; + uint8_t akm_suite[6][4]; + uint8_t RSN_Cap_present; + uint8_t RSN_Cap[2]; + uint16_t pmkid_count; + uint8_t pmkid[4][16]; + uint8_t gp_mgmt_cipher_suite_present; + uint8_t gp_mgmt_cipher_suite[4]; +} tDot11fIERSN; + +#define DOT11F_EID_RSN (48) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSN_MIN_LEN (2) + +#define DOT11F_IE_RSN_MAX_LEN (130) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_rsn( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSN*, + bool); + +uint32_t dot11f_pack_ie_rsn( + tpAniSirGlobal, + tDot11fIERSN *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersn( + tpAniSirGlobal, + tDot11fIERSN *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 65 (0x41) */ +typedef struct sDot11fIERSNIIE { + uint8_t present; + uint8_t rsni; +} tDot11fIERSNIIE; + +#define DOT11F_EID_RSNIIE (65) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSNIIE_MIN_LEN (1) + +#define DOT11F_IE_RSNIIE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_rsniie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSNIIE*, + bool); + +uint32_t dot11f_pack_ie_rsniie( + tpAniSirGlobal, + tDot11fIERSNIIE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersnIIE( + tpAniSirGlobal, + tDot11fIERSNIIE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 48 (0x30) */ +typedef struct sDot11fIERSNOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[253]; +} tDot11fIERSNOpaque; + +#define DOT11F_EID_RSNOPAQUE (48) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_RSNOPAQUE_MIN_LEN (0) + +#define DOT11F_IE_RSNOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_rsn_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIERSNOpaque*, + bool); + +uint32_t dot11f_pack_ie_rsn_opaque( + tpAniSirGlobal, + tDot11fIERSNOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iersnOpaque( + tpAniSirGlobal, + tDot11fIERSNOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 36 (0x24) */ +typedef struct sDot11fIESuppChannels { + uint8_t present; + uint8_t num_bands; + uint8_t bands[48][2]; +} tDot11fIESuppChannels; + +#define DOT11F_EID_SUPPCHANNELS (36) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPCHANNELS_MIN_LEN (0) + +#define DOT11F_IE_SUPPCHANNELS_MAX_LEN (96) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_supp_channels( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppChannels*, + bool); + +uint32_t dot11f_pack_ie_supp_channels( + tpAniSirGlobal, + tDot11fIESuppChannels *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppChannels( + tpAniSirGlobal, + tDot11fIESuppChannels *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 59 (0x3b) */ +typedef struct sDot11fIESuppOperatingClasses { + uint8_t present; + uint8_t num_classes; + uint8_t classes[32]; +} tDot11fIESuppOperatingClasses; + +#define DOT11F_EID_SUPPOPERATINGCLASSES (59) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPOPERATINGCLASSES_MIN_LEN (1) + +#define DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_supp_operating_classes( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppOperatingClasses*, + bool); + +uint32_t dot11f_pack_ie_supp_operating_classes( + tpAniSirGlobal, + tDot11fIESuppOperatingClasses *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppOperatingClasses( + tpAniSirGlobal, + tDot11fIESuppOperatingClasses *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 1 (0x01) */ +typedef struct sDot11fIESuppRates { + uint8_t present; + uint8_t num_rates; + uint8_t rates[12]; +} tDot11fIESuppRates; + +#define DOT11F_EID_SUPPRATES (1) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SUPPRATES_MIN_LEN (0) + +#define DOT11F_IE_SUPPRATES_MAX_LEN (12) + +#define DOT11F_IS_BG_RATE(_x) (((_x) == 02) || \ + ((_x) == 04) || \ + ((_x) == 11) || \ + ((_x) == 22) || \ + ((_x) == 12) || \ + ((_x) == 18) || \ + ((_x) == 24) || \ + ((_x) == 36) || \ + ((_x) == 48) || \ + ((_x) == 72) || \ + ((_x) == 96) || \ + ((_x) == 108)) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_supp_rates( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIESuppRates*, + bool); + +uint32_t dot11f_pack_ie_supp_rates( + tpAniSirGlobal, + tDot11fIESuppRates *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_SuppRates( + tpAniSirGlobal, + tDot11fIESuppRates *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 5 (0x05) */ +typedef struct sDot11fIETIM { + uint8_t present; + uint8_t dtim_count; + uint8_t dtim_period; + uint8_t bmpctl; + uint8_t num_vbmp; + uint8_t vbmp[251]; +} tDot11fIETIM; + +#define DOT11F_EID_TIM (5) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIM_MIN_LEN (4) + +#define DOT11F_IE_TIM_MAX_LEN (254) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tim( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETIM*, + bool); + +uint32_t dot11f_pack_ie_tim( + tpAniSirGlobal, + tDot11fIETIM *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TIM( + tpAniSirGlobal, + tDot11fIETIM *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 35 (0x23) */ +typedef struct sDot11fIETPCReport { + uint8_t present; + uint8_t tx_power; + uint8_t link_margin; +} tDot11fIETPCReport; + +#define DOT11F_EID_TPCREPORT (35) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TPCREPORT_MIN_LEN (2) + +#define DOT11F_IE_TPCREPORT_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tpc_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETPCReport*, + bool); + +uint32_t dot11f_pack_ie_tpc_report( + tpAniSirGlobal, + tDot11fIETPCReport *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TPCReport( + tpAniSirGlobal, + tDot11fIETPCReport *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 34 (0x22) */ +typedef struct sDot11fIETPCRequest { + uint8_t present; +} tDot11fIETPCRequest; + +#define DOT11F_EID_TPCREQUEST (34) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TPCREQUEST_MIN_LEN (0) + +#define DOT11F_IE_TPCREQUEST_MAX_LEN (0) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_tpc_request( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETPCRequest*, + bool); + +uint32_t dot11f_pack_ie_tpc_request( + tpAniSirGlobal, + tDot11fIETPCRequest *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TPCRequest( + tpAniSirGlobal, + tDot11fIETPCRequest *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 69 (0x45) */ +typedef struct sDot11fIETimeAdvertisement { + uint8_t present; + uint8_t timing_capabilities; + uint8_t time_value[10]; + uint8_t time_error[5]; +} tDot11fIETimeAdvertisement; + +#define DOT11F_EID_TIMEADVERTISEMENT (69) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIMEADVERTISEMENT_MIN_LEN (16) + +#define DOT11F_IE_TIMEADVERTISEMENT_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_time_advertisement( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETimeAdvertisement*, + bool); + +uint32_t dot11f_pack_ie_time_advertisement( + tpAniSirGlobal, + tDot11fIETimeAdvertisement *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_time_advertisement( + tpAniSirGlobal, + tDot11fIETimeAdvertisement *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 56 (0x38) */ +typedef struct sDot11fIETimeoutInterval { + uint8_t present; + uint8_t timeoutType; + uint32_t timeoutValue; +} tDot11fIETimeoutInterval; + +#define DOT11F_EID_TIMEOUTINTERVAL (56) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_TIMEOUTINTERVAL_MIN_LEN (5) + +#define DOT11F_IE_TIMEOUTINTERVAL_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_timeout_interval( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIETimeoutInterval*, + bool); + +uint32_t dot11f_pack_ie_timeout_interval( + tpAniSirGlobal, + tDot11fIETimeoutInterval *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_TimeoutInterval( + tpAniSirGlobal, + tDot11fIETimeoutInterval *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 193 (0xc1) */ +typedef struct sDot11fIEVHTExtBssLoad { + uint8_t present; + uint8_t muMIMOCapStaCount; + uint8_t ssUnderUtil; + uint8_t FortyMHzUtil; + uint8_t EightyMHzUtil; + uint8_t OneSixtyMHzUtil; +} tDot11fIEVHTExtBssLoad; + +#define DOT11F_EID_VHTEXTBSSLOAD (193) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VHTEXTBSSLOAD_MIN_LEN (5) + +#define DOT11F_IE_VHTEXTBSSLOAD_MAX_LEN (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vht_ext_bss_load( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVHTExtBssLoad*, + bool); + +uint32_t dot11f_pack_ie_vht_ext_bss_load( + tpAniSirGlobal, + tDot11fIEVHTExtBssLoad *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_VHTExtBssLoad( + tpAniSirGlobal, + tDot11fIEVHTExtBssLoad *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x10, 0x18} */ +typedef struct sDot11fIEVendor1IE { + uint8_t present; +} tDot11fIEVendor1IE; + +#define DOT11F_EID_VENDOR1IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR1IE_MIN_LEN (3) + +#define DOT11F_IE_VENDOR1IE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vendor1_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVendor1IE*, + bool); + +uint32_t dot11f_pack_ie_vendor1_ie( + tpAniSirGlobal, + tDot11fIEVendor1IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Vendor1IE( + tpAniSirGlobal, + tDot11fIEVendor1IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x16, 0x32} */ +typedef struct sDot11fIEVendor3IE { + uint8_t present; +} tDot11fIEVendor3IE; + +#define DOT11F_EID_VENDOR3IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR3IE_MIN_LEN (3) + +#define DOT11F_IE_VENDOR3IE_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vendor3_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEVendor3IE*, + bool); + +uint32_t dot11f_pack_ie_vendor3_ie( + tpAniSirGlobal, + tDot11fIEVendor3IE *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_Vendor3IE( + tpAniSirGlobal, + tDot11fIEVendor3IE *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 68 (0x44) */ +typedef struct sDot11fIEWAPI { + uint8_t present; + uint16_t version /* Must be 1! */; + uint16_t akm_suite_count; + uint8_t akm_suites[4][4]; + uint16_t unicast_cipher_suite_count; + uint8_t unicast_cipher_suites[4][4]; + uint8_t multicast_cipher_suite[4]; + uint16_t preauth:1; + uint16_t reserved:15; + uint16_t bkid_count; + uint8_t bkid[4][16]; +} tDot11fIEWAPI; + +#define DOT11F_EID_WAPI (68) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WAPI_MIN_LEN (12) + +#define DOT11F_IE_WAPI_MAX_LEN (110) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wapi( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWAPI*, + bool); + +uint32_t dot11f_pack_ie_wapi( + tpAniSirGlobal, + tDot11fIEWAPI *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewapi( + tpAniSirGlobal, + tDot11fIEWAPI *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 68 (0x44) */ +typedef struct sDot11fIEWAPIOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[253]; +} tDot11fIEWAPIOpaque; + +#define DOT11F_EID_WAPIOPAQUE (68) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WAPIOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WAPIOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wapi_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWAPIOpaque*, + bool); + +uint32_t dot11f_pack_ie_wapi_opaque( + tpAniSirGlobal, + tDot11fIEWAPIOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewapiOpaque( + tpAniSirGlobal, + tDot11fIEWAPIOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x08, 0x00} */ +typedef struct sDot11fIEWFATPC { + uint8_t present; + uint8_t txPower; + uint8_t linkMargin; +} tDot11fIEWFATPC; + +#define DOT11F_EID_WFATPC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WFATPC_MIN_LEN (7) + +#define DOT11F_IE_WFATPC_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wfatpc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWFATPC*, + bool); + +uint32_t dot11f_pack_ie_wfatpc( + tpAniSirGlobal, + tDot11fIEWFATPC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WFATPC( + tpAniSirGlobal, + tDot11fIEWFATPC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x0a} */ +typedef struct sDot11fIEWFDIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWFDIEOpaque; + +#define DOT11F_EID_WFDIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WFDIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WFDIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wfdie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWFDIEOpaque*, + bool); + +uint32_t dot11f_pack_ie_wfdie_opaque( + tpAniSirGlobal, + tDot11fIEWFDIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WFDIEOpaque( + tpAniSirGlobal, + tDot11fIEWFDIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x05} */ +typedef struct sDot11fIEWMMCaps { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t reserved:4; + uint8_t qack:1; + uint8_t queue_request:1; + uint8_t txop_request:1; + uint8_t more_ack:1; +} tDot11fIEWMMCaps; + +#define DOT11F_EID_WMMCAPS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMCAPS_MIN_LEN (7) + +#define DOT11F_IE_WMMCAPS_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmm_caps( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMCaps*, + bool); + +uint32_t dot11f_pack_ie_wmm_caps( + tpAniSirGlobal, + tDot11fIEWMMCaps *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMCaps( + tpAniSirGlobal, + tDot11fIEWMMCaps *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x00} */ +typedef struct sDot11fIEWMMInfoAp { + uint8_t present; + uint8_t version; + uint8_t param_set_count:4; + uint8_t reserved:3; + uint8_t uapsd:1; +} tDot11fIEWMMInfoAp; + +#define DOT11F_EID_WMMINFOAP (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMINFOAP_MIN_LEN (7) + +#define DOT11F_IE_WMMINFOAP_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmm_info_ap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMInfoAp*, + bool); + +uint32_t dot11f_pack_ie_wmm_info_ap( + tpAniSirGlobal, + tDot11fIEWMMInfoAp *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMInfoAp( + tpAniSirGlobal, + tDot11fIEWMMInfoAp *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x00} */ +typedef struct sDot11fIEWMMInfoStation { + uint8_t present; + uint8_t version; + uint8_t acvo_uapsd:1; + uint8_t acvi_uapsd:1; + uint8_t acbk_uapsd:1; + uint8_t acbe_uapsd:1; + uint8_t reserved1:1; + uint8_t max_sp_length:2; + uint8_t reserved2:1; +} tDot11fIEWMMInfoStation; + +#define DOT11F_EID_WMMINFOSTATION (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMINFOSTATION_MIN_LEN (7) + +#define DOT11F_IE_WMMINFOSTATION_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmm_info_station( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMInfoStation*, + bool); + +uint32_t dot11f_pack_ie_wmm_info_station( + tpAniSirGlobal, + tDot11fIEWMMInfoStation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMInfoStation( + tpAniSirGlobal, + tDot11fIEWMMInfoStation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x02, 0x01} */ +typedef struct sDot11fIEWMMParams { + uint8_t present; + uint8_t version /* Must be 1! */; + uint8_t qosInfo; + uint8_t reserved2; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint16_t acbe_txoplimit; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint16_t acbk_txoplimit; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint16_t acvi_txoplimit; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint16_t acvo_txoplimit; +} tDot11fIEWMMParams; + +#define DOT11F_EID_WMMPARAMS (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WMMPARAMS_MIN_LEN (24) + +#define DOT11F_IE_WMMPARAMS_MAX_LEN (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wmm_params( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWMMParams*, + bool); + +uint32_t dot11f_pack_ie_wmm_params( + tpAniSirGlobal, + tDot11fIEWMMParams *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WMMParams( + tpAniSirGlobal, + tDot11fIEWMMParams *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x01} */ +typedef struct sDot11fIEWPA { + uint8_t present; + uint16_t version /* Must be 1! */; + /* field added to fix the bug in dot11fPackIEWPA */ + uint8_t multicast_cipher_present; + uint8_t multicast_cipher[4]; + uint16_t unicast_cipher_count; + uint8_t unicast_ciphers[4][4]; + uint16_t auth_suite_count; + uint8_t auth_suites[4][4]; + uint16_t caps; +} tDot11fIEWPA; + +#define DOT11F_EID_WPA (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WPA_MIN_LEN (6) + +#define DOT11F_IE_WPA_MAX_LEN (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wpa( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWPA*, + bool); + +uint32_t dot11f_pack_ie_wpa( + tpAniSirGlobal, + tDot11fIEWPA *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewpa( + tpAniSirGlobal, + tDot11fIEWPA *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x01} */ +typedef struct sDot11fIEWPAOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWPAOpaque; + +#define DOT11F_EID_WPAOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WPAOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WPAOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wpa_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWPAOpaque*, + bool); + +uint32_t dot11f_pack_ie_wpa_opaque( + tpAniSirGlobal, + tDot11fIEWPAOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewpaOpaque( + tpAniSirGlobal, + tDot11fIEWPAOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWSC { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVUUID_R UUID_R; + tDot11fTLVRFBands RFBands; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVAssociationState AssociationState; + tDot11fTLVConfigurationError ConfigurationError; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVRequestType RequestType; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; + tDot11fTLVRequestDeviceType RequestDeviceType; +} tDot11fIEWSC; + +#define DOT11F_EID_WSC (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSC_MIN_LEN (4) + +#define DOT11F_IE_WSC_MAX_LEN (366) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWSC*, + bool); + +uint32_t dot11f_pack_ie_wsc( + tpAniSirGlobal, + tDot11fIEWSC *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_iewsc( + tpAniSirGlobal, + tDot11fIEWSC *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscAssocReq { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVRequestType RequestType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscAssocReq; + +#define DOT11F_EID_WSCASSOCREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCASSOCREQ_MIN_LEN (4) + +#define DOT11F_IE_WSCASSOCREQ_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_assoc_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscAssocReq*, + bool); + +uint32_t dot11f_pack_ie_wsc_assoc_req( + tpAniSirGlobal, + tDot11fIEWscAssocReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_assoc_req( + tpAniSirGlobal, + tDot11fIEWscAssocReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscAssocRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscAssocRes; + +#define DOT11F_EID_WSCASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_WSCASSOCRES_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_assoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscAssocRes*, + bool); + +uint32_t dot11f_pack_ie_wsc_assoc_res( + tpAniSirGlobal, + tDot11fIEWscAssocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_assoc_res( + tpAniSirGlobal, + tDot11fIEWscAssocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscBeacon { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscBeacon; + +#define DOT11F_EID_WSCBEACON (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCBEACON_MIN_LEN (4) + +#define DOT11F_IE_WSCBEACON_MAX_LEN (82) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_beacon( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscBeacon*, + bool); + +uint32_t dot11f_pack_ie_wsc_beacon( + tpAniSirGlobal, + tDot11fIEWscBeacon *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_beacon( + tpAniSirGlobal, + tDot11fIEWscBeacon *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscBeaconProbeRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVResponseType ResponseType; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscBeaconProbeRes; + +#define DOT11F_EID_WSCBEACONPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCBEACONPROBERES_MIN_LEN (4) + +#define DOT11F_IE_WSCBEACONPROBERES_MAX_LEN (317) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscBeaconProbeRes*, + bool); + +uint32_t dot11f_pack_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEWscBeaconProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_beacon_probe_res( + tpAniSirGlobal, + tDot11fIEWscBeaconProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} */ +typedef struct sDot11fIEWscIEOpaque { + uint8_t present; + uint8_t num_data; + uint8_t data[249]; +} tDot11fIEWscIEOpaque; + +#define DOT11F_EID_WSCIEOPAQUE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCIEOPAQUE_MIN_LEN (6) + +#define DOT11F_IE_WSCIEOPAQUE_MAX_LEN (253) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_ie_opaque( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscIEOpaque*, + bool); + +uint32_t dot11f_pack_ie_wsc_ie_opaque( + tpAniSirGlobal, + tDot11fIEWscIEOpaque *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_WscIEOpaque( + tpAniSirGlobal, + tDot11fIEWscIEOpaque *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscProbeReq { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVRequestType RequestType; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVRFBands RFBands; + tDot11fTLVAssociationState AssociationState; + tDot11fTLVConfigurationError ConfigurationError; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVVendorExtension VendorExtension; + tDot11fTLVRequestDeviceType RequestDeviceType; +} tDot11fIEWscProbeReq; + +#define DOT11F_EID_WSCPROBEREQ (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCPROBEREQ_MIN_LEN (4) + +#define DOT11F_IE_WSCPROBEREQ_MAX_LEN (284) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_probe_req( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscProbeReq*, + bool); + +uint32_t dot11f_pack_ie_wsc_probe_req( + tpAniSirGlobal, + tDot11fIEWscProbeReq *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_probe_req( + tpAniSirGlobal, + tDot11fIEWscProbeReq *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscProbeRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVWPSState WPSState; + tDot11fTLVAPSetupLocked APSetupLocked; + tDot11fTLVSelectedRegistrar SelectedRegistrar; + tDot11fTLVDevicePasswordID DevicePasswordID; + tDot11fTLVSelectedRegistrarConfigMethods SelectedRegistrarConfigMethods; + tDot11fTLVResponseType ResponseType; + tDot11fTLVUUID_E UUID_E; + tDot11fTLVManufacturer Manufacturer; + tDot11fTLVModelName ModelName; + tDot11fTLVModelNumber ModelNumber; + tDot11fTLVSerialNumber SerialNumber; + tDot11fTLVPrimaryDeviceType PrimaryDeviceType; + tDot11fTLVDeviceName DeviceName; + tDot11fTLVConfigMethods ConfigMethods; + tDot11fTLVRFBands RFBands; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscProbeRes; + +#define DOT11F_EID_WSCPROBERES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCPROBERES_MIN_LEN (4) + +#define DOT11F_IE_WSCPROBERES_MAX_LEN (317) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_probe_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscProbeRes*, + bool); + +uint32_t dot11f_pack_ie_wsc_probe_res( + tpAniSirGlobal, + tDot11fIEWscProbeRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_probe_res( + tpAniSirGlobal, + tDot11fIEWscProbeRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x50, 0xf2, 0x04} (Multi-IE) */ +typedef struct sDot11fIEWscReassocRes { + uint8_t present; + tDot11fTLVVersion Version; + tDot11fTLVResponseType ResponseType; + tDot11fTLVVendorExtension VendorExtension; +} tDot11fIEWscReassocRes; + +#define DOT11F_EID_WSCREASSOCRES (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_WSCREASSOCRES_MIN_LEN (4) + +#define DOT11F_IE_WSCREASSOCRES_MAX_LEN (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_wsc_reassoc_res( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEWscReassocRes*, + bool); + +uint32_t dot11f_pack_ie_wsc_reassoc_res( + tpAniSirGlobal, + tDot11fIEWscReassocRes *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_wsc_reassoc_res( + tpAniSirGlobal, + tDot11fIEWscReassocRes *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 159 (0x9f) */ +typedef struct sDot11fIEaddba_extn_element { + uint8_t present; + uint8_t no_fragmentation:1; + uint8_t he_frag_operation:2; + uint8_t reserved:2; + uint8_t extd_buff_size:3; +} tDot11fIEaddba_extn_element; + +#define DOT11F_EID_ADDBA_EXTN_ELEMENT (159) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ADDBA_EXTN_ELEMENT_MIN_LEN (1) + +#define DOT11F_IE_ADDBA_EXTN_ELEMENT_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_addba_extn_element( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEaddba_extn_element*, + bool); + +uint32_t dot11f_pack_ie_addba_extn_element( + tpAniSirGlobal, + tDot11fIEaddba_extn_element *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_addba_extn_element( + tpAniSirGlobal, + tDot11fIEaddba_extn_element *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 42 (0x2a) */ +typedef struct sDot11fIEbss_color_change { + uint8_t present; + uint8_t countdown; + uint8_t new_color:6; + uint8_t reserved:2; +} tDot11fIEbss_color_change; + +#define DOT11F_EID_BSS_COLOR_CHANGE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BSS_COLOR_CHANGE_MIN_LEN (2) + +#define DOT11F_IE_BSS_COLOR_CHANGE_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_bss_color_change( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEbss_color_change*, + bool); + +uint32_t dot11f_pack_ie_bss_color_change( + tpAniSirGlobal, + tDot11fIEbss_color_change *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_bss_color_change( + tpAniSirGlobal, + tDot11fIEbss_color_change *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 90 (0x5a) */ +typedef struct sDot11fIEbss_max_idle_period { + uint8_t present; + uint16_t max_idle_period; + uint8_t prot_keep_alive_reqd:1; + uint8_t reserved:7; +} tDot11fIEbss_max_idle_period; + +#define DOT11F_EID_BSS_MAX_IDLE_PERIOD (90) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_BSS_MAX_IDLE_PERIOD_MIN_LEN (3) + +#define DOT11F_IE_BSS_MAX_IDLE_PERIOD_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_bss_max_idle_period( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEbss_max_idle_period*, + bool); + +uint32_t dot11f_pack_ie_bss_max_idle_period( + tpAniSirGlobal, + tDot11fIEbss_max_idle_period *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_bss_max_idle_period( + tpAniSirGlobal, + tDot11fIEbss_max_idle_period *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 88 (0x58) */ +typedef struct sDot11fIEdescriptor_element { + uint8_t present; + uint8_t request_type; + uint16_t user_priority_control; + uint32_t stream_timeout; + tDot11fIEtclas_mask tclas_mask; + tDot11fIEmscs_status mscs_status; +} tDot11fIEdescriptor_element; + +#define DOT11F_EID_DESCRIPTOR_ELEMENT (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_DESCRIPTOR_ELEMENT_MIN_LEN (7) + +#define DOT11F_IE_DESCRIPTOR_ELEMENT_MAX_LEN (30) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_descriptor_element( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEdescriptor_element*, + bool); + +uint32_t dot11f_pack_ie_descriptor_element( + tpAniSirGlobal, + tDot11fIEdescriptor_element *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_descriptor_element( + tpAniSirGlobal, + tDot11fIEdescriptor_element *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 32 (0x20) */ +typedef struct sDot11fIEdh_parameter_element { + uint8_t present; + uint8_t group[2]; + uint8_t num_public_key; + uint8_t public_key[255]; +} tDot11fIEdh_parameter_element; + +#define DOT11F_EID_DH_PARAMETER_ELEMENT (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_DH_PARAMETER_ELEMENT_MIN_LEN (2) + +#define DOT11F_IE_DH_PARAMETER_ELEMENT_MAX_LEN (257) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_dh_parameter_element( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEdh_parameter_element*, + bool); + +uint32_t dot11f_pack_ie_dh_parameter_element( + tpAniSirGlobal, + tDot11fIEdh_parameter_element *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_dh_parameter_element( + tpAniSirGlobal, + tDot11fIEdh_parameter_element *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 108 (0x6c) */ +typedef struct sDot11fIEeht_cap { + uint8_t present; + uint16_t epcs_pri_access:1; + uint16_t eht_om_ctl:1; + uint16_t triggered_txop_sharing_mode1:1; + uint16_t triggered_txop_sharing_mode2:1; + uint16_t restricted_twt:1; + uint16_t scs_traffic_desc:1; + uint16_t max_mpdu_len:2; + uint16_t max_a_mpdu_len_exponent_ext:1; + uint16_t eht_trs_support:1; + uint16_t txop_return_support_txop_share_m2:1; + uint16_t two_bqrs_support:1; + uint16_t eht_link_adaptation_support:2; + uint16_t reserved:2; + uint32_t reserved2:1; + uint32_t support_320mhz_6ghz:1; + uint32_t ru_242tone_wt_20mhz:1; + uint32_t ndp_4x_eht_ltf_3dot2_us_gi:1; + uint32_t partial_bw_mu_mimo:1; + uint32_t su_beamformer:1; + uint32_t su_beamformee:1; + uint32_t bfee_ss_le_80mhz:3; + uint32_t bfee_ss_160mhz:3; + uint32_t bfee_ss_320mhz:3; + uint32_t num_sounding_dim_le_80mhz:3; + uint32_t num_sounding_dim_160mhz:3; + uint32_t num_sounding_dim_320mhz:3; + uint32_t ng_16_su_feedback:1; + uint32_t ng_16_mu_feedback:1; + uint32_t cb_sz_4_2_su_feedback:1; + uint32_t cb_sz_7_5_su_feedback:1; + uint32_t trig_su_bforming_feedback:1; + uint32_t trig_mu_bforming_partial_bw_feedback:1; + uint32_t triggered_cqi_feedback:1; + uint32_t partial_bw_dl_mu_mimo:1; + uint32_t psr_based_sr:1; + uint32_t power_boost_factor:1; + uint32_t eht_mu_ppdu_4x_ltf_0_8_us_gi:1; + uint32_t max_nc:4; + uint32_t non_trig_cqi_feedback:1; + uint32_t tx_1024_4096_qam_lt_242_tone_ru:1; + uint32_t rx_1024_4096_qam_lt_242_tone_ru:1; + uint32_t ppet_present:1; + uint32_t common_nominal_pkt_padding:2; + uint32_t max_num_eht_ltf:5; + uint32_t mcs_15:4; + uint32_t eht_dup_6ghz:1; + uint32_t op_sta_rx_ndp_wider_bw_20mhz:1; + uint32_t non_ofdma_ul_mu_mimo_le_80mhz:1; + uint32_t non_ofdma_ul_mu_mimo_160mhz:1; + uint32_t non_ofdma_ul_mu_mimo_320mhz:1; + uint32_t mu_bformer_le_80mhz:1; + uint32_t mu_bformer_160mhz:1; + uint32_t mu_bformer_320mhz:1; + uint32_t tb_sounding_feedback_rl:1; + uint8_t rx_1k_qam_in_wider_bw_dl_ofdma:1; + uint8_t rx_4k_qam_in_wider_bw_dl_ofdma:1; + uint8_t limited_cap_support_20mhz:1; + uint8_t triggered_mu_bf_full_bw_fb_and_dl_mumimo:1; + uint8_t mru_support_20mhz:1; + uint8_t reserved3:3; + uint32_t bw_20_rx_max_nss_for_mcs_0_to_7:4; + uint32_t bw_20_tx_max_nss_for_mcs_0_to_7:4; + uint32_t bw_20_rx_max_nss_for_mcs_8_and_9:4; + uint32_t bw_20_tx_max_nss_for_mcs_8_and_9:4; + uint32_t bw_20_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_20_tx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_20_rx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_20_tx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_le_80_rx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_le_80_tx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_le_80_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_le_80_tx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_le_80_rx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_le_80_tx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_160_rx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_160_tx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_160_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_160_tx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_160_rx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_160_tx_max_nss_for_mcs_12_and_13:4; + uint32_t bw_320_rx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_320_tx_max_nss_for_mcs_0_to_9:4; + uint32_t bw_320_rx_max_nss_for_mcs_10_and_11:4; + uint32_t bw_320_tx_max_nss_for_mcs_10_and_11:4; + uint8_t bw_320_rx_max_nss_for_mcs_12_and_13:4; + uint8_t bw_320_tx_max_nss_for_mcs_12_and_13:4; + union { + struct { + uint8_t num_ppe_th; + uint8_t ppe_th[62]; + } ppe_threshold; /* ppet_present = 1 */ + } ppet; +} tDot11fIEeht_cap; + +#define DOT11F_EID_EHT_CAP (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EHT_CAP_MIN_LEN (24) + +#define DOT11F_IE_EHT_CAP_MAX_LEN (86) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_eht_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEeht_cap*, + bool); + +uint32_t dot11f_pack_ie_eht_cap( + tpAniSirGlobal, + tDot11fIEeht_cap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_eht_cap( + tpAniSirGlobal, + tDot11fIEeht_cap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 106 (0x6a) */ +typedef struct sDot11fIEeht_op { + uint8_t present; + uint8_t eht_op_information_present:1; + uint8_t disabled_sub_chan_bitmap_present:1; + uint8_t eht_default_pe_duration:1; + uint8_t group_addr_bu_indication_limit:1; + uint8_t group_addr_bu_indication_exponent:2; + uint8_t reserved:2; + uint32_t basic_rx_max_nss_for_mcs_0_to_7:4; + uint32_t basic_tx_max_nss_for_mcs_0_to_7:4; + uint32_t basic_rx_max_nss_for_mcs_8_and_9:4; + uint32_t basic_tx_max_nss_for_mcs_8_and_9:4; + uint32_t basic_rx_max_nss_for_mcs_10_and_11:4; + uint32_t basic_tx_max_nss_for_mcs_10_and_11:4; + uint32_t basic_rx_max_nss_for_mcs_12_and_13:4; + uint32_t basic_tx_max_nss_for_mcs_12_and_13:4; + uint8_t channel_width:3; + uint8_t reserved_1:5; + uint8_t ccfs0; + uint8_t ccfs1; + uint8_t disabled_sub_chan_bitmap[1][2]; +} tDot11fIEeht_op; + +#define DOT11F_EID_EHT_OP (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EHT_OP_MIN_LEN (8) + +#define DOT11F_IE_EHT_OP_MAX_LEN (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_eht_op( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEeht_op*, + bool); + +uint32_t dot11f_pack_ie_eht_op( + tpAniSirGlobal, + tDot11fIEeht_op *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_eht_op( + tpAniSirGlobal, + tDot11fIEeht_op *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 11 (0x0b) */ +typedef struct sDot11fIEesp_information { + uint8_t present; + uint8_t num_data; + uint8_t data[96]; +} tDot11fIEesp_information; + +#define DOT11F_EID_ESP_INFORMATION (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ESP_INFORMATION_MIN_LEN (0) + +#define DOT11F_IE_ESP_INFORMATION_MAX_LEN (96) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_esp_information( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEesp_information*, + bool); + +uint32_t dot11f_pack_ie_esp_information( + tpAniSirGlobal, + tDot11fIEesp_information *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_esp_information( + tpAniSirGlobal, + tDot11fIEesp_information *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 60 (0x3c) */ +typedef struct sDot11fIEext_chan_switch_ann { + uint8_t present; + uint8_t switch_mode; + uint8_t new_reg_class; + uint8_t new_channel; + uint8_t switch_count; +} tDot11fIEext_chan_switch_ann; + +#define DOT11F_EID_EXT_CHAN_SWITCH_ANN (60) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_EXT_CHAN_SWITCH_ANN_MIN_LEN (4) + +#define DOT11F_IE_EXT_CHAN_SWITCH_ANN_MAX_LEN (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ext_chan_switch_ann( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEext_chan_switch_ann*, + bool); + +uint32_t dot11f_pack_ie_ext_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEext_chan_switch_ann *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ext_chan_switch_ann( + tpAniSirGlobal, + tDot11fIEext_chan_switch_ann *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 1 (0x01) */ +typedef struct sDot11fIEfils_assoc_delay_info { + uint8_t present; + uint8_t assoc_delay_info; +} tDot11fIEfils_assoc_delay_info; + +#define DOT11F_EID_FILS_ASSOC_DELAY_INFO (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_ASSOC_DELAY_INFO_MIN_LEN (1) + +#define DOT11F_IE_FILS_ASSOC_DELAY_INFO_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_assoc_delay_info( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_assoc_delay_info*, + bool); + +uint32_t dot11f_pack_ie_fils_assoc_delay_info( + tpAniSirGlobal, + tDot11fIEfils_assoc_delay_info *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_assoc_delay_info( + tpAniSirGlobal, + tDot11fIEfils_assoc_delay_info *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 5 (0x05) */ +typedef struct sDot11fIEfils_hlp_container { + uint8_t present; + uint8_t dest_mac[6]; + uint8_t src_mac[6]; + uint8_t num_hlp_packet; + uint8_t hlp_packet[255]; +} tDot11fIEfils_hlp_container; + +#define DOT11F_EID_FILS_HLP_CONTAINER (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_HLP_CONTAINER_MIN_LEN (12) + +#define DOT11F_IE_FILS_HLP_CONTAINER_MAX_LEN (267) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_hlp_container( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_hlp_container*, + bool); + +uint32_t dot11f_pack_ie_fils_hlp_container( + tpAniSirGlobal, + tDot11fIEfils_hlp_container *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_hlp_container( + tpAniSirGlobal, + tDot11fIEfils_hlp_container *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 240 (0xf0) */ +typedef struct sDot11fIEfils_indication { + uint8_t present; + uint16_t public_key_identifiers_cnt:3; + uint16_t realm_identifiers_cnt:3; + uint16_t is_ip_config_supported:1; + uint16_t is_cache_id_present:1; + uint16_t is_hessid_present:1; + uint16_t is_fils_sk_auth_supported:1; + uint16_t is_fils_sk_auth_pfs_supported:1; + uint16_t is_pk_auth_supported:1; + uint16_t reserved:4; + uint8_t num_variable_data; + uint8_t variable_data[255]; +} tDot11fIEfils_indication; + +#define DOT11F_EID_FILS_INDICATION (240) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_INDICATION_MIN_LEN (4) + +#define DOT11F_IE_FILS_INDICATION_MAX_LEN (257) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_indication( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_indication*, + bool); + +uint32_t dot11f_pack_ie_fils_indication( + tpAniSirGlobal, + tDot11fIEfils_indication *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_indication( + tpAniSirGlobal, + tDot11fIEfils_indication *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 7 (0x07) */ +typedef struct sDot11fIEfils_kde { + uint8_t present; + uint8_t key_rsc[8]; + uint8_t num_kde_list; + uint8_t kde_list[255]; +} tDot11fIEfils_kde; + +#define DOT11F_EID_FILS_KDE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_KDE_MIN_LEN (8) + +#define DOT11F_IE_FILS_KDE_MAX_LEN (263) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_kde( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_kde*, + bool); + +uint32_t dot11f_pack_ie_fils_kde( + tpAniSirGlobal, + tDot11fIEfils_kde *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_kde( + tpAniSirGlobal, + tDot11fIEfils_kde *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 3 (0x03) */ +typedef struct sDot11fIEfils_key_confirmation { + uint8_t present; + uint8_t num_key_auth; + uint8_t key_auth[255]; +} tDot11fIEfils_key_confirmation; + +#define DOT11F_EID_FILS_KEY_CONFIRMATION (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_KEY_CONFIRMATION_MIN_LEN (0) + +#define DOT11F_IE_FILS_KEY_CONFIRMATION_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_key_confirmation( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_key_confirmation*, + bool); + +uint32_t dot11f_pack_ie_fils_key_confirmation( + tpAniSirGlobal, + tDot11fIEfils_key_confirmation *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_key_confirmation( + tpAniSirGlobal, + tDot11fIEfils_key_confirmation *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 13 (0x0d) */ +typedef struct sDot11fIEfils_nonce { + uint8_t present; + uint8_t nonce[16]; +} tDot11fIEfils_nonce; + +#define DOT11F_EID_FILS_NONCE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_NONCE_MIN_LEN (16) + +#define DOT11F_IE_FILS_NONCE_MAX_LEN (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_nonce( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_nonce*, + bool); + +uint32_t dot11f_pack_ie_fils_nonce( + tpAniSirGlobal, + tDot11fIEfils_nonce *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_nonce( + tpAniSirGlobal, + tDot11fIEfils_nonce *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 12 (0x0c) */ +typedef struct sDot11fIEfils_public_key { + uint8_t present; + uint8_t key_type; + uint8_t num_public_key; + uint8_t public_key[255]; +} tDot11fIEfils_public_key; + +#define DOT11F_EID_FILS_PUBLIC_KEY (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_PUBLIC_KEY_MIN_LEN (1) + +#define DOT11F_IE_FILS_PUBLIC_KEY_MAX_LEN (256) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_public_key( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_public_key*, + bool); + +uint32_t dot11f_pack_ie_fils_public_key( + tpAniSirGlobal, + tDot11fIEfils_public_key *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_public_key( + tpAniSirGlobal, + tDot11fIEfils_public_key *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 4 (0x04) */ +typedef struct sDot11fIEfils_session { + uint8_t present; + uint8_t session[8]; +} tDot11fIEfils_session; + +#define DOT11F_EID_FILS_SESSION (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_SESSION_MIN_LEN (8) + +#define DOT11F_IE_FILS_SESSION_MAX_LEN (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_session( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_session*, + bool); + +uint32_t dot11f_pack_ie_fils_session( + tpAniSirGlobal, + tDot11fIEfils_session *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_session( + tpAniSirGlobal, + tDot11fIEfils_session *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 8 (0x08) */ +typedef struct sDot11fIEfils_wrapped_data { + uint8_t present; + uint8_t num_wrapped_data; + uint8_t wrapped_data[255]; +} tDot11fIEfils_wrapped_data; + +#define DOT11F_EID_FILS_WRAPPED_DATA (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FILS_WRAPPED_DATA_MIN_LEN (0) + +#define DOT11F_IE_FILS_WRAPPED_DATA_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fils_wrapped_data( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfils_wrapped_data*, + bool); + +uint32_t dot11f_pack_ie_fils_wrapped_data( + tpAniSirGlobal, + tDot11fIEfils_wrapped_data *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fils_wrapped_data( + tpAniSirGlobal, + tDot11fIEfils_wrapped_data *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 242 (0xf2) */ +typedef struct sDot11fIEfragment_ie { + uint8_t present; + uint8_t num_data; + uint8_t data[255]; +} tDot11fIEfragment_ie; + +#define DOT11F_EID_FRAGMENT_IE (242) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_FRAGMENT_IE_MIN_LEN (0) + +#define DOT11F_IE_FRAGMENT_IE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_fragment_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEfragment_ie*, + bool); + +uint32_t dot11f_pack_ie_fragment_ie( + tpAniSirGlobal, + tDot11fIEfragment_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_fragment_ie( + tpAniSirGlobal, + tDot11fIEfragment_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 59 (0x3b) */ +typedef struct sDot11fIEhe_6ghz_band_cap { + uint8_t present; + uint16_t min_mpdu_start_spacing:3; + uint16_t max_ampdu_len_exp:3; + uint16_t max_mpdu_len:3; + uint16_t sm_pow_save:2; + uint16_t rd_responder:1; + uint16_t rx_ant_pattern_consistency:1; + uint16_t tx_ant_pattern_consistency:1; + uint16_t reserved:2; +} tDot11fIEhe_6ghz_band_cap; + +#define DOT11F_EID_HE_6GHZ_BAND_CAP (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HE_6GHZ_BAND_CAP_MIN_LEN (2) + +#define DOT11F_IE_HE_6GHZ_BAND_CAP_MAX_LEN (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_he_6ghz_band_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEhe_6ghz_band_cap*, + bool); + +uint32_t dot11f_pack_ie_he_6ghz_band_cap( + tpAniSirGlobal, + tDot11fIEhe_6ghz_band_cap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_he_6ghz_band_cap( + tpAniSirGlobal, + tDot11fIEhe_6ghz_band_cap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 35 (0x23) */ +typedef struct sDot11fIEhe_cap { + uint8_t present; + uint32_t htc_he:1; + uint32_t twt_request:1; + uint32_t twt_responder:1; + uint32_t fragmentation:2; + uint32_t max_num_frag_msdu_amsdu_exp:3; + uint32_t min_frag_size:2; + uint32_t trigger_frm_mac_pad:2; + uint32_t multi_tid_aggr_rx_supp:3; + uint32_t he_link_adaptation:2; + uint32_t all_ack:1; + uint32_t trigd_rsp_sched:1; + uint32_t a_bsr:1; + uint32_t broadcast_twt:1; + uint32_t ba_32bit_bitmap:1; + uint32_t mu_cascade:1; + uint32_t ack_enabled_multitid:1; + uint32_t reserved:1; + uint32_t omi_a_ctrl:1; + uint32_t ofdma_ra:1; + uint32_t max_ampdu_len_exp_ext:2; + uint32_t amsdu_frag:1; + uint32_t flex_twt_sched:1; + uint32_t rx_ctrl_frame:1; + uint16_t bsrp_ampdu_aggr:1; + uint16_t qtp:1; + uint16_t a_bqr:1; + uint16_t spatial_reuse_param_rspder:1; + uint16_t ndp_feedback_supp:1; + uint16_t ops_supp:1; + uint16_t amsdu_in_ampdu:1; + uint16_t multi_tid_aggr_tx_supp:3; + uint16_t he_sub_ch_sel_tx_supp:1; + uint16_t ul_2x996_tone_ru_supp:1; + uint16_t om_ctrl_ul_mu_data_dis_rx:1; + uint16_t he_dynamic_smps:1; + uint16_t punctured_sounding_supp:1; + uint16_t ht_vht_trg_frm_rx_supp:1; + uint32_t reserved2:1; + uint32_t chan_width_0:1; + uint32_t chan_width_1:1; + uint32_t chan_width_2:1; + uint32_t chan_width_3:1; + uint32_t chan_width_4:1; + uint32_t chan_width_5:1; + uint32_t chan_width_6:1; + uint32_t rx_pream_puncturing:4; + uint32_t device_class:1; + uint32_t ldpc_coding:1; + uint32_t he_1x_ltf_800_gi_ppdu:1; + uint32_t midamble_tx_rx_max_nsts:2; + uint32_t he_4x_ltf_3200_gi_ndp:1; + uint32_t tb_ppdu_tx_stbc_lt_80mhz:1; + uint32_t rx_stbc_lt_80mhz:1; + uint32_t doppler:2; + uint32_t ul_mu:2; + uint32_t dcm_enc_tx:3; + uint32_t dcm_enc_rx:3; + uint32_t ul_he_mu:1; + uint32_t su_beamformer:1; + uint32_t su_beamformee:1; + uint32_t mu_beamformer:1; + uint32_t bfee_sts_lt_80:3; + uint32_t bfee_sts_gt_80:3; + uint32_t num_sounding_lt_80:3; + uint32_t num_sounding_gt_80:3; + uint32_t su_feedback_tone16:1; + uint32_t mu_feedback_tone16:1; + uint32_t codebook_su:1; + uint32_t codebook_mu:1; + uint32_t beamforming_feedback:3; + uint32_t he_er_su_ppdu:1; + uint32_t dl_mu_mimo_part_bw:1; + uint32_t ppet_present:1; + uint32_t srp:1; + uint32_t power_boost:1; + uint32_t he_ltf_800_gi_4x:1; + uint32_t max_nc:3; + uint32_t tb_ppdu_tx_stbc_gt_80mhz:1; + uint32_t rx_stbc_gt_80mhz:1; + uint16_t er_he_ltf_800_gi_4x:1; + uint16_t he_ppdu_20_in_40Mhz_2G:1; + uint16_t he_ppdu_20_in_160_80p80Mhz:1; + uint16_t he_ppdu_80_in_160_80p80Mhz:1; + uint16_t er_1x_he_ltf_gi:1; + uint16_t midamble_tx_rx_1x_he_ltf:1; + uint16_t dcm_max_bw:2; + uint16_t longer_than_16_he_sigb_ofdm_sym:1; + uint16_t non_trig_cqi_feedback:1; + uint16_t tx_1024_qam_lt_242_tone_ru:1; + uint16_t rx_1024_qam_lt_242_tone_ru:1; + uint16_t rx_full_bw_su_he_mu_compress_sigb:1; + uint16_t rx_full_bw_su_he_mu_non_cmpr_sigb:1; + uint16_t reserved3:2; + uint8_t reserved4; + uint16_t rx_he_mcs_map_lt_80; + uint16_t tx_he_mcs_map_lt_80; + uint8_t rx_he_mcs_map_160[1][2]; + uint8_t tx_he_mcs_map_160[1][2]; + uint8_t rx_he_mcs_map_80_80[1][2]; + uint8_t tx_he_mcs_map_80_80[1][2]; + union { + struct { + uint8_t num_ppe_th; + uint8_t ppe_th[25]; + } ppe_threshold; /* ppet_present = 1 */ + } ppet; +} tDot11fIEhe_cap; + +#define DOT11F_EID_HE_CAP (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HE_CAP_MIN_LEN (21) + +#define DOT11F_IE_HE_CAP_MAX_LEN (54) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_he_cap( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEhe_cap*, + bool); + +uint32_t dot11f_pack_ie_he_cap( + tpAniSirGlobal, + tDot11fIEhe_cap *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_he_cap( + tpAniSirGlobal, + tDot11fIEhe_cap *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 36 (0x24) */ +typedef struct sDot11fIEhe_op { + uint8_t present; + uint16_t default_pe:3; + uint16_t twt_required:1; + uint16_t txop_rts_threshold:10; + uint16_t vht_oper_present:1; + uint16_t co_located_bss:1; + uint8_t er_su_disable:1; + uint8_t oper_info_6g_present:1; + uint8_t reserved2:6; + uint8_t bss_color:6; + uint8_t partial_bss_col:1; + uint8_t bss_col_disabled:1; + uint8_t basic_mcs_nss[2]; + union { + struct { + uint8_t chan_width; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + } info; /* vht_oper_present = 1 */ + } vht_oper; + union { + struct { + uint8_t data; + } info; /* co_located_bss = 1 */ + } maxbssid_ind; + union { + struct { + uint8_t primary_ch; + uint8_t ch_width:2; + uint8_t dup_bcon:1; + uint8_t reg_info:3; + uint8_t reserved:2; + uint8_t center_freq_seg0; + uint8_t center_freq_seg1; + uint8_t min_rate; + } info; /* oper_info_6g_present = 1 */ + } oper_info_6g; +} tDot11fIEhe_op; + +#define DOT11F_EID_HE_OP (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HE_OP_MIN_LEN (6) + +#define DOT11F_IE_HE_OP_MAX_LEN (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_he_op( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEhe_op*, + bool); + +uint32_t dot11f_pack_ie_he_op( + tpAniSirGlobal, + tDot11fIEhe_op *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_he_op( + tpAniSirGlobal, + tDot11fIEhe_op *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x10} */ +typedef struct sDot11fIEhs20vendor_ie { + uint8_t present; + uint8_t dgaf_dis:1; + uint8_t hs_id_present:2; + uint8_t reserved:1; + uint8_t release_num:4; + union { + struct { + uint16_t pps_mo_id; + } pps_mo; /* hs_id_present = 1 */ + struct { + uint16_t anqp_domain_id; + } anqp_domain; /* hs_id_present = 2 */ + } hs_id; +} tDot11fIEhs20vendor_ie; + +#define DOT11F_EID_HS20VENDOR_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HS20VENDOR_IE_MIN_LEN (5) + +#define DOT11F_IE_HS20VENDOR_IE_MAX_LEN (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_hs20vendor_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEhs20vendor_ie*, + bool); + +uint32_t dot11f_pack_ie_hs20vendor_ie( + tpAniSirGlobal, + tDot11fIEhs20vendor_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_hs20vendor_ie( + tpAniSirGlobal, + tDot11fIEhs20vendor_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 72 (0x48) */ +typedef struct sDot11fIEht2040_bss_coexistence { + uint8_t present; + uint8_t info_request:1; + uint8_t forty_mhz_intolerant:1; + uint8_t twenty_mhz_bsswidth_req:1; + uint8_t obss_scan_exemption_req:1; + uint8_t obss_scan_exemption_grant:1; + uint8_t unused:3; +} tDot11fIEht2040_bss_coexistence; + +#define DOT11F_EID_HT2040_BSS_COEXISTENCE (72) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HT2040_BSS_COEXISTENCE_MIN_LEN (1) + +#define DOT11F_IE_HT2040_BSS_COEXISTENCE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEht2040_bss_coexistence*, + bool); + +uint32_t dot11f_pack_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + tDot11fIEht2040_bss_coexistence *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ht2040_bss_coexistence( + tpAniSirGlobal, + tDot11fIEht2040_bss_coexistence *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 73 (0x49) */ +typedef struct sDot11fIEht2040_bss_intolerant_report { + uint8_t present; + uint8_t operating_class; + uint8_t num_channel_list; + uint8_t channel_list[50]; +} tDot11fIEht2040_bss_intolerant_report; + +#define DOT11F_EID_HT2040_BSS_INTOLERANT_REPORT (73) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_HT2040_BSS_INTOLERANT_REPORT_MIN_LEN (1) + +#define DOT11F_IE_HT2040_BSS_INTOLERANT_REPORT_MAX_LEN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEht2040_bss_intolerant_report*, + bool); + +uint32_t dot11f_pack_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + tDot11fIEht2040_bss_intolerant_report *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_ht2040_bss_intolerant_report( + tpAniSirGlobal, + tDot11fIEht2040_bss_intolerant_report *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 52 (0x34) */ +typedef struct sDot11fIEmax_chan_switch_time { + uint8_t present; + uint8_t switch_time[3]; +} tDot11fIEmax_chan_switch_time; + +#define DOT11F_EID_MAX_CHAN_SWITCH_TIME (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MAX_CHAN_SWITCH_TIME_MIN_LEN (3) + +#define DOT11F_IE_MAX_CHAN_SWITCH_TIME_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_max_chan_switch_time( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEmax_chan_switch_time*, + bool); + +uint32_t dot11f_pack_ie_max_chan_switch_time( + tpAniSirGlobal, + tDot11fIEmax_chan_switch_time *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_max_chan_switch_time( + tpAniSirGlobal, + tDot11fIEmax_chan_switch_time *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 107 (0x6b) */ +typedef struct sDot11fIEmlo_ie { + uint8_t present; + uint8_t num_data; + uint8_t data[255]; +} tDot11fIEmlo_ie; + +#define DOT11F_EID_MLO_IE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MLO_IE_MIN_LEN (9) + +#define DOT11F_IE_MLO_IE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_mlo_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEmlo_ie*, + bool); + +uint32_t dot11f_pack_ie_mlo_ie( + tpAniSirGlobal, + tDot11fIEmlo_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_mlo_ie( + tpAniSirGlobal, + tDot11fIEmlo_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 38 (0x26) */ +typedef struct sDot11fIEmu_edca_param_set { + uint8_t present; + uint8_t qos; + uint8_t acbe_aifsn:4; + uint8_t acbe_acm:1; + uint8_t acbe_aci:2; + uint8_t unused1:1; + uint8_t acbe_acwmin:4; + uint8_t acbe_acwmax:4; + uint8_t acbe_muedca_timer; + uint8_t acbk_aifsn:4; + uint8_t acbk_acm:1; + uint8_t acbk_aci:2; + uint8_t unused2:1; + uint8_t acbk_acwmin:4; + uint8_t acbk_acwmax:4; + uint8_t acbk_muedca_timer; + uint8_t acvi_aifsn:4; + uint8_t acvi_acm:1; + uint8_t acvi_aci:2; + uint8_t unused3:1; + uint8_t acvi_acwmin:4; + uint8_t acvi_acwmax:4; + uint8_t acvi_muedca_timer; + uint8_t acvo_aifsn:4; + uint8_t acvo_acm:1; + uint8_t acvo_aci:2; + uint8_t unused4:1; + uint8_t acvo_acwmin:4; + uint8_t acvo_acwmax:4; + uint8_t acvo_muedca_timer; +} tDot11fIEmu_edca_param_set; + +#define DOT11F_EID_MU_EDCA_PARAM_SET (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_MU_EDCA_PARAM_SET_MIN_LEN (13) + +#define DOT11F_IE_MU_EDCA_PARAM_SET_MAX_LEN (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_mu_edca_param_set( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEmu_edca_param_set*, + bool); + +uint32_t dot11f_pack_ie_mu_edca_param_set( + tpAniSirGlobal, + tDot11fIEmu_edca_param_set *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_mu_edca_param_set( + tpAniSirGlobal, + tDot11fIEmu_edca_param_set *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 56 (0x38) */ +typedef struct sDot11fIEnon_inheritance { + uint8_t present; + uint8_t num_data; + uint8_t data[255]; +} tDot11fIEnon_inheritance; + +#define DOT11F_EID_NON_INHERITANCE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_NON_INHERITANCE_MIN_LEN (0) + +#define DOT11F_IE_NON_INHERITANCE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_non_inheritance( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEnon_inheritance*, + bool); + +uint32_t dot11f_pack_ie_non_inheritance( + tpAniSirGlobal, + tDot11fIEnon_inheritance *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_non_inheritance( + tpAniSirGlobal, + tDot11fIEnon_inheritance *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 54 (0x36) */ +typedef struct sDot11fIEoci { + uint8_t present; + uint8_t op_class; + uint8_t prim_ch_num; + uint8_t freq_seg_1_ch_num; +} tDot11fIEoci; + +#define DOT11F_EID_OCI (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OCI_MIN_LEN (3) + +#define DOT11F_IE_OCI_MAX_LEN (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_oci( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEoci*, + bool); + +uint32_t dot11f_pack_ie_oci( + tpAniSirGlobal, + tDot11fIEoci *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_oci( + tpAniSirGlobal, + tDot11fIEoci *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x12} */ +typedef struct sDot11fIEosen_ie { + uint8_t present; + uint8_t num_data; + uint8_t data[255]; +} tDot11fIEosen_ie; + +#define DOT11F_EID_OSEN_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_OSEN_IE_MIN_LEN (4) + +#define DOT11F_IE_OSEN_IE_MAX_LEN (259) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_osen_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEosen_ie*, + bool); + +uint32_t dot11f_pack_ie_osen_ie( + tpAniSirGlobal, + tDot11fIEosen_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_osen_ie( + tpAniSirGlobal, + tDot11fIEosen_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x8c, 0xfd, 0xf0, 0x01} (Multi-IE) */ +typedef struct sDot11fIEqcn_ie { + uint8_t present; + tDot11fTLVqcn_version qcn_version; + tDot11fTLVvht_mcs11_attr vht_mcs11_attr; + tDot11fTLVhe_400ns_sgi_attr he_400ns_sgi_attr; + tDot11fTLVhe_2xltf_160mhz_supp he_2xltf_160mhz_supp; + tDot11fTLVhe_dl_ofdma_attr he_dl_ofdma_attr; + tDot11fTLVtrans_reasonp_attr trans_reasonp_attr; + tDot11fTLVtrans_rejectp_attr trans_rejectp_attr; + tDot11fTLVhe_dl_mumimo_attr he_dl_mumimo_attr; + tDot11fTLVhe_mcs13_attr he_mcs13_attr; + tDot11fTLVedca_pifs_param_attr edca_pifs_param_attr; + tDot11fTLVecsa_target_tsf_info_attr ecsa_target_tsf_info_attr; +} tDot11fIEqcn_ie; + +#define DOT11F_EID_QCN_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_QCN_IE_MIN_LEN (4) + +#define DOT11F_IE_QCN_IE_MAX_LEN (53) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_qcn_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEqcn_ie*, + bool); + +uint32_t dot11f_pack_ie_qcn_ie( + tpAniSirGlobal, + tDot11fIEqcn_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_qcn_ie( + tpAniSirGlobal, + tDot11fIEqcn_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 201 (0xc9) */ +typedef struct sDot11fIEreduced_neighbor_report { + uint8_t present; + uint16_t tbtt_type:2; + uint16_t filtered_neighbor_ap:1; + uint16_t reserved:1; + uint16_t tbtt_info_count:4; + uint16_t tbtt_info_len:8; + uint8_t op_class; + uint8_t channel_num; + union { + struct { + uint8_t tbtt_offset; + } tbtt_info_1; /* tbtt_info_len = 1 */ + struct { + uint8_t tbtt_offset; + uint8_t bss_params; + } tbtt_info_2; /* tbtt_info_len = 2 */ + struct { + uint8_t tbtt_offset; + uint32_t short_ssid; + } tbtt_info_5; /* tbtt_info_len = 5 */ + struct { + uint8_t tbtt_offset; + uint32_t short_ssid; + uint8_t bss_params; + } tbtt_info_6; /* tbtt_info_len = 6 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + } tbtt_info_7; /* tbtt_info_len = 7 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + uint8_t bss_params; + } tbtt_info_8; /* tbtt_info_len = 8 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + uint8_t bss_params; + uint8_t psd_20mhz; + } tbtt_info_9; /* tbtt_info_len = 9 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + uint32_t short_ssid; + } tbtt_info_11; /* tbtt_info_len = 11 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + uint32_t short_ssid; + uint8_t bss_params; + } tbtt_info_12; /* tbtt_info_len = 12 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + uint32_t short_ssid; + uint8_t bss_params; + uint8_t psd_20mhz; + } tbtt_info_13; /* tbtt_info_len = 13 */ + struct { + uint8_t tbtt_offset; + uint8_t bssid[6]; + uint32_t short_ssid; + uint8_t bss_params; + uint8_t psd_20mhz; + uint8_t mld_id; + uint16_t link_id:4; + uint16_t bss_param_change_cnt:8; + uint16_t all_updates_included:1; + uint16_t reserved:3; + } tbtt_info_16; /* tbtt_info_len = 16 */ + } tbtt_info; +} tDot11fIEreduced_neighbor_report; + +#define DOT11F_EID_REDUCED_NEIGHBOR_REPORT (201) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_REDUCED_NEIGHBOR_REPORT_MIN_LEN (5) + +#define DOT11F_IE_REDUCED_NEIGHBOR_REPORT_MAX_LEN (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_reduced_neighbor_report( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEreduced_neighbor_report*, + bool); + +uint32_t dot11f_pack_ie_reduced_neighbor_report( + tpAniSirGlobal, + tDot11fIEreduced_neighbor_report *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_reduced_neighbor_report( + tpAniSirGlobal, + tDot11fIEreduced_neighbor_report *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x50, 0x6f, 0x9a, 0x1d} */ +typedef struct sDot11fIEroaming_consortium_sel { + uint8_t present; + uint8_t num_data; + uint8_t data[255]; +} tDot11fIEroaming_consortium_sel; + +#define DOT11F_EID_ROAMING_CONSORTIUM_SEL (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_ROAMING_CONSORTIUM_SEL_MIN_LEN (4) + +#define DOT11F_IE_ROAMING_CONSORTIUM_SEL_MAX_LEN (259) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_roaming_consortium_sel( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEroaming_consortium_sel*, + bool); + +uint32_t dot11f_pack_ie_roaming_consortium_sel( + tpAniSirGlobal, + tDot11fIEroaming_consortium_sel *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_roaming_consortium_sel( + tpAniSirGlobal, + tDot11fIEroaming_consortium_sel *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 62 (0x3e) */ +typedef struct sDot11fIEsec_chan_offset_ele { + uint8_t present; + uint8_t secondaryChannelOffset; +} tDot11fIEsec_chan_offset_ele; + +#define DOT11F_EID_SEC_CHAN_OFFSET_ELE (62) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SEC_CHAN_OFFSET_ELE_MIN_LEN (1) + +#define DOT11F_IE_SEC_CHAN_OFFSET_ELE_MAX_LEN (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_sec_chan_offset_ele( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEsec_chan_offset_ele*, + bool); + +uint32_t dot11f_pack_ie_sec_chan_offset_ele( + tpAniSirGlobal, + tDot11fIEsec_chan_offset_ele *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_sec_chan_offset_ele( + tpAniSirGlobal, + tDot11fIEsec_chan_offset_ele *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 39 (0x27) */ +typedef struct sDot11fIEspatial_reuse { + uint8_t present; + uint8_t psr_disallow:1; + uint8_t non_srg_pd_sr_disallow:1; + uint8_t non_srg_offset_present:1; + uint8_t srg_info_present:1; + uint8_t sr_value15_allow:1; + uint8_t reserved:3; + union { + struct { + uint8_t non_srg_pd_max_offset; + } info; /* non_srg_offset_present = 1 */ + } non_srg_offset; + union { + struct { + uint8_t srg_pd_min_offset; + uint8_t srg_pd_max_offset; + uint8_t srg_color[8]; + uint8_t srg_partial_bssid[8]; + } info; /* srg_info_present = 1 */ + } srg_info; +} tDot11fIEspatial_reuse; + +#define DOT11F_EID_SPATIAL_REUSE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_SPATIAL_REUSE_MIN_LEN (1) + +#define DOT11F_IE_SPATIAL_REUSE_MAX_LEN (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_spatial_reuse( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEspatial_reuse*, + bool); + +uint32_t dot11f_pack_ie_spatial_reuse( + tpAniSirGlobal, + tDot11fIEspatial_reuse *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_spatial_reuse( + tpAniSirGlobal, + tDot11fIEspatial_reuse *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 255 (0xff) Extended EID 109 (0x6d) */ +typedef struct sDot11fIEt2lm_ie { + uint8_t present; + uint8_t num_data; + uint8_t data[255]; +} tDot11fIEt2lm_ie; + +#define DOT11F_EID_T2LM_IE (255) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_T2LM_IE_MIN_LEN (3) + +#define DOT11F_IE_T2LM_IE_MAX_LEN (255) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_t2lm_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEt2lm_ie*, + bool); + +uint32_t dot11f_pack_ie_t2lm_ie( + tpAniSirGlobal, + tDot11fIEt2lm_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_t2lm_ie( + tpAniSirGlobal, + tDot11fIEt2lm_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ + +/* EID 221 (0xdd) {OUI 0x00, 0x90, 0x4c, 0x04} */ +typedef struct sDot11fIEvendor_vht_ie { + uint8_t present; + uint8_t sub_type; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; +} tDot11fIEvendor_vht_ie; + +#define DOT11F_EID_VENDOR_VHT_IE (221) + +/* N.B. These #defines do *not* include the EID & length */ +#define DOT11F_IE_VENDOR_VHT_IE_MIN_LEN (5) + +#define DOT11F_IE_VENDOR_VHT_IE_MAX_LEN (26) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ +__must_check uint32_t dot11f_unpack_ie_vendor_vht_ie( + tpAniSirGlobal, + uint8_t *, + uint8_t, + tDot11fIEvendor_vht_ie*, + bool); + +uint32_t dot11f_pack_ie_vendor_vht_ie( + tpAniSirGlobal, + tDot11fIEvendor_vht_ie *, + uint8_t *, + uint32_t, + uint32_t*); + +uint32_t dot11f_get_packed_ie_vendor_vht_ie( + tpAniSirGlobal, + tDot11fIEvendor_vht_ie *, + uint32_t*); + +#ifdef __cplusplus +}; /* End extern "C". */ +#endif /* C++ */ +/************************************************************************ + * Frames + **********************************************************************/ + +typedef struct sDot11fAddTSRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; +} tDot11fAddTSRequest; + +#define DOT11F_ADDTSREQUEST (1) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_add_ts_request(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAddTSResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatus Status; + tDot11fIETSDelay TSDelay; + tDot11fIETSPEC TSPEC; + uint16_t num_TCLAS; + tDot11fIETCLAS TCLAS[2]; + tDot11fIETCLASSPROC TCLASSPROC; + tDot11fIESchedule Schedule; + tDot11fIEWMMTSDelay WMMTSDelay; + tDot11fIEWMMSchedule WMMSchedule; + tDot11fIEWMMTSPEC WMMTSPEC; + uint16_t num_WMMTCLAS; + tDot11fIEWMMTCLAS WMMTCLAS[2]; + tDot11fIEWMMTCLASPROC WMMTCLASPROC; + tDot11fIEESETrafStrmMet ESETrafStrmMet; +} tDot11fAddTSResponse; + +#define DOT11F_ADDTSRESPONSE (2) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSResponse * pFrm, bool append_ie); +uint32_t dot11f_pack_add_ts_response(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAssocRequest{ + tDot11fFfCapabilities Capabilities; + tDot11fFfListenInterval ListenInterval; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEHTCaps HTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEfils_session fils_session; + tDot11fIEfils_public_key fils_public_key; + tDot11fIEfils_key_confirmation fils_key_confirmation; + tDot11fIEfils_hlp_container fils_hlp_container; + tDot11fIEbss_max_idle_period bss_max_idle_period; + tDot11fIEFTInfo FTInfo; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEfragment_ie fragment_ie; + tDot11fIEdh_parameter_element dh_parameter_element; + tDot11fIEeht_cap eht_cap; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEosen_ie osen_ie; + tDot11fIEroaming_consortium_sel roaming_consortium_sel; +} tDot11fAssocRequest; + +#define DOT11F_ASSOCREQUEST (3) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_assoc_request(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAssocResponse{ + tDot11fFfCapabilities Capabilities; + tDot11fFfStatus Status; + tDot11fFfAID AID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERCPIIE RCPIIE; + tDot11fIERSNIIE RSNIIE; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEExtCap ExtCap; + tDot11fIEbss_max_idle_period bss_max_idle_period; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEfils_session fils_session; + tDot11fIEfils_public_key fils_public_key; + tDot11fIEfils_key_confirmation fils_key_confirmation; + tDot11fIEfils_hlp_container fils_hlp_container; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEspatial_reuse spatial_reuse; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEfragment_ie fragment_ie; + tDot11fIEfils_kde fils_kde; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPA WPA; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEWscAssocRes WscAssocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEreduced_neighbor_report reduced_neighbor_report; +} tDot11fAssocResponse; + +#define DOT11F_ASSOCRESPONSE (4) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocResponse * pFrm, bool append_ie); +uint32_t dot11f_pack_assoc_response(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fAuthentication{ + tDot11fFfAuthAlgo AuthAlgo; + tDot11fFfAuthSeqNo AuthSeqNo; + tDot11fFfStatus Status; + tDot11fIEChallengeText ChallengeText; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIEfils_nonce fils_nonce; + tDot11fIEfils_session fils_session; + tDot11fIEfils_wrapped_data fils_wrapped_data; + tDot11fIEfils_assoc_delay_info fils_assoc_delay_info; + tDot11fIEmlo_ie mlo_ie; +} tDot11fAuthentication; + +#define DOT11F_AUTHENTICATION (5) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_authentication(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAuthentication * pFrm, bool append_ie); +uint32_t dot11f_pack_authentication(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_authentication_size(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + uint16_t num_transmit_power_env; + tDot11fIEtransmit_power_env transmit_power_env[8]; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEfils_indication fils_indication; + tDot11fIEmax_chan_switch_time max_chan_switch_time; + tDot11fIEesp_information esp_information; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEspatial_reuse spatial_reuse; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWAPI WAPI; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPA WPA; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEreduced_neighbor_report reduced_neighbor_report; +} tDot11fBeacon; + +#define DOT11F_BEACON (6) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon * pFrm, bool append_ie); +uint32_t dot11f_pack_beacon(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon_size(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon1{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEDSParams DSParams; +} tDot11fBeacon1; + +#define DOT11F_BEACON1 (7) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon1(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon1 * pFrm, bool append_ie); +uint32_t dot11f_pack_beacon1(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon1_size(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeacon2{ + tDot11fIECountry Country; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + uint16_t num_transmit_power_env; + tDot11fIEtransmit_power_env transmit_power_env[8]; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEfils_indication fils_indication; + tDot11fIEmax_chan_switch_time max_chan_switch_time; + tDot11fIEesp_information esp_information; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEspatial_reuse spatial_reuse; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWAPI WAPI; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPA WPA; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEWscBeacon WscBeacon; + tDot11fIEP2PBeacon P2PBeacon; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEESEVersion ESEVersion; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEreduced_neighbor_report reduced_neighbor_report; +} tDot11fBeacon2; + +#define DOT11F_BEACON2 (8) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon2 * pFrm, bool append_ie); +uint32_t dot11f_pack_beacon2(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon2_size(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fBeaconIEs{ + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIETIM TIM; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSN RSN; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEQOSCapsAp QOSCapsAp; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + uint16_t num_transmit_power_env; + tDot11fIEtransmit_power_env transmit_power_env[8]; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEfils_indication fils_indication; + tDot11fIEmax_chan_switch_time max_chan_switch_time; + tDot11fIEesp_information esp_information; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEspatial_reuse spatial_reuse; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWAPI WAPI; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPA WPA; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEWscBeaconProbeRes WscBeaconProbeRes; + tDot11fIEP2PBeaconProbeRes P2PBeaconProbeRes; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEreduced_neighbor_report reduced_neighbor_report; +} tDot11fBeaconIEs; + +#define DOT11F_BEACONIES (9) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_beacon_i_es(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeaconIEs * pFrm, bool append_ie); +uint32_t dot11f_pack_beacon_i_es(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_beacon_i_es_size(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fChannelSwitch{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; +} tDot11fChannelSwitch; + +#define DOT11F_CHANNELSWITCH (10) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_channel_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fChannelSwitch * pFrm, bool append_ie); +uint32_t dot11f_pack_channel_switch(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_channel_switch_size(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDeAuth{ + tDot11fFfReason Reason; + tDot11fIEP2PDeAuth P2PDeAuth; +} tDot11fDeAuth; + +#define DOT11F_DEAUTH (11) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDeAuth * pFrm, bool append_ie); +uint32_t dot11f_pack_de_auth(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_de_auth_size(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDelTS{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTSInfo TSInfo; + tDot11fFfReason Reason; +} tDot11fDelTS; + +#define DOT11F_DELTS (12) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDelTS * pFrm, bool append_ie); +uint32_t dot11f_pack_del_ts(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fDisassociation{ + tDot11fFfReason Reason; + tDot11fIEP2PDisAssoc P2PDisAssoc; +} tDot11fDisassociation; + +#define DOT11F_DISASSOCIATION (13) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_disassociation(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDisassociation * pFrm, bool append_ie); +uint32_t dot11f_pack_disassociation(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_disassociation_size(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fLinkMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfTPCEleID TPCEleID; + tDot11fFfTPCEleLen TPCEleLen; + tDot11fFfTxPower TxPower; + tDot11fFfLinkMargin LinkMargin; + tDot11fFfRxAntennaId RxAntennaId; + tDot11fFfTxAntennaId TxAntennaId; + tDot11fFfRCPI RCPI; + tDot11fFfRSNI RSNI; +} tDot11fLinkMeasurementReport; + +#define DOT11F_LINKMEASUREMENTREPORT (14) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_link_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementReport * pFrm, bool append_ie); +uint32_t dot11f_pack_link_measurement_report(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_link_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fLinkMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfTxPower TxPower; + tDot11fFfMaxTxPower MaxTxPower; +} tDot11fLinkMeasurementRequest; + +#define DOT11F_LINKMEASUREMENTREQUEST (15) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_link_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_link_measurement_request(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_link_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIEMeasurementReport MeasurementReport; +} tDot11fMeasurementReport; + +#define DOT11F_MEASUREMENTREPORT (16) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementReport * pFrm, bool append_ie); +uint32_t dot11f_pack_measurement_report(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_MeasurementRequest; + tDot11fIEMeasurementRequest MeasurementRequest[4]; +} tDot11fMeasurementRequest; + +#define DOT11F_MEASUREMENTREQUEST (17) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_measurement_request(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fNeighborReportRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIESSID SSID; +} tDot11fNeighborReportRequest; + +#define DOT11F_NEIGHBORREPORTREQUEST (18) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_neighbor_report_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_neighbor_report_request(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_neighbor_report_request_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fNeighborReportResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_NeighborReport; + tDot11fIENeighborReport NeighborReport[15]; +} tDot11fNeighborReportResponse; + +#define DOT11F_NEIGHBORREPORTRESPONSE (19) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_neighbor_report_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportResponse * pFrm, bool append_ie); +uint32_t dot11f_pack_neighbor_report_response(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_neighbor_report_response_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fOperatingMode{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfOperatingMode OperatingMode; +} tDot11fOperatingMode; + +#define DOT11F_OPERATINGMODE (20) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fOperatingMode * pFrm, bool append_ie); +uint32_t dot11f_pack_operating_mode(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_operating_mode_size(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fProbeRequest{ + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIERequestedInfo RequestedInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEDSParams DSParams; + tDot11fIEHTCaps HTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEeht_cap eht_cap; + tDot11fIEmlo_ie mlo_ie; + tDot11fIEWscProbeReq WscProbeReq; + tDot11fIEWFATPC WFATPC; + tDot11fIEP2PProbeReq P2PProbeReq; + tDot11fIEqcn_ie qcn_ie; +} tDot11fProbeRequest; + +#define DOT11F_PROBEREQUEST (21) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_probe_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_probe_request(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_probe_request_size(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fProbeResponse{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfBeaconInterval BeaconInterval; + tDot11fFfCapabilities Capabilities; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEFHParamSet FHParamSet; + tDot11fIEDSParams DSParams; + tDot11fIECFParams CFParams; + tDot11fIECountry Country; + tDot11fIEFHParams FHParams; + tDot11fIEFHPattTable FHPattTable; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIEChanSwitchAnn ChanSwitchAnn; + tDot11fIEQuiet Quiet; + tDot11fIETPCReport TPCReport; + tDot11fIEERPInfo ERPInfo; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQBSSLoad QBSSLoad; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEAPChannelReport APChannelReport; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEext_chan_switch_ann ext_chan_switch_ann; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + uint16_t num_transmit_power_env; + tDot11fIEtransmit_power_env transmit_power_env[8]; + tDot11fIEChannelSwitchWrapper ChannelSwitchWrapper; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEfils_indication fils_indication; + tDot11fIEmax_chan_switch_time max_chan_switch_time; + tDot11fIEesp_information esp_information; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEspatial_reuse spatial_reuse; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEsec_chan_offset_ele sec_chan_offset_ele; + tDot11fIEWAPI WAPI; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPA WPA; + tDot11fIEWMMInfoAp WMMInfoAp; + tDot11fIEWMMParams WMMParams; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEESEVersion ESEVersion; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + tDot11fIEWscProbeRes WscProbeRes; + tDot11fIEP2PProbeRes P2PProbeRes; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEVendor3IE Vendor3IE; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEQComVendorIE QComVendorIE; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEreduced_neighbor_report reduced_neighbor_report; +} tDot11fProbeResponse; + +#define DOT11F_PROBERESPONSE (22) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_probe_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeResponse * pFrm, bool append_ie); +uint32_t dot11f_pack_probe_response(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_probe_response_size(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fQosMapConfigure{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEQosMapSet QosMapSet; +} tDot11fQosMapConfigure; + +#define DOT11F_QOSMAPCONFIGURE (23) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_qos_map_configure(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fQosMapConfigure * pFrm, bool append_ie); +uint32_t dot11f_pack_qos_map_configure(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_qos_map_configure_size(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fRadioMeasurementReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_MeasurementReport; + tDot11fIEMeasurementReport MeasurementReport[1]; +} tDot11fRadioMeasurementReport; + +#define DOT11F_RADIOMEASUREMENTREPORT (24) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_radio_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementReport * pFrm, bool append_ie); +uint32_t dot11f_pack_radio_measurement_report(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_radio_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fRadioMeasurementRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfNumOfRepetitions NumOfRepetitions; + uint16_t num_MeasurementRequest; + tDot11fIEMeasurementRequest MeasurementRequest[5]; +} tDot11fRadioMeasurementRequest; + +#define DOT11F_RADIOMEASUREMENTREQUEST (25) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_radio_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_radio_measurement_request(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_radio_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fReAssocRequest{ + tDot11fFfCapabilities Capabilities; + tDot11fFfListenInterval ListenInterval; + tDot11fFfCurrentAPAddress CurrentAPAddress; + tDot11fIESSID SSID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEPowerCaps PowerCaps; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEHTCaps HTCaps; + tDot11fIEExtCap ExtCap; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEbss_max_idle_period bss_max_idle_period; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEWAPIOpaque WAPIOpaque; + tDot11fIEWAPI WAPI; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEESECckmOpaque ESECckmOpaque; + tDot11fIEeht_cap eht_cap; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPAOpaque WPAOpaque; + tDot11fIEWMMCaps WMMCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEWscIEOpaque WscIEOpaque; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESEVersion ESEVersion; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEP2PIEOpaque P2PIEOpaque; + tDot11fIEWFDIEOpaque WFDIEOpaque; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; +} tDot11fReAssocRequest; + +#define DOT11F_REASSOCREQUEST (26) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_re_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_re_assoc_request(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_re_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fReAssocResponse{ + tDot11fFfCapabilities Capabilities; + tDot11fFfStatus Status; + tDot11fFfAID AID; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIERCPIIE RCPIIE; + tDot11fIERSNIIE RSNIIE; + tDot11fIERRMEnabledCap RRMEnabledCap; + tDot11fIERSNOpaque RSNOpaque; + tDot11fIEMobilityDomain MobilityDomain; + tDot11fIEFTInfo FTInfo; + uint16_t num_RICDataDesc; + tDot11fIERICDataDesc RICDataDesc[2]; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEOBSSScanParameters OBSSScanParameters; + tDot11fIEExtCap ExtCap; + tDot11fIEbss_max_idle_period bss_max_idle_period; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; + tDot11fIEspatial_reuse spatial_reuse; + tDot11fIEbss_color_change bss_color_change; + tDot11fIEmu_edca_param_set mu_edca_param_set; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEQosMapSet QosMapSet; + tDot11fIEESETxmitPower ESETxmitPower; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + tDot11fIEmlo_ie mlo_ie; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; + tDot11fIEWPA WPA; + tDot11fIEWMMParams WMMParams; + tDot11fIEESERadMgmtCap ESERadMgmtCap; + tDot11fIEESETrafStrmMet ESETrafStrmMet; + uint16_t num_WMMTSPEC; + tDot11fIEWMMTSPEC WMMTSPEC[4]; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; + tDot11fIEWscReassocRes WscReassocRes; + tDot11fIEP2PAssocRes P2PAssocRes; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEMBO_IE MBO_IE; + tDot11fIEreduced_neighbor_report reduced_neighbor_report; +} tDot11fReAssocResponse; + +#define DOT11F_REASSOCRESPONSE (27) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_re_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocResponse * pFrm, bool append_ie); +uint32_t dot11f_pack_re_assoc_response(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_re_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSMPowerSave{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfSMPowerModeSet SMPowerModeSet; +} tDot11fSMPowerSave; + +#define DOT11F_SMPOWERSAVE (28) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sm_power_save(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSMPowerSave * pFrm, bool append_ie); +uint32_t dot11f_pack_sm_power_save(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sm_power_save_size(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSaQueryReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTransactionId TransactionId; + tDot11fIEoci oci; +} tDot11fSaQueryReq; + +#define DOT11F_SAQUERYREQ (29) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sa_query_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryReq * pFrm, bool append_ie); +uint32_t dot11f_pack_sa_query_req(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sa_query_req_size(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fSaQueryRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfTransactionId TransactionId; + tDot11fIEoci oci; +} tDot11fSaQueryRsp; + +#define DOT11F_SAQUERYRSP (30) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_sa_query_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryRsp * pFrm, bool append_ie); +uint32_t dot11f_pack_sa_query_rsp(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_sa_query_rsp_size(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSDisReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSDisReq; + +#define DOT11F_TDLSDISREQ (31) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_dis_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisReq * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_dis_req(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_dis_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSDisRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEhe_cap he_cap; +} tDot11fTDLSDisRsp; + +#define DOT11F_TDLSDISRSP (32) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_dis_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisRsp * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_dis_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_dis_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSPeerTrafficInd{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEPTIControl PTIControl; + tDot11fIEPUBufferStatus PUBufferStatus; +} tDot11fTDLSPeerTrafficInd; + +#define DOT11F_TDLSPEERTRAFFICIND (33) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficInd * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_peer_traffic_ind_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSPeerTrafficRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSPeerTrafficRsp; + +#define DOT11F_TDLSPEERTRAFFICRSP (34) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficRsp * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_peer_traffic_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupCnf{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfStatus Status; + tDot11fFfDialogToken DialogToken; + tDot11fIERSN RSN; + tDot11fIEEDCAParamSet EDCAParamSet; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIEHTInfo HTInfo; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMParams WMMParams; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEhe_op he_op; +} tDot11fTDLSSetupCnf; + +#define DOT11F_TDLSSETUPCNF (35) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_cnf(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupCnf * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_setup_cnf(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_cnf_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupReq{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIECountry Country; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEAID AID; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; +} tDot11fTDLSSetupReq; + +#define DOT11F_TDLSSETUPREQ (36) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupReq * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_setup_req(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSSetupRsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfStatus Status; + tDot11fFfDialogToken DialogToken; + tDot11fFfCapabilities Capabilities; + tDot11fIESuppRates SuppRates; + tDot11fIECountry Country; + tDot11fIEExtSuppRates ExtSuppRates; + tDot11fIESuppChannels SuppChannels; + tDot11fIERSN RSN; + tDot11fIEExtCap ExtCap; + tDot11fIESuppOperatingClasses SuppOperatingClasses; + tDot11fIEQOSCapsStation QOSCapsStation; + tDot11fIEFTInfo FTInfo; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERICData RICData; + tDot11fIEHTCaps HTCaps; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIELinkIdentifier LinkIdentifier; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIEAID AID; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; +} tDot11fTDLSSetupRsp; + +#define DOT11F_TDLSSETUPRSP (37) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_setup_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupRsp * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_setup_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_setup_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTDLSTeardown{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfReason Reason; + tDot11fIEFTInfo FTInfo; + tDot11fIELinkIdentifier LinkIdentifier; +} tDot11fTDLSTeardown; + +#define DOT11F_TDLSTEARDOWN (38) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tdls_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSTeardown * pFrm, bool append_ie); +uint32_t dot11f_pack_tdls_teardown(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tdls_teardown_size(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTPCReport{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETPCReport TPCReport; +} tDot11fTPCReport; + +#define DOT11F_TPCREPORT (39) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCReport * pFrm, bool append_ie); +uint32_t dot11f_pack_tpc_report(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tpc_report_size(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTPCRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIETPCRequest TPCRequest; +} tDot11fTPCRequest; + +#define DOT11F_TPCREQUEST (40) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_tpc_request(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_tpc_request_size(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fTimingAdvertisementFrame{ + tDot11fFfTimeStamp TimeStamp; + tDot11fFfCapabilities Capabilities; + tDot11fIECountry Country; + tDot11fIEPowerConstraints PowerConstraints; + tDot11fIETimeAdvertisement TimeAdvertisement; + tDot11fIEExtCap ExtCap; + tDot11fIEVendor1IE Vendor1IE; + tDot11fIEVendor3IE Vendor3IE; +} tDot11fTimingAdvertisementFrame; + +#define DOT11F_TIMINGADVERTISEMENTFRAME (41) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_timing_advertisement_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTimingAdvertisementFrame * pFrm, bool append_ie); +uint32_t dot11f_pack_timing_advertisement_frame(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_timing_advertisement_frame_size(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fVHTGidManagementActionFrame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfVhtMembershipStatusArray VhtMembershipStatusArray; + tDot11fFfVhtUserPositionArray VhtUserPositionArray; +} tDot11fVHTGidManagementActionFrame; + +#define DOT11F_VHTGIDMANAGEMENTACTIONFRAME (42) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fVHTGidManagementActionFrame * pFrm, bool append_ie); +uint32_t dot11f_pack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_vht_gid_management_action_frame_size(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMAddTSRequest{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; + tDot11fIEESETrafStrmRateSet ESETrafStrmRateSet; +} tDot11fWMMAddTSRequest; + +#define DOT11F_WMMADDTSREQUEST (43) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSRequest * pFrm, bool append_ie); +uint32_t dot11f_pack_wmm_add_ts_request(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMAddTSResponse{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; + tDot11fIEESETrafStrmMet ESETrafStrmMet; +} tDot11fWMMAddTSResponse; + +#define DOT11F_WMMADDTSRESPONSE (44) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSResponse * pFrm, bool append_ie); +uint32_t dot11f_pack_wmm_add_ts_response(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fWMMDelTS{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatusCode StatusCode; + tDot11fIEWMMTSPEC WMMTSPEC; +} tDot11fWMMDelTS; + +#define DOT11F_WMMDELTS (45) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_wmm_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMDelTS * pFrm, bool append_ie); +uint32_t dot11f_pack_wmm_del_ts(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_wmm_del_ts_size(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11faddba_req{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfaddba_param_set addba_param_set; + tDot11fFfba_timeout ba_timeout; + tDot11fFfba_start_seq_ctrl ba_start_seq_ctrl; + tDot11fIEaddba_extn_element addba_extn_element; +} tDot11faddba_req; + +#define DOT11F_ADDBA_REQ (46) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_addba_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11faddba_req * pFrm, bool append_ie); +uint32_t dot11f_pack_addba_req(tpAniSirGlobal pCtx, + tDot11faddba_req *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_addba_req_size(tpAniSirGlobal pCtx, + tDot11faddba_req *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11faddba_rsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatus Status; + tDot11fFfaddba_param_set addba_param_set; + tDot11fFfba_timeout ba_timeout; + tDot11fIEaddba_extn_element addba_extn_element; +} tDot11faddba_rsp; + +#define DOT11F_ADDBA_RSP (47) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_addba_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11faddba_rsp * pFrm, bool append_ie); +uint32_t dot11f_pack_addba_rsp(tpAniSirGlobal pCtx, + tDot11faddba_rsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_addba_rsp_size(tpAniSirGlobal pCtx, + tDot11faddba_rsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fdelba_req{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfdelba_param_set delba_param_set; + tDot11fFfReason Reason; +} tDot11fdelba_req; + +#define DOT11F_DELBA_REQ (48) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_delba_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fdelba_req * pFrm, bool append_ie); +uint32_t dot11f_pack_delba_req(tpAniSirGlobal pCtx, + tDot11fdelba_req *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_delba_req_size(tpAniSirGlobal pCtx, + tDot11fdelba_req *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fepcs_neg_req{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; +} tDot11fepcs_neg_req; + +#define DOT11F_EPCS_NEG_REQ (49) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_epcs_neg_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fepcs_neg_req * pFrm, bool append_ie); +uint32_t dot11f_pack_epcs_neg_req(tpAniSirGlobal pCtx, + tDot11fepcs_neg_req *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_epcs_neg_reqSize(tpAniSirGlobal pCtx, + tDot11fepcs_neg_req *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fepcs_neg_rsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatus Status; +} tDot11fepcs_neg_rsp; + +#define DOT11F_EPCS_NEG_RSP (50) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_epcs_neg_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fepcs_neg_rsp * pFrm, bool append_ie); +uint32_t dot11f_pack_epcs_neg_rsp(tpAniSirGlobal pCtx, + tDot11fepcs_neg_rsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_epcs_neg_rspSize(tpAniSirGlobal pCtx, + tDot11fepcs_neg_rsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fepcs_teardown{ + tDot11fFfCategory Category; + tDot11fFfAction Action; +} tDot11fepcs_teardown; + +#define DOT11F_EPCS_TEARDOWN (51) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_epcs_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fepcs_teardown * pFrm, bool append_ie); +uint32_t dot11f_pack_epcs_teardown(tpAniSirGlobal pCtx, + tDot11fepcs_teardown *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_epcs_teardownSize(tpAniSirGlobal pCtx, + tDot11fepcs_teardown *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fext_channel_switch_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfext_chan_switch_ann_action ext_chan_switch_ann_action; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEbw_ind_element bw_ind_element; +} tDot11fext_channel_switch_action_frame; + +#define DOT11F_EXT_CHANNEL_SWITCH_ACTION_FRAME (52) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fext_channel_switch_action_frame * pFrm, bool append_ie); +uint32_t dot11f_pack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_ext_channel_switch_action_frame_size(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fht2040_bss_coexistence_mgmt_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fIEht2040_bss_coexistence ht2040_bss_coexistence; + tDot11fIEht2040_bss_intolerant_report ht2040_bss_intolerant_report; +} tDot11fht2040_bss_coexistence_mgmt_action_frame; + +#define DOT11F_HT2040_BSS_COEXISTENCE_MGMT_ACTION_FRAME (53) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fht2040_bss_coexistence_mgmt_action_frame * pFrm, bool append_ie); +uint32_t dot11f_pack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fmscs_request_action_frame{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fIEdescriptor_element descriptor_element; +} tDot11fmscs_request_action_frame; + +#define DOT11F_MSCS_REQUEST_ACTION_FRAME (54) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_mscs_request_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fmscs_request_action_frame * pFrm, bool append_ie); +uint32_t dot11f_pack_mscs_request_action_frame(tpAniSirGlobal pCtx, + tDot11fmscs_request_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_mscs_request_action_frameSize(tpAniSirGlobal pCtx, + tDot11fmscs_request_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fp2p_oper_chan_change_confirm{ + tDot11fFfCategory Category; + tDot11fFfp2p_action_oui p2p_action_oui; + tDot11fFfp2p_action_subtype p2p_action_subtype; + tDot11fFfDialogToken DialogToken; + tDot11fIEHTCaps HTCaps; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode OperatingMode; +} tDot11fp2p_oper_chan_change_confirm; + +#define DOT11F_P2P_OPER_CHAN_CHANGE_CONFIRM (55) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fp2p_oper_chan_change_confirm * pFrm, bool append_ie); +uint32_t dot11f_pack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_p2p_oper_chan_change_confirmSize(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11ft2lm_neg_req{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + uint16_t num_t2lm_ie; + tDot11fIEt2lm_ie t2lm_ie[2]; +} tDot11ft2lm_neg_req; + +#define DOT11F_T2LM_NEG_REQ (56) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_t2lm_neg_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11ft2lm_neg_req * pFrm, bool append_ie); +uint32_t dot11f_pack_t2lm_neg_req(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_req *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_t2lm_neg_reqSize(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_req *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11ft2lm_neg_rsp{ + tDot11fFfCategory Category; + tDot11fFfAction Action; + tDot11fFfDialogToken DialogToken; + tDot11fFfStatus Status; +} tDot11ft2lm_neg_rsp; + +#define DOT11F_T2LM_NEG_RSP (57) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_t2lm_neg_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11ft2lm_neg_rsp * pFrm, bool append_ie); +uint32_t dot11f_pack_t2lm_neg_rsp(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_rsp *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_t2lm_neg_rspSize(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_rsp *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11ft2lm_teardown{ + tDot11fFfCategory Category; + tDot11fFfAction Action; +} tDot11ft2lm_teardown; + +#define DOT11F_T2LM_TEARDOWN (58) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_t2lm_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11ft2lm_teardown * pFrm, bool append_ie); +uint32_t dot11f_pack_t2lm_teardown(tpAniSirGlobal pCtx, + tDot11ft2lm_teardown *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_t2lm_teardownSize(tpAniSirGlobal pCtx, + tDot11ft2lm_teardown *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +typedef struct sDot11fvendor_action_frame{ + tDot11fFfCategory Category; + tDot11fFfvendor_oui vendor_oui; + tDot11fFfvendor_action_subtype vendor_action_subtype; +} tDot11fvendor_action_frame; + +#define DOT11F_VENDOR_ACTION_FRAME (59) + +#ifdef __cplusplus +extern "C" { +#endif /* C++ */ + +uint32_t dot11f_unpack_vendor_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fvendor_action_frame * pFrm, bool append_ie); +uint32_t dot11f_pack_vendor_action_frame(tpAniSirGlobal pCtx, + tDot11fvendor_action_frame *pFrm, uint8_t *pBuf, + uint32_t nBuf, uint32_t *pnConsumed); +uint32_t dot11f_get_packed_vendor_action_frameSize(tpAniSirGlobal pCtx, + tDot11fvendor_action_frame *pFrm, + uint32_t *pnNeeded); + +#ifdef __cplusplus +} /* End extern "C". */ +#endif /* C++ */ + +#endif /* DOT11F_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/dph_global.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/dph_global.h new file mode 100644 index 0000000000..1e59c708be --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/dph_global.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + + * + + * Author: Sandesh Goel + + * Date: 02/25/02 + + * History:- + + * Date Modified by Modification Information + + * -------------------------------------------------------------------- + + * + + */ + +#ifndef __DPH_GLOBAL_H__ +#define __DPH_GLOBAL_H__ + +#include "lim_global.h" +#include "sir_mac_prot_def.h" +#include "sir_api.h" + +/* DPH Hash Index for BSS(STA's Peer) on station. */ +#define DPH_STA_HASH_INDEX_PEER 1 + +/* DPH PMF SA Query state for station */ +#define DPH_SA_QUERY_NOT_IN_PROGRESS 1 +#define DPH_SA_QUERY_IN_PROGRESS 2 +#define DPH_SA_QUERY_TIMED_OUT 3 + +typedef struct sDphQosParams { + uint8_t addtsPresent; + tSirAddtsReqInfo addts; + tSirMacQosCapabilityStaIE capability; + /*AP EDCA params, extracted from assoc resp*/ + tSirMacEdcaParamSetIE peer_edca_params; +} tDphQosParams; + +/** + * struct parsed_ies: Parsed IE's of BSS capability + * @ht_caps: HT caps IE + * @vht_caps: VHT caps IE + * @ht_operation: HT operation IE + * @vht_operation: VHT operation IE + * @hs20vendor_ie: HS2.0 vendor IE + * @he_operation: HE operation IE + * @srp_ie: Spatial Reuse Parameter IE + * @eht_operation: EHT IE + * + * This structure holds the parsed IE of connected BSS + * and this is not the intersection of BSS and STA + * capability. For example, if BSS supports 80 MHz + * and STA connects to BSS in 20 MHz, this structure + * holds 80 MHz as peer capability. + */ +struct parsed_ies { + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tDot11fIEHTInfo ht_operation; + tDot11fIEVHTOperation vht_operation; + tDot11fIEhs20vendor_ie hs20vendor_ie; +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_op he_operation; +#endif +#ifdef WLAN_FEATURE_SR + tDot11fIEspatial_reuse srp_ie; +#endif +#ifdef WLAN_FEATURE_11BE + tDot11fIEeht_op eht_operation; +#endif +}; + +/* STA state node */ +typedef struct sDphHashNode { + /* + * This STA valid or not + */ + uint8_t valid:1; + uint8_t qosMode:1; + uint8_t erpEnabled:1; + /* This has been added to the dph hash table */ + uint8_t added:1; + uint8_t shortPreambleEnabled:1; + uint8_t shortSlotTimeEnabled:1; + /* set if both ap and sta are wme capable */ + uint8_t wmeEnabled:1; + /* set if both ap and sta are 11e capable */ + uint8_t lleEnabled:1; + /* set if both ap and sta are wsm capable */ + uint8_t wsmEnabled:1; + uint8_t fAniCount:1; + uint8_t rmfEnabled:1; + uint8_t ocv_enabled:1; + /* LIM state */ + struct lim_sta_context mlmStaContext; + /* qos parameter info */ + tDphQosParams qos; + /* + * All the legacy and airgo supported rates. + */ + struct supported_rates supportedRates; + /* MIMO Power Save */ + tSirMacHTMIMOPowerSaveState htMIMOPSState; + uint8_t htGreenfield:1; + uint8_t htShortGI40Mhz:1; + uint8_t htShortGI20Mhz:1; + /* DSSS/CCK at 40 MHz: Enabled 1 or Disabled */ + uint8_t htDsssCckRate40MHzSupport:1; + /* L-SIG TXOP Protection used only if peer support available */ + uint8_t htLsigTXOPProtection:1; + /* + * A-MPDU Density + * 000 - No restriction + * 001 - 1/8 usec + * 010 - 1/4 usec + * 011 - 1/2 usec + * 100 - 1 usec + * 101 - 2 usec + * 110 - 4 usec + * 111 - 8 usec + */ + uint8_t htAMpduDensity:3; + /* Set to 0 for 3839 octets */ + /* Set to 1 for 7935 octets */ + uint8_t htMaxAmsduLength; + /* */ + /* Maximum Rx A-MPDU factor */ + uint8_t htMaxRxAMpduFactor:3; + /* + * Recommended Tx Width Set + * 0 - use 20 MHz channel (control channel) + * 1 - use 40 Mhz channel + */ + uint8_t htSupportedChannelWidthSet:1; + uint8_t htSecondaryChannelOffset:2; + uint16_t assocId; /* Association ID */ + uint8_t staAddr[6]; + uint8_t staType; + + uint8_t vhtSupportedChannelWidthSet; + enum phy_ch_width ch_width; + uint8_t vhtSupportedRxNss; + uint8_t vhtBeamFormerCapable; + uint8_t vht_su_bfee_capable; + uint8_t vht_mcs_10_11_supp; + uint8_t vht_160mhz_nss; + uint8_t vht_80p80mhz_nss; + uint8_t vht_extended_nss_bw_cap; + TX_TIMER pmfSaQueryTimer; + uint16_t pmfSaQueryCurrentTransId; + uint16_t pmfSaQueryStartTransId; + uint8_t pmfSaQueryState; + uint8_t pmfSaQueryRetryCount; + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; +#ifdef FEATURE_WLAN_TDLS + uint16_t ht_caps; + uint32_t vht_caps; +#endif + uint8_t timingMeasCap; + /* key installed for this STA or not in the firmware */ + uint8_t is_key_installed; + uint8_t is_disassoc_deauth_in_progress; + + uint8_t nss; + int8_t del_sta_ctx_rssi; + bool sta_deletion_in_progress; + /* Flag indicating connected STA doesn't support ECSA */ + uint8_t non_ecsa_capable; + struct parsed_ies parsed_ies; + uint32_t last_ocv_done_freq; + +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_config; + uint16_t he_mcs_12_13_map; + tDot11fIEhe_6ghz_band_cap he_6g_band_cap; +#endif + +#ifdef WLAN_FEATURE_11BE + tDot11fIEeht_cap eht_config; + tDot11fIEeht_op eht_op; +#endif + + /* Peer operation class, extracted from ASSOC request frame*/ + tDot11fIESuppOperatingClasses supp_operating_classes; + /* + * When a station with already an existing dph entry tries to + * associate again, the old dph entry will be zeroed out except + * for the next pointer. The next pointer must be defined at the + * end of the structure. + */ + struct sDphHashNode *next; +#ifdef WLAN_FEATURE_11BE_MLO + bool recv_assoc_frm; + uint8_t mld_addr[QDF_MAC_ADDR_SIZE]; + struct mlo_partner_info mlo_info; +#endif +} tDphHashNode, *tpDphHashNode; + +#include "dph_hash_table.h" + +/* ------------------------------------------------------------------- */ +typedef struct sAniSirDph { + /* The hash table object */ + struct dph_hash_table dphHashTable; +} tAniSirDph, *tpAniSirDph; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/parser_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/parser_api.h new file mode 100644 index 0000000000..a8ce040325 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/parser_api.h @@ -0,0 +1,1932 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file parser_api.h contains the definitions used + * for parsing received 802.11 frames + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __PARSE_H__ +#define __PARSE_H__ + +#include "qdf_types.h" +#include "sir_mac_prop_exts.h" +#include "dot11f.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "wlan_mlme_main.h" +#include + +#define COUNTRY_STRING_LENGTH (3) +#define COUNTRY_INFO_MAX_CHANNEL (84) +#define MAX_SIZE_OF_TRIPLETS_IN_COUNTRY_IE (COUNTRY_STRING_LENGTH * \ + COUNTRY_INFO_MAX_CHANNEL) +#define HIGHEST_24GHZ_CHANNEL_NUM (14) + +#define IS_24G_CH(__chNum) ((__chNum > 0) && (__chNum < 15)) +#define IS_5G_CH(__chNum) ((__chNum >= 36) && (__chNum <= 165)) +#define IS_2X2_CHAIN(__chain) ((__chain & 0x3) == 0x3) +#define DISABLE_NSS2_MCS 0xC +#define VHT_1x1_MCS9_MAP 0x2 +#define VHT_2x2_MCS9_MAP 0xA +#define VHT_1x1_MCS8_VAL 0xFFFD +#define VHT_2x2_MCS8_VAL 0xFFF5 +#define VHT_1x1_MCS_MASK 0x3 +#define VHT_2x2_MCS_MASK 0xF +#define DISABLE_VHT_MCS_9(mcs, nss) \ + (mcs = (nss > 1) ? VHT_2x2_MCS8_VAL : VHT_1x1_MCS8_VAL) + +#define NSS_1x1_MODE 1 +#define NSS_2x2_MODE 2 +#define NSS_3x3_MODE 3 +#define NSS_4x4_MODE 4 +#define MBO_IE_ASSOC_DISALLOWED_SUBATTR_ID 0x04 + +#define SIZE_OF_FIXED_PARAM 12 +#define SIZE_OF_TAG_PARAM_NUM 1 +#define SIZE_OF_TAG_PARAM_LEN 1 +#define RSNIEID 0x30 +#define RSNIE_CAPABILITY_LEN 2 +#define DEFAULT_RSNIE_CAP_VAL 0x00 + +#define SIZE_MASK 0x7FFF +#define FIXED_MASK 0x8000 + +#define MAX_TPE_IES 8 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#define QCOM_VENDOR_IE_MCC_AVOID_CH 0x01 + +struct sAvoidChannelIE { + /* following must be 0xDD (221) */ + uint8_t tag_number; + uint8_t length; + /* following must be 00-A0-C6 */ + uint8_t oui[3]; + /* following must be 0x01 */ + uint8_t type; + uint8_t channel; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/* + * Host driver uses TBTT info of length 13 + * in the RNR IE for legacy SAPs. + */ +#define CURRENT_RNR_TBTT_INFO_LEN 13 + +typedef struct sSirCountryInformation { + uint8_t countryString[COUNTRY_STRING_LENGTH]; + uint8_t numIntervals; /* number of channel intervals */ + struct channelPowerLim { + uint8_t channelNumber; + uint8_t numChannel; + uint8_t maxTransmitPower; + } channelTransmitPower[COUNTRY_INFO_MAX_CHANNEL]; +} tSirCountryInformation, *tpSirCountryInformation; + +#ifdef WLAN_FEATURE_FILS_SK +#define SIR_MAX_IDENTIFIER_CNT 7 +#define SIR_CACHE_IDENTIFIER_LEN 2 +#define SIR_HESSID_LEN 6 +#define SIR_MAX_KEY_CNT 7 +#define SIR_MAX_KEY_LEN 48 +#define SIR_FILS_IND_ELEM_OFFSET 2 +/* + * struct public_key_identifier: structure for public key identifier + * present in fils indication element + * @is_present: if Key info is present + * @key_cnt: number of keys present + * @key_type: type of key used + * @length: length of key + * @key: key data + */ +struct public_key_identifier { + bool is_present; + uint8_t key_cnt; + uint8_t key_type; + uint8_t length; + uint8_t key[SIR_MAX_KEY_CNT][SIR_MAX_KEY_LEN]; +}; + +/* + * struct fils_cache_identifier: structure for fils cache identifier + * present in fils indication element + * @is_present: if cache identifier is present + * @identifier: cache identifier + */ +struct fils_cache_identifier { + bool is_present; + uint8_t identifier[SIR_CACHE_IDENTIFIER_LEN]; +}; + +/* + * struct fils_hessid: structure for fils hessid + * present in fils indication element + * @is_present: if hessid info is present + * @hessid: hessid data + */ +struct fils_hessid { + bool is_present; + uint8_t hessid[SIR_HESSID_LEN]; +}; + +/* + * struct fils_realm_identifier: structure for fils_realm_identifier + * present in fils indication element + * @is_present: if realm info is present + * @realm_cnt: realm count + * @realm: realm data + */ +struct fils_realm_identifier { + bool is_present; + uint8_t realm_cnt; + uint8_t realm[SIR_MAX_REALM_COUNT][SIR_REALM_LEN]; +}; + +/* + * struct sir_fils_indication: structure for fils indication element + * @is_present: if indication element is present + * @is_ip_config_supported: if IP config is supported + * @is_fils_sk_auth_supported: if fils sk suppprted + * @is_fils_sk_auth_pfs_supported: if fils sk with pfs supported + * @is_pk_auth_supported: if fils public key supported + * @cache_identifier: fils cache idenfier info + * @hessid: fils hessid info + * @realm_identifier: fils realm info + * @key_identifier: fils key identifier info + */ +struct sir_fils_indication { + bool is_present; + uint8_t is_ip_config_supported; + uint8_t is_fils_sk_auth_supported; + uint8_t is_fils_sk_auth_pfs_supported; + uint8_t is_pk_auth_supported; + struct fils_cache_identifier cache_identifier; + struct fils_hessid hessid; + struct fils_realm_identifier realm_identifier; + struct public_key_identifier key_identifier; +}; +#endif + +enum operating_class_num { + OP_CLASS_131 = 131, + OP_CLASS_132, + OP_CLASS_133, + OP_CLASS_134, + OP_CLASS_135, + OP_CLASS_136, +}; + +enum operating_extension_identifier { + OP_CLASS_ID_200 = 200, + OP_CLASS_ID_201, +}; + +#ifdef WLAN_FEATURE_11BE_MLO +struct sir_multi_link_ie { + uint8_t num_of_mlo_ie; + bool mlo_ie_present; + struct wlan_mlo_ie mlo_ie; +}; +#endif + +/* Structure common to Beacons & Probe Responses */ +typedef struct sSirProbeRespBeacon { + tSirMacTimeStamp timeStamp; + uint16_t beaconInterval; + tSirMacCapabilityInfo capabilityInfo; + + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + uint32_t chan_freq; + tSirMacCfParamSet cfParamSet; + tSirMacTim tim; + tSirMacEdcaParamSetIE edcaParams; + tSirMacQosCapabilityIE qosCapability; + + tSirCountryInformation countryInfoParam; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + + tSirMacErpInfo erpIEInfo; + + tDot11fIEPowerConstraints localPowerConstraint; + tDot11fIETPCReport tpcReport; + tDot11fIEChanSwitchAnn channelSwitchIE; + tDot11fIEsec_chan_offset_ele sec_chan_offset; + tDot11fIEext_chan_switch_ann ext_chan_switch; + tDot11fIESuppOperatingClasses supp_operating_classes; + tSirMacAddr bssid; + tDot11fIEQuiet quietIE; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEP2PProbeRes P2PProbeRes; + uint8_t mdie[SIR_MDIE_SIZE]; +#ifdef FEATURE_WLAN_ESE + tDot11fIEESETxmitPower eseTxPwr; + tDot11fIEQBSSLoad QBSSLoad; +#endif + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + uint8_t supp_operating_class_present; + uint8_t cfPresent; + uint8_t dsParamsPresent; + uint8_t timPresent; + + uint8_t edcaPresent; + uint8_t qosCapabilityPresent; + uint8_t wmeEdcaPresent; + uint8_t wmeInfoPresent; + uint8_t wsmCapablePresent; + + uint8_t countryInfoPresent; + uint8_t wpaPresent; + uint8_t rsnPresent; + uint8_t erpPresent; + uint8_t channelSwitchPresent; + uint8_t sec_chan_offset_present; + uint8_t ext_chan_switch_present; + uint8_t quietIEPresent; + uint8_t tpcReportPresent; + uint8_t powerConstraintPresent; + + uint8_t mdiePresent; + + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEVHTExtBssLoad VHTExtBssLoad; + tDot11fIEExtCap ext_cap; + tDot11fIEOperatingMode OperatingMode; + uint8_t WiderBWChanSwitchAnnPresent; + tDot11fIEWiderBWChanSwitchAnn WiderBWChanSwitchAnn; + uint8_t Vendor1IEPresent; + tDot11fIEvendor_vht_ie vendor_vht_ie; + uint8_t Vendor3IEPresent; + tDot11fIEhs20vendor_ie hs20vendor_ie; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + tDot11fIEQComVendorIE AvoidChannelIE; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_ver_ie_present; +#endif + tDot11fIEOBSSScanParameters obss_scanparams; + bool MBO_IE_present; + uint8_t MBO_capability; + bool assoc_disallowed; + uint8_t assoc_disallowed_reason; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; +#ifdef WLAN_FEATURE_SR + tDot11fIEspatial_reuse srp_ie; +#endif + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; +#ifdef WLAN_FEATURE_11AX_BSS_COLOR + tDot11fIEbss_color_change vendor_he_bss_color_change; +#endif +#ifdef WLAN_FEATURE_FILS_SK + struct sir_fils_indication fils_ind; +#endif + uint8_t num_transmit_power_env; + tDot11fIEtransmit_power_env transmit_power_env[MAX_TPE_IES]; + uint8_t ap_power_type; +#ifdef WLAN_FEATURE_11BE_MLO + struct sir_multi_link_ie mlo_ie; + struct wlan_t2lm_context t2lm_ctx; +#endif + tDot11fIEWMMParams wmm_params; +} tSirProbeRespBeacon, *tpSirProbeRespBeacon; + +/* probe Request structure */ +typedef struct sSirProbeReq { + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tDot11fIEWscProbeReq probeReqWscIeInfo; + tDot11fIEHTCaps HTCaps; + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + uint8_t wscIePresent; + uint8_t p2pIePresent; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEhe_cap he_cap; +} tSirProbeReq, *tpSirProbeReq; + +/* / Association Request structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocReq { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t listenInterval; + tSirMacAddr currentApAddr; /* only in reassoc frames */ + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + + tSirAddtsReqInfo addtsReq; + tSirMacQosCapabilityStaIE qosCapability; + + tSirMacWapiInfo wapi; + tSirMacWpaInfo wpa; + tSirMacRsnInfo rsn; + tSirAddie addIE; + + tSirMacPowerCapabilityIE powerCapability; + tSirMacSupportedChannelIE supportedChannels; + tDot11fIEHTCaps HTCaps; + tDot11fIEWMMInfoStation WMMInfoStation; + tDot11fIESuppOperatingClasses supp_operating_classes; + /* / This is set if the frame is a reassoc request: */ + uint8_t reassocRequest; + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + + uint8_t wmeInfoPresent; + uint8_t qosCapabilityPresent; + uint8_t addtsPresent; + uint8_t wsmCapablePresent; + + uint8_t wapiPresent; + uint8_t wpaPresent; + uint8_t rsnPresent; + uint8_t addIEPresent; + + uint8_t powerCapabilityPresent; + uint8_t supportedChannelsPresent; + /* keeping copy of association request received, this is + required for indicating the frame to upper layers */ + qdf_nbuf_t assoc_req_buf; + uint32_t assocReqFrameLength; + uint8_t *assocReqFrame; + tDot11fIEVHTCaps VHTCaps; + tDot11fIEOperatingMode operMode; + tDot11fIEExtCap ExtCap; + tDot11fIEbss_max_idle_period bss_max_idle_period; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEhs20vendor_ie hs20vendor_ie; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEeht_cap eht_cap; + bool is_sae_authenticated; + struct mlo_partner_info mlo_info; + uint8_t mld_mac[QDF_MAC_ADDR_SIZE]; +} tSirAssocReq, *tpSirAssocReq; + +#define FTIE_SUBELEM_R1KH_ID 1 +#define FTIE_SUBELEM_GTK 2 +#define FTIE_SUBELEM_R0KH_ID 3 +#define FTIE_SUBELEM_IGTK 4 +#define FTIE_SUBELEM_OCI 5 + +#define FTIE_R1KH_LEN 6 +#define FTIE_R0KH_MAX_LEN 48 + +/** + * struct wlan_sha384_ftinfo_subelem - subelements of FTIE + * @r1kh_id: FT R1 Key holder ID + * @gtk: Ft group temporal key + * @gtk_len: GTK length + * @r0kh_id: FT R0 Key Holder ID + * @igtk: FT IGTK used for 11w + * @igtk_len: IGTK length + */ +struct wlan_sha384_ftinfo_subelem { + tDot11fIER1KH_ID r1kh_id; + uint8_t *gtk; + uint8_t gtk_len; + tDot11fIER0KH_ID r0kh_id; + uint8_t *igtk; + uint8_t igtk_len; +}; + +#define MIC_CONTROL_BYTES 2 +#define MIC_SHA384_BYTES 24 +#define NONCE_BYTES 32 + +/** + * struct wlan_sha384_ftinfo - FTE for sha384 based AKMs + * @mic_control: FTIE mic control field of 2 bytes + * @mic: MIC present in the FTIE assoc Response + * @anonce: Anonce sent by the AP + * @snonce: Snonce field in the FTIE + */ +struct wlan_sha384_ftinfo { + uint8_t mic_control[MIC_CONTROL_BYTES]; + uint8_t mic[MIC_SHA384_BYTES]; + uint8_t anonce[NONCE_BYTES]; + uint8_t snonce[NONCE_BYTES]; +}; + +/* / Association Response structure (one day to be replaced by */ +/* / tDot11fAssocRequest) */ +typedef struct sSirAssocRsp { + + tSirMacCapabilityInfo capabilityInfo; + uint16_t aid; + uint16_t status_code; + tSirMacRateSet supportedRates; + tSirMacRateSet extendedRates; + tSirMacEdcaParamSetIE edca; + tSirAddtsRspInfo addtsRsp; + tDot11fIEHTCaps HTCaps; + tDot11fIEHTInfo HTInfo; + tDot11fIEFTInfo FTInfo; + struct wlan_sha384_ftinfo sha384_ft_info; + struct wlan_sha384_ftinfo_subelem sha384_ft_subelem; + uint8_t mdie[SIR_MDIE_SIZE]; + uint8_t num_RICData; + tDot11fIERICDataDesc RICData[2]; + +#ifdef FEATURE_WLAN_ESE + uint8_t num_tspecs; + tDot11fIEWMMTSPEC TSPECInfo[ESE_MAX_TSPEC_IES]; + struct ese_tsm_ie tsmIE; +#endif + + uint8_t suppRatesPresent; + uint8_t extendedRatesPresent; + + uint8_t edcaPresent; + uint8_t wmeEdcaPresent; + uint8_t addtsPresent; + uint8_t wsmCapablePresent; + uint8_t ftinfoPresent; + uint8_t mdiePresent; + uint8_t ricPresent; +#ifdef FEATURE_WLAN_ESE + uint8_t tspecPresent; + uint8_t tsmPresent; +#endif + tDot11fIEVHTCaps VHTCaps; + tDot11fIEVHTOperation VHTOperation; + tDot11fIEExtCap ExtCap; + tDot11fIEOperatingMode oper_mode_ntf; + struct qos_map_set QosMapSet; + tDot11fIETimeoutInterval TimeoutInterval; + tDot11fIERRMEnabledCap rrm_caps; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tDot11fIEOBSSScanParameters obss_scanparams; + tDot11fTLVrssi_assoc_rej rssi_assoc_rej; + tDot11fIEqcn_ie qcn_ie; + tDot11fIEhe_cap he_cap; + tDot11fIEhe_op he_op; +#ifdef WLAN_FEATURE_SR + tDot11fIEspatial_reuse srp_ie; +#endif + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_op eht_op; + bool mu_edca_present; + tSirMacEdcaParamSetIE mu_edca; + tDot11fIEbss_max_idle_period bss_max_idle_period; +#ifdef WLAN_FEATURE_FILS_SK + tDot11fIEfils_session fils_session; + tDot11fIEfils_key_confirmation fils_key_auth; + tDot11fIEfils_kde fils_kde; + struct qdf_mac_addr dst_mac; + struct qdf_mac_addr src_mac; + uint16_t hlp_data_len; + uint8_t hlp_data[FILS_MAX_HLP_DATA_LEN]; +#endif +#ifdef WLAN_FEATURE_11BE_MLO + struct sir_multi_link_ie mlo_ie; + struct wlan_t2lm_context t2lm_ctx; +#endif +} tSirAssocRsp, *tpSirAssocRsp; + +#ifdef FEATURE_WLAN_ESE +/* Structure to hold ESE Beacon report mandatory IEs */ +typedef struct sSirEseBcnReportMandatoryIe { + tSirMacSSid ssId; + tSirMacRateSet supportedRates; + tSirMacFHParamSet fhParamSet; + tSirMacDsParamSetIE dsParamSet; + tSirMacCfParamSet cfParamSet; + tSirMacTim tim; + tSirMacRRMEnabledCap rmEnabledCapabilities; + + uint8_t ssidPresent; + uint8_t suppRatesPresent; + uint8_t fhParamPresent; + uint8_t dsParamsPresent; + uint8_t cfPresent; + uint8_t timPresent; + uint8_t rrmPresent; +} tSirEseBcnReportMandatoryIe, *tpSirEseBcnReportMandatoryIe; +#endif /* FEATURE_WLAN_ESE */ + +/** + * struct s_ext_cap - holds bitfields of extended capability IE + * + * s_ext_cap holds bitfields of extended capability IE. In dot11f files + * extended capability IE information is stored as an array of bytes. + * This structure is used to encode/decode the byte array present in + * dot11f IE structure. + */ + +struct s_ext_cap { + uint8_t bss_coexist_mgmt_support:1; + uint8_t reserved1:1; + uint8_t ext_chan_switch:1; + uint8_t reserved2:1; + uint8_t psmp_cap:1; + uint8_t reserved3:1; + uint8_t spsmp_cap:1; + uint8_t event:1; + uint8_t diagnostics:1; + uint8_t multi_diagnostics:1; + uint8_t loc_tracking:1; + uint8_t fms:1; + uint8_t proxy_arp_service:1; + uint8_t co_loc_intf_reporting:1; + uint8_t civic_loc:1; + uint8_t geospatial_loc:1; + uint8_t tfs:1; + uint8_t wnm_sleep_mode:1; + uint8_t tim_broadcast:1; + uint8_t bss_transition:1; + uint8_t qos_traffic_cap:1; + uint8_t ac_sta_cnt:1; + uint8_t multi_bssid:1; + uint8_t timing_meas:1; + uint8_t chan_usage:1; + uint8_t ssid_list:1; + uint8_t dms:1; + uint8_t utctsf_offset:1; + uint8_t tdls_peer_uapsd_buffer_sta:1; + uint8_t tdls_peer_psm_supp:1; + uint8_t tdls_channel_switching:1; + uint8_t interworking_service:1; + uint8_t qos_map:1; + uint8_t ebr:1; + uint8_t sspn_interface:1; + uint8_t reserved4:1; + uint8_t msg_cf_cap:1; + uint8_t tdls_support:1; + uint8_t tdls_prohibited:1; + uint8_t tdls_chan_swit_prohibited:1; + uint8_t reject_unadmitted_traffic:1; + uint8_t service_interval_granularity:3; + uint8_t identifier_loc:1; + uint8_t uapsd_coexistence:1; + uint8_t wnm_notification:1; + uint8_t qa_bcapbility:1; + uint8_t utf8_ssid:1; + uint8_t qmf_activated:1; + uint8_t qm_frecon_act:1; + uint8_t robust_av_streaming:1; + uint8_t advanced_gcr:1; + uint8_t mesh_gcr:1; + uint8_t scs:1; + uint8_t q_load_report:1; + uint8_t alternate_edca:1; + uint8_t unprot_txo_pneg:1; + uint8_t prot_txo_pneg:1; + uint8_t reserved6:1; + uint8_t prot_q_load_report:1; + uint8_t tdls_wider_bw:1; + uint8_t oper_mode_notification:1; + uint8_t max_num_of_msdu_bit1:1; + uint8_t max_num_of_msdu_bit2:1; + uint8_t chan_sch_mgmt:1; + uint8_t geo_db_inband_en_signal:1; + uint8_t nw_chan_control:1; + uint8_t white_space_map:1; + uint8_t chan_avail_query:1; + uint8_t fine_time_meas_responder:1; + uint8_t fine_time_meas_initiator:1; + uint8_t fils_capability:1; + uint8_t ext_spectrum_management:1; + uint8_t future_channel_guidance:1; + uint8_t reserved7:2; + uint8_t twt_requestor_support:1; + uint8_t twt_responder_support:1; + uint8_t reserved8: 1; + uint8_t reserved9: 4; + uint8_t beacon_protection_enable: 1; +}; + +void swap_bit_field16(uint16_t in, uint16_t *out); + +/* Currently implemented as "shims" between callers & the new framesc- */ +/* generated code: */ + +QDF_STATUS +sir_convert_probe_req_frame2_struct(struct mac_context *mac, + uint8_t *frame, uint32_t len, + tpSirProbeReq probe); + +QDF_STATUS +sir_convert_probe_frame2_struct(struct mac_context *mac, uint8_t *frame, + uint32_t len, tpSirProbeRespBeacon probe); + +enum wlan_status_code +sir_convert_assoc_req_frame2_struct(struct mac_context *mac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); +/** + * wlan_parse_ftie_sha384() - Parse the FT IE if akm uses sha384 KDF + * @frame: Pointer to the association response frame + * @frame_len: Length of the assoc response frame + * @assoc_rsp: Destination assoc response structure in PE to which the FTIE + * needs to be parsed and copied + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlan_parse_ftie_sha384(uint8_t *frame, uint32_t frame_len, + struct sSirAssocRsp *assoc_rsp); + +QDF_STATUS +sir_convert_assoc_resp_frame2_struct(struct mac_context *mac, + struct pe_session *session_entry, + uint8_t *frame, uint32_t len, + tpSirAssocRsp assoc); + +enum wlan_status_code +sir_convert_reassoc_req_frame2_struct(struct mac_context *mac, + uint8_t *frame, uint32_t len, + tpSirAssocReq assoc); + +QDF_STATUS +sir_parse_beacon_ie(struct mac_context *mac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t payloadLength); + +QDF_STATUS +sir_convert_beacon_frame2_struct(struct mac_context *mac, + uint8_t *pBeaconFrame, + tpSirProbeRespBeacon pBeaconStruct); + +QDF_STATUS +sir_convert_auth_frame2_struct(struct mac_context *mac, + uint8_t *frame, uint32_t len, + tpSirMacAuthFrameBody auth); + +QDF_STATUS +sir_convert_addts_rsp2_struct(struct mac_context *mac, + uint8_t *frame, uint32_t len, + tSirAddtsRspInfo *addts); + +QDF_STATUS +sir_convert_delts_req2_struct(struct mac_context *mac, + uint8_t *frame, uint32_t len, + struct delts_req_info *delTs); +QDF_STATUS +sir_convert_qos_map_configure_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, uint32_t nFrame, + struct qos_map_set *pQosMapSet); + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +sir_convert_mlo_probe_rsp_frame2_struct(uint8_t *ml_ie, + uint32_t ml_ie_total_len, + struct sir_multi_link_ie *mlo_ie_ptr); + +QDF_STATUS +populate_dot11f_mlo_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct wlan_mlo_ie *mlo_ie); +#endif + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +sir_convert_tpc_req_frame2_struct(struct mac_context *, uint8_t *, + tpSirMacTpcReqActionFrame, uint32_t); + +QDF_STATUS +sir_convert_meas_req_frame2_struct(struct mac_context *, uint8_t *, + tpSirMacMeasReqActionFrame, uint32_t); +#endif + +/** + * \brief Populated a tDot11fFfCapabilities + * + * \param mac Pointer to the global MAC data structure + * + * \param pDot11f Address of a tDot11fFfCapabilities to be filled in + * + * + * \note If SIR_MAC_PROP_CAPABILITY_11EQOS is enabled, we'll clear the QOS + * bit in pDot11f + * + * + */ + +QDF_STATUS +populate_dot11f_capabilities(struct mac_context *mac, + tDot11fFfCapabilities *pDot11f, + struct pe_session *pe_session); +/** + * populate_dot11f_max_chan_switch_time() - populate max chan switch time + * @mac: pointer to mac + * @pDot11f: pointer to tDot11fIEmax_chan_switch_time + * @pe_session: pe session + * + * Return: Void + */ +void +populate_dot11f_max_chan_switch_time(struct mac_context *mac, + tDot11fIEmax_chan_switch_time *pDot11f, + struct pe_session *pe_session); + +/** + * populate_dot11f_non_inheritance() - populate non inheritance + * @mac_ctx: pointer to mac + * @non_inheritance: pointer to tDot11fIEnon_inheritance + * @non_inher_ie_lists: non inheritance IE list + * @non_inher_ext_ie_lists: non inheritance extend IE list + * @non_inher_len: non inheritance IE list length + * @non_inher_ext_len: non inheritance Extend IE list length + */ +void populate_dot11f_non_inheritance( + struct mac_context *mac_ctx, + tDot11fIEnon_inheritance *non_inheritance, + uint8_t *non_inher_ie_lists, + uint8_t *non_inher_ext_ie_lists, + uint8_t non_inher_len, uint8_t non_inher_ext_len); + +/* / Populate a tDot11fIEChanSwitchAnn */ +void +populate_dot11f_chan_switch_ann(struct mac_context *mac, + tDot11fIEChanSwitchAnn *pDot11f, + struct pe_session *pe_session); + +void +populate_dot_11_f_ext_chann_switch_ann(struct mac_context *mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + struct pe_session *session_entry); + +void +populate_dot11f_tx_power_env(struct mac_context *mac, + tDot11fIEtransmit_power_env *pDot11f, + enum phy_ch_width ch_width, uint32_t chan_freq, + uint16_t *num_tpe, bool is_ch_switch); + +/* / Populate a tDot11fIEChannelSwitchWrapper */ +void +populate_dot11f_chan_switch_wrapper(struct mac_context *mac, + tDot11fIEChannelSwitchWrapper *pDot11f, + struct pe_session *pe_session); + +/* / Populate a tDot11fIECountry */ +QDF_STATUS +populate_dot11f_country(struct mac_context *mac, + tDot11fIECountry *pDot11f, struct pe_session *pe_session); + +/* Populated a populate_dot11f_ds_params */ +QDF_STATUS +populate_dot11f_ds_params(struct mac_context *mac, + tDot11fIEDSParams *pDot11f, qdf_freq_t freq); + +/* / Populated a tDot11fIEEDCAParamSet */ +void +populate_dot11f_edca_param_set(struct mac_context *mac, + tDot11fIEEDCAParamSet *pDot11f, + struct pe_session *pe_session); + +QDF_STATUS +populate_dot11f_erp_info(struct mac_context *mac, + tDot11fIEERPInfo *pDot11f, struct pe_session *pe_session); + +QDF_STATUS +populate_dot11f_ext_supp_rates(struct mac_context *mac, + uint8_t nChannelNum, tDot11fIEExtSuppRates *pDot11f, + struct pe_session *pe_session); + +/** + * populate_dot11f_beacon_report() - Populate the Beacon Report IE + * @mac: Pointer to the global MAC context + * @pDot11f: Pointer to the measurement report structure + * @pBeaconReport: Pointer to the Beacon Report structure + * @is_last_frame: is the current report last or more reports to follow + * + * Return: QDF Status + */ +QDF_STATUS +populate_dot11f_beacon_report(struct mac_context *mac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport, + bool is_last_frame); + +/** + * populate_dot11f_chan_load_report() - populate the chan load Report IE + * @mac: pointer to the global MAC context + * @dot11f: pointer to the measurement report structure + * @channel_load_report: pointer to the chan load Report structure + * + * Return: none + */ +void +populate_dot11f_chan_load_report(struct mac_context *mac, + tDot11fIEMeasurementReport *dot11f, + struct chan_load_report *channel_load_report); + +/** + * populate_dot11f_rrm_sta_stats_report() - Populate RRM STA STATS Report IE + * @mac: Pointer to the global MAC context + * @pdot11f: Pointer to the measurement report structure + * @statistics_report: Pointer to the RRM STA STATS Report structure + * + * Return: QDF Status + */ +QDF_STATUS +populate_dot11f_rrm_sta_stats_report( + struct mac_context *mac, tDot11fIEMeasurementReport *pdot11f, + struct statistics_report *statistics_report); + +/** + * \brief Populate a tDot11fIEExtSuppRates + * + * + * \param mac Pointer to the global MAC data structure + * + * \param nChannelNum Channel on which the enclosing frame will be going out + * + * \param pDot11f Address of a tDot11fIEExtSuppRates struct to be filled in. + * + * + * This method is a NOP if the channel is greater than 14. + * + * + */ + +QDF_STATUS +populate_dot11f_ext_supp_rates1(struct mac_context *mac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f); + +QDF_STATUS +populate_dot11f_ht_caps(struct mac_context *mac, + struct pe_session *pe_session, tDot11fIEHTCaps *pDot11f); + +QDF_STATUS +populate_dot11f_ht_info(struct mac_context *mac, + tDot11fIEHTInfo *pDot11f, struct pe_session *pe_session); + + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +populate_dot11f_measurement_report0(struct mac_context *mac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is CCA */ +QDF_STATUS +populate_dot11f_measurement_report1(struct mac_context *mac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); + +/* / Populate a tDot11fIEMeasurementReport when the report type is RPI Hist */ +QDF_STATUS +populate_dot11f_measurement_report2(struct mac_context *mac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f); +#endif /* ANI_SUPPORT_11H */ + +/* / Populate a tDot11fIEPowerCaps */ +void +populate_dot11f_power_caps(struct mac_context *mac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, struct pe_session *pe_session); + +/* / Populate a tDot11fIEPowerConstraints */ +QDF_STATUS +populate_dot11f_power_constraints(struct mac_context *mac, + tDot11fIEPowerConstraints *pDot11f); + +void +populate_dot11f_qos_caps_station(struct mac_context *mac, struct pe_session *session, + tDot11fIEQOSCapsStation *pDot11f); + +QDF_STATUS +populate_dot11f_rsn(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f); + +QDF_STATUS +populate_dot11f_rsn_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIERSNOpaque *pDot11f); + +#if defined(FEATURE_WLAN_WAPI) +QDF_STATUS +populate_dot11f_wapi(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f); + +QDF_STATUS populate_dot11f_wapi_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f); +#else +static inline QDF_STATUS +populate_dot11f_wapi(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +populate_dot11f_wapi_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* defined(FEATURE_WLAN_WAPI) */ + +/* / Populate a tDot11fIESSID given a tSirMacSSid */ +void +populate_dot11f_ssid(struct mac_context *mac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f); + +/* / Populate a tDot11fIESSID from CFG */ +QDF_STATUS populate_dot11f_ssid2(struct pe_session *pe_session, + tDot11fIESSID *pDot11f); + +/** + * \brief Populate a tDot11fIESchedule + * + * \sa populate_dot11f_wmm_schedule + * + * + * \param pSchedule Address of a tSirMacScheduleIE struct + * + * \param pDot11f Address of a tDot11fIESchedule to be filled in + * + * + */ + +void +populate_dot11f_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIESchedule *pDot11f); + +void +populate_dot11f_supp_channels(struct mac_context *mac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, struct pe_session *pe_session); + +/** + * \brief Populated a tDot11fIESuppRates + * + * + * \param mac Pointer to the global MAC data structure + * + * \param nChannelNum Channel the enclosing frame will be going out on; see + * below + * + * \param pDot11f Address of a tDot11fIESuppRates struct to be filled in. + * + * + * If nChannelNum is greater than 13, the supported rates will be + * WNI_CFG_SUPPORTED_RATES_11B. If it is less than or equal to 13, the + * supported rates will be WNI_CFG_SUPPORTED_RATES_11A. If nChannelNum is + * set to the sentinel value POPULATE_DOT11F_RATES_OPERATIONAL, the struct + * will be populated with WNI_CFG_OPERATIONAL_RATE_SET. + * + * + */ + +#define POPULATE_DOT11F_RATES_OPERATIONAL (0xff) + +QDF_STATUS +populate_dot11f_supp_rates(struct mac_context *mac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, struct pe_session *); + +QDF_STATUS +populate_dot11f_rates_tdls(struct mac_context *p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates, + uint8_t curr_oper_channel); + +QDF_STATUS populate_dot11f_tpc_report(struct mac_context *mac, + tDot11fIETPCReport *pDot11f, + struct pe_session *pe_session); + +/* / Populate a tDot11FfTSInfo */ +void populate_dot11f_ts_info(struct mac_ts_info *pInfo, + tDot11fFfTSInfo *pDot11f); + +void populate_dot11f_wmm(struct mac_context *mac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, struct pe_session *pe_session); + +void populate_dot11f_wmm_caps(tDot11fIEWMMCaps *pCaps); + +#if defined(FEATURE_WLAN_ESE) +/* Fill the ESE version IE */ +void populate_dot11f_ese_version(tDot11fIEESEVersion *pESEVersion); +/* Fill the Radio Management Capability */ +void populate_dot11f_ese_rad_mgmt_cap(tDot11fIEESERadMgmtCap *pESERadMgmtCap); +/* Fill the CCKM IE */ +QDF_STATUS populate_dot11f_ese_cckm_opaque(struct mac_context *mac, + struct mlme_connect_info *connect_info, + tDot11fIEESECckmOpaque *pDot11f); + +void populate_dot11_tsrsie(struct mac_context *mac, + struct ese_tsrs_ie *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length); +#ifdef WLAN_FEATURE_HOST_ROAM +void populate_dot11f_re_assoc_tspec(struct mac_context *mac, + tDot11fReAssocRequest *pReassoc, + struct pe_session *pe_session); +#endif +QDF_STATUS +sir_beacon_ie_ese_bcn_report(struct mac_context *mac, + uint8_t *pPayload, const uint32_t payloadLength, + uint8_t **outIeBuf, uint32_t *pOutIeLen); + +/** + * ese_populate_wmm_tspec() - Populates TSPEC info for + * reassoc + * @source: source structure + * @dest: destination structure + * + * This function copies TSPEC parameters from source + * structure to destination structure. + * + * Return: None + */ +void ese_populate_wmm_tspec(struct mac_tspec_ie *source, + ese_wmm_tspec_ie *dest); + +#endif + +void populate_dot11f_wmm_info_ap(struct mac_context *mac, + tDot11fIEWMMInfoAp *pInfo, + struct pe_session *pe_session); + +void populate_dot11f_wmm_info_station_per_session(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEWMMInfoStation *pInfo); + +void populate_dot11f_wmm_params(struct mac_context *mac, + tDot11fIEWMMParams *pParams, + struct pe_session *pe_session); + +QDF_STATUS +populate_dot11f_wpa(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f); + +QDF_STATUS +populate_dot11f_wpa_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIEWPAOpaque *pDot11f); + +void populate_dot11f_tspec(struct mac_tspec_ie *pOld, tDot11fIETSPEC *pDot11f); + +void populate_dot11f_wmmtspec(struct mac_tspec_ie *pOld, + tDot11fIEWMMTSPEC *pDot11f); + +#ifdef WLAN_FEATURE_MSCS +void +populate_dot11f_mscs_dec_element(struct mscs_req_info *mscs_req, + tDot11fmscs_request_action_frame *dot11f); +#endif + +QDF_STATUS +populate_dot11f_tclas(struct mac_context *mac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f); + +QDF_STATUS +populate_dot11f_wmmtclas(struct mac_context *mac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f); + +QDF_STATUS populate_dot11f_wsc(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f); + +QDF_STATUS populate_dot11f_wsc_registrar_info(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f); + +QDF_STATUS de_populate_dot11f_wsc_registrar_info(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f); + +QDF_STATUS populate_dot11f_probe_res_wpsi_es(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f, + struct pe_session *pe_session); +QDF_STATUS populate_dot11f_beacon_wpsi_es(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f, + struct pe_session *pe_session); + +QDF_STATUS populate_dot11f_wsc_in_probe_res(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f); + +QDF_STATUS +populate_dot11f_wsc_registrar_info_in_probe_res(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f); + +QDF_STATUS +de_populate_dot11f_wsc_registrar_info_in_probe_res(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f); + +QDF_STATUS populate_dot11_assoc_res_p2p_ie(struct mac_context *mac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq); + +QDF_STATUS populate_dot11f_wfatpc(struct mac_context *mac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin); + +QDF_STATUS populate_dot11f_rrm_ie(struct mac_context *mac, + tDot11fIERRMEnabledCap *pDot11f, + struct pe_session *pe_session); + +void populate_mdie(struct mac_context *mac, tDot11fIEMobilityDomain *pDot11f, + uint8_t mdie[]); + +#ifdef WLAN_FEATURE_FILS_SK +/** + * populate_fils_ft_info() - Populate FTIE into assoc request frame + * @mac: Global mac context + * @ft_info: pointer to assoc request frame FT IE buffer + * @pe_session: pointer to PE session + * + * Return: None + */ +void populate_fils_ft_info(struct mac_context *mac, tDot11fIEFTInfo *ft_info, + struct pe_session *pe_session); +#else +static inline +void populate_fils_ft_info(struct mac_context *mac, tDot11fIEFTInfo *ft_info, + struct pe_session *pe_session) +{} +#endif + +void populate_dot11f_assoc_rsp_rates(struct mac_context *mac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates); + +int find_ie_location(struct mac_context *mac, tpSirRSNie pRsnIe, uint8_t EID); + +/** + * wlan_get_cb_mode() - Get channel bonding mode from beacon + * @mac: Global mac context + * @ch_freq: channel frequency + * @ie_struct: beacon ie struct + * @pe_session: pointer to PE session + * + * Return: ePhyChanBondState + */ +ePhyChanBondState wlan_get_cb_mode(struct mac_context *mac, + qdf_freq_t ch_freq, + tDot11fBeaconIEs *ie_struct, + struct pe_session *pe_session); + +void lim_log_vht_cap(struct mac_context *mac, tDot11fIEVHTCaps *pDot11f); + +QDF_STATUS +populate_dot11f_vht_caps(struct mac_context *mac, struct pe_session *pe_session, + tDot11fIEVHTCaps *pDot11f); + +QDF_STATUS +populate_dot11f_vht_operation(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEVHTOperation *pDot11f); + +QDF_STATUS +populate_dot11f_ext_cap(struct mac_context *mac, bool isVHTEnabled, + tDot11fIEExtCap *pDot11f, struct pe_session *pe_session); + +void populate_dot11f_qcn_ie(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEqcn_ie *qcn_ie, + uint8_t attr_id); + +void populate_dot11f_bss_max_idle(struct mac_context *mac, + struct pe_session *session, + tDot11fIEbss_max_idle_period *max_idle_ie); + +#ifdef WLAN_FEATURE_FILS_SK +/** + * populate_dot11f_fils_params() - Populate FILS IE to frame + * @mac_ctx: global mac context + * @frm: Assoc request frame + * @pe_session: PE session + * + * This API is used to populate FILS IE to Association request + * + * Return: None + */ +void populate_dot11f_fils_params(struct mac_context *mac_ctx, + tDot11fAssocRequest * frm, + struct pe_session *pe_session); +#else +static inline void populate_dot11f_fils_params(struct mac_context *mac_ctx, + tDot11fAssocRequest *frm, + struct pe_session *pe_session) +{ } +#endif + +QDF_STATUS +populate_dot11f_operating_mode(struct mac_context *mac, + tDot11fIEOperatingMode *pDot11f, + struct pe_session *pe_session); + +void populate_dot11f_timeout_interval(struct mac_context *mac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* Populate a tDot11fIEQComVendorIE */ +void +populate_dot11f_avoid_channel_ie(struct mac_context *mac_ctx, + tDot11fIEQComVendorIE *dot11f, + struct pe_session *session_entry); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +QDF_STATUS populate_dot11f_timing_advert_frame(struct mac_context *mac, + tDot11fTimingAdvertisementFrame *frame); +void populate_dot11_supp_operating_classes(struct mac_context *mac_ptr, + tDot11fIESuppOperatingClasses *dot_11_ptr, struct pe_session *session_entry); + +QDF_STATUS +sir_validate_and_rectify_ies(struct mac_context *mac_ctx, + uint8_t *mgmt_frame, + uint32_t frame_bytes, + uint32_t *missing_rsn_bytes); +/** + * sir_copy_caps_info() - Copy Caps info from tDot11fFfCapabilities to + * beacon/probe response structure. + * @mac_ctx: MAC Context + * @caps: tDot11fFfCapabilities structure + * @pProbeResp: beacon/probe response structure + * + * Copy the caps info to beacon/probe response structure + * + * Return: None + */ +void sir_copy_caps_info(struct mac_context *mac_ctx, tDot11fFfCapabilities caps, + tpSirProbeRespBeacon pProbeResp); + +#ifdef WLAN_FEATURE_FILS_SK +/** + * update_fils_data: update fils params from beacon/probe response + * @fils_ind: pointer to sir_fils_indication + * @fils_indication: pointer to tDot11fIEfils_indication + * + * Return: None + */ +void update_fils_data(struct sir_fils_indication *fils_ind, + tDot11fIEfils_indication * fils_indication); +#endif +#ifdef WLAN_FEATURE_11AX +/** + * populate_dot11f_he_caps() - populate he capabilities IE + * in beacon/probe response structure + * @mac_context: pointer to mac context + * @pe_session: pointer to pe session + * @he_cap: he capability IE + * + * Return: QDF_STATUS + */ +QDF_STATUS populate_dot11f_he_caps(struct mac_context *, struct pe_session *, + tDot11fIEhe_cap *); + +/** + * populate_dot11f_he_caps_by_band() - pouldate HE Capability IE by band + * @mac_ctx: Global MAC context + * @is_2g: is 2G band + * @eht_cap: pointer to HE capability IE + * @session: pointer to pe session + * + * Populate the HE capability IE based on band. + */ +QDF_STATUS +populate_dot11f_he_caps_by_band(struct mac_context *mac_ctx, + bool is_2g, + tDot11fIEhe_cap *he_cap, + struct pe_session *session); + +/** + * populate_dot11f_he_operation() - populate he operation IE + * in beacon/probe response structure + * @mac_context: pointer to mac context + * @pe_session: pointer to pe session + * @he_op: he operation IE + * + * Return: QDF_STATUS + */ +QDF_STATUS populate_dot11f_he_operation(struct mac_context *, struct pe_session *, + tDot11fIEhe_op *); + +/** + * populate_dot11f_sr_info() - populate tDot11fIEspatial_reuse to + * beacon/probe response structure. + * @mac_context: pointer to mac context + * @pe_session: pointer to pe session + * @sr_info: spatial reuse IE + * + * Return: QDF_STATUS + */ +QDF_STATUS populate_dot11f_sr_info(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEspatial_reuse *sr_info); + +/** + * populate_dot11f_he_6ghz_cap() - populdate HE 6GHz caps IE + * @mac_ctx: Global MAC context + * @session: PE session + * @he_6g_cap: pointer to HE 6GHz IE + * + * Populdate the HE 6GHz IE based on the session. + */ +QDF_STATUS +populate_dot11f_he_6ghz_cap(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEhe_6ghz_band_cap *he_6g_cap); +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +QDF_STATUS populate_dot11f_he_bss_color_change(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbss_color_change *bss_color); +#else +static inline QDF_STATUS populate_dot11f_he_bss_color_change( + struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbss_color_change *bss_color) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#else +static inline QDF_STATUS populate_dot11f_he_caps(struct mac_context *mac_ctx, + struct pe_session *session, tDot11fIEhe_cap *he_cap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +populate_dot11f_he_caps_by_band(struct mac_context *mac_ctx, + bool is_2g, + tDot11fIEhe_cap *he_cap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS populate_dot11f_he_operation(struct mac_context *mac_ctx, + struct pe_session *session, tDot11fIEhe_op *he_op) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +populate_dot11f_he_6ghz_cap(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEhe_6ghz_band_cap *he_6g_cap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS populate_dot11f_he_bss_color_change( + struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbss_color_change *bss_color) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS populate_dot11f_sr_info( + struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEspatial_reuse *sr_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(WLAN_FEATURE_11AX) && defined(WLAN_SUPPORT_TWT) +/** + * populate_dot11f_twt_extended_caps() - populate TWT extended capabilities + * @mac_ctx: Global MAC context. + * @pe_session: Pointer to the PE session. + * @dot11f: Pointer to the extended capabilities of the session. + * + * Populate the TWT extended capabilities based on the target and INI support. + * + * Return: QDF_STATUS Success or Failure + */ +QDF_STATUS populate_dot11f_twt_extended_caps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEExtCap *dot11f); +#else +static inline +QDF_STATUS populate_dot11f_twt_extended_caps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEExtCap *dot11f) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * populate_dot11f_assoc_rsp_mlo_ie() - populate mlo ie for assoc response + * @mac_ctx: Global MAC context + * @session: PE session + * @sta: Pointer to tpDphHashNode + * @frm: Assoc response frame + * + * Return: QDF_STATUS_SUCCESS of no error + */ +QDF_STATUS populate_dot11f_assoc_rsp_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tpDphHashNode sta, + tDot11fAssocResponse *frm); + +/** + * populate_dot11f_bcn_mlo_ie() - populate mlo ie for beacon + * @mac_ctx: Global MAC context + * @session: PE session + * + * Return: QDF_STATUS_SUCCESS of no error + */ +QDF_STATUS populate_dot11f_bcn_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * populate_dot11f_probe_req_mlo_ie() - populate mlo ie for probe req + * @mac_ctx: Global MAC context + * @session: PE session + * + * Return: QDF_STATUS_SUCCESS of no error + */ +QDF_STATUS populate_dot11f_probe_req_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * populate_dot11f_tdls_mgmt_mlo_ie() - populate mlo ie for tdls mgmt frame + * @mac_ctx: Global MAC context + * @session: PE session + * + * Return: QDF_STATUS_SUCCESS of no error + */ +QDF_STATUS populate_dot11f_tdls_mgmt_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * populate_dot11f_mlo_rnr() - populate rnr for mlo + * @mac_ctx: Global MAC context + * @session: PE session + * @dot11f: tDot11fIEreduced_neighbor_report to be filled + * + * Return: void + */ +void populate_dot11f_mlo_rnr(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEreduced_neighbor_report *dot11f); + +/** + * populate_dot11f_rnr_tbtt_info_16() - populate rnr with tbtt_info length 16 + * @mac_ctx: pointer to mac_context + * @pe_session: pe session + * @rnr_session: session to populate in rnr ie + * @dot11f: tDot11fIEreduced_neighbor_report to be filled + * + * Return: void + */ +void populate_dot11f_rnr_tbtt_info_16(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f); + +#else +static inline void populate_dot11f_mlo_rnr( + struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEreduced_neighbor_report *dot11f) +{ +} + +static inline void populate_dot11f_rnr_tbtt_info_16( + struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#ifdef WLAN_FEATURE_11BE +/** + * populate_dot11f_eht_caps() - pouldate EHT Capability IE + * @mac_ctx: Global MAC context + * @session: PE session + * @eht_cap: pointer to EHT capability IE + * + * Populate the EHT capability IE based on the session. + */ +QDF_STATUS populate_dot11f_eht_caps(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEeht_cap *eht_cap); + +/** + * populate_dot11f_eht_caps_by_band() - pouldate EHT Capability IE by band + * @mac_ctx: Global MAC context + * @is_2g: is 2G band + * @eht_cap: pointer to EHT capability IE + * @session: pe session + * + * Populate the EHT capability IE based on band. + */ +QDF_STATUS +populate_dot11f_eht_caps_by_band(struct mac_context *mac_ctx, + bool is_2g, tDot11fIEeht_cap *eht_cap, + struct pe_session *session); + +/** + * populate_dot11f_eht_operation() - pouldate EHT Operation IE + * @mac_ctx: Global MAC context + * @session: PE session + * @eht_op: pointer to EHT Operation IE + * + * Populdate the EHT Operation IE based on the session. + */ +QDF_STATUS populate_dot11f_eht_operation(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEeht_op *eht_op); + +/** + * populate_dot11f_bw_ind_element() - pouldate bandwidth ind element + * @mac_ctx: Global MAC context + * @session: PE session + * @bw_ind: pointer to bw ind element IE + * + * QDF_STATUS + */ +QDF_STATUS populate_dot11f_bw_ind_element(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbw_ind_element *bw_ind); + +/** + * lim_ieee80211_pack_ehtcap() - Pack EHT capabilities IE + * @ie: output pointer for eht capabilities IE + * @dot11f_eht_cap: dot11f EHT capabilities IE structure + * @dot11f_he_cap: dot11f HE capabilities IE structure + * @is_band_2g: Flag to indicate whether operating band is 2g or not + * + * This API is used to encode EHT capabilities IE which is of variable in + * length depending on the HE capabilities IE content. + * + * Return: Void + */ +void lim_ieee80211_pack_ehtcap(uint8_t *ie, tDot11fIEeht_cap dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, bool is_band_2g); + +/** + * lim_strip_and_decode_eht_cap() - API to decode EHT capabilities IE + * @ie: source ie address + * @ie_len: source ie length + * @dot11f_eht_cap: output pointer to dot11f EHT capabilities IE structure + * @dot11f_he_cap: dot11f HE capabilities IE structure + * @freq: frequency + * + * This API is used to strip and decode EHT caps IE which is of variable in + * length depending on the HE capabilities IE content. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len, + tDot11fIEeht_cap *dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, + uint16_t freq); + +/** + * lim_ieee80211_pack_ehtop() - Pack EHT Operations IE + * @ie: output pointer for eht operations IE + * @dot11f_eht_cap: dot11f EHT operations IE structure + * @dot11f_vht_op: dot11f VHT operation IE structure + * @dot11f_he_op: dot11f HE operation IE structure + * @dot11f_ht_info: dot11f HT info IE structure + * + * This API is used to encode EHT operations IE which is of variable in + * length depending on the HE capabilities IE content. + * + * Return: Void + */ +void lim_ieee80211_pack_ehtop(uint8_t *ie, tDot11fIEeht_op dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info); + +/** + * lim_strip_and_decode_eht_op() - API to decode EHT Operations IE + * @ie: source ie address + * @ie_len: source ie length + * @dot11f_eht_op: output pointer to dot11f EHT Operations IE structure + * @dot11f_vht_op: dot11f VHT operation IE structure + * @dot11f_he_op: dot11f HE operation IE structure + * @dot11f_ht_info: dot11f HT info IE structure + * + * This API is used to strip and decode EHT operations IE which is of variable + * in length depending on the HE capabilities IE content. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_strip_and_decode_eht_op(uint8_t *ie, uint16_t ie_len, + tDot11fIEeht_op *dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info); + +#else +static inline QDF_STATUS +populate_dot11f_eht_caps(struct mac_context *mac_ctx, + struct pe_session *session, tDot11fIEeht_cap *eht_cap) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +populate_dot11f_eht_caps_by_band(struct mac_context *mac_ctx, + bool is_2g, + tDot11fIEeht_cap *eht_cap, + struct pe_session *session) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +populate_dot11f_eht_operation(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEeht_op *eht_op) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS populate_dot11f_bw_ind_element(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbw_ind_element *bw_ind) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void lim_ieee80211_pack_ehtcap(uint8_t *ie, + tDot11fIEeht_cap dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, + bool is_band_2g) +{ +} + +static inline +QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len, + tDot11fIEeht_cap *dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, + uint16_t freq) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void lim_ieee80211_pack_ehtop(uint8_t *ie, + tDot11fIEeht_op dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info) +{ +} + +static inline +QDF_STATUS lim_strip_and_decode_eht_op(uint8_t *ie, uint16_t ie_len, + tDot11fIEeht_op *dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * populate_dot11f_auth_mlo_ie() - populate MLO IE in Auth frame + * @mac_ctx: Global MAC context + * @pe_session: PE session + * @mlo_ie: pointer to MLO IE struct + * + * Return: Success if MLO IE is populated in Auth frame, else Failure + * + * Populate the MLO IE in Auth frame based on the session. + */ +QDF_STATUS populate_dot11f_auth_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct wlan_mlo_ie *mlo_ie); + +/** + * populate_dot11f_assoc_req_mlo_ie() - populate MLO Operation IE in assoc req + * @mac_ctx: Global MAC context + * @session: PE session + * @frm: Pointer to Assoc Req IE + * + * Populate the mlo IE in assoc req based on the session. + */ +QDF_STATUS +populate_dot11f_assoc_req_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocRequest *frm); + +/** + * populate_dot11f_mlo_ie() - populate MLO Operation IE + * @mac_ctx: Global MAC context + * @vdev: Pointer to vdev + * @mlo_ie: Pointer to MLO Operation IE + * + * Populate mlo IE for vdev by self capability. + */ +QDF_STATUS populate_dot11f_mlo_ie(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_ie *mlo_ie); +#endif + +/** + * populate_dot11f_btm_extended_caps() - populate btm extended capabilities + * @mac_ctx: Global MAC context. + * @pe_session: Pointer to the PE session. + * @dot11f: Pointer to the extended capabilities of the session. + * + * Disable btm for SAE types for Helium firmware limit + * + * Return: QDF_STATUS Success or Failure + */ +QDF_STATUS populate_dot11f_btm_extended_caps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct sDot11fIEExtCap *dot11f); + +/** + * lim_truncate_ppet: truncates ppet of trailing zeros + * @ppet: ppet to truncate + * max_len: max length of ppet + * + * Return: new length after truncation + */ +static inline uint32_t lim_truncate_ppet(uint8_t *ppet, uint32_t max_len) +{ + while (max_len) { + if (ppet[max_len - 1]) + break; + max_len--; + } + return max_len; +} + +QDF_STATUS wlan_parse_bss_description_ies(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs *ie_struct); + +QDF_STATUS +wlan_get_parsed_bss_description_ies(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs **ie_struct); + +void wlan_populate_basic_rates(tSirMacRateSet *rate_set, bool is_ofdm_rates, + bool is_basic_rates); + +uint32_t wlan_get_11h_power_constraint(struct mac_context *mac_ctx, + tDot11fIEPowerConstraints *constraints); + +QDF_STATUS +wlan_fill_bss_desc_from_scan_entry(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + struct scan_cache_entry *scan_entry); + +/** + * wlan_get_ielen_from_bss_description() - to get IE length + * from struct bss_description structure + * @pBssDescr: pBssDescr + * + * This function is called in various places to get IE length + * from struct bss_description structure + * + * @Return: total IE length + */ +uint16_t +wlan_get_ielen_from_bss_description(struct bss_description *bss_desc); + +bool wlan_rates_is_dot11_rate_supported(struct mac_context *mac_ctx, + uint8_t rate); + +bool wlan_check_rate_bitmap(uint8_t rate, uint16_t rate_bitmap); + +QDF_STATUS wlan_get_rate_set(struct mac_context *mac, + tDot11fBeaconIEs *ie_struct, + struct pe_session *pe_session); + +void wlan_add_rate_bitmap(uint8_t rate, uint16_t *rate_bitmap); + +/** + * dot11f_parse_assoc_response() - API to parse Assoc IE buffer to struct + * @mac_ctx: MAC context + * @p_buf: Pointer to the assoc IE buffer + * @n_buf: length of the @p_buf + * @p_frm: Struct to populate the IE buffer after parsing + * @append_ie: Boolean to indicate whether to reset @p_frm or not. If @append_ie + * is true, @p_frm struct is not reset to zeros. + * + * Return: QDF_STATUS + */ +QDF_STATUS dot11f_parse_assoc_response(struct mac_context *mac_ctx, + uint8_t *p_buf, uint32_t n_buf, + tDot11fAssocResponse *p_frm, + bool append_ie); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * dot11f_parse_assoc_rsp_mlo_partner_info() - get mlo partner info in assoc rsp + * @pe_session: pointer to PE session + * @pframe: pointer of assoc response buffer + * @nframe: length of assoc response buffer + * + * Return: none + */ +void dot11f_parse_assoc_rsp_mlo_partner_info(struct pe_session *pe_session, + uint8_t *pframe, uint32_t nframe); +#else +static inline void +dot11f_parse_assoc_rsp_mlo_partner_info(struct pe_session *pe_session, + uint8_t *pframe, uint32_t nframe) +{ +} +#endif + +/** + * populate_dot11f_6g_rnr() - populate rnr with 6g bss information + * @mac_ctx: MAC context + * @session: reporting session + * @dot11f: pointer to tDot11fIEreduced_neighbor_report to fill + * + * Return: none + */ +void populate_dot11f_6g_rnr(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f); + +/** + * populate_dot11f_rnr_tbtt_info() - populate rnr for the tbtt_len specified + * @mac_ctx: pointer to mac_context + * @pe_session: pe session + * @rnr_session: session to populate in rnr ie + * @dot11f: tDot11fIEreduced_neighbor_report to be filled + * @tbtt_len: length of the TBTT params + * + * Return: QDF STATUS + */ +QDF_STATUS +populate_dot11f_rnr_tbtt_info(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f, + uint8_t tbtt_len); + +/** + * populate_dot11f_edca_pifs_param_set() - populate edca/pifs param ie + * @mac: Mac context + * @qcn_ie: pointer to tDot11fIEqcn_ie + * + * Return: none + */ +void populate_dot11f_edca_pifs_param_set( + struct mac_context *mac, + tDot11fIEqcn_ie *qcn_ie); + +/** + * populate_dot11f_bcn_prot_caps() - populate Beacon protection extended caps + * + * @mac_ctx: Global MAC context. + * @pe_session: Pointer to the PE session. + * @dot11f: Pointer to the extended capabilities of the session. + * + * Populate the Beacon protection extended capabilities based on the target and + * INI support. + * + * Return: QDF_STATUS Success or Failure + */ +QDF_STATUS populate_dot11f_bcn_prot_extcaps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEExtCap *dot11f); +#endif /* __PARSE_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_common.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_common.h new file mode 100644 index 0000000000..66078b9bce --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_common.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011-2014 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sir_common.h contains the common definitions used by all + * Firmware modules. + * + * Author: V. K. Kandarpa + * Date: 04/12/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIRCOMMON_H +#define __SIRCOMMON_H + +#include "sir_api.h" +#include "sir_params.h" +#include "sys_wrapper.h" + +/* ********************************************* * +* * +* SIRIUS SYSTEM EXTERNAL GLOBALS * +* * +* ********************************************* */ + +/* All the following are resource definitions */ + +#endif /* __SIRCOMMON_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_debug.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_debug.h new file mode 100644 index 0000000000..c19fab2ff5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_debug.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011-2012, 2014-2015, 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Author: Sandesh Goel + * Date: 02/25/02 + */ + +#ifndef __POL_DEBUG_H__ +#define __POL_DEBUG_H__ + +#define LOGOFF 0 +#define LOGP 1 +#define LOGE 2 +#define LOGW 3 +#define LOG1 4 +#define LOG2 5 +#define LOG3 6 +#define LOG4 7 +#define LOGD 8 + +#define pe_alert_rl(params...) QDF_TRACE_FATAL_RL(QDF_MODULE_ID_PE, params) +#define pe_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_PE, params) +#define pe_warn_rl(params...) QDF_TRACE_WARN_RL(QDF_MODULE_ID_PE, params) +#define pe_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_PE, params) +#define pe_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_PE, params) + +#define pe_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_PE, params) +#define pe_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_PE, params) +#define pe_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_PE, params) +#define pe_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_PE, params) +#define pe_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_PE, params) + +#define pe_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_rl_err(params...) \ + QDF_TRACE_ERROR_RL_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_rl_debug(params...) \ + QDF_TRACE_DEBUG_RL_NO_FL(QDF_MODULE_ID_PE, params) +#define pe_nofl_rl_info(params...) \ + QDF_TRACE_INFO_RL_NO_FL(QDF_MODULE_ID_PE, params) + +#define PE_ENTER() QDF_TRACE_ENTER(QDF_MODULE_ID_PE, "enter") +#define PE_EXIT() QDF_TRACE_EXIT(QDF_MODULE_ID_PE, "exit") +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_params.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_params.h new file mode 100644 index 0000000000..edc63845f5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sir_params.h @@ -0,0 +1,759 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file sir_params.h contains the common parameter definitions, which + * are not dependent on threadX API. These can be used by all Firmware + * modules. + * + * Author: Sandesh Goel + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SIRPARAMS_H +#define __SIRPARAMS_H + +#include "sir_types.h" + +#define WAKELOCK_DURATION_RECOMMENDED 1000 +#define WAKELOCK_DURATION_MAX 3000 + + +#define SYSTEM_TIME_MSEC_TO_USEC 1000 +#define SYSTEM_TIME_SEC_TO_MSEC 1000 +#define SYSTEM_TIME_NSEC_TO_USEC 1000 + +/* defines for WPS config states */ +#define SAP_WPS_DISABLED 0 +#define SAP_WPS_ENABLED_UNCONFIGURED 1 +#define SAP_WPS_ENABLED_CONFIGURED 2 + + +/* Firmware wide constants */ + +#define SIR_MAX_PACKET_SIZE 512 +#define SIR_MAX_NUM_CHANNELS 64 +#define SIR_MAX_NUM_STA_IN_IBSS 16 +#define SIR_ESE_MAX_MEAS_IE_REQS 8 + +typedef enum { + PHY_SINGLE_CHANNEL_CENTERED = 0, /* 20MHz IF bandwidth centered on IF carrier */ + PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1, /* 40MHz IF bandwidth with lower 20MHz supporting the primary channel */ + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3, /* 40MHz IF bandwidth with higher 20MHz supporting the primary channel */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED = 4, /* 20/40MHZ offset LOW 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED = 5, /* 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED = 6, /* 20/40MHZ offset HIGH 40/80MHZ offset CENTERED */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW = 7, /* 20/40MHZ offset LOW 40/80MHZ offset LOW */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW = 8, /* 20/40MHZ offset HIGH 40/80MHZ offset LOW */ + PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH = 9, /* 20/40MHZ offset LOW 40/80MHZ offset HIGH */ + PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH = 10, /* 20/40MHZ offset-HIGH 40/80MHZ offset HIGH */ + PHY_CHANNEL_BONDING_STATE_MAX = 11 +} ePhyChanBondState; + +#define MAX_BONDED_CHANNELS 8 +/** + * enum cap_bitmap - bit field for FW capability + * MCC - indicate MCC + * P2P - indicate P2P + * DOT11AC - indicate 11AC + * DOT11AC_OPMODE - indicate 11ac opmode + * SAP32STA - indicate SAP32STA + * TDLS - indicate TDLS + * P2P_GO_NOA_DECOUPLE_INIT_SCAN - indicate P2P_GO_NOA_DECOUPLE_INIT_SCAN + * WLANACTIVE_OFFLOAD - indicate active offload + * EXTENDED_SCAN - indicate extended scan + * PNO - indicate PNO + * NAN - indicate NAN + * RTT - indicate RTT + * DOT11AX - indicate 11ax + * DOT11BE - indicate 11be + * SECURE_NAN - indicate NAN Pairing protocol + * WOW - indicate WOW + * WLAN_ROAM_SCAN_OFFLOAD - indicate Roam scan offload + * WLAN_PERIODIC_TX_PTRN - indicate WLAN_PERIODIC_TX_PTRN + * ADVANCE_TDLS - indicate advanced TDLS + * TDLS_OFF_CHANNEL - indicate TDLS off channel + * + * This definition is independent of any other modules. + * We can use any unused numbers. + */ +#define MAX_SUPPORTED_FEATURE 32 +enum cap_bitmap { + MCC = 0, + P2P = 1, + DOT11AC = 2, + DOT11AC_OPMODE = 4, + SAP32STA = 5, + TDLS = 6, + P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7, + WLANACTIVE_OFFLOAD = 8, + EXTENDED_SCAN = 9, +#ifdef FEATURE_WLAN_SCAN_PNO + PNO = 10, +#endif +#ifdef WLAN_FEATURE_NAN + NAN = 11, +#endif + RTT = 12, + DOT11AX = 13, +#ifdef WLAN_FEATURE_11BE + DOT11BE = 14, +#endif +#ifdef WLAN_FEATURE_NAN + SECURE_NAN = 15, +#endif + WOW = 22, + WLAN_ROAM_SCAN_OFFLOAD = 23, + WLAN_PERIODIC_TX_PTRN = 28, +#ifdef FEATURE_WLAN_TDLS + ADVANCE_TDLS = 29, + TDLS_OFF_CHANNEL = 30, +#endif + VDEV_LATENCY_CONFIG = 31, + + /* MAX_FEATURE_SUPPORTED = 32 */ +}; + +/* / Mailbox Message Structure Define */ +typedef struct sSirMbMsg { + uint16_t type; + + /** + * This length includes 4 bytes of header, that is, + * 2 bytes type + 2 bytes msgLen + n*4 bytes of data. + * This field is byte length. + */ + uint16_t msgLen; + + /** + * This is the first data word in the mailbox message. + * It is followed by n words of data. + * NOTE: data[1] is not a place holder to store data + * instead to dereference the message body. + */ + QDF_FLEX_ARRAY(uint32_t, data); +} tSirMbMsg, *tpSirMbMsg; + +/** + * struct sir_mgmt_msg - Structure used to send auth frame from CSR to LIM + * @type: Message type + * @msg_len: Message length + * @vdev_id: vdev id + * @data: Pointer to data tobe transmitted + */ +struct sir_mgmt_msg { + uint16_t type; + uint16_t msg_len; + uint8_t vdev_id; + uint8_t *data; +}; + +/** + * struct sir_cfg_action_frm_tb_ppdu - cfg to set action frame in he tb ppdu + * @type: Message type + * @vdev_id: vdev id + * @cfg: enable/disable cfg + */ +struct sir_cfg_action_frm_tb_ppdu { + uint16_t type; + uint8_t vdev_id; + uint8_t cfg; +}; + +/* ******************************************* * +* * +* SIRIUS MESSAGE TYPES * +* * +* ******************************************* */ + +/* + * The following message types have bounds defined for each module for + * inter thread/module communications. + * Each module will get 256 message types in total. + * Note that message type definitions for mailbox messages for + * communication with Host are in wni_api.h file. + * + * Any addition/deletion to this message list should also be + * reflected in the halUtil_getMsgString() routine. + */ + +/** + * Module ID definitions. + */ +enum { + SIR_HAL_MODULE_ID = 0x10, + SIR_LIM_MODULE_ID = 0x13, + SIR_SME_MODULE_ID, +}; + +#define SIR_WMA_MODULE_ID SIR_HAL_MODULE_ID + +/* HAL message types */ +enum halmsgtype { + SIR_HAL_MSG_TYPES_BEGIN = (SIR_HAL_MODULE_ID << 8), + SIR_HAL_ITC_MSG_TYPES_BEGIN = (SIR_HAL_MSG_TYPES_BEGIN + 0x20), + SIR_HAL_RADAR_DETECTED_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN), + +/* + * New Taurus related messages + */ + SIR_HAL_ADD_STA_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 1), + SIR_HAL_ADD_STA_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 2), + SIR_HAL_DELETE_STA_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 3), + SIR_HAL_DELETE_STA_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 4), + SIR_HAL_ADD_BSS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 5), + SIR_HAL_DELETE_BSS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 7), + SIR_HAL_DELETE_BSS_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 8), +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 9), thru + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 16), are unused + */ + SIR_HAL_SEND_BEACON_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 17), + + SIR_HAL_SET_BSSKEY_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 19), + SIR_HAL_SET_STAKEY_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 21), + SIR_HAL_UPDATE_EDCA_PROFILE_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 22), + + SIR_HAL_UPDATE_BEACON_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 23), + SIR_HAL_CHNL_SWITCH_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 25), + SIR_HAL_ADD_TS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 26), + SIR_HAL_DEL_TS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 27), + + SIR_HAL_MISSED_BEACON_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 34), + + SIR_HAL_SWITCH_CHANNEL_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 35), + SIR_HAL_PWR_SAVE_CFG = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 36), +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 37) to + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 43) are unused + */ + SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 44), + SIR_HAL_SET_LINK_STATE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 45), + SIR_HAL_DELETE_BSS_HO_FAIL_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 46), + SIR_HAL_DELETE_BSS_HO_FAIL_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 47), + +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 48) to + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 57) are unused + */ + + SIR_HAL_SET_STA_BCASTKEY_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 59), + SIR_HAL_ADD_TS_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 60), + SIR_HAL_DPU_MIC_ERROR = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 61), + SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 63), + SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 64), + SIR_HAL_TIMER_ADC_RSSI_STATS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 65), +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 66) is unused */ + SIR_HAL_SET_MIMOPS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 67), + SIR_HAL_SET_MIMOPS_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 68), + SIR_HAL_SYS_READY_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 69), + SIR_HAL_SET_TX_POWER_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 70), + SIR_HAL_SET_TX_POWER_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 71), + SIR_HAL_GET_TX_POWER_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 72), +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 73) thru + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 89) are unused + */ + + SIR_HAL_SET_KEY_DONE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 90), + +/* / PE <-> HAL BTC messages */ + SIR_HAL_BTC_SET_CFG = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 91), +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 92) is unused */ + SIR_HAL_HANDLE_FW_MBOX_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 93), + SIR_HAL_SEND_PROBE_RSP_TMPL = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 94), + +/* PE <-> HAL addr2 mismatch message */ + SIR_LIM_ADDR2_MISS_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 95), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 96) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 97) is unused */ + + SIR_HAL_SET_MAX_TX_POWER_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 98), + SIR_HAL_SET_MAX_TX_POWER_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 99), + +/* / PE <-> HAL Host Offload message */ + SIR_HAL_SET_HOST_OFFLOAD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 100), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 101) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 102) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 103) is unused */ + +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 104) thru + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 108) are unused + */ + SIR_HAL_AGGR_QOS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 109), + SIR_HAL_AGGR_QOS_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 110), + +/* P2P <-> HAL P2P msg */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 111) is unused */ + SIR_HAL_P2P_NOA_ATTR_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 112), +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 113) is unused */ + + SIR_HAL_WLAN_SUSPEND_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 115), + SIR_HAL_WLAN_RESUME_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 116), + +/* / PE <-> HAL Keep Alive message */ + SIR_HAL_SET_KEEP_ALIVE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 117), + +#ifdef WLAN_NS_OFFLOAD + SIR_HAL_SET_NS_OFFLOAD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 118), +#endif /* WLAN_NS_OFFLOAD */ + + SIR_HAL_SOC_ANTENNA_MODE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 120), + SIR_HAL_SOC_ANTENNA_MODE_RESP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 121), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 122) is unused */ + + SIR_HAL_8023_MULTICAST_LIST_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 123), + +#ifdef WLAN_FEATURE_PACKET_FILTERING + SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 124), + SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 125), + SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 126), + SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 127), +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 128) is unused */ + +#ifdef WLAN_FEATURE_GTK_OFFLOAD + SIR_HAL_GTK_OFFLOAD_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 129), + SIR_HAL_GTK_OFFLOAD_GETINFO_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 130), + SIR_HAL_GTK_OFFLOAD_GETINFO_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 131), +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + +#ifdef FEATURE_WLAN_ESE + SIR_HAL_TSM_STATS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 132), + SIR_HAL_TSM_STATS_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 133), +#endif + + SIR_HAL_SET_TM_LEVEL_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 134), + + SIR_HAL_UPDATE_OP_MODE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 135), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 136) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 137) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 138) is unused */ + + SIR_HAL_ROAM_PRE_AUTH_STATUS_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 139), + + SIR_HAL_TRAFFIC_STATS_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 141), + + SIR_HAL_EXCLUDE_UNENCRYPTED_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 142), +#ifdef FEATURE_WLAN_TDLS +/* / PE <-> HAL TDLS messages */ + SIR_HAL_TDLS_LINK_ESTABLISH_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 143), + SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 144), +#endif +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 145) is unused */ + + SIR_HAL_STOP_SCAN_OFFLOAD_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 146), + SIR_HAL_RX_SCAN_EVENT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 147), + SIR_HAL_DHCP_START_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 148), + SIR_HAL_DHCP_STOP_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 149), + + SIR_HAL_LPHB_CONF_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 151), + + SIR_HAL_ADD_PERIODIC_TX_PTRN_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 152), + SIR_HAL_DEL_PERIODIC_TX_PTRN_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 153), + +/* Messages between 156 to 157 are not used */ + SIR_HAL_PDEV_DUAL_MAC_CFG_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 154), + SIR_HAL_PDEV_MAC_CFG_RESP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 155), + + SIR_HAL_RATE_UPDATE_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 159), + + SIR_HAL_FLUSH_LOG_TO_FW = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 160), + + SIR_HAL_SET_PCL_TO_FW = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 161), + +#ifdef WLAN_MWS_INFO_DEBUGFS + SIR_HAL_GET_MWS_COEX_INFO_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 162), +#endif /* WLAN_MWS_INFO_DEBUGFS */ + + SIR_HAL_CLI_SET_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 163), +#ifndef REMOVE_PKT_LOG + SIR_HAL_PKTLOG_ENABLE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 164), +#endif + SIR_HAL_UPDATE_CHAN_LIST_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 167), + SIR_CSA_OFFLOAD_EVENT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 169), + + SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 170), + + SIR_HAL_UPDATE_MEMBERSHIP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 172), + SIR_HAL_UPDATE_USERPOS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 173), + +#ifdef FEATURE_WLAN_TDLS +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 174) is not used */ + SIR_HAL_UPDATE_TDLS_PEER_STATE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 175), + SIR_HAL_TDLS_SHOULD_DISCOVER = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 176), + SIR_HAL_TDLS_SHOULD_TEARDOWN = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 177), + SIR_HAL_TDLS_PEER_DISCONNECTED = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 178), +#endif + +/* Handling of beacon tx indication from FW */ + SIR_HAL_BEACON_TX_SUCCESS_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 179), +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 180) is unused */ + + SIR_HAL_INIT_THERMAL_INFO_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 185), + SIR_HAL_SET_THERMAL_LEVEL = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 186), + +#ifdef FEATURE_WLAN_ESE + SIR_HAL_SET_PLM_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 187), +#endif + + SIR_HAL_SET_TX_POWER_LIMIT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 188), + SIR_HAL_SET_SAP_INTRABSS_DIS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 189), + + SIR_HAL_MODEM_POWER_STATE_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 190), + + SIR_HAL_DISASSOC_TX_COMP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 191), + SIR_HAL_DEAUTH_TX_COMP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 192), + + SIR_HAL_UPDATE_RX_NSS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 193), + +#ifdef WLAN_FEATURE_STATS_EXT + SIR_HAL_STATS_EXT_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 194), +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 195) is unused */ +#endif /* WLAN_FEATURE_STATS_EXT */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 197) is unused */ + +#ifdef FEATURE_WLAN_EXTSCAN + SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 198), + SIR_HAL_EXTSCAN_START_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 199), + SIR_HAL_EXTSCAN_STOP_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 200), + SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 201), + SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 202), + SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 203), + SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 204), + SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 205), +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef FEATURE_WLAN_CH_AVOID + SIR_HAL_CH_AVOID_UPDATE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 206), +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + SIR_HAL_LL_STATS_CLEAR_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 207), + SIR_HAL_LL_STATS_SET_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 208), + SIR_HAL_LL_STATS_GET_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 209), + SIR_HAL_LL_STATS_RESULTS_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 210), +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 211) is unused */ + +#ifdef WLAN_FEATURE_NAN + SIR_HAL_NAN_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 212), +#endif /* WLAN_FEATURE_NAN */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 213), +#endif + + SIR_HAL_SET_BASE_MACADDR_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 214), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 215) is unused */ + + SIR_HAL_LINK_STATUS_GET_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 216), + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + SIR_HAL_CONFIG_EXT_WOW = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 217), + SIR_HAL_CONFIG_APP_TYPE1_PARAMS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 218), + SIR_HAL_CONFIG_APP_TYPE2_PARAMS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 219), +#endif + + SIR_HAL_GET_TEMPERATURE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 220), + SIR_HAL_SET_SCAN_MAC_OUI_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 221), +#ifdef DHCP_SERVER_OFFLOAD + SIR_HAL_SET_DHCP_SERVER_OFFLOAD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 222), +#endif /* DHCP_SERVER_OFFLOAD */ + SIR_HAL_LED_FLASHING_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 223), + +/*= (SIR_HAL_ITC_MSG_TYPES_BEGIN + 228), is unused */ + + SIR_HAL_SET_MAS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 229), + SIR_HAL_SET_MIRACAST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 230), +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + SIR_HAL_UPDATE_Q2Q_IE_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 231), +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + SIR_HAL_CONFIG_STATS_FACTOR = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 232), + SIR_HAL_CONFIG_GUARD_TIME = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 233), +/*= (SIR_HAL_ITC_MSG_TYPES_BEGIN + 234), is unused */ + + SIR_HAL_ENTER_PS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 235), + SIR_HAL_EXIT_PS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 236), + SIR_HAL_ENABLE_UAPSD_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 237), + SIR_HAL_DISABLE_UAPSD_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 238), + SIR_HAL_GATEWAY_PARAM_UPDATE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 239), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 308) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 309) is unused */ + + SIR_HAL_SET_EPNO_LIST_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 313), + SIR_HAL_SET_PASSPOINT_LIST_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 316), + SIR_HAL_RESET_PASSPOINT_LIST_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 317), +/* 318 unused */ + + SIR_HAL_OCB_SET_CONFIG_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 319), + SIR_HAL_OCB_SET_UTC_TIME_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 320), + SIR_HAL_OCB_START_TIMING_ADVERT_CMD = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 321), + SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 322), + SIR_HAL_OCB_GET_TSF_TIMER_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 323), + SIR_HAL_DCC_GET_STATS_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 324), + SIR_HAL_DCC_CLEAR_STATS_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 325), + SIR_HAL_DCC_UPDATE_NDL_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 326), + +/* FW Memory Dump feature is deprecated */ + + SIR_HAL_START_STOP_LOGGING = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 328), + SIR_HAL_PDEV_SET_HW_MODE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 329), + SIR_HAL_PDEV_SET_HW_MODE_RESP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 330), + SIR_HAL_PDEV_HW_MODE_TRANS_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 331), + + SIR_HAL_BAD_PEER_TX_CTL_INI_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 332), + SIR_HAL_SET_RSSI_MONITOR_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 333), + SIR_HAL_SET_IE_INFO = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 334), + + /* SIR_HAL_ITC_MSG_TYPES_BEGIN + 335 is unused */ + /* SIR_HAL_ITC_MSG_TYPES_BEGIN + 336 is unused */ + + SIR_HAL_HT40_OBSS_SCAN_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 337), + + SIR_HAL_TSF_GPIO_PIN_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 338), + + SIR_HAL_ADD_BCN_FILTER_CMDID = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 339), + SIR_HAL_REMOVE_BCN_FILTER_CMDID = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 340), + + + SIR_HAL_APF_GET_CAPABILITIES_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 341), + SIR_HAL_WMA_ROAM_SYNC_TIMEOUT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 342), + + SIR_HAL_SET_WISA_PARAMS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 343), + SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 344), + SIR_HAL_SET_PDEV_IE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 345), + +/* + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 346) to + * (SIR_HAL_ITC_MSG_TYPES_BEGIN + 359) are unused + */ + + SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 360), + SIR_HAL_POWER_DBG_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 362), + SIR_HAL_SET_DTIM_PERIOD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 363), +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 364) is unused */ + SIR_HAL_SHORT_RETRY_LIMIT_CNT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 365), + SIR_HAL_LONG_RETRY_LIMIT_CNT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 366), + SIR_HAL_UPDATE_TX_FAIL_CNT_TH = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 367), + SIR_HAL_POWER_DEBUG_STATS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 368), + + SIR_HAL_SET_WOW_PULSE_CMD = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 369), + +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 370) is unused */ +/* (SIR_HAL_ITC_MSG_TYPES_BEGIN + 371) is unused */ + + SIR_HAL_RX_CHN_STATUS_EVENT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 372), + + SIR_HAL_GET_RCPI_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 373), + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + SIR_HAL_LL_STATS_EXT_SET_THRESHOLD = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 378), +#endif + SIR_HAL_SET_DBS_SCAN_SEL_PARAMS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 379), + +/* + * Unused SIR_HAL_ITC_MSG_TYPES_BEGIN + 380 to + * SIR_HAL_ITC_MSG_TYPES_BEGIN + 387 + */ + +/* ARP Debug stats */ + SIR_HAL_SET_ARP_STATS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 388), + SIR_HAL_GET_ARP_STATS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 389), + + SIR_HAL_SET_LIMIT_OFF_CHAN = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 390), + + SIR_HAL_SET_DEL_PMKID_CACHE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 391), + SIR_HAL_HLP_IE_INFO = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 392), + SIR_HAL_OBSS_DETECTION_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 393), + SIR_HAL_OBSS_DETECTION_INFO = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 394), + SIR_HAL_INVOKE_NEIGHBOR_REPORT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 395), + SIR_HAL_OBSS_COLOR_COLLISION_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 396), + SIR_HAL_OBSS_COLOR_COLLISION_INFO = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 397), + + SIR_HAL_SEND_ADDBA_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 398), + SIR_HAL_GET_ROAM_SCAN_STATS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 399), + SIR_HAL_SEND_AP_VDEV_UP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 400), + SIR_HAL_SEND_BCN_RSP = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 401), + SIR_HAL_CFG_VENDOR_ACTION_TB_PPDU = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 402), + SIR_HAL_BEACON_DEBUG_STATS_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 403), + +#ifdef WLAN_FEATURE_MOTION_DETECTION + SIR_HAL_SET_MOTION_DET_CONFIG = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 405), + SIR_HAL_SET_MOTION_DET_ENABLE = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 406), + SIR_HAL_SET_MOTION_DET_BASE_LINE_CONFIG = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 407), + SIR_HAL_SET_MOTION_DET_BASE_LINE_ENABLE = + (SIR_HAL_ITC_MSG_TYPES_BEGIN + 408), +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +#ifdef FW_THERMAL_THROTTLE_SUPPORT + SIR_HAL_SET_THERMAL_THROTTLE_CFG = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 409), + SIR_HAL_SET_THERMAL_MGMT = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 410), +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + + SIR_HAL_SEND_PEER_UNMAP_CONF = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 411), + + SIR_HAL_GET_ISOLATION = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 412), + + SIR_HAL_SET_ROAM_TRIGGERS = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 413), + + SIR_HAL_ROAM_SCAN_CH_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 414), + + SIR_HAL_REQ_SEND_DELBA_REQ_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 415), + SIR_HAL_SEND_MAX_TX_POWER = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 416), + + SIR_HAL_TWT_ADD_DIALOG_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 417), + SIR_HAL_TWT_DEL_DIALOG_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 418), + SIR_HAL_TWT_PAUSE_DIALOG_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 419), + SIR_HAL_TWT_RESUME_DIALOG_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 420), + SIR_HAL_PEER_CREATE_REQ = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 421), + SIR_HAL_TWT_NUDGE_DIALOG_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 422), + SIR_HAL_PASN_PEER_DELETE_REQUEST = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 423), + SIR_HAL_UPDATE_EDCA_PIFS_PARAM_IND = (SIR_HAL_ITC_MSG_TYPES_BEGIN + 424), + + SIR_HAL_MSG_TYPES_END = (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF), +}; +/* LIM message types */ +#define SIR_LIM_MSG_TYPES_BEGIN (SIR_LIM_MODULE_ID << 8) +#define SIR_LIM_ITC_MSG_TYPES_BEGIN (SIR_LIM_MSG_TYPES_BEGIN+0xB0) +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 1) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 2) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 3) */ +/* Message from BB Transport */ +#define SIR_BB_XPORT_MGMT_MSG (SIR_LIM_ITC_MSG_TYPES_BEGIN + 4) +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 5) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 6) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 7) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 8) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 9) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xA) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xB) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xC) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xD) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xE) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0xF) */ +/* UNUSED (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x10) */ +/* Indication from HAL to delete Station context */ +#define SIR_LIM_DELETE_STA_CONTEXT_IND (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x11) +/* Indication from HAL to delete BA */ +#define SIR_LIM_UPDATE_BEACON (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x13) +/* Indication from HAL to handle RX invalid peer */ +#define SIR_LIM_RX_INVALID_PEER (SIR_LIM_ITC_MSG_TYPES_BEGIN + 0x15) + +/* LIM Timeout messages */ +#define SIR_LIM_TIMEOUT_MSG_START ((SIR_LIM_MODULE_ID << 8) + 0xD0) +#define SIR_LIM_JOIN_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 2) +#define SIR_LIM_AUTH_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 3) +#define SIR_LIM_AUTH_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 4) +#define SIR_LIM_ASSOC_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 5) +#define SIR_LIM_REASSOC_FAIL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 6) +#define SIR_LIM_HEART_BEAT_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 7) +/* currently unused SIR_LIM_TIMEOUT_MSG_START + 0x8 */ +/* Link Monitoring Messages */ +#define SIR_LIM_PROBE_HB_FAILURE_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0xB) +#define SIR_LIM_ADDTS_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0xC) +#define SIR_LIM_LINK_TEST_DURATION_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x13) +#define SIR_LIM_CNF_WAIT_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x17) +/* currently unused (SIR_LIM_TIMEOUT_MSG_START + 0x18) */ +#define SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x19) + +#define SIR_LIM_WPS_OVERLAP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1D) +#define SIR_LIM_FT_PREAUTH_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x1E) + +#define SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x24) +/* currently unused (SIR_LIM_TIMEOUT_MSG_START + 0x25) */ + +#define SIR_LIM_DISASSOC_ACK_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x26) +/*#define SIR_LIM_DEAUTH_ACK_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x27) */ +#define SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT \ + (SIR_LIM_TIMEOUT_MSG_START + 0x28) + +#define SIR_LIM_AUTH_RETRY_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x2D) +#define SIR_LIM_AUTH_SAE_TIMEOUT (SIR_LIM_TIMEOUT_MSG_START + 0x2E) + +#define SIR_LIM_PROCESS_DEFERRED_QUEUE (SIR_LIM_TIMEOUT_MSG_START + 0x2F) + +#define SIR_LIM_MSG_TYPES_END (SIR_LIM_MSG_TYPES_BEGIN+0xFF) + +/* ****************************************** * +* * +* EVENT TYPE Definitions * +* * +* ****************************************** */ + +/* Param Change Bitmap sent to HAL */ +#define PARAM_BCN_INTERVAL_CHANGED (1 << 0) +#define PARAM_SHORT_PREAMBLE_CHANGED (1 << 1) +#define PARAM_SHORT_SLOT_TIME_CHANGED (1 << 2) +#define PARAM_llACOEXIST_CHANGED (1 << 3) +#define PARAM_llBCOEXIST_CHANGED (1 << 4) +#define PARAM_llGCOEXIST_CHANGED (1 << 5) +#define PARAM_HT20MHZCOEXIST_CHANGED (1<<6) +#define PARAM_NON_GF_DEVICES_PRESENT_CHANGED (1<<7) +#define PARAM_RIFS_MODE_CHANGED (1<<8) +#define PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED (1<<9) +#define PARAM_OBSS_MODE_CHANGED (1<<10) +#define PARAM_BSS_COLOR_CHANGED (1 << 11) +#define PARAM_BEACON_UPDATE_MASK (PARAM_BCN_INTERVAL_CHANGED | \ + PARAM_SHORT_PREAMBLE_CHANGED | \ + PARAM_SHORT_SLOT_TIME_CHANGED | \ + PARAM_llACOEXIST_CHANGED | \ + PARAM_llBCOEXIST_CHANGED | \ + PARAM_llGCOEXIST_CHANGED | \ + PARAM_HT20MHZCOEXIST_CHANGED | \ + PARAM_NON_GF_DEVICES_PRESENT_CHANGED | \ + PARAM_RIFS_MODE_CHANGED | \ + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED | \ + PARAM_OBSS_MODE_CHANGED | \ + PARAM_BSS_COLOR_CHANGED) + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sys_global.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sys_global.h new file mode 100644 index 0000000000..98c6980775 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/sys_global.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __SYS_GLOBAL_H__ +#define __SYS_GLOBAL_H__ + +typedef struct sAniSirSys { + uint32_t gSysFrameCount[4][16]; + uint32_t gSysBbtReceived; + uint32_t sys_bbt_pending_mgmt_count; + uint32_t gSysBbtPostedToLim; + uint32_t gSysBbtDropped; + uint32_t gSysEnableLinkMonitorMode; + qdf_spinlock_t bbt_mgmt_lock; +} tAniSirSys, *tpAniSirSys; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/utils_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/utils_api.h new file mode 100644 index 0000000000..957ea0d215 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/include/utils_api.h @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __UTILSAPI_H +#define __UTILSAPI_H + +#include "qdf_types.h" +#include +#include "ani_global.h" +#include "sys_wrapper.h" +#include "wlan_vdev_mlme_main.h" +#include "wlan_vdev_mlme_api.h" + +/** + * sir_swap_u16() + * + * FUNCTION: + * This function is called to swap two U8s of an uint16_t value + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint16_t value to be uint8_t swapped + * @return Swapped uint16_t value + */ + +static inline uint16_t sir_swap_u16(uint16_t val) +{ + return ((val & 0x00FF) << 8) | ((val & 0xFF00) >> 8); +} /*** end sir_swap_u16() ***/ + +/** + * sir_swap_u16if_needed() + * + * FUNCTION: + * This function is called to swap two U8s of an uint16_t value depending + * on endianness of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint16_t value to be uint8_t swapped + * @return Swapped uint16_t value + */ + +static inline uint16_t sir_swap_u16if_needed(uint16_t val) +{ +#ifndef ANI_LITTLE_BYTE_ENDIAN + return sir_swap_u16(val); +#else + return val; +#endif +} /*** end sir_swap_u16if_needed() ***/ + +/** + * sir_swap_u32() + * + * FUNCTION: + * This function is called to swap four U8s of an uint32_t value + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint32_t value to be uint8_t swapped + * @return Swapped uint32_t value + */ + +static inline uint32_t sir_swap_u32(uint32_t val) +{ + return (val << 24) | + (val >> 24) | + ((val & 0x0000FF00) << 8) | ((val & 0x00FF0000) >> 8); +} /*** end sir_swap_u32() ***/ + +/** + * sir_swap_u32if_needed() + * + * FUNCTION: + * This function is called to swap U8s of an uint32_t value depending + * on endianness of the target processor/compiler the software is + * running on + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param val uint32_t value to be uint8_t swapped + * @return Swapped uint32_t value + */ + +static inline uint32_t sir_swap_u32if_needed(uint32_t val) +{ +#ifndef ANI_LITTLE_BYTE_ENDIAN + return sir_swap_u32(val); +#else + return val; +#endif +} /*** end sir_swap_u32if_needed() ***/ + +/** + * sir_swap_u32_buf + * + * FUNCTION: + * It swaps N dwords into the same buffer + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of uint32_t array + * @return void + * + */ + +/** + * sir_read_u32_n + * + * FUNCTION: + * It reads a 32 bit number from the byte array in network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 32 bit value + */ + +static inline uint32_t sir_read_u32_n(uint8_t *ptr) +{ + return (*(ptr) << 24) | + (*(ptr + 1) << 16) | (*(ptr + 2) << 8) | (*(ptr + 3)); +} + +/** + * sir_read_u16 + * + * FUNCTION: + * It reads a 16 bit number from the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 16 bit value + */ + +static inline uint16_t sir_read_u16(uint8_t *ptr) +{ + return (*ptr) | (*(ptr + 1) << 8); +} + +/** + * sir_read_u32 + * + * FUNCTION: + * It reads a 32 bit number from the byte array in NON-network byte order + * i.e. the least significant byte first + * + * LOGIC: + * + * ASSUMPTIONS: + * None. + * + * NOTE: + * + * @param ptr address of byte array + * @return 32 bit value + */ + +static inline uint32_t sir_read_u32(uint8_t *ptr) +{ + return (*(ptr)) | + (*(ptr + 1) << 8) | (*(ptr + 2) << 16) | (*(ptr + 3) << 24); +} + +/* / Copy a MAC address from 'from' to 'to' */ +static inline void sir_copy_mac_addr(uint8_t to[], uint8_t from[]) +{ +#if defined(_X86_) + uint32_t align = (0x3 & ((uint32_t) to | (uint32_t) from)); + + if (align == 0) { + *((uint16_t *) &(to[4])) = *((uint16_t *) &(from[4])); + *((uint32_t *) to) = *((uint32_t *) from); + } else if (align == 2) { + *((uint16_t *) &to[4]) = *((uint16_t *) &from[4]); + *((uint16_t *) &to[2]) = *((uint16_t *) &from[2]); + *((uint16_t *) &to[0]) = *((uint16_t *) &from[0]); + } else { + to[5] = from[5]; + to[4] = from[4]; + to[3] = from[3]; + to[2] = from[2]; + to[1] = from[1]; + to[0] = from[0]; + } +#else + to[0] = from[0]; + to[1] = from[1]; + to[2] = from[2]; + to[3] = from[3]; + to[4] = from[4]; + to[5] = from[5]; +#endif +} + +static inline uint8_t sir_compare_mac_addr(uint8_t addr1[], uint8_t addr2[]) +{ +#if defined(_X86_) + uint32_t align = (0x3 & ((uint32_t) addr1 | (uint32_t) addr2)); + + if (align == 0) { + return (*((uint16_t *) &(addr1[4])) == + *((uint16_t *) &(addr2[4]))) + && (*((uint32_t *) addr1) == *((uint32_t *) addr2)); + } else if (align == 2) { + return (*((uint16_t *) &addr1[4]) == + *((uint16_t *) &addr2[4])) + && (*((uint16_t *) &addr1[2]) == + *((uint16_t *) &addr2[2])) + && (*((uint16_t *) &addr1[0]) == + *((uint16_t *) &addr2[0])); + } else { + return (addr1[5] == addr2[5]) && + (addr1[4] == addr2[4]) && + (addr1[3] == addr2[3]) && + (addr1[2] == addr2[2]) && + (addr1[1] == addr2[1]) && (addr1[0] == addr2[0]); + } +#else + return (addr1[0] == addr2[0]) && + (addr1[1] == addr2[1]) && + (addr1[2] == addr2[2]) && + (addr1[3] == addr2[3]) && + (addr1[4] == addr2[4]) && (addr1[5] == addr2[5]); +#endif +} + +/* + * converts uint16_t CW value to 4 bit value to be inserted in IE + */ +static inline uint8_t convert_cw(uint16_t cw) +{ + uint8_t val = 0; + + while (cw > 0) { + val++; + cw >>= 1; + } + if (val > 15) + return 0xF; + return val; +} + +/* The user priority to AC mapping is such: + * UP(1, 2) ---> AC_BK(1) + * UP(0, 3) ---> AC_BE(0) + * UP(4, 5) ---> AC_VI(2) + * UP(6, 7) ---> AC_VO(3) + */ +#define WLAN_UP_TO_AC_MAP 0x33220110 +#define upToAc(up) ((WLAN_UP_TO_AC_MAP >> ((up) << 2)) & 0x03) + +#endif /* __UTILSAPI_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h new file mode 100644 index 0000000000..3830f7dd4e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_admit_control.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011-2012, 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * Author: Dinesh Upadhyay + * Date: 10/24/06 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_ADMIT_CONTROL_H__ +#define __LIM_ADMIT_CONTROL_H__ + +#include "sir_common.h" +#include "sir_mac_prot_def.h" + +#include "ani_global.h" + +QDF_STATUS +lim_tspec_find_by_assoc_id(struct mac_context *, uint16_t, + struct mac_tspec_ie *, + tpLimTspecInfo, tpLimTspecInfo *); + +/* Add TSPEC in lim local table */ +QDF_STATUS lim_tspec_add(struct mac_context *mac, + uint8_t *pAddr, + uint16_t assocId, + struct mac_tspec_ie *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo); + +/* admit control interface */ +QDF_STATUS lim_admit_control_add_ts(struct mac_context *mac, + uint8_t *pAddr, tSirAddtsReqInfo *addts, + tSirMacQosCapabilityStaIE *qos, + uint16_t assocId, uint8_t alloc, + tSirMacScheduleIE *pSch, + /* index to the lim tspec table. */ + uint8_t *pTspecIdx, + struct pe_session *pe_session); + +static inline QDF_STATUS +lim_admit_control_add_sta(struct mac_context *mac, uint8_t *staAddr, uint8_t alloc) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +lim_admit_control_delete_sta(struct mac_context *mac, uint16_t assocId); + +QDF_STATUS +lim_admit_control_delete_ts(struct mac_context *mac, + uint16_t assocId, + struct mac_ts_info *tsinfo, + uint8_t *tsStatus, uint8_t *tspecIdx); + +QDF_STATUS lim_admit_control_init(struct mac_context *mac); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS lim_send_hal_msg_add_ts(struct mac_context *mac, + uint8_t tspecIdx, + struct mac_tspec_ie tspecIE, + uint8_t sessionId, uint16_t tsm_interval); +#else +QDF_STATUS lim_send_hal_msg_add_ts(struct mac_context *mac, + uint8_t tspecIdx, + struct mac_tspec_ie tspecIE, + uint8_t sessionId); +#endif + +QDF_STATUS lim_send_hal_msg_del_ts(struct mac_context *mac, + uint8_t tspecIdx, + struct delts_req_info delts, + uint8_t sessionId, uint8_t *bssId); +void lim_process_hal_add_ts_rsp(struct mac_context *mac, + struct scheduler_msg *limMsg); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_api.h new file mode 100644 index 0000000000..dfe41985d9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_api.h @@ -0,0 +1,980 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_api.h contains the definitions exported by + * LIM module. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_API_H +#define __LIM_API_H +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "sch_global.h" +#include "utils_api.h" +#include "lim_global.h" +#include "wma_if.h" +#include "wma_types.h" +#include "scheduler_api.h" +#include "spatial_reuse_api.h" + +/* Macro to count heartbeat */ +#define limResetHBPktCount(pe_session) (pe_session->LimRxedBeaconCntDuringHB = 0) + +/* Useful macros for fetching various states in mac->lim */ +/* gLimSystemRole */ +#define GET_LIM_SYSTEM_ROLE(pe_session) (pe_session->limSystemRole) +#define LIM_IS_AP_ROLE(pe_session) (GET_LIM_SYSTEM_ROLE(pe_session) == eLIM_AP_ROLE) +#define LIM_IS_STA_ROLE(pe_session) (GET_LIM_SYSTEM_ROLE(pe_session) == eLIM_STA_ROLE) +#define LIM_IS_UNKNOWN_ROLE(pe_session) (GET_LIM_SYSTEM_ROLE(pe_session) == eLIM_UNKNOWN_ROLE) +#define LIM_IS_P2P_DEVICE_ROLE(pe_session) (GET_LIM_SYSTEM_ROLE(pe_session) == eLIM_P2P_DEVICE_ROLE) +#define LIM_IS_P2P_DEVICE_GO(pe_session) (GET_LIM_SYSTEM_ROLE(pe_session) == eLIM_P2P_DEVICE_GO) +#define LIM_IS_NDI_ROLE(pe_session) \ + (GET_LIM_SYSTEM_ROLE(pe_session) == eLIM_NDI_ROLE) +/* gLimSmeState */ +#define GET_LIM_SME_STATE(mac) (mac->lim.gLimSmeState) +#define SET_LIM_SME_STATE(mac, state) (mac->lim.gLimSmeState = state) +/* gLimMlmState */ +#define GET_LIM_MLM_STATE(mac) (mac->lim.gLimMlmState) +#define SET_LIM_MLM_STATE(mac, state) (mac->lim.gLimMlmState = state) +/*tpdphHashNode mlmStaContext*/ +#define GET_LIM_STA_CONTEXT_MLM_STATE(sta) (sta->mlmStaContext.mlmState) +#define SET_LIM_STA_CONTEXT_MLM_STATE(sta, state) (sta->mlmStaContext.mlmState = state) +#define LIM_IS_CONNECTION_ACTIVE(pe_session) (pe_session->LimRxedBeaconCntDuringHB) +/*mac->lim.gLimProcessDefdMsgs*/ +#define GET_LIM_PROCESS_DEFD_MESGS(mac) (mac->lim.gLimProcessDefdMsgs) + +#ifdef WLAN_FEATURE_SR +/** + * enum sr_status_of_roamed_ap - SR(Spatial Reuse) status of roamed AP + * SR_DISALLOW: SR not supported by roamed AP + * SR_THRESHOLD_IN_RANGE: SR is supported by roamed AP/after param change + * in beacon/probe resp and the configured threshold is in range. + * SR_THRESHOLD_NOT_IN_RANGE: SR is supported by roamed AP/after param change + * in beacon/probe resp and configured threshold is not in range. + */ +enum sr_status_of_roamed_ap { + SR_DISALLOW, + SR_THRESHOLD_IN_RANGE, + SR_THRESHOLD_NOT_IN_RANGE, +}; +#endif + +/** + * lim_post_msg_api() - post normal priority PE message + * @mac: mac context + * @msg: message to be posted + * + * This function is called to post a message to the tail of the PE + * message queue to be processed in the MC Thread with normal + * priority. + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS on error + */ +QDF_STATUS lim_post_msg_api(struct mac_context *mac, struct scheduler_msg *msg); + +static inline void +lim_post_msg_to_process_deferred_queue(struct mac_context *mac) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + if (!mac->lim.gLimProcessDefdMsgs || !mac->lim.gLimDeferredMsgQ.size) + return; + + msg.type = SIR_LIM_PROCESS_DEFERRED_QUEUE; + msg.bodyptr = NULL; + msg.bodyval = 0; + + status = lim_post_msg_api(mac, &msg); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to post lim msg:0x%x", msg.type); +} + +#define SET_LIM_PROCESS_DEFD_MESGS(mac, val) \ + mac->lim.gLimProcessDefdMsgs = val; \ + pe_debug("Defer LIM msg %d", val); \ + lim_post_msg_to_process_deferred_queue(mac); + +/* LIM exported function templates */ +#define LIM_MIN_BCN_PR_LENGTH 12 +#define LIM_BCN_PR_CAPABILITY_OFFSET 10 +#define LIM_ASSOC_REQ_IE_OFFSET 4 + +/** + * enum lim_vendor_ie_access_policy - vendor ie access policy + * @LIM_ACCESS_POLICY_NONE: access policy not valid + * @LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT: respond only if vendor ie + * is present in probe request and assoc request frames + * @LIM_ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT: do not respond if vendor + * ie is present in probe request or assoc request frames + */ +enum lim_vendor_ie_access_policy { + LIM_ACCESS_POLICY_NONE, + LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT, + LIM_ACCESS_POLICY_DONOT_RESPOND_IF_IE_IS_PRESENT, +}; + +typedef enum eMgmtFrmDropReason { + eMGMT_DROP_NO_DROP, + eMGMT_DROP_NOT_LAST_IBSS_BCN, + eMGMT_DROP_INFRA_BCN_IN_IBSS, + eMGMT_DROP_SCAN_MODE_FRAME, + eMGMT_DROP_NON_SCAN_MODE_FRAME, + eMGMT_DROP_INVALID_SIZE, + eMGMT_DROP_SPURIOUS_FRAME, + eMGMT_DROP_DUPLICATE_AUTH_FRAME, + eMGMT_DROP_EXCESSIVE_MGMT_FRAME, + eMGMT_DROP_DEAUTH_DURING_ROAM_STARTED, +} tMgmtFrmDropReason; + +/** + * Function to initialize LIM state machines. + * This called upon LIM thread creation. + */ +QDF_STATUS lim_initialize(struct mac_context *); +QDF_STATUS pe_open(struct mac_context *mac, struct cds_config_info *cds_cfg); +QDF_STATUS pe_close(struct mac_context *mac); +QDF_STATUS lim_start(struct mac_context *mac); +QDF_STATUS pe_start(struct mac_context *mac); +void pe_stop(struct mac_context *mac); + +/** + * is_mgmt_protected - check RMF enabled for the peer + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * + * Return: True if RMF enabled and key is installed + */ +bool is_mgmt_protected(uint32_t vdev_id, const uint8_t *peer_mac_addr); + +/** + * lim_stop_pmfcomeback_timer() - stop pmf comeback timer + * @session: Pointer to PE session + * + * Return: None + */ +void lim_stop_pmfcomeback_timer(struct pe_session *session); + +/** + * pe_register_mgmt_rx_frm_callback() - registers callback for receiving + * mgmt rx frames + * @mac_ctx: mac global ctx + * + * This function registers a PE function to mgmt txrx component and a WMA + * function to WMI layer as event handler for receiving mgmt frames. + * + * Return: None + */ +void pe_register_mgmt_rx_frm_callback(struct mac_context *mac_ctx); + +/** + * pe_deregister_mgmt_rx_frm_callback() - degisters callback for receiving + * mgmt rx frames + * @mac_ctx: mac global ctx + * + * This function deregisters the PE function registered to mgmt txrx component + * and the WMA function registered to WMI layer as event handler for receiving + * mgmt frames. + * + * Return: None + */ +void pe_deregister_mgmt_rx_frm_callback(struct mac_context *mac_ctx); + +/** + * pe_register_callbacks_with_wma() - register SME and PE callback functions to + * WMA. + * @mac: mac global ctx + * @ready_req: Ready request parameters, containing callback pointers + * + * Return: None + */ +void pe_register_callbacks_with_wma(struct mac_context *mac, + struct sme_ready_req *ready_req); + +/** + * Function to cleanup LIM state. + * This called upon reset/persona change etc + */ +void lim_cleanup(struct mac_context *); + +/** + * lim_post_msg_high_priority() - post high priority PE message + * @mac: mac context + * @msg: message to be posted + * + * This function is called to post a message to the head of the PE + * message queue to be processed in the MC Thread with expedited + * priority. + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS on error + */ +QDF_STATUS lim_post_msg_high_priority(struct mac_context *mac, + struct scheduler_msg *msg); + +/** + * Function to process messages posted to LIM thread + * and dispatch to various sub modules within LIM module. + */ +void lim_message_processor(struct mac_context *, struct scheduler_msg *); + +/* / Function used by other Sirius modules to read global SME state */ +static inline tLimSmeStates lim_get_sme_state(struct mac_context *mac) +{ + return mac->lim.gLimSmeState; +} + +/** + * lim_received_hb_handler() - This function is called by + * sch_beacon_process() upon receiving a Beacon on STA. This + * also gets called upon receiving Probe Response after heat + * beat failure is detected. + * + * @mac - global mac structure + * @chan_freq - channel frequency indicated in Beacon, Probe + * + * Response return - none + */ +void lim_received_hb_handler(struct mac_context *, uint32_t, + struct pe_session *); + +/* / Function that triggers STA context deletion */ +void lim_trigger_sta_deletion(struct mac_context *mac, tpDphHashNode sta, + struct pe_session *pe_session); + +#ifdef FEATURE_WLAN_TDLS +/* Function that sends TDLS Del Sta indication to SME */ +void lim_send_sme_tdls_del_sta_ind(struct mac_context *mac, tpDphHashNode sta, + struct pe_session *pe_session, + uint16_t reasonCode); +#endif + +/** + * lim_detect_change_in_ap_capabilities() - Detect any change in AP's + * capabilities. + * @mac: Pointer to Global MAC structure + * @pBeacon: Pointer to parsed Beacon/probe rsp structure + * @session: pe session + * @is_bcn: if passed pointer is beacon or probe + * + * Return: void + */ +void lim_detect_change_in_ap_capabilities(struct mac_context *mac, + tpSirProbeRespBeacon pBeacon, + struct pe_session *session, + bool is_bcn); + +QDF_STATUS lim_update_short_slot(struct mac_context *mac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *); + +/** + * lim_ps_offload_handle_missed_beacon_ind() - handle missed beacon indication + * @mac: global mac context + * @msg: message + * + * This function process the SIR_HAL_MISSED_BEACON_IND + * message from HAL, to do active AP probing. + * + * Return: void + */ +void lim_ps_offload_handle_missed_beacon_ind(struct mac_context *mac, + struct scheduler_msg *msg); + +void lim_send_heart_beat_timeout_ind(struct mac_context *mac, struct pe_session *pe_session); +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac, + uint8_t *pRxPacketInfo, + uint32_t subType); + +bool lim_is_sb_disconnect_allowed_fl(struct pe_session *session, + const char *func, uint32_t line); + +/** + * lim_is_sb_disconnect_allowed() - check pe session state to see if disconnect + * is already in progress. + * @session: pe session + * + * Return: false if disconnect is already in progress + */ +#define lim_is_sb_disconnect_allowed(session) \ + lim_is_sb_disconnect_allowed_fl(session, __func__, __LINE__) + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * pe_roam_synch_callback() - Callback registered at wma, gets invoked when + * ROAM SYNCH event is received from firmware + * @mac_ctx: global mac context + * @vdev_id: VDEV id + * @roam_sync_ind_ptr: Structure with roam synch parameters + * @ie_len: ie length + * @reason: Operation to be done by the callback + * + * This is a PE level callback called from WMA to complete the roam synch + * propagation at PE level and also fill the BSS descriptor which will be + * helpful further to complete the roam synch propagation. + * + * Return: QDF_STATUS + */ +QDF_STATUS +pe_roam_synch_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *roam_sync_ind_ptr, + uint16_t ie_len, + enum sir_roam_op_code reason); + +void +lim_check_ft_initial_im_association(struct roam_offload_synch_ind *roam_synch, + struct pe_session *session_entry); + +/** + * pe_disconnect_callback() - Callback to handle deauth event is received + * from firmware + * @mac: pointer to global mac context + * @vdev_id: VDEV in which the event was received + * @deauth_disassoc_frame: Deauth/disassoc frame received from firmware + * @deauth_disassoc_frame_len: Length of @deauth_disassoc_frame + * @reason_code: Fw sent reason code if disassoc/deauth frame is not + * available + * + * Return: QDF_STATUS + */ +QDF_STATUS +pe_disconnect_callback(struct mac_context *mac, uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code); + +QDF_STATUS +pe_set_ie_for_roam_invoke(struct mac_context *mac_ctx, uint8_t vdev_id, + uint16_t dot11_mode, enum QDF_OPMODE opmode); + +#else +static inline QDF_STATUS +pe_roam_synch_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *roam_sync_ind_ptr, + uint16_t ie_len, + enum sir_roam_op_code reason) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +pe_disconnect_callback(struct mac_context *mac, uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +pe_set_ie_for_roam_invoke(struct mac_context *mac_ctx, uint8_t vdev_id, + uint16_t dot11_mode, enum QDF_OPMODE opmode) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * lim_update_lost_link_info() - update lost link information to SME + * @mac: global MAC handle + * @session: PE session + * @rssi: rssi value from the received frame + * + * Return: None + */ +void lim_update_lost_link_info(struct mac_context *mac, struct pe_session *session, + int32_t rssi); + +/** + * lim_mon_init_session() - create PE session for monitor mode operation + * @mac_ptr: mac pointer + * @msg: Pointer to struct sir_create_session type. + * + * Return: NONE + */ +void lim_mon_init_session(struct mac_context *mac_ptr, + struct sir_create_session *msg); + +/** + * lim_mon_deinit_session() - delete PE session for monitor mode operation + * @mac_ptr: mac pointer + * @msg: Pointer to struct sir_delete_session type. + * + * Return: NONE + */ +void lim_mon_deinit_session(struct mac_context *mac_ptr, + struct sir_delete_session *msg); + +#define limGetQosMode(pe_session, pVal) (*(pVal) = (pe_session)->limQosEnabled) +#define limGetWmeMode(pe_session, pVal) (*(pVal) = (pe_session)->limWmeEnabled) +#define limGetWsmMode(pe_session, pVal) (*(pVal) = (pe_session)->limWsmEnabled) +/* ----------------------------------------------------------------------- */ +static inline void lim_get_phy_mode(struct mac_context *mac, uint32_t *phyMode, + struct pe_session *pe_session) +{ + *phyMode = + pe_session ? pe_session->gLimPhyMode : mac->lim.gLimPhyMode; +} + +/* ----------------------------------------------------------------------- */ +static inline void lim_get_rf_band_new(struct mac_context *mac, + enum reg_wifi_band *band, + struct pe_session *pe_session) +{ + *band = pe_session ? pe_session->limRFBand : REG_BAND_UNKNOWN; +} + +/** + * pe_mc_process_handler() - Message Processor for PE + * @msg: Pointer to the message structure + * + * Verifies the system is in a mode where messages are expected to be + * processed, and if so, routes the message to the appropriate handler + * based upon message type. + * + * Return: QDF_STATUS_SUCCESS if the message was handled, otherwise an + * appropriate QDF_STATUS error code + */ +QDF_STATUS pe_mc_process_handler(struct scheduler_msg *msg); + +/** ------------------------------------------------------------- + \fn pe_free_msg + \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs) + \ to free a given PE message on the TX and MC thread. + \ This happens when there are messages pending in the PE + \ queue when system is being stopped and reset. + \param struct mac_context *mac + \param struct scheduler_msg pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(struct mac_context *mac, struct scheduler_msg *pMsg); + +/** + * lim_process_abort_scan_ind() - abort the scan which is presently being run + * + * @mac_ctx: Pointer to Global MAC structure + * @vdev_id: vdev_id + * @scan_id: Scan ID from the scan request + * @scan_requesor_id: Entity requesting the scan + * + * @return: None + */ +void lim_process_abort_scan_ind(struct mac_context *mac, uint8_t vdev_id, + uint32_t scan_id, uint32_t scan_requestor_id); + +void __lim_process_sme_assoc_cnf_new(struct mac_context *, uint32_t, uint32_t *); + +/** + * lim_handle_frame_genby_mbssid() - wrapper for beacon and probe response + * @frame: the pointer of frame data + * @frame_len: the length of frame data + * @frm_subtype: frame type + * @bssid: the pointer to bssid + * + * This function is used as wrapper to handle the beacon and probe response + * frames which is generated by MBSSID frame. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_handle_frame_genby_mbssid(uint8_t *frame, uint32_t frame_len, + uint8_t frm_subtype, char *bssid); + +/** + * lim_process_sme_addts_rsp_timeout(): Send addts rsp timeout to SME + * @mac: Pointer to Global MAC structure + * @param: Addts rsp timer count + * + * This function is used to reset the addts sent flag and + * send addts rsp timeout to SME + * + * Return: None + */ +void lim_process_sme_addts_rsp_timeout(struct mac_context *mac, uint32_t param); +QDF_STATUS lim_update_ext_cap_ie(struct mac_context *mac_ctx, uint8_t *ie_data, + uint8_t *local_ie_buf, uint16_t *local_ie_len, + struct pe_session *session); + +/** + * lim_handle_sap_beacon(): Handle the beacon received from scan module for SAP + * @pdev: pointer to the pdev object + * @scan_entry: pointer to the scan cache entry for the beacon + * + * Registered as callback to the scan module for handling beacon frames. + * This API filters the and allows beacons for SAP protection mechanisms + * if there are active SAP sessions and the received beacon's channel + * matches the SAP active channel + * + * Return: None + */ +void lim_handle_sap_beacon(struct wlan_objmgr_pdev *pdev, + struct scan_cache_entry *scan_entry); + +/** + * lim_translate_rsn_oui_to_akm_type() - translate RSN OUI to AKM type + * @auth_suite: auth suite + * + * Return: AKM type + */ +enum ani_akm_type lim_translate_rsn_oui_to_akm_type(uint8_t auth_suite[4]); + +#ifdef WLAN_SUPPORT_TWT +/** + * lim_fill_roamed_peer_twt_caps() - Update Peer TWT capabilities + * @mac_ctx: Pointer to mac context + * @vdev_id: vdev id + * @roam_synch: Pointer to roam synch indication + * + * Return: None + */ +void lim_fill_roamed_peer_twt_caps(struct mac_context *mac_ctx, uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch); + +/** + * lim_set_twt_peer_capabilities() - Update Peer TWT capabilities + * @mac_ctx: Pointer to mac context + * @peer_mac: peer mac address + * @he_cap: pointer to HE capabilities IE + * @he_op: pointer to HE IE + * + * Based on the peer IE capabilities, update the TWT peer private object + * + * Return: None + */ +void lim_set_twt_peer_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + tDot11fIEhe_cap *he_cap, + tDot11fIEhe_op *he_op); + +/** + * lim_set_twt_ext_capabilities() - Update twt caps for 11n devices + * @mac_ctx: Pointer to mac context + * @peer_mac: peer mac address + * @ext_cap: pointer to Extended capabilities IE + * + */ +void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + struct s_ext_cap *ext_cap); +#else +static inline +void lim_fill_roamed_peer_twt_caps(struct mac_context *mac_ctx, uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch) +{} + +static inline +void lim_set_twt_peer_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + tDot11fIEhe_cap *he_cap, + tDot11fIEhe_op *he_op) +{} + +static inline +void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + struct s_ext_cap *ext_cap) +{} +#endif + +/** + * lim_get_basic_rates() - Get basic rates for the given frequency + * @b_rates: Pointer to rates + * @chan_freq: frequency for which rates are required + * + * This api will get basic rates for the given frequency + * + * Return: void + */ +void lim_get_basic_rates(tSirMacRateSet *b_rates, uint32_t chan_freq); + +#define FW_CTS2SELF_PROFILE 34 + +/** + * lim_enable_cts_to_self_for_exempted_iot_ap() - enable cts to self for iot ap + * @mac_ctx: mac context + * @session: pe session + * @ie_ptr: ie pointer + * @ie_len: ie length + * + * Return: true on success else false + */ +bool lim_enable_cts_to_self_for_exempted_iot_ap( + struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *ie_ptr, + uint16_t ie_len); + +/** + * lim_fill_pe_session() - Lim fill pe session + * @mac_ctx: Pointer to mac context + * @session: pe session + * @bss_desc: Pointer to bss description + * + * This api will fill lim pe session with info + * from bss description + * + * Return: qdf status + */ +QDF_STATUS +lim_fill_pe_session(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_description *bss_desc); + +/** + * lim_update_omn_ie_ch_width() - update omn_ie_ch_width in struct + * assoc_channel_info while processing bcn/probe resp/assoc resp/re-assoc resp + * @vdev: VDEV object manager + * @ch_width: ch_width present in OMN IE + * + * Return: none + */ +void lim_update_omn_ie_ch_width(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width ch_width); + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * lim_add_bcn_probe() - Add the generated probe resp to scan DB + * @vdev: VDEV object manager + * @bcn_probe: Pointer to bcn/probe + * @len: Length of frame. + * @freq: Freq on frame. + * @rssi: RSSI of the frame. + * + * Prepares the meta data to add the generated bcn/probe frame to + * scan DB. + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe, + uint32_t len, qdf_freq_t freq, int32_t rssi); + +/** + * lim_update_mlo_mgr_info() - API to update mlo_mgr link info + * @mac_ctx: Pointer to mac context + * @vdev: vdev + * @link_addr: link address + * @link_id: Link id + * @freq: chan freq + * + * This api will update link sp[ecific info into mlo_mgr + * + * Return: qdf_status + */ +QDF_STATUS +lim_update_mlo_mgr_info(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *link_addr, uint8_t link_id, + uint16_t freq); +/** + * lim_gen_link_specific_probe_rsp() - Generate link specific prb response + * @mac_ctx: Pointer to mac context + * @session_entry: pe session + * @rcvd_probe_resp: Pointer to received prb resp from AP. + * @probe_rsp: ptr to prb rsp + * @probe_rsp_len: length of prb rsp + * @rssi : rssi for link + * + * This api will generate link specific probe response + * and save in scan database. + * + * Return: qdf status + */ +QDF_STATUS +lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirProbeRespBeacon rcvd_probe_resp, + uint8_t *probe_rsp, + uint32_t probe_rsp_len, + int32_t rssi); +/** + * lim_check_for_ml_probe_req() - check if ml probe req is sent + * @session: pe session + * + * Return qdf status + */ +QDF_STATUS lim_check_for_ml_probe_req(struct pe_session *session); + +/** + * lim_process_cu_for_probe_rsp() - process critical update for probe response + * @mac_ctx: Pointer to mac context + * @session: pe session + * @probe_rsp: ptr to probe response + * @probe_rsp_len: length of probe response + * + * This api will generate link specific probe response and invoke function + * to process critical update IEs + * + * Return: qdf status + */ +QDF_STATUS +lim_process_cu_for_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *probe_rsp, + uint32_t probe_rsp_len); + +#else +static inline QDF_STATUS +lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe, + uint32_t len, qdf_freq_t freq, int32_t rssi) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +lim_update_mlo_mgr_info(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *link_addr, uint8_t link_id, + uint16_t freq) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirProbeRespBeacon rcvd_probe_resp, + uint8_t *probe_rsp, + uint32_t probe_rsp_len, + int32_t rssi) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +lim_check_for_ml_probe_req(struct pe_session *session) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +lim_process_cu_for_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *probe_rsp, + uint32_t probe_rsp_len) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_SR + +/** + * lim_update_vdev_sr_elements() - Update VDEV variable with + * parsed values received in SRP IE + * @session_entry: pe session + * @sta_ds: STA node + * + * Return void + */ +void lim_update_vdev_sr_elements(struct pe_session *session_entry, + tpDphHashNode sta_ds); + +/** + * lim_process_srp_ie() - process srp ie during re/association + * @tpSirAssocRsp: assoc response + * @tpDphHashNode: sta node + * + * Return: success/failure + */ +QDF_STATUS lim_process_srp_ie(tpSirAssocRsp ar, tpDphHashNode sta_ds); + +/** + * lim_handle_sr_cap() - To handle SR(Spatial Reuse) capability + * of roamed AP + * @vdev: objmgr vdev + * @reason: reason for the update + * + * This function is to check and compare SR cap of previous and + * roamed AP and takes decision to send event to userspace. + * + * Return: None + */ +void lim_handle_sr_cap(struct wlan_objmgr_vdev *vdev, + enum sr_osif_reason_code reason); + +#else +static inline void +lim_update_vdev_sr_elements(struct pe_session *session_entry, + tpDphHashNode sta_ds) +{ +} + +static inline +QDF_STATUS lim_process_srp_ie(tpSirAssocRsp ar, tpDphHashNode sta_ds) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +lim_handle_sr_cap(struct wlan_objmgr_vdev *vdev, + enum sr_osif_reason_code reason) +{ +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +/** + * lim_cm_roam_create_session() - Create pe session for legacy to MLO roaming + * @mac_ctx: Pointer to mac context + * @vdev_id: vdev id + * @roam_synch: Pointer to roam synch indication + * + * This api will check if vdev is link vdev and create a new pe session + * for legacy to MLO roaming case. + * + * Return: pe session + */ +struct pe_session * +lim_cm_roam_create_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind); + +/** + * lim_create_and_fill_link_session() - handler for legacy to mlo roaming + * @mac_ctx: Pointer to mac context + * @vdev_id: vdev id + * @roam_synch: Pointer to roam synch indication + * @ie_len: ie length + * + * This is a lim level api called to handle legacy to MLO roaming scenario. + * + * Return: qdf status + */ +QDF_STATUS +lim_create_and_fill_link_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + uint16_t ie_len); + +/** + * lim_cm_fill_link_session() - Update link session parameters + * @mac_ctx: Pointer to mac context + * @vdev_id: vdev id + * @pe_session: Pointer to pe session + * @roam_synch: Pointer to roam synch indication + * @ie_len: ie length + * + * This api will fill pe session and also fill the BSS descriptor + * which will be helpful further to complete the roam synch propagation. + * + * Return: qdf status + */ +QDF_STATUS +lim_cm_fill_link_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct pe_session *pe_session, + struct roam_offload_synch_ind *sync_ind, + uint16_t ie_len); + +/** + * lim_roam_mlo_create_peer() - Create roam mlo peer + * @mac_ctx: Pointer to mac context + * @sync_ind: Pointer to roam synch indication + * @vdev_id: vdev id + * @peer_mac: Peer mac pointer + * + * This api will create mlo peer called during mlo roaming scenario + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_roam_mlo_create_peer(struct mac_context *mac, + struct roam_offload_synch_ind *sync_ind, + uint8_t vdev_id, uint8_t *peer_mac); + +/** + * lim_mlo_roam_delete_link_peer() - Delete mlo link peer + * @pe_session: Pointer to pe session + * @sta_ds: sta state node + * + * This api will delete mlo link peer called during mlo roaming scenario + * + * Return: none + */ +void +lim_mlo_roam_delete_link_peer(struct pe_session *pe_session, + tpDphHashNode sta_ds); +#else +static inline struct pe_session * +lim_cm_roam_create_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + return NULL; +} + +static inline QDF_STATUS +lim_create_and_fill_link_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + uint16_t ie_len) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +lim_cm_fill_link_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct pe_session *pe_session, + struct roam_offload_synch_ind *sync_ind, + uint16_t ie_len) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline QDF_STATUS +lim_roam_mlo_create_peer(struct mac_context *mac, + struct roam_offload_synch_ind *sync_ind, + uint8_t vdev_id, uint8_t *peer_mac) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +lim_mlo_roam_delete_link_peer(struct pe_session *pe_session, + tpDphHashNode sta_ds) +{ +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD && WLAN_FEATURE_11BE_MLO */ + +enum ani_akm_type +lim_get_connected_akm(struct pe_session *session, int32_t ucast_cipher, + int32_t auth_mode, int32_t akm); + +/** + * lim_get_encrypt_ed_type() - Get encrypt type + * @ucast_cipher: Ucast cipher + * + * Return: Encryption type enum + */ +tAniEdType lim_get_encrypt_ed_type(int32_t ucast_cipher); +/************************************************************/ +#endif /* __LIM_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_fils_defs.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_fils_defs.h new file mode 100644 index 0000000000..8c9acae85c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_fils_defs.h @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2017, 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wlan_crypto_global_def.h" + +#define FILS_EAP_TLV_MAX_DATA_LEN 255 +#define FILS_SHA256_128_AUTH_TAG 16 +#define FILS_SHA256_256_AUTH_TAG 32 + +/* RFC 6696 */ +#define RMSK_LABEL "Re-authentication Master Session Key@ietf.org" + +/* 12.12.2.5.3 80211-ai draft */ +#define PTK_KEY_LABEL "FILS PTK Derivation" +#define FT_PMK_R0_KEY_LABEL "FT-R0" +#define FT_PMK_R0_NAME_KEY_LABEL "FT-R0N" +#define FT_PMK_R1_NAME_KEY_LABEL "FT-R1N" + +#define PMKR0_SCATTER_LIST_ELEM 2 +#define PMKR1_SCATTER_LIST_ELEM 4 + +#define SCTR_LST_ELEM0 0 +#define SCTR_LST_ELEM1 1 +#define SCTR_LST_ELEM2 2 +#define SCTR_LST_ELEM3 3 + +/* Length of "FT-R1N" */ +#define SCTR_LST_R0_LABEL_LEN 6 +#define SCTR_LST_R1_LABEL_LEN 6 + +#define MAX_ICK_LEN 48 +#define MAX_KEK_LEN 64 +#define MAX_TK_LEN 32 +#define MAX_KEY_AUTH_DATA_LEN 48 +#define MAX_GTK_LEN 255 +#define MAX_IGTK_LEN 255 +#define SIR_FILS_SESSION_IE_LEN 11 +#define FILS_KEY_RSC_LEN 8 +#define FILS_MAX_KEY_AUTH_LEN (MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN) + +#define IPN_LEN 6 +#define FILS_SESSION_LENGTH 8 +#define FILS_MAX_KDE_LIST_LEN 255 + +/* 12.12.2.5.3 80211-ai draft */ +#define FILS_SHA384_KEK_LEN 64 +#define FILS_SHA256_KEK_LEN 32 + +/* 12.12.2.5.3 80211-ai draft */ +#define FILS_SHA256_ICK_LEN 32 +#define FILS_SHA384_ICK_LEN 48 + +#define TK_LEN_TKIP 32 +#define TK_LEN_CCMP 16 +#define TK_LEN_AES_128_CMAC 32 + +#define FILS_SHA256_PMK_LEN 32 +#define FILS_SHA384_PMK_LEN 48 + +#define FILS_FT_SHA256_LEN 32 +#define FILS_FT_SHA384_LEN 48 + +#define FILS_FT_MAX_R0_KEY_DATA_LEN 64 + +/* 12.7.1.7.3 802.11ai */ +#define FILS_SHA256_Q_LEN 32 +#define FILS_SHA384_Q_LEN 48 + +/* 9.4.2.180 FILS Session element */ +#define SIR_FILS_SESSION_LENGTH 8 +#define SIR_FILS_SESSION_EXT_EID 4 + +/* 9.4.2.184 FILS HLP Container Element */ +#define SIR_FILS_HLP_EXT_EID 5 + +/* 9.4.2.190 FILS Nonce element */ +#define SIR_FILS_NONCE_LENGTH 16 +#define SIR_FILS_NONCE_EXT_EID 13 + +/*9.4.2.188 FILS Wrapped Data element */ +#define SIR_FILS_WRAPPED_DATA_MAX_SIZE 255 +#define SIR_FILS_WRAPPED_DATA_EXT_EID 8 + +/* RFC 6696 5.3.1: EAP-Initiate/Re-auth-Start Packet */ +#define SIR_FILS_EAP_REAUTH_PACKET_TYPE 1 +#define SIR_FILS_EAP_INIT_PACKET_TYPE 2 + +#define FILS_AUTH_TAG_MAX_LENGTH 32 + +#define SIR_FILS_OPTIONAL_DATA_LEN 3 +/* RFC 6696 4.3: RiK deriavtion */ +#define SIR_FILS_RIK_LABEL "Re-authentication Integrity Key@ietf.org" + +/* RFC 6696 5.3.1: EAP-Initiate/Re-auth-Start Packet */ +#define SIR_FILS_EAP_TLV_KEYNAME_NAI 1 +#define SIR_FILS_EAP_TLV_R_RK_LIFETIME 2 +#define SIR_FILS_EAP_TLV_R_MSK_LIFETIME 3 +#define SIR_FILS_EAP_TLV_DOMAIN_NAME 4 +#define SIR_FILS_EAP_TLV_CRYPTO_LIST 5 +#define SIR_FILS_EAP_TLV_AUTH_INDICATION 6 + +#define DATA_TYPE_GTK 1 +#define DATA_TYPE_IGTK 9 +#define KEY_RSC_LEN 8 +#define KDE_IE_DATA_OFFSET 4 +#define KDE_DATA_TYPE_OFFSET 3 +#define GTK_OFFSET 2 +#define IPN_OFFSET 2 +#define IGTK_OFFSET 8 + +#define KDE_OUI_TYPE "\x00\x0F\xAC" +#define KDE_OUI_TYPE_SIZE 3 + +#define SINGLE_ELEMENT_HASH_CNT 1 + +/* + * struct eap_auth_reserved: this structure defines flags format in eap packets + * as defined in RFC 6696 5.3.1 + * flag_r: + * flag_b: + * flag_l: + */ +struct eap_auth_reserved { + uint8_t flag_r:1; + uint8_t flag_b:1; + uint8_t flag_l:1; + uint8_t reserved:5; +}; + +/* + * struct fils_eap_tlv: this structure defines the eap header + * for eap packet present in warpped data element IE + * @type: type of packet + * @length: length of packet + * @data: pointer to eap data + */ +struct fils_eap_tlv { + uint8_t type; + uint8_t length; + uint8_t data[FILS_EAP_TLV_MAX_DATA_LEN]; +}; + +/* struct fils_auth_rsp_info: this structure saves the info from + * fils auth response. + * @keyname: pointer to keyname nai + * @keylength: keyname nai length + * @domain_name: pointer to domain name + * @domain_len: domain length + * @r_rk_lifetime: rRk lifetime + * @r_msk_lifetime: RMSK lifetime + * @sequence: sequence number to be validated + * @fils_nonce: anonce + * @assoc_delay: time in ms, DUT needs to wait after association req + */ +struct fils_auth_rsp_info { + uint8_t *keyname; + uint8_t keylength; + uint8_t *domain_name; + uint8_t domain_len; + uint32_t r_rk_lifetime; + uint32_t r_msk_lifetime; + uint16_t sequence; + uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH]; + uint8_t assoc_delay; +}; + +#define FT_R0KH_ID_MAX_LEN 48 +#define FT_R1KH_ID_LEN 6 +#define FT_NONCE_LEN 32 + +/* MIC Length Specified in Table 12-8- 802.11-2016 Spec */ +#define FT_MIC_LEN 16 +#define FT_GTK_RSC_LEN 8 +#define FT_GTK_KEY_LEN 32 +#define FT_IGTK_KEY_ID_LEN 2 +#define FT_IGTK_IPN_LEN 6 +#define FT_IGTK_KEY_LEN 24 + +/** + * struct mac_ft_gtk_ie - structure to parse the gtk ie + * @present: flag to indicate ie is present + * @key_id: Key-Id + * @reserved: reserved bits + * @key_length: gtk key length + * @rsc: denotes the last TSC or PN sent using the GTK + * @num_key: number of keys + * @key: actual keys + */ +struct mac_ft_gtk_ie { + uint8_t present; + uint16_t key_id:2; + uint16_t reserved:14; + uint8_t key_len; + uint8_t rsc[FT_GTK_RSC_LEN]; + uint8_t num_key; + uint8_t key[FT_GTK_KEY_LEN]; +}; + +/** + * struct mac_ft_gtk_ie - structure to parse the gtk ie + * @present: IE present or not present + * @key_id: 2Byte Key-ID + * @ipn: icorresponds to the last packet number used by broadcaster/multicaster + * @key_len: IGTK key length + * @key: IGTK Key + */ +struct mac_ft_igtk_ie { + uint8_t present; + uint8_t key_id[FT_IGTK_KEY_ID_LEN]; + uint8_t ipn[FT_IGTK_IPN_LEN]; + uint8_t key_len; + uint8_t key[FT_IGTK_KEY_LEN]; +}; + +/** + * struct mac_ft_ie - structure to parse the FT ie from auth frame + * @present: true if IE is present in Auth Frame + * @element_count: number of elements + * @mic: MIC. Will be zero in auth frame sent from AP. (Refer 13.2.4 802.11ai) + * @anonce: Authenticator NONCE. Will be zero in auth frame sent from AP. + * @snonce: Supplicant NONCE. Will be zero in auth frame + * @r1kh_id: R1KH ID. Length of R1KH ID is fixed(6 bytes). + * @r0kh_id_len: Length of R0KH ID + * @r0kh_id: R0KH id + * @gtk_ie: GTK subelement in FTIE + * @igtk_ie: IGTK subelement in FTIE + */ +struct mac_ft_ie { + bool present; + uint8_t element_count; + uint8_t mic[FT_MIC_LEN]; + uint8_t anonce[FT_NONCE_LEN]; + uint8_t snonce[FT_NONCE_LEN]; + uint8_t r1kh_id[FT_R1KH_ID_LEN]; + uint8_t r0kh_id_len; + uint8_t r0kh_id[FT_R0KH_ID_MAX_LEN]; + struct mac_ft_gtk_ie gtk_ie; + struct mac_ft_igtk_ie igtk_ie; +}; + +#define FILS_PMK_LEN 48 +#define FILS_PMK_NAME_LEN 16 +#define FILS_FT_MAX_LEN 48 +#define FILS_FT_PMK_R0_SALT_LEN 16 +#define FILS_MAX_KEY_DATA_LEN \ + (MAX_ICK_LEN + MAX_KEK_LEN + MAX_TK_LEN + FILS_FT_MAX_LEN) + +/* + * struct pe_fils_session: fils session info used in PE session + * @is_fils_connection: whether connection is fils or not + * @keyname_nai_data: keyname nai data + * @keyname_nai_length: keyname nai length + * @akm: akm type will be used + * @auth: authentication type + * @cipher: cipher type + * @fils_erp_reauth_pkt: pointer to fils reauth packet data + * @fils_erp_reauth_pkt_len: reauth packet length + * @fils_rrk: pointer to fils rRk + * @fils_rrk_len: fils rRk length + * @fils_rik: pointer to fils rIk + * @fils_rik_len: fils rIk length + * @sequence_number: sequence number needs to be used in eap packet + * @fils_session: fils session IE element + * @fils_nonce: fils snonce + * @rsn_ie: rsn ie used in auth request + * @rsn_ie_len: rsn ie length + * @group_mgmt_cipher_suite_present: Check if group management cipher suite + * is present in the FILS RSN IE + * @ft_ie: structure to store the parsed FTIE from auth response frame + * @pmkr0: PMKR0 + * @pmkr0_len: length of PMKR0 key + * @pmkr0_name: PMK_R0 name derived + * @pmkr1_name: PMKR1 Name derived + * @fils_eap_finish_pkt: pointer to eap finish packet + * @fils_eap_finish_pkt_len: eap finish packet length + * @fils_rmsk: rmsk data pointer + * @fils_rmsk_len: rmsk data length + * @fils_pmk: pointer to pmk data + * @fils_pmk_len: pmk length + * @fils_pmkid: pointer to pmkid derived + * @auth_info: data obtained from auth response + * @ick: pointer to ick + * @ick_len: ick length + * @kek: pointer to kek + * @kek_len: kek length + * @tk: pointer to tk + * @tk_len: tk length + * @key_auth: data needs to be sent in assoc req, will be validated by AP + * @key_auth_len: key auth data length + * @ap_key_auth_data: data needs to be validated in assoc rsp + * @ap_key_auth_len: ap key data length + * @gtk_len: gtk key length + * @gtk: pointer to gtk data + * @fils_ft: xx_key data + * @fils_ft_len: xx_key length + * @rsc: rsc value + * @igtk_len: igtk length + * @igtk: igtk data pointer + * @ipn: pointer to ipn data + * @dst_mac: HLP destination mac address + * @src_mac: HLP source mac address + * @hlp_data_len: HLP data length + * @hlp_data: pointer to HLP data + */ +struct pe_fils_session { + bool is_fils_connection; + uint8_t *keyname_nai_data; + uint8_t keyname_nai_length; + uint8_t akm; + uint8_t auth; + uint8_t cipher; + uint8_t *fils_erp_reauth_pkt; + uint32_t fils_erp_reauth_pkt_len; + uint8_t *fils_rrk; + uint8_t fils_rrk_len; + uint8_t *fils_rik; + uint32_t fils_rik_len; + uint16_t sequence_number; + uint8_t fils_session[SIR_FILS_SESSION_LENGTH]; + uint8_t fils_nonce[SIR_FILS_NONCE_LENGTH]; + uint8_t rsn_ie[WLAN_MAX_IE_LEN + 2]; + uint8_t rsn_ie_len; + bool group_mgmt_cipher_present; + struct mac_ft_ie ft_ie; + uint8_t pmkr0[FILS_PMK_LEN]; + uint8_t pmkr0_len; + uint8_t pmkr0_name[FILS_PMK_NAME_LEN]; + uint8_t pmkr1_name[FILS_PMK_NAME_LEN]; + uint8_t *fils_eap_finish_pkt; + uint8_t fils_eap_finish_pkt_len; + uint8_t *fils_rmsk; + uint8_t fils_rmsk_len; + uint8_t *fils_pmk; + uint8_t fils_pmk_len; + uint8_t fils_pmkid[PMKID_LEN]; + struct fils_auth_rsp_info auth_info; + uint8_t ick[MAX_ICK_LEN]; + uint8_t ick_len; + uint8_t kek[MAX_KEK_LEN]; + uint8_t kek_len; + uint8_t tk[MAX_TK_LEN]; + uint8_t tk_len; + uint8_t fils_ft[FILS_FT_MAX_LEN]; + uint8_t fils_ft_len; + uint8_t key_auth[MAX_KEY_AUTH_DATA_LEN]; + uint8_t key_auth_len; + uint8_t ap_key_auth_data[MAX_KEY_AUTH_DATA_LEN]; + uint8_t ap_key_auth_len; + uint8_t gtk_len; + uint8_t gtk[MAX_GTK_LEN]; + uint8_t rsc; + uint8_t igtk_len; + uint8_t igtk[MAX_IGTK_LEN]; + uint8_t ipn[IPN_LEN]; + struct qdf_mac_addr dst_mac; + struct qdf_mac_addr src_mac; + uint16_t hlp_data_len; + uint8_t *hlp_data; +}; diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_ft.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_ft.h new file mode 100644 index 0000000000..e1eb500221 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_ft.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFT_H__ +#define __LIMFT_H__ + +#include +#include +#include +#include + +/*------------------------------------------------------------------------- + Function declarations and documentation + ------------------------------------------------------------------------*/ +void lim_ft_open(struct mac_context *mac, struct pe_session *pe_session); +void lim_ft_cleanup(struct mac_context *mac, struct pe_session *pe_session); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_ft_cleanup_pre_auth_info(struct mac_context *mac, + struct pe_session *pe_session); +bool lim_process_ft_pre_auth_req(struct mac_context *mac, + tpSirFTPreAuthReq ft_pre_auth_req); +void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac); + +/** + * lim_process_mlm_ft_reassoc_req() - Handle the Reassoc request + * @mac: Global MAC context + * @reassoc_req: reassoc req + * + * This function handles the Reassoc Req from SME + * + * Return: None + */ +void lim_process_mlm_ft_reassoc_req(struct mac_context *mac, + tLimMlmReassocReq *reassoc_req); +void lim_perform_ft_pre_auth(struct mac_context *mac, QDF_STATUS status, + uint32_t *data, struct pe_session *pe_session); +void lim_post_ft_pre_auth_rsp(struct mac_context *mac, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + struct pe_session *pe_session); +void lim_handle_ft_pre_auth_rsp(struct mac_context *mac, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_len, + struct pe_session *pe_session); +QDF_STATUS lim_ft_setup_auth_session(struct mac_context *mac, + struct pe_session *pe_session); +void lim_process_mlm_reassoc_cnf(struct mac_context *mac_ctx, uint32_t *msg); +/** + * lim_process_sta_mlm_add_bss_rsp_ft() - Handle ft add bss response + * @mac: Global MAC context + * @add_bss_rsp: Bss params rsp data + * @pe_session: PE Session + * + * Function to handle fast roaming add bss response in FT reassoc state, + * send reassociation Request. + * + * Return: None + */ +void lim_process_sta_mlm_add_bss_rsp_ft(struct mac_context *mac, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *pe_session); +void lim_process_mlm_reassoc_req(struct mac_context *mac_ctx, + tLimMlmReassocReq *reassoc_req); + +/** + * lim_preauth_scan_event_handler() - Process preauth scan events + * @mac_ctx:Pointer to global MAC structure + * @event: Scan event + * @vdev_id: vdev id + * @scan_id: scan id from WMA scan event. + * + * If scan event signifies failure or successful completion, operation + * is complete. + * If scan event signifies that STA is on foreign channel, send auth frame + * + * Return: void + */ +void lim_preauth_scan_event_handler(struct mac_context *mac_ctx, + enum sir_scan_event_type event, + uint8_t vdev_id, uint32_t scan_id); +QDF_STATUS lim_send_preauth_scan_offload(struct mac_context *mac_ctx, + struct pe_session *session_entry, tSirFTPreAuthReq *ft_preauth_req); +#else +static inline void lim_ft_cleanup_pre_auth_info(struct mac_context *mac, + struct pe_session *pe_session) +{} +static inline void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac) +{} +static inline +void lim_process_mlm_ft_reassoc_req(struct mac_context *mac, + tLimMlmReassocReq *reassoc_req) +{} +static inline void lim_handle_ft_pre_auth_rsp(struct mac_context *mac, + QDF_STATUS status, uint8_t *auth_rsp, + uint16_t auth_rsp_len, struct pe_session *pe_session) +{} +static inline void lim_process_mlm_reassoc_cnf(struct mac_context *mac_ctx, + uint32_t *msg) +{} +static inline +void lim_process_sta_mlm_add_bss_rsp_ft(struct mac_context *mac, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *pe_session) +{} +static inline void lim_process_mlm_reassoc_req(struct mac_context *mac_ctx, + tLimMlmReassocReq *reassoc_req) +{} +static inline void lim_preauth_scan_event_handler(struct mac_context *mac_ctx, + enum sir_scan_event_type event, + uint8_t vdev_id, uint32_t scan_id) +{} +static inline bool lim_process_ft_pre_auth_req( + struct mac_context *mac, tpSirFTPreAuthReq ft_pre_auth_req) +{ + return false; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS +lim_fill_ft_session(struct mac_context *mac, + struct bss_description *pbssDescription, + struct pe_session *ft_session, + struct pe_session *pe_session, + enum wlan_phymode bss_phymode); + +/** + * lim_ft_prepare_add_bss_req() - Create Add Bss Req to the new AP + * @mac: Global MAC context + * @add_bss_params: Bss params including rsp data + * @pe_session: PE Session + * + * This will be used when we are ready to FT to the new AP. + * The newly created ft Session entry is passed to this function + * + * Return: None + */ +void lim_ft_prepare_add_bss_req(struct mac_context *mac, + struct pe_session *ft_session, + struct bss_description *bssDescription); + +QDF_STATUS lim_send_preauth_scan_offload(struct mac_context *mac_ctx, + struct pe_session *session_entry, tSirFTPreAuthReq *ft_preauth_req); +#else +static inline QDF_STATUS +lim_fill_ft_session(struct mac_context *mac + struct bss_description *pbssDescription, + struct pe_session *ft_session, + struct pe_session *pe_session, + enum wlan_phymode bss_phymode) +{ + return QDF_STATUS_SUCCESS; +} +static inline void lim_ft_prepare_add_bss_req(struct mac_context *mac, + struct pe_session *ft_session, + struct bss_description *bssDescription) +{} +#endif + +QDF_STATUS lim_process_ft_aggr_qos_req(struct mac_context *mac, + uint32_t *msg_buf); +void lim_process_ft_aggr_qos_rsp(struct mac_context *mac, + struct scheduler_msg *limMsg); +void lim_ft_cleanup_all_ft_sessions(struct mac_context *mac); +#endif /* __LIMFT_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h new file mode 100644 index 0000000000..46ab5cb196 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_ft_defs.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + Macros and Function prototypes FT and 802.11R purposes + + ========================================================================*/ + +#ifndef __LIMFTDEFS_H__ +#define __LIMFTDEFS_H__ + +#include +#include "wma_if.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +/* Time to dwell on preauth channel during roaming, in milliseconds */ +#define LIM_FT_PREAUTH_ACTIVE_SCAN_TIME 50 +#define LIM_FT_PREAUTH_PASSIVE_SCAN_TIME 150 + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/*-------------------------------------------------------------------------- + FT Pre Auth Req SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthReq { + uint16_t messageType; /* eWNI_SME_FT_PRE_AUTH_REQ */ + uint16_t length; + uint32_t dot11mode; + /* + * Track if response is processed for this request + * We expect only one response per request. + */ + bool bPreAuthRspProcessed; + uint16_t pre_auth_channel_freq; + /* BSSID currently associated to suspend the link */ + tSirMacAddr currbssId; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + tSirMacAddr self_mac_addr; + uint32_t scan_id; + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; + struct bss_description *pbssDescription; +} tSirFTPreAuthReq, *tpSirFTPreAuthReq; + +/*------------------------------------------------------------------------- + FT Pre Auth Rsp PE<->SME + ------------------------------------------------------------------------*/ +typedef struct sSirFTPreAuthRsp { + uint16_t messageType; /* eWNI_SME_FT_PRE_AUTH_RSP */ + uint16_t length; + uint8_t vdev_id; + tSirMacAddr preAuthbssId; /* BSSID to preauth to */ + QDF_STATUS status; + uint16_t ft_ies_length; + uint8_t ft_ies[MAX_FTIE_SIZE]; +} tSirFTPreAuthRsp, *tpSirFTPreAuthRsp; + +/*-------------------------------------------------------------------------- + FT Pre Auth Rsp Key SME<->PE + ------------------------------------------------------------------------*/ +typedef struct sSirFTUpdateKeyInfo { + uint16_t messageType; + uint16_t length; + uint32_t vdev_id; + struct qdf_mac_addr bssid; +} tSirFTUpdateKeyInfo, *tpSirFTUpdateKeyInfo; + +/*------------------------------------------------------------------------- + Global FT Information + ------------------------------------------------------------------------*/ +typedef struct sFTPEContext { + tpSirFTPreAuthReq pFTPreAuthReq; /* Saved FT Pre Auth Req */ + QDF_STATUS ftPreAuthStatus; + uint16_t saved_auth_rsp_length; + uint8_t saved_auth_rsp[MAX_FTIE_SIZE]; + /* Items created for the new FT, session */ + void *pAddBssReq; /* Save add bss req */ + void *pAddStaReq; /*Save add sta req */ + uint32_t peSessionId; + uint32_t smeSessionId; + + /* This flag is required to indicate on which session the preauth + * has taken place, since the auth response for preauth will come + * for a new BSSID for which there is no session yet. This flag + * will be used to extract the session from the session preauth + * has been initiated + */ + bool ftPreAuthSession; +} tftPEContext, *tpftPEContext; + +#endif /* __LIMFTDEFS_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_global.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_global.h new file mode 100644 index 0000000000..f0848ec905 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_global.h @@ -0,0 +1,448 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_global.h contains the definitions exported by + * LIM module. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_GLOBAL_H +#define __LIM_GLOBAL_H + +#include "wni_api.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "wni_cfg.h" +#include "csr_api.h" +#include "sap_api.h" +#include "dot11f.h" +#include "wma_if.h" + +/* Deferred Message Queue Length */ +#define MAX_DEFERRED_QUEUE_LEN 80 + +#ifdef CHANNEL_HOPPING_ALL_BANDS +#define CHAN_HOP_ALL_BANDS_ENABLE 1 +#else +#define CHAN_HOP_ALL_BANDS_ENABLE 0 +#endif + +/* enums exported by LIM are as follows */ + +/*System role definition */ +typedef enum eLimSystemRole { + eLIM_UNKNOWN_ROLE, + eLIM_AP_ROLE, + eLIM_STA_ROLE, + eLIM_P2P_DEVICE_ROLE, + eLIM_P2P_DEVICE_GO, + eLIM_P2P_DEVICE_CLIENT, + eLIM_NDI_ROLE +} tLimSystemRole; + +/* + * SME state definition accessible across all Sirius modules. + * AP only states are LIM_SME_CHANNEL_SCAN_STATE & + * LIM_SME_NORMAL_CHANNEL_SCAN_STATE. + * Note that these states may also be present in STA + * side too when DFS support is present for a STA in IBSS mode. + */ +typedef enum eLimSmeStates { + eLIM_SME_OFFLINE_STATE, + eLIM_SME_IDLE_STATE, + eLIM_SME_SUSPEND_STATE, + eLIM_SME_WT_JOIN_STATE, + eLIM_SME_WT_AUTH_STATE, + eLIM_SME_WT_ASSOC_STATE, + eLIM_SME_WT_REASSOC_STATE, + eLIM_SME_JOIN_FAILURE_STATE, + eLIM_SME_ASSOCIATED_STATE, + eLIM_SME_REASSOCIATED_STATE, + eLIM_SME_LINK_EST_STATE, + eLIM_SME_WT_PRE_AUTH_STATE, + eLIM_SME_WT_DISASSOC_STATE, + eLIM_SME_WT_DEAUTH_STATE, + eLIM_SME_WT_START_BSS_STATE, + eLIM_SME_WT_STOP_BSS_STATE, + eLIM_SME_NORMAL_STATE, +} tLimSmeStates; + +/* + * MLM state definition. + * While these states are present on AP too when it is + * STA mode, per-STA MLM state exclusive to AP is: + * eLIM_MLM_WT_AUTH_FRAME3. + */ +typedef enum eLimMlmStates { + eLIM_MLM_OFFLINE_STATE, + eLIM_MLM_IDLE_STATE, + eLIM_MLM_WT_JOIN_BEACON_STATE, + eLIM_MLM_JOINED_STATE, + eLIM_MLM_BSS_STARTED_STATE, + eLIM_MLM_WT_AUTH_FRAME2_STATE, + eLIM_MLM_WT_AUTH_FRAME3_STATE, + eLIM_MLM_WT_AUTH_FRAME4_STATE, + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE, + eLIM_MLM_AUTHENTICATED_STATE, + eLIM_MLM_WT_ASSOC_RSP_STATE, + eLIM_MLM_WT_REASSOC_RSP_STATE, + eLIM_MLM_ASSOCIATED_STATE, + eLIM_MLM_REASSOCIATED_STATE, + eLIM_MLM_LINK_ESTABLISHED_STATE, + eLIM_MLM_WT_ASSOC_CNF_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_STATE, + eLIM_MLM_WT_DEL_BSS_RSP_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE, + eLIM_MLM_WT_ADD_STA_RSP_STATE, + eLIM_MLM_WT_DEL_STA_RSP_STATE, + /* + * MLM goes to this state when LIM initiates DELETE_STA + * as processing of Assoc req because the entry already exists. + * LIM comes out of this state when DELETE_STA response from + * HAL is received. LIM needs to maintain this state so that ADD_STA + * can be issued while processing DELETE_STA response from HAL. + */ + eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE, + eLIM_MLM_WT_SET_BSS_KEY_STATE, + eLIM_MLM_WT_SET_STA_KEY_STATE, + eLIM_MLM_WT_SET_STA_BCASTKEY_STATE, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE, + eLIM_MLM_WT_SAE_AUTH_STATE, + eLIM_MLM_WT_FT_AUTH_STATE, +} tLimMlmStates; + +/* 11h channel switch states */ + +/* + * This enum indicates in which state the channel-swith + * is presently operating. + * eLIM_11H_CHANSW_INIT - Default state + * eLIM_11H_CHANSW_RUNNING - When channel switch is running + * eLIM_11H_CHANSW_END - After channel switch is complete + */ +typedef enum eLimDot11hChanSwStates { + eLIM_11H_CHANSW_INIT, + eLIM_11H_CHANSW_RUNNING, + eLIM_11H_CHANSW_END +} tLimDot11hChanSwStates; + +/* MLM Req/Cnf structure definitions */ +typedef struct sLimMlmAuthReq { + tSirMacAddr peerMacAddr; + tAniAuthType authType; + uint8_t sessionId; +} tLimMlmAuthReq, *tpLimMlmAuthReq; + +typedef struct sLimMlmJoinReq { + uint8_t sessionId; + struct bss_description bssDescription; + /* + * WARNING: Pls make bssDescription as last variable in struct + * tLimMlmJoinReq as it has ieFields followed after this bss + * description. Adding a variable after this corrupts the ieFields + */ +} tLimMlmJoinReq, *tpLimMlmJoinReq; + +/* Forward declarations */ +struct sSirAssocReq; +struct sDphHashNode; + +/* struct lim_assoc_data - Assoc data to be cached to defer association + * indication to SME + * @present: Indicates whether assoc data is present or not + * @sub_type: Indicates whether it is Association Request(=0) or Reassociation + * Request(=1) frame + * @sa: Mac address of requesting peer + * @assoc_req: pointer to parsed ASSOC/REASSOC Request frame + * @pmf_connection: flag indicating pmf connection + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * @dup_entry: flag indicating if duplicate entry found + * @sta_ds: station dph entry + * @partner_peer_idx: peer_idx which is already allocated by partner link + */ +struct lim_assoc_data { + bool present; + uint8_t sub_type; + tSirMacAddr sa; + struct sSirAssocReq *assoc_req; + bool pmf_connection; + bool assoc_req_copied; + bool dup_entry; + struct sDphHashNode *sta_ds; + uint16_t partner_peer_idx; +}; + +/* Pre-authentication structure definition */ +typedef struct tLimPreAuthNode { + struct tLimPreAuthNode *next; + tSirMacAddr peerMacAddr; + tAniAuthType authType; + tLimMlmStates mlmState; + uint8_t authNodeIdx; + uint8_t challengeText[SIR_MAC_AUTH_CHALLENGE_LENGTH]; + uint8_t fTimerStarted:1; + uint8_t fSeen:1; + uint8_t fFree:1; + uint8_t rsvd:5; + TX_TIMER timer; + uint16_t seq_num; + unsigned long timestamp; + /* keeping copy of association request received, this is + * to defer the association request processing + */ + struct lim_assoc_data assoc_req; + bool is_mlo_ie_present; +#ifdef WLAN_FEATURE_11BE_MLO + tSirMacAddr peer_mld; +#endif +} tLimPreAuthNode, *tpLimPreAuthNode; + +/* Pre-authentication table definition */ +typedef struct tLimPreAuthTable { + uint32_t numEntry; + tLimPreAuthNode **pTable; +} tLimPreAuthTable, *tpLimPreAuthTable; + +/** + * struct lim_sta_context - LIM per STA structure + * @mlmState: LIM State + * @authType: Authentication algorithm + * @akm_type: AKM of the connection + * @listenInterval: Listen interval + * @capabilityInfo: Capabilities + * @disassocReason: Disassociation reason code + * @resultCode: Result code + * @subType: Indicates association or reassociation + * @updateContext: Update context + * @schClean: Scheduler clean + * @htCapability: 802.11n HT capability + * @vhtCapability: 802.11ac VHT capability + * @cleanupTrigger: Cleanup trigger + * @protStatusCode: Protocol Status code + * @he_capable: 802.11ax HE capability + * @owe_ie: Pointer to OWE IE + * @owe_ie_len: Length of OWE IE + * @ft_ie: Pointer to FT related IE + * @ft_ie_len: Length of FT related IE + * @eht_capable: 802.11be EHT capability + */ +struct lim_sta_context { + tLimMlmStates mlmState; + tAniAuthType authType; /* auth algo in auth frame */ + enum ani_akm_type akm_type; /* akm in rsn/wpa ie */ + uint16_t listenInterval; + tSirMacCapabilityInfo capabilityInfo; + enum wlan_reason_code disassocReason; + + tSirResultCodes resultCode; + + uint8_t subType:1; /* Indicates ASSOC (0) or REASSOC (1) */ + uint8_t updateContext:1; + uint8_t schClean:1; + /* 802.11n HT Capability in Station: Enabled 1 or DIsabled 0 */ + uint8_t htCapability:1; + uint8_t vhtCapability:1; + uint16_t cleanupTrigger; + uint16_t protStatusCode; +#ifdef WLAN_FEATURE_11AX + bool he_capable; +#endif + bool force_1x1; + uint8_t *owe_ie; + uint32_t owe_ie_len; + uint8_t *ft_ie; + uint32_t ft_ie_len; +#ifdef WLAN_FEATURE_11BE + bool eht_capable; +#endif +}; + +/* Structure definition to hold deferred messages queue parameters */ +typedef struct sLimDeferredMsgQParams { + struct scheduler_msg deferredQueue[MAX_DEFERRED_QUEUE_LEN]; + uint16_t size; + uint16_t read; + uint16_t write; +} tLimDeferredMsgQParams, *tpLimDeferredMsgQParams; + +typedef struct sCfgProtection { + uint32_t overlapFromlla:1; + uint32_t overlapFromllb:1; + uint32_t overlapFromllg:1; + uint32_t overlapHt20:1; + uint32_t overlapNonGf:1; + uint32_t overlapLsigTxop:1; + uint32_t overlapRifs:1; + uint32_t overlapOBSS:1; /* added for obss */ + uint32_t fromlla:1; + uint32_t fromllb:1; + uint32_t fromllg:1; + uint32_t ht20:1; + uint32_t nonGf:1; + uint32_t lsigTxop:1; + uint32_t rifs:1; + uint32_t obss:1; /* added for Obss */ +} tCfgProtection, *tpCfgProtection; + +typedef enum eLimProtStaCacheType { + eLIM_PROT_STA_CACHE_TYPE_INVALID, + eLIM_PROT_STA_CACHE_TYPE_llB, + eLIM_PROT_STA_CACHE_TYPE_llG, + eLIM_PROT_STA_CACHE_TYPE_HT20 +} tLimProtStaCacheType; + +typedef struct sCacheParams { + uint8_t active; + tSirMacAddr addr; + tLimProtStaCacheType protStaCacheType; + +} tCacheParams, *tpCacheParams; + +#define LIM_PROT_STA_OVERLAP_CACHE_SIZE HAL_NUM_ASSOC_STA +#define LIM_PROT_STA_CACHE_SIZE HAL_NUM_ASSOC_STA + +typedef struct sLimProtStaParams { + uint8_t numSta; + uint8_t protectionEnabled; +} tLimProtStaParams, *tpLimProtStaParams; + +typedef struct sLimNoShortParams { + uint8_t numNonShortPreambleSta; + tCacheParams staNoShortCache[LIM_PROT_STA_CACHE_SIZE]; +} tLimNoShortParams, *tpLimNoShortParams; + +typedef struct sLimNoShortSlotParams { + uint8_t numNonShortSlotSta; + tCacheParams staNoShortSlotCache[LIM_PROT_STA_CACHE_SIZE]; +} tLimNoShortSlotParams, *tpLimNoShortSlotParams; + +/* Enums used for channel switching. */ +typedef enum eLimChannelSwitchState { + eLIM_CHANNEL_SWITCH_IDLE, + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY, + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY +} tLimChannelSwitchState; + +/* Channel Switch Info */ +typedef struct sLimChannelSwitchInfo { + tLimChannelSwitchState state; + uint32_t sw_target_freq; + uint8_t primaryChannel; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + uint8_t sec_ch_offset; + enum phy_ch_width ch_width; +#ifdef WLAN_FEATURE_11BE + uint16_t puncture_bitmap; +#endif + int8_t switchCount; + uint32_t switchTimeoutValue; + uint8_t switchMode; +} tLimChannelSwitchInfo, *tpLimChannelSwitchInfo; + +typedef struct sLimOperatingModeInfo { + uint8_t present; + uint8_t chanWidth:4; + uint8_t rxNSS:3; + uint8_t rxNSSType:1; +} tLimOperatingModeInfo, *tpLimOperatingModeInfo; + +typedef struct sLimWiderBWChannelSwitch { + uint8_t newChanWidth; + uint8_t newCenterChanFreq0; + uint8_t newCenterChanFreq1; +} tLimWiderBWChannelSwitchInfo, *tpLimWiderBWChannelSwitchInfo; + +typedef struct sLimTspecInfo { + /* 0==free, else used */ + uint8_t inuse; + /* index in list */ + uint8_t idx; + tSirMacAddr staAddr; + uint16_t assocId; + struct mac_tspec_ie tspec; + /* number of Tclas elements */ + uint8_t numTclas; + tSirTclasInfo tclasInfo[SIR_MAC_TCLASIE_MAXNUM]; + uint8_t tclasProc; + /* tclassProc is valid only if this is set to 1. */ + uint8_t tclasProcPresent:1; +} qdf_packed tLimTspecInfo, *tpLimTspecInfo; + +typedef struct sLimAdmitPolicyInfo { + /* admit control policy type */ + uint8_t type; + /* oversubscription factor : 0 means nothing is allowed */ + uint8_t bw_factor; + /* valid only when 'type' is set BW_FACTOR */ +} tLimAdmitPolicyInfo, *tpLimAdmitPolicyInfo; + +typedef enum eLimWscEnrollState { + eLIM_WSC_ENROLL_NOOP, + eLIM_WSC_ENROLL_BEGIN, + eLIM_WSC_ENROLL_IN_PROGRESS, + eLIM_WSC_ENROLL_END +} tLimWscEnrollState; + +#define WSC_PASSWD_ID_PUSH_BUTTON (0x0004) + +typedef struct sLimWscIeInfo { + bool apSetupLocked; + bool selectedRegistrar; + uint16_t selectedRegistrarConfigMethods; + tLimWscEnrollState wscEnrollmentState; + tLimWscEnrollState probeRespWscEnrollmentState; + uint8_t reqType; + uint8_t respType; +} tLimWscIeInfo, *tpLimWscIeInfo; + +/* maximum number of tspec's supported */ +#define LIM_NUM_TSPEC_MAX 15 + +/* structure to hold all 11h specific data */ +typedef struct sLimSpecMgmtInfo { + tLimDot11hChanSwStates dot11hChanSwState; +} tLimSpecMgmtInfo, *tpLimSpecMgmtInfo; + +/** + * struct lim_delba_req_info - Delba request struct + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @tid: tid + * @reason_code: reason code + */ +struct lim_delba_req_info { + uint8_t vdev_id; + tSirMacAddr peer_macaddr; + uint8_t tid; + uint8_t reason_code; +}; +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_process_fils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_process_fils.h new file mode 100644 index 0000000000..0f55bb261c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_process_fils.h @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __LIM_PROCESS_FILS_H +#define __LIM_PROCESS_FILS_H + +#include +#include +#include +#include + +#ifdef WLAN_FEATURE_FILS_SK + +/** + * lim_process_fils_auth_frame2()- This API processes fils data from auth resp + * @mac_ctx: mac context + * @session: PE session + * @rx_auth_frm_body: pointer to auth frame + * + * Return: true if fils data needs to be processed else false + */ +bool lim_process_fils_auth_frame2(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tSirMacAuthFrameBody * rx_auth_frm_body); + +/** + * lim_add_fils_data_to_auth_frame()- This API adds fils data to auth frame. + * Following will be added in this. + * 1. RSNIE + * 2. SNonce + * 3. Session + * 4. Wrapped data + * @session: PE session + * @body: pointer to auth frame where data needs to be added + * + * Return: None + */ +void lim_add_fils_data_to_auth_frame(struct pe_session *session, uint8_t *body); + +/** + * lim_is_valid_fils_auth_frame()- This API checks whether auth frame is a + * valid frame. + * @mac_ctx: mac context + * @pe_session: pe session pointer + * @rx_auth_frm_body: pointer to autherntication frame + * + * Return: true if frame is valid or fils is disable, false otherwise + */ +bool lim_is_valid_fils_auth_frame(struct mac_context *mac_ctx, + struct pe_session *pe_session, tSirMacAuthFrameBody *rx_auth_frm_body); + +/** + * lim_create_fils_rik()- This API create rik using rrk coming from + * supplicant. + * @rrk: input rrk + * @rrk_len: rrk length + * @rik: Created rik + * @rik_len: rik length to be filled + * + * rIK = KDF (K, S), where + * K = rRK and + * S = rIK Label + "\0" + cryptosuite + length + * The rIK Label is the 8-bit ASCII string: + * Re-authentication Integrity Key@ietf.org + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_create_fils_rik(uint8_t *rrk, uint8_t rrk_len, + uint8_t *rik, uint32_t *rik_len); + +/** + * lim_update_fils_config()- This API updates fils session info to csr config + * from join request. + * @mac_ctx: pointer to mac context + * @session: PE session + * @join_req: pointer to join request + * + * Return: None + */ +void lim_update_fils_config(struct mac_context *mac_ctx, + struct pe_session *session, + struct cm_vdev_join_req *join_req); + +/** + * lim_create_fils_auth_data()- This API creates the fils auth data + * which needs to be sent in auth req. + * @mac_ctx: mac context + * @auth_frame: pointer to auth frame + * @session: PE session + * + * Return: length of fils data + */ +QDF_STATUS lim_create_fils_auth_data(struct mac_context *mac_ctx, + tpSirMacAuthFrameBody auth_frame, + struct pe_session *session, + uint32_t *frame_len); + +/** + * lim_increase_fils_sequence_number: this API increases fils sequence number in + * the event of resending auth packet + * @session_entry: pointer to PE session + * + * Return: None + */ +static inline void lim_increase_fils_sequence_number(struct pe_session *session_entry) +{ + if (!session_entry->fils_info) + return; + + if (session_entry->fils_info->is_fils_connection) + session_entry->fils_info->sequence_number++; +} + +/** + * populate_fils_connect_params() - Populate FILS connect params to join rsp + * @mac_ctx: Mac context + * @session: PE session + * @connect_rsp: connect join rsp + * + * This API copies the FILS connect params from PE session to SME join rsp + * + * Return: None + */ +void +populate_fils_connect_params(struct mac_context *mac_ctx, + struct pe_session *session, + struct wlan_cm_connect_resp *connect_rsp); + +/** + * lim_update_fils_hlp_data() - Update the hlp data from association + * response frame to PE session. + * @hlp_frm_src_mac: SRC mac address in HLP IE from assoc frame + * @hlp_frm_dst_mac: DST mac address in HLP IE from assoc frame + * @frm_hlp_len: HLP data length + * @frm_hlp_data: Pointer to hlp data + * @pe_session: Pointer to pe_session + * + * Return: None + */ +void lim_update_fils_hlp_data(struct qdf_mac_addr *hlp_frm_src_mac, + struct qdf_mac_addr *hlp_frm_dest_mac, + uint16_t frm_hlp_len, uint8_t *frm_hlp_data, + struct pe_session *pe_session); + +/** + * aead_encrypt_assoc_req() - Encrypt FILS IE's in assoc request + * @mac_ctx: mac context + * @pe_session: PE session + * @frame: packed frame buffer + * @payload: length of @frame + * + * This API is used to encrypt the all the IE present after FILS session IE + * in Association request frame + * + * Return: QDF_STATUS + */ +QDF_STATUS aead_encrypt_assoc_req(struct mac_context *mac_ctx, + struct pe_session *pe_session, + uint8_t *frame, uint32_t *payload); + +/** + * aead_decrypt_assoc_rsp() - API for AEAD decryption in FILS connection + * @mac_ctx: MAC context + * @session: PE session + * @ar: Assoc response frame structure + * @p_frame: frame buffer received + * @n_frame: length of @p_frame + * + * This API is used to decrypt the AEAD encrypted part of FILS assoc response + * and populate the decrypted FILS IE's to Assoc response frame structure(ar) + * + * Return: QDF_STATUS + */ +QDF_STATUS aead_decrypt_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocResponse *ar, + uint8_t *p_frame, uint32_t *n_frame); +/** + * lim_is_fils_connection() - Check if it is FILS connection + * @pe_session: PE session + * + * This API is used to check if current PE session is FILS connection + * + * Return: True if FILS connection, false if not + */ +static inline bool lim_is_fils_connection(struct pe_session *pe_session) +{ + if (pe_session->fils_info->is_fils_connection) + return true; + return false; +} + +/** + * lim_verify_fils_params_assoc_rsp() - Verify FILS params in assoc rsp + * @mac_ctx: Mac context + * @session_entry: PE session + * @assoc_rsp: Assoc response received + * @assoc_cnf: Assoc cnf msg to be sent to MLME + * + * This API is used to match FILS params received in Assoc response + * with Assoc params received/derived at the Authentication stage + * + * Return: True, if successfully matches. False, otherwise + */ +bool lim_verify_fils_params_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirAssocRsp assoc_rsp, + tLimMlmAssocCnf * assoc_cnf); +#else +static inline bool lim_process_fils_auth_frame2(struct mac_context *mac_ctx, + struct pe_session *pe_session, tSirMacAuthFrameBody *rx_auth_frm_body) +{ + return false; +} + +static inline void +lim_increase_fils_sequence_number(struct pe_session *session_entry) +{ } + +static inline void +lim_add_fils_data_to_auth_frame(struct pe_session *session, uint8_t *body) +{ +} + +static inline bool lim_is_valid_fils_auth_frame(struct mac_context *mac_ctx, + struct pe_session *pe_session, tSirMacAuthFrameBody *rx_auth_frm_body) +{ + return true; +} + +static inline void lim_update_fils_config(struct mac_context *mac_ctx, + struct pe_session *session, + struct cm_vdev_join_req *join_req) +{} + +static inline +QDF_STATUS lim_create_fils_auth_data(struct mac_context *mac_ctx, + tpSirMacAuthFrameBody auth_frame, + struct pe_session *session, + uint32_t *frame_len); +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool lim_is_fils_connection(struct pe_session *pe_session) +{ + return false; +} + +static inline void +populate_fils_connect_params(struct mac_context *mac_ctx, + struct pe_session *session, + struct wlan_cm_connect_resp *connect_rsp) +{ } + +static inline +void lim_update_fils_hlp_data(struct qdf_mac_addr *hlp_frm_src_mac, + struct qdf_mac_addr *hlp_frm_dest_mac, + uint16_t frm_hlp_len, uint8_t *frm_hlp_data, + struct pe_session *pe_session) +{} + +static inline QDF_STATUS aead_encrypt_assoc_req(struct mac_context *mac_ctx, + struct pe_session *pe_session, + uint8_t *frame, + uint32_t *payload) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS aead_decrypt_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocResponse *ar, + uint8_t *p_frame, uint32_t *n_frame) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool lim_verify_fils_params_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirAssocRsp assoc_rsp, + tLimMlmAssocCnf *assoc_cnf) + +{ + return true; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_session.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_session.h new file mode 100644 index 0000000000..38516bd1e2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_session.h @@ -0,0 +1,1275 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__LIM_SESSION_H) +#define __LIM_SESSION_H + +#include "wlan_cm_public_struct.h" +/**========================================================================= + + \file lim_session.h + + \brief prototype for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/* Master Structure: This will be part of PE Session Entry */ +typedef struct sPowersaveoffloadInfo { + uint8_t bcnmiss; +} tPowersaveoffloadInfo, tpPowersaveoffloadInfo; + +struct comeback_timer_info { + struct mac_context *mac; + uint8_t vdev_id; + uint8_t retried; + tLimMlmStates lim_prev_mlm_state; /* Previous MLM State */ + tLimMlmStates lim_mlm_state; /* MLM State */ +}; +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ +#define SCH_PROTECTION_RESET_TIME 4000 + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct { + tSirMacBeaconInterval beaconInterval; + uint8_t fShortPreamble; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20Coexist; + uint8_t llnNonGFCoexist; + uint8_t fRIFSMode; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t gHTObssMode; +} tBeaconParams, *tpBeaconParams; + +typedef struct join_params { + uint16_t prot_status_code; + uint16_t pe_session_id; + tSirResultCodes result_code; +} join_params; + +struct reassoc_params { + uint16_t prot_status_code; + tSirResultCodes result_code; + struct pe_session *session; +}; + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +#define MAX_BSS_COLOR_VALUE 63 +#define TIME_BEACON_NOT_UPDATED 30000 +#define BSS_COLOR_SWITCH_COUNTDOWN 5 +#define OBSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS 120000 +#define OBSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS 120000 +/* + * Have OBSS scan duration as 1200 seconds(20 minutes) when there is an active + * NDP to avoid glitches during NDP traffic due the scan. + */ +#define OBSS_COLOR_COLLISION_DETECTION_NDP_PERIOD_MS 1200000 +#define OBSS_COLOR_COLLISION_SCAN_PERIOD_MS 200 +#define OBSS_COLOR_COLLISION_FREE_SLOT_EXPIRY_MS 50000 +struct bss_color_info { + qdf_time_t timestamp; + uint64_t seen_count; +}; +#endif + +/** + * struct obss_detection_cfg - current obss detection cfg set to firmware + * @obss_11b_ap_detect_mode: detection mode for 11b access point. + * @obss_11b_sta_detect_mode: detection mode for 11b station. + * @obss_11g_ap_detect_mode: detection mode for 11g access point. + * @obss_11a_detect_mode: detection mode for 11a access point. + * @obss_ht_legacy_detect_mode: detection mode for ht ap with legacy mode. + * @obss_ht_mixed_detect_mode: detection mode for ht ap with mixed mode. + * @obss_ht_20mhz_detect_mode: detection mode for ht ap with 20mhz mode. + */ +struct obss_detection_cfg { + uint8_t obss_11b_ap_detect_mode; + uint8_t obss_11b_sta_detect_mode; + uint8_t obss_11g_ap_detect_mode; + uint8_t obss_11a_detect_mode; + uint8_t obss_ht_legacy_detect_mode; + uint8_t obss_ht_mixed_detect_mode; + uint8_t obss_ht_20mhz_detect_mode; +}; + +#define ADAPTIVE_11R_STA_IE_LEN 0x0B +#define ADAPTIVE_11R_STA_OUI "\x00\x00\x0f\x22" +#define ADAPTIVE_11R_OUI_LEN 0x04 +#define ADAPTIVE_11R_OUI_SUBTYPE 0x00 +#define ADAPTIVE_11R_OUI_VERSION 0x01 +#define ADAPTIVE_11R_DATA_LEN 0x04 +#define ADAPTIVE_11R_OUI_DATA "\x00\x00\x00\x01" + +#ifdef WLAN_FEATURE_11BE_MLO +#define WLAN_STA_PROFILE_MAX_LEN 514 +#define WLAN_MLO_IE_COM_MAX_LEN 257 + +/** + * struct wlan_mlo_sta_profile - Per STA profile structure + * @num_data: the length of data + * @data: the Per STA profile subelement data. Subelement ID + LEN + others, + * if num_data more than 257, it includes the frag IE for tx; it does not + * include the frag IE since it has been skipped when store the IE. + */ +struct wlan_mlo_sta_profile { + uint16_t num_data; + uint8_t data[WLAN_STA_PROFILE_MAX_LEN]; +}; + +/** + * struct medium_sync_delay - medium sync delay info + * @medium_sync_duration: medium sync duration + * @medium_sync_ofdm_ed_thresh: medium sync OFDM ED threshold + * @medium_sync_max_txop_num: medium sync max txop num + */ +struct medium_sync_delay { + uint16_t medium_sync_duration:8; + uint16_t medium_sync_ofdm_ed_thresh:4; + uint16_t medium_sync_max_txop_num:4; +}; + +/** + * struct eml_capabilities - EML capability info + * @emlsr_support: EMLSR support + * @emlsr_padding_delay: EMLSR padding delay + * @emlsr_transition_delay: EMLSR transition delay + * @emlmr_support: EMLSR support + * @emlmr_delay: EMLSR delay + * @transition_timeout: transition timeout + * @reserved: reserve + */ +struct eml_capabilities { + uint16_t emlsr_support:1; + uint16_t emlsr_padding_delay:3; + uint16_t emlsr_transition_delay:3; + uint16_t emlmr_support:1; + uint16_t emlmr_delay:3; + uint16_t transition_timeout:4; + uint16_t reserved:1; +}; + +/** + * struct mld_capab_and_op - MLD capability and operations info + * @max_simultaneous_link_num: MAX simultaneous link num + * @srs_support: SRS support + * @tid_link_map_supported: TID link map support + * @str_freq_separation: STR freq separation + * @aar_support: AAR support + * @reserved: reserve + */ +struct mld_capab_and_op { + uint16_t max_simultaneous_link_num:4; + uint16_t srs_support:1; + uint16_t tid_link_map_supported:2; + uint16_t str_freq_separation:5; + uint16_t aar_support:1; + uint16_t reserved:3; +}; + +/** + * struct ext_mld_capab_and_op - EXT MLD capability and operations info + * @op_parameter_update_support: operation parameter update support + * @rec_max_simultaneous_links: recommended max simultaneous links + * @reserved: reserved + */ +struct ext_mld_capab_and_op { + uint16_t op_parameter_update_support:1; + uint16_t rec_max_simultaneous_links:3; + uint16_t reserved:11; +}; + +/** + * struct wlan_mlo_ie - wlan ML IE info + * @type: the variant of the ML IE + * @reserved: reserved + * @link_id_info_present: the present flag of link id info + * @bss_param_change_cnt_present: the present flag of bss prarm change cnt + * @medium_sync_delay_info_present: the present flag of medium sync delay info + * @eml_capab_present: the present flag of EML capability + * @mld_capab_and_op_present: the present flag of MLD capability and operation + * @mld_id_present: the present flag of MLD ID + * @ext_mld_capab_and_op_present: Extended MLD Capabilities And + * Operations Present + * @reserved_1: reserved + * @common_info_length: common info length + * @mld_mac_addr: MLD mac address + * @link_id: link id + * @bss_param_change_count: bss param change count + * @medium_sync_delay_info: structure of medium_sync_delay + * @eml_capabilities_info: structure of eml_capabilities + * @mld_capab_and_op_info: structure of mld_capabilities and operations + * @mld_id_info: MLD ID + * @ext_mld_capab_and_op_info: structure of ext_mld_capab_and operations + * @num_sta_profile: the number of sta profile + * @sta_profile: structure of wlan_mlo_sta_profile + * @num_data: the length of data + * @data: the ML IE data, includes element ID + length + extension element ID + + * multi-link control and common info. + */ +struct wlan_mlo_ie { + uint16_t type:3; + uint16_t reserved:1; + uint16_t link_id_info_present:1; + uint16_t bss_param_change_cnt_present:1; + uint16_t medium_sync_delay_info_present:1; + uint16_t eml_capab_present:1; + uint16_t mld_capab_and_op_present: 1; + uint16_t mld_id_present: 1; + uint16_t ext_mld_capab_and_op_present: 1; + uint16_t reserved_1:5; + uint8_t common_info_length; + uint8_t mld_mac_addr[6]; + uint8_t link_id; + uint8_t bss_param_change_count; + struct medium_sync_delay medium_sync_delay_info; + struct eml_capabilities eml_capabilities_info; + struct mld_capab_and_op mld_capab_and_op_info; + uint8_t mld_id_info; + struct ext_mld_capab_and_op ext_mld_capab_and_op_info; + uint16_t num_sta_profile; + struct wlan_mlo_sta_profile sta_profile[WLAN_MLO_MAX_VDEVS]; + uint16_t num_data; + uint8_t data[WLAN_MLO_IE_COM_MAX_LEN]; +}; + +/** + * struct mlo_link_ie - IE per link to populate mlo ie + * @link_ds: DS IE + * @link_edca: ecsa IE + * @link_wmm_params: wmm params IE + * @link_wmm_caps: wmm caps IE + * @link_csa: csa IE + * @link_ecsa:ecsa IE + * @link_swt_time: switch time IE + * @link_quiet: quiet IE + * @link_ht_cap: ht cap IE + * @link_ht_info: ht info IE + * @link_cap: link caps IE + * @link_ext_cap: link extend cap IE + * @link_vht_cap: vht cap IE + * @link_vht_op: vht op IE + * @link_qcn_ie: qcn IE + * @link_he_cap: he cap IE + * @link_he_op: he op IE + * @link_he_6ghz_band_cap: 6G band cap IE + * @link_eht_cap: eht cap IE + * @link_eht_op: eht op IE + * @max_chan_swt_time: MLOTD + * @bss_param_change_cnt: bss param change count + */ +struct mlo_link_ie { + tDot11fIEDSParams link_ds; + tDot11fIEEDCAParamSet link_edca; + tDot11fIEWMMParams link_wmm_params; + tDot11fIEWMMCaps link_wmm_caps; + tDot11fIEChanSwitchAnn link_csa; + tDot11fIEext_chan_switch_ann link_ecsa; + tDot11fIEmax_chan_switch_time link_swt_time; + tDot11fIEQuiet link_quiet; + tDot11fIEHTCaps link_ht_cap; + tDot11fIEHTInfo link_ht_info; + tDot11fFfCapabilities link_cap; + tDot11fIEExtCap link_ext_cap; + tDot11fIEVHTCaps link_vht_cap; + tDot11fIEVHTOperation link_vht_op; + tDot11fIEqcn_ie link_qcn_ie; + tDot11fIEhe_cap link_he_cap; + tDot11fIEhe_op link_he_op; + tDot11fIEhe_6ghz_band_cap link_he_6ghz_band_cap; + tDot11fIEeht_cap link_eht_cap; + tDot11fIEeht_op link_eht_op; + uint32_t max_chan_swt_time; + uint8_t bss_param_change_cnt; +}; + +/** + * struct mlo_link_ie_info - information per link to populate mlo ie + * @upt_bcn_mlo_ie: notify partner links to update their mlo ie of bcn temp + * @bss_param_change: bss param changed + * @bcn_tmpl_exist: bcn template is generated or not + * @link_ie: IEs which will be used for generating partner mlo IE + */ +struct mlo_link_ie_info { + bool upt_bcn_mlo_ie; + bool bss_param_change; + bool bcn_tmpl_exist; + struct mlo_link_ie link_ie; +}; + +/** + * struct wlan_mlo_ie_info - struct for mlo IE information + * @mld_mac_addr: MLD MAC address + * @common_info_length: Common Info Length + * @reserved_1: reserved bits + * @mld_id_present: MLD ID present + * @mld_capab_and_op_present: MLD capability and operations present + * @eml_capab_present: EML capability present + * @medium_sync_delay_info_present: Medium sync delay information present + * @bss_param_change_cnt_present: BSS parameter change count present + * @link_id_info_present: Link ID information present + * @ext_mld_capab_and_op_present: Extended MLD Capabilities And + * Operations Present + * @reserved: reserved bit + * @type: Type bits + */ +struct wlan_mlo_ie_info { +#ifndef ANI_LITTLE_BIT_ENDIAN + uint8_t mld_mac_addr[6]; + uint8_t common_info_length; + uint16_t reserved_1:5; + uint16_t ext_mld_capab_and_op_present:1; + uint16_t mld_id_present:1; + uint16_t mld_capab_and_op_present:1; + uint16_t eml_capab_present:1; + uint16_t medium_sync_delay_info_present:1; + uint16_t bss_param_change_cnt_present:1; + uint16_t link_id_info_present:1; + uint16_t reserved:1; + uint16_t type:3; +#else + uint16_t type:3; + uint16_t reserved:1; + uint16_t link_id_info_present:1; + uint16_t bss_param_change_cnt_present:1; + uint16_t medium_sync_delay_info_present:1; + uint16_t eml_capab_present:1; + uint16_t mld_capab_and_op_present:1; + uint16_t mld_id_present:1; + uint16_t ext_mld_capab_and_op_present:1; + uint16_t reserved_1:5; + uint8_t common_info_length; + uint8_t mld_mac_addr[6]; +#endif +} qdf_packed; + +#endif + +/** + * struct pe_session - per-vdev PE context + * @available: true if the entry is available, false if it is in use + * @cm_id: + * @peSessionId: unique ID assigned to the entry + * @smeSessionId: ID of the session (legacy nomenclature) + * @vdev_id: ID of the vdev for which this entry is applicable + * @vdev: the actual vdev for which this entry is applicable + * @bssId: BSSID of the session + * @self_mac_addr: self MAC address + * * In AP role: BSSID and self_mac_addr will be the same. + * * In STA role: they will be different + * @ssId: + * @valid: + * @limMlmState: MLM State + * @limPrevMlmState: Previous MLM State + * @limSmeState: SME State + * @limPrevSmeState: Previous SME State + * @limSystemRole: + * @bssType: + * @nwType: + * @pLimStartBssReq: + * @lim_join_req: handle to sme join req + * @pLimReAssocReq: handle to sme reassoc req + * @pLimMlmJoinReq: handle to MLM join Req + * @pLimMlmReassocRetryReq: keep reasoc req for retry + * @pLimMlmReassocReq: handle to MLM reassoc Req + * @channelChangeReasonCode: + * @dot11mode: + * @htCapability: + * @connected_akm: AKM of current connection + * @htSupportedChannelWidthSet: HT Supported Channel Width Set: + * * 0 - 20MHz + * * 1 - 40MHz + * @htRecommendedTxWidthSet: Recommended Tx Width Set: + * * 0 - use 20 MHz channel (control channel) + * * 1 - use channel width enabled under Supported Channel Width Set + * @htSecondaryChannelOffset: Identifies the 40 MHz extension channel + * @limRFBand: + * @limCurrentAuthType: + * @limCurrentBssCaps: + * @limCurrentBssQosCaps: + * @limSentCapsChangeNtf: + * @limAID: + * @limReAssocbssId: + * @lim_reassoc_chan_freq: + * @reAssocHtSupportedChannelWidthSet: + * @reAssocHtRecommendedTxWidthSet: + * @reAssocHtSecondaryChannelOffset: + * @limReassocSSID: + * @limReassocBssCaps: + * @limReassocBssQosCaps: + * @limAssocResponseData: Assoc or ReAssoc Response Data/Frame + * @statypeForBss: to know session is for PEER or SELF + * @shortSlotTimeSupported: + * @dtimPeriod: + * @rateSet: + * @extRateSet: + * @htOperMode: + * @curr_op_freq: + * @curr_req_chan_freq: + * @LimRxedBeaconCntDuringHB: + * @lastBeaconTimeStamp: Time stamp of the last beacon received from the BSS + * to which STA is connected. + * @currentBssBeaconCnt: RX Beacon count for the current BSS to which STA + * is connected. + * @bcon_dtim_period: Beacon DTIM period + * @bcnLen: Length of @beacon + * @beacon: Used to store last beacon / probe response before assoc. + * @assocReqLen: Length of @assoc_req + * @assoc_req: Used to store association request frame + * @assocRspLen: Length of @assocRsp + * @assocRsp: Used to store association response received while associating + * @dph: + * @parsedAssocReq: Used to store parsed assoc req from various requesting + * station + * @RICDataLen: Length of @ricData + * @ricData: Used to store the Ric data received in the assoc response + * @tspecLen: Length of @tspecIes + * @tspecIes: Used to store the TSPEC IEs received in the assoc response + * @encryptType: + * @gLimProtectionControl: used for 11n protection + * @gHTNonGFDevicesPresent: + * @cfgProtection: protection related config cache + * @gLim11bParams: Number of legacy STAs associated + * @gLim11aParams: Number of 11A STAs associated + * @gLim11gParams: Number of non-ht non-legacy STAs associated + * @gLimNonGfParams: Number of nonGf STA associated + * @gLimHt20Params: Number of HT 20 STAs associated + * @gLimLsigTxopParams: Number of Lsig Txop not supported STAs associated + * @gLimNoShortParams: Number of STAs that do not support short preamble + * @gLimNoShortSlotParams: Number of STAs that do not support short slot time + * @gLimOlbcParams: OLBC parameters + * @gLimOverlap11gParams: OLBC parameters + * @gLimOverlap11aParams: + * @gLimOverlapHt20Params: + * @gLimOverlapNonGfParams: + * @protStaCache: cache for each overlap + * @privacy: + * @authType: + * @WEPKeyMaterial: + * @wmm_params: + * @gStartBssRSNIe: + * @gStartBssWPAIe: + * @APWPSIEs: + * @apUapsdEnable: + * @pAPWPSPBCSession: + * @DefProbeRspIeBitmap: + * @proxyProbeRspEn: + * @probeRespFrame: + * @ssidHidden: + * @fwdWPSPBCProbeReq: + * @wps_state: + * @wps_registration: + * @limQosEnabled: Is 802.11e QoS enabled + * @limWmeEnabled: Is WME enabled + * @limWsmEnabled: Is WSM enabled + * @limHcfEnabled: Is HCF enabled + * @limRmfEnabled: Is 802.11w RMF enabled + * @lim11hEnable: Is 802.11h enabled + * @maxTxPower: Max transmit power, the minimum of Regulatory and local + * power constraint) + * @min_11h_pwr: + * @max_11h_pwr: + * @opmode: + * @txMgmtPower: + * @is11Rconnection: + * @is_adaptive_11r_connection: flag to check if we are connecting + * @isESEconnection: + * @eseContext: + * @isFastTransitionEnabled: + * @isFastRoamIniFeatureEnabled: + * @p2pGoPsUpdate: + * @defaultAuthFailureTimeout: + * @gLimEdcaParams: These EDCA parameters are used locally on AP or STA. + * If STA, then these are values taken from the Assoc Rsp when associating, + * or Beacons/Probe Response after association. If AP, then these are + * values originally set locally on AP. + * @gLimEdcaParamsBC: These EDCA parameters are use by AP to broadcast + * to other STATIONs in the BSS. + * @gLimEdcaParamsActive: These EDCA parameters are what's actively being + * used on station. Specific AC values may be downgraded depending on + * admission control for that particular AC. + * @gLimEdcaParamSetCount: + * @beaconParams: + * @vhtCapability: + * @gLimOperatingMode: + * @vhtCapabilityPresentInBeacon: + * @ch_center_freq_seg0: center freq number as advertised OTA + * @ch_width: Session max channel width + * @ap_ch_width: AP advertised channel width + * @puncture_bitmap: + * @ch_center_freq_seg1: + * @enableVhtpAid: + * @enableVhtGid: + * @gLimWiderBWChannelSwitch: + * @enableAmpduPs: + * @send_smps_action: + * @spectrumMgtEnabled: + * @gLimSpecMgmt: + * @gLimChannelSwitch: CB Primary/Secondary Channel Switch Info + * @gLimPhyMode: + * @txLdpcIniFeatureEnabled: + * @gpLimPeerIdxpool: free peer index pool. A non-zero value indicates that + * peer index is available for assignment. + * @freePeerIdxHead: + * @freePeerIdxTail: + * @gLimNumOfCurrentSTAs: + * @peerAIDBitmap: + * @tdls_send_set_state_disable: + * @fWaitForProbeRsp: + * @fIgnoreCapsChange: + * @fDeauthReceived: + * @rssi: + * @max_amsdu_num: + * @ht_config: + * @vht_config: + * @gLimCurrentBssUapsd: + * @gUapsdPerAcBitmask: Used on STA, this is a static UAPSD mask setting + * derived from SME_JOIN_REQ and SME_REASSOC_REQ. If a + * particular AC bit is set, it means the AC is both + * trigger enabled and delivery enabled. + * @gUapsdPerAcTriggerEnableMask: Used on STA, this is a dynamic UPASD mask + * setting derived from AddTS Rsp and DelTS + * frame. If a particular AC bit is set, it + * means AC is trigger enabled. + * @gUapsdPerAcDeliveryEnableMask: Used on STA, dynamic UPASD mask setting + * derived from AddTS Rsp and DelTs frame. If + * a particular AC bit is set, it means AC is + * delivery enabled. + * @csaOffloadEnable: Flag to skip CSA IE processing when CSA offload is + * enabled. + * @gAcAdmitMask: Used on STA for AC downgrade. This is a dynamic mask + * setting which keep tracks of ACs being admitted. + * If bit is set to 0: That particular AC is not admitted + * If bit is set to 1: That particular AC is admitted + * @pmmOffloadInfo: Power Save Off load Parameters + * @smpsMode: SMPS mode + * @chainMask: + * @dfsIncludeChanSwIe: Flag to indicate Chan Sw announcement is required + * @dfsIncludeChanWrapperIe: Flag to indicate Chan Wrapper Element is required + * @bw_update_include_ch_sw_ie: Flag to indicate chan switch Element is required + * due to bandwidth update + * @cc_switch_mode: + * @isCiscoVendorAP: + * @add_ie_params: + * @pSchProbeRspTemplate: + * @pSchBeaconFrameBegin: Beginning portion of the beacon frame to be written + * to TFP + * @pSchBeaconFrameEnd: Trailing portion of the beacon frame to be written + * to TFP + * @schBeaconOffsetBegin: Size of the beginning portion + * @schBeaconOffsetEnd: Size of the trailing portion + * @isOSENConnection: + * @QosMapSet: DSCP to UP mapping for HS 2.0 + * @bRoamSynchInProgress: + * @ftPEContext: Fast Transition (FT) Context + * @isNonRoamReassoc: + * @pmf_retry_timer: + * @pmf_retry_timer_info: + * @protection_fields_reset_timer: timer for resetting protection fields + * at regular intervals + * @ap_ecsa_timer: timer to decrement CSA/ECSA count + * @ap_ecsa_wakelock: wakelock to complete CSA operation. + * @ap_ecsa_runtime_lock: runtime lock to complete SAP CSA operation. + * to Adaptive 11R network + * @mac_ctx: MAC context + * @old_protection_state: variable to store state of various protection + * struct like gLimOlbcParams, gLimOverlap11gParams, + * gLimOverlapHt20Params etc + * @prev_ap_bssid: + * @sap_advertise_avoid_ch_ie: tells if Q2Q IE, from another MDM device in + * AP MCC mode was received + * @is_ese_version_ie_present: + * @sap_dot11mc: + * @is_vendor_specific_vhtcaps: + * @vendor_specific_vht_ie_sub_type: + * @vendor_vht_sap: + * @hs20vendor_ie: HS 2.0 Indication + * @country_info_present: flag to indicate country code in beacon + * @nss: + * @nss_forced_1x1: + * @add_bss_failed: + * @obss_ht40_scanparam: OBSS Scan IE Parameters + * @vdev_nss: + * @supported_nss_1x1: Supported NSS is intersection of self and peer NSS + * @is_ext_caps_present: + * @beacon_tx_rate: + * @access_policy_vendor_ie: + * @access_policy: + * @send_p2p_conf_frame: + * @process_ho_fail: + * @lim_non_ecsa_cap_num: Number of STAs that do not support ECSA capability + * @he_capable: + * @he_config: + * @he_op: + * @he_sta_obsspd: + * @he_6ghz_band: + * @he_bss_color_change: + * @bss_color_info: + * @bss_color_changing: + * @deauth_retry: + * @enable_bcast_probe_rsp: + * @ht_client_cnt: + * @ch_switch_in_progress: + * @he_with_wep_tkip: + * @fils_info: + * @prev_auth_seq_num: Sequence number of previously received auth frame to + * detect duplicate frames. + * @prev_auth_mac_addr: mac_addr of the sta correspond to @prev_auth_seq_num + * @obss_offload_cfg: + * @current_obss_detection: + * @is_session_obss_offload_enabled: + * @is_obss_reset_timer_initialized: + * @sae_pmk_cached: + * @recvd_deauth_while_roaming: + * @recvd_disassoc_while_roaming: + * @deauth_disassoc_rc: + * @obss_color_collision_dec_evt: + * @is_session_obss_color_collision_det_enabled: + * @ap_mu_edca_params: + * @mu_edca_present: + * @def_max_tx_pwr: + * @active_ba_64_session: + * @is_mbssid_enabled: + * @peer_twt_requestor: + * @peer_twt_responder: + * @enable_session_twt_support: + * @cac_duration_ms: + * @stop_bss_reason: + * @prot_status_code: + * @result_code: + * @dfs_regdomain: + * @ap_defined_power_type_6g: 6 GHz power type advertised by AP + * @best_6g_power_type: best 6 GHz power type + * @sta_follows_sap_power: + * @eht_capable: + * @eht_config: + * @eht_op: + * @mlo_link_info: + * @ml_partner_info: + * @mlo_ie_total_len: + * @mlo_ie: + * @user_edca_set: + * @is_oui_auth_assoc_6mbps_2ghz_enable: send auth/assoc req with 6 Mbps rate + * @is_unexpected_peer_error: true if unexpected peer error + * on 2.4 GHz + * @join_probe_cnt: join probe request count + */ +struct pe_session { + uint8_t available; + wlan_cm_id cm_id; + uint16_t peSessionId; + union { + uint8_t smeSessionId; + uint8_t vdev_id; + }; + struct wlan_objmgr_vdev *vdev; + + tSirMacAddr bssId; + tSirMacAddr self_mac_addr; + tSirMacSSid ssId; + uint8_t valid; + tLimMlmStates limMlmState; + tLimMlmStates limPrevMlmState; + tLimSmeStates limSmeState; + tLimSmeStates limPrevSmeState; + tLimSystemRole limSystemRole; + enum bss_type bssType; + tSirNwType nwType; + struct start_bss_config *pLimStartBssReq; + struct join_req *lim_join_req; + struct join_req *pLimReAssocReq; + tpLimMlmJoinReq pLimMlmJoinReq; + void *pLimMlmReassocRetryReq; + void *pLimMlmReassocReq; + uint16_t channelChangeReasonCode; + uint8_t dot11mode; + uint8_t htCapability; + enum ani_akm_type connected_akm; + + uint8_t htSupportedChannelWidthSet; + uint8_t htRecommendedTxWidthSet; + ePhyChanBondState htSecondaryChannelOffset; + enum reg_wifi_band limRFBand; + + tAniAuthType limCurrentAuthType; + uint16_t limCurrentBssCaps; + uint8_t limCurrentBssQosCaps; + uint8_t limSentCapsChangeNtf; + uint16_t limAID; + + tSirMacAddr limReAssocbssId; + uint32_t lim_reassoc_chan_freq; + uint8_t reAssocHtSupportedChannelWidthSet; + uint8_t reAssocHtRecommendedTxWidthSet; + ePhyChanBondState reAssocHtSecondaryChannelOffset; + tSirMacSSid limReassocSSID; + uint16_t limReassocBssCaps; + uint8_t limReassocBssQosCaps; + + void *limAssocResponseData; + + uint16_t statypeForBss; + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + tSirMacRateSet rateSet; + tSirMacRateSet extRateSet; + tSirMacHTOperatingMode htOperMode; + qdf_freq_t curr_op_freq; + uint32_t curr_req_chan_freq; + uint8_t LimRxedBeaconCntDuringHB; + uint64_t lastBeaconTimeStamp; + uint32_t currentBssBeaconCnt; + uint8_t bcon_dtim_period; + + uint32_t bcnLen; + uint8_t *beacon; + + uint32_t assocReqLen; + uint8_t *assoc_req; + + uint32_t assocRspLen; + uint8_t *assocRsp; + tAniSirDph dph; + void **parsedAssocReq; + uint32_t RICDataLen; + uint8_t *ricData; +#ifdef FEATURE_WLAN_ESE + uint32_t tspecLen; + uint8_t *tspecIes; +#endif + uint32_t encryptType; + + uint8_t gLimProtectionControl; + + uint8_t gHTNonGFDevicesPresent; + + tCfgProtection cfgProtection; + tLimProtStaParams gLim11bParams; + tLimProtStaParams gLim11aParams; + tLimProtStaParams gLim11gParams; + tLimProtStaParams gLimNonGfParams; + tLimProtStaParams gLimHt20Params; + tLimProtStaParams gLimLsigTxopParams; + tLimNoShortParams gLimNoShortParams; + tLimNoShortSlotParams gLimNoShortSlotParams; + tLimProtStaParams gLimOlbcParams; + tLimProtStaParams gLimOverlap11gParams; + tLimProtStaParams gLimOverlap11aParams; + tLimProtStaParams gLimOverlapHt20Params; + tLimProtStaParams gLimOverlapNonGfParams; + + tCacheParams protStaCache[LIM_PROT_STA_CACHE_SIZE]; + + uint8_t privacy; + tAniAuthType authType; + tDot11fIEWMMParams wmm_params; + tDot11fIERSN gStartBssRSNIe; + tDot11fIEWPA gStartBssWPAIe; + tSirAPWPSIEs APWPSIEs; + uint8_t apUapsdEnable; + tSirWPSPBCSession *pAPWPSPBCSession; + uint32_t DefProbeRspIeBitmap[8]; + uint32_t proxyProbeRspEn; + tDot11fProbeResponse probeRespFrame; + uint8_t ssidHidden; + bool fwdWPSPBCProbeReq; + uint8_t wps_state; + bool wps_registration; + + uint8_t limQosEnabled:1; + uint8_t limWmeEnabled:1; + uint8_t limWsmEnabled:1; + uint8_t limHcfEnabled:1; + uint8_t limRmfEnabled:1; + uint32_t lim11hEnable; + + int8_t maxTxPower; + int8_t min_11h_pwr; + int8_t max_11h_pwr; + enum QDF_OPMODE opmode; + int8_t txMgmtPower; + bool is11Rconnection; + bool is_adaptive_11r_connection; + +#ifdef FEATURE_WLAN_ESE + tEsePEContext eseContext; +#endif + tSirP2PNoaAttr p2pGoPsUpdate; + uint32_t defaultAuthFailureTimeout; + + tSirMacEdcaParamRecord gLimEdcaParams[QCA_WLAN_AC_ALL]; + tSirMacEdcaParamRecord gLimEdcaParamsBC[QCA_WLAN_AC_ALL]; + tSirMacEdcaParamRecord gLimEdcaParamsActive[QCA_WLAN_AC_ALL]; + + uint8_t gLimEdcaParamSetCount; + + tBeaconParams beaconParams; + uint8_t vhtCapability; + tLimOperatingModeInfo gLimOperatingMode; + uint8_t vhtCapabilityPresentInBeacon; + uint8_t ch_center_freq_seg0; + enum phy_ch_width ch_width; + enum phy_ch_width ap_ch_width; +#ifdef WLAN_FEATURE_11BE + uint16_t puncture_bitmap; +#endif + uint8_t ch_center_freq_seg1; + uint8_t enableVhtpAid; + uint8_t enableVhtGid; + tLimWiderBWChannelSwitchInfo gLimWiderBWChannelSwitch; + uint8_t enableAmpduPs; + bool send_smps_action; + uint8_t spectrumMgtEnabled; + + tLimSpecMgmtInfo gLimSpecMgmt; + tLimChannelSwitchInfo gLimChannelSwitch; + + uint32_t gLimPhyMode; + uint8_t txLdpcIniFeatureEnabled; + uint8_t *gpLimPeerIdxpool; + uint8_t freePeerIdxHead; + uint8_t freePeerIdxTail; + uint16_t gLimNumOfCurrentSTAs; +#ifdef FEATURE_WLAN_TDLS + uint32_t peerAIDBitmap[2]; + bool tdls_send_set_state_disable; +#endif + bool fWaitForProbeRsp; + bool fIgnoreCapsChange; + bool fDeauthReceived; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + int8_t rssi; +#endif + uint8_t max_amsdu_num; + struct mlme_ht_capabilities_info ht_config; + struct wlan_vht_config vht_config; + uint8_t gLimCurrentBssUapsd; + uint8_t gUapsdPerAcBitmask; + uint8_t gUapsdPerAcTriggerEnableMask; + uint8_t gUapsdPerAcDeliveryEnableMask; + uint8_t csaOffloadEnable; + uint8_t gAcAdmitMask[SIR_MAC_DIRECTION_DIRECT]; + + tPowersaveoffloadInfo pmmOffloadInfo; + uint8_t smpsMode; + + uint8_t chainMask; + + uint8_t dfsIncludeChanSwIe; + + uint8_t dfsIncludeChanWrapperIe; + uint8_t bw_update_include_ch_sw_ie; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + + bool isCiscoVendorAP; + + struct add_ie_params add_ie_params; + + uint8_t *pSchProbeRspTemplate; + uint8_t *pSchBeaconFrameBegin; + uint8_t *pSchBeaconFrameEnd; + uint16_t schBeaconOffsetBegin; + uint16_t schBeaconOffsetEnd; + bool isOSENConnection; + struct qos_map_set QosMapSet; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool bRoamSynchInProgress; +#endif + + tftPEContext ftPEContext; + bool isNonRoamReassoc; + qdf_mc_timer_t pmf_retry_timer; + struct comeback_timer_info pmf_retry_timer_info; + qdf_mc_timer_t protection_fields_reset_timer; + qdf_mc_timer_t ap_ecsa_timer; + qdf_wake_lock_t ap_ecsa_wakelock; + qdf_runtime_lock_t ap_ecsa_runtime_lock; + struct mac_context *mac_ctx; + uint16_t old_protection_state; + tSirMacAddr prev_ap_bssid; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_advertise_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#ifdef FEATURE_WLAN_ESE + uint8_t is_ese_version_ie_present; +#endif + bool sap_dot11mc; + bool is_vendor_specific_vhtcaps; + uint8_t vendor_specific_vht_ie_sub_type; + bool vendor_vht_sap; + tDot11fIEhs20vendor_ie hs20vendor_ie; + uint8_t country_info_present; + uint8_t nss; + bool nss_forced_1x1; + bool add_bss_failed; + struct obss_scanparam obss_ht40_scanparam; + uint8_t vdev_nss; + bool supported_nss_1x1; + bool is_ext_caps_present; + uint16_t beacon_tx_rate; + uint8_t *access_policy_vendor_ie; + uint8_t access_policy; + bool send_p2p_conf_frame; + bool process_ho_fail; + uint8_t lim_non_ecsa_cap_num; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + tDot11fIEhe_cap he_config; + tDot11fIEhe_op he_op; + uint32_t he_sta_obsspd; + bool he_6ghz_band; +#ifdef WLAN_FEATURE_11AX_BSS_COLOR + tDot11fIEbss_color_change he_bss_color_change; + struct bss_color_info bss_color_info[MAX_BSS_COLOR_VALUE]; + uint8_t bss_color_changing; +#endif +#endif + struct deauth_retry_params deauth_retry; + bool enable_bcast_probe_rsp; + uint8_t ht_client_cnt; + bool ch_switch_in_progress; + bool he_with_wep_tkip; +#ifdef WLAN_FEATURE_FILS_SK + struct pe_fils_session *fils_info; +#endif + + uint16_t prev_auth_seq_num; + tSirMacAddr prev_auth_mac_addr; + struct obss_detection_cfg obss_offload_cfg; + struct obss_detection_cfg current_obss_detection; + bool is_session_obss_offload_enabled; + bool is_obss_reset_timer_initialized; + bool sae_pmk_cached; + bool recvd_deauth_while_roaming; + bool recvd_disassoc_while_roaming; + uint16_t deauth_disassoc_rc; + enum wmi_obss_color_collision_evt_type obss_color_collision_dec_evt; + bool is_session_obss_color_collision_det_enabled; + tSirMacEdcaParamRecord ap_mu_edca_params[QCA_WLAN_AC_ALL]; + bool mu_edca_present; + int8_t def_max_tx_pwr; + bool active_ba_64_session; + bool is_mbssid_enabled; +#ifdef WLAN_SUPPORT_TWT + uint8_t peer_twt_requestor; + uint8_t peer_twt_responder; +#endif + bool enable_session_twt_support; + uint32_t cac_duration_ms; + tSirResultCodes stop_bss_reason; + uint16_t prot_status_code; + tSirResultCodes result_code; + uint32_t dfs_regdomain; + uint8_t ap_defined_power_type_6g; + uint8_t best_6g_power_type; + bool sta_follows_sap_power; +#ifdef WLAN_FEATURE_11BE + bool eht_capable; + tDot11fIEeht_cap eht_config; + tDot11fIEeht_op eht_op; +#ifdef WLAN_FEATURE_11BE_MLO + struct mlo_link_ie_info mlo_link_info; + struct mlo_partner_info ml_partner_info; + uint16_t mlo_ie_total_len; + struct wlan_mlo_ie mlo_ie; +#endif +#endif /* WLAN_FEATURE_11BE */ + uint8_t user_edca_set; + bool is_oui_auth_assoc_6mbps_2ghz_enable; + bool is_unexpected_peer_error; + uint8_t join_probe_cnt; +}; + +/*------------------------------------------------------------------------- + Function declarations and documentation + ------------------------------------------------------------------------*/ + +#ifdef WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +/** + * pe_allocate_dph_node_array_buffer() - Allocate g_dph_node_array + * memory dynamically + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_NOMEM on failure + */ +QDF_STATUS pe_allocate_dph_node_array_buffer(void); + +/** + * pe_free_dph_node_array_buffer() - Free memory allocated dynamically + * + * Return: None + */ +void pe_free_dph_node_array_buffer(void); +#else /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ +static inline QDF_STATUS pe_allocate_dph_node_array_buffer(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void pe_free_dph_node_array_buffer(void) +{ +} +#endif /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ + +/** + * pe_create_session() - Creates a new PE session given the BSSID + * @mac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: PE session ID is returned here, if PE session is created. + * @numSta: number of stations + * @bssType: bss type of new session to do conditional memory allocation. + * @vdev_id: vdev_id + * + * This function returns the session context and the session ID if the session + * corresponding to the passed BSSID is found in the PE session table. + * + * Return: ptr to the session context or NULL if session can not be created. + */ +struct pe_session *pe_create_session(struct mac_context *mac, + uint8_t *bssid, uint8_t *sessionId, + uint16_t numSta, enum bss_type bssType, + uint8_t vdev_id); + +/** + * pe_find_session_by_bssid() - looks up the PE session given the BSSID. + * + * @mac: pointer to global adapter context + * @bssid: BSSID of the new session + * @sessionId: session ID is returned here, if session is created. + * + * This function returns the session context and the session ID if the session + * corresponding to the given BSSID is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +struct pe_session *pe_find_session_by_bssid(struct mac_context *mac, uint8_t *bssid, + uint8_t *sessionId); + +/** + * pe_find_session_by_vdev_id() - looks up the PE session given the vdev_id. + * @mac: pointer to global adapter context + * @vdev_id: vdev id the session + * + * Return: pointer to the session context or NULL if session is not found. + */ +struct pe_session *pe_find_session_by_vdev_id(struct mac_context *mac, + uint8_t vdev_id); + +/** + * pe_find_session_by_vdev_id_and_state() - Find PE session by vdev_id and + * mlm state. + * @mac: pointer to global adapter context + * @vdev_id: vdev id the session + * @lim_state: LIM state of the session + * + * During LFR2 roaming, new pe session is created before old pe session + * deleted, the 2 pe sessions have different pe session id, but same vdev id, + * can't get correct pe session by vdev id at this time. + * + * Return: pointer to the session context or NULL if session is not found. + */ +struct pe_session +*pe_find_session_by_vdev_id_and_state(struct mac_context *mac, + uint8_t vdev_id, + enum eLimMlmStates lim_state); + +/** + * pe_find_session_by_bssid_and_vdev_id() - looks up the PE session given + * the BSSID and vdev id. + * @mac: pointer to global adapter context + * @bssid: BSSID of the new session + * @vdev_id: vdev id the session + * @sessionId: session ID is returned here, if session is created. + * + * This function returns the session context and the session ID if the session + * corresponding to the given BSSID and vdev id is found in the PE + * session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +struct pe_session *pe_find_session_by_bssid_and_vdev_id(struct mac_context *mac, + uint8_t *bssid, + uint8_t vdev_id, + uint8_t *sessionId); + +/** + * pe_find_session_by_peer_sta() - looks up the PE session given the Peer + * Station Address. + * + * @mac: pointer to global adapter context + * @sa: Peer STA Address of the session + * @sessionId: session ID is returned here, if session is found. + * + * This function returns the session context and the session ID if the session + * corresponding to the given destination address is found in the PE session + * table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +struct pe_session *pe_find_session_by_peer_sta(struct mac_context *mac, uint8_t *sa, + uint8_t *sessionId); + +/** + * pe_find_session_by_session_id() - looks up the PE session given the session + * ID. + * + * @mac: pointer to global adapter context + * @sessionId: session ID for which session context needs to be looked up. + * + * This function returns the session context if the session corresponding to + * the given session ID is found in the PE session table. + * + * Return: pointer to the session context or NULL if session is not found. + */ +struct pe_session *pe_find_session_by_session_id(struct mac_context *mac, + uint8_t sessionId); + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * + * @mac: pointer to global adapter context + * @pe_session: session to delete + * + * Return: void + */ +void pe_delete_session(struct mac_context *mac, struct pe_session *pe_session); + +/** + * pe_find_session_by_scan_id() - looks up the PE session for given scan id + * @mac_ctx: pointer to global adapter context + * @scan_id: scan id + * + * looks up the PE session for given scan id + * + * Return: pe session entry for given scan id if found else NULL + */ +struct pe_session *pe_find_session_by_scan_id(struct mac_context *mac_ctx, + uint32_t scan_id); + +uint8_t pe_get_active_session_count(struct mac_context *mac_ctx); + +/** + * lim_dump_session_info() - Dump the key parameters of PE session + * @mac_ctx: Global MAC context + * @pe_session: PE session + * + * Dumps the fields from the @pe_session for debugging. + * + * Return: void + */ +void lim_dump_session_info(struct mac_context *mac_ctx, + struct pe_session *pe_session); + +#ifdef WLAN_FEATURE_11AX +/** + * lim_dump_he_info() - Dump HE fields in PE session + * @mac: Global MAC context + * @session: PE session + * + * Dumps the fields related to HE from the @session for debugging + * + * Return: void + */ +void lim_dump_he_info(struct mac_context *mac, struct pe_session *session); +#else +static inline void lim_dump_he_info(struct mac_context *mac, + struct pe_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_dump_eht_info() - Dump EHT fields in PE session + * @session: PE session + * + * Dumps the fields related to EHT from @session for debugging + * + * Return: void + */ +void lim_dump_eht_info(struct pe_session *session); +#else +static inline void lim_dump_eht_info(struct pe_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +/** + * pe_delete_fils_info: API to delete fils session info + * @session: pe session + * + * Return: void + */ +void pe_delete_fils_info(struct pe_session *session); +#endif + +/** + * lim_set_bcn_probe_filter - set the beacon/probe filter in mac context + * + * @mac_ctx: pointer to global mac context + * @session: pointer to the PE session + * @sap_channel: Operating Channel of the session for SAP sessions + * + * Sets the beacon/probe filter in the global mac context to filter + * and drop beacon/probe frames before posting it to PE queue + * + * Return: None + */ +void lim_set_bcn_probe_filter(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t sap_channel); + +/** + * lim_reset_bcn_probe_filter - clear the beacon/probe filter in mac context + * + * @mac_ctx: pointer to the global mac context + * @session: pointer to the PE session whose filter is to be cleared + * + * Return: None + */ +void lim_reset_bcn_probe_filter(struct mac_context *mac_ctx, struct pe_session *session); + +/** + * lim_update_bcn_probe_filter - Update the beacon/probe filter in mac context + * + * @mac_ctx: pointer to the global mac context + * @session: pointer to the PE session whose filter is to be cleared + * + * This API is applicable only for SAP sessions to update the SAP channel + * in the filter during a channel switch + * + * Return: None + */ +void lim_update_bcn_probe_filter(struct mac_context *mac_ctx, struct pe_session *session); + +#endif /* #if !defined( __LIM_SESSION_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_trace.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_trace.h new file mode 100644 index 0000000000..8e490b0395 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/lim_trace.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013-2016, 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + * \file lim_trace.h + + * \brief definition for trace related APIs + + * \author Sunit Bhatia + + ========================================================================*/ + +#ifndef __LIM_TRACE_H +#define __LIM_TRACE_H + +#include "lim_global.h" +#include "mac_trace.h" +#include "qdf_trace.h" + +enum pecodetype { + TRACE_CODE_MLM_STATE, + TRACE_CODE_SME_STATE, + TRACE_CODE_TX_MGMT, + TRACE_CODE_RX_MGMT, + TRACE_CODE_RX_MGMT_TSF, + TRACE_CODE_TX_COMPLETE, + TRACE_CODE_TX_SME_MSG, + TRACE_CODE_RX_SME_MSG, + TRACE_CODE_TX_WMA_MSG, + TRACE_CODE_RX_WMA_MSG, + TRACE_CODE_TX_LIM_MSG, + TRACE_CODE_RX_LIM_MSG, + TRACE_CODE_RX_MGMT_DROP, + + TRACE_CODE_TIMER_ACTIVATE, + TRACE_CODE_TIMER_DEACTIVATE, + TRACE_CODE_INFO_LOG +}; + +#ifdef LIM_TRACE_RECORD + +#define LIM_TRACE_GET_SSN(data) (((data) >> 16) & 0xff) +#define LIM_TRACE_GET_SUBTYPE(data) ((data) & 0xff) +#define LIM_TRACE_GET_DEFRD_OR_DROPPED(data) ((data) & 0xc0000000) + +#define LIM_MSG_PROCESSED 0 +#define LIM_MSG_DEFERRED 1 +#define LIM_MSG_DROPPED 2 + +#define LIM_TRACE_MAKE_RXMGMT(type, ssn) \ + (((ssn) << 16) | (type)) +#define LIM_TRACE_MAKE_RXMSG(msg, action) \ + ((msg) | ((action) << 30)) + +void lim_trace_init(struct mac_context *mac); +uint8_t *lim_trace_get_mlm_state_string(uint32_t mlmState); +uint8_t *lim_trace_get_sme_state_string(uint32_t smeState); +void lim_trace_dump(void *mac, tp_qdf_trace_record pRecord, + uint16_t recIndex); +void mac_trace_msg_tx(struct mac_context *mac, uint8_t session, uint32_t data); +void mac_trace_msg_rx(struct mac_context *mac, uint8_t session, uint32_t data); + +#endif /* endof LIM_TRACE_RECORD MACRO */ + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/rrm_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/rrm_api.h new file mode 100644 index 0000000000..4a37cb5b4a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/rrm_api.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2011-2012, 2014-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \file rrm_api.h + + \brief RRM APIs + + ========================================================================*/ + +/* $Header$ */ + +#ifndef __RRM_API_H__ +#define __RRM_API_H__ + +#define RRM_BCN_RPT_NO_BSS_INFO 0 +#define RRM_BCN_RPT_MIN_RPT 1 +#define RRM_CH_BUF_LEN 45 + +QDF_STATUS rrm_initialize(struct mac_context *mac); + +/** + * rrm_cleanup - cleanup RRM measurement related data for the measurement + * index + * @mac: Pointer to mac context + * @idx: Measurement index + * + * Return: None + */ +void rrm_cleanup(struct mac_context *mac, uint8_t idx); + +QDF_STATUS rrm_process_link_measurement_request(struct mac_context *mac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest + *pLinkReq, + struct pe_session * + pe_session); + +QDF_STATUS +rrm_process_radio_measurement_request(struct mac_context *mac_ctx, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest *rrm_req, + struct pe_session *session_entry); + +QDF_STATUS rrm_process_neighbor_report_response(struct mac_context *mac, + tDot11fNeighborReportResponse + *pNeighborRep, + struct pe_session * + pe_session); + +QDF_STATUS rrm_send_set_max_tx_power_req(struct mac_context *mac, + int8_t txPower, + struct pe_session *pe_session); + +int8_t rrm_get_mgmt_tx_power(struct mac_context *mac, + struct pe_session *pe_session); + +void rrm_cache_mgmt_tx_power(struct mac_context *mac, + int8_t txPower, struct pe_session *pe_session); + +tpRRMCaps rrm_get_capabilities(struct mac_context *mac, + struct pe_session *pe_session); + +void rrm_get_start_tsf(struct mac_context *mac, uint32_t *pStartTSF); + +QDF_STATUS rrm_set_max_tx_power_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ); + +QDF_STATUS +rrm_process_neighbor_report_req(struct mac_context *mac, + tpSirNeighborReportReqInd pNeighborReq); + +QDF_STATUS +rrm_process_beacon_report_xmit(struct mac_context *mac_ctx, + tpSirBeaconReportXmitInd beacon_xmit_ind); + +/** + * rrm_process_chan_load_report_xmit() - process channel load report xmit + * @mac_ctx: Mac context + * @chan_load_ind: channel load xmit structure + * + * Return: None + */ +void +rrm_process_chan_load_report_xmit(struct mac_context *mac_ctx, + struct chan_load_xmit_ind *chan_load_ind); + +/** + * rrm_get_country_code_from_connected_profile() - get country code + * from connected profile + * @mac: Mac context + * @vdev_id: vdev_id or csr session id + * @country_code: country code + * + * Return: None + */ +void rrm_get_country_code_from_connected_profile(struct mac_context *mac, + uint8_t vdev_id, + uint8_t *country_code); +/** + * rrm_reject_req - Reject rrm request + * @radiomes_report: radio measurement report + * @rrm_req: Array of Measurement request IEs + * @num_report: Num of report + * @index: Measurement index + * @measurement_type: Measurement Type + * + * Reject the Radio Resource Measurement request, if one is + * already in progress + * + * Return: QDF_STATUS + */ +QDF_STATUS rrm_reject_req(tpSirMacRadioMeasureReport *radiomes_report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, uint8_t index, + uint8_t measurement_type); + +void lim_update_rrm_capability(struct mac_context *mac_ctx); + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +/** + * rrm_send_sta_stats_req - Send RRM STA STATS request + * @mac: mac context + * @session: pe session + * @peer_mac: peer mac + * + * Return: QDF_STATUS + */ +QDF_STATUS +rrm_send_sta_stats_req(struct mac_context *mac, + struct pe_session *session, + tSirMacAddr peer_mac); +#else +static inline QDF_STATUS +rrm_send_sta_stats_req(struct mac_context *mac, + struct pe_session *session, + tSirMacAddr peer_mac) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * rrm_process_rrm_sta_stats_request_failure: send RRM STA Stats report with + * failure + * @mac: mac context + * @pe_session: pe session + * @peer: peer mac + * @status: failure status + * @index: index of report + * + * Return: void + */ +void +rrm_process_rrm_sta_stats_request_failure(struct mac_context *mac, + struct pe_session *pe_session, + tSirMacAddr peer, + tRrmRetStatus status, uint8_t index); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/rrm_global.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/rrm_global.h new file mode 100644 index 0000000000..61f4cd5639 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/rrm_global.h @@ -0,0 +1,489 @@ +/* + * Copyright (c) 2011-2012, 2014-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__RRMGLOBAL_H) +#define __RRMGLOBAL_H + +/**========================================================================= + + \file rrm_global.h + + \brief Definitions for SME APIs + + ========================================================================*/ + +#define MAX_MEASUREMENT_REQUEST 5 +#define MAX_NUM_CHANNELS 255 + +#define DEFAULT_RRM_IDX 0 + +typedef enum eRrmRetStatus { + eRRM_SUCCESS, + eRRM_INCAPABLE, + eRRM_REFUSED, + eRRM_FAILURE +} tRrmRetStatus; + +typedef enum eRrmMsgReqSource { + eRRM_MSG_SOURCE_LEGACY_ESE = 1, /* legacy ese */ + eRRM_MSG_SOURCE_11K = 2, /* 11k */ + eRRM_MSG_SOURCE_ESE_UPLOAD = 3, /* ese upload approach */ +} tRrmMsgReqSource; + +struct sir_channel_info { + uint8_t reg_class; + uint8_t chan_num; + uint32_t chan_freq; +}; + +/** + * struct rrm_reporting - Contains info for rrm_ reporting IE present in + * channel load request received from AP + * @reporting_condition: reporting condition + * @threshold: threshold value to report channel load request + */ +struct rrm_reporting { + uint8_t reporting_condition; + uint8_t threshold; +}; + +/** + * struct bw_ind_element - Contains info for Bandwidth Indication IE + * present in channel load request received from AP + * @is_bw_ind_element: to check Bandwidth Indication optional IE present + * @channel_width: channel width + * @ccfi0: center channel frequency index segment 0 + * @ccfi1: center channel frequency index segment 1 + * @center_freq: center freq segment for 320 MHz request + */ +struct bw_ind_element { + bool is_bw_ind_element; + uint8_t channel_width; + uint8_t ccfi0; + uint8_t ccfi1; + qdf_freq_t center_freq; +}; + +/** + * struct wide_bw_chan_switch - Contains info for Wide Bandwidth Channel + * Switch IE present in channel load request received from AP + * @is_wide_bw_chan_switch: to check Bandwidth Indication optional IE present + * @channel_width: channel width + * @center_chan_freq0: center freq segment 0 for till 160 MHz request + * @center_chan_freq1: center freq segment 1 for till 160 MHz request + */ +struct wide_bw_chan_switch { + uint8_t is_wide_bw_chan_switch; + uint8_t channel_width; + uint8_t center_chan_freq0; + uint8_t center_chan_freq1; +}; + +/** + * struct ch_load_ind - Contains info for channel load request received from AP + * @message_type: message type eWNI_SME_CHAN_LOAD_REQ_IND + * @length: size of struct chan_load_req_ind + * @measurement_idx: measurement index for channel load request + * @peer_addr: connected peer mac address + * @dialog_token: dialog token + * @msg_source: message source of type enum tRrmMsgReqSource + * @op_class: regulatory class + * @channel: channel number + * @req_freq: freq as per channel load req + * @randomization_intv: Random interval in ms + * @meas_duration: measurement duration in ms + * @bw_ind: Info for bandwidth indication IE + * @wide_bw: Info for wide bandwidth channel switch IE + */ +struct ch_load_ind { + uint16_t message_type; + uint16_t length; + uint8_t measurement_idx; + struct qdf_mac_addr peer_addr; + uint16_t dialog_token; + tRrmMsgReqSource msg_source; + uint8_t op_class; + uint8_t channel; + qdf_freq_t req_freq; + uint16_t randomization_intv; + uint16_t meas_duration; + struct bw_ind_element bw_ind; + struct wide_bw_chan_switch wide_bw; +}; + +/** + * struct chan_load_xmit_ind - Contains info for channel load xmit indication + * @messageType: message type eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND + * @length: size of struct chan_load_req_ind + * @measurement_idx: measurement index for channel load request + * @peer_addr: MAC address of the BSS + * @dialog_token: dialog token + * @op_class: regulatory class + * @channel: channel number + * @duration: measurement duration in ms + * @chan_load: channel utilization measurement + * @rrm_scan_tsf: time at which driver triggers rrm scan for channel load + * @is_report_success: need to send failure report or not + * @bw_ind: Info for bandwidth indication IE + * @wide_bw: Info for wide bandwidth channel switch IE + */ +struct chan_load_xmit_ind { + uint16_t messageType; + uint16_t length; + uint8_t measurement_idx; + struct qdf_mac_addr peer_addr; + uint16_t dialog_token; + uint8_t op_class; + uint8_t channel; + uint16_t duration; + uint8_t chan_load; + qdf_time_t rrm_scan_tsf; + bool is_report_success; + struct bw_ind_element bw_ind; + struct wide_bw_chan_switch wide_bw; +}; + +typedef struct sSirBeaconReportReqInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_REQ_IND */ + uint16_t length; + uint8_t measurement_idx; + tSirMacAddr bssId; + uint16_t measurementDuration[SIR_ESE_MAX_MEAS_IE_REQS]; /* ms */ + uint16_t randomizationInterval; /* ms */ + struct sir_channel_info channel_info; + /* 0: wildcard */ + tSirMacAddr macaddrBssid; + /* 0:Passive, 1: Active, 2: table mode */ + uint8_t fMeasurementtype[SIR_ESE_MAX_MEAS_IE_REQS]; + tAniSSID ssId; /* May be wildcard. */ + uint16_t uDialogToken; + struct report_channel_list channel_list; /* From AP channel report. */ + tRrmMsgReqSource msgSource; +} tSirBeaconReportReqInd, *tpSirBeaconReportReqInd; + +typedef struct sSirBeaconReportXmitInd { + uint16_t messageType; /* eWNI_SME_BEACON_REPORT_RESP_XMIT_IND */ + uint16_t length; + uint8_t measurement_idx; + tSirMacAddr bssId; + uint16_t uDialogToken; + uint8_t fMeasureDone; + uint16_t duration; + uint8_t regClass; + uint8_t numBssDesc; + struct bss_description *pBssDescription[SIR_BCN_REPORT_MAX_BSS_DESC]; +} tSirBeaconReportXmitInd, *tpSirBeaconReportXmitInd; + +typedef struct sSirNeighborReportReqInd { + /* eWNI_SME_NEIGHBOR_REPORT_REQ_IND */ + uint16_t messageType; + uint16_t length; + /* For the session. */ + tSirMacAddr bssId; + /* true - dont include SSID in the request. */ + uint16_t noSSID; + /* false include the SSID. It may be null (wildcard) */ + tSirMacSSid ucSSID; +} tSirNeighborReportReqInd, *tpSirNeighborReportReqInd; + +typedef struct sSirNeighborBssDescription { + uint16_t length; + tSirMacAddr bssId; + uint8_t regClass; + uint8_t channel; + uint8_t phyType; + union sSirNeighborBssidInfo { + struct _rrmInfo { + /* see IEEE 802.11k Table 7-43a */ + uint32_t fApPreauthReachable:2; + uint32_t fSameSecurityMode:1; + uint32_t fSameAuthenticator:1; + /* see IEEE 802.11k Table 7-95d */ + uint32_t fCapSpectrumMeasurement:1; + uint32_t fCapQos:1; + uint32_t fCapApsd:1; + uint32_t fCapRadioMeasurement:1; + uint32_t fCapDelayedBlockAck:1; + uint32_t fCapImmediateBlockAck:1; + uint32_t fMobilityDomain:1; + uint32_t reserved:21; + } rrmInfo; + struct _eseInfo { + uint32_t channelBand:8; + uint32_t minRecvSigPower:8; + uint32_t apTxPower:8; + uint32_t roamHysteresis:8; + uint32_t adaptScanThres:8; + + uint32_t transitionTime:8; + uint32_t tsfOffset:16; + + uint32_t beaconInterval:16; + uint32_t reserved:16; + } eseInfo; + } bssidInfo; + + /* Optional sub IEs....ignoring for now. */ +} tSirNeighborBssDescription, *tpSirNeighborBssDescripton; + +typedef struct sSirNeighborReportInd { + uint16_t messageType; /* eWNI_SME_NEIGHBOR_REPORT_IND */ + uint16_t length; + uint8_t sessionId; + uint8_t measurement_idx; + uint16_t numNeighborReports; + tSirMacAddr bssId; /* For the session. */ + QDF_FLEX_ARRAY(tSirNeighborBssDescription, sNeighborBssDescription); +} tSirNeighborReportInd, *tpSirNeighborReportInd; + +typedef struct eid_ext_info { + uint8_t eid; + uint8_t num_eid_ext; + uint8_t eid_ext[255]; +} eid_ext_info; + +typedef struct sRRMBeaconReportRequestedIes { + uint8_t num; + uint8_t *pElementIds; + eid_ext_info ext_info; +} tRRMBeaconReportRequestedIes, *tpRRMBeaconReportRequestedIes; + +/* Reporting detail defines. */ +/* Reference - IEEE Std 802.11k-2008 section 7.3.2.21.6 Table 7-29h */ +#define BEACON_REPORTING_DETAIL_NO_FF_IE 0 +#define BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE 1 +#define BEACON_REPORTING_DETAIL_ALL_FF_IE 2 + +typedef struct sRRMReq { + uint8_t measurement_idx; /* Index of the measurement report in frame */ + uint8_t dialog_token; /* In action frame; */ + uint8_t token; /* Within individual request; */ + uint8_t type; + union { + struct { + uint8_t reportingDetail; + uint8_t last_beacon_report_indication; + tRRMBeaconReportRequestedIes reqIes; + } Beacon; + } request; + uint8_t sendEmptyBcnRpt; +} tRRMReq, *tpRRMReq; + +typedef struct sRRMCaps { + uint8_t LinkMeasurement:1; + uint8_t NeighborRpt:1; + uint8_t parallel:1; + uint8_t repeated:1; + uint8_t BeaconPassive:1; + uint8_t BeaconActive:1; + uint8_t BeaconTable:1; + uint8_t BeaconRepCond:1; + uint8_t FrameMeasurement:1; + uint8_t ChannelLoad:1; + uint8_t NoiseHistogram:1; + uint8_t statistics:1; + uint8_t LCIMeasurement:1; + uint8_t LCIAzimuth:1; + uint8_t TCMCapability:1; + uint8_t triggeredTCM:1; + uint8_t APChanReport:1; + uint8_t RRMMIBEnabled:1; + uint8_t operatingChanMax:3; + uint8_t nonOperatingChanMax:3; + uint8_t MeasurementPilot:3; + uint8_t MeasurementPilotEnabled:1; + uint8_t NeighborTSFOffset:1; + uint8_t RCPIMeasurement:1; + uint8_t RSNIMeasurement:1; + uint8_t BssAvgAccessDelay:1; + uint8_t BSSAvailAdmission:1; + uint8_t AntennaInformation:1; + uint8_t fine_time_meas_rpt:1; + uint8_t lci_capability:1; + uint8_t reserved:4; +} tRRMCaps, *tpRRMCaps; + +/** + * struct rrm_sta_stats - RRM sta stats structure + * @rrm_report: rrm_report + * @peer: peer address + * @index: current req index + * @rrm_sta_stats_res_count: sta stats response count + * @vdev_id: vdev_id + */ +struct rrm_sta_stats { + tSirMacRadioMeasureReport rrm_report; + tSirMacAddr peer; + uint8_t index; + uint8_t rrm_sta_stats_res_count; + uint8_t vdev_id; +}; + +typedef struct sRrmPEContext { + uint8_t rrmEnable; + /* + * Used during scan/measurement to store the start TSF. + * this is not used directly in beacon reports. + */ + uint32_t startTSF[2]; + /* + * This value is stored into bssdescription and beacon report + * gets it from bss decsription. + */ + tRRMCaps rrmEnabledCaps; + int8_t txMgmtPower; + /* Dialog token for the request initiated from station. */ + uint8_t DialogToken; + uint16_t prev_rrm_report_seq_num; + uint8_t num_active_request; + tpRRMReq pCurrentReq[MAX_MEASUREMENT_REQUEST]; + uint32_t beacon_rpt_chan_list[MAX_NUM_CHANNELS]; + uint8_t beacon_rpt_chan_num; + struct rrm_sta_stats rrm_sta_stats; +} tRrmPEContext, *tpRrmPEContext; + +/* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ +#define RCPI_LOW_RSSI_VALUE (-110) +#define RCPI_MAX_VALUE (220) +#define CALCULATE_RCPI(rssi) (((rssi) + 110) * 2) + +/* Bit mask are defined as per Draft P802.11REVmc_D4.2 */ + +/** + * enum mask_rm_capability_byte1 - mask for supported capability + * @RM_CAP_LINK_MEASUREMENT: Link Measurement capability + * @RM_CAP_NEIGHBOR_REPORT: Neighbor report capability + * @RM_CAP_PARALLEL_MEASUREMENT: Parallel Measurement capability + * @RM_CAP_REPEATED_MEASUREMENT: Repeated Measurement capability + * @RM_CAP_BCN_PASSIVE_MEASUREMENT: Beacon passive measurement capability + * @RM_CAP_BCN_ACTIVE_MEASUREMENT: Beacon active measurement capability + * @RM_CAP_BCN_TABLE_MEASUREMENT: Beacon table measurement capability + * @RM_CAP_BCN_MEAS_REPORTING_COND: Beacon measurement reporting conditions + */ +enum mask_rm_capability_byte1 { + RM_CAP_LINK_MEASUREMENT = (1 << (0)), + RM_CAP_NEIGHBOR_REPORT = (1 << (1)), + RM_CAP_PARALLEL_MEASUREMENT = (1 << (2)), + RM_CAP_REPEATED_MEASUREMENT = (1 << (3)), + RM_CAP_BCN_PASSIVE_MEASUREMENT = (1 << (4)), + RM_CAP_BCN_ACTIVE_MEASUREMENT = (1 << (5)), + RM_CAP_BCN_TABLE_MEASUREMENT = (1 << (6)), + RM_CAP_BCN_MEAS_REPORTING_COND = (1 << (7)), +}; + +/** + * enum mask_rm_capability_byte2 - mask for supported capability + * @RM_CAP_FRAME_MEASUREMENT: Frame Measurement capability + * @RM_CAP_CHAN_LOAD_MEASUREMENT: Channel load measurement capability + * @RM_CAP_NOISE_HIST_MEASUREMENT: Noise Histogram Measurement capability + * @RM_CAP_STATISTICS_MEASUREMENT: Statistics Measurement capability + * @RM_CAP_LCI_MEASUREMENT: LCI measurement capability + * @RM_CAP_LCI_AZIMUTH: LCI Azimuth capability + * @RM_CAP_TX_CATEGORY_MEASUREMENT: Transmit category measurement capability + * @RM_CAP_TRIG_TX_CATEGORY_MEASUREMENT: + * Triggered Transmit category measurement capability + */ +enum mask_rm_capability_byte2 { + RM_CAP_FRAME_MEASUREMENT = (1 << (0)), + RM_CAP_CHAN_LOAD_MEASUREMENT = (1 << (1)), + RM_CAP_NOISE_HIST_MEASUREMENT = (1 << (2)), + RM_CAP_STATISTICS_MEASUREMENT = (1 << (3)), + RM_CAP_LCI_MEASUREMENT = (1 << (4)), + RM_CAP_LCI_AZIMUTH = (1 << (5)), + RM_CAP_TX_CATEGORY_MEASUREMENT = (1 << (6)), + RM_CAP_TRIG_TX_CATEGORY_MEASUREMENT = (1 << (7)), +}; + +/** + * enum mask_rm_capability_byte3 - mask for supported capability + * @RM_CAP_AP_CHAN_REPORT: AP channel report capability + * @RM_CAP_RM_MIB: RM MIB capability + * @RM_CAP_OPER_CHAN_MAX_DURATION_1: OPER_CHAN_MAX_DURATION bit1 + * @RM_CAP_OPER_CHAN_MAX_DURATION_2: OPER_CHAN_MAX_DURATION bit2 + * @RM_CAP_OPER_CHAN_MAX_DURATION_3: OPER_CHAN_MAX_DURATION bit3 + * @RM_CAP_NONOPER_CHAN_MAX_DURATION_1: NONOPER_CHAN_MAX bit1 + * @RM_CAP_NONOPER_CHAN_MAX_DURATION_2: NONOPER_CHAN_MAX bit2 + * @RM_CAP_NONOPER_CHAN_MAX_DURATION_3: NONOPER_CHAN_MAX bit3 + * @RM_CAP_OPER_CHAN_MAX_DURATION: Operating Channel Max Measurement Duration + * @RM_CAP_NONOPER_CHAN_MAX_DURATION: + * Nonoperating Channel Max Measurement Duration + */ + +enum mask_rm_capability_byte3 { + RM_CAP_AP_CHAN_REPORT = (1 << (0)), + RM_CAP_RM_MIB = (1 << (1)), + RM_CAP_OPER_CHAN_MAX_DURATION_1 = (1 << (2)), + RM_CAP_OPER_CHAN_MAX_DURATION_2 = (1 << (3)), + RM_CAP_OPER_CHAN_MAX_DURATION_3 = (1 << (4)), + RM_CAP_NONOPER_CHAN_MAX_DURATION_1 = (1 << (5)), + RM_CAP_NONOPER_CHAN_MAX_DURATION_2 = (1 << (6)), + RM_CAP_NONOPER_CHAN_MAX_DURATION_3 = (1 << (7)), + RM_CAP_OPER_CHAN_MAX_DURATION = (RM_CAP_OPER_CHAN_MAX_DURATION_1 | + RM_CAP_OPER_CHAN_MAX_DURATION_2 | + RM_CAP_OPER_CHAN_MAX_DURATION_3), + RM_CAP_NONOPER_CHAN_MAX_DURATION = + (RM_CAP_NONOPER_CHAN_MAX_DURATION_1 | + RM_CAP_NONOPER_CHAN_MAX_DURATION_2 | + RM_CAP_NONOPER_CHAN_MAX_DURATION_3), +}; + +/** + * enum mask_rm_capability_byte4 - mask for supported capability + * @RM_CAP_MEASUREMENT_PILOT_1: MEASUREMENT_PILOT bit1 + * @RM_CAP_MEASUREMENT_PILOT_2: MEASUREMENT_PILOT bit2 + * @RM_CAP_MEASUREMENT_PILOT_3: MEASUREMENT_PILOT bit3 + * @RM_CAP_MEAS_PILOT_TX_INFO: Measurement Pilot Transmission Capability + * @RM_CAP_NEIGHBOR_RPT_TSF_OFFSET: Neighbor Report TSF Offset Capability + * @RM_CAP_RCPI_MEASUREMENT: RCPI Measurement Capability + * @RM_CAP_RSNI_MEASUREMENT: RSNI Measurement Capability + * @RM_CAP_BSS_AVG_ACCESS_DELAY: BSS Average Access Delay Capability + * @RM_CAP_MEASUREMENT_PILOT: Measurement pilot capability + */ + +enum mask_rm_capability_byte4 { + RM_CAP_MEASUREMENT_PILOT_1 = (1 << (0)), + RM_CAP_MEASUREMENT_PILOT_2 = (1 << (1)), + RM_CAP_MEASUREMENT_PILOT_3 = (1 << (2)), + RM_CAP_MEAS_PILOT_TX_INFO = (1 << (3)), + RM_CAP_NEIGHBOR_RPT_TSF_OFFSET = (1 << (4)), + RM_CAP_RCPI_MEASUREMENT1 = (1 << (5)), + RM_CAP_RSNI_MEASUREMENT = (1 << (6)), + RM_CAP_BSS_AVG_ACCESS_DELAY = (1 << (7)), + RM_CAP_MEASUREMENT_PILOT = (RM_CAP_MEASUREMENT_PILOT_1 | + RM_CAP_MEASUREMENT_PILOT_2 | + RM_CAP_MEASUREMENT_PILOT_3), +}; + +/** + * enum mask_rm_capability_byte5 - mask for supported capability + * @RM_CAP_BSS_AVAIL_ADMISSION: BSS Available Admission Capacity Capability + * @RM_CAP_ANTENNA: Antenna Capability + * @RM_CAP_FTM_RANGE_REPORT: FTM Range Report Capability + * @RM_CAP_CIVIC_LOC_MEASUREMENT: Civic Location Measurement capability + * + * 4 bits are reserved + */ +enum mask_rm_capability_byte5 { + RM_CAP_BSS_AVAIL_ADMISSION = (1 << (0)), + RM_CAP_ANTENNA = (1 << (1)), + RM_CAP_FTM_RANGE_REPORT = (1 << (2)), + RM_CAP_CIVIC_LOC_MEASUREMENT = (1 << (3)), +}; + +#endif /* #if defined __RRMGLOBAL_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/sch_api.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/sch_api.h new file mode 100644 index 0000000000..0fb5c7f0ea --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/sch_api.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2011-2015, 2017-2019, 2021 The Linux Foundation. All rights + * reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_API_H__ +#define __SCH_API_H__ + +#include "sir_common.h" +#include "sir_mac_prot_def.h" + +#include "ani_global.h" + +/* update only the broadcast qos params */ +void sch_qos_update_broadcast(struct mac_context *mac, + struct pe_session *pe_session); + +/* fill in the default local edca parameter into gLimEdcaParams[] */ +void sch_set_default_edca_params(struct mac_context *mac, struct pe_session *pe_session); + +/* update only local qos params */ +void sch_qos_update_local(struct mac_context *mac, struct pe_session *pe_session); + +/* update the edca profile parameters based on STA-SAP concurrency */ +void sch_qos_concurrency_update(void); + +/* update the edca profile parameters */ +void sch_edca_profile_update(struct mac_context *mac, + struct pe_session *pe_session); + +/* / Set the fixed fields in a beacon frame */ +QDF_STATUS sch_set_fixed_beacon_fields(struct mac_context *mac, + struct pe_session *pe_session); + +/** + * sch_process_pre_beacon_ind() - Process the PreBeacon Indication from the Lim + * @mac: pointer to mac structure + * @msg: schedular msg + * @reason: beacon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS sch_process_pre_beacon_ind(struct mac_context *mac, + struct scheduler_msg *msg, + enum sir_bcn_update_reason reason); + +void sch_beacon_process(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session); + +QDF_STATUS sch_beacon_edca_process(struct mac_context *mac, + tSirMacEdcaParamSetIE *edca, + struct pe_session *pe_session); + +void sch_generate_tim(struct mac_context *, uint8_t **, uint16_t *, uint8_t); + +void sch_set_beacon_interval(struct mac_context *mac, + struct pe_session *pe_session); + +/** + * sch_send_beacon_req() - send beacon update req to wma + * @mac_ctx: pointer to mac structure + * @bcn_payload: beacon payload + * @size: beacon size + * @session:pe session + * @reason: beacon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS sch_send_beacon_req(struct mac_context *mac_ctx, uint8_t *bcn_payload, + uint16_t size, struct pe_session *session, + enum sir_bcn_update_reason reason); + + +QDF_STATUS lim_update_probe_rsp_template_ie_bitmap_beacon1(struct mac_context *, + tDot11fBeacon1 *, + struct pe_session * + pe_session); +void lim_update_probe_rsp_template_ie_bitmap_beacon2(struct mac_context *, + tDot11fBeacon2 *, + uint32_t *, + tDot11fProbeResponse *); +void set_probe_rsp_ie_bitmap(uint32_t *, uint32_t); +uint32_t lim_send_probe_rsp_template_to_hal(struct mac_context *, + struct pe_session *, + uint32_t *); + +int sch_gen_timing_advert_frame(struct mac_context *mac, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, + uint32_t *time_value_offset); + +/* + * sch_beacon_process_for_ap() - process the beacon frame for AP sessions + * @mac_ctx: pointer to the global mac_ctx + * @rx_pkt_info: pointer to the frame Rx Meta + * @bcn: pointer to the beacon struct + * + * Process the beacon in the context of any existing AP or BTAP + * session. This takes cares of following two scenarios: + * - session = NULL: + * e.g. beacon received from a neighboring BSS, you want to apply the + * protection settings to BTAP/InfraAP beacons + * - session is non NULL: + * e.g. beacon received is from the INFRA AP to which you are connected + * on another concurrent link. In this case also, we want to apply the + * protection settings(as advertised by Infra AP) to BTAP beacons + * + * Return: None + */ +void sch_beacon_process_for_ap(struct mac_context *mac_ctx, + uint8_t session_id, + uint8_t *rx_pkt_info, + tSchBeaconStruct *bcn); + +/** + * sch_edca_profile_update_all() - update edca profile for all sessions + * @pmac: pointer to mac structure + * + * return: None + */ +void sch_edca_profile_update_all(struct mac_context *pmac); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/sch_global.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/sch_global.h new file mode 100644 index 0000000000..b680a0847c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/sch_global.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013-2014, 2017-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_GLOBAL_H__ +#define __SCH_GLOBAL_H__ + +#include "sir_mac_prop_exts.h" +#include "lim_global.h" + +#include "parser_api.h" + +/* ----------------------- Beacon processing ------------------------ */ + +/* / Beacon structure */ +#define tSchBeaconStruct tSirProbeRespBeacon +#define tpSchBeaconStruct struct sSirProbeRespBeacon * + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * struct ml_sch_partner_info - Partner link information + * @vdev_id: Vdev id + * @beacon_interval: Beacon interval + * @bcn_csa_cnt_ofst: CSA switch count offset in beacon frame + * @bcn_ext_csa_cnt_ofst: ECSA switch count offset in beacon frame + * @link_info_sta_prof_ofst: offset sta profile in link info. + * If per sta profile exists, this value is non zero + * @prb_csa_cnt_ofst: CSA switch count offset in probe frame + * @prb_ext_csa_cnt_ofst: ECSA switch count offset in probe frame + * @csa_ext_csa_exist: csa or ext csa exists + */ +struct ml_sch_partner_info { + uint32_t vdev_id; + uint32_t beacon_interval; + uint32_t bcn_csa_cnt_ofst; + uint32_t bcn_ext_csa_cnt_ofst; + uint16_t link_info_sta_prof_ofst; + uint32_t prb_csa_cnt_ofst; + uint32_t prb_ext_csa_cnt_ofst; + bool csa_ext_csa_exist; +}; + +/** + * struct mlo_sch_partner_links - ML partner links + * @num_links: Number of links + * @mlo_ie_link_info_ofst: offset of link info in mlo IE + * @partner_info: Partner link info + */ +struct mlo_sch_partner_links { + uint8_t num_links; + uint16_t mlo_ie_link_info_ofst; + struct ml_sch_partner_info partner_info[WLAN_UMAC_MLO_MAX_VDEVS]; +}; +#endif + +/** + * struct sch_context - SCH global context + * @beacon_interval: global beacon interval + * @beacon_changed: flag to indicate that beacon template has been updated + * @p2p_ie_offset: P2P IE offset + * @csa_count_offset: CSA Switch Count Offset to be sent to FW + * @ecsa_count_offset: ECSA Switch Count Offset to be sent to FW + */ +struct sch_context { + uint16_t beacon_interval; + uint8_t beacon_changed; + uint16_t p2p_ie_offset; + uint32_t csa_count_offset; + uint32_t ecsa_count_offset; +#ifdef WLAN_FEATURE_11BE_MLO + struct mlo_sch_partner_links sch_mlo_partner; +#endif +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h new file mode 100644 index 0000000000..86f6017fb0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/include/wmm_apsd.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMMAPSD_H__ +#define __WMMAPSD_H__ + +#include "ani_global.h" + +/* UAPSD Flag for each AC (WMM spec 2.2.1) */ +#define LIM_UAPSD_BITOFFSET_ACVO 0 +#define LIM_UAPSD_BITOFFSET_ACVI 1 +#define LIM_UAPSD_BITOFFSET_ACBK 2 +#define LIM_UAPSD_BITOFFSET_ACBE 3 + +#define LIM_UAPSD_FLAG_ACVO (1 << LIM_UAPSD_BITOFFSET_ACVO) +#define LIM_UAPSD_FLAG_ACVI (1 << LIM_UAPSD_BITOFFSET_ACVI) +#define LIM_UAPSD_FLAG_ACBK (1 << LIM_UAPSD_BITOFFSET_ACBK) +#define LIM_UAPSD_FLAG_ACBE (1 << LIM_UAPSD_BITOFFSET_ACBE) + +#define LIM_UAPSD_GET(ac, mask) (((mask) & (LIM_UAPSD_FLAG_ ## ac)) >> LIM_UAPSD_BITOFFSET_ ## ac) + +/* Definition for setting/clearing Uapsd Mask */ +#define SET_UAPSD_MASK 1 +#define CLEAR_UAPSD_MASK 0 + +#endif /* __WMMAPSD_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim.c new file mode 100644 index 0000000000..66a9194d92 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "lim_aid_mgmt.c" +#include "lim_admit_control.c" +#include "lim_api.c" +#include "lim_assoc_utils.c" +#include "lim_ft.c" +#include "lim_link_monitoring_algo.c" +#include "lim_process_action_frame.c" +#include "lim_process_assoc_req_frame.c" +#include "lim_process_assoc_rsp_frame.c" +#include "lim_process_auth_frame.c" +#include "lim_process_beacon_frame.c" +#include "lim_process_cfg_updates.c" +#include "lim_process_deauth_frame.c" +#include "lim_process_disassoc_frame.c" +#include "lim_process_message_queue.c" +#include "lim_process_mlm_req_messages.c" +#include "lim_process_mlm_rsp_messages.c" +#include "lim_process_probe_req_frame.c" +#include "lim_process_probe_rsp_frame.c" +#include "lim_process_sme_req_messages.c" +#include "lim_prop_exts_utils.c" +#include "lim_scan_result_utils.c" +#include "lim_security_utils.c" +#include "lim_send_management_frames.c" +#include "lim_send_messages.c" +#include "lim_send_sme_rsp_messages.c" +#include "lim_session.c" +#include "lim_session_utils.c" +#include "lim_sme_req_utils.c" +#include "lim_timer_utils.c" +#include "lim_trace.c" +#include "lim_utils.c" diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c new file mode 100644 index 0000000000..838b26d4c2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_admit_control.c @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file contains TSPEC and STA admit control related functions + * NOTE: applies only to AP builds + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "sys_def.h" +#include "lim_api.h" +#include "lim_trace.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_types.h" +#include "lim_admit_control.h" + +/* total available bandwidth in bps in each phy mode + * these should be defined in hal or dph - replace these later + */ +#define LIM_TOTAL_BW_11A 54000000 +#define LIM_MIN_BW_11A 6000000 +#define LIM_TOTAL_BW_11B 11000000 +#define LIM_MIN_BW_11B 1000000 +#define LIM_TOTAL_BW_11G LIM_TOTAL_BW_11A +#define LIM_MIN_BW_11G LIM_MIN_BW_11B + +/* conversion factors */ +#define LIM_CONVERT_SIZE_BITS(numBytes) ((numBytes) * 8) +#define LIM_CONVERT_RATE_MBPS(rate) ((rate)/1000000) + +/* ------------------------------------------------------------------------------ */ +/* local protos */ + +static void lim_get_available_bw(struct mac_context *, uint32_t *, uint32_t *, uint32_t, + uint32_t); + +/** ------------------------------------------------------------- + \fn lim_calculate_svc_int + \brief TSPEC validation and servcie interval determination + \param struct mac_context * mac + \param struct mac_tspec_ie *pTspec + \param uint32_t *pSvcInt + \return QDF_STATUS - status of the comparison + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_calculate_svc_int(struct mac_context *mac, + struct mac_tspec_ie *pTspec, uint32_t *pSvcInt) +{ + uint32_t msduSz, dataRate; + *pSvcInt = 0; + + /* if a service interval is already specified, we are done */ + if ((pTspec->minSvcInterval != 0) || (pTspec->maxSvcInterval != 0)) { + *pSvcInt = (pTspec->maxSvcInterval != 0) + ? pTspec->maxSvcInterval : pTspec->minSvcInterval; + return QDF_STATUS_SUCCESS; + } + + /* Masking off the fixed bits according to definition of MSDU size + * in IEEE 802.11-2007 spec (section 7.3.2.30). Nominal MSDU size + * is defined as: Bit[0:14]=Size, Bit[15]=Fixed + */ + if (pTspec->nomMsduSz != 0) + msduSz = (pTspec->nomMsduSz & 0x7fff); + else if (pTspec->maxMsduSz != 0) + msduSz = pTspec->maxMsduSz; + else { + pe_err("MsduSize not specified"); + return QDF_STATUS_E_FAILURE; + } + + /* need to calculate a reasonable service interval + * this is simply the msduSz/meanDataRate + */ + if (pTspec->meanDataRate != 0) + dataRate = pTspec->meanDataRate; + else if (pTspec->peakDataRate != 0) + dataRate = pTspec->peakDataRate; + else if (pTspec->minDataRate != 0) + dataRate = pTspec->minDataRate; + else { + pe_err("DataRate not specified"); + return QDF_STATUS_E_FAILURE; + } + + *pSvcInt = + LIM_CONVERT_SIZE_BITS(msduSz) / LIM_CONVERT_RATE_MBPS(dataRate); + return QDF_STATUS_E_FAILURE; +} + +/** + * lim_validate_tspec_edca() - Validate the parameters + * @mac_ctx: Global MAC context + * @tspec: Pointer to the TSPEC + * @session_entry: Session Entry + * + * validate the parameters in the edca tspec + * mandatory fields are derived from 11e Annex I (Table I.1) + * + * Return: Status + **/ +static QDF_STATUS +lim_validate_tspec_edca(struct mac_context *mac_ctx, + struct mac_tspec_ie *tspec, + struct pe_session *session_entry) +{ + uint32_t max_phy_rate, min_phy_rate; + uint32_t phy_mode; + QDF_STATUS retval = QDF_STATUS_SUCCESS; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + lim_get_available_bw(mac_ctx, &max_phy_rate, &min_phy_rate, phy_mode, + 1 /* bandwidth mult factor */); + /* mandatory fields are derived from 11e Annex I (Table I.1) */ + if ((tspec->nomMsduSz == 0) || + (tspec->meanDataRate == 0) || + (tspec->surplusBw == 0) || + (tspec->minPhyRate == 0) || + (tspec->minPhyRate > max_phy_rate)) { + pe_warn("Invalid EDCA Tspec: NomMsdu: %d meanDataRate: %d surplusBw: %d min_phy_rate: %d", + tspec->nomMsduSz, tspec->meanDataRate, + tspec->surplusBw, tspec->minPhyRate); + retval = QDF_STATUS_E_FAILURE; + } + + pe_debug("return status: %d", retval); + return retval; +} + +/** ------------------------------------------------------------- + \fn lim_validate_tspec + \brief validate the offered tspec + \param struct mac_context *mac + \param struct mac_tspec_ie *pTspec + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_validate_tspec(struct mac_context *mac, + struct mac_tspec_ie *pTspec, struct pe_session *pe_session) +{ + QDF_STATUS retval = QDF_STATUS_SUCCESS; + + switch (pTspec->tsinfo.traffic.accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + retval = lim_validate_tspec_edca(mac, pTspec, pe_session); + if (retval != QDF_STATUS_SUCCESS) + pe_warn("EDCA tspec invalid"); + break; + + case SIR_MAC_ACCESSPOLICY_HCCA: + case SIR_MAC_ACCESSPOLICY_BOTH: + /* TBD: should we support hybrid tspec as well?? for now, just fall through */ + default: + pe_warn("AccessType: %d not supported", + pTspec->tsinfo.traffic.accessPolicy); + retval = QDF_STATUS_E_FAILURE; + break; + } + return retval; +} + +/* ----------------------------------------------------------------------------- */ +/* Admit Control Policy */ + +/** ------------------------------------------------------------- + \fn lim_compute_mean_bw_used + \brief determime the used/allocated bandwidth + \param struct mac_context *mac + \param uint32_t *pBw + \param uint32_t phyMode + \param tpLimTspecInfo pTspecInfo + \return void + -------------------------------------------------------------*/ + +static void +lim_compute_mean_bw_used(struct mac_context *mac, + uint32_t *pBw, + uint32_t phyMode, + tpLimTspecInfo pTspecInfo, struct pe_session *pe_session) +{ + uint32_t ctspec; + *pBw = 0; + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (pTspecInfo->inuse) { + tpDphHashNode pSta = + dph_get_hash_entry(mac, pTspecInfo->assocId, + &pe_session->dph.dphHashTable); + if (!pSta) { + /* maybe we should delete the tspec?? */ + pe_err("Tspec: %d assocId: %d dphNode not found", + ctspec, pTspecInfo->assocId); + continue; + } + *pBw += pTspecInfo->tspec.meanDataRate; + } + } +} + +/** ------------------------------------------------------------- + \fn lim_get_available_bw + \brief based on the phy mode and the bw_factor, determine the total bandwidth that + can be supported + \param struct mac_context *mac + \param uint32_t *pMaxBw + \param uint32_t *pMinBw + \param uint32_t phyMode + \param uint32_t bw_factor + \return void + -------------------------------------------------------------*/ + +static void +lim_get_available_bw(struct mac_context *mac, + uint32_t *pMaxBw, + uint32_t *pMinBw, uint32_t phyMode, uint32_t bw_factor) +{ + switch (phyMode) { + case WNI_CFG_PHY_MODE_11B: + *pMaxBw = LIM_TOTAL_BW_11B; + *pMinBw = LIM_MIN_BW_11B; + break; + + case WNI_CFG_PHY_MODE_11A: + *pMaxBw = LIM_TOTAL_BW_11A; + *pMinBw = LIM_MIN_BW_11A; + break; + + case WNI_CFG_PHY_MODE_11G: + case WNI_CFG_PHY_MODE_NONE: + default: + *pMaxBw = LIM_TOTAL_BW_11G; + *pMinBw = LIM_MIN_BW_11G; + break; + } + *pMaxBw *= bw_factor; +} + +/** + * lim_admit_policy_oversubscription() - Admission control policy + * @mac_ctx: Global MAC Context + * @tspec: Pointer to the tspec + * @admit_policy: Admission policy + * @tspec_info: TSPEC information + * @session_entry: Session Entry + * + * simple admission control policy based on oversubscription + * if the total bandwidth of all admitted tspec's exceeds (factor * phy-bw) then + * reject the tspec, else admit it. The phy-bw is the peak available bw in the + * current phy mode. The 'factor' is the configured oversubscription factor. + * + * Return: Status + **/ +static QDF_STATUS +lim_admit_policy_oversubscription(struct mac_context *mac_ctx, + struct mac_tspec_ie *tspec, + tpLimAdmitPolicyInfo admit_policy, + tpLimTspecInfo tspec_info, + struct pe_session *session_entry) +{ + uint32_t totalbw, minbw, usedbw; + uint32_t phy_mode; + + /* determine total bandwidth used so far */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + lim_compute_mean_bw_used(mac_ctx, &usedbw, phy_mode, + tspec_info, session_entry); + + /* determine how much bw is available based on the current phy mode */ + lim_get_available_bw(mac_ctx, &totalbw, &minbw, phy_mode, + admit_policy->bw_factor); + + if (usedbw > totalbw) /* this can't possibly happen */ + return QDF_STATUS_E_FAILURE; + + if ((totalbw - usedbw) < tspec->meanDataRate) { + pe_warn("Total BW: %d Used: %d Tspec request: %d not possible", + totalbw, usedbw, tspec->meanDataRate); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_policy + \brief determine the current admit control policy and apply it for the offered tspec + \param struct mac_context *mac + \param struct mac_tspec_ie *pTspec + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +static QDF_STATUS lim_admit_policy(struct mac_context *mac, + struct mac_tspec_ie *pTspec, + struct pe_session *pe_session) +{ + QDF_STATUS retval = QDF_STATUS_E_FAILURE; + tpLimAdmitPolicyInfo pAdmitPolicy = &mac->lim.admitPolicyInfo; + + switch (pAdmitPolicy->type) { + case WNI_CFG_ADMIT_POLICY_ADMIT_ALL: + retval = QDF_STATUS_SUCCESS; + break; + + case WNI_CFG_ADMIT_POLICY_BW_FACTOR: + retval = lim_admit_policy_oversubscription(mac, pTspec, + &mac->lim. + admitPolicyInfo, + &mac->lim.tspecInfo[0], + pe_session); + if (retval != QDF_STATUS_SUCCESS) + pe_err("rejected by BWFactor policy"); + break; + + case WNI_CFG_ADMIT_POLICY_REJECT_ALL: + retval = QDF_STATUS_E_FAILURE; + break; + + default: + retval = QDF_STATUS_SUCCESS; + pe_warn("Admit Policy: %d unknown, admitting all traffic", + pAdmitPolicy->type); + break; + } + return retval; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_delete + \brief delete the specified tspec + \param struct mac_context *mac + \param tpLimTspecInfo pInfo + \return void + -------------------------------------------------------------*/ + +/* ----------------------------------------------------------------------------- */ +/* delete the specified tspec */ +static void lim_tspec_delete(struct mac_context *mac, tpLimTspecInfo pInfo) +{ + if (!pInfo) + return; + /* pierre */ + pe_debug("tspec entry: %d delete tspec: %pK", pInfo->idx, pInfo); + pInfo->inuse = 0; + + return; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_sta_addr + \brief Send halMsg_AddTs to HAL + \param struct mac_context *mac + \param \param uint8_t *pAddr + \param struct mac_tspec_ie *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +/* find the specified tspec in the list */ +static QDF_STATUS +lim_tspec_find_by_sta_addr(struct mac_context *mac, + uint8_t *pAddr, + struct mac_tspec_ie *pTspecIE, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) && + (!qdf_mem_cmp(pAddr, pTspecList->staAddr, + sizeof(pTspecList->staAddr))) && + (!qdf_mem_cmp(pTspecIE, &pTspecList->tspec, + sizeof(*pTspecIE)))) { + *ppInfo = pTspecList; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_find_by_assoc_id + \brief find tspec with matching staid and Tspec + \param struct mac_context *mac + \param uint32_t staid + \param struct mac_tspec_ie *pTspecIE + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS +lim_tspec_find_by_assoc_id(struct mac_context *mac, + uint16_t assocId, + struct mac_tspec_ie *pTspecIE, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + pe_debug("Trying to find tspec entry for assocId: %d pTsInfo->traffic.direction: %d pTsInfo->traffic.tsid: %d", + assocId, pTspecIE->tsinfo.traffic.direction, + pTspecIE->tsinfo.traffic.tsid); + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) && + (assocId == pTspecList->assocId) && + (!qdf_mem_cmp(pTspecIE, &pTspecList->tspec, + sizeof(*pTspecIE)))) { + *ppInfo = pTspecList; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_find_tspec + \brief finding a TSPEC entry with assocId, tsinfo.direction and tsinfo.tsid + \param uint16_t assocId + \param struct mac_context * mac + \param struct mac_ts_info *pTsInfo + \param tpLimTspecInfo pTspecList + \param tpLimTspecInfo *ppInfo + \return QDF_STATUS - status of the comparison + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_find_tspec(struct mac_context *mac, + uint16_t assocId, + struct mac_ts_info *pTsInfo, + tpLimTspecInfo pTspecList, tpLimTspecInfo *ppInfo) +{ + int ctspec; + + *ppInfo = NULL; + + pe_debug("Trying to find tspec entry for assocId: %d pTsInfo->traffic.direction: %d pTsInfo->traffic.tsid: %d", + assocId, pTsInfo->traffic.direction, pTsInfo->traffic.tsid); + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecList++) { + if ((pTspecList->inuse) + && (assocId == pTspecList->assocId) + && (pTsInfo->traffic.direction == + pTspecList->tspec.tsinfo.traffic.direction) + && (pTsInfo->traffic.tsid == + pTspecList->tspec.tsinfo.traffic.tsid)) { + *ppInfo = pTspecList; + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_tspec_add + \brief add or update the specified tspec to the tspec list + \param struct mac_context * mac + \param uint8_t *pAddr + \param uint16_t assocId + \param struct mac_tspec_ie *pTspec + \param uint32_t interval + \param tpLimTspecInfo *ppInfo + + \return QDF_STATUS - status of the comparison + -------------------------------------------------------------*/ + +QDF_STATUS lim_tspec_add(struct mac_context *mac, + uint8_t *pAddr, + uint16_t assocId, + struct mac_tspec_ie *pTspec, + uint32_t interval, tpLimTspecInfo *ppInfo) +{ + tpLimTspecInfo pTspecList = &mac->lim.tspecInfo[0]; + *ppInfo = NULL; + + /* validate the assocId */ + if (assocId >= mac->lim.maxStation) { + pe_err("Invalid assocId 0x%x", assocId); + return QDF_STATUS_E_FAILURE; + } + /* decide whether to add/update */ + { + *ppInfo = NULL; + + if (QDF_STATUS_SUCCESS == + lim_find_tspec(mac, assocId, &pTspec->tsinfo, pTspecList, + ppInfo)) { + /* update this entry. */ + pe_debug("updating TSPEC table entry: %d", + (*ppInfo)->idx); + } else { + /* We didn't find one to update. So find a free slot in the + * LIM TSPEC list and add this new entry + */ + uint8_t ctspec = 0; + + for (ctspec = 0, pTspecList = &mac->lim.tspecInfo[0]; + ctspec < LIM_NUM_TSPEC_MAX; + ctspec++, pTspecList++) { + if (!pTspecList->inuse) { + pe_debug("Found free slot in TSPEC list. Add to TSPEC table entry: %d", + ctspec); + break; + } + } + + if (ctspec >= LIM_NUM_TSPEC_MAX) + return QDF_STATUS_E_FAILURE; + + /* Record the new index entry */ + pTspecList->idx = ctspec; + } + } + + /* update the tspec info */ + pTspecList->tspec = *pTspec; + pTspecList->assocId = assocId; + qdf_mem_copy(pTspecList->staAddr, pAddr, sizeof(pTspecList->staAddr)); + + /* for edca tspec's, we are all done */ + if (pTspec->tsinfo.traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + pTspecList->inuse = 1; + *ppInfo = pTspecList; + pe_debug("added entry for EDCA AccessPolicy"); + return QDF_STATUS_SUCCESS; + } + + /* + * for hcca tspec's, must set the parameterized bit in the queues + * the 'ts' bit in the queue data structure indicates that the queue is + * parameterized (hcca). When the schedule is written this bit is used + * in the tsid field (bit 3) and the other three bits (0-2) are simply + * filled in as the user priority (or qid). This applies only to uplink + * polls where the qos control field must contain the tsid specified in the + * tspec. + */ + pTspecList->inuse = 1; + *ppInfo = pTspecList; + pe_debug("added entry for HCCA AccessPolicy"); + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_validate_access_policy + \brief Validates Access policy + \param struct mac_context *mac + \param uint8_t accessPolicy + \param uint16_t assocId + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +static QDF_STATUS +lim_validate_access_policy(struct mac_context *mac, + uint8_t accessPolicy, + uint16_t assocId, struct pe_session *pe_session) +{ + QDF_STATUS retval = QDF_STATUS_E_FAILURE; + tpDphHashNode pSta = + dph_get_hash_entry(mac, assocId, &pe_session->dph.dphHashTable); + + if ((!pSta) || (!pSta->valid)) { + pe_err("invalid station address passed"); + return QDF_STATUS_E_FAILURE; + } + + switch (accessPolicy) { + case SIR_MAC_ACCESSPOLICY_EDCA: + if (pSta->wmeEnabled || pSta->lleEnabled) + retval = QDF_STATUS_SUCCESS; + break; + + case SIR_MAC_ACCESSPOLICY_HCCA: + case SIR_MAC_ACCESSPOLICY_BOTH: + default: + pe_err("Invalid accessPolicy: %d", + accessPolicy); + break; + } + + if (retval != QDF_STATUS_SUCCESS) + pe_warn("accPol: %d lle: %d wme: %d wsm: %d sta mac " + QDF_MAC_ADDR_FMT, accessPolicy, pSta->lleEnabled, + pSta->wmeEnabled, pSta->wsmEnabled, + QDF_MAC_ADDR_REF(pSta->staAddr)); + + return retval; +} + +/** + * lim_admit_control_add_ts() - Check if STA can be admitted + * @mac: Global MAC context + * @pAddr: Address + * @pAddts: ADD TS + * @pQos: QOS fields + * @assocId: Association ID + * @alloc: Allocate bandwidth for this tspec + * @pSch: Schedule IE + * @pTspecIdx: TSPEC index + * @pe_session: PE Session Entry + * + * Determine if STA with the specified TSPEC can be admitted. If it can, + * a schedule element is provided + * + * Return: status + **/ +QDF_STATUS lim_admit_control_add_ts(struct mac_context *mac, uint8_t *pAddr, + tSirAddtsReqInfo *pAddts, tSirMacQosCapabilityStaIE *pQos, + uint16_t assocId, uint8_t alloc, tSirMacScheduleIE *pSch, + uint8_t *pTspecIdx, struct pe_session *pe_session) +{ + tpLimTspecInfo pTspecInfo; + QDF_STATUS retval; + uint32_t svcInterval; + (void)pQos; + + /* TBD: modify tspec as needed */ + /* EDCA: need to fill in the medium time and the minimum phy rate */ + /* to be consistent with the desired traffic parameters. */ + + pe_debug("tsid: %d directn: %d start: %d intvl: %d accPolicy: %d up: %d", + pAddts->tspec.tsinfo.traffic.tsid, + pAddts->tspec.tsinfo.traffic.direction, + pAddts->tspec.svcStartTime, pAddts->tspec.minSvcInterval, + pAddts->tspec.tsinfo.traffic.accessPolicy, + pAddts->tspec.tsinfo.traffic.userPrio); + + /* check for duplicate tspec */ + retval = (alloc) + ? lim_tspec_find_by_assoc_id(mac, assocId, &pAddts->tspec, + &mac->lim.tspecInfo[0], &pTspecInfo) + : lim_tspec_find_by_sta_addr(mac, pAddr, &pAddts->tspec, + &mac->lim.tspecInfo[0], &pTspecInfo); + + if (retval == QDF_STATUS_SUCCESS) { + pe_err("duplicate tspec index: %d", pTspecInfo->idx); + return QDF_STATUS_E_FAILURE; + } + /* check that the tspec's are well formed and acceptable */ + if (lim_validate_tspec(mac, &pAddts->tspec, pe_session) != + QDF_STATUS_SUCCESS) { + pe_warn("tspec validation failed"); + return QDF_STATUS_E_FAILURE; + } + /* determine a service interval for the tspec */ + if (lim_calculate_svc_int(mac, &pAddts->tspec, &svcInterval) != + QDF_STATUS_SUCCESS) { + pe_warn("SvcInt calculate failed"); + return QDF_STATUS_E_FAILURE; + } + /* determine if the tspec can be admitted or not based on current policy */ + if (lim_admit_policy(mac, &pAddts->tspec, pe_session) != QDF_STATUS_SUCCESS) { + pe_warn("tspec rejected by admit control policy"); + return QDF_STATUS_E_FAILURE; + } + /* fill in a schedule if requested */ + if (pSch) { + qdf_mem_zero((uint8_t *) pSch, sizeof(*pSch)); + pSch->svcStartTime = pAddts->tspec.svcStartTime; + pSch->svcInterval = svcInterval; + pSch->maxSvcDuration = (uint16_t) pSch->svcInterval; /* use SP = SI */ + pSch->specInterval = 0x1000; /* fixed for now: TBD */ + + pSch->info.direction = pAddts->tspec.tsinfo.traffic.direction; + pSch->info.tsid = pAddts->tspec.tsinfo.traffic.tsid; + pSch->info.aggregation = 0; /* no support for aggregation for now: TBD */ + } + /* if no allocation is requested, done */ + if (!alloc) + return QDF_STATUS_SUCCESS; + + /* check that we are in the proper mode to deal with the tspec type */ + if (lim_validate_access_policy + (mac, (uint8_t) pAddts->tspec.tsinfo.traffic.accessPolicy, assocId, + pe_session) != QDF_STATUS_SUCCESS) { + pe_warn("AccessPolicy: %d is not valid in current mode", + pAddts->tspec.tsinfo.traffic.accessPolicy); + return QDF_STATUS_E_FAILURE; + } + /* add tspec to list */ + if (lim_tspec_add + (mac, pAddr, assocId, &pAddts->tspec, svcInterval, &pTspecInfo) + != QDF_STATUS_SUCCESS) { + pe_err("no space in tspec list"); + return QDF_STATUS_E_FAILURE; + } + /* passing lim tspec table index to the caller */ + *pTspecIdx = pTspecInfo->idx; + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_delete_ts + \brief Delete the specified Tspec for the specified STA + \param struct mac_context *mac + \param uint16_t assocId + \param struct mac_ts_info *pTsInfo + \param uint8_t *pTsStatus + \param uint8_t *ptspecIdx + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS +lim_admit_control_delete_ts(struct mac_context *mac, + uint16_t assocId, + struct mac_ts_info *pTsInfo, + uint8_t *pTsStatus, uint8_t *ptspecIdx) +{ + tpLimTspecInfo pTspecInfo = NULL; + + if (pTsStatus) + *pTsStatus = 0; + + if (lim_find_tspec + (mac, assocId, pTsInfo, &mac->lim.tspecInfo[0], + &pTspecInfo) == QDF_STATUS_SUCCESS) { + if (pTspecInfo) { + pe_debug("Tspec entry: %d found", pTspecInfo->idx); + + *ptspecIdx = pTspecInfo->idx; + lim_tspec_delete(mac, pTspecInfo); + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_delete_sta + \brief Delete all TSPEC for the specified STA + \param struct mac_context *mac + \param uint16_t assocId + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS lim_admit_control_delete_sta(struct mac_context *mac, uint16_t assocId) +{ + tpLimTspecInfo pTspecInfo = &mac->lim.tspecInfo[0]; + int ctspec; + + for (ctspec = 0; ctspec < LIM_NUM_TSPEC_MAX; ctspec++, pTspecInfo++) { + if (assocId == pTspecInfo->assocId) { + lim_tspec_delete(mac, pTspecInfo); + pe_debug("Deleting TSPEC: %d for assocId: %d", ctspec, + assocId); + } + } + pe_debug("assocId: %d done", assocId); + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_admit_control_init + \brief init tspec table + \param struct mac_context *mac + \return QDF_STATUS - status + -------------------------------------------------------------*/ +QDF_STATUS lim_admit_control_init(struct mac_context *mac) +{ + qdf_mem_zero(mac->lim.tspecInfo, + LIM_NUM_TSPEC_MAX * sizeof(tLimTspecInfo)); + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_add_ts + \brief Send halMsg_AddTs to HAL + \param struct mac_context *mac + \param uint8_t tspecIdx + \param struct mac_tspec_ie tspecIE + \param tSirTclasInfo *tclasInfo + \param uint8_t tclasProc + \param uint16_t tsm_interval + \return QDF_STATUS - status + -------------------------------------------------------------*/ +#ifdef FEATURE_WLAN_ESE +QDF_STATUS +lim_send_hal_msg_add_ts(struct mac_context *mac, + uint8_t tspecIdx, + struct mac_tspec_ie tspecIE, + uint8_t sessionId, uint16_t tsm_interval) +#else +QDF_STATUS +lim_send_hal_msg_add_ts(struct mac_context *mac, + uint8_t tspecIdx, + struct mac_tspec_ie tspecIE, + uint8_t sessionId) +#endif +{ + struct scheduler_msg msg = {0}; + struct add_ts_param *pAddTsParam; + + struct pe_session *pe_session = pe_find_session_by_session_id(mac, sessionId); + + if (!pe_session) { + pe_err("Unable to get Session for session Id: %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + + pAddTsParam = qdf_mem_malloc(sizeof(*pAddTsParam)); + if (!pAddTsParam) + return QDF_STATUS_E_NOMEM; + + pAddTsParam->tspec_idx = tspecIdx; + qdf_mem_copy(&pAddTsParam->tspec, &tspecIE, + sizeof(struct mac_tspec_ie)); + pAddTsParam->pe_session_id = sessionId; + pAddTsParam->vdev_id = pe_session->smeSessionId; + +#ifdef FEATURE_WLAN_ESE + pAddTsParam->tsm_interval = tsm_interval; +#endif +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (mac->mlme_cfg->lfr.lfr3_roaming_offload && + pe_session->is11Rconnection) + pAddTsParam->set_ric_params = true; +#endif + + msg.type = WMA_ADD_TS_REQ; + msg.bodyptr = pAddTsParam; + msg.bodyval = 0; + + /* We need to defer any incoming messages until we get a + * WMA_ADD_TS_RSP from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + MTRACE(mac_trace_msg_tx(mac, sessionId, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(mac, &msg)) { + pe_warn("wma_post_ctrl_msg() failed"); + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + qdf_mem_free(pAddTsParam); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_send_hal_msg_del_ts + \brief Send halMsg_AddTs to HAL + \param struct mac_context *mac + \param uint8_t tspecIdx + \param tSirAddtsReqInfo addts + \return QDF_STATUS - status + -------------------------------------------------------------*/ + +QDF_STATUS +lim_send_hal_msg_del_ts(struct mac_context *mac, + uint8_t tspecIdx, + struct delts_req_info delts, + uint8_t sessionId, uint8_t *bssId) +{ + struct scheduler_msg msg = {0}; + struct del_ts_params *pDelTsParam; + struct pe_session *pe_session = NULL; + + pDelTsParam = qdf_mem_malloc(sizeof(*pDelTsParam)); + if (!pDelTsParam) + return QDF_STATUS_E_NOMEM; + + msg.type = WMA_DEL_TS_REQ; + msg.bodyptr = pDelTsParam; + msg.bodyval = 0; + + /* filling message parameters. */ + pDelTsParam->tspecIdx = tspecIdx; + qdf_mem_copy(&pDelTsParam->bssId, bssId, sizeof(tSirMacAddr)); + + pe_session = pe_find_session_by_session_id(mac, sessionId); + if (!pe_session) { + pe_err("Session does Not exist with given sessionId: %d", + sessionId); + goto err; + } + pDelTsParam->sessionId = pe_session->smeSessionId; + pDelTsParam->userPrio = delts.wmeTspecPresent ? + delts.tspec.tsinfo.traffic.userPrio : + delts.tsinfo.traffic.userPrio; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (mac->mlme_cfg->lfr.lfr3_roaming_offload && + pe_session->is11Rconnection) { + qdf_mem_copy(&pDelTsParam->delTsInfo, &delts, + sizeof(struct delts_req_info)); + pDelTsParam->setRICparams = 1; + } +#endif + MTRACE(mac_trace_msg_tx(mac, sessionId, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(mac, &msg)) { + pe_warn("wma_post_ctrl_msg() failed"); + goto err; + } + return QDF_STATUS_SUCCESS; + +err: + qdf_mem_free(pDelTsParam); + return QDF_STATUS_E_FAILURE; +} + +/** ------------------------------------------------------------- + \fn lim_process_hal_add_ts_rsp + \brief This function process the WMA_ADD_TS_RSP from HAL. + \ If response is successful, then send back SME_ADDTS_RSP. + \ Otherwise, send DELTS action frame to peer and then + \ then send back SME_ADDTS_RSP. + \ + \param struct mac_context * mac + \param struct scheduler_msg *limMsg + -------------------------------------------------------------*/ +void lim_process_hal_add_ts_rsp(struct mac_context *mac, + struct scheduler_msg *limMsg) +{ + struct add_ts_param *pAddTsRspMsg = NULL; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + struct pe_session *pe_session = NULL; + + /* Need to process all the deferred messages enqueued + * since sending the WMA_ADD_TS_REQ. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + + if (!limMsg->bodyptr) { + pe_err("Received WMA_ADD_TS_RSP with NULL"); + goto end; + } + + pAddTsRspMsg = limMsg->bodyptr; + + /* 090803: Use pe_find_session_by_session_id() to obtain the PE session context */ + /* from the sessionId in the Rsp Msg from HAL */ + pe_session = pe_find_session_by_session_id(mac, + pAddTsRspMsg->pe_session_id); + + if (!pe_session) { + pe_err("Session does Not exist with given sessionId: %d", + pAddTsRspMsg->pe_session_id); + lim_send_sme_addts_rsp(mac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + pe_session, pAddTsRspMsg->tspec, + mac->lim.gLimAddtsReq.sessionId); + goto end; + } + + if (pAddTsRspMsg->status == QDF_STATUS_SUCCESS) { + pe_debug("Received successful ADDTS response from HAL"); + /* Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(mac, rspReqd, eSIR_SME_SUCCESS, + pe_session, pAddTsRspMsg->tspec, + pe_session->smeSessionId); + goto end; + } else { + pe_debug("Received failure ADDTS response from HAL"); + /* Send DELTS action frame to AP */ + /* 090803: Get peer MAC addr from session */ + sir_copy_mac_addr(peerMacAddr, pe_session->bssId); + + /* 090803: Add the SME Session ID */ + lim_send_delts_req_action_frame(mac, peerMacAddr, rspReqd, + &pAddTsRspMsg->tspec.tsinfo, + &pAddTsRspMsg->tspec, pe_session); + + /* Delete TSPEC */ + /* 090803: Pull the hash table from the session */ + pSta = dph_lookup_hash_entry(mac, peerMacAddr, &assocId, + &pe_session->dph.dphHashTable); + if (pSta) + lim_admit_control_delete_ts(mac, assocId, + &pAddTsRspMsg->tspec.tsinfo, + NULL, + (uint8_t *) &pAddTsRspMsg-> + tspec_idx); + + /* Send SME_ADDTS_RSP */ + /* 090803: Use the smesessionId and smetransactionId from the PE session context */ + lim_send_sme_addts_rsp(mac, rspReqd, eSIR_SME_ADDTS_RSP_FAILED, + pe_session, pAddTsRspMsg->tspec, + pe_session->smeSessionId); + goto end; + } + +end: + if (pAddTsRspMsg) + qdf_mem_free(pAddTsRspMsg); + return; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c new file mode 100644 index 0000000000..d651d22c62 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_aid_mgmt.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) 2011-2016, 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_aid_mgmt.c contains the functions related to + * AID pool management like initialization, assignment etc. + * Author: Chandra Modumudi + * Date: 03/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_params.h" +#include "lim_utils.h" +#include "lim_timer_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_session_utils.h" +#include +#include + +#define LIM_START_PEER_IDX 1 + +/** + * lim_init_peer_idxpool_legacy() - init aid pool for non MLO SAP + * @mac: Pointer to Global MAC structure + * @pe_session: pe session + * + * Return: Void + */ +static void lim_init_peer_idxpool_legacy(struct mac_context *mac, + struct pe_session *pe_session) +{ + uint8_t i; + uint8_t max_assoc_sta = mac->lim.max_sta_of_pe_session; + + pe_session->gpLimPeerIdxpool[0] = 0; + +#ifdef FEATURE_WLAN_TDLS + /* + * In station role, DPH_STA_HASH_INDEX_PEER (index 1) is reserved + * for peer station index corresponding to AP. Avoid choosing that index + * and get index starting from (DPH_STA_HASH_INDEX_PEER + 1) + * (index 2) for TDLS stations; + */ + if (LIM_IS_STA_ROLE(pe_session)) { + pe_session->freePeerIdxHead = DPH_STA_HASH_INDEX_PEER + 1; + } else +#endif + { + pe_session->freePeerIdxHead = LIM_START_PEER_IDX; + } + + for (i = pe_session->freePeerIdxHead; i < max_assoc_sta; i++) + pe_session->gpLimPeerIdxpool[i] = i + 1; + + pe_session->gpLimPeerIdxpool[i] = 0; + + pe_session->freePeerIdxTail = i; +} + +void lim_init_peer_idxpool(struct mac_context *mac, + struct pe_session *pe_session) +{ + if (!wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + lim_init_peer_idxpool_legacy(mac, pe_session); +} + +/** + * lim_create_peer_idxpool_legacy() - AID pool creation for non-MLO AP + * @pe_session: pe session + * @idx_pool_size: aid pool size + * + * Return: true if pool is created successfully + */ +static bool lim_create_peer_idxpool_legacy(struct pe_session *pe_session, + uint8_t idx_pool_size) +{ + pe_session->gpLimPeerIdxpool = qdf_mem_malloc( + sizeof(*pe_session->gpLimPeerIdxpool) * idx_pool_size); + if (!pe_session->gpLimPeerIdxpool) + return false; + + pe_session->freePeerIdxHead = 0; + pe_session->freePeerIdxTail = 0; + + return true; +} + +bool lim_create_peer_idxpool(struct pe_session *pe_session, + uint8_t idx_pool_size) +{ + pe_session->gLimNumOfCurrentSTAs = 0; + if (!wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + return lim_create_peer_idxpool_legacy(pe_session, + idx_pool_size); + + return true; +} + +/** + * lim_free_peer_idxpool_legacy() - Free the non-MLO AP aid pool + * @pe_session: pe session + * + * Return: Void + */ +static void lim_free_peer_idxpool_legacy(struct pe_session *pe_session) +{ + if (pe_session->gpLimPeerIdxpool) { + qdf_mem_free(pe_session->gpLimPeerIdxpool); + pe_session->gpLimPeerIdxpool = NULL; + } +} + +void lim_free_peer_idxpool(struct pe_session *pe_session) +{ + if (!pe_session->vdev) { + pe_debug("vdev is null"); + return; + } + if (!wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + lim_free_peer_idxpool_legacy(pe_session); +} + +/** + * lim_assign_peer_idx_mlo() - trigger mlo api to allocate an AID for a STA + * @pe_session: pe session + * + * Return: peer_idx - assigned AID for STA + */ +#ifdef WLAN_FEATURE_11BE_MLO +static uint16_t lim_assign_peer_idx_mlo(struct pe_session *pe_session) +{ + return mlme_get_aid(pe_session->vdev); +} +#else +static uint16_t lim_assign_peer_idx_mlo(struct pe_session *pe_session) +{ + return 0; /* no more free peer index */ +} +#endif + +/** + * lim_assign_peer_idx_legacy() - non-MLO AP allocates an AID for a STA + * @mac: Pointer to Global MAC structure + * @pe_session: pe session + * + * Return: peer_idx - assigned AID for STA + */ +static uint16_t lim_assign_peer_idx_legacy(struct mac_context *mac, + struct pe_session *pe_session) +{ + uint16_t peer_id; + + /* return head of free list */ + + if (pe_session->freePeerIdxHead) { + peer_id = pe_session->freePeerIdxHead; + pe_session->freePeerIdxHead = + pe_session->gpLimPeerIdxpool[pe_session->freePeerIdxHead]; + if (pe_session->freePeerIdxHead == 0) + pe_session->freePeerIdxTail = 0; + return peer_id; + } + + return 0; /* no more free peer index */ +} + +/** + * lim_assign_peer_idx() + * + ***FUNCTION: + * This function is called to get a peer station index. This index is + * used during Association/Reassociation + * frame handling to assign association ID (aid) to a STA. + * In case of TDLS, this is used to assign a index into the Dph hash entry. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @return peerIdx - assigned peer Station IDx for STA + */ + +uint16_t lim_assign_peer_idx(struct mac_context *mac, + struct pe_session *pe_session) +{ + uint16_t peer_id; + + /* make sure we haven't exceeded the configurable limit on associations */ + /* This count is global to ensure that it doesn't exceed the hardware limits. */ + if (pe_get_current_stas_count(mac) >= + mac->mlme_cfg->sap_cfg.assoc_sta_limit) { + /* too many associations already active */ + return 0; + } + + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + peer_id = lim_assign_peer_idx_mlo(pe_session); + else + peer_id = lim_assign_peer_idx_legacy(mac, pe_session); + + if (peer_id) + pe_session->gLimNumOfCurrentSTAs++; + + return peer_id; +} + +#ifdef WLAN_FEATURE_11BE_MLO +uint16_t lim_assign_mlo_conn_idx(struct mac_context *mac, + struct pe_session *pe_session, + uint16_t partner_peer_idx) +{ + uint16_t peer_id; + + if (pe_get_current_stas_count(mac) >= + mac->mlme_cfg->sap_cfg.assoc_sta_limit) { + /* too many associations already active */ + return 0; + } + + if (partner_peer_idx) + peer_id = partner_peer_idx; + else + peer_id = mlo_get_aid(pe_session->vdev); + + if (peer_id) + pe_session->gLimNumOfCurrentSTAs++; + + return peer_id; +} + +/** + * lim_release_peer_idx_mlo() - trigger mlo api to release aid + * @peer_idx: aid to free + * @pe_session: pe session + * + * Return: Void + */ +static void lim_release_peer_idx_mlo(uint16_t peer_idx, + struct pe_session *pe_session) +{ + return mlme_free_aid(pe_session->vdev, peer_idx); +} +#else +static void lim_release_peer_idx_mlo(uint16_t peer_idx, + struct pe_session *pe_session) +{ +} +#endif + +/** + * lim_release_peer_idx_legacy() - non-MLO AP releases an AID + * @mac: Pointer to Global MAC structure + * @peer_idx: aid to free + * @pe_session: pe session + * + * Return: Void + */ +static void lim_release_peer_idx_legacy(struct mac_context *mac, + uint16_t peer_idx, + struct pe_session *pe_session) +{ + /* insert at tail of free list */ + if (pe_session->freePeerIdxTail) { + pe_session->gpLimPeerIdxpool[pe_session->freePeerIdxTail] = + (uint8_t)peer_idx; + pe_session->freePeerIdxTail = (uint8_t)peer_idx; + } else { + pe_session->freePeerIdxTail = + pe_session->freePeerIdxHead = (uint8_t)peer_idx; + } + pe_session->gpLimPeerIdxpool[(uint8_t)peer_idx] = 0; +} + +/** + * lim_release_peer_idx() + * + ***FUNCTION: + * This function is called when a STA context is removed + * at AP (or TDLS) to return peer Index + * to free pool. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param peerIdx - peer station index that need to return to free pool + * + * @return None + */ + +void +lim_release_peer_idx(struct mac_context *mac, uint16_t peer_idx, + struct pe_session *pe_session) +{ + pe_session->gLimNumOfCurrentSTAs--; + + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + lim_release_peer_idx_mlo(peer_idx, pe_session); + else + lim_release_peer_idx_legacy(mac, peer_idx, pe_session); +} + +#ifdef WLAN_FEATURE_11BE_MLO +void +lim_release_mlo_conn_idx(struct mac_context *mac, uint16_t peer_idx, + struct pe_session *session, bool free_aid) +{ + session->gLimNumOfCurrentSTAs--; + if (free_aid && + wlan_mlo_get_mlpeer_by_aid(session->vdev->mlo_dev_ctx, peer_idx)) + mlo_free_aid(session->vdev, peer_idx); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_api.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_api.c new file mode 100644 index 0000000000..5e429be23a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_api.c @@ -0,0 +1,4537 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_api.cc contains the functions that are + * exported by LIM to other modules. + * + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_cfg.h" +#include "wni_api.h" +#include "sir_common.h" +#include "sir_debug.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_global.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_security_utils.h" +#include "wmm_apsd.h" +#include "lim_trace.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "wma_types.h" +#include "wlan_crypto_global_api.h" +#include "wlan_crypto_def_i.h" + +#include "rrm_api.h" + +#include +#include "qdf_types.h" +#include "cds_packet.h" +#include "cds_utils.h" +#include "sys_startup.h" +#include "cds_api.h" +#include "wlan_policy_mgr_api.h" +#include "nan_datapath.h" +#include "wma.h" +#include "wlan_mgmt_txrx_utils_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "os_if_nan.h" +#include +#include +#include +#include "wlan_utility.h" +#include +#include "cfg_ucfg_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_twt_api.h" +#include "wlan_scan_utils_api.h" +#include +#include +#include "wlan_pkt_capture_ucfg_api.h" +#include +#include "wlan_mlo_mgr_roam.h" +#include "utils_mlo.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlo_mgr_peer.h" +#include +#include "wlan_tdls_api.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "wlan_cm_api.h" +#include "wlan_mlme_api.h" + +struct pe_hang_event_fixed_param { + uint16_t tlv_header; + uint8_t vdev_id; + uint8_t limmlmstate; + uint8_t limprevmlmstate; + uint8_t limsmestate; + uint8_t limprevsmestate; +} qdf_packed; + +static void __lim_init_bss_vars(struct mac_context *mac) +{ + qdf_mem_zero((void *)mac->lim.gpSession, + sizeof(*mac->lim.gpSession) * mac->lim.maxBssId); +} + +static void __lim_init_stats_vars(struct mac_context *mac) +{ + /* / Variable to keep track of number of currently associated STAs */ + mac->lim.gLimNumOfAniSTAs = 0; /* count of ANI peers */ + + qdf_mem_zero(mac->lim.gLimHeartBeatApMac[0], + sizeof(tSirMacAddr)); + qdf_mem_zero(mac->lim.gLimHeartBeatApMac[1], + sizeof(tSirMacAddr)); + mac->lim.gLimHeartBeatApMacIndex = 0; +} + +static void __lim_init_states(struct mac_context *mac) +{ + /* Counts Heartbeat failures */ + mac->lim.gLimHBfailureCntInLinkEstState = 0; + mac->lim.gLimProbeFailureAfterHBfailedCnt = 0; + mac->lim.gLimHBfailureCntInOtherStates = 0; + mac->lim.gLimRspReqd = 0; + mac->lim.gLimPrevSmeState = eLIM_SME_OFFLINE_STATE; + + /* / MLM State visible across all Sirius modules */ + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, NO_SESSION, eLIM_MLM_IDLE_STATE)); + mac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + + /* / Previous MLM State */ + mac->lim.gLimPrevMlmState = eLIM_MLM_OFFLINE_STATE; + + /** + * Initialize state to eLIM_SME_OFFLINE_STATE + */ + mac->lim.gLimSmeState = eLIM_SME_OFFLINE_STATE; + + /** + * By default assume 'unknown' role. This will be updated + * when SME_START_BSS_REQ is received. + */ + + qdf_mem_zero(&mac->lim.gLimNoShortParams, sizeof(tLimNoShortParams)); + qdf_mem_zero(&mac->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams)); + + mac->lim.gLimPhyMode = 0; +} + +static void __lim_init_vars(struct mac_context *mac) +{ + /* Place holder for Measurement Req/Rsp/Ind related info */ + + + /* Deferred Queue Parameters */ + qdf_mem_zero(&mac->lim.gLimDeferredMsgQ, sizeof(tSirAddtsReq)); + + /* addts request if any - only one can be outstanding at any time */ + qdf_mem_zero(&mac->lim.gLimAddtsReq, sizeof(tSirAddtsReq)); + mac->lim.gLimAddtsSent = 0; + mac->lim.gLimAddtsRspTimerCount = 0; + + /* protection related config cache */ + qdf_mem_zero(&mac->lim.cfgProtection, sizeof(tCfgProtection)); + mac->lim.gLimProtectionControl = 0; + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + + /* WMM Related Flag */ + mac->lim.gUapsdEnable = 0; + + /* QoS-AC Downgrade: Initially, no AC is admitted */ + mac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] = 0; + mac->lim.gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] = 0; + + /* dialogue token List head/tail for Action frames request sent. */ + mac->lim.pDialogueTokenHead = NULL; + mac->lim.pDialogueTokenTail = NULL; + + qdf_mem_zero(&mac->lim.tspecInfo, + sizeof(tLimTspecInfo) * LIM_NUM_TSPEC_MAX); + + /* admission control policy information */ + qdf_mem_zero(&mac->lim.admitPolicyInfo, sizeof(tLimAdmitPolicyInfo)); +} + +static void __lim_init_assoc_vars(struct mac_context *mac) +{ + mac->lim.gLimIbssStaLimit = 0; + /* Place holder for current authentication request */ + /* being handled */ + mac->lim.gpLimMlmAuthReq = NULL; + + /* / MAC level Pre-authentication related globals */ + mac->lim.gLimPreAuthChannelNumber = 0; + mac->lim.gLimPreAuthType = eSIR_OPEN_SYSTEM; + qdf_mem_zero(&mac->lim.gLimPreAuthPeerAddr, sizeof(tSirMacAddr)); + mac->lim.gLimNumPreAuthContexts = 0; + qdf_mem_zero(&mac->lim.gLimPreAuthTimerTable, sizeof(tLimPreAuthTable)); + + /* Place holder for Pre-authentication node list */ + mac->lim.pLimPreAuthList = NULL; + + /* One cache for each overlap and associated case. */ + qdf_mem_zero(mac->lim.protStaOverlapCache, + sizeof(tCacheParams) * LIM_PROT_STA_OVERLAP_CACHE_SIZE); + qdf_mem_zero(mac->lim.protStaCache, + sizeof(tCacheParams) * LIM_PROT_STA_CACHE_SIZE); + + mac->lim.pe_session = NULL; + mac->lim.reAssocRetryAttempt = 0; + +} + +static void __lim_init_ht_vars(struct mac_context *mac) +{ + mac->lim.htCapabilityPresentInBeacon = 0; + mac->lim.gHTGreenfield = 0; + mac->lim.gHTShortGI40Mhz = 0; + mac->lim.gHTShortGI20Mhz = 0; + mac->lim.gHTMaxAmsduLength = 0; + mac->lim.gHTDsssCckRate40MHzSupport = 0; + mac->lim.gHTPSMPSupport = 0; + mac->lim.gHTLsigTXOPProtection = 0; + mac->lim.gHTMIMOPSState = eSIR_HT_MIMO_PS_STATIC; + mac->lim.gHTAMpduDensity = 0; + + mac->lim.gMaxAmsduSizeEnabled = false; + mac->lim.gHTMaxRxAMpduFactor = 0; + mac->lim.gHTServiceIntervalGranularity = 0; + mac->lim.gHTControlledAccessOnly = 0; + mac->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + mac->lim.gHTPCOActive = 0; + + mac->lim.gHTPCOPhase = 0; + mac->lim.gHTSecondaryBeacon = 0; + mac->lim.gHTDualCTSProtection = 0; + mac->lim.gHTSTBCBasicMCS = 0; +} + +static QDF_STATUS __lim_init_config(struct mac_context *mac) +{ + struct mlme_ht_capabilities_info *ht_cap_info; +#ifdef FEATURE_WLAN_TDLS + QDF_STATUS status; + uint32_t val1; + bool valb; +#endif + + /* Read all the CFGs here that were updated before pe_start is called */ + /* All these CFG READS/WRITES are only allowed in init, at start when there is no session + * and they will be used throughout when there is no session + */ + mac->lim.gLimIbssStaLimit = mac->mlme_cfg->sap_cfg.assoc_sta_limit; + ht_cap_info = &mac->mlme_cfg->ht_caps.ht_cap_info; + + /* channel bonding mode could be set to anything from 0 to 4(Titan had these */ + /* modes But for Taurus we have only two modes: enable(>0) or disable(=0) */ + ht_cap_info->supported_channel_width_set = + mac->mlme_cfg->feature_flags.channel_bonding_mode ? + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE : + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + + mac->mlme_cfg->ht_caps.info_field_1.recommended_tx_width_set = + ht_cap_info->supported_channel_width_set; + + if (!mac->mlme_cfg->timeouts.heart_beat_threshold) { + mac->sys.gSysEnableLinkMonitorMode = 0; + } else { + /* No need to activate the timer during init time. */ + mac->sys.gSysEnableLinkMonitorMode = 1; + } + + /* WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA - not needed */ + + /* This was initially done after resume notification from HAL. Now, DAL is + started before PE so this can be done here */ + handle_ht_capabilityand_ht_info(mac, NULL); +#ifdef FEATURE_WLAN_TDLS + status = cfg_tdls_get_buffer_sta_enable(mac->psoc, &valb); + if (QDF_STATUS_SUCCESS != status) { + pe_err("cfg get LimTDLSBufStaEnabled failed"); + return QDF_STATUS_E_FAILURE; + } + mac->lim.gLimTDLSBufStaEnabled = (uint8_t)valb; + + status = cfg_tdls_get_uapsd_mask(mac->psoc, &val1); + if (QDF_STATUS_SUCCESS != status) { + pe_err("cfg get LimTDLSUapsdMask failed"); + return QDF_STATUS_E_FAILURE; + } + mac->lim.gLimTDLSUapsdMask = (uint8_t)val1; + + status = cfg_tdls_get_off_channel_enable(mac->psoc, &valb); + if (QDF_STATUS_SUCCESS != status) { + pe_err("cfg get LimTDLSUapsdMask failed"); + return QDF_STATUS_E_FAILURE; + } + mac->lim.gLimTDLSOffChannelEnabled = (uint8_t)valb; + + status = cfg_tdls_get_wmm_mode_enable(mac->psoc, &valb); + if (QDF_STATUS_SUCCESS != status) { + pe_err("cfg get LimTDLSWmmMode failed"); + return QDF_STATUS_E_FAILURE; + } + mac->lim.gLimTDLSWmmMode = (uint8_t)valb; +#endif + + return QDF_STATUS_SUCCESS; +} + +/* + lim_start + This function is to replace the __lim_process_sme_start_req since there is no + eWNI_SME_START_REQ post to PE. + */ +QDF_STATUS lim_start(struct mac_context *mac) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pe_debug("enter"); + + if (mac->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + mac->lim.gLimSmeState = eLIM_SME_IDLE_STATE; + + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, NO_SESSION, + mac->lim.gLimSmeState)); + + /* Initialize MLM state machine */ + if (QDF_STATUS_SUCCESS != lim_init_mlm(mac)) { + pe_err("Init MLM failed"); + return QDF_STATUS_E_FAILURE; + } + } else { + /** + * Should not have received eWNI_SME_START_REQ in states + * other than OFFLINE. Return response to host and + * log error + */ + pe_warn("Invalid SME state: %X", + mac->lim.gLimSmeState); + retCode = QDF_STATUS_E_FAILURE; + } + + mac->lim.req_id = + wlan_scan_register_requester(mac->psoc, + "LIM", + lim_process_rx_scan_handler, + mac); + return retCode; +} + +/** + * lim_initialize() + * + ***FUNCTION: + * This function is called from LIM thread entry function. + * LIM related global data structures are initialized in this function. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to global MAC structure + * @return None + */ + +QDF_STATUS lim_initialize(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + mac->lim.tdls_frm_session_id = NO_SESSION; + mac->lim.deferredMsgCnt = 0; + mac->lim.retry_packet_cnt = 0; + mac->lim.deauthMsgCnt = 0; + mac->lim.disassocMsgCnt = 0; + + __lim_init_assoc_vars(mac); + __lim_init_vars(mac); + __lim_init_states(mac); + __lim_init_stats_vars(mac); + __lim_init_bss_vars(mac); + __lim_init_ht_vars(mac); + + rrm_initialize(mac); + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create( + &mac->lim.lim_frame_register_lock))) { + pe_err("lim lock init failed!"); + return QDF_STATUS_E_FAILURE; + } + + qdf_list_create(&mac->lim.gLimMgmtFrameRegistratinQueue, 0); + + /* initialize the TSPEC admission control table. */ + /* Note that this was initially done after resume notification from HAL. */ + /* Now, DAL is started before PE so this can be done here */ + lim_admit_control_init(mac); + return status; + +} /*** end lim_initialize() ***/ + +/** + * lim_cleanup() + * + ***FUNCTION: + * This function is called upon reset or persona change + * to cleanup LIM state + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @return None + */ + +void lim_cleanup(struct mac_context *mac) +{ + uint8_t i; + qdf_list_node_t *lst_node; + + /* + * Before destroying the list making sure all the nodes have been + * deleted + */ + while (qdf_list_remove_front( + &mac->lim.gLimMgmtFrameRegistratinQueue, + &lst_node) == QDF_STATUS_SUCCESS) { + qdf_mem_free(lst_node); + } + qdf_list_destroy(&mac->lim.gLimMgmtFrameRegistratinQueue); + qdf_mutex_destroy(&mac->lim.lim_frame_register_lock); + + pe_deregister_mgmt_rx_frm_callback(mac); + + /* free up preAuth table */ + if (mac->lim.gLimPreAuthTimerTable.pTable) { + for (i = 0; i < mac->lim.gLimPreAuthTimerTable.numEntry; i++) + qdf_mem_free(mac->lim.gLimPreAuthTimerTable.pTable[i]); + qdf_mem_free(mac->lim.gLimPreAuthTimerTable.pTable); + mac->lim.gLimPreAuthTimerTable.pTable = NULL; + mac->lim.gLimPreAuthTimerTable.numEntry = 0; + } + + if (mac->lim.pDialogueTokenHead) { + lim_delete_dialogue_token_list(mac); + } + + if (mac->lim.pDialogueTokenTail) { + qdf_mem_free(mac->lim.pDialogueTokenTail); + mac->lim.pDialogueTokenTail = NULL; + } + + if (mac->lim.gpLimMlmAuthReq) { + qdf_mem_free(mac->lim.gpLimMlmAuthReq); + mac->lim.gpLimMlmAuthReq = NULL; + } + + if (mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq) { + qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq); + mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + } + + if (mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) { + qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq); + mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + + /* Now, finally reset the deferred message queue pointers */ + lim_reset_deferred_msg_q(mac); + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) + rrm_cleanup(mac, i); + + lim_ft_cleanup_all_ft_sessions(mac); + + wlan_scan_unregister_requester(mac->psoc, mac->lim.req_id); +} /*** end lim_cleanup() ***/ + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * lim_state_info_dump() - print state information of lim layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to print state information of lim layer + * + * Return: None + */ +static void lim_state_info_dump(char **buf_ptr, uint16_t *size) +{ + struct mac_context *mac; + uint16_t len = 0; + char *buf = *buf_ptr; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + return; + } + + pe_debug("size of buffer: %d", *size); + + len += qdf_scnprintf(buf + len, *size - len, + "\n SmeState: %d", mac->lim.gLimSmeState); + len += qdf_scnprintf(buf + len, *size - len, + "\n PrevSmeState: %d", mac->lim.gLimPrevSmeState); + len += qdf_scnprintf(buf + len, *size - len, + "\n MlmState: %d", mac->lim.gLimMlmState); + len += qdf_scnprintf(buf + len, *size - len, + "\n PrevMlmState: %d", mac->lim.gLimPrevMlmState); + len += qdf_scnprintf(buf + len, *size - len, + "\n ProcessDefdMsgs: %d", mac->lim.gLimProcessDefdMsgs); + + *size -= len; + *buf_ptr += len; +} + +/** + * lim_register_debug_callback() - registration function for lim layer + * to print lim state information + * + * Return: None + */ +static void lim_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_PE, &lim_state_info_dump); +} +#else /* WLAN_FEATURE_MEMDUMP_ENABLE */ +static void lim_register_debug_callback(void) +{ +} +#endif /* WLAN_FEATURE_MEMDUMP_ENABLE */ + +#ifdef WLAN_FEATURE_NAN +static void lim_nan_register_callbacks(struct mac_context *mac_ctx) +{ + struct nan_callbacks cb_obj = {0}; + + cb_obj.add_ndi_peer = lim_add_ndi_peer_converged; + cb_obj.ndp_delete_peers = lim_ndp_delete_peers_converged; + cb_obj.delete_peers_by_addr = lim_ndp_delete_peers_by_addr_converged; + + ucfg_nan_register_lim_callbacks(mac_ctx->psoc, &cb_obj); +} +#else +static inline void lim_nan_register_callbacks(struct mac_context *mac_ctx) +{ +} +#endif + +#ifdef FEATURE_WLAN_TDLS +static void lim_register_tdls_callbacks(struct mac_context *mac_ctx) +{ + struct tdls_callbacks tdls_cb = {0}; + + tdls_cb.delete_all_tdls_peers = lim_delete_all_tdls_peers; + + wlan_tdls_register_lim_callbacks(mac_ctx->psoc, &tdls_cb); +} +#else +static inline void lim_register_tdls_callbacks(struct mac_context *mac_ctx) +{} +#endif + +void lim_stop_pmfcomeback_timer(struct pe_session *session) +{ + if (session->opmode != QDF_STA_MODE) + return; + + qdf_mc_timer_stop(&session->pmf_retry_timer); + session->pmf_retry_timer_info.retried = false; +} + +/* + * pe_shutdown_notifier_cb - Shutdown notifier callback + * @ctx: Pointer to Global MAC structure + * + * Return: None + */ +static void pe_shutdown_notifier_cb(void *ctx) +{ + struct mac_context *mac_ctx = (struct mac_context *)ctx; + struct pe_session *session; + uint8_t i; + + lim_deactivate_timers(mac_ctx); + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session = &mac_ctx->lim.gpSession[i]; + if (session->valid == true) { + if (LIM_IS_AP_ROLE(session)) + qdf_mc_timer_stop(&session-> + protection_fields_reset_timer); + lim_stop_pmfcomeback_timer(session); + } + } +} + +bool is_mgmt_protected(uint32_t vdev_id, + const uint8_t *peer_mac_addr) +{ + uint16_t aid; + tpDphHashNode sta_ds; + struct pe_session *session; + bool protected = false; + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return false; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + /* couldn't find session */ + pe_err("Session not found for vdev_id: %d", vdev_id); + return false; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, (uint8_t *)peer_mac_addr, &aid, + &session->dph.dphHashTable); + if (sta_ds) { + /* rmfenabled will be set at the time of addbss. + * but sometimes EAP auth fails and keys are not + * installed then if we send any management frame + * like deauth/disassoc with this bit set then + * firmware crashes. so check for keys are + * installed or not also before setting the bit + */ + if (sta_ds->rmfEnabled && sta_ds->is_key_installed) + protected = true; + } + + return protected; +} + +static void p2p_register_callbacks(struct mac_context *mac_ctx) +{ + struct p2p_protocol_callbacks p2p_cb = {0}; + + p2p_cb.is_mgmt_protected = is_mgmt_protected; + ucfg_p2p_register_callbacks(mac_ctx->psoc, &p2p_cb); +} + +/* + * lim_register_sap_bcn_callback(): Register a callback with scan module for SAP + * @mac_ctx: pointer to the global mac context + * + * Registers the function lim_handle_sap_beacon as callback with the Scan + * module to handle beacon frames for SAP sessions + * + * Return: QDF Status + */ +static QDF_STATUS lim_register_sap_bcn_callback(struct mac_context *mac_ctx) +{ + QDF_STATUS status; + + status = ucfg_scan_register_bcn_cb(mac_ctx->psoc, + lim_handle_sap_beacon, + SCAN_CB_TYPE_UPDATE_BCN); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("failed with status code %08d [x%08x]", + status, status); + } + + return status; +} + +/* + * lim_unregister_sap_bcn_callback(): Unregister the callback with scan module + * @mac_ctx: pointer to the global mac context + * + * Unregisters the callback registered with the Scan + * module to handle beacon frames for SAP sessions + * + * Return: QDF Status + */ +static QDF_STATUS lim_unregister_sap_bcn_callback(struct mac_context *mac_ctx) +{ + QDF_STATUS status; + + status = ucfg_scan_register_bcn_cb(mac_ctx->psoc, + NULL, SCAN_CB_TYPE_UPDATE_BCN); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("failed with status code %08d [x%08x]", + status, status); + } + + return status; +} + +/* + * lim_register_scan_mbssid_callback(): Register callback with scan module + * @mac_ctx: pointer to the global mac context + * + * Registers the function lim_register_scan_mbssid_callback as callback + * with the Scan module to handle generated frames by MBSSID IE + * + * Return: QDF Status + */ +static QDF_STATUS +lim_register_scan_mbssid_callback(struct mac_context *mac_ctx) +{ + QDF_STATUS status; + + status = wlan_scan_register_mbssid_cb(mac_ctx->psoc, + lim_handle_frame_genby_mbssid); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("failed with status code %08d [x%08x]", + status, status); + } + + return status; +} + +/* + * lim_unregister_scan_mbssid_callback(): Unregister callback with scan module + * @mac_ctx: pointer to the global mac context + * + * Unregisters the callback registered with the Scan module to handle + * generated frames by MBSSID IE + * + * Return: QDF Status + */ +static QDF_STATUS +lim_unregister_scan_mbssid_callback(struct mac_context *mac_ctx) +{ + QDF_STATUS status; + + status = wlan_scan_register_mbssid_cb(mac_ctx->psoc, NULL); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("failed with status code %08d [x%08x]", + status, status); + } + + return status; +} + +static void lim_register_policy_mgr_callback(struct wlan_objmgr_psoc *psoc) +{ + struct policy_mgr_conc_cbacks conc_cbacks; + + qdf_mem_zero(&conc_cbacks, sizeof(conc_cbacks)); + conc_cbacks.connection_info_update = lim_send_conc_params_update; + + if (QDF_STATUS_SUCCESS != policy_mgr_register_conc_cb(psoc, + &conc_cbacks)) { + pe_err("failed to register policy manager callbacks"); + } +} + +static int pe_hang_event_notifier_call(struct notifier_block *block, + unsigned long state, + void *data) +{ + qdf_notif_block *notif_block = qdf_container_of(block, qdf_notif_block, + notif_block); + struct mac_context *mac; + struct pe_session *session; + struct qdf_notifer_data *pe_hang_data = data; + uint8_t *pe_data; + uint8_t i; + struct pe_hang_event_fixed_param *cmd; + size_t size; + + if (!data) + return NOTIFY_STOP_MASK; + + mac = notif_block->priv_data; + if (!mac) + return NOTIFY_STOP_MASK; + + size = sizeof(*cmd); + for (i = 0; i < mac->lim.maxBssId; i++) { + session = &mac->lim.gpSession[i]; + if (!session->valid) + continue; + if (pe_hang_data->offset + size > QDF_WLAN_HANG_FW_OFFSET) + return NOTIFY_STOP_MASK; + + pe_data = (pe_hang_data->hang_data + pe_hang_data->offset); + cmd = (struct pe_hang_event_fixed_param *)pe_data; + QDF_HANG_EVT_SET_HDR(&cmd->tlv_header, HANG_EVT_TAG_LEGACY_MAC, + QDF_HANG_GET_STRUCT_TLVLEN(*cmd)); + cmd->vdev_id = session->vdev_id; + cmd->limmlmstate = session->limMlmState; + cmd->limprevmlmstate = session->limPrevMlmState; + cmd->limsmestate = session->limSmeState; + cmd->limprevsmestate = session->limPrevSmeState; + pe_hang_data->offset += size; + } + + return NOTIFY_OK; +} + +static qdf_notif_block pe_hang_event_notifier = { + .notif_block.notifier_call = pe_hang_event_notifier_call, +}; + +/** ------------------------------------------------------------- + \fn pe_open + \brief will be called in Open sequence from mac_open + \param struct mac_context *mac + \param tHalOpenParameters *pHalOpenParam + \return QDF_STATUS + -------------------------------------------------------------*/ + +QDF_STATUS pe_open(struct mac_context *mac, struct cds_config_info *cds_cfg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_DRIVER_TYPE_MFG == cds_cfg->driver_type) + return QDF_STATUS_SUCCESS; + + mac->lim.maxBssId = cds_cfg->max_bssid; + mac->lim.maxStation = cds_cfg->max_station; + mac->lim.max_sta_of_pe_session = + (cds_cfg->max_station > SIR_SAP_MAX_NUM_PEERS) ? + SIR_SAP_MAX_NUM_PEERS : cds_cfg->max_station; + qdf_spinlock_create(&mac->sys.bbt_mgmt_lock); + + if ((mac->lim.maxBssId == 0) || (mac->lim.maxStation == 0)) { + pe_err("max number of Bssid or Stations cannot be zero!"); + return QDF_STATUS_E_FAILURE; + } + + if (!QDF_IS_STATUS_SUCCESS(pe_allocate_dph_node_array_buffer())) { + pe_err("g_dph_node_array memory allocate failed!"); + return QDF_STATUS_E_NOMEM; + } + + mac->lim.lim_timers.gpLimCnfWaitTimer = + qdf_mem_malloc(sizeof(TX_TIMER) * (mac->lim.maxStation + 1)); + if (!mac->lim.lim_timers.gpLimCnfWaitTimer) { + status = QDF_STATUS_E_NOMEM; + goto pe_open_timer_fail; + } + + mac->lim.gpSession = + qdf_mem_common_alloc(sizeof(struct pe_session) * mac->lim.maxBssId); + if (!mac->lim.gpSession) { + status = QDF_STATUS_E_NOMEM; + goto pe_open_psession_fail; + } + + status = lim_initialize(mac); + if (QDF_STATUS_SUCCESS != status) { + pe_err("lim_initialize failed!"); + status = QDF_STATUS_E_FAILURE; + goto pe_open_lock_fail; + } + + /* + * pe_open is successful by now, so it is right time to initialize + * MTRACE for PE module. if LIM_TRACE_RECORD is not defined in build + * file then nothing will be logged for PE module. + */ +#ifdef LIM_TRACE_RECORD + MTRACE(lim_trace_init(mac)); +#endif + lim_register_debug_callback(); + lim_nan_register_callbacks(mac); + p2p_register_callbacks(mac); + lim_register_tdls_callbacks(mac); + lim_register_scan_mbssid_callback(mac); + lim_register_sap_bcn_callback(mac); + wlan_reg_register_ctry_change_callback( + mac->psoc, + lim_update_tx_pwr_on_ctry_change_cb); + + wlan_reg_register_is_chan_connected_callback(mac->psoc, + lim_get_connected_chan_for_mode); + + if (mac->mlme_cfg->edca_params.enable_edca_params) + lim_register_policy_mgr_callback(mac->psoc); + + if (!QDF_IS_STATUS_SUCCESS( + cds_shutdown_notifier_register(pe_shutdown_notifier_cb, mac))) { + pe_err("Shutdown notifier register failed"); + } + + pe_hang_event_notifier.priv_data = mac; + qdf_hang_event_register_notifier(&pe_hang_event_notifier); + + return status; /* status here will be QDF_STATUS_SUCCESS */ + +pe_open_lock_fail: + qdf_mem_common_free(mac->lim.gpSession); + mac->lim.gpSession = NULL; +pe_open_psession_fail: + qdf_mem_free(mac->lim.lim_timers.gpLimCnfWaitTimer); + mac->lim.lim_timers.gpLimCnfWaitTimer = NULL; +pe_open_timer_fail: + pe_free_dph_node_array_buffer(); + + return status; +} + +/** ------------------------------------------------------------- + \fn pe_close + \brief will be called in close sequence from mac_close + \param struct mac_context *mac + \return QDF_STATUS + -------------------------------------------------------------*/ + +QDF_STATUS pe_close(struct mac_context *mac) +{ + uint8_t i; + + if (ANI_DRIVER_TYPE(mac) == QDF_DRIVER_TYPE_MFG) + return QDF_STATUS_SUCCESS; + + qdf_hang_event_unregister_notifier(&pe_hang_event_notifier); + lim_cleanup_mlm(mac); + lim_cleanup(mac); + lim_unregister_scan_mbssid_callback(mac); + lim_unregister_sap_bcn_callback(mac); + wlan_reg_unregister_ctry_change_callback( + mac->psoc, + lim_update_tx_pwr_on_ctry_change_cb); + + wlan_reg_unregister_is_chan_connected_callback(mac->psoc, + lim_get_connected_chan_for_mode); + + if (mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) { + qdf_mem_free(mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq); + mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } + + qdf_spinlock_destroy(&mac->sys.bbt_mgmt_lock); + for (i = 0; i < mac->lim.maxBssId; i++) { + if (mac->lim.gpSession[i].valid == true) + pe_delete_session(mac, &mac->lim.gpSession[i]); + } + qdf_mem_free(mac->lim.lim_timers.gpLimCnfWaitTimer); + mac->lim.lim_timers.gpLimCnfWaitTimer = NULL; + + qdf_mem_common_free(mac->lim.gpSession); + mac->lim.gpSession = NULL; + + pe_free_dph_node_array_buffer(); + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn pe_start + \brief will be called in start sequence from mac_start + \param struct mac_context *mac + \return QDF_STATUS_SUCCESS on success, other QDF_STATUS on error + -------------------------------------------------------------*/ + +QDF_STATUS pe_start(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + status = lim_start(mac); + if (QDF_STATUS_SUCCESS != status) { + pe_err("lim_start failed!"); + return status; + } + /* Initialize the configurations needed by PE */ + if (QDF_STATUS_E_FAILURE == __lim_init_config(mac)) { + pe_err("lim init config failed!"); + /* We need to undo everything in lim_start */ + lim_cleanup_mlm(mac); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** ------------------------------------------------------------- + \fn pe_stop + \brief will be called in stop sequence from mac_stop + \param struct mac_context *mac + \return none + -------------------------------------------------------------*/ + +void pe_stop(struct mac_context *mac) +{ + pe_debug(" PE STOP: Set LIM state to eLIM_MLM_OFFLINE_STATE"); + SET_LIM_MLM_STATE(mac, eLIM_MLM_OFFLINE_STATE); + return; +} + +static void pe_free_nested_messages(struct scheduler_msg *msg) +{ + switch (msg->type) { + default: + break; + } +} + +/** ------------------------------------------------------------- + \fn pe_free_msg + \brief Called by CDS scheduler (function cds_sched_flush_mc_mqs) + \ to free a given PE message on the TX and MC thread. + \ This happens when there are messages pending in the PE + \ queue when system is being stopped and reset. + \param struct mac_context *mac + \param struct scheduler_msg pMsg + \return none + -----------------------------------------------------------------*/ +void pe_free_msg(struct mac_context *mac, struct scheduler_msg *pMsg) +{ + if (pMsg) { + if (pMsg->bodyptr) { + if (SIR_BB_XPORT_MGMT_MSG == pMsg->type) { + cds_pkt_return_packet((cds_pkt_t *) pMsg-> + bodyptr); + } else { + pe_free_nested_messages(pMsg); + qdf_mem_free((void *)pMsg->bodyptr); + } + } + pMsg->bodyptr = 0; + pMsg->bodyval = 0; + pMsg->type = 0; + } + return; +} + +QDF_STATUS lim_post_msg_api(struct mac_context *mac, struct scheduler_msg *msg) +{ + return scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, msg); +} + +QDF_STATUS lim_post_msg_high_priority(struct mac_context *mac, + struct scheduler_msg *msg) +{ + return scheduler_post_msg_by_priority(QDF_MODULE_ID_PE, + msg, true); +} + +QDF_STATUS pe_mc_process_handler(struct scheduler_msg *msg) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG) + return QDF_STATUS_SUCCESS; + + lim_message_processor(mac_ctx, msg); + + return QDF_STATUS_SUCCESS; +} + +/** + * pe_drop_pending_rx_mgmt_frames: To drop pending RX mgmt frames + * @mac_ctx: Pointer to global MAC structure + * @hdr: Management header + * @cds_pkt: Packet + * + * This function is used to drop RX pending mgmt frames if pe mgmt queue + * reaches threshold + * + * Return: QDF_STATUS_SUCCESS on success or QDF_STATUS_E_FAILURE on failure + */ +static QDF_STATUS pe_drop_pending_rx_mgmt_frames(struct mac_context *mac_ctx, + tpSirMacMgmtHdr hdr, cds_pkt_t *cds_pkt) +{ + qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock); + if (mac_ctx->sys.sys_bbt_pending_mgmt_count >= + MGMT_RX_PACKETS_THRESHOLD) { + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + pe_debug("No.of pending RX management frames reaches to threshold, dropping management frames"); + cds_pkt_return_packet(cds_pkt); + cds_pkt = NULL; + mac_ctx->rx_packet_drop_counter++; + return QDF_STATUS_E_FAILURE; + } else if (mac_ctx->sys.sys_bbt_pending_mgmt_count > + (MGMT_RX_PACKETS_THRESHOLD / 2)) { + /* drop all probereq, proberesp and beacons */ + if (hdr->fc.subType == SIR_MAC_MGMT_BEACON || + hdr->fc.subType == SIR_MAC_MGMT_PROBE_REQ || + hdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + if (!(mac_ctx->rx_packet_drop_counter % 100)) + pe_debug("No.of pending RX mgmt frames reaches 1/2 thresh, dropping frame subtype: %d rx_packet_drop_counter: %d", + hdr->fc.subType, + mac_ctx->rx_packet_drop_counter); + mac_ctx->rx_packet_drop_counter++; + cds_pkt_return_packet(cds_pkt); + cds_pkt = NULL; + return QDF_STATUS_E_FAILURE; + } + } + mac_ctx->sys.sys_bbt_pending_mgmt_count++; + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + if (mac_ctx->sys.sys_bbt_pending_mgmt_count == + (MGMT_RX_PACKETS_THRESHOLD / 4)) { + if (!(mac_ctx->rx_packet_drop_counter % 100)) + pe_debug("No.of pending RX management frames reaches to 1/4th of threshold, rx_packet_drop_counter: %d", + mac_ctx->rx_packet_drop_counter); + mac_ctx->rx_packet_drop_counter++; + } + return QDF_STATUS_SUCCESS; +} + +/** + * pe_is_ext_scan_bcn_probe_rsp - Check if the beacon or probe response + * is from Ext or EPNO scan + * + * @hdr: pointer to the 802.11 header of the frame + * @rx_pkt_info: pointer to the rx packet meta + * + * Checks if the beacon or probe response is from Ext Scan or EPNO scan + * + * Return: true or false + */ +#ifdef FEATURE_WLAN_EXTSCAN +static inline bool pe_is_ext_scan_bcn_probe_rsp(tpSirMacMgmtHdr hdr, + uint8_t *rx_pkt_info) +{ + if ((hdr->fc.subType == SIR_MAC_MGMT_BEACON || + hdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) && + (WMA_IS_EXTSCAN_SCAN_SRC(rx_pkt_info) || + WMA_IS_EPNO_SCAN_SRC(rx_pkt_info))) + return true; + + return false; +} +#else +static inline bool pe_is_ext_scan_bcn_probe_rsp(tpSirMacMgmtHdr hdr, + uint8_t *rx_pkt_info) +{ + return false; +} +#endif + +/** + * pe_filter_drop_bcn_probe_frame - Apply filter on the received frame + * + * @mac_ctx: pointer to the global mac context + * @hdr: pointer to the 802.11 header of the frame + * @rx_pkt_info: pointer to the rx packet meta + * + * Applies the filter from global mac context on the received beacon/ + * probe response frame before posting it to the PE queue + * + * Return: true if frame is allowed, false if frame is to be dropped. + */ +static bool pe_filter_bcn_probe_frame(struct mac_context *mac_ctx, + tpSirMacMgmtHdr hdr, + uint8_t *rx_pkt_info) +{ + uint8_t session_id; + struct mgmt_beacon_probe_filter *filter; + + if (pe_is_ext_scan_bcn_probe_rsp(hdr, rx_pkt_info)) + return true; + + filter = &mac_ctx->bcn_filter; + + /* + * If any STA session exists and beacon source matches any of the + * STA BSSIDs, allow the frame + */ + if (filter->num_sta_sessions) { + for (session_id = 0; session_id < WLAN_MAX_VDEVS; + session_id++) { + if (sir_compare_mac_addr(filter->sta_bssid[session_id], + hdr->bssId)) { + return true; + } + } + } + + return false; +} + +static QDF_STATUS pe_handle_probe_req_frames(struct mac_context *mac_ctx, + cds_pkt_t *pkt) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + uint32_t scan_queue_size = 0; + + /* Check if the probe request frame can be posted in the scan queue */ + status = scheduler_get_queue_size(QDF_MODULE_ID_SCAN, &scan_queue_size); + if (!QDF_IS_STATUS_SUCCESS(status) || + scan_queue_size > MAX_BCN_PROBE_IN_SCAN_QUEUE) { + pe_debug_rl("Dropping probe req frame, queue size %d", + scan_queue_size); + return QDF_STATUS_E_FAILURE; + } + + /* Forward to MAC via mesg = SIR_BB_XPORT_MGMT_MSG */ + msg.type = SIR_BB_XPORT_MGMT_MSG; + msg.bodyptr = pkt; + msg.bodyval = 0; + msg.callback = pe_mc_process_handler; + + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_SCAN, &msg); + + return status; +} + +/* --------------------------------------------------------------------------- */ +/** + * pe_handle_mgmt_frame() - Process the Management frames from TXRX + * @psoc: psoc context + * @peer: peer + * @buf: buffer + * @mgmt_rx_params; rx event params + * @frm_type: frame type + * + * This function handles the mgmt rx frame from mgmt txrx component and forms + * a cds packet and schedule it in controller thread for further processing. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +static QDF_STATUS pe_handle_mgmt_frame(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + enum mgmt_frame_type frm_type) +{ + struct mac_context *mac; + tpSirMacMgmtHdr mHdr; + struct scheduler_msg msg = {0}; + cds_pkt_t *pVosPkt; + QDF_STATUS qdf_status; + uint8_t *pRxPacketInfo; + int ret; + + /* skip offload packets */ + if ((ucfg_pkt_capture_get_mode(psoc) != PACKET_CAPTURE_MODE_DISABLE) && + mgmt_rx_params->status & WMI_RX_OFFLOAD_MON_MODE) { + qdf_nbuf_free(buf); + return QDF_STATUS_SUCCESS; + } + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + /* cannot log a failure without a valid mac */ + qdf_nbuf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + if (mac->usr_cfg_disable_rsp_tx) { + pe_debug("Drop Rx pkt with user config"); + qdf_nbuf_free(buf); + return QDF_STATUS_SUCCESS; + } + pVosPkt = qdf_mem_malloc_atomic(sizeof(*pVosPkt)); + if (!pVosPkt) { + qdf_nbuf_free(buf); + return QDF_STATUS_E_NOMEM; + } + + ret = wma_form_rx_packet(buf, mgmt_rx_params, pVosPkt); + if (ret) { + pe_debug_rl("Failed to fill cds packet from event buffer"); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = + wma_ds_peek_rx_packet_info(pVosPkt, (void *)&pRxPacketInfo); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + return QDF_STATUS_E_FAILURE; + } + + /* + * The MPDU header is now present at a certain "offset" in + * the BD and is specified in the BD itself + */ + + mHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + /* + * Filter the beacon/probe response frames before posting it + * on the PE queue + */ + if ((mHdr->fc.subType == SIR_MAC_MGMT_BEACON || + mHdr->fc.subType == SIR_MAC_MGMT_PROBE_RSP) && + !pe_filter_bcn_probe_frame(mac, mHdr, pRxPacketInfo)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + return QDF_STATUS_SUCCESS; + } + + /* + * Post Probe Req frames to Scan queue and return + */ + if (mHdr->fc.subType == SIR_MAC_MGMT_PROBE_REQ) { + qdf_status = pe_handle_probe_req_frames(mac, pVosPkt); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + } + return qdf_status; + } + + if (QDF_STATUS_SUCCESS != + pe_drop_pending_rx_mgmt_frames(mac, mHdr, pVosPkt)) + return QDF_STATUS_E_FAILURE; + + /* Forward to MAC via mesg = SIR_BB_XPORT_MGMT_MSG */ + msg.type = SIR_BB_XPORT_MGMT_MSG; + msg.bodyptr = pVosPkt; + msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != sys_bbt_process_message_core(mac, + &msg, + mHdr->fc.type, + mHdr->fc.subType)) { + cds_pkt_return_packet(pVosPkt); + pVosPkt = NULL; + /* + * Decrement sys_bbt_pending_mgmt_count if packet + * is dropped before posting to LIM + */ + lim_decrement_pending_mgmt_count(mac); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void pe_register_mgmt_rx_frm_callback(struct mac_context *mac_ctx) +{ + QDF_STATUS status; + struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info; + + frm_cb_info.frm_type = MGMT_FRAME_TYPE_ALL; + frm_cb_info.mgmt_rx_cb = pe_handle_mgmt_frame; + + status = wlan_mgmt_txrx_register_rx_cb(mac_ctx->psoc, + WLAN_UMAC_COMP_MLME, &frm_cb_info, 1); + if (status != QDF_STATUS_SUCCESS) + pe_err("Registering the PE Handle with MGMT TXRX layer has failed"); + + wma_register_mgmt_frm_client(); +} + +void pe_deregister_mgmt_rx_frm_callback(struct mac_context *mac_ctx) +{ + QDF_STATUS status; + struct mgmt_txrx_mgmt_frame_cb_info frm_cb_info; + + frm_cb_info.frm_type = MGMT_FRAME_TYPE_ALL; + frm_cb_info.mgmt_rx_cb = pe_handle_mgmt_frame; + + status = wlan_mgmt_txrx_deregister_rx_cb(mac_ctx->psoc, + WLAN_UMAC_COMP_MLME, &frm_cb_info, 1); + if (status != QDF_STATUS_SUCCESS) + pe_err("Deregistering the PE Handle with MGMT TXRX layer has failed"); + + wma_de_register_mgmt_frm_client(); +} + + +/** + * pe_register_callbacks_with_wma() - register SME and PE callback functions to + * WMA. + * (function documentation in lim_api.h) + */ +void pe_register_callbacks_with_wma(struct mac_context *mac, + struct sme_ready_req *ready_req) +{ + QDF_STATUS status; + + status = wma_register_roaming_callbacks( + ready_req->csr_roam_auth_event_handle_cb, + ready_req->pe_roam_synch_cb, + ready_req->pe_disconnect_cb, + ready_req->pe_roam_set_ie_cb); + if (status != QDF_STATUS_SUCCESS) + pe_err("Registering roaming callbacks with WMA failed"); +} + +void +lim_received_hb_handler(struct mac_context *mac, uint32_t chan_freq, + struct pe_session *pe_session) +{ + if (chan_freq == 0 || chan_freq == pe_session->curr_op_freq) + pe_session->LimRxedBeaconCntDuringHB++; + + pe_session->pmmOffloadInfo.bcnmiss = false; +} /*** lim_init_wds_info_params() ***/ + +/** ------------------------------------------------------------- + \fn lim_update_overlap_sta_param + \brief Updates overlap cache and param data structure + \param struct mac_context * mac + \param tSirMacAddr bssId + \param tpLimProtStaParams pStaParams + \return None + -------------------------------------------------------------*/ +void +lim_update_overlap_sta_param(struct mac_context *mac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams) +{ + int i; + + if (!pStaParams->numSta) { + qdf_mem_copy(mac->lim.protStaOverlapCache[0].addr, + bssId, sizeof(tSirMacAddr)); + mac->lim.protStaOverlapCache[0].active = true; + + pStaParams->numSta = 1; + + return; + } + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) { + if (mac->lim.protStaOverlapCache[i].active) { + if (!qdf_mem_cmp + (mac->lim.protStaOverlapCache[i].addr, bssId, + sizeof(tSirMacAddr))) { + return; + } + } else + break; + } + + if (i == LIM_PROT_STA_OVERLAP_CACHE_SIZE) { + pe_debug("Overlap cache is full"); + } else { + qdf_mem_copy(mac->lim.protStaOverlapCache[i].addr, + bssId, sizeof(tSirMacAddr)); + mac->lim.protStaOverlapCache[i].active = true; + + pStaParams->numSta++; + } +} + +/** + * lim_enc_type_matched() - matches security type of incoming beracon with + * current + * @mac_ctx Pointer to Global MAC structure + * @bcn Pointer to parsed Beacon structure + * @session PE session entry + * + * This function matches security type of incoming beracon with current + * + * @return true if matched, false otherwise + */ +static bool +lim_enc_type_matched(struct mac_context *mac_ctx, + tpSchBeaconStruct bcn, + struct pe_session *session) +{ + if (!bcn || !session) + return false; + + /* + * This is handled by sending probe req due to IOT issues so + * return TRUE + */ + if ((bcn->capabilityInfo.privacy) != + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps)) { + pe_warn("Privacy bit miss match"); + return true; + } + + /* Open */ + if ((bcn->capabilityInfo.privacy == 0) && + (session->encryptType == eSIR_ED_NONE)) + return true; + + /* WEP */ + if ((bcn->capabilityInfo.privacy == 1) && + (bcn->wpaPresent == 0) && (bcn->rsnPresent == 0) && + ((session->encryptType == eSIR_ED_WEP40) || + (session->encryptType == eSIR_ED_WEP104) +#ifdef FEATURE_WLAN_WAPI + || (session->encryptType == eSIR_ED_WPI) +#endif + )) + return true; + + /* WPA OR RSN*/ + if ((bcn->capabilityInfo.privacy == 1) && + ((bcn->wpaPresent == 1) || (bcn->rsnPresent == 1)) && + ((session->encryptType == eSIR_ED_TKIP) || + (session->encryptType == eSIR_ED_CCMP) || + (session->encryptType == eSIR_ED_GCMP) || + (session->encryptType == eSIR_ED_GCMP_256) || + (session->encryptType == eSIR_ED_AES_128_CMAC))) + return true; + + /* + * For HS2.0, RSN ie is not present + * in beacon. Therefore no need to + * check for security type in case + * OSEN session. + * For WPS registration session no need to detect + * detect security mismatch as it won't match and + * driver may end up sending probe request without + * WPS IE during WPS registration process. + */ + if (session->isOSENConnection || + session->wps_registration) + return true; + + pe_debug("AP:: Privacy %d WPA %d RSN %d, SELF:: Privacy %d Enc %d OSEN %d WPS %d", + bcn->capabilityInfo.privacy, bcn->wpaPresent, bcn->rsnPresent, + SIR_MAC_GET_PRIVACY(session->limCurrentBssCaps), + session->encryptType, session->isOSENConnection, + session->wps_registration); + + return false; +} + +void +lim_detect_change_in_ap_capabilities(struct mac_context *mac, + tpSirProbeRespBeacon pBeacon, + struct pe_session *pe_session, + bool is_bcn) +{ + uint8_t len; + uint32_t new_chan_freq; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool security_caps_matched = true; + uint16_t ap_cap; + + ap_cap = lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + new_chan_freq = pBeacon->chan_freq; + + security_caps_matched = lim_enc_type_matched(mac, pBeacon, + pe_session); + if ((false == pe_session->limSentCapsChangeNtf) && + (((!lim_is_null_ssid(&pBeacon->ssId)) && + lim_cmp_ssid(&pBeacon->ssId, pe_session)) || + ((SIR_MAC_GET_ESS(ap_cap) != + SIR_MAC_GET_ESS(pe_session->limCurrentBssCaps)) || + (SIR_MAC_GET_PRIVACY(ap_cap) != + SIR_MAC_GET_PRIVACY(pe_session->limCurrentBssCaps)) || + (SIR_MAC_GET_QOS(ap_cap) != + SIR_MAC_GET_QOS(pe_session->limCurrentBssCaps)) || + ((new_chan_freq != pe_session->curr_op_freq) && + (new_chan_freq != 0)) || + (false == security_caps_matched) + ))) { + if (!pe_session->fWaitForProbeRsp || is_bcn) { + /* If Beacon capabilities is not matching with the current capability, + * then send unicast probe request to AP and take decision after + * receiving probe response */ + if (pe_session->fIgnoreCapsChange) { + pe_debug_rl("Ignore the Capability change as probe rsp Capability matched"); + return; + } + pe_session->fWaitForProbeRsp = true; + pe_info(QDF_MAC_ADDR_FMT ": capabilities are not matching, sending directed probe request", + QDF_MAC_ADDR_REF(pe_session->bssId)); + status = + lim_send_probe_req_mgmt_frame( + mac, &pe_session->ssId, + pe_session->bssId, + pe_session->curr_op_freq, + pe_session->self_mac_addr, + pe_session->dot11mode, + NULL, NULL); + + if (QDF_STATUS_SUCCESS != status) { + pe_err("send ProbeReq failed"); + pe_session->fWaitForProbeRsp = false; + } + return; + } + /** + * BSS capabilities have changed. + * Inform Roaming. + */ + len = sizeof(tSirMacCapabilityInfo) + sizeof(tSirMacAddr) + sizeof(uint8_t) + 3 * sizeof(uint8_t) + /* reserved fields */ + pBeacon->ssId.length + 1; + + if (new_chan_freq != pe_session->curr_op_freq) { + pe_info(QDF_MAC_ADDR_FMT ": Channel freq Change from %d --> %d Ignoring beacon!", + QDF_MAC_ADDR_REF(pe_session->bssId), + pe_session->curr_op_freq, new_chan_freq); + return; + } + + /** + * When Cisco 1262 Enterprise APs are configured with WPA2-PSK with + * AES+TKIP Pairwise ciphers and WEP-40 Group cipher, they do not set + * the privacy bit in Beacons (wpa/rsnie is still present in beacons), + * the privacy bit is set in Probe and association responses. + * Due to this anomaly, we detect a change in + * AP capabilities when we receive a beacon after association and + * disconnect from the AP. The following check makes sure that we can + * connect to such APs + */ + else if ((SIR_MAC_GET_PRIVACY(ap_cap) == 0) && + (pBeacon->rsnPresent || pBeacon->wpaPresent)) { + pe_info_rl(QDF_MAC_ADDR_FMT ": BSS Caps (Privacy) bit 0 in beacon, but WPA or RSN IE present, Ignore Beacon!", + QDF_MAC_ADDR_REF(pe_session->bssId)); + return; + } + + pe_session->fIgnoreCapsChange = false; + pe_session->fWaitForProbeRsp = false; + pe_session->limSentCapsChangeNtf = true; + pe_info(QDF_MAC_ADDR_FMT ": initiate Disconnect due to cap mismatch!", + QDF_MAC_ADDR_REF(pe_session->bssId)); + lim_send_deauth_mgmt_frame(mac, REASON_UNSPEC_FAILURE, + pe_session->bssId, pe_session, + false); + lim_tear_down_link_with_ap(mac, pe_session->peSessionId, + REASON_UNSPEC_FAILURE, + eLIM_HOST_DISASSOC); + } else if (pe_session->fWaitForProbeRsp) { + /* Only for probe response frames and matching capabilities the control + * will come here. If beacon is with broadcast ssid then fWaitForProbeRsp + * will be false, the control will not come here*/ + + pe_debug(QDF_MAC_ADDR_FMT ": capabilities in probe rsp are matching, so ignoring capability mismatch", + QDF_MAC_ADDR_REF(pe_session->bssId)); + pe_session->fIgnoreCapsChange = true; + pe_session->fWaitForProbeRsp = false; + } + +} /*** lim_detect_change_in_ap_capabilities() ***/ + +/* --------------------------------------------------------------------- */ +/** + * lim_update_short_slot + * + * FUNCTION: + * Enable/Disable short slot + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param enable Flag to enable/disable short slot + * @return None + */ + +QDF_STATUS lim_update_short_slot(struct mac_context *mac, + tpSirProbeRespBeacon pBeacon, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + + uint16_t ap_cap; + uint32_t nShortSlot; + uint32_t phyMode; + + /* Check Admin mode first. If it is disabled just return */ + if (!mac->mlme_cfg->feature_flags.enable_short_slot_time_11g) + return QDF_STATUS_SUCCESS; + + /* Check for 11a mode or 11b mode. In both cases return since slot time is constant and cannot/should not change in beacon */ + lim_get_phy_mode(mac, &phyMode, pe_session); + if ((phyMode == WNI_CFG_PHY_MODE_11A) + || (phyMode == WNI_CFG_PHY_MODE_11B)) + return QDF_STATUS_SUCCESS; + + ap_cap = lim_get_u16((uint8_t *) &pBeacon->capabilityInfo); + + /* Earlier implementation: determine the appropriate short slot mode based on AP advertised modes */ + /* when erp is present, apply short slot always unless, prot=on && shortSlot=off */ + /* if no erp present, use short slot based on current ap caps */ + + /* Issue with earlier implementation : Cisco 1231 BG has shortSlot = 0, erpIEPresent and useProtection = 0 (Case4); */ + + /* Resolution : always use the shortSlot setting the capability info to decide slot time. */ + /* The difference between the earlier implementation and the new one is only Case4. */ + /* + ERP IE Present | useProtection | shortSlot = QC STA Short Slot + Case1 1 1 1 1 //AP should not advertise this combination. + Case2 1 1 0 0 + Case3 1 0 1 1 + Case4 1 0 0 0 + Case5 0 1 1 1 + Case6 0 1 0 0 + Case7 0 0 1 1 + Case8 0 0 0 0 + */ + nShortSlot = SIR_MAC_GET_SHORT_SLOT_TIME(ap_cap); + + if (nShortSlot != pe_session->shortSlotTimeSupported) { + /* Short slot time capability of AP has changed. Adopt to it. */ + pe_debug("Shortslot capability of AP changed: %d", + nShortSlot); + ((tpSirMacCapabilityInfo) & pe_session-> + limCurrentBssCaps)->shortSlotTime = (uint16_t) nShortSlot; + pe_session->shortSlotTimeSupported = nShortSlot; + pBeaconParams->fShortSlotTime = (uint8_t) nShortSlot; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + } + return QDF_STATUS_SUCCESS; +} + + +void lim_send_heart_beat_timeout_ind(struct mac_context *mac, + struct pe_session *pe_session) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + + /* Prepare and post message to LIM Message Queue */ + msg.type = (uint16_t) SIR_LIM_HEART_BEAT_TIMEOUT; + msg.bodyptr = pe_session; + msg.bodyval = 0; + pe_err("Heartbeat failure from Fw"); + + status = lim_post_msg_api(mac, &msg); + + if (status != QDF_STATUS_SUCCESS) { + pe_err("posting message: %X to LIM failed, reason: %d", + msg.type, status); + } +} + +void lim_ps_offload_handle_missed_beacon_ind(struct mac_context *mac, + struct scheduler_msg *msg) +{ + struct missed_beacon_ind *missed_beacon_ind = msg->bodyptr; + struct pe_session *pe_session = + pe_find_session_by_vdev_id(mac, missed_beacon_ind->bss_idx); + + if (!pe_session) { + pe_err("session does not exist for vdev_id %d", + missed_beacon_ind->bss_idx); + return; + } + + /* Set Beacon Miss in Powersave Offload */ + pe_session->pmmOffloadInfo.bcnmiss = true; + pe_err("Received Heart Beat Failure"); + + /* Do AP probing immediately */ + lim_send_heart_beat_timeout_ind(mac, pe_session); +} + +bool lim_is_sb_disconnect_allowed_fl(struct pe_session *session, + const char *func, uint32_t line) +{ + if (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE && + session->limSmeState != eLIM_SME_WT_DISASSOC_STATE && + session->limSmeState != eLIM_SME_WT_DEAUTH_STATE) + return true; + + pe_nofl_info("%s:%u: Vdev %d (%d): limMlmState %s(%x) limSmeState %s(%x)", + func, line, session->vdev_id, session->peSessionId, + lim_mlm_state_str(session->limMlmState), + session->limMlmState, + lim_sme_state_str(session->limSmeState), + session->limSmeState); + + return false; +} + +#ifdef WLAN_SUPPORT_TWT +#ifdef WLAN_TWT_CONV_SUPPORTED +void lim_set_twt_peer_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + tDot11fIEhe_cap *he_cap, + tDot11fIEhe_op *he_op) +{ + uint8_t caps = 0; + + if (he_cap->twt_request) + caps |= WLAN_TWT_CAPA_REQUESTOR; + + if (he_cap->twt_responder) + caps |= WLAN_TWT_CAPA_RESPONDER; + + if (he_cap->broadcast_twt) + caps |= WLAN_TWT_CAPA_BROADCAST; + + if (he_cap->flex_twt_sched) + caps |= WLAN_TWT_CAPA_FLEXIBLE; + + if (he_op->twt_required) + caps |= WLAN_TWT_CAPA_REQUIRED; + + wlan_set_peer_twt_capabilities(mac_ctx->psoc, peer_mac, caps); +} + +void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + struct s_ext_cap *ext_cap) +{ + uint8_t caps = 0; + + if (ext_cap->twt_requestor_support) + caps |= WLAN_TWT_CAPA_REQUESTOR; + + if (ext_cap->twt_responder_support) + caps |= WLAN_TWT_CAPA_RESPONDER; + + wlan_set_peer_twt_capabilities(mac_ctx->psoc, peer_mac, caps); +} +#else +void lim_set_twt_peer_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + tDot11fIEhe_cap *he_cap, + tDot11fIEhe_op *he_op) +{ + uint8_t caps = 0; + + if (he_cap->twt_request) + caps |= WLAN_TWT_CAPA_REQUESTOR; + + if (he_cap->twt_responder) + caps |= WLAN_TWT_CAPA_RESPONDER; + + if (he_cap->broadcast_twt) + caps |= WLAN_TWT_CAPA_BROADCAST; + + if (he_cap->flex_twt_sched) + caps |= WLAN_TWT_CAPA_FLEXIBLE; + + if (he_op->twt_required) + caps |= WLAN_TWT_CAPA_REQUIRED; + + mlme_set_twt_peer_capabilities(mac_ctx->psoc, peer_mac, + caps); +} + +void lim_set_twt_ext_capabilities(struct mac_context *mac_ctx, + struct qdf_mac_addr *peer_mac, + struct s_ext_cap *ext_cap) +{ + uint8_t caps = 0; + + if (ext_cap->twt_requestor_support) + caps |= WLAN_TWT_CAPA_REQUESTOR; + + if (ext_cap->twt_responder_support) + caps |= WLAN_TWT_CAPA_RESPONDER; + + mlme_set_twt_peer_capabilities(mac_ctx->psoc, peer_mac, caps); +} +#endif /* WLAN_TWT_CONV_SUPPORTED */ +#endif /* WLAN_SUPPORT_TWT */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void pe_update_crypto_params(struct mac_context *mac_ctx, + struct pe_session *ft_session, + struct roam_offload_synch_ind *roam_synch) +{ + uint8_t *assoc_ies; + uint32_t assoc_ies_len; + uint8_t ies_offset = WLAN_REASSOC_REQ_IES_OFFSET; + tpSirMacMgmtHdr hdr; + const uint8_t *wpa_ie, *rsn_ie; + uint32_t wpa_oui; + struct wlan_crypto_params *crypto_params; + + hdr = (tpSirMacMgmtHdr)((uint8_t *)roam_synch + + roam_synch->reassoc_req_offset); + if (hdr->fc.type == SIR_MAC_MGMT_FRAME && + hdr->fc.subType == SIR_MAC_MGMT_ASSOC_REQ) + ies_offset = WLAN_ASSOC_REQ_IES_OFFSET; + + if (roam_synch->reassoc_req_length < + (sizeof(tSirMacMgmtHdr) + ies_offset)) { + pe_err("invalid reassoc req len %d", + roam_synch->reassoc_req_length); + return; + } + + ft_session->limRmfEnabled = false; + + assoc_ies = (uint8_t *)roam_synch + roam_synch->reassoc_req_offset + + sizeof(tSirMacMgmtHdr) + ies_offset; + assoc_ies_len = roam_synch->reassoc_req_length - + sizeof(tSirMacMgmtHdr) - ies_offset; + + rsn_ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSN, assoc_ies, + assoc_ies_len); + wpa_oui = WLAN_WPA_SEL(WLAN_WPA_OUI_TYPE); + wpa_ie = wlan_get_vendor_ie_ptr_from_oui((uint8_t *)&wpa_oui, + WLAN_OUI_SIZE, assoc_ies, + assoc_ies_len); + if (!wpa_ie && !rsn_ie) { + pe_nofl_debug("RSN and WPA IE not present"); + return; + } + + wlan_set_vdev_crypto_prarams_from_ie(ft_session->vdev, assoc_ies, + assoc_ies_len); + ft_session->limRmfEnabled = + lim_get_vdev_rmf_capable(mac_ctx, ft_session); + crypto_params = wlan_crypto_vdev_get_crypto_params(ft_session->vdev); + if (!crypto_params) { + pe_err("crypto params is null"); + return; + } + + ft_session->connected_akm = + lim_get_connected_akm(ft_session, crypto_params->ucastcipherset, + crypto_params->authmodeset, + crypto_params->key_mgmt); + ft_session->encryptType = + lim_get_encrypt_ed_type(crypto_params->ucastcipherset); + pe_nofl_debug("vdev %d roam auth 0x%x akm 0x%0x rsn_caps 0x%x ucastcipher 0x%x akm %d enc: %d", + ft_session->vdev_id, + crypto_params->authmodeset, + crypto_params->key_mgmt, + crypto_params->rsn_caps, + crypto_params->ucastcipherset, + ft_session->connected_akm, + ft_session->encryptType); +} + +/** + * sir_parse_bcn_fixed_fields() - Parse fixed fields in Beacon IE's + * + * @mac_ctx: MAC Context + * @beacon_struct: Beacon/Probe Response structure + * @buf: Fixed Fields buffer + */ +static void sir_parse_bcn_fixed_fields(struct mac_context *mac_ctx, + tpSirProbeRespBeacon beacon_struct, + uint8_t *buf) +{ + tDot11fFfCapabilities dst; + + beacon_struct->timeStamp[0] = lim_get_u32(buf); + beacon_struct->timeStamp[1] = lim_get_u32(buf + 4); + buf += 8; + + beacon_struct->beaconInterval = lim_get_u16(buf); + buf += 2; + + dot11f_unpack_ff_capabilities(mac_ctx, buf, &dst); + + sir_copy_caps_info(mac_ctx, dst, beacon_struct); +} + +static QDF_STATUS +lim_roam_gen_mbssid_beacon(struct mac_context *mac, + struct roam_offload_synch_ind *roam_ind, + tpSirProbeRespBeacon parsed_frm, + uint8_t **ie, uint32_t *ie_len) +{ + qdf_list_t *scan_list; + struct mgmt_rx_event_params rx_param = {0}; + uint8_t list_count = 0, i; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + qdf_list_node_t *next_node = NULL, *cur_node = NULL; + struct scan_cache_node *scan_node; + struct scan_cache_entry *scan_entry; + uint8_t *bcn_prb_ptr; + uint32_t nontx_bcn_prbrsp_len = 0, offset, length; + uint8_t *nontx_bcn_prbrsp = NULL; + uint8_t ie_offset; + + ie_offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET; + bcn_prb_ptr = (uint8_t *)roam_ind + + roam_ind->beacon_probe_resp_offset; + + rx_param.chan_freq = roam_ind->chan_freq; + rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(mac->pdev); + rx_param.rssi = roam_ind->rssi; + + /* Set all per chain rssi as invalid */ + for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) + rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI; + + scan_list = util_scan_unpack_beacon_frame(mac->pdev, bcn_prb_ptr, + roam_ind->beacon_probe_resp_length, + MGMT_SUBTYPE_BEACON, &rx_param); + if (!scan_list) { + pe_err("failed to parse"); + return QDF_STATUS_E_FAILURE; + } + + list_count = qdf_list_size(scan_list); + status = qdf_list_peek_front(scan_list, &cur_node); + if (QDF_IS_STATUS_ERROR(status) || !cur_node) { + pe_debug("list peek front failure. list size %d", list_count); + goto error; + } + + for (i = 1; i < list_count; i++) { + scan_node = qdf_container_of(cur_node, + struct scan_cache_node, node); + scan_entry = scan_node->entry; + if (qdf_is_macaddr_equal(&roam_ind->bssid, + &scan_entry->bssid)) { + pe_debug("matched BSSID "QDF_MAC_ADDR_FMT" bcn len %d profiles %d", + QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), + scan_entry->raw_frame.len, + list_count); + nontx_bcn_prbrsp = scan_entry->raw_frame.ptr; + nontx_bcn_prbrsp_len = scan_entry->raw_frame.len; + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + scan_entry->raw_frame.ptr, + nontx_bcn_prbrsp_len); + break; + } + status = qdf_list_peek_next(scan_list, cur_node, &next_node); + if (QDF_IS_STATUS_ERROR(status) || !next_node) { + pe_debug("list remove failure i:%d, lsize:%d", + i, list_count); + goto error; + } + cur_node = next_node; + } + + if (!nontx_bcn_prbrsp_len) { + pe_debug("failed to generate/find MBSSID beacon"); + goto error; + } + + if (roam_ind->is_beacon) { + offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET; + length = nontx_bcn_prbrsp_len - SIR_MAC_HDR_LEN_3A; + if (sir_parse_beacon_ie(mac, parsed_frm, + &nontx_bcn_prbrsp[offset], + length) != QDF_STATUS_SUCCESS || + !parsed_frm->ssidPresent) { + pe_err("Parse error Beacon, length: %d", + roam_ind->beacon_probe_resp_length); + status = QDF_STATUS_E_FAILURE; + goto error; + } + } else { + offset = SIR_MAC_HDR_LEN_3A; + length = nontx_bcn_prbrsp_len - SIR_MAC_HDR_LEN_3A; + if (sir_convert_probe_frame2_struct(mac, + &nontx_bcn_prbrsp[offset], + length, + parsed_frm) != QDF_STATUS_SUCCESS || + !parsed_frm->ssidPresent) { + pe_err("Parse error ProbeResponse, length: %d", + roam_ind->beacon_probe_resp_length); + status = QDF_STATUS_E_FAILURE; + goto error; + } + } + + *ie_len = nontx_bcn_prbrsp_len - ie_offset; + if (*ie_len) { + *ie = qdf_mem_malloc(*ie_len); + if (!*ie) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(*ie, nontx_bcn_prbrsp + ie_offset, *ie_len); + pe_debug("beacon/probe Ie length: %d", *ie_len); + } +error: + for (i = 0; i < list_count; i++) { + status = qdf_list_remove_front(scan_list, &next_node); + if (QDF_IS_STATUS_ERROR(status) || !next_node) { + pe_debug("list remove failure i:%d, lsize:%d", + i, list_count); + break; + } + scan_node = qdf_container_of(next_node, + struct scan_cache_node, node); + util_scan_free_cache_entry(scan_node->entry); + qdf_mem_free(scan_node); + } + qdf_mem_free(scan_list); + + return status; +} + +static QDF_STATUS +lim_roam_gen_beacon_descr(struct mac_context *mac, + uint8_t *bcn_prb_ptr, + uint16_t bcn_prb_len, bool is_mlo_link, + struct roam_offload_synch_ind *roam_ind, + tpSirProbeRespBeacon parsed_frm, + uint8_t **ie, uint32_t *ie_len, + struct qdf_mac_addr *bssid) +{ + QDF_STATUS status; + tpSirMacMgmtHdr mac_hdr; + uint8_t ie_offset; + bool is_beacon; + + mac_hdr = (tpSirMacMgmtHdr)bcn_prb_ptr; + ie_offset = SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET; + + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)mac_hdr->bssId)) { + pe_debug("bssid is 0 in beacon/probe update it with bssId" + QDF_MAC_ADDR_FMT "in sync ind", + QDF_MAC_ADDR_REF(bssid->bytes)); + qdf_mem_copy(mac_hdr->bssId, bssid->bytes, + sizeof(tSirMacAddr)); + } + + is_beacon = is_mlo_link ? roam_ind->is_link_beacon : roam_ind->is_beacon; + + if ((!is_multi_link_roam(roam_ind)) && + (qdf_mem_cmp(bssid->bytes, + &mac_hdr->bssId, QDF_MAC_ADDR_SIZE) != 0)) { + pe_debug("LFR3:MBSSID Beacon/Prb Rsp: %d bssid " + QDF_MAC_ADDR_FMT, + roam_ind->is_beacon, + QDF_MAC_ADDR_REF(mac_hdr->bssId)); + /* + * Its a MBSSID non-tx BSS roaming scenario. + * Generate non tx BSS beacon/probe response + */ + status = lim_roam_gen_mbssid_beacon(mac, + roam_ind, + parsed_frm, + ie, ie_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to gen mbssid beacon"); + return QDF_STATUS_E_FAILURE; + } + } else { + if (is_beacon) { + if (sir_parse_beacon_ie(mac, parsed_frm, + &bcn_prb_ptr[SIR_MAC_HDR_LEN_3A + + SIR_MAC_B_PR_SSID_OFFSET], + bcn_prb_len - SIR_MAC_HDR_LEN_3A) != + QDF_STATUS_SUCCESS || + !parsed_frm->ssidPresent) { + pe_err("Parse error Beacon, length: %d", + bcn_prb_len); + return QDF_STATUS_E_FAILURE; + } + } else { + if (sir_convert_probe_frame2_struct(mac, + &bcn_prb_ptr[SIR_MAC_HDR_LEN_3A], + bcn_prb_len - + SIR_MAC_HDR_LEN_3A, parsed_frm) != + QDF_STATUS_SUCCESS || + !parsed_frm->ssidPresent) { + pe_err("Parse error ProbeResponse, length: %d", + bcn_prb_len); + return QDF_STATUS_E_FAILURE; + } + } + /* 24 byte MAC header and 12 byte to ssid IE */ + if (bcn_prb_len > ie_offset) { + *ie_len = bcn_prb_len - ie_offset; + *ie = qdf_mem_malloc(*ie_len); + if (!*ie) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(*ie, bcn_prb_ptr + ie_offset, *ie_len); + pe_debug("beacon/probe Ie length: %d", *ie_len); + } + } + /* + * For probe response, unpack core parses beacon interval, capabilities, + * timestamp. For beacon IEs, these fields are not parsed. + */ + if (is_beacon) + sir_parse_bcn_fixed_fields(mac, parsed_frm, + &bcn_prb_ptr[SIR_MAC_HDR_LEN_3A]); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_roam_fill_bss_descr(struct mac_context *mac, + struct roam_offload_synch_ind *roam_synch_ind, + struct bss_description *bss_desc_ptr, + struct pe_session *session) +{ + uint32_t ie_len = 0; + tpSirProbeRespBeacon parsed_frm_ptr = NULL; + tpSirMacMgmtHdr mac_hdr; + uint8_t *bcn_proberesp_ptr = NULL; + uint16_t bcn_proberesp_len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t *ie = NULL; + struct qdf_mac_addr bssid; + bool is_mlo_link; + uint8_t vdev_id = session->vdev_id; + struct element_info frame; + struct cm_roam_values_copy mdie_cfg = {0}; + + bcn_proberesp_ptr = (uint8_t *)roam_synch_ind + + roam_synch_ind->beacon_probe_resp_offset; + bcn_proberesp_len = roam_synch_ind->beacon_probe_resp_length; + + frame.ptr = NULL; + frame.len = 0; + if (is_multi_link_roam(roam_synch_ind)) { + mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind, &bssid); + is_mlo_link = wlan_vdev_mlme_get_is_mlo_link(mac->psoc, vdev_id); + + status = wlan_scan_get_entry_by_mac_addr(mac->pdev, &bssid, + &frame); + if (QDF_IS_STATUS_ERROR(status) || !frame.len) { + pe_err("Failed to get scan entry for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + return status; + } + bcn_proberesp_ptr = frame.ptr; + bcn_proberesp_len = frame.len; + } else { + bssid = roam_synch_ind->bssid; + is_mlo_link = false; + } + + mac_hdr = (tpSirMacMgmtHdr)bcn_proberesp_ptr; + parsed_frm_ptr = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (!parsed_frm_ptr) { + status = QDF_STATUS_E_NOMEM; + goto done; + } + + if (bcn_proberesp_len <= SIR_MAC_HDR_LEN_3A) { + pe_err("very few bytes in synchInd %s beacon / probe resp frame! length: %d", + is_mlo_link ? "link" : "", bcn_proberesp_len); + status = QDF_STATUS_E_FAILURE; + goto done; + } + + pe_debug("LFR3:Beacon/Prb Rsp: %d bssid " QDF_MAC_ADDR_FMT + " beacon " QDF_MAC_ADDR_FMT, + is_mlo_link ? roam_synch_ind->is_link_beacon : + roam_synch_ind->is_beacon, + QDF_MAC_ADDR_REF(bssid.bytes), + QDF_MAC_ADDR_REF(mac_hdr->bssId)); + mgmt_txrx_frame_hex_dump(bcn_proberesp_ptr, bcn_proberesp_len, false); + + status = lim_roam_gen_beacon_descr(mac, bcn_proberesp_ptr, + bcn_proberesp_len, is_mlo_link, + roam_synch_ind, parsed_frm_ptr, + &ie, &ie_len, + &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to parse beacon"); + status = QDF_STATUS_E_FAILURE; + goto done; + } + + /* + * Length of BSS description is without length of + * length itself and length of pointer + * that holds ieFields + * + * struct bss_description + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + bss_desc_ptr->length = (uint16_t) (offsetof(struct bss_description, + ieFields[0]) - + sizeof(bss_desc_ptr->length) + ie_len); + + bss_desc_ptr->fProbeRsp = !(is_mlo_link ? + roam_synch_ind->is_link_beacon : + roam_synch_ind->is_beacon); + bss_desc_ptr->rssi = roam_synch_ind->rssi; + + if (is_multi_link_roam(roam_synch_ind)) { + bss_desc_ptr->chan_freq = + mlo_roam_get_chan_freq(vdev_id, roam_synch_ind); + } else if (parsed_frm_ptr->he_op.oper_info_6g_present) { + bss_desc_ptr->chan_freq = wlan_reg_chan_band_to_freq(mac->pdev, + parsed_frm_ptr->he_op.oper_info_6g.info.primary_ch, + BIT(REG_BAND_6G)); + } else if (parsed_frm_ptr->dsParamsPresent) { + bss_desc_ptr->chan_freq = parsed_frm_ptr->chan_freq; + } else if (parsed_frm_ptr->HTInfo.present) { + bss_desc_ptr->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, + parsed_frm_ptr->HTInfo.primaryChannel); + } else { + /* + * If DS Params or HTIE is not present in the probe resp or + * beacon, then use the channel frequency provided by firmware + * to fill the channel in the BSS descriptor.*/ + bss_desc_ptr->chan_freq = roam_synch_ind->chan_freq; + } + + bss_desc_ptr->nwType = lim_get_nw_type(mac, bss_desc_ptr->chan_freq, + SIR_MAC_MGMT_FRAME, + parsed_frm_ptr); + + bss_desc_ptr->beaconInterval = parsed_frm_ptr->beaconInterval; + bss_desc_ptr->timeStamp[0] = parsed_frm_ptr->timeStamp[0]; + bss_desc_ptr->timeStamp[1] = parsed_frm_ptr->timeStamp[1]; + qdf_mem_copy(&bss_desc_ptr->capabilityInfo, + &bcn_proberesp_ptr[SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_CAPAB_OFFSET], 2); + + qdf_mem_copy((uint8_t *) &bss_desc_ptr->bssId, + (uint8_t *)&bssid.bytes, + sizeof(tSirMacAddr)); + + if (parsed_frm_ptr->mdiePresent) { + bss_desc_ptr->mdiePresent = parsed_frm_ptr->mdiePresent; + qdf_mem_copy((uint8_t *)bss_desc_ptr->mdie, + (uint8_t *)parsed_frm_ptr->mdie, + SIR_MDIE_SIZE); + + mdie_cfg.bool_value = true; + mdie_cfg.uint_value = + (bss_desc_ptr->mdie[1] << 8) | (bss_desc_ptr->mdie[0]); + + wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + MOBILITY_DOMAIN, &mdie_cfg); + } + pe_debug("chan: %d rssi: %d ie_len %d mdie_present:%d mdie = %02x %02x %02x", + bss_desc_ptr->chan_freq, + bss_desc_ptr->rssi, ie_len, bss_desc_ptr->mdiePresent, + bss_desc_ptr->mdie[0], bss_desc_ptr->mdie[1], bss_desc_ptr->mdie[2]); + + if (ie_len) { + qdf_mem_copy(&bss_desc_ptr->ieFields, + ie, ie_len); + qdf_mem_free(ie); + } else { + pe_err("Beacon/Probe rsp doesn't have any IEs"); + status = QDF_STATUS_E_FAILURE; + goto done; + } +done: + qdf_mem_free(frame.ptr); + qdf_mem_free(parsed_frm_ptr); + return status; +} + +#if defined(WLAN_FEATURE_FILS_SK) +/** + * lim_copy_and_free_hlp_data_from_session - Copy HLP info + * @session_ptr: PE session + * @roam_sync_ind_ptr: Roam Synch Indication pointer + * + * This API is used to copy the parsed HLP info from PE session + * to roam synch indication data. THe HLP info is expected to be + * parsed/stored in PE session already from assoc IE's received + * from fw as part of Roam Synch Indication. + * + * Return: None + */ +static void +lim_copy_and_free_hlp_data_from_session(struct pe_session *session_ptr, + struct roam_offload_synch_ind + *roam_sync_ind_ptr) +{ + if (session_ptr->fils_info->hlp_data && + session_ptr->fils_info->hlp_data_len) { + cds_copy_hlp_info(&session_ptr->fils_info->dst_mac, + &session_ptr->fils_info->src_mac, + session_ptr->fils_info->hlp_data_len, + session_ptr->fils_info->hlp_data, + &roam_sync_ind_ptr->dst_mac, + &roam_sync_ind_ptr->src_mac, + &roam_sync_ind_ptr->hlp_data_len, + roam_sync_ind_ptr->hlp_data); + + qdf_mem_free(session_ptr->fils_info->hlp_data); + session_ptr->fils_info->hlp_data = NULL; + session_ptr->fils_info->hlp_data_len = 0; + } +} +#else +static inline void +lim_copy_and_free_hlp_data_from_session(struct pe_session *session_ptr, + struct roam_offload_synch_ind + *roam_sync_ind_ptr) +{} +#endif + +static +uint8_t *lim_process_rmf_disconnect_frame(struct mac_context *mac, + struct pe_session *session, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t *extracted_length) +{ + struct wlan_frame_hdr *mac_hdr; + uint8_t mic_len, hdr_len, pdev_id; + uint8_t *orig_ptr, *efrm; + int32_t mgmtcipherset; + uint32_t mmie_len; + QDF_STATUS status; + + mac_hdr = (struct wlan_frame_hdr *)deauth_disassoc_frame; + orig_ptr = (uint8_t *)mac_hdr; + + if (mac_hdr->i_fc[1] & IEEE80211_FC1_WEP) { + if (QDF_IS_ADDR_BROADCAST(mac_hdr->i_addr1) || + IEEE80211_IS_MULTICAST(mac_hdr->i_addr1)) { + pe_err("Encrypted BC/MC frame dropping the frame"); + *extracted_length = 0; + return NULL; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(mac->pdev); + status = mlme_get_peer_mic_len(mac->psoc, pdev_id, + mac_hdr->i_addr2, &mic_len, + &hdr_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to get mic hdr and length"); + *extracted_length = 0; + return NULL; + } + + if (deauth_disassoc_frame_len < + (sizeof(*mac_hdr) + hdr_len + mic_len)) { + pe_err("Frame len less than expected %d", + deauth_disassoc_frame_len); + *extracted_length = 0; + return NULL; + } + + /* + * Strip the privacy headers and trailer + * for the received deauth/disassoc frame + */ + qdf_mem_move(orig_ptr + hdr_len, mac_hdr, + sizeof(*mac_hdr)); + *extracted_length = deauth_disassoc_frame_len - + (hdr_len + mic_len); + return orig_ptr + hdr_len; + } + + if (!(QDF_IS_ADDR_BROADCAST(mac_hdr->i_addr1) || + IEEE80211_IS_MULTICAST(mac_hdr->i_addr1))) { + pe_err("Rx unprotected unicast mgmt frame"); + *extracted_length = 0; + return NULL; + } + + mgmtcipherset = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_MGMT_CIPHER); + if (mgmtcipherset < 0) { + pe_err("Invalid mgmt cipher"); + *extracted_length = 0; + return NULL; + } + + mmie_len = (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_CMAC) ? + cds_get_mmie_size() : cds_get_gmac_mmie_size()); + + efrm = orig_ptr + deauth_disassoc_frame_len; + if (!mac->pmf_offload && + !wlan_crypto_is_mmie_valid(session->vdev, orig_ptr, efrm)) { + pe_err("Invalid MMIE"); + *extracted_length = 0; + return NULL; + } + + *extracted_length = deauth_disassoc_frame_len - mmie_len; + + return deauth_disassoc_frame; +} + +QDF_STATUS +pe_disconnect_callback(struct mac_context *mac, uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code) +{ + struct pe_session *session; + uint8_t *extracted_frm = NULL; + uint16_t extracted_frm_len; + bool is_pmf_connection; + + session = pe_find_session_by_vdev_id(mac, vdev_id); + if (!session) { + pe_err("LFR3: Vdev %d doesn't exist", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (!lim_is_sb_disconnect_allowed(session)) + return QDF_STATUS_SUCCESS; + + if (!deauth_disassoc_frame || + deauth_disassoc_frame_len < + (sizeof(struct wlan_frame_hdr) + sizeof(reason_code))) { + pe_err_rl("Discard invalid disconnect evt. frame len:%d", + deauth_disassoc_frame_len); + goto end; + } + + /* + * Use vdev pmf status instead of peer pmf capability as + * the firmware might roam to new AP in powersave case and + * roam synch can come before emergency deauth event. + * In that case, get peer will fail and reason code received + * from the WMI_ROAM_EVENTID will be sent to upper layers. + */ + is_pmf_connection = lim_get_vdev_rmf_capable(mac, session); + if (is_pmf_connection) { + extracted_frm = lim_process_rmf_disconnect_frame( + mac, session, + deauth_disassoc_frame, + deauth_disassoc_frame_len, + &extracted_frm_len); + if (!extracted_frm) { + pe_err("PMF frame validation failed"); + goto end; + } + } else { + extracted_frm = deauth_disassoc_frame; + extracted_frm_len = deauth_disassoc_frame_len; + } + + lim_extract_ies_from_deauth_disassoc(session, extracted_frm, + extracted_frm_len); + + reason_code = sir_read_u16(extracted_frm + + sizeof(struct wlan_frame_hdr)); +end: + lim_tear_down_link_with_ap(mac, session->peSessionId, + reason_code, + eLIM_PEER_ENTITY_DEAUTH); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FILS_SK +static void +lim_fill_fils_ft(struct pe_session *src_session, + struct pe_session *dst_session) +{ + if (src_session->fils_info && + src_session->fils_info->fils_ft_len) { + dst_session->fils_info->fils_ft_len = + src_session->fils_info->fils_ft_len; + qdf_mem_copy(dst_session->fils_info->fils_ft, + src_session->fils_info->fils_ft, + src_session->fils_info->fils_ft_len); + } +} +#else +static inline void +lim_fill_fils_ft(struct pe_session *src_session, + struct pe_session *dst_session) +{} +#endif + +#ifdef WLAN_SUPPORT_TWT +void +lim_fill_roamed_peer_twt_caps(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch) +{ + uint8_t *reassoc_body; + uint16_t len; + uint32_t status; + tDot11fReAssocResponse *reassoc_rsp; + struct pe_session *pe_session; + struct qdf_mac_addr mac_addr; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!pe_session) { + pe_err("session not found for given vdev_id %d", vdev_id); + return; + } + + reassoc_rsp = qdf_mem_malloc(sizeof(*reassoc_rsp)); + if (!reassoc_rsp) + return; + + len = roam_synch->reassoc_resp_length - sizeof(tSirMacMgmtHdr); + reassoc_body = (uint8_t *)roam_synch + sizeof(tSirMacMgmtHdr) + + roam_synch->reassoc_resp_offset; + + status = dot11f_unpack_re_assoc_response(mac_ctx, reassoc_body, len, + reassoc_rsp, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse a Re-association Rsp (0x%08x, %d bytes):", + status, len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_INFO, + reassoc_body, len); + qdf_mem_free(reassoc_rsp); + return; + } else if (DOT11F_WARNED(status)) { + pe_debug("Warnings while unpacking a Re-association Rsp (0x%08x, %d bytes):", + status, len); + } + + if (lim_is_session_he_capable(pe_session)) { + if (is_multi_link_roam(roam_synch)) + mlo_get_sta_link_mac_addr(vdev_id, roam_synch, + &mac_addr); + else + qdf_copy_macaddr(&mac_addr, &roam_synch->bssid); + lim_set_twt_peer_capabilities(mac_ctx, + &mac_addr, + &reassoc_rsp->he_cap, + &reassoc_rsp->he_op); + } + qdf_mem_free(reassoc_rsp); +} +#endif + +/** + * lim_check_ft_initial_im_association() - To check FT initial mobility(im) + * association + * @roam_synch: A pointer to roam sync ind structure + * @session_entry: pe session + * + * This function is to check ft_initial_im_association. + * + * Return: None + */ +void +lim_check_ft_initial_im_association(struct roam_offload_synch_ind *roam_synch, + struct pe_session *session_entry) +{ + tpSirMacMgmtHdr hdr; + uint8_t *assoc_req_ptr; + + assoc_req_ptr = (uint8_t *) roam_synch + roam_synch->reassoc_req_offset; + hdr = (tpSirMacMgmtHdr) assoc_req_ptr; + + if (hdr->fc.type == SIR_MAC_MGMT_FRAME && + hdr->fc.subType == SIR_MAC_MGMT_ASSOC_REQ) { + roam_synch->is_assoc = true; + if (session_entry->is11Rconnection) { + pe_debug("Frame subtype: %d and connection is %d", + hdr->fc.subType, + session_entry->is11Rconnection); + roam_synch->is_ft_im_roam = true; + } + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +lim_mlo_roam_copy_partner_info_to_session(struct pe_session *session, + struct roam_offload_synch_ind *sync_ind) +{ + mlo_roam_copy_partner_info(&session->ml_partner_info, + sync_ind, sync_ind->roamed_vdev_id, false); +} + +static QDF_STATUS +lim_gen_link_specific_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + uint8_t *reassoc_rsp, + uint32_t reassoc_rsp_len) +{ + struct element_info link_reassoc_rsp; + struct qdf_mac_addr sta_link_addr; + struct mlo_partner_info *ml_partner_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t idx = 0, num_partner_links, link_id, link_vdev_id; + + link_reassoc_rsp.ptr = qdf_mem_malloc(reassoc_rsp_len); + if (!link_reassoc_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + link_reassoc_rsp.len = reassoc_rsp_len; + + ml_partner_info = &session_entry->ml_partner_info; + num_partner_links = ml_partner_info->num_partner_links; + for (idx = 0; idx < num_partner_links; idx++) { + link_vdev_id = ml_partner_info->partner_link_info[idx].vdev_id; + if (link_vdev_id == WLAN_INVALID_VDEV_ID) + continue; + + if (link_vdev_id != session_entry->vdev_id) + continue; + + link_id = ml_partner_info->partner_link_info[idx].link_id; + status = util_gen_link_assoc_rsp( + reassoc_rsp + WLAN_MAC_HDR_LEN_3A, + reassoc_rsp_len - WLAN_MAC_HDR_LEN_3A, + true, link_id, sta_link_addr, + link_reassoc_rsp.ptr, reassoc_rsp_len, + (qdf_size_t *)&link_reassoc_rsp.len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("MLO ROAM: link_id:%d vdev:%d Reassoc generation failed %d", + link_id, link_vdev_id, status); + goto end; + } + + lim_process_assoc_rsp_frame(mac_ctx, link_reassoc_rsp.ptr, + link_reassoc_rsp.len - WLAN_MAC_HDR_LEN_3A, + LIM_REASSOC, session_entry); + } +end: + qdf_mem_free(link_reassoc_rsp.ptr); + link_reassoc_rsp.len = 0; + return status; +} + +#else +static inline void +lim_mlo_roam_copy_partner_info_to_session(struct pe_session *session, + struct roam_offload_synch_ind *sync_ind) +{} + +static QDF_STATUS +lim_gen_link_specific_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + uint8_t *reassoc_rsp, + uint32_t reassoc_rsp_len) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_11AX +static void pe_roam_fill_obss_scan_param(struct pe_session *src_session, + struct pe_session *dst_session) +{ + dst_session->obss_color_collision_dec_evt = + src_session->obss_color_collision_dec_evt; + dst_session->he_op.bss_color = src_session->he_op.bss_color; +} +#else +static inline void pe_roam_fill_obss_scan_param(struct pe_session *src_session, + struct pe_session *dst_session) +{ +} +#endif + +#ifdef WLAN_FEATURE_SR +void lim_handle_sr_cap(struct wlan_objmgr_vdev *vdev, + enum sr_osif_reason_code reason) +{ + int32_t non_srg_pd_threshold = 0; + int32_t srg_pd_threshold = 0; + uint8_t non_srg_pd_offset = 0; + uint8_t srg_max_pd_offset = 0; + uint8_t srg_min_pd_offset = 0; + uint8_t sr_ctrl, sr_enable_modes; + bool is_pd_threshold_present = false; + struct wlan_objmgr_pdev *pdev; + enum sr_status_of_roamed_ap sr_status; + enum sr_osif_operation sr_op; + enum QDF_OPMODE opmode; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + pe_err("mac ctx is null"); + return; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + pe_err("invalid pdev"); + return; + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + /* If SR is disabled in INI for the session-operating mode + * Then return. + */ + wlan_mlme_get_sr_enable_modes(mac->psoc, &sr_enable_modes); + if (!(sr_enable_modes & (1 << opmode))) { + pe_debug("SR is disabled in INI for mode: %d", opmode); + return; + } + if (!wlan_vdev_mlme_get_he_spr_enabled(vdev)) { + pe_debug("SR is not enabled"); + return; + } + non_srg_pd_offset = wlan_vdev_mlme_get_non_srg_pd_offset(vdev); + wlan_vdev_mlme_get_srg_pd_offset(vdev, &srg_max_pd_offset, + &srg_min_pd_offset); + wlan_vdev_mlme_get_current_non_srg_pd_threshold(vdev, + &non_srg_pd_threshold); + wlan_vdev_mlme_get_current_srg_pd_threshold(vdev, + &srg_pd_threshold); + + sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(vdev); + if ((sr_ctrl & NON_SRG_PD_SR_DISALLOWED) && + (!(sr_ctrl & SRG_INFO_PRESENT))) { + sr_status = SR_DISALLOW; + } else { + if ((!(sr_ctrl & NON_SRG_PD_SR_DISALLOWED) && + (non_srg_pd_threshold > non_srg_pd_offset + + SR_PD_THRESHOLD_MIN)) || + ((sr_ctrl & SRG_INFO_PRESENT) && + ((srg_pd_threshold > srg_max_pd_offset + + SR_PD_THRESHOLD_MIN) || + (srg_pd_threshold < srg_min_pd_offset + + SR_PD_THRESHOLD_MIN)))) + sr_status = SR_THRESHOLD_NOT_IN_RANGE; + else + sr_status = SR_THRESHOLD_IN_RANGE; + } + pe_debug("sr status %d reason %d existing thresholds srg: %d non-srg: %d New: sr offset srg: max %d min %d non-srg: %d", + sr_status, reason, srg_pd_threshold, non_srg_pd_threshold, + srg_max_pd_offset, srg_min_pd_offset, non_srg_pd_offset); + switch (sr_status) { + case SR_DISALLOW: + /** clear thresholds set by previous AP **/ + wlan_vdev_mlme_set_current_non_srg_pd_threshold(vdev, 0); + wlan_vdev_mlme_set_current_srg_pd_threshold(vdev, 0); + wlan_spatial_reuse_osif_event(vdev, + SR_OPERATION_SUSPEND, + reason); + /* + * If SR is disabled due to beacon update, + * notify the firmware to disable SR + */ + if (reason == SR_REASON_CODE_BCN_IE_CHANGE) + wlan_sr_setup_req(vdev, pdev, false, 0, 0); + break; + case SR_THRESHOLD_NOT_IN_RANGE: + wlan_vdev_mlme_get_pd_threshold_present( + vdev, &is_pd_threshold_present); + /* + * if userspace gives pd threshold then check if its within + * range of roamed AP's min and max thresholds, if not in + * range disable and let userspace decide to re-enable. + * if userspace dosesnt give PD threshold then always enable + * SRG based on AP's recommendation of thresholds. + */ + if (is_pd_threshold_present) { + wlan_vdev_mlme_set_current_non_srg_pd_threshold(vdev, + 0); + wlan_vdev_mlme_set_current_srg_pd_threshold(vdev, 0); + wlan_spatial_reuse_osif_event(vdev, + SR_OPERATION_SUSPEND, + reason); + } else { + sr_op = (reason == SR_REASON_CODE_ROAMING) ? + SR_OPERATION_RESUME : + SR_OPERATION_UPDATE_PARAMS; + wlan_sr_setup_req( + vdev, pdev, true, + srg_max_pd_offset + SR_PD_THRESHOLD_MIN, + non_srg_pd_threshold + SR_PD_THRESHOLD_MIN); + wlan_spatial_reuse_osif_event(vdev, sr_op, reason); + } + break; + case SR_THRESHOLD_IN_RANGE: + /* Send enable command to fw, as fw disables SR on roaming */ + wlan_sr_setup_req(vdev, pdev, true, srg_pd_threshold, + non_srg_pd_threshold); + break; + } +} +#endif + +QDF_STATUS +pe_roam_synch_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *roam_sync_ind_ptr, + uint16_t ie_len, + enum sir_roam_op_code reason) +{ + struct pe_session *session_ptr; + struct pe_session *ft_session_ptr; + uint8_t session_id; + uint8_t *reassoc_resp; + tpDphHashNode curr_sta_ds = NULL, sta_ds = NULL; + uint16_t aid; + struct bss_params *add_bss_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct bss_description *bss_desc = NULL; + uint16_t ric_tspec_len; + struct qdf_mac_addr bssid; + uint8_t *oui_ie_ptr; + uint16_t oui_ie_len; + + if (!roam_sync_ind_ptr) { + pe_err("LFR3:roam_sync_ind_ptr is NULL"); + return status; + } + session_ptr = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session_ptr) { + pe_err("LFR3:Unable to find session"); + return status; + } + + if (!LIM_IS_STA_ROLE(session_ptr)) { + pe_err("LFR3:session is not in STA mode"); + return status; + } + + if (is_multi_link_roam(roam_sync_ind_ptr)) + mlo_get_sta_link_mac_addr(vdev_id, roam_sync_ind_ptr, &bssid); + else + bssid = roam_sync_ind_ptr->bssid; + + pe_debug("LFR3: PE callback reason: %d", reason); + switch (reason) { + case SIR_ROAMING_ABORT: + /* + * If there was a disassoc or deauth that was received + * during roaming and it was not honored, then we have + * to internally initiate a disconnect because with + * ROAM_ABORT we come back to original AP. + */ + if (session_ptr->recvd_deauth_while_roaming) + lim_perform_deauth(mac_ctx, session_ptr, + session_ptr->deauth_disassoc_rc, + session_ptr->bssId, 0); + if (session_ptr->recvd_disassoc_while_roaming) { + lim_disassoc_tdls_peers(mac_ctx, session_ptr, + session_ptr->bssId); + lim_perform_disassoc(mac_ctx, 0, + session_ptr->deauth_disassoc_rc, + session_ptr, session_ptr->bssId); + } + return QDF_STATUS_SUCCESS; + case SIR_ROAM_SYNCH_PROPAGATION: + break; + default: + return status; + } + + pe_debug("LFR3:Received ROAM SYNCH IND bssid "QDF_MAC_ADDR_FMT" auth: %d vdevId: %d", + QDF_MAC_ADDR_REF(roam_sync_ind_ptr->bssid.bytes), + roam_sync_ind_ptr->auth_status, + vdev_id); + + /* + * If deauth from AP already in progress, ignore Roam Synch Indication + * from firmware. + */ + if (session_ptr->limSmeState != eLIM_SME_LINK_EST_STATE) { + pe_err("LFR3: Not in Link est state"); + return status; + } + + bss_desc = qdf_mem_malloc(sizeof(struct bss_description) + ie_len); + if (!bss_desc) { + QDF_ASSERT(bss_desc); + status = -QDF_STATUS_E_NOMEM; + return status; + } + + status = lim_roam_fill_bss_descr(mac_ctx, roam_sync_ind_ptr, + bss_desc, session_ptr); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("LFR3:Failed to fill Bss Descr"); + qdf_mem_free(bss_desc); + return status; + } + status = QDF_STATUS_E_FAILURE; + ft_session_ptr = pe_create_session(mac_ctx, bss_desc->bssId, + &session_id, + mac_ctx->lim.max_sta_of_pe_session, + session_ptr->bssType, + session_ptr->vdev_id); + if (!ft_session_ptr) { + pe_err("LFR3:Cannot create PE Session bssid: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bss_desc->bssId)); + qdf_mem_free(bss_desc); + return status; + } + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(mac_ctx, ft_session_ptr, 0); + sir_copy_mac_addr(ft_session_ptr->limReAssocbssId, bss_desc->bssId); + session_ptr->bRoamSynchInProgress = true; + ft_session_ptr->bRoamSynchInProgress = true; + ft_session_ptr->limSystemRole = eLIM_STA_ROLE; + sir_copy_mac_addr(session_ptr->limReAssocbssId, bss_desc->bssId); + ft_session_ptr->csaOffloadEnable = session_ptr->csaOffloadEnable; + + /* Next routine will update nss and vdev_nss with AP's capabilities */ + status = lim_fill_ft_session(mac_ctx, bss_desc, ft_session_ptr, + session_ptr, roam_sync_ind_ptr->phy_mode); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to fill ft session for vdev id %d", + ft_session_ptr->vdev_id); + qdf_mem_free(bss_desc); + goto roam_sync_fail; + } + + roam_sync_ind_ptr->ssid.length = + qdf_min((qdf_size_t)ft_session_ptr->ssId.length, + sizeof(roam_sync_ind_ptr->ssid.ssid)); + qdf_mem_copy(roam_sync_ind_ptr->ssid.ssid, ft_session_ptr->ssId.ssId, + roam_sync_ind_ptr->ssid.length); + pe_update_crypto_params(mac_ctx, ft_session_ptr, roam_sync_ind_ptr); + + /* Reset the SPMK global cache */ + wlan_mlme_set_sae_single_pmk_bss_cap(mac_ctx->psoc, vdev_id, false); + + /* Next routine may update nss based on dot11Mode */ + + lim_ft_prepare_add_bss_req(mac_ctx, ft_session_ptr, bss_desc); + lim_set_tpc_power(mac_ctx, ft_session_ptr, bss_desc); + + if (session_ptr->is11Rconnection) + lim_fill_fils_ft(session_ptr, ft_session_ptr); + + roam_sync_ind_ptr->add_bss_params = + (struct bss_params *) ft_session_ptr->ftPEContext.pAddBssReq; + add_bss_params = ft_session_ptr->ftPEContext.pAddBssReq; + lim_delete_tdls_peers(mac_ctx, session_ptr); + /* + * After deleting the TDLS peers notify the Firmware about TDLS STA + * disconnection due to roaming + */ + wlan_tdls_notify_sta_disconnect(vdev_id, true, + false, session_ptr->vdev); + + sta_ds = dph_lookup_hash_entry(mac_ctx, session_ptr->bssId, &aid, + &session_ptr->dph.dphHashTable); + if (!sta_ds && !is_multi_link_roam(roam_sync_ind_ptr)) { + pe_err("LFR3:failed to lookup hash entry"); + ft_session_ptr->bRoamSynchInProgress = false; + qdf_mem_free(bss_desc); + goto roam_sync_fail; + } + + /* update OBSS scan param */ + pe_roam_fill_obss_scan_param(session_ptr, ft_session_ptr); + + curr_sta_ds = dph_add_hash_entry(mac_ctx, + bssid.bytes, + DPH_STA_HASH_INDEX_PEER, + &ft_session_ptr->dph.dphHashTable); + if (!curr_sta_ds) { + pe_err("LFR3:failed to add hash entry for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_bss_params->staContext.staMac)); + ft_session_ptr->bRoamSynchInProgress = false; + qdf_mem_free(bss_desc); + goto roam_sync_fail; + } + + if (roam_sync_ind_ptr->auth_status == ROAM_AUTH_STATUS_AUTHENTICATED) + curr_sta_ds->is_key_installed = true; + + lim_mlo_roam_copy_partner_info_to_session(ft_session_ptr, + roam_sync_ind_ptr); + + reassoc_resp = (uint8_t *)roam_sync_ind_ptr + + roam_sync_ind_ptr->reassoc_resp_offset; + mgmt_txrx_frame_hex_dump(reassoc_resp, + roam_sync_ind_ptr->reassoc_resp_length, false); + if (wlan_vdev_mlme_get_is_mlo_link(mac_ctx->psoc, vdev_id)) { + status = lim_gen_link_specific_assoc_rsp(mac_ctx, + ft_session_ptr, + reassoc_resp, + roam_sync_ind_ptr->reassoc_resp_length); + if (ft_session_ptr->is_unexpected_peer_error) + status = QDF_STATUS_E_FAILURE; + + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(bss_desc); + goto roam_sync_fail; + } + } else { + lim_process_assoc_rsp_frame(mac_ctx, reassoc_resp, + roam_sync_ind_ptr->reassoc_resp_length - SIR_MAC_HDR_LEN_3A, + LIM_REASSOC, ft_session_ptr); + if (ft_session_ptr->is_unexpected_peer_error) { + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(bss_desc); + goto roam_sync_fail; + } + } + + oui_ie_ptr = (uint8_t *)&bss_desc->ieFields[0]; + oui_ie_len = wlan_get_ielen_from_bss_description(bss_desc); + lim_enable_cts_to_self_for_exempted_iot_ap(mac_ctx, + ft_session_ptr, + oui_ie_ptr, oui_ie_len); + qdf_mem_free(bss_desc); + oui_ie_len = 0; + oui_ie_ptr = NULL; + + lim_check_ft_initial_im_association(roam_sync_ind_ptr, ft_session_ptr); + + lim_copy_and_free_hlp_data_from_session(ft_session_ptr, + roam_sync_ind_ptr); + roam_sync_ind_ptr->aid = ft_session_ptr->limAID; + curr_sta_ds->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + curr_sta_ds->nss = ft_session_ptr->nss; + roam_sync_ind_ptr->nss = ft_session_ptr->nss; + ft_session_ptr->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + ft_session_ptr->limPrevMlmState = ft_session_ptr->limMlmState; + lim_init_tdls_data(mac_ctx, ft_session_ptr); + ric_tspec_len = ft_session_ptr->RICDataLen; + pe_debug("LFR3: Session RicLength: %d", ft_session_ptr->RICDataLen); + lim_handle_sr_cap(ft_session_ptr->vdev, SR_REASON_CODE_ROAMING); +#ifdef FEATURE_WLAN_ESE + ric_tspec_len += ft_session_ptr->tspecLen; + pe_debug("LFR3: tspecLen: %d", ft_session_ptr->tspecLen); +#endif + if (ric_tspec_len) { + roam_sync_ind_ptr->ric_tspec_data = + qdf_mem_malloc(ric_tspec_len); + if (!roam_sync_ind_ptr->ric_tspec_data) { + ft_session_ptr->bRoamSynchInProgress = false; + status = QDF_STATUS_E_NOMEM; + goto roam_sync_fail; + } + + if (ft_session_ptr->ricData) { + roam_sync_ind_ptr->ric_data_len = + ft_session_ptr->RICDataLen; + qdf_mem_copy(roam_sync_ind_ptr->ric_tspec_data, + ft_session_ptr->ricData, + roam_sync_ind_ptr->ric_data_len); + qdf_mem_free(ft_session_ptr->ricData); + ft_session_ptr->ricData = NULL; + ft_session_ptr->RICDataLen = 0; + } +#ifdef FEATURE_WLAN_ESE + if (ft_session_ptr->tspecIes) { + roam_sync_ind_ptr->tspec_len = ft_session_ptr->tspecLen; + qdf_mem_copy(roam_sync_ind_ptr->ric_tspec_data + + roam_sync_ind_ptr->ric_data_len, + ft_session_ptr->tspecIes, + roam_sync_ind_ptr->tspec_len); + qdf_mem_free(ft_session_ptr->tspecIes); + ft_session_ptr->tspecIes = NULL; + ft_session_ptr->tspecLen = 0; + } +#endif + } + roam_sync_ind_ptr->chan_width = ft_session_ptr->ch_width; + roam_sync_ind_ptr->max_rate_flags = + lim_get_max_rate_flags(mac_ctx, curr_sta_ds); + ft_session_ptr->limSmeState = eLIM_SME_LINK_EST_STATE; + ft_session_ptr->limPrevSmeState = ft_session_ptr->limSmeState; + ft_session_ptr->bRoamSynchInProgress = false; + + /* Cleanup the old session */ + session_ptr->limSmeState = eLIM_SME_IDLE_STATE; + + /* + * Delete the ml_peer only if DUT is roamed to a non-11BE candidate. + * ml_peer is already cleaned up in wma_delete_all_peers() at the + * beginning of roam_sync handling for 11BE candidates. + */ + if (sta_ds) { + if (!wlan_vdev_mlme_is_mlo_vdev(session_ptr->vdev)) { + lim_mlo_notify_peer_disconn(session_ptr, sta_ds); + lim_mlo_roam_delete_link_peer(session_ptr, sta_ds); + } + lim_cleanup_rx_path(mac_ctx, sta_ds, session_ptr, false); + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, aid, + session_ptr); + } + + pe_delete_session(mac_ctx, session_ptr); + + return QDF_STATUS_SUCCESS; + +roam_sync_fail: + pe_err("Roam sync failure status %d session vdev %d", status, + session_ptr->vdev_id); + /* + * Cleanup the new session upon roam sync failure. + * Retain the old session for graceful HO failure handling. + */ + if (curr_sta_ds) { + lim_cleanup_rx_path(mac_ctx, curr_sta_ds, ft_session_ptr, + false); + lim_delete_dph_hash_entry(mac_ctx, curr_sta_ds->staAddr, + curr_sta_ds->assocId, ft_session_ptr); + } + pe_delete_session(mac_ctx, ft_session_ptr); + return status; +} + +QDF_STATUS +pe_set_ie_for_roam_invoke(struct mac_context *mac_ctx, uint8_t vdev_id, + uint16_t dot11_mode, enum QDF_OPMODE opmode) +{ + QDF_STATUS status; + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + status = lim_send_ies_per_band(mac_ctx, vdev_id, dot11_mode, opmode); + return status; +} + +#endif + +static bool lim_is_beacon_miss_scenario(struct mac_context *mac, + uint8_t *pRxPacketInfo) +{ + tpSirMacMgmtHdr pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + uint8_t sessionId; + struct pe_session *pe_session = + pe_find_session_by_bssid(mac, pHdr->bssId, &sessionId); + + if (pe_session && pe_session->pmmOffloadInfo.bcnmiss) + return true; + return false; +} + +/** ----------------------------------------------------------------- + \brief lim_is_pkt_candidate_for_drop() - decides whether to drop the frame or not + + This function is called before enqueuing the frame to PE queue for further processing. + This prevents unnecessary frames getting into PE Queue and drops them right away. + Frames will be dropped in the following scenarios: + + - In Scan State, drop the frames which are not marked as scan frames + - In non-Scan state, drop the frames which are marked as scan frames. + + \param mac - global mac structure + \return - none + \sa + ----------------------------------------------------------------- */ + +tMgmtFrmDropReason lim_is_pkt_candidate_for_drop(struct mac_context *mac, + uint8_t *pRxPacketInfo, + uint32_t subType) +{ + uint32_t framelen; + uint8_t *pBody; + tSirMacCapabilityInfo capabilityInfo; + tpSirMacMgmtHdr pHdr = NULL; + struct wlan_objmgr_vdev *vdev; + + /* + * + * In scan mode, drop only Beacon/Probe Response which are NOT marked as scan-frames. + * In non-scan mode, drop only Beacon/Probe Response which are marked as scan frames. + * Allow other mgmt frames, they must be from our own AP, as we don't allow + * other than beacons or probe responses in scan state. + */ + if ((subType == SIR_MAC_MGMT_BEACON) || + (subType == SIR_MAC_MGMT_PROBE_RSP)) { + if (lim_is_beacon_miss_scenario(mac, pRxPacketInfo)) { + MTRACE(mac_trace(mac, TRACE_CODE_INFO_LOG, 0, + eLOG_NODROP_MISSED_BEACON_SCENARIO)); + return eMGMT_DROP_NO_DROP; + } + + framelen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + /* drop the frame if length is less than 12 */ + if (framelen < LIM_MIN_BCN_PR_LENGTH) + return eMGMT_DROP_INVALID_SIZE; + + *((uint16_t *) &capabilityInfo) = + sir_read_u16(pBody + LIM_BCN_PR_CAPABILITY_OFFSET); + + /* Note sure if this is sufficient, basically this condition allows all probe responses and + * beacons from an infrastructure network + */ + if (!capabilityInfo.ibss) + return eMGMT_DROP_NO_DROP; + + /* Drop INFRA Beacons and Probe Responses in IBSS Mode */ + /* This can be enhanced to even check the SSID before deciding to enqueue the frame. */ + if (capabilityInfo.ess) + return eMGMT_DROP_INFRA_BCN_IN_IBSS; + + } else if (subType == SIR_MAC_MGMT_AUTH) { + uint16_t curr_seq_num = 0; + struct tLimPreAuthNode *auth_node; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(mac->pdev, + pHdr->da, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return eMGMT_DROP_NO_DROP; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + curr_seq_num = ((pHdr->seqControl.seqNumHi << 4) | + (pHdr->seqControl.seqNumLo)); + auth_node = lim_search_pre_auth_list(mac, pHdr->sa); + if (auth_node && pHdr->fc.retry && + (auth_node->seq_num == curr_seq_num)) { + pe_err_rl("auth frame, seq num: %d is already processed, drop it", + curr_seq_num); + return eMGMT_DROP_DUPLICATE_AUTH_FRAME; + } + } else if ((subType == SIR_MAC_MGMT_ASSOC_REQ) || + (subType == SIR_MAC_MGMT_DISASSOC) || + (subType == SIR_MAC_MGMT_DEAUTH)) { + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + qdf_time_t *timestamp; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + vdev = wlan_objmgr_get_vdev_by_macaddr_from_pdev(mac->pdev, + pHdr->da, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return eMGMT_DROP_SPURIOUS_FRAME; + + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_STA_MODE && + wlan_cm_is_vdev_roam_started(vdev) && + (subType == SIR_MAC_MGMT_DISASSOC || + subType == SIR_MAC_MGMT_DEAUTH)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return eMGMT_DROP_DEAUTH_DURING_ROAM_STARTED; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + peer = wlan_objmgr_get_peer_by_mac(mac->psoc, + pHdr->sa, + WLAN_LEGACY_MAC_ID); + if (!peer) { + if (subType == SIR_MAC_MGMT_ASSOC_REQ) + return eMGMT_DROP_NO_DROP; + return eMGMT_DROP_SPURIOUS_FRAME; + } + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + if (subType == SIR_MAC_MGMT_ASSOC_REQ) + return eMGMT_DROP_NO_DROP; + return eMGMT_DROP_SPURIOUS_FRAME; + } + + if (subType == SIR_MAC_MGMT_ASSOC_REQ) + timestamp = + &peer_priv->last_assoc_received_time; + else + timestamp = + &peer_priv->last_disassoc_deauth_received_time; + + if (*timestamp > 0 && + qdf_system_time_before(qdf_get_system_timestamp(), + *timestamp + + LIM_DOS_PROTECTION_TIME)) { + pe_debug_rl(FL("Dropping subtype 0x%x frame. %s %d ms %s %d ms"), + subType, "It is received after", + (int)(qdf_get_system_timestamp() - *timestamp), + "of last frame. Allow it only after", + LIM_DOS_PROTECTION_TIME); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return eMGMT_DROP_EXCESSIVE_MGMT_FRAME; + } + + *timestamp = qdf_get_system_timestamp(); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + } + + return eMGMT_DROP_NO_DROP; +} + +void lim_update_lost_link_info(struct mac_context *mac, struct pe_session *session, + int32_t rssi) +{ + struct sir_lost_link_info *lost_link_info; + struct scheduler_msg mmh_msg = {0}; + + if ((!mac) || (!session)) { + pe_err("parameter NULL"); + return; + } + if (!LIM_IS_STA_ROLE(session)) + return; + + lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info)); + if (!lost_link_info) + return; + + lost_link_info->vdev_id = session->smeSessionId; + lost_link_info->rssi = rssi; + mmh_msg.type = eWNI_SME_LOST_LINK_INFO_IND; + mmh_msg.bodyptr = lost_link_info; + mmh_msg.bodyval = 0; + pe_debug("post eWNI_SME_LOST_LINK_INFO_IND, bss_idx: %d rssi: %d", + lost_link_info->vdev_id, lost_link_info->rssi); + + lim_sys_process_mmh_msg_api(mac, &mmh_msg); +} + +/** + * lim_mon_init_session() - create PE session for monitor mode operation + * @mac_ptr: mac pointer + * @msg: Pointer to struct sir_create_session type. + * + * Return: NONE + */ +void lim_mon_init_session(struct mac_context *mac_ptr, + struct sir_create_session *msg) +{ + struct pe_session *psession_entry; + uint8_t session_id; + + psession_entry = pe_create_session(mac_ptr, msg->bss_id.bytes, + &session_id, + mac_ptr->lim.max_sta_of_pe_session, + eSIR_MONITOR_MODE, + msg->vdev_id); + if (!psession_entry) { + pe_err("Monitor mode: Session Can not be created bssid: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(msg->bss_id.bytes)); + return; + } + psession_entry->vhtCapability = 1; +} + +void lim_mon_deinit_session(struct mac_context *mac_ptr, + struct sir_delete_session *msg) +{ + struct pe_session *session; + + session = pe_find_session_by_vdev_id(mac_ptr, msg->vdev_id); + + if (session && session->bssType == eSIR_MONITOR_MODE) + pe_delete_session(mac_ptr, session); +} + +/** + * lim_update_ext_cap_ie() - Update Extended capabilities IE(if present) + * with capabilities of Fine Time measurements(FTM) if set in driver + * + * @mac_ctx: Pointer to Global MAC structure + * @ie_data: Default Scan IE data + * @local_ie_buf: Local Scan IE data + * @local_ie_len: Pointer to length of @ie_data + * @session: Pointer to pe session + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_update_ext_cap_ie(struct mac_context *mac_ctx, uint8_t *ie_data, + uint8_t *local_ie_buf, uint16_t *local_ie_len, + struct pe_session *session) +{ + uint32_t dot11mode; + bool vht_enabled = false; + tDot11fIEExtCap default_scan_ext_cap = {0}, driver_ext_cap = {0}; + QDF_STATUS status; + + status = lim_strip_extcap_update_struct(mac_ctx, ie_data, + local_ie_len, &default_scan_ext_cap); + if (QDF_STATUS_SUCCESS != status) { + pe_err("Strip ext cap fails %d", status); + return QDF_STATUS_E_FAILURE; + } + + if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - EXT_CAP_IE_HDR_LEN)) { + pe_err("Invalid Scan IE length"); + return QDF_STATUS_E_FAILURE; + } + /* copy ie prior to ext cap to local buffer */ + qdf_mem_copy(local_ie_buf, ie_data, (*local_ie_len)); + + /* from here ext cap ie starts, set EID */ + local_ie_buf[*local_ie_len] = DOT11F_EID_EXTCAP; + + dot11mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + if (IS_DOT11_MODE_VHT(dot11mode)) + vht_enabled = true; + + status = populate_dot11f_ext_cap(mac_ctx, vht_enabled, + &driver_ext_cap, NULL); + if (QDF_STATUS_SUCCESS != status) { + pe_err("Failed %d to create ext cap IE. Use default value instead", + status); + local_ie_buf[*local_ie_len + 1] = DOT11F_IE_EXTCAP_MAX_LEN; + + if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - + (DOT11F_IE_EXTCAP_MAX_LEN + EXT_CAP_IE_HDR_LEN))) { + pe_err("Invalid Scan IE length"); + return QDF_STATUS_E_FAILURE; + } + (*local_ie_len) += EXT_CAP_IE_HDR_LEN; + qdf_mem_copy(local_ie_buf + (*local_ie_len), + default_scan_ext_cap.bytes, + DOT11F_IE_EXTCAP_MAX_LEN); + (*local_ie_len) += DOT11F_IE_EXTCAP_MAX_LEN; + return QDF_STATUS_SUCCESS; + } + lim_merge_extcap_struct(&driver_ext_cap, &default_scan_ext_cap, true); + + if (session) + populate_dot11f_twt_extended_caps(mac_ctx, session, + &driver_ext_cap); + else + pe_debug("Session NULL, cannot set TWT caps"); + + local_ie_buf[*local_ie_len + 1] = driver_ext_cap.num_bytes; + + if ((*local_ie_len) > (MAX_DEFAULT_SCAN_IE_LEN - + (EXT_CAP_IE_HDR_LEN + driver_ext_cap.num_bytes))) { + pe_err("Invalid Scan IE length"); + return QDF_STATUS_E_FAILURE; + } + (*local_ie_len) += EXT_CAP_IE_HDR_LEN; + qdf_mem_copy(local_ie_buf + (*local_ie_len), + driver_ext_cap.bytes, driver_ext_cap.num_bytes); + (*local_ie_len) += driver_ext_cap.num_bytes; + return QDF_STATUS_SUCCESS; +} + +#define LIM_RSN_OUI_SIZE 4 + +struct rsn_oui_akm_type_map { + enum ani_akm_type akm_type; + uint8_t rsn_oui[LIM_RSN_OUI_SIZE]; +}; + +static const struct rsn_oui_akm_type_map rsn_oui_akm_type_mapping_table[] = { + {ANI_AKM_TYPE_RSN, {0x00, 0x0F, 0xAC, 0x01} }, + {ANI_AKM_TYPE_RSN_PSK, {0x00, 0x0F, 0xAC, 0x02} }, + {ANI_AKM_TYPE_FT_RSN, {0x00, 0x0F, 0xAC, 0x03} }, + {ANI_AKM_TYPE_FT_RSN_PSK, {0x00, 0x0F, 0xAC, 0x04} }, + {ANI_AKM_TYPE_RSN_8021X_SHA256, {0x00, 0x0F, 0xAC, 0x05} }, + {ANI_AKM_TYPE_RSN_PSK_SHA256, {0x00, 0x0F, 0xAC, 0x06} }, +#ifdef WLAN_FEATURE_SAE + {ANI_AKM_TYPE_SAE, {0x00, 0x0F, 0xAC, 0x08} }, + {ANI_AKM_TYPE_FT_SAE, {0x00, 0x0F, 0xAC, 0x09} }, +#endif + {ANI_AKM_TYPE_SUITEB_EAP_SHA256, {0x00, 0x0F, 0xAC, 0x0B} }, + {ANI_AKM_TYPE_SUITEB_EAP_SHA384, {0x00, 0x0F, 0xAC, 0x0C} }, + {ANI_AKM_TYPE_FT_SUITEB_EAP_SHA384, {0x00, 0x0F, 0xAC, 0x0D} }, + {ANI_AKM_TYPE_FILS_SHA256, {0x00, 0x0F, 0xAC, 0x0E} }, + {ANI_AKM_TYPE_FILS_SHA384, {0x00, 0x0F, 0xAC, 0x0F} }, + {ANI_AKM_TYPE_FT_FILS_SHA256, {0x00, 0x0F, 0xAC, 0x10} }, + {ANI_AKM_TYPE_FT_FILS_SHA384, {0x00, 0x0F, 0xAC, 0x11} }, + {ANI_AKM_TYPE_OWE, {0x00, 0x0F, 0xAC, 0x12} }, +#ifdef FEATURE_WLAN_ESE + {ANI_AKM_TYPE_CCKM, {0x00, 0x40, 0x96, 0x00} }, +#endif + {ANI_AKM_TYPE_OSEN, {0x50, 0x6F, 0x9A, 0x01} }, + {ANI_AKM_TYPE_DPP_RSN, {0x50, 0x6F, 0x9A, 0x02} }, + {ANI_AKM_TYPE_WPA, {0x00, 0x50, 0xF2, 0x01} }, + {ANI_AKM_TYPE_WPA_PSK, {0x00, 0x50, 0xF2, 0x02} }, + {ANI_AKM_TYPE_SAE_EXT_KEY, {0x00, 0x0F, 0xAC, 0x18} }, + {ANI_AKM_TYPE_FT_SAE_EXT_KEY, {0x00, 0x0F, 0xAC, 0x19} }, + /* Add akm type above here */ + {ANI_AKM_TYPE_UNKNOWN, {0} }, +}; + +enum ani_akm_type lim_translate_rsn_oui_to_akm_type(uint8_t auth_suite[4]) +{ + const struct rsn_oui_akm_type_map *map; + enum ani_akm_type akm_type; + + map = rsn_oui_akm_type_mapping_table; + while (true) { + akm_type = map->akm_type; + if ((akm_type == ANI_AKM_TYPE_UNKNOWN) || + (qdf_mem_cmp(auth_suite, map->rsn_oui, 4) == 0)) + break; + map++; + } + + pe_debug("akm_type: %d", akm_type); + + return akm_type; +} + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +QDF_STATUS +lim_cm_fill_link_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct pe_session *pe_session, + struct roam_offload_synch_ind *sync_ind, + uint16_t ie_len) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *assoc_vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct bss_description *bss_desc = NULL; + uint32_t bss_len; + struct join_req *pe_join_req; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("Vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + + if (!assoc_vdev) { + pe_err("Assoc vdev is NULL"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + status = wlan_vdev_mlme_get_ssid(assoc_vdev, + pe_session->ssId.ssId, + &pe_session->ssId.length); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to get ssid vdev id %d", + vdev_id); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + pe_session->lim_join_req = + qdf_mem_malloc(sizeof(*pe_session->lim_join_req) + bss_len); + if (!pe_session->lim_join_req) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + pe_join_req = pe_session->lim_join_req; + + mlo_roam_copy_partner_info(&pe_join_req->partner_info, + sync_ind, vdev_id, false); + + bss_desc = &pe_session->lim_join_req->bssDescription; + + status = lim_roam_fill_bss_descr(mac_ctx, sync_ind, bss_desc, + pe_session); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("LFR3:Failed to fill Bss Descr"); + goto end; + } + + status = lim_fill_pe_session(mac_ctx, pe_session, bss_desc); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to fill pe session vdev id %d", + pe_session->vdev_id); + goto end; + } + + if (pe_session->limSmeState == eLIM_SME_WT_JOIN_STATE) { + pe_session->limSmeState = eLIM_SME_LINK_EST_STATE; + pe_session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + } +end: + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(pe_session->lim_join_req); + pe_session->lim_join_req = NULL; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return status; +} + +struct pe_session * +lim_cm_roam_create_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + struct pe_session *pe_session = NULL; + struct qdf_mac_addr link_mac_addr; + bool is_link_vdev = false; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t session_id; + + is_link_vdev = wlan_vdev_mlme_get_is_mlo_link(mac_ctx->psoc, vdev_id); + status = mlo_get_sta_link_mac_addr(vdev_id, sync_ind, + &link_mac_addr); + + if (QDF_IS_STATUS_ERROR(status)) + return NULL; + + /* In case of legacy to mlo roaming, create pe session */ + if (!pe_session && is_link_vdev) { + pe_session = pe_create_session(mac_ctx, &link_mac_addr.bytes[0], + &session_id, + mac_ctx->lim.max_sta_of_pe_session, + eSIR_INFRASTRUCTURE_MODE, + vdev_id); + if (!pe_session) { + pe_err("vdev_id %d : pe session create failed BSSID" + QDF_MAC_ADDR_FMT, vdev_id, + QDF_MAC_ADDR_REF(link_mac_addr.bytes)); + return NULL; + } + } + + return pe_session; +} + +QDF_STATUS +lim_create_and_fill_link_session(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind, + uint16_t ie_len) +{ + struct pe_session *pe_session; + QDF_STATUS status; + + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + pe_session = lim_cm_roam_create_session(mac_ctx, vdev_id, sync_ind); + if (!pe_session) + goto fail; + + status = lim_cm_fill_link_session(mac_ctx, vdev_id, + pe_session, sync_ind, ie_len); + if (QDF_IS_STATUS_ERROR(status)) + goto fail; + + return QDF_STATUS_SUCCESS; + +fail: + if (pe_session) + pe_delete_session(mac_ctx, pe_session); + + pe_err("MLO ROAM: Link session creation failed"); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS lim_roam_mlo_create_peer(struct mac_context *mac, + struct roam_offload_synch_ind *sync_ind, + uint8_t vdev_id, uint8_t *peer_mac) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *link_peer = NULL; + uint8_t link_id; + struct mlo_partner_info partner_info; + struct qdf_mac_addr link_addr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, + vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) + goto end; + + link_id = mlo_roam_get_link_id(vdev_id, sync_ind); + /* currently only 2 link MLO supported */ + partner_info.num_partner_links = 1; + status = mlo_get_sta_link_mac_addr(vdev_id, sync_ind, &link_addr); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Link mac address not found"); + goto end; + } + + qdf_mem_copy(partner_info.partner_link_info[0].link_addr.bytes, + link_addr.bytes, QDF_MAC_ADDR_SIZE); + partner_info.partner_link_info[0].link_id = link_id; + pe_debug("link_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + partner_info.partner_link_info[0].link_addr.bytes)); + + /* Get the bss peer obj */ + link_peer = wlan_objmgr_get_peer_by_mac(mac->psoc, peer_mac, + WLAN_LEGACY_MAC_ID); + if (!link_peer) { + status = QDF_STATUS_E_INVAL; + goto end; + } + + status = wlan_mlo_peer_create(vdev, link_peer, &partner_info, NULL, 0); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("MLO peer creation failed"); + + wlan_objmgr_peer_release_ref(link_peer, WLAN_LEGACY_MAC_ID); + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return status; +} + +void +lim_mlo_roam_delete_link_peer(struct pe_session *pe_session, + tpDphHashNode sta_ds) +{ + struct wlan_objmgr_peer *peer = NULL; + struct mac_context *mac; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return; + } + if (!pe_session) { + pe_err("pe session is null"); + return; + } + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + + peer = wlan_objmgr_get_peer_by_mac(mac->psoc, + sta_ds->staAddr, + WLAN_LEGACY_MAC_ID); + if (!peer) { + mlo_err("Peer is null"); + return; + } + + wlan_mlo_link_peer_delete(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} +#endif + +void lim_update_omn_ie_ch_width(struct wlan_objmgr_vdev *vdev, + enum phy_ch_width ch_width) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + mlme_legacy_err("vdev legacy private object is NULL"); + return; + } + + mlme_priv->connect_info.assoc_chan_info.omn_ie_ch_width = ch_width; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static bool +lim_match_link_info(uint8_t req_link_id, + struct qdf_mac_addr *link_addr, + struct mlo_partner_info *partner_info) +{ + uint8_t i; + + for (i = 0; i < partner_info->num_partner_links; i++) { + if (partner_info->partner_link_info[i].link_id == req_link_id && + (qdf_is_macaddr_equal(link_addr, + &partner_info->partner_link_info[i].link_addr))) + return true; + } + + return false; +} + +QDF_STATUS +lim_add_bcn_probe(struct wlan_objmgr_vdev *vdev, uint8_t *bcn_probe, + uint32_t len, qdf_freq_t freq, int32_t rssi) +{ + qdf_nbuf_t buf; + struct wlan_objmgr_pdev *pdev; + uint8_t *data, i, vdev_id; + struct mgmt_rx_event_params rx_param = {0}; + struct wlan_frame_hdr *hdr; + enum mgmt_frame_type frm_type = MGMT_BEACON; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev_id = wlan_vdev_get_id(vdev); + if (!bcn_probe || !len || (len < sizeof(*hdr)) || + len > MAX_MGMT_MPDU_LEN) { + pe_err("bcn_probe is null or invalid len %d", + len); + return QDF_STATUS_E_FAILURE; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + pe_err("Failed to find pdev"); + return QDF_STATUS_E_FAILURE; + } + + hdr = (struct wlan_frame_hdr *)bcn_probe; + if ((hdr->i_fc[0] & QDF_IEEE80211_FC0_SUBTYPE_MASK) == + MGMT_SUBTYPE_PROBE_RESP) + frm_type = MGMT_PROBE_RESP; + + rx_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + rx_param.chan_freq = freq; + rx_param.rssi = rssi; + + /* Set all per chain rssi as invalid */ + for (i = 0; i < WLAN_MGMT_TXRX_HOST_MAX_ANTENNA; i++) + rx_param.rssi_ctl[i] = WLAN_INVALID_PER_CHAIN_RSSI; + + buf = qdf_nbuf_alloc(NULL, qdf_roundup(len, 4), 0, 4, false); + if (!buf) + return QDF_STATUS_E_FAILURE; + + qdf_nbuf_put_tail(buf, len); + qdf_nbuf_set_protocol(buf, ETH_P_CONTROL); + + data = qdf_nbuf_data(buf); + qdf_mem_copy(data, bcn_probe, len); + + pe_debug("MLO: add prb rsp to scan db"); + /* buf will be freed by scan module in error or success case */ + status = wlan_scan_process_bcn_probe_rx_sync(wlan_pdev_get_psoc(pdev), buf, + &rx_param, frm_type); + + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +lim_validate_probe_rsp_link_info(struct pe_session *session_entry, + uint8_t *probe_rsp, + uint32_t probe_rsp_len) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t *ml_ie = NULL; + qdf_size_t ml_ie_total_len; + struct mlo_partner_info partner_info; + uint8_t i; + struct mlo_partner_info ml_partner_info; + + status = util_find_mlie(probe_rsp + WLAN_PROBE_RESP_IES_OFFSET, + probe_rsp_len - WLAN_PROBE_RESP_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Mlo ie not found in Probe response"); + return status; + } + status = util_get_bvmlie_persta_partner_info(ml_ie, + ml_ie_total_len, + &partner_info); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Per STA profile parsing failed"); + return status; + } + + ml_partner_info = session_entry->lim_join_req->partner_info; + for (i = 0; i < ml_partner_info.num_partner_links; i++) { + if (!lim_match_link_info(ml_partner_info.partner_link_info[i].link_id, + &ml_partner_info.partner_link_info[i].link_addr, + &partner_info)) { + pe_err("Atleast one Per-STA profile is missing in the ML-probe response"); + return QDF_STATUS_E_PROTO; + } + } + + return status; +} + +static void +lim_clear_ml_partner_info(struct pe_session *session_entry) +{ + uint8_t idx; + struct mlo_partner_info *partner_info = NULL; + + if (!session_entry || !session_entry->lim_join_req) + return; + + partner_info = &session_entry->lim_join_req->partner_info; + if (!partner_info) { + pe_err("Partner link info not present"); + return; + } + pe_debug_rl("Clear Partner Link/s information"); + for (idx = 0; idx < partner_info->num_partner_links; idx++) { + mlo_mgr_clear_ap_link_info(session_entry->vdev, + partner_info->partner_link_info[idx].link_addr.bytes); + + partner_info->partner_link_info[idx].link_id = 0; + qdf_zero_macaddr( + &partner_info->partner_link_info[idx].link_addr); + } + partner_info->num_partner_links = 0; +} + +static QDF_STATUS +lim_check_scan_db_for_join_req_partner_info(struct pe_session *session_entry, + struct mac_context *mac_ctx) +{ + struct join_req *lim_join_req; + struct wlan_objmgr_pdev *pdev; + struct mlo_partner_info *partner_info; + struct mlo_link_info *link_info; + struct scan_cache_entry *partner_entry; + uint8_t i; + + if (!session_entry) { + pe_err("session entry is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!mac_ctx) { + pe_err("mac context is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + lim_join_req = session_entry->lim_join_req; + if (!lim_join_req) { + pe_err("join req is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + pdev = mac_ctx->pdev; + if (!pdev) { + pe_err("pdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + partner_info = &lim_join_req->partner_info; + for (i = 0; i < partner_info->num_partner_links; i++) { + link_info = &partner_info->partner_link_info[i]; + partner_entry = + wlan_scan_get_entry_by_bssid(pdev, + &link_info->link_addr); + if (!partner_entry) { + pe_err("Scan entry is not found for partner link %d " + QDF_MAC_ADDR_FMT, + link_info->link_id, + QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); + return QDF_STATUS_E_FAILURE; + } + util_scan_free_cache_entry(partner_entry); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_update_mlo_mgr_info(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *link_addr, + uint8_t link_id, uint16_t freq) +{ + struct wlan_objmgr_pdev *pdev; + struct scan_cache_entry *cache_entry; + struct wlan_channel channel; + bool is_security_allowed; + + pdev = mac_ctx->pdev; + if (!pdev) { + pe_err("pdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + cache_entry = wlan_scan_get_scan_entry_by_mac_freq(pdev, link_addr, + freq); + if (!cache_entry) + return QDF_STATUS_E_FAILURE; + + /** + * Reject all the partner link if any partner link doesn’t pass the + * security check and proceed connection with single link. + */ + is_security_allowed = + wlan_cm_is_eht_allowed_for_current_security( + wlan_pdev_get_psoc(mac_ctx->pdev), + cache_entry, true); + + if (!is_security_allowed) { + mlme_debug("current security is not valid for partner link link_addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(link_addr->bytes)); + util_scan_free_cache_entry(cache_entry); + return QDF_STATUS_E_FAILURE; + } + + channel.ch_freq = cache_entry->channel.chan_freq; + channel.ch_ieee = wlan_reg_freq_to_chan(pdev, channel.ch_freq); + channel.ch_phymode = cache_entry->phy_mode; + channel.ch_cfreq1 = cache_entry->channel.cfreq0; + channel.ch_cfreq2 = cache_entry->channel.cfreq1; + channel.ch_width = + wlan_mlme_get_ch_width_from_phymode(cache_entry->phy_mode); + + /* + * Supplicant needs non zero center_freq1 in case of 20 MHz connection + * also as a response of get_channel request. In case of 20 MHz channel + * width central frequency is same as channel frequency + */ + if (channel.ch_width == CH_WIDTH_20MHZ) + channel.ch_cfreq1 = channel.ch_freq; + + util_scan_free_cache_entry(cache_entry); + + mlo_mgr_update_ap_channel_info(vdev, link_id, (uint8_t *)link_addr, + channel); + + return QDF_STATUS_SUCCESS; +} +#else +static inline void +lim_clear_ml_partner_info(struct pe_session *session_entry) +{ +} + +static QDF_STATUS +lim_check_db_for_join_req_partner_info(struct pe_session *session_entry, + struct mac_context *mac_ctx) +{ + + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS lim_check_for_ml_probe_req(struct pe_session *session) +{ + if (!session || !session->lim_join_req) + return QDF_STATUS_E_NULL_VALUE; + + if (session->lim_join_req->is_ml_probe_req_sent) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +static QDF_STATUS lim_check_partner_link_for_cmn_akm(struct pe_session *session) +{ + struct scan_filter *filter; + qdf_list_t *scan_list = NULL; + struct wlan_objmgr_pdev *pdev; + uint8_t idx; + struct mlo_link_info *link_info; + struct scan_cache_entry *cur_entry; + struct scan_cache_node *link_node; + struct mlo_partner_info *partner_info; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pdev = wlan_vdev_get_pdev(session->vdev); + if (!pdev) { + pe_err("PDEV NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + cur_entry = + wlan_cm_get_curr_candidate_entry(session->vdev, session->cm_id); + if (!cur_entry) { + pe_err("Current candidate NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) { + status = QDF_STATUS_E_NOMEM; + goto mem_free; + } + + partner_info = &session->lim_join_req->partner_info; + for (idx = 0; idx < partner_info->num_partner_links; idx++) { + link_info = &partner_info->partner_link_info[idx]; + qdf_copy_macaddr(&filter->bssid_list[idx], + &link_info->link_addr); + filter->num_of_bssid++; + + filter->chan_freq_list[idx] = link_info->chan_freq; + filter->num_of_channels++; + } + + /* If no.of. scan entries fetched not equal to no.of partner links + * then fail as common AKM is not determined. + */ + scan_list = wlan_scan_get_result(pdev, filter); + qdf_mem_free(filter); + if (!scan_list || + (qdf_list_size(scan_list) != partner_info->num_partner_links)) { + status = QDF_STATUS_E_INVAL; + goto mem_free; + } + + qdf_list_peek_front(scan_list, &cur_node); + while (cur_node) { + qdf_list_peek_next(scan_list, cur_node, &next_node); + link_node = qdf_container_of(cur_node, struct scan_cache_node, + node); + + if (!wlan_scan_entries_contain_cmn_akm(cur_entry, + link_node->entry)) { + status = QDF_STATUS_E_FAILURE; + break; + } + + cur_node = next_node; + next_node = NULL; + } + +mem_free: + if (scan_list) + wlan_scan_purge_results(scan_list); + util_scan_free_cache_entry(cur_entry); + return status; +} + +QDF_STATUS lim_gen_link_specific_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirProbeRespBeacon rcvd_probe_resp, + uint8_t *probe_rsp, + uint32_t probe_rsp_len, int32_t rssi) +{ + struct element_info link_probe_rsp = {0}; + struct qdf_mac_addr sta_link_addr; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mlo_link_info *link_info = NULL; + struct mlo_partner_info *partner_info; + uint8_t chan; + uint8_t op_class; + uint16_t chan_freq, gen_frame_len; + uint8_t idx; + uint8_t req_link_id; + + if (!session_entry) + return QDF_STATUS_E_NULL_VALUE; + + if (!session_entry->lim_join_req) + return status; + + partner_info = &session_entry->lim_join_req->partner_info; + if (!partner_info->num_partner_links) { + pe_debug("No partner link info since supports 1 link only"); + return status; + } + + if (session_entry->lim_join_req->is_ml_probe_req_sent && + rcvd_probe_resp->mlo_ie.mlo_ie_present) { + session_entry->lim_join_req->is_ml_probe_req_sent = false; + + partner_info = &session_entry->lim_join_req->partner_info; + if (!partner_info->num_partner_links) { + pe_err("STA doesn't have any partner link information"); + return QDF_STATUS_E_FAILURE; + } + + status = lim_validate_probe_rsp_link_info(session_entry, + probe_rsp, + probe_rsp_len); + if (QDF_IS_STATUS_ERROR(status)) { + if(QDF_IS_STATUS_ERROR( + lim_check_scan_db_for_join_req_partner_info( + session_entry, + mac_ctx))) + lim_clear_ml_partner_info(session_entry); + return status; + } + + /* + * When an MLO probe response is received from a link, + * the other link might be superior in features compared to the + * link that sent ML probe rsp and the per-STA profile + * info may carry corresponding IEs. These IEs are extracted + * and added to IE list of link probe response while generating + * it. So, the new link probe response generated might be of + * more size than the original link probe rsp. Allocate buffer + * for the scan entry to accommodate all of the IEs got + * generated as part of link probe rsp generation. Allocate + * MAX_MGMT_MPDU_LEN bytes for IEs as the max frame size that + * can be received from AP is MAX_MGMT_MPDU_LEN bytes. + */ + gen_frame_len = MAX_MGMT_MPDU_LEN; + + link_probe_rsp.ptr = qdf_mem_malloc(gen_frame_len); + if (!link_probe_rsp.ptr) { + if(QDF_IS_STATUS_ERROR( + lim_check_scan_db_for_join_req_partner_info( + session_entry, + mac_ctx))) + lim_clear_ml_partner_info(session_entry); + return QDF_STATUS_E_NOMEM; + } + + link_probe_rsp.len = gen_frame_len; + qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + for (idx = 0; idx < partner_info->num_partner_links; idx++) { + req_link_id = + partner_info->partner_link_info[idx].link_id; + status = util_gen_link_probe_rsp(probe_rsp, + probe_rsp_len, req_link_id, + sta_link_addr, link_probe_rsp.ptr, + gen_frame_len, + (qdf_size_t *)&link_probe_rsp.len); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("MLO: Link %d probe resp gen failed %d", + req_link_id, status); + status = + lim_check_scan_db_for_join_req_partner_info( + session_entry, mac_ctx); + if (QDF_IS_STATUS_ERROR(status)) + lim_clear_ml_partner_info(session_entry); + + goto end; + } + + pe_debug("MLO:link probe rsp size:%u orig probe rsp:%u", + link_probe_rsp.len, probe_rsp_len); + + link_info = &partner_info->partner_link_info[idx]; + wlan_get_chan_by_bssid_from_rnr(session_entry->vdev, + session_entry->cm_id, + &link_info->link_addr, + &chan, &op_class); + if (!chan) + wlan_get_chan_by_link_id_from_rnr( + session_entry->vdev, + session_entry->cm_id, + link_info->link_id, + &chan, &op_class); + if (!chan) { + pe_err("Invalid link id %d link mac: " QDF_MAC_ADDR_FMT, + link_info->link_id, + QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); + status = + lim_check_scan_db_for_join_req_partner_info( + session_entry, mac_ctx); + if (QDF_IS_STATUS_ERROR(status)) + lim_clear_ml_partner_info(session_entry); + + status = QDF_STATUS_E_FAILURE; + goto end; + } + chan_freq = + wlan_reg_chan_opclass_to_freq(chan, op_class, + true); + + status = lim_add_bcn_probe(session_entry->vdev, + link_probe_rsp.ptr, + link_probe_rsp.len, + chan_freq, rssi); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to add bcn probe %d", status); + status = + lim_check_scan_db_for_join_req_partner_info( + session_entry, mac_ctx); + if (QDF_IS_STATUS_ERROR(status)) + lim_clear_ml_partner_info(session_entry); + + goto end; + } + + status = lim_update_mlo_mgr_info(mac_ctx, + session_entry->vdev, + &link_info->link_addr, + link_info->link_id, + link_info->chan_freq); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to update mlo_mgr %d", status); + lim_clear_ml_partner_info(session_entry); + + goto end; + } + } + /* + * If the partner link's AKM not matching current candidate + * remove the partner links for this association. + */ + status = lim_check_partner_link_for_cmn_akm(session_entry); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Non overlapping partner link AKM %d", + status); + lim_clear_ml_partner_info(session_entry); + goto end; + } + } else if (session_entry->lim_join_req->is_ml_probe_req_sent && + !rcvd_probe_resp->mlo_ie.mlo_ie_present) { + status = + lim_check_scan_db_for_join_req_partner_info( + session_entry, mac_ctx); + if (QDF_IS_STATUS_ERROR(status)) + lim_clear_ml_partner_info(session_entry); + + return QDF_STATUS_E_FAILURE; + } else { + return status; + } +end: + if (link_probe_rsp.ptr) + qdf_mem_free(link_probe_rsp.ptr); + link_probe_rsp.ptr = NULL; + link_probe_rsp.len = 0; + return status; +} + +QDF_STATUS +lim_process_cu_for_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *probe_rsp, + uint32_t probe_rsp_len) +{ + struct element_info link_probe_rsp; + struct qdf_mac_addr sta_link_addr; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_vdev *partner_vdev; + uint8_t *ml_ie = NULL; + qdf_size_t ml_ie_total_len = 0; + struct mlo_partner_info partner_info; + uint8_t i, link_id, vdev_id; + uint8_t bpcc, aui; + bool cu_flag = false; + const uint8_t *rnr; + bool msd_cap_found = false; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + vdev = session->vdev; + if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return status; + + rnr = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_REDUCED_NEIGHBOR_REPORT, + probe_rsp + WLAN_PROBE_RESP_IES_OFFSET, + probe_rsp_len - WLAN_PROBE_RESP_IES_OFFSET); + if (!rnr) + return status; + + status = util_find_mlie(probe_rsp + WLAN_PROBE_RESP_IES_OFFSET, + probe_rsp_len - WLAN_PROBE_RESP_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Mlo ie not found in Probe response"); + return status; + } + + util_get_bvmlie_msd_cap(ml_ie, ml_ie_total_len, &msd_cap_found, + NULL); + if (msd_cap_found) { + wlan_vdev_mlme_cap_clear(vdev, WLAN_VDEV_C_EMLSR_CAP); + pe_debug("EMLSR not supported with D2.0 AP"); + } + + status = util_get_bvmlie_persta_partner_info(ml_ie, + ml_ie_total_len, + &partner_info); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Per STA profile parsing failed"); + return status; + } + + link_probe_rsp.ptr = qdf_mem_malloc(probe_rsp_len); + if (!link_probe_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + for (i = 0; i < partner_info.num_partner_links; i++) { + link_id = partner_info.partner_link_info[i].link_id; + partner_vdev = mlo_get_vdev_by_link_id(vdev, link_id, + WLAN_LEGACY_MAC_ID); + if (!partner_vdev) { + pe_debug("No partner vdev for link id %d", link_id); + continue; + } + + status = lim_cu_info_from_rnr_per_link_id(rnr, link_id, + &bpcc, &aui); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("no cu info in rnr for link id %d", link_id); + goto ref_rel; + } + + cu_flag = lim_check_cu_happens(partner_vdev, bpcc); + if (!cu_flag) + goto ref_rel; + + vdev_id = wlan_vdev_get_id(partner_vdev); + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_debug("session is null for vdev id %d", vdev_id); + goto ref_rel; + } + + qdf_mem_copy(&sta_link_addr, session->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + link_probe_rsp.len = probe_rsp_len; + /* Todo: + * it needs to use link_id as parameter to generate + * specific probe rsp frame when api util_gen_link_probe_rsp + * updated. + */ + status = + util_gen_link_probe_rsp(probe_rsp, probe_rsp_len, link_id, + sta_link_addr, link_probe_rsp.ptr, + probe_rsp_len, + (qdf_size_t *)&link_probe_rsp.len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("MLO: Link probe response generation failed %d", + status); + goto ref_rel; + } + + lim_process_gen_probe_rsp_frame(mac_ctx, session, + link_probe_rsp.ptr, + link_probe_rsp.len); + +ref_rel: + wlan_objmgr_vdev_release_ref(partner_vdev, WLAN_LEGACY_MAC_ID); + } + + qdf_mem_free(link_probe_rsp.ptr); + link_probe_rsp.ptr = NULL; + link_probe_rsp.len = 0; + return status; +} +#endif + +#ifdef WLAN_FEATURE_SR +static +void lim_store_array_to_bit_map(uint64_t *val, uint8_t array[8]) +{ + uint32_t bit_map_0 = 0; + uint32_t bit_map_1 = 0; + + QDF_SET_BITS(bit_map_0, 0, SR_PADDING_BYTE, array[0]); + QDF_SET_BITS(bit_map_0, 8, SR_PADDING_BYTE, array[1]); + QDF_SET_BITS(bit_map_0, 16, SR_PADDING_BYTE, array[2]); + QDF_SET_BITS(bit_map_0, 24, SR_PADDING_BYTE, array[3]); + QDF_SET_BITS(bit_map_1, 0, SR_PADDING_BYTE, array[4]); + QDF_SET_BITS(bit_map_1, 8, SR_PADDING_BYTE, array[5]); + QDF_SET_BITS(bit_map_1, 16, SR_PADDING_BYTE, array[6]); + QDF_SET_BITS(bit_map_1, 24, SR_PADDING_BYTE, array[7]); + *val = (uint64_t) bit_map_0 | + (((uint64_t)bit_map_1) << 32); +} + +void lim_update_vdev_sr_elements(struct pe_session *session_entry, + tpDphHashNode sta_ds) +{ + uint8_t sr_ctrl; + uint8_t non_srg_max_pd_offset, srg_min_pd_offset, srg_max_pd_offset; + uint64_t srg_color_bit_map = 0; + uint64_t srg_partial_bssid_bit_map = 0; + tDot11fIEspatial_reuse *srp_ie = &sta_ds->parsed_ies.srp_ie; + + sr_ctrl = srp_ie->sr_value15_allow << 4 | + srp_ie->srg_info_present << 3 | + srp_ie->non_srg_offset_present << 2 | + srp_ie->non_srg_pd_sr_disallow << 1 | + srp_ie->psr_disallow; + non_srg_max_pd_offset = + srp_ie->non_srg_offset.info.non_srg_pd_max_offset; + srg_min_pd_offset = srp_ie->srg_info.info.srg_pd_min_offset; + srg_max_pd_offset = srp_ie->srg_info.info.srg_pd_max_offset; + lim_store_array_to_bit_map(&srg_color_bit_map, + srp_ie->srg_info.info.srg_color); + lim_store_array_to_bit_map(&srg_partial_bssid_bit_map, + srp_ie->srg_info.info.srg_partial_bssid); + pe_debug("Spatial Reuse Control field: %x Non-SRG Max PD Offset: %x SRG range %d - %d srg_color_bit_map:%llu srg_partial_bssid_bit_map: %llu", + sr_ctrl, non_srg_max_pd_offset, srg_min_pd_offset, + srg_max_pd_offset, srg_color_bit_map, + srg_partial_bssid_bit_map); + wlan_vdev_mlme_set_srg_partial_bssid_bit_map(session_entry->vdev, + srg_partial_bssid_bit_map); + wlan_vdev_mlme_set_srg_bss_color_bit_map(session_entry->vdev, + srg_color_bit_map); + wlan_vdev_mlme_set_sr_ctrl(session_entry->vdev, sr_ctrl); + wlan_vdev_mlme_set_non_srg_pd_offset(session_entry->vdev, + non_srg_max_pd_offset); + wlan_vdev_mlme_set_srg_pd_offset(session_entry->vdev, srg_max_pd_offset, + srg_min_pd_offset); + +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c new file mode 100644 index 0000000000..22e05ccc4a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.c @@ -0,0 +1,4878 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_assoc_utils.cc contains the utility functions + * LIM uses while processing (Re) Association messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "wni_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "cfg_ucfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_process_fils.h" + +#include "qdf_types.h" +#include "wma_types.h" +#include "lim_types.h" +#include "wlan_utility.h" +#include "wlan_mlme_api.h" +#include "wma.h" +#include "../../core/src/vdev_mgr_ops.h" + +#include +#include +#include +#include "sir_mac_prot_def.h" +#include "wlan_action_oui_public_struct.h" +#include "wlan_action_oui_main.h" + +/** + * lim_cmp_ssid() - utility function to compare SSIDs + * @rx_ssid: Received SSID + * @session_entry: Session entry + * + * This function is called in various places within LIM code + * to determine whether received SSID is same as SSID in use. + * + * Return: zero if SSID matched, non-zero otherwise. + */ +uint32_t lim_cmp_ssid(tSirMacSSid *rx_ssid, struct pe_session *session_entry) +{ + if (session_entry->ssId.length != rx_ssid->length) + return 1; + + return qdf_mem_cmp(rx_ssid->ssId, &session_entry->ssId.ssId, + session_entry->ssId.length); +} + +/** + * lim_compare_capabilities() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received capabilities + * match with local capabilities or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param pAssocReq - Pointer to received Assoc Req frame + * @param pLocalCapabs - Pointer to local capabilities + * + * @return status - true for Capabilitity match else false. + */ + +uint8_t +lim_compare_capabilities(struct mac_context *mac, + tSirAssocReq *pAssocReq, + tSirMacCapabilityInfo *pLocalCapabs, + struct pe_session *pe_session) +{ + if (LIM_IS_AP_ROLE(pe_session) && + (pAssocReq->capabilityInfo.ibss)) { + /* Requesting STA asserting IBSS capability. */ + pe_debug("Requesting STA asserting IBSS capability"); + return false; + } + /* Compare CF capabilities */ + if (pAssocReq->capabilityInfo.cfPollable || + pAssocReq->capabilityInfo.cfPollReq) { + /* AP does not support PCF functionality */ + pe_debug(" AP does not support PCF functionality"); + return false; + } + /* Compare short preamble capability */ + if (pAssocReq->capabilityInfo.shortPreamble && + (pAssocReq->capabilityInfo.shortPreamble != + pLocalCapabs->shortPreamble)) { + /* Allowing a STA requesting short preamble while */ + /* AP does not support it */ + } + + pe_debug("QoS in AssocReq: %d, local capabs qos: %d", + pAssocReq->capabilityInfo.qos, pLocalCapabs->qos); + + /* Compare QoS capability */ + if (pAssocReq->capabilityInfo.qos && + (pAssocReq->capabilityInfo.qos != pLocalCapabs->qos)) + pe_debug("Received unmatched QOS but cfg to suppress - continuing"); + + /* + * If AP supports shortSlot and if apple user has + * enforced association only from shortSlot station, + * then AP must reject any station that does not support + * shortSlot + */ + if (LIM_IS_AP_ROLE(pe_session) && + (pLocalCapabs->shortSlotTime == 1)) { + if (mac->mlme_cfg->feature_flags.accept_short_slot_assoc) { + if (pAssocReq->capabilityInfo.shortSlotTime != + pLocalCapabs->shortSlotTime) { + pe_err("AP rejects association as station doesn't support shortslot time"); + return false; + } + return false; + } + } + + return true; +} /****** end lim_compare_capabilities() ******/ + +/** + * lim_check_rx_basic_rates() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received rates in + * Assoc/Reassoc request frames include all BSS basic rates + * or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param rxRateSet - pointer to SSID structure + * + * @return status - true if ALL BSS basic rates are present in the + * received rateset else false. + */ + +uint8_t +lim_check_rx_basic_rates(struct mac_context *mac, tSirMacRateSet rxRateSet, + struct pe_session *pe_session) +{ + tSirMacRateSet *pRateSet, basicRate; + uint8_t i, j, k, match; + + pRateSet = qdf_mem_malloc(sizeof(tSirMacRateSet)); + if (!pRateSet) + return false; + + /* Copy operational rate set from session Entry */ + qdf_mem_copy(pRateSet->rate, (pe_session->rateSet.rate), + pe_session->rateSet.numRates); + + pRateSet->numRates = pe_session->rateSet.numRates; + + /* Extract BSS basic rateset from operational rateset */ + for (i = 0, j = 0; + ((i < pRateSet->numRates) && (i < SIR_MAC_MAX_NUMBER_OF_RATES)); + i++) { + if ((pRateSet->rate[i] & 0x80) == 0x80) { + /* msb is set, so this is a basic rate */ + basicRate.rate[j++] = pRateSet->rate[i]; + } + } + + /* + * For each BSS basic rate, find if it is present in the + * received rateset. + */ + for (k = 0; k < j; k++) { + match = 0; + for (i = 0; + ((i < rxRateSet.numRates) && + (i < SIR_MAC_MAX_NUMBER_OF_RATES)); i++) { + if ((rxRateSet.rate[i] | 0x80) == basicRate.rate[k]) + match = 1; + } + + if (!match) { + /* Free up memory allocated for rateset */ + qdf_mem_free((uint8_t *) pRateSet); + + return false; + } + } + + /* Free up memory allocated for rateset */ + qdf_mem_free((uint8_t *) pRateSet); + + return true; +} /****** end lim_check_rx_basic_rates() ******/ + +/** + * lim_check_mcs_set() + * + ***FUNCTION: + * This function is called during Association/Reassociation + * frame handling to determine whether received MCS rates in + * Assoc/Reassoc request frames includes all Basic MCS Rate Set or not. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param supportedMCSSet - pointer to Supported MCS Rate Set + * + * @return status - true if ALL MCS Basic Rate Set rates are present in the + * received rateset else false. + */ + +uint8_t lim_check_mcs_set(struct mac_context *mac, uint8_t *supportedMCSSet) +{ + uint8_t basicMCSSet[SIZE_OF_BASIC_MCS_SET] = { 0 }; + qdf_size_t cfg_len = 0; + uint8_t i; + uint8_t validBytes; + uint8_t lastByteMCSMask = 0x1f; + + cfg_len = mac->mlme_cfg->rates.basic_mcs_set.len; + if (wlan_mlme_get_cfg_str((uint8_t *)basicMCSSet, + &mac->mlme_cfg->rates.basic_mcs_set, + &cfg_len) != QDF_STATUS_SUCCESS) { + /* / Could not get Basic MCS rateset from CFG. Log error. */ + pe_err("could not retrieve Basic MCS rateset"); + return false; + } + + validBytes = VALID_MCS_SIZE / 8; + + /* check if all the Basic MCS Bits are set in supported MCS bitmap */ + for (i = 0; i < validBytes; i++) { + if ((basicMCSSet[i] & supportedMCSSet[i]) != basicMCSSet[i]) { + pe_warn("One of Basic MCS Set Rates is not supported by the Station"); + return false; + } + } + + /* check the last 5 bits of the valid MCS bitmap */ + if (((basicMCSSet[i] & lastByteMCSMask) & + (supportedMCSSet[i] & lastByteMCSMask)) != + (basicMCSSet[i] & lastByteMCSMask)) { + pe_warn("One of Basic MCS Set Rates is not supported by the Station"); + return false; + } + + return true; +} + +#define SECURITY_SUITE_TYPE_MASK 0xFF +#define SECURITY_SUITE_TYPE_WEP40 0x1 +#define SECURITY_SUITE_TYPE_TKIP 0x2 +#define SECURITY_SUITE_TYPE_CCMP 0x4 +#define SECURITY_SUITE_TYPE_WEP104 0x4 +#define SECURITY_SUITE_TYPE_GCMP 0x8 +#define SECURITY_SUITE_TYPE_GCMP_256 0x9 + +/** + *lim_del_peer_info() - remove all peer information from host driver and fw + * @mac: Pointer to Global MAC structure + * @pe_session: Pointer to PE Session entry + * + * @Return: QDF_STATUS + */ + +QDF_STATUS lim_del_peer_info(struct mac_context *mac, + struct pe_session *pe_session) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint16_t i; + uint32_t bitmap = 1 << CDP_PEER_DELETE_NO_SPECIAL; + bool peer_unmap_conf_support_enabled; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + + peer_unmap_conf_support_enabled = + cdp_cfg_get_peer_unmap_conf_support(soc); + + psoc = wlan_vdev_get_psoc(pe_session->vdev); + if (!psoc) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < pe_session->dph.dphHashTable.size; i++) { + tpDphHashNode sta_ds; + + sta_ds = dph_get_hash_entry(mac, i, + &pe_session->dph.dphHashTable); + if (!sta_ds) + continue; + + peer = wlan_objmgr_get_peer_by_mac(psoc, sta_ds->staAddr, + WLAN_LEGACY_MAC_ID); + if (peer) { + wma_peer_tbl_trans_add_entry(peer, false, NULL); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + } + + cdp_peer_teardown(soc, pe_session->vdev_id, sta_ds->staAddr); + if (peer_unmap_conf_support_enabled) + cdp_peer_delete_sync(soc, pe_session->vdev_id, + sta_ds->staAddr, + wma_peer_unmap_conf_cb, + bitmap); + else + cdp_peer_delete(soc, pe_session->vdev_id, + sta_ds->staAddr, bitmap); + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_del_sta_all(): Cleanup all peers associated with VDEV + * @mac: Pointer to Global MAC structure + * @pe_session: Pointer to PE Session entry + * + * @Return: QDF Status of operation + */ + +QDF_STATUS lim_del_sta_all(struct mac_context *mac, + struct pe_session *pe_session) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct vdev_mlme_obj *mlme_obj; + uint32_t i; + tpDphHashNode sta_ds; + + if (!LIM_IS_AP_ROLE(pe_session)) + return QDF_STATUS_E_INVAL; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) { + for (i = 1; i < pe_session->dph.dphHashTable.size; i++) { + sta_ds = dph_get_hash_entry( + mac, i, + &pe_session->dph.dphHashTable); + if (!sta_ds) + continue; + if (lim_is_mlo_conn(pe_session, sta_ds)) + lim_mlo_delete_link_peer(pe_session, sta_ds); + } + } + status = vdev_mgr_peer_delete_all_send(mlme_obj); + if (status != QDF_STATUS_SUCCESS) { + pe_err("failed status = %d", status); + return status; + } + + status = lim_del_peer_info(mac, pe_session); + + return status; +} + +QDF_STATUS +lim_cleanup_rx_path(struct mac_context *mac, tpDphHashNode sta, + struct pe_session *pe_session, bool delete_peer) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pe_debug("Cleanup Rx Path for AID: %d limSmeState: %d, mlmState: %d, delete_peer %d", + sta->assocId, pe_session->limSmeState, + sta->mlmStaContext.mlmState, delete_peer); + + pe_session->isCiscoVendorAP = false; + + if (mac->lim.gLimAddtsSent) { + MTRACE(mac_trace + (mac, TRACE_CODE_TIMER_DEACTIVATE, + pe_session->peSessionId, eLIM_ADDTS_RSP_TIMER)); + tx_timer_deactivate(&mac->lim.lim_timers.gLimAddtsRspTimer); + pe_debug("Reset gLimAddtsSent flag and send addts timeout to SME"); + lim_process_sme_addts_rsp_timeout(mac, + mac->lim.gLimAddtsRspTimerCount); + } + + if (sta->mlmStaContext.mlmState == eLIM_MLM_WT_ASSOC_CNF_STATE) { + lim_deactivate_and_change_per_sta_id_timer(mac, eLIM_CNF_WAIT_TIMER, + sta->assocId); + + if (!sta->mlmStaContext.updateContext) { + /** + * There is no context at Polaris to delete. + * Release our assigned AID back to the free pool + */ + if (LIM_IS_AP_ROLE(pe_session)) { + lim_del_sta(mac, sta, true, pe_session); + return retCode; + } + lim_delete_dph_hash_entry(mac, sta->staAddr, + sta->assocId, pe_session); + + return retCode; + } + } + /* delete all tspecs associated with this sta. */ + lim_admit_control_delete_sta(mac, sta->assocId); + + /** + * Make STA hash entry invalid at eCPU so that DPH + * does not process any more data packets and + * releases those BDs + */ + sta->valid = 0; + lim_send_sme_tsm_ie_ind(mac, pe_session, 0, 0, 0); + /* Any roaming related changes should be above this line */ + if (!delete_peer) + return QDF_STATUS_SUCCESS; + + sta->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + if (LIM_IS_STA_ROLE(pe_session)) { + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + pe_session->limMlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + /* Deactivating probe after heart beat timer */ + lim_deactivate_and_change_timer(mac, eLIM_JOIN_FAIL_TIMER); + } + + /* Do DEL BSS or DEL STA only if ADD BSS was success */ + if (!pe_session->add_bss_failed) { + if (pe_session->limSmeState == eLIM_SME_JOIN_FAILURE_STATE) { + retCode = + lim_del_bss(mac, sta, pe_session->vdev_id, + pe_session); + } else + retCode = lim_del_sta(mac, + sta, true, pe_session); + } + + return retCode; + +} /*** end lim_cleanup_rx_path() ***/ + +/** + * lim_send_del_sta_cnf() - Send Del sta confirmation + * @mac: Pointer to Global MAC structure + * @sta_dsaddr: sta ds address + * @sta_mld_addr: sta mld address + * @staDsAssocId: sta ds association id + * @mlmStaContext: MLM station context + * @status_code: Status code + * @pe_session: Session entry + * + * This function is called to send appropriate CNF message to SME. + * + * Return: None + */ +void +lim_send_del_sta_cnf(struct mac_context *mac, struct qdf_mac_addr sta_dsaddr, + struct qdf_mac_addr sta_mld_addr, + uint16_t staDsAssocId, + struct lim_sta_context mlmStaContext, + tSirResultCodes status_code, struct pe_session *pe_session) +{ + tLimMlmDisassocCnf mlmDisassocCnf; + tLimMlmDeauthCnf mlmDeauthCnf; + tLimMlmPurgeStaInd mlmPurgeStaInd; + + pe_debug("Sessionid: %d staDsAssocId: %d Trigger: %d status_code: %d sta_dsaddr: "QDF_MAC_ADDR_FMT, + pe_session->peSessionId, staDsAssocId, + mlmStaContext.cleanupTrigger, status_code, + QDF_MAC_ADDR_REF(sta_dsaddr.bytes)); + + if (LIM_IS_STA_ROLE(pe_session)) { + /* Set BSSID at CFG to null */ + tSirMacAddr nullAddr = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + sir_copy_mac_addr(nullAddr, pe_session->bssId); + + /* Free up buffer allocated for JoinReq held by */ + /* MLM state machine */ + if (pe_session->pLimMlmJoinReq) { + qdf_mem_free(pe_session->pLimMlmJoinReq); + pe_session->pLimMlmJoinReq = NULL; + } + + pe_session->limAID = 0; + } + + if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DISASSOC) || + (mlmStaContext.cleanupTrigger == + eLIM_PROMISCUOUS_MODE_DISASSOC)) { + qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmDisassocCnf.resultCode = status_code; + mlmDisassocCnf.disassocTrigger = mlmStaContext.cleanupTrigger; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_HOST_DEAUTH) || + (mlmStaContext.cleanupTrigger == + eLIM_LINK_MONITORING_DEAUTH)) { + qdf_copy_macaddr(&mlmDeauthCnf.peer_macaddr, &sta_dsaddr); + mlmDeauthCnf.resultCode = status_code; + mlmDeauthCnf.deauthTrigger = mlmStaContext.cleanupTrigger; + /* PE session Id */ + mlmDeauthCnf.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, + LIM_MLM_DEAUTH_CNF, + (uint32_t *) &mlmDeauthCnf); + } else if ((mlmStaContext.cleanupTrigger == + eLIM_PEER_ENTITY_DISASSOC) || + (mlmStaContext.cleanupTrigger == eLIM_PEER_ENTITY_DEAUTH)) { + qdf_mem_copy((uint8_t *) &mlmPurgeStaInd.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + mlmPurgeStaInd.reasonCode = + (uint8_t) mlmStaContext.disassocReason; + mlmPurgeStaInd.aid = staDsAssocId; + mlmPurgeStaInd.purgeTrigger = mlmStaContext.cleanupTrigger; + mlmPurgeStaInd.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, + LIM_MLM_PURGE_STA_IND, + (uint32_t *) &mlmPurgeStaInd); + } else if (mlmStaContext.cleanupTrigger == eLIM_JOIN_FAILURE) { + /* PE setup the peer entry in HW upfront, right after join is completed. */ + /* If there is a failure during rest of the assoc sequence, this context needs to be cleaned up. */ + uint8_t smesessionId; + + smesessionId = pe_session->smeSessionId; + pe_session->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, pe_session->peSessionId, + pe_session->limSmeState)); + + /* if it is a reassoc failure to join new AP */ + if ((mlmStaContext.resultCode == + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE) + || (mlmStaContext.resultCode == eSIR_SME_FT_REASSOC_FAILURE) + || (mlmStaContext.resultCode == + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE)) { + pe_debug("Lim Posting eWNI_SME_REASSOC_RSP to SME" + "resultCode: %d, status_code: %d," + "sessionId: %d", + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + pe_session->peSessionId); + + lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_REASSOC_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + pe_session, smesessionId); + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(mac, pe_session); + pe_session = NULL; + } + } else { + qdf_mem_free(pe_session->lim_join_req); + pe_session->lim_join_req = NULL; + + pe_debug("Lim Posting eWNI_SME_JOIN_RSP to SME." + "resultCode: %d,status_code: %d," + "sessionId: %d", + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + pe_session->peSessionId); + + lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_JOIN_RSP, + mlmStaContext.resultCode, + mlmStaContext.protStatusCode, + pe_session, smesessionId); + + if (mlmStaContext.resultCode != eSIR_SME_SUCCESS) { + pe_delete_session(mac, pe_session); + pe_session = NULL; + } + } + + } else if (mlmStaContext.cleanupTrigger == eLIM_DUPLICATE_ENTRY) { + + qdf_mem_copy((uint8_t *) &mlmDisassocCnf.peerMacAddr, + (uint8_t *) sta_dsaddr.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy((uint8_t *)&mlmDisassocCnf.peerMldAddr, + (uint8_t *)sta_mld_addr.bytes, QDF_MAC_ADDR_SIZE); + + mlmDisassocCnf.resultCode = status_code; + mlmDisassocCnf.disassocTrigger = eLIM_DUPLICATE_ENTRY; + /* Update PE session Id */ + mlmDisassocCnf.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, + LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlmDisassocCnf); + } + + if (pe_session && !LIM_IS_AP_ROLE(pe_session)) { + pe_delete_session(mac, pe_session); + pe_session = NULL; + } +} + +/** + * lim_reject_association() - function to reject Re/Association Request + * + * @mac_ctx: pointer to global mac structure + * @peer_addr: mac address of the peer + * @sub_type: Indicates whether it is Association Request (=0) or + * Reassociation Request (=1) frame + * @add_pre_auth_context:Indicates whether pre-auth context + * to be added for this STA + * @auth_type: Indicates auth type to be added + * @sta_id: Indicates staId of the STA being rejected + * association + * @delete_sta: Indicates whether to delete STA context + * at Polaris + * @result_code: Indicates what reasonCode to be sent in + * Re/Assoc response to STA + * @session_entry: pointer to PE session + * + * This function is called whenever Re/Association Request need + * to be rejected due to failure in assigning an AID or failure + * in adding STA context at Polaris or reject by applications. + * Resources allocated if any are freedup and (Re) Association + * Response frame is sent to requesting STA. Pre-Auth context + * will be added for this STA if it does not exist already + * + * Return: none + */ + +void +lim_reject_association(struct mac_context *mac_ctx, tSirMacAddr peer_addr, + uint8_t sub_type, uint8_t add_pre_auth_context, + tAniAuthType auth_type, uint16_t sta_id, + uint8_t delete_sta, enum wlan_status_code result_code, + struct pe_session *session_entry) +{ + tpDphHashNode sta_ds; + + pe_debug("Sessionid: %d auth_type: %d sub_type: %d add_pre_auth_context: %d sta_id: %d delete_sta: %d result_code : %d peer_addr: " QDF_MAC_ADDR_FMT, + session_entry->peSessionId, auth_type, sub_type, + add_pre_auth_context, sta_id, delete_sta, result_code, + QDF_MAC_ADDR_REF(peer_addr)); + + if (add_pre_auth_context) { + /* Create entry for this STA in pre-auth list */ + struct tLimPreAuthNode *auth_node; + + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + + if (auth_node) { + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + peer_addr, sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + auth_node->authType = (tAniAuthType) auth_type; + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + } + } + + sta_ds = dph_get_hash_entry(mac_ctx, sta_id, + &session_entry->dph.dphHashTable); + + if (delete_sta == false) { + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + STATUS_AP_UNABLE_TO_HANDLE_NEW_STA, + 1, peer_addr, sub_type, sta_ds, session_entry, + false); + pe_debug("Received Re/Assoc req when max associated STAs reached from " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, peer_addr, + session_entry->smeSessionId); + return; + } + + if (!sta_ds) { + pe_err("No STA context, yet rejecting Association"); + return; + } + + /* + * Polaris has state for this STA. + * Trigger cleanup. + */ + sta_ds->mlmStaContext.cleanupTrigger = eLIM_REASSOC_REJECT; + + /* Receive path cleanup */ + lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry, true); + + /* + * Send Re/Association Response with + * status code to requesting STA. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, result_code, 0, peer_addr, + sub_type, sta_ds, session_entry, false); + + if (session_entry->parsedAssocReq[sta_ds->assocId]) { + lim_free_assoc_req_frm_buf( + session_entry->parsedAssocReq[sta_ds->assocId]); + + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +void lim_free_assoc_req_frm_buf(tpSirAssocReq assoc_req) +{ + if (!assoc_req) + return; + if (assoc_req->assoc_req_buf) { + qdf_nbuf_free(assoc_req->assoc_req_buf); + assoc_req->assoc_req_buf = NULL; + assoc_req->assocReqFrame = NULL; + assoc_req->assocReqFrameLength = 0; + } +} + +bool lim_alloc_assoc_req_frm_buf(tpSirAssocReq assoc_req, + qdf_nbuf_t buf, uint32_t mac_header_len, + uint32_t frame_len) +{ + if (!assoc_req) + return false; + assoc_req->assoc_req_buf = qdf_nbuf_clone(buf); + if (!assoc_req->assoc_req_buf) + return false; + assoc_req->assocReqFrame = qdf_nbuf_data(assoc_req->assoc_req_buf) + + mac_header_len; + assoc_req->assocReqFrameLength = frame_len; + + return true; +} + +/** + * lim_decide_ap_protection_on_ht20_delete() - function to update protection + * parameters. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * protection related function while HT20 station is getting deleted. + * + * Return: none + */ +static void +lim_decide_ap_protection_on_ht20_delete(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + struct pe_session *session_entry) +{ + uint32_t i = 0; + + pe_debug("(%d) A HT 20 STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLimHt20Params.numSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + + if (session_entry->gLimHt20Params.numSta > 0) { + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!session_entry->protStaCache[i].active) + continue; + + if (!qdf_mem_cmp(session_entry->protStaCache[i].addr, + sta_ds->staAddr, sizeof(tSirMacAddr))) { + session_entry->gLimHt20Params.numSta--; + session_entry->protStaCache[i].active = + false; + break; + } + } + } + + if (session_entry->gLimHt20Params.numSta == 0) { + /* disable protection */ + pe_debug("No 11B STA exists, PESessionID %d", + session_entry->peSessionId); + lim_enable_ht20_protection(mac_ctx, false, false, beacon_params, + session_entry); + } +} + +/** + * lim_decide_ap_protection_on_delete() - update SAP protection on station + * deletion. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about protection related settings when a station is getting deleted. + * + * Return: none + */ +void +lim_decide_ap_protection_on_delete(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + struct pe_session *session_entry) +{ + uint32_t phy_mode; + tHalBitVal erp_enabled = eHAL_CLEAR; + enum reg_wifi_band rf_band = REG_BAND_UNKNOWN; + uint32_t i; + + if (!sta_ds) + return; + + lim_get_rf_band_new(mac_ctx, &rf_band, session_entry); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + erp_enabled = sta_ds->erpEnabled; + + if ((REG_BAND_5G == rf_band) && + (true == session_entry->htCapability) && + (session_entry->beaconParams.llaCoexist) && + (false == sta_ds->mlmStaContext.htCapability)) { + /* + * we are HT. if we are 11A, then protection is not required or + * we are HT and 11A station is leaving. + * protection consideration required. + * HT station leaving ==> this case is commonly handled + * between both the bands below. + */ + pe_debug("(%d) A 11A STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLim11aParams.numSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLim11aParams.numSta == 0) { + /* disable protection */ + lim_update_11a_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* we are HT or 11G and 11B station is getting deleted */ + if ((REG_BAND_2G == rf_band) && + (phy_mode == WNI_CFG_PHY_MODE_11G || + session_entry->htCapability) && + (erp_enabled == eHAL_CLEAR)) { + pe_debug("(%d) A legacy STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLim11bParams.numSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->gLim11bParams.numSta--; + session_entry->protStaCache[i].active = + false; + break; + } + } + + if (session_entry->gLim11bParams.numSta == 0) { + /* disable protection */ + lim_enable11g_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* + * we are HT AP and non-11B station is leaving. + * 11g station is leaving + */ + if ((REG_BAND_2G == rf_band) && + session_entry->htCapability && + !sta_ds->mlmStaContext.htCapability) { + pe_debug("(%d) A 11g STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLim11bParams.numSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->gLim11gParams.numSta--; + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLim11gParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_protection_from11g(mac_ctx, false, false, + beacon_params, + session_entry); + } + } + + if (!((true == session_entry->htCapability) && + (true == sta_ds->mlmStaContext.htCapability))) + return; + + /* + * Applies to 2.4 as well as 5 GHZ. + * HT non-GF leaving + */ + if (!sta_ds->htGreenfield) { + pe_debug("(%d) A non-GF STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLimNonGfParams.numSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLimNonGfParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_non_gf_protection(mac_ctx, false, false, + beacon_params, session_entry); + } + } + + /* + * Applies to 2.4 as well as 5 GHZ. + * HT 20Mhz station leaving + */ + if (session_entry->beaconParams.ht20Coexist && + (eHT_CHANNEL_WIDTH_20MHZ == + sta_ds->htSupportedChannelWidthSet)) { + lim_decide_ap_protection_on_ht20_delete(mac_ctx, sta_ds, + beacon_params, session_entry); + } + + /* + * Applies to 2.4 as well as 5 GHZ. + * LSIG TXOP not supporting staiton leaving + */ + if ((false == session_entry->beaconParams. + fLsigTXOPProtectionFullSupport) && + (false == sta_ds->htLsigTXOPProtection)) { + pe_debug("(%d) A HT LSIG not supporting STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLimLsigTxopParams.numSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->protStaCache[i].active && + (!qdf_mem_cmp( + session_entry->protStaCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->protStaCache[i].active = false; + break; + } + } + + if (session_entry->gLimLsigTxopParams.numSta == 0) { + /* disable protection */ + lim_enable_ht_lsig_txop_protection(mac_ctx, true, + false, beacon_params, session_entry); + } + } +} + +/** + * lim_decide_short_preamble() - update short preamble parameters + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about any short preamble related change because of new station + * joining. + * + * Return: None + */ +static void lim_decide_short_preamble(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + struct pe_session *session_entry) +{ + uint32_t i; + + if (sta_ds->shortPreambleEnabled == eHAL_CLEAR) { + pe_debug("(%d) A non-short preamble STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + session_entry->gLimNoShortParams.numNonShortPreambleSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->gLimNoShortParams. + staNoShortCache[i].active && + (!qdf_mem_cmp(session_entry-> + gLimNoShortParams. + staNoShortCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + session_entry->gLimNoShortParams. + numNonShortPreambleSta--; + session_entry->gLimNoShortParams. + staNoShortCache[i].active = false; + break; + } + } + + if (session_entry->gLimNoShortParams.numNonShortPreambleSta) + return; + + /* + * enable short preamble + * reset the cache + */ + qdf_mem_zero((uint8_t *) &session_entry->gLimNoShortParams, + sizeof(tLimNoShortParams)); + if (lim_enable_short_preamble(mac_ctx, true, + beacon_params, session_entry) != QDF_STATUS_SUCCESS) + pe_err("Cannot enable short preamble"); + } +} + +/** + * lim_decide_short_slot() - update short slot time related parameters + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @beacon_params: ap beacon parameters + * @session_entry: pe session entry + * + * Decides about any short slot time related change because of station leaving + * the BSS. + * Return: None + */ +static void +lim_decide_short_slot(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + tpUpdateBeaconParams beacon_params, + struct pe_session *session_entry) +{ + uint32_t i, val, non_short_slot_sta_count; + + if (sta_ds->shortSlotTimeEnabled != eHAL_CLEAR) + return; + + pe_debug("(%d) A non-short slottime STA is disassociated. Addr is "QDF_MAC_ADDR_FMT, + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + + val = mac_ctx->mlme_cfg->feature_flags.enable_short_slot_time_11g; + + if (LIM_IS_AP_ROLE(session_entry)) { + non_short_slot_sta_count = + session_entry->gLimNoShortSlotParams.numNonShortSlotSta; + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active && + (!qdf_mem_cmp(session_entry-> + gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + non_short_slot_sta_count--; + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active = false; + break; + } + } + + if (non_short_slot_sta_count == 0 && val) { + /* + * enable short slot time + * reset the cache + */ + qdf_mem_zero((uint8_t *) &session_entry-> + gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams)); + beacon_params->fShortSlotTime = true; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + session_entry->shortSlotTimeSupported = true; + } + session_entry->gLimNoShortSlotParams.numNonShortSlotSta = + non_short_slot_sta_count; + } else { + non_short_slot_sta_count = + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta; + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active && + (!qdf_mem_cmp( + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + sta_ds->staAddr, + sizeof(tSirMacAddr)))) { + non_short_slot_sta_count--; + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active = false; + break; + } + } + + if (val && !non_short_slot_sta_count) { + /* + * enable short slot time + * reset the cache + */ + qdf_mem_zero( + (uint8_t *) &mac_ctx->lim.gLimNoShortSlotParams, + sizeof(tLimNoShortSlotParams)); + /*in case of AP set SHORT_SLOT_TIME to enable*/ + if (LIM_IS_AP_ROLE(session_entry)) { + beacon_params->fShortSlotTime = true; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + session_entry->shortSlotTimeSupported = true; + } + } + mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta = + non_short_slot_sta_count; + } +} + +static uint8_t lim_get_nss_from_vht_mcs_map(uint16_t mcs_map) +{ + uint8_t nss = 0; + uint16_t mcs_mask = 0x3; + + for (nss = 0; nss < VHT_MAX_NSS; nss++) { + if ((mcs_map & mcs_mask) == mcs_mask) + return nss; + + mcs_mask = (mcs_mask << 2); + } + + return nss; +} + +static void lim_get_vht_gt80_nss(struct mac_context *mac_ctx, + struct sDphHashNode *sta_ds, + tDot11fIEVHTCaps *vht_caps, + struct pe_session *session) +{ + uint8_t nss; + + if (!vht_caps->vht_extended_nss_bw_cap) { + sta_ds->vht_160mhz_nss = 0; + sta_ds->vht_80p80mhz_nss = 0; + pe_debug("peer does not support vht extnd nss bw"); + + return; + } + + nss = lim_get_nss_from_vht_mcs_map(vht_caps->rxMCSMap); + + if (!nss) { + pe_debug("Invalid peer VHT MCS map %0X", vht_caps->rxMCSMap); + nss = 1; + } + + switch (vht_caps->supportedChannelWidthSet) { + case VHT_CAP_NO_160M_SUPP: + if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_80_HALF_NSS_160) { + sta_ds->vht_160mhz_nss = nss / 2; + sta_ds->vht_80p80mhz_nss = 0; + } else if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_80_HALF_NSS_80P80) { + sta_ds->vht_160mhz_nss = nss / 2; + sta_ds->vht_80p80mhz_nss = nss / 2; + } else if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_80_3QUART_NSS_80P80) { + sta_ds->vht_160mhz_nss = (nss * 3) / 4; + sta_ds->vht_80p80mhz_nss = (nss * 3) / 4; + } else { + sta_ds->vht_160mhz_nss = 0; + sta_ds->vht_80p80mhz_nss = 0; + } + break; + case VHT_CAP_160_SUPP: + sta_ds->vht_160mhz_nss = nss; + if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_160_HALF_NSS_80P80) { + sta_ds->vht_80p80mhz_nss = nss / 2; + } else if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_160_3QUART_NSS_80P80) { + sta_ds->vht_80p80mhz_nss = (nss * 3) / 4; + } else if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_2X_NSS_160_1X_NSS_80P80) { + if (nss > (VHT_MAX_NSS / 2)) { + pe_debug("Invalid extnd nss bw support val"); + sta_ds->vht_80p80mhz_nss = nss / 2; + break; + } + sta_ds->vht_160mhz_nss = nss * 2; + if (session->nss == MAX_VDEV_NSS) + break; + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2) + break; + session->nss *= 2; + } else { + sta_ds->vht_80p80mhz_nss = 0; + } + break; + case VHT_CAP_160_AND_80P80_SUPP: + if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_2X_NSS_80_1X_NSS_80P80) { + if (nss > (VHT_MAX_NSS / 2)) { + pe_debug("Invalid extnd nss bw support val"); + break; + } + if (session->nss == MAX_VDEV_NSS) + break; + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2) + break; + session->nss *= 2; + } else { + sta_ds->vht_160mhz_nss = nss; + sta_ds->vht_80p80mhz_nss = nss; + } + break; + default: + sta_ds->vht_160mhz_nss = 0; + sta_ds->vht_80p80mhz_nss = 0; + } + pe_debug("AP Nss config: 160MHz: %d, 80P80MHz %d", + sta_ds->vht_160mhz_nss, sta_ds->vht_80p80mhz_nss); + sta_ds->vht_160mhz_nss = QDF_MIN(sta_ds->vht_160mhz_nss, session->nss); + sta_ds->vht_80p80mhz_nss = QDF_MIN(sta_ds->vht_80p80mhz_nss, + session->nss); + pe_debug("Session Nss config: 160MHz: %d, 80P80MHz %d, session Nss %d", + sta_ds->vht_160mhz_nss, sta_ds->vht_80p80mhz_nss, + session->nss); +} + +QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEVHTCaps *peer_vht_caps, + struct pe_session *session_entry, + uint8_t nss, + struct sDphHashNode *sta_ds) +{ + uint32_t self_sta_dot11mode = 0; + uint16_t mcs_map_mask = MCSMAPMASK1x1; + uint16_t mcs_map_mask2x2 = 0; + struct mlme_vht_capabilities_info *vht_cap_info; + + self_sta_dot11mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + + if (!IS_DOT11_MODE_VHT(self_sta_dot11mode)) + return QDF_STATUS_SUCCESS; + + if (!peer_vht_caps || !peer_vht_caps->present) + return QDF_STATUS_SUCCESS; + + vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + + rates->vhtRxMCSMap = (uint16_t)vht_cap_info->rx_mcs_map; + rates->vhtTxMCSMap = (uint16_t)vht_cap_info->tx_mcs_map; + rates->vhtRxHighestDataRate = + (uint16_t)vht_cap_info->rx_supp_data_rate; + rates->vhtTxHighestDataRate = + (uint16_t)vht_cap_info->tx_supp_data_rate; + + if (NSS_1x1_MODE == nss) { + rates->vhtRxMCSMap |= VHT_MCS_1x1; + rates->vhtTxMCSMap |= VHT_MCS_1x1; + rates->vhtTxHighestDataRate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + rates->vhtRxHighestDataRate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + if (session_entry && !session_entry->ch_width && + !vht_cap_info->enable_vht20_mcs9 && + ((rates->vhtRxMCSMap & VHT_1x1_MCS_MASK) == + VHT_1x1_MCS9_MAP)) { + DISABLE_VHT_MCS_9(rates->vhtRxMCSMap, + NSS_1x1_MODE); + DISABLE_VHT_MCS_9(rates->vhtTxMCSMap, + NSS_1x1_MODE); + } + } else { + if (session_entry && !session_entry->ch_width && + !vht_cap_info->enable_vht20_mcs9 && + ((rates->vhtRxMCSMap & VHT_2x2_MCS_MASK) == + VHT_2x2_MCS9_MAP)) { + DISABLE_VHT_MCS_9(rates->vhtRxMCSMap, + NSS_2x2_MODE); + DISABLE_VHT_MCS_9(rates->vhtTxMCSMap, + NSS_2x2_MODE); + } + } + + if (peer_vht_caps->txSupDataRate) + rates->vhtTxHighestDataRate = + QDF_MIN(rates->vhtTxHighestDataRate, + peer_vht_caps->txSupDataRate); + if (peer_vht_caps->rxHighSupDataRate) + rates->vhtRxHighestDataRate = + QDF_MIN(rates->vhtRxHighestDataRate, + peer_vht_caps->rxHighSupDataRate); + + if (session_entry && session_entry->nss == NSS_2x2_MODE) + mcs_map_mask2x2 = MCSMAPMASK2x2; + + if ((peer_vht_caps->txMCSMap & mcs_map_mask) < + (rates->vhtRxMCSMap & mcs_map_mask)) { + rates->vhtRxMCSMap &= ~(mcs_map_mask); + rates->vhtRxMCSMap |= (peer_vht_caps->txMCSMap & mcs_map_mask); + } + if ((peer_vht_caps->rxMCSMap & mcs_map_mask) < + (rates->vhtTxMCSMap & mcs_map_mask)) { + rates->vhtTxMCSMap &= ~(mcs_map_mask); + rates->vhtTxMCSMap |= (peer_vht_caps->rxMCSMap & mcs_map_mask); + } + + if (mcs_map_mask2x2) { + uint16_t peer_mcs_map, self_mcs_map; + + peer_mcs_map = peer_vht_caps->txMCSMap & mcs_map_mask2x2; + self_mcs_map = rates->vhtRxMCSMap & mcs_map_mask2x2; + + if ((self_mcs_map != mcs_map_mask2x2) && + ((peer_mcs_map == mcs_map_mask2x2) || + (peer_mcs_map < self_mcs_map))) { + rates->vhtRxMCSMap &= ~mcs_map_mask2x2; + rates->vhtRxMCSMap |= peer_mcs_map; + } + + peer_mcs_map = (peer_vht_caps->rxMCSMap & mcs_map_mask2x2); + self_mcs_map = (rates->vhtTxMCSMap & mcs_map_mask2x2); + + if ((self_mcs_map != mcs_map_mask2x2) && + ((peer_mcs_map == mcs_map_mask2x2) || + (peer_mcs_map < self_mcs_map))) { + rates->vhtTxMCSMap &= ~mcs_map_mask2x2; + rates->vhtTxMCSMap |= peer_mcs_map; + } + } + + pe_debug("RxMCSMap %x TxMCSMap %x", rates->vhtRxMCSMap, + rates->vhtTxMCSMap); + + if (!session_entry) + return QDF_STATUS_SUCCESS; + + session_entry->supported_nss_1x1 = + ((rates->vhtTxMCSMap & VHT_MCS_1x1) == VHT_MCS_1x1) ? + true : false; + + if (!sta_ds || CH_WIDTH_80MHZ >= session_entry->ch_width) + return QDF_STATUS_SUCCESS; + + sta_ds->vht_extended_nss_bw_cap = + peer_vht_caps->vht_extended_nss_bw_cap; + lim_get_vht_gt80_nss(mac_ctx, sta_ds, peer_vht_caps, session_entry); + + return QDF_STATUS_SUCCESS; +} + +static void lim_dump_ht_mcs_mask(uint8_t *self_mcs, uint8_t *peer_mcs) +{ + uint32_t len = 0; + uint8_t idx; + uint8_t *buff; + uint32_t buff_len; + + /* + * Buffer of (SIR_MAC_MAX_SUPPORTED_MCS_SET * 5) + 1 to consider the 4 + * char MCS eg 0xff and 1 space after it and 1 to end the string with + * NULL. + */ + buff_len = (SIR_MAC_MAX_SUPPORTED_MCS_SET * 5) + 1; + buff = qdf_mem_malloc(buff_len); + if (!buff) + return; + + if (self_mcs) { + for (idx = 0; idx < SIR_MAC_MAX_SUPPORTED_MCS_SET; idx++) + len += qdf_scnprintf(buff + len, buff_len - len, + "0x%x ", self_mcs[idx]); + + pe_nofl_debug("SELF HT MCS: %s", buff); + } + + if (peer_mcs) { + len = 0; + for (idx = 0; idx < SIR_MAC_MAX_SUPPORTED_MCS_SET; idx++) + len += qdf_scnprintf(buff + len, buff_len - len, + "0x%x ", peer_mcs[idx]); + + pe_nofl_debug("PEER HT MCS: %s", buff); + } + + qdf_mem_free(buff); +} + +QDF_STATUS lim_populate_own_rate_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + uint8_t *supported_mcs_set, + uint8_t basic_only, + struct pe_session *session_entry, + struct sDot11fIEVHTCaps *vht_caps, + struct sDot11fIEhe_cap *he_caps, + struct sDot11fIEeht_cap *eht_caps) +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode = 0; + uint32_t self_sta_dot11mode = 0; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + qdf_size_t val_len; + + is_arate = 0; + + self_sta_dot11mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* + * Include 11b rates only when the device configured in + * auto, 11a/b/g or 11b_only + */ + if ((self_sta_dot11mode == MLME_DOT11_MODE_ALL) || + (self_sta_dot11mode == MLME_DOT11_MODE_11A) || + (self_sta_dot11mode == MLME_DOT11_MODE_11AC) || + (self_sta_dot11mode == MLME_DOT11_MODE_11N) || + (self_sta_dot11mode == MLME_DOT11_MODE_11G) || + (self_sta_dot11mode == MLME_DOT11_MODE_11B) || + (self_sta_dot11mode == MLME_DOT11_MODE_11AX)) { + val_len = mac_ctx->mlme_cfg->rates.supported_11b.len; + wlan_mlme_get_cfg_str((uint8_t *)&temp_rate_set.rate, + &mac_ctx->mlme_cfg->rates.supported_11b, + &val_len); + temp_rate_set.numRates = (uint8_t)val_len; + } else { + temp_rate_set.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_sta_dot11mode)) { + val_len = mac_ctx->mlme_cfg->rates.supported_11a.len; + wlan_mlme_get_cfg_str((uint8_t *)&temp_rate_set2.rate, + &mac_ctx->mlme_cfg->rates.supported_11a, + &val_len); + temp_rate_set2.numRates = (uint8_t)val_len; + } else { + temp_rate_set2.numRates = 0; + } + + if ((temp_rate_set.numRates + temp_rate_set2.numRates) > 12) { + pe_err("more than 12 rates in CFG"); + return QDF_STATUS_E_FAILURE; + } + /* copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /** + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in pSupportedRates + */ + + qdf_mem_zero(rates, sizeof(*rates)); + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + is_arate = 0; + + for (j = 0; (j < temp_rate_set.numRates) && + (j < SIR_MAC_MAX_NUMBER_OF_RATES); j++) { + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < + val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + } + + if (sirIsArate(temp_rate_set.rate[min] & 0x7f)) + is_arate = 1; + + if (is_arate) + rates->llaRates[a_rate_index++] = + temp_rate_set.rate[min]; + else + rates->llbRates[b_rate_index++] = + temp_rate_set.rate[min]; + temp_rate_set.rate[min] = 0xff; + } + + if (IS_DOT11_MODE_HT(self_sta_dot11mode)) { + val_len = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_mlme_get_cfg_str( + rates->supportedMCSSet, + &mac_ctx->mlme_cfg->rates.supported_mcs_set, + &val_len) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve supportedMCSSet"); + return QDF_STATUS_E_FAILURE; + } + + if (session_entry->nss == NSS_1x1_MODE) + rates->supportedMCSSet[1] = 0; + /* + * if supported MCS Set of the peer is passed in, + * then do the intersection + * else use the MCS set from local CFG. + */ + + if (supported_mcs_set) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + rates->supportedMCSSet[i] &= + supported_mcs_set[i]; + } + + lim_dump_ht_mcs_mask(rates->supportedMCSSet, NULL); + } + lim_populate_vht_mcs_set(mac_ctx, rates, vht_caps, session_entry, + session_entry->nss, NULL); + lim_populate_he_mcs_set(mac_ctx, rates, he_caps, + session_entry, session_entry->nss); + lim_populate_eht_mcs_set(mac_ctx, rates, eht_caps, + session_entry, session_entry->ch_width); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11AX +static bool lim_check_valid_mcs_for_nss(struct pe_session *session, + tDot11fIEhe_cap *he_caps) +{ + uint16_t mcs_map; + uint8_t mcs_count = 2, i; + + if (!session->he_capable || !he_caps || !he_caps->present) + return true; + + mcs_map = he_caps->rx_he_mcs_map_lt_80; + + do { + for (i = 0; i < session->nss; i++) { + if (((mcs_map >> (i * 2)) & 0x3) == 0x3) + return false; + } + + mcs_map = he_caps->tx_he_mcs_map_lt_80; + mcs_count--; + } while (mcs_count); + + if ((session->ch_width == CH_WIDTH_160MHZ || + lim_is_session_chwidth_320mhz(session)) && + !he_caps->chan_width_2) { + pe_err("session BW 160/320 MHz but peer BW less than 160 MHz"); + return false; + } + + return true; + +} +#else +static bool lim_check_valid_mcs_for_nss(struct pe_session *session, + tDot11fIEhe_cap *he_caps) +{ + return true; +} +#endif + +/** + * lim_remove_membership_selectors() - remove elements from rate set + * + * @rate_set: pointer to rate set + * + * Removes the BSS membership selector elements from the rate set, and keep + * only the rates + * + * Return: none + */ +static void lim_remove_membership_selectors(tSirMacRateSet *rate_set) +{ + int i, selector_count = 0; + + for (i = 0; i < rate_set->numRates; i++) { + if ((rate_set->rate[i] == (WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_HT_PHY)) || + (rate_set->rate[i] == (WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_VHT_PHY)) || + (rate_set->rate[i] == (WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_GLK)) || + (rate_set->rate[i] == (WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_EPD)) || + (rate_set->rate[i] == (WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_SAE_H2E)) || + (rate_set->rate[i] == (WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_HE_PHY))) + selector_count++; + + if (i + selector_count < rate_set->numRates) + rate_set->rate[i] = rate_set->rate[i + selector_count]; + } + rate_set->numRates -= selector_count; +} + +QDF_STATUS lim_populate_peer_rate_set(struct mac_context *mac, + struct supported_rates *pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + struct pe_session *pe_session, + tDot11fIEVHTCaps *pVHTCaps, + tDot11fIEhe_cap *he_caps, + tDot11fIEeht_cap *eht_caps, + struct sDphHashNode *sta_ds, + struct bss_description *bss_desc) +{ + tSirMacRateSet tempRateSet; + tSirMacRateSet tempRateSet2; + uint32_t i, j, val, min; + qdf_size_t val_len; + uint8_t aRateIndex = 0; + uint8_t bRateIndex = 0; + tDot11fIEhe_cap *peer_he_caps; + tSchBeaconStruct *pBeaconStruct = NULL; + + /* copy operational rate set from pe_session */ + if (pe_session->rateSet.numRates <= SIR_MAC_MAX_NUMBER_OF_RATES) { + qdf_mem_copy((uint8_t *) tempRateSet.rate, + (uint8_t *) (pe_session->rateSet.rate), + pe_session->rateSet.numRates); + tempRateSet.numRates = pe_session->rateSet.numRates; + } else { + pe_err("more than SIR_MAC_MAX_NUMBER_OF_RATES rates"); + return QDF_STATUS_E_FAILURE; + } + if ((pe_session->dot11mode == MLME_DOT11_MODE_11G) || + (pe_session->dot11mode == MLME_DOT11_MODE_11A) || + (pe_session->dot11mode == MLME_DOT11_MODE_11AC) || + (pe_session->dot11mode == MLME_DOT11_MODE_11N) || + (pe_session->dot11mode == MLME_DOT11_MODE_11AX)) { + if (pe_session->extRateSet.numRates <= + SIR_MAC_MAX_NUMBER_OF_RATES) { + qdf_mem_copy((uint8_t *) tempRateSet2.rate, + (uint8_t *) (pe_session->extRateSet. + rate), + pe_session->extRateSet.numRates); + tempRateSet2.numRates = + pe_session->extRateSet.numRates; + } else { + pe_err("numRates more than SIR_MAC_MAX_NUM_OF_RATES"); + return QDF_STATUS_E_FAILURE; + } + } else + tempRateSet2.numRates = 0; + + lim_remove_membership_selectors(&tempRateSet); + lim_remove_membership_selectors(&tempRateSet2); + + if ((tempRateSet.numRates + tempRateSet2.numRates) > + SIR_MAC_MAX_NUMBER_OF_RATES) { + pe_err("rates in CFG are more than SIR_MAC_MAX_NUM_OF_RATES"); + return QDF_STATUS_E_FAILURE; + } + + /* copy all rates in tempRateSet, there are 12 rates max */ + for (i = 0; i < tempRateSet2.numRates; i++) + tempRateSet.rate[i + tempRateSet.numRates] = + tempRateSet2.rate[i]; + tempRateSet.numRates += tempRateSet2.numRates; + /** + * Sort rates in tempRateSet (they are likely to be already sorted) + * put the result in pSupportedRates + */ + + qdf_mem_zero(pRates, sizeof(*pRates)); + for (i = 0; i < tempRateSet.numRates; i++) { + min = 0; + val = 0xff; + for (j = 0; (j < tempRateSet.numRates) && + (j < SIR_MAC_MAX_NUMBER_OF_RATES); j++) { + if ((uint32_t)(tempRateSet.rate[j] & 0x7f) < + val) { + val = tempRateSet.rate[j] & 0x7f; + min = j; + } + } + /* + * HAL needs to know whether the rate is basic rate or not, + * as it needs to update the response rate table accordingly. + * e.g. if one of the 11a rates is basic rate, then that rate + * can be used for sending control frames. HAL updates the + * response rate table whenever basic rate set is changed. + */ + if (basicOnly && !(tempRateSet.rate[min] & 0x80)) { + pe_debug("Invalid basic rate"); + } else if (sirIsArate(tempRateSet.rate[min] & 0x7f)) { + if (aRateIndex >= SIR_NUM_11A_RATES) { + pe_debug("OOB, aRateIndex: %d", aRateIndex); + } else if (aRateIndex >= 1 && (tempRateSet.rate[min] == + pRates->llaRates[aRateIndex - 1])) { + pe_debug("Duplicate 11a rate: %d", + tempRateSet.rate[min]); + } else { + pRates->llaRates[aRateIndex++] = + tempRateSet.rate[min]; + } + } else if (sirIsBrate(tempRateSet.rate[min] & 0x7f)) { + if (bRateIndex >= SIR_NUM_11B_RATES) { + pe_debug("OOB, bRateIndex: %d", bRateIndex); + } else if (bRateIndex >= 1 && (tempRateSet.rate[min] == + pRates->llbRates[bRateIndex - 1])) { + pe_debug("Duplicate 11b rate: %d", + tempRateSet.rate[min]); + } else { + pRates->llbRates[bRateIndex++] = + tempRateSet.rate[min]; + } + } else { + pe_debug("%d is neither 11a nor 11b rate", + tempRateSet.rate[min]); + } + tempRateSet.rate[min] = 0xff; + } + + if (IS_DOT11_MODE_HT(pe_session->dot11mode) && + !lim_is_he_6ghz_band(pe_session)) { + val_len = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_mlme_get_cfg_str( + pRates->supportedMCSSet, + &mac->mlme_cfg->rates.supported_mcs_set, + &val_len) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve supportedMCSSet"); + return QDF_STATUS_E_FAILURE; + } + if (pe_session->nss == NSS_1x1_MODE) + pRates->supportedMCSSet[1] = 0; + + /* if supported MCS Set of the peer is passed in, then do the + * intersection, else use the MCS set from local CFG. + */ + if (pSupportedMCSSet) { + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) + pRates->supportedMCSSet[i] &= + pSupportedMCSSet[i]; + } + + lim_dump_ht_mcs_mask(NULL, pRates->supportedMCSSet); + + if (pRates->supportedMCSSet[0] == 0) { + pe_debug("Incorrect MCS 0 - 7. They must be supported"); + pRates->supportedMCSSet[0] = 0xFF; + } + + pe_session->supported_nss_1x1 = + ((pRates->supportedMCSSet[1] != 0) ? false : true); + } + lim_populate_vht_mcs_set(mac, pRates, pVHTCaps, pe_session, + pe_session->nss, sta_ds); + + if (lim_check_valid_mcs_for_nss(pe_session, he_caps)) { + peer_he_caps = he_caps; + } else { + if (!bss_desc) { + pe_err("bssDescription is NULL"); + return QDF_STATUS_E_INVAL; + } + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!pBeaconStruct) + return QDF_STATUS_E_NOMEM; + + lim_extract_ap_capabilities( + mac, (uint8_t *)bss_desc->ieFields, + lim_get_ielen_from_bss_description(bss_desc), + pBeaconStruct); + peer_he_caps = &pBeaconStruct->he_cap; + } + + lim_populate_he_mcs_set(mac, pRates, peer_he_caps, + pe_session, pe_session->nss); + lim_populate_eht_mcs_set(mac, pRates, eht_caps, + pe_session, pe_session->ch_width); + + pe_debug("nss 1x1 %d nss %d", pe_session->supported_nss_1x1, + pe_session->nss); + + if (pBeaconStruct) + qdf_mem_free(pBeaconStruct); + + return QDF_STATUS_SUCCESS; +} /*** lim_populate_peer_rate_set() ***/ + +/** + * lim_populate_matching_rate_set() -process the CFG rate sets and + * the rate sets received in the Assoc request on AP. + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @oper_rate_set: pointer to operating rate set + * @ext_rate_set: pointer to extended rate set + * @supported_mcs_set: pointer to supported rate set + * @session_entry: pointer to pe session entry + * @vht_caps: pointer to vht capabilities + * @he_caps: pointer to he capabilities + * @eht_caps: pointer to eht capabilities + * + * This is called at the time of Association Request + * processing on AP and while adding peer's context + * in IBSS role to process the CFG rate sets and + * the rate sets received in the Assoc request on AP + * + * 1. It makes the intersection between our own rate set + * and extended rate set and the ones received in the + * association request. + * 2. It creates a combined rate set of 12 rates max which + * comprised the basic and extended rates + * 3. It sorts the combined rate Set and copy it in the + * rate array of the pSTA descriptor + * + * The parser has already ensured unicity of the rates in the + * association request structure + * + * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS_E_FAILURE + */ +QDF_STATUS lim_populate_matching_rate_set(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + tSirMacRateSet *oper_rate_set, + tSirMacRateSet *ext_rate_set, + uint8_t *supported_mcs_set, + struct pe_session *session_entry, + tDot11fIEVHTCaps *vht_caps, + tDot11fIEhe_cap *he_caps, + tDot11fIEeht_cap *eht_caps) +{ + tSirMacRateSet temp_rate_set; + tSirMacRateSet temp_rate_set2 = {0}; + uint32_t i, j, val, min, is_arate; + uint32_t phy_mode; + uint8_t mcs_set[SIZE_OF_SUPPORTED_MCS_SET]; + struct supported_rates *rates; + uint8_t a_rate_index = 0; + uint8_t b_rate_index = 0; + qdf_size_t val_len; + + is_arate = 0; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* copy operational rate set from session_entry */ + qdf_mem_copy((temp_rate_set.rate), (session_entry->rateSet.rate), + session_entry->rateSet.numRates); + temp_rate_set.numRates = (uint8_t) session_entry->rateSet.numRates; + + if (phy_mode == WNI_CFG_PHY_MODE_11G) { + qdf_mem_copy((temp_rate_set2.rate), + (session_entry->extRateSet.rate), + session_entry->extRateSet.numRates); + temp_rate_set2.numRates = + (uint8_t) session_entry->extRateSet.numRates; + } + + lim_remove_membership_selectors(&temp_rate_set); + lim_remove_membership_selectors(&temp_rate_set2); + + /* + * absolute sum of both num_rates should be less than 12. following + * 16-bit sum avoids false condition where 8-bit arithmetic overflow + * might have caused total sum to be less than 12 + */ + if (((uint16_t)temp_rate_set.numRates + + (uint16_t)temp_rate_set2.numRates) > SIR_MAC_MAX_NUMBER_OF_RATES) { + pe_err("more than 12 rates in CFG"); + return QDF_STATUS_E_FAILURE; + } + + /* + * Handling of the rate set IEs is the following: + * - keep only rates that we support and that the station supports + * - sort and the rates into the pSta->rate array + */ + + /* Copy all rates in temp_rate_set, there are 12 rates max */ + for (i = 0; i < temp_rate_set2.numRates; i++) + temp_rate_set.rate[i + temp_rate_set.numRates] = + temp_rate_set2.rate[i]; + + temp_rate_set.numRates += temp_rate_set2.numRates; + + /* + * Sort rates in temp_rate_set (they are likely to be already sorted) + * put the result in temp_rate_set2 + */ + temp_rate_set2.numRates = 0; + + for (i = 0; i < temp_rate_set.numRates; i++) { + min = 0; + val = 0xff; + + for (j = 0; j < temp_rate_set.numRates; j++) + if ((uint32_t) (temp_rate_set.rate[j] & 0x7f) < val) { + val = temp_rate_set.rate[j] & 0x7f; + min = j; + } + + temp_rate_set2.rate[temp_rate_set2.numRates++] = + temp_rate_set.rate[min]; + temp_rate_set.rate[min] = 0xff; + } + + /* + * Copy received rates in temp_rate_set, the parser has ensured + * unicity of the rates so there cannot be more than 12 + */ + for (i = 0; (i < oper_rate_set->numRates && + i < SIR_MAC_MAX_NUMBER_OF_RATES); i++) + temp_rate_set.rate[i] = oper_rate_set->rate[i]; + + temp_rate_set.numRates = oper_rate_set->numRates; + + pe_debug("Sum of SUPPORTED and EXTENDED Rate Set (%1d)", + temp_rate_set.numRates + ext_rate_set->numRates); + + if (ext_rate_set->numRates && + ((temp_rate_set.numRates + ext_rate_set->numRates) > 12) && + temp_rate_set.numRates < 12) { + int found = 0; + int tail = temp_rate_set.numRates; + + for (i = 0; (i < ext_rate_set->numRates && + i < SIR_MAC_MAX_NUMBER_OF_RATES); i++) { + found = 0; + for (j = 0; j < (uint32_t) tail; j++) { + if ((temp_rate_set.rate[j] & 0x7F) == + (ext_rate_set->rate[i] & 0x7F)) { + found = 1; + break; + } + } + + if (!found) { + temp_rate_set.rate[temp_rate_set.numRates++] = + ext_rate_set->rate[i]; + if (temp_rate_set.numRates >= 12) + break; + } + } + } else if (ext_rate_set->numRates && + ((temp_rate_set.numRates + ext_rate_set->numRates) <= 12)) { + for (j = 0; ((j < ext_rate_set->numRates) && + (j < SIR_MAC_MAX_NUMBER_OF_RATES) && + ((i + j) < SIR_MAC_MAX_NUMBER_OF_RATES)); j++) + temp_rate_set.rate[i + j] = ext_rate_set->rate[j]; + + temp_rate_set.numRates += ext_rate_set->numRates; + } else if (ext_rate_set->numRates) { + pe_debug("Relying only on the SUPPORTED Rate Set IE"); + } + + rates = &sta_ds->supportedRates; + qdf_mem_zero(rates, sizeof(*rates)); + for (i = 0; (i < temp_rate_set2.numRates && + i < SIR_MAC_MAX_NUMBER_OF_RATES); i++) { + for (j = 0; (j < temp_rate_set.numRates && + j < SIR_MAC_MAX_NUMBER_OF_RATES); j++) { + if ((temp_rate_set2.rate[i] & 0x7F) != + (temp_rate_set.rate[j] & 0x7F)) + continue; + + if (sirIsArate(temp_rate_set2.rate[i] & 0x7f) && + a_rate_index < SIR_NUM_11A_RATES) { + is_arate = 1; + rates->llaRates[a_rate_index++] = + temp_rate_set2.rate[i]; + } else if ((b_rate_index < SIR_NUM_11B_RATES) && + !(sirIsArate(temp_rate_set2.rate[i] & 0x7f))) { + rates->llbRates[b_rate_index++] = + temp_rate_set2.rate[i]; + } + break; + } + } + + /* + * Now add the Polaris rates only when Proprietary rates are enabled. + * compute the matching MCS rate set, if peer is 11n capable and self + * mode is 11n + */ +#ifdef FEATURE_WLAN_TDLS + if (sta_ds->mlmStaContext.htCapability) +#else + if (IS_DOT11_MODE_HT(session_entry->dot11mode) && + (sta_ds->mlmStaContext.htCapability)) +#endif + { + val_len = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_mlme_get_cfg_str( + mcs_set, + &mac_ctx->mlme_cfg->rates.supported_mcs_set, + &val_len) != QDF_STATUS_SUCCESS) { + pe_err("could not retrieve supportedMCSet"); + return QDF_STATUS_E_FAILURE; + } + + if (session_entry->nss == NSS_1x1_MODE) + mcs_set[1] = 0; + + for (i = 0; i < val_len; i++) + sta_ds->supportedRates.supportedMCSSet[i] = + mcs_set[i] & supported_mcs_set[i]; + + lim_dump_ht_mcs_mask(mcs_set, + sta_ds->supportedRates.supportedMCSSet); + } + lim_populate_vht_mcs_set(mac_ctx, &sta_ds->supportedRates, vht_caps, + session_entry, session_entry->nss, sta_ds); + lim_populate_he_mcs_set(mac_ctx, &sta_ds->supportedRates, he_caps, + session_entry, session_entry->nss); + lim_populate_eht_mcs_set(mac_ctx, &sta_ds->supportedRates, eht_caps, + session_entry, sta_ds->ch_width); + /* + * Set the erpEnabled bit if the phy is in G mode and at least + * one A rate is supported + */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && is_arate) + sta_ds->erpEnabled = eHAL_SET; + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_populate_vht_caps() - populates vht capabilities based on input + * capabilities + * @input_caps: input capabilities based on which we format the vht + * capabilities + * + * function to populate the supported vht capabilities. + * + * Return: vht capabilities derived based on input parameters. + */ +static uint32_t lim_populate_vht_caps(tDot11fIEVHTCaps input_caps) +{ + uint32_t vht_caps; + + vht_caps = ((input_caps.maxMPDULen << SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (input_caps.supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (input_caps.ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (input_caps.shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (input_caps.shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (input_caps.txSTBC << SIR_MAC_VHT_CAP_TXSTBC) | + (input_caps.rxSTBC << SIR_MAC_VHT_CAP_RXSTBC) | + (input_caps.suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (input_caps.suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (input_caps.csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (input_caps.numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (input_caps.muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (input_caps.muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (input_caps.vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (input_caps.htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (input_caps.maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (input_caps.vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (input_caps.rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (input_caps.txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (input_caps.extended_nss_bw_supp << + SIR_MAC_VHT_CAP_EXTD_NSS_BW)); + + return vht_caps; +} + +/** + * lim_update_he_stbc_capable() - Update stbc capable flag based on + * HE capability + * @add_sta_params: add sta related parameters + * + * Update stbc cpable flag based on HE capability + * + * Return: None + */ +#ifdef WLAN_FEATURE_11AX +static void lim_update_he_stbc_capable(tpAddStaParams add_sta_params) +{ + if (add_sta_params && + add_sta_params->he_capable && + add_sta_params->stbc_capable) + add_sta_params->stbc_capable = + add_sta_params->he_config.rx_stbc_lt_80mhz; +} + +static void lim_update_he_mcs_12_13(tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ + pe_debug("he_mcs_12_13_map %0x", sta_ds->he_mcs_12_13_map); + if (sta_ds->he_mcs_12_13_map) + add_sta_params->he_mcs_12_13_map = sta_ds->he_mcs_12_13_map; +} + +static bool lim_is_add_sta_params_he_capable(tpAddStaParams add_sta_params) +{ + return add_sta_params->he_capable; +} +#else +static void lim_update_he_stbc_capable(tpAddStaParams add_sta_params) +{} + +static void lim_update_he_mcs_12_13(tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{} + +static bool lim_is_add_sta_params_he_capable(tpAddStaParams add_sta_params) +{ + return false; +} +#endif + +#ifdef FEATURE_WLAN_TDLS +#ifdef WLAN_FEATURE_11BE +static void lim_add_tdls_sta_eht_config(tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ + if (add_sta_params->eht_capable) { + pe_debug("Adding tdls eht capabilities"); + qdf_mem_copy(&add_sta_params->eht_config, &sta_ds->eht_config, + sizeof(add_sta_params->eht_config)); + qdf_mem_copy(&add_sta_params->eht_op, &sta_ds->eht_op, + sizeof(add_sta_params->eht_op)); + } +} +#else +static void lim_add_tdls_sta_eht_config(tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ +} + +#endif +#ifdef WLAN_FEATURE_11AX +static void lim_add_tdls_sta_he_config(tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ + pe_debug("Adding tdls he capabilities"); + qdf_mem_copy(&add_sta_params->he_config, &sta_ds->he_config, + sizeof(add_sta_params->he_config)); +} + +static void lim_add_tdls_sta_6ghz_he_cap(struct mac_context *mac_ctx, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ + lim_update_he_6ghz_band_caps(mac_ctx, &sta_ds->he_6g_band_cap, + add_sta_params); +} + +#else +static void lim_add_tdls_sta_he_config(tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ +} + +static void lim_add_tdls_sta_6ghz_he_cap(struct mac_context *mac_ctx, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ +} +#endif /* WLAN_FEATURE_11AX */ +#endif /* FEATURE_WLAN_TDLS */ + +#ifdef WLAN_FEATURE_11BE +static bool lim_is_eht_connection_op_info_present(struct pe_session *pe_session, + tpSirAssocRsp assoc_rsp) +{ + if (IS_DOT11_MODE_EHT(pe_session->dot11mode) && + assoc_rsp->eht_op.present && + assoc_rsp->eht_op.eht_op_information_present) + return true; + + return false; +} +#else +static bool lim_is_eht_connection_op_info_present(struct pe_session *pe_session, + tpSirAssocRsp assoc_rsp) +{ + return false; +} +#endif + +#ifdef WLAN_SUPPORT_TWT +/** + * lim_update_peer_twt_caps() - Update peer twt caps to add sta params + * @add_sta_params: pointer to add sta params + * @session_entry: pe session entry + * + * Return: None + */ +static void lim_update_peer_twt_caps(tpAddStaParams add_sta_params, + struct pe_session *session_entry) +{ + add_sta_params->twt_requestor = session_entry->peer_twt_requestor; + add_sta_params->twt_responder = session_entry->peer_twt_responder; +} +#else +static inline void +lim_update_peer_twt_caps(tpAddStaParams add_sta_params, + struct pe_session *session_entry) +{} +#endif + +#ifdef WLAN_FEATURE_SR +/** + * lim_update_srp_ie() - Updates SRP IE to STA node + * @bp_rsp: pointer to probe response / beacon frame + * @sta_ds: STA Node + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_update_srp_ie(tSirProbeRespBeacon *bp_rsp, + tpDphHashNode sta_ds) +{ + QDF_STATUS status = QDF_STATUS_E_NOSUPPORT; + + if (bp_rsp->srp_ie.present) { + sta_ds->parsed_ies.srp_ie = bp_rsp->srp_ie; + status = QDF_STATUS_SUCCESS; + } + + return status; +} +#else +static QDF_STATUS lim_update_srp_ie(tSirProbeRespBeacon *bp_rsp, + tpDphHashNode sta_ds) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * lim_add_sta()- called to add an STA context at hardware + * @mac_ctx: pointer to global mac structure + * @sta_ds: station node + * @update_entry: set to true for updating the entry + * @session_entry: pe session entry + * + * This function is called to add an STA context at hardware + * whenever a STA is (Re) Associated. + * + * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS failure codes + */ + +QDF_STATUS +lim_add_sta(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, uint8_t update_entry, struct pe_session *session_entry) +{ + tpAddStaParams add_sta_params = NULL; + struct scheduler_msg msg_q = {0}; + QDF_STATUS ret_code = QDF_STATUS_SUCCESS; + tSirMacAddr sta_mac, *sta_Addr; + tpSirAssocReq assoc_req; + uint8_t i, nw_type_11b = 0; + const uint8_t *p2p_ie = NULL; + tDot11fIEVHTCaps vht_caps; + struct mlme_vht_capabilities_info *vht_cap_info; + + vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + + sir_copy_mac_addr(sta_mac, session_entry->self_mac_addr); + + add_sta_params = qdf_mem_malloc(sizeof(tAddStaParams)); + if (!add_sta_params) + return QDF_STATUS_E_NOMEM; + + if (LIM_IS_AP_ROLE(session_entry) || LIM_IS_NDI_ROLE(session_entry)) + sta_Addr = &sta_ds->staAddr; +#ifdef FEATURE_WLAN_TDLS + /* SystemRole shouldn't be matter if staType is TDLS peer */ + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) + sta_Addr = &sta_ds->staAddr; +#endif + else + sta_Addr = &sta_mac; + + qdf_mem_copy((uint8_t *) add_sta_params->staMac, + (uint8_t *) *sta_Addr, sizeof(tSirMacAddr)); + qdf_mem_copy((uint8_t *) add_sta_params->bssId, + session_entry->bssId, sizeof(tSirMacAddr)); + qdf_mem_copy(&add_sta_params->capab_info, + &sta_ds->mlmStaContext.capabilityInfo, + sizeof(add_sta_params->capab_info)); + + /* Copy legacy rates */ + qdf_mem_copy(&add_sta_params->supportedRates, + &sta_ds->supportedRates, + sizeof(sta_ds->supportedRates)); + + add_sta_params->assocId = sta_ds->assocId; + + add_sta_params->wmmEnabled = sta_ds->qosMode; + add_sta_params->listenInterval = sta_ds->mlmStaContext.listenInterval; + if (LIM_IS_AP_ROLE(session_entry) && + (sta_ds->mlmStaContext.subType == LIM_REASSOC)) { + /* + * TBD - need to remove this REASSOC check + * after fixinf rmmod issue + */ + add_sta_params->updateSta = sta_ds->mlmStaContext.updateContext; + } + sta_ds->valid = 0; + sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + add_sta_params->staType = sta_ds->staType; + + add_sta_params->updateSta = update_entry; + + add_sta_params->status = QDF_STATUS_SUCCESS; + + /* Update VHT/HT Capability */ + if (LIM_IS_AP_ROLE(session_entry)) { + add_sta_params->htCapable = + sta_ds->mlmStaContext.htCapability && + session_entry->htCapability; + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.vhtCapability && + session_entry->vhtCapability; + } +#ifdef FEATURE_WLAN_TDLS + /* SystemRole shouldn't be matter if staType is TDLS peer */ + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + add_sta_params->htCapable = sta_ds->mlmStaContext.htCapability; + add_sta_params->vhtCapable = + sta_ds->mlmStaContext.vhtCapability; + } +#endif + else { + add_sta_params->htCapable = session_entry->htCapability; + add_sta_params->vhtCapable = session_entry->vhtCapability; + } + + /* + * If HT client is connected to SAP DUT and self cap is NSS = 2 then + * disable ASYNC DBS scan by sending wmi_vdev_param_smps_intolerant + * to FW, because HT client's can't drop down chain using SMPS frames. + */ + if (!policy_mgr_is_hw_dbs_2x2_capable(mac_ctx->psoc) && + LIM_IS_AP_ROLE(session_entry) && + (STA_ENTRY_PEER == sta_ds->staType) && + !add_sta_params->vhtCapable && + (session_entry->nss == 2)) { + session_entry->ht_client_cnt++; + if (session_entry->ht_client_cnt == 1) { + wma_cli_set_command(session_entry->smeSessionId, + (int)wmi_vdev_param_smps_intolerant, + 1, VDEV_CMD); + } + } + + lim_update_sta_he_capable(mac_ctx, add_sta_params, sta_ds, + session_entry); + + lim_update_sta_eht_capable(mac_ctx, add_sta_params, sta_ds, + session_entry); + + lim_update_tdls_sta_eht_capable(mac_ctx, add_sta_params, sta_ds, + session_entry); + + lim_update_sta_mlo_info(session_entry, add_sta_params, sta_ds); + + add_sta_params->maxAmpduDensity = sta_ds->htAMpduDensity; + add_sta_params->maxAmpduSize = sta_ds->htMaxRxAMpduFactor; + add_sta_params->fShortGI20Mhz = sta_ds->htShortGI20Mhz; + add_sta_params->fShortGI40Mhz = sta_ds->htShortGI40Mhz; + add_sta_params->ch_width = sta_ds->ch_width; + add_sta_params->mimoPS = sta_ds->htMIMOPSState; + + if (add_sta_params->vhtCapable) { + if (sta_ds->vhtSupportedChannelWidthSet) + add_sta_params->ch_width = + sta_ds->vhtSupportedChannelWidthSet + 1; + + add_sta_params->vhtSupportedRxNss = sta_ds->vhtSupportedRxNss; + if (LIM_IS_AP_ROLE(session_entry) || + LIM_IS_P2P_DEVICE_GO(session_entry)) + add_sta_params->vhtSupportedRxNss = QDF_MIN( + add_sta_params->vhtSupportedRxNss, + session_entry->nss); + add_sta_params->vhtTxBFCapable = +#ifdef FEATURE_WLAN_TDLS + ((STA_ENTRY_PEER == sta_ds->staType) + || (STA_ENTRY_TDLS_PEER == sta_ds->staType)) ? + sta_ds->vhtBeamFormerCapable : + session_entry->vht_config.su_beam_formee; +#else + (STA_ENTRY_PEER == sta_ds->staType) ? + sta_ds->vhtBeamFormerCapable : + session_entry->vht_config.su_beam_formee; +#endif + add_sta_params->enable_su_tx_bformer = + sta_ds->vht_su_bfee_capable; + add_sta_params->vht_mcs_10_11_supp = + sta_ds->vht_mcs_10_11_supp; + } + +#ifdef FEATURE_WLAN_TDLS + if ((STA_ENTRY_PEER == sta_ds->staType) || + (STA_ENTRY_TDLS_PEER == sta_ds->staType)) +#else + if (STA_ENTRY_PEER == sta_ds->staType) +#endif + { + /* + * peer STA get the LDPC capability from sta_ds, + * which populated from + * HT/VHT capability + */ + if (add_sta_params->vhtTxBFCapable + && vht_cap_info->disable_ldpc_with_txbf_ap) { + add_sta_params->htLdpcCapable = 0; + add_sta_params->vhtLdpcCapable = 0; + } else { + if (session_entry->txLdpcIniFeatureEnabled & 0x1) + add_sta_params->htLdpcCapable = + sta_ds->htLdpcCapable; + else + add_sta_params->htLdpcCapable = 0; + + if (session_entry->txLdpcIniFeatureEnabled & 0x2) + add_sta_params->vhtLdpcCapable = + sta_ds->vhtLdpcCapable; + else + add_sta_params->vhtLdpcCapable = 0; + } + } else if (STA_ENTRY_SELF == sta_ds->staType) { + /* For Self STA get the LDPC capability from config.ini */ + add_sta_params->htLdpcCapable = + (session_entry->txLdpcIniFeatureEnabled & 0x01); + add_sta_params->vhtLdpcCapable = + ((session_entry->txLdpcIniFeatureEnabled >> 1) & 0x01); + } + + /* Update PE session ID */ + add_sta_params->sessionId = session_entry->peSessionId; + + /* Update SME session ID */ + add_sta_params->smesessionId = session_entry->smeSessionId; + + add_sta_params->maxTxPower = session_entry->maxTxPower; + + if (session_entry->parsedAssocReq) { + uint16_t aid = sta_ds->assocId; + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[aid]; + if (assoc_req && assoc_req->addIEPresent + && assoc_req->addIE.length) { + p2p_ie = limGetP2pIEPtr(mac_ctx, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + } + + add_sta_params->p2pCapableSta = (p2p_ie != NULL); + if (assoc_req && add_sta_params->htCapable) { + qdf_mem_copy(&add_sta_params->ht_caps, + ((uint8_t *) &assoc_req->HTCaps) + 1, + sizeof(add_sta_params->ht_caps)); + } + + if (assoc_req && add_sta_params->vhtCapable) { + if (assoc_req->vendor_vht_ie.VHTCaps.present) + vht_caps = assoc_req->vendor_vht_ie.VHTCaps; + else + vht_caps = assoc_req->VHTCaps; + add_sta_params->vht_caps = + lim_populate_vht_caps(vht_caps); + } + + lim_add_he_cap(mac_ctx, session_entry, + add_sta_params, assoc_req); + + lim_add_eht_cap(mac_ctx, session_entry, add_sta_params, + assoc_req); + + } + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == sta_ds->staType) { + add_sta_params->ht_caps = sta_ds->ht_caps; + add_sta_params->vht_caps = sta_ds->vht_caps; + if (add_sta_params->vhtCapable) { + add_sta_params->maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + sta_ds->vht_caps); + } + lim_add_tdls_sta_he_config(add_sta_params, sta_ds); + + if (lim_is_he_6ghz_band(session_entry)) + lim_add_tdls_sta_6ghz_he_cap(mac_ctx, add_sta_params, + sta_ds); + lim_add_tdls_sta_eht_config(add_sta_params, sta_ds); + } +#endif + +#ifdef FEATURE_WLAN_TDLS + if (sta_ds->wmeEnabled && + (LIM_IS_AP_ROLE(session_entry) || + (STA_ENTRY_TDLS_PEER == sta_ds->staType))) +#else + if (sta_ds->wmeEnabled && LIM_IS_AP_ROLE(session_entry)) +#endif + { + add_sta_params->uAPSD = 0; + /* + * update UAPSD and send it to LIM to add STA + * bitmap MSB <- LSB MSB 4 bits are for + * trigger enabled AC setting and LSB 4 bits + * are for delivery enabled AC setting + * 7 6 5 4 3 2 1 0 + * BE BK VI VO BE BK VI VO + */ + add_sta_params->uAPSD |= + sta_ds->qos.capability.qosInfo.acvo_uapsd; + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acvi_uapsd << 1); + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acbk_uapsd << 2); + add_sta_params->uAPSD |= + (sta_ds->qos.capability.qosInfo.acbe_uapsd << 3); + /* + * making delivery enabled and + * trigger enabled setting the same. + */ + add_sta_params->uAPSD |= add_sta_params->uAPSD << 4; + + add_sta_params->maxSPLen = + sta_ds->qos.capability.qosInfo.maxSpLen; + } + add_sta_params->rmfEnabled = sta_ds->rmfEnabled; + + if (!add_sta_params->htLdpcCapable) + add_sta_params->ht_caps &= ~(1 << SIR_MAC_HT_CAP_ADVCODING_S); + if (!add_sta_params->vhtLdpcCapable) + add_sta_params->vht_caps &= + ~(1 << SIR_MAC_VHT_CAP_LDPC_CODING_CAP); + + /* + * we need to defer the message until we get the + * response back from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, false); + + add_sta_params->nwType = session_entry->nwType; + + if (!(add_sta_params->htCapable || add_sta_params->vhtCapable || + lim_is_add_sta_params_he_capable(add_sta_params) || + lim_is_add_sta_params_eht_capable(add_sta_params))) { + nw_type_11b = 1; + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (sirIsArate(sta_ds->supportedRates.llaRates[i] & + 0x7F)) { + nw_type_11b = 0; + break; + } + } + if (nw_type_11b) + add_sta_params->nwType = eSIR_11B_NW_TYPE; + } + + if (add_sta_params->htCapable && session_entry->ht_config.tx_stbc) { + struct sDot11fIEHTCaps *ht_caps = (struct sDot11fIEHTCaps *) + &add_sta_params->ht_caps; + if (ht_caps->rxSTBC) + add_sta_params->stbc_capable = 1; + else + add_sta_params->stbc_capable = 0; + } + + if (add_sta_params->vhtCapable && add_sta_params->stbc_capable) { + struct sDot11fIEVHTCaps *vht_caps = (struct sDot11fIEVHTCaps *) + &add_sta_params->vht_caps; + if (vht_caps->rxSTBC) + add_sta_params->stbc_capable = 1; + else + add_sta_params->stbc_capable = 0; + } + + if (session_entry->opmode == QDF_SAP_MODE || + session_entry->opmode == QDF_P2P_GO_MODE) { + if (session_entry->parsedAssocReq) { + uint16_t aid = sta_ds->assocId; + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[aid]; + + if (assoc_req) { + add_sta_params->wpa_rsn = assoc_req->rsnPresent; + add_sta_params->wpa_rsn |= + (assoc_req->wpaPresent << 1); + } + } + } + + lim_update_he_stbc_capable(add_sta_params); + lim_update_he_mcs_12_13(add_sta_params, sta_ds); + + /* Send peer twt req and res bit during peer assoc command */ + lim_update_peer_twt_caps(add_sta_params, session_entry); + + msg_q.type = WMA_ADD_STA_REQ; + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + + pe_debug("vdev %d: " QDF_MAC_ADDR_FMT " opmode %d sta_type %d subtype %d: update %d aid %d wmm %d li %d ht %d vht %d ht client %d", + session_entry->vdev_id, + QDF_MAC_ADDR_REF(add_sta_params->staMac), + session_entry->opmode, sta_ds->staType, + sta_ds->mlmStaContext.subType, add_sta_params->updateSta, + add_sta_params->assocId, add_sta_params->wmmEnabled, + add_sta_params->listenInterval, add_sta_params->htCapable, + add_sta_params->vhtCapable, session_entry->ht_client_cnt); + pe_nofl_debug("max_ampdu: density %d size %d, width %d sgi20 %d sgi40 %d mimops %d txbf %d subfer %d vht_mcs11 %d uapsd %d " + "max splen %d pmf %d ht ldpc %d vht ldpc %d isp2p %d", + add_sta_params->maxAmpduDensity, + add_sta_params->maxAmpduSize, add_sta_params->ch_width, + add_sta_params->fShortGI20Mhz, + add_sta_params->fShortGI40Mhz, + add_sta_params->mimoPS, add_sta_params->vhtTxBFCapable, + add_sta_params->enable_su_tx_bformer, + add_sta_params->vht_mcs_10_11_supp, add_sta_params->uAPSD, + add_sta_params->maxSPLen, add_sta_params->rmfEnabled, + add_sta_params->htLdpcCapable, + add_sta_params->vhtLdpcCapable, + add_sta_params->p2pCapableSta); + + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, + msg_q.type)); + + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (QDF_STATUS_SUCCESS != ret_code) { + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + pe_err("ADD_STA_REQ for aId %d failed (reason %X)", + sta_ds->assocId, ret_code); + qdf_mem_free(add_sta_params); + } + + return ret_code; +} + +/** + * lim_del_sta() + * + ***FUNCTION: + * This function is called to delete an STA context at hardware + * whenever a STA is disassociated + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param sta - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @param fRespReqd - flag to indicate whether the delete is synchronous (true) + * or not (false) + * @return retCode - Indicates success or failure return code + */ + +QDF_STATUS +lim_del_sta(struct mac_context *mac, + tpDphHashNode sta, bool fRespReqd, struct pe_session *pe_session) +{ + tpDeleteStaParams pDelStaParams = NULL; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + pDelStaParams = qdf_mem_malloc(sizeof(tDeleteStaParams)); + if (!pDelStaParams) + return QDF_STATUS_E_NOMEM; + + /* + * 2G-AS platform: SAP associates with HT (11n)clients as 2x1 in 2G and + * 2X2 in 5G + * Non-2G-AS platform: SAP associates with HT (11n) clients as 2X2 in 2G + * and 5G; and enable async dbs scan when all HT clients are gone + * 5G-AS: Don't care + */ + if (!policy_mgr_is_hw_dbs_2x2_capable(mac->psoc) && + LIM_IS_AP_ROLE(pe_session) && + (sta->staType == STA_ENTRY_PEER) && + !sta->mlmStaContext.vhtCapability && + (pe_session->nss == 2)) { + pe_session->ht_client_cnt--; + if (pe_session->ht_client_cnt == 0) { + pe_debug("clearing SMPS intolrent vdev_param"); + wma_cli_set_command(pe_session->smeSessionId, + (int)wmi_vdev_param_smps_intolerant, + 0, VDEV_CMD); + } + } + + pDelStaParams->assocId = sta->assocId; + sta->valid = 0; + + if (!fRespReqd) + pDelStaParams->respReqd = 0; + else { + if (!(IS_TDLS_PEER(sta->staType))) { + /* when lim_del_sta is called from processSmeAssocCnf + * then mlmState is already set properly. */ + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + GET_LIM_STA_CONTEXT_MLM_STATE(sta)) { + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + SET_LIM_STA_CONTEXT_MLM_STATE(sta, + eLIM_MLM_WT_DEL_STA_RSP_STATE); + } + if (LIM_IS_STA_ROLE(pe_session)) { + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + eLIM_MLM_WT_DEL_STA_RSP_STATE)); + + pe_session->limMlmState = + eLIM_MLM_WT_DEL_STA_RSP_STATE; + + } + } + + /* we need to defer the message until we get the + * response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + + pDelStaParams->respReqd = 1; + } + + /* notify mlo peer to detach reference of the + * link peer before post WMA_DELETE_STA_REQ, which will free + * wlan_objmgr_peer of the link peer + */ + lim_mlo_notify_peer_disconn(pe_session, sta); + lim_mlo_delete_link_peer(pe_session, sta); + /* Update PE session ID */ + pDelStaParams->sessionId = pe_session->peSessionId; + pDelStaParams->smesessionId = pe_session->smeSessionId; + + pDelStaParams->staType = sta->staType; + qdf_mem_copy((uint8_t *) pDelStaParams->staMac, + (uint8_t *) sta->staAddr, sizeof(tSirMacAddr)); + + pDelStaParams->status = QDF_STATUS_SUCCESS; + msgQ.type = WMA_DELETE_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pDelStaParams; + msgQ.bodyval = 0; + + pe_debug("Sessionid %d :Sending SIR_HAL_DELETE_STA_REQ " + "for mac_addr "QDF_MAC_ADDR_FMT" and AssocID: %d MAC : " + QDF_MAC_ADDR_FMT, pDelStaParams->sessionId, + QDF_MAC_ADDR_REF(pDelStaParams->staMac), + pDelStaParams->assocId, + QDF_MAC_ADDR_REF(sta->staAddr)); + + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + if (fRespReqd) + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + pe_err("Posting DELETE_STA_REQ to HAL failed, reason=%X", + retCode); + qdf_mem_free(pDelStaParams); + } + + return retCode; +} + +/** + * lim_set_mbssid_info() - Save mbssid info + * @pe_session: pe session entry + * + * Return: None + */ +static void lim_set_mbssid_info(struct pe_session *pe_session) +{ + struct scan_mbssid_info *mbssid_info; + + if (!pe_session->lim_join_req && !pe_session->pLimReAssocReq) + return; + + if (pe_session->lim_join_req) + mbssid_info = + &pe_session->lim_join_req->bssDescription.mbssid_info; + else + mbssid_info = + &pe_session->pLimReAssocReq->bssDescription.mbssid_info; + + mlme_set_mbssid_info(pe_session->vdev, mbssid_info, + pe_session->curr_op_freq); +} + +/** + * lim_add_sta_self() + * + ***FUNCTION: + * This function is called to add an STA context at hardware + * whenever a STA is (Re) Associated. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param sta - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @return retCode - Indicates success or failure return code + */ + +QDF_STATUS +lim_add_sta_self(struct mac_context *mac, uint8_t updateSta, + struct pe_session *pe_session) +{ + tpAddStaParams pAddStaParams = NULL; + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + tSirMacAddr staMac; + uint32_t listenInterval = MLME_CFG_LISTEN_INTERVAL; + /*This self Sta dot 11 mode comes from the cfg and the expectation here is + * that cfg carries the systemwide capability that device under + * consideration can support. This capability gets plumbed into the cfg + * cache at system initialization time via the .dat and .ini file override + * mechanisms and will not change. If it does change, it is the + * responsibility of SME to evict the selfSta and reissue a new AddStaSelf + * command.*/ + uint32_t selfStaDot11Mode = 0; + + selfStaDot11Mode = mac->mlme_cfg->dot11_mode.dot11_mode; + + sir_copy_mac_addr(staMac, pe_session->self_mac_addr); + pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); + if (!pAddStaParams) + return QDF_STATUS_E_NOMEM; + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + qdf_mem_copy((uint8_t *) pAddStaParams->staMac, + (uint8_t *) staMac, sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) pAddStaParams->bssId, + pe_session->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->assocId = pe_session->limAID; + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = QDF_STATUS_SUCCESS; + + /* Update PE session ID */ + pAddStaParams->sessionId = pe_session->peSessionId; + + /* Update SME session ID */ + pAddStaParams->smesessionId = pe_session->smeSessionId; + + pAddStaParams->maxTxPower = pe_session->maxTxPower; + + pAddStaParams->updateSta = updateSta; + + lim_set_mbssid_info(pe_session); + + lim_populate_own_rate_set(mac, &pAddStaParams->supportedRates, + NULL, false, + pe_session, NULL, NULL, NULL); + if (IS_DOT11_MODE_HT(selfStaDot11Mode)) { + pAddStaParams->htCapable = true; + + pAddStaParams->ch_width = + mac->roam.configParam.channelBondingMode5GHz; + pAddStaParams->mimoPS = + lim_get_ht_capability(mac, eHT_MIMO_POWER_SAVE, + pe_session); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(mac, eHT_MPDU_DENSITY, + pe_session); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(mac, eHT_MAX_RX_AMPDU_FACTOR, + pe_session); + pAddStaParams->fShortGI20Mhz = + pe_session->ht_config.short_gi_20_mhz; + pAddStaParams->fShortGI40Mhz = + pe_session->ht_config.short_gi_40_mhz; + } + pAddStaParams->vhtCapable = pe_session->vhtCapability; + if (pAddStaParams->vhtCapable) + pAddStaParams->ch_width = + pe_session->ch_width; + + pAddStaParams->vhtTxBFCapable = + pe_session->vht_config.su_beam_formee; + pAddStaParams->enable_su_tx_bformer = + pe_session->vht_config.su_beam_former; + + /* In 11ac mode, the hardware is capable of supporting 128K AMPDU size */ + if (pe_session->vhtCapability) + pAddStaParams->maxAmpduSize = + mac->mlme_cfg->vht_caps.vht_cap_info.ampdu_len_exponent; + + pAddStaParams->vhtTxMUBformeeCapable = + pe_session->vht_config.mu_beam_formee; + pAddStaParams->enableVhtpAid = pe_session->enableVhtpAid; + pAddStaParams->enableAmpduPs = pe_session->enableAmpduPs; + pAddStaParams->enableHtSmps = (mac->mlme_cfg->ht_caps.enable_smps && + (!pe_session->supported_nss_1x1)); + pAddStaParams->htSmpsconfig = mac->mlme_cfg->ht_caps.smps; + pAddStaParams->send_smps_action = + pe_session->send_smps_action; + + /* For Self STA get the LDPC capability from session i.e config.ini */ + pAddStaParams->htLdpcCapable = + (pe_session->txLdpcIniFeatureEnabled & 0x01); + pAddStaParams->vhtLdpcCapable = + ((pe_session->txLdpcIniFeatureEnabled >> 1) & 0x01); + + listenInterval = mac->mlme_cfg->sap_cfg.listen_interval; + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + if (QDF_P2P_CLIENT_MODE == pe_session->opmode) + pAddStaParams->p2pCapableSta = 1; + + if (pe_session->isNonRoamReassoc) { + pAddStaParams->nonRoamReassoc = 1; + pe_session->isNonRoamReassoc = 0; + } + + if (IS_DOT11_MODE_HE(selfStaDot11Mode)) + lim_add_self_he_cap(pAddStaParams, pe_session); + + if (IS_DOT11_MODE_EHT(selfStaDot11Mode)) + lim_add_self_eht_cap(pAddStaParams, pe_session); + + if (lim_is_fils_connection(pe_session)) + pAddStaParams->no_ptk_4_way = true; + + msgQ.type = WMA_ADD_STA_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pAddStaParams; + msgQ.bodyval = 0; + + pe_debug(QDF_MAC_ADDR_FMT ": vdev %d Sending WMA_ADD_STA_REQ.LI %d", + QDF_MAC_ADDR_REF(pAddStaParams->staMac), + pe_session->vdev_id, pAddStaParams->listenInterval); + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X", + retCode); + qdf_mem_free(pAddStaParams); + } + return retCode; +} + +/** + * lim_handle_cnf_wait_timeout() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue to handle + * various confirmation failure cases. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param sta - Pointer to a sta descriptor + * @return None + */ + +void lim_handle_cnf_wait_timeout(struct mac_context *mac, uint16_t staId) +{ + tpDphHashNode sta; + struct pe_session *pe_session = NULL; + + pe_session = pe_find_session_by_session_id(mac, + mac->lim.lim_timers.gpLimCnfWaitTimer[staId].sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given sessionID"); + return; + } + sta = dph_get_hash_entry(mac, staId, &pe_session->dph.dphHashTable); + + if (!sta) { + pe_err("No STA context in SIR_LIM_CNF_WAIT_TIMEOUT"); + return; + } + + switch (sta->mlmStaContext.mlmState) { + case eLIM_MLM_WT_ASSOC_CNF_STATE: + pe_debug("Did not receive Assoc Cnf in eLIM_MLM_WT_ASSOC_CNF_STATE sta Assoc id %d and STA: "QDF_MAC_ADDR_FMT, + sta->assocId, QDF_MAC_ADDR_REF(sta->staAddr)); + + if (LIM_IS_AP_ROLE(pe_session)) { + lim_reject_association(mac, sta->staAddr, + sta->mlmStaContext.subType, + true, + sta->mlmStaContext.authType, + sta->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + pe_session); + } + break; + + default: + pe_warn("Received CNF_WAIT_TIMEOUT in state %d", + sta->mlmStaContext.mlmState); + } +} + +/** + * lim_delete_dph_hash_entry()- function to delete dph hash entry + * @mac_ctx: pointer to global mac structure + * @sta_addr: peer station address + * @sta_id: id assigned to peer station + * @session_entry: pe session entry + * + * This function is called whenever we need to delete + * the dph hash entry + * + * Return: none + */ + +void +lim_delete_dph_hash_entry(struct mac_context *mac_ctx, tSirMacAddr sta_addr, + uint16_t sta_id, struct pe_session *session_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tUpdateBeaconParams beacon_params; + + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.paramChangeBitmap = 0; + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, eLIM_CNF_WAIT_TIMER, + sta_id); + if (!session_entry) { + pe_err("NULL session_entry"); + return; + } + + beacon_params.bss_idx = session_entry->vdev_id; + sta_ds = dph_lookup_hash_entry(mac_ctx, sta_addr, &aid, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + pe_err("sta_ds is NULL"); + return; + } + + pe_debug("Deleting DPH Hash entry sta mac " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_addr)); + /* + * update the station count and perform associated actions + * do this before deleting the dph hash entry + */ + lim_util_count_sta_del(mac_ctx, sta_ds, session_entry); + + if (LIM_IS_AP_ROLE(session_entry)) { + if (LIM_IS_AP_ROLE(session_entry)) { + if (session_entry->gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_ap_protection_on_delete(mac_ctx, + sta_ds, &beacon_params, session_entry); + } + + if (sta_ds->non_ecsa_capable) { + if (session_entry->lim_non_ecsa_cap_num == 0) { + pe_debug("NonECSA sta 0, id %d is ecsa", + sta_id); + } else { + session_entry->lim_non_ecsa_cap_num--; + pe_debug("reducing the non ECSA num to %d", + session_entry->lim_non_ecsa_cap_num); + } + } + + lim_decide_short_preamble(mac_ctx, sta_ds, &beacon_params, + session_entry); + lim_decide_short_slot(mac_ctx, sta_ds, &beacon_params, + session_entry); + + /* Send message to HAL about beacon parameter change. */ + pe_debug("param bitmap: %d", beacon_params.paramChangeBitmap); + if (beacon_params.paramChangeBitmap && + (false == + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + sch_set_fixed_beacon_fields(mac_ctx, session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, + session_entry); + } + + lim_obss_send_detection_cfg(mac_ctx, session_entry, false); + + if (sta_ds->rmfEnabled) { + pe_debug("delete pmf timer assoc-id:%d sta mac " + QDF_MAC_ADDR_FMT, sta_ds->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); + } + } + + if (dph_delete_hash_entry(mac_ctx, sta_addr, sta_id, + &session_entry->dph.dphHashTable) != QDF_STATUS_SUCCESS) + pe_err("error deleting hash entry"); + lim_ap_check_6g_compatible_peer(mac_ctx, session_entry); +} + +/** + * lim_check_and_announce_join_success()- function to check if the received + * Beacon/Probe Response is from the BSS that we're attempting to join. + * @mac: pointer to global mac structure + * @beacon_probe_rsp: pointer to reveived beacon/probe response frame + * @header: pointer to received management frame header + * @session_entry: pe session entry + * + * This function is called upon receiving Beacon/Probe Response + * frame in WT_JOIN_BEACON_STATE to check if the received + * Beacon/Probe Response is from the BSS that we're attempting + * to join. + * If the Beacon/Probe Response is indeed from the BSS we're + * attempting to join, join success is sent to SME. + * + * Return: none + */ + +void +lim_check_and_announce_join_success(struct mac_context *mac_ctx, + tSirProbeRespBeacon *beacon_probe_rsp, tpSirMacMgmtHdr header, + struct pe_session *session_entry) +{ + tSirMacSSid current_ssid; + tLimMlmJoinCnf mlm_join_cnf; + tpDphHashNode sta_ds = NULL; + uint32_t val; + uint32_t *noa_duration_from_beacon = NULL; + uint32_t *noa2_duration_from_beacon = NULL; + uint32_t noa; + uint32_t total_num_noa_desc = 0; + uint16_t aid; + bool check_assoc_disallowed; + + qdf_mem_copy(current_ssid.ssId, + session_entry->ssId.ssId, session_entry->ssId.length); + + current_ssid.length = (uint8_t) session_entry->ssId.length; + + /* + * Check for SSID only in probe response. Beacons may not carry + * SSID information in hidden SSID case + */ + if (((SIR_MAC_MGMT_FRAME == header->fc.type) && + (SIR_MAC_MGMT_PROBE_RSP == header->fc.subType)) && + current_ssid.length && + (qdf_mem_cmp((uint8_t *) &beacon_probe_rsp->ssId, + (uint8_t *) ¤t_ssid, + (uint8_t) (1 + current_ssid.length)))) { + /* + * Received SSID does not match with the one we've. + * Ignore received Beacon frame + */ + pe_debug("SSID received in Beacon does not match"); + return; + } + + if (!LIM_IS_STA_ROLE(session_entry)) + return; + + if (SIR_MAC_MGMT_BEACON == header->fc.subType && + lim_is_null_ssid(&beacon_probe_rsp->ssId)) { + pe_debug("for hidden ap, waiting probersp to announce join success"); + return; + } + + pe_debug("Received Beacon/PR with BSSID:"QDF_MAC_ADDR_FMT" pe session %d vdev %d", + QDF_MAC_ADDR_REF(session_entry->bssId), + session_entry->peSessionId, + session_entry->vdev_id); + + /* Deactivate Join Failure timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + /* Deactivate Periodic Join timer */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + + if (QDF_P2P_CLIENT_MODE == session_entry->opmode && + beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.present) { + + noa_duration_from_beacon = (uint32_t *) + (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + 1); + + if (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.num_NoADesc) + total_num_noa_desc = + beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence. + num_NoADesc / SIZE_OF_NOA_DESCRIPTOR; + + noa = *noa_duration_from_beacon; + + if (total_num_noa_desc > 1) { + noa2_duration_from_beacon = (uint32_t *) + (beacon_probe_rsp->P2PProbeRes.NoticeOfAbsence.NoADesc + + SIZE_OF_NOA_DESCRIPTOR + 1); + noa += *noa2_duration_from_beacon; + } + + /* + * If MAX Noa exceeds 3 secs we will consider only 3 secs to + * avoid arbitrary values in noa duration field + */ + noa = noa > MAX_NOA_PERIOD_IN_MICROSECS ? + MAX_NOA_PERIOD_IN_MICROSECS : noa; + noa = noa / 1000; /* Convert to ms */ + + session_entry->defaultAuthFailureTimeout = + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout; + val = mac_ctx->mlme_cfg->timeouts.auth_failure_timeout + noa; + if (cfg_in_range(CFG_AUTH_FAILURE_TIMEOUT, val)) + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = val; + else + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = + cfg_default(CFG_AUTH_FAILURE_TIMEOUT); + } else { + session_entry->defaultAuthFailureTimeout = 0; + } + + wlan_cm_get_check_assoc_disallowed(mac_ctx->psoc, + &check_assoc_disallowed); + + /* + * Check if MBO Association disallowed subattr is present and post + * failure status to LIM if present + */ + if (check_assoc_disallowed && beacon_probe_rsp->assoc_disallowed) { + pe_err("Connection fails due to assoc disallowed reason(%d):"QDF_MAC_ADDR_FMT" PESessionID %d", + beacon_probe_rsp->assoc_disallowed_reason, + QDF_MAC_ADDR_REF(session_entry->bssId), + session_entry->peSessionId); + mlm_join_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + mlm_join_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + mlm_join_cnf.sessionId = session_entry->peSessionId; + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + return; + } + + /* Update Beacon Interval at CFG database */ + + if (beacon_probe_rsp->HTCaps.present) + lim_update_sta_run_time_ht_capability(mac_ctx, + &beacon_probe_rsp->HTCaps); + if (beacon_probe_rsp->HTInfo.present) + lim_update_sta_run_time_ht_info(mac_ctx, + &beacon_probe_rsp->HTInfo, session_entry); + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); + + /* + * update the capability info based on recently received beacon/probe + * response frame + */ + session_entry->limCurrentBssCaps = + lim_get_u16((uint8_t *)&beacon_probe_rsp->capabilityInfo); + + /* + * Announce join success by sending + * Join confirm to SME. + */ + mlm_join_cnf.resultCode = eSIR_SME_SUCCESS; + mlm_join_cnf.protStatusCode = STATUS_SUCCESS; + /* Update PE sessionId */ + mlm_join_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + + if (session_entry->vhtCapability && + beacon_probe_rsp->vendor_vht_ie.VHTCaps.present) { + session_entry->is_vendor_specific_vhtcaps = true; + session_entry->vendor_specific_vht_ie_sub_type = + beacon_probe_rsp->vendor_vht_ie.sub_type; + pe_debug("VHT caps are present in vendor specific IE"); + } + + /* Update HS 2.0 Information Element */ + if (beacon_probe_rsp->hs20vendor_ie.present) { + pe_debug("HS20 Indication Element Present, rel#:%u, id:%u", + beacon_probe_rsp->hs20vendor_ie.release_num, + beacon_probe_rsp->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&session_entry->hs20vendor_ie, + &beacon_probe_rsp->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(beacon_probe_rsp->hs20vendor_ie.hs_id)); + if (beacon_probe_rsp->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&session_entry->hs20vendor_ie.hs_id, + &beacon_probe_rsp->hs20vendor_ie.hs_id, + sizeof(beacon_probe_rsp->hs20vendor_ie.hs_id)); + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, session_entry->self_mac_addr, + &aid, + &session_entry->dph.dphHashTable); + + if (sta_ds && QDF_IS_STATUS_SUCCESS(lim_update_srp_ie(beacon_probe_rsp, + sta_ds))) { + /* update the SR parameters */ + lim_update_vdev_sr_elements(session_entry, sta_ds); + /* TODO: Need to send SRP IE update event to userspace */ + } +} + +/** + * lim_extract_ap_capabilities() + * + ***FUNCTION: + * This function is called to extract all of the AP's capabilities + * from the IEs received from it in Beacon/Probe Response frames + * + ***LOGIC: + * This routine mimics the lim_extract_ap_capability() API. The difference here + * is that this API returns the entire tSirProbeRespBeacon info as is. It is + * left to the caller of this API to use this info as required + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param pIE Pointer to starting IE in Beacon/Probe Response + * @param ieLen Length of all IEs combined + * @param beaconStruct A pointer to tSirProbeRespBeacon that needs to be + * populated + * @return status A status reporting QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + */ +QDF_STATUS lim_extract_ap_capabilities(struct mac_context *mac, + uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct) +{ + qdf_mem_zero((uint8_t *) beaconStruct, sizeof(tSirProbeRespBeacon)); + + /* Parse the Beacon IE's, Don't try to parse if we dont have anything in IE */ + if (ieLen > 0) { + if (QDF_STATUS_SUCCESS != + sir_parse_beacon_ie(mac, beaconStruct, pIE, + (uint32_t) ieLen)) { + pe_err("APCapExtract: Beacon parsing error!"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_del_bss() + * + ***FUNCTION: + * This function is called to delete BSS context at hardware + * whenever a STA is disassociated + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param sta - Pointer to the STA datastructure created by + * LIM and maintained by DPH + * @return retCode - Indicates success or failure return code + */ + +QDF_STATUS +lim_del_bss(struct mac_context *mac, tpDphHashNode sta, uint16_t bss_idx, + struct pe_session *pe_session) +{ + struct scheduler_msg msgQ = {0}; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + /* DPH was storing the AssocID in staID field, */ + /* staID is actually assigned by HAL when AddSTA message is sent. */ + if (sta) { + sta->valid = 0; + sta->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + } + pe_session->limMlmState = eLIM_MLM_WT_DEL_BSS_RSP_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + eLIM_MLM_WT_DEL_BSS_RSP_STATE)); + + if ((pe_session->peSessionId == + mac->lim.lim_timers.gLimJoinFailureTimer.sessionId) + && (true == + tx_timer_running(&mac->lim.lim_timers.gLimJoinFailureTimer))) { + lim_deactivate_and_change_timer(mac, eLIM_JOIN_FAIL_TIMER); + } + + /* we need to defer the message until we get the response back from HAL. */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + + if (pe_session->process_ho_fail) + msgQ.type = WMA_DELETE_BSS_HO_FAIL_REQ; + else + msgQ.type = WMA_DELETE_BSS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = NULL; + msgQ.bodyval = pe_session->smeSessionId; + + pe_debug("Sessionid %d : Sending HAL_DELETE_BSS_REQ BSSID:" QDF_MAC_ADDR_FMT, + pe_session->peSessionId, + QDF_MAC_ADDR_REF(pe_session->bssId)); + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + pe_err("Posting DELETE_BSS_REQ to HAL failed, reason=%X", + retCode); + } + + return retCode; +} + +/** + * lim_update_vhtcaps_assoc_resp : Update VHT caps in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_caps: VHT capabilities. + * @pe_session : session entry. + * + * Return : void + */ +void lim_update_vhtcaps_assoc_resp(struct mac_context *mac_ctx, + struct bss_params *pAddBssParams, + tDot11fIEVHTCaps *vht_caps, + struct pe_session *pe_session) +{ + pAddBssParams->staContext.vht_caps = + ((vht_caps->maxMPDULen << + SIR_MAC_VHT_CAP_MAX_MPDU_LEN) | + (vht_caps->supportedChannelWidthSet << + SIR_MAC_VHT_CAP_SUPP_CH_WIDTH_SET) | + (vht_caps->ldpcCodingCap << + SIR_MAC_VHT_CAP_LDPC_CODING_CAP) | + (vht_caps->shortGI80MHz << + SIR_MAC_VHT_CAP_SHORTGI_80MHZ) | + (vht_caps->shortGI160and80plus80MHz << + SIR_MAC_VHT_CAP_SHORTGI_160_80_80MHZ) | + (vht_caps->txSTBC << + SIR_MAC_VHT_CAP_TXSTBC) | + (vht_caps->rxSTBC << + SIR_MAC_VHT_CAP_RXSTBC) | + (vht_caps->suBeamFormerCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMER_CAP) | + (vht_caps->suBeamformeeCap << + SIR_MAC_VHT_CAP_SU_BEAMFORMEE_CAP) | + (vht_caps->csnofBeamformerAntSup << + SIR_MAC_VHT_CAP_CSN_BEAMORMER_ANT_SUP) | + (vht_caps->numSoundingDim << + SIR_MAC_VHT_CAP_NUM_SOUNDING_DIM) | + (vht_caps->muBeamformerCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMER_CAP) | + (vht_caps->muBeamformeeCap << + SIR_MAC_VHT_CAP_NUM_BEAM_FORMEE_CAP) | + (vht_caps->vhtTXOPPS << + SIR_MAC_VHT_CAP_TXOPPS) | + (vht_caps->htcVHTCap << + SIR_MAC_VHT_CAP_HTC_CAP) | + (vht_caps->maxAMPDULenExp << + SIR_MAC_VHT_CAP_MAX_AMDU_LEN_EXPO) | + (vht_caps->vhtLinkAdaptCap << + SIR_MAC_VHT_CAP_LINK_ADAPT_CAP) | + (vht_caps->rxAntPattern << + SIR_MAC_VHT_CAP_RX_ANTENNA_PATTERN) | + (vht_caps->txAntPattern << + SIR_MAC_VHT_CAP_TX_ANTENNA_PATTERN) | + (vht_caps->extended_nss_bw_supp << + SIR_MAC_VHT_CAP_EXTD_NSS_BW)); + + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); +} + +/** + * lim_update_vht_oper_assoc_resp : Update VHT Operations in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_caps: VHT CAP IE to update. + * @vht_oper: VHT Operations to update. + * @ht_info: HT Info IE to update. + * @pe_session : session entry. + * + * Return : void + */ +static void lim_update_vht_oper_assoc_resp(struct mac_context *mac_ctx, + struct bss_params *pAddBssParams, + tDot11fIEVHTCaps *vht_caps, tDot11fIEVHTOperation *vht_oper, + tDot11fIEHTInfo *ht_info, struct pe_session *pe_session) +{ + uint8_t ch_width; + + ch_width = pAddBssParams->ch_width; + + if (vht_oper->chanWidth == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ && + pe_session->ch_width) + ch_width = + lim_get_vht_ch_width(vht_caps, vht_oper, ht_info) + 1; + + if (ch_width > pe_session->ch_width) + ch_width = pe_session->ch_width; + + pAddBssParams->ch_width = ch_width; + pAddBssParams->staContext.ch_width = ch_width; +} + +#ifdef WLAN_FEATURE_11BE +/** + * lim_update_eht_oper_assoc_resp : Update BW based on EHT operation IE. + * @pe_session : session entry. + * @pAddBssParams: parameters required for add bss params. + * @eht_op: EHT Oper IE to update. + * + * Return : void + */ +static void lim_update_eht_oper_assoc_resp(struct pe_session *pe_session, + struct bss_params *pAddBssParams, + tDot11fIEeht_op *eht_op) +{ + enum phy_ch_width ch_width; + + ch_width = wlan_mlme_convert_eht_op_bw_to_phy_ch_width( + eht_op->channel_width); + + /* Due to puncturing, EHT AP's send seg1 in VHT IE as zero which causes + * downgrade to 80 MHz, check EHT IE and if EHT IE supports 160MHz + * then stick to 160MHz only + */ + + if (ch_width > pAddBssParams->ch_width && + ch_width >= pe_session->ch_width) { + pe_debug("eht ch_width %d and ch_width of add bss param %d", + ch_width, pAddBssParams->ch_width); + ch_width = pe_session->ch_width; + } + + pAddBssParams->ch_width = ch_width; + pAddBssParams->staContext.ch_width = ch_width; +} +#else +static void lim_update_eht_oper_assoc_resp(struct pe_session *pe_session, + struct bss_params *pAddBssParams, + tDot11fIEeht_op *eht_op) +{ +} +#endif + +#ifdef WLAN_SUPPORT_TWT +/** + * lim_set_sta_ctx_twt() - Save the TWT settings in STA context + * @sta_ctx: Pointer to Station Context + * @session: Pointer to PE session + * + * Return: None + */ +static void lim_set_sta_ctx_twt(tAddStaParams *sta_ctx, struct pe_session *session) +{ + sta_ctx->twt_requestor = session->peer_twt_requestor; + sta_ctx->twt_responder = session->peer_twt_responder; +} +#else +static inline void lim_set_sta_ctx_twt(tAddStaParams *sta_ctx, + struct pe_session *session) +{ +} +#endif + +void lim_sta_add_bss_update_ht_parameter(uint32_t bss_chan_freq, + tDot11fIEHTCaps* ht_cap, + tDot11fIEHTInfo* ht_inf, + bool chan_width_support, + struct bss_params *add_bss) +{ + if (!ht_cap->present) + return; + + add_bss->htCapable = ht_cap->present; + + if (!ht_inf->present) + return; + + if (chan_width_support && ht_cap->supportedChannelWidthSet) + add_bss->ch_width = ht_inf->recommendedTxWidthSet; + else + add_bss->ch_width = CH_WIDTH_20MHZ; +} + +/** + * lim_limit_bw_for_iot_ap() - limit sta vdev band width for iot ap + *@mac_ctx: mac context + *@session: pe session + *@bss_desc: bss descriptor + * + * When connect IoT AP, limit sta vdev band width + * + * Return: None + */ +static void +lim_limit_bw_for_iot_ap(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_description *bss_desc) +{ + struct action_oui_search_attr vendor_ap_search_attr = {0}; + uint16_t ie_len; + + ie_len = wlan_get_ielen_from_bss_description(bss_desc); + + vendor_ap_search_attr.ie_data = (uint8_t *)&bss_desc->ieFields[0]; + vendor_ap_search_attr.ie_length = ie_len; + + if (wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_LIMIT_BW)) { + pe_debug("Limit vdev %d bw to 40M for IoT AP", + session->vdev_id); + wma_set_vdev_bw(session->vdev_id, eHT_CHANNEL_WIDTH_40MHZ); + } +} + +QDF_STATUS lim_sta_send_add_bss(struct mac_context *mac, tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + struct bss_description *bssDescription, + uint8_t updateEntry, struct pe_session *pe_session) +{ + struct bss_params *pAddBssParams = NULL; + uint32_t retCode; + tpDphHashNode sta = NULL; + bool chan_width_support = false; + bool is_vht_cap_in_vendor_ie = false; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEVHTOperation *vht_oper = NULL; + tAddStaParams *sta_context; + uint32_t listen_interval = MLME_CFG_LISTEN_INTERVAL; + struct mlme_vht_capabilities_info *vht_cap_info; + + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(struct bss_params)); + if (!pAddBssParams) { + retCode = QDF_STATUS_E_NOMEM; + goto returnFailure; + } + + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = updateEntry; + + if (IS_DOT11_MODE_11B(pe_session->dot11mode) && + bssDescription->nwType != eSIR_11B_NW_TYPE) { + pAddBssParams->nwType = eSIR_11B_NW_TYPE; + } else { + pAddBssParams->nwType = bssDescription->nwType; + } + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pAssocRsp->capabilityInfo.shortSlotTime; + pAddBssParams->llbCoexist = + (uint8_t) pe_session->beaconParams.llbCoexist; + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(pe_session->dot11mode)) { + chan_width_support = + lim_get_ht_capability(mac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + pe_session); + + lim_sta_add_bss_update_ht_parameter(bssDescription->chan_freq, + &pAssocRsp->HTCaps, + &pAssocRsp->HTInfo, + chan_width_support, + pAddBssParams); + /** + * in limExtractApCapability function intersection of FW + * advertised channel width and AP advertised channel + * width has been taken into account for calculating + * pe_session->ch_width + */ + if ((chan_width_support && + ((pAssocRsp->HTCaps.present && + pAssocRsp->HTCaps.supportedChannelWidthSet) || + (pBeaconStruct->HTCaps.present && + pBeaconStruct->HTCaps.supportedChannelWidthSet))) || + lim_is_eht_connection_op_info_present(pe_session, + pAssocRsp)) { + pAddBssParams->ch_width = + pe_session->ch_width; + pAddBssParams->staContext.ch_width = + pe_session->ch_width; + } else { + pAddBssParams->ch_width = CH_WIDTH_20MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_20MHZ; + if (!vht_cap_info->enable_txbf_20mhz) + pAddBssParams->staContext.vhtTxBFCapable = 0; + } + } + + if (pe_session->vhtCapability && (pAssocRsp->VHTCaps.present)) { + pAddBssParams->vhtCapable = pAssocRsp->VHTCaps.present; + vht_caps = &pAssocRsp->VHTCaps; + vht_oper = &pAssocRsp->VHTOperation; + } else if (pe_session->vhtCapability && + pAssocRsp->vendor_vht_ie.VHTCaps.present){ + pAddBssParams->vhtCapable = + pAssocRsp->vendor_vht_ie.VHTCaps.present; + pe_debug("VHT Caps and Operation are present in vendor Specific IE"); + vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; + vht_oper = &pAssocRsp->vendor_vht_ie.VHTOperation; + } else { + pAddBssParams->vhtCapable = 0; + } + if (pAddBssParams->vhtCapable) { + if (vht_oper) + lim_update_vht_oper_assoc_resp(mac, pAddBssParams, + vht_caps, vht_oper, + &pAssocRsp->HTInfo, + pe_session); + if (vht_caps) + lim_update_vhtcaps_assoc_resp(mac, pAddBssParams, + vht_caps, pe_session); + } + + if (lim_is_session_he_capable(pe_session) && + (pAssocRsp->he_cap.present)) { + lim_add_bss_he_cap(pAddBssParams, pAssocRsp); + lim_add_bss_he_cfg(pAddBssParams, pe_session); + } + + if (lim_is_session_eht_capable(pe_session) && + (pAssocRsp->eht_cap.present)) { + lim_add_bss_eht_cap(pAddBssParams, pAssocRsp); + lim_add_bss_eht_cfg(pAddBssParams, pe_session); + } + + if (lim_is_session_eht_capable(pe_session) && + pAssocRsp->eht_op.present && + pAssocRsp->eht_op.eht_op_information_present) + lim_update_eht_oper_assoc_resp(pe_session, pAddBssParams, + &pAssocRsp->eht_op); + + if (pAssocRsp->bss_max_idle_period.present) { + pAddBssParams->bss_max_idle_period = + pAssocRsp->bss_max_idle_period.max_idle_period; + pe_debug("bss_max_idle_period %d", + pAddBssParams->bss_max_idle_period); + } else { + pAddBssParams->bss_max_idle_period = 0; + } + + /* + * Populate the STA-related parameters here + * Note that the STA here refers to the AP + * staType = PEER + */ + sta_context = &pAddBssParams->staContext; + /* Identifying AP as an STA */ + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + qdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + + listen_interval = mac->mlme_cfg->sap_cfg.listen_interval; + pAddBssParams->staContext.listenInterval = listen_interval; + + /* Get STA hash entry from the dph table */ + sta = dph_lookup_hash_entry(mac, pAddBssParams->staContext.bssId, + &pAddBssParams->staContext.assocId, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("Couldn't get assoc id for " "MAC ADDR: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + pAddBssParams->staContext.staMac)); + qdf_mem_free(pAddBssParams); + return QDF_STATUS_E_FAILURE; + } + + /* Update Assoc id from pe_session for STA */ + pAddBssParams->staContext.assocId = pe_session->limAID; + + pAddBssParams->staContext.uAPSD = + pe_session->gUapsdPerAcBitmask; + + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.updateSta = updateEntry; + + if (IS_DOT11_MODE_HT(pe_session->dot11mode) + && pBeaconStruct->HTCaps.present) { + pAddBssParams->staContext.htCapable = 1; + if (pe_session->ht_config.tx_stbc) + pAddBssParams->staContext.stbc_capable = + pAssocRsp->HTCaps.rxSTBC; + + if (pe_session->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct-> + vendor_vht_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + pAddBssParams->staContext.vht_mcs_10_11_supp = + sta->vht_mcs_10_11_supp; + + pAddBssParams->staContext.vhtSupportedRxNss = + sta->vhtSupportedRxNss; + if (pAssocRsp->VHTCaps.present) + vht_caps = &pAssocRsp->VHTCaps; + else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { + vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; + pe_debug("VHT Caps are in vendor Specific IE"); + is_vht_cap_in_vendor_ie = true; + } + + if ((vht_caps) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + pe_session->vht_config.su_beam_formee) + sta_context->vhtTxBFCapable = 1; + + if ((vht_caps) && vht_caps->muBeamformerCap && + pe_session->vht_config.mu_beam_formee) + sta_context->vhtTxMUBformeeCapable = 1; + + if ((vht_caps) && vht_caps->suBeamformeeCap && + pe_session->vht_config.su_beam_former) + sta_context->enable_su_tx_bformer = 1; + + if (vht_caps && pAddBssParams->staContext.stbc_capable) + pAddBssParams->staContext.stbc_capable = + vht_caps->rxSTBC; + if (pe_session->ch_width == CH_WIDTH_160MHZ || + pe_session->ch_width == CH_WIDTH_80P80MHZ) { + sta_context->vht_160mhz_nss = + sta->vht_160mhz_nss; + sta_context->vht_80p80mhz_nss = + sta->vht_80p80mhz_nss; + sta_context->vht_extended_nss_bw_cap = + sta->vht_extended_nss_bw_cap; + } else { + sta_context->vht_160mhz_nss = 0; + sta_context->vht_80p80mhz_nss = 0; + sta_context->vht_extended_nss_bw_cap = 0; + } + } + if (lim_is_session_he_capable(pe_session) && + (pAssocRsp->he_cap.present || + pBeaconStruct->he_cap.present)) { + lim_intersect_ap_he_caps(pe_session, + pAddBssParams, + pBeaconStruct, + pAssocRsp, bssDescription); + lim_update_he_stbc_capable(&pAddBssParams->staContext); + lim_update_he_mcs_12_13(&pAddBssParams->staContext, + sta); + } + + if (lim_is_session_eht_capable(pe_session) && + (pAssocRsp->eht_cap.present || + pBeaconStruct->eht_cap.present)) { + lim_intersect_ap_eht_caps(pe_session, + pAddBssParams, + pBeaconStruct, + pAssocRsp); + } + + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) + pAssocRsp->HTCaps.mimoPowerSave; + pAddBssParams->staContext.maxAmpduDensity = + pAssocRsp->HTCaps.mpduDensity; + /* + * We will check gShortGI20Mhz and gShortGI40Mhz from + * session entry if they are set then we will use what ever + * Assoc response coming from AP supports. If these + * values are set as 0 in session entry then we will + * hardcode this values to 0. + */ + if (pe_session->ht_config.short_gi_20_mhz) { + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pAssocRsp->HTCaps.shortGI20MHz; + } else { + pAddBssParams->staContext.fShortGI20Mhz = false; + } + + if (pe_session->ht_config.short_gi_40_mhz) { + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pAssocRsp->HTCaps.shortGI40MHz; + } else { + pAddBssParams->staContext.fShortGI40Mhz = false; + } + + if (!pAddBssParams->staContext.vhtCapable) + /* Use max ampd factor advertised in + * HTCAP for non-vht connection */ + { + pAddBssParams->staContext.maxAmpduSize = + pAssocRsp->HTCaps.maxRxAMPDUFactor; + } else if (pAddBssParams->staContext.maxAmpduSize < + pAssocRsp->HTCaps.maxRxAMPDUFactor) { + pAddBssParams->staContext.maxAmpduSize = + pAssocRsp->HTCaps.maxRxAMPDUFactor; + } + if (pAddBssParams->staContext.vhtTxBFCapable + && vht_cap_info->disable_ldpc_with_txbf_ap) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + if (pe_session->txLdpcIniFeatureEnabled & 0x1) + pAddBssParams->staContext.htLdpcCapable = + (uint8_t) pAssocRsp->HTCaps.advCodingCap; + else + pAddBssParams->staContext.htLdpcCapable = 0; + + if (pAssocRsp->VHTCaps.present) + vht_caps = &pAssocRsp->VHTCaps; + else if (pAssocRsp->vendor_vht_ie.VHTCaps.present) { + vht_caps = &pAssocRsp->vendor_vht_ie.VHTCaps; + pe_debug("VHT Caps is in vendor Specific IE"); + } + if (vht_caps && + (pe_session->txLdpcIniFeatureEnabled & 0x2)) { + if (!is_vht_cap_in_vendor_ie) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) pAssocRsp->VHTCaps.ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + } else { + pAddBssParams->staContext.vhtLdpcCapable = 0; + } + } + + } + if (lim_is_he_6ghz_band(pe_session)) { + if (lim_is_session_he_capable(pe_session) && + (pAssocRsp->he_cap.present || + pBeaconStruct->he_cap.present)) { + lim_intersect_ap_he_caps(pe_session, + pAddBssParams, + pBeaconStruct, + pAssocRsp, bssDescription); + lim_update_he_stbc_capable(&pAddBssParams->staContext); + lim_update_he_mcs_12_13(&pAddBssParams->staContext, + sta); + if (!lim_is_eht_connection_op_info_present(pe_session, + pAssocRsp)) + lim_update_he_6gop_assoc_resp(pAddBssParams, + &pAssocRsp->he_op, + pe_session); + lim_update_he_6ghz_band_caps(mac, + &pAssocRsp->he_6ghz_band_cap, + &pAddBssParams->staContext); + } + if (lim_is_session_eht_capable(pe_session) && + (pAssocRsp->eht_cap.present || + pBeaconStruct->eht_cap.present)) { + lim_intersect_ap_eht_caps(pe_session, + pAddBssParams, + pBeaconStruct, + pAssocRsp); + } + } + + lim_extract_per_link_id(pe_session, pAddBssParams, pAssocRsp); + lim_extract_ml_info(pe_session, pAddBssParams, pAssocRsp); + lim_intersect_ap_emlsr_caps(mac, pe_session, pAddBssParams, pAssocRsp); + lim_extract_msd_caps(mac, pe_session, pAddBssParams, pAssocRsp); + + pAddBssParams->staContext.smesessionId = + pe_session->smeSessionId; + pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; + pAddBssParams->staContext.wpa_rsn |= + (pBeaconStruct->wpaPresent << 1); + /* For OSEN Connection AP does not advertise RSN or WPA IE + * so from the IEs we get from supplicant we get this info + * so for FW to transmit EAPOL message 4 we shall set + * wpa_rsn + */ + if ((!pAddBssParams->staContext.wpa_rsn) + && (pe_session->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + qdf_mem_copy(&pAddBssParams->staContext.capab_info, + &pAssocRsp->capabilityInfo, + sizeof(pAddBssParams->staContext.capab_info)); + qdf_mem_copy(&pAddBssParams->staContext.ht_caps, + (uint8_t *) &pAssocRsp->HTCaps + sizeof(uint8_t), + sizeof(pAddBssParams->staContext.ht_caps)); + + /* If WMM IE or 802.11E IE is present then enable WMM */ + if ((pe_session->limWmeEnabled && pAssocRsp->wmeEdcaPresent) || + (pe_session->limQosEnabled && pAssocRsp->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + sta = dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (sta) { + qdf_mem_copy(&pAddBssParams->staContext.supportedRates, + &sta->supportedRates, + sizeof(sta->supportedRates)); + } else + pe_err("could not Update the supported rates"); + pAddBssParams->staContext.encryptType = pe_session->encryptType; + + pAddBssParams->maxTxPower = pe_session->maxTxPower; + + if (QDF_P2P_CLIENT_MODE == pe_session->opmode) + pAddBssParams->staContext.p2pCapableSta = 1; + + if (pe_session->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } + + /* Set a new state for MLME */ + if (eLIM_MLM_WT_ASSOC_RSP_STATE == pe_session->limMlmState) + pe_session->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE; + else + pe_session->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + pe_session->limMlmState)); + + if (!pAddBssParams->staContext.htLdpcCapable) + pAddBssParams->staContext.ht_caps &= + ~(1 << SIR_MAC_HT_CAP_ADVCODING_S); + if (!pAddBssParams->staContext.vhtLdpcCapable) + pAddBssParams->staContext.vht_caps &= + ~(1 << SIR_MAC_VHT_CAP_LDPC_CODING_CAP); + + if (pe_session->isNonRoamReassoc) + pAddBssParams->nonRoamReassoc = 1; + + pe_debug("update %d MxAmpduDen %d mimoPS %d vht_mcs11 %d shortSlot %d BI %d DTIM %d enc type %d p2p cab STA %d", + updateEntry, + pAddBssParams->staContext.maxAmpduDensity, + pAddBssParams->staContext.mimoPS, + pAddBssParams->staContext.vht_mcs_10_11_supp, + pAddBssParams->shortSlotTimeSupported, + pAddBssParams->beaconInterval, pAddBssParams->dtimPeriod, + pAddBssParams->staContext.encryptType, + pAddBssParams->staContext.p2pCapableSta); + if (cds_is_5_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_5MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ; + } else if (cds_is_10_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_10MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ; + } + lim_set_sta_ctx_twt(&pAddBssParams->staContext, pe_session); + + if (lim_is_fils_connection(pe_session)) + pAddBssParams->no_ptk_4_way = true; + + /* we need to defer the message until we get the response back */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + + retCode = wma_send_peer_assoc_req(pAddBssParams); + if (QDF_IS_STATUS_ERROR(retCode)) { + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + pe_err("wma_send_peer_assoc_req failed=%X", + retCode); + } + qdf_mem_free(pAddBssParams); + + lim_limit_bw_for_iot_ap(mac, pe_session, bssDescription); + +returnFailure: + /* Clean-up will be done by the caller... */ + return retCode; +} + +QDF_STATUS lim_sta_send_add_bss_pre_assoc(struct mac_context *mac, + struct pe_session *pe_session) +{ + struct bss_params *pAddBssParams = NULL; + uint32_t retCode; + tSchBeaconStruct *pBeaconStruct; + bool chan_width_support = false; + tDot11fIEVHTOperation *vht_oper = NULL; + tDot11fIEVHTCaps *vht_caps = NULL; + uint32_t listen_interval = MLME_CFG_LISTEN_INTERVAL; + struct bss_description *bssDescription = NULL; + struct mlme_vht_capabilities_info *vht_cap_info; + + if (!pe_session->lim_join_req) { + pe_err("Lim Join request is NULL"); + return QDF_STATUS_E_FAILURE; + } + + bssDescription = &pe_session->lim_join_req->bssDescription; + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!pBeaconStruct) + return QDF_STATUS_E_NOMEM; + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(struct bss_params)); + if (!pAddBssParams) { + retCode = QDF_STATUS_E_NOMEM; + goto returnFailure; + } + + lim_extract_ap_capabilities(mac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (mac->lim.gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac, pBeaconStruct, + pe_session); + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = false; + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llbCoexist = + (uint8_t) pe_session->beaconParams.llbCoexist; + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(pe_session->dot11mode)) { + chan_width_support = + lim_get_ht_capability(mac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + pe_session); + lim_sta_add_bss_update_ht_parameter(bssDescription->chan_freq, + &pBeaconStruct->HTCaps, + &pBeaconStruct->HTInfo, + chan_width_support, + pAddBssParams); + } + + if (pe_session->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct->vendor_vht_ie.VHTCaps))) { + + pAddBssParams->vhtCapable = 1; + if (pBeaconStruct->VHTOperation.present) + vht_oper = &pBeaconStruct->VHTOperation; + else if (pBeaconStruct->vendor_vht_ie.VHTOperation.present) { + vht_oper = &pBeaconStruct->vendor_vht_ie.VHTOperation; + pe_debug("VHT Operation is present in vendor Specific IE"); + } + + /* + * in limExtractApCapability function intersection of FW + * advertised channel width and AP advertised channel width has + * been taken into account for calculating + * pe_session->ch_width + */ + pAddBssParams->ch_width = + pe_session->ch_width; + pAddBssParams->staContext.maxAmpduSize = + SIR_MAC_GET_VHT_MAX_AMPDU_EXPO( + pAddBssParams->staContext.vht_caps); + } else { + pAddBssParams->vhtCapable = 0; + } + + if (lim_is_session_he_capable(pe_session) && + pBeaconStruct->he_cap.present) { + lim_update_bss_he_capable(mac, pAddBssParams); + lim_add_bss_he_cfg(pAddBssParams, pe_session); + } + + if (lim_is_session_eht_capable(pe_session) && + pBeaconStruct->eht_cap.present) { + lim_update_bss_eht_capable(mac, pAddBssParams); + lim_add_bss_eht_cfg(pAddBssParams, pe_session); + } + + /* + * Populate the STA-related parameters here + * Note that the STA here refers to the AP + */ + /* Identifying AP as an STA */ + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + qdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + + listen_interval = mac->mlme_cfg->sap_cfg.listen_interval; + pAddBssParams->staContext.listenInterval = listen_interval; + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.updateSta = false; + + if (IS_DOT11_MODE_HT(pe_session->dot11mode) + && (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.htCapable = 1; + if (pe_session->vhtCapability && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE( + pBeaconStruct->vendor_vht_ie.VHTCaps))) { + pAddBssParams->staContext.vhtCapable = 1; + if (pBeaconStruct->VHTCaps.present) + vht_caps = &pBeaconStruct->VHTCaps; + else if (pBeaconStruct->vendor_vht_ie.VHTCaps.present) + vht_caps = &pBeaconStruct-> + vendor_vht_ie.VHTCaps; + + if ((vht_caps) && (vht_caps->suBeamFormerCap || + vht_caps->muBeamformerCap) && + pe_session->vht_config.su_beam_formee) + pAddBssParams->staContext.vhtTxBFCapable = 1; + + if ((vht_caps) && vht_caps->muBeamformerCap && + pe_session->vht_config.mu_beam_formee) + pAddBssParams->staContext.vhtTxMUBformeeCapable + = 1; + + if ((vht_caps) && vht_caps->suBeamformeeCap && + pe_session->vht_config.su_beam_former) + pAddBssParams->staContext.enable_su_tx_bformer + = 1; + } + if (lim_is_session_he_capable(pe_session) && + pBeaconStruct->he_cap.present) + lim_intersect_ap_he_caps(pe_session, pAddBssParams, + pBeaconStruct, NULL, + bssDescription); + + if (lim_is_session_eht_capable(pe_session) && + pBeaconStruct->eht_cap.present) + lim_intersect_ap_eht_caps(pe_session, pAddBssParams, + pBeaconStruct, NULL); + + if (pBeaconStruct->HTCaps.supportedChannelWidthSet && + chan_width_support) { + pAddBssParams->staContext.ch_width = + (uint8_t) pBeaconStruct->HTInfo. + recommendedTxWidthSet; + if ((vht_oper) && + pAddBssParams->staContext.vhtCapable && + vht_oper->chanWidth) + pAddBssParams->staContext.ch_width = + vht_oper->chanWidth + 1; + } else { + pAddBssParams->staContext.ch_width = + CH_WIDTH_20MHZ; + } + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + /* + * We will check gShortGI20Mhz and gShortGI40Mhz from ini file. + * if they are set then we will use what ever Beacon coming + * from AP supports. If these values are set as 0 in ini file + * then we will hardcode this values to 0. + */ + if (pe_session->ht_config.short_gi_20_mhz) + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t)pBeaconStruct->HTCaps.shortGI20MHz; + else + pAddBssParams->staContext.fShortGI20Mhz = false; + + if (pe_session->ht_config.short_gi_40_mhz) + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + else + pAddBssParams->staContext.fShortGI40Mhz = false; + + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + if (pAddBssParams->staContext.vhtTxBFCapable + && vht_cap_info->disable_ldpc_with_txbf_ap) { + pAddBssParams->staContext.htLdpcCapable = 0; + pAddBssParams->staContext.vhtLdpcCapable = 0; + } else { + if (pe_session->txLdpcIniFeatureEnabled & 0x1) + pAddBssParams->staContext.htLdpcCapable = + (uint8_t) pBeaconStruct->HTCaps. + advCodingCap; + else + pAddBssParams->staContext.htLdpcCapable = 0; + + if (pBeaconStruct->VHTCaps.present) + vht_caps = &pBeaconStruct->VHTCaps; + else if (pBeaconStruct->vendor_vht_ie.VHTCaps.present) { + vht_caps = + &pBeaconStruct->vendor_vht_ie.VHTCaps; + } + if (vht_caps && + (pe_session->txLdpcIniFeatureEnabled & 0x2)) + pAddBssParams->staContext.vhtLdpcCapable = + (uint8_t) vht_caps->ldpcCodingCap; + else + pAddBssParams->staContext.vhtLdpcCapable = 0; + } + } + /* + * If WMM IE or 802.11E IE is not present + * and AP is HT AP then enable WMM + */ + if ((pe_session->limWmeEnabled && (pBeaconStruct->wmeEdcaPresent || + pAddBssParams->staContext.htCapable)) || + (pe_session->limQosEnabled && + (pBeaconStruct->edcaPresent || + pAddBssParams->staContext.htCapable))) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + /* Update the rates */ + lim_populate_peer_rate_set(mac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, pe_session, + &pBeaconStruct->VHTCaps, + &pBeaconStruct->he_cap, + &pBeaconStruct->eht_cap, NULL, + bssDescription); + + pAddBssParams->staContext.encryptType = pe_session->encryptType; + + pAddBssParams->maxTxPower = pe_session->maxTxPower; + + pAddBssParams->staContext.smesessionId = pe_session->smeSessionId; + pAddBssParams->staContext.sessionId = pe_session->peSessionId; + + if (pe_session->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } + /* Set a new state for MLME */ + pe_session->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE; + + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + pe_session->limMlmState)); + if (cds_is_5_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_5MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_5MHZ; + } else if (cds_is_10_mhz_enabled()) { + pAddBssParams->ch_width = CH_WIDTH_10MHZ; + pAddBssParams->staContext.ch_width = CH_WIDTH_10MHZ; + } + + if (lim_is_fils_connection(pe_session)) + pAddBssParams->no_ptk_4_way = true; + + retCode = wma_pre_assoc_req(pAddBssParams); + lim_process_sta_add_bss_rsp_pre_assoc(mac, pAddBssParams, + pe_session, retCode); + qdf_mem_free(pAddBssParams); + /* + * Set retCode success as lim_process_sta_add_bss_rsp_pre_assoc take + * care of failure + */ + retCode = QDF_STATUS_SUCCESS; + +returnFailure: + /* Clean-up will be done by the caller... */ + qdf_mem_free(pBeaconStruct); + return retCode; +} + +/** + * lim_prepare_and_send_del_all_sta_cnf() - prepares and send del all sta cnf + * @mac: mac global context + * @status_code: status code + * @pe_session: session context + * + * deletes DPH entry, changes the MLM mode for station, calls + * lim_send_del_sta_cnf + * + * Return: void + */ +void lim_prepare_and_send_del_all_sta_cnf(struct mac_context *mac, + tSirResultCodes status_code, + struct pe_session *pe_session) +{ + tLimMlmDeauthCnf mlm_deauth; + tpDphHashNode sta_ds = NULL; + uint32_t i; + + if (!LIM_IS_AP_ROLE(pe_session)) + return; + + for (i = 1; i < pe_session->dph.dphHashTable.size; i++) { + sta_ds = dph_get_hash_entry(mac, i, + &pe_session->dph.dphHashTable); + if (!sta_ds) + continue; + + lim_delete_dph_hash_entry(mac, sta_ds->staAddr, + sta_ds->assocId, pe_session); + if (lim_is_mlo_conn(pe_session, sta_ds)) + lim_release_mlo_conn_idx(mac, sta_ds->assocId, + pe_session, false); + else + lim_release_peer_idx(mac, sta_ds->assocId, pe_session); + } + + qdf_set_macaddr_broadcast(&mlm_deauth.peer_macaddr); + mlm_deauth.resultCode = status_code; + mlm_deauth.deauthTrigger = eLIM_HOST_DEAUTH; + mlm_deauth.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, LIM_MLM_DEAUTH_CNF, + (uint32_t *)&mlm_deauth); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void lim_copy_mld_mac_addr(uint8_t *sta_mld_addr, + tpDphHashNode sta) +{ + qdf_mem_copy(sta_mld_addr, sta->mld_addr, QDF_MAC_ADDR_SIZE); +} +#else +static inline +void lim_copy_mld_mac_addr(uint8_t *sta_mld_addr, + tpDphHashNode sta) +{ +} +#endif + +/** + * lim_prepare_and_send_del_sta_cnf() - prepares and send del sta cnf + * + * @mac: mac global context + * @sta: sta dph node + * @status_code: status code + * @pe_session: session context + * + * deletes DPH entry, changes the MLM mode for station, calls + * lim_send_del_sta_cnf + * + * Return: void + */ +void +lim_prepare_and_send_del_sta_cnf(struct mac_context *mac, tpDphHashNode sta, + tSirResultCodes status_code, + struct pe_session *pe_session) +{ + uint16_t staDsAssocId = 0; + struct qdf_mac_addr sta_dsaddr; + struct qdf_mac_addr sta_mld_addr = QDF_MAC_ADDR_ZERO_INIT; + struct lim_sta_context mlmStaContext; + bool mlo_conn = false; + + if (!sta) { + pe_err("sta is NULL"); + return; + } + + staDsAssocId = sta->assocId; + qdf_mem_copy((uint8_t *) sta_dsaddr.bytes, + sta->staAddr, QDF_MAC_ADDR_SIZE); + lim_copy_mld_mac_addr(sta_mld_addr.bytes, sta); + + mlmStaContext = sta->mlmStaContext; + + if (LIM_IS_AP_ROLE(pe_session)) { + mlo_conn = lim_is_mlo_conn(pe_session, sta); + if (mlo_conn) + lim_release_mlo_conn_idx(mac, sta->assocId, + pe_session, false); + else + lim_release_peer_idx(mac, sta->assocId, pe_session); + } + + lim_delete_dph_hash_entry(mac, sta->staAddr, sta->assocId, + pe_session); + + if (LIM_IS_STA_ROLE(pe_session)) { + pe_session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + } + + lim_send_del_sta_cnf(mac, sta_dsaddr, sta_mld_addr, staDsAssocId, + mlmStaContext, + status_code, pe_session); +} + +/** ------------------------------------------------------------- + \fn lim_init_pre_auth_timer_table + \brief Initialize the Pre Auth Tanle and creates the timer for + each node for the timeout value got from cfg. + \param struct mac_context * mac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +void lim_init_pre_auth_timer_table(struct mac_context *mac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t cfgValue; + uint32_t authNodeIdx; + + tLimPreAuthNode **pAuthNode = pPreAuthTimerTable->pTable; + + /* Get AUTH_RSP Timers value */ + cfgValue = SYS_MS_TO_TICKS(mac->mlme_cfg->timeouts.auth_rsp_timeout); + for (authNodeIdx = 0; authNodeIdx < pPreAuthTimerTable->numEntry; + authNodeIdx++) { + if (tx_timer_create(mac, &(pAuthNode[authNodeIdx]->timer), + "AUTH RESPONSE TIMEOUT", + lim_auth_response_timer_handler, authNodeIdx, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("Cannot create Auth Rsp timer of Index: %d", + authNodeIdx); + return; + } + pAuthNode[authNodeIdx]->authNodeIdx = (uint8_t) authNodeIdx; + pAuthNode[authNodeIdx]->fFree = 1; + } +} + +/** ------------------------------------------------------------- + \fn lim_acquire_free_pre_auth_node + \brief Retrieves a free Pre Auth node from Pre Auth Table. + \param struct mac_context * mac + \param tpLimPreAuthTable pPreAuthTimerTable + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_acquire_free_pre_auth_node(struct mac_context *mac, + tpLimPreAuthTable pPreAuthTimerTable) +{ + uint32_t i; + tLimPreAuthNode **pTempNode = pPreAuthTimerTable->pTable; + + for (i = 0; i < pPreAuthTimerTable->numEntry; i++) { + if (pTempNode[i]->fFree == 1) { + pTempNode[i]->fFree = 0; + return pTempNode[i]; + } + } + + return NULL; +} + +/** ------------------------------------------------------------- + \fn lim_get_pre_auth_node_from_index + \brief Depending on the Index this retrieves the pre auth node. + \param struct mac_context * mac + \param tpLimPreAuthTable pAuthTable + \param uint32_t authNodeIdx + \return none + -------------------------------------------------------------*/ +tLimPreAuthNode *lim_get_pre_auth_node_from_index(struct mac_context *mac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx) +{ + if ((authNodeIdx >= pAuthTable->numEntry) + || (!pAuthTable->pTable)) { + pe_err("Invalid Auth Timer Index: %d NumEntry: %d", + authNodeIdx, pAuthTable->numEntry); + return NULL; + } + + return pAuthTable->pTable[authNodeIdx]; +} + +/* Util API to check if the channels supported by STA is within range */ +QDF_STATUS lim_is_dot11h_supported_channels_valid(struct mac_context *mac, + tSirAssocReq *assoc) +{ + /* + * Allow all the stations to join with us. + * 802.11h-2003 11.6.1 => An AP may use the supported channels list for associated STAs + * as an input into an algorithm used to select a new channel for the BSS. + * The specification of the algorithm is beyond the scope of this amendment. + */ + + return QDF_STATUS_SUCCESS; +} + +/* Util API to check if the txpower supported by STA is within range */ +QDF_STATUS lim_is_dot11h_power_capabilities_in_range(struct mac_context *mac, + tSirAssocReq *assoc, + struct pe_session *pe_session) +{ + int8_t localMaxTxPower; + uint8_t local_pwr_constraint; + + localMaxTxPower = wlan_reg_get_channel_reg_power_for_freq( + mac->pdev, pe_session->curr_op_freq); + + local_pwr_constraint = mac->mlme_cfg->power.local_power_constraint; + localMaxTxPower -= (int8_t)local_pwr_constraint; + + /** + * The min Tx Power of the associating station should not be greater than (regulatory + * max tx power - local power constraint configured on AP). + */ + if (assoc->powerCapability.minTxPower > localMaxTxPower) { + pe_warn("minTxPower (STA): %d, localMaxTxPower (AP): %d", + assoc->powerCapability.minTxPower, localMaxTxPower); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void lim_fill_rx_highest_supported_rate(struct mac_context *mac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet) +{ + tSirMacRxHighestSupportRate *pRxHighestRate; + uint8_t *pBuf; + uint16_t rate = 0; + + pBuf = pSupportedMCSSet + MCS_RX_HIGHEST_SUPPORTED_RATE_BYTE_OFFSET; + rate = lim_get_u16(pBuf); + + pRxHighestRate = (tSirMacRxHighestSupportRate *) &rate; + *rxHighestRate = pRxHighestRate->rate; + + return; +} + +/** ------------------------------------------------------------- + \fn lim_send_sme_unprotected_mgmt_frame_ind + \brief Forwards the unprotected management frame to SME. + \param struct mac_context * mac + \param frameType - 802.11 frame type + \param frame - frame buffer + \param sessionId - id for the current session + \param pe_session - PE session context + \return none + -------------------------------------------------------------*/ +void lim_send_sme_unprotected_mgmt_frame_ind(struct mac_context *mac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + struct pe_session *pe_session) +{ + struct scheduler_msg mmhMsg = {0}; + tSirSmeUnprotMgmtFrameInd *pSirSmeMgmtFrame = NULL; + uint16_t length; + + length = sizeof(tSirSmeUnprotMgmtFrameInd) + frameLen; + + pSirSmeMgmtFrame = qdf_mem_malloc(length); + if (!pSirSmeMgmtFrame) + return; + + pSirSmeMgmtFrame->sessionId = sessionId; + pSirSmeMgmtFrame->frameType = frameType; + + qdf_mem_copy(pSirSmeMgmtFrame->frameBuf, frame, frameLen); + pSirSmeMgmtFrame->frameLen = frameLen; + + mmhMsg.type = eWNI_SME_UNPROT_MGMT_FRM_IND; + mmhMsg.bodyptr = pSirSmeMgmtFrame; + mmhMsg.bodyval = 0; + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + return; +} + +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_tsm_ie_ind(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t tid, uint8_t state, + uint16_t measurement_interval) +{ + struct scheduler_msg msg = {0}; + struct tsm_ie_ind *tsm_ie_ind; + + if (!mac || !pe_session) + return; + + tsm_ie_ind = qdf_mem_malloc(sizeof(*tsm_ie_ind)); + if (!tsm_ie_ind) + return; + + tsm_ie_ind->sessionId = pe_session->smeSessionId; + tsm_ie_ind->tsm_ie.tsid = tid; + tsm_ie_ind->tsm_ie.state = state; + tsm_ie_ind->tsm_ie.msmt_interval = measurement_interval; + + msg.type = eWNI_SME_TSM_IE_IND; + msg.bodyptr = tsm_ie_ind; + msg.bodyval = 0; + + lim_sys_process_mmh_msg_api(mac, &msg); +} +#endif /* FEATURE_WLAN_ESE */ + +void lim_extract_ies_from_deauth_disassoc(struct pe_session *session, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len) +{ + uint16_t reason_code, ie_offset; + struct element_info ie; + + if (!session) { + pe_err("NULL session"); + return; + } + + /* Get the offset of IEs */ + ie_offset = sizeof(struct wlan_frame_hdr) + sizeof(reason_code); + + if (!deauth_disassoc_frame || deauth_disassoc_frame_len <= ie_offset) + return; + + ie.ptr = deauth_disassoc_frame + ie_offset; + ie.len = deauth_disassoc_frame_len - ie_offset; + + mlme_set_peer_disconnect_ies(session->vdev, &ie); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void lim_get_sta_mld_log(tpDphHashNode sta_ds, tSirMacAddr mld_mac, + char *mld_log_str) +{ + if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)mld_mac)) + qdf_scnprintf(mld_log_str, MAC_ADDR_DUMP_LEN, + " SA mld: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mld_mac)); + + if (!qdf_is_macaddr_zero((struct qdf_mac_addr *) + sta_ds->mld_addr)) + qdf_scnprintf(mld_log_str, MAC_ADDR_DUMP_LEN, + " STA DS mld: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_ds->mld_addr)); +} +#else +static inline +void lim_get_sta_mld_log(tpDphHashNode sta_ds, tSirMacAddr mld_mac, + char *mld_log_str) +{ +} +#endif + +tpDphHashNode lim_get_sta_ds(struct mac_context *mac_ctx, + tSirMacAddr sa, tSirMacAddr mld_mac, + uint16_t *assoc_id, + struct pe_session *session) +{ + tpDphHashNode sta_ds = NULL; + char mld_log_str[52] = {0}; + + /* Check if STA present with SA address */ + sta_ds = dph_lookup_hash_entry( + mac_ctx, sa, + assoc_id, + &session->dph.dphHashTable); + /* Check if STA present with MLD address, + * this can happen if SAP is non ML, + * so the MLD address will be used as address for connected STA + */ + if (!sta_ds && !qdf_is_macaddr_zero((struct qdf_mac_addr *)mld_mac)) + sta_ds = dph_lookup_hash_entry( + mac_ctx, mld_mac, + assoc_id, + &session->dph.dphHashTable); + /* Check if STA present with same MLD address as current SA, + * this can happen if SAP is ML, so the MLD address will be + * used as SA address for connected STA + */ + if (!sta_ds && wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + sta_ds = dph_lookup_hash_entry_by_mld_addr( + mac_ctx, sa, + assoc_id, + &session->dph.dphHashTable); + if (sta_ds) { + lim_get_sta_mld_log(sta_ds, mld_mac, mld_log_str); + pe_debug("Vdev %d STA found for " QDF_MAC_ADDR_FMT "%s", + session->vdev_id, QDF_MAC_ADDR_REF(sa), mld_log_str); + } + return sta_ds; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h new file mode 100644 index 0000000000..4dffac6b60 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_assoc_utils.h @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_assoc_utils.h contains the utility definitions + * LIM uses while processing Re/Association messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ +#ifndef __LIM_ASSOC_UTILS_H +#define __LIM_ASSOC_UTILS_H + +#include "sir_api.h" +#include "sir_debug.h" + +#include "lim_types.h" +#include "wlan_cm_api.h" + +#define SIZE_OF_NOA_DESCRIPTOR 13 +#define MAX_NOA_PERIOD_IN_MICROSECS 3000000 + +uint8_t lim_compare_capabilities(struct mac_context *, + tSirAssocReq *, + tSirMacCapabilityInfo *, struct pe_session *); +uint8_t lim_check_rx_basic_rates(struct mac_context *, tSirMacRateSet, struct pe_session *); +uint8_t lim_check_mcs_set(struct mac_context *mac, uint8_t *supportedMCSSet); + +/** + * lim_cleanup_rx_path() - Called to cleanup STA state at SP & RFP. + * @mac: Pointer to Global MAC structure + * @sta: Pointer to the per STA data structure initialized by LIM + * and maintained at DPH + * @pe_session: pointer to pe session + * @delete_peer: is peer delete allowed + * + * To circumvent RFP's handling of dummy packet when it does not + * have an incomplete packet for the STA to be deleted, a packet + * with 'more framgents' bit set will be queued to RFP's WQ before + * queuing 'dummy packet'. + * A 'dummy' BD is pushed into RFP's WQ with type=00, subtype=1010 + * (Disassociation frame) and routing flags in BD set to eCPU's + * Low Priority WQ. + * RFP cleans up its local context for the STA id mentioned in the + * BD and then pushes BD to eCPU's low priority WQ. + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + */ +QDF_STATUS lim_cleanup_rx_path(struct mac_context *, tpDphHashNode, + struct pe_session *, bool delete_peer); + +void lim_reject_association(struct mac_context *, tSirMacAddr, uint8_t, + uint8_t, tAniAuthType, uint16_t, uint8_t, + enum wlan_status_code, struct pe_session *); + +QDF_STATUS lim_populate_peer_rate_set(struct mac_context *mac, + struct supported_rates *pRates, + uint8_t *pSupportedMCSSet, + uint8_t basicOnly, + struct pe_session *pe_session, + tDot11fIEVHTCaps *pVHTCaps, + tDot11fIEhe_cap *he_caps, + tDot11fIEeht_cap *eht_caps, + struct sDphHashNode *sta_ds, + struct bss_description *bss_desc); + +/** + * lim_populate_own_rate_set() - comprises the basic and extended rates read + * from CFG + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rates + * @supported_mcs_set: pointer to supported mcs rates + * @basic_only: update only basic rates if set true + * @session_entry: pe session entry + * @vht_caps: pointer to vht capability + * @he_caps: pointer to HE capability + * @eht_caps: pointer to EHT capability + * + * This function is called by limProcessAssocRsp() or + * lim_add_staInIBSS() + * - It creates a combined rate set of 12 rates max which + * comprises the basic and extended rates read from CFG + * - It sorts the combined rate Set and copy it in the + * rate array of the pSTA descriptor + * - It sets the erpEnabled bit of the STA descriptor + * ERP bit is set iff the dph PHY mode is 11G and there is at least + * an A rate in the supported or extended rate sets + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE. + */ +QDF_STATUS lim_populate_own_rate_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + uint8_t *supported_mcs_set, + uint8_t basic_only, + struct pe_session *session_entry, + struct sDot11fIEVHTCaps *vht_caps, + struct sDot11fIEhe_cap *he_caps, + struct sDot11fIEeht_cap *eht_caps); + +QDF_STATUS lim_populate_matching_rate_set(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + tSirMacRateSet *oper_rate_set, + tSirMacRateSet *ext_rate_set, + uint8_t *supported_mcs_set, + struct pe_session *session_entry, + tDot11fIEVHTCaps *vht_caps, + tDot11fIEhe_cap *he_caps, + tDot11fIEeht_cap *eht_caps); + +QDF_STATUS lim_add_sta(struct mac_context *, tpDphHashNode, uint8_t, struct pe_session *); +QDF_STATUS lim_del_bss(struct mac_context *, tpDphHashNode, uint16_t, struct pe_session *); +QDF_STATUS lim_del_sta(struct mac_context *, tpDphHashNode, bool, struct pe_session *); +QDF_STATUS lim_add_sta_self(struct mac_context *, uint8_t, struct pe_session *); + +/** + *lim_del_peer_info() - remove all peer information from host driver and fw + * @mac: Pointer to Global MAC structure + * @pe_session: Pointer to PE Session entry + * + * @Return: QDF_STATUS + */ +QDF_STATUS lim_del_peer_info(struct mac_context *mac, + struct pe_session *pe_session); + +/** + * lim_del_sta_all() - Cleanup all peers associated with VDEV + * @mac: Pointer to Global MAC structure + * @pe_session: Pointer to PE Session entry + * + * @Return: QDF Status of operation. + */ +QDF_STATUS lim_del_sta_all(struct mac_context *mac, + struct pe_session *pe_session); +/** + * lim_get_sta_ds() -get sta ds + * @mac_ctx: mac ctx + * @sa: source addr + * @mld_mac: mld mac + * @assoc_id: assoc id + * @session: pe session ctx + * + * @Return: sta ds in case of success else NULL + */ +tpDphHashNode lim_get_sta_ds(struct mac_context *mac_ctx, + tSirMacAddr sa, tSirMacAddr mld_mac, + uint16_t *assoc_id, + struct pe_session *session); + +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_restore_pre_reassoc_state(struct mac_context *, + tSirResultCodes, uint16_t, struct pe_session *); +void lim_post_reassoc_failure(struct mac_context *, + tSirResultCodes, uint16_t, struct pe_session *); +bool lim_is_reassoc_in_progress(struct mac_context *, struct pe_session *); + +void lim_handle_add_bss_in_re_assoc_context(struct mac_context *mac, + tpDphHashNode sta, struct pe_session *pe_session); +void lim_handle_del_bss_in_re_assoc_context(struct mac_context *mac, + tpDphHashNode sta, struct pe_session *pe_session); +void lim_send_retry_reassoc_req_frame(struct mac_context *mac, + tLimMlmReassocReq *pMlmReassocReq, struct pe_session *pe_session); +QDF_STATUS lim_add_ft_sta_self(struct mac_context *mac, uint16_t assocId, + struct pe_session *pe_session); +#else +static inline void lim_restore_pre_reassoc_state(struct mac_context *mac_ctx, + tSirResultCodes res_code, uint16_t prot_status, + struct pe_session *pe_session) +{} +static inline void lim_post_reassoc_failure(struct mac_context *mac_ctx, + tSirResultCodes res_code, uint16_t prot_status, + struct pe_session *pe_session) +{} +static inline void lim_handle_add_bss_in_re_assoc_context(struct mac_context *mac, + tpDphHashNode sta, struct pe_session *pe_session) +{} +static inline void lim_handle_del_bss_in_re_assoc_context(struct mac_context *mac, + tpDphHashNode sta, struct pe_session *pe_session) +{} +static inline void lim_send_retry_reassoc_req_frame(struct mac_context *mac, + tLimMlmReassocReq *pMlmReassocReq, struct pe_session *pe_session) +{} +static inline bool lim_is_reassoc_in_progress(struct mac_context *mac_ctx, + struct pe_session *pe_session) +{ + return false; +} +static inline QDF_STATUS lim_add_ft_sta_self(struct mac_context *mac, + uint16_t assocId, struct pe_session *pe_session) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE +static inline bool +lim_is_add_sta_params_eht_capable(tpAddStaParams add_sta_params) +{ + return add_sta_params->eht_capable; +} +#else +static inline bool +lim_is_add_sta_params_eht_capable(tpAddStaParams add_sta_params) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static inline bool lim_is_roam_synch_in_progress(struct wlan_objmgr_psoc *psoc, + struct pe_session *pe_session) +{ + return wlan_cm_is_vdev_roam_sync_inprogress(pe_session->vdev); +} +#else +static inline bool lim_is_roam_synch_in_progress(struct wlan_objmgr_psoc *psoc, + struct pe_session *pe_session) +{ + return false; +} +#endif + +void +lim_send_del_sta_cnf(struct mac_context *mac, struct qdf_mac_addr sta_dsaddr, + struct qdf_mac_addr sta_mld_addr, + uint16_t staDsAssocId, + struct lim_sta_context mlmStaContext, + tSirResultCodes status_code, + struct pe_session *pe_session); + +void lim_handle_cnf_wait_timeout(struct mac_context *mac, uint16_t staId); +void lim_delete_dph_hash_entry(struct mac_context *, tSirMacAddr, uint16_t, struct pe_session *); +void lim_check_and_announce_join_success(struct mac_context *, + tSirProbeRespBeacon *, + tpSirMacMgmtHdr, struct pe_session *); +void lim_update_re_assoc_globals(struct mac_context *mac, + tpSirAssocRsp pAssocRsp, + struct pe_session *pe_session); + +void lim_update_assoc_sta_datas(struct mac_context *mac, + tpDphHashNode sta, tpSirAssocRsp pAssocRsp, + struct pe_session *pe_session, + tSchBeaconStruct *beacon); + +/** + * lim_sta_add_bss_update_ht_parameter() - function to update ht related + * parameters when add bss request + * @bss_chan_freq: operating frequency of bss + * @ht_cap: ht capability extract from beacon/assoc response + * @ht_inf: ht information extract from beacon/assoc response + * @chan_width_support: local wide bandwidth support capability + * @add_bss: add bss request struct to be updated + * + * Return: none + */ +void lim_sta_add_bss_update_ht_parameter(uint32_t bss_chan_freq, + tDot11fIEHTCaps* ht_cap, + tDot11fIEHTInfo* ht_inf, + bool chan_width_support, + struct bss_params *add_bss); + +/** + * lim_sta_send_add_bss() - add bss and send peer assoc after receive assoc + * rsp in sta mode + *.@mac: pointer to Global MAC structure + * @pAssocRsp: contains the structured assoc/reassoc Response got from AP + * @beaconstruct: the ProbeRsp/Beacon structured details + * @bssDescription: bss description passed to PE from the SME + * @updateEntry: bool flag of whether update bss and sta + * @pe_session: pointer to pe session + * + * Return: none + */ +QDF_STATUS lim_sta_send_add_bss(struct mac_context *mac, + tpSirAssocRsp pAssocRsp, + tpSchBeaconStruct pBeaconStruct, + struct bss_description *bssDescription, + uint8_t updateEntry, + struct pe_session *pe_session); + +/** + * lim_sta_send_add_bss_pre_assoc() - add bss after channel switch and before + * associate req in sta mode + *.@mac: pointer to Global MAC structure + * @pe_session: pointer to pe session + * + * Return: none + */ +QDF_STATUS lim_sta_send_add_bss_pre_assoc(struct mac_context *mac, + struct pe_session *pe_session); + +void lim_prepare_and_send_del_all_sta_cnf(struct mac_context *mac, + tSirResultCodes status_code, + struct pe_session *pe_session); + +void lim_prepare_and_send_del_sta_cnf(struct mac_context *mac, + tpDphHashNode sta, + tSirResultCodes status_code, + struct pe_session *pe_session); + +QDF_STATUS lim_extract_ap_capabilities(struct mac_context *mac, uint8_t *pIE, + uint16_t ieLen, + tpSirProbeRespBeacon beaconStruct); +void lim_init_pre_auth_timer_table(struct mac_context *mac, + tpLimPreAuthTable pPreAuthTimerTable); +tpLimPreAuthNode lim_acquire_free_pre_auth_node(struct mac_context *mac, + tpLimPreAuthTable + pPreAuthTimerTable); +tpLimPreAuthNode lim_get_pre_auth_node_from_index(struct mac_context *mac, + tpLimPreAuthTable pAuthTable, + uint32_t authNodeIdx); + +/* Util API to check if the channels supported by STA is within range */ +QDF_STATUS lim_is_dot11h_supported_channels_valid(struct mac_context *mac, + tSirAssocReq *assoc); + +/* Util API to check if the txpower supported by STA is within range */ +QDF_STATUS lim_is_dot11h_power_capabilities_in_range(struct mac_context *mac, + tSirAssocReq *assoc, + struct pe_session *); +/** + * lim_fill_rx_highest_supported_rate() - Fill highest rx rate + * @mac: Global MAC context + * @rxHighestRate: location to store the highest rate + * @pSupportedMCSSet: location of the 'supported MCS set' field in HT + * capability element + * + * Fills in the Rx Highest Supported Data Rate field from + * the 'supported MCS set' field in HT capability element. + * + * Return: void + */ +void lim_fill_rx_highest_supported_rate(struct mac_context *mac, + uint16_t *rxHighestRate, + uint8_t *pSupportedMCSSet); +void lim_send_sme_unprotected_mgmt_frame_ind(struct mac_context *mac, uint8_t frameType, + uint8_t *frame, uint32_t frameLen, + uint16_t sessionId, + struct pe_session *pe_session); +/** + * lim_send_sme_tsm_ie_ind() - Send TSM IE information to SME + * @mac: Global MAC context + * @pe_session: PE session context + * @tid: traffic id + * @state: tsm state (enabled/disabled) + * @measurement_interval: measurement interval + * + * Return: void + */ +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_tsm_ie_ind(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t tid, uint8_t state, + uint16_t measurement_interval); +#else +static inline +void lim_send_sme_tsm_ie_ind(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t tid, uint8_t state, + uint16_t measurement_interval) +{} +#endif /* FEATURE_WLAN_ESE */ + +/** + * lim_populate_vht_mcs_set - function to populate vht mcs rate set + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rate set + * @peer_vht_caps: pointer to peer vht capabilities + * @session_entry: pe session entry + * @nss: number of spatial streams + * @sta_ds: pointer to peer sta data structure + * + * Populates vht mcs rate set based on peer and self capabilities + * + * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS_E_FAILURE + */ +QDF_STATUS lim_populate_vht_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEVHTCaps *peer_vht_caps, + struct pe_session *session_entry, + uint8_t nss, + struct sDphHashNode *sta_ds); + +/** + * lim_extract_ies_from_deauth_disassoc() - Extract IEs from deauth/disassoc + * + * @session: PE session entry + * @deauth_disassoc_frame: A pointer to the deauth/disconnect frame buffer + * received from WMA. + * @deauth_disassoc_frame_leni: Length of the deauth/disconnect frame. + * + * This function receives deauth/disassoc frame from header. It extracts + * the IEs(tagged params) from the frame and caches in vdev object. + * + * Return: None + */ +void +lim_extract_ies_from_deauth_disassoc(struct pe_session *session, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len); + +/** + * lim_update_vhtcaps_assoc_resp : Update VHT caps in assoc response. + * @mac_ctx Pointer to Global MAC structure + * @pAddBssParams: parameters required for add bss params. + * @vht_caps: VHT capabilities. + * @pe_session : session entry. + * + * Return : void + */ +void lim_update_vhtcaps_assoc_resp(struct mac_context *mac_ctx, + struct bss_params *pAddBssParams, + tDot11fIEVHTCaps *vht_caps, + struct pe_session *pe_session); + +/** + * lim_free_assoc_req_frm_buf() - free assoc request frame buffer + * @assoc_req: pointer to tpSirAssocReq + * + * Return : void + */ +void lim_free_assoc_req_frm_buf(tpSirAssocReq assoc_req); + +/** + * lim_alloc_assoc_req_frm_buf() - allocate assoc request frame buffer + * @assoc_req: pointer to tpSirAssocReq + * @buf: pointer to assoc request frame + * @mac_header_len: ieee80211 header length + * @frame_len: payload length of assoc request frame + */ +bool lim_alloc_assoc_req_frm_buf(tpSirAssocReq assoc_req, + qdf_nbuf_t buf, uint32_t mac_header_len, + uint32_t frame_len); +#endif /* __LIM_ASSOC_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c new file mode 100644 index 0000000000..f219ca4a43 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ft.c @@ -0,0 +1,1112 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \brief implementation for PE 11r VoWiFi FT Protocol + + ========================================================================*/ + +/* $Header$ */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wmm_apsd.h" +#include "wma.h" +#include "wlan_cmn.h" + +/*-------------------------------------------------------------------------- + Initialize the FT variables. + ------------------------------------------------------------------------*/ +void lim_ft_open(struct mac_context *mac, struct pe_session *pe_session) +{ + if (pe_session) + qdf_mem_zero(&pe_session->ftPEContext, sizeof(tftPEContext)); +} + +void lim_ft_cleanup_all_ft_sessions(struct mac_context *mac) +{ + /* Wrapper function to cleanup all FT sessions */ + int i; + + for (i = 0; i < mac->lim.maxBssId; i++) { + if (true == mac->lim.gpSession[i].valid) { + /* The session is valid, may have FT data */ + lim_ft_cleanup(mac, &mac->lim.gpSession[i]); + } + } +} + +void lim_ft_cleanup(struct mac_context *mac, struct pe_session *pe_session) +{ + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_debug("pe_session is not in STA mode"); + return; + } + + if (pe_session->ftPEContext.pFTPreAuthReq) { + pe_debug("Freeing pFTPreAuthReq: %pK", + pe_session->ftPEContext.pFTPreAuthReq); + if (NULL != + pe_session->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq-> + pbssDescription); + pe_session->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq); + pe_session->ftPEContext.pFTPreAuthReq = NULL; + } + + if (pe_session->ftPEContext.pAddBssReq) { + qdf_mem_free(pe_session->ftPEContext.pAddBssReq); + pe_session->ftPEContext.pAddBssReq = NULL; + } + + if (pe_session->ftPEContext.pAddStaReq) { + qdf_mem_free(pe_session->ftPEContext.pAddStaReq); + pe_session->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + qdf_mem_zero(&pe_session->ftPEContext, sizeof(tftPEContext)); +} + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/*------------------------------------------------------------------ + * + * Create the new Add Bss Req to the new AP. + * This will be used when we are ready to FT to the new AP. + * The newly created ft Session entry is passed to this function + * + *------------------------------------------------------------------*/ +void lim_ft_prepare_add_bss_req(struct mac_context *mac, + struct pe_session *ft_session, + struct bss_description *bssDescription) +{ + struct bss_params *pAddBssParams = NULL; + tAddStaParams *sta_ctx; + bool chan_width_support = false; + tSchBeaconStruct *pBeaconStruct; + tDot11fIEVHTCaps *vht_caps = NULL; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(ft_session)) { + pe_err("pe_session is not in STA mode"); + return; + } + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!pBeaconStruct) + return; + + /* Package SIR_HAL_ADD_BSS_REQ message parameters */ + pAddBssParams = qdf_mem_malloc(sizeof(struct bss_params)); + if (!pAddBssParams) { + qdf_mem_free(pBeaconStruct); + return; + } + + lim_extract_ap_capabilities(mac, (uint8_t *) bssDescription->ieFields, + lim_get_ielen_from_bss_description(bssDescription), + pBeaconStruct); + + if (mac->lim.gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac, pBeaconStruct, + ft_session); + + qdf_mem_copy(pAddBssParams->bssId, bssDescription->bssId, + sizeof(tSirMacAddr)); + pAddBssParams->beaconInterval = bssDescription->beaconInterval; + + pAddBssParams->dtimPeriod = pBeaconStruct->tim.dtimPeriod; + pAddBssParams->updateBss = false; + + pAddBssParams->nwType = bssDescription->nwType; + + pAddBssParams->shortSlotTimeSupported = + (uint8_t) pBeaconStruct->capabilityInfo.shortSlotTime; + pAddBssParams->llbCoexist = + (uint8_t) ft_session->beaconParams.llbCoexist; + pAddBssParams->rmfEnabled = ft_session->limRmfEnabled; + + /* Use the advertised capabilities from the received beacon/PR */ + if (IS_DOT11_MODE_HT(ft_session->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + chan_width_support = + lim_get_ht_capability(mac, + eHT_SUPPORTED_CHANNEL_WIDTH_SET, + ft_session); + lim_sta_add_bss_update_ht_parameter(bssDescription->chan_freq, + &pBeaconStruct->HTCaps, + &pBeaconStruct->HTInfo, + chan_width_support, + pAddBssParams); + qdf_mem_copy(&pAddBssParams->staContext.capab_info, + &pBeaconStruct->capabilityInfo, + sizeof(pAddBssParams->staContext.capab_info)); + qdf_mem_copy(&pAddBssParams->staContext.ht_caps, + (uint8_t *) &pBeaconStruct->HTCaps + + sizeof(uint8_t), + sizeof(pAddBssParams->staContext.ht_caps)); + } + + ft_session->htSecondaryChannelOffset = + pBeaconStruct->HTInfo.secondaryChannelOffset; + sta_ctx = &pAddBssParams->staContext; + /* + * in lim_extract_ap_capability function intersection of FW + * advertised channel width and AP advertised channel + * width has been taken into account for calculating + * pe_session->ch_width + */ + pAddBssParams->ch_width = ft_session->ch_width; + sta_ctx->ch_width = ft_session->ch_width; + + if (ft_session->vhtCapability && + ft_session->vhtCapabilityPresentInBeacon) { + pAddBssParams->vhtCapable = pBeaconStruct->VHTCaps.present; + vht_caps = &pBeaconStruct->VHTCaps; + lim_update_vhtcaps_assoc_resp(mac, pAddBssParams, + vht_caps, ft_session); + } else if (ft_session->vhtCapability && + pBeaconStruct->vendor_vht_ie.VHTCaps.present) { + pe_debug("VHT caps are present in vendor specific IE"); + pAddBssParams->vhtCapable = + pBeaconStruct->vendor_vht_ie.VHTCaps.present; + vht_caps = &pBeaconStruct->vendor_vht_ie.VHTCaps; + lim_update_vhtcaps_assoc_resp(mac, pAddBssParams, + vht_caps, ft_session); + } else { + pAddBssParams->vhtCapable = 0; + } + + if (lim_is_session_he_capable(ft_session) && + pBeaconStruct->he_cap.present) { + lim_update_bss_he_capable(mac, pAddBssParams); + lim_add_bss_he_cfg(pAddBssParams, ft_session); + } + + if (lim_is_session_eht_capable(ft_session) && + pBeaconStruct->eht_cap.present) { + lim_update_bss_eht_capable(mac, pAddBssParams); + lim_add_bss_eht_cfg(pAddBssParams, ft_session); + } + + pe_debug("SIR_HAL_ADD_BSS_REQ with frequency: %d, width: %d", + bssDescription->chan_freq, pAddBssParams->ch_width); + + /* Populate the STA-related parameters here */ + /* Note that the STA here refers to the AP */ + { + pAddBssParams->staContext.staType = STA_ENTRY_OTHER; + + qdf_mem_copy(pAddBssParams->staContext.bssId, + bssDescription->bssId, sizeof(tSirMacAddr)); + pAddBssParams->staContext.listenInterval = + bssDescription->beaconInterval; + + pAddBssParams->staContext.assocId = 0; + pAddBssParams->staContext.uAPSD = 0; + pAddBssParams->staContext.maxSPLen = 0; + pAddBssParams->staContext.updateSta = false; + pAddBssParams->staContext.encryptType = + ft_session->encryptType; + pAddBssParams->staContext.rmfEnabled = + ft_session->limRmfEnabled; + + if (IS_DOT11_MODE_HT(ft_session->dot11mode) && + (pBeaconStruct->HTCaps.present)) { + pAddBssParams->staContext.htCapable = 1; + if (ft_session->vhtCapability && + IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps)) { + pAddBssParams->staContext.vhtCapable = 1; + if ((pBeaconStruct->VHTCaps.suBeamFormerCap || + pBeaconStruct->VHTCaps.muBeamformerCap) && + ft_session->vht_config.su_beam_formee) + sta_ctx->vhtTxBFCapable + = 1; + if (pBeaconStruct->VHTCaps.suBeamformeeCap && + ft_session->vht_config.su_beam_former) + sta_ctx->enable_su_tx_bformer = 1; + } + if (lim_is_session_he_capable(ft_session) && + pBeaconStruct->he_cap.present) + lim_intersect_ap_he_caps(ft_session, + pAddBssParams, + pBeaconStruct, NULL, + bssDescription); + + if (lim_is_session_eht_capable(ft_session) && + pBeaconStruct->eht_cap.present) + lim_intersect_ap_eht_caps(ft_session, + pAddBssParams, + pBeaconStruct, NULL); + + pAddBssParams->staContext.mimoPS = + (tSirMacHTMIMOPowerSaveState) pBeaconStruct->HTCaps. + mimoPowerSave; + pAddBssParams->staContext.maxAmpduDensity = + pBeaconStruct->HTCaps.mpduDensity; + pAddBssParams->staContext.fShortGI20Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI20MHz; + pAddBssParams->staContext.fShortGI40Mhz = + (uint8_t) pBeaconStruct->HTCaps.shortGI40MHz; + pAddBssParams->staContext.maxAmpduSize = + pBeaconStruct->HTCaps.maxRxAMPDUFactor; + } + + if ((ft_session->limWmeEnabled + && pBeaconStruct->wmeEdcaPresent) + || (ft_session->limQosEnabled + && pBeaconStruct->edcaPresent)) + pAddBssParams->staContext.wmmEnabled = 1; + else + pAddBssParams->staContext.wmmEnabled = 0; + + pAddBssParams->staContext.wpa_rsn = pBeaconStruct->rsnPresent; + /* For OSEN Connection AP does not advertise RSN or WPA IE + * so from the IEs we get from supplicant we get this info + * so for FW to transmit EAPOL message 4 we shall set + * wpa_rsn + */ + pAddBssParams->staContext.wpa_rsn |= + (pBeaconStruct->wpaPresent << 1); + if ((!pAddBssParams->staContext.wpa_rsn) + && (ft_session->isOSENConnection)) + pAddBssParams->staContext.wpa_rsn = 1; + /* Update the rates */ + lim_populate_peer_rate_set(mac, + &pAddBssParams->staContext. + supportedRates, + pBeaconStruct->HTCaps.supportedMCSSet, + false, ft_session, + &pBeaconStruct->VHTCaps, + &pBeaconStruct->he_cap, + &pBeaconStruct->eht_cap, NULL, + bssDescription); + } + + pAddBssParams->maxTxPower = ft_session->maxTxPower; + + if (ft_session->limRmfEnabled) { + pAddBssParams->rmfEnabled = 1; + pAddBssParams->staContext.rmfEnabled = 1; + } + pAddBssParams->staContext.sessionId = ft_session->peSessionId; + pAddBssParams->staContext.smesessionId = ft_session->smeSessionId; + + /* Set a new state for MLME */ + if (!lim_is_roam_synch_in_progress(mac->psoc, ft_session)) { + ft_session->limMlmState = + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, + ft_session->peSessionId, + eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE)); + } + ft_session->ftPEContext.pAddBssReq = pAddBssParams; + + pe_debug("Saving SIR_HAL_ADD_BSS_REQ for pre-auth ap"); + + qdf_mem_free(pBeaconStruct); + return; +} +#endif + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) + +/** + * lim_convert_phymode_to_dot11mode() - get dot11 mode from phymode + * @phymode: phymode + * + * The function is to convert the phymode to corresponding dot11 mode + * + * Return: dot11mode. + */ +static uint8_t lim_convert_phymode_to_dot11mode(enum wlan_phymode phymode) +{ + + if (IS_WLAN_PHYMODE_HE(phymode)) + return MLME_DOT11_MODE_11AX; + + if (IS_WLAN_PHYMODE_VHT(phymode)) + return MLME_DOT11_MODE_11AC; + + if (IS_WLAN_PHYMODE_HT(phymode)) + return MLME_DOT11_MODE_11N; + +#ifdef WLAN_FEATURE_11BE + if (IS_WLAN_PHYMODE_EHT(phymode)) + return MLME_DOT11_MODE_11BE; +#endif + + if (phymode == WLAN_PHYMODE_11G) + return MLME_DOT11_MODE_11G; + + if (phymode == WLAN_PHYMODE_11G_ONLY) + return MLME_DOT11_MODE_11G_ONLY; + + if (phymode == WLAN_PHYMODE_11A) + return MLME_DOT11_MODE_11A; + + if (phymode == WLAN_PHYMODE_11B) + return MLME_DOT11_MODE_11B; + + return MLME_DOT11_MODE_ALL; +} + +/** + * lim_calculate_dot11_mode() - calculate dot11 mode. + * @mac_ctx: mac context + * @bcn: beacon structure + * @band: reg_wifi_band + * + * The function is to calculate dot11 mode in case fw doesn't send phy mode. + * + * Return: dot11mode. + */ +static uint8_t lim_calculate_dot11_mode(struct mac_context *mac_ctx, + tSchBeaconStruct *bcn, + enum reg_wifi_band band) +{ + enum mlme_dot11_mode self_dot11_mode; + enum mlme_dot11_mode new_dot11_mode; + + self_dot11_mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + + if (band == REG_BAND_2G) + new_dot11_mode = MLME_DOT11_MODE_11G; + else + new_dot11_mode = MLME_DOT11_MODE_11A; + + switch (self_dot11_mode) { + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11AX_ONLY: + case MLME_DOT11_MODE_ALL: + if (bcn->he_cap.present) + return MLME_DOT11_MODE_11AX; + else if ((bcn->VHTCaps.present || + bcn->vendor_vht_ie.present) && + (!(band == REG_BAND_2G && + !mac_ctx->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) + )) + + return MLME_DOT11_MODE_11AC; + else if (bcn->HTCaps.present) + return MLME_DOT11_MODE_11N; + fallthrough; + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AC_ONLY: + if ((bcn->VHTCaps.present || + bcn->vendor_vht_ie.present) && + (!(band == REG_BAND_2G && + !mac_ctx->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) + )) + return MLME_DOT11_MODE_11AC; + else if (bcn->HTCaps.present) + return MLME_DOT11_MODE_11N; + fallthrough; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11N_ONLY: + if (bcn->HTCaps.present) + return MLME_DOT11_MODE_11N; + fallthrough; + default: + return new_dot11_mode; + } + +} + +/** + * lim_fill_dot11mode() - to fill 802.11 mode in FT session + * @mac_ctx: pointer to mac ctx + * @ft_session: FT session + * @pe_session: PE session + * @bcn: AP beacon pointer + * @bss_phymode: bss phy mode + * + * This API fills FT session's dot11mode either from pe session or + * from CFG depending on the condition. + * + * Return: none + */ +static void lim_fill_dot11mode(struct mac_context *mac_ctx, + struct pe_session *ft_session, + struct pe_session *pe_session, + tSchBeaconStruct *bcn, + enum wlan_phymode bss_phymode) +{ + if (pe_session->ftPEContext.pFTPreAuthReq && + !wlan_is_roam_offload_enabled(mac_ctx->mlme_cfg->lfr)) { + ft_session->dot11mode = + pe_session->ftPEContext.pFTPreAuthReq->dot11mode; + return; + } + + if (bss_phymode == WLAN_PHYMODE_AUTO) + ft_session->dot11mode = lim_calculate_dot11_mode( + mac_ctx, bcn, + ft_session->limRFBand); + + else + ft_session->dot11mode = + lim_convert_phymode_to_dot11mode(bss_phymode); +} +#elif defined(WLAN_FEATURE_HOST_ROAM) +/** + * lim_fill_dot11mode() - to fill 802.11 mode in FT session + * @mac_ctx: pointer to mac ctx + * @ft_session: FT session + * @pe_session: PE session + * @bcn: AP beacon pointer + * @bss_phymode: bss phy mode + * + * This API fills FT session's dot11mode either from pe session. + * + * Return: none + */ +static void lim_fill_dot11mode(struct mac_context *mac_ctx, + struct pe_session *ft_session, + struct pe_session *pe_session, + tSchBeaconStruct *bcn, + enum wlan_phymode bss_phymode) +{ + ft_session->dot11mode = + pe_session->ftPEContext.pFTPreAuthReq->dot11mode; +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * lim_fill_session_power_info() - to fill power info in session + * @mac: pointer to mac ctx + * @pbssDescription: Pointer to pbssDescription + * @ft_session: Pointer to FT session + * @pe_session: Pointer to PE session + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_fill_session_power_info( + struct mac_context *mac, + struct bss_description *pbssDescription, + struct pe_session *ft_session, + struct pe_session *pe_session) +{ + uint8_t currentBssUapsd; + int8_t localPowerConstraint = 0; + int8_t regMax = 0; + bool is_pwr_constraint = false; + struct vdev_mlme_obj *mlme_obj; + enum reg_6g_ap_type power_type_6g; + QDF_STATUS status; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + lim_extract_ap_capability(mac, (uint8_t *)pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + &ft_session->limCurrentBssQosCaps, + ¤tBssUapsd, + &localPowerConstraint, ft_session, &is_pwr_constraint); + + mlme_obj->reg_tpc_obj.is_power_constraint_abs = !is_pwr_constraint; + + if (wlan_reg_is_6ghz_chan_freq(pbssDescription->chan_freq)) { + status = wlan_reg_get_best_6g_power_type( + mac->psoc, mac->pdev, + &power_type_6g, + ft_session->ap_defined_power_type_6g, + pbssDescription->chan_freq); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + ft_session->best_6g_power_type = power_type_6g; + mlme_set_best_6g_power_type(ft_session->vdev, power_type_6g); + } + + if (wlan_reg_is_ext_tpc_supported(mac->psoc)) { + mlme_obj->reg_tpc_obj.ap_constraint_power = + localPowerConstraint; + } else { + regMax = wlan_reg_get_channel_reg_power_for_freq( + mac->pdev, ft_session->curr_op_freq); + if (is_pwr_constraint) + localPowerConstraint = regMax - localPowerConstraint; + if (!localPowerConstraint) + localPowerConstraint = regMax; + + mlme_obj->reg_tpc_obj.reg_max[0] = regMax; + mlme_obj->reg_tpc_obj.ap_constraint_power = + localPowerConstraint; + mlme_obj->reg_tpc_obj.frequency[0] = ft_session->curr_op_freq; + +#ifdef FEATURE_WLAN_ESE + ft_session->maxTxPower = lim_get_max_tx_power(mac, mlme_obj); +#else + ft_session->maxTxPower = QDF_MIN(regMax, localPowerConstraint); +#endif + ft_session->def_max_tx_pwr = ft_session->maxTxPower; + } + + /* + * for mdm platform which QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET + * will not call from android framework every 3 seconds, and tx + * power will never update. So we use iw dev get tx power need + * set maxTxPower non-zero value, that firmware can calc a non-zero + * tx power, and update to host driver. + */ + if (ft_session->maxTxPower == 0) + ft_session->maxTxPower = + wlan_reg_get_channel_reg_power_for_freq(mac->pdev, + ft_session->curr_op_freq); + + pe_debug("Reg max: %d local pwr: %d, max tx pwr: %d", regMax, + localPowerConstraint, ft_session->maxTxPower); + + return QDF_STATUS_SUCCESS; +} + +/*------------------------------------------------------------------ + * + * Setup the new session for the pre-auth AP. + * Return the newly created session entry. + * + *------------------------------------------------------------------*/ +QDF_STATUS +lim_fill_ft_session(struct mac_context *mac, + struct bss_description *pbssDescription, + struct pe_session *ft_session, + struct pe_session *pe_session, + enum wlan_phymode bss_phymode) +{ + uint8_t bss_chan_id; + tSchBeaconStruct *pBeaconStruct; + uint8_t cb_mode; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pBeaconStruct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!pBeaconStruct) + return QDF_STATUS_E_NOMEM; + + /* Retrieve the session that was already created and update the entry */ + ft_session->limWmeEnabled = pe_session->limWmeEnabled; + ft_session->limQosEnabled = pe_session->limQosEnabled; + ft_session->limWsmEnabled = pe_session->limWsmEnabled; + ft_session->lim11hEnable = pe_session->lim11hEnable; + ft_session->isOSENConnection = pe_session->isOSENConnection; + ft_session->connected_akm = pe_session->connected_akm; + + /* Fields to be filled later */ + ft_session->lim_join_req = NULL; + ft_session->smeSessionId = pe_session->smeSessionId; + + lim_extract_ap_capabilities(mac, (uint8_t *) pbssDescription->ieFields, + lim_get_ielen_from_bss_description(pbssDescription), + pBeaconStruct); + + qdf_mem_zero(&ft_session->wmm_params, sizeof(tDot11fIEWMMParams)); + if (pBeaconStruct->wmm_params.present) + qdf_mem_copy(&ft_session->wmm_params, + &pBeaconStruct->wmm_params, + sizeof(tDot11fIEWMMParams)); + + ft_session->rateSet.numRates = + pBeaconStruct->supportedRates.numRates; + qdf_mem_copy(ft_session->rateSet.rate, + pBeaconStruct->supportedRates.rate, + pBeaconStruct->supportedRates.numRates); + + ft_session->extRateSet.numRates = + pBeaconStruct->extendedRates.numRates; + qdf_mem_copy(ft_session->extRateSet.rate, + pBeaconStruct->extendedRates.rate, + ft_session->extRateSet.numRates); + + ft_session->ssId.length = pBeaconStruct->ssId.length; + qdf_mem_copy(ft_session->ssId.ssId, pBeaconStruct->ssId.ssId, + ft_session->ssId.length); + /* Copy The channel Id to the session Table */ + bss_chan_id = + wlan_reg_freq_to_chan(mac->pdev, pbssDescription->chan_freq); + ft_session->lim_reassoc_chan_freq = pbssDescription->chan_freq; + ft_session->curr_op_freq = pbssDescription->chan_freq; + ft_session->limRFBand = lim_get_rf_band(ft_session->curr_op_freq); + + lim_fill_dot11mode(mac, ft_session, pe_session, pBeaconStruct, + bss_phymode); + pe_debug("dot11mode: %d bss_phymode %d", ft_session->dot11mode, + bss_phymode); + + ft_session->vhtCapability = + (IS_DOT11_MODE_VHT(ft_session->dot11mode) && + (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) || + IS_BSS_VHT_CAPABLE(pBeaconStruct->vendor_vht_ie.VHTCaps))); + ft_session->htCapability = + (IS_DOT11_MODE_HT(ft_session->dot11mode) + && pBeaconStruct->HTCaps.present); + + if (IS_DOT11_MODE_HE(ft_session->dot11mode) && + pBeaconStruct->he_cap.present) { + lim_update_session_he_capable(mac, ft_session); + lim_copy_join_req_he_cap(ft_session); + } + if (IS_DOT11_MODE_EHT(ft_session->dot11mode) && + pBeaconStruct->eht_cap.present) { + lim_update_session_eht_capable(mac, ft_session); + lim_copy_join_req_eht_cap(ft_session); + } + /* Assign default configured nss value in the new session */ + if (!wlan_reg_is_24ghz_ch_freq(ft_session->curr_op_freq)) + ft_session->vdev_nss = mac->vdev_type_nss_5g.sta; + else + ft_session->vdev_nss = mac->vdev_type_nss_2g.sta; + + ft_session->nss = ft_session ->vdev_nss; + + cb_mode = lim_get_cb_mode_for_freq(mac, ft_session, + ft_session->curr_op_freq); + + ft_session->htSupportedChannelWidthSet = + (pBeaconStruct->HTInfo.present) ? + (cb_mode && pBeaconStruct->HTInfo.recommendedTxWidthSet && + pBeaconStruct->HTCaps.supportedChannelWidthSet) : 0; + ft_session->htRecommendedTxWidthSet = + ft_session->htSupportedChannelWidthSet; + + if (IS_BSS_VHT_CAPABLE(pBeaconStruct->VHTCaps) && + pBeaconStruct->VHTOperation.present && + ft_session->vhtCapability) { + ft_session->vhtCapabilityPresentInBeacon = 1; + } else if (IS_BSS_VHT_CAPABLE(pBeaconStruct->vendor_vht_ie.VHTCaps) && + pBeaconStruct->vendor_vht_ie.VHTOperation.present && + ft_session->vhtCapability){ + ft_session->vhtCapabilityPresentInBeacon = 1; + } else { + ft_session->vhtCapabilityPresentInBeacon = 0; + } + + if (ft_session->htRecommendedTxWidthSet) { + ft_session->ch_width = CH_WIDTH_40MHZ; + if (ft_session->vhtCapabilityPresentInBeacon && + pBeaconStruct->VHTOperation.chanWidth) { + ft_session->ch_width = + pBeaconStruct->VHTOperation.chanWidth + 1; + ft_session->ch_center_freq_seg0 = + pBeaconStruct->VHTOperation.chan_center_freq_seg0; + ft_session->ch_center_freq_seg1 = + pBeaconStruct->VHTOperation.chan_center_freq_seg1; + } else if (ft_session->vhtCapabilityPresentInBeacon && + pBeaconStruct->vendor_vht_ie.VHTOperation.chanWidth) { + ft_session->ch_width = + pBeaconStruct->vendor_vht_ie.VHTOperation.chanWidth + 1; + ft_session->ch_center_freq_seg0 = + pBeaconStruct->vendor_vht_ie.VHTOperation.chan_center_freq_seg0; + ft_session->ch_center_freq_seg1 = + pBeaconStruct->vendor_vht_ie.VHTOperation.chan_center_freq_seg1; + + } else { + if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + ft_session->ch_center_freq_seg0 = + bss_chan_id + 2; + else if (pBeaconStruct->HTInfo.secondaryChannelOffset == + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + ft_session->ch_center_freq_seg0 = + bss_chan_id - 2; + else { + pe_warn("Invalid sec ch offset"); + ft_session->ch_width = CH_WIDTH_20MHZ; + ft_session->ch_center_freq_seg0 = 0; + ft_session->ch_center_freq_seg1 = 0; + } + } + } else { + ft_session->ch_width = CH_WIDTH_20MHZ; + ft_session->ch_center_freq_seg0 = 0; + ft_session->ch_center_freq_seg1 = 0; + } + + sir_copy_mac_addr(ft_session->self_mac_addr, + wlan_vdev_mlme_get_macaddr(pe_session->vdev)); + sir_copy_mac_addr(ft_session->limReAssocbssId, + pbssDescription->bssId); + sir_copy_mac_addr(ft_session->prev_ap_bssid, pe_session->bssId); + + /* Store beaconInterval */ + ft_session->beaconParams.beaconInterval = + pbssDescription->beaconInterval; + ft_session->bssType = pe_session->bssType; + + ft_session->statypeForBss = STA_ENTRY_PEER; + ft_session->nwType = pbssDescription->nwType; + + + if (ft_session->bssType == eSIR_INFRASTRUCTURE_MODE) { + ft_session->limSystemRole = eLIM_STA_ROLE; + } else { + /* Throw an error & return & make sure to delete the session */ + pe_warn("Invalid bss type"); + } + + ft_session->limCurrentBssCaps = pbssDescription->capabilityInfo; + ft_session->limReassocBssCaps = pbssDescription->capabilityInfo; + if (mac->mlme_cfg->ht_caps.short_slot_time_enabled && + SIR_MAC_GET_SHORT_SLOT_TIME(ft_session->limReassocBssCaps)) { + ft_session->shortSlotTimeSupported = true; + } + + status = lim_fill_session_power_info(mac, pbssDescription, ft_session, + pe_session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to fill power info in ft session"); + goto exit; + } + + ft_session->limReassocBssQosCaps = + ft_session->limCurrentBssQosCaps; + + ft_session->is11Rconnection = pe_session->is11Rconnection; + +#ifdef FEATURE_WLAN_ESE + ft_session->is_ese_version_ie_present = + pBeaconStruct->is_ese_ver_ie_present; +#endif + + if (!lim_is_roam_synch_in_progress(mac->psoc, pe_session)) { + ft_session->limPrevSmeState = ft_session->limSmeState; + ft_session->limSmeState = eLIM_SME_WT_REASSOC_STATE; + MTRACE(mac_trace(mac, + TRACE_CODE_SME_STATE, + ft_session->peSessionId, + ft_session->limSmeState)); + } + ft_session->encryptType = pe_session->encryptType; + ft_session->limRmfEnabled = pe_session->limRmfEnabled; + /* Load default OBSS parameters to session entry */ + lim_init_obss_params(mac, ft_session); + + /* + * By default supported NSS 1x1 is set to true + * and later on updated while determining session + * supported rates which is the intersection of + * self and peer rates + */ + ft_session->supported_nss_1x1 = true; + pe_debug("FT enable smps: %d mode: %d supported nss 1x1: %d", + mac->mlme_cfg->ht_caps.enable_smps, + mac->mlme_cfg->ht_caps.smps, + ft_session->supported_nss_1x1); + +exit: + qdf_mem_free(pBeaconStruct); + return status; +} +#endif + +static void +lim_ft_send_aggr_qos_rsp(struct mac_context *mac, uint8_t rspReqd, + struct aggr_add_ts_param *aggrQosRsp, + uint8_t smesessionId) +{ + tpSirAggrQosRsp rsp; + int i = 0; + + if (!rspReqd) { + return; + } + rsp = qdf_mem_malloc(sizeof(tSirAggrQosRsp)); + if (!rsp) + return; + + rsp->messageType = eWNI_SME_FT_AGGR_QOS_RSP; + rsp->sessionId = smesessionId; + rsp->length = sizeof(*rsp); + rsp->aggrInfo.tspecIdx = aggrQosRsp->tspecIdx; + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + if ((1 << i) & aggrQosRsp->tspecIdx) { + if (QDF_IS_STATUS_SUCCESS(aggrQosRsp->status[i])) + rsp->aggrInfo.aggrRsp[i].status = + STATUS_SUCCESS; + else + rsp->aggrInfo.aggrRsp[i].status = + STATUS_UNSPECIFIED_FAILURE; + rsp->aggrInfo.aggrRsp[i].tspec = aggrQosRsp->tspec[i]; + } + } + lim_send_sme_aggr_qos_rsp(mac, rsp, smesessionId); + return; +} + +void lim_process_ft_aggr_qos_rsp(struct mac_context *mac, + struct scheduler_msg *limMsg) +{ + struct aggr_add_ts_param *pAggrQosRspMsg; + struct add_ts_param addTsParam = { 0 }; + tpDphHashNode pSta = NULL; + uint16_t assocId = 0; + tSirMacAddr peerMacAddr; + uint8_t rspReqd = 1; + struct pe_session *pe_session = NULL; + int i = 0; + + pe_debug(" Received AGGR_QOS_RSP from HAL"); + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + pAggrQosRspMsg = limMsg->bodyptr; + if (!pAggrQosRspMsg) { + pe_err("NULL pAggrQosRspMsg"); + return; + } + pe_session = + pe_find_session_by_session_id(mac, pAggrQosRspMsg->sessionId); + if (!pe_session) { + pe_err("Cant find session entry"); + if (pAggrQosRspMsg) { + qdf_mem_free(pAggrQosRspMsg); + } + return; + } + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + return; + } + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + if ((((1 << i) & pAggrQosRspMsg->tspecIdx)) && + (pAggrQosRspMsg->status[i] != QDF_STATUS_SUCCESS)) { + sir_copy_mac_addr(peerMacAddr, pe_session->bssId); + addTsParam.pe_session_id = pAggrQosRspMsg->sessionId; + addTsParam.tspec = pAggrQosRspMsg->tspec[i]; + addTsParam.tspec_idx = pAggrQosRspMsg->tspecIdx; + lim_send_delts_req_action_frame(mac, peerMacAddr, + rspReqd, + &addTsParam.tspec.tsinfo, + &addTsParam.tspec, + pe_session); + pSta = + dph_lookup_hash_entry(mac, peerMacAddr, + &assocId, + &pe_session-> + dph.dphHashTable); + + if (pSta) { + lim_admit_control_delete_ts(mac, assocId, + &addTsParam.tspec. + tsinfo, NULL, + (uint8_t *) & + addTsParam.tspec_idx); + } + } + } + lim_ft_send_aggr_qos_rsp(mac, rspReqd, pAggrQosRspMsg, + pe_session->smeSessionId); + if (pAggrQosRspMsg) { + qdf_mem_free(pAggrQosRspMsg); + } + return; +} + +QDF_STATUS lim_process_ft_aggr_qos_req(struct mac_context *mac, + uint32_t *msg_buf) +{ + struct scheduler_msg msg = {0}; + tSirAggrQosReq *aggrQosReq = (tSirAggrQosReq *) msg_buf; + struct aggr_add_ts_param *pAggrAddTsParam; + struct pe_session *pe_session = NULL; + tpLimTspecInfo tspecInfo; + uint8_t ac; + tpDphHashNode pSta; + uint16_t aid; + uint8_t sessionId; + int i; + + pAggrAddTsParam = qdf_mem_malloc(sizeof(*pAggrAddTsParam)); + if (!pAggrAddTsParam) + return QDF_STATUS_E_NOMEM; + + pe_session = pe_find_session_by_bssid(mac, aggrQosReq->bssid.bytes, + &sessionId); + + if (!pe_session) { + pe_err("psession Entry Null for sessionId: %d", + aggrQosReq->sessionId); + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + + pSta = dph_lookup_hash_entry(mac, aggrQosReq->bssid.bytes, &aid, + &pe_session->dph.dphHashTable); + if (!pSta) { + pe_err("Station context not found - ignoring AddTsRsp"); + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + + /* Fill in the sessionId specific to PE */ + pAggrAddTsParam->sessionId = sessionId; + pAggrAddTsParam->tspecIdx = aggrQosReq->aggrInfo.tspecIdx; + pAggrAddTsParam->vdev_id = pe_session->smeSessionId; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + if (aggrQosReq->aggrInfo.tspecIdx & (1 << i)) { + struct mac_tspec_ie *pTspec = + &aggrQosReq->aggrInfo.aggrAddTsInfo[i].tspec; + /* Since AddTS response was successful, check for the PSB flag + * and directional flag inside the TS Info field. + * An AC is trigger enabled AC if the PSB subfield is set to 1 + * in the uplink direction. + * An AC is delivery enabled AC if the PSB subfield is set to 1 + * in the downlink direction. + * An AC is trigger and delivery enabled AC if the PSB subfield + * is set to 1 in the bi-direction field. + */ + if (pTspec->tsinfo.traffic.psb == 1) { + lim_set_tspec_uapsd_mask_per_session(mac, + pe_session, + &pTspec-> + tsinfo, + SET_UAPSD_MASK); + } else { + lim_set_tspec_uapsd_mask_per_session(mac, + pe_session, + &pTspec-> + tsinfo, + CLEAR_UAPSD_MASK); + } + /* + * ADDTS success, so AC is now admitted. + * We shall now use the default + * EDCA parameters as advertised by AP and + * send the updated EDCA params + * to HAL. + */ + ac = upToAc(pTspec->tsinfo.traffic.userPrio); + if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_UPLINK) { + pe_session-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + pe_session-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (pTspec->tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + pe_session-> + gAcAdmitMask + [SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + pe_session-> + gAcAdmitMask + [SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(mac, + pe_session->gLimEdcaParams, + pe_session); + + lim_send_edca_params(mac, + pe_session->gLimEdcaParamsActive, + pe_session->vdev_id, false); + + if (QDF_STATUS_SUCCESS != + lim_tspec_add(mac, pSta->staAddr, pSta->assocId, + pTspec, 0, &tspecInfo)) { + pe_err("Adding entry in lim Tspec Table failed"); + mac->lim.gLimAddtsSent = false; + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + + pAggrAddTsParam->tspec[i] = + aggrQosReq->aggrInfo.aggrAddTsInfo[i].tspec; + } + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (!mac->mlme_cfg->lfr.lfr3_roaming_offload || + (mac->mlme_cfg->lfr.lfr3_roaming_offload && + !pe_session->is11Rconnection)) +#endif + { + msg.type = WMA_AGGR_QOS_REQ; + msg.bodyptr = pAggrAddTsParam; + msg.bodyval = 0; + + /* We need to defer any incoming messages until we get a + * WMA_AGGR_QOS_RSP from HAL. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(mac, &msg)) { + pe_warn("wma_post_ctrl_msg() failed"); + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + qdf_mem_free(pAggrAddTsParam); + return QDF_STATUS_E_FAILURE; + } + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + else { + /* Implies it is a LFR3.0 based 11r connection + * so donot send add ts request to firmware since it + * already has the RIC IEs */ + + /* Send the Aggr QoS response to SME */ + lim_ft_send_aggr_qos_rsp(mac, true, pAggrAddTsParam, + pe_session->smeSessionId); + if (pAggrAddTsParam) { + qdf_mem_free(pAggrAddTsParam); + } + } +#endif + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c new file mode 100644 index 0000000000..067d786cac --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ft_preauth.c @@ -0,0 +1,812 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: lim_ft_preauth.c + * + * Pre-Authentication implementation for host based roaming + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wma.h" +#include "wlan_crypto_global_api.h" + +/** + * lim_ft_cleanup_pre_auth_info() - Cleanup preauth related information + * @mac: Global MAC Context + * @pe_session: PE Session + * + * This routine is called to free the FT context, session and other + * information used during preauth operation. + * + * Return: None + */ +void lim_ft_cleanup_pre_auth_info(struct mac_context *mac, + struct pe_session *pe_session) +{ + struct pe_session *pReAssocSessionEntry = NULL; + uint8_t sessionId = 0; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + return; + } + + if (pe_session->ftPEContext.pFTPreAuthReq) { + pReAssocSessionEntry = + pe_find_session_by_bssid(mac, + pe_session->ftPEContext. + pFTPreAuthReq->preAuthbssId, + &sessionId); + + if (pe_session->ftPEContext.pFTPreAuthReq-> + pbssDescription) { + qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq-> + pbssDescription); + pe_session->ftPEContext.pFTPreAuthReq-> + pbssDescription = NULL; + } + qdf_mem_free(pe_session->ftPEContext.pFTPreAuthReq); + pe_session->ftPEContext.pFTPreAuthReq = NULL; + } + + if (pe_session->ftPEContext.pAddBssReq) { + qdf_mem_free(pe_session->ftPEContext.pAddBssReq); + pe_session->ftPEContext.pAddBssReq = NULL; + } + + if (pe_session->ftPEContext.pAddStaReq) { + qdf_mem_free(pe_session->ftPEContext.pAddStaReq); + pe_session->ftPEContext.pAddStaReq = NULL; + } + + /* The session is being deleted, cleanup the contents */ + qdf_mem_zero(&pe_session->ftPEContext, sizeof(tftPEContext)); + + /* Delete the session created while handling pre-auth response */ + if (pReAssocSessionEntry) { + /* If we have successful pre-auth response, then we would have + * created a session on which reassoc request will be sent + */ + if (pReAssocSessionEntry->valid && + pReAssocSessionEntry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) { + pe_debug("Deleting Preauth session(%d)", + pReAssocSessionEntry->peSessionId); + pe_delete_session(mac, pReAssocSessionEntry); + } + } +} + +/* + * lim_process_ft_pre_auth_req() - process ft pre auth req + * + * @mac_ctx: global mac ctx + * @ft_pre_auth_req: ft preauth request + * + * In this function, we process the FT Pre Auth Req: + * We receive Pre-Auth, suspend link, register a call back. In the call back, + * we will need to accept frames from the new bssid. Send out the auth req to + * new AP. Start timer and when the timer is done or if we receive the Auth + * response. We change channel. Resume link + * + * Return: value to indicate if buffer was consumed + */ +bool lim_process_ft_pre_auth_req(struct mac_context *mac_ctx, + tpSirFTPreAuthReq ft_pre_auth_req) +{ + bool buf_consumed = false; + struct pe_session *session; + uint8_t session_id; + + if (!ft_pre_auth_req) { + pe_err("tSirFTPreAuthReq is NULL"); + return buf_consumed; + } + + /* Get the current session entry */ + session = pe_find_session_by_bssid(mac_ctx, + ft_pre_auth_req->currbssId, + &session_id); + if (!session) { + pe_err("Unable to find session for the bssid " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ft_pre_auth_req->currbssId)); + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, + session); + buf_consumed = true; + return buf_consumed; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + pe_err("session is not in STA mode"); + buf_consumed = true; + return buf_consumed; + } + + /* Can set it only after sending auth */ + session->ftPEContext.ftPreAuthStatus = QDF_STATUS_E_FAILURE; + session->ftPEContext.ftPreAuthSession = true; + + /* Indicate that this is the session on which preauth is being done */ + if (session->ftPEContext.pFTPreAuthReq) { + if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { + qdf_mem_free( + session->ftPEContext.pFTPreAuthReq->pbssDescription); + session->ftPEContext.pFTPreAuthReq->pbssDescription = + NULL; + } + qdf_mem_free(session->ftPEContext.pFTPreAuthReq); + session->ftPEContext.pFTPreAuthReq = NULL; + } + + /* We need information from the Pre-Auth Req. Lets save that */ + session->ftPEContext.pFTPreAuthReq = ft_pre_auth_req; + + pe_debug("PRE Auth ft_ies_length=%02x%02x%02x", + session->ftPEContext.pFTPreAuthReq->ft_ies[0], + session->ftPEContext.pFTPreAuthReq->ft_ies[1], + session->ftPEContext.pFTPreAuthReq->ft_ies[2]); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, + session, 0, 0); +#endif + + /* + * Dont need to suspend if APs are in same channel and DUT + * is not in MCC state + */ + if ((session->curr_op_freq != + session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq) + || lim_is_in_mcc(mac_ctx)) { + /* Need to suspend link only if the channels are different */ + pe_debug("Performing pre-auth on diff channel(session %pK)", + session); + lim_send_preauth_scan_offload(mac_ctx, session, + session->ftPEContext.pFTPreAuthReq); + } else { + pe_debug("Performing pre-auth on same channel (session %pK)", + session); + /* We are in the same channel. Perform pre-auth */ + lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL, + session); + } + + return buf_consumed; +} + +/** + * lim_perform_ft_pre_auth() - Perform preauthentication + * @mac: Global MAC Context + * @status: Status Code + * @data: pre-auth data + * @pe_session: PE Session + * + * This routine will trigger the sending of authentication frame + * to the peer. + * + * Return: None + */ +void lim_perform_ft_pre_auth(struct mac_context *mac, QDF_STATUS status, + uint32_t *data, struct pe_session *pe_session) +{ + tSirMacAuthFrameBody authFrame; + bool is_open = false; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + + if (cm_is_open_mode(pe_session->vdev)) + is_open = true; + + if (pe_session->is11Rconnection && + pe_session->ftPEContext.pFTPreAuthReq) { + /* Only 11r assoc has FT IEs */ + if ((!is_open) && + (pe_session->ftPEContext.pFTPreAuthReq->ft_ies_length + == 0)) { + pe_err("FTIEs for Auth Req Seq 1 is absent"); + goto preauth_fail; + } + } + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Change channel not successful for FT pre-auth"); + goto preauth_fail; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + return; + } + if (cm_is_auth_type_sae(pe_session->vdev)) { + struct qdf_mac_addr *pre_auth_bssid = (struct qdf_mac_addr *) + pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId; + + lim_trigger_auth_req_sae(mac, pe_session, pre_auth_bssid); + return; + } + pe_debug("Entered wait auth2 state for FT (old session %pK)", + pe_session); + if (pe_session->is11Rconnection) { + /* Now we are on the right channel and need to send out Auth1 + * and receive Auth2 + */ + authFrame.authAlgoNumber = eSIR_FT_AUTH; + } else { + /* Will need to make isESEconnection a enum may be for further + * improvements to this to match this algorithm number + */ + authFrame.authAlgoNumber = eSIR_OPEN_SYSTEM; + } + authFrame.authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + authFrame.authStatusCode = 0; + + mac->lim.lim_timers.g_lim_periodic_auth_retry_timer.sessionId = + pe_session->peSessionId; + + /* Start timer here to come back to operating channel */ + mac->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId = + pe_session->peSessionId; + if (TX_SUCCESS != + tx_timer_activate(&mac->lim.lim_timers.gLimFTPreAuthRspTimer)) { + pe_err("FT Auth Rsp Timer Start Failed"); + goto preauth_fail; + } + MTRACE(mac_trace(mac, TRACE_CODE_TIMER_ACTIVATE, + pe_session->peSessionId, eLIM_FT_PREAUTH_RSP_TIMER)); + + pe_debug("FT Auth Rsp Timer Started"); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac, WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + mac->lim.pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +#endif + if (pe_session->ftPEContext.pFTPreAuthReq) + lim_send_auth_mgmt_frame(mac, &authFrame, + pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId, + LIM_NO_WEP_IN_FC, pe_session); + + return; + +preauth_fail: + lim_handle_ft_pre_auth_rsp(mac, QDF_STATUS_E_FAILURE, NULL, 0, pe_session); + return; +} + +/** + * lim_ft_setup_auth_session() - Fill the FT Session + * @mac: Global MAC Context + * @pe_session: PE Session + * + * Setup the session and the add bss req for the pre-auth AP. + * + * Return: Success or Failure Status + */ +QDF_STATUS lim_ft_setup_auth_session(struct mac_context *mac, + struct pe_session *pe_session) +{ + struct pe_session *ft_session = NULL; + uint8_t sessionId = 0; + struct sSirFTPreAuthReq *req; + QDF_STATUS status; + + ft_session = + pe_find_session_by_bssid(mac, pe_session->limReAssocbssId, + &sessionId); + if (!ft_session) { + pe_err("No session found for bssid: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); + return QDF_STATUS_E_FAILURE; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + return QDF_STATUS_E_FAILURE; + } + + req = pe_session->ftPEContext.pFTPreAuthReq; + if (req && req->pbssDescription) { + status = lim_fill_ft_session(mac, + req->pbssDescription, ft_session, + pe_session, WLAN_PHYMODE_AUTO); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to fill ft session for vdev id %d", + ft_session->vdev_id); + + lim_ft_prepare_add_bss_req(mac, ft_session, + req->pbssDescription); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_ft_process_pre_auth_result() - Process the Auth frame + * @mac: Global MAC context + * @pe_session: PE Session + * + * Return: None + */ +static void lim_ft_process_pre_auth_result(struct mac_context *mac, + struct pe_session *pe_session) +{ + if (!pe_session || + !pe_session->ftPEContext.pFTPreAuthReq) + return; + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + return; + } + + if (pe_session->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) { + pe_session->ftPEContext.ftPreAuthStatus = + lim_ft_setup_auth_session(mac, pe_session); + } + /* Post the FT Pre Auth Response to SME */ + lim_post_ft_pre_auth_rsp(mac, + pe_session->ftPEContext.ftPreAuthStatus, + pe_session->ftPEContext.saved_auth_rsp, + pe_session->ftPEContext.saved_auth_rsp_length, + pe_session); +} + +/** + * lim_handle_ft_pre_auth_rsp() - Handle the Auth response + * @mac: Global MAC Context + * @status: Status Code + * @auth_rsp: Auth Response + * @auth_rsp_length: Auth response length + * @pe_session: PE Session + * + * Send the FT Pre Auth Response to SME whenever we have a status + * ready to be sent to SME + * + * SME will be the one to send it up to the supplicant to receive + * FTIEs which will be required for Reassoc Req. + * + * @Return: None + */ +void lim_handle_ft_pre_auth_rsp(struct mac_context *mac, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + struct pe_session *pe_session) +{ + struct pe_session *ft_session = NULL; + uint8_t sessionId = 0; + struct bss_description *pbssDescription = NULL; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac, WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + pe_session, (uint16_t) status, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("pe_session is not in STA mode"); + return; + } + + /* Save the status of pre-auth */ + pe_session->ftPEContext.ftPreAuthStatus = status; + + /* Save the auth rsp, so we can send it to + * SME once we resume link + */ + pe_session->ftPEContext.saved_auth_rsp_length = 0; + if ((auth_rsp) && (auth_rsp_length < MAX_FTIE_SIZE)) { + qdf_mem_copy(pe_session->ftPEContext.saved_auth_rsp, + auth_rsp, auth_rsp_length); + pe_session->ftPEContext.saved_auth_rsp_length = + auth_rsp_length; + } + + if (!pe_session->ftPEContext.pFTPreAuthReq || + !pe_session->ftPEContext.pFTPreAuthReq->pbssDescription) { + pe_err("pFTPreAuthReq or pbssDescription is NULL"); + return; + } + + /* Create FT session for the re-association at this point */ + if (pe_session->ftPEContext.ftPreAuthStatus == QDF_STATUS_SUCCESS) { + pbssDescription = + pe_session->ftPEContext.pFTPreAuthReq->pbssDescription; + ft_session = + pe_create_session(mac, pbssDescription->bssId, + &sessionId, + mac->lim.max_sta_of_pe_session, + pe_session->bssType, + pe_session->vdev_id); + if (!ft_session) { + pe_err("Session not created for pre-auth 11R AP"); + status = QDF_STATUS_E_FAILURE; + pe_session->ftPEContext.ftPreAuthStatus = status; + goto send_rsp; + } + + sir_copy_mac_addr(ft_session->self_mac_addr, + pe_session->self_mac_addr); + sir_copy_mac_addr(ft_session->limReAssocbssId, + pbssDescription->bssId); + + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(mac, ft_session, 0); + + if (ft_session->bssType == eSIR_INFRASTRUCTURE_MODE) + ft_session->limSystemRole = eLIM_STA_ROLE; + else + pe_err("Invalid bss type"); + + ft_session->limPrevSmeState = ft_session->limSmeState; + ft_session->ht_config = pe_session->ht_config; + ft_session->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + if (wlan_reg_is_24ghz_ch_freq(pe_session->ftPEContext. + pFTPreAuthReq->pre_auth_channel_freq)) + ft_session->vdev_nss = mac->vdev_type_nss_2g.sta; + else + ft_session->vdev_nss = mac->vdev_type_nss_5g.sta; + + /* Update the ReAssoc BSSID of the current session */ + sir_copy_mac_addr(pe_session->limReAssocbssId, + pbssDescription->bssId); + pe_debug("created session (%pK) with id = %d BSSID = "QDF_MAC_ADDR_FMT, + ft_session, ft_session->peSessionId, + QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); + } +send_rsp: + if ((pe_session->curr_op_freq != + pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq) || + lim_is_in_mcc(mac)) { + pe_debug("Pre auth on diff freq as connected AP freq %d or mcc pe sessions exist, so abort scan", + pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq); + + /* Need to move to the original AP channel */ + lim_process_abort_scan_ind(mac, pe_session->smeSessionId, + pe_session->ftPEContext.pFTPreAuthReq->scan_id, + mac->lim.req_id | PREAUTH_REQUESTOR_ID); + } + /* + * Send resp to connection manager, even in case scan needs abort, + * scan complete will be no-op. + */ + lim_ft_process_pre_auth_result(mac, pe_session); +} + +/* + * lim_process_ft_preauth_rsp_timeout() - process ft preauth rsp timeout + * + * @mac_ctx: global mac ctx + * + * This function is called if preauth response is not received from the AP + * within this timeout while FT in progress + * + * Return: void + */ +void lim_process_ft_preauth_rsp_timeout(struct mac_context *mac_ctx) +{ + struct pe_session *session; + + /* + * We have failed pre auth. We need to resume link and get back on + * home channel + */ + pe_err("FT Pre-Auth Time Out!!!!"); + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId); + if (!session) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + pe_err("session is not in STA mode"); + return; + } + + /* Reset the flag to indicate preauth request session */ + session->ftPEContext.ftPreAuthSession = false; + + if (!session->ftPEContext.pFTPreAuthReq) { + /* Auth Rsp might already be posted to SME and ftcleanup done */ + pe_err("pFTPreAuthReq is NULL sessionId: %d", + mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId); + return; + } + + /* + * To handle the race condition where we receive preauth rsp after + * timer has expired. + */ + if (true == + session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { + pe_err("Auth rsp already posted to SME (session %pK)", + session); + return; + } else { + /* + * Here we are sending preauth rsp with failure state + * and which is forwarded to SME. Now, if we receive an preauth + * resp from AP with success it would create a FT pesession, but + * will be dropped in SME leaving behind the pesession. Mark + * Preauth rsp processed so that any rsp from AP is dropped in + * lim_process_auth_frame_no_session. + */ + pe_debug("Auth rsp not yet posted to SME (session %pK)", + session); + session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = true; + } + + /* + * Attempted at Pre-Auth and failed. If we are off channel. We need + * to get back to home channel + */ + lim_handle_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, session); +} + +/* + * lim_cm_post_preauth_rsp() - post preauth response to osif. + * + * @mac_ctx: global mac ctx + * @status: status code to post in auth rsp + * @auth_rsp: pointer to auth rsp FT ie + * @auth_rsp_length: len of the IE field + * @session: pe session + * + * post preauth response to osif. + * + * Return: void + */ +static void +lim_cm_post_preauth_rsp(struct mac_context *mac_ctx, QDF_STATUS status, + uint8_t *auth_rsp, uint16_t auth_rsp_length, + struct pe_session *session) +{ + QDF_STATUS qdf_status; + struct scheduler_msg rsp_msg = {0}; + struct wlan_preauth_rsp *rsp; + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return; + + rsp->psoc = mac_ctx->psoc; + if (session) { + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + pe_err("session is not in STA mode"); + qdf_mem_free(rsp); + return; + } + rsp->vdev_id = session->vdev_id; + /* The bssid of the AP we are sending Auth1 to. */ + if (session->ftPEContext.pFTPreAuthReq) + qdf_mem_copy(rsp->pre_auth_bssid.bytes, + session->ftPEContext. + pFTPreAuthReq->preAuthbssId, + QDF_MAC_ADDR_SIZE); + } + rsp->status = status; + + /* Attach the auth response now back to osif */ + rsp->ft_ie_length = 0; + if (auth_rsp && (auth_rsp_length < MAX_FTIE_SIZE)) { + /* Only 11r assoc has FT IEs */ + qdf_mem_copy(rsp->ft_ie, auth_rsp, auth_rsp_length); + rsp->ft_ie_length = auth_rsp_length; + } + + rsp_msg.bodyptr = rsp; + rsp_msg.callback = cm_handle_preauth_rsp; + + qdf_status = scheduler_post_message( + QDF_MODULE_ID_PE, QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &rsp_msg); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to post preauth rsp to sme vdev_id %d", + rsp->vdev_id); + qdf_mem_free(rsp); + } +} + +/* + * lim_post_ft_pre_auth_rsp() - post ft pre auth response to SME. + * + * @mac_ctx: global mac ctx + * @status: status code to post in auth rsp + * @auth_rsp: pointer to auth rsp FT ie + * @auth_rsp_length: len of the IE field + * @session: pe session + * + * post pre auth response to SME. + * + * Return: void + */ +void lim_post_ft_pre_auth_rsp(struct mac_context *mac_ctx, + QDF_STATUS status, + uint8_t *auth_rsp, + uint16_t auth_rsp_length, + struct pe_session *session) +{ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (status == QDF_STATUS_SUCCESS) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_PREAUTH_DONE, + session, status, 0); +#endif + lim_cm_post_preauth_rsp(mac_ctx, status, auth_rsp, auth_rsp_length, + session); +} + +/** + * lim_send_preauth_scan_offload() - Send scan command to handle preauth. + * + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: pe session + * @ft_preauth_req: Preauth request with parameters + * + * Builds a single channel scan request and sends it to scan module. + * Scan dwell time is the time allocated to go to preauth candidate + * channel for auth frame exchange. + * + * Return: Status of sending message to scan module. + */ +QDF_STATUS lim_send_preauth_scan_offload(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tSirFTPreAuthReq *ft_preauth_req) +{ + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!session_entry) { + pe_err("Session entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = session_entry->smeSessionId; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + qdf_mem_zero(req, sizeof(*req)); + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, + vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev_id %d: vdev is NULL", vdev_id); + qdf_mem_free(req); + return QDF_STATUS_E_FAILURE; + } + + wlan_scan_init_default_params(vdev, req); + + qdf_mem_copy(req->scan_req.bssid_list, + (uint8_t *)ft_preauth_req->currbssId, + QDF_MAC_ADDR_SIZE); + + req->scan_req.scan_id = wlan_scan_get_scan_id(mac_ctx->psoc); + if (!req->scan_req.scan_id) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + qdf_mem_free(req); + pe_err("Invalid scan ID"); + return QDF_STATUS_E_FAILURE; + } + ft_preauth_req->scan_id = req->scan_req.scan_id; + req->scan_req.vdev_id = vdev_id; + req->scan_req.scan_req_id = mac_ctx->lim.req_id | PREAUTH_REQUESTOR_ID; + req->scan_req.scan_priority = SCAN_PRIORITY_VERY_HIGH; + req->scan_req.scan_f_passive = true; + + req->scan_req.chan_list.num_chan = 1; + req->scan_req.chan_list.chan[0].freq = + ft_preauth_req->pre_auth_channel_freq; + + req->scan_req.dwell_time_active = LIM_FT_PREAUTH_ACTIVE_SCAN_TIME; + req->scan_req.dwell_time_passive = LIM_FT_PREAUTH_PASSIVE_SCAN_TIME; + + status = wlan_scan_start(req); + if (QDF_IS_STATUS_ERROR(status)) + /* Don't free req here, ucfg_scan_start will do free */ + pe_info("Issue scan req failed"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return status; +} + +void lim_preauth_scan_event_handler(struct mac_context *mac_ctx, + enum sir_scan_event_type event, + uint8_t vdev_id, uint32_t scan_id) +{ + struct pe_session *session_entry; + + session_entry = pe_find_session_by_scan_id(mac_ctx, scan_id); + /* Pre-auth request is sent */ + if (session_entry) { + if ((event == SIR_SCAN_EVENT_FOREIGN_CHANNEL) && + (session_entry->ftPEContext.ftPreAuthStatus + == QDF_STATUS_SUCCESS)) { + pe_err("Pre-auth is done, skip sending pre-auth req"); + return; + } + } else { + /* For the first pre-auth request + * need to get it by sme session id (vdev id) + */ + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + } + + if (!session_entry) { + pe_err("vdev_id :%d PeSessionId:%d does not exist", vdev_id, + mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer.sessionId); + return; + } + + switch (event) { + case SIR_SCAN_EVENT_START_FAILED: + /* Scan command is rejected by firmware */ + pe_err("Failed to start preauth scan"); + lim_post_ft_pre_auth_rsp(mac_ctx, QDF_STATUS_E_FAILURE, NULL, 0, + session_entry); + return; + + case SIR_SCAN_EVENT_COMPLETED: + /* + * Scan either completed successfully or or got terminated + * after successful auth, or timed out. Either way, STA + * is back to home channel. Data traffic can continue. + * Don't do anything as preauth timer/auth resp will take care + * of the sending resp to the connection manager. + */ + break; + + case SIR_SCAN_EVENT_FOREIGN_CHANNEL: + /* Sta is on candidate channel. Send auth */ + lim_perform_ft_pre_auth(mac_ctx, QDF_STATUS_SUCCESS, NULL, + session_entry); + break; + default: + /* Don't print message for scan events that are ignored */ + break; + } +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c new file mode 100644 index 0000000000..dc1959df98 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_link_monitoring_algo.c @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_link_monitoring_algo.cc contains the code for + * Link monitoring algorithm on AP and heart beat failure + * handling on STA. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "ani_global.h" +#include "wni_cfg.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_assoc_utils.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_prop_exts_utils.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_ser_des_utils.h" +#include "wlan_dlm_api.h" + +/** + * lim_delete_sta_util - utility function for deleting station context + * + * @mac_ctx: global MAC context + * @msg: pointer to delete station context + * @session_entry: PE session entry + * + * utility function called to clear up station context. + * + * Return: None. + */ +static void lim_delete_sta_util(struct mac_context *mac_ctx, tpDeleteStaContext msg, + struct pe_session *session_entry) +{ + tpDphHashNode stads; + + pe_debug("Deleting station: reasonCode: %d", msg->reasonCode); + + stads = dph_lookup_hash_entry(mac_ctx, msg->addr2, &msg->assocId, + &session_entry->dph.dphHashTable); + + if (!stads) { + pe_err("Invalid STA limSystemRole: %d", + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + stads->del_sta_ctx_rssi = msg->rssi; + + if (LIM_IS_AP_ROLE(session_entry)) { + pe_debug("Delete Station assocId: %d", msg->assocId); + /* + * Check if Deauth/Disassoc is triggered from Host. + * If mlmState is in some transient state then + * don't trigger STA deletion to avoid the race + * condition. + */ + if ((stads && + ((stads->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_ASSOCIATED_STATE)))) { + pe_err("Inv Del STA assocId: %d", msg->assocId); + return; + } else { + if (stads->ocv_enabled && stads->last_ocv_done_freq != + session_entry->curr_op_freq) { + lim_send_deauth_mgmt_frame( + mac_ctx, + REASON_PREV_AUTH_NOT_VALID, + stads->staAddr, + session_entry, true); + stads->is_disassoc_deauth_in_progress = 1; + } else { + lim_send_disassoc_mgmt_frame( + mac_ctx, + REASON_DISASSOC_DUE_TO_INACTIVITY, + stads->staAddr, session_entry, false); + lim_trigger_sta_deletion(mac_ctx, stads, + session_entry); + } + } + } else { +#ifdef FEATURE_WLAN_TDLS + if (LIM_IS_STA_ROLE(session_entry) && + STA_ENTRY_TDLS_PEER == stads->staType) { + /* + * TeardownLink with PEER reason code + * HAL_DEL_STA_REASON_CODE_KEEP_ALIVE means + * eSIR_MAC_TDLS_TEARDOWN_PEER_UNREACHABLE + */ + lim_send_sme_tdls_del_sta_ind(mac_ctx, stads, + session_entry, REASON_TDLS_PEER_UNREACHABLE); + } else { +#endif + /* TearDownLink with AP */ + tLimMlmDeauthInd mlm_deauth_ind; + + pe_debug("Delete Station (assocId: %d)", msg->assocId); + + if ((stads && + ((stads->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE) && + (stads->mlmStaContext.mlmState != + eLIM_MLM_ASSOCIATED_STATE)))) { + + /* + * Received SIR_LIM_DELETE_STA_CONTEXT_IND for STA that + * does not have context or in some transit state. + * Log error + */ + pe_debug("Received SIR_LIM_DELETE_STA_CONTEXT_IND for " + "STA that either has no context or " + "in some transit state, Addr = " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(msg->bssId)); + return; + } + + stads->mlmStaContext.disassocReason = + REASON_DISASSOC_DUE_TO_INACTIVITY; + stads->mlmStaContext.cleanupTrigger = + eLIM_LINK_MONITORING_DEAUTH; + + /* Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlm_deauth_ind.peerMacAddr, + stads->staAddr, sizeof(tSirMacAddr)); + mlm_deauth_ind.reasonCode = + (uint8_t) stads->mlmStaContext.disassocReason; + mlm_deauth_ind.deauthTrigger = + stads->mlmStaContext.cleanupTrigger; + +#ifdef FEATURE_WLAN_TDLS + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac_ctx, session_entry); +#endif + if (LIM_IS_STA_ROLE(session_entry)) + lim_post_sme_message(mac_ctx, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlm_deauth_ind); + + lim_send_sme_deauth_ind(mac_ctx, stads, session_entry); +#ifdef FEATURE_WLAN_TDLS + } +#endif + } +} + +/** + * lim_delete_sta_context() - delete sta context. + * + * @mac_ctx: global mac_ctx context + * @lim_msg: lim message. + * + * This function handles the message from HAL: WMA_DELETE_STA_CONTEXT_IND. + * This function validates that the given station id exist, and if so, + * deletes the station by calling lim_trigger_sta_deletion. + * + * Return: none + */ +void lim_delete_sta_context(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg) +{ + tpDeleteStaContext msg = (tpDeleteStaContext) lim_msg->bodyptr; + struct pe_session *session_entry; + tpDphHashNode sta_ds; + enum wlan_reason_code reason_code; + struct reject_ap_info ap_info; + + if (!msg) { + pe_err("Invalid body pointer in message"); + return; + } + session_entry = pe_find_session_by_vdev_id(mac_ctx, msg->vdev_id); + if (!session_entry) { + pe_err("session not found for given sme session"); + qdf_mem_free(msg); + return; + } + + switch (msg->reasonCode) { + case HAL_DEL_STA_REASON_CODE_KEEP_ALIVE: + case HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT: + case HAL_DEL_STA_REASON_CODE_XRETRY: + if (LIM_IS_STA_ROLE(session_entry) && !msg->is_tdls) { + if (!lim_is_sb_disconnect_allowed(session_entry)) { + qdf_mem_free(msg); + return; + } + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + pe_err("Dph entry not found"); + qdf_mem_free(msg); + return; + } + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_DISASSOC_DUE_TO_INACTIVITY, + msg->addr2, session_entry, false); + if (msg->reasonCode == + HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT) + reason_code = REASON_SA_QUERY_TIMEOUT; + else if (msg->reasonCode == + HAL_DEL_STA_REASON_CODE_XRETRY) + reason_code = REASON_PEER_XRETRY_FAIL; + else + reason_code = REASON_PEER_INACTIVITY; + lim_tear_down_link_with_ap(mac_ctx, + session_entry->peSessionId, + reason_code, + eLIM_LINK_MONITORING_DEAUTH); + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + qdf_mem_copy(&ap_info.bssid, msg->addr2, + QDF_MAC_ADDR_SIZE); + ap_info.reject_ap_type = DRIVER_AVOID_TYPE; + ap_info.reject_reason = REASON_STA_KICKOUT; + ap_info.source = ADDED_BY_DRIVER; + wlan_dlm_add_bssid_to_reject_list(mac_ctx->pdev, + &ap_info); + + /* only break for STA role (non TDLS) */ + break; + } + lim_delete_sta_util(mac_ctx, msg, session_entry); + break; + + case HAL_DEL_STA_REASON_CODE_UNKNOWN_A2: + pe_err("Deleting Unknown station: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(msg->addr2)); + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_CLASS3_FRAME_FROM_NON_ASSOC_STA, + msg->addr2, session_entry, false); + break; + + case HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT: + if (!lim_is_sb_disconnect_allowed(session_entry)) { + qdf_mem_free(msg); + lim_msg->bodyptr = NULL; + return; + } + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_DISASSOC_BSS_TRANSITION , + session_entry->bssId, session_entry, false); + lim_tear_down_link_with_ap(mac_ctx, session_entry->peSessionId, + REASON_DISASSOC_BSS_TRANSITION , + eLIM_LINK_MONITORING_DEAUTH); + break; + + default: + pe_err("Unknown reason code"); + break; + } + qdf_mem_free(msg); + lim_msg->bodyptr = NULL; + return; +} + +/** + * lim_trigger_sta_deletion() - + * This function is called to trigger STA context deletion. + * + * @param mac_ctx - Pointer to global MAC structure + * @param sta_ds - Pointer to internal STA Datastructure + * @session_entry: PE session entry + + * @return None + */ +void +lim_trigger_sta_deletion(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + tLimMlmDisassocInd mlm_disassoc_ind; + + if (!sta_ds) { + pe_warn("Skip STA deletion (invalid STA)"); + return; + } + + if ((sta_ds->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (sta_ds->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_BSS_RSP_STATE) || + sta_ds->sta_deletion_in_progress) { + /* Already in the process of deleting context for the peer */ + pe_debug("Deletion is in progress (%d) for peer:%pK in mlmState %d", + sta_ds->sta_deletion_in_progress, sta_ds->staAddr, + sta_ds->mlmStaContext.mlmState); + return; + } + sta_ds->sta_deletion_in_progress = true; + + sta_ds->mlmStaContext.disassocReason = + REASON_DISASSOC_DUE_TO_INACTIVITY; + sta_ds->mlmStaContext.cleanupTrigger = eLIM_LINK_MONITORING_DISASSOC; + qdf_mem_copy(&mlm_disassoc_ind.peerMacAddr, sta_ds->staAddr, + sizeof(tSirMacAddr)); + mlm_disassoc_ind.reasonCode = + REASON_DISASSOC_DUE_TO_INACTIVITY; + mlm_disassoc_ind.disassocTrigger = eLIM_LINK_MONITORING_DISASSOC; + + /* Update PE session Id */ + mlm_disassoc_ind.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_IND, + (uint32_t *) &mlm_disassoc_ind); + if (mac_ctx->mlme_cfg->gen.fatal_event_trigger) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HB_FAILURE, + false, false); + /* Issue Disassoc Indication to SME */ + lim_send_sme_disassoc_ind(mac_ctx, sta_ds, session_entry); +} /*** end lim_trigger_st_adeletion() ***/ + +static void +lim_connectivity_bmiss_disconn_event(tpDphHashNode sta, + struct wlan_objmgr_psoc *psoc, + enum wlan_reason_code reason_code, + uint32_t vdev_id) +{ + if (!(reason_code == REASON_BEACON_MISSED)) + return; + + /* + * Firmware sends final bmiss indication as part of roam scan stats + * event. Disconn log is sent as part of the final bmiss indication + * from roam scan stats event with specific reason. But if RSO stop + * or RSO deinit happens after first bmiss due to concurrent interface + * connection, then firmware doesn't send the final bmiss indication + * to driver since roam scan will be disabled. But final bmiss + * heartbeat failure will be indicated as part of WMI_ROAM_EVENTID with + * reason as BMISS. So generate DISCONN log in this case from host based + * on RSO state and final bmiss HB failure teardown. + */ + if (!(MLME_IS_ROAM_STATE_STOPPED(psoc, vdev_id) || + MLME_IS_ROAM_STATE_DEINIT(psoc, vdev_id))) + return; + + cm_roam_beacon_loss_disconnect_event(psoc, + *(struct qdf_mac_addr *)sta->staAddr, + vdev_id); +} + +void +lim_tear_down_link_with_ap(struct mac_context *mac, uint8_t sessionId, + enum wlan_reason_code reasonCode, + enum eLimDisassocTrigger trigger) +{ + tpDphHashNode sta = NULL; + tLimMlmDeauthInd mlmDeauthInd; + + /* tear down the following pe_session */ + struct pe_session *pe_session; + + pe_session = pe_find_session_by_session_id(mac, sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + pe_info("Session %d Vdev %d reason code %d trigger %d", + pe_session->peSessionId, pe_session->vdev_id, reasonCode, + trigger); + + /* Add the check here in case caller missed the check */ + if (!lim_is_sb_disconnect_allowed(pe_session)) + return; + + /** + * Heart beat failed for upto threshold value + * and AP did not respond for Probe request. + * Trigger link tear down. + */ + pe_session->pmmOffloadInfo.bcnmiss = false; + + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac, pe_session); + + /* Announce loss of link to Roaming algorithm */ + /* and cleanup by sending SME_DISASSOC_REQ to SME */ + + sta = dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_debug("vdev:%d no sta hash entry for peer:" QDF_MAC_ADDR_FMT, + pe_session->vdev_id, + QDF_MAC_ADDR_REF(pe_session->bssId)); + return; + } + + if ((sta->mlmStaContext.disassocReason == + REASON_DEAUTH_NETWORK_LEAVING) || + (sta->mlmStaContext.cleanupTrigger == + eLIM_HOST_DEAUTH)) { + pe_err("Host already issued deauth, do nothing"); + return; + } + + sta->mlmStaContext.disassocReason = reasonCode; + sta->mlmStaContext.cleanupTrigger = trigger; + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + sta->staAddr, sizeof(tSirMacAddr)); + + /* + * if deauth_before_connection is enabled and reasoncode is + * Beacon Missed Store the MAC of AP in the flip flop + * buffer. This MAC will be used to send Deauth before + * connection, if we connect to same AP after HB failure. + */ + if (mac->mlme_cfg->sta.deauth_before_connection && + reasonCode == REASON_BEACON_MISSED) { + int apCount = mac->lim.gLimHeartBeatApMacIndex; + + if (mac->lim.gLimHeartBeatApMacIndex) + mac->lim.gLimHeartBeatApMacIndex = 0; + else + mac->lim.gLimHeartBeatApMacIndex = 1; + + pe_debug("HB Failure on MAC " + QDF_MAC_ADDR_FMT" Store it on Index %d", + QDF_MAC_ADDR_REF(sta->staAddr), apCount); + + sir_copy_mac_addr(mac->lim.gLimHeartBeatApMac[apCount], + sta->staAddr); + } + + mlmDeauthInd.reasonCode = + (uint8_t) sta->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = + sta->mlmStaContext.cleanupTrigger; + + if (LIM_IS_STA_ROLE(pe_session)) { + lim_connectivity_bmiss_disconn_event(sta, mac->psoc, reasonCode, + pe_session->vdev_id); + + lim_post_sme_message(mac, LIM_MLM_DEAUTH_IND, + (uint32_t *)&mlmDeauthInd); + } + + if (mac->mlme_cfg->gen.fatal_event_trigger) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_HB_FAILURE, + false, false); + + lim_send_sme_deauth_ind(mac, sta, pe_session); + +} /*** lim_tear_down_link_with_ap() ***/ + +/** + * lim_handle_heart_beat_failure() - handle hear beat failure in STA + * + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called when heartbeat (beacon reception) + * fails on STA + * + * Return: None + */ + +void lim_handle_heart_beat_failure(struct mac_context *mac_ctx, + struct pe_session *session) +{ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + host_log_beacon_update_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_beacon_update_pkt_type, + LOG_WLAN_BEACON_UPDATE_C); + if (log_ptr) + log_ptr->bcn_rx_cnt = session->LimRxedBeaconCntDuringHB; + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (LIM_IS_STA_ROLE(session) && + lim_is_sb_disconnect_allowed(session)) { + if (!mac_ctx->sys.gSysEnableLinkMonitorMode) { + goto hb_handler_fail; + } + + /* Ignore HB if channel switch is in progress */ + if (session->gLimSpecMgmt.dot11hChanSwState == + eLIM_11H_CHANSW_RUNNING) { + pe_debug("Ignore Heartbeat failure as Channel switch is in progress"); + session->pmmOffloadInfo.bcnmiss = false; + goto hb_handler_fail; + } + /* Beacon frame not received within heartbeat timeout. */ + pe_warn("Heartbeat Failure"); + mac_ctx->lim.gLimHBfailureCntInLinkEstState++; + + /* + * Before host received beacon miss, firmware has checked link + * by sending QoS NULL data, don't need host send probe req. + * Some IoT AP can send probe response, but can't send beacon + * sometimes, need disconnect too, or firmware will assert. + */ + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_DISASSOC_DUE_TO_INACTIVITY, + session->bssId, + session, false); + lim_tear_down_link_with_ap(mac_ctx, + session->peSessionId, + REASON_BEACON_MISSED, + eLIM_LINK_MONITORING_DEAUTH); + } else { + /** + * Heartbeat timer may have timed out + * while we're doing background scanning/learning + * or in states other than link-established state. + * Log error. + */ + pe_debug("received heartbeat timeout in state %X", + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOG1, session->limMlmState); + mac_ctx->lim.gLimHBfailureCntInOtherStates++; + } + +hb_handler_fail: + if (mac_ctx->sme.tx_queue_cb) + mac_ctx->sme.tx_queue_cb(mac_ctx->hdd_handle, + session->smeSessionId, + WLAN_WAKE_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); +} + +void lim_rx_invalid_peer_process(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg) +{ + struct ol_rx_inv_peer_params *msg = + (struct ol_rx_inv_peer_params *)lim_msg->bodyptr; + struct pe_session *session_entry; + uint16_t reason_code = REASON_CLASS3_FRAME_FROM_NON_ASSOC_STA; + uint16_t aid; + tpDphHashNode sta_ds; + + if (!msg) { + pe_err("Invalid body pointer in message"); + return; + } + + session_entry = pe_find_session_by_vdev_id(mac_ctx, msg->vdev_id); + if (!session_entry) { + pe_err_rl("session not found for given sme session"); + qdf_mem_free(msg); + return; + } + + /* only if SAP mode */ + if (session_entry->bssType == eSIR_INFRA_AP_MODE) { + sta_ds = dph_lookup_hash_entry(mac_ctx, msg->ta, &aid, + &session_entry->dph.dphHashTable); + if (sta_ds && sta_ds->is_key_installed) { + /* + * Skip deauth for an associated STA. + * + * The deauth sent for invalid peer indication will + * not cleanup the SM if this is an associated STA. + * Therefore, the deauth for associated STA creates + * stale entries even after STA gets disconnected. + */ + pe_err_rl("Received Invalid rx peer indication for an associated STA " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(msg->ta)); + qdf_mem_free(msg); + lim_msg->bodyptr = NULL; + return; + } + pe_debug("send deauth frame to non-assoc STA"); + lim_send_deauth_mgmt_frame(mac_ctx, + reason_code, + msg->ta, + session_entry, + false); + } + + qdf_mem_free(msg); + lim_msg->bodyptr = NULL; +} + +void lim_req_send_delba_ind_process(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg) +{ + struct lim_delba_req_info *req = + (struct lim_delba_req_info *)lim_msg->bodyptr; + QDF_STATUS status; + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!req) { + pe_err("Invalid body pointer in message"); + return; + } + + status = lim_send_delba_action_frame(mac_ctx, req->vdev_id, + req->peer_macaddr, + req->tid, req->reason_code); + if (status != QDF_STATUS_SUCCESS) + cdp_delba_tx_completion(dp_soc, req->peer_macaddr, + req->vdev_id, req->tid, + WMI_MGMT_TX_COMP_TYPE_DISCARD); + qdf_mem_free(req); + lim_msg->bodyptr = NULL; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_mlo.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_mlo.c new file mode 100644 index 0000000000..59ea762735 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_mlo.c @@ -0,0 +1,1427 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC : lim_mlo.c + * + * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) + * support. + * + */ + +#include "lim_mlo.h" +#include "sch_api.h" +#include "lim_types.h" +#include "wlan_mlo_mgr_ap.h" +#include "wlan_mlo_mgr_op.h" +#include +#include +#include +#include +#include + +QDF_STATUS lim_cu_info_from_rnr_per_link_id(const uint8_t *rnr, + uint8_t linkid, uint8_t *bpcc, + uint8_t *aui) +{ + const uint8_t *data, *rnr_end; + struct neighbor_ap_info_field *neighbor_ap_info; + uint8_t tbtt_type, tbtt_len, tbtt_count; + uint8_t mld_pos, mld_id, link_id; + struct rnr_mld_info *mld_param; + int32_t i, len; + uint8_t nbr_ap_info_len = sizeof(struct neighbor_ap_info_field); + + if (!rnr) + return QDF_STATUS_E_INVAL; + + rnr_end = rnr + rnr[TAG_LEN_POS] + MIN_IE_LEN; + data = rnr + PAYLOAD_START_POS; + while ((data + sizeof(struct neighbor_ap_info_field)) <= rnr_end) { + neighbor_ap_info = (struct neighbor_ap_info_field *)data; + tbtt_count = neighbor_ap_info->tbtt_header.tbtt_info_count; + tbtt_len = neighbor_ap_info->tbtt_header.tbtt_info_length; + tbtt_type = neighbor_ap_info->tbtt_header.tbbt_info_fieldtype; + len = tbtt_len * (tbtt_count + 1) + nbr_ap_info_len; + if (data + len > rnr_end) { + pe_debug("error about rnr length"); + return QDF_STATUS_E_INVAL; + } + + if (tbtt_len >= + TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD_MLD_PARAM) + mld_pos = + TBTT_NEIGHBOR_AP_BSSID_S_SSID_BSS_PARAM_20MHZ_PSD; + else + mld_pos = 0; + + if (mld_pos == 0 || tbtt_type != 0) { + data += len; + continue; + } + + data += nbr_ap_info_len; + for (i = 0; i < tbtt_count + 1; i++) { + mld_param = (struct rnr_mld_info *)&data[mld_pos]; + mld_id = mld_param->mld_id; + if (mld_id == 0) { + link_id = mld_param->link_id; + if (linkid == link_id) { + *bpcc = mld_param->bss_param_change_cnt; + *aui = mld_param->all_updates_included; + pe_debug("rnr bpcc %d, aui %d, linkid %d", + *bpcc, *aui, linkid); + return QDF_STATUS_SUCCESS; + } + } + data += tbtt_len; + } + } + + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS lim_get_bpcc_from_mlo_ie(tSchBeaconStruct *bcn, uint8_t *bpcc) +{ + struct sir_multi_link_ie *mlo_ie; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (!bcn) + return status; + + mlo_ie = &bcn->mlo_ie; + if (mlo_ie->mlo_ie_present && + mlo_ie->mlo_ie.bss_param_change_cnt_present) { + *bpcc = mlo_ie->mlo_ie.bss_param_change_count; + pe_debug("mlie bpcc %d", *bpcc); + status = QDF_STATUS_SUCCESS; + } else { + *bpcc = 0; + } + + return status; +} + +bool lim_check_cu_happens(struct wlan_objmgr_vdev *vdev, uint8_t new_bpcc) +{ + uint8_t bpcc; + uint8_t vdev_id; + QDF_STATUS status; + + if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return false; + + vdev_id = wlan_vdev_get_id(vdev); + + status = wlan_mlo_get_cu_bpcc(vdev, &bpcc); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + if (new_bpcc == 0 && bpcc == 0) + return false; + + pe_debug_rl("vdev id %d new bpcc %d, old bpcc %d", + vdev_id, new_bpcc, bpcc); + if (new_bpcc && new_bpcc < bpcc) + return false; + + wlan_mlo_set_cu_bpcc(vdev, new_bpcc); + + return true; +} + +/** + * lim_send_mlo_ie_update() - mlo ie is changed, populate new beacon template + * @session: pe session + * + * Return: void + */ +static void lim_send_mlo_ie_update(struct mac_context *mac_ctx, + struct pe_session *session) +{ + if (QDF_IS_STATUS_ERROR( + sch_set_fixed_beacon_fields(mac_ctx, session))) { + pe_err("Unable to update mlo IE in beacon"); + return; + } + + lim_send_beacon_ind(mac_ctx, session, REASON_MLO_IE_UPDATE); +} + +QDF_STATUS lim_partner_link_info_change(struct wlan_objmgr_vdev *vdev) +{ + struct pe_session *session; + struct mac_context *mac; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + if (!vdev) { + pe_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + session = pe_find_session_by_vdev_id( + mac, vdev->vdev_objmgr.vdev_id); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (session->mlo_link_info.bcn_tmpl_exist) + lim_send_mlo_ie_update(mac, session); + + return QDF_STATUS_SUCCESS; +} + +void lim_mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev) +{ + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLO_MGR_ID); +} + +struct pe_session *pe_find_partner_session_by_link_id( + struct pe_session *session, uint8_t link_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mac_context *mac; + struct pe_session *partner_session; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return NULL; + } + + if (!session) { + pe_err("session is null"); + return NULL; + } + + vdev = mlo_get_vdev_by_link_id(session->vdev, link_id, + WLAN_LEGACY_MAC_ID); + + if (!vdev) { + pe_err("vdev is null"); + return NULL; + } + + partner_session = pe_find_session_by_vdev_id( + mac, vdev->vdev_objmgr.vdev_id); + + if (!partner_session) + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return partner_session; +} + +void lim_get_mlo_vdev_list(struct pe_session *session, uint16_t *vdev_count, + struct wlan_objmgr_vdev **wlan_vdev_list) +{ + mlo_ap_get_vdev_list(session->vdev, vdev_count, + wlan_vdev_list); +} + +/** + * lim_mlo_get_assoc_link_session_sta_ds() - get assoc link session and sta ds + * @session: pe session + * @partner_peer_idx: aid + * @assoc_session: assoc link session + * @assoc_sta: assoc sta ds + * + * Return: void + */ +static void lim_mlo_get_assoc_link_session_sta_ds( + struct pe_session *session, + uint16_t partner_peer_idx, + struct pe_session **assoc_session, + tpDphHashNode *assoc_sta) +{ + struct wlan_mlo_peer_context *mlo_peer_ctx; + struct wlan_objmgr_peer *peer; + uint16_t aid = 0; + struct mac_context *mac; + struct wlan_objmgr_vdev *vdev; + struct pe_session *partner_session; + + *assoc_session = NULL; + *assoc_sta = NULL; + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return; + } + if (!session) { + pe_err("session is NULL"); + return; + } + + mlo_peer_ctx = wlan_mlo_get_mlpeer_by_aid(session->vdev->mlo_dev_ctx, + partner_peer_idx); + if (!mlo_peer_ctx) { + pe_err("mlo peer ctx is null"); + return; + } + peer = wlan_mlo_peer_get_assoc_peer(mlo_peer_ctx); + if (!peer) { + pe_err("peer is null"); + return; + } + vdev = wlan_peer_get_vdev(peer); + if (!vdev) { + pe_err("vdev is null"); + return; + } + partner_session = pe_find_session_by_vdev_id( + mac, vdev->vdev_objmgr.vdev_id); + + if (!partner_session) { + pe_err("assoc session is null"); + return; + } + *assoc_sta = dph_lookup_hash_entry(mac, peer->macaddr, &aid, + &partner_session->dph.dphHashTable); + *assoc_session = partner_session; +} + +/** + * lim_mlo_update_cleanup_trigger () - update clean up trigger + * @session: pointer to session + * @sta_ds: sta ds + * @clnup_tri: clean up trigger + * + * Return: Void + */ +static void lim_mlo_update_cleanup_trigger(struct pe_session *session, + tpDphHashNode sta_ds, + uint16_t clnup_tri) +{ + tpDphHashNode assoc_sta = NULL; + struct pe_session *link_session; + struct pe_session *assoc_session = NULL; + struct mac_context *mac_ctx; + tpDphHashNode link_sta; + uint8_t link_id; + int link; + uint8_t *sta_addr; + uint16_t assoc_id; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return; + } + if (!session) { + pe_err("session is null"); + return; + } + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + + if (lim_is_mlo_recv_assoc(sta_ds)) { + assoc_sta = sta_ds; + } else { + lim_mlo_get_assoc_link_session_sta_ds(session, sta_ds->assocId, + &assoc_session, + &assoc_sta); + if (!assoc_sta) { + pe_err("assoc link sta ds is null"); + return; + } + + assoc_sta->mlmStaContext.cleanupTrigger = clnup_tri; + } + for (link = 0; link < assoc_sta->mlo_info.num_partner_links; link++) { + link_id = assoc_sta->mlo_info.partner_link_info[link].link_id; + link_session = pe_find_partner_session_by_link_id(session, + link_id); + if (!link_session) + continue; + sta_addr = + assoc_sta->mlo_info.partner_link_info[link].link_addr.bytes; + link_sta = dph_lookup_hash_entry( + mac_ctx, + sta_addr, + &assoc_id, + &link_session->dph.dphHashTable); + if (!link_sta || link_sta == sta_ds) { + lim_mlo_release_vdev_ref(link_session->vdev); + continue; + } + link_sta->mlmStaContext.cleanupTrigger = clnup_tri; + lim_mlo_release_vdev_ref(link_session->vdev); + } +} + +void lim_mlo_notify_peer_disconn(struct pe_session *pe_session, + tpDphHashNode sta_ds) +{ + struct wlan_objmgr_peer *peer; + struct mac_context *mac_ctx; + + if (!pe_session) { + pe_err("pe session is null"); + return; + } + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + mac_ctx = pe_session->mac_ctx; + if (!mac_ctx) { + pe_err("mac context is null"); + return; + } + + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, + sta_ds->staAddr, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("peer is null"); + return; + } + + if (wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO)) { + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + lim_mlo_update_cleanup_trigger( + pe_session, sta_ds, + sta_ds->mlmStaContext.cleanupTrigger); + wlan_mlo_partner_peer_disconnect_notify(peer); + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +void lim_mlo_sta_notify_peer_disconn(struct pe_session *pe_session) +{ + struct wlan_objmgr_peer *peer; + struct mac_context *mac_ctx; + + if (!pe_session) { + pe_err("pe session is null"); + return; + } + mac_ctx = pe_session->mac_ctx; + if (!mac_ctx) { + pe_err("mac context is null"); + return; + } + + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, + pe_session->bssId, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("peer is null"); + return; + } + + if (wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO)) + wlan_mlo_partner_peer_disconnect_notify(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +void lim_mlo_roam_peer_disconn_del(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssid; + + if (!vdev) { + pe_err("vdev is null"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pe_err("psoc is null"); + return; + } + + status = wlan_vdev_get_bss_peer_mac(vdev, &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("vdev id %d : failed to get bssid", + wlan_vdev_get_id(vdev)); + return; + } + + peer = wlan_objmgr_get_peer_by_mac(psoc, + bssid.bytes, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("peer is null"); + return; + } + + if (wlan_peer_mlme_flag_ext_get(peer, WLAN_PEER_FEXT_MLO)) { + pe_debug("vdev id %d disconn del peer", wlan_vdev_get_id(vdev)); + wlan_mlo_partner_peer_disconnect_notify(peer); + wlan_mlo_link_peer_delete(peer); + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +void lim_mlo_cleanup_partner_peer(struct wlan_objmgr_peer *peer) +{ + struct mac_context *mac_ctx; + uint16_t aid; + tpDphHashNode sta_ds; + struct pe_session *pe_session; + tpSirAssocReq tmp_assoc_req; + struct wlan_objmgr_vdev *vdev; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return; + } + + vdev = wlan_peer_get_vdev(peer); + if (!vdev) { + pe_err("vdev is null"); + return; + } + + pe_session = pe_find_session_by_vdev_id( + mac_ctx, vdev->vdev_objmgr.vdev_id); + if (!pe_session) { + pe_err("pe session is null"); + return; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, peer->macaddr, &aid, + &pe_session->dph.dphHashTable); + + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + + lim_cleanup_rx_path(mac_ctx, sta_ds, pe_session, true); + + if (pe_session->parsedAssocReq) { + tmp_assoc_req = pe_session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req) { + lim_free_assoc_req_frm_buf(tmp_assoc_req); + qdf_mem_free(tmp_assoc_req); + tmp_assoc_req = NULL; + } + + pe_session->parsedAssocReq[sta_ds->assocId] = NULL; + } +} + +void lim_mlo_set_mld_mac_peer(tpDphHashNode sta_ds, + uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE]) +{ + WLAN_ADDR_COPY(sta_ds->mld_addr, peer_mld_addr); +} + +bool lim_is_mlo_conn(struct pe_session *session, tpDphHashNode sta_ds) +{ + bool mlo_conn = false; + + if (!sta_ds) { + pe_err("sta ds is null"); + return mlo_conn; + } + + if (!session) { + pe_err("session is null"); + return mlo_conn; + } + + if (wlan_vdev_mlme_is_mlo_vdev(session->vdev) && + !qdf_is_macaddr_zero((struct qdf_mac_addr *)sta_ds->mld_addr)) + mlo_conn = true; + + return mlo_conn; +} + +void lim_set_mlo_recv_assoc(tpDphHashNode sta_ds, bool mlo_recv_assoc_frm) +{ + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + + sta_ds->recv_assoc_frm = mlo_recv_assoc_frm; +} + +bool lim_is_mlo_recv_assoc(tpDphHashNode sta_ds) +{ + if (!sta_ds) { + pe_err("sta ds is null"); + return false; + } + + return sta_ds->recv_assoc_frm; +} + +QDF_STATUS lim_mlo_proc_assoc_req_frm(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_peer_context *ml_peer, + struct qdf_mac_addr *link_addr, + qdf_nbuf_t buf) +{ + struct mac_context *mac_ctx; + struct pe_session *session; + tSirMacAddr sa; + uint8_t sub_type; + uint32_t frame_len; + uint8_t *frm_body; + tpSirMacMgmtHdr pHdr; + tSirMacFrameCtl fc; + tpSirAssocReq assoc_req; + QDF_STATUS status; + qdf_size_t link_frame_len = 0; + struct qdf_mac_addr link_bssid; + + if (!vdev) { + pe_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + if (!ml_peer) { + pe_err("ml_peer is null"); + return QDF_STATUS_E_INVAL; + } + + if (!link_addr) { + pe_err("link addr is null"); + return QDF_STATUS_E_INVAL; + } + + if (!buf) { + pe_err("assoq req buf is null"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + + session = pe_find_session_by_vdev_id( + mac_ctx, vdev->vdev_objmgr.vdev_id); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (qdf_nbuf_len(buf) <= sizeof(*pHdr)) { + pe_err("invalid buf"); + return QDF_STATUS_E_INVAL; + } + + frame_len = qdf_nbuf_len(buf) - sizeof(*pHdr); + frm_body = qdf_nbuf_data(buf) + sizeof(*pHdr); + pHdr = (tpSirMacMgmtHdr)qdf_nbuf_data(buf); + fc = pHdr->fc; + + if (fc.type == SIR_MAC_MGMT_FRAME) { + if (fc.subType == SIR_MAC_MGMT_ASSOC_REQ) { + sub_type = LIM_ASSOC; + } else if (fc.subType == SIR_MAC_MGMT_REASSOC_REQ) { + sub_type = LIM_REASSOC; + } else { + pe_err("invalid mgt_type %d, sub_type %d", + fc.type, fc.subType); + return QDF_STATUS_E_INVAL; + } + } else { + pe_err("invalid mgt_type %d, sub_type %d", + fc.type, fc.subType); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(sa, link_addr->bytes, QDF_MAC_ADDR_SIZE); + status = lim_check_assoc_req(mac_ctx, sub_type, sa, session); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + /* Allocate memory for the Assoc Request frame */ + assoc_req = qdf_mem_malloc(sizeof(*assoc_req)); + if (!assoc_req) + return QDF_STATUS_E_NOMEM; + + assoc_req->assoc_req_buf = qdf_nbuf_copy(buf); + if (!assoc_req->assoc_req_buf) { + pe_err("partner link assoc request buf clone failed"); + qdf_mem_free(assoc_req); + return QDF_STATUS_E_NOMEM; + } + qdf_copy_macaddr(&link_bssid, (struct qdf_mac_addr *)session->bssId); + status = util_gen_link_assoc_req( + frm_body, frame_len, sub_type == LIM_REASSOC, + 0, + link_bssid, + qdf_nbuf_data(assoc_req->assoc_req_buf), + qdf_nbuf_len(assoc_req->assoc_req_buf), + &link_frame_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_warn("Partner Assoc Req frame gen error. source addr:" + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(sa)); + lim_free_assoc_req_frm_buf(assoc_req); + qdf_mem_free(assoc_req); + return status; + } + + qdf_nbuf_set_len(assoc_req->assoc_req_buf, link_frame_len); + assoc_req->assocReqFrame = qdf_nbuf_data(assoc_req->assoc_req_buf) + + sizeof(*pHdr); + assoc_req->assocReqFrameLength = link_frame_len - sizeof(*pHdr); + + qdf_copy_macaddr((struct qdf_mac_addr *)assoc_req->mld_mac, + &ml_peer->peer_mld_addr); + return lim_proc_assoc_req_frm_cmn(mac_ctx, sub_type, session, sa, + assoc_req, ml_peer->assoc_id); +} + +void lim_mlo_ap_sta_assoc_suc(struct wlan_objmgr_peer *peer) +{ + struct mac_context *mac; + tpDphHashNode sta; + struct pe_session *pe_session; + struct wlan_objmgr_vdev *vdev; + uint16_t aid = 0; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return; + } + if (!peer) { + pe_err("peer is null"); + return; + } + vdev = wlan_peer_get_vdev(peer); + + pe_session = pe_find_session_by_vdev_id( + mac, vdev->vdev_objmgr.vdev_id); + + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + sta = dph_lookup_hash_entry(mac, peer->macaddr, &aid, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("sta ds is null"); + return; + } + if (lim_send_mlm_assoc_ind(mac, sta, pe_session) != QDF_STATUS_SUCCESS) + lim_reject_association(mac, sta->staAddr, + sta->mlmStaContext.subType, + true, sta->mlmStaContext.authType, + sta->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + pe_session); +} + +void lim_ap_mlo_sta_peer_ind(struct mac_context *mac, + struct pe_session *pe_session, + tpDphHashNode sta, + bool add_sta_rsp_status) +{ + tpSirAssocReq assoc_req; + struct wlan_mlo_peer_context *ml_peer; + struct wlan_objmgr_peer *peer; + struct mlo_partner_info info; + struct mlo_link_info *linfo; + + if (!sta) { + pe_err("sta ds is null"); + return; + } + if (add_sta_rsp_status) { + peer = wlan_objmgr_get_peer_by_mac(mac->psoc, + sta->staAddr, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("peer is null"); + return; + } + + if (lim_is_mlo_recv_assoc(sta)) { + assoc_req = pe_session->parsedAssocReq[sta->assocId]; + if (assoc_req->mlo_info.num_partner_links < + QDF_ARRAY_SIZE( + assoc_req->mlo_info.partner_link_info)) { + qdf_mem_copy(&info, &assoc_req->mlo_info, + sizeof(info)); + linfo = + &info.partner_link_info[info.num_partner_links]; + linfo->link_id = wlan_vdev_get_link_id( + pe_session->vdev); + qdf_mem_copy(linfo->link_addr.bytes, + sta->staAddr, QDF_MAC_ADDR_SIZE); + info.num_partner_links++; + wlan_mlo_peer_create(pe_session->vdev, peer, + &info, + assoc_req->assoc_req_buf, + sta->assocId); + } else { + pe_err("invalid partner link number %d", + assoc_req->mlo_info.num_partner_links); + } + } else { + ml_peer = wlan_mlo_get_mlpeer_by_aid( + pe_session->vdev->mlo_dev_ctx, + sta->assocId); + if (ml_peer) + wlan_mlo_link_peer_attach(ml_peer, peer, NULL); + } + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + } else { + if (!lim_is_mlo_recv_assoc(sta)) { + ml_peer = wlan_mlo_get_mlpeer_by_aid( + pe_session->vdev->mlo_dev_ctx, + sta->assocId); + if (ml_peer) + wlan_mlo_partner_peer_create_failed_notify( + ml_peer); + } + } +} + +bool lim_mlo_partner_auth_type(struct pe_session *session, + uint16_t partner_peer_idx, + tAniAuthType *auth_type) +{ + bool status = false; + struct pe_session *assoc_link_session = NULL; + + tpDphHashNode sta_ds = NULL; + + lim_mlo_get_assoc_link_session_sta_ds(session, partner_peer_idx, + &assoc_link_session, &sta_ds); + + if (sta_ds) { + *auth_type = sta_ds->mlmStaContext.authType; + status = true; + } else { + pe_err("sta ds is null"); + } + + return status; +} + +void lim_mlo_ap_sta_assoc_fail(struct wlan_objmgr_peer *peer) +{ + struct mac_context *mac; + struct wlan_objmgr_vdev *vdev; + tpDphHashNode sta; + struct pe_session *pe_session; + uint16_t aid = 0; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return; + } + if (!peer) { + pe_err("peer is null"); + return; + } + vdev = wlan_peer_get_vdev(peer); + if (!vdev) { + pe_err("vdev is null"); + return; + } + pe_session = pe_find_session_by_vdev_id( + mac, vdev->vdev_objmgr.vdev_id); + + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + sta = dph_lookup_hash_entry(mac, peer->macaddr, &aid, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("sta ds is null"); + return; + } + lim_reject_association(mac, sta->staAddr, + sta->mlmStaContext.subType, + true, sta->mlmStaContext.authType, + sta->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + pe_session); +} + +void lim_mlo_delete_link_peer(struct pe_session *pe_session, + tpDphHashNode sta_ds) +{ + struct wlan_objmgr_peer *peer; + struct mac_context *mac; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return; + } + if (!pe_session) { + pe_err("pe session is null"); + return; + } + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + if (!lim_is_mlo_conn(pe_session, sta_ds)) + return; + + peer = wlan_objmgr_get_peer_by_mac(mac->psoc, + sta_ds->staAddr, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("peer is null"); + return; + } + + wlan_mlo_link_peer_delete(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +#if defined(SAP_MULTI_LINK_EMULATION) +QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac, + struct pe_session *pe_session, + struct mlo_partner_info *mlo_info) +{ + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac, + struct pe_session *pe_session, + struct mlo_partner_info *mlo_info) +{ + int link; + uint8_t link_id; + struct qdf_mac_addr *link_addr; + struct pe_session *lk_session; + tpDphHashNode sta; + uint16_t aid; + struct assoc_ind *sme_assoc_ind; + struct scheduler_msg msg; + tpLimMlmAssocInd lim_assoc_ind; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!mac) { + pe_err("mac is NULL"); + return status; + } + + if (!pe_session) { + pe_err("pe_session is NULL"); + return status; + } + + if (!mlo_info) { + pe_err("mlo_info is NULL"); + return status; + } + + status = QDF_STATUS_SUCCESS; + for (link = 0; link < mlo_info->num_partner_links; link++) { + link_id = mlo_info->partner_link_info[link].link_id; + link_addr = &mlo_info->partner_link_info[link].link_addr; + lk_session = pe_find_partner_session_by_link_id(pe_session, + link_id); + if (!lk_session) { + pe_err("link_session is NULL"); + status = QDF_STATUS_E_FAILURE; + break; + } + sta = dph_lookup_hash_entry(mac, link_addr->bytes, &aid, + &lk_session->dph.dphHashTable); + if (!sta) { + pe_err("sta_ds is NULL"); + status = QDF_STATUS_E_FAILURE; + lim_mlo_release_vdev_ref(lk_session->vdev); + break; + } + lim_assoc_ind = qdf_mem_malloc(sizeof(tLimMlmAssocInd)); + if (!lim_assoc_ind) { + pe_err("lim assoc ind allocate error"); + qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); + lk_session->parsedAssocReq[sta->assocId] = NULL; + status = QDF_STATUS_E_FAILURE; + lim_mlo_release_vdev_ref(lk_session->vdev); + break; + } + + if (!lim_fill_lim_assoc_ind_params(lim_assoc_ind, mac, + sta, lk_session)) { + pe_err("lim assoc ind fill error"); + qdf_mem_free(lim_assoc_ind); + qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); + lk_session->parsedAssocReq[sta->assocId] = NULL; + status = QDF_STATUS_E_FAILURE; + lim_mlo_release_vdev_ref(lk_session->vdev); + break; + } + sme_assoc_ind = qdf_mem_malloc(sizeof(struct assoc_ind)); + if (!sme_assoc_ind) { + pe_err("sme assoc ind allocate error"); + qdf_mem_free(lim_assoc_ind); + qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); + lk_session->parsedAssocReq[sta->assocId] = NULL; + status = QDF_STATUS_E_FAILURE; + lim_mlo_release_vdev_ref(lk_session->vdev); + break; + } + + sme_assoc_ind->messageType = eWNI_SME_ASSOC_IND_UPPER_LAYER; + lim_fill_sme_assoc_ind_params(mac, lim_assoc_ind, sme_assoc_ind, + lk_session, true); + + qdf_mem_zero(&msg, sizeof(struct scheduler_msg)); + msg.type = eWNI_SME_ASSOC_IND_UPPER_LAYER; + msg.bodyptr = sme_assoc_ind; + msg.bodyval = 0; + sme_assoc_ind->reassocReq = sta->mlmStaContext.subType; + sme_assoc_ind->timingMeasCap = sta->timingMeasCap; + MTRACE(mac_trace_msg_tx(mac, lk_session->peSessionId, + msg.type)); + lim_sys_process_mmh_msg_api(mac, &msg); + + qdf_mem_free(lim_assoc_ind); + lim_free_assoc_req_frm_buf( + lk_session->parsedAssocReq[sta->assocId]); + qdf_mem_free(lk_session->parsedAssocReq[sta->assocId]); + lk_session->parsedAssocReq[sta->assocId] = NULL; + lim_mlo_release_vdev_ref(lk_session->vdev); + } + + return status; +} +#endif + +void lim_mlo_save_mlo_info(tpDphHashNode sta_ds, + struct mlo_partner_info *mlo_info) +{ + if (!sta_ds) { + pe_err("sta ds is null"); + return; + } + + qdf_mem_copy(&sta_ds->mlo_info, mlo_info, sizeof(sta_ds->mlo_info)); +} + +QDF_STATUS lim_fill_complete_mlo_ie(struct pe_session *session, + uint16_t total_len, uint8_t *target) +{ + struct wlan_mlo_sta_profile *sta_prof; + uint16_t mlo_ie_total_len; + uint8_t *buf, *pbuf; + uint16_t i; + uint16_t consumed = 0; + uint16_t index = 0; + struct wlan_mlo_ie *mlo_ie; + + if (!session) + return QDF_STATUS_E_INVAL; + + mlo_ie = &session->mlo_ie; + if (total_len > WLAN_MAX_IE_LEN + MIN_IE_LEN) + mlo_ie->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN; + else + mlo_ie->data[TAG_LEN_POS] = total_len - MIN_IE_LEN; + + buf = qdf_mem_malloc(total_len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + pbuf = buf; + qdf_mem_copy(pbuf, mlo_ie->data, mlo_ie->num_data); + pbuf += mlo_ie->num_data; + + for (i = 0; i < mlo_ie->num_sta_profile; i++) { + sta_prof = &mlo_ie->sta_profile[i]; + qdf_mem_copy(pbuf, sta_prof->data, sta_prof->num_data); + pbuf += sta_prof->num_data; + } + + target[consumed++] = buf[index++]; + target[consumed++] = buf[index++]; + mlo_ie_total_len = pbuf - buf - MIN_IE_LEN; + if (mlo_ie_total_len > total_len - MIN_IE_LEN) { + pe_err("Invalid len: %u, %u", mlo_ie_total_len, total_len); + qdf_mem_free(buf); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < mlo_ie_total_len; i++) { + if (i && (i % WLAN_MAX_IE_LEN) == 0) { + /* add fragmentation IE and length */ + target[consumed++] = WLAN_ELEMID_FRAGMENT; + if ((mlo_ie_total_len - i) > WLAN_MAX_IE_LEN) + target[consumed++] = WLAN_MAX_IE_LEN; + else + target[consumed++] = mlo_ie_total_len - i; + } + target[consumed++] = buf[index++]; + } + qdf_mem_free(buf); + pe_debug("pack mlo ie %d bytes, expected to copy %d bytes", + consumed, total_len); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + target, consumed); + + return QDF_STATUS_SUCCESS; +} + +uint16_t lim_caculate_mlo_ie_length(struct wlan_mlo_ie *mlo_ie) +{ + struct wlan_mlo_sta_profile *sta_prof; + uint16_t total_len; + uint16_t i, tmp; + + total_len = mlo_ie->num_data; + for (i = 0; i < mlo_ie->num_sta_profile; i++) { + sta_prof = &mlo_ie->sta_profile[i]; + total_len += sta_prof->num_data; + } + + if (total_len > WLAN_MAX_IE_LEN + MIN_IE_LEN) { + /* ML IE max length WLAN_MAX_IE_LEN + MIN_IE_LEN */ + tmp = total_len - (WLAN_MAX_IE_LEN + MIN_IE_LEN); + while (tmp > WLAN_MAX_IE_LEN) { + /* add one flagmentation IE */ + total_len += MIN_IE_LEN; + tmp -= WLAN_MAX_IE_LEN; + } + /* add one flagmentation IE */ + total_len += MIN_IE_LEN; + } + return total_len; +} + +QDF_STATUS lim_store_mlo_ie_raw_info(uint8_t *ie, uint8_t *sta_prof_ie, + uint32_t total_len, + struct wlan_mlo_ie *mlo_ie) +{ + uint32_t i, frag_num = 0, sta_index; + /* ml_ie_len = total_len - 2 * frag_num, does not include + * WLAN_ELEMID_FRAGMENT IE and LEN + */ + uint32_t ml_ie_len; + uint32_t index, copied; + uint8_t *pfrm; + uint8_t *buf; + struct wlan_mlo_sta_profile *sta_prof; + uint8_t *sta_data; + /* Per STA profile frag or not */ + bool frag = FALSE; + + if (!ie) + return QDF_STATUS_E_INVAL; + + qdf_mem_zero(mlo_ie, sizeof(*mlo_ie)); + + /* assume element ID + LEN + extension element ID + multi-link control + + * common info length always less than WLAN_MAX_IE_LEN + */ + mlo_ie->num_data = sta_prof_ie - ie; + if (mlo_ie->num_data > WLAN_MLO_IE_COM_MAX_LEN) { + mlo_ie->num_data = 0; + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(mlo_ie->data, ie, mlo_ie->num_data); + + /* Count how many frag IE */ + pfrm = ie; + ml_ie_len = pfrm[TAG_LEN_POS] + MIN_IE_LEN; + while (ml_ie_len < total_len) { + frag_num++; + pfrm += MIN_IE_LEN + pfrm[TAG_LEN_POS]; + ml_ie_len += pfrm[TAG_LEN_POS] + MIN_IE_LEN; + } + ml_ie_len = total_len - frag_num * MIN_IE_LEN; + + pe_debug_rl("ml_ie_len: %d, total_len: %d, frag_num: %d", ml_ie_len, + total_len, frag_num); + + buf = qdf_mem_malloc(total_len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + /* Copy the raw info and skip frag IE */ + index = 0; + copied = 0; + buf[index++] = ie[copied++]; + buf[index++] = ie[copied++]; + for (i = 0; i < ml_ie_len - MIN_IE_LEN; i++) { + /* skip the frag IE */ + if (i && (i % WLAN_MAX_IE_LEN) == 0) + copied += MIN_IE_LEN; + buf[index++] = ie[copied++]; + } + + /* copy sta profile from buf, it has copied the common info */ + sta_index = 0; + copied = mlo_ie->num_data; + pfrm = buf + copied; + while (copied < ml_ie_len && sta_index < WLAN_MLO_MAX_VDEVS && + pfrm[ID_POS] == WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE) { + sta_prof = &mlo_ie->sta_profile[sta_index]; + sta_data = sta_prof->data; + index = 0; + + sta_data[index++] = buf[copied++]; + sta_data[index++] = buf[copied++]; + do { + if (index + pfrm[TAG_LEN_POS] > + WLAN_STA_PROFILE_MAX_LEN) { + qdf_mem_free(buf); + pe_debug("no enough buf to store sta prof"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < pfrm[TAG_LEN_POS]; i++) + sta_data[index++] = buf[copied++]; + sta_prof->num_data = index; + + if (copied < ml_ie_len && + pfrm[TAG_LEN_POS] == WLAN_MAX_IE_LEN && + pfrm[WLAN_MAX_IE_LEN + MIN_IE_LEN] == + WLAN_ML_LINFO_SUBELEMID_FRAGMENT) { + frag = TRUE; + /* skip sta profile frag IE */ + copied += MIN_IE_LEN; + } else { + frag = FALSE; + } + pfrm += pfrm[TAG_LEN_POS] + MIN_IE_LEN; + } while (frag); + pe_debug_rl("sta index: %d, sta_data len: %d, copied: %d", + sta_index, index, copied); + sta_index++; + } + + mlo_ie->num_sta_profile = sta_index; + qdf_mem_free(buf); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_add_frag_ie_for_sta_profile(uint8_t *data, uint16_t *len) +{ + uint16_t total_len; + uint16_t tmp, i; + uint8_t *buf; + uint16_t consumed = 0; + uint16_t index = 0; + + total_len = *len; + buf = qdf_mem_malloc(total_len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(buf, data, total_len); + + if (total_len > WLAN_MAX_IE_LEN + MIN_IE_LEN) { + /* ML IE max length WLAN_MAX_IE_LEN + MIN_IE_LEN */ + tmp = total_len - (WLAN_MAX_IE_LEN + MIN_IE_LEN); + while (tmp > WLAN_MAX_IE_LEN) { + /* add one flagmentation IE */ + total_len += MIN_IE_LEN; + tmp -= WLAN_MAX_IE_LEN; + } + /* add one flagmentation IE */ + total_len += MIN_IE_LEN; + } + + data[consumed++] = buf[index++]; + data[consumed++] = buf[index++]; + for (i = 0; i < (*len - MIN_IE_LEN); i++) { + data[consumed++] = buf[index++]; + if (i && (i % WLAN_MAX_IE_LEN) == 0) { + data[consumed++] = WLAN_ML_LINFO_SUBELEMID_FRAGMENT; + if ((*len - MIN_IE_LEN - i) > WLAN_MAX_IE_LEN) + data[consumed++] = WLAN_MAX_IE_LEN; + else + data[consumed++] = *len - MIN_IE_LEN - i; + } + } + + *len = total_len; + qdf_mem_free(buf); + + return QDF_STATUS_SUCCESS; +} + +uint16_t +lim_fill_assoc_req_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocRequest *frm) +{ + QDF_STATUS status; + + session->mlo_ie_total_len = 0; + qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); + if ((wlan_vdev_mlme_get_opmode(session->vdev) == QDF_STA_MODE) && + wlan_vdev_mlme_is_mlo_vdev(session->vdev)) { + status = + populate_dot11f_assoc_req_mlo_ie(mac_ctx, session, frm); + if (QDF_IS_STATUS_SUCCESS(status)) + session->mlo_ie_total_len = + lim_caculate_mlo_ie_length(&session->mlo_ie); + } + + return session->mlo_ie_total_len; +} + +uint16_t +lim_send_assoc_rsp_mgmt_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session, + tpDphHashNode sta, + tDot11fAssocResponse *frm) +{ + QDF_STATUS status; + + session->mlo_ie_total_len = 0; + qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); + status = populate_dot11f_assoc_rsp_mlo_ie(mac_ctx, session, sta, frm); + if (QDF_IS_STATUS_SUCCESS(status)) + session->mlo_ie_total_len = + lim_caculate_mlo_ie_length(&session->mlo_ie); + + return session->mlo_ie_total_len; +} + +uint16_t +lim_send_bcn_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session) +{ + QDF_STATUS status; + + session->mlo_ie_total_len = 0; + qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); + status = populate_dot11f_bcn_mlo_ie(mac_ctx, session); + if (QDF_IS_STATUS_SUCCESS(status)) + session->mlo_ie_total_len = + lim_caculate_mlo_ie_length(&session->mlo_ie); + + return session->mlo_ie_total_len; +} + +uint16_t +lim_send_probe_req_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session) +{ + QDF_STATUS status; + + session->mlo_ie_total_len = 0; + qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); + status = populate_dot11f_probe_req_mlo_ie(mac_ctx, session); + if (QDF_IS_STATUS_SUCCESS(status)) + session->mlo_ie_total_len = + lim_caculate_mlo_ie_length(&session->mlo_ie); + + return session->mlo_ie_total_len; +} + +uint16_t +lim_send_tdls_mgmt_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session) +{ + QDF_STATUS status; + + session->mlo_ie_total_len = 0; + qdf_mem_zero(&session->mlo_ie, sizeof(session->mlo_ie)); + status = populate_dot11f_tdls_mgmt_mlo_ie(mac_ctx, session); + if (QDF_IS_STATUS_SUCCESS(status)) + session->mlo_ie_total_len = + lim_caculate_mlo_ie_length(&session->mlo_ie); + + return session->mlo_ie_total_len; +} + +uint16_t +lim_get_frame_mlo_ie_len(struct pe_session *session) +{ + if (session) + return session->mlo_ie_total_len; + else + return 0; +} + +bool +lim_is_ml_peer_state_disconn(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *mac_addr) +{ + struct wlan_objmgr_peer *peer; + struct wlan_mlo_peer_context *ml_peer = NULL; + bool is_ml_peer_disconn = false; + + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, mac_addr, + WLAN_LEGACY_MAC_ID); + + if (!peer) { + pe_err("peer is NULL"); + return is_ml_peer_disconn; + } + + if ((session->opmode == QDF_STA_MODE) && + wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + ml_peer = peer->mlo_peer_ctx; + + if (!ml_peer) { + pe_err("ML peer ctx not found"); + goto end; + } + + if (QDF_IS_STATUS_SUCCESS(wlan_mlo_peer_is_disconnect_progress(ml_peer))) + is_ml_peer_disconn = true; + +end: + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return is_ml_peer_disconn; +} + +bool lim_is_emlsr_band_supported(struct pe_session *session) +{ + uint8_t i; + uint32_t freq; + struct mlo_partner_info *partner_info; + + if (!session->lim_join_req) { + /* Initial connection */ + partner_info = &session->ml_partner_info; + } else { + /* Roaming */ + partner_info = &session->lim_join_req->partner_info; + } + + if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + return false; + + for (i = 0; i < partner_info->num_partner_links; i++) { + freq = partner_info->partner_link_info[i].chan_freq; + if (wlan_reg_is_24ghz_ch_freq(freq)) + return false; + } + + return true; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_mlo.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_mlo.h new file mode 100644 index 0000000000..267c9ba601 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_mlo.h @@ -0,0 +1,565 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC : lim_mlo.h + * + * WLAN Host Device Driver file for 802.11be (Extremely High Throughput) + * support. + * + */ + +#if !defined(LIM_MLO_H) +#define LIM_MLO_H + +#include "ani_global.h" +#include "lim_session.h" +#include + +#ifdef WLAN_FEATURE_11BE_MLO + +/** + * lim_update_partner_link_info - Update partner link information + * + * This function is triggered from mlo mgr + * + * @vdev: vdev pointer + * + * Return: QDF_STATUS_SUCCESS on successful update link info else failure. + */ +QDF_STATUS lim_partner_link_info_change(struct wlan_objmgr_vdev *vdev); + +/** + * lim_mlo_free_vdev_ref() - release vdev reference + * @vdev: vdev obj + * + * Return: void + */ +void lim_mlo_release_vdev_ref(struct wlan_objmgr_vdev *vdev); + +/** + * pe_find_partner_session_by_link_id() - Get partner session by link id + * @session: pe session + * @link_id: link id + * + * Return: partner session + */ +struct pe_session *pe_find_partner_session_by_link_id( + struct pe_session *session, uint8_t link_id); + +/** + * lim_get_mlo_vdev_list() - Get mlo vdev list + * @session: pe session + * @vdev_count: vdev count + * @wlan_vdev_list: vdev list + * + * Return: void + */ +void lim_get_mlo_vdev_list(struct pe_session *session, uint16_t *vdev_count, + struct wlan_objmgr_vdev **wlan_vdev_list); + +/** + * lim_mlo_roam_peer_disconn_del - trigger mlo to delete partner peer + * This API is only for MLO STA roam. + * @vdev: vdev pointer + * + * Return: void + */ +void lim_mlo_roam_peer_disconn_del(struct wlan_objmgr_vdev *vdev); + +/** + * lim_mlo_notify_peer_disconn - trigger mlo to delete partner peer + * @pe_session: pe session + * @sta_ds: Pointer to internal STA Datastructure + * + * Return: void + */ +void lim_mlo_notify_peer_disconn(struct pe_session *pe_session, + tpDphHashNode sta_ds); + +/** + * lim_mlo_sta_notify_peer_disconn - trigger mlo to delete partner peer + * This API is only for MLO STA. + * @pe_session: pe session + * + * Return: void + */ +void lim_mlo_sta_notify_peer_disconn(struct pe_session *pe_session); + +/** + * lim_mlo_cleanup_partner_peer() - cleanup given peer which is partner peer + * of mlo connection. + * + * This function is triggered from mlo mgr. + * + * @peer: pointer to peer to be cleanup + * + * Return: void + */ +void lim_mlo_cleanup_partner_peer(struct wlan_objmgr_peer *peer); + +/** + * lim_mlo_set_mld_mac_peer() - set mld mac + * @sta_ds: Pointer to internal STA Datastructure + * @peer_mld_addr: peer mld mac addr + * + * Return: void + */ +void lim_mlo_set_mld_mac_peer(tpDphHashNode sta_ds, + uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE]); + +/** + * lim_is_mlo_conn() - whether it is mlo connection + * @session: pe session + * @sta_ds: Pointer to internal STA Datastructure + * + * Return: true if it is mlo connection + */ +bool lim_is_mlo_conn(struct pe_session *session, tpDphHashNode sta_ds); + +/** + * lim_is_mlo_recv_assoc() - whether it received assoc frame or not + * @sta_ds: Pointer to internal STA Datastructure + * + * Return: true if this peer corresponding link received assoc frame + */ +bool lim_is_mlo_recv_assoc(tpDphHashNode sta_ds); + +/** + * lim_set_mlo_recv_assoc() - set received assoc frame flag + * @sta_ds: Pointer to internal STA Datastructure + * @mlo_recv_assoc_frm: true if it received assoc frame + * + * Return: void + */ +void lim_set_mlo_recv_assoc(tpDphHashNode sta_ds, bool mlo_recv_assoc_frm); + +/** + * lim_mlo_proc_assoc_req_frm() - process assoc frame for mlo partner link + * + * This function is triggered by mlo mgr + * + * @vdev: pointer to vdev + * @ml_peer: pointer to ml_peer + * @link_addr: link addr + * @frm_buf: assoc req buffer + * + * This function is called from mlo mgr. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_mlo_proc_assoc_req_frm(struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_peer_context *ml_peer, + struct qdf_mac_addr *link_addr, + qdf_nbuf_t buf); + +/** + * lim_mlo_ap_sta_assoc_suc() - process add sta rsp for mlo connection + * @peer: pointer to peer to handle add sta response + * + * This function is triggered from mlo mgr. + * + * Return: void + */ +void lim_mlo_ap_sta_assoc_suc(struct wlan_objmgr_peer *peer); + +/** + * lim_ap_mlo_sta_peer_ind() - Indicate mlo mgr after receiving sta rsp + * + * @mac: pointer to mac_context + * @pe_session: pe session + * @sta_ds: Pointer to internal STA Datastructure + * @add_sta_rsp_status: add sta rsp status + * + * Return: void + */ +void lim_ap_mlo_sta_peer_ind(struct mac_context *mac, + struct pe_session *pe_session, + tpDphHashNode sta, + bool add_sta_rsp_status); + +/** + * lim_mlo_partner_auth_type: update auth type from partner + * @session: pe session + * @partner_peer_idx: aid + * @auth_type: auth type to update + * + * Return: true if auth type is gotten successfully + */ +bool lim_mlo_partner_auth_type(struct pe_session *session, + uint16_t partner_peer_idx, + tAniAuthType *auth_type); + +/** + * lim_mlo_ap_sta_assoc_fail() - process add sta rsp fail for mlo connection + * @peer: pointer to peer to handle add sta response + * + * This function is triggered from mlo mgr. + * + * Return: void + */ +void lim_mlo_ap_sta_assoc_fail(struct wlan_objmgr_peer *peer); + +/** + * lim_mlo_delete_link_peer() - notify mlo mgr peer obj is deleted + * @pe_session: pe session + * @sta_ds: Pointer to internal STA Datastructure + * + * Return: void + */ +void lim_mlo_delete_link_peer(struct pe_session *pe_session, + tpDphHashNode sta_ds); + +/** + * lim_mlo_assoc_ind_upper_layer() - indicate assoc confirm to upper layer + * for mlo partner link + * @mac: pointer to mac_context + * @pe_session: pe session + * @mlo_info: mlo partner information + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_mlo_assoc_ind_upper_layer(struct mac_context *mac, + struct pe_session *pe_session, + struct mlo_partner_info *mlo_info); +void lim_mlo_save_mlo_info(tpDphHashNode sta_ds, + struct mlo_partner_info *mlo_info); + +/** + * lim_add_frag_ie_for_sta_profile() - add frag IE if STA prof len more than 255 + * @data: sta profile ie data + * @len: the length of the data + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_add_frag_ie_for_sta_profile(uint8_t *data, uint16_t *len); + +/** + * lim_fill_complete_mlo_ie() - fill mlo ie to target buffer + * @session: pointer to pe_session + * @total_len: the total bytes to fill target buffer + * @target: the buffer to fill data + * + * It also will insert the frag IE WLAN_ELEMID_FRAGMENT if the ML IE's length + * more than 255 bytes. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_fill_complete_mlo_ie(struct pe_session *session, + uint16_t total_len, uint8_t *target); + +/** + * lim_caculate_mlo_ie_length() - calculate the ML IE length + * @mlo_ie: the pointer to wlan_mlo_ie + * + * It tries to add the len of frag IE WLAN_ELEMID_FRAGMENT if the ML IE + * length more than 255 bytes. + * + * Return: QDF_STATUS + */ +uint16_t lim_caculate_mlo_ie_length(struct wlan_mlo_ie *mlo_ie); + +/** + * lim_fill_assoc_req_mlo_ie() - Prepare ML IE for assoc req frame + * @mac_ctx: pointer to mac_context + * @session: pointer to pe_session + * @frm: pointer to tDot11fAssocRequest + * + * Return: the actual ML IE length + */ +uint16_t +lim_fill_assoc_req_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocRequest *frm); + +/** + * lim_send_assoc_rsq_mgmt_frame_mlo() - Prepare ML IE for assoc rsq frame + * @mac_ctx: pointer to mac_context + * @session: pointer to pe_session + * @sta: pointer to tpDphHashNode + * @frm: pointer to tDot11fAssocRequest + * + * Return: the actual ML IE length + */ +uint16_t +lim_send_assoc_rsp_mgmt_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session, + tpDphHashNode sta, + tDot11fAssocResponse *frm); + +/** + * lim_send_bcn_frame_mlo() - Prepare ML IE for beacon frame + * @mac_ctx: pointer to mac_context + * @session: pointer to pe_session + * + * Return: the actual ML IE length + */ +uint16_t +lim_send_bcn_frame_mlo(struct mac_context *mac_ctx, struct pe_session *session); + +/** + * lim_send_probe_req_frame_mlo() - Prepare ML IE for probe req frame + * @mac_ctx: pointer to mac_context + * @session: pointer to pe_session + * + * Return: the actual ML IE length + */ +uint16_t +lim_send_probe_req_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_send_tdls_mgmt_frame_mlo() - Prepare ML IE for tdls mgmt frame + * @mac_ctx: pointer to mac_context + * @session: pointer to pe_session + * + * Return: the actual ML IE length + */ +uint16_t lim_send_tdls_mgmt_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_get_frame_mlo_ie_len() - get ML IE length + * @session: pointer to pe_session + * + * Return: the actual ML IE length + */ +uint16_t lim_get_frame_mlo_ie_len(struct pe_session *session); + +/** + * lim_store_mlo_ie_raw_info() - store the ML IE raw info + * @ie: pointer the ML IE + * @sta_prof_ie: pointer to the first per STA prof + * @total_len: the length of ML IE + * @mlo_ie: the pointer to wlan_mlo_ie + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_store_mlo_ie_raw_info(uint8_t *ie, uint8_t *sta_prof_ie, + uint32_t total_len, + struct wlan_mlo_ie *mlo_ie); + +/** + * lim_is_ml_peer_state_disconn() - Check if ML peer state is + * ML_PEER_DISCONN_INITIATED + * @mac_ctx: pointer to mac_context + * @session: pointer to pe_session + * @mac_addr: peer mac address + * + * Return: True if state is ML_PEER_DISCONN_INITIATED, else False + */ +bool lim_is_ml_peer_state_disconn(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *mac_addr); + +bool lim_is_emlsr_band_supported(struct pe_session *session); + +/** + * lim_cu_info_from_rnr_per_link_id() - get the cu info from rnr per link id + * @rnr: rnr element + * @linkid: link id + * @bpcc: pointer to save BSS parameters change count + * @aui: pointer to save all updates included flag + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_cu_info_from_rnr_per_link_id(const uint8_t *rnr, + uint8_t linkid, uint8_t *bpcc, + uint8_t *aui); + +/** + * lim_get_bpcc_from_mlo_ie() - get the bpcc from mlo_ie info + * @bcn: the pointer to tSchBeaconStruct + * @bpcc: pbcc pointer to save the fetched value + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_get_bpcc_from_mlo_ie(tSchBeaconStruct *bcn, + uint8_t *bpcc); + +/** + * lim_check_cu_happens() - check whether cu happens + * @vdev: vdev object + * @new_bpcc: the new bpcc + * + * Return: bool + */ +bool lim_check_cu_happens(struct wlan_objmgr_vdev *vdev, uint8_t new_bpcc); +#else +static inline void lim_mlo_roam_peer_disconn_del(struct wlan_objmgr_vdev *vdev) +{ +} +static inline void lim_mlo_notify_peer_disconn(struct pe_session *pe_session, + tpDphHashNode sta_ds) +{ +} + +static inline void lim_mlo_sta_notify_peer_disconn( + struct pe_session *pe_session) +{ +} + +static inline void lim_mlo_set_mld_mac_peer( + tpDphHashNode sta_ds, + uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE]) +{ +} + +static inline void lim_mlo_cleanup_partner_peer(struct vdev_mlme_obj *vdev_mlme, + struct wlan_objmgr_peer *peer) +{ +} + +static inline bool lim_is_mlo_conn(struct pe_session *session, + tpDphHashNode sta_ds) +{ + return false; +} + +static inline bool lim_is_mlo_recv_assoc(tpDphHashNode sta_ds) +{ + return false; +} + +static inline void lim_set_mlo_recv_assoc(tpDphHashNode sta_ds, + bool mlo_recv_assoc_frm) +{ +} + +static inline bool lim_mlo_partner_auth_type(struct pe_session *session, + uint16_t partner_peer_idx, + tAniAuthType *auth_type) +{ + return false; +} + +static inline void lim_ap_mlo_sta_peer_ind(struct mac_context *mac, + struct pe_session *pe_session, + tpDphHashNode sta, + bool add_sta_rsp_status) +{ +} + +static inline void lim_mlo_delete_link_peer(struct pe_session *pe_session, + tpDphHashNode sta_ds) +{ +} + +static inline QDF_STATUS lim_mlo_assoc_ind_upper_layer( + struct mac_context *mac, + struct pe_session *pe_session, + struct mlo_partner_info *mlo_info) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void lim_mlo_save_mlo_info(tpDphHashNode sta_ds, + struct mlo_partner_info *mlo_info) +{ +} + +static inline +QDF_STATUS lim_add_frag_ie_for_sta_profile(uint8_t *data, uint16_t *len) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS lim_fill_complete_mlo_ie(struct pe_session *session, + uint16_t total_len, uint8_t *target) +{ + return QDF_STATUS_SUCCESS; +} + +static inline uint16_t +lim_fill_assoc_req_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocRequest *frm) +{ + return 0; +} + +static inline uint16_t +lim_send_assoc_rsp_mgmt_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session, + tpDphHashNode sta, + tDot11fAssocResponse *frm) +{ + return 0; +} + +static inline uint16_t +lim_send_probe_req_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session) +{ + return 0; +} + +static inline uint16_t +lim_send_bcn_frame_mlo(struct mac_context *mac_ctx, struct pe_session *session) +{ + return 0; +} + +static inline uint16_t +lim_send_tdls_mgmt_frame_mlo(struct mac_context *mac_ctx, + struct pe_session *session) +{ + return 0; +} + +static inline +uint16_t lim_get_frame_mlo_ie_len(struct pe_session *session) +{ + return 0; +} + +static inline +bool lim_is_ml_peer_state_disconn(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *mac_addr) +{ + return false; +} + +static inline +bool lim_is_emlsr_band_supported(struct pe_session *session) +{ + return false; +} + +static inline +QDF_STATUS lim_cu_info_from_rnr_per_link_id(const uint8_t *rnr, uint8_t linkid, + uint8_t *bpcc, uint8_t *aui) +{ + return QDF_STATUS_E_INVAL; +} + +static inline +QDF_STATUS lim_get_bpcc_from_mlo_ie(tSchBeaconStruct *bcn, + uint8_t *bpcc) +{ + return QDF_STATUS_E_INVAL; +} + +static inline +bool lim_check_cu_happens(struct wlan_objmgr_vdev *vdev, uint8_t nbpcc) +{ + return true; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c new file mode 100644 index 0000000000..2af13f58d0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_action_frame.c @@ -0,0 +1,2375 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_process_action_frame.cc contains the code + * for processing Action Frame. + * Author: Michael Lui + * Date: 05/23/03 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_admit_control.h" +#include "wmm_apsd.h" +#include "lim_send_messages.h" +#include "rrm_api.h" +#include "lim_session_utils.h" +#include "wlan_policy_mgr_api.h" +#include "wma_types.h" +#include "wma.h" +#include +#include +#include "dot11f.h" +#include "wlan_p2p_cfg_api.h" +#include "son_api.h" +#include "wlan_t2lm_api.h" +#include "wlan_epcs_api.h" +#include +#include "wlan_mlo_mgr_public_structs.h" +#include "wlan_p2p_api.h" +#include "wlan_tdls_api.h" + +#define SA_QUERY_REQ_MIN_LEN \ +(DOT11F_FF_CATEGORY_LEN + DOT11F_FF_ACTION_LEN + DOT11F_FF_TRANSACTIONID_LEN) +#define SA_QUERY_RESP_MIN_LEN \ +(DOT11F_FF_CATEGORY_LEN + DOT11F_FF_ACTION_LEN + DOT11F_FF_TRANSACTIONID_LEN) +#define SA_QUERY_IE_OFFSET (4) + +#define MIN_OCI_IE_LEN 6 +#define OCI_IE_OUI_SIZE 1 +#define OCI_IE_OP_CLS_OFFSET 3 +#define ELE_ID_EXT_LEN 1 + +static last_processed_msg rrm_link_action_frm; + +/**----------------------------------------------------------------- + \fn lim_stop_tx_and_switch_channel + \brief Stops the transmission if channel switch mode is silent and + starts the channel switch timer. + + \param mac + \return NONE + -----------------------------------------------------------------*/ +void lim_stop_tx_and_switch_channel(struct mac_context *mac, uint8_t sessionId) +{ + struct pe_session *pe_session; + QDF_STATUS status; + + pe_session = pe_find_session_by_session_id(mac, sessionId); + + if (!pe_session) { + pe_err("Session: %d not active", sessionId); + return; + } + + if (pe_session->ftPEContext.pFTPreAuthReq) { + pe_debug("Avoid Switch Channel req during pre auth"); + return; + } + + status = policy_mgr_check_and_set_hw_mode_for_channel_switch(mac->psoc, + pe_session->smeSessionId, + pe_session->gLimChannelSwitch.sw_target_freq, + POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA); + + /* + * If status is QDF_STATUS_E_FAILURE, mean HW mode change was required + * but driver failed to set HW mode so ignore CSA for the channel. + * If status is QDF_STATUS_SUCCESS mean HW mode change was required + * and was successfully changed so the channel switch will continue after + * HW mode change completion. + * If status is QDF_STATUS_E_NOSUPPORT or QDF_STATUS_E_ALREADY, mean + * DBS is not supported or required HW mode is already set, so + * So contunue with CSA from here. + */ + if (status == QDF_STATUS_E_FAILURE) { + pe_err("Failed to set required HW mode for channel %d freq %d, ignore CSA", + pe_session->gLimChannelSwitch.primaryChannel, + pe_session->gLimChannelSwitch.sw_target_freq); + return; + } + + if (QDF_IS_STATUS_SUCCESS(status)) { + pe_info("Channel change will continue after HW mode change"); + return; + } + + lim_process_channel_switch(mac, pe_session->smeSessionId); + + return; +} + +/** + * lim_process_ext_channel_switch_action_frame()- Process ECSA Action + * Frames. + * @mac_ctx: pointer to global mac structure + * @rx_packet_info: rx packet meta information + * @session_entry: Session entry. + * + * This function is called when ECSA action frame is received. + * + * Return: void + */ +static void +lim_process_ext_channel_switch_action_frame(struct mac_context *mac_ctx, + uint8_t *rx_packet_info, struct pe_session *session_entry) +{ + + tpSirMacMgmtHdr hdr; + uint8_t *body; + tDot11fext_channel_switch_action_frame *ext_channel_switch_frame; + uint32_t frame_len; + uint32_t status; + uint32_t target_freq; + + hdr = WMA_GET_RX_MAC_HEADER(rx_packet_info); + body = WMA_GET_RX_MPDU_DATA(rx_packet_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_packet_info); + + pe_debug("Received EXT Channel switch action frame"); + + ext_channel_switch_frame = + qdf_mem_malloc(sizeof(*ext_channel_switch_frame)); + if (!ext_channel_switch_frame) + return; + + /* Unpack channel switch frame */ + status = dot11f_unpack_ext_channel_switch_action_frame(mac_ctx, + body, frame_len, ext_channel_switch_frame, false); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse CHANSW action frame (0x%08x, len %d):", + status, frame_len); + qdf_mem_free(ext_channel_switch_frame); + return; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking CHANSW Request (0x%08x, %d bytes):", + status, frame_len); + } + + if (!wlan_reg_is_6ghz_supported(mac_ctx->psoc) && + (wlan_reg_is_6ghz_op_class(mac_ctx->pdev, + ext_channel_switch_frame-> + ext_chan_switch_ann_action.op_class))) { + pe_err("channel belongs to 6 ghz spectrum, abort"); + qdf_mem_free(ext_channel_switch_frame); + return; + } + + target_freq = + wlan_reg_chan_opclass_to_freq(ext_channel_switch_frame->ext_chan_switch_ann_action.new_channel, + ext_channel_switch_frame->ext_chan_switch_ann_action.op_class, + false); + + /* Free ext_channel_switch_frame here as its no longer needed */ + qdf_mem_free(ext_channel_switch_frame); + /* + * Now, validate if channel change is required for the passed + * channel and if is valid in the current regulatory domain, + * and no concurrent session is running. + */ + if (!(session_entry->curr_op_freq != target_freq && + ((wlan_reg_get_channel_state_for_pwrmode(mac_ctx->pdev, + target_freq, + REG_CURRENT_PWR_MODE) == CHANNEL_STATE_ENABLE) || + (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, target_freq) && + !policy_mgr_concurrent_open_sessions_running( + mac_ctx->psoc))))) { + pe_err("Channel freq: %d is not valid", target_freq); + return; + } + + if (session_entry->opmode == QDF_P2P_GO_MODE) { + + struct sir_sme_ext_cng_chan_ind *ext_cng_chan_ind; + struct scheduler_msg mmh_msg = {0}; + + ext_cng_chan_ind = qdf_mem_malloc(sizeof(*ext_cng_chan_ind)); + if (!ext_cng_chan_ind) + return; + + ext_cng_chan_ind->session_id = + session_entry->smeSessionId; + + /* No need to extract op mode as BW will be decided in + * in SAP FSM depending on previous BW. + */ + ext_cng_chan_ind->new_chan_freq = target_freq; + + mmh_msg.type = eWNI_SME_EXT_CHANGE_CHANNEL_IND; + mmh_msg.bodyptr = ext_cng_chan_ind; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac_ctx, &mmh_msg); + } + return; +} /*** end lim_process_ext_channel_switch_action_frame() ***/ + +/** + * __lim_process_operating_mode_action_frame() - To process op mode frames + * @mac_ctx: pointer to mac context + * @rx_pkt_info: pointer to received packet info + * @session: pointer to session + * + * This routine is called to process operating mode action frames + * + * Return: None + */ +static void __lim_process_operating_mode_action_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *session) +{ + + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fOperatingMode *operating_mode_frm; + uint32_t frame_len; + uint32_t status; + tpDphHashNode sta_ptr; + uint16_t aid; + enum phy_ch_width ch_bw = 0; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("Received Operating Mode action frame"); + + /* + * Ignore opmode change during channel change The opmode will be updated + * with the beacons on new channel once the AP move to new channel. + */ + if (session->ch_switch_in_progress) { + pe_debug("Ignore opmode change as channel switch is in progress"); + return; + } + operating_mode_frm = qdf_mem_malloc(sizeof(*operating_mode_frm)); + if (!operating_mode_frm) + return; + + /* Unpack channel switch frame */ + status = dot11f_unpack_operating_mode(mac_ctx, body_ptr, frame_len, + operating_mode_frm, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse (0x%08x, %d bytes)", + status, frame_len); + qdf_mem_free(operating_mode_frm); + return; + } else if (DOT11F_WARNED(status)) { + pe_warn("warnings while unpacking (0x%08x, %d bytes):", + status, frame_len); + } + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + + if (!sta_ptr) { + pe_err("Station context not found"); + goto end; + } + + lim_update_nss(mac_ctx, sta_ptr, + operating_mode_frm->OperatingMode.rxNSS, session); + + if (lim_update_channel_width(mac_ctx, sta_ptr, session, + operating_mode_frm->OperatingMode.chanWidth, + &ch_bw)) + wlan_son_deliver_opmode(session->vdev, + ch_bw, + sta_ptr->vhtSupportedRxNss, + mac_hdr->sa); + +end: + qdf_mem_free(operating_mode_frm); + return; +} + +/** + * __lim_process_gid_management_action_frame() - To process group-id mgmt frames + * @mac_ctx: Pointer to mac context + * @rx_pkt_info: Rx packet info + * @session: pointer to session + * + * This routine will be called to process group id management frames + * + * Return: none + */ +static void +__lim_process_gid_management_action_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, + struct pe_session *session) +{ + uint8_t *body_ptr; + uint16_t aid; + uint32_t frame_len, status, membership = 0, usr_position = 0; + uint32_t *mem_lower, *mem_upper, *mem_cur; + tpSirMacMgmtHdr mac_hdr; + tDot11fVHTGidManagementActionFrame *gid_mgmt_frame; + tpDphHashNode sta_ptr; + struct sDot11fFfVhtMembershipStatusArray *vht_member_status = NULL; + struct sDot11fFfVhtUserPositionArray *vht_user_position = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("Received GID Management action frame"); + gid_mgmt_frame = qdf_mem_malloc(sizeof(*gid_mgmt_frame)); + if (!gid_mgmt_frame) + return; + + /* Unpack Gid Management Action frame */ + status = dot11f_unpack_vht_gid_management_action_frame(mac_ctx, + body_ptr, frame_len, gid_mgmt_frame, false); + if (DOT11F_FAILED(status)) { + pe_err("Fail to parse an Grp id frame (0x%08x, %d bytes):", + status, frame_len); + qdf_mem_free(gid_mgmt_frame); + return; + } else if (DOT11F_WARNED(status)) { + pe_warn("warnings while unpacking Grp id frm (0x%08x, %d bytes):", + status, frame_len); + } + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (!sta_ptr) { + pe_err("Failed to get STA entry from hash table"); + goto out; + } + + pe_debug(" MAC: %0x:%0x:%0x:%0x:%0x:%0x", + mac_hdr->sa[0], mac_hdr->sa[1], mac_hdr->sa[2], + mac_hdr->sa[3], mac_hdr->sa[4], mac_hdr->sa[5]); + vht_member_status = &gid_mgmt_frame->VhtMembershipStatusArray; + mem_lower = (uint32_t *) vht_member_status->membershipStatusArray; + mem_upper = (uint32_t *) &vht_member_status->membershipStatusArray[4]; + + if (*mem_lower && *mem_upper) { + pe_err("rcved frame with mult group ID set"); + goto out; + } + if (*mem_lower) { + mem_cur = mem_lower; + } else if (*mem_upper) { + mem_cur = mem_upper; + membership += sizeof(uint32_t); + } else { + pe_err("rcved Gid frame with no group ID set"); + goto out; + } + while (!(*mem_cur & 1)) { + *mem_cur >>= 1; + ++membership; + } + if (*mem_cur) { + pe_err("rcved frame with mult group ID set"); + goto out; + } + + /*Just read the last two bits */ + vht_user_position = &gid_mgmt_frame->VhtUserPositionArray; + usr_position = vht_user_position->userPositionArray[membership] & 0x3; + lim_check_membership_user_position(mac_ctx, session, membership, + usr_position); +out: + qdf_mem_free(gid_mgmt_frame); + return; +} + +static void +__lim_process_add_ts_req(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ +} + +/** + * lim_is_medium_time_valid() - To check whether AP sends ADD TS response for + * an AC with zero medium time and ACM is enabled + * @mac_ctx: Pointer to mac context + * @pe_session: pointer to session + * @addts: Add TS resp buffer + * + * Return: false if ADD TS response frame for an AC has 0 as medium time. + */ +static bool +lim_is_medium_time_valid(struct mac_context *mac, struct pe_session *pe_session, + tSirAddtsRspInfo addts) +{ + struct mac_ts_info *ts_info = &addts.tspec.tsinfo; + uint16_t user_priority = ts_info->traffic.userPrio; + uint8_t ac = upToAc(user_priority); + bool is_acm = false; + + if (pe_session->wmm_params.present) { + switch (ac) { + case QCA_WLAN_AC_BE: + if (pe_session->wmm_params.acbe_acm) + is_acm = true; + break; + case QCA_WLAN_AC_BK: + if (pe_session->wmm_params.acbk_acm) + is_acm = true; + break; + case QCA_WLAN_AC_VI: + if (pe_session->wmm_params.acvi_acm) + is_acm = true; + break; + case QCA_WLAN_AC_VO: + if (pe_session->wmm_params.acvo_acm) + is_acm = true; + break; + default: + pe_debug("Unknown AC:%d", ac); + break; + } + } + /* + * If AP sends ADD TS response for an AC with medium time as 0 + * and acm disabled treat it as ADD TS failure. + */ + if (!addts.tspec.mediumTime && is_acm) { + pe_debug("medium time 0 and ACM is mandatory. ADDTS failed"); + return false; + } + + return true; +} + +/** + * __lim_process_add_ts_rsp() - To process add ts response frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: Received packet info + * @session: pointer to session + * + * This routine is to handle add ts response frame + * + * Return: none + */ +static void __lim_process_add_ts_rsp(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *session) +{ + tSirAddtsRspInfo addts; + QDF_STATUS retval; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint16_t aid; + uint32_t frameLen; + uint8_t *body_ptr; + tpLimTspecInfo tspec_info; + uint8_t ac; + tpDphHashNode sta_ds_ptr = NULL; + uint8_t rsp_reqd = 1; + uint32_t cfg_len; + tSirMacAddr peer_macaddr; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frameLen = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_warn("Recv AddTs Response"); + if (LIM_IS_AP_ROLE(session)) { + pe_warn("AddTsRsp recvd at AP: ignoring"); + return; + } + + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (!sta_ptr) { + pe_err("Station context not found - ignoring AddTsRsp"); + return; + } + + retval = sir_convert_addts_rsp2_struct(mac_ctx, body_ptr, + frameLen, &addts); + if (retval != QDF_STATUS_SUCCESS) { + pe_err("AddTsRsp parsing failed %d", retval); + return; + } + /* + * don't have to check for qos/wme capabilities since we wouldn't have + * this flag set otherwise + */ + if (!mac_ctx->lim.gLimAddtsSent) { + /* we never sent an addts request! */ + pe_warn("rx AddTsRsp but no req was ever sent-ignoring"); + return; + } + + if (mac_ctx->lim.gLimAddtsReq.req.dialogToken != addts.dialogToken) { + pe_warn("token mismatch got: %d exp: %d - ignoring", + addts.dialogToken, + mac_ctx->lim.gLimAddtsReq.req.dialogToken); + return; + } + + /* + * for successful addts response, try to add the classifier. + * if this fails for any reason, we should send a delts request to the + * ap for now, its ok not to send a delts since we are going to add + * support for multiple tclas soon and until then we won't send any + * addts requests with multiple tclas elements anyway. + * In case of addClassifier failure, we just let the addts timer run out + */ + if (((addts.tspec.tsinfo.traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_HCCA) || + (addts.tspec.tsinfo.traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH)) && + (addts.status == STATUS_SUCCESS)) { + /* add the classifier - this should always succeed */ + if (addts.numTclas > 1) { + /* currently no support for multiple tclas elements */ + pe_err("Sta: %d Too many Tclas: %d 1 supported", + aid, addts.numTclas); + return; + } else if (addts.numTclas == 1) { + pe_debug("Response from STA: %d tsid: %d UP: %d OK!", + aid, addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio); + } + } + + pe_debug("Recv AddTsRsp: tsid: %d UP: %d status: %d", + addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio, addts.status); + + /* + * Change the status to failure and fallthrough to send response + * to SME to cleanup the flow. + */ + if (addts.tspec.tsinfo.traffic.direction != SIR_MAC_DIRECTION_DNLINK && + !lim_is_medium_time_valid(mac_ctx, session, addts)) + addts.status = STATUS_UNSPECIFIED_FAILURE; + + /* deactivate the response timer */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ADDTS_RSP_TIMER); + + if (addts.status != STATUS_SUCCESS) { + pe_debug("Recv AddTsRsp: tsid: %d UP: %d status: %d", + addts.tspec.tsinfo.traffic.tsid, + addts.tspec.tsinfo.traffic.userPrio, addts.status); + lim_send_sme_addts_rsp(mac_ctx, true, addts.status, session, + addts.tspec, session->smeSessionId); + + /* clear the addts flag */ + mac_ctx->lim.gLimAddtsSent = false; + + return; + } +#ifdef FEATURE_WLAN_ESE + if (addts.tsmPresent) { + pe_debug("TSM IE Present"); + session->eseContext.tsm.tid = + addts.tspec.tsinfo.traffic.userPrio; + qdf_mem_copy(&session->eseContext.tsm.tsmInfo, + &addts.tsmIE, sizeof(struct ese_tsm_ie)); + lim_send_sme_tsm_ie_ind(mac_ctx, session, addts.tsmIE.tsid, + addts.tsmIE.state, + addts.tsmIE.msmt_interval); + } +#endif + /* + * Since AddTS response was successful, check for the PSB flag + * and directional flag inside the TS Info field. + * An AC is trigger enabled AC if the PSB subfield is set to 1 + * in the uplink direction. + * An AC is delivery enabled AC if the PSB subfield is set to 1 + * in the downlink direction. + * An AC is trigger and delivery enabled AC if the PSB subfield + * is set to 1 in the bi-direction field. + */ + if (addts.tspec.tsinfo.traffic.psb == 1) + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + &addts.tspec.tsinfo, + SET_UAPSD_MASK); + else + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + &addts.tspec.tsinfo, + CLEAR_UAPSD_MASK); + + /* + * ADDTS success, so AC is now admitted. We shall now use the default + * EDCA parameters as advertised by AP and send the updated EDCA params + * to HAL. + */ + ac = upToAc(addts.tspec.tsinfo.traffic.userPrio); + if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_UPLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (addts.tspec.tsinfo.traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + lim_set_active_edca_params(mac_ctx, session->gLimEdcaParams, + session); + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds_ptr) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + session->vdev_id, false); + else + pe_err("Self entry missing in Hash Table"); + sir_copy_mac_addr(peer_macaddr, session->bssId); + /* if schedule is not present then add TSPEC with svcInterval as 0. */ + if (!addts.schedulePresent) + addts.schedule.svcInterval = 0; + if (QDF_STATUS_SUCCESS != + lim_tspec_add(mac_ctx, sta_ptr->staAddr, sta_ptr->assocId, + &addts.tspec, addts.schedule.svcInterval, &tspec_info)) { + pe_err("Adding entry in lim Tspec Table failed"); + lim_send_delts_req_action_frame(mac_ctx, peer_macaddr, rsp_reqd, + &addts.tspec.tsinfo, + &addts.tspec, session); + mac_ctx->lim.gLimAddtsSent = false; + return; + /* + * Error handling. send the response with error status. + * need to send DelTS to tear down the TSPEC status. + */ + } + if ((addts.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA) || + ((upToAc(addts.tspec.tsinfo.traffic.userPrio) < QCA_WLAN_AC_ALL))) { +#ifdef FEATURE_WLAN_ESE + retval = lim_send_hal_msg_add_ts(mac_ctx, + tspec_info->idx, + addts.tspec, session->peSessionId, + addts.tsmIE.msmt_interval); +#else + retval = lim_send_hal_msg_add_ts(mac_ctx, + tspec_info->idx, + addts.tspec, session->peSessionId); +#endif + if (QDF_STATUS_SUCCESS != retval) { + lim_admit_control_delete_ts(mac_ctx, sta_ptr->assocId, + &addts.tspec.tsinfo, NULL, &tspec_info->idx); + + /* Send DELTS action frame to AP */ + cfg_len = sizeof(tSirMacAddr); + lim_send_delts_req_action_frame(mac_ctx, peer_macaddr, + rsp_reqd, &addts.tspec.tsinfo, + &addts.tspec, session); + lim_send_sme_addts_rsp(mac_ctx, true, retval, + session, addts.tspec, + session->smeSessionId); + mac_ctx->lim.gLimAddtsSent = false; + return; + } + pe_debug("AddTsRsp received successfully UP: %d TSID: %d", + addts.tspec.tsinfo.traffic.userPrio, + addts.tspec.tsinfo.traffic.tsid); + } else { + pe_debug("AddTsRsp received successfully UP: %d TSID: %d", + addts.tspec.tsinfo.traffic.userPrio, + addts.tspec.tsinfo.traffic.tsid); + pe_debug("no ACM: Bypass sending WMA_ADD_TS_REQ to HAL"); + lim_send_sme_addts_rsp(mac_ctx, true, eSIR_SME_SUCCESS, + session, addts.tspec, + session->smeSessionId); + } + /* clear the addts flag */ + mac_ctx->lim.gLimAddtsSent = false; + return; +} + +/** + * __lim_process_del_ts_req() - To process del ts response frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: Received packet info + * @session: pointer to session + * + * This routine is to handle del ts request frame + * + * Return: none + */ +static void __lim_process_del_ts_req(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *session) +{ + QDF_STATUS retval; + struct delts_req_info delts; + tpSirMacMgmtHdr mac_hdr; + tpDphHashNode sta_ptr; + uint32_t frame_len; + uint16_t aid; + uint8_t *body_ptr; + uint8_t ts_status; + struct mac_ts_info *tsinfo; + uint8_t tspec_idx; + uint8_t ac; + tpDphHashNode sta_ds_ptr = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + sta_ptr = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + if (!sta_ptr) { + pe_err("Station context not found - ignoring DelTs"); + return; + } + /* parse the delts request */ + retval = sir_convert_delts_req2_struct(mac_ctx, body_ptr, + frame_len, &delts); + if (retval != QDF_STATUS_SUCCESS) { + pe_err("DelTs parsing failed %d", retval); + return; + } + + if (delts.wmeTspecPresent) { + if ((!session->limWmeEnabled) || (!sta_ptr->wmeEnabled)) { + pe_warn("Ignore delts req: wme not enabled"); + return; + } + pe_debug("WME Delts received"); + } else if ((session->limQosEnabled) && sta_ptr->lleEnabled) { + pe_debug("11e QoS Delts received"); + } else if ((session->limWsmEnabled) && sta_ptr->wsmEnabled) { + pe_debug("WSM Delts received"); + } else { + pe_warn("Ignoring delts request: qos not enabled/capable"); + return; + } + + tsinfo = delts.wmeTspecPresent ? &delts.tspec.tsinfo : &delts.tsinfo; + + /* if no Admit Control, ignore the request */ + if (tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + if (upToAc(tsinfo->traffic.userPrio) >= QCA_WLAN_AC_ALL) { + pe_warn("DelTs with UP: %d has no AC - ignoring req", + tsinfo->traffic.userPrio); + return; + } + } + + if (!LIM_IS_AP_ROLE(session)) + lim_send_sme_delts_ind(mac_ctx, &delts, aid, session); + + /* try to delete the TS */ + if (QDF_STATUS_SUCCESS != + lim_admit_control_delete_ts(mac_ctx, sta_ptr->assocId, tsinfo, + &ts_status, &tspec_idx)) { + pe_warn("Unable to Delete TS"); + return; + } else if (!((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) + || (tsinfo->traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH))){ + /* send message to HAL to delete TS */ + if (QDF_STATUS_SUCCESS != lim_send_hal_msg_del_ts(mac_ctx, + tspec_idx, + delts, session->peSessionId, + session->bssId)) { + pe_warn("DelTs with UP: %d failed ignoring request", + tsinfo->traffic.userPrio); + return; + } + } + /* + * We successfully deleted the TSPEC. Update the dynamic UAPSD Mask. + * The AC for this TSPEC is no longer trigger enabled if this Tspec + * was set-up in uplink direction only. + * The AC for this TSPEC is no longer delivery enabled if this Tspec + * was set-up in downlink direction only. + * The AC for this TSPEC is no longer triiger enabled and delivery + * enabled if this Tspec was a bidirectional TSPEC. + */ + lim_set_tspec_uapsd_mask_per_session(mac_ctx, session, + tsinfo, CLEAR_UAPSD_MASK); + /* + * We're deleting the TSPEC. + * The AC for this TSPEC is no longer admitted in uplink/downlink + * direction if this TSPEC was set-up in uplink/downlink direction only. + * The AC for this TSPEC is no longer admitted in both uplink and + * downlink directions if this TSPEC was a bi-directional TSPEC. + * If ACM is set for this AC and this AC is admitted only in downlink + * direction, PE needs to downgrade the EDCA parameter + * (for the AC for which TS is being deleted) to the + * next best AC for which ACM is not enabled, and send the + * updated values to HAL. + */ + ac = upToAc(tsinfo->traffic.userPrio); + if (tsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (tsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (tsinfo->traffic.direction == SIR_MAC_DIRECTION_BIDIR) { + session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + lim_set_active_edca_params(mac_ctx, session->gLimEdcaParams, + session); + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds_ptr) + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + session->vdev_id, false); + else + pe_err("Self entry missing in Hash Table"); + + pe_debug("DeleteTS succeeded"); +#ifdef FEATURE_WLAN_ESE + lim_send_sme_tsm_ie_ind(mac_ctx, session, 0, 0, 0); +#endif +} + +/** + * __lim_process_qos_map_configure_frame() - to process QoS map configure frame + * @mac_ctx: pointer to mac context + * @rx_pkt_info: pointer to received packet info + * @session: pointer to session + * + * This routine will called to process qos map configure frame + * + * Return: none + */ +static void __lim_process_qos_map_configure_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *session) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + QDF_STATUS retval; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + retval = sir_convert_qos_map_configure_frame2_struct(mac_ctx, + body_ptr, frame_len, &session->QosMapSet); + if (retval != QDF_STATUS_SUCCESS) { + pe_err("QosMapConfigure frame parsing fail %d", retval); + return; + } + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), 0, + WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + RXMGMT_FLAG_NONE); +} + +#ifdef ANI_SUPPORT_11H +static void +__lim_process_basic_meas_req(struct mac_context *mac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, struct pe_session *pe_session) +{ + if (lim_send_meas_report_frame(mac, pMeasReqFrame, + peerMacAddr, pe_session) != + QDF_STATUS_SUCCESS) { + pe_err("fail to send Basic Meas report"); + return; + } +} +static void +__lim_process_cca_meas_req(struct mac_context *mac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, struct pe_session *pe_session) +{ + if (lim_send_meas_report_frame(mac, pMeasReqFrame, + peerMacAddr, pe_session) != + QDF_STATUS_SUCCESS) { + pe_err("fail to send CCA Meas report"); + return; + } +} +static void +__lim_process_rpi_meas_req(struct mac_context *mac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peerMacAddr, struct pe_session *pe_session) +{ + if (lim_send_meas_report_frame(mac, pMeasReqFrame, + peerMacAddr, pe_session) != + QDF_STATUS_SUCCESS) { + pe_err("fail to send RPI Meas report"); + return; + } +} +static void +__lim_process_measurement_request_frame(struct mac_context *mac, + uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + tpSirMacMeasReqActionFrame pMeasReqFrame; + uint32_t frameLen; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pMeasReqFrame = qdf_mem_malloc(sizeof(tSirMacMeasReqActionFrame)); + if (!pMeasReqFrame) + return; + + if (sir_convert_meas_req_frame2_struct(mac, pBody, pMeasReqFrame, frameLen) + != QDF_STATUS_SUCCESS) { + pe_warn("Rcv invalid Measurement Request Action Frame"); + return; + } + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + __lim_process_basic_meas_req(mac, pMeasReqFrame, pHdr->sa, + pe_session); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + __lim_process_cca_meas_req(mac, pMeasReqFrame, pHdr->sa, + pe_session); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + __lim_process_rpi_meas_req(mac, pMeasReqFrame, pHdr->sa, + pe_session); + break; + default: + pe_warn("Unknown Measurement Type: %d", + pMeasReqFrame->measReqIE.measType); + break; + } +} /*** end limProcessMeasurementRequestFrame ***/ +static void +__lim_process_tpc_request_frame(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr pHdr; + uint8_t *pBody; + tpSirMacTpcReqActionFrame pTpcReqFrame; + uint32_t frameLen; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + pe_debug("****LIM: Processing TPC Request from peer ****"); + + pTpcReqFrame = qdf_mem_malloc(sizeof(tSirMacTpcReqActionFrame)); + if (!pTpcReqFrame) + return; + + if (sir_convert_tpc_req_frame2_struct(mac, pBody, pTpcReqFrame, frameLen) != + QDF_STATUS_SUCCESS) { + pe_warn("Rcv invalid TPC Req Action Frame"); + return; + } + if (lim_send_tpc_report_frame(mac, + pTpcReqFrame, + pHdr->sa, pe_session) != QDF_STATUS_SUCCESS) { + pe_err("fail to send TPC Report Frame"); + return; + } +} +#endif + +static void +__lim_process_sm_power_save_update(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + + tpSirMacMgmtHdr pHdr; + tDot11fSMPowerSave frmSMPower; + tSirMacHTMIMOPowerSaveState state; + tpDphHashNode pSta; + uint16_t aid; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pSta = + dph_lookup_hash_entry(mac, pHdr->sa, &aid, + &pe_session->dph.dphHashTable); + if (!pSta) { + pe_err("STA context not found - ignoring UpdateSM PSave Mode from SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pHdr->sa)); + return; + } + + /**Unpack the received frame */ + nStatus = dot11f_unpack_sm_power_save(mac, pBody, frameLen, + &frmSMPower, false); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to unpack and parse a Update SM Power (0x%08x, %d bytes):", + nStatus, frameLen); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pBody, frameLen); + return; + } else if (DOT11F_WARNED(nStatus)) { + pe_debug("There were warnings while unpacking a SMPower Save update (0x%08x, %d bytes):", + nStatus, frameLen); + } + + pe_debug("Received SM Power save Mode update Frame with PS_Enable: %d" + "PS Mode: %d", frmSMPower.SMPowerModeSet.PowerSave_En, + frmSMPower.SMPowerModeSet.Mode); + + /** Update in the DPH Table about the Update in the SM Power Save mode*/ + if (frmSMPower.SMPowerModeSet.PowerSave_En + && frmSMPower.SMPowerModeSet.Mode) + state = eSIR_HT_MIMO_PS_DYNAMIC; + else if ((frmSMPower.SMPowerModeSet.PowerSave_En) + && (frmSMPower.SMPowerModeSet.Mode == 0)) + state = eSIR_HT_MIMO_PS_STATIC; + else if ((frmSMPower.SMPowerModeSet.PowerSave_En == 0) + && (frmSMPower.SMPowerModeSet.Mode == 0)) + state = eSIR_HT_MIMO_PS_NO_LIMIT; + else { + pe_warn("Received SM Power save Mode update Frame with invalid mode"); + return; + } + + if (state == pSta->htMIMOPSState) { + pe_err("The PEER is already set in the same mode"); + return; + } + + /** Update in the HAL Station Table for the Update of the Protection Mode */ + pSta->htMIMOPSState = state; + lim_post_sm_state_update(mac, pSta->htMIMOPSState, + pSta->staAddr, pe_session->smeSessionId); + wlan_son_deliver_smps(pe_session->vdev, + (eSIR_HT_MIMO_PS_STATIC == state) ? 1 : 0, + pSta->staAddr); +} + + +static void +__lim_process_radio_measure_request(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr pHdr; + tDot11fRadioMeasurementRequest *frm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + uint16_t curr_seq_num; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (!pe_session) { + return; + } + + curr_seq_num = ((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo); + if (curr_seq_num == mac->rrm.rrmPEContext.prev_rrm_report_seq_num && + (mac->rrm.rrmPEContext.pCurrentReq[DEFAULT_RRM_IDX] || + mac->rrm.rrmPEContext.pCurrentReq[DEFAULT_RRM_IDX + 1])) { + pe_err("rrm report req frame, seq num: %d is already in progress, drop it", + curr_seq_num); + return; + } + /* Save seq no of currently processing rrm report req frame */ + mac->rrm.rrmPEContext.prev_rrm_report_seq_num = curr_seq_num; + + frm = qdf_mem_malloc(sizeof(*frm)); + if (!frm) + return; + + /**Unpack the received frame */ + nStatus = dot11f_unpack_radio_measurement_request(mac, pBody, + frameLen, frm, false); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to unpack and parse a Radio Measure request (0x%08x, %d bytes):", + nStatus, frameLen); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pBody, frameLen); + goto err; + } else if (DOT11F_WARNED(nStatus)) { + pe_debug("Warnings while unpacking a Radio Measure request (0x%08x, %d bytes):", + nStatus, frameLen); + } + /* Call rrm function to handle the request. */ + + pe_debug("vdev: %d Received rrm req from sa addr:"QDF_MAC_ADDR_FMT" bssId:"QDF_MAC_ADDR_FMT" session addr:"QDF_MAC_ADDR_FMT" session self addr:"QDF_MAC_ADDR_FMT"", + pe_session->vdev_id, + QDF_MAC_ADDR_REF(pHdr->sa), + QDF_MAC_ADDR_REF(pHdr->bssId), + QDF_MAC_ADDR_REF(pe_session->bssId), + QDF_MAC_ADDR_REF(pe_session->self_mac_addr)); + + pe_debug("RX RRM - type %hu, sub type %hu, seq num[%d]", + pHdr->fc.type, pHdr->fc.subType, curr_seq_num); + + rrm_process_radio_measurement_request(mac, pe_session->bssId, frm, + pe_session); +err: + qdf_mem_free(frm); +} + +static QDF_STATUS +__lim_process_link_measurement_req(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr pHdr; + tDot11fLinkMeasurementRequest frm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (!pe_session) { + return QDF_STATUS_E_FAILURE; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_link_measurement_request(mac, pBody, frameLen, + &frm, false); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to unpack and parse a Link Measure request (0x%08x, %d bytes):", + nStatus, frameLen); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pBody, frameLen); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(nStatus)) { + pe_debug("There were warnings while unpacking a Link Measure request (0x%08x, %d bytes):", + nStatus, frameLen); + } + + if (pe_session->sta_follows_sap_power) { + pe_debug("STA power has changed, reject the link measurement request"); + return QDF_STATUS_E_FAILURE; + } + /* Call rrm function to handle the request. */ + return rrm_process_link_measurement_request(mac, pRxPacketInfo, &frm, + pe_session); + +} + +static void +__lim_process_neighbor_report(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr pHdr; + tDot11fNeighborReportResponse *pFrm; + uint32_t frameLen, nStatus; + uint8_t *pBody; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + pFrm = qdf_mem_malloc(sizeof(tDot11fNeighborReportResponse)); + if (!pFrm) + return; + + if (!pe_session) { + qdf_mem_free(pFrm); + return; + } + + /**Unpack the received frame */ + nStatus = + dot11f_unpack_neighbor_report_response(mac, pBody, + frameLen, pFrm, false); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to unpack and parse a Neighbor report response (0x%08x, %d bytes):", + nStatus, frameLen); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pBody, frameLen); + qdf_mem_free(pFrm); + return; + } else if (DOT11F_WARNED(nStatus)) { + pe_debug("There were warnings while unpacking a Neighbor report response (0x%08x, %d bytes):", + nStatus, frameLen); + } + + /* Call rrm function to handle the request. */ + rrm_process_neighbor_report_response(mac, pFrm, pe_session); + + qdf_mem_free(pFrm); +} + +static bool +lim_check_oci_match(struct mac_context *mac, struct pe_session *pe_session, + uint8_t *ie, uint8_t *peer, uint32_t ie_len) +{ + const uint8_t *oci_ie, ext_id_param = WLAN_EXTN_ELEMID_OCI; + tDot11fIEoci self_oci, peer_oci = {0}; + uint16_t peer_chan_width; + uint16_t local_peer_chan_width = 0; + uint8_t country_code[CDS_COUNTRY_CODE_LEN + 1]; + uint32_t status = DOT11F_PARSE_SUCCESS; + + if (!lim_is_self_and_peer_ocv_capable(mac, peer, pe_session)) + return true; + + if (ie_len < MIN_OCI_IE_LEN) + return false; + + oci_ie = wlan_get_ext_ie_ptr_from_ext_id(&ext_id_param, + OCI_IE_OUI_SIZE, + ie, ie_len); + if (!oci_ie) { + pe_err("OCV not found OCI in SA Query frame!"); + return false; + } + + /* OCV enabled, check the OCI information: + * Element ID : 1 byte + * Packet length : 1 byte + * Element ID extension : 1 byte + * Operating class : 1 byte + * Primary channel : 1 byte + * Freq_seg_1_ch_num : 1 byte + */ + status = dot11f_unpack_ie_oci(mac, + (uint8_t *)&oci_ie[OCI_IE_OP_CLS_OFFSET], + oci_ie[SIR_MAC_IE_LEN_OFFSET] - + ELE_ID_EXT_LEN, + &peer_oci, false); + if (!DOT11F_SUCCEEDED(status) || !peer_oci.present) + return false; + + wlan_reg_read_current_country(mac->psoc, country_code); + peer_chan_width = + wlan_reg_dmn_get_chanwidth_from_opclass_auto( + country_code, + peer_oci.prim_ch_num, + peer_oci.op_class); + + lim_fill_oci_params(mac, pe_session, &self_oci, peer, + &local_peer_chan_width); + if ((self_oci.op_class != peer_oci.op_class && + local_peer_chan_width > peer_chan_width) || + self_oci.prim_ch_num != peer_oci.prim_ch_num || + self_oci.freq_seg_1_ch_num != peer_oci.freq_seg_1_ch_num) { + pe_err("OCI mismatch,self %d %d %d %d, peer %d %d %d %d", + self_oci.op_class, + self_oci.prim_ch_num, + self_oci.freq_seg_1_ch_num, + local_peer_chan_width, + peer_oci.op_class, + peer_oci.prim_ch_num, + peer_oci.freq_seg_1_ch_num, + peer_chan_width); + return false; + } + + return true; +} + +/** + * limProcessSAQueryRequestActionFrame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query request Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param pe_session - PE session entry + * + * @return None + */ +static void __lim_process_sa_query_request_action_frame(struct mac_context *mac, + uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr mac_header; + uint8_t *p_body; + uint32_t frame_len; + uint8_t transId[2]; + tpDphHashNode sta_ds; + uint16_t aid; + + /* Prima --- Below Macro not available in prima + pHdr = SIR_MAC_BD_TO_MPDUHEADER(pBd); + pBody = SIR_MAC_BD_TO_MPDUDATA(pBd); */ + + mac_header = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + p_body = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frame_len = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + if (frame_len < SA_QUERY_REQ_MIN_LEN) { + pe_err("Invalid frame length %d", frame_len); + return; + } + /* If this is an unprotected SA Query Request, then ignore it. */ + if (mac_header->fc.wep == 0) + return; + + /* 11w offload is enabled then firmware should not fwd this frame */ + if (LIM_IS_STA_ROLE(pe_session) && mac->pmf_offload) { + pe_err("11w offload enabled, SA Query req isn't expected"); + return; + } + + /*Extract 11w trsansId from SA query request action frame + In SA query response action frame we will send same transId + In SA query request action frame: + Category : 1 byte + Action : 1 byte + Transaction ID : 2 bytes */ + qdf_mem_copy(&transId[0], &p_body[2], 2); + + sta_ds = dph_lookup_hash_entry(mac, mac_header->sa, &aid, + &pe_session->dph.dphHashTable); + + if (!lim_check_oci_match(mac, pe_session, + p_body + SA_QUERY_IE_OFFSET, + mac_header->sa, + frame_len - SA_QUERY_IE_OFFSET)) { + /* + * In case of channel switch, last ocv frequency will be + * different from current frquency. + * If there is channel switch and OCI is invalid in sa_query, + * deauth STA on new channel. + */ + if (sta_ds && sta_ds->ocv_enabled && + sta_ds->last_ocv_done_freq != pe_session->curr_op_freq) + lim_send_deauth_mgmt_frame(mac, REASON_OCI_MISMATCH, + mac_header->sa, pe_session, + false); + return; + } + + /* + * Update the last ocv done freq when OCI is valid. + * To support above algo, if it is moved to the current freq. + */ + if (sta_ds && sta_ds->ocv_enabled) + sta_ds->last_ocv_done_freq = pe_session->curr_op_freq; + + /* Send 11w SA query response action frame */ + if (lim_send_sa_query_response_frame(mac, + transId, + mac_header->sa, + pe_session) != QDF_STATUS_SUCCESS) { + pe_err("fail to send SA query response action frame"); + return; + } +} + +/** + * __lim_process_sa_query_response_action_frame + * + ***FUNCTION: + * This function is called by lim_process_action_frame() upon + * SA query response Action frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param *pRxPacketInfo - Handle to the Rx packet info + * @param pe_session - PE session entry + * @return None + */ +static void __lim_process_sa_query_response_action_frame(struct mac_context *mac, + uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr m_hdr; + uint32_t frame_len; + uint8_t *p_body; + tpDphHashNode pSta; + uint16_t aid; + uint16_t transId; + uint8_t retryNum; + + m_hdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + frame_len = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + p_body = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + pe_debug("SA Query Response received"); + + if (frame_len < SA_QUERY_RESP_MIN_LEN) { + pe_err("Invalid frame length %d", frame_len); + return; + } + /* When a station, supplicant handles SA Query Response. + * Forward to SME to HDD to wpa_supplicant. + */ + if (LIM_IS_STA_ROLE(pe_session)) { + lim_send_sme_mgmt_frame_ind(mac, m_hdr->fc.subType, + (uint8_t *)m_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + 0, + WMA_GET_RX_FREQ(pRxPacketInfo), + WMA_GET_RX_RSSI_NORMALIZED( + pRxPacketInfo), RXMGMT_FLAG_NONE); + return; + } + + /* If this is an unprotected SA Query Response, then ignore it. */ + if (m_hdr->fc.wep == 0) + return; + + pSta = + dph_lookup_hash_entry(mac, m_hdr->sa, &aid, + &pe_session->dph.dphHashTable); + if (!pSta) + return; + + pe_debug("SA Query Response source addr: %0x:%0x:%0x:%0x:%0x:%0x", + m_hdr->sa[0], m_hdr->sa[1], m_hdr->sa[2], m_hdr->sa[3], + m_hdr->sa[4], m_hdr->sa[5]); + pe_debug("SA Query state for station: %d", pSta->pmfSaQueryState); + + if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState) + return; + + /* Extract 11w trsansId from SA query response action frame + In SA query response action frame: + Category : 1 byte + Action : 1 byte + Transaction ID : 2 bytes */ + qdf_mem_copy(&transId, &p_body[2], 2); + + /* If SA Query is in progress with the station and the station + responds then the association request that triggered the SA + query is from a rogue station, just go back to initial state. */ + for (retryNum = 0; retryNum <= pSta->pmfSaQueryRetryCount; retryNum++) + if (transId == pSta->pmfSaQueryStartTransId + retryNum) { + if (!lim_check_oci_match(mac, pe_session, + p_body + SA_QUERY_IE_OFFSET, + m_hdr->sa, + frame_len - + SA_QUERY_IE_OFFSET)) + return; + pe_debug("Found matching SA Query Request - transaction ID: %d", + transId); + tx_timer_deactivate(&pSta->pmfSaQueryTimer); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + break; + } +} + +/** + * lim_drop_unprotected_action_frame + * + ***FUNCTION: + * This function checks if an Action frame should be dropped since it is + * a Robust Management Frame, it is unprotected, and it is received on a + * connection where PMF is enabled. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Global MAC structure + * @param pe_session - PE session entry + * @param pHdr - Frame header + * @param category - Action frame category + * @return true if frame should be dropped + */ + +static bool +lim_drop_unprotected_action_frame(struct mac_context *mac, struct pe_session *pe_session, + tpSirMacMgmtHdr pHdr, uint8_t category) +{ + uint16_t aid; + tpDphHashNode sta; + bool rmfConnection = false; + + sta = dph_lookup_hash_entry(mac, pHdr->sa, &aid, + &pe_session->dph.dphHashTable); + if (sta && sta->rmfEnabled) + rmfConnection = true; + + if (rmfConnection && (pHdr->fc.wep == 0)) { + pe_err("Dropping unprotected Action category: %d frame since RMF is enabled", + category); + return true; + } + + return false; +} + +/** + * lim_process_addba_req() - process ADDBA Request + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * @session: PE session pointer + * + * This routine will be called to process ADDBA request action frame + * + * Return: None + */ +static void lim_process_addba_req(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + struct pe_session *session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11faddba_req *addba_req; + uint32_t frame_len, status; + QDF_STATUS qdf_status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + tpDphHashNode sta_ds; + uint16_t aid, buff_size; + bool he_cap = false; + bool eht_cap = false; + uint8_t extd_buff_size = 0; + + if (mlo_is_any_link_disconnecting(session->vdev)) { + pe_err("Ignore ADDBA, vdev:%d is in not in conncted state", + wlan_vdev_get_id(session->vdev)); + return; + } + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + QDF_TRACE_HEX_DUMP_DEBUG_RL(QDF_MODULE_ID_PE, body_ptr, frame_len); + + addba_req = qdf_mem_malloc(sizeof(*addba_req)); + if (!addba_req) + return; + + /* Unpack ADDBA request frame */ + status = dot11f_unpack_addba_req(mac_ctx, body_ptr, frame_len, + addba_req, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse (0x%08x, %d bytes)", + status, frame_len); + goto error; + } else if (DOT11F_WARNED(status)) { + pe_warn("warning: unpack addba Req(0x%08x, %d bytes)", + status, frame_len); + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, mac_hdr->sa, &aid, + &session->dph.dphHashTable); + /* + * TDLS peer addba request for some TID could be received before + * TDLS_CHANGE_STA is received from userspace in some scenario + * for example when the DUT sends TDLS setup response directly + * to an already discovered peer and peer sends the addba request + * immediately for TID 0. + */ + if (sta_ds && sta_ds->staType == STA_ENTRY_TDLS_PEER && + !wlan_tdls_is_addba_request_allowed(session->vdev, + (struct qdf_mac_addr *)sta_ds->staAddr)) { + pe_err("vdev:%d Dropping TDLS peer addba req received before change_sta", + wlan_vdev_get_id(session->vdev)); + goto error; + } + + if (sta_ds && + (lim_is_session_he_capable(session) || + sta_ds->staType == STA_ENTRY_TDLS_PEER)) + he_cap = lim_is_sta_he_capable(sta_ds); + + if (sta_ds && + (lim_is_session_eht_capable(session) || + sta_ds->staType == STA_ENTRY_TDLS_PEER)) + eht_cap = lim_is_sta_eht_capable(sta_ds); + + if (sta_ds && sta_ds->staType == STA_ENTRY_NDI_PEER) + he_cap = lim_is_session_he_capable(session); + + if (eht_cap) + buff_size = MAX_EHT_BA_BUFF_SIZE; + else if (he_cap) + buff_size = MAX_BA_BUFF_SIZE; + else + buff_size = SIR_MAC_BA_DEFAULT_BUFF_SIZE; + + if (mac_ctx->usr_cfg_ba_buff_size) + buff_size = mac_ctx->usr_cfg_ba_buff_size; + + if (addba_req->addba_extn_element.present) + extd_buff_size = addba_req->addba_extn_element.extd_buff_size; + + if (addba_req->addba_param_set.buff_size) + buff_size = QDF_MIN(buff_size, + addba_req->addba_param_set.buff_size); + else if (extd_buff_size) + /* limit the buff size */ + buff_size = QDF_MIN(buff_size, MAX_EHT_BA_BUFF_SIZE); + + pe_debug("token %d tid %d timeout %d buff_size in frame %d buf_size calculated %d ssn %d, extd buff size %d", + addba_req->DialogToken.token, addba_req->addba_param_set.tid, + addba_req->ba_timeout.timeout, + addba_req->addba_param_set.buff_size, buff_size, + addba_req->ba_start_seq_ctrl.ssn, extd_buff_size); + + qdf_status = cdp_addba_requestprocess( + soc, mac_hdr->sa, + session->vdev_id, + addba_req->DialogToken.token, + addba_req->addba_param_set.tid, + addba_req->ba_timeout.timeout, + buff_size, + addba_req->ba_start_seq_ctrl.ssn); + + if (QDF_STATUS_SUCCESS == qdf_status) { + qdf_status = lim_send_addba_response_frame(mac_ctx, + mac_hdr->sa, + addba_req->addba_param_set.tid, + session, + addba_req->addba_extn_element.present, + addba_req->addba_param_set.amsdu_supp, + mac_hdr->fc.wep, buff_size, mac_hdr->bssId); + if (qdf_status != QDF_STATUS_SUCCESS) { + pe_err("Failed to send addba response frame"); + cdp_addba_resp_tx_completion( + soc, mac_hdr->sa, session->vdev_id, + addba_req->addba_param_set.tid, + WMI_MGMT_TX_COMP_TYPE_DISCARD); + } + } else { + pe_debug_rl("Failed to process addba request"); + } + +error: + qdf_mem_free(addba_req); + return; +} + +/** + * lim_process_delba_req() - process DELBA Request + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * @session: PE session pointer + * + * This routine will be called to process ADDBA request action frame + * + * Return: None + */ +static void lim_process_delba_req(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + struct pe_session *session) +{ + tpSirMacMgmtHdr mac_hdr; + uint8_t *body_ptr; + tDot11fdelba_req *delba_req; + uint32_t frame_len, status; + QDF_STATUS qdf_status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + body_ptr, frame_len); + + delba_req = qdf_mem_malloc(sizeof(*delba_req)); + if (!delba_req) + return; + + /* Unpack DELBA request frame */ + status = dot11f_unpack_delba_req(mac_ctx, body_ptr, frame_len, + delba_req, false); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse (0x%08x, %d bytes)", + status, frame_len); + goto error; + } else if (DOT11F_WARNED(status)) { + pe_warn("warning: unpack addba Req(0x%08x, %d bytes)", + status, frame_len); + } + + qdf_status = cdp_delba_process(soc, mac_hdr->sa, session->vdev_id, + delba_req->delba_param_set.tid, delba_req->Reason.code); + + if (QDF_STATUS_SUCCESS != qdf_status) + pe_err_rl("Failed to process delba request"); + +error: + qdf_mem_free(delba_req); + return; +} + +/** + * lim_process_action_frame() - to process action frames + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to packet info structure + * + * This function is called by limProcessMessageQueue() upon + * Action frame reception. + * + * Return: none + */ + +void lim_process_action_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *session) +{ + uint8_t *body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) body_ptr; + tpSirMacMgmtHdr mac_hdr_11w = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + tpSirMacMgmtHdr mac_hdr = NULL; + int8_t rssi; + uint32_t frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + tpSirMacVendorSpecificFrameHdr vendor_specific; + uint8_t dpp_oui[] = { 0x50, 0x6F, 0x9A, 0x1A }; + tpSirMacVendorSpecificPublicActionFrameHdr pub_action; + enum wlan_t2lm_resp_frm_type status_code; + uint8_t token = 0; + struct wlan_objmgr_peer *peer = NULL; + QDF_STATUS status; + + if (frame_len < sizeof(*action_hdr)) { + pe_debug("frame_len %d less than Action Frame Hdr size", + frame_len); + return; + } + + if (wlan_mgmt_is_rmf_mgmt_action_frame(action_hdr->category) && + lim_drop_unprotected_action_frame(mac_ctx, session, + mac_hdr_11w, action_hdr->category)) + return; + + switch (action_hdr->category) { + case ACTION_CATEGORY_QOS: + if ((session->limQosEnabled) || + (action_hdr->actionID == QOS_MAP_CONFIGURE)) { + switch (action_hdr->actionID) { + case QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, + session); + break; + + case QOS_MAP_CONFIGURE: + __lim_process_qos_map_configure_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + pe_warn("Qos action: %d not handled", + action_hdr->actionID); + break; + } + break; + } + break; + + case ACTION_CATEGORY_SPECTRUM_MGMT: + switch (action_hdr->actionID) { +#ifdef ANI_SUPPORT_11H + case ACTION_SPCT_MSR_REQ: + if (session->lim11hEnable) + __lim_process_measurement_request_frame(mac_ctx, + rx_pkt_info, + session); + break; + case ACTION_SPCT_TPC_REQ: + if ((LIM_IS_STA_ROLE(session) || + LIM_IS_AP_ROLE(session)) && + session->lim11hEnable) + __lim_process_tpc_request_frame(mac_ctx, + rx_pkt_info, session); + break; +#endif + default: + pe_warn("Spectrum mgmt action id: %d not handled", + action_hdr->actionID); + break; + } + break; + + case ACTION_CATEGORY_WMM: + if (!session->limWmeEnabled) { + pe_warn("WME mode disabled - dropping frame: %d", + action_hdr->actionID); + break; + } + switch (action_hdr->actionID) { + case QOS_ADD_TS_REQ: + __lim_process_add_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case QOS_ADD_TS_RSP: + __lim_process_add_ts_rsp(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case QOS_DEL_TS_REQ: + __lim_process_del_ts_req(mac_ctx, + (uint8_t *) rx_pkt_info, session); + break; + + case QOS_MAP_CONFIGURE: + __lim_process_qos_map_configure_frame(mac_ctx, + (uint8_t *)rx_pkt_info, session); + break; + + default: + pe_warn("WME action: %d not handled", + action_hdr->actionID); + break; + } + break; + + case ACTION_CATEGORY_HT: + /** Type of HT Action to be performed*/ + switch (action_hdr->actionID) { + case HT_ACTION_SMPS: + if (LIM_IS_AP_ROLE(session)) + __lim_process_sm_power_save_update(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + pe_warn("Action ID: %d not handled in HT category", + action_hdr->actionID); + break; + } + break; + + case ACTION_CATEGORY_WNM: + pe_debug("WNM Action category: %d action: %d", + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case WNM_BSS_TM_QUERY: + case WNM_BSS_TM_REQUEST: + case WNM_BSS_TM_RESPONSE: + if (cfg_p2p_is_roam_config_disabled(mac_ctx->psoc) && + session && LIM_IS_STA_ROLE(session) && + (policy_mgr_mode_specific_connection_count( + mac_ctx->psoc, PM_P2P_CLIENT_MODE, NULL) || + policy_mgr_mode_specific_connection_count( + mac_ctx->psoc, PM_P2P_GO_MODE, NULL))) { + pe_debug("p2p session active drop BTM frame"); + break; + } + fallthrough; + case WNM_NOTIF_REQUEST: + case WNM_NOTIF_RESPONSE: + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + /* Forward to the SME to HDD to wpa_supplicant */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->vdev_id, + WMA_GET_RX_FREQ(rx_pkt_info), + rssi, RXMGMT_FLAG_NONE); + break; + default: + pe_debug("Action ID: %d not handled in WNM category", + action_hdr->actionID); + break; + } + break; + + case ACTION_CATEGORY_RRM: + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + LIM_IS_AP_ROLE(session) && + action_hdr->actionID == RRM_RADIO_MEASURE_RPT) { + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + wlan_son_deliver_rrm_rpt(session->vdev, + mac_hdr->sa, + body_ptr + sizeof(tSirMacActionFrameHdr), + frame_len - sizeof(tSirMacActionFrameHdr)); + } + + /* Ignore RRM measurement request until DHCP is set */ + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + mac_ctx->roam.roamSession[session->smeSessionId].dhcp_done) { + switch (action_hdr->actionID) { + case RRM_RADIO_MEASURE_REQ: + __lim_process_radio_measure_request(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case RRM_LINK_MEASUREMENT_REQ: + if (!lim_is_valid_frame( + &rrm_link_action_frm, + rx_pkt_info)) + break; + + if (__lim_process_link_measurement_req( + mac_ctx, + (uint8_t *)rx_pkt_info, + session) == QDF_STATUS_SUCCESS) + lim_update_last_processed_frame( + &rrm_link_action_frm, + rx_pkt_info); + + break; + case RRM_NEIGHBOR_RPT: + __lim_process_neighbor_report(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + pe_warn("Action ID: %d not handled in RRM", + action_hdr->actionID); + break; + + } + } else if (LIM_IS_AP_ROLE(session)) { + switch (action_hdr->actionID) { + case RRM_NEIGHBOR_REQ: + case RRM_RADIO_MEASURE_RPT: + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->smeSessionId, + WMA_GET_RX_FREQ(rx_pkt_info), + rssi, RXMGMT_FLAG_NONE); + break; + default: + pe_warn("Action ID: %d not handled in RRM", + action_hdr->actionID); + break; + } + } else { + /* Else we will just ignore the RRM messages. */ + pe_debug("RRM frm ignored, it is disabled in cfg: %d or DHCP not completed: %d", + mac_ctx->rrm.rrmPEContext.rrmEnable, + mac_ctx->roam.roamSession[session->smeSessionId].dhcp_done); + } + break; + + case ACTION_CATEGORY_VENDOR_SPECIFIC: + case ACTION_CATEGORY_VENDOR_SPECIFIC_PROTECTED: + vendor_specific = (tpSirMacVendorSpecificFrameHdr) action_hdr; + mac_hdr = NULL; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + if (frame_len < sizeof(*vendor_specific)) { + pe_debug("frame len %d less than Vendor Specific Hdr len", + frame_len); + return; + } + + /* Forward all vendor specific action frames. */ + if (!qdf_mem_cmp(session->self_mac_addr, + &mac_hdr->da[0], sizeof(tSirMacAddr))) { + pe_debug("Rcvd Vendor specific frame OUI: %x %x %x", + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2]); + /* + * Forward to the SME to HDD to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->vdev_id, + WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + RXMGMT_FLAG_NONE); + } else { + pe_debug("Dropping the vendor specific action frame SelfSta address system role: %d", + GET_LIM_SYSTEM_ROLE(session)); + } + break; + case ACTION_CATEGORY_PUBLIC: + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + switch (action_hdr->actionID) { + case PUB_ACTION_EXT_CHANNEL_SWITCH_ID: + lim_process_ext_channel_switch_action_frame(mac_ctx, + rx_pkt_info, session); + break; + case TDLS_DISCOVERY_RESPONSE: + /* do not forward the tdls discovery response frame, + * it is handled by + * tgt_mgmt_txrx_rx_frame_handler -> + * tgt_tdls_mgmt_frame_rx_cb -> + * tdls_process_rx_frame + */ + break; + case PUB_ACTION_VENDOR_SPECIFIC: + pub_action = + (tpSirMacVendorSpecificPublicActionFrameHdr) + action_hdr; + if (frame_len < sizeof(*pub_action)) { + pe_debug("Received vendor specific public action frame of invalid len %d", + frame_len); + return; + } + /* + * Check if it is a DPP public action frame and fall + * thru, else drop the frame. + */ + if (qdf_mem_cmp(pub_action->Oui, dpp_oui, 4)) { + pe_debug("Unhandled public action frame (Vendor specific) OUI: %x %x %x %x", + pub_action->Oui[0], pub_action->Oui[1], + pub_action->Oui[2], pub_action->Oui[3]); + break; + } + /* send the frame to supplicant */ + fallthrough; + case ACTION_CATEGORY_VENDOR_SPECIFIC: + case ACTION_CATEGORY_VENDOR_SPECIFIC_PROTECTED: + case PUB_ACTION_2040_BSS_COEXISTENCE: + case PUB_ACTION_GAS_INITIAL_REQUEST: + if (action_hdr->actionID == + PUB_ACTION_GAS_INITIAL_REQUEST) { + wlan_son_anqp_frame(session->vdev, + mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + (uint16_t)(frame_len + + sizeof(tSirMacMgmtHdr)), + (void *)action_hdr, + &mac_hdr->sa[0]); + } + fallthrough; + case PUB_ACTION_GAS_INITIAL_RESPONSE: + case PUB_ACTION_GAS_COMEBACK_REQUEST: + case PUB_ACTION_GAS_COMEBACK_RESPONSE: + default: + pe_debug("Public action frame: %d", + action_hdr->actionID); + /* + * Forward to the SME to HDD to wpa_supplicant + * type is ACTION + */ + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->vdev_id, + WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + RXMGMT_FLAG_NONE); + break; + } + break; + + case ACTION_CATEGORY_SA_QUERY: + pe_debug("SA Query Action category: %d action: %d", + action_hdr->category, action_hdr->actionID); + switch (action_hdr->actionID) { + case SA_QUERY_REQUEST: + /**11w SA query request action frame received**/ + /* Respond directly to the incoming request in LIM */ + __lim_process_sa_query_request_action_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + case SA_QUERY_RESPONSE: + /**11w SA query response action frame received**/ + /* Handle based on the current SA Query state */ + __lim_process_sa_query_response_action_frame(mac_ctx, + (uint8_t *)rx_pkt_info, + session); + break; + default: + break; + } + break; + + case ACTION_CATEGORY_VHT: + if (!session->vhtCapability) + break; + switch (action_hdr->actionID) { + case VHT_ACTION_OPMODE_NOTIF: + __lim_process_operating_mode_action_frame(mac_ctx, + rx_pkt_info, session); + break; + case VHT_ACTION_GID_NOTIF: + /* Only if ini supports it */ + if (session->enableVhtGid) + __lim_process_gid_management_action_frame( + mac_ctx, rx_pkt_info, session); + break; + default: + break; + } + break; + case ACTION_CATEGORY_RVS: + case ACTION_CATEGORY_FST: { + tpSirMacMgmtHdr hdr; + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + pe_debug("Received %s MGMT action frame", + (action_hdr->category == ACTION_CATEGORY_FST) ? + "FST" : "RVS"); + + /* Forward to the SME to HDD */ + lim_send_sme_mgmt_frame_ind(mac_ctx, hdr->fc.subType, + (uint8_t *)hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->vdev_id, + WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED( + rx_pkt_info), RXMGMT_FLAG_NONE); + break; + } + case ACTION_CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION: + pe_debug("Rcvd Protected Dual of Public Action: %d", + action_hdr->actionID); + switch (action_hdr->actionID) { + case PDPA_GAS_INIT_REQ: + case PDPA_GAS_INIT_RSP: + case PDPA_GAS_COMEBACK_REQ: + case PDPA_GAS_COMEBACK_RSP: + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + lim_send_sme_mgmt_frame_ind(mac_ctx, + mac_hdr->fc.subType, (uint8_t *) mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + session->vdev_id, + WMA_GET_RX_FREQ(rx_pkt_info), rssi, + RXMGMT_FLAG_NONE); + break; + default: + pe_debug("Unhandled - Protected Dual Public Action"); + break; + } + break; + case ACTION_CATEGORY_BACK: + pe_debug("Rcvd Block Ack for "QDF_MAC_ADDR_FMT"; action: %d", + QDF_MAC_ADDR_REF(session->self_mac_addr), + action_hdr->actionID); + switch (action_hdr->actionID) { + case ADDBA_REQUEST: + lim_process_addba_req(mac_ctx, rx_pkt_info, session); + break; + case DELBA: + lim_process_delba_req(mac_ctx, rx_pkt_info, session); + break; + default: + pe_err("Unhandle BA action frame"); + break; + } + break; + case ACTION_CATEGORY_PROTECTED_EHT: + pe_debug("EHT T2LM/EPCS action category: %d action: %d", + action_hdr->category, action_hdr->actionID); + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, + mac_hdr->sa, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("Peer is null"); + break; + } + switch (action_hdr->actionID) { + case EHT_T2LM_REQUEST: + status = wlan_t2lm_deliver_event( + session->vdev, peer, + WLAN_T2LM_EV_ACTION_FRAME_RX_REQ, + (void *)body_ptr, frame_len, + &token); + if (QDF_IS_STATUS_SUCCESS(status)) + status_code = WLAN_T2LM_RESP_TYPE_SUCCESS; + else + status_code = + WLAN_T2LM_RESP_TYPE_DENIED_TID_TO_LINK_MAPPING; + + if (status == QDF_STATUS_E_NOSUPPORT) + pe_err("STA does not support T2LM drop frame"); + else if (lim_send_t2lm_action_rsp_frame( + mac_ctx, mac_hdr->sa, session, token, + status_code) != QDF_STATUS_SUCCESS) { + pe_err("T2LM action response frame not sent"); + } else { + wlan_send_peer_level_tid_to_link_mapping( + session->vdev, + peer); + wlan_connectivity_t2lm_status_event( + session->vdev); + } + break; + case EHT_T2LM_RESPONSE: + wlan_t2lm_deliver_event( + session->vdev, peer, + WLAN_T2LM_EV_ACTION_FRAME_RX_RESP, + (void *)body_ptr, frame_len, &token); + break; + case EHT_T2LM_TEARDOWN: + wlan_t2lm_deliver_event( + session->vdev, peer, + WLAN_T2LM_EV_ACTION_FRAME_RX_TEARDOWN, + (void *)body_ptr, frame_len, NULL); + break; + case EHT_EPCS_REQUEST: + wlan_epcs_deliver_event( + session->vdev, peer, + WLAN_EPCS_EV_ACTION_FRAME_RX_REQ, + (void *)body_ptr, frame_len); + break; + case EHT_EPCS_RESPONSE: + wlan_epcs_deliver_event( + session->vdev, peer, + WLAN_EPCS_EV_ACTION_FRAME_RX_RESP, + (void *)body_ptr, frame_len); + break; + case EHT_EPCS_TEARDOWN: + wlan_epcs_deliver_event( + session->vdev, peer, + WLAN_EPCS_EV_ACTION_FRAME_RX_TEARDOWN, + (void *)body_ptr, frame_len); + break; + default: + pe_err("Unhandled T2LM/EPCS action frame"); + break; + } + break; + default: + pe_warn_rl("Action category: %d not handled", + action_hdr->category); + break; + } + + if (peer) + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); +} + +/** + * lim_process_action_frame_no_session + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Action frame reception and no session. + * Currently only public action frames can be received from + * a non-associated station. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param *pBd - A pointer to Buffer descriptor + associated PDUs + * @return None + */ +void lim_process_action_frame_no_session(struct mac_context *mac, uint8_t *pBd) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(pBd); + uint32_t frame_len = WMA_GET_RX_PAYLOAD_LEN(pBd); + uint8_t *pBody = WMA_GET_RX_MPDU_DATA(pBd); + tpSirMacActionFrameHdr action_hdr = (tpSirMacActionFrameHdr) pBody; + tpSirMacVendorSpecificPublicActionFrameHdr vendor_specific; + + pe_debug("Received an action frame category: %d action_id: %d", + action_hdr->category, (action_hdr->category == + ACTION_CATEGORY_PUBLIC || action_hdr->category == + ACTION_CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION) ? + action_hdr->actionID : 255); + + if (frame_len < sizeof(*action_hdr)) { + pe_debug("frame_len %d less than action frame header len", + frame_len); + return; + } + + switch (action_hdr->category) { + case ACTION_CATEGORY_PUBLIC: + case ACTION_CATEGORY_PROTECTED_DUAL_OF_PUBLIC_ACTION: + if (action_hdr->actionID == PUB_ACTION_VENDOR_SPECIFIC) { + vendor_specific = + (tpSirMacVendorSpecificPublicActionFrameHdr) + action_hdr; + + if (frame_len < sizeof(*vendor_specific)) { + pe_debug("Received vendor specific public action frame of invalid len %d", + frame_len); + return; + } + + pe_debug("public action frame (Vendor specific) OUI: %x %x %x %x", + vendor_specific->Oui[0], + vendor_specific->Oui[1], + vendor_specific->Oui[2], + vendor_specific->Oui[3]); + + /* Drop P2P frames as they are handled by P2P module */ + if (wlan_p2p_is_action_frame_of_p2p_type( + (uint8_t *)mac_hdr, + WMA_GET_RX_MPDU_LEN(pBd))) { + pe_debug("Drop P2P public action frame as already handled in p2p module"); + return; + } + } + + /* + * Forward all public action frame with no session to + * wpa_supplicant + */ + lim_send_sme_mgmt_frame_ind(mac, mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + 0, WMA_GET_RX_FREQ(pBd), + WMA_GET_RX_RSSI_NORMALIZED(pBd), + RXMGMT_FLAG_NONE); + + break; + default: + pe_info_rl("Unhandled action frame without session: %x", + action_hdr->category); + break; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c new file mode 100644 index 0000000000..1b9d7c64f7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_req_frame.c @@ -0,0 +1,3625 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_process_assoc_req_frame.c contains the code + * for processing Re/Association Request Frame. + */ +#include "cds_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "sir_api.h" +#include "cfg_ucfg_api.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "cds_packet.h" +#include "lim_session_utils.h" +#include "utils_parser.h" +#include "wlan_p2p_api.h" + +#include "qdf_types.h" +#include "cds_utils.h" +#include "wlan_utility.h" +#include "wlan_crypto_global_api.h" +#include "lim_mlo.h" +#include + +/** + * lim_convert_supported_channels - Parses channel support IE + * @mac_ctx: A pointer to Global MAC structure + * @assoc_ind: A pointer to SME ASSOC/REASSOC IND + * @assoc_req: A pointer to ASSOC/REASSOC Request frame + * + * This function is called by lim_process_assoc_req_frame() to + * parse the channel support IE in the Assoc/Reassoc Request + * frame, and send relevant information in the SME_ASSOC_IND + * + * Return: None + */ +static void lim_convert_supported_channels(struct mac_context *mac_ctx, + tpLimMlmAssocInd assoc_ind, + tSirAssocReq *assoc_req) +{ + uint16_t i, j, index = 0; + uint8_t first_ch_no; + uint8_t chn_count; + uint8_t next_ch_no; + uint8_t channel_offset = 0; + uint32_t chan_freq; + + if (assoc_req->supportedChannels.length >= + SIR_MAX_SUPPORTED_CHANNEL_LIST) { + pe_err("Number of supported channels: %d is more than MAX", + assoc_req->supportedChannels.length); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + + for (i = 0; i < (assoc_req->supportedChannels.length); i++) { + /* Get First Channel Number */ + first_ch_no = assoc_req->supportedChannels.supportedChannels[i]; + assoc_ind->supportedChannels.channelList[index] = first_ch_no; + i++; + index++; + + /* Get Number of Channels in a Subband */ + chn_count = assoc_req->supportedChannels.supportedChannels[i]; + if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + pe_warn("Ch count > max supported: %d", chn_count); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + if (chn_count <= 1) + continue; + next_ch_no = first_ch_no; + chan_freq = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, + first_ch_no); + + if (REG_BAND_5G == lim_get_rf_band(chan_freq)) + channel_offset = SIR_11A_FREQUENCY_OFFSET; + else if (REG_BAND_2G == lim_get_rf_band(chan_freq)) + channel_offset = SIR_11B_FREQUENCY_OFFSET; + else + continue; + + for (j = 1; j < chn_count; j++) { + next_ch_no += channel_offset; + assoc_ind->supportedChannels.channelList[index] + = next_ch_no; + index++; + if (index >= SIR_MAX_SUPPORTED_CHANNEL_LIST) { + pe_warn("Ch count > supported: %d", chn_count); + assoc_ind->supportedChannels.numChnl = 0; + return; + } + } + } + + assoc_ind->supportedChannels.numChnl = (uint8_t) index; + pe_debug("Send AssocInd to WSM: minPwr: %d maxPwr: %d numChnl: %d", + assoc_ind->powerCap.minTxPower, + assoc_ind->powerCap.maxTxPower, + assoc_ind->supportedChannels.numChnl); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + assoc_req->supportedChannels.supportedChannels, + assoc_req->supportedChannels.length); +} + +/** + * lim_check_sta_in_pe_entries() - checks if sta exists in any dph tables. + * @mac_ctx: Pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @sessionid - session id for which session is initiated + * @dup_entry: pointer for duplicate entry found + * + * This function is called by lim_process_assoc_req_frame() to check if STA + * entry already exists in any of the PE entries of the AP. If it exists, deauth + * will be sent on that session and the STA deletion will happen. After this, + * the ASSOC request will be processed. If the STA is already in deleting phase + * this will return failure so that assoc req will be rejected till STA is + * deleted. + * + * Return: QDF_STATUS. + */ +static QDF_STATUS lim_check_sta_in_pe_entries(struct mac_context *mac_ctx, + tSirMacAddr sa, + tSirMacAddr mld_mac, + uint16_t sessionid, + bool *dup_entry) +{ + uint8_t i; + uint16_t assoc_id = 0; + tpDphHashNode sta_ds = NULL; + struct pe_session *session; + + *dup_entry = false; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session = &mac_ctx->lim.gpSession[i]; + if (session->valid && + (session->opmode == QDF_SAP_MODE)) { + sta_ds = lim_get_sta_ds( + mac_ctx, sa, mld_mac, + &assoc_id, session); + if (sta_ds + && (!sta_ds->rmfEnabled || + (sessionid != session->peSessionId)) + ) { + if (sta_ds->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_STA_RSP_STATE || + sta_ds->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_BSS_RSP_STATE || + sta_ds->sta_deletion_in_progress) { + pe_debug( + "Deletion is in progress (%d) for peer:"QDF_MAC_ADDR_FMT" in mlmState %d", + sta_ds->sta_deletion_in_progress, + QDF_MAC_ADDR_REF(sta_ds->staAddr), + sta_ds->mlmStaContext.mlmState); + *dup_entry = true; + return QDF_STATUS_E_AGAIN; + } + sta_ds->sta_deletion_in_progress = true; + pe_debug("Vdev %d Delete STA " QDF_MAC_ADDR_FMT, + session->vdev_id, + QDF_MAC_ADDR_REF(sa)); + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, + (uint8_t *)sa, session, false); + /* + * Cleanup Rx path posts eWNI_SME_DISASSOC_RSP + * msg to SME after delete sta which will update + * the userspace with disconnect + */ + sta_ds->mlmStaContext.cleanupTrigger = + eLIM_DUPLICATE_ENTRY; + sta_ds->mlmStaContext.disassocReason = + REASON_DISASSOC_DUE_TO_INACTIVITY; + lim_send_sme_disassoc_ind(mac_ctx, sta_ds, + session); + *dup_entry = true; + break; + } + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_chk_sa_da() - checks source addr to destination addr of assoc req frame + * @mac_ctx: pointer to Global MAC structure + * @hdr: pointer to the MAC head + * @session: pointer to pe session entry + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks source addr to destination addr of assoc req frame + * + * Return: true if source and destination address are different + */ +static bool lim_chk_sa_da(struct mac_context *mac_ctx, tpSirMacMgmtHdr hdr, + struct pe_session *session, uint8_t sub_type) +{ + if (qdf_mem_cmp((uint8_t *) hdr->sa, + (uint8_t *) hdr->da, + (uint8_t) (sizeof(tSirMacAddr)))) + return true; + + pe_err("Assoc Req rejected: wlan.sa = wlan.da"); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, STATUS_UNSPECIFIED_FAILURE, + 1, hdr->sa, sub_type, 0, session, false); + return false; +} + +/** + * lim_chk_assoc_req_parse_error() - checks for error in frame parsing + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @frm_body: frame body + * @frame_len: frame len + * + * Checks for error in frame parsing + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_assoc_req_parse_error(struct mac_context *mac_ctx, + tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, + uint8_t sub_type, uint8_t *frm_body, + uint32_t frame_len) +{ + QDF_STATUS qdf_status; + enum wlan_status_code wlan_status; + struct qdf_mac_addr *mld_mac; + uint32_t offset = WLAN_ASSOC_REQ_IES_OFFSET; + + if (sub_type == LIM_ASSOC) { + wlan_status = sir_convert_assoc_req_frame2_struct(mac_ctx, frm_body, + frame_len, + assoc_req); + } else { + wlan_status = sir_convert_reassoc_req_frame2_struct(mac_ctx, + frm_body, frame_len, assoc_req); + offset = WLAN_REASSOC_REQ_IES_OFFSET; + } + if (wlan_status == STATUS_SUCCESS) { + qdf_status = lim_strip_and_decode_eht_cap( + frm_body + offset, + frame_len - offset, + &assoc_req->eht_cap, + assoc_req->he_cap, + session->curr_op_freq); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to extract eht cap"); + return false; + } + + /* + * If EHT capability is not present but MLO is parsed + * suceesssfully, remove the ML info from assoc request. + */ + mld_mac = (struct qdf_mac_addr *)assoc_req->mld_mac; + if (!assoc_req->eht_cap.present && + !qdf_is_macaddr_zero(mld_mac)) { + qdf_zero_macaddr(mld_mac); + qdf_mem_zero(&assoc_req->mlo_info, + sizeof(assoc_req->mlo_info)); + } + return true; + } + + pe_warn("Assoc Req rejected: frame parsing error. source addr:" + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, wlan_status, + 1, sa, sub_type, 0, session, false); + return false; +} + +/** + * lim_chk_capab() - checks for capab match + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @local_cap: local capabilities of SAP + * + * Checks for capab match + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_capab(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type, tSirMacCapabilityInfo *local_cap) +{ + uint16_t temp; + + if (lim_get_capability_info(mac_ctx, &temp, session) != + QDF_STATUS_SUCCESS) { + pe_err("could not retrieve Capabilities"); + return false; + } + + lim_copy_u16((uint8_t *) local_cap, temp); + + if (lim_compare_capabilities(mac_ctx, assoc_req, + local_cap, session) == false) { + pe_warn("Rcvd %s Req with unsupported capab from" + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + /* + * Capabilities of requesting STA does not match with + * local capabilities. Respond with 'unsupported capabilities' + * status code. + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + return false; + } + return true; +} + +/** + * lim_chk_ssid() - checks for SSID match + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for SSID match + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_ssid(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (!lim_cmp_ssid(&assoc_req->ssId, session)) + return true; + + pe_err("%s Req with ssid wrong(Rcvd: " QDF_SSID_FMT " self: " QDF_SSID_FMT ") from " QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + QDF_SSID_REF(assoc_req->ssId.length, assoc_req->ssId.ssId), + QDF_SSID_REF(session->ssId.length, session->ssId.ssId), + QDF_MAC_ADDR_REF(sa)); + + /* + * Received Re/Association Request with either Broadcast SSID OR with + * SSID that does not match with local one. Respond with unspecified + * status code. + */ + lim_send_assoc_rsp_mgmt_frame(mac_ctx, STATUS_UNSPECIFIED_FAILURE, + 1, sa, sub_type, 0, session, false); + return false; +} + +/** + * lim_chk_rates() - checks for supported rates + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for supported rates + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_rates(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + uint8_t i = 0, j = 0; + tSirMacRateSet basic_rates; + /* + * Verify if the requested rates are available in supported rate + * set or Extended rate set. Some APs are adding basic rates in + * Extended rateset IE + */ + basic_rates.numRates = 0; + + for (i = 0; i < assoc_req->supportedRates.numRates && + (i < SIR_MAC_MAX_NUMBER_OF_RATES); i++) { + basic_rates.rate[i] = assoc_req->supportedRates.rate[i]; + basic_rates.numRates++; + } + + for (j = 0; (j < assoc_req->extendedRates.numRates) && + (i < SIR_MAC_MAX_NUMBER_OF_RATES); i++, j++) { + basic_rates.rate[i] = assoc_req->extendedRates.rate[j]; + basic_rates.numRates++; + } + + if (lim_check_rx_basic_rates(mac_ctx, basic_rates, session) == true) + return true; + + pe_warn("Assoc Req rejected: unsupported rates, source addr: %s" + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + /* + * Requesting STA does not support ALL BSS basic rates. Respond with + * 'basic rates not supported' status code. + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_ASSOC_DENIED_RATES, 1, + sa, sub_type, 0, session, false); + return false; +} + +/** + * lim_chk_11g_only() - checks for non 11g STA + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11g STA + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_11g_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == MLME_DOT11_MODE_11G_ONLY) && + (assoc_req->HTCaps.present)) { + pe_err("SOFTAP was in 11G only mode, rejecting legacy STA: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + return false; + } + return true; +} + +/** + * lim_chk_11n_only() - checks for non 11n STA + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11n STA + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_11n_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == MLME_DOT11_MODE_11N_ONLY) && + (!assoc_req->HTCaps.present)) { + pe_err("SOFTAP was in 11N only mode, rejecting legacy STA: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + return false; + } + return true; +} + +/** + * lim_chk_11ac_only() - checks for non 11ac STA + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11ac STA + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_11ac_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + tDot11fIEVHTCaps *vht_caps; + + if (assoc_req->VHTCaps.present) + vht_caps = &assoc_req->VHTCaps; + else if (assoc_req->vendor_vht_ie.VHTCaps.present && + session->vendor_vht_sap) + vht_caps = &assoc_req->vendor_vht_ie.VHTCaps; + else + vht_caps = NULL; + + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == MLME_DOT11_MODE_11AC_ONLY) && + ((!vht_caps) || ((vht_caps) && (!vht_caps->present)))) { + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + pe_err("SOFTAP was in 11AC only mode, reject"); + return false; + } + return true; +} + +/** + * lim_chk_11ax_only() - checks for non 11ax STA + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11ax STA + * + * Return: true of no error, false otherwise + */ +#ifdef WLAN_FEATURE_11AX +static bool lim_chk_11ax_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == MLME_DOT11_MODE_11AX_ONLY) && + !assoc_req->he_cap.present) { + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + pe_err("SOFTAP was in 11AX only mode, reject"); + return false; + } + return true; +} + +/** + * lim_check_11ax_basic_mcs() - checks for 11ax basic MCS rates + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11ax STA + * + * Return: true of no error, false otherwise + */ +static bool lim_check_11ax_basic_mcs(struct mac_context *mac_ctx, + tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + uint16_t basic_mcs, sta_mcs, rx_mcs, tx_mcs, final_mcs; + + if (LIM_IS_AP_ROLE(session) && + assoc_req->he_cap.present) { + rx_mcs = assoc_req->he_cap.rx_he_mcs_map_lt_80; + tx_mcs = assoc_req->he_cap.tx_he_mcs_map_lt_80; + sta_mcs = HE_INTERSECT_MCS(rx_mcs, tx_mcs); + basic_mcs = + (uint16_t)mac_ctx->mlme_cfg->he_caps.he_ops_basic_mcs_nss; + final_mcs = HE_INTERSECT_MCS(sta_mcs, basic_mcs); + if (final_mcs != basic_mcs) { + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + pe_err("STA did not support basic MCS required by SAP"); + return false; + } + } + return true; +} + +#else +static bool lim_chk_11ax_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + return true; +} + +static bool lim_check_11ax_basic_mcs(struct mac_context *mac_ctx, + tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + return true; +} +#endif + +/** + * lim_chk_11be_only() - checks for non 11be STA + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for non 11be STA + * + * Return: true if no error, false otherwise + */ +#ifdef WLAN_FEATURE_11BE +static bool lim_chk_11be_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, uint8_t sub_type) +{ + if (LIM_IS_AP_ROLE(session) && + (session->dot11mode == MLME_DOT11_MODE_11BE_ONLY) && + !assoc_req->eht_cap.present) { + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_CAPS_UNSUPPORTED, + 1, sa, sub_type, 0, session, false); + pe_err("SOFTAP was in 11BE only mode, reject"); + return false; + } + return true; +} +#else +static bool lim_chk_11be_only(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, uint8_t sub_type) +{ + return true; +} +#endif + +/** + * lim_process_for_spectrum_mgmt() - process assoc req for spectrum mgmt + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @local_cap: local capabilities of SAP + * + * Checks for SSID match + * + * process assoc req for spectrum mgmt + */ +static void +lim_process_for_spectrum_mgmt(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type, tSirMacCapabilityInfo local_cap) +{ + if (local_cap.spectrumMgt) { + QDF_STATUS status = QDF_STATUS_SUCCESS; + /* + * If station is 11h capable, then it SHOULD send all mandatory + * IEs in assoc request frame. Let us verify that + */ + if (assoc_req->capabilityInfo.spectrumMgt) { + if (!((assoc_req->powerCapabilityPresent) + && (assoc_req->supportedChannelsPresent))) { + /* + * One or more required information elements are + * missing, log the peers error + */ + if (!assoc_req->powerCapabilityPresent) { + pe_warn("LIM Info: Missing Power capability IE in %s Req from " + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + } + if (!assoc_req->supportedChannelsPresent) { + pe_warn("LIM Info: Missing Supported channel IE in %s Req from " + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + } + } else { + /* Assoc request has mandatory fields */ + status = + lim_is_dot11h_power_capabilities_in_range( + mac_ctx, assoc_req, session); + if (QDF_STATUS_SUCCESS != status) { + pe_warn("LIM Info: MinTxPower(STA) > MaxTxPower(AP) in %s Req from " + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + } + status = lim_is_dot11h_supported_channels_valid( + mac_ctx, assoc_req); + if (QDF_STATUS_SUCCESS != status) { + pe_warn("LIM Info: wrong supported channels (STA) in %s Req from " + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? + "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + } + /* IEs are valid, use them if needed */ + } + } /* if(assoc.capabilityInfo.spectrumMgt) */ + else { + /* + * As per the capabilities, the spectrum management is + * not enabled on the station. The AP may allow the + * associations to happen even if spectrum management + * is not allowed, if the transmit power of station is + * below the regulatory maximum + */ + + /* + * TODO: presently, this is not handled. In the current + * implementation, the AP would allow the station to + * associate even if it doesn't support spectrum + * management. + */ + } + } /* end of spectrum management related processing */ +} + +/** + * lim_chk_mcs() - checks for supported MCS + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * + * Checks for supported MCS + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_mcs(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type) +{ + if ((assoc_req->HTCaps.present) && (lim_check_mcs_set(mac_ctx, + assoc_req->HTCaps.supportedMCSSet) == false)) { + pe_warn("rcvd %s req with unsupported MCS Rate Set from " + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + /* + * Requesting STA does not support ALL BSS MCS basic Rate set + * rates. Spec does not define any status code for this + * scenario. + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_ASSOC_DENIED_UNSPEC, + 1, sa, sub_type, 0, session, false); + return false; + } + return true; +} + +/** + * lim_chk_is_11b_sta_supported() - checks if STA is 11b + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @phy_mode: phy mode + * + * Checks if STA is 11b + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_is_11b_sta_supported(struct mac_context *mac_ctx, + tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, + uint8_t sub_type, uint32_t phy_mode) +{ + uint32_t cfg_11g_only; + + if (phy_mode == WNI_CFG_PHY_MODE_11G) { + cfg_11g_only = mac_ctx->mlme_cfg->sap_cfg.sap_11g_policy; + if (!assoc_req->extendedRatesPresent && cfg_11g_only) { + /* + * Received Re/Association Request from 11b STA when 11g + * only policy option is set. Reject with unspecified + * status code. + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + STATUS_ASSOC_DENIED_RATES, + 1, sa, sub_type, 0, session, false); + + pe_warn("Rejecting Re/Assoc req from 11b STA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + + return false; + } + } + return true; +} + +/** + * lim_print_ht_cap() - prints HT caps + * @mac_ctx: pointer to Global MAC structure + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * + * Prints HT caps + * + * Return: void + */ +static void lim_print_ht_cap(struct mac_context *mac_ctx, struct pe_session *session, + tpSirAssocReq assoc_req) +{ + if (!session->htCapability) + return; + + if (assoc_req->HTCaps.present) { + /* The station *does* support 802.11n HT capability... */ + pe_debug("AdvCodingCap:%d ChaWidthSet:%d PowerSave:%d greenField:%d shortGI20:%d shortGI40:%d txSTBC:%d rxSTBC:%d delayBA:%d maxAMSDUsize:%d DSSS/CCK:%d PSMP:%d stbcCntl:%d lsigTXProt:%d", + assoc_req->HTCaps.advCodingCap, + assoc_req->HTCaps.supportedChannelWidthSet, + assoc_req->HTCaps.mimoPowerSave, + assoc_req->HTCaps.greenField, + assoc_req->HTCaps.shortGI20MHz, + assoc_req->HTCaps.shortGI40MHz, + assoc_req->HTCaps.txSTBC, + assoc_req->HTCaps.rxSTBC, + assoc_req->HTCaps.delayedBA, + assoc_req->HTCaps.maximalAMSDUsize, + assoc_req->HTCaps.dsssCckMode40MHz, + assoc_req->HTCaps.psmp, + assoc_req->HTCaps.stbcControlFrame, + assoc_req->HTCaps.lsigTXOPProtection); + /* + * Make sure the STA's caps are compatible with our own: + * 11.15.2 Support of DSSS/CCK in 40 MHz the AP shall refuse + * association requests from an HT STA that has the DSSS/CCK + * Mode in 40 MHz subfield set to 1; + */ + } +} + +static enum wlan_status_code +lim_check_crypto_param(tpSirAssocReq assoc_req, + struct wlan_crypto_params *peer_crypto_params) +{ + /* TKIP/WEP is not allowed in HT/VHT mode*/ + if (assoc_req->HTCaps.present) { + if ((peer_crypto_params->ucastcipherset & + (1 << WLAN_CRYPTO_CIPHER_TKIP)) || + (peer_crypto_params->ucastcipherset & + (1 << WLAN_CRYPTO_CIPHER_WEP))) { + pe_info("TKIP/WEP cipher with HT supported client, reject assoc"); + return STATUS_INVALID_IE; + } + } + return STATUS_SUCCESS; +} + +static +enum wlan_status_code lim_check_rsn_ie(struct pe_session *session, + struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + bool *pmf_connection) +{ + struct wlan_objmgr_vdev *vdev; + tSirMacRsnInfo *rsn_ie; + struct wlan_crypto_params peer_crypto_params; + + rsn_ie = qdf_mem_malloc(sizeof(*rsn_ie)); + if (!rsn_ie) { + pe_err("malloc failed for rsn_ie"); + return STATUS_UNSPECIFIED_FAILURE; + } + + rsn_ie->info[0] = WLAN_ELEMID_RSN; + rsn_ie->info[1] = assoc_req->rsn.length; + + rsn_ie->length = assoc_req->rsn.length + 2; + qdf_mem_copy(&rsn_ie->info[2], assoc_req->rsn.info, + assoc_req->rsn.length); + if (wlan_crypto_check_rsn_match(mac_ctx->psoc, session->smeSessionId, + &rsn_ie->info[0], rsn_ie->length, + &peer_crypto_params)) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + session->smeSessionId, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev is NULL"); + qdf_mem_free(rsn_ie); + return STATUS_UNSPECIFIED_FAILURE; + } + if ((peer_crypto_params.rsn_caps & + WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) && + wlan_crypto_vdev_is_pmf_enabled(vdev)) + *pmf_connection = true; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + qdf_mem_free(rsn_ie); + return lim_check_crypto_param(assoc_req, &peer_crypto_params); + + } else { + qdf_mem_free(rsn_ie); + return STATUS_INVALID_IE; + } + + qdf_mem_free(rsn_ie); + return STATUS_SUCCESS; +} + +static enum wlan_status_code lim_check_wpa_ie(struct pe_session *session, + struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + tDot11fIEWPA *wpa) +{ + uint8_t *buffer; + uint32_t dot11f_status, written = 0, nbuffer = WLAN_MAX_IE_LEN; + tSirMacRsnInfo *wpa_ie; + struct wlan_crypto_params peer_crypto_params; + + buffer = qdf_mem_malloc(WLAN_MAX_IE_LEN); + if (!buffer) { + pe_err("malloc failed for ie buffer"); + return STATUS_INVALID_IE; + } + + dot11f_status = dot11f_pack_ie_wpa(mac_ctx, wpa, buffer, + nbuffer, &written); + if (DOT11F_FAILED(dot11f_status)) { + pe_err("Failed to re-pack the RSN IE (0x%0x8)", dot11f_status); + qdf_mem_free(buffer); + return STATUS_INVALID_IE; + } + + wpa_ie = qdf_mem_malloc(sizeof(*wpa_ie)); + if (!wpa_ie) { + pe_err("malloc failed for wpa ie"); + qdf_mem_free(buffer); + return STATUS_INVALID_IE; + } + + wpa_ie->length = (uint8_t)written; + qdf_mem_copy(&wpa_ie->info[0], buffer, wpa_ie->length); + qdf_mem_free(buffer); + + if (wlan_crypto_check_wpa_match(mac_ctx->psoc, session->smeSessionId, + &wpa_ie->info[0], wpa_ie->length, + &peer_crypto_params)) { + qdf_mem_free(wpa_ie); + return lim_check_crypto_param(assoc_req, &peer_crypto_params); + } + + qdf_mem_free(wpa_ie); + return STATUS_INVALID_IE; +} + +/** + * lim_check_sae_pmf_cap() - check pmf capability for SAE STA + * @session: pointer to pe session entry + * @rsn: pointer to RSN + * @akm_type: AKM type + * + * This function checks if SAE STA is pmf capable when SAE SAP is pmf + * capable. Reject with eSIR_MAC_ROBUST_MGMT_FRAMES_POLICY_VIOLATION + * if SAE STA is pmf disable. + * + * Return: wlan_status_code + */ +#if defined(WLAN_FEATURE_SAE) +static enum wlan_status_code lim_check_sae_pmf_cap(struct pe_session *session, + tDot11fIERSN *rsn, + enum ani_akm_type akm_type) +{ + enum wlan_status_code status = STATUS_SUCCESS; + + if (session->limRmfEnabled && + (rsn->RSN_Cap[0] & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED) == 0 && + akm_type == ANI_AKM_TYPE_SAE) + status = STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION; + + return status; +} +#else +static enum wlan_status_code lim_check_sae_pmf_cap(struct pe_session *session, + tDot11fIERSN *rsn, + enum ani_akm_type akm_type) +{ + return STATUS_SUCCESS; +} +#endif + +/** + * lim_check_wpa_rsn_ie() - wpa and rsn ie related checks + * @session: pointer to pe session entry + * @mac_ctx: pointer to Global MAC structure + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sa: Mac address of requesting peer + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @pmf_connection: flag indicating pmf connection + * @akm_type: AKM type + * + * This function checks if wpa/rsn IE is present and validates + * ie version, length and mismatch. + * + * Return: true if no error, false otherwise + */ +static bool lim_check_wpa_rsn_ie(struct pe_session *session, + struct mac_context *mac_ctx, + uint8_t sub_type, tSirMacAddr sa, + tpSirAssocReq assoc_req, bool *pmf_connection, + enum ani_akm_type *akm_type) +{ + uint32_t ret; + tDot11fIEWPA dot11f_ie_wpa = {0}; + tDot11fIERSN dot11f_ie_rsn = {0}; + enum wlan_status_code status = STATUS_SUCCESS; + + /* + * Clear the buffers so that frame parser knows that there isn't a + * previously decoded IE in these buffers + */ + qdf_mem_zero((uint8_t *) &dot11f_ie_rsn, sizeof(dot11f_ie_rsn)); + qdf_mem_zero((uint8_t *) &dot11f_ie_wpa, sizeof(dot11f_ie_wpa)); + pe_debug("RSN enabled auth, Re/Assoc req from STA: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(sa)); + + if (assoc_req->rsnPresent) { + if (!(assoc_req->rsn.length)) { + pe_warn("Re/Assoc rejected from: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + /* + * rcvd Assoc req frame with RSN IE but + * length is zero + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_INVALID_IE, 1, + sa, sub_type, 0, session, false); + return false; + } + + /* Unpack the RSN IE */ + ret = dot11f_unpack_ie_rsn(mac_ctx, + &assoc_req->rsn.info[0], + assoc_req->rsn.length, + &dot11f_ie_rsn, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("Invalid RSN IE"); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_INVALID_IE, 1, + sa, sub_type, 0, session, false); + return false; + } + + /* Check if the RSN version is supported */ + if (SIR_MAC_OUI_VERSION_1 == dot11f_ie_rsn.version) { + /* check the groupwise and pairwise cipher suites */ + status = lim_check_rsn_ie(session, mac_ctx, assoc_req, + pmf_connection); + if (status != STATUS_SUCCESS) { + pe_warn("Re/Assoc rejected from: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, status, 1, sa, sub_type, + 0, session, false); + return false; + } + } else { + pe_warn("Re/Assoc rejected from: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + /* + * rcvd Assoc req frame with RSN IE but + * IE version is wrong + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + STATUS_UNSUPPORTED_RSN_IE_VERSION, + 1, sa, sub_type, 0, session, false); + return false; + } + *akm_type = lim_translate_rsn_oui_to_akm_type( + dot11f_ie_rsn.akm_suite[0]); + + status = lim_check_sae_pmf_cap(session, &dot11f_ie_rsn, + *akm_type); + if (status != STATUS_SUCCESS) { + /* Reject pmf disable SAE STA */ + pe_warn("Re/Assoc rejected from: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + lim_send_assoc_rsp_mgmt_frame(mac_ctx, status, + 1, sa, sub_type, + 0, session, false); + return false; + } + + } else if (assoc_req->wpaPresent) { + if (!(assoc_req->wpa.length)) { + pe_warn("Re/Assoc rejected from: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + + /* rcvd Assoc req frame with invalid WPA IE length */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_INVALID_IE, 1, + sa, sub_type, 0, session, false); + return false; + } + /* Unpack the WPA IE */ + ret = dot11f_unpack_ie_wpa(mac_ctx, + &assoc_req->wpa.info[4], + (assoc_req->wpa.length - 4), + &dot11f_ie_wpa, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("Invalid WPA IE"); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_INVALID_IE, 1, + sa, sub_type, 0, session, false); + return false; + } + + /* check the groupwise and pairwise cipher suites*/ + status = lim_check_wpa_ie(session, mac_ctx, assoc_req, + &dot11f_ie_wpa); + if (status != STATUS_SUCCESS) { + pe_warn("Re/Assoc rejected from: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + /* + * rcvd Assoc req frame with WPA IE + * but there is mismatch + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, status, 1, + sa, sub_type, 0, session, false); + return false; + } + *akm_type = lim_translate_rsn_oui_to_akm_type( + dot11f_ie_wpa.auth_suites[0]); + } else { + if ((session->gStartBssRSNIe.present || + session->gStartBssWPAIe.present) && + session->opmode == QDF_SAP_MODE) { + pe_warn("STA does not support RSN and WPA!"); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_NOT_SUPPORTED_AUTH_ALG, 1, + sa, sub_type, 0, session, false); + return false; + } + } + + return true; +} + +/** + * lim_chk_n_process_wpa_rsn_ie() - wpa ie related checks + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @pmf_connection: flag indicating pmf connection + * @akm_type: AKM type + * + * wpa ie related checks + * + * Return: true if no error, false otherwise + */ +static bool lim_chk_n_process_wpa_rsn_ie(struct mac_context *mac_ctx, + tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, + uint8_t sub_type, + bool *pmf_connection, + enum ani_akm_type *akm_type) +{ + const uint8_t *wps_ie = NULL; + + /* if additional IE is present, check if it has WscIE */ + if (assoc_req->addIEPresent && assoc_req->addIE.length) + wps_ie = limGetWscIEPtr(mac_ctx, assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + else + pe_debug("Assoc req addIEPresent: %d addIE length: %d", + assoc_req->addIEPresent, assoc_req->addIE.length); + + /* when wps_ie is present, RSN/WPA IE is ignored */ + if (!wps_ie) { + /* check whether RSN IE is present */ + if (LIM_IS_AP_ROLE(session) && + session->pLimStartBssReq->privacy && + session->pLimStartBssReq->rsnIE.length) + return lim_check_wpa_rsn_ie(session, mac_ctx, sub_type, + sa, assoc_req, pmf_connection, + akm_type); + } else { + pe_debug("Assoc req WSE IE is present"); + } + return true; +} + +/** + * lim_process_assoc_req_no_sta_ctx() - process assoc req for no sta ctx present + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_pre_auth_ctx: sta pre auth context + * @sta_ds: station dph entry + * @auth_type: indicates security type + * @partner_peer_idx: partner peer idx + * + * Process assoc req for no sta ctx present + * + * Return: true of no error, false otherwise + */ +static bool lim_process_assoc_req_no_sta_ctx(struct mac_context *mac_ctx, + tSirMacAddr sa, struct pe_session *session, + tpSirAssocReq assoc_req, uint8_t sub_type, + struct tLimPreAuthNode *sta_pre_auth_ctx, + tpDphHashNode sta_ds, tAniAuthType *auth_type, + uint16_t partner_peer_idx) +{ + /* Requesting STA is not currently associated */ + if (pe_get_current_stas_count(mac_ctx) == + mac_ctx->mlme_cfg->sap_cfg.assoc_sta_limit) { + /* + * Maximum number of STAs that AP can handle reached. + * Send Association response to peer MAC entity + */ + pe_info_rl("Max Sta count reached : %d", + mac_ctx->lim.maxStation); + lim_reject_association(mac_ctx, sa, sub_type, false, + (tAniAuthType)0, 0, false, + STATUS_UNSPECIFIED_FAILURE, + session); + return false; + } + /* Check if STA is pre-authenticated. */ + if ((!sta_pre_auth_ctx && !partner_peer_idx) || + (sta_pre_auth_ctx && sta_pre_auth_ctx->mlmState != + eLIM_MLM_AUTHENTICATED_STATE)) { + /* + * STA is not pre-authenticated yet requesting Re/Association + * before Authentication. OR STA is in the process of getting + * authenticated and sent Re/Association request. Send + * Deauthentication frame with 'prior authentication required' + * reason code. + */ + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_STA_NOT_AUTHENTICATED, + sa, session, false); + + pe_warn("rcvd %s req, sessionid: %d, without pre-auth ctx" + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, QDF_MAC_ADDR_REF(sa)); + return false; + } + if (partner_peer_idx) { + if (!lim_mlo_partner_auth_type(session, partner_peer_idx, + auth_type)) { + pe_err("can't get partner auth type"); + return false; + } + } else { + /* Delete 'pre-auth' context of STA */ + *auth_type = sta_pre_auth_ctx->authType; + if (sta_pre_auth_ctx->authType == eSIR_AUTH_TYPE_SAE) + assoc_req->is_sae_authenticated = true; + lim_delete_pre_auth_node(mac_ctx, sa); + } + /* All is well. Assign AID (after else part) */ + return true; +} + +static inline void +lim_delete_pmf_query_timer(tpDphHashNode sta_ds) +{ + if (!sta_ds->rmfEnabled) + return; + + if (tx_timer_running(&sta_ds->pmfSaQueryTimer)) + tx_timer_deactivate(&sta_ds->pmfSaQueryTimer); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); +} + +/** + * lim_process_assoc_req_sta_ctx() - process assoc req for sta context present + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_pre_auth_ctx: sta pre auth context + * @sta_ds: station dph entry + * @peer_idx: peer index + * @auth_type: indicates security type + * @update_ctx: indicates if STA context already exist + * + * Process assoc req for sta context present + * + * Return: true of no error, false otherwise + */ +static bool lim_process_assoc_req_sta_ctx(struct mac_context *mac_ctx, + tSirMacAddr sa, struct pe_session *session, + tpSirAssocReq assoc_req, uint8_t sub_type, + struct tLimPreAuthNode *sta_pre_auth_ctx, + tpDphHashNode sta_ds, uint16_t peer_idx, + tAniAuthType *auth_type, uint8_t *update_ctx) +{ + /* Drop if STA deletion is in progress or not in established state */ + if (sta_ds->sta_deletion_in_progress || + (sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + pe_debug("%s: peer:"QDF_MAC_ADDR_FMT" in mlmState %d (%s) and sta del %d", + (sub_type == LIM_ASSOC) ? "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sta_ds->staAddr), + sta_ds->mlmStaContext.mlmState, + lim_mlm_state_str(sta_ds->mlmStaContext.mlmState), + sta_ds->sta_deletion_in_progress); + return false; + } + + /* STA sent assoc req frame while already in 'associated' state */ + + pe_debug("Re/Assoc request from station that is already associated"); + pe_debug("PMF enabled: %d, SA Query state: %d", + sta_ds->rmfEnabled, sta_ds->pmfSaQueryState); + if (sta_ds->rmfEnabled) { + switch (sta_ds->pmfSaQueryState) { + /* + * start SA Query procedure, respond to Association Request with + * try again later + */ + case DPH_SA_QUERY_NOT_IN_PROGRESS: + /* + * We should reset the retry counter before we start + * the SA query procedure, otherwise in next set of SA + * query procedure we will end up using the stale value. + */ + sta_ds->pmfSaQueryRetryCount = 0; + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_ASSOC_REJECTED_TEMPORARILY, 1, + sa, sub_type, sta_ds, session, false); + lim_send_sa_query_request_frame(mac_ctx, + (uint8_t *) &(sta_ds->pmfSaQueryCurrentTransId), + sa, session); + sta_ds->pmfSaQueryStartTransId = + sta_ds->pmfSaQueryCurrentTransId; + sta_ds->pmfSaQueryCurrentTransId++; + + /* start timer for SA Query retry */ + if (tx_timer_activate(&sta_ds->pmfSaQueryTimer) + != TX_SUCCESS) { + pe_err("PMF SA Query timer start failed!"); + return false; + } + sta_ds->pmfSaQueryState = DPH_SA_QUERY_IN_PROGRESS; + return false; + /* + * SA Query procedure still going, respond to Association + * Request with try again later + */ + case DPH_SA_QUERY_IN_PROGRESS: + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_ASSOC_REJECTED_TEMPORARILY, 1, + sa, sub_type, 0, session, false); + return false; + + /* + * SA Query procedure timed out, accept Association + * Request normally + */ + case DPH_SA_QUERY_TIMED_OUT: + sta_ds->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + break; + } + } + + /* no change in the capability so drop the frame */ + if ((sub_type == LIM_ASSOC) && + (!qdf_mem_cmp(&sta_ds->mlmStaContext.capabilityInfo, + &assoc_req->capabilityInfo, + sizeof(tSirMacCapabilityInfo)))) { + pe_err("Received Assoc req in state: %X STAid: %d", + sta_ds->mlmStaContext.mlmState, peer_idx); + return false; + } + + /* + * STA sent Re/association Request frame while already in + * 'associated' state. Update STA capabilities and send + * Association response frame with same AID + */ + pe_debug("Rcvd Assoc req from STA already connected"); + sta_ds->mlmStaContext.capabilityInfo = + assoc_req->capabilityInfo; + if (sta_pre_auth_ctx && (sta_pre_auth_ctx->mlmState == + eLIM_MLM_AUTHENTICATED_STATE)) { + /* STA has triggered pre-auth again */ + *auth_type = sta_pre_auth_ctx->authType; + lim_delete_pre_auth_node(mac_ctx, sa); + } else { + *auth_type = sta_ds->mlmStaContext.authType; + } + + *update_ctx = true; + /* Free pmf query timer before resetting the sta_ds */ + lim_delete_pmf_query_timer(sta_ds); + if (dph_init_sta_state(mac_ctx, sa, peer_idx, + &session->dph.dphHashTable) == NULL) { + pe_err("could not Init STAid: %d", peer_idx); + return false; + } + + return true; +} + +/** + * lim_chk_wmm() - wmm related checks + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @qos_mode: qos mode + * + * wmm related checks + * + * Return: true of no error, false otherwise + */ +static bool lim_chk_wmm(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, tpSirAssocReq assoc_req, + uint8_t sub_type, tHalBitVal qos_mode) +{ + tHalBitVal wme_mode; + + limGetWmeMode(session, &wme_mode); + if ((qos_mode == eHAL_SET) || (wme_mode == eHAL_SET)) { + /* + * for a qsta, check if the requested Traffic spec is admissible + * for a non-qsta check if the sta can be admitted + */ + if (assoc_req->addtsPresent) { + uint8_t tspecIdx = 0; + + if (lim_admit_control_add_ts( + mac_ctx, sa, + &(assoc_req->addtsReq), + &(assoc_req->qosCapability), + 0, false, NULL, &tspecIdx, session) != + QDF_STATUS_SUCCESS) { + pe_warn("AdmitControl: TSPEC rejected"); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, REASON_NO_BANDWIDTH, + 1, sa, sub_type, 0, session, + false); + return false; + } + } else if (lim_admit_control_add_sta(mac_ctx, sa, false) + != QDF_STATUS_SUCCESS) { + pe_warn("AdmitControl: Sta rejected"); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, REASON_NO_BANDWIDTH, 1, + sa, sub_type, 0, session, false); + return false; + } + /* else all ok */ + pe_debug("AdmitControl: Sta OK!"); + } + return true; +} + +static void lim_update_sta_ds_op_classes(tpSirAssocReq assoc_req, + tpDphHashNode sta_ds) +{ + qdf_mem_copy(&sta_ds->supp_operating_classes, + &assoc_req->supp_operating_classes, + sizeof(tDot11fIESuppOperatingClasses)); +} + +static bool lim_is_ocv_enable_in_assoc_req(struct mac_context *mac_ctx, + struct sSirAssocReq *assoc_req) +{ + uint32_t ret; + tDot11fIERSN dot11f_ie_rsn = {0}; + + if ((assoc_req->rsnPresent) && !(assoc_req->rsn.length)) + return false; + + /* Unpack the RSN IE */ + ret = dot11f_unpack_ie_rsn(mac_ctx, &assoc_req->rsn.info[0], + assoc_req->rsn.length, &dot11f_ie_rsn, + false); + if (!DOT11F_SUCCEEDED(ret)) + return false; + + if (*(uint16_t *)&dot11f_ie_rsn.RSN_Cap & + WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED) + return true; + + return false; +} + +/** + * lim_update_sta_ds() - updates ds dph entry + * @mac_ctx: pointer to Global MAC structure + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame pointer + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_ds: station dph entry + * @auth_type: indicates security type + * @akm_type: indicates security type in akm + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * @peer_idx: peer index + * @qos_mode: qos mode + * @pmf_connection: flag indicating pmf connection + * @force_1x1: Flag to check if the HT capable STA needs to be downgraded to 1x1 + * nss. + * + * Updates ds dph entry + * + * Return: true of no error, false otherwise + */ +static bool lim_update_sta_ds(struct mac_context *mac_ctx, tSirMacAddr sa, + struct pe_session *session, + tpSirAssocReq assoc_req, + uint8_t sub_type, tpDphHashNode sta_ds, + tAniAuthType auth_type, + enum ani_akm_type akm_type, + bool *assoc_req_copied, uint16_t peer_idx, + tHalBitVal qos_mode, bool pmf_connection, + bool force_1x1) +{ + tHalBitVal wme_mode, wsm_mode; + uint8_t *ht_cap_ie = NULL; + tPmfSaQueryTimerId timer_id; + uint16_t retry_interval; + tDot11fIEVHTCaps *vht_caps; + tpSirAssocReq tmp_assoc_req; + + if (assoc_req->VHTCaps.present) + vht_caps = &assoc_req->VHTCaps; + else if (assoc_req->vendor_vht_ie.VHTCaps.present && + session->vendor_vht_sap) + vht_caps = &assoc_req->vendor_vht_ie.VHTCaps; + else + vht_caps = NULL; + + /* + * check here if the parsedAssocReq already pointing to the assoc_req + * and free it before assigning this new assoc_req + */ + if (session->parsedAssocReq) { + tmp_assoc_req = session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req) { + lim_free_assoc_req_frm_buf(tmp_assoc_req); + qdf_mem_free(tmp_assoc_req); + tmp_assoc_req = NULL; + } + + session->parsedAssocReq[sta_ds->assocId] = assoc_req; + *assoc_req_copied = true; + } + if (!assoc_req->wmeInfoPresent) { + sta_ds->mlmStaContext.htCapability = 0; + sta_ds->mlmStaContext.vhtCapability = 0; + } else { + sta_ds->mlmStaContext.htCapability = assoc_req->HTCaps.present; + if ((vht_caps) && vht_caps->present) + sta_ds->mlmStaContext.vhtCapability = vht_caps->present; + else + sta_ds->mlmStaContext.vhtCapability = false; + } + + lim_update_stads_he_capable(sta_ds, assoc_req); + lim_update_stads_eht_capable(sta_ds, assoc_req); + sta_ds->qos.addtsPresent = + (assoc_req->addtsPresent == 0) ? false : true; + sta_ds->qos.addts = assoc_req->addtsReq; + sta_ds->qos.capability = assoc_req->qosCapability; + /* + * short slot and short preamble should be updated before doing + * limaddsta + */ + sta_ds->shortPreambleEnabled = + (uint8_t) assoc_req->capabilityInfo.shortPreamble; + sta_ds->shortSlotTimeEnabled = + (uint8_t) assoc_req->capabilityInfo.shortSlotTime; + + sta_ds->valid = 0; + sta_ds->mlmStaContext.authType = auth_type; + sta_ds->mlmStaContext.akm_type = akm_type; + sta_ds->staType = STA_ENTRY_PEER; + sta_ds->mlmStaContext.force_1x1 = force_1x1; + + pe_debug("auth_type = %d, akm_type = %d", auth_type, akm_type); + + /* + * TODO: If listen interval is more than certain limit, reject the + * association. Need to check customer requirements and then implement. + */ + sta_ds->mlmStaContext.listenInterval = assoc_req->listenInterval; + sta_ds->mlmStaContext.capabilityInfo = assoc_req->capabilityInfo; + + if (IS_DOT11_MODE_HT(session->dot11mode) && + sta_ds->mlmStaContext.htCapability) { + sta_ds->htGreenfield = (uint8_t) assoc_req->HTCaps.greenField; + sta_ds->htAMpduDensity = assoc_req->HTCaps.mpduDensity; + sta_ds->htDsssCckRate40MHzSupport = + (uint8_t) assoc_req->HTCaps.dsssCckMode40MHz; + sta_ds->htLsigTXOPProtection = + (uint8_t) assoc_req->HTCaps.lsigTXOPProtection; + sta_ds->htMaxAmsduLength = + (uint8_t) assoc_req->HTCaps.maximalAMSDUsize; + sta_ds->htMaxRxAMpduFactor = assoc_req->HTCaps.maxRxAMPDUFactor; + sta_ds->htMIMOPSState = assoc_req->HTCaps.mimoPowerSave; + + /* assoc_req will be copied to session->parsedAssocReq later */ + ht_cap_ie = ((uint8_t *) &assoc_req->HTCaps) + 1; + + if (session->ht_config.short_gi_20_mhz) { + sta_ds->htShortGI20Mhz = + (uint8_t)assoc_req->HTCaps.shortGI20MHz; + } else { + /* Unset htShortGI20Mhz in ht_caps*/ + *ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI20MHZ_S); + sta_ds->htShortGI20Mhz = 0; + } + + if (session->ht_config.short_gi_40_mhz) { + sta_ds->htShortGI40Mhz = + (uint8_t)assoc_req->HTCaps.shortGI40MHz; + } else { + /* Unset htShortGI40Mhz in ht_caps */ + *ht_cap_ie &= ~(1 << SIR_MAC_HT_CAP_SHORTGI40MHZ_S); + sta_ds->htShortGI40Mhz = 0; + } + + sta_ds->htSupportedChannelWidthSet = + (uint8_t) assoc_req->HTCaps.supportedChannelWidthSet; + if (session->ch_width > CH_WIDTH_20MHZ && + session->ch_width <= CH_WIDTH_80P80MHZ && + sta_ds->htSupportedChannelWidthSet) { + /* + * peer just follows AP; so when we are softAP/GO, + * we just store our session entry's secondary channel + * offset here in peer INFRA STA. However, if peer's + * 40MHz channel width support is disabled then + * secondary channel will be zero + */ + sta_ds->htSecondaryChannelOffset = + session->htSecondaryChannelOffset; + sta_ds->ch_width = CH_WIDTH_40MHZ; + if (sta_ds->mlmStaContext.vhtCapability) { + if (assoc_req->operMode.present) { + sta_ds->ch_width = + assoc_req->operMode.chanWidth; + } else if (vht_caps->supportedChannelWidthSet == + VHT_CAP_160_AND_80P80_SUPP) { + sta_ds->ch_width = CH_WIDTH_80P80MHZ; + } else if (vht_caps->supportedChannelWidthSet == + VHT_CAP_160_SUPP) { + if (vht_caps->vht_extended_nss_bw_cap && + vht_caps->extended_nss_bw_supp) + sta_ds->ch_width = + CH_WIDTH_80P80MHZ; + else + sta_ds->ch_width = + CH_WIDTH_160MHZ; + } else if (vht_caps->vht_extended_nss_bw_cap) { + if (vht_caps->extended_nss_bw_supp == + VHT_EXTD_NSS_80_HALF_NSS_160) + sta_ds->ch_width = + CH_WIDTH_160MHZ; + else if (vht_caps->extended_nss_bw_supp > + VHT_EXTD_NSS_80_HALF_NSS_160) + sta_ds->ch_width = + CH_WIDTH_80P80MHZ; + else + sta_ds->ch_width = + CH_WIDTH_80MHZ; + } else { + sta_ds->ch_width = CH_WIDTH_80MHZ; + } + + sta_ds->ch_width = QDF_MIN(sta_ds->ch_width, + session->ch_width); + } + } else { + sta_ds->htSupportedChannelWidthSet = 0; + sta_ds->htSecondaryChannelOffset = 0; + sta_ds->ch_width = CH_WIDTH_20MHZ; + } + sta_ds->htLdpcCapable = + (uint8_t) assoc_req->HTCaps.advCodingCap; + } + + if (assoc_req->ExtCap.present) + sta_ds->non_ecsa_capable = + !((struct s_ext_cap *)assoc_req->ExtCap.bytes)-> + ext_chan_switch; + else + sta_ds->non_ecsa_capable = 1; + + if (sta_ds->mlmStaContext.vhtCapability && + session->vhtCapability) { + sta_ds->htMaxRxAMpduFactor = + vht_caps->maxAMPDULenExp; + sta_ds->vhtLdpcCapable = + (uint8_t)vht_caps->ldpcCodingCap; + if (session->vht_config.su_beam_formee && + vht_caps->suBeamFormerCap) + sta_ds->vhtBeamFormerCapable = 1; + else + sta_ds->vhtBeamFormerCapable = 0; + if (session->vht_config.su_beam_former && + vht_caps->suBeamformeeCap) + sta_ds->vht_su_bfee_capable = 1; + else + sta_ds->vht_su_bfee_capable = 0; + + pe_debug("peer_caps: suBformer: %d, suBformee: %d", + vht_caps->suBeamFormerCap, + vht_caps->suBeamformeeCap); + pe_debug("self_cap: suBformer: %d, suBformee: %d", + session->vht_config.su_beam_former, + session->vht_config.su_beam_formee); + pe_debug("connection's final cap: suBformer: %d, suBformee: %d", + sta_ds->vhtBeamFormerCapable, + sta_ds->vht_su_bfee_capable); + } + + sta_ds->vht_mcs_10_11_supp = 0; + if (IS_DOT11_MODE_HT(session->dot11mode) && + sta_ds->mlmStaContext.vhtCapability) { + if (mac_ctx->mlme_cfg->vht_caps.vht_cap_info. + vht_mcs_10_11_supp && + assoc_req->qcn_ie.present && + assoc_req->qcn_ie.vht_mcs11_attr.present) + sta_ds->vht_mcs_10_11_supp = + assoc_req->qcn_ie.vht_mcs11_attr. + vht_mcs_10_11_supp; + } + lim_intersect_sta_he_caps(mac_ctx, assoc_req, session, sta_ds); + + lim_intersect_sta_eht_caps(mac_ctx, assoc_req, session, sta_ds); + + lim_mlo_set_mld_mac_peer(sta_ds, assoc_req->mld_mac); + + lim_mlo_save_mlo_info(sta_ds, &assoc_req->mlo_info); + + /* + * Move forward to update sta_ds->ch_width for 6 GHz before call + * lim_populate_matching_rate_set and lim_populate_eht_mcs_set + */ + lim_update_stads_he_6ghz_op(session, sta_ds); + lim_update_sta_ds_op_classes(assoc_req, sta_ds); + lim_update_stads_eht_bw_320mhz(session, sta_ds); + + if (lim_populate_matching_rate_set(mac_ctx, sta_ds, + &(assoc_req->supportedRates), + &(assoc_req->extendedRates), + assoc_req->HTCaps.supportedMCSSet, + session, vht_caps, &assoc_req->he_cap, + &assoc_req->eht_cap) != QDF_STATUS_SUCCESS) { + /* Could not update hash table entry at DPH with rateset */ + pe_err("Couldn't update hash entry for aid: %d MacAddr: " + QDF_MAC_ADDR_FMT, + peer_idx, QDF_MAC_ADDR_REF(sa)); + + /* Release AID */ + if (lim_is_mlo_conn(session, sta_ds)) { + if (lim_is_mlo_recv_assoc(sta_ds)) + lim_release_mlo_conn_idx(mac_ctx, peer_idx, + session, true); + else + lim_release_mlo_conn_idx(mac_ctx, peer_idx, + session, false); + } else { + lim_release_peer_idx(mac_ctx, peer_idx, session); + } + + lim_reject_association(mac_ctx, sa, sub_type, true, + auth_type, peer_idx, false, + STATUS_UNSPECIFIED_FAILURE, session); + pe_err("Delete dph hash entry"); + if (dph_delete_hash_entry(mac_ctx, sa, sta_ds->assocId, + &session->dph.dphHashTable) != + QDF_STATUS_SUCCESS) + pe_err("error deleting hash entry"); + return false; + } + if (assoc_req->operMode.present) { + sta_ds->vhtSupportedRxNss = assoc_req->operMode.rxNSS + 1; + } else { + sta_ds->vhtSupportedRxNss = + ((sta_ds->supportedRates.vhtTxMCSMap & MCSMAPMASK2x2) + == MCSMAPMASK2x2) ? 1 : 2; + } + + /* Add STA context at MAC HW (BMU, RHP & TFP) */ + sta_ds->qosMode = false; + sta_ds->lleEnabled = false; + if (assoc_req->capabilityInfo.qos && (qos_mode == eHAL_SET)) { + sta_ds->lleEnabled = true; + sta_ds->qosMode = true; + } + + sta_ds->wmeEnabled = false; + sta_ds->wsmEnabled = false; + limGetWmeMode(session, &wme_mode); + if ((!sta_ds->lleEnabled) && assoc_req->wmeInfoPresent + && (wme_mode == eHAL_SET)) { + sta_ds->wmeEnabled = true; + sta_ds->qosMode = true; + limGetWsmMode(session, &wsm_mode); + /* + * WMM_APSD - WMM_SA related processing should be separate; + * WMM_SA and WMM_APSD can coexist + */ + if (assoc_req->WMMInfoStation.present) { + /* check whether AP supports or not */ + if (LIM_IS_AP_ROLE(session) && + (session->apUapsdEnable == 0) && + (assoc_req->WMMInfoStation.acbe_uapsd || + assoc_req->WMMInfoStation.acbk_uapsd || + assoc_req->WMMInfoStation.acvo_uapsd || + assoc_req->WMMInfoStation.acvi_uapsd)) { + /* + * Rcvd Re/Assoc Req from STA when UPASD is + * not supported. + */ + pe_err("UAPSD not supported, reply accordingly"); + /* update UAPSD and send it to LIM to add STA */ + sta_ds->qos.capability.qosInfo.acbe_uapsd = 0; + sta_ds->qos.capability.qosInfo.acbk_uapsd = 0; + sta_ds->qos.capability.qosInfo.acvo_uapsd = 0; + sta_ds->qos.capability.qosInfo.acvi_uapsd = 0; + sta_ds->qos.capability.qosInfo.maxSpLen = 0; + } else { + /* update UAPSD and send it to LIM to add STA */ + sta_ds->qos.capability.qosInfo.acbe_uapsd = + assoc_req->WMMInfoStation.acbe_uapsd; + sta_ds->qos.capability.qosInfo.acbk_uapsd = + assoc_req->WMMInfoStation.acbk_uapsd; + sta_ds->qos.capability.qosInfo.acvo_uapsd = + assoc_req->WMMInfoStation.acvo_uapsd; + sta_ds->qos.capability.qosInfo.acvi_uapsd = + assoc_req->WMMInfoStation.acvi_uapsd; + sta_ds->qos.capability.qosInfo.maxSpLen = + assoc_req->WMMInfoStation.max_sp_length; + } + } + if (assoc_req->wsmCapablePresent && (wsm_mode == eHAL_SET)) + sta_ds->wsmEnabled = true; + } + /* Re/Assoc Response frame to requesting STA */ + sta_ds->mlmStaContext.subType = sub_type; + + sta_ds->rmfEnabled = (pmf_connection) ? 1 : 0; + sta_ds->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + timer_id.fields.sessionId = session->peSessionId; + timer_id.fields.peerIdx = peer_idx; + retry_interval = mac_ctx->mlme_cfg->gen.pmf_sa_query_retry_interval; + if (cfg_min(CFG_PMF_SA_QUERY_RETRY_INTERVAL) > retry_interval) { + retry_interval = cfg_default(CFG_PMF_SA_QUERY_RETRY_INTERVAL); + } + if (sta_ds->rmfEnabled) { + sta_ds->ocv_enabled = lim_is_ocv_enable_in_assoc_req(mac_ctx, + assoc_req); + if (sta_ds->ocv_enabled) + sta_ds->last_ocv_done_freq = session->curr_op_freq; + /* Try to delete it before, creating.*/ + lim_delete_pmf_query_timer(sta_ds); + if (tx_timer_create(mac_ctx, &sta_ds->pmfSaQueryTimer, + "PMF SA Query timer", lim_pmf_sa_query_timer_handler, + timer_id.value, + SYS_MS_TO_TICKS((retry_interval * 1024) / 1000), + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create PMF SA Query timer"); + lim_reject_association(mac_ctx, sa, sub_type, + true, auth_type, peer_idx, false, + STATUS_UNSPECIFIED_FAILURE, + session); + return false; + } + pe_debug("Created pmf timer assoc-id:%d sta mac" QDF_MAC_ADDR_FMT, + sta_ds->assocId, QDF_MAC_ADDR_REF(sta_ds->staAddr)); + } + + if (assoc_req->ExtCap.present) { + lim_set_stads_rtt_cap(sta_ds, + (struct s_ext_cap *) assoc_req->ExtCap.bytes, mac_ctx); + } else { + sta_ds->timingMeasCap = 0; + pe_debug("ExtCap not present"); + } + lim_ap_check_6g_compatible_peer(mac_ctx, session); + return true; +} + +/** + * lim_update_sta_ctx() - add/del sta depending on connection state machine + * @mac_ctx: pointer to Global MAC structure + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sta_ds: station dph entry + * @update_ctx: indicates if STA context already exist + * + * Checks for SSID match + * + * Return: true of no error, false otherwise + */ +static bool lim_update_sta_ctx(struct mac_context *mac_ctx, struct pe_session *session, + tpSirAssocReq assoc_req, uint8_t sub_type, + tpDphHashNode sta_ds, uint8_t update_ctx) +{ + tLimMlmStates mlm_prev_state; + /* + * BTAMP: If STA context already exist (ie. update_ctx = 1) for this STA + * then we should delete the old one, and add the new STA. This is taken + * care of in the lim_del_sta() routine. + * + * Prior to BTAMP, we were setting this flag so that when PE receives + * SME_ASSOC_CNF, and if this flag is set, then PE shall delete the old + * station and then add. But now in BTAMP, we're directly adding station + * before waiting for SME_ASSOC_CNF, so we can do this now. + */ + if (!(update_ctx)) { + sta_ds->mlmStaContext.updateContext = 0; + + /* + * BTAMP: Add STA context at HW - issue WMA_ADD_STA_REQ to HAL + */ + if (lim_add_sta(mac_ctx, sta_ds, false, session) != + QDF_STATUS_SUCCESS) { + pe_err("could not Add STA with assocId: %d", + sta_ds->assocId); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + session); + + if (session->parsedAssocReq) + assoc_req = + session->parsedAssocReq[sta_ds->assocId]; + return false; + } + } else { + sta_ds->mlmStaContext.updateContext = 1; + mlm_prev_state = sta_ds->mlmStaContext.mlmState; + + /* + * As per the HAL/FW needs the reassoc req need not be calling + * lim_del_sta + */ + if (sub_type != LIM_REASSOC) { + /* + * we need to set the mlmState here in order + * differentiate in lim_del_sta. + */ + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE; + if (lim_del_sta(mac_ctx, sta_ds, true, session) + != QDF_STATUS_SUCCESS) { + pe_err("Couldn't DEL STA, assocId: %d sta mac" + QDF_MAC_ADDR_FMT, sta_ds->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + session); + + /* Restoring the state back. */ + sta_ds->mlmStaContext.mlmState = mlm_prev_state; + if (session->parsedAssocReq) + assoc_req = session->parsedAssocReq[ + sta_ds->assocId]; + return false; + } + } else { + /* + * mlmState is changed in lim_add_sta context use the + * same AID, already allocated + */ + if (lim_add_sta(mac_ctx, sta_ds, false, session) + != QDF_STATUS_SUCCESS) { + pe_err("UPASD not supported, REASSOC Failed"); + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + STATUS_TDLS_WAKEUP_REJECT, + session); + + /* Restoring the state back. */ + sta_ds->mlmStaContext.mlmState = mlm_prev_state; + if (session->parsedAssocReq) + assoc_req = session->parsedAssocReq[ + sta_ds->assocId]; + return false; + } + } + } + return true; +} + +void lim_process_assoc_cleanup(struct mac_context *mac_ctx, + struct pe_session *session, + tpSirAssocReq assoc_req, + tpDphHashNode sta_ds, + bool assoc_req_copied) +{ + tpSirAssocReq tmp_assoc_req; + + if (assoc_req) { + lim_free_assoc_req_frm_buf(assoc_req); + + qdf_mem_free(assoc_req); + /* to avoid double free */ + if (assoc_req_copied && session->parsedAssocReq && sta_ds) + session->parsedAssocReq[sta_ds->assocId] = NULL; + } + + /* If it is not duplicate Assoc request then only make to Null */ + if ((sta_ds) && + (sta_ds->mlmStaContext.mlmState != eLIM_MLM_WT_ADD_STA_RSP_STATE)) { + if (session->parsedAssocReq) { + tmp_assoc_req = + session->parsedAssocReq[sta_ds->assocId]; + if (tmp_assoc_req) { + lim_free_assoc_req_frm_buf(tmp_assoc_req); + qdf_mem_free(tmp_assoc_req); + session->parsedAssocReq[sta_ds->assocId] = NULL; + } + } + } +} + +/** + * lim_defer_sme_indication() - Defer assoc indication to SME + * @mac_ctx: Pointer to Global MAC structure + * @session: pe session entry + * @sub_type: Indicates whether it is Association Request(=0) or Reassociation + * Request(=1) frame + * @sa: Mac address of requesting peer + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @pmf_connection: flag indicating pmf connection + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * @dup_entry: flag indicating if duplicate entry found + * @partner_peer_idx: association id allocated by partner peer + * + * Defer Initialization of PE data structures and wait for an external event. + * lim_send_assoc_ind_to_sme() will be called to initialize PE data structures + * when the expected event is received. + * + * Return: void + */ +static void lim_defer_sme_indication(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t sub_type, + tSirMacAddr sa, + struct sSirAssocReq *assoc_req, + bool pmf_connection, + bool assoc_req_copied, + bool dup_entry, + struct sDphHashNode *sta_ds, + uint16_t partner_peer_idx) +{ + struct tLimPreAuthNode *sta_pre_auth_ctx; + struct lim_assoc_data *cached_req; + + /* Extract pre-auth context for the STA, if any. */ + sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, sa); + if (sta_pre_auth_ctx->assoc_req.present) { + pe_debug("Free the cached assoc req as a new one is received"); + cached_req = &sta_pre_auth_ctx->assoc_req; + lim_process_assoc_cleanup(mac_ctx, session, + cached_req->assoc_req, + cached_req->sta_ds, + cached_req->assoc_req_copied); + } + + sta_pre_auth_ctx->assoc_req.present = true; + sta_pre_auth_ctx->assoc_req.sub_type = sub_type; + qdf_mem_copy(sta_pre_auth_ctx->assoc_req.sa, sa, + sizeof(sta_pre_auth_ctx->assoc_req.sa)); + sta_pre_auth_ctx->assoc_req.assoc_req = assoc_req; + sta_pre_auth_ctx->assoc_req.pmf_connection = pmf_connection; + sta_pre_auth_ctx->assoc_req.assoc_req_copied = assoc_req_copied; + sta_pre_auth_ctx->assoc_req.dup_entry = dup_entry; + sta_pre_auth_ctx->assoc_req.sta_ds = sta_ds; + sta_pre_auth_ctx->assoc_req.partner_peer_idx = partner_peer_idx; +} + +static bool lim_is_sae_akm_present(tDot11fIERSN * const rsn_ie) +{ + uint16_t i; + + if (rsn_ie->akm_suite_cnt > 6) + return false; + + for (i = 0; i < rsn_ie->akm_suite_cnt; i++) { + if ((LE_READ_4(rsn_ie->akm_suite[i]) == RSN_AUTH_KEY_MGMT_SAE) || + (LE_READ_4(rsn_ie->akm_suite[i]) == + RSN_AUTH_KEY_MGMT_SAE_EXT_KEY)) { + pe_debug("SAE AKM present"); + return true; + } + } + return false; +} + +static bool lim_is_pmkid_found_for_peer(struct mac_context *mac_ctx, + tSirMacAddr peer_mac_addr, + struct pe_session *session, + uint8_t *pmkid, + uint16_t pmkid_count) +{ + uint32_t i; + uint8_t *session_pmkid; + struct wlan_crypto_pmksa *pmkid_cache; + + pmkid_cache = qdf_mem_malloc(sizeof(*pmkid_cache)); + + if (!pmkid_cache) + return false; + + qdf_mem_copy(pmkid_cache->bssid.bytes, peer_mac_addr, + QDF_MAC_ADDR_SIZE); + + if (!cm_lookup_pmkid_using_bssid(mac_ctx->psoc, session->vdev_id, + pmkid_cache)) { + qdf_mem_free(pmkid_cache); + return false; + } + + session_pmkid = pmkid_cache->pmkid; + for (i = 0; i < pmkid_count; i++) { + if (!qdf_mem_cmp(pmkid + (i * PMKID_LEN), + session_pmkid, PMKID_LEN)) { + qdf_mem_free(pmkid_cache); + return true; + } + } + + pe_debug("PMKID in cache doesn't match with PMKIDs from the peer"); + qdf_mem_free(pmkid_cache); + + return false; +} + +static bool lim_is_sae_peer_allowed(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIERSN *rsn_ie, tSirMacAddr sa, + enum wlan_status_code *mac_status_code) +{ + bool is_allowed = false; + uint8_t *peer_mac_addr = sa; + + /* Allow the peer with valid PMKID */ + if (!rsn_ie->pmkid_count) { + *mac_status_code = STATUS_NOT_SUPPORTED_AUTH_ALG; + pe_debug("No PMKID present in RSNIE; Tried to use SAE AKM after non-SAE authentication"); + } else if (lim_is_pmkid_found_for_peer(mac_ctx, peer_mac_addr, session, + &rsn_ie->pmkid[0][0], + rsn_ie->pmkid_count)) { + pe_debug("Valid PMKID found for SAE peer"); + is_allowed = true; + } else { + *mac_status_code = STATUS_INVALID_PMKID; + pe_debug("No valid PMKID found for SAE peer"); + } + + return is_allowed; +} + +static bool lim_validate_pmkid_for_sae(struct mac_context *mac_ctx, + struct pe_session *session, + tpSirAssocReq assoc_req, tSirMacAddr sa, + uint8_t sub_type) +{ + tDot11fIERSN rsn_ie = {0}; + enum wlan_status_code code = STATUS_INVALID_IE; + + if (!assoc_req->rsnPresent) + return true; + + if (dot11f_unpack_ie_rsn(mac_ctx, &assoc_req->rsn.info[0], + assoc_req->rsn.length, + &rsn_ie, false) != DOT11F_PARSE_SUCCESS) + goto reject_assoc; + + if (lim_is_sae_akm_present(&rsn_ie) && + !assoc_req->is_sae_authenticated && + !lim_is_sae_peer_allowed(mac_ctx, session, &rsn_ie, sa, &code)) + goto reject_assoc; + + return true; + +reject_assoc: + lim_send_assoc_rsp_mgmt_frame(mac_ctx, code, 1, sa, sub_type, 0, + session, false); + return false; +} + +bool lim_send_assoc_ind_to_sme(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t sub_type, tSirMacAddr sa, + tpSirAssocReq assoc_req, + enum ani_akm_type akm_type, + bool pmf_connection, bool *assoc_req_copied, + bool dup_entry, bool force_1x1, + uint16_t partner_peer_idx) +{ + uint16_t peer_idx; + struct tLimPreAuthNode *sta_pre_auth_ctx; + tpDphHashNode sta_ds = NULL; + tHalBitVal qos_mode; + tAniAuthType auth_type; + uint8_t update_ctx = false; + + limGetQosMode(session, &qos_mode); + /* Extract 'associated' context for STA, if any. */ + sta_ds = dph_lookup_hash_entry(mac_ctx, sa, &peer_idx, + &session->dph.dphHashTable); + + /* Extract pre-auth context for the STA, if any. */ + sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, sa); + + if (!sta_ds) { + if (!lim_process_assoc_req_no_sta_ctx(mac_ctx, sa, session, + assoc_req, sub_type, + sta_pre_auth_ctx, sta_ds, + &auth_type, + partner_peer_idx)) + return false; + } else { + if (!lim_process_assoc_req_sta_ctx(mac_ctx, sa, session, + assoc_req, sub_type, + sta_pre_auth_ctx, sta_ds, + peer_idx, &auth_type, + &update_ctx)) + return false; + goto send_ind_to_sme; + } + + if (LIM_IS_AP_ROLE(session)) { + if ((assoc_req->wpaPresent || assoc_req->rsnPresent) && + !session->privacy) { + pe_debug("reject assoc. wpa: %d, rsn: %d, privacy: %d", + assoc_req->wpaPresent, + assoc_req->rsnPresent, + session->privacy); + lim_reject_association(mac_ctx, sa, sub_type, true, + auth_type, peer_idx, false, + STATUS_UNSPECIFIED_FAILURE, + session); + return false; + } + } + + /* check if sta is allowed per QoS AC rules */ + if (!lim_chk_wmm(mac_ctx, sa, session, assoc_req, sub_type, qos_mode)) + return false; + + if (!lim_validate_pmkid_for_sae(mac_ctx, session, assoc_req, + sa, sub_type)) + return false; + + /* STA is Associated ! */ + pe_debug("Received: %s Req successful from " QDF_MAC_ADDR_FMT, + (sub_type == LIM_ASSOC) ? "Assoc" : "ReAssoc", + QDF_MAC_ADDR_REF(sa)); + + /* + * AID for this association will be same as the peer Index used in DPH + * table. Assign unused/least recently used peer Index from perStaDs. + * NOTE: lim_assign_peer_idx() assigns AID values ranging between + * 1 - cfg_item(WNI_CFG_ASSOC_STA_LIMIT) + */ + + if (wlan_vdev_mlme_is_mlo_ap(session->vdev) && + assoc_req->eht_cap.present && + IS_DOT11_MODE_EHT(session->dot11mode) && + (partner_peer_idx || + !qdf_is_macaddr_zero((struct qdf_mac_addr *)assoc_req->mld_mac))) + peer_idx = lim_assign_mlo_conn_idx(mac_ctx, session, + partner_peer_idx); + else + peer_idx = lim_assign_peer_idx(mac_ctx, session); + + if (!peer_idx && !partner_peer_idx) { + /* Could not assign AID. Reject association */ + pe_err("PeerIdx not available. Reject associaton"); + lim_reject_association(mac_ctx, sa, sub_type, + true, auth_type, peer_idx, false, + STATUS_UNSPECIFIED_FAILURE, + session); + return false; + } else if (!peer_idx) { + pe_err("mlo partner PeerIdx not available. Reject associaton"); + lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, sa, + session->smeSessionId); + return false; + } + + /* Add an entry to hash table maintained by DPH module */ + + sta_ds = dph_add_hash_entry(mac_ctx, sa, peer_idx, + &session->dph.dphHashTable); + + if (!sta_ds && !partner_peer_idx) { + /* Could not add hash table entry at DPH */ + pe_err("couldn't add hash entry at DPH for aid: %d MacAddr:" + QDF_MAC_ADDR_FMT, peer_idx, QDF_MAC_ADDR_REF(sa)); + + /* Release AID */ + if (wlan_vdev_mlme_is_mlo_ap(session->vdev) && + assoc_req->eht_cap.present && + IS_DOT11_MODE_EHT(session->dot11mode) && + (partner_peer_idx || assoc_req->mlo_info.num_partner_links)) + lim_release_mlo_conn_idx(mac_ctx, peer_idx, session, + true); + else + lim_release_peer_idx(mac_ctx, peer_idx, session); + + lim_reject_association(mac_ctx, sa, sub_type, + true, auth_type, peer_idx, false, + STATUS_UNSPECIFIED_FAILURE, + session); + return false; + } else if (!sta_ds) { + pe_err("mlo partner peer couldn't add hash entry at DPH for aid: %d MacAddr:" + QDF_MAC_ADDR_FMT, peer_idx, QDF_MAC_ADDR_REF(sa)); + lim_send_sme_max_assoc_exceeded_ntf(mac_ctx, sa, + session->smeSessionId); + return false; + } + + /*only mlo partner peer get valid aid before proc assoc req*/ + if (!partner_peer_idx) + lim_set_mlo_recv_assoc(sta_ds, true); + else + lim_set_mlo_recv_assoc(sta_ds, false); + +send_ind_to_sme: + if (!lim_update_sta_ds(mac_ctx, sa, session, assoc_req, + sub_type, sta_ds, auth_type, akm_type, + assoc_req_copied, peer_idx, qos_mode, + pmf_connection, force_1x1)) + return false; + + /* BTAMP: Storing the parsed assoc request in the session array */ + if (session->parsedAssocReq) + session->parsedAssocReq[sta_ds->assocId] = assoc_req; + *assoc_req_copied = true; + + /* If it is duplicate entry wait till the peer is deleted */ + if (!dup_entry) { + if (!lim_update_sta_ctx(mac_ctx, session, assoc_req, + sub_type, sta_ds, update_ctx)) + return false; + } + + /* AddSta is success here */ + if (LIM_IS_AP_ROLE(session) && IS_DOT11_MODE_HT(session->dot11mode) && + assoc_req->HTCaps.present && assoc_req->wmeInfoPresent) { + /* + * Update in the HAL Sta Table for the Update of the Protection + * Mode + */ + lim_post_sm_state_update(mac_ctx, + sta_ds->htMIMOPSState, sta_ds->staAddr, + session->smeSessionId); + } + + return true; +} + +/** + * lim_peer_present_on_any_sta() - Check if Same MAC is connected with STA, i.e. + * duplicate mac detection. + * @mac_ctx: Pointer to Global MAC structure + * @peer_addr: peer address to check + * + * This function will return true if a peer STA and AP are using same mac + * address. + * + * @Return: bool + */ +static bool +lim_peer_present_on_any_sta(struct mac_context *mac_ctx, uint8_t *peer_addr) +{ + struct wlan_objmgr_peer *peer; + bool sta_peer_present = false; + enum QDF_OPMODE mode; + uint8_t peer_vdev_id; + + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, peer_addr, + WLAN_LEGACY_MAC_ID); + if (!peer) + return sta_peer_present; + + peer_vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + mode = wlan_vdev_mlme_get_opmode(wlan_peer_get_vdev(peer)); + if (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) { + pe_debug("duplicate mac detected!!! Peer " QDF_MAC_ADDR_FMT " present on STA vdev %d", + QDF_MAC_ADDR_REF(peer_addr), peer_vdev_id); + sta_peer_present = true; + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + return sta_peer_present; +} + +QDF_STATUS lim_check_assoc_req(struct mac_context *mac_ctx, + uint8_t sub_type, tSirMacAddr sa, + struct pe_session *session) +{ + if (LIM_IS_STA_ROLE(session)) { + pe_err("Rcvd unexpected ASSOC REQ, sessionid: %d sys sub_type: %d for role: %d from: " + QDF_MAC_ADDR_FMT, + session->peSessionId, sub_type, + GET_LIM_SYSTEM_ROLE(session), + QDF_MAC_ADDR_REF(sa)); + return QDF_STATUS_E_INVAL; + } + + if (session->limMlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) { + pe_err("drop ASSOC REQ on sessionid: %d role: %d from: " + QDF_MAC_ADDR_FMT " in limMlmState: %d", + session->peSessionId, + GET_LIM_SYSTEM_ROLE(session), + QDF_MAC_ADDR_REF(sa), + eLIM_MLM_WT_DEL_BSS_RSP_STATE); + return QDF_STATUS_E_INVAL; + } + + if (lim_peer_present_on_any_sta(mac_ctx, sa)) + /* + * This mean a AP and STA have same mac address and device STA + * is already connected to the AP, and STA is now trying to + * connect to device SAP. So ignore association. + */ + return QDF_STATUS_E_INVAL; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_SUPPORT_TWT +/* lim_set_sap_peer_twt_cap() - Set SAP peer twt requestor and responder bit + * @session: PE session handle + * @ext_cap: pointer to ext cap + * + * This function is used to update SAP peer twt requestor and responder bit + * from ext cap of assoc request received by SAP + * + * Return: None + */ +static void lim_set_sap_peer_twt_cap(struct pe_session *session, + struct s_ext_cap *ext_cap) +{ + session->peer_twt_requestor = ext_cap->twt_requestor_support; + session->peer_twt_responder = ext_cap->twt_responder_support; + + pe_debug("Ext Cap peer TWT requestor: %d, responder: %d", + ext_cap->twt_requestor_support, + ext_cap->twt_responder_support); +} +#else +static inline void +lim_set_sap_peer_twt_cap(struct pe_session *session, + struct s_ext_cap *ext_cap) +{ +} +#endif + +/* lim_update_ap_ext_cap() - Update SAP with ext capabilities + * @session: PE session handle + * @ assoc_req: pointer to assoc req + * + * This function is called by lim_proc_assoc_req_frm_cmn to + * update SAP ext capabilities + * + * Return: None + */ +static void lim_update_ap_ext_cap(struct pe_session *session, + tpSirAssocReq assoc_req) +{ + struct s_ext_cap *ext_cap; + + ext_cap = (struct s_ext_cap *)assoc_req->ExtCap.bytes; + lim_set_sap_peer_twt_cap(session, ext_cap); +} + +QDF_STATUS lim_proc_assoc_req_frm_cmn(struct mac_context *mac_ctx, + uint8_t sub_type, + struct pe_session *session, + tSirMacAddr sa, + tpSirAssocReq assoc_req, + uint16_t peer_aid) +{ + bool pmf_connection = false, assoc_req_copied = false; + uint32_t phy_mode; + tHalBitVal qos_mode; + struct tLimPreAuthNode *sta_pre_auth_ctx; + enum ani_akm_type akm_type = ANI_AKM_TYPE_NONE; + tSirMacCapabilityInfo local_cap; + tpDphHashNode sta_ds = NULL; + bool dup_entry = false, force_1x1 = false; + QDF_STATUS status; + uint8_t *frm_body; + uint32_t frame_len; + + frm_body = assoc_req->assocReqFrame; + frame_len = assoc_req->assocReqFrameLength; + lim_get_phy_mode(mac_ctx, &phy_mode, session); + limGetQosMode(session, &qos_mode); + + if (!lim_chk_assoc_req_parse_error(mac_ctx, sa, session, + assoc_req, sub_type, + frm_body, frame_len)) + goto error; + + status = lim_check_sta_in_pe_entries(mac_ctx, sa, assoc_req->mld_mac, + session->peSessionId, + &dup_entry); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Reject assoc as duplicate entry is present and is already being deleted, assoc will be accepted once deletion is completed"); + /* + * This mean that the duplicate entry is present on other vdev + * and is already being deleted, so reject the assoc and lets + * peer try again to connect, once peer is deleted from + * other vdev. + */ + if (!peer_aid) + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, + STATUS_UNSPECIFIED_FAILURE, + 1, sa, + sub_type, 0, session, false); + goto error; + } + /* check for the presence of vendor IE */ + if (session->access_policy_vendor_ie && + session->access_policy == + LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT) { + if (frame_len <= LIM_ASSOC_REQ_IE_OFFSET) { + pe_debug("Received action frame of invalid len %d", + frame_len); + goto error; + } + if (!wlan_get_vendor_ie_ptr_from_oui( + &session->access_policy_vendor_ie[2], + 3, frm_body + LIM_ASSOC_REQ_IE_OFFSET, + frame_len - LIM_ASSOC_REQ_IE_OFFSET)) { + pe_err("Vendor ie not present and access policy is %x, Rejected association", + session->access_policy); + if (!peer_aid) + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_UNSPECIFIED_FAILURE, + 1, sa, sub_type, 0, session, false); + goto error; + } + } + + + if (!lim_chk_capab(mac_ctx, sa, session, assoc_req, + sub_type, &local_cap)) + goto error; + + if (!lim_chk_ssid(mac_ctx, sa, session, assoc_req, sub_type)) + goto error; + + if (!lim_chk_rates(mac_ctx, sa, session, assoc_req, sub_type)) + goto error; + + if (!lim_chk_11g_only(mac_ctx, sa, session, assoc_req, + sub_type)) + goto error; + + if (!lim_chk_11n_only(mac_ctx, sa, session, assoc_req, + sub_type)) + goto error; + + if (!lim_chk_11ac_only(mac_ctx, sa, session, assoc_req, + sub_type)) + goto error; + + if (!lim_chk_11ax_only(mac_ctx, sa, session, assoc_req, + sub_type)) + goto error; + + if (!lim_chk_11be_only(mac_ctx, sa, session, assoc_req, + sub_type)) + goto error; + + if (!lim_check_11ax_basic_mcs(mac_ctx, sa, session, assoc_req, + sub_type)) + goto error; + + /* Spectrum Management (11h) specific checks */ + lim_process_for_spectrum_mgmt(mac_ctx, sa, session, + assoc_req, sub_type, local_cap); + + if (!lim_chk_mcs(mac_ctx, sa, session, assoc_req, sub_type)) + goto error; + + if (!lim_chk_is_11b_sta_supported(mac_ctx, sa, session, + assoc_req, sub_type, phy_mode)) + goto error; + + /* + * Check for 802.11n HT caps compatibility; are HT Capabilities + * turned on in lim? + */ + lim_print_ht_cap(mac_ctx, session, assoc_req); + + if (!lim_chk_n_process_wpa_rsn_ie(mac_ctx, sa, session, + assoc_req, sub_type, + &pmf_connection, + &akm_type)) + goto error; + + /* Update ap ext cap */ + lim_update_ap_ext_cap(session, assoc_req); + + /* Extract pre-auth context for the STA, if any. */ + sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, sa); + + /* SAE authentication is offloaded to hostapd. Hostapd sends + * authentication status to driver after completing SAE + * authentication (after sending out 4/4 SAE auth frame). + * There is a possible race condition where driver gets + * assoc request from SAE station before getting authentication + * status from hostapd. Don't reject the association in such + * cases and defer the processing of assoc request frame by caching + * the frame and process it when the auth status is received. + */ + if (sta_pre_auth_ctx && + sta_pre_auth_ctx->authType == eSIR_AUTH_TYPE_SAE && + sta_pre_auth_ctx->mlmState == eLIM_MLM_WT_SAE_AUTH_STATE) { + pe_debug("Received assoc request frame while SAE authentication is in progress; Defer association request handling till SAE auth status is received"); + lim_defer_sme_indication(mac_ctx, session, sub_type, sa, + assoc_req, pmf_connection, + assoc_req_copied, dup_entry, sta_ds, + peer_aid); + + return QDF_STATUS_SUCCESS; + } + + if (session->opmode == QDF_P2P_GO_MODE) { + /* + * WAR: In P2P GO mode, if the P2P client device + * is only HT capable and not VHT capable, but the P2P + * GO device is VHT capable and advertises 2x2 NSS with + * HT capability client device, which results in IOT + * issues. + * When GO is operating in DBS mode, GO beacons + * advertise 2x2 capability but include OMN IE to + * indicate current operating mode of 1x1. But here + * peer device is only HT capable and will not + * understand OMN IE. + */ + force_1x1 = wlan_p2p_check_oui_and_force_1x1( + frm_body + LIM_ASSOC_REQ_IE_OFFSET, + frame_len - LIM_ASSOC_REQ_IE_OFFSET); + } + + /* Send assoc indication to SME */ + if (!lim_send_assoc_ind_to_sme(mac_ctx, session, sub_type, sa, + assoc_req, akm_type, pmf_connection, + &assoc_req_copied, dup_entry, force_1x1, + peer_aid)) + goto error; + + return QDF_STATUS_SUCCESS; + +error: + lim_process_assoc_cleanup(mac_ctx, session, assoc_req, sta_ds, + assoc_req_copied); + + return QDF_STATUS_E_FAILURE; +} + +/** + * lim_process_assoc_req_frame() - Process RE/ASSOC Request frame. + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to Buffer descriptor + associated PDUs + * @sub_type: Indicates whether it is Association Request(=0) or Reassociation + * Request(=1) frame + * @session: pe session entry + * + * This function is called to process RE/ASSOC Request frame. + * + * @Return: void + */ +void lim_process_assoc_req_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, + uint8_t sub_type, + struct pe_session *session) +{ + uint8_t *frm_body; + uint16_t assoc_id = 0; + uint32_t frame_len; + tpSirMacMgmtHdr hdr; + tpDphHashNode sta_ds = NULL; + struct wlan_objmgr_vdev *vdev; + tpSirAssocReq assoc_req; + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_nofl_rl_debug("Assoc req RX: subtype %d vdev %d sys role %d lim state %d rssi %d from " QDF_MAC_ADDR_FMT, + sub_type, session->vdev_id, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + QDF_MAC_ADDR_REF(hdr->sa)); + + if (QDF_IS_STATUS_ERROR(lim_check_assoc_req(mac_ctx, sub_type, + hdr->sa, session))) + return; + + vdev = session->vdev; + if (!vdev) { + pe_err("vdev is NULL"); + return; + } + + if (wlan_vdev_mlme_get_state(vdev) != WLAN_VDEV_S_UP || + wlan_vdev_mlme_get_substate(vdev) != WLAN_VDEV_SS_UP_ACTIVE) { + pe_err("SAP is not up, drop ASSOC REQ on sessionid: %d", + session->peSessionId); + + return; + } + + /* + * If a STA is already present in DPH and it is initiating a Assoc + * re-transmit, do not process it. This can happen when first Assoc Req + * frame is received but ACK lost at STA side. The ACK for this dropped + * Assoc Req frame should be sent by HW. Host simply does not process it + * once the entry for the STA is already present in DPH. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, hdr->sa, &assoc_id, + &session->dph.dphHashTable); + if (sta_ds && !sta_ds->rmfEnabled) { + /* + * Drop only retries for non-PMF assoc requests. + * For PMF case: + * a) Before key installation - Drop assoc request + * b) After key installation - Send SA query + */ + if (hdr->fc.retry > 0) { + pe_err("STA is initiating Assoc Req after ACK lost. Do not process sessionid: %d sys sub_type=%d for role=%d from: " + QDF_MAC_ADDR_FMT, session->peSessionId, + sub_type, GET_LIM_SYSTEM_ROLE(session), + QDF_MAC_ADDR_REF(hdr->sa)); + return; + } else if (sub_type == LIM_REASSOC) { + /* + * SAP should send reassoc response with reject code + * to avoid IOT issues. as per the specification SAP + * should do 4-way handshake after reassoc response and + * some STA doesn't like 4way handshake after reassoc + * where some STA does expect 4-way handshake. + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, STATUS_ASSOC_DENIED_UNSPEC, + sta_ds->assocId, sta_ds->staAddr, + sub_type, sta_ds, session, false); + pe_err("Rejecting reassoc req from STA"); + return; + } else { + /* + * Do this only for non PMF case. + * STA might have missed the assoc response, so it is + * sending assoc request frame again. + */ + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, QDF_STATUS_SUCCESS, + sta_ds->assocId, sta_ds->staAddr, + sub_type, + sta_ds, session, false); + pe_err("DUT already received an assoc request frame and STA is sending another assoc req.So, do not Process sessionid: %d sys sub_type: %d for role: %d from: " + QDF_MAC_ADDR_FMT, + session->peSessionId, sub_type, + session->limSystemRole, + QDF_MAC_ADDR_REF(hdr->sa)); + return; + } + } else if (sta_ds && sta_ds->rmfEnabled && !sta_ds->is_key_installed) { + /* When PMF enabled, SA Query will be triggered + * unexpectedly if duplicated assoc_req received - + * 1) after pre_auth node deleted and + * 2) before key installed. + * Here drop such duplicated assoc_req frame. + */ + pe_err("Drop duplicate assoc_req before 4-way HS"); + return; + } + + /* Get pointer to Re/Association Request frame body */ + frm_body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + if (IEEE80211_IS_MULTICAST(hdr->sa)) { + /* + * Rcvd Re/Assoc Req frame from BC/MC address Log error and + * ignore it + */ + pe_err("Rcvd: %s Req, sessionid: %d from a BC/MC address" + QDF_MAC_ADDR_FMT, + (LIM_ASSOC == sub_type) ? "Assoc" : "ReAssoc", + session->peSessionId, QDF_MAC_ADDR_REF(hdr->sa)); + return; + } + + if (false == lim_chk_sa_da(mac_ctx, hdr, session, sub_type)) + return; + + /* Allocate memory for the Assoc Request frame */ + assoc_req = qdf_mem_malloc(sizeof(*assoc_req)); + if (!assoc_req) + return; + + if (!lim_alloc_assoc_req_frm_buf(assoc_req, + WMA_GET_QDF_NBUF(rx_pkt_info), + WMA_GET_RX_MAC_HEADER_LEN(rx_pkt_info), + frame_len)) + goto error; + + lim_proc_assoc_req_frm_cmn(mac_ctx, sub_type, session, hdr->sa, + assoc_req, 0); + + if (sub_type == LIM_ASSOC) { + lim_cp_stats_cstats_log_assoc_req_evt + (session, CSTATS_DIR_RX, hdr->bssId, hdr->sa, + assoc_req->ssId.length, assoc_req->ssId.ssId, + assoc_req->HTCaps.present, assoc_req->VHTCaps.present, + assoc_req->he_cap.present, assoc_req->eht_cap.present, + false); + } else if (sub_type == LIM_REASSOC) { + lim_cp_stats_cstats_log_assoc_req_evt + (session, CSTATS_DIR_RX, hdr->bssId, hdr->sa, + assoc_req->ssId.length, assoc_req->ssId.ssId, + assoc_req->HTCaps.present, assoc_req->VHTCaps.present, + assoc_req->he_cap.present, assoc_req->eht_cap.present, + true); + } + + return; +error: + if (assoc_req) { + lim_free_assoc_req_frm_buf(assoc_req); + qdf_mem_free(assoc_req); + } +} + +#ifdef FEATURE_WLAN_WAPI +/** + * lim_fill_assoc_ind_wapi_info()- Updates WAPI data in assoc indication + * @mac_ctx: Global Mac context + * @assoc_req: pointer to association request + * @assoc_ind: Pointer to association indication + * @wpsie: WPS IE + * + * This function updates WAPI meta data in association indication message + * sent to SME. + * + * Return: None + */ +static void lim_fill_assoc_ind_wapi_info(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, tpLimMlmAssocInd assoc_ind, + const uint8_t *wpsie) +{ + if (assoc_req->wapiPresent && (!wpsie)) { + pe_debug("Received WAPI IE length in Assoc Req is %d", + assoc_req->wapi.length); + assoc_ind->wapiIE.wapiIEdata[0] = WLAN_ELEMID_WAPI; + assoc_ind->wapiIE.wapiIEdata[1] = assoc_req->wapi.length; + qdf_mem_copy(&assoc_ind->wapiIE.wapiIEdata[2], + assoc_req->wapi.info, assoc_req->wapi.length); + assoc_ind->wapiIE.length = + 2 + assoc_req->wapi.length; + } + return; +} +#else +static void lim_fill_assoc_ind_wapi_info( + struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, tpLimMlmAssocInd assoc_ind, + const uint8_t *wpsie) +{ +} +#endif + +#ifdef WLAN_FEATURE_11AX +static bool lim_fill_assoc_he_info(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirAssocReq assoc_req, + tpLimMlmAssocInd assoc_ind) +{ + if (session_entry->he_capable && assoc_req->he_cap.present) { + if (session_entry->limRFBand == REG_BAND_2G) { + if (session_entry->ch_width == CH_WIDTH_20MHZ) + assoc_ind->chan_info.info = MODE_11AX_HE20; + else if (session_entry->ch_width == CH_WIDTH_40MHZ && + assoc_req->he_cap.chan_width_0 == 1) + assoc_ind->chan_info.info = MODE_11AX_HE40; + else + assoc_ind->chan_info.info = MODE_11AX_HE20; + } else { + if (session_entry->ch_width == CH_WIDTH_160MHZ && + assoc_req->he_cap.chan_width_2 == 1) + assoc_ind->chan_info.info = MODE_11AX_HE160; + else if (session_entry->ch_width >= CH_WIDTH_80MHZ && + assoc_req->he_cap.chan_width_1 == 1) + assoc_ind->chan_info.info = MODE_11AX_HE80; + else if (session_entry->ch_width >= CH_WIDTH_40MHZ && + assoc_req->he_cap.chan_width_1 == 1) + assoc_ind->chan_info.info = MODE_11AX_HE40; + else + assoc_ind->chan_info.info = MODE_11AX_HE20; + } + return true; + } + + return false; +} +#else +static bool lim_fill_assoc_he_info(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirAssocReq assoc_req, + tpLimMlmAssocInd assoc_ind) +{ + return false; +} +#endif +/** + * lim_fill_assoc_ind_info() - Updates HE/VHT/HT information in assoc indication + * @mac_ctx: Global Mac context + * @assoc_req: pointer to association request + * @session_entry: PE session entry + * @assoc_ind: Pointer to association indication + * + * This function updates VHT information in association indication message + * sent to SME. + * + * Return: None + */ +static void lim_fill_assoc_ind_info(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirAssocReq assoc_req, + tpLimMlmAssocInd assoc_ind, + tpDphHashNode sta_ds) +{ + uint8_t chan; + uint8_t i; + bool nw_type_11b = true; + uint32_t cfreq = 0; + enum reg_wifi_band band; + + band = wlan_reg_freq_to_band(session_entry->curr_op_freq); + cfreq = wlan_reg_chan_band_to_freq(mac_ctx->pdev, + session_entry->ch_center_freq_seg0, BIT(band)); + assoc_ind->chan_info.band_center_freq1 = cfreq; + if (session_entry->ch_center_freq_seg1) { + cfreq = wlan_reg_chan_band_to_freq(mac_ctx->pdev, + session_entry->ch_center_freq_seg1, BIT(band)); + assoc_ind->chan_info.band_center_freq2 = cfreq; + } + if (session_entry->ch_width == CH_WIDTH_40MHZ) { + if (session_entry->htSecondaryChannelOffset == + PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + assoc_ind->chan_info.band_center_freq1 += 10; + else + assoc_ind->chan_info.band_center_freq1 -= 10; + } + if (lim_fill_assoc_he_info(mac_ctx, session_entry, + assoc_req, assoc_ind)) + return; + + if (session_entry->limRFBand == REG_BAND_2G) { + if (session_entry->vhtCapability + && assoc_req->VHTCaps.present) { + assoc_ind->chan_info.info = MODE_11AC_VHT20_2G; + } else if (session_entry->htCapability + && assoc_req->HTCaps.present) { + assoc_ind->chan_info.info = MODE_11NG_HT20; + } else { + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (sirIsArate(sta_ds-> + supportedRates.llaRates[i] + & 0x7F)) { + assoc_ind->chan_info.info = MODE_11G; + nw_type_11b = false; + break; + } + } + if (nw_type_11b) + assoc_ind->chan_info.info = MODE_11B; + } + return; + } + + if (session_entry->vhtCapability && assoc_req->VHTCaps.present) { + if ((session_entry->ch_width > CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + chan = session_entry->ch_center_freq_seg0; + assoc_ind->chan_info.band_center_freq1 = + cds_chan_to_freq(chan); + assoc_ind->chan_info.info = MODE_11AC_VHT80; + return; + } + + if ((session_entry->ch_width == CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + assoc_ind->chan_info.info = MODE_11AC_VHT40; + return; + } + + assoc_ind->chan_info.info = MODE_11AC_VHT20; + return; + } + + if (session_entry->htCapability && assoc_req->HTCaps.present) { + if ((session_entry->ch_width == CH_WIDTH_40MHZ) + && assoc_req->HTCaps.supportedChannelWidthSet) { + assoc_ind->chan_info.info = MODE_11NA_HT40; + return; + } + + assoc_ind->chan_info.info = MODE_11NA_HT20; + return; + } + + assoc_ind->chan_info.info = MODE_11A; + return; +} + +static void fill_mlm_assoc_ind_vht(tpSirAssocReq assocreq, + tpDphHashNode stads, + tpLimMlmAssocInd assocind) +{ + if (stads->mlmStaContext.vhtCapability) { + /* ampdu */ + assocind->ampdu = true; + + /* sgi */ + if (assocreq->VHTCaps.shortGI80MHz || + assocreq->VHTCaps.shortGI160and80plus80MHz) + assocind->sgi_enable = true; + + /* stbc */ + assocind->tx_stbc = assocreq->VHTCaps.txSTBC; + assocind->rx_stbc = assocreq->VHTCaps.rxSTBC; + + /* ch width */ + assocind->ch_width = stads->vhtSupportedChannelWidthSet ? + eHT_CHANNEL_WIDTH_80MHZ : + stads->htSupportedChannelWidthSet ? + eHT_CHANNEL_WIDTH_40MHZ : eHT_CHANNEL_WIDTH_20MHZ; + + /* mode */ + assocind->mode = SIR_SME_PHY_MODE_VHT; + assocind->rx_mcs_map = assocreq->VHTCaps.rxMCSMap & 0xff; + assocind->tx_mcs_map = assocreq->VHTCaps.txMCSMap & 0xff; + } +} + +/** + *lim_convert_channel_width_enum() - map between two channel width enums + *@ch_width: channel width of enum type phy_ch_width + * + *Return: channel width of enum type tSirMacHTChannelWidth + */ +static tSirMacHTChannelWidth +lim_convert_channel_width_enum(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + return eHT_CHANNEL_WIDTH_20MHZ; + case CH_WIDTH_40MHZ: + return eHT_CHANNEL_WIDTH_40MHZ; + case CH_WIDTH_80MHZ: + return eHT_CHANNEL_WIDTH_80MHZ; + case CH_WIDTH_160MHZ: + return eHT_CHANNEL_WIDTH_160MHZ; + case CH_WIDTH_80P80MHZ: + return eHT_CHANNEL_WIDTH_80P80MHZ; + case CH_WIDTH_320MHZ: + return eHT_CHANNEL_WIDTH_320MHZ; + case CH_WIDTH_MAX: + return eHT_MAX_CHANNEL_WIDTH; + case CH_WIDTH_5MHZ: + break; + case CH_WIDTH_10MHZ: + break; + case CH_WIDTH_INVALID: + break; + } + pe_debug("invalid enum: %d", ch_width); + return eHT_CHANNEL_WIDTH_20MHZ; +} + +/** + * lim_convert_rate_flags_enum() - map between channel width and rate flag enums + * @rate_flags: the current rate flags + * @ch_width: channel width of enum type phy_ch_width + * + * Return: updated rate flags per ch width + */ +static uint32_t lim_convert_rate_flags_enum(uint32_t rate_flags, + enum phy_ch_width ch_width) +{ + if (rate_flags & (TX_RATE_HE160 | + TX_RATE_HE80 | + TX_RATE_HE40 | + TX_RATE_HE20)) { + switch (ch_width) { + case CH_WIDTH_20MHZ: + rate_flags |= TX_RATE_HE20; + break; + case CH_WIDTH_40MHZ: + rate_flags |= TX_RATE_HE40; + break; + case CH_WIDTH_80MHZ: + rate_flags |= TX_RATE_HE80; + break; + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + rate_flags |= TX_RATE_HE160; + break; + default: + break; + } + } else if (rate_flags & (TX_RATE_VHT160 | + TX_RATE_VHT80 | + TX_RATE_VHT40 | + TX_RATE_VHT20)) { + switch (ch_width) { + case CH_WIDTH_20MHZ: + rate_flags |= TX_RATE_VHT20; + break; + case CH_WIDTH_40MHZ: + rate_flags |= TX_RATE_VHT40; + break; + case CH_WIDTH_80MHZ: + rate_flags |= TX_RATE_VHT80; + break; + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + rate_flags |= TX_RATE_VHT160; + break; + default: + break; + } + } else { + switch (ch_width) { + case CH_WIDTH_20MHZ: + rate_flags |= TX_RATE_HT20; + break; + case CH_WIDTH_40MHZ: + rate_flags |= TX_RATE_HT40; + break; + default: + break; + } + } + return rate_flags; +} + +static void lim_fill_assoc_ind_he_bw_info(tpLimMlmAssocInd assoc_ind, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + if (lim_is_sta_he_capable(sta_ds) && + lim_is_session_he_capable(session_entry)) { + assoc_ind->ch_width = + lim_convert_channel_width_enum(sta_ds->ch_width); + assoc_ind->chan_info.rate_flags = + lim_convert_rate_flags_enum(assoc_ind->chan_info.rate_flags, + sta_ds->ch_width); + } +} + +/** + * lim_fill_assoc_ind_real_max_mcs_idx() - fill max real mcs index to assoc ind + * @assoc_ind: assoc_ind to fill + * @assoc_req: pointer to tpSirAssocReq + * @sta_ds: pointer to tpDphHashNode + * @session: pointer to session + * + * Return: void + */ +static void lim_fill_assoc_ind_real_max_mcs_idx(tpLimMlmAssocInd assoc_ind, + tpSirAssocReq assoc_req, + tpDphHashNode sta_ds, + struct pe_session *session) +{ + assoc_ind->max_real_mcs_idx = INVALID_MCS_NSS_INDEX; + + if (lim_is_sta_he_capable(sta_ds) && + lim_is_session_he_capable(session)) + assoc_ind->max_real_mcs_idx = lim_get_he_max_mcs_idx( + sta_ds->ch_width, &assoc_req->he_cap); + + if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX && + sta_ds->mlmStaContext.vhtCapability) + assoc_ind->max_real_mcs_idx = + lim_get_vht_max_mcs_idx(&assoc_req->VHTCaps); + + if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX) + assoc_ind->max_real_mcs_idx = assoc_ind->max_mcs_idx; + + if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX) + assoc_ind->max_real_mcs_idx = assoc_ind->max_ext_idx; + + if (assoc_ind->max_real_mcs_idx == INVALID_MCS_NSS_INDEX) + assoc_ind->max_real_mcs_idx = assoc_ind->max_supp_idx; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +lim_fill_lim_assoc_ind_mac_addr_copy(tpLimMlmAssocInd assoc_ind, + tpDphHashNode sta_ds, + uint32_t num_bytes) +{ + qdf_mem_copy((uint8_t *)assoc_ind->peer_mld_addr, + (uint8_t *)sta_ds->mld_addr, + num_bytes); +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +lim_fill_lim_assoc_ind_mac_addr_copy(tpLimMlmAssocInd assoc_ind, + tpDphHashNode sta_ds, + uint32_t num_bytes) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +bool lim_fill_lim_assoc_ind_params( + tpLimMlmAssocInd assoc_ind, + struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + tpSirAssocReq assoc_req; + uint16_t rsn_len; + uint32_t phy_mode; + const uint8_t *wpsie = NULL; + bool wme_enable; + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *mlme_obj; + uint8_t country_iso[REG_ALPHA2_LEN + 1]; + tDot11fIESuppOperatingClasses *oper_class; + + if (!session_entry->parsedAssocReq) { + pe_err(" Parsed Assoc req is NULL"); + return false; + } + + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq)session_entry->parsedAssocReq[sta_ds->assocId]; + + if (!assoc_req) { + pe_err("assoc req for assoc_id:%d is NULL", sta_ds->assocId); + return false; + } + + /* Get the phy_mode */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + qdf_mem_copy((uint8_t *)assoc_ind->peerMacAddr, + (uint8_t *)sta_ds->staAddr, sizeof(tSirMacAddr)); + lim_fill_lim_assoc_ind_mac_addr_copy(assoc_ind, sta_ds, + sizeof(tSirMacAddr)); + assoc_ind->aid = sta_ds->assocId; + qdf_mem_copy((uint8_t *)&assoc_ind->ssId, + (uint8_t *)&assoc_req->ssId, + assoc_req->ssId.length + 1); + assoc_ind->sessionId = session_entry->peSessionId; + assoc_ind->authType = sta_ds->mlmStaContext.authType; + assoc_ind->akm_type = sta_ds->mlmStaContext.akm_type; + assoc_ind->capabilityInfo = assoc_req->capabilityInfo; + + /* Fill in RSN IE information */ + assoc_ind->rsnIE.length = 0; + /* if WPS IE is present, ignore RSN IE */ + if (assoc_req->addIEPresent && assoc_req->addIE.length) { + wpsie = limGetWscIEPtr( + mac_ctx, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + } + if (assoc_req->rsnPresent && !wpsie) { + pe_debug("Assoc Req RSN IE len: %d", + assoc_req->rsn.length); + assoc_ind->rsnIE.length = 2 + assoc_req->rsn.length; + assoc_ind->rsnIE.rsnIEdata[0] = WLAN_ELEMID_RSN; + assoc_ind->rsnIE.rsnIEdata[1] = + assoc_req->rsn.length; + qdf_mem_copy( + &assoc_ind->rsnIE.rsnIEdata[2], + assoc_req->rsn.info, + assoc_req->rsn.length); + } + /* Fill in 802.11h related info */ + if (assoc_req->powerCapabilityPresent && + assoc_req->supportedChannelsPresent) { + assoc_ind->spectrumMgtIndicator = true; + assoc_ind->powerCap.minTxPower = + assoc_req->powerCapability.minTxPower; + assoc_ind->powerCap.maxTxPower = + assoc_req->powerCapability.maxTxPower; + lim_convert_supported_channels( + mac_ctx, assoc_ind, + assoc_req); + } else { + assoc_ind->spectrumMgtIndicator = false; + } + + /* This check is to avoid extra Sec IEs present incase of WPS */ + if (assoc_req->wpaPresent && !wpsie) { + rsn_len = assoc_ind->rsnIE.length; + if ((rsn_len + assoc_req->wpa.length) + >= WLAN_MAX_IE_LEN) { + pe_err("rsnIEdata index out of bounds: %d", + rsn_len); + return false; + } + assoc_ind->rsnIE.rsnIEdata[rsn_len] = + SIR_MAC_WPA_EID; + assoc_ind->rsnIE.rsnIEdata[rsn_len + 1] + = assoc_req->wpa.length; + qdf_mem_copy( + &assoc_ind->rsnIE.rsnIEdata[rsn_len + 2], + assoc_req->wpa.info, assoc_req->wpa.length); + assoc_ind->rsnIE.length += 2 + assoc_req->wpa.length; + } + lim_fill_assoc_ind_wapi_info(mac_ctx, assoc_req, assoc_ind, wpsie); + + assoc_ind->addIE.length = 0; + if (assoc_req->addIEPresent) { + qdf_mem_copy( + &assoc_ind->addIE.addIEdata, + assoc_req->addIE.addIEdata, + assoc_req->addIE.length); + assoc_ind->addIE.length = assoc_req->addIE.length; + } + /* + * Add HT Capabilities into addIE for OBSS + * processing in hostapd + */ + if (assoc_req->HTCaps.present) { + qdf_mem_copy(&assoc_ind->ht_caps, &assoc_req->HTCaps, + sizeof(tDot11fIEHTCaps)); + rsn_len = assoc_ind->addIE.length; + if (assoc_ind->addIE.length + DOT11F_IE_HTCAPS_MIN_LEN + + 2 < WLAN_MAX_IE_LEN) { + assoc_ind->addIE.addIEdata[rsn_len] = + WLAN_ELEMID_HTCAP_ANA; + assoc_ind->addIE.addIEdata[rsn_len + 1] = + DOT11F_IE_HTCAPS_MIN_LEN; + qdf_mem_copy( + &assoc_ind->addIE.addIEdata[rsn_len + 2], + ((uint8_t *)&assoc_req->HTCaps) + 1, + DOT11F_IE_HTCAPS_MIN_LEN); + assoc_ind->addIE.length += + 2 + DOT11F_IE_HTCAPS_MIN_LEN; + } else { + pe_err("Fail:HT capabilities IE to addIE"); + } + } + + if (assoc_req->wmeInfoPresent) { + /* Set whether AP is enabled with WMM or not */ + wme_enable = mac_ctx->mlme_cfg->wmm_params.wme_enabled; + assoc_ind->WmmStaInfoPresent = wme_enable; + /* + * Note: we are not rejecting association here + * because IOT will fail + */ + } + /* Required for indicating the frames to upper layer */ + assoc_ind->assocReqLength = assoc_req->assocReqFrameLength; + assoc_ind->assocReqPtr = assoc_req->assocReqFrame; + + assoc_ind->chan_info.mhz = session_entry->curr_op_freq; + assoc_ind->chan_info.band_center_freq1 = + session_entry->curr_op_freq; + assoc_ind->chan_info.band_center_freq2 = 0; + assoc_ind->chan_info.reg_info_1 = + (session_entry->maxTxPower << 16); + assoc_ind->chan_info.reg_info_2 = + (session_entry->maxTxPower << 8); + assoc_ind->chan_info.nss = sta_ds->nss; + assoc_ind->chan_info.rate_flags = + lim_get_max_rate_flags(mac_ctx, sta_ds); + assoc_ind->ampdu = false; + assoc_ind->sgi_enable = false; + assoc_ind->tx_stbc = false; + assoc_ind->rx_stbc = false; + assoc_ind->ch_width = eHT_CHANNEL_WIDTH_20MHZ; + assoc_ind->mode = SIR_SME_PHY_MODE_LEGACY; + assoc_ind->max_supp_idx = INVALID_MCS_NSS_INDEX; + assoc_ind->max_ext_idx = INVALID_MCS_NSS_INDEX; + assoc_ind->max_mcs_idx = INVALID_MCS_NSS_INDEX; + assoc_ind->rx_mcs_map = 0xff; + assoc_ind->tx_mcs_map = 0xff; + + if (assoc_req->supportedRates.numRates) + assoc_ind->max_supp_idx = + lim_get_max_rate_idx(&assoc_req->supportedRates); + if (assoc_req->extendedRates.numRates) + assoc_ind->max_ext_idx = + lim_get_max_rate_idx(&assoc_req->extendedRates); + + if (sta_ds->mlmStaContext.htCapability) { + /* ampdu */ + assoc_ind->ampdu = true; + + /* sgi */ + if (sta_ds->htShortGI20Mhz || sta_ds->htShortGI40Mhz) + assoc_ind->sgi_enable = true; + + /* stbc */ + assoc_ind->tx_stbc = assoc_req->HTCaps.txSTBC; + assoc_ind->rx_stbc = assoc_req->HTCaps.rxSTBC; + + /* ch width */ + assoc_ind->ch_width = + sta_ds->htSupportedChannelWidthSet ? + eHT_CHANNEL_WIDTH_40MHZ : + eHT_CHANNEL_WIDTH_20MHZ; + /* mode */ + assoc_ind->mode = SIR_SME_PHY_MODE_HT; + assoc_ind->max_mcs_idx = lim_get_ht_max_mcs_idx( + &assoc_req->HTCaps); + } + fill_mlm_assoc_ind_vht(assoc_req, sta_ds, assoc_ind); + if (assoc_req->ExtCap.present) { + assoc_ind->ecsa_capable = + ((struct s_ext_cap *)assoc_req->ExtCap.bytes)->ext_chan_switch; + if (assoc_req->ExtCap.num_bytes >= sizeof(assoc_ind->ext_cap)) + qdf_mem_copy(&assoc_ind->ext_cap, + assoc_req->ExtCap.bytes, + sizeof(assoc_ind->ext_cap)); + else + qdf_mem_copy(&assoc_ind->ext_cap, + assoc_req->ExtCap.bytes, + assoc_req->ExtCap.num_bytes); + } + + if (assoc_req->supp_operating_classes.present) { + oper_class = &assoc_req->supp_operating_classes; + qdf_mem_zero(country_iso, sizeof(country_iso)); + country_iso[2] = OP_CLASS_GLOBAL; + assoc_ind->supported_band = + wlan_reg_get_band_cap_from_op_class( + country_iso, + oper_class->num_classes, + oper_class->classes); + } + + /* updates VHT information in assoc indication */ + if (assoc_req->VHTCaps.present) + qdf_mem_copy(&assoc_ind->vht_caps, &assoc_req->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + else if (assoc_req->vendor_vht_ie.VHTCaps.present) + qdf_mem_copy(&assoc_ind->vht_caps, + &assoc_req->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + + lim_fill_assoc_ind_info(mac_ctx, session_entry, assoc_req, + assoc_ind, sta_ds); + pe_debug("ch_width: %d vht_cap %d ht_cap %d chan_info %d center_freq1 %d", + session_entry->ch_width, + session_entry->vhtCapability, session_entry->htCapability, + assoc_ind->chan_info.info, + assoc_ind->chan_info.band_center_freq1); + assoc_ind->he_caps_present = assoc_req->he_cap.present; + assoc_ind->eht_caps_present = assoc_req->eht_cap.present; + assoc_ind->is_sae_authenticated = + assoc_req->is_sae_authenticated; + /* updates HE bandwidth in assoc indication */ + lim_fill_assoc_ind_he_bw_info(assoc_ind, sta_ds, session_entry); + lim_fill_assoc_ind_real_max_mcs_idx(assoc_ind, assoc_req, + sta_ds, session_entry); + + vdev = session_entry->vdev; + if (!vdev) + return true; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) + pe_err("vdev component object is NULL"); + else + qdf_mem_copy( + &mlme_obj->ext_vdev_ptr->connect_info.chan_info, + &assoc_ind->chan_info, + sizeof(mlme_obj->ext_vdev_ptr->connect_info.chan_info)); + + return true; +} + +QDF_STATUS lim_send_mlm_assoc_ind(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + tpLimMlmAssocInd assoc_ind; + tpSirAssocReq assoc_req; + uint16_t temp; + uint32_t phy_mode; + uint8_t sub_type; + + if (!session_entry->parsedAssocReq) { + pe_err(" Parsed Assoc req is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq) session_entry->parsedAssocReq[sta_ds->assocId]; + + if (!assoc_req) { + pe_err("assoc req for assoc_id:%d is NULL", sta_ds->assocId); + return QDF_STATUS_E_INVAL; + } + + /* Get the phy_mode */ + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + /* Determine if its Assoc or ReAssoc Request */ + if (assoc_req->reassocRequest == 1) + sub_type = LIM_REASSOC; + else + sub_type = LIM_ASSOC; + + pe_debug("Sessionid: %d ssid: " QDF_SSID_FMT " sub_type: %d Associd: %d staAddr: " + QDF_MAC_ADDR_FMT, session_entry->peSessionId, + QDF_SSID_REF(assoc_req->ssId.length, assoc_req->ssId.ssId), + sub_type, sta_ds->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + + wlan_son_ind_assoc_req_frm(session_entry->vdev, sta_ds->staAddr, + assoc_req->reassocRequest, + qdf_nbuf_data(assoc_req->assoc_req_buf), + qdf_nbuf_len(assoc_req->assoc_req_buf), + QDF_STATUS_SUCCESS); + + if (sub_type == LIM_ASSOC || sub_type == LIM_REASSOC) { + temp = sizeof(tLimMlmAssocInd); + + assoc_ind = qdf_mem_malloc(temp); + if (!assoc_ind) { + if (lim_is_mlo_conn(session_entry, sta_ds)) + lim_release_mlo_conn_idx(mac_ctx, + sta_ds->assocId, + session_entry, false); + else + lim_release_peer_idx(mac_ctx, sta_ds->assocId, + session_entry); + return QDF_STATUS_E_INVAL; + } + if (!lim_fill_lim_assoc_ind_params(assoc_ind, mac_ctx, + sta_ds, session_entry)) { + qdf_mem_free(assoc_ind); + return QDF_STATUS_E_INVAL; + } + + pe_debug("assoc_ind->akm_type:%d ", assoc_ind->akm_type); + if (assoc_ind->akm_type == ANI_AKM_TYPE_FT_RSN_PSK) { + lim_send_sme_mgmt_frame_ind(mac_ctx, sub_type, + qdf_nbuf_data(assoc_req->assoc_req_buf), + qdf_nbuf_len(assoc_req->assoc_req_buf), + session_entry->smeSessionId, + 0, 0, RXMGMT_FLAG_NONE); + } + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_IND, + (uint32_t *)assoc_ind); + qdf_mem_free(assoc_ind); + } + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c new file mode 100644 index 0000000000..a95cb41107 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c @@ -0,0 +1,1828 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_process_assoc_rsp_frame.cc contains the code + * for processing Re/Association Response Frame. + * Author: Chandra Modumudi + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sch_api.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" +#include "lim_process_fils.h" +#include "wlan_dlm_api.h" +#include "wlan_mlme_twt_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_connectivity_logging.h" +#include +#include "parser_api.h" +#include "wlan_twt_cfg_ext_api.h" +#include "wlan_mlo_mgr_roam.h" + +/** + * lim_update_stads_htcap() - Updates station Descriptor HT capability + * @mac_ctx: Pointer to Global MAC structure + * @sta_ds: Station Descriptor in DPH + * @assoc_rsp: Pointer to Association Response Structure + * @session_entry : PE session Entry + * + * This function is called to Update the HT capabilities in + * Station Descriptor (dph) Details from + * Association / ReAssociation Response Frame + * + * Return: None + */ +static void lim_update_stads_htcap(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry) +{ + uint16_t highest_rxrate = 0; + tDot11fIEHTCaps *ht_caps; + + ht_caps = &assoc_rsp->HTCaps; + sta_ds->mlmStaContext.htCapability = assoc_rsp->HTCaps.present; + if (assoc_rsp->HTCaps.present) { + sta_ds->htGreenfield = + (uint8_t) ht_caps->greenField; + if (session_entry->htSupportedChannelWidthSet) { + sta_ds->htSupportedChannelWidthSet = + (uint8_t) (ht_caps->supportedChannelWidthSet ? + assoc_rsp->HTInfo.recommendedTxWidthSet : + ht_caps->supportedChannelWidthSet); + } else + sta_ds->htSupportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + sta_ds->htLsigTXOPProtection = + (uint8_t) ht_caps->lsigTXOPProtection; + sta_ds->htMIMOPSState = + (tSirMacHTMIMOPowerSaveState)ht_caps->mimoPowerSave; + sta_ds->htMaxAmsduLength = + (uint8_t) ht_caps->maximalAMSDUsize; + sta_ds->htAMpduDensity = ht_caps->mpduDensity; + sta_ds->htDsssCckRate40MHzSupport = + (uint8_t) ht_caps->dsssCckMode40MHz; + sta_ds->htMaxRxAMpduFactor = + ht_caps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(mac_ctx, &highest_rxrate, + ht_caps->supportedMCSSet); + sta_ds->supportedRates.rxHighestDataRate = + highest_rxrate; + /* + * This is for AP as peer STA and we are INFRA STA + *.We will put APs offset in dph node which is peer STA + */ + sta_ds->htSecondaryChannelOffset = + (uint8_t) assoc_rsp->HTInfo.secondaryChannelOffset; + + /* Check if we have support for gShortGI20Mhz and + * gShortGI40Mhz from ini file + */ + if (session_entry->ht_config.short_gi_20_mhz) + sta_ds->htShortGI20Mhz = + (uint8_t)assoc_rsp->HTCaps.shortGI20MHz; + else + sta_ds->htShortGI20Mhz = false; + + if (session_entry->ht_config.short_gi_40_mhz) + sta_ds->htShortGI40Mhz = + (uint8_t)assoc_rsp->HTCaps.shortGI40MHz; + else + sta_ds->htShortGI40Mhz = false; + } +} + +/** + * lim_update_assoc_sta_datas() - Updates station Descriptor + * mac_ctx: Pointer to Global MAC structure + * sta_ds: Station Descriptor in DPH + * assoc_rsp: Pointer to Association Response Structure + * session_entry : PE session Entry + * + * This function is called to Update the Station Descriptor (dph) Details from + * Association / ReAssociation Response Frame + * + * Return: None + */ +void lim_update_assoc_sta_datas(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, tSchBeaconStruct *beacon) +{ + uint32_t phy_mode; + bool qos_mode; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEhe_cap *he_cap = NULL; + tDot11fIEeht_cap *eht_cap = NULL; + struct bss_description *bss_desc = NULL; + tDot11fIEVHTOperation *vht_oper = NULL; + enum phy_ch_width omn_ie_ch_width; + + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + sta_ds->staType = STA_ENTRY_SELF; + limGetQosMode(session_entry, &qos_mode); + sta_ds->mlmStaContext.authType = session_entry->limCurrentAuthType; + + /* Add capabilities information, rates and AID */ + sta_ds->mlmStaContext.capabilityInfo = assoc_rsp->capabilityInfo; + sta_ds->shortPreambleEnabled = + (uint8_t) assoc_rsp->capabilityInfo.shortPreamble; + + /* Update HT Capabilities only when the self mode supports HT */ + if (IS_DOT11_MODE_HT(session_entry->dot11mode)) + lim_update_stads_htcap(mac_ctx, sta_ds, assoc_rsp, + session_entry); + + if (assoc_rsp->VHTCaps.present) { + vht_caps = &assoc_rsp->VHTCaps; + vht_oper = &assoc_rsp->VHTOperation; + } else if (assoc_rsp->vendor_vht_ie.VHTCaps.present) { + vht_caps = &assoc_rsp->vendor_vht_ie.VHTCaps; + vht_oper = &assoc_rsp->vendor_vht_ie.VHTOperation; + } + + if (session_entry->vhtCapability && (vht_caps && vht_caps->present)) { + sta_ds->mlmStaContext.vhtCapability = + vht_caps->present; + + /* + * If 11ac is supported and if the peer is + * sending VHT capabilities, + * then htMaxRxAMpduFactor should be + * overloaded with VHT maxAMPDULenExp + */ + sta_ds->htMaxRxAMpduFactor = vht_caps->maxAMPDULenExp; + if (session_entry->htSupportedChannelWidthSet) { + if (vht_oper && vht_oper->present) + sta_ds->vhtSupportedChannelWidthSet = + lim_get_vht_ch_width(vht_caps, + vht_oper, + &assoc_rsp->HTInfo); + else + sta_ds->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } + sta_ds->vht_mcs_10_11_supp = 0; + if (mac_ctx->mlme_cfg->vht_caps.vht_cap_info. + vht_mcs_10_11_supp && + assoc_rsp->qcn_ie.present && + assoc_rsp->qcn_ie.vht_mcs11_attr.present) + sta_ds->vht_mcs_10_11_supp = + assoc_rsp->qcn_ie.vht_mcs11_attr. + vht_mcs_10_11_supp; + } + + lim_update_stads_he_caps(mac_ctx, sta_ds, assoc_rsp, + session_entry, beacon); + + lim_update_stads_eht_caps(mac_ctx, sta_ds, assoc_rsp, + session_entry, beacon); + + if (lim_is_sta_he_capable(sta_ds)) + he_cap = &assoc_rsp->he_cap; + + if (lim_is_sta_eht_capable(sta_ds)) + eht_cap = &assoc_rsp->eht_cap; + + if (session_entry->lim_join_req) + bss_desc = &session_entry->lim_join_req->bssDescription; + + if (lim_populate_peer_rate_set(mac_ctx, &sta_ds->supportedRates, + assoc_rsp->HTCaps.supportedMCSSet, + false, session_entry, + vht_caps, he_cap, eht_cap, + sta_ds, bss_desc) != + QDF_STATUS_SUCCESS) { + pe_err("could not get rateset and extended rate set"); + return; + } + sta_ds->vhtSupportedRxNss = + ((sta_ds->supportedRates.vhtTxMCSMap & MCSMAPMASK2x2) + == MCSMAPMASK2x2) ? 1 : 2; + + /* If one of the rates is 11g rates, set the ERP mode. */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && + sirIsArate(sta_ds->supportedRates.llaRates[0] & 0x7f)) + sta_ds->erpEnabled = eHAL_SET; + + /* Could not get prop rateset from CFG. Log error. */ + sta_ds->qosMode = 0; + sta_ds->lleEnabled = 0; + + /* update TSID to UP mapping */ + if (qos_mode) { + if (assoc_rsp->edcaPresent) { + QDF_STATUS status; + + qdf_mem_copy(&sta_ds->qos.peer_edca_params, + &assoc_rsp->edca, + sizeof(assoc_rsp->edca)); + + status = + sch_beacon_edca_process(mac_ctx, + &assoc_rsp->edca, session_entry); + pe_debug("Edca set update based on AssocRsp: status %d", + status); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Edca error in AssocResp"); + } else { + /* update default tidmap based on ACM */ + sta_ds->qosMode = 1; + sta_ds->lleEnabled = 1; + } + } + } + + sta_ds->wmeEnabled = 0; + sta_ds->wsmEnabled = 0; + if (session_entry->limWmeEnabled && assoc_rsp->wmeEdcaPresent) { + QDF_STATUS status; + + qdf_mem_copy(&sta_ds->qos.peer_edca_params, + &assoc_rsp->edca, + sizeof(assoc_rsp->edca)); + + status = sch_beacon_edca_process(mac_ctx, &assoc_rsp->edca, + session_entry); + pe_debug("WME Edca set update based on AssocRsp: status %d", + status); + + if (status != QDF_STATUS_SUCCESS) + pe_err("WME Edca error in AssocResp - ignoring"); + + else { + /* update default tidmap based on HashACM */ + sta_ds->qosMode = 1; + sta_ds->wmeEnabled = 1; + } + } else { + /* + * We received assoc rsp from a legacy AP. + * So fill in the default local EDCA params. + * This is needed (refer to bug #14989) as we'll + * be passing the gLimEdcaParams to HAL in + * lim_process_sta_mlm_add_bss_rsp(). + */ + sch_set_default_edca_params(mac_ctx, session_entry); + } + + if (qos_mode && (!sta_ds->qosMode) && + sta_ds->mlmStaContext.htCapability) { + /* + * Enable QOS for all HT AP's even though WMM + * or 802.11E IE is not present + */ + sta_ds->qosMode = 1; + sta_ds->wmeEnabled = 1; + } + if (session_entry->limRmfEnabled) + sta_ds->rmfEnabled = 1; + + if (session_entry->vhtCapability && assoc_rsp->oper_mode_ntf.present) { + /** + * OMN IE is present in the Assoc response, but the channel + * width/Rx NSS update will happen through the peer_assoc cmd. + */ + omn_ie_ch_width = assoc_rsp->oper_mode_ntf.chanWidth; + pe_debug("OMN IE present in re/assoc rsp, omn_ie_ch_width: %d", + omn_ie_ch_width); + lim_update_omn_ie_ch_width(session_entry->vdev, + omn_ie_ch_width); + } + + if (lim_process_srp_ie(assoc_rsp, sta_ds) == QDF_STATUS_SUCCESS) + lim_update_vdev_sr_elements(session_entry, sta_ds); +} + +/** + * lim_update_ric_data() - update session with ric data + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with RIC data. + * + * Return: None + */ +static void lim_update_ric_data(struct mac_context *mac_ctx, + struct pe_session *session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->ricData) { + qdf_mem_free(session_entry->ricData); + session_entry->ricData = NULL; + session_entry->RICDataLen = 0; + } + if (assoc_rsp->ricPresent) { + session_entry->RICDataLen = + assoc_rsp->num_RICData * sizeof(tDot11fIERICDataDesc); + if (session_entry->RICDataLen) { + session_entry->ricData = + qdf_mem_malloc(session_entry->RICDataLen); + if (!session_entry->ricData) + session_entry->RICDataLen = 0; + else + qdf_mem_copy(session_entry->ricData, + &assoc_rsp->RICData[0], + session_entry->RICDataLen); + } else { + pe_err("RIC data not present"); + } + } else { + session_entry->RICDataLen = 0; + session_entry->ricData = NULL; + } + return; +} + +#ifdef FEATURE_WLAN_ESE +/** + * lim_update_ese_tspec() - update session with Tspec info. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with Tspec data. + * + * Return: None + */ +static void lim_update_ese_tspec(struct mac_context *mac_ctx, + struct pe_session *session_entry, tpSirAssocRsp assoc_rsp) +{ + if (session_entry->tspecIes) { + qdf_mem_free(session_entry->tspecIes); + session_entry->tspecIes = NULL; + session_entry->tspecLen = 0; + } + if (assoc_rsp->tspecPresent) { + pe_debug("Tspec EID present in assoc rsp"); + session_entry->tspecLen = + assoc_rsp->num_tspecs * sizeof(tDot11fIEWMMTSPEC); + if (session_entry->tspecLen) { + session_entry->tspecIes = + qdf_mem_malloc(session_entry->tspecLen); + if (!session_entry->tspecIes) + session_entry->tspecLen = 0; + else + qdf_mem_copy(session_entry->tspecIes, + &assoc_rsp->TSPECInfo[0], + session_entry->tspecLen); + } else { + pe_err("TSPEC has Zero length"); + } + } else { + session_entry->tspecLen = 0; + session_entry->tspecIes = NULL; + } + return; +} + +/** + * lim_update_ese_tsm() - update session with TSM info. + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update PE session context with TSM IE data and send + * eWNI_TSM_IE_IND to SME. + * + * Return: None + */ +static void lim_update_ese_tsm(struct mac_context *mac_ctx, + struct pe_session *session_entry, tpSirAssocRsp assoc_rsp) +{ + uint8_t cnt = 0; + tpEseTSMContext tsm_ctx; + + pe_debug("TSM IE Present in Reassoc Rsp"); + /* + * Start the TSM timer only if the TSPEC + * Ie is present in the reassoc rsp + */ + if (!assoc_rsp->tspecPresent) { + pe_debug("TSM present but TSPEC IE not present"); + return; + } + tsm_ctx = &session_entry->eseContext.tsm; + /* Find the TSPEC IE with VO user priority */ + for (cnt = 0; cnt < assoc_rsp->num_tspecs; cnt++) { + if (upToAc(assoc_rsp->TSPECInfo[cnt].user_priority) == + QCA_WLAN_AC_VO) { + tsm_ctx->tid = + assoc_rsp->TSPECInfo[cnt].user_priority; + qdf_mem_copy(&tsm_ctx->tsmInfo, + &assoc_rsp->tsmIE, sizeof(struct ese_tsm_ie)); + lim_send_sme_tsm_ie_ind(mac_ctx, + session_entry, assoc_rsp->tsmIE.tsid, + assoc_rsp->tsmIE.state, + assoc_rsp->tsmIE.msmt_interval); + if (tsm_ctx->tsmInfo.state) + tsm_ctx->tsmMetrics.RoamingCount++; + break; + } + } +} +#endif + +/** + * lim_update_stads_ext_cap() - update sta ds with ext cap + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: PE session handle + * @assoc_rsp: pointer to assoc response + * + * This function is called by lim_process_assoc_rsp_frame() to + * update STA DS with ext capabilities. + * + * Return: None + */ +static void lim_update_stads_ext_cap(struct mac_context *mac_ctx, + struct pe_session *session_entry, tpSirAssocRsp assoc_rsp, + tpDphHashNode sta_ds) +{ + struct s_ext_cap *ext_cap; + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *mlme_obj; + + if (!assoc_rsp->ExtCap.present) { + sta_ds->timingMeasCap = 0; +#ifdef FEATURE_WLAN_TDLS + mlme_set_tdls_prohibited(session_entry->vdev, false); + mlme_set_tdls_chan_switch_prohibited(session_entry->vdev, + false); +#endif + pe_debug("ExtCap not present"); + return; + } + + ext_cap = (struct s_ext_cap *)assoc_rsp->ExtCap.bytes; + lim_set_stads_rtt_cap(sta_ds, ext_cap, mac_ctx); + + vdev = session_entry->vdev; + if (vdev) { + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) + pe_err("vdev component object is NULL"); + else + mlme_obj->ext_vdev_ptr->connect_info.timing_meas_cap = + sta_ds->timingMeasCap; + } + +#ifdef FEATURE_WLAN_TDLS + mlme_set_tdls_prohibited(session_entry->vdev, ext_cap->tdls_prohibited); + mlme_set_tdls_chan_switch_prohibited(session_entry->vdev, + ext_cap->tdls_chan_swit_prohibited); + ; + pe_debug("ExtCap: tdls_prohibited: %d tdls_chan_swit_prohibited: %d", + ext_cap->tdls_prohibited, + ext_cap->tdls_chan_swit_prohibited); +#endif + lim_set_peer_twt_cap(session_entry, ext_cap); +} + +/** + * lim_stop_reassoc_retry_timer() - Cleanup after reassoc response is received + * @mac_ctx: Global MAC context + * + * Stop the reassoc retry timer and release the stored reassoc request. + * + * Return: None + */ +static void lim_stop_reassoc_retry_timer(struct mac_context *mac_ctx) +{ + mac_ctx->lim.reAssocRetryAttempt = 0; + if ((mac_ctx->lim.pe_session) + && (NULL != + mac_ctx->lim.pe_session->pLimMlmReassocRetryReq)) { + qdf_mem_free( + mac_ctx->lim.pe_session->pLimMlmReassocRetryReq); + mac_ctx->lim.pe_session->pLimMlmReassocRetryReq = NULL; + } + lim_deactivate_and_change_timer(mac_ctx, eLIM_REASSOC_FAIL_TIMER); +} + +uint8_t lim_get_nss_supported_by_ap(tDot11fIEVHTCaps *vht_caps, + tDot11fIEHTCaps *ht_caps, + tDot11fIEhe_cap *he_caps) +{ + if (he_caps->present) { + if ((he_caps->rx_he_mcs_map_lt_80 & 0xC0) != 0xC0) + return NSS_4x4_MODE; + + if ((he_caps->rx_he_mcs_map_lt_80 & 0x30) != 0x30) + return NSS_3x3_MODE; + + if ((he_caps->rx_he_mcs_map_lt_80 & 0x0C) != 0x0C) + return NSS_2x2_MODE; + } else if (vht_caps->present) { + if ((vht_caps->rxMCSMap & 0xC0) != 0xC0) + return NSS_4x4_MODE; + + if ((vht_caps->rxMCSMap & 0x30) != 0x30) + return NSS_3x3_MODE; + + if ((vht_caps->rxMCSMap & 0x0C) != 0x0C) + return NSS_2x2_MODE; + } else if (ht_caps->present) { + if (ht_caps->supportedMCSSet[3]) + return NSS_4x4_MODE; + + if (ht_caps->supportedMCSSet[2]) + return NSS_3x3_MODE; + + if (ht_caps->supportedMCSSet[1]) + return NSS_2x2_MODE; + } + + return NSS_1x1_MODE; +} + +#ifdef WLAN_FEATURE_11AX +static void lim_process_he_info(tpSirProbeRespBeacon beacon, + tpDphHashNode sta_ds) +{ + if (beacon->he_op.present) + sta_ds->parsed_ies.he_operation = beacon->he_op; +} +#else +static inline void lim_process_he_info(tpSirProbeRespBeacon beacon, + tpDphHashNode sta_ds) +{ +} +#endif + +#ifdef WLAN_FEATURE_SR +QDF_STATUS lim_process_srp_ie(tpSirAssocRsp ar, tpDphHashNode sta_ds) +{ + QDF_STATUS status = QDF_STATUS_E_NOSUPPORT; + + if (ar->srp_ie.present) { + sta_ds->parsed_ies.srp_ie = ar->srp_ie; + status = QDF_STATUS_SUCCESS; + } + + return status; +} +#endif + +#ifdef WLAN_FEATURE_11BE +static void lim_process_eht_info(tpSirProbeRespBeacon beacon, + tpDphHashNode sta_ds) +{ + if (beacon->eht_op.present) + sta_ds->parsed_ies.eht_operation = beacon->eht_op; +} +#else +static inline void lim_process_eht_info(tpSirProbeRespBeacon beacon, + tpDphHashNode sta_ds) +{ +} +#endif + +#define MAX_RETRY_TIMER 1500 +static QDF_STATUS +lim_handle_pmfcomeback_timer(struct pe_session *session_entry, + tpSirAssocRsp assoc_rsp) +{ + uint16_t timeout_value; + + if (session_entry->opmode != QDF_STA_MODE) + return QDF_STATUS_E_FAILURE; + + if (session_entry->limRmfEnabled && + session_entry->pmf_retry_timer_info.retried && + assoc_rsp->status_code == STATUS_ASSOC_REJECTED_TEMPORARILY) { + pe_debug("Already retry in progress"); + return QDF_STATUS_SUCCESS; + } + + /* + * Handle association Response for sta mode with RMF enabled and TRY + * again later with timeout interval and Assoc comeback type + */ + if (!session_entry->limRmfEnabled || assoc_rsp->status_code != + STATUS_ASSOC_REJECTED_TEMPORARILY || + !assoc_rsp->TimeoutInterval.present || + assoc_rsp->TimeoutInterval.timeoutType != + SIR_MAC_TI_TYPE_ASSOC_COMEBACK || + session_entry->pmf_retry_timer_info.retried) + return QDF_STATUS_E_FAILURE; + + timeout_value = assoc_rsp->TimeoutInterval.timeoutValue; + if (timeout_value < 10) { + /* + * if this value is less than 10 then our timer + * will fail to start and due to this we will + * never re-attempt. Better modify the timer + * value here. + */ + timeout_value = 10; + } + timeout_value = QDF_MIN(MAX_RETRY_TIMER, timeout_value); + pe_debug("ASSOC res with eSIR_MAC_TRY_AGAIN_LATER recvd.Starting timer to wait timeout: %d", + timeout_value); + if (QDF_STATUS_SUCCESS != + qdf_mc_timer_start(&session_entry->pmf_retry_timer, + timeout_value)) { + pe_err("Failed to start comeback timer"); + return QDF_STATUS_E_FAILURE; + } + session_entry->pmf_retry_timer_info.retried = true; + + return QDF_STATUS_SUCCESS; +} + +static void clean_up_ft_sha384(tpSirAssocRsp assoc_rsp, bool sha384_akm) +{ + if (sha384_akm) { + qdf_mem_free(assoc_rsp->sha384_ft_subelem.gtk); + qdf_mem_free(assoc_rsp->sha384_ft_subelem.igtk); + } +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void lim_set_r0kh(tpSirAssocRsp assoc_rsp, struct pe_session *session) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + if (assoc_rsp->sha384_ft_subelem.r0kh_id.present) { + mlme_priv->connect_info.ft_info.r0kh_id_len = + assoc_rsp->sha384_ft_subelem.r0kh_id.num_PMK_R0_ID; + qdf_mem_copy(mlme_priv->connect_info.ft_info.r0kh_id, + assoc_rsp->sha384_ft_subelem.r0kh_id.PMK_R0_ID, + mlme_priv->connect_info.ft_info.r0kh_id_len); + } else if (assoc_rsp->FTInfo.R0KH_ID.present) { + mlme_priv->connect_info.ft_info.r0kh_id_len = + assoc_rsp->FTInfo.R0KH_ID.num_PMK_R0_ID; + qdf_mem_copy(mlme_priv->connect_info.ft_info.r0kh_id, + assoc_rsp->FTInfo.R0KH_ID.PMK_R0_ID, + mlme_priv->connect_info.ft_info.r0kh_id_len); + } else { + mlme_priv->connect_info.ft_info.r0kh_id_len = 0; + qdf_mem_zero(mlme_priv->connect_info.ft_info.r0kh_id, + ROAM_R0KH_ID_MAX_LEN); + } +} +#else +static inline +void lim_set_r0kh(tpSirAssocRsp assoc_rsp, struct pe_session *session) {} +#endif + +/** + * lim_get_iot_aggr_sz() - check and get IOT aggr size for configured OUI + * + * @mac_ctx: Pointer to Global MAC structure + * @ie_ptr: Pointer to starting IE in Beacon/Probe Response + * @ie_len: Length of all IEs combined + * @amsdu_sz: pointer to buffer to store AMSDU size + * @ampdu_sz: pointer to buffer to store AMPDU size + * + * This function is called to find configured vendor specific OUIs + * from the IEs in Beacon/Probe Response frames, if one of the OUI is + * present, get the configured aggr size for the OUI. + * + * Return: true if found, false otherwise. + */ +static bool +lim_get_iot_aggr_sz(struct mac_context *mac, uint8_t *ie_ptr, uint32_t ie_len, + uint32_t *amsdu_sz, uint32_t *ampdu_sz) +{ + const uint8_t *oui, *vendor_ie; + struct wlan_mlme_iot *iot; + uint32_t oui_len, aggr_num; + int i; + + iot = &mac->mlme_cfg->iot; + aggr_num = iot->aggr_num; + if (!aggr_num) + return false; + + for (i = 0; i < aggr_num; i++) { + oui = iot->aggr[i].oui; + oui_len = iot->aggr[i].oui_len; + vendor_ie = wlan_get_vendor_ie_ptr_from_oui(oui, oui_len, + ie_ptr, ie_len); + if (!vendor_ie) + continue; + + *amsdu_sz = iot->aggr[i].amsdu_sz; + *ampdu_sz = iot->aggr[i].ampdu_sz; + return true; + } + + return false; +} + +/** + * lim_update_iot_aggr_sz() - check and update IOT aggr size + * + * @mac_ctx: Pointer to Global MAC structure + * @ie_ptr: Pointer to starting IE in Beacon/Probe Response + * @ie_len: Length of all IEs combined + * @session_entry: A pointer to session entry + * + * This function is called to find configured vendor specific OUIs + * from the IEs in Beacon/Probe Response frames, and set the aggr + * size accordingly. + * + * Return: None + */ +static void +lim_update_iot_aggr_sz(struct mac_context *mac_ctx, uint8_t *ie_ptr, + uint32_t ie_len, struct pe_session *session_entry) +{ + int ret; + uint32_t amsdu_sz, ampdu_sz; + bool iot_hit; + + if (!ie_ptr || !ie_len) + return; + + iot_hit = lim_get_iot_aggr_sz(mac_ctx, ie_ptr, ie_len, + &amsdu_sz, &du_sz); + if (!iot_hit) + return; + + pe_debug("Try to set iot amsdu size: %u", amsdu_sz); + ret = wma_cli_set_command(session_entry->smeSessionId, + GEN_VDEV_PARAM_AMSDU, amsdu_sz, GEN_CMD); + if (ret) + pe_err("Failed to set iot amsdu size: %d", ret); +} + +/** + * hdd_cm_update_mcs_rate_set() - Update MCS rate set from HT capability + * @vdev: Pointer to vdev object + * @ht_cap: pointer to parsed HT capability + * + * Return: None. + */ +static inline void +lim_update_mcs_rate_set(struct wlan_objmgr_vdev *vdev, tDot11fIEHTCaps *ht_cap) +{ + qdf_size_t len = 0; + int i; + uint32_t *mcs_set; + uint8_t dst_rate[VALID_MAX_MCS_INDEX] = {0}; + + mcs_set = (uint32_t *)ht_cap->supportedMCSSet; + for (i = 0; i < VALID_MAX_MCS_INDEX; i++) { + if (!QDF_GET_BITS(*mcs_set, i, 1)) + continue; + + dst_rate[len++] = i; + } + + mlme_set_mcs_rate(vdev, dst_rate, len); +} + +#ifdef WLAN_FEATURE_11BE +/** + * lim_update_sta_vdev_punc() - Update puncture set according to assoc resp + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * @assoc_resp: pointer to parsed associate response + * + * Return: None. + */ +static QDF_STATUS +lim_update_sta_vdev_punc(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + tpSirAssocRsp assoc_resp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_channel *des_chan; + enum phy_ch_width ori_bw; + uint16_t ori_puncture_bitmap; + uint16_t primary_puncture_bitmap = 0; + qdf_freq_t center_freq_320; + uint8_t band_mask; + + if (!assoc_resp->eht_op.disabled_sub_chan_bitmap_present) + return QDF_STATUS_SUCCESS; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev not found for id: %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + ori_puncture_bitmap = + *(uint16_t *)assoc_resp->eht_op.disabled_sub_chan_bitmap; + + ori_bw = wlan_mlme_convert_eht_op_bw_to_phy_ch_width( + assoc_resp->eht_op.channel_width); + + if (ori_bw == CH_WIDTH_320MHZ) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(des_chan->ch_freq)) + band_mask = BIT(REG_BAND_2G); + else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(des_chan->ch_freq)) + band_mask = BIT(REG_BAND_6G); + else + band_mask = BIT(REG_BAND_5G); + center_freq_320 = wlan_reg_chan_band_to_freq( + wlan_vdev_get_pdev(vdev), + assoc_resp->eht_op.ccfs1, + band_mask); + } else { + center_freq_320 = 0; + } + wlan_reg_extract_puncture_by_bw(ori_bw, ori_puncture_bitmap, + des_chan->ch_freq, + center_freq_320, + CH_WIDTH_20MHZ, + &primary_puncture_bitmap); + if (primary_puncture_bitmap) { + pe_err("sta vdev %d freq %d assoc rsp bw %d puncture 0x%x primary chan is punctured", + vdev_id, des_chan->ch_freq, ori_bw, ori_puncture_bitmap); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return QDF_STATUS_E_FAILURE; + } + if (des_chan->ch_width == ori_bw) + des_chan->puncture_bitmap = ori_puncture_bitmap; + else + wlan_reg_extract_puncture_by_bw(ori_bw, ori_puncture_bitmap, + des_chan->ch_freq, + center_freq_320, + des_chan->ch_width, + &des_chan->puncture_bitmap); + pe_debug("sta vdev %d freq %d assoc rsp bw %d puncture 0x%x 320M center frequency %d intersect bw %d puncture 0x%x", + vdev_id, des_chan->ch_freq, ori_bw, ori_puncture_bitmap, + center_freq_320, des_chan->ch_width, + des_chan->puncture_bitmap); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +lim_update_sta_vdev_punc(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + tpSirAssocRsp assoc_resp) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * hdd_cm_update_rate_set() - Update rate set according to assoc resp + * @psoc: Pointer to psoc object + * @vdev_id: vdev id + * @assoc_resp: pointer to parsed associate response + * + * Return: None. + */ +static void +lim_update_vdev_rate_set(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + tpSirAssocRsp assoc_resp) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev not found for id: %d", vdev_id); + return; + } + + if (assoc_resp->suppRatesPresent && assoc_resp->supportedRates.numRates) + mlme_set_opr_rate(vdev, assoc_resp->supportedRates.rate, + assoc_resp->supportedRates.numRates); + + if (assoc_resp->extendedRatesPresent && + assoc_resp->extendedRates.numRates) + mlme_set_ext_opr_rate(vdev, + assoc_resp->extendedRates.rate, + assoc_resp->extendedRates.numRates); + else + mlme_clear_ext_opr_rate(vdev); + + if (assoc_resp->HTCaps.present) + lim_update_mcs_rate_set(vdev, &assoc_resp->HTCaps); + else + mlme_clear_mcs_rate(vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +lim_process_assoc_rsp_t2lm(struct pe_session *session, + tpSirAssocRsp assoc_rsp) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_t2lm_context *t2lm_ctx; + struct wlan_mlo_dev_context *mlo_dev_ctx; + struct wlan_objmgr_psoc *psoc; + + if (!session || !assoc_rsp) { + pe_err("invalid input parameters"); + return; + } + + vdev = session->vdev; + if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + if (!wlan_mlme_get_t2lm_negotiation_supported(psoc)) { + pe_err_rl("T2LM negotiation not supported"); + return; + } + + mlo_dev_ctx = wlan_vdev_get_mlo_dev_ctx(vdev); + if (!mlo_dev_ctx) { + pe_err("ml dev ctx is null"); + return; + } + + if (wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return; + + if (assoc_rsp->t2lm_ctx.upcoming_t2lm.t2lm.direction == + WLAN_T2LM_INVALID_DIRECTION && + assoc_rsp->t2lm_ctx.established_t2lm.t2lm.direction == + WLAN_T2LM_INVALID_DIRECTION) { + pe_debug("No t2lm IE"); + return; + } + + t2lm_ctx = &mlo_dev_ctx->sta_ctx->copied_t2lm_ie_assoc_rsp; + + if (assoc_rsp->t2lm_ctx.established_t2lm.t2lm.expected_duration_present && + !assoc_rsp->t2lm_ctx.established_t2lm.t2lm.mapping_switch_time_present && + assoc_rsp->t2lm_ctx.established_t2lm.t2lm.direction != + WLAN_T2LM_INVALID_DIRECTION) { + qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, + &assoc_rsp->t2lm_ctx.established_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + } + + if (assoc_rsp->t2lm_ctx.upcoming_t2lm.t2lm.mapping_switch_time_present && + assoc_rsp->t2lm_ctx.established_t2lm.t2lm.direction != + WLAN_T2LM_INVALID_DIRECTION) { + qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, + &assoc_rsp->t2lm_ctx.upcoming_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + } +} +#else +static inline void +lim_process_assoc_rsp_t2lm(struct pe_session *session, + tpSirAssocRsp assoc_rsp) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_cache_emlsr_params() - cache the EMLSR parameters in ML STA context + * @session_entry: session entry + * @assoc_rsp: pointer to parsed associate response + * + * Return: None + */ +static void lim_cache_emlsr_params(struct pe_session *session_entry, + tpSirAssocRsp assoc_rsp) +{ + struct wlan_mlo_sta *sta_ctx; + struct wlan_objmgr_vdev *vdev = session_entry->vdev; + struct emlsr_capability *ml_emlcap; + + wlan_objmgr_vdev_get_ref(vdev, WLAN_MLME_SB_ID); + if (!vdev) { + pe_err("vdev is null"); + return; + } + + if (!vdev->mlo_dev_ctx) { + pe_err("mlo dev ctx is null"); + goto end; + } + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!sta_ctx) { + pe_err("sta ctx is null"); + goto end; + } + + ml_emlcap = &sta_ctx->emlsr_cap; + + if (wlan_vdev_mlme_cap_get(vdev, + WLAN_VDEV_C_EMLSR_CAP)) { + ml_emlcap->emlsr_supp = true; + ml_emlcap->trans_timeout = + assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.transition_timeout; + } else { + ml_emlcap->emlsr_supp = false; + ml_emlcap->trans_timeout = 0; + } + + pe_debug("EML caps support%d timeout%d", ml_emlcap->emlsr_supp, + ml_emlcap->trans_timeout); +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} +#else +static inline void lim_cache_emlsr_params(struct pe_session *session_entry, + tpSirAssocRsp assoc_rsp) +{ +} +#endif + +/** + * lim_send_join_fail_on_vdev() - Send join failure for link vdev + * @mac_ctx: Pointer to Global MAC structure + * @session_entry: Session entry + * @result_code: result code to send in join result + * + * This function sends join failure when bssid of assoc/reassoc + * resp doesn't match with current bssid + */ +static +void lim_send_join_fail_on_vdev(struct mac_context *mac_ctx, + struct pe_session *session_entry, + enum eSirResultCodes result_code) +{ + if (!wlan_vdev_mlme_is_mlo_link_vdev(session_entry->vdev)) + return; + + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + /* Send Join response to Host */ + lim_handle_sme_join_result( + mac_ctx, result_code, STATUS_UNSPECIFIED_FAILURE, + session_entry); +} + +/** + * lim_process_assoc_rsp_frame() - Processes assoc response + * @mac_ctx: Pointer to Global MAC structure + * @rx_packet_info - A pointer to Rx packet info structure + * @frame_body_length - frame body length of reassoc/assoc response frame + * @sub_type - Indicates whether it is Association Response (=0) or + * Reassociation Response (=1) frame + * @session_entry: Session entry + * + * This function is called by limProcessMessageQueue() upon + * Re/Association Response frame reception. + * + * Return: None + */ +void +lim_process_assoc_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + uint32_t frame_body_len, + uint8_t subtype, struct pe_session *session_entry) +{ + uint8_t *body, *ie; + uint16_t caps, ie_len; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr hdr = NULL; + tSirMacCapabilityInfo mac_capab; + tpDphHashNode sta_ds; + tpSirAssocRsp assoc_rsp; + tLimMlmAssocCnf assoc_cnf; + tSchBeaconStruct *beacon; + uint8_t ap_nss; + uint16_t aid; + int8_t rssi; + QDF_STATUS status; + enum ani_akm_type auth_type; + bool sha384_akm, twt_support_in_11n = false; + struct s_ext_cap *ext_cap; + + assoc_cnf.resultCode = eSIR_SME_SUCCESS; + /* Update PE session Id */ + assoc_cnf.sessionId = session_entry->peSessionId; + + if (LIM_IS_AP_ROLE(session_entry)) { + /* + * Should not have received Re/Association + * Response frame on AP. Log error + */ + pe_err("Should not received Re/Assoc Response in role: %d", + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + if (lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry) || + wlan_vdev_mlme_is_mlo_link_vdev(session_entry->vdev)) { + hdr = (tpSirMacMgmtHdr)rx_pkt_info; + rssi = 0; + } else { + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + } + + if (!hdr) { + pe_err("LFR3: Reassoc response packet header is NULL"); + return; + } + + pe_nofl_rl_info("Assoc rsp RX: subtype %d vdev %d sys role %d lim state %d rssi %d from " QDF_MAC_ADDR_FMT, + subtype, session_entry->vdev_id, + GET_LIM_SYSTEM_ROLE(session_entry), + session_entry->limMlmState, rssi, + QDF_MAC_ADDR_REF(hdr->sa)); + + beacon = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!beacon) + return; + + if (((subtype == LIM_ASSOC) && + (session_entry->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE)) || + ((subtype == LIM_REASSOC) && + !lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry) && + !MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(mac_ctx->psoc, + session_entry->vdev_id) && + ((session_entry->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) + && (session_entry->limMlmState != + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) + ))) { + /* Received unexpected Re/Association Response frame */ + pe_debug("Received Re/Assoc rsp in unexpected state: %d on session: %d", + session_entry->limMlmState, session_entry->peSessionId); + if (!hdr->fc.retry) { + if (!(mac_ctx->lim.retry_packet_cnt & 0xf)) { + pe_err("recvd Re/Assoc rsp:not a retry frame"); + lim_print_mlm_state(mac_ctx, LOGE, + session_entry->limMlmState); + } else { + mac_ctx->lim.retry_packet_cnt++; + } + } + qdf_mem_free(beacon); + return; + } + sir_copy_mac_addr(current_bssid, session_entry->bssId); + if (subtype == LIM_ASSOC) { + if (qdf_mem_cmp + (hdr->sa, current_bssid, sizeof(tSirMacAddr))) { + /* + * Received Association Response frame from an entity + * other than one to which request was initiated. + * Ignore this and wait until Assoc Failure Timeout + */ + pe_warn("received AssocRsp from unexpected peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdr->sa)); + + if (lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry)) { + session_entry->is_unexpected_peer_error = true; + qdf_mem_free(beacon); + return; + } + /* + * Send Assoc failure to avoid connection in + * progress state for link vdev. + */ + lim_send_join_fail_on_vdev(mac_ctx, session_entry, + eSIR_SME_ASSOC_REFUSED); + qdf_mem_free(beacon); + return; + } + } else { + if (qdf_mem_cmp + (hdr->sa, session_entry->limReAssocbssId, + sizeof(tSirMacAddr))) { + /* + * Received Reassociation Response frame from an entity + * other than one to which request was initiated. + * Ignore this and wait until Reassoc Failure Timeout. + */ + pe_warn("received ReassocRsp from unexpected peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdr->sa)); + + if (lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry)) { + session_entry->is_unexpected_peer_error = true; + qdf_mem_free(beacon); + return; + } + + /* + * Send Reassoc failure to avoid connection in + * progress state for link vdev. + */ + lim_send_join_fail_on_vdev(mac_ctx, session_entry, + eSIR_SME_REASSOC_REFUSED); + qdf_mem_free(beacon); + return; + } + } + + assoc_rsp = qdf_mem_malloc(sizeof(*assoc_rsp)); + if (!assoc_rsp) { + qdf_mem_free(beacon); + return; + } + /* Get pointer to Re/Association Response frame body */ + if (lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry) || + wlan_vdev_mlme_is_mlo_link_vdev(session_entry->vdev)) + body = rx_pkt_info + SIR_MAC_HDR_LEN_3A; + else + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + /* parse Re/Association Response frame. */ + if (sir_convert_assoc_resp_frame2_struct(mac_ctx, session_entry, body, + frame_body_len, assoc_rsp) == QDF_STATUS_E_FAILURE) { + qdf_mem_free(assoc_rsp); + pe_err("Parse error Assoc resp subtype: %d" "length: %d", + frame_body_len, subtype); + qdf_mem_free(beacon); + return; + } + + if (subtype == LIM_REASSOC) { + lim_cp_stats_cstats_log_assoc_resp_evt + (session_entry, CSTATS_DIR_RX, assoc_rsp->status_code, + assoc_rsp->aid, hdr->bssId, hdr->da, + assoc_rsp->HTCaps.present, + assoc_rsp->VHTCaps.present, assoc_rsp->he_cap.present, + assoc_rsp->eht_op.present, true); + } else if (subtype == LIM_ASSOC) { + lim_cp_stats_cstats_log_assoc_resp_evt + (session_entry, CSTATS_DIR_RX, assoc_rsp->status_code, + assoc_rsp->aid, hdr->bssId, hdr->da, + assoc_rsp->HTCaps.present, + assoc_rsp->VHTCaps.present, assoc_rsp->he_cap.present, + assoc_rsp->eht_op.present, false); + } + + if (subtype != LIM_REASSOC) { + aid = assoc_rsp->aid & 0x3FFF; + wlan_connectivity_mgmt_event(mac_ctx->psoc, + (struct wlan_frame_hdr *)hdr, + session_entry->vdev_id, + assoc_rsp->status_code, 0, rssi, + 0, 0, 0, aid, + WLAN_ASSOC_RSP); + } + + if (lim_is_session_eht_capable(session_entry)) { + uint8_t ies_offset; + + if (subtype == LIM_ASSOC) + ies_offset = WLAN_ASSOC_RSP_IES_OFFSET; + else + ies_offset = WLAN_REASSOC_REQ_IES_OFFSET; + + if (frame_body_len < ies_offset) { + pe_err("frame body length is < ies_offset"); + return; + } + + status = lim_strip_and_decode_eht_op( + body + ies_offset, + frame_body_len - ies_offset, + &assoc_rsp->eht_op, + assoc_rsp->VHTOperation, + assoc_rsp->he_op, + assoc_rsp->HTInfo); + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + return; + } + + status = lim_strip_and_decode_eht_cap( + body + ies_offset, + frame_body_len - ies_offset, + &assoc_rsp->eht_cap, + assoc_rsp->he_cap, + session_entry->curr_op_freq); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + return; + } + } + + if (!assoc_rsp->suppRatesPresent) { + pe_debug("assoc response does not have supported rate set"); + qdf_mem_copy(&assoc_rsp->supportedRates, + &session_entry->rateSet, + sizeof(tSirMacRateSet)); + } + + assoc_cnf.protStatusCode = assoc_rsp->status_code; + if (session_entry->assocRsp) { + pe_warn("session_entry->assocRsp is not NULL freeing it and setting NULL"); + qdf_mem_free(session_entry->assocRsp); + session_entry->assocRsp = NULL; + session_entry->assocRspLen = 0; + } + + if (frame_body_len) { + session_entry->assocRsp = qdf_mem_malloc(frame_body_len); + if (session_entry->assocRsp) { + /* + * Store the Assoc response. This is sent + * to csr/hdd in join cnf response. + */ + qdf_mem_copy(session_entry->assocRsp, body, frame_body_len); + session_entry->assocRspLen = frame_body_len; + } + } + + lim_update_ric_data(mac_ctx, session_entry, assoc_rsp); + + lim_set_r0kh(assoc_rsp, session_entry); + +#ifdef FEATURE_WLAN_ESE + lim_update_ese_tspec(mac_ctx, session_entry, assoc_rsp); +#endif + + auth_type = session_entry->connected_akm; + sha384_akm = lim_is_sha384_akm(auth_type); + + if (lim_get_capability_info(mac_ctx, &caps, session_entry) + != QDF_STATUS_SUCCESS) { + clean_up_ft_sha384(assoc_rsp, sha384_akm); + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + pe_err("could not retrieve Capabilities"); + return; + } + lim_copy_u16((uint8_t *) &mac_capab, caps); + + if (assoc_rsp->status_code == STATUS_DENIED_POOR_CHANNEL_CONDITIONS && + assoc_rsp->rssi_assoc_rej.present) { + struct sir_rssi_disallow_lst ap_info = {{0}}; + + if (!assoc_rsp->rssi_assoc_rej.retry_delay) + ap_info.expected_rssi = assoc_rsp->rssi_assoc_rej.delta_rssi + + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info) + + wlan_dlm_get_rssi_denylist_threshold(mac_ctx->pdev); + else + ap_info.expected_rssi = assoc_rsp->rssi_assoc_rej.delta_rssi + + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + + ap_info.retry_delay = assoc_rsp->rssi_assoc_rej.retry_delay * + QDF_MC_TIMER_TO_MS_UNIT; + qdf_mem_copy(ap_info.bssid.bytes, hdr->sa, QDF_MAC_ADDR_SIZE); + ap_info.reject_reason = REASON_ASSOC_REJECT_OCE; + ap_info.source = ADDED_BY_DRIVER; + ap_info.original_timeout = ap_info.retry_delay; + ap_info.received_time = qdf_mc_timer_get_system_time(); + lim_add_bssid_to_reject_list(mac_ctx->pdev, &ap_info); + } + + status = lim_handle_pmfcomeback_timer(session_entry, assoc_rsp); + /* return if retry again timer is started and ignore this assoc resp */ + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(beacon); + clean_up_ft_sha384(assoc_rsp, sha384_akm); + qdf_mem_free(assoc_rsp); + return; + } + + /* Stop Association failure timer */ + if (subtype == LIM_ASSOC) + lim_deactivate_and_change_timer(mac_ctx, eLIM_ASSOC_FAIL_TIMER); + else + lim_stop_reassoc_retry_timer(mac_ctx); + + if (assoc_rsp->status_code != STATUS_SUCCESS) { + /* + *Re/Association response was received + * either with failure code. + */ + pe_err("received Re/AssocRsp frame failure code: %d", + assoc_rsp->status_code); + /* + * Need to update 'association failure' error counter + * along with STATUS CODE + * Return Assoc confirm to SME with received failure code + */ + assoc_cnf.resultCode = eSIR_SME_ASSOC_REFUSED; + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + goto assocReject; + } else if ((assoc_rsp->aid & 0x3FFF) > 2007) { + /* + * Re/Association response was received + * with invalid AID value + */ + pe_err("received Re/AssocRsp frame with invalid aid: %X", + assoc_rsp->aid); + assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, + hdr->sa, session_entry, false); + goto assocReject; + } + + /* + * If it is FILS connection, check is FILS params are matching + * with Authentication stage. + */ + if (!lim_verify_fils_params_assoc_rsp(mac_ctx, session_entry, + assoc_rsp, &assoc_cnf)) { + pe_err("FILS params does not match"); + assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, + hdr->sa, session_entry, false); + goto assocReject; + } + + if (assoc_rsp->QosMapSet.present) + qdf_mem_copy(&session_entry->QosMapSet, + &assoc_rsp->QosMapSet, + sizeof(struct qos_map_set)); + else + qdf_mem_zero(&session_entry->QosMapSet, + sizeof(struct qos_map_set)); + + if (assoc_rsp->obss_scanparams.present) + lim_update_obss_scanparams(session_entry, + &assoc_rsp->obss_scanparams); + + if (lim_is_session_he_capable(session_entry)) { + if (!wlan_cm_is_vdev_roaming(session_entry->vdev)) + lim_set_twt_peer_capabilities( + mac_ctx, + (struct qdf_mac_addr *)current_bssid, + &assoc_rsp->he_cap, + &assoc_rsp->he_op); + + } else { + wlan_twt_cfg_get_support_in_11n(mac_ctx->psoc, + &twt_support_in_11n); + if (twt_support_in_11n && session_entry->htCapability && + assoc_rsp->HTCaps.present && assoc_rsp->ExtCap.present) { + ext_cap = (struct s_ext_cap *)assoc_rsp->ExtCap.bytes; + lim_set_twt_ext_capabilities( + mac_ctx, + (struct qdf_mac_addr *)current_bssid, + ext_cap); + } + } + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + session_entry, + (assoc_rsp->status_code ? QDF_STATUS_E_FAILURE : + QDF_STATUS_SUCCESS), assoc_rsp->status_code); + + ap_nss = lim_get_nss_supported_by_ap(&assoc_rsp->VHTCaps, + &assoc_rsp->HTCaps, + &assoc_rsp->he_cap); + + if (subtype == LIM_REASSOC) { + pe_debug("Successfully Reassociated with BSS"); +#ifdef FEATURE_WLAN_ESE + if (assoc_rsp->tsmPresent) + lim_update_ese_tsm(mac_ctx, session_entry, assoc_rsp); +#endif + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + + if (session_entry->limAssocResponseData) { + tpSirAssocRsp pre_assoc_rsp; + + pre_assoc_rsp = (tpSirAssocRsp) + session_entry->limAssocResponseData; + qdf_mem_free(pre_assoc_rsp->sha384_ft_subelem.gtk); + qdf_mem_free(pre_assoc_rsp->sha384_ft_subelem.igtk); + qdf_mem_free(session_entry->limAssocResponseData); + } + session_entry->limAssocResponseData = (void *)assoc_rsp; + /* + * Store the ReAssocRsp Frame in DphTable + * to be used during processing DelSta and + * DelBss to send AddBss again + */ + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + pe_err("could not get hash entry at DPH for SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdr->sa)); + assoc_cnf.resultCode = + eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = + STATUS_UNSPECIFIED_FAILURE; + + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, hdr->sa, + session_entry, false); + goto assocReject; + } + + if (ap_nss < session_entry->nss) + session_entry->nss = ap_nss; + + lim_objmgr_update_vdev_nss(mac_ctx->psoc, + session_entry->smeSessionId, + session_entry->nss); + lim_update_vdev_rate_set(mac_ctx->psoc, + session_entry->smeSessionId, + assoc_rsp); + + if ((session_entry->limMlmState == + eLIM_MLM_WT_FT_REASSOC_RSP_STATE) || + lim_is_roam_synch_in_progress(mac_ctx->psoc, + session_entry)) { + pe_debug("Sending self sta"); + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, + session_entry, NULL); + lim_update_stads_ext_cap(mac_ctx, session_entry, + assoc_rsp, sta_ds); + /* Store assigned AID for TIM processing */ + session_entry->limAID = assoc_rsp->aid & 0x3FFF; + /* Downgrade the EDCA parameters if needed */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, + session_entry); + /* Send the active EDCA parameters to HAL */ + if (!lim_is_roam_synch_in_progress(mac_ctx->psoc, + session_entry)) { + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + session_entry->vdev_id, false); + lim_add_ft_sta_self(mac_ctx, + (assoc_rsp->aid & 0x3FFF), + session_entry); + } else { + lim_set_emlsr_caps(mac_ctx, session_entry); + lim_objmgr_update_emlsr_caps(mac_ctx->psoc, + session_entry->vdev_id, + assoc_rsp); + lim_cache_emlsr_params(session_entry, + assoc_rsp); + } + qdf_mem_free(beacon); + return; + } + + /* + * If we're re-associating to the same BSS, + * we don't want to invoke delete STA, delete + * BSS, as that would remove the already + * established TSPEC. Just go ahead and re-add + * the BSS, STA with new capability information. + * However, if we're re-associating to a different + * BSS, then follow thru with del STA, del BSS, + * add BSS, add STA. + */ + if (sir_compare_mac_addr(session_entry->bssId, + session_entry->limReAssocbssId)) + lim_handle_add_bss_in_re_assoc_context(mac_ctx, sta_ds, + session_entry); + else { + /* + * reset the uapsd mask settings since + * we're re-associating to new AP + */ + session_entry->gUapsdPerAcDeliveryEnableMask = 0; + session_entry->gUapsdPerAcTriggerEnableMask = 0; + + lim_mlo_notify_peer_disconn(session_entry, sta_ds); + if (lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry, + true) != QDF_STATUS_SUCCESS) { + pe_err("Could not cleanup the rx path"); + goto assocReject; + } + } + if (!mlo_roam_is_auth_status_connected(mac_ctx->psoc, + wlan_vdev_get_id(session_entry->vdev))) { + qdf_mem_free(beacon); + return; + } + } + pe_debug("Successfully Associated with BSS " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdr->sa)); + +#ifdef FEATURE_WLAN_ESE + if (session_entry->eseContext.tsm.tsmInfo.state) + session_entry->eseContext.tsm.tsmMetrics.RoamingCount = 0; +#endif + /* Store assigned AID for TIM processing */ + session_entry->limAID = assoc_rsp->aid & 0x3FFF; + + /* STA entry was created during pre-assoc state. */ + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + /* Could not add hash table entry */ + pe_err("could not get hash entry at DPH SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(hdr->sa)); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = eSIR_SME_SUCCESS; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + clean_up_ft_sha384(assoc_rsp, sha384_akm); + /* + * Don't free the assoc rsp if it's cached in pe_session. + * It would be reused in link connect in cases like OWE + * roaming + */ + if (session_entry->limAssocResponseData != assoc_rsp) + qdf_mem_free(assoc_rsp); + qdf_mem_free(beacon); + return; + } + /* Delete Pre-auth context for the associated BSS */ + if (lim_search_pre_auth_list(mac_ctx, hdr->sa)) + lim_delete_pre_auth_node(mac_ctx, hdr->sa); + + if (ap_nss < session_entry->nss) + session_entry->nss = ap_nss; + + lim_objmgr_update_vdev_nss(mac_ctx->psoc, + session_entry->smeSessionId, + session_entry->nss); + lim_update_vdev_rate_set(mac_ctx->psoc, session_entry->smeSessionId, + assoc_rsp); + if (QDF_IS_STATUS_ERROR(lim_update_sta_vdev_punc( + mac_ctx->psoc, + session_entry->smeSessionId, + assoc_rsp))) { + assoc_cnf.resultCode = eSIR_SME_INVALID_ASSOC_RSP_RXED; + assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Send advisory Disassociation frame to AP */ + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, + hdr->sa, session_entry, false); + goto assocReject; + } + + lim_objmgr_update_emlsr_caps(mac_ctx->psoc, session_entry->smeSessionId, + assoc_rsp); + + lim_process_assoc_rsp_t2lm(session_entry, assoc_rsp); + /* + * Extract the AP capabilities from the beacon that + * was received earlier + */ + ie_len = lim_get_ielen_from_bss_description( + &session_entry->lim_join_req->bssDescription); + ie = (uint8_t *)session_entry->lim_join_req->bssDescription.ieFields; + lim_update_iot_aggr_sz(mac_ctx, ie, ie_len, session_entry); + + lim_extract_ap_capabilities(mac_ctx, ie, ie_len, beacon); + + if (session_entry->opmode == QDF_STA_MODE) { + lim_enable_cts_to_self_for_exempted_iot_ap( + mac_ctx, session_entry, + ie, ie_len); + } + + lim_update_assoc_sta_datas(mac_ctx, sta_ds, assoc_rsp, + session_entry, beacon); + + if (lim_is_session_he_capable(session_entry)) { + session_entry->mu_edca_present = assoc_rsp->mu_edca_present; + if (session_entry->mu_edca_present) { + pe_debug("Save MU EDCA params to session"); + session_entry->ap_mu_edca_params[QCA_WLAN_AC_BE] = + assoc_rsp->mu_edca.acbe; + session_entry->ap_mu_edca_params[QCA_WLAN_AC_BK] = + assoc_rsp->mu_edca.acbk; + session_entry->ap_mu_edca_params[QCA_WLAN_AC_VI] = + assoc_rsp->mu_edca.acvi; + session_entry->ap_mu_edca_params[QCA_WLAN_AC_VO] = + assoc_rsp->mu_edca.acvo; + } + } + + if (beacon->VHTCaps.present) + sta_ds->parsed_ies.vht_caps = beacon->VHTCaps; + if (beacon->HTCaps.present) + sta_ds->parsed_ies.ht_caps = beacon->HTCaps; + if (beacon->hs20vendor_ie.present) + sta_ds->parsed_ies.hs20vendor_ie = beacon->hs20vendor_ie; + if (beacon->HTInfo.present) + sta_ds->parsed_ies.ht_operation = beacon->HTInfo; + if (beacon->VHTOperation.present) + sta_ds->parsed_ies.vht_operation = beacon->VHTOperation; + + lim_process_he_info(beacon, sta_ds); + if (lim_process_srp_ie(assoc_rsp, sta_ds) == QDF_STATUS_SUCCESS) + lim_update_vdev_sr_elements(session_entry, sta_ds); + + if (lim_is_session_eht_capable(session_entry)) + lim_process_eht_info(beacon, sta_ds); + + if (mac_ctx->lim.gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac_ctx, beacon, + session_entry); + + if (beacon->erpPresent) { + if (beacon->erpIEInfo.barkerPreambleMode) + session_entry->beaconParams.fShortPreamble = false; + else + session_entry->beaconParams.fShortPreamble = true; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_CONNECTED, session_entry, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +#endif + lim_update_stads_ext_cap(mac_ctx, session_entry, assoc_rsp, sta_ds); + + /* Update the BSS Entry, this entry was added during preassoc. */ + if (QDF_STATUS_SUCCESS == + lim_sta_send_add_bss(mac_ctx, assoc_rsp, beacon, + &session_entry->lim_join_req->bssDescription, + true, session_entry)) { + clean_up_ft_sha384(assoc_rsp, sha384_akm); + if (session_entry->limAssocResponseData != assoc_rsp) + qdf_mem_free(assoc_rsp); + + qdf_mem_free(beacon); + + return; + } + + pe_err("vdev:%d could not update the bss entry", + session_entry->vdev_id); + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + +assocReject: + if (subtype == LIM_ASSOC || + (subtype == LIM_REASSOC && + session_entry->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE)) { + pe_err("Assoc Rejected by the peer mlmestate: %d sessionid: %d Reason: %d MACADDR:" + QDF_MAC_ADDR_FMT, session_entry->limMlmState, + session_entry->peSessionId, assoc_cnf.resultCode, + QDF_MAC_ADDR_REF(hdr->sa)); + + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + + if (subtype == LIM_ASSOC) { + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + } else { + assoc_cnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *)&assoc_cnf); + } + } else { + lim_restore_pre_reassoc_state(mac_ctx, + eSIR_SME_REASSOC_REFUSED, + assoc_cnf.protStatusCode, + session_entry); + } + + qdf_mem_free(beacon); + qdf_mem_free(assoc_rsp->sha384_ft_subelem.gtk); + qdf_mem_free(assoc_rsp->sha384_ft_subelem.igtk); + qdf_mem_free(assoc_rsp); + + return; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c new file mode 100644 index 0000000000..8a4a5b737f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_auth_frame.c @@ -0,0 +1,2403 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_process_auth_frame.cc contains the code + * for processing received Authentication Frame. + * Author: Chandra Modumudi + * Date: 03/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/12/2010 js To support Shared key authentication at AP side + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "cfg_ucfg_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_ft.h" +#include "cds_utils.h" +#include "lim_send_messages.h" +#include "lim_process_fils.h" +#include "wlan_mlme_api.h" +#include "wlan_connectivity_logging.h" +#include "lim_types.h" +#include +#include "wlan_nan_api_i.h" +#include +/** + * is_auth_valid + * + ***FUNCTION: + * This function is called by lim_process_auth_frame() upon Authentication + * frame reception. + * + ***LOGIC: + * This function is used to test validity of auth frame: + * - AUTH1 and AUTH3 must be received in AP mode + * - AUTH2 and AUTH4 must be received in STA mode + * - AUTH3 and AUTH4 must have challenge text IE, that is,'type' field has been set to + * WLAN_ELEMID_CHALLENGE by parser + * - + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param *auth - Pointer to extracted auth frame body + * + * @return 0 or 1 (Valid) + */ + +static inline unsigned int is_auth_valid(struct mac_context *mac, + tpSirMacAuthFrameBody auth, + struct pe_session *pe_session) +{ + unsigned int valid = 1; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_1) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3)) && + (LIM_IS_STA_ROLE(pe_session))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (LIM_IS_AP_ROLE(pe_session))) + valid = 0; + + if (((auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_3) || + (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_4)) && + (auth->type != WLAN_ELEMID_CHALLENGE) && + (auth->authAlgoNumber != eSIR_SHARED_KEY)) + valid = 0; + + return valid; +} + +/** + * lim_get_wep_key_sap() - get sap's wep key for shared wep auth + * @pe_session: pointer to pe session + * @wep_params: pointer to wlan_mlme_wep_cfg + * @key_id: key id + * @default_key: output of the key + * @key_len: output of key length + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_get_wep_key_sap(struct pe_session *pe_session, + struct wlan_mlme_wep_cfg *wep_params, + uint8_t key_id, + uint8_t *default_key, + qdf_size_t *key_len) +{ + return mlme_get_wep_key(pe_session->vdev, + wep_params, + (MLME_WEP_DEFAULT_KEY_1 + key_id), + default_key, + key_len); +} + +static void lim_process_auth_shared_system_algo(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + struct pe_session *pe_session) +{ + uint32_t val; + uint8_t cfg_privacy_opt_imp; + struct tLimPreAuthNode *auth_node; + uint8_t challenge_txt_arr[SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH] = {0}; + + pe_debug("=======> eSIR_SHARED_KEY"); + if (LIM_IS_AP_ROLE(pe_session)) + val = pe_session->privacy; + else + val = mac_ctx->mlme_cfg->wep_params.is_privacy_enabled; + + cfg_privacy_opt_imp = (uint8_t) val; + if (!cfg_privacy_opt_imp) { + pe_err("rx Auth frame for unsupported auth algorithm %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + /* + * Authenticator does not have WEP + * implemented. + * Reject by sending Authentication frame + * with Auth algorithm not supported status + * code. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_NOT_SUPPORTED_AUTH_ALG; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } else { + /* Create entry for this STA in pre-auth list */ + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (!auth_node) { + pe_warn("Max preauth-nodes reached SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, mac_hdr->sa, + sizeof(tSirMacAddr)); + auth_node->mlmState = eLIM_MLM_WT_AUTH_FRAME3_STATE; + auth_node->authType = + (tAniAuthType) rx_auth_frm_body->authAlgoNumber; + auth_node->fSeen = 0; + auth_node->fTimerStarted = 0; + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + + pe_debug("Alloc new data: %pK id: %d peer "QDF_MAC_ADDR_FMT, + auth_node, auth_node->authNodeIdx, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* / Create and activate Auth Response timer */ + if (tx_timer_change_context(&auth_node->timer, + auth_node->authNodeIdx) != TX_SUCCESS) { + /* Could not start Auth response timer. Log error */ + pe_warn("Unable to chg context auth response timer for peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + /* + * Send Auth frame with unspecified failure status code. + */ + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_UNSPECIFIED_FAILURE; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + return; + } + + /* + * get random bytes and use as challenge text. + */ + get_random_bytes(challenge_txt_arr, + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH); + qdf_mem_zero(auth_node->challengeText, + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH); + if (!qdf_mem_cmp(challenge_txt_arr, + auth_node->challengeText, + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH)) { + pe_err("Challenge text preparation failed SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_ASSOC_REJECTED_TEMPORARILY; + lim_send_auth_mgmt_frame(mac_ctx, + auth_frame, + mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + return; + } + + lim_activate_auth_rsp_timer(mac_ctx, auth_node); + auth_node->fTimerStarted = 1; + + qdf_mem_copy(auth_node->challengeText, + challenge_txt_arr, + sizeof(challenge_txt_arr)); + /* + * Sending Authenticaton frame with challenge. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = STATUS_SUCCESS; + auth_frame->type = WLAN_ELEMID_CHALLENGE; + auth_frame->length = SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH; + qdf_mem_copy(auth_frame->challengeText, + auth_node->challengeText, + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH); + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + } +} + +static void lim_process_auth_open_system_algo(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + struct pe_session *pe_session) +{ + struct tLimPreAuthNode *auth_node; + + pe_debug("=======> eSIR_OPEN_SYSTEM"); + /* Create entry for this STA in pre-auth list */ + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (!auth_node) { + pe_warn("Max pre-auth nodes reached SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + pe_debug("Alloc new data: %pK peer "QDF_MAC_ADDR_FMT, auth_node, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + mac_hdr->sa, sizeof(tSirMacAddr)); + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + auth_node->authType = (tAniAuthType) rx_auth_frm_body->authAlgoNumber; + auth_node->fSeen = 0; + auth_node->fTimerStarted = 0; + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + + /* Check for MLO IE in Auth request in case of MLO connection */ + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev) && + rx_auth_frm_body->is_mlo_ie_present) { + auth_node->is_mlo_ie_present = true; + pe_debug("MLO IE is present in auth req"); + } + + lim_add_pre_auth_node(mac_ctx, auth_node); + /* + * Send Authenticaton frame with Success + * status code. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = STATUS_SUCCESS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); +} + +#ifdef WLAN_FEATURE_SAE +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_external_auth_update_pre_auth_node_mld() - Update preauth node mld addr + * for the peer performing external authentication + * @auth_node: Pointer to pre-auth node to be added to the list + * @peer_mld: Peer MLD address + * + * Return: None + */ +static void +lim_external_auth_update_pre_auth_node_mld(struct tLimPreAuthNode *auth_node, + struct qdf_mac_addr *peer_mld) +{ + qdf_mem_copy((uint8_t *)auth_node->peer_mld, peer_mld->bytes, + QDF_MAC_ADDR_SIZE); +} +#else +static void +lim_external_auth_update_pre_auth_node_mld(struct tLimPreAuthNode *auth_node, + struct qdf_mac_addr *peer_mld) +{ +} +#endif + +/** + * lim_external_auth_add_pre_auth_node()- Add preauth node for the peer + * performing external authentication + * @mac_ctx: MAC context + * @mac_hdr: Mac header of the packet + * @mlm_state: MLM state to be marked to track SAE authentication + * @peer_mld: Peer MLD address + * + * Return: None + */ +static void lim_external_auth_add_pre_auth_node(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tLimMlmStates mlm_state, + struct qdf_mac_addr *peer_mld) +{ + struct tLimPreAuthNode *auth_node; + tpLimPreAuthTable preauth_table = &mac_ctx->lim.gLimPreAuthTimerTable; + + pe_debug("=======> eSIR_AUTH_TYPE_SAE"); + /* Create entry for this STA in pre-auth list */ + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, preauth_table); + if (!auth_node) { + pe_debug("Max pre-auth nodes reached " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + pe_debug("Creating preauth node for SAE peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + qdf_mem_copy((uint8_t *)auth_node->peerMacAddr, + mac_hdr->sa, sizeof(tSirMacAddr)); + lim_external_auth_update_pre_auth_node_mld(auth_node, peer_mld); + + auth_node->mlmState = mlm_state; + auth_node->authType = eSIR_AUTH_TYPE_SAE; + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->assoc_req.present = false; + lim_add_pre_auth_node(mac_ctx, auth_node); +} + +void lim_sae_auth_cleanup_retry(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + struct pe_session *pe_session; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!pe_session) { + pe_err("session not found for given vdev_id %d", vdev_id); + return; + } + + pe_debug("sae auth cleanup for vdev_id %d", vdev_id); + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + mlme_free_sae_auth_retry(pe_session->vdev); +} + +#define SAE_AUTH_ALGO_BYTES 2 +#define SAE_AUTH_SEQ_NUM_BYTES 2 +#define SAE_AUTH_SEQ_OFFSET 1 + +/** + * lim_is_sae_auth_algo_match()- Match SAE auth seq in queued SAE auth and + * SAE auth rx frame + * @queued_frame: Pointer to queued SAE auth retry frame + * @q_len: length of queued sae auth retry frame + * @rx_pkt_info: Rx packet + * + * Return: True if SAE auth seq is matched else false + */ +static bool lim_is_sae_auth_algo_match(uint8_t *queued_frame, uint16_t q_len, + uint8_t *rx_pkt_info) +{ + tpSirMacMgmtHdr qmac_hdr = (tpSirMacMgmtHdr)queued_frame; + uint16_t *rxbody_ptr, *qbody_ptr, rxframe_len, min_len; + + min_len = sizeof(tSirMacMgmtHdr) + SAE_AUTH_ALGO_BYTES + + SAE_AUTH_SEQ_NUM_BYTES; + + rxframe_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + if (rxframe_len < min_len || q_len < min_len) { + pe_debug("rxframe_len %d, queued_frame_len %d, min_len %d", + rxframe_len, q_len, min_len); + return false; + } + + rxbody_ptr = (uint16_t *)WMA_GET_RX_MPDU_DATA(rx_pkt_info); + qbody_ptr = (uint16_t *)((uint8_t *)qmac_hdr + sizeof(tSirMacMgmtHdr)); + + pe_debug("sae_auth : rx pkt auth seq %d queued pkt auth seq %d", + rxbody_ptr[SAE_AUTH_SEQ_OFFSET], + qbody_ptr[SAE_AUTH_SEQ_OFFSET]); + if (rxbody_ptr[SAE_AUTH_SEQ_OFFSET] == + qbody_ptr[SAE_AUTH_SEQ_OFFSET]) + return true; + + return false; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/* + * lim_skip_sae_fixed_field: This API is called to parse the SAE auth frame and + * skip the SAE fixed fields + * @body_ptr: Pointer to a SAE auth frame + * @frame_len: Length of SAE auth frame + * @ie_ptr: Buffer to be searched for the Multi-Link element or the start of the + * Multi-Link element fragment sequence + * @ie_len: Length of the buffer + * + * Return: QDF_STATUS_SUCCESS in the case of success, QDF_STATUS value giving + * the reason for error in the case of failure + */ +static QDF_STATUS lim_skip_sae_fixed_field(uint8_t *body_ptr, + uint32_t frame_len, + uint8_t **ie_ptr, qdf_size_t *ie_len) +{ + uint16_t sae_status_code = 0; + uint16_t sae_group_id = 0; + + if (!body_ptr || !frame_len || !ie_ptr || !ie_len) + return QDF_STATUS_E_NULL_VALUE; + + if (frame_len < (SAE_AUTH_GROUP_ID_OFFSET + 2)) + return QDF_STATUS_E_INVAL; + + sae_status_code = *(uint16_t *)(body_ptr + SAE_AUTH_STATUS_CODE_OFFSET); + + if (sae_status_code != WLAN_SAE_STATUS_HASH_TO_ELEMENT && + sae_status_code != WLAN_SAE_STATUS_PK) + return QDF_STATUS_E_NOSUPPORT; + + sae_group_id = *(uint16_t *)(body_ptr + SAE_AUTH_GROUP_ID_OFFSET); + *ie_ptr = body_ptr + SAE_AUTH_GROUP_ID_OFFSET + 2; + *ie_len = frame_len - SAE_AUTH_GROUP_ID_OFFSET - 2; + + switch (sae_group_id) { + case SAE_GROUP_ID_19: + if (*ie_len < SAE_GROUP_19_FIXED_FIELDS_LEN) + return QDF_STATUS_E_NOSUPPORT; + + *ie_ptr = *ie_ptr + SAE_GROUP_19_FIXED_FIELDS_LEN; + *ie_len = *ie_len - SAE_GROUP_19_FIXED_FIELDS_LEN; + break; + case SAE_GROUP_ID_20: + if (*ie_len < SAE_GROUP_20_FIXED_FIELDS_LEN) + return QDF_STATUS_E_NOSUPPORT; + + *ie_ptr = *ie_ptr + SAE_GROUP_20_FIXED_FIELDS_LEN; + *ie_len = *ie_len - SAE_GROUP_20_FIXED_FIELDS_LEN; + break; + case SAE_GROUP_ID_21: + if (*ie_len < SAE_GROUP_21_FIXED_FIELDS_LEN) + return QDF_STATUS_E_NOSUPPORT; + + *ie_ptr = *ie_ptr + SAE_GROUP_21_FIXED_FIELDS_LEN; + *ie_len = *ie_len - SAE_GROUP_21_FIXED_FIELDS_LEN; + break; + default: + return QDF_STATUS_E_NOSUPPORT; + } + + if (*ie_len == 0) + return QDF_STATUS_E_NOSUPPORT; + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_get_sta_mld_address: This API is called to get the STA MLD address + * from SAE 1st auth frame. + * @vdev: vdev + * @body_ptr: Pointer to a SAE auth frame + * @frame_len: Length of SAE auth frame + * @peer_mld: fill peer MLD address + * + * Return: void + */ +static void lim_get_sta_mld_address(struct wlan_objmgr_vdev *vdev, + uint8_t *body_ptr, uint32_t frame_len, + struct qdf_mac_addr *peer_mld) +{ + uint8_t *ie_ptr = NULL; + uint8_t *ml_ie = NULL; + qdf_size_t ml_ie_total_len = 0; + qdf_size_t ie_len = 0; + QDF_STATUS status; + + if (!wlan_cm_is_sae_auth_addr_conversion_required(vdev)) + return; + + status = lim_skip_sae_fixed_field(body_ptr, frame_len, &ie_ptr, + &ie_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Failed in skip SAE field"); + return; + } + + status = util_find_mlie(ie_ptr, ie_len, &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("ML IE not found"); + return; + } + + util_get_bvmlie_mldmacaddr(ml_ie, ml_ie_total_len, peer_mld); +} + +/** + * lim_update_link_to_mld_address:This API is called to update SA and DA address + * @mac_ctx: Pointer to mac context + * @vdev: vdev + * @mac_hdr: Pointer to MAC management header + * + * Return: void + */ +static QDF_STATUS lim_update_link_to_mld_address(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + tpSirMacMgmtHdr mac_hdr) +{ + struct qdf_mac_addr *self_mld_addr; + struct tLimPreAuthNode *pre_auth_node; + struct qdf_mac_addr peer_mld_addr; + struct qdf_mac_addr *peer_roaming_mld_addr; + enum QDF_OPMODE opmode; + QDF_STATUS status; + + if (!wlan_cm_is_sae_auth_addr_conversion_required(vdev)) + return QDF_STATUS_SUCCESS; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + self_mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + + switch (opmode) { + case QDF_SAP_MODE: + pre_auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (!pre_auth_node) + return QDF_STATUS_E_INVAL; + + if (qdf_is_macaddr_zero( + (struct qdf_mac_addr *)pre_auth_node->peer_mld)) + return QDF_STATUS_SUCCESS; + + qdf_mem_copy(mac_hdr->sa, pre_auth_node->peer_mld, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(mac_hdr->bssId, self_mld_addr->bytes, + QDF_MAC_ADDR_SIZE); + break; + case QDF_STA_MODE: + if (!wlan_cm_is_vdev_roaming(vdev)) { + status = wlan_vdev_get_bss_peer_mld_mac(vdev, + &peer_mld_addr); + if (QDF_IS_STATUS_ERROR(status)) + return status; + } else { + peer_roaming_mld_addr = + wlan_cm_roaming_get_peer_mld_addr(vdev); + if (!peer_roaming_mld_addr) + return QDF_STATUS_E_FAILURE; + + peer_mld_addr = *peer_roaming_mld_addr; + } + + qdf_mem_copy(mac_hdr->sa, peer_mld_addr.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(mac_hdr->bssId, peer_mld_addr.bytes, + QDF_MAC_ADDR_SIZE); + break; + default: + return QDF_STATUS_SUCCESS; + } + + qdf_mem_copy(mac_hdr->da, self_mld_addr->bytes, QDF_MAC_ADDR_SIZE); + + return QDF_STATUS_SUCCESS; +} +#else +static void lim_get_sta_mld_address(struct wlan_objmgr_vdev *vdev, + uint8_t *body_ptr, uint32_t frame_len, + struct qdf_mac_addr *peer_mld) +{ +} + +static QDF_STATUS lim_update_link_to_mld_address(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + tpSirMacMgmtHdr mac_hdr) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static bool +lim_check_and_trigger_pmf_sta_deletion(struct mac_context *mac, + struct pe_session *pe_session, + tpSirMacMgmtHdr mac_hdr) +{ + tpDphHashNode sta_ds_ptr = NULL; + tLimMlmDisassocReq *mlm_disassoc_req = NULL; + tLimMlmDeauthReq *mlm_deauth_req = NULL; + bool is_connected = true; + uint16_t associd = 0; + + sta_ds_ptr = dph_lookup_hash_entry(mac, mac_hdr->sa, &associd, + &pe_session->dph.dphHashTable); + if (!sta_ds_ptr) + return false; + + mlm_disassoc_req = mac->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (mlm_disassoc_req && + !qdf_mem_cmp(mac_hdr->sa, &mlm_disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)) { + pe_debug("TODO:Ack pending for disassoc frame Issue del sta for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mlm_disassoc_req->peer_macaddr.bytes)); + lim_process_disassoc_ack_timeout(mac); + is_connected = false; + } + + mlm_deauth_req = mac->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (mlm_deauth_req && + !qdf_mem_cmp(mac_hdr->sa, &mlm_deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)) { + pe_debug("TODO:Ack for deauth frame is pending Issue del sta for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mlm_deauth_req->peer_macaddr.bytes)); + lim_process_deauth_ack_timeout(mac, pe_session->vdev_id); + is_connected = false; + } + + /* + * pStaDS != NULL and is_connected = 1 means the STA is already + * connected, But SAP received the Auth from that station. For non-PMF + * connection send Deauth frame as STA will retry to connect back. The + * reason for above logic is captured in CR620403. If we silently drop + * the auth, the subsequent EAPOL exchange will fail & peer STA will + * keep trying until DUT SAP/GO gets a kickout event from FW & cleans + * up. + * + * For PMF connection the AP should not tear down or otherwise modify + * the state of the existing association until the SA-Query procedure + * determines that the original SA is invalid. + */ + if (is_connected && !sta_ds_ptr->rmfEnabled) { + pe_err("STA is already connected but received auth frame" + "Send the Deauth and lim Delete Station Context" + "(associd: %d) sta mac" QDF_MAC_ADDR_FMT, + associd, QDF_MAC_ADDR_REF(mac_hdr->sa)); + + lim_send_deauth_mgmt_frame(mac, REASON_UNSPEC_FAILURE, + mac_hdr->sa, pe_session, false); + lim_trigger_sta_deletion(mac, sta_ds_ptr, pe_session); + + return true; + } + + return false; +} + +/** + * lim_process_sae_auth_frame()-Process SAE authentication frame + * @mac_ctx: MAC context + * @rx_pkt_info: Rx packet + * @pe_session: PE session + * + * Return: None + */ +static void lim_process_sae_auth_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *pe_session) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + enum rxmgmt_flags rx_flags = RXMGMT_FLAG_NONE; + struct sae_auth_retry *sae_retry; + uint16_t sae_auth_seq = 0, sae_status_code = 0; + uint16_t auth_algo; + QDF_STATUS status; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + auth_algo = *(uint16_t *)body_ptr; + if (frame_len >= (SAE_AUTH_STATUS_CODE_OFFSET + 2)) { + sae_auth_seq = *(uint16_t *)(body_ptr + SAE_AUTH_SEQ_NUM_OFFSET); + sae_status_code = *(uint16_t *)(body_ptr + + SAE_AUTH_STATUS_CODE_OFFSET); + } + + pe_nofl_rl_info("vdev:%d SAE Auth RX type %d subtype %d trans_seq_num:%d from " QDF_MAC_ADDR_FMT, + pe_session->vdev_id, + mac_hdr->fc.type, mac_hdr->fc.subType, + sae_auth_seq, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + if (LIM_IS_STA_ROLE(pe_session) && + pe_session->limMlmState != eLIM_MLM_WT_SAE_AUTH_STATE) + pe_err("SAE auth response for STA in unexpected state %x", + pe_session->limMlmState); + + if (LIM_IS_AP_ROLE(pe_session)) { + struct tLimPreAuthNode *pre_auth_node; + struct qdf_mac_addr peer_mld = {0}; + + rx_flags = RXMGMT_FLAG_EXTERNAL_AUTH; + /* + * Add preauth node when the first SAE authentication frame + * is received and mark state as authenticating. + * It's not good to track SAE authentication frames with + * authTransactionSeqNumber as it's subjected to + * SAE protocol optimizations. + */ + pre_auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (!pre_auth_node || + (pre_auth_node->mlmState != eLIM_MLM_WT_SAE_AUTH_STATE)) { + if (pre_auth_node) { + pe_debug("Delete existing preauth node for SAE peer in state: %u " + QDF_MAC_ADDR_FMT, + pre_auth_node->mlmState, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + } + /* case: when SAP receives auth SAE 1st frame with + * SA, DA and bssid as link address. Driver needs to + * get the STA MLD address and save it in preauth node + * struct for further use. + * For the 1st SAE RX frame, + * driver does not need to convert it in mld_address. + */ + lim_get_sta_mld_address(pe_session->vdev, body_ptr, + frame_len, &peer_mld); + lim_external_auth_add_pre_auth_node(mac_ctx, mac_hdr, + eLIM_MLM_WT_SAE_AUTH_STATE, + &peer_mld); + } else { + /* case: when SAP receives Auth SAE 3rd frame with + * SA, DA and bssid as link address. Needs to convert + * it into MLD address and send it userspace. + */ + status = lim_update_link_to_mld_address(mac_ctx, + pe_session->vdev, + mac_hdr); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("SAE address conversion failure with status:%d", + status); + return; + } + } + } + + sae_retry = mlme_get_sae_auth_retry(pe_session->vdev); + if (LIM_IS_STA_ROLE(pe_session) && sae_retry && + sae_retry->sae_auth.ptr) { + if (lim_is_sae_auth_algo_match(sae_retry->sae_auth.ptr, + sae_retry->sae_auth.len, + rx_pkt_info)) + lim_sae_auth_cleanup_retry(mac_ctx, + pe_session->vdev_id); + } + + if (LIM_IS_STA_ROLE(pe_session)) { + /* + * Cache the connectivity event with link address. + * So call the Connectivity logging API before address + * translation while forwarding the frame to userspace. + */ + wlan_connectivity_mgmt_event( + mac_ctx->psoc, + (struct wlan_frame_hdr *)mac_hdr, + pe_session->vdev_id, sae_status_code, 0, + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + auth_algo, sae_auth_seq, sae_auth_seq, 0, + WLAN_AUTH_RESP); + + lim_cp_stats_cstats_log_auth_evt(pe_session, CSTATS_DIR_RX, + auth_algo, sae_auth_seq, + sae_status_code); + + status = lim_update_link_to_mld_address(mac_ctx, + pe_session->vdev, + mac_hdr); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("vdev:%d STA SAE address conversion failed status:%d", + pe_session->vdev_id, status); + return; + } + } + + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + pe_session->vdev_id, + WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + rx_flags); +} +#else +static inline void lim_process_sae_auth_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, struct pe_session *pe_session) +{} +#endif + +static void lim_process_ft_auth_frame(struct mac_context *mac_ctx, + uint8_t *rx_pkt_info, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + enum rxmgmt_flags rx_flags = RXMGMT_FLAG_NONE; + uint16_t auth_algo; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("FT Auth RX type %d subtype %d from " QDF_MAC_ADDR_FMT, + mac_hdr->fc.type, mac_hdr->fc.subType, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + if (LIM_IS_AP_ROLE(pe_session)) { + struct tLimPreAuthNode *sta_pre_auth_ctx; + + rx_flags = RXMGMT_FLAG_EXTERNAL_AUTH; + /* Extract pre-auth context for the STA, if any. */ + sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, + mac_hdr->sa); + if (sta_pre_auth_ctx) { + pe_debug("STA Auth ctx have ininted"); + /* Pre-auth context exists for the STA */ + if (sta_pre_auth_ctx->mlmState == eLIM_MLM_WT_FT_AUTH_STATE) { + pe_warn("previous Auth not completed, don't process this auth frame"); + return; + } + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + } + + /* Create entry for this STA in pre-auth list */ + sta_pre_auth_ctx = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (!sta_pre_auth_ctx) { + pe_warn("Max pre-auth nodes reached "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + pe_debug("Alloc new data: %pK peer "QDF_MAC_ADDR_FMT, + sta_pre_auth_ctx, QDF_MAC_ADDR_REF(mac_hdr->sa)); + auth_algo = *(uint16_t *)body_ptr; + qdf_mem_copy((uint8_t *)sta_pre_auth_ctx->peerMacAddr, + mac_hdr->sa, sizeof(tSirMacAddr)); + sta_pre_auth_ctx->mlmState = eLIM_MLM_WT_FT_AUTH_STATE; + sta_pre_auth_ctx->authType = (tAniAuthType) auth_algo; + sta_pre_auth_ctx->fSeen = 0; + sta_pre_auth_ctx->fTimerStarted = 0; + sta_pre_auth_ctx->seq_num = + ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + sta_pre_auth_ctx->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, sta_pre_auth_ctx); + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + pe_session->smeSessionId, + WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + rx_flags); + } +} + +static uint8_t +lim_get_pasn_peer_vdev_id(struct mac_context *mac, uint8_t *bssid) +{ + struct wlan_objmgr_peer *peer; + uint8_t vdev_id; + + peer = wlan_objmgr_get_peer_by_mac(mac->psoc, bssid, + WLAN_MGMT_RX_ID); + if (!peer) { + pe_err("PASN peer doesn't exist for bssid: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid)); + return WLAN_UMAC_VDEV_ID_MAX; + } + + vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_RX_ID); + + return vdev_id; +} + +/** + * lim_process_pasn_auth_frame()- Process PASN authentication frame + * @mac_ctx: MAC context + * @vdev_id: Vdev identifier + * @rx_pkt_info: Rx packet + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_process_pasn_auth_frame(struct mac_context *mac_ctx, + uint8_t vdev_id, + uint8_t *rx_pkt_info) +{ + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + uint8_t *body_ptr; + enum rxmgmt_flags rx_flags = RXMGMT_FLAG_NONE; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("vdev_id:%d", vdev_id); + lim_send_sme_mgmt_frame_ind(mac_ctx, mac_hdr->fc.subType, + (uint8_t *)mac_hdr, + frame_len + sizeof(tSirMacMgmtHdr), + vdev_id, WMA_GET_RX_FREQ(rx_pkt_info), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + rx_flags); + + return QDF_STATUS_SUCCESS; +} + +static void lim_process_auth_frame_type1(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + uint8_t *rx_pkt_info, uint16_t curr_seq_num, + tSirMacAuthFrameBody *auth_frame, struct pe_session *pe_session) +{ + tpDphHashNode sta_ds_ptr = NULL; + struct tLimPreAuthNode *auth_node; + uint32_t maxnum_preauth; + uint16_t associd = 0; + + if (lim_check_and_trigger_pmf_sta_deletion(mac_ctx, pe_session, + mac_hdr)) + return; + + /* Check if there exists pre-auth context for this STA */ + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (auth_node) { + /* Pre-auth context exists for the STA */ + if (!(mac_hdr->fc.retry == 0 || + auth_node->seq_num != curr_seq_num)) { + /* + * This can happen when first authentication frame is + * received but ACK lost at STA side, in this case 2nd + * auth frame is already in transmission queue + */ + pe_warn("STA is initiating Auth after ACK lost"); + return; + } + /* + * STA is initiating brand-new Authentication + * sequence after local Auth Response timeout Or STA + * retrying to transmit First Auth frame due to packet + * drop OTA Delete Pre-auth node and fall through. + */ + if (auth_node->fTimerStarted) + lim_deactivate_and_change_per_sta_id_timer( + mac_ctx, eLIM_AUTH_RSP_TIMER, + auth_node->authNodeIdx); + pe_debug("STA is initiating brand-new Auth"); + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + /* + * SAP Mode:Disassociate the station and + * delete its entry if we have its entry + * already and received "auth" from the + * same station. + * SAP dphHashTable.size = 8 + */ + for (associd = 0; associd < pe_session->dph.dphHashTable.size; + associd++) { + sta_ds_ptr = dph_get_hash_entry(mac_ctx, associd, + &pe_session->dph.dphHashTable); + if (!sta_ds_ptr) + continue; + + if (sta_ds_ptr->valid && (!qdf_mem_cmp( + (uint8_t *)&sta_ds_ptr->staAddr, + (uint8_t *) &(mac_hdr->sa), + (uint8_t) sizeof(tSirMacAddr)))) + break; + + sta_ds_ptr = NULL; + } + + if (sta_ds_ptr && !sta_ds_ptr->rmfEnabled) { + pe_debug("lim Del Sta Ctx associd: %d sta mac" + QDF_MAC_ADDR_FMT, associd, + QDF_MAC_ADDR_REF(sta_ds_ptr->staAddr)); + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, + (uint8_t *)auth_node->peerMacAddr, + pe_session, false); + lim_trigger_sta_deletion(mac_ctx, sta_ds_ptr, + pe_session); + return; + } + } + + maxnum_preauth = mac_ctx->mlme_cfg->lfr.max_num_pre_auth; + if (mac_ctx->lim.gLimNumPreAuthContexts == maxnum_preauth && + !lim_delete_open_auth_pre_auth_node(mac_ctx)) { + pe_err("Max no of preauth context reached"); + /* + * Maximum number of pre-auth contexts reached. + * Send Authentication frame with unspecified failure + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_UNSPECIFIED_FAILURE; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + /* No Pre-auth context exists for the STA. */ + if (lim_is_auth_algo_supported(mac_ctx, + (tAniAuthType) rx_auth_frm_body->authAlgoNumber, + pe_session)) { + switch (rx_auth_frm_body->authAlgoNumber) { + case eSIR_OPEN_SYSTEM: + lim_process_auth_open_system_algo(mac_ctx, mac_hdr, + rx_auth_frm_body, auth_frame, pe_session); + break; + + case eSIR_SHARED_KEY: + lim_process_auth_shared_system_algo(mac_ctx, mac_hdr, + rx_auth_frm_body, auth_frame, pe_session); + break; + default: + pe_err("rx Auth frm for unsupported auth algo %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + /* + * Responding party does not support the + * authentication algorithm requested by + * sending party. + * Reject by sending Authentication frame + * with auth algorithm not supported status code + */ + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_NOT_SUPPORTED_AUTH_ALG; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + } else { + pe_err("received Authentication frame for unsupported auth algorithm %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + /* + * Responding party does not support the + * authentication algorithm requested by sending party. + * Reject Authentication with StatusCode=13. + */ + auth_frame->authAlgoNumber = rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_NOT_SUPPORTED_AUTH_ALG; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + return; + } +} + +static void lim_process_auth_frame_type2(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + uint8_t *plainbody, + uint8_t *body_ptr, uint16_t frame_len, + struct pe_session *pe_session) +{ + uint8_t key_id, cfg_privacy_opt_imp; + uint32_t key_length = 8; + qdf_size_t val; + uint8_t defaultkey[SIR_MAC_KEY_LENGTH]; + struct tLimPreAuthNode *auth_node; + uint8_t *encr_auth_frame; + struct wlan_mlme_wep_cfg *wep_params = &mac_ctx->mlme_cfg->wep_params; + QDF_STATUS qdf_status; + + /* AuthFrame 2 */ + if (pe_session->limMlmState != eLIM_MLM_WT_AUTH_FRAME2_STATE) { + /** + * Check if a Reassociation is in progress and this is a + * Pre-Auth frame + */ + if (LIM_IS_STA_ROLE(pe_session) && + (pe_session->limSmeState == eLIM_SME_WT_REASSOC_STATE) && + (rx_auth_frm_body->authStatusCode == STATUS_SUCCESS) && + (pe_session->ftPEContext.pFTPreAuthReq) && + (!qdf_mem_cmp( + pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId, + mac_hdr->sa, sizeof(tSirMacAddr)))) { + + /* Update the FTIEs in the saved auth response */ + pe_warn("rx PreAuth frm2 in smestate: %d from: "QDF_MAC_ADDR_FMT, + pe_session->limSmeState, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + pe_session->ftPEContext.saved_auth_rsp_length = 0; + + if ((body_ptr) && (frame_len < MAX_FTIE_SIZE)) { + qdf_mem_copy( + pe_session->ftPEContext.saved_auth_rsp, + body_ptr, frame_len); + pe_session->ftPEContext.saved_auth_rsp_length = + frame_len; + } + } else { + /* + * Received Auth frame2 in an unexpected state. + * Log error and ignore the frame. + */ + pe_debug("rx Auth frm2 from peer in state: %d addr "QDF_MAC_ADDR_FMT, + pe_session->limMlmState, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + } + return; + } + + if (qdf_mem_cmp((uint8_t *) mac_hdr->sa, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr))) { + /* + * Received Authentication frame from an entity + * other than one request was initiated. + * Wait until Authentication Failure Timeout. + */ + + pe_warn("received Auth frame2 from unexpected peer" + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + if (LIM_IS_STA_ROLE(pe_session) && + wlan_vdev_mlme_is_mlo_vdev(pe_session->vdev)) { + if (!rx_auth_frm_body->is_mlo_ie_present) { + pe_err("MLO IE not present in auth frame from peer, abort connection"); + lim_send_deauth_mgmt_frame( + mac_ctx, REASON_UNSPEC_FAILURE, + pe_session->bssId, pe_session, false); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + REASON_UNSPEC_FAILURE, + pe_session); + return; + } + } + + if (rx_auth_frm_body->authStatusCode == + STATUS_NOT_SUPPORTED_AUTH_ALG) { + /* + * Interoperability workaround: Linksys WAP4400N is returning + * wrong authType in OpenAuth response in case of + * SharedKey AP configuration. Pretend we don't see that, + * so upper layer can fallback to SharedKey authType, + * and successfully connect to the AP. + */ + if (rx_auth_frm_body->authAlgoNumber != + mac_ctx->lim.gpLimMlmAuthReq->authType) { + rx_auth_frm_body->authAlgoNumber = + mac_ctx->lim.gpLimMlmAuthReq->authType; + } + } + + if (rx_auth_frm_body->authAlgoNumber != + mac_ctx->lim.gpLimMlmAuthReq->authType) { + /* + * Auth algo is open in rx auth frame when auth type is SAE and + * PMK is cached as driver sent auth algo as open in tx frame + * as well. + */ + if ((mac_ctx->lim.gpLimMlmAuthReq->authType == + eSIR_AUTH_TYPE_SAE) && pe_session->sae_pmk_cached) { + pe_debug("rx Auth frame2 auth algo %d in SAE PMK case", + rx_auth_frm_body->authAlgoNumber); + } else { + /* + * Received Authentication frame with an auth + * algorithm other than one requested. + * Wait until Authentication Failure Timeout. + */ + + pe_warn("rx Auth frame2 for unexpected auth algo %d" + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + } + + if (rx_auth_frm_body->authStatusCode != STATUS_SUCCESS) { + /* + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + pe_err("rx Auth frame from peer with failure code %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authStatusCode, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_AUTH_REFUSED, + rx_auth_frm_body->authStatusCode, + pe_session); + return; + } + + if (lim_process_fils_auth_frame2(mac_ctx, pe_session, + rx_auth_frm_body)) { + lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS, + rx_auth_frm_body->authStatusCode, pe_session); + return; + } + + if (rx_auth_frm_body->authAlgoNumber == eSIR_OPEN_SYSTEM) { + pe_session->limCurrentAuthType = eSIR_OPEN_SYSTEM; + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (!auth_node) { + pe_warn("Max pre-auth nodes reached SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + pe_debug("add new auth node: for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->authType = + mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_node->seq_num = + ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS, + rx_auth_frm_body->authStatusCode, pe_session); + } else { + /* Shared key authentication */ + if (LIM_IS_AP_ROLE(pe_session)) + cfg_privacy_opt_imp = pe_session->privacy; + else + cfg_privacy_opt_imp = wep_params->is_privacy_enabled; + + if (!cfg_privacy_opt_imp) { + /* + * Requesting STA does not have WEP implemented. + * Reject with unsupported authentication algo + * Status code & wait until auth failure timeout + */ + + pe_err("rx Auth frm from peer for unsupported auth algo %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + auth_frame->authStatusCode = + STATUS_NOT_SUPPORTED_AUTH_ALG; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + if (rx_auth_frm_body->type != WLAN_ELEMID_CHALLENGE) { + pe_err("rx auth frm with invalid challenge txtie"); + return; + } + + key_id = mac_ctx->mlme_cfg->wep_params.wep_default_key_id; + val = SIR_MAC_KEY_LENGTH; + if (LIM_IS_AP_ROLE(pe_session)) { + qdf_status = lim_get_wep_key_sap(pe_session, + wep_params, + key_id, + defaultkey, + &val); + } else { + qdf_status = mlme_get_wep_key(pe_session->vdev, + wep_params, + (MLME_WEP_DEFAULT_KEY_1 + + key_id), defaultkey, + &val); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_warn("cant retrieve Defaultkey"); + + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + rx_auth_frm_body->authTransactionSeqNumber + 1; + + auth_frame->authStatusCode = + STATUS_CHALLENGE_FAIL; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_INVALID_WEP_DEFAULT_KEY, + REASON_UNSPEC_FAILURE, + pe_session); + return; + } + } + key_length = val; + ((tpSirMacAuthFrameBody)plainbody)->authAlgoNumber = + sir_swap_u16if_needed(rx_auth_frm_body->authAlgoNumber); + ((tpSirMacAuthFrameBody)plainbody)->authTransactionSeqNumber = + sir_swap_u16if_needed((uint16_t)( + rx_auth_frm_body->authTransactionSeqNumber + + 1)); + ((tpSirMacAuthFrameBody)plainbody)->authStatusCode = + STATUS_SUCCESS; + ((tpSirMacAuthFrameBody)plainbody)->type = + WLAN_ELEMID_CHALLENGE; + ((tpSirMacAuthFrameBody)plainbody)->length = + rx_auth_frm_body->length; + qdf_mem_copy((uint8_t *) ( + (tpSirMacAuthFrameBody)plainbody)->challengeText, + rx_auth_frm_body->challengeText, + rx_auth_frm_body->length); + encr_auth_frame = qdf_mem_malloc(rx_auth_frm_body->length + + LIM_ENCR_AUTH_INFO_LEN); + if (!encr_auth_frame) + return; + lim_encrypt_auth_frame(mac_ctx, key_id, + defaultkey, plainbody, + encr_auth_frame, key_length); + pe_session->limMlmState = eLIM_MLM_WT_AUTH_FRAME4_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + lim_send_auth_mgmt_frame(mac_ctx, + (tpSirMacAuthFrameBody)encr_auth_frame, + mac_hdr->sa, rx_auth_frm_body->length, + pe_session); + qdf_mem_free(encr_auth_frame); + return; + } +} + +static void lim_process_auth_frame_type3(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + tSirMacAuthFrameBody *auth_frame, + struct pe_session *pe_session) +{ + struct tLimPreAuthNode *auth_node; + + /* AuthFrame 3 */ + if (rx_auth_frm_body->authAlgoNumber != eSIR_SHARED_KEY) { + pe_err("rx Auth frame3 from peer with auth algo number %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * Received Authentication frame3 with algorithm other than + * Shared Key authentication type. Reject with Auth frame4 + * with 'out of sequence' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_UNKNOWN_AUTH_TRANSACTION; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + if (LIM_IS_AP_ROLE(pe_session)) { + /* + * Check if wep bit was set in FC. If not set, + * reject with Authentication frame4 with + * 'challenge failure' status code. + */ + if (!mac_hdr->fc.wep) { + pe_err("received Auth frame3 from peer with no WEP bit set " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* WEP bit is not set in FC of Auth Frame3 */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_CHALLENGE_FAIL; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, + LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (!auth_node) { + pe_warn("received AuthFrame3 from peer that has no preauth context " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * No 'pre-auth' context exists for this STA that sent + * an Authentication frame3. Send Auth frame4 with + * 'out of sequence' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_UNKNOWN_AUTH_TRANSACTION; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + + if (auth_node->mlmState == eLIM_MLM_AUTH_RSP_TIMEOUT_STATE) { + pe_warn("auth response timer timedout for peer " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * Received Auth Frame3 after Auth Response timeout. + * Reject by sending Auth Frame4 with + * Auth respone timeout Status Code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_AUTH_TIMEOUT; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + /* Delete pre-auth context of STA */ + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + return; + } + if (rx_auth_frm_body->authStatusCode != + STATUS_SUCCESS) { + /* + * Received Authenetication Frame 3 with status code + * other than success. Wait until Auth response timeout + * to delete STA context. + */ + pe_err("rx Auth frm3 from peer with status code %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authStatusCode, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + /* + * Check if received challenge text is same as one sent in + * Authentication frame3 + */ + if (!qdf_mem_cmp(rx_auth_frm_body->challengeText, + auth_node->challengeText, + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH)) { + /* + * Challenge match. STA is authenticated + * Delete Authentication response timer if running + */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + + auth_node->fTimerStarted = 0; + auth_node->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + + /* + * Send Auth Frame4 with 'success' Status Code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_SUCCESS; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } else { + pe_warn("Challenge failure for peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * Challenge Failure. + * Send Authentication frame4 with 'challenge failure' + * status code and wait until Auth response timeout to + * delete STA context. + */ + auth_frame->authAlgoNumber = + rx_auth_frm_body->authAlgoNumber; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_CHALLENGE_FAIL; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + return; + } + } +} + +static void lim_process_auth_frame_type4(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + tSirMacAuthFrameBody *rx_auth_frm_body, + struct pe_session *pe_session) +{ + struct tLimPreAuthNode *auth_node; + + if (pe_session->limMlmState != eLIM_MLM_WT_AUTH_FRAME4_STATE) { + /* + * Received Authentication frame4 in an unexpected state. + * Log error and ignore the frame. + */ + pe_warn("received unexpected Auth frame4 from peer in state %d, addr " + QDF_MAC_ADDR_FMT, + pe_session->limMlmState, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authAlgoNumber != eSIR_SHARED_KEY) { + /* + * Received Authentication frame4 with algorithm other than + * Shared Key authentication type. + * Wait until Auth failure timeout to report authentication + * failure to SME. + */ + pe_err("received Auth frame4 from peer with invalid auth algo %d" + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authAlgoNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + if (qdf_mem_cmp((uint8_t *) mac_hdr->sa, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr))) { + /* + * Received Authentication frame from an entity + * other than one to which request was initiated. + * Wait until Authentication Failure Timeout. + */ + + pe_warn("received Auth frame4 from unexpected peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authAlgoNumber != + mac_ctx->lim.gpLimMlmAuthReq->authType) { + /* + * Received Authentication frame with an auth algorithm + * other than one requested. + * Wait until Authentication Failure Timeout. + */ + + pe_err("received Authentication frame from peer with invalid auth seq number %d " + QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authTransactionSeqNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + if (rx_auth_frm_body->authStatusCode == STATUS_SUCCESS) { + /* + * Authentication Success, Inform SME of same. + */ + pe_session->limCurrentAuthType = eSIR_SHARED_KEY; + auth_node = lim_acquire_free_pre_auth_node(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable); + if (!auth_node) { + pe_warn("Max pre-auth nodes reached SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + pe_debug("Alloc new data: %pK peer "QDF_MAC_ADDR_FMT, auth_node, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + qdf_mem_copy((uint8_t *) auth_node->peerMacAddr, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + auth_node->fTimerStarted = 0; + auth_node->authType = mac_ctx->lim.gpLimMlmAuthReq->authType; + auth_node->seq_num = ((mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo)); + auth_node->timestamp = qdf_mc_timer_get_system_ticks(); + lim_add_pre_auth_node(mac_ctx, auth_node); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_SUCCESS, + rx_auth_frm_body->authStatusCode, pe_session); + } else { + /* + * Authentication failure. + * Return Auth confirm with received failure code to SME + */ + pe_err("Authentication failure from peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + lim_restore_from_auth_state(mac_ctx, eSIR_SME_AUTH_REFUSED, + rx_auth_frm_body->authStatusCode, + pe_session); + } +} + +/** + * lim_process_auth_frame() - to process auth frame + * @mac_ctx - Pointer to Global MAC structure + * @rx_pkt_info - A pointer to Rx packet info structure + * @session - A pointer to session + * + * This function is called by limProcessMessageQueue() upon Authentication + * frame reception. + * + * LOGIC: + * This function processes received Authentication frame and responds + * with either next Authentication frame in sequence to peer MAC entity + * or LIM_MLM_AUTH_IND on AP or LIM_MLM_AUTH_CNF on STA. + * + * NOTE: + * 1. Authentication failures are reported to SME with same status code + * received from the peer MAC entity. + * 2. Authentication frame2/4 received with algorithm number other than + * one requested in frame1/3 are logged with an error and auth confirm + * will be sent to SME only after auth failure timeout. + * 3. Inconsistency in the spec: + * On receiving Auth frame2, specs says that if WEP key mapping key + * or default key is NULL, Auth frame3 with a status code 15 (challenge + * failure to be returned to peer entity. However, section 7.2.3.10, + * table 14 says that status code field is 'reserved' for frame3 ! + * In the current implementation, Auth frame3 is returned with status + * code 15 overriding section 7.2.3.10. + * 4. If number pre-authentications reach configrable max limit, + * Authentication frame with 'unspecified failure' status code is + * returned to requesting entity. + * + * Return: None + */ +void +lim_process_auth_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + struct pe_session *pe_session) +{ + uint8_t *body_ptr, key_id, cfg_privacy_opt_imp; + uint8_t defaultkey[SIR_MAC_KEY_LENGTH]; + uint8_t *plainbody = NULL; + uint8_t decrypt_result; + uint16_t frame_len, curr_seq_num = 0, auth_alg; + uint32_t key_length = 8; + qdf_size_t val; + tSirMacAuthFrameBody *rx_auth_frm_body, *rx_auth_frame, *auth_frame; + tpSirMacMgmtHdr mac_hdr; + struct tLimPreAuthNode *auth_node; + struct wlan_mlme_wep_cfg *wep_params = &mac_ctx->mlme_cfg->wep_params; + QDF_STATUS qdf_status; + + /* Get pointer to Authentication frame header and body */ + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + if (!frame_len) { + /* Log error */ + pe_err("received Auth frame with no body from: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + + if (IEEE80211_IS_MULTICAST(mac_hdr->sa)) { + /* + * Received Auth frame from a BC/MC address + * Log error and ignore it + */ + pe_err("received Auth frame from a BC/MC addr: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + return; + } + curr_seq_num = (mac_hdr->seqControl.seqNumHi << 4) | + (mac_hdr->seqControl.seqNumLo); + + if (pe_session->prev_auth_seq_num == curr_seq_num && + !qdf_mem_cmp(pe_session->prev_auth_mac_addr, &mac_hdr->sa, + ETH_ALEN) && + mac_hdr->fc.retry) { + pe_debug("auth frame, seq num: %d is already processed, drop it", + curr_seq_num); + return; + } + + /* Duplicate Auth frame from peer */ + auth_node = lim_search_pre_auth_list(mac_ctx, mac_hdr->sa); + if (auth_node && (auth_node->seq_num == curr_seq_num)) { + pe_err("Received an already processed auth frame with seq_num : %d", + curr_seq_num); + return; + } + + /* save seq number and mac_addr in pe_session */ + pe_session->prev_auth_seq_num = curr_seq_num; + qdf_mem_copy(pe_session->prev_auth_mac_addr, mac_hdr->sa, ETH_ALEN); + + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + if (frame_len < 2) { + pe_err("invalid frame len: %d", frame_len); + return; + } + auth_alg = *(uint16_t *) body_ptr; + + pe_nofl_rl_info("Auth RX: vdev %d sys role %d lim_state %d from " QDF_MAC_ADDR_FMT " rssi %d auth_alg %d seq %d", + pe_session->vdev_id, GET_LIM_SYSTEM_ROLE(pe_session), + pe_session->limMlmState, + QDF_MAC_ADDR_REF(mac_hdr->sa), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + auth_alg, curr_seq_num); + + /* Restore default failure timeout */ + if (QDF_P2P_CLIENT_MODE == pe_session->opmode && + pe_session->defaultAuthFailureTimeout) { + pe_debug("Restore default failure timeout"); + if (cfg_in_range(CFG_AUTH_FAILURE_TIMEOUT, + pe_session->defaultAuthFailureTimeout)) { + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = + pe_session->defaultAuthFailureTimeout; + } else { + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = + cfg_default(CFG_AUTH_FAILURE_TIMEOUT); + pe_session->defaultAuthFailureTimeout = + cfg_default(CFG_AUTH_FAILURE_TIMEOUT); + } + } + + rx_auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!rx_auth_frame) + return; + + auth_frame = qdf_mem_malloc(sizeof(tSirMacAuthFrameBody)); + if (!auth_frame) + goto free; + + plainbody = qdf_mem_malloc(LIM_ENCR_AUTH_BODY_LEN); + if (!plainbody) + goto free; + + qdf_mem_zero(plainbody, LIM_ENCR_AUTH_BODY_LEN); + + /* + * Determine if WEP bit is set in the FC or received MAC header + * Note: WEP bit is set in FC of MAC header. + */ + if (mac_hdr->fc.wep) { + if (frame_len < 4) { + pe_err("invalid frame len: %d", frame_len); + goto free; + } + /* Extract key ID from IV (most 2 bits of 4th byte of IV) */ + key_id = (*(body_ptr + 3)) >> 6; + + /* + * On STA in infrastructure BSS, Authentication frames received + * with WEP bit set in the FC must be rejected with challenge + * failure status code (weird thing in the spec - this should've + * been rejected with unspecified failure/unexpected assertion + * of wep bit (this status code does not exist though) or + * Out-of-sequence-Authentication-Frame status code. + */ + if (LIM_IS_STA_ROLE(pe_session)) { + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_CHALLENGE_FAIL; + /* Log error */ + pe_err("rx Auth frm with wep bit set role: %d "QDF_MAC_ADDR_FMT, + GET_LIM_SYSTEM_ROLE(pe_session), + QDF_MAC_ADDR_REF(mac_hdr->sa)); + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + if ((frame_len < LIM_ENCR_AUTH_BODY_LEN_SAP) || + (frame_len > LIM_ENCR_AUTH_BODY_LEN)) { + /* Log error */ + pe_err("Not enough size: %d to decry rx Auth frm "QDF_MAC_ADDR_FMT, + frame_len, QDF_MAC_ADDR_REF(mac_hdr->sa)); + goto free; + } + + /* + * Accept Authentication frame only if Privacy is + * implemented + */ + if (LIM_IS_AP_ROLE(pe_session)) + cfg_privacy_opt_imp = pe_session->privacy; + else + cfg_privacy_opt_imp = wep_params->is_privacy_enabled; + + if (!cfg_privacy_opt_imp) { + pe_err("received Authentication frame3 from peer that while privacy option is turned OFF " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * Privacy option is not implemented. + * So reject Authentication frame received with + * WEP bit set by sending Authentication frame + * with 'challenge failure' status code. This is + * another strange thing in the spec. Status code + * should have been 'unsupported algorithm' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_CHALLENGE_FAIL; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + /* + * Privacy option is implemented. Check if the received frame is + * Authentication frame3 and there is a context for requesting + * STA. If not, reject with unspecified failure status code + */ + if (!auth_node) { + pe_err("rx Auth frame with no preauth ctx with WEP bit set " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * No 'pre-auth' context exists for this STA + * that sent an Authentication frame with FC + * bit set. Send Auth frame4 with + * 'out of sequence' status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_UNKNOWN_AUTH_TRANSACTION; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + /* Change the auth-response timeout */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + + /* 'Pre-auth' status exists for STA */ + if ((auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) && + (auth_node->mlmState != + eLIM_MLM_AUTH_RSP_TIMEOUT_STATE)) { + pe_err("received Authentication frame from peer that is in state %d " + QDF_MAC_ADDR_FMT, + auth_node->mlmState, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* + * Should not have received Authentication frame + * with WEP bit set in FC in other states. + * Reject by sending Authenticaton frame with + * out of sequence Auth frame status code. + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_UNKNOWN_AUTH_TRANSACTION; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + + val = SIR_MAC_KEY_LENGTH; + + if (LIM_IS_AP_ROLE(pe_session)) { + qdf_status = lim_get_wep_key_sap(pe_session, + wep_params, + key_id, + defaultkey, + &val); + } else { + qdf_status = mlme_get_wep_key(pe_session->vdev, + wep_params, + (MLME_WEP_DEFAULT_KEY_1 + + key_id), defaultkey, + &val); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_warn("could not retrieve Default key"); + + /* + * Send Authentication frame + * with challenge failure status code + */ + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = + STATUS_CHALLENGE_FAIL; + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + } + + key_length = val; + decrypt_result = lim_decrypt_auth_frame(mac_ctx, defaultkey, + body_ptr, plainbody, key_length, + (uint16_t) (frame_len - + SIR_MAC_WEP_IV_LENGTH)); + if (decrypt_result == LIM_DECRYPT_ICV_FAIL) { + pe_err("received Authentication frame from peer that failed decryption: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* ICV failure */ + lim_delete_pre_auth_node(mac_ctx, mac_hdr->sa); + auth_frame->authAlgoNumber = eSIR_SHARED_KEY; + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + auth_frame->authStatusCode = STATUS_CHALLENGE_FAIL; + + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_hdr->sa, LIM_NO_WEP_IN_FC, + pe_session); + goto free; + } + if ((sir_convert_auth_frame2_struct(mac_ctx, plainbody, + frame_len - 8, rx_auth_frame) != QDF_STATUS_SUCCESS) + || (!is_auth_valid(mac_ctx, rx_auth_frame, + pe_session))) { + pe_err("failed to convert Auth Frame to structure or Auth is not valid"); + goto free; + } + } else if (auth_alg == eSIR_AUTH_TYPE_SAE) { + if (LIM_IS_STA_ROLE(pe_session) || + (LIM_IS_AP_ROLE(pe_session) && + mac_ctx->mlme_cfg->sap_cfg.sap_sae_enabled)) + lim_process_sae_auth_frame(mac_ctx, rx_pkt_info, + pe_session); + goto free; + } else if (auth_alg == eSIR_AUTH_TYPE_PASN) { + lim_process_pasn_auth_frame(mac_ctx, pe_session->vdev_id, + rx_pkt_info); + goto free; + } else if (auth_alg == eSIR_FT_AUTH && LIM_IS_AP_ROLE(pe_session)) { + pe_debug("Auth Frame auth_alg eSIR_FT_AUTH"); + lim_process_ft_auth_frame(mac_ctx, + rx_pkt_info, pe_session); + goto free; + } else if ((sir_convert_auth_frame2_struct(mac_ctx, body_ptr, + frame_len, rx_auth_frame) != QDF_STATUS_SUCCESS) + || (!is_auth_valid(mac_ctx, rx_auth_frame, + pe_session))) { + pe_err("failed to convert Auth Frame to structure or Auth is not valid"); + goto free; + } + + rx_auth_frm_body = rx_auth_frame; + + if (!lim_is_valid_fils_auth_frame(mac_ctx, pe_session, + rx_auth_frm_body)) { + pe_err("Received invalid FILS auth packet"); + goto free; + } + + /* + * IOT Workaround: with invalid WEP key, some APs reply + * AuthFrame 4 with invalid seqNumber. This AuthFrame + * will be dropped by driver, thus driver sends the + * generic status code instead of protocol status code. + * As a workaround, override AuthFrame 4's seqNumber. + */ + if ((pe_session->limMlmState == + eLIM_MLM_WT_AUTH_FRAME4_STATE) && + (rx_auth_frm_body->authTransactionSeqNumber != + SIR_MAC_AUTH_FRAME_1) && + (rx_auth_frm_body->authTransactionSeqNumber != + SIR_MAC_AUTH_FRAME_2) && + (rx_auth_frm_body->authTransactionSeqNumber != + SIR_MAC_AUTH_FRAME_3)) { + pe_warn("Override AuthFrame 4's seqNumber to 4"); + rx_auth_frm_body->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_4; + } + + wlan_connectivity_mgmt_event(mac_ctx->psoc, + (struct wlan_frame_hdr *)mac_hdr, + pe_session->vdev_id, + rx_auth_frm_body->authStatusCode, + 0, WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info), + auth_alg, 0, + rx_auth_frm_body->authTransactionSeqNumber, + 0, WLAN_AUTH_RESP); + + lim_cp_stats_cstats_log_auth_evt + (pe_session, CSTATS_DIR_RX, auth_alg, + rx_auth_frm_body->authTransactionSeqNumber, + rx_auth_frm_body->authStatusCode); + + switch (rx_auth_frm_body->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_1: + lim_process_auth_frame_type1(mac_ctx, + mac_hdr, rx_auth_frm_body, rx_pkt_info, + curr_seq_num, auth_frame, pe_session); + break; + case SIR_MAC_AUTH_FRAME_2: + lim_process_auth_frame_type2(mac_ctx, + mac_hdr, rx_auth_frm_body, auth_frame, plainbody, + body_ptr, frame_len, pe_session); + break; + case SIR_MAC_AUTH_FRAME_3: + lim_process_auth_frame_type3(mac_ctx, + mac_hdr, rx_auth_frm_body, auth_frame, pe_session); + break; + case SIR_MAC_AUTH_FRAME_4: + lim_process_auth_frame_type4(mac_ctx, + mac_hdr, rx_auth_frm_body, pe_session); + break; + default: + /* Invalid Authentication Frame received. Ignore it. */ + pe_warn("rx auth frm with invalid authseq no: %d from: "QDF_MAC_ADDR_FMT, + rx_auth_frm_body->authTransactionSeqNumber, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + break; + } +free: + if (auth_frame) + qdf_mem_free(auth_frame); + if (rx_auth_frame) + qdf_mem_free(rx_auth_frame); + if (plainbody) + qdf_mem_free(plainbody); +} + +/** + * lim_process_sae_preauth_frame() - Send the WPA3 preauth SAE frame received + * to the user space. + * @mac: Global mac context + * @rx_pkt: Received auth packet + * + * SAE auth frame will be received with no session if its SAE preauth during + * roaming offloaded to the host. Forward this frame to the wpa supplicant. + * + * Return: True if auth algo is SAE else false + */ +static +bool lim_process_sae_preauth_frame(struct mac_context *mac, uint8_t *rx_pkt) +{ + tpSirMacMgmtHdr dot11_hdr; + tSirMacMgmtHdr original_hdr; + uint16_t auth_alg, frm_len; + uint16_t sae_auth_seq = 0, sae_status_code = 0; + uint8_t *frm_body, pdev_id, vdev_id; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + dot11_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt); + original_hdr = *dot11_hdr; + frm_body = WMA_GET_RX_MPDU_DATA(rx_pkt); + frm_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt); + + if (frm_len < 2) { + pe_debug("LFR3: Invalid auth frame len:%d", frm_len); + return false; + } + + auth_alg = *(uint16_t *)frm_body; + if (auth_alg != eSIR_AUTH_TYPE_SAE) + return false; + + if (frm_len >= (SAE_AUTH_STATUS_CODE_OFFSET + 2)) { + sae_auth_seq = + *(uint16_t *)(frm_body + SAE_AUTH_SEQ_NUM_OFFSET); + sae_status_code = + *(uint16_t *)(frm_body + SAE_AUTH_STATUS_CODE_OFFSET); + } + + pe_debug("LFR3: SAE auth frame: seq_ctrl:0x%X auth_transaction_num:%d", + ((dot11_hdr->seqControl.seqNumHi << 8) | + (dot11_hdr->seqControl.seqNumLo << 4) | + (dot11_hdr->seqControl.fragNum)), *(uint16_t *)(frm_body + 2)); + + pdev_id = wlan_objmgr_pdev_get_pdev_id(mac->pdev); + vdev = wlan_objmgr_get_vdev_by_macaddr_from_psoc(mac->psoc, pdev_id, + dot11_hdr->da, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + vdev = wlan_objmgr_pdev_get_roam_vdev(mac->pdev, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("not able to find roaming vdev"); + return false; + } + } + + vdev_id = wlan_vdev_get_id(vdev); + lim_sae_auth_cleanup_retry(mac, vdev_id); + status = lim_update_link_to_mld_address(mac, vdev, dot11_hdr); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("vdev:%d dropping auth frame BSSID: " QDF_MAC_ADDR_FMT ", SAE address conversion failure", + vdev_id, QDF_MAC_ADDR_REF(dot11_hdr->bssId)); + return false; + } + + wlan_connectivity_mgmt_event(mac->psoc, + (struct wlan_frame_hdr *)&original_hdr, + vdev_id, sae_status_code, + 0, WMA_GET_RX_RSSI_NORMALIZED(rx_pkt), + auth_alg, sae_auth_seq, + sae_auth_seq, 0, WLAN_AUTH_RESP); + + lim_send_sme_mgmt_frame_ind(mac, dot11_hdr->fc.subType, + (uint8_t *)dot11_hdr, + frm_len + sizeof(tSirMacMgmtHdr), + SME_SESSION_ID_ANY, + WMA_GET_RX_FREQ(rx_pkt), + WMA_GET_RX_RSSI_NORMALIZED(rx_pkt), + RXMGMT_FLAG_NONE); + return true; +} + +#define WLAN_MIN_AUTH_FRM_ALGO_FIELD_LEN 2 + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void lim_process_ft_sae_auth_frame(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t *body, uint16_t frame_len) +{ +} +#else +/** + * lim_process_ft_sae_auth_frame() - process SAE pre auth frame for LFR2 + * @mac: pointer to mac_context + * @pe_session: pointer to pe session + * @body: auth frame body + * @frame_len: auth frame length + * + * Return: void + */ +static void lim_process_ft_sae_auth_frame(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t *body, uint16_t frame_len) +{ + tpSirMacAuthFrameBody auth = (tpSirMacAuthFrameBody)body; + + if (!pe_session || !pe_session->ftPEContext.pFTPreAuthReq) { + pe_debug("cannot find session or FT in FT pre-auth phase"); + return; + } + + if (auth->authTransactionSeqNumber == SIR_MAC_AUTH_FRAME_2) + lim_handle_ft_pre_auth_rsp(mac, QDF_STATUS_SUCCESS, body, + frame_len, pe_session); +} +#endif + +/** + * + * Pass the received Auth frame. This is possibly the pre-auth from the + * neighbor AP, in the same mobility domain. + * This will be used in case of 11r FT. + * + ***---------------------------------------------------------------------- + */ +QDF_STATUS lim_process_auth_frame_no_session(struct mac_context *mac, + uint8_t *pBd, void *body) +{ + tpSirMacMgmtHdr mac_hdr; + struct pe_session *pe_session = NULL; + uint8_t *pBody; + uint8_t vdev_id; + uint16_t frameLen, curr_seq_num, auth_alg = 0; + tSirMacAuthFrameBody *rx_auth_frame; + QDF_STATUS ret_status = QDF_STATUS_E_FAILURE; + int i; + bool sae_auth_frame; + + mac_hdr = WMA_GET_RX_MAC_HEADER(pBd); + pBody = WMA_GET_RX_MPDU_DATA(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + curr_seq_num = mac_hdr->seqControl.seqNumHi << 4 | + mac_hdr->seqControl.seqNumLo; + + if (frameLen == 0) { + pe_err("Frame len = 0"); + return QDF_STATUS_E_FAILURE; + } + + if (frameLen > WLAN_MIN_AUTH_FRM_ALGO_FIELD_LEN) + auth_alg = *(uint16_t *)pBody; + + pe_debug("Auth RX: BSSID " QDF_MAC_ADDR_FMT " RSSI:%d auth_alg:%d seq:%d", + QDF_MAC_ADDR_REF(mac_hdr->bssId), + (uint)abs((int8_t)WMA_GET_RX_RSSI_NORMALIZED(pBd)), + auth_alg, curr_seq_num); + + /* Auth frame has come on a new BSS, however, we need to find the session + * from where the auth-req was sent to the new AP + */ + for (i = 0; i < mac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (mac->lim.gpSession[i].valid == true && + mac->lim.gpSession[i].ftPEContext.ftPreAuthSession == + true) { + /* Found the session */ + pe_session = &mac->lim.gpSession[i]; + mac->lim.gpSession[i].ftPEContext.ftPreAuthSession = + false; + } + } + + sae_auth_frame = lim_process_sae_preauth_frame(mac, pBd); + if (sae_auth_frame) { + lim_process_ft_sae_auth_frame(mac, pe_session, pBody, frameLen); + return QDF_STATUS_SUCCESS; + } + + if (auth_alg == eSIR_AUTH_TYPE_PASN) { + vdev_id = lim_get_pasn_peer_vdev_id(mac, mac_hdr->bssId); + if (vdev_id == WLAN_UMAC_VDEV_ID_MAX) { + /* + * This can be NAN auth mgmt frame and for NAN, PASN + * peer is not available. + */ + vdev_id = wlan_nan_get_vdev_id_from_bssid(mac->pdev, + mac_hdr->bssId, + WLAN_MGMT_RX_ID); + if (vdev_id == WLAN_UMAC_VDEV_ID_MAX) { + pe_err("NAN vdev_id not found"); + return QDF_STATUS_E_FAILURE; + } + } + + return lim_process_pasn_auth_frame(mac, vdev_id, pBd); + } + + if (!pe_session) { + pe_debug("cannot find session id in FT pre-auth phase"); + return QDF_STATUS_E_FAILURE; + } + + if (!pe_session->ftPEContext.pFTPreAuthReq) { + pe_err("Error: No FT"); + /* No FT in progress. */ + return QDF_STATUS_E_FAILURE; + } + + /* Check that its the same bssId we have for preAuth */ + if (qdf_mem_cmp + (pe_session->ftPEContext.pFTPreAuthReq->preAuthbssId, + mac_hdr->bssId, sizeof(tSirMacAddr))) { + pe_err("Error: Same bssid as preauth BSSID"); + /* In this case SME if indeed has triggered a */ + /* pre auth it will time out. */ + return QDF_STATUS_E_FAILURE; + } + + if (true == + pe_session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed) { + /* + * This is likely a duplicate for the same pre-auth request. + * PE/LIM already posted a response to SME. Hence, drop it. + * TBD: + * 1) How did we even receive multiple auth responses? + * 2) Do we need to delete pre-auth session? Suppose we + * previously received an auth resp with failure which + * would not have created the session and forwarded to SME. + * And, we subsequently received an auth resp with success + * which would have created the session. This will now be + * dropped without being forwarded to SME! However, it is + * very unlikely to receive auth responses from the same + * AP with different reason codes. + * NOTE: return QDF_STATUS_SUCCESS so that the packet is dropped + * as this was indeed a response from the BSSID we tried to + * pre-auth. + */ + pe_debug("Auth rsp already posted to SME" + " (session %pK, FT session %pK)", pe_session, + pe_session); + return QDF_STATUS_SUCCESS; + } else { + pe_warn("Auth rsp not yet posted to SME" + " (session %pK, FT session %pK)", pe_session, + pe_session); + pe_session->ftPEContext.pFTPreAuthReq->bPreAuthRspProcessed = + true; + } + + /* Stopping timer now, that we have our unicast from the AP */ + /* of our choice. */ + lim_deactivate_and_change_timer(mac, eLIM_FT_PREAUTH_RSP_TIMER); + + rx_auth_frame = qdf_mem_malloc(sizeof(*rx_auth_frame)); + if (!rx_auth_frame) { + lim_handle_ft_pre_auth_rsp(mac, QDF_STATUS_E_FAILURE, NULL, 0, + pe_session); + return QDF_STATUS_E_NOMEM; + } + + /* Save off the auth resp. */ + if ((sir_convert_auth_frame2_struct(mac, pBody, frameLen, + rx_auth_frame) != + QDF_STATUS_SUCCESS)) { + pe_err("failed to convert Auth frame to struct"); + lim_handle_ft_pre_auth_rsp(mac, QDF_STATUS_E_FAILURE, NULL, 0, + pe_session); + qdf_mem_free(rx_auth_frame); + return QDF_STATUS_E_FAILURE; + } + pe_info("Pre-Auth RX: type: %d trans_seqnum: %d status: %d %d from " QDF_MAC_ADDR_FMT, + (uint32_t)rx_auth_frame->authAlgoNumber, + (uint32_t)rx_auth_frame->authTransactionSeqNumber, + (uint32_t)rx_auth_frame->authStatusCode, + (uint32_t)mac->lim.gLimNumPreAuthContexts, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + + switch (rx_auth_frame->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_2: + if (rx_auth_frame->authStatusCode != STATUS_SUCCESS) { + pe_err("Auth status code received is %d", + (uint32_t)rx_auth_frame->authStatusCode); + if (STATUS_AP_UNABLE_TO_HANDLE_NEW_STA == + rx_auth_frame->authStatusCode) + ret_status = QDF_STATUS_E_NOSPC; + } else { + ret_status = QDF_STATUS_SUCCESS; + } + break; + + default: + pe_warn("Seq. no incorrect expected 2 received %d", + (uint32_t)rx_auth_frame->authTransactionSeqNumber); + break; + } + + /* Send the Auth response to SME */ + lim_handle_ft_pre_auth_rsp(mac, ret_status, pBody, + frameLen, pe_session); + qdf_mem_free(rx_auth_frame); + + return ret_status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c new file mode 100644 index 0000000000..870f90abe5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_beacon_frame.c @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_process_beacon_frame.cc contains the code + * for processing Received Beacon Frame. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_cfg.h" +#include "ani_global.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "wlan_mlo_t2lm.h" +#include "wlan_mlo_mgr_roam.h" +#include "lim_mlo.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_cm_api.h" +#include "wlan_mlme_api.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_reg_services_api.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include +#endif +#include "wlan_t2lm_api.h" + +/*Invalid Recommended Max Simultaneous Links value */ +#define RESERVED_REC_LINK_VALUE 1 + +#ifdef WLAN_FEATURE_11BE_MLO + +void lim_process_bcn_prb_rsp_t2lm(struct mac_context *mac_ctx, + struct pe_session *session, + tpSirProbeRespBeacon bcn_ptr) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_t2lm_context *t2lm_ctx; + + if (!session || !bcn_ptr || !mac_ctx) { + pe_err("invalid input parameters"); + return; + } + + if (!wlan_mlme_get_t2lm_negotiation_supported(mac_ctx->psoc)) { + pe_err_rl("T2LM negotiation not supported"); + return; + } + + vdev = session->vdev; + if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + if (!wlan_cm_is_vdev_connected(vdev)) + return; + + if (!mlo_check_if_all_links_up(vdev)) + return; + + t2lm_ctx = &vdev->mlo_dev_ctx->t2lm_ctx; + + qdf_mem_copy((uint8_t *)&t2lm_ctx->tsf, (uint8_t *)bcn_ptr->timeStamp, + sizeof(uint64_t)); + wlan_update_t2lm_mapping(vdev, &bcn_ptr->t2lm_ctx, t2lm_ctx->tsf); +} + +static uint8_t valid_max_rec_links(uint8_t value) +{ + if (value > RESERVED_REC_LINK_VALUE && + value <= WLAN_DEFAULT_REC_LINK_VALUE) + return value; + return WLAN_DEFAULT_REC_LINK_VALUE; +} + +void lim_process_beacon_mlo(struct mac_context *mac_ctx, + struct pe_session *session, + tSchBeaconStruct *bcn_ptr) +{ + struct csa_offload_params csa_param; + int i; + uint8_t link_id; + uint8_t *per_sta_pro; + uint32_t per_sta_pro_len; + uint8_t *sta_pro; + uint32_t sta_pro_len; + uint16_t stacontrol; + struct ieee80211_channelswitch_ie *csa_ie; + struct ieee80211_extendedchannelswitch_ie *xcsa_ie; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct wlan_mlo_dev_context *mlo_ctx; + uint8_t is_sta_csa_synced; + struct mlo_link_info *link_info; + uint8_t sta_info_len = 0; + uint8_t tmp_rec_value; + + if (!session || !bcn_ptr || !mac_ctx) { + pe_err("invalid input parameters"); + return; + } + vdev = session->vdev; + if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + pe_err("null pdev"); + return; + } + mlo_ctx = vdev->mlo_dev_ctx; + if (!mlo_ctx) { + pe_err("null mlo_dev_ctx"); + return; + } + + if (bcn_ptr->mlo_ie.mlo_ie.medium_sync_delay_info_present) { + wlan_vdev_mlme_cap_clear(vdev, WLAN_VDEV_C_EMLSR_CAP); + pe_debug("EMLSR not supported with D2.0 AP"); + } + + /** max num of active links recommended by AP */ + tmp_rec_value = + bcn_ptr->mlo_ie.mlo_ie.ext_mld_capab_and_op_info.rec_max_simultaneous_links; + mlo_ctx->mlo_max_recom_simult_links = + valid_max_rec_links(tmp_rec_value); + + for (i = 0; i < bcn_ptr->mlo_ie.mlo_ie.num_sta_profile; i++) { + csa_ie = NULL; + xcsa_ie = NULL; + qdf_mem_zero(&csa_param, sizeof(csa_param)); + per_sta_pro = bcn_ptr->mlo_ie.mlo_ie.sta_profile[i].data; + /* Append one byte to get the element length */ + per_sta_pro_len = bcn_ptr->mlo_ie.mlo_ie.sta_profile[i].num_data; + stacontrol = *(uint16_t *)(per_sta_pro + sizeof(struct subelem_header)); + sta_info_len = *(uint8_t *)(per_sta_pro + + sizeof(struct subelem_header) + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE); + /* IE ID + LEN + STA control STA info len*/ + sta_pro = per_sta_pro + sizeof(struct subelem_header) + + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE + sta_info_len; + sta_pro_len = per_sta_pro_len - sizeof(struct subelem_header) - + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE - sta_info_len; + link_id = QDF_GET_BITS( + stacontrol, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS); + + csa_ie = (struct ieee80211_channelswitch_ie *) + wlan_get_ie_ptr_from_eid( + DOT11F_EID_CHANSWITCHANN, + sta_pro, sta_pro_len); + xcsa_ie = (struct ieee80211_extendedchannelswitch_ie *) + wlan_get_ie_ptr_from_eid( + DOT11F_EID_EXT_CHAN_SWITCH_ANN, + sta_pro, sta_pro_len); + is_sta_csa_synced = mlo_is_sta_csa_synced(mlo_ctx, link_id); + link_info = mlo_mgr_get_ap_link_by_link_id(mlo_ctx, link_id); + if (!link_info) { + mlo_err("link info null"); + return; + } + + if (csa_ie) { + csa_param.channel = csa_ie->newchannel; + csa_param.csa_chan_freq = wlan_reg_legacy_chan_to_freq( + pdev, csa_ie->newchannel); + csa_param.switch_mode = csa_ie->switchmode; + csa_param.ies_present_flag |= MLME_CSA_IE_PRESENT; + mlo_sta_handle_csa_standby_link(mlo_ctx, link_id, + &csa_param, vdev); + + if (!is_sta_csa_synced) + mlo_sta_csa_save_params(mlo_ctx, link_id, + &csa_param); + } else if (xcsa_ie) { + csa_param.channel = xcsa_ie->newchannel; + csa_param.switch_mode = xcsa_ie->switchmode; + csa_param.new_op_class = xcsa_ie->newClass; + if (wlan_reg_is_6ghz_op_class(pdev, xcsa_ie->newClass)) + csa_param.csa_chan_freq = + wlan_reg_chan_band_to_freq( + pdev, xcsa_ie->newchannel, + BIT(REG_BAND_6G)); + else + csa_param.csa_chan_freq = + wlan_reg_legacy_chan_to_freq( + pdev, xcsa_ie->newchannel); + csa_param.ies_present_flag |= MLME_XCSA_IE_PRESENT; + mlo_sta_handle_csa_standby_link(mlo_ctx, link_id, + &csa_param, vdev); + if (!is_sta_csa_synced) + mlo_sta_csa_save_params(mlo_ctx, link_id, + &csa_param); + } + } +} +#endif + +static QDF_STATUS +lim_validate_rsn_ie(const uint8_t *ie_ptr, uint16_t ie_len) +{ + QDF_STATUS status; + const uint8_t *rsn_ie; + struct wlan_crypto_params crypto_params; + + rsn_ie = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSN, ie_ptr, ie_len); + if (!rsn_ie) + return QDF_STATUS_SUCCESS; + + qdf_mem_zero(&crypto_params, sizeof(struct wlan_crypto_params)); + status = wlan_crypto_rsnie_check(&crypto_params, rsn_ie); + if (status != QDF_STATUS_SUCCESS) { + pe_debug_rl("RSN IE check failed %d", status); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +/** + * lim_get_update_eht_bw_puncture_allow() - whether bw and puncture can be + * sent to target directly + * @session: pe session + * @ori_bw: bandwdith from beacon + * @new_bw: bandwidth intersection between reference AP and STA + * @update_allow: return true if bw and puncture can be updated directly + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_get_update_eht_bw_puncture_allow(struct pe_session *session, + enum phy_ch_width ori_bw, + enum phy_ch_width *new_bw, + bool *update_allow) +{ + enum phy_ch_width ch_width; + struct wlan_objmgr_psoc *psoc; + enum wlan_phymode phy_mode; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + *update_allow = false; + + psoc = wlan_vdev_get_psoc(session->vdev); + if (!psoc) { + pe_err("psoc object invalid"); + return QDF_STATUS_E_INVAL; + } + status = mlme_get_peer_phymode(psoc, session->bssId, &phy_mode); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to get phy_mode %d mac: " QDF_MAC_ADDR_FMT, + status, QDF_MAC_ADDR_REF(session->bssId)); + return QDF_STATUS_E_INVAL; + } + ch_width = wlan_mlme_get_ch_width_from_phymode(phy_mode); + + if (ori_bw <= ch_width) { + *new_bw = ori_bw; + *update_allow = true; + return QDF_STATUS_SUCCESS; + } + + if ((ori_bw == CH_WIDTH_320MHZ) && + !session->eht_config.support_320mhz_6ghz) { + if (ch_width == CH_WIDTH_160MHZ) { + *new_bw = CH_WIDTH_160MHZ; + *update_allow = true; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_SUCCESS; +} + +void lim_process_beacon_eht_op(struct pe_session *session, + struct sSirProbeRespBeacon *bcn_ptr) +{ + uint16_t ori_punc = 0; + enum phy_ch_width ori_bw = CH_WIDTH_INVALID; + enum phy_ch_width ori_bw_no_punct = CH_WIDTH_INVALID; + uint8_t cb_mode; + enum phy_ch_width new_bw; + bool update_allow; + QDF_STATUS status; + struct mac_context *mac_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_channel *des_chan; + struct csa_offload_params *csa_param; + uint8_t ccfs0; + uint8_t ccfs1; + tDot11fIEeht_op *eht_op; + tDot11fIEhe_op *he_op; + uint8_t ch_width; + uint8_t chan_id; + struct wlan_channel bss_chan = {0}; + struct wlan_channel *current_chan = NULL; + uint8_t band_mask; + uint32_t ch_cfreq2 = 0; + + if (!bcn_ptr || !session || !session->mac_ctx || !session->vdev) { + pe_err("invalid input parameters"); + return; + } + + eht_op = &bcn_ptr->eht_op; + he_op = &bcn_ptr->he_op; + mac_ctx = session->mac_ctx; + vdev = session->vdev; + + chan_id = wlan_reg_freq_to_chan(wlan_vdev_get_pdev(vdev), + bcn_ptr->chan_freq); + + cb_mode = lim_get_cb_mode_for_freq(mac_ctx, session, + session->curr_op_freq); + if (cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) { + /* + * if channel bonding is disabled from INI do not + * update the chan width + */ + pe_debug_rl("chan banding is disabled skip bw update"); + + return; + } + /* handle beacon IE for 11be non-mlo case */ + if (eht_op->eht_op_information_present) { + ori_bw = wlan_mlme_convert_eht_op_bw_to_phy_ch_width( + eht_op->channel_width); + ccfs0 = eht_op->ccfs0; + ccfs1 = eht_op->ccfs1; + if (eht_op->disabled_sub_chan_bitmap_present) { + ori_punc = QDF_GET_BITS(eht_op->disabled_sub_chan_bitmap[0][0], 0, 8); + ori_punc |= QDF_GET_BITS(eht_op->disabled_sub_chan_bitmap[0][1], 0, 8) << 8; + + if (!wlan_mlme_get_eht_disable_punct_in_us_lpi(mac_ctx->psoc)) + goto update_bw; + + bss_chan.ch_freq = bcn_ptr->chan_freq; + bss_chan.puncture_bitmap = ori_punc; + bss_chan.ch_width = ori_bw; + bss_chan.ch_phymode = WLAN_PHYMODE_11BEA_EHT160; + + if (ori_bw == CH_WIDTH_320MHZ && + WLAN_REG_IS_6GHZ_CHAN_FREQ(bcn_ptr->chan_freq)) { + band_mask = BIT(REG_BAND_6G); + ch_cfreq2 = wlan_reg_chan_band_to_freq(mac_ctx->pdev, + ccfs1, + band_mask); + bss_chan.ch_cfreq2 = ch_cfreq2; + } + + status = wlan_mlme_get_bw_no_punct(mac_ctx->psoc, + vdev, + &bss_chan, + &ori_bw_no_punct); + current_chan = wlan_vdev_mlme_get_bss_chan(vdev); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (ori_bw_no_punct != current_chan->ch_width) { + status = wlan_mlme_send_ch_width_update_with_notify(mac_ctx->psoc, + vdev, + session->vdev_id, + ori_bw_no_punct); + } + return; + } + } + } else if (he_op->oper_info_6g_present) { + ch_width = he_op->oper_info_6g.info.ch_width; + ccfs0 = he_op->oper_info_6g.info.center_freq_seg0; + ccfs1 = he_op->oper_info_6g.info.center_freq_seg1; + ori_bw = wlan_mlme_convert_he_6ghz_op_bw_to_phy_ch_width(ch_width, + chan_id, + ccfs0, + ccfs1); + } else { + return; + } + +update_bw: + status = lim_get_update_eht_bw_puncture_allow(session, ori_bw, + &new_bw, + &update_allow); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (update_allow) { + wlan_cm_sta_update_bw_puncture(vdev, session->bssId, + ori_punc, ori_bw, + ccfs0, + ccfs1, + new_bw); + } else { + csa_param = qdf_mem_malloc(sizeof(*csa_param)); + if (!csa_param) { + pe_err("csa_param allocation fails"); + return; + } + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + csa_param->channel = des_chan->ch_ieee; + csa_param->csa_chan_freq = des_chan->ch_freq; + csa_param->new_ch_width = ori_bw; + csa_param->new_punct_bitmap = ori_punc; + csa_param->new_ch_freq_seg1 = ccfs0; + csa_param->new_ch_freq_seg2 = ccfs1; + qdf_copy_macaddr(&csa_param->bssid, + (struct qdf_mac_addr *)session->bssId); + lim_handle_sta_csa_param(session->mac_ctx, csa_param, false); + } +} + +void lim_process_beacon_eht(struct mac_context *mac_ctx, + struct pe_session *session, + tSchBeaconStruct *bcn_ptr) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_channel *des_chan; + + if (!session || !bcn_ptr || !mac_ctx) { + pe_err("invalid input parameters"); + return; + } + vdev = session->vdev; + if (!vdev || wlan_vdev_mlme_get_opmode(vdev) != QDF_STA_MODE || + !qdf_is_macaddr_equal((struct qdf_mac_addr *)session->bssId, + (struct qdf_mac_addr *)bcn_ptr->bssid)) + return; + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan || !IS_WLAN_PHYMODE_EHT(des_chan->ch_phymode)) + return; + + if (wlan_cm_is_vdev_connected(vdev)) + lim_process_beacon_eht_op(session, bcn_ptr); + + if (mlo_is_mld_sta(vdev)) + /* handle beacon IE for 802.11be mlo case */ + lim_process_beacon_mlo(mac_ctx, session, bcn_ptr); +} + +void +lim_process_ml_reconfig(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *rx_pkt_info) +{ + uint8_t *frame; + uint16_t frame_len; + + if (!session->vdev) + return; + + frame = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + if (frame_len < SIR_MAC_B_PR_SSID_OFFSET) + return; + + mlo_process_ml_reconfig_ie(session->vdev, NULL, + frame + SIR_MAC_B_PR_SSID_OFFSET, + frame_len - SIR_MAC_B_PR_SSID_OFFSET, NULL); +} +#endif + +/** + * lim_process_beacon_frame() - to process beacon frames + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to RX packet info structure + * @session: A pointer to session + * + * This function is called by limProcessMessageQueue() upon Beacon + * frame reception. + * Note: + * 1. Beacons received in 'normal' state in IBSS are handled by + * Beacon Processing module. + * + * Return: none + */ + +void +lim_process_beacon_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + struct pe_session *session) +{ + tpSirMacMgmtHdr mac_hdr; + tSchBeaconStruct *bcn_ptr; + uint8_t *frame; + const uint8_t *owe_transition_ie; + uint16_t frame_len; + uint8_t bpcc; + bool cu_flag = true; + QDF_STATUS status; + + /* + * here is it required to increment session specific heartBeat + * beacon counter + */ + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + frame = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + if (frame_len < SIR_MAC_B_PR_SSID_OFFSET) { + pe_debug_rl("payload invalid len %d", frame_len); + return; + } + if (lim_validate_rsn_ie(frame + SIR_MAC_B_PR_SSID_OFFSET, + frame_len - SIR_MAC_B_PR_SSID_OFFSET) != + QDF_STATUS_SUCCESS) + return; + /* Expect Beacon in any state as Scan is independent of LIM state */ + bcn_ptr = qdf_mem_malloc(sizeof(*bcn_ptr)); + if (!bcn_ptr) + return; + + /* Parse received Beacon */ + if (sir_convert_beacon_frame2_struct(mac_ctx, + rx_pkt_info, bcn_ptr) != + QDF_STATUS_SUCCESS) { + /* + * Received wrongly formatted/invalid Beacon. + * Ignore it and move on. + */ + pe_warn("Received invalid Beacon in state: %X", + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGW, + session->limMlmState); + qdf_mem_free(bcn_ptr); + return; + } + + if (mlo_is_mld_sta(session->vdev)) { + cu_flag = false; + status = lim_get_bpcc_from_mlo_ie(bcn_ptr, &bpcc); + if (QDF_IS_STATUS_SUCCESS(status)) + cu_flag = lim_check_cu_happens(session->vdev, bpcc); + lim_process_ml_reconfig(mac_ctx, session, rx_pkt_info); + } + + lim_process_bcn_prb_rsp_t2lm(mac_ctx, session, bcn_ptr); + if (QDF_IS_STATUS_SUCCESS(lim_check_for_ml_probe_req(session))) + goto end; + + /* + * during scanning, when any session is active, and + * beacon/Pr belongs to one of the session, fill up the + * following, TBD - HB counter + */ + if (sir_compare_mac_addr(session->bssId, + bcn_ptr->bssid)) { + qdf_mem_copy((uint8_t *)&session->lastBeaconTimeStamp, + (uint8_t *) bcn_ptr->timeStamp, + sizeof(uint64_t)); + session->currentBssBeaconCnt++; + } + MTRACE(mac_trace(mac_ctx, + TRACE_CODE_RX_MGMT_TSF, 0, bcn_ptr->timeStamp[0])); + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, 0, + bcn_ptr->timeStamp[1])); + + if (session->limMlmState == + eLIM_MLM_WT_JOIN_BEACON_STATE) { + owe_transition_ie = wlan_get_vendor_ie_ptr_from_oui( + OWE_TRANSITION_OUI_TYPE, + OWE_TRANSITION_OUI_SIZE, + frame + SIR_MAC_B_PR_SSID_OFFSET, + frame_len - SIR_MAC_B_PR_SSID_OFFSET); + if (session->connected_akm == ANI_AKM_TYPE_OWE && + owe_transition_ie) { + pe_debug("vdev:%d Drop OWE rx beacon. Wait for probe for join success", + session->vdev_id); + qdf_mem_free(bcn_ptr); + return; + } + + if (session->beacon) { + qdf_mem_free(session->beacon); + session->beacon = NULL; + session->bcnLen = 0; + } + + mac_ctx->lim.bss_rssi = + (int8_t)WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + session->bcnLen = WMA_GET_RX_MPDU_LEN(rx_pkt_info); + session->beacon = qdf_mem_malloc(session->bcnLen); + if (session->beacon) + /* + * Store the whole Beacon frame. This is sent to + * csr/hdd in join cnf response. + */ + qdf_mem_copy(session->beacon, + WMA_GET_RX_MAC_HEADER(rx_pkt_info), + session->bcnLen); + mgmt_txrx_frame_hex_dump((uint8_t *)mac_hdr, + WMA_GET_RX_MPDU_LEN(rx_pkt_info), + false); + lim_check_and_announce_join_success(mac_ctx, bcn_ptr, + mac_hdr, session); + } + + if (cu_flag) + lim_process_beacon_eht(mac_ctx, session, bcn_ptr); +end: + qdf_mem_free(bcn_ptr); + return; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c new file mode 100644 index 0000000000..c4ef2fb006 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_cfg_updates.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_process_cfg_updates.cc contains the utility functions + * to handle various CFG parameter update events + * Author: Chandra Modumudi + * Date: 01/20/03 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_global.h" + +#include "wni_cfg.h" +#include "sir_mac_prot_def.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_prop_exts_utils.h" +#include "sch_api.h" +#include "rrm_api.h" + +static void lim_update_config(struct mac_context *mac, struct pe_session *pe_session); + +void lim_set_cfg_protection(struct mac_context *mac, struct pe_session *pesessionEntry) +{ + uint32_t val = 0; + struct wlan_mlme_cfg *mlme_cfg = mac->mlme_cfg; + + if (pesessionEntry && LIM_IS_AP_ROLE(pesessionEntry)) { + if (pesessionEntry->gLimProtectionControl == + MLME_FORCE_POLICY_PROTECTION_DISABLE) + qdf_mem_zero((void *)&pesessionEntry->cfgProtection, + sizeof(tCfgProtection)); + else { + pe_debug("frm11a = %d, from11b = %d, frm11g = %d, " + "ht20 = %d, nongf = %d, lsigTxop = %d, " + "rifs = %d, obss = %d", + pesessionEntry->cfgProtection.fromlla, + pesessionEntry->cfgProtection.fromllb, + pesessionEntry->cfgProtection.fromllg, + pesessionEntry->cfgProtection.ht20, + pesessionEntry->cfgProtection.nonGf, + pesessionEntry->cfgProtection.lsigTxop, + pesessionEntry->cfgProtection.rifs, + pesessionEntry->cfgProtection.obss); + } + } else { + mac->lim.gLimProtectionControl = + mlme_cfg->sap_protection_cfg.protection_force_policy; + + + if (mac->lim.gLimProtectionControl == + MLME_FORCE_POLICY_PROTECTION_DISABLE) + qdf_mem_zero((void *)&mac->lim.cfgProtection, + sizeof(tCfgProtection)); + else { + val = mlme_cfg->sap_protection_cfg.protection_enabled; + + mac->lim.cfgProtection.fromlla = + (val >> MLME_PROTECTION_ENABLED_FROM_llA) & 1; + mac->lim.cfgProtection.fromllb = + (val >> MLME_PROTECTION_ENABLED_FROM_llB) & 1; + mac->lim.cfgProtection.fromllg = + (val >> MLME_PROTECTION_ENABLED_FROM_llG) & 1; + mac->lim.cfgProtection.ht20 = + (val >> MLME_PROTECTION_ENABLED_HT_20) & 1; + mac->lim.cfgProtection.nonGf = + (val >> MLME_PROTECTION_ENABLED_NON_GF) & 1; + mac->lim.cfgProtection.lsigTxop = + (val >> MLME_PROTECTION_ENABLED_LSIG_TXOP) & 1; + mac->lim.cfgProtection.rifs = + (val >> MLME_PROTECTION_ENABLED_RIFS) & 1; + mac->lim.cfgProtection.obss = + (val >> MLME_PROTECTION_ENABLED_OBSS) & 1; + + } + } +} + +/** + * lim_handle_param_update() + * + ***FUNCTION: + * This function is use to post a message whenever need indicate + * there is update of config parameter. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param cfgId - ID of CFG parameter that got updated + * @return None + */ +void lim_handle_param_update(struct mac_context *mac, eUpdateIEsType cfgId) +{ + struct scheduler_msg msg = { 0 }; + QDF_STATUS status; + + pe_debug("Handling CFG parameter id %X update", cfgId); + + switch (cfgId) { + case eUPDATE_IE_PROBE_BCN: + { + msg.type = SIR_LIM_UPDATE_BEACON; + status = lim_post_msg_api(mac, &msg); + + if (status != QDF_STATUS_SUCCESS) + pe_err("Failed lim_post_msg_api %u", status); + break; + } + default: + break; + } +} + +/** + * lim_apply_configuration() + * + ***FUNCTION: + * This function is called to apply the configured parameters + * before joining or reassociating with a BSS or starting a BSS. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @return None + */ + +void lim_apply_configuration(struct mac_context *mac, struct pe_session *pe_session) +{ + uint32_t phyMode; + + pe_session->limSentCapsChangeNtf = false; + + lim_get_phy_mode(mac, &phyMode, pe_session); + + lim_update_config(mac, pe_session); + + lim_get_short_slot_from_phy_mode(mac, pe_session, phyMode, + &pe_session->shortSlotTimeSupported); + + lim_set_cfg_protection(mac, pe_session); + + /* Added for BT - AMP Support */ + if (LIM_IS_AP_ROLE(pe_session)) { + /* This check is required to ensure the beacon generation is not done + as a part of join request for a BT-AMP station */ + + if (pe_session->statypeForBss == STA_ENTRY_SELF) { + sch_set_beacon_interval(mac, pe_session); + sch_set_fixed_beacon_fields(mac, pe_session); + } + } +} /*** end lim_apply_configuration() ***/ + +/** + * lim_update_config + * + * FUNCTION: + * Update the local state from CFG database + * (This used to be dphUpdateConfig) + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +static void lim_update_config(struct mac_context *mac, struct pe_session *pe_session) +{ + bool enabled; + + pe_session->beaconParams.fShortPreamble = + mac->mlme_cfg->ht_caps.short_preamble; + + /* In STA case this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(pe_session)) { + enabled = mac->mlme_cfg->wmm_params.wme_enabled; + pe_session->limWmeEnabled = enabled; + } + enabled = mac->mlme_cfg->wmm_params.wsm_enabled; + pe_session->limWsmEnabled = enabled; + + if ((!pe_session->limWmeEnabled) && (pe_session->limWsmEnabled)) { + pe_err("Can't enable WSM without WME"); + pe_session->limWsmEnabled = 0; + } + /* In STA , this parameter is filled during the join request */ + if (LIM_IS_AP_ROLE(pe_session)) { + enabled = mac->mlme_cfg->wmm_params.qos_enabled; + pe_session->limQosEnabled = enabled; + } + pe_session->limHcfEnabled = mac->mlme_cfg->feature_flags.enable_hcf; + + /* AP: WSM should enable HCF as well, for STA enable WSM only after */ + /* association response is received */ + if (pe_session->limWsmEnabled && LIM_IS_AP_ROLE(pe_session)) + pe_session->limHcfEnabled = 1; + + pe_debug("Updated Lim shadow state based on CFG"); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c new file mode 100644 index 0000000000..e7e989a19d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_deauth_frame.c @@ -0,0 +1,648 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_process_deauth_frame.cc contains the code + * for processing Deauthentication Frame. + * Author: Chandra Modumudi + * Date: 03/24/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "ani_global.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "wlan_connectivity_logging.h" +#include "cds_ieee80211_common.h" + +/** + * lim_process_deauth_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Deauthentication frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Buffer descriptor + associated PDUs + * @return None + */ + +void +lim_process_deauth_frame(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + uint8_t *pBody; + uint16_t reasonCode; + tpSirMacMgmtHdr pHdr; + struct pe_session *pRoamSessionEntry = NULL; + uint8_t roamSessionId; + uint32_t frameLen; + int32_t frame_rssi; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frame_rssi = (int32_t)WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + if (frameLen < sizeof(reasonCode)) { + pe_err("Deauth Frame length invalid %d", frameLen); + return ; + } + + if (LIM_IS_STA_ROLE(pe_session) && + wlan_drop_mgmt_frame_on_link_removal(pe_session->vdev)) { + pe_debug("Received deauth Frame when link removed on vdev %d", + wlan_vdev_get_id(pe_session->vdev)); + return; + } + + if (LIM_IS_STA_ROLE(pe_session) && + !(lim_is_sb_disconnect_allowed(pe_session) || + (pe_session->limMlmState == eLIM_MLM_WT_SAE_AUTH_STATE && + pe_session->limSmeState == eLIM_SME_WT_AUTH_STATE))) { + /*Every 15th deauth frame will be logged in kmsg */ + if (!(mac->lim.deauthMsgCnt & 0xF)) { + pe_debug("received Deauth frame in DEAUTH_WT_STATE" + "(already processing previously received DEAUTH frame)" + "Dropping this.. Deauth Failed %d", + ++mac->lim.deauthMsgCnt); + } else { + mac->lim.deauthMsgCnt++; + } + return; + } + + if (IEEE80211_IS_MULTICAST(pHdr->sa)) { + /* Received Deauth frame from a BC/MC address */ + /* Log error and ignore it */ + pe_debug("received Deauth frame from a BC/MC address"); + return; + } + + if (IEEE80211_IS_MULTICAST(pHdr->da) && + !QDF_IS_ADDR_BROADCAST(pHdr->da)) { + /* Received Deauth frame for a MC address */ + /* Log error and ignore it */ + pe_debug("received Deauth frame for a MC address"); + return; + } + if (!lim_validate_received_frame_a1_addr(mac, + pHdr->da, pe_session)) { + pe_err("rx frame doesn't have valid a1 address, drop it"); + return; + } + + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (is_mgmt_protected(pe_session->vdev_id, (const uint8_t *)pHdr->sa) && + (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + pe_debug("received an unprotected deauth from AP"); + /* + * When 11w offload is enabled then + * firmware should not fwd this frame + */ + if (LIM_IS_STA_ROLE(pe_session) && mac->pmf_offload) { + pe_err("11w offload is enable,unprotected deauth is not expected"); + return; + } + + /* If the frame received is unprotected, forward it to the supplicant to initiate */ + /* an SA query */ + + /* send the unprotected frame indication to SME */ + lim_send_sme_unprotected_mgmt_frame_ind(mac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + + sizeof(tSirMacMgmtHdr)), + pe_session->smeSessionId, + pe_session); + return; + } + + /* Get reasonCode from Deauthentication frame body */ + reasonCode = sir_read_u16(pBody); + + pe_nofl_rl_info("Deauth RX: vdev %d from "QDF_MAC_ADDR_FMT" for "QDF_MAC_ADDR_FMT" RSSI = %d reason %d mlm state = %d, sme state = %d systemrole = %d ", + pe_session->vdev_id, QDF_MAC_ADDR_REF(pHdr->sa), + QDF_MAC_ADDR_REF(pHdr->da), frame_rssi, + reasonCode, pe_session->limMlmState, + pe_session->limSmeState, + GET_LIM_SYSTEM_ROLE(pe_session)); + + lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_FRAME_EVENT, + pe_session, 0, reasonCode); + + lim_cp_stats_cstats_log_deauth_evt(pe_session, CSTATS_DIR_RX, + reasonCode); + + if (lim_check_disassoc_deauth_ack_pending(mac, (uint8_t *) pHdr->sa)) { + pe_debug("Ignore the Deauth received, while waiting for ack of " + "disassoc/deauth"); + lim_clean_up_disassoc_deauth_req(mac, (uint8_t *) pHdr->sa, 1); + wlan_connectivity_mgmt_event(mac->psoc, (struct wlan_frame_hdr *)pHdr, + pe_session->vdev_id, reasonCode, + 0, frame_rssi, 0, 0, 0, 0, + WLAN_DEAUTH_RX); + return; + } + + if (LIM_IS_AP_ROLE(pe_session)) { + switch (reasonCode) { + case REASON_UNSPEC_FAILURE: + case REASON_DEAUTH_NETWORK_LEAVING: + /* Valid reasonCode in received Deauthentication frame */ + break; + + default: + /* Invalid reasonCode in received Deauthentication frame */ + /* Log error and ignore the frame */ + pe_err("received Deauth frame with invalid reasonCode %d from " + QDF_MAC_ADDR_FMT, reasonCode, + QDF_MAC_ADDR_REF(pHdr->sa)); + + break; + } + } else if (LIM_IS_STA_ROLE(pe_session)) { + switch (reasonCode) { + case REASON_UNSPEC_FAILURE: + case REASON_PREV_AUTH_NOT_VALID: + case REASON_DEAUTH_NETWORK_LEAVING: + case REASON_CLASS2_FRAME_FROM_NON_AUTH_STA: + case REASON_CLASS3_FRAME_FROM_NON_ASSOC_STA: + case REASON_STA_NOT_AUTHENTICATED: + /* Valid reasonCode in received Deauth frame */ + break; + + default: + /* Invalid reasonCode in received Deauth frame */ + /* Log error and ignore the frame */ + pe_err("received Deauth frame with invalid reasonCode %d from " + QDF_MAC_ADDR_FMT, reasonCode, + QDF_MAC_ADDR_REF(pHdr->sa)); + + break; + } + } else { + /* Received Deauth frame un-known role. Log and ignore it */ + pe_err("received Deauth frame with reasonCode %d in role %d from " + QDF_MAC_ADDR_FMT, reasonCode, + GET_LIM_SYSTEM_ROLE(pe_session), + QDF_MAC_ADDR_REF(pHdr->sa)); + + return; + } + + /** If we are in the middle of ReAssoc, a few things could happen: + * - STA is reassociating to current AP, and receives deauth from: + * a) current AP + * b) other AP + * - STA is reassociating to a new AP, and receives deauth from: + * c) current AP + * d) reassoc AP + * e) other AP + * + * The logic is: + * 1) If rcv deauth from an AP other than the one we're trying to + * reassociate with, then drop the deauth frame (case b, c, e) + * 2) If rcv deauth from the "new" reassoc AP (case d), then restore + * context with previous AP and send SME_REASSOC_RSP failure. + * 3) If rcv deauth from the reassoc AP, which is also the same + * AP we're currently associated with (case a), then proceed + * with normal deauth processing. + */ + pRoamSessionEntry = + pe_find_session_by_bssid(mac, pe_session->limReAssocbssId, + &roamSessionId); + + if (lim_is_reassoc_in_progress(mac, pe_session) || + lim_is_reassoc_in_progress(mac, pRoamSessionEntry) || + MLME_IS_ROAMING_IN_PROG(mac->psoc, pe_session->vdev_id)) { + /* + * For LFR3, the roaming bssid is not known during ROAM_START, + * so check if the deauth is received from current AP when + * roaming is being done in the firmware + */ + if (MLME_IS_ROAMING_IN_PROG(mac->psoc, pe_session->vdev_id) && + IS_CURRENT_BSSID(mac, pHdr->sa, pe_session)) { + pe_debug("LFR3: Drop deauth frame from connected AP"); + /* + * recvd_deauth_while_roaming will be stored in the + * current AP session amd if roaming has been aborted + * for some reason and come back to same AP, then issue + * a disconnect internally if this flag is true. There + * is no need to reset this flag to false, because if + * roaming succeeds, then this session gets deleted and + * new session is created. + */ + pe_session->recvd_deauth_while_roaming = true; + pe_session->deauth_disassoc_rc = reasonCode; + return; + } + if (!IS_REASSOC_BSSID(mac, pHdr->sa, pe_session)) { + pe_debug("Rcv Deauth from unknown/different " + "AP while ReAssoc. Ignore " QDF_MAC_ADDR_FMT + "limReAssocbssId : " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pHdr->sa), + QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); + return; + } + + /** Received deauth from the new AP to which we tried to ReAssociate. + * Drop ReAssoc and Restore the Previous context( current connected AP). + */ + if (!IS_CURRENT_BSSID(mac, pHdr->sa, pe_session)) { + pe_debug("received DeAuth from the New AP to " + "which ReAssoc is sent " QDF_MAC_ADDR_FMT + "pe_session->bssId: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pHdr->sa), + QDF_MAC_ADDR_REF(pe_session->bssId)); + + lim_restore_pre_reassoc_state(mac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + pe_session); + return; + } + } + + /* If received DeAuth from AP other than the one we're trying to join with + * nor associated with, then ignore deauth and delete Pre-auth entry. + */ + if (!LIM_IS_AP_ROLE(pe_session)) { + if (!IS_CURRENT_BSSID(mac, pHdr->bssId, pe_session)) { + pe_err("received DeAuth from an AP other " + "than we're trying to join. Ignore. " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(pHdr->sa)); + + if (lim_search_pre_auth_list(mac, pHdr->sa)) { + pe_debug("Preauth entry exist. Deleting"); + lim_delete_pre_auth_node(mac, pHdr->sa); + } + return; + } + } + + lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr, + WMA_GET_RX_MPDU_LEN(pRxPacketInfo)); + wlan_connectivity_mgmt_event(mac->psoc, (struct wlan_frame_hdr *)pHdr, + pe_session->vdev_id, reasonCode, + 0, frame_rssi, 0, 0, 0, 0, + WLAN_DEAUTH_RX); + + lim_perform_deauth(mac, pe_session, reasonCode, pHdr->sa, + frame_rssi); + + if (mac->mlme_cfg->gen.fatal_event_trigger && + (reasonCode != REASON_UNSPEC_FAILURE && + reasonCode != REASON_DEAUTH_NETWORK_LEAVING && + reasonCode != REASON_DISASSOC_NETWORK_LEAVING)) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DISCONNECT, + false, false); + } + +} /*** end lim_process_deauth_frame() ***/ + +#ifdef WLAN_FEATURE_SAE +/* + * lim_process_sae_auth_msg() - Process auth msg after receiving deauth + * @mac_ctx: Global MAC context + * @pe_session: PE session entry pointer + * @addr: peer address/ source address + * + * Return: None + */ +static void lim_process_sae_auth_msg(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tSirMacAddr addr) +{ + struct sir_sae_msg *sae_msg; + + sae_msg = qdf_mem_malloc(sizeof(*sae_msg)); + if (!sae_msg) + return; + + sae_msg->vdev_id = pe_session->vdev_id; + sae_msg->sae_status = STATUS_UNSPECIFIED_FAILURE; + sae_msg->result_code = eSIR_SME_AUTH_REFUSED; + qdf_mem_copy(sae_msg->peer_mac_addr, addr, QDF_MAC_ADDR_SIZE); + lim_process_sae_msg(mac_ctx, sae_msg); + + qdf_mem_free(sae_msg); +} +#else +static inline void lim_process_sae_auth_msg(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tSirMacAddr addr) +{} +#endif + +void lim_perform_deauth(struct mac_context *mac_ctx, struct pe_session *pe_session, + uint16_t rc, tSirMacAddr addr, int32_t frame_rssi) +{ + tLimMlmDeauthInd mlmDeauthInd; + tLimMlmAssocCnf mlmAssocCnf; + uint16_t aid; + tpDphHashNode sta_ds; + tpSirAssocRsp assoc_rsp; + + sta_ds = dph_lookup_hash_entry(mac_ctx, addr, &aid, + &pe_session->dph.dphHashTable); + if (!sta_ds) { + pe_debug("Hash entry not found"); + return; + } + /* Check for pre-assoc states */ + switch (GET_LIM_SYSTEM_ROLE(pe_session)) { + case eLIM_STA_ROLE: + switch (pe_session->limMlmState) { + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + /** + * AP sent Deauth frame while waiting + * for Auth frame2. Report Auth failure + * to SME. + */ + + pe_debug("received Deauth frame state %X with failure " + "code %d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_DEAUTH_WHILE_JOIN, + rc, pe_session); + + return; + + case eLIM_MLM_AUTHENTICATED_STATE: + pe_debug("received Deauth frame state %X with " + "reasonCode=%d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + addr, sizeof(tSirMacAddr)); + mlmDeauthInd.reasonCode = rc; + + pe_session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + + lim_post_sme_message(mac_ctx, + LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + return; + + case eLIM_MLM_WT_ASSOC_RSP_STATE: + /** + * AP may have 'aged-out' our Pre-auth + * context. Delete local pre-auth context + * if any and issue ASSOC_CNF to SME. + */ + pe_debug("received Deauth frame state %X with " + "reasonCode=%d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + if (lim_search_pre_auth_list(mac_ctx, addr)) + lim_delete_pre_auth_node(mac_ctx, addr); + + lim_stop_pmfcomeback_timer(pe_session); + if (pe_session->pLimMlmJoinReq) { + qdf_mem_free(pe_session->pLimMlmJoinReq); + pe_session->pLimMlmJoinReq = NULL; + } + + mlmAssocCnf.resultCode = eSIR_SME_DEAUTH_WHILE_JOIN; + mlmAssocCnf.protStatusCode = rc; + + /* PE session Id */ + mlmAssocCnf.sessionId = pe_session->peSessionId; + + pe_session->limMlmState = + pe_session->limPrevMlmState; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + + /* Deactivate Association response timeout */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_ASSOC_FAIL_TIMER); + + lim_post_sme_message(mac_ctx, + LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlmAssocCnf); + + return; + + case eLIM_MLM_WT_ADD_STA_RSP_STATE: + pe_session->fDeauthReceived = true; + pe_debug("Received Deauth frame in state %X with Reason " + "Code %d from Peer" QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + return; + + case eLIM_MLM_IDLE_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: +#ifdef FEATURE_WLAN_TDLS + if ((sta_ds) + && (STA_ENTRY_TDLS_PEER == sta_ds->staType)) { + pe_err("received Deauth frame in state %X with " + "reason code %d from Tdls peer" + QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + lim_send_sme_tdls_del_sta_ind(mac_ctx, sta_ds, + pe_session, + rc); + return; + } else { + + /* + * Delete all the TDLS peers only if Deauth + * is received from the AP + */ + if (IS_CURRENT_BSSID(mac_ctx, addr, pe_session)) + lim_delete_tdls_peers(mac_ctx, pe_session); +#endif + /** + * This could be Deauthentication frame from + * a BSS with which pre-authentication was + * performed. Delete Pre-auth entry if found. + */ + if (lim_search_pre_auth_list(mac_ctx, addr)) + lim_delete_pre_auth_node(mac_ctx, addr); +#ifdef FEATURE_WLAN_TDLS + } +#endif + break; + + case eLIM_MLM_WT_REASSOC_RSP_STATE: + pe_err("received Deauth frame state %X with " + "reasonCode=%d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + break; + + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + pe_err("received Deauth frame in FT state %X with " + "reasonCode=%d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + break; + + case eLIM_MLM_WT_SAE_AUTH_STATE: + pe_debug("received Deauth frame state %X with " + "reasonCode=%d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + + /* this will be treated as SAE authenticaton failure + * and connect failure to userspace. + */ + lim_process_sae_auth_msg(mac_ctx, pe_session, addr); + return; + + default: + pe_err("received Deauth frame in state %X with " + "reasonCode=%d from " QDF_MAC_ADDR_FMT, + pe_session->limMlmState, rc, + QDF_MAC_ADDR_REF(addr)); + return; + } + break; + + case eLIM_AP_ROLE: + break; + + default: + return; + } /* end switch (mac->lim.gLimSystemRole) */ + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + if (!sta_ds) { + pe_err("sta_ds is NULL"); + return; + } + + if ((sta_ds->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (sta_ds->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) || + sta_ds->sta_deletion_in_progress) { + /** + * Already in the process of deleting context for the peer + * and received Deauthentication frame. Log and Ignore. + */ + pe_debug("Deletion is in progress (%d) for peer:"QDF_MAC_ADDR_FMT" in mlmState %d", + sta_ds->sta_deletion_in_progress, + QDF_MAC_ADDR_REF(addr), + sta_ds->mlmStaContext.mlmState); + return; + } + sta_ds->mlmStaContext.disassocReason = rc; + sta_ds->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DEAUTH; + sta_ds->sta_deletion_in_progress = true; + + /* / Issue Deauth Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDeauthInd.peerMacAddr, + sta_ds->staAddr, sizeof(tSirMacAddr)); + mlmDeauthInd.reasonCode = + (uint8_t) sta_ds->mlmStaContext.disassocReason; + mlmDeauthInd.deauthTrigger = eLIM_PEER_ENTITY_DEAUTH; + + /* + * If we're in the middle of ReAssoc and received deauth from + * the ReAssoc AP, then notify SME by sending REASSOC_RSP with + * failure result code. SME will post the disconnect to the + * supplicant and the latter would start a fresh assoc. + */ + if (lim_is_reassoc_in_progress(mac_ctx, pe_session)) { + /** + * AP may have 'aged-out' our Pre-auth + * context. Delete local pre-auth context + * if any and issue REASSOC_CNF to SME. + */ + if (lim_search_pre_auth_list(mac_ctx, addr)) + lim_delete_pre_auth_node(mac_ctx, addr); + + if (pe_session->limAssocResponseData) { + assoc_rsp = (tpSirAssocRsp) pe_session-> + limAssocResponseData; + qdf_mem_free(assoc_rsp->sha384_ft_subelem.gtk); + qdf_mem_free(assoc_rsp->sha384_ft_subelem.igtk); + qdf_mem_free(pe_session->limAssocResponseData); + pe_session->limAssocResponseData = NULL; + } + + pe_debug("Rcv Deauth from ReAssoc AP Issue REASSOC_CNF"); + /* + * TODO: Instead of overloading eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE + * it would have been good to define/use a different failure type. + * Using eSIR_SME_FT_REASSOC_FAILURE does not seem to clean-up + * properly and we end up seeing "transmit queue timeout". + */ + lim_post_reassoc_failure(mac_ctx, + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE, + STATUS_UNSPECIFIED_FAILURE, + pe_session); + return; + } + /* reset the deauthMsgCnt here since we are able to Process + * the deauth frame and sending up the indication as well */ + if (mac_ctx->lim.deauthMsgCnt != 0) { + mac_ctx->lim.deauthMsgCnt = 0; + } + if (LIM_IS_STA_ROLE(pe_session)) + wma_tx_abort(pe_session->smeSessionId); + + lim_update_lost_link_info(mac_ctx, pe_session, frame_rssi); + + /* / Deauthentication from peer MAC entity */ + if (LIM_IS_STA_ROLE(pe_session)) + lim_post_sme_message(mac_ctx, LIM_MLM_DEAUTH_IND, + (uint32_t *) &mlmDeauthInd); + + /* send eWNI_SME_DEAUTH_IND to SME */ + lim_send_sme_deauth_ind(mac_ctx, sta_ds, pe_session); + return; + +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c new file mode 100644 index 0000000000..6db9b82e6e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_disassoc_frame.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_process_disassoc_frame.cc contains the code + * for processing Disassociation Frame. + * Author: Chandra Modumudi + * Date: 03/24/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" +#include "sch_api.h" +#include "wlan_dlm_api.h" +#include "wlan_connectivity_logging.h" + +/** + * lim_process_disassoc_frame + * + ***FUNCTION: + * This function is called by limProcessMessageQueue() upon + * Disassociation frame reception. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * DPH drops packets for STA with 'valid' bit in sta set to '0'. + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param *pRxPacketInfo - A pointer to Rx packet info structure + * @return None + */ +void +lim_process_disassoc_frame(struct mac_context *mac, uint8_t *pRxPacketInfo, + struct pe_session *pe_session) +{ + uint8_t *pBody; + uint16_t aid, reasonCode; + tpSirMacMgmtHdr pHdr; + tpDphHashNode sta; + uint32_t frame_len; + int32_t frame_rssi; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + frame_len = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + + frame_rssi = (int32_t)WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); + + if (IEEE80211_IS_MULTICAST(pHdr->sa)) { + /* Received Disassoc frame from a BC/MC address */ + /* Log error and ignore it */ + pe_err("received Disassoc frame from a BC/MC address"); + return; + } + + if (IEEE80211_IS_MULTICAST(pHdr->da) && + !QDF_IS_ADDR_BROADCAST(pHdr->da)) { + /* Received Disassoc frame for a MC address */ + /* Log error and ignore it */ + pe_err("received Disassoc frame for a MC address"); + return; + } + if (!lim_validate_received_frame_a1_addr(mac, + pHdr->da, pe_session)) { + pe_err("rx frame doesn't have valid a1 address, drop it"); + return; + } + + if (LIM_IS_STA_ROLE(pe_session) && + wlan_drop_mgmt_frame_on_link_removal(pe_session->vdev)) { + pe_debug("Received Disassoc Frame when link removed on vdev %d", + wlan_vdev_get_id(pe_session->vdev)); + return; + } + + if (LIM_IS_STA_ROLE(pe_session) && + !lim_is_sb_disconnect_allowed(pe_session)) { + if (!(mac->lim.disassocMsgCnt & 0xF)) { + pe_debug("received Disassoc frame in %s" + "already processing previously received Disassoc frame, dropping this %d", + lim_sme_state_str(pe_session->limSmeState), + ++mac->lim.disassocMsgCnt); + } else { + mac->lim.disassocMsgCnt++; + } + return; + } + /* PMF: If this session is a PMF session, then ensure that this frame was protected */ + if (is_mgmt_protected(pe_session->vdev_id, (const uint8_t *)pHdr->sa) && + (WMA_GET_RX_DPU_FEEDBACK(pRxPacketInfo) & + DPU_FEEDBACK_UNPROTECTED_ERROR)) { + pe_err("received an unprotected disassoc from AP"); + /* + * When 11w offload is enabled then + * firmware should not fwd this frame + */ + if (LIM_IS_STA_ROLE(pe_session) && mac->pmf_offload) { + pe_err("11w offload is enable,unprotected disassoc is not expected"); + return; + } + + /* If the frame received is unprotected, forward it to the supplicant to initiate */ + /* an SA query */ + /* send the unprotected frame indication to SME */ + lim_send_sme_unprotected_mgmt_frame_ind(mac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frame_len + + sizeof(tSirMacMgmtHdr)), + pe_session->smeSessionId, + pe_session); + return; + } + + if (frame_len < 2) { + pe_err("frame len less than 2"); + return; + } + + /* Get reasonCode from Disassociation frame body */ + reasonCode = sir_read_u16(pBody); + + pe_nofl_rl_info("Disassoc RX: vdev %d from "QDF_MAC_ADDR_FMT" for "QDF_MAC_ADDR_FMT" RSSI = %d reason %d mlm state = %d, sme state = %d systemrole = %d ", + pe_session->vdev_id, QDF_MAC_ADDR_REF(pHdr->sa), + QDF_MAC_ADDR_REF(pHdr->da), frame_rssi, + reasonCode, pe_session->limMlmState, + pe_session->limSmeState, + GET_LIM_SYSTEM_ROLE(pe_session)); + lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_FRAME_EVENT, + pe_session, 0, reasonCode); + + lim_cp_stats_cstats_log_disassoc_evt(pe_session, CSTATS_DIR_RX, + reasonCode); + + /** + * Extract 'associated' context for STA, if any. + * This is maintained by DPH and created by LIM. + */ + sta = + dph_lookup_hash_entry(mac, pHdr->sa, &aid, + &pe_session->dph.dphHashTable); + + if (!sta) { + /** + * Disassociating STA is not associated. + * Log error. + */ + pe_err("received Disassoc frame from STA that does not have context" + "reasonCode=%d, addr " QDF_MAC_ADDR_FMT, + reasonCode, QDF_MAC_ADDR_REF(pHdr->sa)); + return; + } + + if (lim_check_disassoc_deauth_ack_pending(mac, (uint8_t *) pHdr->sa)) { + pe_err("Ignore the DisAssoc received, while waiting for ack of disassoc/deauth"); + lim_clean_up_disassoc_deauth_req(mac, (uint8_t *) pHdr->sa, 1); + return; + } + + if (mac->lim.disassocMsgCnt != 0) { + mac->lim.disassocMsgCnt = 0; + } + + /** If we are in the Wait for ReAssoc Rsp state */ + if (lim_is_reassoc_in_progress(mac, pe_session)) { + /* + * For LFR3, the roaming bssid is not known during ROAM_START, + * so check if the disassoc is received from current AP when + * roaming is being done in the firmware + */ + if (MLME_IS_ROAMING_IN_PROG(mac->psoc, pe_session->vdev_id) && + IS_CURRENT_BSSID(mac, pHdr->sa, pe_session)) { + pe_debug("Dropping disassoc frame from connected AP"); + pe_session->recvd_disassoc_while_roaming = true; + pe_session->deauth_disassoc_rc = reasonCode; + return; + } + /** If we had received the DisAssoc from, + * a. the Current AP during ReAssociate to different AP in same ESS + * b. Unknown AP + * drop/ignore the DisAssoc received + */ + if (!IS_REASSOC_BSSID(mac, pHdr->sa, pe_session)) { + pe_err("Ignore DisAssoc while Processing ReAssoc"); + return; + } + /** If the Disassoc is received from the new AP to which we tried to ReAssociate + * Drop ReAssoc and Restore the Previous context( current connected AP). + */ + if (!IS_CURRENT_BSSID(mac, pHdr->sa, pe_session)) { + pe_debug("received Disassoc from the New AP to which ReAssoc is sent"); + lim_restore_pre_reassoc_state(mac, + eSIR_SME_REASSOC_REFUSED, + reasonCode, + pe_session); + return; + } + } + + if (LIM_IS_AP_ROLE(pe_session)) { + switch (reasonCode) { + case REASON_UNSPEC_FAILURE: + case REASON_DISASSOC_DUE_TO_INACTIVITY: + case REASON_DISASSOC_NETWORK_LEAVING: + case REASON_MIC_FAILURE: + case REASON_4WAY_HANDSHAKE_TIMEOUT : + case REASON_GROUP_KEY_UPDATE_TIMEOUT: + case REASON_IN_4WAY_DIFFERS: + case REASON_1X_AUTH_FAILURE: + /* Valid reasonCode in received Disassociation frame */ + break; + + default: + /* Invalid reasonCode in received Disassociation frame */ + pe_warn("received Disassoc frame with invalid reasonCode: %d from " QDF_MAC_ADDR_FMT, + reasonCode, QDF_MAC_ADDR_REF(pHdr->sa)); + break; + } + } else if (LIM_IS_STA_ROLE(pe_session) && + ((pe_session->limSmeState != eLIM_SME_WT_JOIN_STATE) && + (pe_session->limSmeState != eLIM_SME_WT_AUTH_STATE) && + (pe_session->limSmeState != eLIM_SME_WT_ASSOC_STATE) && + (pe_session->limSmeState != eLIM_SME_WT_REASSOC_STATE))) { + switch (reasonCode) { + case REASON_DEAUTH_NETWORK_LEAVING: + case REASON_DISASSOC_NETWORK_LEAVING: + case REASON_POOR_RSSI_CONDITIONS: + /* Valid reasonCode in received Disassociation frame */ + /* as long as we're not about to channel switch */ + if (pe_session->gLimChannelSwitch.state != + eLIM_CHANNEL_SWITCH_IDLE) { + pe_err("Ignoring disassoc frame due to upcoming channel switch, from "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pHdr->sa)); + return; + } + break; + + default: + break; + } + } else { + /* Received Disassoc in un-known role. Log and ignore it */ + pe_err("received Disassoc frame with invalid reasonCode: %d in role:" + "%d in sme state: %d from " QDF_MAC_ADDR_FMT, reasonCode, + GET_LIM_SYSTEM_ROLE(pe_session), pe_session->limSmeState, + QDF_MAC_ADDR_REF(pHdr->sa)); + + return; + } + + if ((sta->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (sta->mlmStaContext.mlmState == eLIM_MLM_WT_DEL_BSS_RSP_STATE) || + sta->sta_deletion_in_progress) { + /** + * Already in the process of deleting context for the peer + * and received Disassociation frame. Log and Ignore. + */ + pe_debug("Deletion is in progress (%d) for peer:"QDF_MAC_ADDR_FMT" in mlmState %d", + sta->sta_deletion_in_progress, + QDF_MAC_ADDR_REF(pHdr->sa), + sta->mlmStaContext.mlmState); + return; + } + sta->sta_deletion_in_progress = true; + lim_disassoc_tdls_peers(mac, pe_session, pHdr->sa); + if (sta->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) { + /** + * Requesting STA is in some 'transient' state? + * Log error. + */ + if (sta->mlmStaContext.mlmState == + eLIM_MLM_WT_ASSOC_CNF_STATE) + sta->mlmStaContext.updateContext = 1; + + pe_err("received Disassoc frame from peer that is in state: %X, addr "QDF_MAC_ADDR_FMT, + sta->mlmStaContext.mlmState, + QDF_MAC_ADDR_REF(pHdr->sa)); + + } /* if (sta->mlmStaContext.mlmState != eLIM_MLM_LINK_ESTABLISHED_STATE) */ + + if (reasonCode == REASON_POOR_RSSI_CONDITIONS) { + struct sir_rssi_disallow_lst ap_info = {{0}}; + + ap_info.retry_delay = 0; + ap_info.expected_rssi = frame_rssi + + wlan_dlm_get_rssi_denylist_threshold(mac->pdev); + qdf_mem_copy(ap_info.bssid.bytes, pHdr->sa, QDF_MAC_ADDR_SIZE); + ap_info.reject_reason = REASON_ASSOC_REJECT_POOR_RSSI; + ap_info.source = ADDED_BY_DRIVER; + ap_info.original_timeout = ap_info.retry_delay; + ap_info.received_time = qdf_mc_timer_get_system_time(); + + lim_add_bssid_to_reject_list(mac->pdev, &ap_info); + } + lim_extract_ies_from_deauth_disassoc(pe_session, (uint8_t *)pHdr, + WMA_GET_RX_MPDU_LEN(pRxPacketInfo)); + wlan_connectivity_mgmt_event(mac->psoc, (struct wlan_frame_hdr *)pHdr, + pe_session->vdev_id, reasonCode, + 0, frame_rssi, 0, 0, 0, 0, + WLAN_DISASSOC_RX); + + lim_perform_disassoc(mac, frame_rssi, reasonCode, + pe_session, pHdr->sa); + + if (mac->mlme_cfg->gen.fatal_event_trigger && + (reasonCode != REASON_UNSPEC_FAILURE && + reasonCode != REASON_DEAUTH_NETWORK_LEAVING && + reasonCode != REASON_DISASSOC_NETWORK_LEAVING)) { + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_DISCONNECT, + false, false); + } +} /*** end lim_process_disassoc_frame() ***/ + +#ifdef FEATURE_WLAN_TDLS +void lim_disassoc_tdls_peers(struct mac_context *mac_ctx, + struct pe_session *pe_session, tSirMacAddr addr) +{ + tpDphHashNode sta_ds; + uint16_t aid; + + sta_ds = dph_lookup_hash_entry(mac_ctx, addr, &aid, + &pe_session->dph.dphHashTable); + if (!sta_ds) { + pe_debug("Hash entry not found"); + return; + } + /** + * Delete all the TDLS peers only if Disassoc is received + * from the AP + */ + if ((LIM_IS_STA_ROLE(pe_session)) && + ((sta_ds->mlmStaContext.mlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) || + (sta_ds->mlmStaContext.mlmState == + eLIM_MLM_IDLE_STATE)) && + (IS_CURRENT_BSSID(mac_ctx, addr, pe_session))) + lim_delete_tdls_peers(mac_ctx, pe_session); +} +#endif + +void lim_perform_disassoc(struct mac_context *mac_ctx, int32_t frame_rssi, + uint16_t rc, struct pe_session *pe_session, tSirMacAddr addr) +{ + tLimMlmDisassocInd mlmDisassocInd; + uint16_t aid; + tpDphHashNode sta_ds; + tpSirAssocRsp assoc_rsp; + + sta_ds = dph_lookup_hash_entry(mac_ctx, addr, &aid, + &pe_session->dph.dphHashTable); + if (!sta_ds) { + pe_debug("Hash entry not found"); + return; + } + sta_ds->mlmStaContext.cleanupTrigger = eLIM_PEER_ENTITY_DISASSOC; + sta_ds->mlmStaContext.disassocReason = rc; + + /* Issue Disassoc Indication to SME. */ + qdf_mem_copy((uint8_t *) &mlmDisassocInd.peerMacAddr, + (uint8_t *) sta_ds->staAddr, sizeof(tSirMacAddr)); + mlmDisassocInd.reasonCode = + (uint8_t) sta_ds->mlmStaContext.disassocReason; + mlmDisassocInd.disassocTrigger = eLIM_PEER_ENTITY_DISASSOC; + + /* Update PE session Id */ + mlmDisassocInd.sessionId = pe_session->peSessionId; + if (LIM_IS_STA_ROLE(pe_session) && + (pe_session->limMlmState == eLIM_MLM_WT_ASSOC_RSP_STATE)) + lim_stop_pmfcomeback_timer(pe_session); + + if (lim_is_reassoc_in_progress(mac_ctx, pe_session)) { + + /* If we're in the middle of ReAssoc and received disassoc from + * the ReAssoc AP, then notify SME by sending REASSOC_RSP with + * failure result code. By design, SME will then issue "Disassoc" + * and cleanup will happen at that time. + */ + pe_debug("received Disassoc from AP while waiting for Reassoc Rsp"); + + if (pe_session->limAssocResponseData) { + assoc_rsp = (tpSirAssocRsp) pe_session-> + limAssocResponseData; + qdf_mem_free(assoc_rsp->sha384_ft_subelem.gtk); + qdf_mem_free(assoc_rsp->sha384_ft_subelem.igtk); + qdf_mem_free(pe_session->limAssocResponseData); + pe_session->limAssocResponseData = NULL; + } + + lim_restore_pre_reassoc_state(mac_ctx, eSIR_SME_REASSOC_REFUSED, + rc, pe_session); + return; + } + + lim_update_lost_link_info(mac_ctx, pe_session, frame_rssi); + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_IND, + (uint32_t *) &mlmDisassocInd); + + /* send eWNI_SME_DISASSOC_IND to SME */ + lim_send_sme_disassoc_ind(mac_ctx, sta_ds, pe_session); + + return; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c new file mode 100644 index 0000000000..94c69c7aec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c @@ -0,0 +1,2262 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "lim_process_fils.h" +#include +#include +#include +#include +#include +#include +#include +#include "qdf_util.h" +#include "wlan_crypto_global_api.h" +#include "wlan_cm_roam_api.h" + +#ifdef WLAN_FEATURE_FILS_SK + +#ifdef WLAN_FILS_DEBUG +/** + * lim_fils_data_dump()- dump fils data + * @type: Data name + * @data: pointer to data buffer + * @len: data len + * + * Return: None + */ +static void lim_fils_data_dump(char *type, uint8_t *data, uint32_t len) +{ + + pe_debug("%s : length %d", type, len); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, data, len); +} +#else +static void lim_fils_data_dump(char *type, uint8_t *data, uint32_t len) +{ } +#endif + +/** + * lim_get_crypto_digest_len()- Returns hash length based on crypto type + * @type: Crypto type + * + * Return: hash length + */ +static int lim_get_crypto_digest_len(uint8_t *type) +{ + if (!strcmp(type, HMAC_SHA386_CRYPTO_TYPE)) + return SHA384_DIGEST_SIZE; + else if (!strcmp(type, HMAC_SHA256_CRYPTO_TYPE)) + return SHA256_DIGEST_SIZE; + + return 0; +} + +/** + * lim_get_auth_tag_len()- This API returns auth tag len based on crypto suit + * used to encrypt erp packet. + * @crypto_suite: Crtpto suit + * + * Return: tag length + */ +static uint8_t lim_get_auth_tag_len(enum fils_erp_cryptosuite crypto_suite) +{ + switch (crypto_suite) { + case HMAC_SHA256_64: + return -EINVAL; + case HMAC_SHA256_128: + return FILS_SHA256_128_AUTH_TAG; + case HMAC_SHA256_256: + return FILS_SHA256_256_AUTH_TAG; + default: + return -EINVAL; + } +} + + +/** + * lim_get_crypto_type()- This API returns crypto type based on akm suite used + * @akm: akm used for authentication + * + * Return: Crypto type + */ +static uint8_t *lim_get_hash_crypto_type(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return SHA386_CRYPTO_TYPE; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + default: + return SHA256_CRYPTO_TYPE; + } +} + +/** + * lim_get_hmac_crypto_type()- This API returns crypto type based on akm suite + * used. + * @akm: akm used for authentication + * + * This API is used to get the crypto type when HMAC-hash() needs to + * be generated. + * Eg: PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) + * Here HMAC-Hash will be either hmac(sha256) or hmac(sha384) + * + * Return: Crypto type + */ +static uint8_t *lim_get_hmac_crypto_type(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return HMAC_SHA386_CRYPTO_TYPE; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + default: + return HMAC_SHA256_CRYPTO_TYPE; + } +} + +/** + * lim_get_Q_length()- This API returns pmk length based on akm used + * @akm: akm used for authentication + * + * [IEEE 802.11ai - 12.7.1.7.3 PMK-R0] + * PMK-R0 = L(R0-Key-Data, 0, Q) + * where Q is 32 if AKM negotiated is 00-0F-AC:16 + * Q is 48 if AKM negotiated is 00-0F-AC:17 + * + * PMK-R0 Derivation is for FT protocol akm only. + * So Value of Q is not applicable for non-FT akm. + * + * Return: Q length + */ +static uint8_t lim_get_Q_length(int akm_type) +{ + switch (akm_type) { + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return FILS_SHA256_Q_LEN; + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_Q_LEN; + default: + return 0; + } +} + +/** + * lim_get_pmk_length()- This API returns pmk length based on akm used + * @akm: akm used for authentication + * + * Return: PMK length + */ +static uint8_t lim_get_pmk_length(int akm_type) +{ + switch (akm_type) { + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return FILS_SHA256_PMK_LEN; + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_PMK_LEN; + default: + return FILS_SHA256_PMK_LEN; + } +} + +/** + * lim_get_fils_ft_length()- This API returns fils_ft length based on akm used + * @akm: akm used for authentication + * + * FILS_FT is the xx key used in derivation of the PMKR0. + * + * Return: PMK length + */ +static uint8_t lim_get_fils_ft_length(int akm_type) +{ + switch (akm_type) { + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return FILS_FT_SHA256_LEN; + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_FT_SHA384_LEN; + default: + return 0; + } +} + +/** + * lim_get_kek_len()- This API returns kek length based on akm used + * @akm: akm used for authentication + * + * Return: KEK length + */ +static uint8_t lim_get_kek_len(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_KEK_LEN; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + return FILS_SHA256_KEK_LEN; + default: + return FILS_SHA256_KEK_LEN; + } +} + +/** + * lim_get_tk_len()- This API returns tk length based on cypher used + * @akm: cypher used + * + * Return: TK length + */ +static uint8_t lim_get_tk_len(int cypher_suite) +{ + switch (cypher_suite) { + case eSIR_ED_TKIP: + return TK_LEN_TKIP; + case eSIR_ED_CCMP: + return TK_LEN_CCMP; + case eSIR_ED_AES_128_CMAC: + return TK_LEN_AES_128_CMAC; + default: + return 0; + } +} + +/** + * lim_get_ick_len()- This API returns ick length based on akm used + * @akm: akm used for authentication + * + * Return: ICK length + */ +static int lim_get_ick_len(uint8_t akm) +{ + switch (akm) { + case eCSR_AUTH_TYPE_FILS_SHA384: + case eCSR_AUTH_TYPE_FT_FILS_SHA384: + return FILS_SHA384_ICK_LEN; + case eCSR_AUTH_TYPE_FILS_SHA256: + case eCSR_AUTH_TYPE_FT_FILS_SHA256: + default: + return FILS_SHA256_ICK_LEN; + } +} + +/** + * lim_get_key_from_prf()- This API returns key data using PRF-X as defined in + * 11.6.1.7.2 ieee-80211-2012. + * @type: crypto type needs to be used + * @secret: key which needs to be used in crypto + * @secret_len: key_len of secret + * @label: PRF label + * @optional_data: Data used for hash + * @optional_data_len: data length + * @key: key data output + * @keylen: key data length + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_get_key_from_prf(uint8_t *type, uint8_t *secret, + uint32_t secret_len, uint8_t *label, uint8_t *optional_data, + uint32_t optional_data_len, uint8_t *key, uint32_t keylen) +{ + uint8_t count[2]; + uint8_t *addr[4]; + uint32_t len[4]; + uint16_t key_bit_length = keylen * 8; + uint8_t key_length[2]; + uint32_t i = 0, remain_len; + uint16_t iteration; + uint8_t crypto_digest_len = lim_get_crypto_digest_len(type); + uint8_t tmp_hash[SHA384_DIGEST_SIZE] = {0}; + + if (!crypto_digest_len) { + pe_err("Incorrect crypto length"); + return QDF_STATUS_E_FAILURE; + } + + addr[0] = count; + len[0] = sizeof(count); + + addr[1] = label; + len[1] = strlen(label); + + addr[2] = optional_data; + len[2] = optional_data_len; + + qdf_mem_copy(key_length, &key_bit_length, sizeof(key_bit_length)); + addr[3] = key_length; + len[3] = sizeof(key_length); + + for (iteration = 1; i < keylen; iteration++) { + remain_len = keylen - i; + qdf_mem_copy(count, &iteration, sizeof(iteration)); + + if (remain_len >= crypto_digest_len) + remain_len = crypto_digest_len; + + if (qdf_get_hmac_hash(type, secret, secret_len, 4, + addr, len, tmp_hash) < 0) { + pe_err("qdf_get_hmac_hash failed"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&key[i], tmp_hash, remain_len); + i += crypto_digest_len; + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_fils_eap_tlv()- This API process eap tlv available in auth resp + * and returns remaining length. + * @pe_session: PE session + * @wrapped_data: wrapped data + * @data_len: length of tlv + * + * Return: remaining length + */ +static uint32_t lim_process_fils_eap_tlv(struct pe_session *pe_session, + uint8_t *wrapped_data, uint32_t data_len) +{ + struct fils_eap_tlv *tlv; + struct fils_auth_rsp_info *auth_info; + uint8_t auth_tag_len; + + auth_info = &pe_session->fils_info->auth_info; + /* Minimum */ + auth_tag_len = lim_get_auth_tag_len(HMAC_SHA256_128); + + while (data_len > (auth_tag_len + 1)) { + tlv = (struct fils_eap_tlv *) wrapped_data; + + pe_debug("tlv type %x len %u total %u", + tlv->type, tlv->length, data_len); + + if (tlv->length > (data_len - 2)) { + pe_err("tlv len %d greater data_len %d", + tlv->length, data_len); + return 0; + } + + switch (tlv->type) { + case SIR_FILS_EAP_TLV_KEYNAME_NAI: + auth_info->keyname = qdf_mem_malloc(tlv->length); + if (!auth_info->keyname) + return 0; + + qdf_mem_copy(auth_info->keyname, + tlv->data, tlv->length); + auth_info->keylength = tlv->length; + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + case SIR_FILS_EAP_TLV_R_RK_LIFETIME: + /* TODO check this */ + auth_info->r_rk_lifetime = lim_get_u32(tlv->data); + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + case SIR_FILS_EAP_TLV_R_MSK_LIFETIME: + /* TODO check this */ + auth_info->r_msk_lifetime = lim_get_u32(tlv->data); + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + case SIR_FILS_EAP_TLV_DOMAIN_NAME: + auth_info->domain_name = qdf_mem_malloc(tlv->length); + if (!auth_info->domain_name) + return 0; + + qdf_mem_copy(auth_info->domain_name, + tlv->data, tlv->length); + auth_info->domain_len = tlv->length; + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + /* TODO process these now */ + case SIR_FILS_EAP_TLV_CRYPTO_LIST: + case SIR_FILS_EAP_TLV_AUTH_INDICATION: + data_len -= (tlv->length + 2); + wrapped_data += (tlv->length + 2); + break; + default: + pe_debug("Unknown type"); + return data_len; + } + } + return data_len; +} + +/** + * lim_generate_key_data()- This API generates key data using prf + * FILS-Key-Data = KDF-X(PMK, "FILS PTK Derivation", SPA||AA||SNonce||ANonce) + * @fils_info: fils session info + * @key_label: label used + * @data: data buffer + * @data_len: data buffer len + * @key_data: hash data needs to be generated + * @key_data_len: hash data len + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_generate_key_data(struct pe_fils_session *fils_info, + uint8_t *key_label, uint8_t *data, uint32_t data_len, + uint8_t *key_data, uint32_t key_data_len) +{ + QDF_STATUS status; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + status = lim_get_key_from_prf(lim_get_hmac_crypto_type(fils_info->akm), + fils_info->fils_pmk, + fils_info->fils_pmk_len, key_label, data, + data_len, key_data, key_data_len); + if (status != QDF_STATUS_SUCCESS) + pe_err("failed to generate keydata"); + + return status; +} + +/** + * lim_generate_ap_key_auth()- This API generates ap auth data which needs to be + * verified in assoc response. + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_ap_key_auth(struct pe_session *pe_session) +{ + uint8_t *buf, *addr[1]; + uint32_t len; + struct pe_fils_session *fils_info = pe_session->fils_info; + uint8_t data[SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE] = {0}; + + if (!fils_info) + return; + + len = SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE; + addr[0] = data; + buf = data; + qdf_mem_copy(buf, fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(buf, pe_session->self_mac_addr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + if (qdf_get_hmac_hash(lim_get_hmac_crypto_type(fils_info->akm), + fils_info->ick, fils_info->ick_len, 1, &addr[0], + &len, fils_info->ap_key_auth_data) < 0) + pe_err("failed to generate PMK id"); + fils_info->ap_key_auth_len = lim_get_crypto_digest_len( + lim_get_hmac_crypto_type(fils_info->akm)); + lim_fils_data_dump("AP Key Auth", fils_info->ap_key_auth_data, + fils_info->ap_key_auth_len); +} + +/** + * lim_generate_key_auth()- This API generates sta auth data which needs to be + * send to AP in assoc request, AP will generate the same the verify it. + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_key_auth(struct pe_session *pe_session) +{ + uint8_t *buf, *addr[1]; + uint32_t len; + struct pe_fils_session *fils_info = pe_session->fils_info; + uint8_t data[SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE] = {0}; + + if (!fils_info) + return; + + len = SIR_FILS_NONCE_LENGTH + SIR_FILS_NONCE_LENGTH + + QDF_MAC_ADDR_SIZE + QDF_MAC_ADDR_SIZE; + + addr[0] = data; + buf = data; + qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + qdf_mem_copy(buf, pe_session->self_mac_addr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + if (qdf_get_hmac_hash(lim_get_hmac_crypto_type(fils_info->akm), + fils_info->ick, fils_info->ick_len, 1, + &addr[0], &len, fils_info->key_auth) < 0) + pe_err("failed to generate key auth"); + fils_info->key_auth_len = lim_get_crypto_digest_len( + lim_get_hmac_crypto_type(fils_info->akm)); + lim_fils_data_dump("STA Key Auth", + fils_info->key_auth, fils_info->key_auth_len); +} + +/** + * lim_get_keys()- This API generates keys keydata which is generated after + * parsing of auth response. + * KCK = L(FILS-Key-Data, 0, KCK_bits) + * KEK = L(FILS-Key-Data, KCK_bits, KEK_bits) + * TK = L(FILS-Key-Data, KCK_bits + KEK_bits, TK_bits) + * FILS-FT = L(FILS-Key-Data, KCK_bits + KEK_bits + TK_bits, FILS-FT_bits) + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_get_keys(struct mac_context *mac_ctx, + struct pe_session *pe_session) +{ + uint8_t key_label[] = PTK_KEY_LABEL; + uint8_t *data; + uint8_t data_len; + struct pe_fils_session *fils_info = pe_session->fils_info; + uint8_t key_data[FILS_MAX_KEY_DATA_LEN] = {0}; + uint8_t key_data_len; + uint8_t ick_len; + uint8_t kek_len; + uint8_t fils_ft_len = 0; + uint8_t tk_len = lim_get_tk_len(pe_session->encryptType); + uint8_t *buf; + QDF_STATUS status; + + if (!fils_info) + return; + + ick_len = lim_get_ick_len(fils_info->akm); + kek_len = lim_get_kek_len(fils_info->akm); + + if (pe_session->is11Rconnection) + fils_ft_len = lim_get_fils_ft_length(fils_info->akm); + + /* + * [IEEE 802.11ai - 12.12.2.5.3] + * FILS-Key-Data = PRF-X(PMK, “FILS PTK Derivation”, SPA || AA || + * SNonce || ANonce) + * ICK = L(FILS-Key-Data, 0, ICK_bits) + * KEK = L(FILS-Key-Data, ICK_bits, KEK_bits) + * TK = L(FILS-Key-Data, ICK_bits + KEK_bits, TK_bits) + * When doing FT initial mobility domain association using + * FILS authentication, + * FILS-FT = L(FILS-Key-Data, ICK_bits + KEK_bits + + * TK_bits, FILS-FT_bits) + */ + key_data_len = ick_len + kek_len + tk_len + fils_ft_len; + + data_len = 2 * SIR_FILS_NONCE_LENGTH + 2 * QDF_MAC_ADDR_SIZE; + data = qdf_mem_malloc(data_len); + if (!data) + return; + + /* data is SPA || AA ||SNonce || ANonce */ + buf = data; + qdf_mem_copy(buf, pe_session->self_mac_addr, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + qdf_mem_copy(buf, pe_session->bssId, QDF_MAC_ADDR_SIZE); + buf += QDF_MAC_ADDR_SIZE; + + qdf_mem_copy(buf, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + buf += SIR_FILS_NONCE_LENGTH; + + qdf_mem_copy(buf, fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + + /* Derive FILS-Key-Data */ + lim_generate_key_data(fils_info, key_label, data, data_len, + key_data, key_data_len); + buf = key_data; + + qdf_mem_copy(fils_info->ick, buf, ick_len); + fils_info->ick_len = ick_len; + buf += ick_len; + + qdf_mem_copy(fils_info->kek, buf, kek_len); + fils_info->kek_len = kek_len; + buf += kek_len; + + qdf_mem_copy(fils_info->tk, buf, tk_len); + fils_info->tk_len = tk_len; + buf += tk_len; + + /* + * Derive FILS-FT: + * FILS-FT = + * L(FILS-Key-Data, ICK_bits + KEK_bits + TK_bits, FILS-FT_bits) + */ + if (pe_session->is11Rconnection && fils_ft_len) { + qdf_mem_copy(fils_info->fils_ft, buf, fils_ft_len); + fils_info->fils_ft_len = fils_ft_len; + status = wlan_cm_update_fils_ft(mac_ctx->psoc, + pe_session->vdev_id, + fils_info->fils_ft, + fils_ft_len); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to update FILS FT to mlme"); + } + qdf_mem_zero(data, data_len); + qdf_mem_free(data); +} + +/** + * lim_generate_pmkid()- This API generates PMKID using hash of erp auth packet + * parsing of auth response. + * PMKID = Truncate-128(Hash(EAP-Initiate/Reauth)) + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_pmkid(struct pe_session *pe_session) +{ + uint8_t hash[SHA384_DIGEST_SIZE]; + struct pe_fils_session *fils_info = pe_session->fils_info; + + if (!fils_info) + return; + + qdf_get_hash(lim_get_hash_crypto_type(fils_info->akm), 1, + &fils_info->fils_erp_reauth_pkt, + &fils_info->fils_erp_reauth_pkt_len, hash); + qdf_mem_copy(fils_info->fils_pmkid, hash, PMKID_LEN); + lim_fils_data_dump("PMKID", fils_info->fils_pmkid, PMKID_LEN); +} + +/** + * lim_generate_pmk()- This API generates PMK using hmac hash of rmsk data + * anonce, snonce will be used as key for this + * PMK = HMAC-Hash(SNonce || ANonce, rMSK [ || DHss ]) + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_pmk(struct pe_session *pe_session) +{ + uint8_t nonce[2 * SIR_FILS_NONCE_LENGTH] = {0}; + uint8_t nonce_len = 2 * SIR_FILS_NONCE_LENGTH; + uint8_t *addr[1]; + uint32_t len[1]; + struct pe_fils_session *fils_info = pe_session->fils_info; + + if (!fils_info) + return; + + /* Snonce */ + qdf_mem_copy(nonce, pe_session->fils_info->fils_nonce, + SIR_FILS_NONCE_LENGTH); + /* anonce */ + qdf_mem_copy(nonce + SIR_FILS_NONCE_LENGTH, + pe_session->fils_info->auth_info.fils_nonce, + SIR_FILS_NONCE_LENGTH); + fils_info->fils_pmk_len = lim_get_pmk_length(fils_info->akm); + + if (fils_info->fils_pmk) + qdf_mem_free(fils_info->fils_pmk); + + fils_info->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len); + if (!fils_info->fils_pmk) + return; + + addr[0] = fils_info->fils_rmsk; + len[0] = fils_info->fils_rmsk_len; + lim_fils_data_dump("Nonce", nonce, nonce_len); + if (qdf_get_hmac_hash(lim_get_hmac_crypto_type(fils_info->akm), nonce, + nonce_len, 1, &addr[0], &len[0], + fils_info->fils_pmk) < 0) + pe_err("failed to generate PMK"); +} + +/** + * lim_generate_rmsk_data()- This API generates RMSK data using + * default kdf as defined in RFC4306. + * @pe_session: pe session pointer + * + * Return: None + */ +static void lim_generate_rmsk_data(struct pe_session *pe_session) +{ + uint8_t optional_data[4] = {0}; + uint8_t rmsk_label[] = RMSK_LABEL; + struct pe_fils_session *fils_info = pe_session->fils_info; + struct fils_auth_rsp_info *auth_info; + + if (!fils_info) + return; + + auth_info = &(pe_session->fils_info->auth_info); + fils_info->fils_rmsk_len = fils_info->fils_rrk_len; + fils_info->fils_rmsk = qdf_mem_malloc(fils_info->fils_rrk_len); + if (!fils_info->fils_rmsk) + return; + + /* + * Sequence number sent in EAP-INIT packet, + * it should be in network byte order + */ + lim_copy_u16_be(&optional_data[0], fils_info->sequence_number); + lim_copy_u16_be(&optional_data[2], fils_info->fils_rrk_len); + qdf_default_hmac_sha256_kdf( + fils_info->fils_rrk, fils_info->fils_rrk_len, rmsk_label, + optional_data, sizeof(optional_data), fils_info->fils_rmsk, + fils_info->fils_rmsk_len); +} + +/** + * lim_process_auth_wrapped_data()- This API process wrapped data element + * of auth response. + * @pe_session: pe session pointer + * @wrapped_data: wrapped data pointer + * @data_len: wrapped data len + * + * Return: None + */ +static QDF_STATUS lim_process_auth_wrapped_data(struct pe_session *pe_session, + uint8_t *wrapped_data, uint32_t data_len) +{ + uint8_t code; + uint8_t identifier; + uint16_t length; + uint8_t type; + unsigned long flags; + struct pe_fils_session *fils_info; + uint8_t hash[32] = {0}, crypto; + uint32_t remaining_len = data_len, new_len; + uint8_t *input_data[1]; + uint32_t input_len[1]; + uint8_t auth_tag_len; + + fils_info = pe_session->fils_info; + input_data[0] = wrapped_data; + input_len[0] = data_len; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + pe_debug("trying to process the wrappped data"); + + code = *wrapped_data; + wrapped_data++; + remaining_len--; + identifier = *wrapped_data; + wrapped_data++; + remaining_len--; + + length = lim_get_u16(wrapped_data); + wrapped_data += sizeof(uint16_t); + remaining_len -= sizeof(uint16_t); + + type = *wrapped_data; /* val should be 2 here */ + wrapped_data++; + remaining_len--; + + flags = *wrapped_data; + if (test_bit(7, &flags)) { + pe_err("R bit is set in flag, error"); + return QDF_STATUS_E_FAILURE; + } + wrapped_data++; + remaining_len--; + + fils_info->auth_info.sequence = lim_get_u16_be(wrapped_data); + wrapped_data += sizeof(uint16_t); + remaining_len -= sizeof(uint16_t); + /* Validate Auth sequence number */ + if (fils_info->auth_info.sequence < fils_info->sequence_number) { + pe_err("sequence EAP-finish:%d is less than EAP-init:%d", + fils_info->auth_info.sequence, + fils_info->sequence_number); + return QDF_STATUS_E_FAILURE; + } + + /* Parse attached TLVs */ + new_len = lim_process_fils_eap_tlv(pe_session, + wrapped_data, remaining_len); + + wrapped_data += remaining_len - new_len; + remaining_len = new_len; + /* Remove cryptosuite */ + crypto = *wrapped_data; + wrapped_data++; + remaining_len--; + + auth_tag_len = lim_get_auth_tag_len(crypto); + input_len[0] -= auth_tag_len; + /* if we have auth tag remaining */ + if (remaining_len == auth_tag_len) { + qdf_get_hmac_hash(HMAC_SHA256_CRYPTO_TYPE, + fils_info->fils_rik, + fils_info->fils_rik_len, + SINGLE_ELEMENT_HASH_CNT, + input_data, input_len, hash); + } else { + pe_err("invalid remaining len %d", + remaining_len); + } + if (qdf_mem_cmp(wrapped_data, hash, auth_tag_len)) { + pe_err("integratity check failed for auth, crypto %d", + crypto); + return QDF_STATUS_E_FAILURE; + } + + lim_generate_rmsk_data(pe_session); + lim_generate_pmk(pe_session); + lim_generate_pmkid(pe_session); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_is_valid_fils_auth_frame()- This API check whether auth frame is a + * valid frame. + * @mac_ctx: mac context + * @pe_session: pe session pointer + * @rx_auth_frm_body: pointer to autherntication frame + * + * Return: true if frame is valid or fils is disable, false otherwise + */ +bool lim_is_valid_fils_auth_frame(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tSirMacAuthFrameBody *rx_auth_frm_body) +{ + if (!pe_session->fils_info) + return true; + + if (pe_session->fils_info->is_fils_connection == false) + return true; + + if (qdf_mem_cmp(rx_auth_frm_body->session, + pe_session->fils_info->fils_session, + SIR_FILS_SESSION_LENGTH)) { + lim_fils_data_dump("Current FILS session", + pe_session->fils_info->fils_session, + SIR_FILS_SESSION_LENGTH); + lim_fils_data_dump("FILS Session in pkt", + rx_auth_frm_body->session, + SIR_FILS_SESSION_LENGTH); + return false; + } + qdf_mem_copy(pe_session->fils_info->auth_info.fils_nonce, + rx_auth_frm_body->nonce, SIR_FILS_NONCE_LENGTH); + pe_session->fils_info->auth_info.assoc_delay = + rx_auth_frm_body->assoc_delay_info; + return true; +} + +/** + * lim_create_fils_wrapper_data()- This API create warpped data which will be + * sent in auth request. + * @fils_info: fils session info + * + * Return: length of the created wrapped data + */ +static int lim_create_fils_wrapper_data(struct pe_fils_session *fils_info) +{ + uint8_t *buf; + uint8_t auth_tag[FILS_AUTH_TAG_MAX_LENGTH] = {0}; + uint32_t length = 0; + QDF_STATUS status; + int buf_len; + + if (!fils_info) + return 0; + + if (!fils_info->keyname_nai_length || !fils_info->fils_rrk_len) { + pe_debug("FILS_PMKSA: NO keyname nai/RRK configured. Use PMKSA caching"); + return 0; + } + + buf_len = + /* code + identifier */ + sizeof(uint8_t) * 2 + + /* length */ + sizeof(uint16_t) + + /* type + flags */ + sizeof(uint8_t) * 2 + + /* sequence */ + sizeof(uint16_t) + + /* tlv : type, length, data */ + sizeof(uint8_t) * 2 + fils_info->keyname_nai_length + + /* cryptosuite + auth_tag */ + sizeof(uint8_t) + lim_get_auth_tag_len(HMAC_SHA256_128); + + fils_info->fils_erp_reauth_pkt = qdf_mem_malloc(buf_len); + if (!fils_info->fils_erp_reauth_pkt) + return -EINVAL; + + buf = fils_info->fils_erp_reauth_pkt; + *buf = 5; + buf++; + /* Identifier */ + *buf = 0; + buf++; + /* Length */ + lim_copy_u16_be(buf, buf_len); + buf += sizeof(uint16_t); + /* type */ + *buf = SIR_FILS_EAP_INIT_PACKET_TYPE; + buf++; + + /** + * flag + * 0 1 2 <-- 5 --> + * ---------------- + * |R|B|L| Reserved| + * ----------------- + */ + *buf = 0x20; /* l=1, b=0, r=0 */ + buf++; + /* sequence */ + lim_copy_u16_be(buf, fils_info->sequence_number); + buf += sizeof(uint16_t); + + /* tlv */ + /* Type */ + *buf = SIR_FILS_EAP_TLV_KEYNAME_NAI; + buf++; + /* NAI Length */ + *buf = fils_info->keyname_nai_length; + buf++; + /* NAI Data */ + qdf_mem_copy(buf, fils_info->keyname_nai_data, + fils_info->keyname_nai_length); + buf += fils_info->keyname_nai_length; + + /* cryptosuite */ + *buf = HMAC_SHA256_128; + buf++; + + /* + * This should be moved to just after sending probe to save time + * lim_process_switch_channel_join_req ?? + */ + fils_info->fils_rik = qdf_mem_malloc(fils_info->fils_rrk_len); + if (!fils_info->fils_rik) { + qdf_mem_free(fils_info->fils_erp_reauth_pkt); + fils_info->fils_erp_reauth_pkt = NULL; + return -EINVAL; + } + + status = wlan_crypto_create_fils_rik(fils_info->fils_rrk, + fils_info->fils_rrk_len, + fils_info->fils_rik, + &fils_info->fils_rik_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("RIK create fails"); + qdf_mem_free(fils_info->fils_erp_reauth_pkt); + qdf_mem_free(fils_info->fils_rik); + fils_info->fils_erp_reauth_pkt = NULL; + fils_info->fils_rik = NULL; + return -EINVAL; + } + + fils_info->fils_erp_reauth_pkt_len = buf_len; + length = fils_info->fils_erp_reauth_pkt_len - + lim_get_auth_tag_len(HMAC_SHA256_128); + qdf_get_hmac_hash(HMAC_SHA256_CRYPTO_TYPE, + fils_info->fils_rik, fils_info->fils_rik_len, 1, + &fils_info->fils_erp_reauth_pkt, &length, auth_tag); + + lim_fils_data_dump("Auth tag", auth_tag, + lim_get_auth_tag_len(HMAC_SHA256_128)); + lim_fils_data_dump("EAP init pkt", fils_info->fils_erp_reauth_pkt, + fils_info->fils_erp_reauth_pkt_len); + + qdf_mem_copy(buf, auth_tag, lim_get_auth_tag_len(HMAC_SHA256_128)); + buf += lim_get_auth_tag_len(HMAC_SHA256_128); + + return buf_len; +} + +/** + * lim_add_fils_data_to_auth_frame()- This API add fils data to auth frame. + * Following will be added in this. + * RSNIE + * SNonce + * Session + * Wrapped data + * @session: PE session + * @body: pointer to auth frame where data needs to be added + * + * Return: None + */ +void lim_add_fils_data_to_auth_frame(struct pe_session *session, + uint8_t *body) +{ + struct pe_fils_session *fils_info; + + fils_info = session->fils_info; + + if (!fils_info) + return; + + /* RSN IE */ + qdf_mem_copy(body, fils_info->rsn_ie, fils_info->rsn_ie_len); + body += fils_info->rsn_ie_len; + lim_fils_data_dump("FILS RSN", fils_info->rsn_ie, + fils_info->rsn_ie_len); + + /* + * FT-FILS IEEE-802.11ai specification mandates + * MDIE to be sent in auth frame during initial + * mobility domain association + */ + if (session->is11Rconnection) { + struct bss_description *bss_desc; + + bss_desc = &session->lim_join_req->bssDescription; + + if (bss_desc->mdiePresent) { + /* Populate MDIE received from AP */ + *body = WLAN_ELEMID_MOBILITY_DOMAIN; + body++; + *body = SIR_MDIE_SIZE; + body++; + qdf_mem_copy(body, &bss_desc->mdie[0], + SIR_MDIE_SIZE); + pe_debug("FILS: mdie = %02x %02x %02x", + bss_desc->mdie[0], bss_desc->mdie[1], + bss_desc->mdie[2]); + body += SIR_MDIE_SIZE; + } else { + pe_err("FT-FILS: MDIE not advertised by AP"); + } + } + + /* ***Nonce*** */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add nonce length + 1 for ext element id */ + *body = SIR_FILS_NONCE_LENGTH + 1; + body++; + /* Add ext element */ + *body = SIR_FILS_NONCE_EXT_EID; + body++; + /* Add data */ + qdf_get_random_bytes(fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + qdf_mem_copy(body, fils_info->fils_nonce, SIR_FILS_NONCE_LENGTH); + body = body + SIR_FILS_NONCE_LENGTH; + /* Dump data */ + lim_fils_data_dump("fils anonce", fils_info->fils_nonce, + SIR_FILS_NONCE_LENGTH); + + /* *** Session *** */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add nonce length + 1 for ext element id */ + *body = SIR_FILS_SESSION_LENGTH + 1; + body++; + /* Add ext element */ + *body = SIR_FILS_SESSION_EXT_EID; + body++; + /* Add data */ + qdf_get_random_bytes(fils_info->fils_session, SIR_FILS_SESSION_LENGTH); + qdf_mem_copy(body, fils_info->fils_session, SIR_FILS_SESSION_LENGTH); + body = body + SIR_FILS_SESSION_LENGTH; + /* dump data */ + lim_fils_data_dump("Fils Session", + fils_info->fils_session, SIR_FILS_SESSION_LENGTH); + + if (!fils_info->fils_erp_reauth_pkt || + !fils_info->fils_erp_reauth_pkt_len) { + pe_debug("FILS: No ERP data. Dont add auth wrapped data"); + return; + } + + /* ERP Packet */ + /* Add element id */ + *body = SIR_MAX_ELEMENT_ID; + body++; + /* Add packet length + 1 for ext element id */ + *body = fils_info->fils_erp_reauth_pkt_len + 1; + body++; + /* Add ext element */ + *body = SIR_FILS_WRAPPED_DATA_EXT_EID; + body++; + /* Copy data */ + qdf_mem_copy(body, fils_info->fils_erp_reauth_pkt, + fils_info->fils_erp_reauth_pkt_len); + lim_fils_data_dump("Fils ERP reauth Pkt", + fils_info->fils_erp_reauth_pkt, + fils_info->fils_erp_reauth_pkt_len); + body = body + fils_info->fils_erp_reauth_pkt_len; +} + +/** + * lim_generate_fils_pmkr0() - Derive PMKR0 and PMKR0-Name from FT-FILS + * key data + * @pe_session: pointer to pe_session + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_generate_fils_pmkr0(struct pe_session *pe_session) +{ + uint8_t *key_data, *data_buf; + uint8_t key_label[] = FT_PMK_R0_KEY_LABEL; + uint8_t key_data_len, ssid_length, r0kh_len, mdid_len; + uint8_t *r0_key_data; + uint8_t *hash; + uint8_t r0_key_data_len; + uint8_t pmkr0_len; + uint8_t *buf, *pmkr0_name_salt; + uint8_t *scatter_list[PMKR0_SCATTER_LIST_ELEM]; + uint32_t len[PMKR0_SCATTER_LIST_ELEM]; + uint16_t data_buf_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pe_fils_session *fils_info = pe_session->fils_info; + struct bss_description *bss_desc = + &pe_session->lim_join_req->bssDescription; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + ssid_length = pe_session->ssId.length; + r0kh_len = fils_info->ft_ie.r0kh_id_len; + mdid_len = (SIR_MDIE_SIZE - 1); + pmkr0_len = lim_get_Q_length(fils_info->akm); + r0_key_data_len = pmkr0_len + FILS_FT_PMK_R0_SALT_LEN; + + /* + * [IEEE 802.11ai 12.7.1.7.3] + * R0-Key-Data = KDF-Hash-Length(XXKey, "FT-R0", SSIDlength || SSID || + * MDID || R0KHlength || R0KH-ID || S0KH-ID) + * PMK-R0 = L(R0-Key-Data, 0, Q) + * PMK-R0Name-Salt = L(R0-Key-Data, Q, 128) + * Length = Q + 128 + */ + key_data_len = (1 + ssid_length + mdid_len + 1 + r0kh_len + + QDF_MAC_ADDR_SIZE); + pe_debug("FT-FILS: ssid_length:%d MDID len:%d R0KH len:%d key_data len:%d", + ssid_length, mdid_len, r0kh_len, key_data_len); + + data_buf_len = (key_data_len + FILS_FT_MAX_R0_KEY_DATA_LEN + + SHA384_DIGEST_SIZE); + data_buf = qdf_mem_malloc(data_buf_len); + if (!data_buf) + return QDF_STATUS_E_NOMEM; + + key_data = &data_buf[0]; + r0_key_data = &data_buf[key_data_len]; + hash = &data_buf[key_data_len + FILS_FT_MAX_R0_KEY_DATA_LEN]; + + /* + * key_data is (SSIDlength || SSID || MDID || R0KHlength || R0KH-ID || + * S0KH-ID) + */ + buf = key_data; + + *key_data = pe_session->ssId.length; + key_data += 1; + + qdf_mem_copy(key_data, pe_session->ssId.ssId, ssid_length); + key_data += ssid_length; + + qdf_mem_copy(key_data, bss_desc->mdie, mdid_len); + key_data += mdid_len; + + *key_data = r0kh_len; + key_data += 1; + + qdf_mem_copy(key_data, fils_info->ft_ie.r0kh_id, r0kh_len); + key_data += r0kh_len; + + qdf_mem_copy(key_data, pe_session->self_mac_addr, QDF_MAC_ADDR_SIZE); + + pe_debug("FT-FILS: Derive R0-Key-Data"); + status = lim_get_key_from_prf(lim_get_hmac_crypto_type(fils_info->akm), + fils_info->fils_ft, + fils_info->fils_ft_len, key_label, + buf, key_data_len, r0_key_data, + r0_key_data_len); + if (QDF_IS_STATUS_ERROR(status)) + goto free_buf; + + /* PMK-R0 is the first Q bytes of R0-Key-Data */ + qdf_mem_copy(fils_info->pmkr0, r0_key_data, pmkr0_len); + fils_info->pmkr0_len = pmkr0_len; + + /* PMK-R0Name-Salt = L(R0-Key-Data, Q, 128) */ + pmkr0_name_salt = r0_key_data + pmkr0_len; + + /* + * [IEEE 802.11-2016 12.7.1.7.3] + * PMKR0Name = Truncate-128(Hash("FT-R0N" || PMK-R0Name-Salt) + * The Hash function requires the crypto type, number of scatterlist + * parameters, scatterlist, lengths of scatterlist arguments, pointer + * to output hash. + * + * The scatterlist has two arguments - label "FT-R0N" and + * PMK-R0Name-Salt + * + */ + scatter_list[SCTR_LST_ELEM0] = FT_PMK_R0_NAME_KEY_LABEL; + len[SCTR_LST_ELEM0] = SCTR_LST_R0_LABEL_LEN; + scatter_list[SCTR_LST_ELEM1] = pmkr0_name_salt; + len[SCTR_LST_ELEM1] = FILS_FT_PMK_R0_SALT_LEN; + + pe_debug("FT-FILS: Derive PMK-R0 Name"); + if (qdf_get_hash(lim_get_hash_crypto_type(fils_info->akm), + PMKR0_SCATTER_LIST_ELEM, scatter_list, len, + hash) < 0) { + pe_err("FT-FILS: PMK-R0Name derivation failed"); + status = QDF_STATUS_E_FAILURE; + goto free_buf; + } + qdf_mem_copy(fils_info->pmkr0_name, hash, FILS_PMK_NAME_LEN); + +free_buf: + qdf_mem_zero(data_buf, data_buf_len); + qdf_mem_free(data_buf); + + return status; +} + +/** + * lim_generate_fils_pmkr1_name() - Derive PMKR1 and PMKR1-Name from FT-FILS + * key data + * @pe_session: pointer to pe_session + * + * Return: None + */ +static QDF_STATUS lim_generate_fils_pmkr1_name(struct mac_context *mac_ctx, + struct pe_session *pe_session) +{ + uint8_t *hash; + uint8_t *scatter_list[PMKR1_SCATTER_LIST_ELEM]; + uint32_t len[PMKR1_SCATTER_LIST_ELEM]; + uint8_t *buf; + uint8_t gp_mgmt_cipher_suite[4]; + uint32_t ret; + tDot11fIERSN dot11f_ie_rsn = {0}; + struct pe_fils_session *fils_info = pe_session->fils_info; + + if (!fils_info) + return QDF_STATUS_E_FAILURE; + + hash = qdf_mem_malloc(SHA384_DIGEST_SIZE); + if (!hash) + return QDF_STATUS_E_NOMEM; + + /* + * [IEEE 802.11-2016 12.7.1.7.4] + * PMKR1Name = Truncate-128(Hash("FT-R1N" || PMKR0Name || + * R1KH-ID || S1KH-ID)) + */ + scatter_list[SCTR_LST_ELEM0] = FT_PMK_R1_NAME_KEY_LABEL; + len[SCTR_LST_ELEM0] = SCTR_LST_R1_LABEL_LEN; + scatter_list[SCTR_LST_ELEM1] = fils_info->pmkr0_name; + len[SCTR_LST_ELEM1] = FILS_PMK_NAME_LEN; + scatter_list[SCTR_LST_ELEM2] = fils_info->ft_ie.r1kh_id; + len[SCTR_LST_ELEM2] = FT_R1KH_ID_LEN; + scatter_list[SCTR_LST_ELEM3] = pe_session->self_mac_addr; + len[SCTR_LST_ELEM3] = QDF_MAC_ADDR_SIZE; + + if (qdf_get_hash(lim_get_hash_crypto_type(fils_info->akm), + PMKR1_SCATTER_LIST_ELEM, scatter_list, len, + hash) < 0) { + qdf_mem_zero(hash, SHA384_DIGEST_SIZE); + qdf_mem_free(hash); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(fils_info->pmkr1_name, hash, FILS_PMK_NAME_LEN); + + qdf_mem_zero(hash, SHA384_DIGEST_SIZE); + qdf_mem_free(hash); + + if (!fils_info->rsn_ie_len) { + pe_err("FT-FILS: RSN IE not present"); + return QDF_STATUS_E_FAILURE; + } + + ret = dot11f_unpack_ie_rsn(mac_ctx, fils_info->rsn_ie + 2, + fils_info->rsn_ie_len - 2, + &dot11f_ie_rsn, 0); + + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack RSN IE failed, ret: %d", ret); + return QDF_STATUS_E_FAILURE; + } + + buf = fils_info->rsn_ie + fils_info->rsn_ie_len; + + if (fils_info->group_mgmt_cipher_present) { + /* + * If 802.11w is enabled, group management cipher + * suite is added at the end of RSN IE after + * PMKID. Since the driver has opaque RSN IE + * saved in fils_session, strip the last 4 bytes + * of the RSN IE to get group mgmt cipher suite. + * Then copy the PMKID followed by the grp mgmt cipher + * suite. + */ + + buf -= 4; + fils_info->rsn_ie[1] -= 4; /* strip the grp mgmt cipher len */ + qdf_mem_copy(gp_mgmt_cipher_suite, buf, 4); + } + + if (dot11f_ie_rsn.pmkid_count || fils_info->group_mgmt_cipher_present) { + /* Skip past PMKID and PMKID count */ + buf -= (dot11f_ie_rsn.pmkid_count * PMKID_LEN) + 2; + fils_info->rsn_ie[1] -= + (dot11f_ie_rsn.pmkid_count * PMKID_LEN) + 2; + /* Clear the buffer occupied by PMKID */ + qdf_mem_zero(buf, (dot11f_ie_rsn.pmkid_count * PMKID_LEN) + 2); + } + + /* + * Add PMKID count as 1. PMKID count field is 2 bytes long. + * Copy the PMKR1-Name in the PMKID list at the end of the + * RSN IE. + */ + *buf = 1; /* RSNIE PMKID Count = 1 */ + buf += 2; /* RSNIE PMKID count field is 2 bytes */ + /* PMKID = fils_info->pmkr1_name */ + qdf_mem_copy(buf, fils_info->pmkr1_name, FILS_PMK_NAME_LEN); + buf += FILS_PMK_NAME_LEN; + fils_info->rsn_ie[1] += FILS_PMK_NAME_LEN + 2; + + if (fils_info->group_mgmt_cipher_present) { + qdf_mem_copy(buf, gp_mgmt_cipher_suite, 4); + fils_info->rsn_ie[1] += 4; /* Add the grp mgmt cipher len */ + } + + fils_info->rsn_ie_len = fils_info->rsn_ie[1] + 2; + + pe_debug("FT-FILS: Final RSN length:%d", fils_info->rsn_ie[1]); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + fils_info->rsn_ie, fils_info->rsn_ie_len); + + if (pe_session->lim_join_req) { + qdf_mem_zero(pe_session->lim_join_req->rsnIE.rsnIEdata, + WLAN_MAX_IE_LEN + 2); + pe_session->lim_join_req->rsnIE.length = + fils_info->rsn_ie[1] + 2; + qdf_mem_copy(pe_session->lim_join_req->rsnIE.rsnIEdata, + fils_info->rsn_ie, + pe_session->lim_join_req->rsnIE.length); + } else { + pe_debug("FT-FILS: Join req is NULL"); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_fils_auth_frame2()- This API process fils data from auth response + * @mac_ctx: mac context + * @session: PE session + * @rx_auth_frm_body: pointer to auth frame + * + * Return: true if fils data needs to be processed else false + */ +bool lim_process_fils_auth_frame2(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tSirMacAuthFrameBody *rx_auth_frm_body) +{ + int i; + uint32_t ret; + bool pmkid_found = false; + tDot11fIERSN dot11f_ie_rsn = {0}; + QDF_STATUS status; + + if (!pe_session->fils_info) + return false; + + if (rx_auth_frm_body->authAlgoNumber != SIR_FILS_SK_WITHOUT_PFS) + return false; + + ret = dot11f_unpack_ie_rsn(mac_ctx, &rx_auth_frm_body->rsn_ie.info[0], + rx_auth_frm_body->rsn_ie.length, + &dot11f_ie_rsn, 0); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack failed, ret: %d", ret); + return false; + } + + /* + * copy FTIE to fils_info and send it over assoc response frame + * for FT-FILS connection + */ + if (pe_session->is11Rconnection && pe_session->fils_info) { + pe_session->fils_info->ft_ie = rx_auth_frm_body->ft_ie; + if (!pe_session->fils_info->ft_ie.present) { + pe_err("FT-FILS: NO FTIE in auth response"); + } + } + + for (i = 0; i < dot11f_ie_rsn.pmkid_count; i++) { + if (qdf_mem_cmp(dot11f_ie_rsn.pmkid[i], + pe_session->fils_info->fils_pmkid, + PMKID_LEN) == 0) { + pmkid_found = true; + pe_debug("pmkid match in rsn ie total_count %d", + dot11f_ie_rsn.pmkid_count); + break; + } + } + if (!pmkid_found) { + if (QDF_STATUS_SUCCESS != + lim_process_auth_wrapped_data(pe_session, + rx_auth_frm_body->wrapped_data, + rx_auth_frm_body->wrapped_data_len)) + return false; + } + lim_get_keys(mac_ctx, pe_session); + if (pe_session->is11Rconnection) { + status = lim_generate_fils_pmkr0(pe_session); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + status = lim_generate_fils_pmkr1_name(mac_ctx, pe_session); + if (QDF_IS_STATUS_ERROR(status)) + return false; + } + lim_generate_key_auth(pe_session); + lim_generate_ap_key_auth(pe_session); + return true; +} + +static enum eAniAuthType lim_get_auth_type(uint8_t auth_type) +{ + switch (auth_type) { + case FILS_SK_WITHOUT_PFS: + return SIR_FILS_SK_WITHOUT_PFS; + case FILS_SK_WITH_PFS: + return SIR_FILS_SK_WITH_PFS; + case FILS_PK_AUTH: + return SIR_FILS_PK_AUTH; + default: + return eSIR_DONOT_USE_AUTH_TYPE; + } +} + +static uint8_t lim_get_akm_type(struct wlan_objmgr_vdev *vdev) +{ + int32_t akm; + + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) + return eCSR_AUTH_TYPE_FT_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) + return eCSR_AUTH_TYPE_FT_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) + return eCSR_AUTH_TYPE_FILS_SHA384; + else + return eCSR_AUTH_TYPE_FILS_SHA256; +} + +void lim_update_fils_config(struct mac_context *mac_ctx, + struct pe_session *session, + struct cm_vdev_join_req *join_req) +{ + struct pe_fils_session *pe_fils_info; + struct wlan_fils_connection_info *fils_info = NULL; + tDot11fIERSN dot11f_ie_rsn = {0}; + uint32_t ret; + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + fils_info = mlme_priv->connect_info.fils_con_info; + if (!fils_info) + return; + pe_fils_info = session->fils_info; + if (!pe_fils_info) + return; + + if (!fils_info->is_fils_connection) + return; + + pe_fils_info->is_fils_connection = fils_info->is_fils_connection; + pe_fils_info->keyname_nai_length = fils_info->key_nai_length; + pe_fils_info->fils_rrk_len = fils_info->r_rk_length; + pe_fils_info->akm = lim_get_akm_type(session->vdev); + pe_fils_info->auth = lim_get_auth_type(fils_info->auth_type); + pe_fils_info->sequence_number = fils_info->erp_sequence_number; + + if (fils_info->key_nai_length > FILS_MAX_KEYNAME_NAI_LENGTH) { + pe_err("Restricting the key_nai_length of %d to max %d", + fils_info->key_nai_length, + FILS_MAX_KEYNAME_NAI_LENGTH); + fils_info->key_nai_length = FILS_MAX_KEYNAME_NAI_LENGTH; + } + + if (fils_info->key_nai_length) { + pe_fils_info->keyname_nai_data = + qdf_mem_malloc(fils_info->key_nai_length); + if (!pe_fils_info->keyname_nai_data) + return; + + qdf_mem_copy(pe_fils_info->keyname_nai_data, + fils_info->keyname_nai, + fils_info->key_nai_length); + } + + if (fils_info->r_rk_length) { + pe_fils_info->fils_rrk = + qdf_mem_malloc(fils_info->r_rk_length); + if (!pe_fils_info->fils_rrk) { + qdf_mem_free(pe_fils_info->keyname_nai_data); + return; + } + + if (fils_info->r_rk_length <= WLAN_FILS_MAX_RRK_LENGTH) + qdf_mem_copy(pe_fils_info->fils_rrk, + fils_info->r_rk, + fils_info->r_rk_length); + } + + qdf_mem_copy(pe_fils_info->fils_pmkid, fils_info->pmkid, + PMKID_LEN); + pe_fils_info->rsn_ie_len = session->lim_join_req->rsnIE.length; + qdf_mem_copy(pe_fils_info->rsn_ie, + session->lim_join_req->rsnIE.rsnIEdata, + session->lim_join_req->rsnIE.length); + + /* + * When AP is MFP capable and STA is also MFP capable, + * the supplicant fills the RSN IE with PMKID count as 0 + * and PMKID as 0, then appends the group management cipher + * suite. This opaque RSN IE is copied into fils_info in pe + * session. For FT-FILS association, STA has to fill the + * PMKR0 derived after authentication response is received from + * the AP. So unpack the RSN IE to find if group management cipher + * suite is present and based on this RSN IE will be constructed in + * lim_generate_fils_pmkr1_name() for FT-FILS connection. + */ + ret = dot11f_unpack_ie_rsn(mac_ctx, pe_fils_info->rsn_ie + 2, + pe_fils_info->rsn_ie_len - 2, + &dot11f_ie_rsn, 0); + if (DOT11F_SUCCEEDED(ret)) + pe_fils_info->group_mgmt_cipher_present = + dot11f_ie_rsn.gp_mgmt_cipher_suite_present; + else + pe_err("FT-FILS: Invalid RSN IE"); + + pe_fils_info->fils_pmk_len = fils_info->pmk_len; + if (fils_info->pmk_len) { + pe_fils_info->fils_pmk = + qdf_mem_malloc(fils_info->pmk_len); + if (!pe_fils_info->fils_pmk) { + qdf_mem_free(pe_fils_info->keyname_nai_data); + qdf_mem_free(pe_fils_info->fils_rrk); + return; + } + qdf_mem_copy(pe_fils_info->fils_pmk, fils_info->pmk, + fils_info->pmk_len); + } + + pe_debug("FILS: fils=%d nai-len=%d rrk_len=%d akm=%d auth=%d pmk_len=%d rsn_len:%d", + fils_info->is_fils_connection, + fils_info->key_nai_length, + fils_info->r_rk_length, + fils_info->akm_type, + fils_info->auth_type, + fils_info->pmk_len, pe_fils_info->rsn_ie_len); +} + +#define EXTENDED_IE_HEADER_LEN 3 +/** + * lim_create_fils_auth_data()- This API creates the fils auth data + * which needs to be sent in auth req. + * @mac_ctx: mac context + * @auth_frame: pointer to auth frame + * @session: PE session + * + * Return: length of fils data + */ +QDF_STATUS lim_create_fils_auth_data(struct mac_context *mac_ctx, + tpSirMacAuthFrameBody auth_frame, + struct pe_session *session, + uint32_t *frame_len) +{ + uint16_t frm_len = 0; + int32_t wrapped_data_len; + + if (!session->fils_info) + return QDF_STATUS_SUCCESS; + + /* These memory may already been allocated if auth retry */ + if (session->fils_info->fils_rik) { + qdf_mem_free(session->fils_info->fils_rik); + session->fils_info->fils_rik = NULL; + } + + if (session->fils_info->fils_erp_reauth_pkt) { + qdf_mem_free(session->fils_info->fils_erp_reauth_pkt); + session->fils_info->fils_erp_reauth_pkt = NULL; + } + + if (auth_frame->authAlgoNumber == SIR_FILS_SK_WITHOUT_PFS) { + frm_len += session->fils_info->rsn_ie_len; + /* FILS nonce */ + frm_len += SIR_FILS_NONCE_LENGTH + EXTENDED_IE_HEADER_LEN; + /* FILS Session */ + frm_len += SIR_FILS_SESSION_LENGTH + EXTENDED_IE_HEADER_LEN; + /* Calculate data/length for FILS Wrapped Data */ + wrapped_data_len = + lim_create_fils_wrapper_data(session->fils_info); + if (wrapped_data_len < 0) { + pe_err("failed to allocate wrapped data"); + return QDF_STATUS_E_FAILURE; + } + + if (wrapped_data_len) + frm_len += wrapped_data_len + EXTENDED_IE_HEADER_LEN; + } + + *frame_len += frm_len; + + return QDF_STATUS_SUCCESS; +} + +void populate_fils_connect_params(struct mac_context *mac_ctx, + struct pe_session *session, + struct wlan_cm_connect_resp *connect_rsp) +{ + struct pe_fils_session *fils_info = session->fils_info; + struct fils_connect_rsp_params *fils_ie; + + if (!lim_is_fils_connection(session)) + return; + + if (!fils_info->fils_pmk_len || + !fils_info->tk_len || !fils_info->gtk_len || + !fils_info->fils_pmk || !fils_info->kek_len) { + pe_err("Invalid FILS info pmk len %d kek len %d tk len %d gtk len %d", + fils_info->fils_pmk_len, fils_info->kek_len, + fils_info->tk_len, fils_info->gtk_len); + return; + } + + connect_rsp->connect_ies.fils_ie = qdf_mem_malloc(sizeof(*fils_ie)); + if (!connect_rsp->connect_ies.fils_ie) { + pe_delete_fils_info(session); + return; + } + + fils_ie = connect_rsp->connect_ies.fils_ie; + fils_ie->fils_pmk = qdf_mem_malloc(fils_info->fils_pmk_len); + if (!fils_ie->fils_pmk) { + qdf_mem_free(fils_ie); + connect_rsp->connect_ies.fils_ie = NULL; + pe_delete_fils_info(session); + return; + } + fils_ie->fils_seq_num = fils_info->sequence_number; + fils_ie->fils_pmk_len = fils_info->fils_pmk_len; + qdf_mem_copy(fils_ie->fils_pmk, fils_info->fils_pmk, + fils_info->fils_pmk_len); + + qdf_mem_copy(fils_ie->fils_pmkid, fils_info->fils_pmkid, PMKID_LEN); + + fils_ie->kek_len = fils_info->kek_len; + qdf_mem_copy(fils_ie->kek, fils_info->kek, fils_info->kek_len); + + fils_ie->tk_len = fils_info->tk_len; + qdf_mem_copy(fils_ie->tk, fils_info->tk, fils_info->tk_len); + + fils_ie->gtk_len = fils_info->gtk_len; + qdf_mem_copy(fils_ie->gtk, fils_info->gtk, fils_info->gtk_len); + + cds_copy_hlp_info(&fils_info->dst_mac, &fils_info->src_mac, + fils_info->hlp_data_len, fils_info->hlp_data, + &fils_ie->dst_mac, &fils_ie->src_mac, + &fils_ie->hlp_data_len, + fils_ie->hlp_data); + + pe_debug("FILS connect params copied lim"); +} + +/** + * lim_parse_kde_elements() - Parse Key Delivery Elements + * @mac_ctx: mac context + * @fils_info: FILS info + * @kde_list: KDE list buffer + * @kde_list_len: Length of @kde_list + * + * This API is used to parse the Key Delivery Elements from buffer + * and populate them in PE FILS session struct i.e @fils_info + * + * Key Delivery Element[KDE] format + * +----------+--------+-----------+------------+----------+ + * | ID(0xDD) | length | KDE OUI | data type | IE data | + * |----------|--------|-----------|------------|----------| + * | 1 byte | 1 byte | 3 bytes | 1 byte | variable | + * +----------+--------+-----------+------------+----------+ + * + * there can be multiple KDE present inside KDE list. + * the IE data could be GTK, IGTK etc based on the data type + * + * Return: QDF_STATUS_SUCCESS if we parse GTK successfully, + * QDF_STATUS_E_FAILURE otherwise + */ +static QDF_STATUS lim_parse_kde_elements(struct mac_context *mac_ctx, + struct pe_fils_session *fils_info, + uint8_t *kde_list, + uint8_t kde_list_len) +{ + uint8_t rem_len = kde_list_len; + uint8_t *temp_ie = kde_list; + uint8_t elem_id, data_type, data_len, *ie_data = NULL, *current_ie; + uint16_t elem_len; + + if (!kde_list_len || !kde_list) { + pe_err("kde_list NULL or kde_list_len %d", kde_list_len); + return QDF_STATUS_E_FAILURE; + } + + while (rem_len >= 2) { + current_ie = temp_ie; + elem_id = *temp_ie++; + elem_len = *temp_ie++; + rem_len -= 2; + + if (rem_len < elem_len || elem_len > kde_list_len) { + pe_err("Invalid elem_len %d rem_len %d list_len %d", + elem_len, rem_len, kde_list_len); + return QDF_STATUS_E_FAILURE; + } + + if (elem_len < KDE_IE_DATA_OFFSET) { + pe_err("Not enough len to parse elem_len %d", + elem_len); + return QDF_STATUS_E_FAILURE; + } + + if (lim_check_if_vendor_oui_match(mac_ctx, KDE_OUI_TYPE, + KDE_OUI_TYPE_SIZE, current_ie, elem_len)) { + + data_type = *(temp_ie + KDE_DATA_TYPE_OFFSET); + ie_data = (temp_ie + KDE_IE_DATA_OFFSET); + data_len = (elem_len - KDE_IE_DATA_OFFSET); + + switch (data_type) { + case DATA_TYPE_GTK: + if (data_len < GTK_OFFSET) { + pe_err("Invalid KDE data_len %d", + data_len); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(fils_info->gtk, (ie_data + + GTK_OFFSET), (data_len - + GTK_OFFSET)); + fils_info->gtk_len = (data_len - GTK_OFFSET); + break; + + case DATA_TYPE_IGTK: + if (data_len < IGTK_OFFSET) { + pe_err("Invalid KDE data_len %d", + data_len); + return QDF_STATUS_E_FAILURE; + } + fils_info->igtk_len = (data_len - IGTK_OFFSET); + qdf_mem_copy(fils_info->igtk, (ie_data + + IGTK_OFFSET), (data_len - + IGTK_OFFSET)); + qdf_mem_copy(fils_info->ipn, (ie_data + + IPN_OFFSET), IPN_LEN); + break; + default: + pe_err("Unknown KDE data type %x", data_type); + break; + } + } + + temp_ie += elem_len; + rem_len -= elem_len; + ie_data = NULL; + } + + /* Expecting GTK in KDE */ + if (!fils_info->gtk_len) { + pe_err("GTK not found in KDE"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void lim_update_fils_hlp_data(struct qdf_mac_addr *hlp_frm_src_mac, + struct qdf_mac_addr *hlp_frm_dest_mac, + uint16_t frm_hlp_len, uint8_t *frm_hlp_data, + struct pe_session *pe_session) +{ + struct pe_fils_session *pe_fils_info = pe_session->fils_info; + + if (!pe_fils_info) { + pe_err("Not a fils connection"); + return; + } + + if (frm_hlp_data && frm_hlp_len) { + qdf_mem_free(pe_fils_info->hlp_data); + pe_fils_info->hlp_data = qdf_mem_malloc(frm_hlp_len); + if (!pe_fils_info->hlp_data) + return; + + pe_debug("FILS: hlp_data_len:%d", frm_hlp_len); + cds_copy_hlp_info(hlp_frm_dest_mac, hlp_frm_src_mac, + frm_hlp_len, frm_hlp_data, + &pe_fils_info->dst_mac, + &pe_fils_info->src_mac, + &pe_fils_info->hlp_data_len, + pe_fils_info->hlp_data); + } +} + +bool lim_verify_fils_params_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirAssocRsp assoc_rsp, + tLimMlmAssocCnf *assoc_cnf) +{ + struct pe_fils_session *fils_info = session_entry->fils_info; + tDot11fIEfils_session fils_session = assoc_rsp->fils_session; + tDot11fIEfils_key_confirmation *fils_key_auth; + QDF_STATUS status; + + if (!lim_is_fils_connection(session_entry)) + return true; + + if (!fils_info) { + pe_err("FILS Info not present"); + goto verify_fils_params_fails; + } + + if (!assoc_rsp->fils_session.present) { + pe_err("FILS IE not present"); + goto verify_fils_params_fails; + } + + /* Compare FILS session */ + if (qdf_mem_cmp(fils_info->fils_session, + fils_session.session, DOT11F_IE_FILS_SESSION_MAX_LEN)) { + pe_err("FILS session mismatch"); + goto verify_fils_params_fails; + } + + fils_key_auth = qdf_mem_malloc(sizeof(*fils_key_auth)); + if (!fils_key_auth) { + pe_err("malloc failed for fils_key_auth"); + goto verify_fils_params_fails; + } + + *fils_key_auth = assoc_rsp->fils_key_auth; + + /* Compare FILS key auth */ + if (fils_key_auth->num_key_auth != fils_info->key_auth_len || + qdf_mem_cmp(fils_info->ap_key_auth_data, + fils_key_auth->key_auth, + fils_info->ap_key_auth_len)) { + lim_fils_data_dump("session keyauth", + fils_info->ap_key_auth_data, + fils_info->ap_key_auth_len); + lim_fils_data_dump("Pkt keyauth", + fils_key_auth->key_auth, + fils_key_auth->num_key_auth); + qdf_mem_free(fils_key_auth); + goto verify_fils_params_fails; + } + + qdf_mem_free(fils_key_auth); + + /* Verify the Key Delivery Element presence */ + if (!assoc_rsp->fils_kde.num_kde_list) { + pe_err("FILS KDE list absent"); + goto verify_fils_params_fails; + } + + /* Derive KDE elements */ + status = lim_parse_kde_elements(mac_ctx, fils_info, + assoc_rsp->fils_kde.kde_list, + assoc_rsp->fils_kde.num_kde_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("KDE parsing fails"); + goto verify_fils_params_fails; + } + + lim_update_fils_hlp_data(&assoc_rsp->dst_mac, + &assoc_rsp->src_mac, + assoc_rsp->hlp_data_len, + assoc_rsp->hlp_data, + session_entry); + return true; + +verify_fils_params_fails: + assoc_cnf->resultCode = eSIR_SME_ASSOC_REFUSED; + assoc_cnf->protStatusCode = STATUS_UNSPECIFIED_FAILURE; + return false; +} + +/** + * find_ie_data_after_fils_session_ie() - Find IE pointer after FILS Session IE + * @mac_ctx: MAC context + * @buf: IE buffer + * @buf_len: Length of @buf + * @ie: Pointer to update the found IE pointer after FILS session IE + * @ie_len: length of the IE data after FILS session IE + * + * This API is used to find the IE data ptr and length after FILS session IE + * + * Return: QDF_STATUS_SUCCESS if found, else QDF_STATUS_E_FAILURE + */ +static QDF_STATUS find_ie_data_after_fils_session_ie(struct mac_context *mac_ctx, + uint8_t *buf, + uint32_t buf_len, + uint8_t **ie, + uint32_t *ie_len) +{ + uint32_t left = buf_len; + uint8_t *ptr = buf; + uint8_t elem_id, elem_len; + + if (!buf || 0 == buf_len) + return QDF_STATUS_E_FAILURE; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) + return QDF_STATUS_E_FAILURE; + + if ((elem_id == WLAN_REQUEST_IE_MAX_LEN) && + (left >= 3 && ptr[2] == SIR_FILS_SESSION_EXT_EID)) { + (*ie) = ((&ptr[1]) + ptr[1] + 1); + (*ie_len) = (left - elem_len); + return QDF_STATUS_SUCCESS; + } + left -= elem_len; + ptr += (elem_len + 2); + } + return QDF_STATUS_E_FAILURE; +} + +/** + * fils_aead_encrypt() - API to do FILS AEAD encryption + * + * @kek: Pointer to KEK + * @kek_len: KEK length + * @own_mac: Pointer to own MAC address + * @bssid: Bssid + * @snonce: Supplicant Nonce + * @anonce: Authenticator Nonce + * @data: Pointer to data after MAC header + * @data_len: length of @data + * @plain_text: Pointer to data after FILS Session IE + * @plain_text_len: length of @plain_text + * @out: Pointer to the encrypted data + * + * length of AEAD encryption @out is @plain_text_len + AES_BLOCK_SIZE[16 bytes] + * + * Return: zero on success, error otherwise + */ +static int fils_aead_encrypt(const uint8_t *kek, unsigned int kek_len, + const uint8_t *own_mac, const uint8_t *bssid, + const uint8_t *snonce, const uint8_t *anonce, + const uint8_t *data, size_t data_len, + uint8_t *plain_text, size_t plain_text_len, + uint8_t *out) +{ + uint8_t v[AES_BLOCK_SIZE]; + const uint8_t *aad[6]; + size_t aad_len[6]; + uint8_t *buf; + int ret; + + /* SIV Encrypt/Decrypt takes input key of length 256, 384 or 512 bits */ + if (kek_len != 32 && kek_len != 48 && kek_len != 64) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Invalid key length: %u"), kek_len); + return -EINVAL; + } + + if (!own_mac || !bssid || !snonce || + !anonce || data_len == 0 || plain_text_len == 0 || + !out) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Error missing params mac:%pK bssid:%pK snonce:%pK anonce:%pK data_len:%zu plain_text_len:%zu out:%pK"), + own_mac, bssid, snonce, anonce, data_len, + plain_text_len, out); + return -EINVAL; + } + + if (plain_text == out) { + buf = qdf_mem_malloc(plain_text_len); + if (!buf) + return -ENOMEM; + qdf_mem_copy(buf, plain_text, plain_text_len); + } else { + buf = plain_text; + } + + aad[0] = own_mac; + aad_len[0] = QDF_MAC_ADDR_SIZE; + aad[1] = bssid; + aad_len[1] = QDF_MAC_ADDR_SIZE; + aad[2] = snonce; + aad_len[2] = SIR_FILS_NONCE_LENGTH; + aad[3] = anonce; + aad_len[3] = SIR_FILS_NONCE_LENGTH; + aad[4] = data; + aad_len[4] = data_len; + /* Plain text, P, is Sn in AES-SIV */ + aad[5] = buf; + aad_len[5] = plain_text_len; + + /* AES-SIV S2V */ + /* K1 = leftmost(K, len(K)/2) */ + ret = qdf_aes_s2v(kek, kek_len/2, aad, aad_len, 6, v); + if (ret) + goto error; + + /* out = SIV || C (Synthetic Initialization Vector || Ciphered text) */ + qdf_mem_copy(out, v, AES_BLOCK_SIZE); + + /* AES-SIV CTR */ + /* K2 = rightmost(K, len(K)/2) */ + /* Clear 31st and 63rd bits in counter synthetic iv */ + v[12] &= 0x7F; + v[8] &= 0x7F; + + ret = qdf_aes_ctr(kek + kek_len/2, kek_len/2, v, buf, plain_text_len, + out + AES_BLOCK_SIZE, true); + +error: + if (plain_text == out) + qdf_mem_free(buf); + return ret; +} + +QDF_STATUS aead_encrypt_assoc_req(struct mac_context *mac_ctx, + struct pe_session *pe_session, + uint8_t *frm, uint32_t *frm_len) +{ + uint8_t *plain_text = NULL, *data; + uint32_t plain_text_len = 0, data_len; + QDF_STATUS status; + struct pe_fils_session *fils_info = pe_session->fils_info; + + /* + * data is the packet data after MAC header till + * FILS session IE(inclusive) + */ + data = frm + sizeof(tSirMacMgmtHdr); + + /* + * plain_text is the packet data after FILS session IE + * which needs to be encrypted. Get plain_text ptr and + * plain_text_len values using find_ptr_aft_fils_session_ie() + */ + status = find_ie_data_after_fils_session_ie(mac_ctx, data + + FIXED_PARAM_OFFSET_ASSOC_REQ, + (*frm_len - + FIXED_PARAM_OFFSET_ASSOC_REQ), + &plain_text, &plain_text_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Could not find FILS session IE"); + return QDF_STATUS_E_FAILURE; + } + data_len = ((*frm_len) - plain_text_len); + + lim_fils_data_dump("Plain text: ", plain_text, plain_text_len); + + /* Overwrite the AEAD encrypted output @ plain_text */ + if (fils_aead_encrypt(fils_info->kek, fils_info->kek_len, + pe_session->self_mac_addr, pe_session->bssId, + fils_info->fils_nonce, + fils_info->auth_info.fils_nonce, + data, data_len, plain_text, plain_text_len, + plain_text)) { + pe_err("AEAD Encryption fails!"); + return QDF_STATUS_E_FAILURE; + } + + /* + * AEAD encrypted output(cipher_text) will have length equals to + * plain_text_len + AES_BLOCK_SIZE(AEAD encryption header info). + * Add this to frm_len + */ + (*frm_len) += (AES_BLOCK_SIZE); + + return QDF_STATUS_SUCCESS; +} + +/** + * fils_aead_decrypt() - API to do AEAD decryption + * + * @kek: Pointer to KEK + * @kek_len: KEK length + * @own_mac: Pointer to own MAC address + * @bssid: Bssid + * @snonce: Supplicant Nonce + * @anonce: Authenticator Nonce + * @data: Pointer to data after MAC header + * @data_len: length of @data + * @plain_text: Pointer to data after FILS Session IE + * @plain_text_len: length of @plain_text + * @out: Pointer to the encrypted data + * + * Return: zero on success, error otherwise + */ +static int fils_aead_decrypt(const uint8_t *kek, unsigned int kek_len, + const uint8_t *own_mac, const uint8_t *bssid, + const uint8_t *snonce, const uint8_t *anonce, + const uint8_t *data, size_t data_len, + uint8_t *ciphered_text, size_t ciphered_text_len, + uint8_t *plain_text) +{ + const uint8_t *aad[6]; + size_t aad_len[6]; + uint8_t *buf; + size_t buf_len; + uint8_t v[AES_BLOCK_SIZE]; + uint8_t siv[AES_BLOCK_SIZE]; + int ret; + + /* SIV Encrypt/Decrypt takes input key of length 256, 384 or 512 bits */ + if (kek_len != 32 && kek_len != 48 && kek_len != 64) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Invalid key length: %u"), kek_len); + return -EINVAL; + } + + if (!own_mac || !bssid || !snonce || + !anonce || data_len == 0 || ciphered_text_len < AES_BLOCK_SIZE || + !plain_text) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("Error missing params mac:%pK bssid:%pK snonce:%pK anonce:%pK data_len:%zu ciphered_text_len:%zu plain_text:%pK"), + own_mac, bssid, snonce, anonce, data_len, + ciphered_text_len, plain_text); + return -EINVAL; + } + + qdf_mem_copy(v, ciphered_text, AES_BLOCK_SIZE); + qdf_mem_copy(siv, ciphered_text, AES_BLOCK_SIZE); + v[12] &= 0x7F; + v[8] &= 0x7F; + + buf_len = ciphered_text_len - AES_BLOCK_SIZE; + if (ciphered_text == plain_text) { + /* in place decryption */ + buf = qdf_mem_malloc(buf_len); + if (!buf) + return -ENOMEM; + qdf_mem_copy(buf, ciphered_text + AES_BLOCK_SIZE, buf_len); + } else { + buf = ciphered_text + AES_BLOCK_SIZE; + } + + /* AES-SIV CTR */ + /* K2 = rightmost(K, len(K)/2) */ + ret = qdf_aes_ctr(kek + kek_len/2, kek_len/2, v, buf, buf_len, + plain_text, false); + if (ret) + goto error; + + aad[0] = bssid; + aad_len[0] = QDF_MAC_ADDR_SIZE; + aad[1] = own_mac; + aad_len[1] = QDF_MAC_ADDR_SIZE; + aad[2] = anonce; + aad_len[2] = SIR_FILS_NONCE_LENGTH; + aad[3] = snonce; + aad_len[3] = SIR_FILS_NONCE_LENGTH; + aad[4] = data; + aad_len[4] = data_len; + aad[5] = plain_text; + aad_len[5] = buf_len; + + /* AES-SIV S2V */ + /* K1 = leftmost(K, len(K)/2) */ + ret = qdf_aes_s2v(kek, kek_len/2, aad, aad_len, 6, v); + if (ret) + goto error; + + /* compare the iv generated against the one sent by AP */ + if (memcmp(v, siv, AES_BLOCK_SIZE) != 0) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + FL("siv not same as frame siv")); + ret = -EINVAL; + } + +error: + if (ciphered_text == plain_text) + qdf_mem_free(buf); + return ret; +} + +QDF_STATUS aead_decrypt_assoc_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fAssocResponse *ar, + uint8_t *p_frame, uint32_t *n_frame) +{ + QDF_STATUS status; + uint32_t data_len, fils_ies_len; + uint8_t *fils_ies; + struct pe_fils_session *fils_info = session->fils_info; + + if (*n_frame < FIXED_PARAM_OFFSET_ASSOC_RSP) { + pe_debug("payload len is less than ASSOC RES offset"); + return QDF_STATUS_E_FAILURE; + } + + status = find_ie_data_after_fils_session_ie(mac_ctx, p_frame + + FIXED_PARAM_OFFSET_ASSOC_RSP, + ((*n_frame) - + FIXED_PARAM_OFFSET_ASSOC_RSP), + &fils_ies, &fils_ies_len); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("FILS session IE not present"); + return status; + } + + data_len = (*n_frame) - fils_ies_len; + + if (fils_aead_decrypt(fils_info->kek, fils_info->kek_len, + session->self_mac_addr, session->bssId, + fils_info->fils_nonce, + fils_info->auth_info.fils_nonce, + p_frame, data_len, + fils_ies, fils_ies_len, fils_ies)){ + pe_err("AEAD decryption fails"); + return QDF_STATUS_E_FAILURE; + } + + /* Dump the output of AEAD decrypt */ + lim_fils_data_dump("Plain text: ", fils_ies, + fils_ies_len - AES_BLOCK_SIZE); + + (*n_frame) -= AES_BLOCK_SIZE; + return status; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c new file mode 100644 index 0000000000..4c3c9ad48a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_message_queue.c @@ -0,0 +1,2405 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim ProcessMessageQueue.cc contains the code + * for processing LIM message Queue. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "wni_api.h" +#include "wma_types.h" + +#include "wni_cfg.h" +#include "sir_common.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" + +#include "lim_admit_control.h" +#include "sch_api.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_send_messages.h" + +#include "rrm_api.h" + +#include "lim_ft.h" + +#include "qdf_types.h" +#include "cds_packet.h" +#include "qdf_mem.h" +#include "wlan_policy_mgr_api.h" +#include "nan_datapath.h" +#include "wlan_reg_services_api.h" +#include "lim_security_utils.h" +#include "cds_ieee80211_common.h" +#include +#include "wlan_mlme_public_struct.h" +#include "wma.h" +#include "wma_internal.h" +#include "../../core/src/vdev_mgr_ops.h" +#include "wlan_p2p_cfg_api.h" + +void lim_log_session_states(struct mac_context *mac); +static void lim_process_normal_hdd_msg(struct mac_context *mac_ctx, + struct scheduler_msg *msg, uint8_t rsp_reqd); + +#ifdef WLAN_FEATURE_SAE + +/** + * lim_process_sae_msg_sta() - Process SAE message for STA + * @mac: Global MAC pointer + * @session: Pointer to the PE session entry + * @sae_msg: SAE message buffer pointer + * + * Return: None + */ +static void lim_process_sae_msg_sta(struct mac_context *mac, + struct pe_session *session, + struct sir_sae_msg *sae_msg) +{ + struct wlan_crypto_pmksa *pmksa; + uint8_t *rsn_ie_buf; + + switch (session->limMlmState) { + case eLIM_MLM_WT_SAE_AUTH_STATE: + /* SAE authentication is completed. + * Restore from auth state + */ + if (tx_timer_running(&mac->lim.lim_timers.sae_auth_timer)) + lim_deactivate_and_change_timer(mac, + eLIM_AUTH_SAE_TIMER); + lim_sae_auth_cleanup_retry(mac, session->vdev_id); + /* success */ + if (sae_msg->sae_status == STATUS_SUCCESS) { + uint8_t zero_pmkid[PMKID_LEN] = {0}; + + if (!qdf_mem_cmp(sae_msg->pmkid, zero_pmkid, + PMKID_LEN)) { + pe_debug("pmkid not received in ext auth"); + goto restore_auth_state; + } + + pmksa = qdf_mem_malloc(sizeof(*pmksa)); + if (!pmksa) + goto restore_auth_state; + + rsn_ie_buf = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!rsn_ie_buf) { + qdf_mem_free(pmksa); + goto restore_auth_state; + } + + qdf_mem_copy(pmksa->pmkid, sae_msg->pmkid, PMKID_LEN); + qdf_mem_copy(pmksa->bssid.bytes, sae_msg->peer_mac_addr, + QDF_MAC_ADDR_SIZE); + + qdf_mem_zero(session->lim_join_req->rsnIE.rsnIEdata, + WLAN_MAX_IE_LEN + 2); + lim_update_connect_rsn_ie(mac, session, rsn_ie_buf, + pmksa); + + qdf_mem_free(pmksa); + qdf_mem_free(rsn_ie_buf); +restore_auth_state: + lim_restore_from_auth_state(mac, + eSIR_SME_SUCCESS, + STATUS_SUCCESS, + session); + } else { + lim_restore_from_auth_state(mac, sae_msg->result_code, + sae_msg->sae_status, + session); + } + break; + default: + /* SAE msg is received in unexpected state */ + pe_err("received SAE msg in state %X", session->limMlmState); + lim_print_mlm_state(mac, LOGE, session->limMlmState); + break; + } +} + +/** + * lim_process_sae_msg_ap() - Process SAE message + * @mac: Global MAC pointer + * @session: Pointer to the PE session entry + * @sae_msg: SAE message buffer pointer + * + * Return: None + */ +static void lim_process_sae_msg_ap(struct mac_context *mac, + struct pe_session *session, + struct sir_sae_msg *sae_msg) +{ + struct tLimPreAuthNode *sta_pre_auth_ctx; + struct lim_assoc_data *assoc_req; + bool assoc_ind_sent; + + /* Extract pre-auth context for the STA and move limMlmState + * of preauth node to eLIM_MLM_AUTHENTICATED_STATE + */ + sta_pre_auth_ctx = lim_search_pre_auth_list(mac, + sae_msg->peer_mac_addr); + + if (!sta_pre_auth_ctx) { + pe_debug("No preauth node created for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sae_msg->peer_mac_addr)); + return; + } + + assoc_req = &sta_pre_auth_ctx->assoc_req; + + if (sae_msg->sae_status != STATUS_SUCCESS) { + pe_debug("SAE authentication failed for " + QDF_MAC_ADDR_FMT " status: %u", + QDF_MAC_ADDR_REF(sae_msg->peer_mac_addr), + sae_msg->sae_status); + if (assoc_req->present) { + pe_debug("Assoc req cached; clean it up"); + lim_process_assoc_cleanup(mac, session, + assoc_req->assoc_req, + assoc_req->sta_ds, + assoc_req->assoc_req_copied); + assoc_req->present = false; + } + lim_delete_pre_auth_node(mac, sae_msg->peer_mac_addr); + return; + } + sta_pre_auth_ctx->mlmState = eLIM_MLM_AUTHENTICATED_STATE; + /* Send assoc indication to SME if any assoc request is cached*/ + if (assoc_req->present) { + /* Assoc request is present in preauth context. Get the assoc + * request and make it invalid in preauth context. It'll be + * freed later in the legacy path. + */ + bool assoc_req_copied; + + assoc_req->present = false; + pe_debug("Assoc req cached; handle it"); + assoc_ind_sent = + lim_send_assoc_ind_to_sme(mac, session, + assoc_req->sub_type, + assoc_req->sa, + assoc_req->assoc_req, + ANI_AKM_TYPE_SAE, + assoc_req->pmf_connection, + &assoc_req_copied, + assoc_req->dup_entry, false, + assoc_req->partner_peer_idx); + if (!assoc_ind_sent) + lim_process_assoc_cleanup(mac, session, + assoc_req->assoc_req, + assoc_req->sta_ds, + assoc_req_copied); + } +} + +/** + * lim_process_sae_msg() - Process SAE message + * @mac: Global MAC pointer + * @body: Buffer pointer + * + * Return: None + */ +void lim_process_sae_msg(struct mac_context *mac, struct sir_sae_msg *body) +{ + struct sir_sae_msg *sae_msg = body; + struct pe_session *session; + + if (!sae_msg) { + pe_err("SAE msg is NULL"); + return; + } + + session = pe_find_session_by_vdev_id(mac, sae_msg->vdev_id); + if (!session) { + pe_err("SAE:Unable to find session"); + return; + } + + if (session->opmode != QDF_STA_MODE && + session->opmode != QDF_SAP_MODE && + session->opmode != QDF_P2P_GO_MODE && + session->opmode != QDF_P2P_CLIENT_MODE) { + pe_err("SAE:Not supported in this mode %d", + session->opmode); + return; + } + + pe_debug("SAE:status %d limMlmState %d opmode %d peer: " + QDF_MAC_ADDR_FMT, sae_msg->sae_status, + session->limMlmState, session->opmode, + QDF_MAC_ADDR_REF(sae_msg->peer_mac_addr)); + if (LIM_IS_STA_ROLE(session)) + lim_process_sae_msg_sta(mac, session, sae_msg); + else if (LIM_IS_AP_ROLE(session)) + lim_process_sae_msg_ap(mac, session, sae_msg); + else + pe_debug("SAE message on unsupported interface"); +} +#endif + +/** + * lim_process_dual_mac_cfg_resp() - Process set dual mac config response + * @mac: Global MAC pointer + * @body: Set dual mac config response in sir_dual_mac_config_resp format + * + * Process the set dual mac config response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_dual_mac_cfg_resp(struct mac_context *mac, void *body) +{ + struct sir_dual_mac_config_resp *resp, *param; + uint32_t len, fail_resp = 0; + struct scheduler_msg msg = {0}; + + resp = (struct sir_dual_mac_config_resp *)body; + if (!resp) { + pe_err("Set dual mac cfg param is NULL"); + fail_resp = 1; + /* Not returning here. If possible, let us proceed + * and send fail response to SME + */ + } + + len = sizeof(*param); + + param = qdf_mem_malloc(len); + if (!param) + return; + + if (fail_resp) { + pe_err("Send fail status to SME"); + param->status = SET_HW_MODE_STATUS_ECANCELED; + } else { + param->status = resp->status; + /* + * TODO: Update this HW mode info in any UMAC params, if needed + */ + } + + msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + pe_debug("Send eWNI_SME_SET_DUAL_MAC_CFG_RESP to SME"); + lim_sys_process_mmh_msg_api(mac, &msg); + return; +} + +/** + * lim_process_set_hw_mode_resp() - Process set HW mode response + * @mac: Global MAC pointer + * @body: Set HW mode response in sir_set_hw_mode_resp format + * + * Process the set HW mode response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_set_hw_mode_resp(struct mac_context *mac, void *body) +{ + struct sir_set_hw_mode_resp *resp, *param; + uint32_t len, i, fail_resp = 0; + struct scheduler_msg msg = {0}; + + resp = (struct sir_set_hw_mode_resp *)body; + if (!resp) { + pe_err("Set HW mode param is NULL"); + fail_resp = 1; + /* Not returning here. If possible, let us proceed + * and send fail response to SME */ + } + + len = sizeof(*param); + + param = qdf_mem_malloc(len); + if (!param) + return; + + if (fail_resp) { + pe_err("Send fail status to SME"); + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + } else { + param->status = resp->status; + param->cfgd_hw_mode_index = resp->cfgd_hw_mode_index; + param->num_vdev_mac_entries = resp->num_vdev_mac_entries; + + for (i = 0; i < resp->num_vdev_mac_entries; i++) { + param->vdev_mac_map[i].vdev_id = + resp->vdev_mac_map[i].vdev_id; + param->vdev_mac_map[i].mac_id = + resp->vdev_mac_map[i].mac_id; + } + /* + * TODO: Update this HW mode info in any UMAC params, if needed + */ + } + + msg.type = eWNI_SME_SET_HW_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + pe_debug("Send eWNI_SME_SET_HW_MODE_RESP to SME"); + lim_sys_process_mmh_msg_api(mac, &msg); + return; +} + +/** + * lim_process_antenna_mode_resp() - Process set antenna mode + * response + * @mac: Global MAC pointer + * @body: Set antenna mode response in sir_antenna_mode_resp + * format + * + * Process the set antenna mode response and post the message + * to SME to process this further and release the active + * command list + * + * Return: None + */ +static void lim_process_set_antenna_resp(struct mac_context *mac, void *body) +{ + struct sir_antenna_mode_resp *resp, *param; + bool fail_resp = false; + struct scheduler_msg msg = {0}; + + resp = (struct sir_antenna_mode_resp *)body; + if (!resp) { + pe_err("Set antenna mode resp is NULL"); + fail_resp = true; + /* Not returning here. If possible, let us proceed + * and send fail response to SME + */ + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return; + + if (fail_resp) { + pe_err("Send fail status to SME"); + param->status = SET_ANTENNA_MODE_STATUS_ECANCELED; + } else { + param->status = resp->status; + } + + msg.type = eWNI_SME_SET_ANTENNA_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + pe_debug("Send eWNI_SME_SET_ANTENNA_MODE_RESP to SME"); + lim_sys_process_mmh_msg_api(mac, &msg); + return; +} + +/** + * lim_process_set_default_scan_ie_request() - Process the Set default + * Scan IE request from HDD. + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to incoming data + * + * This function receives the default scan IEs and updates the ext cap IE + * (if present) with FTM capabilities and pass the Scan IEs to WMA. + * + * Return: None + */ +static void lim_process_set_default_scan_ie_request(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct hdd_default_scan_ie *set_ie_params; + struct vdev_ie_info *wma_ie_params; + uint8_t *local_ie_buf; + uint16_t local_ie_len; + struct scheduler_msg msg_q = {0}; + QDF_STATUS ret_code; + struct pe_session *pe_session; + + if (!msg_buf) { + pe_err("msg_buf is NULL"); + return; + } + + set_ie_params = (struct hdd_default_scan_ie *) msg_buf; + local_ie_len = set_ie_params->ie_len; + + local_ie_buf = qdf_mem_malloc(MAX_DEFAULT_SCAN_IE_LEN); + if (!local_ie_buf) + return; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, + set_ie_params->vdev_id); + if (lim_update_ext_cap_ie(mac_ctx, + (uint8_t *)set_ie_params->ie_data, + local_ie_buf, &local_ie_len, pe_session)) { + pe_err("Update ext cap IEs fails"); + goto scan_ie_send_fail; + } + + wma_ie_params = qdf_mem_malloc(sizeof(*wma_ie_params) + local_ie_len); + if (!wma_ie_params) + goto scan_ie_send_fail; + + wma_ie_params->vdev_id = set_ie_params->vdev_id; + wma_ie_params->ie_id = DEFAULT_SCAN_IE_ID; + wma_ie_params->length = local_ie_len; + wma_ie_params->data = (uint8_t *)(wma_ie_params) + + sizeof(*wma_ie_params); + qdf_mem_copy(wma_ie_params->data, local_ie_buf, local_ie_len); + + msg_q.type = WMA_SET_IE_INFO; + msg_q.bodyptr = wma_ie_params; + msg_q.bodyval = 0; + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (QDF_STATUS_SUCCESS != ret_code) { + pe_err("fail to send WMA_SET_IE_INFO"); + qdf_mem_free(wma_ie_params); + } +scan_ie_send_fail: + qdf_mem_free(local_ie_buf); +} + +/** + * def_msg_decision() - Should a message be deferred? + * @mac_ctx: The global MAC context + * @lim_msg: The message to check for potential deferral + * + * This function decides whether to defer a message or not in + * lim_message_processor() function + * + * Return: true if the message can be deferred, false otherwise + */ +static bool def_msg_decision(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg) +{ + uint8_t type, subtype; + QDF_STATUS status; + bool mgmt_pkt_defer = true; + + /* this function should not changed */ + if (mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) { + /* Defer processing this message */ + if (lim_defer_msg(mac_ctx, lim_msg) != TX_SUCCESS) { + pe_err_rl("Unable to Defer Msg in offline state"); + lim_log_session_states(mac_ctx); + lim_handle_defer_msg_error(mac_ctx, lim_msg); + } + + return true; + } + + /* + * When defer is requested then defer all the messages except + * HAL responses. + */ + if (!GET_LIM_PROCESS_DEFD_MESGS(mac_ctx)) { + if (lim_msg->type == SIR_BB_XPORT_MGMT_MSG) { + /* + * Dont defer beacon and probe response + * because it will fill the differ queue quickly + */ + status = lim_util_get_type_subtype(lim_msg->bodyptr, + &type, &subtype); + if (QDF_IS_STATUS_SUCCESS(status) && + (type == SIR_MAC_MGMT_FRAME) && + ((subtype == SIR_MAC_MGMT_BEACON) || + (subtype == SIR_MAC_MGMT_PROBE_RSP))) + mgmt_pkt_defer = false; + } + + if ((lim_msg->type != WMA_DELETE_BSS_RSP) && + (lim_msg->type != WMA_DELETE_BSS_HO_FAIL_RSP) && + (lim_msg->type != WMA_ADD_STA_RSP) && + (lim_msg->type != WMA_DELETE_STA_RSP) && + (lim_msg->type != WMA_SET_BSSKEY_RSP) && + (lim_msg->type != WMA_SET_STAKEY_RSP) && + (lim_msg->type != WMA_SET_STA_BCASTKEY_RSP) && + (lim_msg->type != WMA_AGGR_QOS_RSP) && + (lim_msg->type != WMA_SET_MIMOPS_RSP) && + (lim_msg->type != WMA_SWITCH_CHANNEL_RSP) && + (lim_msg->type != WMA_P2P_NOA_ATTR_IND) && + (lim_msg->type != WMA_ADD_TS_RSP) && + /* + * LIM won't process any defer queue commands if gLimAddtsSent is + * set to TRUE. gLimAddtsSent will be set TRUE to while sending + * ADDTS REQ. Say, when deferring is enabled, if + * SIR_LIM_ADDTS_RSP_TIMEOUT is posted (because of not receiving ADDTS + * RSP) then this command will be added to defer queue and as + * gLimAddtsSent is set TRUE LIM will never process any commands from + * defer queue, including SIR_LIM_ADDTS_RSP_TIMEOUT. Hence allowing + * SIR_LIM_ADDTS_RSP_TIMEOUT command to be processed with deferring + * enabled, so that this will be processed immediately and sets + * gLimAddtsSent to FALSE. + */ + (lim_msg->type != SIR_LIM_ADDTS_RSP_TIMEOUT) && + /* Allow processing of RX frames while awaiting reception + * of ADD TS response over the air. This logic particularly + * handles the case when host sends ADD BA request to FW + * after ADD TS request is sent over the air and + * ADD TS response received over the air */ + !(lim_msg->type == SIR_BB_XPORT_MGMT_MSG && + mac_ctx->lim.gLimAddtsSent) && + (mgmt_pkt_defer)) { + pe_debug("Defer the current message %s , gLimProcessDefdMsgs is false and system is not in scan/learn mode", + lim_msg_str(lim_msg->type)); + /* Defer processing this message */ + if (lim_defer_msg(mac_ctx, lim_msg) != TX_SUCCESS) { + pe_err_rl("Unable to Defer Msg"); + lim_log_session_states(mac_ctx); + lim_handle_defer_msg_error(mac_ctx, lim_msg); + } + return true; + } + } + return false; +} + +#ifdef FEATURE_WLAN_EXTSCAN +static void +__lim_pno_match_fwd_bcn_probepsp(struct mac_context *pmac, uint8_t *rx_pkt_info, + tSirProbeRespBeacon *frame, uint32_t ie_len, + uint32_t msg_type) +{ + struct pno_match_found *result; + uint8_t *body; + struct scheduler_msg mmh_msg = {0}; + tpSirMacMgmtHdr hdr; + uint32_t num_results = 1, len, i; + + /* Upon receiving every matched beacon, bss info is forwarded to the + * the upper layer, hence num_results is set to 1 */ + len = sizeof(*result) + (num_results * sizeof(tSirWifiScanResult)) + + ie_len; + + result = qdf_mem_malloc(len); + if (!result) + return; + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* Received frame does not have request id, hence set 0 */ + result->request_id = 0; + result->more_data = 0; + result->num_results = num_results; + + for (i = 0; i < result->num_results; i++) { + result->ap[i].ts = qdf_mc_timer_get_system_time(); + result->ap[i].beaconPeriod = frame->beaconInterval; + result->ap[i].capability = + lim_get_u16((uint8_t *) &frame->capabilityInfo); + result->ap[i].channel = wlan_reg_freq_to_chan( + pmac->pdev, + WMA_GET_RX_FREQ(rx_pkt_info)); + result->ap[i].rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + result->ap[i].rtt = 0; + result->ap[i].rtt_sd = 0; + result->ap[i].ieLength = ie_len; + qdf_mem_copy((uint8_t *) &result->ap[i].ssid[0], + (uint8_t *) frame->ssId.ssId, frame->ssId.length); + result->ap[i].ssid[frame->ssId.length] = '\0'; + qdf_mem_copy((uint8_t *) &result->ap[i].bssid, + (uint8_t *) hdr->bssId, + sizeof(tSirMacAddr)); + /* Copy IE fields */ + qdf_mem_copy((uint8_t *) &result->ap[i].ieData, + body + SIR_MAC_B_PR_SSID_OFFSET, ie_len); + } + + mmh_msg.type = msg_type; + mmh_msg.bodyptr = result; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(pmac, &mmh_msg); +} + + +static void +__lim_ext_scan_forward_bcn_probe_rsp(struct mac_context *pmac, uint8_t *rx_pkt_info, + tSirProbeRespBeacon *frame, + uint32_t ie_len, + uint32_t msg_type) +{ + tpSirWifiFullScanResultEvent result; + uint8_t *body; + struct scheduler_msg mmh_msg = {0}; + tpSirMacMgmtHdr hdr; + uint32_t frame_len; + struct bss_description *bssdescr; + + result = qdf_mem_malloc(sizeof(*result) + ie_len); + if (!result) + return; + + hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* Received frame does not have request id, hence set 0 */ + result->requestId = 0; + + result->moreData = 0; + result->ap.ts = qdf_mc_timer_get_system_time(); + result->ap.beaconPeriod = frame->beaconInterval; + result->ap.capability = + lim_get_u16((uint8_t *) &frame->capabilityInfo); + result->ap.channel = wlan_reg_freq_to_chan( + pmac->pdev, + WMA_GET_RX_FREQ(rx_pkt_info)); + result->ap.rssi = WMA_GET_RX_RSSI_NORMALIZED(rx_pkt_info); + result->ap.rtt = 0; + result->ap.rtt_sd = 0; + result->ap.ieLength = ie_len; + + qdf_mem_copy((uint8_t *) &result->ap.ssid[0], + (uint8_t *) frame->ssId.ssId, frame->ssId.length); + result->ap.ssid[frame->ssId.length] = '\0'; + qdf_mem_copy((uint8_t *) &result->ap.bssid.bytes, + (uint8_t *) hdr->bssId, + QDF_MAC_ADDR_SIZE); + /* Copy IE fields */ + qdf_mem_copy((uint8_t *) &result->ap.ieData, + body + SIR_MAC_B_PR_SSID_OFFSET, ie_len); + + frame_len = sizeof(*bssdescr) + ie_len - sizeof(bssdescr->ieFields[1]); + bssdescr = qdf_mem_malloc(frame_len); + if (!bssdescr) { + qdf_mem_free(result); + return; + } + + qdf_mem_zero(bssdescr, frame_len); + + lim_collect_bss_description(pmac, bssdescr, frame, rx_pkt_info, false); + + qdf_mem_free(bssdescr); + + mmh_msg.type = msg_type; + mmh_msg.bodyptr = result; + mmh_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(pmac, &mmh_msg); +} + +static void +__lim_process_ext_scan_beacon_probe_rsp(struct mac_context *pmac, + uint8_t *rx_pkt_info, + uint8_t sub_type) +{ + tSirProbeRespBeacon *frame; + uint8_t *body; + uint32_t frm_len; + QDF_STATUS status; + + frm_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + if (frm_len <= SIR_MAC_B_PR_SSID_OFFSET) { + pe_err("RX packet has invalid length %d", frm_len); + return; + } + + frame = qdf_mem_malloc(sizeof(*frame)); + if (!frame) + return; + + if (sub_type == SIR_MAC_MGMT_BEACON) { + pe_debug("Beacon due to ExtScan/epno"); + status = sir_convert_beacon_frame2_struct(pmac, + (uint8_t *)rx_pkt_info, + frame); + } else if (sub_type == SIR_MAC_MGMT_PROBE_RSP) { + pe_debug("Probe Rsp due to ExtScan/epno"); + body = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + status = sir_convert_probe_frame2_struct(pmac, body, + frm_len, frame); + } else { + qdf_mem_free(frame); + return; + } + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Frame parsing failed"); + qdf_mem_free(frame); + return; + } + + if (WMA_IS_EXTSCAN_SCAN_SRC(rx_pkt_info)) + __lim_ext_scan_forward_bcn_probe_rsp(pmac, rx_pkt_info, frame, + (frm_len - SIR_MAC_B_PR_SSID_OFFSET), + eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND); + + if (WMA_IS_EPNO_SCAN_SRC(rx_pkt_info)) + __lim_pno_match_fwd_bcn_probepsp(pmac, rx_pkt_info, frame, + (frm_len - SIR_MAC_B_PR_SSID_OFFSET), + eWNI_SME_EPNO_NETWORK_FOUND_IND); + + qdf_mem_free(frame); +} +#endif + +/* + * Beacon Handling Cases: + * during scanning, when no session is active: + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * during scanning, when any session is active, but beacon/Pr does not belong to that session, pe_session will be null. + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * during scanning, when any session is active, and beacon/Pr belongs to one of the session, pe_session will not be null. + * handled by lim_handle_frames_in_scan_state before __lim_handle_beacon call is invoked. + * Not scanning, no session: + * there should not be any beacon coming, if coming, should be dropped. + * Not Scanning, + */ +static void +__lim_handle_beacon(struct mac_context *mac, struct scheduler_msg *pMsg, + struct pe_session *pe_session) +{ + uint8_t *pRxPacketInfo; + + lim_get_b_dfrom_rx_packet(mac, pMsg->bodyptr, + (uint32_t **) &pRxPacketInfo); + + /* This function should not be called if beacon is received in scan state. */ + /* So not doing any checks for the global state. */ + + if (!pe_session) { + sch_beacon_process(mac, pRxPacketInfo, NULL); + } else if ((pe_session->limSmeState == eLIM_SME_LINK_EST_STATE) || + (pe_session->limSmeState == eLIM_SME_NORMAL_STATE)) { + sch_beacon_process(mac, pRxPacketInfo, pe_session); + } else + lim_process_beacon_frame(mac, pRxPacketInfo, pe_session); + + return; +} + +/* + * lim_fill_sap_bcn_pkt_meta(): Fills essential fields in Rx Pkt Meta + * @scan_entry: pointer to the scan cache entry of the beacon + * @rx_pkt: pointer to the cds pkt allocated + * + * This API fills only the essential parameters in the Rx Pkt Meta which are + * required while converting the beacon frame to struct and while handling + * the beacon for implementation of SAP protection mechanisms. + * + * Return: None + */ +static void lim_fill_sap_bcn_pkt_meta(struct scan_cache_entry *scan_entry, + cds_pkt_t *rx_pkt) +{ + rx_pkt->pkt_meta.frequency = scan_entry->channel.chan_freq; + rx_pkt->pkt_meta.mpdu_hdr_len = sizeof(struct ieee80211_frame); + rx_pkt->pkt_meta.mpdu_len = scan_entry->raw_frame.len; + rx_pkt->pkt_meta.mpdu_data_len = rx_pkt->pkt_meta.mpdu_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + + rx_pkt->pkt_meta.mpdu_hdr_ptr = scan_entry->raw_frame.ptr; + rx_pkt->pkt_meta.mpdu_data_ptr = rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + + /* + * The scan_entry->raw_frame contains the qdf_nbuf->data from the SKB + * of the beacon. We set the rx_pkt->pkt_meta.mpdu_hdr_ptr to point + * to this memory directly. However we do not have the pointer to + * the SKB itself here which is usually is pointed by rx_pkt->pkt_buf. + * Also, we always get the pkt data using WMA_GET_RX_MPDU_DATA and + * dont actually use the pkt_buf. So setting this to NULL. + */ + rx_pkt->pkt_buf = NULL; +} + +/* + * lim_allocate_and_get_bcn() - Allocate and get the bcn frame pkt and structure + * @mac_ctx: pointer to global mac_ctx + * @pkt: pointer to the pkt to be allocated + * @rx_pkt_info: pointer to the allocated pkt meta + * @bcn: pointer to the beacon struct + * @scan_entry: pointer to the scan cache entry from scan module + * + * Allocates a cds_pkt for beacon frame in scan cache entry, + * fills the essential pkt_meta elements and converts the + * pkt to beacon strcut. + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_allocate_and_get_bcn( + struct mac_context *mac_ctx, + cds_pkt_t **pkt, + uint8_t **rx_pkt_info, + tSchBeaconStruct **bcn, + struct scan_cache_entry *scan_entry) +{ + QDF_STATUS status; + uint8_t *rx_pkt_info_l = NULL; + tSchBeaconStruct *bcn_l = NULL; + cds_pkt_t *pkt_l = NULL; + + pkt_l = qdf_mem_malloc_atomic(sizeof(cds_pkt_t)); + if (!pkt_l) + return QDF_STATUS_E_FAILURE; + + status = wma_ds_peek_rx_packet_info(pkt_l, (void *)&rx_pkt_info_l); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed to get Rx Pkt meta"); + goto free; + } + + bcn_l = qdf_mem_malloc_atomic(sizeof(tSchBeaconStruct)); + if (!bcn_l) + goto free; + + lim_fill_sap_bcn_pkt_meta(scan_entry, pkt_l); + + /* Convert the beacon frame into a structure */ + if (sir_convert_beacon_frame2_struct(mac_ctx, + (uint8_t *)rx_pkt_info_l, + bcn_l) != QDF_STATUS_SUCCESS) { + pe_err("beacon parsing failed"); + goto free; + } + + *pkt = pkt_l; + *bcn = bcn_l; + *rx_pkt_info = rx_pkt_info_l; + + return QDF_STATUS_SUCCESS; + +free: + if (pkt_l) { + qdf_mem_free(pkt_l); + pkt_l = NULL; + } + + if (bcn_l) { + qdf_mem_free(bcn_l); + bcn_l = NULL; + } + + return QDF_STATUS_E_FAILURE; +} + +void lim_handle_sap_beacon(struct wlan_objmgr_pdev *pdev, + struct scan_cache_entry *scan_entry) +{ + struct mac_context *mac_ctx; + cds_pkt_t *pkt = NULL; + tSchBeaconStruct *bcn = NULL; + struct mgmt_beacon_probe_filter *filter; + QDF_STATUS status; + uint8_t *rx_pkt_info = NULL; + int session_id; + + if (!scan_entry) { + pe_err("scan_entry is NULL"); + return; + } + + if (scan_entry->frm_subtype != MGMT_SUBTYPE_BEACON) + return; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return; + + filter = &mac_ctx->bcn_filter; + + if (!filter->num_sap_sessions) { + return; + } + for (session_id = 0; session_id < mac_ctx->lim.maxBssId; session_id++) { + if (filter->sap_channel[session_id] && + (filter->sap_channel[session_id] == + wlan_reg_freq_to_chan(pdev, + scan_entry->channel.chan_freq))) { + if (!pkt) { + status = lim_allocate_and_get_bcn( + mac_ctx, &pkt, &rx_pkt_info, + &bcn, scan_entry); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_debug("lim_allocate_and_get_bcn fail!"); + return; + } + } + sch_beacon_process_for_ap(mac_ctx, session_id, + rx_pkt_info, bcn); + } + } + + /* + * Free only the pkt memory we allocated and not the pkt->pkt_buf. + * The actual SKB buffer is freed in the scan module from where + * this API is invoked via callback + */ + if (bcn) + qdf_mem_free(bcn); + if (pkt) + qdf_mem_free(pkt); +} + +/** + * lim_defer_msg() + * + ***FUNCTION: + * This function is called to defer the messages received + * during Learn mode + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param pMsg of type struct scheduler_msg - Pointer to the message structure + * @return None + */ + +uint32_t lim_defer_msg(struct mac_context *mac, struct scheduler_msg *pMsg) +{ + uint32_t retCode = TX_SUCCESS; + + retCode = lim_write_deferred_msg_q(mac, pMsg); + + if (retCode == TX_SUCCESS) { + MTRACE(mac_trace_msg_rx + (mac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DEFERRED))); + } else { + pe_err_rl("Dropped lim message (0x%X) Message %s", pMsg->type, + lim_msg_str(pMsg->type)); + MTRACE(mac_trace_msg_rx + (mac, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(pMsg->type, LIM_MSG_DROPPED))); + } + + return retCode; +} /*** end lim_defer_msg() ***/ + +/** + * lim_handle_unknown_a2_index_frames() - This function handles Unknown Unicast + * (A2 Index) packets + * @mac_ctx: Pointer to the Global Mac Context. + * @rx_pkt_buffer: Pointer to the packet Buffer descriptor. + * @session_entry: Pointer to the PE Session Entry. + * + * This routine will handle public action frames. + * + * Return: None. + */ +static void lim_handle_unknown_a2_index_frames(struct mac_context *mac_ctx, + void *rx_pkt_buffer, struct pe_session *session_entry) +{ +#ifdef FEATURE_WLAN_TDLS + tpSirMacDataHdr3a mac_hdr; +#endif + if (LIM_IS_P2P_DEVICE_ROLE(session_entry)) + lim_process_action_frame_no_session(mac_ctx, + (uint8_t *) rx_pkt_buffer); +#ifdef FEATURE_WLAN_TDLS + mac_hdr = WMA_GET_RX_MPDUHEADER3A(rx_pkt_buffer); + + if (IEEE80211_IS_MULTICAST(mac_hdr->addr2)) { + pe_debug("Ignoring A2 Invalid Packet received for MC/BC: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(mac_hdr->addr2)); + return; + } + pe_debug("type=0x%x, subtype=0x%x", + mac_hdr->fc.type, mac_hdr->fc.subType); + /* Currently only following type and subtype are handled. + * If there are more combinations, then add switch-case + * statements. + */ + if (LIM_IS_STA_ROLE(session_entry) && + (mac_hdr->fc.type == SIR_MAC_MGMT_FRAME) && + (mac_hdr->fc.subType == SIR_MAC_MGMT_ACTION)) + lim_process_action_frame(mac_ctx, rx_pkt_buffer, session_entry); +#endif + return; +} + +static bool +lim_is_ignore_btm_frame(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + tSirMacFrameCtl fc, uint8_t *body, uint16_t frm_len) +{ + bool is_sta_roam_disabled_by_p2p, is_mbo_wo_pmf, is_disable_btm; + uint8_t action_id, category, token = 0; + tpSirMacActionFrameHdr action_hdr; + enum wlan_diag_btm_block_reason reason; + struct cm_roam_values_copy temp; + + /* + * Drop BTM frame, if BTM roam disabled by userspace via vendor + * command QCA_WLAN_VENDOR_ATTR_CONFIG_BTM_SUPPORT + */ + wlan_cm_roam_cfg_get_value(psoc, vdev_id, IS_DISABLE_BTM, &temp); + is_disable_btm = temp.bool_value; + if (is_disable_btm) { + pe_debug("Drop BTM frame. vdev:%d BTM roam disabled by user", + vdev_id); + return true; + } + + /* + * When DUT associated to BTM disabled AP and receives BTM req frame + * from connected AP then instead of forwarding the BTM req frame to + * supplicant, host should drop it + */ + if (!wlan_cm_get_assoc_btm_cap(psoc, vdev_id)) { + pe_debug("Drop BTM frame. vdev:%d BTM not supported by AP", + vdev_id); + return true; + } + + /* + * Drop BTM frame received on STA interface if concurrent + * P2P connection is active and p2p_disable_roam ini is + * enabled. This will help to avoid scan triggered by + * userspace after processing the BTM frame from AP so the + * audio glitches are not seen in P2P connection. + */ + is_sta_roam_disabled_by_p2p = cfg_p2p_is_roam_config_disabled(psoc) && + (policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_CLIENT_MODE, + NULL) || + policy_mgr_mode_specific_connection_count(psoc, + PM_P2P_GO_MODE, + NULL)); + + is_mbo_wo_pmf = wlan_cm_is_mbo_ap_without_pmf(psoc, vdev_id); + if (!is_sta_roam_disabled_by_p2p && !is_mbo_wo_pmf) + return false; + + action_hdr = (tpSirMacActionFrameHdr)body; + + if (frm_len < sizeof(*action_hdr) || !action_hdr || + fc.type != SIR_MAC_MGMT_FRAME || fc.subType != SIR_MAC_MGMT_ACTION) + return false; + + action_id = action_hdr->actionID; + category = action_hdr->category; + if (category == ACTION_CATEGORY_WNM && + (action_id == WNM_BSS_TM_QUERY || + action_id == WNM_BSS_TM_REQUEST || + action_id == WNM_BSS_TM_RESPONSE)) { + if (frm_len >= sizeof(*action_hdr) + 1) + token = *(body + sizeof(*action_hdr)); + if (is_mbo_wo_pmf) { + pe_debug("Drop the BTM frame as it's received from MBO AP without PMF, vdev %d", + vdev_id); + reason = WLAN_DIAG_BTM_BLOCK_MBO_WO_PMF; + } else { + pe_debug("Drop the BTM frame as p2p session is active, vdev %d", + vdev_id); + reason = WLAN_DIAG_BTM_BLOCK_UNSUPPORTED_P2P_CONC; + } + wlan_cm_roam_btm_block_event(vdev_id, token, reason); + return true; + } + + return false; +} + +/** + * lim_check_mgmt_registered_frames() - This function handles registered + * management frames. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @buff_desc: Pointer to the packet Buffer descriptor. + * @session_entry: Pointer to the PE Session Entry. + * + * This function is called to process to check if received frame match with + * any of the registered frame from HDD. If yes pass this frame to SME. + * + * Return: True or False for Match or Mismatch respectively. + */ +static bool +lim_check_mgmt_registered_frames(struct mac_context *mac_ctx, uint8_t *buff_desc, + struct pe_session *session_entry) +{ + tSirMacFrameCtl fc; + tpSirMacMgmtHdr hdr; + uint8_t *body; + struct mgmt_frm_reg_info *mgmt_frame = NULL; + struct mgmt_frm_reg_info *next_frm = NULL; + uint16_t frm_type; + uint16_t frm_len; + uint8_t type, sub_type; + bool match = false; + uint8_t vdev_id = WLAN_INVALID_VDEV_ID; + QDF_STATUS qdf_status; + + hdr = WMA_GET_RX_MAC_HEADER(buff_desc); + fc = hdr->fc; + frm_type = (fc.type << 2) | (fc.subType << 4); + body = WMA_GET_RX_MPDU_DATA(buff_desc); + frm_len = WMA_GET_RX_PAYLOAD_LEN(buff_desc); + + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_list_peek_front(&mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t **) &mgmt_frame); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + + while (mgmt_frame) { + type = (mgmt_frame->frameType >> 2) & 0x03; + sub_type = (mgmt_frame->frameType >> 4) & 0x0f; + if ((type == SIR_MAC_MGMT_FRAME) + && (fc.type == SIR_MAC_MGMT_FRAME) + && (sub_type == SIR_MAC_MGMT_RESERVED15)) { + pe_debug("rcvd frm match for SIR_MAC_MGMT_RESERVED15"); + match = true; + break; + } + if (mgmt_frame->frameType == frm_type) { + if (mgmt_frame->matchLen <= 0) { + match = true; + break; + } + if (mgmt_frame->matchLen <= frm_len && + (!qdf_mem_cmp(mgmt_frame->matchData, body, + mgmt_frame->matchLen))) { + /* found match! */ + match = true; + break; + } + } + + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_status = + qdf_list_peek_next( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t *) mgmt_frame, + (qdf_list_node_t **) &next_frm); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + mgmt_frame = next_frm; + next_frm = NULL; + } + if (match) { + pe_debug("rcvd frame match with registered frame params"); + + if (session_entry && LIM_IS_STA_ROLE(session_entry) && + lim_is_ignore_btm_frame(mac_ctx->psoc, + session_entry->vdev_id, fc, body, + frm_len)) + return match; + + /* + * Some frames like GAS_INITIAL_REQ are registered with + * SME_SESSION_ID_ANY, and received without session. + */ + vdev_id = mgmt_frame->sessionId; + if (session_entry) + vdev_id = session_entry->vdev_id; + + /* Indicate this to SME */ + lim_send_sme_mgmt_frame_ind(mac_ctx, hdr->fc.subType, + (uint8_t *) hdr, + WMA_GET_RX_PAYLOAD_LEN(buff_desc) + + sizeof(tSirMacMgmtHdr), vdev_id, + WMA_GET_RX_FREQ(buff_desc), + WMA_GET_RX_RSSI_NORMALIZED(buff_desc), + RXMGMT_FLAG_NONE); + + if ((type == SIR_MAC_MGMT_FRAME) + && (fc.type == SIR_MAC_MGMT_FRAME) + && (sub_type == SIR_MAC_MGMT_RESERVED15)) + /* These packets needs to be processed by PE/SME + * as well as HDD.If it returns true here, + * the packet is forwarded to HDD only. + */ + match = false; + } + + return match; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * lim_is_mgmt_frame_loggable() - to log non-excessive mgmt frames + * @type: type of frames i.e. mgmt, control, data + * @subtype: subtype of frames i.e. beacon, probe rsp, probe req and etc + * + * This API tells if given mgmt frame is expected to come excessive in + * amount or not. + * + * Return: true if mgmt is expected to come not that often, so makes it + * loggable. false if mgmt is expected to come too often, so makes + * it not loggable + */ +static bool +lim_is_mgmt_frame_loggable(uint8_t type, uint8_t subtype) +{ + if (type != SIR_MAC_MGMT_FRAME) + return false; + + switch (subtype) { + case SIR_MAC_MGMT_BEACON: + case SIR_MAC_MGMT_PROBE_REQ: + case SIR_MAC_MGMT_PROBE_RSP: + return false; + default: + return true; + } +} +#else +static bool +lim_is_mgmt_frame_loggable(uint8_t type, uint8_t subtype) +{ + return false; +} +#endif + +/** + * lim_handle80211_frames() + * + ***FUNCTION: + * This function is called to process 802.11 frames + * received by LIM. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param pMsg of type struct scheduler_msg - Pointer to the message structure + * @return None + */ + +static void +lim_handle80211_frames(struct mac_context *mac, struct scheduler_msg *limMsg, + uint8_t *pDeferMsg) +{ + uint8_t *pRxPacketInfo = NULL; + tSirMacFrameCtl fc; + tpSirMacMgmtHdr pHdr = NULL; + struct pe_session *pe_session = NULL; + uint8_t sessionId; + bool isFrmFt = false; + uint32_t frequency; + bool is_hw_sbs_capable = false; + + *pDeferMsg = false; + lim_get_b_dfrom_rx_packet(mac, limMsg->bodyptr, + (uint32_t **) &pRxPacketInfo); + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + isFrmFt = WMA_GET_RX_FT_DONE(pRxPacketInfo); + frequency = WMA_GET_RX_FREQ(pRxPacketInfo); + fc = pHdr->fc; + + is_hw_sbs_capable = + policy_mgr_is_hw_sbs_capable(mac->psoc); + if (WLAN_REG_IS_5GHZ_CH_FREQ(frequency) && + (!is_hw_sbs_capable || + (is_hw_sbs_capable && + wlan_reg_is_dfs_for_freq(mac->pdev, frequency))) && + mac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + pe_session = pe_find_session_by_bssid(mac, + pHdr->bssId, &sessionId); + if (pe_session && + (QDF_SAP_MODE == pe_session->opmode)) { + pe_debug("CAC timer running - drop the frame"); + goto end; + } + } + +#ifdef WLAN_DUMP_MGMTFRAMES + pe_debug("ProtVersion %d, Type %d, Subtype %d rateIndex=%d", + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, pHdr, + WMA_GET_RX_MPDU_HEADER_LEN(pRxPacketInfo)); +#endif + if (fc.type == SIR_MAC_MGMT_FRAME) { + if ((mac->mlme_cfg->gen.debug_packet_log & + DEBUG_PKTLOG_TYPE_MGMT) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) && + (fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON) && + (fc.subType != SIR_MAC_MGMT_ACTION)) + mgmt_txrx_frame_hex_dump((uint8_t *)pHdr, + WMA_GET_RX_MPDU_LEN(pRxPacketInfo), + false); + } + +#ifdef FEATURE_WLAN_EXTSCAN + if (WMA_IS_EXTSCAN_SCAN_SRC(pRxPacketInfo) || + WMA_IS_EPNO_SCAN_SRC(pRxPacketInfo)) { + if (fc.subType == SIR_MAC_MGMT_BEACON || + fc.subType == SIR_MAC_MGMT_PROBE_RSP) { + __lim_process_ext_scan_beacon_probe_rsp(mac, + pRxPacketInfo, + fc.subType); + } else { + pe_err("Wrong frameType %d, Subtype %d for %d", + fc.type, fc.subType, + WMA_GET_SCAN_SRC(pRxPacketInfo)); + } + goto end; + } +#endif + /* Added For BT-AMP Support */ + pe_session = pe_find_session_by_bssid(mac, pHdr->bssId, + &sessionId); + if (!pe_session) { + if (fc.subType == SIR_MAC_MGMT_AUTH) { + pe_debug("ProtVersion %d, Type %d, Subtype %d rateIndex=%d bssid=" QDF_MAC_ADDR_FMT, + fc.protVer, fc.type, fc.subType, + WMA_GET_RX_MAC_RATE_IDX(pRxPacketInfo), + QDF_MAC_ADDR_REF(pHdr->bssId)); + if (lim_process_auth_frame_no_session + (mac, pRxPacketInfo, + limMsg->bodyptr) == QDF_STATUS_SUCCESS) { + goto end; + } + } + /* Public action frame can be received from non-assoc stations*/ + if ((fc.subType != SIR_MAC_MGMT_PROBE_RSP) && + (fc.subType != SIR_MAC_MGMT_BEACON) && + (fc.subType != SIR_MAC_MGMT_PROBE_REQ) + && (fc.subType != SIR_MAC_MGMT_ACTION)) { + + pe_session = pe_find_session_by_peer_sta(mac, + pHdr->sa, &sessionId); + if (!pe_session) { + pe_debug("session does not exist for bssId: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pHdr->sa)); + goto end; + } else { + pe_debug("SessionId:%d exists for given Bssid", + pe_session->peSessionId); + } + } + /* For p2p resp frames search for valid session with DA as */ + /* BSSID will be SA and session will be present with DA only */ + if (fc.subType == SIR_MAC_MGMT_ACTION) { + pe_session = + pe_find_session_by_bssid(mac, pHdr->da, &sessionId); + } + } + + /* Check if frame is registered by HDD */ + if (lim_check_mgmt_registered_frames(mac, pRxPacketInfo, pe_session)) + goto end; + + if (fc.protVer != SIR_MAC_PROTOCOL_VERSION) { /* Received Frame with non-zero Protocol Version */ + pe_err("Unexpected frame with protVersion %d received", + fc.protVer); + lim_pkt_free(mac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); + goto end; + } + + switch (fc.type) { + case SIR_MAC_MGMT_FRAME: + { + /* Received Management frame */ + switch (fc.subType) { + case SIR_MAC_MGMT_ASSOC_REQ: + /* Make sure the role supports Association */ + if (LIM_IS_AP_ROLE(pe_session)) + lim_process_assoc_req_frame(mac, + pRxPacketInfo, + LIM_ASSOC, + pe_session); + else { + pe_err("unexpected message received %X", + limMsg->type); + lim_print_msg_name(mac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_ASSOC_RSP: + lim_process_assoc_rsp_frame(mac, pRxPacketInfo, + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo), + LIM_ASSOC, + pe_session); + break; + + case SIR_MAC_MGMT_REASSOC_REQ: + /* Make sure the role supports Reassociation */ + if (LIM_IS_AP_ROLE(pe_session)) { + lim_process_assoc_req_frame(mac, + pRxPacketInfo, + LIM_REASSOC, + pe_session); + } else { + pe_err("unexpected message received %X", + limMsg->type); + lim_print_msg_name(mac, LOGE, + limMsg->type); + } + break; + + case SIR_MAC_MGMT_REASSOC_RSP: + lim_process_assoc_rsp_frame(mac, pRxPacketInfo, + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo), + LIM_REASSOC, + pe_session); + break; + + case SIR_MAC_MGMT_PROBE_REQ: + lim_process_probe_req_frame_multiple_bss(mac, + pRxPacketInfo, + pe_session); + break; + + case SIR_MAC_MGMT_PROBE_RSP: + if (pe_session) + lim_process_probe_rsp_frame(mac, + pRxPacketInfo, + pe_session); + break; + + case SIR_MAC_MGMT_BEACON: + __lim_handle_beacon(mac, limMsg, pe_session); + break; + + case SIR_MAC_MGMT_DISASSOC: + lim_process_disassoc_frame(mac, pRxPacketInfo, + pe_session); + break; + + case SIR_MAC_MGMT_AUTH: + lim_process_auth_frame(mac, pRxPacketInfo, + pe_session); + break; + + case SIR_MAC_MGMT_DEAUTH: + lim_process_deauth_frame(mac, pRxPacketInfo, + pe_session); + break; + + case SIR_MAC_MGMT_ACTION: + if (!pe_session) + lim_process_action_frame_no_session(mac, + pRxPacketInfo); + else { + if (mac->mlme_cfg->gen.debug_packet_log & + DEBUG_PKTLOG_TYPE_ACTION) { + pe_debug("RX MGMT - Type %hu, SubType %hu, seq num[%d]", + fc.type, fc.subType, + ((pHdr->seqControl.seqNumHi << HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + pHdr, + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) + + SIR_MAC_HDR_LEN_3A); + } + + if (WMA_GET_RX_UNKNOWN_UCAST + (pRxPacketInfo)) + lim_handle_unknown_a2_index_frames + (mac, pRxPacketInfo, + pe_session); + else + lim_process_action_frame(mac, + pRxPacketInfo, + pe_session); + } + break; + default: + /* Received Management frame of 'reserved' subtype */ + break; + } /* switch (fc.subType) */ + + } + break; + case SIR_MAC_DATA_FRAME: + { + } + break; + default: + /* Received frame of type 'reserved' */ + break; + + } /* switch (fc.type) */ + if (lim_is_mgmt_frame_loggable(fc.type, fc.subType)) + lim_diag_mgmt_rx_event_report(mac, pHdr, + pe_session, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +end: + lim_pkt_free(mac, TXRX_FRM_802_11_MGMT, pRxPacketInfo, + (void *)limMsg->bodyptr); + return; +} /*** end lim_handle80211_frames() ***/ + +QDF_STATUS lim_handle_frame_genby_mbssid(uint8_t *frame, uint32_t frame_len, + uint8_t frm_subtype, char *bssid) +{ + struct mac_context *mac_ctx; + struct pe_session *session; + uint8_t sessionid; + t_packetmeta meta_data = {0}; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + + session = pe_find_session_by_bssid(mac_ctx, bssid, &sessionid); + if (!session) + return QDF_STATUS_E_INVAL; + + meta_data.mpdu_hdr_ptr = frame; + meta_data.mpdu_len = frame_len; + meta_data.mpdu_data_ptr = frame + sizeof(struct wlan_frame_hdr); + meta_data.mpdu_data_len = frame_len - sizeof(struct wlan_frame_hdr); + + if (frm_subtype == MGMT_SUBTYPE_BEACON) { + pe_debug("Gen beacon frame for critical update feature"); + if (session->limSmeState == eLIM_SME_LINK_EST_STATE || + session->limSmeState == eLIM_SME_NORMAL_STATE) + sch_beacon_process(mac_ctx, (uint8_t *)&meta_data, + session); + else + lim_process_beacon_frame(mac_ctx, (uint8_t *)&meta_data, + session); + } else if (frm_subtype == MGMT_SUBTYPE_PROBE_RESP) { + pe_debug("Gen Probe rsp frame for critical update feature"); + lim_process_probe_rsp_frame(mac_ctx, (uint8_t *)&meta_data, + session); + } + + return QDF_STATUS_SUCCESS; +} + +void lim_process_abort_scan_ind(struct mac_context *mac_ctx, + uint8_t vdev_id, uint32_t scan_id, uint32_t scan_requestor_id) +{ + QDF_STATUS status; + struct scan_cancel_request *req; + struct wlan_objmgr_vdev *vdev; + + pe_debug("scan_id %d, scan_requestor_id 0x%x", + scan_id, scan_requestor_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + mac_ctx->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_debug("vdev is NULL"); + return; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + goto fail; + + req->vdev = vdev; + req->cancel_req.requester = scan_requestor_id; + req->cancel_req.scan_id = scan_id; + req->cancel_req.vdev_id = vdev_id; + req->cancel_req.req_type = WLAN_SCAN_CANCEL_SINGLE; + + status = wlan_scan_cancel(req); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Cancel scan request failed"); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +static void lim_process_sme_obss_scan_ind(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct pe_session *session; + uint8_t session_id; + struct sme_obss_ht40_scanind_msg *ht40_scanind; + + ht40_scanind = (struct sme_obss_ht40_scanind_msg *)msg->bodyptr; + session = pe_find_session_by_bssid(mac_ctx, + ht40_scanind->mac_addr.bytes, &session_id); + if (!session) { + pe_err("OBSS Scan not started: session id is NULL"); + return; + } + pe_debug("OBSS Scan Req: vdev %d (pe session %d) htSupportedChannelWidthSet %d", + session->vdev_id, session->peSessionId, + session->htSupportedChannelWidthSet); + if (session->htSupportedChannelWidthSet == + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE) + lim_send_ht40_obss_scanind(mac_ctx, session); +} + +/** + * lim_process_messages() - Process messages from upper layers. + * + * @mac_ctx: Pointer to the Global Mac Context. + * @msg: Received message. + * + * Return: None. + */ +static void lim_process_messages(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + uint8_t vdev_id = 0; + tUpdateBeaconParams beacon_params; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + uint8_t i; + struct pe_session *session_entry = NULL; + uint8_t defer_msg = false; + uint16_t pkt_len = 0; + cds_pkt_t *body_ptr = NULL; + QDF_STATUS qdf_status; + struct scheduler_msg new_msg = {0}; + + if (!msg) { + pe_err("Message pointer is Null"); + QDF_ASSERT(0); + return; + } + + if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG) { + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + return; + } + + /* + * MTRACE logs not captured for events received from SME + * SME enums (eWNI_SME_START_REQ) starts with 0x16xx. + * Compare received SME events with SIR_SME_MODULE_ID + */ + if ((SIR_SME_MODULE_ID == + (uint8_t)MAC_TRACE_GET_MODULE_ID(msg->type)) && + (msg->type != eWNI_SME_REGISTER_MGMT_FRAME_REQ)) { + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_SME_MSG, + NO_SESSION, msg->type)); + } else { + /* + * Omitting below message types as these are too frequent + * and when crash happens we loose critical trace logs + * if these are also logged + */ + if (msg->type != SIR_BB_XPORT_MGMT_MSG && + msg->type != WMA_RX_SCAN_EVENT) + MTRACE(mac_trace_msg_rx(mac_ctx, NO_SESSION, + LIM_TRACE_MAKE_RXMSG(msg->type, + LIM_MSG_PROCESSED))); + } + + switch (msg->type) { + + case SIR_LIM_UPDATE_BEACON: + lim_update_beacon(mac_ctx); + break; + case SIR_BB_XPORT_MGMT_MSG: + /* These messages are from Peer MAC entity. + * The original msg which we were deferring have the + * bodyPointer point to 'BD' instead of 'cds pkt'. If we + * don't make a copy of msg, then overwrite the + * msg->bodyPointer and next time when we try to + * process the msg, we will try to use 'BD' as + * 'cds Pkt' which will cause a crash + */ + if (!msg->bodyptr) { + pe_err("Message bodyptr is Null"); + QDF_ASSERT(0); + break; + } + qdf_mem_copy((uint8_t *) &new_msg, + (uint8_t *) msg, sizeof(struct scheduler_msg)); + body_ptr = (cds_pkt_t *) new_msg.bodyptr; + cds_pkt_get_packet_length(body_ptr, &pkt_len); + + qdf_status = + wma_ds_peek_rx_packet_info(body_ptr, + (void **) &new_msg.bodyptr); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + lim_decrement_pending_mgmt_count(mac_ctx); + cds_pkt_return_packet(body_ptr); + break; + } + if (WMA_GET_ROAMCANDIDATEIND(new_msg.bodyptr)) + pe_debug("roamCandidateInd: %d", + WMA_GET_ROAMCANDIDATEIND(new_msg.bodyptr)); + if (WMA_GET_OFFLOADSCANLEARN(new_msg.bodyptr)) + pe_debug("offloadScanLearn: %d", + WMA_GET_OFFLOADSCANLEARN(new_msg.bodyptr)); + + lim_handle80211_frames(mac_ctx, &new_msg, &defer_msg); + + if (defer_msg == true) { + pe_debug("Defer Msg type=%x", msg->type); + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + pe_err("Unable to Defer Msg %x", msg->type); + lim_log_session_states(mac_ctx); + lim_decrement_pending_mgmt_count(mac_ctx); + cds_pkt_return_packet(body_ptr); + } + } else { + /* PE is not deferring this 802.11 frame so we need to + * call cds_pkt_return. Assumption here is when Rx mgmt + * frame processing is done, cds packet could be + * freed here. + */ + lim_decrement_pending_mgmt_count(mac_ctx); + cds_pkt_return_packet(body_ptr); + } + break; + case eWNI_SME_DISASSOC_REQ: + case eWNI_SME_DEAUTH_REQ: +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + case eWNI_SME_TDLS_ADD_STA_REQ: + case eWNI_SME_TDLS_DEL_STA_REQ: + case eWNI_SME_TDLS_LINK_ESTABLISH_REQ: +#endif + case eWNI_SME_SET_HW_MODE_REQ: + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + case eWNI_SME_SET_ANTENNA_MODE_REQ: + case eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE: + case eWNI_SME_UPDATE_CONFIG: + /* These messages are from HDD. Need to respond to HDD */ + lim_process_normal_hdd_msg(mac_ctx, msg, true); + break; + case eWNI_SME_SEND_DISASSOC_FRAME: + /* Need to response to hdd */ + lim_process_normal_hdd_msg(mac_ctx, msg, true); + break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: + case eWNI_SME_SET_VDEV_IES_PER_BAND: + case eWNI_SME_SYS_READY_IND: + case eWNI_SME_JOIN_REQ: + case eWNI_SME_REASSOC_REQ: + case eWNI_SME_START_BSS_REQ: + case eWNI_SME_STOP_BSS_REQ: + case eWNI_SME_SWITCH_CHL_IND: + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + case eWNI_SME_ASSOC_CNF: + case eWNI_SME_ADDTS_REQ: + case eWNI_SME_MSCS_REQ: + case eWNI_SME_DELTS_REQ: + case eWNI_SME_SESSION_UPDATE_PARAM: + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + case eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND: +#if defined FEATURE_WLAN_ESE + case eWNI_SME_ESE_ADJACENT_AP_REPORT: +#endif + case eWNI_SME_FT_AGGR_QOS_REQ: + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_REGISTER_MGMT_FRAME_CB: + case eWNI_SME_EXT_CHANGE_CHANNEL: + case eWNI_SME_SET_ADDBA_ACCEPT: + case eWNI_SME_UPDATE_EDCA_PROFILE: + case WNI_SME_UPDATE_MU_EDCA_PARAMS: + case eWNI_SME_UPDATE_SESSION_EDCA_TXQ_PARAMS: + case WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU: + case eWNI_SME_VDEV_PAUSE_IND: + /* These messages are from HDD.No need to respond to HDD */ + lim_process_normal_hdd_msg(mac_ctx, msg, false); + break; + case eWNI_SME_SEND_MGMT_FRAME_TX: + lim_send_mgmt_frame_tx(mac_ctx, msg); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_MON_INIT_SESSION: + lim_mon_init_session(mac_ctx, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_MON_DEINIT_SESSION: + lim_mon_deinit_session(mac_ctx, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_P2P_NOA_ATTR_IND: + session_entry = &mac_ctx->lim.gpSession[0]; + pe_debug("Received message Noa_ATTR %x", + msg->type); + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session_entry = &mac_ctx->lim.gpSession[i]; + if ((session_entry) && (session_entry->valid) && + (session_entry->opmode == QDF_P2P_GO_MODE)) { + /* Save P2P attr for Go */ + qdf_mem_copy(&session_entry->p2pGoPsUpdate, + msg->bodyptr, + sizeof(tSirP2PNoaAttr)); + pe_debug("bssId" + QDF_MAC_ADDR_FMT + " ctWin=%d oppPsFlag=%d", + QDF_MAC_ADDR_REF(session_entry->bssId), + session_entry->p2pGoPsUpdate.ctWin, + session_entry->p2pGoPsUpdate.oppPsFlag); + pe_debug("uNoa1IntervalCnt=%d uNoa1Duration=%d uNoa1Interval=%d uNoa1StartTime=%d", + session_entry->p2pGoPsUpdate.uNoa1IntervalCnt, + session_entry->p2pGoPsUpdate.uNoa1Duration, + session_entry->p2pGoPsUpdate.uNoa1Interval, + session_entry->p2pGoPsUpdate.uNoa1StartTime); + break; + } + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_MISSED_BEACON_IND: + lim_ps_offload_handle_missed_beacon_ind(mac_ctx, msg); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_LIM_ADDTS_RSP_TIMEOUT: + lim_process_sme_req_messages(mac_ctx, msg); + break; +#ifdef FEATURE_WLAN_ESE + case WMA_TSM_STATS_RSP: + lim_send_sme_pe_ese_tsm_rsp(mac_ctx, + (tAniGetTsmStatsRsp *) msg->bodyptr); + break; +#endif + case WMA_ADD_TS_RSP: + lim_process_hal_add_ts_rsp(mac_ctx, msg); + break; + case SIR_LIM_DELETE_STA_CONTEXT_IND: + lim_delete_sta_context(mac_ctx, msg); + break; + case SIR_LIM_RX_INVALID_PEER: + lim_rx_invalid_peer_process(mac_ctx, msg); + break; + case SIR_HAL_REQ_SEND_DELBA_REQ_IND: + lim_req_send_delba_ind_process(mac_ctx, msg); + break; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: + case SIR_LIM_AUTH_FAIL_TIMEOUT: + case SIR_LIM_AUTH_RSP_TIMEOUT: + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + case SIR_LIM_REASSOC_FAIL_TIMEOUT: + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + case SIR_LIM_DISASSOC_ACK_TIMEOUT: + case SIR_LIM_AUTH_RETRY_TIMEOUT: + case SIR_LIM_AUTH_SAE_TIMEOUT: + case SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT: + /* These timeout messages are handled by MLM sub module */ + lim_process_mlm_req_messages(mac_ctx, msg); + break; + case SIR_LIM_HEART_BEAT_TIMEOUT: + /** check if heart beat failed, even if one Beacon + * is rcvd within the Heart Beat interval continue + * normal processing + */ + if (!msg->bodyptr) + pe_err("Can't Process HB TO - bodyptr is Null"); + else { + session_entry = (struct pe_session *) msg->bodyptr; + pe_err("SIR_LIM_HEART_BEAT_TIMEOUT, Session %d", + ((struct pe_session *) msg->bodyptr)->peSessionId); + limResetHBPktCount(session_entry); + lim_handle_heart_beat_timeout_for_session(mac_ctx, + session_entry); + } + break; + case SIR_LIM_CNF_WAIT_TIMEOUT: + /* Does not receive CNF or dummy packet */ + lim_handle_cnf_wait_timeout(mac_ctx, (uint16_t) msg->bodyval); + break; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + lim_handle_update_olbc_cache(mac_ctx); + break; + case WMA_ADD_STA_RSP: + lim_process_add_sta_rsp(mac_ctx, msg); + break; + case WMA_DELETE_STA_RSP: + lim_process_mlm_del_sta_rsp(mac_ctx, msg); + break; + case WMA_DELETE_BSS_RSP: + case WMA_DELETE_BSS_HO_FAIL_RSP: + lim_handle_delete_bss_rsp(mac_ctx, msg->bodyptr); + break; + case WMA_CSA_OFFLOAD_EVENT: + case eWNI_SME_CSA_REQ: + lim_handle_csa_offload_msg(mac_ctx, msg); + break; + case WMA_SET_BSSKEY_RSP: + case WMA_SET_STA_BCASTKEY_RSP: + lim_process_mlm_set_bss_key_rsp(mac_ctx, msg); + break; + case WMA_SET_STAKEY_RSP: + lim_process_mlm_set_sta_key_rsp(mac_ctx, msg); + break; + case WMA_SET_MIMOPS_RSP: + case WMA_SET_TX_POWER_RSP: + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_SET_MAX_TX_POWER_RSP: + rrm_set_max_tx_power_rsp(mac_ctx, msg); + if (msg->bodyptr) { + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + } + break; + case SIR_LIM_ADDR2_MISS_IND: + pe_err( + FL("Addr2 mismatch interrupt received %X"), msg->type); + /* message from HAL indicating addr2 mismatch interrupt occurred + * msg->bodyptr contains only pointer to 48-bit addr2 field + */ + qdf_mem_free((void *)(msg->bodyptr)); + msg->bodyptr = NULL; + break; + case WMA_AGGR_QOS_RSP: + lim_process_ft_aggr_qos_rsp(mac_ctx, msg); + break; + case WMA_DFS_BEACON_TX_SUCCESS_IND: + lim_process_beacon_tx_success_ind(mac_ctx, msg->type, + (void *)msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_DISASSOC_TX_COMP: + lim_disassoc_tx_complete_cnf(mac_ctx, msg->bodyval, + msg->bodyptr); + break; + case WMA_DEAUTH_TX_COMP: + lim_deauth_tx_complete_cnf(mac_ctx, msg->bodyval, + msg->bodyptr); + break; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + case WMA_UPDATE_Q2Q_IE_IND: + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.paramChangeBitmap = 0; + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + vdev_id = ((uint8_t *)msg->bodyptr)[i]; + session_entry = pe_find_session_by_vdev_id(mac_ctx, + vdev_id); + if (!session_entry) + continue; + session_entry->sap_advertise_avoid_ch_ie = + (uint8_t)msg->bodyval; + /* + * if message comes for DFS channel, no need to update: + * 1) We won't have MCC with DFS channels. so no need to + * add Q2Q IE + * 2) We cannot end up in DFS channel SCC by channel + * switch from non DFS MCC scenario, so no need to + * remove Q2Q IE + * 3) There is however a case where device start MCC and + * then user modifies hostapd.conf and does SAP + * restart, in such a case, beacon params will be + * reset and thus will not contain Q2Q IE, by default + */ + if (wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + session_entry->curr_op_freq, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_DFS) { + beacon_params.bss_idx = session_entry->vdev_id; + beacon_params.beaconInterval = + session_entry->beaconParams.beaconInterval; + beacon_params.paramChangeBitmap |= + PARAM_BCN_INTERVAL_CHANGED; + sch_set_fixed_beacon_fields(mac_ctx, + session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, + session_entry); + } + } + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + case eWNI_SME_NSS_UPDATE_REQ: + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; +#endif + case SIR_HAL_PDEV_SET_HW_MODE_RESP: + lim_process_set_hw_mode_resp(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_HAL_PDEV_MAC_CFG_RESP: + lim_process_dual_mac_cfg_resp(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_SET_IE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_HT40_OBSS_SCAN_IND: + lim_process_sme_obss_scan_ind(mac_ctx, msg); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_ANTENNA_MODE_RESP: + lim_process_set_antenna_resp(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_DEFAULT_SCAN_IE: + lim_process_set_default_scan_ie_request(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_SET_HE_BSS_COLOR: + lim_process_set_he_bss_color(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_RECONFIG_OBSS_SCAN_PARAM: + lim_reconfig_obss_scan_param(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_DEL_ALL_TDLS_PEERS: + lim_process_sme_del_all_tdls_peers(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_OBSS_DETECTION_INFO: + lim_process_obss_detection_ind(mac_ctx, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_SEND_SAE_MSG: + lim_process_sae_msg(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case WMA_OBSS_COLOR_COLLISION_INFO: + lim_process_obss_color_collision_info(mac_ctx, msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_CSA_RESTART_REQ: + lim_send_csa_restart_req(mac_ctx, msg->bodyval); + break; + case eWNI_SME_STA_CSA_CONTINUE_REQ: + lim_continue_sta_csa_req(mac_ctx, msg->bodyval); + break; + case WMA_SEND_BCN_RSP: + lim_send_bcn_rsp(mac_ctx, (tpSendbeaconParams)msg->bodyptr); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + case SIR_LIM_PROCESS_DEFERRED_QUEUE: + break; + case CM_BSS_PEER_CREATE_REQ: + cm_process_peer_create(msg); + break; + case CM_CONNECT_REQ: + cm_process_join_req(msg); + break; + case CM_REASSOC_REQ: + cm_process_reassoc_req(msg); + break; + case CM_DISCONNECT_REQ: + cm_process_disconnect_req(msg); + break; + case CM_PREAUTH_REQ: + cm_process_preauth_req(msg); + break; + case CM_ABORT_CONN_TIMER: + lim_deactivate_timers_for_vdev(mac_ctx, msg->bodyval); + break; + case WIFI_POS_PASN_PEER_DELETE_ALL: + lim_process_pasn_delete_all_peers(mac_ctx, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + break; + case eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ: + lim_process_sme_req_messages(mac_ctx, msg); + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + break; + default: + qdf_mem_free((void *)msg->bodyptr); + msg->bodyptr = NULL; + pe_debug("Discarding unexpected message received %X", + msg->type); + lim_print_msg_name(mac_ctx, LOGE, msg->type); + break; + + } /* switch (msg->type) */ +} /*** end lim_process_messages() ***/ + +/** + * lim_process_deferred_message_queue() + * + * This function is called by LIM while exiting from Learn + * mode. This function fetches messages posted to the LIM + * deferred message queue limDeferredMsgQ. + * + * @mac: Pointer to Global MAC structure + * @return None + */ + +static void lim_process_deferred_message_queue(struct mac_context *mac) +{ + struct scheduler_msg limMsg = {0}; + struct scheduler_msg *readMsg; + uint16_t size; + + /* + ** check any deferred messages need to be processed + **/ + size = mac->lim.gLimDeferredMsgQ.size; + if (size > 0) { + while ((readMsg = lim_read_deferred_msg_q(mac)) != NULL) { + qdf_mem_copy((uint8_t *) &limMsg, + (uint8_t *) readMsg, + sizeof(struct scheduler_msg)); + size--; + lim_process_messages(mac, &limMsg); + + if (!GET_LIM_PROCESS_DEFD_MESGS(mac) || + mac->lim.gLimAddtsSent) + break; + } + } +} /*** end lim_process_deferred_message_queue() ***/ + +/** + * lim_message_processor() - Process messages from LIM. + * @mac_ctx: Pointer to the Global Mac Context. + * @msg: Received LIM message. + * + * Wrapper function for lim_process_messages when handling messages received by + * LIM. Could either defer messages or process them. + * + * Return: None. + */ +void lim_message_processor(struct mac_context *mac_ctx, struct scheduler_msg *msg) +{ + if (eLIM_MLM_OFFLINE_STATE == mac_ctx->lim.gLimMlmState) { + pe_free_msg(mac_ctx, msg); + return; + } + + if (!def_msg_decision(mac_ctx, msg)) { + lim_process_messages(mac_ctx, msg); + /* process deferred message queue if allowed */ + if ((!(mac_ctx->lim.gLimAddtsSent)) && + GET_LIM_PROCESS_DEFD_MESGS(mac_ctx)) + lim_process_deferred_message_queue(mac_ctx); + } +} + +/** + * lim_process_normal_hdd_msg() - Process the message and defer if needed + * @mac_ctx : Pointer to Global MAC structure + * @msg : The message need to be processed + * @rsp_reqd: whether return result to hdd + * + * This function checks the current lim state and decide whether the message + * passed will be deferred or not. + * + * Return: None + */ +static void lim_process_normal_hdd_msg(struct mac_context *mac_ctx, + struct scheduler_msg *msg, + uint8_t rsp_reqd) +{ + bool defer_msg = true; + + /* Added For BT-AMP Support */ + if ((mac_ctx->lim.gLimSystemRole == eLIM_AP_ROLE) + || (mac_ctx->lim.gLimSystemRole == eLIM_UNKNOWN_ROLE)) { + /* + * This check is required only for the AP and in 2 cases. + * 1. If we are in learn mode and we receive any of these + * messages, you have to come out of scan and process the + * message, hence dont defer the message here. In handler, + * these message could be deferred till we actually come out of + * scan mode. + * 2. If radar is detected, you might have to defer all of + * these messages except Stop BSS request/ Switch channel + * request. This decision is also made inside its handler. + * + * Please be careful while using the flag defer_msg. Possibly + * you might end up in an infinite loop. + */ + if ((msg->type == eWNI_SME_START_BSS_REQ) || + (msg->type == eWNI_SME_STOP_BSS_REQ) || + (msg->type == eWNI_SME_SWITCH_CHL_IND)) + defer_msg = false; + } + + if (mac_ctx->lim.gLimAddtsSent && defer_msg) { + /* + * System is in DFS (Learn) mode or awaiting addts response or + * if radar is detected, Defer processing this message + */ + if (lim_defer_msg(mac_ctx, msg) != TX_SUCCESS) { + lim_log_session_states(mac_ctx); + /* Release body */ + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + } else { + /* + * These messages are from HDD.Since these requests may also be + * generated internally within LIM module, need to distinguish + * and send response to host + */ + if (rsp_reqd) + mac_ctx->lim.gLimRspReqd = true; + if (lim_process_sme_req_messages(mac_ctx, msg)) { + /* + * Release body. limProcessSmeReqMessage consumed the + * buffer. We can free it. + */ + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + } +} + +void +handle_ht_capabilityand_ht_info(struct mac_context *mac, + struct pe_session *pe_session) +{ + struct mlme_ht_capabilities_info *ht_cap_info; + + ht_cap_info = &mac->mlme_cfg->ht_caps.ht_cap_info; + mac->lim.gHTLsigTXOPProtection = + (uint8_t)ht_cap_info->l_sig_tx_op_protection; + mac->lim.gHTMIMOPSState = + (tSirMacHTMIMOPowerSaveState)ht_cap_info->mimo_power_save; + mac->lim.gHTGreenfield = (uint8_t)ht_cap_info->green_field; + mac->lim.gHTMaxAmsduLength = + (uint8_t)ht_cap_info->maximal_amsdu_size; + mac->lim.gHTShortGI20Mhz = (uint8_t)ht_cap_info->short_gi_20_mhz; + mac->lim.gHTShortGI40Mhz = (uint8_t)ht_cap_info->short_gi_40_mhz; + mac->lim.gHTPSMPSupport = (uint8_t)ht_cap_info->psmp; + mac->lim.gHTDsssCckRate40MHzSupport = + (uint8_t)ht_cap_info->dsss_cck_mode_40_mhz; + + mac->lim.gHTAMpduDensity = + (uint8_t)mac->mlme_cfg->ht_caps.ampdu_params.mpdu_density; + mac->lim.gHTMaxRxAMpduFactor = + (uint8_t)mac->mlme_cfg->ht_caps.ampdu_params. + max_rx_ampdu_factor; + + /* Get HT IE Info */ + mac->lim.gHTServiceIntervalGranularity = + (uint8_t)mac->mlme_cfg->ht_caps.info_field_1. + service_interval_granularity; + mac->lim.gHTControlledAccessOnly = + (uint8_t)mac->mlme_cfg->ht_caps.info_field_1. + controlled_access_only; + + mac->lim.gHTOperMode = (tSirMacHTOperatingMode)mac->mlme_cfg->ht_caps. + info_field_2.op_mode; + + mac->lim.gHTPCOActive = (uint8_t)mac->mlme_cfg->ht_caps.info_field_3. + pco_active; + mac->lim.gHTPCOPhase = (uint8_t)mac->mlme_cfg->ht_caps.info_field_3. + pco_phase; + mac->lim.gHTSecondaryBeacon = + (uint8_t)mac->mlme_cfg->ht_caps.info_field_3.secondary_beacon; + mac->lim.gHTDualCTSProtection = (uint8_t)mac->mlme_cfg->ht_caps. + info_field_3.dual_cts_protection; + mac->lim.gHTSTBCBasicMCS = (uint8_t)mac->mlme_cfg->ht_caps. + info_field_3.basic_stbc_mcs; + + /* The lim globals for channelwidth and secondary chnl have been removed and should not be used during no session; + * instead direct cfg is read and used when no session for transmission of mgmt frames (same as old); + * For now, we might come here during init and join with pe_session = NULL; in that case just fill the globals which exist + * Sessionized entries values will be filled in join or add bss req. The ones which are missed in join are filled below + */ + if (pe_session) { + pe_session->htCapability = + IS_DOT11_MODE_HT(pe_session->dot11mode); + pe_session->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t)mac->mlme_cfg->ht_caps.info_field_3. + lsig_txop_protection_full_support; + lim_init_obss_params(mac, pe_session); + } +} + +void lim_log_session_states(struct mac_context *mac_ctx) +{ +#ifdef WLAN_DEBUG + int i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid) { + pe_debug("sysRole(%d) Session (%d)", + mac_ctx->lim.gLimSystemRole, i); + pe_debug("SME: Curr %s,Prev %s,MLM: Curr %s,Prev %s", + lim_sme_state_str( + mac_ctx->lim.gpSession[i].limSmeState), + lim_sme_state_str( + mac_ctx->lim.gpSession[i].limPrevSmeState), + lim_mlm_state_str( + mac_ctx->lim.gpSession[i].limMlmState), + lim_mlm_state_str( + mac_ctx->lim.gpSession[i].limPrevMlmState)); + } + } +#endif +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c new file mode 100644 index 0000000000..54396f1fd7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_host_roam.c @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: lim_process_mlm_host_roam.c + * + * Host based roaming MLM implementation + */ +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sir_params.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_send_messages.h" +#include "lim_session_utils.h" +#include +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +#include "host_diag_core_log.h" +#endif +#include "wma_if.h" +#include "rrm_api.h" +#include "wma.h" +#include + +static void lim_handle_sme_reaasoc_result(struct mac_context *, tSirResultCodes, + uint16_t, struct pe_session *); +/** + * lim_process_mlm_reassoc_req() - process mlm reassoc request. + * + * @mac_ctx: pointer to Global MAC structure + * @msg: pointer to the MLM message buffer + * + * This function is called to process MLM_REASSOC_REQ message + * from SME + * + * Return: None + */ +void lim_process_mlm_reassoc_req(struct mac_context *mac_ctx, + tLimMlmReassocReq *reassoc_req) +{ + struct tLimPreAuthNode *auth_node; + tLimMlmReassocCnf reassoc_cnf; + struct pe_session *session; + + session = pe_find_session_by_session_id(mac_ctx, + reassoc_req->sessionId); + if (!session) { + pe_err("Session Does not exist for given sessionId: %d", + reassoc_req->sessionId); + qdf_mem_free(reassoc_req); + return; + } + + pe_debug("ReAssoc Req on session: %d role: %d mlm: %d " QDF_MAC_ADDR_FMT, + reassoc_req->sessionId, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + QDF_MAC_ADDR_REF(reassoc_req->peerMacAddr)); + + if (LIM_IS_AP_ROLE(session) || + (session->limMlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + /* + * Received Reassoc request in invalid state or + * in AP role.Return Reassoc confirm with Invalid + * parameters code. + */ + + pe_warn("unexpected msg state: %X role: %d MAC " + QDF_MAC_ADDR_FMT, + session->limMlmState, GET_LIM_SYSTEM_ROLE(session), + QDF_MAC_ADDR_REF(reassoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + reassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + reassoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + goto end; + } + + if (session->pLimMlmReassocReq) + qdf_mem_free(session->pLimMlmReassocReq); + + /* + * Hold Re-Assoc request as part of Session, knock-out mac_ctx + * Hold onto Reassoc request parameters + */ + session->pLimMlmReassocReq = reassoc_req; + + /* See if we have pre-auth context with new AP */ + auth_node = lim_search_pre_auth_list(mac_ctx, session->limReAssocbssId); + + if (!auth_node && (qdf_mem_cmp(reassoc_req->peerMacAddr, + session->bssId, + sizeof(tSirMacAddr)))) { + /* + * Either pre-auth context does not exist AND + * we are not reassociating with currently + * associated AP. + * Return Reassoc confirm with not authenticated + */ + reassoc_cnf.resultCode = eSIR_SME_STA_NOT_AUTHENTICATED; + reassoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + + goto end; + } + /* assign the sessionId to the timer object */ + mac_ctx->lim.lim_timers.gLimReassocFailureTimer.sessionId = + reassoc_req->sessionId; + session->limPrevMlmState = session->limMlmState; + session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session); + + /* store the channel switch reason code in the lim global var */ + session->channelChangeReasonCode = LIM_SWITCH_CHANNEL_REASSOC; + mlme_set_chan_switch_in_progress(session->vdev, true); + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_FW_VDEV_RESTART, + sizeof(struct pe_session), session); + return; +end: + reassoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Update PE session Id */ + reassoc_cnf.sessionId = reassoc_req->sessionId; + /* Free up buffer allocated for reassocReq */ + qdf_mem_free(reassoc_req); + session->pLimReAssocReq = NULL; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *) &reassoc_cnf); +} + +/** + * lim_handle_sme_reaasoc_result() - Handle the reassoc result + * @mac: Global MAC Context + * @resultCode: Result code + * @protStatusCode: Protocol Status Code + * @pe_session: PE Session + * + * This function is called to process reassoc failures + * upon receiving REASSOC_CNF with a failure code or + * MLM_REASSOC_CNF with a success code in case of STA role + * + * Return: None + */ +static void lim_handle_sme_reaasoc_result(struct mac_context *mac, + tSirResultCodes resultCode, uint16_t protStatusCode, + struct pe_session *pe_session) +{ + tpDphHashNode sta = NULL; + uint8_t smesessionId; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + smesessionId = pe_session->smeSessionId; + if (resultCode != eSIR_SME_SUCCESS) { + sta = + dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (sta) { + sta->mlmStaContext.disassocReason = + REASON_UNSPEC_FAILURE; + sta->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + sta->mlmStaContext.resultCode = resultCode; + sta->mlmStaContext.protStatusCode = protStatusCode; + lim_mlo_notify_peer_disconn(pe_session, sta); + lim_cleanup_rx_path(mac, sta, pe_session, true); + /* Cleanup if add bss failed */ + if (pe_session->add_bss_failed) { + dph_delete_hash_entry(mac, + sta->staAddr, sta->assocId, + &pe_session->dph.dphHashTable); + goto error; + } + return; + } + } +error: + /* Delete the session if REASSOC failure occurred. */ + if (resultCode != eSIR_SME_SUCCESS) { + if (pe_session) { + pe_delete_session(mac, pe_session); + pe_session = NULL; + } + } + lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_REASSOC_RSP, resultCode, + protStatusCode, pe_session, smesessionId); +} + +/** + * lim_process_mlm_reassoc_cnf() - process mlm reassoc cnf msg + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_REASSOC_CNF message from MLM State + * machine. + * + * @Return: void + */ +void lim_process_mlm_reassoc_cnf(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + struct pe_session *session; + tLimMlmReassocCnf *lim_mlm_reassoc_cnf; + struct reassoc_params param; + QDF_STATUS status; + enum wlan_vdev_state sub_state; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + lim_mlm_reassoc_cnf = (tLimMlmReassocCnf *)msg_buf; + session = pe_find_session_by_session_id( + mac_ctx, + lim_mlm_reassoc_cnf->sessionId); + if (!session) { + pe_err("session Does not exist for given session Id"); + return; + } + if (session->limSmeState != eLIM_SME_WT_REASSOC_STATE || + LIM_IS_AP_ROLE(session)) { + /* + * Should not have received Reassocication confirm + * from MLM in other states OR on AP. + */ + pe_err("Rcv unexpected MLM_REASSOC_CNF role: %d sme 0x%X", + GET_LIM_SYSTEM_ROLE(session), session->limSmeState); + return; + } + + /* + * Upon Reassoc success or failure, freeup the cached preauth request, + * to ensure that channel switch is now allowed following any change in + * HT params. + */ + if (session->ftPEContext.pFTPreAuthReq) { + pe_debug("Freeing pFTPreAuthReq: %pK", + session->ftPEContext.pFTPreAuthReq); + if (session->ftPEContext.pFTPreAuthReq->pbssDescription) { + qdf_mem_free( + session->ftPEContext.pFTPreAuthReq->pbssDescription); + session->ftPEContext.pFTPreAuthReq->pbssDescription = + NULL; + } + qdf_mem_free(session->ftPEContext.pFTPreAuthReq); + session->ftPEContext.pFTPreAuthReq = NULL; + session->ftPEContext.ftPreAuthSession = false; + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (session->bRoamSynchInProgress) { + pe_debug("LFR3:Re-set the LIM Ctxt Roam Synch In Progress"); + session->bRoamSynchInProgress = false; + } +#endif + + sub_state = wlan_vdev_mlme_get_substate(session->vdev); + pe_debug("Rcv MLM_REASSOC_CNF with result code: %d vdev SS %d", + lim_mlm_reassoc_cnf->resultCode, sub_state); + if (lim_mlm_reassoc_cnf->resultCode == eSIR_SME_SUCCESS) { + /* Successful Reassociation */ + pe_debug("*** Reassociated with new BSS ***"); + + session->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace( + mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_SUCCESS, + 0, NULL); + + /* Need to send Reassoc rsp with Reassoc success to Host. */ + lim_send_sme_join_reassoc_rsp( + mac_ctx, eWNI_SME_REASSOC_RSP, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId); + } else if (sub_state == WLAN_VDEV_SS_START_CONN_PROGRESS || + sub_state == WLAN_VDEV_SS_START_RESTART_PROGRESS) { + session->limSmeState = eLIM_SME_LINK_EST_STATE; + /* + * Need to send Reassoc rsp with re-Assoc failure to CM + * so that disconnect can be initiated. + */ + lim_send_sme_join_reassoc_rsp( + mac_ctx, eWNI_SME_REASSOC_RSP, + lim_mlm_reassoc_cnf->resultCode, + lim_mlm_reassoc_cnf->protStatusCode, + session, session->smeSessionId); + } else { + param.result_code = lim_mlm_reassoc_cnf->resultCode; + param.prot_status_code = lim_mlm_reassoc_cnf->protStatusCode; + param.session = session; + + mlme_set_connection_fail(session->vdev, true); + + if (sub_state == WLAN_VDEV_SS_START_START_PROGRESS) + status = wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_REQ_FAIL, + sizeof(param), ¶m); + else + status = wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_CONNECTION_FAIL, + sizeof(param), ¶m); + } + + if (session->pLimReAssocReq) { + qdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } +} + +QDF_STATUS lim_sta_reassoc_error_handler(struct reassoc_params *param) +{ + struct pe_session *session; + struct mac_context *mac_ctx; + + if (!param) { + pe_err("param is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = param->session; + if (param->result_code + == eSIR_SME_REASSOC_REFUSED) { + /* + * Reassociation failure With the New AP but we still have the + * link with the Older AP + */ + session->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace( + mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + + /* Need to send Reassoc rsp with Assoc failure to Host. */ + lim_send_sme_join_reassoc_rsp( + mac_ctx, eWNI_SME_REASSOC_RSP, + param->result_code, + param->prot_status_code, + session, session->smeSessionId); + } else { + /* Reassociation failure */ + session->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace( + mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + /* Need to send Reassoc rsp with Assoc failure to Host. */ + lim_handle_sme_reaasoc_result( + mac_ctx, + param->result_code, + param->prot_status_code, + session); + } + return QDF_STATUS_SUCCESS; +} + +void lim_process_sta_mlm_add_bss_rsp_ft(struct mac_context *mac, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *pe_session) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tpDphHashNode sta = NULL; + tpAddStaParams pAddStaParams = NULL; + uint32_t listenInterval = MLME_CFG_LISTEN_INTERVAL; + struct bss_description *bss_desc = NULL; + + /* Sanity Checks */ + + if (!add_bss_rsp) { + pe_err("add_bss_rsp is NULL"); + goto end; + } + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE != + pe_session->limMlmState) { + goto end; + } + + sta = dph_add_hash_entry(mac, pe_session->bssId, + DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (!sta) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pe_session->bssId)); + goto end; + } + + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ + mac->lim.lim_timers.gLimReassocFailureTimer.sessionId = + pe_session->peSessionId; + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (mac, TRACE_CODE_TIMER_ACTIVATE, + pe_session->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + + if (tx_timer_activate(&mac->lim.lim_timers.gLimReassocFailureTimer) != + TX_SUCCESS) { + /* / Could not start reassoc failure timer. */ + /* Log error */ + pe_err("could not start Reassoc failure timer"); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + goto end; + } + + mac->lim.pe_session = pe_session; + if (!mac->lim.pe_session->pLimMlmReassocRetryReq) { + /* Take a copy of reassoc request for retrying */ + mac->lim.pe_session->pLimMlmReassocRetryReq = + qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (!mac->lim.pe_session->pLimMlmReassocRetryReq) + goto end; + + qdf_mem_copy(mac->lim.pe_session->pLimMlmReassocRetryReq, + pe_session->pLimMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + mac->lim.reAssocRetryAttempt = 0; + lim_send_reassoc_req_with_ft_ies_mgmt_frame( + mac, pe_session->pLimMlmReassocReq, pe_session); + + pe_session->limPrevMlmState = pe_session->limMlmState; + pe_session->limMlmState = eLIM_MLM_WT_FT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + eLIM_MLM_WT_FT_REASSOC_RSP_STATE)); + pe_debug("Set the mlm state: %d session: %d", + pe_session->limMlmState, pe_session->peSessionId); + + /* Success, handle below */ + + pAddStaParams = qdf_mem_malloc(sizeof(tAddStaParams)); + if (!pAddStaParams) + goto end; + + /* / Add STA context at MAC HW (BMU, RHP & TFP) */ + qdf_mem_copy((uint8_t *)pAddStaParams->staMac, + (uint8_t *)pe_session->self_mac_addr, + sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *)pAddStaParams->bssId, + pe_session->bssId, sizeof(tSirMacAddr)); + + pAddStaParams->staType = STA_ENTRY_SELF; + pAddStaParams->status = QDF_STATUS_SUCCESS; + + /* Update PE session ID */ + pAddStaParams->sessionId = pe_session->peSessionId; + pAddStaParams->smesessionId = pe_session->smeSessionId; + + pAddStaParams->updateSta = false; + + if (pe_session->lim_join_req) + bss_desc = &pe_session->lim_join_req->bssDescription; + + lim_populate_peer_rate_set(mac, &pAddStaParams->supportedRates, NULL, + false, pe_session, NULL, NULL, NULL, NULL, + bss_desc); + + if (pe_session->htCapability) { + pAddStaParams->htCapable = pe_session->htCapability; + pAddStaParams->vhtCapable = pe_session->vhtCapability; + pAddStaParams->ch_width = pe_session->ch_width; + + pAddStaParams->mimoPS = + lim_get_ht_capability(mac, eHT_MIMO_POWER_SAVE, + pe_session); + pAddStaParams->maxAmpduDensity = + lim_get_ht_capability(mac, eHT_MPDU_DENSITY, + pe_session); + pAddStaParams->maxAmpduSize = + lim_get_ht_capability(mac, eHT_MAX_RX_AMPDU_FACTOR, + pe_session); + pAddStaParams->fShortGI20Mhz = + lim_get_ht_capability(mac, eHT_SHORT_GI_20MHZ, + pe_session); + pAddStaParams->fShortGI40Mhz = + lim_get_ht_capability(mac, eHT_SHORT_GI_40MHZ, + pe_session); + } + + listenInterval = mac->mlme_cfg->sap_cfg.listen_interval; + pAddStaParams->listenInterval = (uint16_t) listenInterval; + + pAddStaParams->encryptType = pe_session->encryptType; + pAddStaParams->maxTxPower = pe_session->maxTxPower; + + /* Lets save this for when we receive the Reassoc Rsp */ + pe_session->ftPEContext.pAddStaReq = pAddStaParams; + + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (pe_session) + if (pe_session->pLimMlmReassocReq) { + qdf_mem_free(pe_session->pLimMlmReassocReq); + pe_session->pLimMlmReassocReq = NULL; + } + + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Update PE session Id */ + if (pe_session) + mlmReassocCnf.sessionId = pe_session->peSessionId; + else + mlmReassocCnf.sessionId = 0; + + lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +void lim_process_mlm_ft_reassoc_req(struct mac_context *mac, + tLimMlmReassocReq *reassoc_req) +{ + struct pe_session *session; + uint16_t caps; + uint32_t val; + QDF_STATUS status; + uint32_t teleBcnEn = 0; + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *mlme_obj; + + if (!reassoc_req) { + pe_err("reassoc_req is NULL"); + return; + } + + session = pe_find_session_by_session_id(mac, reassoc_req->sessionId); + if (!session) { + pe_err("session Does not exist for given session Id"); + qdf_mem_free(reassoc_req); + return; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_REASSOCIATING, + session, 0, 0); +#endif + + /* Nothing to be done if the session is not in STA mode */ + if (!LIM_IS_STA_ROLE(session)) { + pe_err("pe_session is not in STA mode"); + qdf_mem_free(reassoc_req); + return; + } + + if (!session->ftPEContext.pAddBssReq) { + pe_err("pAddBssReq is NULL"); + return; + } + + qdf_mem_copy(reassoc_req->peerMacAddr, + session->bssId, sizeof(tSirMacAddr)); + + if (lim_get_capability_info(mac, &caps, session) != + QDF_STATUS_SUCCESS) { + /** + * Could not get Capabilities value + * from CFG. Log error. + */ + pe_err("could not get Capabilities value"); + qdf_mem_free(reassoc_req); + return; + } + + lim_update_caps_info_for_bss(mac, &caps, + session->pLimReAssocReq->bssDescription.capabilityInfo); + pe_debug("Capabilities info FT Reassoc: 0x%X", caps); + + reassoc_req->capabilityInfo = caps; + + /* If telescopic beaconing is enabled, set listen interval + to CFG_TELE_BCN_MAX_LI + */ + teleBcnEn = mac->mlme_cfg->sap_cfg.tele_bcn_wakeup_en; + if (teleBcnEn) + val = mac->mlme_cfg->sap_cfg.tele_bcn_max_li; + else + val = mac->mlme_cfg->sap_cfg.listen_interval; + + reassoc_req->listenInterval = (uint16_t) val; + + vdev = session->vdev; + if (!vdev) { + pe_err("vdev is NULL"); + qdf_mem_free(reassoc_req); + return; + } + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return; + } + + status = lim_pre_vdev_start(mac, mlme_obj, session); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(reassoc_req); + return; + } + qdf_mem_copy(mlme_obj->mgmt.generic.bssid, session->bssId, + QDF_MAC_ADDR_SIZE); + + session->pLimMlmReassocReq = reassoc_req; + /* we need to defer the message until we get response back from HAL */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + status = wma_add_bss_lfr2_vdev_start(session->vdev, + session->ftPEContext.pAddBssReq); + if (QDF_IS_STATUS_ERROR(status)) { + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + pe_err("wma_add_bss_lfr2_vdev_start, reason: %X", status); + session->pLimMlmReassocReq = NULL; + qdf_mem_free(reassoc_req); + } + qdf_mem_free(session->ftPEContext.pAddBssReq); + + session->ftPEContext.pAddBssReq = NULL; + return; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c new file mode 100644 index 0000000000..bd4d610ae6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_req_messages.c @@ -0,0 +1,2162 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sir_params.h" +#include "cfg_ucfg_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_security_utils.h" +#include "lim_send_messages.h" +#include "lim_send_messages.h" +#include "lim_session_utils.h" +#include +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +#include "host_diag_core_log.h" +#endif +#include "wma_if.h" +#include "wma.h" +#include "wlan_reg_services_api.h" +#include "lim_process_fils.h" +#include "wlan_mlme_public_struct.h" +#include "../../core/src/vdev_mgr_ops.h" +#include "wlan_pmo_ucfg_api.h" +#include "wlan_cp_stats_utils_api.h" +#include "wlan_objmgr_vdev_obj.h" +#include +#include +#include "wlan_mlo_mgr_peer.h" +#include +#include "wifi_pos_pasn_api.h" +#include "rrm_api.h" +#include "../../core/src/wlan_cp_stats_obj_mgr_handler.h" + +static void lim_process_mlm_auth_req(struct mac_context *, uint32_t *); +static void lim_process_mlm_assoc_req(struct mac_context *, uint32_t *); +static void lim_process_mlm_disassoc_req(struct mac_context *, uint32_t *); + +/* MLM Timeout event handler templates */ +static void lim_process_auth_rsp_timeout(struct mac_context *, uint32_t); +static void lim_process_periodic_join_probe_req_timer(struct mac_context *); +static void lim_process_auth_retry_timer(struct mac_context *); + +static void lim_fill_status_code(uint8_t frame_type, + enum tx_ack_status ack_status, + enum wlan_status_code *proto_status_code) +{ + if (frame_type == SIR_MAC_MGMT_AUTH) { + switch (ack_status) { + case LIM_TX_FAILED: + *proto_status_code = STATUS_AUTH_TX_FAIL; + break; + case LIM_ACK_RCD_FAILURE: + case LIM_ACK_NOT_RCD: + *proto_status_code = STATUS_AUTH_NO_ACK_RECEIVED; + break; + case LIM_ACK_RCD_SUCCESS: + *proto_status_code = STATUS_AUTH_NO_RESP_RECEIVED; + break; + default: + *proto_status_code = STATUS_UNSPECIFIED_FAILURE; + } + } else if (frame_type == SIR_MAC_MGMT_ASSOC_RSP) { + switch (ack_status) { + case LIM_TX_FAILED: + *proto_status_code = STATUS_ASSOC_TX_FAIL; + break; + case LIM_ACK_RCD_FAILURE: + case LIM_ACK_NOT_RCD: + *proto_status_code = STATUS_ASSOC_NO_ACK_RECEIVED; + break; + case LIM_ACK_RCD_SUCCESS: + *proto_status_code = STATUS_ASSOC_NO_RESP_RECEIVED; + break; + default: + *proto_status_code = STATUS_UNSPECIFIED_FAILURE; + } + } +} + +void lim_process_rrm_sta_stats_rsp_timeout(struct mac_context *mac) +{ + struct pe_session *session; + tSirMacRadioMeasureReport rrm_report; + QDF_STATUS status; + uint8_t index; + tpRRMReq pcurrent_req = NULL; + tRrmRetStatus rrm_status; + + session = pe_find_session_by_session_id(mac, + mac->lim.lim_timers.rrm_sta_stats_resp_timer.sessionId); + if (!session) { + pe_err("Session does not exist for given session id %d", + mac->lim.lim_timers.rrm_sta_stats_resp_timer.sessionId); + rrm_cleanup(mac, mac->rrm.rrmPEContext.rrm_sta_stats.index); + return; + } + + pe_warn("STA STATS RSP timeout vdev_id %d", session->vdev_id); + index = mac->rrm.rrmPEContext.rrm_sta_stats.index; + pcurrent_req = mac->rrm.rrmPEContext.pCurrentReq[index]; + if (!pcurrent_req) { + pe_err("Current request is NULL for index %d", index); + qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats, + sizeof(mac->rrm.rrmPEContext.rrm_sta_stats)); + return; + } + + if (!mac->rrm.rrmPEContext.rrm_sta_stats.rrm_sta_stats_res_count) { + pe_err("response not received for previous req"); + rrm_status = eRRM_INCAPABLE; + goto err; + } + + rrm_report = mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report; + switch (rrm_report.report.statistics_report.group_id) { + /* + * For Counter stats and Mac stats some stats will be received + * via FW and some via DP. So, same handling is required for both + * cases. + */ + case STA_STAT_GROUP_ID_COUNTER_STATS: + case STA_STAT_GROUP_ID_MAC_STATS: + status = wlan_cp_stats_infra_cp_deregister_resp_cb(mac->psoc); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("failed to deregister callback %d", status); + + status = + rrm_send_sta_stats_req( + mac, session, + mac->rrm.rrmPEContext.rrm_sta_stats.peer); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("fail to send stats req"); + rrm_status = eRRM_FAILURE; + goto err; + } + break; + case STA_STAT_GROUP_ID_DELAY_STATS: + /* TOdo: fetch from scan ie */ + break; + } + return; +err: + rrm_process_rrm_sta_stats_request_failure( + mac, session, mac->rrm.rrmPEContext.rrm_sta_stats.peer, + rrm_status, mac->rrm.rrmPEContext.rrm_sta_stats.index); + rrm_cleanup(mac, mac->rrm.rrmPEContext.rrm_sta_stats.index); +} + +void lim_process_sae_auth_timeout(struct mac_context *mac_ctx) +{ + struct pe_session *session; + enum wlan_status_code proto_status_code; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.lim_timers.sae_auth_timer.sessionId); + if (!session) { + pe_err("Session does not exist for given session id"); + return; + } + + pe_warn("SAE auth timeout sessionid %d mlmstate %X SmeState %X", + session->peSessionId, session->limMlmState, + session->limSmeState); + + switch (session->limMlmState) { + case eLIM_MLM_WT_SAE_AUTH_STATE: + lim_fill_status_code(SIR_MAC_MGMT_AUTH, + mac_ctx->auth_ack_status, + &proto_status_code); + /* + * SAE authentication is not completed. Restore from + * auth state. + */ + if ((session->opmode == QDF_STA_MODE) || + (session->opmode == QDF_P2P_CLIENT_MODE)) + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + proto_status_code, session); + break; + default: + /* SAE authentication is timed out in unexpected state */ + pe_err("received unexpected SAE auth timeout in state %X", + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + break; + } +} + +/** + * lim_process_mlm_req_messages() - process mlm request messages + * @mac_ctx: global MAC context + * @msg: mlm request message + * + * This function is called by lim_post_mlm_message(). This + * function handles MLM primitives invoked by SME. + * Depending on the message type, corresponding function will be + * called. + * ASSUMPTIONS: + * 1. Upon receiving Beacon in WT_JOIN_STATE, MLM module invokes + * APIs exposed by Beacon Processing module for setting parameters + * at MAC hardware. + * 2. If attempt to Reassociate with an AP fails, link with current + * AP is restored back. + * + * Return: None + */ +void lim_process_mlm_req_messages(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + switch (msg->type) { + case LIM_MLM_AUTH_REQ: + lim_process_mlm_auth_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_ASSOC_REQ: + lim_process_mlm_assoc_req(mac_ctx, msg->bodyptr); + break; + case LIM_MLM_DISASSOC_REQ: + lim_process_mlm_disassoc_req(mac_ctx, msg->bodyptr); + break; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + lim_process_join_failure_timeout(mac_ctx); + break; + case SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT: + lim_process_periodic_join_probe_req_timer(mac_ctx); + break; + case SIR_LIM_AUTH_FAIL_TIMEOUT: + lim_process_auth_failure_timeout(mac_ctx); + break; + case SIR_LIM_AUTH_RSP_TIMEOUT: + lim_process_auth_rsp_timeout(mac_ctx, msg->bodyval); + break; + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + lim_process_assoc_failure_timeout(mac_ctx, msg->bodyval); + break; + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + lim_process_ft_preauth_rsp_timeout(mac_ctx); + break; + case SIR_LIM_DISASSOC_ACK_TIMEOUT: + lim_process_disassoc_ack_timeout(mac_ctx); + break; + case SIR_LIM_AUTH_RETRY_TIMEOUT: + lim_process_auth_retry_timer(mac_ctx); + break; + case SIR_LIM_AUTH_SAE_TIMEOUT: + lim_process_sae_auth_timeout(mac_ctx); + break; + case SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT: + lim_process_rrm_sta_stats_rsp_timeout(mac_ctx); + break; + case LIM_MLM_TSPEC_REQ: + default: + break; + } /* switch (msg->type) */ +} + +static void update_rmfEnabled(struct bss_params *addbss_param, + struct pe_session *session) +{ + addbss_param->rmfEnabled = session->limRmfEnabled; +} + +/** + * lim_mlm_add_bss() - HAL interface for WMA_ADD_BSS_REQ + * @mac_ctx: global MAC context + * @mlm_start_req: MLM start request + * @session: PE session entry + * + * Package WMA_ADD_BSS_REQ to HAL, in order to start a BSS + * + * Return: eSIR_SME_SUCCESS on success, other error codes otherwise + */ +tSirResultCodes +lim_mlm_add_bss(struct mac_context *mac_ctx, + tLimMlmStartReq *mlm_start_req, struct pe_session *session) +{ + struct vdev_mlme_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev = session->vdev; + uint8_t vdev_id = session->vdev_id; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct bss_params *addbss_param = NULL; + + if (!wma) + return eSIR_SME_INVALID_PARAMETERS; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return eSIR_SME_INVALID_PARAMETERS; + } + + qdf_mem_copy(mlme_obj->mgmt.generic.bssid, mlm_start_req->bssId, + QDF_MAC_ADDR_SIZE); + if (lim_is_session_he_capable(session)) { + lim_decide_he_op(mac_ctx, &mlme_obj->proto.he_ops_info.he_ops, + session); + lim_update_usr_he_cap(mac_ctx, session); + } + +#ifdef WLAN_FEATURE_11BE + if (lim_is_session_eht_capable(session)) { + lim_decide_eht_op(mac_ctx, + &mlme_obj->proto.eht_ops_info.eht_ops, + session); + lim_update_usr_eht_cap(mac_ctx, session); + } +#endif + + /* Set a new state for MLME */ + session->limMlmState = eLIM_MLM_WT_ADD_BSS_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + status = lim_pre_vdev_start(mac_ctx, mlme_obj, session); + if (QDF_IS_STATUS_ERROR(status)) + goto send_fail_resp; + + addbss_param = qdf_mem_malloc(sizeof(struct bss_params)); + if (!addbss_param) + goto send_fail_resp; + + addbss_param->vhtCapable = mlm_start_req->htCapable; + addbss_param->htCapable = session->vhtCapability; + addbss_param->ch_width = session->ch_width; + update_rmfEnabled(addbss_param, session); + addbss_param->staContext.fShortGI20Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_20MHZ, session); + addbss_param->staContext.fShortGI40Mhz = + lim_get_ht_capability(mac_ctx, eHT_SHORT_GI_40MHZ, session); + status = wma_pre_vdev_start_setup(vdev_id, addbss_param); + qdf_mem_free(addbss_param); + if (QDF_IS_STATUS_ERROR(status)) + goto send_fail_resp; + + if (session->wps_state == SAP_WPS_DISABLED) + ucfg_pmo_disable_wakeup_event(wma->psoc, vdev_id, + WOW_PROBE_REQ_WPS_IE_EVENT); + status = wma_vdev_pre_start(vdev_id, false); + if (QDF_IS_STATUS_ERROR(status)) + goto peer_cleanup; + status = vdev_mgr_start_send(mlme_obj, false); + if (QDF_IS_STATUS_ERROR(status)) + goto peer_cleanup; + wma_post_vdev_start_setup(vdev_id); + + return eSIR_SME_SUCCESS; + +peer_cleanup: + wma_remove_bss_peer_on_failure(wma, vdev_id); +send_fail_resp: + wma_send_add_bss_resp(wma, vdev_id, QDF_STATUS_E_FAILURE); + + return eSIR_SME_SUCCESS; +} + +void lim_process_mlm_start_req(struct mac_context *mac_ctx, + tLimMlmStartReq *mlm_start_req) +{ + tLimMlmStartCnf mlm_start_cnf; + struct pe_session *session = NULL; + + if (!mlm_start_req) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + session = pe_find_session_by_session_id(mac_ctx, + mlm_start_req->sessionId); + if (!session) { + pe_err("Session Does not exist for given sessionID"); + mlm_start_cnf.resultCode = eSIR_SME_REFUSED; + goto end; + } + + if (session->limMlmState != eLIM_MLM_IDLE_STATE) { + /* + * Should not have received Start req in states other than idle. + * Return Start confirm with failure code. + */ + pe_err("received unexpected MLM_START_REQ in state %X", + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + mlm_start_cnf.resultCode = + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + goto end; + } + + mlm_start_cnf.resultCode = + lim_mlm_add_bss(mac_ctx, mlm_start_req, session); + +end: + /* Update PE session Id */ + mlm_start_cnf.sessionId = mlm_start_req->sessionId; + + /* + * Respond immediately to LIM, only if MLME has not been + * successfully able to send WMA_ADD_BSS_REQ to HAL. + * Else, LIM_MLM_START_CNF will be sent after receiving + * WMA_ADD_BSS_RSP from HAL + */ + if (eSIR_SME_SUCCESS != mlm_start_cnf.resultCode) + lim_send_start_bss_confirm(mac_ctx, &mlm_start_cnf); +} + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +void +lim_pasn_peer_del_all_resp_vdev_delete_resume(struct mac_context *mac, + struct wlan_objmgr_vdev *vdev) +{ + if (!mac) { + pe_err("Mac ctx is NULL"); + return; + } + + /* + * If PASN peer delete all command to firmware timedout, then + * the PASN peers will not be cleaned up. So cleanup the + * objmgr peers from here and reset the peer delete all in + * progress flag. + */ + if (wifi_pos_get_pasn_peer_count(vdev)) + wifi_pos_cleanup_pasn_peers(mac->psoc, vdev); + + wifi_pos_set_delete_all_peer_in_progress(vdev, false); + + pe_debug("Resume vdev delete"); + if (mac->sme.sme_vdev_del_cb) + mac->sme.sme_vdev_del_cb(MAC_HANDLE(mac), vdev); +} +#endif + +void lim_send_peer_create_resp(struct mac_context *mac, uint8_t vdev_id, + QDF_STATUS qdf_status, uint8_t *peer_mac) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, + vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return; + status = wlan_cm_bss_peer_create_rsp(vdev, qdf_status, + (struct qdf_mac_addr *)peer_mac); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +static void +lim_process_mlm_post_join_suspend_link(struct mac_context *mac_ctx, + struct pe_session *session) +{ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.lim_timers.gLimJoinFailureTimer.sessionId = + session->peSessionId; + + /* + * store the channel switch session_entry in the lim + * global variable + */ + session->channelChangeReasonCode = LIM_SWITCH_CHANNEL_JOIN; + session->pLimMlmReassocRetryReq = NULL; + lim_send_switch_chnl_params(mac_ctx, session); +} + +/** + * lim_process_mlm_join_req() - process mlm join request. + * + * @mac_ctx: Pointer to Global MAC structure + * @mlm_join_req: Pointer to the mlme join request + * + * This function is called to process MLM_JOIN_REQ message + * from SME. It does following: + * 1) Initialize LIM, HAL, DPH + * 2) Configure the BSS for which the JOIN REQ was received + * a) Send WMA_ADD_BSS_REQ to HAL - + * This will identify the BSS that we are interested in + * --AND-- + * Add a STA entry for the AP (in a STA context) + * b) Wait for WMA_ADD_BSS_RSP + * c) Send WMA_ADD_STA_REQ to HAL + * This will add the "local STA" entry to the STA table + * 3) Continue as before, i.e, + * a) Send a PROBE REQ + * b) Wait for PROBE RSP/BEACON containing the SSID that + * we are interested in + * c) Then start an AUTH seq + * d) Followed by the ASSOC seq + * + * @Return: None + */ +void lim_process_mlm_join_req(struct mac_context *mac_ctx, + tLimMlmJoinReq *mlm_join_req) +{ + uint8_t sessionid; + struct pe_session *session; + + sessionid = mlm_join_req->sessionId; + + session = pe_find_session_by_session_id(mac_ctx, sessionid); + if (!session) { + pe_err("SessionId:%d does not exist", sessionid); + return; + } + + session->pLimMlmJoinReq = mlm_join_req; + lim_process_mlm_post_join_suspend_link(mac_ctx, session); +} + +/** + * lim_is_auth_req_expected() - check if auth request is expected + * + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called by lim_process_mlm_auth_req to check + * if auth request is expected. + * + * Return: true if expected and false otherwise + */ +static bool lim_is_auth_req_expected(struct mac_context *mac_ctx, + struct pe_session *session) +{ + bool flag = false; + + /* + * Expect Auth request only when: + * 1. STA joined/associated with a BSS or + * 2. STA is going to authenticate with a unicast + * address and requested authentication algorithm is + * supported. + */ + + flag = (((LIM_IS_STA_ROLE(session) && + ((session->limMlmState == eLIM_MLM_JOINED_STATE) || + (session->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE)))) && + (!IEEE80211_IS_MULTICAST( + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)) && + lim_is_auth_algo_supported(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->authType, session)); + + return flag; +} + +/** + * lim_is_preauth_ctx_exists() - check if preauth context exists + * @mac_ctx: global MAC context + * @session: PE session entry + * @preauth_node_ptr: pointer to preauth node pointer + * + * This function is called by lim_process_mlm_auth_req to check + * if preauth context already exists + * + * Return: true if exists and false otherwise + */ +static bool lim_is_preauth_ctx_exists(struct mac_context *mac_ctx, + struct pe_session *session, + struct tLimPreAuthNode **preauth_node_ptr) +{ + bool fl = false; + struct tLimPreAuthNode *preauth_node; + tpDphHashNode stads; + tSirMacAddr curr_bssid; + + preauth_node = *preauth_node_ptr; + sir_copy_mac_addr(curr_bssid, session->bssId); + stads = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + preauth_node = lim_search_pre_auth_list(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr); + + fl = (((LIM_IS_STA_ROLE(session)) && + (session->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) && + ((stads) && + (mac_ctx->lim.gpLimMlmAuthReq->authType == + stads->mlmStaContext.authType)) && + (!qdf_mem_cmp(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + curr_bssid, sizeof(tSirMacAddr)))) || + ((preauth_node) && + (preauth_node->authType == + mac_ctx->lim.gpLimMlmAuthReq->authType))); + + return fl; +} + +#ifdef WLAN_FEATURE_SAE +static inline +uint32_t lim_get_sae_keymgmt_suite(uint32_t keymgmt) +{ + /* Select the best SAE AKM suite supported */ + if (QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + return WLAN_AKM_FT_SAE_EXT_KEY; + else if (QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) + return WLAN_AKM_SAE_EXT_KEY; + else if (QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) + return WLAN_AKM_FT_SAE; + else if (QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_SAE)) + return WLAN_AKM_SAE; + + pe_err("Invalid SAE Keymgmt suite %d", keymgmt); + return WLAN_AKM_SAE; +} + +QDF_STATUS lim_trigger_auth_req_sae(struct mac_context *mac_ctx, + struct pe_session *session, + struct qdf_mac_addr *peer_bssid) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sir_sae_info *sae_info; + struct scheduler_msg msg = {0}; + uint32_t keymgmt; + + sae_info = qdf_mem_malloc(sizeof(*sae_info)); + if (!sae_info) + return QDF_STATUS_E_FAILURE; + + sae_info->msg_type = eWNI_SME_TRIGGER_SAE; + sae_info->msg_len = sizeof(*sae_info); + sae_info->vdev_id = session->smeSessionId; + + qdf_copy_macaddr(&sae_info->peer_mac_addr, peer_bssid); + keymgmt = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + sae_info->akm = lim_get_sae_keymgmt_suite(keymgmt); + + sae_info->ssid.length = session->ssId.length; + qdf_mem_copy(sae_info->ssid.ssId, + session->ssId.ssId, + session->ssId.length); + + pe_debug("vdev_id %d ssid " QDF_SSID_FMT " " QDF_MAC_ADDR_FMT "akm %d", + sae_info->vdev_id, + QDF_SSID_REF(sae_info->ssid.length, sae_info->ssid.ssId), + QDF_MAC_ADDR_REF(sae_info->peer_mac_addr.bytes), + sae_info->akm); + + msg.type = eWNI_SME_TRIGGER_SAE; + msg.bodyptr = sae_info; + msg.bodyval = 0; + + qdf_status = mac_ctx->lim.sme_msg_callback(mac_ctx, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("SAE failed for AUTH frame"); + qdf_mem_free(sae_info); + return qdf_status; + } + + return qdf_status; +} + +/** + * lim_process_mlm_auth_req_sae() - Handle SAE authentication + * @mac_ctx: global MAC context + * @session: PE session entry + * + * This function is called by lim_process_mlm_auth_req to handle SAE + * authentication. + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_process_mlm_auth_req_sae(struct mac_context *mac_ctx, + struct pe_session *session) +{ + QDF_STATUS qdf_status; + + qdf_status = lim_trigger_auth_req_sae( + mac_ctx, session, + (struct qdf_mac_addr *)session->bssId); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + session->limMlmState = eLIM_MLM_WT_SAE_AUTH_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + mac_ctx->lim.lim_timers.sae_auth_timer.sessionId = + session->peSessionId; + + /* Activate SAE auth timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session->peSessionId, eLIM_AUTH_SAE_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.lim_timers.sae_auth_timer) + != TX_SUCCESS) { + pe_err("could not start Auth SAE timer"); + } + + return qdf_status; +} +#else +static QDF_STATUS lim_process_mlm_auth_req_sae(struct mac_context *mac_ctx, + struct pe_session *session) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + + +/** + * lim_process_mlm_auth_req() - process lim auth request + * + * @mac_ctx: global MAC context + * @msg: MLM auth request message + * + * This function is called to process MLM_AUTH_REQ message from SME + * + * @Return: None + */ +static void lim_process_mlm_auth_req(struct mac_context *mac_ctx, uint32_t *msg) +{ + uint32_t num_preauth_ctx; + tSirMacAddr curr_bssid; + tSirMacAuthFrameBody *auth_frame_body; + tLimMlmAuthCnf mlm_auth_cnf; + struct tLimPreAuthNode *preauth_node = NULL; + uint8_t session_id; + struct pe_session *session; + + if (!msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mac_ctx->lim.gpLimMlmAuthReq = (tLimMlmAuthReq *) msg; + session_id = mac_ctx->lim.gpLimMlmAuthReq->sessionId; + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (!session) { + pe_err("SessionId:%d does not exist", session_id); + qdf_mem_free(msg); + mac_ctx->lim.gpLimMlmAuthReq = NULL; + return; + } + + pe_debug("vdev %d Systemrole %d mlmstate %d from: " QDF_MAC_ADDR_FMT "with authtype %d", + session->vdev_id, GET_LIM_SYSTEM_ROLE(session), + session->limMlmState, + QDF_MAC_ADDR_REF(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr), + mac_ctx->lim.gpLimMlmAuthReq->authType); + + sir_copy_mac_addr(curr_bssid, session->bssId); + + if (!lim_is_auth_req_expected(mac_ctx, session)) { + /* + * Unexpected auth request. + * Return Auth confirm with Invalid parameters code. + */ + pe_err("Auth req not expected is_privacy_enabled %d is_auth_open_system %d auth type %d", + mac_ctx->mlme_cfg->wep_params.is_privacy_enabled, + mac_ctx->mlme_cfg->wep_params.is_auth_open_system, + mac_ctx->lim.gpLimMlmAuthReq->authType); + mlm_auth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + /* + * This is a request for pre-authentication. Check if there exists + * context already for the requested peer OR + * if this request is for the AP we're currently associated with. + * If yes, return auth confirm immediately when + * requested auth type is same as the one used before. + */ + if (lim_is_preauth_ctx_exists(mac_ctx, session, &preauth_node)) { + pe_debug("Already have pre-auth context with peer: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr)); + mlm_auth_cnf.resultCode = (tSirResultCodes)STATUS_SUCCESS; + goto end; + } else { + num_preauth_ctx = mac_ctx->mlme_cfg->lfr.max_num_pre_auth; + if (mac_ctx->lim.gLimNumPreAuthContexts == num_preauth_ctx) { + pe_warn("Number of pre-auth reached max limit"); + /* Return Auth confirm with reject code */ + mlm_auth_cnf.resultCode = + eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED; + goto end; + } + } + + /* Delete pre-auth node if exists */ + if (preauth_node) + lim_delete_pre_auth_node(mac_ctx, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr); + + session->limPrevMlmState = session->limMlmState; + + auth_frame_body = qdf_mem_malloc(sizeof(*auth_frame_body)); + if (!auth_frame_body) { + pe_err("mem alloc failed for auth frame body"); + return; + } + + if ((mac_ctx->lim.gpLimMlmAuthReq->authType == eSIR_AUTH_TYPE_SAE) && + !session->sae_pmk_cached) { + if (lim_process_mlm_auth_req_sae(mac_ctx, session) != + QDF_STATUS_SUCCESS) { + mlm_auth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + qdf_mem_free(auth_frame_body); + goto end; + } else { + pe_debug("lim_process_mlm_auth_req_sae is successful"); + auth_frame_body->authAlgoNumber = eSIR_AUTH_TYPE_SAE; + auth_frame_body->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_1; + auth_frame_body->authStatusCode = 0; + host_log_wlan_auth_info(auth_frame_body->authAlgoNumber, + auth_frame_body->authTransactionSeqNumber, + auth_frame_body->authStatusCode); + + qdf_mem_free(auth_frame_body); + return; + } + } else + session->limMlmState = eLIM_MLM_WT_AUTH_FRAME2_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session->peSessionId, + session->limMlmState)); + + /* Mark auth algo as open when auth type is SAE and PMK is cached */ + if ((mac_ctx->lim.gpLimMlmAuthReq->authType == eSIR_AUTH_TYPE_SAE) && + session->sae_pmk_cached) { + auth_frame_body->authAlgoNumber = eSIR_OPEN_SYSTEM; + } else { + auth_frame_body->authAlgoNumber = + (uint8_t) mac_ctx->lim.gpLimMlmAuthReq->authType; + } + + /* Prepare & send Authentication frame */ + auth_frame_body->authTransactionSeqNumber = SIR_MAC_AUTH_FRAME_1; + auth_frame_body->authStatusCode = 0; + host_log_wlan_auth_info(auth_frame_body->authAlgoNumber, + auth_frame_body->authTransactionSeqNumber, + auth_frame_body->authStatusCode); + mac_ctx->auth_ack_status = LIM_ACK_NOT_RCD; + lim_send_auth_mgmt_frame(mac_ctx, + auth_frame_body, mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + LIM_NO_WEP_IN_FC, session); + + /* assign appropriate session_id to the timer object */ + mac_ctx->lim.lim_timers.gLimAuthFailureTimer.sessionId = session_id; + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer.sessionId = + session_id; + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + /* Activate Auth failure timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session->peSessionId, eLIM_AUTH_FAIL_TIMER)); + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_FAIL_TIMER); + if (tx_timer_activate(&mac_ctx->lim.lim_timers.gLimAuthFailureTimer) + != TX_SUCCESS) { + pe_err("could not start Auth failure timer"); + /* Cleanup as if auth timer expired */ + lim_process_auth_failure_timeout(mac_ctx); + } else { + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session->peSessionId, eLIM_AUTH_RETRY_TIMER)); + /* Activate Auth Retry timer */ + if (tx_timer_activate + (&mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) + pe_err("could not activate Auth Retry timer"); + } + + qdf_mem_free(auth_frame_body); + + return; +end: + qdf_mem_copy((uint8_t *) &mlm_auth_cnf.peerMacAddr, + (uint8_t *) &mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + + mlm_auth_cnf.authType = mac_ctx->lim.gpLimMlmAuthReq->authType; + mlm_auth_cnf.sessionId = session_id; + + qdf_mem_free(mac_ctx->lim.gpLimMlmAuthReq); + mac_ctx->lim.gpLimMlmAuthReq = NULL; + pe_debug("SessionId:%d LimPostSme LIM_MLM_AUTH_CNF", + session_id); + lim_post_sme_message(mac_ctx, LIM_MLM_AUTH_CNF, + (uint32_t *) &mlm_auth_cnf); +} + +static void lim_store_pmfcomeback_timerinfo(struct pe_session *session_entry) +{ + if (session_entry->opmode != QDF_STA_MODE || + !session_entry->limRmfEnabled) + return; + /* + * Store current MLM state in case ASSOC response returns with + * TRY_AGAIN_LATER return code. + */ + session_entry->pmf_retry_timer_info.lim_prev_mlm_state = + session_entry->limPrevMlmState; + session_entry->pmf_retry_timer_info.lim_mlm_state = + session_entry->limMlmState; +} + +/** + * lim_process_mlm_assoc_req() - This function is called to process + * MLM_ASSOC_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_ASSOC_REQ message from SME + * + * @Return None + */ + +static void lim_process_mlm_assoc_req(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + tSirMacAddr curr_bssId; + tLimMlmAssocReq *mlm_assoc_req; + tLimMlmAssocCnf mlm_assoc_cnf; + struct pe_session *session_entry; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_assoc_req = (tLimMlmAssocReq *) msg_buf; + session_entry = pe_find_session_by_session_id(mac_ctx, + mlm_assoc_req->sessionId); + if (!session_entry) { + pe_err("SessionId:%d Session Does not exist", + mlm_assoc_req->sessionId); + qdf_mem_free(mlm_assoc_req); + return; + } + + sir_copy_mac_addr(curr_bssId, session_entry->bssId); + + if (!(!LIM_IS_AP_ROLE(session_entry) && + (session_entry->limMlmState == eLIM_MLM_AUTHENTICATED_STATE || + session_entry->limMlmState == eLIM_MLM_JOINED_STATE) && + (!qdf_mem_cmp(mlm_assoc_req->peerMacAddr, + curr_bssId, sizeof(tSirMacAddr))))) { + /* + * Received Association request either in invalid state + * or to a peer MAC entity whose address is different + * from one that STA is currently joined with or on AP. + * Return Assoc confirm with Invalid parameters code. + */ + pe_warn("received unexpected MLM_ASSOC_CNF in state %X for role=%d, MAC addr= " + QDF_MAC_ADDR_FMT, session_entry->limMlmState, + GET_LIM_SYSTEM_ROLE(session_entry), + QDF_MAC_ADDR_REF(mlm_assoc_req->peerMacAddr)); + lim_print_mlm_state(mac_ctx, LOGW, session_entry->limMlmState); + mlm_assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + mlm_assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + goto end; + } + + /* map the session entry pointer to the AssocFailureTimer */ + mac_ctx->lim.lim_timers.gLimAssocFailureTimer.sessionId = + mlm_assoc_req->sessionId; + lim_store_pmfcomeback_timerinfo(session_entry); + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + pe_debug("vdev %d Sending Assoc_Req Frame, timeout %d msec", + session_entry->vdev_id, + (int)mac_ctx->lim.lim_timers.gLimAssocFailureTimer.initScheduleTimeInMsecs); + + /* Prepare and send Association request frame */ + lim_send_assoc_req_mgmt_frame(mac_ctx, mlm_assoc_req, session_entry); + + /* Start association failure timer */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session_entry->peSessionId, eLIM_ASSOC_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.lim_timers.gLimAssocFailureTimer) + != TX_SUCCESS) { + pe_warn("SessionId:%d couldn't start Assoc failure timer", + session_entry->peSessionId); + /* Cleanup as if assoc timer expired */ + lim_process_assoc_failure_timeout(mac_ctx, LIM_ASSOC); + } + + return; +end: + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = mlm_assoc_req->sessionId; + /* Free up buffer allocated for assoc_req */ + qdf_mem_free(mlm_assoc_req); + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); +} + +/** + * lim_process_mlm_disassoc_req_ntf() - process disassoc request notification + * + * @mac_ctx: global MAC context + * @suspend_status: suspend status + * @msg: mlm message buffer + * + * This function is used to process MLM disassoc notification + * + * Return: None + */ +static void +lim_process_mlm_disassoc_req_ntf(struct mac_context *mac_ctx, + QDF_STATUS suspend_status, uint32_t *msg) +{ + uint16_t aid; + struct qdf_mac_addr curr_bssid; + tpDphHashNode stads; + tLimMlmDisassocReq *mlm_disassocreq; + tLimMlmDisassocCnf mlm_disassoccnf; + struct pe_session *session; + extern bool send_disassoc_frame; + tLimMlmStates mlm_state; + struct disassoc_rsp *sme_disassoc_rsp; + + if (QDF_STATUS_SUCCESS != suspend_status) + pe_err("Suspend Status is not success %X", + suspend_status); + + mlm_disassocreq = (tLimMlmDisassocReq *) msg; + + session = pe_find_session_by_session_id(mac_ctx, + mlm_disassocreq->sessionId); + if (!session) { + pe_err("session does not exist for given sessionId %d", + mlm_disassocreq->sessionId); + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + qdf_mem_copy(curr_bssid.bytes, session->bssId, QDF_MAC_ADDR_SIZE); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + if (!qdf_is_macaddr_equal(&mlm_disassocreq->peer_macaddr, + &curr_bssid)) { + pe_warn("received MLM_DISASSOC_REQ with invalid BSS: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + mlm_disassocreq->peer_macaddr.bytes)); + + /* + * Disassociation response due to host triggered + * disassociation + */ + sme_disassoc_rsp = + qdf_mem_malloc(sizeof(*sme_disassoc_rsp)); + if (!sme_disassoc_rsp) { + qdf_mem_free(mlm_disassocreq); + return; + } + + pe_debug("send disassoc rsp with ret code %d for "QDF_MAC_ADDR_FMT, + eSIR_SME_DEAUTH_STATUS, + QDF_MAC_ADDR_REF( + mlm_disassocreq->peer_macaddr.bytes)); + + sme_disassoc_rsp->messageType = eWNI_SME_DISASSOC_RSP; + sme_disassoc_rsp->length = sizeof(*sme_disassoc_rsp); + sme_disassoc_rsp->sessionId = + mlm_disassocreq->sessionId; + sme_disassoc_rsp->status_code = eSIR_SME_DEAUTH_STATUS; + + qdf_copy_macaddr(&sme_disassoc_rsp->peer_macaddr, + &mlm_disassocreq->peer_macaddr); + msg = (uint32_t *)sme_disassoc_rsp; + + lim_send_sme_disassoc_deauth_ntf(mac_ctx, + QDF_STATUS_SUCCESS, msg); + qdf_mem_free(mlm_disassocreq); + return; + + } + break; + default: + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(session)) */ + + /* + * Check if there exists a context for the peer entity + * to be disassociated with. + */ + stads = dph_lookup_hash_entry(mac_ctx, + mlm_disassocreq->peer_macaddr.bytes, + &aid, &session->dph.dphHashTable); + if (stads) + mlm_state = stads->mlmStaContext.mlmState; + + if ((!stads) || + (stads && + ((mlm_state != eLIM_MLM_LINK_ESTABLISHED_STATE) && + (mlm_state != eLIM_MLM_WT_ASSOC_CNF_STATE) && + (mlm_state != eLIM_MLM_ASSOCIATED_STATE)))) { + /* + * Received LIM_MLM_DISASSOC_REQ for STA that does not + * have context or in some transit state. + */ + pe_warn("Invalid MLM_DISASSOC_REQ, Addr= " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mlm_disassocreq->peer_macaddr.bytes)); + if (stads) + pe_err("Sta MlmState: %d", stads->mlmStaContext.mlmState); + + /* Prepare and Send LIM_MLM_DISASSOC_CNF */ + mlm_disassoccnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + stads->mlmStaContext.disassocReason = mlm_disassocreq->reasonCode; + stads->mlmStaContext.cleanupTrigger = mlm_disassocreq->disassocTrigger; + + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from AP + */ + + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + /* Send Disassociate frame to peer entity */ + if (send_disassoc_frame && (mlm_disassocreq->reasonCode != + REASON_AUTHORIZED_ACCESS_LIMIT_REACHED)) { + if (mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq) { + pe_err("pMlmDisassocReq is not NULL, freeing"); + qdf_mem_free(mac_ctx->lim.limDisassocDeauthCnfReq. + pMlmDisassocReq); + } + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = + mlm_disassocreq; + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and deauth from AP + */ + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + lim_send_disassoc_mgmt_frame(mac_ctx, + mlm_disassocreq->reasonCode, + mlm_disassocreq->peer_macaddr.bytes, session, true); + /* + * Abort Tx so that data frames won't be sent to the AP + * after sending Disassoc. + */ + if (LIM_IS_STA_ROLE(session)) + wma_tx_abort(session->smeSessionId); + } else { + lim_mlo_notify_peer_disconn(session, stads); + /* Disassoc frame is not sent OTA */ + send_disassoc_frame = 1; + /* Receive path cleanup with dummy packet */ + if (QDF_STATUS_SUCCESS != + lim_cleanup_rx_path(mac_ctx, stads, session, true)) { + mlm_disassoccnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(mlm_disassocreq); + } + + return; + +end: + qdf_mem_copy((uint8_t *) &mlm_disassoccnf.peerMacAddr, + (uint8_t *) mlm_disassocreq->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + mlm_disassoccnf.aid = mlm_disassocreq->aid; + mlm_disassoccnf.disassocTrigger = mlm_disassocreq->disassocTrigger; + + /* Update PE session ID */ + mlm_disassoccnf.sessionId = mlm_disassocreq->sessionId; + + /* Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(mlm_disassocreq); + + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_CNF, + (uint32_t *) &mlm_disassoccnf); +} + +/** + * lim_check_disassoc_deauth_ack_pending() - check if deauth is pending + * + * @mac_ctx - global MAC context + * @sta_mac - station MAC + * + * This function checks if diassociation or deauthentication is pending for + * given station MAC address. + * + * Return: true if pending and false otherwise. + */ +bool lim_check_disassoc_deauth_ack_pending(struct mac_context *mac_ctx, + uint8_t *sta_mac) +{ + tLimMlmDisassocReq *disassoc_req; + tLimMlmDeauthReq *deauth_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if ((disassoc_req && (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) || + (deauth_req && (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)))) { + pe_debug("Disassoc/Deauth ack pending"); + return true; + } else { + pe_debug("Disassoc/Deauth Ack not pending"); + return false; + } +} + +/* + * lim_clean_up_disassoc_deauth_req() - cleans up pending disassoc or deauth req + * + * @mac_ctx: mac_ctx + * @sta_mac: sta mac address + * @clean_rx_path: flag to indicate whether to cleanup rx path or not + * + * This function cleans up pending disassoc or deauth req + * + * Return: void + */ +void lim_clean_up_disassoc_deauth_req(struct mac_context *mac_ctx, + uint8_t *sta_mac, bool clean_rx_path) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + tLimMlmDeauthReq *mlm_deauth_req; + + mlm_disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (mlm_disassoc_req && + (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &mlm_disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + if (clean_rx_path) { + lim_process_disassoc_ack_timeout(mac_ctx); + } else { + if (tx_timer_running( + &mac_ctx->lim.lim_timers.gLimDisassocAckTimer)) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DISASSOC_ACK_TIMER); + } + qdf_mem_free(mlm_disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = + NULL; + } + } + + mlm_deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (mlm_deauth_req && + (!qdf_mem_cmp((uint8_t *) sta_mac, + (uint8_t *) &mlm_deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE))) { + if (clean_rx_path) { + lim_process_deauth_ack_timeout(mac_ctx, + mlm_deauth_req->sessionId); + } else { + if (tx_timer_running( + &mac_ctx->lim.lim_timers.gLimDeauthAckTimer)) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DEAUTH_ACK_TIMER); + } + qdf_mem_free(mlm_deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = + NULL; + } + } +} + +/* + * lim_process_disassoc_ack_timeout() - wrapper function around + * lim_send_disassoc_cnf + * + * @mac_ctx: mac_ctx + * + * wrapper function around lim_send_disassoc_cnf + * + * Return: void + */ +void lim_process_disassoc_ack_timeout(struct mac_context *mac_ctx) +{ + lim_send_disassoc_cnf(mac_ctx); +} + +/** + * lim_process_mlm_disassoc_req() - This function is called to process + * MLM_DISASSOC_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DISASSOC_REQ message from SME + * + * @Return: None + */ +static void +lim_process_mlm_disassoc_req(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDisassocReq *mlm_disassoc_req; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_disassoc_req = (tLimMlmDisassocReq *) msg_buf; + lim_process_mlm_disassoc_req_ntf(mac_ctx, QDF_STATUS_SUCCESS, + (uint32_t *) msg_buf); +} + +/** + * lim_process_mlm_deauth_req_ntf() - This function is process mlm deauth req + * notification + * + * @mac_ctx: Pointer to Global MAC structure + * @suspend_status: suspend status + * @msg_buf: A pointer to the MLM message buffer + * + * This function is process mlm deauth req notification + * + * @Return: None + */ +static void +lim_process_mlm_deauth_req_ntf(struct mac_context *mac_ctx, + QDF_STATUS suspend_status, uint32_t *msg_buf) +{ + uint16_t aid, i; + tSirMacAddr curr_bssId; + tpDphHashNode sta_ds; + struct tLimPreAuthNode *auth_node; + tLimMlmDeauthReq *mlm_deauth_req; + tLimMlmDeauthCnf mlm_deauth_cnf; + struct pe_session *session; + struct deauth_rsp *sme_deauth_rsp; + + if (QDF_STATUS_SUCCESS != suspend_status) + pe_err("Suspend Status is not success %X", + suspend_status); + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (!session) { + pe_err("session does not exist for given sessionId %d", + mlm_deauth_req->sessionId); + qdf_mem_free(mlm_deauth_req); + return; + } + sir_copy_mac_addr(curr_bssId, session->bssId); + + switch (GET_LIM_SYSTEM_ROLE(session)) { + case eLIM_STA_ROLE: + switch (session->limMlmState) { + case eLIM_MLM_IDLE_STATE: + /* + * Attempting to Deauthenticate with a pre-authenticated + * peer. Deauthetiate with peer if there exists a + * pre-auth context below. + */ + break; + case eLIM_MLM_AUTHENTICATED_STATE: + case eLIM_MLM_WT_ASSOC_RSP_STATE: + case eLIM_MLM_LINK_ESTABLISHED_STATE: + if (qdf_mem_cmp(mlm_deauth_req->peer_macaddr.bytes, + curr_bssId, QDF_MAC_ADDR_SIZE)) { + pe_err("received MLM_DEAUTH_REQ with invalid BSS id " + "Peer MAC: "QDF_MAC_ADDR_FMT + " CFG BSSID Addr : "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + mlm_deauth_req->peer_macaddr.bytes), + QDF_MAC_ADDR_REF(curr_bssId)); + /* + * Deauthentication response to host triggered + * deauthentication + */ + sme_deauth_rsp = + qdf_mem_malloc(sizeof(*sme_deauth_rsp)); + if (!sme_deauth_rsp) { + qdf_mem_free(mlm_deauth_req); + return; + } + + sme_deauth_rsp->messageType = + eWNI_SME_DEAUTH_RSP; + sme_deauth_rsp->length = + sizeof(*sme_deauth_rsp); + sme_deauth_rsp->status_code = + eSIR_SME_DEAUTH_STATUS; + sme_deauth_rsp->sessionId = + session->vdev_id; + + qdf_mem_copy(sme_deauth_rsp->peer_macaddr.bytes, + mlm_deauth_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + + msg_buf = (uint32_t *)sme_deauth_rsp; + + lim_send_sme_disassoc_deauth_ntf(mac_ctx, + QDF_STATUS_SUCCESS, msg_buf); + qdf_mem_free(mlm_deauth_req); + return; + } + + if ((session->limMlmState == + eLIM_MLM_AUTHENTICATED_STATE) || + (session->limMlmState == + eLIM_MLM_WT_ASSOC_RSP_STATE)) { + /* Send deauth frame to peer entity */ + lim_send_deauth_mgmt_frame(mac_ctx, + mlm_deauth_req->reasonCode, + mlm_deauth_req->peer_macaddr.bytes, + session, false); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, + session->limMlmState)); + goto end; + } + break; + default: + pe_warn("received MLM_DEAUTH_REQ with in state %d for peer " + QDF_MAC_ADDR_FMT, + session->limMlmState, + QDF_MAC_ADDR_REF( + mlm_deauth_req->peer_macaddr.bytes)); + lim_print_mlm_state(mac_ctx, LOGW, + session->limMlmState); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = + eSIR_SME_STA_NOT_AUTHENTICATED; + + goto end; + } + break; + default: + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(session)) */ + + /* + * Check if there exists a context for the peer entity + * to be deauthenticated with. + */ + sta_ds = dph_lookup_hash_entry(mac_ctx, + mlm_deauth_req->peer_macaddr.bytes, + &aid, + &session->dph.dphHashTable); + + if (!sta_ds && (!mac_ctx->mlme_cfg->sap_cfg.is_sap_bcast_deauth_enabled + || (mac_ctx->mlme_cfg->sap_cfg.is_sap_bcast_deauth_enabled && + !qdf_is_macaddr_broadcast(&mlm_deauth_req->peer_macaddr)))) { + /* Check if there exists pre-auth context for this STA */ + auth_node = lim_search_pre_auth_list(mac_ctx, mlm_deauth_req-> + peer_macaddr.bytes); + if (!auth_node) { + /* + * Received DEAUTH REQ for a STA that is neither + * Associated nor Pre-authenticated. Log error, + * Prepare and Send LIM_MLM_DEAUTH_CNF + */ + pe_warn("rcvd MLM_DEAUTH_REQ in mlme state %d STA does not have context, Addr="QDF_MAC_ADDR_FMT, + session->limMlmState, + QDF_MAC_ADDR_REF( + mlm_deauth_req->peer_macaddr.bytes)); + mlm_deauth_cnf.resultCode = + eSIR_SME_STA_NOT_AUTHENTICATED; + } else { + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + /* Delete STA from pre-auth STA list */ + lim_delete_pre_auth_node(mac_ctx, + mlm_deauth_req-> + peer_macaddr.bytes); + /*Send Deauthentication frame to peer entity*/ + lim_send_deauth_mgmt_frame(mac_ctx, + mlm_deauth_req->reasonCode, + mlm_deauth_req-> + peer_macaddr.bytes, + session, false); + } + goto end; + } else if (sta_ds && (sta_ds->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE) && + (sta_ds->mlmStaContext.mlmState != + eLIM_MLM_WT_ASSOC_CNF_STATE)) { + /* + * received MLM_DEAUTH_REQ for STA that either has no + * context or in some transit state + */ + pe_warn("Invalid MLM_DEAUTH_REQ, Addr=" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mlm_deauth_req-> + peer_macaddr.bytes)); + /* Prepare and Send LIM_MLM_DEAUTH_CNF */ + mlm_deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } else if (sta_ds) { + /* sta_ds->mlmStaContext.rxPurgeReq = 1; */ + sta_ds->mlmStaContext.disassocReason = + mlm_deauth_req->reasonCode; + sta_ds->mlmStaContext.cleanupTrigger = + mlm_deauth_req->deauthTrigger; + + /* + * Set state to mlm State to eLIM_MLM_WT_DEL_STA_RSP_STATE + * This is to address the issue of race condition between + * disconnect request from the HDD and disassoc from + * inactivity timer. This will make sure that we will not + * process disassoc if deauth is in progress for the station + * and thus mlmStaContext.cleanupTrigger will not be + * overwritten. + */ + sta_ds->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + } else if (mac_ctx->mlme_cfg->sap_cfg.is_sap_bcast_deauth_enabled && + qdf_is_macaddr_broadcast(&mlm_deauth_req->peer_macaddr)) { + for (i = 0; i < session->dph.dphHashTable.size; i++) { + sta_ds = dph_get_hash_entry(mac_ctx, i, + &session->dph.dphHashTable); + if (!sta_ds) + continue; + + sta_ds->mlmStaContext.disassocReason = + mlm_deauth_req->reasonCode; + sta_ds->mlmStaContext.cleanupTrigger = + mlm_deauth_req->deauthTrigger; + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_WT_DEL_STA_RSP_STATE; + } + } + + if (mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq) { + pe_err("pMlmDeauthReq is not NULL, freeing"); + qdf_mem_free(mac_ctx->lim.limDisassocDeauthCnfReq. + pMlmDeauthReq); + } + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = mlm_deauth_req; + + /* Send Deauthentication frame to peer entity */ + if (mlm_deauth_req->reasonCode != REASON_DISASSOC_DUE_TO_INACTIVITY || + wlan_son_peer_is_kickout_allow(session->vdev, sta_ds->staAddr)) { + lim_send_deauth_mgmt_frame(mac_ctx, mlm_deauth_req->reasonCode, + mlm_deauth_req->peer_macaddr.bytes, + session, true); + } else { + pe_err("peer " QDF_MAC_ADDR_FMT " is in band steering, do not send deauth frame", + QDF_MAC_ADDR_REF(mlm_deauth_req->peer_macaddr.bytes)); + mlm_deauth_cnf.resultCode = eSIR_SME_SUCCESS; + goto end; + } + + return; +end: + qdf_copy_macaddr(&mlm_deauth_cnf.peer_macaddr, + &mlm_deauth_req->peer_macaddr); + mlm_deauth_cnf.deauthTrigger = mlm_deauth_req->deauthTrigger; + mlm_deauth_cnf.aid = mlm_deauth_req->aid; + mlm_deauth_cnf.sessionId = mlm_deauth_req->sessionId; + + /* Free up buffer allocated for mlmDeauthReq */ + qdf_mem_free(mlm_deauth_req); + lim_post_sme_message(mac_ctx, + LIM_MLM_DEAUTH_CNF, (uint32_t *) &mlm_deauth_cnf); +} + +/* + * lim_process_deauth_ack_timeout() - wrapper function around + * lim_send_deauth_cnf + * + * @pMacGlobal: mac_ctx + * @vdev_id: vdev id + * + * wrapper function around lim_send_deauth_cnf + * + * Return: void + */ +void lim_process_deauth_ack_timeout(void *pMacGlobal, uint32_t vdev_id) +{ + struct mac_context *mac_ctx = (struct mac_context *)pMacGlobal; + + pe_debug("Deauth Ack timeout for vdev id %d", vdev_id); + lim_send_deauth_cnf(mac_ctx, vdev_id); +} + +/* + * lim_process_mlm_deauth_req() - This function is called to process + * MLM_DEAUTH_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DEAUTH_REQ message from SME + * + * @Return: None + */ +void lim_process_mlm_deauth_req(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + tLimMlmDeauthReq *mlm_deauth_req; + struct pe_session *session; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mlm_deauth_req = (tLimMlmDeauthReq *) msg_buf; + session = pe_find_session_by_session_id(mac_ctx, + mlm_deauth_req->sessionId); + if (!session) { + pe_err("session does not exist for given sessionId %d", + mlm_deauth_req->sessionId); + qdf_mem_free(mlm_deauth_req); + return; + } + lim_process_mlm_deauth_req_ntf(mac_ctx, QDF_STATUS_SUCCESS, + (uint32_t *) msg_buf); +} + +void lim_process_join_failure_timeout(struct mac_context *mac_ctx) +{ + tLimMlmJoinCnf mlm_join_cnf; + uint32_t len; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + struct pe_session *session; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.lim_timers.gLimJoinFailureTimer.sessionId); + if (!session) { + pe_err("Session Does not exist for given sessionID"); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, + host_log_rssi_pkt_type, LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + session->join_probe_cnt = 0; + + if (session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + len = sizeof(tSirMacAddr); + /* Change timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_JOIN_FAIL_TIMER); + /* Change Periodic probe req timer for future activation */ + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + /* Issue MLM join confirm with timeout reason code */ + pe_err("Join Failure Timeout, In eLIM_MLM_WT_JOIN_BEACON_STATE session:%d " + QDF_MAC_ADDR_FMT, + session->peSessionId, + QDF_MAC_ADDR_REF(session->bssId)); + + mlm_join_cnf.resultCode = eSIR_SME_JOIN_TIMEOUT_RESULT_CODE; + mlm_join_cnf.protStatusCode = STATUS_NO_NETWORK_FOUND; + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + /* Update PE session Id */ + mlm_join_cnf.sessionId = session->peSessionId; + /* Freeup buffer allocated to join request */ + if (session->pLimMlmJoinReq) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *) &mlm_join_cnf); + return; + } else { + pe_warn("received unexpected JOIN failure timeout in state %X", + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + } +} + +/** + * lim_process_periodic_join_probe_req_timer() - This function is called to + * process periodic probe request send during joining process. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process periodic probe request send during + * joining process. + * + * @Return None + */ +static void lim_process_periodic_join_probe_req_timer(struct mac_context *mac_ctx) +{ + struct pe_session *session; + tSirMacSSid ssid; + tSirMacAddr bssid; + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.lim_timers.gLimPeriodicJoinProbeReqTimer.sessionId); + if (!session) { + pe_err("session does not exist for given SessionId: %d", + mac_ctx->lim.lim_timers.gLimPeriodicJoinProbeReqTimer. + sessionId); + return; + } + + if ((true == + tx_timer_running(&mac_ctx->lim.lim_timers.gLimJoinFailureTimer)) + && (session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE)) { + qdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + ssid.length = session->ssId.length; + sir_copy_mac_addr(bssid, + session->pLimMlmJoinReq->bssDescription.bssId); + + lim_send_probe_req_mgmt_frame(mac_ctx, &ssid, bssid, + session->curr_op_freq, + session->self_mac_addr, session->dot11mode, + &session->lim_join_req->addIEScan.length, + session->lim_join_req->addIEScan.addIEdata); + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate( + &mac_ctx->lim.lim_timers.gLimPeriodicJoinProbeReqTimer) != + TX_SUCCESS) { + pe_warn("could not activate Periodic Join req failure timer"); + return; + } + session->join_probe_cnt++; + } +} + +static void lim_send_pre_auth_failure(uint8_t vdev_id, tSirMacAddr bssid) +{ + struct scheduler_msg sch_msg = {0}; + struct wmi_roam_auth_status_params *params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return; + + params->vdev_id = vdev_id; + params->preauth_status = STATUS_UNSPECIFIED_FAILURE; + qdf_mem_copy(params->bssid.bytes, bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_zero(params->pmkid, PMKID_LEN); + + sch_msg.type = WMA_ROAM_PRE_AUTH_STATUS; + sch_msg.bodyptr = params; + pe_debug("Sending pre auth failure for mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params->bssid.bytes)); + + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &sch_msg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Sending preauth status failed"); + qdf_mem_free(params); + } +} + +static void lim_handle_sae_auth_timeout(struct mac_context *mac_ctx, + struct pe_session *session_entry) +{ + struct sae_auth_retry *sae_retry; + tpSirMacMgmtHdr mac_hdr; + + sae_retry = mlme_get_sae_auth_retry(session_entry->vdev); + if (!(sae_retry && sae_retry->sae_auth.ptr)) { + pe_debug("sae auth frame is not buffered vdev id %d", + session_entry->vdev_id); + return; + } + + if (!sae_retry->sae_auth_max_retry) { + if (!wlan_cm_is_vdev_connecting(session_entry->vdev)) { + mac_hdr = (tpSirMacMgmtHdr)sae_retry->sae_auth.ptr; + lim_send_pre_auth_failure(session_entry->vdev_id, + mac_hdr->bssId); + } + goto free_and_deactivate_timer; + } + + pe_debug("Retry sae auth for seq num %d vdev id %d", + mac_ctx->mgmtSeqNum, session_entry->vdev_id); + lim_send_frame(mac_ctx, session_entry->vdev_id, sae_retry->sae_auth.ptr, + sae_retry->sae_auth.len); + sae_retry->sae_auth_max_retry--; + + if (TX_SUCCESS != tx_timer_activate( + &mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer)) + goto free_and_deactivate_timer; + return; + +free_and_deactivate_timer: + lim_sae_auth_cleanup_retry(mac_ctx, session_entry->vdev_id); +} + +/** + * lim_process_auth_retry_timer()- function to Retry Auth when auth timeout + * occurs + * @mac_ctx:pointer to global mac + * + * Return: void + */ +static void lim_process_auth_retry_timer(struct mac_context *mac_ctx) +{ + struct pe_session *session_entry; + tAniAuthType auth_type; + tLimTimers *lim_timers = &mac_ctx->lim.lim_timers; + uint16_t pe_session_id = + lim_timers->g_lim_periodic_auth_retry_timer.sessionId; + + session_entry = pe_find_session_by_session_id(mac_ctx, pe_session_id); + if (!session_entry) { + pe_err("session does not exist for pe_session_id: %d", + pe_session_id); + return; + } + + /** For WPA3 SAE gLimAuthFailureTimer is not running hence + * we don't enter in below "if" block in case of wpa3 sae + */ + if (tx_timer_running(&mac_ctx->lim.lim_timers.gLimAuthFailureTimer) && + (session_entry->limMlmState == eLIM_MLM_WT_AUTH_FRAME2_STATE) && + (LIM_ACK_RCD_SUCCESS != mac_ctx->auth_ack_status)) { + /* + * Send the auth retry only in case we have received ack failure + * else just restart the retry timer. + */ + if (((mac_ctx->auth_ack_status == LIM_ACK_RCD_FAILURE) || + (mac_ctx->auth_ack_status == LIM_TX_FAILED)) && + mac_ctx->lim.gpLimMlmAuthReq) { + tSirMacAuthFrameBody *auth_frame; + + auth_type = mac_ctx->lim.gpLimMlmAuthReq->authType; + + auth_frame = qdf_mem_malloc(sizeof(*auth_frame)); + if (!auth_frame) { + pe_err("malloc failed for auth_frame"); + return; + } + + /* Prepare & send Authentication frame */ + if (session_entry->sae_pmk_cached && + auth_type == eSIR_AUTH_TYPE_SAE) + auth_frame->authAlgoNumber = eSIR_OPEN_SYSTEM; + else + auth_frame->authAlgoNumber = (uint8_t)auth_type; + + auth_frame->authTransactionSeqNumber = + SIR_MAC_AUTH_FRAME_1; + auth_frame->authStatusCode = 0; + pe_debug("Retry Auth"); + lim_increase_fils_sequence_number(session_entry); + lim_send_auth_mgmt_frame(mac_ctx, auth_frame, + mac_ctx->lim.gpLimMlmAuthReq->peerMacAddr, + LIM_NO_WEP_IN_FC, session_entry); + + qdf_mem_free(auth_frame); + } + + lim_deactivate_and_change_timer(mac_ctx, eLIM_AUTH_RETRY_TIMER); + + /* Activate Auth Retry timer */ + if (tx_timer_activate + (&mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) + pe_err("could not activate Auth Retry failure timer"); + + return; + } + + /* Auth retry time out for wpa3 sae */ + lim_handle_sae_auth_timeout(mac_ctx, session_entry); +} /*** lim_process_auth_retry_timer() ***/ + +void lim_process_auth_failure_timeout(struct mac_context *mac_ctx) +{ + /* fetch the pe_session based on the sessionId */ + struct pe_session *session; + uint32_t val; + enum wlan_status_code proto_status_code; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + + session = pe_find_session_by_session_id(mac_ctx, + mac_ctx->lim.lim_timers.gLimAuthFailureTimer.sessionId); + if (!session) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + pe_warn("received AUTH failure timeout in sessionid %d " + "limMlmstate %X limSmeState %X", + session->peSessionId, session->limMlmState, + session->limSmeState); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_TIMEOUT, session, + 0, AUTH_FAILURE_TIMEOUT); + + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, host_log_rssi_pkt_type, + LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + switch (session->limMlmState) { + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + /* + * Requesting STA did not receive next auth frame before Auth + * Failure timeout. Issue MLM auth confirm with timeout reason + * code. Restore default failure timeout + */ + if (QDF_P2P_CLIENT_MODE == session->opmode && + session->defaultAuthFailureTimeout) { + if (cfg_in_range(CFG_AUTH_FAILURE_TIMEOUT, + session->defaultAuthFailureTimeout)) { + val = session->defaultAuthFailureTimeout; + } else { + val = cfg_default(CFG_AUTH_FAILURE_TIMEOUT); + session->defaultAuthFailureTimeout = val; + } + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = val; + } + lim_fill_status_code(SIR_MAC_MGMT_AUTH, + mac_ctx->auth_ack_status, + &proto_status_code); + lim_restore_from_auth_state(mac_ctx, + eSIR_SME_AUTH_TIMEOUT_RESULT_CODE, + proto_status_code, session); + mac_ctx->auth_ack_status = LIM_ACK_NOT_RCD; + break; + default: + /* + * Auth failure timer should not have timed out + * in states other than wt_auth_frame2/4 + */ + pe_err("received unexpected AUTH failure timeout in state %X", + session->limMlmState); + lim_print_mlm_state(mac_ctx, LOGE, session->limMlmState); + break; + } +} + +/** + * lim_process_auth_rsp_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +static void +lim_process_auth_rsp_timeout(struct mac_context *mac_ctx, uint32_t auth_idx) +{ + struct tLimPreAuthNode *auth_node; + struct pe_session *session; + uint8_t session_id; + + auth_node = lim_get_pre_auth_node_from_index(mac_ctx, + &mac_ctx->lim.gLimPreAuthTimerTable, auth_idx); + if (!auth_node) { + pe_warn("Invalid auth node"); + return; + } + + session = pe_find_session_by_bssid(mac_ctx, auth_node->peerMacAddr, + &session_id); + if (!session) { + pe_warn("session does not exist for given BSSID"); + return; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_TIMEOUT, + session, 0, AUTH_RESPONSE_TIMEOUT); +#endif + + if (LIM_IS_AP_ROLE(session)) { + if (auth_node->mlmState != eLIM_MLM_WT_AUTH_FRAME3_STATE) { + pe_err("received AUTH rsp timeout in unexpected " + "state for MAC address: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(auth_node->peerMacAddr)); + } else { + auth_node->mlmState = eLIM_MLM_AUTH_RSP_TIMEOUT_STATE; + auth_node->fTimerStarted = 0; + pe_debug("AUTH rsp timedout for MAC address " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(auth_node->peerMacAddr)); + /* Change timer to reactivate it in future */ + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_AUTH_RSP_TIMER, auth_node->authNodeIdx); + lim_delete_pre_auth_node(mac_ctx, + auth_node->peerMacAddr); + } + } +} + +void lim_process_assoc_failure_timeout(struct mac_context *mac_ctx, + uint32_t msg_type) +{ + + tLimMlmAssocCnf mlm_assoc_cnf; + struct pe_session *session; + enum wlan_status_code proto_status_code; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + host_log_rssi_pkt_type *rssi_log = NULL; +#endif + /* + * to fetch the lim/mlm state based on the session_id, use the + * below pe_session + */ + uint8_t session_id; + + if (msg_type == LIM_ASSOC) + session_id = + mac_ctx->lim.lim_timers.gLimAssocFailureTimer.sessionId; + else + session_id = + mac_ctx->lim.lim_timers.gLimReassocFailureTimer.sessionId; + + session = pe_find_session_by_session_id(mac_ctx, session_id); + if (!session) { + pe_err("Session Does not exist for given sessionID"); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_TIMEOUT, + session, 0, 0); + + WLAN_HOST_DIAG_LOG_ALLOC(rssi_log, + host_log_rssi_pkt_type, + LOG_WLAN_RSSI_UPDATE_C); + if (rssi_log) + rssi_log->rssi = session->rssi; + WLAN_HOST_DIAG_LOG_REPORT(rssi_log); +#endif + + pe_debug("Re/Association Response not received before timeout"); + + /* + * Send Deauth to handle the scenareo where association timeout happened + * when device has missed the assoc resp sent by peer. + * By sending deauth try to clear the session created on peer device. + */ + if (msg_type == LIM_ASSOC && + mlme_get_reconn_after_assoc_timeout_flag(mac_ctx->psoc, + session->vdev_id)) { + pe_debug("vdev: %d skip sending deauth on channel freq %d to BSSID: " + QDF_MAC_ADDR_FMT, session->vdev_id, + session->curr_op_freq, + QDF_MAC_ADDR_REF(session->bssId)); + } else { + pe_debug("vdev: %d try sending deauth on channel freq %d to BSSID: " + QDF_MAC_ADDR_FMT, session->vdev_id, + session->curr_op_freq, + QDF_MAC_ADDR_REF(session->bssId)); + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_UNSPEC_FAILURE, + session->bssId, session, false); + } + if ((LIM_IS_AP_ROLE(session)) || + ((session->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) && + (session->limMlmState != eLIM_MLM_WT_REASSOC_RSP_STATE) && + (session->limMlmState != eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + /* + * Re/Assoc failure timer should not have timedout on AP + * or in a state other than wt_re/assoc_response. + */ + pe_warn("received unexpected REASSOC failure timeout in state %X for role %d", + session->limMlmState, + GET_LIM_SYSTEM_ROLE(session)); + lim_print_mlm_state(mac_ctx, LOGW, session->limMlmState); + return; + } + + if ((msg_type == LIM_ASSOC) || ((msg_type == LIM_REASSOC) + && (session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE))) { + pe_err("(Re)Assoc Failure Timeout occurred"); + session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + /* Change timer for future activations */ + lim_deactivate_and_change_timer(mac_ctx, eLIM_ASSOC_FAIL_TIMER); + lim_stop_pmfcomeback_timer(session); + /* + * Free up buffer allocated for JoinReq held by + * MLM state machine + */ + if (session->pLimMlmJoinReq) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + /* To remove the preauth node in case of fail to associate */ + if (lim_search_pre_auth_list(mac_ctx, session->bssId)) { + pe_debug("delete pre auth node for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(session->bssId)); + lim_delete_pre_auth_node(mac_ctx, + session->bssId); + } + lim_fill_status_code(SIR_MAC_MGMT_ASSOC_RSP, + mac_ctx->assoc_ack_status, + &proto_status_code); + + mlm_assoc_cnf.resultCode = eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE; + mlm_assoc_cnf.protStatusCode = proto_status_code; + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session->peSessionId; + if (msg_type == LIM_ASSOC) { + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); + } else { + /* + * Will come here only in case of 11r, Ese FT + * when reassoc rsp is not received and we + * receive a reassoc - timesout + */ + mlm_assoc_cnf.resultCode = + eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlm_assoc_cnf); + } + } else { + /* + * Restore pre-reassoc req state. + * Set BSSID to currently associated AP address. + */ + session->limMlmState = session->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session->peSessionId, session->limMlmState)); + lim_restore_pre_reassoc_state(mac_ctx, + eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE, + STATUS_UNSPECIFIED_FAILURE, session); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c new file mode 100644 index 0000000000..2d059054ec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c @@ -0,0 +1,3479 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_timer_utils.h" +#include "lim_send_messages.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ft.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_session_utils.h" +#include "rrm_api.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "lim_types.h" +#include "wlan_policy_mgr_api.h" +#include "nan_datapath.h" +#include "wlan_reg_services_api.h" +#include "wma.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_lmac_if_def.h" +#include +#include "wlan_mlo_mgr_sta.h" +#include "utils_mlo.h" +#include "wlan_mlo_mgr_roam.h" +#include "wlan_mlme_api.h" + +#define MAX_SUPPORTED_PEERS_WEP 16 + +void lim_process_mlm_join_cnf(struct mac_context *, uint32_t *); +void lim_process_mlm_auth_cnf(struct mac_context *, uint32_t *); +void lim_process_mlm_assoc_ind(struct mac_context *, uint32_t *); +void lim_process_mlm_assoc_cnf(struct mac_context *, uint32_t *); +void lim_process_mlm_set_keys_cnf(struct mac_context *, uint32_t *); +void lim_process_mlm_disassoc_ind(struct mac_context *, uint32_t *); +void lim_process_mlm_disassoc_cnf(struct mac_context *, uint32_t *); +static void lim_process_mlm_deauth_ind(struct mac_context *, tLimMlmDeauthInd *); +void lim_process_mlm_deauth_cnf(struct mac_context *, uint32_t *); +void lim_process_mlm_purge_sta_ind(struct mac_context *, uint32_t *); + +/** + * lim_process_mlm_rsp_messages() + * + ***FUNCTION: + * This function is called to processes various MLM response (CNF/IND + * messages from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msgType Indicates the MLM message type + * @param *msg_buf A pointer to the MLM message buffer + * + * @return None + */ +void +lim_process_mlm_rsp_messages(struct mac_context *mac, uint32_t msgType, + uint32_t *msg_buf) +{ + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + MTRACE(mac_trace(mac, TRACE_CODE_TX_LIM_MSG, 0, msgType)); + switch (msgType) { + case LIM_MLM_AUTH_CNF: + lim_process_mlm_auth_cnf(mac, msg_buf); + break; + case LIM_MLM_ASSOC_CNF: + lim_process_mlm_assoc_cnf(mac, msg_buf); + break; + case LIM_MLM_START_CNF: + lim_process_mlm_start_cnf(mac, msg_buf); + break; + case LIM_MLM_JOIN_CNF: + lim_process_mlm_join_cnf(mac, msg_buf); + break; + case LIM_MLM_ASSOC_IND: + lim_process_mlm_assoc_ind(mac, msg_buf); + break; + case LIM_MLM_REASSOC_CNF: + lim_process_mlm_reassoc_cnf(mac, msg_buf); + break; + case LIM_MLM_DISASSOC_CNF: + lim_process_mlm_disassoc_cnf(mac, msg_buf); + break; + case LIM_MLM_DISASSOC_IND: + lim_process_mlm_disassoc_ind(mac, msg_buf); + break; + case LIM_MLM_PURGE_STA_IND: + lim_process_mlm_purge_sta_ind(mac, msg_buf); + break; + case LIM_MLM_DEAUTH_CNF: + lim_process_mlm_deauth_cnf(mac, msg_buf); + break; + case LIM_MLM_DEAUTH_IND: + lim_process_mlm_deauth_ind(mac, (tLimMlmDeauthInd *)msg_buf); + break; + case LIM_MLM_SETKEYS_CNF: + lim_process_mlm_set_keys_cnf(mac, msg_buf); + break; + case LIM_MLM_TSPEC_CNF: + break; + default: + break; + } /* switch (msgType) */ + return; +} /*** end lim_process_mlm_rsp_messages() ***/ + +/** + * lim_process_mlm_start_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_START_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msg_buf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_start_cnf(struct mac_context *mac, uint32_t *msg_buf) +{ + struct pe_session *pe_session = NULL; + tLimMlmStartCnf *pLimMlmStartCnf; + uint8_t smesessionId; + uint32_t chan_freq, ch_cfreq1 = 0; + uint8_t send_bcon_ind = false; + enum reg_wifi_band band; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pLimMlmStartCnf = (tLimMlmStartCnf *)msg_buf; + pe_session = pe_find_session_by_session_id(mac, + pLimMlmStartCnf->sessionId); + if (!pe_session) { + pe_err("Session does Not exist with given sessionId"); + return; + } + smesessionId = pe_session->smeSessionId; + + if (pe_session->limSmeState != eLIM_SME_WT_START_BSS_STATE) { + /* + * Should not have received Start confirm from MLM + * in other states. Log error. + */ + pe_err("received unexpected MLM_START_CNF in state %X", + pe_session->limSmeState); + return; + } + if (((tLimMlmStartCnf *)msg_buf)->resultCode == eSIR_SME_SUCCESS) { + + /* + * Update global SME state so that Beacon Generation + * module starts writing Beacon frames into TFP's + * Beacon file register. + */ + pe_session->limSmeState = eLIM_SME_NORMAL_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, pe_session->peSessionId, + pe_session->limSmeState)); + if (pe_session->bssType == eSIR_INFRA_AP_MODE) + pe_debug("*** Started BSS in INFRA AP SIDE***"); + else if (pe_session->bssType == eSIR_NDI_MODE) + pe_debug("*** Started BSS in NDI mode ***"); + else + pe_debug("*** Started BSS ***"); + } else { + /* Start BSS is a failure */ + pe_delete_session(mac, pe_session); + pe_session = NULL; + pe_err("Start BSS Failed"); + } + lim_send_sme_start_bss_rsp(mac, + ((tLimMlmStartCnf *)msg_buf)->resultCode, + pe_session, smesessionId); + if (pe_session && + (((tLimMlmStartCnf *)msg_buf)->resultCode == eSIR_SME_SUCCESS)) { + lim_ndi_mlme_vdev_up_transition(pe_session); + + /* We should start beacon transmission only if the channel + * on which we are operating is non-DFS until the channel + * availability check is done. The PE will receive an explicit + * request from upper layers to start the beacon transmission + */ + chan_freq = pe_session->curr_op_freq; + band = wlan_reg_freq_to_band(pe_session->curr_op_freq); + if (pe_session->ch_center_freq_seg1) + ch_cfreq1 = wlan_reg_chan_band_to_freq( + mac->pdev, + pe_session->ch_center_freq_seg1, + BIT(band)); + + if (!LIM_IS_AP_ROLE(pe_session)) + return; + if (pe_session->ch_width == CH_WIDTH_160MHZ) { + struct ch_params ch_params = {0}; + + if (IS_DOT11_MODE_EHT(pe_session->dot11mode)) + wlan_reg_set_create_punc_bitmap(&ch_params, true); + ch_params.ch_width = pe_session->ch_width; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac->pdev, + chan_freq, + &ch_params, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_DFS) + send_bcon_ind = true; + } else if (pe_session->ch_width == CH_WIDTH_80P80MHZ) { + if ((wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, chan_freq, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_DFS) && + (wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, ch_cfreq1, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_DFS)) + send_bcon_ind = true; + } else { + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (!wlan_reg_is_dfs_for_freq(mac->pdev, chan_freq)) + send_bcon_ind = true; + } + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(pe_session->curr_op_freq)) + send_bcon_ind = true; + + if (send_bcon_ind) { + /* Configure beacon and send beacons to HAL */ + pe_debug("Start Beacon with ssid " QDF_SSID_FMT " Ch freq %d", + QDF_SSID_REF(pe_session->ssId.length, + pe_session->ssId.ssId), + pe_session->curr_op_freq); + lim_send_beacon(mac, pe_session); + lim_enable_obss_detection_config(mac, pe_session); + lim_send_obss_color_collision_cfg(mac, pe_session, + OBSS_COLOR_COLLISION_DETECTION); + } else { + lim_sap_move_to_cac_wait_state(pe_session); + } + } +} + +/*** end lim_process_mlm_start_cnf() ***/ + +/** + * lim_process_mlm_join_cnf() - Processes join confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This Function handles the join confirmation message + * LIM_MLM_JOIN_CNF. + * + * Return: None + */ +void lim_process_mlm_join_cnf(struct mac_context *mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmJoinCnf *join_cnf; + struct pe_session *session_entry; + + join_cnf = (tLimMlmJoinCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + join_cnf->sessionId); + if (!session_entry) { + pe_err("SessionId:%d does not exist", join_cnf->sessionId); + return; + } + + wlan_connectivity_sta_info_event(mac_ctx->psoc, session_entry->vdev_id, + false); + wlan_connectivity_connecting_event(session_entry->vdev, NULL); + + session_entry->join_probe_cnt = 0; + if (session_entry->limSmeState != eLIM_SME_WT_JOIN_STATE) { + pe_err("received unexpected MLM_JOIN_CNF in state %X", + session_entry->limSmeState); + return; + } + + result_code = ((tLimMlmJoinCnf *) msg)->resultCode; + /* Process Join confirm from MLM */ + if (result_code == eSIR_SME_SUCCESS) { + /* Setup hardware upfront */ + if (lim_sta_send_add_bss_pre_assoc(mac_ctx, + session_entry) == + QDF_STATUS_SUCCESS) + return; + else + result_code = eSIR_SME_REFUSED; + } + + /* Join failure */ + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /* Send Join response to Host */ + lim_handle_sme_join_result(mac_ctx, result_code, + ((tLimMlmJoinCnf *) msg)->protStatusCode, session_entry); + return; +} + +/** + * lim_send_mlm_assoc_req() - Association request will be processed + * mac_ctx: Pointer to Global MAC structure + * session_entry: Pointer to session etnry + * + * This function is sends ASSOC request MLM message to MLM State machine. + * ASSOC request packet would be by picking parameters from pe_session + * automatically based on the current state of MLM state machine. + * ASSUMPTIONS: + * this function is called in middle of connection state machine and is + * expected to be called after auth cnf has been received or after ASSOC rsp + * with TRY_AGAIN_LATER was received and required time has elapsed after that. + * + * Return: None + */ + +static void lim_send_mlm_assoc_req(struct mac_context *mac_ctx, + struct pe_session *session_entry) +{ + tLimMlmAssocReq *assoc_req; + uint32_t val; + uint16_t caps; + uint32_t tele_bcn = 0; + tpSirMacCapabilityInfo cap_info; + + if (!session_entry->lim_join_req) { + pe_err("Join Request is NULL"); + /* No need to Assert. JOIN timeout will handle this error */ + return; + } + + assoc_req = qdf_mem_malloc(sizeof(tLimMlmAssocReq)); + if (!assoc_req) { + pe_err("call to AllocateMemory failed for mlmAssocReq"); + return; + } + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(assoc_req->peerMacAddr, session_entry->bssId); + + if (lim_get_capability_info(mac_ctx, &caps, session_entry) + != QDF_STATUS_SUCCESS) + /* Could not get Capabilities value from CFG.*/ + pe_err("could not retrieve Capabilities value"); + + /* Clear spectrum management bit if AP doesn't support it */ + if (!(session_entry->lim_join_req->bssDescription.capabilityInfo & + LIM_SPECTRUM_MANAGEMENT_BIT_MASK)) + /* + * AP doesn't support spectrum management + * clear spectrum management bit + */ + caps &= (~LIM_SPECTRUM_MANAGEMENT_BIT_MASK); + + /* Clear rrm bit if AP doesn't support it */ + if (!(session_entry->lim_join_req->bssDescription.capabilityInfo & + LIM_RRM_BIT_MASK)) + caps &= (~LIM_RRM_BIT_MASK); + + /* Clear short preamble bit if AP does not support it */ + if (!(session_entry->lim_join_req->bssDescription.capabilityInfo & + (LIM_SHORT_PREAMBLE_BIT_MASK))) { + caps &= (~LIM_SHORT_PREAMBLE_BIT_MASK); + pe_debug("Clearing short preamble:no AP support"); + } + + /* Clear immediate block ack bit if AP does not support it */ + if (!(session_entry->lim_join_req->bssDescription.capabilityInfo & + (LIM_IMMEDIATE_BLOCK_ACK_MASK))) { + caps &= (~LIM_IMMEDIATE_BLOCK_ACK_MASK); + pe_debug("Clearing Immed Blk Ack:no AP support"); + } + + assoc_req->capabilityInfo = caps; + cap_info = ((tpSirMacCapabilityInfo) &assoc_req->capabilityInfo); + + /* + * If telescopic beaconing is enabled, set listen interval to + * CFG_TELE_BCN_MAX_LI + */ + tele_bcn = mac_ctx->mlme_cfg->sap_cfg.tele_bcn_wakeup_en; + if (tele_bcn) + val = mac_ctx->mlme_cfg->sap_cfg.tele_bcn_max_li; + else + val = mac_ctx->mlme_cfg->sap_cfg.listen_interval; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_REQ_EVENT, + session_entry, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +#endif + assoc_req->listenInterval = (uint16_t) val; + pe_debug("Listen Interval : %d", assoc_req->listenInterval); + /* Update PE session ID */ + assoc_req->sessionId = session_entry->peSessionId; + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, session_entry->limSmeState)); + lim_post_mlm_message(mac_ctx, LIM_MLM_ASSOC_REQ, + (uint32_t *) assoc_req); +} + +/** + * lim_pmf_comeback_timer_callback() -PMF callback handler + * @context: Timer context + * + * This function is called to processes the PMF comeback + * callback + * + * Return: None + */ +void lim_pmf_comeback_timer_callback(void *context) +{ + struct comeback_timer_info *info = + (struct comeback_timer_info *)context; + struct mac_context *mac_ctx = info->mac; + struct pe_session *session; + + session = pe_find_session_by_vdev_id(mac_ctx, info->vdev_id); + if (!session) { + pe_err("no session found for vdev %d", info->vdev_id); + return; + } + + if (session->limMlmState != eLIM_MLM_WT_ASSOC_RSP_STATE) { + pe_debug("Don't send assoc req, timer expire when limMlmState %d vdev id %d", + session->limMlmState, session->vdev_id); + return; + } + + pe_info("comeback later timer expired. sending MLM ASSOC req for vdev %d, session limMlmState %d, info lim_mlm_state %d", + session->vdev_id, session->limMlmState, info->lim_mlm_state); + + /* set MLM state such that ASSOC REQ packet will be sent out */ + session->limPrevMlmState = info->lim_prev_mlm_state; + session->limMlmState = info->lim_mlm_state; + lim_send_mlm_assoc_req(mac_ctx, session); +} + +/** + * lim_process_mlm_auth_cnf()-Process Auth confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_AUTH_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_auth_cnf(struct mac_context *mac_ctx, uint32_t *msg) +{ + tAniAuthType auth_type, auth_mode; + tLimMlmAuthReq *auth_req; + tLimMlmAuthCnf *auth_cnf; + struct pe_session *session_entry; + + if (!msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + auth_cnf = (tLimMlmAuthCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + auth_cnf->sessionId); + if (!session_entry) { + pe_err("SessionId:%d session doesn't exist", + auth_cnf->sessionId); + return; + } + + if ((session_entry->limSmeState != eLIM_SME_WT_AUTH_STATE && + session_entry->limSmeState != eLIM_SME_WT_PRE_AUTH_STATE) || + LIM_IS_AP_ROLE(session_entry)) { + /** + * Should not have received AUTH confirm + * from MLM in other states or on AP. + * Log error + */ + pe_err("SessionId:%d received MLM_AUTH_CNF in state %X", + session_entry->peSessionId, session_entry->limSmeState); + return; + } + + if (auth_cnf->resultCode == eSIR_SME_SUCCESS) { + if (session_entry->limSmeState == eLIM_SME_WT_AUTH_STATE) { + lim_deactivate_and_change_timer(mac_ctx, + eLIM_ASSOC_FAIL_TIMER); + lim_send_mlm_assoc_req(mac_ctx, session_entry); + } else { + /* + * Successful Pre-authentication. Send + * Pre-auth response to host + */ + session_entry->limSmeState = + session_entry->limPrevSmeState; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } + /* Return for success case */ + return; + } + /* + * Failure case handle: + * Process AUTH confirm from MLM + */ + if (session_entry->limSmeState == eLIM_SME_WT_AUTH_STATE) + auth_type = mac_ctx->mlme_cfg->wep_params.auth_type; + else + auth_type = mac_ctx->lim.gLimPreAuthType; + + if ((auth_type == eSIR_AUTO_SWITCH) && + (auth_cnf->authType == eSIR_SHARED_KEY) && + ((auth_cnf->protStatusCode == STATUS_NOT_SUPPORTED_AUTH_ALG) || + (auth_cnf->resultCode == eSIR_SME_AUTH_TIMEOUT_RESULT_CODE))) { + /* + * When shared authentication fails with reason + * code "13" and authType set to 'auto switch', + * Try with open Authentication + */ + auth_mode = eSIR_OPEN_SYSTEM; + /* Trigger MAC based Authentication */ + auth_req = qdf_mem_malloc(sizeof(tLimMlmAuthReq)); + if (!auth_req) { + pe_err("mlmAuthReq :Memory alloc failed"); + return; + } + if (session_entry->limSmeState == + eLIM_SME_WT_AUTH_STATE) { + sir_copy_mac_addr(auth_req->peerMacAddr, + session_entry->bssId); + } else { + qdf_mem_copy((uint8_t *)&auth_req->peerMacAddr, + (uint8_t *)&mac_ctx->lim.gLimPreAuthPeerAddr, + sizeof(tSirMacAddr)); + } + auth_req->authType = auth_mode; + /* Update PE session Id */ + auth_req->sessionId = auth_cnf->sessionId; + lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, + (uint32_t *) auth_req); + return; + } else { + /* MAC based authentication failure */ + if (session_entry->limSmeState == + eLIM_SME_WT_AUTH_STATE) { + pe_err("Auth Failure occurred"); + session_entry->limSmeState = + eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + session_entry->limMlmState = + eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + + /* WAR for some IOT issue on specific AP: + * STA failed to connect to SAE AP due to incorrect + * password is used. Then AP will still reject the + * authentication even correct password is used unless + * STA send deauth to AP upon authentication failure. + * + * Do not send deauth mgmt frame when already in Deauth + * state while joining. + */ + if (auth_type == eSIR_AUTH_TYPE_SAE && + auth_cnf->resultCode != eSIR_SME_DEAUTH_WHILE_JOIN) { + pe_debug("Send deauth for SAE auth failure"); + lim_send_deauth_mgmt_frame(mac_ctx, + REASON_TIMEDOUT, + auth_cnf->peerMacAddr, + session_entry, false); + } + + /* + * Need to send Join response with + * auth failure to Host. + */ + lim_handle_sme_join_result(mac_ctx, + auth_cnf->resultCode, + auth_cnf->protStatusCode, + session_entry); + } else { + /* + * Pre-authentication failure. + * Send Pre-auth failure response to host + */ + session_entry->limSmeState = + session_entry->limPrevSmeState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } + } +} + +/** + * lim_process_mlm_assoc_cnf() - Process association confirmation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_ASSOC_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_assoc_cnf(struct mac_context *mac_ctx, + uint32_t *msg) +{ + struct pe_session *session_entry; + tLimMlmAssocCnf *assoc_cnf; + + if (!msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + assoc_cnf = (tLimMlmAssocCnf *) msg; + session_entry = pe_find_session_by_session_id(mac_ctx, + assoc_cnf->sessionId); + if (!session_entry) { + pe_err("SessionId:%d Session does not exist", + assoc_cnf->sessionId); + return; + } + if (session_entry->limSmeState != eLIM_SME_WT_ASSOC_STATE || + LIM_IS_AP_ROLE(session_entry)) { + /* + * Should not have received Assocication confirm + * from MLM in other states OR on AP. + * Log error + */ + pe_err("SessionId:%d Received MLM_ASSOC_CNF in state %X", + session_entry->peSessionId, session_entry->limSmeState); + return; + } + if (((tLimMlmAssocCnf *) msg)->resultCode != eSIR_SME_SUCCESS) { + /* Association failure */ + pe_err("SessionId:%d Association failure resultCode: %d limSmeState:%d", + session_entry->peSessionId, + ((tLimMlmAssocCnf *) msg)->resultCode, + session_entry->limSmeState); + + /* If driver gets deauth when its waiting for ADD_STA_RSP then + * we need to do DEL_STA followed by DEL_BSS. So based on below + * reason-code here we decide whether to do only DEL_BSS or + * DEL_STA + DEL_BSS. + */ + if (((tLimMlmAssocCnf *) msg)->resultCode != + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA) + session_entry->limSmeState = + eLIM_SME_JOIN_FAILURE_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, mac_ctx->lim.gLimSmeState)); + /* + * Need to send Join response with + * Association failure to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAssocCnf *) msg)->resultCode, + ((tLimMlmAssocCnf *) msg)->protStatusCode, + session_entry); + } else { + /* Successful Association */ + pe_debug("SessionId:%d Associated with BSS", + session_entry->peSessionId); + session_entry->limSmeState = eLIM_SME_LINK_EST_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /** + * Need to send Join response with + * Association success to Host. + */ + lim_handle_sme_join_result(mac_ctx, + ((tLimMlmAssocCnf *) msg)->resultCode, + ((tLimMlmAssocCnf *) msg)->protStatusCode, + session_entry); + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +lim_fill_sme_assoc_ind_mlo_mld_addr_copy(struct assoc_ind *sme_assoc_ind, + tpLimMlmAssocInd assoc_ind, + uint32_t num_bytes) +{ + qdf_mem_copy(sme_assoc_ind->peer_mld_addr, assoc_ind->peer_mld_addr, + num_bytes); +} + +/** + * lim_update_connected_links() - Update connected mlo links bmap + * @session: Pointer to pe session + * + * Update connected mlo links bmap for all vdev taking + * part in association + * + * Return: None + */ +static void lim_update_connected_links(struct pe_session *session) +{ + mlo_update_connected_links(session->vdev, 1); + mlo_update_connected_links_bmap(session->vdev->mlo_dev_ctx, + session->ml_partner_info); +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +lim_fill_sme_assoc_ind_mlo_mld_addr_copy(struct assoc_ind *sme_assoc_ind, + tpLimMlmAssocInd assoc_ind, + uint32_t num_bytes) +{ +} + +static void lim_update_connected_links(struct pe_session *session) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +void +lim_fill_sme_assoc_ind_params( + struct mac_context *mac_ctx, + tpLimMlmAssocInd assoc_ind, struct assoc_ind *sme_assoc_ind, + struct pe_session *session_entry, bool assoc_req_alloc) +{ + sme_assoc_ind->length = sizeof(struct assoc_ind); + sme_assoc_ind->sessionId = session_entry->smeSessionId; + + /* Required for indicating the frames to upper layer */ + sme_assoc_ind->assocReqLength = assoc_ind->assocReqLength; + if (assoc_req_alloc && assoc_ind->assocReqLength) { + sme_assoc_ind->assocReqPtr = qdf_mem_malloc( + assoc_ind->assocReqLength); + qdf_mem_copy(sme_assoc_ind->assocReqPtr, assoc_ind->assocReqPtr, + assoc_ind->assocReqLength); + } else { + sme_assoc_ind->assocReqPtr = assoc_ind->assocReqPtr; + } + + /* Fill in peerMacAddr */ + qdf_mem_copy(sme_assoc_ind->peerMacAddr, assoc_ind->peerMacAddr, + sizeof(tSirMacAddr)); + lim_fill_sme_assoc_ind_mlo_mld_addr_copy(sme_assoc_ind, assoc_ind, + sizeof(tSirMacAddr)); + /* Fill in aid */ + sme_assoc_ind->aid = assoc_ind->aid; + /* Fill in bssId */ + qdf_mem_copy(sme_assoc_ind->bssId, session_entry->bssId, + sizeof(tSirMacAddr)); + /* Fill in authType */ + sme_assoc_ind->authType = assoc_ind->authType; + /* Fill in rsn_akm_type */ + sme_assoc_ind->akm_type = assoc_ind->akm_type; + /* Fill in ssId */ + qdf_mem_copy((uint8_t *) &sme_assoc_ind->ssId, + (uint8_t *) &(assoc_ind->ssId), assoc_ind->ssId.length + 1); + sme_assoc_ind->rsnIE.length = assoc_ind->rsnIE.length; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->rsnIE.rsnIEdata, + (uint8_t *) &(assoc_ind->rsnIE.rsnIEdata), + assoc_ind->rsnIE.length); + +#ifdef FEATURE_WLAN_WAPI + sme_assoc_ind->wapiIE.length = assoc_ind->wapiIE.length; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->wapiIE.wapiIEdata, + (uint8_t *) &(assoc_ind->wapiIE.wapiIEdata), + assoc_ind->wapiIE.length); +#endif + sme_assoc_ind->addIE.length = assoc_ind->addIE.length; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->addIE.addIEdata, + (uint8_t *) &(assoc_ind->addIE.addIEdata), + assoc_ind->addIE.length); + + /* Copy the new TITAN capabilities */ + sme_assoc_ind->spectrumMgtIndicator = assoc_ind->spectrumMgtIndicator; + if (assoc_ind->spectrumMgtIndicator == true) { + sme_assoc_ind->powerCap.minTxPower = + assoc_ind->powerCap.minTxPower; + sme_assoc_ind->powerCap.maxTxPower = + assoc_ind->powerCap.maxTxPower; + sme_assoc_ind->supportedChannels.numChnl = + assoc_ind->supportedChannels.numChnl; + qdf_mem_copy((uint8_t *) &sme_assoc_ind->supportedChannels. + channelList, + (uint8_t *) &(assoc_ind->supportedChannels.channelList), + assoc_ind->supportedChannels.numChnl); + } + qdf_mem_copy(&sme_assoc_ind->chan_info, &assoc_ind->chan_info, + sizeof(struct oem_channel_info)); + /* Fill in WmmInfo */ + sme_assoc_ind->wmmEnabledSta = assoc_ind->WmmStaInfoPresent; + sme_assoc_ind->ampdu = assoc_ind->ampdu; + sme_assoc_ind->sgi_enable = assoc_ind->sgi_enable; + sme_assoc_ind->tx_stbc = assoc_ind->tx_stbc; + sme_assoc_ind->rx_stbc = assoc_ind->rx_stbc; + sme_assoc_ind->ch_width = assoc_ind->ch_width; + sme_assoc_ind->mode = assoc_ind->mode; + sme_assoc_ind->max_supp_idx = assoc_ind->max_supp_idx; + sme_assoc_ind->max_ext_idx = assoc_ind->max_ext_idx; + sme_assoc_ind->max_mcs_idx = assoc_ind->max_mcs_idx; + sme_assoc_ind->max_real_mcs_idx = assoc_ind->max_real_mcs_idx; + sme_assoc_ind->rx_mcs_map = assoc_ind->rx_mcs_map; + sme_assoc_ind->tx_mcs_map = assoc_ind->tx_mcs_map; + sme_assoc_ind->ecsa_capable = assoc_ind->ecsa_capable; + sme_assoc_ind->ext_cap = assoc_ind->ext_cap; + sme_assoc_ind->supported_band = assoc_ind->supported_band; + + if (assoc_ind->ht_caps.present) + sme_assoc_ind->HTCaps = assoc_ind->ht_caps; + if (assoc_ind->vht_caps.present) + sme_assoc_ind->VHTCaps = assoc_ind->vht_caps; + sme_assoc_ind->capability_info = assoc_ind->capabilityInfo; + sme_assoc_ind->he_caps_present = assoc_ind->he_caps_present; + sme_assoc_ind->eht_caps_present = assoc_ind->eht_caps_present; + sme_assoc_ind->is_sae_authenticated = assoc_ind->is_sae_authenticated; +} + +/** + * lim_process_mlm_assoc_ind() - This function is called to processes MLM_ASSOC_IND + * message from MLM State machine. + * @mac Pointer to Global MAC structure + * @msg_buf A pointer to the MLM message buffer + * + * Return: None + */ +void lim_process_mlm_assoc_ind(struct mac_context *mac, uint32_t *msg_buf) +{ + uint32_t len; + struct scheduler_msg msg = {0}; + struct assoc_ind *pSirSmeAssocInd; + tpDphHashNode sta = 0; + struct pe_session *pe_session; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pe_session = pe_find_session_by_session_id(mac, + ((tpLimMlmAssocInd) msg_buf)->sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given sessionId"); + return; + } + /* / Inform Host of STA association */ + len = sizeof(struct assoc_ind); + pSirSmeAssocInd = qdf_mem_malloc(len); + if (!pSirSmeAssocInd) { + pe_err("call to AllocateMemory failed for eWNI_SME_ASSOC_IND"); + return; + } + + pSirSmeAssocInd->messageType = eWNI_SME_ASSOC_IND; + lim_fill_sme_assoc_ind_params(mac, (tpLimMlmAssocInd)msg_buf, + pSirSmeAssocInd, + pe_session, false); + msg.type = eWNI_SME_ASSOC_IND; + msg.bodyptr = pSirSmeAssocInd; + msg.bodyval = 0; + sta = dph_get_hash_entry(mac, + ((tpLimMlmAssocInd) msg_buf)->aid, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("MLM AssocInd: Station context no longer valid (aid %d)", + ((tpLimMlmAssocInd) msg_buf)->aid); + qdf_mem_free(pSirSmeAssocInd); + + return; + } + + pSirSmeAssocInd->reassocReq = sta->mlmStaContext.subType; + pSirSmeAssocInd->timingMeasCap = sta->timingMeasCap; + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, msg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_ASSOC_IND_EVENT, pe_session, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pe_debug("Create CNF_WAIT_TIMER after received LIM_MLM_ASSOC_IND"); + /* + ** turn on a timer to detect the loss of ASSOC CNF + **/ + lim_activate_cnf_timer(mac, + (uint16_t) ((tpLimMlmAssocInd)msg_buf)->aid, + pe_session); + + mac->lim.sme_msg_callback(mac, &msg); +} /*** end lim_process_mlm_assoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_ind() - This function is called to processes + * MLM_DISASSOC_IND message from MLM State machine. + * @mac: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * Return None + */ +void lim_process_mlm_disassoc_ind(struct mac_context *mac, uint32_t *msg_buf) +{ + tLimMlmDisassocInd *pMlmDisassocInd; + struct pe_session *pe_session; + + pMlmDisassocInd = (tLimMlmDisassocInd *)msg_buf; + pe_session = pe_find_session_by_session_id(mac, + pMlmDisassocInd->sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given sessionID"); + return; + } + switch (GET_LIM_SYSTEM_ROLE(pe_session)) { + case eLIM_STA_ROLE: + pe_session->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, pe_session->peSessionId, + pe_session->limSmeState)); + break; + default: /* eLIM_AP_ROLE */ + pe_debug("*** Peer staId=%d Disassociated ***", + pMlmDisassocInd->aid); + /* Send SME_DISASOC_IND after Polaris cleanup */ + /* (after receiving LIM_MLM_PURGE_STA_IND) */ + break; + } /* end switch (GET_LIM_SYSTEM_ROLE(pe_session)) */ +} /*** end lim_process_mlm_disassoc_ind() ***/ + +/** + * lim_process_mlm_disassoc_cnf() - Processes disassociation + * @mac_ctx: Pointer to Global MAC structure + * @msg: A pointer to the MLM message buffer + * + * This function is called to processes MLM_DISASSOC_CNF + * message from MLM State machine. + * + * Return: None + */ +void lim_process_mlm_disassoc_cnf(struct mac_context *mac_ctx, + uint32_t *msg) +{ + tSirResultCodes result_code; + tLimMlmDisassocCnf *disassoc_cnf; + struct pe_session *session_entry; + struct qdf_mac_addr mld_mac = QDF_MAC_ADDR_ZERO_INIT; + + disassoc_cnf = (tLimMlmDisassocCnf *) msg; + + session_entry = + pe_find_session_by_session_id(mac_ctx, disassoc_cnf->sessionId); + if (!session_entry) { + pe_err("session Does not exist for given session Id"); + return; + } + result_code = (tSirResultCodes)(disassoc_cnf->disassocTrigger == + eLIM_LINK_MONITORING_DISASSOC) ? + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE : + disassoc_cnf->resultCode; + if (LIM_IS_STA_ROLE(session_entry)) { + /* Disassociate Confirm from MLM */ + if ((session_entry->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (session_entry->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + /* + * Should not have received + * Disassociate confirm + * from MLM in other states.Log error + */ + pe_err("received MLM_DISASSOC_CNF in state %X", + session_entry->limSmeState); + return; + } + if (mac_ctx->lim.gLimRspReqd) + mac_ctx->lim.gLimRspReqd = false; + if (disassoc_cnf->disassocTrigger == + eLIM_PROMISCUOUS_MODE_DISASSOC) { + if (disassoc_cnf->resultCode != eSIR_SME_SUCCESS) + session_entry->limSmeState = + session_entry->limPrevSmeState; + else + session_entry->limSmeState = + eLIM_SME_OFFLINE_STATE; + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + } else { + if (disassoc_cnf->resultCode != eSIR_SME_SUCCESS) + session_entry->limSmeState = + session_entry->limPrevSmeState; + else + session_entry->limSmeState = + eLIM_SME_IDLE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + lim_send_sme_disassoc_ntf(mac_ctx, + disassoc_cnf->peerMacAddr, + (uint8_t *)mld_mac.bytes, result_code, + disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry)) { + lim_send_sme_disassoc_ntf( + mac_ctx, disassoc_cnf->peerMacAddr, + disassoc_cnf->peerMldAddr, + result_code, disassoc_cnf->disassocTrigger, + disassoc_cnf->aid, session_entry->smeSessionId, + session_entry); + } +} + +/** + * lim_process_mlm_deauth_ind() - processes MLM_DEAUTH_IND + * @mac_ctx: global mac structure + * @deauth_ind: deauth indication + * + * This function is called to processes MLM_DEAUTH_IND + * message from MLM State machine. + * + * Return: None + */ +static void lim_process_mlm_deauth_ind(struct mac_context *mac_ctx, + tLimMlmDeauthInd *deauth_ind) +{ + struct pe_session *session; + uint8_t session_id; + enum eLimSystemRole role; + + if (!deauth_ind) { + pe_err("deauth_ind is null"); + return; + } + session = pe_find_session_by_bssid(mac_ctx, + deauth_ind->peerMacAddr, + &session_id); + if (!session) { + pe_err("session does not exist for Addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(deauth_ind->peerMacAddr)); + return; + } + role = GET_LIM_SYSTEM_ROLE(session); + if (role == eLIM_STA_ROLE) { + session->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, session->limSmeState)); + } +} + +/** + * lim_process_mlm_deauth_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_DEAUTH_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msg_buf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_deauth_cnf(struct mac_context *mac, uint32_t *msg_buf) +{ + uint16_t aid; + tSirResultCodes resultCode; + tLimMlmDeauthCnf *pMlmDeauthCnf; + struct pe_session *pe_session; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pMlmDeauthCnf = (tLimMlmDeauthCnf *)msg_buf; + pe_session = pe_find_session_by_session_id(mac, + pMlmDeauthCnf->sessionId); + if (!pe_session) { + pe_err("session does not exist for given session Id"); + return; + } + + resultCode = (tSirResultCodes) + (pMlmDeauthCnf->deauthTrigger == + eLIM_LINK_MONITORING_DEAUTH) ? + eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE : + pMlmDeauthCnf->resultCode; + aid = LIM_IS_AP_ROLE(pe_session) ? pMlmDeauthCnf->aid : 1; + if (LIM_IS_STA_ROLE(pe_session)) { + /* Deauth Confirm from MLM */ + if ((pe_session->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && pe_session->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) { + /** + * Should not have received Deauth confirm + * from MLM in other states. + * Log error + */ + pe_err("received unexpected MLM_DEAUTH_CNF in state %X", + pe_session->limSmeState); + return; + } + if (pMlmDeauthCnf->resultCode == eSIR_SME_SUCCESS) { + pe_session->limSmeState = eLIM_SME_IDLE_STATE; + } else + pe_session->limSmeState = + pe_session->limPrevSmeState; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, pe_session->peSessionId, + pe_session->limSmeState)); + + if (mac->lim.gLimRspReqd) + mac->lim.gLimRspReqd = false; + } + /* On STA or on BASIC AP, send SME_DEAUTH_RSP to host */ + lim_send_sme_deauth_ntf(mac, pMlmDeauthCnf->peer_macaddr.bytes, + resultCode, + pMlmDeauthCnf->deauthTrigger, + aid, pe_session->smeSessionId); +} /*** end lim_process_mlm_deauth_cnf() ***/ + +/** + * lim_process_mlm_purge_sta_ind() + * + ***FUNCTION: + * This function is called to processes MLM_PURGE_STA_IND + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msg_buf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_purge_sta_ind(struct mac_context *mac, uint32_t *msg_buf) +{ + tSirResultCodes resultCode; + tpLimMlmPurgeStaInd pMlmPurgeStaInd; + struct pe_session *pe_session; + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pMlmPurgeStaInd = (tpLimMlmPurgeStaInd)msg_buf; + pe_session = pe_find_session_by_session_id(mac, + pMlmPurgeStaInd->sessionId); + if (!pe_session) { + pe_err("session does not exist for given bssId"); + return; + } + /* Purge STA indication from MLM */ + resultCode = (tSirResultCodes) pMlmPurgeStaInd->reasonCode; + switch (GET_LIM_SYSTEM_ROLE(pe_session)) { + case eLIM_STA_ROLE: + default: /* eLIM_AP_ROLE */ + if (LIM_IS_STA_ROLE(pe_session) && + (pe_session->limSmeState != + eLIM_SME_WT_DISASSOC_STATE) && + (pe_session->limSmeState != eLIM_SME_WT_DEAUTH_STATE)) { + /** + * Should not have received + * Purge STA indication + * from MLM in other states. + * Log error + */ + pe_err("received unexpected MLM_PURGE_STA_IND in state %X", + pe_session->limSmeState); + break; + } + pe_debug("*** Cleanup completed for staId=%d ***", + pMlmPurgeStaInd->aid); + if (LIM_IS_STA_ROLE(pe_session)) { + pe_session->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, + pe_session->peSessionId, + pe_session->limSmeState)); + + } + if (pMlmPurgeStaInd->purgeTrigger == eLIM_PEER_ENTITY_DEAUTH) { + lim_send_sme_deauth_ntf(mac, + pMlmPurgeStaInd->peerMacAddr, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + pe_session->smeSessionId); + } else + lim_send_sme_disassoc_ntf(mac, + pMlmPurgeStaInd->peerMacAddr, + (uint8_t *)mld_addr.bytes, + resultCode, + pMlmPurgeStaInd->purgeTrigger, + pMlmPurgeStaInd->aid, + pe_session->smeSessionId, + pe_session); + } /* end switch (GET_LIM_SYSTEM_ROLE(pe_session)) */ +} /*** end lim_process_mlm_purge_sta_ind() ***/ + +/** + * lim_process_mlm_set_keys_cnf() + * + ***FUNCTION: + * This function is called to processes MLM_SETKEYS_CNF + * message from MLM State machine. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msg_buf A pointer to the MLM message buffer + * + * @return None + */ +void lim_process_mlm_set_keys_cnf(struct mac_context *mac, uint32_t *msg_buf) +{ + /* Prepare and send SME_SETCONTEXT_RSP message */ + tLimMlmSetKeysCnf *pMlmSetKeysCnf; + struct pe_session *pe_session; + uint16_t aid; + tpDphHashNode sta_ds = NULL; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + pMlmSetKeysCnf = (tLimMlmSetKeysCnf *)msg_buf; + pe_session = pe_find_session_by_session_id(mac, + pMlmSetKeysCnf->sessionId); + if (!pe_session) { + pe_err("session does not exist for given sessionId %d", + pMlmSetKeysCnf->sessionId); + return; + } + /* if the status is success keys are installed in the + * Firmware so we can set the protection bit + */ + if (eSIR_SME_SUCCESS == pMlmSetKeysCnf->resultCode) { + sta_ds = dph_lookup_hash_entry(mac, + pMlmSetKeysCnf->peer_macaddr.bytes, + &aid, &pe_session->dph.dphHashTable); + if (sta_ds && pMlmSetKeysCnf->key_len_nonzero) + sta_ds->is_key_installed = 1; + } + pe_debug("vdev %d: " QDF_MAC_ADDR_FMT " Status %d key_len_nonzero %d key installed %d", + pe_session->vdev_id, + QDF_MAC_ADDR_REF(pMlmSetKeysCnf->peer_macaddr.bytes), + pMlmSetKeysCnf->resultCode, + pMlmSetKeysCnf->key_len_nonzero, + sta_ds ? sta_ds->is_key_installed : 0); + + lim_send_sme_set_context_rsp(mac, + pMlmSetKeysCnf->peer_macaddr, + 1, + (tSirResultCodes) pMlmSetKeysCnf->resultCode, + pe_session, pe_session->smeSessionId); + + wlan_mlme_update_bw_no_punct(mac->psoc, pe_session->vdev_id); +} /*** end lim_process_mlm_set_keys_cnf() ***/ + +void lim_update_lost_link_rssi(struct mac_context *mac, uint32_t rssi) +{ + if (!mac) { + pe_debug("mac is null"); + return; + } + + mac->lim.bss_rssi = rssi; +} + +void lim_join_result_callback(struct mac_context *mac, + uint8_t vdev_id) +{ + struct pe_session *session; + + session = pe_find_session_by_vdev_id(mac, vdev_id); + if (!session) { + return; + } + lim_send_sme_join_reassoc_rsp(mac, eWNI_SME_JOIN_RSP, + session->result_code, + session->prot_status_code, + session, vdev_id); + pe_delete_session(mac, session); +} + +QDF_STATUS lim_sta_handle_connect_fail(join_params *param) +{ + struct pe_session *session; + struct mac_context *mac_ctx; + tpDphHashNode sta_ds = NULL; + QDF_STATUS status; + + if (!param) { + pe_err("param is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = pe_find_session_by_session_id(mac_ctx, param->pe_session_id); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (sta_ds) { + sta_ds->mlmStaContext.disassocReason = + REASON_UNSPEC_FAILURE; + sta_ds->mlmStaContext.cleanupTrigger = + eLIM_JOIN_FAILURE; + sta_ds->mlmStaContext.resultCode = param->result_code; + sta_ds->mlmStaContext.protStatusCode = param->prot_status_code; + /* + * FIX_ME: at the end of lim_cleanup_rx_path, + * make sure PE is sending eWNI_SME_JOIN_RSP + * to SME + */ + lim_mlo_notify_peer_disconn(session, sta_ds); + lim_cleanup_rx_path(mac_ctx, sta_ds, session, true); + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + /* Cleanup if add bss failed */ + if (session->add_bss_failed) { + dph_delete_hash_entry(mac_ctx, + sta_ds->staAddr, sta_ds->assocId, + &session->dph.dphHashTable); + goto error; + } + return QDF_STATUS_SUCCESS; + } else { + lim_mlo_sta_notify_peer_disconn(session); + } + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + +error: + session->prot_status_code = param->prot_status_code; + session->result_code = param->result_code; + + status = wma_send_vdev_stop(session->smeSessionId); + if (QDF_IS_STATUS_ERROR(status)) + lim_join_result_callback(mac_ctx, session->smeSessionId); + + return status; +} + +/** + * lim_handle_sme_join_result() - Handles sme join result + * @mac_ctx: Pointer to Global MAC structure + * @result_code: Failure code to be sent + * @prot_status_code : Protocol status code + * @session_entry: PE session handle + * + * This function is called to process join/auth/assoc failures + * upon receiving MLM_JOIN/AUTH/ASSOC_CNF with a failure code or + * MLM_ASSOC_CNF with a success code in case of STA role and + * MLM_JOIN_CNF with success in case of STA in IBSS role. + * + * Return: None + */ +void lim_handle_sme_join_result(struct mac_context *mac_ctx, + tSirResultCodes result_code, uint16_t prot_status_code, + struct pe_session *session) +{ + join_params param; + QDF_STATUS status; + + if (!session) { + pe_err("session is NULL"); + return; + } + + if (result_code == eSIR_SME_SUCCESS) { + if (wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + lim_update_connected_links(session); + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_SUCCESS, + 0, NULL); + return lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_JOIN_RSP, + result_code, + prot_status_code, session, + session->smeSessionId); + } + + param.result_code = result_code; + param.prot_status_code = prot_status_code; + param.pe_session_id = session->peSessionId; + + mlme_set_connection_fail(session->vdev, true); + if (wlan_vdev_mlme_get_substate(session->vdev) == + WLAN_VDEV_SS_START_START_PROGRESS) { + mlme_set_vdev_start_failed(session->vdev, true); + status = wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_REQ_FAIL, + sizeof(param), ¶m); + } + else + status = wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_CONNECTION_FAIL, + sizeof(param), ¶m); + + return; +} + + +/** + * lim_process_mlm_add_sta_rsp() + * + ***FUNCTION: + * This function is called to process a WMA_ADD_STA_RSP from HAL. + * Upon receipt of this message from HAL, MLME - + * > Determines the "state" in which this message was received + * > Forwards it to the appropriate callback + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param struct scheduler_msg The MsgQ header, which contains the + * response buffer + * + * @return None + */ +void lim_process_mlm_add_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session) +{ + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deferred flag. */ + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + if (LIM_IS_AP_ROLE(pe_session)) { + lim_process_ap_mlm_add_sta_rsp(mac, limMsgQ, pe_session); + return; + } + lim_process_sta_mlm_add_sta_rsp(mac, limMsgQ, pe_session); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +lim_process_add_sta_rsp_mlo(struct mac_context *mac_ctx, + tLimMlmAssocCnf *mlm_assoc_cnf, + struct pe_session *session_entry) +{ + if (wlan_vdev_mlme_is_mlo_link_vdev(session_entry->vdev)) { + pe_err("sending assoc cnf for MLO link vdev"); + mlm_assoc_cnf->resultCode = eSIR_SME_SUCCESS; + mlm_assoc_cnf->sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *)mlm_assoc_cnf); + } +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +lim_process_add_sta_rsp_mlo(struct mac_context *mac_ctx, + tLimMlmAssocCnf *mlm_assoc_cnf, + struct pe_session *session_entry) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +/** + * lim_process_sta_mlm_add_sta_rsp () - Process add sta response + * @mac_ctx: Pointer to mac context + * @msg: struct scheduler_msg *an Message structure + * @session_entry: PE session entry + * + * Process ADD STA response sent from WMA and posts results + * to SME. + * + * Return: Null + */ + +void lim_process_sta_mlm_add_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg, struct pe_session *session_entry) +{ + tLimMlmAssocCnf mlm_assoc_cnf; + tpDphHashNode sta_ds; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + tpAddStaParams add_sta_params = (tpAddStaParams) msg->bodyptr; + + if (!add_sta_params) { + pe_err("Encountered NULL Pointer"); + return; + } + + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + msg_type = LIM_MLM_REASSOC_CNF; + + if (true == session_entry->fDeauthReceived) { + pe_err("Received Deauth frame in ADD_STA_RESP state"); + if (QDF_STATUS_SUCCESS == add_sta_params->status) { + pe_err("ADD_STA success, send update result code with eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA limMlmState: %d bssid "QDF_MAC_ADDR_FMT, + session_entry->limMlmState, + QDF_MAC_ADDR_REF(add_sta_params->staMac)); + + if (session_entry->limSmeState == + eLIM_SME_WT_REASSOC_STATE) + msg_type = LIM_MLM_REASSOC_CNF; + /* + * We are sending result code + * eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA which + * will trigger proper cleanup (DEL_STA/DEL_BSS both + * required) in either assoc cnf or reassoc cnf handler. + */ + mlm_assoc_cnf.resultCode = + eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA; + mlm_assoc_cnf.protStatusCode = + STATUS_UNSPECIFIED_FAILURE; + goto end; + } + } + + if (QDF_STATUS_SUCCESS == add_sta_params->status) { + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != + session_entry->limMlmState) { + pe_err("Received WMA_ADD_STA_RSP in state %X", + session_entry->limMlmState); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + goto end; + } + /* + * Update the DPH Hash Entry for this STA + * with proper state info + */ + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (sta_ds) { + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + sta_ds->nss = add_sta_params->nss; + } else + pe_warn("Fail to get DPH Hash Entry for AID - %d", + DPH_STA_HASH_INDEX_PEER); + session_entry->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + lim_process_add_sta_rsp_mlo(mac_ctx, &mlm_assoc_cnf, + session_entry); + +#ifdef FEATURE_WLAN_TDLS + /* initialize TDLS peer related data */ + lim_init_tdls_data(mac_ctx, session_entry); +#endif + /* + * Return Assoc confirm to SME with success + * FIXME - Need the correct ASSOC RSP code to + * be passed in here + */ + mlm_assoc_cnf.resultCode = (tSirResultCodes) eSIR_SME_SUCCESS; + lim_send_obss_color_collision_cfg(mac_ctx, session_entry, + OBSS_COLOR_COLLISION_DETECTION); + if (lim_is_session_he_capable(session_entry) && sta_ds) { + if (mac_ctx->usr_cfg_mu_edca_params) { + pe_debug("Send user cfg MU EDCA params to FW"); + lim_send_edca_params(mac_ctx, + mac_ctx->usr_mu_edca_params, + session_entry->vdev_id, true); + } else if (session_entry->mu_edca_present) { + pe_debug("Send MU EDCA params to FW"); + lim_send_edca_params(mac_ctx, + session_entry->ap_mu_edca_params, + session_entry->vdev_id, true); + } + } + } else { + pe_err("ADD_STA failed!"); + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_FT_REASSOC_FAILURE; + else + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + mlm_assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + } +end: + if (msg->bodyptr) { + qdf_mem_free(add_sta_params); + msg->bodyptr = NULL; + } + /* Updating PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, (uint32_t *) &mlm_assoc_cnf); + if (true == session_entry->fDeauthReceived) + session_entry->fDeauthReceived = false; + return; +} + +void lim_process_mlm_del_bss_rsp(struct mac_context *mac, + struct del_bss_resp *vdev_stop_rsp, + struct pe_session *pe_session) +{ + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deferred flag. */ + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + mac->sys.gSysFrameCount[SIR_MAC_MGMT_FRAME][SIR_MAC_MGMT_DEAUTH] = 0; + + if (LIM_IS_AP_ROLE(pe_session) && + (pe_session->statypeForBss == STA_ENTRY_SELF)) { + lim_process_ap_mlm_del_bss_rsp(mac, vdev_stop_rsp, pe_session); + return; + } + lim_process_sta_mlm_del_bss_rsp(mac, vdev_stop_rsp, pe_session); + + if (pe_session->limRmfEnabled) { + if (QDF_STATUS_SUCCESS != + lim_send_exclude_unencrypt_ind(mac, true, pe_session)) { + pe_err("Could not send down Exclude Unencrypted Indication!"); + } + } +} + +void lim_process_sta_mlm_del_bss_rsp(struct mac_context *mac, + struct del_bss_resp *vdev_stop_rsp, + struct pe_session *pe_session) +{ + tpDphHashNode sta = + dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + tSirResultCodes status_code = eSIR_SME_SUCCESS; + + if (!vdev_stop_rsp) { + pe_err("Invalid body pointer in message"); + goto end; + } + if (vdev_stop_rsp->status == QDF_STATUS_SUCCESS) { + if (!sta) { + pe_err("DPH Entry for STA 1 missing"); + status_code = eSIR_SME_REFUSED; + goto end; + } + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != + sta->mlmStaContext.mlmState) { + pe_err("Received unexpected WMA_DEL_BSS_RSP in state %X", + sta->mlmStaContext.mlmState); + status_code = eSIR_SME_REFUSED; + goto end; + } + pe_debug("STA AssocID %d MAC "QDF_MAC_ADDR_FMT, sta->assocId, + QDF_MAC_ADDR_REF(sta->staAddr)); + } else { + pe_err("DEL BSS failed!"); + status_code = eSIR_SME_STOP_BSS_FAILURE; + } +end: + if (!sta) + return; + if ((LIM_IS_STA_ROLE(pe_session)) && + (pe_session->limSmeState != + eLIM_SME_WT_DISASSOC_STATE && + pe_session->limSmeState != + eLIM_SME_WT_DEAUTH_STATE) && + sta->mlmStaContext.cleanupTrigger != + eLIM_JOIN_FAILURE) { + /** The Case where the DelBss is invoked from + * context of other than normal DisAssoc / Deauth OR + * as part of Join Failure. + */ + lim_handle_del_bss_in_re_assoc_context(mac, sta, pe_session); + return; + } + lim_prepare_and_send_del_sta_cnf(mac, sta, status_code, pe_session); + return; +} + +void lim_process_ap_mlm_del_bss_rsp(struct mac_context *mac, + struct del_bss_resp *vdev_stop_rsp, + struct pe_session *pe_session) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + + if (!pe_session) { + pe_err("Session entry passed is NULL"); + if (vdev_stop_rsp) + qdf_mem_free(vdev_stop_rsp); + return; + } + + if (!vdev_stop_rsp) { + pe_err("BSS: DEL_BSS_RSP with no body!"); + rc = eSIR_SME_REFUSED; + goto end; + } + mac->lim.gLimMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, NO_SESSION, + mac->lim.gLimMlmState)); + + if (eLIM_MLM_WT_DEL_BSS_RSP_STATE != pe_session->limMlmState) { + pe_err("Received unexpected WMA_DEL_BSS_RSP in state %X", + pe_session->limMlmState); + rc = eSIR_SME_REFUSED; + goto end; + } + if (vdev_stop_rsp->status != QDF_STATUS_SUCCESS) { + pe_err("BSS: DEL_BSS_RSP error (%x)", vdev_stop_rsp->status); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + /** Softmac may send all the buffered packets right after resuming the transmission hence + * to occupy the medium during non channel occupancy period. So resume the transmission after + * HAL gives back the response. + */ + dph_hash_table_init(mac, &pe_session->dph.dphHashTable); + lim_delete_pre_auth_list(mac); + /* Initialize number of associated stations during cleanup */ + pe_session->gLimNumOfCurrentSTAs = 0; +end: + lim_send_stop_bss_response(mac, pe_session->vdev_id, rc); + pe_delete_session(mac, pe_session); +} + +/** + * lim_process_mlm_del_all_sta_rsp() - Process DEL STA response + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_DEL_ALL_STA_RSP from + * WMA Upon receipt of this message from FW. + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_process_mlm_del_all_sta_rsp(struct vdev_mlme_obj *vdev_mlme, + struct peer_delete_all_response *rsp) +{ + struct pe_session *session_entry; + tSirResultCodes status_code = eSIR_SME_SUCCESS; + struct mac_context *mac_ctx; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + + vdev = vdev_mlme->vdev; + vdev_id = wlan_vdev_get_id(vdev); + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + + session_entry = pe_find_session_by_vdev_id(mac_ctx, + vdev_id); + if (!session_entry) { + pe_err("Session Doesn't exist: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + lim_prepare_and_send_del_all_sta_cnf(mac_ctx, status_code, + session_entry); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_mlm_del_sta_rsp() - Process DEL STA response + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process a WMA_DEL_STA_RSP from + * WMA Upon receipt of this message from FW. + * + * Return: None + */ +void lim_process_mlm_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + /* + * we need to process the deferred message since the + * initiating req. there might be nested request + * in the case of nested request the new request + * initiated from the response will take care of resetting + * the deferred flag. + */ + struct pe_session *session_entry; + tpDeleteStaParams del_sta_params; + + del_sta_params = (tpDeleteStaParams) msg->bodyptr; + if (!del_sta_params) { + pe_err("null pointer del_sta_params msg"); + return; + } + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + + session_entry = pe_find_session_by_session_id(mac_ctx, + del_sta_params->sessionId); + if (!session_entry) { + pe_err("Session Doesn't exist: %d", + del_sta_params->sessionId); + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) { + lim_process_ap_mlm_del_sta_rsp(mac_ctx, msg, + session_entry); + return; + } + if (LIM_IS_NDI_ROLE(session_entry)) { + lim_process_ndi_del_sta_rsp(mac_ctx, msg, session_entry); + return; + } + lim_process_sta_mlm_del_sta_rsp(mac_ctx, msg, session_entry); +} + +/** + * lim_process_ap_mlm_del_sta_rsp() - Process WMA_DEL_STA_RSP + * @mac_ctx: Global pointer to MAC context + * @msg: Received message + * @session_entry: Session entry + * + * Process WMA_DEL_STA_RSP for AP role + * + * Retunrn: None + */ +void lim_process_ap_mlm_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg, + struct pe_session *session_entry) +{ + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) msg->bodyptr; + tpDphHashNode sta_ds; + tSirResultCodes status_code = eSIR_SME_SUCCESS; + + if (!msg->bodyptr) { + pe_err("msg->bodyptr NULL"); + return; + } + + sta_ds = dph_get_hash_entry(mac_ctx, del_sta_params->assocId, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + pe_err("DPH Entry for STA %X missing", + del_sta_params->assocId); + status_code = eSIR_SME_REFUSED; + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + return; + } + pe_debug("Received del Sta Rsp in StaD MlmState: %d", + sta_ds->mlmStaContext.mlmState); + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + pe_warn("DEL STA failed!"); + status_code = eSIR_SME_REFUSED; + goto end; + } + + pe_debug("AP received the DEL_STA_RSP for assocID: %X sta mac " + QDF_MAC_ADDR_FMT, del_sta_params->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + if ((eLIM_MLM_WT_DEL_STA_RSP_STATE != sta_ds->mlmStaContext.mlmState) && + (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + sta_ds->mlmStaContext.mlmState)) { + pe_err("Received unexpected WMA_DEL_STA_RSP in state %s for assocId %d", + lim_mlm_state_str(sta_ds->mlmStaContext.mlmState), + sta_ds->assocId); + status_code = eSIR_SME_REFUSED; + goto end; + } + + pe_debug("Deleted STA AssocID %d Addr "QDF_MAC_ADDR_FMT, + sta_ds->assocId, QDF_MAC_ADDR_REF(sta_ds->staAddr)); + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE == + sta_ds->mlmStaContext.mlmState) { + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + if (lim_add_sta(mac_ctx, sta_ds, false, session_entry) != + QDF_STATUS_SUCCESS) { + pe_err("could not Add STA with assocId: %d", + sta_ds->assocId); + /* + * delete the TS if it has already been added. + * send the response with error status. + */ + if (sta_ds->qos.addtsPresent) { + tpLimTspecInfo pTspecInfo; + + if (QDF_STATUS_SUCCESS == + lim_tspec_find_by_assoc_id(mac_ctx, + sta_ds->assocId, + &sta_ds->qos.addts.tspec, + &mac_ctx->lim.tspecInfo[0], + &pTspecInfo)) { + lim_admit_control_delete_ts(mac_ctx, + sta_ds->assocId, + &sta_ds->qos.addts.tspec.tsinfo, + NULL, + &pTspecInfo->idx); + } + } + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, true, + sta_ds->mlmStaContext.authType, sta_ds->assocId, + true, + STATUS_UNSPECIFIED_FAILURE, + session_entry); + } + return; + } +end: + qdf_mem_free(del_sta_params); + msg->bodyptr = NULL; + if (eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE != + sta_ds->mlmStaContext.mlmState) { + lim_prepare_and_send_del_sta_cnf(mac_ctx, sta_ds, status_code, + session_entry); + } + return; +} + +void lim_process_sta_mlm_del_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session) +{ + tSirResultCodes status_code = eSIR_SME_SUCCESS; + tpDeleteStaParams pDelStaParams = (tpDeleteStaParams) limMsgQ->bodyptr; + + if (!pDelStaParams) { + pe_err("Encountered NULL Pointer"); + goto end; + } + pe_debug("Del STA RSP received. Status: %d AssocID: %d", + pDelStaParams->status, pDelStaParams->assocId); + +#ifdef FEATURE_WLAN_TDLS + if (pDelStaParams->staType == STA_ENTRY_TDLS_PEER) { + pe_debug("TDLS Del STA RSP received"); + lim_process_tdls_del_sta_rsp(mac, limMsgQ, pe_session); + return; + } +#endif + if (QDF_STATUS_SUCCESS != pDelStaParams->status) + pe_err("Del STA failed! Status:%d, proceeding with Del BSS", + pDelStaParams->status); + + if (eLIM_MLM_WT_DEL_STA_RSP_STATE != pe_session->limMlmState) { + pe_err("Received unexpected WDA_DELETE_STA_RSP in state %s", + lim_mlm_state_str(pe_session->limMlmState)); + status_code = eSIR_SME_REFUSED; + goto end; + } + /* + * we must complete all cleanup related to delSta before + * calling limDelBSS. + */ + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + + lim_disconnect_complete(pe_session, true); + + return; +end: + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pDelStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +void lim_process_ap_mlm_add_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session) +{ + tpAddStaParams pAddStaParams = (tpAddStaParams) limMsgQ->bodyptr; + tpDphHashNode sta = NULL; + bool add_sta_rsp_status = true; + + if (!pAddStaParams) { + pe_err("Invalid body pointer in message"); + add_sta_rsp_status = false; + goto end; + } + + sta = + dph_get_hash_entry(mac, pAddStaParams->assocId, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("DPH Entry for STA %X missing", pAddStaParams->assocId); + add_sta_rsp_status = false; + goto end; + } + + if (eLIM_MLM_WT_ADD_STA_RSP_STATE != sta->mlmStaContext.mlmState) { + pe_err("Received unexpected WMA_ADD_STA_RSP in state %X", + sta->mlmStaContext.mlmState); + add_sta_rsp_status = false; + goto end; + } + if (QDF_STATUS_SUCCESS != pAddStaParams->status) { + pe_err("Error! rcvd delSta rsp from HAL with status %d", + pAddStaParams->status); + lim_reject_association(mac, sta->staAddr, + sta->mlmStaContext.subType, + true, sta->mlmStaContext.authType, + sta->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + pe_session); + add_sta_rsp_status = false; + goto end; + } + sta->nss = pAddStaParams->nss; + /* if the AssocRsp frame is not acknowledged, then keep alive timer will take care of the state */ + sta->valid = 1; + sta->mlmStaContext.mlmState = eLIM_MLM_WT_ASSOC_CNF_STATE; + pe_debug("AddStaRsp Success.STA AssocID %d sta mac" QDF_MAC_ADDR_FMT, + sta->assocId, QDF_MAC_ADDR_REF(sta->staAddr)); + + /* For BTAMP-AP, the flow sequence shall be: + * 1) PE sends eWNI_SME_ASSOC_IND to SME + * 2) PE receives eWNI_SME_ASSOC_CNF from SME + * 3) BTAMP-AP sends Re/Association Response to BTAMP-STA + */ + if (!lim_is_mlo_conn(pe_session, sta) && + lim_send_mlm_assoc_ind(mac, sta, pe_session) != + QDF_STATUS_SUCCESS) { + lim_reject_association(mac, sta->staAddr, + sta->mlmStaContext.subType, + true, sta->mlmStaContext.authType, + sta->assocId, true, + STATUS_UNSPECIFIED_FAILURE, + pe_session); + add_sta_rsp_status = false; + } + /* fall though to reclaim the original Add STA Response message */ +end: + if (lim_is_mlo_conn(pe_session, sta)) + lim_ap_mlo_sta_peer_ind(mac, pe_session, sta, + add_sta_rsp_status); + if (0 != limMsgQ->bodyptr) { + qdf_mem_free(pAddStaParams); + limMsgQ->bodyptr = NULL; + } + return; +} + +static void lim_process_ap_mlm_add_bss_rsp(struct mac_context *mac, + struct add_bss_rsp *add_bss_rsp) +{ + tLimMlmStartCnf mlmStartCnf; + struct pe_session *pe_session; + uint8_t isWepEnabled = false; + + if (!add_bss_rsp) { + pe_err("Encountered NULL Pointer"); + return; + } + /* TBD: free the memory before returning, do it for all places where lookup fails. */ + pe_session = pe_find_session_by_vdev_id(mac, add_bss_rsp->vdev_id); + if (!pe_session) { + pe_err("session does not exist for vdev_id %d", + add_bss_rsp->vdev_id); + return; + } + /* Update PE session Id */ + mlmStartCnf.sessionId = pe_session->peSessionId; + if (QDF_IS_STATUS_SUCCESS(add_bss_rsp->status)) { + pe_debug("WMA_ADD_BSS_RSP returned with QDF_STATUS_SUCCESS"); + /* Set MLME state */ + pe_session->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + pe_session->chainMask = add_bss_rsp->chain_mask; + pe_session->smpsMode = add_bss_rsp->smps_mode; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + pe_session->limMlmState)); + pe_session->limSystemRole = eLIM_AP_ROLE; + + sch_edca_profile_update(mac, pe_session); + /* For dual AP case, delete pre auth node if any */ + lim_delete_pre_auth_list(mac); + /* Check the SAP security configuration.If configured to + * WEP then max clients supported is 16 + */ + if (pe_session->privacy) { + if ((pe_session->gStartBssRSNIe.present) + || (pe_session->gStartBssWPAIe.present)) + pe_debug("WPA/WPA2 SAP configuration"); + else { + if (mac->mlme_cfg->sap_cfg.assoc_sta_limit > + MAX_SUPPORTED_PEERS_WEP) { + pe_debug("WEP SAP Configuration"); + mac->mlme_cfg->sap_cfg.assoc_sta_limit + = MAX_SUPPORTED_PEERS_WEP; + isWepEnabled = true; + } + } + } + lim_init_peer_idxpool(mac, pe_session); + + /* Start OLBC timer */ + if (tx_timer_activate + (&mac->lim.lim_timers.gLimUpdateOlbcCacheTimer) != + TX_SUCCESS) { + pe_err("tx_timer_activate failed"); + } + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac, pe_session); + + /* In lim_apply_configuration gLimAssocStaLimit is assigned from cfg. + * So update the value to 16 in case SoftAP is configured in WEP. + */ + if ((mac->mlme_cfg->sap_cfg.assoc_sta_limit > + MAX_SUPPORTED_PEERS_WEP) + && (isWepEnabled)) + mac->mlme_cfg->sap_cfg.assoc_sta_limit = + MAX_SUPPORTED_PEERS_WEP; + mlmStartCnf.resultCode = eSIR_SME_SUCCESS; + } else { + pe_err("WMA_ADD_BSS_REQ failed with status %d", + add_bss_rsp->status); + mlmStartCnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + + lim_send_start_bss_confirm(mac, &mlmStartCnf); +} + +#ifdef WLAN_FEATURE_FILS_SK +/* + * lim_update_fils_auth_mode: API to update Auth mode in case of fils session + * @session_entry: pe session entry + * @auth_mode: auth mode needs to be updated + * + * Return: None + */ +static void lim_update_fils_auth_mode(struct pe_session *session_entry, + tAniAuthType *auth_mode) +{ + if (!session_entry->fils_info) + return; + + if (session_entry->fils_info->is_fils_connection) + *auth_mode = session_entry->fils_info->auth; +} +#else +static void lim_update_fils_auth_mode(struct pe_session *session_entry, + tAniAuthType *auth_mode) +{ } +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static bool +lim_process_mlo_sta_add_bss_skip_auth(tLimMlmAuthReq *pMlmAuthReq, + struct pe_session *session_entry) +{ + if (wlan_vdev_mlme_is_mlo_link_vdev(session_entry->vdev)) { + qdf_mem_free(pMlmAuthReq); + pe_err("vdev is an MLO link, skip Auth"); + return true; + } + + return false; +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline bool +lim_process_mlo_sta_add_bss_skip_auth(tLimMlmAuthReq *pMlmAuthReq, + struct pe_session *session_entry) +{ + return false; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +void lim_process_sta_add_bss_rsp_pre_assoc(struct mac_context *mac_ctx, + struct bss_params *add_bss_params, + struct pe_session *session_entry, + QDF_STATUS status) +{ + tAniAuthType cfgAuthType, authMode; + tLimMlmAuthReq *pMlmAuthReq; + tpDphHashNode sta = NULL; + + if (!add_bss_params) { + pe_err("Invalid body pointer in message"); + goto joinFailure; + } + if (QDF_IS_STATUS_SUCCESS(status)) { + sta = dph_add_hash_entry(mac_ctx, + add_bss_params->staContext.staMac, + DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (!sta) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for STA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + add_bss_params->staContext.staMac)); + goto joinFailure; + } + /* Success, handle below */ + /* Trigger Authentication with AP */ + cfgAuthType = mac_ctx->mlme_cfg->wep_params.auth_type; + + /* Try shared Authentication first */ + if (cfgAuthType == eSIR_AUTO_SWITCH) + authMode = eSIR_SHARED_KEY; + else + authMode = cfgAuthType; + + lim_update_fils_auth_mode(session_entry, &authMode); + /* Trigger MAC based Authentication */ + pMlmAuthReq = qdf_mem_malloc(sizeof(tLimMlmAuthReq)); + if (!pMlmAuthReq) { + pe_err("Allocate Memory failed for mlmAuthReq"); + return; + } + sir_copy_mac_addr(pMlmAuthReq->peerMacAddr, + session_entry->bssId); + + pMlmAuthReq->authType = authMode; + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_JOINED_STATE)); + pMlmAuthReq->sessionId = session_entry->peSessionId; + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_AUTH_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + if (lim_process_mlo_sta_add_bss_skip_auth(pMlmAuthReq, + session_entry)) + return; + lim_post_mlm_message(mac_ctx, LIM_MLM_AUTH_REQ, + (uint32_t *) pMlmAuthReq); + return; + } + +joinFailure: + { + session_entry->limSmeState = eLIM_SME_JOIN_FAILURE_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + + /* Send Join response to Host */ + lim_handle_sme_join_result(mac_ctx, eSIR_SME_REFUSED, + STATUS_UNSPECIFIED_FAILURE, session_entry); + } + +} + +static void lim_process_sta_mlm_add_bss_rsp(struct mac_context *mac_ctx, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *session_entry) +{ + tLimMlmAssocCnf mlm_assoc_cnf; + uint32_t msg_type = LIM_MLM_ASSOC_CNF; + uint32_t sub_type = LIM_ASSOC; + tpDphHashNode sta_ds = NULL; + uint8_t update_sta = false; + + mlm_assoc_cnf.resultCode = eSIR_SME_SUCCESS; + if (eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE == session_entry->limMlmState + || (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState)) { + msg_type = LIM_MLM_REASSOC_CNF; + sub_type = LIM_REASSOC; + /* + * If Reassoc is happening for the same BSS, then + * use the existing StaId and indicate to HAL to update + * the existing STA entry. + * If Reassoc is happening for the new BSS, then + * old BSS and STA entry would have been already deleted + * before PE tries to add BSS for the new BSS, so set the + * updateSta to false and pass INVALID STA Index. + */ + if (sir_compare_mac_addr(session_entry->bssId, + session_entry->limReAssocbssId)) { + update_sta = true; + } + } + + if (QDF_IS_STATUS_SUCCESS(add_bss_rsp->status)) { + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) { + pe_debug("Mlm=%d %d", session_entry->limMlmState, + eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + lim_process_sta_mlm_add_bss_rsp_ft(mac_ctx, + add_bss_rsp, + session_entry); + return; + } + + /* Set MLME state */ + session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + /* to know the session started for self or for peer */ + session_entry->statypeForBss = STA_ENTRY_PEER; + sta_ds = + dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + pe_err("Session:%d Fail to add Self Entry for STA", + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } else { + /* Success, handle below */ + /* Downgrade the EDCA parameters if needed */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, session_entry); + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + session_entry->vdev_id, false); + if (lim_add_sta_self(mac_ctx, update_sta, + session_entry) != QDF_STATUS_SUCCESS) { + /* Add STA context at HW */ + pe_err("Session:%d could not Add Self" + "Entry for the station", + session_entry->peSessionId); + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + } + } + } else { + pe_err("SessionId: %d ADD_BSS failed!", + session_entry->peSessionId); + mlm_assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Return Assoc confirm to SME with failure */ + if (eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE == + session_entry->limMlmState) + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_FT_REASSOC_FAILURE; + else + mlm_assoc_cnf.resultCode = + (tSirResultCodes) eSIR_SME_REFUSED; + session_entry->add_bss_failed = true; + } + + if (mlm_assoc_cnf.resultCode != eSIR_SME_SUCCESS) { + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + /* Update PE session Id */ + mlm_assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, msg_type, + (uint32_t *) &mlm_assoc_cnf); + } +} + +void lim_handle_add_bss_rsp(struct mac_context *mac_ctx, + struct add_bss_rsp *add_bss_rsp) +{ + tLimMlmStartCnf mlm_start_cnf; + struct pe_session *session_entry; + enum bss_type bss_type; + struct wlan_lmac_if_reg_tx_ops *tx_ops; + struct vdev_mlme_obj *mlme_obj; + struct pe_session *sta_session; + + if (!add_bss_rsp) { + pe_err("add_bss_rsp is NULL"); + return; + } + + /* + * we need to process the deferred message since the + * initiating req.there might be nested request. + * in the case of nested request the new request initiated + * from the response will take care of resetting the deferred + * flag. + */ + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + /* Validate SME/LIM/MLME state */ + session_entry = pe_find_session_by_vdev_id(mac_ctx, + add_bss_rsp->vdev_id); + if (!session_entry) { + pe_err("vdev id:%d Session Doesn't exist", + add_bss_rsp->vdev_id); + goto err; + } + if (LIM_IS_AP_ROLE(session_entry)) { + if (wlan_reg_is_ext_tpc_supported(mac_ctx->psoc)) { + mlme_obj = + wlan_vdev_mlme_get_cmpt_obj(session_entry->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + goto err; + } + tx_ops = wlan_reg_get_tx_ops(mac_ctx->psoc); + + lim_calculate_tpc(mac_ctx, session_entry); + + if (tx_ops->set_tpc_power) + tx_ops->set_tpc_power(mac_ctx->psoc, + session_entry->vdev_id, + &mlme_obj->reg_tpc_obj); + if (wlan_get_tpc_update_required_for_sta( + session_entry->vdev)) { + sta_session = + lim_get_concurrent_session(mac_ctx, + session_entry->vdev_id, + session_entry->opmode); + if (!sta_session) { + pe_err("TPC update required is set, but concurrent session doesn't exist"); + wlan_set_tpc_update_required_for_sta( + session_entry->vdev, + false); + } else { + lim_update_tx_power(mac_ctx, + session_entry, sta_session, + false); + } + } + } + } + bss_type = session_entry->bssType; + /* update PE session Id */ + mlm_start_cnf.sessionId = session_entry->peSessionId; + if (eSIR_NDI_MODE == session_entry->bssType) { + lim_process_ndi_mlm_add_bss_rsp(mac_ctx, add_bss_rsp, + session_entry); + } else { + if (eLIM_SME_WT_START_BSS_STATE == session_entry->limSmeState) { + if (eLIM_MLM_WT_ADD_BSS_RSP_STATE != + session_entry->limMlmState) { + pe_err("SessionId:%d Received " + " WMA_ADD_BSS_RSP in state %X", + session_entry->peSessionId, + session_entry->limMlmState); + mlm_start_cnf.resultCode = + eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + + lim_send_start_bss_confirm(mac_ctx, &mlm_start_cnf); + } + lim_process_ap_mlm_add_bss_rsp(mac_ctx, + add_bss_rsp); + } else { + /* Called while processing assoc response */ + lim_process_sta_mlm_add_bss_rsp(mac_ctx, add_bss_rsp, + session_entry); + } + } + + if (session_entry->limRmfEnabled) { + if (QDF_STATUS_SUCCESS != + lim_send_exclude_unencrypt_ind(mac_ctx, false, + session_entry)) { + pe_err("Failed to send Exclude Unencrypted Ind"); + } + } +err: + qdf_mem_free(add_bss_rsp); +} + +void lim_process_mlm_update_hidden_ssid_rsp(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + struct pe_session *session_entry; + struct scheduler_msg message = {0}; + QDF_STATUS status; + + pe_debug("hidden ssid resp for vdev_id:%d ", vdev_id); + + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session_entry) { + pe_err("vdev_id:%d Session Doesn't exist", + vdev_id); + return; + } + /* Update beacon */ + sch_set_fixed_beacon_fields(mac_ctx, session_entry); + lim_send_beacon(mac_ctx, session_entry); + + message.type = eWNI_SME_HIDDEN_SSID_RESTART_RSP; + message.bodyval = vdev_id; + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &message); + + if (status != QDF_STATUS_SUCCESS) + pe_err("Failed to post message %u", status); +} + +/** + * lim_process_mlm_set_sta_key_rsp() - Process STA key response + * + * @mac_ctx: Pointer to Global MAC structure + * @msg: The MsgQ header, which contains the response buffer + * + * This function is called to process the following two + * messages from HAL: + * 1) WMA_SET_BSSKEY_RSP + * 2) WMA_SET_STAKEY_RSP + * 3) WMA_SET_STA_BCASTKEY_RSP + * Upon receipt of this message from HAL, + * MLME - + * > Determines the "state" in which this message was received + * > Forwards it to the appropriate callback + * LOGIC: + * WMA_SET_BSSKEY_RSP/WMA_SET_STAKEY_RSP can be + * received by MLME while in the following state: + * MLME state = eLIM_MLM_WT_SET_BSS_KEY_STATE --OR-- + * MLME state = eLIM_MLM_WT_SET_STA_KEY_STATE --OR-- + * MLME state = eLIM_MLM_WT_SET_STA_BCASTKEY_STATE + * Based on this state, this API will determine where to + * route the message to + * Assumption: + * ONLY the MLME state is being taken into account for now. + * This is because, it appears that the handling of the + * SETKEYS REQ is handled symmetrically on both the AP & STA + * + * Return: None + */ +void lim_process_mlm_set_sta_key_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct sLimMlmSetKeysCnf mlm_set_key_cnf; + uint8_t session_id = 0; + uint8_t vdev_id; + struct pe_session *session_entry; + uint16_t key_len; + uint16_t result_status; + tSetStaKeyParams *set_key_params; + tLimMlmStates mlm_state = eLIM_MLM_OFFLINE_STATE; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + qdf_mem_zero((void *)&mlm_set_key_cnf, sizeof(tLimMlmSetKeysCnf)); + if (!msg->bodyptr) { + pe_err("msg bodyptr is NULL"); + return; + } + set_key_params = msg->bodyptr; + vdev_id = set_key_params->vdev_id; + session_id = vdev_id; + if (wlan_get_opmode_from_vdev_id(mac_ctx->pdev, + vdev_id) != QDF_NAN_DISC_MODE) { + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session_entry) { + pe_err("session does not exist for given vdev_id %d", + vdev_id); + qdf_mem_zero(msg->bodyptr, sizeof(*set_key_params)); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + lim_send_sme_set_context_rsp(mac_ctx, + mlm_set_key_cnf.peer_macaddr, + 0, + eSIR_SME_INVALID_SESSION, + NULL, vdev_id); + return; + } + session_id = session_entry->peSessionId; + mlm_state = session_entry->limMlmState; + } + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, session_id, mlm_state)); + result_status = set_key_params->status; + key_len = set_key_params->key_len; + pe_debug("PE session ID %d, vdev_id %d key_len %d status %d", + session_id, vdev_id, key_len, result_status); + + if (result_status == eSIR_SME_SUCCESS && key_len) + mlm_set_key_cnf.key_len_nonzero = true; + else + mlm_set_key_cnf.key_len_nonzero = false; + + qdf_copy_macaddr(&mlm_set_key_cnf.peer_macaddr, + &set_key_params->macaddr); + mlm_set_key_cnf.sessionId = session_id; + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &mlm_set_key_cnf); + + qdf_mem_zero(msg->bodyptr, sizeof(*set_key_params)); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; +} + +/** + * lim_process_mlm_set_bss_key_rsp() - handles BSS key + * + * @mac_ctx: A pointer to Global MAC structure + * @msg: Message from SME + * + * This function processes BSS key response and updates + * PE status accordingly. + * + * Return: NULL + */ +void lim_process_mlm_set_bss_key_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct sLimMlmSetKeysCnf set_key_cnf; + uint16_t result_status; + uint8_t session_id = 0; + uint8_t vdev_id; + struct pe_session *session_entry; + uint16_t key_len; + tSetBssKeyParams *bss_key; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + qdf_mem_zero((void *)&set_key_cnf, sizeof(tLimMlmSetKeysCnf)); + if (!msg->bodyptr) { + pe_err("msg bodyptr is null"); + return; + } + bss_key = msg->bodyptr; + vdev_id = bss_key->vdev_id; + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session_entry) { + pe_err("session does not exist for vdev_id %d", vdev_id); + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + lim_send_sme_set_context_rsp(mac_ctx, set_key_cnf.peer_macaddr, + 0, eSIR_SME_INVALID_SESSION, NULL, + vdev_id); + return; + } + + session_id = session_entry->peSessionId; + result_status = (uint16_t)bss_key->status; + key_len = bss_key->key_len; + pe_debug("vdev %d (pe %d) limMlmState %d status %d key_len %d", + vdev_id, session_id, session_entry->limMlmState, + result_status, key_len); + + if (result_status == eSIR_SME_SUCCESS && key_len) + set_key_cnf.key_len_nonzero = true; + else + set_key_cnf.key_len_nonzero = false; + + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_MLM_STATE, session_entry->peSessionId, + session_entry->limMlmState)); + set_key_cnf.sessionId = session_id; + + /* Prepare and Send LIM_MLM_SETKEYS_CNF */ + qdf_copy_macaddr(&set_key_cnf.peer_macaddr, &bss_key->macaddr); + qdf_mem_zero(msg->bodyptr, sizeof(tSetBssKeyParams)); + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + + lim_post_sme_message(mac_ctx, LIM_MLM_SETKEYS_CNF, + (uint32_t *) &set_key_cnf); +} + +/** + * lim_process_switch_channel_re_assoc_req() + * + ***FUNCTION: + * This function is called to send the reassoc req mgmt frame after the + * switchChannelRsp message is received from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure. + * @param pe_session - session related information. + * @param status - channel switch success/failure. + * + * @return None + */ +static void lim_process_switch_channel_re_assoc_req(struct mac_context *mac, + struct pe_session *pe_session, + QDF_STATUS status) +{ + tLimMlmReassocCnf mlmReassocCnf; + tLimMlmReassocReq *pMlmReassocReq; + + pMlmReassocReq = + (tLimMlmReassocReq *) (pe_session->pLimMlmReassocReq); + if (!pMlmReassocReq) { + pe_err("pLimMlmReassocReq does not exist for given switchChanSession"); + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Change channel failed!!"); + mlmReassocCnf.resultCode = eSIR_SME_CHANNEL_SWITCH_FAIL; + goto end; + } + /* / Start reassociation failure timer */ + MTRACE(mac_trace + (mac, TRACE_CODE_TIMER_ACTIVATE, pe_session->peSessionId, + eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&mac->lim.lim_timers.gLimReassocFailureTimer) + != TX_SUCCESS) { + pe_err("could not start Reassociation failure timer"); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* / Prepare and send Reassociation request frame */ + lim_send_reassoc_req_mgmt_frame(mac, pMlmReassocReq, pe_session); + return; +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq) { + /* Update PE session Id */ + mlmReassocCnf.sessionId = pMlmReassocReq->sessionId; + qdf_mem_free(pMlmReassocReq); + pe_session->pLimMlmReassocReq = NULL; + } else { + mlmReassocCnf.sessionId = 0; + } + + mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Update PE session Id */ + mlmReassocCnf.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +lim_process_switch_channel_join_mlo(struct pe_session *session_entry, + struct mac_context *mac_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mlo_partner_info *partner_info; + struct element_info assoc_rsp, link_assoc_rsp; + tLimMlmJoinCnf mlm_join_cnf; + tLimMlmAssocCnf assoc_cnf; + uint8_t *frame_ie_buf, *mlie; + qdf_size_t frame_ie_len, mlie_len; + bool link_id_found = false; + struct qdf_mac_addr sta_link_addr; + uint8_t assoc_link_id, link_id; + struct wlan_frame_hdr *link_frame_hdr; + + assoc_rsp.len = 0; + mlo_get_assoc_rsp(session_entry->vdev, &assoc_rsp); + + partner_info = &session_entry->ml_partner_info; + if (!partner_info->num_partner_links) { + pe_debug("MLO: vdev:%d num_partner_links is 0", + session_entry->vdev_id); + return QDF_STATUS_E_INVAL; + } + + /* Todo: update the sta addr by matching link id */ + qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + if (!assoc_rsp.len) + return status; + + mlm_join_cnf.resultCode = eSIR_SME_SUCCESS; + mlm_join_cnf.protStatusCode = STATUS_SUCCESS; + /* Update PE sessionId */ + mlm_join_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *)&mlm_join_cnf); + + session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE; + assoc_rsp.len += SIR_MAC_HDR_LEN_3A; + pe_debug("MLO:assoc rsp len + hdr %d ", assoc_rsp.len); + + link_assoc_rsp.ptr = qdf_mem_malloc(assoc_rsp.len); + if (!link_assoc_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + link_assoc_rsp.len = assoc_rsp.len + 24; + session_entry->limMlmState = eLIM_MLM_WT_ASSOC_RSP_STATE; + + link_id = wlan_vdev_get_link_id(session_entry->vdev); + pe_debug("MLO: Generate and process assoc rsp for link vdev %d", + link_id); + + if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(session_entry->vdev)) { + frame_ie_buf = assoc_rsp.ptr + WLAN_ASSOC_RSP_IES_OFFSET; + frame_ie_len = assoc_rsp.len - 24 - WLAN_ASSOC_RSP_IES_OFFSET; + + status = util_find_mlie(frame_ie_buf, frame_ie_len, + &mlie, &mlie_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("ML IE not found"); + goto rsp_gen_fail; + } + + status = util_get_bvmlie_primary_linkid(mlie, mlie_len, + &link_id_found, + &assoc_link_id); + if (QDF_IS_STATUS_ERROR(status) || !link_id_found) { + pe_debug("Assoc link ID not found"); + goto rsp_gen_fail; + } + + if (assoc_link_id != link_id) + goto gen_link_assoc_rsp; + + pe_debug("Skip assoc rsp gen for link %d", link_id); + link_frame_hdr = (struct wlan_frame_hdr *)link_assoc_rsp.ptr; + qdf_ether_addr_copy(link_frame_hdr->i_addr3, + session_entry->bssId); + qdf_ether_addr_copy(link_frame_hdr->i_addr2, + session_entry->bssId); + qdf_ether_addr_copy(link_frame_hdr->i_addr1, + &sta_link_addr.bytes[0]); + link_frame_hdr->i_fc[0] = MLO_LINKSPECIFIC_ASSOC_RESP_FC0; + link_frame_hdr->i_fc[1] = MLO_LINKSPECIFIC_ASSOC_RESP_FC1; + + qdf_mem_copy(link_assoc_rsp.ptr + SIR_MAC_HDR_LEN_3A, + assoc_rsp.ptr, assoc_rsp.len - SIR_MAC_HDR_LEN_3A); + + goto process_assoc_rsp; + } + +gen_link_assoc_rsp: + status = util_gen_link_assoc_rsp(assoc_rsp.ptr, + assoc_rsp.len - 24, + false, link_id, sta_link_addr, + link_assoc_rsp.ptr, + assoc_rsp.len, + (qdf_size_t *)&link_assoc_rsp.len); +process_assoc_rsp: + if (QDF_IS_STATUS_SUCCESS(status)) { + pe_debug("MLO: process assoc rsp for link vdev"); + lim_process_assoc_rsp_frame(mac_ctx, + link_assoc_rsp.ptr, + (link_assoc_rsp.len - SIR_MAC_HDR_LEN_3A), + LIM_ASSOC, + session_entry); + goto mem_free; + } + +rsp_gen_fail: + pe_debug("MLO: link vdev assoc rsp generation failed"); + assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Update PE sessionId */ + assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *)&assoc_cnf); + +mem_free: + qdf_mem_free(link_assoc_rsp.ptr); + link_assoc_rsp.ptr = NULL; + link_assoc_rsp.len = 0; + + return status; +} + +#else /* WLAN_FEATURE_11BE_MLO */ +static QDF_STATUS +lim_process_switch_channel_join_mlo(struct pe_session *session_entry, + struct mac_context *mac_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#if defined(WLAN_FEATURE_ROAM_OFFLOAD) && defined(WLAN_FEATURE_11BE_MLO) +static QDF_STATUS +lim_process_switch_channel_join_mlo_roam(struct pe_session *session_entry, + struct mac_context *mac_ctx) +{ + QDF_STATUS status; + struct element_info assoc_rsp = {}; + struct qdf_mac_addr sta_link_addr; + struct element_info link_assoc_rsp; + tLimMlmJoinCnf mlm_join_cnf; + tLimMlmAssocCnf assoc_cnf; + struct qdf_mac_addr bssid; + uint8_t link_id = 0; + + assoc_rsp.len = 0; + mlo_get_assoc_rsp(session_entry->vdev, &assoc_rsp); + + if (!session_entry->ml_partner_info.num_partner_links) { + pe_debug("MLO_ROAM: vdev:%d num_partner_links is 0", + session_entry->vdev_id); + return QDF_STATUS_E_INVAL; + } + + /* Todo: update the sta addr by matching link id */ + qdf_mem_copy(&sta_link_addr, session_entry->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + pe_err("vdev:%d sta_link_addr" QDF_MAC_ADDR_FMT, + session_entry->vdev_id, + QDF_MAC_ADDR_REF(&sta_link_addr.bytes[0])); + + if (!assoc_rsp.len) + return QDF_STATUS_SUCCESS; + + mlm_join_cnf.resultCode = eSIR_SME_SUCCESS; + mlm_join_cnf.protStatusCode = STATUS_SUCCESS; + /* Update PE sessionId */ + mlm_join_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *)&mlm_join_cnf); + + session_entry->limSmeState = eLIM_SME_WT_ASSOC_STATE; + pe_debug("MLO_ROAM: reassoc rsp len %d ", assoc_rsp.len); + + link_assoc_rsp.ptr = qdf_mem_malloc(assoc_rsp.len); + if (!link_assoc_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + link_assoc_rsp.len = assoc_rsp.len; + session_entry->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + mlo_get_link_mac_addr_from_reassoc_rsp(session_entry->vdev, &bssid); + sir_copy_mac_addr(session_entry->limReAssocbssId, bssid.bytes); + link_id = wlan_vdev_get_link_id(session_entry->vdev); + pe_debug("MLO ROAM: Generate and process assoc rsp for link_id:%d vdev %d", + link_id, session_entry->vdev_id); + + status = util_gen_link_assoc_rsp(assoc_rsp.ptr, + assoc_rsp.len, + true, link_id, sta_link_addr, + link_assoc_rsp.ptr, + assoc_rsp.len, + (qdf_size_t *)&link_assoc_rsp.len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("MLO_ROAM: link vdev:%d link_id:%d assoc rsp generation failed", + session_entry->vdev_id, link_id); + assoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + assoc_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Update PE sessionId */ + assoc_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *)&assoc_cnf); + + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + qdf_mem_free(link_assoc_rsp.ptr); + + return status; + } + + pe_debug("MLO_ROAM: process reassoc rsp for link vdev"); + lim_process_assoc_rsp_frame(mac_ctx, link_assoc_rsp.ptr, + (link_assoc_rsp.len - WLAN_MAC_HDR_LEN_3A), + LIM_REASSOC, session_entry); + qdf_mem_free(link_assoc_rsp.ptr); + + return QDF_STATUS_SUCCESS; +} +#else /* (WLAN_FEATURE_ROAM_OFFLOAD) && (WLAN_FEATURE_11BE_MLO) */ +static QDF_STATUS +lim_process_switch_channel_join_mlo_roam(struct pe_session *session_entry, + struct mac_context *mac_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* (WLAN_FEATURE_ROAM_OFFLOAD) && (WLAN_FEATURE_11BE_MLO) */ + +#ifdef WLAN_FEATURE_11BE_MLO +static void +lim_update_mlo_mgr_ap_link_info_mbssid_connect(struct pe_session *session) +{ + struct mlo_partner_info *partner_info; + struct mlo_link_info *partner_link_info; + struct wlan_channel channel = {0}; + struct mlo_link_switch_context *link_ctx; + uint8_t i = 0; + + if (!session->vdev) { + pe_err("vdev:%d is NULL", session->vdev_id); + return; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + return; + + if (!session->lim_join_req) { + pe_err("vdev:%d lim_join_req is NULL", session->vdev_id); + return; + } + + link_ctx = session->vdev->mlo_dev_ctx->link_ctx; + if (!link_ctx) { + pe_err("vdev:%d MLO Link_ctx not found", + session->vdev_id); + return; + } + + /* Populating Assoc Link Band info */ + channel.ch_freq = (uint16_t)session->curr_op_freq; + + mlo_mgr_reset_ap_link_info(session->vdev); + mlo_mgr_update_ap_link_info(session->vdev, + wlan_vdev_get_link_id(session->vdev), + session->bssId, channel); + + /* Populating Partner link band Info */ + partner_info = &session->lim_join_req->partner_info; + for (i = 0; i < partner_info->num_partner_links; i++) { + partner_link_info = &partner_info->partner_link_info[i]; + + qdf_mem_zero(&channel, sizeof(channel)); + channel.ch_freq = partner_link_info->chan_freq; + + mlo_mgr_update_ap_link_info(session->vdev, + partner_link_info->link_id, + partner_link_info->link_addr.bytes, + channel); + } +} +#else +static void +lim_update_mlo_mgr_ap_link_info_mbssid_connect(struct pe_session *session) +{} +#endif + +/** + * lim_process_switch_channel_join_req() -Initiates probe request + * + * @mac_ctx - A pointer to Global MAC structure + * @pe_session - session related information. + * @status - channel switch success/failure + * + * This function is called to send the probe req mgmt frame + * after the switchChannelRsp message is received from HAL. + * + * Return None + */ +static void lim_process_switch_channel_join_req( + struct mac_context *mac_ctx, struct pe_session *session_entry, + QDF_STATUS status) +{ + tSirMacSSid ssId; + tLimMlmJoinCnf join_cnf; + uint8_t nontx_bss_id = 0; + struct bss_description *bss; + struct vdev_mlme_obj *mlme_obj; + struct wlan_lmac_if_reg_tx_ops *tx_ops; + bool tpe_change = false; + QDF_STATUS mlo_status; + struct pe_session *sap_session; + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Change channel failed!!"); + goto error; + } + + if ((!session_entry) || (!session_entry->pLimMlmJoinReq) || + (!session_entry->lim_join_req)) { + pe_err("invalid pointer!!"); + goto error; + } + + if (lim_connect_skip_join_for_gc(session_entry)) { + join_cnf.resultCode = eSIR_SME_SUCCESS; + join_cnf.protStatusCode = STATUS_SUCCESS; + join_cnf.sessionId = session_entry->peSessionId; + lim_post_sme_message(mac_ctx, + LIM_MLM_JOIN_CNF, + (uint32_t *)&join_cnf.resultCode); + return; + } + + bss = &session_entry->lim_join_req->bssDescription; + nontx_bss_id = bss->mbssid_info.profile_num; + + session_entry->limPrevMlmState = session_entry->limMlmState; + session_entry->limMlmState = eLIM_MLM_WT_JOIN_BEACON_STATE; + + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session_entry); + + if (wlan_vdev_mlme_is_mlo_link_vdev(session_entry->vdev)) { + if (mlo_roam_is_auth_status_connected(mac_ctx->psoc, + session_entry->vdev_id)) + mlo_status = lim_process_switch_channel_join_mlo_roam(session_entry, + mac_ctx); + else + mlo_status = lim_process_switch_channel_join_mlo(session_entry, + mac_ctx); + + if (mlo_status == QDF_STATUS_E_INVAL) + goto error; + else + return; + } + /* + * If deauth_before_connection is enabled, Send Deauth first to AP if + * last disconnection was caused by HB failure. + */ + if (mac_ctx->mlme_cfg->sta.deauth_before_connection) { + int apCount; + + for (apCount = 0; apCount < 2; apCount++) { + + if (!qdf_mem_cmp(session_entry->pLimMlmJoinReq->bssDescription.bssId, + mac_ctx->lim.gLimHeartBeatApMac[apCount], sizeof(tSirMacAddr))) { + + pe_err("Index %d Sessionid: %d Send deauth on " + "channel freq %d to BSSID: " QDF_MAC_ADDR_FMT, + apCount, + session_entry->peSessionId, + session_entry->curr_op_freq, + QDF_MAC_ADDR_REF( + session_entry->pLimMlmJoinReq->bssDescription.bssId)); + + lim_send_deauth_mgmt_frame(mac_ctx, REASON_UNSPEC_FAILURE, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry, false); + + qdf_mem_zero(mac_ctx->lim.gLimHeartBeatApMac[apCount], + sizeof(tSirMacAddr)); + break; + } + } + } + + /* + * MBSSID: Non Tx BSS may or may not respond to unicast + * probe request.So dont send unicast probe request + * and wait for the probe response/ beacon to post JOIN CNF + */ + if (nontx_bss_id) { + pe_debug("Skip sending join probe for MBSS candidate"); + session_entry->limMlmState = eLIM_MLM_JOINED_STATE; + join_cnf.sessionId = session_entry->peSessionId; + join_cnf.resultCode = eSIR_SME_SUCCESS; + join_cnf.protStatusCode = STATUS_SUCCESS; + + lim_update_mlo_mgr_ap_link_info_mbssid_connect(session_entry); + + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, + (uint32_t *)&join_cnf); + return; + } + + /* Wait for Beacon to announce join success */ + qdf_mem_copy(ssId.ssId, + session_entry->ssId.ssId, session_entry->ssId.length); + ssId.length = session_entry->ssId.length; + + lim_deactivate_and_change_timer(mac_ctx, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + + /* assign appropriate sessionId to the timer object */ + mac_ctx->lim.lim_timers.gLimPeriodicJoinProbeReqTimer.sessionId = + session_entry->peSessionId; + pe_debug("vdev %d Send Probe req on freq %d " QDF_SSID_FMT " " QDF_MAC_ADDR_FMT, + session_entry->vdev_id, + session_entry->curr_op_freq, + QDF_SSID_REF(ssId.length, ssId.ssId), + QDF_MAC_ADDR_REF( + session_entry->pLimMlmJoinReq->bssDescription.bssId)); + + /* + * We need to wait for probe response, so start join + * timeout timer.This timer will be deactivated once + * we receive probe response. + */ + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TIMER_ACTIVATE, + session_entry->peSessionId, eLIM_JOIN_FAIL_TIMER)); + if (tx_timer_activate(&mac_ctx->lim.lim_timers.gLimJoinFailureTimer) != + TX_SUCCESS) { + pe_err("couldn't activate Join failure timer"); + session_entry->limMlmState = session_entry->limPrevMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + mac_ctx->lim.gLimMlmState)); + goto error; + } + + sap_session = + lim_get_concurrent_session(mac_ctx, session_entry->vdev_id, + session_entry->opmode); + + /* + * STA LPI + SAP VLP is supported. For this, STA should move to + * VLP power. + * If there is a concurrent SAP operating on VLP in the same channel, + * then do not update the TPC if the connecting AP is in LPI. + */ + if (sap_session && + lim_is_power_change_required_for_sta(mac_ctx, session_entry, sap_session)) + lim_update_tx_power(mac_ctx, sap_session, session_entry, false); + + if (wlan_reg_is_ext_tpc_supported(mac_ctx->psoc) && + !session_entry->sta_follows_sap_power) { + tx_ops = wlan_reg_get_tx_ops(mac_ctx->psoc); + + lim_process_tpe_ie_from_beacon(mac_ctx, session_entry, bss, + &tpe_change); + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session_entry->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + goto error; + } + + lim_calculate_tpc(mac_ctx, session_entry); + + if (tx_ops->set_tpc_power) + tx_ops->set_tpc_power(mac_ctx->psoc, + session_entry->vdev_id, + &mlme_obj->reg_tpc_obj); + } + /* include additional IE if there is */ + lim_send_probe_req_mgmt_frame(mac_ctx, &ssId, + session_entry->pLimMlmJoinReq->bssDescription.bssId, + session_entry->curr_op_freq, + session_entry->self_mac_addr, + session_entry->dot11mode, + &session_entry->lim_join_req->addIEScan.length, + session_entry->lim_join_req->addIEScan.addIEdata); + + /* Activate Join Periodic Probe Req timer */ + if (tx_timer_activate + (&mac_ctx->lim.lim_timers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + pe_err("Periodic JoinReq timer activate failed"); + goto error; + } + + session_entry->join_probe_cnt++; + return; +error: + if (session_entry) { + if (session_entry->pLimMlmJoinReq) { + qdf_mem_free(session_entry->pLimMlmJoinReq); + session_entry->pLimMlmJoinReq = NULL; + } + if (session_entry->lim_join_req) { + qdf_mem_free(session_entry->lim_join_req); + session_entry->lim_join_req = NULL; + } + join_cnf.sessionId = session_entry->peSessionId; + } else { + join_cnf.sessionId = 0; + } + join_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + join_cnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + lim_post_sme_message(mac_ctx, LIM_MLM_JOIN_CNF, (uint32_t *)&join_cnf); +} + +static void lim_handle_mon_switch_channel_rsp(struct pe_session *session, + QDF_STATUS status) +{ + struct scheduler_msg message = {0}; + + if (session->bssType != eSIR_MONITOR_MODE) + return; + + if (QDF_IS_STATUS_ERROR(status)) { + enum wlan_vdev_sm_evt event = WLAN_VDEV_SM_EV_START_REQ_FAIL; + + pe_err("Set channel failed for monitor mode vdev substate %d", + wlan_vdev_mlme_get_substate(session->vdev)); + + if (QDF_IS_STATUS_SUCCESS( + wlan_vdev_is_restart_progress(session->vdev))) + event = WLAN_VDEV_SM_EV_RESTART_REQ_FAIL; + + wlan_vdev_mlme_sm_deliver_evt(session->vdev, event, 0, NULL); + + return; + } + + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_SUCCESS, 0, NULL); + + message.type = eWNI_SME_MONITOR_MODE_VDEV_UP; + message.bodyval = session->vdev_id; + pe_debug("vdev id %d ", session->vdev_id); + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &message)) { + pe_err("Failed to post message montior mode vdev up"); + } +} + +/** + * lim_process_switch_channel_rsp() + * + ***FUNCTION: + * This function is called to process switchChannelRsp message from HAL. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param body - message body. + * + * @return None + */ +void lim_process_switch_channel_rsp(struct mac_context *mac, + struct vdev_start_response *rsp) +{ + QDF_STATUS status; + uint16_t channelChangeReasonCode; + struct pe_session *pe_session; + struct wlan_channel *vdev_chan; + /* we need to process the deferred message since the initiating req. there might be nested request. */ + /* in the case of nested request the new request initiated from the response will take care of resetting */ + /* the deferred flag. */ + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + status = rsp->status; + + pe_session = pe_find_session_by_vdev_id(mac, rsp->vdev_id); + if (!pe_session) { + pe_err("session does not exist for given sessionId"); + return; + } + pe_session->ch_switch_in_progress = false; + channelChangeReasonCode = pe_session->channelChangeReasonCode; + /* initialize it back to invalid id */ + pe_session->chainMask = rsp->chain_mask; + pe_session->smpsMode = rsp->smps_mode; + pe_session->channelChangeReasonCode = 0xBAD; + + vdev_chan = wlan_vdev_mlme_get_des_chan(pe_session->vdev); + + if (WLAN_REG_IS_24GHZ_CH_FREQ(vdev_chan->ch_freq)) { + if (vdev_chan->ch_phymode == WLAN_PHYMODE_11B) + pe_session->nwType = eSIR_11B_NW_TYPE; + else + pe_session->nwType = eSIR_11G_NW_TYPE; + } else { + pe_session->nwType = eSIR_11A_NW_TYPE; + } + pe_debug("new network type for peer: %d", pe_session->nwType); + switch (channelChangeReasonCode) { + case LIM_SWITCH_CHANNEL_REASSOC: + lim_process_switch_channel_re_assoc_req(mac, pe_session, status); + break; + case LIM_SWITCH_CHANNEL_JOIN: + lim_process_switch_channel_join_req(mac, pe_session, status); + break; + + case LIM_SWITCH_CHANNEL_OPERATION: + case LIM_SWITCH_CHANNEL_HT_WIDTH: + /* + * The above code should also use the callback. + * mechanism below, there is scope for cleanup here. + * THat way all this response handler does is call the call back + * We can get rid of the reason code here. + */ + if (mac->lim.gpchangeChannelCallback) + mac->lim.gpchangeChannelCallback(mac, status, + mac->lim. + gpchangeChannelData, + pe_session); + + /* If MCC upgrade/DBS downgrade happened during channel switch, + * the policy manager connection table needs to be updated. + * STA PCL to F/W need update after sta channel switch. + */ + policy_mgr_update_connection_info(mac->psoc, + pe_session->smeSessionId); + wlan_cm_handle_sta_sta_roaming_enablement(mac->psoc, + pe_session->smeSessionId); + if (pe_session->opmode == QDF_P2P_CLIENT_MODE) { + pe_debug("Send p2p operating channel change conf action frame once first beacon is received on new channel"); + pe_session->send_p2p_conf_frame = true; + } + + if (ucfg_pkt_capture_get_pktcap_mode(mac->psoc)) + ucfg_pkt_capture_record_channel(pe_session->vdev); + break; + case LIM_SWITCH_CHANNEL_SAP_DFS: + if (QDF_IS_STATUS_SUCCESS(status)) + lim_set_tpc_power(mac, pe_session, NULL); + + /* Note: This event code specific to SAP mode + * When SAP session issues channel change as performing + * DFS, we will come here. Other sessions, for e.g. P2P + * will have to define their own event code and channel + * switch handler. This is required since the SME may + * require completely different information for P2P unlike + * SAP. + */ + lim_send_sme_ap_channel_switch_resp(mac, pe_session, rsp); + /* If MCC upgrade/DBS downgrade happened during channel switch, + * the policy manager connection table needs to be updated. + */ + policy_mgr_update_connection_info(mac->psoc, + pe_session->smeSessionId); + lim_check_conc_power_for_csa(mac, pe_session); + break; + case LIM_SWITCH_CHANNEL_MONITOR: + lim_handle_mon_switch_channel_rsp(pe_session, status); + /* + * If MCC upgrade/DBS downgrade happened during channel switch, + * the policy manager connection table needs to be updated. + */ + policy_mgr_update_connection_info(mac->psoc, + pe_session->smeSessionId); + if (ucfg_pkt_capture_get_pktcap_mode(mac->psoc)) + ucfg_pkt_capture_record_channel(pe_session->vdev); + break; + default: + break; + } +} + +QDF_STATUS lim_send_beacon_ind(struct mac_context *mac, + struct pe_session *pe_session, + enum sir_bcn_update_reason reason) +{ + struct beacon_gen_params *params; + struct scheduler_msg msg = {0}; + + if (!pe_session) { + pe_err("Error:Unable to get the PESessionEntry"); + return QDF_STATUS_E_INVAL; + } + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(params->bssid, pe_session->bssId, QDF_MAC_ADDR_SIZE); + msg.bodyptr = params; + + return sch_process_pre_beacon_ind(mac, &msg, reason); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c new file mode 100644 index 0000000000..6077a9d099 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_req_frame.c @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_process_probe_req_frame.cc contains the code + * for processing Probe Request Frame. + * Author: Chandra Modumudi + * Date: 02/28/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_cfg.h" +#include "ani_global.h" + +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_ser_des_utils.h" +#include "parser_api.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "wlan_utility.h" + +void + +lim_send_sme_probe_req_ind(struct mac_context *mac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, struct pe_session *pe_session); + +/** + * lim_remove_timeout_pbc_sessions() - remove pbc probe req entries. + * @mac - Pointer to Global MAC structure + * @pbc - The beginning entry in WPS PBC probe request link list + * + * This function is called to remove the WPS PBC probe request entries from + * specific entry to end. + * + * Return - None + */ +static void lim_remove_timeout_pbc_sessions(struct mac_context *mac, + tSirWPSPBCSession *pbc) +{ + tSirWPSPBCSession *prev; + + while (pbc) { + prev = pbc; + pbc = pbc->next; + pe_debug("WPS PBC sessions remove"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + prev->addr.bytes, QDF_MAC_ADDR_SIZE); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + prev->uuid_e, SIR_WPS_UUID_LEN); + + qdf_mem_free(prev); + } +} + +/** + * lim_update_pbc_session_entry + * + ***FUNCTION: + * This function is called when probe request with WPS PBC IE is received + * + ***LOGIC: + * This function add the WPS PBC probe request in the WPS PBC probe request link list + * The link list is in decreased time order of probe request that is received. + * The entry that is more than 120 second is removed. + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param addr A pointer to probe request source MAC address + * @param uuid_e A pointer to UUIDE element of WPS IE + * @param pe_session A pointer to station PE session + * + * @return None + */ + +static void lim_update_pbc_session_entry(struct mac_context *mac, + uint8_t *addr, uint8_t *uuid_e, + struct pe_session *pe_session) +{ + tSirWPSPBCSession *pbc, *prev = NULL; + + uint32_t curTime; + + curTime = + (uint32_t) (qdf_mc_timer_get_system_ticks() / + QDF_TICKS_PER_SECOND); + + pe_debug("Receive WPS probe request curTime: %d", curTime); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + addr, QDF_MAC_ADDR_SIZE); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + uuid_e, SIR_WPS_UUID_LEN); + + pbc = pe_session->pAPWPSPBCSession; + + while (pbc) { + if ((!qdf_mem_cmp + ((uint8_t *) pbc->addr.bytes, (uint8_t *) addr, + QDF_MAC_ADDR_SIZE)) + && (!qdf_mem_cmp((uint8_t *) pbc->uuid_e, + (uint8_t *) uuid_e, SIR_WPS_UUID_LEN))) { + if (prev) + prev->next = pbc->next; + else + pe_session->pAPWPSPBCSession = pbc->next; + break; + } + prev = pbc; + pbc = pbc->next; + } + + if (!pbc) { + pbc = qdf_mem_malloc(sizeof(tSirWPSPBCSession)); + if (!pbc) + return; + qdf_mem_copy((uint8_t *) pbc->addr.bytes, (uint8_t *) addr, + QDF_MAC_ADDR_SIZE); + + if (uuid_e) + qdf_mem_copy((uint8_t *) pbc->uuid_e, + (uint8_t *) uuid_e, SIR_WPS_UUID_LEN); + } + + pbc->next = pe_session->pAPWPSPBCSession; + pe_session->pAPWPSPBCSession = pbc; + pbc->timestamp = curTime; + + /* remove entries that have timed out */ + prev = pbc; + pbc = pbc->next; + + while (pbc) { + if (curTime > pbc->timestamp + SIR_WPS_PBC_WALK_TIME) { + prev->next = NULL; + lim_remove_timeout_pbc_sessions(mac, pbc); + break; + } + prev = pbc; + pbc = pbc->next; + } +} + +/** + * lim_wpspbc_close + * + ***FUNCTION: + * This function is called when BSS is closed + * + ***LOGIC: + * This function remove all the WPS PBC entries + * + ***ASSUMPTIONS: + * + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param pe_session A pointer to station PE session + * + * @return None + */ + +void lim_wpspbc_close(struct mac_context *mac, struct pe_session *pe_session) +{ + + lim_remove_timeout_pbc_sessions(mac, pe_session->pAPWPSPBCSession); + +} + +/** + * lim_check11b_rates + * + ***FUNCTION: + * This function is called by lim_process_probe_req_frame() upon + * Probe Request frame reception. + * + ***LOGIC: + * This function check 11b rates in supportedRates and extendedRates rates + * + ***NOTE: + * + * @param rate + * + * @return BOOLEAN + */ + +static bool lim_check11b_rates(uint8_t rate) +{ + if ((0x02 == (rate)) + || (0x04 == (rate)) + || (0x0b == (rate)) + || (0x16 == (rate)) + ) { + return true; + } + return false; +} + +#ifdef CONFIG_BAND_6GHZ +/** + * lim_need_broadcast_probe_rsp: check whether need broadcast probe rsp + * @session: a pointer to session entry + * @probe_req_da: probe request dst addr + * + * Return: bool + */ +static bool lim_need_broadcast_probe_rsp(struct pe_session *session, + tSirMacAddr probe_req_da) +{ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(session->curr_op_freq) && + QDF_IS_ADDR_BROADCAST(probe_req_da)) + return true; + else + return false; +} +#else +static bool lim_need_broadcast_probe_rsp(struct pe_session *session, + tSirMacAddr probe_req_da) +{ + return false; +} +#endif + +/** + * lim_process_probe_req_frame: to process probe req frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_pkt_info: A pointer to Buffer descriptor + associated PDUs + * @session: a pointer to session entry + * + * This function is called by limProcessMessageQueue() upon + * Probe Request frame reception. This function processes received + * Probe Request frame and responds with Probe Response. + * Only AP or STA in IBSS mode that sent last Beacon will respond to + * Probe Request. + * ASSUMPTIONS: + * 1. AP or STA in IBSS mode that sent last Beacon will always respond + * to Probe Request received with broadcast SSID. + * NOTE: + * 1. Dunno what to do with Rates received in Probe Request frame + * 2. Frames with out-of-order fields/IEs are dropped. + * + * + * Return: none + */ + +void +lim_process_probe_req_frame(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + struct pe_session *session) +{ + uint8_t *body_ptr; + tpSirMacMgmtHdr mac_hdr; + uint32_t frame_len; + tpSirProbeReq probe_req = NULL; + tAniSSID ssid; + uint8_t *uuid; + tSirMacAddr dst_mac; + + mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + if (LIM_IS_AP_ROLE(session) && + session->curr_op_freq == WMA_GET_RX_FREQ(rx_pkt_info)) { + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_pkt_info); + + pe_debug("Received Probe Request: %d bytes from "QDF_MAC_ADDR_FMT, + frame_len, QDF_MAC_ADDR_REF(mac_hdr->sa)); + /* Get pointer to Probe Request frame body */ + body_ptr = WMA_GET_RX_MPDU_DATA(rx_pkt_info); + + /* check for vendor IE presence */ + if ((session->access_policy_vendor_ie) && + (session->access_policy == + LIM_ACCESS_POLICY_RESPOND_IF_IE_IS_PRESENT)) { + if (!wlan_get_vendor_ie_ptr_from_oui( + &session->access_policy_vendor_ie[2], + 3, body_ptr, frame_len)) { + pe_warn("Vendor IE is not present and access policy is: %x dropping probe request", + session->access_policy); + return; + } + } + + probe_req = qdf_mem_malloc(sizeof(tSirProbeReq)); + if (!probe_req) + return; + + /* Parse Probe Request frame */ + if (sir_convert_probe_req_frame2_struct(mac_ctx, body_ptr, + frame_len, probe_req) == QDF_STATUS_E_FAILURE) { + pe_err("Parse error ProbeReq, length: %d, SA is: " + QDF_MAC_ADDR_FMT, frame_len, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + goto free_and_exit; + } + if (session->opmode == QDF_P2P_GO_MODE) { + uint8_t i = 0, rate_11b = 0, other_rates = 0; + /* Check 11b rates in supported rates */ + for (i = 0; i < probe_req->supportedRates.numRates; + i++) { + if (lim_check11b_rates( + probe_req->supportedRates.rate[i] & + 0x7f)) + rate_11b++; + else + other_rates++; + } + + /* Check 11b rates in extended rates */ + for (i = 0; i < probe_req->extendedRates.numRates; + i++) { + if (lim_check11b_rates( + probe_req->extendedRates.rate[i] & + 0x7f)) + rate_11b++; + else + other_rates++; + } + + if ((rate_11b > 0) && (other_rates == 0)) { + pe_debug("Received a probe req frame with only 11b rates, SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + goto free_and_exit; + } + } + if (LIM_IS_AP_ROLE(session) && + ((session->APWPSIEs.SirWPSProbeRspIE.FieldPresent + & SIR_WPS_PROBRSP_VER_PRESENT) && + (probe_req->wscIePresent == 1) && + (probe_req->probeReqWscIeInfo.DevicePasswordID.id == + WSC_PASSWD_ID_PUSH_BUTTON) && + (probe_req->probeReqWscIeInfo.UUID_E.present == 1))) { + if (session->fwdWPSPBCProbeReq) { + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + mac_hdr->sa, + QDF_MAC_ADDR_SIZE); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + body_ptr, frame_len); + lim_send_sme_probe_req_ind(mac_ctx, mac_hdr->sa, + body_ptr, frame_len, session); + } else { + uuid = probe_req->probeReqWscIeInfo.UUID_E.uuid; + lim_update_pbc_session_entry(mac_ctx, + mac_hdr->sa, + uuid, + session); + } + } + ssid.length = session->ssId.length; + /* Copy the SSID from session entry to local variable */ + qdf_mem_copy(ssid.ssId, session->ssId.ssId, + session->ssId.length); + + if (lim_need_broadcast_probe_rsp(session, mac_hdr->da)) + qdf_set_macaddr_broadcast((struct qdf_mac_addr *)dst_mac); + else + qdf_mem_copy(dst_mac, mac_hdr->sa, ETH_ALEN); + + /* + * Compare received SSID with current SSID. If they match, + * reply with Probe Response + */ + if (probe_req->ssId.length) { + if (!ssid.length) + goto multipleSSIDcheck; + + if (!qdf_mem_cmp((uint8_t *) &ssid, + (uint8_t *)&probe_req->ssId, + (uint8_t)(ssid.length + 1))) { + lim_send_probe_rsp_mgmt_frame(mac_ctx, + dst_mac, &ssid, + session, + probe_req->p2pIePresent); + goto free_and_exit; + } else if (session->opmode == + QDF_P2P_GO_MODE) { + uint8_t direct_ssid[7] = "DIRECT-"; + uint8_t direct_ssid_len = 7; + + if (!qdf_mem_cmp((uint8_t *) &direct_ssid, + (uint8_t *)&probe_req->ssId.ssId, + (uint8_t)(direct_ssid_len))) { + lim_send_probe_rsp_mgmt_frame( + mac_ctx, dst_mac, &ssid, + session, + probe_req->p2pIePresent); + goto free_and_exit; + } + } else { + pe_debug("Ignore ProbeReq frm with unmatch SSID received from SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + } + } else { + /* + * Broadcast SSID in the Probe Request. + * Reply with SSID we're configured with. + * Turn off the SSID length to 0 if hidden SSID feature + * is present + */ + if (session->ssidHidden) + /* + * We are returning from here as probe request + * contains the broadcast SSID. So no need to + * send the probe resp + */ + goto free_and_exit; + lim_send_probe_rsp_mgmt_frame(mac_ctx, dst_mac, + &ssid, + session, + probe_req->p2pIePresent); + goto free_and_exit; + } +multipleSSIDcheck: + pe_debug("Ignore ProbeReq frm with unmatch SSID rcved from SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + } else { + /* Ignore received Probe Request frame */ + pe_debug("Ignoring Probe Request frame received from SA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->sa)); + } + +free_and_exit: + qdf_mem_free(probe_req); + return; +} + +/** + * lim_indicate_probe_req_to_hdd + * + ***FUNCTION: + * This function is called by lim_process_probe_req_frame_multiple_bss() upon + * Probe Request frame reception. + * + ***LOGIC: + * This function processes received Probe Request frame and Pass + * Probe Request Frame to HDD. + * + * @param mac Pointer to Global MAC structure + * @param *pBd A pointer to Buffer descriptor + associated PDUs + * @param pe_session A pointer to PE session + * + * @return None + */ + +static void +lim_indicate_probe_req_to_hdd(struct mac_context *mac, uint8_t *pBd, + struct pe_session *pe_session) +{ + tpSirMacMgmtHdr pHdr; + uint32_t frameLen; + + pe_debug("Received a probe request frame"); + + pHdr = WMA_GET_RX_MAC_HEADER(pBd); + frameLen = WMA_GET_RX_PAYLOAD_LEN(pBd); + + /* send the probe req to SME. */ + lim_send_sme_mgmt_frame_ind(mac, pHdr->fc.subType, + (uint8_t *) pHdr, + (frameLen + sizeof(tSirMacMgmtHdr)), + pe_session->vdev_id, + WMA_GET_RX_FREQ(pBd), + WMA_GET_RX_RSSI_NORMALIZED(pBd), + RXMGMT_FLAG_NONE); +} /*** end lim_indicate_probe_req_to_hdd() ***/ + +/** + * lim_process_probe_req_frame_multiple_bss() - to process probe req + * @mac_ctx: Pointer to Global MAC structure + * @buf_descr: A pointer to Buffer descriptor + associated PDUs + * @session: A pointer to PE session + * + * This function is called by limProcessMessageQueue() upon + * Probe Request frame reception. This function call + * lim_indicate_probe_req_to_hdd function to indicate + * Probe Request frame to HDD. It also call lim_process_probe_req_frame + * function which process received Probe Request frame and responds + * with Probe Response. + * + * @return None + */ +void +lim_process_probe_req_frame_multiple_bss(struct mac_context *mac_ctx, + uint8_t *buf_descr, struct pe_session *session) +{ + uint8_t i; + struct wlan_channel *chan; + uint16_t probe_req_freq = WMA_GET_RX_FREQ(buf_descr); + + if (session) { + if (LIM_IS_AP_ROLE(session)) { + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + } + lim_process_probe_req_frame(mac_ctx, buf_descr, session); + return; + } + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + session = pe_find_session_by_session_id(mac_ctx, i); + if (!session) + continue; + + if (!LIM_IS_AP_ROLE(session)) + continue; + + if (wlan_vdev_is_up(session->vdev) != QDF_STATUS_SUCCESS) + continue; + + chan = wlan_vdev_get_active_channel(session->vdev); + /** + * For GO present on 5G/6G/2G band channel and if probe req + * is received for p2p listen on the listen channel then no + * need to send probe resp on GO operating channel + **/ + if (!chan || chan->ch_freq != probe_req_freq) { + pe_debug("do not send probe resp to requested probe freq %d", + probe_req_freq); + continue; + } + + lim_indicate_probe_req_to_hdd(mac_ctx, + buf_descr, session); + lim_process_probe_req_frame(mac_ctx, + buf_descr, session); + } +} + +/** + * lim_send_sme_probe_req_ind() + * + ***FUNCTION: + * This function is to send + * eWNI_SME_WPS_PBC_PROBE_REQ_IND message to host + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * This function is used for sending eWNI_SME_WPS_PBC_PROBE_REQ_IND + * to host. + * + * @param peerMacAddr Indicates the peer MAC addr that the probe request + * is generated. + * @param pProbeReqIE pointer to RAW probe request IE + * @param ProbeReqIELen The length of probe request IE. + * @param pe_session A pointer to PE session + * + * @return None + */ +void +lim_send_sme_probe_req_ind(struct mac_context *mac, + tSirMacAddr peerMacAddr, + uint8_t *pProbeReqIE, + uint32_t ProbeReqIELen, struct pe_session *pe_session) +{ + tSirSmeProbeReqInd *pSirSmeProbeReqInd; + struct scheduler_msg msgQ = {0}; + + pSirSmeProbeReqInd = qdf_mem_malloc(sizeof(tSirSmeProbeReqInd)); + if (!pSirSmeProbeReqInd) + return; + + msgQ.type = eWNI_SME_WPS_PBC_PROBE_REQ_IND; + msgQ.bodyval = 0; + msgQ.bodyptr = pSirSmeProbeReqInd; + + pSirSmeProbeReqInd->messageType = eWNI_SME_WPS_PBC_PROBE_REQ_IND; + pSirSmeProbeReqInd->length = sizeof(*pSirSmeProbeReqInd); + pSirSmeProbeReqInd->sessionId = pe_session->smeSessionId; + + qdf_mem_copy(pSirSmeProbeReqInd->bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.peer_macaddr.bytes, + peerMacAddr, QDF_MAC_ADDR_SIZE); + + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, msgQ.type)); + + if (ProbeReqIELen > sizeof(pSirSmeProbeReqInd->WPSPBCProbeReq. + probeReqIE)) { + ProbeReqIELen = sizeof(pSirSmeProbeReqInd->WPSPBCProbeReq. + probeReqIE); + } + + pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIELen = + (uint16_t) ProbeReqIELen; + qdf_mem_copy(pSirSmeProbeReqInd->WPSPBCProbeReq.probeReqIE, pProbeReqIE, + ProbeReqIELen); + + lim_sys_process_mmh_msg_api(mac, &msgQ); + +} /*** end lim_send_sme_probe_req_ind() ***/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c new file mode 100644 index 0000000000..62140b8ea1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_probe_rsp_frame.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_process_probe_rsp_frame.cc contains the code + * for processing Probe Response Frame. + * Author: Chandra Modumudi + * Date: 03/01/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_messages.h" +#include "lim_mlo.h" +#include "wlan_mlo_mgr_sta.h" +#include "parser_api.h" + +/** + * lim_validate_ie_information_in_probe_rsp_frame () - validates ie + * information in probe response. + * @mac_ctx: mac context + * @pRxPacketInfo: Rx packet info + * + * Return: 0 on success, one on failure + */ +static QDF_STATUS +lim_validate_ie_information_in_probe_rsp_frame(struct mac_context *mac_ctx, + uint8_t *pRxPacketInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t *pframe; + uint32_t nframe; + uint32_t missing_rsn_bytes; + + /* + * Validate a Probe response frame for malformed frame. + * If the frame is malformed then do not consider as it + * may cause problem fetching wrong IE values + */ + + if (WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) < + (SIR_MAC_B_PR_SSID_OFFSET + SIR_MAC_MIN_IE_LEN)) + return QDF_STATUS_E_FAILURE; + + pframe = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + nframe = WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo); + missing_rsn_bytes = 0; + + status = sir_validate_and_rectify_ies(mac_ctx, + pframe, nframe, &missing_rsn_bytes); + + if (status == QDF_STATUS_SUCCESS) + WMA_GET_RX_MPDU_LEN(pRxPacketInfo) += missing_rsn_bytes; + + return status; +} + +/** + * lim_process_updated_ies_in_probe_rsp() - process IEs of probe rsp frame + * @mac_ctx: pointer to global mac context + * @session_entry: pointer to pe session + * @probe_rsp: pointer to structure tSirProbeRespBeacon + * + * Return: void + */ +static void +lim_process_updated_ies_in_probe_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tSirProbeRespBeacon *probe_rsp) +{ + bool qos_enabled; + bool wme_enabled; + tpDphHashNode sta_ds; + QDF_STATUS status; + + if (session_entry->limMlmState == eLIM_MLM_LINK_ESTABLISHED_STATE) { + /* + * Now Process EDCA Parameters, if EDCAParamSet + * count is different. + * -- While processing beacons in link established + * state if it is determined that + * QoS Info IE has a different count for EDCA Params, + * and EDCA IE is not present in beacon, + * then probe req is sent out to get the EDCA params. + */ + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + + limGetQosMode(session_entry, &qos_enabled); + limGetWmeMode(session_entry, &wme_enabled); + pe_debug("wmeEdcaPresent: %d wme_enabled: %d edcaPresent: %d, qos_enabled: %d edcaParams.qosInfo.count: %d schObject.gLimEdcaParamSetCount: %d", + probe_rsp->wmeEdcaPresent, wme_enabled, + probe_rsp->edcaPresent, qos_enabled, + probe_rsp->edcaParams.qosInfo.count, + session_entry->gLimEdcaParamSetCount); + + if (((probe_rsp->wmeEdcaPresent && wme_enabled) || + (probe_rsp->edcaPresent && qos_enabled)) && + (probe_rsp->edcaParams.qosInfo.count != + session_entry->gLimEdcaParamSetCount)) { + status = sch_beacon_edca_process(mac_ctx, + &probe_rsp->edcaParams, + session_entry); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("EDCA param process error"); + } else if (sta_ds) { + qdf_mem_copy(&sta_ds->qos.peer_edca_params, + &probe_rsp->edcaParams, + sizeof(probe_rsp->edcaParams)); + /* + * If needed, downgrade the + * EDCA parameters + */ + lim_set_active_edca_params(mac_ctx, + session_entry->gLimEdcaParams, + session_entry); + lim_send_edca_params(mac_ctx, + session_entry->gLimEdcaParamsActive, + session_entry->vdev_id, false); + sch_qos_concurrency_update(); + } else { + pe_err("SelfEntry missing in Hash"); + } + } + if (session_entry->fWaitForProbeRsp) { + pe_warn("Check probe resp for caps change"); + lim_detect_change_in_ap_capabilities(mac_ctx, probe_rsp, + session_entry, + false); + } + } +} + +void lim_process_gen_probe_rsp_frame(struct mac_context *mac_ctx, + struct pe_session *session_entry, + uint8_t *bcn_probe, uint32_t len) +{ + tSirProbeRespBeacon *probe_rsp; + struct wlan_frame_hdr *header; + QDF_STATUS status; + + if (!bcn_probe || !len) { + pe_err("bcn_probe is null or invalid len %d", len); + return; + } + + if (!session_entry) { + pe_err("session_entry is NULL"); + return; + } + + probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (!probe_rsp) { + pe_err("Unable to allocate memory"); + return; + } + + header = (struct wlan_frame_hdr *)(bcn_probe); + pe_debug("Generate Probe Resp for cu (len %d): " QDF_MAC_ADDR_FMT, + len, QDF_MAC_ADDR_REF(header->i_addr3)); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + bcn_probe, len); + + bcn_probe = (uint8_t *)(bcn_probe + sizeof(*header)); + len -= sizeof(*header); + + status = sir_convert_probe_frame2_struct(mac_ctx, + bcn_probe, len, probe_rsp); + if (QDF_IS_STATUS_ERROR(status) || !probe_rsp->ssidPresent) { + pe_err("Parse error ProbeResponse, length=%d", len); + qdf_mem_free(probe_rsp); + return; + } + + lim_process_updated_ies_in_probe_rsp(mac_ctx, session_entry, probe_rsp); + qdf_mem_free(probe_rsp); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static +void lim_update_mlo_mgr_prb_info(struct mac_context *mac_ctx, + struct pe_session *session_entry, + struct qdf_mac_addr *mac_addr, + tpSirProbeRespBeacon probe_rsp) +{ + if (!(session_entry->lim_join_req && + session_entry->lim_join_req->is_ml_probe_req_sent && + probe_rsp->mlo_ie.mlo_ie_present)) + return; + + lim_update_mlo_mgr_info(mac_ctx, session_entry->vdev, mac_addr, + session_entry->lim_join_req->assoc_link_id, + probe_rsp->chan_freq); +} +#else +static inline +void lim_update_mlo_mgr_prb_info(struct mac_context *mac_ctx, + struct pe_session *session_entry, + struct qdf_mac_addr *mac_addr, + tpSirProbeRespBeacon probe_rsp) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static bool +lim_validate_probe_rsp_mld_addr(struct pe_session *session, + tpSirProbeRespBeacon probe_rsp) +{ + QDF_STATUS status; + struct wlan_mlo_ie *mlo_ie; + struct qdf_mac_addr curr_bss_mld; + struct qdf_mac_addr *probe_rsp_mld; + + /* If ML-IE is not present or if the VDEV is not MLO return success */ + if (!probe_rsp->mlo_ie.mlo_ie_present || + !wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + return true; + + status = wlan_vdev_get_bss_peer_mld_mac(session->vdev, &curr_bss_mld); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to fetch MLD address for ML VDEV"); + return false; + } + + mlo_ie = &probe_rsp->mlo_ie.mlo_ie; + probe_rsp_mld = (struct qdf_mac_addr *)mlo_ie->mld_mac_addr; + if (qdf_is_macaddr_zero(probe_rsp_mld) || + !qdf_is_macaddr_equal(probe_rsp_mld, &curr_bss_mld)) { + pe_err("prb rsp MLD " QDF_MAC_ADDR_FMT ", bss peer MLD " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(probe_rsp_mld->bytes), + QDF_MAC_ADDR_REF(curr_bss_mld.bytes)); + return false; + } + + return true; +} +#else +static inline bool +lim_validate_probe_rsp_mld_addr(struct pe_session *session, + tpSirProbeRespBeacon probe_rsp) +{ + return true; +} +#endif +/** + * lim_process_probe_rsp_frame() - processes received Probe Response frame + * @mac_ctx: Pointer to Global MAC structure + * @rx_Packet_info: A pointer to Buffer descriptor + associated PDUs + * @session_entry: Handle to the session. + * + * This function processes received Probe Response frame. + * Frames with out-of-order IEs are dropped. + * In case of IBSS, join 'success' makes MLM state machine + * transition into 'BSS started' state. This may have to change + * depending on supporting what kinda Authentication in IBSS. + * + * Return: None + */ +void +lim_process_probe_rsp_frame(struct mac_context *mac_ctx, uint8_t *rx_Packet_info, + struct pe_session *session_entry) +{ + uint8_t *body; + uint32_t frame_len = 0; + tSirMacAddr current_bssid; + tpSirMacMgmtHdr header; + tSirProbeRespBeacon *probe_rsp; + uint32_t chan_freq = 0; + uint8_t bpcc; + bool cu_flag = true; + QDF_STATUS status; + + if (!session_entry) { + pe_err("session_entry is NULL"); + return; + } + + probe_rsp = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (!probe_rsp) { + pe_err("Unable to allocate memory"); + return; + } + + probe_rsp->ssId.length = 0; + probe_rsp->wpa.length = 0; + + header = WMA_GET_RX_MAC_HEADER(rx_Packet_info); + + mac_ctx->lim.bss_rssi = (int8_t) + WMA_GET_RX_RSSI_NORMALIZED(rx_Packet_info); + + /* Validate IE information before processing Probe Response Frame */ + if (lim_validate_ie_information_in_probe_rsp_frame(mac_ctx, + rx_Packet_info) != + QDF_STATUS_SUCCESS) { + pe_err("Parse error ProbeResponse, length=%d", frame_len); + goto mem_free; + } + + frame_len = WMA_GET_RX_PAYLOAD_LEN(rx_Packet_info); + /* Get pointer to Probe Response frame body */ + body = WMA_GET_RX_MPDU_DATA(rx_Packet_info); + /* Enforce Mandatory IEs */ + if ((sir_convert_probe_frame2_struct(mac_ctx, + body, frame_len, probe_rsp) == QDF_STATUS_E_FAILURE) || + !probe_rsp->ssidPresent) { + pe_err("Parse error ProbeResponse, length=%d", frame_len); + goto mem_free; + } + + if (!lim_validate_probe_rsp_mld_addr(session_entry, probe_rsp)) + goto mem_free; + + lim_update_mlo_mgr_prb_info(mac_ctx, session_entry, + (struct qdf_mac_addr *)header->bssId, + probe_rsp); + + lim_process_bcn_prb_rsp_t2lm(mac_ctx, session_entry, probe_rsp); + lim_gen_link_specific_probe_rsp(mac_ctx, session_entry, + probe_rsp, + body, + frame_len, + mac_ctx->lim.bss_rssi); + + if (mlo_is_mld_sta(session_entry->vdev)) { + cu_flag = false; + status = lim_get_bpcc_from_mlo_ie(probe_rsp, &bpcc); + if (QDF_IS_STATUS_SUCCESS(status)) + cu_flag = lim_check_cu_happens(session_entry->vdev, + bpcc); + lim_process_cu_for_probe_rsp(mac_ctx, session_entry, + body, frame_len); + } + + if (session_entry->limMlmState == + eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* + * Either Beacon/probe response is required. + * Hence store it in same buffer. + */ + if (session_entry->beacon) { + qdf_mem_free(session_entry->beacon); + session_entry->beacon = NULL; + session_entry->bcnLen = 0; + } + session_entry->bcnLen = + WMA_GET_RX_MPDU_LEN(rx_Packet_info); + session_entry->beacon = + qdf_mem_malloc(session_entry->bcnLen); + if (!session_entry->beacon) { + pe_err("No Memory to store beacon"); + } else { + /* + * Store the whole ProbeRsp frame. + * This is sent to csr/hdd in join cnf response. + */ + qdf_mem_copy(session_entry->beacon, + WMA_GET_RX_MAC_HEADER + (rx_Packet_info), + session_entry->bcnLen); + } + /* STA in WT_JOIN_BEACON_STATE */ + mgmt_txrx_frame_hex_dump((uint8_t *)header, + WMA_GET_RX_MPDU_LEN(rx_Packet_info), + false); + lim_check_and_announce_join_success(mac_ctx, probe_rsp, + header, + session_entry); + + } else if (session_entry->limMlmState == + eLIM_MLM_LINK_ESTABLISHED_STATE) { + /* + * Check if this Probe Response is for + * our Probe Request sent upon reaching + * heart beat threshold + */ + sir_copy_mac_addr(current_bssid, session_entry->bssId); + if (qdf_mem_cmp(current_bssid, header->bssId, + sizeof(tSirMacAddr))) { + goto mem_free; + } + if (!LIM_IS_CONNECTION_ACTIVE(session_entry)) { + pe_warn("Recved Probe Resp from AP,AP-alive"); + if (probe_rsp->HTInfo.present) { + chan_freq = + wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, + probe_rsp->HTInfo.primaryChannel); + lim_received_hb_handler(mac_ctx, chan_freq, + session_entry); + } else + lim_received_hb_handler(mac_ctx, + probe_rsp->chan_freq, + session_entry); + } + + if (!cu_flag) + goto mem_free; + + lim_process_updated_ies_in_probe_rsp(mac_ctx, session_entry, + probe_rsp); + } + +mem_free: + qdf_mem_free(probe_rsp); + + /* Ignore Probe Response frame in all other states */ + return; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c new file mode 100644 index 0000000000..586126b9fe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_sme_req_messages.c @@ -0,0 +1,11055 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_process_sme_req_messages.cc contains the code + * for processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_api.h" +#include "wni_cfg.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sme_req_utils.h" +#include "lim_admit_control.h" +#include "dph_hash_table.h" +#include "lim_send_messages.h" +#include "lim_api.h" +#include "wmm_apsd.h" +#include "sir_mac_prot_def.h" +#include "rrm_api.h" +#include "nan_datapath.h" +#include "sap_api.h" +#include +#include "cds_regdomain.h" +#include +#include "lim_process_fils.h" +#include "wlan_utility.h" +#include +#include "../../core/src/vdev_mgr_ops.h" +#include "wma.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include "wlan_action_oui_main.h" +#include +#include +#include +#include +#include "wlan_lmac_if_def.h" +#include "wlan_reg_services_api.h" +#include +#include +#include "cfg_ucfg_api.h" +#include "wlan_twt_cfg_ext_api.h" +#include +#include "wlan_psoc_mlme_api.h" +#include "wma_he.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlme_main.h" +#ifdef WLAN_FEATURE_11BE_MLO +#include +#endif + +/* SME REQ processing function templates */ +static bool __lim_process_sme_sys_ready_ind(struct mac_context *, uint32_t *); +static bool __lim_process_sme_start_bss_req(struct mac_context *, + struct scheduler_msg *pMsg); +static void __lim_process_sme_disassoc_req(struct mac_context *, uint32_t *); +static void lim_process_sme_disassoc_cnf(struct mac_context *mac_ctx, + struct scheduler_msg *msg); +static void lim_process_sme_deauth_req(struct mac_context *mac_ctx, + struct scheduler_msg *msg); +static void lim_process_sme_disassoc_req(struct mac_context *mac_ctx, + struct scheduler_msg *msg); +static void __lim_process_sme_disassoc_cnf(struct mac_context *, uint32_t *); +static void __lim_process_sme_deauth_req(struct mac_context *, uint32_t *); +static bool __lim_process_sme_stop_bss_req(struct mac_context *, + struct scheduler_msg *pMsg); +static void lim_process_sme_channel_change_request(struct mac_context *mac, + uint32_t *pMsg); +static void lim_process_sme_start_beacon_req(struct mac_context *mac, uint32_t *pMsg); +static void lim_process_sme_dfs_csa_ie_request(struct mac_context *mac, uint32_t *pMsg); +static void lim_process_nss_update_request(struct mac_context *mac, uint32_t *pMsg); +static void lim_process_set_ie_req(struct mac_context *mac, uint32_t *pMsg); + +static void lim_start_bss_update_add_ie_buffer(struct mac_context *mac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, + uint16_t srcDataLen); + +static void lim_update_add_ie_buffer(struct mac_context *mac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen); +static void lim_process_modify_add_ies(struct mac_context *mac, uint32_t *pMsg); + +static void lim_process_update_add_ies(struct mac_context *mac, uint32_t *pMsg); + +static void lim_process_ext_change_channel(struct mac_context *mac_ctx, + uint32_t *msg); + +static void lim_mlo_sap_validate_and_update_ra(struct pe_session *session, + struct qdf_mac_addr *peer_addr); +/** + * enum get_next_lower_bw - Get next higher bandwidth for a given BW. + * This enum is used in conjunction with + * wlan_reg_set_channel_params_for_pwrmode API to fetch center frequencies + * for each BW starting from 20MHz upto Max BSS BW in case of non-PSD power. + * + */ +static const enum phy_ch_width get_next_higher_bw[] = { + [CH_WIDTH_20MHZ] = CH_WIDTH_40MHZ, + [CH_WIDTH_40MHZ] = CH_WIDTH_80MHZ, + [CH_WIDTH_80MHZ] = CH_WIDTH_160MHZ, +#if !defined(WLAN_FEATURE_11BE) + [CH_WIDTH_160MHZ] = CH_WIDTH_INVALID +#else + [CH_WIDTH_160MHZ] = CH_WIDTH_320MHZ, + [CH_WIDTH_320MHZ] = CH_WIDTH_INVALID +#endif +}; + +/** + * lim_process_set_hw_mode() - Send set HW mode command to WMA + * @mac: Globacl MAC pointer + * @msg: Message containing the hw mode index + * + * Send the set HW mode command to WMA + * + * Return: QDF_STATUS_SUCCESS if message posting is successful + */ +static QDF_STATUS lim_process_set_hw_mode(struct mac_context *mac, uint32_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + struct policy_mgr_hw_mode *req_msg; + uint32_t len; + struct s_sir_set_hw_mode *buf; + struct scheduler_msg resp_msg = {0}; + struct sir_set_hw_mode_resp *param; + + buf = (struct s_sir_set_hw_mode *) msg; + if (!buf) { + pe_err("Set HW mode param is NULL"); + status = QDF_STATUS_E_INVAL; + /* To free the active command list */ + goto fail; + } + + len = sizeof(*req_msg); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + + req_msg->hw_mode_index = buf->set_hw.hw_mode_index; + req_msg->reason = buf->set_hw.reason; + /* Other parameters are not needed for WMA */ + + message.bodyptr = req_msg; + message.type = SIR_HAL_PDEV_SET_HW_MODE; + + pe_debug("Posting SIR_HAL_SOC_SET_HW_MOD to WMA"); + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_FAILURE; + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + resp_msg.type = eWNI_SME_SET_HW_MODE_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg); + return status; +} + +/** + * lim_process_set_dual_mac_cfg_req() - Set dual mac config command to WMA + * @mac: Global MAC pointer + * @msg: Message containing the dual mac config parameter + * + * Send the set dual mac config command to WMA + * + * Return: QDF_STATUS_SUCCESS if message posting is successful + */ +static QDF_STATUS lim_process_set_dual_mac_cfg_req(struct mac_context *mac, + uint32_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + struct policy_mgr_dual_mac_config *req_msg; + uint32_t len; + struct sir_set_dual_mac_cfg *buf; + struct scheduler_msg resp_msg = {0}; + struct sir_dual_mac_config_resp *param; + + buf = (struct sir_set_dual_mac_cfg *) msg; + if (!buf) { + pe_err("Set Dual mac config is NULL"); + status = QDF_STATUS_E_INVAL; + /* To free the active command list */ + goto fail; + } + + len = sizeof(*req_msg); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + + req_msg->scan_config = buf->set_dual_mac.scan_config; + req_msg->fw_mode_config = buf->set_dual_mac.fw_mode_config; + /* Other parameters are not needed for WMA */ + + message.bodyptr = req_msg; + message.type = SIR_HAL_PDEV_DUAL_MAC_CFG_REQ; + + pe_debug("Post SIR_HAL_PDEV_DUAL_MAC_CFG_REQ to WMA: %x %x", + req_msg->scan_config, req_msg->fw_mode_config); + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_FAILURE; + param->status = SET_HW_MODE_STATUS_ECANCELED; + resp_msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg); + return status; +} + +#ifdef FEATURE_WLAN_ESE +static inline bool +lim_is_ese_enabled(struct mac_context *mac_ctx) +{ + return mac_ctx->mlme_cfg->lfr.ese_enabled; +} +#else +static inline bool +lim_is_ese_enabled(struct mac_context *mac_ctx) +{ + return false; +} +#endif + +/** + * lim_process_set_antenna_mode_req() - Set antenna mode command + * to WMA + * @mac: Global MAC pointer + * @msg: Message containing the antenna mode parameter + * + * Send the set antenna mode command to WMA + * + * Return: QDF_STATUS_SUCCESS if message posting is successful + */ +static QDF_STATUS lim_process_set_antenna_mode_req(struct mac_context *mac, + uint32_t *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + struct sir_antenna_mode_param *req_msg; + struct sir_set_antenna_mode *buf; + struct scheduler_msg resp_msg = {0}; + struct sir_antenna_mode_resp *param; + + buf = (struct sir_set_antenna_mode *) msg; + if (!buf) { + pe_err("Set antenna mode is NULL"); + status = QDF_STATUS_E_INVAL; + /* To free the active command list */ + goto fail; + } + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) { + status = QDF_STATUS_E_NOMEM; + goto fail; + } + + req_msg->num_rx_chains = buf->set_antenna_mode.num_rx_chains; + req_msg->num_tx_chains = buf->set_antenna_mode.num_tx_chains; + + message.bodyptr = req_msg; + message.type = SIR_HAL_SOC_ANTENNA_MODE_REQ; + + pe_debug("Post SIR_HAL_SOC_ANTENNA_MODE_REQ to WMA: %d %d", + req_msg->num_rx_chains, + req_msg->num_tx_chains); + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + goto fail; + } + return status; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_NOMEM; + param->status = SET_ANTENNA_MODE_STATUS_ECANCELED; + resp_msg.type = eWNI_SME_SET_ANTENNA_MODE_RESP; + resp_msg.bodyptr = param; + resp_msg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &resp_msg); + return status; +} + +/** + * __lim_is_sme_assoc_cnf_valid() -- Validate ASSOC_CNF message + * @assoc_cnf: Pointer to Received ASSOC_CNF message + * + * This function is called by __lim_process_sme_assoc_cnf_new() upon + * receiving SME_ASSOC_CNF. + * + * Return: true when received SME_ASSOC_CNF is formatted correctly + * false otherwise + */ +static bool __lim_is_sme_assoc_cnf_valid(struct assoc_cnf *assoc_cnf) +{ + if (qdf_is_macaddr_group(&assoc_cnf->peer_macaddr)) + return false; + + return true; +} + +/** + * __lim_is_deferred_msg_for_radar() - Defers the message if radar is detected + * @mac_ctx: Pointer to Global MAC structure + * @message: Pointer to message posted from SME to LIM. + * + * Has role only if 11h is enabled. Not used on STA side. + * Defers the message if radar is detected. + * + * Return: true, if deferred otherwise return false. + */ +static bool +__lim_is_deferred_msg_for_radar(struct mac_context *mac_ctx, + struct scheduler_msg *message) +{ + /* + * fRadarDetCurOperChan will be set only if we + * detect radar in current operating channel and + * System Role == AP ROLE + * + * TODO: Need to take care radar detection. + * + * if (LIM_IS_RADAR_DETECTED(mac_ctx)) + */ + if (0) { + if (lim_defer_msg(mac_ctx, message) != TX_SUCCESS) { + pe_err("Could not defer Msg: %d", message->type); + return false; + } + pe_debug("Defer the message, in learn mode type: %d", + message->type); + return true; + } + return false; +} + +/** + * __lim_process_sme_sys_ready_ind () - Process ready indication from WMA + * @mac: Global MAC context + * @msg_buf: Message from WMA + * + * handles the notification from HDD. PE just forwards this message to HAL. + * + * Return: true-Posting to HAL failed, so PE will consume the buffer. + * false-Posting to HAL successful, so HAL will consume the buffer. + */ + +static bool __lim_process_sme_sys_ready_ind(struct mac_context *mac, + uint32_t *msg_buf) +{ + struct scheduler_msg msg = {0}; + struct sme_ready_req *ready_req = (struct sme_ready_req *)msg_buf; + + msg.type = WMA_SYS_READY_IND; + msg.reserved = 0; + msg.bodyptr = msg_buf; + msg.bodyval = 0; + + if (ANI_DRIVER_TYPE(mac) != QDF_DRIVER_TYPE_MFG) { + ready_req->pe_roam_synch_cb = pe_roam_synch_callback; + ready_req->pe_disconnect_cb = pe_disconnect_callback; + ready_req->pe_roam_set_ie_cb = pe_set_ie_for_roam_invoke; + pe_register_mgmt_rx_frm_callback(mac); + pe_register_callbacks_with_wma(mac, ready_req); + mac->lim.sme_msg_callback = ready_req->sme_msg_cb; + mac->lim.stop_roaming_callback = ready_req->stop_roaming_cb; + } + + pe_debug("sending WMA_SYS_READY_IND msg to HAL"); + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msg.type)); + + if (QDF_STATUS_SUCCESS != wma_post_ctrl_msg(mac, &msg)) { + pe_err("wma_post_ctrl_msg failed"); + return true; + } + return false; +} + +/** + *lim_configure_ap_start_bss_session() - Configure the AP Start BSS in session. + *@mac_ctx: Pointer to Global MAC structure + *@session: A pointer to session entry + *@sme_start_bss_req: Start BSS Request from upper layers. + * + * This function is used to configure the start bss parameters + * in to the session. + * + * Return: None. + */ +static void +lim_configure_ap_start_bss_session(struct mac_context *mac_ctx, + struct pe_session *session, + struct start_bss_config *sme_start_bss_req) +{ + bool sap_uapsd; + uint16_t ht_cap = cfg_default(CFG_AP_PROTECTION_MODE); + + session->limSystemRole = eLIM_AP_ROLE; + session->privacy = sme_start_bss_req->privacy; + session->fwdWPSPBCProbeReq = 1; + session->authType = sme_start_bss_req->authType; + /* Store the DTIM period */ + session->dtimPeriod = (uint8_t) sme_start_bss_req->dtimPeriod; + + /* Enable/disable UAPSD */ + wlan_mlme_is_sap_uapsd_enabled(mac_ctx->psoc, &sap_uapsd); + session->apUapsdEnable = sap_uapsd; + + session->gLimProtectionControl = + wlan_mlme_is_ap_prot_enabled(mac_ctx->psoc); + + wlan_mlme_get_ap_protection_mode(mac_ctx->psoc, &ht_cap); + qdf_mem_copy((void *)&session->cfgProtection, + (void *)&ht_cap, + sizeof(uint16_t)); + + wlan_mlme_get_vendor_vht_for_24ghz(mac_ctx->psoc, + &session->vendor_vht_sap); + if (session->opmode == QDF_P2P_GO_MODE) { + session->sap_dot11mc = 1; + session->proxyProbeRspEn = 0; + } else { + session->sap_dot11mc = mac_ctx->mlme_cfg->gen.sap_dot11mc; + /* + * To detect PBC overlap in SAP WPS mode, + * Host handles Probe Requests. + */ + if (SAP_WPS_DISABLED == sme_start_bss_req->wps_state) + session->proxyProbeRspEn = 1; + else + session->proxyProbeRspEn = 0; + } + session->ssidHidden = sme_start_bss_req->ssidHidden; + session->wps_state = sme_start_bss_req->wps_state; + + lim_get_short_slot_from_phy_mode(mac_ctx, session, session->gLimPhyMode, + &session->shortSlotTimeSupported); + + session->beacon_tx_rate = sme_start_bss_req->beacon_tx_rate; + +} + +static void lim_set_privacy(struct mac_context *mac_ctx, + int32_t ucast_cipher, + int32_t auth_mode, int32_t akm, bool ap_privacy) +{ + bool rsn_enabled, privacy; + + /* set default to open */ + mac_ctx->mlme_cfg->wep_params.auth_type = eSIR_OPEN_SYSTEM; + if (QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_AUTO) && + (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104))) + mac_ctx->mlme_cfg->wep_params.auth_type = eSIR_AUTO_SWITCH; + else if (QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_SHARED)) + mac_ctx->mlme_cfg->wep_params.auth_type = eSIR_SHARED_KEY; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + mac_ctx->mlme_cfg->wep_params.auth_type = eSIR_AUTH_TYPE_SAE; + + if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104)) { + privacy = true; + rsn_enabled = false; + } else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_TKIP) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_CCM) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_OCB) || + QDF_HAS_PARAM(ucast_cipher, + WLAN_CRYPTO_CIPHER_AES_CCM_256) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_GCM) || + QDF_HAS_PARAM(ucast_cipher, + WLAN_CRYPTO_CIPHER_AES_GCM_256) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WAPI_GCM4) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WAPI_SMS4)) { + privacy = ap_privacy; + rsn_enabled = true; + } else { + rsn_enabled = false; + privacy = false; + } + + mac_ctx->mlme_cfg->feature_flags.enable_rsn = rsn_enabled; + mac_ctx->mlme_cfg->wep_params.is_privacy_enabled = privacy; + mac_ctx->mlme_cfg->wep_params.wep_default_key_id = 0; +} + +/** + * lim_send_start_vdev_req() - send vdev start request + *@session: pe session + *@mlm_start_req: vdev start req + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_send_start_vdev_req(struct pe_session *session, tLimMlmStartReq *mlm_start_req) +{ + return wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START, + sizeof(*mlm_start_req), + mlm_start_req); +} + +#ifdef WLAN_FEATURE_11BE +void lim_strip_eht_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct add_ie_params *add_ie = &session->add_ie_params; + QDF_STATUS status; + uint8_t eht_cap_buff[DOT11F_IE_EHT_CAP_MAX_LEN + 2]; + uint8_t eht_op_buff[DOT11F_IE_EHT_OP_MAX_LEN + 2]; + + qdf_mem_zero(eht_cap_buff, sizeof(eht_cap_buff)); + qdf_mem_zero(eht_op_buff, sizeof(eht_op_buff)); + + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_EHT_CAP, ONE_BYTE, + EHT_CAP_OUI_TYPE, (uint8_t)EHT_CAP_OUI_SIZE, + eht_cap_buff, DOT11F_IE_EHT_CAP_MAX_LEN); + if (status != QDF_STATUS_SUCCESS) + pe_debug("Failed to strip EHT cap IE status: %d", status); + + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_EHT_OP, ONE_BYTE, + EHT_OP_OUI_TYPE, (uint8_t)EHT_OP_OUI_SIZE, + eht_op_buff, DOT11F_IE_EHT_OP_MAX_LEN); + if (status != QDF_STATUS_SUCCESS) + pe_debug("Failed to strip EHT op IE status: %d", status); +} +#else +void lim_strip_eht_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_11AX +void lim_strip_he_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct add_ie_params *add_ie = &session->add_ie_params; + QDF_STATUS status; + uint8_t he_cap_buff[DOT11F_IE_HE_CAP_MAX_LEN + 2]; + uint8_t he_op_buff[DOT11F_IE_HE_OP_MAX_LEN + 2]; + + qdf_mem_zero(he_cap_buff, sizeof(he_cap_buff)); + qdf_mem_zero(he_op_buff, sizeof(he_op_buff)); + + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_HE_CAP, ONE_BYTE, + HE_CAP_OUI_TYPE, (uint8_t)HE_CAP_OUI_SIZE, + he_cap_buff, DOT11F_IE_HE_CAP_MAX_LEN); + if (status != QDF_STATUS_SUCCESS) + pe_debug("Failed to strip HE cap IE status: %d", status); + + + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_HE_OP, ONE_BYTE, + HE_OP_OUI_TYPE, (uint8_t)HE_OP_OUI_SIZE, + he_op_buff, DOT11F_IE_HE_OP_MAX_LEN); + if (status != QDF_STATUS_SUCCESS) + pe_debug("Failed to strip HE op IE status: %d", status); +} +#else +void lim_strip_he_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} +#endif + +#ifdef FEATURE_WLAN_WAPI + +void lim_strip_wapi_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct add_ie_params *add_ie = &session->add_ie_params; + uint8_t wapiie_buff[DOT11F_IE_WAPIOPAQUE_MAX_LEN + 2]; + QDF_STATUS status; + + qdf_mem_zero(wapiie_buff, sizeof(wapiie_buff)); + + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_WAPIOPAQUE, ONE_BYTE, + NULL, 0, + wapiie_buff, DOT11F_IE_WAPIOPAQUE_MAX_LEN); + if (status != QDF_STATUS_SUCCESS) + pe_debug("Failed to strip WAPI IE status: %d", status); +} +#else +void lim_strip_wapi_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} +#endif +/** + * lim_set_ldpc_exception() - to set allow any LDPC exception permitted + * @mac_ctx: Pointer to mac context + * @vdev_mlme: vdev mlme + * @ch_freq: Given channel frequency where connection will go + * + * This API will check if hardware allows LDPC to be enabled for provided + * channel and user has enabled the RX LDPC selection + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_set_ldpc_exception(struct mac_context *mac_ctx, + struct vdev_mlme_obj *vdev_mlme, + uint32_t ch_freq) +{ + struct wlan_vht_config vht_config; + struct wlan_ht_config ht_caps; + + vht_config.caps = vdev_mlme->proto.vht_info.caps; + ht_caps.caps = vdev_mlme->proto.ht_info.ht_caps; + + if (mac_ctx->mlme_cfg->ht_caps.ht_cap_info.adv_coding_cap && + wma_is_rx_ldpc_supported_for_channel(ch_freq)) { + ht_caps.ht_caps.adv_coding_cap = 1; + vht_config.ldpc_coding = 1; + sme_debug("LDPC enable for ch freq[%d]", ch_freq); + } else { + ht_caps.ht_caps.adv_coding_cap = 0; + vht_config.ldpc_coding = 0; + sme_debug("LDPC disable for ch freq[%d]", ch_freq); + } + vdev_mlme->proto.vht_info.caps = vht_config.caps; + vdev_mlme->proto.ht_info.ht_caps = ht_caps.caps; + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_revise_req_vht_cap_per_band: Update vht cap based on band + * @session: Session pointer + * + * Return: None + * + */ +static void lim_revise_req_vht_cap_per_band(struct pe_session *session) +{ + struct wlan_vht_config *vht_config; + + vht_config = &session->vht_config; + /* Disable shortgi160 and 80 for 2.4Ghz BSS*/ + if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) { + vht_config->shortgi80 = 0; + vht_config->shortgi160and80plus80 = 0; + } +} + +static void lim_start_bss_update_ht_vht_caps(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct vdev_mlme_obj *vdev_mlme; + struct wlan_vht_config vht_config; + uint8_t value = 0; + struct wlan_ht_config ht_caps; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!vdev_mlme) + return; + if (!policy_mgr_is_dbs_enable(mac_ctx->psoc)) + lim_set_ldpc_exception(mac_ctx, vdev_mlme, + session->curr_op_freq); + vht_config.caps = vdev_mlme->proto.vht_info.caps; + value = mac_ctx->mlme_cfg->vht_caps.vht_cap_info.su_bformee; + vht_config.su_beam_formee = + value && mac_ctx->mlme_cfg->vht_caps.vht_cap_info.tx_bfee_sap; + value = MLME_VHT_CSN_BEAMFORMEE_ANT_SUPPORTED_FW_DEF; + vht_config.csnof_beamformer_antSup = value; + vht_config.mu_beam_formee = 0; + if (session->pLimStartBssReq->vht_channel_width <= CH_WIDTH_80MHZ) { + vht_config.shortgi160and80plus80 = 0; + vht_config.supported_channel_widthset = 0; + } + + session->vht_config = vht_config; + + ht_caps.caps = vdev_mlme->proto.ht_info.ht_caps; + session->ht_config = ht_caps.ht_caps; + + lim_revise_req_vht_cap_per_band(session); + pe_debug("cur_op_freq %d HT capability 0x%x VHT capability 0x%x bw %d", + session->curr_op_freq, ht_caps.caps, vht_config.caps, + session->pLimStartBssReq->vht_channel_width); +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static inline void lim_fill_cc_mode(struct mac_context *mac_ctx, + struct pe_session *session) +{ + session->cc_switch_mode = mac_ctx->roam.configParam.cc_switch_mode; +} +#else +static inline void lim_fill_cc_mode(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_SON +/** + * lim_save_max_mcs_idx() - save max mcs index to mlme component + * @mac_ctx: Pointer to Global MAC structure + * @session: pointer to pe session + * + * Return: void + */ +static void +lim_save_max_mcs_idx(struct mac_context *mac_ctx, struct pe_session *session) +{ + tDot11fIEVHTCaps vht_cap; + tDot11fIEhe_cap he_cap; + tDot11fIEHTCaps ht_cap; + u_int8_t session_max_mcs_idx = INVALID_MCS_NSS_INDEX; + + if (IS_DOT11_MODE_HE(session->dot11mode)) { + qdf_mem_zero(&he_cap, sizeof(tDot11fIEhe_cap)); + populate_dot11f_he_caps(mac_ctx, session, &he_cap); + session_max_mcs_idx = lim_get_he_max_mcs_idx(session->ch_width, + &he_cap); + } + if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX && + IS_DOT11_MODE_VHT(session->dot11mode)) { + qdf_mem_zero(&vht_cap, sizeof(tDot11fIEVHTCaps)); + populate_dot11f_vht_caps(mac_ctx, session, &vht_cap); + session_max_mcs_idx = lim_get_vht_max_mcs_idx(&vht_cap); + } + if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX && + IS_DOT11_MODE_HT(session->dot11mode)) { + qdf_mem_zero(&ht_cap, sizeof(tDot11fIEHTCaps)); + populate_dot11f_ht_caps(mac_ctx, session, &ht_cap); + session_max_mcs_idx = lim_get_ht_max_mcs_idx(&ht_cap); + } + if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX && + session->extRateSet.numRates) + session_max_mcs_idx = + lim_get_max_rate_idx(&session->extRateSet); + + if (session_max_mcs_idx == INVALID_MCS_NSS_INDEX && + session->rateSet.numRates) + session_max_mcs_idx = + lim_get_max_rate_idx(&session->rateSet); + + mlme_save_vdev_max_mcs_idx(session->vdev, session_max_mcs_idx); +} +#else +static void +lim_save_max_mcs_idx(struct mac_context *mac_ctx, struct pe_session *session) +{ +} +#endif + +/** + * __lim_handle_sme_start_bss_request() - process SME_START_BSS_REQ message + *@mac_ctx: Pointer to Global MAC structure + *@msg_buf: A pointer to the SME message buffer + * + * This function is called to process SME_START_BSS_REQ message + * from HDD or upper layer application. + * + * Return: None + */ +static void +__lim_handle_sme_start_bss_request(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + uint16_t size; + uint32_t val = 0; + tSirMacChanNum channel_number; + tLimMlmStartReq *mlm_start_req = NULL; + struct start_bss_config *sme_start_bss_req = NULL; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + uint8_t session_id; + struct pe_session *session = NULL; + uint8_t vdev_id = 0xFF; + uint32_t chanwidth; + struct vdev_type_nss *vdev_type_nss; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int32_t ucast_cipher; + int32_t auth_mode; + int32_t akm; + int32_t rsn_caps; + bool cfg_value = false; + enum QDF_OPMODE opmode; + ePhyChanBondState cb_mode; + enum bss_type bss_type; + struct qdf_mac_addr bssid; + +/* FEATURE_WLAN_DIAG_SUPPORT */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM + /* + * Since the session is not created yet, sending NULL. + * The response should have the correct state. + */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_START_BSS_REQ_EVENT, + NULL, 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + size = sizeof(*sme_start_bss_req); + sme_start_bss_req = qdf_mem_malloc(size); + if (!sme_start_bss_req) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + qdf_mem_copy(sme_start_bss_req, msg_buf, size); + vdev_id = sme_start_bss_req->vdev_id; + + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + if (opmode == QDF_NDI_MODE) + bss_type = eSIR_NDI_MODE; + else + bss_type = eSIR_INFRA_AP_MODE; + + wlan_mlme_get_mac_vdev_id(mac_ctx->pdev, vdev_id, &bssid); + + if ((mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) || + (mac_ctx->lim.gLimSmeState == eLIM_SME_IDLE_STATE)) { + if (!lim_is_sme_start_bss_req_valid(mac_ctx, + sme_start_bss_req, bss_type)) { + pe_warn("Received invalid eWNI_SME_START_BSS_REQ"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } + channel_number = wlan_reg_freq_to_chan(mac_ctx->pdev, + sme_start_bss_req->oper_ch_freq); + /* + * This is the place where PE is going to create a session. + * If session is not existed, then create a new session + */ + session = pe_find_session_by_bssid(mac_ctx, bssid.bytes, + &session_id); + if (session) { + pe_warn("Session Already exists for given BSSID"); + ret_code = eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + session = NULL; + goto free; + } else { + session = pe_create_session(mac_ctx, bssid.bytes, + &session_id, + mac_ctx->lim.max_sta_of_pe_session, + bss_type, + sme_start_bss_req->vdev_id); + if (!session) { + pe_warn("Session Can not be created"); + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(mac_ctx, session, + channel_number); + } + + if (QDF_NDI_MODE != opmode) { + /* Probe resp add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->add_ie_params.probeRespData_buff, + &session->add_ie_params.probeRespDataLen, + sme_start_bss_req->add_ie_params. + probeRespData_buff, + sme_start_bss_req->add_ie_params. + probeRespDataLen); + + /* Probe Beacon add ie */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->add_ie_params.probeRespBCNData_buff, + &session->add_ie_params.probeRespBCNDataLen, + sme_start_bss_req->add_ie_params. + probeRespBCNData_buff, + sme_start_bss_req->add_ie_params. + probeRespBCNDataLen); + + /* Assoc resp IE */ + lim_start_bss_update_add_ie_buffer(mac_ctx, + &session->add_ie_params.assocRespData_buff, + &session->add_ie_params.assocRespDataLen, + sme_start_bss_req->add_ie_params. + assocRespData_buff, + sme_start_bss_req->add_ie_params. + assocRespDataLen); + } + /* Store the session related params in newly created session */ + session->curr_op_freq = sme_start_bss_req->oper_ch_freq; + session->pLimStartBssReq = sme_start_bss_req; + lim_start_bss_update_ht_vht_caps(mac_ctx, session); + + sir_copy_mac_addr(session->self_mac_addr, bssid.bytes); + /* Copy SSID to session table */ + qdf_mem_copy((uint8_t *) &session->ssId, + (uint8_t *) &sme_start_bss_req->ssId, + (sme_start_bss_req->ssId.length + 1)); + + session->nwType = sme_start_bss_req->nwType; + + session->beaconParams.beaconInterval = + sme_start_bss_req->beaconInterval; + + /* Update the phymode */ + session->gLimPhyMode = sme_start_bss_req->nwType; + + session->maxTxPower = wlan_reg_get_channel_reg_power_for_freq( + mac_ctx->pdev, session->curr_op_freq); + /* Store the dot 11 mode in to the session Table */ + session->dot11mode = sme_start_bss_req->dot11mode; + + if (session->dot11mode == MLME_DOT11_MODE_11B) + mac_ctx->mlme_cfg-> + feature_flags.enable_short_slot_time_11g = 0; + else + mac_ctx->mlme_cfg->feature_flags. + enable_short_slot_time_11g = + mac_ctx->mlme_cfg->ht_caps. + short_slot_time_enabled; + ucast_cipher = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + auth_mode = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + akm = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + + lim_set_privacy(mac_ctx, ucast_cipher, auth_mode, akm, + sme_start_bss_req->privacy); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + lim_fill_cc_mode(mac_ctx, session); +#endif + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) { + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; + cb_mode = mac_ctx->roam.configParam. + channelBondingMode5GHz; + } else { + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + cb_mode = mac_ctx->roam.configParam. + channelBondingMode24GHz; + } + + switch (bss_type) { + case eSIR_INFRA_AP_MODE: + lim_configure_ap_start_bss_session(mac_ctx, session, + sme_start_bss_req); + if (session->opmode == QDF_SAP_MODE) + session->vdev_nss = vdev_type_nss->sap; + else + session->vdev_nss = vdev_type_nss->p2p_go; + break; + case eSIR_NDI_MODE: + session->vdev_nss = vdev_type_nss->ndi; + session->limSystemRole = eLIM_NDI_ROLE; + break; + + + /* + * There is one more mode called auto mode. + * which is used no where + */ + + /* FORBUILD -TEMPFIX.. HOW TO use AUTO MODE????? */ + + default: + /* not used anywhere...used in scan function */ + break; + } + + session->nss = session->vdev_nss; + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2) + session->nss = 1; + + session->htCapability = + IS_DOT11_MODE_HT(session->dot11mode); + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + + if (IS_DOT11_MODE_HE(session->dot11mode)) { + lim_update_session_he_capable(mac_ctx, session); + lim_copy_bss_he_cap(session); + } else if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + pe_err("Invalid oper_ch_freq %d for dot11mode %d", + session->curr_op_freq, session->dot11mode); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } else { + lim_strip_he_ies_from_add_ies(mac_ctx, session); + } + + if (IS_DOT11_MODE_EHT(session->dot11mode)) { + lim_update_session_eht_capable(mac_ctx, session); + lim_copy_bss_eht_cap(session); + } else { + lim_strip_eht_ies_from_add_ies(mac_ctx, session); + } + + session->txLdpcIniFeatureEnabled = + mac_ctx->mlme_cfg->ht_caps.tx_ldpc_enable; + rsn_caps = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_RSN_CAP); + session->limRmfEnabled = + rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED ? 1 : 0; + + qdf_mem_copy((void *)&session->rateSet, + (void *)&sme_start_bss_req->operationalRateSet, + sizeof(tSirMacRateSet)); + qdf_mem_copy((void *)&session->extRateSet, + (void *)&sme_start_bss_req->extendedRateSet, + sizeof(tSirMacRateSet)); + /* + * Allocate memory for the array of + * parsed (Re)Assoc request structure + */ + if (bss_type == eSIR_INFRA_AP_MODE) { + session->parsedAssocReq = + qdf_mem_malloc(session->dph.dphHashTable. + size * sizeof(tpSirAssocReq)); + if (!session->parsedAssocReq) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + } + + if (!sme_start_bss_req->oper_ch_freq && + bss_type != eSIR_NDI_MODE) { + pe_err("Received invalid eWNI_SME_START_BSS_REQ"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto free; + } +#ifdef QCA_HT_2040_COEX + if (mac_ctx->roam.configParam.obssEnabled && + !policy_mgr_is_vdev_ll_lt_sap(mac_ctx->psoc, vdev_id)) + session->htSupportedChannelWidthSet = + session->htCapability; + else +#endif + session->htSupportedChannelWidthSet = + (sme_start_bss_req->sec_ch_offset) ? 1 : 0; + session->htSecondaryChannelOffset = + sme_start_bss_req->sec_ch_offset; + session->htRecommendedTxWidthSet = + (session->htSecondaryChannelOffset) ? 1 : 0; + if (lim_is_session_he_capable(session) || + lim_is_session_eht_capable(session) || + session->vhtCapability || session->htCapability) { + chanwidth = sme_start_bss_req->vht_channel_width; + session->ch_width = chanwidth; + session->ch_center_freq_seg0 = + sme_start_bss_req->center_freq_seg0; + session->ch_center_freq_seg1 = + sme_start_bss_req->center_freq_seg1; + lim_update_he_bw_cap_mcs(session, NULL); + lim_update_eht_bw_cap_mcs(session, NULL); + } + + /* Delete pre-auth list if any */ + lim_delete_pre_auth_list(mac_ctx); + + /* + * keep the RSN/WPA IE information in PE Session Entry + * later will be using this to check when received (Re)Assoc req + */ + lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(mac_ctx, + &sme_start_bss_req->rsnIE, session); + + if (LIM_IS_AP_ROLE(session) || LIM_IS_NDI_ROLE(session)) { + /* Initialize WPS PBC session link list */ + session->pAPWPSPBCSession = NULL; + } + /* Prepare and Issue LIM_MLM_START_REQ to MLM */ + mlm_start_req = qdf_mem_malloc(sizeof(tLimMlmStartReq)); + if (!mlm_start_req) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto free; + } + + /* Copy SSID to the MLM start structure */ + qdf_mem_copy((uint8_t *) &mlm_start_req->ssId, + (uint8_t *) &sme_start_bss_req->ssId, + sme_start_bss_req->ssId.length + 1); + mlm_start_req->ssidHidden = sme_start_bss_req->ssidHidden; + + mlm_start_req->bssType = session->bssType; + + /* Fill PE session Id from the session Table */ + mlm_start_req->sessionId = session->peSessionId; + + sir_copy_mac_addr(mlm_start_req->bssId, session->bssId); + /* store the channel num in mlmstart req structure */ + mlm_start_req->oper_ch_freq = session->curr_op_freq; + mlm_start_req->beaconPeriod = + session->beaconParams.beaconInterval; + mlm_start_req->cac_duration_ms = + sme_start_bss_req->cac_duration_ms; + mlm_start_req->dfs_regdomain = + sme_start_bss_req->dfs_regdomain; + if (LIM_IS_AP_ROLE(session)) { + mlm_start_req->dtimPeriod = session->dtimPeriod; + mlm_start_req->wps_state = session->wps_state; + session->cac_duration_ms = + mlm_start_req->cac_duration_ms; + session->dfs_regdomain = mlm_start_req->dfs_regdomain; + mlm_start_req->cbMode = cb_mode; + qdf_status = + wlan_mlme_is_ap_obss_prot_enabled(mac_ctx->psoc, + &cfg_value); + if (QDF_IS_STATUS_ERROR(qdf_status)) + pe_err("Unable to get obssProtEnabled"); + mlm_start_req->obssProtEnabled = cfg_value; + } else { + val = mac_ctx->mlme_cfg->sap_cfg.dtim_interval; + mlm_start_req->dtimPeriod = (uint8_t) val; + } + + mlm_start_req->cfParamSet.cfpPeriod = + mac_ctx->mlme_cfg->rates.cfp_period; + mlm_start_req->cfParamSet.cfpMaxDuration = + mac_ctx->mlme_cfg->rates.cfp_max_duration; + + /* + * this may not be needed anymore now, + * as rateSet is now included in the + * session entry and MLM has session context. + */ + qdf_mem_copy((void *)&mlm_start_req->rateSet, + (void *)&session->rateSet, + sizeof(tSirMacRateSet)); + + /* Now populate the 11n related parameters */ + mlm_start_req->nwType = session->nwType; + mlm_start_req->htCapable = session->htCapability; + + mlm_start_req->htOperMode = mac_ctx->lim.gHTOperMode; + /* Unused */ + mlm_start_req->dualCTSProtection = + mac_ctx->lim.gHTDualCTSProtection; + mlm_start_req->txChannelWidthSet = + session->htRecommendedTxWidthSet; + + session->limRFBand = lim_get_rf_band( + sme_start_bss_req->oper_ch_freq); + + /* Initialize 11h Enable Flag */ + session->lim11hEnable = 0; + if (CHAN_HOP_ALL_BANDS_ENABLE || + (session->limRFBand != REG_BAND_2G)) { + session->lim11hEnable = + mac_ctx->mlme_cfg->gen.enabled_11h; + + if (session->lim11hEnable && + (eSIR_INFRA_AP_MODE == + mlm_start_req->bssType)) { + session->lim11hEnable = + mac_ctx->mlme_cfg-> + dfs_cfg.dfs_master_capable; + } + } + + if (!session->lim11hEnable) + mac_ctx->mlme_cfg->power.local_power_constraint = 0; + + mlm_start_req->beacon_tx_rate = session->beacon_tx_rate; + lim_save_max_mcs_idx(mac_ctx, session); + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_START_BSS_STATE; + + lim_dump_session_info(mac_ctx, session); + lim_dump_he_info(mac_ctx, session); + lim_dump_eht_info(session); + + MTRACE(mac_trace + (mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + qdf_status = lim_send_start_vdev_req(session, mlm_start_req); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto free; + qdf_mem_free(mlm_start_req); + lim_update_rrm_capability(mac_ctx); + + return; + } else { + + pe_err("Received unexpected START_BSS_REQ, in state %X", + mac_ctx->lim.gLimSmeState); + ret_code = eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED; + goto free; + } /* if (mac_ctx->lim.gLimSmeState == eLIM_SME_OFFLINE_STATE) */ + +free: + if ((session) && + (session->pLimStartBssReq == sme_start_bss_req)) { + session->pLimStartBssReq = NULL; + } + if (sme_start_bss_req) + qdf_mem_free(sme_start_bss_req); + if (mlm_start_req) + qdf_mem_free(mlm_start_req); + if (session) { + pe_delete_session(mac_ctx, session); + session = NULL; + } + lim_send_sme_start_bss_rsp(mac_ctx, ret_code, session, vdev_id); +} + +/** + * __lim_process_sme_start_bss_req() - Call handler to start BSS + * + * @mac: Global MAC context + * @pMsg: Message pointer + * + * Wrapper for the function __lim_handle_sme_start_bss_request + * This message will be deferred until softmac come out of + * scan mode or if we have detected radar on the current + * operating channel. + * + * return true - If we consumed the buffer + * false - If have deferred the message. + */ +static bool __lim_process_sme_start_bss_req(struct mac_context *mac, + struct scheduler_msg *pMsg) +{ + if (__lim_is_deferred_msg_for_radar(mac, pMsg)) { + /** + * If message deferred, buffer is not consumed yet. + * So return false + */ + return false; + } + + __lim_handle_sme_start_bss_request(mac, (uint32_t *) pMsg->bodyptr); + return true; +} + +/** + * lim_get_random_bssid() + * + * FUNCTION:This function is called to process generate the random number for bssid + * This function is called to process SME_SCAN_REQ message + * from HDD or upper layer application. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * 1. geneartes the unique random number for bssid in ibss + * + * @param mac Pointer to Global MAC structure + * @param *data Pointer to bssid buffer + * @return None + */ +void lim_get_random_bssid(struct mac_context *mac, uint8_t *data) +{ + uint32_t random[2]; + + random[0] = qdf_mc_timer_get_system_ticks(); + random[0] |= (random[0] << 15); + random[1] = random[0] >> 1; + qdf_mem_copy(data, random, sizeof(tSirMacAddr)); +} + +/** + * lim_send_join_req() - send vdev start request for assoc + *@session: pe session + *@mlm_join_req: join req + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_send_join_req(struct pe_session *session, + tLimMlmJoinReq *mlm_join_req) +{ + QDF_STATUS status; + + /* Continue connect only if Vdev is in INIT state */ + status = wlan_vdev_mlme_is_init_state(session->vdev); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Vdev %d not in int state cur state %d substate %d", + session->vdev_id, + wlan_vdev_mlme_get_state(session->vdev), + wlan_vdev_mlme_get_substate(session->vdev)); + qdf_trigger_self_recovery(session->mac_ctx->psoc, + QDF_VDEV_SM_OUT_OF_SYNC); + return status; + } + status = mlme_set_assoc_type(session->vdev, VDEV_ASSOC); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START, + sizeof(*mlm_join_req), + mlm_join_req); +} + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * lim_send_reassoc_req() - send vdev start request for reassoc + *@session: pe session + *@mlm_join_req: join req + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_send_reassoc_req(struct pe_session *session, + tLimMlmReassocReq *reassoc_req) +{ + QDF_STATUS status; + + status = mlme_set_assoc_type(session->vdev, VDEV_REASSOC); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + if (wlan_vdev_mlme_get_state(session->vdev) != WLAN_VDEV_S_UP) { + pe_err("Reassoc req in unexpected vdev SM state:%d", + wlan_vdev_mlme_get_state(session->vdev)); + return QDF_STATUS_E_FAILURE; + } + + lim_process_mlm_reassoc_req(session->mac_ctx, reassoc_req); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_ft_reassoc_req() - send vdev start request for ft_reassoc + *@session: pe session + *@mlm_join_req: join req + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_send_ft_reassoc_req(struct pe_session *session, + tLimMlmReassocReq *reassoc_req) +{ + QDF_STATUS status; + + status = mlme_set_assoc_type(session->vdev, VDEV_FT_REASSOC); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + if (wlan_vdev_mlme_get_state(session->vdev) == WLAN_VDEV_S_UP) { + pe_err("ft_reassoc req in unexpected vdev SM state:%d", + wlan_vdev_mlme_get_state(session->vdev)); + return QDF_STATUS_E_FAILURE; + } + + return wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START, + sizeof(*reassoc_req), + reassoc_req); +} +#endif + +static void lim_join_req_update_ht_vht_caps(struct mac_context *mac, + struct pe_session *session, + struct bss_description *bss_desc, + tDot11fBeaconIEs *bcn_ie) +{ + struct vdev_mlme_obj *vdev_mlme; + struct wlan_vht_config vht_config; + uint8_t value, value1; + tDot11fIEVHTCaps *vht_caps = NULL; + uint8_t tx_bf_csn = 0; + struct wlan_ht_config ht_caps; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!vdev_mlme) + return; + + lim_set_ldpc_exception(mac, vdev_mlme, session->curr_op_freq); + vht_config.caps = vdev_mlme->proto.vht_info.caps; + + value = mac->mlme_cfg->vht_caps.vht_cap_info.su_bformee; + value1 = mac->mlme_cfg->vht_caps.vht_cap_info.tx_bfee_ant_supp; + + vht_config.su_beam_formee = value; + + if (bcn_ie->VHTCaps.present) + vht_caps = &bcn_ie->VHTCaps; + else if (bcn_ie->vendor_vht_ie.VHTCaps.present) + vht_caps = &bcn_ie->vendor_vht_ie.VHTCaps; + /* Set BF CSN value only if SU Bformee is enabled */ + if (vht_caps && vht_config.su_beam_formee) { + tx_bf_csn = value1; + /* + * Certain commercial AP display a bad behavior when + * CSN value in assoc request is more than AP's CSN. + * Sending absolute self CSN value with such AP leads to + * IOT issues. However this issue is observed only with + * CSN cap of less than 4. To avoid such issues, take a + * min of self and peer CSN while sending ASSOC request. + */ + if (bcn_ie->Vendor1IE.present && + vht_caps->csnofBeamformerAntSup < 4) { + if (vht_caps->csnofBeamformerAntSup) + tx_bf_csn = QDF_MIN(tx_bf_csn, + vht_caps->csnofBeamformerAntSup); + } + } + vht_config.csnof_beamformer_antSup = tx_bf_csn; + + value = mac->mlme_cfg->vht_caps.vht_cap_info.su_bformer; + /* + * Set SU Bformer only if SU Bformer is enabled in INI + * and AP is SU Bformee capable + */ + if (value && !((IS_BSS_VHT_CAPABLE(bcn_ie->VHTCaps) && + bcn_ie->VHTCaps.suBeamformeeCap) || + (IS_BSS_VHT_CAPABLE(bcn_ie->vendor_vht_ie.VHTCaps) && + bcn_ie->vendor_vht_ie.VHTCaps.suBeamformeeCap))) + value = 0; + + vht_config.su_beam_former = value; + + /* Set num soundingdim value to 0 if SU Bformer is disabled */ + if (!vht_config.su_beam_former) + vht_config.num_soundingdim = 0; + + value = mac->mlme_cfg->vht_caps.vht_cap_info.enable_mu_bformee; + /* + * Set MU Bformee only if SU Bformee is enabled and + * MU Bformee is enabled in INI + */ + if (value && vht_config.su_beam_formee && + bcn_ie->VHTCaps.muBeamformerCap) + vht_config.mu_beam_formee = 1; + else + vht_config.mu_beam_formee = 0; + + if (IS_DOT11_MODE_VHT(session->dot11mode) && + session->opmode != QDF_STA_MODE) + vht_config.su_beam_formee = 0; + + session->vht_config = vht_config; + ht_caps.caps = vdev_mlme->proto.ht_info.ht_caps; + session->ht_config = ht_caps.ht_caps; + + if (session->opmode == QDF_STA_MODE) { + if (session->ht_config.short_gi_20_mhz) + session->ht_config.short_gi_20_mhz = + bcn_ie->HTCaps.shortGI20MHz; + + if (session->ht_config.short_gi_40_mhz) + session->ht_config.short_gi_40_mhz = + bcn_ie->HTCaps.shortGI40MHz; + } + + lim_revise_req_vht_cap_per_band(session); + pe_debug("HT cap 0x%x VHT cap 0x%x, AP cap sgi_20 %d sgi_40 %d", + ht_caps.caps, vht_config.caps, + bcn_ie->HTCaps.shortGI20MHz, bcn_ie->HTCaps.shortGI40MHz); +} + +bool +lim_get_vdev_rmf_capable(struct mac_context *mac, struct pe_session *session) +{ + struct wlan_objmgr_vdev *vdev; + int32_t rsn_caps; + bool peer_rmf_capable = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, + session->vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + pe_err("Invalid vdev"); + return false; + } + rsn_caps = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_RSN_CAP); + if (rsn_caps < 0) { + pe_err("Invalid mgmt cipher"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return false; + } + if (wlan_crypto_vdev_has_mgmtcipher( + vdev, + (1 << WLAN_CRYPTO_CIPHER_AES_GMAC) | + (1 << WLAN_CRYPTO_CIPHER_AES_GMAC_256) | + (1 << WLAN_CRYPTO_CIPHER_AES_CMAC)) && + (rsn_caps & WLAN_CRYPTO_RSN_CAP_MFP_ENABLED)) + peer_rmf_capable = true; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + return peer_rmf_capable; +} + +/** + * lim_get_nss_supported_by_sta_and_ap() - finds out nss from session + * and beacon from AP + * @vht_caps: VHT capabilities + * @ht_caps: HT capabilities + * @dot11_mode: dot11 mode + * + * Return: number of nss advertised by beacon + */ +static uint8_t +lim_get_nss_supported_by_sta_and_ap(tDot11fIEVHTCaps *vht_caps, + tDot11fIEHTCaps *ht_caps, + tDot11fIEhe_cap *he_cap, + enum mlme_dot11_mode dot11_mode) +{ + bool vht_capability, ht_capability, he_capability; + + vht_capability = IS_DOT11_MODE_VHT(dot11_mode); + ht_capability = IS_DOT11_MODE_HT(dot11_mode); + he_capability = IS_DOT11_MODE_HE(dot11_mode); + + if (he_capability && he_cap->present) { + if ((he_cap->rx_he_mcs_map_lt_80 & 0xC0) != 0xC0) + return NSS_4x4_MODE; + + if ((he_cap->rx_he_mcs_map_lt_80 & 0x30) != 0x30) + return NSS_3x3_MODE; + + if ((he_cap->rx_he_mcs_map_lt_80 & 0x0C) != 0x0C) + return NSS_2x2_MODE; + } else if (vht_capability && vht_caps->present) { + if ((vht_caps->rxMCSMap & 0xC0) != 0xC0) + return NSS_4x4_MODE; + + if ((vht_caps->rxMCSMap & 0x30) != 0x30) + return NSS_3x3_MODE; + + if ((vht_caps->rxMCSMap & 0x0C) != 0x0C) + return NSS_2x2_MODE; + } else if (ht_capability && ht_caps->present) { + if (ht_caps->supportedMCSSet[3]) + return NSS_4x4_MODE; + + if (ht_caps->supportedMCSSet[2]) + return NSS_3x3_MODE; + + if (ht_caps->supportedMCSSet[1]) + return NSS_2x2_MODE; + } + + return NSS_1x1_MODE; +} + +/** + * lim_check_vendor_ap_3_present() - Check if Vendor AP 3 is present + * @mac_ctx: Pointer to Global MAC structure + * @ie: Pointer to starting IE in Beacon/Probe Response + * @ie_len: Length of all IEs combined + * + * For Vendor AP 3, the condition is that Vendor AP 3 IE should be present + * and Vendor AP 4 IE should not be present. + * If Vendor AP 3 IE is present and Vendor AP 4 IE is also present, + * return false, else return true. + * + * Return: true or false + */ +static bool +lim_check_vendor_ap_3_present(struct mac_context *mac_ctx, uint8_t *ie, + uint16_t ie_len) +{ + bool ret = true; + + if ((wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_VENDOR_AP_3_OUI, + SIR_MAC_VENDOR_AP_3_OUI_LEN, ie, ie_len)) && + (wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_VENDOR_AP_4_OUI, + SIR_MAC_VENDOR_AP_4_OUI_LEN, ie, ie_len))) { + pe_debug("Vendor OUI 3 and Vendor OUI 4 found"); + ret = false; + } + + return ret; +} + +#ifdef WLAN_FEATURE_11AX +static void +lim_handle_iot_ap_no_common_he_rates(struct mac_context *mac, + struct pe_session *session, + tDot11fBeaconIEs *ies) +{ + uint16_t int_mcs; + struct wlan_objmgr_vdev *vdev = session->vdev; + struct mlme_legacy_priv *mlme_priv; + + /* if the connection is not 11AX mode then return */ + if (session->dot11mode != MLME_DOT11_MODE_11AX) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + int_mcs = HE_INTERSECT_MCS(mlme_priv->he_config.tx_he_mcs_map_lt_80, + ies->he_cap.rx_he_mcs_map_lt_80); + pe_debug("HE self rates %x AP rates %x int_mcs %x vendorIE %d", + mlme_priv->he_config.rx_he_mcs_map_lt_80, + ies->he_cap.rx_he_mcs_map_lt_80, int_mcs, + ies->vendor_vht_ie.present); + if (ies->he_cap.present) + if ((int_mcs == 0xFFFF) && + (ies->vendor_vht_ie.present || + ies->VHTCaps.present)) { + session->dot11mode = MLME_DOT11_MODE_11AC; + sme_debug("No common 11AX rate. Force 11AC connection"); + } +} +#else +static void lim_handle_iot_ap_no_common_he_rates(struct mac_context *mac, + struct pe_session *session, + tDot11fBeaconIEs *ies) +{ +} +#endif + +#ifdef WLAN_FEATURE_11AX + +/** + * lim_update_he_caps_htc() - Update htc in he caps + * @session: Pointer to PE session + * @val: htc he enabled status + * + * Return: void + */ +static void +lim_update_he_caps_htc(struct pe_session *session, bool val) +{ + struct wlan_objmgr_vdev *vdev = session->vdev; + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + pe_debug("new htc he: %d", val); + mlme_priv->he_config.htc_he = val; +} +#else + +static void +lim_update_he_caps_htc(struct pe_session *session, bool val) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +void +lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session) +{ + uint8_t tx_nss = 0; + uint8_t rx_nss = 0; + struct wlan_objmgr_vdev *vdev = session->vdev; + struct mlme_legacy_priv *mlme_priv; + struct wlan_mlme_cfg *mlme_cfg = mac->mlme_cfg; + tDot11fIEeht_cap *dot11_eht_cap; + tDot11fIEeht_cap *eht_config; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + eht_config = &mlme_priv->eht_config; + dot11_eht_cap = &mlme_cfg->eht_caps.dot11_eht_cap; + + if (session->nss == 1) { + tx_nss = 1; + rx_nss = 1; + } else { + tx_nss = dot11_eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7; + rx_nss = dot11_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7; + } + + if (!tx_nss || tx_nss > 2 || !rx_nss || rx_nss > 2) { + pe_err("invalid Nss values tx_nss: %u rx_nss: %u", + tx_nss, rx_nss); + return; + } + + eht_config->bw_20_rx_max_nss_for_mcs_0_to_7 = rx_nss; + eht_config->bw_20_tx_max_nss_for_mcs_0_to_7 = tx_nss; + eht_config->bw_20_rx_max_nss_for_mcs_8_and_9 = rx_nss; + eht_config->bw_20_tx_max_nss_for_mcs_8_and_9 = tx_nss; + if (dot11_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11) { + eht_config->bw_20_rx_max_nss_for_mcs_10_and_11 = rx_nss; + eht_config->bw_20_tx_max_nss_for_mcs_10_and_11 = tx_nss; + } + if (dot11_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13) { + eht_config->bw_20_rx_max_nss_for_mcs_12_and_13 = rx_nss; + eht_config->bw_20_tx_max_nss_for_mcs_12_and_13 = tx_nss; + } + eht_config->bw_le_80_rx_max_nss_for_mcs_0_to_9 = rx_nss; + eht_config->bw_le_80_tx_max_nss_for_mcs_0_to_9 = tx_nss; + if (dot11_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11) { + eht_config->bw_le_80_rx_max_nss_for_mcs_10_and_11 = rx_nss; + eht_config->bw_le_80_tx_max_nss_for_mcs_10_and_11 = tx_nss; + } + if (dot11_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13) { + eht_config->bw_le_80_rx_max_nss_for_mcs_12_and_13 = rx_nss; + eht_config->bw_le_80_tx_max_nss_for_mcs_12_and_13 = tx_nss; + } + eht_config->bw_160_rx_max_nss_for_mcs_0_to_9 = rx_nss; + eht_config->bw_160_tx_max_nss_for_mcs_0_to_9 = tx_nss; + if (dot11_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11) { + eht_config->bw_160_rx_max_nss_for_mcs_10_and_11 = rx_nss; + eht_config->bw_160_tx_max_nss_for_mcs_10_and_11 = tx_nss; + } + if (dot11_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13) { + eht_config->bw_160_rx_max_nss_for_mcs_12_and_13 = rx_nss; + eht_config->bw_160_tx_max_nss_for_mcs_12_and_13 = tx_nss; + } + eht_config->bw_320_rx_max_nss_for_mcs_0_to_9 = rx_nss; + eht_config->bw_320_tx_max_nss_for_mcs_0_to_9 = tx_nss; + + if (dot11_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11) { + eht_config->bw_320_rx_max_nss_for_mcs_10_and_11 = rx_nss; + eht_config->bw_320_tx_max_nss_for_mcs_10_and_11 = tx_nss; + } + if (dot11_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13) { + eht_config->bw_320_rx_max_nss_for_mcs_12_and_13 = rx_nss; + eht_config->bw_320_tx_max_nss_for_mcs_12_and_13 = tx_nss; + } +} +#endif + +static void lim_check_oui_and_update_session(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fBeaconIEs *ie_struct) +{ + struct action_oui_search_attr vendor_ap_search_attr = {0}; + uint16_t ie_len; + bool follow_ap_edca; + struct bss_description *bss_desc = + &session->lim_join_req->bssDescription; + bool is_vendor_ap_present; + uint8_t ap_nss; + struct vdev_type_nss *vdev_type_nss; + + if (wlan_reg_is_5ghz_ch_freq(bss_desc->chan_freq)) + vdev_type_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_type_nss = &mac_ctx->vdev_type_nss_2g; + + if (wlan_vdev_mlme_get_opmode(session->vdev) == QDF_P2P_CLIENT_MODE) + session->vdev_nss = vdev_type_nss->p2p_cli; + else + session->vdev_nss = vdev_type_nss->sta; + session->nss = session->vdev_nss; + + ie_len = wlan_get_ielen_from_bss_description(bss_desc); + + /* Fill the Vendor AP search params */ + vendor_ap_search_attr.ie_data = + (uint8_t *)&bss_desc->ieFields[0]; + vendor_ap_search_attr.ie_length = ie_len; + vendor_ap_search_attr.mac_addr = &bss_desc->bssId[0]; + ap_nss = lim_get_nss_supported_by_sta_and_ap( + &ie_struct->VHTCaps, &ie_struct->HTCaps, + &ie_struct->he_cap, session->dot11mode); + vendor_ap_search_attr.nss = ap_nss; + vendor_ap_search_attr.ht_cap = ie_struct->HTCaps.present; + vendor_ap_search_attr.vht_cap = ie_struct->VHTCaps.present; + vendor_ap_search_attr.enable_2g = + wlan_reg_is_24ghz_ch_freq(bss_desc->chan_freq); + vendor_ap_search_attr.enable_5g = + wlan_reg_is_5ghz_ch_freq(bss_desc->chan_freq); + + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2) { + session->nss = 1; + session->vdev_nss = 1; + } + + /* + * If CCK WAR is set for current AP, update to firmware via + * wmi_vdev_param_abg_mode_tx_chain_num + */ + is_vendor_ap_present = + wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_CCKM_1X1); + if (is_vendor_ap_present) { + pe_debug("vdev: %d wmi_vdev_param_abg_mode_tx_chain_num 1", + session->vdev_id); + wma_cli_set_command(session->vdev_id, + (int)wmi_vdev_param_abg_mode_tx_chain_num, 1, + VDEV_CMD); + } + + /* + * If Switch to 11N WAR is set for current AP, change dot11 + * mode to 11N. + */ + is_vendor_ap_present = + wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_SWITCH_TO_11N_MODE); + if (mac_ctx->roam.configParam.is_force_1x1 && + mac_ctx->mlme_cfg->gen.as_enabled && + is_vendor_ap_present && + (session->dot11mode == MLME_DOT11_MODE_ALL || + session->dot11mode == MLME_DOT11_MODE_11AC || + session->dot11mode == MLME_DOT11_MODE_11AC_ONLY)) + session->dot11mode = MLME_DOT11_MODE_11N; + + follow_ap_edca = wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_DISABLE_AGGRESSIVE_EDCA); + mlme_set_follow_ap_edca_flag(session->vdev, follow_ap_edca); + + if (wlan_action_oui_search(mac_ctx->psoc, &vendor_ap_search_attr, + ACTION_OUI_HOST_RECONN)) { + mlme_set_reconn_after_assoc_timeout_flag( + mac_ctx->psoc, session->vdev_id, + true); + } + is_vendor_ap_present = + wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_CONNECT_1X1); + + if (is_vendor_ap_present) { + is_vendor_ap_present = lim_check_vendor_ap_3_present( + mac_ctx, + vendor_ap_search_attr.ie_data, + ie_len); + } + + /* + * For WMI_ACTION_OUI_CONNECT_1x1_WITH_1_CHAIN, the host + * sends the NSS as 1 to the FW and the FW then decides + * after receiving the first beacon after connection to + * switch to 1 Tx/Rx Chain. + */ + + if (!is_vendor_ap_present) { + is_vendor_ap_present = + wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_CONNECT_1X1_WITH_1_CHAIN); + if (is_vendor_ap_present) + pe_debug("1x1 with 1 Chain AP"); + } + + if (is_vendor_ap_present && + !policy_mgr_is_hw_dbs_2x2_capable(mac_ctx->psoc) && + ((mac_ctx->roam.configParam.is_force_1x1 == + FORCE_1X1_ENABLED_FOR_AS && + mac_ctx->mlme_cfg->gen.as_enabled) || + mac_ctx->roam.configParam.is_force_1x1 == + FORCE_1X1_ENABLED_FORCED)) { + session->vdev_nss = 1; + session->nss = 1; + session->nss_forced_1x1 = true; + pe_debug("For special ap, NSS: %d force 1x1 %d", + session->nss, + mac_ctx->roam.configParam.is_force_1x1); + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq) && + wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_AUTH_ASSOC_6MBPS_2GHZ)) { + session->is_oui_auth_assoc_6mbps_2ghz_enable = true; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq) && + !mac_ctx->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band && + session->dot11mode == MLME_DOT11_MODE_11AC) { + /* Need to disable VHT operation in 2.4 GHz band */ + session->dot11mode = MLME_DOT11_MODE_11N; + } + + lim_handle_iot_ap_no_common_he_rates(mac_ctx, session, ie_struct); + lim_update_he_caps_mcs(mac_ctx, session); + lim_update_eht_caps_mcs(mac_ctx, session); + + is_vendor_ap_present = wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI, + SIR_MAC_BA_2K_JUMP_AP_VENDOR_OUI_LEN, + vendor_ap_search_attr.ie_data, ie_len); + wlan_mlme_set_ba_2k_jump_iot_ap(session->vdev, is_vendor_ap_present); + + is_vendor_ap_present = wlan_get_vendor_ie_ptr_from_oui + (SIR_MAC_BAD_HTC_HE_VENDOR_OUI1, + SIR_MAC_BAD_HTC_HE_VENDOR_OUI_LEN, + vendor_ap_search_attr.ie_data, ie_len) && + wlan_get_vendor_ie_ptr_from_oui + (SIR_MAC_BAD_HTC_HE_VENDOR_OUI2, + SIR_MAC_BAD_HTC_HE_VENDOR_OUI_LEN, + vendor_ap_search_attr.ie_data, ie_len); + + /* + * For SAP with special OUI, if DUT STA connect with 11ax mode with ht + * control enabled, SAP can't decode unicast pkt from DUT. + * Fix it by clearing ht control bit in he cap when send peer assoc cmd + * to firmware when connect such IOT AP with 11ax mode. + * New requirement is to change default setting for HT control to false. + */ + if (is_vendor_ap_present) + lim_update_he_caps_htc(session, !is_vendor_ap_present); +} + +static enum mlme_dot11_mode +lim_get_user_dot11_mode(struct wlan_objmgr_vdev *vdev) +{ + WMI_HOST_WIFI_STANDARD wifi_std; + + wifi_std = mlme_get_vdev_wifi_std(vdev); + + switch (wifi_std) { + case WMI_HOST_WIFI_STANDARD_4: + return MLME_DOT11_MODE_11N; + case WMI_HOST_WIFI_STANDARD_5: + return MLME_DOT11_MODE_11AC; + case WMI_HOST_WIFI_STANDARD_6: + case WMI_HOST_WIFI_STANDARD_6E: + return MLME_DOT11_MODE_11AX; + case WMI_HOST_WIFI_STANDARD_7: + default: + return MLME_DOT11_MODE_11BE; + } +} + +static enum mlme_dot11_mode +lim_intersect_user_dot11_mode(struct mac_context *mac_ctx, + enum QDF_OPMODE opmode, uint8_t vdev_id, + enum mlme_dot11_mode self_mode) +{ + struct wlan_objmgr_vdev *vdev; + enum mlme_dot11_mode user_mode; + + switch (opmode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + break; + default: + return self_mode; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) + return self_mode; + + user_mode = lim_get_user_dot11_mode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + return user_mode > self_mode ? self_mode : user_mode; +} + +static enum mlme_dot11_mode +lim_get_self_dot11_mode(struct mac_context *mac_ctx, enum QDF_OPMODE opmode, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *vdev_mlme; + enum mlme_vdev_dot11_mode vdev_dot11_mode; + enum mlme_dot11_mode self_dot11_mode = + mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + + switch (opmode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + break; + default: + return self_dot11_mode; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) + return self_dot11_mode; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return self_dot11_mode; + } + + vdev_dot11_mode = vdev_mlme->proto.vdev_dot11_mode; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + if (vdev_dot11_mode == MLME_VDEV_DOT11_MODE_AUTO) + return self_dot11_mode; + + if (IS_DOT11_MODE_HT(self_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11N) + return MLME_DOT11_MODE_11N; + + if (IS_DOT11_MODE_VHT(self_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11AC) + return MLME_DOT11_MODE_11AC; + + if (IS_DOT11_MODE_HE(self_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11AX) + return MLME_DOT11_MODE_11AX; + + if (IS_DOT11_MODE_EHT(self_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11BE) + return MLME_DOT11_MODE_11BE; + + return self_dot11_mode; +} + +static bool +lim_get_bss_11be_mode_allowed(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs *ie_struct) +{ + struct scan_cache_entry *scan_entry; + bool is_eht_allowed; + + if (!ie_struct->eht_cap.present) + return false; + + scan_entry = wlan_scan_get_entry_by_bssid(mac_ctx->pdev, + (struct qdf_mac_addr *) + bss_desc->bssId); + + /* + * If AP advertises multiple AKMs(WPA2 PSK + WPA3), allow connection + * in 11BE mode as our connection is going to be WPA3 + */ + if (scan_entry) { + is_eht_allowed = + wlan_cm_is_eht_allowed_for_current_security( + wlan_pdev_get_psoc(mac_ctx->pdev), + scan_entry, false); + util_scan_free_cache_entry(scan_entry); + if (!is_eht_allowed) { + pe_debug("Downgrade to 11ax mode due to AP security validation failure"); + return false; + } + } + return mlme_get_bss_11be_allowed( + mac_ctx->psoc, + (struct qdf_mac_addr *)&bss_desc->bssId, + (uint8_t *)&bss_desc->ieFields[0], + wlan_get_ielen_from_bss_description(bss_desc)); +} + +static enum mlme_dot11_mode +lim_get_bss_dot11_mode(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs *ie_struct) +{ + enum mlme_dot11_mode bss_dot11_mode; + + switch (bss_desc->nwType) { + case eSIR_11B_NW_TYPE: + return MLME_DOT11_MODE_11B; + case eSIR_11A_NW_TYPE: + bss_dot11_mode = MLME_DOT11_MODE_11A; + break; + case eSIR_11G_NW_TYPE: + bss_dot11_mode = MLME_DOT11_MODE_11G; + break; + default: + if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) + bss_dot11_mode = MLME_DOT11_MODE_11G; + else + bss_dot11_mode = MLME_DOT11_MODE_11A; + } + + if (ie_struct->HTCaps.present) + bss_dot11_mode = MLME_DOT11_MODE_11N; + + if (IS_BSS_VHT_CAPABLE(ie_struct->VHTCaps) || + IS_BSS_VHT_CAPABLE(ie_struct->vendor_vht_ie.VHTCaps)) + bss_dot11_mode = MLME_DOT11_MODE_11AC; + + if (ie_struct->he_cap.present) + bss_dot11_mode = MLME_DOT11_MODE_11AX; + + if (ie_struct->eht_cap.present && + lim_get_bss_11be_mode_allowed(mac_ctx, bss_desc, ie_struct)) + bss_dot11_mode = MLME_DOT11_MODE_11BE; + + return bss_dot11_mode; +} + +static QDF_STATUS +lim_handle_11abg_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + struct bss_description *bss_desc) +{ + if (!WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq) && + !WLAN_REG_IS_5GHZ_CH_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11ABG, BSS freq %d not 2.4 or 5 GHz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11B: + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + *intersected_mode = MLME_DOT11_MODE_11A; + break; + case MLME_DOT11_MODE_11G: + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11N: + fallthrough; + case MLME_DOT11_MODE_11AC: + fallthrough; + case MLME_DOT11_MODE_11AX: + fallthrough; + case MLME_DOT11_MODE_11BE: + if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) + *intersected_mode = MLME_DOT11_MODE_11G; + else + *intersected_mode = MLME_DOT11_MODE_11A; + break; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11a_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + struct bss_description *bss_desc) +{ + if (!WLAN_REG_IS_5GHZ_CH_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11A and bss freq %d not 5ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11G: + /* Self 11A and BSS 11B/G cannot connect */ + pe_err("Self dot11mode 11A, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + case MLME_DOT11_MODE_11A: + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11BE: + *intersected_mode = MLME_DOT11_MODE_11A; + break; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11b_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + struct bss_description *bss_desc) +{ + if (!WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11B and bss freq %d not 2.4ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11BE: + /* Self 11B and BSS 11A cannot connect */ + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11B, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11g_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + struct bss_description *bss_desc) +{ + if (!WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11G and bss freq %d not 2.4ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11BE: + /* Self 11B and BSS 11A cannot connect */ + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11B: + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11G, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11n_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct, + struct bss_description *bss_desc) +{ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11N and bss freq %d is 6ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + *intersected_mode = MLME_DOT11_MODE_11N; + break; + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11BE: + case MLME_DOT11_MODE_11AX: + if (ie_struct->HTCaps.present) { + *intersected_mode = MLME_DOT11_MODE_11N; + break; + } + if (WLAN_REG_IS_5GHZ_CH_FREQ(bss_desc->chan_freq)) + *intersected_mode = MLME_DOT11_MODE_11A; + else + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11G: + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11B: + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + *intersected_mode = MLME_DOT11_MODE_11A; + break; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11ac_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct, + struct bss_description *bss_desc) +{ + bool vht_capable = false; + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11AC and bss freq %d is 6ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + if (IS_BSS_VHT_CAPABLE(ie_struct->VHTCaps) || + IS_BSS_VHT_CAPABLE(ie_struct->vendor_vht_ie.VHTCaps)) + vht_capable = true; + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + *intersected_mode = MLME_DOT11_MODE_11N; + break; + case MLME_DOT11_MODE_11AC: + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11BE: + if (vht_capable) { + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + } + if (ie_struct->HTCaps.present) { + *intersected_mode = MLME_DOT11_MODE_11N; + break; + } + if (WLAN_REG_IS_5GHZ_CH_FREQ(bss_desc->chan_freq)) + *intersected_mode = MLME_DOT11_MODE_11A; + else + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11G: + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11B: + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + *intersected_mode = MLME_DOT11_MODE_11A; + break; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11ax_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct, + struct bss_description *bss_desc) +{ + bool vht_capable = false; + + if (IS_BSS_VHT_CAPABLE(ie_struct->VHTCaps) || + IS_BSS_VHT_CAPABLE(ie_struct->vendor_vht_ie.VHTCaps)) + vht_capable = true; + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + *intersected_mode = MLME_DOT11_MODE_11N; + break; + case MLME_DOT11_MODE_11AC: + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + case MLME_DOT11_MODE_11AX: + *intersected_mode = MLME_DOT11_MODE_11AX; + break; + case MLME_DOT11_MODE_11BE: + if (ie_struct->he_cap.present) { + *intersected_mode = MLME_DOT11_MODE_11AX; + break; + } + if (vht_capable) { + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + } + if (ie_struct->HTCaps.present) { + *intersected_mode = MLME_DOT11_MODE_11N; + break; + } + if (WLAN_REG_IS_5GHZ_CH_FREQ(bss_desc->chan_freq)) { + *intersected_mode = MLME_DOT11_MODE_11A; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) { + *intersected_mode = MLME_DOT11_MODE_11G; + } else { + pe_err("Invalid bss dot11mode %d freq %d", + bss_dot11_mode, bss_desc->chan_freq); + return QDF_STATUS_E_FAILURE; + } + break; + case MLME_DOT11_MODE_11G: + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11B: + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + *intersected_mode = MLME_DOT11_MODE_11A; + break; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11be_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode) +{ + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + *intersected_mode = MLME_DOT11_MODE_11N; + break; + case MLME_DOT11_MODE_11AC: + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + case MLME_DOT11_MODE_11AX: + *intersected_mode = MLME_DOT11_MODE_11AX; + break; + case MLME_DOT11_MODE_11BE: + *intersected_mode = MLME_DOT11_MODE_11BE; + break; + case MLME_DOT11_MODE_11G: + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11B: + *intersected_mode = MLME_DOT11_MODE_11B; + break; + case MLME_DOT11_MODE_11A: + *intersected_mode = MLME_DOT11_MODE_11A; + break; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11g_only_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + struct bss_description *bss_desc) +{ + if (!WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11G ONLY and bss freq %d not 2.4ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11BE: + /* Self 11B and BSS 11A cannot connect */ + *intersected_mode = MLME_DOT11_MODE_11G; + break; + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11G only, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11n_only_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct, + struct bss_description *bss_desc) +{ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11N ONLY and bss freq %d is 6ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11N: + *intersected_mode = MLME_DOT11_MODE_11N; + break; + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11BE: + if (ie_struct->HTCaps.present) { + *intersected_mode = MLME_DOT11_MODE_11N; + break; + } + pe_err("Self dot11mode is 11N ONLY peer is not HT capable"); + return QDF_STATUS_E_INVAL; + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11N only, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11ac_only_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct, + struct bss_description *bss_desc) +{ + bool vht_capable = false; + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(bss_desc->chan_freq)) { + pe_err("self Dot11mode is 11AC and bss freq %d is 6ghz", + bss_desc->chan_freq); + return QDF_STATUS_E_INVAL; + } + + if (IS_BSS_VHT_CAPABLE(ie_struct->VHTCaps) || + IS_BSS_VHT_CAPABLE(ie_struct->vendor_vht_ie.VHTCaps)) + vht_capable = true; + + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11AC: + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11BE: + if (vht_capable) { + *intersected_mode = MLME_DOT11_MODE_11AC; + break; + } + pe_err("Self dot11mode is 11AC ONLY peer is not VHT capable"); + return QDF_STATUS_E_INVAL; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11AC only, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11ax_only_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct) +{ + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11AX: + *intersected_mode = MLME_DOT11_MODE_11AX; + break; + case MLME_DOT11_MODE_11BE: + if (ie_struct->he_cap.present) { + *intersected_mode = MLME_DOT11_MODE_11AX; + break; + } + fallthrough; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11AX only, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_handle_11be_only_dot11_mode(enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode) +{ + switch (bss_dot11_mode) { + case MLME_DOT11_MODE_11BE: + *intersected_mode = MLME_DOT11_MODE_11BE; + break; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11A: + pe_err("Self dot11mode 11BE only, bss dot11mode %d not compatible", + bss_dot11_mode); + return QDF_STATUS_E_INVAL; + default: + pe_err("Invalid bss dot11mode %d passed", bss_dot11_mode); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_get_intersected_dot11_mode_sta_ap(struct mac_context *mac_ctx, + enum mlme_dot11_mode self_dot11_mode, + enum mlme_dot11_mode bss_dot11_mode, + enum mlme_dot11_mode *intersected_mode, + tDot11fBeaconIEs *ie_struct, + struct bss_description *bss_desc) +{ + switch (self_dot11_mode) { + case MLME_DOT11_MODE_ALL: + *intersected_mode = bss_dot11_mode; + return QDF_STATUS_SUCCESS; + case MLME_DOT11_MODE_11A: + return lim_handle_11a_dot11_mode(bss_dot11_mode, + intersected_mode, bss_desc); + case MLME_DOT11_MODE_11B: + return lim_handle_11b_dot11_mode(bss_dot11_mode, + intersected_mode, bss_desc); + case MLME_DOT11_MODE_11G: + return lim_handle_11g_dot11_mode(bss_dot11_mode, + intersected_mode, bss_desc); + case MLME_DOT11_MODE_11N: + return lim_handle_11n_dot11_mode(bss_dot11_mode, + intersected_mode, ie_struct, + bss_desc); + case MLME_DOT11_MODE_11G_ONLY: + return lim_handle_11g_only_dot11_mode(bss_dot11_mode, + intersected_mode, + bss_desc); + case MLME_DOT11_MODE_11N_ONLY: + return lim_handle_11n_only_dot11_mode(bss_dot11_mode, + intersected_mode, + ie_struct, + bss_desc); + case MLME_DOT11_MODE_11AC: + return lim_handle_11ac_dot11_mode(bss_dot11_mode, + intersected_mode, ie_struct, + bss_desc); + case MLME_DOT11_MODE_11AC_ONLY: + return lim_handle_11ac_only_dot11_mode(bss_dot11_mode, + intersected_mode, + ie_struct, + bss_desc); + case MLME_DOT11_MODE_11AX: + return lim_handle_11ax_dot11_mode(bss_dot11_mode, + intersected_mode, + ie_struct, + bss_desc); + case MLME_DOT11_MODE_11AX_ONLY: + return lim_handle_11ax_only_dot11_mode(bss_dot11_mode, + intersected_mode, + ie_struct); + case MLME_DOT11_MODE_11BE: + return lim_handle_11be_dot11_mode(bss_dot11_mode, + intersected_mode); + case MLME_DOT11_MODE_11BE_ONLY: + return lim_handle_11be_only_dot11_mode(bss_dot11_mode, + intersected_mode); + case MLME_DOT11_MODE_ABG: + return lim_handle_11abg_dot11_mode(bss_dot11_mode, + intersected_mode, bss_desc); + default: + pe_err("Invalid self dot11mode %d not supported", + self_dot11_mode); + return QDF_STATUS_E_FAILURE; + } +} + +static void +lim_verify_dot11_mode_with_crypto(struct pe_session *session) +{ + struct bss_description *bss_desc = + &session->lim_join_req->bssDescription; + int32_t ucast_cipher; + + if (!(session->dot11mode == MLME_DOT11_MODE_11N || + session->dot11mode == MLME_DOT11_MODE_11AC || + session->dot11mode == MLME_DOT11_MODE_11AX || + session->dot11mode == MLME_DOT11_MODE_11BE)) + return; + + ucast_cipher = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + if (ucast_cipher == -1) + return; + + if (!((ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_TKIP)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_40)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_104)))) + return; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq)) + session->dot11mode = MLME_DOT11_MODE_11G; + else + session->dot11mode = MLME_DOT11_MODE_11A; + + pe_info("HT not supported with TKIP/WEP overriding dot11mode to %d", + session->dot11mode); + + session->he_with_wep_tkip = + session->mac_ctx->roam.configParam.wep_tkip_in_he; +} + +static QDF_STATUS +lim_fill_dot11_mode(struct mac_context *mac_ctx, struct pe_session *session, + tDot11fBeaconIEs *ie_struct) +{ + struct bss_description *bss_desc = + &session->lim_join_req->bssDescription; + QDF_STATUS status; + enum mlme_dot11_mode self_dot11_mode; + enum mlme_dot11_mode bss_dot11_mode; + enum mlme_dot11_mode intersected_mode; + + self_dot11_mode = lim_get_self_dot11_mode(mac_ctx, session->opmode, + session->vdev_id); + + /* if user set dot11 mode by cmd, need to do intersect first */ + self_dot11_mode = + lim_intersect_user_dot11_mode(mac_ctx, session->opmode, + session->vdev_id, + self_dot11_mode); + + bss_dot11_mode = lim_get_bss_dot11_mode(mac_ctx, bss_desc, ie_struct); + + status = lim_get_intersected_dot11_mode_sta_ap(mac_ctx, self_dot11_mode, + bss_dot11_mode, + &intersected_mode, + ie_struct, bss_desc); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + pe_debug("vdev id %d opmode %d self dot11mode %d bss_dot11 mode %d intersected %d", + session->vdev_id, session->opmode, self_dot11_mode, + bss_dot11_mode, intersected_mode); + + if (wlan_vdev_mlme_is_mlo_link_vdev(session->vdev) && + !IS_DOT11_MODE_EHT(intersected_mode)) + return QDF_STATUS_E_INVAL; + + session->dot11mode = intersected_mode; + lim_verify_dot11_mode_with_crypto(session); + + return status; +} + +#ifdef WLAN_FEATURE_11AX +static bool lim_enable_twt(struct mac_context *mac_ctx, tDot11fBeaconIEs *ie) +{ + struct s_ext_cap *ext_cap; + bool twt_support_in_11n = false; + bool twt_request = false; + + if (!ie) { + pe_debug("ie is null"); + return false; + } + + wlan_twt_cfg_get_support_requestor(mac_ctx->psoc, &twt_request); + if (twt_request && (ie->qcn_ie.present || ie->he_cap.twt_responder)) { + pe_debug("TWT is supported, hence disable UAPSD; twt req supp: %d,twt respon supp: %d, QCN_IE: %d", + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.twt_request, + ie->he_cap.twt_responder, + ie->qcn_ie.present); + return true; + } + + wlan_twt_cfg_get_support_in_11n(mac_ctx->psoc, + &twt_support_in_11n); + ext_cap = (struct s_ext_cap *)ie->ExtCap.bytes; + if (twt_support_in_11n && ie->ExtCap.present && + ext_cap->twt_responder_support) { + pe_debug("TWT is supported for 11n, twt_support_in_11n %d, ext_cap %d, twt_responder support %d", + twt_support_in_11n, ie->ExtCap.present, + ext_cap->twt_responder_support); + return true; + } + + return false; +} +#else +static inline bool +lim_enable_twt(struct mac_context *mac_ctx, tDot11fBeaconIEs *ie) +{ + return false; +} +#endif + +static int8_t lim_get_cfg_max_tx_power(struct mac_context *mac, + uint32_t ch_freq) +{ + return wlan_get_cfg_max_tx_power(mac->psoc, mac->pdev, ch_freq); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +static inline void lim_fill_rssi(struct pe_session *session, + struct bss_description *bss_desc) +{ + session->rssi = bss_desc->rssi; +} +#else +static inline void lim_fill_rssi(struct pe_session *session, + struct bss_description *bss_desc) +{ +} +#endif + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * lim_update_sae_single_pmk_ap_cap() - Function to update sae single pmk ap ie + * @mac: pointer to mac context + * @session: pe session + * + * Return: set sae single pmk feature + */ +static void +lim_update_sae_single_pmk_ap_cap(struct mac_context *mac, + struct pe_session *session) +{ + int32_t akm; + + akm = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + + if ((QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) && + mac->mlme_cfg->lfr.sae_single_pmk_feature_enabled) + wlan_mlme_set_sae_single_pmk_bss_cap(mac->psoc, + session->vdev_id, + session->lim_join_req->bssDescription.is_single_pmk); + +} +#else +static inline void +lim_update_sae_single_pmk_ap_cap(struct mac_context *mac, + struct pe_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static void lim_get_mld_peer(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ + struct wlan_objmgr_peer *peer; + + if (!vdev || !wlan_vdev_mlme_is_mlo_vdev(vdev)) + return; + + peer = wlan_vdev_get_bsspeer(vdev); + if (!peer) + return; + + qdf_mem_copy(bssid->bytes, peer->mldaddr, QDF_MAC_ADDR_SIZE); +} +#else +static void lim_get_mld_peer(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *bssid) +{ +} +#endif + +#ifdef WLAN_FEATURE_SAE +static void lim_update_sae_config(struct mac_context *mac, + struct pe_session *session) +{ + struct wlan_crypto_pmksa *pmksa; + struct qdf_mac_addr bssid; + struct bss_description *bss_desc; + struct action_oui_search_attr ap_attr = {0}; + bool is_vendor_ap = false; + + qdf_mem_copy(bssid.bytes, session->bssId, + QDF_MAC_ADDR_SIZE); + + /* For MLO connection, override BSSID with peer mldaddr */ + lim_get_mld_peer(session->vdev, &bssid); + + pmksa = wlan_crypto_get_pmksa(session->vdev, &bssid); + if (!pmksa) + return; + + bss_desc = &session->lim_join_req->bssDescription; + ap_attr.ie_data = (uint8_t *)&bss_desc->ieFields[0]; + ap_attr.ie_length = + wlan_get_ielen_from_bss_description(bss_desc); + is_vendor_ap = wlan_action_oui_search(mac->psoc, + &ap_attr, + ACTION_OUI_RESTRICT_MAX_MLO_LINKS); + if (is_vendor_ap) + return; + + session->sae_pmk_cached = true; + pe_debug("PMKSA Found for BSSID=" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); +} +#else +static inline void lim_update_sae_config(struct mac_context *mac, + struct pe_session *session) +{ } +#endif + +static void +lim_fill_11r_params(struct mac_context *mac_ctx, struct pe_session *session, + bool ese_version_present) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(mac_ctx->psoc); + if (!mlme_obj) + return; + if (wlan_cm_is_auth_type_11r(mlme_obj, session->vdev, + session->lim_join_req->bssDescription.mdiePresent) && + !cm_ese_open_present(session->vdev, mlme_obj, ese_version_present)) + session->is11Rconnection = true; +} + +#ifdef FEATURE_WLAN_ESE +static void +lim_fill_ese_params(struct mac_context *mac_ctx, struct pe_session *session, + bool ese_version_present) +{ + wlan_cm_set_ese_assoc(mac_ctx->pdev, session->vdev_id, + cm_is_ese_connection(session->vdev, + ese_version_present)); +} +#else +static inline void +lim_fill_ese_params(struct mac_context *mac_ctx, struct pe_session *session, + bool ese_version_present) +{ +} +#endif + +void lim_get_basic_rates(tSirMacRateSet *b_rates, uint32_t chan_freq) +{ + /* + * Some IOT APs don't send supported rates in + * probe resp, hence add BSS basic rates in + * supported rates IE of assoc request. + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) + wlan_populate_basic_rates(b_rates, false, true); + else if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) + wlan_populate_basic_rates(b_rates, true, true); +} + +/* + * lim_iterate_triplets() - Iterate the country IE to validate it + * @country_ie: country IE to iterate through + * + * This function always returns success because connection should not be failed + * in the case of missing elements in the country IE + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_iterate_triplets(tDot11fIECountry country_ie) +{ + u_int8_t i; + + if (country_ie.first_triplet[0] > OP_CLASS_ID_200) { + if (country_ie.more_triplets[0][0] <= OP_CLASS_ID_200) + return QDF_STATUS_SUCCESS; + } + + for (i = 0; i < country_ie.num_more_triplets; i++) { + if ((country_ie.more_triplets[i][0] > OP_CLASS_ID_200) && + (i < country_ie.num_more_triplets - 1)) { + if (country_ie.more_triplets[i + 1][0] <= + OP_CLASS_ID_200) + return QDF_STATUS_SUCCESS; + } + } + pe_debug("No operating class triplet followed by sub-band triplet"); + + return QDF_STATUS_SUCCESS; +} + +static bool lim_is_bss_description_wme(struct mac_context *mac, + tDot11fBeaconIEs *ie_struct) +{ + + if (!(ie_struct->WMMParams.present || ie_struct->WMMInfoAp.present)) + return false; + if (mac->roam.configParam.WMMSupportMode == WMM_USER_MODE_NO_QOS && + !ie_struct->HTCaps.present) + return false; + + return true; +} + +static enum medium_access_type +lim_get_qos_from_bss_desc(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs *ie_struct) +{ + enum medium_access_type qos_type = MEDIUM_ACCESS_DCF; + tSirMacCapabilityInfo *ap_cap_info; + + /* + * If we find WMM in the Bss Description, then we let this + * override and use WMM. + */ + if (lim_is_bss_description_wme(mac_ctx, ie_struct)) + return MEDIUM_ACCESS_WMM_EDCF_DSCP; + + ap_cap_info = (tSirMacCapabilityInfo *)&bss_desc->capabilityInfo; + /* If the QoS bit is on, then the AP is advertising 11E QoS. */ + if (ap_cap_info->qos) + qos_type = MEDIUM_ACCESS_11E_EDCF; + + if (qos_type == MEDIUM_ACCESS_11E_EDCF && + !mac_ctx->roam.configParam.Is11eSupportEnabled) + qos_type = MEDIUM_ACCESS_DCF; + + return qos_type; +} + +static void lim_set_qos_to_cfg(struct pe_session *session, + enum medium_access_type qos_type) +{ + bool qos_enabled; + bool wme_enabled; + + switch (qos_type) { + case MEDIUM_ACCESS_WMM_EDCF_DSCP: + qos_enabled = false; + wme_enabled = true; + break; + case MEDIUM_ACCESS_11E_EDCF: + qos_enabled = true; + wme_enabled = false; + break; + default: + case MEDIUM_ACCESS_DCF: + qos_enabled = false; + wme_enabled = false; + break; + } + + session->limWmeEnabled = wme_enabled; + session->limQosEnabled = qos_enabled; +} + +static void lim_update_qos(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_description *bss_desc, + tDot11fBeaconIEs *ie_struct) +{ + struct mlme_legacy_priv *mlme_priv; + enum medium_access_type qos_type; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + + qos_type = lim_get_qos_from_bss_desc(mac_ctx, bss_desc, ie_struct); + + if ((session->dot11mode != MLME_DOT11_MODE_11N) && + (mac_ctx->roam.configParam.WMMSupportMode == + WMM_USER_MODE_NO_QOS)) { + /* + * Joining BSS is not 11n capable and WMM is disabled on client. + * Disable QoS and WMM + */ + qos_type = MEDIUM_ACCESS_DCF; + } + + if ((session->dot11mode == MLME_DOT11_MODE_11N || + session->dot11mode == MLME_DOT11_MODE_11AC) && + (qos_type != MEDIUM_ACCESS_WMM_EDCF_DSCP && + qos_type != MEDIUM_ACCESS_11E_EDCF)) { + /* + * Joining BSS is 11n capable and WMM is disabled on AP. + * Assume all HT AP's are QOS AP's and enable WMM + */ + qos_type = MEDIUM_ACCESS_WMM_EDCF_DSCP; + } + + lim_set_qos_to_cfg(session, qos_type); + mlme_priv->connect_info.qos_enabled = session->limWmeEnabled; + pe_debug("qos_type %d QOS %d WMM %d", qos_type, + session->limQosEnabled, + session->limWmeEnabled); +} + +static void lim_reset_self_ocv_caps(struct pe_session *session) +{ + uint16_t self_rsn_cap; + + self_rsn_cap = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_RSN_CAP); + if (self_rsn_cap == -1) + return; + + self_rsn_cap &= ~WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED; + + /* Update the new rsn caps */ + wlan_crypto_set_vdev_param(session->vdev, WLAN_CRYPTO_PARAM_RSN_CAP, + self_rsn_cap); + +} + +bool lim_enable_cts_to_self_for_exempted_iot_ap( + struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *ie_ptr, + uint16_t ie_len) +{ + struct action_oui_search_attr vendor_ap_search_attr = {0}; + + vendor_ap_search_attr.ie_data = ie_ptr; + vendor_ap_search_attr.ie_length = ie_len; + + if (wlan_action_oui_search(mac_ctx->psoc, &vendor_ap_search_attr, + ACTION_OUI_ENABLE_CTS2SELF)) { + pe_debug("vdev %d: enable cts to self", session->vdev_id); + wma_cli_set_command(session->vdev_id, + wmi_vdev_param_enable_rtscts, + FW_CTS2SELF_PROFILE, VDEV_CMD); + return true; + } + return false; +} + +/** + * lim_disable_bformee_for_iot_ap() - disable bformee for iot ap + *@mac_ctx: mac context + *@session: pe session + *@bss_desc: bss descriptor + * + * When connect IoT AP with BW 160MHz and NSS 2, disable Beamformee + * + * Return: None + */ +static void +lim_disable_bformee_for_iot_ap(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_description *bss_desc) +{ + struct action_oui_search_attr vendor_ap_search_attr = {0}; + uint16_t ie_len; + + ie_len = wlan_get_ielen_from_bss_description(bss_desc); + + vendor_ap_search_attr.ie_data = (uint8_t *)&bss_desc->ieFields[0]; + vendor_ap_search_attr.ie_length = ie_len; + + if (wlan_action_oui_search(mac_ctx->psoc, + &vendor_ap_search_attr, + ACTION_OUI_DISABLE_BFORMEE) && + session->nss == 2 && CH_WIDTH_160MHZ == session->ch_width) { + session->vht_config.su_beam_formee = 0; + session->vht_config.mu_beam_formee = 0; + pe_debug("IoT ap with BW 160 MHz NSS 2, disable Beamformee"); + } +} + +QDF_STATUS +lim_fill_pe_session(struct mac_context *mac_ctx, struct pe_session *session, + struct bss_description *bss_desc) +{ + uint8_t bss_chan_id; + tDot11fBeaconIEs *ie_struct; + QDF_STATUS status; + ePhyChanBondState cb_mode; + const uint8_t *vendor_ie; + uint16_t ie_len; + int8_t local_power_constraint = 0; + struct vdev_mlme_obj *mlme_obj; + bool is_pwr_constraint = false; + tSirMacCapabilityInfo *ap_cap_info; + uint8_t wmm_mode, value; + struct wlan_mlme_lfr_cfg *lfr = &mac_ctx->mlme_cfg->lfr; + struct cm_roam_values_copy config = {}; + bool ese_ver_present; + int8_t reg_max; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = + &ps_global_info->ps_params[session->vdev_id]; + uint32_t timeout; + enum reg_6g_ap_type power_type_6g; + struct cm_roam_values_copy temp; + uint32_t neighbor_lookup_threshold; + uint32_t hi_rssi_scan_rssi_delta; + + /* + * Update the capability here itself as this is used in + * lim_extract_ap_capability() below. If not updated issues + * like not honoring power constraint on 1st association after + * driver loading might occur. + */ + lim_update_rrm_capability(mac_ctx); + bss_chan_id = wlan_reg_freq_to_chan(mac_ctx->pdev, + bss_desc->chan_freq); + + lim_update_sae_config(mac_ctx, session); + lim_update_sae_single_pmk_ap_cap(mac_ctx, session); + + /* Update the beacon/probe filter in mac_ctx */ + lim_set_bcn_probe_filter(mac_ctx, session, + bss_chan_id); + session->max_amsdu_num = + mac_ctx->mlme_cfg->ht_caps.max_num_amsdu; + /* Store beaconInterval */ + session->beaconParams.beaconInterval = + bss_desc->beaconInterval; + /* Copy oper freq to the session Table */ + session->curr_op_freq = bss_desc->chan_freq; + + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ie_struct); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("IE parsing failed vdev id %d", + session->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&session->wmm_params, sizeof(tDot11fIEWMMParams)); + if (ie_struct->WMMParams.present) + qdf_mem_copy(&session->wmm_params, &ie_struct->WMMParams, + sizeof(tDot11fIEWMMParams)); + + mac_ctx->mlme_cfg->power.local_power_constraint = + wlan_get_11h_power_constraint(mac_ctx, + &ie_struct->PowerConstraints); + + session->enable_session_twt_support = + lim_enable_twt(mac_ctx, ie_struct); + status = lim_fill_dot11_mode(mac_ctx, session, ie_struct); + if (QDF_IS_STATUS_ERROR(status)) { + status = QDF_STATUS_E_FAILURE; + goto send; + } + cb_mode = wlan_get_cb_mode(mac_ctx, session->curr_op_freq, ie_struct, + session); + + if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq) && + wlan_cm_get_force_20mhz_in_24ghz(session->vdev)) + cb_mode = PHY_SINGLE_CHANNEL_CENTERED; + + status = wlan_get_rate_set(mac_ctx, ie_struct, session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Get rate failed vdev id %d", session->vdev_id); + lim_get_basic_rates(&session->rateSet, bss_desc->chan_freq); + } + + if (session->dot11mode == MLME_DOT11_MODE_11B) + mac_ctx->mlme_cfg->feature_flags.enable_short_slot_time_11g = 0; + else + mac_ctx->mlme_cfg->feature_flags.enable_short_slot_time_11g = + mac_ctx->mlme_cfg->ht_caps.short_slot_time_enabled; + + /* + * Join timeout: if we find a BeaconInterval in the BssDescription, + * then set the Join Timeout to be 10 x the BeaconInterval. + * + * 10 * BeaconInterval should be greater than the minimum join + * timeout and lesser than the configured timeout. + */ + timeout = mac_ctx->mlme_cfg->timeouts.join_failure_timeout_ori; + if (bss_desc->beaconInterval) + timeout = QDF_MAX(10 * bss_desc->beaconInterval, + cfg_min(CFG_JOIN_FAILURE_TIMEOUT)); + + mac_ctx->mlme_cfg->timeouts.join_failure_timeout = + QDF_MIN(timeout, + mac_ctx->mlme_cfg->timeouts.join_failure_timeout_ori); + /* + * Calculate probe request retry timeout, + * Change probe req retry to MAX_JOIN_PROBE_REQ if sta freq + * can cause MCC + */ + timeout = JOIN_PROBE_REQ_TIMER_MS; + if (policy_mgr_will_freq_lead_to_mcc(mac_ctx->psoc, + bss_desc->chan_freq)) { + /* Send MAX_JOIN_PROBE_REQ probe req during join timeout */ + timeout = mac_ctx->mlme_cfg->timeouts.join_failure_timeout/ + MAX_JOIN_PROBE_REQ; + timeout = QDF_MAX(JOIN_PROBE_REQ_TIMER_MS, timeout); + } + mac_ctx->mlme_cfg->timeouts.probe_req_retry_timeout = timeout; + + lim_join_req_update_ht_vht_caps(mac_ctx, session, bss_desc, + ie_struct); + + lim_check_oui_and_update_session(mac_ctx, session, ie_struct); + ese_ver_present = ie_struct->ESEVersion.present; + + /* Copying of bssId is already done, while creating session */ + sir_copy_mac_addr(session->self_mac_addr, + wlan_vdev_mlme_get_macaddr(session->vdev)); + + session->statypeForBss = STA_ENTRY_PEER; + + lim_update_qos(mac_ctx, session, bss_desc, ie_struct); + + if (session->lim_join_req->bssDescription.adaptive_11r_ap) + session->is_adaptive_11r_connection = + wlan_get_adaptive_11r_enabled(lfr); + config.bool_value = session->is_adaptive_11r_connection; + wlan_cm_roam_cfg_set_value(mac_ctx->psoc, session->vdev_id, + ADAPTIVE_11R_CONNECTION, + &config); + lim_fill_11r_params(mac_ctx, session , ese_ver_present); + lim_fill_ese_params(mac_ctx, session, ese_ver_present); + + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, session->vdev_id, + NEIGHBOUR_LOOKUP_THRESHOLD, &temp); + neighbor_lookup_threshold = temp.uint_value; + + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, session->vdev_id, + HI_RSSI_SCAN_RSSI_DELTA, &temp); + hi_rssi_scan_rssi_delta = temp.uint_value; + + /* + * Firmware will take care of checking hi_scan rssi delta, take care of + * legacy -> legacy hi-rssi roam also if this feature flag is + * advertised. + */ + if (wlan_cm_is_self_mld_roam_supported(mac_ctx->psoc)) { + wlan_cm_set_disable_hi_rssi(mac_ctx->pdev, session->vdev_id, + false); + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(bss_desc->chan_freq) && + (abs(bss_desc->rssi) > + (neighbor_lookup_threshold - hi_rssi_scan_rssi_delta))) { + pe_debug("Enabling HI_RSSI, rssi: %d lookup_th: %d, delta:%d", + bss_desc->rssi, neighbor_lookup_threshold, + hi_rssi_scan_rssi_delta); + wlan_cm_set_disable_hi_rssi(mac_ctx->pdev, session->vdev_id, + false); + } else { + wlan_cm_set_disable_hi_rssi(mac_ctx->pdev, session->vdev_id, + true); + pe_debug("Disabling HI_RSSI, AP freq=%d, rssi=%d", + bss_desc->chan_freq, bss_desc->rssi); + } + + if (session->opmode == QDF_STA_MODE) + session->enable_bcast_probe_rsp = + mac_ctx->mlme_cfg->oce.enable_bcast_probe_rsp; + + /* Store vendor specific IE for CISCO AP */ + ie_len = (bss_desc->length + sizeof(bss_desc->length) - + GET_FIELD_OFFSET(struct bss_description, ieFields)); + + vendor_ie = wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_CISCO_OUI, SIR_MAC_CISCO_OUI_SIZE, + ((uint8_t *)&bss_desc->ieFields), ie_len); + + if (vendor_ie) + session->isCiscoVendorAP = true; + else + session->isCiscoVendorAP = false; + + session->nwType = bss_desc->nwType; + session->enableAmpduPs = + mac_ctx->mlme_cfg->ht_caps.enable_ampdu_ps; + session->send_smps_action = + mac_ctx->roam.configParam.send_smps_action; + session->vhtCapability = + IS_DOT11_MODE_VHT(session->dot11mode); + if (session->vhtCapability) { + session->enableVhtpAid = + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_paid; + session->enableVhtGid = + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_gid; + } + /*Phy mode */ + session->gLimPhyMode = bss_desc->nwType; + handle_ht_capabilityand_ht_info(mac_ctx, session); + + session->htSupportedChannelWidthSet = cb_mode ? 1 : 0; + session->htRecommendedTxWidthSet = + session->htSupportedChannelWidthSet; + session->htSecondaryChannelOffset = cb_mode; + + if (cb_mode == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) { + session->ch_center_freq_seg0 = + wlan_reg_freq_to_chan( + mac_ctx->pdev, session->curr_op_freq) - 2; + session->ch_width = CH_WIDTH_40MHZ; + } else if (cb_mode == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) { + session->ch_center_freq_seg0 = + wlan_reg_freq_to_chan( + mac_ctx->pdev, session->curr_op_freq) + 2; + session->ch_width = CH_WIDTH_40MHZ; + } else { + session->ch_center_freq_seg0 = 0; + session->ch_width = CH_WIDTH_20MHZ; + } + session->ap_ch_width = session->ch_width; + + if (IS_DOT11_MODE_HE(session->dot11mode)) { + lim_update_session_he_capable(mac_ctx, session); + lim_copy_join_req_he_cap(session); + } + + if (IS_DOT11_MODE_EHT(session->dot11mode)) { + lim_update_session_eht_capable(mac_ctx, session); + lim_reset_self_ocv_caps(session); + lim_copy_join_req_eht_cap(session); + } + + /* Record if management frames need to be protected */ + session->limRmfEnabled = + lim_get_vdev_rmf_capable(mac_ctx, session); + + session->txLdpcIniFeatureEnabled = + mac_ctx->mlme_cfg->ht_caps.tx_ldpc_enable; + + session->limSystemRole = eLIM_STA_ROLE; + if (session->nss == 1) + session->supported_nss_1x1 = true; + + session->limCurrentBssCaps = bss_desc->capabilityInfo; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!mlme_obj) { + status = QDF_STATUS_E_FAILURE; + goto send; + } + + lim_extract_ap_capability(mac_ctx, + (uint8_t *)bss_desc->ieFields, + lim_get_ielen_from_bss_description(bss_desc), + &session->limCurrentBssQosCaps, + &session->gLimCurrentBssUapsd, + &local_power_constraint, session, &is_pwr_constraint); + + lim_disable_bformee_for_iot_ap(mac_ctx, session, bss_desc); + + mlme_obj->reg_tpc_obj.is_power_constraint_abs = + !is_pwr_constraint; + + if (wlan_reg_is_6ghz_chan_freq(bss_desc->chan_freq)) { + if (!ie_struct->Country.present) + pe_debug("Channel is 6G but country IE not present"); + status = wlan_reg_get_best_6g_power_type( + mac_ctx->psoc, mac_ctx->pdev, + &power_type_6g, + session->ap_defined_power_type_6g, + bss_desc->chan_freq); + if (QDF_IS_STATUS_ERROR(status)) { + status = QDF_STATUS_E_NOSUPPORT; + goto send; + } + session->best_6g_power_type = power_type_6g; + mlme_set_best_6g_power_type(session->vdev, power_type_6g); + + lim_iterate_triplets(ie_struct->Country); + + if (!ie_struct->num_transmit_power_env || + !ie_struct->transmit_power_env[0].present) + pe_debug("TPE not present for 6G channel"); + } + + if (wlan_reg_is_ext_tpc_supported(mac_ctx->psoc)) { + mlme_obj->reg_tpc_obj.ap_constraint_power = + local_power_constraint; + } else { + reg_max = wlan_reg_get_channel_reg_power_for_freq( + mac_ctx->pdev, session->curr_op_freq); + if (is_pwr_constraint) + local_power_constraint = reg_max - + local_power_constraint; + if (!local_power_constraint) + local_power_constraint = reg_max; + + mlme_obj->reg_tpc_obj.reg_max[0] = reg_max; + mlme_obj->reg_tpc_obj.ap_constraint_power = + local_power_constraint; + mlme_obj->reg_tpc_obj.frequency[0] = session->curr_op_freq; + + session->maxTxPower = lim_get_max_tx_power(mac_ctx, mlme_obj); + session->def_max_tx_pwr = session->maxTxPower; + } + + /* + * for mdm platform which QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET + * will not call from android framework every 3 seconds, and tx + * power will never update. So we use iw dev get tx power need + * set maxTxPower non-zero value, that firmware can calc a non-zero + * tx power, and update to host driver. + */ + if (LIM_IS_STA_ROLE(session) && session->maxTxPower == 0) + session->maxTxPower = + wlan_reg_get_channel_reg_power_for_freq(mac_ctx->pdev, + session->curr_op_freq); + + session->limRFBand = lim_get_rf_band(session->curr_op_freq); + + /* Initialize 11h Enable Flag */ + if (session->limRFBand != REG_BAND_2G) + session->lim11hEnable = + mac_ctx->mlme_cfg->gen.enabled_11h; + else + session->lim11hEnable = 0; + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_JOIN_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session->peSessionId, + session->limSmeState)); + + /* Enable MBSSID only for station */ + session->is_mbssid_enabled = wma_is_mbssid_enabled(); + + /* Enable the spectrum management if this is a DFS channel */ + if (session->country_info_present && + lim_isconnected_on_dfs_freq( + mac_ctx, + session->curr_op_freq)) + session->spectrumMgtEnabled = true; + + ap_cap_info = (tSirMacCapabilityInfo *)&bss_desc->capabilityInfo; + + /* + * tell the target AP my 11H capability only if both AP and STA + * support + * 11H and the channel being used is 11a + */ + if (mac_ctx->mlme_cfg->gen.enabled_11h && + ap_cap_info->spectrumMgt && bss_desc->nwType == eSIR_11A_NW_TYPE) + session->spectrumMgtEnabled = true; + + /* + * This is required for 11k test VoWiFi Ent: Test 2. + * We need the power capabilities for Assoc Req. + * This macro is provided by the halPhyCfg.h. We pick our + * max and min capability by the halPhy provided macros + * Any change in this power cap IE should also be done + * in csr_update_driver_assoc_ies() which would send + * assoc IE's to FW which is used for LFR3 roaming + * ie. used in reassociation requests from FW. + */ + session->max_11h_pwr = + QDF_MIN(lim_get_cfg_max_tx_power(mac_ctx, + bss_desc->chan_freq), + MAX_TX_PWR_CAP); + + if (!session->max_11h_pwr) + session->max_11h_pwr = MAX_TX_PWR_CAP; + + if (session->max_11h_pwr > session->maxTxPower) + session->max_11h_pwr = session->maxTxPower; + + session->min_11h_pwr = MIN_TX_PWR_CAP; + + if (!session->enable_session_twt_support) { + status = wlan_mlme_get_wmm_mode(mac_ctx->psoc, &wmm_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Get wmm_mode failed"); + status = QDF_STATUS_E_INVAL; + goto send; + } + if (wmm_mode == 2 || !(LIM_IS_QOS_BSS(ie_struct)) || + !(LIM_IS_UAPSD_BSS(ie_struct))) { + /*QoS not enabled in cfg file or in BSS*/ + session->gUapsdPerAcBitmask = 0; + } else { + /*QoS enabled, update uapsd mask from cfg file */ + status = wlan_mlme_get_wmm_uapsd_mask(mac_ctx->psoc, + &value); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Get uapsd_mask failed"); + status = QDF_STATUS_E_INVAL; + goto send; + } + session->gUapsdPerAcBitmask = value; + } + ps_param->uapsd_per_ac_bit_mask = session->gUapsdPerAcBitmask; + } + + if (session->gLimCurrentBssUapsd) { + /* resetting the dynamic uapsd mask */ + session->gUapsdPerAcDeliveryEnableMask = 0; + session->gUapsdPerAcTriggerEnableMask = 0; + } + + lim_fill_cc_mode(mac_ctx, session); + lim_fill_rssi(session, bss_desc); + + status = QDF_STATUS_SUCCESS; + +send: + qdf_mem_free(ie_struct); + return status; + +} + +static QDF_STATUS +lim_send_connect_req_to_mlm(struct pe_session *session) +{ + tLimMlmJoinReq *mlm_join_req; + uint32_t len; + QDF_STATUS status; + + len = sizeof(tLimMlmJoinReq) + + session->lim_join_req->bssDescription.length + 2; + mlm_join_req = qdf_mem_malloc(len); + if (!mlm_join_req) + return QDF_STATUS_E_FAILURE; + + /* PE SessionId is stored as a part of JoinReq */ + mlm_join_req->sessionId = session->peSessionId; + + mlm_join_req->bssDescription.length = + session->lim_join_req->bssDescription.length; + + qdf_mem_copy((uint8_t *) &mlm_join_req->bssDescription.bssId, + (uint8_t *) + &session->lim_join_req->bssDescription.bssId, + session->lim_join_req->bssDescription.length + 2); + + /* Issue LIM_MLM_JOIN_REQ to MLM */ + status = lim_send_join_req(session, mlm_join_req); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(mlm_join_req); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static struct pe_session * +lim_cm_create_session(struct mac_context *mac_ctx, struct cm_vdev_join_req *req) +{ + struct pe_session *pe_session; + uint8_t session_id; + + pe_session = pe_find_session_by_bssid(mac_ctx, req->entry->bssid.bytes, + &session_id); + + if (pe_session) { + pe_err("vdev_id: %d cm_id 0x%x :pe-session(%d (vdev %d)) already exists for BSSID: " + QDF_MAC_ADDR_FMT " in lim_sme_state = %X", + req->vdev_id, req->cm_id, session_id, + pe_session->vdev_id, + QDF_MAC_ADDR_REF(req->entry->bssid.bytes), + pe_session->limSmeState); + + qdf_trigger_self_recovery(mac_ctx->psoc, + QDF_VDEV_SM_OUT_OF_SYNC); + return NULL; + } + + pe_session = pe_create_session(mac_ctx, req->entry->bssid.bytes, + &session_id, + mac_ctx->lim.max_sta_of_pe_session, + eSIR_INFRASTRUCTURE_MODE, + req->vdev_id); + if (!pe_session) + pe_err("vdev_id: %d cm_id 0x%x : pe_session create failed BSSID" + QDF_MAC_ADDR_FMT, req->vdev_id, req->cm_id, + QDF_MAC_ADDR_REF(req->entry->bssid.bytes)); + + return pe_session; +} + +static bool +lim_is_wpa_profile(struct pe_session *session) +{ + int32_t ucast_cipher; + int32_t auth_mode; + + ucast_cipher = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + auth_mode = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + + if (auth_mode == -1 || ucast_cipher == -1) + return false; + + if (!QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_WPA)) + return false; + + if (((ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_TKIP)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_104)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_40)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_CCM)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_OCB)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_CCM_256)))) + return true; + + return false; +} + +static bool +lim_is_wapi_profile(struct pe_session *session) +{ + int32_t ucast_cipher; + int32_t auth_mode; + + ucast_cipher = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + auth_mode = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + + if (auth_mode == -1 || ucast_cipher == -1) + return false; + + if (!QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_WAPI)) + return false; + + if (((ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WAPI_GCM4)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WAPI_SMS4)))) + return true; + + return false; +} + +static bool +lim_is_rsn_profile(struct pe_session *session) +{ + int32_t ucast_cipher; + int32_t auth_mode; + bool is_rsn = false; + + ucast_cipher = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + auth_mode = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + + if (auth_mode == -1 || ucast_cipher == -1) + return false; + + if (QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_8021X) || + QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_RSNA) || + QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_CCKM) || + QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_SAE) || + QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_FILS_SK)) + is_rsn = true; + + if (!is_rsn) + return false; + + if (((ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_TKIP)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_104)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_WEP_40)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_CCM)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_OCB)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_CCM_256)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_GCM_256)) || + (ucast_cipher & (1 << WLAN_CRYPTO_CIPHER_AES_GCM)))) + return true; + + return false; +} + +tAniEdType lim_get_encrypt_ed_type(int32_t ucast_cipher) +{ + if (ucast_cipher == -1) + return eSIR_ED_NONE; + + if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_GCM_256)) + return eSIR_ED_GCMP_256; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_GCM)) + return eSIR_ED_GCMP; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_CCM) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_OCB) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_CCM_256)) + return eSIR_ED_CCMP; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_TKIP)) + return eSIR_ED_TKIP; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_CMAC) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_CMAC_256)) + return eSIR_ED_AES_128_CMAC; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WAPI_GCM4) || + QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WAPI_SMS4)) + return eSIR_ED_WPI; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_GMAC)) + return eSIR_ED_AES_GMAC_128; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_AES_GMAC_256)) + return eSIR_ED_AES_GMAC_256; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP)) + return eSIR_ED_WEP40; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_40)) + return eSIR_ED_WEP40; + else if (QDF_HAS_PARAM(ucast_cipher, WLAN_CRYPTO_CIPHER_WEP_104)) + return eSIR_ED_WEP104; + + return eSIR_ED_NONE; +} + +static enum ani_akm_type +lim_get_wpa_akm(uint32_t akm) +{ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return ANI_AKM_TYPE_WPA; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + return ANI_AKM_TYPE_WPA_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return ANI_AKM_TYPE_CCKM; + else + return ANI_AKM_TYPE_UNKNOWN; +} + +static enum ani_akm_type +lim_get_rsn_akm(uint32_t akm) +{ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) + return ANI_AKM_TYPE_FT_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) + return ANI_AKM_TYPE_FT_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) + return ANI_AKM_TYPE_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) + return ANI_AKM_TYPE_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + return ANI_AKM_TYPE_FT_SAE_EXT_KEY; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) + return ANI_AKM_TYPE_FT_SAE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE)) + return ANI_AKM_TYPE_SAE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_DPP)) + return ANI_AKM_TYPE_DPP_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OSEN)) + return ANI_AKM_TYPE_OSEN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE)) + return ANI_AKM_TYPE_OWE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) + return ANI_AKM_TYPE_FT_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) + return ANI_AKM_TYPE_FT_RSN_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + return ANI_AKM_TYPE_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + return ANI_AKM_TYPE_RSN_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + return ANI_AKM_TYPE_CCKM; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) + return ANI_AKM_TYPE_RSN_PSK_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) + return ANI_AKM_TYPE_RSN_8021X_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B)) + return ANI_AKM_TYPE_SUITEB_EAP_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) + return ANI_AKM_TYPE_SUITEB_EAP_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) + return ANI_AKM_TYPE_FT_SUITEB_EAP_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) + return ANI_AKM_TYPE_SAE_EXT_KEY; + else + return ANI_AKM_TYPE_NONE; +} + +enum ani_akm_type +lim_get_connected_akm(struct pe_session *session, int32_t ucast_cipher, + int32_t auth_mode, int32_t akm) +{ + if (auth_mode == -1 || ucast_cipher == -1 || akm == -1) + return ANI_AKM_TYPE_NONE; + + if (QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_NONE) || + QDF_HAS_PARAM(auth_mode, WLAN_CRYPTO_AUTH_OPEN)) + return ANI_AKM_TYPE_NONE; + + if (lim_is_rsn_profile(session)) + return lim_get_rsn_akm(akm); + + if (lim_is_wpa_profile(session)) + return lim_get_wpa_akm(akm); + + if (lim_is_wapi_profile(session)) + return ANI_AKM_TYPE_UNKNOWN; + + return ANI_AKM_TYPE_NONE; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * lim_update_pmksa_to_profile() - update pmk and pmkid to profile which will be + * used in case of fils session + * @vdev: vdev + * @pmkid_cache: pmksa cache + * + * Return: None + */ +static inline void lim_update_pmksa_to_profile(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_pmksa *pmksa) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + pe_err("vdev legacy private object is NULL"); + return; + } + if (!mlme_priv->connect_info.fils_con_info) + return; + mlme_priv->connect_info.fils_con_info->pmk_len = pmksa->pmk_len; + qdf_mem_copy(mlme_priv->connect_info.fils_con_info->pmk, + pmksa->pmk, pmksa->pmk_len); + qdf_mem_copy(mlme_priv->connect_info.fils_con_info->pmkid, + pmksa->pmkid, PMKID_LEN); +} +#else +static inline void lim_update_pmksa_to_profile(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_pmksa *pmksa) +{ +} +#endif + +/* + * lim_is_non_default_rsnxe_cap_set() - Check if non-default userspace RSNXE + * CAP is set + * + * @mac_ctx: pointer to mac contetx + * @req: join request + * + * Return: Non default cap set + */ +static inline bool +lim_is_non_default_rsnxe_cap_set(struct mac_context *mac_ctx, + struct cm_vdev_join_req *req) +{ + const uint8_t *rsnxe, *rsnxe_cap; + uint8_t cap_len = 0, cap_index; + uint32_t cap_mask; + + rsnxe = wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, + req->assoc_ie.ptr, + req->assoc_ie.len); + if (!rsnxe) + return false; + + rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnxe, &cap_len); + if (!rsnxe_cap || (rsnxe[SIR_MAC_IE_LEN_OFFSET] > (cap_len + 1))) { + mlme_err("RSNXE caps not present/unknown caps present. Cap len %d", + cap_len); + return true; + } + + /* + * Below is the definition of RSNXE capabilities defined + * in (IEEE Std 802.11-2020, 9.4.2.241, Table 9-780). + * The Extended RSN Capabilities field, except its first 4 bits, is a + * bit field indicating the extended RSN capabilities being advertised + * by the STA transmitting the element. The length of the Extended + * RSN Capabilities field is a variable n, in octets, as indicated by + * the first 4 bits in the field. + * Let's consider a uint32_t cap_mask which can accommodate 28(32-4) + * bits to check if those bits are set or not. This is to keep it + * simple as current supported bits are only 11. + * TODO: If spec supports more than this range in future, this needs to + * be an array to hold the complete bitmap/bitmask. + */ + cap_mask = ~(0xF | WLAN_CRYPTO_RSNX_CAP_SAE_H2E | + WLAN_CRYPTO_RSNX_CAP_SAE_PK | + WLAN_CRYPTO_RSNX_CAP_SECURE_LTF | + WLAN_CRYPTO_RSNX_CAP_SECURE_RTT | + WLAN_CRYPTO_RSNX_CAP_URNM_MFPR); + + /* Check if any other bits are set than cap_mask */ + for (cap_index = 0; cap_index <= cap_len; cap_index++) { + if (rsnxe_cap[cap_index] & (cap_mask & 0xFF)) + return true; + cap_mask >>= 8; + } + + return false; +} + +/* + * lim_rebuild_rsnxe_cap() - Rebuild the RSNXE CAP for STA + * + * @rsnx_ie: RSNX IE + * @length: length of extended RSN cap field + * + * This API is used to truncate/rebuild the RSNXE based on the length + * provided. This length marks the length of the extended RSN cap field. + * + * Return: Newly constructed RSNX IE + */ +static inline uint8_t *lim_rebuild_rsnxe_cap(uint8_t *rsnx_ie, uint8_t length) +{ + const uint8_t *rsnxe_cap; + uint8_t cap_len; + uint8_t *new_rsnxe = NULL; + + if (length < SIR_MAC_RSNX_CAP_MIN_LEN || + length > SIR_MAC_RSNX_CAP_MAX_LEN) { + pe_err("Invalid length %d", length); + return NULL; + } + + rsnxe_cap = wlan_crypto_parse_rsnxe_ie(rsnx_ie, &cap_len); + if (!rsnxe_cap) + return NULL; + + new_rsnxe = qdf_mem_malloc(length + SIR_MAC_IE_TYPE_LEN_SIZE); + if (!new_rsnxe) + return NULL; + + new_rsnxe[SIR_MAC_IE_TYPE_OFFSET] = WLAN_ELEMID_RSNXE; + new_rsnxe[SIR_MAC_IE_LEN_OFFSET] = length; + qdf_mem_copy(&new_rsnxe[SIR_MAC_IE_TYPE_LEN_SIZE], rsnxe_cap, length); + + /* Now update the new field length in octet 0 for the new length*/ + new_rsnxe[SIR_MAC_IE_TYPE_LEN_SIZE] = + (new_rsnxe[SIR_MAC_IE_TYPE_LEN_SIZE] & 0xF0) | (length - 1); + + pe_debug("New RSNXE length %d", length); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + new_rsnxe, length + SIR_MAC_IE_TYPE_LEN_SIZE); + return new_rsnxe; +} + +/* + * lim_append_rsnxe_to_assoc_ie() - Append the new RSNXE to the + * assoc ie buffer + * + * @req: join request + * @new_rsnxe: new rsnxe to be appended + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +lim_append_rsnxe_to_assoc_ie(struct cm_vdev_join_req *req, + uint8_t *new_rsnxe) +{ + uint8_t *assoc_ie = NULL; + uint8_t assoc_ie_len; + + assoc_ie = qdf_mem_malloc(req->assoc_ie.len + + new_rsnxe[SIR_MAC_IE_LEN_OFFSET] + + SIR_MAC_IE_TYPE_LEN_SIZE); + if (!assoc_ie) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(assoc_ie, req->assoc_ie.ptr, req->assoc_ie.len); + assoc_ie_len = req->assoc_ie.len; + qdf_mem_copy(&assoc_ie[assoc_ie_len], new_rsnxe, + new_rsnxe[SIR_MAC_IE_LEN_OFFSET] + + SIR_MAC_IE_TYPE_LEN_SIZE); + assoc_ie_len += new_rsnxe[SIR_MAC_IE_LEN_OFFSET] + + SIR_MAC_IE_TYPE_LEN_SIZE; + + /* Replace the assoc ie with new assoc_ie */ + qdf_mem_free(req->assoc_ie.ptr); + req->assoc_ie.ptr = &assoc_ie[0]; + req->assoc_ie.len = assoc_ie_len; + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +lim_strip_rsnx_ie(struct mac_context *mac_ctx, + struct pe_session *session, + struct cm_vdev_join_req *req) +{ + int32_t akm; + uint8_t ap_rsnxe_len = 0, len = 0; + uint8_t *rsnxe = NULL, *new_rsnxe = NULL; + uint8_t *ap_rsnxe = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + akm = wlan_crypto_get_param(session->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (akm == -1 || + !(WLAN_CRYPTO_IS_WPA_WPA2(akm) || WLAN_CRYPTO_IS_WPA3(akm))) + return status; + + if (!wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, req->assoc_ie.ptr, + req->assoc_ie.len)) + return status; + + /* + * Userspace may send RSNXE also in connect request irrespective + * of the connecting AP capabilities. This allows the driver to chose + * best candidate based on score. But the chosen candidate may + * not support the RSNXE feature and may not advertise RSNXE + * in beacon/probe response. Station is not supposed to include + * the RSNX IE in assoc request in such cases as legacy APs + * may misbahave due to the new IE. It's observed that few + * legacy APs which don't support the RSNXE reject the + * connection at EAPOL stage. + * + * Modify the RSNXE only when known capability bits are set. + * i.e., don't strip when bits other than SAE_H2E, SAE_PK, SECURE_LTF, + * SECURE_RTT, PROT_RANGE_NEGOTIOATION are set by userspace. + * + */ + if (lim_is_non_default_rsnxe_cap_set(mac_ctx, req)) { + pe_debug("Do not strip RSNXE, unknown caps are set"); + return status; + } + + ap_rsnxe = util_scan_entry_rsnxe(req->entry); + if (!ap_rsnxe) + ap_rsnxe_len = 0; + else + ap_rsnxe_len = ap_rsnxe[SIR_MAC_IE_LEN_OFFSET]; + + /* + * Do not modify userspace RSNXE if either: + * a) AP supports RSNXE cap with more than 1 bytes + * b) AP has zero length RSNXE. + */ + + if (ap_rsnxe_len > 1 || (ap_rsnxe && ap_rsnxe_len == 0)) + return QDF_STATUS_SUCCESS; + + rsnxe = qdf_mem_malloc(WLAN_MAX_IE_LEN + SIR_MAC_IE_TYPE_LEN_SIZE); + if (!rsnxe) + return QDF_STATUS_E_FAILURE; + + lim_strip_ie(mac_ctx, req->assoc_ie.ptr, + (uint16_t *)&req->assoc_ie.len, WLAN_ELEMID_RSNXE, + ONE_BYTE, NULL, 0, rsnxe, WLAN_MAX_IE_LEN); + + if (!rsnxe[SIR_MAC_IE_TYPE_OFFSET] || !rsnxe[SIR_MAC_IE_LEN_OFFSET]) + goto end; + + /* + * Do not rebuild the RSNXE with length 1, if none of the caps are set + * in the first octet. It leads to the creation of an empty RSNXE. + */ + if (!(rsnxe[2] & 0xF0)) { + pe_debug("None of the caps are set in 1st octet, strip RSNXE"); + goto end; + } + + switch (ap_rsnxe_len) { + case 0: + /* + * AP doesn't broadcast RSNXE/invalid RSNXE: + * For WPA2 - Strip the RSNXE + * For WPA3 - Retain only SAE caps: H2E and PK in the 1st octet + */ + if (WLAN_CRYPTO_IS_WPA_WPA2(akm)) { + mlme_debug("Strip RSNXE as it is not supported by AP"); + goto end; + } + if (WLAN_CRYPTO_IS_WPA3(akm)) { + len = 1; + goto rebuild_rsnxe; + } + break; + case 1: + /* + * In some IOT cases, APs do not recognize more than 1 octet of + * RSNXE. This leads to connectivity failures. + * Therefore, restrict the self RSNXE to 1 octet if AP supports + * only 1 octet + */ + len = 1; + goto rebuild_rsnxe; + default: + break; + } + + pe_err("Error in handling RSNXE. Length AP: %d SELF: %d", + ap_rsnxe_len, rsnxe[SIR_MAC_IE_LEN_OFFSET]); + status = QDF_STATUS_E_FAILURE; + goto end; + +rebuild_rsnxe: + /* Build the new RSNXE */ + new_rsnxe = lim_rebuild_rsnxe_cap(rsnxe, len); + if (!new_rsnxe) { + status = QDF_STATUS_E_FAILURE; + goto end; + } else if (!new_rsnxe[1]) { + qdf_mem_free(new_rsnxe); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Append the new RSNXE to the assoc ie */ + status = lim_append_rsnxe_to_assoc_ie(req, new_rsnxe); + qdf_mem_free(new_rsnxe); + +end: + qdf_mem_free(rsnxe); + return status; +} + +void +lim_update_connect_rsn_ie(struct mac_context *mac, + struct pe_session *session, + uint8_t *rsn_ie_buf, struct wlan_crypto_pmksa *pmksa) +{ + uint8_t *rsn_ie_end; + uint16_t rsn_ie_len = 0; + struct bss_description *bss_desc = + &session->lim_join_req->bssDescription; + struct action_oui_search_attr ap_attr = {0}; + + ap_attr.ie_data = (uint8_t *)&bss_desc->ieFields[0]; + ap_attr.ie_length = + wlan_get_ielen_from_bss_description(bss_desc); + if (wlan_action_oui_search(mac->psoc, + &ap_attr, + ACTION_OUI_RESTRICT_MAX_MLO_LINKS)) + pmksa = NULL; + + rsn_ie_end = wlan_crypto_build_rsnie_with_pmksa(session->vdev, + rsn_ie_buf, pmksa); + if (!rsn_ie_end) { + pe_debug("Build RSN IE failed"); + return; + } + + rsn_ie_len = rsn_ie_end - rsn_ie_buf; + session->lim_join_req->rsnIE.length = rsn_ie_len; + qdf_mem_copy(session->lim_join_req->rsnIE.rsnIEdata, + rsn_ie_buf, rsn_ie_len); +} + +static QDF_STATUS +lim_fill_rsn_ie(struct mac_context *mac_ctx, struct pe_session *session, + struct cm_vdev_join_req *req) +{ + QDF_STATUS status; + uint8_t *rsn_ie; + uint8_t rsn_ie_len = 0; + struct wlan_crypto_pmksa pmksa, *pmksa_peer; + struct bss_description *bss_desc; + + rsn_ie = qdf_mem_malloc(DOT11F_IE_RSN_MAX_LEN + 2); + if (!rsn_ie) + return QDF_STATUS_E_NOMEM; + + status = lim_strip_ie(mac_ctx, req->assoc_ie.ptr, + (uint16_t *)&req->assoc_ie.len, + WLAN_ELEMID_RSN, ONE_BYTE, + NULL, 0, rsn_ie, DOT11F_IE_RSN_MAX_LEN); + + if (req->force_rsne_override && QDF_IS_STATUS_SUCCESS(status)) { + rsn_ie_len = rsn_ie[1] + 2; + if (rsn_ie_len < DOT11F_IE_RSN_MIN_LEN || + rsn_ie_len > DOT11F_IE_RSN_MAX_LEN) { + pe_err("RSN length %d not within limits", rsn_ie_len); + qdf_mem_free(rsn_ie); + return QDF_STATUS_E_FAILURE; + } + + session->lim_join_req->rsnIE.length = rsn_ie_len; + qdf_mem_copy(session->lim_join_req->rsnIE.rsnIEdata, + rsn_ie, rsn_ie_len); + + qdf_mem_free(rsn_ie); + return QDF_STATUS_SUCCESS; + } + + bss_desc = &session->lim_join_req->bssDescription; + + qdf_mem_zero(&pmksa, sizeof(pmksa)); + if (bss_desc->fils_info_element.is_cache_id_present) { + pmksa.ssid_len = session->ssId.length; + qdf_mem_copy(pmksa.ssid, session->ssId.ssId, + session->ssId.length); + qdf_mem_copy(pmksa.cache_id, + bss_desc->fils_info_element.cache_id, + CACHE_ID_LEN); + pe_debug("FILS: vdev %d Cache id =0x%x 0x%x ssid: " QDF_SSID_FMT, + session->vdev_id, pmksa.cache_id[0], pmksa.cache_id[1], + QDF_SSID_REF(pmksa.ssid_len, pmksa.ssid)); + } else { + qdf_mem_copy(&pmksa.bssid, session->bssId, QDF_MAC_ADDR_SIZE); + /* For MLO connection, override BSSID with peer mldaddr */ + lim_get_mld_peer(session->vdev, &pmksa.bssid); + } + + pmksa_peer = wlan_crypto_get_peer_pmksa(session->vdev, &pmksa); + if (pmksa_peer) + pe_debug("PMKSA found"); + + lim_update_connect_rsn_ie(mac_ctx, session, rsn_ie, pmksa_peer); + qdf_mem_free(rsn_ie); + + /* + * If a PMK cache is found for the BSSID, then + * update the PMK in CSR session also as this + * will be sent to the FW during RSO. + */ + if (pmksa_peer) { + wlan_cm_set_psk_pmk(mac_ctx->pdev, session->vdev_id, + pmksa_peer->pmk, pmksa_peer->pmk_len); + lim_update_pmksa_to_profile(session->vdev, pmksa_peer); + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_fill_wpa_ie(struct mac_context *mac_ctx, struct pe_session *session, + struct cm_vdev_join_req *req) +{ + QDF_STATUS status; + uint8_t *wpa_ie; + uint8_t ie_len = 0; + uint8_t *wpa_ie_end = NULL; + + wpa_ie = qdf_mem_malloc(DOT11F_IE_WPA_MAX_LEN + 2); + if (!wpa_ie) + return QDF_STATUS_E_NOMEM; + + status = lim_strip_ie(mac_ctx, req->assoc_ie.ptr, + (uint16_t *)&req->assoc_ie.len, + DOT11F_EID_WPA, ONE_BYTE, + "\x00\x50\xf2", 3, NULL, 0); + + wpa_ie_end = wlan_crypto_build_wpaie(session->vdev, wpa_ie); + if (wpa_ie_end) + ie_len = wpa_ie_end - wpa_ie; + + session->lim_join_req->rsnIE.length = ie_len; + qdf_mem_copy(session->lim_join_req->rsnIE.rsnIEdata, + wpa_ie, ie_len); + + qdf_mem_free(wpa_ie); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_WAPI +static QDF_STATUS +lim_fill_wapi_ie(struct mac_context *mac_ctx, struct pe_session *session, + struct cm_vdev_join_req *req) +{ + QDF_STATUS status; + uint8_t *wapi_ie; + uint8_t ie_len = 0; + uint8_t *wapi_ie_end = NULL; + + wapi_ie = qdf_mem_malloc(DOT11F_IE_WAPI_MAX_LEN + 2); + if (!wapi_ie) + return QDF_STATUS_E_NOMEM; + + status = lim_strip_ie(mac_ctx, req->assoc_ie.ptr, + (uint16_t *)&req->assoc_ie.len, + WLAN_ELEMID_WAPI, ONE_BYTE, + NULL, 0, NULL, 0); + + wapi_ie_end = wlan_crypto_build_wapiie(session->vdev, wapi_ie); + if (wapi_ie_end) + ie_len = wapi_ie_end - wapi_ie; + + session->lim_join_req->rsnIE.length = ie_len; + qdf_mem_copy(session->lim_join_req->rsnIE.rsnIEdata, + wapi_ie, ie_len); + + qdf_mem_free(wapi_ie); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +lim_fill_wapi_ie(struct mac_context *mac_ctx, struct pe_session *session, + struct cm_vdev_join_req *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS lim_fill_crypto_params(struct mac_context *mac_ctx, + struct pe_session *session, + struct cm_vdev_join_req *req) +{ + int32_t ucast_cipher; + int32_t auth_mode; + int32_t akm; + tSirMacCapabilityInfo *ap_cap_info; + QDF_STATUS status; + + ucast_cipher = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + auth_mode = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + akm = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + ap_cap_info = (tSirMacCapabilityInfo *) + &session->lim_join_req->bssDescription.capabilityInfo; + + lim_set_privacy(mac_ctx, ucast_cipher, auth_mode, akm, + ap_cap_info->privacy); + session->encryptType = lim_get_encrypt_ed_type(ucast_cipher); + session->connected_akm = lim_get_connected_akm(session, ucast_cipher, + auth_mode, akm); + + session->wps_registration = req->is_wps_connection; + session->isOSENConnection = req->is_osen_connection; + + if (lim_is_rsn_profile(session)) + lim_fill_rsn_ie(mac_ctx, session, req); + else if (lim_is_wpa_profile(session)) + lim_fill_wpa_ie(mac_ctx, session, req); + else if (lim_is_wapi_profile(session)) + lim_fill_wapi_ie(mac_ctx, session, req); + + status = lim_strip_rsnx_ie(mac_ctx, session, req); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + lim_update_fils_config(mac_ctx, session, req); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void lim_fill_ml_info(struct cm_vdev_join_req *req, + struct join_req *pe_join_req) +{ + uint8_t idx, num_links = 0; + struct mlo_partner_info *partner_info = NULL; + + partner_info = &pe_join_req->partner_info; + if (!partner_info) + return; + + num_links = req->partner_info.num_partner_links; + if (num_links > WLAN_UMAC_MLO_MAX_VDEVS) + num_links = WLAN_UMAC_MLO_MAX_VDEVS; + + partner_info->num_partner_links = num_links; + + for (idx = 0; idx < num_links; idx++) { + partner_info->partner_link_info[idx].link_id = + req->partner_info.partner_link_info[idx].link_id; + qdf_copy_macaddr( + &partner_info->partner_link_info[idx].link_addr, + &req->partner_info.partner_link_info[idx].link_addr); + partner_info->partner_link_info[idx].chan_freq = + req->partner_info.partner_link_info[idx].chan_freq; + } + pe_join_req->assoc_link_id = req->assoc_link_id; +} + +static void lim_copy_ml_partner_info_to_session(struct pe_session *session, + struct cm_vdev_join_req *req) +{ + session->ml_partner_info = req->partner_info; +} + +void lim_set_emlsr_caps(struct mac_context *mac_ctx, struct pe_session *session) +{ + bool emlsr_cap, emlsr_allowed, emlsr_band_check, emlsr_enabled = false; + bool emlsr_aux_support = false; + + /* Check if HW supports eMLSR mode */ + emlsr_cap = policy_mgr_is_hw_emlsr_capable(mac_ctx->psoc); + if (!emlsr_cap) + return; + + /* Check if vendor command chooses eMLSR mode */ + wlan_mlme_get_emlsr_mode_enabled(mac_ctx->psoc, &emlsr_enabled); + + /* Check if ML links are in 5 GHz + 6 GHz combination */ + emlsr_band_check = lim_is_emlsr_band_supported(session); + + emlsr_allowed = emlsr_cap && emlsr_enabled && emlsr_band_check; + emlsr_aux_support = emlsr_enabled && WLAN_EMLSR_ENABLE && + wlan_mlme_is_aux_emlsr_support(mac_ctx->psoc, + WLAN_MLME_HW_MODE_MAX); + + if (emlsr_allowed || emlsr_aux_support) { + wlan_vdev_obj_lock(session->vdev); + wlan_vdev_mlme_cap_set(session->vdev, WLAN_VDEV_C_EMLSR_CAP); + wlan_vdev_obj_unlock(session->vdev); + } else { + wlan_vdev_obj_lock(session->vdev); + wlan_vdev_mlme_cap_clear(session->vdev, WLAN_VDEV_C_EMLSR_CAP); + wlan_vdev_obj_unlock(session->vdev); + } + + pe_debug("eMLSR vdev cap: %d", emlsr_allowed); + pe_debug("eMLSR aux support: %d", emlsr_aux_support); +} +#else +static void lim_fill_ml_info(struct cm_vdev_join_req *req, + struct join_req *pe_join_req) +{ +} + +static void +lim_copy_ml_partner_info_to_session(struct pe_session *session, + struct cm_vdev_join_req *req) +{} +#endif + +static QDF_STATUS +lim_fill_session_params(struct mac_context *mac_ctx, + struct pe_session *session, + struct cm_vdev_join_req *req) +{ + QDF_STATUS status; + struct bss_description *bss_desc; + uint32_t ie_len; + uint32_t bss_len; + struct join_req *pe_join_req; + int32_t akm; + struct mlme_legacy_priv *mlme_priv; + uint32_t assoc_ie_len; + bool eht_capab; + + ie_len = util_scan_entry_ie_len(req->entry); + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + + session->lim_join_req = qdf_mem_malloc(sizeof(*session->lim_join_req) + + bss_len); + if (!session->lim_join_req) + return QDF_STATUS_E_NOMEM; + + pe_join_req = session->lim_join_req; + bss_desc = &session->lim_join_req->bssDescription; + mgmt_txrx_frame_hex_dump(util_scan_entry_frame_ptr(req->entry), + util_scan_entry_frame_len(req->entry), + false); + status = wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc, + req->entry); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + + akm = wlan_crypto_get_param(session->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + if (!req->entry->ssid.length && + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE) && + req->owe_trans_ssid.length) { + req->entry->ssid = req->owe_trans_ssid; + pe_debug("OWE transition ssid is " QDF_SSID_FMT, + QDF_SSID_REF(req->entry->ssid.length, + req->entry->ssid.ssid)); + } + + /* Copy the SSID from req to session entry */ + session->ssId.length = req->entry->ssid.length; + qdf_mem_copy(session->ssId.ssId, req->entry->ssid.ssid, + session->ssId.length); + session->ssidHidden = req->is_ssid_hidden; + + status = lim_fill_pe_session(mac_ctx, session, bss_desc); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to fill pe session vdev id %d", + session->vdev_id); + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + + lim_copy_ml_partner_info_to_session(session, req); + + pe_debug("Assoc IE len: %d", req->assoc_ie.len); + if (req->assoc_ie.len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + req->assoc_ie.ptr, req->assoc_ie.len); + + assoc_ie_len = req->assoc_ie.len; + status = lim_fill_crypto_params(mac_ctx, session, req); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Error in handling RSNXE"); + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + + /* Reset the SPMK global cache for non-SAE connection */ + if (session->connected_akm != ANI_AKM_TYPE_SAE) { + wlan_mlme_set_sae_single_pmk_bss_cap(mac_ctx->psoc, + session->vdev_id, + false); + wlan_mlme_clear_sae_single_pmk_info(session->vdev, + NULL); + } + + if (assoc_ie_len != req->assoc_ie.len) { + pe_debug("After stripping Assoc IE len: %d", req->assoc_ie.len); + if (req->assoc_ie.len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + req->assoc_ie.ptr, + req->assoc_ie.len); + } + + qdf_mem_copy(pe_join_req->addIEAssoc.addIEdata, + req->assoc_ie.ptr, req->assoc_ie.len); + /* update assoc ie to cm */ + cm_update_session_assoc_ie(mac_ctx->psoc, session->vdev_id, + &req->assoc_ie); + pe_join_req->addIEAssoc.length = req->assoc_ie.len; + qdf_mem_copy(pe_join_req->addIEScan.addIEdata, + req->scan_ie.ptr, req->scan_ie.len); + pe_join_req->addIEScan.length = req->scan_ie.len; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) { + pe_err("Invalid mlme priv object"); + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(mlme_priv->connect_info.ext_cap_ie, + DOT11F_IE_EXTCAP_MAX_LEN + 2); + + if (session->lim_join_req->addIEAssoc.length) { + uint8_t *add_ie = NULL; + uint16_t add_ie_len; + + add_ie_len = session->lim_join_req->addIEAssoc.length; + add_ie = qdf_mem_malloc(add_ie_len); + if (!add_ie) { + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(add_ie, + session->lim_join_req->addIEAssoc.addIEdata, + add_ie_len); + + status = lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + DOT11F_EID_EXTCAP, ONE_BYTE, + NULL, 0, + mlme_priv->connect_info.ext_cap_ie, + DOT11F_IE_EXTCAP_MAX_LEN); + qdf_mem_free(add_ie); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Parsing of ext cap failed with status : %d", + status); + qdf_mem_zero(mlme_priv->connect_info.ext_cap_ie, + DOT11F_IE_EXTCAP_MAX_LEN + 2); + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + } + + if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + if (!lim_is_session_he_capable(session)) { + pe_err("JOIN_REQ with invalid 6G security"); + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + return QDF_STATUS_E_FAILURE; + } + } + + wlan_psoc_mlme_get_11be_capab(mac_ctx->psoc, &eht_capab); + if (eht_capab && wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + lim_fill_ml_info(req, pe_join_req); + + lim_set_emlsr_caps(mac_ctx, session); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_cm_handle_join_req(struct cm_vdev_join_req *req) +{ + struct mac_context *mac_ctx; + struct pe_session *pe_session; + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_INVAL; + + if (!req) + return QDF_STATUS_E_INVAL; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_REQ_EVENT, NULL, 0, 0); + + pe_session = lim_cm_create_session(mac_ctx, req); + if (!pe_session) + goto fail; + + pe_session->cm_id = req->cm_id; + status = lim_fill_session_params(mac_ctx, pe_session, req); + + if (QDF_IS_STATUS_ERROR(status)) + goto fail; + + lim_dump_session_info(mac_ctx, pe_session); + lim_dump_he_info(mac_ctx, pe_session); + lim_dump_eht_info(pe_session); + + if (lim_connect_skip_join_for_gc(pe_session)) { + pe_session->beacon = + qdf_mem_malloc(util_scan_entry_frame_len(req->entry)); + if (!pe_session->beacon) + goto fail; + pe_session->bcnLen = util_scan_entry_frame_len(req->entry); + qdf_mem_copy(pe_session->beacon, + util_scan_entry_frame_ptr(req->entry), + pe_session->bcnLen); + } + + status = lim_send_connect_req_to_mlm(pe_session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to send mlm req vdev id %d", + pe_session->vdev_id); + goto fail; + } + + if (!wlan_vdev_mlme_is_mlo_link_vdev(pe_session->vdev)) + lim_send_mlo_caps_ie(mac_ctx, pe_session->vdev, + QDF_STA_MODE, + pe_session->vdev_id); + + return QDF_STATUS_SUCCESS; + +fail: + if (pe_session) + pe_delete_session(mac_ctx, pe_session); + status = wma_remove_bss_peer_before_join(wma, req->vdev_id, req); + if (status == QDF_STATUS_E_PENDING) + return status; + lim_cm_send_connect_rsp(mac_ctx, NULL, req, CM_GENERIC_FAILURE, + QDF_STATUS_E_FAILURE, 0, false); + + return status; +} + +QDF_STATUS cm_process_join_req(struct scheduler_msg *msg) +{ + struct cm_vdev_join_req *req; + QDF_STATUS status; + + if (!msg || !msg->bodyptr) { + pe_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + req = msg->bodyptr; + + status = lim_cm_handle_join_req(req); + if (status != QDF_STATUS_E_PENDING) + cm_free_join_req(req); + + return status; +} + +static void lim_process_disconnect_sta(struct pe_session *session, + struct scheduler_msg *msg) +{ + if (QDF_IS_STATUS_SUCCESS( + wlan_vdev_is_restart_progress(session->vdev))) + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_RESTART_REQ_FAIL, + sizeof(*msg), msg); + else + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_DOWN, + sizeof(*msg), msg); +} + +static void lim_prepare_and_send_deauth(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct wlan_cm_vdev_discon_req *req) +{ + struct scheduler_msg msg = {0}; + struct deauth_req deauth_req = {0}; + + deauth_req.messageType = eWNI_SME_DEAUTH_REQ; + deauth_req.length = sizeof(deauth_req); + deauth_req.vdev_id = req->req.vdev_id; + qdf_mem_copy(deauth_req.bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + deauth_req.peer_macaddr = deauth_req.bssid; + deauth_req.reasonCode = req->req.reason_code; + + msg.bodyptr = &deauth_req; + msg.type = eWNI_SME_DEAUTH_REQ; + lim_process_disconnect_sta(pe_session, &msg); +} + +static void lim_prepare_and_send_disassoc(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct wlan_cm_vdev_discon_req *req) +{ + struct scheduler_msg msg = {0}; + struct disassoc_req disassoc_req = {0}; + + disassoc_req.messageType = eWNI_SME_DISASSOC_REQ; + disassoc_req.length = sizeof(disassoc_req); + disassoc_req.sessionId = req->req.vdev_id; + qdf_mem_copy(disassoc_req.bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + disassoc_req.peer_macaddr = disassoc_req.bssid; + disassoc_req.reasonCode = req->req.reason_code; + if (req->req.reason_code == REASON_FW_TRIGGERED_ROAM_FAILURE) { + disassoc_req.process_ho_fail = true; + disassoc_req.doNotSendOverTheAir = 1; + } else if (wlan_cm_is_vdev_roam_reassoc_state(pe_session->vdev)) { + disassoc_req.doNotSendOverTheAir = 1; + disassoc_req.reasonCode = + REASON_AUTHORIZED_ACCESS_LIMIT_REACHED; + } else if (req->req.reason_code == CM_MLO_LINK_SWITCH_DISCONNECT) { + disassoc_req.doNotSendOverTheAir = 1; + } + + msg.bodyptr = &disassoc_req; + msg.type = eWNI_SME_DISASSOC_REQ; + lim_process_disconnect_sta(pe_session, &msg); +} + +static void lim_process_nb_disconnect_req(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct wlan_cm_vdev_discon_req *req) +{ + enum wlan_reason_code reason_code; + bool enable_deauth_to_disassoc_map = false; + + reason_code = req->req.reason_code; + + switch (reason_code) { + case REASON_IFACE_DOWN: + case REASON_DEVICE_RECOVERY: + case REASON_OPER_CHANNEL_BAND_CHANGE: + case REASON_USER_TRIGGERED_ROAM_FAILURE: + case REASON_CHANNEL_SWITCH_FAILED: + case REASON_GATEWAY_REACHABILITY_FAILURE: + case REASON_OPER_CHANNEL_DISABLED_INDOOR: + /* Set reason REASON_DEAUTH_NETWORK_LEAVING for prop deauth */ + req->req.reason_code = REASON_DEAUTH_NETWORK_LEAVING; + fallthrough; + case REASON_PREV_AUTH_NOT_VALID: + case REASON_CLASS2_FRAME_FROM_NON_AUTH_STA: + lim_prepare_and_send_deauth(mac_ctx, pe_session, req); + break; + case REASON_DEAUTH_NETWORK_LEAVING: + wlan_mlme_get_enable_deauth_to_disassoc_map( + mac_ctx->psoc, + &enable_deauth_to_disassoc_map); + if (enable_deauth_to_disassoc_map) { + req->req.reason_code = REASON_DISASSOC_NETWORK_LEAVING; + return lim_prepare_and_send_disassoc(mac_ctx, + pe_session, req); + } + lim_prepare_and_send_deauth(mac_ctx, pe_session, req); + break; + default: + /* Set reason REASON_UNSPEC_FAILURE for prop disassoc */ + if (reason_code >= REASON_PROP_START && + reason_code != REASON_FW_TRIGGERED_ROAM_FAILURE) + req->req.reason_code = REASON_UNSPEC_FAILURE; + lim_prepare_and_send_disassoc(mac_ctx, pe_session, req); + } +} + +static void lim_process_sb_disconnect_req(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct wlan_cm_vdev_discon_req *req) +{ + struct scheduler_msg msg = {0}; + struct disassoc_cnf disassoc_cnf = {0}; + + /* For SB disconnect smeState should be in Deauth state + * One scenario where the smeState is not updated is when + * AP sends deauth on link vdev and disconnect req is triggered + */ + if (pe_session->limSmeState == eLIM_SME_LINK_EST_STATE) + pe_session->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + + if (pe_session->limSmeState == eLIM_SME_WT_DEAUTH_STATE) + disassoc_cnf.messageType = eWNI_SME_DEAUTH_CNF; + else + disassoc_cnf.messageType = eWNI_SME_DISASSOC_CNF; + disassoc_cnf.vdev_id = req->req.vdev_id; + qdf_mem_copy(disassoc_cnf.bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + disassoc_cnf.length = sizeof(disassoc_cnf); + disassoc_cnf.peer_macaddr = disassoc_cnf.bssid; + + msg.bodyptr = &disassoc_cnf; + msg.type = disassoc_cnf.messageType; + lim_process_disconnect_sta(pe_session, &msg); +} + +static +struct pe_session *lim_get_disconnect_session(struct mac_context *mac_ctx, + struct wlan_cm_vdev_discon_req *req) +{ + struct pe_session *session; + uint8_t pe_session_id; + + /* Try to find pe session with bssid */ + session = pe_find_session_by_bssid_and_vdev_id(mac_ctx, + req->req.bssid.bytes, + req->req.vdev_id, + &pe_session_id); + /* + * If bssid search fail try to find by vdev id, this can happen if + * Roaming change the BSSID during disconnect was getting processed. + */ + if (!session) { + session = pe_find_session_by_vdev_id(mac_ctx, req->req.vdev_id); + if (session) + pe_info("vdev_id %d cm_id 0x%x: using vdev id, session (%d) found for bssid " QDF_MAC_ADDR_FMT " [bssid in req " QDF_MAC_ADDR_FMT "] sme state %d mlm state %d", + req->req.vdev_id, req->cm_id, session->peSessionId, + QDF_MAC_ADDR_REF(session->bssId), + QDF_MAC_ADDR_REF(req->req.bssid.bytes), + session->limSmeState, session->limMlmState); + } + + /* + * In LFR2.0 roaming scenario, if HO disconnect is completed but + * NB disconnect is received before reassoc can start OR reassoc failure + * lead to disconnect, new AP's session will be idle in wait reassoc + * state and vdev in INIT state, so cleanup the session and send + * response of disconnect complete. + */ + if (session && + QDF_IS_STATUS_SUCCESS(wlan_vdev_mlme_is_init_state(session->vdev))) { + pe_err("vdev_id %d cm_id 0x%x: sme state %d mlm state %d: vdev is in INIT state. Delete session", + req->req.vdev_id, req->cm_id, session->limSmeState, + session->limMlmState); + pe_delete_session(mac_ctx, session); + session = NULL; + } + + return session; +} +static QDF_STATUS +lim_cm_handle_disconnect_req(struct wlan_cm_vdev_discon_req *req) +{ + struct mac_context *mac_ctx; + struct pe_session *pe_session; + + if (!req) + return QDF_STATUS_E_INVAL; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + pe_session = lim_get_disconnect_session(mac_ctx, req); + if (!pe_session) { + pe_err("vdev_id %d cm_id 0x%x: bssid " QDF_MAC_ADDR_FMT " : no session found", + req->req.vdev_id, req->cm_id, + QDF_MAC_ADDR_REF(req->req.bssid.bytes)); + lim_cm_send_disconnect_rsp(mac_ctx, req->req.vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (req->req.source == CM_PEER_DISCONNECT || + req->req.source == CM_SB_DISCONNECT || + req->req.source == CM_MLO_LINK_SWITCH_DISCONNECT) + lim_process_sb_disconnect_req(mac_ctx, pe_session, req); + else + lim_process_nb_disconnect_req(mac_ctx, pe_session, req); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_process_disconnect_req(struct scheduler_msg *msg) +{ + struct wlan_cm_vdev_discon_req *req; + QDF_STATUS status; + + if (!msg || !msg->bodyptr) { + mlme_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + req = msg->bodyptr; + + status = lim_cm_handle_disconnect_req(req); + + qdf_mem_free(req); + return status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wma_get_mld_info_sta() - get peer_mld_addr and assoc peer flag for sta + * @req: cm_peer_create_req + * @peer_mld_addr: peer mld mac addr + * @is_assoc_peer: is assoc peer + * + * Return: void + */ +static void wma_get_mld_info_sta(struct cm_peer_create_req *req, + uint8_t **peer_mld_addr, + bool *is_assoc_peer) +{ + if (!qdf_is_macaddr_zero(&req->mld_mac)) { + *peer_mld_addr = req->mld_mac.bytes; + *is_assoc_peer = req->is_assoc_peer; + } else { + *peer_mld_addr = NULL; + *is_assoc_peer = false; + } +} +#else +static void wma_get_mld_info_sta(struct cm_peer_create_req *req, + uint8_t **peer_mld_addr, + bool *is_assoc_peer) +{ + *peer_mld_addr = NULL; + *is_assoc_peer = false; +} +#endif + +QDF_STATUS cm_process_peer_create(struct scheduler_msg *msg) +{ + struct cm_peer_create_req *req; + QDF_STATUS status; + uint8_t *peer_mld_addr = NULL; + bool is_assoc_peer = false; + + if (!msg || !msg->bodyptr) { + mlme_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + req = msg->bodyptr; + + wma_get_mld_info_sta(req, &peer_mld_addr, &is_assoc_peer); + status = wma_add_bss_peer_sta(req->vdev_id, req->peer_mac.bytes, true, + peer_mld_addr, is_assoc_peer); + + qdf_mem_free(req); + + return status; +} + +#ifdef WLAN_FEATURE_HOST_ROAM +static void lim_handle_reassoc_req(struct cm_vdev_join_req *req) +{ + struct mac_context *mac_ctx; + struct pe_session *session_entry; + uint8_t session_id; + uint8_t vdev_id; + uint32_t ie_len; + uint32_t bss_len; + struct join_req *reassoc_req = NULL; + uint16_t caps; + uint32_t val; + tLimMlmReassocReq *mlm_reassoc_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + int8_t local_pwr_constraint = 0, reg_max = 0; + uint32_t tele_bcn_en = 0; + QDF_STATUS status; + tDot11fBeaconIEs *ie_struct; + ePhyChanBondState cb_mode; + tSirMacCapabilityInfo *ap_cap_info; + struct bss_description *bss_desc; + uint8_t wmm_mode, value; + bool is_pwr_constraint; + int32_t ucast_cipher; + int32_t auth_mode; + int32_t akm; + + if (!req) + return; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return; + + vdev_id = req->vdev_id; + session_entry = pe_find_session_by_bssid(mac_ctx, + req->entry->bssid.bytes, + &session_id); + if (!session_entry) { + pe_err("Session does not exist for: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(req->entry->bssid.bytes)); + ret_code = eSIR_SME_INVALID_PARAMETERS; + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (session_entry) + lim_handle_sme_join_result(mac_ctx, + eSIR_SME_INVALID_PARAMETERS, + STATUS_UNSPECIFIED_FAILURE, + session_entry); + goto end; + } + + if (session_entry->lim_join_req) { + qdf_mem_free(session_entry->lim_join_req); + session_entry->lim_join_req = NULL; + } + + session_entry->cm_id = req->cm_id; + ie_len = util_scan_entry_ie_len(req->entry); + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + + reassoc_req = qdf_mem_malloc(sizeof(*session_entry->lim_join_req) + + bss_len); + if (!reassoc_req) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_REQ_EVENT, + session_entry, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + pe_debug("Beacon/probe frame received:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + util_scan_entry_frame_ptr(req->entry), + util_scan_entry_frame_len(req->entry)); + + bss_desc = &reassoc_req->bssDescription; + status = wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc, + req->entry); + if (QDF_IS_STATUS_ERROR(status)) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + /* Store the reassoc handle in the session Table */ + session_entry->lim_join_req = reassoc_req; + session_entry->pLimReAssocReq = reassoc_req; + + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ie_struct); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("IE parsing failed vdev id %d", + session_entry->vdev_id); + session_entry->lim_join_req = NULL; + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + pe_debug("Assoc IE len: %d", req->assoc_ie.len); + if (req->assoc_ie.len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + req->assoc_ie.ptr, req->assoc_ie.len); + if (lim_is_rsn_profile(session_entry)) + lim_fill_rsn_ie(mac_ctx, session_entry, req); + else if (lim_is_wpa_profile(session_entry)) + lim_fill_wpa_ie(mac_ctx, session_entry, req); + else if (lim_is_wapi_profile(session_entry)) + lim_fill_wapi_ie(mac_ctx, session_entry, req); + + lim_strip_rsnx_ie(mac_ctx, session_entry, req); + + if (lim_is_rsn_profile(session_entry) && + !util_scan_entry_rsnxe(req->entry)) { + pe_debug("Bss bcn has no RSNXE, strip if has"); + status = lim_strip_ie(mac_ctx, req->assoc_ie.ptr, + (uint16_t *)&req->assoc_ie.len, + WLAN_ELEMID_RSNXE, ONE_BYTE, + NULL, 0, NULL, 0); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Strip RNSXE failed"); + } + + pe_debug("After stripping Assoc IE len: %d", req->assoc_ie.len); + if (req->assoc_ie.len) + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + req->assoc_ie.ptr, req->assoc_ie.len); + qdf_mem_copy(reassoc_req->addIEAssoc.addIEdata, + req->assoc_ie.ptr, req->assoc_ie.len); + reassoc_req->addIEAssoc.length = req->assoc_ie.len; + /* update assoc ie to cm */ + cm_update_session_assoc_ie(mac_ctx->psoc, vdev_id, &req->assoc_ie); + ucast_cipher = wlan_crypto_get_param(session_entry->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + auth_mode = wlan_crypto_get_param(session_entry->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + akm = wlan_crypto_get_param(session_entry->vdev, + WLAN_CRYPTO_PARAM_KEY_MGMT); + ap_cap_info = (tSirMacCapabilityInfo *)&req->entry->cap_info.value; + + lim_set_privacy(mac_ctx, ucast_cipher, auth_mode, akm, + ap_cap_info->privacy); + + if (session_entry->vhtCapability) { + if (session_entry->opmode == QDF_STA_MODE) { + session_entry->vht_config.su_beam_formee = + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.su_bformee; + } else { + session_entry->vht_config.su_beam_formee = 0; + } + session_entry->enableVhtpAid = + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_paid; + session_entry->enableVhtGid = + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_gid; + } + + if (session_entry->nss == 1) + session_entry->supported_nss_1x1 = true; + + lim_check_oui_and_update_session(mac_ctx, session_entry, ie_struct); + + session_entry->lim_reassoc_chan_freq = req->entry->channel.chan_freq; + cb_mode = wlan_get_cb_mode(mac_ctx, + session_entry->lim_reassoc_chan_freq, + ie_struct, + session_entry); + session_entry->reAssocHtSupportedChannelWidthSet = cb_mode ? 1 : 0; + session_entry->reAssocHtRecommendedTxWidthSet = + session_entry->reAssocHtSupportedChannelWidthSet; + session_entry->reAssocHtSecondaryChannelOffset = cb_mode; + + mac_ctx->mlme_cfg->power.local_power_constraint = + wlan_get_11h_power_constraint(mac_ctx, + &ie_struct->PowerConstraints); + if (session_entry->dot11mode == MLME_DOT11_MODE_11B) + mac_ctx->mlme_cfg->feature_flags.enable_short_slot_time_11g = 0; + else + mac_ctx->mlme_cfg->feature_flags.enable_short_slot_time_11g = + mac_ctx->mlme_cfg->ht_caps.short_slot_time_enabled; + session_entry->enable_session_twt_support = + lim_enable_twt(mac_ctx, ie_struct); + + qdf_mem_free(ie_struct); + + session_entry->send_smps_action = + mac_ctx->roam.configParam.send_smps_action; + session_entry->lim_join_req = NULL; + + /* Reassociate request is expected in link established state only. */ + if (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE) { + if (session_entry->limSmeState == eLIM_SME_WT_REASSOC_STATE) { + /* + * May be from 11r FT pre-auth. So lets check it + * before we bail out + */ + pe_debug("Session in reassoc state is %d", + session_entry->peSessionId); + + /* Make sure its our preauth bssid */ + if (qdf_mem_cmp(req->entry->bssid.bytes, + session_entry->limReAssocbssId, + QDF_MAC_ADDR_SIZE)) { + pe_err("Requested BSSID: "QDF_MAC_ADDR_FMT " but bssId in reassoc state" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(req->entry->bssid.bytes), + QDF_MAC_ADDR_REF(session_entry->limReAssocbssId)); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + session_entry->vdev_id = vdev_id; + mlm_reassoc_req = + qdf_mem_malloc(sizeof(*mlm_reassoc_req)); + if (!mlm_reassoc_req) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + lim_dump_session_info(mac_ctx, session_entry); + lim_dump_he_info(mac_ctx, session_entry); + lim_dump_eht_info(session_entry); + + /* Update PE sessionId */ + mlm_reassoc_req->sessionId = session_entry->peSessionId; + status = lim_send_ft_reassoc_req(session_entry, + mlm_reassoc_req); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(mlm_reassoc_req); + ret_code = eSIR_SME_REFUSED; + goto end; + } + return; + } + /* + * Should not have received eWNI_SME_REASSOC_REQ + */ + pe_err("received unexpected SME_REASSOC_REQ in state %X", + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, session_entry->limSmeState); + + ret_code = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto end; + } + + qdf_mem_copy(session_entry->limReAssocbssId, req->entry->bssid.bytes, + sizeof(tSirMacAddr)); + + session_entry->limReassocBssCaps = req->entry->cap_info.value; + reg_max = wlan_reg_get_channel_reg_power_for_freq( + mac_ctx->pdev, session_entry->curr_op_freq); + local_pwr_constraint = reg_max; + + lim_extract_ap_capability(mac_ctx, (uint8_t *)bss_desc->ieFields, + lim_get_ielen_from_bss_description(bss_desc), + &session_entry->limReassocBssQosCaps, + &session_entry->gLimCurrentBssUapsd, + &local_pwr_constraint, session_entry, + &is_pwr_constraint); + if (is_pwr_constraint) + local_pwr_constraint = reg_max - local_pwr_constraint; + + session_entry->maxTxPower = QDF_MIN(reg_max, (local_pwr_constraint)); + session_entry->max_11h_pwr = + QDF_MIN(lim_get_cfg_max_tx_power(mac_ctx, + bss_desc->chan_freq), + MAX_TX_PWR_CAP); + session_entry->min_11h_pwr = MIN_TX_PWR_CAP; + if (!session_entry->max_11h_pwr) + session_entry->max_11h_pwr = MAX_TX_PWR_CAP; + + if (session_entry->max_11h_pwr > session_entry->maxTxPower) + session_entry->max_11h_pwr = session_entry->maxTxPower; + + pe_info("Reg max = %d, local pwr constraint = %d, max tx = %d", + reg_max, local_pwr_constraint, session_entry->maxTxPower); + /* Copy the SSID from session entry to local variable */ + session_entry->limReassocSSID.length = req->entry->ssid.length; + qdf_mem_copy(session_entry->limReassocSSID.ssId, + req->entry->ssid.ssid, + session_entry->limReassocSSID.length); + + if (!session_entry->enable_session_twt_support) { + status = wlan_mlme_get_wmm_mode(mac_ctx->psoc, &wmm_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Get wmm_mode failed"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } else if (wmm_mode == 2) { + /*QoS not enabled in cfg file */ + session_entry->gUapsdPerAcBitmask = 0; + } else { + /*QoS enabled, update uapsd mask from cfg file */ + status = wlan_mlme_get_wmm_uapsd_mask(mac_ctx->psoc, + &value); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Get uapsd_mask failed"); + ret_code = eSIR_SME_INVALID_PARAMETERS; + goto end; + } else + session_entry->gUapsdPerAcBitmask = value; + } + } + + mlm_reassoc_req = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (!mlm_reassoc_req) { + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + goto end; + } + + qdf_mem_copy(mlm_reassoc_req->peerMacAddr, + session_entry->limReAssocbssId, sizeof(tSirMacAddr)); + + if (lim_get_capability_info(mac_ctx, &caps, session_entry) != + QDF_STATUS_SUCCESS) + pe_err("could not retrieve Capabilities value"); + + lim_update_caps_info_for_bss(mac_ctx, &caps, + req->entry->cap_info.value); + pe_debug("Capabilities info Reassoc: 0x%X", caps); + + mlm_reassoc_req->capabilityInfo = caps; + + /* Update PE session_id */ + mlm_reassoc_req->sessionId = session_id; + + /* + * If telescopic beaconing is enabled, set listen interval to + * CFG_TELE_BCN_MAX_LI + */ + + tele_bcn_en = mac_ctx->mlme_cfg->sap_cfg.tele_bcn_wakeup_en; + + if (tele_bcn_en) + val = mac_ctx->mlme_cfg->sap_cfg.tele_bcn_max_li; + else + val = mac_ctx->mlme_cfg->sap_cfg.listen_interval; + + mlm_reassoc_req->listenInterval = (uint16_t) val; + if (mac_ctx->mlme_cfg->gen.enabled_11h && + ap_cap_info->spectrumMgt && bss_desc->nwType == eSIR_11A_NW_TYPE) + session_entry->spectrumMgtEnabled = true; + + /* Enable the spectrum management if this is a DFS channel */ + if (session_entry->country_info_present && + lim_isconnected_on_dfs_freq( + mac_ctx, session_entry->curr_op_freq)) + session_entry->spectrumMgtEnabled = true; + + session_entry->limPrevSmeState = session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_REASSOC_STATE; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, session_entry->peSessionId, + session_entry->limSmeState)); + + lim_dump_session_info(mac_ctx, session_entry); + lim_dump_he_info(mac_ctx, session_entry); + lim_dump_eht_info(session_entry); + + status = lim_send_reassoc_req(session_entry, mlm_reassoc_req); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(mlm_reassoc_req); + ret_code = eSIR_SME_REFUSED; + goto end; + } + + return; +end: + if (reassoc_req) { + qdf_mem_free(reassoc_req); + if (session_entry) + session_entry->pLimReAssocReq = NULL; + } + + /* + * Send Reassoc failure response to host + * (note session_entry may be NULL, but that's OK) + */ + lim_send_sme_join_reassoc_rsp(mac_ctx, eWNI_SME_REASSOC_RSP, + ret_code, STATUS_UNSPECIFIED_FAILURE, + session_entry, vdev_id); +} + +QDF_STATUS cm_process_reassoc_req(struct scheduler_msg *msg) +{ + struct cm_vdev_join_req *req; + + if (!msg || !msg->bodyptr) { + mlme_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + req = msg->bodyptr; + + lim_handle_reassoc_req(req); + + cm_free_join_req(req); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_fill_preauth_req_dot11_mode(struct mac_context *mac_ctx, + tpSirFTPreAuthReq req, + uint8_t vdev_id) +{ + QDF_STATUS status; + tDot11fBeaconIEs *ie_struct; + enum mlme_dot11_mode self_dot11_mode; + enum mlme_dot11_mode bss_dot11_mode; + enum mlme_dot11_mode intersected_mode; + struct bss_description *bss_desc = req->pbssDescription; + + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ie_struct); + if (QDF_IS_STATUS_ERROR(status)) { + mlme_err("IE parsing failed"); + return QDF_STATUS_E_FAILURE; + } + + self_dot11_mode = lim_get_self_dot11_mode(mac_ctx, QDF_STA_MODE, + vdev_id); + /* if user set dot11 mode by cmd, need to do intersect first */ + self_dot11_mode = + lim_intersect_user_dot11_mode(mac_ctx, QDF_STA_MODE, + vdev_id, self_dot11_mode); + + bss_dot11_mode = lim_get_bss_dot11_mode(mac_ctx, bss_desc, ie_struct); + + status = lim_get_intersected_dot11_mode_sta_ap(mac_ctx, self_dot11_mode, + bss_dot11_mode, + &intersected_mode, + ie_struct, bss_desc); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(ie_struct); + return status; + } + + req->dot11mode = intersected_mode; + pe_debug("vdev %d self dot11mode %d bss_dot11 mode %d intersected_mode %d", + vdev_id, self_dot11_mode, bss_dot11_mode, intersected_mode); + + qdf_mem_free(ie_struct); + return status; +} + +static QDF_STATUS lim_cm_handle_preauth_req(struct wlan_preauth_req *req) +{ + struct mac_context *mac_ctx; + struct wlan_objmgr_vdev *vdev; + struct scan_cache_entry *scan_entry; + struct bss_description *bss_desc = NULL; + uint32_t ie_len, bss_len; + uint8_t vdev_id; + struct mlme_legacy_priv *mlme_priv; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirFTPreAuthReq preauth_req = NULL; + bool buf_consumed = true; + + if (!req) + return QDF_STATUS_E_INVAL; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + ie_len = util_scan_entry_ie_len(req->entry); + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + + bss_desc = qdf_mem_malloc(sizeof(*bss_desc) + bss_len); + if (!bss_desc) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + scan_entry = req->entry; + status = wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc, + scan_entry); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + + preauth_req = qdf_mem_malloc(sizeof(tSirFTPreAuthReq)); + if (!preauth_req) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + vdev_id = req->vdev_id; + preauth_req->pbssDescription = bss_desc; + status = lim_fill_preauth_req_dot11_mode(mac_ctx, preauth_req, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("dot11mode doesn't get proper filling"); + goto end; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + status = QDF_STATUS_E_FAILURE; + goto end; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + status = QDF_STATUS_E_FAILURE; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + goto end; + } + qdf_mem_copy(preauth_req->ft_ies, + mlme_priv->connect_info.ft_info.auth_ft_ie, + mlme_priv->connect_info.ft_info.auth_ie_len); + preauth_req->ft_ies_length = + mlme_priv->connect_info.ft_info.auth_ie_len; + preauth_req->pre_auth_channel_freq = scan_entry->channel.chan_freq; + wlan_mlme_get_bssid_vdev_id( + mac_ctx->pdev, vdev_id, + (struct qdf_mac_addr *)&preauth_req->currbssId); + qdf_mem_copy(&preauth_req->preAuthbssId, + scan_entry->bssid.bytes, QDF_MAC_ADDR_SIZE); + + wlan_vdev_obj_lock(vdev); + qdf_mem_copy(&preauth_req->self_mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), QDF_MAC_ADDR_SIZE); + wlan_vdev_obj_unlock(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + buf_consumed = lim_process_ft_pre_auth_req(mac_ctx, preauth_req); + +end: + if (buf_consumed) { + if (bss_desc) + qdf_mem_free(bss_desc); + if (preauth_req) + qdf_mem_free(preauth_req); + } + + return status; +} + +QDF_STATUS cm_process_preauth_req(struct scheduler_msg *msg) +{ + struct wlan_preauth_req *req; + QDF_STATUS status; + + if (!msg || !msg->bodyptr) { + mlme_err("msg or msg->bodyptr is NULL"); + return QDF_STATUS_E_INVAL; + } + + req = msg->bodyptr; + + status = lim_cm_handle_preauth_req(req); + + cm_free_preauth_req(req); + return status; +} +#endif + +/** + * lim_get_eirp_320_power_from_tpe_ie() - To get eirp power for 320 MHZ + * @tpe: transmit power env Ie advertised by AP + * + * Return: eirp power + */ +static uint8_t +lim_get_eirp_320_power_from_tpe_ie(tDot11fIEtransmit_power_env *tpe) +{ + uint8_t eirp_power_320_Mhz = 0; + + /* + * Don't consider 320 MHz EIRP power until AP advertises EIRP + * powers till 160 MHz. + */ + if (tpe->max_tx_pwr_count < MAX_TX_PWR_COUNT_FOR_160MHZ) { + pe_debug("tx power count advertised by ap %d less than %d", + tpe->max_tx_pwr_count, MAX_TX_PWR_COUNT_FOR_160MHZ); + return INVALID_TPE_POWER; + } + + if (tpe->num_tx_power < MAX_NUM_TX_POWER_FOR_320MHZ) + return INVALID_TPE_POWER; + + if (tpe->max_tx_pwr_interpret == LOCAL_EIRP) + eirp_power_320_Mhz = + tpe->ext_max_tx_power.ext_max_tx_power_local_eirp.max_tx_power_for_320; + else + eirp_power_320_Mhz = + tpe->ext_max_tx_power.ext_max_tx_power_reg_eirp.max_tx_power_for_320; + + return eirp_power_320_Mhz; +} + +/** + * lim_update_ext_tpe_power() - To update ext max transmit power element + * @mac: mac context + * @session: pe session + * @tpe: transmit power env Ie + * @curr_freq: current freq + * @tpe_updated: tpe power changed or not + * @existing_pwr_count: no of existing pwr updated + * @is_psd: is psd or not + * + * Return: no. of power updated + */ +static uint8_t +lim_update_ext_tpe_power(struct mac_context *mac, struct pe_session *session, + tDot11fIEtransmit_power_env *tpe, qdf_freq_t curr_freq, + bool *tpe_updated, uint8_t existing_pwr_count, + bool is_psd) +{ + struct vdev_mlme_obj *vdev_mlme; + struct ch_params ch_params = {0}; + qdf_freq_t curr_op_freq; + uint8_t total_psd_power = 0; + uint8_t ext_power_updated = 0; + uint8_t i, j; + uint8_t eirp_pwr = 0; + uint8_t ext_psd_count = 0; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!vdev_mlme) + return 0; + + ch_params.ch_width = CH_WIDTH_320MHZ; + curr_op_freq = session->curr_op_freq; + if (is_psd) { + if (tpe->max_tx_pwr_interpret == LOCAL_EIRP_PSD) + ext_psd_count = + tpe->ext_max_tx_power.ext_max_tx_power_local_psd.ext_count; + else + ext_psd_count = + tpe->ext_max_tx_power.ext_max_tx_power_reg_psd.ext_count; + + if (existing_pwr_count >= MAX_NUM_PWR_LEVEL) { + pe_debug("already updated %d psd powers", + existing_pwr_count); + return 0; + } + + if (!ext_psd_count) { + pe_debug("Ext psd count is 0"); + return 0; + } + + total_psd_power = existing_pwr_count + ext_psd_count; + if (total_psd_power > MAX_NUM_PWR_LEVEL) { + pe_debug("total powers greater than max %d", + MAX_NUM_PWR_LEVEL); + return existing_pwr_count; + } + i = existing_pwr_count; + for (j = 0; j < ext_psd_count && i < total_psd_power; j++) + { + if (tpe->max_tx_pwr_interpret == LOCAL_EIRP_PSD) { + if (vdev_mlme->reg_tpc_obj.tpe[i] != + tpe->ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power[j] || + vdev_mlme->reg_tpc_obj.frequency[i] != curr_freq) + *tpe_updated = true; + } else { + if (vdev_mlme->reg_tpc_obj.tpe[i] != + tpe->ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power[j] || + vdev_mlme->reg_tpc_obj.frequency[i] != curr_freq) + *tpe_updated = true; + } + + vdev_mlme->reg_tpc_obj.frequency[i] = curr_freq; + curr_freq += 20; + if (tpe->max_tx_pwr_interpret == LOCAL_EIRP_PSD) + vdev_mlme->reg_tpc_obj.tpe[i] = + tpe->ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power[j]; + else + vdev_mlme->reg_tpc_obj.tpe[i] = + tpe->ext_max_tx_power.ext_max_tx_power_reg_psd.max_tx_psd_power[j]; + i++; + } + ext_power_updated = i; + + } else { + eirp_pwr = lim_get_eirp_320_power_from_tpe_ie(tpe); + if (eirp_pwr == INVALID_TPE_POWER) + return 0; + i = lim_get_num_pwr_levels(false, CH_WIDTH_320MHZ) - 1; + + wlan_reg_set_channel_params_for_pwrmode( + mac->pdev, curr_op_freq, 0, + &ch_params, REG_CURRENT_PWR_MODE); + + if (vdev_mlme->reg_tpc_obj.tpe[i] != eirp_pwr || + vdev_mlme->reg_tpc_obj.frequency[i] != + ch_params.mhz_freq_seg0) + *tpe_updated = true; + + vdev_mlme->reg_tpc_obj.frequency[i] = ch_params.mhz_freq_seg0; + vdev_mlme->reg_tpc_obj.tpe[i] = eirp_pwr; + ext_power_updated = 1; + } + return ext_power_updated; +} + +static uint8_t lim_get_num_tpe_octets(uint8_t max_transmit_power_count) +{ + if (!max_transmit_power_count) + return max_transmit_power_count; + + return 1 << (max_transmit_power_count - 1); +} + +void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session, + tDot11fIEtransmit_power_env *tpe_ies, uint8_t num_tpe_ies, + tDot11fIEhe_op *he_op, bool *has_tpe_updated) +{ + struct vdev_mlme_obj *vdev_mlme; + uint8_t i, local_tpe_count = 0, reg_tpe_count = 0, num_octets; + uint8_t psd_index = 0, non_psd_index = 0; + uint8_t bw_num; + uint16_t bw_val, ch_width; + qdf_freq_t curr_op_freq, curr_freq = 0; + enum reg_6g_client_type client_mobility_type; + struct ch_params ch_params = {0}; + tDot11fIEtransmit_power_env single_tpe, local_tpe, reg_tpe; + /* + * PSD is power spectral density, incoming TPE could contain + * non PSD info, or PSD info, or both, so need to keep track of them + */ + bool non_psd_set = false, psd_set = false; + bool both_tpe_present = false; + bool local_eirp_set = false, local_psd_set = false; + bool reg_eirp_set = false, reg_psd_set = false; + uint8_t local_eirp_idx = 0, local_psd_idx = 0; + uint8_t reg_eirp_idx = 0, reg_psd_idx = 0; + uint8_t min_count = 0; + uint8_t ext_power_updated = 0, eirp_power = 0; + uint8_t expect_num; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!vdev_mlme) + return; + + if (session->sta_follows_sap_power) { + pe_debug_rl("STA operates in 6 GHz power of SAP, do not update STA power"); + return; + } + + vdev_mlme->reg_tpc_obj.num_pwr_levels = 0; + *has_tpe_updated = false; + + wlan_reg_get_cur_6g_client_type(mac->pdev, &client_mobility_type); + + for (i = 0; i < num_tpe_ies; i++) { + single_tpe = tpe_ies[i]; + if (single_tpe.present && + (single_tpe.max_tx_pwr_category == client_mobility_type)) { + if (single_tpe.max_tx_pwr_interpret == LOCAL_EIRP || + single_tpe.max_tx_pwr_interpret == LOCAL_EIRP_PSD) + local_tpe_count++; + else if (single_tpe.max_tx_pwr_interpret == + REGULATORY_CLIENT_EIRP || + single_tpe.max_tx_pwr_interpret == + REGULATORY_CLIENT_EIRP_PSD) + reg_tpe_count++; + } + } + + if (!reg_tpe_count && !local_tpe_count) + return; + else if (reg_tpe_count && local_tpe_count) + both_tpe_present = true; + + for (i = 0; i < num_tpe_ies; i++) { + single_tpe = tpe_ies[i]; + if (single_tpe.present && + (single_tpe.max_tx_pwr_category == client_mobility_type)) { + if (single_tpe.max_tx_pwr_interpret == LOCAL_EIRP) { + non_psd_index = i; + non_psd_set = true; + local_eirp_idx = non_psd_index; + local_eirp_set = non_psd_set; + } else if (single_tpe.max_tx_pwr_interpret == + LOCAL_EIRP_PSD) { + psd_index = i; + psd_set = true; + local_psd_idx = psd_index; + local_psd_set = psd_set; + } else if (single_tpe.max_tx_pwr_interpret == + REGULATORY_CLIENT_EIRP) { + non_psd_index = i; + non_psd_set = true; + reg_eirp_idx = non_psd_index; + reg_eirp_set = non_psd_set; + } else if (single_tpe.max_tx_pwr_interpret == + REGULATORY_CLIENT_EIRP_PSD) { + psd_index = i; + psd_set = true; + reg_psd_idx = psd_index; + reg_psd_set = psd_set; + } + } + } + + curr_op_freq = session->curr_op_freq; + bw_val = wlan_reg_get_bw_value(session->ch_width); + + if (non_psd_set && !psd_set) { + single_tpe = tpe_ies[non_psd_index]; + if (single_tpe.max_tx_pwr_count > + MAX_TX_PWR_COUNT_FOR_160MHZ) { + pe_debug("Invalid max tx pwr count: %d", + single_tpe.max_tx_pwr_count); + single_tpe.max_tx_pwr_count = + MAX_TX_PWR_COUNT_FOR_160MHZ; + } + expect_num = lim_get_num_pwr_levels(false, session->ch_width); + single_tpe.max_tx_pwr_count = + QDF_MIN(single_tpe.max_tx_pwr_count, expect_num - 1); + + vdev_mlme->reg_tpc_obj.is_psd_power = false; + vdev_mlme->reg_tpc_obj.eirp_power = 0; + bw_num = sizeof(get_next_higher_bw) / + sizeof(get_next_higher_bw[0]); + if (single_tpe.max_tx_pwr_count >= bw_num) { + pe_debug("tx pwr count: %d, larger than bw num: %d", + single_tpe.max_tx_pwr_count, bw_num); + single_tpe.max_tx_pwr_count = bw_num - 1; + } + vdev_mlme->reg_tpc_obj.num_pwr_levels = + single_tpe.max_tx_pwr_count + 1; + + ch_params.ch_width = CH_WIDTH_20MHZ; + /* + * Update tpe power till 160 MHZ, 320 MHZ power will be + * advertised via ext_max_tx_power param of TPE IE. + */ + for (i = 0; i < single_tpe.max_tx_pwr_count + 1 && + (ch_params.ch_width != CH_WIDTH_320MHZ); i++) { + wlan_reg_set_channel_params_for_pwrmode( + mac->pdev, + curr_op_freq, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + if (vdev_mlme->reg_tpc_obj.tpe[i] != + single_tpe.tx_power[i] || + vdev_mlme->reg_tpc_obj.frequency[i] != + ch_params.mhz_freq_seg0) + *has_tpe_updated = true; + vdev_mlme->reg_tpc_obj.frequency[i] = + ch_params.mhz_freq_seg0; + vdev_mlme->reg_tpc_obj.tpe[i] = single_tpe.tx_power[i]; + if (ch_params.ch_width != CH_WIDTH_INVALID) + ch_params.ch_width = + get_next_higher_bw[ch_params.ch_width]; + } + + if (ch_params.ch_width == CH_WIDTH_320MHZ) { + ext_power_updated = + lim_update_ext_tpe_power( + mac, session, &single_tpe, + curr_freq, has_tpe_updated, + 0, false); + vdev_mlme->reg_tpc_obj.num_pwr_levels += + ext_power_updated; + } + } + + if (psd_set) { + single_tpe = tpe_ies[psd_index]; + if (single_tpe.max_tx_pwr_count > + MAX_TX_PWR_COUNT_FOR_160MHZ_PSD) { + pe_debug("Invalid max tx pwr count psd: %d", + single_tpe.max_tx_pwr_count); + single_tpe.max_tx_pwr_count = + MAX_TX_PWR_COUNT_FOR_160MHZ_PSD; + } + expect_num = lim_get_num_pwr_levels(true, session->ch_width); + + vdev_mlme->reg_tpc_obj.is_psd_power = true; + num_octets = + lim_get_num_tpe_octets(single_tpe.max_tx_pwr_count); + num_octets = QDF_MIN(num_octets, expect_num); + + vdev_mlme->reg_tpc_obj.num_pwr_levels = num_octets; + + ch_params.ch_width = session->ch_width; + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, curr_op_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + + if (ch_params.mhz_freq_seg1) + curr_freq = ch_params.mhz_freq_seg1 - bw_val / 2 + 10; + else + curr_freq = ch_params.mhz_freq_seg0 - bw_val / 2 + 10; + + if (!num_octets) { + if (!he_op->oper_info_6g_present) + ch_width = session->ch_width; + else + ch_width = he_op->oper_info_6g.info.ch_width; + num_octets = lim_get_num_pwr_levels(true, + session->ch_width); + vdev_mlme->reg_tpc_obj.num_pwr_levels = num_octets; + for (i = 0; i < num_octets; i++) { + if (vdev_mlme->reg_tpc_obj.tpe[i] != + single_tpe.tx_power[0] || + vdev_mlme->reg_tpc_obj.frequency[i] != + curr_freq) + *has_tpe_updated = true; + vdev_mlme->reg_tpc_obj.frequency[i] = curr_freq; + curr_freq += 20; + vdev_mlme->reg_tpc_obj.tpe[i] = + single_tpe.tx_power[0]; + } + } else { + for (i = 0; i < num_octets; i++) { + if (vdev_mlme->reg_tpc_obj.tpe[i] != + single_tpe.tx_power[i] || + vdev_mlme->reg_tpc_obj.frequency[i] != + curr_freq) + *has_tpe_updated = true; + vdev_mlme->reg_tpc_obj.frequency[i] = curr_freq; + curr_freq += 20; + vdev_mlme->reg_tpc_obj.tpe[i] = + single_tpe.tx_power[i]; + } + } + ext_power_updated = + lim_update_ext_tpe_power(mac, session, &single_tpe, + curr_freq, has_tpe_updated, + num_octets, true); + vdev_mlme->reg_tpc_obj.num_pwr_levels = + ext_power_updated; + } + + if (non_psd_set) { + single_tpe = tpe_ies[non_psd_index]; + vdev_mlme->reg_tpc_obj.eirp_power = + single_tpe.tx_power[single_tpe.max_tx_pwr_count]; + /* + * If a valid eirp power is received in 320 MHZ via ext element + * then update eirp power with received eirp. + */ + if (session->ch_width == CH_WIDTH_320MHZ) { + eirp_power = + lim_get_eirp_320_power_from_tpe_ie(&single_tpe); + if (eirp_power != INVALID_TPE_POWER) + vdev_mlme->reg_tpc_obj.eirp_power = eirp_power; + } + vdev_mlme->reg_tpc_obj.is_psd_power = false; + } + + if (both_tpe_present) { + pe_debug("Local: eirp: %d psd: %d, Regulatory: eirp: %d psd %d", + local_eirp_set, local_psd_set, reg_eirp_set, + reg_psd_set); + if (local_eirp_set && reg_eirp_set) { + local_tpe = tpe_ies[local_eirp_idx]; + reg_tpe = tpe_ies[reg_eirp_idx]; + } else if (local_psd_set && reg_psd_set) { + local_tpe = tpe_ies[local_psd_idx]; + reg_tpe = tpe_ies[reg_psd_idx]; + } else { + return; + } + + min_count = QDF_MIN(local_tpe.max_tx_pwr_count, + reg_tpe.max_tx_pwr_count); + for (i = 0; i < min_count + 1; i++) { + if (vdev_mlme->reg_tpc_obj.tpe[i] != + QDF_MIN(local_tpe.tx_power[i], reg_tpe.tx_power[i])) + *has_tpe_updated = true; + vdev_mlme->reg_tpc_obj.tpe[i] = + QDF_MIN(local_tpe.tx_power[i], + reg_tpe.tx_power[i]); + pe_debug("TPE: Local: %d, Reg: %d, power updated: %d", + local_tpe.tx_power[i], reg_tpe.tx_power[i], + *has_tpe_updated); + } + } +} + +void lim_process_tpe_ie_from_beacon(struct mac_context *mac, + struct pe_session *session, + struct bss_description *bss_desc, + bool *has_tpe_updated) +{ + tDot11fBeaconIEs *bcn_ie; + uint32_t buf_len; + uint8_t *buf; + int status; + + bcn_ie = qdf_mem_malloc(sizeof(*bcn_ie)); + if (!bcn_ie) + return; + + buf_len = lim_get_ielen_from_bss_description(bss_desc); + buf = (uint8_t *)bss_desc->ieFields; + status = dot11f_unpack_beacon_i_es(mac, buf, buf_len, bcn_ie, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse Beacon IEs (0x%08x, %d bytes):", + status, buf_len); + qdf_mem_free(bcn_ie); + return; + } else if (DOT11F_WARNED(status)) { + pe_debug("warnings (0x%08x, %d bytes):", status, buf_len); + } + + status = lim_strip_and_decode_eht_op(buf, buf_len, &bcn_ie->eht_op, + bcn_ie->VHTOperation, + bcn_ie->he_op, + bcn_ie->HTInfo); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + return; + } + + status = lim_strip_and_decode_eht_cap(buf, buf_len, &bcn_ie->eht_cap, + bcn_ie->he_cap, + session->curr_op_freq); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + return; + } + + lim_parse_tpe_ie(mac, session, bcn_ie->transmit_power_env, + bcn_ie->num_transmit_power_env, &bcn_ie->he_op, + has_tpe_updated); + qdf_mem_free(bcn_ie); +} + +uint32_t lim_get_num_pwr_levels(bool is_psd, + enum phy_ch_width ch_width) +{ + uint32_t num_pwr_levels = 0; + + if (is_psd) { + switch (ch_width) { + case CH_WIDTH_20MHZ: + num_pwr_levels = 1; + break; + case CH_WIDTH_40MHZ: + num_pwr_levels = 2; + break; + case CH_WIDTH_80MHZ: + num_pwr_levels = 4; + break; + case CH_WIDTH_160MHZ: + num_pwr_levels = 8; + break; + case CH_WIDTH_320MHZ: + num_pwr_levels = 16; + break; + default: + pe_err_rl("Invalid channel width"); + return 0; + } + } else { + switch (ch_width) { + case CH_WIDTH_20MHZ: + num_pwr_levels = 1; + break; + case CH_WIDTH_40MHZ: + num_pwr_levels = 2; + break; + case CH_WIDTH_80MHZ: + num_pwr_levels = 3; + break; + case CH_WIDTH_160MHZ: + num_pwr_levels = 4; + break; + case CH_WIDTH_320MHZ: + num_pwr_levels = 5; + break; + default: + pe_err_rl("Invalid channel width"); + return 0; + } + } + return num_pwr_levels; +} + +uint8_t lim_get_max_tx_power(struct mac_context *mac, + struct vdev_mlme_obj *mlme_obj) +{ + uint8_t max_tx_power = 0; + uint8_t tx_power; + + if (wlan_reg_get_fcc_constraint(mac->pdev, + mlme_obj->reg_tpc_obj.frequency[0])) + return mlme_obj->reg_tpc_obj.reg_max[0]; + + tx_power = QDF_MIN(mlme_obj->reg_tpc_obj.reg_max[0], + mlme_obj->reg_tpc_obj.ap_constraint_power); + + if (tx_power >= MIN_TX_PWR_CAP && tx_power <= MAX_TX_PWR_CAP) + max_tx_power = tx_power; + else if (tx_power < MIN_TX_PWR_CAP) + max_tx_power = MIN_TX_PWR_CAP; + else + max_tx_power = MAX_TX_PWR_CAP; + + return max_tx_power; +} + +void lim_calculate_tpc(struct mac_context *mac, + struct pe_session *session) +{ + bool is_psd_power = false; + bool is_tpe_present = false, is_6ghz_freq = false; + uint8_t i = 0; + int8_t max_tx_power; + uint16_t reg_max = 0, reg_psd_pwr_max = 0; + uint16_t tx_power_within_bw = 0, psd_power_within_bw = 0; + uint16_t local_constraint, bw_val = 0; + uint32_t num_pwr_levels, ap_power_type_6g = 0; + qdf_freq_t oper_freq, start_freq = 0; + struct ch_params ch_params = {0}; + struct vdev_mlme_obj *mlme_obj; + int8_t tpe_power; + bool skip_tpe = false; + bool rf_test_mode = false; + bool safe_mode_enable = false; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return; + } + + if (session->sta_follows_sap_power) { + pe_debug_rl("STA operates in 6 GHz power of SAP, do not update STA power"); + return; + } + + oper_freq = session->curr_op_freq; + bw_val = wlan_reg_get_bw_value(session->ch_width); + + ch_params.ch_width = session->ch_width; + /* start frequency calculation */ + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, oper_freq, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params.mhz_freq_seg1) + start_freq = ch_params.mhz_freq_seg1 - bw_val / 2 + 10; + else + start_freq = ch_params.mhz_freq_seg0 - bw_val / 2 + 10; + + if (!wlan_reg_is_6ghz_chan_freq(oper_freq)) { + reg_max = wlan_reg_get_channel_reg_power_for_freq(mac->pdev, + oper_freq); + skip_tpe = wlan_mlme_skip_tpe(mac->psoc); + } else { + is_6ghz_freq = true; + /* Power mode calculation for 6 GHz STA*/ + if (LIM_IS_STA_ROLE(session)) { + ap_power_type_6g = session->best_6g_power_type; + wlan_mlme_get_safe_mode_enable(mac->psoc, + &safe_mode_enable); + wlan_mlme_is_rf_test_mode_enabled(mac->psoc, + &rf_test_mode); + /* + * set LPI power if safe mode is enabled OR RF test + * mode is enabled. + */ + if (rf_test_mode || safe_mode_enable) + ap_power_type_6g = REG_INDOOR_AP; + } + } + + if (mlme_obj->reg_tpc_obj.num_pwr_levels) { + is_tpe_present = true; + num_pwr_levels = mlme_obj->reg_tpc_obj.num_pwr_levels; + is_psd_power = mlme_obj->reg_tpc_obj.is_psd_power; + } else { + /** + * Set is_psd_power based on reg channel list if it is a 6 GHz + * channel and TPE IE is absent. + */ + if (is_6ghz_freq) + is_psd_power = wlan_reg_is_6g_psd_power(mac->pdev); + num_pwr_levels = lim_get_num_pwr_levels(is_psd_power, + session->ch_width); + } + + if (num_pwr_levels > MAX_NUM_PWR_LEVELS) { + pe_debug("reset num_pwr_levels %d to MAX_NUM_PWR_LEVELS %d", + num_pwr_levels, MAX_NUM_PWR_LEVELS); + num_pwr_levels = MAX_NUM_PWR_LEVELS; + } + + ch_params.ch_width = CH_WIDTH_20MHZ; + + for (i = 0; + i < num_pwr_levels && (ch_params.ch_width != CH_WIDTH_INVALID); + i++) { + if (is_tpe_present) { + if (is_6ghz_freq) { + if (is_psd_power) { + wlan_reg_get_client_power_for_connecting_ap( + mac->pdev, ap_power_type_6g, + mlme_obj->reg_tpc_obj.frequency[i], + is_psd_power, ®_max, + ®_psd_pwr_max); + } else { + wlan_reg_get_client_power_for_connecting_ap( + mac->pdev, ap_power_type_6g, oper_freq, + is_psd_power, ®_max, + ®_psd_pwr_max); + } + } + } else { + /* center frequency calculation */ + if (is_psd_power) { + mlme_obj->reg_tpc_obj.frequency[i] = + start_freq + (20 * i); + } else { + /* Use operating frequency to fetch EIRP pwr */ + mlme_obj->reg_tpc_obj.frequency[i] = oper_freq; + } + if (is_6ghz_freq) { + if (LIM_IS_STA_ROLE(session)) { + wlan_reg_get_client_power_for_connecting_ap + (mac->pdev, ap_power_type_6g, + mlme_obj->reg_tpc_obj.frequency[i], + is_psd_power, ®_max, + ®_psd_pwr_max); + } else { + if (wlan_reg_decide_6ghz_power_within_bw_for_freq( + mac->pdev, oper_freq, + session->ch_width, + &is_psd_power, + &tx_power_within_bw, + &psd_power_within_bw, + &ap_power_type_6g, + REG_BEST_PWR_MODE, + NO_SCHANS_PUNC) == + QDF_STATUS_SUCCESS) { + pe_debug("get pwr attr from secondary list"); + reg_max = tx_power_within_bw; + reg_psd_pwr_max = + psd_power_within_bw; + } else { + wlan_reg_get_cur_6g_ap_pwr_type( + mac->pdev, + &ap_power_type_6g); + wlan_reg_get_6g_chan_ap_power( + mac->pdev, + mlme_obj->reg_tpc_obj. + frequency[i], + &is_psd_power, + ®_max, + ®_psd_pwr_max); + } + } + } + } + /* Check for regulatory channel power. If it is zero due to + * invalid frequency or other inputs, then assign the regulatory + * power of operating frequency to reg_max. + */ + if (reg_max) { + mlme_obj->reg_tpc_obj.reg_max[i] = reg_max; + } else { + pe_debug("Reg power due to invalid freq: %d", + mlme_obj->reg_tpc_obj.frequency[i]); + reg_max = mlme_obj->reg_tpc_obj.reg_max[0]; + mlme_obj->reg_tpc_obj.reg_max[i] = reg_max; + } + + mlme_obj->reg_tpc_obj.chan_power_info[i].chan_cfreq = + mlme_obj->reg_tpc_obj.frequency[i]; + + /* max tx power calculation */ + max_tx_power = mlme_obj->reg_tpc_obj.reg_max[i]; + + local_constraint = mlme_obj->reg_tpc_obj.ap_constraint_power; + pe_debug("local constraint: %d power constraint absolute %d", + local_constraint, + mlme_obj->reg_tpc_obj.is_power_constraint_abs); + + if (is_psd_power) { + max_tx_power = reg_psd_pwr_max; + } else if (mlme_obj->reg_tpc_obj.is_power_constraint_abs) { + if (!local_constraint) { + pe_debug("ignore abs ap constraint power 0!"); + max_tx_power = reg_max; + } else { + max_tx_power = QDF_MIN(reg_max, + local_constraint); + } + } else { + max_tx_power = reg_max - local_constraint; + if (!max_tx_power) + max_tx_power = reg_max; + } + + /* If TPE is present */ + if (is_tpe_present && !skip_tpe) { + if (!is_psd_power && mlme_obj->reg_tpc_obj.eirp_power) + tpe_power = mlme_obj->reg_tpc_obj.eirp_power; + else + tpe_power = mlme_obj->reg_tpc_obj.tpe[i]; + /** + * AP advertises TPE IE tx power as 8-bit unsigned int. + * STA needs to convert it into an 8-bit 2s complement + * signed integer in the range –64 dBm to 63 dBm with a + * 0.5 dB step + */ + tpe_power /= 2; + max_tx_power = QDF_MIN(max_tx_power, tpe_power); + pe_debug("TPE: %d", tpe_power); + } + + mlme_obj->reg_tpc_obj.chan_power_info[i].tx_power = + (uint8_t)max_tx_power; + + pe_debug("freq: %d reg power: %d, max_tx_power(eirp/psd): %d", + mlme_obj->reg_tpc_obj.frequency[i], reg_max, + mlme_obj->reg_tpc_obj.chan_power_info[i].tx_power); + } + + mlme_obj->reg_tpc_obj.num_pwr_levels = num_pwr_levels; + mlme_obj->reg_tpc_obj.eirp_power = reg_max; + mlme_obj->reg_tpc_obj.power_type_6g = ap_power_type_6g; + mlme_obj->reg_tpc_obj.is_psd_power = is_psd_power; + + if (LIM_IS_AP_ROLE(session) && is_psd_power) + wlan_mlme_set_sap_psd_for_20mhz(session->vdev, + (uint8_t)reg_psd_pwr_max); + + pe_debug("num_pwr_levels: %d, is_psd_power: %d, total eirp_power: %d, ap_pwr_type: %d", + num_pwr_levels, is_psd_power, reg_max, ap_power_type_6g); +} + +/** + * lim_mlo_sap_validate_and_update_ra() - Validate peer address for ML SAP + * management frames. + * @session: pe_session + * @peer_addr: address of the peer + * + * Check if address pointed by @peer_addr is MLD of the client, + * if so, replace the address with link address of the client + * to send the management packet over the air. + * + * Return: void + */ +#ifdef WLAN_FEATURE_11BE_MLO +static void lim_mlo_sap_validate_and_update_ra(struct pe_session *session, + struct qdf_mac_addr *peer_addr) +{ + uint8_t i; + struct wlan_mlo_dev_context *ml_ctx; + struct wlan_mlo_peer_list *mlo_peer_list; + struct wlan_mlo_peer_context *ml_peer; + struct wlan_mlo_link_peer_entry *link_peer; + + if (!wlan_vdev_mlme_is_mlo_ap(session->vdev)) + return; + + ml_ctx = session->vdev->mlo_dev_ctx; + mlo_peer_list = &ml_ctx->mlo_peer_list; + + ml_peerlist_lock_acquire(mlo_peer_list); + ml_peer = mlo_get_mlpeer(ml_ctx, peer_addr); + if (!ml_peer) { + ml_peerlist_lock_release(mlo_peer_list); + return; + } + + for (i = 0; i < MAX_MLO_LINK_PEERS; i++) { + link_peer = &ml_peer->peer_list[i]; + if (link_peer->is_primary && + !qdf_is_macaddr_equal(peer_addr, &link_peer->link_addr)) { + qdf_copy_macaddr(peer_addr, &link_peer->link_addr); + break; + } + } + ml_peerlist_lock_release(mlo_peer_list); +} +#else +static inline void +lim_mlo_sap_validate_and_update_ra(struct pe_session *session, + struct qdf_mac_addr *peer_addr) +{ +} +#endif + +bool send_disassoc_frame = 1; +/** + * __lim_process_sme_disassoc_req() + * + ***FUNCTION: + * This function is called to process SME_DISASSOC_REQ message + * from HDD or upper layer application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param *msg_buf A pointer to the SME message buffer + * @return None + */ + +static void __lim_process_sme_disassoc_req(struct mac_context *mac, + uint32_t *msg_buf) +{ + uint16_t disassocTrigger, reasonCode; + tLimMlmDisassocReq *pMlmDisassocReq; + tSirResultCodes retCode = eSIR_SME_SUCCESS; + struct disassoc_req smeDisassocReq; + struct pe_session *pe_session = NULL; + uint8_t sessionId; + uint8_t smesessionId; + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + qdf_mem_copy(&smeDisassocReq, msg_buf, sizeof(struct disassoc_req)); + smesessionId = smeDisassocReq.sessionId; + if (!lim_is_sme_disassoc_req_valid(mac, + &smeDisassocReq, + pe_session)) { + pe_err("received invalid SME_DISASSOC_REQ message"); + if (mac->lim.gLimRspReqd) { + mac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + pe_session = pe_find_session_by_bssid_and_vdev_id(mac, + smeDisassocReq.bssid.bytes, + smeDisassocReq.sessionId, + &sessionId); + if (!pe_session) { + pe_err("session does not exist for bssid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(smeDisassocReq.bssid.bytes)); + retCode = eSIR_SME_INVALID_PARAMETERS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + pe_debug("vdev %d (%d) opmode %d Reason: %u SmeState: %d limMlmState %d ho fail %d send OTA %d to: " QDF_MAC_ADDR_FMT " bssid " QDF_MAC_ADDR_FMT, + pe_session->vdev_id, pe_session->peSessionId, + pe_session->opmode, smeDisassocReq.reasonCode, + pe_session->limSmeState, pe_session->limMlmState, + smeDisassocReq.process_ho_fail, + smeDisassocReq.doNotSendOverTheAir, + QDF_MAC_ADDR_REF(smeDisassocReq.peer_macaddr.bytes), + QDF_MAC_ADDR_REF(smeDisassocReq.bssid.bytes)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_REQ_EVENT, pe_session, + 0, smeDisassocReq.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + pe_session->smeSessionId = smesessionId; + pe_session->process_ho_fail = smeDisassocReq.process_ho_fail; + + switch (GET_LIM_SYSTEM_ROLE(pe_session)) { + case eLIM_STA_ROLE: + switch (pe_session->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + pe_session->limPrevSmeState = + pe_session->limSmeState; + pe_session->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac, pe_session); + MTRACE(mac_trace(mac, TRACE_CODE_SME_STATE, + pe_session->peSessionId, + pe_session->limSmeState)); + break; + + case eLIM_SME_WT_DEAUTH_STATE: + /* PE shall still process the DISASSOC_REQ and proceed with + * link tear down even if it had already sent a DEAUTH_IND to + * to SME. mac->lim.gLimPrevSmeState shall remain the same as + * its been set when PE entered WT_DEAUTH_STATE. + */ + pe_session->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, + pe_session->peSessionId, + pe_session->limSmeState)); + break; + + case eLIM_SME_WT_DISASSOC_STATE: + /* PE Received a Disassoc frame. Normally it gets DISASSOC_CNF but it + * received DISASSOC_REQ. Which means host is also trying to disconnect. + * PE can continue processing DISASSOC_REQ and send the response instead + * of failing the request. SME will anyway ignore DEAUTH_IND that was sent + * for disassoc frame. + * + * It will send a disassoc, which is ok. However, we can use the global flag + * sendDisassoc to not send disassoc frame. + */ + break; + + case eLIM_SME_JOIN_FAILURE_STATE: { + /* Already in Disconnected State, return success */ + if (mac->lim.gLimRspReqd) { + retCode = eSIR_SME_SUCCESS; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + } + break; + default: + /** + * STA is not currently associated. + * Log error and send response to host + */ + pe_err("received unexpected SME_DISASSOC_REQ in state %X", + pe_session->limSmeState); + lim_print_sme_state(mac, LOGE, + pe_session->limSmeState); + + if (mac->lim.gLimRspReqd) { + if (pe_session->limSmeState != + eLIM_SME_WT_ASSOC_STATE) + mac->lim.gLimRspReqd = false; + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } + + return; + } + + break; + + case eLIM_AP_ROLE: + /* Check if MAC address is MLD of the client and + * change it to primary link address to send OTA. + */ + lim_mlo_sap_validate_and_update_ra( + pe_session, &smeDisassocReq.peer_macaddr); + break; + + default: + /* eLIM_UNKNOWN_ROLE */ + pe_err("received unexpected SME_DISASSOC_REQ for role %d", + GET_LIM_SYSTEM_ROLE(pe_session)); + + retCode = eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + disassocTrigger = eLIM_HOST_DISASSOC; + goto sendDisassoc; + } /* end switch (mac->lim.gLimSystemRole) */ + + disassocTrigger = eLIM_HOST_DISASSOC; + reasonCode = smeDisassocReq.reasonCode; + + if (smeDisassocReq.doNotSendOverTheAir) + send_disassoc_frame = 0; + + pMlmDisassocReq = qdf_mem_malloc(sizeof(tLimMlmDisassocReq)); + if (!pMlmDisassocReq) + return; + + qdf_copy_macaddr(&pMlmDisassocReq->peer_macaddr, + &smeDisassocReq.peer_macaddr); + + pMlmDisassocReq->reasonCode = reasonCode; + pMlmDisassocReq->disassocTrigger = disassocTrigger; + + /* Update PE session ID */ + pMlmDisassocReq->sessionId = sessionId; + + lim_post_mlm_message(mac, + LIM_MLM_DISASSOC_REQ, (uint32_t *) pMlmDisassocReq); + return; + +sendDisassoc: + if (pe_session) + lim_send_sme_disassoc_ntf(mac, + smeDisassocReq.peer_macaddr.bytes, + (uint8_t *)mld_addr.bytes, + retCode, + disassocTrigger, + 1, smesessionId, + pe_session); + else + lim_send_sme_disassoc_ntf(mac, + smeDisassocReq.peer_macaddr.bytes, + (uint8_t *)mld_addr.bytes, + retCode, disassocTrigger, 1, + smesessionId, NULL); + +} /*** end __lim_process_sme_disassoc_req() ***/ + +/** ----------------------------------------------------------------- + \brief __lim_process_sme_disassoc_cnf() - Process SME_DISASSOC_CNF + + This function is called to process SME_DISASSOC_CNF message + from HDD or upper layer application. + + \param mac - global mac structure + \param sta - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void __lim_process_sme_disassoc_cnf(struct mac_context *mac, uint32_t *msg_buf) +{ + struct disassoc_cnf smeDisassocCnf; + uint16_t aid; + tpDphHashNode sta; + struct pe_session *pe_session; + uint8_t sessionId; + uint32_t *msg = NULL; + QDF_STATUS status; + + qdf_mem_copy(&smeDisassocCnf, msg_buf, sizeof(smeDisassocCnf)); + + pe_session = pe_find_session_by_bssid_and_vdev_id(mac, + smeDisassocCnf.bssid.bytes, + smeDisassocCnf.vdev_id, + &sessionId); + if (!pe_session) { + pe_err("session does not exist for bssid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(smeDisassocCnf.bssid.bytes)); + status = lim_prepare_disconnect_done_ind(mac, &msg, + smeDisassocCnf.vdev_id, + eSIR_SME_INVALID_SESSION, + NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + if (!lim_is_sme_disassoc_cnf_valid(mac, &smeDisassocCnf, pe_session)) { + pe_err("received invalid SME_DISASSOC_CNF message"); + status = lim_prepare_disconnect_done_ind( + mac, &msg, + pe_session->smeSessionId, + eSIR_SME_INVALID_PARAMETERS, + &smeDisassocCnf.peer_macaddr.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + if (smeDisassocCnf.messageType == eWNI_SME_DISASSOC_CNF) + lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + pe_session, + (uint16_t)smeDisassocCnf.status_code, 0); + else if (smeDisassocCnf.messageType == eWNI_SME_DEAUTH_CNF) + lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + pe_session, + (uint16_t)smeDisassocCnf.status_code, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pe_debug("vdev %d (%d) opmode %d SmeState: %d limMlmState %d from: " QDF_MAC_ADDR_FMT " bssid " QDF_MAC_ADDR_FMT, + pe_session->vdev_id, pe_session->peSessionId, + pe_session->opmode, pe_session->limSmeState, + pe_session->limMlmState, + QDF_MAC_ADDR_REF(smeDisassocCnf.peer_macaddr.bytes), + QDF_MAC_ADDR_REF(smeDisassocCnf.bssid.bytes)); + + switch (GET_LIM_SYSTEM_ROLE(pe_session)) { + case eLIM_STA_ROLE: + if ((pe_session->limSmeState != eLIM_SME_IDLE_STATE) && + (pe_session->limSmeState != eLIM_SME_WT_DISASSOC_STATE) + && (pe_session->limSmeState != + eLIM_SME_WT_DEAUTH_STATE)) { + pe_err("received unexp SME_DISASSOC_CNF in state %X", + pe_session->limSmeState); + lim_print_sme_state(mac, LOGE, + pe_session->limSmeState); + status = lim_prepare_disconnect_done_ind( + mac, &msg, + pe_session->smeSessionId, + eSIR_SME_INVALID_STATE, + &smeDisassocCnf.peer_macaddr.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + break; + + case eLIM_AP_ROLE: + break; + default: /* eLIM_UNKNOWN_ROLE */ + pe_err("received unexpected SME_DISASSOC_CNF role %d", + GET_LIM_SYSTEM_ROLE(pe_session)); + status = lim_prepare_disconnect_done_ind( + mac, &msg, + pe_session->smeSessionId, + eSIR_SME_INVALID_STATE, + &smeDisassocCnf.peer_macaddr.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + if ((pe_session->limSmeState == eLIM_SME_WT_DISASSOC_STATE) || + (pe_session->limSmeState == eLIM_SME_WT_DEAUTH_STATE) || + LIM_IS_AP_ROLE(pe_session)) { + sta = dph_lookup_hash_entry(mac, + smeDisassocCnf.peer_macaddr.bytes, &aid, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("DISASSOC_CNF for a STA with no context, addr= " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(smeDisassocCnf.peer_macaddr.bytes)); + status = lim_prepare_disconnect_done_ind( + mac, &msg, + pe_session->smeSessionId, + eSIR_SME_INVALID_PARAMETERS, + &smeDisassocCnf.peer_macaddr.bytes[0]); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + if ((sta->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_STA_RSP_STATE) || + (sta->mlmStaContext.mlmState == + eLIM_MLM_WT_DEL_BSS_RSP_STATE)) { + pe_err("No need of cleanup for addr:" QDF_MAC_ADDR_FMT "as MLM state is %d", + QDF_MAC_ADDR_REF(smeDisassocCnf.peer_macaddr.bytes), + sta->mlmStaContext.mlmState); + status = lim_prepare_disconnect_done_ind(mac, &msg, + pe_session->smeSessionId, + eSIR_SME_SUCCESS, + NULL); + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac, + QDF_STATUS_SUCCESS, + (uint32_t *)msg); + return; + } + + lim_mlo_notify_peer_disconn(pe_session, sta); + + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(mac, pe_session); + lim_cleanup_rx_path(mac, sta, pe_session, true); + + lim_clean_up_disassoc_deauth_req(mac, + (char *)&smeDisassocCnf.peer_macaddr, 0); + } + + return; +} + +/** + * __lim_process_sme_deauth_req() - process sme deauth req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_DEAUTH_REQ message + * from HDD or upper layer application. + * + * Return: None + */ + +static void __lim_process_sme_deauth_req(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + uint16_t deauth_trigger, reason_code; + tLimMlmDeauthReq *mlm_deauth_req; + struct deauth_req sme_deauth_req; + tSirResultCodes ret_code = eSIR_SME_SUCCESS; + struct pe_session *session_entry; + uint8_t session_id; /* PE sessionId */ + uint8_t vdev_id; + + qdf_mem_copy(&sme_deauth_req, msg_buf, sizeof(sme_deauth_req)); + vdev_id = sme_deauth_req.vdev_id; + + /* + * We need to get a session first but we don't even know + * if the message is correct. + */ + session_entry = pe_find_session_by_bssid_and_vdev_id(mac_ctx, + sme_deauth_req.bssid.bytes, + sme_deauth_req.vdev_id, + &session_id); + if (!session_entry) { + pe_err("session does not exist for bssid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sme_deauth_req.bssid.bytes)); + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + + if (!lim_is_sme_deauth_req_valid(mac_ctx, &sme_deauth_req, + session_entry)) { + pe_err("received invalid SME_DEAUTH_REQ message"); + mac_ctx->lim.gLimRspReqd = false; + + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + pe_debug("vdev %d (%d) opmode %d reasoncode %u limSmestate %d limMlmState %d to " QDF_MAC_ADDR_FMT " bssid " QDF_MAC_ADDR_FMT, + vdev_id, session_entry->peSessionId, + session_entry->opmode, sme_deauth_req.reasonCode, + session_entry->limSmeState, session_entry->limMlmState, + QDF_MAC_ADDR_REF(sme_deauth_req.peer_macaddr.bytes), + QDF_MAC_ADDR_REF(sme_deauth_req.bssid.bytes)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_DEAUTH_REQ_EVENT, + session_entry, 0, sme_deauth_req.reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + session_entry->vdev_id = vdev_id; + + switch (GET_LIM_SYSTEM_ROLE(session_entry)) { + case eLIM_STA_ROLE: + switch (session_entry->limSmeState) { + case eLIM_SME_ASSOCIATED_STATE: + case eLIM_SME_LINK_EST_STATE: + /* Delete all TDLS peers connected before leaving BSS */ + lim_delete_tdls_peers(mac_ctx, session_entry); + fallthrough; + case eLIM_SME_WT_ASSOC_STATE: + case eLIM_SME_JOIN_FAILURE_STATE: + case eLIM_SME_IDLE_STATE: + session_entry->limPrevSmeState = + session_entry->limSmeState; + session_entry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, + session_entry->peSessionId, + session_entry->limSmeState)); + /* Send Deauthentication request to MLM below */ + break; + case eLIM_SME_WT_DEAUTH_STATE: + case eLIM_SME_WT_DISASSOC_STATE: + /* + * PE Received a Deauth/Disassoc frame. Normally it get + * DEAUTH_CNF/DISASSOC_CNF but it received DEAUTH_REQ. + * Which means host is also trying to disconnect. + * PE can continue processing DEAUTH_REQ and send + * the response instead of failing the request. + * SME will anyway ignore DEAUTH_IND/DISASSOC_IND that + * was sent for deauth/disassoc frame. + */ + session_entry->limSmeState = eLIM_SME_WT_DEAUTH_STATE; + break; + default: + /* + * STA is not in a state to deauthenticate with + * peer. Log error and send response to host. + */ + pe_err("received unexp SME_DEAUTH_REQ in state %X", + session_entry->limSmeState); + lim_print_sme_state(mac_ctx, LOGE, + session_entry->limSmeState); + + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + + ret_code = eSIR_SME_STA_NOT_AUTHENTICATED; + deauth_trigger = eLIM_HOST_DEAUTH; + + /* + * here we received deauth request from AP so + * sme state is eLIM_SME_WT_DEAUTH_STATE.if we + * have ISSUED delSta then mlm state should be + * eLIM_MLM_WT_DEL_STA_RSP_STATE and ifwe got + * delBSS rsp then mlm state should be + * eLIM_MLM_IDLE_STATE so the below condition + * captures the state where delSta not done + * and firmware still in connected state. + */ + if (session_entry->limSmeState == + eLIM_SME_WT_DEAUTH_STATE && + session_entry->limMlmState != + eLIM_MLM_IDLE_STATE && + session_entry->limMlmState != + eLIM_MLM_WT_DEL_STA_RSP_STATE) + ret_code = eSIR_SME_DEAUTH_STATUS; + goto send_deauth; + } + return; + } + break; + case eLIM_AP_ROLE: + /* Check if MAC address is MLD of the client and + * change it to primary link address to send OTA. + */ + lim_mlo_sap_validate_and_update_ra( + session_entry, &sme_deauth_req.peer_macaddr); + break; + default: + pe_err("received unexpected SME_DEAUTH_REQ for role %X", + GET_LIM_SYSTEM_ROLE(session_entry)); + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_INVALID_PARAMETERS; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + } /* end switch (mac_ctx->lim.gLimSystemRole) */ + + if (sme_deauth_req.reasonCode == eLIM_LINK_MONITORING_DEAUTH && + session_entry->limSystemRole == eLIM_STA_ROLE) { + /* Deauthentication is triggered by Link Monitoring */ + pe_debug("** Lost link with AP **"); + deauth_trigger = eLIM_LINK_MONITORING_DEAUTH; + reason_code = REASON_UNSPEC_FAILURE; + } else { + deauth_trigger = eLIM_HOST_DEAUTH; + reason_code = sme_deauth_req.reasonCode; + } + + /* Trigger Deauthentication frame to peer MAC entity */ + mlm_deauth_req = qdf_mem_malloc(sizeof(tLimMlmDeauthReq)); + if (!mlm_deauth_req) { + if (mac_ctx->lim.gLimRspReqd) { + mac_ctx->lim.gLimRspReqd = false; + ret_code = eSIR_SME_RESOURCES_UNAVAILABLE; + deauth_trigger = eLIM_HOST_DEAUTH; + goto send_deauth; + } + return; + } + + qdf_copy_macaddr(&mlm_deauth_req->peer_macaddr, + &sme_deauth_req.peer_macaddr); + + mlm_deauth_req->reasonCode = reason_code; + mlm_deauth_req->deauthTrigger = deauth_trigger; + + /* Update PE session Id */ + mlm_deauth_req->sessionId = session_id; + lim_process_mlm_deauth_req(mac_ctx, (uint32_t *)mlm_deauth_req); + + return; + +send_deauth: + lim_send_sme_deauth_ntf(mac_ctx, sme_deauth_req.peer_macaddr.bytes, + ret_code, deauth_trigger, 1, vdev_id); +} + +/** + * __lim_counter_measures() + * + * FUNCTION: + * This function is called to "implement" MIC counter measure + * and is *temporary* only + * + * LOGIC: on AP, disassoc all STA associated thru TKIP, + * we don't do the proper STA disassoc sequence since the + * BSS will be stopped anyway + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @return None + */ + +static void __lim_counter_measures(struct mac_context *mac, struct pe_session *pe_session) +{ + tSirMacAddr mac_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + if (LIM_IS_AP_ROLE(pe_session)) + lim_send_disassoc_mgmt_frame(mac, REASON_MIC_FAILURE, + mac_addr, pe_session, false); +}; + +void lim_send_stop_bss_failure_resp(struct mac_context *mac_ctx, + struct pe_session *session) +{ + session->limSmeState = session->limPrevSmeState; + + MTRACE(mac_trace(mac_ctx, TRACE_CODE_SME_STATE, session->peSessionId, + session->limSmeState)); + lim_send_stop_bss_response(mac_ctx, session->vdev_id, + eSIR_SME_STOP_BSS_FAILURE); +} + +static void lim_flush_all_peer_from_serialization_queue( + struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct wlan_serialization_queued_cmd_info cmd = {0}; + struct wlan_objmgr_vdev *vdev; + + vdev = session->vdev; + if (!vdev) { + pe_err("vdev is null"); + return; + } + + pe_debug("vdev id is %d for disconnect/deauth cmd", session->vdev_id); + + /* Flush any pending NB peer deauth command */ + cmd.vdev = vdev; + cmd.cmd_type = WLAN_SER_CMD_FORCE_DEAUTH_STA; + cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE; + cmd.requestor = WLAN_UMAC_COMP_MLME; + cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; + + wlan_serialization_cancel_request(&cmd); + + /* Flush any pending NB peer disassoc command */ + qdf_mem_zero(&cmd, sizeof(cmd)); + cmd.vdev = vdev; + cmd.cmd_type = WLAN_SER_CMD_FORCE_DISASSOC_STA; + cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE; + cmd.requestor = WLAN_UMAC_COMP_MLME; + cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; + + wlan_serialization_cancel_request(&cmd); + + /* Flush any pending SB peer deauth/disconnect command */ + qdf_mem_zero(&cmd, sizeof(cmd)); + cmd.vdev = vdev; + cmd.cmd_type = WLAN_SER_CMD_WM_STATUS_CHANGE; + cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE; + cmd.requestor = WLAN_UMAC_COMP_MLME; + cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; + + wlan_serialization_cancel_request(&cmd); +} + +void lim_delete_all_peers(struct pe_session *session) +{ + uint8_t i = 0; + struct mac_context *mac_ctx = session->mac_ctx; + tpDphHashNode sta_ds = NULL; + QDF_STATUS status; + tSirMacAddr bc_addr = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + /* IBSS and NDI doesn't send Disassoc frame */ + if (!LIM_IS_NDI_ROLE(session)) { + pe_debug("stop_bss_reason: %d", session->stop_bss_reason); + if (session->stop_bss_reason == eSIR_SME_MIC_COUNTER_MEASURES) + __lim_counter_measures(mac_ctx, session); + else + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_DEAUTH_NETWORK_LEAVING, + bc_addr, session, false); + } + + for (i = 1; i < session->dph.dphHashTable.size; i++) { + sta_ds = dph_get_hash_entry(mac_ctx, i, + &session->dph.dphHashTable); + if (!sta_ds) + continue; + lim_mlo_notify_peer_disconn(session, sta_ds); + status = lim_del_sta(mac_ctx, sta_ds, false, session); + if (QDF_STATUS_SUCCESS == status) { + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, + sta_ds->assocId, session); + if (lim_is_mlo_conn(session, sta_ds)) + lim_release_mlo_conn_idx(mac_ctx, + sta_ds->assocId, + session, false); + else + lim_release_peer_idx(mac_ctx, sta_ds->assocId, + session); + } else { + pe_err("lim_del_sta failed with Status: %d", status); + QDF_ASSERT(0); + } + } + + /** + * Scenario: CSA happens and south bound disconnection got queued + * in serialization parallelly. + * As part of CSA, remove all peer from serialization, so that when + * south bound disconnection becomes active, it should not lead to a + * race where the peer is trying to connect and the driver is trying + * to disconnect the same peer, leading to an active command timeout + */ + lim_flush_all_peer_from_serialization_queue(mac_ctx, session); + + lim_disconnect_complete(session, false); + if (mac_ctx->del_peers_ind_cb) + mac_ctx->del_peers_ind_cb(mac_ctx->psoc, session->vdev_id); +} + +QDF_STATUS lim_sta_send_del_bss(struct pe_session *session) +{ + struct mac_context *mac_ctx = session->mac_ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpDphHashNode sta_ds = NULL; + + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (!sta_ds) { + pe_err("DPH Entry for STA is missing, failed to send delbss"); + goto end; + } + + status = lim_del_bss(mac_ctx, sta_ds, 0, session); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("delBss failed for bss %d", session->vdev_id); + +end: + return status; +} + +QDF_STATUS lim_send_vdev_stop(struct pe_session *session) +{ + struct mac_context *mac_ctx = session->mac_ctx; + QDF_STATUS status; + + status = lim_del_bss(mac_ctx, NULL, session->vdev_id, session); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("delBss failed for bss %d", session->vdev_id); + lim_send_stop_bss_failure_resp(mac_ctx, session); + } + + return status; +} + +/** + * lim_delete_peers_and_send_vdev_stop() -delete peers and send vdev stop + * @session: session pointer + * + * Return None + */ +static void lim_delete_peers_and_send_vdev_stop(struct pe_session *session) +{ + struct mac_context *mac_ctx = session->mac_ctx; + QDF_STATUS status; + + if (QDF_IS_STATUS_SUCCESS( + wlan_vdev_is_restart_progress(session->vdev))) + status = + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_RESTART_REQ_FAIL, + sizeof(*session), session); + else + status = wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_DOWN, + sizeof(*session), + session); + if (QDF_IS_STATUS_ERROR(status)) + lim_send_stop_bss_failure_resp(mac_ctx, session); +} + +static void +__lim_handle_sme_stop_bss_request(struct mac_context *mac, uint32_t *msg_buf) +{ + struct stop_bss_req stop_bss_req; + tLimSmeStates prevState; + struct pe_session *pe_session; + struct qdf_mac_addr bssid; + uint8_t vdev_id; + uint8_t session_id; + + qdf_mem_copy(&stop_bss_req, msg_buf, sizeof(stop_bss_req)); + vdev_id = stop_bss_req.vdev_id; + wlan_mlme_get_mac_vdev_id(mac->pdev, vdev_id, &bssid); + + pe_session = pe_find_session_by_bssid(mac, bssid.bytes, + &session_id); + if (!pe_session) { + pe_err("session does not exist for bssid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + lim_send_stop_bss_response(mac, vdev_id, + eSIR_SME_INVALID_PARAMETERS); + return; + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, pe_session, + 0, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (pe_session->limSmeState != eLIM_SME_NORMAL_STATE || /* Added For BT -AMP Support */ + LIM_IS_STA_ROLE(pe_session)) { + /** + * Should not have received STOP_BSS_REQ in states + * other than 'normal' state or on STA in Infrastructure + * mode. Log error and return response to host. + */ + pe_err("received unexpected SME_STOP_BSS_REQ in state %X, for role %d", + pe_session->limSmeState, + GET_LIM_SYSTEM_ROLE(pe_session)); + lim_print_sme_state(mac, LOGE, pe_session->limSmeState); + /* / Send Stop BSS response to host */ + lim_send_stop_bss_response(mac, vdev_id, + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE); + return; + } + + if (LIM_IS_AP_ROLE(pe_session)) + lim_wpspbc_close(mac, pe_session); + + prevState = pe_session->limSmeState; + pe_session->limPrevSmeState = prevState; + + pe_session->limSmeState = eLIM_SME_IDLE_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_SME_STATE, pe_session->peSessionId, + pe_session->limSmeState)); + + pe_session->smeSessionId = vdev_id; + pe_session->stop_bss_reason = 0; + + if (!LIM_IS_NDI_ROLE(pe_session)) { + /* Free the buffer allocated in START_BSS_REQ */ + qdf_mem_free(pe_session->add_ie_params.probeRespData_buff); + pe_session->add_ie_params.probeRespDataLen = 0; + pe_session->add_ie_params.probeRespData_buff = NULL; + + qdf_mem_free(pe_session->add_ie_params.assocRespData_buff); + pe_session->add_ie_params.assocRespDataLen = 0; + pe_session->add_ie_params.assocRespData_buff = NULL; + + qdf_mem_free(pe_session->add_ie_params.probeRespBCNData_buff); + pe_session->add_ie_params.probeRespBCNDataLen = 0; + pe_session->add_ie_params.probeRespBCNData_buff = NULL; + } + + lim_delete_peers_and_send_vdev_stop(pe_session); + +} + +/** + * __lim_process_sme_stop_bss_req() - Process STOP_BSS from SME + * @mac: Global MAC context + * @pMsg: Message from SME + * + * Wrapper for the function __lim_handle_sme_stop_bss_request + * This message will be deferred until softmac come out of + * scan mode. Message should be handled even if we have + * detected radar in the current operating channel. + * + * Return: true - If we consumed the buffer + * false - If have deferred the message. + */ + +static bool __lim_process_sme_stop_bss_req(struct mac_context *mac, + struct scheduler_msg *pMsg) +{ + __lim_handle_sme_stop_bss_request(mac, (uint32_t *) pMsg->bodyptr); + return true; +} /*** end __lim_process_sme_stop_bss_req() ***/ + +void lim_process_sme_del_bss_rsp(struct mac_context *mac, + struct pe_session *pe_session) +{ + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + dph_hash_table_init(mac, &pe_session->dph.dphHashTable); + lim_delete_pre_auth_list(mac); + lim_send_stop_bss_response(mac, pe_session->vdev_id, + eSIR_SME_SUCCESS); + return; +} + +/** + * __lim_process_sme_assoc_cnf_new() - process sme assoc/reassoc cnf + * + * @mac_ctx: pointer to mac context + * @msg_type: message type + * @msg_buf: pointer to the SME message buffer + * + * This function handles SME_ASSOC_CNF/SME_REASSOC_CNF + * in BTAMP AP. + * + * Return: None + */ + +void __lim_process_sme_assoc_cnf_new(struct mac_context *mac_ctx, uint32_t msg_type, + uint32_t *msg_buf) +{ + struct assoc_cnf assoc_cnf; + tpDphHashNode sta_ds = NULL; + struct pe_session *session_entry = NULL; + uint8_t session_id; + tpSirAssocReq assoc_req; + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + if (!msg_buf) { + pe_err("msg_buf is NULL"); + return; + } + + qdf_mem_copy(&assoc_cnf, msg_buf, sizeof(assoc_cnf)); + if (!__lim_is_sme_assoc_cnf_valid(&assoc_cnf)) { + pe_err("Received invalid SME_RE(ASSOC)_CNF message"); + goto end; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, assoc_cnf.bssid.bytes, + &session_id); + if (!session_entry) { + pe_err("session does not exist for given bssId"); + goto end; + } + + if ((!LIM_IS_AP_ROLE(session_entry)) || + (session_entry->limSmeState != eLIM_SME_NORMAL_STATE)) { + pe_err("Rcvd unexpected msg %X in state %X, in role %X", + msg_type, session_entry->limSmeState, + GET_LIM_SYSTEM_ROLE(session_entry)); + goto end; + } + sta_ds = dph_get_hash_entry(mac_ctx, assoc_cnf.aid, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + pe_err("Rcvd invalid msg %X due to no STA ctx, aid %d, peer "QDF_MAC_ADDR_FMT, + msg_type, assoc_cnf.aid, + QDF_MAC_ADDR_REF(assoc_cnf.peer_macaddr.bytes)); + + /* + * send a DISASSOC_IND message to WSM to make sure + * the state in WSM and LIM is the same + */ + lim_send_sme_disassoc_ntf( + mac_ctx, + assoc_cnf.peer_macaddr.bytes, + (uint8_t *)mld_addr.bytes, + eSIR_SME_STA_NOT_ASSOCIATED, + eLIM_PEER_ENTITY_DISASSOC, assoc_cnf.aid, + session_entry->smeSessionId, + session_entry); + goto end; + } + if (qdf_mem_cmp((uint8_t *)sta_ds->staAddr, + (uint8_t *) assoc_cnf.peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE)) { + pe_debug("peerMacAddr mismatched for aid %d, peer "QDF_MAC_ADDR_FMT, + assoc_cnf.aid, + QDF_MAC_ADDR_REF(assoc_cnf.peer_macaddr.bytes)); + goto end; + } + + if ((sta_ds->mlmStaContext.mlmState != eLIM_MLM_WT_ASSOC_CNF_STATE) || + ((sta_ds->mlmStaContext.subType == LIM_ASSOC) && + (msg_type != eWNI_SME_ASSOC_CNF)) || + ((sta_ds->mlmStaContext.subType == LIM_REASSOC) && + (msg_type != eWNI_SME_ASSOC_CNF))) { + pe_debug("peer " QDF_MAC_ADDR_FMT " not in WT_ASSOC_CNF_STATE, for aid %d, sta mlmstate %d", + QDF_MAC_ADDR_REF(assoc_cnf.peer_macaddr.bytes), + assoc_cnf.aid, sta_ds->mlmStaContext.mlmState); + goto end; + } + /* + * Deactivate/delete CNF_WAIT timer since ASSOC_CNF + * has been received + */ + pe_debug("Received SME_ASSOC_CNF. Delete Timer"); + lim_deactivate_and_change_per_sta_id_timer(mac_ctx, + eLIM_CNF_WAIT_TIMER, sta_ds->assocId); + + if (assoc_cnf.status_code == eSIR_SME_SUCCESS) { + /* + * In BTAMP-AP, PE already finished the WMA_ADD_STA sequence + * when it had received Assoc Request frame. Now, PE just needs + * to send association rsp frame to the requesting BTAMP-STA. + */ + sta_ds->mlmStaContext.mlmState = + eLIM_MLM_LINK_ESTABLISHED_STATE; + sta_ds->mlmStaContext.owe_ie = assoc_cnf.owe_ie; + sta_ds->mlmStaContext.owe_ie_len = assoc_cnf.owe_ie_len; + sta_ds->mlmStaContext.ft_ie = assoc_cnf.ft_ie; + sta_ds->mlmStaContext.ft_ie_len = assoc_cnf.ft_ie_len; + pe_debug("sending Assoc Rsp frame to STA assoc id=%d, tx cb %d", + sta_ds->assocId, assoc_cnf.need_assoc_rsp_tx_cb); + lim_send_assoc_rsp_mgmt_frame( + mac_ctx, QDF_STATUS_SUCCESS, + sta_ds->assocId, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, sta_ds, + session_entry, + assoc_cnf.need_assoc_rsp_tx_cb); + sta_ds->mlmStaContext.owe_ie = NULL; + sta_ds->mlmStaContext.owe_ie_len = 0; + sta_ds->mlmStaContext.ft_ie = NULL; + sta_ds->mlmStaContext.ft_ie_len = 0; + goto end; + } else { + uint8_t add_pre_auth_context = true; + /* + * SME_ASSOC_CNF status is non-success, so STA is not allowed + * to be associated since the HAL sta entry is created for + * denied STA we need to remove this HAL entry. + * So to do that set updateContext to 1 + */ + enum wlan_status_code mac_status_code = + STATUS_UNSPECIFIED_FAILURE; + + if (!sta_ds->mlmStaContext.updateContext) + sta_ds->mlmStaContext.updateContext = 1; + pe_debug("Recv Assoc Cnf, status Code : %d(assoc id=%d) Reason code: %d", + assoc_cnf.status_code, sta_ds->assocId, + assoc_cnf.mac_status_code); + if (assoc_cnf.mac_status_code) + mac_status_code = assoc_cnf.mac_status_code; + if (assoc_cnf.mac_status_code == STATUS_INVALID_PMKID || + assoc_cnf.mac_status_code == + STATUS_NOT_SUPPORTED_AUTH_ALG) + add_pre_auth_context = false; + + lim_reject_association(mac_ctx, sta_ds->staAddr, + sta_ds->mlmStaContext.subType, + add_pre_auth_context, + sta_ds->mlmStaContext.authType, + sta_ds->assocId, true, + mac_status_code, + session_entry); + } +end: + if (((session_entry) && (sta_ds)) && + (session_entry->parsedAssocReq[sta_ds->assocId]) && + !assoc_cnf.need_assoc_rsp_tx_cb) { + assoc_req = (tpSirAssocReq) + session_entry->parsedAssocReq[sta_ds->assocId]; + lim_free_assoc_req_frm_buf(assoc_req); + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + } + qdf_mem_free(assoc_cnf.owe_ie); + qdf_mem_free(assoc_cnf.ft_ie); +} + +static void +__lim_process_sme_addts_req(struct mac_context *mac, uint32_t *msg_buf) +{ + tpDphHashNode sta; + tSirMacAddr peerMac; + tpSirAddtsReq pSirAddts; + uint32_t timeout; + struct pe_session *pe_session; + uint8_t sessionId; /* PE sessionId */ + uint8_t smesessionId; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pSirAddts = (tpSirAddtsReq) msg_buf; + smesessionId = pSirAddts->sessionId; + pe_session = pe_find_session_by_bssid(mac, pSirAddts->bssid.bytes, + &sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given bssId"); + lim_send_sme_addts_rsp(mac, pSirAddts->rspReqd, + QDF_STATUS_E_FAILURE, + NULL, pSirAddts->req.tspec, + smesessionId); + return; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_ADDTS_REQ_EVENT, pe_session, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + /* if sta + * - verify assoc state + * - send addts request to ap + * - wait for addts response from ap + * if ap, just ignore with error log + */ + pe_debug("Received SME_ADDTS_REQ (TSid %d, UP %d)", + pSirAddts->req.tspec.tsinfo.traffic.tsid, + pSirAddts->req.tspec.tsinfo.traffic.userPrio); + + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("AddTs received on AP - ignoring"); + goto send_failure_addts_rsp; + } + + sta = + dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + + if (!sta) { + pe_err("Cannot find AP context for addts req"); + goto send_failure_addts_rsp; + } + + if ((!sta->valid) || (sta->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + pe_err("AddTs received in invalid MLM state"); + goto send_failure_addts_rsp; + } + + pSirAddts->req.wsmTspecPresent = 0; + pSirAddts->req.wmeTspecPresent = 0; + pSirAddts->req.lleTspecPresent = 0; + + if ((sta->wsmEnabled) && + (pSirAddts->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + pSirAddts->req.wsmTspecPresent = 1; + else if (sta->wmeEnabled) + pSirAddts->req.wmeTspecPresent = 1; + else if (sta->lleEnabled) + pSirAddts->req.lleTspecPresent = 1; + else { + pe_warn("ADDTS_REQ ignore - qos is disabled"); + goto send_failure_addts_rsp; + } + + if ((pe_session->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (pe_session->limSmeState != eLIM_SME_LINK_EST_STATE)) { + pe_err("AddTs received in invalid LIMsme state (%d)", + pe_session->limSmeState); + goto send_failure_addts_rsp; + } + + if (mac->lim.gLimAddtsSent) { + pe_err("Addts (token %d, tsid %d, up %d) is still pending", + mac->lim.gLimAddtsReq.req.dialogToken, + mac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic.tsid, + mac->lim.gLimAddtsReq.req.tspec.tsinfo.traffic. + userPrio); + goto send_failure_addts_rsp; + } + + sir_copy_mac_addr(peerMac, pe_session->bssId); + + /* save the addts request */ + mac->lim.gLimAddtsSent = true; + qdf_mem_copy((uint8_t *) &mac->lim.gLimAddtsReq, + (uint8_t *) pSirAddts, sizeof(tSirAddtsReq)); + + /* ship out the message now */ + lim_send_addts_req_action_frame(mac, peerMac, &pSirAddts->req, + pe_session); + pe_debug("Sent ADDTS request"); + /* start a timer to wait for the response */ + if (pSirAddts->timeout) + timeout = pSirAddts->timeout; + else + timeout = mac->mlme_cfg->timeouts.addts_rsp_timeout; + + timeout = SYS_MS_TO_TICKS(timeout); + if (tx_timer_change(&mac->lim.lim_timers.gLimAddtsRspTimer, timeout, 0) + != TX_SUCCESS) { + pe_err("AddtsRsp timer change failed!"); + goto send_failure_addts_rsp; + } + mac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_change_context(&mac->lim.lim_timers.gLimAddtsRspTimer, + mac->lim.gLimAddtsRspTimerCount) != + TX_SUCCESS) { + pe_err("AddtsRsp timer change failed!"); + goto send_failure_addts_rsp; + } + MTRACE(mac_trace + (mac, TRACE_CODE_TIMER_ACTIVATE, pe_session->peSessionId, + eLIM_ADDTS_RSP_TIMER)); + + /* add the sessionId to the timer object */ + mac->lim.lim_timers.gLimAddtsRspTimer.sessionId = sessionId; + if (tx_timer_activate(&mac->lim.lim_timers.gLimAddtsRspTimer) != + TX_SUCCESS) { + pe_err("AddtsRsp timer activation failed!"); + goto send_failure_addts_rsp; + } + return; + +send_failure_addts_rsp: + lim_send_sme_addts_rsp(mac, pSirAddts->rspReqd, QDF_STATUS_E_FAILURE, + pe_session, pSirAddts->req.tspec, + smesessionId); +} + +#ifdef WLAN_FEATURE_MSCS +static void +__lim_process_sme_mscs_req(struct mac_context *mac, uint32_t *msg_buf) +{ + struct qdf_mac_addr peer_mac; + struct mscs_req_info *mscs_req; + struct pe_session *pe_session; + uint8_t pe_session_id; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + mscs_req = (struct mscs_req_info *) msg_buf; + pe_session = pe_find_session_by_bssid(mac, mscs_req->bssid.bytes, + &pe_session_id); + if (!pe_session) { + pe_err("Session Does not exist for bssid: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mscs_req->bssid.bytes)); + return; + } + + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("MSCS req received on AP - ignoring"); + return; + } + + if (QDF_IS_STATUS_ERROR(wlan_vdev_mlme_is_active(pe_session->vdev))) { + pe_err("mscs req in unexpected vdev SM state:%d", + wlan_vdev_mlme_get_state(pe_session->vdev)); + return; + } + + if (mscs_req->is_mscs_req_sent) { + pe_err("MSCS req already sent"); + return; + } + + qdf_mem_copy(peer_mac.bytes, pe_session->bssId, QDF_MAC_ADDR_SIZE); + + /* save the mscs request */ + mscs_req->is_mscs_req_sent = true; + + /* ship out the message now */ + lim_send_mscs_req_action_frame(mac, peer_mac, mscs_req, + pe_session); +} +#else +static inline void +__lim_process_sme_mscs_req(struct mac_context *mac, uint32_t *msg_buf) +{ + return; +} + +#endif + +static void +__lim_process_sme_delts_req(struct mac_context *mac, uint32_t *msg_buf) +{ + tSirMacAddr peerMacAddr; + uint8_t ac; + struct mac_ts_info *pTsinfo; + tpSirDeltsReq pDeltsReq = (tpSirDeltsReq) msg_buf; + tpDphHashNode sta = NULL; + struct pe_session *pe_session; + uint8_t sessionId; + uint32_t status = QDF_STATUS_SUCCESS; + uint8_t smesessionId; + + smesessionId = pDeltsReq->sessionId; + + pe_session = pe_find_session_by_bssid(mac, + pDeltsReq->bssid.bytes, + &sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given bssId"); + status = QDF_STATUS_E_FAILURE; + goto end; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DELTS_REQ_EVENT, pe_session, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (QDF_STATUS_SUCCESS != + lim_validate_delts_req(mac, pDeltsReq, peerMacAddr, pe_session)) { + pe_err("lim_validate_delts_req failed"); + status = QDF_STATUS_E_FAILURE; + lim_send_sme_delts_rsp(mac, pDeltsReq, QDF_STATUS_E_FAILURE, + pe_session, smesessionId); + return; + } + + pe_debug("Sent DELTS request to station with assocId = %d MacAddr = " + QDF_MAC_ADDR_FMT, + pDeltsReq->aid, QDF_MAC_ADDR_REF(peerMacAddr)); + + lim_send_delts_req_action_frame(mac, peerMacAddr, + pDeltsReq->req.wmeTspecPresent, + &pDeltsReq->req.tsinfo, + &pDeltsReq->req.tspec, pe_session); + + pTsinfo = + pDeltsReq->req.wmeTspecPresent ? &pDeltsReq->req.tspec. + tsinfo : &pDeltsReq->req.tsinfo; + + /* We've successfully send DELTS frame to AP. Update the + * dynamic UAPSD mask. The AC for this TSPEC to be deleted + * is no longer trigger enabled or delivery enabled + */ + lim_set_tspec_uapsd_mask_per_session(mac, pe_session, + pTsinfo, CLEAR_UAPSD_MASK); + + /* We're deleting the TSPEC, so this particular AC is no longer + * admitted. PE needs to downgrade the EDCA + * parameters(for the AC for which TS is being deleted) to the + * next best AC for which ACM is not enabled, and send the + * updated values to HAL. + */ + ac = upToAc(pTsinfo->traffic.userPrio); + + if (pTsinfo->traffic.direction == SIR_MAC_DIRECTION_UPLINK) { + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_DNLINK) { + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } else if (pTsinfo->traffic.direction == + SIR_MAC_DIRECTION_BIDIR) { + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] &= + ~(1 << ac); + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK] &= + ~(1 << ac); + } + + lim_set_active_edca_params(mac, pe_session->gLimEdcaParams, + pe_session); + + sta = + dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (sta) { + lim_send_edca_params(mac, pe_session->gLimEdcaParamsActive, + pe_session->vdev_id, false); + status = QDF_STATUS_SUCCESS; + } else { + pe_err("Self entry missing in Hash Table"); + status = QDF_STATUS_E_FAILURE; + } +#ifdef FEATURE_WLAN_ESE + lim_send_sme_tsm_ie_ind(mac, pe_session, 0, 0, 0); +#endif + + /* send an sme response back */ +end: + lim_send_sme_delts_rsp(mac, pDeltsReq, QDF_STATUS_SUCCESS, pe_session, + smesessionId); +} + +void lim_process_sme_addts_rsp_timeout(struct mac_context *mac, uint32_t param) +{ + /* fetch the pe_session based on the sessionId */ + struct pe_session *pe_session; + + pe_session = pe_find_session_by_session_id(mac, + mac->lim.lim_timers.gLimAddtsRspTimer. + sessionId); + if (!pe_session) { + pe_err("Session Does not exist for given sessionID"); + return; + } + + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_warn("AddtsRspTimeout in non-Sta role (%d)", + GET_LIM_SYSTEM_ROLE(pe_session)); + mac->lim.gLimAddtsSent = false; + return; + } + + if (!mac->lim.gLimAddtsSent) { + pe_warn("AddtsRspTimeout but no AddtsSent"); + return; + } + + if (param != mac->lim.gLimAddtsRspTimerCount) { + pe_err("Invalid AddtsRsp Timer count %d (exp %d)", param, + mac->lim.gLimAddtsRspTimerCount); + return; + } + /* this a real response timeout */ + mac->lim.gLimAddtsSent = false; + mac->lim.gLimAddtsRspTimerCount++; + + lim_send_sme_addts_rsp(mac, true, eSIR_SME_ADDTS_RSP_TIMEOUT, + pe_session, mac->lim.gLimAddtsReq.req.tspec, + pe_session->smeSessionId); +} + +#ifdef FEATURE_WLAN_ESE +/** + * __lim_process_sme_get_tsm_stats_request() - get tsm stats request + * + * @mac: Pointer to Global MAC structure + * @msg_buf: A pointer to the SME message buffer + * + * Return: None + */ +static void __lim_process_sme_get_tsm_stats_request(struct mac_context *mac, + uint32_t *msg_buf) +{ + struct scheduler_msg msgQ = {0}; + + msgQ.type = WMA_TSM_STATS_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = msg_buf; + msgQ.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + + if (QDF_STATUS_SUCCESS != (wma_post_ctrl_msg(mac, &msgQ))) { + qdf_mem_free(msg_buf); + msg_buf = NULL; + pe_err("Unable to forward request"); + return; + } +} +#endif /* FEATURE_WLAN_ESE */ + +static void lim_process_sme_set_addba_accept(struct mac_context *mac_ctx, + struct sme_addba_accept *msg) +{ + if (!msg) { + pe_err("Msg Buffer is NULL"); + return; + } + if (!msg->addba_accept) + mac_ctx->reject_addba_req = 1; + else + mac_ctx->reject_addba_req = 0; +} + +static void lim_process_sme_update_edca_params(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ + struct pe_session *pe_session; + tpDphHashNode sta_ds_ptr; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!pe_session) { + pe_err("Session does not exist: vdev_id %d", vdev_id); + return; + } + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BE].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BE]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BK].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BK]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VI].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VI]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VO].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VO]; + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (sta_ds_ptr) + lim_send_edca_params(mac_ctx, + pe_session->gLimEdcaParamsActive, + pe_session->vdev_id, false); + else + pe_err("Self entry missing in Hash Table"); +} + +/** + * lim_process_sme_update_session_edca_txq_params() + * Update the edca tx queue parameters for the vdev + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to SME message buffer + * + * Return: None + */ +static void +lim_process_sme_update_session_edca_txq_params(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_update_session_txq_edca_param *msg; + struct pe_session *pe_session; + uint8_t ac; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + msg = (struct sir_update_session_txq_edca_param *)msg_buf; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, msg->vdev_id); + if (!pe_session) { + pe_warn("Session does not exist for given vdev_id %d", + msg->vdev_id); + return; + } + + ac = msg->txq_edca_params.aci.aci; + pe_debug("received SME Session tx queue update for vdev %d queue %d", + msg->vdev_id, ac); + + if ((!LIM_IS_AP_ROLE(pe_session)) || + (pe_session->limSmeState != eLIM_SME_NORMAL_STATE)) { + pe_err("Rcvd edca update req in state %X, in role %X", + pe_session->limSmeState, + GET_LIM_SYSTEM_ROLE(pe_session)); + return; + } + + pe_session->gLimEdcaParams[ac].cw.min = + msg->txq_edca_params.cw.min; + pe_session->gLimEdcaParams[ac].cw.max = + msg->txq_edca_params.cw.max; + pe_session->gLimEdcaParams[ac].aci.aci = + msg->txq_edca_params.aci.aci; + pe_session->gLimEdcaParams[ac].aci.aifsn = + msg->txq_edca_params.aci.aifsn; + pe_session->gLimEdcaParams[ac].txoplimit = + msg->txq_edca_params.txoplimit; + + lim_send_edca_params(mac_ctx, + pe_session->gLimEdcaParams, + pe_session->vdev_id, false); +} + +static void lim_process_sme_update_mu_edca_params(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ + struct pe_session *pe_session; + tpDphHashNode sta_ds_ptr; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!pe_session) { + pe_err("Session does not exist: vdev_id %d", vdev_id); + return; + } + sta_ds_ptr = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (sta_ds_ptr) + lim_send_edca_params(mac_ctx, mac_ctx->usr_mu_edca_params, + pe_session->vdev_id, true); + else + pe_err("Self entry missing in Hash Table"); +} + +static void +lim_process_sme_cfg_action_frm_in_tb_ppdu(struct mac_context *mac_ctx, + struct sir_cfg_action_frm_tb_ppdu + *msg) +{ + if (!msg) { + pe_err("Buffer is NULL"); + return; + } + + lim_send_action_frm_tb_ppdu_cfg(mac_ctx, msg->vdev_id, msg->cfg); +} + +static void +lim_process_sme_send_vdev_pause(struct mac_context *mac_ctx, + struct sme_vdev_pause *msg) +{ + struct pe_session *session; + uint16_t vdev_pause_dur_ms; + + if (!msg) { + pe_err("Buffer is NULL"); + return; + } + + session = pe_find_session_by_vdev_id(mac_ctx, msg->session_id); + if (!session) { + pe_warn("Session does not exist for given BSSID"); + return; + } + + if (!(wlan_vdev_mlme_get_opmode(session->vdev) == QDF_STA_MODE) && + wlan_vdev_mlme_is_mlo_vdev(session->vdev)) { + pe_err("vdev is not ML STA"); + return; + } + + vdev_pause_dur_ms = session->beaconParams.beaconInterval * + msg->vdev_pause_duration; + wlan_mlo_send_vdev_pause(mac_ctx->psoc, session->vdev, + msg->session_id, vdev_pause_dur_ms); +} + +static void lim_process_sme_update_config(struct mac_context *mac_ctx, + struct update_config *msg) +{ + struct pe_session *pe_session; + + pe_debug("received eWNI_SME_UPDATE_HT_CONFIG message"); + if (!msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pe_session = pe_find_session_by_vdev_id(mac_ctx, msg->vdev_id); + if (!pe_session) { + pe_warn("Session does not exist for given BSSID"); + return; + } + + switch (msg->capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + pe_session->ht_config.adv_coding_cap = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + pe_session->ht_config.tx_stbc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + pe_session->ht_config.rx_stbc = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + pe_session->ht_config.short_gi_20_mhz = msg->value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + pe_session->ht_config.short_gi_40_mhz = msg->value; + break; + } + + if (LIM_IS_AP_ROLE(pe_session)) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session); + lim_send_beacon_ind(mac_ctx, pe_session, REASON_CONFIG_UPDATE); + } +} + +void +lim_send_vdev_restart(struct mac_context *mac, + struct pe_session *pe_session, uint8_t sessionId) +{ + struct vdev_mlme_obj *mlme_obj; + + if (!pe_session) { + pe_err("Invalid parameters"); + return; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return; + } + + mlme_obj->mgmt.ap.hidden_ssid = pe_session->ssidHidden ? true : false; + + vdev_mgr_start_send(mlme_obj, true); +} + +static void lim_handle_update_ssid_hidden(struct mac_context *mac_ctx, + struct pe_session *session, uint8_t ssid_hidden) +{ + pe_debug("rcvd HIDE_SSID message old HIDE_SSID: %d new HIDE_SSID: %d", + session->ssidHidden, ssid_hidden); + + if (ssid_hidden != session->ssidHidden) { + session->ssidHidden = ssid_hidden; + } else { + pe_debug("Dont process HIDE_SSID msg with existing setting"); + return; + } + + ap_mlme_set_hidden_ssid_restart_in_progress(session->vdev, true); + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_FW_VDEV_RESTART, + sizeof(*session), session); +} + +/** + * __lim_process_sme_session_update - process SME session update msg + * + * @mac_ctx: Pointer to global mac context + * @msg_buf: Pointer to the received message buffer + * + * Return: None + */ +static void __lim_process_sme_session_update(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_update_session_param *msg; + struct pe_session *session; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + msg = (struct sir_update_session_param *) msg_buf; + + session = pe_find_session_by_vdev_id(mac_ctx, msg->vdev_id); + if (!session) { + pe_warn("Session does not exist for given vdev_id %d", + msg->vdev_id); + return; + } + + pe_debug("received SME Session update for %d val %d", + msg->param_type, msg->param_val); + switch (msg->param_type) { + case SIR_PARAM_SSID_HIDDEN: + lim_handle_update_ssid_hidden(mac_ctx, session, msg->param_val); + break; + default: + pe_err("Unknown session param"); + break; + } +} + +/* + Update the beacon Interval dynamically if beaconInterval is different in MCC + */ +static void __lim_process_sme_change_bi(struct mac_context *mac, + uint32_t *msg_buf) +{ + struct wlan_change_bi *pChangeBIParams; + struct pe_session *pe_session; + uint8_t sessionId = 0; + tUpdateBeaconParams beaconParams; + + pe_debug("received Update Beacon Interval message"); + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + pChangeBIParams = (struct wlan_change_bi *)msg_buf; + + pe_session = pe_find_session_by_bssid(mac, + pChangeBIParams->bssid.bytes, + &sessionId); + if (!pe_session) { + pe_err("Session does not exist for given BSSID"); + return; + } + + /*Update pe_session Beacon Interval */ + if (pe_session->beaconParams.beaconInterval != + pChangeBIParams->beacon_interval) { + pe_session->beaconParams.beaconInterval = + pChangeBIParams->beacon_interval; + } + + /*Update sch beaconInterval */ + if (mac->sch.beacon_interval != + pChangeBIParams->beacon_interval) { + mac->sch.beacon_interval = + pChangeBIParams->beacon_interval; + + pe_debug("LIM send update BeaconInterval Indication: %d", + pChangeBIParams->beacon_interval); + + if (false == mac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + /* Update beacon */ + sch_set_fixed_beacon_fields(mac, pe_session); + + beaconParams.bss_idx = pe_session->vdev_id; + /* Set change in beacon Interval */ + beaconParams.beaconInterval = + pChangeBIParams->beacon_interval; + beaconParams.paramChangeBitmap = + PARAM_BCN_INTERVAL_CHANGED; + lim_send_beacon_params(mac, &beaconParams, pe_session); + } + } + + return; +} /*** end __lim_process_sme_change_bi() ***/ + +#ifdef QCA_HT_2040_COEX +static void __lim_process_sme_set_ht2040_mode(struct mac_context *mac, + uint32_t *msg_buf) +{ + struct set_ht2040_mode *pSetHT2040Mode; + struct pe_session *pe_session; + uint8_t sessionId = 0; + struct scheduler_msg msg = {0}; + tUpdateVHTOpMode *pHtOpMode = NULL; + uint16_t staId = 0; + tpDphHashNode sta = NULL; + + pe_debug("received Set HT 20/40 mode message"); + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pSetHT2040Mode = (struct set_ht2040_mode *)msg_buf; + + pe_session = pe_find_session_by_bssid(mac, + pSetHT2040Mode->bssid.bytes, + &sessionId); + if (!pe_session) { + pe_debug("Session does not exist for given BSSID: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pSetHT2040Mode->bssid.bytes)); + return; + } + + pe_debug("Update session entry for cbMod=%d", + pSetHT2040Mode->cbMode); + /*Update pe_session HT related fields */ + switch (pSetHT2040Mode->cbMode) { + case PHY_SINGLE_CHANNEL_CENTERED: + pe_session->htSecondaryChannelOffset = + PHY_SINGLE_CHANNEL_CENTERED; + pe_session->htRecommendedTxWidthSet = 0; + if (pSetHT2040Mode->obssEnabled) + pe_session->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_40MHZ; + else + pe_session->htSupportedChannelWidthSet + = eHT_CHANNEL_WIDTH_20MHZ; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + pe_session->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + pe_session->htRecommendedTxWidthSet = 1; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + pe_session->htSecondaryChannelOffset = + PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + pe_session->htRecommendedTxWidthSet = 1; + break; + default: + pe_err("Invalid cbMode"); + return; + } + + /* Update beacon */ + sch_set_fixed_beacon_fields(mac, pe_session); + lim_send_beacon_ind(mac, pe_session, REASON_SET_HT2040); + + /* update OP Mode for each associated peer */ + for (staId = 0; staId < pe_session->dph.dphHashTable.size; staId++) { + sta = dph_get_hash_entry(mac, staId, + &pe_session->dph.dphHashTable); + if (!sta) + continue; + + if (sta->valid && sta->htSupportedChannelWidthSet) { + pHtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (!pHtOpMode) + return; + pHtOpMode->opMode = + (pe_session->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) ? + eHT_CHANNEL_WIDTH_20MHZ : eHT_CHANNEL_WIDTH_40MHZ; + qdf_mem_copy(pHtOpMode->peer_mac, &sta->staAddr, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = pe_session->smeSessionId; + + msg.type = WMA_UPDATE_OP_MODE; + msg.reserved = 0; + msg.bodyptr = pHtOpMode; + if (!QDF_IS_STATUS_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + pe_err("Not able to post WMA_UPDATE_OP_MODE message to WMA"); + qdf_mem_free(pHtOpMode); + return; + } + pe_debug("Notified FW about OP mode: %d", + pHtOpMode->opMode); + + } else + pe_debug("station does not support HT40"); + } + + return; +} +#endif + +/* -------------------------------------------------------------------- */ +/** + * __lim_process_report_message + * + * FUNCTION: Processes the next received Radio Resource Management message + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +static void __lim_process_report_message(struct mac_context *mac, + struct scheduler_msg *pMsg) +{ + switch (pMsg->type) { + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + rrm_process_neighbor_report_req(mac, pMsg->bodyptr); + break; + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + rrm_process_beacon_report_xmit(mac, pMsg->bodyptr); + break; + case eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND: + rrm_process_chan_load_report_xmit(mac, pMsg->bodyptr); + break; + default: + pe_err("Invalid msg type: %d", pMsg->type); + } +} + +/* -------------------------------------------------------------------- */ +/** + * lim_send_set_max_tx_power_req + * + * FUNCTION: Send SIR_HAL_SET_MAX_TX_POWER_REQ message to change the max tx power. + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param txPower txPower to be set. + * @param pe_session session entry. + * @return None + */ +QDF_STATUS +lim_send_set_max_tx_power_req(struct mac_context *mac, int8_t txPower, + struct pe_session *pe_session) +{ + tpMaxTxPowerParams pMaxTxParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + if (!pe_session) { + pe_err("Invalid parameters"); + return QDF_STATUS_E_FAILURE; + } + + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (!pMaxTxParams) + return QDF_STATUS_E_NOMEM; + pMaxTxParams->power = txPower; + qdf_mem_copy(pMaxTxParams->bssId.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMaxTxParams->selfStaMacAddr.bytes, + pe_session->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + msgQ.type = WMA_SET_MAX_TX_POWER_REQ; + msgQ.bodyptr = pMaxTxParams; + msgQ.bodyval = 0; + pe_debug("Post WMA_SET_MAX_TX_POWER_REQ to WMA"); + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("wma_post_ctrl_msg() failed"); + qdf_mem_free(pMaxTxParams); + } + return retCode; +} + +/** + * __lim_process_sme_register_mgmt_frame_req() - process sme reg mgmt frame req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process eWNI_SME_REGISTER_MGMT_FRAME_REQ message + * from SME. It Register this information within PE. + * + * Return: None + */ +static void __lim_process_sme_register_mgmt_frame_req(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + QDF_STATUS qdf_status; + struct register_mgmt_frame *sme_req = + (struct register_mgmt_frame *)msg_buf; + struct mgmt_frm_reg_info *lim_mgmt_regn = NULL; + struct mgmt_frm_reg_info *next = NULL; + bool match = false; + + pe_nofl_debug("Register Frame: register %d, type %d, match length %d", + sme_req->registerFrame, sme_req->frameType, + sme_req->matchLen); + /* First check whether entry exists already */ + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_list_peek_front(&mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t **) &lim_mgmt_regn); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + + while (lim_mgmt_regn) { + if (lim_mgmt_regn->frameType != sme_req->frameType) + goto skip_match; + if (sme_req->matchLen) { + if ((lim_mgmt_regn->matchLen == sme_req->matchLen) && + (!qdf_mem_cmp(lim_mgmt_regn->matchData, + sme_req->matchData, + lim_mgmt_regn->matchLen))) { + /* found match! */ + match = true; + break; + } + } else { + /* found match! */ + match = true; + break; + } +skip_match: + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + qdf_status = qdf_list_peek_next( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t *)lim_mgmt_regn, + (qdf_list_node_t **)&next); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + lim_mgmt_regn = next; + next = NULL; + } + if (match) { + qdf_mutex_acquire(&mac_ctx->lim.lim_frame_register_lock); + if (QDF_STATUS_SUCCESS == + qdf_list_remove_node( + &mac_ctx->lim.gLimMgmtFrameRegistratinQueue, + (qdf_list_node_t *)lim_mgmt_regn)) + qdf_mem_free(lim_mgmt_regn); + qdf_mutex_release(&mac_ctx->lim.lim_frame_register_lock); + } + + if (sme_req->registerFrame) { + lim_mgmt_regn = + qdf_mem_malloc(sizeof(struct mgmt_frm_reg_info) + + sme_req->matchLen); + if (lim_mgmt_regn) { + lim_mgmt_regn->frameType = sme_req->frameType; + lim_mgmt_regn->matchLen = sme_req->matchLen; + lim_mgmt_regn->sessionId = sme_req->sessionId; + if (sme_req->matchLen) { + qdf_mem_copy(lim_mgmt_regn->matchData, + sme_req->matchData, + sme_req->matchLen); + } + qdf_mutex_acquire( + &mac_ctx->lim.lim_frame_register_lock); + qdf_list_insert_front(&mac_ctx->lim. + gLimMgmtFrameRegistratinQueue, + &lim_mgmt_regn->node); + qdf_mutex_release( + &mac_ctx->lim.lim_frame_register_lock); + } + } + return; +} + +/** + * lim_register_mgmt_frame_ind_cb() - Save the Management frame + * indication callback in PE. + * @mac_ptr: Mac pointer + * @msg_buf: Msg pointer containing the callback + * + * This function is used save the Management frame + * indication callback in PE. + * + * Return: None + */ +static void lim_register_mgmt_frame_ind_cb(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_sme_mgmt_frame_cb_req *sme_req = + (struct sir_sme_mgmt_frame_cb_req *)msg_buf; + + if (!msg_buf) { + pe_err("msg_buf is null"); + return; + } + if (sme_req->callback) + mac_ctx->mgmt_frame_ind_cb = + (sir_mgmt_frame_ind_callback)sme_req->callback; + else + pe_err("sme_req->callback is null"); +} + +/** + *__lim_process_send_disassoc_frame() - processes send disassoc frame request + * @mac_ctx: pointer to mac context + * @msg_buf: request message buffer + * + * Process a request from SME to send a disassoc frame + * + * Return: none + */ +static void __lim_process_send_disassoc_frame(struct mac_context *mac_ctx, + void *msg_buf) +{ + struct sme_send_disassoc_frm_req *req = msg_buf; + struct pe_session *session_entry; + + if (!req) { + pe_err("NULL req"); + return; + } + + if ((IEEE80211_IS_MULTICAST(req->peer_mac) && + !QDF_IS_ADDR_BROADCAST(req->peer_mac))) { + pe_err("received invalid SME_DISASSOC_REQ message"); + return; + } + + session_entry = pe_find_session_by_vdev_id(mac_ctx, req->vdev_id); + if (!session_entry) { + pe_err("session does not exist for given bssId " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(req->peer_mac)); + return; + } + + /* Check if MAC address is MLD of the client and + * change it to primary link address to send OTA. + */ + lim_mlo_sap_validate_and_update_ra( + session_entry, (struct qdf_mac_addr *)req->peer_mac); + + pe_debug("msg_type %d len %d vdev_id %d mac: " QDF_MAC_ADDR_FMT " reason %d wait_for_ack %d", + req->msg_type, req->length, req->vdev_id, + QDF_MAC_ADDR_REF(req->peer_mac), req->reason, req->wait_for_ack); + + lim_send_disassoc_mgmt_frame(mac_ctx, req->reason, req->peer_mac, + session_entry, req->wait_for_ack); +} + +/** + * lim_set_pdev_ht_ie() - sends the set HT IE req to FW + * @mac_ctx: Pointer to Global MAC structure + * @pdev_id: pdev id to set the IE. + * @nss: Nss values to prepare the HT IE. + * + * Prepares the HT IE with self capabilities for different + * Nss values and sends the set HT IE req to FW. + * + * Return: None + */ +static void lim_set_pdev_ht_ie(struct mac_context *mac_ctx, uint8_t pdev_id, + uint8_t nss) +{ + struct set_ie_param *ie_params; + struct scheduler_msg msg = {0}; + QDF_STATUS rc = QDF_STATUS_SUCCESS; + const uint8_t *p_ie = NULL; + tHtCaps *p_ht_cap; + int i; + + for (i = 1; i <= nss; i++) { + ie_params = qdf_mem_malloc(sizeof(*ie_params)); + if (!ie_params) + return; + ie_params->nss = i; + ie_params->pdev_id = pdev_id; + ie_params->ie_type = DOT11_HT_IE; + /* 2 for IE len and EID */ + ie_params->ie_len = 2 + sizeof(tHtCaps); + ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len); + if (!ie_params->ie_ptr) { + qdf_mem_free(ie_params); + return; + } + *ie_params->ie_ptr = WLAN_ELEMID_HTCAP_ANA; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_ht_caps(mac_ctx, ie_params->ie_ptr, + ie_params->ie_len); + + if (NSS_1x1_MODE == i) { + p_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_HTCAPS, + ie_params->ie_ptr, ie_params->ie_len); + if (!p_ie) { + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + pe_err("failed to get IE ptr"); + return; + } + p_ht_cap = (tHtCaps *)&p_ie[2]; + p_ht_cap->supportedMCSSet[1] = 0; + p_ht_cap->txSTBC = 0; + } + + msg.type = WMA_SET_PDEV_IE_REQ; + msg.bodyptr = ie_params; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != QDF_STATUS_SUCCESS) { + pe_err("wma_post_ctrl_msg() return failure"); + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + return; + } + } +} + +/** + * lim_set_pdev_vht_ie() - sends the set VHT IE to req FW + * @mac_ctx: Pointer to Global MAC structure + * @pdev_id: pdev id to set the IE. + * @nss: Nss values to prepare the VHT IE. + * + * Prepares the VHT IE with self capabilities for different + * Nss values and sends the set VHT IE req to FW. + * + * Return: None + */ +static void lim_set_pdev_vht_ie(struct mac_context *mac_ctx, uint8_t pdev_id, + uint8_t nss) +{ + struct set_ie_param *ie_params; + struct scheduler_msg msg = {0}; + QDF_STATUS rc = QDF_STATUS_SUCCESS; + const uint8_t *p_ie = NULL; + tSirMacVHTCapabilityInfo *vht_cap; + int i; + tSirVhtMcsInfo *vht_mcs; + + for (i = 1; i <= nss; i++) { + ie_params = qdf_mem_malloc(sizeof(*ie_params)); + if (!ie_params) + return; + ie_params->nss = i; + ie_params->pdev_id = pdev_id; + ie_params->ie_type = DOT11_VHT_IE; + /* 2 for IE len and EID */ + ie_params->ie_len = 2 + sizeof(tSirMacVHTCapabilityInfo) + + sizeof(tSirVhtMcsInfo); + ie_params->ie_ptr = qdf_mem_malloc(ie_params->ie_len); + if (!ie_params->ie_ptr) { + qdf_mem_free(ie_params); + return; + } + *ie_params->ie_ptr = WLAN_ELEMID_VHTCAP; + *(ie_params->ie_ptr + 1) = ie_params->ie_len - 2; + lim_set_vht_caps(mac_ctx, ie_params->ie_ptr, ie_params->ie_len); + + if (NSS_1x1_MODE == i) { + p_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_VHTCAPS, + ie_params->ie_ptr, ie_params->ie_len); + if (!p_ie) { + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + pe_err("failed to get IE ptr"); + return; + } + vht_cap = (tSirMacVHTCapabilityInfo *)&p_ie[2]; + vht_cap->txSTBC = 0; + vht_mcs = + (tSirVhtMcsInfo *)&p_ie[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + vht_mcs->rxMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->rxHighest = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + vht_mcs->txMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->txHighest = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + msg.type = WMA_SET_PDEV_IE_REQ; + msg.bodyptr = ie_params; + msg.bodyval = 0; + + rc = wma_post_ctrl_msg(mac_ctx, &msg); + if (rc != QDF_STATUS_SUCCESS) { + pe_err("wma_post_ctrl_msg failure"); + qdf_mem_free(ie_params->ie_ptr); + qdf_mem_free(ie_params); + return; + } + } +} + +/** + * lim_process_set_vdev_ies_per_band() - process the set vdev IE req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to the SME message buffer + * + * This function is called by limProcessMessageQueue(). This function sets the + * VDEV IEs to the FW. + * + * Return: None + */ +static void lim_process_set_vdev_ies_per_band(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_set_vdev_ies_per_band *p_msg = + (struct sir_set_vdev_ies_per_band *)msg_buf; + + if (!p_msg) { + pe_err("NULL p_msg"); + return; + } + + pe_debug("rcvd set vdev ie per band req vdev_id = %d", + p_msg->vdev_id); + + if (lim_send_ies_per_band(mac_ctx, p_msg->vdev_id, + p_msg->dot11_mode, p_msg->device_mode) != + QDF_STATUS_SUCCESS) + pe_err("Unable to send HT/VHT Cap to FW"); +} + +/** + * lim_process_set_pdev_IEs() - process the set pdev IE req + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: Pointer to the SME message buffer + * + * This function is called by limProcessMessageQueue(). This + * function sets the PDEV IEs to the FW. + * + * Return: None + */ +static void lim_process_set_pdev_IEs(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + struct sir_set_ht_vht_cfg *ht_vht_cfg; + + ht_vht_cfg = (struct sir_set_ht_vht_cfg *)msg_buf; + + if (!ht_vht_cfg) { + pe_err("NULL ht_vht_cfg"); + return; + } + + pe_debug("rcvd set pdev ht vht ie req with nss = %d", + ht_vht_cfg->nss); + lim_set_pdev_ht_ie(mac_ctx, ht_vht_cfg->pdev_id, ht_vht_cfg->nss); + + if (IS_DOT11_MODE_VHT(ht_vht_cfg->dot11mode)) + lim_set_pdev_vht_ie(mac_ctx, ht_vht_cfg->pdev_id, + ht_vht_cfg->nss); +} + +/** + * lim_process_sme_update_access_policy_vendor_ie: function updates vendor IE + * + * access policy + * @mac_ctx: pointer to mac context + * @msg: message buffer + * + * function processes vendor IE and access policy from SME and updates PE + * + * session entry + * + * return: none +*/ +static void lim_process_sme_update_access_policy_vendor_ie( + struct mac_context *mac_ctx, + uint32_t *msg) +{ + struct sme_update_access_policy_vendor_ie *update_vendor_ie; + struct pe_session *pe_session_entry; + uint16_t num_bytes; + + if (!msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + update_vendor_ie = (struct sme_update_access_policy_vendor_ie *) msg; + pe_session_entry = pe_find_session_by_vdev_id(mac_ctx, + update_vendor_ie->vdev_id); + + if (!pe_session_entry) { + pe_err("Session does not exist for given vdev_id %d", + update_vendor_ie->vdev_id); + return; + } + if (pe_session_entry->access_policy_vendor_ie) + qdf_mem_free(pe_session_entry->access_policy_vendor_ie); + + num_bytes = update_vendor_ie->ie[1] + 2; + pe_session_entry->access_policy_vendor_ie = qdf_mem_malloc(num_bytes); + if (!pe_session_entry->access_policy_vendor_ie) + return; + qdf_mem_copy(pe_session_entry->access_policy_vendor_ie, + &update_vendor_ie->ie[0], num_bytes); + + pe_session_entry->access_policy = update_vendor_ie->access_policy; +} + +QDF_STATUS lim_sta_mlme_vdev_disconnect_bss(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct mac_context *mac_ctx; + struct scheduler_msg *msg = (struct scheduler_msg *)data; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + if (data) + qdf_mem_free(data); + return QDF_STATUS_E_INVAL; + } + pe_debug("Vdev %d: disconnect bss callback type:(%d)", + wlan_vdev_get_id(vdev_mlme->vdev), msg->type); + + switch (msg->type) { + case eWNI_SME_DEAUTH_REQ: + __lim_process_sme_deauth_req(mac_ctx, + (uint32_t *)msg->bodyptr); + break; + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + __lim_process_sme_disassoc_cnf(mac_ctx, + (uint32_t *)msg->bodyptr); + break; + case eWNI_SME_DISASSOC_REQ: + __lim_process_sme_disassoc_req(mac_ctx, + (uint32_t *)msg->bodyptr); + break; + default: + pe_err("Vdev %d Wrong message type received %d", + wlan_vdev_get_id(vdev_mlme->vdev), msg->type); + } + return QDF_STATUS_SUCCESS; +} + +static void lim_process_sme_disassoc_cnf(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct disassoc_cnf sme_disassoc_cnf; + struct pe_session *session; + uint8_t session_id; + uint32_t *err_msg = NULL; + QDF_STATUS status; + + qdf_mem_copy(&sme_disassoc_cnf, msg->bodyptr, sizeof(sme_disassoc_cnf)); + + session = pe_find_session_by_bssid(mac_ctx, + sme_disassoc_cnf.bssid.bytes, + &session_id); + if (!session) { + pe_err("session not found for bssid:"QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sme_disassoc_cnf.bssid.bytes)); + status = lim_prepare_disconnect_done_ind + (mac_ctx, &err_msg, + sme_disassoc_cnf.vdev_id, + eSIR_SME_INVALID_SESSION, + NULL); + + if (QDF_IS_STATUS_SUCCESS(status)) + lim_send_sme_disassoc_deauth_ntf(mac_ctx, + QDF_STATUS_SUCCESS, + err_msg); + return; + } + + __lim_process_sme_disassoc_cnf(mac_ctx, (uint32_t *)msg->bodyptr); +} + +static void lim_process_sme_disassoc_req(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct disassoc_req disassoc_req; + struct pe_session *session; + uint8_t session_id; + struct qdf_mac_addr mld_addr = QDF_MAC_ADDR_ZERO_INIT; + + qdf_mem_copy(&disassoc_req, msg->bodyptr, sizeof(struct disassoc_req)); + + session = pe_find_session_by_bssid(mac_ctx, + disassoc_req.bssid.bytes, + &session_id); + if (!session) { + pe_err("session not found for bssid:"QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(disassoc_req.bssid.bytes)); + lim_send_sme_disassoc_ntf(mac_ctx, + disassoc_req.peer_macaddr.bytes, + mld_addr.bytes, + eSIR_SME_INVALID_PARAMETERS, + eLIM_HOST_DISASSOC, 1, + disassoc_req.sessionId, NULL); + + return; + } + + __lim_process_sme_disassoc_req(mac_ctx, (uint32_t *)msg->bodyptr); +} + +static void lim_process_sme_deauth_req(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct deauth_req sme_deauth_req; + struct pe_session *session; + uint8_t session_id; + + qdf_mem_copy(&sme_deauth_req, msg->bodyptr, sizeof(sme_deauth_req)); + + session = pe_find_session_by_bssid(mac_ctx, + sme_deauth_req.bssid.bytes, + &session_id); + if (!session) { + pe_err("session not found for bssid:"QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sme_deauth_req.bssid.bytes)); + lim_send_sme_deauth_ntf(mac_ctx, + sme_deauth_req.peer_macaddr.bytes, + eSIR_SME_INVALID_PARAMETERS, + eLIM_HOST_DEAUTH, 1, + sme_deauth_req.vdev_id); + + return; + } + + __lim_process_sme_deauth_req(mac_ctx, (uint32_t *)msg->bodyptr); +} + +void lim_send_bcn_rsp(struct mac_context *mac_ctx, tpSendbeaconParams rsp) +{ + if (!rsp) { + pe_err("rsp is NULL"); + return; + } + + /* Success case response is sent from beacon_tx completion/timeout */ + if (rsp->reason == REASON_CH_WIDTH_UPDATE && + QDF_IS_STATUS_SUCCESS(rsp->status)) + return; + + pe_debug("Send beacon resp status %d for reason %d", + rsp->status, rsp->reason); + + lim_nss_or_ch_width_update_rsp(mac_ctx, rsp->vdev_id, + rsp->status, rsp->reason); +} + +static void +lim_update_bcn_with_new_ch_width(struct mac_context *mac_ctx, + struct pe_session *session, + enum phy_ch_width ch_width) +{ + QDF_STATUS status; + + session->gLimOperatingMode.present = 1; + session->gLimOperatingMode.chanWidth = ch_width; + + pe_debug("ch width %d", + session->gLimOperatingMode.chanWidth); + + session->bw_update_include_ch_sw_ie = true; + status = qdf_mc_timer_start(&session->ap_ecsa_timer, + MAX_WAIT_FOR_CH_WIDTH_UPDATE_COMPLETE); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("cannot start ap_ecsa_timer"); + + /* Send nss update request from here */ + status = sch_set_fixed_beacon_fields(mac_ctx, session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Unable to set op mode IE in beacon"); + goto end; + } + + status = lim_send_beacon_ind(mac_ctx, session, + REASON_CH_WIDTH_UPDATE); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + pe_err("Unable to send beacon"); +end: + /* + * send resp only in case of failure, + * success case response will be from wma. + */ + lim_nss_or_ch_width_update_rsp(mac_ctx, session->vdev_id, status, + REASON_CH_WIDTH_UPDATE); +} + +static enum phy_ch_width +lim_calculate_peer_ch_width(struct pe_session *session, + uint8_t *mac_addr, + enum phy_ch_width new_ch_width) +{ + enum phy_ch_width peer_org_bw, updated_bw; + struct peer_oper_mode_event data = {0}; + QDF_STATUS status; + + peer_org_bw = wlan_mlme_get_peer_ch_width( + wlan_vdev_get_psoc(session->vdev), mac_addr); + + updated_bw = new_ch_width; + + qdf_mem_copy(&data.peer_mac_address.bytes, mac_addr, QDF_MAC_ADDR_SIZE); + status = wlan_mlme_get_peer_indicated_ch_width( + wlan_vdev_get_psoc(session->vdev), &data); + if (QDF_IS_STATUS_SUCCESS(status)) + updated_bw = data.new_bw; + + pe_debug("Peer: " QDF_MAC_ADDR_FMT " original bw: %d, updated bw: %d, new bw: %d", + QDF_MAC_ADDR_REF(mac_addr), peer_org_bw, updated_bw, + new_ch_width); + + return qdf_min(peer_org_bw, qdf_min(updated_bw, new_ch_width)); +} + +static void +lim_update_new_ch_width_to_fw(struct mac_context *mac_ctx, + struct pe_session *session, + enum phy_ch_width ch_bandwidth) +{ + uint8_t i; + tpDphHashNode psta; + tUpdateVHTOpMode params; + + for (i = 0; i <= mac_ctx->lim.max_sta_of_pe_session; i++) { + psta = session->dph.dphHashTable.pDphNodeArray + i; + if (!psta || !psta->added) + continue; + + params.opMode = lim_calculate_peer_ch_width(session, + psta->staAddr, ch_bandwidth); + params.smesessionId = session->smeSessionId; + qdf_mem_copy(params.peer_mac, psta->staAddr, + sizeof(tSirMacAddr)); + + lim_send_mode_update(mac_ctx, ¶ms, session); + } +} + +/** + * lim_process_sap_ch_width_update() - process sme nss update req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void +lim_process_sap_ch_width_update(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_sap_ch_width_update *req; + struct pe_session *session = NULL; + uint8_t vdev_id; + struct sir_bcn_update_rsp *param; + struct scheduler_msg msg_return = {0}; + uint8_t primary_channel; + struct ch_params ch_params = {0}; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + req = (struct sir_sap_ch_width_update *)msg_buf; + vdev_id = req->vdev_id; + session = pe_find_session_by_vdev_id(mac_ctx, req->vdev_id); + if (!session) { + pe_err("vdev %d session not found", req->vdev_id); + goto fail; + } + + if (session->opmode != QDF_SAP_MODE) { + pe_err("Invalid opmode %d", session->opmode); + goto fail; + } + + ch_params.ch_width = req->ch_width; + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + session->curr_op_freq, + 0, + &ch_params, + REG_CURRENT_PWR_MODE); + + session->gLimChannelSwitch.switchCount = 1; + session->gLimChannelSwitch.sw_target_freq = session->curr_op_freq; + primary_channel = wlan_reg_freq_to_chan(mac_ctx->pdev, + session->curr_op_freq); + session->gLimChannelSwitch.primaryChannel = primary_channel; + session->gLimChannelSwitch.ch_width = req->ch_width; + session->gLimChannelSwitch.ch_center_freq_seg0 = + ch_params.center_freq_seg0; + session->gLimChannelSwitch.ch_center_freq_seg1 = + ch_params.center_freq_seg1; + + wlan_mlme_set_ap_oper_ch_width(session->vdev, req->ch_width); + + /* Send ECSA to the peers */ + send_extended_chan_switch_action_frame(mac_ctx, + session->curr_op_freq, + req->ch_width, session); + + /* Send beacon template to firmware */ + lim_update_bcn_with_new_ch_width(mac_ctx, session, req->ch_width); + /* Send updated bw info of each peer to firmware */ + lim_update_new_ch_width_to_fw(mac_ctx, session, req->ch_width); + + /* + * Release the SER command only after this, otherwise it may cause + * out of sync issues if any other WMI commands go to fw + */ + return; + +fail: + pe_err("vdev %d: send bandwidth update fail", vdev_id); + param = qdf_mem_malloc(sizeof(*param)); + if (param) { + param->status = QDF_STATUS_E_FAILURE; + param->vdev_id = INVALID_VDEV_ID; + param->reason = REASON_CH_WIDTH_UPDATE; + } + msg_return.type = eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP; + msg_return.bodyptr = param; + msg_return.bodyval = 0; + sys_process_mmh_msg(mac_ctx, &msg_return); +} + +/** + * lim_process_sme_req_messages() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue(). This + * function processes SME request messages from HDD or upper layer + * application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *msg_buf A pointer to the SME message buffer + * @return Boolean - true - if msg_buf is consumed and can be freed. + * false - if msg_buf is not to be freed. + */ + +bool lim_process_sme_req_messages(struct mac_context *mac, + struct scheduler_msg *pMsg) +{ + /* + * Set this flag to false within case block of any following message, + * that doesn't want msg_buf to be freed. + */ + bool bufConsumed = true; + uint32_t *msg_buf = pMsg->bodyptr; + + pe_nofl_debug("LIM handle SME Msg %s(%d)", + lim_msg_str(pMsg->type), pMsg->type); + + /* If no insert NOA required then execute the code below */ + + switch (pMsg->type) { + case eWNI_SME_SYS_READY_IND: + bufConsumed = __lim_process_sme_sys_ready_ind(mac, msg_buf); + break; + + case eWNI_SME_START_BSS_REQ: + bufConsumed = __lim_process_sme_start_bss_req(mac, pMsg); + break; + case eWNI_SME_DISASSOC_REQ: + lim_process_sme_disassoc_req(mac, pMsg); + break; + + case eWNI_SME_DISASSOC_CNF: + case eWNI_SME_DEAUTH_CNF: + lim_process_sme_disassoc_cnf(mac, pMsg); + break; + + case eWNI_SME_DEAUTH_REQ: + lim_process_sme_deauth_req(mac, pMsg); + break; + + case eWNI_SME_SEND_DISASSOC_FRAME: + __lim_process_send_disassoc_frame(mac, msg_buf); + break; + + case eWNI_SME_STOP_BSS_REQ: + bufConsumed = __lim_process_sme_stop_bss_req(mac, pMsg); + break; + + case eWNI_SME_ASSOC_CNF: + pe_debug("Received ASSOC_CNF message"); + __lim_process_sme_assoc_cnf_new(mac, pMsg->type, + msg_buf); + break; + + case eWNI_SME_ADDTS_REQ: + pe_debug("Received ADDTS_REQ message"); + __lim_process_sme_addts_req(mac, msg_buf); + break; + + case eWNI_SME_MSCS_REQ: + pe_debug("Received MSCS_REQ message"); + __lim_process_sme_mscs_req(mac, msg_buf); + break; + + case eWNI_SME_DELTS_REQ: + pe_debug("Received DELTS_REQ message"); + __lim_process_sme_delts_req(mac, msg_buf); + break; + + case SIR_LIM_ADDTS_RSP_TIMEOUT: + pe_debug("Received SIR_LIM_ADDTS_RSP_TIMEOUT message"); + lim_process_sme_addts_rsp_timeout(mac, pMsg->bodyval); + break; + +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: + __lim_process_sme_get_tsm_stats_request(mac, msg_buf); + bufConsumed = false; + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_SESSION_UPDATE_PARAM: + __lim_process_sme_session_update(mac, msg_buf); + break; + case eWNI_SME_CHNG_MCC_BEACON_INTERVAL: + /* Update the beaconInterval */ + __lim_process_sme_change_bi(mac, msg_buf); + break; + +#ifdef QCA_HT_2040_COEX + case eWNI_SME_SET_HT_2040_MODE: + __lim_process_sme_set_ht2040_mode(mac, msg_buf); + break; +#endif + + case eWNI_SME_NEIGHBOR_REPORT_REQ_IND: + case eWNI_SME_BEACON_REPORT_RESP_XMIT_IND: + case eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND: + __lim_process_report_message(mac, pMsg); + break; + case eWNI_SME_FT_AGGR_QOS_REQ: + lim_process_ft_aggr_qos_req(mac, msg_buf); + break; + + case eWNI_SME_REGISTER_MGMT_FRAME_REQ: + __lim_process_sme_register_mgmt_frame_req(mac, msg_buf); + break; +#ifdef FEATURE_WLAN_TDLS + case eWNI_SME_TDLS_SEND_MGMT_REQ: + lim_process_sme_tdls_mgmt_send_req(mac, msg_buf); + break; + case eWNI_SME_TDLS_ADD_STA_REQ: + lim_process_sme_tdls_add_sta_req(mac, msg_buf); + break; + case eWNI_SME_TDLS_DEL_STA_REQ: + lim_process_sme_tdls_del_sta_req(mac, msg_buf); + break; +#endif + case eWNI_SME_CHANNEL_CHANGE_REQ: + lim_process_sme_channel_change_request(mac, msg_buf); + break; + + case eWNI_SME_START_BEACON_REQ: + lim_process_sme_start_beacon_req(mac, msg_buf); + break; + + case eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ: + lim_process_sme_dfs_csa_ie_request(mac, msg_buf); + break; + + case eWNI_SME_UPDATE_ADDITIONAL_IES: + lim_process_update_add_ies(mac, msg_buf); + break; + + case eWNI_SME_MODIFY_ADDITIONAL_IES: + lim_process_modify_add_ies(mac, msg_buf); + break; + case eWNI_SME_SET_HW_MODE_REQ: + lim_process_set_hw_mode(mac, msg_buf); + break; + case eWNI_SME_NSS_UPDATE_REQ: + lim_process_nss_update_request(mac, msg_buf); + break; + case eWNI_SME_SET_DUAL_MAC_CFG_REQ: + lim_process_set_dual_mac_cfg_req(mac, msg_buf); + break; + case eWNI_SME_SET_IE_REQ: + lim_process_set_ie_req(mac, msg_buf); + break; + case eWNI_SME_REGISTER_MGMT_FRAME_CB: + lim_register_mgmt_frame_ind_cb(mac, msg_buf); + break; + case eWNI_SME_EXT_CHANGE_CHANNEL: + lim_process_ext_change_channel(mac, msg_buf); + break; + case eWNI_SME_SET_ANTENNA_MODE_REQ: + lim_process_set_antenna_mode_req(mac, msg_buf); + break; + case eWNI_SME_PDEV_SET_HT_VHT_IE: + lim_process_set_pdev_IEs(mac, msg_buf); + break; + case eWNI_SME_SET_VDEV_IES_PER_BAND: + lim_process_set_vdev_ies_per_band(mac, msg_buf); + break; + case eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE: + lim_process_sme_update_access_policy_vendor_ie(mac, msg_buf); + break; + case eWNI_SME_UPDATE_CONFIG: + lim_process_sme_update_config(mac, + (struct update_config *)msg_buf); + break; + case eWNI_SME_SET_ADDBA_ACCEPT: + lim_process_sme_set_addba_accept(mac, + (struct sme_addba_accept *)msg_buf); + break; + case eWNI_SME_UPDATE_EDCA_PROFILE: + lim_process_sme_update_edca_params(mac, pMsg->bodyval); + break; + case WNI_SME_UPDATE_MU_EDCA_PARAMS: + lim_process_sme_update_mu_edca_params(mac, pMsg->bodyval); + break; + case eWNI_SME_UPDATE_SESSION_EDCA_TXQ_PARAMS: + lim_process_sme_update_session_edca_txq_params(mac, msg_buf); + break; + case WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU: + lim_process_sme_cfg_action_frm_in_tb_ppdu(mac, + (struct sir_cfg_action_frm_tb_ppdu *)msg_buf); + break; + case eWNI_SME_VDEV_PAUSE_IND: + lim_process_sme_send_vdev_pause(mac, + (struct sme_vdev_pause *)msg_buf); + break; + case eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ: + lim_process_sap_ch_width_update(mac, msg_buf); + break; + default: + qdf_mem_free((void *)pMsg->bodyptr); + pMsg->bodyptr = NULL; + break; + } /* switch (msgType) */ + + return bufConsumed; +} /*** end lim_process_sme_req_messages() ***/ + +/** + * lim_process_sme_start_beacon_req() + * + ***FUNCTION: + * This function is called by limProcessMessageQueue(). This + * function processes SME request messages from HDD or upper layer + * application. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param msgType Indicates the SME message type + * @param *msg_buf A pointer to the SME message buffer + * @return Boolean - true - if msg_buf is consumed and can be freed. + * false - if msg_buf is not to be freed. + */ +static void lim_process_sme_start_beacon_req(struct mac_context *mac, uint32_t *pMsg) +{ + tpSirStartBeaconIndication pBeaconStartInd; + struct pe_session *pe_session; + uint8_t sessionId; /* PE sessionID */ + + if (!pMsg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + pBeaconStartInd = (tpSirStartBeaconIndication) pMsg; + pe_session = pe_find_session_by_bssid(mac, + pBeaconStartInd->bssid, + &sessionId); + if (!pe_session) { + pe_err("Session does not exist for given bssId: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pBeaconStartInd->bssid)); + return; + } + + if (pBeaconStartInd->beaconStartStatus == true) { + /* + * Currently this Indication comes from SAP + * to start Beacon Tx on a DFS channel + * since beaconing has to be done on DFS + * channel only after CAC WAIT is completed. + * On a DFS Channel LIM does not start beacon + * Tx right after the WMA_ADD_BSS_RSP. + */ + lim_apply_configuration(mac, pe_session); + pe_debug("Start Beacon with ssid " QDF_SSID_FMT " Ch freq %d", + QDF_SSID_REF(pe_session->ssId.length, + pe_session->ssId.ssId), + pe_session->curr_op_freq); + lim_send_beacon(mac, pe_session); + lim_enable_obss_detection_config(mac, pe_session); + lim_send_obss_color_collision_cfg(mac, pe_session, + OBSS_COLOR_COLLISION_DETECTION); + } else { + pe_err("Invalid Beacon Start Indication"); + return; + } +} + +static void lim_mon_change_channel( + struct mac_context *mac_ctx, + struct pe_session *session_entry) +{ + if (wlan_vdev_mlme_get_state(session_entry->vdev) == WLAN_VDEV_S_INIT) + wlan_vdev_mlme_sm_deliver_evt(session_entry->vdev, + WLAN_VDEV_SM_EV_START, + sizeof(*session_entry), + session_entry); + else if (wlan_vdev_mlme_get_state(session_entry->vdev) == + WLAN_VDEV_S_UP) { + mlme_set_chan_switch_in_progress(session_entry->vdev, true); + wlan_vdev_mlme_sm_deliver_evt(session_entry->vdev, + WLAN_VDEV_SM_EV_FW_VDEV_RESTART, + sizeof(*session_entry), + session_entry); + } else { + pe_err("Invalid vdev state to change channel"); + } +} + +static void lim_change_channel( + struct mac_context *mac_ctx, + struct pe_session *session_entry) +{ + if (session_entry->bssType == eSIR_MONITOR_MODE) + return lim_mon_change_channel(mac_ctx, session_entry); + + mlme_set_chan_switch_in_progress(session_entry->vdev, true); + + if (wlan_vdev_mlme_get_state(session_entry->vdev) == + WLAN_VDEV_S_DFS_CAC_WAIT) + wlan_vdev_mlme_sm_deliver_evt(session_entry->vdev, + WLAN_VDEV_SM_EV_RADAR_DETECTED, + sizeof(*session_entry), + session_entry); + else + wlan_vdev_mlme_sm_deliver_evt(session_entry->vdev, + WLAN_VDEV_SM_EV_CSA_COMPLETE, + sizeof(*session_entry), + session_entry); +} + +#ifdef WLAN_FEATURE_11BE +static bool +lim_is_puncture_bitmap_changed(struct pe_session *session, + struct channel_change_req *ch_change_req) +{ + uint16_t ori_puncture_bitmap; + + ori_puncture_bitmap = + *(uint16_t *)session->eht_op.disabled_sub_chan_bitmap; + + return ori_puncture_bitmap != ch_change_req->target_punc_bitmap; +} +#else +static inline bool +lim_is_puncture_bitmap_changed(struct pe_session *session, + struct channel_change_req *ch_change_req) +{ + return false; +} +#endif + +/** + * lim_abort_channel_change() - Abort channel change + * + * @mac_ctx : Pointer to pe_session + * @vdev_id: vdev ID + * + * This function is called to abort channel change request after CSA + * countdown and allow SAP/GO to operate on current channel without + * vdev restart. + * + * Return: None + */ +static void lim_abort_channel_change(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + struct qdf_mac_addr bssid; + struct pe_session *session_entry; + uint8_t session_id; + QDF_STATUS status; + struct scheduler_msg sch_msg = {0}; + struct sSirChanChangeResponse *chan_change_rsp; + + status = wlan_mlme_get_mac_vdev_id(mac_ctx->pdev, vdev_id, &bssid); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed to get vdev ID"); + return; + } + + session_entry = pe_find_session_by_bssid(mac_ctx, bssid.bytes, + &session_id); + if (!session_entry) { + pe_err("Session does not exist for bssid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + return; + } + + session_entry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_SAP_DFS; + mac_ctx->sap.SapDfsInfo.target_chan_freq = + session_entry->curr_op_freq; + mac_ctx->sap.SapDfsInfo.new_chanWidth = session_entry->ch_width; + mac_ctx->sap.SapDfsInfo.new_ch_params.ch_width = + session_entry->ch_width; + + wlan_vdev_mlme_sm_deliver_evt(session_entry->vdev, + WLAN_VDEV_SM_EV_CHAN_SWITCH_DISABLED, + sizeof(*session_entry), session_entry); + + chan_change_rsp = qdf_mem_malloc(sizeof(struct sSirChanChangeResponse)); + if (!chan_change_rsp) { + pe_err("Failed to allocate chan_change_rsp"); + return; + } + + chan_change_rsp->new_op_freq = session_entry->curr_op_freq; + chan_change_rsp->channelChangeStatus = QDF_STATUS_SUCCESS; + chan_change_rsp->sessionId = session_id; + sch_msg.type = eWNI_SME_CHANNEL_CHANGE_RSP; + sch_msg.bodyptr = (void *)chan_change_rsp; + sch_msg.bodyval = 0; + + lim_sys_process_mmh_msg_api(mac_ctx, &sch_msg); +} + +#ifdef WLAN_FEATURE_11AX +static inline void +lim_update_he_capable(struct pe_session *session, uint8_t dot11mode) +{ + session->he_capable = IS_DOT11_MODE_HE(dot11mode); +} +#else +static inline void +lim_update_he_capable(struct pe_session *session, uint8_t dot11mode) +{} +#endif +#ifdef WLAN_FEATURE_11BE +static inline void +lim_update_eht_capable(struct pe_session *session, uint8_t dot11mode) +{ + session->eht_capable = IS_DOT11_MODE_EHT(dot11mode); +} +#else +static inline void +lim_update_eht_capable(struct pe_session *session, uint8_t dot11mode) +{} +#endif + + +/** + * lim_process_sme_channel_change_request() - process sme ch change req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function is called to process SME_CHANNEL_CHANGE_REQ message + * + * Return: None + */ +static void lim_process_sme_channel_change_request(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct channel_change_req *ch_change_req; + struct qdf_mac_addr bssid; + struct pe_session *session_entry; + uint8_t session_id; /* PE session_id */ + int8_t max_tx_pwr; + uint32_t target_freq; + bool is_curr_ch_2g, is_new_ch_2g, update_he_cap, update_eht_cap; + + if (!msg_buf) { + pe_err("msg_buf is NULL"); + return; + } + ch_change_req = (struct channel_change_req *)msg_buf; + target_freq = ch_change_req->target_chan_freq; + + max_tx_pwr = wlan_reg_get_channel_reg_power_for_freq( + mac_ctx->pdev, target_freq); + if (max_tx_pwr == WMA_MAX_TXPOWER_INVALID) { + pe_err("Invalid max tx power"); + return; + } + wlan_mlme_get_mac_vdev_id(mac_ctx->pdev, + ch_change_req->vdev_id, &bssid); + session_entry = pe_find_session_by_bssid(mac_ctx, bssid.bytes, + &session_id); + if (!session_entry) { + pe_err("Session does not exist for bssid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + return; + } + + /* + * The scenario here is, existing SAP/GO is operating on non-DFS chan + * and STA connects to a DFS AP which creates MCC. This will then + * trigger SCC enforcement logic. Now during CSA countdown (before + * GO/SAP actually moves to STA's channel), if STA disconnects, then + * moving GO / SAP to DFS channel will lead to FCC violation if radar + * detection is disabled + * + * Hence to handle this scenario, better to stop current GO/SAP's + * movement to this DFS channel and allow to operate on current channel + * only, STA associated to GO/SAP's will find that SAP/GO didn't beacon + * on new channel so Heartbeat failure will happen and they will scan + * and connect again. + */ + + if (LIM_IS_AP_ROLE(session_entry) && + !policy_mgr_is_sap_allowed_on_dfs_freq(mac_ctx->pdev, session_id, + target_freq)) { + lim_abort_channel_change(mac_ctx, ch_change_req->vdev_id); + return; + } else if ((session_entry->curr_op_freq == target_freq && + session_entry->ch_width == ch_change_req->ch_width) && + (!IS_DOT11_MODE_EHT(session_entry->dot11mode) || + !lim_is_puncture_bitmap_changed(session_entry, + ch_change_req))) { + pe_err("Target channel and mode is same as current channel and mode channel freq %d and mode %d", + session_entry->curr_op_freq, session_entry->ch_width); + return; + } + + if (LIM_IS_AP_ROLE(session_entry)) + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_SAP_DFS; + else + session_entry->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_MONITOR; + + pe_nofl_debug("SAP CSA: %d ---> %d, ch_bw %d, nw_type %d, dot11mode %d, old dot11mode %d", + session_entry->curr_op_freq, target_freq, + ch_change_req->ch_width, ch_change_req->nw_type, + ch_change_req->dot11mode, session_entry->dot11mode); + + /* Update ht/vht/he/eht capability as per the new dot11mode */ + if (ch_change_req->dot11mode != session_entry->dot11mode) { + session_entry->htCapability = + IS_DOT11_MODE_HT(ch_change_req->dot11mode); + session_entry->vhtCapability = + IS_DOT11_MODE_VHT(ch_change_req->dot11mode); + lim_update_he_capable(session_entry, ch_change_req->dot11mode); + lim_update_eht_capable(session_entry, ch_change_req->dot11mode); + } + + if (IS_DOT11_MODE_HE(ch_change_req->dot11mode) && + ((QDF_MONITOR_MODE == session_entry->opmode) || + lim_is_session_he_capable(session_entry))) { + lim_update_session_he_capable_chan_switch + (mac_ctx, session_entry, target_freq); + is_new_ch_2g = wlan_reg_is_24ghz_ch_freq(target_freq); + is_curr_ch_2g = wlan_reg_is_24ghz_ch_freq( + session_entry->curr_op_freq); + if ((is_new_ch_2g && !is_curr_ch_2g) || + (!is_new_ch_2g && is_curr_ch_2g)) + update_he_cap = true; + else + update_he_cap = false; + if (!update_he_cap) { + if ((session_entry->ch_width != + ch_change_req->ch_width) && + (session_entry->ch_width > CH_WIDTH_80MHZ || + ch_change_req->ch_width > CH_WIDTH_80MHZ)) + update_he_cap = true; + } + if (update_he_cap) { + session_entry->curr_op_freq = target_freq; + session_entry->ch_width = ch_change_req->ch_width; + lim_copy_bss_he_cap(session_entry); + lim_update_he_bw_cap_mcs(session_entry, NULL); + } + } else if (wlan_reg_is_6ghz_chan_freq(target_freq)) { + pe_debug("Invalid target_freq %d for dot11mode %d cur HE %d", + target_freq, ch_change_req->dot11mode, + lim_is_session_he_capable(session_entry)); + return; + } + + if (IS_DOT11_MODE_EHT(ch_change_req->dot11mode) && + ((QDF_MONITOR_MODE == session_entry->opmode) || + lim_is_session_eht_capable(session_entry))) { + lim_update_session_eht_capable_chan_switch( + mac_ctx, session_entry, target_freq); + is_new_ch_2g = wlan_reg_is_24ghz_ch_freq(target_freq); + is_curr_ch_2g = wlan_reg_is_24ghz_ch_freq( + session_entry->curr_op_freq); + if ((is_new_ch_2g && !is_curr_ch_2g) || + (!is_new_ch_2g && is_curr_ch_2g)) + update_eht_cap = true; + else + update_eht_cap = false; + if (!update_eht_cap) { + if ((session_entry->ch_width != + ch_change_req->ch_width) && + (session_entry->ch_width > CH_WIDTH_80MHZ || + ch_change_req->ch_width > CH_WIDTH_80MHZ)) + update_eht_cap = true; + } + if (update_eht_cap) { + session_entry->curr_op_freq = target_freq; + session_entry->ch_width = ch_change_req->ch_width; + lim_copy_bss_eht_cap(session_entry); + lim_update_eht_bw_cap_mcs(session_entry, NULL); + } + } + + /* Store the New Channel Params in session_entry */ + session_entry->ch_width = ch_change_req->ch_width; + session_entry->ch_center_freq_seg0 = + ch_change_req->center_freq_seg0; + session_entry->ch_center_freq_seg1 = + ch_change_req->center_freq_seg1; + session_entry->htSecondaryChannelOffset = ch_change_req->sec_ch_offset; + session_entry->htSupportedChannelWidthSet = + (ch_change_req->ch_width ? 1 : 0); + session_entry->htRecommendedTxWidthSet = + session_entry->htSupportedChannelWidthSet; + session_entry->curr_op_freq = target_freq; + session_entry->limRFBand = lim_get_rf_band( + session_entry->curr_op_freq); + if (mlme_get_cac_required(session_entry->vdev)) + session_entry->cac_duration_ms = ch_change_req->cac_duration_ms; + else + session_entry->cac_duration_ms = 0; + session_entry->dfs_regdomain = ch_change_req->dfs_regdomain; + session_entry->maxTxPower = max_tx_pwr; + + /* Update the global beacon filter */ + lim_update_bcn_probe_filter(mac_ctx, session_entry); + + /* Initialize 11h Enable Flag */ + if (CHAN_HOP_ALL_BANDS_ENABLE || + session_entry->limRFBand != REG_BAND_2G) + session_entry->lim11hEnable = + mac_ctx->mlme_cfg->gen.enabled_11h; + else + session_entry->lim11hEnable = 0; + + session_entry->dot11mode = ch_change_req->dot11mode; + session_entry->nwType = ch_change_req->nw_type; + qdf_mem_copy(&session_entry->rateSet, + &ch_change_req->opr_rates, + sizeof(session_entry->rateSet)); + qdf_mem_copy(&session_entry->extRateSet, + &ch_change_req->ext_rates, + sizeof(session_entry->extRateSet)); + lim_change_channel(mac_ctx, session_entry); + lim_check_conc_power_for_csa(mac_ctx, session_entry); + + lim_dump_session_info(mac_ctx, session_entry); + lim_dump_he_info(mac_ctx, session_entry); + lim_dump_eht_info(session_entry); +} + +/****************************************************************************** +* lim_start_bss_update_add_ie_buffer() +* +***FUNCTION: +* This function checks the src buffer and its length and then malloc for +* dst buffer update the same +* +***LOGIC: +* +***ASSUMPTIONS: +* +***NOTE: +* +* @param mac Pointer to Global MAC structure +* @param **pDstData_buff A pointer to pointer of uint8_t dst buffer +* @param *pDstDataLen A pointer to pointer of uint16_t dst buffer length +* @param *pSrcData_buff A pointer of uint8_t src buffer +* @param srcDataLen src buffer length +******************************************************************************/ + +static void +lim_start_bss_update_add_ie_buffer(struct mac_context *mac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (srcDataLen > 0 && pSrcData_buff) { + *pDstDataLen = srcDataLen; + + *pDstData_buff = qdf_mem_malloc(*pDstDataLen); + if (!*pDstData_buff) + return; + qdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + } else { + *pDstData_buff = NULL; + *pDstDataLen = 0; + } +} + +/****************************************************************************** +* lim_update_add_ie_buffer() +* +***FUNCTION: +* This function checks the src buffer and length if src buffer length more +* than dst buffer length then free the dst buffer and malloc for the new src +* length, and update the dst buffer and length. But if dst buffer is bigger +* than src buffer length then it just update the dst buffer and length +* +***LOGIC: +* +***ASSUMPTIONS: +* +***NOTE: +* +* @param mac Pointer to Global MAC structure +* @param **pDstData_buff A pointer to pointer of uint8_t dst buffer +* @param *pDstDataLen A pointer to pointer of uint16_t dst buffer length +* @param *pSrcData_buff A pointer of uint8_t src buffer +* @param srcDataLen src buffer length +******************************************************************************/ + +static void +lim_update_add_ie_buffer(struct mac_context *mac, + uint8_t **pDstData_buff, + uint16_t *pDstDataLen, + uint8_t *pSrcData_buff, uint16_t srcDataLen) +{ + + if (!pSrcData_buff) { + pe_err("src buffer is null"); + return; + } + + if (srcDataLen > *pDstDataLen) { + *pDstDataLen = srcDataLen; + /* free old buffer */ + qdf_mem_free(*pDstData_buff); + /* allocate a new */ + *pDstData_buff = qdf_mem_malloc(*pDstDataLen); + if (!*pDstData_buff) { + *pDstDataLen = 0; + return; + } + } + + /* copy the content of buffer into dst buffer + */ + *pDstDataLen = srcDataLen; + qdf_mem_copy(*pDstData_buff, pSrcData_buff, *pDstDataLen); + +} + +/* +* lim_process_modify_add_ies() - process modify additional IE req. +* +* @mac_ctx: Pointer to Global MAC structure +* @msg_buf: pointer to the SME message buffer +* +* This function update the PE buffers for additional IEs. +* +* Return: None +*/ +static void lim_process_modify_add_ies(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + tpSirModifyIEsInd modify_add_ies; + struct pe_session *session_entry; + uint8_t session_id; + bool ret = false; + struct add_ie_params *add_ie_params; + + if (!msg_buf) { + pe_err("msg_buf is NULL"); + return; + } + + modify_add_ies = (tpSirModifyIEsInd)msg_buf; + /* Incoming message has smeSession, use BSSID to find PE session */ + session_entry = pe_find_session_by_bssid(mac_ctx, + modify_add_ies->modifyIE.bssid.bytes, &session_id); + + if (!session_entry) { + pe_err("Session not found for given bssid" + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(modify_add_ies->modifyIE.bssid.bytes)); + goto end; + } + if ((0 == modify_add_ies->modifyIE.ieBufferlength) || + (0 == modify_add_ies->modifyIE.ieIDLen) || + (!modify_add_ies->modifyIE.pIEBuffer)) { + pe_err("Invalid request pIEBuffer %pK ieBufferlength %d ieIDLen %d ieID %d. update Type %d", + modify_add_ies->modifyIE.pIEBuffer, + modify_add_ies->modifyIE.ieBufferlength, + modify_add_ies->modifyIE.ieID, + modify_add_ies->modifyIE.ieIDLen, + modify_add_ies->updateType); + goto end; + } + add_ie_params = &session_entry->add_ie_params; + switch (modify_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + /* Probe resp */ + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + if (!add_ie_params->assocRespDataLen) + pe_err("assoc resp add ie not present"); + /* search through the buffer and modify the IE */ + break; + case eUPDATE_IE_PROBE_BCN: + /*probe beacon IE */ + if (ret == true && modify_add_ies->modifyIE.notify) { + lim_handle_param_update(mac_ctx, + modify_add_ies->updateType); + } + break; + default: + pe_err("unhandled buffer type %d", + modify_add_ies->updateType); + break; + } +end: + qdf_mem_free(modify_add_ies->modifyIE.pIEBuffer); + modify_add_ies->modifyIE.pIEBuffer = NULL; +} + +/* +* lim_process_update_add_ies() - process additional IE update req +* +* @mac_ctx: Pointer to Global MAC structure +* @msg_buf: pointer to the SME message buffer +* +* This function update the PE buffers for additional IEs. +* +* Return: None +*/ +static void lim_process_update_add_ies(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + tpSirUpdateIEsInd update_add_ies = (tpSirUpdateIEsInd)msg_buf; + uint8_t session_id; + struct pe_session *session_entry; + struct add_ie_params *addn_ie; + uint16_t new_length = 0; + uint8_t *new_ptr = NULL; + tSirUpdateIE *update_ie; + + if (!msg_buf) { + pe_err("msg_buf is NULL"); + return; + } + update_ie = &update_add_ies->updateIE; + /* incoming message has smeSession, use BSSID to find PE session */ + session_entry = pe_find_session_by_bssid(mac_ctx, + update_ie->bssid.bytes, &session_id); + + if (!session_entry) { + pe_debug("Session not found for given bssid" + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(update_ie->bssid.bytes)); + goto end; + } + addn_ie = &session_entry->add_ie_params; + /* if len is 0, upper layer requested freeing of buffer */ + if (0 == update_ie->ieBufferlength) { + switch (update_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + qdf_mem_free(addn_ie->probeRespData_buff); + addn_ie->probeRespData_buff = NULL; + addn_ie->probeRespDataLen = 0; + break; + case eUPDATE_IE_ASSOC_RESP: + qdf_mem_free(addn_ie->assocRespData_buff); + addn_ie->assocRespData_buff = NULL; + addn_ie->assocRespDataLen = 0; + break; + case eUPDATE_IE_PROBE_BCN: + qdf_mem_free(addn_ie->probeRespBCNData_buff); + addn_ie->probeRespBCNData_buff = NULL; + addn_ie->probeRespBCNDataLen = 0; + + if (update_ie->notify) + lim_handle_param_update(mac_ctx, + update_add_ies->updateType); + break; + default: + break; + } + return; + } + switch (update_add_ies->updateType) { + case eUPDATE_IE_PROBE_RESP: + if (update_ie->append) { + /* + * In case of append, allocate new memory + * with combined length. + * Multiple back to back append commands + * can lead to a huge length.So, check + * for the validity of the length. + */ + if (addn_ie->probeRespDataLen > + (USHRT_MAX - update_ie->ieBufferlength)) { + pe_err("IE Length overflow, curr:%d, new:%d", + addn_ie->probeRespDataLen, + update_ie->ieBufferlength); + goto end; + } + new_length = update_ie->ieBufferlength + + addn_ie->probeRespDataLen; + new_ptr = qdf_mem_malloc(new_length); + if (!new_ptr) + goto end; + /* append buffer to end of local buffers */ + qdf_mem_copy(new_ptr, addn_ie->probeRespData_buff, + addn_ie->probeRespDataLen); + qdf_mem_copy(&new_ptr[addn_ie->probeRespDataLen], + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + /* free old memory */ + qdf_mem_free(addn_ie->probeRespData_buff); + /* adjust length accordingly */ + addn_ie->probeRespDataLen = new_length; + /* save reference of local buffer in PE session */ + addn_ie->probeRespData_buff = new_ptr; + goto end; + } + lim_update_add_ie_buffer(mac_ctx, &addn_ie->probeRespData_buff, + &addn_ie->probeRespDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + break; + case eUPDATE_IE_ASSOC_RESP: + /* assoc resp IE */ + lim_update_add_ie_buffer(mac_ctx, &addn_ie->assocRespData_buff, + &addn_ie->assocRespDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + break; + case eUPDATE_IE_PROBE_BCN: + /* probe resp Bcn IE */ + lim_update_add_ie_buffer(mac_ctx, + &addn_ie->probeRespBCNData_buff, + &addn_ie->probeRespBCNDataLen, + update_ie->pAdditionIEBuffer, + update_ie->ieBufferlength); + if (update_ie->notify) + lim_handle_param_update(mac_ctx, + update_add_ies->updateType); + break; + default: + pe_err("unhandled buffer type %d", update_add_ies->updateType); + break; + } +end: + qdf_mem_free(update_ie->pAdditionIEBuffer); + update_ie->pAdditionIEBuffer = NULL; +} + +void send_extended_chan_switch_action_frame(struct mac_context *mac_ctx, + uint16_t new_channel_freq, + enum phy_ch_width ch_bandwidth, + struct pe_session *session_entry) +{ + uint8_t op_class = 0; + uint8_t switch_mode = 0, i; + tpDphHashNode psta; + uint8_t new_channel = 0; + enum phy_ch_width ch_width; + tLimChannelSwitchInfo *ch_switch = &session_entry->gLimChannelSwitch; + + op_class = + lim_op_class_from_bandwidth(mac_ctx, new_channel_freq, + ch_bandwidth, + ch_switch->sec_ch_offset); + new_channel = wlan_reg_freq_to_chan(mac_ctx->pdev, new_channel_freq); + if (LIM_IS_AP_ROLE(session_entry) && + (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false)) + switch_mode = ch_switch->switchMode; + + if (LIM_IS_AP_ROLE(session_entry)) { + for (i = 0; i <= mac_ctx->lim.max_sta_of_pe_session; i++) { + psta = + session_entry->dph.dphHashTable.pDphNodeArray + i; + if (!psta || !psta->added) + continue; + ch_width = lim_calculate_peer_ch_width(session_entry, + psta->staAddr, + ch_bandwidth); + op_class = lim_op_class_from_bandwidth(mac_ctx, + new_channel_freq, ch_width, + ch_switch->sec_ch_offset); + lim_send_extended_chan_switch_action_frame( + mac_ctx, psta->staAddr, + switch_mode, op_class, new_channel, + ch_switch->switchCount, session_entry); + } + } else if (LIM_IS_STA_ROLE(session_entry)) { + lim_send_extended_chan_switch_action_frame(mac_ctx, + session_entry->bssId, + switch_mode, op_class, new_channel, + ch_switch->switchCount, + session_entry); + } + +} + +void lim_send_chan_switch_action_frame(struct mac_context *mac_ctx, + uint16_t new_channel_freq, + enum phy_ch_width ch_bandwidth, + struct pe_session *session_entry) +{ + uint8_t op_class = 0, new_channel; + uint8_t switch_mode = 0, i; + uint8_t switch_count; + tpDphHashNode psta; + tpDphHashNode dph_node_array_ptr; + + dph_node_array_ptr = session_entry->dph.dphHashTable.pDphNodeArray; + op_class = + lim_op_class_from_bandwidth(mac_ctx, new_channel_freq, + ch_bandwidth, + session_entry->gLimChannelSwitch.sec_ch_offset); + new_channel = wlan_reg_freq_to_chan(mac_ctx->pdev, new_channel_freq); + + if (LIM_IS_AP_ROLE(session_entry) && + (false == mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch)) + switch_mode = session_entry->gLimChannelSwitch.switchMode; + + switch_count = session_entry->gLimChannelSwitch.switchCount; + + if (LIM_IS_AP_ROLE(session_entry)) { + for (i = 0; i <= mac_ctx->lim.max_sta_of_pe_session; i++) { + psta = dph_node_array_ptr + i; + if (!(psta && psta->added)) + continue; + if (session_entry->lim_non_ecsa_cap_num == 0) + lim_send_extended_chan_switch_action_frame + (mac_ctx, psta->staAddr, switch_mode, + op_class, new_channel, switch_count, + session_entry); + else + lim_send_channel_switch_mgmt_frame + (mac_ctx, psta->staAddr, switch_mode, + new_channel, switch_count, + session_entry); + } + } else if (LIM_IS_STA_ROLE(session_entry)) { + lim_send_extended_chan_switch_action_frame + (mac_ctx, session_entry->bssId, switch_mode, op_class, + new_channel, switch_count, session_entry); + } +} + +/** + * lim_process_sme_dfs_csa_ie_request() - process sme dfs csa ie req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_sme_dfs_csa_ie_request(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + tpSirDfsCsaIeRequest dfs_csa_ie_req; + struct pe_session *session_entry = NULL; + uint8_t session_id; + tLimWiderBWChannelSwitchInfo *wider_bw_ch_switch; + QDF_STATUS status; + enum phy_ch_width ch_width; + uint32_t target_ch_freq; + bool is_vdev_ll_lt_sap = false; + uint8_t peer_count; + uint16_t max_wait_for_bcn_tx_complete; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + dfs_csa_ie_req = (tSirDfsCsaIeRequest *)msg_buf; + session_entry = pe_find_session_by_bssid(mac_ctx, + dfs_csa_ie_req->bssid, &session_id); + if (!session_entry) { + pe_err("Session not found for given BSSID" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(dfs_csa_ie_req->bssid)); + return; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + pe_err("Invalid SystemRole %d", + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + /* target channel */ + session_entry->gLimChannelSwitch.primaryChannel = + wlan_reg_freq_to_chan(mac_ctx->pdev, + dfs_csa_ie_req->target_chan_freq); + session_entry->gLimChannelSwitch.sw_target_freq = + dfs_csa_ie_req->target_chan_freq; + target_ch_freq = dfs_csa_ie_req->target_chan_freq; + /* Channel switch announcement needs to be included in beacon */ + session_entry->dfsIncludeChanSwIe = true; + + wlan_reg_set_create_punc_bitmap(&dfs_csa_ie_req->ch_params, false); + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + dfs_csa_ie_req->target_chan_freq, + 0, + &dfs_csa_ie_req->ch_params, + REG_CURRENT_PWR_MODE); + + ch_width = dfs_csa_ie_req->ch_params.ch_width; + if (ch_width >= CH_WIDTH_160MHZ && + wma_get_vht_ch_width() < WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + ch_width = CH_WIDTH_80MHZ; + } + session_entry->gLimChannelSwitch.ch_width = ch_width; + session_entry->gLimChannelSwitch.sec_ch_offset = + dfs_csa_ie_req->ch_params.sec_ch_offset; + + is_vdev_ll_lt_sap = policy_mgr_is_vdev_ll_lt_sap( + mac_ctx->psoc, + session_entry->vdev_id); + + if (is_vdev_ll_lt_sap) { + session_entry->gLimChannelSwitch.switchCount = 1; + session_entry->gLimChannelSwitch.switchMode = 0; + } else { + session_entry->gLimChannelSwitch.switchCount = + dfs_csa_ie_req->ch_switch_beacon_cnt; + if (!mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch) + session_entry->gLimChannelSwitch.switchMode = + dfs_csa_ie_req->ch_switch_mode; + } + + /* + * Validate if SAP is operating HT or VHT/HE mode and set the Channel + * Switch Wrapper element with the Wide Band Switch subelement. + */ + if (!(session_entry->vhtCapability || + lim_is_session_he_capable(session_entry))) + goto skip_vht; + + /* Now encode the Wider Ch BW element depending on the ch width */ + wider_bw_ch_switch = &session_entry->gLimWiderBWChannelSwitch; + switch (ch_width) { + case CH_WIDTH_20MHZ: + /* + * Wide channel BW sublement in channel wrapper element is not + * required in case of 20 Mhz operation. Currently It is set + * only set in case of 40/80 Mhz Operation. + */ + session_entry->dfsIncludeChanWrapperIe = false; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + break; + case CH_WIDTH_40MHZ: + session_entry->dfsIncludeChanWrapperIe = false; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + break; + case CH_WIDTH_80MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + break; + case CH_WIDTH_160MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + break; + case CH_WIDTH_80P80MHZ: + session_entry->dfsIncludeChanWrapperIe = true; + wider_bw_ch_switch->newChanWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + /* + * This is not applicable for 20/40/80 Mhz. + * Only used when we support 80+80 Mhz operation. + * In case of 80+80 Mhz, this parameter indicates + * center channel frequency index of 80 Mhz channel of + * frequency segment 1. + */ + wider_bw_ch_switch->newCenterChanFreq1 = + dfs_csa_ie_req->ch_params.center_freq_seg1; + break; + default: + session_entry->dfsIncludeChanWrapperIe = false; + /* + * Need to handle 80+80 Mhz Scenario. When 80+80 is supported + * set the gLimWiderBWChannelSwitch.newChanWidth to 3 + */ + pe_err("Invalid Channel Width"); + break; + } + /* Fetch the center channel based on the channel width */ + wider_bw_ch_switch->newCenterChanFreq0 = + dfs_csa_ie_req->ch_params.center_freq_seg0; +skip_vht: + + /* Take a wakelock for CSA for 5 seconds and release in vdev start */ + + qdf_wake_lock_timeout_acquire(&session_entry->ap_ecsa_wakelock, + MAX_WAKELOCK_FOR_CSA); + qdf_runtime_pm_prevent_suspend(&session_entry->ap_ecsa_runtime_lock); + + session_entry->cac_duration_ms = dfs_csa_ie_req->new_chan_cac_ms; + wlan_util_vdev_mgr_set_cac_timeout_for_vdev( + session_entry->vdev, dfs_csa_ie_req->new_chan_cac_ms); + + peer_count = wlan_vdev_get_peer_sta_count(session_entry->vdev); + + if (is_vdev_ll_lt_sap && !peer_count) { + pe_debug("Peer count is 0 for LL_LT_SAP, continue CSA directly"); + /* initiate vdev restart if no peer connected on XPAN */ + lim_send_csa_tx_complete(session_entry->vdev_id); + /* Clear CSA IE count and update beacon */ + lim_send_dfs_chan_sw_ie_update(mac_ctx, session_entry); + return; + } + + /* Send CSA IE request from here */ + lim_send_dfs_chan_sw_ie_update(mac_ctx, session_entry); + + /* + * Wait for max_wait_for_bcn_tx_complete ms for tx complete for beacon. + * If tx complete for beacon is received before this timer expire, + * stop this timer and then this will be restarted for every beacon + * interval until switchCount become 0 and bcn template with new + * switchCount will be sent to firmware. + * OR + * If no tx complete for beacon is received till this timer expire + * this will be restarted for every beacon interval until switchCount + * become 0 and bcn template with new switchCount will be sent to + * firmware. + */ + if (is_vdev_ll_lt_sap) + max_wait_for_bcn_tx_complete = MAX_WAIT_FOR_BCN_TX_COMPLETE_FOR_LL_SAP; + else + max_wait_for_bcn_tx_complete = MAX_WAIT_FOR_BCN_TX_COMPLETE; + + status = qdf_mc_timer_start(&session_entry->ap_ecsa_timer, + max_wait_for_bcn_tx_complete); + + if (QDF_IS_STATUS_ERROR(status)) + pe_err("cannot start ap_ecsa_timer"); + + lim_cp_stats_cstats_log_csa_evt( + session_entry, CSTATS_DIR_TX, + session_entry->gLimChannelSwitch.sw_target_freq, + session_entry->gLimChannelSwitch.ch_width, + session_entry->gLimChannelSwitch.switchMode); + + pe_debug("IE count:%d chan:%d freq %d width:%d wrapper:%d ch_offset:%d", + session_entry->gLimChannelSwitch.switchCount, + session_entry->gLimChannelSwitch.primaryChannel, + session_entry->gLimChannelSwitch.sw_target_freq, + session_entry->gLimChannelSwitch.ch_width, + session_entry->dfsIncludeChanWrapperIe, + session_entry->gLimChannelSwitch.sec_ch_offset); + + /* + * Send ECSA/CSA Action frame after updating the beacon. + * For LL_LT_SAP, send ECSA action frame only + */ + if (CHAN_HOP_ALL_BANDS_ENABLE && + session_entry->lim_non_ecsa_cap_num && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(target_ch_freq) && + !is_vdev_ll_lt_sap) + lim_send_chan_switch_action_frame + (mac_ctx, + session_entry->gLimChannelSwitch.primaryChannel, + ch_width, session_entry); + else + send_extended_chan_switch_action_frame + (mac_ctx, target_ch_freq, ch_width, + session_entry); +} + +/** + * lim_process_ext_change_channel()- function to send ECSA + * action frame for STA/CLI . + * @mac_ctx: pointer to global mac structure + * @msg: params from sme for new channel. + * + * This function is called to send ECSA frame for STA/CLI. + * + * Return: void + */ + +static void lim_process_ext_change_channel(struct mac_context *mac_ctx, + uint32_t *msg) +{ + struct sir_sme_ext_cng_chan_req *ext_chng_channel = + (struct sir_sme_ext_cng_chan_req *) msg; + struct pe_session *session_entry = NULL; + + if (!msg) { + pe_err("Buffer is Pointing to NULL"); + return; + } + session_entry = + pe_find_session_by_vdev_id(mac_ctx, ext_chng_channel->vdev_id); + if (!session_entry) { + pe_err("Session not found for given vdev_id %d", + ext_chng_channel->vdev_id); + return; + } + if (LIM_IS_AP_ROLE(session_entry)) { + pe_err("not an STA/CLI session"); + return; + } + session_entry->gLimChannelSwitch.sec_ch_offset = 0; + send_extended_chan_switch_action_frame(mac_ctx, + ext_chng_channel->new_ch_freq, 0, + session_entry); +} + +/** + * lim_process_nss_update_request() - process sme nss update req + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_nss_update_request(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_nss_update_request *nss_update_req_ptr; + struct pe_session *session_entry = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t vdev_id; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + nss_update_req_ptr = (struct sir_nss_update_request *)msg_buf; + vdev_id = nss_update_req_ptr->vdev_id; + session_entry = pe_find_session_by_vdev_id(mac_ctx, + nss_update_req_ptr->vdev_id); + if (!session_entry) { + pe_err("Session not found for given session_id %d", + nss_update_req_ptr->vdev_id); + goto end; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + pe_err("Invalid SystemRole %d", + GET_LIM_SYSTEM_ROLE(session_entry)); + goto end; + } + + /* populate nss field in the beacon */ + session_entry->gLimOperatingMode.present = 1; + session_entry->gLimOperatingMode.rxNSS = nss_update_req_ptr->new_nss; + session_entry->gLimOperatingMode.chanWidth = session_entry->ch_width; + + if ((nss_update_req_ptr->new_nss == NSS_1x1_MODE) && + (session_entry->ch_width > CH_WIDTH_80MHZ)) + session_entry->gLimOperatingMode.chanWidth = CH_WIDTH_80MHZ; + if (session_entry->gLimOperatingMode.chanWidth <= CH_WIDTH_160MHZ && + nss_update_req_ptr->ch_width < + session_entry->gLimOperatingMode.chanWidth) + session_entry->gLimOperatingMode.chanWidth = + nss_update_req_ptr->ch_width; + + pe_debug("ch width %d Rx NSS %d", + session_entry->gLimOperatingMode.chanWidth, + session_entry->gLimOperatingMode.rxNSS); + + /* Send nss update request from here */ + status = sch_set_fixed_beacon_fields(mac_ctx, session_entry); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Unable to set op mode IE in beacon"); + goto end; + } + + status = lim_send_beacon_ind(mac_ctx, session_entry, REASON_NSS_UPDATE); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + pe_err("Unable to send beacon"); +end: + /* + * send resp only in case of failure, + * success case response will be from wma. + */ + lim_nss_or_ch_width_update_rsp(mac_ctx, vdev_id, status, + REASON_NSS_UPDATE); +} + +/** + * lim_process_set_ie_req() - process sme set IE request + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: pointer to the SME message buffer + * + * This function processes SME request messages from HDD or upper layer + * application. + * + * Return: None + */ +static void lim_process_set_ie_req(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + struct send_extcap_ie *msg; + QDF_STATUS status; + tDot11fIEExtCap extra_ext_cap = {0}; + uint16_t vdev_id; + struct wlan_objmgr_vdev *vdev = NULL; + struct mlme_legacy_priv *mlme_priv; + struct s_ext_cap *p_ext_cap; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + msg = (struct send_extcap_ie *)msg_buf; + vdev_id = msg->session_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + + if (!mlme_priv->connect_info.ext_cap_ie[0]) + goto send_ie; + + lim_update_extcap_struct(mac_ctx, + mlme_priv->connect_info.ext_cap_ie, + &extra_ext_cap); + p_ext_cap = (struct s_ext_cap *)extra_ext_cap.bytes; + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extra_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length(&extra_ext_cap); +send_ie: + status = lim_send_ext_cap_ie(mac_ctx, msg->session_id, &extra_ext_cap, + true); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Unable to send ExtCap to FW"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR + +/** + * obss_color_collision_process_color_disable() - Disable bss color + * @mac_ctx: Pointer to Global MAC structure + * @session: pointer to session + * + * This function will disable bss color. + * + * Return: None + */ +static void obss_color_collision_process_color_disable(struct mac_context *mac_ctx, + struct pe_session *session) +{ + tUpdateBeaconParams beacon_params; + + if (!session) { + pe_err("Invalid session"); + return; + } + + if (session->valid && !LIM_IS_AP_ROLE(session)) { + pe_err("Invalid SystemRole %d", + GET_LIM_SYSTEM_ROLE(session)); + return; + } + + if (session->bss_color_changing == 1) { + pe_warn("%d: color change in progress", session->smeSessionId); + /* Continue color collision detection */ + lim_send_obss_color_collision_cfg(mac_ctx, session, + OBSS_COLOR_COLLISION_DETECTION); + return; + } + + if (session->he_op.bss_col_disabled == 1) { + pe_warn("%d: bss color already disabled", + session->smeSessionId); + /* Continue free color detection */ + lim_send_obss_color_collision_cfg(mac_ctx, session, + OBSS_COLOR_FREE_SLOT_AVAILABLE); + return; + } + + qdf_mem_zero(&beacon_params, sizeof(beacon_params)); + beacon_params.paramChangeBitmap |= PARAM_BSS_COLOR_CHANGED; + session->he_op.bss_col_disabled = 1; + beacon_params.bss_color_disabled = 1; + beacon_params.bss_color = session->he_op.bss_color; + + if (sch_set_fixed_beacon_fields(mac_ctx, session) != + QDF_STATUS_SUCCESS) { + pe_err("Unable to set op mode IE in beacon"); + return; + } + + lim_send_beacon_params(mac_ctx, &beacon_params, session); + lim_send_obss_color_collision_cfg(mac_ctx, session, + OBSS_COLOR_FREE_SLOT_AVAILABLE); +} + +/** + * obss_color_collision_process_color_change() - Process bss color change + * @mac_ctx: Pointer to Global MAC structure + * @session: pointer to session + * @obss_color_info: obss color collision/free slot indication info + * + * This function selects new color ib case of bss color collision. + * + * Return: None + */ +static void obss_color_collision_process_color_change(struct mac_context *mac_ctx, + struct pe_session *session, + struct wmi_obss_color_collision_info *obss_color_info) +{ + int i, num_bss_color = 0; + uint32_t bss_color_bitmap; + uint8_t bss_color_index_array[MAX_BSS_COLOR_VALUE]; + uint32_t rand_byte = 0; + struct sir_set_he_bss_color he_bss_color; + bool is_color_collision = false; + + + if (session->bss_color_changing == 1) { + pe_err("%d: color change in progress", session->smeSessionId); + return; + } + + if (!session->he_op.bss_col_disabled) { + if (session->he_op.bss_color < 32) + is_color_collision = (obss_color_info-> + obss_color_bitmap_bit0to31 >> + session->he_op.bss_color) & 0x01; + else + is_color_collision = (obss_color_info-> + obss_color_bitmap_bit32to63 >> + (session->he_op.bss_color - + 32)) & 0x01; + if (!is_color_collision) { + pe_err("%d: color collision not found, curr_color: %d", + session->smeSessionId, + session->he_op.bss_color); + return; + } + } + + bss_color_bitmap = obss_color_info->obss_color_bitmap_bit0to31; + + /* Skip color zero */ + bss_color_bitmap = bss_color_bitmap >> 1; + for (i = 0; (i < 31) && (num_bss_color < MAX_BSS_COLOR_VALUE); i++) { + if (!(bss_color_bitmap & 0x01)) { + bss_color_index_array[num_bss_color] = i + 1; + num_bss_color++; + } + bss_color_bitmap = bss_color_bitmap >> 1; + } + + bss_color_bitmap = obss_color_info->obss_color_bitmap_bit32to63; + for (i = 0; (i < 32) && (num_bss_color < MAX_BSS_COLOR_VALUE); i++) { + if (!(bss_color_bitmap & 0x01)) { + bss_color_index_array[num_bss_color] = i + 32; + num_bss_color++; + } + bss_color_bitmap = bss_color_bitmap >> 1; + } + + if (num_bss_color) { + qdf_get_random_bytes((void *) &rand_byte, 1); + i = (rand_byte + qdf_mc_timer_get_system_ticks()) % + num_bss_color; + pe_debug("New bss color = %d", bss_color_index_array[i]); + he_bss_color.vdev_id = obss_color_info->vdev_id; + he_bss_color.bss_color = bss_color_index_array[i]; + + /* Take the wakelock for 2 sec, release it after color change */ + wma_prevent_suspend_on_obss_color_collision(session->vdev); + + lim_process_set_he_bss_color(mac_ctx, + (uint32_t *)&he_bss_color); + } else { + pe_err("Unable to find bss color from bitmasp"); + if (obss_color_info->evt_type == + OBSS_COLOR_FREE_SLOT_TIMER_EXPIRY && + session->obss_color_collision_dec_evt == + OBSS_COLOR_FREE_SLOT_TIMER_EXPIRY) + /* In dot11BSSColorCollisionAPPeriod and + * timer expired, time to disable bss color. + */ + obss_color_collision_process_color_disable(mac_ctx, + session); + else + /* + * Enter dot11BSSColorCollisionAPPeriod period. + */ + lim_send_obss_color_collision_cfg(mac_ctx, session, + OBSS_COLOR_FREE_SLOT_TIMER_EXPIRY); + } +} + +void lim_process_set_he_bss_color(struct mac_context *mac_ctx, uint32_t *msg_buf) +{ + struct sir_set_he_bss_color *bss_color; + struct pe_session *session_entry = NULL; + tUpdateBeaconParams beacon_params; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + bss_color = (struct sir_set_he_bss_color *)msg_buf; + session_entry = pe_find_session_by_vdev_id(mac_ctx, bss_color->vdev_id); + if (!session_entry) { + pe_err("Session not found for given vdev_id %d", + bss_color->vdev_id); + return; + } + + if (session_entry->valid && !LIM_IS_AP_ROLE(session_entry)) { + pe_err("Invalid SystemRole %d", + GET_LIM_SYSTEM_ROLE(session_entry)); + return; + } + + if (bss_color->bss_color == session_entry->he_op.bss_color) { + pe_err("No change in BSS color, current BSS color %d", + bss_color->bss_color); + return; + } + qdf_mem_zero(&beacon_params, sizeof(beacon_params)); + beacon_params.paramChangeBitmap |= PARAM_BSS_COLOR_CHANGED; + session_entry->he_op.bss_col_disabled = 1; + session_entry->he_bss_color_change.countdown = + BSS_COLOR_SWITCH_COUNTDOWN; + session_entry->he_bss_color_change.new_color = bss_color->bss_color; + beacon_params.bss_color_disabled = 1; + beacon_params.bss_color = session_entry->he_op.bss_color; + session_entry->bss_color_changing = 1; + + if (wlan_vdev_mlme_get_he_spr_enabled(session_entry->vdev)) + /* Disable spatial reuse during BSS color change */ + wlan_spatial_reuse_config_set(session_entry->vdev, 0, 0); + + if (sch_set_fixed_beacon_fields(mac_ctx, session_entry) != + QDF_STATUS_SUCCESS) { + pe_err("Unable to set op mode IE in beacon"); + return; + } + + lim_send_beacon_params(mac_ctx, &beacon_params, session_entry); + lim_send_obss_color_collision_cfg(mac_ctx, session_entry, + OBSS_COLOR_COLLISION_DETECTION_DISABLE); +} + +void lim_reconfig_obss_scan_param(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct sir_cfg_obss_scan *obss_scan_param; + struct pe_session *session = NULL; + struct wmi_obss_color_collision_cfg_param *cfg_param; + struct scheduler_msg msg = {0}; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + obss_scan_param = (struct sir_cfg_obss_scan *)msg_buf; + session = pe_find_session_by_vdev_id(mac_ctx, obss_scan_param->vdev_id); + if (!session) { + pe_err("Session not found for given vdev_id %d", + obss_scan_param->vdev_id); + return; + } + + if (!session->he_capable || + !session->is_session_obss_color_collision_det_enabled || + session->obss_color_collision_dec_evt == + OBSS_COLOR_COLLISION_DETECTION_DISABLE) { + pe_debug("%d: obss color det not enabled, he_cap:%d, sup:%d:%d event_type:%d", + session->smeSessionId, session->he_capable, + session->is_session_obss_color_collision_det_enabled, + mac_ctx->mlme_cfg->obss_ht40.obss_color_collision_offload_enabled, + session->obss_color_collision_dec_evt); + return; + } + + cfg_param = qdf_mem_malloc(sizeof(*cfg_param)); + if (!cfg_param) + return; + + pe_debug("vdev_id %d: sending event:%d scan_reconfig:%d", + session->smeSessionId, session->obss_color_collision_dec_evt, + obss_scan_param->is_scan_reconfig); + cfg_param->vdev_id = session->smeSessionId; + cfg_param->evt_type = session->obss_color_collision_dec_evt; + cfg_param->current_bss_color = session->he_op.bss_color; + + if (obss_scan_param->is_scan_reconfig) + cfg_param->detection_period_ms = + OBSS_COLOR_COLLISION_DETECTION_NDP_PERIOD_MS; + else + cfg_param->detection_period_ms = + OBSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS; + cfg_param->scan_period_ms = OBSS_COLOR_COLLISION_SCAN_PERIOD_MS; + + if (session->obss_color_collision_dec_evt == + OBSS_COLOR_FREE_SLOT_TIMER_EXPIRY) + cfg_param->free_slot_expiry_time_ms = + OBSS_COLOR_COLLISION_FREE_SLOT_EXPIRY_MS; + + msg.type = WMA_OBSS_COLOR_COLLISION_REQ; + msg.bodyptr = cfg_param; + msg.reserved = 0; + + if (QDF_IS_STATUS_ERROR(scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + qdf_mem_free(cfg_param); + } +} + +void lim_send_obss_color_collision_cfg(struct mac_context *mac_ctx, + struct pe_session *session, + enum wmi_obss_color_collision_evt_type + event_type) +{ + struct wmi_obss_color_collision_cfg_param *cfg_param; + struct scheduler_msg msg = {0}; + + if (!session) { + pe_err("Invalid session"); + return; + } + + if (!session->he_capable || + !session->is_session_obss_color_collision_det_enabled) { + pe_debug("%d: obss color det not enabled, he_cap:%d, sup:%d:%d", + session->smeSessionId, session->he_capable, + session->is_session_obss_color_collision_det_enabled, + mac_ctx->mlme_cfg->obss_ht40. + obss_color_collision_offload_enabled); + return; + } + + cfg_param = qdf_mem_malloc(sizeof(*cfg_param)); + if (!cfg_param) + return; + + pe_debug("%d: sending event:%d", session->smeSessionId, event_type); + qdf_mem_zero(cfg_param, sizeof(*cfg_param)); + cfg_param->vdev_id = session->smeSessionId; + cfg_param->evt_type = event_type; + cfg_param->current_bss_color = session->he_op.bss_color; + if (LIM_IS_AP_ROLE(session)) + cfg_param->detection_period_ms = + OBSS_COLOR_COLLISION_DETECTION_AP_PERIOD_MS; + else + cfg_param->detection_period_ms = + OBSS_COLOR_COLLISION_DETECTION_STA_PERIOD_MS; + + cfg_param->scan_period_ms = OBSS_COLOR_COLLISION_SCAN_PERIOD_MS; + if (event_type == OBSS_COLOR_FREE_SLOT_TIMER_EXPIRY) + cfg_param->free_slot_expiry_time_ms = + OBSS_COLOR_COLLISION_FREE_SLOT_EXPIRY_MS; + + msg.type = WMA_OBSS_COLOR_COLLISION_REQ; + msg.bodyptr = cfg_param; + msg.reserved = 0; + + if (QDF_IS_STATUS_ERROR(scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + qdf_mem_free(cfg_param); + } else { + session->obss_color_collision_dec_evt = event_type; + } +} + +void lim_process_obss_color_collision_info(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ + struct wmi_obss_color_collision_info *obss_color_info; + struct pe_session *session; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + obss_color_info = (struct wmi_obss_color_collision_info *)msg_buf; + session = pe_find_session_by_vdev_id(mac_ctx, obss_color_info->vdev_id); + if (!session) { + pe_err("Session not found for given session_id %d", + obss_color_info->vdev_id); + return; + } + + pe_debug("vdev_id:%d, evt:%d:%d, 0to31:0x%x, 32to63:0x%x, cap:%d:%d:%d", + obss_color_info->vdev_id, + obss_color_info->evt_type, + session->obss_color_collision_dec_evt, + obss_color_info->obss_color_bitmap_bit0to31, + obss_color_info->obss_color_bitmap_bit32to63, + session->he_capable, + session->is_session_obss_color_collision_det_enabled, + mac_ctx->mlme_cfg->obss_ht40. + obss_color_collision_offload_enabled); + + if (!session->he_capable || + !session->is_session_obss_color_collision_det_enabled) { + return; + } + + switch (obss_color_info->evt_type) { + case OBSS_COLOR_COLLISION_DETECTION_DISABLE: + pe_err("%d: FW disabled obss color det. he_cap:%d, sup:%d:%d", + session->smeSessionId, session->he_capable, + session->is_session_obss_color_collision_det_enabled, + mac_ctx->mlme_cfg->obss_ht40. + obss_color_collision_offload_enabled); + session->is_session_obss_color_collision_det_enabled = false; + return; + case OBSS_COLOR_FREE_SLOT_AVAILABLE: + case OBSS_COLOR_COLLISION_DETECTION: + case OBSS_COLOR_FREE_SLOT_TIMER_EXPIRY: + if (session->valid && !LIM_IS_AP_ROLE(session)) { + pe_debug("Invalid System Role %d", + GET_LIM_SYSTEM_ROLE(session)); + return; + } + + if (session->obss_color_collision_dec_evt != + obss_color_info->evt_type) { + pe_debug("%d: Wrong event: %d, skipping", + obss_color_info->vdev_id, + obss_color_info->evt_type); + return; + } + obss_color_collision_process_color_change(mac_ctx, session, + obss_color_info); + break; + default: + pe_err("%d: Invalid event type %d", + obss_color_info->vdev_id, obss_color_info->evt_type); + return; + } +} +#endif + +void lim_send_csa_restart_req(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + struct pe_session *session; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("session not found for vdev id %d", vdev_id); + return; + } + + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_CSA_RESTART, + sizeof(*session), session); +} + +void lim_continue_sta_csa_req(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + pe_info("Continue CSA for STA vdev id %d", vdev_id); + lim_process_channel_switch(mac_ctx, vdev_id); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c new file mode 100644 index 0000000000..3fe9c20b12 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c @@ -0,0 +1,4536 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=========================================================================== + * lim_process_tdls.c + * OVERVIEW: + * + * DEPENDENCIES: + * + * Are listed for each API below. + * ===========================================================================*/ + +/*=========================================================================== + + * EDIT HISTORY FOR FILE + + * This section contains comments describing changes made to the module. + * Notice that changes are listed in reverse chronological order. + + * $Header$$DateTime$$Author$ + + * when who what, where, why + * ---------- --- ------------------------------------------------------ + * 05/05/2010 Ashwani Initial Creation, added TDLS action frame + * functionality,TDLS message exchange with SME..etc.. + + ===========================================================================*/ + +/** + * \file lim_process_tdls.c + * + * \brief Code for preparing,processing and sending 802.11z action frames + * + */ + +#ifdef FEATURE_WLAN_TDLS + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "dot11f.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "utils_parser.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "dph_hash_table.h" +#include "wma_types.h" +#include "cds_regdomain.h" +#include "cds_utils.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_reg_services_api.h" +#include "wlan_tdls_tgt_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_api.h" +#include "wlan_tdls_public_structs.h" +#include "wlan_cfg80211_tdls.h" +#include "wlan_tdls_api.h" +#include "lim_mlo.h" +#include "wlan_mlo_mgr_link_switch.h" + +/* define NO_PAD_TDLS_MIN_8023_SIZE to NOT padding: See CR#447630 + There was IOT issue with cisco 1252 open mode, where it pads + discovery req/teardown frame with some junk value up to min size. + To avoid this issue, we pad QCOM_VENDOR_IE. + If there is other IOT issue because of this bandage, define NO_PAD... + */ +#ifndef NO_PAD_TDLS_MIN_8023_SIZE +#define MIN_IEEE_8023_SIZE 46 +#define MIN_VENDOR_SPECIFIC_IE_SIZE 5 +#endif + +/* + * TDLS data frames will go out/come in as non-qos data. + * so, eth_890d_header will be aligned access.. + */ +static const uint8_t eth_890d_header[] = { + 0xaa, 0xaa, 0x03, 0x00, + 0x00, 0x00, 0x89, 0x0d, +}; + +#define ETH_ADDR_LEN 6 /* bytes */ + +struct tdls_ethernet_hdr { + uint8_t dest_addr[ETH_ADDR_LEN]; + uint8_t src_addr[ETH_ADDR_LEN]; +} qdf_packed; + +#define eth_890d_hdr_len 2 /* bytes */ + +static const uint8_t eth_890d_tdls_discvory_frm_hdr[] = { + 0x89, 0x0d, 0x02, 0x0c, 0x0a, +}; + +#define TDLS_ETHR_HDR_LEN (sizeof(struct tdls_ethernet_hdr)) + +/* + * type of links used in TDLS + */ +enum tdlsLinks { + TDLS_LINK_AP, + TDLS_LINK_DIRECT +} e_tdls_link; + +enum tdlsReqType { + TDLS_INITIATOR, + TDLS_RESPONDER +} e_tdls_req_type; + +typedef enum tdlsLinkSetupStatus { + TDLS_SETUP_STATUS_SUCCESS = 0, + TDLS_SETUP_STATUS_FAILURE = 37 +} etdlsLinkSetupStatus; + +/* These maps to Kernel TDLS peer capability + * flags and should get changed as and when necessary + */ +enum tdls_peer_capability { + TDLS_PEER_HT_CAP = 0, + TDLS_PEER_VHT_CAP = 1, + TDLS_PEER_WMM_CAP = 2, + TDLS_PEER_HE_CAP = 3 +} e_tdls_peer_capability; + +#define LINK_IDEN_ADDR_OFFSET(x) (&(x)->LinkIdentifier) + +/* TODO, Move this parameters to configuration */ +#define PEER_PSM_SUPPORT (0) +#define TDLS_SUPPORT (1) +#define TDLS_PROHIBITED (0) +#define TDLS_CH_SWITCH_PROHIBITED (1) +/** @brief Set bit manipulation macro */ +#define SET_BIT(value, mask) ((value) |= (1 << (mask))) +/** @brief Clear bit manipulation macro */ +#define CLEAR_BIT(value, mask) ((value) &= ~(1 << (mask))) +/** @brief Check bit manipulation macro */ +#define CHECK_BIT(value, mask) ((value) & (1 << (mask))) + +#define SET_PEER_AID_BITMAP(peer_bitmap, aid) \ + do { \ + if ((aid) < (sizeof(uint32_t) << 3)) \ + SET_BIT(peer_bitmap[0], (aid)); \ + else if ((aid) < (sizeof(uint32_t) << 4)) \ + SET_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ + } while (0); + +#define CLEAR_PEER_AID_BITMAP(peer_bitmap, aid) \ + do { \ + if ((aid) < (sizeof(uint32_t) << 3)) \ + CLEAR_BIT(peer_bitmap[0], (aid)); \ + else if ((aid) < (sizeof(uint32_t) << 4)) \ + CLEAR_BIT(peer_bitmap[1], ((aid) - (sizeof(uint32_t) << 3)));\ + } while (0); + +#define IS_QOS_ENABLED(pe_session) ((((pe_session)->limQosEnabled) && \ + SIR_MAC_GET_QOS((pe_session)->limCurrentBssCaps)) || \ + (((pe_session)->limWmeEnabled) && \ + LIM_BSS_CAPS_GET(WME, (pe_session)->limCurrentBssQosCaps))) + +#define TID_AC_VI 4 +#define TID_AC_BK 1 + +static const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) +{ + switch (tdlsActionCode) { + CASE_RETURN_STRING(TDLS_SETUP_REQUEST); + CASE_RETURN_STRING(TDLS_SETUP_RESPONSE); + CASE_RETURN_STRING(TDLS_SETUP_CONFIRM); + CASE_RETURN_STRING(TDLS_TEARDOWN); + CASE_RETURN_STRING(TDLS_PEER_TRAFFIC_INDICATION); + CASE_RETURN_STRING(TDLS_CHANNEL_SWITCH_REQUEST); + CASE_RETURN_STRING(TDLS_CHANNEL_SWITCH_RESPONSE); + CASE_RETURN_STRING(TDLS_PEER_TRAFFIC_RESPONSE); + CASE_RETURN_STRING(TDLS_DISCOVERY_REQUEST); + CASE_RETURN_STRING(TDLS_DISCOVERY_RESPONSE); + } + return (const uint8_t *)"UNKNOWN"; +} + +/* + * initialize TDLS setup list and related data structures. + */ +void lim_init_tdls_data(struct mac_context *mac, struct pe_session *pe_session) +{ + lim_init_peer_idxpool(mac, pe_session); + + return; +} + +static bool +is_duplicate_chan(uint8_t *arr, uint8_t index, uint8_t ch_id) +{ + int i; + + for (i = 0; i < index; i++) { + if (arr[i] == ch_id) + return true; + } + return false; +} + +static void populate_dot11f_tdls_offchannel_params( + struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIESuppChannels *suppChannels, + tDot11fIESuppOperatingClasses *suppOperClasses) +{ + uint32_t numChans = CFG_VALID_CHANNEL_LIST_LEN; + uint8_t validChan[CFG_VALID_CHANNEL_LIST_LEN]; + uint8_t i, count_opclss = 1; + uint8_t valid_count = 0; + uint8_t chanOffset; + uint8_t op_class; + uint8_t numClasses; + uint8_t classes[REG_MAX_SUPP_OPER_CLASSES]; + uint32_t band; + uint8_t nss_2g; + uint8_t nss_5g; + qdf_freq_t ch_freq; + bool is_vlp_country; + uint8_t ap_cc[REG_ALPHA2_LEN + 1]; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + numChans = mac->mlme_cfg->reg.valid_channel_list_num; + + if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) + band = BAND_2G; + else + band = BAND_5G; + + nss_5g = QDF_MIN(mac->vdev_type_nss_5g.tdls, + mac->user_configured_nss); + nss_2g = QDF_MIN(mac->vdev_type_nss_2g.tdls, + mac->user_configured_nss); + + wlan_cm_get_country_code(mac->pdev, pe_session->vdev_id, ap_cc); + wlan_reg_read_current_country(mac->psoc, reg_cc); + is_vlp_country = wlan_reg_ctry_support_vlp(ap_cc) && + wlan_reg_ctry_support_vlp(reg_cc); + + /* validating the channel list for DFS and 2G channels */ + for (i = 0; i < numChans; i++) { + ch_freq = mac->mlme_cfg->reg.valid_channel_freq_list[i]; + + validChan[i] = wlan_reg_freq_to_chan(mac->pdev, + mac->mlme_cfg->reg.valid_channel_freq_list[i]); + + if (is_duplicate_chan(validChan, i, validChan[i])) + continue; + + if ((band == BAND_5G) && + (NSS_2x2_MODE == nss_5g) && + (NSS_1x1_MODE == nss_2g) && + (wlan_reg_is_dfs_for_freq(mac->pdev, ch_freq))) { + pe_debug("skipping channel: %d, nss_5g: %d, nss_2g: %d", + validChan[i], nss_5g, nss_2g); + continue; + } else { + if (wlan_reg_is_dsrc_freq(ch_freq)) { + pe_debug("skipping freq: %d from the valid freq list", + ch_freq); + continue; + } + } + + if (wlan_reg_is_6ghz_chan_freq(ch_freq) && + !(is_vlp_country && + wlan_reg_is_6ghz_psc_chan_freq(ch_freq))) { + pe_debug("skipping is_vlp_country %d or non-psc channel %d", + is_vlp_country, ch_freq); + continue; + } + + if (valid_count >= ARRAY_SIZE(suppChannels->bands)) + break; + + suppChannels->bands[valid_count][0] = validChan[i]; + suppChannels->bands[valid_count][1] = 1; + valid_count++; + } + + suppChannels->num_bands = valid_count; + suppChannels->present = 1; + + /* find channel offset and get op class for current operating channel */ + switch (pe_session->htSecondaryChannelOffset) { + case PHY_SINGLE_CHANNEL_CENTERED: + chanOffset = BW20; + break; + + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + chanOffset = BW40_LOW_PRIMARY; + break; + + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + chanOffset = BW40_HIGH_PRIMARY; + break; + + default: + chanOffset = BWALL; + break; + } + + op_class = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, + wlan_reg_freq_to_chan(mac->pdev, pe_session->curr_op_freq), + chanOffset); + + suppOperClasses->present = 1; + suppOperClasses->classes[0] = op_class; + + wlan_reg_dmn_get_curr_opclasses(&numClasses, &classes[0]); + + for (i = 0; i < numClasses; i++) { + if (wlan_reg_is_6ghz_op_class(mac->pdev, classes[i]) && + !is_vlp_country) + continue; + + suppOperClasses->classes[count_opclss] = classes[i]; + count_opclss++; + } + + pe_debug("countryCodeCurrent: %s, curr_op_freq: %d, htSecondaryChannelOffset: %d, chanOffset: %d op class: %d num_supportd_chan %d total opclasses %d num_supportd_opclass %d", + reg_cc, + pe_session->curr_op_freq, + pe_session->htSecondaryChannelOffset, + chanOffset, op_class, valid_count, numClasses, + count_opclss); + + /* add one for present operating class, added in the beginning */ + suppOperClasses->num_classes = count_opclss; + + return; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_tdls_copy_self_mac() - copy mac address + * @session: pe session + * @init_sta_addr: the pointer to save the address + * + * For MLD device, it needs to copy mld mac address. + * + * Return: void + */ +static void lim_tdls_copy_self_mac(struct pe_session *session, + uint8_t *init_sta_addr) +{ + struct wlan_mlo_dev_context *mlo_dev_ctx; + + if (wlan_vdev_mlme_is_mlo_vdev(session->vdev)) { + mlo_dev_ctx = session->vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + pe_debug("mlo_dev_ctx is NULL"); + return; + } + + qdf_mem_copy((uint8_t *)init_sta_addr, + mlo_dev_ctx->mld_addr.bytes, QDF_MAC_ADDR_SIZE); + } else { + qdf_mem_copy((uint8_t *)init_sta_addr, + session->self_mac_addr, QDF_MAC_ADDR_SIZE); + } +} +#else +static void lim_tdls_copy_self_mac(struct pe_session *session, + uint8_t *init_sta_addr) +{ + qdf_mem_copy((uint8_t *)init_sta_addr, + session->self_mac_addr, QDF_MAC_ADDR_SIZE); +} +#endif + +/* + * FUNCTION: Populate Link Identifier element IE + * + */ + +static void populate_dot11f_link_iden(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIELinkIdentifier *linkIden, + struct qdf_mac_addr peer_mac, + uint8_t reqType) +{ + uint8_t *initaddr = NULL; + uint8_t *respaddr = NULL; + + (reqType == TDLS_INITIATOR) ? ((initaddr = linkIden->InitStaAddr), + (respaddr = linkIden->RespStaAddr)) + : ((respaddr = linkIden->InitStaAddr), + (initaddr = linkIden->RespStaAddr)); + qdf_mem_copy((uint8_t *)linkIden->bssid, + (uint8_t *)pe_session->bssId, QDF_MAC_ADDR_SIZE); + + lim_tdls_copy_self_mac(pe_session, initaddr); + + qdf_mem_copy((uint8_t *)respaddr, (uint8_t *)peer_mac.bytes, + QDF_MAC_ADDR_SIZE); + + linkIden->present = 1; + return; + +} + +static void populate_dot11f_tdls_ext_capability(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEExtCap *extCapability) +{ + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)extCapability->bytes; + + p_ext_cap->tdls_peer_psm_supp = PEER_PSM_SUPPORT; + p_ext_cap->tdls_peer_uapsd_buffer_sta = mac->lim.gLimTDLSBufStaEnabled; + + /* + * Set TDLS channel switching bits only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == mac->lim.gLimTDLSOffChannelEnabled) && + (!mlme_get_tdls_chan_switch_prohibited(pe_session->vdev))) { + p_ext_cap->tdls_channel_switching = 1; + p_ext_cap->tdls_chan_swit_prohibited = 0; + } else { + p_ext_cap->tdls_channel_switching = 0; + p_ext_cap->tdls_chan_swit_prohibited = TDLS_CH_SWITCH_PROHIBITED; + } + p_ext_cap->tdls_support = TDLS_SUPPORT; + p_ext_cap->tdls_prohibited = TDLS_PROHIBITED; + /* + * For supporting wider bandwidth set tdls_wider_bw set as 1 + */ + if (wlan_cfg80211_tdls_is_fw_wideband_capable(pe_session->vdev) && + (mac->lim.gLimTDLSOffChannelEnabled || + !wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq))) + p_ext_cap->tdls_wider_bw = 1; + + extCapability->present = 1; + extCapability->num_bytes = lim_compute_ext_cap_ie_length(extCapability); + + return; +} + +/* + * prepare TDLS frame header, it includes + * | | | | + * |802.11 header|RFC1042 header|TDLS_PYLOAD_TYPE|PAYLOAD + * | | | | + */ +static uint32_t lim_prepare_tdls_frame_header(struct mac_context *mac, uint8_t *pFrame, + tDot11fIELinkIdentifier *link_iden, + uint8_t tdlsLinkType, uint8_t reqType, + uint8_t tid, + struct pe_session *pe_session) +{ + tpSirMacDataHdr3a pMacHdr; + uint32_t header_offset = 0; + uint8_t *addr1 = NULL; + uint8_t *addr3 = NULL; + uint8_t toDs = (tdlsLinkType == TDLS_LINK_AP) + ? ANI_TXDIR_TODS : ANI_TXDIR_IBSS; + uint8_t *peerMac = (reqType == TDLS_INITIATOR) + ? link_iden->RespStaAddr : link_iden->InitStaAddr; + uint8_t *staMac = (reqType == TDLS_INITIATOR) + ? link_iden->InitStaAddr : link_iden->RespStaAddr; + tpDphHashNode sta_ds; + uint16_t aid = 0; + uint8_t qos_mode = 0; + + pMacHdr = (tpSirMacDataHdr3a) (pFrame); + + /* + * if TDLS frame goes through the AP link, it follows normal address + * pattern, if TDLS frame goes through the direct link, then + * A1--> Peer STA addr, A2-->Self STA address, A3--> BSSID + */ + (tdlsLinkType == TDLS_LINK_AP) ? ((addr1 = (link_iden->bssid)), + (addr3 = (peerMac))) + : ((addr1 = (peerMac)), (addr3 = (link_iden->bssid))); + /* + * prepare 802.11 header + */ + pMacHdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + pMacHdr->fc.type = SIR_MAC_DATA_FRAME; + + sta_ds = dph_lookup_hash_entry(mac, peerMac, &aid, + &pe_session->dph.dphHashTable); + if (sta_ds) + qos_mode = sta_ds->qosMode; + + pMacHdr->fc.subType = + ((IS_QOS_ENABLED(pe_session) && + (tdlsLinkType == TDLS_LINK_AP)) || + ((tdlsLinkType == TDLS_LINK_DIRECT) && qos_mode)) + ? SIR_MAC_DATA_QOS_DATA : SIR_MAC_DATA_DATA; + + /* + * TL is not setting up below fields, so we are doing it here + */ + pMacHdr->fc.toDS = toDs; + pMacHdr->fc.powerMgmt = 0; + pMacHdr->fc.wep = (pe_session->encryptType == eSIR_ED_NONE) ? 0 : 1; + + qdf_mem_copy((uint8_t *) pMacHdr->addr1, + (uint8_t *) addr1, sizeof(tSirMacAddr)); + qdf_mem_copy((uint8_t *) pMacHdr->addr2, + (uint8_t *) staMac, sizeof(tSirMacAddr)); + + qdf_mem_copy((uint8_t *) pMacHdr->addr3, + (uint8_t *) (addr3), sizeof(tSirMacAddr)); + + pe_debug("Preparing TDLS frame header to %s A1:" + QDF_MAC_ADDR_FMT", A2:"QDF_MAC_ADDR_FMT", A3:" + QDF_MAC_ADDR_FMT, + (tdlsLinkType == TDLS_LINK_AP) ? "AP" : "DIRECT", + QDF_MAC_ADDR_REF(pMacHdr->addr1), + QDF_MAC_ADDR_REF(pMacHdr->addr2), + QDF_MAC_ADDR_REF(pMacHdr->addr3)); + + if (pMacHdr->fc.subType == SIR_MAC_DATA_QOS_DATA) { + pMacHdr->qosControl.tid = tid; + header_offset += sizeof(tSirMacDataHdr3a); + } else + header_offset += sizeof(tSirMacMgmtHdr); + + /* + * Now form RFC1042 header + */ + qdf_mem_copy((uint8_t *) (pFrame + header_offset), + (uint8_t *) eth_890d_header, sizeof(eth_890d_header)); + + header_offset += sizeof(eth_890d_header); + + /* add payload type as TDLS */ + *(pFrame + header_offset) = PAYLOAD_TYPE_TDLS; + header_offset += PAYLOAD_TYPE_TDLS_SIZE; + + return header_offset; +} + +/** + * lim_mgmt_tdls_tx_complete - callback to indicate Tx completion + * @context: pointer to mac structure + * @buf: buffer + * @tx_complete: indicates tx success/failure + * @params: tx completion params + * + * Function will be invoked on receiving tx completion indication + * + * Return: success: eHAL_STATUS_SUCCESS failure: eHAL_STATUS_FAILURE + */ +static QDF_STATUS lim_mgmt_tdls_tx_complete(void *context, qdf_nbuf_t buf, + uint32_t tx_complete, void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + struct tdls_ethernet_hdr *ethernet_hdr; + tpSirMacActionFrameHdr action_hdr; + bool is_tdls_discvory_frm = false; + + + if (NO_SESSION != mac_ctx->lim.tdls_frm_session_id) { + if (buf && + (qdf_nbuf_len(buf) >= (TDLS_ETHR_HDR_LEN + + eth_890d_hdr_len + + PAYLOAD_TYPE_TDLS_SIZE + + sizeof(*action_hdr)))) { + ethernet_hdr = + (struct tdls_ethernet_hdr *)qdf_nbuf_data(buf); + is_tdls_discvory_frm = + !qdf_mem_cmp(((uint8_t *)qdf_nbuf_data(buf) + + TDLS_ETHR_HDR_LEN), + eth_890d_tdls_discvory_frm_hdr, + sizeof(eth_890d_tdls_discvory_frm_hdr)); + + if (is_tdls_discvory_frm && + tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) + wlan_tdls_increment_discovery_attempts( + mac_ctx->psoc, + mac_ctx->lim.tdls_frm_session_id, + ethernet_hdr->dest_addr); + } + + lim_send_sme_mgmt_tx_completion(mac_ctx, + mac_ctx->lim.tdls_frm_session_id, + tx_complete); + mac_ctx->lim.tdls_frm_session_id = NO_SESSION; + } + + pe_debug("tdls_frm_session_id: %x tx_complete: %x is_discovery:%d", + mac_ctx->lim.tdls_frm_session_id, tx_complete, + is_tdls_discvory_frm); + + if (buf) + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_get_assoc_link_vdev_id() - get vdev id + * @session: pe session + * + * Since fw only uses assoc link vdev to transmit data packets, + * it needs to fetch the right vdev id when transfer tdls management + * frame for partner link. + * + * Return: vdev id + */ +static uint8_t lim_get_assoc_link_vdev_id(struct pe_session *session) +{ + struct wlan_objmgr_vdev *assoc_vdev; + + if (wlan_vdev_mlme_is_mlo_vdev(session->vdev)) { + assoc_vdev = wlan_mlo_get_assoc_link_vdev(session->vdev); + if (assoc_vdev) + return wlan_vdev_get_id(assoc_vdev); + } + + return session->smeSessionId; +} +#else +static uint8_t lim_get_assoc_link_vdev_id(struct pe_session *session) +{ + return session->smeSessionId; +} +#endif + +/* + * This function can be used for bacst or unicast discovery request + * We are not differentiating it here, it will all depend on peer MAC address, + */ +static QDF_STATUS lim_send_tdls_dis_req_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + struct pe_session *pe_session, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSDisReq *tdls_dis_req; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t size = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + uint8_t vdev_id; + QDF_STATUS qdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + uint16_t mlo_ie_len = 0; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + tdls_dis_req = qdf_mem_malloc(sizeof(*tdls_dis_req)); + if (!tdls_dis_req) { + pe_err("memory allocation failed for DisReq"); + return QDF_STATUS_E_NOMEM; + } + + smeSessionId = pe_session->smeSessionId; + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). + */ + + /* + * setup Fixed fields, + */ + tdls_dis_req->Category.category = ACTION_CATEGORY_TDLS; + tdls_dis_req->Action.action = TDLS_DISCOVERY_REQUEST; + tdls_dis_req->DialogToken.token = dialog; + + size = sizeof(tSirMacAddr); + + populate_dot11f_link_iden(mac, pe_session, + &tdls_dis_req->LinkIdentifier, + peer_mac, TDLS_INITIATOR); + + if (wlan_vdev_mlme_is_mlo_vdev(pe_session->vdev)) + mlo_ie_len = lim_send_tdls_mgmt_frame_mlo(mac, pe_session); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_req_size(mac, tdls_dis_req, + &nPayload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a discovery Request (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTDLSDisReq); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a discovery Request (0x%08x)", + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(pe_session)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + + mlo_ie_len; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate: %d bytes for a TDLS Discovery Request", + nBytes); + qdf_mem_free(tdls_dis_req); + return QDF_STATUS_E_NOMEM; + } + + /* zero out the memory */ + qdf_mem_zero(pFrame, nBytes); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(mac, pFrame, + &tdls_dis_req->LinkIdentifier, TDLS_LINK_AP, + TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + pe_session); + + status = dot11f_pack_tdls_dis_req(mac, tdls_dis_req, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS discovery req (0x%08x)", + status); + cds_packet_free((void *)pPacket); + qdf_mem_free(tdls_dis_req); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Discovery Request (0x%08x)", + status); + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + pFrame + header_offset + + nPayload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + + nPayload += mlo_ie_len; + } + + lim_cp_stats_cstats_log_disc_req_evt(tdls_dis_req, pe_session); + + qdf_mem_free(tdls_dis_req); + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = pFrame + header_offset + nPayload; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + pe_debug("Padding Vendor Specific Ie Len: %d", padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + qdf_mem_zero(pFrame + header_offset + nPayload + + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE); + } +#endif + + pe_debug("[TDLS] action: %d (%s) -AP-> OTA peer="QDF_MAC_ADDR_FMT, + TDLS_DISCOVERY_REQUEST, + lim_trace_tdls_action_string(TDLS_DISCOVERY_REQUEST), + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + mac->lim.tdls_frm_session_id = pe_session->smeSessionId; + vdev_id = lim_get_assoc_link_vdev_id(pe_session); + + lim_diag_mgmt_tx_event_report(mac, (tpSirMacMgmtHdr) pFrame, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = wma_tx_frameWithTxComplete(mac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + TID_AC_VI, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME | + HAL_USE_PEER_STA_REQUESTED_MASK, + vdev_id, false, 0, + RATEID_DEFAULT, 0, 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->lim.tdls_frm_session_id = NO_SESSION; + pe_err("could not send TDLS Discovery Request frame"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} + +/* + * This static function is consistent with any kind of TDLS management + * frames we are sending. Currently it is being used by lim_send_tdls_dis_rsp_frame, + * lim_send_tdls_link_setup_req_frame and lim_send_tdls_setup_rsp_frame + */ +static void populate_dot11f_tdls_ht_vht_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fIEHTCaps *htCap, + tDot11fIEVHTCaps *vhtCap, + struct pe_session *pe_session) +{ + uint8_t nss; + qdf_size_t val_len; + struct mlme_vht_capabilities_info *vht_cap_info; + bool is_wideband; + + is_wideband = + wlan_cfg80211_tdls_is_fw_wideband_capable(pe_session->vdev); + + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + + if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) + nss = mac->vdev_type_nss_2g.tdls; + else + nss = mac->vdev_type_nss_5g.tdls; + + nss = QDF_MIN(nss, mac->user_configured_nss); + if (IS_DOT11_MODE_HT(selfDot11Mode) && + !lim_is_he_6ghz_band(pe_session)) { + /* Include HT Capability IE */ + populate_dot11f_ht_caps(mac, pe_session, htCap); + val_len = SIZE_OF_SUPPORTED_MCS_SET; + wlan_mlme_get_cfg_str(&htCap->supportedMCSSet[0], + &mac->mlme_cfg->rates.supported_mcs_set, + &val_len); + if (WLAN_REG_IS_5GHZ_CH_FREQ(pe_session->curr_op_freq) && + !wlan_reg_is_dfs_for_freq(mac->pdev, + pe_session->curr_op_freq) && + is_wideband) + htCap->supportedChannelWidthSet = 1; + else + if (pe_session->ch_width == CH_WIDTH_20MHZ) + htCap->supportedChannelWidthSet = 0; + + if (NSS_1x1_MODE == nss) + htCap->supportedMCSSet[1] = 0; + /* + * Advertise ht capability and max supported channel bandwidth + * when populating HT IE in TDLS Setup Request/Setup Response/ + * Setup Confirmation frames. + * 11.21.6.2 Setting up a 40 MHz direct link: A 40 MHz + * off-channel direct link may be started if both TDLS peer STAs + * indicated 40 MHz support in the Supported Channel Width Set + * field of the HT Capabilities element (which is included in + * the TDLS Setup Request frame and the TDLS Setup Response + * frame). Switching to a 40 MHz off-channel direct link is + * achieved by including the following information in the TDLS + * Channel Switch Request + * 11.21.1 General: The channel width of the TDLS direct link on + * the base channel shall not exceed the channel width of the + * BSS to which the TDLS peer STAs are associated. + * Select supportedChannelWidthSet based on channel bonding + * settings for each band + */ + } else { + htCap->present = 0; + } + pe_debug("HT present: %hu, Chan Width: %hu", + htCap->present, htCap->supportedChannelWidthSet); + + if ((WLAN_REG_IS_24GHZ_CH_FREQ(pe_session->curr_op_freq) && + vht_cap_info->b24ghz_band) || + WLAN_REG_IS_5GHZ_CH_FREQ(pe_session->curr_op_freq)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * Include VHT Capability IE + * + * VHT supportedChannelWidthSet should be set such as + * 1. Set to 0 if AP does not support either + * 160 or 80+80 MHz. With 0, it means 20/40/80 Mhz. + * Since for TDLS wideband we need to restrict the BW + * to 80 MHz for AP supporting BW less than 80 Mhz. + * So, set it to 0 for such cases so that TDLS STA + * can connect with 80 MHz width. + * 2. Set to 1 if AP supports 160 MHz, thus TDLS STA can + * connect with 160 MHz BW + * 3. Set to 2 if AP supports 160 MHz and + * 80+80 MHz. Not possible in case of 5 GHz + * + * The value 3 is reserved + */ + populate_dot11f_vht_caps(mac, pe_session, vhtCap); + vhtCap->suBeamformeeCap = 0; + vhtCap->suBeamFormerCap = 0; + vhtCap->muBeamformeeCap = 0; + vhtCap->muBeamformerCap = 0; + + vhtCap->rxMCSMap = vht_cap_info->rx_mcs_map; + + vhtCap->rxHighSupDataRate = + vht_cap_info->rx_supp_data_rate; + vhtCap->txMCSMap = vht_cap_info->tx_mcs_map; + vhtCap->txSupDataRate = vht_cap_info->tx_supp_data_rate; + if (nss == NSS_1x1_MODE) { + vhtCap->txMCSMap |= DISABLE_NSS2_MCS; + vhtCap->rxMCSMap |= DISABLE_NSS2_MCS; + vhtCap->txSupDataRate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + vhtCap->rxHighSupDataRate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + } else { + vhtCap->present = 0; + } + } else { + /* Vht Disable from ini in 2.4 GHz */ + vhtCap->present = 0; + } + pe_debug("VHT present: %hu, Chan Width: %u", + vhtCap->present, vhtCap->supportedChannelWidthSet); +} + +#ifdef WLAN_FEATURE_11AX +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static void +lim_tdls_populate_dot11f_6hgz_he_caps(struct mac_context *mac, + struct tdls_add_sta_req *add_sta_req, + tDot11fIEhe_6ghz_band_cap *pDot11f) +{ + union { + struct hecap_6ghz he_6ghz_cap; + struct he_6ghz_capability_info dot11f; + } peer_cfg; + + if (!add_sta_req->he_6ghz_cap.a_mpdu_params && + !add_sta_req->he_6ghz_cap.info) { + tdls_debug("6Ghz HE capabilities not present"); + return; + } + + qdf_mem_copy(&peer_cfg.he_6ghz_cap, + &add_sta_req->he_6ghz_cap, + sizeof(add_sta_req->he_6ghz_cap)); + + pDot11f->present = 1; + pDot11f->min_mpdu_start_spacing = + peer_cfg.dot11f.min_mpdu_start_spacing; + pDot11f->max_ampdu_len_exp = peer_cfg.dot11f.max_ampdu_len_exp; + pDot11f->max_mpdu_len = peer_cfg.dot11f.max_mpdu_len; + pDot11f->sm_pow_save = peer_cfg.dot11f.sm_pow_save; + pDot11f->rd_responder = peer_cfg.dot11f.rd_responder; + pDot11f->rx_ant_pattern_consistency = + peer_cfg.dot11f.rx_ant_pattern_consistency; + pDot11f->tx_ant_pattern_consistency = + peer_cfg.dot11f.tx_ant_pattern_consistency; + + lim_log_he_6g_cap(mac, pDot11f); +} + +static void lim_populate_tdls_setup_6g_cap(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *hecap_6g, + struct pe_session *session) +{ + if (hecap_6g) + populate_dot11f_he_6ghz_cap(mac, session, hecap_6g); +} + +#else +static void +lim_tdls_populate_dot11f_6hgz_he_caps(struct mac_context *mac, + struct tdls_add_sta_req *add_sta_req, + tDot11fIEhe_6ghz_band_cap *pDot11f) +{ +} + +static void lim_populate_tdls_setup_6g_cap(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *hecap_6g, + struct pe_session *session) +{ +} +#endif + +static void lim_fill_session_he_width(struct pe_session *session, + tDot11fIEhe_cap *heCap) +{ + /* + * For TDLS, the bw is filled using mlme_cfg so max supported bw + * will be set, so here reset he bw as per session bw. + */ + if (session->ch_width == CH_WIDTH_20MHZ) { + goto bw_20; + } else if (session->ch_width == CH_WIDTH_40MHZ) { + heCap->chan_width_0 = 1; + goto bw_40; + } else if (session->ch_width == CH_WIDTH_80MHZ) { + heCap->chan_width_1 = 1; + goto bw_80; + } else if (session->ch_width == CH_WIDTH_160MHZ) { + heCap->chan_width_2 = 1; + goto bw_160; + } else if (session->ch_width == CH_WIDTH_80P80MHZ) { + heCap->chan_width_3 = 1; + return; + } + +bw_20: + heCap->chan_width_0 = 0; +bw_40: + heCap->chan_width_1 = 0; +bw_80: + heCap->chan_width_2 = 0; +bw_160: + heCap->chan_width_3 = 0; +} + +static void lim_tdls_set_he_chan_width(struct mac_context *mac, + tDot11fIEhe_cap *heCap, + struct pe_session *session, + bool wideband_sta) +{ + if (!wideband_sta || + wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) { + lim_fill_session_he_width(session, heCap); + return; + } + + if (wlan_reg_is_5ghz_ch_freq(session->curr_op_freq)) { + if (wlan_reg_is_dfs_for_freq(mac->pdev, + session->curr_op_freq)) { + lim_fill_session_he_width(session, heCap); + return; + } + /* + * Right now, no support for ch_width 160 Mhz or 80P80 Mhz in 5 Ghz + * Also, restricting bw to 80 Mhz in case ap on 5 ghz is operating in + * less than 80 Mhz bw. + */ + if (session->ch_width <= CH_WIDTH_80MHZ) + heCap->chan_width_2 = 0; + heCap->chan_width_3 = 0; + heCap->chan_width_4 = 0; + heCap->chan_width_5 = 0; + heCap->chan_width_6 = 0; + } +} + +static void lim_tdls_populate_ppe_caps(struct mac_context *mac, + struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + uint8_t *ppet; + + /* + * No Need to populate if ppet is not present + */ + if (!he_cap->ppet_present) + return; + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + ppet = mac->mlme_cfg->he_caps.he_ppet_5g; + else + ppet = mac->mlme_cfg->he_caps.he_ppet_2g; + + he_cap->ppet.ppe_threshold.num_ppe_th = lim_truncate_ppet(ppet, + MLME_HE_PPET_LEN); + + /* + * If num_ppe_th calculated above is zero and ppet_present is set then + * atleast one byte should be sent with zero data otherwise framework + * will fail add_sta on the peer end. + */ + if (he_cap->ppet.ppe_threshold.num_ppe_th) + qdf_mem_copy(he_cap->ppet.ppe_threshold.ppe_th, ppet, + MLME_HE_PPET_LEN); + else + he_cap->ppet.ppe_threshold.num_ppe_th = 1; +} + +static void populate_dot11f_set_tdls_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fIEhe_cap *heCap, + tDot11fIEhe_6ghz_band_cap *hecap_6g, + struct pe_session *session) +{ + if (IS_DOT11_MODE_HE(selfDot11Mode)) { + populate_dot11f_he_caps(mac, NULL, heCap); + lim_tdls_set_he_chan_width(mac, heCap, session, + wlan_cfg80211_tdls_is_fw_wideband_capable(session->vdev)); + lim_tdls_populate_ppe_caps(mac, session, heCap); + lim_log_he_cap(mac, heCap); + lim_populate_tdls_setup_6g_cap(mac, hecap_6g, session); + } else { + pe_debug("Not populating he cap as SelfDot11Mode not HE %d", + selfDot11Mode); + } +} + +static void lim_tdls_fill_dis_rsp_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fTDLSDisRsp *tdls_dis_rsp, + struct pe_session *pe_session) +{ + populate_dot11f_set_tdls_he_cap(mac, selfDot11Mode, + &tdls_dis_rsp->he_cap, + NULL, + pe_session); +} + +static void lim_tdls_fill_setup_req_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fTDLSSetupReq *tdls_setup_req, + struct pe_session *pe_session) +{ + populate_dot11f_set_tdls_he_cap(mac, selfDot11Mode, + &tdls_setup_req->he_cap, + &tdls_setup_req->he_6ghz_band_cap, + pe_session); +} + +static void lim_tdls_fill_setup_rsp_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fTDLSSetupRsp *tdls_setup_rsp, + struct pe_session *pe_session) +{ + populate_dot11f_set_tdls_he_cap(mac, selfDot11Mode, + &tdls_setup_rsp->he_cap, + &tdls_setup_rsp->he_6ghz_band_cap, + pe_session); +} + +static void lim_tdls_populate_he_operations(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEhe_op *he_op) +{ + struct wlan_mlme_he_caps *he_cap_info; + uint16_t mcs_set = 0; + + he_cap_info = &mac->mlme_cfg->he_caps; + he_op->co_located_bss = 0; + he_op->bss_color = pe_session->he_bss_color_change.new_color; + if (!he_op->bss_color) + he_op->bss_col_disabled = 1; + + mcs_set = (uint16_t)he_cap_info->he_ops_basic_mcs_nss; + if (pe_session->nss == NSS_1x1_MODE) + mcs_set |= 0xFFFC; + else + mcs_set |= 0xFFF0; + + *((uint16_t *)he_op->basic_mcs_nss) = mcs_set; + populate_dot11f_he_operation(mac, + pe_session, + he_op); +} + +static void lim_tdls_fill_setup_cnf_he_op(struct mac_context *mac, + uint32_t peer_capability, + tDot11fTDLSSetupCnf *tdls_setup_cnf, + struct pe_session *pe_session) +{ + if (CHECK_BIT(peer_capability, TDLS_PEER_HE_CAP)) + lim_tdls_populate_he_operations(mac, + pe_session, + &tdls_setup_cnf->he_op); +} + +static void lim_tdls_fill_he_wideband_offchannel_mcs(struct mac_context *mac_ctx, + tpDphHashNode stads, + uint8_t nss, + struct pe_session *session) +{ + struct supported_rates *rates = &stads->supportedRates; + tDot11fIEhe_cap *peer_he_caps = &stads->he_config; + struct tdls_vdev_priv_obj *tdls_obj = NULL; + struct tdls_peer *tdls_peer_candidate = NULL; + struct tdls_peer *curr_peer_candidate = NULL; + qdf_list_t *head; + qdf_list_node_t *p_node; + int i = 0; + uint16_t rx_he_mcs_map_160 = 0xfffa; + uint16_t tx_he_mcs_map_160 = 0xfffa; + QDF_STATUS status; + + tdls_obj = wlan_vdev_get_tdls_vdev_obj(session->vdev); + if (!tdls_obj) { + pe_debug("failed to ger tdls priv object"); + return; + } + + for (i = 0; i < WLAN_TDLS_PEER_LIST_SIZE; i++) { + head = &tdls_obj->peer_list[i]; + status = qdf_list_peek_front(head, &p_node); + while (QDF_IS_STATUS_SUCCESS(status)) { + curr_peer_candidate = qdf_container_of(p_node, + struct tdls_peer, + node); + if (!qdf_mem_cmp(&curr_peer_candidate->peer_mac.bytes, + &stads->staAddr, QDF_MAC_ADDR_SIZE)) { + tdls_peer_candidate = curr_peer_candidate; + break; + } + status = qdf_list_peek_next(head, p_node, &p_node); + } + } + + if (!tdls_peer_candidate) { + pe_debug("failed to ger tdls peer object"); + return; + } + + if (stads->ch_width == CH_WIDTH_160MHZ) { + lim_populate_he_mcs_per_bw( + mac_ctx, &rates->rx_he_mcs_map_160, + &rates->tx_he_mcs_map_160, + *((uint16_t *)peer_he_caps->rx_he_mcs_map_160), + *((uint16_t *)peer_he_caps->tx_he_mcs_map_160), + nss, + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160), + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160)); + } else if (tdls_peer_candidate->pref_off_chan_width & + (1 << BW_160_OFFSET_BIT)) { + lim_populate_he_mcs_per_bw( + mac_ctx, &rates->rx_he_mcs_map_160, + &rates->tx_he_mcs_map_160, + rx_he_mcs_map_160, + tx_he_mcs_map_160, + nss, + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160), + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160)); + } else { + rates->tx_he_mcs_map_160 = HE_MCS_ALL_DISABLED; + rates->rx_he_mcs_map_160 = HE_MCS_ALL_DISABLED; + } + if (stads->ch_width == CH_WIDTH_80P80MHZ) { + lim_populate_he_mcs_per_bw( + mac_ctx, &rates->rx_he_mcs_map_80_80, + &rates->tx_he_mcs_map_80_80, + *((uint16_t *)peer_he_caps->rx_he_mcs_map_80_80), + *((uint16_t *)peer_he_caps->tx_he_mcs_map_80_80), nss, + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_80_80), + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_80_80)); + } else { + rates->tx_he_mcs_map_80_80 = HE_MCS_ALL_DISABLED; + rates->rx_he_mcs_map_80_80 = HE_MCS_ALL_DISABLED; + } +} + +static void lim_tdls_populate_he_matching_rate_set(struct mac_context *mac_ctx, + tpDphHashNode stads, + uint8_t nss, + struct pe_session *session) +{ + lim_populate_he_mcs_set(mac_ctx, &stads->supportedRates, + &stads->he_config, session, nss); + + lim_tdls_fill_he_wideband_offchannel_mcs(mac_ctx, stads, nss, session); +} + +static QDF_STATUS +lim_tdls_populate_dot11f_he_caps(struct mac_context *mac, + struct tdls_add_sta_req *add_sta_req, + tDot11fIEhe_cap *pDot11f) +{ + uint32_t chan_width; + union { + struct hecap nCfgValue; + struct he_capability_info he_cap; + } uHECapInfo; + + if (add_sta_req->he_cap_len < MIN_TDLS_HE_CAP_LEN) { + pe_debug("He_capability invalid"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(&uHECapInfo.nCfgValue, &add_sta_req->he_cap, + sizeof(uHECapInfo.nCfgValue)); + + pDot11f->present = 1; + pDot11f->htc_he = uHECapInfo.he_cap.htc_he; + pDot11f->twt_request = uHECapInfo.he_cap.twt_request; + pDot11f->twt_responder = uHECapInfo.he_cap.twt_responder; + pDot11f->fragmentation = uHECapInfo.he_cap.fragmentation; + pDot11f->max_num_frag_msdu_amsdu_exp = + uHECapInfo.he_cap.max_num_frag_msdu_amsdu_exp; + pDot11f->min_frag_size = uHECapInfo.he_cap.min_frag_size; + pDot11f->trigger_frm_mac_pad = uHECapInfo.he_cap.trigger_frm_mac_pad; + pDot11f->multi_tid_aggr_rx_supp = + uHECapInfo.he_cap.multi_tid_aggr_rx_supp; + pDot11f->he_link_adaptation = uHECapInfo.he_cap.he_link_adaptation; + pDot11f->all_ack = uHECapInfo.he_cap.all_ack; + pDot11f->trigd_rsp_sched = uHECapInfo.he_cap.trigd_rsp_sched; + pDot11f->a_bsr = uHECapInfo.he_cap.a_bsr; + pDot11f->broadcast_twt = uHECapInfo.he_cap.broadcast_twt; + pDot11f->ba_32bit_bitmap = uHECapInfo.he_cap.ba_32bit_bitmap; + pDot11f->mu_cascade = uHECapInfo.he_cap.mu_cascade; + pDot11f->ack_enabled_multitid = uHECapInfo.he_cap.ack_enabled_multitid; + pDot11f->omi_a_ctrl = uHECapInfo.he_cap.omi_a_ctrl; + pDot11f->ofdma_ra = uHECapInfo.he_cap.ofdma_ra; + pDot11f->max_ampdu_len_exp_ext = + uHECapInfo.he_cap.max_ampdu_len_exp_ext; + pDot11f->amsdu_frag = uHECapInfo.he_cap.amsdu_frag; + pDot11f->flex_twt_sched = uHECapInfo.he_cap.flex_twt_sched; + pDot11f->rx_ctrl_frame = uHECapInfo.he_cap.rx_ctrl_frame; + + pDot11f->bsrp_ampdu_aggr = uHECapInfo.he_cap.bsrp_ampdu_aggr; + pDot11f->qtp = uHECapInfo.he_cap.qtp; + pDot11f->a_bqr = uHECapInfo.he_cap.a_bqr; + pDot11f->spatial_reuse_param_rspder = + uHECapInfo.he_cap.spatial_reuse_param_rspder; + pDot11f->ops_supp = uHECapInfo.he_cap.ops_supp; + pDot11f->ndp_feedback_supp = uHECapInfo.he_cap.ndp_feedback_supp; + pDot11f->amsdu_in_ampdu = uHECapInfo.he_cap.amsdu_in_ampdu; + + chan_width = uHECapInfo.he_cap.chan_width; + pDot11f->chan_width_0 = HE_CH_WIDTH_GET_BIT(chan_width, 0); + pDot11f->chan_width_1 = HE_CH_WIDTH_GET_BIT(chan_width, 1); + pDot11f->chan_width_2 = HE_CH_WIDTH_GET_BIT(chan_width, 2); + pDot11f->chan_width_3 = HE_CH_WIDTH_GET_BIT(chan_width, 3); + pDot11f->chan_width_4 = HE_CH_WIDTH_GET_BIT(chan_width, 4); + pDot11f->chan_width_5 = HE_CH_WIDTH_GET_BIT(chan_width, 5); + pDot11f->chan_width_6 = HE_CH_WIDTH_GET_BIT(chan_width, 6); + + pDot11f->rx_pream_puncturing = uHECapInfo.he_cap.rx_pream_puncturing; + pDot11f->device_class = uHECapInfo.he_cap.device_class; + pDot11f->ldpc_coding = uHECapInfo.he_cap.ldpc_coding; + pDot11f->he_1x_ltf_800_gi_ppdu = + uHECapInfo.he_cap.he_1x_ltf_800_gi_ppdu; + pDot11f->midamble_tx_rx_max_nsts = + uHECapInfo.he_cap.midamble_tx_rx_max_nsts; + pDot11f->he_4x_ltf_3200_gi_ndp = + uHECapInfo.he_cap.he_4x_ltf_3200_gi_ndp; + pDot11f->tb_ppdu_tx_stbc_lt_80mhz = + uHECapInfo.he_cap.tb_ppdu_tx_stbc_lt_80mhz; + pDot11f->rx_stbc_lt_80mhz = uHECapInfo.he_cap.rx_stbc_lt_80mhz; + pDot11f->tb_ppdu_tx_stbc_gt_80mhz = + uHECapInfo.he_cap.tb_ppdu_tx_stbc_gt_80mhz; + pDot11f->rx_stbc_gt_80mhz = uHECapInfo.he_cap.rx_stbc_gt_80mhz; + pDot11f->doppler = uHECapInfo.he_cap.doppler; + pDot11f->ul_mu = uHECapInfo.he_cap.ul_mu; + pDot11f->dcm_enc_tx = uHECapInfo.he_cap.dcm_enc_tx; + pDot11f->dcm_enc_rx = uHECapInfo.he_cap.dcm_enc_rx; + pDot11f->ul_he_mu = uHECapInfo.he_cap.ul_he_mu; + pDot11f->su_beamformer = uHECapInfo.he_cap.su_beamformer; + + pDot11f->su_beamformee = uHECapInfo.he_cap.su_beamformee; + pDot11f->mu_beamformer = uHECapInfo.he_cap.mu_beamformer; + pDot11f->bfee_sts_lt_80 = uHECapInfo.he_cap.bfee_sts_lt_80; + pDot11f->bfee_sts_gt_80 = uHECapInfo.he_cap.bfee_sts_gt_80; + pDot11f->num_sounding_lt_80 = uHECapInfo.he_cap.num_sounding_lt_80; + pDot11f->num_sounding_gt_80 = uHECapInfo.he_cap.num_sounding_gt_80; + pDot11f->su_feedback_tone16 = uHECapInfo.he_cap.su_feedback_tone16; + pDot11f->mu_feedback_tone16 = uHECapInfo.he_cap.mu_feedback_tone16; + pDot11f->codebook_su = uHECapInfo.he_cap.codebook_su; + pDot11f->codebook_mu = uHECapInfo.he_cap.codebook_mu; + pDot11f->beamforming_feedback = uHECapInfo.he_cap.beamforming_feedback; + pDot11f->he_er_su_ppdu = uHECapInfo.he_cap.he_er_su_ppdu; + pDot11f->dl_mu_mimo_part_bw = uHECapInfo.he_cap.dl_mu_mimo_part_bw; + pDot11f->ppet_present = uHECapInfo.he_cap.ppet_present; + pDot11f->srp = uHECapInfo.he_cap.srp; + pDot11f->power_boost = uHECapInfo.he_cap.power_boost; + + pDot11f->he_ltf_800_gi_4x = uHECapInfo.he_cap.he_ltf_800_gi_4x; + pDot11f->max_nc = uHECapInfo.he_cap.max_nc; + pDot11f->er_he_ltf_800_gi_4x = uHECapInfo.he_cap.er_he_ltf_800_gi_4x; + pDot11f->he_ppdu_20_in_40Mhz_2G = + uHECapInfo.he_cap.he_ppdu_20_in_40Mhz_2G; + pDot11f->he_ppdu_20_in_160_80p80Mhz = + uHECapInfo.he_cap.he_ppdu_20_in_160_80p80Mhz; + pDot11f->he_ppdu_80_in_160_80p80Mhz = + uHECapInfo.he_cap.he_ppdu_80_in_160_80p80Mhz; + pDot11f->er_1x_he_ltf_gi = + uHECapInfo.he_cap.er_1x_he_ltf_gi; + pDot11f->midamble_tx_rx_1x_he_ltf = + uHECapInfo.he_cap.midamble_tx_rx_1x_he_ltf; + pDot11f->reserved2 = uHECapInfo.he_cap.reserved2; + + pDot11f->rx_he_mcs_map_lt_80 = uHECapInfo.he_cap.rx_he_mcs_map_lt_80; + pDot11f->tx_he_mcs_map_lt_80 = uHECapInfo.he_cap.tx_he_mcs_map_lt_80; + if (pDot11f->chan_width_2) { + *((uint16_t *)pDot11f->rx_he_mcs_map_160) = + uHECapInfo.he_cap.rx_he_mcs_map_160; + *((uint16_t *)pDot11f->tx_he_mcs_map_160) = + uHECapInfo.he_cap.tx_he_mcs_map_160; + } + if (pDot11f->chan_width_3) { + *((uint16_t *)pDot11f->rx_he_mcs_map_80_80) = + uHECapInfo.he_cap.rx_he_mcs_map_80_80; + *((uint16_t *)pDot11f->tx_he_mcs_map_80_80) = + uHECapInfo.he_cap.tx_he_mcs_map_80_80; + } + + return QDF_STATUS_SUCCESS; +} + +static void lim_tdls_check_and_force_he_ldpc_cap(struct pe_session *pe_session, + tDphHashNode *sta) +{ + if (pe_session && sta->he_config.present) + lim_check_and_force_he_ldpc_cap(pe_session, &sta->he_config); +} + +static enum phy_ch_width lim_tdls_get_he_ch_width(struct pe_session *pe_session, + tDot11fIEhe_cap *he_cap) +{ + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + + if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) && + he_cap->chan_width_0) + return CH_WIDTH_40MHZ; + + if (he_cap->chan_width_3) + ch_width = CH_WIDTH_80P80MHZ; + else if (he_cap->chan_width_2) + ch_width = CH_WIDTH_160MHZ; + else if (he_cap->chan_width_1) + ch_width = CH_WIDTH_80MHZ; + + return ch_width; +} + +static void lim_tdls_update_node_he_caps(struct mac_context *mac, + struct tdls_add_sta_req *add_sta_req, + tDphHashNode *sta, + struct pe_session *pe_session, + bool wide_band_peer) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + pe_debug("Populating HE IEs"); + status = lim_tdls_populate_dot11f_he_caps(mac, add_sta_req, + &sta->he_config); + + if (status != QDF_STATUS_SUCCESS) + return; + + if (!sta->he_config.present) + return; + + sta->mlmStaContext.he_capable = 1; + lim_tdls_set_he_chan_width(mac, &sta->he_config, pe_session, + wide_band_peer); + lim_log_he_cap(mac, &sta->he_config); + if (lim_is_he_6ghz_band(pe_session)) { + lim_tdls_populate_dot11f_6hgz_he_caps(mac, add_sta_req, + &sta->he_6g_band_cap); + /* + * In 6Ghz, vht and ht ie may not present, peer channel width + * is populated while extracting HT and VHT cap itself. So, + * incase of 6ghz fill the chan_width. + */ + lim_update_stads_he_6ghz_op(pe_session, sta); + } + sta->ch_width = lim_tdls_get_he_ch_width(pe_session, + &sta->he_config); + pe_debug("sta->ch_width %d", sta->ch_width); +} + +#else +static void lim_tdls_fill_dis_rsp_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fTDLSDisRsp *tdls_dis_rsp, + struct pe_session *pe_session) +{ +} + +static void lim_tdls_fill_setup_req_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fTDLSSetupReq *tdls_setup_req, + struct pe_session *pe_session) +{ +} + +static void lim_tdls_fill_setup_rsp_he_cap(struct mac_context *mac, + uint32_t selfDot11Mode, + tDot11fTDLSSetupRsp *tdls_setup_rsp, + struct pe_session *pe_session) +{ +} + +static void lim_tdls_fill_setup_cnf_he_op(struct mac_context *mac, + uint32_t peer_capability, + tDot11fTDLSSetupCnf *tdls_setup_cnf, + struct pe_session *pe_session) +{ +} + +static void lim_tdls_populate_he_matching_rate_set(struct mac_context *mac_ctx, + tpDphHashNode stads, + uint8_t nss, + struct pe_session *session) +{ +} + +static void lim_tdls_update_node_he_caps(struct mac_context *mac, + struct tdls_add_sta_req *add_sta_req, + tDphHashNode *sta, + struct pe_session *pe_session, + bool wide_band_peer) +{ +} + +static void lim_tdls_check_and_force_he_ldpc_cap(struct pe_session *pe_session, + tDphHashNode *sta) +{ +} + +#endif + +#ifdef WLAN_FEATURE_11BE +static uint8_t * +lim_ieee80211_pack_ehtcap_tdls(struct mac_context *mac, + struct pe_session *pe_session, uint8_t *len) +{ + tDot11fIEhe_cap he_cap; + uint8_t *eht_cap_ie; + bool is_band_2g; + uint32_t self_mode; + + if (!pe_session || !len) + return NULL; + + eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + *len = 0; + return NULL; + } + + is_band_2g = WLAN_REG_IS_24GHZ_CH_FREQ(pe_session->curr_op_freq); + self_mode = mac->mlme_cfg->dot11_mode.dot11_mode; + populate_dot11f_set_tdls_he_cap(mac, self_mode, &he_cap, + NULL, pe_session); + + lim_ieee80211_pack_ehtcap(eht_cap_ie, pe_session->eht_config, + he_cap, is_band_2g); + + *len = eht_cap_ie[1] + 2; + return eht_cap_ie; +} +#else +static uint8_t * +lim_ieee80211_pack_ehtcap_tdls(struct mac_context *mac, + struct pe_session *pe_session, uint8_t *len) +{ + if (!mac || !pe_session || !len) + return NULL; + + *len = 0; + return NULL; +} +#endif + +/* + * Send TDLS discovery response frame on direct link. + */ +static QDF_STATUS lim_send_tdls_dis_rsp_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + struct pe_session *pe_session, + uint8_t *addIe, + uint16_t addIeLen) +{ + tDot11fTDLSDisRsp *tdls_dis_rsp; + uint16_t caps = 0; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; + uint32_t selfDot11Mode; + uint8_t selfaddr[QDF_MAC_ADDR_SIZE]; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + uint8_t smeSessionId = 0; + uint16_t mlo_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + uint16_t action; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + tdls_dis_rsp = qdf_mem_malloc(sizeof(*tdls_dis_rsp)); + if (!tdls_dis_rsp) { + pe_err("memory allocation failed for DisRsp"); + return QDF_STATUS_E_NOMEM; + } + + smeSessionId = pe_session->smeSessionId; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). + */ + + /* + * setup Fixed fields, + */ + tdls_dis_rsp->Category.category = ACTION_CATEGORY_PUBLIC; + tdls_dis_rsp->Action.action = TDLS_DISCOVERY_RESPONSE; + tdls_dis_rsp->DialogToken.token = dialog; + + populate_dot11f_link_iden(mac, pe_session, + LINK_IDEN_ADDR_OFFSET(tdls_dis_rsp), + peer_mac, TDLS_RESPONDER); + + if (lim_get_capability_info(mac, &caps, pe_session) != + QDF_STATUS_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + pe_err("could not retrieve Capabilities value"); + } + swap_bit_field16(caps, (uint16_t *)&tdls_dis_rsp->Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (QDF_STATUS_E_FAILURE == populate_dot11f_rates_tdls(mac, + &tdls_dis_rsp->SuppRates, + &tdls_dis_rsp->ExtSuppRates, + wlan_reg_freq_to_chan( + mac->pdev, pe_session->curr_op_freq))) + pe_err("could not populate supported data rates"); + + /* populate extended capability IE */ + populate_dot11f_tdls_ext_capability(mac, + pe_session, + &tdls_dis_rsp->ExtCap); + + selfDot11Mode = mac->mlme_cfg->dot11_mode.dot11_mode; + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(mac, selfDot11Mode, + &tdls_dis_rsp->HTCaps, + &tdls_dis_rsp->VHTCaps, + pe_session); + + lim_tdls_fill_dis_rsp_he_cap(mac, selfDot11Mode, tdls_dis_rsp, + pe_session); + + if (wlan_vdev_mlme_is_mlo_vdev(pe_session->vdev)) + mlo_ie_len = lim_send_tdls_mgmt_frame_mlo(mac, pe_session); + + if (lim_is_session_eht_capable(pe_session)) { + eht_cap_ie = lim_ieee80211_pack_ehtcap_tdls(mac, pe_session, + &eht_cap_ie_len); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + qdf_mem_free(tdls_dis_rsp); + return QDF_STATUS_E_FAILURE; + } + } + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == mac->lim.gLimTDLSOffChannelEnabled) && + (!mlme_get_tdls_chan_switch_prohibited(pe_session->vdev))) { + populate_dot11f_tdls_offchannel_params(mac, pe_session, + &tdls_dis_rsp->SuppChannels, + &tdls_dis_rsp->SuppOperatingClasses); + if (mac->mlme_cfg->gen.band_capability != BIT(REG_BAND_2G)) { + tdls_dis_rsp->ht2040_bss_coexistence.present = 1; + tdls_dis_rsp->ht2040_bss_coexistence.info_request = 1; + } + } else { + pe_debug("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled: %d tdls_chan_swit_prohibited: %d", + mac->lim.gLimTDLSOffChannelEnabled, + mlme_get_tdls_chan_switch_prohibited(pe_session->vdev)); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_dis_rsp_size(mac, tdls_dis_rsp, + &nPayload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a Discovery Response (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a Discovery Response (0x%08x)", + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + sizeof(tSirMacMgmtHdr) + addIeLen + + eht_cap_ie_len + mlo_ie_len; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TDLS Discovery Request", + nBytes); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(tdls_dis_rsp); + return QDF_STATUS_E_NOMEM; + } + + /* zero out the memory */ + qdf_mem_zero(pFrame, nBytes); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * response frame + */ + + /* Make public Action Frame */ + lim_tdls_copy_self_mac(pe_session, selfaddr); + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac.bytes, + selfaddr); + + { + tpSirMacMgmtHdr pMacHdr; + + pMacHdr = (tpSirMacMgmtHdr) pFrame; + pMacHdr->fc.toDS = ANI_TXDIR_IBSS; + pMacHdr->fc.powerMgmt = 0; + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + } + + status = dot11f_pack_tdls_dis_rsp(mac, tdls_dis_rsp, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS discovery response (0x%08x)", + status); + cds_packet_free((void *)pPacket); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(tdls_dis_rsp); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Discovery Response (0x%08x)", + status); + } + + if (eht_cap_ie_len) { + /* Copy the EHT IE to the end of the frame */ + qdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, + eht_cap_ie, eht_cap_ie_len); + qdf_mem_free(eht_cap_ie); + + nPayload += eht_cap_ie_len; + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + pFrame + + sizeof(tSirMacMgmtHdr) + + nPayload); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + + nPayload += mlo_ie_len; + } + + lim_cp_stats_cstats_log_disc_resp_evt(tdls_dis_rsp, pe_session); + + qdf_mem_free(tdls_dis_rsp); + + if (0 != addIeLen) { + pe_debug("Copy Additional Ie Len: %d", addIeLen); + qdf_mem_copy(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, addIe, + addIeLen); + } + pe_debug("[TDLS] action: %d (%s) -DIRECT-> OTA peer="QDF_MAC_ADDR_FMT, + TDLS_DISCOVERY_RESPONSE, + lim_trace_tdls_action_string(TDLS_DISCOVERY_RESPONSE), + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + mac->lim.tdls_frm_session_id = pe_session->smeSessionId; + lim_diag_mgmt_tx_event_report(mac, (tpSirMacMgmtHdr) pFrame, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + /* + * Transmit Discovery response and watch if this is delivered to + * peer STA. + */ + /* In CLD 2.0, pass Discovery Response as mgmt frame so that + * wma does not do header conversion to 802.3 before calling tx/rx + * routine and subsequenly target also sends frame as is OTA + */ + action = ACTION_CATEGORY_PUBLIC << 8 | TDLS_DISCOVERY_RESPONSE; + qdf_status = wma_tx_frameWithTxComplete(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_IBSS, + 0, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_SELF_STA_REQUESTED_MASK, + smeSessionId, false, 0, + RATEID_DEFAULT, 0, + action); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->lim.tdls_frm_session_id = NO_SESSION; + pe_err("could not send TDLS Discovery Response frame!"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * This static function is currently used by lim_send_tdls_link_setup_req_frame and + * lim_send_tdls_setup_rsp_frame to populate the AID if device is 11ac capable. + */ +static void populate_dotf_tdls_vht_aid(struct mac_context *mac, uint32_t selfDot11Mode, + struct qdf_mac_addr peerMac, + tDot11fIEAID *Aid, + struct pe_session *pe_session) +{ + if (((wlan_reg_freq_to_chan(mac->pdev, pe_session->curr_op_freq) <= + SIR_11B_CHANNEL_END) && + mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) || + (wlan_reg_freq_to_chan(mac->pdev, pe_session->curr_op_freq) >= + SIR_11B_CHANNEL_END)) { + if (IS_DOT11_MODE_VHT(selfDot11Mode) && + IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + + uint16_t aid; + tpDphHashNode sta; + + sta = + dph_lookup_hash_entry(mac, peerMac.bytes, &aid, + &pe_session->dph. + dphHashTable); + if (sta) { + Aid->present = 1; + Aid->assocId = aid | LIM_AID_MASK; /* set bit 14 and 15 1's */ + } else { + Aid->present = 0; + pe_err("sta is NULL for " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peerMac.bytes)); + } + } + } else { + Aid->present = 0; + pe_warn("Vht not enable from ini for 2.4GHz"); + } +} + +#ifdef CONFIG_HL_SUPPORT + +/** + * wma_tx_frame_with_tx_complete_send() - Send tx frames on Direct link or AP link + * depend on reason code + * @mac: pointer to MAC Sirius parameter structure + * @pPacket: pointer to mgmt packet + * @nBytes: number of bytes to send + * @tid:tid value for AC + * @pFrame: pointer to tdls frame + * @smeSessionId:session id + * @flag: tdls flag + * + * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. + * + * Return: None + */ +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(struct mac_context *mac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(mac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + tid, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME + | HAL_USE_PEER_STA_REQUESTED_MASK, + smeSessionId, flag, 0, + RATEID_DEFAULT, 0, 0); +} +#else + +static inline QDF_STATUS +wma_tx_frame_with_tx_complete_send(struct mac_context *mac, void *pPacket, + uint16_t nBytes, + uint8_t tid, + uint8_t *pFrame, + uint8_t smeSessionId, bool flag) +{ + return wma_tx_frameWithTxComplete(mac, pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_DATA, + ANI_TXDIR_TODS, + tid, + lim_tx_complete, pFrame, + lim_mgmt_tdls_tx_complete, + HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME + | HAL_USE_PEER_STA_REQUESTED_MASK, + smeSessionId, false, 0, + RATEID_DEFAULT, 0, 0); +} +#endif + +static +bool lim_is_wide_band_set(uint8_t *ext_capability) +{ + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *)ext_capability; + + if (!p_ext_cap) + return false; + + pe_debug("p_ext_cap->tdls_wider_bw %d", p_ext_cap->tdls_wider_bw); + return p_ext_cap->tdls_wider_bw; +} + +/* + * TDLS setup Request frame on AP link + */ +static +QDF_STATUS lim_send_tdls_link_setup_req_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + struct pe_session *pe_session, + uint8_t *addIe, + uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSSetupReq *tdls_setup_req; + uint16_t caps = 0; + uint32_t status = 0; + uint32_t payload = 0; + uint32_t nbytes = 0; + uint32_t header_offset = 0; + uint8_t vdev_id; + uint8_t *frame; + void *packet; + QDF_STATUS qdf_status; + uint32_t selfDot11Mode; + uint8_t smeSessionId = 0; + uint8_t sp_length = 0; + uint16_t mlo_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + + if (!pe_session) { + pe_err("pe_session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + tdls_setup_req = qdf_mem_malloc(sizeof(*tdls_setup_req)); + if (!tdls_setup_req) { + pe_err("memory allocation failed for SetupReq"); + return QDF_STATUS_E_NOMEM; + } + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). + */ + smeSessionId = pe_session->smeSessionId; + + tdls_setup_req->Category.category = ACTION_CATEGORY_TDLS; + tdls_setup_req->Action.action = TDLS_SETUP_REQUEST; + tdls_setup_req->DialogToken.token = dialog; + + populate_dot11f_link_iden(mac, pe_session, + &tdls_setup_req->LinkIdentifier, peer_mac, + TDLS_INITIATOR); + + if (lim_get_capability_info(mac, &caps, pe_session) != + QDF_STATUS_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + pe_err("could not retrieve Capabilities value"); + } + swap_bit_field16(caps, (uint16_t *)&tdls_setup_req->Capabilities); + + /* populate supported rate and ext supported rate IE */ + if (QDF_STATUS_E_FAILURE == populate_dot11f_rates_tdls(mac, + &tdls_setup_req->SuppRates, + &tdls_setup_req->ExtSuppRates, + wlan_reg_freq_to_chan( + mac->pdev, pe_session->curr_op_freq))) + pe_err("could not populate supported data rates"); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(mac, + pe_session, + &tdls_setup_req->ExtCap); + + if (1 == mac->lim.gLimTDLSWmmMode) { + + pe_debug("populate WMM IE in Setup Request Frame"); + sp_length = mac->mlme_cfg->wmm_params.max_sp_length; + /* include WMM IE */ + tdls_setup_req->WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + tdls_setup_req->WMMInfoStation.acvo_uapsd = + (mac->lim.gLimTDLSUapsdMask & 0x01); + tdls_setup_req->WMMInfoStation.acvi_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdls_setup_req->WMMInfoStation.acbk_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdls_setup_req->WMMInfoStation.acbe_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdls_setup_req->WMMInfoStation.max_sp_length = sp_length; + tdls_setup_req->WMMInfoStation.present = 1; + } else { + /* + * TODO: we need to see if we have to support conditions where + * we have EDCA parameter info element is needed a) if we need + * different QOS parameters for off channel operations or QOS + * is not supported on AP link and we wanted to QOS on direct + * link. + */ + + /* Populate QOS info, needed for Peer U-APSD session */ + + /* + * TODO: Now hardcoded, since populate_dot11f_qos_caps_station() + * depends on AP's capability, and TDLS doesn't want to depend + * on AP's capability + */ + + pe_debug("populate QOS IE in Setup Request Frame"); + tdls_setup_req->QOSCapsStation.present = 1; + tdls_setup_req->QOSCapsStation.max_sp_length = 0; + tdls_setup_req->QOSCapsStation.qack = 0; + tdls_setup_req->QOSCapsStation.acbe_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + tdls_setup_req->QOSCapsStation.acbk_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + tdls_setup_req->QOSCapsStation.acvi_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + tdls_setup_req->QOSCapsStation.acvo_uapsd = + (mac->lim.gLimTDLSUapsdMask & 0x01); + } + + /* + * we will always try to init TDLS link with 11n capabilities + * let TDLS setup response to come, and we will set our caps based + * of peer caps + */ + + selfDot11Mode = mac->mlme_cfg->dot11_mode.dot11_mode; + + /* Populate HT/VHT Capabilities */ + + populate_dot11f_tdls_ht_vht_cap(mac, selfDot11Mode, + &tdls_setup_req->HTCaps, + &tdls_setup_req->VHTCaps, + pe_session); + lim_tdls_fill_setup_req_he_cap(mac, selfDot11Mode, tdls_setup_req, + pe_session); + /* Populate AID */ + populate_dotf_tdls_vht_aid(mac, selfDot11Mode, peer_mac, + &tdls_setup_req->AID, pe_session); + + if (wlan_vdev_mlme_is_mlo_vdev(pe_session->vdev)) + mlo_ie_len = lim_send_tdls_mgmt_frame_mlo(mac, pe_session); + + if (lim_is_session_eht_capable(pe_session)) { + eht_cap_ie = lim_ieee80211_pack_ehtcap_tdls(mac, pe_session, + &eht_cap_ie_len); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + qdf_mem_free(tdls_setup_req); + return QDF_STATUS_E_FAILURE; + } + } + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == mac->lim.gLimTDLSOffChannelEnabled) && + (!mlme_get_tdls_chan_switch_prohibited(pe_session->vdev))) { + populate_dot11f_tdls_offchannel_params(mac, pe_session, + &tdls_setup_req->SuppChannels, + &tdls_setup_req->SuppOperatingClasses); + if (mac->mlme_cfg->gen.band_capability != BIT(REG_BAND_2G)) { + tdls_setup_req->ht2040_bss_coexistence.present = 1; + tdls_setup_req->ht2040_bss_coexistence.info_request = 1; + } + } else { + pe_debug("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled: %d tdls_chan_swit_prohibited: %d", + mac->lim.gLimTDLSOffChannelEnabled, + mlme_get_tdls_chan_switch_prohibited(pe_session->vdev)); + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_req_size(mac, tdls_setup_req, + &payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a Setup Request (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a Setup Request (0x%08x)", + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nbytes = payload + ((IS_QOS_ENABLED(pe_session)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen + eht_cap_ie_len + + mlo_ie_len; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t)nbytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TDLS Setup Request", + nbytes); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(tdls_setup_req); + return QDF_STATUS_E_NOMEM; + } + + /* zero out the memory */ + qdf_mem_zero(frame, nbytes); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(mac, frame, + &tdls_setup_req->LinkIdentifier, + TDLS_LINK_AP, TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + pe_session); + + pe_debug("SupportedChnlWidth: %x rxMCSMap: %x rxMCSMap: %x txSupDataRate: %x", + tdls_setup_req->VHTCaps.supportedChannelWidthSet, + tdls_setup_req->VHTCaps.rxMCSMap, + tdls_setup_req->VHTCaps.txMCSMap, + tdls_setup_req->VHTCaps.txSupDataRate); + + status = dot11f_pack_tdls_setup_req(mac, tdls_setup_req, + frame + header_offset, + payload, &payload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS Setup request (0x%08x)", + status); + cds_packet_free((void *)packet); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(tdls_setup_req); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Setup Request (0x%08x)", + status); + } + + lim_cp_stats_cstats_log_setup_req_evt(tdls_setup_req, pe_session); + + qdf_mem_free(tdls_setup_req); + + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesn't */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + pe_debug("Copy Additional Ie Len = %d", addIeLen); + qdf_mem_copy(frame + header_offset + payload, addIe, + addIeLen); + payload += addIeLen; + } + + if (eht_cap_ie_len) { + /* Copy the EHT IE to the end of the frame */ + qdf_mem_copy(frame + header_offset + payload, + eht_cap_ie, eht_cap_ie_len); + qdf_mem_free(eht_cap_ie); + + payload += eht_cap_ie_len; + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + frame + header_offset + + payload); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + + payload += mlo_ie_len; + } + + pe_debug("[TDLS] action: %d (%s) -AP-> OTA peer="QDF_MAC_ADDR_FMT, + TDLS_SETUP_REQUEST, + lim_trace_tdls_action_string(TDLS_SETUP_REQUEST), + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + mac->lim.tdls_frm_session_id = pe_session->smeSessionId; + + vdev_id = lim_get_assoc_link_vdev_id(pe_session); + + lim_diag_mgmt_tx_event_report(mac, (tpSirMacMgmtHdr) frame, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(mac, packet, + (uint16_t)nbytes, + TID_AC_VI, + frame, + vdev_id, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->lim.tdls_frm_session_id = NO_SESSION; + pe_err("could not send TDLS Setup Request frame!"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} + +/* + * Send TDLS Teardown frame on Direct link or AP link, depends on reason code. + */ +static +QDF_STATUS lim_send_tdls_teardown_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + uint16_t reason, + uint8_t responder, + struct pe_session *pe_session, + uint8_t *addIe, uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSTeardown *teardown; + uint32_t status = 0; + uint32_t payload = 0; + uint32_t nbytes = 0; + uint32_t header_offset = 0; + uint8_t *frame; + void *packet; + uint8_t vdev_id; + QDF_STATUS qdf_status; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padlen = 0; +#endif + uint8_t smeSessionId = 0; + tpDphHashNode sta_ds; + uint16_t aid = 0; + uint8_t qos_mode = 0; + uint8_t tdls_link_type; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + teardown = qdf_mem_malloc(sizeof(*teardown)); + if (!teardown) { + pe_err("memory allocation failed for teardown"); + return QDF_STATUS_E_NOMEM; + } + + smeSessionId = pe_session->smeSessionId; + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). + */ + teardown->Category.category = ACTION_CATEGORY_TDLS; + teardown->Action.action = TDLS_TEARDOWN; + teardown->Reason.code = reason; + + populate_dot11f_link_iden(mac, pe_session, + LINK_IDEN_ADDR_OFFSET(teardown), + peer_mac, + (responder == + true) ? TDLS_RESPONDER : TDLS_INITIATOR); + + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_teardown_size(mac, teardown, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a discovery Request (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a discovery Request (0x%08x)", + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + sta_ds = dph_lookup_hash_entry(mac, pe_session->bssId, &aid, + &pe_session->dph.dphHashTable); + if (sta_ds) + qos_mode = sta_ds->qosMode; + + if (reason == REASON_TDLS_PEER_UNREACHABLE) + tdls_link_type = TDLS_LINK_AP; + else + tdls_link_type = TDLS_LINK_DIRECT; + + nbytes = payload + sizeof(eth_890d_header) + PAYLOAD_TYPE_TDLS_SIZE; + nbytes += addIeLen; + + if ((IS_QOS_ENABLED(pe_session) && tdls_link_type == TDLS_LINK_AP) || + (tdls_link_type == TDLS_LINK_DIRECT && qos_mode)) + nbytes += sizeof(tSirMacDataHdr3a); + else + nbytes += sizeof(tSirMacMgmtHdr); + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (payload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padlen = + MIN_IEEE_8023_SIZE - (payload + PAYLOAD_TYPE_TDLS_SIZE); + + /* + * if padlen is less than minimum vendorSpecific (5), + * pad up to 5 + */ + if (padlen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padlen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nbytes += padlen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t)nbytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TDLS Teardown Frame.", + nbytes); + qdf_mem_free(teardown); + return QDF_STATUS_E_NOMEM; + } + + /* zero out the memory */ + qdf_mem_zero(frame, nbytes); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + pe_debug("Reason of TDLS Teardown: %d", reason); + header_offset = lim_prepare_tdls_frame_header(mac, frame, + LINK_IDEN_ADDR_OFFSET(teardown), + (reason == REASON_TDLS_PEER_UNREACHABLE) ? + TDLS_LINK_AP : TDLS_LINK_DIRECT, + (responder == true) ? TDLS_RESPONDER : TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + pe_session); + + status = dot11f_pack_tdls_teardown(mac, teardown, frame + + header_offset, payload, &payload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS Teardown frame (0x%08x)", + status); + cds_packet_free((void *)packet); + qdf_mem_free(teardown); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Teardown frame (0x%08x)", + status); + } + + lim_cp_stats_cstats_log_tear_down_evt(teardown, pe_session); + + qdf_mem_free(teardown); + + if (addIeLen != 0) { + pe_debug("Copy Additional Ie Len = %d", addIeLen); + qdf_mem_copy(frame + header_offset + payload, addIe, + addIeLen); + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padlen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = + frame + header_offset + payload + addIeLen; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padlen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + pe_debug("Padding Vendor Specific Ie Len = %d", padlen); + + /* padding zero if more than 5 bytes are required */ + if (padlen > MIN_VENDOR_SPECIFIC_IE_SIZE) + qdf_mem_zero(frame + header_offset + payload + + addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, + padlen - MIN_VENDOR_SPECIFIC_IE_SIZE); + } +#endif + pe_debug("[TDLS] vdev:%d action: %d (%s) -%s-> OTA peer="QDF_MAC_ADDR_FMT, + pe_session->vdev_id, TDLS_TEARDOWN, + lim_trace_tdls_action_string(TDLS_TEARDOWN), + ((reason == REASON_TDLS_PEER_UNREACHABLE) ? "AP" : "DIRECT"), + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + mac->lim.tdls_frm_session_id = pe_session->smeSessionId; + + vdev_id = lim_get_assoc_link_vdev_id(pe_session); + + lim_diag_mgmt_tx_event_report(mac, (tpSirMacMgmtHdr)frame, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(mac, packet, + (uint16_t)nbytes, + TID_AC_VI, frame, vdev_id, + (reason == REASON_TDLS_PEER_UNREACHABLE) + ? true : false); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->lim.tdls_frm_session_id = NO_SESSION; + pe_err("could not send TDLS Teardown frame"); + return QDF_STATUS_E_FAILURE; + + } + + return QDF_STATUS_SUCCESS; +} + +/* + * Send Setup RSP frame on AP link. + */ +static QDF_STATUS +lim_send_tdls_setup_rsp_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + struct pe_session *pe_session, + etdlsLinkSetupStatus setupStatus, + uint8_t *addIe, uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSSetupRsp *setup_rsp; + uint32_t status = 0; + uint16_t caps = 0; + uint32_t nPayload = 0; + uint32_t header_offset = 0; + uint32_t nBytes = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; + uint32_t selfDot11Mode; + uint8_t max_sp_length = 0; + uint8_t vdev_id; +/* Placeholder to support different channel bonding mode of TDLS than AP. */ +/* Today, WNI_CFG_CHANNEL_BONDING_MODE will be overwritten when connecting to AP */ +/* To support this feature, we need to introduce WNI_CFG_TDLS_CHANNEL_BONDING_MODE */ +/* As of now, we hardcoded to max channel bonding of dot11Mode (i.e HT80 for 11ac/HT40 for 11n) */ +/* uint32_t tdlsChannelBondingMode; */ + uint8_t smeSessionId = 0; + uint16_t mlo_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + setup_rsp = qdf_mem_malloc(sizeof(*setup_rsp)); + if (!setup_rsp) { + pe_err("memory allocation failed for SetupRsp"); + return QDF_STATUS_E_NOMEM; + } + + smeSessionId = pe_session->smeSessionId; + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). + */ + + /* + * setup Fixed fields, + */ + setup_rsp->Category.category = ACTION_CATEGORY_TDLS; + setup_rsp->Action.action = TDLS_SETUP_RESPONSE; + setup_rsp->DialogToken.token = dialog; + + populate_dot11f_link_iden(mac, pe_session, + LINK_IDEN_ADDR_OFFSET(setup_rsp), peer_mac, + TDLS_RESPONDER); + + if (lim_get_capability_info(mac, &caps, pe_session) != + QDF_STATUS_SUCCESS) { + /* + * Could not get Capabilities value + * from CFG. Log error. + */ + pe_err("could not retrieve Capabilities value"); + } + swap_bit_field16(caps, (uint16_t *)&setup_rsp->Capabilities); + + if (QDF_STATUS_E_FAILURE == populate_dot11f_rates_tdls(mac, + &setup_rsp->SuppRates, + &setup_rsp->ExtSuppRates, + wlan_reg_freq_to_chan( + mac->pdev, pe_session->curr_op_freq))) + pe_err("could not populate supported data rates"); + + /* Populate extended capability IE */ + populate_dot11f_tdls_ext_capability(mac, + pe_session, + &setup_rsp->ExtCap); + + if (1 == mac->lim.gLimTDLSWmmMode) { + + pe_debug("populate WMM IE in Setup Response frame"); + max_sp_length = mac->mlme_cfg->wmm_params.max_sp_length; + /* include WMM IE */ + setup_rsp->WMMInfoStation.version = SIR_MAC_OUI_VERSION_1; + setup_rsp->WMMInfoStation.acvo_uapsd = + (mac->lim.gLimTDLSUapsdMask & 0x01); + setup_rsp->WMMInfoStation.acvi_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + setup_rsp->WMMInfoStation.acbk_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + setup_rsp->WMMInfoStation.acbe_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + setup_rsp->WMMInfoStation.max_sp_length = max_sp_length; + setup_rsp->WMMInfoStation.present = 1; + } else { + /* + * TODO: we need to see if we have to support conditions where + * we have EDCA parameter info element is needed a) if we need + * different QOS parameters for off channel operations or QOS + * is not supported on AP link and we wanted to QOS on direct + * link. + */ + /* Populate QOS info, needed for Peer U-APSD session */ + /* + * TODO: Now hardcoded, because + * populate_dot11f_qos_caps_station() depends on AP's + * capability, and TDLS doesn't want to depend on AP's + * capability + */ + pe_debug("populate QOS IE in Setup Response frame"); + setup_rsp->QOSCapsStation.present = 1; + setup_rsp->QOSCapsStation.max_sp_length = 0; + setup_rsp->QOSCapsStation.qack = 0; + setup_rsp->QOSCapsStation.acbe_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x08) >> 3); + setup_rsp->QOSCapsStation.acbk_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x04) >> 2); + setup_rsp->QOSCapsStation.acvi_uapsd = + ((mac->lim.gLimTDLSUapsdMask & 0x02) >> 1); + setup_rsp->QOSCapsStation.acvo_uapsd = + (mac->lim.gLimTDLSUapsdMask & 0x01); + } + + selfDot11Mode = mac->mlme_cfg->dot11_mode.dot11_mode; + + /* Populate HT/VHT Capabilities */ + populate_dot11f_tdls_ht_vht_cap(mac, selfDot11Mode, &setup_rsp->HTCaps, + &setup_rsp->VHTCaps, pe_session); + + lim_tdls_fill_setup_rsp_he_cap(mac, selfDot11Mode, setup_rsp, + pe_session); + /* Populate AID */ + populate_dotf_tdls_vht_aid(mac, selfDot11Mode, peer_mac, + &setup_rsp->AID, pe_session); + + if (wlan_vdev_mlme_is_mlo_vdev(pe_session->vdev)) + mlo_ie_len = lim_send_tdls_mgmt_frame_mlo(mac, pe_session); + + if (lim_is_session_eht_capable(pe_session)) { + eht_cap_ie = lim_ieee80211_pack_ehtcap_tdls(mac, pe_session, + &eht_cap_ie_len); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + qdf_mem_free(setup_rsp); + return QDF_STATUS_E_FAILURE; + } + } + + /* Populate TDLS offchannel param only if offchannel is enabled + * and TDLS Channel Switching is not prohibited by AP in ExtCap + * IE in assoc/re-assoc response. + */ + if ((1 == mac->lim.gLimTDLSOffChannelEnabled) && + (!mlme_get_tdls_chan_switch_prohibited(pe_session->vdev))) { + populate_dot11f_tdls_offchannel_params(mac, pe_session, + &setup_rsp->SuppChannels, + &setup_rsp-> + SuppOperatingClasses); + if (mac->mlme_cfg->gen.band_capability != BIT(REG_BAND_2G)) { + setup_rsp->ht2040_bss_coexistence.present = 1; + setup_rsp->ht2040_bss_coexistence.info_request = 1; + } + } else { + pe_debug("TDLS offchan not enabled, or channel switch prohibited by AP, gLimTDLSOffChannelEnabled: %d tdls_chan_swit_prohibited: %d", + mac->lim.gLimTDLSOffChannelEnabled, + mlme_get_tdls_chan_switch_prohibited(pe_session->vdev)); + } + setup_rsp->Status.status = setupStatus; + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_rsp_size(mac, setup_rsp, + &nPayload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a Setup Response (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for Setup Response (0x%08x)", + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(pe_session)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen + eht_cap_ie_len + + mlo_ie_len; + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TDLS Setup Response", + nBytes); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(setup_rsp); + return QDF_STATUS_E_NOMEM; + } + + /* zero out the memory */ + qdf_mem_zero(pFrame, nBytes); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(mac, pFrame, + LINK_IDEN_ADDR_OFFSET(setup_rsp), TDLS_LINK_AP, + TDLS_RESPONDER, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + pe_session); + + pe_debug("SupportedChnlWidth: %x rxMCSMap: %x rxMCSMap: %x txSupDataRate: %x", + setup_rsp->VHTCaps.supportedChannelWidthSet, + setup_rsp->VHTCaps.rxMCSMap, setup_rsp->VHTCaps.txMCSMap, + setup_rsp->VHTCaps.txSupDataRate); + status = dot11f_pack_tdls_setup_rsp(mac, setup_rsp, + pFrame + header_offset, + nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS Setup Response (0x%08x)", + status); + cds_packet_free((void *)pPacket); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(setup_rsp); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Setup Response (0x%08x)", + status); + } + + lim_cp_stats_cstats_log_setup_resp_evt(setup_rsp, pe_session); + + qdf_mem_free(setup_rsp); + + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesn't */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + nPayload += addIeLen; + } + + if (eht_cap_ie_len) { + /* Copy the EHT IE to the end of the frame */ + qdf_mem_copy(pFrame + header_offset + nPayload, + eht_cap_ie, eht_cap_ie_len); + qdf_mem_free(eht_cap_ie); + + nPayload += eht_cap_ie_len; + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + pFrame + header_offset + + nPayload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + + nPayload += mlo_ie_len; + } + + pe_debug("[TDLS] vdev:%d action: %d (%s) -AP-> OTA peer="QDF_MAC_ADDR_FMT, + pe_session->vdev_id, TDLS_SETUP_RESPONSE, + lim_trace_tdls_action_string(TDLS_SETUP_RESPONSE), + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + mac->lim.tdls_frm_session_id = pe_session->smeSessionId; + vdev_id = lim_get_assoc_link_vdev_id(pe_session); + lim_diag_mgmt_tx_event_report(mac, (tpSirMacMgmtHdr) pFrame, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(mac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + vdev_id, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->lim.tdls_frm_session_id = NO_SESSION; + pe_err("could not send TDLS Dis Request frame!"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * Send TDLS setup CNF frame on AP link + */ +static +QDF_STATUS lim_send_tdls_link_setup_cnf_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + uint8_t dialog, + uint32_t peerCapability, + struct pe_session *pe_session, + uint8_t *addIe, + uint16_t addIeLen, + enum wifi_traffic_ac ac) +{ + tDot11fTDLSSetupCnf *setup_cnf; + uint32_t status = 0; + uint32_t nPayload = 0; + uint32_t nBytes = 0; + uint32_t header_offset = 0; + uint8_t *pFrame; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t vdev_id; +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + uint32_t padLen = 0; +#endif + uint8_t smeSessionId = 0; + uint16_t mlo_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + setup_cnf = qdf_mem_malloc(sizeof(*setup_cnf)); + if (!setup_cnf) { + pe_err("memory allocation failed for SetupCnf"); + return QDF_STATUS_E_NOMEM; + } + + /* + * The scheme here is to fill out a 'tDot11fProbeRequest' structure + * and then hand it off to 'dot11f_pack_probe_request' (for + * serialization). We start by zero-initializing the structure: + */ + smeSessionId = pe_session->smeSessionId; + + /* + * setup Fixed fields, + */ + setup_cnf->Category.category = ACTION_CATEGORY_TDLS; + setup_cnf->Action.action = TDLS_SETUP_CONFIRM; + setup_cnf->DialogToken.token = dialog; + + populate_dot11f_link_iden(mac, pe_session, + LINK_IDEN_ADDR_OFFSET(setup_cnf), peer_mac, + TDLS_INITIATOR); + /* + * TODO: we need to see if we have to support conditions where we have + * EDCA parameter info element is needed a) if we need different QOS + * parameters for off channel operations or QOS is not supported on + * AP link and we wanted to QOS on direct link. + */ + + /* Check self and peer WMM capable */ + if ((1 == mac->lim.gLimTDLSWmmMode) && + (CHECK_BIT(peerCapability, TDLS_PEER_WMM_CAP))) { + pe_debug("populate WMM praram in Setup Confirm"); + populate_dot11f_wmm_params(mac, &setup_cnf->WMMParams, + pe_session); + } + + /* Check peer is VHT capable */ + if (CHECK_BIT(peerCapability, TDLS_PEER_VHT_CAP)) { + populate_dot11f_vht_operation(mac, + pe_session, + &setup_cnf->VHTOperation); + populate_dot11f_ht_info(mac, &setup_cnf->HTInfo, pe_session); + } else if (CHECK_BIT(peerCapability, TDLS_PEER_HT_CAP)) { /* Check peer is HT capable */ + populate_dot11f_ht_info(mac, &setup_cnf->HTInfo, pe_session); + } + + lim_tdls_fill_setup_cnf_he_op(mac, peerCapability, setup_cnf, + pe_session); + + if (wlan_vdev_mlme_is_mlo_vdev(pe_session->vdev)) + mlo_ie_len = lim_send_tdls_mgmt_frame_mlo(mac, pe_session); + + if (lim_is_session_eht_capable(pe_session)) { + eht_cap_ie = lim_ieee80211_pack_ehtcap_tdls(mac, pe_session, + &eht_cap_ie_len); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + qdf_mem_free(setup_cnf); + return QDF_STATUS_E_FAILURE; + } + } + /* + * now we pack it. First, how much space are we going to need? + */ + status = dot11f_get_packed_tdls_setup_cnf_size(mac, setup_cnf, + &nPayload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a Setup Confirm (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for Setup Confirm (0x%08x)", + status); + } + + /* + * This frame is going out from PE as data frames with special ethertype + * 89-0d. + * 8 bytes of RFC 1042 header + */ + + nBytes = nPayload + ((IS_QOS_ENABLED(pe_session)) + ? sizeof(tSirMacDataHdr3a) : + sizeof(tSirMacMgmtHdr)) + + sizeof(eth_890d_header) + + PAYLOAD_TYPE_TDLS_SIZE + addIeLen + eht_cap_ie_len + + mlo_ie_len; + +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + /* IOT issue with some AP : some AP doesn't like the data packet size < minimum 802.3 frame length (64) + Hence AP itself padding some bytes, which caused teardown packet is dropped at + receiver side. To avoid such IOT issue, we added some extra bytes to meet data frame size >= 64 + */ + if (nPayload + PAYLOAD_TYPE_TDLS_SIZE < MIN_IEEE_8023_SIZE) { + padLen = + MIN_IEEE_8023_SIZE - (nPayload + PAYLOAD_TYPE_TDLS_SIZE); + + /* if padLen is less than minimum vendorSpecific (5), pad up to 5 */ + if (padLen < MIN_VENDOR_SPECIFIC_IE_SIZE) + padLen = MIN_VENDOR_SPECIFIC_IE_SIZE; + + nBytes += padLen; + } +#endif + + /* Ok-- try to allocate memory from MGMT PKT pool */ + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TDLS Setup Confirm", + nBytes); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(setup_cnf); + return QDF_STATUS_E_NOMEM; + } + + /* zero out the memory */ + qdf_mem_zero(pFrame, nBytes); + + /* + * IE formation, memory allocation is completed, Now form TDLS discovery + * request frame + */ + + /* fill out the buffer descriptor */ + + header_offset = lim_prepare_tdls_frame_header(mac, pFrame, + LINK_IDEN_ADDR_OFFSET(setup_cnf), + TDLS_LINK_AP, + TDLS_INITIATOR, + (ac == WIFI_AC_VI) ? TID_AC_VI : TID_AC_BK, + pe_session); + + status = dot11f_pack_tdls_setup_cnf(mac, setup_cnf, pFrame + + header_offset, nPayload, &nPayload); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a TDLS discovery req (0x%08x)", status); + cds_packet_free((void *)pPacket); + qdf_mem_free(eht_cap_ie); + qdf_mem_free(setup_cnf); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing TDLS Discovery Request (0x%08x)", + status); + } + + lim_cp_stats_cstats_log_setup_confirm_evt(setup_cnf, pe_session); + + qdf_mem_free(setup_cnf); + + /* Copy the additional IE. */ + /* TODO : addIe is added at the end of the frame. This means it doesn't */ + /* follow the order. This should be ok, but we should consider changing this */ + /* if there is any IOT issue. */ + if (addIeLen != 0) { + qdf_mem_copy(pFrame + header_offset + nPayload, addIe, + addIeLen); + nPayload += addIeLen; + } + + if (eht_cap_ie_len) { + /* Copy the EHT IE to the end of the frame */ + qdf_mem_copy(pFrame + header_offset + nPayload, + eht_cap_ie, eht_cap_ie_len); + qdf_mem_free(eht_cap_ie); + + nPayload += eht_cap_ie_len; + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + pFrame + header_offset + + nPayload); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + + nPayload += mlo_ie_len; + } +#ifndef NO_PAD_TDLS_MIN_8023_SIZE + if (padLen != 0) { + /* QCOM VENDOR OUI = { 0x00, 0xA0, 0xC6, type = 0x0000 }; */ + uint8_t *padVendorSpecific = + pFrame + header_offset + nPayload + addIeLen; + /* make QCOM_VENDOR_OUI, and type = 0x0000, and all the payload to be zero */ + padVendorSpecific[0] = 221; + padVendorSpecific[1] = padLen - 2; + padVendorSpecific[2] = 0x00; + padVendorSpecific[3] = 0xA0; + padVendorSpecific[4] = 0xC6; + + pe_debug("Padding Vendor Specific Ie Len: %d", padLen); + + /* padding zero if more than 5 bytes are required */ + if (padLen > MIN_VENDOR_SPECIFIC_IE_SIZE) + qdf_mem_zero(pFrame + header_offset + nPayload + + addIeLen + MIN_VENDOR_SPECIFIC_IE_SIZE, + padLen - MIN_VENDOR_SPECIFIC_IE_SIZE); + } +#endif + + pe_debug("[TDLS] action: %d (%s) -AP-> OTA peer="QDF_MAC_ADDR_FMT, + TDLS_SETUP_CONFIRM, + lim_trace_tdls_action_string(TDLS_SETUP_CONFIRM), + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + mac->lim.tdls_frm_session_id = pe_session->smeSessionId; + vdev_id = lim_get_assoc_link_vdev_id(pe_session); + lim_diag_mgmt_tx_event_report(mac, (tpSirMacMgmtHdr) pFrame, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + qdf_status = wma_tx_frame_with_tx_complete_send(mac, pPacket, + (uint16_t) nBytes, + TID_AC_VI, + pFrame, + vdev_id, true); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->lim.tdls_frm_session_id = NO_SESSION; + pe_err("could not send TDLS Setup Confirm frame"); + return QDF_STATUS_E_FAILURE; + + } + + return QDF_STATUS_SUCCESS; +} + +/* This Function is similar to populate_dot11f_ht_caps, except that + * the HT Capabilities are considered from the AddStaReq rather from + * the cfg.dat as in populate_dot11f_ht_caps + */ +static QDF_STATUS +lim_tdls_populate_dot11f_ht_caps(struct mac_context *mac, + struct pe_session *pe_session, + struct tdls_add_sta_req *add_sta_req, + tDot11fIEHTCaps *pDot11f) +{ + uint32_t nCfgValue; + uint8_t nCfgValue8; + tSirMacHTParametersInfo *pHTParametersInfo; + union { + uint16_t nCfgValue16; + struct mlme_ht_capabilities_info ht_cap_info; + tSirMacExtendedHTCapabilityInfo extHtCapInfo; + } uHTCapabilityInfo; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + + nCfgValue = add_sta_req->ht_cap.hc_cap; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->advCodingCap = uHTCapabilityInfo.ht_cap_info.adv_coding_cap; + pDot11f->mimoPowerSave = uHTCapabilityInfo.ht_cap_info.mimo_power_save; + pDot11f->greenField = uHTCapabilityInfo.ht_cap_info.green_field; + pDot11f->shortGI20MHz = uHTCapabilityInfo.ht_cap_info.short_gi_20_mhz; + pDot11f->shortGI40MHz = uHTCapabilityInfo.ht_cap_info.short_gi_40_mhz; + pDot11f->txSTBC = uHTCapabilityInfo.ht_cap_info.tx_stbc; + pDot11f->rxSTBC = uHTCapabilityInfo.ht_cap_info.rx_stbc; + pDot11f->delayedBA = uHTCapabilityInfo.ht_cap_info.delayed_ba; + pDot11f->maximalAMSDUsize = + uHTCapabilityInfo.ht_cap_info.maximal_amsdu_size; + pDot11f->dsssCckMode40MHz = + uHTCapabilityInfo.ht_cap_info.dsss_cck_mode_40_mhz; + pDot11f->psmp = uHTCapabilityInfo.ht_cap_info.psmp; + pDot11f->stbcControlFrame = + uHTCapabilityInfo.ht_cap_info.stbc_control_frame; + pDot11f->lsigTXOPProtection = + uHTCapabilityInfo.ht_cap_info.l_sig_tx_op_protection; + + /* + * All sessionized entries will need the check below + * Only in case of NO session + */ + if (!pe_session) { + pDot11f->supportedChannelWidthSet = + uHTCapabilityInfo.ht_cap_info. + supported_channel_width_set; + } else { + pDot11f->supportedChannelWidthSet = + pe_session->htSupportedChannelWidthSet; + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + pe_debug("SupportedChnlWidth: %d, mimoPS: %d, GF: %d, shortGI20:%d, shortGI40: %d, dsssCck: %d", + pDot11f->supportedChannelWidthSet, + pDot11f->mimoPowerSave, + pDot11f->greenField, + pDot11f->shortGI20MHz, + pDot11f->shortGI40MHz, + pDot11f->dsssCckMode40MHz); + + nCfgValue = add_sta_req->ht_cap.ampdu_param; + + nCfgValue8 = (uint8_t) nCfgValue; + pHTParametersInfo = (tSirMacHTParametersInfo *) &nCfgValue8; + + pDot11f->maxRxAMPDUFactor = pHTParametersInfo->maxRxAMPDUFactor; + pDot11f->mpduDensity = pHTParametersInfo->mpduDensity; + pDot11f->reserved1 = pHTParametersInfo->reserved; + + pe_debug("AMPDU Param: %x", nCfgValue); + qdf_mem_copy(pDot11f->supportedMCSSet, add_sta_req->ht_cap.mcsset, + SIZE_OF_SUPPORTED_MCS_SET); + + nCfgValue = add_sta_req->ht_cap.extcap; + + uHTCapabilityInfo.nCfgValue16 = nCfgValue & 0xFFFF; + + pDot11f->pco = uHTCapabilityInfo.extHtCapInfo.pco; + pDot11f->transitionTime = uHTCapabilityInfo.extHtCapInfo.transitionTime; + pDot11f->mcsFeedback = uHTCapabilityInfo.extHtCapInfo.mcsFeedback; + + nCfgValue = add_sta_req->ht_cap.txbf_cap; + + pTxBFCapabilityInfo = (tSirMacTxBFCapabilityInfo *) &nCfgValue; + pDot11f->txBF = pTxBFCapabilityInfo->txBF; + pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; + pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; + pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; + pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; + pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; + pDot11f->calibration = pTxBFCapabilityInfo->calibration; + pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; + pDot11f->explicitUncompressedSteeringMatrix = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; + pDot11f->explicitBFCSIFeedback = + pTxBFCapabilityInfo->explicitBFCSIFeedback; + pDot11f->explicitUncompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; + pDot11f->explicitCompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; + pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; + pDot11f->uncompressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; + pDot11f->compressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; + + nCfgValue = add_sta_req->ht_cap.antenna; + + nCfgValue8 = (uint8_t) nCfgValue; + + pASCapabilityInfo = (tSirMacASCapabilityInfo *) &nCfgValue8; + pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; + pDot11f->explicitCSIFeedbackTx = + pASCapabilityInfo->explicitCSIFeedbackTx; + pDot11f->antennaIndicesFeedbackTx = + pASCapabilityInfo->antennaIndicesFeedbackTx; + pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; + pDot11f->antennaIndicesFeedback = + pASCapabilityInfo->antennaIndicesFeedback; + pDot11f->rxAS = pASCapabilityInfo->rxAS; + pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; + + pDot11f->present = add_sta_req->htcap_present; + + return QDF_STATUS_SUCCESS; + +} + +static QDF_STATUS +lim_tdls_populate_dot11f_vht_caps(struct mac_context *mac, + struct tdls_add_sta_req *add_sta_req, + tDot11fIEVHTCaps *pDot11f) +{ + uint32_t nCfgValue = 0; + union { + uint32_t nCfgValue32; + tSirMacVHTCapabilityInfo vhtCapInfo; + } uVHTCapabilityInfo; + union { + uint16_t nCfgValue16; + tSirMacVHTTxSupDataRateInfo vhtTxSupDataRateInfo; + tSirMacVHTRxSupDataRateInfo vhtRxsupDataRateInfo; + } uVHTSupDataRateInfo; + + pDot11f->present = add_sta_req->vhtcap_present; + + nCfgValue = add_sta_req->vht_cap.vht_capinfo; + uVHTCapabilityInfo.nCfgValue32 = nCfgValue; + + pDot11f->maxMPDULen = uVHTCapabilityInfo.vhtCapInfo.maxMPDULen; + pDot11f->supportedChannelWidthSet = + uVHTCapabilityInfo.vhtCapInfo.supportedChannelWidthSet; + pDot11f->ldpcCodingCap = uVHTCapabilityInfo.vhtCapInfo.ldpcCodingCap; + pDot11f->shortGI80MHz = uVHTCapabilityInfo.vhtCapInfo.shortGI80MHz; + pDot11f->shortGI160and80plus80MHz = + uVHTCapabilityInfo.vhtCapInfo.shortGI160and80plus80MHz; + pDot11f->txSTBC = uVHTCapabilityInfo.vhtCapInfo.txSTBC; + pDot11f->rxSTBC = uVHTCapabilityInfo.vhtCapInfo.rxSTBC; + pDot11f->suBeamFormerCap = 0; + pDot11f->suBeamformeeCap = 0; + pDot11f->csnofBeamformerAntSup = + uVHTCapabilityInfo.vhtCapInfo.csnofBeamformerAntSup; + pDot11f->numSoundingDim = uVHTCapabilityInfo.vhtCapInfo.numSoundingDim; + pDot11f->muBeamformerCap = 0; + pDot11f->muBeamformeeCap = 0; + pDot11f->vhtTXOPPS = uVHTCapabilityInfo.vhtCapInfo.vhtTXOPPS; + pDot11f->htcVHTCap = uVHTCapabilityInfo.vhtCapInfo.htcVHTCap; + pDot11f->maxAMPDULenExp = uVHTCapabilityInfo.vhtCapInfo.maxAMPDULenExp; + pDot11f->vhtLinkAdaptCap = + uVHTCapabilityInfo.vhtCapInfo.vhtLinkAdaptCap; + pDot11f->rxAntPattern = uVHTCapabilityInfo.vhtCapInfo.rxAntPattern; + pDot11f->txAntPattern = uVHTCapabilityInfo.vhtCapInfo.txAntPattern; + pDot11f->extended_nss_bw_supp = + uVHTCapabilityInfo.vhtCapInfo.extended_nss_bw_supp; + + pDot11f->rxMCSMap = add_sta_req->vht_cap.supp_mcs.rx_mcs_map; + + nCfgValue = add_sta_req->vht_cap.supp_mcs.rx_highest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->rxHighSupDataRate = + uVHTSupDataRateInfo.vhtRxsupDataRateInfo.rxSupDataRate; + pDot11f->max_nsts_total = + uVHTSupDataRateInfo.vhtRxsupDataRateInfo.max_nsts_total; + + pDot11f->txMCSMap = add_sta_req->vht_cap.supp_mcs.tx_mcs_map; + + nCfgValue = add_sta_req->vht_cap.supp_mcs.tx_highest; + uVHTSupDataRateInfo.nCfgValue16 = nCfgValue & 0xffff; + pDot11f->txSupDataRate = + uVHTSupDataRateInfo.vhtTxSupDataRateInfo.txSupDataRate; + + pDot11f->vht_extended_nss_bw_cap = + uVHTSupDataRateInfo.vhtTxSupDataRateInfo.vht_extended_nss_bw_cap; + + lim_log_vht_cap(mac, pDot11f); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +static void +lim_tdls_populate_eht_mcs(struct mac_context *mac_ctx, tpDphHashNode stads, + struct pe_session *session_entry) +{ + lim_populate_eht_mcs_set(mac_ctx, &stads->supportedRates, + &stads->eht_config, session_entry, + session_entry->ch_width); +} +#else +static void +lim_tdls_populate_eht_mcs(struct mac_context *mac_ctx, tpDphHashNode stads, + struct pe_session *session_entry) +{ +} +#endif + +/** + * lim_tdls_populate_matching_rate_set() - populate matching rate set + * + * @mac_ctx - global MAC context + * @stads - station hash entry + * @supp_rate_set - pointer to supported rate set + * @supp_rates_len - length of the supported rates + * @supp_mcs_set - pointer to supported MSC set + * @session_entry - pointer to PE session entry + * @vht_caps - pointer to VHT capability + * + * + * This function gets set of available rates from the config and compare them + * against the set of received supported rates. After the comparison station + * entry's rates is populated with 11A rates and 11B rates. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on failure. + */ +static QDF_STATUS +lim_tdls_populate_matching_rate_set(struct mac_context *mac_ctx, + tpDphHashNode stads, + uint8_t *supp_rate_set, + uint8_t supp_rates_len, + uint8_t *supp_mcs_set, + struct pe_session *session_entry, + tDot11fIEVHTCaps *vht_caps) +{ + tSirMacRateSet temp_rate_set; + uint32_t i, j, is_a_rate; + uint32_t phymode; + uint8_t mcsSet[SIZE_OF_SUPPORTED_MCS_SET]; + struct supported_rates *rates; + uint8_t a_rateindex = 0; + uint8_t b_rateindex = 0; + uint8_t nss; + qdf_size_t val_len; + + is_a_rate = 0; + + lim_get_phy_mode(mac_ctx, &phymode, NULL); + + /** + * Copy received rates in temp_rate_set, the parser has ensured + * unicity of the rates so there cannot be more than 12 . + */ + if (supp_rates_len > SIR_MAC_MAX_NUMBER_OF_RATES) { + pe_warn("Supported rates length: %d more than the Max limit, reset to Max", + supp_rates_len); + supp_rates_len = SIR_MAC_MAX_NUMBER_OF_RATES; + } + + for (i = 0; i < supp_rates_len; i++) + temp_rate_set.rate[i] = supp_rate_set[i]; + + temp_rate_set.numRates = supp_rates_len; + + rates = &stads->supportedRates; + qdf_mem_zero(rates, sizeof(*rates)); + + for (j = 0; j < temp_rate_set.numRates; j++) { + if ((b_rateindex > SIR_NUM_11B_RATES) || + (a_rateindex > SIR_NUM_11A_RATES)) { + pe_warn("Invalid number of rates (11b->%d, 11a->%d)", + b_rateindex, a_rateindex); + return QDF_STATUS_E_FAILURE; + } + if (sirIsArate(temp_rate_set.rate[j] & 0x7f)) { + is_a_rate = 1; + if (a_rateindex < SIR_NUM_11A_RATES) + rates->llaRates[a_rateindex++] = + temp_rate_set.rate[j]; + } else { + if (b_rateindex < SIR_NUM_11B_RATES) + rates->llbRates[b_rateindex++] = + temp_rate_set.rate[j]; + } + } + + if (wlan_reg_is_5ghz_ch_freq(session_entry->curr_op_freq)) + nss = mac_ctx->vdev_type_nss_5g.tdls; + else + nss = mac_ctx->vdev_type_nss_2g.tdls; + + nss = QDF_MIN(nss, mac_ctx->user_configured_nss); + + /* compute the matching MCS rate set, if peer is 11n capable and self mode is 11n */ +#ifdef FEATURE_WLAN_TDLS + if (stads->mlmStaContext.htCapability) +#else + if (IS_DOT11_MODE_HT(session_entry->dot11mode) && + (stads->mlmStaContext.htCapability)) +#endif + { + val_len = SIZE_OF_SUPPORTED_MCS_SET; + if (wlan_mlme_get_cfg_str( + mcsSet, + &mac_ctx->mlme_cfg->rates.supported_mcs_set, + &val_len) != QDF_STATUS_SUCCESS) { + /* Could not get rateset from CFG. Log error. */ + pe_err("could not retrieve supportedMCSSet"); + return QDF_STATUS_E_FAILURE; + } + + if (NSS_1x1_MODE == nss) + mcsSet[1] = 0; + for (i = 0; i < val_len; i++) + stads->supportedRates.supportedMCSSet[i] = + mcsSet[i] & supp_mcs_set[i]; + + pe_debug("MCS Rate Set Bitmap from CFG and DPH"); + for (i = 0; i < SIR_MAC_MAX_SUPPORTED_MCS_SET; i++) { + pe_debug("%x %x", mcsSet[i], + stads->supportedRates.supportedMCSSet[i]); + } + } + lim_populate_vht_mcs_set(mac_ctx, &stads->supportedRates, vht_caps, + session_entry, nss, NULL); + + lim_tdls_populate_eht_mcs(mac_ctx, stads, session_entry); + + lim_tdls_populate_he_matching_rate_set(mac_ctx, stads, nss, + session_entry); + /** + * Set the erpEnabled bit if the phy is in G mode and at least + * one A rate is supported + */ + if ((phymode == WNI_CFG_PHY_MODE_11G) && is_a_rate) + stads->erpEnabled = eHAL_SET; + + return QDF_STATUS_SUCCESS; +} + +static void lim_tdls_fill_session_vht_width(struct pe_session *pe_session, + tDphHashNode *sta) +{ + if (pe_session->ch_width) + sta->vhtSupportedChannelWidthSet = + pe_session->ch_width - 1; + else + sta->vhtSupportedChannelWidthSet = + pe_session->ch_width; +} + +static inline enum phy_ch_width +lim_reg_bw_to_ht_ch_width(uint16_t reg_max_bw) +{ + return reg_max_bw > 20 ? CH_WIDTH_40MHZ : CH_WIDTH_20MHZ; +} + +#ifdef WLAN_FEATURE_11BE +static void +lim_tdls_populate_dot11f_eht_caps(struct pe_session *pe_session, + tDphHashNode *sta, + struct tdls_add_sta_req *add_sta_req) +{ + if (add_sta_req->ehtcap_present) { + pe_debug("copy eht config from pe_session"); + qdf_mem_copy(&sta->eht_config, &pe_session->eht_config, + sizeof(sta->eht_config)); + qdf_mem_copy(&sta->eht_op, &pe_session->eht_op, + sizeof(sta->eht_op)); + } +} +#else +static inline void +lim_tdls_populate_dot11f_eht_caps(struct pe_session *pe_session, + tDphHashNode *sta, + struct tdls_add_sta_req *add_sta_req) +{ +} +#endif + +/* + * update HASH node entry info + */ +static void lim_tdls_update_hash_node_info(struct mac_context *mac, + tDphHashNode *sta, + struct tdls_add_sta_req *add_sta_req, + struct pe_session *pe_session) +{ + tDot11fIEHTCaps htCap = {0,}; + tDot11fIEHTCaps *htCaps; + tDot11fIEVHTCaps *pVhtCaps = NULL; + tDot11fIEVHTCaps *pVhtCaps_txbf = NULL; + tDot11fIEVHTCaps vhtCap; + uint8_t cbMode, selfDot11Mode; + bool wide_band_peer = false; + uint16_t reg_max_bw = 0; + uint16_t reg_ch_width = 0; + + if (add_sta_req->tdls_oper == TDLS_OPER_ADD) { + populate_dot11f_ht_caps(mac, pe_session, &htCap); + } else if (add_sta_req->tdls_oper == TDLS_OPER_UPDATE) { + lim_tdls_populate_dot11f_ht_caps(mac, NULL, + add_sta_req, &htCap); + sta->rmfEnabled = add_sta_req->is_pmf; + } + + lim_tdls_populate_dot11f_eht_caps(pe_session, sta, add_sta_req); + + reg_max_bw = wlan_reg_get_max_chwidth(mac->pdev, + pe_session->curr_op_freq); + + wide_band_peer = lim_is_wide_band_set(add_sta_req->extn_capability) && + wlan_cfg80211_tdls_is_fw_wideband_capable(pe_session->vdev); + selfDot11Mode = mac->mlme_cfg->dot11_mode.dot11_mode; + htCaps = &htCap; + if (htCaps->present && IS_DOT11_MODE_HT(selfDot11Mode)) { + sta->mlmStaContext.htCapability = 1; + sta->htGreenfield = htCaps->greenField; + /* + * sta->htSupportedChannelWidthSet should have the base + * channel capability. The htSupportedChannelWidthSet of the + * TDLS link on base channel should be less than or equal to + * channel width of STA-AP link. So take this setting from the + * pe_session. + */ + /* + * Since, now wideband is supported, bw should be restricted + * only in case of dfs channel + */ + pe_debug("peer htSupportedChannelWidthSet: 0x%x " + "pe session htSupportedChannelWidthSet: 0x%x", + htCaps->supportedChannelWidthSet, + pe_session->htSupportedChannelWidthSet); + + if (!wide_band_peer || + wlan_reg_is_dfs_for_freq(mac->pdev, + pe_session->curr_op_freq) || + wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) { + sta->htSupportedChannelWidthSet = + (htCaps->supportedChannelWidthSet < + pe_session->htSupportedChannelWidthSet) ? + htCaps->supportedChannelWidthSet : + pe_session->htSupportedChannelWidthSet; + } else { + reg_ch_width = lim_reg_bw_to_ht_ch_width(reg_max_bw); + + pe_debug("regulatory max bw %d MHz ch_width 0x%x", + reg_max_bw, + reg_ch_width); + + sta->htSupportedChannelWidthSet = + (htCaps->supportedChannelWidthSet < + reg_ch_width) ? + htCaps->supportedChannelWidthSet : + reg_ch_width; + } + + pe_debug("sta->htSupportedChannelWidthSet: 0x%x", + sta->htSupportedChannelWidthSet); + + sta->ch_width = sta->htSupportedChannelWidthSet; + sta->htMIMOPSState = htCaps->mimoPowerSave; + sta->htMaxAmsduLength = htCaps->maximalAMSDUsize; + sta->htAMpduDensity = htCaps->mpduDensity; + sta->htDsssCckRate40MHzSupport = htCaps->dsssCckMode40MHz; + sta->htShortGI20Mhz = htCaps->shortGI20MHz; + sta->htShortGI40Mhz = htCaps->shortGI40MHz; + sta->htMaxRxAMpduFactor = htCaps->maxRxAMPDUFactor; + lim_fill_rx_highest_supported_rate(mac, + &sta->supportedRates. + rxHighestDataRate, + htCaps->supportedMCSSet); + sta->ht_caps = add_sta_req->ht_cap.hc_cap; + } else { + sta->mlmStaContext.htCapability = 0; + } + lim_tdls_populate_dot11f_vht_caps(mac, add_sta_req, &vhtCap); + pVhtCaps = &vhtCap; + if (pVhtCaps->present && IS_DOT11_MODE_VHT(selfDot11Mode)) { + sta->mlmStaContext.vhtCapability = 1; + + /* + * 11.21.1 General: The channel width of the TDLS direct + * link on the base channel shall not exceed the channel + * width of the BSS to which the TDLS peer STAs are + * associated, if the base channel is dfs channel and peer is + * not wide band supported + */ + if (!wide_band_peer || + wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) { + lim_tdls_fill_session_vht_width(pe_session, sta); + } else { + if (pVhtCaps->supportedChannelWidthSet >= + VHT_CAP_NO_160M_SUPP) + sta->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + + if (wlan_reg_is_dfs_for_freq(mac->pdev, + pe_session->curr_op_freq)) { + lim_tdls_fill_session_vht_width(pe_session, + sta); + } + } + + if (sta->htSupportedChannelWidthSet) { + if (sta->vhtSupportedChannelWidthSet > + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + sta->ch_width = CH_WIDTH_160MHZ; + else + sta->ch_width = + sta->vhtSupportedChannelWidthSet + 1; + } else { + sta->ch_width = CH_WIDTH_20MHZ; + } + + pe_debug("vhtSupportedChannelWidthSet: %hu htSupportedChannelWidthSet: %hu sta_ch_width %d", + sta->vhtSupportedChannelWidthSet, + sta->htSupportedChannelWidthSet, + sta->ch_width); + + sta->vhtLdpcCapable = pVhtCaps->ldpcCodingCap; + sta->vhtBeamFormerCapable = 0; + pVhtCaps_txbf = (tDot11fIEVHTCaps *) (&add_sta_req->vht_cap); + pVhtCaps_txbf->suBeamformeeCap = 0; + pVhtCaps_txbf->suBeamFormerCap = 0; + pVhtCaps_txbf->muBeamformerCap = 0; + pVhtCaps_txbf->muBeamformeeCap = 0; + sta->vht_caps = add_sta_req->vht_cap.vht_capinfo; + } else { + sta->mlmStaContext.vhtCapability = 0; + sta->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } + + if (IS_DOT11_MODE_HE(selfDot11Mode)) + lim_tdls_update_node_he_caps(mac, add_sta_req, sta, pe_session, + wide_band_peer); + else + pe_debug("Not populating he cap as SelfDot11Mode not HE %d", + selfDot11Mode); + /* + * Calculate the Secondary Coannel Offset if our + * own channel bonding state is enabled + */ + if (pe_session->htSupportedChannelWidthSet) { + cbMode = lim_select_cb_mode(sta, pe_session, + wlan_reg_freq_to_chan( + mac->pdev, pe_session->curr_op_freq), + sta->vhtSupportedChannelWidthSet); + + if (sta->mlmStaContext.vhtCapability) + sta->htSecondaryChannelOffset = + lim_get_htcb_state(cbMode); + else + sta->htSecondaryChannelOffset = cbMode; + } + /* Lets enable QOS parameter */ + sta->qosMode = (add_sta_req->capability & CAPABILITIES_QOS_OFFSET) + || add_sta_req->htcap_present; + sta->wmeEnabled = 1; + sta->lleEnabled = 0; + /* TDLS Dummy AddSTA does not have qosInfo , is it OK ?? + */ + sta->qos.capability.qosInfo = + (*(tSirMacQosInfoStation *) &add_sta_req->uapsd_queues); + + /* populate matching rate set */ + + /* TDLS Dummy AddSTA does not have HTCap,VHTCap,Rates info , is it OK ?? + */ + + lim_tdls_populate_matching_rate_set(mac, sta, + add_sta_req->supported_rates, + add_sta_req->supported_rates_length, + add_sta_req->ht_cap.mcsset, + pe_session, pVhtCaps); + + lim_tdls_check_and_force_he_ldpc_cap(pe_session, sta); + + /* TDLS Dummy AddSTA does not have right capability , is it OK ?? + */ + sta->mlmStaContext.capabilityInfo = + (*(tSirMacCapabilityInfo *) &add_sta_req->capability); + + return; +} + +static QDF_STATUS lim_tdls_setup_add_sta(struct mac_context *mac, + struct tdls_add_sta_req *pAddStaReq, + struct pe_session *pe_session) +{ + tpDphHashNode sta = NULL; + struct wlan_objmgr_peer *peer; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t aid = 0; + uint8_t peer_vdev_id; + + sta = dph_lookup_hash_entry(mac, pAddStaReq->peermac.bytes, &aid, + &pe_session->dph.dphHashTable); + if (!sta && pAddStaReq->tdls_oper == TDLS_OPER_UPDATE) { + pe_err("vdev:%d TDLS update peer is given without peer creation", + pe_session->vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (sta && pAddStaReq->tdls_oper == TDLS_OPER_ADD) { + pe_err("vdev:%d TDLS entry for peer: " QDF_MAC_ADDR_FMT " already exist, cannot add new entry", + pe_session->vdev_id, + QDF_MAC_ADDR_REF(pAddStaReq->peermac.bytes)); + return QDF_STATUS_E_FAILURE; + } + + peer = wlan_objmgr_get_peer_by_mac(mac->psoc, pAddStaReq->peermac.bytes, + WLAN_TDLS_NB_ID); + if (peer) { + peer_vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + wlan_objmgr_peer_release_ref(peer, WLAN_TDLS_NB_ID); + + if (pAddStaReq->tdls_oper == TDLS_OPER_ADD) { + pe_err("vdev:%d peer: " QDF_MAC_ADDR_FMT " already exist on vdev:%d, cannot add new entry", + pe_session->vdev_id, + QDF_MAC_ADDR_REF(pAddStaReq->peermac.bytes), + peer_vdev_id); + return QDF_STATUS_E_EXISTS; + } + } + + if (sta && sta->staType != STA_ENTRY_TDLS_PEER) { + pe_err("Non TDLS entry for peer: "QDF_MAC_ADDR_FMT " already exist", + QDF_MAC_ADDR_REF(pAddStaReq->peermac.bytes)); + return QDF_STATUS_E_FAILURE; + } + + if (!sta) { + aid = lim_assign_peer_idx(mac, pe_session); + if (!aid) { + pe_err("No more free AID for peer: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pAddStaReq->peermac.bytes)); + return QDF_STATUS_E_FAILURE; + } + + /* Set the aid in peerAIDBitmap as it has been assigned to TDLS peer */ + SET_PEER_AID_BITMAP(pe_session->peerAIDBitmap, aid); + + pe_debug("Aid: %d, for peer: " QDF_MAC_ADDR_FMT, + aid, QDF_MAC_ADDR_REF(pAddStaReq->peermac.bytes)); + sta = dph_get_hash_entry(mac, aid, + &pe_session->dph.dphHashTable); + if (sta) { + /* asynchronous */ + lim_del_sta(mac, sta, false, pe_session); + lim_delete_dph_hash_entry(mac, sta->staAddr, aid, + pe_session); + } + + sta = dph_add_hash_entry(mac, pAddStaReq->peermac.bytes, + aid, &pe_session->dph.dphHashTable); + + if (!sta) { + pe_err("vdev::%d add hash entry failed", + pe_session->vdev_id); + CLEAR_PEER_AID_BITMAP(pe_session->peerAIDBitmap, aid); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + } + + lim_tdls_update_hash_node_info(mac, sta, pAddStaReq, pe_session); + sta->staType = STA_ENTRY_TDLS_PEER; + + status = lim_add_sta(mac, sta, + pAddStaReq->tdls_oper == TDLS_OPER_UPDATE, + pe_session); + if (QDF_IS_STATUS_ERROR(status)) { + CLEAR_PEER_AID_BITMAP(pe_session->peerAIDBitmap, aid); + QDF_ASSERT(0); + } + + return status; +} + +/* + * Del STA, after Link is teardown or discovery response sent on direct link + */ +static QDF_STATUS lim_tdls_del_sta(struct mac_context *mac, + struct qdf_mac_addr peerMac, + struct pe_session *pe_session, + bool resp_reqd) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint16_t peerIdx = 0; + tpDphHashNode sta; + + sta = dph_lookup_hash_entry(mac, peerMac.bytes, &peerIdx, + &pe_session->dph.dphHashTable); + + if (sta && sta->staType == STA_ENTRY_TDLS_PEER) + status = lim_del_sta(mac, sta, resp_reqd, pe_session); + else + pe_debug("TDLS peer "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(peerMac.bytes)); + + return status; +} + +/* + * Once Link is setup with PEER, send Add STA ind to SME + */ +static QDF_STATUS lim_send_sme_tdls_add_sta_rsp(struct mac_context *mac, + uint8_t sessionId, + tSirMacAddr peerMac, + uint8_t updateSta, + tDphHashNode *sta, uint8_t status) +{ + struct scheduler_msg msg = { 0 }; + struct tdls_add_sta_rsp *add_sta_rsp; + QDF_STATUS ret; + + msg.type = eWNI_SME_TDLS_ADD_STA_RSP; + + add_sta_rsp = qdf_mem_malloc(sizeof(*add_sta_rsp)); + if (!add_sta_rsp) + return QDF_STATUS_E_NOMEM; + + add_sta_rsp->session_id = sessionId; + add_sta_rsp->status_code = status; + + if (peerMac) + qdf_mem_copy(add_sta_rsp->peermac.bytes, + (uint8_t *) peerMac, QDF_MAC_ADDR_SIZE); + + if (updateSta) + add_sta_rsp->tdls_oper = TDLS_OPER_UPDATE; + else + add_sta_rsp->tdls_oper = TDLS_OPER_ADD; + + add_sta_rsp->psoc = mac->psoc; + msg.bodyptr = add_sta_rsp; + msg.callback = tgt_tdls_add_peer_rsp; + + ret = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(ret)) { + pe_err("post msg fail, %d", ret); + qdf_mem_free(add_sta_rsp); + } + + return ret; +} + +/* + * STA RSP received from HAL + */ +QDF_STATUS lim_process_tdls_add_sta_rsp(struct mac_context *mac, void *msg, + struct pe_session *pe_session) +{ + tAddStaParams *pAddStaParams = (tAddStaParams *) msg; + uint8_t status = QDF_STATUS_SUCCESS; + tDphHashNode *sta = NULL; + uint16_t aid = 0; + + SET_LIM_PROCESS_DEFD_MESGS(mac, true); + + sta = dph_lookup_hash_entry(mac, pAddStaParams->staMac, &aid, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("staMac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pAddStaParams->staMac)); + CLEAR_PEER_AID_BITMAP(pe_session->peerAIDBitmap, + pAddStaParams->assocId); + lim_release_peer_idx(mac, pAddStaParams->assocId, pe_session); + status = QDF_STATUS_E_FAILURE; + goto add_sta_error; + } + + if (pAddStaParams->status != QDF_STATUS_SUCCESS) { + pe_err("vdev:%d TDLS add sta failed", pe_session->vdev_id); + CLEAR_PEER_AID_BITMAP(pe_session->peerAIDBitmap, aid); + lim_release_peer_idx(mac, sta->assocId, pe_session); + + if (sta && + dph_delete_hash_entry(mac, pAddStaParams->staMac, + sta->assocId, + &pe_session->dph.dphHashTable)) + pe_err("Unable to delete Hash entry"); + + status = QDF_STATUS_E_FAILURE; + QDF_ASSERT(0); + goto add_sta_error; + } + + sta->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + sta->valid = 1; + pe_debug("vdev:%d sta_mac: " QDF_MAC_ADDR_FMT, + pe_session->vdev_id, + QDF_MAC_ADDR_REF(pAddStaParams->staMac)); + +add_sta_error: + status = lim_send_sme_tdls_add_sta_rsp(mac, pe_session->smeSessionId, + pAddStaParams->staMac, + pAddStaParams->updateSta, sta, + status); + qdf_mem_free(pAddStaParams); + return status; +} + +/** + * lim_send_tdls_comp_mgmt_rsp() - Send Response to upper layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued + * eWNI_SME_msg_type_REQ message + * @vdev_id: vdev id + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_START_RSP, eWNI_SME_STOP_BSS_RSP + * or eWNI_SME_SWITCH_CHL_RSP messages to applications above MAC + * Software. + * + * Return: None + */ + +static void +lim_send_tdls_comp_mgmt_rsp(struct mac_context *mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t vdev_id) +{ + struct scheduler_msg msg = {0}; + struct tdls_send_mgmt_rsp *sme_rsp; + QDF_STATUS status; + + pe_debug("vdev:%d Sending message %s with reasonCode %s", vdev_id, + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + sme_rsp = qdf_mem_malloc(sizeof(*sme_rsp)); + if (!sme_rsp) + return; + + sme_rsp->status_code = (enum legacy_result_code)result_code; + sme_rsp->vdev_id = vdev_id; + sme_rsp->psoc = mac_ctx->psoc; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.callback = tgt_tdls_send_mgmt_rsp; + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("post msg fail, %d", status); + qdf_mem_free(sme_rsp); + } +} + +QDF_STATUS lim_process_sme_tdls_mgmt_send_req(struct mac_context *mac_ctx, + void *msg) +{ + struct tdls_send_mgmt_request *send_req = msg; + struct pe_session *session_entry; + uint8_t session_id; + uint16_t ie_len; + tSirResultCodes result_code = eSIR_SME_INVALID_PARAMETERS; + + pe_debug("Send Mgmt Received"); + session_entry = pe_find_session_by_bssid(mac_ctx, + send_req->bssid.bytes, + &session_id); + if (!session_entry) { + pe_err("PE Session does not exist for given sme session_id %d", + send_req->session_id); + goto lim_tdls_send_mgmt_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(session_entry)) { + pe_err("send mgmt received in wrong system Role: %d", + GET_LIM_SYSTEM_ROLE(session_entry)); + goto lim_tdls_send_mgmt_error; + } + + if (lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry)) { + pe_err("roaming in progress, reject mgmt! for session %d", + send_req->session_id); + result_code = eSIR_SME_REFUSED; + goto lim_tdls_send_mgmt_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((session_entry->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (session_entry->limSmeState != eLIM_SME_LINK_EST_STATE)) { + pe_err("send mgmt received in invalid LIMsme state: %d", + session_entry->limSmeState); + goto lim_tdls_send_mgmt_error; + } + + cds_tdls_tx_rx_mgmt_event(ACTION_CATEGORY_TDLS, + SIR_MAC_ACTION_TX, SIR_MAC_MGMT_ACTION, + send_req->req_type, send_req->peer_mac.bytes); + + ie_len = send_req->length - sizeof(*send_req); + + switch (send_req->req_type) { + case TDLS_DISCOVERY_REQUEST: + pe_debug("Transmit Discovery Request Frame"); + /* format TDLS discovery request frame and transmit it */ + lim_send_tdls_dis_req_frame(mac_ctx, send_req->peer_mac, + send_req->dialog, session_entry, + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case TDLS_DISCOVERY_RESPONSE: + pe_debug("Transmit Discovery Response Frame"); + /* Send a response mgmt action frame */ + lim_send_tdls_dis_rsp_frame(mac_ctx, send_req->peer_mac, + send_req->dialog, session_entry, + send_req->add_ie, ie_len); + result_code = eSIR_SME_SUCCESS; + break; + case TDLS_SETUP_REQUEST: + pe_debug("Transmit Setup Request Frame"); + lim_send_tdls_link_setup_req_frame(mac_ctx, + send_req->peer_mac, + send_req->dialog, + session_entry, + send_req->add_ie, ie_len, + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case TDLS_SETUP_RESPONSE: + pe_debug("Transmit Setup Response Frame"); + lim_send_tdls_setup_rsp_frame(mac_ctx, + send_req->peer_mac, + send_req->dialog, session_entry, + send_req->status_code, + send_req->add_ie, ie_len, + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case TDLS_SETUP_CONFIRM: + pe_debug("Transmit Setup Confirm Frame"); + lim_send_tdls_link_setup_cnf_frame(mac_ctx, + send_req->peer_mac, + send_req->dialog, + send_req->peer_capability, + session_entry, + send_req->add_ie, ie_len, + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case TDLS_TEARDOWN: + pe_debug("Transmit Teardown Frame"); + lim_send_tdls_teardown_frame(mac_ctx, + send_req->peer_mac, + send_req->status_code, + send_req->responder, + session_entry, + send_req->add_ie, ie_len, + send_req->ac); + result_code = eSIR_SME_SUCCESS; + break; + case TDLS_PEER_TRAFFIC_INDICATION: + break; + case TDLS_CHANNEL_SWITCH_REQUEST: + break; + case TDLS_CHANNEL_SWITCH_RESPONSE: + break; + case TDLS_PEER_TRAFFIC_RESPONSE: + break; + default: + break; + } + +lim_tdls_send_mgmt_error: + lim_send_tdls_comp_mgmt_rsp(mac_ctx, eWNI_SME_TDLS_SEND_MGMT_RSP, + result_code, send_req->session_id); + + return QDF_STATUS_SUCCESS; +} + +/* + * Once link is teardown, send Del Peer Ind to SME + */ +static QDF_STATUS lim_send_sme_tdls_del_sta_rsp(struct mac_context *mac, + uint8_t sessionId, + struct qdf_mac_addr peerMac, + tDphHashNode *sta, uint8_t status) +{ + struct scheduler_msg msg = { 0 }; + struct tdls_del_sta_rsp *del_sta_rsp; + QDF_STATUS ret; + + msg.type = eWNI_SME_TDLS_DEL_STA_RSP; + + del_sta_rsp = qdf_mem_malloc(sizeof(*del_sta_rsp)); + if (!del_sta_rsp) + return QDF_STATUS_E_NOMEM; + + del_sta_rsp->session_id = sessionId; + del_sta_rsp->status_code = status; + + qdf_copy_macaddr(&del_sta_rsp->peermac, &peerMac); + + del_sta_rsp->psoc = mac->psoc; + msg.bodyptr = del_sta_rsp; + msg.callback = tgt_tdls_del_peer_rsp; + ret = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(ret)) { + pe_err("post msg fail, %d", ret); + qdf_mem_free(del_sta_rsp); + } + + return ret; +} + +QDF_STATUS lim_process_sme_tdls_add_sta_req(struct mac_context *mac, + void *msg) +{ + struct tdls_add_sta_req *add_sta_req = msg; + struct pe_session *pe_session; + uint8_t session_id; + + pe_debug("vdev:%d TDLS Add STA Request Received", + add_sta_req->session_id); + pe_session = + pe_find_session_by_bssid(mac, add_sta_req->bssid.bytes, + &session_id); + if (!pe_session) { + pe_err("PE Session does not exist for given sme sessionId: %d", + add_sta_req->session_id); + goto lim_tdls_add_sta_error; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("send mgmt received in wrong system Role: %d", + GET_LIM_SYSTEM_ROLE(pe_session)); + goto lim_tdls_add_sta_error; + } + + if (lim_is_roam_synch_in_progress(mac->psoc, pe_session)) { + pe_err("roaming in progress, reject add sta! for session %d", + add_sta_req->session_id); + goto lim_tdls_add_sta_error; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((pe_session->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (pe_session->limSmeState != eLIM_SME_LINK_EST_STATE)) { + pe_err("send mgmt received in invalid LIMsme state: %d", + pe_session->limSmeState); + goto lim_tdls_add_sta_error; + } + + + /* To start with, send add STA request to HAL */ + if (QDF_STATUS_E_FAILURE == lim_tdls_setup_add_sta(mac, add_sta_req, pe_session)) { + pe_err("Add TDLS Station request failed"); + goto lim_tdls_add_sta_error; + } + return QDF_STATUS_SUCCESS; +lim_tdls_add_sta_error: + lim_send_sme_tdls_add_sta_rsp(mac, + add_sta_req->session_id, + add_sta_req->peermac.bytes, + (add_sta_req->tdls_oper == TDLS_OPER_UPDATE), + NULL, QDF_STATUS_E_FAILURE); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_process_sme_tdls_del_sta_req(struct mac_context *mac, + void *msg) +{ + struct tdls_del_sta_req *del_sta_req = msg; + struct pe_session *pe_session; + uint8_t session_id; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirMacAddr peer; + + pe_debug("TDLS Delete STA Request Received"); + pe_session = + pe_find_session_by_bssid(mac, del_sta_req->bssid.bytes, + &session_id); + if (!pe_session) { + pe_err("PE Session does not exist for given vdev id: %d", + del_sta_req->session_id); + lim_send_sme_tdls_del_sta_rsp(mac, del_sta_req->session_id, + del_sta_req->peermac, NULL, + QDF_STATUS_E_FAILURE); + return QDF_STATUS_E_FAILURE; + } + + /* check if we are in proper state to work as TDLS client */ + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_err("Del sta received in wrong system Role %d", + GET_LIM_SYSTEM_ROLE(pe_session)); + goto lim_tdls_del_sta_error; + } + + if (lim_is_roam_synch_in_progress(mac->psoc, pe_session)) { + pe_err("roaming in progress, reject del sta! for session %d", + del_sta_req->session_id); + lim_send_sme_tdls_del_sta_rsp(mac, del_sta_req->session_id, + del_sta_req->peermac, NULL, + QDF_STATUS_E_FAILURE); + return QDF_STATUS_E_FAILURE; + } + + /* + * if we are still good, go ahead and check if we are in proper state to + * do TDLS discovery req/rsp/....frames. + */ + if ((pe_session->limSmeState != eLIM_SME_ASSOCIATED_STATE) && + (pe_session->limSmeState != eLIM_SME_LINK_EST_STATE)) { + + pe_err("Del Sta received in invalid LIMsme state: %d", + pe_session->limSmeState); + goto lim_tdls_del_sta_error; + } + + qdf_mem_copy(peer, del_sta_req->peermac.bytes, sizeof(tSirMacAddr)); + lim_send_deauth_mgmt_frame(mac, REASON_DEAUTH_NETWORK_LEAVING, + peer, pe_session, false); + status = lim_tdls_del_sta(mac, del_sta_req->peermac, + pe_session, true); + if (status == QDF_STATUS_SUCCESS) + return status; + +lim_tdls_del_sta_error: + lim_send_sme_tdls_del_sta_rsp(mac, pe_session->smeSessionId, + del_sta_req->peermac, NULL, QDF_STATUS_E_FAILURE); + + return status; +} + +/** + * lim_check_aid_and_delete_peer() - Function to check aid and delete peer + * @p_mac: pointer to mac context + * @session_entry: pointer to PE session + * + * This function verifies aid and delete's peer with that aid from hash table + * + * Return: None + */ +static void lim_check_aid_and_delete_peer(struct mac_context *p_mac, + struct pe_session *session_entry) +{ + tpDphHashNode stads = NULL; + int i, aid; + size_t aid_bitmap_size = sizeof(session_entry->peerAIDBitmap); + struct qdf_mac_addr mac_addr; + QDF_STATUS status; + /* + * Check all the set bit in peerAIDBitmap and delete the peer + * (with that aid) entry from the hash table and add the aid + * in free pool + */ + for (i = 0; i < aid_bitmap_size / sizeof(uint32_t); i++) { + for (aid = 0; aid < (sizeof(uint32_t) << 3); aid++) { + if (!CHECK_BIT(session_entry->peerAIDBitmap[i], aid)) + continue; + stads = dph_get_hash_entry(p_mac, + (aid + i * (sizeof(uint32_t) << 3)), + &session_entry->dph.dphHashTable); + + if (!stads) + goto skip; + + pe_err("Deleting "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(stads->staAddr)); + + if (!lim_is_roam_synch_in_progress(p_mac->psoc, + session_entry)) + lim_send_deauth_mgmt_frame( + p_mac, + REASON_DEAUTH_NETWORK_LEAVING, + stads->staAddr, session_entry, false); + + /* Delete TDLS peer */ + qdf_mem_copy(mac_addr.bytes, stads->staAddr, + QDF_MAC_ADDR_SIZE); + + status = lim_tdls_del_sta(p_mac, mac_addr, + session_entry, false); + + dph_delete_hash_entry(p_mac, + stads->staAddr, stads->assocId, + &session_entry->dph.dphHashTable); +skip: + lim_release_peer_idx(p_mac, + (aid + i * (sizeof(uint32_t) << 3)), + session_entry); + CLEAR_BIT(session_entry->peerAIDBitmap[i], aid); + } + } +} + +void lim_update_tdls_set_state_for_fw(struct pe_session *session_entry, + bool value) +{ + session_entry->tdls_send_set_state_disable = value; +} + +void lim_update_tdls_2g_bw(struct pe_session *session) +{ + struct wlan_objmgr_psoc *psoc = NULL; + + /* + * For 2.4 GHz band, if AP switches its BW from 40 MHz to 20 Mhz, it + * changes its beacon respectivily with ch_width 20 Mhz without STA + * disconnection. + * This will result in TDLS remaining on 40 MHz and not following APs BW + * on 2.4 GHz. + * Better Teardown the link here and with traffic going on between peers + * the tdls connection will again be restablished with the new BW + */ + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + return; + + psoc = wlan_vdev_get_psoc(session->vdev); + if (!psoc) + return; + + wlan_tdls_teardown_links(psoc); +} + +/** + * lim_delete_tdls_peers() - delete tdls peers + * + * @mac_ctx - global MAC context + * @session_entry - PE session entry + * + * Delete all the TDLS peer connected before leaving the BSS + * + * Return: QDF_STATUS_SUCCESS on success, error code otherwise + */ +QDF_STATUS lim_delete_tdls_peers(struct mac_context *mac_ctx, + struct pe_session *session_entry) +{ + + if (!session_entry) { + pe_err("NULL session_entry"); + return QDF_STATUS_E_FAILURE; + } + + lim_check_aid_and_delete_peer(mac_ctx, session_entry); + + tgt_tdls_delete_all_peers_indication(mac_ctx->psoc, + session_entry->vdev_id); + + if (lim_is_roam_synch_in_progress(mac_ctx->psoc, session_entry)) + return QDF_STATUS_SUCCESS; + + /* + * For Link Switch disconnect, TDLS set state to disable will be sent + * to firmware after the disconnect complete indication. So don't + * send TDLS set state disable from here. + */ + if (mlo_mgr_is_link_switch_in_progress(session_entry->vdev)) + return QDF_STATUS_SUCCESS; + + /* + * In case of CSA, Only peers in lim and TDLS component + * needs to be removed and set state disable command + * should not be sent to fw as there is no way to enable + * TDLS in FW after vdev restart. + */ + if (session_entry->tdls_send_set_state_disable) + tgt_tdls_peers_deleted_notification(mac_ctx->psoc, + session_entry->smeSessionId); + + /* reset the set_state_disable flag */ + session_entry->tdls_send_set_state_disable = true; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev) +{ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct pe_session *session; + + if (!mac) + return QDF_STATUS_E_FAILURE; + + session = pe_find_session_by_vdev_id(mac, wlan_vdev_get_id(vdev)); + if (!session) { + pe_debug("No pe_session found for vdev_id:%d", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_FAILURE; + } + + return lim_delete_tdls_peers(mac, session); +} + +QDF_STATUS +lim_process_sme_del_all_tdls_peers(struct mac_context *p_mac, uint32_t *msg_buf) +{ + struct tdls_del_all_tdls_peers *msg; + struct pe_session *session_entry; + uint8_t session_id; + + msg = (struct tdls_del_all_tdls_peers *)msg_buf; + if (!msg) { + pe_err("NULL msg"); + return QDF_STATUS_E_FAILURE; + } + + session_entry = pe_find_session_by_bssid(p_mac, + msg->bssid.bytes, &session_id); + if (!session_entry) { + pe_debug("NULL pe_session"); + return QDF_STATUS_E_FAILURE; + } + + lim_check_aid_and_delete_peer(p_mac, session_entry); + + tgt_tdls_peers_deleted_notification(p_mac->psoc, + session_entry->smeSessionId); + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_process_tdls_del_sta_rsp() - Handle WDA_DELETE_STA_RSP for TDLS + * @mac_ctx: Global MAC context + * @lim_msg: LIM message + * @pe_session: PE session + * + * Return: None + */ +void lim_process_tdls_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg, + struct pe_session *session_entry) +{ + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr; + tpDphHashNode sta_ds; + uint16_t peer_idx = 0; + struct qdf_mac_addr peer_mac; + + if (!del_sta_params) { + pe_err("del_sta_params is NULL"); + return; + } + + qdf_mem_copy(peer_mac.bytes, + del_sta_params->staMac, QDF_MAC_ADDR_SIZE); + + sta_ds = dph_lookup_hash_entry(mac_ctx, del_sta_params->staMac, + &peer_idx, &session_entry->dph.dphHashTable); + if (!sta_ds) { + pe_err("DPH Entry for STA: %X is missing release the serialization command", + DPH_STA_HASH_INDEX_PEER); + lim_send_sme_tdls_del_sta_rsp(mac_ctx, + session_entry->smeSessionId, + peer_mac, NULL, + QDF_STATUS_SUCCESS); + goto skip_event; + } + + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + pe_err("DEL STA failed!"); + lim_send_sme_tdls_del_sta_rsp(mac_ctx, + session_entry->smeSessionId, + peer_mac, NULL, QDF_STATUS_E_FAILURE); + goto skip_event; + } + + pe_debug("DEL STA success"); + + /* now send indication to SME-->HDD->TL to remove STA from TL */ + + lim_send_sme_tdls_del_sta_rsp(mac_ctx, session_entry->smeSessionId, + peer_mac, sta_ds, + QDF_STATUS_SUCCESS); + lim_release_peer_idx(mac_ctx, sta_ds->assocId, session_entry); + + /* Clear the aid in peerAIDBitmap as this aid is now in freepool */ + CLEAR_PEER_AID_BITMAP(session_entry->peerAIDBitmap, + sta_ds->assocId); + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, sta_ds->assocId, + session_entry); + +skip_event: + qdf_mem_free(del_sta_params); + lim_msg->bodyptr = NULL; +} + + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c new file mode 100644 index 0000000000..8500ad3e86 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.c @@ -0,0 +1,900 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_prop_exts_utils.cc contains the utility functions + * to populate, parse proprietary extensions required to + * support ANI feature set. + * + * Author: Chandra Modumudi + * Date: 11/27/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "ani_global.h" +#include "wni_cfg.h" +#include "sir_common.h" +#include "sir_debug.h" +#include "utils_api.h" +#include "lim_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_trace.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "wma.h" +#include "wlan_utility.h" + +#ifdef FEATURE_WLAN_ESE +/** + * get_local_power_constraint_probe_response() - extracts local constraint + * from probe response + * @beacon_struct: beacon structure + * @local_constraint: local constraint pointer + * @session: A pointer to session entry. + * + * Return: None + */ +static void get_local_power_constraint_probe_response( + tpSirProbeRespBeacon beacon_struct, + int8_t *local_constraint, + struct pe_session *session) +{ + if (beacon_struct->eseTxPwr.present) + *local_constraint = + beacon_struct->eseTxPwr.power_limit; +} + +/** + * get_ese_version_ie_probe_response() - extracts ESE version IE + * from probe response + * @mac_ctx: MAC context + * @beacon_struct: beacon structure + * @session: A pointer to session entry. + * + * Return: None + */ +static void get_ese_version_ie_probe_response(struct mac_context *mac_ctx, + tpSirProbeRespBeacon beacon_struct, + struct pe_session *session) +{ + if (mac_ctx->mlme_cfg->lfr.ese_enabled) + session->is_ese_version_ie_present = + beacon_struct->is_ese_ver_ie_present; +} +#else +static void get_local_power_constraint_probe_response( + tpSirProbeRespBeacon beacon_struct, + int8_t *local_constraint, + struct pe_session *session) +{ + +} + +static inline void get_ese_version_ie_probe_response(struct mac_context *mac_ctx, + tpSirProbeRespBeacon beacon_struct, + struct pe_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_11AX +static void lim_extract_he_op(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{ + uint8_t fw_vht_ch_wd; + uint8_t ap_bcon_ch_width; + uint8_t center_freq_diff; + + if (!session->he_capable) + return; + if (!beacon_struct->he_op.present) { + return; + } + qdf_mem_copy(&session->he_op, &beacon_struct->he_op, + sizeof(session->he_op)); + if (!session->he_6ghz_band) + return; + if (!session->he_op.oper_info_6g_present) { + session->ap_defined_power_type_6g = REG_CURRENT_MAX_AP_TYPE; + return; + } + session->ch_width = session->he_op.oper_info_6g.info.ch_width; + session->ch_center_freq_seg0 = + session->he_op.oper_info_6g.info.center_freq_seg0; + session->ch_center_freq_seg1 = + session->he_op.oper_info_6g.info.center_freq_seg1; + session->ap_defined_power_type_6g = + session->he_op.oper_info_6g.info.reg_info; + if (session->ap_defined_power_type_6g < REG_INDOOR_AP || + session->ap_defined_power_type_6g > REG_MAX_SUPP_AP_TYPE) { + session->ap_defined_power_type_6g = REG_CURRENT_MAX_AP_TYPE; + pe_debug("AP power type invalid, defaulting to MAX_AP_TYPE"); + } + + pe_debug("6G op info: ch_wd %d cntr_freq_seg0 %d cntr_freq_seg1 %d", + session->ch_width, session->ch_center_freq_seg0, + session->ch_center_freq_seg1); + + if (!session->ch_center_freq_seg1) + return; + + fw_vht_ch_wd = wma_get_vht_ch_width(); + if (fw_vht_ch_wd <= WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + session->ch_width = CH_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + return; + } + center_freq_diff = abs(session->ch_center_freq_seg1 - + session->ch_center_freq_seg0); + if (center_freq_diff == 8) { + ap_bcon_ch_width = CH_WIDTH_160MHZ; + } else if (center_freq_diff > 16) { + ap_bcon_ch_width = CH_WIDTH_80P80MHZ; + } else { + session->ch_width = CH_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + return; + } + + if ((ap_bcon_ch_width == CH_WIDTH_80P80MHZ) && + (fw_vht_ch_wd != WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ)) { + session->ch_width = CH_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + } +} + +static bool lim_validate_he160_mcs_map(struct mac_context *mac_ctx, + uint16_t peer_rx, uint16_t peer_tx, + uint8_t nss) +{ + uint16_t rx_he_mcs_map; + uint16_t tx_he_mcs_map; + uint16_t he_mcs_map; + + he_mcs_map = *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160); + rx_he_mcs_map = HE_INTERSECT_MCS(peer_rx, he_mcs_map); + + he_mcs_map = *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160); + tx_he_mcs_map = HE_INTERSECT_MCS(peer_tx, he_mcs_map); + + if (nss == NSS_1x1_MODE) { + rx_he_mcs_map |= HE_MCS_INV_MSK_4_NSS(1); + tx_he_mcs_map |= HE_MCS_INV_MSK_4_NSS(1); + } else if (nss == NSS_2x2_MODE) { + rx_he_mcs_map |= (HE_MCS_INV_MSK_4_NSS(1) & + HE_MCS_INV_MSK_4_NSS(2)); + tx_he_mcs_map |= (HE_MCS_INV_MSK_4_NSS(1) & + HE_MCS_INV_MSK_4_NSS(2)); + } + + return ((rx_he_mcs_map != HE_MCS_ALL_DISABLED) && + (tx_he_mcs_map != HE_MCS_ALL_DISABLED)); +} + +static void lim_check_is_he_mcs_valid(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{ + uint8_t i; + uint16_t mcs_map; + + if (!session->he_capable || !beacon_struct->he_cap.present) + return; + + mcs_map = beacon_struct->he_cap.rx_he_mcs_map_lt_80; + for (i = 0; i < session->nss; i++) { + if (((mcs_map >> (i * 2)) & 0x3) != 0x3) + return; + } + session->he_capable = false; + if (session->vhtCapability) + session->dot11mode = MLME_DOT11_MODE_11AC; + else + session->dot11mode = MLME_DOT11_MODE_11N; + pe_err("vdev %d: Invalid LT80 MCS map 0x%x with NSS %d, falback to dot11mode %d", + session->vdev_id, mcs_map, session->nss, session->dot11mode); +} + +void lim_update_he_bw_cap_mcs(struct pe_session *session, + tSirProbeRespBeacon *beacon) +{ + uint8_t is_80mhz; + uint8_t sta_prefer_80mhz_over_160mhz; + + if (!session->he_capable) + return; + + sta_prefer_80mhz_over_160mhz = + session->mac_ctx->mlme_cfg->sta.sta_prefer_80mhz_over_160mhz; + if ((session->opmode == QDF_STA_MODE || + session->opmode == QDF_P2P_CLIENT_MODE) && + beacon && beacon->he_cap.present) { + if (!beacon->he_cap.chan_width_2) { + is_80mhz = 1; + } else if (beacon->he_cap.chan_width_2 && + !lim_validate_he160_mcs_map(session->mac_ctx, + *((uint16_t *)beacon->he_cap.rx_he_mcs_map_160), + *((uint16_t *)beacon->he_cap.tx_he_mcs_map_160), + session->nss)) { + is_80mhz = 1; + if (session->ch_width == CH_WIDTH_160MHZ) { + pe_debug("HE160 Rx/Tx MCS is not valid, falling back to 80MHz"); + session->ch_width = CH_WIDTH_80MHZ; + } + } else if (sta_prefer_80mhz_over_160mhz == + STA_PREFER_BW_80MHZ) { + is_80mhz = 1; + if (session->ch_width == CH_WIDTH_160MHZ) { + pe_debug("STA preferred HE80 over HE160, falling back to 80MHz"); + session->ch_width = CH_WIDTH_80MHZ; + } + } else { + is_80mhz = 0; + } + } else { + is_80mhz = 1; + } + + if (session->ch_width <= CH_WIDTH_80MHZ && is_80mhz) { + session->he_config.chan_width_2 = 0; + session->he_config.chan_width_3 = 0; + } else if (session->ch_width == CH_WIDTH_160MHZ) { + session->he_config.chan_width_3 = 0; + } + /* Reset the > 20MHz caps for 20MHz connection */ + if (session->ch_width == CH_WIDTH_20MHZ) { + session->he_config.chan_width_0 = 0; + session->he_config.chan_width_1 = 0; + session->he_config.chan_width_2 = 0; + session->he_config.chan_width_3 = 0; + session->he_config.chan_width_4 = 0; + session->he_config.chan_width_5 = 0; + session->he_config.chan_width_6 = 0; + session->he_config.he_ppdu_20_in_40Mhz_2G = 0; + session->he_config.he_ppdu_20_in_160_80p80Mhz = 0; + session->he_config.he_ppdu_80_in_160_80p80Mhz = 0; + } + if (WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq)) { + session->he_config.chan_width_1 = 0; + session->he_config.chan_width_2 = 0; + session->he_config.chan_width_3 = 0; + session->he_config.chan_width_5 = 0; + session->he_config.chan_width_6 = 0; + } else { + session->he_config.chan_width_0 = 0; + session->he_config.chan_width_4 = 0; + session->he_config.chan_width_6 = 0; + } + if (!session->he_config.chan_width_2) { + session->he_config.bfee_sts_gt_80 = 0; + session->he_config.num_sounding_gt_80 = 0; + session->he_config.he_ppdu_20_in_160_80p80Mhz = 0; + session->he_config.he_ppdu_80_in_160_80p80Mhz = 0; + *(uint16_t *)session->he_config.rx_he_mcs_map_160 = + HE_MCS_ALL_DISABLED; + *(uint16_t *)session->he_config.tx_he_mcs_map_160 = + HE_MCS_ALL_DISABLED; + } + if (!session->he_config.chan_width_3) { + *(uint16_t *)session->he_config.rx_he_mcs_map_80_80 = + HE_MCS_ALL_DISABLED; + *(uint16_t *)session->he_config.tx_he_mcs_map_80_80 = + HE_MCS_ALL_DISABLED; + } +} + +void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t he_mcs_12_13_map) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev not found for id: %d", vdev_id); + return; + } + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_set_he_mcs_12_13_map(vdev, he_mcs_12_13_map); + wlan_vdev_obj_unlock(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} +#else +static inline void lim_extract_he_op(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{} +static void lim_check_is_he_mcs_valid(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{ +} + +void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t he_mcs_12_13_map) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +void lim_extract_eht_op(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{ + uint32_t max_eht_bw; + + if (!session->eht_capable) + return; + + if (!beacon_struct->eht_op.present) + return; + + if (!beacon_struct->eht_op.eht_op_information_present) + return; + + qdf_mem_copy(&session->eht_op, &beacon_struct->eht_op, + sizeof(session->eht_op)); + + max_eht_bw = wma_get_eht_ch_width(); + + if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_320) { + if (max_eht_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) { + session->ch_width = CH_WIDTH_320MHZ; + } else if (max_eht_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + session->ch_width = CH_WIDTH_160MHZ; + } else { + session->ch_width = CH_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + } + } else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_160) { + if (max_eht_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + session->ch_width = CH_WIDTH_160MHZ; + } else { + session->ch_width = CH_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + } + } else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_80) { + session->ch_width = CH_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + } else if (session->eht_op.channel_width == WLAN_EHT_CHWIDTH_40) { + session->ch_width = CH_WIDTH_40MHZ; + session->ch_center_freq_seg1 = 0; + } else { + session->ch_width = CH_WIDTH_20MHZ; + session->ch_center_freq_seg1 = 0; + } + + session->ch_center_freq_seg0 = session->eht_op.ccfs0; + session->ch_center_freq_seg1 = session->eht_op.ccfs1; +} + +void lim_update_eht_bw_cap_mcs(struct pe_session *session, + tSirProbeRespBeacon *beacon) +{ + if (!session->eht_capable) + return; + + if ((session->opmode == QDF_STA_MODE || + session->opmode == QDF_P2P_CLIENT_MODE) && + beacon && beacon->eht_cap.present) { + if (!beacon->eht_cap.support_320mhz_6ghz) + session->eht_config.support_320mhz_6ghz = 0; + if (!beacon->eht_cap.support_320mhz_6ghz || + !beacon->eht_cap.su_beamformer) + session->eht_config.num_sounding_dim_320mhz = 0; + } +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +void lim_objmgr_update_emlsr_caps(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, tpSirAssocRsp assoc_rsp) +{ + struct wlan_objmgr_vdev *vdev; + bool ap_emlsr_cap = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev not found for id: %d", vdev_id); + return; + } + + /* Check for assoc link vdev to extract emlsr cap from assoc rsp */ + if (!wlan_vdev_mlme_is_mlo_link_vdev(vdev)) { + ap_emlsr_cap = + assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.emlsr_support; + + if (!(wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_EMLSR_CAP) && + ap_emlsr_cap)) { + if (!wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_EMLSR_CAP) + && ap_emlsr_cap) + pe_debug("No eMLSR STA supp but recvd EML caps in assc rsp"); + else + pe_debug("EML caps not present in assoc rsp"); + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_cap_clear(vdev, WLAN_VDEV_C_EMLSR_CAP); + wlan_vdev_obj_unlock(vdev); + } else { + pe_debug("EML caps present in assoc rsp"); + } + } else { + pe_debug("no change required for link vdev"); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} +#endif + +void lim_objmgr_update_vdev_nss(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t nss) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev not found for id: %d", vdev_id); + return; + } + wlan_vdev_obj_lock(vdev); + wlan_vdev_mlme_set_nss(vdev, nss); + wlan_vdev_obj_unlock(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +#ifdef WLAN_ADAPTIVE_11R +/** + * lim_extract_adaptive_11r_cap() - check if the AP has adaptive 11r + * IE + * @ie: Pointer to the IE + * @ie_len: ie Length + * + * Return: True if adaptive 11r IE is present + */ +static bool lim_extract_adaptive_11r_cap(uint8_t *ie, uint16_t ie_len) +{ + const uint8_t *adaptive_ie; + uint8_t data; + bool adaptive_11r; + + adaptive_ie = wlan_get_vendor_ie_ptr_from_oui(LIM_ADAPTIVE_11R_OUI, + LIM_ADAPTIVE_11R_OUI_SIZE, + ie, ie_len); + if (!adaptive_ie) + return false; + + if ((adaptive_ie[1] < (OUI_LENGTH + 1)) || + (adaptive_ie[1] > MAX_ADAPTIVE_11R_IE_LEN)) + return false; + + data = *(adaptive_ie + OUI_LENGTH + 2); + adaptive_11r = (data & 0x1) ? true : false; + + return adaptive_11r; +} + +#else +static inline bool lim_extract_adaptive_11r_cap(uint8_t *ie, uint16_t ie_len) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_11AX +static void lim_check_peer_ldpc_and_update(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{ + /* + * In 2.4G if AP supports HE till MCS 0-9 we can associate + * with HE mode instead downgrading to 11ac + */ + if (session->he_capable && + WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq) && + beacon_struct->he_cap.present && + lim_check_he_80_mcs11_supp(session, &beacon_struct->he_cap) && + !beacon_struct->he_cap.ldpc_coding) { + session->he_capable = false; + pe_err("LDPC check failed for HE operation"); + if (session->vhtCapability) { + session->dot11mode = MLME_DOT11_MODE_11AC; + pe_debug("Update dot11mode to 11ac"); + } else { + session->dot11mode = MLME_DOT11_MODE_11N; + pe_debug("Update dot11mode to 11N"); + } + } +} +#else +static void lim_check_peer_ldpc_and_update(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{} +#endif + +static +void lim_update_ch_width_for_p2p_client(struct mac_context *mac, + struct pe_session *session, + uint32_t ch_freq) +{ + struct ch_params ch_params = {0}; + + if (session->dot11mode < MLME_DOT11_MODE_11AC) + return; + /* + * Some IOT AP's/P2P-GO's (e.g. make: Wireless-AC 9560160MHz as P2P GO), + * send beacon with 20mhz and assoc resp with 80mhz and + * after assoc resp, next beacon also has 80mhz. + * Connection is expected to happen in better possible + * bandwidth(80MHz in this case). + * Start the vdev with max supported ch_width in order to support this. + * It'll be downgraded to appropriate ch_width or the same would be + * continued based on assoc resp. + * Restricting this check for p2p client and 5G only and this may be + * extended to STA based on wider testing results with multiple AP's. + * Limit it to 80MHz as 80+80 is channel specific and 160MHz is not + * supported in p2p. + */ + ch_params.ch_width = CH_WIDTH_80MHZ; + + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, ch_freq, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params.ch_width == CH_WIDTH_20MHZ) + ch_params.sec_ch_offset = PHY_SINGLE_CHANNEL_CENTERED; + + session->htSupportedChannelWidthSet = ch_params.sec_ch_offset ? 1 : 0; + session->htRecommendedTxWidthSet = session->htSupportedChannelWidthSet; + session->htSecondaryChannelOffset = ch_params.sec_ch_offset; + session->ch_width = ch_params.ch_width; + session->ch_center_freq_seg0 = ch_params.center_freq_seg0; + session->ch_center_freq_seg1 = ch_params.center_freq_seg1; + pe_debug("Start P2P_CLI in ch freq %d max supported ch_width: %u cbmode: %u seg0: %u, seg1: %u", + ch_freq, ch_params.ch_width, ch_params.sec_ch_offset, + session->ch_center_freq_seg0, session->ch_center_freq_seg1); +} + +void lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie, + uint16_t ie_len, uint8_t *qos_cap, + uint8_t *uapsd, int8_t *local_constraint, + struct pe_session *session, + bool *is_pwr_constraint) +{ + tSirProbeRespBeacon *beacon_struct; + uint8_t ap_bcon_ch_width; + bool new_ch_width_dfn = false; + tDot11fIEVHTOperation *vht_op; + uint8_t fw_vht_ch_wd; + uint8_t vht_ch_wd; + uint8_t center_freq_diff; + struct s_ext_cap *ext_cap; + uint8_t chan_center_freq_seg1; + tDot11fIEVHTCaps *vht_caps; + uint8_t channel = 0; + uint8_t sta_prefer_80mhz_over_160mhz; + struct mlme_vht_capabilities_info *mlme_vht_cap; + QDF_STATUS status; + + beacon_struct = qdf_mem_malloc(sizeof(tSirProbeRespBeacon)); + if (!beacon_struct) + return; + + *qos_cap = 0; + *uapsd = 0; + sta_prefer_80mhz_over_160mhz = + session->mac_ctx->mlme_cfg->sta.sta_prefer_80mhz_over_160mhz; + + status = sir_parse_beacon_ie(mac_ctx, beacon_struct, p_ie, + (uint32_t)ie_len); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("sir_parse_beacon_ie failed to parse beacon"); + qdf_mem_free(beacon_struct); + return; + } + + mlme_vht_cap = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + if (beacon_struct->wmeInfoPresent || + beacon_struct->wmeEdcaPresent || + beacon_struct->HTCaps.present) + LIM_BSS_CAPS_SET(WME, *qos_cap); + + if (LIM_BSS_CAPS_GET(WME, *qos_cap) && beacon_struct->wsmCapablePresent) + LIM_BSS_CAPS_SET(WSM, *qos_cap); + + if (beacon_struct->HTCaps.present) + mac_ctx->lim.htCapabilityPresentInBeacon = 1; + else + mac_ctx->lim.htCapabilityPresentInBeacon = 0; + + vht_op = &beacon_struct->VHTOperation; + vht_caps = &beacon_struct->VHTCaps; + if (IS_BSS_VHT_CAPABLE(beacon_struct->VHTCaps) && vht_op->present && + session->vhtCapability) { + session->vhtCapabilityPresentInBeacon = 1; + + if (((beacon_struct->Vendor1IEPresent && + beacon_struct->vendor_vht_ie.present && + beacon_struct->Vendor3IEPresent)) && + (((beacon_struct->VHTCaps.txMCSMap & VHT_MCS_3x3_MASK) == + VHT_MCS_3x3_MASK) && + ((beacon_struct->VHTCaps.txMCSMap & VHT_MCS_2x2_MASK) != + VHT_MCS_2x2_MASK))) + session->vht_config.su_beam_formee = 0; + } else { + session->vhtCapabilityPresentInBeacon = 0; + } + + if (session->vhtCapabilityPresentInBeacon == 1 && + !session->htSupportedChannelWidthSet) { + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable_txbf_20mhz) + session->vht_config.su_beam_formee = 0; + + if (session->opmode == QDF_P2P_CLIENT_MODE && + !wlan_reg_is_24ghz_ch_freq(beacon_struct->chan_freq) && + mac_ctx->roam.configParam.channelBondingMode5GHz) + lim_update_ch_width_for_p2p_client( + mac_ctx, session, + beacon_struct->chan_freq); + + } else if (session->vhtCapabilityPresentInBeacon && vht_op->chanWidth) { + /* If VHT is supported min 80 MHz support is must */ + ap_bcon_ch_width = vht_op->chanWidth; + if (vht_caps->vht_extended_nss_bw_cap) { + if (!vht_caps->extended_nss_bw_supp) + chan_center_freq_seg1 = + vht_op->chan_center_freq_seg1; + else + chan_center_freq_seg1 = + beacon_struct->HTInfo.chan_center_freq_seg2; + } else { + chan_center_freq_seg1 = vht_op->chan_center_freq_seg1; + } + if (chan_center_freq_seg1 && + (ap_bcon_ch_width == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ)) { + new_ch_width_dfn = true; + if (chan_center_freq_seg1 > + vht_op->chan_center_freq_seg0) + center_freq_diff = chan_center_freq_seg1 - + vht_op->chan_center_freq_seg0; + else + center_freq_diff = vht_op->chan_center_freq_seg0 - + chan_center_freq_seg1; + if (center_freq_diff == 8) + ap_bcon_ch_width = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + else if (center_freq_diff > 16) + ap_bcon_ch_width = + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + else + ap_bcon_ch_width = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + } + + fw_vht_ch_wd = wma_get_vht_ch_width(); + vht_ch_wd = QDF_MIN(fw_vht_ch_wd, ap_bcon_ch_width); + + if ((vht_ch_wd > WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) && + (ap_bcon_ch_width == + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) && + mlme_vht_cap->restricted_80p80_bw_supp) { + if ((chan_center_freq_seg1 == 138 && + vht_op->chan_center_freq_seg0 == 155) || + (vht_op->chan_center_freq_seg0 == 138 && + chan_center_freq_seg1 == 155)) + vht_ch_wd = + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + else + vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + } + /* + * If the supported channel width is greater than 80MHz and + * AP supports Nss > 1 in 160MHz mode then connect the STA + * in 2x2 80MHz mode instead of connecting in 160MHz mode. + */ + if (vht_ch_wd > WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + if (sta_prefer_80mhz_over_160mhz == STA_PREFER_BW_80MHZ) + vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + else if ((sta_prefer_80mhz_over_160mhz == + STA_PREFER_BW_VHT80MHZ) && + (!(IS_VHT_NSS_1x1(beacon_struct->VHTCaps.txMCSMap)) && + (!IS_VHT_NSS_1x1(beacon_struct->VHTCaps.rxMCSMap)))) + vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + } + /* + * VHT OP IE old definition: + * vht_op->chan_center_freq_seg0: center freq of 80MHz/160MHz/ + * primary 80 in 80+80MHz. + * + * vht_op->chan_center_freq_seg1: center freq of secondary 80 + * in 80+80MHz. + * + * VHT OP IE NEW definition: + * vht_op->chan_center_freq_seg0: center freq of 80MHz/primary + * 80 in 80+80MHz/center freq of the 80 MHz channel segment + * that contains the primary channel in 160MHz mode. + * + * vht_op->chan_center_freq_seg1: center freq of secondary 80 + * in 80+80MHz/center freq of 160MHz. + */ + session->ch_center_freq_seg0 = vht_op->chan_center_freq_seg0; + session->ch_center_freq_seg1 = chan_center_freq_seg1; + channel = wlan_reg_freq_to_chan(mac_ctx->pdev, + beacon_struct->chan_freq); + if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + /* DUT or AP supports only 160MHz */ + if (ap_bcon_ch_width == + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) { + /* AP is in 160MHz mode */ + if (!new_ch_width_dfn) { + session->ch_center_freq_seg1 = + vht_op->chan_center_freq_seg0; + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel(channel); + } + } else { + /* DUT supports only 160MHz and AP is + * in 80+80 mode + */ + vht_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + session->ch_center_freq_seg1 = 0; + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel(channel); + } + } else if (vht_ch_wd == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) { + /* DUT or AP supports only 80MHz */ + session->ch_center_freq_seg0 = + lim_get_80Mhz_center_channel(channel); + session->ch_center_freq_seg1 = 0; + } + session->ch_width = vht_ch_wd + 1; + session->ap_ch_width = session->ch_width; + } + + if (session->vhtCapability && session->vhtCapabilityPresentInBeacon && + beacon_struct->ext_cap.present) { + ext_cap = (struct s_ext_cap *)beacon_struct->ext_cap.bytes; + session->gLimOperatingMode.present = + ext_cap->oper_mode_notification; + if (ext_cap->oper_mode_notification) { + uint8_t self_nss = 0; + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + self_nss = mac_ctx->vdev_type_nss_5g.sta; + else + self_nss = mac_ctx->vdev_type_nss_2g.sta; + + if (CH_WIDTH_160MHZ > session->ch_width) + session->gLimOperatingMode.chanWidth = + session->ch_width; + else + session->gLimOperatingMode.chanWidth = + CH_WIDTH_160MHZ; + /** Populate vdev nss in OMN ie of assoc requse for + * WFA CERT test scenario. + */ + if (ext_cap->beacon_protection_enable && + session->opmode == QDF_STA_MODE && + !session->nss_forced_1x1 && + lim_get_nss_supported_by_ap( + &beacon_struct->VHTCaps, + &beacon_struct->HTCaps, + &beacon_struct->he_cap) == NSS_1x1_MODE) + session->gLimOperatingMode.rxNSS = self_nss - 1; + else + session->gLimOperatingMode.rxNSS = + session->nss - 1; + } else { + pe_err("AP does not support op_mode rx"); + } + } + + lim_check_is_he_mcs_valid(session, beacon_struct); + lim_check_peer_ldpc_and_update(session, beacon_struct); + lim_extract_he_op(session, beacon_struct); + lim_extract_eht_op(session, beacon_struct); + if (!mac_ctx->usr_eht_testbed_cfg) + lim_update_he_bw_cap_mcs(session, beacon_struct); + lim_update_eht_bw_cap_mcs(session, beacon_struct); + /* Extract the UAPSD flag from WMM Parameter element */ + if (beacon_struct->wmeEdcaPresent) + *uapsd = beacon_struct->edcaParams.qosInfo.uapsd; + + if (mac_ctx->mlme_cfg->sta.allow_tpc_from_ap) { + if (beacon_struct->powerConstraintPresent) { + *local_constraint = + beacon_struct->localPowerConstraint. + localPowerConstraints; + *is_pwr_constraint = true; + } else { + get_local_power_constraint_probe_response( + beacon_struct, local_constraint, session); + *is_pwr_constraint = false; + } + } + + get_ese_version_ie_probe_response(mac_ctx, beacon_struct, session); + + session->country_info_present = false; + /* Initializing before first use */ + if (beacon_struct->countryInfoPresent) + session->country_info_present = true; + /* Check if Extended caps are present in probe resp or not */ + if (beacon_struct->ext_cap.present) + session->is_ext_caps_present = true; + /* Update HS 2.0 Information Element */ + if (beacon_struct->hs20vendor_ie.present) { + pe_debug("HS20 Indication Element Present, rel#: %u id: %u", + beacon_struct->hs20vendor_ie.release_num, + beacon_struct->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&session->hs20vendor_ie, + &beacon_struct->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(beacon_struct->hs20vendor_ie.hs_id)); + if (beacon_struct->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&session->hs20vendor_ie.hs_id, + &beacon_struct->hs20vendor_ie.hs_id, + sizeof(beacon_struct->hs20vendor_ie.hs_id)); + } + + lim_objmgr_update_vdev_nss(mac_ctx->psoc, session->smeSessionId, + session->nss); + + session->is_adaptive_11r_connection = + lim_extract_adaptive_11r_cap(p_ie, ie_len); + qdf_mem_free(beacon_struct); + return; +} /****** end lim_extract_ap_capability() ******/ + +/** + * lim_get_htcb_state + * + ***FUNCTION: + * This routing provides the translation of Airgo Enum to HT enum for determining + * secondary channel offset. + * Airgo Enum is required for backward compatibility purposes. + * + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @return The corresponding HT enumeration + */ +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode) +{ + switch (aniCBMode) { + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + return PHY_SINGLE_CHANNEL_CENTERED; + default: + return PHY_SINGLE_CHANNEL_CENTERED; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h new file mode 100644 index 0000000000..92913058c3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_prop_exts_utils.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011-2014, 2016, 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_prop_exts_utils.h contains the definitions + * used by all LIM modules to support proprietary features. + * Author: Chandra Modumudi + * Date: 12/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __LIM_PROP_EXTS_UTILS_H +#define __LIM_PROP_EXTS_UTILS_H + +#define LIM_ADAPTIVE_11R_OUI "\x00\x40\x96\x2C" +#define LIM_ADAPTIVE_11R_OUI_SIZE 4 + +/** + * lim_extract_ap_capability() - extract AP's HCF/WME/WSM capability + * @mac_ctx: Pointer to Global MAC structure + * @p_ie: Pointer to starting IE in Beacon/Probe Response + * @ie_len: Length of all IEs combined + * @qos_cap: Bits are set according to capabilities + * @uapsd: pointer to uapsd + * @local_constraint: Pointer to local power constraint. + * @session: A pointer to session entry. + * @is_pwr_constraint: Check for Power constraint bit in beacon + * + * This function is called to extract AP's HCF/WME/WSM capability + * from the IEs received from it in Beacon/Probe Response frames + * + * Return: None + */ +void +lim_extract_ap_capability(struct mac_context *mac_ctx, uint8_t *p_ie, + uint16_t ie_len, uint8_t *qos_cap, uint8_t *uapsd, + int8_t *local_constraint, struct pe_session *session, + bool *is_pwr_constraint); + +#ifdef WLAN_FEATURE_11BE +/** + * lim_extract_eht_op() - Extract EHT operation IE into session + * @session: Pointer to pe_session + * @beacon_struct: Pointer to extracted beacon/probe response of the + * AP + * + * Return: None + */ +void lim_extract_eht_op(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct); +#else +static inline void +lim_extract_eht_op(struct pe_session *session, + tSirProbeRespBeacon *beacon_struct) +{} +#endif + +ePhyChanBondState lim_get_htcb_state(ePhyChanBondState aniCBMode); + +/** + * lim_objmgr_update_vdev_nss() - update nss in vdev object + * @psoc: Pointer to Global MAC structure + * @vdev_id: vdev id + * @nss: nss + * + * Return: None + */ +void lim_objmgr_update_vdev_nss(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint8_t nss); + +/** + * lim_update_he_mcs_12_13_map() - update he_mcs_12_13_map in vdev object + * @psoc: Pointer to Global MAC structure + * @vdev_id: vdev id + * @he_mcs_12_13_map: he mcs 12/13 map + * + * Return: None + */ +void lim_update_he_mcs_12_13_map(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, uint16_t he_mcs_12_13_map); + +#ifdef WLAN_FEATURE_11BE_MLO +void lim_objmgr_update_emlsr_caps(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, tpSirAssocRsp assoc_rsp); +#else +static inline +void lim_objmgr_update_emlsr_caps(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, tpSirAssocRsp assoc_rsp) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ +#endif /* __LIM_PROP_EXTS_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c new file mode 100644 index 0000000000..350e7a2c6c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_reassoc_utils.c @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: lim_reassoc_utils.c + * + * Host based roaming re-association utilities + */ + +#include "cds_api.h" +#include "ani_global.h" +#include "wni_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "lim_send_messages.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_process_fils.h" + +#include "qdf_types.h" +#include "wma_types.h" +#include "lim_types.h" + +/** + * lim_update_re_assoc_globals() - Update reassoc global data + * @mac: Global MAC context + * @pAssocRsp: Reassociation response data + * @pe_session: PE Session + * + * This function is called to Update the Globals (LIM) during ReAssoc. + * + * Return: None + */ + +void lim_update_re_assoc_globals(struct mac_context *mac, tpSirAssocRsp pAssocRsp, + struct pe_session *pe_session) +{ + /* Update the current Bss Information */ + qdf_mem_copy(pe_session->bssId, + pe_session->limReAssocbssId, sizeof(tSirMacAddr)); + pe_session->curr_op_freq = pe_session->lim_reassoc_chan_freq; + pe_session->htSecondaryChannelOffset = + pe_session->reAssocHtSupportedChannelWidthSet; + pe_session->htRecommendedTxWidthSet = + pe_session->reAssocHtRecommendedTxWidthSet; + pe_session->htSecondaryChannelOffset = + pe_session->reAssocHtSecondaryChannelOffset; + pe_session->limCurrentBssCaps = pe_session->limReassocBssCaps; + pe_session->limCurrentBssQosCaps = + pe_session->limReassocBssQosCaps; + + qdf_mem_copy((uint8_t *) &pe_session->ssId, + (uint8_t *) &pe_session->limReassocSSID, + pe_session->limReassocSSID.length + 1); + + /* Store assigned AID for TIM processing */ + pe_session->limAID = pAssocRsp->aid & 0x3FFF; + /** Set the State Back to ReAssoc Rsp*/ + pe_session->limMlmState = eLIM_MLM_WT_REASSOC_RSP_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + pe_session->limMlmState)); + +} + +/** + * @lim_handle_del_bss_in_re_assoc_context() - DEL BSS during reassociation + * @mac: Global MAC Context + * @sta: Station Hash entry + * @pe_session: PE Session + * + * While Processing the ReAssociation Response Frame in STA, + * a.immediately after receiving the Reassoc Response the RxCleanUp is + * being issued and the end of DelBSS the new BSS is being added. + * + * b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context + * change, We need to update CSR with ReAssocCNF Response with the + * ReAssoc Fail and the reason Code, that is also being handled in the + * DELBSS context only + * + * Return: None + */ +void lim_handle_del_bss_in_re_assoc_context(struct mac_context *mac, + tpDphHashNode sta, struct pe_session *pe_session) +{ + tLimMlmReassocCnf mlmReassocCnf; + struct bss_description *bss_desc; + /* + * Skipped the DeleteDPH Hash Entry as we need it for the new BSS + * Set the MlmState to IDLE + */ + pe_session->limMlmState = eLIM_MLM_IDLE_STATE; + /* Update PE session Id */ + mlmReassocCnf.sessionId = pe_session->peSessionId; + switch (pe_session->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: + { + tpSirAssocRsp assocRsp; + tpDphHashNode sta; + QDF_STATUS retStatus = QDF_STATUS_SUCCESS; + tpSchBeaconStruct beacon_struct; + + beacon_struct = qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!beacon_struct) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + STATUS_UNSPECIFIED_FAILURE; + lim_delete_dph_hash_entry(mac, pe_session->bssId, + DPH_STA_HASH_INDEX_PEER, pe_session); + goto error; + } + /* Delete the older STA Table entry */ + lim_delete_dph_hash_entry(mac, pe_session->bssId, + DPH_STA_HASH_INDEX_PEER, pe_session); + /* + * Add an entry for AP to hash table + * maintained by DPH module + */ + sta = dph_add_hash_entry(mac, + pe_session->limReAssocbssId, + DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (!sta) { + /* Could not add hash table entry */ + pe_err("could not add hash entry at DPH for BSSID: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS; + qdf_mem_free(beacon_struct); + goto error; + } + /* + * While Processing the ReAssoc Response Frame the Rsp Frame + * is being stored to be used here for sending ADDBSS + */ + assocRsp = + (tpSirAssocRsp) pe_session->limAssocResponseData; + + bss_desc = &pe_session->pLimReAssocReq->bssDescription; + lim_extract_ap_capabilities(mac, + (uint8_t *)bss_desc->ieFields, + lim_get_ielen_from_bss_description(bss_desc), + beacon_struct); + + lim_update_assoc_sta_datas(mac, sta, assocRsp, + pe_session, beacon_struct); + lim_update_re_assoc_globals(mac, assocRsp, pe_session); + if (mac->lim.gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac, + beacon_struct, + pe_session); + if (beacon_struct->erpPresent) { + if (beacon_struct->erpIEInfo.barkerPreambleMode) + pe_session->beaconParams.fShortPreamble = 0; + else + pe_session->beaconParams.fShortPreamble = 1; + } + /* + * updateBss flag is false, as in this case, PE is first + * deleting the existing BSS and then adding a new one + */ + if (QDF_STATUS_SUCCESS != + lim_sta_send_add_bss(mac, assocRsp, beacon_struct, + bss_desc, + false, pe_session)) { + pe_err("Posting ADDBSS in the ReAssocCtx Failed"); + retStatus = QDF_STATUS_E_FAILURE; + } + if (retStatus != QDF_STATUS_SUCCESS) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + STATUS_UNSPECIFIED_FAILURE; + qdf_mem_free(assocRsp); + mac->lim.gLimAssocResponseData = NULL; + qdf_mem_free(beacon_struct); + goto error; + } + qdf_mem_free(assocRsp->sha384_ft_subelem.gtk); + qdf_mem_free(assocRsp->sha384_ft_subelem.igtk); + qdf_mem_free(assocRsp); + qdf_mem_free(beacon_struct); + pe_session->limAssocResponseData = NULL; + } + break; + default: + pe_err("DelBss in wrong system Role and SME State"); + mlmReassocCnf.resultCode = eSIR_SME_REFUSED; + mlmReassocCnf.protStatusCode = + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto error; + } + return; +error: + lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * @lim_handle_add_bss_in_re_assoc_context() - ADD BSS during reassociation + * @mac: Global MAC Context + * @sta: Station Hash entry + * @pe_session: PE Session + * + * While Processing the ReAssociation Response Frame in STA, + * a. immediately after receiving the Reassoc Response the RxCleanUp is + * being issued and the end of DelBSS the new BSS is being added. + * + * b. If an AP rejects the ReAssociation (Disassoc/Deauth) with some context + * change, We need to update CSR with ReAssocCNF Response with the + * ReAssoc Fail and the reason Code, that is also being handled in the + * DELBSS context only + * + * Return: None + */ +void lim_handle_add_bss_in_re_assoc_context(struct mac_context *mac, + tpDphHashNode sta, struct pe_session *pe_session) +{ + tLimMlmReassocCnf mlmReassocCnf; + /** Skipped the DeleteDPH Hash Entry as we need it for the new BSS*/ + /** Set the MlmState to IDLE*/ + pe_session->limMlmState = eLIM_MLM_IDLE_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + pe_session->limMlmState)); + switch (pe_session->limSmeState) { + case eLIM_SME_WT_REASSOC_STATE: { + tpSirAssocRsp assocRsp; + tpDphHashNode sta; + QDF_STATUS retStatus = QDF_STATUS_SUCCESS; + tSchBeaconStruct *pBeaconStruct; + + pBeaconStruct = + qdf_mem_malloc(sizeof(tSchBeaconStruct)); + if (!pBeaconStruct) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + goto Error; + } + /* Get the AP entry from DPH hash table */ + sta = + dph_get_hash_entry(mac, DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (!sta) { + pe_err("Fail to get STA PEER entry from hash"); + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = eSIR_SME_SUCCESS; + qdf_mem_free(pBeaconStruct); + goto Error; + } + /* + * While Processing the ReAssoc Response Frame the Rsp Frame + * is being stored to be used here for sending ADDBSS + */ + assocRsp = + (tpSirAssocRsp) pe_session->limAssocResponseData; + lim_extract_ap_capabilities(mac, + (uint8_t *)pe_session->pLimReAssocReq->bssDescription.ieFields, + lim_get_ielen_from_bss_description + (&pe_session->pLimReAssocReq->bssDescription), + pBeaconStruct); + lim_update_assoc_sta_datas(mac, sta, assocRsp, + pe_session, pBeaconStruct); + lim_update_re_assoc_globals(mac, assocRsp, pe_session); + if (mac->lim.gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection_on_assoc(mac, + pBeaconStruct, + pe_session); + + if (pBeaconStruct->erpPresent) { + if (pBeaconStruct->erpIEInfo.barkerPreambleMode) + pe_session->beaconParams. + fShortPreamble = 0; + else + pe_session->beaconParams. + fShortPreamble = 1; + } + + pe_session->isNonRoamReassoc = 1; + if (QDF_STATUS_SUCCESS != + lim_sta_send_add_bss(mac, assocRsp, pBeaconStruct, + &pe_session->pLimReAssocReq-> + bssDescription, true, + pe_session)) { + pe_err("Post ADDBSS in the ReAssocCtxt Failed"); + retStatus = QDF_STATUS_E_FAILURE; + } + if (retStatus != QDF_STATUS_SUCCESS) { + mlmReassocCnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = + STATUS_UNSPECIFIED_FAILURE; + qdf_mem_free(assocRsp); + mac->lim.gLimAssocResponseData = NULL; + qdf_mem_free(pBeaconStruct); + goto Error; + } + qdf_mem_free(assocRsp->sha384_ft_subelem.gtk); + qdf_mem_free(assocRsp->sha384_ft_subelem.igtk); + qdf_mem_free(assocRsp); + pe_session->limAssocResponseData = NULL; + qdf_mem_free(pBeaconStruct); + } + break; + default: + pe_err("DelBss in the wrong system Role and SME State"); + mlmReassocCnf.resultCode = eSIR_SME_REFUSED; + mlmReassocCnf.protStatusCode = + eSIR_SME_UNEXPECTED_REQ_RESULT_CODE; + goto Error; + } + return; +Error: + lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_is_reassoc_in_progress() - Check if reassoiciation is in progress + * @mac: Global MAC Context + * @pe_session: PE Session + * + * Return: true When STA is waiting for Reassoc response from AP + * else false + */ +bool lim_is_reassoc_in_progress(struct mac_context *mac, struct pe_session *pe_session) +{ + if (!pe_session) + return false; + + if (LIM_IS_STA_ROLE(pe_session) && + (pe_session->limSmeState == eLIM_SME_WT_REASSOC_STATE)) + return true; + + return false; +} + +/** + * lim_add_ft_sta_self()- function to add STA once we have connected with a + * new AP + * @mac_ctx: pointer to global mac structure + * @assoc_id: association id for the station connection + * @session_entry: pe session entr + * + * This function is called to add a STA once we have connected with a new + * AP, that we have performed an FT to. + * + * The Add STA Response is created and now after the ADD Bss Is Successful + * we add the self sta. We update with the association id from the reassoc + * response from the AP. + * + * Return: QDF_STATUS_SUCCESS on success else QDF_STATUS failure codes + */ +QDF_STATUS lim_add_ft_sta_self(struct mac_context *mac_ctx, uint16_t assoc_id, + struct pe_session *session_entry) +{ + tpAddStaParams add_sta_params = NULL; + QDF_STATUS ret_code = QDF_STATUS_SUCCESS; + struct scheduler_msg msg_q = {0}; + tpDphHashNode sta_ds; + + sta_ds = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + pe_err("Could not get hash entry at DPH"); + return QDF_STATUS_E_FAILURE; + } + + add_sta_params = session_entry->ftPEContext.pAddStaReq; + add_sta_params->assocId = assoc_id; + add_sta_params->smesessionId = session_entry->smeSessionId; + + qdf_mem_copy(add_sta_params->supportedRates.supportedMCSSet, + sta_ds->supportedRates.supportedMCSSet, + SIR_MAC_MAX_SUPPORTED_MCS_SET); + + if (lim_is_fils_connection(session_entry)) + add_sta_params->no_ptk_4_way = true; + + msg_q.type = WMA_ADD_STA_REQ; + msg_q.reserved = 0; + msg_q.bodyptr = add_sta_params; + msg_q.bodyval = 0; + + pe_debug("Sending WMA_ADD_STA_REQ (aid %d)", add_sta_params->assocId); + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, + msg_q.type)); + + session_entry->limPrevMlmState = session_entry->limMlmState; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, eLIM_MLM_WT_ADD_STA_RSP_STATE)); + session_entry->limMlmState = eLIM_MLM_WT_ADD_STA_RSP_STATE; + ret_code = wma_post_ctrl_msg(mac_ctx, &msg_q); + if (QDF_STATUS_SUCCESS != ret_code) { + pe_err("Posting WMA_ADD_STA_REQ to HAL failed, reason=%X", + ret_code); + qdf_mem_free(add_sta_params); + } + + session_entry->ftPEContext.pAddStaReq = NULL; + return ret_code; +} + +/** + * lim_restore_pre_reassoc_state() - Restore the pre-association context + * @mac: Global MAC Context + * @resultCode: Assoc response result + * @protStatusCode: Internal protocol status code + * @pe_session: PE Session + * + * This function is called on STA role whenever Reasociation + * Response with a reject code is received from AP. + * Reassociation failure timer is stopped, Old (or current) AP's + * context is restored both at Polaris & software + * + * Return: None + */ + +void +lim_restore_pre_reassoc_state(struct mac_context *mac, + tSirResultCodes resultCode, uint16_t protStatusCode, + struct pe_session *pe_session) +{ + tLimMlmReassocCnf mlmReassocCnf; + + pe_debug("sessionid: %d protStatusCode: %d resultCode: %d", + pe_session->smeSessionId, protStatusCode, resultCode); + + pe_session->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + /* 'Change' timer for future activations */ + lim_deactivate_and_change_timer(mac, eLIM_REASSOC_FAIL_TIMER); + + /* @ToDo:Need to Integrate the STOP the Dataxfer to AP from 11H code */ + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + mlmReassocCnf.sessionId = pe_session->peSessionId; + lim_post_sme_message(mac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_post_reassoc_failure() - Post failure message to SME + * @mac: Global MAC Context + * @resultCode: Result Code + * @protStatusCode: Protocol Status Code + * @pe_session: PE Session + * + * Return: None + */ +void lim_post_reassoc_failure(struct mac_context *mac, + tSirResultCodes resultCode, uint16_t protStatusCode, + struct pe_session *pe_session) +{ + tLimMlmReassocCnf mlmReassocCnf; + + pe_session->limMlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + eLIM_MLM_LINK_ESTABLISHED_STATE)); + + lim_deactivate_and_change_timer(mac, eLIM_REASSOC_FAIL_TIMER); + + mlmReassocCnf.resultCode = resultCode; + mlmReassocCnf.protStatusCode = protStatusCode; + mlmReassocCnf.sessionId = pe_session->peSessionId; + lim_post_sme_message(mac, + LIM_MLM_REASSOC_CNF, (uint32_t *) &mlmReassocCnf); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c new file mode 100644 index 0000000000..4f0d67471f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_roam_timer_utils.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: lim_roam_timer_utils.c + * + * Host based roaming timers implementation + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" + +/** + * lim_create_timers_host_roam() - Create timers used in host based roaming + * @mac_ctx: Global MAC context + * + * Create reassoc and preauth timers + * + * Return: TX_SUCCESS or TX_TIMER_ERROR + */ +uint32_t lim_create_timers_host_roam(struct mac_context *mac_ctx) +{ + uint32_t cfg_value; + + cfg_value = SYS_MS_TO_TICKS( + mac_ctx->mlme_cfg->timeouts.reassoc_failure_timeout); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(mac_ctx, + &mac_ctx->lim.lim_timers.gLimReassocFailureTimer, + "REASSOC FAILURE TIMEOUT", lim_assoc_failure_timer_handler, + LIM_REASSOC, cfg_value, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("failed to create Reassoc timer"); + return TX_TIMER_ERROR; + } + cfg_value = 1000; + cfg_value = SYS_MS_TO_TICKS(cfg_value); + if (tx_timer_create(mac_ctx, + &mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer, + "FT PREAUTH RSP TIMEOUT", + lim_timer_handler, SIR_LIM_FT_PREAUTH_RSP_TIMEOUT, + cfg_value, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("failed to create Join fail timer"); + goto err_roam_timer; + } + return TX_SUCCESS; + +err_roam_timer: + tx_timer_delete(&mac_ctx->lim.lim_timers.gLimReassocFailureTimer); + return TX_TIMER_ERROR; +} + +void lim_delete_timers_host_roam(struct mac_context *mac_ctx) +{ + tLimTimers *lim_timer = &mac_ctx->lim.lim_timers; + + /* Delete Reassociation failure timer. */ + tx_timer_delete(&lim_timer->gLimReassocFailureTimer); + /* Delete FT Preauth response timer */ + tx_timer_delete(&lim_timer->gLimFTPreAuthRspTimer); +} + +void lim_deactivate_timers_host_roam(struct mac_context *mac_ctx) +{ + tLimTimers *lim_timer = &mac_ctx->lim.lim_timers; + + /* Deactivate Reassociation failure timer. */ + tx_timer_deactivate(&lim_timer->gLimReassocFailureTimer); + /* Deactivate FT Preauth response timer */ + tx_timer_deactivate(&lim_timer->gLimFTPreAuthRspTimer); +} + +/** + * lim_deactivate_and_change_timer_host_roam() - Change timers in host roaming + * @mac_ctx: Pointer to Global MAC structure + * @timer_id: enum of timer to be deactivated and changed + * + * This function is called to deactivate and change a timer for future + * re-activation for host roaming timers. + * + * Return: None + */ +void lim_deactivate_and_change_timer_host_roam(struct mac_context *mac_ctx, + uint32_t timer_id) +{ + uint32_t val = 0; + + switch (timer_id) { + case eLIM_REASSOC_FAIL_TIMER: + if (tx_timer_deactivate + (&mac_ctx->lim.lim_timers.gLimReassocFailureTimer) != + TX_SUCCESS) + pe_warn("unable to deactivate Reassoc fail timer"); + + val = SYS_MS_TO_TICKS( + mac_ctx->mlme_cfg->timeouts.reassoc_failure_timeout); + if (tx_timer_change + (&mac_ctx->lim.lim_timers.gLimReassocFailureTimer, val, + 0) != TX_SUCCESS) + pe_warn("unable to change Reassoc fail timer"); + break; + + case eLIM_FT_PREAUTH_RSP_TIMER: + if (tx_timer_deactivate + (&mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer) != + TX_SUCCESS) { + pe_err("Unable to deactivate Preauth Fail timer"); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change( + &mac_ctx->lim.lim_timers.gLimFTPreAuthRspTimer, + val, 0) != TX_SUCCESS) { + pe_err("Unable to change Join Failure timer"); + return; + } + break; + } +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c new file mode 100644 index 0000000000..a399f7312e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_scan_result_utils.cc contains the utility functions + * LIM uses for maintaining and accessing scan results on STA. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_api.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "rrm_api.h" +#include "cds_utils.h" + +/** + * lim_collect_bss_description() + * + ***FUNCTION: + * This function is called during scan upon receiving + * Beacon/Probe Response frame to check if the received + * frame matches scan criteria, collect BSS description + * and add it to cached scan results. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param pBPR - Pointer to parsed Beacon/Probe Response structure + * @param pRxPacketInfo - Pointer to Received frame's BD + * @param fScanning - flag to indicate if it is during scan. + * --------------------------------------------- + * + * @return None + */ +void +lim_collect_bss_description(struct mac_context *mac, + struct bss_description *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning) +{ + uint8_t *pBody; + uint32_t ieLen = 0; + tpSirMacMgmtHdr pHdr; + uint32_t chan_freq; + uint8_t rfBand = 0; + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + if (SIR_MAC_B_PR_SSID_OFFSET > WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo)) { + QDF_ASSERT(WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) >= + SIR_MAC_B_PR_SSID_OFFSET); + return; + } + ieLen = + WMA_GET_RX_PAYLOAD_LEN(pRxPacketInfo) - SIR_MAC_B_PR_SSID_OFFSET; + pBody = WMA_GET_RX_MPDU_DATA(pRxPacketInfo); + rfBand = WMA_GET_RX_RFBAND(pRxPacketInfo); + + /** + * Length of BSS description is without length of + * length itself and length of pointer that holds ieFields. + * + * struct bss_description + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + pBssDescr->length = + (uint16_t)(offsetof(struct bss_description, ieFields[0]) - + sizeof(pBssDescr->length) + ieLen); + + /* Copy BSS Id */ + qdf_mem_copy((uint8_t *) &pBssDescr->bssId, + (uint8_t *) pHdr->bssId, sizeof(tSirMacAddr)); + + pBssDescr->timeStamp[0] = pBPR->timeStamp[0]; + pBssDescr->timeStamp[1] = pBPR->timeStamp[1]; + pBssDescr->beaconInterval = pBPR->beaconInterval; + pBssDescr->capabilityInfo = + lim_get_u16((uint8_t *) &pBPR->capabilityInfo); + + if (!pBssDescr->beaconInterval) { + pe_warn("Beacon Interval is ZERO, making it to default 100 " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(pHdr->bssId)); + pBssDescr->beaconInterval = 100; + } + /* + * There is a narrow window after Channel Switch msg is sent to HAL and before the AGC is shut + * down and beacons/Probe Rsps can trickle in and we may report the incorrect channel in 5Ghz + * band, so not relying on the 'last Scanned Channel' stored in LIM. + * Instead use the value returned by RXP in BD. This the the same value which HAL programs into + * RXP before every channel switch. + * Right now there is a problem in 5Ghz, where we are receiving beacons from a channel different from + * the currently scanned channel. so incorrect channel is reported to CSR and association does not happen. + * So for now we keep on looking for the channel info in the beacon (DSParamSet IE OR HT Info IE), and only if it + * is not present in the beacon, we go for the channel info present in RXP. + * This fix will work for 5Ghz 11n devices, but for 11a devices, we have to rely on RXP routing flag to get the correct channel. + * So The problem of incorrect channel reporting in 5Ghz will still remain for 11a devices. + */ + chan_freq = lim_get_channel_from_beacon(mac, pBPR); + pBssDescr->chan_freq = chan_freq; + + /* set the network type in bss description */ + pBssDescr->nwType = + lim_get_nw_type(mac, chan_freq, SIR_MAC_MGMT_FRAME, pBPR); + + /* Copy RSSI & SINR from BD */ + pBssDescr->rssi = (int8_t) WMA_GET_RX_RSSI_NORMALIZED(pRxPacketInfo); + pBssDescr->rssi_raw = (int8_t) WMA_GET_RX_RSSI_RAW(pRxPacketInfo); + + pe_debug(QDF_MAC_ADDR_FMT " rssi: normalized: %d, absolute: %d", + QDF_MAC_ADDR_REF(pHdr->bssId), pBssDescr->rssi, + pBssDescr->rssi_raw); + + pe_debug("Received %s from BSSID: " QDF_MAC_ADDR_FMT " Seq Num: %x ssid:" QDF_SSID_FMT ", rssi: %d", + pBssDescr->fProbeRsp ? "Probe Rsp" : "Beacon", + QDF_MAC_ADDR_REF(pHdr->bssId), + ((pHdr->seqControl.seqNumHi << HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo), + QDF_SSID_REF(pBPR->ssId.length, pBPR->ssId.ssId), + pBssDescr->rssi_raw); + + if (fScanning) { + rrm_get_start_tsf(mac, pBssDescr->startTSF); + pBssDescr->parentTSF = WMA_GET_RX_TIMESTAMP(pRxPacketInfo); + } + + /* MobilityDomain */ + pBssDescr->mdie[0] = 0; + pBssDescr->mdie[1] = 0; + pBssDescr->mdie[2] = 0; + pBssDescr->mdiePresent = false; + /* If mdie is present in the probe resp we */ + /* fill it in the bss description */ + if (pBPR->mdiePresent) { + pBssDescr->mdiePresent = true; + pBssDescr->mdie[0] = pBPR->mdie[0]; + pBssDescr->mdie[1] = pBPR->mdie[1]; + pBssDescr->mdie[2] = pBPR->mdie[2]; + } + + /* Copy IE fields */ + qdf_mem_copy((uint8_t *) &pBssDescr->ieFields, + pBody + SIR_MAC_B_PR_SSID_OFFSET, ieLen); + + /*set channel number in beacon in case it is not present */ + pBPR->chan_freq = chan_freq; + mac->lim.beacon_probe_rsp_cnt_per_scan++; + + return; +} /*** end lim_collect_bss_description() ***/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h new file mode 100644 index 0000000000..a483856cf4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_scan_result_utils.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2012, 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_scan_result_utils.h contains the utility definitions + * LIM uses for maintaining and accessing scan results on STA. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SCAN_UTILS_H +#define __LIM_SCAN_UTILS_H + +#include "parser_api.h" +#include "lim_types.h" + +/* Scan result hash related functions */ +void lim_collect_bss_description(struct mac_context *mac, + struct bss_description *pBssDescr, + tpSirProbeRespBeacon pBPR, + uint8_t *pRxPacketInfo, uint8_t fScanning); +#endif /* __LIM_SCAN_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c new file mode 100644 index 0000000000..e16d3dc9b6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.c @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_utils.cc contains the utility functions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "ani_global.h" +#include "wni_api.h" + +#include "sir_common.h" +#include "wni_cfg.h" + +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include + +#define LIM_SEED_LENGTH 16 +/* + * preauth node timeout value in interval of 10msec + */ +#define LIM_OPENAUTH_TIMEOUT 500 + +/** + * lim_is_auth_algo_supported() + * + ***FUNCTION: + * This function is called in various places within LIM code + * to determine whether passed authentication algorithm is enabled + * or not + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param authType Indicates MAC based authentication type + * (eSIR_OPEN_SYSTEM or eSIR_SHARED_KEY) + * If Shared Key authentication to be used, + * 'Privacy Option Implemented' flag is also + * checked. + * + * @return true if passed authType is enabled else false + */ +uint8_t +lim_is_auth_algo_supported(struct mac_context *mac, tAniAuthType authType, + struct pe_session *pe_session) +{ + bool algoEnable, privacyOptImp; + struct wlan_mlme_wep_cfg *wep_params = &mac->mlme_cfg->wep_params; + + if (authType == eSIR_OPEN_SYSTEM) { + + if (LIM_IS_AP_ROLE(pe_session)) { + if ((pe_session->authType == eSIR_OPEN_SYSTEM) + || (pe_session->authType == eSIR_AUTO_SWITCH)) + return true; + else + return false; + } + + algoEnable = wep_params->is_auth_open_system; + return algoEnable > 0 ? true : false; + + } else { + + if (LIM_IS_AP_ROLE(pe_session)) { + if ((pe_session->authType == eSIR_SHARED_KEY) + || (pe_session->authType == eSIR_AUTO_SWITCH)) + algoEnable = true; + else + algoEnable = false; + + } else { + algoEnable = wep_params->is_shared_key_auth; + } + + if (LIM_IS_AP_ROLE(pe_session)) + privacyOptImp = pe_session->privacy; + else + privacyOptImp = wep_params->is_privacy_enabled; + + return algoEnable && privacyOptImp; + } +} /****** end lim_is_auth_algo_supported() ******/ + +/** + * lim_init_pre_auth_list + * + ***FUNCTION: + * This function is called while starting a BSS at AP + * to initialize MAC authenticated STA list. This may also be called + * while joining/starting an IBSS if MAC authentication is allowed + * in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @return None + */ + +void lim_init_pre_auth_list(struct mac_context *mac) +{ + mac->lim.pLimPreAuthList = NULL; + +} /*** end lim_init_pre_auth_list() ***/ + +/** + * lim_delete_pre_auth_list + * + ***FUNCTION: + * This function is called cleanup Pre-auth list either on + * AP or on STA when moving from one persona to other. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @return None + */ + +void lim_delete_pre_auth_list(struct mac_context *mac) +{ + struct tLimPreAuthNode *pCurrNode, *pTempNode; + + pCurrNode = pTempNode = mac->lim.pLimPreAuthList; + while (pCurrNode) { + pTempNode = pCurrNode->next; + lim_release_pre_auth_node(mac, pCurrNode); + + pCurrNode = pTempNode; + } + mac->lim.pLimPreAuthList = NULL; +} /*** end lim_delete_pre_auth_list() ***/ + +/** + * lim_search_pre_auth_list + * + ***FUNCTION: + * This function is called when Authentication frame is received + * by AP (or at a STA in IBSS supporting MAC based authentication) + * to search if a STA is in the middle of MAC Authentication + * transaction sequence. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param macAddr - MAC address of the STA that sent + * Authentication frame. + * + * @return Pointer to pre-auth node if found, else NULL + */ + +struct tLimPreAuthNode *lim_search_pre_auth_list(struct mac_context *mac, + tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pTempNode = mac->lim.pLimPreAuthList; + + while (pTempNode) { + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) + break; + + pTempNode = pTempNode->next; + } + + return pTempNode; +} /*** end lim_search_pre_auth_list() ***/ + +#ifdef WLAN_FEATURE_11BE_MLO +struct tLimPreAuthNode * +lim_search_pre_auth_list_by_mld_addr(struct mac_context *mac, + tSirMacAddr mldaddr) +{ + struct tLimPreAuthNode *pTempNode = mac->lim.pLimPreAuthList; + + while (pTempNode) { + if (!qdf_mem_cmp((uint8_t *)mldaddr, + (uint8_t *)&pTempNode->peer_mld, + sizeof(tSirMacAddr))) + break; + + pTempNode = pTempNode->next; + } + + return pTempNode; +} +#endif + +/** + * lim_delete_open_auth_pre_auth_node() - delete any stale preauth nodes + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to delete any stale preauth nodes on + * receiving authentication frame and existing preauth nodes + * reached the maximum allowed limit. + * + * Return: return true if any preauthnode deleted else false + */ +uint8_t +lim_delete_open_auth_pre_auth_node(struct mac_context *mac_ctx) +{ + struct tLimPreAuthNode *prev_node, *temp_node, *found_node; + uint8_t auth_node_freed = false; + + temp_node = prev_node = mac_ctx->lim.pLimPreAuthList; + + if (!temp_node) + return auth_node_freed; + + while (temp_node) { + if (temp_node->mlmState == eLIM_MLM_AUTHENTICATED_STATE && + temp_node->authType == eSIR_OPEN_SYSTEM && + (qdf_mc_timer_get_system_ticks() > + (LIM_OPENAUTH_TIMEOUT + temp_node->timestamp) || + qdf_mc_timer_get_system_ticks() < temp_node->timestamp)) { + /* Found node to be deleted */ + auth_node_freed = true; + found_node = temp_node; + if (mac_ctx->lim.pLimPreAuthList == temp_node) { + prev_node = mac_ctx->lim.pLimPreAuthList = + temp_node = found_node->next; + } else { + prev_node->next = temp_node->next; + temp_node = prev_node->next; + } + + lim_release_pre_auth_node(mac_ctx, found_node); + } else { + prev_node = temp_node; + temp_node = prev_node->next; + } + } + + return auth_node_freed; +} + +/** + * lim_add_pre_auth_node + * + ***FUNCTION: + * This function is called at AP while sending Authentication + * frame2. + * This may also be called on a STA in IBSS if MAC authentication is + * allowed in IBSS mode. + * + ***LOGIC: + * Node is always added to the front of the list + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to pre-auth node to be added to the list. + * + * @return None + */ + +void lim_add_pre_auth_node(struct mac_context *mac, struct tLimPreAuthNode *pAuthNode) +{ + mac->lim.gLimNumPreAuthContexts++; + + pAuthNode->next = mac->lim.pLimPreAuthList; + + mac->lim.pLimPreAuthList = pAuthNode; +} /*** end lim_add_pre_auth_node() ***/ + +/** + * lim_release_pre_auth_node + * + ***FUNCTION: + * This function is called to release the acquired + * pre auth node from list. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param pAuthNode - Pointer to Pre Auth node to be released + * @return None + */ + +void lim_release_pre_auth_node(struct mac_context *mac, + tpLimPreAuthNode pAuthNode) +{ + pAuthNode->fFree = 1; + if (pAuthNode->authType == eSIR_AUTH_TYPE_SAE && + pAuthNode->assoc_req.present) { + tpSirAssocReq assoc = + (tpSirAssocReq)pAuthNode->assoc_req.assoc_req; + + lim_free_assoc_req_frm_buf(assoc); + qdf_mem_free(assoc); + pAuthNode->assoc_req.assoc_req = NULL; + pAuthNode->assoc_req.present = false; + } + MTRACE(mac_trace + (mac, TRACE_CODE_TIMER_DEACTIVATE, NO_SESSION, + eLIM_PRE_AUTH_CLEANUP_TIMER)); + tx_timer_deactivate(&pAuthNode->timer); + mac->lim.gLimNumPreAuthContexts--; +} /*** end lim_release_pre_auth_node() ***/ + +/** + * lim_delete_pre_auth_node + * + ***FUNCTION: + * This function is called at AP when a pre-authenticated STA is + * Associated/Reassociated or when AuthFrame4 is received after + * Auth Response timeout. + * This may also be called on a STA in IBSS if MAC authentication and + * Association/Reassociation is allowed in IBSS mode. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param peerMacAddr - MAC address of the STA that need to be deleted + * from pre-auth node list. + * + * @return None + */ + +void lim_delete_pre_auth_node(struct mac_context *mac, tSirMacAddr macAddr) +{ + struct tLimPreAuthNode *pPrevNode, *pTempNode; + + pTempNode = pPrevNode = mac->lim.pLimPreAuthList; + + if (!pTempNode) + return; + + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* First node to be deleted */ + + mac->lim.pLimPreAuthList = pTempNode->next; + + pe_debug("fRelease data for %d peer "QDF_MAC_ADDR_FMT, + pTempNode->authNodeIdx, + QDF_MAC_ADDR_REF(macAddr)); + lim_release_pre_auth_node(mac, pTempNode); + + return; + } + + pTempNode = pTempNode->next; + + while (pTempNode) { + if (!qdf_mem_cmp((uint8_t *) macAddr, + (uint8_t *) &pTempNode->peerMacAddr, + sizeof(tSirMacAddr))) { + /* Found node to be deleted */ + + pPrevNode->next = pTempNode->next; + + pe_debug("subsequent node to delete, Release data entry: %pK id %d peer "QDF_MAC_ADDR_FMT, + pTempNode, pTempNode->authNodeIdx, + QDF_MAC_ADDR_REF(macAddr)); + lim_release_pre_auth_node(mac, pTempNode); + + return; + } + + pPrevNode = pTempNode; + pTempNode = pTempNode->next; + } + + pe_err("peer not found in pre-auth list, addr= "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(macAddr)); + +} /*** end lim_delete_pre_auth_node() ***/ + +/** + * limRestoreFromPreAuthState + * + ***FUNCTION: + * This function is called on STA whenever an Authentication + * sequence is complete and state prior to auth need to be + * restored. + * + ***LOGIC: + * MLM_AUTH_CNF is prepared and sent to SME state machine. + * In case of restoring from pre-auth: + * - Channel Id is programmed at LO/RF synthesizer + * - BSSID is programmed at RHP + * + ***ASSUMPTIONS: + * + ***NOTE: + * + * @param mac - Pointer to Global MAC structure + * @param resultCode - result of authentication attempt + * @return None + */ + +void +lim_restore_from_auth_state(struct mac_context *mac, tSirResultCodes resultCode, + uint16_t protStatusCode, struct pe_session *pe_session) +{ + tSirMacAddr currentBssId; + tLimMlmAuthCnf mlmAuthCnf; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac, WLAN_PE_DIAG_AUTH_COMP_EVENT, pe_session, + resultCode, protStatusCode); +#endif + + qdf_mem_copy((uint8_t *) &mlmAuthCnf.peerMacAddr, + (uint8_t *) &mac->lim.gpLimMlmAuthReq->peerMacAddr, + sizeof(tSirMacAddr)); + mlmAuthCnf.authType = mac->lim.gpLimMlmAuthReq->authType; + mlmAuthCnf.resultCode = resultCode; + mlmAuthCnf.protStatusCode = protStatusCode; + + /* Update PE session ID */ + mlmAuthCnf.sessionId = pe_session->peSessionId; + + /* / Free up buffer allocated */ + /* / for mac->lim.gLimMlmAuthReq */ + qdf_mem_free(mac->lim.gpLimMlmAuthReq); + mac->lim.gpLimMlmAuthReq = NULL; + + pe_session->limMlmState = pe_session->limPrevMlmState; + + MTRACE(mac_trace + (mac, TRACE_CODE_MLM_STATE, pe_session->peSessionId, + pe_session->limMlmState)); + + /* + * Set the auth_ack_status status flag as success as + * host have received the auth rsp and no longer auth + * retry is needed also cancel the auth rety timer + */ + mac->auth_ack_status = LIM_ACK_RCD_SUCCESS; + + /* Auth retry and AUth failure timers are not started for SAE */ + /* 'Change' timer for future activations */ + if (tx_timer_running(&mac->lim.lim_timers. + g_lim_periodic_auth_retry_timer)) + lim_deactivate_and_change_timer(mac, + eLIM_AUTH_RETRY_TIMER); + /* 'Change' timer for future activations */ + if (tx_timer_running(&mac->lim.lim_timers.gLimAuthFailureTimer)) + lim_deactivate_and_change_timer(mac, + eLIM_AUTH_FAIL_TIMER); + + sir_copy_mac_addr(currentBssId, pe_session->bssId); + + if (pe_session->limSmeState == eLIM_SME_WT_PRE_AUTH_STATE) { + mac->lim.gLimPreAuthChannelNumber = 0; + } + + lim_post_sme_message(mac, LIM_MLM_AUTH_CNF, (uint32_t *) &mlmAuthCnf); +} /*** end lim_restore_from_auth_state() ***/ + +/** + * lim_encrypt_auth_frame() + * + ***FUNCTION: + * This function is called in lim_process_auth_frame() function + * to encrypt Authentication frame3 body. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac Pointer to Global MAC structure + * @param keyId key id to used + * @param pKey Pointer to the key to be used for encryption + * @param pPlainText Pointer to the body to be encrypted + * @param pEncrBody Pointer to the encrypted auth frame body + * @param keyLength 8 (WEP40) or 16 (WEP104) + * @return None + */ + +void +lim_encrypt_auth_frame(struct mac_context *mac, uint8_t keyId, uint8_t *pKey, + uint8_t *pPlainText, uint8_t *pEncrBody, + uint32_t keyLength) +{ + uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; + uint16_t frame_len; + + frame_len = ((tpSirMacAuthFrameBody)pPlainText)->length + + SIR_MAC_AUTH_FRAME_INFO_LEN + SIR_MAC_CHALLENGE_ID_LEN; + keyLength += 3; + + /* + * Make sure that IV is non-zero, because few IOT APs fails to decrypt + * auth sequence 3 encrypted frames if initialization vector value is 0 + */ + qdf_get_random_bytes(seed, SIR_MAC_WEP_IV_LENGTH); + while (!(*(uint32_t *)seed)) + qdf_get_random_bytes(seed, SIR_MAC_WEP_IV_LENGTH); + + /* Bytes 3-7 of seed is key */ + qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); + + /* Compute CRC-32 and place them in last 4 bytes of plain text */ + lim_compute_crc32(icv, pPlainText, frame_len); + + qdf_mem_copy(pPlainText + frame_len, + icv, SIR_MAC_WEP_ICV_LENGTH); + + /* Run RC4 on plain text with the seed */ + lim_rc4(pEncrBody + SIR_MAC_WEP_IV_LENGTH, + (uint8_t *) pPlainText, seed, keyLength, + frame_len + SIR_MAC_WEP_ICV_LENGTH); + + /* Prepare IV */ + pEncrBody[0] = seed[0]; + pEncrBody[1] = seed[1]; + pEncrBody[2] = seed[2]; + pEncrBody[3] = keyId << 6; +} /****** end lim_encrypt_auth_frame() ******/ + +/** + * lim_compute_crc32() + * + ***FUNCTION: + * This function is called to compute CRC-32 on a given source. + * Used while encrypting/decrypting Authentication frame 3. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pDest Destination location for computed CRC + * @param pSrc Source location to be CRC computed + * @param len Length over which CRC to be computed + * @return None + */ + +void lim_compute_crc32(uint8_t *pDest, uint8_t *pSrc, uint16_t len) +{ + uint32_t crc; + int i; + + crc = 0; + crc = ~crc; + + while (len-- > 0) + crc = lim_crc_update(crc, *pSrc++); + + crc = ~crc; + + for (i = 0; i < SIR_MAC_WEP_IV_LENGTH; i++) { + pDest[i] = (uint8_t) crc; + crc >>= 8; + } +} /****** end lim_compute_crc32() ******/ + +/** + * lim_rc4() + * + ***FUNCTION: + * This function is called to run RC4 algorithm. Called while + * encrypting/decrypting Authentication frame 3. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pDest Destination location for encrypted text + * @param pSrc Source location to be encrypted + * @param seed Contains seed (IV + key) for PRNG + * @param keyLength 8 (WEP40) or 16 (WEP104) + * @param frameLen Length of the frame + * + * @return None + */ + +void +lim_rc4(uint8_t *pDest, uint8_t *pSrc, uint8_t *seed, uint32_t keyLength, + uint16_t frameLen) +{ + typedef struct { + uint8_t i, j; + uint8_t sbox[256]; + } tRC4Context; + + tRC4Context ctx; + + { + uint16_t i, j, k; + + /* */ + /* Initialize sbox using seed */ + /* */ + + ctx.i = ctx.j = 0; + for (i = 0; i < 256; i++) + ctx.sbox[i] = (uint8_t) i; + + j = 0; + k = 0; + for (i = 0; i < 256; i++) { + uint8_t temp; + + if (k < LIM_SEED_LENGTH) + j = (uint8_t) (j + ctx.sbox[i] + seed[k]); + temp = ctx.sbox[i]; + ctx.sbox[i] = ctx.sbox[j]; + ctx.sbox[j] = temp; + + if (++k >= keyLength) + k = 0; + } + } + + { + uint8_t i = ctx.i; + uint8_t j = ctx.j; + uint16_t len = frameLen; + + while (len-- > 0) { + uint8_t temp1, temp2; + + i = (uint8_t) (i + 1); + temp1 = ctx.sbox[i]; + j = (uint8_t) (j + temp1); + + ctx.sbox[i] = temp2 = ctx.sbox[j]; + ctx.sbox[j] = temp1; + + temp1 = (uint8_t) (temp1 + temp2); + temp1 = ctx.sbox[temp1]; + temp2 = (uint8_t) (pSrc ? *pSrc++ : 0); + + *pDest++ = (uint8_t) (temp1 ^ temp2); + } + + ctx.i = i; + ctx.j = j; + } +} /****** end lim_rc4() ******/ + +/** + * lim_decrypt_auth_frame() + * + ***FUNCTION: + * This function is called in lim_process_auth_frame() function + * to decrypt received Authentication frame3 body. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac Pointer to Global MAC structure + * @param pKey Pointer to the key to be used for decryption + * @param pEncrBody Pointer to the body to be decrypted + * @param pPlainBody Pointer to the decrypted body + * @param keyLength 8 (WEP40) or 16 (WEP104) + * + * @return Decrypt result - QDF_STATUS_SUCCESS for success and + * LIM_DECRYPT_ICV_FAIL for ICV mismatch. + * If decryption is a success, pBody will + * have decrypted auth frame body. + */ + +uint8_t +lim_decrypt_auth_frame(struct mac_context *mac, uint8_t *pKey, uint8_t *pEncrBody, + uint8_t *pPlainBody, uint32_t keyLength, uint16_t frameLen) +{ + uint8_t seed[LIM_SEED_LENGTH], icv[SIR_MAC_WEP_ICV_LENGTH]; + int i; + + keyLength += 3; + + /* Bytes 0-2 of seed is received IV */ + qdf_mem_copy((uint8_t *) seed, pEncrBody, SIR_MAC_WEP_IV_LENGTH - 1); + + /* Bytes 3-7 of seed is key */ + qdf_mem_copy((uint8_t *) &seed[3], pKey, keyLength - 3); + + /* Run RC4 on encrypted text with the seed */ + lim_rc4(pPlainBody, + pEncrBody + SIR_MAC_WEP_IV_LENGTH, seed, keyLength, frameLen); + + /* Compute CRC-32 and place them in last 4 bytes of encrypted body */ + lim_compute_crc32(icv, + (uint8_t *) pPlainBody, + (frameLen - SIR_MAC_WEP_ICV_LENGTH)); + + /* Compare RX_ICV with computed ICV */ + for (i = 0; i < SIR_MAC_WEP_ICV_LENGTH; i++) { + pe_debug("computed ICV%d[%x], rxed ICV%d[%x]", + i, icv[i], i, + pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]); + + if (icv[i] != + pPlainBody[frameLen - SIR_MAC_WEP_ICV_LENGTH + i]) + return LIM_DECRYPT_ICV_FAIL; + } + + return QDF_STATUS_SUCCESS; +} /****** end lim_decrypt_auth_frame() ******/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h new file mode 100644 index 0000000000..1e8e1c98ab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_security_utils.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011-2015, 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_security_utils.h contains the utility definitions + * related to WEP encryption/decryption etc. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SECURITY_UTILS_H +#define __LIM_SECURITY_UTILS_H +#include "sir_mac_prot_def.h" /* for tSirMacAuthFrameBody */ + +#define LIM_ENCR_AUTH_BODY_LEN (SIR_MAC_AUTH_FRAME_INFO_LEN + \ + SIR_MAC_AUTH_CHALLENGE_BODY_LEN + \ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH) + +#define LIM_ENCR_AUTH_BODY_LEN_SAP (SIR_MAC_AUTH_FRAME_INFO_LEN + \ + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + \ + SIR_MAC_CHALLENGE_ID_LEN + \ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH) + +#define LIM_ENCR_AUTH_INFO_LEN (SIR_MAC_AUTH_FRAME_INFO_LEN +\ + SIR_MAC_WEP_IV_LENGTH + \ + SIR_MAC_WEP_ICV_LENGTH + \ + SIR_MAC_CHALLENGE_ID_LEN) + + +struct tLimPreAuthNode; + +uint8_t lim_is_auth_algo_supported(struct mac_context *, tAniAuthType, + struct pe_session *); + +/* MAC based authentication related functions */ +void lim_init_pre_auth_list(struct mac_context *); +void lim_delete_pre_auth_list(struct mac_context *); +struct tLimPreAuthNode *lim_search_pre_auth_list(struct mac_context *, + tSirMacAddr); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_search_pre_auth_list_by_mld_addr() - This function is called when + * Authentication frame is received by AP (or at a STA in IBSS supporting MAC + * based authentication) to search using MLD address if a STA is in the middle + * of MAC Authentication transaction sequence. + * @mac: MAC context + * @mldaddr: MLD address of the STA that sent + * + * Return: Pointer to pre-auth node if found, else NULL + */ +struct tLimPreAuthNode *lim_search_pre_auth_list_by_mld_addr( + struct mac_context *mac, + tSirMacAddr mldaddr); +#endif +void lim_add_pre_auth_node(struct mac_context *, struct tLimPreAuthNode *); +void lim_delete_pre_auth_node(struct mac_context *, tSirMacAddr); +void lim_release_pre_auth_node(struct mac_context *mac, + tpLimPreAuthNode pAuthNode); +void lim_restore_from_auth_state(struct mac_context *, + tSirResultCodes, uint16_t, struct pe_session *); +uint8_t lim_delete_open_auth_pre_auth_node(struct mac_context *mac_ctx); + +/* Encryption/Decryption related functions */ +void lim_compute_crc32(uint8_t *, uint8_t *, uint16_t); +void lim_rc4(uint8_t *, uint8_t *, uint8_t *, uint32_t, uint16_t); +void lim_encrypt_auth_frame(struct mac_context *, uint8_t, uint8_t *, uint8_t *, + uint8_t *, uint32_t); +uint8_t lim_decrypt_auth_frame(struct mac_context *, uint8_t *, uint8_t *, + uint8_t *, uint32_t, uint16_t); + +#define PTAPS 0xedb88320 + +static inline uint32_t lim_crc_update(uint32_t crc, uint8_t x) +{ + + /* Update CRC computation for 8 bits contained in x */ + /* */ + uint32_t z; + uint32_t fb; + int i; + + z = crc ^ x; + for (i = 0; i < 8; i++) { + fb = z & 1; + z >>= 1; + if (fb) + z ^= PTAPS; + } + return z; +} + +#endif /* __LIM_SECURITY_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c new file mode 100644 index 0000000000..045ed34f8c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_frames_host_roam.c @@ -0,0 +1,1008 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: lim_send_frames_host_roam.c + * + * Send management frames for host based roaming + */ +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "dot11f.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#include "wni_cfg.h" + +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sme_trace.h" +#include "rrm_api.h" + +#include "wma_types.h" +#include "wlan_utility.h" + +/** + * lim_send_reassoc_req_with_ft_ies_mgmt_frame() - Send Reassoc Req with FTIEs. + * + * @mac_ctx: Handle to mac context + * @mlm_reassoc_req: Original reassoc request + * @pe_session: PE session information + * + * It builds a reassoc request with FT IEs and sends it to AP through WMA. + * Then it creates assoc request and stores it for sending after join + * confirmation. + * + * Return: None + */ +void lim_send_reassoc_req_with_ft_ies_mgmt_frame(struct mac_context *mac_ctx, + tLimMlmReassocReq *mlm_reassoc_req, + struct pe_session *pe_session) +{ + tDot11fReAssocRequest *frm; + uint16_t caps; + uint8_t *frame; + uint32_t bytes, payload, status; + uint8_t qos_enabled, wme_enabled, wsm_enabled; + void *packet; + QDF_STATUS qdf_status; + uint8_t power_caps_populated = false; + uint16_t ft_ies_length = 0; + uint8_t *body; + uint16_t add_ie_len; + uint8_t *add_ie; + const uint8_t *wps_ie = NULL; + uint8_t tx_flag = 0; + uint8_t vdev_id = 0; + bool vht_enabled = false; + tpSirMacMgmtHdr mac_hdr; + struct mlme_legacy_priv *mlme_priv; + int ret; + tDot11fIEExtCap extr_ext_cap; + QDF_STATUS sir_status; + bool extr_ext_flag = true; + uint32_t ie_offset = 0; + tDot11fIEExtCap bcn_ext_cap; + uint8_t *bcn_ie = NULL; + uint32_t bcn_ie_len = 0; + uint8_t *p_ext_cap = NULL; + + if (!pe_session) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(pe_session->vdev); + if (!mlme_priv) + return; + + vdev_id = pe_session->vdev_id; + + /* check this early to avoid unnecessary operation */ + if (!pe_session->pLimReAssocReq) + return; + + frm = qdf_mem_malloc(sizeof(*frm)); + if (!frm) + goto err; + + add_ie_len = pe_session->pLimReAssocReq->addIEAssoc.length; + add_ie = pe_session->pLimReAssocReq->addIEAssoc.addIEdata; + pe_debug("called in state: %d", pe_session->limMlmState); + + qdf_mem_zero((uint8_t *) frm, sizeof(*frm)); + + if (add_ie_len && pe_session->is_ext_caps_present) { + qdf_mem_zero((uint8_t *)&extr_ext_cap, + sizeof(tDot11fIEExtCap)); + sir_status = lim_strip_extcap_update_struct( + mac_ctx, add_ie, &add_ie_len, &extr_ext_cap); + if (QDF_STATUS_SUCCESS != sir_status) { + extr_ext_flag = false; + pe_debug("Unable to Stripoff ExtCap IE from Assoc Req"); + } else { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + extr_ext_cap.bytes; + + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extr_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length(&extr_ext_cap); + extr_ext_flag = (extr_ext_cap.num_bytes > 0); + } + } else { + pe_debug("No addn IE or peer doesn't support addnIE for Assoc Req"); + extr_ext_flag = false; + } + caps = mlm_reassoc_req->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield + * to 0 in transmitted Association or Reassociation management + * frames. APs ignore the Privacy subfield within received + * Association and Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm->Capabilities); + + frm->ListenInterval.interval = mlm_reassoc_req->listenInterval; + + /* + * Get the old bssid of the older AP. + * The previous ap bssid is stored in the FT Session + * while creating the PE FT Session for reassociation. + */ + qdf_mem_copy((uint8_t *)frm->CurrentAPAddress.mac, + pe_session->prev_ap_bssid, sizeof(tSirMacAddr)); + + populate_dot11f_ssid2(pe_session, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + qos_enabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limReassocBssCaps); + + wme_enabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limReassocBssQosCaps); + + wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limReassocBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->spectrumMgtEnabled) { + power_caps_populated = true; + + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_REASSOC, pe_session); + populate_dot11f_supp_channels(mac_ctx, &frm->SuppChannels, + LIM_REASSOC, pe_session); + } + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (power_caps_populated == false) { + power_caps_populated = true; + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_REASSOC, pe_session); + } + } + + if (qos_enabled) + populate_dot11f_qos_caps_station(mac_ctx, pe_session, + &frm->QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, &frm->ExtSuppRates, + pe_session); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) + populate_dot11f_rrm_ie(mac_ctx, &frm->RRMEnabledCap, pe_session); + + /* + * Ideally this should be enabled for 11r also. But 11r does + * not follow the usual norm of using the Opaque object + * for rsnie and fties. Instead we just add the rsnie and fties + * at the end of the pack routine for 11r. + * This should ideally! be fixed. + */ + /* + * The join request *should* contain zero or one of the WPA and RSN + * IEs. The payload send along with the request is a + * 'struct join_req'; the IE portion is held inside a 'tSirRSNie': + * + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[WLAN_MAX_IE_LEN+2]; + * } tSirRSNie, *tpSirRSNie; + * + * So, we should be able to make the following two calls harmlessly, + * since they do nothing if they don't find the given IE in the + * bytestream with which they're provided. + * + * The net effect of this will be to faithfully transmit whatever + * security IE is in the join request. + + * However, if we're associating for the purpose of WPS + * enrollment, and we've been configured to indicate that by + * eliding the WPA or RSN IE, we just skip this: + */ + if (!pe_session->is11Rconnection) { + if (add_ie_len && add_ie) + wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len); + if (!wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->rsnIE), + &frm->RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &(pe_session->pLimReAssocReq->rsnIE), + &frm->WPAOpaque); + } +#ifdef FEATURE_WLAN_ESE + if (mlme_priv->connect_info.cckm_ie_len) { + populate_dot11f_ese_cckm_opaque(mac_ctx, + &mlme_priv->connect_info, + &frm->ESECckmOpaque); + } +#endif + } +#ifdef FEATURE_WLAN_ESE + /* + * ESE Version IE will be included in re-association request + * when ESE is enabled on DUT through ini and it is also + * advertised by the peer AP to which we are trying to + * associate to. + */ + if (pe_session->is_ese_version_ie_present && + mac_ctx->mlme_cfg->lfr.ese_enabled) + populate_dot11f_ese_version(&frm->ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id)) { +#ifndef FEATURE_DISABLE_RM + populate_dot11f_ese_rad_mgmt_cap(&frm->ESERadMgmtCap); +#endif + } +#endif /* FEATURE_WLAN_ESE */ + + /* include WME EDCA IE as well */ + if (wme_enabled) { + populate_dot11f_wmm_info_station_per_session(mac_ctx, + pe_session, &frm->WMMInfoStation); + if (wsm_enabled) + populate_dot11f_wmm_caps(&frm->WMMCaps); +#ifdef FEATURE_WLAN_ESE + if (wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id)) { + uint32_t phymode; + uint8_t rate; + + populate_dot11f_re_assoc_tspec(mac_ctx, frm, + pe_session); + + /* + * Populate the TSRS IE if TSPEC is included in + * the reassoc request + */ + lim_get_phy_mode(mac_ctx, &phymode, pe_session); + if (phymode == WNI_CFG_PHY_MODE_11G || + phymode == WNI_CFG_PHY_MODE_11A) + rate = TSRS_11AG_RATE_6MBPS; + else + rate = TSRS_11B_RATE_5_5MBPS; + + if (mlme_priv->connect_info.ese_tspec_info.numTspecs) + { + struct ese_tsrs_ie tsrs_ie; + + tsrs_ie.tsid = 0; + tsrs_ie.rates[0] = rate; + populate_dot11_tsrsie(mac_ctx, &tsrs_ie, + &frm->ESETrafStrmRateSet, + sizeof(uint8_t)); + } + } +#endif + } + + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + } + if (pe_session->pLimReAssocReq->bssDescription.mdiePresent && + (mlme_priv->connect_info.ft_info.add_mdie) +#if defined FEATURE_WLAN_ESE + && !wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id) +#endif + ) { + populate_mdie(mac_ctx, &frm->MobilityDomain, + pe_session->pLimReAssocReq->bssDescription.mdie); + } + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + pe_debug("Populate VHT IEs in Re-Assoc Request"); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + vht_enabled = true; + populate_dot11f_ext_cap(mac_ctx, vht_enabled, &frm->ExtCap, + pe_session); + } + if (!vht_enabled && + pe_session->is_vendor_specific_vhtcaps) { + pe_debug("Populate Vendor VHT IEs in Re-Assoc Request"); + frm->vendor_vht_ie.present = 1; + frm->vendor_vht_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + frm->vendor_vht_ie.VHTCaps.present = 1; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm->vendor_vht_ie.VHTCaps); + vht_enabled = true; + } + + if (lim_is_session_he_capable(pe_session)) { + pe_debug("Populate HE IEs"); + populate_dot11f_he_caps(mac_ctx, pe_session, + &frm->he_cap); + populate_dot11f_he_6ghz_cap(mac_ctx, pe_session, + &frm->he_6ghz_band_cap); + } + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extr_ext_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap, true); + + /* Clear the bits in EXTCAP IE if AP not advertise it in beacon */ + if (frm->ExtCap.present && pe_session->is_ext_caps_present) { + ie_offset = DOT11F_FF_TIMESTAMP_LEN + + DOT11F_FF_BEACONINTERVAL_LEN + + DOT11F_FF_CAPABILITIES_LEN; + + qdf_mem_zero((uint8_t *)&bcn_ext_cap, sizeof(tDot11fIEExtCap)); + if (pe_session->beacon && (pe_session->bcnLen > + (ie_offset + sizeof(struct wlan_frame_hdr)))) { + bcn_ie = pe_session->beacon + ie_offset + + sizeof(struct wlan_frame_hdr); + bcn_ie_len = pe_session->bcnLen - ie_offset - + sizeof(struct wlan_frame_hdr); + p_ext_cap = (uint8_t *)wlan_get_ie_ptr_from_eid( + DOT11F_EID_EXTCAP, + bcn_ie, bcn_ie_len); + lim_update_extcap_struct(mac_ctx, p_ext_cap, + &bcn_ext_cap); + lim_merge_extcap_struct(&frm->ExtCap, &bcn_ext_cap, + false); + } + /* + * TWT extended capabilities should be populated after the + * intersection of beacon caps and self caps is done because + * the bits for TWT are unique to STA and AP and cannot be + * intersected. + */ + populate_dot11f_twt_extended_caps(mac_ctx, pe_session, + &frm->ExtCap); + } + + /* + * Do unpack to populate the add_ie buffer to frm structure + * before packing the frm structure. In this way, the IE ordering + * which the latest 802.11 spec mandates is maintained. + */ + if (add_ie_len) { + ret = dot11f_unpack_re_assoc_request(mac_ctx, add_ie, + add_ie_len, + frm, true); + if (DOT11F_FAILED(ret)) { + pe_err("unpack failed, ret: 0x%x", ret); + goto end; + } + } + + if (lim_is_session_eht_capable(pe_session)) { + pe_debug("Populate EHT IEs"); + populate_dot11f_eht_caps(mac_ctx, pe_session, &frm->eht_cap); + } + + status = dot11f_get_packed_re_assoc_request_size(mac_ctx, frm, + &payload); + if (DOT11F_FAILED(status)) { + pe_err("Failure in size calculation (0x%08x)", status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fReAssocRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("Warnings in size calculation (0x%08x)", status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr); + + pe_debug("FT IE Reassoc Req %d", + mlme_priv->connect_info.ft_info.reassoc_ie_len); + + if (pe_session->is11Rconnection) + ft_ies_length = mlme_priv->connect_info.ft_info.reassoc_ie_len; + + qdf_status = cds_packet_alloc((uint16_t) bytes + ft_ies_length, + (void **)&frame, (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + pe_err("Failed to alloc memory %d", bytes); + goto end; + } + /* Paranoia: */ + qdf_mem_zero(frame, bytes + ft_ies_length); + + pe_debug("BSSID: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pe_session->limReAssocbssId)); + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, pe_session->limReAssocbssId, + pe_session->self_mac_addr); + mac_hdr = (tpSirMacMgmtHdr) frame; + /* That done, pack the ReAssoc Request: */ + status = dot11f_pack_re_assoc_request(mac_ctx, frm, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Failure in pack (0x%08x)", status); + cds_packet_free((void *)packet); + goto end; + } else if (DOT11F_WARNED(status)) { + pe_warn("Warnings in pack (0x%08x)", status); + } + + pe_debug("*** Sending Re-Assoc Request length: %d %d to", + bytes, payload); + + if (pe_session->is11Rconnection && + mlme_priv->connect_info.ft_info.reassoc_ie_len) { + int i = 0; + + body = frame + bytes; + for (i = 0; i < ft_ies_length; i++) { + *body = + mlme_priv->connect_info.ft_info.reassoc_ft_ie[i]; + body++; + } + payload += ft_ies_length; + } + pe_debug("Re-assoc Req Frame is:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *) frame, (bytes + ft_ies_length)); + + if ((pe_session->ftPEContext.pFTPreAuthReq) && + (!wlan_reg_is_24ghz_ch_freq( + pe_session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq))) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + else if (wlan_reg_is_5ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (pe_session->assoc_req) { + qdf_mem_free(pe_session->assoc_req); + pe_session->assoc_req = NULL; + pe_session->assocReqLen = 0; + } + + pe_session->assoc_req = qdf_mem_malloc(payload); + if (pe_session->assoc_req) { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assoc_req, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_START_EVENT, + pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + lim_diag_mgmt_tx_event_report(mac_ctx, mac_hdr, + pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + qdf_status = wma_tx_frame(mac_ctx, packet, + (uint16_t) (bytes + ft_ies_length), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, tx_flag, vdev_id, + 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send Re-Assoc Request: %X!", qdf_status); + } + +end: + qdf_mem_free(frm); +err: + /* Free up buffer allocated for mlmAssocReq */ + qdf_mem_free(mlm_reassoc_req); + pe_session->pLimMlmReassocReq = NULL; + +} + +/** + * lim_send_retry_reassoc_req_frame() - Retry for reassociation + * @mac: Global MAC Context + * @pMlmReassocReq: Request buffer to be sent + * @pe_session: PE Session + * + * Return: None + */ +void lim_send_retry_reassoc_req_frame(struct mac_context *mac, + tLimMlmReassocReq *pMlmReassocReq, + struct pe_session *pe_session) +{ + tLimMlmReassocCnf mlmReassocCnf; /* keep sme */ + tLimMlmReassocReq *pTmpMlmReassocReq = NULL; + + if (!pTmpMlmReassocReq) { + pTmpMlmReassocReq = qdf_mem_malloc(sizeof(tLimMlmReassocReq)); + if (!pTmpMlmReassocReq) + goto end; + qdf_mem_copy(pTmpMlmReassocReq, pMlmReassocReq, + sizeof(tLimMlmReassocReq)); + } + /* Prepare and send Reassociation request frame */ + /* start reassoc timer. */ + mac->lim.lim_timers.gLimReassocFailureTimer.sessionId = + pe_session->peSessionId; + /* Start reassociation failure timer */ + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TIMER_ACTIVATE, + pe_session->peSessionId, eLIM_REASSOC_FAIL_TIMER)); + if (tx_timer_activate(&mac->lim.lim_timers.gLimReassocFailureTimer) + != TX_SUCCESS) { + /* Could not start reassoc failure timer. */ + /* Log error */ + pe_err("could not start Reassociation failure timer"); + /* Return Reassoc confirm with */ + /* Resources Unavailable */ + mlmReassocCnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + goto end; + } + + lim_send_reassoc_req_with_ft_ies_mgmt_frame(mac, pTmpMlmReassocReq, + pe_session); + return; + +end: + /* Free up buffer allocated for reassocReq */ + if (pMlmReassocReq) { + qdf_mem_free(pMlmReassocReq); + pMlmReassocReq = NULL; + } + if (pTmpMlmReassocReq) { + qdf_mem_free(pTmpMlmReassocReq); + pTmpMlmReassocReq = NULL; + } + mlmReassocCnf.resultCode = eSIR_SME_FT_REASSOC_FAILURE; + mlmReassocCnf.protStatusCode = STATUS_UNSPECIFIED_FAILURE; + /* Update PE session Id */ + mlmReassocCnf.sessionId = pe_session->peSessionId; + + lim_post_sme_message(mac, LIM_MLM_REASSOC_CNF, + (uint32_t *) &mlmReassocCnf); +} + +/** + * lim_send_reassoc_req_mgmt_frame() - Send the reassociation frame + * @mac: Global MAC Context + * @pMlmReassocReq: Reassociation request buffer to be sent + * @pe_session: PE Session + * + * Return: None + */ +void lim_send_reassoc_req_mgmt_frame(struct mac_context *mac, + tLimMlmReassocReq *pMlmReassocReq, + struct pe_session *pe_session) +{ + tDot11fReAssocRequest *frm; + uint16_t caps; + uint8_t *pFrame; + uint32_t nBytes, nPayload, nStatus; + uint8_t fQosEnabled, fWmeEnabled, fWsmEnabled; + void *pPacket; + QDF_STATUS qdf_status; + uint16_t nAddIELen; + uint8_t *pAddIE; + const uint8_t *wpsIe = NULL; + uint8_t txFlag = 0; + uint8_t PowerCapsPopulated = false; + uint8_t smeSessionId = 0; + bool isVHTEnabled = false; + tpSirMacMgmtHdr pMacHdr; + int ret; + tDot11fIEExtCap extr_ext_cap; + QDF_STATUS sir_status; + bool extr_ext_flag = true; + uint32_t ie_offset = 0; + tDot11fIEExtCap bcn_ext_cap; + uint8_t *bcn_ie = NULL; + uint32_t bcn_ie_len = 0; + uint8_t *p_ext_cap = NULL; + enum rateid min_rid = RATEID_DEFAULT; + + if (!pe_session) + return; + + smeSessionId = pe_session->smeSessionId; + if (!pe_session->pLimReAssocReq) + return; + + frm = qdf_mem_malloc(sizeof(*frm)); + if (!frm) + goto err; + nAddIELen = pe_session->pLimReAssocReq->addIEAssoc.length; + pAddIE = pe_session->pLimReAssocReq->addIEAssoc.addIEdata; + + qdf_mem_zero((uint8_t *) frm, sizeof(*frm)); + + if (nAddIELen && pe_session->is_ext_caps_present) { + qdf_mem_zero((uint8_t *)&extr_ext_cap, + sizeof(tDot11fIEExtCap)); + sir_status = lim_strip_extcap_update_struct( + mac, pAddIE, &nAddIELen, &extr_ext_cap); + if (QDF_STATUS_SUCCESS != sir_status) { + extr_ext_flag = false; + pe_debug("Unable to Stripoff ExtCap IE from Assoc Req"); + } else { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + extr_ext_cap.bytes; + + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extr_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length(&extr_ext_cap); + extr_ext_flag = (extr_ext_cap.num_bytes > 0); + } + } else { + pe_debug("No addn IE or peer doesn't support addnIE for Assoc Req"); + extr_ext_flag = false; + } + + caps = pMlmReassocReq->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * CR: 262463 : + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 in + * transmitted. Association or Reassociation management frames. APs + * ignore the Privacy subfield within received Association and + * Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm->Capabilities); + + frm->ListenInterval.interval = pMlmReassocReq->listenInterval; + + qdf_mem_copy((uint8_t *) frm->CurrentAPAddress.mac, + (uint8_t *) pe_session->bssId, 6); + + populate_dot11f_ssid2(pe_session, &frm->SSID); + populate_dot11f_supp_rates(mac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + fQosEnabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limReassocBssCaps); + + fWmeEnabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limReassocBssQosCaps); + + fWsmEnabled = (pe_session->limWsmEnabled) && fWmeEnabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limReassocBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->spectrumMgtEnabled) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(mac, &frm->PowerCaps, LIM_REASSOC, + pe_session); + populate_dot11f_supp_channels(mac, &frm->SuppChannels, + LIM_REASSOC, pe_session); + } + if (mac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (PowerCapsPopulated == false) { + PowerCapsPopulated = true; + populate_dot11f_power_caps(mac, &frm->PowerCaps, + LIM_REASSOC, pe_session); + } + } + + if (fQosEnabled) + populate_dot11f_qos_caps_station(mac, pe_session, + &frm->QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->ExtSuppRates, pe_session); + + if (mac->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) + populate_dot11f_rrm_ie(mac, &frm->RRMEnabledCap, pe_session); + /* The join request *should* contain zero or one of the WPA and RSN */ + /* IEs. The payload send along with the request is a */ + /* 'struct join_req'; the IE portion is held inside a 'tSirRSNie': */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[WLAN_MAX_IE_LEN+2]; */ + /* } tSirRSNie, *tpSirRSNie; */ + + /* So, we should be able to make the following two calls harmlessly, */ + /* since they do nothing if they don't find the given IE in the */ + /* bytestream with which they're provided. */ + + /* The net effect of this will be to faithfully transmit whatever */ + /* security IE is in the join request. */ + + /**However*, if we're associating for the purpose of WPS */ + /* enrollment, and we've been configured to indicate that by */ + /* eliding the WPA or RSN IE, we just skip this: */ + if (nAddIELen && pAddIE) + wpsIe = limGetWscIEPtr(mac, pAddIE, nAddIELen); + if (!wpsIe) { + populate_dot11f_rsn_opaque(mac, + &(pe_session->pLimReAssocReq->rsnIE), + &frm->RSNOpaque); + populate_dot11f_wpa_opaque(mac, + &(pe_session->pLimReAssocReq->rsnIE), + &frm->WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(mac, + &(pe_session->pLimReAssocReq-> + rsnIE), &frm->WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (fWmeEnabled) { + populate_dot11f_wmm_info_station_per_session(mac, + pe_session, &frm->WMMInfoStation); + + if (fWsmEnabled) + populate_dot11f_wmm_caps(&frm->WMMCaps); + } + + if (pe_session->htCapability && + mac->lim.htCapabilityPresentInBeacon) { + populate_dot11f_ht_caps(mac, pe_session, &frm->HTCaps); + } + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + pe_warn("Populate VHT IEs in Re-Assoc Request"); + populate_dot11f_vht_caps(mac, pe_session, &frm->VHTCaps); + isVHTEnabled = true; + } + populate_dot11f_ext_cap(mac, isVHTEnabled, &frm->ExtCap, pe_session); + + if (lim_is_session_he_capable(pe_session)) { + pe_debug("Populate HE IEs"); + populate_dot11f_he_caps(mac, pe_session, + &frm->he_cap); + populate_dot11f_he_6ghz_cap(mac, pe_session, + &frm->he_6ghz_band_cap); + } + + if (lim_is_session_eht_capable(pe_session)) { + pe_debug("Populate EHT IEs"); + populate_dot11f_eht_caps(mac, pe_session, &frm->eht_cap); + } + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extr_ext_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap, true); + + /* Clear the bits in EXTCAP IE if AP not advertise it in beacon */ + if (frm->ExtCap.present && pe_session->is_ext_caps_present) { + ie_offset = DOT11F_FF_TIMESTAMP_LEN + + DOT11F_FF_BEACONINTERVAL_LEN + + DOT11F_FF_CAPABILITIES_LEN; + + qdf_mem_zero((uint8_t *)&bcn_ext_cap, sizeof(tDot11fIEExtCap)); + if (pe_session->beacon && (pe_session->bcnLen > + (ie_offset + sizeof(struct wlan_frame_hdr)))) { + bcn_ie = pe_session->beacon + ie_offset + + sizeof(struct wlan_frame_hdr); + bcn_ie_len = pe_session->bcnLen - ie_offset - + sizeof(struct wlan_frame_hdr); + p_ext_cap = (uint8_t *)wlan_get_ie_ptr_from_eid( + DOT11F_EID_EXTCAP, + bcn_ie, bcn_ie_len); + lim_update_extcap_struct(mac, p_ext_cap, + &bcn_ext_cap); + lim_merge_extcap_struct(&frm->ExtCap, &bcn_ext_cap, + false); + } + /* + * TWT extended capabilities should be populated after the + * intersection of beacon caps and self caps is done because + * the bits for TWT are unique to STA and AP and cannot be + * intersected. + */ + populate_dot11f_twt_extended_caps(mac, pe_session, + &frm->ExtCap); + } + + /* + * Do unpack to populate the add_ie buffer to frm structure + * before packing the frm structure. In this way, the IE ordering + * which the latest 802.11 spec mandates is maintained. + */ + if (nAddIELen) { + ret = dot11f_unpack_re_assoc_request(mac, pAddIE, nAddIELen, + frm, true); + if (DOT11F_FAILED(ret)) { + pe_err("unpack failed, ret: 0x%x", ret); + goto end; + } + } + + nStatus = + dot11f_get_packed_re_assoc_request_size(mac, frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Fail to get size:ReassocReq: (0x%08x)", nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fReAssocRequest); + } else if (DOT11F_WARNED(nStatus)) { + pe_err("warning for size:ReAssoc Req: (0x%08x)", nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + pe_err("Failed to alloc %d bytes for a ReAssociation Req", + nBytes); + goto end; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_REASSOC_REQ, pe_session->limReAssocbssId, + pe_session->self_mac_addr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* That done, pack the Probe Request: */ + nStatus = dot11f_pack_re_assoc_request(mac, frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Fail to pack a Re-Assoc Req: (0x%08x)", nStatus); + cds_packet_free((void *)pPacket); + goto end; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("warning packing a Re-AssocReq: (0x%08x)", nStatus); + } + + lim_cp_stats_cstats_log_assoc_req_evt(pe_session, CSTATS_DIR_TX, + pMacHdr->bssId, pMacHdr->sa, + frm->SSID.num_ssid, + frm->SSID.ssid, + frm->HTCaps.present, + frm->VHTCaps.present, + frm->he_cap.present, + frm->eht_cap.present, true); + + pe_debug("*** Sending Re-Association Request length: %d" "to", nBytes); + + if (pe_session->assoc_req) { + qdf_mem_free(pe_session->assoc_req); + pe_session->assoc_req = NULL; + pe_session->assocReqLen = 0; + } + + pe_session->assoc_req = qdf_mem_malloc(nPayload); + if (pe_session->assoc_req) { + /* Store the Assocrequest. It is sent to csr in joincnfrsp */ + qdf_mem_copy(pe_session->assoc_req, + pFrame + sizeof(tSirMacMgmtHdr), nPayload); + pe_session->assocReqLen = nPayload; + } + + if (wlan_reg_is_5ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_STA_MODE) + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + lim_diag_event_report(mac, WLAN_PE_DIAG_REASSOC_START_EVENT, + pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + if (pe_session->is_oui_auth_assoc_6mbps_2ghz_enable) + min_rid = RATEID_6MBPS; + + qdf_status = + wma_tx_frame(mac, pPacket, + (uint16_t) (sizeof(tSirMacMgmtHdr) + nPayload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, txFlag, smeSessionId, 0, + min_rid, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send Re-Association Request: %X!", + qdf_status); + /* Pkt will be freed up by the callback */ + } + +end: + qdf_mem_free(frm); +err: + /* Free up buffer allocated for mlmAssocReq */ + qdf_mem_free(pMlmReassocReq); + pe_session->pLimMlmReassocReq = NULL; + +} + +void lim_process_rx_scan_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + struct mac_context *mac_ctx; + enum sir_scan_event_type event_type; + + pe_debug("event: %u, id: 0x%x, requestor: 0x%x, freq: %u, reason: %u", + event->type, event->scan_id, event->requester, + event->chan_freq, event->reason); + + mac_ctx = (struct mac_context *)arg; + event_type = 0x1 << event->type; + + qdf_mtrace(QDF_MODULE_ID_SCAN, QDF_MODULE_ID_PE, event->type, + event->vdev_id, event->scan_id); + + switch (event_type) { + case SIR_SCAN_EVENT_STARTED: + break; + case SIR_SCAN_EVENT_COMPLETED: + pe_debug("No.of beacons and probe response received per scan %d", + mac_ctx->lim.beacon_probe_rsp_cnt_per_scan); + fallthrough; + case SIR_SCAN_EVENT_FOREIGN_CHANNEL: + case SIR_SCAN_EVENT_START_FAILED: + if ((mac_ctx->lim.req_id | PREAUTH_REQUESTOR_ID) == + event->requester) + lim_preauth_scan_event_handler(mac_ctx, + event_type, + event->vdev_id, + event->scan_id); + break; + case SIR_SCAN_EVENT_BSS_CHANNEL: + case SIR_SCAN_EVENT_DEQUEUED: + case SIR_SCAN_EVENT_PREEMPTED: + default: + pe_debug("Received unhandled scan event %u", event_type); + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c new file mode 100644 index 0000000000..ad0c67d45d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c @@ -0,0 +1,7752 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: lim_send_management_frames.c + * + * WLAN Host Device Driver file for preparing and sending 802.11 Management + * frames + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "dot11f.h" +#include "sch_api.h" +#include "lim_send_messages.h" +#include "lim_assoc_utils.h" +#include "lim_ft.h" +#include "wni_cfg.h" + +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sme_trace.h" +#include "rrm_api.h" +#include "qdf_crypto.h" +#include "parser_api.h" + +#include "wma_types.h" +#include +#include +#include "lim_process_fils.h" +#include "wlan_utility.h" +#include +#include +#include "wlan_crypto_global_api.h" +#include "wlan_connectivity_logging.h" +#include "lim_mlo.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_t2lm_api.h" +#include "wlan_connectivity_logging.h" + +/** + * + * \brief This function is called to add the sequence number to the + * management frames + * + * \param mac Pointer to Global MAC structure + * + * \param pMacHdr Pointer to MAC management header + * + * The pMacHdr argument points to the MAC management header. The + * sequence number stored in the mac structure will be incremented + * and updated to the MAC management header. The start sequence + * number is WLAN_HOST_SEQ_NUM_MIN and the end value is + * WLAN_HOST_SEQ_NUM_MAX. After reaching the MAX value, the sequence + * number will roll over. + * + */ +static void lim_add_mgmt_seq_num(struct mac_context *mac, tpSirMacMgmtHdr pMacHdr) +{ + if (mac->mgmtSeqNum >= WLAN_HOST_SEQ_NUM_MAX) { + mac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + } + + mac->mgmtSeqNum++; + + pMacHdr->seqControl.seqNumLo = (mac->mgmtSeqNum & LOW_SEQ_NUM_MASK); + pMacHdr->seqControl.seqNumHi = + ((mac->mgmtSeqNum & HIGH_SEQ_NUM_MASK) >> HIGH_SEQ_NUM_OFFSET); + pMacHdr->seqControl.fragNum = 0; +} + +/** + * lim_populate_mac_header() - Fill in 802.11 header of frame + * + * @mac_ctx: Pointer to Global MAC structure + * @buf: Pointer to the frame buffer that needs to be populate + * @type: 802.11 Type of the frame + * @sub_type: 802.11 Subtype of the frame + * @peer_addr: dst address + * @self_mac_addr: local mac address + * + * This function is called by various LIM modules to prepare the + * 802.11 frame MAC header + * + * The buf argument points to the beginning of the frame buffer to + * which - a) The 802.11 MAC header is set b) Following this MAC header + * will be the MGMT frame payload The payload itself is populated by the + * caller API + * + * Return: None + */ + +void lim_populate_mac_header(struct mac_context *mac_ctx, uint8_t *buf, + uint8_t type, uint8_t sub_type, tSirMacAddr peer_addr, + tSirMacAddr self_mac_addr) +{ + tpSirMacMgmtHdr mac_hdr; + + /* Prepare MAC management header */ + mac_hdr = (tpSirMacMgmtHdr) (buf); + + /* Prepare FC */ + mac_hdr->fc.protVer = SIR_MAC_PROTOCOL_VERSION; + mac_hdr->fc.type = type; + mac_hdr->fc.subType = sub_type; + + /* Prepare Address 1 */ + qdf_mem_copy((uint8_t *) mac_hdr->da, + (uint8_t *) peer_addr, sizeof(tSirMacAddr)); + + /* Prepare Address 2 */ + sir_copy_mac_addr(mac_hdr->sa, self_mac_addr); + + /* Prepare Address 3 */ + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) peer_addr, sizeof(tSirMacAddr)); + + /* Prepare sequence number */ + lim_add_mgmt_seq_num(mac_ctx, mac_hdr); + pe_debug("seqNumLo=%d, seqNumHi=%d, mgmtSeqNum=%d, fragNum=%d", + mac_hdr->seqControl.seqNumLo, mac_hdr->seqControl.seqNumHi, + mac_ctx->mgmtSeqNum, mac_hdr->seqControl.fragNum); +} + +/** + * lim_send_probe_req_mgmt_frame() - send probe request management frame + * @mac_ctx: Pointer to Global MAC structure + * @ssid: SSID to be sent in Probe Request frame + * @bssid: BSSID to be sent in Probe Request frame + * @chan_freq: Channel frequency on which the Probe Request is going out + * @self_macaddr: self MAC address + * @dot11mode: self dotllmode + * @additional_ielen: if non-zero, include additional_ie in the Probe Request + * frame + * @additional_ie: if additional_ielen is non zero, include this field in the + * Probe Request frame + * + * This function is called by various LIM modules to send Probe Request frame + * during active scan/learn phase. + * Probe request is sent out in the following scenarios: + * --heartbeat failure: session needed + * --join req: session needed + * --foreground scan: no session + * --background scan: no session + * --sch_beacon_processing: to get EDCA parameters: session needed + * + * Return: QDF_STATUS (QDF_STATUS_SUCCESS on success and error codes otherwise) + */ +QDF_STATUS +lim_send_probe_req_mgmt_frame(struct mac_context *mac_ctx, + tSirMacSSid *ssid, + tSirMacAddr bssid, + qdf_freq_t chan_freq, + tSirMacAddr self_macaddr, + uint32_t dot11mode, + uint16_t *additional_ielen, + uint8_t *additional_ie) +{ + tDot11fProbeRequest *pr; + uint32_t status, bytes, payload; + uint8_t *frame; + void *packet; + QDF_STATUS qdf_status; + struct pe_session *pesession = NULL; + uint8_t sessionid; + const uint8_t *p2pie = NULL; + uint8_t txflag = 0; + uint8_t vdev_id = 0; + bool is_vht_enabled = false; + uint8_t txPower; + uint16_t addn_ielen = 0; + bool extracted_ext_cap_flag = false; + tDot11fIEExtCap extracted_ext_cap; + QDF_STATUS sir_status; + const uint8_t *qcn_ie = NULL; + uint8_t channel; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + bool is_band_2g; + uint16_t mlo_ie_len = 0; + tSirMacAddr bcast_mac = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + if (additional_ielen) + addn_ielen = *additional_ielen; + + channel = wlan_reg_freq_to_chan(mac_ctx->pdev, chan_freq); + /* + * The probe req should not send 11ac capabilities if band is + * 2.4GHz, unless gEnableVhtFor24GHzBand is enabled in INI. So + * if gEnableVhtFor24GHzBand is false and dot11mode is 11ac + * set it to 11n. + */ + if (wlan_reg_is_24ghz_ch_freq(chan_freq) && + !mac_ctx->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band && + (MLME_DOT11_MODE_11AC == dot11mode || + MLME_DOT11_MODE_11AC_ONLY == dot11mode)) + dot11mode = MLME_DOT11_MODE_11N; + /* + * session context may or may not be present, when probe request needs + * to be sent out. Following cases exist: + * --heartbeat failure: session needed + * --join req: session needed + * --foreground scan: no session + * --background scan: no session + * --sch_beacon_processing: to get EDCA parameters: session needed + * If session context does not exist, some IEs will be populated from + * CFGs, e.g. Supported and Extended rate set IEs + */ + pesession = pe_find_session_by_bssid(mac_ctx, bssid, &sessionid); + + if (pesession) + vdev_id = pesession->vdev_id; + + pr = qdf_mem_malloc(sizeof(*pr)); + if (!pr) { + pe_err("memory alloc failed for probe request"); + return QDF_STATUS_E_NOMEM; + } + + /* + * Some IOT APs doesn't respond to unicast probe requests, + * however those APs respond to broadcast probe requests. + * Therefore for hidden ssid connections, after 3 unicast probe + * requests, try the pending probes with broadcast mac. + */ + if (pesession && !WLAN_REG_IS_6GHZ_CHAN_FREQ(pesession->curr_op_freq) && + pesession->join_probe_cnt > 2) + sir_copy_mac_addr(bssid, bcast_mac); + + /* The scheme here is to fill out a 'tDot11fProbeRequest' structure */ + /* and then hand it off to 'dot11f_pack_probe_request' (for */ + /* serialization). */ + + /* & delegating to assorted helpers: */ + populate_dot11f_ssid(mac_ctx, ssid, &pr->SSID); + + if (addn_ielen && additional_ie) + p2pie = limGetP2pIEPtr(mac_ctx, additional_ie, addn_ielen); + + /* + * Don't include 11b rate if it is a P2P search or probe request is + * sent by P2P Client + */ + if ((MLME_DOT11_MODE_11B != dot11mode) && (p2pie) && + ((pesession) && (QDF_P2P_CLIENT_MODE == pesession->opmode))) { + /* + * In the below API pass channel number > 14, do that it fills + * only 11a rates in supported rates + */ + populate_dot11f_supp_rates(mac_ctx, 15, &pr->SuppRates, + pesession); + } else { + populate_dot11f_supp_rates(mac_ctx, channel, + &pr->SuppRates, pesession); + + if (MLME_DOT11_MODE_11B != dot11mode) { + populate_dot11f_ext_supp_rates1(mac_ctx, channel, + &pr->ExtSuppRates); + } + } + + /* + * Table 7-14 in IEEE Std. 802.11k-2008 says + * DS params "can" be present in RRM is disabled and "is" present if + * RRM is enabled. It should be ok even if we add it into probe req when + * RRM is not enabled. + */ + populate_dot11f_ds_params(mac_ctx, &pr->DSParams, + chan_freq); + /* Call RRM module to get the tx power for management used. */ + txPower = (uint8_t) rrm_get_mgmt_tx_power(mac_ctx, pesession); + populate_dot11f_wfatpc(mac_ctx, &pr->WFATPC, txPower, 0); + + if (pesession) { + /* Include HT Capability IE */ + if (pesession->htCapability && + !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq))) + populate_dot11f_ht_caps(mac_ctx, pesession, + &pr->HTCaps); + } else { /* !pesession */ + if (IS_DOT11_MODE_HT(dot11mode) && + !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq))) + populate_dot11f_ht_caps(mac_ctx, NULL, &pr->HTCaps); + } + + /* + * Set channelbonding information as "disabled" when tuned to a + * 2.4 GHz channel + */ + if (wlan_reg_is_24ghz_ch_freq(chan_freq)) { + if (mac_ctx->roam.configParam.channelBondingMode24GHz + == PHY_SINGLE_CHANNEL_CENTERED) { + pr->HTCaps.supportedChannelWidthSet = + eHT_CHANNEL_WIDTH_20MHZ; + pr->HTCaps.shortGI40MHz = 0; + } else { + pr->HTCaps.supportedChannelWidthSet = + eHT_CHANNEL_WIDTH_40MHZ; + } + } + if (pesession) { + /* Include VHT Capability IE */ + if (pesession->vhtCapability && + !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq))) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr->VHTCaps); + is_vht_enabled = true; + } + } else { + if (IS_DOT11_MODE_VHT(dot11mode) && + !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq))) { + populate_dot11f_vht_caps(mac_ctx, pesession, + &pr->VHTCaps); + is_vht_enabled = true; + } + } + if (pesession) + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &pr->ExtCap, + pesession); + + if (IS_DOT11_MODE_HE(dot11mode) && pesession) + lim_update_session_he_capable(mac_ctx, pesession); + + populate_dot11f_he_caps(mac_ctx, pesession, &pr->he_cap); + populate_dot11f_he_6ghz_cap(mac_ctx, pesession, + &pr->he_6ghz_band_cap); + + if (IS_DOT11_MODE_EHT(dot11mode) && pesession && + pesession->lim_join_req && + !qdf_is_macaddr_broadcast((struct qdf_mac_addr *)bssid)) { + lim_update_session_eht_capable(mac_ctx, pesession); + + if (pesession->lim_join_req->bssDescription.is_ml_ap) + mlo_ie_len = lim_send_probe_req_frame_mlo(mac_ctx, pesession); + } + + populate_dot11f_eht_caps(mac_ctx, pesession, &pr->eht_cap); + + if (addn_ielen && additional_ie) { + qdf_mem_zero((uint8_t *)&extracted_ext_cap, + sizeof(tDot11fIEExtCap)); + sir_status = lim_strip_extcap_update_struct(mac_ctx, + additional_ie, + &addn_ielen, + &extracted_ext_cap); + if (QDF_STATUS_SUCCESS != sir_status) { + pe_debug("Unable to Stripoff ExtCap IE from Probe Req"); + } else { + struct s_ext_cap *p_ext_cap = + (struct s_ext_cap *) + extracted_ext_cap.bytes; + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extracted_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length + (&extracted_ext_cap); + extracted_ext_cap_flag = + (extracted_ext_cap.num_bytes > 0); + if (additional_ielen) + *additional_ielen = addn_ielen; + } + qcn_ie = wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_QCN_OUI_TYPE, + SIR_MAC_QCN_OUI_TYPE_SIZE, + additional_ie, addn_ielen); + } + + /* Add qcn_ie only if qcn ie is not present in additional_ie */ + if (pesession) { + if (!qcn_ie) + populate_dot11f_qcn_ie(mac_ctx, pesession, + &pr->qcn_ie, + QCN_IE_ATTR_ID_ALL); + else + populate_dot11f_qcn_ie(mac_ctx, pesession, + &pr->qcn_ie, + QCN_IE_ATTR_ID_VHT_MCS11); + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extracted_ext_cap_flag) + lim_merge_extcap_struct(&pr->ExtCap, &extracted_ext_cap, true); + + if (pesession) + populate_dot11f_btm_extended_caps(mac_ctx, pesession, + &pr->ExtCap); + + if (lim_is_session_eht_capable(pesession)) { + eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + MIN_IE_LEN); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + qdf_status = QDF_STATUS_E_NOMEM; + goto mem_free; + } + is_band_2g = WLAN_REG_IS_24GHZ_CH_FREQ(pesession->curr_op_freq); + lim_ieee80211_pack_ehtcap(eht_cap_ie, pr->eht_cap, pr->he_cap, + is_band_2g); + eht_cap_ie_len = eht_cap_ie[TAG_LEN_POS] + MIN_IE_LEN; + pr->eht_cap.present = false; + } + + /* That's it-- now we pack it. First, how much space are we going to */ + status = dot11f_get_packed_probe_request_size(mac_ctx, pr, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a Probe Request (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a Probe Request (0x%08x)", + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + addn_ielen + mlo_ie_len + + eht_cap_ie_len; + + /* Ok-- try to allocate some memory: */ + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a Probe Request", bytes); + qdf_status = QDF_STATUS_E_NOMEM; + goto mem_free; + } + /* Paranoia: */ + qdf_mem_zero(frame, bytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_REQ, bssid, self_macaddr); + + /* That done, pack the Probe Request: */ + status = dot11f_pack_probe_request(mac_ctx, pr, frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a Probe Request (0x%08x)", status); + cds_packet_free((void *)packet); + qdf_status = QDF_STATUS_E_FAILURE; + goto mem_free; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing a Probe Request (0x%08x)", status); + } + + if (eht_cap_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + eht_cap_ie, eht_cap_ie_len); + payload += eht_cap_ie_len; + } + + /* Append any AddIE if present. */ + if (addn_ielen) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + additional_ie, addn_ielen); + payload += addn_ielen; + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pesession, mlo_ie_len, + frame + sizeof(tSirMacMgmtHdr) + payload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error, status %d", qdf_status); + mlo_ie_len = 0; + } + + payload += mlo_ie_len; + } + + pe_nofl_debug("Probe req TX: vdev %d seq num %d to " QDF_MAC_ADDR_FMT " len %d", + vdev_id, mac_ctx->mgmtSeqNum, + QDF_MAC_ADDR_REF(bssid), + (int)sizeof(tSirMacMgmtHdr) + payload); + mgmt_txrx_frame_hex_dump(frame, sizeof(tSirMacMgmtHdr) + payload, true); + + /* If this probe request is sent during P2P Search State, then we need + * to send it at OFDM rate. + */ + if ((REG_BAND_5G == lim_get_rf_band(chan_freq)) || + /* + * For unicast probe req mgmt from Join function we don't set + * above variables. So we need to add one more check whether it + * is opmode is P2P_CLIENT or not + */ + ((pesession) && (QDF_P2P_CLIENT_MODE == pesession->opmode))) + txflag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + qdf_status = + wma_tx_frame(mac_ctx, packet, + (uint16_t) sizeof(tSirMacMgmtHdr) + payload, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, txflag, vdev_id, + 0, RATEID_DEFAULT, 0); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("could not send Probe Request frame!"); + /* Pkt will be freed up by the callback */ + qdf_status = QDF_STATUS_E_FAILURE; + goto mem_free; + } + + qdf_status = QDF_STATUS_SUCCESS; + +mem_free: + qdf_mem_free(eht_cap_ie); + qdf_mem_free(pr); + + return qdf_status; +} /* End lim_send_probe_req_mgmt_frame. */ + +static QDF_STATUS lim_get_addn_ie_for_probe_resp(struct mac_context *mac, + uint8_t *addIE, uint16_t *addnIELen, + uint8_t probeReqP2pIe) +{ + /* If Probe request doesn't have P2P IE, then take out P2P IE + from additional IE */ + if (!probeReqP2pIe) { + uint8_t *tempbuf = NULL; + uint16_t tempLen = 0; + int left = *addnIELen; + uint8_t *ptr = addIE; + uint8_t elem_id, elem_len; + + if (!addIE) { + pe_err("NULL addIE pointer"); + return QDF_STATUS_E_FAILURE; + } + + tempbuf = qdf_mem_malloc(left); + if (!tempbuf) + return QDF_STATUS_E_NOMEM; + + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + pe_err("Invalid IEs eid: %d elem_len: %d left: %d", + elem_id, elem_len, left); + qdf_mem_free(tempbuf); + return QDF_STATUS_E_FAILURE; + } + if (!((WLAN_ELEMID_VENDOR == elem_id) && + (memcmp + (&ptr[2], SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE) == 0))) { + qdf_mem_copy(tempbuf + tempLen, &ptr[0], + elem_len + 2); + tempLen += (elem_len + 2); + } + left -= elem_len; + ptr += (elem_len + 2); + } + qdf_mem_copy(addIE, tempbuf, tempLen); + *addnIELen = tempLen; + qdf_mem_free(tempbuf); + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_add_additional_ie() - Add additional IE to management frame + * @frame: pointer to frame + * @frame_offset: current offset of frame + * @add_ie: pointer to additional ie + * @add_ie_len: length of additional ie + * @p2p_ie: pointer to p2p ie + * @noa_ie: pointer to noa ie, this is separate p2p ie + * @noa_ie_len: length of noa ie + * @noa_stream: pointer to noa stream, this is noa attribute only + * @noa_stream_len: length of noa stream + * + * This function adds additional IE to management frame. + * + * Return: None + */ +static void lim_add_additional_ie(uint8_t *frame, uint32_t frame_offset, + uint8_t *add_ie, uint32_t add_ie_len, + uint8_t *p2p_ie, uint8_t *noa_ie, + uint32_t noa_ie_len, uint8_t *noa_stream, + uint32_t noa_stream_len) { + uint16_t p2p_ie_offset; + + if (!add_ie_len || !add_ie) { + pe_debug("no valid additional ie"); + return; + } + + if (!noa_stream_len) { + qdf_mem_copy(frame + frame_offset, &add_ie[0], add_ie_len); + return; + } + + if (noa_ie_len > (SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN)) { + pe_err("Not able to insert NoA, len=%d", noa_ie_len); + return; + } else if (noa_ie_len > 0) { + pe_debug("new p2p ie for noa attr"); + qdf_mem_copy(frame + frame_offset, &add_ie[0], add_ie_len); + frame_offset += add_ie_len; + qdf_mem_copy(frame + frame_offset, &noa_ie[0], noa_ie_len); + } else { + if (!p2p_ie || (p2p_ie < add_ie) || + (p2p_ie > (add_ie + add_ie_len))) { + pe_err("invalid p2p ie"); + return; + } + p2p_ie_offset = p2p_ie - add_ie + p2p_ie[1] + 2; + if (p2p_ie_offset > add_ie_len) { + pe_err("Invalid p2p ie"); + return; + } + pe_debug("insert noa attr to existed p2p ie"); + p2p_ie[1] = p2p_ie[1] + noa_stream_len; + qdf_mem_copy(frame + frame_offset, &add_ie[0], p2p_ie_offset); + frame_offset += p2p_ie_offset; + qdf_mem_copy(frame + frame_offset, &noa_stream[0], + noa_stream_len); + if (p2p_ie_offset < add_ie_len) { + frame_offset += noa_stream_len; + qdf_mem_copy(frame + frame_offset, + &add_ie[p2p_ie_offset], + add_ie_len - p2p_ie_offset); + } + } +} + +void +lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_macaddr, + tpAniSSID ssid, + struct pe_session *pe_session, + uint8_t preq_p2pie) +{ + tDot11fProbeResponse *frm; + QDF_STATUS sir_status; + uint32_t cfg, payload, bytes = 0, status; + tpSirMacMgmtHdr mac_hdr; + uint8_t *frame; + void *packet = NULL; + QDF_STATUS qdf_status; + uint32_t addn_ie_present = false; + + uint16_t addn_ie_len = 0; + bool wps_ap = 0; + uint8_t tx_flag = 0; + uint8_t *add_ie = NULL; + uint8_t *p2p_ie = NULL; + uint8_t noalen = 0; + uint8_t total_noalen = 0; + uint8_t noa_stream[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t noa_ie[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t vdev_id = 0; + bool is_vht_enabled = false; + tDot11fIEExtCap extracted_ext_cap = {0}; + bool extracted_ext_cap_flag = false; + uint16_t mlo_ie_len = 0; + uint16_t tpe_ie_len = 0; + tDot11fIEtransmit_power_env *transmit_power_env = NULL; + uint16_t num_transmit_power_env = 0; + + /* We don't answer requests in this case*/ + if (ANI_DRIVER_TYPE(mac_ctx) == QDF_DRIVER_TYPE_MFG) + return; + + if (!pe_session) + return; + + /* + * In case when cac timer is running for this SAP session then + * avoid sending probe rsp out. It is violation of dfs specification. + */ + if (((pe_session->opmode == QDF_SAP_MODE) || + (pe_session->opmode == QDF_P2P_GO_MODE)) && + (true == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + pe_info("CAC timer is running, probe response dropped"); + return; + } + if (wlan_vdev_is_up(pe_session->vdev) != QDF_STATUS_SUCCESS) + return; + + vdev_id = pe_session->vdev_id; + frm = qdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (!frm) + return; + /* + * Fill out 'frm', after which we'll just hand the struct off to + * 'dot11f_pack_probe_response'. + */ + qdf_mem_zero((uint8_t *) frm, sizeof(tDot11fProbeResponse)); + + /* + * Timestamp to be updated by TFP, below. + * + * Beacon Interval: + */ + if (LIM_IS_AP_ROLE(pe_session)) { + frm->BeaconInterval.interval = + mac_ctx->sch.beacon_interval; + } else { + cfg = mac_ctx->mlme_cfg->sap_cfg.beacon_interval; + frm->BeaconInterval.interval = (uint16_t) cfg; + } + + populate_dot11f_capabilities(mac_ctx, &frm->Capabilities, pe_session); + populate_dot11f_ssid(mac_ctx, (tSirMacSSid *) ssid, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + populate_dot11f_tpc_report(mac_ctx, &frm->TPCReport, pe_session); + + populate_dot11f_ds_params( + mac_ctx, &frm->DSParams, + pe_session->curr_op_freq); + + if (LIM_IS_AP_ROLE(pe_session)) { + if (pe_session->wps_state != SAP_WPS_DISABLED) + populate_dot11f_probe_res_wpsi_es(mac_ctx, + &frm->WscProbeRes, + pe_session); + } else { + wps_ap = mac_ctx->mlme_cfg->wps_params.enable_wps & + WNI_CFG_WPS_ENABLE_AP; + if (wps_ap) + populate_dot11f_wsc_in_probe_res(mac_ctx, + &frm->WscProbeRes); + + if (mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState == + eLIM_WSC_ENROLL_BEGIN) { + populate_dot11f_wsc_registrar_info_in_probe_res(mac_ctx, + &frm->WscProbeRes); + mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState = + eLIM_WSC_ENROLL_IN_PROGRESS; + } + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_END) { + de_populate_dot11f_wsc_registrar_info_in_probe_res( + mac_ctx, &frm->WscProbeRes); + mac_ctx->lim.wscIeInfo.probeRespWscEnrollmentState = + eLIM_WSC_ENROLL_NOOP; + } + } + + populate_dot11f_country(mac_ctx, &frm->Country, pe_session); + populate_dot11f_edca_param_set(mac_ctx, &frm->EDCAParamSet, pe_session); + + if (pe_session->dot11mode != MLME_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &frm->ERPInfo, pe_session); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->ExtSuppRates, pe_session); + + /* Populate HT IEs, when operating in 11n */ + if (pe_session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + populate_dot11f_ht_info(mac_ctx, &frm->HTInfo, pe_session); + } + if (pe_session->vhtCapability) { + pe_debug("Populate VHT IE in Probe Response"); + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm->VHTOperation); + /* + * we do not support multi users yet. + * populate_dot11f_vht_ext_bss_load( mac_ctx, + * &frm.VHTExtBssLoad ); + */ + is_vht_enabled = true; + } + + if (pe_session->vhtCapability || + wlan_reg_is_6ghz_chan_freq(pe_session->curr_op_freq)) { + transmit_power_env = qdf_mem_malloc( + WLAN_MAX_NUM_TPE_IE * + sizeof(tDot11fIEtransmit_power_env)); + if (!transmit_power_env) + goto err_ret; + + populate_dot11f_tx_power_env(mac_ctx, + transmit_power_env, + pe_session->ch_width, + pe_session->curr_op_freq, + &num_transmit_power_env, + false); + tpe_ie_len = lim_get_tpe_ie_length(pe_session->ch_width, + transmit_power_env, + num_transmit_power_env); + } + + if (lim_is_session_he_capable(pe_session)) { + pe_debug("Populate HE IEs"); + populate_dot11f_he_caps(mac_ctx, pe_session, + &frm->he_cap); + populate_dot11f_he_operation(mac_ctx, pe_session, + &frm->he_op); + populate_dot11f_sr_info(mac_ctx, pe_session, + &frm->spatial_reuse); + populate_dot11f_he_6ghz_cap(mac_ctx, pe_session, + &frm->he_6ghz_band_cap); + } + + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) { + mlo_ie_len = lim_send_bcn_frame_mlo(mac_ctx, pe_session); + populate_dot11f_mlo_rnr(mac_ctx, pe_session, + &frm->reduced_neighbor_report); + } + if (lim_is_session_eht_capable(pe_session)) { + pe_debug("Populate EHT IEs"); + populate_dot11f_eht_caps(mac_ctx, pe_session, &frm->eht_cap); + populate_dot11f_eht_operation(mac_ctx, pe_session, + &frm->eht_op); + } + + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &frm->ExtCap, + pe_session); + + if (pe_session->pLimStartBssReq) { + populate_dot11f_wpa(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->RSNOpaque); + } + + populate_dot11f_wmm(mac_ctx, &frm->WMMInfoAp, &frm->WMMParams, + &frm->WMMCaps, pe_session); + +#if defined(FEATURE_WLAN_WAPI) + if (pe_session->pLimStartBssReq) + populate_dot11f_wapi(mac_ctx, + &(pe_session->pLimStartBssReq->rsnIE), + &frm->WAPI); +#endif /* defined(FEATURE_WLAN_WAPI) */ + + /* + * Only use CFG for non-listen mode. This CFG is not working for + * concurrency. In listening mode, probe rsp IEs is passed in + * the message from SME to PE. + */ + addn_ie_present = + (pe_session->add_ie_params.probeRespDataLen != 0); + + if (addn_ie_present) { + + add_ie = qdf_mem_malloc( + pe_session->add_ie_params.probeRespDataLen); + if (!add_ie) + goto err_ret; + + qdf_mem_copy(add_ie, + pe_session->add_ie_params.probeRespData_buff, + pe_session->add_ie_params.probeRespDataLen); + addn_ie_len = pe_session->add_ie_params.probeRespDataLen; + + if (QDF_STATUS_SUCCESS != lim_get_addn_ie_for_probe_resp(mac_ctx, + add_ie, &addn_ie_len, preq_p2pie)) { + pe_err("Unable to get addn_ie"); + goto err_ret; + } + + sir_status = lim_strip_extcap_update_struct(mac_ctx, + add_ie, &addn_ie_len, + &extracted_ext_cap); + if (QDF_STATUS_SUCCESS != sir_status) { + pe_debug("Unable to strip off ExtCap IE"); + } else { + extracted_ext_cap_flag = true; + } + + bytes = bytes + addn_ie_len; + + if (preq_p2pie) + p2p_ie = (uint8_t *)limGetP2pIEPtr(mac_ctx, &add_ie[0], + addn_ie_len); + + if (p2p_ie) { + /* get NoA attribute stream P2P IE */ + noalen = lim_get_noa_attr_stream(mac_ctx, + noa_stream, pe_session); + if (noalen) { + if ((p2p_ie[1] + noalen) > + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + total_noalen = lim_build_p2p_ie( + mac_ctx, + &noa_ie[0], + &noa_stream[0], + noalen); + bytes = bytes + total_noalen; + } else { + bytes = bytes + noalen; + } + } + } + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extracted_ext_cap_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extracted_ext_cap, + true); + populate_dot11f_bcn_prot_extcaps(mac_ctx, pe_session, &frm->ExtCap); + + status = dot11f_get_packed_probe_response_size(mac_ctx, frm, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Probe Response size error (0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fProbeResponse); + } else if (DOT11F_WARNED(status)) { + pe_warn("Probe Response size warning (0x%08x)", + status); + } + + bytes += payload + sizeof(tSirMacMgmtHdr) + mlo_ie_len + tpe_ie_len; + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Probe Response allocation failed"); + goto err_ret; + } + /* Paranoia: */ + qdf_mem_zero(frame, bytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, peer_macaddr, + pe_session->self_mac_addr); + + mac_hdr = (tpSirMacMgmtHdr) frame; + + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + + /* That done, pack the Probe Response: */ + status = + dot11f_pack_probe_response(mac_ctx, frm, + frame + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Probe Response pack failure (0x%08x)", + status); + goto err_ret; + } else if (DOT11F_WARNED(status)) { + pe_warn("Probe Response pack warning (0x%08x)", status); + } + + if (tpe_ie_len) { + qdf_status = lim_fill_complete_tpe_ie( + pe_session->ch_width, tpe_ie_len, + transmit_power_env, + num_transmit_power_env, frame + + sizeof(tSirMacMgmtHdr) + payload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble tpe ie error"); + tpe_ie_len = 0; + } + payload += tpe_ie_len; + } + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + frame + sizeof(tSirMacMgmtHdr) + payload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + payload += mlo_ie_len; + } + + pe_debug("Sending Probe Response frame to: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_macaddr)); + + lim_add_additional_ie(frame, sizeof(tSirMacMgmtHdr) + payload, add_ie, + addn_ie_len, p2p_ie, noa_ie, total_noalen, + noa_stream, noalen); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + /* Queue Probe Response frame in high priority WQ */ + qdf_status = wma_tx_frame(mac_ctx, packet, + (uint16_t)bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + vdev_id, 0, RATEID_DEFAULT, 0); + + /* Pkt will be freed up by the callback */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + pe_err("Could not send Probe Response"); + + if (add_ie) + qdf_mem_free(add_ie); + qdf_mem_free(transmit_power_env); + qdf_mem_free(frm); + + return; + +err_ret: + if (add_ie) + qdf_mem_free(add_ie); + if (frm) + qdf_mem_free(frm); + if (packet) + cds_packet_free((void *)packet); + if (transmit_power_env) + qdf_mem_free(transmit_power_env); + + return; + +} /* End lim_send_probe_rsp_mgmt_frame. */ + +void +lim_send_addts_req_action_frame(struct mac_context *mac, + tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *pAddTS, struct pe_session *pe_session) +{ + uint16_t i; + uint8_t *pFrame; + tDot11fAddTSRequest AddTSReq; + tDot11fWMMAddTSRequest WMMAddTSReq; + uint32_t nPayload, nBytes, nStatus; + tpSirMacMgmtHdr pMacHdr; + void *pPacket; +#ifdef FEATURE_WLAN_ESE + uint32_t phyMode; +#endif + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (!pe_session) { + return; + } + + smeSessionId = pe_session->smeSessionId; + + if (!pAddTS->wmeTspecPresent) { + qdf_mem_zero((uint8_t *) &AddTSReq, sizeof(AddTSReq)); + + AddTSReq.Action.action = QOS_ADD_TS_REQ; + AddTSReq.DialogToken.token = pAddTS->dialogToken; + AddTSReq.Category.category = ACTION_CATEGORY_QOS; + if (pAddTS->lleTspecPresent) { + populate_dot11f_tspec(&pAddTS->tspec, &AddTSReq.TSPEC); + } else { + populate_dot11f_wmmtspec(&pAddTS->tspec, + &AddTSReq.WMMTSPEC); + } + + if (pAddTS->lleTspecPresent) { + AddTSReq.num_WMMTCLAS = 0; + AddTSReq.num_TCLAS = pAddTS->numTclas; + for (i = 0; i < pAddTS->numTclas; ++i) { + populate_dot11f_tclas(mac, &pAddTS->tclasInfo[i], + &AddTSReq.TCLAS[i]); + } + } else { + AddTSReq.num_TCLAS = 0; + AddTSReq.num_WMMTCLAS = pAddTS->numTclas; + for (i = 0; i < pAddTS->numTclas; ++i) { + populate_dot11f_wmmtclas(mac, + &pAddTS->tclasInfo[i], + &AddTSReq.WMMTCLAS[i]); + } + } + + if (pAddTS->tclasProcPresent) { + if (pAddTS->lleTspecPresent) { + AddTSReq.TCLASSPROC.processing = + pAddTS->tclasProc; + AddTSReq.TCLASSPROC.present = 1; + } else { + AddTSReq.WMMTCLASPROC.version = 1; + AddTSReq.WMMTCLASPROC.processing = + pAddTS->tclasProc; + AddTSReq.WMMTCLASPROC.present = 1; + } + } + + nStatus = + dot11f_get_packed_add_ts_request_size(mac, &AddTSReq, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for an Add TS Request (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fAddTSRequest); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for an Add TS Request (0x%08x)", + nStatus); + } + } else { + qdf_mem_zero((uint8_t *) &WMMAddTSReq, sizeof(WMMAddTSReq)); + + WMMAddTSReq.Action.action = QOS_ADD_TS_REQ; + WMMAddTSReq.DialogToken.token = pAddTS->dialogToken; + WMMAddTSReq.Category.category = ACTION_CATEGORY_WMM; + + /* WMM spec 2.2.10 - status code is only filled in for ADDTS response */ + WMMAddTSReq.StatusCode.statusCode = 0; + + populate_dot11f_wmmtspec(&pAddTS->tspec, &WMMAddTSReq.WMMTSPEC); +#ifdef FEATURE_WLAN_ESE + lim_get_phy_mode(mac, &phyMode, pe_session); + + if (phyMode == WNI_CFG_PHY_MODE_11G + || phyMode == WNI_CFG_PHY_MODE_11A) { + pAddTS->tsrsIE.rates[0] = TSRS_11AG_RATE_6MBPS; + } else { + pAddTS->tsrsIE.rates[0] = TSRS_11B_RATE_5_5MBPS; + } + populate_dot11_tsrsie(mac, &pAddTS->tsrsIE, + &WMMAddTSReq.ESETrafStrmRateSet, + sizeof(uint8_t)); +#endif + /* fillWmeTspecIE */ + + nStatus = + dot11f_get_packed_wmm_add_ts_request_size(mac, &WMMAddTSReq, + &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a WMM Add TS Request (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fAddTSRequest); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a WMM Add TS Request (0x%08x)", + nStatus); + } + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for an Add TS Request", + nBytes); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peerMacAddr, pe_session->self_mac_addr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + lim_set_protected_bit(mac, pe_session, peerMacAddr, pMacHdr); + + /* That done, pack the struct: */ + if (!pAddTS->wmeTspecPresent) { + nStatus = dot11f_pack_add_ts_request(mac, &AddTSReq, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack an Add TS Request " + "(0x%08x)", nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing an Add TS Request (0x%08x)", + nStatus); + } + } else { + nStatus = dot11f_pack_wmm_add_ts_request(mac, &WMMAddTSReq, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a WMM Add TS Request (0x%08x)", + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a WMM Add TS Request (0x%08x)", + nStatus); + } + } + + pe_debug("Sending an Add TS Request frame to "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peerMacAddr)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + /* Queue Addts Response frame in high priority WQ */ + qdf_status = wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + pe_err("Could not send an Add TS Request (%X", + qdf_status); +} /* End lim_send_addts_req_action_frame. */ + +#ifdef WLAN_FEATURE_MSCS +/** + * lim_mscs_req_tx_complete_cnf()- Confirmation for mscs req sent over the air + * @context: pointer to global mac + * @buf: buffer + * @tx_complete : Sent status + * @params; tx completion params + * + * Return: This returns QDF_STATUS + */ + +static QDF_STATUS lim_mscs_req_tx_complete_cnf(void *context, qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + uint16_t mscs_ack_status; + uint16_t reason_code; + + pe_debug("mscs req TX: %s (%d)", + (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) ? + "success" : "fail", tx_complete); + + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) { + mscs_ack_status = ACKED; + reason_code = QDF_STATUS_SUCCESS; + } else { + mscs_ack_status = NOT_ACKED; + reason_code = QDF_STATUS_E_FAILURE; + } + if (buf) + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +void lim_send_mscs_req_action_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + struct mscs_req_info *mscs_req, + struct pe_session *pe_session) +{ + uint8_t *frame; + tDot11fmscs_request_action_frame mscs_req_frame; + uint32_t payload, bytes; + tpSirMacMgmtHdr peer_mac_hdr; + void *packet; + QDF_STATUS qdf_status; + tpSirMacMgmtHdr mac_hdr; + + qdf_mem_zero(&mscs_req_frame, sizeof(mscs_req_frame)); + + mscs_req_frame.Action.action = MCSC_REQ; + mscs_req_frame.DialogToken.token = mscs_req->dialog_token; + mscs_req_frame.Category.category = ACTION_CATEGORY_RVS; + populate_dot11f_mscs_dec_element(mscs_req, &mscs_req_frame); + bytes = dot11f_get_packed_mscs_request_action_frameSize(mac, + &mscs_req_frame, &payload); + if (DOT11F_FAILED(bytes)) { + pe_err("Failed to calculate the packed size for an MSCS Request (0x%08x)", + bytes); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fmscs_request_action_frame); + } else if (DOT11F_WARNED(bytes)) { + pe_warn("There were warnings while calculating the packed size for MSCS Request (0x%08x)", + bytes); + } + + bytes = payload + sizeof(struct qdf_mac_addr); + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for an mscs request", + bytes); + return; + } + /* Paranoia: */ + qdf_mem_zero(frame, bytes); + + lim_populate_mac_header(mac, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, + peer_mac.bytes, pe_session->self_mac_addr); + peer_mac_hdr = (tpSirMacMgmtHdr) frame; + + qdf_mem_copy(peer_mac.bytes, pe_session->bssId, QDF_MAC_ADDR_SIZE); + + lim_set_protected_bit(mac, pe_session, peer_mac.bytes, peer_mac_hdr); + + bytes = dot11f_pack_mscs_request_action_frame(mac, &mscs_req_frame, + frame + + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(bytes)) { + pe_err("Failed to pack an mscs Request " "(0x%08x)", bytes); + cds_packet_free((void *)packet); + return; /* allocated! */ + } else if (DOT11F_WARNED(bytes)) { + pe_warn("There were warnings while packing an mscs Request (0x%08x)", + bytes); + } + + mac_hdr = (tpSirMacMgmtHdr) frame; + + pe_debug("mscs req TX: vdev id: %d to "QDF_MAC_ADDR_FMT" seq num[%d], frame subtype:%d ", + mscs_req->vdev_id, QDF_MAC_ADDR_REF(peer_mac.bytes), + mac->mgmtSeqNum, mac_hdr->fc.subType); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + frame, + (uint16_t)(sizeof(tSirMacMgmtHdr) + payload)); + qdf_status = + wma_tx_frameWithTxComplete(mac, packet, + (uint16_t) (sizeof(tSirMacMgmtHdr) + payload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, lim_mscs_req_tx_complete_cnf, + HAL_USE_PEER_STA_REQUESTED_MASK, + pe_session->vdev_id, false, 0, RATEID_DEFAULT, 0, 0); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + mlme_set_is_mscs_req_sent(pe_session->vdev, true); + } else { + pe_err("Could not send an mscs Request (%X)", qdf_status); + } + + /* Pkt will be freed up by the callback */ +} /* End lim_send_mscs_req_action_frame */ +#endif + +/** + * lim_assoc_rsp_tx_complete() - Confirmation for assoc rsp OTA + * @context: pointer to global mac + * @buf: buffer which is nothing but entire assoc rsp frame + * @tx_complete : Sent status + * @params; tx completion params + * + * Return: This returns QDF_STATUS + */ +static QDF_STATUS lim_assoc_rsp_tx_complete( + void *context, + qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + tSirMacMgmtHdr *mac_hdr; + struct pe_session *session_entry; + uint8_t session_id; + tpLimMlmAssocInd lim_assoc_ind; + tpDphHashNode sta_ds; + uint16_t aid; + uint8_t *data; + struct assoc_ind *sme_assoc_ind; + struct scheduler_msg msg; + tpSirAssocReq assoc_req; + + if (!buf) { + pe_err("Assoc rsp frame buffer is NULL"); + goto null_buf; + } + + data = qdf_nbuf_data(buf); + + if (!data) { + pe_err("Assoc rsp frame is NULL"); + goto end; + } + + mac_hdr = (tSirMacMgmtHdr *)data; + + session_entry = pe_find_session_by_bssid( + mac_ctx, mac_hdr->sa, + &session_id); + if (!session_entry) { + pe_err("session entry is NULL"); + goto end; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, + (uint8_t *)mac_hdr->da, &aid, + &session_entry->dph.dphHashTable); + if (!sta_ds) { + pe_err("sta_ds is NULL"); + goto end; + } + + /* Get a copy of the already parsed Assoc Request */ + assoc_req = + (tpSirAssocReq)session_entry->parsedAssocReq[sta_ds->assocId]; + + if (!assoc_req) { + pe_err("assoc req for assoc_id:%d is NULL", sta_ds->assocId); + goto end; + } + + if (tx_complete != WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) { + lim_send_disassoc_mgmt_frame(mac_ctx, + REASON_DISASSOC_DUE_TO_INACTIVITY, + sta_ds->staAddr, + session_entry, false); + lim_trigger_sta_deletion(mac_ctx, sta_ds, session_entry); + goto free_buffers; + } + + if (lim_is_mlo_conn(session_entry, sta_ds) && + QDF_IS_STATUS_ERROR(lim_mlo_assoc_ind_upper_layer( + mac_ctx, session_entry, + &assoc_req->mlo_info))) { + pe_err("partner link indicate upper layer error"); + goto free_assoc_req; + } + lim_assoc_ind = qdf_mem_malloc(sizeof(tLimMlmAssocInd)); + if (!lim_assoc_ind) + goto free_assoc_req; + + if (!lim_fill_lim_assoc_ind_params(lim_assoc_ind, mac_ctx, + sta_ds, session_entry)) { + pe_err("lim assoc ind fill error"); + goto lim_assoc_ind; + } + + sme_assoc_ind = qdf_mem_malloc(sizeof(struct assoc_ind)); + if (!sme_assoc_ind) + goto lim_assoc_ind; + + sme_assoc_ind->messageType = eWNI_SME_ASSOC_IND_UPPER_LAYER; + lim_fill_sme_assoc_ind_params( + mac_ctx, lim_assoc_ind, + sme_assoc_ind, + session_entry, true); + + qdf_mem_zero(&msg, sizeof(struct scheduler_msg)); + msg.type = eWNI_SME_ASSOC_IND_UPPER_LAYER; + msg.bodyptr = sme_assoc_ind; + msg.bodyval = 0; + sme_assoc_ind->reassocReq = sta_ds->mlmStaContext.subType; + sme_assoc_ind->timingMeasCap = sta_ds->timingMeasCap; + MTRACE(mac_trace_msg_tx(mac_ctx, session_entry->peSessionId, msg.type)); + lim_sys_process_mmh_msg_api(mac_ctx, &msg); + + qdf_mem_free(lim_assoc_ind); + +free_buffers: + lim_free_assoc_req_frm_buf(assoc_req); + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; + +lim_assoc_ind: + qdf_mem_free(lim_assoc_ind); +free_assoc_req: + lim_free_assoc_req_frm_buf(assoc_req); + qdf_mem_free(session_entry->parsedAssocReq[sta_ds->assocId]); + session_entry->parsedAssocReq[sta_ds->assocId] = NULL; +end: + qdf_nbuf_free(buf); +null_buf: + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_FEATURE_11BE +QDF_STATUS lim_strip_eht_cap_ie(struct mac_context *mac_ctx, + uint8_t *frame_ies, + uint16_t *ie_buf_size, + uint8_t *eht_cap_ie) +{ + return lim_strip_ie(mac_ctx, frame_ies, ie_buf_size, + WLAN_ELEMID_EXTN_ELEM, ONE_BYTE, + EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE, + eht_cap_ie, WLAN_MAX_IE_LEN); +} + +QDF_STATUS lim_strip_eht_op_ie(struct mac_context *mac_ctx, + uint8_t *frame_ies, + uint16_t *ie_buf_size, + uint8_t *eht_op_ie) +{ + return lim_strip_ie(mac_ctx, frame_ies, ie_buf_size, + WLAN_ELEMID_EXTN_ELEM, ONE_BYTE, + EHT_OP_OUI_TYPE, EHT_OP_OUI_SIZE, + eht_op_ie, WLAN_MAX_IE_LEN); +} +#endif + +void +lim_send_assoc_rsp_mgmt_frame(struct mac_context *mac_ctx, + uint16_t status_code, uint16_t aid, + tSirMacAddr peer_addr, + uint8_t subtype, tpDphHashNode sta, + struct pe_session *pe_session, + bool tx_complete) +{ + static tDot11fAssocResponse frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + QDF_STATUS sir_status; + uint8_t lle_mode = 0, addts; + tHalBitVal qos_mode, wme_mode; + uint32_t payload, bytes = 0, status; + void *packet; + QDF_STATUS qdf_status; + tUpdateBeaconParams beacon_params; + uint8_t tx_flag = 0; + uint32_t addn_ie_len = 0; + uint8_t *add_ie; + tpSirAssocReq assoc_req = NULL; + uint8_t sme_session = 0; + bool is_vht = false; + uint16_t stripoff_len = 0; + tDot11fIEExtCap extracted_ext_cap; + bool extracted_flag = false; + uint8_t retry_int; + uint16_t max_retries; + uint8_t *eht_op_ie = NULL, eht_op_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + bool is_band_2g; + uint16_t mlo_ie_len = 0; + struct element_info ie; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return; + } + if (sta && lim_is_mlo_conn(pe_session, sta) && + !lim_is_mlo_recv_assoc(sta)) { + pe_err("Do not send assoc rsp in mlo partner peer " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta->staAddr)); + return; + } + + sme_session = pe_session->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + limGetQosMode(pe_session, &qos_mode); + limGetWmeMode(pe_session, &wme_mode); + + /* + * An Add TS IE is added only if the AP supports it and + * the requesting STA sent a traffic spec. + */ + addts = (qos_mode && sta && sta->qos.addtsPresent) ? 1 : 0; + + frm.Status.status = status_code; + + frm.AID.associd = aid | LIM_AID_MASK; + + if (!sta) { + populate_dot11f_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.SuppRates, pe_session); + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &frm.ExtSuppRates, pe_session); + } else { + populate_dot11f_assoc_rsp_rates(mac_ctx, &frm.SuppRates, + &frm.ExtSuppRates, + sta->supportedRates.llbRates, + sta->supportedRates.llaRates); + } + + if (LIM_IS_AP_ROLE(pe_session) && sta && + QDF_STATUS_SUCCESS == status_code) { + assoc_req = (tpSirAssocReq) + pe_session->parsedAssocReq[sta->assocId]; + /* + * populate P2P IE in AssocRsp when assoc_req from the peer + * includes P2P IE + */ + if (assoc_req && assoc_req->addIEPresent) + populate_dot11_assoc_res_p2p_ie(mac_ctx, + &frm.P2PAssocRes, + assoc_req); + } + + if (sta) { + if (eHAL_SET == qos_mode) { + if (sta->lleEnabled) { + lle_mode = 1; + populate_dot11f_edca_param_set(mac_ctx, + &frm.EDCAParamSet, pe_session); + } + } + + if ((!lle_mode) && (eHAL_SET == wme_mode) && sta->wmeEnabled) { + populate_dot11f_wmm_params(mac_ctx, &frm.WMMParams, + pe_session); + + if (sta->wsmEnabled) + populate_dot11f_wmm_caps(&frm.WMMCaps); + } + + if (sta->mlmStaContext.htCapability && + pe_session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, pe_session, + &frm.HTCaps); + /* + * Check the STA capability and + * update the HTCaps accordingly + */ + frm.HTCaps.supportedChannelWidthSet = ( + sta->htSupportedChannelWidthSet < + pe_session->htSupportedChannelWidthSet) ? + sta->htSupportedChannelWidthSet : + pe_session->htSupportedChannelWidthSet; + if (!frm.HTCaps.supportedChannelWidthSet) + frm.HTCaps.shortGI40MHz = 0; + + populate_dot11f_ht_info(mac_ctx, &frm.HTInfo, + pe_session); + } + + if (sta->mlmStaContext.vhtCapability && + pe_session->vhtCapability) { + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm.VHTOperation); + is_vht = true; + } else if (sta->mlmStaContext.force_1x1 && + frm.HTCaps.present) { + /* + * WAR: In P2P GO mode, if the P2P client device + * is only HT capable and not VHT capable, but the P2P + * GO device is VHT capable and advertises 2x2 NSS with + * HT capability client device, which results in IOT + * issues. + * When GO is operating in DBS mode, GO beacons + * advertise 2x2 capability but include OMN IE to + * indicate current operating mode of 1x1. But here + * peer device is only HT capable and will not + * understand OMN IE. + */ + frm.HTInfo.basicMCSSet[1] = 0; + frm.HTCaps.supportedMCSSet[1] = 0; + } + + if (pe_session->vhtCapability && + pe_session->vendor_vht_sap && + (assoc_req) && + assoc_req->vendor_vht_ie.VHTCaps.present) { + frm.vendor_vht_ie.present = 1; + frm.vendor_vht_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + frm.vendor_vht_ie.VHTCaps.present = 1; + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm.vendor_vht_ie.VHTCaps); + populate_dot11f_vht_operation(mac_ctx, pe_session, + &frm.vendor_vht_ie.VHTOperation); + is_vht = true; + } + populate_dot11f_ext_cap(mac_ctx, is_vht, &frm.ExtCap, + pe_session); + + populate_dot11f_qcn_ie(mac_ctx, pe_session, &frm.qcn_ie, + QCN_IE_ATTR_ID_ALL); + + if (lim_is_sta_he_capable(sta) && + lim_is_session_he_capable(pe_session)) { + populate_dot11f_he_caps(mac_ctx, pe_session, + &frm.he_cap); + populate_dot11f_sr_info(mac_ctx, pe_session, + &frm.spatial_reuse); + populate_dot11f_he_operation(mac_ctx, pe_session, + &frm.he_op); + populate_dot11f_he_6ghz_cap(mac_ctx, pe_session, + &frm.he_6ghz_band_cap); + } + + if (lim_is_sta_eht_capable(sta) && + lim_is_session_eht_capable(pe_session)) { + populate_dot11f_eht_caps(mac_ctx, pe_session, + &frm.eht_cap); + populate_dot11f_eht_operation(mac_ctx, pe_session, + &frm.eht_op); + } + + if (status_code == STATUS_ASSOC_REJECTED_TEMPORARILY) { + max_retries = + mac_ctx->mlme_cfg->gen.pmf_sa_query_max_retries; + retry_int = + mac_ctx->mlme_cfg->gen.pmf_sa_query_retry_interval; + populate_dot11f_timeout_interval(mac_ctx, + &frm.TimeoutInterval, + SIR_MAC_TI_TYPE_ASSOC_COMEBACK, + (max_retries - + sta->pmfSaQueryRetryCount) + * retry_int); + } + + if (LIM_IS_AP_ROLE(pe_session) && sta->non_ecsa_capable) + pe_session->lim_non_ecsa_cap_num++; + } + + qdf_mem_zero((uint8_t *) &beacon_params, sizeof(beacon_params)); + + if (LIM_IS_AP_ROLE(pe_session) && + (pe_session->gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE)) + lim_decide_ap_protection(mac_ctx, peer_addr, &beacon_params, + pe_session); + + lim_update_short_preamble(mac_ctx, peer_addr, &beacon_params, + pe_session); + lim_update_short_slot_time(mac_ctx, peer_addr, &beacon_params, + pe_session); + + /* + * Populate Do11capabilities after updating session with + * Assos req details + */ + populate_dot11f_capabilities(mac_ctx, &frm.Capabilities, pe_session); + + beacon_params.bss_idx = pe_session->vdev_id; + + /* Send message to HAL about beacon parameter change. */ + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beacon_params.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session); + lim_send_beacon_params(mac_ctx, &beacon_params, pe_session); + } + + lim_obss_send_detection_cfg(mac_ctx, pe_session, false); + + add_ie = qdf_mem_malloc(WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN); + if (!add_ie) { + pe_err("memory alloc failed for add_ie"); + return; + } + + if (assoc_req) { + addn_ie_len = pe_session->add_ie_params.assocRespDataLen; + + /* Nonzero length indicates Assoc rsp IE available */ + if (addn_ie_len > 0 && + addn_ie_len <= WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN && + (bytes + addn_ie_len) <= SIR_MAX_PACKET_SIZE) { + qdf_mem_copy(add_ie, + pe_session->add_ie_params.assocRespData_buff, + pe_session->add_ie_params.assocRespDataLen); + + qdf_mem_zero((uint8_t *) &extracted_ext_cap, + sizeof(extracted_ext_cap)); + + stripoff_len = addn_ie_len; + sir_status = + lim_strip_extcap_update_struct + (mac_ctx, &add_ie[0], &stripoff_len, + &extracted_ext_cap); + if (QDF_STATUS_SUCCESS != sir_status) { + pe_debug("strip off extcap IE failed"); + } else { + addn_ie_len = stripoff_len; + extracted_flag = true; + } + bytes = bytes + addn_ie_len; + } + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extracted_flag) + lim_merge_extcap_struct(&(frm.ExtCap), &extracted_ext_cap, + true); + populate_dot11f_bcn_prot_extcaps(mac_ctx, pe_session, &(frm.ExtCap)); + if (sta && lim_is_sta_eht_capable(sta) && + lim_is_mlo_conn(pe_session, sta) && + lim_is_session_eht_capable(pe_session) && + wlan_vdev_mlme_is_mlo_ap(pe_session->vdev) && + (status_code != STATUS_ASSOC_REJECTED_TEMPORARILY)) { + pe_debug("Populate mlo IEs"); + mlo_ie_len = lim_send_assoc_rsp_mgmt_frame_mlo(mac_ctx, + pe_session, + sta, &frm); + } + + if (sta && lim_is_sta_eht_capable(sta) && + lim_is_session_eht_capable(pe_session)) { + eht_op_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + MIN_IE_LEN); + if (!eht_op_ie) { + pe_err("malloc failed for eht_op_ie"); + goto error; + } + + lim_ieee80211_pack_ehtop(eht_op_ie, frm.eht_op, + frm.VHTOperation, + frm.he_op, + frm.HTInfo); + eht_op_ie_len = eht_op_ie[TAG_LEN_POS] + MIN_IE_LEN; + + /* Set eht op to false as frame contents are present in + * eht_op_ie buffer + */ + frm.eht_op.present = false; + + eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + MIN_IE_LEN); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + goto error; + } + + is_band_2g = + WLAN_REG_IS_24GHZ_CH_FREQ(pe_session->curr_op_freq); + lim_ieee80211_pack_ehtcap(eht_cap_ie, frm.eht_cap, frm.he_cap, + is_band_2g); + + eht_cap_ie_len = eht_cap_ie[TAG_LEN_POS] + MIN_IE_LEN; + + /* Set eht cap to false as frame contents are present in + * eht_cap_ie buffer + */ + frm.eht_cap.present = false; + } + + /* Allocate a buffer for this frame: */ + status = dot11f_get_packed_assoc_response_size(mac_ctx, &frm, &payload); + if (DOT11F_FAILED(status)) { + pe_err("get Association Response size failure (0x%08x)", + status); + goto error; + } else if (DOT11F_WARNED(status)) { + pe_warn("get Association Response size warning (0x%08x)", + status); + } + + bytes += sizeof(tSirMacMgmtHdr) + payload + mlo_ie_len + eht_op_ie_len + + eht_cap_ie_len; + + if (sta) { + bytes += sta->mlmStaContext.owe_ie_len; + bytes += sta->mlmStaContext.ft_ie_len; + } + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("cds_packet_alloc failed"); + goto error; + } + /* Paranoia: */ + qdf_mem_zero(frame, bytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + (LIM_ASSOC == subtype) ? + SIR_MAC_MGMT_ASSOC_RSP : SIR_MAC_MGMT_REASSOC_RSP, + peer_addr, + pe_session->self_mac_addr); + mac_hdr = (tpSirMacMgmtHdr) frame; + + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + + status = dot11f_pack_assoc_response(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), + payload, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Association Response pack failure(0x%08x)", + status); + cds_packet_free((void *)packet); + goto error; + } else if (DOT11F_WARNED(status)) { + pe_warn("Association Response pack warning (0x%08x)", + status); + } + + if (eht_op_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + eht_op_ie, eht_op_ie_len); + payload += eht_op_ie_len; + } + + if (eht_cap_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + eht_cap_ie, eht_cap_ie_len); + payload += eht_cap_ie_len; + } + + if (addn_ie_len && addn_ie_len <= WNI_CFG_ASSOC_RSP_ADDNIE_DATA_LEN) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + &add_ie[0], addn_ie_len); + payload += addn_ie_len; + } + + if (sta && sta->mlmStaContext.owe_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + sta->mlmStaContext.owe_ie, + sta->mlmStaContext.owe_ie_len); + payload += sta->mlmStaContext.owe_ie_len; + } + + if (sta && sta->mlmStaContext.ft_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + sta->mlmStaContext.ft_ie, + sta->mlmStaContext.ft_ie_len); + payload += sta->mlmStaContext.ft_ie_len; + } + + if (sta && mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + frame + sizeof(tSirMacMgmtHdr) + payload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + payload += mlo_ie_len; + } + + pe_nofl_debug("Assoc rsp TX: vdev %d subtype %d to "QDF_MAC_ADDR_FMT" seq num %d status %d aid %d addn_ie_len %d ht %d vht %d vendor vht %d he %d eht %d", + pe_session->vdev_id, subtype, + QDF_MAC_ADDR_REF(mac_hdr->da), + mac_ctx->mgmtSeqNum, status_code, aid, addn_ie_len, + frm.HTCaps.present, frm.VHTCaps.present, + frm.vendor_vht_ie.present, frm.he_cap.present, + frm.eht_cap.present); + + lim_cp_stats_cstats_log_assoc_resp_evt(pe_session, CSTATS_DIR_TX, + status_code, aid, mac_hdr->bssId, + mac_hdr->da, frm.HTCaps.present, + frm.VHTCaps.present, + frm.he_cap.present, + frm.eht_cap.present, false); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + ie.ptr = frame + sizeof(tSirMacMgmtHdr) + WLAN_ASSOC_RSP_IES_OFFSET; + ie.len = payload - WLAN_ASSOC_RSP_IES_OFFSET; + + mlme_set_peer_assoc_rsp_ie(mac_ctx->psoc, peer_addr, &ie); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + lim_diag_mgmt_tx_event_report(mac_ctx, mac_hdr, + pe_session, QDF_STATUS_SUCCESS, status_code); + /* Queue Association Response frame in high priority WQ */ + if (tx_complete) + qdf_status = wma_tx_frameWithTxComplete( + mac_ctx, packet, (uint16_t)bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, + lim_assoc_rsp_tx_complete, tx_flag, + sme_session, false, 0, RATEID_DEFAULT, 0, 0); + else + qdf_status = wma_tx_frame( + mac_ctx, packet, (uint16_t)bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, tx_flag, + sme_session, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + + /* Pkt will be freed up by the callback */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + pe_err("Could not Send Re/AssocRsp, retCode=%X", + qdf_status); + + /* + * update the ANI peer station count. + * FIXME_PROTECTION : take care of different type of station + * counter inside this function. + */ + lim_util_count_sta_add(mac_ctx, sta, pe_session); + +error: + qdf_mem_free(eht_cap_ie); + qdf_mem_free(eht_op_ie); + qdf_mem_free(add_ie); +} + +void +lim_send_delts_req_action_frame(struct mac_context *mac, + tSirMacAddr peer, + uint8_t wmmTspecPresent, + struct mac_ts_info *pTsinfo, + struct mac_tspec_ie *pTspecIe, + struct pe_session *pe_session) +{ + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + tDot11fDelTS DelTS; + tDot11fWMMDelTS WMMDelTS; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (!pe_session) + return; + + smeSessionId = pe_session->smeSessionId; + + if (!wmmTspecPresent) { + qdf_mem_zero((uint8_t *) &DelTS, sizeof(DelTS)); + + DelTS.Category.category = ACTION_CATEGORY_QOS; + DelTS.Action.action = QOS_DEL_TS_REQ; + populate_dot11f_ts_info(pTsinfo, &DelTS.TSInfo); + + nStatus = dot11f_get_packed_del_ts_size(mac, &DelTS, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Del TS (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDelTS); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Del TS (0x%08x)", + nStatus); + } + } else { + qdf_mem_zero((uint8_t *) &WMMDelTS, sizeof(WMMDelTS)); + + WMMDelTS.Category.category = ACTION_CATEGORY_WMM; + WMMDelTS.Action.action = QOS_DEL_TS_REQ; + WMMDelTS.DialogToken.token = 0; + WMMDelTS.StatusCode.statusCode = 0; + populate_dot11f_wmmtspec(pTspecIe, &WMMDelTS.WMMTSPEC); + nStatus = + dot11f_get_packed_wmm_del_ts_size(mac, &WMMDelTS, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a WMM Del TS (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDelTS); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a WMM Del TS (0x%08x)", + nStatus); + } + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for an Add TS Response", + nBytes); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, pe_session->self_mac_addr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + /* That done, pack the struct: */ + if (!wmmTspecPresent) { + nStatus = dot11f_pack_del_ts(mac, &DelTS, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Del TS frame (0x%08x)", + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a Del TS frame (0x%08x)", + nStatus); + } + } else { + nStatus = dot11f_pack_wmm_del_ts(mac, &WMMDelTS, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a WMM Del TS frame (0x%08x)", + nStatus); + cds_packet_free((void *)pPacket); + return; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a WMM Del TS frame (0x%08x)", + nStatus); + } + } + + pe_debug("Sending DELTS REQ (size %d) to "QDF_MAC_ADDR_FMT, nBytes, + QDF_MAC_ADDR_REF(pMacHdr->da)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + /* Pkt will be freed up by the callback */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + pe_err("Failed to send Del TS (%X)!", qdf_status); + +} /* End lim_send_delts_req_action_frame. */ + +#define SAE_AUTH_SEQ_NUM_OFFSET 2 +#define SAE_AUTH_STATUS_CODE_OFFSET 4 +#define SAE_AUTH_MESSAGE_TYPE_OFFSET 6 +#define SAE_FRAME_LENGTH \ + (sizeof(struct wlan_frame_hdr) + SAE_AUTH_MESSAGE_TYPE_OFFSET) + +/** + * wlan_send_tx_complete_event() - Fill mgmt params + * @mac: Pointer to mac context + * @buf: skb buffer + * @params: Pointer to wmi_mgmt_params + * @tx_complete: Sent status + * @tag: wlan main tag + * + * Function is used to send connectivity log event for mgmt ack status + * + * Return None + */ + +static void wlan_send_tx_complete_event(struct mac_context *mac, qdf_nbuf_t buf, + struct wmi_mgmt_params *params, + uint8_t tx_complete, + enum wlan_main_tag tag) +{ + struct pe_session *pe_session = NULL; + struct wlan_frame_hdr *mac_hdr; + enum qdf_dp_tx_rx_status qdf_tx_complete; + uint8_t *frm_body; + uint16_t reason_code = 0; + + pe_session = pe_find_session_by_vdev_id(mac, params->vdev_id); + if (pe_session && pe_session->opmode == QDF_STA_MODE) { + if (qdf_nbuf_len(buf) < sizeof(struct wlan_frame_hdr) + 2) + return; + + mac_hdr = (struct wlan_frame_hdr *)qdf_nbuf_data(buf); + frm_body = (uint8_t *)mac_hdr + sizeof(struct wlan_frame_hdr); + + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) + qdf_tx_complete = QDF_TX_RX_STATUS_OK; + else if (tx_complete == WMI_MGMT_TX_COMP_TYPE_DISCARD) + qdf_tx_complete = QDF_TX_RX_STATUS_FW_DISCARD; + else + qdf_tx_complete = QDF_TX_RX_STATUS_NO_ACK; + + if (tag == WLAN_AUTH_REQ) { + uint16_t algo = 0, type = 0, seq = 0, status = 0; + + if (qdf_nbuf_len(buf) < SAE_FRAME_LENGTH) + return; + + algo = *(uint16_t *)frm_body; + seq = *(uint16_t *)(frm_body + SAE_AUTH_SEQ_NUM_OFFSET); + status = + *(uint16_t *)(frm_body + SAE_AUTH_STATUS_CODE_OFFSET); + + if (algo == eSIR_AUTH_TYPE_SAE) + type = seq; + + wlan_connectivity_mgmt_event( + mac->psoc, + mac_hdr, params->vdev_id, status, + qdf_tx_complete, mac->lim.bss_rssi, + algo, type, seq, 0, WLAN_AUTH_REQ); + lim_cp_stats_cstats_log_auth_evt(pe_session, + CSTATS_DIR_TX, algo, + seq, status); + return; + } + + if (tag == WLAN_DEAUTH_TX || tag == WLAN_DISASSOC_TX) + reason_code = pe_session->deauth_disassoc_rc; + + wlan_connectivity_mgmt_event( + mac->psoc, + mac_hdr, params->vdev_id, reason_code, + qdf_tx_complete, mac->lim.bss_rssi, + 0, 0, 0, 0, tag); + } +} + +/** + * lim_assoc_tx_complete_cnf()- Confirmation for assoc sent over the air + * @context: pointer to global mac + * @buf: buffer + * @tx_complete: Sent status + * @params: tx completion params + * + * Return: This returns QDF_STATUS + */ + +static QDF_STATUS lim_assoc_tx_complete_cnf(void *context, + qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + uint16_t assoc_ack_status; + uint16_t reason_code; + struct mac_context *mac_ctx = (struct mac_context *)context; + + pe_nofl_rl_info("Assoc req TX: %s (%d)", + (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) ? + "success" : "fail", tx_complete); + + if (params) + wlan_send_tx_complete_event(context, buf, params, tx_complete, + WLAN_ASSOC_REQ); + + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) { + assoc_ack_status = ACKED; + reason_code = QDF_STATUS_SUCCESS; + mac_ctx->assoc_ack_status = LIM_ACK_RCD_SUCCESS; + } else if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK) { + assoc_ack_status = NOT_ACKED; + reason_code = QDF_STATUS_E_FAILURE; + mac_ctx->assoc_ack_status = LIM_ACK_RCD_FAILURE; + } else { + assoc_ack_status = SENT_FAIL; + reason_code = QDF_STATUS_E_FAILURE; + mac_ctx->assoc_ack_status = LIM_TX_FAILED; + } + + if (buf) + qdf_nbuf_free(buf); + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_ACK_EVENT, + NULL, assoc_ack_status, reason_code); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_ADAPTIVE_11R +/** + * lim_fill_adaptive_11r_ie() - Populate the Vendor specific adaptive 11r + * IE to association request frame + * @pe_session: pointer to PE session + * @ie_buf: buffer to which Adaptive 11r IE will be copied + * @ie_len: length of the Adaptive 11r Vendor specific IE + * + * Return QDF_STATUS + */ +static QDF_STATUS lim_fill_adaptive_11r_ie(struct pe_session *pe_session, + uint8_t **ie_buf, uint8_t *ie_len) +{ + uint8_t *buf = NULL, *adaptive_11r_ie = NULL; + + if (!pe_session->is_adaptive_11r_connection) + return QDF_STATUS_SUCCESS; + + /* + * Vendor specific Adaptive 11r IE to be advertised in Assoc + * req: + * Type 0xDD + * Length 0x0B + * OUI 0x00 0x00 0x0F + * Type 0x22 + * subtype 0x00 + * Version 0x01 + * Length 0x04 + * Data 0x00 00 00 01(0th bit is 1 means adaptive 11r is + * supported) + */ + adaptive_11r_ie = qdf_mem_malloc(ADAPTIVE_11R_STA_IE_LEN + 2); + if (!adaptive_11r_ie) + return QDF_STATUS_E_FAILURE; + + /* Fill the Vendor IE Type (0xDD) */ + buf = adaptive_11r_ie; + *buf = WLAN_ELEMID_VENDOR; + buf++; + + /* Fill the Vendor IE length (0x0B) */ + *buf = ADAPTIVE_11R_STA_IE_LEN; + buf++; + + /* + * Fill the Adaptive 11r Vendor specific OUI(0x00 0x00 0x0F 0x22) + */ + qdf_mem_copy(buf, ADAPTIVE_11R_STA_OUI, ADAPTIVE_11R_OUI_LEN); + buf += ADAPTIVE_11R_OUI_LEN; + + /* Fill Adaptive 11r Vendor specific Subtype (0x00) */ + *buf = ADAPTIVE_11R_OUI_SUBTYPE; + buf++; + + /* Fill Adaptive 11r Version (0x01) */ + *buf = ADAPTIVE_11R_OUI_VERSION; + buf++; + + /* Fill Adaptive 11r IE Data length (0x04) */ + *buf = ADAPTIVE_11R_DATA_LEN; + buf++; + + /* Fill Adaptive 11r IE Data (0x00 0x00 0x00 0x01) */ + qdf_mem_copy(buf, ADAPTIVE_11R_OUI_DATA, ADAPTIVE_11R_DATA_LEN); + + *ie_len = ADAPTIVE_11R_STA_IE_LEN + 2; + *ie_buf = adaptive_11r_ie; + + return QDF_STATUS_SUCCESS; +} + +#else +static inline +QDF_STATUS lim_fill_adaptive_11r_ie(struct pe_session *pe_session, + uint8_t **ie_buf, uint8_t *ie_len) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * lim_send_assoc_req_mgmt_frame() - Send association request + * @mac_ctx: Handle to MAC context + * @mlm_assoc_req: Association request information + * @pe_session: PE session information + * + * Builds and transmits association request frame to AP. + * + * Return: Void + */ +void +lim_send_assoc_req_mgmt_frame(struct mac_context *mac_ctx, + tLimMlmAssocReq *mlm_assoc_req, + struct pe_session *pe_session) +{ + int ret; + tDot11fAssocRequest *frm; + uint16_t caps; + uint8_t *frame, *rsnx_ie = NULL; + QDF_STATUS sir_status; + tLimMlmAssocCnf assoc_cnf; + uint32_t bytes = 0, payload, status; + uint8_t qos_enabled, wme_enabled, wsm_enabled; + void *packet; + QDF_STATUS qdf_status; + uint16_t add_ie_len, current_len = 0, vendor_ie_len = 0; + uint8_t *add_ie = NULL, *mscs_ext_ie = NULL; + const uint8_t *wps_ie = NULL; + uint8_t power_caps = false; + uint8_t tx_flag = 0; + uint8_t vdev_id = 0; + bool vht_enabled = false; + tDot11fIEExtCap extr_ext_cap; + bool extr_ext_flag = true, is_open_auth = false; + tpSirMacMgmtHdr mac_hdr; + uint32_t ie_offset = 0; + uint8_t *p_ext_cap = NULL; + tDot11fIEExtCap bcn_ext_cap; + uint8_t *bcn_ie = NULL; + uint32_t bcn_ie_len = 0; + uint32_t aes_block_size_len = 0; + enum rateid min_rid = RATEID_DEFAULT; + uint8_t *mbo_ie = NULL, *adaptive_11r_ie = NULL, *vendor_ies = NULL; + uint8_t mbo_ie_len = 0, adaptive_11r_ie_len = 0, rsnx_ie_len = 0; + uint8_t mscs_ext_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + bool bss_mfp_capable, frag_ie_present = false; + int8_t peer_rssi = 0; + bool is_band_2g, is_ml_ap; + uint16_t mlo_ie_len = 0, fils_hlp_ie_len = 0; + uint8_t *fils_hlp_ie = NULL; + struct cm_roam_values_copy mdie_cfg = {0}; + + if (!pe_session) { + pe_err("pe_session is NULL"); + qdf_mem_free(mlm_assoc_req); + return; + } + + vdev_id = pe_session->vdev_id; + + /* check this early to avoid unnecessary operation */ + if (!pe_session->lim_join_req) { + pe_err("pe_session->lim_join_req is NULL"); + qdf_mem_free(mlm_assoc_req); + return; + } + add_ie_len = pe_session->lim_join_req->addIEAssoc.length; + if (add_ie_len) { + add_ie = qdf_mem_malloc(add_ie_len); + if (!add_ie) { + qdf_mem_free(mlm_assoc_req); + return; + } + /* + * copy the additional ie to local, as this func modify + * the IE, these IE will be required in assoc/re-assoc + * retry. So do not modify the original IE. + */ + qdf_mem_copy(add_ie, pe_session->lim_join_req->addIEAssoc.addIEdata, + add_ie_len); + + } + + frm = qdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (!frm) { + qdf_mem_free(mlm_assoc_req); + qdf_mem_free(add_ie); + return; + } + qdf_mem_zero((uint8_t *) frm, sizeof(tDot11fAssocRequest)); + + if (add_ie_len && pe_session->is_ext_caps_present) { + qdf_mem_zero((uint8_t *) &extr_ext_cap, + sizeof(tDot11fIEExtCap)); + sir_status = lim_strip_extcap_update_struct(mac_ctx, + add_ie, &add_ie_len, &extr_ext_cap); + if (QDF_STATUS_SUCCESS != sir_status) { + extr_ext_flag = false; + pe_debug("Unable to Stripoff ExtCap IE from Assoc Req"); + } else { + struct s_ext_cap *p_ext_cap = (struct s_ext_cap *) + extr_ext_cap.bytes; + + if (p_ext_cap->interworking_service) + p_ext_cap->qos_map = 1; + extr_ext_cap.num_bytes = + lim_compute_ext_cap_ie_length(&extr_ext_cap); + extr_ext_flag = (extr_ext_cap.num_bytes > 0); + } + } else { + extr_ext_flag = false; + } + + caps = mlm_assoc_req->capabilityInfo; +#if defined(FEATURE_WLAN_WAPI) + /* + * According to WAPI standard: + * 7.3.1.4 Capability Information field + * In WAPI, non-AP STAs within an ESS set the Privacy subfield to 0 + * in transmitted Association or Reassociation management frames. + * APs ignore the Privacy subfield within received Association and + * Reassociation management frames. + */ + if (pe_session->encryptType == eSIR_ED_WPI) + ((tSirMacCapabilityInfo *) &caps)->privacy = 0; +#endif + swap_bit_field16(caps, (uint16_t *) &frm->Capabilities); + + frm->ListenInterval.interval = mlm_assoc_req->listenInterval; + + populate_dot11f_ssid2(pe_session, &frm->SSID); + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &frm->SuppRates, pe_session); + + qos_enabled = (pe_session->limQosEnabled) && + SIR_MAC_GET_QOS(pe_session->limCurrentBssCaps); + + wme_enabled = (pe_session->limWmeEnabled) && + LIM_BSS_CAPS_GET(WME, pe_session->limCurrentBssQosCaps); + + /* We prefer .11e asociations: */ + if (qos_enabled) + wme_enabled = false; + + wsm_enabled = (pe_session->limWsmEnabled) && wme_enabled && + LIM_BSS_CAPS_GET(WSM, pe_session->limCurrentBssQosCaps); + + if (pe_session->lim11hEnable && + pe_session->spectrumMgtEnabled == true) { + power_caps = true; + + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_ASSOC, pe_session); + populate_dot11f_supp_channels(mac_ctx, &frm->SuppChannels, + LIM_ASSOC, pe_session); + + } + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) { + if (power_caps == false) { + power_caps = true; + populate_dot11f_power_caps(mac_ctx, &frm->PowerCaps, + LIM_ASSOC, pe_session); + } + } + if (qos_enabled) + populate_dot11f_qos_caps_station(mac_ctx, pe_session, + &frm->QOSCapsStation); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, &frm->ExtSuppRates, + pe_session); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + SIR_MAC_GET_RRM(pe_session->limCurrentBssCaps)) + populate_dot11f_rrm_ie(mac_ctx, &frm->RRMEnabledCap, + pe_session); + + /* + * The join request *should* contain zero or one of the WPA and RSN + * IEs. The payload send along with the request is a + * 'struct join_req'; the IE portion is held inside a 'tSirRSNie': + * typedef struct sSirRSNie + * { + * uint16_t length; + * uint8_t rsnIEdata[WLAN_MAX_IE_LEN+2]; + * } tSirRSNie, *tpSirRSNie; + * So, we should be able to make the following two calls harmlessly, + * since they do nothing if they don't find the given IE in the + * bytestream with which they're provided. + * The net effect of this will be to faithfully transmit whatever + * security IE is in the join request. + * However, if we're associating for the purpose of WPS + * enrollment, and we've been configured to indicate that by + * eliding the WPA or RSN IE, we just skip this: + */ + if (add_ie_len && add_ie) + wps_ie = limGetWscIEPtr(mac_ctx, add_ie, add_ie_len); + + if (!wps_ie) { + populate_dot11f_rsn_opaque(mac_ctx, + &pe_session->lim_join_req->rsnIE, + &frm->RSNOpaque); + populate_dot11f_wpa_opaque(mac_ctx, + &pe_session->lim_join_req->rsnIE, + &frm->WPAOpaque); +#if defined(FEATURE_WLAN_WAPI) + populate_dot11f_wapi_opaque(mac_ctx, + &(pe_session->lim_join_req->rsnIE), + &frm->WAPIOpaque); +#endif /* defined(FEATURE_WLAN_WAPI) */ + } + /* include WME EDCA IE as well */ + if (wme_enabled) { + populate_dot11f_wmm_info_station_per_session(mac_ctx, + pe_session, &frm->WMMInfoStation); + + if (wsm_enabled) + populate_dot11f_wmm_caps(&frm->WMMCaps); + } + + /* + * Populate HT IEs, when operating in 11n and + * when AP is also operating in 11n mode + */ + if (pe_session->htCapability && + mac_ctx->lim.htCapabilityPresentInBeacon) + populate_dot11f_ht_caps(mac_ctx, pe_session, &frm->HTCaps); + else if (pe_session->he_with_wep_tkip) + populate_dot11f_ht_caps(mac_ctx, NULL, &frm->HTCaps); + + if (pe_session->vhtCapability && + pe_session->vhtCapabilityPresentInBeacon) { + populate_dot11f_vht_caps(mac_ctx, pe_session, &frm->VHTCaps); + vht_enabled = true; + if (pe_session->gLimOperatingMode.present && + pe_session->ap_ch_width == CH_WIDTH_20MHZ && + frm->VHTCaps.present && + !IS_DOT11_MODE_HE(pe_session->dot11mode)) { + populate_dot11f_operating_mode(mac_ctx, + &frm->OperatingMode, pe_session); + } + } else if (pe_session->he_with_wep_tkip) { + populate_dot11f_vht_caps(mac_ctx, NULL, &frm->VHTCaps); + } + + if (!vht_enabled && pe_session->is_vendor_specific_vhtcaps) { + frm->vendor_vht_ie.present = 1; + frm->vendor_vht_ie.sub_type = + pe_session->vendor_specific_vht_ie_sub_type; + frm->vendor_vht_ie.VHTCaps.present = 1; + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.vendor_vhtie && + pe_session->vht_config.su_beam_formee) { + pe_debug("Disable SU beamformee for vendor IE"); + pe_session->vht_config.su_beam_formee = 0; + } + populate_dot11f_vht_caps(mac_ctx, pe_session, + &frm->vendor_vht_ie.VHTCaps); + vht_enabled = true; + } + if (pe_session->is_ext_caps_present) + populate_dot11f_ext_cap(mac_ctx, vht_enabled, + &frm->ExtCap, pe_session); + + populate_dot11f_qcn_ie(mac_ctx, pe_session, + &frm->qcn_ie, QCN_IE_ATTR_ID_ALL); + + populate_dot11f_bss_max_idle(mac_ctx, pe_session, + &frm->bss_max_idle_period); + + if (IS_DOT11_MODE_HE(pe_session->dot11mode)) + lim_update_session_he_capable(mac_ctx, pe_session); + + if (lim_is_session_he_capable(pe_session)) { + populate_dot11f_he_caps(mac_ctx, pe_session, + &frm->he_cap); + populate_dot11f_he_6ghz_cap(mac_ctx, pe_session, + &frm->he_6ghz_band_cap); + } else if (pe_session->he_with_wep_tkip) { + populate_dot11f_he_caps(mac_ctx, NULL, &frm->he_cap); + populate_dot11f_he_6ghz_cap(mac_ctx, pe_session, + &frm->he_6ghz_band_cap); + } + + if (add_ie_len && lim_is_session_eht_capable(pe_session)) { + populate_dot11f_eht_caps(mac_ctx, pe_session, &frm->eht_cap); + lim_strip_mlo_ie(mac_ctx, add_ie, &add_ie_len); + } + + is_ml_ap = !!pe_session->lim_join_req->bssDescription.is_ml_ap; + if (is_ml_ap) + mlo_ie_len = lim_fill_assoc_req_mlo_ie(mac_ctx, pe_session, frm); + + /** + * In case of ML connection, if ML IE length is 0 then return failure. + */ + if (is_ml_ap && mlo_is_mld_sta(pe_session->vdev) && !mlo_ie_len) { + pe_err("Failed to add ML IE for vdev:%d", pe_session->vdev_id); + goto end; + } + + if (pe_session->is11Rconnection) { + struct bss_description *bssdescr; + + bssdescr = &pe_session->lim_join_req->bssDescription; + pe_debug("mdie = %02x %02x %02x", + (unsigned int) bssdescr->mdie[0], + (unsigned int) bssdescr->mdie[1], + (unsigned int) bssdescr->mdie[2]); + populate_mdie(mac_ctx, &frm->MobilityDomain, + pe_session->lim_join_req->bssDescription.mdie); + if (bssdescr->mdiePresent) { + mdie_cfg.bool_value = true; + mdie_cfg.uint_value = + (bssdescr->mdie[1] << 8) | (bssdescr->mdie[0]); + } else { + mdie_cfg.bool_value = false; + mdie_cfg.uint_value = 0; + } + + wlan_cm_roam_cfg_set_value(mac_ctx->psoc, vdev_id, + MOBILITY_DOMAIN, &mdie_cfg); + + /* + * IEEE80211-ai [13.2.4 FT initial mobility domain association + * over FILS in an RSN] + * Populate FT IE in association request. This FT IE should be + * same as the FT IE received in auth response frame during the + * FT-FILS authentication. + */ + if (lim_is_fils_connection(pe_session)) + populate_fils_ft_info(mac_ctx, &frm->FTInfo, + pe_session); + } + +#ifdef FEATURE_WLAN_ESE + /* + * ESE Version IE will be included in association request + * when ESE is enabled on DUT through ini and it is also + * advertised by the peer AP to which we are trying to + * associate to. + */ + if (pe_session->is_ese_version_ie_present && + mac_ctx->mlme_cfg->lfr.ese_enabled) + populate_dot11f_ese_version(&frm->ESEVersion); + /* For ESE Associations fill the ESE IEs */ + if (wlan_cm_get_ese_assoc(mac_ctx->pdev, pe_session->vdev_id)) { +#ifndef FEATURE_DISABLE_RM + populate_dot11f_ese_rad_mgmt_cap(&frm->ESERadMgmtCap); +#endif + } +#endif + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + if (extr_ext_flag) + lim_merge_extcap_struct(&frm->ExtCap, &extr_ext_cap, true); + + /* Clear the bits in EXTCAP IE if AP not advertise it in beacon */ + if (frm->ExtCap.present && pe_session->is_ext_caps_present) { + ie_offset = DOT11F_FF_TIMESTAMP_LEN + + DOT11F_FF_BEACONINTERVAL_LEN + + DOT11F_FF_CAPABILITIES_LEN; + + qdf_mem_zero((uint8_t *)&bcn_ext_cap, sizeof(tDot11fIEExtCap)); + if (pe_session->beacon && (pe_session->bcnLen > + (ie_offset + sizeof(struct wlan_frame_hdr)))) { + bcn_ie = pe_session->beacon + ie_offset + + sizeof(struct wlan_frame_hdr); + bcn_ie_len = pe_session->bcnLen - ie_offset - + sizeof(struct wlan_frame_hdr); + p_ext_cap = (uint8_t *)wlan_get_ie_ptr_from_eid( + DOT11F_EID_EXTCAP, + bcn_ie, bcn_ie_len); + lim_update_extcap_struct(mac_ctx, p_ext_cap, + &bcn_ext_cap); + lim_merge_extcap_struct(&frm->ExtCap, &bcn_ext_cap, + false); + } + + populate_dot11f_btm_extended_caps(mac_ctx, pe_session, + &frm->ExtCap); + /* + * TWT extended capabilities should be populated after the + * intersection of beacon caps and self caps is done because + * the bits for TWT are unique to STA and AP and cannot be + * intersected. + */ + populate_dot11f_twt_extended_caps(mac_ctx, pe_session, + &frm->ExtCap); + } else { + wlan_cm_set_assoc_btm_cap(pe_session->vdev, false); + } + + if (QDF_STATUS_SUCCESS != lim_strip_supp_op_class_update_struct(mac_ctx, + add_ie, &add_ie_len, &frm->SuppOperatingClasses)) + pe_debug("Unable to Stripoff supp op classes IE from Assoc Req"); + + if (lim_is_fils_connection(pe_session)) { + populate_dot11f_fils_params(mac_ctx, frm, pe_session); + aes_block_size_len = AES_BLOCK_SIZE; + if (add_ie_len && wlan_get_ie_ptr_from_eid(WLAN_ELEMID_FRAGMENT, + add_ie, add_ie_len)) + frag_ie_present = true; + } + + /* Strip and append HLP container IE only if it is fragmented */ + if (frag_ie_present && add_ie_len && + wlan_get_ext_ie_ptr_from_ext_id(SIR_FILS_HLP_OUI_TYPE, + SIR_FILS_HLP_OUI_LEN, add_ie, + add_ie_len)) { + fils_hlp_ie = qdf_mem_malloc(SIR_FILS_HLP_IE_LEN); + if (!fils_hlp_ie) + goto end; + + qdf_status = + lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + WLAN_ELEMID_EXTN_ELEM, ONE_BYTE, + SIR_FILS_HLP_OUI_TYPE, + SIR_FILS_HLP_OUI_LEN, fils_hlp_ie, + SIR_FILS_HLP_IE_LEN - 2); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip FILS HLP container IE"); + goto end; + } + fils_hlp_ie_len = fils_hlp_ie[1] + 2; + + current_len = add_ie_len; + qdf_status = + lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + WLAN_ELEMID_FRAGMENT, ONE_BYTE, + NULL, 0, &fils_hlp_ie[fils_hlp_ie_len], + SIR_FILS_HLP_IE_LEN - fils_hlp_ie_len - 2); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip fragment IE of HLP container IE"); + goto end; + } + fils_hlp_ie_len += current_len - add_ie_len; + } + + /* RSNX IE for SAE PWE derivation based on H2E */ + if (add_ie_len && + wlan_get_ie_ptr_from_eid(WLAN_ELEMID_RSNXE, add_ie, add_ie_len)) { + rsnx_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!rsnx_ie) + goto end; + + qdf_status = lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + WLAN_ELEMID_RSNXE, ONE_BYTE, + NULL, 0, rsnx_ie, WLAN_MAX_IE_LEN); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip Vendor IEs"); + goto end; + } + rsnx_ie_len = rsnx_ie[1] + 2; + } + /* MSCS ext ie */ + if (add_ie_len && + wlan_get_ext_ie_ptr_from_ext_id(MSCS_OUI_TYPE, MSCS_OUI_SIZE, + add_ie, add_ie_len)) { + mscs_ext_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!mscs_ext_ie) + goto end; + + qdf_status = lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + WLAN_ELEMID_EXTN_ELEM, ONE_BYTE, + MSCS_OUI_TYPE, MSCS_OUI_SIZE, + mscs_ext_ie, WLAN_MAX_IE_LEN); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip MSCS ext IE"); + goto end; + } + mscs_ext_ie_len = mscs_ext_ie[1] + 2; + } + + /* + * MBO IE needs to be appendded at the end of the assoc request + * frame and is not parsed and unpacked by the frame parser + * as the supplicant can send multiple TLVs with same Attribute + * in the MBO IE and the frame parser does not support multiple + * TLVs with same attribute in a single IE. + * Strip off the MBO IE from add_ie and append it at the end. + */ + if (add_ie_len && + wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_MBO_OUI, + SIR_MAC_MBO_OUI_SIZE, add_ie, + add_ie_len)) { + mbo_ie = qdf_mem_malloc(DOT11F_IE_MBO_IE_MAX_LEN + 2); + if (!mbo_ie) + goto end; + + qdf_status = lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + WLAN_ELEMID_VENDOR, ONE_BYTE, + SIR_MAC_MBO_OUI, + SIR_MAC_MBO_OUI_SIZE, + mbo_ie, DOT11F_IE_MBO_IE_MAX_LEN); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip MBO IE"); + goto end; + } + + /* Include the EID and length fields */ + mbo_ie_len = mbo_ie[1] + 2; + + if (pe_session->connected_akm == ANI_AKM_TYPE_NONE) + is_open_auth = true; + + if (!is_open_auth) { + bss_mfp_capable = + lim_get_vdev_rmf_capable(mac_ctx, pe_session); + if (!bss_mfp_capable) { + pe_debug("Peer doesn't support PMF, Don't add MBO IE"); + qdf_mem_free(mbo_ie); + mbo_ie = NULL; + mbo_ie_len = 0; + } + } + } + + /* + * Strip rest of the vendor IEs and append to the assoc request frame. + * Append the IEs just before MBO IEs as MBO IEs have to be at the + * end of the frame. + */ + if (add_ie_len && + wlan_get_ie_ptr_from_eid(WLAN_ELEMID_VENDOR, add_ie, add_ie_len)) { + vendor_ies = qdf_mem_malloc(MAX_VENDOR_IES_LEN + 2); + if (vendor_ies) { + current_len = add_ie_len; + qdf_status = lim_strip_ie(mac_ctx, add_ie, &add_ie_len, + WLAN_ELEMID_VENDOR, ONE_BYTE, + NULL, + 0, + vendor_ies, + MAX_VENDOR_IES_LEN); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip Vendor IEs"); + goto end; + } + + vendor_ie_len = current_len - add_ie_len; + } + } + + qdf_status = lim_fill_adaptive_11r_ie(pe_session, &adaptive_11r_ie, + &adaptive_11r_ie_len); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to fill adaptive 11r IE"); + goto end; + } + + /* + * Do unpack to populate the add_ie buffer to frm structure + * before packing the frm structure. In this way, the IE ordering + * which the latest 802.11 spec mandates is maintained. + */ + if (add_ie_len) { + ret = dot11f_unpack_assoc_request(mac_ctx, add_ie, + add_ie_len, frm, true); + if (DOT11F_FAILED(ret)) { + pe_err("unpack failed, ret: 0x%x", ret); + goto end; + } + } + + /* Strip EHT capabilities IE */ + if (lim_is_session_eht_capable(pe_session)) { + eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + MIN_IE_LEN); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + goto end; + } + + is_band_2g = + WLAN_REG_IS_24GHZ_CH_FREQ(pe_session->curr_op_freq); + + lim_ieee80211_pack_ehtcap(eht_cap_ie, frm->eht_cap, frm->he_cap, + is_band_2g); + eht_cap_ie_len = eht_cap_ie[TAG_LEN_POS] + MIN_IE_LEN; + + /* Mark EHT capability as false as this the data is already + * present in eht_cap_ie buffer pointer + */ + frm->eht_cap.present = false; + } + + status = dot11f_get_packed_assoc_request_size(mac_ctx, frm, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Association Request packet size failure(0x%08x)", + status); + /* We'll fall back on the worst case scenario: */ + payload = sizeof(tDot11fAssocRequest); + } else if (DOT11F_WARNED(status)) { + pe_warn("Association request packet size warning (0x%08x)", + status); + } + + bytes = payload + sizeof(tSirMacMgmtHdr) + aes_block_size_len + + rsnx_ie_len + mbo_ie_len + adaptive_11r_ie_len + + mscs_ext_ie_len + vendor_ie_len + mlo_ie_len + fils_hlp_ie_len + + eht_cap_ie_len; + + + qdf_status = cds_packet_alloc((uint16_t) bytes, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes", bytes); + + pe_session->limMlmState = pe_session->limPrevMlmState; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_MLM_STATE, + pe_session->peSessionId, + pe_session->limMlmState)); + + /* Update PE session id */ + assoc_cnf.sessionId = pe_session->peSessionId; + + assoc_cnf.resultCode = eSIR_SME_RESOURCES_UNAVAILABLE; + + lim_post_sme_message(mac_ctx, LIM_MLM_ASSOC_CNF, + (uint32_t *) &assoc_cnf); + + goto end; + } + /* Paranoia: */ + qdf_mem_zero(frame, bytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ASSOC_REQ, pe_session->bssId, + pe_session->self_mac_addr); + /* That done, pack the Assoc Request: */ + status = dot11f_pack_assoc_request(mac_ctx, frm, + frame + sizeof(tSirMacMgmtHdr), payload, &payload); + if (DOT11F_FAILED(status)) { + pe_err("Assoc request pack failure (0x%08x)", status); + cds_packet_free((void *)packet); + goto end; + } else if (DOT11F_WARNED(status)) { + pe_warn("Assoc request pack warning (0x%08x)", status); + } + + if (fils_hlp_ie && fils_hlp_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + fils_hlp_ie, fils_hlp_ie_len); + payload = payload + fils_hlp_ie_len; + } + + if (eht_cap_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + eht_cap_ie, eht_cap_ie_len); + payload += eht_cap_ie_len; + } + + if (rsnx_ie && rsnx_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + rsnx_ie, rsnx_ie_len); + payload = payload + rsnx_ie_len; + } + + if (mscs_ext_ie && mscs_ext_ie_len) { + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + mscs_ext_ie, mscs_ext_ie_len); + payload = payload + mscs_ext_ie_len; + } + + /* Copy the vendor IEs to the end of the frame */ + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + vendor_ies, vendor_ie_len); + payload = payload + vendor_ie_len; + + /* Copy the MBO IE to the end of the frame */ + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + mbo_ie, mbo_ie_len); + payload = payload + mbo_ie_len; + + /* + * Copy the Vendor specific Adaptive 11r IE to end of the + * assoc request frame + */ + qdf_mem_copy(frame + sizeof(tSirMacMgmtHdr) + payload, + adaptive_11r_ie, adaptive_11r_ie_len); + payload = payload + adaptive_11r_ie_len; + + if (mlo_ie_len) { + qdf_status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + frame + sizeof(tSirMacMgmtHdr) + payload); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + payload = payload + mlo_ie_len; + } + + if (pe_session->assoc_req) { + qdf_mem_free(pe_session->assoc_req); + pe_session->assoc_req = NULL; + pe_session->assocReqLen = 0; + } + + if (lim_is_fils_connection(pe_session)) { + qdf_status = aead_encrypt_assoc_req(mac_ctx, pe_session, + frame, &payload); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + cds_packet_free((void *)packet); + goto end; + } + } + + pe_session->assoc_req = qdf_mem_malloc(payload); + if (pe_session->assoc_req) { + /* + * Store the Assoc request. This is sent to csr/hdd in + * join cnf response. + */ + qdf_mem_copy(pe_session->assoc_req, + frame + sizeof(tSirMacMgmtHdr), payload); + pe_session->assocReqLen = payload; + } + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_STA_MODE) + tx_flag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + mac_hdr = (tpSirMacMgmtHdr) frame; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, mac_hdr->fc.subType)); + + pe_debug("extr_ext_flag %d mbo ie len %d is open auth %d stripped vendor len %d he with tkip %d ht %d vht %d opmode %d vendor vht %d he %d eht %d", + extr_ext_flag, mbo_ie_len, is_open_auth, current_len, + pe_session->he_with_wep_tkip, + frm->HTCaps.present, frm->VHTCaps.present, + frm->OperatingMode.present, frm->vendor_vht_ie.present, + frm->he_cap.present, frm->eht_cap.present); + pe_nofl_info("Assoc req TX: vdev %d to "QDF_MAC_ADDR_FMT" seq num %d", + pe_session->vdev_id, QDF_MAC_ADDR_REF(pe_session->bssId), + mac_ctx->mgmtSeqNum); + + lim_cp_stats_cstats_log_assoc_req_evt(pe_session, CSTATS_DIR_TX, + pe_session->bssId, + mac_hdr->sa, + frm->SSID.num_ssid, + frm->SSID.ssid, + frm->HTCaps.present, + frm->VHTCaps.present, + frm->he_cap.present, + frm->eht_cap.present, false); + + min_rid = lim_get_min_session_txrate(pe_session, NULL); + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_START_EVENT, + pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + lim_diag_mgmt_tx_event_report(mac_ctx, mac_hdr, + pe_session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + peer_rssi = mac_ctx->lim.bss_rssi; + + qdf_status = + wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t) (sizeof(tSirMacMgmtHdr) + payload), + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame, lim_assoc_tx_complete_cnf, + tx_flag, vdev_id, false, 0, + min_rid, peer_rssi, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send Association Request (%X)!", + qdf_status); + mac_ctx->assoc_ack_status = LIM_TX_FAILED; + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_ASSOC_ACK_EVENT, + pe_session, SENT_FAIL, QDF_STATUS_E_FAILURE); + /* Pkt will be freed up by the callback */ + } + +end: + qdf_mem_free(eht_cap_ie); + qdf_mem_free(fils_hlp_ie); + qdf_mem_free(rsnx_ie); + qdf_mem_free(vendor_ies); + qdf_mem_free(mbo_ie); + qdf_mem_free(mscs_ext_ie); + + /* Free up buffer allocated for mlm_assoc_req */ + qdf_mem_free(adaptive_11r_ie); + qdf_mem_free(mlm_assoc_req); + qdf_mem_free(add_ie); + mlm_assoc_req = NULL; + qdf_mem_free(frm); + return; +} + +/** + * lim_get_addba_rsp_ptr() - Search the pointer to addba response + * @ie: the pointer to entire frame + * @ie_len: length of ie + * + * Host reserved 8 bytes for CCMP header trailer and initialize them + * as 0 when rmf enabled & key installed and tx addba rsp frame. So, + * search the pointer to addba response and then unpack the frame. + * + * Return: the pointer to addba response + */ +static uint8_t * +lim_get_addba_rsp_ptr(uint8_t *ie, uint32_t ie_len) +{ + uint32_t left = ie_len; + uint8_t *ptr = ie; + uint8_t category, action; + uint32_t addba_rsp_len = sizeof(tDot11faddba_rsp); + + while (left >= addba_rsp_len) { + category = ptr[0]; + action = ptr[1]; + + if (category == ACTION_CATEGORY_BACK && + action == ADDBA_RESPONSE) + return ptr; + + left--; + ptr++; + } + + return NULL; +} + +/** + * lim_addba_rsp_tx_complete_cnf() - Confirmation for add BA response OTA + * @context: pointer to global mac + * @buf: buffer which is nothing but entire ADD BA frame + * @tx_complete: Sent status + * @params: tx completion params + * + * Return: This returns QDF_STATUS + */ +static QDF_STATUS lim_addba_rsp_tx_complete_cnf(void *context, + qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + tSirMacMgmtHdr *mac_hdr; + tDot11faddba_rsp rsp = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t rsp_len; + QDF_STATUS status; + uint8_t *data; + uint8_t *addba_rsp_ptr; + uint32_t data_len; + struct wmi_mgmt_params *mgmt_params = (struct wmi_mgmt_params *)params; + + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) + pe_debug("Add ba response successfully sent"); + else + pe_debug("Fail to send add ba response"); + + if (!buf) { + pe_err("Addba response frame buffer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + data = qdf_nbuf_data(buf); + + if (!data) { + pe_err("Addba response frame is NULL"); + return QDF_STATUS_E_FAILURE; + } + + data_len = (uint32_t)qdf_nbuf_get_data_len(buf); + if (data_len < (sizeof(*mac_hdr) + sizeof(rsp))) { + pe_err("Invalid data len %d", data_len); + return QDF_STATUS_E_FAILURE; + } + + addba_rsp_ptr = lim_get_addba_rsp_ptr( + data + sizeof(*mac_hdr), + data_len - sizeof(*mac_hdr)); + if (!addba_rsp_ptr) { + pe_debug("null addba_rsp_ptr"); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + (void *)data, data_len); + addba_rsp_ptr = (uint8_t *)data + sizeof(*mac_hdr); + } + mac_hdr = (tSirMacMgmtHdr *)data; + rsp_len = sizeof(rsp); + status = dot11f_unpack_addba_rsp(mac_ctx, addba_rsp_ptr, + rsp_len, &rsp, false); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse (0x%08x, %d bytes)", + status, rsp_len); + goto error; + } + + cdp_addba_resp_tx_completion(soc, mac_hdr->da, mgmt_params->vdev_id, + rsp.addba_param_set.tid, tx_complete); +error: + if (buf) + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +#define SAE_AUTH_ALGO_LEN 2 +#define SAE_AUTH_ALGO_OFFSET 0 +static bool lim_is_ack_for_sae_auth(qdf_nbuf_t buf) +{ + tpSirMacMgmtHdr mac_hdr; + uint16_t *sae_auth, min_len; + + if (!buf) { + pe_debug("buf is NULL"); + return false; + } + + min_len = sizeof(tSirMacMgmtHdr) + SAE_AUTH_ALGO_LEN; + if (qdf_nbuf_len(buf) < min_len) { + pe_debug("buf_len %d less than min_len %d", + (uint32_t)qdf_nbuf_len(buf), min_len); + return false; + } + + mac_hdr = (tpSirMacMgmtHdr)(qdf_nbuf_data(buf)); + if (mac_hdr->fc.subType == SIR_MAC_MGMT_AUTH) { + sae_auth = (uint16_t *)((uint8_t *)mac_hdr + + sizeof(tSirMacMgmtHdr)); + if (sae_auth[SAE_AUTH_ALGO_OFFSET] == + eSIR_AUTH_TYPE_SAE) + return true; + } + + return false; +} + +/** + * lim_auth_tx_complete_cnf()- Confirmation for auth sent over the air + * @context: pointer to global mac + * @buf: buffer + * @tx_complete : Sent status + * @params: tx completion params + * + * Return: This returns QDF_STATUS + */ +static QDF_STATUS lim_auth_tx_complete_cnf(void *context, + qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + uint16_t auth_ack_status; + uint16_t reason_code; + bool sae_auth_acked; + + if (params) + wlan_send_tx_complete_event(context, buf, params, tx_complete, + WLAN_AUTH_REQ); + + pe_nofl_rl_info("Auth TX: %s (%d)", + (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) ? + "success" : "fail", tx_complete); + if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) { + mac_ctx->auth_ack_status = LIM_ACK_RCD_SUCCESS; + auth_ack_status = ACKED; + reason_code = QDF_STATUS_SUCCESS; + sae_auth_acked = lim_is_ack_for_sae_auth(buf); + /* + * 'Change' timer for future activations only if ack + * received is not for WPA SAE auth frames. + */ + if (!sae_auth_acked) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_AUTH_RETRY_TIMER); + } else if (tx_complete == WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK) { + mac_ctx->auth_ack_status = LIM_ACK_RCD_FAILURE; + auth_ack_status = NOT_ACKED; + reason_code = QDF_STATUS_E_FAILURE; + } else { + mac_ctx->auth_ack_status = LIM_TX_FAILED; + auth_ack_status = SENT_FAIL; + reason_code = QDF_STATUS_E_FAILURE; + } + + if (buf) + qdf_nbuf_free(buf); + + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_ACK_EVENT, + NULL, auth_ack_status, reason_code); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static uint32_t lim_calculate_auth_mlo_ie_len(struct mac_context *mac_ctx, + struct pe_session *session, + tSirMacAddr peer_addr) +{ + struct wlan_mlo_ie *mlo_ie; + uint32_t mlo_ie_len = 0; + struct tLimPreAuthNode *auth_node; + + mlo_ie = &session->mlo_ie; + if (wlan_vdev_mlme_is_mlo_vdev(session->vdev)) { + qdf_mem_zero(mlo_ie, sizeof(*mlo_ie)); + + pe_debug("Auth TX sys role: %d", GET_LIM_SYSTEM_ROLE(session)); + if (LIM_IS_STA_ROLE(session)) { + populate_dot11f_auth_mlo_ie(mac_ctx, session, mlo_ie); + mlo_ie_len = lim_caculate_mlo_ie_length(mlo_ie); + } else if (LIM_IS_AP_ROLE(session)) { + auth_node = lim_search_pre_auth_list(mac_ctx, peer_addr); + if (!auth_node) { + pe_err("no pre-auth ctx with peer addr"); + return 0; + } + + /* + * Populate MLO IE in Auth response frame if + * is_mlo_ie_present flag is set. It is set when peer + * is MLO AP + */ + if (auth_node && auth_node->is_mlo_ie_present) { + populate_dot11f_auth_mlo_ie(mac_ctx, session, + mlo_ie); + mlo_ie_len = lim_caculate_mlo_ie_length(mlo_ie); + } + } + } + + return mlo_ie_len; +} + +#else +static inline +uint32_t lim_calculate_auth_mlo_ie_len(struct mac_context *mac_ctx, + struct pe_session *session, + tSirMacAddr peer_addr) +{ + return 0; +} +#endif + +/** + * lim_send_auth_mgmt_frame() - Send an Authentication frame + * @mac_ctx: Pointer to Global MAC structure + * @auth_frame: Pointer to Authentication frame structure + * @peer_addr: MAC address of destination peer + * @wep_challenge_len: wep challenge length + * @session: PE session information + * + * This function is called by lim_process_mlm_messages(). Authentication frame + * is formatted and sent when this function is called. + * + * Return: void + */ +void +lim_send_auth_mgmt_frame(struct mac_context *mac_ctx, + tpSirMacAuthFrameBody auth_frame, + tSirMacAddr peer_addr, + uint8_t wep_challenge_len, + struct pe_session *session) +{ + uint8_t *frame, *body; + uint32_t frame_len = 0, body_len = 0; + tpSirMacMgmtHdr mac_hdr; + void *packet; + QDF_STATUS qdf_status, status; + uint8_t tx_flag = 0; + uint8_t vdev_id = 0; + uint16_t ft_ies_length = 0; + bool challenge_req = false; + enum rateid min_rid = RATEID_DEFAULT; + uint16_t ch_freq_tx_frame = 0; + int8_t peer_rssi = 0; + uint8_t *mlo_ie_buf = NULL; + uint32_t mlo_ie_len = 0; + + if (!session) { + pe_err("Error: psession Entry is NULL"); + return; + } + + vdev_id = session->vdev_id; + + if (wep_challenge_len) { + /* + * Auth frame3 to be sent with encrypted framebody + * + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus 2 bytes + * each for auth algorithm number, transaction number, + * status code, 128 bytes for challenge text and + * 4 bytes each for IV & ICV. + */ + body_len = wep_challenge_len + LIM_ENCR_AUTH_INFO_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + + goto alloc_packet; + } + + switch (auth_frame->authTransactionSeqNumber) { + case SIR_MAC_AUTH_FRAME_1: + /* + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus 2 bytes + * each for auth algorithm number, transaction number + * and status code. + */ + + body_len = SIR_MAC_AUTH_FRAME_INFO_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + + status = lim_create_fils_auth_data(mac_ctx, auth_frame, + session, &frame_len); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (auth_frame->authAlgoNumber == eSIR_FT_AUTH) { + if (session->ftPEContext.pFTPreAuthReq && + 0 != session->ftPEContext.pFTPreAuthReq-> + ft_ies_length) { + ft_ies_length = session->ftPEContext. + pFTPreAuthReq->ft_ies_length; + frame_len += ft_ies_length; + pe_debug("Auth frame, FTIES length added=%d", + ft_ies_length); + } else { + pe_debug("Auth frame, Does not contain FTIES!"); + frame_len += (2 + SIR_MDIE_SIZE); + } + } + + /* include MDIE in FILS authentication frame */ + if (session->lim_join_req && + session->is11Rconnection && + auth_frame->authAlgoNumber == SIR_FILS_SK_WITHOUT_PFS && + session->lim_join_req->bssDescription.mdiePresent) + frame_len += (2 + SIR_MDIE_SIZE); + break; + + case SIR_MAC_AUTH_FRAME_2: + if ((auth_frame->authAlgoNumber == eSIR_OPEN_SYSTEM) || + ((auth_frame->authAlgoNumber == eSIR_SHARED_KEY) && + (auth_frame->authStatusCode != STATUS_SUCCESS))) { + /* + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus + * 2 bytes each for auth algorithm number, + * transaction number and status code. + */ + + body_len = SIR_MAC_AUTH_FRAME_INFO_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + } else { + /* + * Shared Key algorithm with challenge text + * to be sent. + * + * Allocate buffer for Authenticaton frame of size + * equal to management frame header length plus + * 2 bytes each for auth algorithm number, + * transaction number, status code and 128 bytes + * for challenge text. + */ + + challenge_req = true; + body_len = SIR_MAC_AUTH_FRAME_INFO_LEN + + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + + SIR_MAC_CHALLENGE_ID_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + } + break; + + case SIR_MAC_AUTH_FRAME_3: + /* + * Auth frame3 to be sent without encrypted framebody + * + * Allocate buffer for Authenticaton frame of size equal + * to management frame header length plus 2 bytes each + * for auth algorithm number, transaction number and + * status code. + */ + + body_len = SIR_MAC_AUTH_FRAME_INFO_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + break; + + case SIR_MAC_AUTH_FRAME_4: + /* + * Allocate buffer for Authenticaton frame of size equal + * to management frame header length plus 2 bytes each + * for auth algorithm number, transaction number and + * status code. + */ + + body_len = SIR_MAC_AUTH_FRAME_INFO_LEN; + frame_len = sizeof(tSirMacMgmtHdr) + body_len; + + break; + default: + pe_err("Invalid auth transaction seq num"); + return; + } /* switch (auth_frame->authTransactionSeqNumber) */ + + mlo_ie_len = lim_calculate_auth_mlo_ie_len(mac_ctx, session, peer_addr); + + if (mlo_ie_len) { + mlo_ie_buf = qdf_mem_malloc(mlo_ie_len); + if (mlo_ie_buf) { + qdf_status = lim_fill_complete_mlo_ie(session, + mlo_ie_len, + mlo_ie_buf); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + mlo_ie_len = 0; + qdf_mem_free(mlo_ie_buf); + } + + frame_len += mlo_ie_len; + } + } +alloc_packet: + qdf_status = cds_packet_alloc((uint16_t) frame_len, (void **)&frame, + (void **)&packet); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("call to bufAlloc failed for AUTH frame"); + return; + } + + qdf_mem_zero(frame, frame_len); + + /* Prepare BD */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_AUTH, peer_addr, session->self_mac_addr); + mac_hdr = (tpSirMacMgmtHdr) frame; + if (wep_challenge_len) + mac_hdr->fc.wep = LIM_WEP_IN_FC; + else + mac_hdr->fc.wep = LIM_NO_WEP_IN_FC; + + /* Prepare BSSId */ + if (LIM_IS_AP_ROLE(session)) + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session->bssId, + sizeof(tSirMacAddr)); + + /* Prepare Authentication frame body */ + body = frame + sizeof(tSirMacMgmtHdr); + + if (wep_challenge_len) { + qdf_mem_copy(body, (uint8_t *) auth_frame, body_len); + } else { + *((uint16_t *) (body)) = + sir_swap_u16if_needed(auth_frame->authAlgoNumber); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + *((uint16_t *) (body)) = + sir_swap_u16if_needed( + auth_frame->authTransactionSeqNumber); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + *((uint16_t *) (body)) = + sir_swap_u16if_needed(auth_frame->authStatusCode); + body += sizeof(uint16_t); + body_len -= sizeof(uint16_t); + + if (challenge_req) { + if (body_len < SIR_MAC_AUTH_CHALLENGE_BODY_LEN) { + /* copy challenge IE id, len, challenge text */ + *body = auth_frame->type; + body++; + body_len -= sizeof(uint8_t); + *body = auth_frame->length; + body++; + body_len -= sizeof(uint8_t); + qdf_mem_copy(body, auth_frame->challengeText, + body_len); + pe_err("Incomplete challenge info: length: %d, expected: %d", + body_len, + SIR_MAC_AUTH_CHALLENGE_BODY_LEN); + body += body_len; + body_len = 0; + } else { + /* copy challenge IE id, len, challenge text */ + *body = auth_frame->type; + body++; + *body = auth_frame->length; + body++; + qdf_mem_copy(body, auth_frame->challengeText, + SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH); + body += SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH; + body_len -= SIR_MAC_SAP_AUTH_CHALLENGE_LENGTH + + SIR_MAC_CHALLENGE_ID_LEN; + } + } + + if ((auth_frame->authAlgoNumber == eSIR_FT_AUTH) && + (auth_frame->authTransactionSeqNumber == + SIR_MAC_AUTH_FRAME_1) && + (session->ftPEContext.pFTPreAuthReq)) { + + if (ft_ies_length > 0) { + qdf_mem_copy(body, + session->ftPEContext. + pFTPreAuthReq->ft_ies, + ft_ies_length); + pe_debug("Auth1 Frame FTIE is: "); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + (uint8_t *) body, + ft_ies_length); + } else if (session->ftPEContext. + pFTPreAuthReq->pbssDescription) { + /* MDID attr is 54 */ + *body = WLAN_ELEMID_MOBILITY_DOMAIN; + body++; + *body = SIR_MDIE_SIZE; + body++; + qdf_mem_copy(body, + &session->ftPEContext.pFTPreAuthReq-> + pbssDescription->mdie[0], + SIR_MDIE_SIZE); + } + } else if ((auth_frame->authAlgoNumber == + SIR_FILS_SK_WITHOUT_PFS) && + (auth_frame->authTransactionSeqNumber == + SIR_MAC_AUTH_FRAME_1)) { + pe_debug("FILS: appending fils Auth data"); + lim_add_fils_data_to_auth_frame(session, body); + } + } + + if (mlo_ie_len && mlo_ie_buf) { + qdf_mem_copy(body, mlo_ie_buf, mlo_ie_len); + qdf_mem_free(mlo_ie_buf); + } + + pe_nofl_info("Auth TX: vdev %d seq %d seq num %d status %d WEP %d to " QDF_MAC_ADDR_FMT, + vdev_id, auth_frame->authTransactionSeqNumber, + mac_ctx->mgmtSeqNum, auth_frame->authStatusCode, + mac_hdr->fc.wep, QDF_MAC_ADDR_REF(mac_hdr->da)); + + if ((session->ftPEContext.pFTPreAuthReq) && + (!wlan_reg_is_24ghz_ch_freq( + session->ftPEContext.pFTPreAuthReq->pre_auth_channel_freq))) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + else if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + if (session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_STA_MODE) + tx_flag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mac_hdr->fc.subType)); + + if (mac_ctx->auth_ack_status != LIM_ACK_RCD_FAILURE && + mac_ctx->auth_ack_status != LIM_TX_FAILED) + mac_ctx->auth_ack_status = LIM_ACK_NOT_RCD; + min_rid = lim_get_min_session_txrate(session, NULL); + peer_rssi = mac_ctx->lim.bss_rssi; + lim_diag_mgmt_tx_event_report(mac_ctx, mac_hdr, + session, QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + + if (session->ftPEContext.pFTPreAuthReq) + ch_freq_tx_frame = session->ftPEContext. + pFTPreAuthReq->pre_auth_channel_freq; + + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t)frame_len, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, + lim_auth_tx_complete_cnf, + tx_flag, vdev_id, false, + ch_freq_tx_frame, min_rid, peer_rssi, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("*** Could not send Auth frame, retCode=%X ***", + qdf_status); + mac_ctx->auth_ack_status = LIM_TX_FAILED; + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_ACK_EVENT, + session, SENT_FAIL, QDF_STATUS_E_FAILURE); + /* Pkt will be freed up by the callback */ + } + return; +} + +static +void lim_delete_deauth_all_pending_sta(struct mac_context *mac_ctx, + struct pe_session *session) +{ + int i = 0; + tpDphHashNode sta_ds = NULL; + + if (!session) + return; + + for (i = 0; i < session->dph.dphHashTable.size; i++) { + sta_ds = dph_get_hash_entry(mac_ctx, i, + &session->dph.dphHashTable); + /* + * In case of multiple STA kickout on SAP interface, + * DeauthAckTimer would be started only for the first + * deauth queued. So, the ack timeout would not be + * fired for other deauth frames. Therefore as part of + * of this timer expiry(of first queued deauth), trigger + * sta deletion for all the peers with deauth in progress. + * + * Do not trigger deletion if sta_deletion is already in + * progress. + */ + + if (!sta_ds || !sta_ds->valid || + sta_ds->sta_deletion_in_progress || + !sta_ds->is_disassoc_deauth_in_progress) + continue; + + sta_ds->is_disassoc_deauth_in_progress = 0; + lim_trigger_sta_deletion(mac_ctx, sta_ds, session); + } +} + +QDF_STATUS lim_send_deauth_cnf(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tLimMlmDeauthReq *deauth_req; + tLimMlmDeauthCnf deauth_cnf; + struct pe_session *session_entry; + QDF_STATUS qdf_status; + uint32_t i; + + deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + if (deauth_req) { + if (tx_timer_running( + &mac_ctx->lim.lim_timers.gLimDeauthAckTimer)) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DEAUTH_ACK_TIMER); + + session_entry = pe_find_session_by_session_id(mac_ctx, + deauth_req->sessionId); + if (!session_entry) { + pe_err("session does not exist for given sessionId"); + deauth_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + if (qdf_is_macaddr_broadcast(&deauth_req->peer_macaddr) && + mac_ctx->mlme_cfg->sap_cfg.is_sap_bcast_deauth_enabled) { + if (wlan_vdev_mlme_is_mlo_ap(session_entry->vdev)) { + for (i = 1; + i < session_entry->dph.dphHashTable.size; + i++) { + sta_ds = dph_get_hash_entry( + mac_ctx, i, + &session_entry->dph.dphHashTable); + if (!sta_ds) + continue; + if (lim_is_mlo_conn(session_entry, + sta_ds)) + lim_mlo_notify_peer_disconn( + session_entry, + sta_ds); + } + } + qdf_status = lim_del_sta_all(mac_ctx, session_entry); + qdf_mem_free(deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = + NULL; + return qdf_status; + } + + sta_ds = + dph_lookup_hash_entry(mac_ctx, + deauth_req->peer_macaddr.bytes, + &aid, + &session_entry-> + dph.dphHashTable); + if (!sta_ds) { + deauth_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_mlo_notify_peer_disconn(session_entry, sta_ds); + + /* / Receive path cleanup with dummy packet */ + lim_ft_cleanup_pre_auth_info(mac_ctx, session_entry); + lim_cleanup_rx_path(mac_ctx, sta_ds, session_entry, true); + if ((session_entry->limSystemRole == eLIM_STA_ROLE) && + ( +#ifdef FEATURE_WLAN_ESE + (wlan_cm_get_ese_assoc(mac_ctx->pdev, + session_entry->vdev_id)) || +#endif + (cm_is_fast_roam_enabled(mac_ctx->psoc)) || + (session_entry->is11Rconnection))) { + pe_debug("FT Preauth (%pK,%d) Deauth rc %d src = %d", + session_entry, + session_entry->peSessionId, + deauth_req->reasonCode, + deauth_req->deauthTrigger); + lim_ft_cleanup(mac_ctx, session_entry); + } else { +#ifdef FEATURE_WLAN_ESE + pe_debug("No FT Preauth Session Cleanup in role %d" + " isESE %d" + " isLFR %d" + " is11r %d, Deauth reason %d Trigger = %d", + session_entry->limSystemRole, + mac_ctx->mlme_cfg->lfr.ese_enabled, + cm_is_fast_roam_enabled(mac_ctx->psoc), + session_entry->is11Rconnection, + deauth_req->reasonCode, + deauth_req->deauthTrigger); +#else + pe_debug("No FT Preauth Session Cleanup in role %d" + " isLFR %d" + " is11r %d, Deauth reason %d Trigger = %d", + session_entry->limSystemRole, + cm_is_fast_roam_enabled(mac_ctx->psoc), + session_entry->is11Rconnection, + deauth_req->reasonCode, + deauth_req->deauthTrigger); +#endif + } + /* Free up buffer allocated for mlmDeauthReq */ + qdf_mem_free(deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + } else { + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session_entry || (session_entry->opmode != QDF_SAP_MODE && + session_entry->opmode !=QDF_P2P_GO_MODE)) + return QDF_STATUS_SUCCESS; + /* + * If deauth request is not present, then the deauth could + * be from the SB STA kickout queued in SAP context. + * Cleanup all the STA which has is_disassoc_deauth_in_progress + */ + lim_delete_deauth_all_pending_sta(mac_ctx, session_entry); + } + return QDF_STATUS_SUCCESS; +end: + qdf_copy_macaddr(&deauth_cnf.peer_macaddr, + &deauth_req->peer_macaddr); + deauth_cnf.deauthTrigger = deauth_req->deauthTrigger; + deauth_cnf.aid = deauth_req->aid; + deauth_cnf.sessionId = deauth_req->sessionId; + + /* Free up buffer allocated */ + /* for mlmDeauthReq */ + qdf_mem_free(deauth_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq = NULL; + + lim_post_sme_message(mac_ctx, + LIM_MLM_DEAUTH_CNF, (uint32_t *) &deauth_cnf); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_disassoc_cnf() - Send disassoc confirmation to SME + * + * @mac_ctx: Handle to MAC context + * + * Sends disassoc confirmation to SME. Removes disassoc request stored + * in lim. + * + * Return: QDF_STATUS_SUCCESS + */ + +QDF_STATUS lim_send_disassoc_cnf(struct mac_context *mac_ctx) +{ + uint16_t aid; + tpDphHashNode sta_ds; + tLimMlmDisassocCnf disassoc_cnf; + struct pe_session *pe_session; + tLimMlmDisassocReq *disassoc_req; + + disassoc_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq; + if (disassoc_req) { + if (tx_timer_running( + &mac_ctx->lim.lim_timers.gLimDisassocAckTimer)) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DISASSOC_ACK_TIMER); + + pe_session = pe_find_session_by_session_id( + mac_ctx, disassoc_req->sessionId); + if (!pe_session) { + pe_err("No session for given sessionId"); + disassoc_cnf.resultCode = + eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, + disassoc_req->peer_macaddr.bytes, &aid, + &pe_session->dph.dphHashTable); + if (!sta_ds) { + pe_err("StaDs Null"); + disassoc_cnf.resultCode = eSIR_SME_INVALID_PARAMETERS; + goto end; + } + + lim_mlo_notify_peer_disconn(pe_session, sta_ds); + + /* Receive path cleanup with dummy packet */ + if (QDF_STATUS_SUCCESS != + lim_cleanup_rx_path(mac_ctx, sta_ds, pe_session, true)) { + disassoc_cnf.resultCode = + eSIR_SME_RESOURCES_UNAVAILABLE; + pe_err("cleanup_rx_path error"); + goto end; + } + if (LIM_IS_STA_ROLE(pe_session) && + (disassoc_req->reasonCode != + REASON_AUTHORIZED_ACCESS_LIMIT_REACHED)) { + pe_debug("FT Preauth Session (%pK %d) Clean up", + pe_session, pe_session->peSessionId); + + /* Delete FT session if there exists one */ + lim_ft_cleanup_pre_auth_info(mac_ctx, pe_session); + } + /* Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + return QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_SUCCESS; + } +end: + qdf_mem_copy((uint8_t *) &disassoc_cnf.peerMacAddr, + (uint8_t *) disassoc_req->peer_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + disassoc_cnf.aid = disassoc_req->aid; + disassoc_cnf.disassocTrigger = disassoc_req->disassocTrigger; + + /* Update PE session ID */ + disassoc_cnf.sessionId = disassoc_req->sessionId; + + if (disassoc_req) { + /* / Free up buffer allocated for mlmDisassocReq */ + qdf_mem_free(disassoc_req); + mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDisassocReq = NULL; + } + + lim_post_sme_message(mac_ctx, LIM_MLM_DISASSOC_CNF, + (uint32_t *) &disassoc_cnf); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_disassoc_tx_complete_cnf(void *context, + uint32_t tx_success, + void *params) +{ + struct mac_context *max_ctx = (struct mac_context *)context; + + pe_debug("tx_success: %d", tx_success); + + return lim_send_disassoc_cnf(max_ctx); +} + +static QDF_STATUS lim_disassoc_tx_complete_cnf_handler(void *context, + qdf_nbuf_t buf, + uint32_t tx_success, + void *params) +{ + struct mac_context *max_ctx = (struct mac_context *)context; + QDF_STATUS status_code; + struct scheduler_msg msg = {0}; + + if (params) + wlan_send_tx_complete_event(context, buf, params, tx_success, + WLAN_DISASSOC_TX); + + pe_debug("tx_success: %d", tx_success); + + if (buf) + qdf_nbuf_free(buf); + msg.type = (uint16_t) WMA_DISASSOC_TX_COMP; + msg.bodyptr = params; + msg.bodyval = tx_success; + + status_code = lim_post_msg_high_priority(max_ctx, &msg); + if (status_code != QDF_STATUS_SUCCESS) + pe_err("posting message: %X to LIM failed, reason: %d", + msg.type, status_code); + return status_code; +} + +QDF_STATUS lim_deauth_tx_complete_cnf(void *context, + uint32_t tx_success, + void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + struct wmi_mgmt_params *mgmt_params = + (struct wmi_mgmt_params *)params; + uint8_t vdev_id = WLAN_INVALID_VDEV_ID; + + pe_debug("tx_success: %d", tx_success); + if (mgmt_params) + vdev_id = mgmt_params->vdev_id; + qdf_mem_free(params); + + return lim_send_deauth_cnf(mac_ctx, vdev_id); +} + +static QDF_STATUS lim_ap_delete_sta_upon_deauth_tx(struct mac_context *mac_ctx, + struct pe_session *session, + tSirMacAddr peer) +{ + tpDphHashNode stads; + uint16_t aid; + + if (!session || (session->opmode != QDF_SAP_MODE && + session->opmode != QDF_P2P_GO_MODE)) + return QDF_STATUS_E_FAILURE; + + stads = dph_lookup_hash_entry(mac_ctx, peer, &aid, + &session->dph.dphHashTable); + + if (!stads || !stads->ocv_enabled || + stads->last_ocv_done_freq == session->curr_op_freq) + return QDF_STATUS_E_FAILURE; + + /* + * Proceed with sta deletion only if + * is_disassoc_deauth_in_progress is set. If unset, + * sta deletion will be handled by the deauth ack + * timeout handler. + */ + if (!stads->is_disassoc_deauth_in_progress || + stads->sta_deletion_in_progress) + return QDF_STATUS_SUCCESS; + + lim_trigger_sta_deletion(mac_ctx, stads, session); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS lim_deauth_tx_complete_cnf_handler(void *context, + qdf_nbuf_t buf, + uint32_t tx_success, + void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + QDF_STATUS status_code = QDF_STATUS_E_FAILURE; + struct scheduler_msg msg = {0}; + tLimMlmDeauthReq *deauth_req; + struct pe_session *session = NULL; + tSirMacMgmtHdr *mac_hdr = NULL; + uint8_t vdev_id = WLAN_INVALID_VDEV_ID; + struct wmi_mgmt_params *mgmt_params = + (struct wmi_mgmt_params *)params; + struct wmi_mgmt_params *msg_params = NULL; + + if (params) + wlan_send_tx_complete_event(context, buf, params, tx_success, + WLAN_DEAUTH_TX); + + deauth_req = mac_ctx->lim.limDisassocDeauthCnfReq.pMlmDeauthReq; + + pe_debug("tx_complete = %s tx_success = %d", + (tx_success == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) ? + "success" : "fail", tx_success); + + if (buf && (qdf_nbuf_len(buf) > sizeof(struct wlan_frame_hdr) + 2)) + mac_hdr = (tSirMacMgmtHdr *)qdf_nbuf_data(buf); + + if (!deauth_req && mac_hdr) { + if (mgmt_params) + vdev_id = mgmt_params->vdev_id; + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + status_code = lim_ap_delete_sta_upon_deauth_tx(mac_ctx, session, + (uint8_t *)mac_hdr->da); + } + + if (buf) + qdf_nbuf_free(buf); + + /* Cleanup has been handled for SAP/GO context, return */ + if (QDF_IS_STATUS_SUCCESS(status_code)) + return QDF_STATUS_SUCCESS; + + if (deauth_req) + session = pe_find_session_by_session_id(mac_ctx, + deauth_req->sessionId); + if (tx_success != WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK && session && + session->deauth_retry.retry_cnt) { + if (tx_timer_running( + &mac_ctx->lim.lim_timers.gLimDeauthAckTimer)) + lim_deactivate_and_change_timer(mac_ctx, + eLIM_DEAUTH_ACK_TIMER); + lim_send_deauth_mgmt_frame(mac_ctx, + session->deauth_retry.reason_code, + session->deauth_retry.peer_macaddr.bytes, + session, true); + session->deauth_retry.retry_cnt--; + return QDF_STATUS_SUCCESS; + } + + msg_params = qdf_mem_malloc(sizeof(struct wmi_mgmt_params)); + if (!msg_params) { + pe_err("malloc failed"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(msg_params, mgmt_params, sizeof(struct wmi_mgmt_params)); + + msg.type = (uint16_t) WMA_DEAUTH_TX_COMP; + msg.bodyptr = msg_params; + msg.bodyval = tx_success; + + status_code = lim_post_msg_high_priority(mac_ctx, &msg); + if (status_code != QDF_STATUS_SUCCESS) { + qdf_mem_free(msg_params); + pe_err("posting message: %X to LIM failed, reason: %d", + msg.type, status_code); + } + + return status_code; +} + +/** + * lim_append_ies_to_frame() - Append IEs to the frame + * + * @frame: Pointer to the frame buffer that needs to be populated + * @frame_len: Pointer for current frame length + * @ie: pointer for disconnect IEs + * + * This function is called by lim_send_disassoc_mgmt_frame and + * lim_send_deauth_mgmt_frame APIs as part of disconnection. + * Append IEs and update frame length. + * + * Return: None + */ +static void +lim_append_ies_to_frame(uint8_t *frame, uint32_t *frame_len, + struct element_info *ie) +{ + if (!ie || !ie->len || !ie->ptr) + return; + qdf_mem_copy(frame, ie->ptr, ie->len); + *frame_len += ie->len; + pe_debug("Appended IEs len: %u", ie->len); +} + +/** + * \brief This function is called to send Disassociate frame. + * + * + * \param mac Pointer to Global MAC structure + * + * \param nReason Indicates the reason that need to be sent in + * Disassociation frame + * + * \param peerMacAddr MAC address of the STA to which Disassociation frame is + * sent + * + * + */ + +void +lim_send_disassoc_mgmt_frame(struct mac_context *mac, + uint16_t nReason, + tSirMacAddr peer, + struct pe_session *pe_session, bool waitForAck) +{ + tDot11fDisassociation frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint32_t val = 0; + uint8_t smeSessionId = 0; + struct element_info *discon_ie; + + if (!pe_session) { + return; + } + + /* + * In case when cac timer is running for this SAP session then + * avoid sending disassoc out. It is violation of dfs specification. + */ + if (((pe_session->opmode == QDF_SAP_MODE) || + (pe_session->opmode == QDF_P2P_GO_MODE)) && + (true == mac->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + pe_info("CAC timer is running, drop disassoc from going out"); + if (waitForAck) + lim_send_disassoc_cnf(mac); + return; + } else if (lim_is_ml_peer_state_disconn(mac, pe_session, peer)) { + /** + * Check if disassoc is already sent on link vdev and ML peer + * state is moved to ML_PEER_DISCONN_INITIATED. In which case, + * do not send disassoc on assoc vdev, issue disassoc only if + * this check fails. + */ + pe_debug("disassoc tx not required for vdev id %d", + pe_session->vdev_id); + lim_send_disassoc_cnf(mac); + return; + } + smeSessionId = pe_session->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_disassociation_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Disassociation (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDisassociation); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Disassociation (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + discon_ie = mlme_get_self_disconnect_ies(pe_session->vdev); + if (discon_ie && discon_ie->len) + nBytes += discon_ie->len; + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a Disassociation", + nBytes); + if (waitForAck) + lim_send_disassoc_cnf(mac); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DISASSOC, peer, pe_session->self_mac_addr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + if (mac->is_usr_cfg_pmf_wep != PMF_WEP_DISABLE) + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + else + pe_debug("Skip WEP bit setting per usr cfg"); + + if (mac->is_usr_cfg_pmf_wep == PMF_INCORRECT_KEY) + txFlag |= HAL_USE_INCORRECT_KEY_PMF; + + nStatus = dot11f_pack_disassociation(mac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Disassociation (0x%08x)", + nStatus); + cds_packet_free((void *)pPacket); + if (waitForAck) + lim_send_disassoc_cnf(mac); + return; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a Disassociation (0x%08x)", + nStatus); + } + + /* Copy disconnect IEs to the end of the frame */ + lim_append_ies_to_frame(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, + &nPayload, discon_ie); + mlme_free_self_disconnect_ies(pe_session->vdev); + + pe_nofl_info("Disassoc TX: vdev %d seq %d reason %u and waitForAck %d to " QDF_MAC_ADDR_FMT " From " QDF_MAC_ADDR_FMT, + pe_session->vdev_id, mac->mgmtSeqNum, nReason, waitForAck, + QDF_MAC_ADDR_REF(pMacHdr->da), + QDF_MAC_ADDR_REF(pe_session->self_mac_addr)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; + + pe_session->deauth_disassoc_rc = nReason; + if (waitForAck) { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, + pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + /* Queue Disassociation frame in high priority WQ */ + /* get the duration from the request */ + qdf_status = + wma_tx_frameWithTxComplete(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + pFrame, lim_disassoc_tx_complete_cnf_handler, + txFlag, smeSessionId, false, 0, + RATEID_DEFAULT, 0, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to send disassoc frame"); + lim_send_disassoc_cnf(mac); + return; + } + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + + if (tx_timer_change + (&mac->lim.lim_timers.gLimDisassocAckTimer, val, 0) + != TX_SUCCESS) { + pe_err("Unable to change Disassoc ack Timer val"); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&mac->lim.lim_timers. + gLimDisassocAckTimer)) { + pe_err("Unable to activate Disassoc ack Timer"); + lim_deactivate_and_change_timer(mac, + eLIM_DISASSOC_ACK_TIMER); + return; + } + } else { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, + pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + wlan_connectivity_mgmt_event(mac->psoc, + (struct wlan_frame_hdr *)pMacHdr, + pe_session->vdev_id, nReason, + QDF_TX_RX_STATUS_OK, + mac->lim.bss_rssi, 0, 0, 0, 0, + WLAN_DISASSOC_TX); + + lim_cp_stats_cstats_log_disassoc_evt(pe_session, CSTATS_DIR_TX, + nReason); + + /* Queue Disassociation frame in high priority WQ */ + qdf_status = wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, + lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send Disassociation (%X)!", + qdf_status); + /* Pkt will be freed up by the callback */ + } + } +} /* End lim_send_disassoc_mgmt_frame. */ + +/** + * \brief This function is called to send a Deauthenticate frame + * + * + * \param mac Pointer to global MAC structure + * + * \param nReason Indicates the reason that need to be sent in the + * Deauthenticate frame + * + * \param peer address of the STA to which the frame is to be sent + * + * + */ + +void +lim_send_deauth_mgmt_frame(struct mac_context *mac, + uint16_t nReason, + tSirMacAddr peer, + struct pe_session *pe_session, bool waitForAck) +{ + tDot11fDeAuth frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint32_t val = 0; +#ifdef FEATURE_WLAN_TDLS + uint16_t aid; + tpDphHashNode sta; +#endif + uint8_t smeSessionId = 0; + struct element_info *discon_ie; + bool drop_deauth = false; + + if (!pe_session) { + return; + } + + /* + * Avoid sending deauth frame out when + * 1. CAC timer is running for this SAP session, + * It is avoid violation of dfs specification. + * 2. Silent deauth is requested for a particular peer + */ + if ((pe_session->opmode == QDF_SAP_MODE) || + (pe_session->opmode == QDF_P2P_GO_MODE)) { + if (mac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + pe_info("CAC timer is running, drop the deauth from going out"); + drop_deauth = true; + } + if (nReason == REASON_HOST_TRIGGERED_SILENT_DEAUTH) { + pe_info("Silent deauth, remove the peer"); + drop_deauth = true; + } + if (drop_deauth) { + if (waitForAck) + lim_send_deauth_cnf(mac, pe_session->vdev_id); + return; + } + } else if (lim_is_ml_peer_state_disconn(mac, pe_session, peer)) { + /** + * Check if deauth is already sent on link vdev and ML peer + * state is moved to ML_PEER_DISCONN_INITIATED. In which case, + * do not send deauth on assoc vdev as well. Issue deauth only + * if this check fails. + */ + pe_debug("Deauth tx not required for vdev id %d", + pe_session->vdev_id); + lim_send_deauth_cnf(mac, pe_session->vdev_id); + return; + } + smeSessionId = pe_session->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Reason.code = nReason; + + nStatus = dot11f_get_packed_de_auth_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a De-Authentication (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fDeAuth); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a De-Authentication (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + discon_ie = mlme_get_self_disconnect_ies(pe_session->vdev); + if (discon_ie && discon_ie->len) + nBytes += discon_ie->len; + + qdf_status = cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a De-Authentication", + nBytes); + if (waitForAck) + lim_send_deauth_cnf(mac, pe_session->vdev_id); + return; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_DEAUTH, peer, pe_session->self_mac_addr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + /* Prepare the BSSID */ + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + nStatus = dot11f_pack_de_auth(mac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a DeAuthentication (0x%08x)", + nStatus); + cds_packet_free((void *)pPacket); + if (waitForAck) + lim_send_deauth_cnf(mac, pe_session->vdev_id); + return; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a De-Authentication (0x%08x)", + nStatus); + } + + /* Copy disconnect IEs to the end of the frame */ + lim_append_ies_to_frame(pFrame + sizeof(tSirMacMgmtHdr) + nPayload, + &nPayload, discon_ie); + mlme_free_self_disconnect_ies(pe_session->vdev); + + pe_nofl_rl_info("Deauth TX: vdev %d seq_num %d reason %u waitForAck %d to " QDF_MAC_ADDR_FMT " from " QDF_MAC_ADDR_FMT, + pe_session->vdev_id, mac->mgmtSeqNum, nReason, waitForAck, + QDF_MAC_ADDR_REF(pMacHdr->da), + QDF_MAC_ADDR_REF(pe_session->self_mac_addr)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + txFlag |= HAL_USE_PEER_STA_REQUESTED_MASK; +#ifdef FEATURE_WLAN_TDLS + sta = + dph_lookup_hash_entry(mac, peer, &aid, + &pe_session->dph.dphHashTable); +#endif + + pe_session->deauth_disassoc_rc = nReason; + if (waitForAck) { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, + pMacHdr->fc.subType)); + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); + if (pe_session->opmode == QDF_STA_MODE && + mac->mlme_cfg->sta.deauth_retry_cnt && + !pe_session->deauth_retry.retry_cnt) { + pe_session->deauth_retry.retry_cnt = + mac->mlme_cfg->sta.deauth_retry_cnt; + pe_session->deauth_retry.reason_code = nReason; + qdf_mem_copy(pe_session->deauth_retry.peer_macaddr.bytes, + peer, QDF_MAC_ADDR_SIZE); + } + + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frameWithTxComplete(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, lim_tx_complete, + pFrame, lim_deauth_tx_complete_cnf_handler, + txFlag, smeSessionId, false, 0, + RATEID_DEFAULT, 0, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + /* Pkt will be freed up by the callback lim_tx_complete */ + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send De-Authentication (%X)!", + qdf_status); + + /* Call lim_process_deauth_ack_timeout which will send + * DeauthCnf for this frame + */ + lim_process_deauth_ack_timeout(mac, + pe_session->peSessionId); + return; + } + + val = SYS_MS_TO_TICKS(LIM_DISASSOC_DEAUTH_ACK_TIMEOUT); + if (tx_timer_change_context( + &mac->lim.lim_timers.gLimDeauthAckTimer, + pe_session->vdev_id) != TX_SUCCESS) { + pe_err("Unable to update the vdev id in the Deauth ack timer"); + return; + } else if (tx_timer_change + (&mac->lim.lim_timers.gLimDeauthAckTimer, val, 0) + != TX_SUCCESS) { + pe_err("Unable to change Deauth ack Timer val"); + return; + } else if (TX_SUCCESS != + tx_timer_activate(&mac->lim.lim_timers. + gLimDeauthAckTimer)) { + pe_err("Unable to activate Deauth ack Timer"); + lim_deactivate_and_change_timer(mac, + eLIM_DEAUTH_ACK_TIMER); + return; + } + } else { + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, + pMacHdr->fc.subType)); +#ifdef FEATURE_WLAN_TDLS + if ((sta) + && (STA_ENTRY_TDLS_PEER == sta->staType)) { + /* Queue Disassociation frame in high priority WQ */ + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, + QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + qdf_status = + wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_IBSS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + } else { +#endif + lim_diag_mgmt_tx_event_report(mac, pMacHdr, + pe_session, + QDF_STATUS_SUCCESS, + QDF_STATUS_SUCCESS); + + wlan_connectivity_mgmt_event(mac->psoc, + (struct wlan_frame_hdr *)pMacHdr, + pe_session->vdev_id, nReason, + QDF_TX_RX_STATUS_OK, + mac->lim.bss_rssi, 0, 0, 0, 0, + WLAN_DEAUTH_TX); + + lim_cp_stats_cstats_log_deauth_evt(pe_session, CSTATS_DIR_TX, + nReason); + + /* Queue Disassociation frame in high priority WQ */ + qdf_status = + wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); +#ifdef FEATURE_WLAN_TDLS + } +#endif + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send De-Authentication (%X)!", + qdf_status); + /* Pkt will be freed up by the callback */ + } + } + +} /* End lim_send_deauth_mgmt_frame. */ + +#ifdef ANI_SUPPORT_11H +/** + * \brief Send a Measurement Report Action frame + * + * + * \param mac Pointer to the global MAC structure + * + * \param pMeasReqFrame Address of a tSirMacMeasReqActionFrame + * + * \return QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE else + * + * + */ + +QDF_STATUS +lim_send_meas_report_frame(struct mac_context *mac, + tpSirMacMeasReqActionFrame pMeasReqFrame, + tSirMacAddr peer, struct pe_session *pe_session) +{ + tDot11fMeasurementReport frm; + uint8_t *pFrame; + QDF_STATUS nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_SPECTRUM_MGMT; + frm.Action.action = ACTION_SPCT_MSR_RPRT; + frm.DialogToken.token = pMeasReqFrame->actionHeader.dialogToken; + + switch (pMeasReqFrame->measReqIE.measType) { + case SIR_MAC_BASIC_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report0(mac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_CCA_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report1(mac, pMeasReqFrame, + &frm.MeasurementReport); + break; + case SIR_MAC_RPI_MEASUREMENT_TYPE: + nSirStatus = + populate_dot11f_measurement_report2(mac, pMeasReqFrame, + &frm.MeasurementReport); + break; + default: + pe_err("Unknown measurement type %d in limSendMeasReportFrame", + pMeasReqFrame->measReqIE.measType); + return QDF_STATUS_E_FAILURE; + } + + if (QDF_STATUS_SUCCESS != nSirStatus) + return QDF_STATUS_E_FAILURE; + + nStatus = dot11f_get_packed_measurement_report_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Measurement Report (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fMeasurementReport); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Measurement Report (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc(mac->hdd_handle, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a De-Authentication", + nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, pe_session->bssId, sizeof(tSirMacAddr)); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + nStatus = dot11f_pack_measurement_report(mac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Measurement Report (0x%08x)", + nStatus); + cds_packet_free(mac->hdd_handle, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return QDF_STATUS_E_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a Measurement Report (0x%08x)", + nStatus); + } + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((pe_session) ? pe_session-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((pe_session) ? pe_session->peSessionId : NO_SESSION), + qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send a Measurement Report (%X)!", + qdf_status); + /* Pkt will be freed up by the callback */ + return QDF_STATUS_E_FAILURE; /* just allocated... */ + } + + return QDF_STATUS_SUCCESS; + +} /* End lim_send_meas_report_frame. */ + +/** + * \brief Send a TPC Report Action frame + * + * + * \param mac Pointer to the global MAC datastructure + * + * \param pTpcReqFrame Pointer to the received TPC Request + * + * \return QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE else + * + * + */ + +QDF_STATUS +lim_send_tpc_report_frame(struct mac_context *mac, + tpSirMacTpcReqActionFrame pTpcReqFrame, + tSirMacAddr peer, struct pe_session *pe_session) +{ + tDot11fTPCReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + struct vdev_mlme_obj *mlme_obj; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_SPECTRUM_MGMT; + frm.Action.action = ACTION_SPCT_TPC_RPRT; + frm.DialogToken.token = pTpcReqFrame->actionHeader.dialogToken; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (mlme_obj) + frm.TPCReport.tx_power = mlme_obj->mgmt.generic.tx_pwrlimit; + + frm.TPCReport.link_margin = 0; + frm.TPCReport.present = 1; + + nStatus = dot11f_get_packed_tpc_report_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a TPC Report (0x%08x)", nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fTPCReport); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a TPC Report (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc(mac->hdd_handle, TXRX_FRM_802_11_MGMT, + (uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TPC" + " Report", nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer); + + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + qdf_mem_copy(pMacHdr->bssId, pe_session->bssId, sizeof(tSirMacAddr)); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + nStatus = dot11f_pack_tpc_report(mac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a TPC Report (0x%08x)", + nStatus); + cds_packet_free(mac->hdd_handle, TXRX_FRM_802_11_MGMT, + (void *)pFrame, (void *)pPacket); + return QDF_STATUS_E_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a TPC Report (0x%08x)", + nStatus); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + ((pe_session) ? pe_session-> + peSessionId : NO_SESSION), pMacHdr->fc.subType)); + qdf_status = + wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, pFrame, 0, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace + (QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + ((pe_session) ? pe_session->peSessionId : NO_SESSION), + qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send a TPC Report (%X)!", + qdf_status); + /* Pkt will be freed up by the callback */ + return QDF_STATUS_E_FAILURE; /* just allocated... */ + } + + return QDF_STATUS_SUCCESS; + +} /* End lim_send_tpc_report_frame. */ +#endif /* ANI_SUPPORT_11H */ + +/** + * \brief Send a Channel Switch Announcement + * + * + * \param mac Pointer to the global MAC datastructure + * + * \param peer MAC address to which this frame will be sent + * + * \param nMode + * + * \param nNewChannel + * + * \param nCount + * + * \return QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE else + * + * + */ + +QDF_STATUS +lim_send_channel_switch_mgmt_frame(struct mac_context *mac, + tSirMacAddr peer, + uint8_t nMode, + uint8_t nNewChannel, + uint8_t nCount, struct pe_session *pe_session) +{ + tDot11fChannelSwitch frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; /* , nCfg; */ + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + + uint8_t smeSessionId = 0; + + if (!pe_session) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = pe_session->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_SPECTRUM_MGMT; + frm.Action.action = ACTION_SPCT_CHL_SWITCH; + frm.ChanSwitchAnn.switchMode = nMode; + frm.ChanSwitchAnn.newChannel = nNewChannel; + frm.ChanSwitchAnn.switchCount = nCount; + frm.ChanSwitchAnn.present = 1; + + nStatus = dot11f_get_packed_channel_switch_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Channel Switch (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fChannelSwitch); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Channel Switch (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a TPC Report", nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, + pe_session->self_mac_addr); + pMacHdr = (tpSirMacMgmtHdr) pFrame; + qdf_mem_copy((uint8_t *) pMacHdr->bssId, + (uint8_t *) pe_session->bssId, sizeof(tSirMacAddr)); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + nStatus = dot11f_pack_channel_switch(mac, &frm, pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Channel Switch (0x%08x)", + nStatus); + cds_packet_free((void *)pPacket); + return QDF_STATUS_E_FAILURE; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a Channel Switch (0x%08x)", + nStatus); + } + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(mac, pPacket, (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send a Channel Switch (%X)!", + qdf_status); + /* Pkt will be freed up by the callback */ + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; + +} /* End lim_send_channel_switch_mgmt_frame. */ + +/** + * lim_send_extended_chan_switch_action_frame()- function to send ECSA + * action frame over the air . + * @mac_ctx: pointer to global mac structure + * @peer: Destination mac. + * @mode: channel switch mode + * @new_op_class: new op class + * @new_channel: new channel to switch + * @count: channel switch count + * + * This function is called to send ECSA frame. + * + * Return: success if frame is sent else return failure + */ + +QDF_STATUS +lim_send_extended_chan_switch_action_frame(struct mac_context *mac_ctx, + tSirMacAddr peer, uint8_t mode, uint8_t new_op_class, + uint8_t new_channel, uint8_t count, struct pe_session *session_entry) +{ + tDot11fext_channel_switch_action_frame frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + uint32_t num_bytes, n_payload, status; + void *packet; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t vdev_id = 0; + uint8_t ch_spacing; + tLimWiderBWChannelSwitchInfo *wide_bw_ie; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + if (!session_entry) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = session_entry->smeSessionId; + + qdf_mem_zero(&frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_PUBLIC; + frm.Action.action = PUB_ACTION_EXT_CHANNEL_SWITCH_ID; + + frm.ext_chan_switch_ann_action.switch_mode = mode; + frm.ext_chan_switch_ann_action.op_class = new_op_class; + frm.ext_chan_switch_ann_action.new_channel = new_channel; + frm.ext_chan_switch_ann_action.switch_count = count; + + wlan_reg_read_current_country(mac_ctx->psoc, reg_cc); + ch_spacing = wlan_reg_dmn_get_chanwidth_from_opclass( + reg_cc, new_channel, new_op_class); + + if ((ch_spacing == 80) || (ch_spacing == 160)) { + wide_bw_ie = &session_entry->gLimWiderBWChannelSwitch; + frm.WiderBWChanSwitchAnn.newChanWidth = + wide_bw_ie->newChanWidth; + frm.WiderBWChanSwitchAnn.newCenterChanFreq0 = + wide_bw_ie->newCenterChanFreq0; + frm.WiderBWChanSwitchAnn.newCenterChanFreq1 = + wide_bw_ie->newCenterChanFreq1; + frm.WiderBWChanSwitchAnn.present = 1; + pe_debug("wrapper: width:%d f0:%d f1:%d", + frm.WiderBWChanSwitchAnn.newChanWidth, + frm.WiderBWChanSwitchAnn.newCenterChanFreq0, + frm.WiderBWChanSwitchAnn.newCenterChanFreq1); + } + + if (lim_is_session_eht_capable(session_entry)) + populate_dot11f_bw_ind_element(mac_ctx, session_entry, + &frm.bw_ind_element); + + status = dot11f_get_packed_ext_channel_switch_action_frame_size(mac_ctx, + &frm, &n_payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to get packed size for Channel Switch 0x%08x", + status); + /* We'll fall back on the worst case scenario*/ + n_payload = sizeof(tDot11fext_channel_switch_action_frame); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a Ext Channel Switch (0x%08x)", + status); + } + + num_bytes = n_payload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t)num_bytes, + (void **) &frame, (void **) &packet); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a Ext Channel Switch", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + + /* Paranoia*/ + qdf_mem_zero(frame, num_bytes); + + /* Next, we fill out the buffer descriptor */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, session_entry->self_mac_addr); + mac_hdr = (tpSirMacMgmtHdr) frame; + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session_entry->bssId, + sizeof(tSirMacAddr)); + + lim_set_protected_bit(mac_ctx, session_entry, peer, mac_hdr); + + status = dot11f_pack_ext_channel_switch_action_frame(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), n_payload, &n_payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a Channel Switch 0x%08x", status); + cds_packet_free((void *)packet); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing a Channel Switch 0x%08x", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session_entry->curr_op_freq) || + session_entry->opmode == QDF_P2P_CLIENT_MODE || + session_entry->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + pe_debug("ECSA frame to :"QDF_MAC_ADDR_FMT" count %d mode %d chan %d op class %d", + QDF_MAC_ADDR_REF(mac_hdr->da), + frm.ext_chan_switch_ann_action.switch_count, + frm.ext_chan_switch_ann_action.switch_mode, + frm.ext_chan_switch_ann_action.new_channel, + frm.ext_chan_switch_ann_action.op_class); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session_entry->peSessionId, mac_hdr->fc.subType)); + qdf_status = wma_tx_frame(mac_ctx, packet, (uint16_t) num_bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, + lim_tx_complete, frame, + txFlag, vdev_id, 0, + RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session_entry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send a Ext Channel Switch %X!", + qdf_status); + /* Pkt will be freed up by the callback */ + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} /* End lim_send_extended_chan_switch_action_frame */ + + +/** + * lim_oper_chan_change_confirm_tx_complete_cnf()- Confirmation for oper_chan_change_confirm + * sent over the air + * + * @context: pointer to global mac + * @buf: buffer + * @tx_complete : Sent status + * @params: tx completion params + * + * Return: This returns QDF_STATUS + */ + +static QDF_STATUS lim_oper_chan_change_confirm_tx_complete_cnf( + void *context, + qdf_nbuf_t buf, + uint32_t tx_complete, + void *params) +{ + pe_debug("tx_complete: %d", tx_complete); + if (buf) + qdf_nbuf_free(buf); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_p2p_oper_chan_change_confirm_action_frame()- function to send + * p2p oper chan change confirm action frame + * @mac_ctx: pointer to global mac structure + * @peer: Destination mac. + * @session_entry: session entry + * + * This function is called to send p2p oper chan change confirm action frame. + * + * Return: success if frame is sent else return failure + */ + +QDF_STATUS +lim_p2p_oper_chan_change_confirm_action_frame(struct mac_context *mac_ctx, + tSirMacAddr peer, struct pe_session *session_entry) +{ + tDot11fp2p_oper_chan_change_confirm frm; + uint8_t *frame; + tpSirMacMgmtHdr mac_hdr; + uint32_t num_bytes, n_payload, status; + void *packet; + QDF_STATUS qdf_status; + uint8_t tx_flag = 0; + uint8_t vdev_id = 0; + + if (!session_entry) { + pe_err("Session entry is NULL!!!"); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = session_entry->smeSessionId; + + qdf_mem_zero(&frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_VENDOR_SPECIFIC; + + qdf_mem_copy(frm.p2p_action_oui.oui_data, + SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + frm.p2p_action_subtype.subtype = 0x04; + frm.DialogToken.token = 0x0; + + if (session_entry->htCapability) { + pe_debug("Populate HT Caps in Assoc Request"); + populate_dot11f_ht_caps(mac_ctx, session_entry, &frm.HTCaps); + } + + if (session_entry->vhtCapability) { + pe_debug("Populate VHT Caps in Assoc Request"); + populate_dot11f_vht_caps(mac_ctx, session_entry, &frm.VHTCaps); + populate_dot11f_operating_mode(mac_ctx, + &frm.OperatingMode, session_entry); + } + + status = dot11f_get_packed_p2p_oper_chan_change_confirmSize(mac_ctx, + &frm, &n_payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to get packed size 0x%08x", status); + /* We'll fall back on the worst case scenario*/ + n_payload = sizeof(tDot11fp2p_oper_chan_change_confirm); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size (0x%08x)", + status); + } + + num_bytes = n_payload + sizeof(tSirMacMgmtHdr); + + qdf_status = cds_packet_alloc((uint16_t)num_bytes, + (void **) &frame, (void **) &packet); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes", num_bytes); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(frame, num_bytes); + + /* Next, fill out the buffer descriptor */ + lim_populate_mac_header(mac_ctx, frame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, session_entry->self_mac_addr); + mac_hdr = (tpSirMacMgmtHdr) frame; + qdf_mem_copy((uint8_t *) mac_hdr->bssId, + (uint8_t *) session_entry->bssId, + sizeof(tSirMacAddr)); + + status = dot11f_pack_p2p_oper_chan_change_confirm(mac_ctx, &frm, + frame + sizeof(tSirMacMgmtHdr), n_payload, &n_payload); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack 0x%08x", status); + cds_packet_free((void *)packet); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing 0x%08x", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session_entry->curr_op_freq) || + session_entry->opmode == QDF_P2P_CLIENT_MODE || + session_entry->opmode == QDF_P2P_GO_MODE) { + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + } + pe_debug("Send frame on channel freq %d to mac " + QDF_MAC_ADDR_FMT, session_entry->curr_op_freq, + QDF_MAC_ADDR_REF(peer)); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session_entry->peSessionId, mac_hdr->fc.subType)); + + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, + lim_oper_chan_change_confirm_tx_complete_cnf, + tx_flag, vdev_id, false, 0, RATEID_DEFAULT, 0, 0); + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session_entry->peSessionId, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to send status %X!", qdf_status); + /* Pkt will be freed up by the callback */ + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + + +/** + * \brief Send a Neighbor Report Request Action frame + * + * + * \param mac Pointer to the global MAC structure + * + * \param pNeighborReq Address of a tSirMacNeighborReportReq + * + * \param peer mac address of peer station. + * + * \param pe_session address of session entry. + * + * \return QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE else + * + * + */ + +QDF_STATUS +lim_send_neighbor_report_request_frame(struct mac_context *mac, + tpSirMacNeighborReportReq pNeighborReq, + tSirMacAddr peer, struct pe_session *pe_session) +{ + QDF_STATUS status_code = QDF_STATUS_SUCCESS; + tDot11fNeighborReportRequest frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + if (!pe_session) { + pe_err("(!psession) in Request to send Neighbor Report request action frame"); + return QDF_STATUS_E_FAILURE; + } + smeSessionId = pe_session->smeSessionId; + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_RRM; + frm.Action.action = RRM_NEIGHBOR_REQ; + frm.DialogToken.token = pNeighborReq->dialogToken; + + if (pNeighborReq->ssid_present) { + populate_dot11f_ssid(mac, &pNeighborReq->ssid, &frm.SSID); + } + + nStatus = + dot11f_get_packed_neighbor_report_request_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Neighbor Report Request(0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fNeighborReportRequest); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Neighbor Report Request(0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a Neighbor " + "Report Request", nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Copy necessary info to BD */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, pe_session->self_mac_addr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_neighbor_report_request(mac, + &frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack an Neighbor Report Request (0x%08x)", + nStatus); + + /* FIXME - Need to convert to QDF_STATUS */ + status_code = QDF_STATUS_E_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing Neighbor Report Request (0x%08x)", + nStatus); + } + + pe_debug("Sending a Neighbor Report Request to "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(mac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + status_code = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + return status_code; + } else + return QDF_STATUS_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return status_code; +} /* End lim_send_neighbor_report_request_frame. */ + +QDF_STATUS +lim_send_link_report_action_frame(struct mac_context *mac, + tpSirMacLinkReport pLinkReport, + tSirMacAddr peer, struct pe_session *pe_session) +{ + QDF_STATUS status_code = QDF_STATUS_SUCCESS; + tDot11fLinkMeasurementReport frm; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t vdev_id = 0; + + if (!pe_session) { + pe_err("RRM: Send link report: NULL PE session"); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = pe_session->vdev_id; + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + + frm.Category.category = ACTION_CATEGORY_RRM; + frm.Action.action = RRM_LINK_MEASUREMENT_RPT; + frm.DialogToken.token = pLinkReport->dialogToken; + + /* IEEE Std. 802.11 7.3.2.18. for the report element. */ + /* Even though TPC report an IE, it is represented using fixed fields since it is positioned */ + /* in the middle of other fixed fields in the link report frame(IEEE Std. 802.11k section7.4.6.4 */ + /* and frame parser always expects IEs to come after all fixed fields. It is easier to handle */ + /* such case this way than changing the frame parser. */ + frm.TPCEleID.TPCId = WLAN_ELEMID_TPCREP; + frm.TPCEleLen.TPCLen = 2; + frm.TxPower.txPower = pLinkReport->txPower; + frm.LinkMargin.linkMargin = 0; + + frm.RxAntennaId.antennaId = pLinkReport->rxAntenna; + frm.TxAntennaId.antennaId = pLinkReport->txAntenna; + frm.RCPI.rcpi = pLinkReport->rcpi; + frm.RSNI.rsni = pLinkReport->rsni; + + nStatus = + dot11f_get_packed_link_measurement_report_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Link Report (0x%08x)", nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fLinkMeasurementReport); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for a Link Report (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a Link " + "Report", nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Copy necessary info to BD */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, pe_session->self_mac_addr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_link_measurement_report(mac, + &frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack an Link Report (0x%08x)", nStatus); + + /* FIXME - Need to convert to QDF_STATUS */ + status_code = QDF_STATUS_E_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing Link Report (0x%08x)", + nStatus); + } + + pe_warn_rl("RRM: Sending Link Report to "QDF_MAC_ADDR_FMT" on vdev[%d]", + QDF_MAC_ADDR_REF(peer), vdev_id); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(mac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + vdev_id, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err_rl("wma_tx_frame FAILED! Status [%d]", qdf_status); + status_code = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + return status_code; + } else + return QDF_STATUS_SUCCESS; + +returnAfterError: + cds_packet_free((void *)pPacket); + + return status_code; +} /* End lim_send_link_report_action_frame. */ + +#ifdef CONNECTIVITY_DIAG_EVENT +/** + * lim_beacon_report_response_event() - Send Beacon Report Response log + * event + * @token: Dialog token + * @num_rpt: Number of Report element + * @pe_session: pe session pointer + */ +static void +lim_beacon_report_response_event(uint8_t token, uint8_t num_rpt, + struct pe_session *pe_session) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_bcn_rpt); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + wlan_diag_event.diag_cmn.vdev_id = wlan_vdev_get_id(pe_session->vdev); + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + + wlan_diag_event.version = DIAG_BCN_RPT_VERSION_2; + wlan_diag_event.subtype = WLAN_CONN_DIAG_BCN_RPT_RESP_EVENT; + wlan_diag_event.meas_token = token; + wlan_diag_event.num_rpt = num_rpt; + + if (mlo_is_mld_sta(pe_session->vdev)) + wlan_diag_event.band = + wlan_convert_freq_to_diag_band(pe_session->curr_op_freq); + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BCN_RPT); +} +#else +static void +lim_beacon_report_response_event(uint8_t token, uint8_t num_rpt, + struct pe_session *pe_session) +{ +} +#endif + +QDF_STATUS +lim_send_radio_measure_report_action_frame(struct mac_context *mac, + uint8_t dialog_token, + uint8_t num_report, + bool is_last_frame, + tpSirMacRadioMeasureReport pRRMReport, + tSirMacAddr peer, + struct pe_session *pe_session) +{ + QDF_STATUS status_code = QDF_STATUS_SUCCESS; + uint8_t *pFrame; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t i; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + bool is_last_report = false; + + /* Malloc size of (tDot11fIEMeasurementReport) * (num_report - 1) + * as memory for one Dot11fIEMeasurementReport is already calculated. + */ + tDot11fRadioMeasurementReport *frm = + qdf_mem_malloc(sizeof(tDot11fRadioMeasurementReport) + + (sizeof(tDot11fIEMeasurementReport) * (num_report - 1))); + if (!frm) + return QDF_STATUS_E_NOMEM; + + if (!pe_session) { + pe_err("session not found"); + qdf_mem_free(frm); + return QDF_STATUS_E_FAILURE; + } + + smeSessionId = pe_session->smeSessionId; + + frm->Category.category = ACTION_CATEGORY_RRM; + frm->Action.action = RRM_RADIO_MEASURE_RPT; + frm->DialogToken.token = dialog_token; + + frm->num_MeasurementReport = num_report; + + for (i = 0; i < frm->num_MeasurementReport; i++) { + frm->MeasurementReport[i].type = pRRMReport[i].type; + frm->MeasurementReport[i].token = pRRMReport[i].token; + frm->MeasurementReport[i].late = 0; /* IEEE 802.11k section 7.3.22. (always zero in rrm) */ + switch (pRRMReport[i].type) { + case SIR_MAC_RRM_BEACON_TYPE: + /* + * Last beacon report indication needs to be set to 1 + * only for the last report in the last frame + */ + if (is_last_frame && + (i == (frm->num_MeasurementReport - 1))) + is_last_report = true; + + populate_dot11f_beacon_report(mac, + &frm->MeasurementReport[i], + &pRRMReport[i].report. + beaconReport, + is_last_report); + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + case SIR_MAC_RRM_CHANNEL_LOAD_TYPE: + populate_dot11f_chan_load_report(mac, + &frm->MeasurementReport[i], + &pRRMReport[i].report.channel_load_report); + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + case SIR_MAC_RRM_STA_STATISTICS_TYPE: + populate_dot11f_rrm_sta_stats_report( + mac, &frm->MeasurementReport[i], + &pRRMReport[i].report.statistics_report); + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + default: + frm->MeasurementReport[i].incapable = + pRRMReport[i].incapable; + frm->MeasurementReport[i].refused = + pRRMReport[i].refused; + frm->MeasurementReport[i].present = 1; + break; + } + } + + + nStatus = + dot11f_get_packed_radio_measurement_report_size(mac, frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_nofl_err("TX: [802.11 RRM] Failed to get packed size for RM Report (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fLinkMeasurementReport); + qdf_mem_free(frm); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("Warnings while calculating the size for Radio Measure Report (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + + qdf_status = + cds_packet_alloc((uint16_t) nBytes, (void **)&pFrame, + (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_nofl_err("TX: [802.11 RRM] Allocation of %d bytes failed for RM" + "Report", nBytes); + qdf_mem_free(frm); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Copy necessary info to BD */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, pe_session->self_mac_addr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + /* Now, we're ready to "pack" the frames */ + nStatus = dot11f_pack_radio_measurement_report(mac, + frm, + pFrame + + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_nofl_err("Failed to pack an Radio Measure Report (0x%08x)", + nStatus); + + /* FIXME - Need to convert to QDF_STATUS */ + status_code = QDF_STATUS_E_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("Warnings while packing Radio Measure Report (0x%08x)", + nStatus); + } + + if (frm->MeasurementReport[0].type == SIR_MAC_RRM_BEACON_TYPE) { + lim_beacon_report_response_event(frm->MeasurementReport[0].token, + num_report, + pe_session); + } + + pe_nofl_rl_info("TX: type:%d seq_no:%d dialog_token:%d no. of APs:%d is_last_rpt:%d num_report:%d peer:"QDF_MAC_ADDR_FMT, + frm->MeasurementReport[0].type, + (pMacHdr->seqControl.seqNumHi << HIGH_SEQ_NUM_OFFSET | + pMacHdr->seqControl.seqNumLo), + dialog_token, frm->num_MeasurementReport, + is_last_report, num_report, QDF_MAC_ADDR_REF(peer)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(mac, pPacket, (uint16_t)nBytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_nofl_rl_err("TX: [802.11 RRM] Send FAILED! err_status [%d]", + qdf_status); + status_code = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + } + + qdf_mem_free(frm); + return status_code; + +returnAfterError: + qdf_mem_free(frm); + cds_packet_free((void *)pPacket); + return status_code; +} + +bool +lim_is_self_and_peer_ocv_capable(struct mac_context *mac, + uint8_t *peer, + struct pe_session *pe_session) +{ + uint16_t self_rsn_cap, aid; + tpDphHashNode sta_ds; + + self_rsn_cap = wlan_crypto_get_param(pe_session->vdev, + WLAN_CRYPTO_PARAM_RSN_CAP); + if (!(self_rsn_cap & WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED)) + return false; + + sta_ds = dph_lookup_hash_entry(mac, peer, &aid, + &pe_session->dph.dphHashTable); + + if (sta_ds && sta_ds->ocv_enabled) + return true; + + return false; +} + +void +lim_fill_oci_params(struct mac_context *mac, struct pe_session *session, + tDot11fIEoci *oci, uint8_t *peer, uint16_t *tx_chan_width) +{ + tpDphHashNode sta_ds; + uint16_t aid; + uint8_t ch_offset; + uint8_t prim_ch_num = wlan_reg_freq_to_chan(mac->pdev, + session->curr_op_freq); + if (session->ch_width == CH_WIDTH_80MHZ) { + ch_offset = BW80; + } else { + switch (session->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_offset = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_offset = BW40_LOW_PRIMARY; + break; + default: + ch_offset = BW20; + break; + } + } + oci->op_class = lim_op_class_from_bandwidth(mac, + session->curr_op_freq, + session->ch_width, + ch_offset); + oci->prim_ch_num = prim_ch_num; + oci->freq_seg_1_ch_num = session->ch_center_freq_seg1; + oci->present = 1; + if (tx_chan_width) + *tx_chan_width = ch_width_in_mhz(session->ch_width); + if (LIM_IS_STA_ROLE(session)) + return; + + if (!peer || !tx_chan_width) + return; + + sta_ds = dph_lookup_hash_entry(mac, peer, &aid, + &session->dph.dphHashTable); + if (!sta_ds) { + pe_nofl_debug("no find sta ds "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer)); + return; + } + if (WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq)) { + if (*tx_chan_width > 20 && + !sta_ds->htSupportedChannelWidthSet) { + *tx_chan_width = 20; + pe_nofl_debug("peer no support ht40 in 2g, %d :"QDF_MAC_ADDR_FMT, + sta_ds->ch_width, + QDF_MAC_ADDR_REF(peer)); + } + } +} + +/** + * \brief Send SA query request action frame to peer + * + * \sa lim_send_sa_query_request_frame + * + * + * \param mac The global struct mac_context *object + * + * \param transId Transaction identifier + * + * \param peer The Mac address of the station to which this action frame is addressed + * + * \param pe_session The PE session entry + * + * \return QDF_STATUS_SUCCESS if setup completes successfully + * QDF_STATUS_E_FAILURE is some problem is encountered + */ + +QDF_STATUS lim_send_sa_query_request_frame(struct mac_context *mac, uint8_t *transId, + tSirMacAddr peer, + struct pe_session *pe_session) +{ + + tDot11fSaQueryReq frm; /* SA query request action frame */ + uint8_t *pFrame; + QDF_STATUS nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + frm.Category.category = ACTION_CATEGORY_SA_QUERY; + /* 11w action field is : + action: 0 --> SA Query Request action frame + action: 1 --> SA Query Response action frame */ + frm.Action.action = SA_QUERY_REQUEST; + /* 11w SA Query Request transId */ + qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + + if (lim_is_self_and_peer_ocv_capable(mac, peer, pe_session)) + lim_fill_oci_params(mac, pe_session, &frm.oci, NULL, NULL); + + nStatus = dot11f_get_packed_sa_query_req_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for an SA Query Request (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fSaQueryReq); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for an SA Query Request (0x%08x)", + nStatus); + } + + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + qdf_status = + cds_packet_alloc(nBytes, (void **)&pFrame, (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a SA Query Request " + "action frame", nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Copy necessary info to BD */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, pe_session->self_mac_addr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + /* Since this is a SA Query Request, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + /* Pack 11w SA Query Request frame */ + nStatus = dot11f_pack_sa_query_req(mac, + &frm, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack an SA Query Request (0x%08x)", + nStatus); + /* FIXME - Need to convert to QDF_STATUS */ + nSirStatus = QDF_STATUS_E_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing SA Query Request (0x%08x)", + nStatus); + } + + pe_debug("Sending an SA Query Request from "QDF_MAC_ADDR_FMT" to "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pe_session->self_mac_addr), + QDF_MAC_ADDR_REF(peer)); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + smeSessionId = pe_session->smeSessionId; + + qdf_status = wma_tx_frame(mac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + nSirStatus = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + return nSirStatus; + } else { + return QDF_STATUS_SUCCESS; + } + +returnAfterError: + cds_packet_free((void *)pPacket); + + return nSirStatus; +} /* End lim_send_sa_query_request_frame */ + +/** + * lim_send_sa_query_response_frame() - Send SA query response action frame to + * peer + * @mac: The global struct mac_context *object + * @transId: Transaction identifier received in SA query request action frame + * @peer: The Mac address of the AP to which this action frame is addressed + * @pe_session: The PE session entry + * + * Return: QDF_STATUS_SUCCESS if setup completes successfully + * QDF_STATUS_E_FAILURE is some problem is encountered + */ +QDF_STATUS lim_send_sa_query_response_frame(struct mac_context *mac, + uint8_t *transId, tSirMacAddr peer, + struct pe_session *pe_session) +{ + + tDot11fSaQueryRsp frm; /* SA query response action frame */ + uint8_t *pFrame; + QDF_STATUS nSirStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t nBytes, nPayload, nStatus; + void *pPacket; + QDF_STATUS qdf_status; + uint8_t txFlag = 0; + uint8_t smeSessionId = 0; + + smeSessionId = pe_session->smeSessionId; + + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + frm.Category.category = ACTION_CATEGORY_SA_QUERY; + /*11w action field is : + action: 0 --> SA query request action frame + action: 1 --> SA query response action frame */ + frm.Action.action = SA_QUERY_RESPONSE; + /*11w SA query response transId is same as + SA query request transId */ + qdf_mem_copy(&frm.TransactionId.transId[0], &transId[0], 2); + if (lim_is_self_and_peer_ocv_capable(mac, peer, pe_session)) + lim_fill_oci_params(mac, pe_session, &frm.oci, NULL, NULL); + + nStatus = dot11f_get_packed_sa_query_rsp_size(mac, &frm, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a SA Query Response (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fSaQueryRsp); + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while calculating the packed size for an SA Query Response (0x%08x)", + nStatus); + } + nBytes = nPayload + sizeof(tSirMacMgmtHdr); + qdf_status = + cds_packet_alloc(nBytes, (void **)&pFrame, (void **)&pPacket); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Failed to allocate %d bytes for a SA query response" + " action frame", nBytes); + return QDF_STATUS_E_FAILURE; + } + /* Paranoia: */ + qdf_mem_zero(pFrame, nBytes); + + /* Copy necessary info to BD */ + lim_populate_mac_header(mac, pFrame, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer, pe_session->self_mac_addr); + + /* Update A3 with the BSSID */ + pMacHdr = (tpSirMacMgmtHdr) pFrame; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + /* Since this is a SA Query Response, set the "protect" (aka WEP) bit */ + /* in the FC */ + lim_set_protected_bit(mac, pe_session, peer, pMacHdr); + + /* Pack 11w SA query response frame */ + nStatus = dot11f_pack_sa_query_rsp(mac, + &frm, + pFrame + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack an SA Query Response (0x%08x)", + nStatus); + /* FIXME - Need to convert to QDF_STATUS */ + nSirStatus = QDF_STATUS_E_FAILURE; + goto returnAfterError; + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing SA Query Response (0x%08x)", + nStatus); + } + + pe_debug("Sending SA Query Response to "QDF_MAC_ADDR_FMT" op_class %d prim_ch_num %d freq_seg_1_ch_num %d oci_present %d", + QDF_MAC_ADDR_REF(peer), frm.oci.op_class, + frm.oci.prim_ch_num, frm.oci.freq_seg_1_ch_num, + frm.oci.present); + + if (!wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq) || + pe_session->opmode == QDF_P2P_CLIENT_MODE || + pe_session->opmode == QDF_P2P_GO_MODE) + txFlag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + pe_session->peSessionId, pMacHdr->fc.subType)); + qdf_status = wma_tx_frame(mac, + pPacket, + (uint16_t) nBytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, + 7, lim_tx_complete, pFrame, txFlag, + smeSessionId, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + pe_session->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + nSirStatus = QDF_STATUS_E_FAILURE; + /* Pkt will be freed up by the callback */ + return nSirStatus; + } else { + return QDF_STATUS_SUCCESS; + } + +returnAfterError: + cds_packet_free((void *)pPacket); + return nSirStatus; +} /* End lim_send_sa_query_response_frame */ + +#if defined(CONFIG_LITHIUM) || defined(CONFIG_BERYLLIUM) +#ifdef WLAN_FEATURE_11AX +#define IS_PE_SESSION_HE_MODE(_session) ((_session)->he_capable) +#else +#define IS_PE_SESSION_HE_MODE(_session) false +#endif /* WLAN_FEATURE_11AX */ +#else +#define IS_PE_SESSION_HE_MODE(_session) false +#endif + +#ifdef FEATURE_WLAN_TDLS +static bool lim_tdls_peer_support_he(tpDphHashNode sta_ds) +{ + bool peer_he_cap = false; + + if (sta_ds) { + peer_he_cap = lim_is_sta_he_capable(sta_ds); + if (sta_ds->staType == STA_ENTRY_TDLS_PEER && peer_he_cap) + return true; + else + return false; + } else { + return false; + } +} +#else +static inline +bool lim_tdls_peer_support_he(tpDphHashNode sta_ds) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static +void lim_prepare_tdls_with_mlo(struct pe_session *session, + tSirMacAddr peer_mac, tSirMacAddr self_mac, + uint16_t *action) +{ + uint8_t *mld_addr; + + if (!sir_compare_mac_addr(session->bssId, peer_mac) && + wlan_mlo_get_tdls_link_vdev(session->vdev)) { + mld_addr = wlan_vdev_mlme_get_mldaddr(session->vdev); + sir_copy_mac_addr(self_mac, mld_addr); + *action = ACTION_CATEGORY_BACK << 8 | ADDBA_RESPONSE; + } else { + sir_copy_mac_addr(self_mac, session->self_mac_addr); + *action = 0; + } +} +#else +static +void lim_prepare_tdls_with_mlo(struct pe_session *session, + tSirMacAddr peer_mac, tSirMacAddr self_mac, + uint16_t *action) +{ + sir_copy_mac_addr(self_mac, session->self_mac_addr); + *action = 0; +} +#endif + +QDF_STATUS lim_send_addba_response_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_mac, uint16_t tid, + struct pe_session *session, + uint8_t addba_extn_present, + uint8_t amsdu_support, uint8_t is_wep, + uint16_t calc_buff_size, + tSirMacAddr bssid) +{ + + tDot11faddba_rsp frm; + uint8_t *frame_ptr; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size, status; + void *pkt_ptr = NULL; + QDF_STATUS qdf_status; + uint8_t tx_flag = 0; + uint8_t vdev_id = 0; + uint16_t buff_size, status_code, batimeout; + uint16_t frm_buff_size = 0; + uint8_t dialog_token; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t he_frag = 0; + tpDphHashNode sta_ds = NULL; + uint16_t aid; + bool he_cap = false; + bool eht_cap = false; + struct wlan_mlme_qos *qos_aggr; + tSirMacAddr self_mac; + uint16_t action; + + vdev_id = session->vdev_id; + + cdp_addba_responsesetup(soc, peer_mac, vdev_id, tid, + &dialog_token, &status_code, &buff_size, + &batimeout); + + qos_aggr = &mac_ctx->mlme_cfg->qos_mlme_params; + qdf_mem_zero((uint8_t *) &frm, sizeof(frm)); + frm.Category.category = ACTION_CATEGORY_BACK; + frm.Action.action = ADDBA_RESPONSE; + + frm.DialogToken.token = dialog_token; + frm.Status.status = status_code; + + sta_ds = dph_lookup_hash_entry(mac_ctx, peer_mac, &aid, + &session->dph.dphHashTable); + + if (sta_ds && lim_is_session_he_capable(session)) + he_cap = lim_is_sta_he_capable(sta_ds); + + if (sta_ds && lim_is_session_eht_capable(session)) + eht_cap = lim_is_sta_eht_capable(sta_ds); + + if ((LIM_IS_STA_ROLE(session) && qos_aggr->rx_aggregation_size == 1 && + !mac_ctx->usr_cfg_ba_buff_size) || mac_ctx->reject_addba_req) { + frm.Status.status = STATUS_REQUEST_DECLINED; + pe_err("refused addba req for rx_aggregation_size: %d mac_ctx->reject_addba_req: %d", + qos_aggr->rx_aggregation_size, mac_ctx->reject_addba_req); + } else if (LIM_IS_STA_ROLE(session) && !mac_ctx->usr_cfg_ba_buff_size) { + frm_buff_size = + QDF_MIN(qos_aggr->rx_aggregation_size, calc_buff_size); + pe_debug("rx_aggregation_size %d, calc_buff_size %d", + qos_aggr->rx_aggregation_size, calc_buff_size); + + if (eht_cap) { + if (frm_buff_size > MAX_EHT_BA_BUFF_SIZE) + frm_buff_size = MAX_EHT_BA_BUFF_SIZE; + } else { + if (frm_buff_size > MAX_BA_BUFF_SIZE) + frm_buff_size = MAX_BA_BUFF_SIZE; + } + } else { + if (sta_ds && sta_ds->staType == STA_ENTRY_NDI_PEER) + frm_buff_size = calc_buff_size; + else if (eht_cap) + frm_buff_size = MAX_EHT_BA_BUFF_SIZE; + else if (he_cap) + frm_buff_size = MAX_BA_BUFF_SIZE; + else + frm_buff_size = SIR_MAC_BA_DEFAULT_BUFF_SIZE; + + if (mac_ctx->usr_cfg_ba_buff_size) + frm_buff_size = mac_ctx->usr_cfg_ba_buff_size; + + if (eht_cap) { + if (frm_buff_size > MAX_EHT_BA_BUFF_SIZE) + frm_buff_size = MAX_EHT_BA_BUFF_SIZE; + } else { + if (frm_buff_size > MAX_BA_BUFF_SIZE) + frm_buff_size = MAX_BA_BUFF_SIZE; + } + + if (frm_buff_size > SIR_MAC_BA_DEFAULT_BUFF_SIZE) { + if (session->active_ba_64_session) { + frm_buff_size = SIR_MAC_BA_DEFAULT_BUFF_SIZE; + } + } else if (!session->active_ba_64_session) { + session->active_ba_64_session = true; + } + if (buff_size && frm_buff_size > buff_size) { + pe_debug("buff size: %d larger than peer's capability: %d", + frm_buff_size, buff_size); + frm_buff_size = buff_size; + } + } + + /* In case where AP advertizes BA window size which is different + * than our max supported BA window size. + */ + cdp_tid_update_ba_win_size(soc, peer_mac, vdev_id, tid, frm_buff_size); + + frm.addba_param_set.tid = tid; + frm.addba_param_set.buff_size = frm_buff_size % MAX_EHT_BA_BUFF_SIZE; + + /* Enable RX AMSDU only in HE mode if supported */ + if (mac_ctx->is_usr_cfg_amsdu_enabled && + ((IS_PE_SESSION_HE_MODE(session) && + WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq)) || + !WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq) || + lim_tdls_peer_support_he(sta_ds))) + frm.addba_param_set.amsdu_supp = amsdu_support; + else + frm.addba_param_set.amsdu_supp = 0; + + frm.addba_param_set.policy = SIR_MAC_BA_POLICY_IMMEDIATE; + frm.ba_timeout.timeout = batimeout; + if (addba_extn_present) { + frm.addba_extn_element.present = 1; + frm.addba_extn_element.no_fragmentation = 1; + frm.addba_extn_element.extd_buff_size = + frm_buff_size / MAX_EHT_BA_BUFF_SIZE; + if (lim_is_session_he_capable(session)) { + he_frag = lim_get_session_he_frag_cap(session); + if (he_frag != 0) { + frm.addba_extn_element.no_fragmentation = 0; + frm.addba_extn_element.he_frag_operation = + he_frag; + } + } + } + + /* + * for TDLS MLO case, it needs to use MLD mac address for TA and + * set action code to send out from specific vdev in fw. + */ + lim_prepare_tdls_with_mlo(session, peer_mac, self_mac, &action); + pe_debug("Sending a ADDBA Response from "QDF_MAC_ADDR_FMT" to "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(self_mac), + QDF_MAC_ADDR_REF(peer_mac)); + pe_debug("tid %d dialog_token %d status %d buff_size %d amsdu_supp %d", + tid, frm.DialogToken.token, frm.Status.status, + frm.addba_param_set.buff_size, + frm.addba_param_set.amsdu_supp); + pe_debug("addba_extn %d he_capable %d no_frag %d he_frag %d, exted buff size %d", + addba_extn_present, + lim_is_session_he_capable(session), + frm.addba_extn_element.no_fragmentation, + frm.addba_extn_element.he_frag_operation, + frm.addba_extn_element.extd_buff_size); + + status = dot11f_get_packed_addba_rsp_size(mac_ctx, &frm, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a ADDBA Response (0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(tDot11faddba_rsp); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating the packed size for a ADDBA Response (0x%08x).", status); + } + + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || (!pkt_ptr)) { + pe_err("Failed to allocate %d bytes for a ADDBA response action frame", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(frame_ptr, num_bytes); + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac, self_mac); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr) frame_ptr; + + sir_copy_mac_addr(mgmt_hdr->bssId, bssid); + + /* ADDBA Response is a robust mgmt action frame, + * set the "protect" (aka WEP) bit in the FC + */ + lim_set_protected_bit(mac_ctx, session, peer_mac, mgmt_hdr); + + if (is_wep && sta_ds && sta_ds->staType == STA_ENTRY_NDI_PEER) { + mgmt_hdr->fc.wep = 1; + tx_flag |= HAL_USE_PMF; + } + + status = dot11f_pack_addba_rsp(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), payload_size, + &payload_size); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a ADDBA Response (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_addba_rsp; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing ADDBA Response (0x%08x)", + status); + } + + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, pkt_ptr, + (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, + NULL, frame_ptr, + lim_addba_rsp_tx_complete_cnf, + tx_flag, vdev_id, + false, 0, RATEID_DEFAULT, 0, + action); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", + qdf_status); + return QDF_STATUS_E_FAILURE; + } else { + return QDF_STATUS_SUCCESS; + } + +error_addba_rsp: + cds_packet_free((void *)pkt_ptr); + return qdf_status; +} + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +lim_send_epcs_update_edca_params(struct wlan_objmgr_vdev *vdev, + tSirMacEdcaParamRecord *edca, bool mu_edca) +{ + struct mac_context *mac_ctx; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + return lim_send_edca_params(mac_ctx, edca, + wlan_vdev_get_id(vdev), mu_edca); +} + +QDF_STATUS +lim_send_epcs_restore_edca_params(struct wlan_objmgr_vdev *vdev) +{ + struct mac_context *mac_ctx; + struct pe_session *session; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = pe_find_session_by_vdev_id(mac_ctx, wlan_vdev_get_id(vdev)); + if (!session) + return QDF_STATUS_E_INVAL; + + lim_send_edca_params(mac_ctx, session->gLimEdcaParamsActive, + session->vdev_id, false); + + if (mac_ctx->usr_cfg_mu_edca_params) + lim_send_edca_params(mac_ctx, mac_ctx->usr_mu_edca_params, + session->vdev_id, true); + else if (session->mu_edca_present) + lim_send_edca_params(mac_ctx, session->ap_mu_edca_params, + session->vdev_id, true); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +lim_send_epcs_action_rsp_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args) +{ + struct mac_context *mac_ctx; + struct pe_session *session; + tDot11fepcs_neg_rsp frm; + uint8_t *frame_ptr; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size, status; + void *pkt_ptr = NULL; + uint8_t vdev_id = 0; + uint8_t tx_flag = 0; + QDF_STATUS qdf_status; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = pe_find_session_by_vdev_id(mac_ctx, wlan_vdev_get_id(vdev)); + if (!session) + return QDF_STATUS_E_INVAL; + + frm.Category.category = args->category; + frm.Action.action = args->action; + frm.DialogToken.token = args->arg1; + frm.Status.status = args->arg2; + + pe_debug("Sending a EPCS negotiation Response from " QDF_MAC_ADDR_FMT " to " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(session->self_mac_addr), + QDF_MAC_ADDR_REF(peer_mac)); + pe_debug("Dialog token %d status %d", frm.DialogToken.token, + frm.Status.status); + + status = dot11f_get_packed_epcs_neg_rspSize(mac_ctx, &frm, + &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate packed size for a EPCS negotiation Response (0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(tDot11fepcs_neg_rsp); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating packed size for a EPCS negotiation Response (0x%08x).", + status); + } + + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || !pkt_ptr) { + pe_err("Failed to allocate %d bytes for a EPCS rsp action frm", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + + lim_set_protected_bit(mac_ctx, session, peer_mac, mgmt_hdr); + + status = dot11f_pack_epcs_neg_rsp(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a EPCS negotiation response (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_epcs_rsp; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing EPCS rsp (0x%08x)", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + + vdev_id = session->vdev_id; + qdf_status = wma_tx_frame(mac_ctx, pkt_ptr, (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame_ptr, tx_flag, + vdev_id, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (QDF_STATUS_SUCCESS != qdf_status) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + return QDF_STATUS_E_FAILURE; + } else { + return QDF_STATUS_SUCCESS; + } + +error_epcs_rsp: + cds_packet_free((void *)pkt_ptr); + return qdf_status; +} + +QDF_STATUS +lim_send_epcs_action_req_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args) +{ + tDot11fepcs_neg_req frm; + struct mac_context *mac_ctx; + struct pe_session *session; + uint8_t *frame_ptr; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size, status; + void *pkt_ptr = NULL; + QDF_STATUS qdf_status; + uint8_t vdev_id = 0; + uint8_t tx_flag = 0; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + vdev_id = wlan_vdev_get_id(vdev); + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_debug("session not found for given vdev_id %d ", vdev_id); + return QDF_STATUS_E_INVAL; + } + + frm.Category.category = args->category; + frm.Action.action = args->action; + frm.DialogToken.token = args->arg1; + + pe_debug("Sending a EPCS negotiation Request token %d from " QDF_MAC_ADDR_FMT " to " QDF_MAC_ADDR_FMT, + frm.DialogToken.token, QDF_MAC_ADDR_REF(session->self_mac_addr), + QDF_MAC_ADDR_REF(peer_mac)); + + status = dot11f_get_packed_epcs_neg_reqSize(mac_ctx, &frm, + &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate packed size for a EPCS negotiation Request (0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(tDot11fepcs_neg_req); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating packed size for a EPCS negotiation Request (0x%08x).", + status); + } + + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || (!pkt_ptr)) { + pe_err("Failed to allocate %d bytes for a EPCS req action frm", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + lim_set_protected_bit(mac_ctx, session, peer_mac, mgmt_hdr); + + status = dot11f_pack_epcs_neg_req(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a EPCS negotiation request (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_epcs_req; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing EPCS req (0x%08x)", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + qdf_status = wma_tx_frame(mac_ctx, pkt_ptr, (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame_ptr, tx_flag, + vdev_id, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (qdf_status != QDF_STATUS_SUCCESS) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + return QDF_STATUS_E_FAILURE; + } else { + return QDF_STATUS_SUCCESS; + } + +error_epcs_req: + cds_packet_free((void *)pkt_ptr); + return qdf_status; +} + +QDF_STATUS +lim_send_epcs_action_teardown_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args) +{ + tDot11fepcs_teardown frm; + struct mac_context *mac_ctx; + struct pe_session *session; + uint8_t *frame_ptr; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size, status; + void *pkt_ptr = NULL; + QDF_STATUS qdf_status; + uint8_t vdev_id = 0; + uint8_t tx_flag = 0; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + vdev_id = wlan_vdev_get_id(vdev); + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("session not found for given vdev_id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + frm.Category.category = args->category; + frm.Action.action = args->action; + + pe_debug("Sending a EPCS tear down from " QDF_MAC_ADDR_FMT " to " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(session->self_mac_addr), + QDF_MAC_ADDR_REF(peer_mac)); + + status = dot11f_get_packed_epcs_teardownSize(mac_ctx, &frm, + &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate packed size for a EPCS tear down (0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(tDot11fepcs_teardown); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating packed size for a EPCS tear down (0x%08x).", + status); + } + + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || (!pkt_ptr)) { + pe_err("Failed to allocate %d bytes for a EPCS req action frm", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(frame_ptr, num_bytes); + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + lim_set_protected_bit(mac_ctx, session, peer_mac, mgmt_hdr); + + status = dot11f_pack_epcs_teardown(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a EPCS tear down (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_epcs_td; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing EPCS tear down(0x%08x)", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + qdf_status = wma_tx_frame(mac_ctx, pkt_ptr, (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame_ptr, tx_flag, + vdev_id, 0, RATEID_DEFAULT, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (qdf_status != QDF_STATUS_SUCCESS) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + return QDF_STATUS_E_FAILURE; + } else { + return QDF_STATUS_SUCCESS; + } + +error_epcs_td: + cds_packet_free((void *)pkt_ptr); + return qdf_status; +} + +static QDF_STATUS +lim_mgmt_t2lm_rsp_tx_complete(void *context, qdf_nbuf_t buf, + uint32_t tx_status, void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + struct pe_session *pe_session; + struct wlan_frame_hdr *mac_hdr; + struct wmi_mgmt_params *mgmt_params; + tDot11ft2lm_neg_rsp rsp = {0}; + enum qdf_dp_tx_rx_status qdf_tx_complete; + uint32_t extract_status; + uint8_t *frame_ptr; + uint8_t ff_offset; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!params) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + frame_ptr = qdf_nbuf_data(buf); + mac_hdr = (struct wlan_frame_hdr *)frame_ptr; + + ff_offset = sizeof(*mac_hdr); + if (wlan_crypto_is_data_protected(frame_ptr)) + ff_offset += IEEE80211_CCMP_MICLEN; + + if (qdf_nbuf_len(buf) < (ff_offset + sizeof(rsp))) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + mgmt_params = params; + pe_session = pe_find_session_by_vdev_id(mac_ctx, mgmt_params->vdev_id); + if (!pe_session || pe_session->opmode != QDF_STA_MODE) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (tx_status == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) + qdf_tx_complete = QDF_TX_RX_STATUS_OK; + else if (tx_status == WMI_MGMT_TX_COMP_TYPE_DISCARD) + qdf_tx_complete = QDF_TX_RX_STATUS_FW_DISCARD; + else + qdf_tx_complete = QDF_TX_RX_STATUS_NO_ACK; + + extract_status = + dot11f_unpack_t2lm_neg_rsp(mac_ctx, + frame_ptr + ff_offset, + sizeof(rsp), &rsp, false); + if (DOT11F_FAILED(extract_status)) { + pe_err("Failed to unpack T2LM negotiation response (0x%08x)", + extract_status); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + wlan_connectivity_t2lm_req_resp_event(pe_session->vdev, + rsp.DialogToken.token, + rsp.Status.status, + qdf_tx_complete, + (qdf_freq_t)mgmt_params->chanfreq, + false, + WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT); +out: + qdf_nbuf_free(buf); + + return status; +} + +static QDF_STATUS +lim_mgmt_t2lm_req_tx_complete(void *context, qdf_nbuf_t buf, + uint32_t tx_status, void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + struct pe_session *pe_session; + struct wlan_frame_hdr *mac_hdr; + struct wmi_mgmt_params *mgmt_params; + tDot11ft2lm_neg_req req = {0}; + enum qdf_dp_tx_rx_status qdf_tx_complete; + uint32_t extract_status; + uint8_t *frame_ptr; + uint8_t ff_offset; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!params) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + frame_ptr = qdf_nbuf_data(buf); + mac_hdr = (struct wlan_frame_hdr *)frame_ptr; + + ff_offset = sizeof(*mac_hdr); + if (wlan_crypto_is_data_protected(frame_ptr)) + ff_offset += IEEE80211_CCMP_MICLEN; + + if (qdf_nbuf_len(buf) < (ff_offset + sizeof(struct action_frm_hdr))) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + mgmt_params = params; + pe_session = pe_find_session_by_vdev_id(mac_ctx, mgmt_params->vdev_id); + if (!pe_session || pe_session->opmode != QDF_STA_MODE) { + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (tx_status == WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK) + qdf_tx_complete = QDF_TX_RX_STATUS_OK; + else if (tx_status == WMI_MGMT_TX_COMP_TYPE_DISCARD) + qdf_tx_complete = QDF_TX_RX_STATUS_FW_DISCARD; + else + qdf_tx_complete = QDF_TX_RX_STATUS_NO_ACK; + + extract_status = + dot11f_unpack_t2lm_neg_req(mac_ctx, + frame_ptr + ff_offset, + sizeof(req), &req, false); + if (DOT11F_FAILED(extract_status)) { + pe_err("Failed to unpack T2LM negotiation request (0x%08x)", + extract_status); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + wlan_connectivity_t2lm_req_resp_event(pe_session->vdev, + req.DialogToken.token, + false, + qdf_tx_complete, + (qdf_freq_t)mgmt_params->chanfreq, + false, + WLAN_CONN_DIAG_MLO_T2LM_REQ_EVENT); +out: + qdf_nbuf_free(buf); + + return status; +} + +QDF_STATUS +lim_send_t2lm_action_rsp_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_mac, + struct pe_session *session, uint8_t token, + enum wlan_t2lm_resp_frm_type status_code) +{ + tDot11ft2lm_neg_rsp frm; + uint8_t session_id = 0; + uint8_t *frame_ptr; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size, dot11f_status; + void *pkt_ptr = NULL; + QDF_STATUS status; + uint8_t vdev_id = 0; + uint8_t tx_flag = 0; + + session_id = session->smeSessionId; + vdev_id = session->vdev_id; + + qdf_mem_zero((uint8_t *)&frm, sizeof(frm)); + frm.Category.category = ACTION_CATEGORY_PROTECTED_EHT; + frm.Action.action = EHT_T2LM_RESPONSE; + + frm.DialogToken.token = token; + frm.Status.status = status_code; + + pe_debug("Sending a T2LM negotiation Response from " QDF_MAC_ADDR_FMT " to " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(session->self_mac_addr), + QDF_MAC_ADDR_REF(peer_mac)); + pe_debug("Dialog token %d status %d", frm.DialogToken.token, + frm.Status.status); + + dot11f_status = dot11f_get_packed_t2lm_neg_rspSize(mac_ctx, &frm, + &payload_size); + if (DOT11F_FAILED(dot11f_status)) { + pe_err("Failed to calculate packed size for a T2LM negotiation Response (0x%08x).", + dot11f_status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(tDot11ft2lm_neg_rsp); + } else if (DOT11F_WARNED(dot11f_status)) { + pe_warn("There were warnings while calculating packed size for a T2LM negotiation Response (0x%08x).", + dot11f_status); + } + + num_bytes = payload_size + sizeof(*mgmt_hdr); + status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(status) || !pkt_ptr) { + pe_err("Failed to allocate %d bytes for a T2LM rsp action frm", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(frame_ptr, num_bytes); + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + + lim_set_protected_bit(mac_ctx, session, peer_mac, mgmt_hdr); + + status = dot11f_pack_t2lm_neg_rsp(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a T2LM negotiation response (0x%08x)", + status); + status = QDF_STATUS_E_FAILURE; + goto error_t2lm_rsp; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing T2LM rsp (0x%08x)", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + status = wma_tx_frameWithTxComplete( + mac_ctx, pkt_ptr, (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame_ptr, + lim_mgmt_t2lm_rsp_tx_complete, + tx_flag, vdev_id, 0, session->curr_op_freq, + RATEID_DEFAULT, 0, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, status)); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("wma_tx_frame FAILED! Status [%d]", status); + + return status; + +error_t2lm_rsp: + cds_packet_free((void *)pkt_ptr); + return status; +} + +QDF_STATUS +lim_send_t2lm_action_req_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args, + struct wlan_t2lm_onging_negotiation_info *t2lm_neg, + uint8_t token) +{ + tDot11ft2lm_neg_req frm; + struct mac_context *mac_ctx; + struct pe_session *session; + uint8_t session_id = 0; + uint8_t *frame_ptr; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size, status; + void *pkt_ptr = NULL; + QDF_STATUS qdf_status; + uint8_t vdev_id = 0; + uint8_t tx_flag = 0; + struct wlan_ie_tid_to_link_mapping *t2lm_ie; + struct wlan_ie_tid_to_link_mapping *ie_buf; + uint8_t *t2lm_frame; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + if (!vdev) + return QDF_STATUS_E_NULL_VALUE; + + vdev_id = wlan_vdev_get_id(vdev); + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("session not found for given vdev_id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + session_id = session->smeSessionId; + + qdf_mem_zero((uint8_t *)&frm, sizeof(frm)); + + ie_buf = qdf_mem_malloc(sizeof(uint8_t) * T2LM_IE_ACTION_FRAME_MAX_LEN); + + if (!ie_buf) { + pe_err("Malloc failed"); + return QDF_STATUS_E_NULL_VALUE; + } + + t2lm_ie = (struct wlan_ie_tid_to_link_mapping *)&frm.t2lm_ie[0].data; + t2lm_frame = wlan_mlo_add_t2lm_ie((uint8_t *)ie_buf, + t2lm_neg, + vdev); + if (!t2lm_frame) { + pe_debug("Failed to populate T2LM IE"); + qdf_mem_free(ie_buf); + return QDF_STATUS_E_FAILURE; + } + + frm.t2lm_ie[0].num_data = ie_buf->elem_len - 1; + qdf_mem_copy(&frm.t2lm_ie[0].data, ie_buf->data, + frm.t2lm_ie[0].num_data); + + qdf_mem_free(ie_buf); + + frm.Category.category = args->category; + frm.Action.action = args->action; + frm.DialogToken.token = args->arg1; + frm.num_t2lm_ie = 1; + frm.t2lm_ie[0].present = 1; + + pe_debug("Sending a T2LM negotiation Request token %d from " QDF_MAC_ADDR_FMT " to " QDF_MAC_ADDR_FMT, + frm.DialogToken.token, QDF_MAC_ADDR_REF(session->self_mac_addr), + QDF_MAC_ADDR_REF(peer_mac)); + + status = dot11f_get_packed_t2lm_neg_reqSize(mac_ctx, &frm, + &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate packed size for a T2LM negotiation Request (0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(tDot11ft2lm_neg_req); + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while calculating packed size for a T2LM negotiation Request (0x%08x).", + status); + } + + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || (!pkt_ptr)) { + pe_err("Failed to allocate %d bytes for a T2LM req action frm", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(frame_ptr, num_bytes); + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_mac, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + lim_set_protected_bit(mac_ctx, session, peer_mac, mgmt_hdr); + + status = dot11f_pack_t2lm_neg_req(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a T2LM negotiation request (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_t2lm_req; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing T2LM req (0x%08x)", + status); + } + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + qdf_status = wma_tx_frameWithTxComplete( + mac_ctx, pkt_ptr, (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, 7, + lim_tx_complete, frame_ptr, + lim_mgmt_t2lm_req_tx_complete, tx_flag, + vdev_id, 0, session->curr_op_freq, + RATEID_DEFAULT, 0, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session->peSessionId, qdf_status)); + if (qdf_status != QDF_STATUS_SUCCESS) { + pe_err("wma_tx_frame FAILED! Status [%d]", qdf_status); + return QDF_STATUS_E_FAILURE; + } else { + return QDF_STATUS_SUCCESS; + } + +error_t2lm_req: + cds_packet_free((void *)pkt_ptr); + return qdf_status; +} +#endif + +/** + * lim_delba_tx_complete_cnf() - Confirmation for Delba OTA + * @context: pointer to global mac + * @buf: netbuf of Del BA frame + * @tx_complete: Sent status + * @params: tx completion params + * + * Return: This returns QDF_STATUS + */ +static QDF_STATUS lim_delba_tx_complete_cnf(void *context, qdf_nbuf_t buf, + uint32_t tx_complete, void *params) +{ + struct mac_context *mac_ctx = (struct mac_context *)context; + tSirMacMgmtHdr *mac_hdr; + struct sDot11fdelba_req frm; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t frame_len; + QDF_STATUS status; + uint8_t *data; + struct wmi_mgmt_params *mgmt_params = (struct wmi_mgmt_params *)params; + + if (!mgmt_params || !mac_ctx || !buf || !soc) { + pe_err("delba tx cnf invalid parameters"); + goto error; + } + data = qdf_nbuf_data(buf); + if (!data) { + pe_err("Delba frame is NULL"); + goto error; + } + + mac_hdr = (tSirMacMgmtHdr *)data; + qdf_mem_zero((void *)&frm, sizeof(struct sDot11fdelba_req)); + frame_len = sizeof(frm); + status = dot11f_unpack_delba_req(mac_ctx, (uint8_t *)data + + sizeof(*mac_hdr), frame_len, + &frm, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to unpack and parse delba (0x%08x, %d bytes)", + status, frame_len); + goto error; + } + pe_debug("delba ota done vdev %d "QDF_MAC_ADDR_FMT" tid %d desc_id %d status %d", + mgmt_params->vdev_id, + QDF_MAC_ADDR_REF(mac_hdr->da), frm.delba_param_set.tid, + mgmt_params->desc_id, tx_complete); + cdp_delba_tx_completion(soc, mac_hdr->da, mgmt_params->vdev_id, + frm.delba_param_set.tid, tx_complete); + +error: + if (buf) + qdf_nbuf_free(buf); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_send_delba_action_frame(struct mac_context *mac_ctx, + uint8_t vdev_id, uint8_t *peer_macaddr, + uint8_t tid, uint8_t reason_code) +{ + struct pe_session *session; + struct sDot11fdelba_req frm; + QDF_STATUS qdf_status; + tpSirMacMgmtHdr mgmt_hdr; + uint32_t num_bytes, payload_size = 0; + uint32_t status; + void *pkt_ptr = NULL; + uint8_t *frame_ptr; + uint8_t tx_flag = 0; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_debug("delba invalid vdev id %d ", vdev_id); + return QDF_STATUS_E_INVAL; + } + pe_debug("send delba vdev %d "QDF_MAC_ADDR_FMT" tid %d reason %d", vdev_id, + QDF_MAC_ADDR_REF(peer_macaddr), tid, reason_code); + qdf_mem_zero((uint8_t *)&frm, sizeof(frm)); + frm.Category.category = ACTION_CATEGORY_BACK; + frm.Action.action = DELBA; + frm.delba_param_set.initiator = 0; + frm.delba_param_set.tid = tid; + frm.Reason.code = reason_code; + + status = dot11f_get_packed_delba_req_size(mac_ctx, &frm, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to calculate the packed size for a DELBA(0x%08x).", + status); + /* We'll fall back on the worst case scenario: */ + payload_size = sizeof(struct sDot11fdelba_req); + } else if (DOT11F_WARNED(status)) { + pe_warn("Warnings in calculating the packed size for a DELBA (0x%08x).", + status); + } + num_bytes = payload_size + sizeof(*mgmt_hdr); + qdf_status = cds_packet_alloc(num_bytes, (void **)&frame_ptr, + (void **)&pkt_ptr); + if (!QDF_IS_STATUS_SUCCESS(qdf_status) || !pkt_ptr) { + pe_err("Failed to allocate %d bytes for a DELBA", + num_bytes); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(frame_ptr, num_bytes); + + lim_populate_mac_header(mac_ctx, frame_ptr, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, peer_macaddr, + session->self_mac_addr); + + /* Update A3 with the BSSID */ + mgmt_hdr = (tpSirMacMgmtHdr)frame_ptr; + sir_copy_mac_addr(mgmt_hdr->bssId, session->bssId); + + /* DEL is a robust mgmt action frame, + * set the "protect" (aka WEP) bit in the FC + */ + lim_set_protected_bit(mac_ctx, session, peer_macaddr, mgmt_hdr); + + status = dot11f_pack_delba_req(mac_ctx, &frm, + frame_ptr + sizeof(tSirMacMgmtHdr), + payload_size, &payload_size); + if (DOT11F_FAILED(status)) { + pe_err("Failed to pack a DELBA (0x%08x)", + status); + qdf_status = QDF_STATUS_E_FAILURE; + goto error_delba; + } else if (DOT11F_WARNED(status)) { + pe_warn("There were warnings while packing DELBA (0x%08x)", + status); + } + if (wlan_reg_is_5ghz_ch_freq(session->curr_op_freq) || + wlan_reg_is_6ghz_chan_freq(session->curr_op_freq) || + session->opmode == QDF_P2P_CLIENT_MODE || + session->opmode == QDF_P2P_GO_MODE) + tx_flag |= HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME; + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_MGMT, + session->peSessionId, mgmt_hdr->fc.subType)); + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, pkt_ptr, + (uint16_t)num_bytes, + TXRX_FRM_802_11_MGMT, + ANI_TXDIR_TODS, 7, + NULL, frame_ptr, + lim_delba_tx_complete_cnf, + tx_flag, vdev_id, + false, 0, RATEID_DEFAULT, 0, 0); + if (qdf_status != QDF_STATUS_SUCCESS) { + pe_err("delba wma_tx_frame FAILED! Status [%d]", qdf_status); + return qdf_status; + } else { + return QDF_STATUS_SUCCESS; + } + +error_delba: + if (pkt_ptr) + cds_packet_free((void *)pkt_ptr); + + return qdf_status; +} + +#define MAC_AUTH_FRAME_STATUS_CODE_OFFSET 4 + +/** + * lim_tx_mgmt_frame() - Transmits Auth mgmt frame + * @mac_ctx Pointer to Global MAC structure + * @vdev_id: vdev id + * @msg_len: Received message length + * @packet: Packet to be transmitted + * @frame: Received frame + * + * Return: None + */ +static void lim_tx_mgmt_frame(struct mac_context *mac_ctx, uint8_t vdev_id, + uint32_t msg_len, void *packet, uint8_t *frame) +{ + tpSirMacFrameCtl fc = (tpSirMacFrameCtl)frame; + QDF_STATUS qdf_status; + struct pe_session *session = NULL; + uint16_t auth_ack_status; + enum rateid min_rid = RATEID_DEFAULT; + enum QDF_OPMODE opmode; + uint16_t session_id; + qdf_freq_t channel_freq = 0; + qdf_freq_t *pre_auth_freq = NULL; + + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + if (opmode != QDF_NAN_DISC_MODE) { + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + cds_packet_free((void *)packet); + pe_err("session not found for given vdev_id %d", + vdev_id); + return; + } + session_id = session->peSessionId; + } else { + session_id = vdev_id; + } + + qdf_mtrace(QDF_MODULE_ID_PE, QDF_MODULE_ID_WMA, TRACE_CODE_TX_MGMT, + session_id, 0); + + if (opmode != QDF_NAN_DISC_MODE) { + if (fc->subType == SIR_MAC_MGMT_AUTH) { + tpSirFTPreAuthReq pre_auth_req; + uint16_t auth_algo = *(uint16_t *)(frame + + sizeof(tSirMacMgmtHdr)); + + if (auth_algo == eSIR_AUTH_TYPE_SAE) { + if (session->ftPEContext.pFTPreAuthReq) { + pre_auth_req = + session->ftPEContext.pFTPreAuthReq; + channel_freq = + pre_auth_req->pre_auth_channel_freq; + } + pre_auth_freq = &channel_freq; + } + pe_debug("TX SAE pre-auth frame on freq %d", + channel_freq); + } + min_rid = lim_get_min_session_txrate(session, pre_auth_freq); + } + + qdf_status = wma_tx_frameWithTxComplete(mac_ctx, packet, + (uint16_t)msg_len, + TXRX_FRM_802_11_MGMT, ANI_TXDIR_TODS, + 7, lim_tx_complete, frame, + lim_auth_tx_complete_cnf, + 0, vdev_id, false, channel_freq, + min_rid, 0, 0); + MTRACE(qdf_trace(QDF_MODULE_ID_PE, TRACE_CODE_TX_COMPLETE, + session_id, qdf_status)); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("Could not send Auth frame, retCode=%X", qdf_status); + mac_ctx->auth_ack_status = LIM_TX_FAILED; + auth_ack_status = SENT_FAIL; + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_AUTH_ACK_EVENT, + session, auth_ack_status, QDF_STATUS_E_FAILURE); + /* Pkt will be freed up by the callback */ + } +} + +static void +lim_handle_sae_auth_retry(struct mac_context *mac_ctx, uint8_t vdev_id, + uint8_t *frame, uint32_t frame_len) +{ + struct pe_session *session; + struct sae_auth_retry *sae_retry; + uint8_t retry_count = 0; + uint32_t val = 0; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("session not found for given vdev_id %d", + vdev_id); + return; + } + if ((session->opmode != QDF_STA_MODE) && + (session->opmode != QDF_P2P_CLIENT_MODE)) + return; + + if (session->limMlmState == eLIM_MLM_WT_SAE_AUTH_STATE) + wlan_mlme_get_sae_auth_retry_count(mac_ctx->psoc, &retry_count); + else + wlan_mlme_get_sae_roam_auth_retry_count(mac_ctx->psoc, + &retry_count); + if (!retry_count) { + pe_debug("vdev %d: SAE Auth retry disabled", vdev_id); + return; + } + + sae_retry = mlme_get_sae_auth_retry(session->vdev); + if (!sae_retry) { + pe_err("sae retry pointer is NULL for vdev_id %d", + vdev_id); + return; + } + + if (sae_retry->sae_auth.ptr) + lim_sae_auth_cleanup_retry(mac_ctx, vdev_id); + + sae_retry->sae_auth.ptr = qdf_mem_malloc(frame_len); + if (!sae_retry->sae_auth.ptr) + return; + + pe_debug("SAE auth frame queued vdev_id %d seq_num %d", + vdev_id, mac_ctx->mgmtSeqNum + 1); + qdf_mem_copy(sae_retry->sae_auth.ptr, frame, frame_len); + mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer.sessionId = + session->peSessionId; + sae_retry->sae_auth.len = frame_len; + sae_retry->sae_auth_max_retry = retry_count; + + val = mac_ctx->mlme_cfg->timeouts.sae_auth_failure_timeout; + + tx_timer_change( + &mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer, + SYS_MS_TO_TICKS(val), 0); + /* Activate Auth Retry timer */ + if (tx_timer_activate( + &mac_ctx->lim.lim_timers.g_lim_periodic_auth_retry_timer) != + TX_SUCCESS) { + pe_err("failed to start periodic auth retry timer"); + lim_sae_auth_cleanup_retry(mac_ctx, vdev_id); + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS lim_update_mld_to_link_address(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + tpSirMacMgmtHdr mac_hdr) +{ + struct qdf_mac_addr *self_link_addr; + struct tLimPreAuthNode *pre_auth_node; + struct qdf_mac_addr peer_link_addr; + struct wlan_objmgr_peer *bss_peer = NULL; + struct qdf_mac_addr *peer_roaming_link_addr; + enum QDF_OPMODE opmode; + uint8_t *peer_mld_addr = NULL; + QDF_STATUS status; + + if (!wlan_cm_is_sae_auth_addr_conversion_required(vdev)) + return QDF_STATUS_SUCCESS; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + self_link_addr = (struct qdf_mac_addr *) + wlan_vdev_mlme_get_linkaddr(vdev); + + switch (opmode) { + case QDF_SAP_MODE: + pre_auth_node = + lim_search_pre_auth_list_by_mld_addr(mac_ctx, + mac_hdr->da); + if (!pre_auth_node) { + /** + * Using MLD address, if pre_auth_node is not present then + * check for peer mac address due to legacy connection. + */ + pre_auth_node = lim_search_pre_auth_list(mac_ctx, + mac_hdr->da); + if (!pre_auth_node) { + pe_err("pre_auth not found by MLD: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->da)); + return QDF_STATUS_E_INVAL; + } else { + return QDF_STATUS_SUCCESS; + } + } + + qdf_mem_copy(mac_hdr->da, pre_auth_node->peerMacAddr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(mac_hdr->bssId, self_link_addr->bytes, + QDF_MAC_ADDR_SIZE); + break; + case QDF_STA_MODE: + if (!wlan_cm_is_vdev_roaming(vdev)) { + status = wlan_vdev_get_bss_peer_mac(vdev, + &peer_link_addr); + if (QDF_IS_STATUS_ERROR(status)) + return status; + bss_peer = wlan_objmgr_vdev_try_get_bsspeer( + vdev, WLAN_MLME_OBJMGR_ID); + if (bss_peer) { + peer_mld_addr = + wlan_peer_mlme_get_mldaddr(bss_peer); + wlan_objmgr_peer_release_ref( + bss_peer, WLAN_MLME_OBJMGR_ID); + } + } else { + peer_roaming_link_addr = + wlan_cm_roaming_get_peer_link_addr(vdev); + if (!peer_roaming_link_addr) + return QDF_STATUS_E_FAILURE; + peer_link_addr = *peer_roaming_link_addr; + peer_mld_addr = (uint8_t *) + wlan_cm_roaming_get_peer_mld_addr(vdev); + } + if (!peer_mld_addr) + return QDF_STATUS_SUCCESS; + + pe_debug("dest address"QDF_MAC_ADDR_FMT"mld addr"QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_hdr->da), + QDF_MAC_ADDR_REF(peer_mld_addr)); + if (!qdf_mem_cmp(mac_hdr->da, peer_mld_addr, QDF_MAC_ADDR_SIZE)) + qdf_mem_copy(mac_hdr->da, peer_link_addr.bytes, + QDF_MAC_ADDR_SIZE); + + qdf_mem_copy(mac_hdr->bssId, peer_link_addr.bytes, + QDF_MAC_ADDR_SIZE); + break; + default: + return QDF_STATUS_SUCCESS; + } + + qdf_mem_copy(mac_hdr->sa, self_link_addr->bytes, QDF_MAC_ADDR_SIZE); + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS lim_update_mld_to_link_address(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + tpSirMacMgmtHdr mac_hdr) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void lim_send_frame(struct mac_context *mac_ctx, uint8_t vdev_id, uint8_t *buf, + uint16_t buf_len) +{ + QDF_STATUS qdf_status; + uint8_t *frame; + void *packet; + tpSirMacFrameCtl fc = (tpSirMacFrameCtl)buf; + tpSirMacMgmtHdr mac_hdr = (tpSirMacMgmtHdr)buf; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + pe_debug("sending fc->type: %d fc->subType: %d", fc->type, fc->subType); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return; + + /* Case: + * 1. In case of SAP, userspace will send MLD addresses in 2nd and 4th + * SAE auth frames. Driver needs to convert it into link address. + * 2. In case of STA, userspace will send MLD addresses in 1st and 3rd + * SAE auth frames. Driver needs to convert it into link address. + */ + status = lim_update_mld_to_link_address(mac_ctx, vdev, mac_hdr); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("SAE address conversion failure with status:%d", status); + return; + } + + lim_add_mgmt_seq_num(mac_ctx, mac_hdr); + qdf_status = cds_packet_alloc(buf_len, (void **)&frame, + (void **)&packet); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + pe_err("call to bufAlloc failed for AUTH frame"); + return; + } + + qdf_mem_copy(frame, buf, buf_len); + lim_tx_mgmt_frame(mac_ctx, vdev_id, buf_len, packet, frame); +} + +void lim_send_mgmt_frame_tx(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct sir_mgmt_msg *mb_msg = (struct sir_mgmt_msg *)msg->bodyptr; + uint32_t msg_len; + tpSirMacFrameCtl fc = (tpSirMacFrameCtl)mb_msg->data; + uint8_t vdev_id; + uint16_t auth_algo; + + msg_len = mb_msg->msg_len - sizeof(*mb_msg); + vdev_id = mb_msg->vdev_id; + + if (fc->subType == SIR_MAC_MGMT_AUTH) { + auth_algo = *(uint16_t *)(mb_msg->data + + sizeof(tSirMacMgmtHdr)); + if (auth_algo == eSIR_AUTH_TYPE_SAE) + lim_handle_sae_auth_retry(mac_ctx, vdev_id, + mb_msg->data, msg_len); + if (auth_algo == eSIR_FT_AUTH) { + struct tLimPreAuthNode *sta_pre_auth_ctx; + + sta_pre_auth_ctx = lim_search_pre_auth_list(mac_ctx, + ((tpSirMacMgmtHdr)(mb_msg->data))->da); + pe_debug("FT Auth TX to " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(((tpSirMacMgmtHdr)(mb_msg->data))->da)); + if (sta_pre_auth_ctx) { + pe_debug("STA is AUTHENTICATED_STATE"); + sta_pre_auth_ctx->mlmState = + eLIM_MLM_AUTHENTICATED_STATE; + } + } + } + mac_ctx->auth_ack_status = LIM_ACK_NOT_RCD; + lim_send_frame(mac_ctx, vdev_id, mb_msg->data, msg_len); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c new file mode 100644 index 0000000000..dda1416903 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.c @@ -0,0 +1,587 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * lim_send_messages.c: Provides functions to send messages or Indications to HAL. + * Author: Sunit Bhatia + * Date: 09/21/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ +#include "lim_send_messages.h" +#include "lim_trace.h" +#include "wlan_reg_services_api.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_utils.h" +#include "wma.h" +#include "../../core/src/vdev_mgr_ops.h" + +/* Max debug string size in bytes */ +#define LIM_DEBUG_STRING_SIZE 512 + +/** + * lim_send_beacon_params() - updates bcn params to WMA + * + * @mac : pointer to Global Mac structure. + * @tpUpdateBeaconParams : pointer to the structure, which contains the beacon + * parameters which are changed. + * + * This function is called to send beacon interval, short preamble or other + * parameters to WMA, which are changed and indication is received in beacon. + * + * @return success if message send is ok, else false. + */ +QDF_STATUS lim_send_beacon_params(struct mac_context *mac, + tpUpdateBeaconParams pUpdatedBcnParams, + struct pe_session *pe_session) +{ + tpUpdateBeaconParams pBcnParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pBcnParams = qdf_mem_malloc(sizeof(*pBcnParams)); + if (!pBcnParams) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy((uint8_t *) pBcnParams, pUpdatedBcnParams, + sizeof(*pBcnParams)); + msgQ.type = WMA_UPDATE_BEACON_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pBcnParams; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_BEACON_IND, paramChangeBitmap in hex: %x", + pUpdatedBcnParams->paramChangeBitmap); + if (!pe_session) { + qdf_mem_free(pBcnParams); + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + return QDF_STATUS_E_FAILURE; + } else { + MTRACE(mac_trace_msg_tx(mac, + pe_session->peSessionId, + msgQ.type)); + } + pBcnParams->vdev_id = pe_session->vdev_id; + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pBcnParams); + pe_err("Posting WMA_UPDATE_BEACON_IND, reason=%X", + retCode); + } + lim_send_beacon_ind(mac, pe_session, REASON_DEFAULT); + return retCode; +} + +QDF_STATUS lim_send_switch_chnl_params(struct mac_context *mac, + struct pe_session *session) +{ + struct vdev_mlme_obj *mlme_obj; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct vdev_start_response rsp = {0}; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_FAILURE; + + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (!session->vdev) { + pe_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + status = lim_pre_vdev_start(mac, mlme_obj, session); + if (QDF_IS_STATUS_ERROR(status)) + goto send_resp; + + session->ch_switch_in_progress = true; + + /* we need to defer the message until we + * get the response back from WMA + */ + SET_LIM_PROCESS_DEFD_MESGS(mac, false); + + status = wma_pre_chan_switch_setup(session->vdev_id); + if (status != QDF_STATUS_SUCCESS) { + pe_err("failed status = %d", status); + goto send_resp; + } + status = vdev_mgr_start_send(mlme_obj, + mlme_is_chan_switch_in_progress(session->vdev)); + if (status != QDF_STATUS_SUCCESS) { + pe_err("failed status = %d", status); + goto send_resp; + } + wma_post_chan_switch_setup(session->vdev_id); + + return QDF_STATUS_SUCCESS; +send_resp: + rsp.status = status; + rsp.vdev_id = session->vdev_id; + + wma_handle_channel_switch_resp(wma, &rsp); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_send_edca_params(struct mac_context *mac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t vdev_id, bool mu_edca) +{ + tEdcaParams *pEdcaParams = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pEdcaParams = qdf_mem_malloc(sizeof(tEdcaParams)); + if (!pEdcaParams) + return QDF_STATUS_E_NOMEM; + pEdcaParams->vdev_id = vdev_id; + pEdcaParams->acbe = pUpdatedEdcaParams[QCA_WLAN_AC_BE]; + pEdcaParams->acbk = pUpdatedEdcaParams[QCA_WLAN_AC_BK]; + pEdcaParams->acvi = pUpdatedEdcaParams[QCA_WLAN_AC_VI]; + pEdcaParams->acvo = pUpdatedEdcaParams[QCA_WLAN_AC_VO]; + pEdcaParams->mu_edca_params = mu_edca; + msgQ.type = WMA_UPDATE_EDCA_PROFILE_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pEdcaParams; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_EDCA_PROFILE_IND"); + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pEdcaParams); + pe_err("Posting WMA_UPDATE_EDCA_PROFILE_IND failed, reason=%X", + retCode); + } + return retCode; +} + +void lim_set_active_edca_params(struct mac_context *mac_ctx, + tSirMacEdcaParamRecord *edca_params, + struct pe_session *pe_session) +{ + uint8_t ac, new_ac, i; + uint8_t ac_admitted; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + uint8_t *debug_str; + uint32_t len = 0; + + /* Initialize gLimEdcaParamsActive[] to be same as localEdcaParams */ + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BE] = edca_params[QCA_WLAN_AC_BE]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BK] = edca_params[QCA_WLAN_AC_BK]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VI] = edca_params[QCA_WLAN_AC_VI]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VO] = edca_params[QCA_WLAN_AC_VO]; + + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BE].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BE]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BK].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_BK]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VI].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VI]; + pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VO].no_ack = + mac_ctx->no_ack_policy_cfg[QCA_WLAN_AC_VO]; + /* An AC requires downgrade if the ACM bit is set, and the AC has not + * yet been admitted in uplink or bi-directions. + * If an AC requires downgrade, it will downgrade to the next beset AC + * for which ACM is not enabled. + * + * - There's no need to downgrade AC_BE since it IS the lowest AC. Hence + * start the for loop with AC_BK. + * - If ACM bit is set for an AC, initially downgrade it to AC_BE. Then + * traverse thru the AC list. If we do find the next best AC which is + * better than AC_BE, then use that one. For example, if ACM bits are set + * such that: BE_ACM=1, BK_ACM=1, VI_ACM=1, VO_ACM=0 + * then all AC will be downgraded to AC_BE. + */ + + debug_str = qdf_mem_malloc(LIM_DEBUG_STRING_SIZE); + if (!debug_str) + return; + + for (ac = QCA_WLAN_AC_BK; ac <= QCA_WLAN_AC_VO; ac++) { + ac_admitted = + ((pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK] & + (1 << ac)) >> ac); + + len += qdf_scnprintf(debug_str + len, + LIM_DEBUG_STRING_SIZE - len, + "AC[%d]:acm=%d ac_admitted=%d,", ac, + edca_params[ac].aci.acm, ac_admitted); + if ((edca_params[ac].aci.acm == 1) && (ac_admitted == 0)) { + /* Loop backwards through AC values until it finds + * acm == 0 or reaches QCA_WLAN_AC_BE. + * Note that for block has no executable statements. + */ + for (i = ac - 1; + (i > QCA_WLAN_AC_BE && + (edca_params[i].aci.acm != 0)); + i--) + ; + new_ac = i; + len += qdf_scnprintf(debug_str + len, + LIM_DEBUG_STRING_SIZE - len, + "AC %d ---> AC %d, ", ac, new_ac); + pe_session->gLimEdcaParamsActive[ac] = + edca_params[new_ac]; + } + } + + pe_debug("adAdmitMask: uplink 0x%x downlink 0x%x, %s", + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_UPLINK], + pe_session->gAcAdmitMask[SIR_MAC_DIRECTION_DNLINK], debug_str); + qdf_mem_free(debug_str); +/* log: LOG_WLAN_QOS_EDCA_C */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, + LOG_WLAN_QOS_EDCA_C); + if (log_ptr) { + tSirMacEdcaParamRecord *rec; + + rec = &pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BE]; + log_ptr->aci_be = rec->aci.aci; + log_ptr->cw_be = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_be = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_BK]; + log_ptr->aci_bk = rec->aci.aci; + log_ptr->cw_bk = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_bk = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VI]; + log_ptr->aci_vi = rec->aci.aci; + log_ptr->cw_vi = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_vi = rec->txoplimit; + + rec = &pe_session->gLimEdcaParamsActive[QCA_WLAN_AC_VO]; + log_ptr->aci_vo = rec->aci.aci; + log_ptr->cw_vo = rec->cw.max << 4 | rec->cw.min; + log_ptr->txoplimit_vo = rec->txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + return; +} + +QDF_STATUS lim_send_mode_update(struct mac_context *mac, + tUpdateVHTOpMode *pTempParam, + struct pe_session *pe_session) +{ + tUpdateVHTOpMode *pVhtOpMode = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pVhtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (!pVhtOpMode) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy((uint8_t *) pVhtOpMode, pTempParam, + sizeof(tUpdateVHTOpMode)); + msgQ.type = WMA_UPDATE_OP_MODE; + msgQ.reserved = 0; + msgQ.bodyptr = pVhtOpMode; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_OP_MODE, op_mode %d", + pVhtOpMode->opMode); + if (!pe_session) + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(mac, + pe_session->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pVhtOpMode); + pe_err("Posting WMA_UPDATE_OP_MODE failed, reason=%X", + retCode); + } + + return retCode; +} + +QDF_STATUS lim_send_rx_nss_update(struct mac_context *mac, + tUpdateRxNss *pTempParam, + struct pe_session *pe_session) +{ + tUpdateRxNss *pRxNss = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pRxNss = qdf_mem_malloc(sizeof(tUpdateRxNss)); + if (!pRxNss) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy((uint8_t *) pRxNss, pTempParam, sizeof(tUpdateRxNss)); + msgQ.type = WMA_UPDATE_RX_NSS; + msgQ.reserved = 0; + msgQ.bodyptr = pRxNss; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_RX_NSS"); + if (!pe_session) + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(mac, + pe_session->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pRxNss); + pe_err("Posting WMA_UPDATE_RX_NSS failed, reason=%X", + retCode); + } + + return retCode; +} + +QDF_STATUS lim_set_membership(struct mac_context *mac, + tUpdateMembership *pTempParam, + struct pe_session *pe_session) +{ + tUpdateMembership *pMembership = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pMembership = qdf_mem_malloc(sizeof(tUpdateMembership)); + if (!pMembership) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy((uint8_t *) pMembership, pTempParam, + sizeof(tUpdateMembership)); + + msgQ.type = WMA_UPDATE_MEMBERSHIP; + msgQ.reserved = 0; + msgQ.bodyptr = pMembership; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_MEMBERSHIP"); + if (!pe_session) + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(mac, + pe_session->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pMembership); + pe_err("Posting WMA_UPDATE_MEMBERSHIP failed, reason=%X", + retCode); + } + + return retCode; +} + +QDF_STATUS lim_set_user_pos(struct mac_context *mac, + tUpdateUserPos *pTempParam, + struct pe_session *pe_session) +{ + tUpdateUserPos *pUserPos = NULL; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + pUserPos = qdf_mem_malloc(sizeof(tUpdateUserPos)); + if (!pUserPos) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy((uint8_t *) pUserPos, pTempParam, sizeof(tUpdateUserPos)); + + msgQ.type = WMA_UPDATE_USERPOS; + msgQ.reserved = 0; + msgQ.bodyptr = pUserPos; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_USERPOS"); + if (!pe_session) + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + else + MTRACE(mac_trace_msg_tx(mac, + pe_session->peSessionId, + msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pUserPos); + pe_err("Posting WMA_UPDATE_USERPOS failed, reason=%X", + retCode); + } + + return retCode; +} + +/** + * lim_send_exclude_unencrypt_ind() - sends WMA_EXCLUDE_UNENCRYPTED_IND to HAL + * @mac: mac global context + * @excludeUnenc: true: ignore, false: indicate + * @pe_session: session context + * + * LIM sends a message to HAL to indicate whether to ignore or indicate the + * unprotected packet error. + * + * Return: status of operation + */ +QDF_STATUS lim_send_exclude_unencrypt_ind(struct mac_context *mac, + bool excludeUnenc, + struct pe_session *pe_session) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + tSirWlanExcludeUnencryptParam *pExcludeUnencryptParam; + + pExcludeUnencryptParam = + qdf_mem_malloc(sizeof(tSirWlanExcludeUnencryptParam)); + if (!pExcludeUnencryptParam) + return QDF_STATUS_E_NOMEM; + + pExcludeUnencryptParam->excludeUnencrypt = excludeUnenc; + qdf_mem_copy(pExcludeUnencryptParam->bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + + msgQ.type = WMA_EXCLUDE_UNENCRYPTED_IND; + msgQ.reserved = 0; + msgQ.bodyptr = pExcludeUnencryptParam; + msgQ.bodyval = 0; + pe_debug("Sending WMA_EXCLUDE_UNENCRYPTED_IND"); + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + qdf_mem_free(pExcludeUnencryptParam); + pe_err("Posting WMA_EXCLUDE_UNENCRYPTED_IND failed, reason=%X", + retCode); + } + + return retCode; +} + +/** + * lim_send_ht40_obss_scanind() - send ht40 obss start scan request + * mac: mac context + * session PE session handle + * + * LIM sends a HT40 start scan message to WMA + * + * Return: status of operation + */ +QDF_STATUS lim_send_ht40_obss_scanind(struct mac_context *mac_ctx, + struct pe_session *session) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct obss_ht40_scanind *ht40_obss_scanind; + uint32_t channelnum, chan_freq; + struct scheduler_msg msg = {0}; + uint8_t channel24gnum, count; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + ht40_obss_scanind = qdf_mem_malloc(sizeof(struct obss_ht40_scanind)); + if (!ht40_obss_scanind) + return QDF_STATUS_E_FAILURE; + + wlan_reg_read_current_country(mac_ctx->psoc, reg_cc); + ht40_obss_scanind->cmd = HT40_OBSS_SCAN_PARAM_START; + ht40_obss_scanind->scan_type = eSIR_ACTIVE_SCAN; + ht40_obss_scanind->obss_passive_dwelltime = + session->obss_ht40_scanparam.obss_passive_dwelltime; + ht40_obss_scanind->obss_active_dwelltime = + session->obss_ht40_scanparam.obss_active_dwelltime; + ht40_obss_scanind->obss_width_trigger_interval = + session->obss_ht40_scanparam.obss_width_trigger_interval; + ht40_obss_scanind->obss_passive_total_per_channel = + session->obss_ht40_scanparam.obss_passive_total_per_channel; + ht40_obss_scanind->obss_active_total_per_channel = + session->obss_ht40_scanparam.obss_active_total_per_channel; + ht40_obss_scanind->bsswidth_ch_trans_delay = + session->obss_ht40_scanparam.bsswidth_ch_trans_delay; + ht40_obss_scanind->obss_activity_threshold = + session->obss_ht40_scanparam.obss_activity_threshold; + ht40_obss_scanind->current_operatingclass = + wlan_reg_dmn_get_opclass_from_channel( + reg_cc, + wlan_reg_freq_to_chan( + mac_ctx->pdev, session->curr_op_freq), + session->ch_width); + channelnum = mac_ctx->mlme_cfg->reg.valid_channel_list_num; + + /* Extract 24G channel list */ + channel24gnum = 0; + for (count = 0; count < channelnum && + (channel24gnum < CFG_VALID_CHANNEL_LIST_LEN); count++) { + chan_freq = + mac_ctx->mlme_cfg->reg.valid_channel_freq_list[count]; + if (wlan_reg_is_24ghz_ch_freq(chan_freq)) { + ht40_obss_scanind->chan_freq_list[channel24gnum] = + chan_freq; + channel24gnum++; + } + } + ht40_obss_scanind->channel_count = channel24gnum; + /* FW API requests BSS IDX */ + ht40_obss_scanind->bss_id = session->vdev_id; + ht40_obss_scanind->fortymhz_intolerent = 0; + ht40_obss_scanind->iefield_len = 0; + msg.type = WMA_HT40_OBSS_SCAN_IND; + msg.reserved = 0; + msg.bodyptr = (void *)ht40_obss_scanind; + msg.bodyval = 0; + pe_debug("Obss Scan trigger width: %d, delay factor: %d bssid " QDF_MAC_ADDR_FMT, + ht40_obss_scanind->obss_width_trigger_interval, + ht40_obss_scanind->bsswidth_ch_trans_delay, + QDF_MAC_ADDR_REF(session->bssId)); + ret = wma_post_ctrl_msg(mac_ctx, &msg); + if (QDF_STATUS_SUCCESS != ret) { + pe_err("WDA_HT40_OBSS_SCAN_IND msg failed, reason=%X", + ret); + qdf_mem_free(ht40_obss_scanind); + } + return ret; +} + +QDF_STATUS +lim_send_edca_pifs_param(struct mac_context *mac, + struct wlan_edca_pifs_param_ie *param, + uint8_t vdev_id) +{ + struct edca_pifs_vparam *edca_pifs = NULL; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + edca_pifs = qdf_mem_malloc(sizeof(*edca_pifs)); + if (!edca_pifs) + return QDF_STATUS_E_NOMEM; + + edca_pifs->vdev_id = vdev_id; + qdf_mem_copy(&edca_pifs->param, param, + sizeof(struct wlan_edca_pifs_param_ie)); + + msgQ.type = WMA_UPDATE_EDCA_PIFS_PARAM_IND; + msgQ.reserved = 0; + msgQ.bodyptr = edca_pifs; + msgQ.bodyval = 0; + pe_debug("Sending WMA_UPDATE_EDCA_PIFS_PARAM_IND"); + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + ret = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_IS_STATUS_ERROR(ret)) { + qdf_mem_free(edca_pifs); + pe_err("Posting WMA_UPDATE_EDCA_PIFS_PARAM_IND failed, reason=%X", + ret); + } + return ret; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h new file mode 100644 index 0000000000..4145d100af --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_messages.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2011-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * lim_send_messages.h: Provides functions to send messages or Indications to HAL. + * Author: Sunit Bhatia + * Date: 09/21/2006 + * History:- + * Date Modified by Modification Information + * + * -------------------------------------------------------------------------- + * + */ +#ifndef __LIM_SEND_MESSAGES_H +#define __LIM_SEND_MESSAGES_H + +#include "ani_global.h" +#include "lim_types.h" +#include "wma_if.h" +#include "sir_params.h" +QDF_STATUS lim_send_beacon_params(struct mac_context *mac, + tpUpdateBeaconParams pUpdatedBcnParams, + struct pe_session *pe_session); +/* QDF_STATUS lim_send_beacon_params(struct mac_context *mac, tpUpdateBeaconParams pUpdatedBcnParams); */ +QDF_STATUS lim_send_mode_update(struct mac_context *mac, + tUpdateVHTOpMode *tempParam, + struct pe_session *pe_session); +QDF_STATUS lim_send_rx_nss_update(struct mac_context *mac, + tUpdateRxNss *tempParam, + struct pe_session *pe_session); + +QDF_STATUS lim_set_membership(struct mac_context *mac, + tUpdateMembership *pTempParam, + struct pe_session *pe_session); + +QDF_STATUS lim_set_user_pos(struct mac_context *mac, + tUpdateUserPos *pTempParam, + struct pe_session *pe_session); + +/** + * lim_send_switch_chnl_params() - change channel + * @mac: pointer to Global MAC structure + * @session: pe session + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_switch_chnl_params(struct mac_context *mac, + struct pe_session *session); + +/** + * lim_send_edca_params() - Send edsa params to firmware + * @mac: pointer to Global MAC structure + * @pUpdatedEdcaParams: updated edca params + * @vdev_id: vdev id + * @mu_edca: MU edca + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_edca_params(struct mac_context *mac, + tSirMacEdcaParamRecord *pUpdatedEdcaParams, + uint16_t vdev_id, bool mu_edca); +/** + * lim_set_active_edca_params() - Choose best EDCA parameters + * @mac_ctx: pointer to Global Mac structure. + * @edca_params: pointer to the local EDCA parameters + * @pe_session: point to the session entry + * + * This function is called to set the most up-to-date EDCA parameters + * given the default local EDCA parameters. The rules are as following: + * - If ACM bit is set for all ACs, then downgrade everything to Best Effort. + * - If ACM is not set for any AC, then PE will use the default EDCA + * parameters as advertised by AP. + * - If ACM is set in any of the ACs, PE will use the EDCA parameters + * from the next best AC for which ACM is not enabled. + * + * Return: none + */ +void lim_set_active_edca_params(struct mac_context *mac_ctx, + tSirMacEdcaParamRecord *edca_params, + struct pe_session *pe_session); + +#define CAPABILITY_FILTER_MASK 0x73CF +#define ERP_FILTER_MASK 0xF8 +#define EDCA_FILTER_MASK 0xF0 +#define QOS_FILTER_MASK 0xF0 +#define HT_BYTE0_FILTER_MASK 0x0 +#define HT_BYTE2_FILTER_MASK 0xEB +#define HT_BYTE5_FILTER_MASK 0xFD +#define DS_PARAM_CHANNEL_MASK 0x0 +#define VHTOP_CHWIDTH_MASK 0xFC + +QDF_STATUS lim_send_exclude_unencrypt_ind(struct mac_context *mac, + bool excludeUnenc, + struct pe_session *pe_session); +QDF_STATUS lim_send_ht40_obss_scanind(struct mac_context *mac_ctx, + struct pe_session *session); +void lim_handle_sme_join_result(struct mac_context *, + tSirResultCodes, uint16_t, struct pe_session *); + +/** + * lim_send_edca_pifs_param() - Send edca/pifs param to firmware based on + * edca_param_type ini + * @mac: pointer to Global Mac structure + * @param: pointer to param + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_send_edca_pifs_param(struct mac_context *mac, + struct wlan_edca_pifs_param_ie *param, + uint8_t vdev_id); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c new file mode 100644 index 0000000000..1dbdb7c28e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.c @@ -0,0 +1,2921 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_send_sme_rspMessages.cc contains the functions + * for sending SME response/notification messages to applications + * above MAC software. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "qdf_types.h" +#include "wni_api.h" +#include "sir_common.h" +#include "ani_global.h" + +#include "wni_cfg.h" +#include "sys_def.h" + +#include "sch_api.h" +#include "utils_api.h" +#include "lim_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "lim_session_utils.h" +#include "lim_types.h" +#include "sir_api.h" +#include "cds_regdomain.h" +#include "lim_send_messages.h" +#include "nan_datapath.h" +#include "lim_assoc_utils.h" +#include "wlan_reg_services_api.h" +#include "wlan_utility.h" + +#include "wlan_tdls_tgt_api.h" +#include "lim_process_fils.h" +#include "wma.h" +#include "wma_he.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include +#include +#include +#include "wlan_mlme_public_struct.h" + +void lim_send_sme_rsp(struct mac_context *mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t vdev_id) +{ + struct scheduler_msg msg = {0}; + tSirSmeRsp *sme_rsp; + + pe_debug("Sending message: %s with reasonCode: %s", + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + sme_rsp = qdf_mem_malloc(sizeof(tSirSmeRsp)); + if (!sme_rsp) + return; + + sme_rsp->messageType = msg_type; + sme_rsp->length = sizeof(tSirSmeRsp); + sme_rsp->status_code = result_code; + sme_rsp->vdev_id = vdev_id; + + msg.type = msg_type; + msg.bodyptr = sme_rsp; + msg.bodyval = 0; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_TX_SME_MSG, vdev_id, msg.type)); + + lim_sys_process_mmh_msg_api(mac_ctx, &msg); +} + +void +lim_send_stop_bss_response(struct mac_context *mac_ctx, uint8_t vdev_id, + tSirResultCodes result_code) +{ + struct scheduler_msg msg = {0}; + struct stop_bss_rsp *stop_bss_rsp; + struct pe_session *pe_session; + struct pe_session *sta_session; + + pe_debug("Sending stop bss response with reasonCode: %s", + lim_result_code_str(result_code)); + + pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!pe_session) { + pe_err("Unable to find session for stop bss response"); + return; + } + + /* + * STA LPI + SAP VLP is supported. For this STA should operate in VLP + * power level of the SAP. + * + * For the STA, if the TPC is changed to VLP, then restore the original + * power for the STA when SAP disconnects. + */ + if (wlan_get_tpc_update_required_for_sta(pe_session->vdev)) { + sta_session = lim_get_concurrent_session(mac_ctx, vdev_id, + pe_session->opmode); + if (sta_session && + sta_session->curr_op_freq == pe_session->curr_op_freq) + lim_update_tx_power(mac_ctx, pe_session, + sta_session, true); + } + + stop_bss_rsp = qdf_mem_malloc(sizeof(*stop_bss_rsp)); + if (!stop_bss_rsp) + return; + + stop_bss_rsp->status_code = result_code; + stop_bss_rsp->vdev_id = vdev_id; + + msg.type = eWNI_SME_STOP_BSS_RSP; + msg.bodyptr = stop_bss_rsp; + msg.bodyval = 0; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + NULL, (uint16_t) result_code, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_sys_process_mmh_msg_api(mac_ctx, &msg); +} + +#ifdef WLAN_FEATURE_11AX +/** + * lim_get_he_rate_info_flag() - Get he tx rate info flag + * @sta_ds: Pointer to station ds structure + * + * This function is called to get the he tx rate info. + * + * Return: Returns he tx rate flag + */ +static enum tx_rate_info +lim_get_he_rate_info_flag(tpDphHashNode sta_ds) +{ + tDot11fIEhe_cap *peer_he = &sta_ds->he_config; + + if (peer_he->chan_width_3 || peer_he->chan_width_2) + return TX_RATE_HE160; + else if (peer_he->chan_width_1) + return TX_RATE_HE80; + else if (peer_he->chan_width_0) + return TX_RATE_HE40; + else + return TX_RATE_HE20; +} +#else +static enum tx_rate_info +lim_get_he_rate_info_flag(tpDphHashNode sta_ds) +{ + return TX_RATE_LEGACY; +} +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * lim_get_eht_rate_info_flag() - Get eht tx rate info flag + * @sta_ds: Pointer to station ds structure + * + * This function is called to get the eht tx rate info. + * + * Return: Returns eht tx rate flag + */ +static enum tx_rate_info +lim_get_eht_rate_info_flag(tpDphHashNode sta_ds) +{ + if (sta_ds->eht_config.support_320mhz_6ghz) + return TX_RATE_EHT320; + else if (sta_ds->ch_width == CH_WIDTH_160MHZ) + return TX_RATE_EHT160; + else if (sta_ds->ch_width == CH_WIDTH_80MHZ) + return TX_RATE_EHT80; + else if (sta_ds->ch_width == CH_WIDTH_40MHZ) + return TX_RATE_EHT40; + else + return TX_RATE_EHT20; +} +#else +static enum tx_rate_info +lim_get_eht_rate_info_flag(tpDphHashNode sta_ds) +{ + return TX_RATE_LEGACY; +} +#endif + +/** + * lim_get_max_rate_flags() - Get rate flags + * @mac_ctx: Pointer to global MAC structure + * @sta_ds: Pointer to station ds structure + * + * This function is called to get the rate flags for a connection + * from the station ds structure depending on the ht and the vht + * channel width supported. + * + * Return: Returns the populated rate_flags + */ +uint32_t lim_get_max_rate_flags(struct mac_context *mac_ctx, tpDphHashNode sta_ds) +{ + uint32_t rate_flags = 0; + + if (!sta_ds) { + pe_err("sta_ds is NULL"); + return rate_flags; + } + + if (!lim_is_sta_eht_capable(sta_ds) && + !sta_ds->mlmStaContext.htCapability && + !sta_ds->mlmStaContext.vhtCapability && + !lim_is_sta_he_capable(sta_ds)) { + rate_flags |= TX_RATE_LEGACY; + } else { + if (lim_is_sta_eht_capable(sta_ds)) { + rate_flags |= lim_get_eht_rate_info_flag(sta_ds); + } else if (lim_is_sta_he_capable(sta_ds)) { + rate_flags |= lim_get_he_rate_info_flag(sta_ds); + } else if (sta_ds->mlmStaContext.vhtCapability) { + if (WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ == + sta_ds->vhtSupportedChannelWidthSet || + WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ == + sta_ds->vhtSupportedChannelWidthSet) { + rate_flags |= TX_RATE_VHT160; + } else if (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ == + sta_ds->vhtSupportedChannelWidthSet) { + rate_flags |= TX_RATE_VHT80; + } else if (WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ == + sta_ds->vhtSupportedChannelWidthSet) { + if (sta_ds->htSupportedChannelWidthSet) + rate_flags |= TX_RATE_VHT40; + else + rate_flags |= TX_RATE_VHT20; + } + } else if (sta_ds->mlmStaContext.htCapability) { + if (sta_ds->htSupportedChannelWidthSet) + rate_flags |= TX_RATE_HT40; + else + rate_flags |= TX_RATE_HT20; + } + } + + if (sta_ds->htShortGI20Mhz || sta_ds->htShortGI40Mhz) + rate_flags |= TX_RATE_SGI; + + return rate_flags; +} + +static void lim_send_smps_intolerent(struct mac_context *mac_ctx, + struct pe_session *pe_session, + uint32_t bcn_len, uint8_t *bcn_ptr) +{ + const uint8_t *vendor_ap_1; + uint32_t bcn_ie_len; + uint8_t *bcn_ie_ptr; + + if (!bcn_ptr || (bcn_len <= (sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)))) + return; + + bcn_ie_len = bcn_len - sizeof(struct wlan_frame_hdr) - + offsetof(struct wlan_bcn_frame, ie); + bcn_ie_ptr = bcn_ptr + sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie); + + vendor_ap_1 = + wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_VENDOR_AP_1_OUI, + SIR_MAC_VENDOR_AP_1_OUI_LEN, + bcn_ie_ptr, bcn_ie_len); + if (mac_ctx->roam.configParam.is_force_1x1 && + vendor_ap_1 && (pe_session->nss == 2) && + (!mac_ctx->mlme_cfg->gen.as_enabled || + wlan_reg_is_5ghz_ch_freq(pe_session->curr_op_freq))) { + /* SET vdev param */ + pe_debug("sending SMPS intolrent vdev_param"); + wma_cli_set_command(pe_session->vdev_id, + (int)wmi_vdev_param_smps_intolerant, + 1, VDEV_CMD); + } +} + +#ifdef WLAN_FEATURE_FILS_SK +static void lim_set_fils_connection(struct wlan_cm_connect_resp *connect_rsp, + struct pe_session *session_entry) +{ + if (lim_is_fils_connection(session_entry)) + connect_rsp->is_fils_connection = true; + pe_debug("is_fils_connection %d", connect_rsp->is_fils_connection); +} +#else +static inline +void lim_set_fils_connection(struct wlan_cm_connect_resp *connect_rsp, + struct pe_session *session_entry) +{} +#endif + +#ifdef FEATURE_WLAN_ESE +static void lim_copy_tspec_ie(struct pe_session *pe_session, + struct cm_vdev_join_rsp *rsp) +{ + if (pe_session->tspecIes) { + rsp->tspec_ie.len = pe_session->tspecLen; + rsp->tspec_ie.ptr = + qdf_mem_malloc(rsp->tspec_ie.len); + if (!rsp->tspec_ie.ptr) + return; + + qdf_mem_copy(rsp->tspec_ie.ptr, pe_session->tspecIes, + rsp->tspec_ie.len); + pe_debug("ESE-TspecLen: %d", rsp->tspec_ie.len); + } +} + +static void lim_free_tspec_ie(struct pe_session *pe_session) +{ + if (pe_session->tspecIes) { + qdf_mem_free(pe_session->tspecIes); + pe_session->tspecIes = NULL; + pe_session->tspecLen = 0; + } +} +#else +static inline void lim_copy_tspec_ie(struct pe_session *pe_session, + struct cm_vdev_join_rsp *rsp) +{} +static inline void lim_free_tspec_ie(struct pe_session *pe_session) +{} +#endif + +static void lim_cm_fill_rsp_from_stads(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct cm_vdev_join_rsp *rsp) +{ + tpDphHashNode sta_ds; + + sta_ds = dph_get_hash_entry(mac_ctx, + DPH_STA_HASH_INDEX_PEER, + &pe_session->dph.dphHashTable); + if (!sta_ds) + return; + + rsp->nss = sta_ds->nss; +} + +static QDF_STATUS +lim_cm_prepare_join_rsp_from_pe_session(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct cm_vdev_join_rsp *rsp, + enum wlan_cm_connect_fail_reason reason, + QDF_STATUS connect_status, + enum wlan_status_code status_code) +{ + struct wlan_cm_connect_resp *connect_rsp = &rsp->connect_rsp; + struct wlan_connect_rsp_ies *connect_ie = &rsp->connect_rsp.connect_ies; + uint32_t bcn_len; + uint8_t *bcn_ptr; + + connect_rsp->cm_id = pe_session->cm_id; + connect_rsp->vdev_id = pe_session->vdev_id; + qdf_ether_addr_copy(connect_rsp->bssid.bytes, pe_session->bssId); + wlan_cm_connect_resp_fill_mld_addr_from_cm_id(pe_session->vdev, + pe_session->cm_id, + connect_rsp); + connect_rsp->freq = pe_session->curr_op_freq; + connect_rsp->connect_status = connect_status; + connect_rsp->reason = reason; + connect_rsp->status_code = status_code; + connect_rsp->ssid.length = + QDF_MIN(WLAN_SSID_MAX_LEN, pe_session->ssId.length); + qdf_mem_copy(connect_rsp->ssid.ssid, pe_session->ssId.ssId, + connect_rsp->ssid.length); + + lim_set_fils_connection(connect_rsp, pe_session); + if (pe_session->beacon) { + connect_ie->bcn_probe_rsp.len = pe_session->bcnLen; + connect_ie->bcn_probe_rsp.ptr = + qdf_mem_malloc(connect_ie->bcn_probe_rsp.len); + if (!connect_ie->bcn_probe_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(connect_ie->bcn_probe_rsp.ptr, pe_session->beacon, + connect_ie->bcn_probe_rsp.len); + } + bcn_len = connect_ie->bcn_probe_rsp.len; + bcn_ptr = connect_ie->bcn_probe_rsp.ptr; + + if (pe_session->assoc_req) { + connect_ie->assoc_req.len = pe_session->assocReqLen; + connect_ie->assoc_req.ptr = + qdf_mem_malloc(connect_ie->assoc_req.len); + if (!connect_ie->assoc_req.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(connect_ie->assoc_req.ptr, pe_session->assoc_req, + connect_ie->assoc_req.len); + } + + if (pe_session->assocRsp) { + connect_ie->assoc_rsp.len = pe_session->assocRspLen; + connect_ie->assoc_rsp.ptr = + qdf_mem_malloc(connect_ie->assoc_rsp.len); + if (!connect_ie->assoc_rsp.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(connect_ie->assoc_rsp.ptr, pe_session->assocRsp, + connect_ie->assoc_rsp.len); + } + connect_rsp->is_wps_connection = pe_session->wps_registration; + connect_rsp->is_osen_connection = pe_session->isOSENConnection; + + if (QDF_IS_STATUS_SUCCESS(connect_status)) { + connect_rsp->status_code = STATUS_SUCCESS; + populate_fils_connect_params(mac_ctx, pe_session, connect_rsp); + connect_rsp->aid = pe_session->limAID; + + /* move ric date to cm_vdev_join_rsp to fill in csr session */ + if (pe_session->ricData) { + rsp->ric_resp_ie.len = pe_session->RICDataLen; + rsp->ric_resp_ie.ptr = + qdf_mem_malloc(rsp->ric_resp_ie.len); + if (!rsp->ric_resp_ie.ptr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(rsp->ric_resp_ie.ptr, pe_session->ricData, + rsp->ric_resp_ie.len); + } + + lim_copy_tspec_ie(pe_session, rsp); + + lim_send_smps_intolerent(mac_ctx, pe_session, bcn_len, bcn_ptr); + lim_cm_fill_rsp_from_stads(mac_ctx, pe_session, rsp); + rsp->uapsd_mask = pe_session->gUapsdPerAcBitmask; + } + + return QDF_STATUS_SUCCESS; +} + +static void +lim_cm_fill_join_rsp_from_connect_req(struct cm_vdev_join_req *req, + struct cm_vdev_join_rsp *rsp, + enum wlan_cm_connect_fail_reason reason) +{ + struct wlan_cm_connect_resp *connect_rsp = &rsp->connect_rsp; + + connect_rsp->cm_id = req->cm_id; + connect_rsp->vdev_id = req->vdev_id; + qdf_copy_macaddr(&connect_rsp->bssid, &req->entry->bssid); + connect_rsp->freq = req->entry->channel.chan_freq; + connect_rsp->connect_status = QDF_STATUS_E_FAILURE; + connect_rsp->reason = reason; + connect_rsp->ssid = req->entry->ssid; + connect_rsp->is_wps_connection = req->is_wps_connection; + connect_rsp->is_osen_connection = req->is_osen_connection; + wlan_cm_connect_resp_fill_mld_addr_from_vdev_id(rsp->psoc, req->vdev_id, + req->entry, + connect_rsp); +} + +static QDF_STATUS lim_cm_flush_connect_rsp(struct scheduler_msg *msg) +{ + struct cm_vdev_join_rsp *rsp; + + if (!msg || !msg->bodyptr) + return QDF_STATUS_E_INVAL; + + rsp = msg->bodyptr; + wlan_cm_free_connect_rsp(rsp); + + return QDF_STATUS_SUCCESS; +} + +static void lim_free_pession_ies(struct pe_session *pe_session) +{ + if (pe_session->beacon) { + qdf_mem_free(pe_session->beacon); + pe_session->beacon = NULL; + pe_session->bcnLen = 0; + } + if (pe_session->assoc_req) { + qdf_mem_free(pe_session->assoc_req); + pe_session->assoc_req = NULL; + pe_session->assocReqLen = 0; + } + if (pe_session->assocRsp) { + qdf_mem_free(pe_session->assocRsp); + pe_session->assocRsp = NULL; + pe_session->assocRspLen = 0; + } + if (pe_session->ricData) { + qdf_mem_free(pe_session->ricData); + pe_session->ricData = NULL; + pe_session->RICDataLen = 0; + } + lim_free_tspec_ie(pe_session); +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void lim_copy_ml_partner_info(struct cm_vdev_join_rsp *rsp, + struct pe_session *pe_session) +{ + int i; + struct mlo_partner_info *partner_info; + struct mlo_partner_info *rsp_partner_info; + uint8_t chan = 0, op_class, link_id; + + partner_info = &pe_session->ml_partner_info; + rsp_partner_info = &rsp->connect_rsp.ml_parnter_info; + + rsp_partner_info->num_partner_links = partner_info->num_partner_links; + + for (i = 0; i < rsp_partner_info->num_partner_links; i++) { + link_id = partner_info->partner_link_info[i].link_id; + rsp_partner_info->partner_link_info[i].link_id = link_id; + qdf_copy_macaddr( + &rsp_partner_info->partner_link_info[i].link_addr, + &partner_info->partner_link_info[i].link_addr); + + wlan_get_chan_by_bssid_from_rnr( + pe_session->vdev, + pe_session->cm_id, + &partner_info->partner_link_info[i].link_addr, + &chan, &op_class); + if (!chan) + wlan_get_chan_by_link_id_from_rnr( + pe_session->vdev, + pe_session->cm_id, + link_id, &chan, &op_class); + if (chan) { + rsp_partner_info->partner_link_info[i].chan_freq = + wlan_reg_chan_opclass_to_freq_auto(chan, + op_class, + false); + } else { + pe_debug("Failed to get channel info for link ID:%d", + link_id); + } + } +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +lim_copy_ml_partner_info(struct cm_vdev_join_rsp *rsp, + struct pe_session *pe_session) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +void lim_cm_send_connect_rsp(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct cm_vdev_join_req *req, + enum wlan_cm_connect_fail_reason reason, + QDF_STATUS connect_status, + enum wlan_status_code status_code, + bool is_reassoc) +{ + struct cm_vdev_join_rsp *rsp; + QDF_STATUS status; + struct scheduler_msg msg; + + if (!pe_session && !req) + return; + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return; + + rsp->psoc = mac_ctx->psoc; + + if (!pe_session) { + lim_cm_fill_join_rsp_from_connect_req(req, rsp, reason); + } else { + status = + lim_cm_prepare_join_rsp_from_pe_session(mac_ctx, + pe_session, + rsp, + reason, + connect_status, + status_code); + lim_free_pession_ies(pe_session); + lim_copy_ml_partner_info(rsp, pe_session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("vdev_id: %d cm_id 0x%x : fail to prepare rsp", + rsp->connect_rsp.vdev_id, + rsp->connect_rsp.cm_id); + wlan_cm_free_connect_rsp(rsp); + return; + } + } + + rsp->connect_rsp.is_reassoc = is_reassoc; + qdf_mem_zero(&msg, sizeof(msg)); + + msg.bodyptr = rsp; + msg.callback = wlan_cm_send_connect_rsp; + msg.flush_callback = lim_cm_flush_connect_rsp; + + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &msg); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("vdev_id: %d cm_id 0x%x : msg post fails", + rsp->connect_rsp.vdev_id, rsp->connect_rsp.cm_id); + wlan_cm_free_connect_rsp(rsp); + } +} + +static enum wlan_cm_connect_fail_reason +lim_cm_get_fail_reason_from_result_code(tSirResultCodes result_code) +{ + enum wlan_cm_connect_fail_reason fail_reason; + + switch (result_code) { + case eSIR_SME_JOIN_TIMEOUT_RESULT_CODE: + fail_reason = CM_JOIN_TIMEOUT; + break; + case eSIR_SME_AUTH_TIMEOUT_RESULT_CODE: + fail_reason = CM_AUTH_TIMEOUT; + break; + case eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE: + case eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE: + case eSIR_SME_FT_REASSOC_TIMEOUT_FAILURE: + fail_reason = CM_ASSOC_TIMEOUT; + break; + case eSIR_SME_AUTH_REFUSED: + case eSIR_SME_INVALID_WEP_DEFAULT_KEY: + fail_reason = CM_AUTH_FAILED; + break; + case eSIR_SME_ASSOC_REFUSED: + case eSIR_SME_REASSOC_REFUSED: + case eSIR_SME_FT_REASSOC_FAILURE: + case eSIR_SME_INVALID_ASSOC_RSP_RXED: + case eSIR_SME_JOIN_DEAUTH_FROM_AP_DURING_ADD_STA: + fail_reason = CM_ASSOC_FAILED; + break; + default: + fail_reason = CM_JOIN_FAILED; + break; + } + + return fail_reason; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM +static +void lim_send_assoc_rsp_diag_event(struct mac_context *mac_ctx, + struct pe_session *session_entry, + uint16_t msg_type, uint16_t result_code) +{ + if (msg_type == eWNI_SME_REASSOC_RSP) + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_REASSOC_RSP_EVENT, + session_entry, result_code, 0); + else + lim_diag_event_report(mac_ctx, WLAN_PE_DIAG_JOIN_RSP_EVENT, + session_entry, result_code, 0); +} +#else +static inline +void lim_send_assoc_rsp_diag_event(struct mac_context *mac_ctx, + struct pe_session *session_entry, + uint16_t msg_type, uint16_t result_code) +{} +#endif + +void lim_send_sme_join_reassoc_rsp(struct mac_context *mac_ctx, + uint16_t msg_type, + tSirResultCodes result_code, + uint16_t prot_status_code, + struct pe_session *session_entry, + uint8_t vdev_id) +{ + QDF_STATUS connect_status; + enum wlan_cm_connect_fail_reason fail_reason = 0; + + lim_send_assoc_rsp_diag_event(mac_ctx, session_entry, msg_type, + result_code); + + pe_debug("Sending message: %s with reasonCode: %s", + lim_msg_str(msg_type), lim_result_code_str(result_code)); + + if (result_code == eSIR_SME_SUCCESS) { + connect_status = QDF_STATUS_SUCCESS; + } else { + connect_status = QDF_STATUS_E_FAILURE; + fail_reason = + lim_cm_get_fail_reason_from_result_code(result_code); + } + + return lim_cm_send_connect_rsp(mac_ctx, session_entry, NULL, + fail_reason, connect_status, + prot_status_code, + msg_type == eWNI_SME_JOIN_RSP ? + false : true); + + /* add reassoc resp API */ +} + +void lim_send_sme_start_bss_rsp(struct mac_context *mac, + tSirResultCodes resultCode, + struct pe_session *pe_session, + uint8_t smesessionId) +{ + + struct scheduler_msg mmhMsg = {0}; + struct start_bss_rsp *start_bss_rsp; + + pe_debug("Sending start bss response with reasonCode: %s", + lim_result_code_str(resultCode)); + + start_bss_rsp = qdf_mem_malloc(sizeof(*start_bss_rsp)); + if (!start_bss_rsp) + return; + start_bss_rsp->vdev_id = smesessionId; + start_bss_rsp->status_code = resultCode; + + mmhMsg.type = eWNI_SME_START_BSS_RSP; + mmhMsg.bodyptr = start_bss_rsp; + mmhMsg.bodyval = 0; + if (!pe_session) { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_START_BSS_RSP_EVENT, + pe_session, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); +} /*** end lim_send_sme_start_bss_rsp() ***/ + +static void lim_send_sta_disconnect_ind(struct mac_context *mac, + struct scheduler_msg *msg) +{ + struct cm_vdev_discon_ind *ind; + struct disassoc_ind *disassoc; + struct deauth_ind *deauth; + struct scheduler_msg ind_msg = {0}; + QDF_STATUS status; + + ind = qdf_mem_malloc(sizeof(*ind)); + if (!ind) { + qdf_mem_free(msg->bodyptr); + return; + } + + ind->psoc = mac->psoc; + if (msg->type == eWNI_SME_DISASSOC_IND) { + disassoc = (struct disassoc_ind *)msg->bodyptr; + ind->disconnect_param.vdev_id = disassoc->vdev_id; + ind->disconnect_param.bssid = disassoc->bssid; + ind->disconnect_param.reason_code = disassoc->reasonCode; + if (disassoc->from_ap) + ind->disconnect_param.source = CM_PEER_DISCONNECT; + else + ind->disconnect_param.source = CM_SB_DISCONNECT; + } else { + deauth = (struct deauth_ind *)msg->bodyptr; + ind->disconnect_param.vdev_id = deauth->vdev_id; + ind->disconnect_param.bssid = deauth->bssid; + ind->disconnect_param.reason_code = deauth->reasonCode; + if (deauth->from_ap) + ind->disconnect_param.source = CM_PEER_DISCONNECT; + else + ind->disconnect_param.source = CM_SB_DISCONNECT; + } + ind_msg.bodyptr = ind; + ind_msg.callback = cm_send_sb_disconnect_req; + ind_msg.type = msg->type; + qdf_mem_free(msg->bodyptr); + + status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &ind_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("vdev_id: %d, source %d, reason %d, type %d msg post fails", + ind->disconnect_param.vdev_id, + ind->disconnect_param.source, + ind->disconnect_param.reason_code, ind_msg.type); + qdf_mem_free(ind); + } +} + +void lim_cm_send_disconnect_rsp(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + QDF_STATUS status; + struct scheduler_msg rsp_msg = {0}; + struct cm_vdev_disconnect_rsp *rsp; + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (!rsp) + return; + + rsp->vdev_id = vdev_id; + rsp->psoc = mac_ctx->psoc; + + rsp_msg.bodyptr = rsp; + rsp_msg.callback = cm_handle_disconnect_resp; + + status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_OS_IF, &rsp_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to post disconnect rsp to sme vdev_id %d", + vdev_id); + qdf_mem_free(rsp); + } +} + +static void lim_sap_send_sme_disassoc_deauth_ntf(struct mac_context *mac, + QDF_STATUS status, + uint32_t *pCtx) +{ + struct scheduler_msg mmhMsg = {0}; + struct scheduler_msg *pMsg = (struct scheduler_msg *)pCtx; + + mmhMsg.type = pMsg->type; + mmhMsg.bodyptr = pMsg; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, NO_SESSION, mmhMsg.type)); + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); +} + +void lim_send_sme_disassoc_deauth_ntf(struct mac_context *mac, + QDF_STATUS status, uint32_t *pCtx) +{ + struct scheduler_msg *msg = (struct scheduler_msg *)pCtx; + struct disassoc_rsp *disassoc; + struct deauth_rsp *deauth; + struct sir_sme_discon_done_ind *discon; + uint8_t vdev_id; + enum QDF_OPMODE opmode; + + switch (msg->type) { + case eWNI_SME_DISASSOC_RSP: + disassoc = (struct disassoc_rsp *)pCtx; + vdev_id = disassoc->sessionId; + break; + case eWNI_SME_DEAUTH_RSP: + deauth = (struct deauth_rsp *)pCtx; + vdev_id = deauth->sessionId; + break; + case eWNI_SME_DISCONNECT_DONE_IND: + discon = (struct sir_sme_discon_done_ind *)pCtx; + vdev_id = discon->session_id; + break; + default: + pe_err("Received invalid disconnect rsp type %d", msg->type); + qdf_mem_free(pCtx); + return; + } + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, vdev_id); + /* Use connection manager for STA and CLI */ + if (opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) { + qdf_mem_free(pCtx); + lim_cm_send_disconnect_rsp(mac, vdev_id); + return; + } + + lim_sap_send_sme_disassoc_deauth_ntf(mac, status, pCtx); +} + +void lim_send_sme_disassoc_ntf(struct mac_context *mac, + tSirMacAddr peerMacAddr, + tSirMacAddr peerMldAddr, + tSirResultCodes reasonCode, + uint16_t disassocTrigger, + uint16_t aid, + uint8_t smesessionId, + struct pe_session *pe_session) +{ + struct disassoc_rsp *pSirSmeDisassocRsp; + struct disassoc_ind *pSirSmeDisassocInd = NULL; + uint32_t *pMsg = NULL; + bool failure = false; + struct pe_session *session = NULL; + uint16_t i, assoc_id; + tpDphHashNode sta_ds = NULL; + QDF_STATUS status; + enum QDF_OPMODE opmode; + + pe_debug("Disassoc Ntf with trigger : %d reasonCode: %d", + disassocTrigger, reasonCode); + + switch (disassocTrigger) { + case eLIM_DUPLICATE_ENTRY: + /* + * Duplicate entry is removed at LIM. + * Initiate new entry for other session + */ + pe_debug("Rcvd eLIM_DUPLICATE_ENTRY for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peerMacAddr)); + + for (i = 0; i < mac->lim.maxBssId; i++) { + session = &mac->lim.gpSession[i]; + if (session->valid && + (session->opmode == QDF_SAP_MODE)) { + /* Find the sta ds entry in another session */ + sta_ds = lim_get_sta_ds(mac, peerMacAddr, + peerMldAddr, &assoc_id, + session); + if (sta_ds) + break; + } + } + if (sta_ds) { + if (lim_add_sta(mac, sta_ds, false, session) != + QDF_STATUS_SUCCESS) + pe_err("could not Add STA with assocId: %d", + sta_ds->assocId); + } + status = lim_prepare_disconnect_done_ind(mac, &pMsg, + smesessionId, + reasonCode, + &peerMacAddr[0]); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed to prepare message"); + return; + } + break; + + case eLIM_HOST_DISASSOC: + /** + * Disassociation response due to + * host triggered disassociation + */ + + pSirSmeDisassocRsp = qdf_mem_malloc(sizeof(struct disassoc_rsp)); + if (!pSirSmeDisassocRsp) { + failure = true; + goto error; + } + pe_debug("send eWNI_SME_DISASSOC_RSP with retCode: %d for " + QDF_MAC_ADDR_FMT, + reasonCode, QDF_MAC_ADDR_REF(peerMacAddr)); + pSirSmeDisassocRsp->messageType = eWNI_SME_DISASSOC_RSP; + pSirSmeDisassocRsp->length = sizeof(struct disassoc_rsp); + pSirSmeDisassocRsp->sessionId = smesessionId; + pSirSmeDisassocRsp->status_code = reasonCode; + qdf_mem_copy(pSirSmeDisassocRsp->peer_macaddr.bytes, + peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + pe_session, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocRsp; + break; + + case eLIM_PEER_ENTITY_DISASSOC: + case eLIM_LINK_MONITORING_DISASSOC: + status = lim_prepare_disconnect_done_ind(mac, &pMsg, + smesessionId, + reasonCode, &peerMacAddr[0]); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed to prepare message"); + return; + } + break; + + default: + /** + * Disassociation indication due to Disassociation + * frame reception from peer entity or due to + * loss of link with peer entity. + */ + pSirSmeDisassocInd = + qdf_mem_malloc(sizeof(*pSirSmeDisassocInd)); + if (!pSirSmeDisassocInd) { + failure = true; + goto error; + } + pe_debug("send eWNI_SME_DISASSOC_IND with retCode: %d for " + QDF_MAC_ADDR_FMT, + reasonCode, QDF_MAC_ADDR_REF(peerMacAddr)); + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(*pSirSmeDisassocInd); + pSirSmeDisassocInd->vdev_id = smesessionId; + pSirSmeDisassocInd->reasonCode = reasonCode; + pSirSmeDisassocInd->status_code = reasonCode; + qdf_mem_copy(pSirSmeDisassocInd->bssid.bytes, + pe_session->bssId, sizeof(tSirMacAddr)); + qdf_mem_copy(pSirSmeDisassocInd->peer_macaddr.bytes, + peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, + pe_session, (uint16_t) reasonCode, 0); +#endif + pMsg = (uint32_t *) pSirSmeDisassocInd; + + break; + } + +error: + /* Delete the PE session Created */ + if ((pe_session) && LIM_IS_STA_ROLE(pe_session)) + pe_delete_session(mac, pe_session); + + if (failure) + return; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, smesessionId); + if ((opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) && + pSirSmeDisassocInd && + pSirSmeDisassocInd->messageType == eWNI_SME_DISASSOC_IND) { + struct scheduler_msg msg = {0}; + + msg.type = pSirSmeDisassocInd->messageType; + msg.bodyptr = pSirSmeDisassocInd; + + return lim_send_sta_disconnect_ind(mac, &msg); + } + + lim_send_sme_disassoc_deauth_ntf(mac, QDF_STATUS_SUCCESS, + (uint32_t *)pMsg); +} /*** end lim_send_sme_disassoc_ntf() ***/ + +static bool lim_is_disconnect_from_ap(enum eLimDisassocTrigger trigger) +{ + if (trigger == eLIM_PEER_ENTITY_DEAUTH || + trigger == eLIM_PEER_ENTITY_DISASSOC) + return true; + + return false; +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_disassoc_ind() - sends SME_DISASSOC_IND + + After receiving disassociation frame from peer entity, this + function sends a eWNI_SME_DISASSOC_IND to SME with a specific + reason code. + + \param mac - global mac structure + \param sta - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_disassoc_ind(struct mac_context *mac, tpDphHashNode sta, + struct pe_session *pe_session) +{ + struct scheduler_msg mmhMsg = {0}; + struct disassoc_ind *pSirSmeDisassocInd; + + pSirSmeDisassocInd = qdf_mem_malloc(sizeof(*pSirSmeDisassocInd)); + if (!pSirSmeDisassocInd) + return; + + pSirSmeDisassocInd->messageType = eWNI_SME_DISASSOC_IND; + pSirSmeDisassocInd->length = sizeof(*pSirSmeDisassocInd); + + pSirSmeDisassocInd->vdev_id = pe_session->smeSessionId; + pSirSmeDisassocInd->status_code = eSIR_SME_DEAUTH_STATUS; + pSirSmeDisassocInd->reasonCode = sta->mlmStaContext.disassocReason; + + qdf_mem_copy(pSirSmeDisassocInd->bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + + qdf_mem_copy(pSirSmeDisassocInd->peer_macaddr.bytes, sta->staAddr, + QDF_MAC_ADDR_SIZE); + + if (LIM_IS_STA_ROLE(pe_session)) + pSirSmeDisassocInd->from_ap = + lim_is_disconnect_from_ap(sta->mlmStaContext.cleanupTrigger); + + mmhMsg.type = eWNI_SME_DISASSOC_IND; + mmhMsg.bodyptr = pSirSmeDisassocInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DISASSOC_IND_EVENT, pe_session, + 0, (uint16_t) sta->mlmStaContext.disassocReason); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (LIM_IS_STA_ROLE(pe_session)) + return lim_send_sta_disconnect_ind(mac, &mmhMsg); + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + +} /*** end lim_send_sme_disassoc_ind() ***/ + +/** ----------------------------------------------------------------- + \brief lim_send_sme_deauth_ind() - sends SME_DEAUTH_IND + + After receiving deauthentication frame from peer entity, this + function sends a eWNI_SME_DEAUTH_IND to SME with a specific + reason code. + + \param mac - global mac structure + \param sta - station dph hash node + \return none + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_deauth_ind(struct mac_context *mac, tpDphHashNode sta, + struct pe_session *pe_session) +{ + struct scheduler_msg mmhMsg = {0}; + struct deauth_ind *pSirSmeDeauthInd; + + pSirSmeDeauthInd = qdf_mem_malloc(sizeof(*pSirSmeDeauthInd)); + if (!pSirSmeDeauthInd) + return; + + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(*pSirSmeDeauthInd); + + pSirSmeDeauthInd->vdev_id = pe_session->smeSessionId; + if (eSIR_INFRA_AP_MODE == pe_session->bssType) { + pSirSmeDeauthInd->status_code = + (tSirResultCodes) sta->mlmStaContext.cleanupTrigger; + } else { + /* Need to indicate the reason code over the air */ + pSirSmeDeauthInd->status_code = + (tSirResultCodes) sta->mlmStaContext.disassocReason; + } + /* BSSID */ + qdf_mem_copy(pSirSmeDeauthInd->bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + /* peerMacAddr */ + qdf_mem_copy(pSirSmeDeauthInd->peer_macaddr.bytes, sta->staAddr, + QDF_MAC_ADDR_SIZE); + pSirSmeDeauthInd->reasonCode = sta->mlmStaContext.disassocReason; + + if (sta->mlmStaContext.disassocReason == REASON_STA_LEAVING) + pSirSmeDeauthInd->rssi = sta->del_sta_ctx_rssi; + + if (LIM_IS_STA_ROLE(pe_session)) + pSirSmeDeauthInd->from_ap = + lim_is_disconnect_from_ap(sta->mlmStaContext.cleanupTrigger); + + mmhMsg.type = eWNI_SME_DEAUTH_IND; + mmhMsg.bodyptr = pSirSmeDeauthInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, pe_session, + 0, sta->mlmStaContext.cleanupTrigger); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (LIM_IS_STA_ROLE(pe_session)) + return lim_send_sta_disconnect_ind(mac, &mmhMsg); + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + return; +} /*** end lim_send_sme_deauth_ind() ***/ + +#ifdef FEATURE_WLAN_TDLS +/** + * lim_send_sme_tdls_del_sta_ind() + * + ***FUNCTION: + * This function is called to send the TDLS STA context deletion to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param mac - Pointer to global MAC structure + * @param sta - Pointer to internal STA Datastructure + * @param pe_session - Pointer to the session entry + * @param reasonCode - Reason for TDLS sta deletion + * @return None + */ +void +lim_send_sme_tdls_del_sta_ind(struct mac_context *mac, tpDphHashNode sta, + struct pe_session *pe_session, uint16_t reasonCode) +{ + struct tdls_event_info info; + + pe_debug("Delete TDLS Peer "QDF_MAC_ADDR_FMT "with reason code: %d", + QDF_MAC_ADDR_REF(sta->staAddr), reasonCode); + info.vdev_id = pe_session->smeSessionId; + qdf_mem_copy(info.peermac.bytes, sta->staAddr, QDF_MAC_ADDR_SIZE); + info.message_type = TDLS_PEER_DISCONNECTED; + info.peer_reason = TDLS_DISCONNECTED_PEER_DELETE; + + tgt_tdls_event_handler(mac->psoc, &info); + + return; +} /*** end lim_send_sme_tdls_del_sta_ind() ***/ + +/** + * lim_send_sme_mgmt_tx_completion() + * + ***FUNCTION: + * This function is called to send the eWNI_SME_MGMT_FRM_TX_COMPLETION_IND + * message to SME. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param mac - Pointer to global MAC structure + * @param pe_session - Pointer to the session entry + * @param txCompleteStatus - TX Complete Status of Mgmt Frames + * @return None + */ +void +lim_send_sme_mgmt_tx_completion(struct mac_context *mac, + uint32_t vdev_id, + uint32_t txCompleteStatus) +{ + struct scheduler_msg msg = {0}; + struct tdls_mgmt_tx_completion_ind *mgmt_tx_completion_ind; + QDF_STATUS status; + + mgmt_tx_completion_ind = + qdf_mem_malloc(sizeof(*mgmt_tx_completion_ind)); + if (!mgmt_tx_completion_ind) + return; + + /* sessionId */ + mgmt_tx_completion_ind->vdev_id = vdev_id; + + mgmt_tx_completion_ind->tx_complete_status = txCompleteStatus; + + msg.type = eWNI_SME_MGMT_FRM_TX_COMPLETION_IND; + msg.bodyptr = mgmt_tx_completion_ind; + msg.bodyval = 0; + + mgmt_tx_completion_ind->psoc = mac->psoc; + msg.callback = tgt_tdls_send_mgmt_tx_completion; + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_TDLS, + QDF_MODULE_ID_TARGET_IF, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("post msg fail, %d", status); + qdf_mem_free(mgmt_tx_completion_ind); + } +} /*** end lim_send_sme_tdls_delete_all_peer_ind() ***/ + +#endif /* FEATURE_WLAN_TDLS */ + +QDF_STATUS lim_prepare_disconnect_done_ind(struct mac_context *mac_ctx, + uint32_t **msg, + uint8_t session_id, + tSirResultCodes reason_code, + uint8_t *peer_mac_addr) +{ + struct sir_sme_discon_done_ind *sir_sme_dis_ind; + + sir_sme_dis_ind = qdf_mem_malloc(sizeof(*sir_sme_dis_ind)); + if (!sir_sme_dis_ind) + return QDF_STATUS_E_FAILURE; + + pe_debug("Prepare eWNI_SME_DISCONNECT_DONE_IND withretCode: %d", + reason_code); + + sir_sme_dis_ind->message_type = eWNI_SME_DISCONNECT_DONE_IND; + sir_sme_dis_ind->length = sizeof(*sir_sme_dis_ind); + sir_sme_dis_ind->session_id = session_id; + if (peer_mac_addr) + qdf_mem_copy(sir_sme_dis_ind->peer_mac, + peer_mac_addr, ETH_ALEN); + + /* + * Instead of sending deauth reason code as 505 which is + * internal value(eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + * Send reason code as zero to Supplicant + */ + if (reason_code == eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE) + sir_sme_dis_ind->reason_code = 0; + else + sir_sme_dis_ind->reason_code = reason_code; + + *msg = (uint32_t *)sir_sme_dis_ind; + + return QDF_STATUS_SUCCESS; +} + +void lim_send_sme_deauth_ntf(struct mac_context *mac, tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, uint16_t deauthTrigger, + uint16_t aid, uint8_t smesessionId) +{ + uint8_t *pBuf; + struct deauth_rsp *pSirSmeDeauthRsp; + struct deauth_ind *pSirSmeDeauthInd = NULL; + struct pe_session *pe_session; + uint8_t sessionId; + uint32_t *pMsg = NULL; + QDF_STATUS status; + enum QDF_OPMODE opmode; + + pe_session = pe_find_session_by_bssid(mac, peerMacAddr, &sessionId); + switch (deauthTrigger) { + case eLIM_HOST_DEAUTH: + /** + * Deauthentication response to host triggered + * deauthentication. + */ + pSirSmeDeauthRsp = qdf_mem_malloc(sizeof(*pSirSmeDeauthRsp)); + if (!pSirSmeDeauthRsp) + return; + pe_debug("send eWNI_SME_DEAUTH_RSP with retCode: %d for " + QDF_MAC_ADDR_FMT, + reasonCode, QDF_MAC_ADDR_REF(peerMacAddr)); + pSirSmeDeauthRsp->messageType = eWNI_SME_DEAUTH_RSP; + pSirSmeDeauthRsp->length = sizeof(*pSirSmeDeauthRsp); + pSirSmeDeauthRsp->status_code = reasonCode; + pSirSmeDeauthRsp->sessionId = smesessionId; + + pBuf = (uint8_t *) pSirSmeDeauthRsp->peer_macaddr.bytes; + qdf_mem_copy(pBuf, peerMacAddr, sizeof(tSirMacAddr)); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + pe_session, 0, (uint16_t) reasonCode); +#endif + pMsg = (uint32_t *) pSirSmeDeauthRsp; + + break; + + case eLIM_PEER_ENTITY_DEAUTH: + case eLIM_LINK_MONITORING_DEAUTH: + status = lim_prepare_disconnect_done_ind(mac, &pMsg, + smesessionId, reasonCode, + &peerMacAddr[0]); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed to prepare message"); + return; + } + break; + default: + /** + * Deauthentication indication due to Deauthentication + * frame reception from peer entity or due to + * loss of link with peer entity. + */ + pSirSmeDeauthInd = qdf_mem_malloc(sizeof(*pSirSmeDeauthInd)); + if (!pSirSmeDeauthInd) + return; + pe_debug("send eWNI_SME_DEAUTH_IND with retCode: %d for " + QDF_MAC_ADDR_FMT, + reasonCode, QDF_MAC_ADDR_REF(peerMacAddr)); + pSirSmeDeauthInd->messageType = eWNI_SME_DEAUTH_IND; + pSirSmeDeauthInd->length = sizeof(*pSirSmeDeauthInd); + pSirSmeDeauthInd->reasonCode = REASON_UNSPEC_FAILURE; + pSirSmeDeauthInd->vdev_id = smesessionId; + pSirSmeDeauthInd->status_code = reasonCode; + qdf_mem_copy(pSirSmeDeauthInd->bssid.bytes, pe_session->bssId, + sizeof(tSirMacAddr)); + qdf_mem_copy(pSirSmeDeauthInd->peer_macaddr.bytes, peerMacAddr, + QDF_MAC_ADDR_SIZE); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DEAUTH_IND_EVENT, + pe_session, 0, (uint16_t) reasonCode); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pMsg = (uint32_t *) pSirSmeDeauthInd; + + break; + } + + /*Delete the PE session created */ + if (pe_session && LIM_IS_STA_ROLE(pe_session)) + pe_delete_session(mac, pe_session); + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, smesessionId); + if ((opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) && + pSirSmeDeauthInd && + pSirSmeDeauthInd->messageType == eWNI_SME_DEAUTH_IND) { + struct scheduler_msg msg = {0}; + + msg.type = pSirSmeDeauthInd->messageType; + msg.bodyptr = pSirSmeDeauthInd; + return lim_send_sta_disconnect_ind(mac, &msg); + } + + lim_send_sme_disassoc_deauth_ntf(mac, QDF_STATUS_SUCCESS, + (uint32_t *) pMsg); + +} /*** end lim_send_sme_deauth_ntf() ***/ + +void lim_send_sme_set_context_rsp(struct mac_context *mac, + struct qdf_mac_addr peer_macaddr, + uint16_t aid, + tSirResultCodes resultCode, + struct pe_session *pe_session, + uint8_t smesessionId) +{ + struct scheduler_msg mmhMsg = {0}; + struct set_context_rsp *set_context_rsp; + + set_context_rsp = qdf_mem_malloc(sizeof(*set_context_rsp)); + if (!set_context_rsp) + return; + + set_context_rsp->messageType = eWNI_SME_SETCONTEXT_RSP; + set_context_rsp->length = sizeof(*set_context_rsp); + set_context_rsp->status_code = resultCode; + + qdf_copy_macaddr(&set_context_rsp->peer_macaddr, &peer_macaddr); + + set_context_rsp->sessionId = smesessionId; + + mmhMsg.type = eWNI_SME_SETCONTEXT_RSP; + mmhMsg.bodyptr = set_context_rsp; + mmhMsg.bodyval = 0; + if (!pe_session) { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); + } + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + pe_session, (uint16_t) resultCode, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + mac->lim.sme_msg_callback(mac, &mmhMsg); +} /*** end lim_send_sme_set_context_rsp() ***/ + +void lim_send_sme_addts_rsp(struct mac_context *mac, + uint8_t rspReqd, uint32_t status, + struct pe_session *pe_session, + struct mac_tspec_ie tspec, + uint8_t smesessionId) +{ + tpSirAddtsRsp rsp; + struct scheduler_msg mmhMsg = {0}; + + if (!rspReqd) + return; + + rsp = qdf_mem_malloc(sizeof(tSirAddtsRsp)); + if (!rsp) + return; + + rsp->messageType = eWNI_SME_ADDTS_RSP; + rsp->rc = status; + rsp->rsp.status = (enum wlan_status_code)status; + rsp->rsp.tspec = tspec; + rsp->sessionId = smesessionId; + + mmhMsg.type = eWNI_SME_ADDTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (!pe_session) { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_ADDTS_RSP_EVENT, pe_session, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + return; +} + +void lim_send_sme_delts_rsp(struct mac_context *mac, tpSirDeltsReq delts, + uint32_t status, struct pe_session *pe_session, + uint8_t smesessionId) +{ + tpSirDeltsRsp rsp; + struct scheduler_msg mmhMsg = {0}; + + pe_debug("SendSmeDeltsRsp aid: %d tsid: %d up: %d status: %d", + delts->aid, + delts->req.tsinfo.traffic.tsid, + delts->req.tsinfo.traffic.userPrio, status); + if (!delts->rspReqd) + return; + + rsp = qdf_mem_malloc(sizeof(tSirDeltsRsp)); + if (!rsp) + return; + + if (pe_session) { + + rsp->aid = delts->aid; + qdf_copy_macaddr(&rsp->macaddr, &delts->macaddr); + qdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) &delts->req, + sizeof(struct delts_req_info)); + } + + rsp->messageType = eWNI_SME_DELTS_RSP; + rsp->rc = status; + rsp->sessionId = smesessionId; + + mmhMsg.type = eWNI_SME_DELTS_RSP; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + if (!pe_session) { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + NO_SESSION, mmhMsg.type)); + } else { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DELTS_RSP_EVENT, pe_session, + (uint16_t) status, 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); +} + +void +lim_send_sme_delts_ind(struct mac_context *mac, struct delts_req_info *delts, + uint16_t aid, struct pe_session *pe_session) +{ + tpSirDeltsRsp rsp; + struct scheduler_msg mmhMsg = {0}; + + pe_debug("SendSmeDeltsInd aid: %d tsid: %d up: %d", + aid, delts->tsinfo.traffic.tsid, delts->tsinfo.traffic.userPrio); + + rsp = qdf_mem_malloc(sizeof(tSirDeltsRsp)); + if (!rsp) + return; + + rsp->messageType = eWNI_SME_DELTS_IND; + rsp->rc = QDF_STATUS_SUCCESS; + rsp->aid = aid; + qdf_mem_copy((uint8_t *) &rsp->rsp, (uint8_t *) delts, sizeof(*delts)); + rsp->sessionId = pe_session->smeSessionId; + + mmhMsg.type = eWNI_SME_DELTS_IND; + mmhMsg.bodyptr = rsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, mmhMsg.type)); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_LIM /* FEATURE_WLAN_DIAG_SUPPORT */ + lim_diag_event_report(mac, WLAN_PE_DIAG_DELTS_IND_EVENT, pe_session, 0, + 0); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + lim_sys_process_mmh_msg_api(mac, &mmhMsg); +} + +#ifdef FEATURE_WLAN_ESE +/** + * lim_send_sme_pe_ese_tsm_rsp() - send tsm response + * @mac: Pointer to global mac structure + * @pStats: Pointer to TSM Stats + * + * This function is called to send tsm stats response to HDD. + * This function posts the result back to HDD. This is a response to + * HDD's request to get tsm stats. + * + * Return: None + */ +void lim_send_sme_pe_ese_tsm_rsp(struct mac_context *mac, + tAniGetTsmStatsRsp *pStats) +{ + struct scheduler_msg mmhMsg = {0}; + uint8_t sessionId; + tAniGetTsmStatsRsp *pPeStats = (tAniGetTsmStatsRsp *) pStats; + struct pe_session *pPeSessionEntry = NULL; + + /* Get the Session Id based on Sta Id */ + pPeSessionEntry = pe_find_session_by_bssid(mac, pPeStats->bssid.bytes, + &sessionId); + /* Fill the Session Id */ + if (pPeSessionEntry) { + /* Fill the Session Id */ + pPeStats->sessionId = pPeSessionEntry->smeSessionId; + } else { + pe_err("Session not found for the Sta peer:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pPeStats->bssid.bytes)); + qdf_mem_free(pPeStats->tsmStatsReq); + qdf_mem_free(pPeStats); + return; + } + + pPeStats->msgType = eWNI_SME_GET_TSM_STATS_RSP; + pPeStats->tsmMetrics.RoamingCount + = pPeSessionEntry->eseContext.tsm.tsmMetrics.RoamingCount; + pPeStats->tsmMetrics.RoamingDly + = pPeSessionEntry->eseContext.tsm.tsmMetrics.RoamingDly; + + mmhMsg.type = eWNI_SME_GET_TSM_STATS_RSP; + mmhMsg.bodyptr = pStats; + mmhMsg.bodyval = 0; + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, sessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + + return; +} /*** end lim_send_sme_pe_ese_tsm_rsp() ***/ + +#endif /* FEATURE_WLAN_ESE */ + +/** + * lim_process_csa_wbw_ie() - Process CSA Wide BW IE + * @mac_ctx: pointer to global adapter context + * @csa_params: pointer to CSA parameters + * @chnl_switch_info:pointer to channel switch parameters + * @session_entry: session pointer + * + * Return: None + */ +static QDF_STATUS lim_process_csa_wbw_ie(struct mac_context *mac_ctx, + struct csa_offload_params *csa_params, + tLimWiderBWChannelSwitchInfo *chnl_switch_info, + struct pe_session *session_entry) +{ + struct ch_params ch_params = {0}; + enum phy_ch_width ap_new_ch_width; + uint8_t center_freq_diff; + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width() + 1; + uint32_t cent_freq1, cent_freq2; + uint32_t csa_cent_freq, csa_cent_freq1 = 0, csa_cent_freq2 = 0; + + ap_new_ch_width = csa_params->new_ch_width; + + if (!csa_params->new_ch_freq_seg1 && !csa_params->new_ch_freq_seg2) + return QDF_STATUS_E_INVAL; + + csa_cent_freq = csa_params->csa_chan_freq; + if (wlan_reg_is_6ghz_op_class(mac_ctx->pdev, + csa_params->new_op_class)) { + cent_freq1 = wlan_reg_chan_opclass_to_freq( + csa_params->new_ch_freq_seg1, + csa_params->new_op_class, false); + cent_freq2 = wlan_reg_chan_opclass_to_freq( + csa_params->new_ch_freq_seg2, + csa_params->new_op_class, false); + } else { + cent_freq1 = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, + csa_params->new_ch_freq_seg1); + cent_freq2 = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, + csa_params->new_ch_freq_seg2); + } + + switch (ap_new_ch_width) { + case CH_WIDTH_80MHZ: + csa_cent_freq1 = cent_freq1; + if (csa_params->new_ch_freq_seg2) { + center_freq_diff = abs(csa_params->new_ch_freq_seg2 - + csa_params->new_ch_freq_seg1); + if (center_freq_diff == CENTER_FREQ_DIFF_160MHz) { + ap_new_ch_width = CH_WIDTH_160MHZ; + csa_cent_freq1 = cent_freq2; + csa_params->new_ch_freq_seg1 = + csa_params->new_ch_freq_seg2; + csa_params->new_ch_freq_seg2 = 0; + } else if (center_freq_diff > CENTER_FREQ_DIFF_160MHz) { + ap_new_ch_width = CH_WIDTH_80P80MHZ; + csa_cent_freq2 = cent_freq2; + } + } + break; + case CH_WIDTH_80P80MHZ: + csa_cent_freq1 = cent_freq1; + csa_cent_freq2 = cent_freq2; + break; + case CH_WIDTH_160MHZ: + csa_cent_freq1 = cent_freq1; + break; + default: + pe_debug("CSA wide BW IE has ch_width %d", ap_new_ch_width); + return QDF_STATUS_E_INVAL; + } + + /* Verify whether the bandwidth and channel segments are valid. */ + switch (ap_new_ch_width) { + case CH_WIDTH_80MHZ: + if (abs(csa_cent_freq1 - csa_cent_freq) != 10 && + abs(csa_cent_freq1 - csa_cent_freq) != 30) { + pe_err("CSA WBW 80MHz has invalid seg0 freq %d", + csa_cent_freq1); + return QDF_STATUS_E_INVAL; + } + if (csa_cent_freq2) { + pe_err("CSA WBW 80MHz has invalid seg1 freq %d", + csa_cent_freq2); + return QDF_STATUS_E_INVAL; + } + break; + case CH_WIDTH_80P80MHZ: + if (abs(csa_cent_freq1 - csa_cent_freq) != 10 && + abs(csa_cent_freq1 - csa_cent_freq) != 30) { + pe_err("CSA WBW 80MHz has invalid seg0 freq %d", + csa_cent_freq1); + return QDF_STATUS_E_INVAL; + } + if (!csa_cent_freq2) { + pe_err("CSA WBW 80MHz has invalid seg1 freq %d", + csa_cent_freq2); + return QDF_STATUS_E_INVAL; + } + /* adjacent is not allowed -- that's a 160 MHz channel */ + if (abs(csa_cent_freq1 - csa_cent_freq2) == 80) { + pe_err("CSA WBW wrong bandwidth"); + return QDF_STATUS_E_INVAL; + } + break; + case CH_WIDTH_160MHZ: + if (abs(csa_cent_freq1 - csa_cent_freq) != 70 && + abs(csa_cent_freq1 - csa_cent_freq) != 50 && + abs(csa_cent_freq1 - csa_cent_freq) != 30 && + abs(csa_cent_freq1 - csa_cent_freq) != 10) { + pr_err("CSA WBW 160MHz has invalid seg0 freq %d", + csa_cent_freq1); + return QDF_STATUS_E_INVAL; + } + if (csa_cent_freq2) { + pe_err("CSA WBW 80MHz has invalid seg1 freq %d", + csa_cent_freq2); + return QDF_STATUS_E_INVAL; + } + break; + default: + pe_err("CSA wide BW IE has wrong ch_width %d", ap_new_ch_width); + return QDF_STATUS_E_INVAL; + } + + if (ap_new_ch_width > fw_vht_ch_wd) { + pe_debug("New BW is not supported, downgrade BW to %d", + fw_vht_ch_wd); + ap_new_ch_width = fw_vht_ch_wd; + } + ch_params.ch_width = ap_new_ch_width; + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + ap_new_ch_width = ch_params.ch_width; + csa_params->new_ch_freq_seg1 = ch_params.center_freq_seg0; + csa_params->new_ch_freq_seg2 = ch_params.center_freq_seg1; + + session_entry->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + + chnl_switch_info->newChanWidth = ap_new_ch_width; + chnl_switch_info->newCenterChanFreq0 = csa_params->new_ch_freq_seg1; + chnl_switch_info->newCenterChanFreq1 = csa_params->new_ch_freq_seg2; + + return QDF_STATUS_SUCCESS; +} + +static bool lim_is_csa_channel_allowed(struct mac_context *mac_ctx, + struct pe_session *session_entry, + qdf_freq_t ch_freq1, + struct csa_offload_params *csa_params) +{ + bool is_allowed = true; + u32 cnx_count = 0; + enum QDF_OPMODE mode; + qdf_freq_t csa_freq = csa_params->csa_chan_freq, sec_ch_2g_freq = 0; + enum phy_ch_width new_ch_width = csa_params->new_ch_width; + enum channel_state chan_state; + + if (!session_entry->vdev || + wlan_cm_is_vdev_disconnecting(session_entry->vdev) || + wlan_cm_is_vdev_disconnected(session_entry->vdev)) { + pe_warn("CSA is ignored, vdev %d is disconnecting/ed", + session_entry->vdev_id); + return false; + } + + /* + * This is a temporary check and will be removed once ll_lt_sap CSA + * support is added. + */ + if (policy_mgr_get_ll_lt_sap_freq(mac_ctx->psoc) == csa_freq) { + pe_err("CSA not allowed on LL_LT_SAP freq %d", csa_freq); + lim_tear_down_link_with_ap(mac_ctx, session_entry->peSessionId, + REASON_CHANNEL_SWITCH_FAILED, + eLIM_HOST_DISASSOC); + return false; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(csa_freq) && + wlan_reg_get_bw_value(new_ch_width) > 20) { + if (csa_params->new_ch_freq_seg1 == csa_params->channel + 2) + sec_ch_2g_freq = csa_freq + HT40_SEC_OFFSET; + else if (csa_params->new_ch_freq_seg1 == csa_params->channel - 2) + sec_ch_2g_freq = csa_freq - HT40_SEC_OFFSET; + } + + chan_state = wlan_reg_get_bonded_channel_state_for_pwrmode( + mac_ctx->pdev, + csa_freq, new_ch_width, + sec_ch_2g_freq, + REG_CURRENT_PWR_MODE); + if (chan_state == CHANNEL_STATE_INVALID || + chan_state == CHANNEL_STATE_DISABLE) { + pe_err("Invalid csa_freq %d ch_width %d ccfs0 %d ccfs1 %d sec_ch %d. Disconnect", + csa_freq, new_ch_width, csa_params->new_ch_freq_seg1, + csa_params->new_ch_freq_seg2, sec_ch_2g_freq); + lim_tear_down_link_with_ap(mac_ctx, + session_entry->peSessionId, + REASON_CHANNEL_SWITCH_FAILED, + eLIM_HOST_DISASSOC); + return false; + } + + mode = wlan_vdev_mlme_get_opmode(session_entry->vdev); + cnx_count = policy_mgr_get_connection_count(mac_ctx->psoc); + if ((cnx_count > 1) && !policy_mgr_is_hw_dbs_capable(mac_ctx->psoc) && + !policy_mgr_is_interband_mcc_supported(mac_ctx->psoc)) { + is_allowed = wlan_reg_is_same_band_freqs(ch_freq1, csa_freq); + } else if (cnx_count > 2) { + is_allowed = + policy_mgr_allow_concurrency_csa( + mac_ctx->psoc, + policy_mgr_qdf_opmode_to_pm_con_mode(mac_ctx->psoc, + mode, + session_entry->vdev_id), + csa_freq, + policy_mgr_get_bw(new_ch_width), + session_entry->vdev_id, false, + CSA_REASON_UNKNOWN); + } + + return is_allowed; +} + +#ifdef WLAN_FEATURE_11BE +/** + * lim_set_csa_chan_param_11be() - set csa chan params for 11be + * @session: pointer to pe session + * @csa_param: pointer to csa_offload_params + * @ch_param: channel parameters to get + * + * Return: void + */ +static void lim_set_csa_chan_param_11be(struct pe_session *session, + struct csa_offload_params *csa_param, + struct ch_params *ch_param) +{ + if (!session || !csa_param || !ch_param || !session->vdev) { + pe_err("invalid input parameter"); + return; + } + + if (csa_param->new_ch_width == CH_WIDTH_320MHZ && + !session->eht_config.support_320mhz_6ghz) + ch_param->ch_width = CH_WIDTH_160MHZ; + + wlan_cm_sta_set_chan_param(session->vdev, + csa_param->csa_chan_freq, + csa_param->new_ch_width, + csa_param->new_punct_bitmap, + csa_param->new_ch_freq_seg1, + csa_param->new_ch_freq_seg2, + ch_param); +} + +/** + * lim_set_chan_sw_puncture() - set puncture to channel switch info + * @lim_ch_switch: pointer to tLimChannelSwitchInfo + * @ch_param: pointer to ch_params + * + * Return: void + */ +static void lim_set_chan_sw_puncture(tLimChannelSwitchInfo *lim_ch_switch, + struct ch_params *ch_param) +{ + lim_ch_switch->puncture_bitmap = ch_param->reg_punc_bitmap; +} + +/** + * lim_reset_csa_puncture() - reset puncture of channel switch + * @lim_ch_switch: pointer to tLimChannelSwitchInfo + * + * Return: void + */ +static void lim_reset_csa_puncture(tLimChannelSwitchInfo *lim_ch_switch) +{ + lim_ch_switch->puncture_bitmap = 0; +} + +/** + * lim_is_puncture_same() - Check whether puncture changed + * @lim_ch_switch: pointer to tLimChannelSwitchInfo + * @session: pe session + * + * Return: bool, true: puncture changed + */ +static bool lim_is_puncture_same(tLimChannelSwitchInfo *lim_ch_switch, + struct pe_session *session) +{ + pe_debug("vdevid %d puncture, old: 0x%x, new: 0x%x", session->vdev_id, + session->puncture_bitmap, + lim_ch_switch->puncture_bitmap); + return lim_ch_switch->puncture_bitmap == session->puncture_bitmap; +} + +static void update_csa_link_info(struct wlan_objmgr_vdev *vdev, + uint8_t link_id, + struct csa_offload_params *csa_params) +{ + struct wlan_objmgr_pdev *pdev; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + pe_err("pdev is null"); + return; + } + + mlo_mgr_update_csa_link_info(pdev, vdev->mlo_dev_ctx, + csa_params, link_id); + pe_debug("vdev_id: %d link id %d mlo csa sta param updated ", + vdev_id, link_id); +} + +static bool +lim_mlo_is_csa_allow(struct wlan_objmgr_vdev *vdev, uint16_t csa_freq) +{ + return wlan_mlo_is_csa_allow(vdev, csa_freq); +} + +#else +static void lim_set_csa_chan_param_11be(struct pe_session *session, + struct csa_offload_params *csa_param, + struct ch_params *ch_param) +{ +} + +static void lim_set_chan_sw_puncture(tLimChannelSwitchInfo *lim_ch_switch, + struct ch_params *ch_param) +{ +} + +static void lim_reset_csa_puncture(tLimChannelSwitchInfo *lim_ch_switch) +{ +} + +static bool lim_is_puncture_same(tLimChannelSwitchInfo *lim_ch_switch, + struct pe_session *session) +{ + return true; +} + +static void update_csa_link_info(struct wlan_objmgr_vdev *vdev, + uint8_t link_id, + struct csa_offload_params *csa_params) +{ +} + +static bool +lim_mlo_is_csa_allow(struct wlan_objmgr_vdev *vdev, uint16_t csa_freq) +{ + return true; +} +#endif + +/** + * lim_sta_follow_csa() - Check if STA needs to follow CSA + * @session_entry: Session pointer + * @csa_params: Pointer to CSA params + * @lim_ch_switch: Pointer to lim channel switch info + * @ch_params: Channel params + * + * Return: True if CSA is required, else return false. + */ +static bool lim_sta_follow_csa(struct pe_session *session_entry, + struct csa_offload_params *csa_params, + tLimChannelSwitchInfo *lim_ch_switch, + struct ch_params ch_params) +{ + if (session_entry->curr_op_freq == csa_params->csa_chan_freq && + session_entry->ch_width == ch_params.ch_width && + lim_is_puncture_same(lim_ch_switch, session_entry)) { + pe_debug("Ignore CSA, no change in ch, bw and puncture"); + return false; + } + return true; +} + +/** + * lim_get_max_channel_width_from_dot11mode()- This API will get maximum + * channel width allowed for given dot11mode. + * @dot11mode: dot11 mode + * + * Return: channel width + */ +static enum phy_ch_width +lim_get_max_channel_width_from_dot11mode(enum mlme_dot11_mode dot11mode) +{ + switch (dot11mode) { + case MLME_DOT11_MODE_ABG: + case MLME_DOT11_MODE_11A: + case MLME_DOT11_MODE_11B: + case MLME_DOT11_MODE_11G: + case MLME_DOT11_MODE_11G_ONLY: + return CH_WIDTH_20MHZ; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11N_ONLY: + return CH_WIDTH_40MHZ; + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AC_ONLY: + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11AX_ONLY: + return CH_WIDTH_160MHZ; + case MLME_DOT11_MODE_11BE: + case MLME_DOT11_MODE_11BE_ONLY: + case MLME_DOT11_MODE_ALL: + return CH_WIDTH_320MHZ; + default: + pe_err("Invalid dot11mode %d", dot11mode); + break; + } + + return CH_WIDTH_INVALID; +} + +/** + * lim_csa_update_channel_width_for_dot11mode()- This API will get maximum + * channel width allowed for given dot11mode and update CSA channel width. + * @session_entry: Session pointer + * @csa_params: Pointer to CSA params + * + * Return: None + */ +static void lim_csa_update_channel_width_for_dot11mode( + struct pe_session *session_entry, + struct csa_offload_params *csa_params) +{ + enum phy_ch_width max_ch_width; + + max_ch_width = lim_get_max_channel_width_from_dot11mode( + session_entry->dot11mode); + + /* If AP wants to set in 80 + 80 BW, do not change to 160 MHz */ + if (csa_params->new_ch_width == CH_WIDTH_80P80MHZ && + max_ch_width == CH_WIDTH_160MHZ) + return; + + if (csa_params->new_ch_width != CH_WIDTH_5MHZ && + csa_params->new_ch_width != CH_WIDTH_10MHZ && + csa_params->new_ch_width > max_ch_width) { + pe_debug("Downgrade bw from %d to max supported bw %d for dot11mode %d ", + csa_params->new_ch_width, max_ch_width, + session_entry->dot11mode); + csa_params->new_ch_width = max_ch_width; + } +} + +void lim_handle_sta_csa_param(struct mac_context *mac_ctx, + struct csa_offload_params *csa_params, + bool send_status) +{ + struct pe_session *session_entry; + struct mlme_legacy_priv *mlme_priv; + tpDphHashNode sta_ds = NULL; + uint8_t session_id; + uint16_t aid = 0; + uint16_t chan_space = 0; + struct ch_params ch_params = {0}; + uint32_t channel_bonding_mode; + uint8_t country_code[CDS_COUNTRY_CODE_LEN + 1]; + tLimWiderBWChannelSwitchInfo *chnl_switch_info = NULL; + tLimChannelSwitchInfo *lim_ch_switch = NULL; + uint8_t link_id; + + if (!csa_params) { + pe_err("limMsgQ body ptr is NULL"); + return; + } + + session_entry = + pe_find_session_by_bssid(mac_ctx, + csa_params->bssid.bytes, &session_id); + if (!session_entry) { + pe_err("Session does not exists for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(csa_params->bssid.bytes)); + goto free; + } + sta_ds = dph_lookup_hash_entry(mac_ctx, session_entry->bssId, &aid, + &session_entry->dph.dphHashTable); + + if (!sta_ds) { + pe_err("sta_ds does not exist"); + goto send_event; + } + + if (!LIM_IS_STA_ROLE(session_entry)) { + pe_debug("Invalid role to handle CSA"); + goto send_event; + } + + lim_ch_switch = &session_entry->gLimChannelSwitch; + + lim_csa_update_channel_width_for_dot11mode(session_entry, csa_params); + ch_params.ch_width = csa_params->new_ch_width; + + if (IS_DOT11_MODE_EHT(session_entry->dot11mode)) + lim_set_csa_chan_param_11be(session_entry, csa_params, + &ch_params); + else + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + lim_set_chan_sw_puncture(lim_ch_switch, &ch_params); + + if (!lim_sta_follow_csa(session_entry, csa_params, + lim_ch_switch, ch_params)) + goto send_event; + else + qdf_mem_zero(&ch_params, sizeof(struct ch_params)); + + if (!lim_is_csa_channel_allowed(mac_ctx, session_entry, + session_entry->curr_op_freq, + csa_params)) { + pe_debug("Channel switch is not allowed"); + goto send_event; + } + + if (!lim_mlo_is_csa_allow(session_entry->vdev, + csa_params->csa_chan_freq)) { + pe_debug("Channel switch for MLO vdev is not allowed"); + goto send_event; + } + /* + * on receiving channel switch announcement from AP, delete all + * TDLS peers before leaving BSS and proceed for channel switch + */ + + lim_update_tdls_set_state_for_fw(session_entry, false); + lim_delete_tdls_peers(mac_ctx, session_entry); + + lim_ch_switch->switchMode = csa_params->switch_mode; + /* timer already started by firmware, switch immediately */ + lim_ch_switch->switchCount = 0; + lim_ch_switch->primaryChannel = + csa_params->channel; + lim_ch_switch->sw_target_freq = + csa_params->csa_chan_freq; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + lim_ch_switch->ch_width = CH_WIDTH_20MHZ; + lim_reset_csa_puncture(lim_ch_switch); + + lim_ch_switch->sec_ch_offset = + session_entry->htSecondaryChannelOffset; + lim_ch_switch->ch_center_freq_seg0 = 0; + lim_ch_switch->ch_center_freq_seg1 = 0; + chnl_switch_info = + &session_entry->gLimWiderBWChannelSwitch; + + channel_bonding_mode = lim_get_cb_mode_for_freq(mac_ctx, session_entry, + csa_params->csa_chan_freq); + + pe_debug("Session %d vdev %d: vht: %d ht: %d he %d cbmode %d", + session_entry->peSessionId, session_entry->vdev_id, + session_entry->vhtCapability, + session_entry->htSupportedChannelWidthSet, + lim_is_session_he_capable(session_entry), + channel_bonding_mode); + + session_entry->htSupportedChannelWidthSet = false; + wlan_reg_read_current_country(mac_ctx->psoc, country_code); + if (!csa_params->ies_present_flag || + (csa_params->ies_present_flag & MLME_CSWRAP_IE_EXT_V2_PRESENT)) { + pe_debug("new freq: %u, width: %d", csa_params->csa_chan_freq, + csa_params->new_ch_width); + ch_params.ch_width = csa_params->new_ch_width; + if (IS_DOT11_MODE_EHT(session_entry->dot11mode)) + lim_set_csa_chan_param_11be(session_entry, csa_params, + &ch_params); + else + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + pe_debug("idea width: %d, chn_seg0 %u chn_seg1 %u freq_seg0 %u freq_seg1 %u", + ch_params.ch_width, ch_params.center_freq_seg0, + ch_params.center_freq_seg1, ch_params.mhz_freq_seg0, + ch_params.mhz_freq_seg1); + + lim_ch_switch->sec_ch_offset = ch_params.sec_ch_offset; + lim_ch_switch->ch_width = ch_params.ch_width; + lim_ch_switch->ch_center_freq_seg0 = ch_params.center_freq_seg0; + lim_ch_switch->ch_center_freq_seg1 = ch_params.center_freq_seg1; + lim_set_chan_sw_puncture(lim_ch_switch, &ch_params); + + if (ch_params.ch_width == CH_WIDTH_20MHZ) { + lim_ch_switch->state = eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + session_entry->htSupportedChannelWidthSet = false; + } else { + chnl_switch_info->newChanWidth = + lim_ch_switch->ch_width; + chnl_switch_info->newCenterChanFreq0 = + lim_ch_switch->ch_center_freq_seg0; + chnl_switch_info->newCenterChanFreq1 = + lim_ch_switch->ch_center_freq_seg1; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + session_entry->htSupportedChannelWidthSet = true; + } + } else if (channel_bonding_mode && + ((session_entry->vhtCapability && session_entry->htCapability) || + lim_is_session_he_capable(session_entry))) { + if ((csa_params->ies_present_flag & MLME_WBW_IE_PRESENT) && + (QDF_STATUS_SUCCESS == lim_process_csa_wbw_ie( + mac_ctx, csa_params, chnl_switch_info, + session_entry))) { + lim_ch_switch->sec_ch_offset = + PHY_SINGLE_CHANNEL_CENTERED; + if (chnl_switch_info->newChanWidth) { + ch_params.ch_width = + chnl_switch_info->newChanWidth; + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + session_entry->htSupportedChannelWidthSet = + true; + } + } else if (csa_params->ies_present_flag + & MLME_XCSA_IE_PRESENT) { + uint32_t fw_vht_ch_wd = wma_get_vht_ch_width(); + + if (wlan_reg_is_6ghz_op_class + (mac_ctx->pdev, csa_params->new_op_class)) { + chan_space = wlan_reg_get_op_class_width + (mac_ctx->pdev, + csa_params->new_op_class, true); + } else { + chan_space = + wlan_reg_dmn_get_chanwidth_from_opclass_auto( + country_code, + csa_params->channel, + csa_params->new_op_class); + } + if (chan_space >= 160 && fw_vht_ch_wd < + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + chan_space = 80; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + if (chan_space == 160) { + chnl_switch_info->newChanWidth = + CH_WIDTH_160MHZ; + } else if (chan_space == 80) { + chnl_switch_info->newChanWidth = + CH_WIDTH_80MHZ; + session_entry->htSupportedChannelWidthSet = + true; + } else if (chan_space == 40) { + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + session_entry->htSupportedChannelWidthSet = + true; + } else { + chnl_switch_info->newChanWidth = + CH_WIDTH_20MHZ; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + } + + ch_params.ch_width = + chnl_switch_info->newChanWidth; + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, csa_params->csa_chan_freq, 0, + &ch_params, REG_CURRENT_PWR_MODE); + chnl_switch_info->newCenterChanFreq0 = + ch_params.center_freq_seg0; + /* + * This is not applicable for 20/40/80 MHz. + * Only used when we support 80+80 MHz operation. + * In case of 80+80 MHz, this parameter indicates + * center channel frequency index of 80 MHz + * channel offrequency segment 1. + */ + chnl_switch_info->newCenterChanFreq1 = + ch_params.center_freq_seg1; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + } else { + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_params.ch_width = CH_WIDTH_40MHZ; + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + chnl_switch_info->newChanWidth = CH_WIDTH_40MHZ; + chnl_switch_info->newCenterChanFreq0 = + ch_params.center_freq_seg0; + chnl_switch_info->newCenterChanFreq1 = 0; + session_entry->htSupportedChannelWidthSet = true; + } + lim_ch_switch->ch_center_freq_seg0 = + chnl_switch_info->newCenterChanFreq0; + lim_ch_switch->ch_center_freq_seg1 = + chnl_switch_info->newCenterChanFreq1; + lim_ch_switch->ch_width = + chnl_switch_info->newChanWidth; + + } else if (channel_bonding_mode && session_entry->htCapability) { + if (csa_params->ies_present_flag + & MLME_XCSA_IE_PRESENT) { + chan_space = + wlan_reg_dmn_get_chanwidth_from_opclass_auto( + country_code, + csa_params->channel, + csa_params->new_op_class); + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + if (chan_space == 40) { + lim_ch_switch->ch_width = + CH_WIDTH_40MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_40MHZ; + ch_params.ch_width = + chnl_switch_info->newChanWidth; + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + lim_ch_switch->ch_center_freq_seg0 = + ch_params.center_freq_seg0; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + session_entry->htSupportedChannelWidthSet = + true; + } else { + lim_ch_switch->ch_width = + CH_WIDTH_20MHZ; + chnl_switch_info->newChanWidth = + CH_WIDTH_20MHZ; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_ONLY; + lim_ch_switch->sec_ch_offset = + PHY_SINGLE_CHANNEL_CENTERED; + } + } else { + lim_ch_switch->ch_width = + CH_WIDTH_40MHZ; + lim_ch_switch->state = + eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY; + ch_params.ch_width = CH_WIDTH_40MHZ; + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + csa_params->csa_chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + lim_ch_switch->ch_center_freq_seg0 = + ch_params.center_freq_seg0; + lim_ch_switch->sec_ch_offset = + ch_params.sec_ch_offset; + session_entry->htSupportedChannelWidthSet = true; + } + } + + lim_cp_stats_cstats_log_csa_evt(session_entry, CSTATS_DIR_RX, + lim_ch_switch->sw_target_freq, + lim_ch_switch->ch_width, + lim_ch_switch->switchMode); + + pe_debug("new ch %d: freq %d width: %d freq0 %d freq1 %d ht width %d, current freq %d: bw %d", + lim_ch_switch->primaryChannel, lim_ch_switch->sw_target_freq, + lim_ch_switch->ch_width, lim_ch_switch->ch_center_freq_seg0, + lim_ch_switch->ch_center_freq_seg1, + lim_ch_switch->sec_ch_offset, session_entry->curr_op_freq, + session_entry->ch_width); + + if (!lim_sta_follow_csa(session_entry, csa_params, + lim_ch_switch, ch_params)) + goto send_event; + + if (wlan_vdev_mlme_is_mlo_vdev(session_entry->vdev)) { + link_id = wlan_vdev_get_link_id(session_entry->vdev); + update_csa_link_info(session_entry->vdev, link_id, csa_params); + } else { + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session_entry->vdev); + if (!mlme_priv) + return; + mlme_priv->connect_info.assoc_chan_info.assoc_ch_width = + csa_params->new_ch_width; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(csa_params->csa_chan_freq) && + session_entry->dot11mode == MLME_DOT11_MODE_11A) + session_entry->dot11mode = MLME_DOT11_MODE_11G; + else if (!WLAN_REG_IS_24GHZ_CH_FREQ(csa_params->csa_chan_freq) && + ((session_entry->dot11mode == MLME_DOT11_MODE_11G) || + (session_entry->dot11mode == MLME_DOT11_MODE_11G_ONLY))) + session_entry->dot11mode = MLME_DOT11_MODE_11A; + + /* Send RSO Stop to FW before triggering the vdev restart for CSA */ + if (mac_ctx->lim.stop_roaming_callback) + mac_ctx->lim.stop_roaming_callback(MAC_HANDLE(mac_ctx), + session_entry->smeSessionId, + REASON_VDEV_RESTART_FROM_HOST, + RSO_CHANNEL_SWITCH); + + if (mlo_is_any_link_disconnecting(session_entry->vdev)) { + pe_info_rl("Ignore CSA, vdev is in not in conncted state"); + goto send_event; + } + + lim_prepare_for11h_channel_switch(mac_ctx, session_entry); + + lim_flush_bssid(mac_ctx, session_entry->bssId); + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + lim_diag_event_report(mac_ctx, + WLAN_PE_DIAG_SWITCH_CHL_IND_EVENT, session_entry, + QDF_STATUS_SUCCESS, QDF_STATUS_SUCCESS); +#endif +free: + qdf_mem_free(csa_params); + return; +send_event: + if (send_status) + wlan_mlme_send_csa_event_status_ind(session_entry->vdev, 0); + qdf_mem_free(csa_params); +} + +void lim_handle_csa_offload_msg(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct pe_session *session; + struct csa_offload_params *csa_params = + (struct csa_offload_params *)(msg->bodyptr); + uint8_t session_id; + + if (!csa_params) { + pe_err("limMsgQ body ptr is NULL"); + return; + } + + session = pe_find_session_by_bssid( + mac_ctx, csa_params->bssid.bytes, &session_id); + if (!session) { + pe_err("Session does not exists for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(csa_params->bssid.bytes)); + qdf_mem_free(csa_params); + return; + } + if (wlan_vdev_mlme_is_mlo_vdev(session->vdev) && + mlo_is_sta_csa_param_handled(session->vdev, csa_params)) { + pe_debug("vdev_id: %d, csa param is already handled. return", + session_id); + qdf_mem_free(csa_params); + return; + } + lim_handle_sta_csa_param(mac_ctx, csa_params, true); +} + +#ifdef WLAN_FEATURE_11BE_MLO +void lim_handle_mlo_sta_csa_param(struct wlan_objmgr_vdev *vdev, + struct csa_offload_params *csa_params) +{ + struct mac_context *mac; + struct csa_offload_params *tmp_csa_params; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + pe_err("mac ctx is null"); + return; + } + + tmp_csa_params = qdf_mem_malloc(sizeof(*tmp_csa_params)); + if (!tmp_csa_params) { + pe_err("tmp_csa_params allocation fails"); + return; + } + + qdf_mem_copy(tmp_csa_params, csa_params, sizeof(*tmp_csa_params)); + + lim_handle_sta_csa_param(mac, tmp_csa_params, false); +} +#endif + +/*-------------------------------------------------------------------------- + \brief pe_delete_session() - Handle the Delete BSS Response from HAL. + + \param mac - pointer to global adapter context + \param sessionId - Message pointer. + + \sa + --------------------------------------------------------------------------*/ + +void lim_handle_delete_bss_rsp(struct mac_context *mac, + struct del_bss_resp *del_bss_rsp) +{ + struct pe_session *pe_session; + + pe_session = + pe_find_session_by_vdev_id_and_state(mac, + del_bss_rsp->vdev_id, + eLIM_MLM_WT_DEL_BSS_RSP_STATE); + if (!pe_session) { + qdf_mem_free(del_bss_rsp); + return; + } + + /* + * During DEL BSS handling, the PE Session will be deleted, but it is + * better to clear this flag if the session is hanging around due + * to some error conditions so that the next DEL_BSS request does + * not take the HO_FAIL path + */ + pe_session->process_ho_fail = false; + if (LIM_IS_UNKNOWN_ROLE(pe_session)) + lim_process_sme_del_bss_rsp(mac, pe_session); + else if (LIM_IS_NDI_ROLE(pe_session)) + lim_ndi_del_bss_rsp(mac, del_bss_rsp, pe_session); + else + lim_process_mlm_del_bss_rsp(mac, del_bss_rsp, pe_session); + + qdf_mem_free(del_bss_rsp); +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_aggr_qos_rsp() - sends SME FT AGGR QOS RSP + \ This function sends a eWNI_SME_FT_AGGR_QOS_RSP to SME. + \ SME only looks at rc and tspec field. + \param mac - global mac structure + \param rspReqd - is SmeAddTsRsp required + \param status - status code of eWNI_SME_FT_AGGR_QOS_RSP + \return tspec + \sa + ----------------------------------------------------------------- */ +void +lim_send_sme_aggr_qos_rsp(struct mac_context *mac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId) +{ + struct scheduler_msg mmhMsg = {0}; + + mmhMsg.type = eWNI_SME_FT_AGGR_QOS_RSP; + mmhMsg.bodyptr = aggrQosRsp; + mmhMsg.bodyval = 0; + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + + return; +} + +void lim_send_sme_max_assoc_exceeded_ntf(struct mac_context *mac, tSirMacAddr peerMacAddr, + uint8_t smesessionId) +{ + struct scheduler_msg mmhMsg = {0}; + tSmeMaxAssocInd *pSmeMaxAssocInd; + + pSmeMaxAssocInd = qdf_mem_malloc(sizeof(tSmeMaxAssocInd)); + if (!pSmeMaxAssocInd) + return; + qdf_mem_copy((uint8_t *) pSmeMaxAssocInd->peer_mac.bytes, + (uint8_t *) peerMacAddr, QDF_MAC_ADDR_SIZE); + pSmeMaxAssocInd->mesgType = eWNI_SME_MAX_ASSOC_EXCEEDED; + pSmeMaxAssocInd->mesgLen = sizeof(tSmeMaxAssocInd); + pSmeMaxAssocInd->sessionId = smesessionId; + mmhMsg.type = pSmeMaxAssocInd->mesgType; + mmhMsg.bodyptr = pSmeMaxAssocInd; + pe_debug("msgType: %s peerMacAddr "QDF_MAC_ADDR_FMT "sme session id %d", + "eWNI_SME_MAX_ASSOC_EXCEEDED", QDF_MAC_ADDR_REF(peerMacAddr), + pSmeMaxAssocInd->sessionId); + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + smesessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + + return; +} + +/** ----------------------------------------------------------------- + \brief lim_send_sme_ap_channel_switch_resp() - sends + eWNI_SME_CHANNEL_CHANGE_RSP + After receiving WMA_SWITCH_CHANNEL_RSP indication this + function sends a eWNI_SME_CHANNEL_CHANGE_RSP to SME to notify + that the Channel change has been done to the specified target + channel in the Channel change request + \param mac - global mac structure + \param pe_session - session info + \param pChnlParams - Channel switch params + --------------------------------------------------------------------*/ +void +lim_send_sme_ap_channel_switch_resp(struct mac_context *mac, + struct pe_session *pe_session, + struct vdev_start_response *rsp) +{ + struct scheduler_msg mmhMsg = {0}; + struct sSirChanChangeResponse *chan_change_rsp; + bool is_ch_dfs = false; + enum phy_ch_width ch_width; + uint32_t ch_cfreq1 = 0; + enum reg_wifi_band band; + + qdf_runtime_pm_allow_suspend(&pe_session->ap_ecsa_runtime_lock); + qdf_wake_lock_release(&pe_session->ap_ecsa_wakelock, 0); + + chan_change_rsp = + qdf_mem_malloc(sizeof(struct sSirChanChangeResponse)); + if (!chan_change_rsp) + return; + + chan_change_rsp->new_op_freq = pe_session->curr_op_freq; + chan_change_rsp->channelChangeStatus = rsp->status; + /* + * Pass the sme sessionID to SME instead + * PE session ID. + */ + chan_change_rsp->sessionId = rsp->vdev_id; + + mmhMsg.type = eWNI_SME_CHANNEL_CHANGE_RSP; + mmhMsg.bodyptr = (void *)chan_change_rsp; + mmhMsg.bodyval = 0; + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + + if (QDF_IS_STATUS_ERROR(rsp->status)) { + pe_err("failed to change sap freq to %u", + pe_session->curr_op_freq); + return; + } + + /* + * We should start beacon transmission only if the new + * channel after channel change is Non-DFS. For a DFS + * channel, PE will receive an explicit request from + * upper layers to start the beacon transmission . + */ + ch_width = pe_session->ch_width; + band = wlan_reg_freq_to_band(pe_session->curr_op_freq); + if (pe_session->ch_center_freq_seg1) + ch_cfreq1 = wlan_reg_chan_band_to_freq( + mac->pdev, + pe_session->ch_center_freq_seg1, + BIT(band)); + + if (ch_width == CH_WIDTH_160MHZ) { + struct ch_params ch_params = {0}; + + if (IS_DOT11_MODE_EHT(pe_session->dot11mode)) + wlan_reg_set_create_punc_bitmap(&ch_params, true); + ch_params.ch_width = ch_width; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac->pdev, + pe_session->curr_op_freq, + &ch_params, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else if (ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, + pe_session->curr_op_freq, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, + ch_cfreq1, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (wlan_reg_is_dfs_for_freq(mac->pdev, + pe_session->curr_op_freq)) + is_ch_dfs = true; + } + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(pe_session->curr_op_freq)) + is_ch_dfs = false; + + if (is_ch_dfs) { + lim_sap_move_to_cac_wait_state(pe_session); + + } else { + lim_apply_configuration(mac, pe_session); + lim_send_beacon(mac, pe_session); + lim_obss_send_detection_cfg(mac, pe_session, true); + } + return; +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * lim_send_bss_color_change_ie_update() - update bss color change IE in + * beacon template + * + * @mac_ctx: pointer to global adapter context + * @session: session pointer + * + * Return: none + */ +static void +lim_send_bss_color_change_ie_update(struct mac_context *mac_ctx, + struct pe_session *session) +{ + /* Update the beacon template and send to FW */ + if (sch_set_fixed_beacon_fields(mac_ctx, session) != QDF_STATUS_SUCCESS) { + pe_err("Unable to set BSS color change IE in beacon"); + return; + } + + /* Send update beacon template message */ + lim_send_beacon_ind(mac_ctx, session, REASON_COLOR_CHANGE); + pe_debug("Updated BSS color change countdown = %d", + session->he_bss_color_change.countdown); +} + +#ifdef WLAN_FEATURE_SR +static void +lim_update_spatial_reuse(struct pe_session *session) +{ + struct wlan_objmgr_psoc *psoc; + uint32_t conc_vdev_id; + uint8_t mac_id, sr_ctrl, non_srg_pd_max_offset; + uint8_t vdev_id = session->vdev_id; + + sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(session->vdev); + non_srg_pd_max_offset = + wlan_vdev_mlme_get_non_srg_pd_offset(session->vdev); + if (non_srg_pd_max_offset && sr_ctrl && + wlan_vdev_mlme_get_he_spr_enabled(session->vdev)) { + psoc = wlan_vdev_get_psoc(session->vdev); + policy_mgr_get_mac_id_by_session_id(psoc, + vdev_id, + &mac_id); + conc_vdev_id = policy_mgr_get_conc_vdev_on_same_mac(psoc, + vdev_id, + mac_id); + if (conc_vdev_id == WLAN_INVALID_VDEV_ID || + policy_mgr_sr_same_mac_conc_enabled(psoc)) { + wlan_vdev_mlme_set_sr_disable_due_conc(session->vdev, + false); + wlan_spatial_reuse_config_set(session->vdev, sr_ctrl, + non_srg_pd_max_offset); + wlan_spatial_reuse_osif_event(session->vdev, + SR_OPERATION_RESUME, + SR_REASON_CODE_CONCURRENCY); + } else { + wlan_vdev_mlme_set_sr_disable_due_conc(session->vdev, + true); + wlan_spatial_reuse_config_set(session->vdev, sr_ctrl, + NON_SR_PD_THRESHOLD_DISABLED); + wlan_spatial_reuse_osif_event(session->vdev, + SR_OPERATION_SUSPEND, + SR_REASON_CODE_CONCURRENCY); + } + } +} +#else +static void +lim_update_spatial_reuse(struct pe_session *session) +{ +} +#endif + +static void +lim_handle_bss_color_change_ie(struct mac_context *mac_ctx, + struct pe_session *session) +{ + tUpdateBeaconParams beacon_params; + + /* handle bss color change IE */ + if (LIM_IS_AP_ROLE(session) && + session->he_op.bss_col_disabled && + session->he_bss_color_change.new_color) { + pe_debug("countdown: %d, new_color: %d", + session->he_bss_color_change.countdown, + session->he_bss_color_change.new_color); + if (session->he_bss_color_change.countdown > 0) { + session->he_bss_color_change.countdown--; + } else { + session->bss_color_changing = 0; + /* + * On OBSS color collision detection, spatial reuse + * gets disabled. Enable spatial reuse if it was + * enabled during AP start + */ + lim_update_spatial_reuse(session); + qdf_mem_zero(&beacon_params, sizeof(beacon_params)); + session->he_op.bss_col_disabled = 0; + session->he_op.bss_color = + session->he_bss_color_change.new_color; + session->he_bss_color_change.new_color = 0; + beacon_params.paramChangeBitmap |= + PARAM_BSS_COLOR_CHANGED; + beacon_params.bss_color_disabled = 0; + beacon_params.bss_color = session->he_op.bss_color; + lim_send_beacon_params(mac_ctx, + &beacon_params, + session); + lim_send_obss_color_collision_cfg( + mac_ctx, session, + OBSS_COLOR_COLLISION_DETECTION); + wma_allow_suspend_after_obss_color_change( + session->vdev); + } + lim_send_bss_color_change_ie_update(mac_ctx, session); + } +} + +#else +static void +lim_handle_bss_color_change_ie(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} +#endif + +void +lim_process_beacon_tx_success_ind(struct mac_context *mac_ctx, uint16_t msgType, + void *event) +{ + struct pe_session *session; + struct wlan_objmgr_vdev *vdev; + bool csa_tx_offload, is_sap_go_moved_before_sta = false; + tpSirFirstBeaconTxCompleteInd bcn_ind = + (tSirFirstBeaconTxCompleteInd *) event; + + session = pe_find_session_by_vdev_id(mac_ctx, bcn_ind->bss_idx); + if (!session) { + pe_err("Session Does not exist for given session id"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + session->vdev_id, + WLAN_LEGACY_MAC_ID); + if (vdev) { + is_sap_go_moved_before_sta = + wlan_vdev_mlme_is_sap_go_move_before_sta(vdev); + wlan_vdev_mlme_set_sap_go_move_before_sta(vdev, false); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + } + pe_debug("role: %d swIe: %d opIe: %d switch cnt:%d Is SAP / GO Moved before STA: %d", + GET_LIM_SYSTEM_ROLE(session), + session->dfsIncludeChanSwIe, + session->gLimOperatingMode.present, + session->gLimChannelSwitch.switchCount, + is_sap_go_moved_before_sta); + + if (!LIM_IS_AP_ROLE(session)) + return; + csa_tx_offload = wlan_psoc_nif_fw_ext_cap_get(mac_ctx->psoc, + WLAN_SOC_CEXT_CSA_TX_OFFLOAD); + if ((session->dfsIncludeChanSwIe && !csa_tx_offload && + ((session->gLimChannelSwitch.switchCount == + mac_ctx->sap.SapDfsInfo.sap_ch_switch_beacon_cnt) || + (session->gLimChannelSwitch.switchCount == 1) || + is_sap_go_moved_before_sta)) || + session->bw_update_include_ch_sw_ie) + lim_process_ap_ecsa_timeout(session); + + if (session->gLimOperatingMode.present) + /* Done with nss update */ + session->gLimOperatingMode.present = 0; + + lim_handle_bss_color_change_ie(mac_ctx, session); + + return; +} + +void lim_nss_or_ch_width_update_rsp(struct mac_context *mac_ctx, + uint8_t vdev_id, QDF_STATUS status, + enum sir_bcn_update_reason reason) +{ + struct scheduler_msg msg = {0}; + struct sir_bcn_update_rsp *rsp; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + + rsp = qdf_mem_malloc(sizeof(*rsp)); + if (rsp) { + rsp->vdev_id = vdev_id; + rsp->status = status; + rsp->reason = reason; + } + + if (reason == REASON_NSS_UPDATE) + msg.type = eWNI_SME_NSS_UPDATE_RSP; + else if (reason == REASON_CH_WIDTH_UPDATE) + msg.type = eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP; + else + goto done; + + msg.bodyptr = rsp; + msg.bodyval = 0; + qdf_status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &msg); +done: + if (QDF_IS_STATUS_ERROR(qdf_status)) + qdf_mem_free(rsp); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h new file mode 100644 index 0000000000..ac2f116a8d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_send_sme_rsp_messages.h @@ -0,0 +1,319 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_send_sme_rsp_messages.h contains the definitions for + * sending SME response/notification messages to applications above + * MAC software. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_SEND_SME_RSP_H +#define __LIM_SEND_SME_RSP_H + +#include "sir_common.h" +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include <../../core/src/wlan_cm_vdev_api.h> + +/* Functions for sending responses up the stack */ + +/** + * lim_send_sme_rsp() - Send Generic Response to upper layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued + * eWNI_SME_msg_type_REQ message + * @vdev_id: vdev_id + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_START_RSP, eWNI_SME_STOP_BSS_RSP + * or eWNI_SME_SWITCH_CHL_RSP messages to applications above MAC + * Software. + * + * Return: None + */ +void lim_send_sme_rsp(struct mac_context *mac_ctx, uint16_t msg_type, + tSirResultCodes result_code, uint8_t vdev_id); + +/** + * lim_send_sme_start_bss_rsp() - Send Start BSS response + * @mac: Pointer to Global MAC structure + * @resultCode: Indicates the result of previously issued request + * @pe_session: PE session associated with the BSS + * @smesessionId: ID of the SME session associated with the BSS + * + * This function is called to send eWNI_SME_START_BSS_RSP + * message to applications above MAC Software. + */ +void lim_send_sme_start_bss_rsp(struct mac_context *mac, + tSirResultCodes resultCode, + struct pe_session *pe_session, + uint8_t smesessionId); + +/** + * lim_send_sme_join_reassoc_rsp() - Send Response to Upper Layers + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Indicates message type + * @result_code: Indicates the result of previously issued request + * @prot_status_code: Protocol Status Code + * @session_entry: PE Session Info + * @vdev_id: vdev_id + * + * This function is called by lim_process_sme_req_messages() to send + * eWNI_SME_JOIN_RSP or eWNI_SME_REASSOC_RSP messages to applications + * above MAC Software. + * + * Return: None + */ +void lim_send_sme_join_reassoc_rsp(struct mac_context *mac_ctx, + uint16_t msg_type, + tSirResultCodes result_code, + uint16_t prot_status_code, + struct pe_session *session_entry, + uint8_t vdev_id); + +/** + * lim_cm_send_connect_rsp() - Send Response to Upper Layers + * @mac_ctx: Pointer to Global MAC structure + * @pe_session: PE Session Info + * @req: connect req if pe session is NULL + * @reason: reason of failure, valid only if status is failure + * @connect_status: Indicates the status of the req + * @status_code: Protocol Status Code + * @is_reassoc: if reassoc resp + * + * Return: None + */ +void lim_cm_send_connect_rsp(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct cm_vdev_join_req *req, + enum wlan_cm_connect_fail_reason reason, + QDF_STATUS connect_status, + enum wlan_status_code status_code, + bool is_reassoc); + +/** + * lim_prepare_disconnect_done_ind() - Prepares the disconnect done ind message + * @mac_ctx: Global mac_ctx + * @session_id: PE session id + * @reason_code: Disconnect indication reason code + * @peer_mac_addr: MAC address of the peer + * + * Prepares the disconnect done indication message to be sent to the upper layer + * + * Return: QDF Status + */ +QDF_STATUS lim_prepare_disconnect_done_ind(struct mac_context *mac_ctx, + uint32_t **msg, + uint8_t session_id, + tSirResultCodes reason_code, + uint8_t *peer_mac_addr); + +/** + * lim_send_sme_disassoc_ntf() - Send disassoc notification to upper layer + * @mac: Global MAC context + * @peerMacAddr: The peer MAC addr to which disassociate was initiated + * @peerMldAddr: Peer MLD mac + * @reasonCode: The reason for Disassociation + * @disassocTrigger: The trigger for Disassociation + * @aid: The STAID. This parameter is present only on AP + * @smesessionId: ID of the SME session associated with the event + * @pe_session: The PE session associated with the event + * + * This function is used for sending eWNI_SME_DISASSOC_RSP, + * or eWNI_SME_DISASSOC_IND to upper layer depending on + * disassociation trigger. + * + * Return: None + */ +void lim_send_sme_disassoc_ntf(struct mac_context *mac, + tSirMacAddr peerMacAddr, + tSirMacAddr peerMldAddr, + tSirResultCodes reasonCode, + uint16_t disassocTrigger, + uint16_t aid, + uint8_t smesessionId, + struct pe_session *pe_session); + +/** + * lim_send_sme_deauth_ntf() - send deauth notice to upper layer + * @peerMacAddr: peer MAC addr to which deauthentication was initiated + * @reasonCode: the reason for Deauthetication + * @deauthTrigger: the trigger for Deauthetication + * @aid: the STAID. This parameter is present only on AP. + * @vdev_id: vdev id + * + * This function is used for sending eWNI_SME_DEAUTH_RSP or + * eWNI_SME_DEAUTH_IND to upper layers depending on deauthentication + * trigger. + * + * Return: None + */ +void lim_send_sme_deauth_ntf(struct mac_context *mac, tSirMacAddr peerMacAddr, + tSirResultCodes reasonCode, uint16_t deauthTrigger, + uint16_t aid, uint8_t vdev_id); + +void lim_send_sme_disassoc_ind(struct mac_context *, tpDphHashNode, struct pe_session *); +void lim_send_sme_deauth_ind(struct mac_context *, tpDphHashNode, + struct pe_session *pe_session); +/** + * lim_send_sme_set_context_rsp() - Send set context response to upper layer + * @mac: Pointer to Global MAC structure + * @peer_macaddr: the peer MAC addr to which setContext was performed + * @aid: the aid corresponding to the peer MAC address + * @resultCode: the result of previously issued Set Context Req message + * @pe_session: The PE session associated with the peer + * @smesessionId: ID of the SME session associated with the peer + * + * This function is called to send eWNI_SME_SETCONTEXT_RSP message to + * upper layer + * + * Return: None + */ +void lim_send_sme_set_context_rsp(struct mac_context *mac, + struct qdf_mac_addr peer_macaddr, + uint16_t aid, + tSirResultCodes resultCode, + struct pe_session *pe_session, + uint8_t smesessionId); + +/** + * lim_handle_delete_bss_rsp () - API to handle delete bss response + * @mac: global mac structure + * @del_bss_rsp: pointer to del bss response + * + * Return: None + */ +void lim_handle_delete_bss_rsp(struct mac_context *mac, + struct del_bss_resp *del_bss_rsp); + +/** + * lim_handle_csa_offload_msg() - Handle CSA offload message + * @mac_ctx: pointer to global adapter context + * @msg: Message pointer. + * + * Return: None + */ +void lim_handle_csa_offload_msg(struct mac_context *mac_ctx, + struct scheduler_msg *msg); + +void +lim_send_sme_aggr_qos_rsp(struct mac_context *mac, tpSirAggrQosRsp aggrQosRsp, + uint8_t smesessionId); + +/** + * lim_send_sme_addts_rsp() - sends SME ADDTS RSP + * @mac: global mac structure + * @rspReqd: is SmeAddTsRsp required + * @status: status code of SME_ADD_TS_RSP + * @pe_session: The PE session associated with the connection + * @tspec: The TSpec that was added + * @smesessionId: ID of the SME session associated with the connection + * + * This function sends a eWNI_SME_ADDTS_RSP to upper layer + * + * Return: None + */ +void lim_send_sme_addts_rsp(struct mac_context *mac, + uint8_t rspReqd, uint32_t status, + struct pe_session *pe_session, + struct mac_tspec_ie tspec, + uint8_t smesessionId); + +void lim_send_sme_delts_rsp(struct mac_context *mac, tpSirDeltsReq delts, + uint32_t status, struct pe_session *pe_session, + uint8_t smesessionId); +void lim_send_sme_delts_ind(struct mac_context *mac, + struct delts_req_info *delts, + uint16_t aid, struct pe_session *); + +#ifdef FEATURE_WLAN_ESE +void lim_send_sme_pe_ese_tsm_rsp(struct mac_context *mac, tAniGetTsmStatsRsp *pStats); +#endif + +void lim_send_sme_max_assoc_exceeded_ntf(struct mac_context *mac, tSirMacAddr peerMacAddr, + uint8_t smesessionId); + +void lim_send_sme_ap_channel_switch_resp(struct mac_context *mac, + struct pe_session *pe_session, + struct vdev_start_response *rsp); +/* + * lim_process_beacon_tx_success_ind() - handle successful beacon transmission + * indication from the FW This is a generic event generated by the FW after the + * first beacon is sent out after the beacon template update by the host. + * + * @mac_ctx: Global mac_ctx + * @msg_type: msg_type + */ +void +lim_process_beacon_tx_success_ind(struct mac_context *mac, uint16_t msgType, + void *event); + +/** + * lim_handle_sta_csa_param() - Handle CSA offload param + * @mac_ctx: pointer to global adapter context + * @csa_params: csa parameters. + * @send_status: Flag to send CSA status to fw in case of failure + * + * Return: None + */ +void lim_handle_sta_csa_param(struct mac_context *mac_ctx, + struct csa_offload_params *csa_params, + bool send_status); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_handle_mlo_sta_csa_param() - handle mlo sta csa parameters + * @vdev: vdev + * @csa_params: csa parameters + * + * Return: None + */ +void lim_handle_mlo_sta_csa_param(struct wlan_objmgr_vdev *vdev, + struct csa_offload_params *csa_params); +#endif /* WLAN_FEATURE_11BE_MLO */ + +/** lim_send_stop_bss_response() - Send stop bss response to CSR + * + * @mac_ctx : Global mac ctx + * @vdev_id : vdev_id + * @result_code: result + * + * Return: None + */ +void lim_send_stop_bss_response(struct mac_context *mac_ctx, uint8_t vdev_id, + tSirResultCodes result_code); + +/** + * lim_nss_or_ch_width_update_rsp() - send NSS/ch_width update response to SME + * @mac_ctx Pointer to Global MAC structure + * @status: nss/ch_width update status + * @reason: Indicates whether it's from NSS update or ch_width update + * + * Return: None + */ +void lim_nss_or_ch_width_update_rsp(struct mac_context *mac_ctx, + uint8_t vdev_id, QDF_STATUS status, + enum sir_bcn_update_reason reason); +#endif /* __LIM_SEND_SME_RSP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h new file mode 100644 index 0000000000..488529a81b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_ser_des_utils.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_ser_des_utils.h contains the utility definitions + * LIM uses while processing messages from upper layer software + * modules + * Author: Chandra Modumudi + * Date: 10/20/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SERDES_UTILS_H +#define __LIM_SERDES_UTILS_H + +#include "sir_api.h" +#include "ani_system_defs.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_prop_exts_utils.h" + +/* Byte String <--> uint16_t/uint32_t copy functions */ +static inline void lim_copy_u16(uint8_t *ptr, uint16_t u16Val) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + *ptr++ = (uint8_t) (u16Val & 0xff); + *ptr = (uint8_t) ((u16Val >> 8) & 0xff); +#else +#error "Unknown combination of OS Type and endianness" +#endif +} + +static inline uint16_t lim_get_u16(uint8_t *ptr) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + return ((uint16_t) (*(ptr + 1) << 8)) | ((uint16_t) (*ptr)); +#else +#error "Unknown combination of OS Type and endianness" +#endif +} + +static inline void lim_copy_u32(uint8_t *ptr, uint32_t u32Val) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + *ptr++ = (uint8_t) (u32Val & 0xff); + *ptr++ = (uint8_t) ((u32Val >> 8) & 0xff); + *ptr++ = (uint8_t) ((u32Val >> 16) & 0xff); + *ptr = (uint8_t) ((u32Val >> 24) & 0xff); +#else +#error "Unknown combination of OS Type and endianness" +#endif +} + +static inline uint32_t lim_get_u32(uint8_t *ptr) +{ +#if ((defined(ANI_OS_TYPE_QNX) && defined(ANI_LITTLE_BYTE_ENDIAN)) || \ + (defined(ANI_OS_TYPE_ANDROID) && defined(ANI_LITTLE_BYTE_ENDIAN))) + return ((*(ptr + 3) << 24) | + (*(ptr + 2) << 16) | (*(ptr + 1) << 8) | (*(ptr))); +#else +#error "Unknown combination of OS Type and endianness" +#endif +} + +/** + * lim_copy_u16_be()- This API copies a u16 value in buffer + * to network byte order + * @ptr: pointer to buffer + * @u16_val: value needs to be copied + * + * Return: None + */ +static inline void lim_copy_u16_be(uint8_t *ptr, uint16_t u16_val) +{ + ptr[0] = u16_val >> 8; + ptr[1] = u16_val & 0xff; +} + +/** + * lim_copy_u16_be()- This API reads u16 value from network byte order buffer + * @ptr: pointer to buffer + * + * Return: 16bit value + */ +static inline uint16_t lim_get_u16_be(uint8_t *buf) +{ + return (buf[0] << 8) | buf[1]; +} +#endif /* __LIM_SERDES_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session.c new file mode 100644 index 0000000000..3d32081c71 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session.c @@ -0,0 +1,1216 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \file lim_session.c + + \brief implementation for lim Session related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "lim_ft_defs.h" +#include "lim_ft.h" +#include "lim_session.h" +#include "lim_utils.h" + +#include "sch_api.h" +#include "lim_send_messages.h" +#include "cfg_ucfg_api.h" +#include +#include + +#ifdef WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +static struct sDphHashNode *g_dph_node_array; + +QDF_STATUS pe_allocate_dph_node_array_buffer(void) +{ + uint32_t buf_size; + + buf_size = WLAN_MAX_VDEVS * (SIR_SAP_MAX_NUM_PEERS + 1) * + sizeof(struct sDphHashNode); + g_dph_node_array = qdf_mem_malloc(buf_size); + if (!g_dph_node_array) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} + +void pe_free_dph_node_array_buffer(void) +{ + qdf_mem_free(g_dph_node_array); + g_dph_node_array = NULL; +} + +static inline +struct sDphHashNode *pe_get_session_dph_node_array(uint8_t session_id) +{ + return &g_dph_node_array[session_id * (SIR_SAP_MAX_NUM_PEERS + 1)]; +} + +#else /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ +static struct sDphHashNode + g_dph_node_array[WLAN_MAX_VDEVS][SIR_SAP_MAX_NUM_PEERS + 1]; + +static inline +struct sDphHashNode *pe_get_session_dph_node_array(uint8_t session_id) +{ + return g_dph_node_array[session_id]; +} +#endif /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ + +/*-------------------------------------------------------------------------- + + \brief pe_init_beacon_params() - Initialize the beaconParams structure + + \param struct pe_session * - pointer to the session context or NULL if session can not be created. + \return void + \sa + + --------------------------------------------------------------------------*/ + +static void pe_init_beacon_params(struct mac_context *mac, + struct pe_session *pe_session) +{ + pe_session->beaconParams.beaconInterval = 0; + pe_session->beaconParams.fShortPreamble = 0; + pe_session->beaconParams.llaCoexist = 0; + pe_session->beaconParams.llbCoexist = 0; + pe_session->beaconParams.llgCoexist = 0; + pe_session->beaconParams.ht20Coexist = 0; + pe_session->beaconParams.llnNonGFCoexist = 0; + pe_session->beaconParams.fRIFSMode = 0; + pe_session->beaconParams.fLsigTXOPProtectionFullSupport = 0; + pe_session->beaconParams.gHTObssMode = 0; + + /* Number of legacy STAs associated */ + qdf_mem_zero((void *)&pe_session->gLim11bParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&pe_session->gLim11aParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&pe_session->gLim11gParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&pe_session->gLimNonGfParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&pe_session->gLimHt20Params, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&pe_session->gLimLsigTxopParams, + sizeof(tLimProtStaParams)); + qdf_mem_zero((void *)&pe_session->gLimOlbcParams, + sizeof(tLimProtStaParams)); +} + +/* + * pe_reset_protection_callback() - resets protection structs so that when an AP + * causing use of protection goes away, corresponding protection bit can be + * reset + * @ptr: pointer to pe_session + * + * This function resets protection structs so that when an AP causing use of + * protection goes away, corresponding protection bit can be reset. This allowes + * protection bits to be reset once legacy overlapping APs are gone. + * + * Return: void + */ +static void pe_reset_protection_callback(void *ptr) +{ + struct pe_session *pe_session_entry = (struct pe_session *)ptr; + struct mac_context *mac_ctx = pe_session_entry->mac_ctx; + int8_t i = 0; + tUpdateBeaconParams beacon_params; + uint16_t current_protection_state = 0; + tpDphHashNode station_hash_node = NULL; + tSirMacHTOperatingMode old_op_mode; + bool bcn_prms_changed = false; + + if (pe_session_entry->valid == false) { + pe_err("session already deleted. exiting timer callback"); + return; + } + + /* + * During CAC period, if the callback is triggered, the beacon + * template may get updated. Subsequently if the vdev is not up, the + * vdev would be made up -- which should not happen during the CAC + * period. To avoid this, ignore the protection callback if the session + * is not yet up. + */ + if (!wma_is_vdev_up(pe_session_entry->smeSessionId)) { + pe_err("session is not up yet. exiting timer callback"); + return; + } + + /* + * If dfsIncludeChanSwIe is set restrat timer as we are going to change + * channel and no point in checking protection mode for this channel. + */ + if (pe_session_entry->dfsIncludeChanSwIe) { + pe_err("CSA going on restart timer"); + goto restart_timer; + } + current_protection_state |= + pe_session_entry->gLimOverlap11gParams.protectionEnabled | + pe_session_entry->gLimOverlap11aParams.protectionEnabled << 1 | + pe_session_entry->gLimOverlapHt20Params.protectionEnabled << 2 | + pe_session_entry->gLimOverlapNonGfParams.protectionEnabled << 3 | + pe_session_entry->gLimOlbcParams.protectionEnabled << 4; + + pe_debug("old protection state: 0x%04X, new protection state: 0x%04X", + pe_session_entry->old_protection_state, + current_protection_state); + + qdf_mem_zero(&pe_session_entry->gLimOverlap11gParams, + sizeof(pe_session_entry->gLimOverlap11gParams)); + qdf_mem_zero(&pe_session_entry->gLimOverlap11aParams, + sizeof(pe_session_entry->gLimOverlap11aParams)); + qdf_mem_zero(&pe_session_entry->gLimOverlapHt20Params, + sizeof(pe_session_entry->gLimOverlapHt20Params)); + qdf_mem_zero(&pe_session_entry->gLimOverlapNonGfParams, + sizeof(pe_session_entry->gLimOverlapNonGfParams)); + + qdf_mem_zero(&pe_session_entry->gLimOlbcParams, + sizeof(pe_session_entry->gLimOlbcParams)); + + /* + * Do not reset fShortPreamble and beaconInterval, as they + * are not updated. + */ + pe_session_entry->beaconParams.llaCoexist = 0; + pe_session_entry->beaconParams.llbCoexist = 0; + pe_session_entry->beaconParams.llgCoexist = 0; + pe_session_entry->beaconParams.ht20Coexist = 0; + pe_session_entry->beaconParams.llnNonGFCoexist = 0; + pe_session_entry->beaconParams.fRIFSMode = 0; + pe_session_entry->beaconParams.fLsigTXOPProtectionFullSupport = 0; + pe_session_entry->beaconParams.gHTObssMode = 0; + + + old_op_mode = pe_session_entry->htOperMode; + pe_session_entry->htOperMode = eSIR_HT_OP_MODE_PURE; + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + /* index 0, is self node, peers start from 1 */ + for (i = 1 ; i <= mac_ctx->lim.max_sta_of_pe_session; i++) { + station_hash_node = dph_get_hash_entry(mac_ctx, i, + &pe_session_entry->dph.dphHashTable); + if (!station_hash_node) + continue; + lim_decide_ap_protection(mac_ctx, station_hash_node->staAddr, + &beacon_params, pe_session_entry); + } + + if (pe_session_entry->htOperMode != old_op_mode) + bcn_prms_changed = true; + + if ((current_protection_state != + pe_session_entry->old_protection_state) && + (false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running)) { + pe_debug("protection changed, update beacon template"); + /* update beacon fix params and send update to FW */ + qdf_mem_zero(&beacon_params, sizeof(tUpdateBeaconParams)); + beacon_params.bss_idx = pe_session_entry->vdev_id; + beacon_params.fShortPreamble = + pe_session_entry->beaconParams.fShortPreamble; + beacon_params.beaconInterval = + pe_session_entry->beaconParams.beaconInterval; + beacon_params.llaCoexist = + pe_session_entry->beaconParams.llaCoexist; + beacon_params.llbCoexist = + pe_session_entry->beaconParams.llbCoexist; + beacon_params.llgCoexist = + pe_session_entry->beaconParams.llgCoexist; + beacon_params.ht20MhzCoexist = + pe_session_entry->beaconParams.ht20Coexist; + beacon_params.llnNonGFCoexist = + pe_session_entry->beaconParams.llnNonGFCoexist; + beacon_params.fLsigTXOPProtectionFullSupport = + pe_session_entry->beaconParams. + fLsigTXOPProtectionFullSupport; + beacon_params.fRIFSMode = + pe_session_entry->beaconParams.fRIFSMode; + beacon_params.vdev_id = + pe_session_entry->vdev_id; + beacon_params.paramChangeBitmap |= PARAM_llBCOEXIST_CHANGED; + bcn_prms_changed = true; + } + + if (bcn_prms_changed) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session_entry); + lim_send_beacon_params(mac_ctx, &beacon_params, pe_session_entry); + } + + pe_session_entry->old_protection_state = current_protection_state; +restart_timer: + if (qdf_mc_timer_start(&pe_session_entry-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME) + != QDF_STATUS_SUCCESS) { + pe_err("cannot create or start protectionFieldsResetTimer"); + } +} + +/** + * pe_init_pmf_comeback_timer: init PMF comeback timer + * @mac_ctx: pointer to global adapter context + * @session: pe session + * + * Return: void + */ +static void +pe_init_pmf_comeback_timer(tpAniSirGlobal mac_ctx, struct pe_session *session) +{ + QDF_STATUS status; + + if (session->opmode != QDF_STA_MODE) + return; + + session->pmf_retry_timer_info.mac = mac_ctx; + session->pmf_retry_timer_info.vdev_id = session->vdev_id; + session->pmf_retry_timer_info.retried = false; + status = qdf_mc_timer_init( + &session->pmf_retry_timer, QDF_TIMER_TYPE_SW, + lim_pmf_comeback_timer_callback, + (void *)&session->pmf_retry_timer_info); + if (!QDF_IS_STATUS_SUCCESS(status)) + pe_err("cannot init pmf comeback timer"); +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * pe_delete_fils_info: API to delete fils session info + * @session: pe session + * + * Return: void + */ +void pe_delete_fils_info(struct pe_session *session) +{ + struct pe_fils_session *fils_info; + + if (!session || (session && !session->valid)) { + pe_debug("session is not valid"); + return; + } + fils_info = session->fils_info; + if (!fils_info) { + pe_debug("fils info not found"); + return; + } + if (fils_info->keyname_nai_data) + qdf_mem_free(fils_info->keyname_nai_data); + if (fils_info->fils_erp_reauth_pkt) + qdf_mem_free(fils_info->fils_erp_reauth_pkt); + if (fils_info->fils_rrk) + qdf_mem_free(fils_info->fils_rrk); + if (fils_info->fils_rik) + qdf_mem_free(fils_info->fils_rik); + if (fils_info->fils_eap_finish_pkt) + qdf_mem_free(fils_info->fils_eap_finish_pkt); + if (fils_info->fils_rmsk) + qdf_mem_free(fils_info->fils_rmsk); + if (fils_info->fils_pmk) + qdf_mem_free(fils_info->fils_pmk); + if (fils_info->auth_info.keyname) + qdf_mem_free(fils_info->auth_info.keyname); + if (fils_info->auth_info.domain_name) + qdf_mem_free(fils_info->auth_info.domain_name); + if (fils_info->hlp_data) + qdf_mem_free(fils_info->hlp_data); + qdf_mem_free(fils_info); + session->fils_info = NULL; +} +/** + * pe_init_fils_info: API to initialize fils session info elements to null + * @session: pe session + * + * Return: void + */ +static void pe_init_fils_info(struct pe_session *session) +{ + struct pe_fils_session *fils_info; + + if (!session || (session && !session->valid)) { + pe_debug("session is not valid"); + return; + } + session->fils_info = qdf_mem_malloc(sizeof(struct pe_fils_session)); + fils_info = session->fils_info; + if (!fils_info) + return; + fils_info->keyname_nai_data = NULL; + fils_info->fils_erp_reauth_pkt = NULL; + fils_info->fils_rrk = NULL; + fils_info->fils_rik = NULL; + fils_info->fils_eap_finish_pkt = NULL; + fils_info->fils_rmsk = NULL; + fils_info->fils_pmk = NULL; + fils_info->auth_info.keyname = NULL; + fils_info->auth_info.domain_name = NULL; +} +#else +static void pe_delete_fils_info(struct pe_session *session) { } +static void pe_init_fils_info(struct pe_session *session) { } +#endif + +/** + * lim_get_peer_idxpool_size: get number of peer idx pool size + * @num_sta: Max number of STA + * @bss_type: BSS type + * + * The peer index start from 1 and thus index 0 is not used, so + * add 1 to the max sta. For STA if TDLS is enabled add 2 as + * index 1 is reserved for peer BSS. + * + * Return: number of peer idx pool size + */ +#ifdef FEATURE_WLAN_TDLS +static inline uint8_t +lim_get_peer_idxpool_size(uint16_t num_sta, enum bss_type bss_type) +{ + /* + * In station role, index 1 is reserved for peer + * corresponding to AP. For TDLS the index should + * start from 2 + */ + if (bss_type == eSIR_INFRASTRUCTURE_MODE) + return num_sta + 2; + else + return num_sta + 1; + +} +#else +static inline uint8_t +lim_get_peer_idxpool_size(uint16_t num_sta, enum bss_type bss_type) +{ + return num_sta + 1; +} +#endif + +void lim_set_bcn_probe_filter(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t sap_channel) +{ + struct mgmt_beacon_probe_filter *filter; + enum bss_type bss_type; + uint8_t session_id; + tSirMacAddr *bssid; + + if (!session) { + pe_err("Invalid session pointer"); + return; + } + + bss_type = session->bssType; + session_id = session->peSessionId; + bssid = &session->bssId; + + if (session_id >= WLAN_MAX_VDEVS) { + pe_err("vdev %d Invalid session_id %d of type %d", + session->vdev_id, session_id, bss_type); + return; + } + + filter = &mac_ctx->bcn_filter; + + if (eSIR_INFRASTRUCTURE_MODE == bss_type) { + filter->num_sta_sessions++; + sir_copy_mac_addr(filter->sta_bssid[session_id], *bssid); + } else if (eSIR_INFRA_AP_MODE == bss_type) { + if (!sap_channel) { + pe_err("vdev %d with invalid chan", session->vdev_id); + return; + } + filter->num_sap_sessions++; + filter->sap_channel[session_id] = sap_channel; + } +} + +void lim_reset_bcn_probe_filter(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct mgmt_beacon_probe_filter *filter; + enum bss_type bss_type; + uint8_t session_id; + + if (!session) { + pe_err("Invalid session pointer"); + return; + } + + bss_type = session->bssType; + session_id = session->peSessionId; + + if (session_id >= WLAN_MAX_VDEVS) { + pe_err("Invalid session_id %d of type %d", + session_id, bss_type); + return; + } + + filter = &mac_ctx->bcn_filter; + + if (eSIR_INFRASTRUCTURE_MODE == bss_type) { + if (filter->num_sta_sessions) + filter->num_sta_sessions--; + qdf_mem_zero(&filter->sta_bssid[session_id], + sizeof(tSirMacAddr)); + pe_debug("Cleared STA Filter for session %d", session_id); + } else if (eSIR_INFRA_AP_MODE == bss_type) { + if (filter->num_sap_sessions) + filter->num_sap_sessions--; + filter->sap_channel[session_id] = 0; + pe_debug("Cleared SAP Filter for session %d", session_id); + } + + pe_debug("sta %d sap %d", filter->num_sta_sessions, + filter->num_sap_sessions); +} + +void lim_update_bcn_probe_filter(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct mgmt_beacon_probe_filter *filter; + enum bss_type bss_type; + uint8_t session_id; + + if (!session) { + pe_err("Invalid session pointer"); + return; + } + + bss_type = session->bssType; + session_id = session->peSessionId; + + if (session_id >= WLAN_MAX_VDEVS) { + pe_err("Invalid session_id %d of type %d", + session_id, bss_type); + return; + } + + filter = &mac_ctx->bcn_filter; + + if (eSIR_INFRA_AP_MODE == bss_type) { + filter->sap_channel[session_id] = wlan_reg_freq_to_chan( + mac_ctx->pdev, session->curr_op_freq); + pe_debug("Updated SAP Filter for session %d channel %d", + session_id, filter->sap_channel[session_id]); + } else { + pe_debug("Invalid session type %d session id %d", + bss_type, session_id); + } + + pe_debug("sta %d sap %d", filter->num_sta_sessions, + filter->num_sap_sessions); +} + +struct pe_session *pe_create_session(struct mac_context *mac, + uint8_t *bssid, uint8_t *sessionId, + uint16_t numSta, enum bss_type bssType, + uint8_t vdev_id) +{ + QDF_STATUS status; + uint8_t i; + struct pe_session *session_ptr; + struct wlan_objmgr_vdev *vdev; + + for (i = 0; i < mac->lim.maxBssId; i++) { + /* Find first free room in session table */ + if (mac->lim.gpSession[i].valid == true) + continue; + break; + } + + if (i == mac->lim.maxBssId) { + pe_err("Session can't be created. Reached max sessions"); + return NULL; + } + + session_ptr = &mac->lim.gpSession[i]; + qdf_mem_zero((void *)session_ptr, sizeof(struct pe_session)); + /* Allocate space for Station Table for this session. */ + session_ptr->dph.dphHashTable.pHashTable = + qdf_mem_malloc(sizeof(tpDphHashNode) * (numSta + 1)); + if (!session_ptr->dph.dphHashTable.pHashTable) + return NULL; + + session_ptr->dph.dphHashTable.pDphNodeArray = + pe_get_session_dph_node_array(i); + session_ptr->dph.dphHashTable.size = numSta + 1; + dph_hash_table_init(mac, &session_ptr->dph.dphHashTable); + + /* Copy the BSSID to the session table */ + sir_copy_mac_addr(session_ptr->bssId, bssid); + if (bssType == eSIR_MONITOR_MODE) + sir_copy_mac_addr(mac->lim.gpSession[i].self_mac_addr, bssid); + session_ptr->valid = true; + /* Initialize the SME and MLM states to IDLE */ + session_ptr->limMlmState = eLIM_MLM_IDLE_STATE; + session_ptr->limSmeState = eLIM_SME_IDLE_STATE; + session_ptr->limCurrentAuthType = eSIR_OPEN_SYSTEM; + pe_init_beacon_params(mac, &mac->lim.gpSession[i]); + session_ptr->is11Rconnection = false; + *sessionId = i; + session_ptr->peSessionId = i; + session_ptr->bssType = bssType; + session_ptr->gLimPhyMode = WNI_CFG_PHY_MODE_11G; + /* Initialize CB mode variables when session is created */ + session_ptr->htSupportedChannelWidthSet = 0; + session_ptr->htRecommendedTxWidthSet = 0; + session_ptr->htSecondaryChannelOffset = 0; +#ifdef FEATURE_WLAN_TDLS + qdf_mem_zero(session_ptr->peerAIDBitmap, + sizeof(session_ptr->peerAIDBitmap)); +#endif + lim_update_tdls_set_state_for_fw(session_ptr, true); + session_ptr->fWaitForProbeRsp = 0; + session_ptr->fIgnoreCapsChange = 0; + session_ptr->is_session_obss_color_collision_det_enabled = + mac->mlme_cfg->obss_ht40.obss_color_collision_offload_enabled; + + if (bssType == eSIR_INFRA_AP_MODE) { + session_ptr->pSchProbeRspTemplate = + qdf_mem_malloc(SIR_MAX_PROBE_RESP_SIZE); + session_ptr->pSchBeaconFrameBegin = + qdf_mem_malloc(SIR_MAX_BEACON_SIZE); + session_ptr->pSchBeaconFrameEnd = + qdf_mem_malloc(SIR_MAX_BEACON_SIZE); + if ((!session_ptr->pSchProbeRspTemplate) + || (!session_ptr->pSchBeaconFrameBegin) + || (!session_ptr->pSchBeaconFrameEnd)) { + goto free_session_attrs; + } + } + + /* + * Get vdev object from soc which automatically increments + * reference count. + */ + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, + vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_err("vdev is NULL for vdev_id: %u", vdev_id); + goto free_session_attrs; + } + session_ptr->vdev = vdev; + session_ptr->vdev_id = vdev_id; + session_ptr->mac_ctx = mac; + session_ptr->opmode = wlan_vdev_mlme_get_opmode(vdev); + mlme_set_tdls_chan_switch_prohibited(vdev, false); + mlme_set_tdls_prohibited(vdev, false); + pe_debug("Create PE session: %d opmode %d vdev_id %d BSSID: "QDF_MAC_ADDR_FMT" Max No of STA: %d", + *sessionId, session_ptr->opmode, vdev_id, + QDF_MAC_ADDR_REF(bssid), numSta); + + if (!lim_create_peer_idxpool( + session_ptr, + lim_get_peer_idxpool_size(numSta, bssType))) + goto free_session_attrs; + + if (eSIR_INFRASTRUCTURE_MODE == bssType) + lim_ft_open(mac, &mac->lim.gpSession[i]); + + if (eSIR_MONITOR_MODE == bssType) + lim_ft_open(mac, &mac->lim.gpSession[i]); + + if (eSIR_INFRA_AP_MODE == bssType) { + session_ptr->old_protection_state = 0; + session_ptr->is_session_obss_offload_enabled = false; + session_ptr->is_obss_reset_timer_initialized = false; + + status = qdf_mc_timer_init(&session_ptr-> + protection_fields_reset_timer, + QDF_TIMER_TYPE_SW, + pe_reset_protection_callback, + (void *)&mac->lim.gpSession[i]); + + if (QDF_IS_STATUS_ERROR(status)) + pe_err("cannot create protection fields reset timer"); + else + session_ptr->is_obss_reset_timer_initialized = true; + + qdf_wake_lock_create(&session_ptr->ap_ecsa_wakelock, + "ap_ecsa_wakelock"); + qdf_runtime_lock_init(&session_ptr->ap_ecsa_runtime_lock); + status = qdf_mc_timer_init(&session_ptr->ap_ecsa_timer, + QDF_TIMER_TYPE_WAKE_APPS, + lim_process_ap_ecsa_timeout, + (void *)&mac->lim.gpSession[i]); + if (status != QDF_STATUS_SUCCESS) + pe_err("cannot create ap_ecsa_timer"); + } + if (session_ptr->opmode == QDF_STA_MODE) + session_ptr->is_session_obss_color_collision_det_enabled = + mac->mlme_cfg->obss_ht40.bss_color_collision_det_sta; + pe_init_fils_info(session_ptr); + pe_init_pmf_comeback_timer(mac, session_ptr); + session_ptr->ht_client_cnt = 0; + /* following is invalid value since seq number is 12 bit */ + session_ptr->prev_auth_seq_num = 0xFFFF; + + session_ptr->user_edca_set = 0; + session_ptr->join_probe_cnt = 0; + + return &mac->lim.gpSession[i]; + +free_session_attrs: + lim_free_peer_idxpool(session_ptr); + qdf_mem_free(session_ptr->pSchProbeRspTemplate); + qdf_mem_free(session_ptr->pSchBeaconFrameBegin); + qdf_mem_free(session_ptr->pSchBeaconFrameEnd); + + session_ptr->pSchProbeRspTemplate = NULL; + session_ptr->pSchBeaconFrameBegin = NULL; + session_ptr->pSchBeaconFrameEnd = NULL; + + qdf_mem_free(session_ptr->dph.dphHashTable.pHashTable); + qdf_mem_zero(session_ptr->dph.dphHashTable.pDphNodeArray, + sizeof(struct sDphHashNode) * (SIR_SAP_MAX_NUM_PEERS + 1)); + + session_ptr->dph.dphHashTable.pHashTable = NULL; + session_ptr->dph.dphHashTable.pDphNodeArray = NULL; + session_ptr->valid = false; + + return NULL; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_bssid() - looks up the PE session given the BSSID. + + This function returns the session context and the session ID if the session + corresponding to the given BSSID is found in the PE session table. + + \param mac - pointer to global adapter context + \param bssid - BSSID of the session + \param sessionId -session ID is returned here, if session is found. + + \return struct pe_session * - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +struct pe_session *pe_find_session_by_bssid(struct mac_context *mac, uint8_t *bssid, + uint8_t *sessionId) +{ + uint8_t i; + + for (i = 0; i < mac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((mac->lim.gpSession[i].valid) + && (sir_compare_mac_addr(mac->lim.gpSession[i].bssId, + bssid))) { + *sessionId = i; + return &mac->lim.gpSession[i]; + } + } + + return NULL; + +} + +struct pe_session *pe_find_session_by_vdev_id(struct mac_context *mac, + uint8_t vdev_id) +{ + uint8_t i; + + for (i = 0; i < mac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((mac->lim.gpSession[i].valid) && + (mac->lim.gpSession[i].vdev_id == vdev_id)) + return &mac->lim.gpSession[i]; + } + pe_debug("Session lookup fails for vdev_id: %d", vdev_id); + + return NULL; +} + +struct pe_session +*pe_find_session_by_vdev_id_and_state(struct mac_context *mac, + uint8_t vdev_id, + enum eLimMlmStates lim_state) +{ + uint8_t i; + + for (i = 0; i < mac->lim.maxBssId; i++) { + if (mac->lim.gpSession[i].valid && + mac->lim.gpSession[i].vdev_id == vdev_id && + mac->lim.gpSession[i].limMlmState == lim_state) + return &mac->lim.gpSession[i]; + } + pe_debug("Session lookup fails for vdev_id: %d, mlm state: %d", + vdev_id, lim_state); + + return NULL; +} + +struct pe_session * +pe_find_session_by_bssid_and_vdev_id(struct mac_context *mac, + uint8_t *bssid, + uint8_t vdev_id, + uint8_t *sessionId) +{ + uint8_t i; + + for (i = 0; i < mac->lim.maxBssId; i++) { + /* If BSSID matches return corresponding tables address */ + if ((mac->lim.gpSession[i].valid) && + (mac->lim.gpSession[i].vdev_id == vdev_id) && + (sir_compare_mac_addr(mac->lim.gpSession[i].bssId, + bssid))) { + *sessionId = i; + return &mac->lim.gpSession[i]; + } + } + + return NULL; +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_session_id() - looks up the PE session given the session ID. + + This function returns the session context if the session + corresponding to the given session ID is found in the PE session table. + + \param mac - pointer to global adapter context + \param sessionId -session ID for which session context needs to be looked up. + + \return struct pe_session * - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ +struct pe_session *pe_find_session_by_session_id(struct mac_context *mac, + uint8_t sessionId) +{ + if (sessionId >= mac->lim.maxBssId) { + pe_err("Invalid sessionId: %d", sessionId); + return NULL; + } + + if (mac->lim.gpSession[sessionId].valid) + return &mac->lim.gpSession[sessionId]; + + return NULL; +} + +static void lim_clear_pmfcomeback_timer(struct pe_session *session) +{ + if (session->opmode != QDF_STA_MODE) + return; + + pe_debug("deinit pmf comeback timer for vdev %d", session->vdev_id); + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&session->pmf_retry_timer)) + qdf_mc_timer_stop(&session->pmf_retry_timer); + qdf_mc_timer_destroy(&session->pmf_retry_timer); + session->pmf_retry_timer_info.retried = false; +} + +static void lim_clear_mbssid_info(struct wlan_objmgr_vdev *vdev) +{ + struct scan_mbssid_info mbssid_info = {0}; + + mlme_set_mbssid_info(vdev, &mbssid_info, INVALID_CHANNEL_NUM); +} + +/** + * pe_delete_session() - deletes the PE session given the session ID. + * @mac_ctx: pointer to global adapter context + * @session: session to be deleted. + * + * Deletes the given PE session + * + * Return: void + */ +void pe_delete_session(struct mac_context *mac_ctx, struct pe_session *session) +{ + uint16_t i = 0; + uint16_t n; + TX_TIMER *timer_ptr; + struct wlan_objmgr_vdev *vdev; + tpSirAssocRsp assoc_rsp; + + if (!session || (session && !session->valid)) { + pe_debug("session already deleted or not valid"); + return; + } + + pe_debug("Delete PE session: %d opmode: %d vdev_id: %d BSSID: "QDF_MAC_ADDR_FMT, + session->peSessionId, session->opmode, session->vdev_id, + QDF_MAC_ADDR_REF(session->bssId)); + + lim_reset_bcn_probe_filter(mac_ctx, session); + lim_sae_auth_cleanup_retry(mac_ctx, session->vdev_id); + lim_cleanup_power_change(mac_ctx, session); + lim_clear_mbssid_info(session->vdev); + + /* Restore default failure timeout */ + if (session->defaultAuthFailureTimeout) { + pe_debug("Restore default failure timeout"); + if (cfg_in_range(CFG_AUTH_FAILURE_TIMEOUT, + session->defaultAuthFailureTimeout)) + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = + session->defaultAuthFailureTimeout; + else + mac_ctx->mlme_cfg->timeouts.auth_failure_timeout = + cfg_default(CFG_AUTH_FAILURE_TIMEOUT); + } + + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + timer_ptr = &mac_ctx->lim.lim_timers.gpLimCnfWaitTimer[n]; + if (session->peSessionId == timer_ptr->sessionId) + if (true == tx_timer_running(timer_ptr)) + tx_timer_deactivate(timer_ptr); + } + + if (LIM_IS_AP_ROLE(session)) { + qdf_runtime_lock_deinit(&session->ap_ecsa_runtime_lock); + qdf_wake_lock_destroy(&session->ap_ecsa_wakelock); + qdf_mc_timer_stop(&session->protection_fields_reset_timer); + qdf_mc_timer_destroy(&session->protection_fields_reset_timer); + session->dfsIncludeChanSwIe = 0; + qdf_mc_timer_stop(&session->ap_ecsa_timer); + qdf_mc_timer_destroy(&session->ap_ecsa_timer); + lim_del_pmf_sa_query_timer(mac_ctx, session); + } + + /* Delete FT related information */ + lim_ft_cleanup(mac_ctx, session); + if (session->pLimStartBssReq) { + qdf_mem_free(session->pLimStartBssReq); + session->pLimStartBssReq = NULL; + } + + if (session->lim_join_req) { + qdf_mem_free(session->lim_join_req); + session->lim_join_req = NULL; + } + + if (session->pLimReAssocReq) { + qdf_mem_free(session->pLimReAssocReq); + session->pLimReAssocReq = NULL; + } + + if (session->pLimMlmJoinReq) { + qdf_mem_free(session->pLimMlmJoinReq); + session->pLimMlmJoinReq = NULL; + } + + if (session->dph.dphHashTable.pHashTable) { + qdf_mem_free(session->dph.dphHashTable.pHashTable); + session->dph.dphHashTable.pHashTable = NULL; + } + + if (session->dph.dphHashTable.pDphNodeArray) { + qdf_mem_zero(session->dph.dphHashTable.pDphNodeArray, + sizeof(struct sDphHashNode) * + (SIR_SAP_MAX_NUM_PEERS + 1)); + session->dph.dphHashTable.pDphNodeArray = NULL; + } + + lim_free_peer_idxpool(session); + + if (session->beacon) { + qdf_mem_free(session->beacon); + session->beacon = NULL; + session->bcnLen = 0; + } + + if (session->assoc_req) { + qdf_mem_free(session->assoc_req); + session->assoc_req = NULL; + session->assocReqLen = 0; + } + + if (session->assocRsp) { + qdf_mem_free(session->assocRsp); + session->assocRsp = NULL; + session->assocRspLen = 0; + } + + if (session->parsedAssocReq) { + tpSirAssocReq tmp_ptr = NULL; + /* Cleanup the individual allocation first */ + for (i = 0; i < session->dph.dphHashTable.size; i++) { + if (!session->parsedAssocReq[i]) + continue; + tmp_ptr = ((tpSirAssocReq) + (session->parsedAssocReq[i])); + lim_free_assoc_req_frm_buf(tmp_ptr); + qdf_mem_free(session->parsedAssocReq[i]); + session->parsedAssocReq[i] = NULL; + } + /* Cleanup the whole block */ + qdf_mem_free(session->parsedAssocReq); + session->parsedAssocReq = NULL; + } + if (session->limAssocResponseData) { + assoc_rsp = (tpSirAssocRsp) session->limAssocResponseData; + qdf_mem_free(assoc_rsp->sha384_ft_subelem.gtk); + qdf_mem_free(assoc_rsp->sha384_ft_subelem.igtk); + qdf_mem_free(session->limAssocResponseData); + session->limAssocResponseData = NULL; + } + if (session->pLimMlmReassocRetryReq) { + qdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } + if (session->pLimMlmReassocReq) { + qdf_mem_free(session->pLimMlmReassocReq); + session->pLimMlmReassocReq = NULL; + } + + if (session->pSchProbeRspTemplate) { + qdf_mem_free(session->pSchProbeRspTemplate); + session->pSchProbeRspTemplate = NULL; + } + + if (session->pSchBeaconFrameBegin) { + qdf_mem_free(session->pSchBeaconFrameBegin); + session->pSchBeaconFrameBegin = NULL; + } + + if (session->pSchBeaconFrameEnd) { + qdf_mem_free(session->pSchBeaconFrameEnd); + session->pSchBeaconFrameEnd = NULL; + } + + /* Must free the buffer before peSession invalid */ + if (session->add_ie_params.probeRespData_buff) { + qdf_mem_free(session->add_ie_params.probeRespData_buff); + session->add_ie_params.probeRespData_buff = NULL; + session->add_ie_params.probeRespDataLen = 0; + } + if (session->add_ie_params.assocRespData_buff) { + qdf_mem_free(session->add_ie_params.assocRespData_buff); + session->add_ie_params.assocRespData_buff = NULL; + session->add_ie_params.assocRespDataLen = 0; + } + if (session->add_ie_params.probeRespBCNData_buff) { + qdf_mem_free(session->add_ie_params.probeRespBCNData_buff); + session->add_ie_params.probeRespBCNData_buff = NULL; + session->add_ie_params.probeRespBCNDataLen = 0; + } + pe_delete_fils_info(session); + lim_clear_pmfcomeback_timer(session); + session->valid = false; + + session->mac_ctx = NULL; + + if (session->access_policy_vendor_ie) + qdf_mem_free(session->access_policy_vendor_ie); + + session->access_policy_vendor_ie = NULL; + + if (LIM_IS_AP_ROLE(session)) { + lim_check_and_reset_protection_params(mac_ctx); + wlan_set_sap_user_config_freq(session->vdev, 0); + } + + session->user_edca_set = 0; + + vdev = session->vdev; + session->vdev = NULL; + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +/*-------------------------------------------------------------------------- + \brief pe_find_session_by_peer_sta() - looks up the PE session given the Station Address. + + This function returns the session context and the session ID if the session + corresponding to the given station address is found in the PE session table. + + \param mac - pointer to global adapter context + \param sa - Peer STA Address of the session + \param sessionId -session ID is returned here, if session is found. + + \return struct pe_session * - pointer to the session context or NULL if session is not found. + + \sa + --------------------------------------------------------------------------*/ + +struct pe_session *pe_find_session_by_peer_sta(struct mac_context *mac, uint8_t *sa, + uint8_t *sessionId) +{ + uint8_t i; + tpDphHashNode pSta; + uint16_t aid; + + for (i = 0; i < mac->lim.maxBssId; i++) { + if ((mac->lim.gpSession[i].valid)) { + pSta = + dph_lookup_hash_entry(mac, sa, &aid, + &mac->lim.gpSession[i].dph. + dphHashTable); + if (pSta) { + *sessionId = i; + return &mac->lim.gpSession[i]; + } + } + } + + pe_debug("Session lookup fails for Peer: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sa)); + return NULL; +} + +/** + * pe_find_session_by_scan_id() - looks up the PE session for given scan id + * @mac_ctx: pointer to global adapter context + * @scan_id: scan id + * + * looks up the PE session for given scan id + * + * Return: pe session entry for given scan id if found else NULL + */ +struct pe_session *pe_find_session_by_scan_id(struct mac_context *mac_ctx, + uint32_t scan_id) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if ((mac_ctx->lim.gpSession[i].valid) && + (mac_ctx->lim.gpSession[i].ftPEContext.pFTPreAuthReq) && + (mac_ctx->lim.gpSession[i].ftPEContext.pFTPreAuthReq + ->scan_id == scan_id)) { + return &mac_ctx->lim.gpSession[i]; + } + } + return NULL; +} + +void lim_dump_session_info(struct mac_context *mac_ctx, + struct pe_session *pe_session) +{ + if (!mac_ctx || !pe_session) + return; + + pe_nofl_debug("vdev_id %d freq %d ch_bw %d freq0 %d freq1 %d, smps %d mode %d action %d, nss_1x1 %d vdev_nss %d nss %d, cbMode %d, dot11Mode %d, subfer %d subfee %d csn %d, is_cisco %d, WPS %d OSEN %d FILS %d AKM %d", + pe_session->vdev_id, pe_session->curr_op_freq, + pe_session->ch_width, pe_session->ch_center_freq_seg0, + pe_session->ch_center_freq_seg1, + mac_ctx->mlme_cfg->ht_caps.enable_smps, + mac_ctx->mlme_cfg->ht_caps.smps, + pe_session->send_smps_action, + pe_session->supported_nss_1x1, pe_session->vdev_nss, + pe_session->nss, pe_session->htSupportedChannelWidthSet, + pe_session->dot11mode, + pe_session->vht_config.su_beam_former, + pe_session->vht_config.su_beam_formee, + pe_session->vht_config.csnof_beamformer_antSup, + pe_session->isCiscoVendorAP, pe_session->wps_registration, + pe_session->isOSENConnection, + lim_is_fils_connection(pe_session), + pe_session->connected_akm); + + pe_nofl_debug(" MaxTxPwr %d RMF %d force_20_24 %d UAPSD flag 0x%2x auth type %d privacy %d", + pe_session->maxTxPower, pe_session->limRmfEnabled, + wlan_cm_get_force_20mhz_in_24ghz(pe_session->vdev), + pe_session->gUapsdPerAcBitmask, + mac_ctx->mlme_cfg->wep_params.auth_type, + mac_ctx->mlme_cfg->wep_params.is_privacy_enabled); +} + +#ifdef WLAN_FEATURE_11AX +void lim_dump_he_info(struct mac_context *mac, struct pe_session *session) +{ + struct mlme_legacy_priv *mlme_priv; + + if (!session->he_capable) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + + pe_nofl_debug(" HE info: bss_color %d default_pe %d ul mu %d, rx_pream_puncturing %d MCS LT_80: tx: 0x%x, rx: 0x%x, 160: tx: 0x%x, rx: 0x%x", + session->he_op.bss_color, session->he_op.default_pe, + session->he_config.ul_mu, + mac->he_cap_5g.rx_pream_puncturing, + mlme_priv->he_config.tx_he_mcs_map_lt_80, + mlme_priv->he_config.rx_he_mcs_map_lt_80, + *(uint16_t *)mlme_priv->he_config.tx_he_mcs_map_160, + *(uint16_t *)mlme_priv->he_config.rx_he_mcs_map_160); +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +void lim_dump_eht_info(struct pe_session *session) +{ + bool is_emlsr; + struct mlo_partner_info *partner_info; + struct qdf_mac_addr mld_addr = {0}; + uint8_t buffer[100] = {0}; + uint8_t idx, len = 0, buf_len = QDF_ARRAY_SIZE(buffer); + + if (!session->eht_capable) + return; + + wlan_vdev_obj_lock(session->vdev); + is_emlsr = wlan_vdev_mlme_cap_get(session->vdev, WLAN_VDEV_C_EMLSR_CAP); + wlan_vdev_obj_unlock(session->vdev); + + wlan_vdev_get_bss_peer_mld_mac(session->vdev, &mld_addr); + + if (!session->lim_join_req) + return; + + partner_info = &session->lim_join_req->partner_info; + for (idx = 0; idx < partner_info->num_partner_links; idx++) { + if (len >= buf_len) + break; + + len += qdf_scnprintf(buffer + len, buf_len - len, "Link %d: " QDF_MAC_ADDR_FMT, + partner_info->partner_link_info[idx].link_id, + QDF_MAC_ADDR_REF(partner_info->partner_link_info[idx].link_addr.bytes)); + } + + pe_nofl_debug(" 802.11be D-3.0, MLD: " QDF_MAC_ADDR_FMT " 320MHz %d num_sounding_dim_320 %d, eMLSR %d, partner_links %d, %s", + QDF_MAC_ADDR_REF(mld_addr.bytes), + session->eht_config.support_320mhz_6ghz, + session->eht_config.num_sounding_dim_320mhz, is_emlsr, + partner_info->num_partner_links, + len ? buffer : '\0'); +} +#endif + +/** + * pe_get_active_session_count() - function to return active pe session count + * + * @mac_ctx: pointer to global mac structure + * + * returns number of active pe session count + * + * Return: 0 if there are no active sessions else return number of active + * sessions + */ +uint8_t pe_get_active_session_count(struct mac_context *mac_ctx) +{ + uint8_t i, active_session_count = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid) + active_session_count++; + + return active_session_count; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c new file mode 100644 index 0000000000..1507ff6647 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \file lim_session_utils.c + \brief implementation for lim Session Utility APIs + \author Sunit Bhatia + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "lim_session_utils.h" +#include "lim_utils.h" + +/** + * lim_is_in_mcc() - check if device is in MCC + * @mac_ctx: Global MAC context. + * + * Return: true - if in MCC. + * false - Not in MCC + **/ +uint8_t lim_is_in_mcc(struct mac_context *mac_ctx) +{ + uint8_t i; + uint32_t freq = 0; + uint32_t curr_oper_freq = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* + * if another session is valid and it is on different channel + * it is an off channel operation. + */ + if ((mac_ctx->lim.gpSession[i].valid)) { + curr_oper_freq = + mac_ctx->lim.gpSession[i].curr_op_freq; + if (curr_oper_freq == 0) + continue; + if (freq == 0) + freq = curr_oper_freq; + else if (freq != curr_oper_freq) + return true; + } + } + return false; +} + +/** + * pe_get_current_stas_count() - Total stations associated on all sessions. + * @mac_ctx: Global MAC context. + * + * Return: true - Number of stations active on all sessions. + **/ +uint8_t pe_get_current_stas_count(struct mac_context *mac_ctx) +{ + uint8_t i; + uint8_t stacount = 0; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) + if (mac_ctx->lim.gpSession[i].valid == true) + stacount += + mac_ctx->lim.gpSession[i].gLimNumOfCurrentSTAs; + return stacount; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h new file mode 100644 index 0000000000..952838ae3b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_session_utils.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012-2015, 2018, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__LIM_SESSION_UTILS_H) +#define __LIM_SESSION_UTILS_H + +uint8_t lim_is_in_mcc(struct mac_context *mac); +uint8_t pe_get_current_stas_count(struct mac_context *mac); + +#endif /* #if !defined( __LIM_SESSION_UTILS_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c new file mode 100644 index 0000000000..ba6d6c05c4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_sme_req_utils.cc contains the utility functions + * for processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * 05/26/10 js WPA handling in (Re)Assoc frames + * + */ + +#include "wni_api.h" +#include "wni_cfg.h" +#include "sir_api.h" +#include "sch_api.h" +#include "utils_api.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "lim_ser_des_utils.h" +#include "lim_sme_req_utils.h" + +/** + * lim_is_rsn_ie_valid_in_sme_req_message() + * + * @mac_ctx Pointer to Global MAC structure + * @rsn_ie Pointer to received RSN IE + * + * This function is called to verify if the RSN IE received in various SME_REQ + * messages is valid or not + * + * Return: true when RSN IE is valid, false otherwise + * + */ +static uint8_t +lim_is_rsn_ie_valid_in_sme_req_message(struct mac_context *mac_ctx, + tpSirRSNie rsn_ie) +{ + uint8_t start = 0; + uint32_t val; + int len; + + val = mac_ctx->mlme_cfg->feature_flags.enable_rsn; + if (rsn_ie->length && !val) { + /* Privacy & RSN not enabled in CFG. + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + pe_debug("RSN ie len: %d RSN: %d", + rsn_ie->length, val); + } + + if (!rsn_ie->length) { + pe_debug("RSN IE length is 0"); + return true; + } + + if ((rsn_ie->rsnIEdata[0] != DOT11F_EID_RSN) +#ifdef FEATURE_WLAN_WAPI + && (rsn_ie->rsnIEdata[0] != DOT11F_EID_WAPI) +#endif + && (rsn_ie->rsnIEdata[0] != DOT11F_EID_WPA)) { + pe_err("RSN/WPA/WAPI EID: %d not [%d || %d]", + rsn_ie->rsnIEdata[0], DOT11F_EID_RSN, + DOT11F_EID_WPA); + return false; + } + + len = rsn_ie->length; + start = 0; + while (len > 0) { + switch (rsn_ie->rsnIEdata[start]) { + case DOT11F_EID_RSN: + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_RSN_MAX_LEN) + || (rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_RSN_MIN_LEN)) { + pe_err("RSN IE len: %d not [%d,%d]", + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_RSN_MIN_LEN, + DOT11F_IE_RSN_MAX_LEN); + return false; + } + break; + case DOT11F_EID_WPA: + /* Check validity of WPA IE */ + if (WLAN_MAX_IE_LEN <= start) + break; + + if (start <= (WLAN_MAX_IE_LEN - sizeof(uint32_t))) + val = sir_read_u32((uint8_t *) & + rsn_ie->rsnIEdata[start + 2]); + + if ((rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_WPA_MIN_LEN) + || (rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_WPA_MAX_LEN) + || (SIR_MAC_WPA_OUI != val)) { + pe_err("WPA IE len: %d not [%d,%d] OR data 0x%x not 0x%x", + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_WPA_MIN_LEN, + DOT11F_IE_WPA_MAX_LEN, + val, SIR_MAC_WPA_OUI); + return false; + } + break; +#ifdef FEATURE_WLAN_WAPI + case DOT11F_EID_WAPI: + if ((rsn_ie->rsnIEdata[start + 1] > + DOT11F_IE_WAPI_MAX_LEN) + || (rsn_ie->rsnIEdata[start + 1] < + DOT11F_IE_WAPI_MIN_LEN)) { + pe_err("WAPI IE len: %d not [%d,%d]", + rsn_ie->rsnIEdata[start + 1], + DOT11F_IE_WAPI_MIN_LEN, + DOT11F_IE_WAPI_MAX_LEN); + return false; + } + break; +#endif + default: + /* we will never be here, simply for completeness */ + return false; + } /* end of switch */ + /* EID + length field + length */ + start += 2 + rsn_ie->rsnIEdata[start + 1]; + len -= start; + } /* end while loop */ + return true; +} /*** end lim_is_rs_nie_valid_in_sme_req_message() ***/ + +/** + * lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message() - to set rsnie/wpaie + * + * @mac_ctx : Pointer to Global MAC structure + * @rsn_ie : Pointer to received RSN IE + * @session : Pointer to pe session + * + * This function is called to verify if the RSN IE received in various + * SME_REQ messages is valid or not. RSN IE validity checks are performed in + * this function + * + * Return: true when RSN IE is valid, false otherwise + */ +uint8_t +lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(struct mac_context *mac_ctx, + tpSirRSNie rsn_ie, + struct pe_session *session) +{ + uint32_t ret; + uint8_t wpa_idx = 0; + uint32_t val; + bool privacy; + + privacy = mac_ctx->mlme_cfg->wep_params.is_privacy_enabled; + + val = mac_ctx->mlme_cfg->feature_flags.enable_rsn; + if (rsn_ie->length && (!privacy || !val)) { + /* + * Privacy & RSN not enabled in CFG. + * In order to allow mixed mode for Guest access + * allow BSS creation/join with no Privacy capability + * yet advertising WPA IE + */ + pe_debug("RSN ie len: %d but PRIVACY: %d RSN: %d", + rsn_ie->length, privacy, val); + } + + if (!rsn_ie->length) + return true; + + if ((rsn_ie->rsnIEdata[0] != WLAN_ELEMID_RSN) && + (rsn_ie->rsnIEdata[0] != SIR_MAC_WPA_EID)) { + pe_err("RSN/WPA EID: %d not [%d || %d]", + rsn_ie->rsnIEdata[0], WLAN_ELEMID_RSN, + SIR_MAC_WPA_EID); + return false; + } + /* Check validity of RSN IE */ + if ((rsn_ie->rsnIEdata[0] == WLAN_ELEMID_RSN) && + (rsn_ie->rsnIEdata[1] < SIR_MAC_RSN_IE_MIN_LENGTH)) { + pe_err("RSN IE len: %d not [%d,%d]", + rsn_ie->rsnIEdata[1], SIR_MAC_RSN_IE_MIN_LENGTH, + WLAN_MAX_IE_LEN); + return false; + } + + if (rsn_ie->length > rsn_ie->rsnIEdata[1] + 2) { + if (rsn_ie->rsnIEdata[0] != WLAN_ELEMID_RSN) { + pe_err("First byte: %d in rsnIEdata isn't RSN_EID", + rsn_ie->rsnIEdata[1]); + return false; + } + pe_debug("WPA IE is present along with WPA2 IE"); + wpa_idx = 2 + rsn_ie->rsnIEdata[1]; + } else if ((rsn_ie->length == rsn_ie->rsnIEdata[1] + 2) && + (rsn_ie->rsnIEdata[0] == WLAN_ELEMID_RSN)) { + pe_debug("Only RSN IE is present"); + ret = dot11f_unpack_ie_rsn(mac_ctx, &rsn_ie->rsnIEdata[2], + rsn_ie->rsnIEdata[1], + &session->gStartBssRSNIe, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack failed, ret: %d", ret); + return false; + } + return true; + } else if ((rsn_ie->length == rsn_ie->rsnIEdata[1] + 2) + && (rsn_ie->rsnIEdata[0] == SIR_MAC_WPA_EID)) { + pe_debug("Only WPA IE is present"); + ret = dot11f_unpack_ie_wpa(mac_ctx, &rsn_ie->rsnIEdata[6], + rsn_ie->rsnIEdata[1] - 4, + &session->gStartBssWPAIe, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack failed, ret: %d", ret); + return false; + } + return true; + } + /* Check validity of WPA IE */ + if (wpa_idx + 6 >= WLAN_MAX_IE_LEN) + return false; + + val = sir_read_u32((uint8_t *)&rsn_ie->rsnIEdata[wpa_idx + 2]); + if ((rsn_ie->rsnIEdata[wpa_idx] == SIR_MAC_WPA_EID) + && ((rsn_ie->rsnIEdata[wpa_idx + 1] < SIR_MAC_WPA_IE_MIN_LENGTH) + || (SIR_MAC_WPA_OUI != val))) { + pe_err("WPA IE len: %d not [%d,%d] OR data 0x%x not 0x%x", + rsn_ie->rsnIEdata[1], + SIR_MAC_RSN_IE_MIN_LENGTH, + WLAN_MAX_IE_LEN, val, + SIR_MAC_WPA_OUI); + return false; + } else { + /* Both RSN and WPA IEs are present */ + ret = dot11f_unpack_ie_rsn(mac_ctx, &rsn_ie->rsnIEdata[2], + rsn_ie->rsnIEdata[1], + &session->gStartBssRSNIe, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack failed, ret: %d", ret); + return false; + } + ret = dot11f_unpack_ie_wpa(mac_ctx, + &rsn_ie->rsnIEdata[wpa_idx + 6], + rsn_ie->rsnIEdata[wpa_idx + 1] - 4, + &session->gStartBssWPAIe, false); + if (!DOT11F_SUCCEEDED(ret)) { + pe_err("unpack failed, ret: %d", ret); + return false; + } + } + return true; +} + +bool lim_is_sme_start_bss_req_valid(struct mac_context *mac_ctx, + struct start_bss_config *start_bss_req, + enum bss_type bss_type) +{ + uint8_t i = 0; + tSirMacRateSet *opr_rates = &start_bss_req->operationalRateSet; + + switch (bss_type) { + case eSIR_INFRASTRUCTURE_MODE: + /** + * Should not have received start BSS req with bssType + * Infrastructure on STA. + */ + pe_warn("Invalid bss type: %d in eWNI_SME_START_BSS_REQ", + bss_type); + return false; + break; + case eSIR_INFRA_AP_MODE: + break; + case eSIR_NDI_MODE: + break; + default: + /** + * Should not have received start BSS req with bssType + * other than Infrastructure/IBSS. + */ + pe_warn("Invalid bss type: %d in eWNI_SME_START_BSS_REQ", + bss_type); + return false; + } + + if (!lim_is_rsn_ie_valid_in_sme_req_message(mac_ctx, + &start_bss_req->rsnIE)) + return false; + + if (start_bss_req->nwType != eSIR_11A_NW_TYPE + && start_bss_req->nwType != eSIR_11B_NW_TYPE + && start_bss_req->nwType != eSIR_11G_NW_TYPE) + return false; + + if (start_bss_req->nwType == eSIR_11A_NW_TYPE) { + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsArate(opr_rates->rate[i] & 0x7F)) + continue; + + pe_warn("Invalid operational 11A rates"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_WARN, + opr_rates->rate, + opr_rates->numRates); + return false; + } + return true; + } + /* check if all the rates in the opr rate set are legal 11G rates */ + if (start_bss_req->nwType == eSIR_11G_NW_TYPE) { + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsGrate(opr_rates->rate[i] & 0x7F)) + continue; + + pe_warn("Invalid operational 11G rates"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_WARN, + opr_rates->rate, + opr_rates->numRates); + return false; + } + return true; + } + + for (i = 0; i < opr_rates->numRates; i++) { + if (sirIsBrate(opr_rates->rate[i] & 0x7F)) + continue; + + pe_warn("Invalid operational 11B rates"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_WARN, + opr_rates->rate, + opr_rates->numRates); + return false; + } + return true; +} + +bool lim_is_sme_disassoc_req_valid(struct mac_context *mac, + struct disassoc_req *disassoc_req, + struct pe_session *pe_session) +{ + if (qdf_is_macaddr_group(&disassoc_req->peer_macaddr) && + !qdf_is_macaddr_broadcast(&disassoc_req->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_req_valid() ***/ + +bool lim_is_sme_disassoc_cnf_valid(struct mac_context *mac, + struct disassoc_cnf *disassoc_cnf, + struct pe_session *pe_session) +{ + if (qdf_is_macaddr_group(&disassoc_cnf->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_disassoc_cnf_valid() ***/ + +bool lim_is_sme_deauth_req_valid(struct mac_context *mac, + struct deauth_req *deauth_req, + struct pe_session *pe_session) +{ + if (qdf_is_macaddr_group(&deauth_req->peer_macaddr) && + !qdf_is_macaddr_broadcast(&deauth_req->peer_macaddr)) + return false; + + return true; +} /*** end lim_is_sme_deauth_req_valid() ***/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h new file mode 100644 index 0000000000..3e81dcd658 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_sme_req_utils.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011-2012,2014-2015,2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_sme_req_utils.h contains the utility definitions + * LIM uses while processing SME request messages. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_SME_REQ_UTILS_H +#define __LIM_SME_REQ_UTILS_H + +#include "sir_api.h" +#include "lim_types.h" + +/* LIM SME request messages related utility functions */ + +/** + * lim_is_sme_start_bss_req_valid() - To validate sme start bss request + * @mac_ctx: Pointer to Global MAC structure + * @start_bss_req: Pointer to received SME_START_BSS_REQ message + * @bss_type: bss type + * + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_START_BSS_REQ message from application. + * + * Return: true when received SME_START_BSS_REQ is formatted correctly false + * otherwise + */ +bool lim_is_sme_start_bss_req_valid(struct mac_context *mac_ctx, + struct start_bss_config *start_bss_req, + enum bss_type bss_type); +uint8_t lim_set_rs_nie_wp_aiefrom_sme_start_bss_req_message(struct mac_context *, + tpSirRSNie, struct pe_session *); + +/** + * lim_is_sme_disassoc_req_valid() - Validate disassoc req message + * @mac: Pointer to Global MAC structure + * @disassoc_req: Pointer to received SME_DISASSOC_REQ message + * @pe_session: Pointer to the PE session + * + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_REQ message from application. + * + * Return: true When received SME_DISASSOC_REQ is formatted correctly + * false otherwise + */ +bool lim_is_sme_disassoc_req_valid(struct mac_context *mac, + struct disassoc_req *disassoc_req, + struct pe_session *pe_session); + +/** + * lim_is_sme_deauth_req_valid() - Validate deauth req message + * @mac: Pointer to Global MAC structure + * @disassoc_req: Pointer to received SME_DEAUTH_REQ message + * @pe_session: Pointer to the PE session + * + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DEAUTH_REQ message from application. + * + * Return: true When received SME_DEAUTH_REQ is formatted correctly + * false otherwise + */ +bool lim_is_sme_deauth_req_valid(struct mac_context *mac, + struct deauth_req *deauth_req, + struct pe_session *pe_session); + +/** + * lim_is_sme_disassoc_cnf_valid() - Validate disassoc cnf message + * @mac: Pointer to Global MAC structure + * @disassoc_cnf: Pointer to received SME_DISASSOC_CNF message + * @pe_session: Pointer to the PE session + * + * This function is called by lim_process_sme_req_messages() upon + * receiving SME_DISASSOC_CNF message from application. + * + * Return: true When received SME_DISASSOC_CNF is formatted correctly + * false otherwise + */ +bool lim_is_sme_disassoc_cnf_valid(struct mac_context *mac, + struct disassoc_cnf *disassoc_cnf, + struct pe_session *pe_session); + +#endif /* __LIM_SME_REQ_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c new file mode 100644 index 0000000000..bd391fa595 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.c @@ -0,0 +1,908 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_timer_utils.cc contains the utility functions + * LIM uses for handling various timers. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_assoc_utils.h" +#include "lim_security_utils.h" +#include "wlan_mlme_public_struct.h" +#include + +/* Lim Quite timer in ticks */ +#define LIM_QUIET_TIMER_TICKS 100 +/* Lim Quite BSS timer interval in ticks */ +#define LIM_QUIET_BSS_TIMER_TICK 100 +/* Lim KeepAlive timer default (3000)ms */ +#define LIM_KEEPALIVE_TIMER_MS 3000 +/* Lim Periodic Auth Retry timer default 60 ms */ +#define LIM_AUTH_RETRY_TIMER_MS 60 + +/* + * SAE auth timer of 5secs. This is required for duration of entire SAE + * authentication. + */ +#define LIM_AUTH_SAE_TIMER_MS 5000 + +/* + * STA stats resp timer of 10secs. This is required for duration of RRM + * STA STATS report response from report request. + */ +#define LIM_RRM_STA_STATS_RSP_TIMER_MS 10000 + +static bool lim_create_non_ap_timers(struct mac_context *mac) +{ + uint32_t cfgValue; + + cfgValue = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.join_failure_timeout); + /* Create Join failure timer and activate it later */ + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimJoinFailureTimer, + "JOIN FAILURE TIMEOUT", + lim_timer_handler, SIR_LIM_JOIN_FAIL_TIMEOUT, + cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + /* / Could not create Join failure timer. */ + /* Log error */ + pe_err("could not create Join failure timer"); + return false; + } + cfgValue = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.probe_req_retry_timeout); + /* Send unicast probe req frame every 200 ms */ + if (tx_timer_create(mac, + &mac->lim.lim_timers.gLimPeriodicJoinProbeReqTimer, + "Periodic Join Probe Request Timer", + lim_timer_handler, + SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT, + cfgValue, 0, + TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create Periodic Join Probe Request tmr"); + return false; + } + + /* Send Auth frame every 60 ms */ + if ((tx_timer_create(mac, + &mac->lim.lim_timers.g_lim_periodic_auth_retry_timer, + "Periodic AUTH Timer", + lim_timer_handler, SIR_LIM_AUTH_RETRY_TIMEOUT, + SYS_MS_TO_TICKS(LIM_AUTH_RETRY_TIMER_MS), 0, + TX_NO_ACTIVATE)) != TX_SUCCESS) { + pe_err("could not create Periodic AUTH Timer"); + return false; + } + + cfgValue = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.assoc_failure_timeout); + /* Create Association failure timer and activate it later */ + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimAssocFailureTimer, + "ASSOC FAILURE TIMEOUT", + lim_assoc_failure_timer_handler, LIM_ASSOC, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create Association failure timer"); + return false; + } + + cfgValue = SYS_MS_TO_TICKS(mac->mlme_cfg->timeouts.addts_rsp_timeout); + + /* Create Addts response timer and activate it later */ + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimAddtsRspTimer, + "ADDTS RSP TIMEOUT", + lim_addts_response_timer_handler, + SIR_LIM_ADDTS_RSP_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create Addts response timer"); + return false; + } + + cfgValue = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.auth_failure_timeout); + /* Create Auth failure timer and activate it later */ + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimAuthFailureTimer, + "AUTH FAILURE TIMEOUT", + lim_timer_handler, + SIR_LIM_AUTH_FAIL_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create Auth failure timer"); + return false; + } + + /* + * SAE auth timer of 5secs. This is required for duration of entire SAE + * authentication. + */ + if ((tx_timer_create(mac, + &mac->lim.lim_timers.sae_auth_timer, + "SAE AUTH Timer", + lim_timer_handler, SIR_LIM_AUTH_SAE_TIMEOUT, + SYS_MS_TO_TICKS(LIM_AUTH_SAE_TIMER_MS), 0, + TX_NO_ACTIVATE)) != TX_SUCCESS) { + pe_err("could not create SAE AUTH Timer"); + return false; + } + + return true; +} +/** + * lim_create_timers() + * + * @mac : Pointer to Global MAC structure + * + * This function is called upon receiving + * 1. SME_START_REQ for STA in ESS role + * 2. SME_START_BSS_REQ for AP role & STA in IBSS role + * + * @return : status of operation + */ + +uint32_t lim_create_timers(struct mac_context *mac) +{ + uint32_t cfgValue, i = 0; + + pe_debug("Creating Timers used by LIM module in Role: %d", + mac->lim.gLimSystemRole); + /* Create timers required for host roaming feature */ + if (TX_SUCCESS != lim_create_timers_host_roam(mac)) + return TX_TIMER_ERROR; + + if (mac->lim.gLimSystemRole != eLIM_AP_ROLE) + if (false == lim_create_non_ap_timers(mac)) + goto err_timer; + + cfgValue = mac->mlme_cfg->sta.wait_cnf_timeout; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + for (i = 0; i < (mac->lim.maxStation + 1); i++) { + if (tx_timer_create(mac, + &mac->lim.lim_timers.gpLimCnfWaitTimer[i], + "CNF_MISS_TIMEOUT", + lim_cnf_wait_tmer_handler, + (uint32_t) i, cfgValue, + 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("Cannot create CNF wait timer"); + goto err_timer; + } + } + + /* Alloc and init table for the preAuth timer list */ + cfgValue = mac->mlme_cfg->lfr.max_num_pre_auth; + mac->lim.gLimPreAuthTimerTable.numEntry = cfgValue; + mac->lim.gLimPreAuthTimerTable.pTable = + qdf_mem_malloc(cfgValue * sizeof(tLimPreAuthNode *)); + + if (!mac->lim.gLimPreAuthTimerTable.pTable) + goto err_timer; + + for (i = 0; i < cfgValue; i++) { + mac->lim.gLimPreAuthTimerTable.pTable[i] = + qdf_mem_malloc(sizeof(tLimPreAuthNode)); + if (!mac->lim.gLimPreAuthTimerTable.pTable[i]) { + mac->lim.gLimPreAuthTimerTable.numEntry = 0; + goto err_timer; + } + } + + lim_init_pre_auth_timer_table(mac, &mac->lim.gLimPreAuthTimerTable); + pe_debug("alloc and init table for preAuth timers"); + + cfgValue = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.olbc_detect_timeout); + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimUpdateOlbcCacheTimer, + "OLBC UPDATE CACHE TIMEOUT", + lim_update_olbc_cache_timer_handler, + SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT, cfgValue, + cfgValue, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("Cannot create update OLBC cache tmr"); + goto err_timer; + } + + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimDisassocAckTimer, + "DISASSOC ACK TIMEOUT", + lim_timer_handler, SIR_LIM_DISASSOC_ACK_TIMEOUT, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not DISASSOC ACK TIMEOUT timer"); + goto err_timer; + } + + cfgValue = 1000; + cfgValue = SYS_MS_TO_TICKS(cfgValue); + if (tx_timer_create(mac, &mac->lim.lim_timers.gLimDeauthAckTimer, + "DISASSOC ACK TIMEOUT", + lim_process_deauth_ack_timeout, + WLAN_INVALID_VDEV_ID, + cfgValue, 0, TX_NO_ACTIVATE) != TX_SUCCESS) { + pe_err("could not create DEAUTH ACK TIMEOUT timer"); + goto err_timer; + } + + if ((tx_timer_create(mac, + &mac->lim.lim_timers.rrm_sta_stats_resp_timer, + "STA STATS RSP timer", + lim_timer_handler, + SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT, + SYS_MS_TO_TICKS(LIM_RRM_STA_STATS_RSP_TIMER_MS), 0, + TX_NO_ACTIVATE)) != TX_SUCCESS) { + pe_err("could not create STA STATS RSP Timer"); + goto err_timer; + } + return TX_SUCCESS; + +err_timer: + lim_delete_timers_host_roam(mac); + tx_timer_delete(&mac->lim.lim_timers.rrm_sta_stats_resp_timer); + tx_timer_delete(&mac->lim.lim_timers.gLimDeauthAckTimer); + tx_timer_delete(&mac->lim.lim_timers.gLimDisassocAckTimer); + tx_timer_delete(&mac->lim.lim_timers.gLimUpdateOlbcCacheTimer); + while (((int32_t)-- i) >= 0) { + tx_timer_delete(&mac->lim.lim_timers.gpLimCnfWaitTimer[i]); + } + tx_timer_delete(&mac->lim.lim_timers.gLimAuthFailureTimer); + tx_timer_delete(&mac->lim.lim_timers.gLimAddtsRspTimer); + tx_timer_delete(&mac->lim.lim_timers.gLimAssocFailureTimer); + tx_timer_delete(&mac->lim.lim_timers.gLimJoinFailureTimer); + tx_timer_delete(&mac->lim.lim_timers.gLimPeriodicJoinProbeReqTimer); + tx_timer_delete(&mac->lim.lim_timers.g_lim_periodic_auth_retry_timer); + tx_timer_delete(&mac->lim.lim_timers.sae_auth_timer); + + if (mac->lim.gLimPreAuthTimerTable.pTable) { + for (i = 0; i < mac->lim.gLimPreAuthTimerTable.numEntry; i++) + qdf_mem_free(mac->lim.gLimPreAuthTimerTable.pTable[i]); + qdf_mem_free(mac->lim.gLimPreAuthTimerTable.pTable); + mac->lim.gLimPreAuthTimerTable.pTable = NULL; + } + return TX_TIMER_ERROR; +} /****** end lim_create_timers() ******/ + +/** + * lim_timer_handler() + * + ***FUNCTION: + * This function is called upon + * 1. MIN_CHANNEL, MAX_CHANNEL timer expiration during scanning + * 2. JOIN_FAILURE timer expiration while joining a BSS + * 3. AUTH_FAILURE timer expiration while authenticating with a peer + * 4. Heartbeat timer expiration on STA + * 5. Background scan timer expiration on STA + * 6. AID release, Pre-auth cleanup and Link monitoring timer + * expiration on AP + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - Message corresponding to the timer that expired + * + * @return None + */ + +void lim_timer_handler(void *pMacGlobal, uint32_t param) +{ + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct mac_context *mac = (struct mac_context *) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = (uint16_t) param; + msg.bodyptr = NULL; + msg.bodyval = 0; + + pe_debug("param %X ", msg.type); + + status = lim_post_msg_high_priority(mac, &msg); + if (status != QDF_STATUS_SUCCESS) + pe_err("posting message: %X to LIM failed, reason: %d", + msg.type, status); +} /****** end lim_timer_handler() ******/ + +/** + * lim_addts_response_timer_handler() + * + ***FUNCTION: + * This function is called upon Addts response timer expiration on sta + * + ***LOGIC: + * Message SIR_LIM_ADDTS_RSP_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - pointer to pre-auth node + * + * @return None + */ + +void lim_addts_response_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + struct mac_context *mac = (struct mac_context *) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_ADDTS_RSP_TIMEOUT; + msg.bodyval = param; + msg.bodyptr = NULL; + + lim_post_msg_api(mac, &msg); +} /****** end lim_auth_response_timer_handler() ******/ + +/** + * lim_auth_response_timer_handler() + * + ***FUNCTION: + * This function is called upon Auth response timer expiration on AP + * + ***LOGIC: + * Message SIR_LIM_AUTH_RSP_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param param - pointer to pre-auth node + * + * @return None + */ + +void lim_auth_response_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + struct mac_context *mac = (struct mac_context *) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_AUTH_RSP_TIMEOUT; + msg.bodyptr = NULL; + msg.bodyval = (uint32_t) param; + + lim_post_msg_api(mac, &msg); +} /****** end lim_auth_response_timer_handler() ******/ + +/** + * lim_assoc_failure_timer_handler() + * + * @mac_global : Pointer to Global MAC structure + * @param : Indicates whether this is assoc or reassoc failure timeout + * + * This function is called upon Re/Assoc failure timer expiration on STA. + * Message SIR_LIM_ASSOC_FAIL_TIMEOUT is posted to gSirLimMsgQ when this + * function is executed. + * + * Return void + */ +void lim_assoc_failure_timer_handler(void *mac_global, uint32_t param) +{ + struct scheduler_msg msg = {0}; + struct mac_context *mac_ctx = (struct mac_context *) mac_global; + struct pe_session *session = NULL; + + session = mac_ctx->lim.pe_session; + if (LIM_REASSOC == param && session + && session->limMlmState == eLIM_MLM_WT_FT_REASSOC_RSP_STATE) { + pe_err("Reassoc timeout happened"); + if (mac_ctx->lim.reAssocRetryAttempt < + LIM_MAX_REASSOC_RETRY_LIMIT) { + lim_send_retry_reassoc_req_frame(mac_ctx, + session->pLimMlmReassocRetryReq, session); + mac_ctx->lim.reAssocRetryAttempt++; + pe_warn("Reassoc request retry is sent %d times", + mac_ctx->lim.reAssocRetryAttempt); + return; + } else { + pe_warn("Reassoc request retry MAX: %d reached", + LIM_MAX_REASSOC_RETRY_LIMIT); + if (session->pLimMlmReassocRetryReq) { + qdf_mem_free(session->pLimMlmReassocRetryReq); + session->pLimMlmReassocRetryReq = NULL; + } + } + } + /* Prepare and post message to LIM Message Queue */ + msg.type = SIR_LIM_ASSOC_FAIL_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + lim_post_msg_api(mac_ctx, &msg); +} /****** end lim_assoc_failure_timer_handler() ******/ + +/** + * lim_update_olbc_cache_timer_handler() + * + ***FUNCTION: + * This function is called upon update olbc cache timer expiration + * on STA + * + ***LOGIC: + * Message SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT is posted to gSirLimMsgQ + * when this function is executed. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ +void lim_update_olbc_cache_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + struct mac_context *mac = (struct mac_context *) pMacGlobal; + + /* Prepare and post message to LIM Message Queue */ + + msg.type = SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT; + msg.bodyval = 0; + msg.bodyptr = NULL; + + lim_post_msg_api(mac, &msg); +} /****** end lim_update_olbc_cache_timer_handler() ******/ + +/** + * lim_deactivate_and_change_timer() + * + ***FUNCTION: + * This function is called to deactivate and change a timer + * for future re-activation + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param timerId - enum of timer to be deactivated and changed + * This enum is defined in lim_utils.h file + * + * @return None + */ + +void lim_deactivate_and_change_timer(struct mac_context *mac, uint32_t timerId) +{ + uint32_t val = 0; + struct pe_session * session_entry; + + switch (timerId) { + case eLIM_REASSOC_FAIL_TIMER: + case eLIM_FT_PREAUTH_RSP_TIMER: + lim_deactivate_and_change_timer_host_roam(mac, timerId); + break; + + case eLIM_ADDTS_RSP_TIMER: + mac->lim.gLimAddtsRspTimerCount++; + if (tx_timer_deactivate(&mac->lim.lim_timers.gLimAddtsRspTimer) + != TX_SUCCESS) { + /* Could not deactivate AddtsRsp Timer */ + /* Log error */ + pe_err("Unable to deactivate AddtsRsp timer"); + } + break; + + case eLIM_JOIN_FAIL_TIMER: + if (tx_timer_deactivate + (&mac->lim.lim_timers.gLimJoinFailureTimer) + != TX_SUCCESS) { + /** + * Could not deactivate Join Failure + * timer. Log error. + */ + pe_err("Unable to deactivate Join Failure timer"); + } + + val = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.join_failure_timeout); + + if (tx_timer_change(&mac->lim.lim_timers.gLimJoinFailureTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + pe_err("Unable to change Join Failure timer"); + } + + break; + + case eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER: + if (tx_timer_deactivate + (&mac->lim.lim_timers.gLimPeriodicJoinProbeReqTimer) + != TX_SUCCESS) { + /* Could not deactivate periodic join req Times. */ + pe_err("Unable to deactivate periodic join request timer"); + } + val = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.probe_req_retry_timeout); + if (tx_timer_change + (&mac->lim.lim_timers.gLimPeriodicJoinProbeReqTimer, + val, 0) != TX_SUCCESS) { + /* Could not change periodic join req times. */ + /* Log error */ + pe_err("Unable to change periodic join request timer"); + } + + break; + + case eLIM_AUTH_FAIL_TIMER: + if (tx_timer_deactivate + (&mac->lim.lim_timers.gLimAuthFailureTimer) + != TX_SUCCESS) { + /* Could not deactivate Auth failure timer. */ + /* Log error */ + pe_err("Unable to deactivate auth failure timer"); + } + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.auth_failure_timeout); + + if (tx_timer_change(&mac->lim.lim_timers.gLimAuthFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Authentication failure timer. */ + /* Log error */ + pe_err("unable to change Auth failure timer"); + } + + break; + + case eLIM_AUTH_RETRY_TIMER: + + if (tx_timer_deactivate + (&mac->lim.lim_timers.g_lim_periodic_auth_retry_timer) + != TX_SUCCESS) { + /* Could not deactivate Auth Retry Timer. */ + pe_err("Unable to deactivate Auth Retry timer"); + } + session_entry = pe_find_session_by_session_id(mac, + mac->lim.lim_timers. + g_lim_periodic_auth_retry_timer.sessionId); + if (!session_entry) { + pe_debug("session does not exist for given SessionId : %d", + mac->lim.lim_timers. + g_lim_periodic_auth_retry_timer.sessionId); + break; + } + /* 3/5 of the beacon interval */ + val = (session_entry->beaconParams.beaconInterval * 3) / 5; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change + (&mac->lim.lim_timers.g_lim_periodic_auth_retry_timer, + val, 0) != TX_SUCCESS) { + /* Could not change Auth Retry timer. */ + pe_err("Unable to change Auth Retry timer"); + } + break; + + case eLIM_ASSOC_FAIL_TIMER: + if (tx_timer_deactivate + (&mac->lim.lim_timers.gLimAssocFailureTimer) != + TX_SUCCESS) { + /* Could not deactivate Association failure timer. */ + /* Log error */ + pe_err("unable to deactivate Association failure timer"); + } + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.assoc_failure_timeout); + + if (tx_timer_change(&mac->lim.lim_timers.gLimAssocFailureTimer, + val, 0) != TX_SUCCESS) { + /* Could not change Association failure timer. */ + /* Log error */ + pe_err("unable to change Assoc failure timer"); + } + + break; + + case eLIM_DISASSOC_ACK_TIMER: + if (tx_timer_deactivate( + &mac->lim.lim_timers.gLimDisassocAckTimer) != + TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + pe_err("Unable to deactivate Disassoc ack timer"); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&mac->lim.lim_timers.gLimDisassocAckTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + pe_err("Unable to change timer"); + return; + } + break; + + case eLIM_DEAUTH_ACK_TIMER: + if (tx_timer_deactivate(&mac->lim.lim_timers.gLimDeauthAckTimer) + != TX_SUCCESS) { + /** + ** Could not deactivate Join Failure + ** timer. Log error. + **/ + pe_err("Unable to deactivate Deauth ack timer"); + return; + } + val = 1000; + val = SYS_MS_TO_TICKS(val); + if (tx_timer_change(&mac->lim.lim_timers.gLimDeauthAckTimer, + val, 0) != TX_SUCCESS) { + /** + * Could not change Join Failure + * timer. Log error. + */ + pe_err("Unable to change timer"); + return; + } + break; + + case eLIM_AUTH_SAE_TIMER: + if (tx_timer_deactivate + (&mac->lim.lim_timers.sae_auth_timer) + != TX_SUCCESS) + pe_err("Unable to deactivate SAE auth timer"); + + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS(LIM_AUTH_SAE_TIMER_MS); + + if (tx_timer_change(&mac->lim.lim_timers.sae_auth_timer, + val, 0) != TX_SUCCESS) + pe_err("unable to change SAE auth timer"); + + break; + case eLIM_RRM_STA_STATS_RSP_TIMER: + if (tx_timer_deactivate + (&mac->lim.lim_timers.rrm_sta_stats_resp_timer) + != TX_SUCCESS) + pe_err("Unable to deactivate STA STATS RSP timer"); + + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS(LIM_RRM_STA_STATS_RSP_TIMER_MS); + + if (tx_timer_change( + &mac->lim.lim_timers.rrm_sta_stats_resp_timer, + val, 0) != TX_SUCCESS) + pe_err("unable to change STA STATS RSP timer"); + + break; + + default: + /* Invalid timerId. Log error */ + break; + } +} /****** end lim_deactivate_and_change_timer() ******/ + +/** + * lim_deactivate_and_change_per_sta_id_timer() + * + * + * @brief: This function is called to deactivate and change a per STA timer + * for future re-activation + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + * @note staId for eLIM_AUTH_RSP_TIMER is auth Node Index. + * + * @param mac - Pointer to Global MAC structure + * @param timerId - enum of timer to be deactivated and changed + * This enum is defined in lim_utils.h file + * @param staId - staId + * + * @return None + */ + +void +lim_deactivate_and_change_per_sta_id_timer(struct mac_context *mac, uint32_t timerId, + uint16_t staId) +{ + uint32_t val; + + switch (timerId) { + case eLIM_CNF_WAIT_TIMER: + + if (staId >= (mac->lim.maxStation + 1)) { + pe_err("Invalid staId = %d ", staId); + return; + } + + if (tx_timer_deactivate(&mac->lim.lim_timers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + pe_err("unable to deactivate CNF wait timer"); + } + + /* Change timer to reactivate it in future */ + val = mac->mlme_cfg->sta.wait_cnf_timeout; + val = SYS_MS_TO_TICKS(val); + + if (tx_timer_change + (&mac->lim.lim_timers.gpLimCnfWaitTimer[staId], val, + val) != TX_SUCCESS) { + /* Could not change cnf timer. */ + /* Log error */ + pe_err("unable to change cnf wait timer"); + } + + break; + + case eLIM_AUTH_RSP_TIMER: + { + tLimPreAuthNode *pAuthNode; + + pAuthNode = + lim_get_pre_auth_node_from_index(mac, + &mac->lim. + gLimPreAuthTimerTable, + staId); + + if (!pAuthNode) { + pe_err("Invalid Pre Auth Index passed :%d", + staId); + break; + } + + if (tx_timer_deactivate(&pAuthNode->timer) != + TX_SUCCESS) { + /* Could not deactivate auth response timer. */ + /* Log error */ + pe_err("unable to deactivate auth response timer"); + } + /* Change timer to reactivate it in future */ + val = SYS_MS_TO_TICKS( + mac->mlme_cfg->timeouts.auth_rsp_timeout); + + if (tx_timer_change(&pAuthNode->timer, val, 0) != + TX_SUCCESS) { + /* Could not change auth rsp timer. */ + /* Log error */ + pe_err("unable to change auth rsp timer"); + } + } + break; + + default: + /* Invalid timerId. Log error */ + break; + + } +} + +/** + * lim_activate_cnf_timer() + * + ***FUNCTION: + * This function is called to activate a per STA timer + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param StaId - staId + * + * @return None + */ + +void lim_activate_cnf_timer(struct mac_context *mac, uint16_t staId, + struct pe_session *pe_session) +{ + mac->lim.lim_timers.gpLimCnfWaitTimer[staId].sessionId = + pe_session->peSessionId; + if (tx_timer_activate(&mac->lim.lim_timers.gpLimCnfWaitTimer[staId]) + != TX_SUCCESS) { + pe_err("could not activate cnf wait timer"); + } +} + +/** + * lim_activate_auth_rsp_timer() + * + ***FUNCTION: + * This function is called to activate a per STA timer + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param id - id + * + * @return None + */ + +void lim_activate_auth_rsp_timer(struct mac_context *mac, tLimPreAuthNode *pAuthNode) +{ + if (tx_timer_activate(&pAuthNode->timer) != TX_SUCCESS) { + /* / Could not activate auth rsp timer. */ + /* Log error */ + pe_err("could not activate auth rsp timer"); + } +} + +/** + * limAssocCnfWaitTmerHandler() + * + ***FUNCTION: + * This function post a message to send a disassociate frame out. + * + ***LOGIC: + * + ***ASSUMPTIONS: + * + ***NOTE: + * NA + * + * @param + * + * @return None + */ + +void lim_cnf_wait_tmer_handler(void *pMacGlobal, uint32_t param) +{ + struct scheduler_msg msg = {0}; + uint32_t status_code; + struct mac_context *mac = (struct mac_context *) pMacGlobal; + + msg.type = SIR_LIM_CNF_WAIT_TIMEOUT; + msg.bodyval = (uint32_t) param; + msg.bodyptr = NULL; + + status_code = lim_post_msg_api(mac, &msg); + if (status_code != QDF_STATUS_SUCCESS) + pe_err("posting to LIM failed, reason: %d", status_code); + +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h new file mode 100644 index 0000000000..36a8493719 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_timer_utils.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011-2014, 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file lim_timer_utils.h contains the utility definitions + * LIM uses for timer handling. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_TIMER_UTILS_H +#define __LIM_TIMER_UTILS_H + +#include "lim_types.h" + +/* Timer related functions */ +enum limtimertype { + eLIM_MIN_CHANNEL_TIMER, + eLIM_MAX_CHANNEL_TIMER, + eLIM_JOIN_FAIL_TIMER, + eLIM_AUTH_FAIL_TIMER, + eLIM_AUTH_RESP_TIMER, + eLIM_ASSOC_FAIL_TIMER, + eLIM_REASSOC_FAIL_TIMER, + eLIM_PRE_AUTH_CLEANUP_TIMER, + eLIM_CNF_WAIT_TIMER, + eLIM_AUTH_RSP_TIMER, + eLIM_UPDATE_OLBC_CACHE_TIMER, + eLIM_ADDTS_RSP_TIMER, + eLIM_CHANNEL_SWITCH_TIMER, + eLIM_WPS_OVERLAP_TIMER, + eLIM_FT_PREAUTH_RSP_TIMER, + eLIM_REMAIN_CHN_TIMER, + eLIM_DISASSOC_ACK_TIMER, + eLIM_DEAUTH_ACK_TIMER, + eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER, + eLIM_INSERT_SINGLESHOT_NOA_TIMER, + eLIM_AUTH_RETRY_TIMER, + eLIM_AUTH_SAE_TIMER, + eLIM_RRM_STA_STATS_RSP_TIMER +}; + +#define LIM_DISASSOC_DEAUTH_ACK_TIMEOUT 500 + +/* Timer Handler functions */ +uint32_t lim_create_timers(struct mac_context *); +void lim_timer_handler(void *, uint32_t); +void lim_auth_response_timer_handler(void *, uint32_t); +void lim_assoc_failure_timer_handler(void *, uint32_t); + +void lim_deactivate_and_change_timer(struct mac_context *, uint32_t); +void lim_cnf_wait_tmer_handler(void *, uint32_t); +void lim_deactivate_and_change_per_sta_id_timer(struct mac_context *, uint32_t, uint16_t); +void lim_activate_cnf_timer(struct mac_context *, uint16_t, struct pe_session *); +void lim_activate_auth_rsp_timer(struct mac_context *, tLimPreAuthNode *); +void lim_update_olbc_cache_timer_handler(void *, uint32_t); +void lim_addts_response_timer_handler(void *, uint32_t); +#endif /* __LIM_TIMER_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c new file mode 100644 index 0000000000..ce7ba37334 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_trace.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \file lim_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "ani_global.h" /* for struct mac_context **/ + +#include "lim_trace.h" +#include "lim_timer_utils.h" +#include "qdf_trace.h" + +#ifdef LIM_TRACE_RECORD + +#define LIM_TRACE_MAX_SUBTYPES 14 + +static uint8_t *__lim_trace_get_timer_string(uint16_t timerId) +{ + switch (timerId) { + CASE_RETURN_STRING(eLIM_MIN_CHANNEL_TIMER); + CASE_RETURN_STRING(eLIM_MAX_CHANNEL_TIMER); + CASE_RETURN_STRING(eLIM_JOIN_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RESP_TIMER); + CASE_RETURN_STRING(eLIM_ASSOC_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_REASSOC_FAIL_TIMER); + CASE_RETURN_STRING(eLIM_PRE_AUTH_CLEANUP_TIMER); + CASE_RETURN_STRING(eLIM_CNF_WAIT_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RSP_TIMER); + CASE_RETURN_STRING(eLIM_UPDATE_OLBC_CACHE_TIMER); + CASE_RETURN_STRING(eLIM_ADDTS_RSP_TIMER); + CASE_RETURN_STRING(eLIM_CHANNEL_SWITCH_TIMER); + CASE_RETURN_STRING(eLIM_WPS_OVERLAP_TIMER); + CASE_RETURN_STRING(eLIM_FT_PREAUTH_RSP_TIMER); + CASE_RETURN_STRING(eLIM_REMAIN_CHN_TIMER); + CASE_RETURN_STRING(eLIM_DISASSOC_ACK_TIMER); + CASE_RETURN_STRING(eLIM_DEAUTH_ACK_TIMER); + CASE_RETURN_STRING(eLIM_PERIODIC_JOIN_PROBE_REQ_TIMER); + CASE_RETURN_STRING(eLIM_AUTH_RETRY_TIMER); + CASE_RETURN_STRING(eLIM_RRM_STA_STATS_RSP_TIMER); + default: + return "UNKNOWN"; + break; + } +} + +static uint8_t *__lim_trace_get_mgmt_drop_reason_string(uint16_t dropReason) +{ + + switch (dropReason) { + CASE_RETURN_STRING(eMGMT_DROP_INFRA_BCN_IN_IBSS); + CASE_RETURN_STRING(eMGMT_DROP_INVALID_SIZE); + CASE_RETURN_STRING(eMGMT_DROP_NON_SCAN_MODE_FRAME); + CASE_RETURN_STRING(eMGMT_DROP_NOT_LAST_IBSS_BCN); + CASE_RETURN_STRING(eMGMT_DROP_NO_DROP); + CASE_RETURN_STRING(eMGMT_DROP_SCAN_MODE_FRAME); + CASE_RETURN_STRING(eMGMT_DROP_SPURIOUS_FRAME); + + default: + return "UNKNOWN"; + break; + } +} + +void lim_trace_init(struct mac_context *mac) +{ + qdf_trace_register(QDF_MODULE_ID_PE, &lim_trace_dump); +} + +void lim_trace_dump(void *mac, tp_qdf_trace_record pRecord, + uint16_t recIndex) +{ + static char *frameSubtypeStr[LIM_TRACE_MAX_SUBTYPES] = { + "Association request", + "Association response", + "Reassociation request", + "Reassociation response", + "Probe request", + "Probe response", + NULL, + NULL, + "Beacon", + "ATIM", + "Disassociation", + "Authentication", + "Deauthentication", + "Action" + }; + + switch (pRecord->code) { + case TRACE_CODE_MLM_STATE: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "MLM State:", + lim_trace_get_mlm_state_string( + (uint16_t)pRecord->data), + pRecord->data); + break; + case TRACE_CODE_SME_STATE: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "SME State:", + lim_trace_get_sme_state_string( + (uint16_t)pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TX_MGMT: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX Mgmt:", frameSubtypeStr[pRecord->data], + pRecord->data); + break; + + case TRACE_CODE_RX_MGMT: + if (LIM_TRACE_MAX_SUBTYPES <= + LIM_TRACE_GET_SUBTYPE(pRecord->data)) + pe_nofl_debug("Wrong Subtype - %d", + LIM_TRACE_GET_SUBTYPE(pRecord->data)); + else + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(%d) SN: %d", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "RX Mgmt:", + frameSubtypeStr[LIM_TRACE_GET_SUBTYPE + (pRecord->data)], + LIM_TRACE_GET_SUBTYPE(pRecord->data), + LIM_TRACE_GET_SSN(pRecord->data)); + break; + case TRACE_CODE_RX_MGMT_DROP: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(%d)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "Drop RX Mgmt:", + __lim_trace_get_mgmt_drop_reason_string( + (uint16_t)pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_RX_MGMT_TSF: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s0x%x(%d)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "RX Mgmt TSF:", " ", + pRecord->data, pRecord->data); + break; + + case TRACE_CODE_TX_COMPLETE: + pe_nofl_debug("%04d %012llu %s S%d %-14s %d", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX Complete", pRecord->data); + break; + + case TRACE_CODE_TX_SME_MSG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX SME Msg:", + mac_trace_get_sme_msg_string((uint16_t)pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_SME_MSG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX Sme Msg:", + mac_trace_get_sme_msg_string((uint16_t)pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_TX_WMA_MSG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t)pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_RX_WMA_MSG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t)pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_TX_LIM_MSG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "TX LIM Msg:", + mac_trace_get_lim_msg_string((uint16_t)pRecord->data), + pRecord->data); + break; + case TRACE_CODE_RX_LIM_MSG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + LIM_TRACE_GET_DEFRD_OR_DROPPED( + pRecord->data) ? "Def/Drp LIM Msg:" : "RX LIM Msg", + mac_trace_get_lim_msg_string((uint16_t)pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TIMER_ACTIVATE: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "Timer Actvtd", + __lim_trace_get_timer_string((uint16_t)pRecord->data), + pRecord->data); + break; + case TRACE_CODE_TIMER_DEACTIVATE: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", recIndex, + pRecord->qtime, pRecord->time, pRecord->session, + "Timer DeActvtd", + __lim_trace_get_timer_string((uint16_t)pRecord->data), + pRecord->data); + break; + + case TRACE_CODE_INFO_LOG: + pe_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "INFORMATION_LOG", + mac_trace_get_info_log_string((uint16_t)pRecord->data), + pRecord->data); + break; + default: + pe_nofl_debug("%04d %012llu %s S%d %-14s(%d) (0x%x)", + recIndex, pRecord->qtime, pRecord->time, + pRecord->session, "Unknown Code", + pRecord->code, pRecord->data); + break; + } +} + +void mac_trace_msg_tx(struct mac_context *mac, uint8_t session, uint32_t data) +{ + + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t module_id = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (module_id) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace(mac, TRACE_CODE_TX_LIM_MSG, session, data); + else + mac_trace(mac, TRACE_CODE_TX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(mac, TRACE_CODE_TX_WMA_MSG, session, data); + break; + default: + mac_trace(mac, module_id, session, data); + break; + } +} + +/* + * bit31: Rx message deferred or not + * bit 0-15: message ID: + */ +void mac_trace_msg_rx(struct mac_context *mac, uint8_t session, uint32_t data) +{ + uint16_t msgId = (uint16_t) MAC_TRACE_GET_MSG_ID(data); + uint8_t module_id = (uint8_t) MAC_TRACE_GET_MODULE_ID(data); + + switch (module_id) { + case SIR_LIM_MODULE_ID: + if (msgId >= SIR_LIM_ITC_MSG_TYPES_BEGIN) + mac_trace(mac, TRACE_CODE_RX_LIM_MSG, session, data); + else + mac_trace(mac, TRACE_CODE_RX_SME_MSG, session, data); + break; + case SIR_WMA_MODULE_ID: + mac_trace(mac, TRACE_CODE_RX_WMA_MSG, session, data); + break; + default: + mac_trace(mac, msgId, session, data); + break; + } +} + +uint8_t *lim_trace_get_mlm_state_string(uint32_t mlmState) +{ + switch (mlmState) { + CASE_RETURN_STRING(eLIM_MLM_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_MLM_IDLE_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_JOIN_BEACON_STATE); + CASE_RETURN_STRING(eLIM_MLM_JOINED_STATE); + CASE_RETURN_STRING(eLIM_MLM_BSS_STARTED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME2_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME3_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME4_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTH_RSP_TIMEOUT_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTHENTICATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_LINK_ESTABLISHED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_CNF_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_BSS_KEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_STA_KEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_SET_STA_BCASTKEY_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_FT_REASSOC_RSP_STATE); + default: + return "UNKNOWN"; + break; + } +} + +uint8_t *lim_trace_get_sme_state_string(uint32_t smeState) +{ + switch (smeState) { + + CASE_RETURN_STRING(eLIM_SME_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_SME_IDLE_STATE); + CASE_RETURN_STRING(eLIM_SME_SUSPEND_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_JOIN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_JOIN_FAILURE_STATE); + CASE_RETURN_STRING(eLIM_SME_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_PRE_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DISASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DEAUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_START_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_STOP_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_STATE); + default: + return "UNKNOWN"; + break; + } +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_types.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_types.h new file mode 100644 index 0000000000..2004a9fa2d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_types.h @@ -0,0 +1,1865 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_types.h contains the definitions used by all + * all LIM modules. + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __LIM_TYPES_H +#define __LIM_TYPES_H + +#include "wni_api.h" +#include "sir_api.h" +#include "sir_common.h" +#include "sir_mac_prot_def.h" +#include "utils_api.h" + +#include "lim_api.h" +#include "lim_trace.h" +#include "lim_send_sme_rsp_messages.h" +#include "sys_global.h" +#include "dph_global.h" +#include "parser_api.h" +#include "wma_if.h" + +#define LINK_TEST_DEFER 1 + +#define TRACE_EVENT_CNF_TIMER_DEACT 0x6600 +#define TRACE_EVENT_CNF_TIMER_ACT 0x6601 +#define TRACE_EVENT_AUTH_RSP_TIMER_DEACT 0x6602 +#define TRACE_EVENT_AUTH_RSP_TIMER_ACT 0x6603 + +#define SAE_AUTH_SEQ_NUM_OFFSET 2 +#define SAE_AUTH_STATUS_CODE_OFFSET 4 +#define SAE_AUTH_GROUP_ID_OFFSET 6 + +#define SAE_GROUP_ID_19 19 +#define SAE_GROUP_ID_20 20 +#define SAE_GROUP_ID_21 21 + +#define SAE_GROUP_19_FIXED_FIELDS_LEN 96 +#define SAE_GROUP_20_FIXED_FIELDS_LEN 144 +#define SAE_GROUP_21_FIXED_FIELDS_LEN 198 + +#define WLAN_SAE_STATUS_HASH_TO_ELEMENT 126 +#define WLAN_SAE_STATUS_PK 127 + +/* MLM message types */ +enum mlmmsgtype { + LIM_MLM_MSG_START = 1000, + LIM_MLM_SCAN_REQ = LIM_MLM_MSG_START, + LIM_MLM_SCAN_CNF = (LIM_MLM_MSG_START + 1), + LIM_MLM_START_CNF = (LIM_MLM_MSG_START + 3), + LIM_MLM_JOIN_REQ = (LIM_MLM_MSG_START + 4), + LIM_MLM_JOIN_CNF = (LIM_MLM_MSG_START + 5), + LIM_MLM_AUTH_REQ = (LIM_MLM_MSG_START + 6), + LIM_MLM_AUTH_CNF = (LIM_MLM_MSG_START + 7), + LIM_MLM_AUTH_IND = (LIM_MLM_MSG_START + 8), + LIM_MLM_ASSOC_REQ = (LIM_MLM_MSG_START + 9), + LIM_MLM_ASSOC_CNF = (LIM_MLM_MSG_START + 10), + LIM_MLM_ASSOC_IND = (LIM_MLM_MSG_START + 11), + LIM_MLM_DISASSOC_REQ = (LIM_MLM_MSG_START + 12), + LIM_MLM_DISASSOC_CNF = (LIM_MLM_MSG_START + 13), + LIM_MLM_DISASSOC_IND = (LIM_MLM_MSG_START + 14), + LIM_MLM_REASSOC_CNF = (LIM_MLM_MSG_START + 15), + LIM_MLM_REASSOC_IND = (LIM_MLM_MSG_START + 16), + LIM_MLM_DEAUTH_REQ = (LIM_MLM_MSG_START + 17), + LIM_MLM_DEAUTH_CNF = (LIM_MLM_MSG_START + 18), + LIM_MLM_DEAUTH_IND = (LIM_MLM_MSG_START + 19), + LIM_MLM_TSPEC_REQ = (LIM_MLM_MSG_START + 20), + LIM_MLM_TSPEC_CNF = (LIM_MLM_MSG_START + 21), + LIM_MLM_TSPEC_IND = (LIM_MLM_MSG_START + 22), + LIM_MLM_SETKEYS_CNF = LIM_MLM_MSG_START + 24, + LIM_MLM_LINK_TEST_STOP_REQ = LIM_MLM_MSG_START + 30, + LIM_MLM_PURGE_STA_IND = (LIM_MLM_MSG_START + 31), + /* + * Values (LIM_MLM_MSG_START + 32) through + * (LIM_MLM_MSG_START + 40) are unused. + */ +}; + +#define LIM_WEP_IN_FC 1 +#define LIM_NO_WEP_IN_FC 0 + +#define LIM_DECRYPT_ICV_FAIL 1 + +/* / Definitions to distinguish between Association/Reassociaton */ +#define LIM_ASSOC 0 +#define LIM_REASSOC 1 + +/* / Verifies whether given mac addr matches the CURRENT Bssid */ +#define IS_CURRENT_BSSID(mac, addr, pe_session) (!qdf_mem_cmp(addr, \ + pe_session->bssId, \ + sizeof(pe_session->bssId))) +/* / Verifies whether given addr matches the REASSOC Bssid */ +#define IS_REASSOC_BSSID(mac, addr, pe_session) (!qdf_mem_cmp(addr, \ + pe_session->limReAssocbssId, \ + sizeof(pe_session->limReAssocbssId))) + +#define REQ_TYPE_REGISTRAR (0x2) +#define REQ_TYPE_WLAN_MANAGER_REGISTRAR (0x3) + +#define RESP_TYPE_ENROLLEE_INFO_ONLY (0x0) +#define RESP_TYPE_ENROLLEE_OPEN_8021X (0x1) +#define RESP_TYPE_AP (0x3) + + +#define HAL_USE_SELF_STA_REQUESTED_MASK 0x2 /* bit 1 for STA overwrite with selfSta Requested. */ + +#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 /* Bit 6 will be used to control BD rate for Management frames */ +#define HAL_USE_PEER_STA_REQUESTED_MASK 0x80 /* bit 7 will be used to control frames for p2p interface */ +#define HAL_USE_PMF 0x20 +#define HAL_USE_INCORRECT_KEY_PMF 0x10 + +#define MGMT_TX_USE_INCORRECT_KEY BIT(0) + +#define LIM_DOS_PROTECTION_TIME 1000 //1000ms +/* enums used by LIM are as follows */ + +enum eLimDisassocTrigger { + eLIM_HOST_DISASSOC, + eLIM_PEER_ENTITY_DISASSOC, + eLIM_LINK_MONITORING_DISASSOC, + eLIM_PROMISCUOUS_MODE_DISASSOC, + eLIM_HOST_DEAUTH, + eLIM_PEER_ENTITY_DEAUTH, + eLIM_LINK_MONITORING_DEAUTH, + eLIM_JOIN_FAILURE, + eLIM_REASSOC_REJECT, + eLIM_DUPLICATE_ENTRY, +}; + +/** + * enum eChannelChangeReasonCodes - Reason code to determine the channel change + * reason + * @LIM_SWITCH_CHANNEL_REASSOC: channel switch to reassoc + * @LIM_SWITCH_CHANNEL_JOIN: switch for connect req + * @LIM_SWITCH_CHANNEL_OPERATION: Generic change channel for STA + * @LIM_SWITCH_CHANNEL_SAP_DFS: SAP channel change req + * @LIM_SWITCH_CHANNEL_HT_WIDTH: HT channel width change reg + * @LIM_SWITCH_CHANNEL_MONITOR: Monitor mode channel change req + */ +enum eChannelChangeReasonCodes { + LIM_SWITCH_CHANNEL_REASSOC, + LIM_SWITCH_CHANNEL_JOIN, + LIM_SWITCH_CHANNEL_OPERATION, + LIM_SWITCH_CHANNEL_SAP_DFS, + LIM_SWITCH_CHANNEL_HT_WIDTH, + LIM_SWITCH_CHANNEL_MONITOR, +}; + +typedef struct sLimMlmStartReq { + tSirMacSSid ssId; + enum bss_type bssType; + tSirMacAddr bssId; + tSirMacBeaconInterval beaconPeriod; + uint8_t dtimPeriod; + tSirMacCfParamSet cfParamSet; + uint32_t oper_ch_freq; + ePhyChanBondState cbMode; + tSirMacRateSet rateSet; + uint8_t sessionId; /* Added For BT-AMP Support */ + + /* Parameters reqd for new HAL (message) interface */ + tSirNwType nwType; + uint8_t htCapable; + tSirMacHTOperatingMode htOperMode; + uint8_t dualCTSProtection; + uint8_t txChannelWidthSet; + uint8_t ssidHidden; + uint8_t wps_state; + uint8_t obssProtEnabled; + uint16_t beacon_tx_rate; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +} tLimMlmStartReq, *tpLimMlmStartReq; + +typedef struct sLimMlmStartCnf { + tSirResultCodes resultCode; + uint8_t sessionId; +} tLimMlmStartCnf, *tpLimMlmStartCnf; + +typedef struct sLimMlmJoinCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmJoinCnf, *tpLimMlmJoinCnf; + +typedef struct sLimMlmAssocReq { + tSirMacAddr peerMacAddr; + uint16_t capabilityInfo; + tSirMacListenInterval listenInterval; + uint8_t sessionId; +} tLimMlmAssocReq, *tpLimMlmAssocReq; + +typedef struct sLimMlmAssocCnf { + tSirResultCodes resultCode; /* Internal status code. */ + uint16_t protStatusCode; /* Protocol Status code. */ + uint8_t sessionId; +} tLimMlmAssocCnf, *tpLimMlmAssocCnf; + +typedef struct sLimMlmAssocInd { + tSirMacAddr peerMacAddr; + uint16_t aid; + tAniAuthType authType; + enum ani_akm_type akm_type; + tAniSSID ssId; + tSirRSNie rsnIE; + tSirWAPIie wapiIE; + tSirAddie addIE; /* additional IE received from the peer, which possibly includes WSC IE and/or P2P IE. */ + tSirMacCapabilityInfo capabilityInfo; + bool spectrumMgtIndicator; + struct power_cap_info powerCap; + struct supported_channels supportedChannels; + uint8_t sessionId; + + bool WmmStaInfoPresent; + + /* Required for indicating the frames to upper layer */ + uint32_t assocReqLength; + uint8_t *assocReqPtr; + struct oem_channel_info chan_info; + bool ampdu; + bool sgi_enable; + bool tx_stbc; + bool rx_stbc; + tSirMacHTChannelWidth ch_width; + enum sir_sme_phy_mode mode; + uint8_t max_supp_idx; + uint8_t max_ext_idx; + uint8_t max_mcs_idx; + uint8_t max_real_mcs_idx; + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + uint8_t ecsa_capable; + uint32_t ext_cap; + uint8_t supported_band; + + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + bool he_caps_present; + bool eht_caps_present; + bool is_sae_authenticated; +#ifdef WLAN_FEATURE_11BE_MLO + tSirMacAddr peer_mld_addr; +#endif +} tLimMlmAssocInd, *tpLimMlmAssocInd; + +typedef struct sLimMlmReassocReq { + tSirMacAddr peerMacAddr; + uint16_t capabilityInfo; + tSirMacListenInterval listenInterval; + uint8_t sessionId; +} tLimMlmReassocReq, *tpLimMlmReassocReq; + +typedef struct sLimMlmReassocCnf { + tSirResultCodes resultCode; + uint16_t protStatusCode; /* Protocol Status code. */ + uint8_t sessionId; +} tLimMlmReassocCnf, *tpLimMlmReassocCnf; + +typedef struct sLimMlmAuthCnf { + tSirMacAddr peerMacAddr; + tAniAuthType authType; + tSirResultCodes resultCode; + uint16_t protStatusCode; + uint8_t sessionId; +} tLimMlmAuthCnf, *tpLimMlmAuthCnf; + +typedef struct sLimMlmDeauthReq { + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; + uint16_t deauthTrigger; + uint16_t aid; + uint8_t sessionId; /* Added for BT-AMP SUPPORT */ + +} tLimMlmDeauthReq, *tpLimMlmDeauthReq; + +typedef struct sLimMlmDeauthCnf { + struct qdf_mac_addr peer_macaddr; + tSirResultCodes resultCode; + uint16_t deauthTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDeauthCnf, *tpLimMLmDeauthCnf; + +typedef struct sLimMlmDeauthInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t deauthTrigger; + uint16_t aid; +} tLimMlmDeauthInd, *tpLimMlmDeauthInd; + +typedef struct sLimMlmDisassocReq { + struct qdf_mac_addr peer_macaddr; + uint16_t reasonCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocReq, *tpLimMlmDisassocReq; + +typedef struct sLimMlmDisassocCnf { + tSirMacAddr peerMacAddr; + tSirMacAddr peerMldAddr; + tSirResultCodes resultCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocCnf, *tpLimMlmDisassocCnf; + +typedef struct sLimMlmDisassocInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t disassocTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmDisassocInd, *tpLimMlmDisassocInd; + +typedef struct sLimMlmPurgeStaInd { + tSirMacAddr peerMacAddr; + uint16_t reasonCode; + uint16_t purgeTrigger; + uint16_t aid; + uint8_t sessionId; +} tLimMlmPurgeStaInd, *tpLimMlmPurgeStaInd; + +/** + * struct sLimMlmSetKeysCnf - set key confirmation parameters + * @peer_macaddr: peer mac address + * @resultCode: Result of set key operation + * @aid: association id + * @sessionId: PE session id + * @key_len_nonzero: Keys are non-zero length + */ +typedef struct sLimMlmSetKeysCnf { + struct qdf_mac_addr peer_macaddr; + uint16_t resultCode; + uint16_t aid; + uint8_t sessionId; + bool key_len_nonzero; +} tLimMlmSetKeysCnf, *tpLimMlmSetKeysCnf; + +/* Function templates */ + +bool lim_process_sme_req_messages(struct mac_context *, struct scheduler_msg *); +void lim_process_mlm_req_messages(struct mac_context *, struct scheduler_msg *); +void lim_process_mlm_rsp_messages(struct mac_context *, uint32_t, uint32_t *); +void lim_process_sme_del_bss_rsp(struct mac_context *mac, + struct pe_session *pe_session); + +/** + * lim_process_mlm_start_cnf(): called to processes MLM_START_CNF message from + * MLM State machine. + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * Return: None + */ +void lim_process_mlm_start_cnf(struct mac_context *mac_ctx, uint32_t *msg_buf); + +void lim_get_random_bssid(struct mac_context *mac, uint8_t *data); + +/* Function to handle HT and HT IE CFG parameter intializations */ +void handle_ht_capabilityand_ht_info(struct mac_context *mac, + struct pe_session *pe_session); + +void lim_handle_param_update(struct mac_context *mac, eUpdateIEsType cfgId); + +/* Function to apply CFG parameters before join/reassoc/start BSS */ +void lim_apply_configuration(struct mac_context *, struct pe_session *); + +/** + * lim_set_cfg_protection() - sets lim global cfg cache from the config + * @mac: global mac context + * @pesessionEntry: PE session + * + * Return none + */ +void lim_set_cfg_protection(struct mac_context *mac, struct pe_session *pesessionEntry); + +/* Function to Initialize MLM state machine on STA */ +QDF_STATUS lim_init_mlm(struct mac_context *); + +/** + * struct pasn_peer_delete_msg - PASN peer delete request message + * @message_type: Message type + * @length: message length + * @vdev_id: Vdev id + */ +struct pasn_peer_delete_msg { + uint16_t message_type; + uint16_t length; + uint8_t vdev_id; +}; + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +/** + * lim_process_pasn_delete_all_peers() - Process delete all PASN peers + * request + * @mac: Pointer to mac address + * @msg: Peer delete message + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_process_pasn_delete_all_peers(struct mac_context *mac, + struct pasn_peer_delete_msg *msg); +#else +static inline QDF_STATUS +lim_process_pasn_delete_all_peers(struct mac_context *mac, + struct pasn_peer_delete_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/* Function to cleanup MLM state machine */ +void lim_cleanup_mlm(struct mac_context *); + +/* Management frame handling functions */ + +#ifdef WLAN_FEATURE_11BE +/** + * lim_process_beacon_eht() - process beacon 11be IE + * @mac_ctx: global mac context + * @session: pe session + * @bcn_ptr: pointer to tSchBeaconStruct + * + * Return none + */ +void lim_process_beacon_eht(struct mac_context *mac_ctx, + struct pe_session *session, + tSchBeaconStruct *bcn_ptr); + +/** + * lim_process_beacon_eht_op() - process beacon 11be eht op IE + * @session: pe session + * @bcn_ptr: pointer to bcn ptr + * + * Return none + */ +void lim_process_beacon_eht_op(struct pe_session *session, + struct sSirProbeRespBeacon *bcn_ptr); +#else +static inline +void lim_process_beacon_eht(struct mac_context *mac_ctx, + struct pe_session *session, + tSchBeaconStruct *bcn_ptr) +{ +} + +static inline +void lim_process_beacon_eht_op(struct pe_session *session, + struct sSirProbeRespBeacon *bcn_ptr) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_process_bcn_prb_rsp_t2lm() - process beacon/probe response + * 11be t2lm IE + * @mac_ctx: global mac context + * @session: pe session + * @bcn_ptr: pointer to tpSirProbeRespBeacon + * + * Return none + */ +void lim_process_bcn_prb_rsp_t2lm(struct mac_context *mac_ctx, + struct pe_session *session, + tpSirProbeRespBeacon bcn_ptr); + +/** + * lim_process_beacon_mlo() - process beacon mlo IE + * @mac_ctx: global mac context + * @session: pe session + * @bcn_ptr: pointer to tSchBeaconStruct + * + * Return none + */ +void lim_process_beacon_mlo(struct mac_context *mac_ctx, + struct pe_session *session, + tSchBeaconStruct *bcn_ptr); + +/** + * lim_process_ml_reconfig() - to process beacon frames with reconfig IE + * @mac_ctx: Pointer to Global MAC structure + * @session: A pointer to session + * @rx_pkt_info: A pointer to RX packet info structure + * + * This function will process ml reconfig beacon frames. If reconfig ie + * is present for link removal, link reconfig timer will start. + * + * Return: none + */ +void +lim_process_ml_reconfig(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *rx_pkt_info); +#else +static inline +void lim_process_beacon_mlo(struct mac_context *mac_ctx, + struct pe_session *session, + tSchBeaconStruct *bcn_ptr) +{ +} + +static inline +void lim_process_bcn_prb_rsp_t2lm(struct mac_context *mac_ctx, + struct pe_session *session, + tpSirProbeRespBeacon bcn_ptr) +{ +} + +static inline void +lim_process_ml_reconfig(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t *rx_pkt_info) +{ +} +#endif + +void lim_process_beacon_frame(struct mac_context *, uint8_t *, struct pe_session *); +void lim_process_probe_req_frame(struct mac_context *, uint8_t *, struct pe_session *); +void lim_process_probe_rsp_frame(struct mac_context *, uint8_t *, struct pe_session *); +void lim_process_probe_req_frame_multiple_bss(struct mac_context *, uint8_t *, + struct pe_session *); + +/** + * lim_process_gen_probe_rsp_frame() - process generate probe rsp frame + * @mac_ctx: pointer to global mac context + * @session_entry: pointer to pe session + * @bcn_probe: pointer to the data frame + * @len: the length of data frame + * + * Return: void + */ +void lim_process_gen_probe_rsp_frame(struct mac_context *mac_ctx, + struct pe_session *session_entry, + uint8_t *bcn_probe, uint32_t len); + +/* Process Auth frame when we have a session in progress. */ +void lim_process_auth_frame(struct mac_context *, uint8_t *, struct pe_session *); + +/** + * lim_process_auth_frame_no_session() - Process auth frame received from AP to + * which we are not connected currently. + * @mac: Pointer to global mac context + * @bd: Pointer to rx auth frame + * @body: Pointer to lim_msg->body_ptr + * + * This is possibly the pre-auth from the neighbor AP, in the same mobility + * domain or pre-authentication reply for WPA3 SAE roaming. + * This will be used in case of 11r FT. + */ +QDF_STATUS lim_process_auth_frame_no_session(struct mac_context *mac, + uint8_t *bd, void *body); + +/** + * lim_check_assoc_req() - check session and peer info before handling it + * @mac_ctx: pointer to Global MAC structure + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @sa: Mac address of requesting peer + * @session: pointer to pe session entry + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_check_assoc_req(struct mac_context *mac_ctx, + uint8_t sub_type, tSirMacAddr sa, + struct pe_session *session); + +/** + * lim_proc_assoc_req_frm_cmn() - process assoc req frame + * @mac_ctx: pointer to Global MAC structure + * @sub_type: Assoc(=0) or Reassoc(=1) Requestframe + * @session: pointer to pe session entry + * @sa: Mac address of requesting peer + * @assoc_req: assoc req + * @peer_aid: association id + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_proc_assoc_req_frm_cmn(struct mac_context *mac_ctx, + uint8_t sub_type, + struct pe_session *session, + tSirMacAddr sa, + tpSirAssocReq assoc_req, + uint16_t peer_aid); + +void lim_process_assoc_req_frame(struct mac_context *, uint8_t *, uint8_t, struct pe_session *); + +/** + * lim_fill_lim_assoc_ind_params() - Initialize lim association indication + * @assoc_ind: PE association indication structure + * @mac_ctx: Pointer to Global MAC structure + * @sta_ds: station dph entry + * @session_entry: PE session entry + * + * Return: true if lim assoc ind filled successfully + */ +bool lim_fill_lim_assoc_ind_params( + tpLimMlmAssocInd assoc_ind, + struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + struct pe_session *session_entry); + +/** + * lim_sae_auth_cleanup_retry() - API to cleanup sae auth frmae stored + * and deactivate the timer + * @mac_ctx: Pointer to mac context + * @vdev_id: vdev id + * + * Return: none + */ +void lim_sae_auth_cleanup_retry(struct mac_context *mac_ctx, + uint8_t vdev_id); + +/** + * lim_fill_sme_assoc_ind_params() - Initialize association indication + * @mac_ctx: Pointer to Global MAC structure + * @assoc_ind: PE association indication structure + * @sme_assoc_ind: SME association indication + * @session_entry: PE session entry + * @assoc_req_alloc: malloc memory for assoc_req or not + * + * Return: None + */ +void +lim_fill_sme_assoc_ind_params( + struct mac_context *mac_ctx, + tpLimMlmAssocInd assoc_ind, struct assoc_ind *sme_assoc_ind, + struct pe_session *session_entry, bool assoc_req_alloc); + +/** + * lim_send_mlm_assoc_ind() - Sends assoc indication to SME + * @mac_ctx: Global Mac context + * @sta_ds: Station DPH hash entry + * @session_entry: PE session entry + * + * This function sends either LIM_MLM_ASSOC_IND + * or LIM_MLM_REASSOC_IND to SME. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_mlm_assoc_ind(struct mac_context *mac, + tpDphHashNode sta, + struct pe_session *pe_session); + +/** + * lim_process_assoc_rsp_frame() - Processes assoc response + * @mac_ctx: Pointer to Global MAC structure + * @rx_packet_info: A pointer to Rx packet info structure + * @reassoc_frame_length: Valid frame length if its a reassoc response frame + * else 0 + * @sub_type: Indicates whether it is Association Response (=0) or + * Reassociation Response (=1) frame + * + * This function is called by lim_handle80211_frames() or + * pe_roam_synch_callback() upon Re/Association Response frame reception or + * roam synch indication with reassociation response frame is received. + * + * Return: None + */ +void lim_process_assoc_rsp_frame(struct mac_context *mac, uint8_t *rx_pkt_info, + uint32_t reassoc_frame_len, uint8_t subtype, + struct pe_session *pe_session); + +void lim_process_disassoc_frame(struct mac_context *, uint8_t *, struct pe_session *); + +/** + * lim_get_nss_supported_by_ap() - finds out nss from AP's beacons + * @vht_caps: VHT capabilities + * @ht_caps: HT capabilities + * + * Return: nss advertised by AP in beacon + */ +uint8_t lim_get_nss_supported_by_ap(tDot11fIEVHTCaps *vht_caps, + tDot11fIEHTCaps *ht_caps, + tDot11fIEhe_cap *he_caps); +/* + * lim_perform_disassoc() - Actual action taken after receiving disassoc + * @mac_ctx: Global MAC context + * @frame_rssi: RSSI of the frame + * @rc: Reason code of the deauth + * @pe_session: PE session entry pointer + * @addr: BSSID from which the disassoc is received + * + * Return: None + */ +void lim_perform_disassoc(struct mac_context *mac_ctx, int32_t frame_rssi, + uint16_t rc, struct pe_session *pe_session, + tSirMacAddr addr); +/* + * lim_disassoc_tdls_peers() - Disassoc action for tdls peers + * @mac_ctx: Global MAC context + * @pe_session: PE session entry pointer + * @addr: BSSID from which the disassoc is received + * + * Return: None + */ +#ifdef FEATURE_WLAN_TDLS +void lim_disassoc_tdls_peers(struct mac_context *mac_ctx, + struct pe_session *pe_session, tSirMacAddr addr); +#else +static inline void lim_disassoc_tdls_peers(struct mac_context *mac_ctx, + struct pe_session *pe_session, tSirMacAddr addr) +{ +} +#endif +void lim_process_deauth_frame(struct mac_context *, uint8_t *, struct pe_session *); +/* + * lim_perform_deauth() - Actual action taken after receiving deauth + * @mac_ctx: Global MAC context + * @pe_session: PE session entry pointer + * @rc: Reason code of the deauth + * @addr: BSSID from which the deauth is received + * @frame_rssi: RSSI of the frame + * + * Return: None + */ +void lim_perform_deauth(struct mac_context *mac_ctx, struct pe_session *pe_session, + uint16_t rc, tSirMacAddr addr, int32_t frame_rssi); +void lim_process_action_frame(struct mac_context *, uint8_t *, struct pe_session *); +void lim_process_action_frame_no_session(struct mac_context *mac, uint8_t *pRxMetaInfo); + +void lim_populate_mac_header(struct mac_context *, uint8_t *, uint8_t, uint8_t, + tSirMacAddr, tSirMacAddr); +QDF_STATUS lim_send_probe_req_mgmt_frame(struct mac_context *, tSirMacSSid *, + tSirMacAddr, qdf_freq_t, tSirMacAddr, + uint32_t, uint16_t *, uint8_t *); + +/** + * lim_send_probe_rsp_mgmt_frame() - Send probe response + * @mac_ctx: Handle for mac context + * @peer_macaddr: Mac address of requesting peer + * @ssid: SSID for response + * @pe_session: PE session id + * @preq_p2pie: P2P IE in incoming probe request + * + * Builds and sends probe response frame to the requesting peer + * + * Return: void + */ +void +lim_send_probe_rsp_mgmt_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_macaddr, + tpAniSSID ssid, + struct pe_session *pe_session, + uint8_t preq_p2pie); + +void lim_send_auth_mgmt_frame(struct mac_context *, tSirMacAuthFrameBody *, tSirMacAddr, + uint8_t, struct pe_session *); +void lim_send_assoc_req_mgmt_frame(struct mac_context *, tLimMlmAssocReq *, struct pe_session *); +#ifdef WLAN_FEATURE_HOST_ROAM +void lim_send_reassoc_req_with_ft_ies_mgmt_frame(struct mac_context *mac, + tLimMlmReassocReq *pMlmReassocReq, struct pe_session *pe_session); +void lim_send_reassoc_req_mgmt_frame(struct mac_context *, tLimMlmReassocReq *, + struct pe_session *); +/** + * lim_process_rx_scan_handler() - + * process the event for scan which is issued by LIM + * @vdev: wlan objmgr vdev pointer + * @event: scan event + * @arg: global mac context pointer + * + * Return: void + */ +void lim_process_rx_scan_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); +#else +static inline void lim_send_reassoc_req_with_ft_ies_mgmt_frame( + struct mac_context *mac, tLimMlmReassocReq *pMlmReassocReq, + struct pe_session *pe_session) +{} +static inline void lim_send_reassoc_req_mgmt_frame(struct mac_context *mac_ctx, + tLimMlmReassocReq *reassoc_req, struct pe_session *pe_session) +{} +static inline void lim_process_rx_scan_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{} +#endif +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * lim_process_set_he_bss_color() - process the set he bss color request + * + * @mac_ctx: global mac context pointer + * @msg_buf: message buffer pointer + * + * Return: void + */ +void lim_process_set_he_bss_color(struct mac_context *mac_ctx, uint32_t *msg_buf); + +/** + * lim_reconfig_obss_scan_param() - reconfig the obss scan params + * + * @mac_ctx: global mac context pointer + * @msg_buf: message buffer pointer + * + * Return: void + */ +void lim_reconfig_obss_scan_param(struct mac_context *mac_ctx, + uint32_t *msg_buf); + +/** + * lim_process_obss_color_collision_info() - Process the obss color collision + * request. + * @mac_ctx: global mac context pointer + * @msg_buf: message buffer pointer + * + * Return: void + */ +void lim_process_obss_color_collision_info(struct mac_context *mac_ctx, + uint32_t *msg_buf); + +/** + * lim_send_obss_color_collision_cfg() - Send obss color collision cfg. + * @mac_ctx: global mac context pointer + * @session: Pointer to session + * @event_type: obss color collision detection type + * + * Return: void + */ +void lim_send_obss_color_collision_cfg(struct mac_context *mac_ctx, + struct pe_session *session, + enum wmi_obss_color_collision_evt_type + event_type); +#else +static inline void lim_process_set_he_bss_color(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{} + +static inline void lim_reconfig_obss_scan_param(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{ +} +static inline void lim_process_obss_color_collision_info(struct mac_context *mac_ctx, + uint32_t *msg_buf) +{} +static inline void lim_send_obss_color_collision_cfg(struct mac_context *mac_ctx, + struct pe_session *session, + enum wmi_obss_color_collision_evt_type event_type) +{} +#endif +void lim_send_delts_req_action_frame(struct mac_context *mac, tSirMacAddr peer, + uint8_t wmmTspecPresent, + struct mac_ts_info * pTsinfo, + struct mac_tspec_ie * pTspecIe, + struct pe_session *pe_session); +void lim_send_addts_req_action_frame(struct mac_context *mac, tSirMacAddr peerMacAddr, + tSirAddtsReqInfo *addts, struct pe_session *); + +#ifdef WLAN_FEATURE_MSCS +/** + * lim_send_mscs_req_action_frame() - Send mscs req + * @mac_ctx: Handle for mac context + * @peer_mac: Mac address of requesting peer + * @mscs_req: mscs request buffer + * @pe_session: PE session id. + * + * Builds and sends mscs action frame to the peer. + * + * Return: void + */ +void lim_send_mscs_req_action_frame(struct mac_context *mac, + struct qdf_mac_addr peer_mac, + struct mscs_req_info *mscs_req, + struct pe_session *pe_session); +#endif + +/** + * lim_send_assoc_rsp_mgmt_frame() - Send assoc response + * @mac_ctx: Handle for mac context + * @status_code: Status code for assoc response frame + * @aid: Association ID + * @peer_addr: Mac address of requesting peer + * @subtype: Assoc/Reassoc + * @sta: Pointer to station node + * @pe_session: PE session id. + * @tx_complete: Need tx complete callback or not + * + * Builds and sends association response frame to the requesting peer. + * + * Return: void + */ +void +lim_send_assoc_rsp_mgmt_frame( + struct mac_context *mac_ctx, + uint16_t status_code, uint16_t aid, tSirMacAddr peer_addr, + uint8_t subtype, tpDphHashNode sta, struct pe_session *pe_session, + bool tx_complete); + +void lim_send_disassoc_mgmt_frame(struct mac_context *, uint16_t, tSirMacAddr, + struct pe_session *, bool waitForAck); +void lim_send_deauth_mgmt_frame(struct mac_context *, uint16_t, tSirMacAddr, struct pe_session *, + bool waitForAck); + +/** + * lim_process_mlm_update_hidden_ssid_rsp() - process hidden ssid response + * @mac_ctx: global mac context + * @vdev_id: vdev id + * + * Return: None + */ +void lim_process_mlm_update_hidden_ssid_rsp(struct mac_context *mac_ctx, + uint8_t vdev_id); + +tSirResultCodes lim_mlm_add_bss(struct mac_context *, tLimMlmStartReq *, + struct pe_session *pe_session); + +QDF_STATUS lim_send_channel_switch_mgmt_frame(struct mac_context *, tSirMacAddr, + uint8_t, uint8_t, uint8_t, + struct pe_session *); + +QDF_STATUS lim_send_extended_chan_switch_action_frame(struct mac_context *mac_ctx, + tSirMacAddr peer, uint8_t mode, uint8_t new_op_class, + uint8_t new_channel, uint8_t count, struct pe_session *session_entry); +QDF_STATUS lim_p2p_oper_chan_change_confirm_action_frame( + struct mac_context *mac_ctx, tSirMacAddr peer, + struct pe_session *session_entry); + +QDF_STATUS lim_send_neighbor_report_request_frame(struct mac_context *, + tpSirMacNeighborReportReq, + tSirMacAddr, struct pe_session *); + +/** + * lim_send_link_report_action_frame() - Send link measurement report action + * frame in response for a link measurement request received. + * @mac: Pointer to Mac context + * @link_report: Pointer to the sSirMacLinkReport struct + * @peer: BSSID of the peer + * @pe_session: Pointer to the pe_session + * + * Return: QDF_STATUS + * + */ +QDF_STATUS +lim_send_link_report_action_frame(struct mac_context *mac, + tpSirMacLinkReport link_report, + tSirMacAddr peer, + struct pe_session *pe_session); + +/** + * lim_send_radio_measure_report_action_frame - Send RRM report action frame + * @mac: pointer to global MAC context + * @dialog_token: Dialog token to be used in the action frame + * @num_report: number of reports in pRRMReport + * @is_last_frame: is the current report last or more reports to follow + * @pRRMReport: Pointer to the RRM report structure + * @peer: MAC address of the peer + * @pe_session: Pointer to the PE session entry + * + * Return: Ret Status + */ +QDF_STATUS +lim_send_radio_measure_report_action_frame(struct mac_context *mac, + uint8_t dialog_token, + uint8_t num_report, + bool is_last_frame, + tpSirMacRadioMeasureReport pRRMReport, + tSirMacAddr peer, + struct pe_session *pe_session); + +#ifdef FEATURE_WLAN_TDLS +void lim_init_tdls_data(struct mac_context *, struct pe_session *); + +/** + * lim_process_sme_tdls_mgmt_send_req() - send out tdls management frames + * @mac_ctx: global mac context + * @msg: message buffer received from SME. + * + * Process Send Mgmt Request from SME and transmit to AP. + * + * Return: QDF_STATUS_SUCCESS on success, error code otherwise + */ +QDF_STATUS lim_process_sme_tdls_mgmt_send_req(struct mac_context *mac_ctx, + void *msg); + +/** + * lim_process_sme_tdls_add_sta_req() - process TDLS Add STA + * @mac_ctx: global mac context + * @msg: message buffer received from SME. + * + * Process TDLS Add Station request + * + * Return: QDF_STATUS_SUCCESS on success, error code otherwise + */ +QDF_STATUS lim_process_sme_tdls_add_sta_req(struct mac_context *mac, + void *msg); + +/** + * lim_process_sme_tdls_del_sta_req() - process TDLS Del STA + * @mac_ctx: global mac context + * @msg: message buffer received from SME. + * + * Process TDLS Delete Station request + * + * Return: QDF_STATUS_SUCCESS on success, error code otherwise + */ +QDF_STATUS lim_process_sme_tdls_del_sta_req(struct mac_context *mac, + void *msg); + +void lim_send_sme_mgmt_tx_completion(struct mac_context *mac, uint32_t vdev_id, + uint32_t txCompleteStatus); +QDF_STATUS lim_delete_tdls_peers(struct mac_context *mac_ctx, + struct pe_session *session_entry); +QDF_STATUS lim_process_tdls_add_sta_rsp(struct mac_context *mac, void *msg, struct pe_session *); +void lim_process_tdls_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg, + struct pe_session *session_entry); + +/** + * lim_update_tdls_state_in_fw() - Update TDLS state in FW + * + * @session_entry - PE sessions + * @value -value to be updated + * + * + * Return: void + */ +void lim_update_tdls_set_state_for_fw(struct pe_session *session_entry, + bool value); + +/** + * lim_update_tdls_2g_bw() - Update TDLS peer bw to fw + * + * @session_entry - PE sessions + * + * Return: void + */ +void lim_update_tdls_2g_bw(struct pe_session *session); + +#else +static inline QDF_STATUS lim_delete_tdls_peers(struct mac_context *mac_ctx, + struct pe_session *session_entry) +{ + return QDF_STATUS_SUCCESS; +} +static inline void lim_init_tdls_data(struct mac_context *mac, + struct pe_session *pe_session) +{ + +} + +static inline void lim_update_tdls_set_state_for_fw(struct pe_session + *session_entry, bool value) +{ +} + +static inline void lim_update_tdls_2g_bw(struct pe_session *session) +{ +} +#endif + +/* Algorithms & Link Monitoring related functions */ +/* / Function that handles heartbeat failure */ +void lim_handle_heart_beat_failure(struct mac_context *, struct pe_session *); + +/** + * lim_tear_down_link_with_ap() - Tear down link with AP + * @mac: mac context + * @session_id: PE session id + * @reason_code: Disconnect reason code as per emun wlan_reason_code + * @trigger: Disconnect trigger as per enum eLimDisassocTrigger + * + * Function that triggers link tear down with AP upon HB failure + * + * Return: None + */ +void lim_tear_down_link_with_ap(struct mac_context *mac, + uint8_t session_id, + enum wlan_reason_code reason_code, + enum eLimDisassocTrigger trigger); + +/* / Function that defers the messages received */ +uint32_t lim_defer_msg(struct mac_context *, struct scheduler_msg *); + +#ifdef ANI_SUPPORT_11H +/* / Function that sends Measurement Report action frame */ +QDF_STATUS lim_send_meas_report_frame(struct mac_context *, tpSirMacMeasReqActionFrame, + tSirMacAddr, struct pe_session *pe_session); + +/* / Function that sends TPC Report action frame */ +QDF_STATUS lim_send_tpc_report_frame(struct mac_context *, tpSirMacTpcReqActionFrame, + tSirMacAddr, struct pe_session *pe_session); +#endif + +/** + * lim_handle_add_bss_rsp() - Handle add bss response + * @mac_ctx: mac context + * @add_bss_rsp: add bss rsp + * + * This function is called to handle all types of add bss rsp + * It will free memory of add_bss_rsp in the end after rsp is handled. + * + * Return: None + */ +void lim_handle_add_bss_rsp(struct mac_context *mac_ctx, + struct add_bss_rsp *add_bss_rsp); + +void lim_process_mlm_add_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQt, + struct pe_session *pe_session); +void lim_process_mlm_del_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ); + +QDF_STATUS +lim_process_mlm_del_all_sta_rsp(struct vdev_mlme_obj *vdev_mlme, + struct peer_delete_all_response *rsp); +/** + * lim_process_mlm_del_bss_rsp () - API to process delete bss response + * @mac: Pointer to Global MAC structure + * @vdev_stop_rsp: pointer to vdev stop response + * @pe_session: pointer to pe_session + * + * Return: None + */ +void lim_process_mlm_del_bss_rsp(struct mac_context *mac, + struct del_bss_resp *vdev_stop_rsp, + struct pe_session *pe_session); + +void lim_process_sta_mlm_add_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session); +void lim_process_sta_mlm_del_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session); + +/** + * lim_process_sta_mlm_del_bss_rsp() - handle del bss response of STA + * @mac: Pointer to Global MAC structure + * @vdev_stop_rsp: pointer to vdev stop response + * @pe_session: pointer to pe_session + * + * Return: none + */ +void lim_process_sta_mlm_del_bss_rsp(struct mac_context *mac, + struct del_bss_resp *vdev_stop_rsp, + struct pe_session *pe_session); + +void lim_process_mlm_set_sta_key_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ); +void lim_process_mlm_set_bss_key_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ); + +/* Function to process WMA_SWITCH_CHANNEL_RSP message */ +void lim_process_switch_channel_rsp(struct mac_context *mac, + struct vdev_start_response *rsp); + +/** + * lim_sta_handle_connect_fail() - handle connect failure of STA + * @param - join params + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_sta_handle_connect_fail(join_params *param); + +/** + * lim_join_result_callback() - Callback to handle join rsp + * @mac: Pointer to Global MAC structure + * @vdev_id: vdev id + * + * This callback function is used to delete PE session + * entry and send join response to sme. + * + * Return: None + */ +void lim_join_result_callback(struct mac_context *mac, + uint8_t vdev_id); + +/** + * lim_update_lost_link_rssi() - API to update lost link rssi in lim session + * @mac: Pointer to Global MAC structure + * @rssi: rssi at disconnect time + * + * Return: None + */ +void lim_update_lost_link_rssi(struct mac_context *mac, uint32_t rssi); + +#ifdef WLAN_FEATURE_HOST_ROAM +QDF_STATUS lim_sta_reassoc_error_handler(struct reassoc_params *param); +#else +static inline +QDF_STATUS lim_sta_reassoc_error_handler(struct reassoc_params *param) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/* 11w send SA query request action frame */ +QDF_STATUS lim_send_sa_query_request_frame(struct mac_context *mac, uint8_t *transId, + tSirMacAddr peer, + struct pe_session *pe_session); +/* 11w SA query request action frame handler */ +QDF_STATUS lim_send_sa_query_response_frame(struct mac_context *mac, + uint8_t *transId, tSirMacAddr peer, + struct pe_session *pe_session); +/* Inline functions */ + +/** + * lim_post_sme_message() + * + ***FUNCTION: + * This function is called by limProcessMlmMessages(). In this + * function MLM sub-module invokes MLM ind/cnf primitives. + * + ***LOGIC: + * Initially MLM makes an SME function call to invoke MLM ind/cnf + * primitive. In future this can be enhanced to 'post' messages to SME. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *msg_buf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_sme_message(struct mac_context *mac, uint32_t msgType, + uint32_t *msg_buf) +{ + struct scheduler_msg msg = {0}; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + + msg.type = (uint16_t) msgType; + msg.bodyptr = msg_buf; + msg.bodyval = 0; + if (msgType > eWNI_SME_MSG_TYPES_BEGIN) { + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, NO_SESSION, + msg.type)); + lim_process_sme_req_messages(mac, &msg); + } else { + lim_process_mlm_rsp_messages(mac, msgType, msg_buf); + } +} /*** end lim_post_sme_message() ***/ + +/** + * lim_post_mlm_message() + * + ***FUNCTION: + * This function is called by limProcessSmeMessages(). In this + * function SME invokes MLME primitives. + * + ***PARAMS: + * + ***LOGIC: + * Initially SME makes an MLM function call to invoke MLM primitive. + * In future this can be enhanced to 'post' messages to MLM. + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param mac Pointer to Global MAC structure + * @param msgType Indicates the MLM primitive message type + * @param *msg_buf A pointer to the MLM message buffer + * + * @return None + */ +static inline void +lim_post_mlm_message(struct mac_context *mac, uint32_t msgType, + uint32_t *msg_buf) +{ + struct scheduler_msg msg = {0}; + + if (!msg_buf) { + pe_err("Buffer is Pointing to NULL"); + return; + } + msg.type = (uint16_t) msgType; + msg.bodyptr = msg_buf; + msg.bodyval = 0; + MTRACE(mac_trace_msg_rx(mac, NO_SESSION, msg.type)); + lim_process_mlm_req_messages(mac, &msg); +} /*** end lim_post_mlm_message() ***/ + +/** + * lim_get_ielen_from_bss_description() + * + ***FUNCTION: + * This function is called in various places to get IE length + * from struct bss_description structure + * number being scanned. + * + ***PARAMS: + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param pBssDescr + * @return Total IE length + */ + +static inline uint16_t +lim_get_ielen_from_bss_description(struct bss_description *pBssDescr) +{ + return wlan_get_ielen_from_bss_description(pBssDescr); +} /*** end lim_get_ielen_from_bss_description() ***/ + +/** + * lim_send_beacon_ind() - send the beacon indication + * @mac_ctx: pointer to mac structure + * @session: pe session + * @reason: beacon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS lim_send_beacon_ind(struct mac_context *mac_ctx, struct pe_session *session, + enum sir_bcn_update_reason reason); + +void +lim_send_vdev_restart(struct mac_context *mac, struct pe_session *pe_session, + uint8_t sessionId); + +void lim_wpspbc_close(struct mac_context *mac, struct pe_session *pe_session); + +#define LIM_WPS_OVERLAP_TIMER_MS 10000 + +void lim_process_disassoc_ack_timeout(struct mac_context *mac); +void lim_process_deauth_ack_timeout(void *pMacGlobal, uint32_t vdev_id); +QDF_STATUS lim_send_disassoc_cnf(struct mac_context *mac); +QDF_STATUS lim_send_deauth_cnf(struct mac_context *mac, uint8_t vdev_id); + +/** + * lim_disassoc_tx_complete_cnf() - callback to indicate Tx completion + * @context: pointer to mac structure + * @txCompleteSuccess: indicates tx success/failure + * @params: tx completion params + * + * function will be invoked on receiving tx completion indication + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS lim_disassoc_tx_complete_cnf(void *context, + uint32_t txCompleteSuccess, + void *params); + +/** + * lim_deauth_tx_complete_cnf() - callback to indicate Tx completion + * @context: pointer to mac structure + * @txCompleteSuccess: indicates tx success/failure + * @params: tx completion params + * + * function will be invoked on receiving tx completion indication + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +QDF_STATUS lim_deauth_tx_complete_cnf(void *context, + uint32_t txCompleteSuccess, + void *params); + +/** + * lim_cm_send_disconnect_rsp() - To send disconnect rsp to CM + * @ctx: pointer to mac structure + * @vdev_id: vdev id + * + * return: None + */ +void lim_cm_send_disconnect_rsp(struct mac_context *mac_ctx, uint8_t vdev_id); + +void lim_send_sme_disassoc_deauth_ntf(struct mac_context *mac_ctx, + QDF_STATUS status, uint32_t *ctx); + +#ifdef FEATURE_WLAN_TDLS +/** + * lim_process_sme_del_all_tdls_peers(): process delete tdls peers + * @mac: pointer to mac context + * @msg_buf: message buffer + * + * This function processes request to delete tdls peers + * + * Return: Success: QDF_STATUS_SUCCESS Failure: Error value + */ +QDF_STATUS +lim_process_sme_del_all_tdls_peers(struct mac_context *mac, uint32_t *msg_buf); + +/** + * lim_delete_all_tdls_peers() - Delete all TDLS peers + * @vdev: Pointer to vdev object + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev); +#else +static inline +QDF_STATUS lim_process_sme_del_all_tdls_peers(struct mac_context *p_mac, + uint32_t *msg_buf) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS lim_delete_all_tdls_peers(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * lim_send_bcn_rsp() - handle beacon send response + * @mac_ctx Pointer to Global MAC structure + * @rsp: beacon send response + * + * Return: None + */ +void lim_send_bcn_rsp(struct mac_context *mac_ctx, tpSendbeaconParams rsp); + +/* / Bit value data structure */ +typedef enum sHalBitVal /* For Bit operations */ +{ + eHAL_CLEAR, + eHAL_SET +} tHalBitVal; + +/** + * lim_send_addba_response_frame(): Send ADDBA response action frame to peer + * @mac_ctx: mac context + * @peer_mac: Peer MAC address + * @tid: TID for which addba response is being sent + * @session: PE session entry + * @addba_extn_present: ADDBA extension present flag + * @amsdu_support: amsdu in ampdu support + * @is_wep: protected bit in fc + * @calc_buff_size: Calculated buf size from peer and self capabilities + * @bssid: peer BSSID + * + * This function is called when ADDBA request is successful. ADDBA response is + * setup by calling addba_response_setup API and frame is then sent out OTA. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_addba_response_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_mac, uint16_t tid, + struct pe_session *session, + uint8_t addba_extn_present, + uint8_t amsdu_support, uint8_t is_wep, + uint16_t calc_buff_size, + tSirMacAddr bssid); + +/** + * lim_send_delba_action_frame() - Send delba to peer + * @mac_ctx: mac context + * @vdev_id: vdev id + * @peer_macaddr: Peer mac addr + * @tid: Tid number + * @reason_code: reason code + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS lim_send_delba_action_frame(struct mac_context *mac_ctx, + uint8_t vdev_id, + uint8_t *peer_macaddr, uint8_t tid, + uint8_t reason_code); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_send_t2lm_action_req_frame() - Send T2LM negotiation request to peer + * @vdev: vdev pointer + * @peer_mac: Peer mac addr + * @args: Pointer to action frame args + * @ongoing_t2lm_neg: T2LM negotiation request + * @token: Dialog token + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_t2lm_action_req_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args, + struct wlan_t2lm_onging_negotiation_info *t2lm_neg, + uint8_t token); + +/** + * lim_send_t2lm_action_rsp_frame() - Send T2LM negotiation response to peer + * @mac_ctx: mac context + * @peer_mac: Peer mac addr + * @session: PE session entry + * @token: Dialog token + * @status_code: T2LM negotiation response status code + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_t2lm_action_rsp_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_mac, + struct pe_session *session, + uint8_t token, + enum wlan_t2lm_resp_frm_type status_code); + +/** + * lim_send_epcs_update_edca_params() - Wrapper for EPCS update edca + * @vdev: vdev object + * @edca: the pointer of edca parameters + * @mu_edca: the flag of mu edca + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_epcs_update_edca_params(struct wlan_objmgr_vdev *vdev, + tSirMacEdcaParamRecord *edca, bool mu_edca); + +/** + * lim_send_epcs_restore_edca_params() - Restore edca parameters + * @vdev: vdev object + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_epcs_restore_edca_params(struct wlan_objmgr_vdev *vdev); + +/** + * lim_send_epcs_action_rsp_frame() - Send EPCS action response frame + * @vdev: vdev object + * @peer_mac: peer mac address pointer + * @args: the pointer of action frame args + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_epcs_action_rsp_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args); + +/** + * lim_send_epcs_action_req_frame() - Send EPCS action request frame + * @vdev: vdev object + * @peer_mac: peer mac address pointer + * @args: the pointer of action frame args + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_epcs_action_req_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args); + +/** + * lim_send_epcs_action_teardown_frame() - Send EPCS action teardown frame + * @vdev: vdev object + * @peer_mac: peer mac address pointer + * @args: the pointer of action frame args + * + * Return: 0 for success, non-zero for failure + */ +QDF_STATUS +lim_send_epcs_action_teardown_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args); +#else +static inline QDF_STATUS +lim_send_t2lm_action_rsp_frame(struct mac_context *mac_ctx, + tSirMacAddr peer_mac, + struct pe_session *session, uint8_t token, + enum wlan_t2lm_resp_frm_type status_code) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +lim_send_t2lm_action_req_frame(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + struct wlan_action_frame_args *args, + struct wlan_t2lm_onging_negotiation_info *t2lm_neg, + uint8_t token) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * lim_process_join_failure_timeout() - This function is called to process + * JoinFailureTimeout + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process JoinFailureTimeout + * + * @Return None + */ +void lim_process_join_failure_timeout(struct mac_context *mac_ctx); + +/** + * lim_process_auth_failure_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +void lim_process_auth_failure_timeout(struct mac_context *mac_ctx); + +/** + * lim_process_assoc_failure_timeout() - This function is called to process Min + * Channel Timeout during channel scan. + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_type: Assoc or reassoc + * + * This function is called to process Min Channel Timeout during channel scan. + * + * @Return: None + */ +void lim_process_assoc_failure_timeout(struct mac_context *mac_ctx, + uint32_t msg_type); + +/** + * lim_process_sae_auth_timeout() - This function is called to process sae + * auth timeout + * @mac_ctx: Pointer to Global MAC structure + * + * @Return: None + */ +void lim_process_sae_auth_timeout(struct mac_context *mac_ctx); + +/** + * lim_process_rrm_sta_stats_rsp_timeout() - This function is called to process + * sta stats response timeout + * @mac_ctx: Pointer to Global MAC structure + * + * @Return: None + */ +void lim_process_rrm_sta_stats_rsp_timeout(struct mac_context *mac_ctx); + +/** + * lim_send_frame() - API to send frame + * @mac_ctx Pointer to Global MAC structure + * @vdev_id: vdev id + * @buf: Pointer to SAE auth retry frame + * @buf_len: length of frame + * + * Return: None + */ +void lim_send_frame(struct mac_context *mac_ctx, uint8_t vdev_id, uint8_t *buf, + uint16_t buf_len); + +/** + * lim_send_mgmt_frame_tx() - Sends mgmt frame + * @mac_ctx Pointer to Global MAC structure + * @msg: Received message info + * + * Return: None + */ +void lim_send_mgmt_frame_tx(struct mac_context *mac_ctx, + struct scheduler_msg *msg); + +/** + * lim_send_csa_restart_req() - send csa restart req + * @mac_ctx Pointer to Global MAC structure + * @vdev_id: vdev id + * + * Return: None + */ +void lim_send_csa_restart_req(struct mac_context *mac_ctx, uint8_t vdev_id); + +/** + * lim_continue_sta_csa_req() - continue with CSA req after HW mode change + * @mac_ctx Pointer to Global MAC structure + * @vdev_id: vdev id + * + * Return: None + */ +void lim_continue_sta_csa_req(struct mac_context *mac_ctx, uint8_t vdev_id); + +/** + * lim_process_mlm_start_req() - process MLM_START_REQ message + * + * @mac_ctx: global MAC context + * @mlm_start_req: Pointer to start req + * + * This function is called to process MLM_START_REQ message + * from SME. MLME now waits for HAL to send WMA_ADD_BSS_RSP. + * + * Return: None + */ +void lim_process_mlm_start_req(struct mac_context *mac_ctx, + tLimMlmStartReq *mlm_start_req); + +/** + * lim_process_mlm_join_req() - process mlm join request. + * + * @mac_ctx: Pointer to Global MAC structure + * @msg: Pointer to the MLM message buffer + * + * This function is called to process MLM_JOIN_REQ message + * from SME. It does following: + * 1) Initialize LIM, HAL, DPH + * 2) Configure the BSS for which the JOIN REQ was received + * a) Send WMA_ADD_BSS_REQ to HAL - + * This will identify the BSS that we are interested in + * --AND-- + * Add a STA entry for the AP (in a STA context) + * b) Wait for WMA_ADD_BSS_RSP + * c) Send WMA_ADD_STA_REQ to HAL + * This will add the "local STA" entry to the STA table + * 3) Continue as before, i.e, + * a) Send a PROBE REQ + * b) Wait for PROBE RSP/BEACON containing the SSID that + * we are interested in + * c) Then start an AUTH seq + * d) Followed by the ASSOC seq + * + * @Return: None + */ +void lim_process_mlm_join_req(struct mac_context *mac_ctx, + tLimMlmJoinReq *mlm_join_req); + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +/** + * lim_pasn_peer_del_all_resp_vdev_delete_resume() - Delete all PASN peers is + * complete resume vdev delete. + * @mac: Mac context pointer + * @vdev: Vdev object pointer + * + * Return: None + */ +void +lim_pasn_peer_del_all_resp_vdev_delete_resume(struct mac_context *mac, + struct wlan_objmgr_vdev *vdev); +#else +static inline void +lim_pasn_peer_del_all_resp_vdev_delete_resume(struct mac_context *mac, + struct wlan_objmgr_vdev *vdev) +{} +#endif + +/** + * lim_send_peer_create_resp() - Send peer create response + * @mac: Pointer to MAC context + * @vdev_id: vdev id + * @status: Status of peer create + * @peer_mac: Peer mac address + */ +void lim_send_peer_create_resp(struct mac_context *mac, uint8_t vdev_id, + QDF_STATUS status, uint8_t *peer_mac); + +/* + * lim_process_mlm_deauth_req() - This function is called to process + * MLM_DEAUTH_REQ message from SME + * + * @mac_ctx: Pointer to Global MAC structure + * @msg_buf: A pointer to the MLM message buffer + * + * This function is called to process MLM_DEAUTH_REQ message from SME + * + * @Return: None + */ +void lim_process_mlm_deauth_req(struct mac_context *mac_ctx, uint32_t *msg_buf); + +/** + * lim_sta_mlme_vdev_disconnect_bss() - Disconnect from BSS + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes BSS disconnection + * + * Return: SUCCESS on successful completion of disconnection + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_sta_mlme_vdev_disconnect_bss(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_process_assoc_cleanup() - frees up resources used in function + * lim_process_assoc_req_frame() + * @mac_ctx: pointer to Global MAC structure + * @session: pointer to pe session entry + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @sta_ds: station dph entry + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * + * Frees up resources used in function lim_process_assoc_req_frame + * + * Return: void + */ +void lim_process_assoc_cleanup(struct mac_context *mac_ctx, + struct pe_session *session, + tpSirAssocReq assoc_req, + tpDphHashNode sta_ds, + bool assoc_req_copied); + +/** + * lim_send_assoc_ind_to_sme() - Initialize PE data structures and send assoc + * indication to SME. + * @mac_ctx: Pointer to Global MAC structure + * @session: pe session entry + * @sub_type: Indicates whether it is Association Request(=0) or Reassociation + * Request(=1) frame + * @sa: Mac address of requesting peer + * @assoc_req: pointer to ASSOC/REASSOC Request frame + * @akm_type: AKM type + * @pmf_connection: flag indicating pmf connection + * @assoc_req_copied: boolean to indicate if assoc req was copied to tmp above + * @dup_entry: flag indicating if duplicate entry found + * @force_1x1: flag to indicate if the STA nss needs to be downgraded to 1x1 + * @partner_peer_idx: peer_idx which is already allocated by partner link + * + * Return: void + */ +bool lim_send_assoc_ind_to_sme(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t sub_type, + tSirMacAddr sa, + tpSirAssocReq assoc_req, + enum ani_akm_type akm_type, + bool pmf_connection, + bool *assoc_req_copied, + bool dup_entry, bool force_1x1, + uint16_t partner_peer_idx); + +/** + * lim_process_sta_add_bss_rsp_pre_assoc - Processes handoff request + * @mac_ctx: Pointer to mac context + * @pAddBssParams: Bss params including rsp data + * @session_entry: PE session handle + * @status: Qdf status + * + * This function is called to process a WMA_ADD_BSS_RSP from HAL. + * Upon receipt of this message from HAL if the state is pre assoc. + * + * Return: Null + */ +void lim_process_sta_add_bss_rsp_pre_assoc(struct mac_context *mac_ctx, + struct bss_params *add_bss_params, + struct pe_session *session_entry, + QDF_STATUS status); +#endif /* __LIM_TYPES_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c new file mode 100644 index 0000000000..2df60e7bd6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_utils.c @@ -0,0 +1,12381 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_utils.cc contains the utility functions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#include "sch_api.h" +#include "lim_utils.h" +#include "lim_types.h" +#include "lim_security_utils.h" +#include "lim_prop_exts_utils.h" +#include "lim_send_messages.h" +#include "lim_ser_des_utils.h" +#include "lim_admit_control.h" +#include "dot11f.h" +#include "dot11fdefs.h" +#include "wmm_apsd.h" +#include "lim_trace.h" +#include "wlan_vdev_mlme_api.h" +#include "../../core/src/vdev_mgr_ops.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "lim_session_utils.h" +#include "lim_ft_defs.h" +#include "lim_session.h" +#include "cds_reg_service.h" +#include "nan_datapath.h" +#include "wma.h" +#include "wlan_reg_services_api.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_ucfg_api.h" +#include "wma_pasn_peer_api.h" +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +#include "wma_he.h" +#endif +#include "wlan_utility.h" + +#include "wni_cfg.h" +#include "cfg_mlme_obss_ht40.h" +#include "cfg_ucfg_api.h" +#include "lim_ft.h" +#include "wlan_mlme_main.h" +#include "qdf_util.h" +#include "wlan_qct_sys.h" +#include +#include +#include +#include "wlan_mlme_ucfg_api.h" +#include "nan_ucfg_api.h" +#include "wlan_twt_ucfg_ext_cfg.h" +#ifdef WLAN_FEATURE_11BE +#include "wma_eht.h" +#endif +#ifdef WLAN_FEATURE_11BE_MLO +#include +#endif +#include "wlan_cmn_ieee80211.h" +#include +#include +#include "parser_api.h" +#include "wlan_mlo_mgr_link_switch.h" +#include "wlan_epcs_api.h" +#include "wlan_nan_api_i.h" + +/** ------------------------------------------------------------- + \fn lim_delete_dialogue_token_list + \brief deletes the complete lim dialogue token linked list. + \param struct mac_context * mac + \return None + -------------------------------------------------------------*/ +void lim_delete_dialogue_token_list(struct mac_context *mac) +{ + tpDialogueToken pCurrNode = mac->lim.pDialogueTokenHead; + + while (mac->lim.pDialogueTokenHead) { + pCurrNode = mac->lim.pDialogueTokenHead; + mac->lim.pDialogueTokenHead = + mac->lim.pDialogueTokenHead->next; + qdf_mem_free(pCurrNode); + pCurrNode = NULL; + } + mac->lim.pDialogueTokenTail = NULL; +} + +char *lim_mlm_state_str(tLimMlmStates state) +{ + switch (state) { + case eLIM_MLM_OFFLINE_STATE: + return "eLIM_MLM_OFFLINE_STATE"; + case eLIM_MLM_IDLE_STATE: + return "eLIM_MLM_IDLE_STATE"; + case eLIM_MLM_WT_JOIN_BEACON_STATE: + return "eLIM_MLM_WT_JOIN_BEACON_STATE"; + case eLIM_MLM_JOINED_STATE: + return "eLIM_MLM_JOINED_STATE"; + case eLIM_MLM_BSS_STARTED_STATE: + return "eLIM_MLM_BSS_STARTED_STATE"; + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + return "eLIM_MLM_WT_AUTH_FRAME2_STATE"; + case eLIM_MLM_WT_AUTH_FRAME3_STATE: + return "eLIM_MLM_WT_AUTH_FRAME3_STATE"; + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + return "eLIM_MLM_WT_AUTH_FRAME4_STATE"; + case eLIM_MLM_AUTH_RSP_TIMEOUT_STATE: + return "eLIM_MLM_AUTH_RSP_TIMEOUT_STATE"; + case eLIM_MLM_AUTHENTICATED_STATE: + return "eLIM_MLM_AUTHENTICATED_STATE"; + case eLIM_MLM_WT_ASSOC_RSP_STATE: + return "eLIM_MLM_WT_ASSOC_RSP_STATE"; + case eLIM_MLM_WT_REASSOC_RSP_STATE: + return "eLIM_MLM_WT_REASSOC_RSP_STATE"; + case eLIM_MLM_WT_FT_REASSOC_RSP_STATE: + return "eLIM_MLM_WT_FT_REASSOC_RSP_STATE"; + case eLIM_MLM_WT_DEL_STA_RSP_STATE: + return "eLIM_MLM_WT_DEL_STA_RSP_STATE"; + case eLIM_MLM_WT_DEL_BSS_RSP_STATE: + return "eLIM_MLM_WT_DEL_BSS_RSP_STATE"; + case eLIM_MLM_WT_ADD_STA_RSP_STATE: + return "eLIM_MLM_WT_ADD_STA_RSP_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_STATE"; + case eLIM_MLM_REASSOCIATED_STATE: + return "eLIM_MLM_REASSOCIATED_STATE"; + case eLIM_MLM_LINK_ESTABLISHED_STATE: + return "eLIM_MLM_LINK_ESTABLISHED_STATE"; + case eLIM_MLM_WT_ASSOC_CNF_STATE: + return "eLIM_MLM_WT_ASSOC_CNF_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE"; + case eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE: + return "eLIM_MLM_WT_ADD_BSS_RSP_FT_REASSOC_STATE"; + case eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE: + return "eLIM_MLM_WT_ASSOC_DEL_STA_RSP_STATE"; + case eLIM_MLM_WT_SET_BSS_KEY_STATE: + return "eLIM_MLM_WT_SET_BSS_KEY_STATE"; + case eLIM_MLM_WT_SET_STA_KEY_STATE: + return "eLIM_MLM_WT_SET_STA_KEY_STATE"; + default: + return "INVALID MLM state"; + } +} + +void +lim_print_mlm_state(struct mac_context *mac, uint16_t logLevel, tLimMlmStates state) +{ + pe_debug("Mlm state: %s", lim_mlm_state_str(state)); +} + +char *lim_sme_state_str(tLimSmeStates state) +{ + switch (state) { + case eLIM_SME_OFFLINE_STATE: + return "eLIM_SME_OFFLINE_STATE"; + case eLIM_SME_IDLE_STATE: + return "eLIM_SME_OFFLINE_STATE"; + case eLIM_SME_SUSPEND_STATE: + return "eLIM_SME_SUSPEND_STATE"; + case eLIM_SME_WT_JOIN_STATE: + return "eLIM_SME_WT_JOIN_STATE"; + case eLIM_SME_WT_AUTH_STATE: + return "eLIM_SME_WT_AUTH_STATE"; + case eLIM_SME_WT_ASSOC_STATE: + return "eLIM_SME_WT_ASSOC_STATE"; + case eLIM_SME_WT_REASSOC_STATE: + return "eLIM_SME_WT_REASSOC_STATE"; + case eLIM_SME_JOIN_FAILURE_STATE: + return "eLIM_SME_JOIN_FAILURE_STATE"; + case eLIM_SME_ASSOCIATED_STATE: + return "eLIM_SME_ASSOCIATED_STATE"; + case eLIM_SME_REASSOCIATED_STATE: + return "eLIM_SME_REASSOCIATED_STATE"; + case eLIM_SME_LINK_EST_STATE: + return "eLIM_SME_LINK_EST_STATE"; + case eLIM_SME_WT_PRE_AUTH_STATE: + return "eLIM_SME_WT_PRE_AUTH_STATE"; + case eLIM_SME_WT_DISASSOC_STATE: + return "eLIM_SME_WT_DISASSOC_STATE"; + case eLIM_SME_WT_DEAUTH_STATE: + return "eLIM_SME_WT_DEAUTH_STATE"; + case eLIM_SME_WT_START_BSS_STATE: + return "eLIM_SME_WT_START_BSS_STATE"; + case eLIM_SME_WT_STOP_BSS_STATE: + return "eLIM_SME_WT_STOP_BSS_STATE"; + case eLIM_SME_NORMAL_STATE: + return "eLIM_SME_NORMAL_STATE"; + default: + return "INVALID SME STATE"; + } +} + +void +lim_print_sme_state(struct mac_context *mac, uint16_t logLevel, tLimSmeStates state) +{ + pe_debug("SME state: %s", lim_sme_state_str(state)); +} + +char *lim_msg_str(uint32_t msgType) +{ + switch (msgType) { + case eWNI_SME_SYS_READY_IND: + return "eWNI_SME_SYS_READY_IND"; + case eWNI_SME_JOIN_REQ: + return "eWNI_SME_JOIN_REQ"; + case eWNI_SME_JOIN_RSP: + return "eWNI_SME_JOIN_RSP"; + case eWNI_SME_SETCONTEXT_RSP: + return "eWNI_SME_SETCONTEXT_RSP"; + case eWNI_SME_REASSOC_REQ: + return "eWNI_SME_REASSOC_REQ"; + case eWNI_SME_REASSOC_RSP: + return "eWNI_SME_REASSOC_RSP"; + case eWNI_SME_DISASSOC_REQ: + return "eWNI_SME_DISASSOC_REQ"; + case eWNI_SME_DISASSOC_RSP: + return "eWNI_SME_DISASSOC_RSP"; + case eWNI_SME_DISASSOC_IND: + return "eWNI_SME_DISASSOC_IND"; + case eWNI_SME_DISASSOC_CNF: + return "eWNI_SME_DISASSOC_CNF"; + case eWNI_SME_DEAUTH_REQ: + return "eWNI_SME_DEAUTH_REQ"; + case eWNI_SME_DEAUTH_RSP: + return "eWNI_SME_DEAUTH_RSP"; + case eWNI_SME_DEAUTH_IND: + return "eWNI_SME_DEAUTH_IND"; + case eWNI_SME_START_BSS_REQ: + return "eWNI_SME_START_BSS_REQ"; + case eWNI_SME_START_BSS_RSP: + return "eWNI_SME_START_BSS_RSP"; + case eWNI_SME_ASSOC_IND: + return "eWNI_SME_ASSOC_IND"; + case eWNI_SME_ASSOC_IND_UPPER_LAYER: + return "eWNI_SME_ASSOC_IND_UPPER_LAYER"; + case eWNI_SME_ASSOC_CNF: + return "eWNI_SME_ASSOC_CNF"; + case eWNI_SME_SWITCH_CHL_IND: + return "eWNI_SME_SWITCH_CHL_IND"; + case eWNI_SME_STOP_BSS_REQ: + return "eWNI_SME_STOP_BSS_REQ"; + case eWNI_SME_STOP_BSS_RSP: + return "eWNI_SME_STOP_BSS_RSP"; + case eWNI_SME_DEAUTH_CNF: + return "eWNI_SME_DEAUTH_CNF"; + case eWNI_SME_ADDTS_REQ: + return "eWNI_SME_ADDTS_REQ"; + case eWNI_SME_MSCS_REQ: + return "eWNI_SME_MSCS_REQ"; + case eWNI_SME_ADDTS_RSP: + return "eWNI_SME_ADDTS_RSP"; + case eWNI_SME_DELTS_REQ: + return "eWNI_SME_DELTS_REQ"; + case eWNI_SME_DELTS_RSP: + return "eWNI_SME_DELTS_RSP"; + case eWNI_SME_DELTS_IND: + return "eWNI_SME_DELTS_IND"; + case SIR_BB_XPORT_MGMT_MSG: + return "SIR_BB_XPORT_MGMT_MSG"; + case SIR_LIM_JOIN_FAIL_TIMEOUT: + return "SIR_LIM_JOIN_FAIL_TIMEOUT"; + case SIR_LIM_AUTH_FAIL_TIMEOUT: + return "SIR_LIM_AUTH_FAIL_TIMEOUT"; + case SIR_LIM_AUTH_RSP_TIMEOUT: + return "SIR_LIM_AUTH_RSP_TIMEOUT"; + case SIR_LIM_ASSOC_FAIL_TIMEOUT: + return "SIR_LIM_ASSOC_FAIL_TIMEOUT"; + case SIR_LIM_REASSOC_FAIL_TIMEOUT: + return "SIR_LIM_REASSOC_FAIL_TIMEOUT"; + case SIR_LIM_HEART_BEAT_TIMEOUT: + return "SIR_LIM_HEART_BEAT_TIMEOUT"; + case SIR_LIM_ADDTS_RSP_TIMEOUT: + return "SIR_LIM_ADDTS_RSP_TIMEOUT"; + case SIR_LIM_LINK_TEST_DURATION_TIMEOUT: + return "SIR_LIM_LINK_TEST_DURATION_TIMEOUT"; + case SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT: + return "SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT"; + case SIR_LIM_CNF_WAIT_TIMEOUT: + return "SIR_LIM_CNF_WAIT_TIMEOUT"; + case SIR_LIM_FT_PREAUTH_RSP_TIMEOUT: + return "SIR_LIM_FT_PREAUTH_RSP_TIMEOUT"; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_REQ: + return "eWNI_SME_GET_TSM_STATS_REQ"; + case eWNI_SME_GET_TSM_STATS_RSP: + return "eWNI_SME_GET_TSM_STATS_RSP"; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_SET_HW_MODE_REQ: + return "eWNI_SME_SET_HW_MODE_REQ"; + case eWNI_SME_SET_HW_MODE_RESP: + return "eWNI_SME_SET_HW_MODE_RESP"; + case eWNI_SME_HW_MODE_TRANS_IND: + return "eWNI_SME_HW_MODE_TRANS_IND"; + case SIR_LIM_PROCESS_DEFERRED_QUEUE: + return "SIR_LIM_PROCESS_DEFERRED_QUEUE"; + default: + return "Unknown"; + } +} + +char *lim_result_code_str(tSirResultCodes resultCode) +{ + switch (resultCode) { + case eSIR_SME_SUCCESS: + return "eSIR_SME_SUCCESS"; + case eSIR_LOGE_EXCEPTION: + return "eSIR_LOGE_EXCEPTION"; + case eSIR_SME_INVALID_PARAMETERS: + return "eSIR_SME_INVALID_PARAMETERS"; + case eSIR_SME_UNEXPECTED_REQ_RESULT_CODE: + return "eSIR_SME_UNEXPECTED_REQ_RESULT_CODE"; + case eSIR_SME_RESOURCES_UNAVAILABLE: + return "eSIR_SME_RESOURCES_UNAVAILABLE"; + case eSIR_SME_SCAN_FAILED: + return "eSIR_SME_SCAN_FAILED"; + case eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED: + return "eSIR_SME_BSS_ALREADY_STARTED_OR_JOINED"; + case eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE: + return "eSIR_SME_LOST_LINK_WITH_PEER_RESULT_CODE"; + case eSIR_SME_REFUSED: + return "eSIR_SME_REFUSED"; + case eSIR_SME_JOIN_TIMEOUT_RESULT_CODE: + return "eSIR_SME_JOIN_TIMEOUT_RESULT_CODE"; + case eSIR_SME_AUTH_TIMEOUT_RESULT_CODE: + return "eSIR_SME_AUTH_TIMEOUT_RESULT_CODE"; + case eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE: + return "eSIR_SME_ASSOC_TIMEOUT_RESULT_CODE"; + case eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE: + return "eSIR_SME_REASSOC_TIMEOUT_RESULT_CODE"; + case eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED: + return "eSIR_SME_MAX_NUM_OF_PRE_AUTH_REACHED"; + case eSIR_SME_AUTH_REFUSED: + return "eSIR_SME_AUTH_REFUSED"; + case eSIR_SME_INVALID_WEP_DEFAULT_KEY: + return "eSIR_SME_INVALID_WEP_DEFAULT_KEY"; + case eSIR_SME_ASSOC_REFUSED: + return "eSIR_SME_ASSOC_REFUSED"; + case eSIR_SME_REASSOC_REFUSED: + return "eSIR_SME_REASSOC_REFUSED"; + case eSIR_SME_STA_NOT_AUTHENTICATED: + return "eSIR_SME_STA_NOT_AUTHENTICATED"; + case eSIR_SME_STA_NOT_ASSOCIATED: + return "eSIR_SME_STA_NOT_ASSOCIATED"; + case eSIR_SME_ALREADY_JOINED_A_BSS: + return "eSIR_SME_ALREADY_JOINED_A_BSS"; + case eSIR_SME_MORE_SCAN_RESULTS_FOLLOW: + return "eSIR_SME_MORE_SCAN_RESULTS_FOLLOW"; + case eSIR_SME_INVALID_ASSOC_RSP_RXED: + return "eSIR_SME_INVALID_ASSOC_RSP_RXED"; + case eSIR_SME_MIC_COUNTER_MEASURES: + return "eSIR_SME_MIC_COUNTER_MEASURES"; + case eSIR_SME_ADDTS_RSP_TIMEOUT: + return "eSIR_SME_ADDTS_RSP_TIMEOUT"; + case eSIR_SME_CHANNEL_SWITCH_FAIL: + return "eSIR_SME_CHANNEL_SWITCH_FAIL"; + case eSIR_SME_HAL_SCAN_INIT_FAILED: + return "eSIR_SME_HAL_SCAN_INIT_FAILED"; + case eSIR_SME_HAL_SCAN_END_FAILED: + return "eSIR_SME_HAL_SCAN_END_FAILED"; + case eSIR_SME_HAL_SCAN_FINISH_FAILED: + return "eSIR_SME_HAL_SCAN_FINISH_FAILED"; + case eSIR_SME_HAL_SEND_MESSAGE_FAIL: + return "eSIR_SME_HAL_SEND_MESSAGE_FAIL"; + + default: + return "Unknown resultCode"; + } +} + +void lim_print_msg_name(struct mac_context *mac, uint16_t logLevel, uint32_t msgType) +{ + pe_debug("Msg: %s", lim_msg_str(msgType)); +} + +/** + * lim_init_mlm() - This function is called by limProcessSmeMessages() to + * initialize MLM state machine on STA + * @mac: Pointer to Global MAC structure + * + * @Return: Status of operation + */ +QDF_STATUS lim_init_mlm(struct mac_context *mac) +{ + uint32_t retVal; + + mac->lim.gLimTimersCreated = 0; + + MTRACE(mac_trace(mac, TRACE_CODE_MLM_STATE, NO_SESSION, + mac->lim.gLimMlmState)); + + /* Initialize number of pre-auth contexts */ + mac->lim.gLimNumPreAuthContexts = 0; + + /* Initialize MAC based Authentication STA list */ + lim_init_pre_auth_list(mac); + + /* Create timers used by LIM */ + retVal = lim_create_timers(mac); + if (retVal != TX_SUCCESS) { + pe_err("lim_create_timers Failed"); + return QDF_STATUS_SUCCESS; + } + + mac->lim.gLimTimersCreated = 1; + return QDF_STATUS_SUCCESS; +} /*** end lim_init_mlm() ***/ + +void lim_deactivate_timers(struct mac_context *mac_ctx) +{ + uint32_t n; + tLimTimers *lim_timer = &mac_ctx->lim.lim_timers; + + lim_deactivate_timers_host_roam(mac_ctx); + + /* Deactivate addts response timer. */ + tx_timer_deactivate(&lim_timer->gLimAddtsRspTimer); + + if (tx_timer_running(&lim_timer->gLimJoinFailureTimer)) { + pe_err("Join failure timer running call the timeout API"); + /* Cleanup as if join timer expired */ + lim_timer_handler(mac_ctx, SIR_LIM_JOIN_FAIL_TIMEOUT); + } + /* Deactivate Join failure timer. */ + tx_timer_deactivate(&lim_timer->gLimJoinFailureTimer); + + /* Deactivate Periodic Join Probe Request timer. */ + tx_timer_deactivate(&lim_timer->gLimPeriodicJoinProbeReqTimer); + + /* Deactivate Auth Retry timer. */ + tx_timer_deactivate + (&lim_timer->g_lim_periodic_auth_retry_timer); + + if (tx_timer_running(&lim_timer->gLimAssocFailureTimer)) { + pe_err("Assoc failure timer running call the timeout API"); + /* Cleanup as if assoc timer expired */ + lim_assoc_failure_timer_handler(mac_ctx, LIM_ASSOC); + } + /* Deactivate Association failure timer. */ + tx_timer_deactivate(&lim_timer->gLimAssocFailureTimer); + + if (tx_timer_running(&mac_ctx->lim.lim_timers.gLimAuthFailureTimer)) { + pe_err("Auth failure timer running call the timeout API"); + /* Cleanup as if auth timer expired */ + lim_timer_handler(mac_ctx, SIR_LIM_AUTH_FAIL_TIMEOUT); + } + /* Deactivate Authentication failure timer. */ + tx_timer_deactivate(&lim_timer->gLimAuthFailureTimer); + + /* Deactivate cnf wait timer */ + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + tx_timer_deactivate(&lim_timer->gpLimCnfWaitTimer[n]); + } + + /* Deactivate any Authentication response timers */ + lim_delete_pre_auth_list(mac_ctx); + + tx_timer_deactivate(&lim_timer->gLimUpdateOlbcCacheTimer); + tx_timer_deactivate(&lim_timer->gLimPreAuthClnupTimer); + + if (tx_timer_running(&lim_timer->gLimDisassocAckTimer)) { + pe_err("Disassoc timer running call the timeout API"); + lim_timer_handler(mac_ctx, SIR_LIM_DISASSOC_ACK_TIMEOUT); + } + tx_timer_deactivate(&lim_timer->gLimDisassocAckTimer); + + if (tx_timer_running(&lim_timer->gLimDeauthAckTimer)) { + pe_err("Deauth timer running call the timeout API"); + lim_process_deauth_ack_timeout(mac_ctx, WLAN_INVALID_VDEV_ID); + } + tx_timer_deactivate(&lim_timer->gLimDeauthAckTimer); + + if (tx_timer_running(&lim_timer->sae_auth_timer)) { + pe_err("SAE Auth failure timer running call the timeout API"); + /* Cleanup as if SAE auth timer expired */ + lim_timer_handler(mac_ctx, SIR_LIM_AUTH_SAE_TIMEOUT); + } + tx_timer_deactivate(&lim_timer->sae_auth_timer); + + if (tx_timer_running(&lim_timer->rrm_sta_stats_resp_timer)) { + pe_err("sta stats resp timer running call the timeout API"); + lim_timer_handler(mac_ctx, SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT); + } + tx_timer_deactivate(&lim_timer->rrm_sta_stats_resp_timer); +} + +void lim_deactivate_timers_for_vdev(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + tLimTimers *lim_timer = &mac_ctx->lim.lim_timers; + struct pe_session *pe_session; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!pe_session) { + pe_err("pe session invalid for vdev %d", vdev_id); + return; + } + pe_debug("pe limMlmState %s vdev %d", + lim_mlm_state_str(pe_session->limMlmState), + vdev_id); + switch (pe_session->limMlmState) { + case eLIM_MLM_WT_JOIN_BEACON_STATE: + if (tx_timer_running( + &lim_timer->gLimJoinFailureTimer)) { + pe_debug("Trigger Join failure timeout for vdev %d", + vdev_id); + tx_timer_deactivate( + &lim_timer->gLimJoinFailureTimer); + lim_process_join_failure_timeout(mac_ctx); + } + break; + case eLIM_MLM_WT_AUTH_FRAME2_STATE: + case eLIM_MLM_WT_AUTH_FRAME4_STATE: + if (tx_timer_running( + &lim_timer->gLimAuthFailureTimer)) { + pe_debug("Trigger Auth failure timeout for vdev %d", + vdev_id); + tx_timer_deactivate( + &lim_timer->gLimAuthFailureTimer); + lim_process_auth_failure_timeout(mac_ctx); + } + break; + case eLIM_MLM_WT_ASSOC_RSP_STATE: + if (tx_timer_running( + &lim_timer->gLimAssocFailureTimer)) { + pe_debug("Trigger Assoc failure timeout for vdev %d", + vdev_id); + tx_timer_deactivate( + &lim_timer->gLimAssocFailureTimer); + lim_process_assoc_failure_timeout(mac_ctx, + LIM_ASSOC); + } + break; + case eLIM_MLM_WT_SAE_AUTH_STATE: + if (tx_timer_running(&lim_timer->sae_auth_timer)) { + pe_debug("Trigger SAE Auth failure timeout for vdev %d", + vdev_id); + tx_timer_deactivate( + &lim_timer->sae_auth_timer); + lim_process_sae_auth_timeout(mac_ctx); + } + break; + case eLIM_MLM_LINK_ESTABLISHED_STATE: + if (!pe_session->ftPEContext.ftPreAuthSession) + break; + + pe_debug("pre-auth in progress"); + if (tx_timer_running(&lim_timer->gLimFTPreAuthRspTimer)) { + pe_debug("Trigger pre auth timeout for vdev %d", + vdev_id); + tx_timer_deactivate( + &lim_timer->gLimFTPreAuthRspTimer); + } + lim_process_ft_preauth_rsp_timeout(mac_ctx); + break; + default: + return; + } +} + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +QDF_STATUS +lim_process_pasn_delete_all_peers(struct mac_context *mac, + struct pasn_peer_delete_msg *msg) +{ + struct wlan_objmgr_vdev *vdev; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + + if (!wma) + return QDF_STATUS_E_INVAL; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, msg->vdev_id, + WLAN_WIFI_POS_CORE_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + status = wma_delete_all_pasn_peers(wma, vdev); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Failed to delete all PASN peers for vdev:%d", + msg->vdev_id); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_WIFI_POS_CORE_ID); + + return status; +} +#endif + +/** + * lim_cleanup_mlm() - This function is called to cleanup + * @mac_ctx: Pointer to Global MAC structure + * + * Function is called to cleanup any resources allocated by the MLM + * state machine. + * + * Return: none + */ +void lim_cleanup_mlm(struct mac_context *mac_ctx) +{ + uint32_t n; + + tLimPreAuthNode **pAuthNode; + tLimTimers *lim_timer = NULL; + + if (mac_ctx->lim.gLimTimersCreated == 1) { + lim_timer = &mac_ctx->lim.lim_timers; + + lim_deactivate_timers(mac_ctx); + + lim_delete_timers_host_roam(mac_ctx); + + /* Delete addts response timer. */ + tx_timer_delete(&lim_timer->gLimAddtsRspTimer); + + /* Delete Join failure timer. */ + tx_timer_delete(&lim_timer->gLimJoinFailureTimer); + + /* Delete Periodic Join Probe Request timer. */ + tx_timer_delete(&lim_timer->gLimPeriodicJoinProbeReqTimer); + + /* Delete Auth Retry timer. */ + tx_timer_delete(&lim_timer->g_lim_periodic_auth_retry_timer); + + /* Delete Association failure timer. */ + tx_timer_delete(&lim_timer->gLimAssocFailureTimer); + + /* Delete Authentication failure timer. */ + tx_timer_delete(&lim_timer->gLimAuthFailureTimer); + + /* Delete cnf wait timer */ + for (n = 0; n < (mac_ctx->lim.maxStation + 1); n++) { + tx_timer_delete(&lim_timer->gpLimCnfWaitTimer[n]); + } + + pAuthNode = mac_ctx->lim.gLimPreAuthTimerTable.pTable; + + /* Delete any Auth rsp timers, which might have been started */ + for (n = 0; n < mac_ctx->lim.gLimPreAuthTimerTable.numEntry; + n++) + tx_timer_delete(&pAuthNode[n]->timer); + + tx_timer_delete(&lim_timer->gLimUpdateOlbcCacheTimer); + tx_timer_delete(&lim_timer->gLimPreAuthClnupTimer); + + tx_timer_delete(&lim_timer->gLimDisassocAckTimer); + + tx_timer_delete(&lim_timer->gLimDeauthAckTimer); + + tx_timer_delete(&lim_timer->sae_auth_timer); + tx_timer_delete(&lim_timer->rrm_sta_stats_resp_timer); + + mac_ctx->lim.gLimTimersCreated = 0; + } +} /*** end lim_cleanup_mlm() ***/ + +/* + * lim_reset_deferred_msg_q() + * + ***FUNCTION: + * This function resets the deferred message queue parameters. + * + ***PARAMS: + * @param mac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + ***RETURNS: + * None + */ + +void lim_reset_deferred_msg_q(struct mac_context *mac) +{ + struct scheduler_msg *read_msg = {0}; + + if (mac->lim.gLimDeferredMsgQ.size > 0) { + while ((read_msg = lim_read_deferred_msg_q(mac)) != NULL) { + pe_free_msg(mac, read_msg); + } + } + + mac->lim.gLimDeferredMsgQ.size = + mac->lim.gLimDeferredMsgQ.write = + mac->lim.gLimDeferredMsgQ.read = 0; + +} + +#define LIM_DEFERRED_Q_CHECK_THRESHOLD (MAX_DEFERRED_QUEUE_LEN/2) +#define LIM_MAX_NUM_MGMT_FRAME_DEFERRED (MAX_DEFERRED_QUEUE_LEN/2) + +/** + * lim_write_deferred_msg_q() - This function queues up a deferred message + * + * @mac_ctx: Pointer to Global MAC structure + * @lim_msg: a LIM message + * + * Function queues up a deferred message for later processing on the + * STA side. + * + * Return: none + */ + +uint8_t lim_write_deferred_msg_q(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg) +{ + uint8_t type = 0, subtype = 0; + + pe_debug("Queue a deferred message size: %d write: %d - type: 0x%x", + mac_ctx->lim.gLimDeferredMsgQ.size, + mac_ctx->lim.gLimDeferredMsgQ.write, + lim_msg->type); + + /* check if the deferred message queue is full */ + if (mac_ctx->lim.gLimDeferredMsgQ.size >= MAX_DEFERRED_QUEUE_LEN) { + if (!(mac_ctx->lim.deferredMsgCnt & 0xF)) { + pe_err("queue->MsgQ full Msg: %d Msgs Failed: %d", + lim_msg->type, + ++mac_ctx->lim.deferredMsgCnt); + cds_flush_logs(WLAN_LOG_TYPE_NON_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_QUEUE_FULL, + false, false); + } else { + mac_ctx->lim.deferredMsgCnt++; + } + return TX_QUEUE_FULL; + } + + /* + * In the application, there should not be more than 1 message get + * queued up. If happens, flags a warning. In the future, this can + * happen. + */ + if (mac_ctx->lim.gLimDeferredMsgQ.size > 0) + pe_debug("%d Deferred Msg type: 0x%x global sme: %d global mlme: %d addts: %d", + mac_ctx->lim.gLimDeferredMsgQ.size, + lim_msg->type, + mac_ctx->lim.gLimSmeState, + mac_ctx->lim.gLimMlmState, + mac_ctx->lim.gLimAddtsSent); + + if (SIR_BB_XPORT_MGMT_MSG == lim_msg->type) { + lim_util_get_type_subtype(lim_msg->bodyptr, + &type, &subtype); + pe_debug(" Deferred management type %d subtype %d ", + type, subtype); + } + + /* + * To prevent the deferred Q is full of management frames, only give + * them certain space + */ + if ((SIR_BB_XPORT_MGMT_MSG == lim_msg->type) && + (LIM_DEFERRED_Q_CHECK_THRESHOLD < + mac_ctx->lim.gLimDeferredMsgQ.size)) { + uint16_t idx, count = 0; + + for (idx = 0; idx < mac_ctx->lim.gLimDeferredMsgQ.size; + idx++) { + if (SIR_BB_XPORT_MGMT_MSG == + mac_ctx->lim.gLimDeferredMsgQ. + deferredQueue[idx].type) { + count++; + } + } + if (LIM_MAX_NUM_MGMT_FRAME_DEFERRED < count) { + /* + * We reach the quota for management frames, + * drop this one + */ + pe_warn_rl("Too many queue->MsgQ Msg: %d count: %d", + lim_msg->type, count); + /* Return error, caller knows what to do */ + return TX_QUEUE_FULL; + } + } + + ++mac_ctx->lim.gLimDeferredMsgQ.size; + + /* reset the count here since we are able to defer the message */ + if (mac_ctx->lim.deferredMsgCnt != 0) + mac_ctx->lim.deferredMsgCnt = 0; + + /* if the write pointer hits the end of the queue, rewind it */ + if (mac_ctx->lim.gLimDeferredMsgQ.write >= MAX_DEFERRED_QUEUE_LEN) + mac_ctx->lim.gLimDeferredMsgQ.write = 0; + + /* save the message to the queue and advanced the write pointer */ + qdf_mem_copy((uint8_t *) &mac_ctx->lim.gLimDeferredMsgQ. + deferredQueue[mac_ctx->lim.gLimDeferredMsgQ.write++], + (uint8_t *) lim_msg, + sizeof(struct scheduler_msg)); + return TX_SUCCESS; + +} + +/* + * lim_read_deferred_msg_q() + * + ***FUNCTION: + * This function dequeues a deferred message for processing on the + * STA side. + * + ***PARAMS: + * @param mac - Pointer to Global MAC structure + * + ***LOGIC: + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * + ***RETURNS: + * Returns the message at the head of the deferred message queue + */ + +struct scheduler_msg *lim_read_deferred_msg_q(struct mac_context *mac) +{ + struct scheduler_msg *msg = {0}; + + /* + ** check any messages left. If no, return + **/ + if (mac->lim.gLimDeferredMsgQ.size <= 0) + return NULL; + + /* + ** decrement the queue size + **/ + mac->lim.gLimDeferredMsgQ.size--; + + /* + ** retrieve the message from the head of the queue + **/ + msg = + &mac->lim.gLimDeferredMsgQ.deferredQueue[mac->lim. + gLimDeferredMsgQ.read]; + + /* + ** advance the read pointer + **/ + mac->lim.gLimDeferredMsgQ.read++; + + /* + ** if the read pointer hits the end of the queue, rewind it + **/ + if (mac->lim.gLimDeferredMsgQ.read >= MAX_DEFERRED_QUEUE_LEN) + mac->lim.gLimDeferredMsgQ.read = 0; + + pe_debug("DeQueue a deferred message size: %d read: %d - type: 0x%x", + mac->lim.gLimDeferredMsgQ.size, + mac->lim.gLimDeferredMsgQ.read, msg->type); + + pe_debug("DQ msg -- global sme: %d global mlme: %d addts: %d", + mac->lim.gLimSmeState, mac->lim.gLimMlmState, + mac->lim.gLimAddtsSent); + + return msg; +} + +/* + * lim_handle_update_olbc_cache() - This function update olbc cache + * + * @mac_ctx: Pointer to Global MAC structure + * + * Function updates olbc cache + * + * Return: none + */ +void lim_handle_update_olbc_cache(struct mac_context *mac_ctx) +{ + int i; + static int enable; + tUpdateBeaconParams beaconParams; + + struct pe_session *pe_session = lim_is_ap_session_active(mac_ctx); + + if (!pe_session) { + pe_debug(" Session not found"); + return; + } + + if (pe_session->is_session_obss_offload_enabled) { + pe_debug("protection offloaded"); + return; + } + qdf_mem_zero((uint8_t *) &beaconParams, sizeof(tUpdateBeaconParams)); + beaconParams.bss_idx = pe_session->vdev_id; + + beaconParams.paramChangeBitmap = 0; + /* + * This is doing a 2 pass check. The first pass is to invalidate + * all the cache entries. The second pass is to decide whether to + * disable protection. + */ + if (!enable) { + pe_debug("Resetting OLBC cache"); + pe_session->gLimOlbcParams.numSta = 0; + pe_session->gLimOverlap11gParams.numSta = 0; + pe_session->gLimOverlapHt20Params.numSta = 0; + pe_session->gLimNonGfParams.numSta = 0; + pe_session->gLimLsigTxopParams.numSta = 0; + + for (i = 0; i < LIM_PROT_STA_OVERLAP_CACHE_SIZE; i++) + mac_ctx->lim.protStaOverlapCache[i].active = false; + + enable = 1; + } else { + if ((!pe_session->gLimOlbcParams.numSta) && + (pe_session->gLimOlbcParams.protectionEnabled) && + (!pe_session->gLim11bParams.protectionEnabled)) { + pe_debug("Overlap cache clear and no 11B STA set"); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + pe_session); + } + + if ((!pe_session->gLimOverlap11gParams.numSta) && + (pe_session->gLimOverlap11gParams.protectionEnabled) + && (!pe_session->gLim11gParams.protectionEnabled)) { + pe_debug("Overlap cache clear and no 11G STA set"); + lim_enable_ht_protection_from11g(mac_ctx, false, true, + &beaconParams, + pe_session); + } + + if ((!pe_session->gLimOverlapHt20Params.numSta) && + (pe_session->gLimOverlapHt20Params.protectionEnabled) + && (!pe_session->gLimHt20Params.protectionEnabled)) { + pe_debug("Overlap cache clear and no HT20 STA set"); + lim_enable11g_protection(mac_ctx, false, true, + &beaconParams, + pe_session); + } + + enable = 0; + } + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + sch_set_fixed_beacon_fields(mac_ctx, pe_session); + lim_send_beacon_params(mac_ctx, &beaconParams, pe_session); + } + /* Start OLBC timer */ + if (tx_timer_activate(&mac_ctx->lim.lim_timers.gLimUpdateOlbcCacheTimer) + != TX_SUCCESS) + pe_err("tx_timer_activate failed"); +} + +/** + * lim_is_null_ssid() - This function checks if ssid supplied is Null SSID + * @ssid: pointer to tSirMacSSid + * + * Function checks if ssid supplied is Null SSID + * + * Return: none + */ + +uint8_t lim_is_null_ssid(tSirMacSSid *ssid) +{ + uint8_t fnull_ssid = false; + uint32_t ssid_len; + uint8_t *ssid_str; + + if (0 == ssid->length) { + fnull_ssid = true; + return fnull_ssid; + } + /* If the first characters is space, then check if all + * characters in SSID are spaces to consider it as NULL SSID + */ + if ((ASCII_SPACE_CHARACTER == ssid->ssId[0]) && + (ssid->length == 1)) { + fnull_ssid = true; + return fnull_ssid; + } else { + /* check if all the characters in SSID are NULL */ + ssid_len = ssid->length; + ssid_str = ssid->ssId; + + while (ssid_len) { + if (*ssid_str) + return fnull_ssid; + + ssid_str++; + ssid_len--; + } + + if (0 == ssid_len) { + fnull_ssid = true; + return fnull_ssid; + } + } + + return fnull_ssid; +} + +/** ------------------------------------------------------------- + \fn lim_update_prot_sta_params + \brief updates protection related counters. + \param struct mac_context * mac + \param tSirMacAddr peerMacAddr + \param tLimProtStaCacheType protStaCacheType + \param tHalBitVal gfSupported + \param tHalBitVal lsigTxopSupported + \return None + -------------------------------------------------------------*/ +static void +lim_update_prot_sta_params(struct mac_context *mac, + tSirMacAddr peerMacAddr, + tLimProtStaCacheType protStaCacheType, + tHalBitVal gfSupported, tHalBitVal lsigTxopSupported, + struct pe_session *pe_session) +{ + uint32_t i; + + pe_debug("Associated STA addr is: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peerMacAddr)); + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (pe_session->protStaCache[i].active) { + pe_debug("Addr:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pe_session->protStaCache[i].addr)); + + if (!qdf_mem_cmp + (pe_session->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr))) { + pe_debug("matching cache entry at: %d already active", + i); + return; + } + } + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (!pe_session->protStaCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + pe_err("No space in ProtStaCache"); + return; + } + + qdf_mem_copy(pe_session->protStaCache[i].addr, + peerMacAddr, sizeof(tSirMacAddr)); + + pe_session->protStaCache[i].protStaCacheType = protStaCacheType; + pe_session->protStaCache[i].active = true; + if (eLIM_PROT_STA_CACHE_TYPE_llB == protStaCacheType) { + pe_session->gLim11bParams.numSta++; + pe_debug("11B,"); + } else if (eLIM_PROT_STA_CACHE_TYPE_llG == protStaCacheType) { + pe_session->gLim11gParams.numSta++; + pe_debug("11G,"); + } else if (eLIM_PROT_STA_CACHE_TYPE_HT20 == protStaCacheType) { + pe_session->gLimHt20Params.numSta++; + pe_debug("HT20,"); + } + + if (!gfSupported) { + pe_session->gLimNonGfParams.numSta++; + pe_debug("NonGf,"); + } + if (!lsigTxopSupported) { + pe_session->gLimLsigTxopParams.numSta++; + pe_debug("!lsigTxopSupported"); + } +} /* --------------------------------------------------------------------- */ + +/** ------------------------------------------------------------- + \fn lim_decide_ap_protection + \brief Decides all the protection related staiton coexistence and also sets + \ short preamble and short slot appropriately. This function will be called + \ when AP is ready to send assocRsp tp the station joining right now. + \param struct mac_context * mac + \param tSirMacAddr peerMacAddr + \return None + -------------------------------------------------------------*/ +void +lim_decide_ap_protection(struct mac_context *mac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + uint16_t tmpAid; + tpDphHashNode sta; + enum reg_wifi_band rfBand = REG_BAND_UNKNOWN; + uint32_t phyMode; + tLimProtStaCacheType protStaCacheType = + eLIM_PROT_STA_CACHE_TYPE_INVALID; + tHalBitVal gfSupported = eHAL_SET, lsigTxopSupported = eHAL_SET; + + pBeaconParams->paramChangeBitmap = 0; + /* check whether to enable protection or not */ + sta = + dph_lookup_hash_entry(mac, peerMacAddr, &tmpAid, + &pe_session->dph.dphHashTable); + if (!sta) + return; + lim_get_rf_band_new(mac, &rfBand, pe_session); + /* if we are in 5 GHZ band */ + if (REG_BAND_5G == rfBand) { + /* We are 11N. we need to protect from 11A and Ht20. we don't need any other protection in 5 GHZ. */ + /* HT20 case is common between both the bands and handled down as common code. */ + if (true == pe_session->htCapability) { + /* we are 11N and 11A station is joining. */ + /* protection from 11A required. */ + if (false == sta->mlmStaContext.htCapability) { + lim_update_11a_protection(mac, true, false, + pBeaconParams, + pe_session); + return; + } + } + } else if (REG_BAND_2G == rfBand) { + lim_get_phy_mode(mac, &phyMode, pe_session); + + /* We are 11G. Check if we need protection from 11b Stations. */ + if ((phyMode == WNI_CFG_PHY_MODE_11G) && + (false == pe_session->htCapability)) { + + if (sta->erpEnabled == eHAL_CLEAR) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + pe_debug("Enabling protection from 11B"); + lim_enable11g_protection(mac, true, false, + pBeaconParams, + pe_session); + } + } + /* HT station. */ + if (true == pe_session->htCapability) { + /* check if we need protection from 11b station */ + if ((sta->erpEnabled == eHAL_CLEAR) && + (!sta->mlmStaContext.htCapability)) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llB; + /* enable protection */ + pe_debug("Enabling protection from 11B"); + lim_enable11g_protection(mac, true, false, + pBeaconParams, + pe_session); + } + /* station being joined is non-11b and non-ht ==> 11g device */ + else if (!sta->mlmStaContext.htCapability) { + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_llG; + /* enable protection */ + lim_enable_ht_protection_from11g(mac, true, false, + pBeaconParams, + pe_session); + } + /* ERP mode is enabled for the latest station joined */ + /* latest station joined is HT capable */ + /* This case is being handled in common code (commn between both the bands) below. */ + } + } + /* we are HT and HT station is joining. This code is common for both the bands. */ + if ((true == pe_session->htCapability) && + (true == sta->mlmStaContext.htCapability)) { + if (!sta->htGreenfield) { + lim_enable_ht_non_gf_protection(mac, true, false, + pBeaconParams, + pe_session); + gfSupported = eHAL_CLEAR; + } + /* Station joining is HT 20Mhz */ + if ((eHT_CHANNEL_WIDTH_20MHZ == + sta->htSupportedChannelWidthSet) && + (eHT_CHANNEL_WIDTH_20MHZ != + pe_session->htSupportedChannelWidthSet)){ + protStaCacheType = eLIM_PROT_STA_CACHE_TYPE_HT20; + lim_enable_ht20_protection(mac, true, false, + pBeaconParams, pe_session); + } + /* Station joining does not support LSIG TXOP Protection */ + if (!sta->htLsigTXOPProtection) { + lim_enable_ht_lsig_txop_protection(mac, false, false, + pBeaconParams, + pe_session); + lsigTxopSupported = eHAL_CLEAR; + } + } + + lim_update_prot_sta_params(mac, peerMacAddr, protStaCacheType, + gfSupported, lsigTxopSupported, pe_session); + + return; +} + +/** ------------------------------------------------------------- + \fn lim_enable_overlap11g_protection + \brief wrapper function for setting overlap 11g protection. + \param struct mac_context * mac + \param tpUpdateBeaconParams pBeaconParams + \param tpSirMacMgmtHdr pMh + \return None + -------------------------------------------------------------*/ +void +lim_enable_overlap11g_protection(struct mac_context *mac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, struct pe_session *pe_session) +{ + lim_update_overlap_sta_param(mac, pMh->bssId, + &(pe_session->gLimOlbcParams)); + + if (pe_session->gLimOlbcParams.numSta && + !pe_session->gLimOlbcParams.protectionEnabled) { + /* enable protection */ + pe_debug("OLBC happens!!!"); + lim_enable11g_protection(mac, true, true, pBeaconParams, + pe_session); + } +} + +/** + * lim_update_short_preamble() - This function Updates short preamble + * @mac_ctx: pointer to Global MAC structure + * @peer_mac_addr: pointer to tSirMacAddr + * @pbeaconparams: pointer to tpUpdateBeaconParams + * @psession_entry: pointer to struct pe_session * + * + * Function Updates short preamble if needed when a new station joins + * + * Return: none + */ +void +lim_update_short_preamble(struct mac_context *mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beaconparams, + struct pe_session *psession_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + uint32_t phy_mode; + uint16_t i; + + /* check whether to enable protection or not */ + sta_ds = + dph_lookup_hash_entry(mac_ctx, peer_mac_addr, &aid, + &psession_entry->dph.dphHashTable); + + lim_get_phy_mode(mac_ctx, &phy_mode, psession_entry); + + if (!sta_ds || phy_mode != WNI_CFG_PHY_MODE_11G) + return; + + if (sta_ds->shortPreambleEnabled != eHAL_CLEAR) + return; + + pe_debug("Short Preamble is not enabled in Assoc Req from "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac_addr)); + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(psession_entry) && + (psession_entry->gLimNoShortParams. + staNoShortCache[i].active) && + (!qdf_mem_cmp + (psession_entry->gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)))) + return; + else if (!LIM_IS_AP_ROLE(psession_entry) && + (mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].active) && + (!qdf_mem_cmp(mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, + sizeof(tSirMacAddr)))) + return; + } + + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(psession_entry) && + !psession_entry->gLimNoShortParams. + staNoShortCache[i].active) + break; + else if (!mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + tLimNoShortParams *lim_params = + &psession_entry->gLimNoShortParams; + if (LIM_IS_AP_ROLE(psession_entry)) { + pe_err("No space in Short cache active: %d sta: %d for sta "QDF_MAC_ADDR_FMT, + i, lim_params->numNonShortPreambleSta, + QDF_MAC_ADDR_REF(peer_mac_addr)); + return; + } else { + pe_err("No space in Short cache active: %d sta: %d for sta "QDF_MAC_ADDR_FMT, + i, lim_params->numNonShortPreambleSta, + QDF_MAC_ADDR_REF(peer_mac_addr)); + return; + } + + } + + if (LIM_IS_AP_ROLE(psession_entry)) { + qdf_mem_copy(psession_entry->gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + psession_entry->gLimNoShortParams.staNoShortCache[i]. + active = true; + psession_entry->gLimNoShortParams.numNonShortPreambleSta++; + } else { + qdf_mem_copy(mac_ctx->lim.gLimNoShortParams. + staNoShortCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + mac_ctx->lim.gLimNoShortParams.staNoShortCache[i].active = true; + mac_ctx->lim.gLimNoShortParams.numNonShortPreambleSta++; + } + + /* enable long preamble */ + pe_debug("Disabling short preamble"); + + if (lim_enable_short_preamble(mac_ctx, false, beaconparams, + psession_entry) != QDF_STATUS_SUCCESS) + pe_err("Cannot enable long preamble"); +} + +/** + * lim_update_short_slot_time() - This function Updates short slot time + * @mac_ctx: pointer to Global MAC structure + * @peer_mac_addr: pointer to tSirMacAddr + * @beacon_params: pointer to tpUpdateBeaconParams + * @psession_entry: pointer to struct pe_session * + * + * Function Updates short slot time if needed when a new station joins + * + * Return: None + */ +void +lim_update_short_slot_time(struct mac_context *mac_ctx, tSirMacAddr peer_mac_addr, + tpUpdateBeaconParams beacon_params, + struct pe_session *session_entry) +{ + uint16_t aid; + tpDphHashNode sta_ds; + uint32_t phy_mode; + uint32_t val; + uint16_t i; + + /* check whether to enable protection or not */ + sta_ds = dph_lookup_hash_entry(mac_ctx, peer_mac_addr, &aid, + &session_entry->dph.dphHashTable); + lim_get_phy_mode(mac_ctx, &phy_mode, session_entry); + + if (!sta_ds || phy_mode != WNI_CFG_PHY_MODE_11G) + return; + + /* + * Only in case of softap in 11g mode, slot time might change + * depending on the STA being added. In 11a case, it should + * be always 1 and in 11b case, it should be always 0. + * Only when the new STA has short slot time disabled, we need to + * change softap's overall slot time settings else the default for + * softap is always short slot enabled. When the last long slot STA + * leaves softAP, we take care of it in lim_decide_short_slot + */ + if (sta_ds->shortSlotTimeEnabled != eHAL_CLEAR) + return; + + pe_debug("Short Slot Time is not enabled in Assoc Req from "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac_addr)); + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(session_entry) && + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active) { + if (!qdf_mem_cmp(session_entry-> + gLimNoShortSlotParams.staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr))) + return; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active) { + if (!qdf_mem_cmp(mac_ctx-> + lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr))) + return; + } + } + } + for (i = 0; i < LIM_PROT_STA_CACHE_SIZE; i++) { + if (LIM_IS_AP_ROLE(session_entry) && + !session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active) + break; + else + if (!mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active) + break; + } + + if (i >= LIM_PROT_STA_CACHE_SIZE) { + if (LIM_IS_AP_ROLE(session_entry)) { + pe_err("No space in ShortSlot cache active: %d sta: %d for sta "QDF_MAC_ADDR_FMT, + i, session_entry->gLimNoShortSlotParams.numNonShortSlotSta, + QDF_MAC_ADDR_REF(peer_mac_addr)); + return; + } else { + pe_err("No space in ShortSlot cache active: %d sta: %d for sta "QDF_MAC_ADDR_FMT, + i, mac_ctx->lim.gLimNoShortSlotParams.numNonShortSlotSta, + QDF_MAC_ADDR_REF(peer_mac_addr)); + return; + } + } + + if (LIM_IS_AP_ROLE(session_entry)) { + qdf_mem_copy(session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + session_entry->gLimNoShortSlotParams. + staNoShortSlotCache[i].active = true; + session_entry->gLimNoShortSlotParams.numNonShortSlotSta++; + } else { + qdf_mem_copy(mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].addr, + peer_mac_addr, sizeof(tSirMacAddr)); + mac_ctx->lim.gLimNoShortSlotParams. + staNoShortSlotCache[i].active = true; + mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta++; + } + val = mac_ctx->mlme_cfg->feature_flags.enable_short_slot_time_11g; + /* + * Here we check if we are AP role and short slot enabled + * (both admin and oper modes) but we have atleast one STA + * connected with only long slot enabled, we need to change + * our beacon/pb rsp to broadcast short slot disabled + */ + if ((LIM_IS_AP_ROLE(session_entry)) && (val && + session_entry->gLimNoShortSlotParams.numNonShortSlotSta + && session_entry->shortSlotTimeSupported)) { + /* enable long slot time */ + beacon_params->fShortSlotTime = false; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + pe_debug("Disable short slot time. Enable long slot time"); + session_entry->shortSlotTimeSupported = false; + } else if (!LIM_IS_AP_ROLE(session_entry) && + (val && mac_ctx->lim.gLimNoShortSlotParams. + numNonShortSlotSta && + session_entry->shortSlotTimeSupported)) { + /* enable long slot time */ + beacon_params->fShortSlotTime = false; + beacon_params->paramChangeBitmap |= + PARAM_SHORT_SLOT_TIME_CHANGED; + pe_debug("Disable short slot time. Enable long slot time"); + session_entry->shortSlotTimeSupported = false; + } +} + +/** ------------------------------------------------------------- + \fn lim_decide_sta_protection_on_assoc + \brief Decide protection related settings on Sta while association. + \param struct mac_context * mac + \param tpSchBeaconStruct pBeaconStruct + \return None + -------------------------------------------------------------*/ +void +lim_decide_sta_protection_on_assoc(struct mac_context *mac, + tpSchBeaconStruct pBeaconStruct, + struct pe_session *pe_session) +{ + enum reg_wifi_band rfBand = REG_BAND_UNKNOWN; + uint32_t phyMode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(mac, &rfBand, pe_session); + lim_get_phy_mode(mac, &phyMode, pe_session); + + if (REG_BAND_5G == rfBand) { + if ((eSIR_HT_OP_MODE_MIXED == pBeaconStruct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + pBeaconStruct->HTInfo.opMode)) { + if (mac->lim.cfgProtection.fromlla) + pe_session->beaconParams.llaCoexist = true; + } else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + pBeaconStruct->HTInfo.opMode) { + if (mac->lim.cfgProtection.ht20) + pe_session->beaconParams.ht20Coexist = true; + } + + } else if (REG_BAND_2G == rfBand) { + /* spec 7.3.2.13 */ + /* UseProtection will be set when nonERP STA is associated. */ + /* NonERPPresent bit will be set when: */ + /* --nonERP Sta is associated OR */ + /* --nonERP Sta exists in overlapping BSS */ + /* when useProtection is not set then protection from nonERP stations is optional. */ + + /* CFG protection from 11b is enabled and */ + /* 11B device in the BSS */ + /* TODO, This is not sessionized */ + if (phyMode != WNI_CFG_PHY_MODE_11B) { + if (mac->lim.cfgProtection.fromllb && + pBeaconStruct->erpPresent && + (pBeaconStruct->erpIEInfo.useProtection || + pBeaconStruct->erpIEInfo.nonErpPresent)) { + pe_session->beaconParams.llbCoexist = true; + } + /* AP has no 11b station associated. */ + else { + pe_session->beaconParams.llbCoexist = false; + } + } + /* following code block is only for HT station. */ + if ((pe_session->htCapability) && + (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + + /* Obss Non HT STA present mode */ + pe_session->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + /* CFG protection from 11G is enabled and */ + /* our AP has at least one 11G station associated. */ + if (mac->lim.cfgProtection.fromllg && + ((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) + && (!pe_session->beaconParams.llbCoexist)) { + if (mac->lim.cfgProtection.fromllg) + pe_session->beaconParams.llgCoexist = + true; + } + /* AP has only HT stations associated and at least one station is HT 20 */ + /* disable protection from any non-HT devices. */ + /* decision for disabling protection from 11b has already been taken above. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == htInfo.opMode) { + /* Disable protection from 11G station. */ + pe_session->beaconParams.llgCoexist = false; + /* CFG protection from HT 20 is enabled. */ + if (mac->lim.cfgProtection.ht20) + pe_session->beaconParams. + ht20Coexist = true; + } + /* Disable protection from non-HT and HT20 devices. */ + /* decision for disabling protection from 11b has already been taken above. */ + if (eSIR_HT_OP_MODE_PURE == htInfo.opMode) { + pe_session->beaconParams.llgCoexist = false; + pe_session->beaconParams.ht20Coexist = false; + } + + } + } + /* protection related factors other than HT operating mode. Applies to 2.4 GHZ as well as 5 GHZ. */ + if ((pe_session->htCapability) && (pBeaconStruct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = pBeaconStruct->HTInfo; + + pe_session->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + pe_session->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + pe_session->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) htInfo.lsigTXOPProtectionFullSupport; + } +} + + +/** + * lim_decide_sta_11bg_protection() - decides protection related settings on sta + * @mac_ctx: pointer to global mac structure + * @beacon_struct: pointer to tpschbeaconstruct + * @beaconparams: pointer to tpupdatebeaconparams + * @psession_entry: pointer to tppesession + * @phy_mode: phy mode index + * + * decides 11bg protection related settings on sta while processing beacon + * + * Return: none + */ +static void +lim_decide_sta_11bg_protection(struct mac_context *mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + struct pe_session *psession_entry, + uint32_t phy_mode) +{ + + tDot11fIEHTInfo htInfo; + + /* + * spec 7.3.2.13 + * UseProtection will be set when nonERP STA is associated. + * NonERPPresent bit will be set when: + * --nonERP Sta is associated OR + * --nonERP Sta exists in overlapping BSS + * when useProtection is not set then protection from + * nonERP stations is optional. + */ + if (phy_mode != WNI_CFG_PHY_MODE_11B) { + if (beacon_struct->erpPresent && + (beacon_struct->erpIEInfo.useProtection || + beacon_struct->erpIEInfo.nonErpPresent)) { + lim_enable11g_protection(mac_ctx, true, false, + beaconparams, + psession_entry); + } + /* AP has no 11b station associated. */ + else { + /* disable protection from 11b station */ + lim_enable11g_protection(mac_ctx, false, false, + beaconparams, + psession_entry); + } + } + + if (!(psession_entry->htCapability) || + !(beacon_struct->HTInfo.present)) + return; + + /* following code is only for HT station. */ + + htInfo = beacon_struct->HTInfo; + /* AP has at least one 11G station associated. */ + if (((eSIR_HT_OP_MODE_MIXED == htInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == htInfo.opMode)) && + (!psession_entry->beaconParams.llbCoexist)) { + lim_enable_ht_protection_from11g(mac_ctx, true, false, + beaconparams, psession_entry); + + } + /* + * no HT operating mode change ==> no change in + * protection settings except for MIXED_MODE/Legacy + * Mode. + */ + /* + * in Mixed mode/legacy Mode even if there is no + * change in HT operating mode, there might be + * change in 11bCoexist or 11gCoexist. Hence this + * check is being done after mixed/legacy mode + * check. + */ + if (mac_ctx->lim.gHTOperMode != + (tSirMacHTOperatingMode)htInfo.opMode) { + mac_ctx->lim.gHTOperMode = + (tSirMacHTOperatingMode) htInfo.opMode; + /* + * AP has only HT stations associated and + * at least one station is HT 20 + */ + + /* disable protection from any non-HT devices. */ + + /* + * decision for disabling protection from + * 11b has already been taken above. + */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + htInfo.opMode) { + /* Disable protection from 11G station. */ + lim_enable_ht_protection_from11g(mac_ctx, false, + false, beaconparams, + psession_entry); + + lim_enable_ht20_protection(mac_ctx, true, false, + beaconparams, + psession_entry); + } + /* + * Disable protection from non-HT and + * HT20 devices. + */ + /* + * decision for disabling protection from + * 11b has already been taken above. + */ + else if (eSIR_HT_OP_MODE_PURE == htInfo.opMode) { + lim_enable_ht_protection_from11g(mac_ctx, false, + false, beaconparams, + psession_entry); + + lim_enable_ht20_protection(mac_ctx, false, + false, beaconparams, + psession_entry); + + } + } + +} + +/** + * lim_decide_sta_protection() - decides protection related settings on sta + * @mac_ctx: pointer to global mac structure + * @beacon_struct: pointer to tpschbeaconstruct + * @beaconparams: pointer to tpupdatebeaconparams + * @psession_entry: pointer to tppesession + * + * decides protection related settings on sta while processing beacon + * + * Return: none + */ +void +lim_decide_sta_protection(struct mac_context *mac_ctx, + tpSchBeaconStruct beacon_struct, + tpUpdateBeaconParams beaconparams, + struct pe_session *psession_entry) +{ + + enum reg_wifi_band rfband = REG_BAND_UNKNOWN; + uint32_t phy_mode = WNI_CFG_PHY_MODE_NONE; + + lim_get_rf_band_new(mac_ctx, &rfband, psession_entry); + lim_get_phy_mode(mac_ctx, &phy_mode, psession_entry); + + if ((REG_BAND_5G == rfband) && + /* we are HT capable. */ + (true == psession_entry->htCapability) && + (beacon_struct->HTInfo.present)) { + /* + * we are HT capable, AP's HT OPMode is + * mixed / overlap legacy ==> need protection + * from 11A. + */ + if ((eSIR_HT_OP_MODE_MIXED == + beacon_struct->HTInfo.opMode) || + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + beacon_struct->HTInfo.opMode)) { + lim_update_11a_protection(mac_ctx, true, false, + beaconparams, psession_entry); + } + /* + * we are HT capable, AP's HT OPMode is + * HT20 ==> disable protection from 11A if + * enabled. + */ + /* protection from HT20 if needed. */ + else if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + beacon_struct->HTInfo.opMode) { + lim_update_11a_protection(mac_ctx, false, false, + beaconparams, psession_entry); + lim_enable_ht20_protection(mac_ctx, true, false, + beaconparams, psession_entry); + } else if (eSIR_HT_OP_MODE_PURE == + beacon_struct->HTInfo.opMode) { + lim_update_11a_protection(mac_ctx, false, false, + beaconparams, psession_entry); + lim_enable_ht20_protection(mac_ctx, false, + false, beaconparams, + psession_entry); + } + } else if (REG_BAND_2G == rfband) { + lim_decide_sta_11bg_protection(mac_ctx, beacon_struct, + beaconparams, psession_entry, phy_mode); + } + /* + * following code block is only for HT station. + * (2.4 GHZ as well as 5 GHZ) + */ + if ((psession_entry->htCapability) && (beacon_struct->HTInfo.present)) { + tDot11fIEHTInfo htInfo = beacon_struct->HTInfo; + /* + * Check for changes in protection related factors other + * than HT operating mode. + */ + /* + * Check for changes in RIFS mode, nonGFDevicesPresent, + * lsigTXOPProtectionFullSupport. + */ + if (psession_entry->beaconParams.fRIFSMode != + (uint8_t) htInfo.rifsMode) { + beaconparams->fRIFSMode = + psession_entry->beaconParams.fRIFSMode = + (uint8_t) htInfo.rifsMode; + beaconparams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + + if (psession_entry->beaconParams.llnNonGFCoexist != + htInfo.nonGFDevicesPresent) { + beaconparams->llnNonGFCoexist = + psession_entry->beaconParams.llnNonGFCoexist = + (uint8_t) htInfo.nonGFDevicesPresent; + beaconparams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + + if (psession_entry->beaconParams. + fLsigTXOPProtectionFullSupport != + (uint8_t) htInfo.lsigTXOPProtectionFullSupport) { + beaconparams->fLsigTXOPProtectionFullSupport = + psession_entry->beaconParams. + fLsigTXOPProtectionFullSupport = + (uint8_t) htInfo. + lsigTXOPProtectionFullSupport; + beaconparams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + /* + * For Station just update the global lim variable, + * no need to send message to HAL since Station already + * taking care of HT OPR Mode=01, + * meaning AP is seeing legacy + */ + /* stations in overlapping BSS. */ + if (psession_entry->beaconParams.gHTObssMode != + (uint8_t) htInfo.obssNonHTStaPresent) + psession_entry->beaconParams.gHTObssMode = + (uint8_t) htInfo.obssNonHTStaPresent; + + } +} + +/** + * __lim_process_channel_switch_timeout() + * + ***FUNCTION: + * This function is invoked when Channel Switch Timer expires at + * the STA. Now, STA must stop traffic, and then change/disable + * primary or secondary channel. + * + * + ***NOTE: + * @param pe_session - Pointer to pe session + * + * @return qdf_status + */ +static QDF_STATUS +__lim_process_channel_switch_timeout(struct pe_session *pe_session) +{ + struct mac_context *mac; + uint32_t channel_freq; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!pe_session) { + pe_err("Invalid pe session"); + return QDF_STATUS_E_INVAL; + } + mac = pe_session->mac_ctx; + if (!mac) { + pe_err("Invalid mac context"); + return QDF_STATUS_E_INVAL; + } + + if (!LIM_IS_STA_ROLE(pe_session)) { + pe_warn("Channel switch can be done only in STA role, Current Role: %d", + GET_LIM_SYSTEM_ROLE(pe_session)); + return QDF_STATUS_E_INVAL; + } + + if (pe_session->gLimSpecMgmt.dot11hChanSwState != + eLIM_11H_CHANSW_RUNNING) { + pe_warn("Channel switch timer should not have been running in state: %d", + pe_session->gLimSpecMgmt.dot11hChanSwState); + return QDF_STATUS_E_INVAL; + } + + channel_freq = pe_session->gLimChannelSwitch.sw_target_freq; + /* Restore Channel Switch parameters to default */ + pe_session->gLimChannelSwitch.switchTimeoutValue = 0; + + /* Channel-switch timeout has occurred. reset the state */ + pe_session->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_END; + + /* Check if the AP is switching to a channel that we support. + * Else, just don't bother to switch. Indicate HDD to look for a + * better AP to associate + */ + if (!lim_is_channel_valid_for_channel_switch(mac, channel_freq)) { + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(mac, pe_session) != + QDF_STATUS_SUCCESS) { + pe_err("Could not restore pre-channelSwitch (11h) state, resetting the system"); + return QDF_STATUS_E_INVAL; + } + + /* + * The channel switch request received from AP is carrying + * invalid channel. It's ok to ignore this channel switch + * request as it might be from spoof AP. If it's from genuine + * AP, it may lead to heart beat failure and result in + * disconnection. DUT can go ahead and reconnect to it/any + * other AP once it disconnects. + */ + pe_err("Invalid channel freq %u Ignore CSA request", + channel_freq); + return QDF_STATUS_E_INVAL; + } + switch (pe_session->gLimChannelSwitch.state) { + case eLIM_CHANNEL_SWITCH_PRIMARY_ONLY: + status = lim_switch_primary_channel(mac, + pe_session->gLimChannelSwitch.sw_target_freq, + pe_session); + pe_session->gLimChannelSwitch.state = + eLIM_CHANNEL_SWITCH_IDLE; + break; + case eLIM_CHANNEL_SWITCH_PRIMARY_AND_SECONDARY: + status = lim_switch_primary_secondary_channel(mac, pe_session); + pe_session->gLimChannelSwitch.state = eLIM_CHANNEL_SWITCH_IDLE; + break; + + case eLIM_CHANNEL_SWITCH_IDLE: + default: + pe_err("incorrect state"); + if (lim_restore_pre_channel_switch_state(mac, pe_session) != + QDF_STATUS_SUCCESS) { + pe_err("Could not restore pre-channelSwitch (11h) state, resetting the system"); + status = QDF_STATUS_E_FAILURE; + } + /* Please note, this is 'return' and not 'break' */ + return status; + } + + return status; +} + +void lim_disconnect_complete(struct pe_session *session, bool del_bss) +{ + QDF_STATUS status; + struct mac_context *mac = session->mac_ctx; + + if (wlan_vdev_mlme_get_substate(session->vdev) == + WLAN_VDEV_SS_STOP_STOP_PROGRESS) { + status = wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_STOP_REQ, + sizeof(*session), + session); + return; + } + status = + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_DISCONNECT_COMPLETE, + sizeof(*session), session); + if (QDF_IS_STATUS_ERROR(status)) + lim_send_stop_bss_failure_resp(mac, session); +} + +void lim_process_channel_switch(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + struct pe_session *session_entry; + QDF_STATUS status; + + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session_entry) { + pe_err("Session does not exist for given vdev_id %d", vdev_id); + return; + } + + session_entry->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + mlme_set_chan_switch_in_progress(session_entry->vdev, true); + status = wlan_vdev_mlme_sm_deliver_evt( + session_entry->vdev, + WLAN_VDEV_SM_EV_FW_VDEV_RESTART, + sizeof(*session_entry), + session_entry); + if (QDF_IS_STATUS_ERROR(status)) + mlme_set_chan_switch_in_progress(session_entry->vdev, false); +} + +/** ------------------------------------------------------------------------ **/ +/** + * keep track of the number of ANI peers associated in the BSS + * For the first and last ANI peer, we have to update EDCA params as needed + * + * When the first ANI peer joins the BSS, we notify SCH + * When the last ANI peer leaves the BSS, we notfiy SCH + */ +void +lim_util_count_sta_add(struct mac_context *mac, + tpDphHashNode pSta, struct pe_session *pe_session) +{ + + if ((!pSta) || (!pSta->valid) || (pSta->fAniCount)) + return; + + pSta->fAniCount = 1; + + if (mac->lim.gLimNumOfAniSTAs++ != 0) + return; + + if (mac->mlme_cfg->wmm_params.edca_profile != + WNI_CFG_EDCA_PROFILE_ANI) + return; + + /* get here only if this is the first ANI peer in the BSS */ + sch_edca_profile_update(mac, pe_session); +} + +void +lim_util_count_sta_del(struct mac_context *mac, + tpDphHashNode pSta, struct pe_session *pe_session) +{ + + if ((!pSta) || (!pSta->fAniCount)) + return; + + /* Only if sta is invalid and the validInDummyState bit is set to 1, + * then go ahead and update the count and profiles. This ensures + * that the "number of ani station" count is properly incremented/decremented. + */ + if (pSta->valid == 1) + return; + + pSta->fAniCount = 0; + + if (mac->lim.gLimNumOfAniSTAs <= 0) { + pe_err("CountStaDel: ignoring Delete Req when AniPeer count: %d", + mac->lim.gLimNumOfAniSTAs); + return; + } + + mac->lim.gLimNumOfAniSTAs--; + + if (mac->lim.gLimNumOfAniSTAs != 0) + return; + + if (mac->mlme_cfg->wmm_params.edca_profile != + WNI_CFG_EDCA_PROFILE_ANI) + return; + + /* get here only if this is the last ANI peer in the BSS */ + sch_edca_profile_update(mac, pe_session); +} + +/** + * lim_switch_channel_vdev_started() - Send vdev started when switch channel + * + * @pe_session: PE session entry + * + * This function is called to deliver WLAN_VDEV_SM_EV_START_SUCCESS to VDEV SM + * + * Return: None + */ +static void lim_switch_channel_vdev_started(struct pe_session *pe_session) +{ + QDF_STATUS status; + + status = wlan_vdev_mlme_sm_deliver_evt( + pe_session->vdev, + WLAN_VDEV_SM_EV_START_SUCCESS, + sizeof(*pe_session), pe_session); +} + +/** + * lim_switch_channel_cback() + * + ***FUNCTION: + * This is the callback function registered while requesting to switch channel + * after AP indicates a channel switch for spectrum management (11h). + * + ***NOTE: + * @param mac Pointer to Global MAC structure + * @param status Status of channel switch request + * @param data User data + * @param pe_session Session information + * @return NONE + */ +void lim_switch_channel_cback(struct mac_context *mac, QDF_STATUS status, + uint32_t *data, struct pe_session *pe_session) +{ + struct scheduler_msg mmhMsg = { 0 }; + struct switch_channel_ind *pSirSmeSwitchChInd; + struct wlan_channel *des_chan; + struct vdev_mlme_obj *mlme_obj; + + if (QDF_IS_STATUS_ERROR(status)) { + lim_tear_down_link_with_ap(mac, pe_session->peSessionId, + REASON_CHANNEL_SWITCH_FAILED, + eLIM_HOST_DISASSOC); + return; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return; + } + + des_chan = mlme_obj->vdev->vdev_mlme.des_chan; + if (!des_chan) { + pe_err("des_chan is NULL"); + return; + } + pe_session->curr_op_freq = pe_session->curr_req_chan_freq; + /* We need to restore pre-channelSwitch state on the STA */ + if (lim_restore_pre_channel_switch_state(mac, pe_session) != + QDF_STATUS_SUCCESS) { + pe_err("Could not restore pre-channelSwitch (11h) state, resetting the system"); + return; + } + + mmhMsg.type = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd = qdf_mem_malloc(sizeof(*pSirSmeSwitchChInd)); + if (!pSirSmeSwitchChInd) + return; + + pSirSmeSwitchChInd->messageType = eWNI_SME_SWITCH_CHL_IND; + pSirSmeSwitchChInd->length = sizeof(*pSirSmeSwitchChInd); + pSirSmeSwitchChInd->freq = des_chan->ch_freq; + pSirSmeSwitchChInd->sessionId = pe_session->smeSessionId; + pSirSmeSwitchChInd->chan_params.ch_width = des_chan->ch_width; + if (des_chan->ch_width > CH_WIDTH_20MHZ) { + pSirSmeSwitchChInd->chan_params.sec_ch_offset = + pe_session->gLimChannelSwitch.sec_ch_offset; + pSirSmeSwitchChInd->chan_params.center_freq_seg0 = + des_chan->ch_freq_seg1; + pSirSmeSwitchChInd->chan_params.mhz_freq_seg0 = + des_chan->ch_cfreq1; + pSirSmeSwitchChInd->chan_params.center_freq_seg1 = + des_chan->ch_freq_seg2; + pSirSmeSwitchChInd->chan_params.mhz_freq_seg1 = + des_chan->ch_cfreq2; + } + pSirSmeSwitchChInd->ch_phymode = des_chan->ch_phymode; + + pSirSmeSwitchChInd->status = status; + qdf_mem_copy(pSirSmeSwitchChInd->bssid.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + mmhMsg.bodyptr = pSirSmeSwitchChInd; + mmhMsg.bodyval = 0; + + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); + + sys_process_mmh_msg(mac, &mmhMsg); + + lim_switch_channel_vdev_started(pe_session); +} + +#ifdef WLAN_FEATURE_11BE +/** + * lim_set_puncture_from_chan_switch_to_session() - set puncture from channel + * switch to pe session + * @pe_session: pointer to pe session + * + * Return: void + */ +static void +lim_set_puncture_from_chan_switch_to_session(struct pe_session *pe_session) +{ + pe_session->puncture_bitmap = + pe_session->gLimChannelSwitch.puncture_bitmap; +} +#else +static void +lim_set_puncture_from_chan_switch_to_session(struct pe_session *pe_session) +{ +} +#endif + +QDF_STATUS lim_switch_primary_channel(struct mac_context *mac, + uint32_t new_channel_freq, + struct pe_session *pe_session) +{ + pe_debug("freq: %d --> freq: %d", pe_session->curr_op_freq, + new_channel_freq); + + pe_session->curr_req_chan_freq = new_channel_freq; + pe_session->curr_op_freq = pe_session->curr_req_chan_freq; + pe_session->ch_center_freq_seg0 = 0; + pe_session->ch_center_freq_seg1 = 0; + pe_session->ch_width = CH_WIDTH_20MHZ; + lim_set_puncture_from_chan_switch_to_session(pe_session); + pe_session->limRFBand = lim_get_rf_band(pe_session->curr_req_chan_freq); + + pe_session->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + + mac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + mac->lim.gpchangeChannelData = NULL; + + return lim_send_switch_chnl_params(mac, pe_session); +} + +QDF_STATUS lim_switch_primary_secondary_channel(struct mac_context *mac, + struct pe_session *pe_session) +{ + uint32_t new_channel_freq; + uint8_t ch_center_freq_seg0; + uint8_t ch_center_freq_seg1; + enum phy_ch_width ch_width; + + new_channel_freq = pe_session->gLimChannelSwitch.sw_target_freq, + ch_center_freq_seg0 = pe_session->gLimChannelSwitch.ch_center_freq_seg0, + ch_center_freq_seg1 = pe_session->gLimChannelSwitch.ch_center_freq_seg1, + ch_width = pe_session->gLimChannelSwitch.ch_width; + + /* Assign the callback to resume TX once channel is changed. */ + pe_session->curr_req_chan_freq = new_channel_freq; + pe_session->limRFBand = lim_get_rf_band(pe_session->curr_req_chan_freq); + pe_session->channelChangeReasonCode = LIM_SWITCH_CHANNEL_OPERATION; + mac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + mac->lim.gpchangeChannelData = NULL; + + /* Store the new primary and secondary channel in session entries if different */ + if (pe_session->curr_op_freq != new_channel_freq || + pe_session->ch_width != ch_width) { + pe_warn("freq: %d[%d] --> freq: %d[%d]", + pe_session->curr_op_freq, pe_session->ch_width, + new_channel_freq, ch_width); + pe_session->curr_op_freq = new_channel_freq; + } + if (pe_session->htSecondaryChannelOffset != + pe_session->gLimChannelSwitch.sec_ch_offset) { + pe_warn("HT sec chnl: %d --> HT sec chnl: %d", + pe_session->htSecondaryChannelOffset, + pe_session->gLimChannelSwitch.sec_ch_offset); + pe_session->htSecondaryChannelOffset = + pe_session->gLimChannelSwitch.sec_ch_offset; + if (pe_session->htSecondaryChannelOffset == + PHY_SINGLE_CHANNEL_CENTERED) { + pe_session->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + } else { + pe_session->htSupportedChannelWidthSet = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + } + pe_session->htRecommendedTxWidthSet = + pe_session->htSupportedChannelWidthSet; + } + + pe_session->ch_center_freq_seg0 = ch_center_freq_seg0; + pe_session->ch_center_freq_seg1 = ch_center_freq_seg1; + pe_session->ch_width = ch_width; + lim_set_puncture_from_chan_switch_to_session(pe_session); + + return lim_send_switch_chnl_params(mac, pe_session); +} + +/** + * lim_get_ht_capability() + * + ***FUNCTION: + * A utility function that returns the "current HT capability state" for the HT + * capability of interest (as requested in the API) + * + ***LOGIC: + * This routine will return with the "current" setting of a requested HT + * capability. This state info could be retrieved from - + * a) CFG (for static entries) + * b) Run time info + * - Dynamic state maintained by LIM + * - Configured at radio init time by SME + * + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * + * @param mac Pointer to Global MAC structure + * @param htCap The HT capability being queried + * @return uint8_t The current state of the requested HT capability is returned in a + * uint8_t variable + */ + +uint8_t lim_get_ht_capability(struct mac_context *mac, + uint32_t htCap, struct pe_session *pe_session) +{ + uint8_t retVal = 0; + uint8_t *ptr; + tSirMacTxBFCapabilityInfo macTxBFCapabilityInfo = { 0 }; + tSirMacASCapabilityInfo macASCapabilityInfo = { 0 }; + struct mlme_vht_capabilities_info *vht_cap_info; + + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + + /* */ + /* Determine which CFG to read from. Not ALL of the HT */ + /* related CFG's need to be read each time this API is */ + /* accessed */ + /* */ + if (htCap >= eHT_ANTENNA_SELECTION && htCap < eHT_SI_GRANULARITY) { + /* Get Antenna Selection HT Capabilities */ + ptr = (uint8_t *) &macASCapabilityInfo; + *((uint8_t *)ptr) = (uint8_t)(vht_cap_info->as_cap & 0xff); + } else if (htCap >= eHT_TX_BEAMFORMING && + htCap < eHT_ANTENNA_SELECTION) { + /* Get Transmit Beam Forming HT Capabilities */ + ptr = (uint8_t *)&macTxBFCapabilityInfo; + *((uint32_t *)ptr) = (uint32_t)(vht_cap_info->tx_bf_cap); + } + + switch (htCap) { + case eHT_LSIG_TXOP_PROTECTION: + retVal = mac->lim.gHTLsigTXOPProtection; + break; + + case eHT_STBC_CONTROL_FRAME: + retVal = (uint8_t)mac->mlme_cfg->ht_caps.ht_cap_info. + stbc_control_frame; + break; + + case eHT_PSMP: + retVal = mac->lim.gHTPSMPSupport; + break; + + case eHT_DSSS_CCK_MODE_40MHZ: + retVal = mac->lim.gHTDsssCckRate40MHzSupport; + break; + + case eHT_MAX_AMSDU_LENGTH: + retVal = (uint8_t)mac->mlme_cfg->ht_caps.ht_cap_info. + maximal_amsdu_size; + break; + + case eHT_MAX_AMSDU_NUM: + retVal = (uint8_t) pe_session->max_amsdu_num; + break; + + case eHT_RX_STBC: + retVal = (uint8_t) pe_session->ht_config.rx_stbc; + break; + + case eHT_TX_STBC: + retVal = (uint8_t) pe_session->ht_config.tx_stbc; + break; + + case eHT_SHORT_GI_40MHZ: + retVal = (uint8_t)(pe_session->ht_config.short_gi_40_mhz) ? + mac->mlme_cfg->ht_caps.ht_cap_info.short_gi_40_mhz : 0; + break; + + case eHT_SHORT_GI_20MHZ: + retVal = (uint8_t)(pe_session->ht_config.short_gi_20_mhz) ? + mac->mlme_cfg->ht_caps.ht_cap_info.short_gi_20_mhz : 0; + break; + + case eHT_GREENFIELD: + retVal = (uint8_t)mac->mlme_cfg->ht_caps.ht_cap_info. + green_field; + break; + + case eHT_MIMO_POWER_SAVE: + retVal = (uint8_t) mac->lim.gHTMIMOPSState; + break; + + case eHT_SUPPORTED_CHANNEL_WIDTH_SET: + retVal = (uint8_t) pe_session->htSupportedChannelWidthSet; + break; + + case eHT_ADVANCED_CODING: + retVal = (uint8_t) pe_session->ht_config.adv_coding_cap; + break; + + case eHT_MAX_RX_AMPDU_FACTOR: + retVal = mac->lim.gHTMaxRxAMpduFactor; + break; + + case eHT_MPDU_DENSITY: + retVal = mac->lim.gHTAMpduDensity; + break; + + case eHT_PCO: + retVal = (uint8_t)mac->mlme_cfg->ht_caps.ext_cap_info.pco; + break; + + case eHT_TRANSITION_TIME: + retVal = (uint8_t)mac->mlme_cfg->ht_caps.ext_cap_info. + transition_time; + break; + + case eHT_MCS_FEEDBACK: + retVal = (uint8_t)mac->mlme_cfg->ht_caps.ext_cap_info. + mcs_feedback; + break; + + case eHT_TX_BEAMFORMING: + retVal = (uint8_t) macTxBFCapabilityInfo.txBF; + break; + + case eHT_ANTENNA_SELECTION: + retVal = (uint8_t) macASCapabilityInfo.antennaSelection; + break; + + case eHT_SI_GRANULARITY: + retVal = mac->lim.gHTServiceIntervalGranularity; + break; + + case eHT_CONTROLLED_ACCESS: + retVal = mac->lim.gHTControlledAccessOnly; + break; + + case eHT_RIFS_MODE: + retVal = pe_session->beaconParams.fRIFSMode; + break; + + case eHT_RECOMMENDED_TX_WIDTH_SET: + retVal = pe_session->htRecommendedTxWidthSet; + break; + + case eHT_EXTENSION_CHANNEL_OFFSET: + retVal = pe_session->htSecondaryChannelOffset; + break; + + case eHT_OP_MODE: + if (LIM_IS_AP_ROLE(pe_session)) + retVal = pe_session->htOperMode; + else + retVal = mac->lim.gHTOperMode; + break; + + case eHT_BASIC_STBC_MCS: + retVal = mac->lim.gHTSTBCBasicMCS; + break; + + case eHT_DUAL_CTS_PROTECTION: + retVal = mac->lim.gHTDualCTSProtection; + break; + + case eHT_LSIG_TXOP_PROTECTION_FULL_SUPPORT: + retVal = + pe_session->beaconParams.fLsigTXOPProtectionFullSupport; + break; + + case eHT_PCO_ACTIVE: + retVal = mac->lim.gHTPCOActive; + break; + + case eHT_PCO_PHASE: + retVal = mac->lim.gHTPCOPhase; + break; + + default: + break; + } + + return retVal; +} + +/** + * lim_enable_11a_protection() - updates protection params for enable 11a + * protection request + * @mac_ctx: pointer to Global MAC structure + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @pe_session: pe session entry + * + * This function updates protection params for enable 11a protection request + * + * @Return: void + */ +static void +lim_enable_11a_protection(struct mac_context *mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + struct pe_session *pe_session) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(pe_session) && (true == pe_session->htCapability)) { + if (overlap) { + pe_session->gLimOverlap11aParams.protectionEnabled = + true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + mac_ctx->lim.gHTOperMode) + && (eSIR_HT_OP_MODE_MIXED != + mac_ctx->lim.gHTOperMode)) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_session->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + } + } else { + pe_session->gLim11aParams.protectionEnabled = true; + if (eSIR_HT_OP_MODE_MIXED != pe_session->htOperMode) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_MIXED; + pe_session->htOperMode = eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, bcn_prms, pe_session); + } + } + } + /* This part is common for station as well. */ + if (false == pe_session->beaconParams.llaCoexist) { + pe_debug(" => protection from 11A Enabled"); + bcn_prms->llaCoexist = true; + pe_session->beaconParams.llaCoexist = true; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + } +} + +/** + * lim_disable_11a_protection() - updates protection params for disable 11a + * protection request + * @mac_ctx: pointer to Global MAC structure + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @pe_session: pe session entry + * + * This function updates protection params for disable 11a protection request + * + * @Return: void + */ +static void +lim_disable_11a_protection(struct mac_context *mac_ctx, + uint8_t overlap, + tpUpdateBeaconParams bcn_prms, + struct pe_session *pe_session) +{ + if (false == pe_session->beaconParams.llaCoexist) + return; + + /* for station role */ + if (!LIM_IS_AP_ROLE(pe_session)) { + pe_debug("===> Protection from 11A Disabled"); + bcn_prms->llaCoexist = false; + pe_session->beaconParams.llaCoexist = false; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + return; + } + /* + * for AP role. + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (overlap) { + /* Overlap Legacy protection disabled. */ + pe_session->gLimOverlap11aParams.protectionEnabled = false; + + /* + * We need to take care of HT OP mode iff we are HT AP. + * OR no HT op-mode change is needed if any of the overlap + * protection enabled. + */ + if (!pe_session->htCapability || + (pe_session->gLimOverlap11aParams.protectionEnabled + || pe_session->gLimOverlapHt20Params.protectionEnabled + || pe_session->gLimOverlapNonGfParams.protectionEnabled)) + goto disable_11a_end; + + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + mac_ctx->lim.gHTOperMode) { + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + + if (pe_session->gLimHt20Params.protectionEnabled) + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + else + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } + } else { + /* Disable protection from 11A stations. */ + pe_session->gLim11aParams.protectionEnabled = false; + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + + /* + * Check if any other non-HT protection enabled. Right now we + * are in HT OP Mixed mode. Change HT op mode appropriately. + */ + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (pe_session->gLimOverlap11aParams.protectionEnabled + || pe_session->gLimOverlapHt20Params.protectionEnabled + || pe_session->gLimOverlapNonGfParams.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_session->htOperMode = eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, overlap, + bcn_prms, pe_session); + } else if (pe_session->gLimHt20Params.protectionEnabled) { + mac_ctx->lim.gHTOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + pe_session->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + } else { + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + pe_session->htOperMode = eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, overlap, + bcn_prms, pe_session); + } + } + +disable_11a_end: + if (!pe_session->gLimOverlap11aParams.protectionEnabled && + !pe_session->gLim11aParams.protectionEnabled) { + pe_warn("===> Protection from 11A Disabled"); + bcn_prms->llaCoexist = false; + pe_session->beaconParams.llaCoexist = false; + bcn_prms->paramChangeBitmap |= PARAM_llACOEXIST_CHANGED; + } +} + +/** + * lim_update_11a_protection() - based on config setting enables\disables 11a + * protection. + * @mac_ctx: pointer to Global MAC structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @bcn_prms: beacon parameters + * @session: pe session entry + * + * This based on config setting enables\disables 11a protection. + * + * @Return: success of failure of operation + */ +QDF_STATUS +lim_update_11a_protection(struct mac_context *mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams bcn_prms, + struct pe_session *session) +{ + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session)) && + (!session->cfgProtection.fromlla)) { + /* protection disabled. */ + pe_warn("protection from 11a is disabled"); + return QDF_STATUS_SUCCESS; + } + } + + if (enable) + lim_enable_11a_protection(mac_ctx, overlap, bcn_prms, session); + else + lim_disable_11a_protection(mac_ctx, overlap, bcn_prms, session); + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_handle_enable11g_protection_enabled() - handle 11g protection enabled + * @mac_ctx: pointer to Globale Mac structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @session_entry: pointer to struct pe_session * + * + * Function handles 11g protection enaled case + * + * Return: none + */ +static void +lim_handle_enable11g_protection_enabled(struct mac_context *mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, struct pe_session *session_entry) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + session_entry->gLimOlbcParams.protectionEnabled = true; + + pe_debug("protection from olbc is enabled"); + + if (true == session_entry->htCapability) { + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + session_entry->htOperMode) && + (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode)) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + /* + * CR-263021: OBSS bit is not switching back to 0 after + * disabling the overlapping legacy BSS + */ + /* + * This fixes issue of OBSS bit not set after 11b, 11g + * station leaves + */ + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + /* + * Not processing OBSS bit from other APs, as we are + * already taking care of Protection from overlapping + * BSS based on erp IE or useProtection bit + */ + lim_enable_ht_obss_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + session_entry->gLim11bParams.protectionEnabled = true; + pe_debug("protection from 11b is enabled"); + if (true == session_entry->htCapability) { + if (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + true, overlap, beaconparams, + session_entry); + } + } + } + + /* This part is common for staiton as well. */ + if (false == session_entry->beaconParams.llbCoexist) { + pe_debug("=> 11G Protection Enabled"); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = true; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } +} + +/** + * lim_handle_11g_protection_for_11bcoexist() - 11g protection for 11b co-ex + * @mac_ctx: pointer to Globale Mac structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @session_entry: pointer to struct pe_session * + * + * Function handles 11g protection for 11b co-exist + * + * Return: none + */ +static void +lim_handle_11g_protection_for_11bcoexist(struct mac_context *mac_ctx, + tpUpdateBeaconParams beaconparams, + uint8_t overlap, struct pe_session *session_entry) +{ + /* + * For AP role: + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOlbcParams.protectionEnabled = false; + + /* We need to take care of HT OP mode if we are HT AP. */ + if (session_entry->htCapability) { + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOverlap11gParams. + protectionEnabled || + session_entry->gLimOverlapHt20Params. + protectionEnabled || + session_entry->gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + session_entry->htOperMode)) { + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + if (session_entry->gLimHt20Params. + protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + session_entry->htSupportedChannelWidthSet) + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11B stations. */ + session_entry->gLim11bParams.protectionEnabled = false; + pe_debug("===> 11B Protection Disabled"); + /* Check if any other non-HT protection enabled. */ + if (!session_entry->gLim11gParams.protectionEnabled) { + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(mac_ctx, false, overlap, + beaconparams, session_entry); + /* + * Change HT OP mode to 01 if any overlap protection + * enabled + */ + if (session_entry->gLimOlbcParams.protectionEnabled || + session_entry->gLimOverlap11gParams. + protectionEnabled || + session_entry->gLimOverlapHt20Params. + protectionEnabled || + session_entry->gLimOverlapNonGfParams. + protectionEnabled) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + pe_debug("===> 11G Protection Disabled"); + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, + session_entry); + } else if (session_entry->gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + pe_debug("===> 11G Protection Disabled"); + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, + session_entry); + } else { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, + session_entry); + } + } + } + if (LIM_IS_AP_ROLE(session_entry)) { + if (!session_entry->gLimOlbcParams.protectionEnabled && + !session_entry->gLim11bParams.protectionEnabled) { + pe_debug("===> 11G Protection Disabled"); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = + false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } + } + /* For station role */ + if (!LIM_IS_AP_ROLE(session_entry)) { + pe_debug("===> 11G Protection Disabled"); + beaconparams->llbCoexist = + session_entry->beaconParams.llbCoexist = false; + beaconparams->paramChangeBitmap |= + PARAM_llBCOEXIST_CHANGED; + } +} + +/** + * lim_enable11g_protection() - Function to enable 11g protection + * @mac_ctx: pointer to Global Mac structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to struct pe_session * + * + * based on config setting enables\disables 11g protection. + * + * Return: Success - QDF_STATUS_SUCCESS - Success, Error number - Failure + */ +QDF_STATUS +lim_enable11g_protection(struct mac_context *mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + struct pe_session *session_entry) +{ + + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session_entry)) && + !session_entry->cfgProtection.fromllb) { + /* protection disabled. */ + pe_debug("protection from 11b is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (!mac_ctx->lim.cfgProtection.fromllb) { + /* protection disabled. */ + pe_debug("protection from 11b is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (enable) { + lim_handle_enable11g_protection_enabled(mac_ctx, beaconparams, + overlap, session_entry); + } else if (true == session_entry->beaconParams.llbCoexist) { + lim_handle_11g_protection_for_11bcoexist(mac_ctx, beaconparams, + overlap, session_entry); + } + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_protection_from11g + \brief based on cofig enables\disables protection from 11g. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +QDF_STATUS +lim_enable_ht_protection_from11g(struct mac_context *mac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + if (!pe_session->htCapability) + return QDF_STATUS_SUCCESS; /* protection from 11g is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + if ((LIM_IS_AP_ROLE(pe_session)) + && (!pe_session->cfgProtection.overlapFromllg)) { + /* protection disabled. */ + pe_debug("overlap protection from 11g is disabled"); + return QDF_STATUS_SUCCESS; + } + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(pe_session) && + !pe_session->cfgProtection.fromllg) { + /* protection disabled. */ + pe_debug("protection from 11g is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(pe_session)) { + if (!mac->lim.cfgProtection.fromllg) { + /* protection disabled. */ + pe_debug("protection from 11g is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + if (enable) { + /* If we are AP and HT capable, we need to set the HT OP mode */ + /* appropriately. */ + + if (LIM_IS_AP_ROLE(pe_session)) { + if (overlap) { + pe_session->gLimOverlap11gParams. + protectionEnabled = true; + /* 11g exists in overlap BSS. */ + /* need not to change the operating mode to overlap_legacy */ + /* if higher or same protection operating mode is enabled right now. */ + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + pe_session->htOperMode) + && (eSIR_HT_OP_MODE_MIXED != + pe_session->htOperMode)) { + pe_session->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + } + lim_enable_ht_rifs_protection(mac, true, overlap, + pBeaconParams, + pe_session); + lim_enable_ht_obss_protection(mac, true, overlap, + pBeaconParams, + pe_session); + } else { + /* 11g is associated to an AP operating in 11n mode. */ + /* Change the HT operating mode to 'mixed mode'. */ + pe_session->gLim11gParams.protectionEnabled = + true; + if (eSIR_HT_OP_MODE_MIXED != + pe_session->htOperMode) { + pe_session->htOperMode = + eSIR_HT_OP_MODE_MIXED; + lim_enable_ht_rifs_protection(mac, true, + overlap, + pBeaconParams, + pe_session); + lim_enable_ht_obss_protection(mac, true, + overlap, + pBeaconParams, + pe_session); + } + } + } + /* This part is common for staiton as well. */ + if (false == pe_session->beaconParams.llgCoexist) { + pBeaconParams->llgCoexist = + pe_session->beaconParams.llgCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } else if (true == + pe_session->gLimOverlap11gParams. + protectionEnabled) { + /* As operating mode changed after G station assoc some way to update beacon */ + /* This addresses the issue of mode not changing to - 11 in beacon when OBSS overlap is enabled */ + /* mac->sch.beacon_changed = 1; */ + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } else if (true == pe_session->beaconParams.llgCoexist) { + /* for AP role. */ + /* we need to take care of HT OP mode change if needed. */ + /* We need to take care of Overlap cases. */ + + if (LIM_IS_AP_ROLE(pe_session)) { + if (overlap) { + /* Overlap Legacy protection disabled. */ + if (pe_session->gLim11gParams.numSta == 0) + pe_session->gLimOverlap11gParams. + protectionEnabled = false; + + /* no HT op mode change if any of the overlap protection enabled. */ + if (! + (pe_session->gLimOlbcParams. + protectionEnabled + || pe_session->gLimOverlapHt20Params. + protectionEnabled + || pe_session->gLimOverlapNonGfParams. + protectionEnabled)) { + /* Check if there is a need to change HT OP mode. */ + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + pe_session->htOperMode) { + lim_enable_ht_rifs_protection(mac, + false, + overlap, + pBeaconParams, + pe_session); + lim_enable_ht_obss_protection(mac, + false, + overlap, + pBeaconParams, + pe_session); + + if (pe_session->gLimHt20Params.protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + pe_session->htSupportedChannelWidthSet) + pe_session->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + pe_session->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + } else + pe_session->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else { + /* Disable protection from 11G stations. */ + pe_session->gLim11gParams.protectionEnabled = + false; + /* Check if any other non-HT protection enabled. */ + if (!pe_session->gLim11bParams. + protectionEnabled) { + + /* Right now we are in HT OP Mixed mode. */ + /* Change HT op mode appropriately. */ + lim_enable_ht_obss_protection(mac, false, + overlap, + pBeaconParams, + pe_session); + + /* Change HT OP mode to 01 if any overlap protection enabled */ + if (pe_session->gLimOlbcParams. + protectionEnabled + || pe_session-> + gLimOverlap11gParams. + protectionEnabled + || pe_session-> + gLimOverlapHt20Params. + protectionEnabled + || pe_session-> + gLimOverlapNonGfParams. + protectionEnabled) { + pe_session->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac, + true, + overlap, + pBeaconParams, + pe_session); + } else if (pe_session-> + gLimHt20Params. + protectionEnabled) { + /* Commenting because of CR 258588 WFA cert */ + /* pe_session->htOperMode = eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; */ + pe_session->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac, + false, + overlap, + pBeaconParams, + pe_session); + } else { + pe_session->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac, + false, + overlap, + pBeaconParams, + pe_session); + } + } + } + if (!pe_session->gLimOverlap11gParams. + protectionEnabled + && !pe_session->gLim11gParams. + protectionEnabled) { + pe_debug("===> Protection from 11G Disabled"); + pBeaconParams->llgCoexist = + pe_session->beaconParams.llgCoexist = + false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + /* for station role */ + else { + pe_debug("===> Protection from 11G Disabled"); + pBeaconParams->llgCoexist = + pe_session->beaconParams.llgCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_llGCOEXIST_CHANGED; + } + } + return QDF_STATUS_SUCCESS; +} + +/* FIXME_PROTECTION : need to check for no APSD whenever we want to enable this protection. */ +/* This check will be done at the caller. */ + +/** ------------------------------------------------------------- + \fn limEnableHtObssProtection + \brief based on cofig enables\disables obss protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +QDF_STATUS +lim_enable_ht_obss_protection(struct mac_context *mac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + + if (!pe_session->htCapability) + return QDF_STATUS_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + /* overlapping protection configuration check. */ + } else { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(pe_session)) && + !pe_session->cfgProtection.obss) { /* ToDo Update this field */ + /* protection disabled. */ + pe_debug("protection from Obss is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(pe_session)) { + if (!mac->lim.cfgProtection.obss) { /* ToDo Update this field */ + /* protection disabled. */ + pe_debug("protection from Obss is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(pe_session)) { + if ((enable) + && (false == pe_session->beaconParams.gHTObssMode)) { + pe_debug("=>obss protection enabled"); + pe_session->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + pe_session->beaconParams.gHTObssMode)) { + pe_debug("===> obss Protection disabled"); + pe_session->beaconParams.gHTObssMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_OBSS_MODE_CHANGED; + + } +/* CR-263021: OBSS bit is not switching back to 0 after disabling the overlapping legacy BSS */ + if (!enable && !overlap) { + pe_session->gLimOverlap11gParams.protectionEnabled = + false; + } + } else { + if ((enable) + && (false == pe_session->beaconParams.gHTObssMode)) { + pe_debug("=>obss protection enabled"); + pe_session->beaconParams.gHTObssMode = true; + pBeaconParams->paramChangeBitmap |= PARAM_OBSS_MODE_CHANGED; /* UPDATE AN ENUM FOR OBSS MODE */ + + } else if (!enable + && (true == + pe_session->beaconParams.gHTObssMode)) { + pe_debug("===> obss Protection disabled"); + pe_session->beaconParams.gHTObssMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_OBSS_MODE_CHANGED; + + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * lim_handle_ht20protection_enabled() - Handle ht20 protection enabled + * @mac_ctx: pointer to Gloal Mac Structure + * @overlap: variable for overlap detection + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to struct pe_session * + * + * Function handles ht20 protection enabled + * + * Return: none + */ +static void lim_handle_ht20protection_enabled(struct mac_context *mac_ctx, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + struct pe_session *session_entry) +{ + /* + * If we are AP and HT capable, we need to set the HT OP mode + * appropriately. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + session_entry->gLimOverlapHt20Params.protectionEnabled = true; + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY != + session_entry->htOperMode) && + (eSIR_HT_OP_MODE_MIXED != + session_entry->htOperMode)) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_OVERLAP_LEGACY; + lim_enable_ht_rifs_protection(mac_ctx, true, + overlap, beaconparams, session_entry); + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + session_entry->gLimHt20Params.protectionEnabled = true; + if (eSIR_HT_OP_MODE_PURE == session_entry->htOperMode) { + if (session_entry->htSupportedChannelWidthSet != + eHT_CHANNEL_WIDTH_20MHZ) + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + /* This part is common for staiton as well. */ + if (false == session_entry->beaconParams.ht20Coexist) { + pe_debug("=> Protection from HT20 Enabled"); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = true; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } +} + +/** + * lim_handle_ht20coexist_ht20protection() - ht20 protection for ht20 coexist + * @mac_ctx: pointer to Gloal Mac Structure + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to struct pe_session * + * @overlap: variable for overlap detection + * + * Function handles ht20 protection for ht20 coexist + * + * Return: none + */ +static void lim_handle_ht20coexist_ht20protection(struct mac_context *mac_ctx, + tpUpdateBeaconParams beaconparams, + struct pe_session *session_entry, uint8_t overlap) +{ + /* + * For AP role: + * we need to take care of HT OP mode change if needed. + * We need to take care of Overlap cases. + */ + if (LIM_IS_AP_ROLE(session_entry) && overlap) { + /* Overlap Legacy protection disabled. */ + session_entry->gLimOverlapHt20Params.protectionEnabled = + false; + /* + * no HT op mode change if any of the overlap + * protection enabled. + */ + if (!(session_entry->gLimOlbcParams.protectionEnabled || + session_entry->gLimOverlap11gParams.protectionEnabled || + session_entry->gLimOverlapHt20Params.protectionEnabled + || session_entry->gLimOverlapNonGfParams. + protectionEnabled) && + /* + * Check if there is a need to change HT + * OP mode. + */ + (eSIR_HT_OP_MODE_OVERLAP_LEGACY == + session_entry->htOperMode)) { + if (session_entry->gLimHt20Params. + protectionEnabled) { + if (eHT_CHANNEL_WIDTH_20MHZ == + session_entry-> + htSupportedChannelWidthSet) + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + else + session_entry->htOperMode = + eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT; + + lim_enable_ht_rifs_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + lim_enable_ht_obss_protection(mac_ctx, + false, overlap, beaconparams, + session_entry); + } else { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + } + } + } else if (LIM_IS_AP_ROLE(session_entry) && !overlap) { + /* Disable protection from 11G stations. */ + session_entry->gLimHt20Params.protectionEnabled = false; + /* Change HT op mode appropriately. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == + session_entry->htOperMode) { + session_entry->htOperMode = + eSIR_HT_OP_MODE_PURE; + lim_enable_ht_rifs_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + lim_enable_ht_obss_protection(mac_ctx, false, + overlap, beaconparams, session_entry); + } + } + if (LIM_IS_AP_ROLE(session_entry)) { + pe_debug("===> Protection from HT 20 Disabled"); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } + if (!LIM_IS_AP_ROLE(session_entry)) { + /* For station role */ + pe_debug("===> Protection from HT20 Disabled"); + beaconparams->ht20MhzCoexist = + session_entry->beaconParams.ht20Coexist = false; + beaconparams->paramChangeBitmap |= + PARAM_HT20MHZCOEXIST_CHANGED; + } +} + +/** + * lim_enable_ht20_protection() - Function to enable ht20 protection + * @mac_ctx: pointer to Global Mac structure + * @enable: 1=> enable protection, 0=> disable protection. + * @overlap: 1=> called from overlap context, 0 => called from assoc context. + * @beaconparams: pointer to tpUpdateBeaconParams + * @session_entry: pointer to struct pe_session * + * + * based on cofig enables\disables protection from Ht20 + * + * Return: 0 - success + */ +QDF_STATUS lim_enable_ht20_protection(struct mac_context *mac_ctx, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams beaconparams, + struct pe_session *session_entry) +{ + /* This protection is only for HT stations. */ + if (!session_entry->htCapability) + return QDF_STATUS_SUCCESS; + + /* overlapping protection configuration check. */ + if (!overlap) { + /* normal protection config check */ + if ((LIM_IS_AP_ROLE(session_entry)) && + !session_entry->cfgProtection.ht20) { + /* protection disabled. */ + pe_debug("protection from HT20 is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(session_entry)) { + if (!mac_ctx->lim.cfgProtection.ht20) { + /* protection disabled. */ + pe_debug("protection from HT20 is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (enable) + lim_handle_ht20protection_enabled(mac_ctx, overlap, + beaconparams, session_entry); + else if (true == session_entry->beaconParams.ht20Coexist) + lim_handle_ht20coexist_ht20protection(mac_ctx, beaconparams, + session_entry, overlap); + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_non_gf_protection + \brief based on cofig enables\disables protection from NonGf. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +QDF_STATUS +lim_enable_ht_non_gf_protection(struct mac_context *mac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + if (!pe_session->htCapability) + return QDF_STATUS_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(pe_session) && + !pe_session->cfgProtection.nonGf) { + /* protection disabled. */ + pe_debug("protection from NonGf is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(pe_session)) { + /* normal protection config check */ + if (!mac->lim.cfgProtection.nonGf) { + /* protection disabled. */ + pe_debug("protection from NonGf is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + if (LIM_IS_AP_ROLE(pe_session)) { + if ((enable) + && (false == pe_session->beaconParams.llnNonGFCoexist)) { + pe_debug(" => Protection from non GF Enabled"); + pBeaconParams->llnNonGFCoexist = + pe_session->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + pe_session->beaconParams.llnNonGFCoexist)) { + pe_debug("===> Protection from Non GF Disabled"); + pBeaconParams->llnNonGFCoexist = + pe_session->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } else { + if ((enable) + && (false == pe_session->beaconParams.llnNonGFCoexist)) { + pe_debug(" => Protection from non GF Enabled"); + pBeaconParams->llnNonGFCoexist = + pe_session->beaconParams.llnNonGFCoexist = true; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } else if (!enable + && (true == + pe_session->beaconParams.llnNonGFCoexist)) { + pe_debug("===> Protection from Non GF Disabled"); + pBeaconParams->llnNonGFCoexist = + pe_session->beaconParams.llnNonGFCoexist = false; + pBeaconParams->paramChangeBitmap |= + PARAM_NON_GF_DEVICES_PRESENT_CHANGED; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** ------------------------------------------------------------- + \fn lim_enable_ht_lsig_txop_protection + \brief based on cofig enables\disables LsigTxop protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +QDF_STATUS +lim_enable_ht_lsig_txop_protection(struct mac_context *mac, uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + if (!pe_session->htCapability) + return QDF_STATUS_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(pe_session) && + !pe_session->cfgProtection.lsigTxop) { + /* protection disabled. */ + pe_debug("protection from LsigTxop not supported is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(pe_session)) { + /* normal protection config check */ + if (!mac->lim.cfgProtection.lsigTxop) { + /* protection disabled. */ + pe_debug("protection from LsigTxop not supported is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(pe_session)) { + if ((enable) + && (false == + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug(" => Protection from LsigTxop Enabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug("===> Protection from LsigTxop Disabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } else { + if ((enable) + && (false == + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug(" => Protection from LsigTxop Enabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport = true; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } else if (!enable + && (true == + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport)) { + pe_debug("===> Protection from LsigTxop Disabled"); + pBeaconParams->fLsigTXOPProtectionFullSupport = + pe_session->beaconParams. + fLsigTXOPProtectionFullSupport = false; + pBeaconParams->paramChangeBitmap |= + PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED; + } + } + return QDF_STATUS_SUCCESS; +} + +/* FIXME_PROTECTION : need to check for no APSD whenever we want to enable this protection. */ +/* This check will be done at the caller. */ +/** ------------------------------------------------------------- + \fn lim_enable_ht_rifs_protection + \brief based on cofig enables\disables Rifs protection. + \param uint8_t enable : 1=> enable protection, 0=> disable protection. + \param uint8_t overlap: 1=> called from overlap context, 0 => called from assoc context. + \param tpUpdateBeaconParams pBeaconParams + \return None + -------------------------------------------------------------*/ +QDF_STATUS +lim_enable_ht_rifs_protection(struct mac_context *mac, uint8_t enable, + uint8_t overlap, tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + if (!pe_session->htCapability) + return QDF_STATUS_SUCCESS; /* this protection is only for HT stations. */ + + /* overlapping protection configuration check. */ + if (overlap) { + } else { + /* normal protection config check */ + if (LIM_IS_AP_ROLE(pe_session) && + !pe_session->cfgProtection.rifs) { + /* protection disabled. */ + pe_debug("protection from Rifs is disabled"); + return QDF_STATUS_SUCCESS; + } else if (!LIM_IS_AP_ROLE(pe_session)) { + /* normal protection config check */ + if (!mac->lim.cfgProtection.rifs) { + /* protection disabled. */ + pe_debug("protection from Rifs is disabled"); + return QDF_STATUS_SUCCESS; + } + } + } + + if (LIM_IS_AP_ROLE(pe_session)) { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == pe_session->beaconParams.fRIFSMode)) { + pe_debug(" => Rifs protection Disabled"); + pBeaconParams->fRIFSMode = + pe_session->beaconParams.fRIFSMode = true; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + /* Enabling the RIFS Protection means Disable the RIFS mode of operation in the BSS */ + else if (enable + && (true == pe_session->beaconParams.fRIFSMode)) { + pe_debug("===> Rifs Protection Enabled"); + pBeaconParams->fRIFSMode = + pe_session->beaconParams.fRIFSMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + } else { + /* Disabling the RIFS Protection means Enable the RIFS mode of operation in the BSS */ + if ((!enable) + && (false == pe_session->beaconParams.fRIFSMode)) { + pe_debug(" => Rifs protection Disabled"); + pBeaconParams->fRIFSMode = + pe_session->beaconParams.fRIFSMode = true; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + /* Enabling the RIFS Protection means Disable the RIFS mode of operation in the BSS */ + else if (enable + && (true == pe_session->beaconParams.fRIFSMode)) { + pe_debug("===> Rifs Protection Enabled"); + pBeaconParams->fRIFSMode = + pe_session->beaconParams.fRIFSMode = false; + pBeaconParams->paramChangeBitmap |= + PARAM_RIFS_MODE_CHANGED; + } + } + return QDF_STATUS_SUCCESS; +} + +/* --------------------------------------------------------------------- */ +/** + * lim_enable_short_preamble + * + * FUNCTION: + * Enable/Disable short preamble + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param enable Flag to enable/disable short preamble + * @return None + */ + +QDF_STATUS +lim_enable_short_preamble(struct mac_context *mac, uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session) +{ + if (!mac->mlme_cfg->ht_caps.short_preamble) + return QDF_STATUS_SUCCESS; + + /* 11G short preamble switching is disabled. */ + if (!mac->mlme_cfg->feature_flags.enable_short_preamble_11g) + return QDF_STATUS_SUCCESS; + + if (LIM_IS_AP_ROLE(pe_session)) { + if (enable && (pe_session->beaconParams.fShortPreamble == 0)) { + pe_debug("===> Short Preamble Enabled"); + pe_session->beaconParams.fShortPreamble = true; + pBeaconParams->fShortPreamble = + (uint8_t) pe_session->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } else if (!enable + && (pe_session->beaconParams.fShortPreamble == + 1)) { + pe_debug("===> Short Preamble Disabled"); + pe_session->beaconParams.fShortPreamble = false; + pBeaconParams->fShortPreamble = + (uint8_t) pe_session->beaconParams. + fShortPreamble; + pBeaconParams->paramChangeBitmap |= + PARAM_SHORT_PREAMBLE_CHANGED; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_tx_complete + * + * Function: + * This is LIM's very own "TX MGMT frame complete" completion routine. + * + * Logic: + * LIM wants to send a MGMT frame (broadcast or unicast) + * LIM allocates memory using cds_packet_alloc( ..., **pData, **pPacket ) + * LIM transmits the MGMT frame using the API: + * wma_tx_frame( ... pPacket, ..., (void *) lim_tx_complete, pData ) + * HDD, via wma_tx_frame/DXE, "transfers" the packet over to BMU + * HDD, if it determines that a TX completion routine (in this case + * lim_tx_complete) has been provided, will invoke this callback + * LIM will try to free the TX MGMT packet that was earlier allocated, in order + * to send this MGMT frame, using the PAL API cds_packet_free( ... pData, pPacket ) + * + * Assumptions: + * Presently, this is ONLY being used for MGMT frames/packets + * TODO: + * Would it do good for LIM to have some sort of "signature" validation to + * ensure that the pData argument passed in was a buffer that was actually + * allocated by LIM and/or is not corrupted? + * + * Note: FIXME and TODO + * Looks like cds_packet_free() is interested in pPacket. But, when this completion + * routine is called, only pData is made available to LIM!! + * + * @param void A pointer to pData. Shouldn't it be pPacket?! + * + * @return QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS lim_tx_complete(void *context, qdf_nbuf_t buf, bool free) +{ + if (free) + cds_packet_free((void *)buf); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +lim_ht_switch_chnl_params(struct pe_session *pe_session) +{ + uint8_t center_freq = 0; + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + struct mac_context *mac; + uint8_t primary_channel; + + mac = pe_session->mac_ctx; + if (!mac) { + pe_err("Invalid mac_ctx"); + return QDF_STATUS_E_INVAL; + } + + primary_channel = wlan_reg_freq_to_chan(mac->pdev, + pe_session->curr_op_freq); + if (eHT_CHANNEL_WIDTH_40MHZ == + pe_session->htRecommendedTxWidthSet) { + ch_width = CH_WIDTH_40MHZ; + if (PHY_DOUBLE_CHANNEL_LOW_PRIMARY == + pe_session->htSecondaryChannelOffset) + center_freq = primary_channel + 2; + else if (PHY_DOUBLE_CHANNEL_HIGH_PRIMARY == + pe_session->htSecondaryChannelOffset) + center_freq = primary_channel - 2; + else + ch_width = CH_WIDTH_20MHZ; + } + pe_session->gLimChannelSwitch.primaryChannel = primary_channel; + pe_session->curr_req_chan_freq = pe_session->curr_op_freq; + pe_session->ch_center_freq_seg0 = center_freq; + pe_session->gLimChannelSwitch.ch_center_freq_seg0 = center_freq; + pe_session->gLimChannelSwitch.sw_target_freq = + pe_session->curr_op_freq; + pe_session->ch_width = ch_width; + pe_session->gLimChannelSwitch.ch_width = ch_width; + pe_session->gLimChannelSwitch.sec_ch_offset = + pe_session->htSecondaryChannelOffset; + pe_session->gLimChannelSwitch.ch_center_freq_seg1 = 0; + + pe_debug("HT IE changed: Primary Channel: %d center chan: %d Channel Width: %d cur op freq %d", + primary_channel, center_freq, + pe_session->htRecommendedTxWidthSet, + pe_session->gLimChannelSwitch.sw_target_freq); + pe_session->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_HT_WIDTH; + mac->lim.gpchangeChannelCallback = lim_switch_channel_cback; + mac->lim.gpchangeChannelData = NULL; + + return lim_send_switch_chnl_params(mac, pe_session); +} + +static void lim_ht_switch_chnl_req(struct pe_session *session) +{ + struct mac_context *mac; + QDF_STATUS status; + + mac = session->mac_ctx; + if (!mac) { + pe_err("Invalid mac context"); + return; + } + + session->channelChangeReasonCode = + LIM_SWITCH_CHANNEL_HT_WIDTH; + mlme_set_chan_switch_in_progress(session->vdev, true); + status = wlan_vdev_mlme_sm_deliver_evt( + session->vdev, + WLAN_VDEV_SM_EV_FW_VDEV_RESTART, + sizeof(*session), + session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to post WLAN_VDEV_SM_EV_FW_VDEV_RESTART for vdevid %d", + session->smeSessionId); + mlme_set_chan_switch_in_progress(session->vdev, false); + } +} + +uint8_t lim_get_cb_mode_for_freq(struct mac_context *mac, + struct pe_session *session, + qdf_freq_t chan_freq) +{ + uint8_t cb_mode = mac->roam.configParam.channelBondingMode5GHz; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) { + if (wlan_cm_get_force_20mhz_in_24ghz(session->vdev)) { + cb_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + pe_debug_rl("vdev %d force 20 Mhz in 2.4 GHz", + session->vdev_id); + } else { + cb_mode = mac->roam.configParam.channelBondingMode24GHz; + } + } + + return cb_mode; +} + +static +uint8_t lim_get_sta_cb_mode_for_24ghz(struct mac_context *mac, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + uint8_t cb_mode = mac->roam.configParam.channelBondingMode24GHz; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, + vdev_id, WLAN_MLME_SB_ID); + if (!vdev) + return cb_mode; + + if (!wlan_cm_get_force_20mhz_in_24ghz(vdev)) + goto end; + + cb_mode = WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); + return cb_mode; +} + +void lim_update_sta_run_time_ht_switch_chnl_params(struct mac_context *mac, + tDot11fIEHTInfo *pHTInfo, + struct pe_session *pe_session) +{ + qdf_freq_t chan_freq; + uint8_t cb_mode; + + cb_mode = lim_get_cb_mode_for_freq(mac, pe_session, + pe_session->curr_op_freq); + + /* If self capability is set to '20Mhz only', then do not change the CB mode. */ + if (cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) { + pe_debug_rl("self_cb_mode 0 for freq %d", + pe_session->curr_op_freq); + return; + } + + if (!wlan_cm_is_vdev_connected(pe_session->vdev)) { + pe_debug_rl("vdev not connected, ignore HT IE BW update"); + return; + } + + if (pe_session->ch_switch_in_progress == true) { + pe_debug("ch switch is in progress, ignore HT IE BW update"); + return; + } + chan_freq = wlan_reg_legacy_chan_to_freq(mac->pdev, + pHTInfo->primaryChannel); + + if (reg_is_chan_enum_invalid( + wlan_reg_get_chan_enum_for_freq(chan_freq))) { + pe_debug("Ignore Invalid channel in HT info"); + return; + } + + /* If channel mismatch the CSA will take care of this change */ + if (pHTInfo->primaryChannel != wlan_reg_freq_to_chan( + mac->pdev, pe_session->curr_op_freq)) { + pe_debug("Current channel doesn't match HT info ignore"); + return; + } + + if (pe_session->htSecondaryChannelOffset != + (uint8_t) pHTInfo->secondaryChannelOffset + || pe_session->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + pe_session->htSecondaryChannelOffset = + (ePhyChanBondState) pHTInfo->secondaryChannelOffset; + pe_session->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + pe_session->htSupportedChannelWidthSet = + pe_session->htRecommendedTxWidthSet; + + /* Before restarting vdev, delete the tdls peers */ + lim_update_tdls_set_state_for_fw(pe_session, false); + lim_delete_tdls_peers(mac, pe_session); + + lim_ht_switch_chnl_req(pe_session); + } + +} /* End limUpdateStaRunTimeHTParams. */ + +/** + * \brief This function updates the lim global structure, if any of the + * HT Capabilities have changed. + * + * + * \param mac Pointer to Global MAC structure + * + * \param pHTCapability Pointer to HT Capability Information Element + * obtained from a Beacon or Probe Response + * + * + * + */ + +void lim_update_sta_run_time_ht_capability(struct mac_context *mac, + tDot11fIEHTCaps *pHTCaps) +{ + + if (mac->lim.gHTLsigTXOPProtection != + (uint8_t) pHTCaps->lsigTXOPProtection) { + mac->lim.gHTLsigTXOPProtection = + (uint8_t) pHTCaps->lsigTXOPProtection; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTAMpduDensity != (uint8_t) pHTCaps->mpduDensity) { + mac->lim.gHTAMpduDensity = (uint8_t) pHTCaps->mpduDensity; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTMaxRxAMpduFactor != + (uint8_t) pHTCaps->maxRxAMPDUFactor) { + mac->lim.gHTMaxRxAMpduFactor = + (uint8_t) pHTCaps->maxRxAMPDUFactor; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_capability. */ + +/** + * \brief This function updates lim global structure, if any of the HT + * Info Parameters have changed. + * + * + * \param mac Pointer to the global MAC structure + * + * \param pHTInfo Pointer to the HT Info IE obtained from a Beacon or + * Probe Response + * + * + */ + +void lim_update_sta_run_time_ht_info(struct mac_context *mac, + tDot11fIEHTInfo *pHTInfo, + struct pe_session *pe_session) +{ + if (pe_session->htRecommendedTxWidthSet != + (uint8_t) pHTInfo->recommendedTxWidthSet) { + pe_session->htRecommendedTxWidthSet = + (uint8_t) pHTInfo->recommendedTxWidthSet; + /* Send change notification to HAL */ + } + + if (pe_session->beaconParams.fRIFSMode != + (uint8_t) pHTInfo->rifsMode) { + pe_session->beaconParams.fRIFSMode = + (uint8_t) pHTInfo->rifsMode; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTServiceIntervalGranularity != + (uint8_t) pHTInfo->serviceIntervalGranularity) { + mac->lim.gHTServiceIntervalGranularity = + (uint8_t) pHTInfo->serviceIntervalGranularity; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTOperMode != (tSirMacHTOperatingMode) pHTInfo->opMode) { + mac->lim.gHTOperMode = + (tSirMacHTOperatingMode) pHTInfo->opMode; + /* Send change notification to HAL */ + } + + if (pe_session->beaconParams.llnNonGFCoexist != + pHTInfo->nonGFDevicesPresent) { + pe_session->beaconParams.llnNonGFCoexist = + (uint8_t) pHTInfo->nonGFDevicesPresent; + } + + if (mac->lim.gHTSTBCBasicMCS != (uint8_t) pHTInfo->basicSTBCMCS) { + mac->lim.gHTSTBCBasicMCS = (uint8_t) pHTInfo->basicSTBCMCS; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTDualCTSProtection != + (uint8_t) pHTInfo->dualCTSProtection) { + mac->lim.gHTDualCTSProtection = + (uint8_t) pHTInfo->dualCTSProtection; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTSecondaryBeacon != (uint8_t) pHTInfo->secondaryBeacon) { + mac->lim.gHTSecondaryBeacon = + (uint8_t) pHTInfo->secondaryBeacon; + /* Send change notification to HAL */ + } + + if (pe_session->beaconParams.fLsigTXOPProtectionFullSupport != + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport) { + pe_session->beaconParams.fLsigTXOPProtectionFullSupport = + (uint8_t) pHTInfo->lsigTXOPProtectionFullSupport; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTPCOActive != (uint8_t) pHTInfo->pcoActive) { + mac->lim.gHTPCOActive = (uint8_t) pHTInfo->pcoActive; + /* Send change notification to HAL */ + } + + if (mac->lim.gHTPCOPhase != (uint8_t) pHTInfo->pcoPhase) { + mac->lim.gHTPCOPhase = (uint8_t) pHTInfo->pcoPhase; + /* Send change notification to HAL */ + } + +} /* End lim_update_sta_run_time_ht_info. */ + +/** + * lim_validate_delts_req() - This function validates DelTs req + * @mac_ctx: pointer to Global Mac structure + * @delts_req: pointer to delete traffic stream structure + * @peer_mac_addr: variable for peer mac address + * @session: pe session entry + * + * Function validates DelTs req originated by SME or by HAL and also + * sends halMsg_DelTs to HAL + * + * Return: QDF_STATUS_SUCCESS - Success, QDF_STATUS_E_FAILURE - Failure + */ + +QDF_STATUS +lim_validate_delts_req(struct mac_context *mac_ctx, tpSirDeltsReq delts_req, + tSirMacAddr peer_mac_addr, + struct pe_session *session) +{ + tpDphHashNode sta; + uint8_t ts_status; + struct mac_ts_info *tsinfo; + uint32_t i; + uint8_t tspec_idx; + + /* + * if sta + * - verify assoc state + * - del tspec locally + * if ap + * - verify sta is in assoc state + * - del sta tspec locally + */ + if (!delts_req) { + pe_err("Delete TS request pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (LIM_IS_STA_ROLE(session)) { + uint32_t val; + + /* station always talks to the AP */ + sta = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + + val = sizeof(tSirMacAddr); + sir_copy_mac_addr(peer_mac_addr, session->bssId); + + } else { + uint16_t associd; + uint8_t *macaddr = (uint8_t *) peer_mac_addr; + + associd = delts_req->aid; + if (associd != 0) + sta = dph_get_hash_entry(mac_ctx, associd, + &session->dph.dphHashTable); + else + sta = dph_lookup_hash_entry(mac_ctx, + delts_req->macaddr.bytes, + &associd, + &session->dph. + dphHashTable); + + if (sta) + /* TBD: check sta assoc state as well */ + for (i = 0; i < sizeof(tSirMacAddr); i++) + macaddr[i] = sta->staAddr[i]; + } + + if (!sta) { + pe_err("Cannot find station context for delts req"); + return QDF_STATUS_E_FAILURE; + } + + if ((!sta->valid) || + (sta->mlmStaContext.mlmState != + eLIM_MLM_LINK_ESTABLISHED_STATE)) { + pe_err("Invalid Sta (or state) for DelTsReq"); + return QDF_STATUS_E_FAILURE; + } + + delts_req->req.wsmTspecPresent = 0; + delts_req->req.wmeTspecPresent = 0; + delts_req->req.lleTspecPresent = 0; + + if ((sta->wsmEnabled) && + (delts_req->req.tspec.tsinfo.traffic.accessPolicy != + SIR_MAC_ACCESSPOLICY_EDCA)) + delts_req->req.wsmTspecPresent = 1; + else if (sta->wmeEnabled) + delts_req->req.wmeTspecPresent = 1; + else if (sta->lleEnabled) + delts_req->req.lleTspecPresent = 1; + else { + pe_warn("DELTS_REQ ignore - qos is disabled"); + return QDF_STATUS_E_FAILURE; + } + + tsinfo = delts_req->req.wmeTspecPresent ? &delts_req->req.tspec.tsinfo + : &delts_req->req.tsinfo; + pe_debug("received DELTS_REQ message wmeTspecPresent: %d lleTspecPresent: %d wsmTspecPresent: %d tsid: %d up: %d direction: %d", + delts_req->req.wmeTspecPresent, + delts_req->req.lleTspecPresent, + delts_req->req.wsmTspecPresent, tsinfo->traffic.tsid, + tsinfo->traffic.userPrio, tsinfo->traffic.direction); + + /* if no Access Control, ignore the request */ + if (lim_admit_control_delete_ts(mac_ctx, sta->assocId, tsinfo, + &ts_status, &tspec_idx) != QDF_STATUS_SUCCESS) { + pe_err("DELTS request for sta assocId: %d tsid: %d up: %d", + sta->assocId, tsinfo->traffic.tsid, + tsinfo->traffic.userPrio); + return QDF_STATUS_E_FAILURE; + } else if ((tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_HCCA) + || (tsinfo->traffic.accessPolicy == + SIR_MAC_ACCESSPOLICY_BOTH)) { + /* edca only now. */ + } else if (tsinfo->traffic.accessPolicy == SIR_MAC_ACCESSPOLICY_EDCA) { + /* send message to HAL to delete TS */ + if (QDF_STATUS_SUCCESS != + lim_send_hal_msg_del_ts(mac_ctx, + tspec_idx, delts_req->req, + session->peSessionId, + session->bssId)) { + pe_warn("DelTs with UP: %d failed in lim_send_hal_msg_del_ts - ignoring request", + tsinfo->traffic.userPrio); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * @function : lim_post_sm_state_update() + * + * @brief : This function Updates the HAL and Softmac about the change in the STA's SMPS state. + * + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param limMsg - Lim Message structure object with the MimoPSparam in body + * @return None + */ +QDF_STATUS +lim_post_sm_state_update(struct mac_context *mac, + tSirMacHTMIMOPowerSaveState state, + uint8_t *pPeerStaMac, uint8_t sessionId) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + tpSetMIMOPS pMIMO_PSParams; + + msgQ.reserved = 0; + msgQ.type = WMA_SET_MIMOPS_REQ; + + /* Allocate for WMA_SET_MIMOPS_REQ */ + pMIMO_PSParams = qdf_mem_malloc(sizeof(tSetMIMOPS)); + if (!pMIMO_PSParams) + return QDF_STATUS_E_NOMEM; + + pMIMO_PSParams->htMIMOPSState = state; + pMIMO_PSParams->fsendRsp = true; + pMIMO_PSParams->sessionId = sessionId; + qdf_mem_copy(pMIMO_PSParams->peerMac, pPeerStaMac, sizeof(tSirMacAddr)); + + msgQ.bodyptr = pMIMO_PSParams; + msgQ.bodyval = 0; + + pe_debug("Sending WMA_SET_MIMOPS_REQ"); + + MTRACE(mac_trace_msg_tx(mac, NO_SESSION, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("Posting WMA_SET_MIMOPS_REQ to HAL failed! Reason: %d", + retCode); + qdf_mem_free(pMIMO_PSParams); + return retCode; + } + + return retCode; +} + +void lim_pkt_free(struct mac_context *mac, + eFrameType frmType, uint8_t *pRxPacketInfo, void *pBody) +{ + (void)mac; + (void)frmType; + (void)pRxPacketInfo; + (void)pBody; +} + +/** + * lim_get_b_dfrom_rx_packet() + * + ***FUNCTION: + * This function is called to get pointer to Polaris + * Buffer Descriptor containing MAC header & other control + * info from the body of the message posted to LIM. + * + ***LOGIC: + * NA + * + ***ASSUMPTIONS: + * NA + * + ***NOTE: + * NA + * + * @param body - Received message body + * @param pRxPacketInfo - Pointer to received BD + * @return None + */ + +void +lim_get_b_dfrom_rx_packet(struct mac_context *mac, void *body, uint32_t **pRxPacketInfo) +{ + *pRxPacketInfo = (uint32_t *) body; +} /*** end lim_get_b_dfrom_rx_packet() ***/ + +bool lim_is_channel_valid_for_channel_switch(struct mac_context *mac, + uint32_t channel_freq) +{ + bool ok = false; + + if (policy_mgr_is_chan_ok_for_dnbs(mac->psoc, channel_freq, + &ok)) { + pe_err("policy_mgr_is_chan_ok_for_dnbs() returned error"); + return false; + } + + if (!ok) { + pe_debug("channel not ok for DNBS"); + return false; + } + + if (wlan_reg_is_freq_enabled(mac->pdev, channel_freq, + REG_CURRENT_PWR_MODE)) + return true; + + /* channel does not belong to list of valid channels */ + return false; +} + +/** + * @function : lim_restore_pre_channel_switch_state() + * + * @brief : This API is called by the user to undo any + * specific changes done on the device during + * channel switch. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @return None + */ + +QDF_STATUS +lim_restore_pre_channel_switch_state(struct mac_context *mac, struct pe_session *pe_session) +{ + + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + + if (!LIM_IS_STA_ROLE(pe_session)) + return retCode; + + /* Channel switch should be ready for the next time */ + pe_session->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_INIT; + + return retCode; +} + +/** + * @function: lim_prepare_for11h_channel_switch() + * + * @brief : This API is called by the user to prepare for + * 11h channel switch. As of now, the API does + * very minimal work. User can add more into the + * same API if needed. + * LOGIC: + * + * ASSUMPTIONS: + * NA + * + * NOTE: + * NA + * + * @param mac - Pointer to Global MAC structure + * @param pe_session + * @return None + */ +void +lim_prepare_for11h_channel_switch(struct mac_context *mac, struct pe_session *pe_session) +{ + if (!LIM_IS_STA_ROLE(pe_session)) + return; + + /* Flag to indicate 11h channel switch in progress */ + pe_session->gLimSpecMgmt.dot11hChanSwState = eLIM_11H_CHANSW_RUNNING; + + /** We are safe to switch channel at this point */ + lim_stop_tx_and_switch_channel(mac, pe_session->peSessionId); +} + +tSirNwType lim_get_nw_type(struct mac_context *mac, uint32_t chan_freq, uint32_t type, + tpSchBeaconStruct pBeacon) +{ + tSirNwType nwType = eSIR_11B_NW_TYPE; + + /* Logic to be cleaned up for 11AC & 11AX */ + if (type == SIR_MAC_DATA_FRAME) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) { + nwType = eSIR_11G_NW_TYPE; + } else { + nwType = eSIR_11A_NW_TYPE; + } + } else { + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) { + int i; + /* 11b or 11g packet */ + /* 11g iff extended Rate IE is present or */ + /* if there is an A rate in suppRate IE */ + for (i = 0; i < pBeacon->supportedRates.numRates; i++) { + if (sirIsArate + (pBeacon->supportedRates.rate[i] & 0x7f)) { + nwType = eSIR_11G_NW_TYPE; + break; + } + } + if (pBeacon->extendedRatesPresent) { + nwType = eSIR_11G_NW_TYPE; + } else if (pBeacon->HTInfo.present || + IS_BSS_VHT_CAPABLE(pBeacon->VHTCaps)) { + nwType = eSIR_11G_NW_TYPE; + } + } else { + /* 11a packet */ + nwType = eSIR_11A_NW_TYPE; + } + } + return nwType; +} + +uint32_t lim_get_channel_from_beacon(struct mac_context *mac, tpSchBeaconStruct pBeacon) +{ + uint8_t chan_freq = 0; + + if (pBeacon->he_op.oper_info_6g_present) + chan_freq = wlan_reg_chan_band_to_freq(mac->pdev, + pBeacon->he_op.oper_info_6g.info.primary_ch, + BIT(REG_BAND_6G)); + else if (pBeacon->dsParamsPresent) + chan_freq = pBeacon->chan_freq; + else if (pBeacon->HTInfo.present) + chan_freq = wlan_reg_legacy_chan_to_freq(mac->pdev, + pBeacon->HTInfo.primaryChannel); + else + chan_freq = pBeacon->chan_freq; + + return chan_freq; +} + +void lim_set_tspec_uapsd_mask_per_session(struct mac_context *mac, + struct pe_session *pe_session, + struct mac_ts_info *pTsInfo, + uint32_t action) +{ + uint8_t userPrio = (uint8_t) pTsInfo->traffic.userPrio; + uint16_t direction = pTsInfo->traffic.direction; + uint8_t ac = upToAc(userPrio); + + pe_debug("Set UAPSD mask for AC: %d dir: %d action: %d" + , ac, direction, action); + + /* Converting AC to appropriate Uapsd Bit Mask + * AC_BE(0) --> UAPSD_BITOFFSET_ACVO(3) + * AC_BK(1) --> UAPSD_BITOFFSET_ACVO(2) + * AC_VI(2) --> UAPSD_BITOFFSET_ACVO(1) + * AC_VO(3) --> UAPSD_BITOFFSET_ACVO(0) + */ + ac = ((~ac) & 0x3); + + if (action == CLEAR_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + pe_session->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + pe_session->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + pe_session->gUapsdPerAcTriggerEnableMask &= + ~(1 << ac); + pe_session->gUapsdPerAcDeliveryEnableMask &= + ~(1 << ac); + } + } else if (action == SET_UAPSD_MASK) { + if (direction == SIR_MAC_DIRECTION_UPLINK) + pe_session->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + pe_session->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + pe_session->gUapsdPerAcTriggerEnableMask |= + (1 << ac); + pe_session->gUapsdPerAcDeliveryEnableMask |= + (1 << ac); + } + } + + pe_debug("New pe_session->gUapsdPerAcTriggerEnableMask 0x%x pe_session->gUapsdPerAcDeliveryEnableMask 0x%x", + pe_session->gUapsdPerAcTriggerEnableMask, + pe_session->gUapsdPerAcDeliveryEnableMask); + + return; +} + +/** + * lim_handle_heart_beat_timeout_for_session() - Handle heart beat time out + * @mac_ctx: pointer to Global Mac Structure + * @psession_entry: pointer to struct pe_session * + * + * Function handles heart beat time out for session + * + * Return: none + */ +void lim_handle_heart_beat_timeout_for_session(struct mac_context *mac_ctx, + struct pe_session *psession_entry) +{ + if (psession_entry->valid) { + if ((psession_entry->bssType == eSIR_INFRASTRUCTURE_MODE) && + (LIM_IS_STA_ROLE(psession_entry))) + lim_handle_heart_beat_failure(mac_ctx, psession_entry); + } +} + +void lim_process_add_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + struct pe_session *session; + tpAddStaParams add_sta_params; + + add_sta_params = (tpAddStaParams) msg->bodyptr; + + session = pe_find_session_by_session_id(mac_ctx, + add_sta_params->sessionId); + if (!session) { + pe_err("Session Does not exist for given sessionID"); + qdf_mem_free(add_sta_params); + return; + } + session->csaOffloadEnable = add_sta_params->csaOffloadEnable; + if (LIM_IS_NDI_ROLE(session)) + lim_ndp_add_sta_rsp(mac_ctx, session, msg->bodyptr); +#ifdef FEATURE_WLAN_TDLS + else if (add_sta_params->staType == STA_ENTRY_TDLS_PEER) + lim_process_tdls_add_sta_rsp(mac_ctx, msg->bodyptr, session); +#endif + else + lim_process_mlm_add_sta_rsp(mac_ctx, msg, session); + +} + +/** + * lim_update_beacon() - This function updates beacon + * @mac_ctx: pointer to Global Mac Structure + * + * This Function is invoked to update the beacon + * + * Return: none + */ +void lim_update_beacon(struct mac_context *mac_ctx) +{ + uint8_t i; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + if (mac_ctx->lim.gpSession[i].valid != true) + continue; + if ((mac_ctx->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE) + && (eLIM_SME_NORMAL_STATE == + mac_ctx->lim.gpSession[i].limSmeState)) { + + sch_set_fixed_beacon_fields(mac_ctx, + &mac_ctx->lim.gpSession[i]); + + if (false == mac_ctx->sap.SapDfsInfo. + is_dfs_cac_timer_running) + lim_send_beacon_ind(mac_ctx, + &mac_ctx->lim.gpSession[i], + REASON_DEFAULT); + } + } +} + +struct pe_session *lim_is_ap_session_active(struct mac_context *mac) +{ + uint8_t i; + + for (i = 0; i < mac->lim.maxBssId; i++) { + if (mac->lim.gpSession[i].valid && + (mac->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE)) + return &mac->lim.gpSession[i]; + } + + return NULL; +} + +/**--------------------------------------------------------- + \fn lim_handle_defer_msg_error + \brief handles error scenario, when the msg can not be deferred. + \param mac + \param pLimMsg LIM msg, which could not be deferred. + \return void + -----------------------------------------------------------*/ + +void lim_handle_defer_msg_error(struct mac_context *mac, + struct scheduler_msg *pLimMsg) +{ + if (SIR_BB_XPORT_MGMT_MSG == pLimMsg->type) { + lim_decrement_pending_mgmt_count(mac); + cds_pkt_return_packet((cds_pkt_t *) pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } else if (pLimMsg->bodyptr) { + qdf_mem_free(pLimMsg->bodyptr); + pLimMsg->bodyptr = NULL; + } + +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/**--------------------------------------------------------- + \fn lim_diag_event_report + \brief This function reports Diag event + \param mac + \param eventType + \param bssid + \param status + \param reasonCode + \return void + -----------------------------------------------------------*/ +void lim_diag_event_report(struct mac_context *mac, uint16_t eventType, + struct pe_session *pe_session, uint16_t status, + uint16_t reasonCode) +{ + tSirMacAddr nullBssid = { 0, 0, 0, 0, 0, 0 }; + + WLAN_HOST_DIAG_EVENT_DEF(peEvent, host_event_wlan_pe_payload_type); + + qdf_mem_zero(&peEvent, sizeof(host_event_wlan_pe_payload_type)); + + if (!pe_session) { + qdf_mem_copy(peEvent.bssid, nullBssid, sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) mac->lim.gLimSmeState; + peEvent.mlm_state = (uint16_t) mac->lim.gLimMlmState; + + } else { + qdf_mem_copy(peEvent.bssid, pe_session->bssId, + sizeof(tSirMacAddr)); + peEvent.sme_state = (uint16_t) pe_session->limSmeState; + peEvent.mlm_state = (uint16_t) pe_session->limMlmState; + } + peEvent.event_type = eventType; + peEvent.status = status; + peEvent.reason_code = reasonCode; + + WLAN_HOST_DIAG_EVENT_REPORT(&peEvent, EVENT_WLAN_PE); + return; +} + +static void lim_diag_fill_mgmt_event_report(struct mac_context *mac_ctx, + tpSirMacMgmtHdr mac_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code, + struct host_event_wlan_mgmt_payload_type *mgmt_event) +{ + uint8_t length; + + qdf_mem_zero(mgmt_event, sizeof(*mgmt_event)); + mgmt_event->mgmt_type = mac_hdr->fc.type; + mgmt_event->mgmt_subtype = mac_hdr->fc.subType; + qdf_mem_copy(mgmt_event->self_mac_addr, session->self_mac_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(mgmt_event->bssid, mac_hdr->bssId, + QDF_MAC_ADDR_SIZE); + length = session->ssId.length; + if (length > WLAN_SSID_MAX_LEN) + length = WLAN_SSID_MAX_LEN; + qdf_mem_copy(mgmt_event->ssid, session->ssId.ssId, length); + mgmt_event->ssid_len = length; + mgmt_event->operating_channel = wlan_reg_freq_to_chan( + mac_ctx->pdev, session->curr_op_freq); + mgmt_event->result_code = result_code; + mgmt_event->reason_code = reason_code; +} + +void lim_diag_mgmt_tx_event_report(struct mac_context *mac_ctx, void *mgmt_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code) +{ + tpSirMacMgmtHdr mac_hdr = mgmt_hdr; + + WLAN_HOST_DIAG_EVENT_DEF(mgmt_event, + struct host_event_wlan_mgmt_payload_type); + if (!session || !mac_hdr) { + pe_err("not valid input"); + return; + } + lim_diag_fill_mgmt_event_report(mac_ctx, mac_hdr, session, + result_code, reason_code, &mgmt_event); + + pe_debug("TX frame: type:%d sub_type:%d seq_num:%d ssid:" QDF_SSID_FMT " selfmacaddr:" QDF_MAC_ADDR_FMT " bssid:" QDF_MAC_ADDR_FMT " channel:%d", + mgmt_event.mgmt_type, mgmt_event.mgmt_subtype, + ((mac_hdr->seqControl.seqNumHi << 4) | + mac_hdr->seqControl.seqNumLo), + QDF_SSID_REF(mgmt_event.ssid_len, mgmt_event.ssid), + QDF_MAC_ADDR_REF(mgmt_event.self_mac_addr), + QDF_MAC_ADDR_REF(mgmt_event.bssid), + mgmt_event.operating_channel); + WLAN_HOST_DIAG_EVENT_REPORT(&mgmt_event, EVENT_WLAN_HOST_MGMT_TX_V2); +} + +void lim_diag_mgmt_rx_event_report(struct mac_context *mac_ctx, void *mgmt_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code) +{ + tpSirMacMgmtHdr mac_hdr = mgmt_hdr; + + WLAN_HOST_DIAG_EVENT_DEF(mgmt_event, + struct host_event_wlan_mgmt_payload_type); + if (!session || !mac_hdr) { + pe_debug("not valid input"); + return; + } + lim_diag_fill_mgmt_event_report(mac_ctx, mac_hdr, session, + result_code, reason_code, &mgmt_event); + pe_debug("RX frame: type:%d sub_type:%d seq_num:%d ssid:" QDF_SSID_FMT " selfmacaddr:" QDF_MAC_ADDR_FMT " bssid:" QDF_MAC_ADDR_FMT " channel:%d", + mgmt_event.mgmt_type, mgmt_event.mgmt_subtype, + ((mac_hdr->seqControl.seqNumHi << 4) | + mac_hdr->seqControl.seqNumLo), + QDF_SSID_REF(mgmt_event.ssid_len, mgmt_event.ssid), + QDF_MAC_ADDR_REF(mgmt_event.self_mac_addr), + QDF_MAC_ADDR_REF(mgmt_event.bssid), + mgmt_event.operating_channel); + WLAN_HOST_DIAG_EVENT_REPORT(&mgmt_event, EVENT_WLAN_HOST_MGMT_RX_V2); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/* Returns length of P2P stream and Pointer ie passed to this function is filled with noa stream */ + +uint8_t lim_build_p2p_ie(struct mac_context *mac, uint8_t *ie, uint8_t *data, + uint8_t ie_len) +{ + int length = 0; + uint8_t *ptr = ie; + + ptr[length++] = WLAN_ELEMID_VENDOR; + ptr[length++] = ie_len + SIR_MAC_P2P_OUI_SIZE; + qdf_mem_copy(&ptr[length], SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE); + qdf_mem_copy(&ptr[length + SIR_MAC_P2P_OUI_SIZE], data, ie_len); + return ie_len + SIR_P2P_IE_HEADER_LEN; +} + +/* Returns length of NoA stream and Pointer pNoaStream passed to this function is filled with noa stream */ +uint8_t lim_get_noa_attr_stream(struct mac_context *mac, uint8_t *pNoaStream, + struct pe_session *pe_session) +{ + uint8_t len = 0; + + uint8_t *pBody = pNoaStream; + + if ((pe_session) && (pe_session->valid) && + (pe_session->opmode == QDF_P2P_GO_MODE)) { + if ((!(pe_session->p2pGoPsUpdate.uNoa1Duration)) + && (!(pe_session->p2pGoPsUpdate.uNoa2Duration)) + && (!pe_session->p2pGoPsUpdate.oppPsFlag) + ) + return 0; /* No NoA Descriptor then return 0 */ + + pBody[0] = SIR_P2P_NOA_ATTR; + + pBody[3] = pe_session->p2pGoPsUpdate.index; + pBody[4] = + pe_session->p2pGoPsUpdate.ctWin | (pe_session-> + p2pGoPsUpdate. + oppPsFlag << 7); + len = 5; + pBody += len; + + if (pe_session->p2pGoPsUpdate.uNoa1Duration) { + *pBody = pe_session->p2pGoPsUpdate.uNoa1IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(pe_session->p2pGoPsUpdate. + uNoa1Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(pe_session->p2pGoPsUpdate. + uNoa1Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(pe_session->p2pGoPsUpdate. + uNoa1StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + if (pe_session->p2pGoPsUpdate.uNoa2Duration) { + *pBody = pe_session->p2pGoPsUpdate.uNoa2IntervalCnt; + pBody += 1; + len += 1; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(pe_session->p2pGoPsUpdate. + uNoa2Duration); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(pe_session->p2pGoPsUpdate. + uNoa2Interval); + pBody += sizeof(uint32_t); + len += 4; + + *((uint32_t *) (pBody)) = + sir_swap_u32if_needed(pe_session->p2pGoPsUpdate. + uNoa2StartTime); + pBody += sizeof(uint32_t); + len += 4; + + } + + pBody = pNoaStream + 1; + *((uint16_t *) (pBody)) = sir_swap_u16if_needed(len - 3); /*one byte for Attr and 2 bytes for length */ + + return len; + + } + return 0; + +} + +void pe_set_resume_channel(struct mac_context *mac, uint16_t channel, + ePhyChanBondState phyCbState) +{ + + mac->lim.gResumeChannel = channel; + mac->lim.gResumePhyCbState = phyCbState; +} + +bool lim_isconnected_on_dfs_freq(struct mac_context *mac_ctx, + qdf_freq_t oper_freq) +{ + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, oper_freq)) + return true; + else + return false; +} + +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param) +{ + struct mac_context *mac = (struct mac_context *) pMacGlobal; + tPmfSaQueryTimerId timerId; + struct pe_session *pe_session; + tpDphHashNode pSta; + uint8_t maxretries; + + pe_debug("SA Query timer fires"); + timerId.value = param; + + /* Check that SA Query is in progress */ + pe_session = pe_find_session_by_session_id(mac, + timerId.fields.sessionId); + if (!pe_session) { + pe_err("Session does not exist for given session ID: %d", + timerId.fields.sessionId); + return; + } + pSta = dph_get_hash_entry(mac, timerId.fields.peerIdx, + &pe_session->dph.dphHashTable); + if (!pSta) { + pe_err("Entry does not exist for given peer index: %d", + timerId.fields.peerIdx); + return; + } + if (DPH_SA_QUERY_IN_PROGRESS != pSta->pmfSaQueryState) + return; + + /* Increment the retry count, check if reached maximum */ + maxretries = mac->mlme_cfg->gen.pmf_sa_query_max_retries; + pSta->pmfSaQueryRetryCount++; + if (pSta->pmfSaQueryRetryCount >= maxretries) { + pe_err("SA Query timed out,Deleting STA: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pSta->staAddr)); + lim_send_disassoc_mgmt_frame(mac, + REASON_DISASSOC_DUE_TO_INACTIVITY, + pSta->staAddr, pe_session, false); + lim_trigger_sta_deletion(mac, pSta, pe_session); + pSta->pmfSaQueryState = DPH_SA_QUERY_TIMED_OUT; + return; + } + /* Retry SA Query */ + lim_send_sa_query_request_frame(mac, + (uint8_t *) &(pSta-> + pmfSaQueryCurrentTransId), + pSta->staAddr, pe_session); + pSta->pmfSaQueryCurrentTransId++; + pe_debug("Starting SA Query retry: %d", pSta->pmfSaQueryRetryCount); + if (tx_timer_activate(&pSta->pmfSaQueryTimer) != TX_SUCCESS) { + pe_err("PMF SA Query timer activation failed!"); + pSta->pmfSaQueryState = DPH_SA_QUERY_NOT_IN_PROGRESS; + } +} + +/** + * lim_get_update_bw_allow() whether bw can be sent to target directly + * @session: pe session + * @new_bw: bandwdith to set + * @update_allow: return true if bw and puncture can be updated directly + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_get_update_bw_allow(struct pe_session *session, + enum phy_ch_width new_bw, + bool *update_allow) +{ + enum phy_ch_width ch_width; + struct wlan_objmgr_psoc *psoc; + enum wlan_phymode phy_mode; + QDF_STATUS status = QDF_STATUS_E_INVAL; + + if (!session || !update_allow) { + pe_err("invalid input"); + return status; + } + *update_allow = false; + + psoc = wlan_vdev_get_psoc(session->vdev); + if (!psoc) { + pe_err("psoc object invalid"); + return status; + } + status = mlme_get_peer_phymode(psoc, session->bssId, &phy_mode); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("failed to get phy_mode %d mac: " QDF_MAC_ADDR_FMT, + status, QDF_MAC_ADDR_REF(session->bssId)); + return status; + } + ch_width = wlan_mlme_get_ch_width_from_phymode(phy_mode); + if (new_bw <= ch_width) + *update_allow = true; + + return status; +} + +bool lim_check_vht_op_mode_change(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t chanWidth, uint8_t *peerMac) +{ + QDF_STATUS status; + bool update_allow; + struct ch_params ch_params; + struct csa_offload_params *csa_param; + enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(pe_session->vdev); + + if (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) { + status = lim_get_update_bw_allow(pe_session, chanWidth, + &update_allow); + if (QDF_IS_STATUS_ERROR(status)) + return false; + } else { + update_allow = true; + } + + if (update_allow) { + tUpdateVHTOpMode tempParam; + + tempParam.opMode = chanWidth; + tempParam.smesessionId = pe_session->smeSessionId; + qdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_mode_update(mac, &tempParam, pe_session); + lim_update_tdls_2g_bw(pe_session); + + return true; + } + + if (!wlan_cm_is_vdev_connected(pe_session->vdev)) + return false; + + /* use vdev restart to update STA mode */ + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = chanWidth; + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + pe_session->curr_op_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + csa_param = qdf_mem_malloc(sizeof(*csa_param)); + if (!csa_param) { + pe_err("csa_param allocation fails"); + return false; + } + + csa_param->channel = wlan_reg_freq_to_chan(mac->pdev, + pe_session->curr_op_freq); + csa_param->csa_chan_freq = pe_session->curr_op_freq; + csa_param->new_ch_width = ch_params.ch_width; + csa_param->new_ch_freq_seg1 = ch_params.center_freq_seg0; + csa_param->new_ch_freq_seg2 = ch_params.center_freq_seg1; + qdf_copy_macaddr(&csa_param->bssid, + (struct qdf_mac_addr *)pe_session->bssId); + lim_handle_sta_csa_param(mac, csa_param, false); + + return true; +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +bool lim_send_he_ie_update(struct mac_context *mac_ctx, struct pe_session *pe_session) +{ + QDF_STATUS status; + + status = wma_update_he_ops_ie(cds_get_context(QDF_MODULE_ID_WMA), + pe_session->smeSessionId, + &pe_session->he_op); + if (QDF_IS_STATUS_ERROR(status)) + return false; + + return true; +} +#endif + +bool lim_set_nss_change(struct mac_context *mac, struct pe_session *pe_session, + uint8_t rxNss, uint8_t *peerMac) +{ + tUpdateRxNss tempParam; + + if (!rxNss) { + pe_err("Invalid rxNss value: %u", rxNss); + return false; + } + + tempParam.rxNss = rxNss; + tempParam.smesessionId = pe_session->smeSessionId; + qdf_mem_copy(tempParam.peer_mac, peerMac, sizeof(tSirMacAddr)); + + lim_send_rx_nss_update(mac, &tempParam, pe_session); + + return true; +} + +bool lim_check_membership_user_position(struct mac_context *mac, + struct pe_session *pe_session, + uint32_t membership, + uint32_t userPosition) +{ + tUpdateMembership tempParamMembership; + tUpdateUserPos tempParamUserPosition; + + tempParamMembership.membership = membership; + tempParamMembership.smesessionId = pe_session->smeSessionId; + qdf_mem_copy(tempParamMembership.peer_mac, pe_session->bssId, + sizeof(tSirMacAddr)); + + lim_set_membership(mac, &tempParamMembership, pe_session); + + tempParamUserPosition.userPos = userPosition; + tempParamUserPosition.smesessionId = pe_session->smeSessionId; + qdf_mem_copy(tempParamUserPosition.peer_mac, pe_session->bssId, + sizeof(tSirMacAddr)); + + lim_set_user_pos(mac, &tempParamUserPosition, pe_session); + + return true; +} + +void lim_get_short_slot_from_phy_mode(struct mac_context *mac, struct pe_session *pe_session, + uint32_t phyMode, uint8_t *pShortSlotEnabled) +{ + uint8_t val = 0; + + /* only 2.4G band should have short slot enable, rest it should be default */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + /* short slot is default in all other modes */ + if ((pe_session->opmode == QDF_SAP_MODE) || + (pe_session->opmode == QDF_IBSS_MODE) || + (pe_session->opmode == QDF_P2P_GO_MODE)) { + val = true; + } + /* Program Polaris based on AP capability */ + if (pe_session->limMlmState == eLIM_MLM_WT_JOIN_BEACON_STATE) { + /* Joining BSS. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(pe_session-> + limCurrentBssCaps); + } else if (pe_session->limMlmState == + eLIM_MLM_WT_REASSOC_RSP_STATE) { + /* Reassociating with AP. */ + val = + SIR_MAC_GET_SHORT_SLOT_TIME(pe_session-> + limReassocBssCaps); + } + } else { + /* + * 11B does not short slot and short slot is default + * for 11A mode. Hence, not need to set this bit + */ + val = false; + } + + pe_debug("phyMode: %u shortslotsupported: %u", phyMode, val); + *pShortSlotEnabled = val; +} + +/** + * + * \brief This function is called by various LIM modules to correctly set + * the Protected bit in the Frame Control Field of the 802.11 frame MAC header + * + * + * \param mac Pointer to Global MAC structure + * + * \param pe_session Pointer to session corresponding to the connection + * + * \param peer Peer address of the STA to which the frame is to be sent + * + * \param pMacHdr Pointer to the frame MAC header + * + * \return nothing + * + * + */ +void +lim_set_protected_bit(struct mac_context *mac, + struct pe_session *pe_session, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr) +{ + uint16_t aid; + tpDphHashNode sta; + + sta = dph_lookup_hash_entry(mac, peer, &aid, + &pe_session->dph.dphHashTable); + if (sta) { + /* rmfenabled will be set at the time of addbss. + * but sometimes EAP auth fails and keys are not + * installed then if we send any management frame + * like deauth/disassoc with this bit set then + * firmware crashes. so check for keys are + * installed or not also before setting the bit + */ + if (sta->rmfEnabled && sta->is_key_installed) + pMacHdr->fc.wep = 1; + + pe_debug("wep:%d rmf:%d is_key_set:%d", pMacHdr->fc.wep, + sta->rmfEnabled, sta->is_key_installed); + } +} /*** end lim_set_protected_bit() ***/ + +void lim_set_ht_caps(struct mac_context *p_mac, uint8_t *p_ie_start, + uint32_t num_bytes) +{ + const uint8_t *p_ie = NULL; + tDot11fIEHTCaps dot11_ht_cap = {0,}; + + populate_dot11f_ht_caps(p_mac, NULL, &dot11_ht_cap); + p_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_HTCAPS, + p_ie_start, num_bytes); + pe_debug("p_ie: %pK dot11_ht_cap.supportedMCSSet[0]: 0x%x", + p_ie, dot11_ht_cap.supportedMCSSet[0]); + if (p_ie) { + /* convert from unpacked to packed structure */ + tHtCaps *p_ht_cap = (tHtCaps *) &p_ie[2]; + + p_ht_cap->advCodingCap = dot11_ht_cap.advCodingCap; + p_ht_cap->supportedChannelWidthSet = + dot11_ht_cap.supportedChannelWidthSet; + p_ht_cap->mimoPowerSave = dot11_ht_cap.mimoPowerSave; + p_ht_cap->greenField = dot11_ht_cap.greenField; + p_ht_cap->shortGI20MHz = dot11_ht_cap.shortGI20MHz; + p_ht_cap->shortGI40MHz = dot11_ht_cap.shortGI40MHz; + p_ht_cap->txSTBC = dot11_ht_cap.txSTBC; + p_ht_cap->rxSTBC = dot11_ht_cap.rxSTBC; + p_ht_cap->delayedBA = dot11_ht_cap.delayedBA; + p_ht_cap->maximalAMSDUsize = dot11_ht_cap.maximalAMSDUsize; + p_ht_cap->dsssCckMode40MHz = dot11_ht_cap.dsssCckMode40MHz; + p_ht_cap->psmp = dot11_ht_cap.psmp; + p_ht_cap->stbcControlFrame = dot11_ht_cap.stbcControlFrame; + p_ht_cap->lsigTXOPProtection = dot11_ht_cap.lsigTXOPProtection; + p_ht_cap->maxRxAMPDUFactor = dot11_ht_cap.maxRxAMPDUFactor; + p_ht_cap->mpduDensity = dot11_ht_cap.mpduDensity; + qdf_mem_copy((void *)p_ht_cap->supportedMCSSet, + (void *)(dot11_ht_cap.supportedMCSSet), + sizeof(p_ht_cap->supportedMCSSet)); + p_ht_cap->pco = dot11_ht_cap.pco; + p_ht_cap->transitionTime = dot11_ht_cap.transitionTime; + p_ht_cap->mcsFeedback = dot11_ht_cap.mcsFeedback; + p_ht_cap->txBF = dot11_ht_cap.txBF; + p_ht_cap->rxStaggeredSounding = + dot11_ht_cap.rxStaggeredSounding; + p_ht_cap->txStaggeredSounding = + dot11_ht_cap.txStaggeredSounding; + p_ht_cap->rxZLF = dot11_ht_cap.rxZLF; + p_ht_cap->txZLF = dot11_ht_cap.txZLF; + p_ht_cap->implicitTxBF = dot11_ht_cap.implicitTxBF; + p_ht_cap->calibration = dot11_ht_cap.calibration; + p_ht_cap->explicitCSITxBF = dot11_ht_cap.explicitCSITxBF; + p_ht_cap->explicitUncompressedSteeringMatrix = + dot11_ht_cap.explicitUncompressedSteeringMatrix; + p_ht_cap->explicitBFCSIFeedback = + dot11_ht_cap.explicitBFCSIFeedback; + p_ht_cap->explicitUncompressedSteeringMatrixFeedback = + dot11_ht_cap.explicitUncompressedSteeringMatrixFeedback; + p_ht_cap->explicitCompressedSteeringMatrixFeedback = + dot11_ht_cap.explicitCompressedSteeringMatrixFeedback; + p_ht_cap->csiNumBFAntennae = dot11_ht_cap.csiNumBFAntennae; + p_ht_cap->uncompressedSteeringMatrixBFAntennae = + dot11_ht_cap.uncompressedSteeringMatrixBFAntennae; + p_ht_cap->compressedSteeringMatrixBFAntennae = + dot11_ht_cap.compressedSteeringMatrixBFAntennae; + p_ht_cap->antennaSelection = dot11_ht_cap.antennaSelection; + p_ht_cap->explicitCSIFeedbackTx = + dot11_ht_cap.explicitCSIFeedbackTx; + p_ht_cap->antennaIndicesFeedbackTx = + dot11_ht_cap.antennaIndicesFeedbackTx; + p_ht_cap->explicitCSIFeedback = + dot11_ht_cap.explicitCSIFeedback; + p_ht_cap->antennaIndicesFeedback = + dot11_ht_cap.antennaIndicesFeedback; + p_ht_cap->rxAS = dot11_ht_cap.rxAS; + p_ht_cap->txSoundingPPDUs = dot11_ht_cap.txSoundingPPDUs; + } +} + +void lim_set_vht_caps(struct mac_context *p_mac, + uint8_t *p_ie_start, uint32_t num_bytes) +{ + const uint8_t *p_ie = NULL; + tDot11fIEVHTCaps dot11_vht_cap; + + populate_dot11f_vht_caps(p_mac, NULL, &dot11_vht_cap); + p_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_VHTCAPS, p_ie_start, + num_bytes); + if (p_ie) { + tSirMacVHTCapabilityInfo *vht_cap = + (tSirMacVHTCapabilityInfo *) &p_ie[2]; + tSirVhtMcsInfo *vht_mcs = (tSirVhtMcsInfo *) &p_ie[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + + union { + uint16_t u_value; + tSirMacVHTRxSupDataRateInfo vht_rx_supp_rate; + tSirMacVHTTxSupDataRateInfo vht_tx_supp_rate; + } u_vht_data_rate_info; + + vht_cap->maxMPDULen = dot11_vht_cap.maxMPDULen; + vht_cap->supportedChannelWidthSet = + dot11_vht_cap.supportedChannelWidthSet; + vht_cap->ldpcCodingCap = dot11_vht_cap.ldpcCodingCap; + vht_cap->shortGI80MHz = dot11_vht_cap.shortGI80MHz; + vht_cap->shortGI160and80plus80MHz = + dot11_vht_cap.shortGI160and80plus80MHz; + vht_cap->txSTBC = dot11_vht_cap.txSTBC; + vht_cap->rxSTBC = dot11_vht_cap.rxSTBC; + vht_cap->suBeamFormerCap = dot11_vht_cap.suBeamFormerCap; + vht_cap->suBeamformeeCap = dot11_vht_cap.suBeamformeeCap; + vht_cap->csnofBeamformerAntSup = + dot11_vht_cap.csnofBeamformerAntSup; + vht_cap->numSoundingDim = dot11_vht_cap.numSoundingDim; + vht_cap->muBeamformerCap = dot11_vht_cap.muBeamformerCap; + vht_cap->muBeamformeeCap = dot11_vht_cap.muBeamformeeCap; + vht_cap->vhtTXOPPS = dot11_vht_cap.vhtTXOPPS; + vht_cap->htcVHTCap = dot11_vht_cap.htcVHTCap; + vht_cap->maxAMPDULenExp = dot11_vht_cap.maxAMPDULenExp; + vht_cap->vhtLinkAdaptCap = dot11_vht_cap.vhtLinkAdaptCap; + vht_cap->rxAntPattern = dot11_vht_cap.rxAntPattern; + vht_cap->txAntPattern = dot11_vht_cap.txAntPattern; + vht_cap->extended_nss_bw_supp = + dot11_vht_cap.extended_nss_bw_supp; + + /* Populate VHT MCS Information */ + vht_mcs->rxMcsMap = dot11_vht_cap.rxMCSMap; + u_vht_data_rate_info.vht_rx_supp_rate.rxSupDataRate = + dot11_vht_cap.rxHighSupDataRate; + u_vht_data_rate_info.vht_rx_supp_rate.max_nsts_total = + dot11_vht_cap.max_nsts_total; + vht_mcs->rxHighest = u_vht_data_rate_info.u_value; + + vht_mcs->txMcsMap = dot11_vht_cap.txMCSMap; + u_vht_data_rate_info.vht_tx_supp_rate.txSupDataRate = + dot11_vht_cap.txSupDataRate; + u_vht_data_rate_info.vht_tx_supp_rate.vht_extended_nss_bw_cap = + dot11_vht_cap.vht_extended_nss_bw_cap; + vht_mcs->txHighest = u_vht_data_rate_info.u_value; + } +} + +/* + * Firmware will send RTS for every frame and also will disable SIFS bursting + * if value 0x11 is sent for RTS profile. + */ +#define A_EDCA_SCC_RTS_PROFILE_VALUE 0x11 +#define MAX_NUMBER_OF_SINGLE_PORT_CONC_CONNECTIONS 2 + +static void lim_update_sta_edca_params(struct mac_context *mac, + struct pe_session *sta_session) +{ + uint8_t i; + + for (i = QCA_WLAN_AC_BE; i < QCA_WLAN_AC_ALL; i++) { + sta_session->gLimEdcaParamsActive[i] = + sta_session->gLimEdcaParams[i]; + } + lim_send_edca_params(mac, + sta_session->gLimEdcaParamsActive, + sta_session->vdev_id, false); +} + +static void check_and_send_vendor_oui(struct mac_context *mac, + struct pe_session *sta_session) +{ + QDF_STATUS status; + uint8_t *tmp_ptr = NULL; + struct element_info frame; + + status = wlan_scan_get_entry_by_mac_addr( + mac->pdev, + (struct qdf_mac_addr *)&sta_session->bssId, + &frame); + if (QDF_IS_STATUS_ERROR(status) && !frame.len) { + pe_err("Failed to get scan entry for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_session->bssId)); + return; + } + + tmp_ptr = frame.ptr; + tmp_ptr += SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET; + frame.len -= SIR_MAC_HDR_LEN_3A + SIR_MAC_B_PR_SSID_OFFSET; + + if (!lim_enable_cts_to_self_for_exempted_iot_ap( + mac, sta_session, + tmp_ptr, frame.len)) + wma_cli_set_command(sta_session->vdev_id, + wmi_vdev_param_enable_rtscts, + cfg_get(mac->psoc, + CFG_ENABLE_FW_RTS_PROFILE), + VDEV_CMD); + qdf_mem_free(frame.ptr); +} + +/** + * lim_check_conc_and_send_edca() - Function to check and update EDCA params + * and RTS profile based on STA/SAP + * concurrency. If updated, it will also send + * the updated parameters to FW. It will update + * EDCA params and RTS profile such that: + * 1) For STA and SAP concurrency, send STA's AP EDCA params to fw. + * Also, for SAP or P2P Go, update the value in Broadcast EDCA params + * as well so that it should be broadcasted to other stations connected + * to that BSS. Also, update the RTS profile value to 0x11 for which + * FW will send RTS for every frame and will also disable SIFS + * bursting. + * + * 2) For standalone STA (can even happen after SAP/P2P Go + * disconnects), if the parameters are updated, reset them to original + * parameters and send them to FW. Also, update the RTS profile + * value to which it was set before. + * + * 3) For standalone SAP (can even happen after STA disconnects), + * if the parameters are updated, reset them to original + * parameters and send them to FW and reset the Broadcast EDCA params + * as well so that it should be broadcasted to other stations connected + * to that BSS Also, update the RTS profile value to which it was set + * before. + * + * This update is needed because throughput drop was seen because of + * inconsistency in the EDCA params used in STA-SAP or STA-P2P_GO concurrency. + * + * Return: void + */ + +static void lim_check_conc_and_send_edca(struct mac_context *mac, + struct pe_session *sta_session, + struct pe_session *sap_session) +{ + bool params_update_required = false; + uint8_t i; + tpDphHashNode sta_ds = NULL; + uint16_t assoc_id; + + if (sta_session && sap_session && + (sta_session->curr_op_freq == + sap_session->curr_op_freq)) { + /* RTS profile update to FW */ + wma_cli_set_command(sap_session->vdev_id, + wmi_vdev_param_enable_rtscts, + A_EDCA_SCC_RTS_PROFILE_VALUE, + VDEV_CMD); + wma_cli_set_command(sta_session->vdev_id, + wmi_vdev_param_enable_rtscts, + A_EDCA_SCC_RTS_PROFILE_VALUE, + VDEV_CMD); + + sta_ds = dph_lookup_hash_entry(mac, + sta_session->bssId, + &assoc_id, + &sta_session->dph.dphHashTable); + + if (!sta_ds) { + pe_debug("No STA DS entry found for " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sta_session->bssId)); + return; + } + + if (!sta_ds->qos.peer_edca_params.length) { + pe_debug("No sta_ds edca_params present"); + return; + } + + /* + * Here what we do is disable A-EDCA by sending the edca params of + * connected AP which we got as part of assoc resp So as these EDCA + * params are updated per mac , its fine to send for SAP which will + * be used for STA as well on the same channel. No need to send for + * both SAP and STA. + */ + + sap_session->gLimEdcaParamsBC[QCA_WLAN_AC_BE] = + sta_ds->qos.peer_edca_params.acbe; + sap_session->gLimEdcaParamsBC[QCA_WLAN_AC_BK] = + sta_ds->qos.peer_edca_params.acbk; + sap_session->gLimEdcaParamsBC[QCA_WLAN_AC_VI] = + sta_ds->qos.peer_edca_params.acvi; + sap_session->gLimEdcaParamsBC[QCA_WLAN_AC_VO] = + sta_ds->qos.peer_edca_params.acvo; + + sap_session->gLimEdcaParamsActive[QCA_WLAN_AC_BE] = + sta_ds->qos.peer_edca_params.acbe; + sap_session->gLimEdcaParamsActive[QCA_WLAN_AC_BK] = + sta_ds->qos.peer_edca_params.acbk; + sap_session->gLimEdcaParamsActive[QCA_WLAN_AC_VI] = + sta_ds->qos.peer_edca_params.acvi; + sap_session->gLimEdcaParamsActive[QCA_WLAN_AC_VO] = + sta_ds->qos.peer_edca_params.acvo; + + for (i = QCA_WLAN_AC_BE; i < QCA_WLAN_AC_ALL; i++) { + sta_session->gLimEdcaParamsActive[i] = + sap_session->gLimEdcaParamsActive[i]; + } + /* For AP, the bssID is stored in LIM Global context. */ + lim_send_edca_params(mac, sap_session->gLimEdcaParamsActive, + sap_session->vdev_id, false); + + sap_session->gLimEdcaParamSetCount++; + csr_update_beacon(mac); + } else if (!sap_session && sta_session) { + /* + * Enable A-EDCA for standalone STA. The original EDCA parameters are + * stored in gLimEdcaParams (computed by sch_beacon_edca_process()), + * if active parameters are not equal that means they have been updated + * because of conncurrency and are need to be restored now + */ + check_and_send_vendor_oui(mac, sta_session); + + for (i = QCA_WLAN_AC_BE; i < QCA_WLAN_AC_ALL; i++) { + if (qdf_mem_cmp(&sta_session->gLimEdcaParamsActive[i], + &sta_session->gLimEdcaParams[i], + sizeof(tSirMacEdcaParamRecord))) { + pe_debug("local sta EDCA params are not equal to Active EDCA params, hence update required"); + params_update_required = true; + break; + } + } + + if (params_update_required) { + lim_update_sta_edca_params(mac, + sta_session); + } + } else { + /* + * For STA+SAP/GO DBS, STA+SAP/GO MCC or standalone SAP/GO + */ + + wma_cli_set_command(sap_session->vdev_id, + wmi_vdev_param_enable_rtscts, + cfg_get(mac->psoc, + CFG_ENABLE_FW_RTS_PROFILE), + VDEV_CMD); + if (sta_session) { + check_and_send_vendor_oui(mac, sta_session); + } + + for (i = QCA_WLAN_AC_BE; i < QCA_WLAN_AC_ALL; i++) { + if (qdf_mem_cmp(&sap_session->gLimEdcaParamsActive[i], + &sap_session->gLimEdcaParams[i], + sizeof(tSirMacEdcaParamRecord))) { + pe_debug("local sap EDCA params are not equal to Active EDCA params, hence update required"); + params_update_required = true; + break; + } + } + + if (params_update_required) { + for (i = QCA_WLAN_AC_BE; i < QCA_WLAN_AC_ALL; i++) { + sap_session->gLimEdcaParamsActive[i] = + sap_session->gLimEdcaParams[i]; + } + lim_send_edca_params(mac, + sap_session->gLimEdcaParamsActive, + sap_session->vdev_id, false); + sch_qos_update_broadcast(mac, sap_session); + + /* + * In case of mcc, where cb can come from scc to mcc switch where we + * need to restore the default parameters + */ + if (sta_session) { + lim_update_sta_edca_params(mac, + sta_session); + } + } + } +} + +void lim_send_conc_params_update(void) +{ + struct pe_session *sta_session = NULL; + struct pe_session *sap_session = NULL; + uint8_t i; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return; + + if (!mac->mlme_cfg->edca_params.enable_edca_params || + (policy_mgr_get_connection_count(mac->psoc) > + MAX_NUMBER_OF_SINGLE_PORT_CONC_CONNECTIONS)) { + pe_debug("A-EDCA not enabled or max number of connections: %d", + policy_mgr_get_connection_count(mac->psoc)); + return; + } + + for (i = 0; i < mac->lim.maxBssId; i++) { + /* + * Finding whether STA or Go session exists + */ + if (sta_session && sap_session) + break; + + if ((mac->lim.gpSession[i].valid) && + (mac->lim.gpSession[i].limSystemRole == + eLIM_STA_ROLE)) { + sta_session = &mac->lim.gpSession[i]; + continue; + } + if ((mac->lim.gpSession[i].valid) && + ((mac->lim.gpSession[i].limSystemRole == eLIM_AP_ROLE) || + (mac->lim.gpSession[i].limSystemRole == + eLIM_P2P_DEVICE_GO))) { + sap_session = &mac->lim.gpSession[i]; + continue; + } + } + + if (!(sta_session || sap_session)) { + pe_debug("No sta or sap or P2P go session"); + return; + } + + pe_debug("Valid STA session: %d Valid SAP session: %d", + (sta_session ? sta_session->valid : 0), + (sap_session ? sap_session->valid : 0)); + lim_check_conc_and_send_edca(mac, sta_session, sap_session); +} + +/** + * lim_validate_received_frame_a1_addr() - To validate received frame's A1 addr + * @mac_ctx: pointer to mac context + * @a1: received frame's a1 address which is nothing but our self address + * @session: PE session pointer + * + * This routine will validate, A1 address of the received frame + * + * Return: true or false + */ +bool lim_validate_received_frame_a1_addr(struct mac_context *mac_ctx, + tSirMacAddr a1, struct pe_session *session) +{ + if (!mac_ctx || !session) { + pe_err("mac or session context is null"); + /* let main routine handle it */ + return true; + } + if (IEEE80211_IS_MULTICAST(a1) || QDF_IS_ADDR_BROADCAST(a1)) { + /* just for fail safe, don't handle MC/BC a1 in this routine */ + return true; + } + if (qdf_mem_cmp(a1, session->self_mac_addr, 6)) { + pe_err("Invalid A1 address in received frame"); + return false; + } + return true; +} + +/** + * lim_check_and_reset_protection_params() - reset protection related parameters + * + * @mac_ctx: pointer to global mac structure + * + * resets protection related global parameters if the pe active session count + * is zero. + * + * Return: None + */ +void lim_check_and_reset_protection_params(struct mac_context *mac_ctx) +{ + if (!pe_get_active_session_count(mac_ctx)) { + mac_ctx->lim.gHTOperMode = eSIR_HT_OP_MODE_PURE; + } +} + +/** + * lim_set_stads_rtt_cap() - update station node RTT capability + * @sta_ds: Station hash node + * @ext_cap: Pointer to extended capability + * @mac_ctx: global MAC context + * + * This function update hash node's RTT capability based on received + * Extended capability IE. + * + * Return: None + */ +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + struct mac_context *mac_ctx) +{ + sta_ds->timingMeasCap = 0; + sta_ds->timingMeasCap |= (ext_cap->timing_meas) ? + RTT_TIMING_MEAS_CAPABILITY : + RTT_INVALID; + sta_ds->timingMeasCap |= (ext_cap->fine_time_meas_initiator) ? + RTT_FINE_TIME_MEAS_INITIATOR_CAPABILITY : + RTT_INVALID; + sta_ds->timingMeasCap |= (ext_cap->fine_time_meas_responder) ? + RTT_FINE_TIME_MEAS_RESPONDER_CAPABILITY : + RTT_INVALID; + + pe_debug("ExtCap present, timingMeas: %d Initiator: %d Responder: %d", + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); +} + +#ifdef WLAN_SUPPORT_TWT +void lim_set_peer_twt_cap(struct pe_session *session, struct s_ext_cap *ext_cap) +{ + if (session->enable_session_twt_support) { + session->peer_twt_requestor = ext_cap->twt_requestor_support; + session->peer_twt_responder = ext_cap->twt_responder_support; + } + + pe_debug("Ext Cap peer TWT requestor: %d, responder: %d, enable_twt %d", + ext_cap->twt_requestor_support, + ext_cap->twt_responder_support, + session->enable_session_twt_support); +} +#endif + +/** + * lim_send_ie() - sends IE to wma + * @mac_ctx: global MAC context + * @vdev_id: vdev_id + * @eid: IE id + * @band: band for which IE is intended + * @buf: buffer containing IE + * @len: length of buffer + * + * This function sends the IE data to WMA. + * + * Return: status of operation + */ +static QDF_STATUS lim_send_ie(struct mac_context *mac_ctx, uint32_t vdev_id, + uint8_t eid, enum cds_band_type band, + uint8_t *buf, uint32_t len) +{ + struct vdev_ie_info *ie_msg; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + /* Allocate memory for the WMI request */ + ie_msg = qdf_mem_malloc(sizeof(*ie_msg) + len); + if (!ie_msg) + return QDF_STATUS_E_NOMEM; + + ie_msg->vdev_id = vdev_id; + ie_msg->ie_id = eid; + ie_msg->length = len; + ie_msg->band = band; + /* IE data buffer starts at end of the struct */ + ie_msg->data = (uint8_t *)&ie_msg[1]; + + qdf_mem_copy(ie_msg->data, buf, len); + msg.type = WMA_SET_IE_INFO; + msg.bodyptr = ie_msg; + msg.reserved = 0; + + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (QDF_STATUS_SUCCESS != status) { + pe_err("Not able to post WMA_SET_IE_INFO to WMA"); + qdf_mem_free(ie_msg); + return status; + } + + return status; +} + +/** + * lim_get_rx_ldpc() - gets ldpc setting for given channel(band) + * @mac_ctx: global mac context + * @ch: channel enum for which ldpc setting is required + * Note: ch param is not absolute channel number rather it is + * channel number enum. + * + * Return: true if enabled and false otherwise + */ +static inline bool lim_get_rx_ldpc(struct mac_context *mac_ctx, + enum channel_enum ch) +{ + if (mac_ctx->mlme_cfg->ht_caps.ht_cap_info.adv_coding_cap && + wma_is_rx_ldpc_supported_for_channel(wlan_reg_ch_to_freq(ch))) + return true; + else + return false; +} + +/** + * lim_populate_mcs_set_ht_per_vdev() - update the MCS set according to vdev nss + * @mac_ctx: global mac context + * @ht_cap: pointer to ht caps + * @vdev_id: vdev for which IE is targeted + * @band: band for which the MCS set has to be updated + * + * This function updates the MCS set according to vdev nss + * + * Return: None + */ +static void lim_populate_mcs_set_ht_per_vdev(struct mac_context *mac_ctx, + struct sHtCaps *ht_cap, + uint8_t vdev_id, + uint8_t band) +{ + struct wlan_mlme_nss_chains *nss_chains_ini_cfg; + struct wlan_objmgr_vdev *vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + pe_err("Got NULL vdev obj, returning"); + return; + } + if (!ht_cap->supportedMCSSet[1]) + goto end; + nss_chains_ini_cfg = mlme_get_ini_vdev_config(vdev); + if (!nss_chains_ini_cfg) { + pe_err("nss chain dynamic config NULL"); + goto end; + } + + /* convert from unpacked to packed structure */ + if (nss_chains_ini_cfg->rx_nss[band] == 1) + ht_cap->supportedMCSSet[1] = 0; + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +/** + * lim_populate_mcs_set_vht_per_vdev() - update MCS set according to vdev nss + * @mac_ctx: global mac context + * @vht_caps: pointer to vht_caps + * @vdev_id: vdev for which IE is targeted + * @band: band for which the MCS set has to be updated + * + * This function updates the MCS set according to vdev nss + * + * Return: None + */ +static void lim_populate_mcs_set_vht_per_vdev(struct mac_context *mac_ctx, + uint8_t *vht_caps, + uint8_t vdev_id, + uint8_t band) +{ + struct wlan_mlme_nss_chains *nss_chains_ini_cfg; + tSirVhtMcsInfo *vht_mcs; + struct wlan_objmgr_vdev *vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_MLME_SB_ID); + if (!vdev) { + pe_err("Got NULL vdev obj, returning"); + return; + } + + nss_chains_ini_cfg = mlme_get_ini_vdev_config(vdev); + if (!nss_chains_ini_cfg) { + pe_err("nss chain dynamic config NULL"); + goto end; + } + + vht_mcs = (tSirVhtMcsInfo *)&vht_caps[2 + + sizeof(tSirMacVHTCapabilityInfo)]; + if (nss_chains_ini_cfg->tx_nss[band] == 1) { + /* Populate VHT MCS Information */ + vht_mcs->txMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->txHighest = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + + if (nss_chains_ini_cfg->rx_nss[band] == 1) { + /* Populate VHT MCS Information */ + vht_mcs->rxMcsMap |= DISABLE_NSS2_MCS; + vht_mcs->rxHighest = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + } + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_SB_ID); +} + +/** + * is_dot11mode_support_ht_cap() - Check dot11mode supports HT capability + * @dot11mode: dot11mode + * + * This function checks whether dot11mode support HT capability or not + * + * Return: True, if supports. False otherwise + */ +static bool is_dot11mode_support_ht_cap(enum csr_cfgdot11mode dot11mode) +{ + if ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || + (dot11mode == eCSR_CFG_DOT11_MODE_11N) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AC) || + (dot11mode == eCSR_CFG_DOT11_MODE_11N_ONLY) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AX) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) { + return true; + } + + return false; +} + +/** + * is_dot11mode_support_vht_cap() - Check dot11mode supports VHT capability + * @dot11mode: dot11mode + * + * This function checks whether dot11mode support VHT capability or not + * + * Return: True, if supports. False otherwise + */ +static bool is_dot11mode_support_vht_cap(enum csr_cfgdot11mode dot11mode) +{ + if ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AC) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AX) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) { + return true; + } + + return false; +} + +/** + * is_dot11mode_support_he_cap() - Check dot11mode supports HE capability + * @dot11mode: dot11mode + * + * This function checks whether dot11mode support HE capability or not + * + * Return: True, if supports. False otherwise + */ +static bool is_dot11mode_support_he_cap(enum csr_cfgdot11mode dot11mode) +{ + if ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AX) || + (dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) { + return true; + } + + return false; +} + +#ifdef WLAN_FEATURE_11BE +/** + * is_dot11mode_support_eht_cap() - Check dot11mode supports EHT capability + * @dot11mode: dot11mode + * + * This function checks whether dot11mode support EHT capability or not + * + * Return: True, if supports. False otherwise + */ +static bool is_dot11mode_support_eht_cap(enum csr_cfgdot11mode dot11mode) +{ + if ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) { + return true; + } + + return false; +} + +bool lim_is_session_chwidth_320mhz(struct pe_session *session) +{ + return session->ch_width == CH_WIDTH_320MHZ; +} +#else +static bool is_dot11mode_support_eht_cap(enum csr_cfgdot11mode dot11mode) +{ + return false; +} +#endif + +/** + * lim_send_ht_caps_ie() - gets HT capability and send to firmware via wma + * @mac_ctx: global mac context + * @device_mode: VDEV op mode + * @vdev_id: vdev for which IE is targeted + * + * This function gets HT capability and send to firmware via wma + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_send_ht_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + uint8_t ht_caps[DOT11F_IE_HTCAPS_MIN_LEN + 2] = {0}; + tHtCaps *p_ht_cap = (tHtCaps *)(&ht_caps[2]); + QDF_STATUS status_5g, status_2g; + bool nan_beamforming_supported; + + ht_caps[0] = DOT11F_EID_HTCAPS; + ht_caps[1] = DOT11F_IE_HTCAPS_MIN_LEN; + lim_set_ht_caps(mac_ctx, ht_caps, + DOT11F_IE_HTCAPS_MIN_LEN + 2); + /* Get LDPC and over write for 2G */ + p_ht_cap->advCodingCap = lim_get_rx_ldpc(mac_ctx, + CHAN_ENUM_2437); + /* Get self cap for HT40 support in 2G */ + if (lim_get_sta_cb_mode_for_24ghz(mac_ctx, vdev_id)) { + p_ht_cap->supportedChannelWidthSet = 1; + p_ht_cap->shortGI40MHz = 1; + } else { + p_ht_cap->supportedChannelWidthSet = 0; + p_ht_cap->shortGI40MHz = 0; + } + + lim_populate_mcs_set_ht_per_vdev(mac_ctx, p_ht_cap, vdev_id, + NSS_CHAINS_BAND_2GHZ); + + nan_beamforming_supported = + ucfg_nan_is_beamforming_supported(mac_ctx->psoc); + if (device_mode == QDF_NDI_MODE && !nan_beamforming_supported) { + p_ht_cap->txBF = 0; + p_ht_cap->implicitTxBF = 0; + p_ht_cap->explicitCSITxBF = 0; + } + + status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HTCAPS, + CDS_BAND_2GHZ, &ht_caps[2], + DOT11F_IE_HTCAPS_MIN_LEN); + /* + * Get LDPC and over write for 5G - using channel 64 because it + * is available in all reg domains. + */ + p_ht_cap->advCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_5320); + /* Get self cap for HT40 support in 5G */ + if (mac_ctx->roam.configParam.channelBondingMode5GHz) { + p_ht_cap->supportedChannelWidthSet = 1; + p_ht_cap->shortGI40MHz = 1; + } else { + p_ht_cap->supportedChannelWidthSet = 0; + p_ht_cap->shortGI40MHz = 0; + } + lim_populate_mcs_set_ht_per_vdev(mac_ctx, p_ht_cap, vdev_id, + NSS_CHAINS_BAND_5GHZ); + status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HTCAPS, + CDS_BAND_5GHZ, &ht_caps[2], + DOT11F_IE_HTCAPS_MIN_LEN); + + if (QDF_IS_STATUS_SUCCESS(status_2g) && + QDF_IS_STATUS_SUCCESS(status_5g)) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +/** + * lim_send_vht_caps_ie() - gets VHT capability and send to firmware via wma + * @mac_ctx: global mac context + * @device_mode: VDEV op mode + * @vdev_id: vdev for which IE is targeted + * + * This function gets VHT capability and send to firmware via wma + * + * Return: QDF_STATUS + */ +static QDF_STATUS lim_send_vht_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + uint8_t vht_caps[DOT11F_IE_VHTCAPS_MAX_LEN + 2] = {0}; + bool vht_for_2g_enabled = false, nan_beamforming_supported; + tSirMacVHTCapabilityInfo *p_vht_cap = + (tSirMacVHTCapabilityInfo *)(&vht_caps[2]); + QDF_STATUS status_5g, status_2g; + + vht_caps[0] = DOT11F_EID_VHTCAPS; + vht_caps[1] = DOT11F_IE_VHTCAPS_MAX_LEN; + lim_set_vht_caps(mac_ctx, vht_caps, DOT11F_IE_VHTCAPS_MIN_LEN + 2); + /* + * Get LDPC and over write for 5G - using channel 64 because it + * is available in all reg domains. + */ + p_vht_cap->ldpcCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_5320); + lim_populate_mcs_set_vht_per_vdev(mac_ctx, vht_caps, vdev_id, + NSS_CHAINS_BAND_5GHZ); + + nan_beamforming_supported = + ucfg_nan_is_beamforming_supported(mac_ctx->psoc); + if (device_mode == QDF_NDI_MODE && !nan_beamforming_supported) { + p_vht_cap->muBeamformeeCap = 0; + p_vht_cap->muBeamformerCap = 0; + p_vht_cap->suBeamformeeCap = 0; + p_vht_cap->suBeamFormerCap = 0; + } + /* + * Self VHT channel width for 5G is already negotiated + * with FW + */ + status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_VHTCAPS, + CDS_BAND_5GHZ, &vht_caps[2], + DOT11F_IE_VHTCAPS_MIN_LEN); + /* Send VHT CAP for 2.4G band based on CFG_ENABLE_VHT_FOR_24GHZ ini */ + ucfg_mlme_get_vht_for_24ghz(mac_ctx->psoc, &vht_for_2g_enabled); + + if (!vht_for_2g_enabled) + return status_5g; + + + /* Get LDPC and over write for 2G */ + p_vht_cap->ldpcCodingCap = lim_get_rx_ldpc(mac_ctx, CHAN_ENUM_2437); + /* Self VHT 80/160/80+80 channel width for 2G is 0 */ + p_vht_cap->supportedChannelWidthSet = 0; + p_vht_cap->shortGI80MHz = 0; + p_vht_cap->shortGI160and80plus80MHz = 0; + lim_populate_mcs_set_vht_per_vdev(mac_ctx, vht_caps, vdev_id, + NSS_CHAINS_BAND_2GHZ); + status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_VHTCAPS, + CDS_BAND_2GHZ, &vht_caps[2], + DOT11F_IE_VHTCAPS_MIN_LEN); + + if (QDF_IS_STATUS_SUCCESS(status_2g) && + QDF_IS_STATUS_SUCCESS(status_5g)) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS lim_send_ies_per_band(struct mac_context *mac_ctx, uint8_t vdev_id, + enum csr_cfgdot11mode dot11_mode, + enum QDF_OPMODE device_mode) +{ + QDF_STATUS status_ht = QDF_STATUS_SUCCESS; + QDF_STATUS status_vht = QDF_STATUS_SUCCESS; + QDF_STATUS status_he = QDF_STATUS_SUCCESS; + QDF_STATUS status_eht = QDF_STATUS_SUCCESS; + + /* + * Note: Do not use Dot11f VHT structure, since 1 byte present flag in + * it is causing weird padding errors. Instead use Sir Mac VHT struct + * to send IE to wma. + */ + if (is_dot11mode_support_ht_cap(dot11_mode)) + status_ht = lim_send_ht_caps_ie(mac_ctx, device_mode, vdev_id); + + if (is_dot11mode_support_vht_cap(dot11_mode)) + status_vht = lim_send_vht_caps_ie(mac_ctx, device_mode, vdev_id); + + if (is_dot11mode_support_he_cap(dot11_mode)) { + status_he = lim_send_he_caps_ie(mac_ctx, device_mode, vdev_id); + + if (QDF_IS_STATUS_SUCCESS(status_he)) + status_he = lim_send_he_6g_band_caps_ie(mac_ctx, + vdev_id); + } + + if (is_dot11mode_support_eht_cap(dot11_mode)) { + if ((device_mode == QDF_NAN_DISC_MODE || + device_mode == QDF_NDI_MODE) && + !wlan_nan_is_eht_capable(mac_ctx->psoc)) + goto end; + + status_eht = lim_send_eht_caps_ie(mac_ctx, device_mode, + vdev_id); + } + +end: + if (QDF_IS_STATUS_SUCCESS(status_ht) && + QDF_IS_STATUS_SUCCESS(status_vht) && + QDF_IS_STATUS_SUCCESS(status_he) && + QDF_IS_STATUS_SUCCESS(status_eht)) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_FEATURE_11AX +static +void lim_update_ext_cap_he_params(struct mac_context *mac_ctx, + tDot11fIEExtCap *ext_cap_data, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + tDot11fIEhe_cap *he_cap; + struct s_ext_cap *p_ext_cap; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + return; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return; + } + + he_cap = &mlme_priv->he_config; + + p_ext_cap = (struct s_ext_cap *)ext_cap_data->bytes; + p_ext_cap->twt_requestor_support = he_cap->twt_request; + p_ext_cap->twt_responder_support = he_cap->twt_responder; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + ext_cap_data->num_bytes = lim_compute_ext_cap_ie_length(ext_cap_data); +} + +/** + * lim_update_ap_he_op() - update ap he op + * @session: session + * @ch_params: pointer to ch_params + * + * Return: void + */ +static void lim_update_ap_he_op(struct pe_session *session, + struct ch_params *ch_params) +{ + pe_debug("freq0: %d, freq1: %d, width: %d", + ch_params->center_freq_seg0, ch_params->center_freq_seg1, + ch_params->ch_width); + if (session->he_op.vht_oper_present) { + session->he_op.vht_oper.info.center_freq_seg0 = + ch_params->center_freq_seg0; + session->he_op.vht_oper.info.center_freq_seg1 = + ch_params->center_freq_seg1; + session->he_op.vht_oper.info.chan_width = + ch_params->ch_width; + } else if (session->he_6ghz_band) { + session->he_op.oper_info_6g_present = 1; + session->he_op.oper_info_6g.info.center_freq_seg0 = + ch_params->center_freq_seg0; + session->he_op.oper_info_6g.info.center_freq_seg1 = + ch_params->center_freq_seg1; + session->he_op.oper_info_6g.info.ch_width = + ch_params->ch_width; + } +} +#else +static inline void +lim_update_ext_cap_he_params(struct mac_context *mac_ctx, + tDot11fIEExtCap *ext_cap_data, + uint8_t vdev_id) +{} + +static void lim_update_ap_he_op(struct pe_session *session, + struct ch_params *ch_params) +{} +#endif + +/** + * lim_send_ext_cap_ie() - send ext cap IE to FW + * @mac_ctx: global MAC context + * @session_entry: PE session + * @extra_extcap: extracted ext cap + * @merge: merge extra ext cap + * + * This function is invoked after VDEV is created to update firmware + * about the extended capabilities that the corresponding VDEV is capable + * of. Since STA/SAP can have different Extended capabilities set, this function + * is called per vdev creation. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_ext_cap_ie(struct mac_context *mac_ctx, + uint32_t vdev_id, + tDot11fIEExtCap *extra_extcap, bool merge) +{ + tDot11fIEExtCap ext_cap_data = {0}; + uint32_t dot11mode, num_bytes; + bool vht_enabled = false; + struct vdev_ie_info *vdev_ie; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + struct pe_session *session_entry; + + dot11mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + if (IS_DOT11_MODE_VHT(dot11mode)) + vht_enabled = true; + + status = populate_dot11f_ext_cap(mac_ctx, vht_enabled, &ext_cap_data, + NULL); + if (QDF_STATUS_SUCCESS != status) { + pe_err("Failed to populate ext cap IE"); + return QDF_STATUS_E_FAILURE; + } + + lim_update_ext_cap_he_params(mac_ctx, &ext_cap_data, vdev_id); + num_bytes = ext_cap_data.num_bytes; + + if (merge && extra_extcap && extra_extcap->num_bytes > 0) { + if (extra_extcap->num_bytes > ext_cap_data.num_bytes) + num_bytes = extra_extcap->num_bytes; + lim_merge_extcap_struct(&ext_cap_data, extra_extcap, true); + } + + /* After merging extcap, check whether disable btm bit require or not */ + session_entry = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (session_entry) + populate_dot11f_btm_extended_caps(mac_ctx, session_entry, + &ext_cap_data); + + /* Allocate memory for the WMI request, and copy the parameter */ + vdev_ie = qdf_mem_malloc(sizeof(*vdev_ie) + num_bytes); + if (!vdev_ie) + return QDF_STATUS_E_NOMEM; + + vdev_ie->vdev_id = vdev_id; + vdev_ie->ie_id = DOT11F_EID_EXTCAP; + vdev_ie->length = num_bytes; + vdev_ie->band = 0; + + vdev_ie->data = (uint8_t *)vdev_ie + sizeof(*vdev_ie); + qdf_mem_copy(vdev_ie->data, ext_cap_data.bytes, num_bytes); + + msg.type = WMA_SET_IE_INFO; + msg.bodyptr = vdev_ie; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + pe_err("Not able to post WMA_SET_IE_INFO to WDA"); + qdf_mem_free(vdev_ie); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_strip_ie(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, enum size_of_len_field size_of_len_field, + uint8_t *oui, uint8_t oui_length, uint8_t *extracted_ie, + uint32_t eid_max_len) +{ + return wlan_strip_ie(addn_ie, addn_ielen, eid, size_of_len_field, + oui, oui_length, extracted_ie, eid_max_len); +} + +void lim_del_pmf_sa_query_timer(struct mac_context *mac_ctx, struct pe_session *pe_session) +{ + uint32_t associated_sta; + tpDphHashNode sta_ds = NULL; + + for (associated_sta = 1; + associated_sta <= + mac_ctx->lim.max_sta_of_pe_session; + associated_sta++) { + sta_ds = dph_get_hash_entry(mac_ctx, associated_sta, + &pe_session->dph.dphHashTable); + if (!sta_ds) + continue; + if (!sta_ds->rmfEnabled) { + pe_debug("no PMF timer for assoc-id:%d sta mac" + QDF_MAC_ADDR_FMT, sta_ds->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + continue; + } + + pe_debug("Deleting pmfSaQueryTimer for assoc-id:%d sta mac" + QDF_MAC_ADDR_FMT, sta_ds->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + tx_timer_deactivate(&sta_ds->pmfSaQueryTimer); + tx_timer_delete(&sta_ds->pmfSaQueryTimer); + } +} + +QDF_STATUS lim_strip_supp_op_class_update_struct(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + tDot11fIESuppOperatingClasses *dst) +{ + uint8_t extracted_buff[DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN + 2]; + QDF_STATUS status; + + qdf_mem_zero((uint8_t *)&extracted_buff[0], + DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN + 2); + status = lim_strip_ie(mac_ctx, addn_ie, addn_ielen, + DOT11F_EID_SUPPOPERATINGCLASSES, ONE_BYTE, + NULL, 0, extracted_buff, + DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN); + if (QDF_STATUS_SUCCESS != status) { + pe_warn("Failed to strip supp_op_mode IE status: %d", + status); + return status; + } + + if (DOT11F_EID_SUPPOPERATINGCLASSES != extracted_buff[0] || + extracted_buff[1] > DOT11F_IE_SUPPOPERATINGCLASSES_MAX_LEN) { + pe_warn("Invalid IEs eid: %d elem_len: %d", + extracted_buff[0], extracted_buff[1]); + return QDF_STATUS_E_FAILURE; + } + + /* update the extracted supp op class to struct*/ + if (DOT11F_PARSE_SUCCESS != dot11f_unpack_ie_supp_operating_classes( + mac_ctx, &extracted_buff[2], extracted_buff[1], dst, false)) { + pe_err("dot11f_unpack Parse Error"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +uint8_t lim_op_class_from_bandwidth(struct mac_context *mac_ctx, + uint16_t channel_freq, + enum phy_ch_width ch_bandwidth, + enum offset_t offset) +{ + uint8_t op_class = 0; + uint16_t ch_behav_limit = BEHAV_NONE; + uint8_t channel; + + if (ch_bandwidth == CH_WIDTH_40MHZ && + wlan_reg_is_24ghz_ch_freq(channel_freq)) { + if (offset == BW40_LOW_PRIMARY) + ch_behav_limit = BEHAV_BW40_LOW_PRIMARY; + else + ch_behav_limit = BEHAV_BW40_HIGH_PRIMARY; + } else if (ch_bandwidth == CH_WIDTH_80P80MHZ) { + ch_behav_limit = BEHAV_BW80_PLUS; + } + wlan_reg_freq_width_to_chan_op_class(mac_ctx->pdev, channel_freq, + ch_width_in_mhz(ch_bandwidth), + true, BIT(ch_behav_limit), + &op_class, &channel); + + return op_class; +} + +/** + * lim_update_extcap_struct() - poputlate the dot11f structure + * @mac_ctx: global MAC context + * @buf: extracted IE buffer + * @dst: extended capability IE structure to be updated + * + * This function is used to update the extended capability structure + * with @buf. + * + * Return: None + */ +void lim_update_extcap_struct(struct mac_context *mac_ctx, + uint8_t *buf, tDot11fIEExtCap *dst) +{ + uint8_t out[DOT11F_IE_EXTCAP_MAX_LEN]; + uint32_t status; + + if (!buf) { + pe_err("Invalid Buffer Address"); + return; + } + + if (!dst) { + pe_err("NULL dst pointer"); + return; + } + + if (DOT11F_EID_EXTCAP != buf[0] || buf[1] > DOT11F_IE_EXTCAP_MAX_LEN) { + pe_debug_rl("Invalid IEs eid: %d elem_len: %d", buf[0], buf[1]); + return; + } + + qdf_mem_zero((uint8_t *)&out[0], DOT11F_IE_EXTCAP_MAX_LEN); + qdf_mem_copy(&out[0], &buf[2], buf[1]); + + status = dot11f_unpack_ie_ext_cap(mac_ctx, &out[0], + buf[1], dst, false); + if (DOT11F_PARSE_SUCCESS != status) + pe_err("dot11f_unpack Parse Error %d", status); +} + +/** + * lim_strip_extcap_update_struct - strip extended capability IE and populate + * the dot11f structure + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @dst: extended capability IE structure to be updated + * + * This function is used to strip extended capability IE from IE buffer and + * update the passed structure. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_strip_extcap_update_struct(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst) +{ + uint8_t extracted_buff[DOT11F_IE_EXTCAP_MAX_LEN + 2]; + QDF_STATUS status; + + qdf_mem_zero((uint8_t *)&extracted_buff[0], + DOT11F_IE_EXTCAP_MAX_LEN + 2); + status = lim_strip_ie(mac_ctx, addn_ie, addn_ielen, + DOT11F_EID_EXTCAP, ONE_BYTE, + NULL, 0, extracted_buff, + DOT11F_IE_EXTCAP_MAX_LEN); + if (QDF_STATUS_SUCCESS != status) { + pe_debug("Failed to strip extcap IE status: %d", status); + return status; + } + + /* update the extracted ExtCap to struct*/ + lim_update_extcap_struct(mac_ctx, extracted_buff, dst); + return status; +} + +/** + * lim_merge_extcap_struct() - merge extended capabilities info + * @dst: destination extended capabilities + * @src: source extended capabilities + * @add: true if add the capabilities, false if strip the capabilities. + * + * This function is used to take @src info and add/strip it to/from + * @dst extended capabilities info. + * + * Return: None + */ +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, + tDot11fIEExtCap *src, + bool add) +{ + uint8_t *tempdst = (uint8_t *)dst->bytes; + uint8_t *tempsrc = (uint8_t *)src->bytes; + uint8_t structlen = member_size(tDot11fIEExtCap, bytes); + + /* Return if @src not present */ + if (!src->present) + return; + + pe_debug("source extended capabilities length:%d", src->num_bytes); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + src->bytes, src->num_bytes); + + /* Return if strip the capabilities from @dst which not present */ + if (!dst->present && !add) + return; + + /* Merge the capabilities info in other cases */ + while (tempdst && tempsrc && structlen--) { + if (add) + *tempdst |= *tempsrc; + else + *tempdst &= *tempsrc; + tempdst++; + tempsrc++; + } + dst->num_bytes = lim_compute_ext_cap_ie_length(dst); + if (dst->num_bytes == 0) { + dst->present = 0; + } else { + dst->present = 1; + pe_debug("destination extended capabilities length: %d", + dst->num_bytes); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + dst->bytes, dst->num_bytes); + } +} + +/** + * lim_send_action_frm_tb_ppdu_cfg_flush_cb() - flush TB PPDU cfg msg + * @msg: Message pointer + * + * Flushes the send action frame in HE TB PPDU configuration message. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +lim_send_action_frm_tb_ppdu_cfg_flush_cb(struct scheduler_msg *msg) +{ + if (msg->bodyptr) { + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_send_action_frm_tb_ppdu_cfg(struct mac_context *mac_ctx, + uint32_t vdev_id, uint8_t cfg) +{ + tDot11fvendor_action_frame *frm; + uint8_t frm_len = sizeof(*frm); + struct pe_session *session; + struct cfg_action_frm_tb_ppdu *cfg_msg; + struct scheduler_msg msg = {0}; + uint8_t *data_buf; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("pe session does not exist for vdev_id %d", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + data_buf = qdf_mem_malloc(frm_len + sizeof(*cfg_msg)); + if (!data_buf) + return QDF_STATUS_E_FAILURE; + + cfg_msg = (struct cfg_action_frm_tb_ppdu *)data_buf; + + frm = (tDot11fvendor_action_frame *)(data_buf + sizeof(*cfg_msg)); + + frm->Category.category = ACTION_CATEGORY_VENDOR_SPECIFIC; + + frm->vendor_oui.oui_data[0] = 0x00; + frm->vendor_oui.oui_data[1] = 0xA0; + frm->vendor_oui.oui_data[2] = 0xC6; + + frm->vendor_action_subtype.subtype = 0xFF; + + cfg_msg->vdev_id = vdev_id; + cfg_msg->cfg = cfg; + cfg_msg->frm_len = frm_len; + cfg_msg->data = (uint8_t *)frm; + + msg.type = WMA_CFG_VENDOR_ACTION_TB_PPDU; + msg.bodyptr = cfg_msg; + msg.reserved = 0; + msg.flush_callback = lim_send_action_frm_tb_ppdu_cfg_flush_cb; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + pe_err("Not able to post WMA_SET_IE_INFO to WDA"); + qdf_mem_free(data_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_get_80Mhz_center_channel - finds 80 Mhz center channel + * + * @primary_channel: Primary channel for given 80 MHz band + * + * There are fixed 80MHz band and for each fixed band there is only one center + * valid channel. Also location of primary channel decides what 80 MHz band will + * it use, hence it decides what center channel will be used. This function + * does thus calculation and returns the center channel. + * + * Return: center channel + */ +uint8_t +lim_get_80Mhz_center_channel(uint8_t primary_channel) +{ + if (primary_channel >= 36 && primary_channel <= 48) + return (36+48)/2; + if (primary_channel >= 52 && primary_channel <= 64) + return (52+64)/2; + if (primary_channel >= 100 && primary_channel <= 112) + return (100+112)/2; + if (primary_channel >= 116 && primary_channel <= 128) + return (116+128)/2; + if (primary_channel >= 132 && primary_channel <= 144) + return (132+144)/2; + if (primary_channel >= 149 && primary_channel <= 161) + return (149+161)/2; + + return INVALID_CHANNEL_ID; +} + +/** + * lim_bss_type_to_string(): converts bss type enum to string. + * @bss_type: enum value of bss_type. + * + * Return: Printable string for bss_type + */ +const char *lim_bss_type_to_string(const uint16_t bss_type) +{ + switch (bss_type) { + CASE_RETURN_STRING(eSIR_INFRASTRUCTURE_MODE); + CASE_RETURN_STRING(eSIR_INFRA_AP_MODE); + CASE_RETURN_STRING(eSIR_AUTO_MODE); + CASE_RETURN_STRING(eSIR_NDI_MODE); + default: + return "Unknown bss_type"; + } +} + +/** + * lim_init_obss_params(): Initializes the OBSS Scan Parameters + * @session: LIM session + * @mac_ctx: Mac context + * + * Return: None + */ +void lim_init_obss_params(struct mac_context *mac_ctx, struct pe_session *session) +{ + struct wlan_mlme_obss_ht40 *obss_ht40; + + if (!(mac_ctx->mlme_cfg)) { + pe_err("invalid mlme cfg"); + return; + } + + obss_ht40 = &mac_ctx->mlme_cfg->obss_ht40; + + session->obss_ht40_scanparam.obss_active_dwelltime = + obss_ht40->active_dwelltime; + + session->obss_ht40_scanparam.obss_passive_dwelltime = + obss_ht40->passive_dwelltime; + + session->obss_ht40_scanparam.obss_width_trigger_interval = + obss_ht40->width_trigger_interval; + + session->obss_ht40_scanparam.obss_active_total_per_channel = + obss_ht40->active_per_channel; + + session->obss_ht40_scanparam.obss_passive_total_per_channel = + obss_ht40->passive_per_channel; + + session->obss_ht40_scanparam.bsswidth_ch_trans_delay = + obss_ht40->width_trans_delay; + + session->obss_ht40_scanparam.obss_activity_threshold = + obss_ht40->scan_activity_threshold; +} + +/** + * lim_update_obss_scanparams(): Updates OBSS SCAN IE parameters to session + * @session: LIM session + * @scan_params: Scan parameters + * + * Return: None + */ +void lim_update_obss_scanparams(struct pe_session *session, + tDot11fIEOBSSScanParameters *scan_params) +{ + /* + * If the received value is not in the range specified + * by the Specification then it will be the default value + * configured through cfg + */ + if ((scan_params->obssScanActiveDwell > + cfg_min(CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME)) && + (scan_params->obssScanActiveDwell < + cfg_max(CFG_OBSS_HT40_SCAN_ACTIVE_DWELL_TIME))) + session->obss_ht40_scanparam.obss_active_dwelltime = + scan_params->obssScanActiveDwell; + + if ((scan_params->obssScanPassiveDwell > + cfg_min(CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME)) && + (scan_params->obssScanPassiveDwell < + cfg_max(CFG_OBSS_HT40_SCAN_PASSIVE_DWELL_TIME))) + session->obss_ht40_scanparam.obss_passive_dwelltime = + scan_params->obssScanPassiveDwell; + + if ((scan_params->bssWidthChannelTransitionDelayFactor > + cfg_min(CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY)) && + (scan_params->bssWidthChannelTransitionDelayFactor < + cfg_max(CFG_OBSS_HT40_WIDTH_CH_TRANSITION_DELAY))) + session->obss_ht40_scanparam.bsswidth_ch_trans_delay = + scan_params->bssWidthChannelTransitionDelayFactor; + + if ((scan_params->obssScanActiveTotalPerChannel > + cfg_min(CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL)) && + (scan_params->obssScanActiveTotalPerChannel < + cfg_max(CFG_OBSS_HT40_SCAN_ACTIVE_TOTAL_PER_CHANNEL))) + session->obss_ht40_scanparam.obss_active_total_per_channel = + scan_params->obssScanActiveTotalPerChannel; + + if ((scan_params->obssScanPassiveTotalPerChannel > + cfg_min(CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL)) && + (scan_params->obssScanPassiveTotalPerChannel < + cfg_max(CFG_OBSS_HT40_SCAN_PASSIVE_TOTAL_PER_CHANNEL))) + session->obss_ht40_scanparam.obss_passive_total_per_channel = + scan_params->obssScanPassiveTotalPerChannel; + + if ((scan_params->bssChannelWidthTriggerScanInterval > + cfg_min(CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL)) && + (scan_params->bssChannelWidthTriggerScanInterval < + cfg_max(CFG_OBSS_HT40_SCAN_WIDTH_TRIGGER_INTERVAL))) + session->obss_ht40_scanparam.obss_width_trigger_interval = + scan_params->bssChannelWidthTriggerScanInterval; + + if ((scan_params->obssScanActivityThreshold > + cfg_min(CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD)) && + (scan_params->obssScanActivityThreshold < + cfg_max(CFG_OBSS_HT40_SCAN_ACTIVITY_THRESHOLD))) + session->obss_ht40_scanparam.obss_activity_threshold = + scan_params->obssScanActivityThreshold; + return; +} + +/** + * lim_compute_ext_cap_ie_length - compute the length of ext cap ie + * based on the bits set + * @ext_cap: extended IEs structure + * + * Return: length of the ext cap ie, 0 means should not present + */ +uint8_t lim_compute_ext_cap_ie_length(tDot11fIEExtCap *ext_cap) +{ + uint8_t i = DOT11F_IE_EXTCAP_MAX_LEN; + + while (i) { + if (ext_cap->bytes[i-1]) + break; + i--; + } + + return i; +} + +/** + * lim_update_caps_info_for_bss - Update capability info for this BSS + * + * @mac_ctx: mac context + * @caps: Pointer to capability info to be updated + * @bss_caps: Capability info of the BSS + * + * Update the capability info in Assoc/Reassoc request frames and reset + * the spectrum management, short preamble, immediate block ack bits + * if the BSS does not support it + * + * Return: None + */ +void lim_update_caps_info_for_bss(struct mac_context *mac_ctx, + uint16_t *caps, uint16_t bss_caps) +{ + if (!(bss_caps & LIM_SPECTRUM_MANAGEMENT_BIT_MASK)) { + *caps &= (~LIM_SPECTRUM_MANAGEMENT_BIT_MASK); + pe_debug("Clearing spectrum management:no AP support"); + } + + if (!(bss_caps & LIM_SHORT_PREAMBLE_BIT_MASK)) { + *caps &= (~LIM_SHORT_PREAMBLE_BIT_MASK); + pe_debug("Clearing short preamble:no AP support"); + } + + if (!(bss_caps & LIM_IMMEDIATE_BLOCK_ACK_MASK)) { + *caps &= (~LIM_IMMEDIATE_BLOCK_ACK_MASK); + pe_debug("Clearing Immed Blk Ack:no AP support"); + } +} +/** + * lim_send_set_dtim_period(): Send SIR_HAL_SET_DTIM_PERIOD message + * to set dtim period. + * + * @session: LIM session + * @dtim_period: dtim value + * @mac_ctx: Mac context + * @return None + */ +void lim_send_set_dtim_period(struct mac_context *mac_ctx, uint8_t dtim_period, + struct pe_session *session) +{ + struct set_dtim_params *dtim_params = NULL; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0}; + + if (!session) { + pe_err("Inavalid parameters"); + return; + } + dtim_params = qdf_mem_malloc(sizeof(*dtim_params)); + if (!dtim_params) + return; + dtim_params->dtim_period = dtim_period; + dtim_params->session_id = session->smeSessionId; + msg.type = WMA_SET_DTIM_PERIOD; + msg.bodyptr = dtim_params; + msg.bodyval = 0; + pe_debug("Post WMA_SET_DTIM_PERIOD to WMA"); + ret = wma_post_ctrl_msg(mac_ctx, &msg); + if (QDF_STATUS_SUCCESS != ret) { + pe_err("wma_post_ctrl_msg() failed"); + qdf_mem_free(dtim_params); + } +} + +/** + * lim_is_valid_frame(): validate RX frame using last processed frame details + * to find if it is duplicate frame. + * + * @last_processed_frm: last processed frame pointer. + * @pRxPacketInfo: RX packet. + * + * Frame treat as duplicate: + * if retry bit is set and + * if source address and seq number matches with the last processed frame + * + * Return: false if duplicate frame, else true. + */ +bool lim_is_valid_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo) +{ + uint16_t seq_num; + tpSirMacMgmtHdr pHdr; + + if (!pRxPacketInfo) { + pe_err("Invalid RX frame"); + return false; + } + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + if (pHdr->fc.retry == 0) + return true; + + seq_num = (((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + + if (last_processed_frm->seq_num == seq_num && + qdf_mem_cmp(last_processed_frm->sa, pHdr->sa, ETH_ALEN) == 0) { + pe_err("Duplicate frame from "QDF_MAC_ADDR_FMT " Seq Number %d", + QDF_MAC_ADDR_REF(pHdr->sa), seq_num); + return false; + } + return true; +} + +/** + * lim_update_last_processed_frame(): update new processed frame info to cache. + * + * @last_processed_frm: last processed frame pointer. + * @pRxPacketInfo: Successfully processed RX packet. + * + * Return: None. + */ +void lim_update_last_processed_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo) +{ + uint16_t seq_num; + tpSirMacMgmtHdr pHdr; + + if (!pRxPacketInfo) { + pe_err("Invalid RX frame"); + return; + } + + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + seq_num = (((pHdr->seqControl.seqNumHi << + HIGH_SEQ_NUM_OFFSET) | + pHdr->seqControl.seqNumLo)); + + qdf_mem_copy(last_processed_frm->sa, pHdr->sa, ETH_ALEN); + last_processed_frm->seq_num = seq_num; +} + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +static bool lim_support_6ghz_band_op_class(struct mac_context *mac_ctx, + tDot11fIESuppOperatingClasses * + op_class_ie) +{ + uint16_t i; + + if (!op_class_ie->present) + return false; + for (i = 0; i < op_class_ie->num_classes; i++) { + if (wlan_reg_is_6ghz_op_class(mac_ctx->pdev, + op_class_ie->classes[i])) + break; + } + if (i < op_class_ie->num_classes) + return true; + + return false; +} + +void lim_ap_check_6g_compatible_peer(struct mac_context *mac_ctx, + struct pe_session *session) +{ + uint16_t i; + tpDphHashNode sta_ds; + bool legacy_client_present = false; + + if (!LIM_IS_AP_ROLE(session)) + return; + + for (i = 1; i < session->dph.dphHashTable.size; i++) { + sta_ds = dph_get_hash_entry(mac_ctx, i, + &session->dph.dphHashTable); + if (!sta_ds) + continue; + if (sta_ds->staType != STA_ENTRY_PEER) + continue; + if (!lim_support_6ghz_band_op_class( + mac_ctx, &sta_ds->supp_operating_classes)) { + legacy_client_present = true; + pe_debug("peer "QDF_MAC_ADDR_FMT" 6ghz not supported", + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + break; + } + pe_debug("peer "QDF_MAC_ADDR_FMT" 6ghz supported", + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + } + if (legacy_client_present) + policy_mgr_set_ap_6ghz_capable( + mac_ctx->psoc, session->vdev_id, false, + CONN_6GHZ_FLAG_NO_LEGACY_CLIENT); + else + policy_mgr_set_ap_6ghz_capable( + mac_ctx->psoc, session->vdev_id, true, + CONN_6GHZ_FLAG_NO_LEGACY_CLIENT); +} +#endif + +#ifdef WLAN_FEATURE_11AX +void lim_update_he_6ghz_band_caps(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *he_6ghz_band_cap, + tpAddStaParams params) +{ + qdf_mem_copy(¶ms->he_6ghz_band_caps, he_6ghz_band_cap, + sizeof(tDot11fIEhe_6ghz_band_cap)); + + lim_log_he_6g_cap(mac, ¶ms->he_6ghz_band_caps); +} + +void lim_add_he_cap(struct mac_context *mac_ctx, struct pe_session *pe_session, + tpAddStaParams add_sta_params, tpSirAssocReq assoc_req) +{ + if (!add_sta_params->he_capable || !assoc_req) + return; + + qdf_mem_copy(&add_sta_params->he_config, &assoc_req->he_cap, + sizeof(add_sta_params->he_config)); + + if (lim_is_he_6ghz_band(pe_session)) + lim_update_he_6ghz_band_caps(mac_ctx, + &assoc_req->he_6ghz_band_cap, + add_sta_params); + +} + +void lim_add_self_he_cap(tpAddStaParams add_sta_params, struct pe_session *session) +{ + if (!session) + return; + + add_sta_params->he_capable = true; + + qdf_mem_copy(&add_sta_params->he_config, &session->he_config, + sizeof(add_sta_params->he_config)); + qdf_mem_copy(&add_sta_params->he_op, &session->he_op, + sizeof(add_sta_params->he_op)); +} + +static bool lim_check_is_bss_greater_than_4_nss_supp(struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + uint8_t i; + uint16_t mcs_map; +#define NSS_4 4 +#define NSS_8 8 + + if (!session->he_capable || !he_cap->present) + return false; + mcs_map = he_cap->rx_he_mcs_map_lt_80; + for (i = NSS_4; i < NSS_8; i++) { + if (((mcs_map >> (i * 2)) & 0x3) != 0x3) + return true; + } + + return false; +} + +bool lim_check_he_80_mcs11_supp(struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + uint16_t rx_mcs_map; + uint16_t tx_mcs_map; + + rx_mcs_map = he_cap->rx_he_mcs_map_lt_80; + tx_mcs_map = he_cap->tx_he_mcs_map_lt_80; + if ((session->nss == NSS_1x1_MODE) && + ((HE_GET_MCS_4_NSS(rx_mcs_map, 1) == HE_MCS_0_11) || + (HE_GET_MCS_4_NSS(tx_mcs_map, 1) == HE_MCS_0_11))) + return true; + + if ((session->nss == NSS_2x2_MODE) && + ((HE_GET_MCS_4_NSS(rx_mcs_map, 2) == HE_MCS_0_11) || + (HE_GET_MCS_4_NSS(tx_mcs_map, 2) == HE_MCS_0_11))) + return true; + + return false; +} + +/** + * lim_check_he_ldpc_cap() - set he ldpc coding to one if + * channel width is > 20 or mcs 10/11 bit are supported or + * nss is greater than 4. + * @beacon_struct: beacon structure + * @session: A pointer to session entry. + * + * Return: None + */ + +void lim_check_and_force_he_ldpc_cap(struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + if (!he_cap->ldpc_coding && + (session->ch_width > CH_WIDTH_20MHZ || + lim_check_he_80_mcs11_supp(session, he_cap) || + lim_check_is_bss_greater_than_4_nss_supp(session, he_cap))) + he_cap->ldpc_coding = 1; +} + +/** + * lim_intersect_he_caps() - Intersect peer capability and self capability + * @rcvd_he: pointer to received peer capability + * @peer_he: pointer to Intersected capability + * @session: A pointer to session entry. + * + * Return: None + */ +static void lim_intersect_he_caps(tDot11fIEhe_cap *rcvd_he, + tDot11fIEhe_cap *peer_he, + struct pe_session *session) +{ + uint8_t val; + tDot11fIEhe_cap *session_he = &session->he_config; + + qdf_mem_copy(peer_he, rcvd_he, sizeof(*peer_he)); + + peer_he->fragmentation = QDF_MIN(session_he->fragmentation, + peer_he->fragmentation); + + peer_he->ldpc_coding &= session_he->ldpc_coding; + lim_check_and_force_he_ldpc_cap(session, peer_he); + + if (session_he->tb_ppdu_tx_stbc_lt_80mhz && peer_he->rx_stbc_lt_80mhz) + peer_he->rx_stbc_lt_80mhz = 1; + else + peer_he->rx_stbc_lt_80mhz = 0; + + if (session_he->rx_stbc_lt_80mhz && peer_he->tb_ppdu_tx_stbc_lt_80mhz) + peer_he->tb_ppdu_tx_stbc_lt_80mhz = 1; + else + peer_he->tb_ppdu_tx_stbc_lt_80mhz = 0; + + if (session_he->tb_ppdu_tx_stbc_gt_80mhz && peer_he->rx_stbc_gt_80mhz) + peer_he->rx_stbc_gt_80mhz = 1; + else + peer_he->rx_stbc_gt_80mhz = 0; + + if (session_he->rx_stbc_gt_80mhz && peer_he->tb_ppdu_tx_stbc_gt_80mhz) + peer_he->tb_ppdu_tx_stbc_gt_80mhz = 1; + else + peer_he->tb_ppdu_tx_stbc_gt_80mhz = 0; + + /* Tx Doppler is first bit and Rx Doppler is second bit */ + if (session_he->doppler) { + val = 0; + if ((session_he->doppler & 0x1) && (peer_he->doppler & 0x10)) + val |= (1 << 1); + if ((session_he->doppler & 0x10) && (peer_he->doppler & 0x1)) + val |= (1 << 0); + peer_he->doppler = val; + } + + peer_he->su_beamformer = session_he->su_beamformee ? + peer_he->su_beamformer : 0; + peer_he->su_beamformee = (session_he->su_beamformer || + session_he->mu_beamformer) ? + peer_he->su_beamformee : 0; + peer_he->mu_beamformer = session_he->su_beamformee ? + peer_he->mu_beamformer : 0; + + peer_he->twt_request = session_he->twt_responder ? + peer_he->twt_request : 0; + peer_he->twt_responder = session_he->twt_request ? + peer_he->twt_responder : 0; +} + +void lim_intersect_sta_he_caps(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + struct pe_session *session, + tpDphHashNode sta_ds) +{ + tDot11fIEhe_cap *rcvd_he = &assoc_req->he_cap; + tDot11fIEhe_cap *peer_he = &sta_ds->he_config; + struct wlan_mlme_cfg *mlme_cfg = mac_ctx->mlme_cfg; + + if (!sta_ds->mlmStaContext.he_capable) + return; + + /* If HE is not supported, do not fill sta_ds and return */ + if (!IS_DOT11_MODE_HE(session->dot11mode)) + return; + + lim_intersect_he_caps(rcvd_he, peer_he, session); + + if ((mlme_cfg->he_caps.disable_sap_mcs_12_13 & + BIT(DISABLE_MCS_12_13_2G_40M)) && + LIM_IS_AP_ROLE(session) && + wlan_reg_is_24ghz_ch_freq(session->curr_op_freq) && + session->ch_width == CH_WIDTH_40MHZ) { + sta_ds->he_mcs_12_13_map = 0; + return; + } + + /* If MCS 12/13 is supported from assoc QCN IE */ + if (assoc_req->qcn_ie.present && + assoc_req->qcn_ie.he_mcs13_attr.present) { + sta_ds->he_mcs_12_13_map = + assoc_req->qcn_ie.he_mcs13_attr.he_mcs_12_13_supp_80 | + assoc_req->qcn_ie.he_mcs13_attr.he_mcs_12_13_supp_160 << 8; + } else { + return; + } + + /* Take intersection of FW capability for HE MCS 12/13 */ + if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + sta_ds->he_mcs_12_13_map &= + mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_2g; + else + sta_ds->he_mcs_12_13_map &= + mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_5g; +} + +static bool +lim_is_vendor_htc_he_ap(struct bss_description *bss_desc) +{ + struct action_oui_search_attr vendor_ap_search_attr = {0}; + uint16_t ie_len; + + ie_len = wlan_get_ielen_from_bss_description(bss_desc); + + vendor_ap_search_attr.ie_data = (uint8_t *)&bss_desc->ieFields[0]; + vendor_ap_search_attr.ie_length = ie_len; + + return wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_BAD_HTC_HE_VENDOR_OUI1, + SIR_MAC_BAD_HTC_HE_VENDOR_OUI_LEN, + vendor_ap_search_attr.ie_data, + ie_len) && + wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_BAD_HTC_HE_VENDOR_OUI2, + SIR_MAC_BAD_HTC_HE_VENDOR_OUI_LEN, + vendor_ap_search_attr.ie_data, + ie_len); +} + +void lim_intersect_ap_he_caps(struct pe_session *session, + struct bss_params *add_bss, + tSchBeaconStruct *beacon, + tpSirAssocRsp assoc_rsp, + struct bss_description *bss_desc) +{ + tDot11fIEhe_cap *rcvd_he; + tDot11fIEhe_cap *peer_he = &add_bss->staContext.he_config; + bool vendor_ap_present = false; + + if (assoc_rsp && assoc_rsp->he_cap.present) + rcvd_he = &assoc_rsp->he_cap; + else + rcvd_he = &beacon->he_cap; + + lim_intersect_he_caps(rcvd_he, peer_he, session); + peer_he->htc_he = rcvd_he->htc_he; + vendor_ap_present = lim_is_vendor_htc_he_ap(bss_desc); + if (vendor_ap_present) { + if (session->he_config.htc_he && peer_he->htc_he) + peer_he->htc_he = 1; + else + peer_he->htc_he = 0; + pe_debug("intersected htc he is: %d", peer_he->htc_he); + } + + pe_debug("HTC HE: self: %d recvd: %d, peer: %d", + session->he_config.htc_he, rcvd_he->htc_he, peer_he->htc_he); + add_bss->staContext.he_capable = true; +} + +void lim_add_bss_he_cap(struct bss_params *add_bss, tpSirAssocRsp assoc_rsp) +{ + tDot11fIEhe_cap *he_cap; + tDot11fIEhe_op *he_op; + + he_cap = &assoc_rsp->he_cap; + he_op = &assoc_rsp->he_op; + add_bss->he_capable = he_cap->present; + if (he_cap) + qdf_mem_copy(&add_bss->staContext.he_config, + he_cap, sizeof(*he_cap)); + if (he_op) + qdf_mem_copy(&add_bss->staContext.he_op, + he_op, sizeof(*he_op)); +} + +void lim_add_bss_he_cfg(struct bss_params *add_bss, struct pe_session *session) +{ + add_bss->he_sta_obsspd = session->he_sta_obsspd; +} + +void lim_update_he_6gop_assoc_resp(struct bss_params *pAddBssParams, + tDot11fIEhe_op *he_op, + struct pe_session *pe_session) +{ + if (!pe_session->he_6ghz_band) + return; + + if (!he_op->oper_info_6g_present) { + pe_debug("6G operation info not present in beacon"); + return; + } + if (!pe_session->ch_width) + return; + + pAddBssParams->ch_width = QDF_MIN(he_op->oper_info_6g.info.ch_width, + pe_session->ch_width); + + if (pAddBssParams->ch_width == CH_WIDTH_160MHZ) + pAddBssParams->ch_width = pe_session->ch_width; + pAddBssParams->staContext.ch_width = pAddBssParams->ch_width; +} + +void lim_update_stads_he_caps(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, + tSchBeaconStruct *beacon) +{ + /* If HE is not supported, do not fill sta_ds and return */ + if (!IS_DOT11_MODE_HE(session_entry->dot11mode)) + goto out; + + if (!assoc_rsp->he_cap.present && beacon && beacon->he_cap.present) { + /* Use beacon HE caps if assoc resp doesn't have he caps */ + pe_debug("he_caps missing in assoc rsp"); + qdf_mem_copy(&assoc_rsp->he_cap, &beacon->he_cap, + sizeof(tDot11fIEhe_cap)); + } + + /* assoc resp and beacon doesn't have he caps */ + if (!assoc_rsp->he_cap.present) + goto out; + + sta_ds->mlmStaContext.he_capable = assoc_rsp->he_cap.present; + + /* setting ldpc_coding if any of assoc_rsp or beacon has ldpc_coding + * enabled + */ + if (beacon) + assoc_rsp->he_cap.ldpc_coding |= beacon->he_cap.ldpc_coding; + lim_check_and_force_he_ldpc_cap(session_entry, &assoc_rsp->he_cap); + if (beacon) + beacon->he_cap.ldpc_coding = assoc_rsp->he_cap.ldpc_coding; + + qdf_mem_copy(&sta_ds->he_config, &assoc_rsp->he_cap, + sizeof(tDot11fIEhe_cap)); + + /* If MCS 12/13 is supported by the assoc resp QCN IE */ + if (assoc_rsp->qcn_ie.present && + assoc_rsp->qcn_ie.he_mcs13_attr.present) { + sta_ds->he_mcs_12_13_map = + assoc_rsp->qcn_ie.he_mcs13_attr.he_mcs_12_13_supp_80 | + assoc_rsp->qcn_ie.he_mcs13_attr.he_mcs_12_13_supp_160 << 8; + } + + /* Take intersection of the FW capability for HE MCS 12/13 */ + if (wlan_reg_is_24ghz_ch_freq(session_entry->curr_op_freq)) + sta_ds->he_mcs_12_13_map &= + mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_2g; + else + sta_ds->he_mcs_12_13_map &= + mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_5g; +out: + pe_debug("he_mcs_12_13_map: sta_ds 0x%x, 2g_fw 0x%x, 5g_fw 0x%x", + sta_ds->he_mcs_12_13_map, + mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_2g, + mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_5g); + lim_update_he_mcs_12_13_map(mac_ctx->psoc, + session_entry->smeSessionId, + sta_ds->he_mcs_12_13_map); + +} + +void lim_update_stads_he_6ghz_op(struct pe_session *session, + tpDphHashNode sta_ds) +{ + tDot11fIEhe_cap *peer_he = &sta_ds->he_config; + enum phy_ch_width ch_width; + + if (!session->he_6ghz_band) + return; + + if (!peer_he->present) { + pe_debug("HE cap not present in peer"); + return; + } + + if (peer_he->chan_width_3) + ch_width = CH_WIDTH_80P80MHZ; + else if (peer_he->chan_width_2) + ch_width = CH_WIDTH_160MHZ; + else if (peer_he->chan_width_1) + ch_width = CH_WIDTH_80MHZ; + else + ch_width = CH_WIDTH_20MHZ; + if (ch_width > session->ch_width) + ch_width = session->ch_width; + sta_ds->ch_width = ch_width; +} + +void lim_update_usr_he_cap(struct mac_context *mac_ctx, struct pe_session *session) +{ + struct add_ie_params *add_ie = &session->add_ie_params; + tDot11fIEhe_cap *he_cap = &session->he_config; + struct he_cap_network_endian *he_cap_from_ie; + uint8_t extracted_buff[DOT11F_IE_HE_CAP_MAX_LEN + 2]; + QDF_STATUS status; + struct wlan_vht_config *vht_cfg = &session->vht_config; + struct mlme_legacy_priv *mlme_priv; + + qdf_mem_zero(extracted_buff, sizeof(extracted_buff)); + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_HE_CAP, ONE_BYTE, + HE_CAP_OUI_TYPE, (uint8_t)HE_CAP_OUI_SIZE, + extracted_buff, DOT11F_IE_HE_CAP_MAX_LEN); + if (QDF_STATUS_SUCCESS != status) { + pe_debug("Failed to strip HE cap IE status: %d", status); + return; + } + + pe_debug("Before update: su_beamformer: %d, su_beamformee: %d, mu_beamformer: %d", + he_cap->su_beamformer, he_cap->su_beamformee, he_cap->mu_beamformer); + + he_cap_from_ie = (struct he_cap_network_endian *) + &extracted_buff[HE_CAP_OUI_SIZE + 2]; + + he_cap->su_beamformer = + he_cap->su_beamformer & he_cap_from_ie->su_beamformer; + he_cap->su_beamformee = + he_cap->su_beamformee & he_cap_from_ie->su_beamformee; + he_cap->mu_beamformer = + he_cap->mu_beamformer & he_cap_from_ie->mu_beamformer; + + pe_debug("After update: su_beamformer: %d, su_beamformee: %d, mu_beamformer: %d", + he_cap->su_beamformer, he_cap->su_beamformee, he_cap->mu_beamformer); + if (!he_cap->su_beamformer) { + he_cap->mu_beamformer = 0; + he_cap->num_sounding_lt_80 = 0; + he_cap->num_sounding_gt_80 = 0; + vht_cfg->su_beam_former = 0; + vht_cfg->mu_beam_former = 0; + vht_cfg->num_soundingdim = 0; + } + if (!he_cap->su_beamformee) { + he_cap->bfee_sts_lt_80 = 0; + he_cap->bfee_sts_gt_80 = 0; + vht_cfg->su_beam_formee = 0; + vht_cfg->mu_beam_formee = 0; + vht_cfg->csnof_beamformer_antSup = 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (mlme_priv) { + mlme_priv->he_config.mu_beamformer = he_cap->mu_beamformer; + mlme_priv->he_config.su_beamformer = he_cap->su_beamformer; + mlme_priv->he_config.su_beamformee = he_cap->su_beamformee; + mlme_priv->he_config.bfee_sts_lt_80 = he_cap->bfee_sts_lt_80; + mlme_priv->he_config.bfee_sts_gt_80 = he_cap->bfee_sts_gt_80; + mlme_priv->he_config.num_sounding_lt_80 = + he_cap->num_sounding_lt_80; + mlme_priv->he_config.num_sounding_gt_80 = + he_cap->num_sounding_gt_80; + } + wma_set_he_txbf_params(session->vdev_id, he_cap->su_beamformer, + he_cap->su_beamformee, he_cap->mu_beamformer); +} + +void lim_decide_he_op(struct mac_context *mac_ctx, uint32_t *mlme_he_ops, + struct pe_session *session) +{ + uint32_t val; + uint8_t color; + struct he_ops_network_endian *he_ops_from_ie; + tDot11fIEhe_op he_ops = {0}; + struct add_ie_params *add_ie = &session->add_ie_params; + uint8_t extracted_buff[DOT11F_IE_HE_OP_MAX_LEN + 2]; + QDF_STATUS status; + + qdf_mem_zero(extracted_buff, sizeof(extracted_buff)); + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_HE_OP, ONE_BYTE, + HE_OP_OUI_TYPE, (uint8_t)HE_OP_OUI_SIZE, + extracted_buff, DOT11F_IE_HE_OP_MAX_LEN); + if (QDF_STATUS_SUCCESS != status) { + pe_debug("Failed to strip HE OP IE status: %d", status); + return; + } + he_ops_from_ie = (struct he_ops_network_endian *) + &extracted_buff[HE_OP_OUI_SIZE + 2]; + + if (he_ops_from_ie->bss_color) { + he_ops.bss_color = he_ops_from_ie->bss_color; + } else { + qdf_get_random_bytes(&color, sizeof(color)); + /* make sure color is within 1-63*/ + he_ops.bss_color = (color % WNI_CFG_HE_OPS_BSS_COLOR_MAX) + 1; + } + he_ops.default_pe = he_ops_from_ie->default_pe; + he_ops.twt_required = he_ops_from_ie->twt_required; + he_ops.txop_rts_threshold = he_ops_from_ie->txop_rts_threshold; + he_ops.partial_bss_col = he_ops_from_ie->partial_bss_col; + + val = mac_ctx->mlme_cfg->he_caps.he_ops_basic_mcs_nss; + + *((uint16_t *)he_ops.basic_mcs_nss) = (uint16_t)val; + + qdf_mem_copy(&session->he_op, &he_ops, sizeof(tDot11fIEhe_op)); + + pe_debug("HE Op: bss_color: 0x%0x, default_pe_duration: 0x%0x", + he_ops.bss_color, he_ops.default_pe); + pe_debug("He Op: twt_required: 0x%0x, txop_rts_threshold: 0x%0x", + he_ops.twt_required, he_ops.txop_rts_threshold); + pe_debug("HE Op: partial_bss_color: 0x%0x", + he_ops.partial_bss_col); + pe_debug("HE Op: BSS color disabled: 0x%0x", + he_ops.bss_col_disabled); + pe_debug("HE Op: Basic MCS NSS: 0x%04x", + *((uint16_t *)he_ops.basic_mcs_nss)); + + wma_update_vdev_he_ops(mlme_he_ops, &he_ops); +} + +void lim_update_he_caps_mcs(struct mac_context *mac, struct pe_session *session) +{ + uint32_t tx_mcs_map = 0; + uint32_t rx_mcs_map = 0; + uint32_t mcs_map = 0; + struct wlan_objmgr_vdev *vdev = session->vdev; + struct mlme_legacy_priv *mlme_priv; + struct wlan_mlme_cfg *mlme_cfg = mac->mlme_cfg; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + rx_mcs_map = mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80; + tx_mcs_map = mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_lt_80; + mcs_map = rx_mcs_map & 0x3; + + if (session->nss == 1) { + tx_mcs_map = HE_SET_MCS_4_NSS(tx_mcs_map, HE_MCS_DISABLE, 2); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, HE_MCS_DISABLE, 2); + } else { + tx_mcs_map = HE_SET_MCS_4_NSS(tx_mcs_map, mcs_map, 2); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, mcs_map, 2); + } + + mlme_priv->he_config.tx_he_mcs_map_lt_80 = tx_mcs_map; + mlme_priv->he_config.rx_he_mcs_map_lt_80 = rx_mcs_map; + *((uint16_t *)mlme_priv->he_config.tx_he_mcs_map_160) = tx_mcs_map; + *((uint16_t *)mlme_priv->he_config.rx_he_mcs_map_160) = rx_mcs_map; + qdf_mem_copy(mlme_priv->he_config.tx_he_mcs_map_160, &tx_mcs_map, + sizeof(u_int16_t)); + qdf_mem_copy(mlme_priv->he_config.rx_he_mcs_map_160, &rx_mcs_map, + sizeof(u_int16_t)); +} + +static void +lim_revise_req_he_cap_per_band(struct mlme_legacy_priv *mlme_priv, + struct pe_session *session) +{ + struct mac_context *mac = session->mac_ctx; + tDot11fIEhe_cap *he_config; + struct wlan_objmgr_psoc *psoc; + uint32_t max_ampdu_len_exp; + + psoc = wlan_vdev_get_psoc(session->vdev); + if (!psoc) { + pe_err("Failed to get psoc"); + return; + } + max_ampdu_len_exp = cfg_get(psoc, CFG_HE_MAX_AMPDU_LEN); + + he_config = &mlme_priv->he_config; + if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) { + he_config->bfee_sts_lt_80 = + mac->he_cap_2g.bfee_sts_lt_80; + he_config->tx_he_mcs_map_lt_80 = + mac->he_cap_2g.tx_he_mcs_map_lt_80; + he_config->rx_he_mcs_map_lt_80 = + mac->he_cap_2g.rx_he_mcs_map_lt_80; + he_config->max_ampdu_len_exp_ext = + QDF_MIN(max_ampdu_len_exp, + mac->he_cap_2g.max_ampdu_len_exp_ext); + he_config->ul_2x996_tone_ru_supp = 0; + he_config->num_sounding_gt_80 = 0; + he_config->bfee_sts_gt_80 = 0; + he_config->tb_ppdu_tx_stbc_gt_80mhz = 0; + he_config->rx_stbc_gt_80mhz = 0; + he_config->he_ppdu_20_in_160_80p80Mhz = 0; + he_config->he_ppdu_80_in_160_80p80Mhz = 0; + } else { + he_config->bfee_sts_lt_80 = + mac->he_cap_5g.bfee_sts_lt_80; + he_config->tx_he_mcs_map_lt_80 = + mac->he_cap_5g.tx_he_mcs_map_lt_80; + he_config->rx_he_mcs_map_lt_80 = + mac->he_cap_5g.rx_he_mcs_map_lt_80; + + he_config->num_sounding_lt_80 = + mac->he_cap_5g.num_sounding_lt_80; + he_config->max_ampdu_len_exp_ext = + QDF_MIN(max_ampdu_len_exp, + mac->he_cap_5g.max_ampdu_len_exp_ext); + if (he_config->chan_width_2 || + he_config->chan_width_3) { + he_config->bfee_sts_gt_80 = + mac->he_cap_5g.bfee_sts_gt_80; + he_config->num_sounding_gt_80 = + mac->he_cap_5g.num_sounding_gt_80; + he_config->he_ppdu_20_in_160_80p80Mhz = + mac->he_cap_5g.he_ppdu_20_in_160_80p80Mhz; + he_config->he_ppdu_80_in_160_80p80Mhz = + mac->he_cap_5g.he_ppdu_80_in_160_80p80Mhz; + he_config->rx_stbc_gt_80mhz = + mac->he_cap_5g.rx_stbc_gt_80mhz; + he_config->tb_ppdu_tx_stbc_gt_80mhz = + mac->he_cap_5g.tb_ppdu_tx_stbc_gt_80mhz; + he_config->ul_2x996_tone_ru_supp = + mac->he_cap_5g.ul_2x996_tone_ru_supp; + } + he_config->su_feedback_tone16 = + mac->he_cap_5g.su_feedback_tone16; + he_config->mu_feedback_tone16 = + mac->he_cap_5g.mu_feedback_tone16; + he_config->codebook_su = mac->he_cap_5g.codebook_su; + he_config->codebook_mu = mac->he_cap_5g.codebook_mu; + } +} + +void lim_copy_bss_he_cap(struct pe_session *session) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + lim_revise_req_he_cap_per_band(mlme_priv, session); + lim_update_he_caps_mcs(session->mac_ctx, session); + qdf_mem_copy(&(session->he_config), &(mlme_priv->he_config), + sizeof(session->he_config)); +} + +void lim_copy_join_req_he_cap(struct pe_session *session) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + if (!session->mac_ctx->usr_cfg_tx_bfee_nsts) + lim_revise_req_he_cap_per_band(mlme_priv, session); + qdf_mem_copy(&(session->he_config), &(mlme_priv->he_config), + sizeof(session->he_config)); + if (WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq)) { + session->he_config.chan_width_1 = 0; + session->he_config.chan_width_2 = 0; + session->he_config.chan_width_3 = 0; + session->he_config.chan_width_5 = 0; + session->he_config.chan_width_6 = 0; + } else { + session->he_config.chan_width_0 = 0; + session->he_config.chan_width_4 = 0; + session->he_config.chan_width_6 = 0; + } +} + +void lim_log_he_cap(struct mac_context *mac, tDot11fIEhe_cap *he_cap) +{ + uint8_t chan_width; + struct ppet_hdr *hdr; + + if (!he_cap->present) + return; + + pe_nofl_debug("HE Capabilities: htc_he 0x%x twt_req 0x%x twt_res 0x%x fragmentation 0x%x max frag msdu amsdu 0x%x min frag 0x%x", + he_cap->htc_he, he_cap->twt_request, + he_cap->twt_responder, he_cap->fragmentation, + he_cap->max_num_frag_msdu_amsdu_exp, + he_cap->min_frag_size); + pe_nofl_debug("\ttrig frm mac pad 0x%x multi tid aggr supp 0x%x link adaptation 0x%x all ack 0x%x trigd_rsp_sched 0x%x a_bsr 0x%x", + he_cap->trigger_frm_mac_pad, + he_cap->multi_tid_aggr_rx_supp, + he_cap->he_link_adaptation, he_cap->all_ack, + he_cap->trigd_rsp_sched, he_cap->a_bsr); + pe_nofl_debug("\tBC twt 0x%x ba_32bit_bitmap supp 0x%x mu_cascade 0x%x ack_enabled_multitid 0x%x omi_a_ctrl 0x%x ofdma_ra 0x%x", + he_cap->broadcast_twt, he_cap->ba_32bit_bitmap, + he_cap->mu_cascade, he_cap->ack_enabled_multitid, + he_cap->omi_a_ctrl, he_cap->ofdma_ra); + pe_nofl_debug("\tmax_ampdu_len exp ext 0x%x amsdu_frag 0x%x flex_twt_sched 0x%x rx_ctrl frm 0x%x bsrp_ampdu_aggr 0x%x qtp 0x%x a_bqr 0x%x", + he_cap->max_ampdu_len_exp_ext, he_cap->amsdu_frag, + he_cap->flex_twt_sched, he_cap->rx_ctrl_frame, + he_cap->bsrp_ampdu_aggr, he_cap->qtp, he_cap->a_bqr); + pe_nofl_debug("\tSR Reponder 0x%x ndp_feedback 0x%x ops_supp 0x%x amsdu_in_ampdu 0x%x multi_tid_aggr_tx 0x%x he_sub_ch_sel_tx 0x%x", + he_cap->spatial_reuse_param_rspder, + he_cap->ndp_feedback_supp, + he_cap->ops_supp, he_cap->amsdu_in_ampdu, + he_cap->multi_tid_aggr_tx_supp, + he_cap->he_sub_ch_sel_tx_supp); + + pe_nofl_debug("\tul_2x996_tone_ru 0x%x om_ctrl_ul_mu_data_dis_rx 0x%x dynamic_smps 0x%x punctured_sounding 0x%x ht_vht_trg_frm_rx 0x%x", + he_cap->ul_2x996_tone_ru_supp, + he_cap->om_ctrl_ul_mu_data_dis_rx, + he_cap->he_dynamic_smps, he_cap->punctured_sounding_supp, + he_cap->ht_vht_trg_frm_rx_supp); + + chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0, + he_cap->chan_width_1, he_cap->chan_width_2, + he_cap->chan_width_3, he_cap->chan_width_4, + he_cap->chan_width_5, he_cap->chan_width_6); + + pe_nofl_debug("\tchan width %d rx_pream_puncturing 0x%x device_class 0x%x ldpc_coding 0x%x 1x_ltf_800_gi_ppdu 0x%x midamble_tx_rx_max_nsts 0x%x", + chan_width, he_cap->rx_pream_puncturing, + he_cap->device_class, + he_cap->ldpc_coding, he_cap->he_1x_ltf_800_gi_ppdu, + he_cap->midamble_tx_rx_max_nsts); + + pe_nofl_debug("\t4x_ltf_3200_gi_ndp 0x%x tb_ppdu_tx_stbc_lt_80mhz 0x%x rx_stbc_lt_80mhz 0x%x doppler 0x%x ul_mu 0x%x dcm_enc_tx 0x%x dcm_enc_rx 0x%x", + he_cap->he_4x_ltf_3200_gi_ndp, + he_cap->tb_ppdu_tx_stbc_lt_80mhz, + he_cap->rx_stbc_lt_80mhz, he_cap->doppler, he_cap->ul_mu, + he_cap->dcm_enc_tx, he_cap->dcm_enc_rx); + + pe_nofl_debug("\tul_he_mu 0x%x su_bfer 0x%x su_fee 0x%x mu_bfer 0x%x bfee_sts_lt_80 0x%x bfee_sts_gt_80 0x%x num_sd_lt_80 0x%x num_sd_gt_80 0x%x", + he_cap->ul_he_mu, he_cap->su_beamformer, + he_cap->su_beamformee, + he_cap->mu_beamformer, he_cap->bfee_sts_lt_80, + he_cap->bfee_sts_gt_80, he_cap->num_sounding_lt_80, + he_cap->num_sounding_gt_80); + + pe_nofl_debug("\tsu_fb_tone16 0x%x mu_fb_tone16 0x%x codebook_su 0x%x codebook_mu 0x%x bforming_feedback 0x%x he_er_su_ppdu 0x%x dl_mu_mimo_part_bw 0x%x", + he_cap->su_feedback_tone16, he_cap->mu_feedback_tone16, + he_cap->codebook_su, he_cap->codebook_mu, + he_cap->beamforming_feedback, he_cap->he_er_su_ppdu, + he_cap->dl_mu_mimo_part_bw); + + pe_nofl_debug("\tppet_present 0x%x srp 0x%x power_boost 0x%x ltf_800_gi_4x 0x%x tb_ppdu_tx_stbc_gt_80mhz 0x%x rx_stbc_gt_80mhz 0x%x max_nc 0x%x", + he_cap->ppet_present, he_cap->srp, + he_cap->power_boost, he_cap->he_ltf_800_gi_4x, + he_cap->tb_ppdu_tx_stbc_gt_80mhz, + he_cap->rx_stbc_gt_80mhz, he_cap->max_nc); + + pe_nofl_debug("\ter_ltf_800_gi_4x 0x%x ppdu_20_in_40Mhz_2G 0x%x ppdu_20_in_160_80p80Mhz 0x%x ppdu_80_in_160_80p80Mhz 0x%x er_1x_ltf_gi 0x%x", + he_cap->er_he_ltf_800_gi_4x, + he_cap->he_ppdu_20_in_40Mhz_2G, + he_cap->he_ppdu_20_in_160_80p80Mhz, + he_cap->he_ppdu_80_in_160_80p80Mhz, + he_cap->er_1x_he_ltf_gi); + + pe_nofl_debug("\tmidamble_tx_rx_1x_ltf 0x%x dcm_max_bw 0x%x longer_than_16_he_sigb_ofdm_sym 0x%x non_trig_cqi_feedback 0x%x tx_1024_qam_lt_242_tone_ru 0x%x", + he_cap->midamble_tx_rx_1x_he_ltf, he_cap->dcm_max_bw, + he_cap->longer_than_16_he_sigb_ofdm_sym, + he_cap->non_trig_cqi_feedback, + he_cap->tx_1024_qam_lt_242_tone_ru); + + pe_nofl_debug("\trx_1024_qam_lt_242_tone_ru 0x%x rx_full_bw_su_he_mu_compress_sigb 0x%x rx_he_mcs_map_lt_80 0x%x tx_he_mcs_map_lt_80 0x%x", + he_cap->rx_1024_qam_lt_242_tone_ru, + he_cap->rx_full_bw_su_he_mu_compress_sigb, + he_cap->rx_he_mcs_map_lt_80, + he_cap->tx_he_mcs_map_lt_80); + + hdr = (struct ppet_hdr *)&he_cap->ppet; + pe_nofl_debug("\tRx MCS map 160 Mhz: 0x%x Tx MCS map 160 Mhz: 0x%x Rx MCS map 80+80 Mhz: 0x%x Tx MCS map 80+80 Mhz: 0x%x ppe_th:: nss_count: %d, ru_idx_msk: %d", + *((uint16_t *)he_cap->rx_he_mcs_map_160), + *((uint16_t *)he_cap->tx_he_mcs_map_160), + *((uint16_t *)he_cap->rx_he_mcs_map_80_80), + *((uint16_t *)he_cap->tx_he_mcs_map_80_80), + hdr->nss, hdr->ru_idx_mask); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &he_cap->ppet, HE_MAX_PPET_SIZE); +} + +void lim_log_he_op(struct mac_context *mac, tDot11fIEhe_op *he_ops, + struct pe_session *session) +{ + pe_debug("bss_color 0x%x pe_dur 0x%x twt req 0x%x txop_rts_thres 0x%x vht_op 0x%x part color 0x%x Co-located 0x%x color dis 0x%x basic mcs nss 0x%x", + he_ops->bss_color, he_ops->default_pe, + he_ops->twt_required, he_ops->txop_rts_threshold, + he_ops->vht_oper_present, he_ops->partial_bss_col,\ + he_ops->co_located_bss, he_ops->bss_col_disabled, + *((uint16_t *)he_ops->basic_mcs_nss)); + + if (!session->he_6ghz_band && he_ops->vht_oper_present) + pe_debug("VHT Info: ch_bw %d cntr_freq0 %d cntr_freq1 %d", + he_ops->vht_oper.info.chan_width, + he_ops->vht_oper.info.center_freq_seg0, + he_ops->vht_oper.info.center_freq_seg1); + else if (he_ops->oper_info_6g_present) + pe_debug("6G_op_info:ch_bw %d cntr_freq0 %d cntr_freq1 %d dup_bcon %d, min_rate %d", + he_ops->oper_info_6g.info.ch_width, + he_ops->oper_info_6g.info.center_freq_seg0, + he_ops->oper_info_6g.info.center_freq_seg1, + he_ops->oper_info_6g.info.dup_bcon, + he_ops->oper_info_6g.info.min_rate); +} + +void lim_log_he_6g_cap(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *he_6g_cap) +{ + pe_debug("min_mpdu_space: %0d, max_mpdu_len_exp: %0x, max_mpdu_len %0x, smps %0x, rd %0x rx_ant_ptn %d tx_ant_ptn %d", + he_6g_cap->min_mpdu_start_spacing, + he_6g_cap->max_ampdu_len_exp, he_6g_cap->max_mpdu_len, + he_6g_cap->sm_pow_save, he_6g_cap->rd_responder, + he_6g_cap->rx_ant_pattern_consistency, + he_6g_cap->tx_ant_pattern_consistency); +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +void lim_log_he_bss_color(struct mac_context *mac, + tDot11fIEbss_color_change *he_bss_color) +{ + pe_debug("countdown: %d, new_color: %d", + he_bss_color->countdown, he_bss_color->new_color); +} +#endif + +void lim_update_sta_he_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + if (LIM_IS_AP_ROLE(session_entry)) + add_sta_params->he_capable = sta_ds->mlmStaContext.he_capable && + session_entry->he_capable; +#ifdef FEATURE_WLAN_TDLS + else if (STA_ENTRY_TDLS_PEER == sta_ds->staType) + add_sta_params->he_capable = sta_ds->mlmStaContext.he_capable; +#endif + else + add_sta_params->he_capable = session_entry->he_capable; + + add_sta_params->he_mcs_12_13_map = sta_ds->he_mcs_12_13_map; + pe_debug("he_capable: %d", add_sta_params->he_capable); +} + +void lim_update_bss_he_capable(struct mac_context *mac, + struct bss_params *add_bss) +{ + add_bss->he_capable = true; + pe_debug("he_capable: %d", add_bss->he_capable); +} + +void lim_update_stads_he_capable(tpDphHashNode sta_ds, tpSirAssocReq assoc_req) +{ + sta_ds->mlmStaContext.he_capable = assoc_req->he_cap.present; +} + +void lim_update_session_he_capable(struct mac_context *mac, struct pe_session *session) +{ + session->he_capable = true; + if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + session->htCapability = 0; + session->vhtCapability = 0; + session->he_6ghz_band = 1; + } + + if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) { + session->he_config.ul_mu = mac->he_cap_2g.ul_mu; + if (!mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) + session->vhtCapability = 0; + } + + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) { + session->he_config.ul_mu = mac->he_cap_5g.ul_mu; + session->he_config.rx_pream_puncturing = + mac->he_cap_5g.rx_pream_puncturing; + } +} + +void lim_update_session_he_capable_chan_switch(struct mac_context *mac, + struct pe_session *session, + uint32_t new_chan_freq) +{ + session->he_capable = true; + if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq) && + !wlan_reg_is_6ghz_chan_freq(new_chan_freq)) { + session->htCapability = 1; + session->vhtCapability = 1; + session->he_6ghz_band = 0; + } else if (!wlan_reg_is_6ghz_chan_freq(session->curr_op_freq) && + wlan_reg_is_6ghz_chan_freq(new_chan_freq)) { + session->htCapability = 0; + session->vhtCapability = 0; + session->he_6ghz_band = 1; + } + + /* + * If new channel is 2.4gh set VHT as per the b24ghz_band INI + * if new channel is 5Ghz set the vht, this will happen if we move from + * 2.4Ghz to 5Ghz. + */ + if (wlan_reg_is_24ghz_ch_freq(new_chan_freq) && + !mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) + session->vhtCapability = 0; + else if (wlan_reg_is_5ghz_ch_freq(new_chan_freq)) + session->vhtCapability = 1; + /* + * Re-initialize color bss parameters during channel change + */ + + session->he_op.bss_col_disabled = 1; + session->bss_color_changing = 1; + session->he_bss_color_change.new_color = session->he_op.bss_color; + session->he_bss_color_change.countdown = BSS_COLOR_SWITCH_COUNTDOWN; + pe_debug("he_capable: %d ht %d vht %d 6ghz_band %d new freq %d vht in 2.4gh %d", + session->he_capable, session->htCapability, + session->vhtCapability, session->he_6ghz_band, new_chan_freq, + mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band); +} + +void lim_set_he_caps(struct mac_context *mac, uint8_t *ie_start, + uint32_t num_bytes, uint8_t band) +{ + const uint8_t *ie = NULL; + tDot11fIEhe_cap dot11_cap; + struct he_capability_info *he_cap; + bool is_band_2g = false; + + if (band == CDS_BAND_2GHZ) + is_band_2g = true; + + populate_dot11f_he_caps_by_band(mac, is_band_2g, &dot11_cap, + NULL); + lim_log_he_cap(mac, &dot11_cap); + ie = wlan_get_ext_ie_ptr_from_ext_id(HE_CAP_OUI_TYPE, + HE_CAP_OUI_SIZE, ie_start, num_bytes); + if (ie) { + /* convert from unpacked to packed structure */ + he_cap = (struct he_capability_info *) &ie[2 + HE_CAP_OUI_SIZE]; + + he_cap->htc_he = dot11_cap.htc_he; + he_cap->twt_request = dot11_cap.twt_request; + he_cap->twt_responder = dot11_cap.twt_responder; + he_cap->fragmentation = dot11_cap.fragmentation; + he_cap->max_num_frag_msdu_amsdu_exp = + dot11_cap.max_num_frag_msdu_amsdu_exp; + he_cap->min_frag_size = dot11_cap.min_frag_size; + he_cap->trigger_frm_mac_pad = dot11_cap.trigger_frm_mac_pad; + he_cap->multi_tid_aggr_rx_supp = + dot11_cap.multi_tid_aggr_rx_supp; + he_cap->he_link_adaptation = dot11_cap.he_link_adaptation; + he_cap->all_ack = dot11_cap.all_ack; + he_cap->trigd_rsp_sched = dot11_cap.trigd_rsp_sched; + he_cap->a_bsr = dot11_cap.a_bsr; + he_cap->broadcast_twt = dot11_cap.broadcast_twt; + he_cap->ba_32bit_bitmap = dot11_cap.ba_32bit_bitmap; + he_cap->mu_cascade = dot11_cap.mu_cascade; + he_cap->ack_enabled_multitid = dot11_cap.ack_enabled_multitid; + he_cap->omi_a_ctrl = dot11_cap.omi_a_ctrl; + he_cap->ofdma_ra = dot11_cap.ofdma_ra; + he_cap->max_ampdu_len_exp_ext = dot11_cap.max_ampdu_len_exp_ext; + he_cap->amsdu_frag = dot11_cap.amsdu_frag; + he_cap->flex_twt_sched = dot11_cap.flex_twt_sched; + he_cap->rx_ctrl_frame = dot11_cap.rx_ctrl_frame; + + he_cap->bsrp_ampdu_aggr = dot11_cap.bsrp_ampdu_aggr; + he_cap->qtp = dot11_cap.qtp; + he_cap->a_bqr = dot11_cap.a_bqr; + he_cap->spatial_reuse_param_rspder = + dot11_cap.spatial_reuse_param_rspder; + he_cap->ops_supp = dot11_cap.ops_supp; + he_cap->ndp_feedback_supp = dot11_cap.ndp_feedback_supp; + he_cap->amsdu_in_ampdu = dot11_cap.amsdu_in_ampdu; + + if (!mac->roam.configParam.channelBondingMode5GHz) { + /* + * clearing bits for setting 20MHz support + */ + dot11_cap.chan_width_1 = + HE_CH_WIDTH_CLR_BIT(dot11_cap.chan_width_1, 0); + dot11_cap.chan_width_2 = + HE_CH_WIDTH_CLR_BIT(dot11_cap.chan_width_2, 0); + dot11_cap.chan_width_3 = + HE_CH_WIDTH_CLR_BIT(dot11_cap.chan_width_3, 0); + he_cap->he_ppdu_20_in_160_80p80Mhz = 0; + } + he_cap->chan_width = HE_CH_WIDTH_COMBINE(dot11_cap.chan_width_0, + dot11_cap.chan_width_1, dot11_cap.chan_width_2, + dot11_cap.chan_width_3, dot11_cap.chan_width_4, + dot11_cap.chan_width_5, dot11_cap.chan_width_6); + + he_cap->rx_pream_puncturing = dot11_cap.rx_pream_puncturing; + he_cap->device_class = dot11_cap.device_class; + he_cap->ldpc_coding = dot11_cap.ldpc_coding; + he_cap->he_1x_ltf_800_gi_ppdu = dot11_cap.he_1x_ltf_800_gi_ppdu; + he_cap->midamble_tx_rx_max_nsts = + dot11_cap.midamble_tx_rx_max_nsts; + he_cap->he_4x_ltf_3200_gi_ndp = dot11_cap.he_4x_ltf_3200_gi_ndp; + he_cap->tb_ppdu_tx_stbc_lt_80mhz = + dot11_cap.tb_ppdu_tx_stbc_lt_80mhz; + he_cap->rx_stbc_lt_80mhz = dot11_cap.rx_stbc_lt_80mhz; + he_cap->tb_ppdu_tx_stbc_gt_80mhz = + dot11_cap.tb_ppdu_tx_stbc_gt_80mhz; + he_cap->rx_stbc_gt_80mhz = dot11_cap.rx_stbc_gt_80mhz; + he_cap->doppler = dot11_cap.doppler; + he_cap->ul_mu = dot11_cap.ul_mu; + he_cap->dcm_enc_tx = dot11_cap.dcm_enc_tx; + he_cap->dcm_enc_rx = dot11_cap.dcm_enc_rx; + he_cap->ul_he_mu = dot11_cap.ul_he_mu; + he_cap->su_beamformer = dot11_cap.su_beamformer; + + he_cap->su_beamformee = dot11_cap.su_beamformee; + he_cap->mu_beamformer = dot11_cap.mu_beamformer; + he_cap->bfee_sts_lt_80 = dot11_cap.bfee_sts_lt_80; + he_cap->bfee_sts_gt_80 = dot11_cap.bfee_sts_gt_80; + he_cap->num_sounding_lt_80 = dot11_cap.num_sounding_lt_80; + he_cap->num_sounding_gt_80 = dot11_cap.num_sounding_gt_80; + he_cap->su_feedback_tone16 = dot11_cap.su_feedback_tone16; + he_cap->mu_feedback_tone16 = dot11_cap.mu_feedback_tone16; + he_cap->codebook_su = dot11_cap.codebook_su; + he_cap->codebook_mu = dot11_cap.codebook_mu; + he_cap->beamforming_feedback = dot11_cap.beamforming_feedback; + he_cap->he_er_su_ppdu = dot11_cap.he_er_su_ppdu; + he_cap->dl_mu_mimo_part_bw = dot11_cap.dl_mu_mimo_part_bw; + he_cap->ppet_present = dot11_cap.ppet_present; + he_cap->srp = dot11_cap.srp; + he_cap->power_boost = dot11_cap.power_boost; + + he_cap->tx_1024_qam_lt_242_tone_ru = + dot11_cap.tx_1024_qam_lt_242_tone_ru; + he_cap->rx_1024_qam_lt_242_tone_ru = + dot11_cap.rx_1024_qam_lt_242_tone_ru; + + he_cap->he_ltf_800_gi_4x = dot11_cap.he_ltf_800_gi_4x; + he_cap->max_nc = dot11_cap.max_nc; + he_cap->er_he_ltf_800_gi_4x = dot11_cap.er_he_ltf_800_gi_4x; + he_cap->he_ppdu_20_in_40Mhz_2G = + dot11_cap.he_ppdu_20_in_40Mhz_2G; + he_cap->he_ppdu_20_in_160_80p80Mhz = + dot11_cap.he_ppdu_20_in_160_80p80Mhz; + he_cap->he_ppdu_80_in_160_80p80Mhz = + dot11_cap.he_ppdu_80_in_160_80p80Mhz; + he_cap->er_1x_he_ltf_gi = + dot11_cap.er_1x_he_ltf_gi; + he_cap->midamble_tx_rx_1x_he_ltf = + dot11_cap.midamble_tx_rx_1x_he_ltf; + he_cap->reserved2 = dot11_cap.reserved2; + + he_cap->rx_he_mcs_map_lt_80 = dot11_cap.rx_he_mcs_map_lt_80; + he_cap->tx_he_mcs_map_lt_80 = dot11_cap.tx_he_mcs_map_lt_80; + if (dot11_cap.chan_width_2) { + he_cap->rx_he_mcs_map_160 = + *((uint16_t *)dot11_cap.rx_he_mcs_map_160); + he_cap->tx_he_mcs_map_160 = + *((uint16_t *)dot11_cap.tx_he_mcs_map_160); + ie_start[1] += HE_CAP_160M_MCS_MAP_LEN; + } + if (dot11_cap.chan_width_3) { + he_cap->rx_he_mcs_map_80_80 = + *((uint16_t *)dot11_cap.rx_he_mcs_map_80_80); + he_cap->tx_he_mcs_map_80_80 = + *((uint16_t *)dot11_cap.tx_he_mcs_map_80_80); + ie_start[1] += HE_CAP_80P80_MCS_MAP_LEN; + } + } +} + +static void lim_intersect_he_ch_width_2g(struct mac_context *mac, + struct he_capability_info *he_cap, + uint8_t vdev_id) +{ + struct wlan_objmgr_psoc *psoc; + uint32_t cbm_24ghz; + + psoc = mac->psoc; + if (!psoc) + return; + + cbm_24ghz = lim_get_sta_cb_mode_for_24ghz(mac, vdev_id); + + pe_debug("channel bonding mode 2.4GHz %d", cbm_24ghz); + + if (!cbm_24ghz) { + /* B0: 40Mhz channel width in the 2.4GHz band */ + he_cap->chan_width = HE_CH_WIDTH_CLR_BIT(he_cap->chan_width, 0); + he_cap->he_ppdu_20_in_40Mhz_2G = 0; + } + + pe_debug("HE cap: chan_width: 0x%07x he_ppdu_20_in_40Mhz_2G %d", + he_cap->chan_width, he_cap->he_ppdu_20_in_40Mhz_2G); +} + +static uint8_t lim_set_he_caps_ppet(struct mac_context *mac, uint8_t *ie, + enum cds_band_type band) +{ + uint8_t ppe_th[WNI_CFG_HE_PPET_LEN] = {0}; + /* Append at the end after ID + LEN + OUI + IE_Data */ + uint8_t offset = ie[1] + 1 + 1 + 1; + uint8_t num_ppe_th; + + if (band == CDS_BAND_2GHZ) + qdf_mem_copy(ppe_th, mac->mlme_cfg->he_caps.he_ppet_2g, + WNI_CFG_HE_PPET_LEN); + else if (band == CDS_BAND_5GHZ) + qdf_mem_copy(ppe_th, mac->mlme_cfg->he_caps.he_ppet_5g, + WNI_CFG_HE_PPET_LEN); + else + return 0; + + num_ppe_th = lim_truncate_ppet(ppe_th, WNI_CFG_HE_PPET_LEN); + + qdf_mem_copy(ie + offset, ppe_th, num_ppe_th); + + return num_ppe_th; +} + +QDF_STATUS lim_send_he_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + uint8_t he_caps[SIR_MAC_HE_CAP_MIN_LEN + HE_CAP_OUI_LEN + + HE_CAP_160M_MCS_MAP_LEN + HE_CAP_80P80_MCS_MAP_LEN + + WNI_CFG_HE_PPET_LEN]; + struct he_capability_info *he_cap; + QDF_STATUS status_5g, status_2g; + uint8_t he_cap_total_len = SIR_MAC_HE_CAP_MIN_LEN + HE_CAP_OUI_LEN + + HE_CAP_160M_MCS_MAP_LEN + + HE_CAP_80P80_MCS_MAP_LEN; + uint8_t num_ppe_th = 0; + bool nan_beamforming_supported; + bool disable_nan_tx_bf = false, value = false; + + /* Sending only minimal info(no PPET) to FW now, update if required */ + qdf_mem_zero(he_caps, he_cap_total_len); + he_caps[0] = DOT11F_EID_HE_CAP; + he_caps[1] = SIR_MAC_HE_CAP_MIN_LEN; + qdf_mem_copy(&he_caps[2], HE_CAP_OUI_TYPE, HE_CAP_OUI_SIZE); + lim_set_he_caps(mac_ctx, he_caps, he_cap_total_len, + CDS_BAND_5GHZ); + he_cap = (struct he_capability_info *) (&he_caps[2 + HE_CAP_OUI_SIZE]); + + nan_beamforming_supported = + ucfg_nan_is_beamforming_supported(mac_ctx->psoc); + if (device_mode == QDF_NDI_MODE && !nan_beamforming_supported) { + he_cap->su_beamformee = 0; + he_cap->su_beamformer = 0; + he_cap->mu_beamformer = 0; + he_cap->bfee_sts_gt_80 = 0; + he_cap->bfee_sts_lt_80 = 0; + he_cap->num_sounding_gt_80 = 0; + he_cap->num_sounding_lt_80 = 0; + he_cap->su_feedback_tone16 = 0; + he_cap->mu_feedback_tone16 = 0; + disable_nan_tx_bf = true; + } + + /* + * For 5G band HE cap, set the beamformee STS <= 80Mhz to + * mac->he_cap_5g.bfee_sts_lt_80 to keep the values same + * as initial connection + */ + if (!disable_nan_tx_bf) { + he_cap->bfee_sts_lt_80 = mac_ctx->he_cap_5g.bfee_sts_lt_80; + he_cap->bfee_sts_gt_80 = mac_ctx->he_cap_5g.bfee_sts_gt_80; + he_cap->num_sounding_gt_80 = + mac_ctx->he_cap_5g.num_sounding_gt_80; + pe_debug("he_cap_5g: bfee_sts_gt_80 %d num_sounding_gt_80 %d", + he_cap->bfee_sts_gt_80, he_cap->num_sounding_gt_80); + } + + if (he_cap->ppet_present) + num_ppe_th = lim_set_he_caps_ppet(mac_ctx, he_caps, + CDS_BAND_5GHZ); + + if ((device_mode == QDF_STA_MODE) || + (device_mode == QDF_P2P_CLIENT_MODE)) { + ucfg_twt_cfg_get_requestor(mac_ctx->psoc, &value); + if (!value) { + he_cap->twt_request = false; + he_cap->flex_twt_sched = false; + } + he_cap->twt_responder = false; + } else if ((device_mode == QDF_SAP_MODE) || + (device_mode == QDF_P2P_GO_MODE)) { + ucfg_twt_cfg_get_responder(mac_ctx->psoc, &value); + if (!value) { + he_cap->twt_responder = false; + he_cap->flex_twt_sched = false; + } + he_cap->twt_request = false; + } + + status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP, + CDS_BAND_5GHZ, &he_caps[2], + he_caps[1] + 1 + num_ppe_th); + if (QDF_IS_STATUS_ERROR(status_5g)) + pe_err("Unable send HE Cap IE for 5GHZ band, status: %d", + status_5g); + + qdf_mem_zero(he_caps, he_cap_total_len); + he_caps[0] = DOT11F_EID_HE_CAP; + he_caps[1] = SIR_MAC_HE_CAP_MIN_LEN; + qdf_mem_copy(&he_caps[2], HE_CAP_OUI_TYPE, HE_CAP_OUI_SIZE); + lim_set_he_caps(mac_ctx, he_caps, he_cap_total_len, + CDS_BAND_2GHZ); + he_cap = (struct he_capability_info *)(&he_caps[2 + HE_CAP_OUI_SIZE]); + + /* + * For 5G band HE cap, set the beamformee STS <= 80Mhz to + * mac->he_cap_5g.bfee_sts_lt_80 to keep the values same + * as initial connection + */ + if (!disable_nan_tx_bf) { + he_cap->bfee_sts_lt_80 = mac_ctx->he_cap_2g.bfee_sts_lt_80; + he_cap->bfee_sts_gt_80 = mac_ctx->he_cap_2g.bfee_sts_gt_80; + he_cap->num_sounding_gt_80 = + mac_ctx->he_cap_2g.num_sounding_gt_80; + pe_debug("he_cap_2g: bfee_sts_gt_80 %d num_sounding_gt_80 %d", + he_cap->bfee_sts_gt_80, he_cap->num_sounding_gt_80); + } + lim_intersect_he_ch_width_2g(mac_ctx, he_cap, vdev_id); + + if (he_cap->ppet_present) + num_ppe_th = lim_set_he_caps_ppet(mac_ctx, he_caps, + CDS_BAND_2GHZ); + + status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_CAP, + CDS_BAND_2GHZ, &he_caps[2], + he_caps[1] + 1 + num_ppe_th); + if (QDF_IS_STATUS_ERROR(status_2g)) + pe_err("Unable send HE Cap IE for 2GHZ band, status: %d", + status_2g); + + if (QDF_IS_STATUS_SUCCESS(status_2g) && + QDF_IS_STATUS_SUCCESS(status_5g)) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +/** + * lim_populate_he_mcs_per_bw() - pouldate HE mcs set per BW (le 80, 160, 80+80) + * @mac_ctx: Global MAC context + * @self_rx: self rx mcs set + * @self_tx: self tx mcs set + * @peer_rx: peer rx mcs set + * @peer_tx: peer tx mcs set + * @nss: nss + * @cfg_rx_param: rx wni param to read + * @cfg_tx_param: tx wni param to read + * + * MCS values are interpreted as in IEEE 11ax-D1.4 spec onwards + * +-----------------------------------------------------+ + * | SS8 | SS7 | SS6 | SS5 | SS4 | SS3 | SS2 | SS1 | + * +-----------------------------------------------------+ + * | 15-14 | 13-12 | 11-10 | 9-8 | 7-6 | 5-4 | 3-2 | 1-0 | + * +-----------------------------------------------------+ + * + * Return: status of operation + */ +QDF_STATUS lim_populate_he_mcs_per_bw(struct mac_context *mac_ctx, + uint16_t *supp_rx_mcs, + uint16_t *supp_tx_mcs, + uint16_t peer_rx, uint16_t peer_tx, + uint8_t nss, uint16_t rx_mcs, + uint16_t tx_mcs) +{ + + pe_debug("peer rates: rx_mcs - 0x%04x tx_mcs - 0x%04x", + peer_rx, peer_tx); + + pe_debug("self rates: rx_mcs - 0x%04x tx_mcs - 0x%04x", + rx_mcs, tx_mcs); + + *supp_tx_mcs = HE_INTERSECT_MCS(rx_mcs, peer_tx); + *supp_rx_mcs = HE_INTERSECT_MCS(tx_mcs, peer_rx); + + if (nss == NSS_1x1_MODE) { + *supp_rx_mcs |= HE_MCS_INV_MSK_4_NSS(1); + *supp_tx_mcs |= HE_MCS_INV_MSK_4_NSS(1); + } + /* if nss is 2, disable higher NSS */ + if (nss == NSS_2x2_MODE) { + *supp_rx_mcs |= (HE_MCS_INV_MSK_4_NSS(1) & + HE_MCS_INV_MSK_4_NSS(2)); + *supp_tx_mcs |= (HE_MCS_INV_MSK_4_NSS(1) & + HE_MCS_INV_MSK_4_NSS(2)); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_populate_he_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEhe_cap *peer_he_caps, + struct pe_session *session_entry, uint8_t nss) +{ + bool support_2x2 = false; + uint32_t self_sta_dot11mode = mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + + if (!IS_DOT11_MODE_HE(self_sta_dot11mode)) + return QDF_STATUS_SUCCESS; + + if ((!peer_he_caps) || (!peer_he_caps->present)) { + pe_debug("peer not he capable or he_caps NULL"); + return QDF_STATUS_SUCCESS; + } + + if (!session_entry) { + pe_err("session is NULL"); + return QDF_STATUS_E_FAILURE; + } + + pe_debug("session chan width: %d", session_entry->ch_width); + pe_debug("PEER: lt 80: rx 0x%04x tx 0x%04x, 160: rx 0x%04x tx 0x%04x, 80+80: rx 0x%04x tx 0x%04x", + peer_he_caps->rx_he_mcs_map_lt_80, + peer_he_caps->tx_he_mcs_map_lt_80, + (*(uint16_t *)peer_he_caps->rx_he_mcs_map_160), + (*(uint16_t *)peer_he_caps->tx_he_mcs_map_160), + (*(uint16_t *)peer_he_caps->rx_he_mcs_map_80_80), + (*(uint16_t *)peer_he_caps->tx_he_mcs_map_80_80)); + + if (nss == NSS_2x2_MODE) { + if (mac_ctx->mlme_cfg->gen.as_enabled && + wlan_reg_is_24ghz_ch_freq(session_entry->curr_op_freq)) { + if (IS_2X2_CHAIN(session_entry->chainMask)) + support_2x2 = true; + else + pe_err("2x2 not enabled %d", + session_entry->chainMask); + } else { + support_2x2 = true; + } + } + + if (wlan_reg_is_24ghz_ch_freq(session_entry->curr_op_freq)) + lim_populate_he_mcs_per_bw(mac_ctx, + &rates->rx_he_mcs_map_lt_80, + &rates->tx_he_mcs_map_lt_80, + peer_he_caps->rx_he_mcs_map_lt_80, + peer_he_caps->tx_he_mcs_map_lt_80, nss, + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80, + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80); + else + lim_populate_he_mcs_per_bw(mac_ctx, + &rates->rx_he_mcs_map_lt_80, + &rates->tx_he_mcs_map_lt_80, + peer_he_caps->rx_he_mcs_map_lt_80, + peer_he_caps->tx_he_mcs_map_lt_80, nss, + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80, + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80); + + if ((session_entry->ch_width == CH_WIDTH_160MHZ || + lim_is_session_chwidth_320mhz(session_entry)) && + peer_he_caps->chan_width_2) { + lim_populate_he_mcs_per_bw( + mac_ctx, &rates->rx_he_mcs_map_160, + &rates->tx_he_mcs_map_160, + *((uint16_t *)peer_he_caps->rx_he_mcs_map_160), + *((uint16_t *)peer_he_caps->tx_he_mcs_map_160), + nss, + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160), + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160)); + } else { + rates->tx_he_mcs_map_160 = HE_MCS_ALL_DISABLED; + rates->rx_he_mcs_map_160 = HE_MCS_ALL_DISABLED; + } + if (session_entry->ch_width == CH_WIDTH_80P80MHZ) { + lim_populate_he_mcs_per_bw( + mac_ctx, &rates->rx_he_mcs_map_80_80, + &rates->tx_he_mcs_map_80_80, + *((uint16_t *)peer_he_caps->rx_he_mcs_map_80_80), + *((uint16_t *)peer_he_caps->tx_he_mcs_map_80_80), nss, + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_80_80), + *((uint16_t *)mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_80_80)); + } else { + rates->tx_he_mcs_map_80_80 = HE_MCS_ALL_DISABLED; + rates->rx_he_mcs_map_80_80 = HE_MCS_ALL_DISABLED; + } + if (!support_2x2) { + /* disable 2 and higher NSS MCS sets */ + rates->rx_he_mcs_map_lt_80 |= HE_MCS_INV_MSK_4_NSS(1); + rates->tx_he_mcs_map_lt_80 |= HE_MCS_INV_MSK_4_NSS(1); + rates->rx_he_mcs_map_160 |= HE_MCS_INV_MSK_4_NSS(1); + rates->tx_he_mcs_map_160 |= HE_MCS_INV_MSK_4_NSS(1); + rates->rx_he_mcs_map_80_80 |= HE_MCS_INV_MSK_4_NSS(1); + rates->tx_he_mcs_map_80_80 |= HE_MCS_INV_MSK_4_NSS(1); + } + + pe_debug("lt 80: rx 0x%x tx 0x%x, 160: rx 0x%x tx 0x%x, 80_80: rx 0x%x tx 0x%x", + rates->rx_he_mcs_map_lt_80, rates->tx_he_mcs_map_lt_80, + rates->rx_he_mcs_map_160, rates->tx_he_mcs_map_160, + rates->rx_he_mcs_map_80_80, rates->tx_he_mcs_map_80_80); + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +void lim_update_sta_mlo_info(struct pe_session *session, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ + if (lim_is_add_sta_params_eht_capable(add_sta_params) && + lim_is_mlo_conn(session, sta_ds)) { + WLAN_ADDR_COPY(add_sta_params->mld_mac_addr, sta_ds->mld_addr); + add_sta_params->is_assoc_peer = lim_is_mlo_recv_assoc(sta_ds); + pe_debug("mld mac " QDF_MAC_ADDR_FMT " assoc peer %d", + QDF_MAC_ADDR_REF(add_sta_params->mld_mac_addr), + add_sta_params->is_assoc_peer); + return; + } + + pe_debug("is not mlo capable"); +} + +void lim_set_mlo_caps(struct mac_context *mac, struct pe_session *session, + uint8_t *ie_start, uint32_t num_bytes) +{ + const uint8_t *ie = NULL; + struct wlan_mlo_ie dot11_cap; + struct wlan_mlo_ie_info *mlo_ie_info; + + populate_dot11f_mlo_caps(mac, session, &dot11_cap); + + ie = wlan_get_ext_ie_ptr_from_ext_id(MLO_IE_OUI_TYPE, + MLO_IE_OUI_SIZE, + ie_start, num_bytes); + + if (ie) { + /* convert from unpacked to packed structure */ + mlo_ie_info = (struct wlan_mlo_ie_info *)&ie[2 + MLO_IE_OUI_SIZE]; + + mlo_ie_info->type = dot11_cap.type; + mlo_ie_info->reserved = dot11_cap.reserved; + mlo_ie_info->link_id_info_present = + dot11_cap.link_id_info_present; + mlo_ie_info->bss_param_change_cnt_present = + dot11_cap.bss_param_change_cnt_present; + mlo_ie_info->medium_sync_delay_info_present = + dot11_cap.medium_sync_delay_info_present; + mlo_ie_info->eml_capab_present = dot11_cap.eml_capab_present; + mlo_ie_info->mld_capab_and_op_present = dot11_cap.mld_capab_and_op_present; + mlo_ie_info->mld_id_present = dot11_cap.mld_id_present; + mlo_ie_info->ext_mld_capab_and_op_present = + dot11_cap.ext_mld_capab_and_op_present; + mlo_ie_info->reserved_1 = dot11_cap.reserved_1; + mlo_ie_info->common_info_length = dot11_cap.common_info_length; + qdf_mem_copy(&mlo_ie_info->mld_mac_addr, + &dot11_cap.mld_mac_addr, + QDF_MAC_ADDR_SIZE); + ie_start[1] += QDF_MAC_ADDR_SIZE; + } +} + +QDF_STATUS lim_send_mlo_caps_ie(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + + QDF_STATUS status_2g, status_5g; + struct wlan_mlo_ie mlo_ie; + + populate_dot11f_mlo_ie(mac_ctx, vdev, &mlo_ie); + status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_MLO_IE, + CDS_BAND_2GHZ, &mlo_ie.data[2], + mlo_ie.num_data - 2); + + status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_MLO_IE, + CDS_BAND_5GHZ, &mlo_ie.data[2], + mlo_ie.num_data - 2); + + if (QDF_IS_STATUS_SUCCESS(status_2g) && + QDF_IS_STATUS_SUCCESS(status_5g)) { + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_SUCCESS; +} + +void lim_strip_mlo_ie(struct mac_context *mac_ctx, + uint8_t *add_ie, uint16_t *add_ielen) +{ + uint8_t *mlo_ie_buff = NULL; + uint16_t mlo_ie_buff_len = 0; + QDF_STATUS qdf_status; + + /* MLO ext ie in addition IE*/ + if (wlan_get_ext_ie_ptr_from_ext_id(MLO_IE_OUI_TYPE, ONE_BYTE, + add_ie, *add_ielen)) { + mlo_ie_buff = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + + if (!mlo_ie_buff) { + pe_err("Failed to allocate MLO IE buff"); + return; + } + + qdf_status = lim_strip_ie(mac_ctx, add_ie, add_ielen, + WLAN_ELEMID_EXTN_ELEM, ONE_BYTE, + MLO_IE_OUI_TYPE, MLO_IE_OUI_SIZE, + mlo_ie_buff, WLAN_MAX_IE_LEN); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("Failed to strip MLO IE"); + qdf_mem_free(mlo_ie_buff); + return; + } + mlo_ie_buff_len = mlo_ie_buff[1] + 2; /* 2 - EID+LEN */ + pe_debug("remove supplicant mlo ie, %d bytes", mlo_ie_buff[1]); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + mlo_ie_buff, mlo_ie_buff_len); + + qdf_mem_free(mlo_ie_buff); + } +} +#endif + +#ifdef WLAN_FEATURE_11BE +static void lim_populate_eht_320_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps) +{ + tDot11fIEeht_cap *fw_5g_eht_cap; + + fw_5g_eht_cap = &mac_ctx->eht_cap_5g; + + rates->bw_320_tx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_320_tx_max_nss_for_mcs_12_and_13, + fw_5g_eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13); + rates->bw_320_rx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_320_rx_max_nss_for_mcs_12_and_13, + fw_5g_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13); + rates->bw_320_tx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_320_tx_max_nss_for_mcs_10_and_11, + fw_5g_eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11); + rates->bw_320_rx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_320_rx_max_nss_for_mcs_10_and_11, + fw_5g_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11); + rates->bw_320_rx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_320_rx_max_nss_for_mcs_0_to_9, + fw_5g_eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9); + rates->bw_320_tx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_320_tx_max_nss_for_mcs_0_to_9, + fw_5g_eht_cap->bw_320_tx_max_nss_for_mcs_0_to_9); + rates->bw_320_rx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_320_rx_max_nss_for_mcs_0_to_9, + fw_5g_eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9); + rates->bw_320_rx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_320_rx_max_nss_for_mcs_0_to_9, + fw_5g_eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9); +} + +static void lim_populate_eht_160_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps) +{ + tDot11fIEeht_cap *fw_5g_eht_cap; + + fw_5g_eht_cap = &mac_ctx->eht_cap_5g; + + rates->bw_160_tx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_160_tx_max_nss_for_mcs_12_and_13, + fw_5g_eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13); + rates->bw_160_rx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_160_rx_max_nss_for_mcs_12_and_13, + fw_5g_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13); + rates->bw_160_tx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_160_tx_max_nss_for_mcs_10_and_11, + fw_5g_eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11); + rates->bw_160_rx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_160_rx_max_nss_for_mcs_10_and_11, + fw_5g_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11); + rates->bw_160_tx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_160_tx_max_nss_for_mcs_0_to_9, + fw_5g_eht_cap->bw_160_tx_max_nss_for_mcs_0_to_9); + rates->bw_160_rx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_160_rx_max_nss_for_mcs_0_to_9, + fw_5g_eht_cap->bw_160_rx_max_nss_for_mcs_0_to_9); +} + +static void lim_populate_eht_le80_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps) +{ + tDot11fIEeht_cap *fw_le80_eht_cap; + + fw_le80_eht_cap = &mac_ctx->eht_cap_5g; + + rates->bw_le_80_tx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_le_80_tx_max_nss_for_mcs_12_and_13, + fw_le80_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13); + rates->bw_le_80_rx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_le_80_rx_max_nss_for_mcs_12_and_13, + fw_le80_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13); + rates->bw_le_80_tx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_le_80_tx_max_nss_for_mcs_10_and_11, + fw_le80_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11); + rates->bw_le_80_rx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_le_80_rx_max_nss_for_mcs_10_and_11, + fw_le80_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11); + rates->bw_le_80_tx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_le_80_tx_max_nss_for_mcs_0_to_9, + fw_le80_eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9); + rates->bw_le_80_rx_max_nss_for_mcs_0_to_9 = + QDF_MIN(peer_eht_caps->bw_le_80_rx_max_nss_for_mcs_0_to_9, + fw_le80_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9); +} + +static void lim_populate_eht_20only_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps) +{ + tDot11fIEeht_cap *fw_2g_eht_cap; + + fw_2g_eht_cap = &mac_ctx->eht_cap_2g; + + rates->bw_20_tx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_20_tx_max_nss_for_mcs_12_and_13, + fw_2g_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13); + rates->bw_20_rx_max_nss_for_mcs_12_and_13 = + QDF_MIN(peer_eht_caps->bw_20_rx_max_nss_for_mcs_12_and_13, + fw_2g_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13); + rates->bw_20_tx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_20_tx_max_nss_for_mcs_10_and_11, + fw_2g_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11); + rates->bw_20_rx_max_nss_for_mcs_10_and_11 = + QDF_MIN(peer_eht_caps->bw_20_rx_max_nss_for_mcs_10_and_11, + fw_2g_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11); + rates->bw_20_tx_max_nss_for_mcs_8_and_9 = + QDF_MIN(peer_eht_caps->bw_20_tx_max_nss_for_mcs_8_and_9, + fw_2g_eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9); + rates->bw_20_rx_max_nss_for_mcs_8_and_9 = + QDF_MIN(peer_eht_caps->bw_20_rx_max_nss_for_mcs_8_and_9, + fw_2g_eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9); + rates->bw_20_tx_max_nss_for_mcs_0_to_7 = + QDF_MIN(peer_eht_caps->bw_20_tx_max_nss_for_mcs_0_to_7, + fw_2g_eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7); + rates->bw_20_rx_max_nss_for_mcs_0_to_7 = + QDF_MIN(peer_eht_caps->bw_20_rx_max_nss_for_mcs_0_to_7, + fw_2g_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7); +} + +QDF_STATUS lim_populate_eht_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps, + struct pe_session *session_entry, + enum phy_ch_width ch_width) +{ + if ((!peer_eht_caps) || (!peer_eht_caps->present)) { + pe_debug("peer not eht capable or eht_caps NULL"); + return QDF_STATUS_SUCCESS; + } + if (!lim_is_session_eht_capable(session_entry)) { + pe_debug("session not eht capable"); + return QDF_STATUS_SUCCESS; + } + + pe_debug("bw is %d", ch_width); + + switch (ch_width) { + case CH_WIDTH_320MHZ: + lim_populate_eht_320_mcs_set(mac_ctx, rates, peer_eht_caps); + fallthrough; + case CH_WIDTH_160MHZ: + lim_populate_eht_160_mcs_set(mac_ctx, rates, peer_eht_caps); + fallthrough; + case CH_WIDTH_80MHZ: + case CH_WIDTH_40MHZ: + lim_populate_eht_le80_mcs_set(mac_ctx, rates, peer_eht_caps); + break; + case CH_WIDTH_20MHZ: + lim_populate_eht_20only_mcs_set(mac_ctx, rates, peer_eht_caps); + break; + default: + break; + } + + return QDF_STATUS_SUCCESS; +} + +void lim_add_self_eht_cap(tpAddStaParams add_sta_params, + struct pe_session *session) +{ + if (!session) + return; + + add_sta_params->eht_capable = true; + + qdf_mem_copy(&add_sta_params->eht_config, &session->eht_config, + sizeof(add_sta_params->eht_config)); + qdf_mem_copy(&add_sta_params->eht_op, &session->eht_op, + sizeof(add_sta_params->eht_op)); +} + +/** + * lim_intersect_eht_caps() - Intersect peer capability and self capability + * @rcvd_eht: pointer to received peer capability + * @peer_eht: pointer to Intersected capability + * @session: A pointer to session entry. + * + * Return: None + */ +static void lim_intersect_eht_caps(tDot11fIEeht_cap *rcvd_eht, + tDot11fIEeht_cap *peer_eht, + struct pe_session *session) +{ + tDot11fIEeht_cap *session_eht = &session->eht_config; + + qdf_mem_copy(peer_eht, rcvd_eht, sizeof(*peer_eht)); + + peer_eht->su_beamformer = session_eht->su_beamformee ? + peer_eht->su_beamformer : 0; + peer_eht->su_beamformee = (session_eht->su_beamformer || + session_eht->mu_bformer_le_80mhz || + session_eht->mu_bformer_160mhz || + session_eht->mu_bformer_320mhz) ? + peer_eht->su_beamformee : 0; + peer_eht->mu_bformer_le_80mhz = session_eht->su_beamformee ? + peer_eht->mu_bformer_le_80mhz : 0; + peer_eht->mu_bformer_160mhz = session_eht->su_beamformee ? + peer_eht->mu_bformer_160mhz : 0; + peer_eht->mu_bformer_320mhz = session_eht->su_beamformee ? + peer_eht->mu_bformer_320mhz : 0; + + if (session_eht->support_320mhz_6ghz && rcvd_eht->support_320mhz_6ghz) + peer_eht->support_320mhz_6ghz = 1; + else + peer_eht->support_320mhz_6ghz = 0; +} + +void lim_update_usr_eht_cap(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct add_ie_params *add_ie = &session->add_ie_params; + tDot11fIEeht_cap *eht_cap = &session->eht_config; + struct wlan_eht_cap_info_network_endian *eht_cap_from_ie; + uint8_t extracted_buff[DOT11F_IE_EHT_CAP_MAX_LEN + 2]; + QDF_STATUS status; + struct wlan_vht_config *vht_cfg = &session->vht_config; + tDot11fIEhe_cap *he_cap = &session->he_config; + struct mlme_legacy_priv *mlme_priv; + + qdf_mem_zero(extracted_buff, sizeof(extracted_buff)); + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_EHT_CAP, ONE_BYTE, + EHT_CAP_OUI_TYPE, (uint8_t)EHT_CAP_OUI_SIZE, + extracted_buff, DOT11F_IE_EHT_CAP_MAX_LEN); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Failed to strip EHT cap IE status: %d", status); + return; + } + + pe_debug("Before update: su_bformer: %d, su_bformee: %d, mu_bformer <= 80MHZ: %d 160MHZ: %d 320MHZ: %d", + eht_cap->su_beamformer, eht_cap->su_beamformee, + eht_cap->mu_bformer_le_80mhz, eht_cap->mu_bformer_160mhz, + eht_cap->mu_bformer_320mhz); + + eht_cap_from_ie = (struct wlan_eht_cap_info_network_endian *) + &extracted_buff[EHT_CAP_OUI_SIZE + 2]; + + eht_cap->su_beamformer = + eht_cap->su_beamformer & eht_cap_from_ie->su_beamformer; + eht_cap->su_beamformee = + eht_cap->su_beamformee & eht_cap_from_ie->su_beamformee; + eht_cap->mu_bformer_le_80mhz = + eht_cap->mu_bformer_le_80mhz & + eht_cap_from_ie->mu_bformer_le_80mhz; + eht_cap->mu_bformer_160mhz = + eht_cap->mu_bformer_160mhz & + eht_cap_from_ie->mu_bformer_160mhz; + eht_cap->mu_bformer_320mhz = + eht_cap->mu_bformer_320mhz & + eht_cap_from_ie->mu_bformer_320mhz; + + pe_debug("After update: su_bformer: %d, su_bformee: %d, mu_bformer <= 80MHZ: %d 160MHZ: %d 320MHZ: %d", + eht_cap->su_beamformer, eht_cap->su_beamformee, + eht_cap->mu_bformer_le_80mhz, eht_cap->mu_bformer_160mhz, + eht_cap->mu_bformer_320mhz); + if (!eht_cap->su_beamformer) { + eht_cap->mu_bformer_le_80mhz = 0; + eht_cap->mu_bformer_160mhz = 0; + eht_cap->mu_bformer_320mhz = 0; + eht_cap->num_sounding_dim_le_80mhz = 0; + eht_cap->num_sounding_dim_160mhz = 0; + eht_cap->num_sounding_dim_320mhz = 0; + he_cap->mu_beamformer = 0; + he_cap->num_sounding_lt_80 = 0; + he_cap->num_sounding_gt_80 = 0; + vht_cfg->su_beam_former = 0; + vht_cfg->mu_beam_former = 0; + vht_cfg->num_soundingdim = 0; + } + if (!eht_cap->su_beamformee) { + eht_cap->bfee_ss_le_80mhz = 0; + eht_cap->bfee_ss_160mhz = 0; + eht_cap->bfee_ss_320mhz = 0; + he_cap->bfee_sts_lt_80 = 0; + he_cap->bfee_sts_gt_80 = 0; + vht_cfg->su_beam_formee = 0; + vht_cfg->mu_beam_formee = 0; + vht_cfg->csnof_beamformer_antSup = 0; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (mlme_priv) { + mlme_priv->eht_config.mu_bformer_le_80mhz = + eht_cap->mu_bformer_le_80mhz; + mlme_priv->eht_config.mu_bformer_160mhz = + eht_cap->mu_bformer_160mhz; + mlme_priv->eht_config.mu_bformer_320mhz = + eht_cap->mu_bformer_320mhz; + mlme_priv->eht_config.su_beamformer = eht_cap->su_beamformer; + mlme_priv->eht_config.su_beamformee = eht_cap->su_beamformee; + mlme_priv->eht_config.bfee_ss_le_80mhz = + eht_cap->bfee_ss_le_80mhz; + mlme_priv->eht_config.bfee_ss_160mhz = eht_cap->bfee_ss_160mhz; + mlme_priv->eht_config.bfee_ss_320mhz = eht_cap->bfee_ss_320mhz; + mlme_priv->eht_config.num_sounding_dim_le_80mhz = + eht_cap->num_sounding_dim_le_80mhz; + mlme_priv->eht_config.num_sounding_dim_160mhz = + eht_cap->num_sounding_dim_160mhz; + mlme_priv->eht_config.num_sounding_dim_320mhz = + eht_cap->num_sounding_dim_320mhz; + } + wma_set_eht_txbf_params(session->vdev_id, eht_cap->su_beamformer, + eht_cap->su_beamformee, + eht_cap->mu_bformer_le_80mhz || + eht_cap->mu_bformer_160mhz || + eht_cap->mu_bformer_320mhz); +} + +static void +lim_revise_req_eht_cap_per_band(struct mlme_legacy_priv *mlme_priv, + struct pe_session *session) +{ + struct mac_context *mac = session->mac_ctx; + + if (wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + mlme_priv->eht_config = mac->eht_cap_2g; + else + mlme_priv->eht_config = mac->eht_cap_5g; +} + +/** + * lim_revise_req_eht_cap_per_mode() - revise eht capabilities per device mode + * @mlme_legacy_priv: vdev mlme legacy priv object + * @session: pointer to session entry. + * + * Return: None + */ +static void lim_revise_req_eht_cap_per_mode(struct mlme_legacy_priv *mlme_priv, + struct pe_session *session) +{ + if (session->opmode == QDF_SAP_MODE || + session->opmode == QDF_P2P_GO_MODE) { + pe_debug("Disable eht cap for SAP/GO"); + mlme_priv->eht_config.tx_1024_4096_qam_lt_242_tone_ru = 0; + mlme_priv->eht_config.rx_1024_4096_qam_lt_242_tone_ru = 0; + } + + mlme_priv->eht_config.non_ofdma_ul_mu_mimo_le_80mhz = 0; + mlme_priv->eht_config.non_ofdma_ul_mu_mimo_160mhz = 0; + mlme_priv->eht_config.non_ofdma_ul_mu_mimo_320mhz = 0; +} + +void lim_copy_bss_eht_cap(struct pe_session *session) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + + lim_revise_req_eht_cap_per_band(mlme_priv, session); + + /* + * As per firmware, SAP/GO doesn’t support some EHT capabilities. So if + * unsupported capabilities are advertised in beacon, probe rsp and + * assoc rsp can cause IOT issues. + * Disable unsupported capabilities per mode. + */ + lim_revise_req_eht_cap_per_mode(mlme_priv, session); + lim_update_eht_caps_mcs(session->mac_ctx, session); + qdf_mem_copy(&session->eht_config, &mlme_priv->eht_config, + sizeof(session->eht_config)); + + if (wlan_epcs_get_config(session->vdev)) + session->eht_config.epcs_pri_access = 1; + else + session->eht_config.epcs_pri_access = 0; +} + +void lim_copy_join_req_eht_cap(struct pe_session *session) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(session->vdev); + if (!mlme_priv) + return; + lim_revise_req_eht_cap_per_band(mlme_priv, session); + lim_revise_req_eht_cap_per_mode(mlme_priv, session); + qdf_mem_copy(&session->eht_config, &mlme_priv->eht_config, + sizeof(session->eht_config)); +} + +void lim_add_eht_cap(struct mac_context *mac_ctx, struct pe_session *pe_session, + tpAddStaParams add_sta_params, tpSirAssocReq assoc_req) +{ + if (!add_sta_params->eht_capable || !assoc_req) + return; + + qdf_mem_copy(&add_sta_params->eht_config, &assoc_req->eht_cap, + sizeof(add_sta_params->eht_config)); +} + +void lim_intersect_ap_eht_caps(struct pe_session *session, + struct bss_params *add_bss, + tSchBeaconStruct *beacon, + tpSirAssocRsp assoc_rsp) +{ + tDot11fIEeht_cap *rcvd_eht; + tDot11fIEeht_cap *peer_eht = &add_bss->staContext.eht_config; + + if (assoc_rsp && assoc_rsp->eht_cap.present) + rcvd_eht = &assoc_rsp->eht_cap; + else + rcvd_eht = &beacon->eht_cap; + + lim_intersect_eht_caps(rcvd_eht, peer_eht, session); + add_bss->staContext.eht_capable = true; +} + +void lim_add_bss_eht_cap(struct bss_params *add_bss, tpSirAssocRsp assoc_rsp) +{ + tDot11fIEeht_cap *eht_cap; + tDot11fIEeht_op *eht_op; + + eht_cap = &assoc_rsp->eht_cap; + eht_op = &assoc_rsp->eht_op; + add_bss->eht_capable = eht_cap->present; + if (eht_cap) + qdf_mem_copy(&add_bss->staContext.eht_config, + eht_cap, sizeof(*eht_cap)); + if (eht_op) + qdf_mem_copy(&add_bss->staContext.eht_op, + eht_op, sizeof(*eht_op)); +} + +void lim_intersect_sta_eht_caps(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + struct pe_session *session, + tpDphHashNode sta_ds) +{ + tDot11fIEeht_cap *rcvd_eht = &assoc_req->eht_cap; + tDot11fIEeht_cap *peer_eht = &sta_ds->eht_config; + + if (!sta_ds->mlmStaContext.eht_capable) + return; + + /* If EHT is not supported, do not fill sta_ds and return */ + if (!IS_DOT11_MODE_EHT(session->dot11mode)) + return; + + lim_intersect_eht_caps(rcvd_eht, peer_eht, session); +} + +void lim_update_session_eht_capable(struct mac_context *mac, + struct pe_session *session) +{ + session->eht_capable = true; +} + +void lim_add_bss_eht_cfg(struct bss_params *add_bss, struct pe_session *session) +{ +} + +#define EHT_OP_LEN (DOT11F_IE_EHT_OP_MAX_LEN + EHT_OP_OUI_SIZE * 2 + ONE_BYTE) +void lim_decide_eht_op(struct mac_context *mac_ctx, uint32_t *mlme_eht_ops, + struct pe_session *session) +{ + struct add_ie_params *add_ie = &session->add_ie_params; + uint8_t extracted_buff[EHT_OP_LEN + 2]; + QDF_STATUS status; + uint16_t ori_puncture_bitmap; + uint8_t len; + + pe_debug("beacon ie:"); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + add_ie->probeRespBCNData_buff, + add_ie->probeRespBCNDataLen); + + qdf_mem_zero(extracted_buff, sizeof(extracted_buff)); + status = lim_strip_ie(mac_ctx, add_ie->probeRespBCNData_buff, + &add_ie->probeRespBCNDataLen, + DOT11F_EID_EHT_OP, ONE_BYTE, + EHT_OP_OUI_TYPE, (uint8_t)EHT_OP_OUI_SIZE, + extracted_buff, EHT_OP_LEN); + if (QDF_STATUS_SUCCESS != status) { + pe_debug("Failed to strip EHT OP IE status: %d", status); + return; + } + + pe_debug("eht op:"); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + extracted_buff, EHT_OP_LEN); + + session->eht_op.present = 1; + + len = qdf_min((uint8_t)(sizeof(tDot11fIEeht_op) - 1), + (uint8_t)(DOT11F_IE_EHT_OP_MAX_LEN)); + qdf_mem_copy((uint8_t *)(&session->eht_op) + 1, + &extracted_buff[EHT_OP_OUI_SIZE * 2 + ONE_BYTE], + len); + + ori_puncture_bitmap = + *(uint16_t *)session->eht_op.disabled_sub_chan_bitmap; + pe_debug("puncture bitmap: %d, ch width: %d, ccfs0: %d, ccfs1: %d", + ori_puncture_bitmap, session->eht_op.channel_width, + session->eht_op.ccfs0, session->eht_op.ccfs1); + + wma_update_vdev_eht_ops(mlme_eht_ops, &session->eht_op); +} + +void lim_update_stads_eht_capable(tpDphHashNode sta_ds, tpSirAssocReq assoc_req) +{ + sta_ds->mlmStaContext.eht_capable = assoc_req->eht_cap.present; +} + +#ifdef FEATURE_WLAN_TDLS +#ifdef WLAN_FEATURE_11BE +void lim_update_tdls_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + if (sta_ds->staType == STA_ENTRY_TDLS_PEER) { + if (!sta_ds->eht_config.present) + add_sta_params->eht_capable = 0; + } + + pe_debug("tdls eht_capable: %d", add_sta_params->eht_capable); +} +#endif +#endif + +void lim_update_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ + if (LIM_IS_AP_ROLE(session_entry)) + add_sta_params->eht_capable = + sta_ds->mlmStaContext.eht_capable && + session_entry->eht_capable; + else + add_sta_params->eht_capable = session_entry->eht_capable; + + pe_debug("eht_capable: %d", add_sta_params->eht_capable); +} + +void lim_update_session_eht_capable_chan_switch(struct mac_context *mac, + struct pe_session *session, + uint32_t new_chan_freq) +{ + session->eht_capable = true; + session->he_capable = true; + /* TODO: Update */ + if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq) && + !wlan_reg_is_6ghz_chan_freq(new_chan_freq)) { + session->htCapability = 1; + session->vhtCapability = 1; + session->he_6ghz_band = 0; + } else if (!wlan_reg_is_6ghz_chan_freq(session->curr_op_freq) && + wlan_reg_is_6ghz_chan_freq(new_chan_freq)) { + session->htCapability = 0; + session->vhtCapability = 0; + session->he_6ghz_band = 1; + } + + /* + * If new channel is 2.4gh set VHT as per the b24ghz_band INI + * if new channel is 5Ghz set the vht, this will happen if we move from + * 2.4Ghz to 5Ghz. + */ + if (wlan_reg_is_24ghz_ch_freq(new_chan_freq) && + !mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) + session->vhtCapability = 0; + else if (wlan_reg_is_5ghz_ch_freq(new_chan_freq)) + session->vhtCapability = 1; + + pe_debug("eht_capable:%d he_capable:%d ht:%d vht:%d 6ghz_band:%d new freq:%d vht in 2.4gh:%d", + session->eht_capable, session->he_capable, + session->htCapability, session->vhtCapability, + session->he_6ghz_band, new_chan_freq, + mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band); +} + +void lim_update_bss_eht_capable(struct mac_context *mac, + struct bss_params *add_bss) +{ + add_bss->eht_capable = true; + pe_debug("eht_capable: %d", add_bss->eht_capable); +} + +void lim_log_eht_cap(struct mac_context *mac, tDot11fIEeht_cap *eht_cap) +{ + if (!eht_cap->present) + return; + + pe_nofl_debug("EHT Capabilities:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + eht_cap, sizeof(tDot11fIEeht_cap)); +} + +void lim_log_eht_op(struct mac_context *mac, tDot11fIEeht_op *eht_ops, + struct pe_session *session) +{ + if (!eht_ops->present) + return; + + pe_nofl_debug("EHT operation element:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + eht_ops, sizeof(tDot11fIEeht_op)); +} + +static void +lim_revise_eht_caps_per_band(struct mac_context *mac, enum cds_band_type band, + tDot11fIEeht_cap *eht_cap) +{ + uint32_t country_max_allowed_bw; + + if (band == CDS_BAND_2GHZ) + return; + + country_max_allowed_bw = wlan_reg_get_country_max_allowed_bw(mac->pdev); + if (!country_max_allowed_bw) { + pe_debug("Failed to get country_max_allowed_bw"); + return; + } else { + pe_debug("max_allowed_bw %d", country_max_allowed_bw); + } + + if (country_max_allowed_bw < BW_320_MHZ) + eht_cap->support_320mhz_6ghz = 0; + else if (country_max_allowed_bw == BW_320_MHZ) + eht_cap->support_320mhz_6ghz = 1; +} + +void lim_set_eht_caps(struct mac_context *mac, + uint8_t *ie_start, uint32_t num_bytes, uint8_t band, + uint8_t vdev_id) +{ + const uint8_t *ie = NULL; + uint8_t offset = 0; + uint8_t offset_1 = 0; + tDot11fIEeht_cap dot11_cap; + tDot11fIEhe_cap dot11_he_cap; + struct wlan_eht_cap_info *eht_cap; + struct wlan_eht_cap_info eht_mcs_cap; + bool is_band_2g = false; + uint32_t cbm_24ghz; + struct wlan_objmgr_vdev *vdev; + + if (band == CDS_BAND_2GHZ) + is_band_2g = true; + + populate_dot11f_eht_caps_by_band(mac, is_band_2g, &dot11_cap, NULL); + lim_revise_eht_caps_per_band(mac, band, &dot11_cap); + populate_dot11f_he_caps_by_band(mac, is_band_2g, &dot11_he_cap, + NULL); + lim_log_eht_cap(mac, &dot11_cap); + + if (is_band_2g) { + cbm_24ghz = lim_get_sta_cb_mode_for_24ghz(mac, vdev_id); + if (!cbm_24ghz) { + /* B0: 40Mhz channel width in the 2.4GHz band */ + dot11_he_cap.chan_width_0 = 0; + dot11_he_cap.he_ppdu_20_in_40Mhz_2G = 0; + } + } + + ie = wlan_get_ext_ie_ptr_from_ext_id(EHT_CAP_OUI_TYPE, + EHT_CAP_OUI_SIZE, + ie_start, num_bytes); + + if (ie) { + /* convert from unpacked to packed structure */ + eht_cap = (struct wlan_eht_cap_info *)&ie[2 + EHT_CAP_OUI_SIZE]; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_MLME_CM_ID); + if (wlan_epcs_get_config(vdev)) + eht_cap->epcs_pri_access = 1; + else + eht_cap->epcs_pri_access = 0; + + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + eht_cap->eht_om_ctl = dot11_cap.eht_om_ctl; + eht_cap->triggered_txop_sharing_mode1 = + dot11_cap.triggered_txop_sharing_mode1; + eht_cap->triggered_txop_sharing_mode2 = + dot11_cap.triggered_txop_sharing_mode2; + eht_cap->restricted_twt = + dot11_cap.restricted_twt; + eht_cap->scs_traffic_desc = + dot11_cap.scs_traffic_desc; + eht_cap->max_mpdu_len = + dot11_cap.max_mpdu_len; + eht_cap->max_a_mpdu_len_exponent_ext = + dot11_cap.max_a_mpdu_len_exponent_ext; + eht_cap->eht_trs_support = dot11_cap.eht_trs_support; + eht_cap->txop_return_support_txop_share_m2 = + dot11_cap.txop_return_support_txop_share_m2; + eht_cap->two_bqrs_support = + dot11_cap.two_bqrs_support; + eht_cap->eht_link_adaptation_support = + dot11_cap.eht_link_adaptation_support; + eht_cap->support_320mhz_6ghz = dot11_cap.support_320mhz_6ghz; + eht_cap->ru_242tone_wt_20mhz = dot11_cap.ru_242tone_wt_20mhz; + eht_cap->ndp_4x_eht_ltf_3dot2_us_gi = + dot11_cap.ndp_4x_eht_ltf_3dot2_us_gi; + eht_cap->partial_bw_mu_mimo = dot11_cap.partial_bw_mu_mimo; + eht_cap->su_beamformer = dot11_cap.su_beamformer; + eht_cap->su_beamformee = dot11_cap.su_beamformee; + eht_cap->bfee_ss_le_80mhz = dot11_cap.bfee_ss_le_80mhz; + eht_cap->bfee_ss_160mhz = dot11_cap.bfee_ss_160mhz; + eht_cap->bfee_ss_320mhz = dot11_cap.bfee_ss_320mhz; + eht_cap->num_sounding_dim_le_80mhz = + dot11_cap.num_sounding_dim_le_80mhz; + eht_cap->num_sounding_dim_160mhz = + dot11_cap.num_sounding_dim_160mhz; + eht_cap->num_sounding_dim_320mhz = + dot11_cap.num_sounding_dim_320mhz; + eht_cap->ng_16_su_feedback = dot11_cap.ng_16_su_feedback; + eht_cap->ng_16_mu_feedback = dot11_cap.ng_16_mu_feedback; + eht_cap->cb_sz_4_2_su_feedback = + dot11_cap.cb_sz_4_2_su_feedback; + eht_cap->cb_sz_7_5_su_feedback = + dot11_cap.cb_sz_7_5_su_feedback; + eht_cap->trig_su_bforming_feedback = + dot11_cap.trig_su_bforming_feedback; + eht_cap->trig_mu_bforming_partial_bw_feedback = + dot11_cap.trig_mu_bforming_partial_bw_feedback; + eht_cap->triggered_cqi_feedback = + dot11_cap.triggered_cqi_feedback; + eht_cap->partial_bw_dl_mu_mimo = + dot11_cap.partial_bw_dl_mu_mimo; + eht_cap->psr_based_sr = dot11_cap.psr_based_sr; + eht_cap->power_boost_factor = dot11_cap.power_boost_factor; + eht_cap->eht_mu_ppdu_4x_ltf_0_8_us_gi = + dot11_cap.eht_mu_ppdu_4x_ltf_0_8_us_gi; + eht_cap->max_nc = dot11_cap.max_nc; + eht_cap->non_trig_cqi_feedback = + dot11_cap.non_trig_cqi_feedback; + eht_cap->tx_1024_4096_qam_lt_242_tone_ru = + dot11_cap.tx_1024_4096_qam_lt_242_tone_ru; + eht_cap->rx_1024_4096_qam_lt_242_tone_ru = + dot11_cap.rx_1024_4096_qam_lt_242_tone_ru; + eht_cap->ppet_present = dot11_cap.ppet_present; + eht_cap->common_nominal_pkt_padding = + dot11_cap.common_nominal_pkt_padding; + eht_cap->max_num_eht_ltf = dot11_cap.max_num_eht_ltf; + eht_cap->mcs_15 = dot11_cap.mcs_15; + eht_cap->eht_dup_6ghz = dot11_cap.eht_dup_6ghz; + eht_cap->op_sta_rx_ndp_wider_bw_20mhz = + dot11_cap.op_sta_rx_ndp_wider_bw_20mhz; + eht_cap->non_ofdma_ul_mu_mimo_le_80mhz = + dot11_cap.non_ofdma_ul_mu_mimo_le_80mhz; + eht_cap->non_ofdma_ul_mu_mimo_160mhz = + dot11_cap.non_ofdma_ul_mu_mimo_160mhz; + eht_cap->non_ofdma_ul_mu_mimo_320mhz = + dot11_cap.non_ofdma_ul_mu_mimo_320mhz; + eht_cap->mu_bformer_le_80mhz = + dot11_cap.mu_bformer_le_80mhz; + eht_cap->mu_bformer_160mhz = dot11_cap.mu_bformer_160mhz; + eht_cap->mu_bformer_320mhz = dot11_cap.mu_bformer_320mhz; + eht_cap->tb_sounding_feedback_rl = + dot11_cap.tb_sounding_feedback_rl; + eht_cap->rx_1k_qam_in_wider_bw_dl_ofdma = + dot11_cap.rx_1k_qam_in_wider_bw_dl_ofdma; + eht_cap->rx_4k_qam_in_wider_bw_dl_ofdma = + dot11_cap.rx_4k_qam_in_wider_bw_dl_ofdma; + eht_cap->limited_cap_support_20mhz = + dot11_cap.limited_cap_support_20mhz; + eht_cap->triggered_mu_bf_full_bw_fb_and_dl_mumimo = + dot11_cap.triggered_mu_bf_full_bw_fb_and_dl_mumimo; + eht_cap->mru_support_20mhz = + dot11_cap.mru_support_20mhz; + + if ((is_band_2g && !dot11_he_cap.chan_width_0) || + (!is_band_2g && !dot11_he_cap.chan_width_1 && + !dot11_he_cap.chan_width_2 && + !dot11_he_cap.chan_width_3)) { + eht_mcs_cap.bw_20_rx_max_nss_for_mcs_0_to_7 = + dot11_cap.bw_20_rx_max_nss_for_mcs_0_to_7; + eht_mcs_cap.bw_20_tx_max_nss_for_mcs_0_to_7 = + dot11_cap.bw_20_tx_max_nss_for_mcs_0_to_7; + eht_mcs_cap.bw_20_rx_max_nss_for_mcs_8_and_9 = + dot11_cap.bw_20_rx_max_nss_for_mcs_8_and_9; + eht_mcs_cap.bw_20_tx_max_nss_for_mcs_8_and_9 = + dot11_cap.bw_20_tx_max_nss_for_mcs_8_and_9; + eht_mcs_cap.bw_20_rx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_20_rx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_20_tx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_20_tx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_20_rx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_20_rx_max_nss_for_mcs_12_and_13; + eht_mcs_cap.bw_20_tx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_20_tx_max_nss_for_mcs_12_and_13; + offset = ie_start[1] + 3; + qdf_mem_copy(&ie_start[offset], + (((uint8_t *)&eht_mcs_cap) + + EHT_CAP_FIXED_FIELDS), + EHT_CAP_20M_MCS_MAP_LEN); + ie_start[1] += EHT_CAP_20M_MCS_MAP_LEN; + + return; + } + + if ((is_band_2g && dot11_he_cap.chan_width_0) || + (!is_band_2g && dot11_he_cap.chan_width_1)) { + eht_mcs_cap.bw_le_80_rx_max_nss_for_mcs_0_to_9 = + dot11_cap.bw_le_80_rx_max_nss_for_mcs_0_to_9; + eht_mcs_cap.bw_le_80_tx_max_nss_for_mcs_0_to_9 = + dot11_cap.bw_le_80_tx_max_nss_for_mcs_0_to_9; + eht_mcs_cap.bw_le_80_rx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_le_80_rx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_le_80_tx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_le_80_tx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_le_80_rx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_le_80_rx_max_nss_for_mcs_12_and_13; + eht_mcs_cap.bw_le_80_tx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_le_80_tx_max_nss_for_mcs_12_and_13; + offset = ie_start[1] + 3; + offset_1 = EHT_CAP_FIXED_FIELDS + + EHT_CAP_20M_MCS_MAP_LEN; + qdf_mem_copy(&ie_start[offset], + (((uint8_t *)&eht_mcs_cap) + offset_1), + EHT_CAP_80M_MCS_MAP_LEN); + ie_start[1] += EHT_CAP_80M_MCS_MAP_LEN; + } + + if (!is_band_2g && dot11_he_cap.chan_width_2) { + eht_mcs_cap.bw_160_rx_max_nss_for_mcs_0_to_9 = + dot11_cap.bw_160_rx_max_nss_for_mcs_0_to_9; + eht_mcs_cap.bw_160_tx_max_nss_for_mcs_0_to_9 = + dot11_cap.bw_160_tx_max_nss_for_mcs_0_to_9; + eht_mcs_cap.bw_160_rx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_160_rx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_160_tx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_160_tx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_160_rx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_160_rx_max_nss_for_mcs_12_and_13; + eht_mcs_cap.bw_160_tx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_160_tx_max_nss_for_mcs_12_and_13; + offset = ie_start[1] + 3; + offset_1 = EHT_CAP_FIXED_FIELDS + + EHT_CAP_20M_MCS_MAP_LEN + + EHT_CAP_80M_MCS_MAP_LEN; + qdf_mem_copy(&ie_start[offset], + (((uint8_t *)&eht_mcs_cap) + offset_1), + EHT_CAP_160M_MCS_MAP_LEN); + ie_start[1] += EHT_CAP_160M_MCS_MAP_LEN; + + } + + if (!is_band_2g && eht_cap->support_320mhz_6ghz) { + eht_mcs_cap.bw_320_rx_max_nss_for_mcs_0_to_9 = + dot11_cap.bw_320_rx_max_nss_for_mcs_0_to_9; + eht_mcs_cap.bw_320_tx_max_nss_for_mcs_0_to_9 = + dot11_cap.bw_320_tx_max_nss_for_mcs_0_to_9; + eht_mcs_cap.bw_320_rx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_320_rx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_320_tx_max_nss_for_mcs_10_and_11 = + dot11_cap.bw_320_tx_max_nss_for_mcs_10_and_11; + eht_mcs_cap.bw_320_rx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_320_rx_max_nss_for_mcs_12_and_13; + eht_mcs_cap.bw_320_tx_max_nss_for_mcs_12_and_13 = + dot11_cap.bw_320_tx_max_nss_for_mcs_12_and_13; + offset = ie_start[1] + 3; + offset_1 = EHT_CAP_FIXED_FIELDS + + EHT_CAP_20M_MCS_MAP_LEN + + EHT_CAP_80M_MCS_MAP_LEN + + EHT_CAP_160M_MCS_MAP_LEN; + qdf_mem_copy(&ie_start[offset], + (((uint8_t *)&eht_mcs_cap) + offset_1), + EHT_CAP_320M_MCS_MAP_LEN); + ie_start[1] += EHT_CAP_320M_MCS_MAP_LEN; + } + } +} + +QDF_STATUS lim_send_eht_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + uint8_t eht_cap_total_len = DOT11F_IE_EHT_CAP_MIN_LEN + + EHT_CAP_OUI_LEN + EHT_CAP_20M_MCS_MAP_LEN + + EHT_CAP_80M_MCS_MAP_LEN + + EHT_CAP_160M_MCS_MAP_LEN + + EHT_CAP_320M_MCS_MAP_LEN; + QDF_STATUS status_2g, status_5g; + uint8_t eht_caps_2g[DOT11F_IE_EHT_CAP_MIN_LEN + + EHT_CAP_OUI_LEN + EHT_CAP_20M_MCS_MAP_LEN + + EHT_CAP_80M_MCS_MAP_LEN + + EHT_CAP_160M_MCS_MAP_LEN + + EHT_CAP_320M_MCS_MAP_LEN] = {0}; + + uint8_t eht_caps_5g[DOT11F_IE_EHT_CAP_MIN_LEN + + EHT_CAP_OUI_LEN + EHT_CAP_20M_MCS_MAP_LEN + + EHT_CAP_80M_MCS_MAP_LEN + + EHT_CAP_160M_MCS_MAP_LEN + + EHT_CAP_320M_MCS_MAP_LEN] = {0}; + + eht_caps_2g[0] = DOT11F_EID_EHT_CAP; + eht_caps_2g[1] = EHT_CAP_FIXED_FIELDS; + + qdf_mem_copy(&eht_caps_2g[2], EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE); + + lim_set_eht_caps(mac_ctx, eht_caps_2g, eht_cap_total_len, + CDS_BAND_2GHZ, vdev_id); + status_2g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_EHT_CAP, + CDS_BAND_2GHZ, &eht_caps_2g[2], + eht_caps_2g[1] + 1); + + eht_caps_5g[0] = DOT11F_EID_EHT_CAP; + eht_caps_5g[1] = EHT_CAP_FIXED_FIELDS; + + qdf_mem_copy(&eht_caps_5g[2], EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE); + + lim_set_eht_caps(mac_ctx, eht_caps_5g, eht_cap_total_len, + CDS_BAND_5GHZ, vdev_id); + status_5g = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_EHT_CAP, + CDS_BAND_5GHZ, &eht_caps_5g[2], + eht_caps_5g[1] + 1); + + if (QDF_IS_STATUS_SUCCESS(status_2g) && + QDF_IS_STATUS_SUCCESS(status_5g)) { + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_SUCCESS; +} + +void lim_update_stads_eht_caps(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, + tSchBeaconStruct *beacon) +{ + /* If EHT is not supported, do not fill sta_ds and return */ + if (!IS_DOT11_MODE_EHT(session_entry->dot11mode)) + return; + + if (!assoc_rsp->eht_cap.present && beacon && beacon->eht_cap.present) { + /* Use beacon EHT caps if assoc resp doesn't have he caps */ + pe_debug("eht_caps missing in assoc rsp"); + qdf_mem_copy(&assoc_rsp->eht_cap, &beacon->eht_cap, + sizeof(tDot11fIEeht_cap)); + } + + /* assoc resp and beacon doesn't have eht caps */ + if (!assoc_rsp->eht_cap.present) + return; + + sta_ds->mlmStaContext.eht_capable = assoc_rsp->eht_cap.present; + + qdf_mem_copy(&sta_ds->eht_config, &assoc_rsp->eht_cap, + sizeof(tDot11fIEeht_cap)); +} + +void lim_update_stads_eht_bw_320mhz(struct pe_session *session, + tpDphHashNode sta_ds) +{ + tDot11fIEeht_cap *peer_eht = &sta_ds->eht_config; + + if (!IS_DOT11_MODE_EHT(session->dot11mode) || !peer_eht->present) + return; + + /* EHT only defines 320 MHz. If session is not in 320 MHz, BW will be + * set in HE mode. + * + * Set ch_width to 320 MHz only when session is in 320 MHz and peer eht + * caps support 320 MHz after eht caps intersection. + */ + if (session->ch_width == CH_WIDTH_320MHZ && + peer_eht->support_320mhz_6ghz) { + sta_ds->ch_width = CH_WIDTH_320MHZ; + pe_debug("ch_width %d", sta_ds->ch_width); + } +} + +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +void lim_extract_per_link_id(struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ + uint8_t vdev_id = wlan_vdev_get_id(session->vdev); + + if (!wlan_vdev_mlme_is_mlo_link_vdev(session->vdev) && + assoc_rsp->mlo_ie.mlo_ie.link_id_info_present) + add_bss->staContext.link_id = + assoc_rsp->mlo_ie.mlo_ie.link_id; + else + add_bss->staContext.link_id = + wlan_vdev_get_link_id(session->vdev); + + pe_debug("vdev: %d, link id: %d", vdev_id, add_bss->staContext.link_id); +} + +void lim_extract_ml_info(struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ + uint8_t i, link_id, partner_idx = 0; + struct mlo_partner_info *ml_partner_info; + struct mlo_link_info *link_info; + struct peer_ml_info *ml_link; + + if (!wlan_vdev_mlme_is_mlo_vdev(session->vdev)) + return; + + ml_link = &add_bss->staContext.ml_info; + ml_partner_info = &session->ml_partner_info; + + ml_link->vdev_id = wlan_vdev_get_id(session->vdev); + ml_link->link_id = wlan_vdev_get_link_id(session->vdev); + + ml_link->rec_max_simultaneous_links = + session->vdev->mlo_dev_ctx->mlo_max_recom_simult_links; + + link_info = mlo_mgr_get_ap_link_by_link_id(session->vdev->mlo_dev_ctx, + ml_link->link_id); + if (!link_info) + return; + + qdf_mem_copy(&ml_link->channel_info, link_info->link_chan_info, + sizeof(ml_link->channel_info)); + qdf_mem_copy(&ml_link->link_addr, &link_info->ap_link_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&ml_link->self_mac_addr, &link_info->link_addr, + QDF_MAC_ADDR_SIZE); + + if (wlan_vdev_mlme_is_mlo_link_vdev(session->vdev)) + return; + + for (i = 0; i < ml_partner_info->num_partner_links; i++) { + link_id = ml_partner_info->partner_link_info[i].link_id; + link_info = mlo_mgr_get_ap_link_by_link_id( + session->vdev->mlo_dev_ctx, + link_id); + if (!link_info) + continue; + + ml_link->partner_info[partner_idx].vdev_id = link_info->vdev_id; + ml_link->partner_info[partner_idx].link_id = link_info->link_id; + + qdf_mem_copy(&ml_link->partner_info[partner_idx].channel_info, + link_info->link_chan_info, + sizeof(ml_link->partner_info[partner_idx].channel_info)); + qdf_mem_copy(&ml_link->partner_info[partner_idx].link_addr, + &link_info->ap_link_addr, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&ml_link->partner_info[partner_idx].self_mac_addr, + &link_info->link_addr, QDF_MAC_ADDR_SIZE); + + partner_idx++; + } + + ml_link->num_links = partner_idx; + pe_debug("vdev:%d Num of partner links: %d", session->vdev_id, + ml_link->num_links); +} + +void lim_intersect_ap_emlsr_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ + struct wlan_mlo_sta *sta_ctx; + struct wlan_objmgr_vdev *vdev = session->vdev; + struct emlsr_capability *ml_emlcap; + + wlan_objmgr_vdev_get_ref(vdev, WLAN_MLME_NB_ID); + if (!vdev) { + pe_err("vdev is null"); + return; + } + + if (!vdev->mlo_dev_ctx) { + pe_err("mlo dev ctx is null"); + goto end; + } + + sta_ctx = vdev->mlo_dev_ctx->sta_ctx; + if (!sta_ctx) { + pe_err("sta ctx is null"); + goto end; + } + + ml_emlcap = &sta_ctx->emlsr_cap; + + if (!wlan_vdev_mlme_cap_get(vdev, WLAN_VDEV_C_EMLSR_CAP)) { + add_bss->staContext.emlsr_support = false; + goto end; + } + + if (wlan_vdev_mlme_is_mlo_link_vdev(session->vdev)) { + add_bss->staContext.emlsr_support = ml_emlcap->emlsr_supp; + add_bss->staContext.emlsr_trans_timeout = + ml_emlcap->trans_timeout; + } else { + add_bss->staContext.emlsr_support = true; + add_bss->staContext.emlsr_trans_timeout = + assoc_rsp->mlo_ie.mlo_ie.eml_capabilities_info.transition_timeout; + + ml_emlcap->emlsr_supp = add_bss->staContext.emlsr_support; + ml_emlcap->trans_timeout = + add_bss->staContext.emlsr_trans_timeout; + } + +end: + pe_debug("emlsr support: %d, transition timeout:%d", + add_bss->staContext.emlsr_support, + add_bss->staContext.emlsr_trans_timeout); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); +} + +#define MAX_MSD_OFDM_ED_THRESHOLD 10 + +void lim_extract_msd_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ + struct wlan_objmgr_peer *peer; + struct wlan_mlo_peer_context *mlo_peer_ctx; + + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, add_bss->bssId, + WLAN_LEGACY_MAC_ID); + if (!peer) { + pe_err("peer is null"); + return; + } + + mlo_peer_ctx = peer->mlo_peer_ctx; + if (!mlo_peer_ctx) { + pe_err("mlo peer ctx is null"); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return; + } + + if (wlan_vdev_mlme_is_mlo_link_vdev(session->vdev)) { + add_bss->staContext.msd_caps_present = + mlo_peer_ctx->msd_cap_present; + add_bss->staContext.msd_caps.med_sync_duration = + mlo_peer_ctx->mlpeer_msdcap.medium_sync_duration; + add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh = + mlo_peer_ctx->mlpeer_msdcap.medium_sync_ofdm_ed_thresh; + add_bss->staContext.msd_caps.med_sync_max_txop_num = + mlo_peer_ctx->mlpeer_msdcap.medium_sync_max_txop_num; + } else { + add_bss->staContext.msd_caps_present = + assoc_rsp->mlo_ie.mlo_ie.medium_sync_delay_info_present; + if (add_bss->staContext.msd_caps_present) { + add_bss->staContext.msd_caps.med_sync_duration = + assoc_rsp->mlo_ie.mlo_ie.medium_sync_delay_info.medium_sync_duration; + add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh = + assoc_rsp->mlo_ie.mlo_ie.medium_sync_delay_info.medium_sync_ofdm_ed_thresh; + if (add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh > + MAX_MSD_OFDM_ED_THRESHOLD) + add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh = 0; + add_bss->staContext.msd_caps.med_sync_max_txop_num = + assoc_rsp->mlo_ie.mlo_ie.medium_sync_delay_info.medium_sync_max_txop_num; + } else { + /** + * Fill MSD params with default values if MSD caps are + * absent. + * MSD duration = 5484usec / 32 = 171. + * OFDM ED threshold = 0. FW adds -72 to Host value. + * Maximum number of TXOPs = AP value (default = 0). + */ + add_bss->staContext.msd_caps.med_sync_duration = 171; + add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh = 0; + add_bss->staContext.msd_caps.med_sync_max_txop_num = 0; + } + mlo_peer_ctx->msd_cap_present = + add_bss->staContext.msd_caps_present; + mlo_peer_ctx->mlpeer_msdcap.medium_sync_duration = + add_bss->staContext.msd_caps.med_sync_duration; + mlo_peer_ctx->mlpeer_msdcap.medium_sync_ofdm_ed_thresh = + add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh; + mlo_peer_ctx->mlpeer_msdcap.medium_sync_max_txop_num = + add_bss->staContext.msd_caps.med_sync_max_txop_num; + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + pe_debug("MSD caps: %d, Duration: %d, Threshold:%d, TXOP num: %d", + add_bss->staContext.msd_caps_present, + add_bss->staContext.msd_caps.med_sync_duration, + add_bss->staContext.msd_caps.med_sync_ofdm_ed_thresh, + add_bss->staContext.msd_caps.med_sync_max_txop_num); +} +#endif + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +QDF_STATUS lim_send_he_6g_band_caps_ie(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + uint8_t he_6g_band_caps_ie[DOT11F_IE_HE_6GHZ_BAND_CAP_MIN_LEN + 3]; + tDot11fIEhe_6ghz_band_cap he_6g_band_cap; + QDF_STATUS status; + uint32_t size = 0; + uint32_t result; + + qdf_mem_zero(&he_6g_band_cap, sizeof(he_6g_band_cap)); + populate_dot11f_he_6ghz_cap(mac_ctx, NULL, &he_6g_band_cap); + if (!he_6g_band_cap.present) { + pe_debug("no HE 6g band cap for vdev %d", vdev_id); + return QDF_STATUS_SUCCESS; + } + + qdf_mem_zero(he_6g_band_caps_ie, sizeof(he_6g_band_caps_ie)); + result = dot11f_pack_ie_he_6ghz_band_cap(mac_ctx, &he_6g_band_cap, + he_6g_band_caps_ie, + sizeof(he_6g_band_caps_ie), + &size); + if (result != DOT11F_PARSE_SUCCESS) { + pe_err("pack error for HE 6g band cap for vdev %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + pe_debug("send HE 6ghz band cap: 0x%01x 0x%01x for vdev %d", + he_6g_band_caps_ie[3], he_6g_band_caps_ie[4], + vdev_id); + status = lim_send_ie(mac_ctx, vdev_id, DOT11F_EID_HE_6GHZ_BAND_CAP, + CDS_BAND_5GHZ, &he_6g_band_caps_ie[2], + DOT11F_IE_HE_6GHZ_BAND_CAP_MIN_LEN + 1); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Unable send HE 6g band Cap IE for 5GHZ band, status: %d", + status); + + return status; +} +#endif + +int +lim_assoc_rej_get_remaining_delta(struct sir_rssi_disallow_lst *node) +{ + qdf_time_t cur_time; + uint32_t time_diff; + + cur_time = qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + time_diff = cur_time - node->time_during_rejection; + + return node->retry_delay - time_diff; +} + +QDF_STATUS +lim_rem_denylist_entry_with_lowest_delta(qdf_list_t *list) +{ + struct sir_rssi_disallow_lst *oldest_node = NULL; + struct sir_rssi_disallow_lst *cur_node; + qdf_list_node_t *cur_list = NULL; + qdf_list_node_t *next_list = NULL; + + qdf_list_peek_front(list, &cur_list); + while (cur_list) { + cur_node = qdf_container_of(cur_list, + struct sir_rssi_disallow_lst, node); + if (!oldest_node || + (lim_assoc_rej_get_remaining_delta(oldest_node) > + lim_assoc_rej_get_remaining_delta(cur_node))) + oldest_node = cur_node; + + qdf_list_peek_next(list, cur_list, &next_list); + cur_list = next_list; + next_list = NULL; + } + + if (oldest_node) { + pe_debug("remove node "QDF_MAC_ADDR_FMT" with lowest delta %d", + QDF_MAC_ADDR_REF(oldest_node->bssid.bytes), + lim_assoc_rej_get_remaining_delta(oldest_node)); + qdf_list_remove_node(list, &oldest_node->node); + qdf_mem_free(oldest_node); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_INVAL; +} + +void +lim_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct sir_rssi_disallow_lst *entry) +{ + struct reject_ap_info ap_info; + + qdf_mem_zero(&ap_info, sizeof(struct reject_ap_info)); + ap_info.bssid = entry->bssid; + ap_info.reject_ap_type = DRIVER_RSSI_REJECT_TYPE; + ap_info.rssi_reject_params.expected_rssi = entry->expected_rssi; + ap_info.rssi_reject_params.retry_delay = entry->retry_delay; + ap_info.reject_reason = entry->reject_reason; + ap_info.source = entry->source; + ap_info.rssi_reject_params.received_time = entry->received_time; + ap_info.rssi_reject_params.original_timeout = entry->original_timeout; + /* Add this ap info to the rssi reject ap type in denylist manager */ + wlan_dlm_add_bssid_to_reject_list(pdev, &ap_info); +} + +void lim_decrement_pending_mgmt_count(struct mac_context *mac_ctx) +{ + qdf_spin_lock(&mac_ctx->sys.bbt_mgmt_lock); + if (!mac_ctx->sys.sys_bbt_pending_mgmt_count) { + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); + return; + } + mac_ctx->sys.sys_bbt_pending_mgmt_count--; + qdf_spin_unlock(&mac_ctx->sys.bbt_mgmt_lock); +} + +bool lim_check_if_vendor_oui_match(struct mac_context *mac_ctx, + uint8_t *oui, uint8_t oui_len, + uint8_t *ie, uint8_t ie_len) +{ + uint8_t *ptr = ie; + uint8_t elem_id; + + if (!ie || 0 == ie_len) { + pe_err("IE Null or ie len zero %d", ie_len); + return false; + } + + elem_id = *ie; + + if (elem_id == WLAN_ELEMID_VENDOR && + !qdf_mem_cmp(&ptr[2], oui, oui_len)) + return true; + else + return false; +} + +QDF_STATUS lim_util_get_type_subtype(void *pkt, uint8_t *type, + uint8_t *subtype) +{ + cds_pkt_t *cds_pkt; + QDF_STATUS status; + tpSirMacMgmtHdr hdr; + uint8_t *rxpktinfor; + + cds_pkt = (cds_pkt_t *) pkt; + if (!cds_pkt) { + pe_err("NULL packet received"); + return QDF_STATUS_E_FAILURE; + } + status = wma_ds_peek_rx_packet_info(cds_pkt, (void *)&rxpktinfor); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Failed extract cds packet. status %d", status); + return QDF_STATUS_E_FAILURE; + } + + hdr = WMA_GET_RX_MAC_HEADER(rxpktinfor); + if (hdr->fc.type == SIR_MAC_MGMT_FRAME) { + pe_debug("RxBd: %pK mHdr: %pK Type: %d Subtype: %d SizeFC: %zu", + rxpktinfor, hdr, hdr->fc.type, hdr->fc.subType, + sizeof(tSirMacFrameCtl)); + *type = hdr->fc.type; + *subtype = hdr->fc.subType; + } else { + pe_err("Not a management packet type %d", hdr->fc.type); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +static void lim_get_min_rate(uint8_t *min_rate, tSirMacRateSet *rateset) +{ + uint8_t curr_rate, i; + + for (i = 0; i < rateset->numRates; i++) { + /* Ignore MSB - set to indicate basic rate */ + curr_rate = rateset->rate[i] & 0x7F; + *min_rate = (curr_rate < *min_rate) ? curr_rate : + *min_rate; + } + + pe_debug("supported min_rate: %0x(%d)", *min_rate, *min_rate); +} + +static bool lim_is_enable_he_mcs0_for_6ghz_mgmt(struct pe_session *session, + qdf_freq_t freq) +{ + bool enable_he_mcs0_for_6ghz_mgmt = false; + + if (!wlan_reg_is_6ghz_chan_freq(freq)) + return enable_he_mcs0_for_6ghz_mgmt; + + /* + * For 6GHz freq and if enable_he_mcs0_for_mgmt_6ghz INI is + * enabled then FW will use rate of MCS0 for 11AX and configured + * via WMI_MGMT_TX_SEND_CMDID + */ + wlan_mlme_get_mgmt_6ghz_rate_support( + session->mac_ctx->psoc, + &enable_he_mcs0_for_6ghz_mgmt); + + return enable_he_mcs0_for_6ghz_mgmt; +} + +enum rateid lim_get_min_session_txrate(struct pe_session *session, + qdf_freq_t *pre_auth_freq) +{ + enum rateid rid = RATEID_DEFAULT; + uint8_t min_rate = SIR_MAC_RATE_54; + tSirMacRateSet *rateset; + qdf_freq_t op_freq; + + if (!session) + return rid; + + rateset = &session->rateSet; + + if (pre_auth_freq) { + pe_debug("updated rateset to pre auth freq %d", + *pre_auth_freq); + if (*pre_auth_freq && + !lim_is_enable_he_mcs0_for_6ghz_mgmt(session, + *pre_auth_freq)) + lim_get_basic_rates(rateset, *pre_auth_freq); + else + return rid; + } + + op_freq = wlan_get_operation_chan_freq(session->vdev); + if (lim_is_enable_he_mcs0_for_6ghz_mgmt(session, op_freq)) + return rid; + + lim_get_min_rate(&min_rate, rateset); + + if (session->is_oui_auth_assoc_6mbps_2ghz_enable) + min_rate = SIR_MAC_RATE_6; + + switch (min_rate) { + case SIR_MAC_RATE_1: + rid = RATEID_1MBPS; + break; + case SIR_MAC_RATE_2: + rid = RATEID_2MBPS; + break; + case SIR_MAC_RATE_5_5: + rid = RATEID_5_5MBPS; + break; + case SIR_MAC_RATE_11: + rid = RATEID_11MBPS; + break; + case SIR_MAC_RATE_6: + rid = RATEID_6MBPS; + break; + case SIR_MAC_RATE_9: + rid = RATEID_9MBPS; + break; + case SIR_MAC_RATE_12: + rid = RATEID_12MBPS; + break; + case SIR_MAC_RATE_18: + rid = RATEID_18MBPS; + break; + case SIR_MAC_RATE_24: + rid = RATEID_24MBPS; + break; + case SIR_MAC_RATE_36: + rid = RATEID_36MBPS; + break; + case SIR_MAC_RATE_48: + rid = RATEID_48MBPS; + break; + case SIR_MAC_RATE_54: + rid = RATEID_54MBPS; + break; + default: + rid = RATEID_DEFAULT; + break; + } + + return rid; +} + +void lim_send_sme_mgmt_frame_ind(struct mac_context *mac_ctx, uint8_t frame_type, + uint8_t *frame, uint32_t frame_len, + uint16_t vdev_id, uint32_t rx_freq, + int8_t rx_rssi, enum rxmgmt_flags rx_flags) +{ + tpSirSmeMgmtFrameInd sme_mgmt_frame = NULL; + uint16_t length; + struct wlan_objmgr_vdev *vdev; + + length = sizeof(tSirSmeMgmtFrameInd) + frame_len; + + sme_mgmt_frame = qdf_mem_malloc(length); + if (!sme_mgmt_frame) + return; + + if (qdf_is_macaddr_broadcast( + (struct qdf_mac_addr *)(frame + 4)) && + !vdev_id) { + pe_debug("Broadcast action frame"); + vdev_id = SME_SESSION_ID_BROADCAST; + } + + sme_mgmt_frame->frame_len = frame_len; + sme_mgmt_frame->sessionId = vdev_id; + sme_mgmt_frame->frameType = frame_type; + sme_mgmt_frame->rxRssi = rx_rssi; + sme_mgmt_frame->rx_freq = rx_freq; + sme_mgmt_frame->rx_flags = rx_flags; + + qdf_mem_zero(sme_mgmt_frame->frameBuf, frame_len); + qdf_mem_copy(sme_mgmt_frame->frameBuf, frame, frame_len); + + if (vdev_id != SME_SESSION_ID_BROADCAST && + frame_type == SIR_MAC_MGMT_ACTION) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + pe_debug("Invalid VDEV %d", vdev_id); + goto send_frame; + } + + wlan_mlo_update_action_frame_to_user(vdev, + sme_mgmt_frame->frameBuf, + sme_mgmt_frame->frame_len); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + } + +send_frame: + if (mac_ctx->mgmt_frame_ind_cb) + mac_ctx->mgmt_frame_ind_cb(sme_mgmt_frame); + else + pe_debug_rl("Management indication callback not registered!!"); + + qdf_mem_free(sme_mgmt_frame); + + return; +} + +void +lim_send_dfs_chan_sw_ie_update(struct mac_context *mac_ctx, struct pe_session *session) +{ + /* Update the beacon template and send to FW */ + if (sch_set_fixed_beacon_fields(mac_ctx, session) != + QDF_STATUS_SUCCESS) { + pe_err("Unable to set CSA IE in beacon"); + return; + } + + /* Send update beacon template message */ + lim_send_beacon_ind(mac_ctx, session, REASON_CHANNEL_SWITCH); + pe_debug("Updated CSA IE, IE COUNT: %d", + session->gLimChannelSwitch.switchCount); +} + +bool lim_is_csa_tx_pending(uint8_t vdev_id) +{ + struct pe_session *session; + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + bool csa_tx_offload; + + if (!mac_ctx) { + mlme_err("Invalid mac context"); + return false; + } + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("Session does not exist for given vdev_id %d", vdev_id); + return false; + } + + csa_tx_offload = wlan_psoc_nif_fw_ext_cap_get(mac_ctx->psoc, + WLAN_SOC_CEXT_CSA_TX_OFFLOAD); + if (session->dfsIncludeChanSwIe && + (session->gLimChannelSwitch.switchCount == + mac_ctx->sap.SapDfsInfo.sap_ch_switch_beacon_cnt) && + csa_tx_offload) + return true; + + return false; +} + +void lim_send_csa_tx_complete(uint8_t vdev_id) +{ + QDF_STATUS status; + tSirSmeCSAIeTxCompleteRsp *chan_switch_tx_rsp; + struct pe_session *session; + struct scheduler_msg msg = {0}; + bool csa_tx_offload; + uint8_t length = sizeof(*chan_switch_tx_rsp); + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) { + mlme_err("Invalid mac context"); + return; + } + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("Session does not exist for given vdev_id %d", vdev_id); + return; + } + + /* Stop the timer if already running in case of csa*/ + csa_tx_offload = wlan_psoc_nif_fw_ext_cap_get(mac_ctx->psoc, + WLAN_SOC_CEXT_CSA_TX_OFFLOAD); + if (csa_tx_offload) + qdf_mc_timer_stop(&session->ap_ecsa_timer); + + /* Done with CSA IE update, send response back to SME */ + session->gLimChannelSwitch.switchCount = 0; + if (mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch == false) + session->gLimChannelSwitch.switchMode = 0; + + session->dfsIncludeChanSwIe = false; + session->dfsIncludeChanWrapperIe = false; + + chan_switch_tx_rsp = qdf_mem_malloc(length); + if (!chan_switch_tx_rsp) + return; + + chan_switch_tx_rsp->sessionId = session->smeSessionId; + chan_switch_tx_rsp->chanSwIeTxStatus = QDF_STATUS_SUCCESS; + + msg.type = eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND; + msg.bodyptr = chan_switch_tx_rsp; + + status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &msg); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(chan_switch_tx_rsp); +} + +void lim_process_ap_ecsa_timeout(void *data) +{ + struct pe_session *session = (struct pe_session *)data; + struct mac_context *mac_ctx; + uint8_t bcn_int, ch_width; + uint32_t ch_freq; + bool csa_tx_offload; + QDF_STATUS status; + + if (!session || !session->valid) { + pe_err("Session is not valid"); + return; + } + + mac_ctx = session->mac_ctx; + + if (!session->dfsIncludeChanSwIe && + !session->bw_update_include_ch_sw_ie) { + pe_debug("session->dfsIncludeChanSwIe/chWidthUpdateIncludeChanSwIe not set"); + return; + } + + if (session->bw_update_include_ch_sw_ie) { + /* Stop the timer if already running */ + qdf_mc_timer_stop(&session->ap_ecsa_timer); + + lim_nss_or_ch_width_update_rsp(mac_ctx, + session->vdev_id, + QDF_STATUS_SUCCESS, + REASON_CH_WIDTH_UPDATE); + session->gLimChannelSwitch.switchCount = 0; + session->bw_update_include_ch_sw_ie = false; + + /* Clear CSA IE count and update beacon */ + lim_send_dfs_chan_sw_ie_update(mac_ctx, session); + + return; + } + + if (lim_is_csa_tx_pending(session->vdev_id)) + return lim_send_csa_tx_complete(session->vdev_id); + + csa_tx_offload = wlan_psoc_nif_fw_ext_cap_get(mac_ctx->psoc, + WLAN_SOC_CEXT_CSA_TX_OFFLOAD); + + if (csa_tx_offload) + return; + + /* Stop the timer if already running */ + qdf_mc_timer_stop(&session->ap_ecsa_timer); + + if (session->gLimChannelSwitch.switchCount) + /* Decrement the beacon switch count */ + session->gLimChannelSwitch.switchCount--; + + /* + * Send only g_sap_chanswitch_beacon_cnt beacons with CSA IE Set in + * when a radar is detected + */ + if (session->gLimChannelSwitch.switchCount > 0) { + /* Send the next beacon with updated CSA IE count */ + lim_send_dfs_chan_sw_ie_update(mac_ctx, session); + + ch_freq = session->gLimChannelSwitch.sw_target_freq; + ch_width = session->gLimChannelSwitch.ch_width; + if (mac_ctx->mlme_cfg->dfs_cfg.dfs_beacon_tx_enhanced) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq)) { + send_extended_chan_switch_action_frame + (mac_ctx, ch_freq, ch_width, + session); + } else { + /* Send Action frame after updating beacon */ + lim_send_chan_switch_action_frame + (mac_ctx, ch_freq, ch_width, + session); + } + } + + /* Restart the timer */ + if (session->beaconParams.beaconInterval) + bcn_int = session->beaconParams.beaconInterval; + else + bcn_int = MLME_CFG_BEACON_INTERVAL_DEF; + + status = qdf_mc_timer_start(&session->ap_ecsa_timer, + bcn_int); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("cannot start ap_ecsa_timer"); + lim_process_ap_ecsa_timeout(session); + } + } else { + lim_send_csa_tx_complete(session->vdev_id); + /* Clear CSA IE count and update beacon */ + lim_send_dfs_chan_sw_ie_update(mac_ctx, session); + } +} + +QDF_STATUS lim_sta_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct mac_context *mac_ctx; + enum vdev_assoc_type assoc_type; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + if (data) + qdf_mem_free(data); + return QDF_STATUS_E_INVAL; + } + + assoc_type = mlme_get_assoc_type(vdev_mlme->vdev); + switch (assoc_type) { + case VDEV_ASSOC: + lim_process_mlm_join_req(mac_ctx, (tLimMlmJoinReq *)data); + break; + case VDEV_REASSOC: + lim_process_mlm_reassoc_req(mac_ctx, (tLimMlmReassocReq *)data); + break; + case VDEV_FT_REASSOC: + lim_process_mlm_ft_reassoc_req(mac_ctx, + (tLimMlmReassocReq *)data); + break; + default: + pe_err("assoc_type %d is invalid", assoc_type); + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_sta_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct pe_session *session; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + session = (struct pe_session *)data; + if (!session) { + pe_err("Invalid session"); + return QDF_STATUS_E_INVAL; + } + if (!vdev_mlme) { + pe_err("vdev_mlme is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!data) { + pe_err("event_data is NULL"); + return QDF_STATUS_E_INVAL; + } + if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) { + switch (session->channelChangeReasonCode) { + case LIM_SWITCH_CHANNEL_OPERATION: + status = __lim_process_channel_switch_timeout(session); + break; + case LIM_SWITCH_CHANNEL_HT_WIDTH: + status = lim_ht_switch_chnl_params(session); + break; + case LIM_SWITCH_CHANNEL_REASSOC: + status = lim_send_switch_chnl_params(session->mac_ctx, + session); + break; + default: + break; + } + } + if (QDF_IS_STATUS_ERROR(status)) { + pe_err_rl("Failed to send VDEV_RESTART for chan switch vdev %d", + wlan_vdev_get_id(vdev_mlme->vdev)); + mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false); + } + + return status; +} + +QDF_STATUS lim_sta_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool connection_fail = false; + enum vdev_assoc_type assoc_type; + + if (!vdev_mlme) { + pe_err("vdev_mlme is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!data) { + pe_err("event_data is NULL"); + return QDF_STATUS_E_INVAL; + } + + connection_fail = mlme_is_connection_fail(vdev_mlme->vdev); + pe_debug("Send vdev stop, connection_fail %d", connection_fail); + if (connection_fail) { + assoc_type = mlme_get_assoc_type(vdev_mlme->vdev); + switch (assoc_type) { + case VDEV_ASSOC: + status = + lim_sta_handle_connect_fail((join_params *)data); + break; + case VDEV_REASSOC: + case VDEV_FT_REASSOC: + status = lim_sta_reassoc_error_handler( + (struct reassoc_params *)data); + break; + default: + pe_info("Invalid assoc_type %d", assoc_type); + status = QDF_STATUS_E_INVAL; + break; + } + mlme_set_connection_fail(vdev_mlme->vdev, false); + } else { + status = lim_sta_send_del_bss((struct pe_session *)data); + } + + return status; +} + +QDF_STATUS +lim_sta_mlme_vdev_sta_disconnect_start(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tpDphHashNode stads; + struct pe_session *session; + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("session is NULL for vdevid %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + stads = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if (!stads) + return QDF_STATUS_E_INVAL; + mlme_set_connection_fail(vdev_mlme->vdev, false); + + session->limPrevSmeState = session->limSmeState; + session->limSmeState = eLIM_SME_WT_DISASSOC_STATE; + + stads->mlmStaContext.disassocReason = REASON_UNSPEC_FAILURE; + stads->mlmStaContext.cleanupTrigger = eLIM_HOST_DISASSOC; + + stads->mlmStaContext.mlmState = eLIM_MLM_WT_DEL_STA_RSP_STATE; + + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_CONNECTION_FAIL, + sizeof(*session), session); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_sta_mlme_vdev_req_fail(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum vdev_assoc_type assoc_type; + + if (!vdev_mlme) { + pe_err("vdev_mlme is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!data) { + pe_err("event_data is NULL"); + return QDF_STATUS_E_INVAL; + } + + assoc_type = mlme_get_assoc_type(vdev_mlme->vdev); + switch (assoc_type) { + case VDEV_ASSOC: + status = lim_sta_handle_connect_fail((join_params *)data); + break; + case VDEV_REASSOC: + case VDEV_FT_REASSOC: + status = lim_sta_reassoc_error_handler( + (struct reassoc_params *)data); + break; + default: + pe_info("Invalid assoc_type %d", assoc_type); + status = QDF_STATUS_E_INVAL; + break; + } + + return status; +} + +void lim_send_beacon(struct mac_context *mac_ctx, struct pe_session *session) +{ + if (wlan_vdev_mlme_get_state(session->vdev) == + WLAN_VDEV_S_DFS_CAC_WAIT) + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_DFS_CAC_COMPLETED, + sizeof(*session), session); + else if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch && + (wlan_vdev_mlme_get_substate(session->vdev) == + WLAN_VDEV_SS_SUSPEND_CSA_RESTART)) + wlan_vdev_mlme_sm_deliver_evt( + session->vdev, + WLAN_VDEV_SM_EV_CHAN_SWITCH_DISABLED, + sizeof(*session), session); + else + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_SUCCESS, + sizeof(*session), session); +} + +void lim_ndi_mlme_vdev_up_transition(struct pe_session *session) +{ + if (!LIM_IS_NDI_ROLE(session)) + return; + + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_SUCCESS, + sizeof(*session), session); +} + +QDF_STATUS lim_sap_move_to_cac_wait_state(struct pe_session *session) +{ + QDF_STATUS status; + + status = + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_DFS_CAC_WAIT, + sizeof(*session), session); + return status; +} + +QDF_STATUS lim_ap_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct pe_session *session; + tpLimMlmStartReq start_req = (tLimMlmStartReq *)data; + struct mac_context *mac_ctx; + + if (!data) { + pe_err("data is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = pe_find_session_by_session_id(mac_ctx, + start_req->sessionId); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + + lim_process_mlm_start_req(session->mac_ctx, start_req); + + return QDF_STATUS_SUCCESS; +} + +static inline void lim_send_csa_restart_resp(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + msg.type = eWNI_SME_CSA_RESTART_RSP; + msg.bodyptr = NULL; + msg.bodyval = session->smeSessionId; + + status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &msg); +} + +QDF_STATUS lim_ap_mlme_vdev_update_beacon(struct vdev_mlme_obj *vdev_mlme, + enum beacon_update_op op, + uint16_t data_len, void *data) +{ + struct pe_session *session; + struct mac_context *mac_ctx; + + if (!data) { + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + session = pe_find_session_by_vdev_id( + mac_ctx, vdev_mlme->vdev->vdev_objmgr.vdev_id); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + } else { + session = (struct pe_session *)data; + } + if (LIM_IS_NDI_ROLE(session)) + return QDF_STATUS_SUCCESS; + + if (op == BEACON_INIT) + lim_send_beacon_ind(session->mac_ctx, session, REASON_DEFAULT); + else if (op == BEACON_UPDATE) + lim_send_beacon_ind(session->mac_ctx, + session, + REASON_CONFIG_UPDATE); + else if (op == BEACON_CSA) + lim_send_csa_restart_resp(session->mac_ctx, session); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_ap_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + struct pe_session *session; + struct mac_context *mac_ctx; + + if (!data) { + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + session = pe_find_session_by_vdev_id( + mac_ctx, vdev_mlme->vdev->vdev_objmgr.vdev_id); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + } else { + session = (struct pe_session *)data; + } + + if (LIM_IS_NDI_ROLE(session)) + return QDF_STATUS_SUCCESS; + + if (!wlan_vdev_mlme_is_mlo_ap(vdev_mlme->vdev)) + lim_configure_fd_for_existing_6ghz_sap(session, true); + + msg.type = SIR_HAL_SEND_AP_VDEV_UP; + msg.bodyval = session->smeSessionId; + + status = scheduler_post_message(QDF_MODULE_ID_PE, QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + + return status; +} + +QDF_STATUS lim_ap_mlme_vdev_rnr_notify(struct pe_session *session) +{ + struct mac_context *mac_ctx; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t vdev_num; + uint8_t i; + struct pe_session *co_session; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + if (!mlme_is_notify_co_located_ap_update_rnr(session->vdev)) + return status; + mlme_set_notify_co_located_ap_update_rnr(session->vdev, false); + // Only 6G SAP need to notify co-located SAP to add RNR + if (!wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) + return status; + pe_debug("vdev id %d non mlo 6G AP notify co-located AP to update RNR", + wlan_vdev_get_id(session->vdev)); + vdev_num = policy_mgr_get_sap_mode_info(mac_ctx->psoc, freq_list, + vdev_id_list); + for (i = 0; i < vdev_num; i++) { + if (vdev_id_list[i] == session->vdev_id) + continue; + if (wlan_reg_is_6ghz_chan_freq(freq_list[i])) + continue; + co_session = pe_find_session_by_vdev_id(mac_ctx, + vdev_id_list[i]); + if (!co_session) + continue; + + status = sch_set_fixed_beacon_fields(mac_ctx, co_session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Unable to update 6g co located RNR in beacon"); + return status; + } + + status = lim_send_beacon_ind(mac_ctx, co_session, + REASON_RNR_UPDATE); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Unable to send beacon indication"); + return status; + } + } + + return status; +} + +QDF_STATUS lim_ap_mlme_vdev_disconnect_peers(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct pe_session *session; + struct mac_context *mac_ctx; + + if (!data) { + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return QDF_STATUS_E_INVAL; + } + session = pe_find_session_by_vdev_id( + mac_ctx, vdev_mlme->vdev->vdev_objmgr.vdev_id); + if (!session) { + pe_err("session is NULL"); + return QDF_STATUS_E_INVAL; + } + } else { + session = (struct pe_session *)data; + } + + lim_delete_all_peers(session); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +static +void lim_apply_puncture(struct mac_context *mac, + struct pe_session *session, + qdf_freq_t sec_chan_freq) +{ + uint16_t puncture_bitmap; + + puncture_bitmap = + *(uint16_t *)session->eht_op.disabled_sub_chan_bitmap; + + if (puncture_bitmap) { + pe_debug("Apply puncture to reg: bitmap 0x%x, freq: %d, bw %d, mhz_freq_seg1: %d", + puncture_bitmap, + session->curr_op_freq, + session->ch_width, + sec_chan_freq); + wlan_reg_apply_puncture(mac->pdev, + puncture_bitmap, + session->curr_op_freq, + session->ch_width, + sec_chan_freq); + } +} + +static +void lim_remove_puncture(struct mac_context *mac, + struct pe_session *session) +{ + uint16_t puncture_bitmap; + + puncture_bitmap = + *(uint16_t *)session->eht_op.disabled_sub_chan_bitmap; + if (puncture_bitmap) { + pe_debug("Remove puncture from reg: bitmap 0x%x", + puncture_bitmap); + wlan_reg_remove_puncture(mac->pdev); + } +} +#else +static inline +void lim_apply_puncture(struct mac_context *mac, + struct pe_session *session, + qdf_freq_t sec_chan_freq) +{ +} + +static inline +void lim_remove_puncture(struct mac_context *mac, + struct pe_session *session) +{ +} +#endif + +QDF_STATUS lim_ap_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct pe_session *session = (struct pe_session *)data; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = session->mac_ctx; + + if (!data) { + pe_err("data is NULL"); + return QDF_STATUS_E_INVAL; + } + + lim_remove_puncture(mac_ctx, session); + + if (!wlan_vdev_mlme_is_mlo_ap(vdev_mlme->vdev)) { + mlme_set_notify_co_located_ap_update_rnr(vdev_mlme->vdev, true); + lim_ap_mlme_vdev_rnr_notify(session); + lim_configure_fd_for_existing_6ghz_sap(session, false); + } + + status = lim_send_vdev_stop(session); + + return status; +} + +QDF_STATUS lim_ap_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct pe_session *session = (struct pe_session *)data; + + if (!data) { + pe_err("data is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (ap_mlme_is_hidden_ssid_restart_in_progress(vdev_mlme->vdev)) + lim_send_vdev_restart(session->mac_ctx, session, + session->smeSessionId); + else + lim_send_switch_chnl_params(session->mac_ctx, session); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_ap_mlme_vdev_start_req_failed(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct mac_context *mac_ctx; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + if (data) + qdf_mem_free(data); + return QDF_STATUS_E_INVAL; + } + + lim_process_mlm_start_cnf(mac_ctx, data); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_mon_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + struct mac_context *mac_ctx; + struct pe_session *session = (struct pe_session *)data; + + if (!data) { + pe_err("data is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx = session->mac_ctx; + if (!mac_ctx) { + pe_err("mac_ctx is NULL"); + return QDF_STATUS_E_INVAL; + } + + lim_send_switch_chnl_params(mac_ctx, session); + + return QDF_STATUS_SUCCESS; +} + +void lim_send_start_bss_confirm(struct mac_context *mac_ctx, + tLimMlmStartCnf *start_cnf) +{ + if (start_cnf->resultCode == eSIR_SME_SUCCESS) { + lim_post_sme_message(mac_ctx, LIM_MLM_START_CNF, + (uint32_t *)start_cnf); + } else { + struct pe_session *session; + + session = pe_find_session_by_session_id(mac_ctx, + start_cnf->sessionId); + if (!session) { + pe_err("session is NULL"); + return; + } + mlme_set_vdev_start_failed(session->vdev, true); + wlan_vdev_mlme_sm_deliver_evt(session->vdev, + WLAN_VDEV_SM_EV_START_REQ_FAIL, + sizeof(*start_cnf), start_cnf); + } +} + +QDF_STATUS lim_get_capability_info(struct mac_context *mac, uint16_t *pcap, + struct pe_session *pe_session) +{ + uint32_t val = 0; + tpSirMacCapabilityInfo pcap_info; + + *pcap = 0; + pcap_info = (tpSirMacCapabilityInfo)pcap; + + if (LIM_IS_AP_ROLE(pe_session) || + LIM_IS_STA_ROLE(pe_session)) + pcap_info->ess = 1; /* ESS bit */ + else if (LIM_IS_P2P_DEVICE_ROLE(pe_session) || + LIM_IS_NDI_ROLE(pe_session)) { + pcap_info->ess = 0; + pcap_info->ibss = 0; + } else + pe_warn("can't get capability, role is UNKNOWN!!"); + + if (LIM_IS_AP_ROLE(pe_session)) { + val = pe_session->privacy; + } else { + /* PRIVACY bit */ + val = mac->mlme_cfg->wep_params.is_privacy_enabled; + } + if (val) + pcap_info->privacy = 1; + + /* Short preamble bit */ + if (mac->mlme_cfg->ht_caps.short_preamble) + pcap_info->shortPreamble = + mac->mlme_cfg->ht_caps.short_preamble; + + /* criticalUpdateFlag bit */ + pcap_info->criticalUpdateFlag = 0; + + /* Channel agility bit */ + pcap_info->channelAgility = 0; + /* If STA/AP operating in 11B mode, don't set rest of the + * capability info bits. + */ + if (pe_session->dot11mode == MLME_DOT11_MODE_11B) + return QDF_STATUS_SUCCESS; + + /* Short slot time bit */ + if (LIM_IS_AP_ROLE(pe_session)) { + pcap_info->shortSlotTime = pe_session->shortSlotTimeSupported; + } else { + /* When in STA mode, we need to check if short slot is + * enabled as well as check if the current operating + * mode is short slot time and then decide whether to + * enable short slot or not. It is safe to check both + * cfg values to determine short slot value in this + * funcn since this funcn is always used after assoc + * when these cfg values are already set based on + * peer's capability. Even in case of IBSS, its value + * is set to correct value either in delBSS as part of + * deleting the previous IBSS or in start BSS as part + * of coalescing + */ + if (mac->mlme_cfg->feature_flags.enable_short_slot_time_11g) { + pcap_info->shortSlotTime = + pe_session->shortSlotTimeSupported; + } + } + + /* Spectrum Management bit */ + if (pe_session->lim11hEnable) { + if (mac->mlme_cfg->gen.enabled_11h) + pcap_info->spectrumMgt = 1; + } + /* QoS bit */ + if (mac->mlme_cfg->wmm_params.qos_enabled) + pcap_info->qos = 1; + + /* APSD bit */ + if (mac->mlme_cfg->roam_scoring.apsd_enabled) + pcap_info->apsd = 1; + + pcap_info->rrm = mac->rrm.rrmConfig.rrm_enabled; + pe_debug("RRM: %d", pcap_info->rrm); + /* DSSS-OFDM */ + /* FIXME : no config defined yet. */ + + /* Block ack bit */ + val = mac->mlme_cfg->feature_flags.enable_block_ack; + pcap_info->delayedBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + pcap_info->immediateBA = + (uint16_t) ((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + return QDF_STATUS_SUCCESS; +} + +void lim_flush_bssid(struct mac_context *mac_ctx, uint8_t *bssid) +{ + struct scan_filter *filter; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status; + + if (!bssid) + return; + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return; + + filter->num_of_bssid = 1; + qdf_mem_copy(filter->bssid_list[0].bytes, bssid, QDF_MAC_ADDR_SIZE); + + pdev = wlan_objmgr_get_pdev_by_id(mac_ctx->psoc, 0, WLAN_LEGACY_MAC_ID); + if (!pdev) { + pe_err("pdev is NULL"); + qdf_mem_free(filter); + return; + } + status = ucfg_scan_flush_results(pdev, filter); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + + if (QDF_IS_STATUS_SUCCESS(status)) + pe_debug("Removed BSS entry:"QDF_MAC_ADDR_FMT" from scan cache", + QDF_MAC_ADDR_REF(bssid)); + + if (filter) + qdf_mem_free(filter); +} + +bool lim_is_sha384_akm(enum ani_akm_type akm) +{ + switch (akm) { + case ANI_AKM_TYPE_FILS_SHA384: + case ANI_AKM_TYPE_FT_FILS_SHA384: + case ANI_AKM_TYPE_SUITEB_EAP_SHA384: + case ANI_AKM_TYPE_FT_SUITEB_EAP_SHA384: + return true; + default: + return false; + } +} + +QDF_STATUS lim_set_ch_phy_mode(struct wlan_objmgr_vdev *vdev, uint8_t dot11mode) +{ + struct vdev_mlme_obj *mlme_obj; + struct wlan_channel *des_chan; + uint32_t chan_mode; + enum phy_ch_width ch_width; + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + uint16_t bw_val; + enum reg_wifi_band band; + uint8_t band_mask; + enum channel_state ch_state; + uint32_t start_ch_freq; + struct ch_params ch_params = {0}; + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + des_chan = vdev->vdev_mlme.des_chan; + /* + * Set ch_cfreq1 to ch_freq for 20Mhz. If BW is greater than 20 it + * will be updated from ch_freq_seg1. + */ + des_chan->ch_cfreq1 = des_chan->ch_freq; + band = wlan_reg_freq_to_band(des_chan->ch_freq); + band_mask = 1 << band; + ch_width = des_chan->ch_width; + bw_val = wlan_reg_get_bw_value(ch_width); + if (bw_val > 20) { + if (des_chan->ch_freq_seg1) { + des_chan->ch_cfreq1 = + wlan_reg_chan_band_to_freq(mac_ctx->pdev, + des_chan->ch_freq_seg1, + band_mask); + } else if (bw_val >= 160) { + pe_debug("Skip center_freq check for bw %d", bw_val); + } else { + pe_err("Invalid cntr_freq for bw %d, drop to 20", + bw_val); + ch_width = CH_WIDTH_20MHZ; + bw_val = 20; + if (des_chan->ch_cfreq1) + des_chan->ch_freq_seg1 = + wlan_reg_freq_to_chan( + mac_ctx->pdev, + des_chan->ch_cfreq1); + } + } else if (des_chan->ch_cfreq1) { + des_chan->ch_freq_seg1 = + wlan_reg_freq_to_chan(mac_ctx->pdev, + des_chan->ch_cfreq1); + } + if (bw_val > 80) { + if (des_chan->ch_freq_seg2) { + des_chan->ch_cfreq2 = + wlan_reg_chan_band_to_freq(mac_ctx->pdev, + des_chan->ch_freq_seg2, + band_mask); + } else { + pe_err("Invalid cntr_freq for bw %d, drop to 80", + bw_val); + des_chan->ch_cfreq2 = 0; + des_chan->ch_freq_seg2 = 0; + ch_width = CH_WIDTH_80MHZ; + } + } else { + des_chan->ch_cfreq2 = 0; + des_chan->ch_freq_seg2 = 0; + } + + des_chan->ch_width = ch_width; + + des_chan->ch_flags = 0; + switch (ch_width) { + case CH_WIDTH_20MHZ: + des_chan->ch_flags |= IEEE80211_CHAN_VHT20; + break; + case CH_WIDTH_40MHZ: + des_chan->ch_flags |= IEEE80211_CHAN_VHT40PLUS; + break; + case CH_WIDTH_80MHZ: + des_chan->ch_flags |= IEEE80211_CHAN_VHT80; + break; + case CH_WIDTH_80P80MHZ: + des_chan->ch_flags |= IEEE80211_CHAN_VHT80_80; + break; + case CH_WIDTH_160MHZ: + des_chan->ch_flags |= IEEE80211_CHAN_VHT160; + break; + default: + break; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(des_chan->ch_freq)) + des_chan->ch_flags |= IEEE80211_CHAN_2GHZ; + else + des_chan->ch_flags |= IEEE80211_CHAN_5GHZ; + + des_chan->ch_flagext = 0; + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, des_chan->ch_freq)) + des_chan->ch_flagext |= IEEE80211_CHAN_DFS; + if (des_chan->ch_cfreq2) { + if (CH_WIDTH_80P80MHZ == des_chan->ch_width) + start_ch_freq = des_chan->ch_cfreq2 - 30; + else + start_ch_freq = des_chan->ch_freq; + + if (IS_DOT11_MODE_EHT(dot11mode)) + wlan_reg_set_create_punc_bitmap(&ch_params, true); + ch_params.ch_width = des_chan->ch_width; + ch_state = + wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac_ctx->pdev, + start_ch_freq, + &ch_params, + REG_CURRENT_PWR_MODE); + if (CHANNEL_STATE_DFS == ch_state) + des_chan->ch_flagext |= IEEE80211_CHAN_DFS_CFREQ2; + } + + chan_mode = wma_chan_phy_mode(des_chan->ch_freq, ch_width, + dot11mode); + + if (chan_mode == WLAN_PHYMODE_AUTO || chan_mode == WLAN_PHYMODE_MAX) { + pe_err("Invalid phy mode!"); + return QDF_STATUS_E_FAILURE; + } + if (!des_chan->ch_cfreq1) { + pe_err("Invalid center freq1"); + return QDF_STATUS_E_FAILURE; + } + + if ((ch_width == CH_WIDTH_160MHZ || + ch_width == CH_WIDTH_80P80MHZ) && !des_chan->ch_cfreq2) { + pe_err("Invalid center freq2 for 160MHz"); + return QDF_STATUS_E_FAILURE; + } + /* Till conversion is not done in WMI we need to fill fw phy mode */ + mlme_obj->mgmt.generic.phy_mode = wmi_host_to_fw_phymode(chan_mode); + des_chan->ch_phymode = chan_mode; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +/** + * lim_update_ap_puncture() - set puncture_bitmap for ap session + * @session: session + * @ch_params: pointer to ch_params + * + * Return: void + */ +static void lim_update_ap_puncture(struct pe_session *session, + struct ch_params *ch_params) +{ + if (ch_params->reg_punc_bitmap) { + *(uint16_t *)session->eht_op.disabled_sub_chan_bitmap = + ch_params->reg_punc_bitmap; + session->eht_op.disabled_sub_chan_bitmap_present = true; + pe_debug("vdev %d, puncture %d", session->vdev_id, + ch_params->reg_punc_bitmap); + } +} + +void lim_update_des_chan_puncture(struct wlan_channel *des_chan, + struct ch_params *ch_params) +{ + des_chan->puncture_bitmap = ch_params->reg_punc_bitmap; +} + +void lim_overwrite_sta_puncture(struct pe_session *session, + struct ch_params *ch_param) +{ + uint16_t new_punc = 0; + + wlan_reg_extract_puncture_by_bw(session->ch_width, + session->puncture_bitmap, + session->curr_op_freq, + ch_param->mhz_freq_seg1, + ch_param->ch_width, + &new_punc); + + ch_param->reg_punc_bitmap = new_punc; + session->puncture_bitmap = new_punc; +} + +#else +static void lim_update_ap_puncture(struct pe_session *session, + struct ch_params *ch_params) +{ +} +#endif + +QDF_STATUS lim_pre_vdev_start(struct mac_context *mac, + struct vdev_mlme_obj *mlme_obj, + struct pe_session *session) +{ + struct wlan_channel *des_chan; + enum reg_wifi_band band; + uint8_t band_mask; + struct ch_params ch_params = {0}; + qdf_freq_t sec_chan_freq = 0; + + band = wlan_reg_freq_to_band(session->curr_op_freq); + band_mask = 1 << band; + + ch_params.ch_width = session->ch_width; + ch_params.mhz_freq_seg0 = + wlan_reg_chan_band_to_freq(mac->pdev, + session->ch_center_freq_seg0, + band_mask); + + if (session->ch_center_freq_seg1) + ch_params.mhz_freq_seg1 = + wlan_reg_chan_band_to_freq(mac->pdev, + session->ch_center_freq_seg1, + band_mask); + + if (band == (REG_BAND_2G) && (ch_params.ch_width == CH_WIDTH_40MHZ)) { + if (ch_params.mhz_freq_seg0 == session->curr_op_freq + 10) + sec_chan_freq = session->curr_op_freq + 20; + if (ch_params.mhz_freq_seg0 == session->curr_op_freq - 10) + sec_chan_freq = session->curr_op_freq - 20; + } + if (LIM_IS_AP_ROLE(session) && + !mlme_is_chan_switch_in_progress(mlme_obj->vdev)) + lim_apply_puncture(mac, session, ch_params.mhz_freq_seg1); + + if (LIM_IS_STA_ROLE(session)) + wlan_cdp_set_peer_freq(mac->psoc, session->bssId, + session->curr_op_freq, + wlan_vdev_get_id(session->vdev)); + + if (IS_DOT11_MODE_EHT(session->dot11mode)) + wlan_reg_set_create_punc_bitmap(&ch_params, true); + + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + session->curr_op_freq, + sec_chan_freq, &ch_params, + REG_CURRENT_PWR_MODE); + + pe_debug("vdev id %d freq %d seg0 %d seg1 %d ch_width %d cac_duration_ms %d beacon_interval %d hidden_ssid: %d dtimPeriod %d slot_time %d bcn tx rate %d mhz seg0 %d mhz seg1 %d", + session->vdev_id, session->curr_op_freq, + ch_params.center_freq_seg0, + ch_params.center_freq_seg1, ch_params.ch_width, + session->cac_duration_ms, + session->beaconParams.beaconInterval, + session->ssidHidden, session->dtimPeriod, + session->shortSlotTimeSupported, + session->beacon_tx_rate, + ch_params.mhz_freq_seg0, + ch_params.mhz_freq_seg1); + + /* Invalid channel width means no suitable channel bonding in current + * regdomain for requested channel frequency. Abort vdev start. + */ + if (ch_params.ch_width == CH_WIDTH_INVALID) { + pe_debug("abort vdev start invalid chan parameters"); + return QDF_STATUS_E_INVAL; + } + + if (LIM_IS_STA_ROLE(session)) + lim_overwrite_sta_puncture(session, &ch_params); + + des_chan = mlme_obj->vdev->vdev_mlme.des_chan; + des_chan->ch_freq = session->curr_op_freq; + des_chan->ch_width = ch_params.ch_width; + des_chan->ch_freq_seg1 = ch_params.center_freq_seg0; + des_chan->ch_freq_seg2 = ch_params.center_freq_seg1; + des_chan->ch_ieee = wlan_reg_freq_to_chan(mac->pdev, des_chan->ch_freq); + lim_update_des_chan_puncture(des_chan, &ch_params); + if (LIM_IS_AP_ROLE(session)) + lim_update_ap_puncture(session, &ch_params); + session->ch_width = ch_params.ch_width; + session->ch_center_freq_seg0 = ch_params.center_freq_seg0; + session->ch_center_freq_seg1 = ch_params.center_freq_seg1; + if (LIM_IS_AP_ROLE(session)) { + /* Update he ops for puncture */ + wlan_reg_set_create_punc_bitmap(&ch_params, false); + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + session->curr_op_freq, + sec_chan_freq, + &ch_params, + REG_CURRENT_PWR_MODE); + lim_update_ap_he_op(session, &ch_params); + + wlan_mlme_set_ap_oper_ch_width(session->vdev, + session->ch_width); + if (session->ch_width == CH_WIDTH_320MHZ && + policy_mgr_is_conn_lead_to_dbs_sbs(mac->psoc, + session->vdev_id, + session->curr_op_freq)) + wlan_mlme_set_ap_oper_ch_width(session->vdev, + CH_WIDTH_160MHZ); + } + mlme_obj->mgmt.generic.maxregpower = session->maxTxPower; + mlme_obj->proto.generic.beacon_interval = + session->beaconParams.beaconInterval; + if (mlme_obj->mgmt.generic.type == WLAN_VDEV_MLME_TYPE_AP) { + mlme_obj->mgmt.ap.hidden_ssid = session->ssidHidden; + wlan_util_vdev_mgr_set_cac_timeout_for_vdev( + mlme_obj->vdev, session->cac_duration_ms); + } + mlme_obj->proto.generic.dtim_period = session->dtimPeriod; + mlme_obj->proto.generic.slot_time = session->shortSlotTimeSupported; + mlme_obj->mgmt.rate_info.bcn_tx_rate = session->beacon_tx_rate; + + mlme_obj->proto.ht_info.allow_ht = !!session->htCapability; + mlme_obj->proto.vht_info.allow_vht = !!session->vhtCapability; + mlme_obj->ext_vdev_ptr->connect_info.uapsd_per_ac_bitmask = + session->gUapsdPerAcBitmask; + + if (cds_is_5_mhz_enabled()) + mlme_obj->mgmt.rate_info.quarter_rate = 1; + else if (cds_is_10_mhz_enabled()) + mlme_obj->mgmt.rate_info.half_rate = 1; + + if (session->nss == 2) { + mlme_obj->mgmt.chainmask_info.num_rx_chain = 2; + mlme_obj->mgmt.chainmask_info.num_tx_chain = 2; + } else { + mlme_obj->mgmt.chainmask_info.num_rx_chain = 1; + mlme_obj->mgmt.chainmask_info.num_tx_chain = 1; + } + wlan_vdev_mlme_set_ssid(mlme_obj->vdev, session->ssId.ssId, + session->ssId.length); + + return lim_set_ch_phy_mode(mlme_obj->vdev, session->dot11mode); +} + +uint8_t lim_get_he_max_mcs_idx(enum phy_ch_width ch_width, + tDot11fIEhe_cap *he_cap) +{ + uint16_t hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80 + 1]; + uint16_t hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80 + 1]; + + qdf_mem_zero(hecap_rxmcsnssmap, sizeof(hecap_rxmcsnssmap)); + qdf_mem_zero(hecap_txmcsnssmap, sizeof(hecap_txmcsnssmap)); + + qdf_mem_copy(&hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80], + &he_cap->rx_he_mcs_map_lt_80, + sizeof(u_int16_t)); + qdf_mem_copy(&hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80], + &he_cap->tx_he_mcs_map_lt_80, + sizeof(u_int16_t)); + if (he_cap->chan_width_2) { + qdf_mem_copy(&hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160], + &he_cap->rx_he_mcs_map_160, + sizeof(u_int16_t)); + qdf_mem_copy(&hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_160], + &he_cap->tx_he_mcs_map_160, + sizeof(u_int16_t)); + } + if (he_cap->chan_width_3) { + qdf_mem_copy(&hecap_rxmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80], + &he_cap->rx_he_mcs_map_80_80, + sizeof(u_int16_t)); + qdf_mem_copy(&hecap_txmcsnssmap[HECAP_TXRX_MCS_NSS_IDX_80_80], + &he_cap->tx_he_mcs_map_80_80, + sizeof(u_int16_t)); + } + + return mlme_get_max_he_mcs_idx(ch_width, hecap_rxmcsnssmap, + hecap_txmcsnssmap); +} + +uint8_t lim_get_vht_max_mcs_idx(tDot11fIEVHTCaps *vht_cap) +{ + return mlme_get_max_vht_mcs_idx(vht_cap->rxMCSMap & 0xff, + vht_cap->txMCSMap & 0xff); +} + +uint8_t lim_get_ht_max_mcs_idx(tDot11fIEHTCaps *ht_cap) +{ + uint8_t i, maxidx = INVALID_MCS_NSS_INDEX; + + for (i = 0; i < 8; i++) { + if (ht_cap->supportedMCSSet[0] & (1 << i)) + maxidx = i; + } + + return maxidx; +} + +uint8_t lim_get_max_rate_idx(tSirMacRateSet *rateset) +{ + uint8_t maxidx; + int i; + + maxidx = rateset->rate[0] & 0x7f; + for (i = 1; i < rateset->numRates; i++) { + if ((rateset->rate[i] & 0x7f) > maxidx) + maxidx = rateset->rate[i] & 0x7f; + } + + return maxidx; +} + +void lim_update_nss(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + uint8_t rx_nss, struct pe_session *session) +{ + if (sta_ds->vhtSupportedRxNss != (rx_nss + 1)) { + if (session->nss_forced_1x1) { + pe_debug("Not Updating NSS for special AP"); + return; + } + sta_ds->vhtSupportedRxNss = rx_nss + 1; + lim_set_nss_change(mac_ctx, session, + sta_ds->vhtSupportedRxNss, + sta_ds->staAddr); + } +} + + +bool lim_update_channel_width(struct mac_context *mac_ctx, + tpDphHashNode sta_ptr, + struct pe_session *session, + enum phy_ch_width ch_width, + enum phy_ch_width *new_ch_width) +{ + uint8_t cb_mode; + enum phy_ch_width oper_mode; + enum phy_ch_width fw_vht_ch_wd; + + cb_mode = lim_get_cb_mode_for_freq(mac_ctx, session, + session->curr_op_freq); + /* + * Do not update the channel bonding mode if channel bonding + * mode is disabled in INI. + */ + if (cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) + return false; + + if (sta_ptr->htSupportedChannelWidthSet) { + if (sta_ptr->vhtSupportedChannelWidthSet > + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ) + oper_mode = CH_WIDTH_160MHZ; + else + oper_mode = sta_ptr->vhtSupportedChannelWidthSet + 1; + } else { + oper_mode = CH_WIDTH_20MHZ; + } + + fw_vht_ch_wd = wlan_mlme_get_max_bw(); + + if (ch_width > fw_vht_ch_wd) { + pe_debug_rl(QDF_MAC_ADDR_FMT ": Downgrade new bw: %d to max %d", + QDF_MAC_ADDR_REF(sta_ptr->staAddr), + ch_width, fw_vht_ch_wd); + ch_width = fw_vht_ch_wd; + } + if (oper_mode == ch_width) + return false; + + pe_debug(QDF_MAC_ADDR_FMT ": Current : %d, New: %d max %d ", + QDF_MAC_ADDR_REF(sta_ptr->staAddr), oper_mode, + ch_width, fw_vht_ch_wd); + + if (ch_width >= CH_WIDTH_160MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + ch_width = CH_WIDTH_160MHZ; + } else if (ch_width == CH_WIDTH_80MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + } else if (ch_width == CH_WIDTH_40MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } else if (ch_width == CH_WIDTH_20MHZ) { + sta_ptr->vhtSupportedChannelWidthSet = + WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } else { + return false; + } + if (ch_width >= CH_WIDTH_40MHZ) + sta_ptr->htSupportedChannelWidthSet = CH_WIDTH_40MHZ; + else + sta_ptr->htSupportedChannelWidthSet = CH_WIDTH_20MHZ; + *new_ch_width = ch_width; + + return lim_check_vht_op_mode_change(mac_ctx, session, *new_ch_width, + sta_ptr->staAddr); +} + +uint8_t lim_get_vht_ch_width(tDot11fIEVHTCaps *vht_cap, + tDot11fIEVHTOperation *vht_op, + tDot11fIEHTInfo *ht_info) +{ + uint8_t ccfs0, ccfs1, offset; + uint8_t ch_width; + + ccfs0 = vht_op->chan_center_freq_seg0; + ccfs1 = vht_op->chan_center_freq_seg1; + ch_width = vht_op->chanWidth; + + if (ch_width > WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ) { + pe_err("Invalid ch width in vht operation IE %d", ch_width); + return WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ; + } + + if (vht_cap->vht_extended_nss_bw_cap && + vht_cap->extended_nss_bw_supp && ht_info && ht_info->present) + ccfs1 = ht_info->chan_center_freq_seg2; + + /* According to new VHTOP IE definition, vht ch_width will + * be 1 for 80MHz, 160MHz and 80+80MHz. + * + * To get the correct operation ch_width, find center + * frequency difference. + */ + if (ch_width == WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ && ccfs1) { + offset = abs(ccfs0 - ccfs1); + + if (offset == 8) + ch_width = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + else if (offset > 16) + ch_width = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + } + return ch_width; +} + +bool +lim_set_tpc_power(struct mac_context *mac_ctx, struct pe_session *session, + struct bss_description *bss_desc) +{ + struct wlan_lmac_if_reg_tx_ops *tx_ops; + struct vdev_mlme_obj *mlme_obj; + bool tpe_change = false; + + if (!wlan_reg_is_ext_tpc_supported(mac_ctx->psoc)) + return true; + tx_ops = wlan_reg_get_tx_ops(mac_ctx->psoc); + + if (!tx_ops || !tx_ops->set_tpc_power) + return false; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!mlme_obj) + return false; + + if ((session->opmode == QDF_STA_MODE || + session->opmode == QDF_P2P_CLIENT_MODE) && + bss_desc) + lim_process_tpe_ie_from_beacon(mac_ctx, session, + bss_desc, &tpe_change); + + if (session->opmode == QDF_SAP_MODE || + session->opmode == QDF_P2P_GO_MODE) + mlme_obj->reg_tpc_obj.num_pwr_levels = 0; + + lim_calculate_tpc(mac_ctx, session); + + tx_ops->set_tpc_power(mac_ctx->psoc, session->vdev_id, + &mlme_obj->reg_tpc_obj); + return true; +} + +/* + * lim_get_tx_power() - Function to get the Tx power of the center frequency + * of the sap interface. + * + * @reg_tpc: reg_tpc mlme obj pointer + * @freq: center frequency of the SAP. + * + * Return: tx power + */ +static uint8_t +lim_get_tx_power(struct reg_tpc_power_info *reg_tpc, qdf_freq_t freq) +{ + int i; + + for (i = 0; i < reg_tpc->num_pwr_levels; i++) { + if (reg_tpc->chan_power_info[i].chan_cfreq == freq) + return reg_tpc->chan_power_info[i].tx_power; + } + + return 0; +} + +struct pe_session * +lim_get_concurrent_session(struct mac_context *mac_ctx, uint8_t vdev_id, + enum QDF_OPMODE opmode) +{ + uint8_t mac_id, conc_vdev_id; + struct pe_session *session; + + policy_mgr_get_mac_id_by_session_id(mac_ctx->psoc, vdev_id, &mac_id); + + conc_vdev_id = policy_mgr_get_conc_vdev_on_same_mac(mac_ctx->psoc, + vdev_id, mac_id); + + session = pe_find_session_by_vdev_id(mac_ctx, conc_vdev_id); + if (!session) + return NULL; + + switch (opmode) { + case QDF_STA_MODE: + case QDF_P2P_CLIENT_MODE: + if (session->opmode != QDF_SAP_MODE && + session->opmode != QDF_P2P_GO_MODE) + return NULL; + break; + case QDF_SAP_MODE: + case QDF_P2P_GO_MODE: + if (session->opmode != QDF_STA_MODE && + session->opmode != QDF_P2P_CLIENT_MODE) + return NULL; + break; + default: + return NULL; + } + + return session; +} + +QDF_STATUS +lim_update_tx_power(struct mac_context *mac_ctx, struct pe_session *sap_session, + struct pe_session *sta_session, bool restore_sta_power) +{ + uint8_t pwr_level; + struct vdev_mlme_obj *sta_mlme_obj, *sap_mlme_obj; + struct reg_tpc_power_info *reg_info; + uint8_t tx_power, i; + struct bss_description *bss_desc = NULL; + + sta_mlme_obj = wlan_vdev_mlme_get_cmpt_obj(sta_session->vdev); + sap_mlme_obj = wlan_vdev_mlme_get_cmpt_obj(sap_session->vdev); + + if (!sta_mlme_obj || !sap_mlme_obj) + return QDF_STATUS_E_FAILURE; + + if (restore_sta_power) { + /* SAP interface is removed, restore the STA power */ + wlan_set_tpc_update_required_for_sta(sap_session->vdev, false); + sta_session->sta_follows_sap_power = false; + + if (sta_session->lim_join_req) + bss_desc = &sta_session->lim_join_req->bssDescription; + + lim_set_tpc_power(mac_ctx, sta_session, bss_desc); + } else { + /* + * SAP and STA are in different AP power types. Therefore, + * update the reg_tpc_obj of STA with new power levels. + * Do not send new TPC power to FW. + */ + sta_session->sta_follows_sap_power = true; + + if (sta_mlme_obj->reg_tpc_obj.power_type_6g == + sap_mlme_obj->reg_tpc_obj.power_type_6g) { + pe_err("STA and SAP are in same power type"); + return QDF_STATUS_E_FAILURE; + } + pe_debug("STA is moved to %d from %d power type", + sap_mlme_obj->reg_tpc_obj.power_type_6g, + sta_mlme_obj->reg_tpc_obj.power_type_6g); + sta_mlme_obj->reg_tpc_obj.power_type_6g = + sap_mlme_obj->reg_tpc_obj.power_type_6g; + + tx_power = lim_get_tx_power(&sap_mlme_obj->reg_tpc_obj, + sap_session->curr_op_freq); + + reg_info = &sta_mlme_obj->reg_tpc_obj; + pwr_level = reg_info->num_pwr_levels; + for (i = 0; i < pwr_level; i++) + reg_info->chan_power_info[i].tx_power = tx_power; + wlan_set_tpc_update_required_for_sta(sap_session->vdev, true); + } + return QDF_STATUS_SUCCESS; +} + +bool +lim_is_power_change_required_for_sta(struct mac_context *mac_ctx, + struct pe_session *sta_session, + struct pe_session *sap_session) +{ + enum channel_state channel_state; + struct vdev_mlme_obj *mlme_obj; + uint32_t ap_power_type_6g = 0; + + channel_state = + wlan_reg_get_channel_state_for_pwrmode(mac_ctx->pdev, + sap_session->curr_op_freq, + REG_AP_VLP); + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(sap_session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return false; + } + + if (sta_session->curr_op_freq != sap_session->curr_op_freq) + return false; + + wlan_reg_get_cur_6g_ap_pwr_type(mac_ctx->pdev, &ap_power_type_6g); + + if (sta_session->best_6g_power_type == REG_INDOOR_AP && + channel_state & CHANNEL_STATE_ENABLE && + ap_power_type_6g == REG_VERY_LOW_POWER_AP) { + pe_debug("Change the power type of STA from LPI to VLP"); + return true; + } + + return false; +} + +void +lim_check_conc_power_for_csa(struct mac_context *mac_ctx, + struct pe_session *sap_session) +{ + struct pe_session *sta_session; + bool update_required_scc_sta_power = + wlan_get_tpc_update_required_for_sta(sap_session->vdev); + + /* + * If SCC power has changed and concurrent session doesn't exist, + * then STA must have got deleted or moved out of 6GHz. + * In that case, reset the change scc power flag for SAP. + */ + sta_session = lim_get_concurrent_session(mac_ctx, sap_session->vdev_id, + sap_session->opmode); + if (!sta_session) { + pe_debug("STA session doesn't exist"); + return; + } + + /* If SCC power has changed and the SAP is moving away from 6GHz, + * reset the scc power flag in SAP vdev and restore the STA + * power + */ + if (update_required_scc_sta_power && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_session->curr_op_freq) && + WLAN_REG_IS_6GHZ_CHAN_FREQ(sta_session->curr_op_freq)) { + pe_debug("SAP has moved from 6GHz, restore STA power"); + lim_update_tx_power(mac_ctx, sap_session, sta_session, true); + return; + } + + /* If SAP is moving to 6GHz. Then: + * a) If change scc power is not set, check if it needs to be set + * If it is getting set, then send new tpc power to FW. + * b) If change scc power is already set, then SAP is moving from one + * 6GHz to another 6GHz. Recompute the TPC. + */ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_session->curr_op_freq) && + sta_session && + WLAN_REG_IS_6GHZ_CHAN_FREQ(sta_session->curr_op_freq) && + (wlan_vdev_mlme_get_state(sap_session->vdev) == WLAN_VDEV_S_UP)) { + if (lim_is_power_change_required_for_sta(mac_ctx, sta_session, + sap_session)) { + lim_set_tpc_power(mac_ctx, sap_session, NULL); + if (lim_update_tx_power(mac_ctx, sap_session, + sta_session, false) == + QDF_STATUS_SUCCESS) + wlan_set_tpc_update_required_for_sta( + sap_session->vdev, + true); + } + } +} + +void +lim_cleanup_power_change(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct pe_session *sap_session; + + if (session->opmode != QDF_STA_MODE && + session->opmode != QDF_P2P_CLIENT_MODE) + return; + + sap_session = + lim_get_concurrent_session(mac_ctx, session->vdev_id, + session->opmode); + if (!sap_session) + return; + + wlan_set_tpc_update_required_for_sta(sap_session->vdev, false); +} + +void +lim_update_tx_pwr_on_ctry_change_cb(uint8_t vdev_id) +{ + struct mac_context *mac_ctx; + struct pe_session *session; + struct bss_description *bss_desc = NULL; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + pe_err("mac ctx is null"); + return; + } + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + pe_err("Unable to find session"); + return; + } + + if (session->lim_join_req) + bss_desc = &session->lim_join_req->bssDescription; + + lim_set_tpc_power(mac_ctx, session, bss_desc); +} + +struct wlan_channel * +lim_get_connected_chan_for_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE device_mode, + qdf_freq_t start_freq, + qdf_freq_t end_freq) +{ + struct wlan_channel *des_chan; + struct wlan_objmgr_vdev *vdev; + uint8_t vdev_id; + + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) + continue; + + if (vdev->vdev_mlme.vdev_opmode != device_mode) + goto next; + + if ((device_mode == QDF_STA_MODE || + device_mode == QDF_P2P_CLIENT_MODE) && + !wlan_cm_is_vdev_connected(vdev)) + goto next; + + des_chan = vdev->vdev_mlme.des_chan; + if (!des_chan) + goto next; + + if (des_chan->ch_freq < start_freq || + des_chan->ch_freq > end_freq) + goto next; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + return des_chan; +next: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + } + + return NULL; +} + +enum phy_ch_width +lim_convert_vht_chwidth_to_phy_chwidth(uint8_t ch_width, bool is_40) +{ + switch (ch_width) { + case WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ: + return CH_WIDTH_80P80MHZ; + case WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ: + return CH_WIDTH_160MHZ; + case WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ: + return CH_WIDTH_80MHZ; + case WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ: + if (is_40) + return CH_WIDTH_40MHZ; + else + return CH_WIDTH_20MHZ; + default: + pe_debug("Unknown VHT ch width %d", ch_width); + break; + } + return CH_WIDTH_20MHZ; +} + +void +lim_configure_fd_for_existing_6ghz_sap(struct pe_session *session, + bool is_sap_starting) +{ + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + qdf_freq_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *mlme_obj; + uint8_t vdev_num, i; + bool is_legacy_sap_present = false; + + if (session->opmode != QDF_SAP_MODE) + return; + + vdev_num = policy_mgr_get_sap_mode_info(session->mac_ctx->psoc, + freq_list, vdev_id_list); + + for (i = 0; i < vdev_num; i++) { + if (vdev_id_list[i] == session->vdev_id) + continue; + + if (!wlan_reg_is_6ghz_chan_freq(freq_list[i])) { + is_legacy_sap_present = true; + break; + } + } + + if (is_sap_starting) { + /* + * The SAP which is coming up is also in 6 GHz, therefore do not + * modify the FD config for other 6 GHz SAPs. + * vdev start will enable/disable the FD config for this SAP. + */ + if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + wlan_mlme_disable_fd_in_6ghz_band(session->vdev, + is_legacy_sap_present); + return; + } + + /* + * Atleast one legacy SAP is present, disable FD for all the + * existing 6 GHz SAPs. + */ + for (i = 0; i < vdev_num; i++) { + if (!wlan_reg_is_6ghz_chan_freq(freq_list[i])) + continue; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + session->mac_ctx->psoc, + vdev_id_list[i], + WLAN_LEGACY_MAC_ID); + if (!vdev) + continue; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + pe_err("Unable to get mlme obj for vdev %d", + vdev_id_list[i]); + goto rel; + } + + if (!wlan_mlme_is_fd_disabled_in_6ghz_band(vdev)) { + wlan_mlme_disable_fd_in_6ghz_band(vdev, true); + vdev_mgr_configure_fd_for_sap(mlme_obj); + } +rel: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + } + } else { + if (wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + wlan_mlme_disable_fd_in_6ghz_band(session->vdev, false); + return; + } + + if (is_legacy_sap_present) + return; + /* + * If no other legacy SAP is present, and the last legacy SAP + * is going down, re-enable FD for all the 6 GHz SAP. + */ + for (i = 0; i < vdev_num; i++) { + if (!wlan_reg_is_6ghz_chan_freq(freq_list[i])) + continue; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + session->mac_ctx->psoc, + vdev_id_list[i], + WLAN_LEGACY_MAC_ID); + if (!vdev) + continue; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + pe_err("Unable to get mlme obj for vdev %d", + vdev_id_list[i]); + goto rel_vdev; + } + + if (wlan_mlme_is_fd_disabled_in_6ghz_band(vdev)) { + wlan_mlme_disable_fd_in_6ghz_band(vdev, false); + vdev_mgr_configure_fd_for_sap(mlme_obj); + } +rel_vdev: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + } + } +} + +#ifdef WLAN_CHIPSET_STATS +void lim_cp_stats_cstats_log_assoc_resp_evt(struct pe_session *session_entry, + enum cstats_dir dir, + uint16_t status_code, uint16_t aid, + uint8_t *bssid, uint8_t *da, + bool is_ht, bool is_vht, + bool is_he, bool is_eht, + bool is_reassoc) +{ + struct cstats_assoc_resp_mgmt_frm stat = {0}; + + if (is_reassoc) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_MGMT_REASSOC_RESP_EVENT_ID; + } else { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_MGMT_ASSOC_RESP_EVENT_ID; + } + + stat.cmn.hdr.length = sizeof(struct cstats_assoc_resp_mgmt_frm) - + sizeof(struct cstats_hdr); + stat.cmn.vdev_id = session_entry->vdev_id; + stat.cmn.opmode = session_entry->opmode; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.direction = dir; + stat.status_code = status_code; + stat.aid = aid; + + if (is_ht) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT); + + if (is_vht) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT); + + if (is_he) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE); + + if (is_eht) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_EHT); + + CSTATS_MAC_COPY(stat.bssid, bssid); + CSTATS_MAC_COPY(stat.dest_mac, da); + + wlan_cstats_host_stats(sizeof(struct cstats_assoc_resp_mgmt_frm), + &stat); +} + +void +lim_cp_stats_cstats_log_auth_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t algo, + uint16_t seq, uint16_t status) +{ + struct cstats_auth_mgmt_frm stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_AUTH_EVENT_ID; + stat.cmn.hdr.length = + sizeof(struct cstats_auth_mgmt_frm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.direction = dir; + stat.auth_algo = algo; + stat.auth_seq_num = seq; + stat.status = status; + + wlan_cstats_host_stats(sizeof(struct cstats_auth_mgmt_frm), &stat); +} + +void lim_cp_stats_cstats_log_deauth_evt(struct pe_session *pe_session, + enum cstats_dir dir, + uint16_t reasonCode) +{ + struct cstats_deauth_mgmt_frm stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_DEAUTH_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_deauth_mgmt_frm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.reason = reasonCode; + stat.direction = dir; + + wlan_cstats_host_stats(sizeof(struct cstats_deauth_mgmt_frm), &stat); +} + +void lim_cp_stats_cstats_log_disassoc_evt(struct pe_session *pe_session, + enum cstats_dir dir, + uint16_t reasonCode) +{ + struct cstats_disassoc_mgmt_frm stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_MGMT_DISASSOC_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_disassoc_mgmt_frm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.reason = reasonCode; + stat.direction = dir; + + wlan_cstats_host_stats(sizeof(struct cstats_disassoc_mgmt_frm), &stat); +} + +void lim_cp_stats_cstats_log_assoc_req_evt(struct pe_session *pe_session, + enum cstats_dir dir, + uint8_t *bssid, uint8_t *sa, + uint8_t ssid_len, uint8_t *ssid, + bool is_ht, bool is_vht, bool is_he, + bool is_eht, bool is_reassoc) +{ + struct cstats_assoc_req_mgmt_frm stat = {0}; + + if (is_reassoc) { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_MGMT_REASSOC_REQ_EVENT_ID; + } else { + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_MGMT_ASSOC_REQ_EVENT_ID; + } + + stat.cmn.hdr.length = sizeof(struct cstats_assoc_req_mgmt_frm) - + sizeof(struct cstats_hdr); + + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.freq = pe_session->curr_op_freq; + stat.ssid_len = ssid_len; + qdf_mem_copy(stat.ssid, ssid, ssid_len); + + stat.direction = dir; + CSTATS_MAC_COPY(stat.bssid, bssid); + CSTATS_MAC_COPY(stat.sa, sa); + + if (is_ht) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT); + + if (is_vht) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT); + + if (is_he) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE); + + if (is_eht) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_EHT); + + wlan_cstats_host_stats(sizeof(struct cstats_assoc_req_mgmt_frm), &stat); +} + +void lim_cp_stats_cstats_log_disc_req_evt(tDot11fTDLSDisReq *frm, + struct pe_session *pe_session) +{ + struct cstats_tdls_disc_req stat = {0}; + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_STA_TDLS_DISCOVERY_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_disc_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.act_category = frm->Category.category; + stat.act = frm->Action.action; + stat.dt = frm->DialogToken.token; + stat.direction = CSTATS_DIR_TX; + + CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr); + CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid); + CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr); + + wlan_cstats_host_stats(sizeof(struct cstats_tdls_disc_req), &stat); +} + +void lim_cp_stats_cstats_log_disc_resp_evt(tDot11fTDLSDisRsp *frm, + struct pe_session *pe_session) +{ + struct cstats_tdls_disc_resp stat = {0}; + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_STA_TDLS_DISCOVERY_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_disc_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.act_category = frm->Category.category; + stat.act = frm->Action.action; + stat.dt = frm->DialogToken.token; + stat.direction = CSTATS_DIR_TX; + + if (frm->HTCaps.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT); + + if (frm->VHTCaps.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT); + + if (frm->he_cap.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE); + + CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr); + CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid); + CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr); + + wlan_cstats_host_stats(sizeof(struct cstats_tdls_disc_resp), &stat); +} + +void lim_cp_stats_cstats_log_setup_req_evt(tDot11fTDLSSetupReq *frm, + struct pe_session *pe_session) +{ + struct cstats_tdls_setup_req stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_TDLS_SETUP_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.act_category = frm->Category.category; + stat.act = frm->Action.action; + stat.dt = frm->DialogToken.token; + stat.direction = CSTATS_DIR_TX; + + if (frm->HTCaps.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT); + + if (frm->VHTCaps.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT); + + if (frm->he_cap.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE); + + CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr); + CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid); + CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr); + + wlan_cstats_host_stats(sizeof(struct cstats_tdls_setup_req), &stat); +} + +void +lim_cp_stats_cstats_log_setup_resp_evt(tDot11fTDLSSetupRsp *frm, + struct pe_session *pe_session) +{ + struct cstats_tdls_setup_resp stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_TDLS_SETUP_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.act_category = frm->Category.category; + stat.act = frm->Action.action; + stat.dt = frm->DialogToken.token; + stat.direction = CSTATS_DIR_TX; + + if (frm->HTCaps.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT); + + if (frm->VHTCaps.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT); + + if (frm->he_cap.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE); + + stat.status = frm->Status.status; + + CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr); + CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid); + CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr); + + wlan_cstats_host_stats(sizeof(struct cstats_tdls_setup_resp), &stat); +} + +void +lim_cp_stats_cstats_log_setup_confirm_evt(tDot11fTDLSSetupCnf *frm, + struct pe_session *pe_session) +{ + struct cstats_tdls_setup_confirm stat = {0}; + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_STA_TDLS_SETUP_CONFIRM_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_confirm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.act_category = frm->Category.category; + stat.act = frm->Action.action; + stat.dt = frm->DialogToken.token; + stat.direction = CSTATS_DIR_TX; + + if (frm->HTInfo.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HT); + + if (frm->VHTOperation.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_VHT); + + if (frm->he_op.present) + CSTATS_SET_BIT(stat.flags, CSTATS_FLAG_HE); + + stat.status = frm->Status.status; + + CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr); + CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid); + CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr); + + wlan_cstats_host_stats(sizeof(struct cstats_tdls_setup_confirm), &stat); +} + +void +lim_cp_stats_cstats_log_tear_down_evt(tDot11fTDLSTeardown *frm, + struct pe_session *pe_session) +{ + struct cstats_tdls_tear_down stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_STA_TDLS_TEARDOWN_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_setup_confirm) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.act_category = frm->Category.category; + stat.act = frm->Action.action; + stat.direction = CSTATS_DIR_TX; + + stat.reason = frm->Reason.code; + + CSTATS_MAC_COPY(stat.init_sta_addr, frm->LinkIdentifier.InitStaAddr); + CSTATS_MAC_COPY(stat.bssid, frm->LinkIdentifier.bssid); + CSTATS_MAC_COPY(stat.resp_sta_addr, frm->LinkIdentifier.RespStaAddr); + + wlan_cstats_host_stats(sizeof(struct cstats_tdls_tear_down), &stat); +} + +void lim_cp_stats_cstats_log_csa_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t target_freq, + uint8_t target_ch_width, + uint8_t switch_mode) +{ + struct cstats_csa_evt stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_CSA_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_csa_evt) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = pe_session->opmode; + stat.cmn.vdev_id = pe_session->vdev_id; + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.direction = dir; + stat.target_freq = target_freq; + stat.target_ch_width = target_ch_width; + stat.current_freq = pe_session->curr_op_freq; + stat.current_ch_width = pe_session->ch_width; + stat.switch_mode = switch_mode; + + wlan_cstats_host_stats(sizeof(struct cstats_csa_evt), &stat); +} +#endif /* WLAN_CHIPSET_STATS */ + +uint16_t lim_get_tpe_ie_length(enum phy_ch_width chan_width, + tDot11fIEtransmit_power_env *tpe_ie, + uint16_t num_tpe) +{ + uint16_t total_ie_len = 0; + uint16_t idx = 0; + + for (idx = 0; idx < num_tpe; idx++) { + if (!tpe_ie[idx].present) + return total_ie_len; + + /* +2 for including element id and length */ + total_ie_len += 2; + /* +1 for including tx power info */ + total_ie_len += 1; + total_ie_len += tpe_ie[idx].num_tx_power; + + if (!(chan_width == CH_WIDTH_320MHZ && + tpe_ie[idx].max_tx_pwr_interpret)) + continue; + + if (tpe_ie[idx].max_tx_pwr_interpret == LOCAL_EIRP || + tpe_ie[idx].max_tx_pwr_interpret == REGULATORY_CLIENT_EIRP) { + /* Maximum Transmit Power For 320 MHz */ + total_ie_len += 1; + } else if (tpe_ie[idx].max_tx_pwr_interpret == LOCAL_EIRP_PSD || + tpe_ie[idx].max_tx_pwr_interpret == REGULATORY_CLIENT_EIRP_PSD) { + /* Extension Transmit PSD Information */ + total_ie_len += 1; + /* Maximum Transmit PSD power */ + total_ie_len += MAX_TX_PSD_POWER; + } + } + + return total_ie_len; +} + +QDF_STATUS lim_fill_complete_tpe_ie(enum phy_ch_width chan_width, + uint16_t tpe_ie_len, + tDot11fIEtransmit_power_env *tpe_ptr, + uint16_t num_tpe, uint8_t *target) +{ + uint8_t *ie_len = NULL; + uint32_t consumed = 0; + uint32_t total_consumed = 0; + uint8_t tx_pwr_info = 0U; + uint8_t local_psd = 0U; + uint8_t reg_psd = 0U; + uint8_t *on_entry_target = target; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t idx = 0; + + for (idx = 0; idx < num_tpe; idx++) { + if (!tpe_ptr[idx].present) + return QDF_STATUS_E_INVAL; + + consumed = 0; + *target = WLAN_ELEMID_VHT_TX_PWR_ENVLP; + ++target; + ++consumed; + + ie_len = target; + ++target; + ++consumed; + + tx_pwr_info = 0U; + tx_pwr_info |= (tpe_ptr[idx].max_tx_pwr_count << 0); + tx_pwr_info |= (tpe_ptr[idx].max_tx_pwr_interpret << 3); + tx_pwr_info |= (tpe_ptr[idx].max_tx_pwr_category << 6); + *target = tx_pwr_info; + ++consumed; + ++target; + + qdf_mem_copy(target, &tpe_ptr[idx].tx_power, tpe_ptr[idx].num_tx_power); + consumed += tpe_ptr[idx].num_tx_power; + target += tpe_ptr[idx].num_tx_power; + + if (!(chan_width == CH_WIDTH_320MHZ && + tpe_ptr[idx].max_tx_pwr_interpret)) + goto end; + + switch (tpe_ptr[idx].max_tx_pwr_interpret) { + case LOCAL_EIRP: + /* Maximum Local EIRP Transmit Power For 320 MHz */ + *target = tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_eirp.max_tx_power_for_320; + target += 1; + consumed += 1; + break; + case LOCAL_EIRP_PSD: + local_psd = 0U; + local_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_psd.ext_count << 0); + local_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_psd.reserved << 4); + /* Extension Transmit Local PSD Information */ + *target = local_psd; + target += 1; + consumed += 1; + /* Maximum Transmit Local PSD power */ + qdf_mem_copy(target, tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power, MAX_TX_PSD_POWER); + target += MAX_TX_PSD_POWER; + consumed += MAX_TX_PSD_POWER; + break; + case REGULATORY_CLIENT_EIRP: + /* Maximum Regulatory EIRP Transmit Power For 320 MHz */ + *target = tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_eirp.max_tx_power_for_320; + target += 1; + consumed += 1; + break; + case REGULATORY_CLIENT_EIRP_PSD: + reg_psd = 0U; + reg_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_psd.ext_count << 0); + reg_psd |= (tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_psd.reserved << 4); + /* Extension Transmit Regulatory PSD Information */ + *target = reg_psd; + consumed += 1; + target += 1; + /* Maximum Transmit Regulatory PSD power */ + qdf_mem_copy(target, tpe_ptr[idx].ext_max_tx_power.ext_max_tx_power_reg_psd.max_tx_psd_power, MAX_TX_PSD_POWER); + target += MAX_TX_PSD_POWER; + consumed += MAX_TX_PSD_POWER; + break; + } +end: + if (ie_len && consumed >= 2) { + total_consumed += consumed; + /* -2 for element id and length */ + *ie_len = consumed - 2; + } + } + + pe_debug("pack tpe ie %d bytes, expected to copy %d bytes", + total_consumed, tpe_ie_len); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + on_entry_target, total_consumed); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h new file mode 100644 index 0000000000..6cf87946d8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h @@ -0,0 +1,3692 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file lim_utils.h contains the utility definitions + * LIM uses. + * Author: Chandra Modumudi + * Date: 02/13/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __LIM_UTILS_H +#define __LIM_UTILS_H + +#include "sir_api.h" +#include "sir_debug.h" + +#include "lim_types.h" +#include "lim_scan_result_utils.h" +#include "lim_timer_utils.h" +#include "lim_trace.h" +#include "include/wlan_vdev_mlme.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_qct_sys.h" +#include + +#define LIM_QOS_AP_SUPPORTS_UAPSD 0x80 + +#define LIM_IS_QOS_BSS(ie_struct) \ + (ie_struct->WMMParams.present || ie_struct->WMMInfoAp.present) + +#define LIM_IS_UAPSD_BSS(ie_struct) \ + ((ie_struct->WMMParams.present && \ + (ie_struct->WMMParams.qosInfo & LIM_QOS_AP_SUPPORTS_UAPSD)) || \ + (ie_struct->WMMInfoAp.present && ie_struct->WMMInfoAp.uapsd)) + +#define LIM_AID_MASK 0xC000 +#define LIM_SPECTRUM_MANAGEMENT_BIT_MASK 0x0100 +#define LIM_RRM_BIT_MASK 0x1000 +#define LIM_SHORT_PREAMBLE_BIT_MASK 0x0020 +#define LIM_IMMEDIATE_BLOCK_ACK_MASK 0x8000 +#define LIM_MAX_REASSOC_RETRY_LIMIT 2 + +#define VHT_MCS_3x3_MASK 0x30 +#define VHT_MCS_2x2_MASK 0x0C + +#define CENTER_FREQ_DIFF_160MHz 8 +#define CENTER_FREQ_DIFF_80P80MHz 16 + +#define CH_TO_CNTR_FREQ_DIFF_160MHz 14 +#define CH_TO_CNTR_FREQ_DIFF_80MHz 6 + +#define IS_VHT_NSS_1x1(__mcs_map) ((__mcs_map & 0xFFFC) == 0xFFFC) + +#define MGMT_RX_PACKETS_THRESHOLD 200 + +/* 11B AP detection bit position */ +#define OBSS_DETECTION_11B_AP_BIT_MASK 0x0001 +/* 11B STA detection bit position */ +#define OBSS_DETECTION_11B_STA_BIT_MASK 0x0002 +/* 11G AP detection bit position */ +#define OBSS_DETECTION_11G_AP_BIT_MASK 0x0004 +/* 11A AP detection bit position */ +#define OBSS_DETECTION_11A_BIT_MASK 0x0008 +/* HT legacy detection bit position */ +#define OBSS_DETECTION_HT_LEGACY_BIT_MASK 0x0010 +/* HT mixed detection bit position */ +#define OBSS_DETECTION_HT_MIXED_BIT_MASK 0x0020 +/* HT 20mhz detection bit position */ +#define OBSS_DETECTION_HT_20MHZ_BIT_MASK 0x0040 + +/** + * OBSS detection period in ms, used by firmware to decide + * absent detection and also gap between same detection ind. + */ +#define OBSS_DETECTION_PERIOD_MS 4000 + +/* To check if 11B AP detection bit set */ +#define OBSS_DETECTION_IS_11B_AP(_m) ((_m) & OBSS_DETECTION_11B_AP_BIT_MASK) +/* To check if 11B STA detection bit set */ +#define OBSS_DETECTION_IS_11B_STA(_m) ((_m) & OBSS_DETECTION_11B_STA_BIT_MASK) +/* To check if 11G AP detection bit set */ +#define OBSS_DETECTION_IS_11G_AP(_m) ((_m) & OBSS_DETECTION_11G_AP_BIT_MASK) +/* To check if 11A AP detection bit set */ +#define OBSS_DETECTION_IS_11A(_m) ((_m) & OBSS_DETECTION_11A_BIT_MASK) +/* To check if HT legacy detection bit set */ +#define OBSS_DETECTION_IS_HT_LEGACY(_m) \ + ((_m) & OBSS_DETECTION_HT_LEGACY_BIT_MASK) +/* To check if HT mixed detection bit set */ +#define OBSS_DETECTION_IS_HT_MIXED(_m) ((_m) & OBSS_DETECTION_HT_MIXED_BIT_MASK) +/* To check if HT 20mhz detection bit set */ +#define OBSS_DETECTION_IS_HT_20MHZ(_m) ((_m) & OBSS_DETECTION_HT_20MHZ_BIT_MASK) + +#define MAX_WAIT_FOR_BCN_TX_COMPLETE_FOR_LL_SAP 500 +#define MAX_WAIT_FOR_BCN_TX_COMPLETE 4000 + +#define MAX_WAKELOCK_FOR_CSA 5000 +#define MAX_WAIT_FOR_CH_WIDTH_UPDATE_COMPLETE 200 + +#ifdef WLAN_FEATURE_11BE +#define MAX_NUM_PWR_LEVELS 16 +#else +#define MAX_NUM_PWR_LEVELS 8 +#endif + +/* SR is disabled if NON_SRG is disallowed and SRG INFO is not present */ +#define SR_DISABLE NON_SRG_PD_SR_DISALLOWED & (~SRG_INFO_PRESENT & 0x0F) + +typedef union uPmfSaQueryTimerId { + struct { + uint8_t sessionId; + uint16_t peerIdx; + } fields; + uint32_t value; +} tPmfSaQueryTimerId, *tpPmfSaQueryTimerId; + +typedef struct last_processed_frame { + tSirMacAddr sa; + uint16_t seq_num; +} last_processed_msg; + +/* LIM utility functions */ +bool lim_is_valid_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo); +void lim_update_last_processed_frame(last_processed_msg *last_processed_frm, + uint8_t *pRxPacketInfo); + +char *lim_mlm_state_str(tLimMlmStates state); +char *lim_sme_state_str(tLimSmeStates state); +char *lim_msg_str(uint32_t msgType); +char *lim_result_code_str(tSirResultCodes resultCode); +char *lim_dot11_mode_str(struct mac_context *mac, uint8_t dot11Mode); +void lim_print_mlm_state(struct mac_context *mac, uint16_t logLevel, + tLimMlmStates state); +void lim_print_sme_state(struct mac_context *mac, uint16_t logLevel, + tLimSmeStates state); +void lim_print_msg_name(struct mac_context *mac, uint16_t logLevel, uint32_t msgType); + +QDF_STATUS lim_send_set_max_tx_power_req(struct mac_context *mac, + int8_t txPower, + struct pe_session *pe_session); + +/** + * lim_get_num_pwr_levels() - Utility to get number of tx power levels + * @is_psd: PSD power check + * @ch_width: BSS channel bandwidth + * + * This function is used to get the number of tx power levels based on + * channel bandwidth and psd power. + * + * Return: number of tx power levels + */ +uint32_t lim_get_num_pwr_levels(bool is_psd, + enum phy_ch_width ch_width); + +/** + * lim_get_max_tx_power() - Utility to get maximum tx power + * @mac: mac handle + * @mlme_obj: pointer to struct containing list of tx powers + * + * This function is used to get the maximum possible tx power from the list + * of tx powers mentioned in @attr. + * + * Return: Max tx power + */ +uint8_t lim_get_max_tx_power(struct mac_context *mac, + struct vdev_mlme_obj *mlme_obj); +/** + * lim_calculate_tpc() - Utility to get maximum tx power + * @mac: mac handle + * @session: PE Session Entry + * + * This function is used to get the maximum possible tx power from the list + * of tx powers mentioned in @attr. + * + * Return: None + */ +void lim_calculate_tpc(struct mac_context *mac, + struct pe_session *session); + +/* AID pool management functions */ + +/** + * lim_init_peer_idxpool() -- initializes peer index pool + * @mac: mac context + * @pe_session: session entry + * + * This function is called while starting a BSS at AP + * to initialize AID pool. + * + * Return: None + */ +void lim_init_peer_idxpool(struct mac_context *, struct pe_session *); +uint16_t lim_assign_peer_idx(struct mac_context *, struct pe_session *); + +/** + * lim_create_peer_idxpool() - api to create aid pool + * @pe_session: pe session + * @idx_pool_size: aid pool size + * + * Return: true if pool is created successfully + */ +bool lim_create_peer_idxpool(struct pe_session *pe_session, + uint8_t idx_pool_size); + +/** + * lim_free_peer_idxpool() - api to free aid pool + * @pe_session: pe session + * + * Return: Void + */ +void lim_free_peer_idxpool(struct pe_session *pe_session); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_assign_mlo_conn_idx() - api to assign mlo peer station index with given + * partner peer station index + * @mac: mac context + * @pe_session: session entry + * @partner_peer_idx: partner peer station index + * + * Return: peer station index + */ +uint16_t lim_assign_mlo_conn_idx(struct mac_context *mac, + struct pe_session *pe_session, + uint16_t partner_peer_idx); + +/** + * lim_release_mlo_conn_idx() - api to release mlo peer AID + * @mac: mac context + * @peer_idx: given aid + * @pe_session: session entry + * @free_aid: trigger mlo mgr to free AID or not. It only can be + * true before mlo peer is created. Once mlo peer is + * created, AID is freed in mlo peer context. + * + * Return: Void + */ +void +lim_release_mlo_conn_idx(struct mac_context *mac, uint16_t peer_idx, + struct pe_session *pe_session, bool free_aid); + +/** + * lim_update_sta_mlo_info() - update sta mlo information + * @pe_session: session entry + * @add_sta_params: pointer to tpAddStaParams + * @sta_ds: pointer tpDphHashNode + * + * Return: Void + */ +void lim_update_sta_mlo_info(struct pe_session *pe_session, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds); + +void lim_set_mlo_caps(struct mac_context *mac, struct pe_session *session, + uint8_t *ie_start, uint32_t num_bytes); + +QDF_STATUS lim_send_mlo_caps_ie(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + enum QDF_OPMODE device_mode, + uint8_t vdev_id); + +/** + * lim_strip_mlo_ie() - Removes the MLO IE data from additional IE data + * + * @mac_ctx: global MAC context + * @add_ie: Additional IE buffer + * @add_ielen: Pointer to length of additional IE + * + * Return: Void + */ +void lim_strip_mlo_ie(struct mac_context *mac_ctx, + uint8_t *add_ie, uint16_t *add_ielen); + +/** + * lim_set_emlsr_caps() - This API will set EMLSR caps in vdev obj if ELMSR is + * supported. + * @mac: mac context + * @pe_session: session entry + * + * Return: Void + */ +void lim_set_emlsr_caps(struct mac_context *mac_ctx, + struct pe_session *session); +#else +static inline uint16_t lim_assign_mlo_conn_idx(struct mac_context *mac, + struct pe_session *pe_session, + uint16_t partner_peer_idx) +{ + return 0; +} + +static inline void +lim_release_mlo_conn_idx(struct mac_context *mac, uint16_t peer_idx, + struct pe_session *pe_session, bool free_aid) +{ +} + +static inline void lim_update_sta_mlo_info(struct pe_session *session, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds) +{ +} + +static inline +void lim_set_mlo_caps(struct mac_context *mac, struct pe_session *session, + uint8_t *ie_start, uint32_t num_bytes) +{ +} + +static inline +void lim_strip_mlo_ie(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen) +{ +} + +static inline +QDF_STATUS lim_send_mlo_caps_ie(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void lim_set_emlsr_caps(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} +#endif + +void lim_enable_overlap11g_protection(struct mac_context *mac, + tpUpdateBeaconParams pBeaconParams, + tpSirMacMgmtHdr pMh, + struct pe_session *pe_session); +void lim_update_overlap_sta_param(struct mac_context *mac, tSirMacAddr bssId, + tpLimProtStaParams pStaParams); +void lim_update_short_preamble(struct mac_context *mac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); +void lim_update_short_slot_time(struct mac_context *mac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); + +/* + * lim_send_sme_mgmt_frame_ind() - Function to send mgmt frame ind to HDD + * @mac_ctx: Pointer to Global MAC structure + * @frame_type: Type of mgmt frame + * @frame: Frame pointer + * @frame_len: Length og mgmt frame + * @vdev_id: session id + * @rx_freq: Frequency on which packet is received + * @rx_rssi: rssi value + * @rx_flags: RXMGMT flags to be set for the frame. Defined in enum rxmgmt_flags + * + * Indicate the Mgmt Frame received to SME to HDD callback + * handle Probe_req/Action frame currently + * + * Return: None +*/ +void lim_send_sme_mgmt_frame_ind(struct mac_context *mac_ctx, uint8_t frame_type, + uint8_t *frame, uint32_t frame_len, + uint16_t vdev_id, uint32_t rx_freq, + int8_t rx_rssi, enum rxmgmt_flags rx_flags); + +/* + * lim_deactivate_timers() - Function to deactivate lim timers + * @mac_ctx: Pointer to global mac structure + * + * This function is used to deactivate lim timers + * + * Return: None + */ +void lim_deactivate_timers(struct mac_context *mac_ctx); + +/* + * lim_deactivate_timers_for_vdev() - Deactivate lim connection timers + * @mac_ctx: Pointer to global mac structure + * @vdev_id: vdev id + * + * This function is used to trigger timeout of lim connection timers to abort + * connect request. + * + * Return: None + */ +void lim_deactivate_timers_for_vdev(struct mac_context *mac_ctx, + uint8_t vdev_id); + +/* + * The below 'product' check tobe removed if 'Association' is + * allowed in IBSS. + */ +void lim_release_peer_idx(struct mac_context *, uint16_t, struct pe_session *); + +void lim_decide_ap_protection(struct mac_context *mac, tSirMacAddr peerMacAddr, + tpUpdateBeaconParams pBeaconParams, struct pe_session *); +void lim_decide_ap_protection_on_delete(struct mac_context *mac, + tpDphHashNode sta, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); + +QDF_STATUS lim_update_11a_protection(struct mac_context *mac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *); +QDF_STATUS lim_enable11g_protection(struct mac_context *mac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); +QDF_STATUS lim_enable_ht_protection_from11g(struct mac_context *mac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + struct pe_session *pe_session); +QDF_STATUS lim_enable_ht20_protection(struct mac_context *mac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); +QDF_STATUS lim_enable_ht_non_gf_protection(struct mac_context *mac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, struct pe_session *); +QDF_STATUS lim_enable_ht_rifs_protection(struct mac_context *mac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, + struct pe_session *pe_session); +QDF_STATUS lim_enable_ht_lsig_txop_protection(struct mac_context *mac, + uint8_t enable, + uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, struct pe_session *); +QDF_STATUS lim_enable_short_preamble(struct mac_context *mac, + uint8_t enable, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); +QDF_STATUS lim_enable_ht_obss_protection(struct mac_context *mac, + uint8_t enable, uint8_t overlap, + tpUpdateBeaconParams + pBeaconParams, struct pe_session *); +void lim_decide_sta_protection(struct mac_context *mac, + tpSchBeaconStruct pBeaconStruct, + tpUpdateBeaconParams pBeaconParams, + struct pe_session *pe_session); +void lim_decide_sta_protection_on_assoc(struct mac_context *mac, + tpSchBeaconStruct pBeaconStruct, + struct pe_session *pe_session); + +/** + * lim_get_cb_mode_for_freq() - Get cb mode depending on the freq + * @mac: pointer to Global MAC structure + * @pe_session: pe session + * @chan_freq: Freq to get cb mode for + * + * Return: cb mode allowed for the freq + */ +uint8_t lim_get_cb_mode_for_freq(struct mac_context *mac, + struct pe_session *session, + qdf_freq_t chan_freq); + +/** + * lim_update_sta_run_time_ht_switch_chnl_params() - Process change in HT + * bandwidth + * @mac: pointer to Global MAC structure + * @pHTInfo: ht info IE + * @pe_session: pe session + * + * Return: none + */ +void lim_update_sta_run_time_ht_switch_chnl_params(struct mac_context *mac, + tDot11fIEHTInfo *pHTInfo, + struct pe_session *pe_session); + +/* Deferred Message Queue read/write */ +uint8_t lim_write_deferred_msg_q(struct mac_context *mac, + struct scheduler_msg *limMsg); +struct scheduler_msg *lim_read_deferred_msg_q(struct mac_context *mac); +void lim_handle_defer_msg_error(struct mac_context *mac, + struct scheduler_msg *pLimMsg); + +/* Deferred Message Queue Reset */ +void lim_reset_deferred_msg_q(struct mac_context *mac); + +static inline void lim_sys_process_mmh_msg_api(struct mac_context *mac, + struct scheduler_msg *msg) +{ + sys_process_mmh_msg(mac, msg); +} + +void lim_handle_update_olbc_cache(struct mac_context *mac); + +uint8_t lim_is_null_ssid(tSirMacSSid *pSsid); + +/* 11h Support */ +void lim_stop_tx_and_switch_channel(struct mac_context *mac, uint8_t sessionId); + +/** + * lim_process_channel_switch() - Process channel switch + * @mac: pointer to Global MAC structure + * @vdev_id: Vdev on which CSA is happening + * + * Return: none + */ +void lim_process_channel_switch(struct mac_context *mac, uint8_t vdev_id); + +/** + * lim_switch_primary_channel() - switch primary channel of session + * @mac: Global MAC structure + * @new_channel_freq: new chnannel freq in Mhz + * @pe_session: pe session context + * + * This function changes the current operating channel frequency. + * + * return qdf_status + */ +QDF_STATUS lim_switch_primary_channel(struct mac_context *mac, + uint32_t new_channel_freq, + struct pe_session *pe_session); + +/** + * lim_switch_primary_secondary_channel() - switch primary and secondary + * channel of session + * @mac: Global MAC structure + * @pe_session: session context + * + * This function changes the primary and secondary channel. + * If 11h is enabled and user provides a "new channel freq" + * that is different from the current operating channel, + * then we must set this new channel in session context and + * assign notify LIM of such change. + * + * @return qdf_status + */ +QDF_STATUS lim_switch_primary_secondary_channel(struct mac_context *mac, + struct pe_session *pe_session); + +void lim_update_sta_run_time_ht_capability(struct mac_context *mac, + tDot11fIEHTCaps *pHTCaps); +void lim_update_sta_run_time_ht_info(struct mac_context *mac, + tDot11fIEHTInfo *pRcvdHTInfo, + struct pe_session *pe_session); + +/** + * lim_is_channel_valid_for_channel_switch - check channel valid for switching + * @mac: Global mac context + * @channel_freq: channel freq (MHz) + * + * This function checks if the channel to which AP is expecting us to switch, + * is a valid channel for us. + * + * Return bool, true if channel is valid + */ +bool lim_is_channel_valid_for_channel_switch(struct mac_context *mac, + uint32_t channel_freq); + +QDF_STATUS lim_restore_pre_channel_switch_state(struct mac_context *mac, + struct pe_session *pe_session); + +void lim_prepare_for11h_channel_switch(struct mac_context *mac, + struct pe_session *pe_session); +void lim_switch_channel_cback(struct mac_context *mac, QDF_STATUS status, + uint32_t *data, struct pe_session *pe_session); + +/** + * lim_assoc_rej_get_remaining_delta() - Get remaining time delta for + * the rssi based disallowed list entry + * @node: rssi based disallowed list entry + * + * Return: remaining delta, can be -ve if time has already expired. + */ +int +lim_assoc_rej_get_remaining_delta(struct sir_rssi_disallow_lst *node); + +/** + * lim_rem_denylist_entry_with_lowest_delta() - Remove the entry with lowest + * time delta + * @list: rssi based rejected BSSID list + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_rem_denylist_entry_with_lowest_delta(qdf_list_t *list); + +static inline enum reg_wifi_band lim_get_rf_band(uint32_t chan_freq) +{ + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) + return REG_BAND_6G; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq)) + return REG_BAND_5G; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) + return REG_BAND_2G; + + return REG_BAND_UNKNOWN; +} + +static inline QDF_STATUS +lim_get_mgmt_staid(struct mac_context *mac, uint16_t *staid, + struct pe_session *pe_session) +{ + if (LIM_IS_AP_ROLE(pe_session)) + *staid = 1; + else if (LIM_IS_STA_ROLE(pe_session)) + *staid = 0; + else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +static inline int lim_select_cb_mode(tDphHashNode *sta, + struct pe_session *pe_session, uint8_t channel, + uint8_t chan_bw) +{ + if (sta->mlmStaContext.vhtCapability && chan_bw) { + if (channel == 36 || channel == 52 || channel == 100 || + channel == 116 || channel == 149) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1; + } else if (channel == 40 || channel == 56 || channel == 104 || + channel == 120 || channel == 153) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW - 1; + } else if (channel == 44 || channel == 60 || channel == 108 || + channel == 124 || channel == 157) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH - 1; + } else if (channel == 48 || channel == 64 || channel == 112 || + channel == 128 || channel == 161) { + return PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH - 1; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } else if (sta->mlmStaContext.htCapability) { + if (channel == 40 || channel == 48 || channel == 56 || + channel == 64 || channel == 104 || channel == 112 || + channel == 120 || channel == 128 || channel == 136 || + channel == 144 || channel == 153 || channel == 161) { + return PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + } else if (channel == 36 || channel == 44 || channel == 52 || + channel == 60 || channel == 100 || + channel == 108 || channel == 116 || + channel == 124 || channel == 132 || + channel == 140 || channel == 149 || + channel == 157) { + return PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + } else if (channel == 165) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + } + return PHY_SINGLE_CHANNEL_CENTERED; +} + +/* ANI peer station count management and associated actions */ +void lim_util_count_sta_add(struct mac_context *mac, tpDphHashNode pSta, + struct pe_session *pe_session); +void lim_util_count_sta_del(struct mac_context *mac, tpDphHashNode pSta, + struct pe_session *pe_session); + +uint8_t lim_get_ht_capability(struct mac_context *, uint32_t, struct pe_session *); +QDF_STATUS lim_tx_complete(void *context, qdf_nbuf_t buf, bool free); + +QDF_STATUS lim_validate_delts_req(struct mac_context *mac, + tpSirDeltsReq pDeltsReq, + tSirMacAddr peerMacAddr, + struct pe_session *pe_session); + +void lim_pkt_free(struct mac_context *mac, + eFrameType frmType, uint8_t *pBD, void *body); + +void lim_get_b_dfrom_rx_packet(struct mac_context *mac, void *body, uint32_t **pBD); + +/** + * utils_power_xy() - calc result of base raised to power + * @base: Base value + * @power: Base raised to this Power value + * + * Given a base(X) and power(Y), this API will return + * the result of base raised to power - (X ^ Y) + * + * Return: Result of X^Y + * + */ +static inline uint32_t utils_power_xy(uint16_t base, uint16_t power) +{ + uint32_t result = 1, i; + + for (i = 0; i < power; i++) + result *= base; + + return result; +} + +QDF_STATUS lim_post_sm_state_update(struct mac_context *mac, + tSirMacHTMIMOPowerSaveState MIMOPSState, + uint8_t *pPeerStaMac, uint8_t sessionId); + +void lim_delete_sta_context(struct mac_context *mac, struct scheduler_msg *limMsg); +void lim_delete_dialogue_token_list(struct mac_context *mac); + +/** + * lim_get_channel_from_beacon() - extract channel number + * from beacon and convert to channel frequency + * @mac: Pointer to Global MAC structure + * @pBeacon: Pointer to beacon or probe rsp + * + * Return: channel frequency + */ +uint32_t lim_get_channel_from_beacon(struct mac_context *mac, + tpSchBeaconStruct pBeacon); + +/** + * lim_get_nw_type() - Get type of the network from + * data packet or beacon + * @mac: Pointer to Global MAC structure + * @chan_freq: Channel frequency + * @type: Type of packet + * @pBeacon: Pointer to beacon or probe response + * + * Return: Network type a/b/g + */ +tSirNwType lim_get_nw_type(struct mac_context *mac, uint32_t chan_freq, + uint32_t type, tpSchBeaconStruct pBeacon); + +void lim_set_tspec_uapsd_mask_per_session(struct mac_context *mac, + struct pe_session *pe_session, + struct mac_ts_info *pTsInfo, uint32_t action); + +void lim_handle_heart_beat_timeout_for_session(struct mac_context *mac, + struct pe_session *pe_session); + +/** + * lim_process_add_sta_rsp() - process WDA_ADD_STA_RSP from WMA + * @mac_ctx: Pointer to Global MAC structure + * @msg: msg from WMA + * + * Return: void + */ +void lim_process_add_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *msg); + +void lim_update_beacon(struct mac_context *mac); + +void lim_process_ap_mlm_add_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session); + +/** + * lim_process_ap_mlm_del_bss_rsp() - handle del bss response of AP + * @mac: Pointer to Global MAC structure + * @vdev_stop_rsp: pointer to vdev stop response + * @pe_session: pointer to pe_session + * + * Return: none + */ +void lim_process_ap_mlm_del_bss_rsp(struct mac_context *mac, + struct del_bss_resp *vdev_stop_rsp, + struct pe_session *pe_session); + +void lim_process_ap_mlm_del_sta_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ, + struct pe_session *pe_session); + +/** + * ch_width_in_mhz() - API to get channel space in MHz + * + * For CH_WIDTH_80P80MHZ, the channel space is max channel space of one + * segment - 80MHz. + * + */ +static inline uint16_t ch_width_in_mhz(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_40MHZ: + return 40; + case CH_WIDTH_80MHZ: + return 80; + case CH_WIDTH_160MHZ: + return 160; + case CH_WIDTH_80P80MHZ: + return 80; + case CH_WIDTH_5MHZ: + return 5; + case CH_WIDTH_10MHZ: + return 10; + case CH_WIDTH_320MHZ: + return 320; + default: + return 20; + } +} + +struct pe_session *lim_is_ap_session_active(struct mac_context *mac); + +#define limGetWscIEPtr(mac, ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_WSC_OUI, \ + SIR_MAC_WSC_OUI_SIZE, ie, ie_len) + +#define limGetP2pIEPtr(mac, ie, ie_len) \ + wlan_get_vendor_ie_ptr_from_oui(SIR_MAC_P2P_OUI, \ + SIR_MAC_P2P_OUI_SIZE, ie, ie_len) + +uint8_t lim_get_noa_attr_stream(struct mac_context *mac, uint8_t *pNoaStream, + struct pe_session *pe_session); + +uint8_t lim_build_p2p_ie(struct mac_context *mac, uint8_t *ie, uint8_t *data, + uint8_t ie_len); + +bool lim_isconnected_on_dfs_freq(struct mac_context *mac_ctx, + qdf_freq_t curr_chan_freq); + +uint32_t lim_get_max_rate_flags(struct mac_context *mac_ctx, + tpDphHashNode sta_ds); + +bool lim_check_vht_op_mode_change(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t chanWidth, + uint8_t *peerMac); +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +bool lim_send_he_ie_update(struct mac_context *mac_ctx, struct pe_session *pe_session); +#endif +bool lim_set_nss_change(struct mac_context *mac, struct pe_session *pe_session, + uint8_t rxNss, uint8_t *peerMac); +bool lim_check_membership_user_position(struct mac_context *mac, + struct pe_session *pe_session, + uint32_t membership, uint32_t userPosition); + +/** + * enum ack_status - Indicate TX status of ASSOC/AUTH + * @ACKED : Ack is received. + * @NOT_ACKED : No Ack received. + * @SENT_FAIL : Failure while sending. + * + * Indicate if driver is waiting for ACK status of assoc/auth or ACK received + * for ASSOC/AUTH OR NO ACK is received for the assoc/auth sent or assoc/auth + * sent failed. + */ +enum assoc_ack_status { + ACKED, + NOT_ACKED, + SENT_FAIL, +}; + +typedef enum { + WLAN_PE_DIAG_SCAN_REQ_EVENT = 0, + WLAN_PE_DIAG_SCAN_ABORT_IND_EVENT, + WLAN_PE_DIAG_SCAN_RSP_EVENT, + WLAN_PE_DIAG_JOIN_REQ_EVENT, + WLAN_PE_DIAG_JOIN_RSP_EVENT, + WLAN_PE_DIAG_SETCONTEXT_REQ_EVENT, + WLAN_PE_DIAG_SETCONTEXT_RSP_EVENT, + WLAN_PE_DIAG_REASSOC_REQ_EVENT, + WLAN_PE_DIAG_REASSOC_RSP_EVENT, + WLAN_PE_DIAG_AUTH_REQ_EVENT, + WLAN_PE_DIAG_AUTH_RSP_EVENT = 10, + WLAN_PE_DIAG_DISASSOC_REQ_EVENT, + WLAN_PE_DIAG_DISASSOC_RSP_EVENT, + WLAN_PE_DIAG_DISASSOC_IND_EVENT, + WLAN_PE_DIAG_DISASSOC_CNF_EVENT, + WLAN_PE_DIAG_DEAUTH_REQ_EVENT, + WLAN_PE_DIAG_DEAUTH_RSP_EVENT, + WLAN_PE_DIAG_DEAUTH_IND_EVENT, + WLAN_PE_DIAG_START_BSS_REQ_EVENT, + WLAN_PE_DIAG_START_BSS_RSP_EVENT, + WLAN_PE_DIAG_AUTH_IND_EVENT = 20, + WLAN_PE_DIAG_ASSOC_IND_EVENT, + WLAN_PE_DIAG_ASSOC_CNF_EVENT, + WLAN_PE_DIAG_REASSOC_IND_EVENT, + WLAN_PE_DIAG_SWITCH_CHL_IND_EVENT, + WLAN_PE_DIAG_SWITCH_CHL_RSP_EVENT, + WLAN_PE_DIAG_STOP_BSS_REQ_EVENT, + WLAN_PE_DIAG_STOP_BSS_RSP_EVENT, + WLAN_PE_DIAG_DEAUTH_CNF_EVENT, + WLAN_PE_DIAG_ADDTS_REQ_EVENT, + WLAN_PE_DIAG_ADDTS_RSP_EVENT = 30, + WLAN_PE_DIAG_DELTS_REQ_EVENT, + WLAN_PE_DIAG_DELTS_RSP_EVENT, + WLAN_PE_DIAG_DELTS_IND_EVENT, + WLAN_PE_DIAG_ENTER_BMPS_REQ_EVENT, + WLAN_PE_DIAG_ENTER_BMPS_RSP_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_REQ_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_RSP_EVENT, + WLAN_PE_DIAG_EXIT_BMPS_IND_EVENT, + WLAN_PE_DIAG_ENTER_IMPS_REQ_EVENT, + WLAN_PE_DIAG_ENTER_IMPS_RSP_EVENT = 40, + WLAN_PE_DIAG_EXIT_IMPS_REQ_EVENT, + WLAN_PE_DIAG_EXIT_IMPS_RSP_EVENT, + WLAN_PE_DIAG_ENTER_UAPSD_REQ_EVENT, + WLAN_PE_DIAG_ENTER_UAPSD_RSP_EVENT, + WLAN_PE_DIAG_EXIT_UAPSD_REQ_EVENT, + WLAN_PE_DIAG_EXIT_UAPSD_RSP_EVENT, + WLAN_PE_DIAG_WOWL_ADD_BCAST_PTRN_EVENT, + WLAN_PE_DIAG_WOWL_DEL_BCAST_PTRN_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_REQ_EVENT, + WLAN_PE_DIAG_ENTER_WOWL_RSP_EVENT = 50, + WLAN_PE_DIAG_EXIT_WOWL_REQ_EVENT, + WLAN_PE_DIAG_EXIT_WOWL_RSP_EVENT, + WLAN_PE_DIAG_HAL_ADDBA_REQ_EVENT, + WLAN_PE_DIAG_HAL_ADDBA_RSP_EVENT, + WLAN_PE_DIAG_HAL_DELBA_IND_EVENT, + WLAN_PE_DIAG_HB_FAILURE_TIMEOUT, + WLAN_PE_DIAG_PRE_AUTH_REQ_EVENT, + WLAN_PE_DIAG_PRE_AUTH_RSP_EVENT, + WLAN_PE_DIAG_PREAUTH_DONE, + WLAN_PE_DIAG_REASSOCIATING = 60, + WLAN_PE_DIAG_CONNECTED, + WLAN_PE_DIAG_ASSOC_REQ_EVENT, + WLAN_PE_DIAG_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_AUTH_START_EVENT, + WLAN_PE_DIAG_ASSOC_START_EVENT, + WLAN_PE_DIAG_REASSOC_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_START_EVENT, + WLAN_PE_DIAG_ROAM_AUTH_COMP_EVENT, + WLAN_PE_DIAG_ROAM_ASSOC_START_EVENT = 70, + WLAN_PE_DIAG_ROAM_ASSOC_COMP_EVENT, + WLAN_PE_DIAG_SCAN_COMPLETE_EVENT, + WLAN_PE_DIAG_SCAN_RESULT_FOUND_EVENT, + WLAN_PE_DIAG_ASSOC_TIMEOUT, + WLAN_PE_DIAG_AUTH_TIMEOUT, + WLAN_PE_DIAG_DEAUTH_FRAME_EVENT, + WLAN_PE_DIAG_DISASSOC_FRAME_EVENT, + WLAN_PE_DIAG_AUTH_ACK_EVENT, + WLAN_PE_DIAG_ASSOC_ACK_EVENT, + WLAN_PE_DIAG_AUTH_ALGO_NUM, +} WLAN_PE_DIAG_EVENT_TYPE; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void lim_diag_event_report(struct mac_context *mac, uint16_t eventType, + struct pe_session *pe_session, uint16_t status, + uint16_t reasonCode); +/** + * lim_diag_mgmt_tx_event_report() - to log TX event to external application + * @mac_ctx: mac context + * @mgmt_hdr: 802.11 mgmt header of given frame + * @session: PE session for given frame + * @result_code: result code of to be populated in TX frame + * @reason_code: reason code if TX OTA status + * + * Anytime driver sends some mgmt frame down to firmware for OTA delivery, + * log mgmt frame through DIAG utility. Don't log frames which come too + * excessively. + * + * Return: void + */ +void lim_diag_mgmt_tx_event_report(struct mac_context *mac_ctx, void *mgmt_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code); +/** + * lim_diag_mgmt_rx_event_report() - to log RX event to external application + * @mac_ctx: mac context + * @mgmt_hdr: 802.11 mgmt header of given frame + * @session: PE session for given frame + * @result_code: result code given in RX frame + * @reason_code: reason code for RX OTA status + * + * Anytime driver receives some mgmt frame from firmware OTA, + * log mgmt frame through DIAG utility. Don't log frames which come too + * excessively. + * + * Return: void + */ +void lim_diag_mgmt_rx_event_report(struct mac_context *mac_ctx, void *mgmt_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code); +#else +static inline void lim_diag_event_report(struct mac_context *mac, uint16_t + eventType, struct pe_session *pe_session, uint16_t status, + uint16_t reasonCode) {} +static inline +void lim_diag_mgmt_tx_event_report(struct mac_context *mac_ctx, void *mgmt_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code) {} +static inline +void lim_diag_mgmt_rx_event_report(struct mac_context *mac_ctx, void *mgmt_hdr, + struct pe_session *session, uint16_t result_code, + uint16_t reason_code) {} +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +void pe_set_resume_channel(struct mac_context *mac, uint16_t channel, + ePhyChanBondState cbState); + +void lim_get_short_slot_from_phy_mode(struct mac_context *mac, + struct pe_session *pe_session, + uint32_t phyMode, uint8_t *pShortSlotEnable); + +void lim_clean_up_disassoc_deauth_req(struct mac_context *mac, uint8_t *staMac, + bool cleanRxPath); + +bool lim_check_disassoc_deauth_ack_pending(struct mac_context *mac, + uint8_t *staMac); + +void lim_pmf_sa_query_timer_handler(void *pMacGlobal, uint32_t param); +void lim_pmf_comeback_timer_callback(void *context); +void lim_set_protected_bit(struct mac_context *mac, + struct pe_session *pe_session, + tSirMacAddr peer, tpSirMacMgmtHdr pMacHdr); + +void lim_set_ht_caps(struct mac_context *p_mac, uint8_t *p_ie_start, + uint32_t num_bytes); + +void lim_set_vht_caps(struct mac_context *p_mac, uint8_t *p_ie_start, + uint32_t num_bytes); +bool lim_validate_received_frame_a1_addr(struct mac_context *mac_ctx, + tSirMacAddr a1, struct pe_session *session); +void lim_set_stads_rtt_cap(tpDphHashNode sta_ds, struct s_ext_cap *ext_cap, + struct mac_context *mac_ctx); + +void lim_check_and_reset_protection_params(struct mac_context *mac_ctx); + +QDF_STATUS lim_send_ext_cap_ie(struct mac_context *mac_ctx, uint32_t session_id, + tDot11fIEExtCap *extracted_extcap, bool merge); + +/** + * lim_send_ies_per_band() - gets ht and vht capability and send to firmware via + * wma + * @mac_ctx: global mac context + * @vdev_id: vdev for which IE is targeted + * @dot11_mode: vdev dot11 mode + * @device_mode: device mode + * + * This function gets ht and vht capability and send to firmware via wma + * + * Return: status of operation + */ +QDF_STATUS lim_send_ies_per_band(struct mac_context *mac_ctx, + uint8_t vdev_id, + enum csr_cfgdot11mode dot11_mode, + enum QDF_OPMODE device_mode); + +/** + * lim_update_connect_rsn_ie() - Update the connection RSN IE + * @mac_ctx: MAC context + * @session: PE session + * @rsn_ie_buf: RSN IE buffer + * @pmksa: PMKSA entry for the connecting AP + * + * Return: None + */ +void +lim_update_connect_rsn_ie(struct mac_context *mac_ctx, + struct pe_session *session, uint8_t *rsn_ie_buf, + struct wlan_crypto_pmksa *pmksa); + +/** + * lim_send_action_frm_tb_ppdu_cfg() - sets action frame in TB PPDU cfg to FW + * @mac_ctx: global MAC context + * @vdev_id: vdev id + * @cfg: config setting + * + * Preapres the vendor action frame and send action frame in HE TB PPDU + * configuration to FW. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_action_frm_tb_ppdu_cfg(struct mac_context *mac_ctx, + uint32_t vdev_id, + uint8_t cfg); + +void lim_update_extcap_struct(struct mac_context *mac_ctx, uint8_t *buf, + tDot11fIEExtCap *ext_cap); +QDF_STATUS lim_strip_extcap_update_struct(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, tDot11fIEExtCap *dst); +void lim_merge_extcap_struct(tDot11fIEExtCap *dst, tDot11fIEExtCap *src, + bool add); + +/** + * lim_strip_he_ies_from_add_ies() - This function strip HE IE from add_ie + * @mac_ctx: pointer to mac context + * @pe_session: pointer to PE session + * + * This API is to strip HE IE from add_ie + * + * Return: none + */ +void lim_strip_he_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session); + +void lim_strip_eht_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_strip_wapi_ies_from_add_ies() - This function strip WAPI IE from add_ie + * @mac_ctx: pointer to mac context + * @pe_session: pointer to PE session + * + * This API is to strip WAPI IE from add_ie + * + * Return: none + */ +void lim_strip_wapi_ies_from_add_ies(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_del_pmf_sa_query_timer() - This function deletes SA query timer + * @mac_ctx: pointer to mac context + * @pe_session: pointer to PE session + * + * This API is to delete the PMF SA query timer created for each associated STA + * + * Return: none + */ +void lim_del_pmf_sa_query_timer(struct mac_context *mac_ctx, struct pe_session *pe_session); + +/** + * lim_get_vdev_rmf_capable() - get rmf capable - MFPC + * @mac: mac context + * @session: pe session + * + * Get intersection of local & peer (BSS) RSN caps + * and check MFPC bit. + * + * Return: bool + */ +bool lim_get_vdev_rmf_capable(struct mac_context *mac, + struct pe_session *session); + +/** + * lim_add_bssid_to_reject_list:- Add rssi reject Ap info to denylist mgr. + * @pdev: pdev + * @entry: info of the BSSID to be put in rssi reject list. + * + * This API will add the passed ap info to the rssi reject list. + * + */ +void +lim_add_bssid_to_reject_list(struct wlan_objmgr_pdev *pdev, + struct sir_rssi_disallow_lst *entry); + +/** + * lim_strip_op_class_update_struct - strip sup op class IE and populate + * the dot11f structure + * @mac_ctx: global MAC context + * @addn_ie: Additional IE buffer + * @addn_ielen: Length of additional IE + * @dst: Supp operating class IE structure to be updated + * + * This function is used to strip supp op class IE from IE buffer and + * update the passed structure. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_strip_supp_op_class_update_struct(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + tDot11fIESuppOperatingClasses *dst); + +uint8_t lim_get_80Mhz_center_channel(uint8_t primary_channel); +void lim_update_obss_scanparams(struct pe_session *session, + tDot11fIEOBSSScanParameters *scan_params); +void lim_init_obss_params(struct mac_context *mac_ctx, struct pe_session *session); +#ifdef WLAN_FEATURE_HOST_ROAM +uint32_t lim_create_timers_host_roam(struct mac_context *mac_ctx); +/** + * lim_delete_timers_host_roam() - Delete timers used in host based roaming + * @mac_ctx: Global MAC context + * + * Delete reassoc and preauth timers + * + * Return: none + */ +void lim_delete_timers_host_roam(struct mac_context *mac_ctx); +/** + * lim_deactivate_timers_host_roam() - deactivate timers used in host based + * roaming + * @mac_ctx: Global MAC context + * + * Delete reassoc and preauth timers + * + * Return: none + */ +void lim_deactivate_timers_host_roam(struct mac_context *mac_ctx); +void lim_deactivate_and_change_timer_host_roam(struct mac_context *mac_ctx, + uint32_t timer_id); +#else +static inline uint32_t lim_create_timers_host_roam(struct mac_context *mac_ctx) +{ + return 0; +} +static inline void lim_delete_timers_host_roam(struct mac_context *mac_ctx) +{} +static inline void lim_deactivate_timers_host_roam(struct mac_context *mac_ctx) {} +static inline void lim_deactivate_and_change_timer_host_roam( + struct mac_context *mac_ctx, uint32_t timer_id) +{} +#endif + +uint8_t lim_compute_ext_cap_ie_length(tDot11fIEExtCap *ext_cap); + +void lim_update_caps_info_for_bss(struct mac_context *mac_ctx, + uint16_t *caps, uint16_t bss_caps); +void lim_send_set_dtim_period(struct mac_context *mac_ctx, uint8_t dtim_period, + struct pe_session *session); + +QDF_STATUS lim_strip_ie(struct mac_context *mac_ctx, + uint8_t *addn_ie, uint16_t *addn_ielen, + uint8_t eid, enum size_of_len_field size_of_len_field, + uint8_t *oui, uint8_t out_len, uint8_t *extracted_ie, + uint32_t eid_max_len); + +#define MCSMAPMASK1x1 0x3 +#define MCSMAPMASK2x2 0xC + +#ifdef WLAN_FEATURE_11AX + +/** + * lim_intersect_ap_he_caps() - Intersect AP capability with self STA capability + * @session: pointer to PE session + * @add_bss: pointer to ADD BSS params + * @beacon: pointer to beacon + * @assoc_rsp: pointer to assoc response + * @bss_desc: pointer to BSS description + * + * Return: None + */ +void lim_intersect_ap_he_caps(struct pe_session *session, + struct bss_params *add_bss, + tSchBeaconStruct *pBeaconStruct, + tpSirAssocRsp assoc_rsp, + struct bss_description *bss_desc); + +/** + * lim_intersect_sta_he_caps() - Intersect STA capability with SAP capability + * @mac_ctx: pointer to the MAC context + * @assoc_req: pointer to assoc request + * @session: pointer to PE session + * @sta_ds: pointer to STA dph hash table entry + * + * Return: None + */ +void lim_intersect_sta_he_caps(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + struct pe_session *session, + tpDphHashNode sta_ds); + +/** + * lim_add_he_cap() - Copy HE capability into Add sta params + * @mac_ctx: Global MAC context + * @pe_session: pe session entry + * @add_sta_params: pointer to add sta params + * @assoc_req: pointer to Assoc request + * + * Return: None + */ +void lim_add_he_cap(struct mac_context *mac_ctx, struct pe_session *pe_session, + tpAddStaParams add_sta_params, tpSirAssocReq assoc_req); + +/** + * lim_add_self_he_cap() - Copy HE capability into add sta from PE session + * @add_sta_params: pointer to add sta params + * @session: pointer to PE Session + * + * Return: None + */ +void lim_add_self_he_cap(tpAddStaParams add_sta_params, struct pe_session *session); + +/** + * lim_add_bss_he_cap() - Copy HE capability into ADD BSS params + * @add_bss: pointer to add bss params + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_add_bss_he_cap(struct bss_params *add_bss, tpSirAssocRsp assoc_rsp); + +/** + * lim_add_bss_he_cfg() - Set HE config to BSS params + * @add_bss: pointer to add bss params + * @session: Pointer to Session entry struct + * + * Return: None + */ +void lim_add_bss_he_cfg(struct bss_params *add_bss, struct pe_session *session); + +/** + * lim_copy_bss_he_cap() - Copy HE capability into PE session from start bss + * @session: pointer to PE session + * + * Return: None + */ +void lim_copy_bss_he_cap(struct pe_session *session); + +/** + * lim_update_he_caps_mcs() - Update he caps MCS + * @mac: MAC context + * @session: pointer to PE session + * + * Return: None + */ +void lim_update_he_caps_mcs(struct mac_context *mac, + struct pe_session *session); + + +/** + * lim_update_he_6gop_assoc_resp() - Update HE 6GHz op info to BSS params + * @add_bss: pointer to add bss params + * @he_op: Pointer to HE operation info IE + * @session: Pointer to Session entry struct + * + * Return: None + */ +void lim_update_he_6gop_assoc_resp(struct bss_params *pAddBssParams, + tDot11fIEhe_op *he_op, + struct pe_session *pe_session); +/** + * lim_copy_join_req_he_cap() - Copy HE capability to PE session from Join req + * and update as per bandwidth supported + * @session: pointer to PE session + * + * Return: None + */ +void lim_copy_join_req_he_cap(struct pe_session *session); + +/** + * lim_log_he_6g_cap() - Print HE 6G cap IE + * @mac: pointer to MAC context + * @he_6g_cap: pointer to HE 6G cap IE + * + * Print HE 6G caps stored as dot11f structure + * + * Return: None + */ +void lim_log_he_6g_cap(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *he_6g_cap); + +/** + * lim_log_he_op() - Print HE Operation + * @mac: pointer to MAC context + * @he_op: pointer to HE Operation + * @session: pointer to PE session + * + * Print HE operation stored as dot11f structure + * + * Return: None + */ +void lim_log_he_op(struct mac_context *mac, tDot11fIEhe_op *he_ops, + struct pe_session *session); + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * lim_log_he_bss_color() - Print HE bss color + * @mac: pointer to MAC context + * @he_bss_color: pointer to HE bss color + * + * Print HE bss color IE + * + * Return: None + */ +void lim_log_he_bss_color(struct mac_context *mac, + tDot11fIEbss_color_change *he_bss_color); +#endif + +/** + * lim_log_he_cap() - Print HE capabilities + * @mac: pointer to MAC context + * @he_cap: pointer to HE Capability + * + * Received HE capabilities are converted into dot11f structure. + * This function will print all the HE capabilities as stored + * in the dot11f structure. + * + * Return: None + */ +void lim_log_he_cap(struct mac_context *mac, tDot11fIEhe_cap *he_cap); + +/** + * lim_check_he_80_mcs11_supp() - Check whether MCS 0-11 rates are supported + * @session: pointer to PE session + * @he_cap: pointer to HE capabilities + * + * Return: true if MCS 0-11 rates are supported + */ +bool lim_check_he_80_mcs11_supp(struct pe_session *session, + tDot11fIEhe_cap *he_cap); + +void lim_check_and_force_he_ldpc_cap(struct pe_session *session, + tDot11fIEhe_cap *he_cap); + +/** + * lim_update_stads_he_caps() - Copy HE capability into STA DPH hash table entry + * @mac_ctx: pointer to mac context + * @sta_ds: pointer to sta dph hash table entry + * @assoc_rsp: pointer to assoc response + * @session_entry: pointer to PE session + * @beacon: pointer to beacon + * + * Return: None + */ +void lim_update_stads_he_caps(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, + tSchBeaconStruct *beacon); + +/** + * lim_update_usr_he_cap() - Update HE capability based on userspace + * @mac_ctx: global mac context + * @session: PE session entry + * + * Parse the HE Capability IE and populate the fields to be + * sent to FW as part of add bss and update PE session. + */ +void lim_update_usr_he_cap(struct mac_context *mac_ctx, struct pe_session *session); + +/** + * lim_decide_he_op() - Determine HE operation elements + * @mac_ctx: global mac context + * @he_ops: mlme he ops + * @session: PE session entry + * + * Parse the HE Operation IE and populate the fields to be + * sent to FW as part of add bss. + */ +void lim_decide_he_op(struct mac_context *mac_ctx, uint32_t *mlme_he_ops, + struct pe_session *session); + +/** + * lim_update_sta_he_capable(): Update he_capable in add sta params + * @mac: pointer to MAC context + * @add_sta_params: pointer to add sta params + * @sta_ds: pointer to dph hash table entry + * @session_entry: pointer to PE session + * + * Return: None + */ +void lim_update_sta_he_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, tpDphHashNode sta_ds, + struct pe_session *session_entry); + +static inline bool lim_is_session_he_capable(struct pe_session *session) +{ + return session->he_capable; +} + +/** + * lim_update_he_bw_cap_mcs(): Update he mcs map per bandwidth + * @session_entry: pointer to PE session + * @beacon: pointer to beacon + * + * Return: None + */ +void lim_update_he_bw_cap_mcs(struct pe_session *session, + tSirProbeRespBeacon *beacon); + +static inline bool lim_is_he_6ghz_band(struct pe_session *session) +{ + return session->he_6ghz_band; +} + +/** + * lim_get_session_he_frag_cap(): Get session HE fragmentation cap + * @session: pointer to session + * + * Return: HE fragmentation value + */ +static inline uint8_t lim_get_session_he_frag_cap(struct pe_session *session) +{ + return session->he_config.fragmentation; +} + +static inline bool lim_is_sta_he_capable(tpDphHashNode sta_ds) +{ + return sta_ds->mlmStaContext.he_capable; +} + +/** + * lim_update_bss_he_capable() - Update he_capable in add BSS params + * @mac: pointer to MAC context + * @add_bss: pointer to add BSS params + * + * Return: None + */ +void lim_update_bss_he_capable(struct mac_context *mac, + struct bss_params *add_bss); + +/** + * lim_update_stads_he_capable() - Update he_capable in sta ds context + * @sta_ds: pointer to sta ds + * @assoc_req: pointer to assoc request + * + * Return: None + */ +void lim_update_stads_he_capable(tpDphHashNode sta_ds, tpSirAssocReq assoc_req); + +/** + * lim_update_session_he_capable(): Update he_capable in PE session + * @mac: pointer to MAC context + * @session: pointer to PE session + * + * Return: None + */ +void lim_update_session_he_capable(struct mac_context *mac, struct pe_session *session); + +/** + * lim_update_session_he_capable_chan_switch(): Update he_capable in PE session + * @mac: pointer to MAC context + * @session: pointer to PE session + * @new_chan_freq: new channel frequency Mhz + * + * Update session he capable during AP channel switching + * + * Return: None + */ +void lim_update_session_he_capable_chan_switch(struct mac_context *mac, + struct pe_session *session, + uint32_t new_chan_freq); + +/** + * lim_set_he_caps() - update HE caps to be sent to FW as part of scan IE + * @mac: pointer to MAC + * @ie_start: pointer to start of IE buffer + * @num_bytes: length of IE buffer + * @band: 2g or 5g band + * + * Return: None + */ +void lim_set_he_caps(struct mac_context *mac, uint8_t *ie_start, + uint32_t num_bytes, uint8_t band); + +/** + * lim_send_he_caps_ie() - gets HE capability and send to firmware via wma + * @mac_ctx: global mac context + * @device_mode: VDEV op mode + * @vdev_id: vdev for which IE is targeted + * + * This function gets HE capability and send to firmware via wma + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_he_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id); + +/** + * lim_populate_he_mcs_per_bw() - pouldate HE mcs set per BW (le 80, 160, 80+80) + * @mac_ctx: Global MAC context + * @self_rx: self rx mcs set + * @self_tx: self tx mcs set + * @peer_rx: peer rx mcs set + * @peer_tx: peer tx mcs set + * @nss: nss + * @cfg_rx_param: rx wni param to read + * @cfg_tx_param: tx wni param to read + * + * MCS values are interpreted as in IEEE 11ax-D1.4 spec onwards + * +-----------------------------------------------------+ + * | SS8 | SS7 | SS6 | SS5 | SS4 | SS3 | SS2 | SS1 | + * +-----------------------------------------------------+ + * | 15-14 | 13-12 | 11-10 | 9-8 | 7-6 | 5-4 | 3-2 | 1-0 | + * +-----------------------------------------------------+ + * + * Return: status of operation + */ +QDF_STATUS lim_populate_he_mcs_per_bw(struct mac_context *mac_ctx, + uint16_t *supp_rx_mcs, + uint16_t *supp_tx_mcs, + uint16_t peer_rx, uint16_t peer_tx, + uint8_t nss, uint16_t rx_mcs, + uint16_t tx_mcs); + +/** + * lim_populate_he_mcs_set() - function to populate HE mcs rate set + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rate set + * @peer_vht_caps: pointer to peer HE capabilities + * @session_entry: pe session entry + * @nss: number of spatial streams + * + * Populates HE mcs rate set based on peer and self capabilities + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_populate_he_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEhe_cap *peer_he_caps, + struct pe_session *session_entry, + uint8_t nss); + +/** + * lim_update_stads_he_6ghz_op() - Update sta ds channel info + * @session: pe session + * @sta_ds: pointer to sta ds struct + + * Update sta_ds channel width. + * + * Return: void + */ +void lim_update_stads_he_6ghz_op(struct pe_session *session, + tpDphHashNode sta_ds); + +/** + * lim_update_he_6ghz_band_caps() - Update he 6ghz band caps + * @mac_ctx: Global MAC context + * @pAssocRsp: contains the structured assoc/reassoc Response got from AP + * @add_bss: pointer to ADD BSS params + * + * Update 6ghz band caps based on HE capability + * + * Return: none + */ +void lim_update_he_6ghz_band_caps(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *he_6ghz_band_cap, + tpAddStaParams params); + +#else +static inline void lim_add_he_cap(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tpAddStaParams add_sta_params, + tpSirAssocReq assoc_req) +{ +} + +static inline void lim_add_self_he_cap(tpAddStaParams add_sta_params, + struct pe_session *session) +{ +} + +static inline void lim_add_bss_he_cap(struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ + return; +} + +static inline void lim_add_bss_he_cfg(struct bss_params *add_bss, + struct pe_session *session) +{ +} + +static inline void lim_update_he_6gop_assoc_resp( + struct bss_params *pAddBssParams, + tDot11fIEhe_op *he_op, + struct pe_session *pe_session) +{ +} + +static inline void lim_intersect_ap_he_caps(struct pe_session *session, + struct bss_params *add_bss, + tSchBeaconStruct *pBeaconStruct, + tpSirAssocRsp assoc_rsp, + struct bss_description *bss_desc) +{ + return; +} + +static inline void lim_intersect_sta_he_caps(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + struct pe_session *session, + tpDphHashNode sta_ds) +{ +} + +static inline void lim_update_stads_he_caps(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, + tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, + tSchBeaconStruct *beacon) +{ + return; +} + +static inline void lim_update_usr_he_cap(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} + +static inline void lim_decide_he_op(struct mac_context *mac_ctx, + uint32_t *mlme_he_ops, struct pe_session *session) +{ +} + +static inline +void lim_copy_bss_he_cap(struct pe_session *session) +{ +} + +static inline +void lim_update_he_caps_mcs(struct mac_context *mac, struct pe_session *session) +{ +} + +static inline void lim_copy_join_req_he_cap(struct pe_session *session) +{ +} + +static inline void lim_log_he_op(struct mac_context *mac, + tDot11fIEhe_op *he_ops, + struct pe_session *session) +{ +} + +static inline void lim_log_he_cap(struct mac_context *mac, + tDot11fIEhe_cap *he_cap) +{ +} + +static inline void lim_update_sta_he_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, struct pe_session *session_entry) +{ +} + +static inline bool lim_is_session_he_capable(struct pe_session *session) +{ + return false; +} + +static inline void lim_update_he_bw_cap_mcs(struct pe_session *session, + tSirProbeRespBeacon *beacon) +{ +} + +static inline bool lim_is_he_6ghz_band(struct pe_session *session) +{ + return false; +} + +static inline uint8_t lim_get_session_he_frag_cap(struct pe_session *session) +{ + return 0; +} + +static inline bool lim_is_sta_he_capable(tpDphHashNode sta_ds) +{ + return false; +} + +static inline void lim_update_bss_he_capable(struct mac_context *mac, + struct bss_params *add_bss) +{ +} + +static inline void lim_update_stads_he_capable(tpDphHashNode sta_ds, + tpSirAssocReq assoc_req) +{ +} + +static inline void lim_update_session_he_capable(struct mac_context *mac, + struct pe_session *session) +{ +} + +static inline +void lim_update_session_he_capable_chan_switch(struct mac_context *mac, + struct pe_session *session, + uint32_t new_chan_freq) +{ +} + +static inline void lim_set_he_caps(struct mac_context *mac, struct pe_session *session, + uint8_t *ie_start, uint32_t num_bytes, + uint8_t band) +{ +} + +static inline QDF_STATUS lim_send_he_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS lim_populate_he_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEhe_cap *peer_he_caps, + struct pe_session *session_entry, + uint8_t nss) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +lim_update_stads_he_6ghz_op(struct pe_session *session, + tpDphHashNode sta_ds) +{ +} + +static inline void +lim_update_he_6ghz_band_caps(struct mac_context *mac, + tDot11fIEhe_6ghz_band_cap *he_6ghz_band_cap, + tpAddStaParams params) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +static inline bool lim_is_session_eht_capable(struct pe_session *session) +{ + if (!session) + return false; + + return session->eht_capable; +} + +static inline bool lim_is_sta_eht_capable(tpDphHashNode sta_ds) +{ + return sta_ds->mlmStaContext.eht_capable; +} + +QDF_STATUS lim_strip_eht_op_ie(struct mac_context *mac_ctx, + uint8_t *frame_ies, + uint16_t *ie_buf_size, + uint8_t *eht_op_ie); + +QDF_STATUS lim_strip_eht_cap_ie(struct mac_context *mac_ctx, + uint8_t *frame_ies, + uint16_t *ie_buf_size, + uint8_t *eht_cap_ie); + +/** + * lim_populate_eht_mcs_set() - function to populate EHT mcs rate set + * @mac_ctx: pointer to global mac structure + * @rates: pointer to supported rate set + * @peer_eht_caps: pointer to peer EHT capabilities + * @session_entry: pe session entry + * @ch_width: channel width of the association + * + * Populates EHT mcs rate set based on peer and self capabilities + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_populate_eht_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps, + struct pe_session *session_entry, + enum phy_ch_width ch_width); + +/** + * lim_update_eht_bw_cap_mcs(): Update eht mcs map per bandwidth + * @session_entry: pointer to PE session + * @beacon: pointer to beacon + * + * Return: None + */ +void lim_update_eht_bw_cap_mcs(struct pe_session *session, + tSirProbeRespBeacon *beacon); + +/** + * lim_add_self_eht_cap() - Copy EHT capability into add sta from PE session + * @add_sta_params: pointer to add sta params + * @session: pointer to PE Session + * + * Return: None + */ +void lim_add_self_eht_cap(tpAddStaParams add_sta_params, + struct pe_session *session); + +/** + * lim_update_usr_eht_cap() - Update EHT capability based on userspace + * @mac_ctx: global mac context + * @session: PE session entry + * + * Parse the EHT Capability IE and populate the fields to be + * sent to FW as part of add bss and update PE session. + */ +void lim_update_usr_eht_cap(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_copy_bss_eht_cap() - Copy EHT capability into PE session from start bss + * @session: pointer to PE session + * + * Return: None + */ +void lim_copy_bss_eht_cap(struct pe_session *session); + +/** + * lim_copy_join_req_eht_cap() - Copy EHT capability to PE session from Join req + * and update as per bandwidth supported + * @session: pointer to PE session + * + * Return: None + */ +void lim_copy_join_req_eht_cap(struct pe_session *session); + +/** + * lim_add_eht_cap() - Copy EHT capability into Add sta params + * @mac_ctx: Global MAC context + * @pe_session: pe session entry + * @add_sta_params: pointer to add sta params + * @assoc_req: pointer to Assoc request + * + * Return: None + */ +void lim_add_eht_cap(struct mac_context *mac_ctx, struct pe_session *pe_session, + tpAddStaParams add_sta_params, tpSirAssocReq assoc_req); + +/** + * lim_intersect_ap_eht_caps() - Intersect AP and self STA EHT capabilities + * @session: pointer to PE session + * @add_bss: pointer to ADD BSS params + * @beacon: pointer to beacon + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_intersect_ap_eht_caps(struct pe_session *session, + struct bss_params *add_bss, + tSchBeaconStruct *pBeaconStruct, + tpSirAssocRsp assoc_rsp); + +/** + * lim_add_bss_eht_cap() - Copy EHT capability into ADD BSS params + * @add_bss: pointer to add bss params + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_add_bss_eht_cap(struct bss_params *add_bss, tpSirAssocRsp assoc_rsp); + +/** + * lim_intersect_sta_eht_caps() - Intersect STA capability with SAP capability + * @mac_ctx: pointer to the MAC context + * @assoc_req: pointer to assoc request + * @session: pointer to PE session + * @sta_ds: pointer to STA dph hash table entry + * + * Return: None + */ +void lim_intersect_sta_eht_caps(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + struct pe_session *session, + tpDphHashNode sta_ds); + +/** + * lim_update_session_eht_capable(): Update eht_capable in PE session + * @mac: pointer to MAC context + * @session: pointer to PE session + * + * Return: None + */ +void lim_update_session_eht_capable(struct mac_context *mac, + struct pe_session *session); + +/** + * lim_add_bss_eht_cfg() - Set EHT config to BSS params + * @add_bss: pointer to add bss params + * @session: Pointer to Session entry struct + * + * Return: None + */ +void lim_add_bss_eht_cfg(struct bss_params *add_bss, + struct pe_session *session); + +/** + * lim_decide_eht_op() - Determine EHT operation elements + * @mac_ctx: global mac context + * @eht_ops: mlme eht ops + * @session: PE session entry + * + * Parse the EHT Operation IE and populate the fields to be + * sent to FW as part of add bss. + */ +void lim_decide_eht_op(struct mac_context *mac_ctx, uint32_t *mlme_eht_ops, + struct pe_session *session); + +/** + * lim_update_stads_eht_capable() - Update eht_capable in sta ds context + * @sta_ds: pointer to sta ds + * @assoc_req: pointer to assoc request + * + * Return: None + */ +void lim_update_stads_eht_capable(tpDphHashNode sta_ds, + tpSirAssocReq assoc_req); + +/** + * lim_update_sta_eht_capable(): Update eht_capable in add sta params + * @mac: pointer to MAC context + * @add_sta_params: pointer to add sta params + * @sta_ds: pointer to dph hash table entry + * @session_entry: pointer to PE session + * + * Return: None + */ +void lim_update_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry); + +#ifdef FEATURE_WLAN_TDLS +/** + * lim_update_tdls_sta_eht_capable(): Update eht_capable in add tdls sta params + * @mac: pointer to MAC context + * @add_sta_params: pointer to add sta params + * @sta_ds: pointer to dph hash table entry + * @session_entry: pointer to PE session + * + * Return: None + */ +void lim_update_tdls_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry); +#else +static inline +void lim_update_tdls_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ +} +#endif + +/** + * lim_update_session_eht_capable_chan_switch(): Update eht_capable in PE + * session + * @mac: pointer to MAC context + * @session: pointer to PE session + * @new_chan_freq: new channel frequency Mhz + * + * Update session eht capable during AP channel switching + * + * Return: None + */ +void lim_update_session_eht_capable_chan_switch(struct mac_context *mac, + struct pe_session *session, + uint32_t new_chan_freq); + +/** + * lim_update_bss_eht_capable() - Update eht_capable in add BSS params + * @mac: pointer to MAC context + * @add_bss: pointer to add BSS params + * + * Return: None + */ +void lim_update_bss_eht_capable(struct mac_context *mac, + struct bss_params *add_bss); + +/** + * lim_log_eht_cap() - Print EHT capabilities + * @mac: pointer to MAC context + * @eht_cap: pointer to HE Capability + * + * Received EHT capabilities are converted into dot11f structure. + * This function will print all the EHT capabilities as stored + * in the dot11f structure. + * + * Return: None + */ +void lim_log_eht_cap(struct mac_context *mac, tDot11fIEeht_cap *eht_cap); + +/** + * lim_set_eht_caps() - update EHT caps to be sent to FW as part of scan IE + * @mac: pointer to MAC + * @ie_start: pointer to start of IE buffer + * @num_bytes: length of IE buffer + * @band: 2g or 5g band + * @vdev_id: vdev id + * + * Return: None + */ +void lim_set_eht_caps(struct mac_context *mac, uint8_t *ie_start, + uint32_t num_bytes, uint8_t band, uint8_t vdev_id); + +/** + * lim_send_eht_caps_ie() - gets EHT capability and send to firmware via wma + * @mac_ctx: global mac context + * @device_mode: VDEV op mode + * @vdev_id: vdev for which IE is targeted + * + * This function gets EHT capability and send to firmware via wma + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_send_eht_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, + uint8_t vdev_id); +/** + * lim_log_eht_op() - Print EHT Operation + * @mac: pointer to MAC context + * @eht_op: pointer to EHT Operation + * @session: pointer to PE session + * + * Print EHT operation stored as dot11f structure + * + * Return: None + */ +void lim_log_eht_op(struct mac_context *mac, tDot11fIEeht_op *eht_ops, + struct pe_session *session); + +/** + * lim_update_stads_eht_caps() - Copy EHT capability into STA DPH hash table + * entry + * @mac_ctx: pointer to mac context + * @sta_ds: pointer to sta dph hash table entry + * @assoc_rsp: pointer to assoc response + * @session_entry: pointer to PE session + * @beacon: pointer to beacon + * + * Return: None + */ +void lim_update_stads_eht_caps(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, + tSchBeaconStruct *beacon); + +/** + * lim_update_stads_eht_bw_320mhz() - Set ch_width to 320MHz for sta_ds + * @session: pointer to PE session + * @sta_ds: pointer to sta dph hash table entry + * + * Set ch_width to 320 MHz only when session is in 320 MHz and peer eht + * caps support 320 MHz after eht caps intersection. + * + * Return: None + */ +void lim_update_stads_eht_bw_320mhz(struct pe_session *session, + tpDphHashNode sta_ds); + +/** + * lim_is_session_chwidth_320mhz() - Check if session chan width is 320 MHz + * @session: pointer to PE session + * + * Check if session channel width is 320 MHz + * + * Return: bool + */ +bool lim_is_session_chwidth_320mhz(struct pe_session *session); + +/** + * lim_update_eht_caps_mcs() - update eht caps + * + * @mac: Pointer to Global mac structure + * @session: Session pointer of the interface + * + * Return: None + */ +void +lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session); + +/** + * lim_update_des_chan_puncture() - set puncture_bitmap of des_chan + * @des_chan: pointer to wlan_channel + * @ch_params: pointer to ch_params + * + * Return: void + */ +void lim_update_des_chan_puncture(struct wlan_channel *des_chan, + struct ch_params *ch_params); + +/** + * lim_overwrite_sta_puncture() - overwrite STA puncture with AP puncture + * @session: session + * @@ch_param: pointer to ch_params + * + * Return: void + */ +void lim_overwrite_sta_puncture(struct pe_session *session, + struct ch_params *ch_param); +#else +static inline +void lim_update_tdls_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ +} + +static inline bool lim_is_session_eht_capable(struct pe_session *session) +{ + return false; +} + +static inline bool lim_is_sta_eht_capable(tpDphHashNode sta_ds) +{ + return false; +} + +static inline +QDF_STATUS lim_strip_eht_op_ie(struct mac_context *mac_ctx, + uint8_t *frame_ies, + uint16_t *ie_buf_size, + uint8_t *eht_op_ie) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +QDF_STATUS lim_strip_eht_cap_ie(struct mac_context *mac_ctx, + uint8_t *frame_ies, + uint16_t *ie_buf_size, + uint8_t *eht_cap_ie) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +QDF_STATUS lim_populate_eht_mcs_set(struct mac_context *mac_ctx, + struct supported_rates *rates, + tDot11fIEeht_cap *peer_eht_caps, + struct pe_session *session_entry, + enum phy_ch_width ch_width) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void lim_update_eht_bw_cap_mcs(struct pe_session *session, + tSirProbeRespBeacon *beacon) +{ +} + +static inline void lim_add_self_eht_cap(tpAddStaParams add_sta_params, + struct pe_session *session) +{ +} + +static inline void lim_update_usr_eht_cap(struct mac_context *mac_ctx, + struct pe_session *session) +{ +} + +static inline void lim_copy_bss_eht_cap(struct pe_session *session) +{ +} + +static inline void lim_copy_join_req_eht_cap(struct pe_session *session) +{ +} + +static inline void lim_add_eht_cap(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tpAddStaParams add_sta_params, + tpSirAssocReq assoc_req) +{ +} + +static inline void +lim_intersect_ap_eht_caps(struct pe_session *session, + struct bss_params *add_bss, + tSchBeaconStruct *pBeaconStruct, + tpSirAssocRsp assoc_rsp) +{ +} + +static inline void lim_add_bss_eht_cap(struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ +} + +static inline +void lim_intersect_sta_eht_caps(struct mac_context *mac_ctx, + tpSirAssocReq assoc_req, + struct pe_session *session, + tpDphHashNode sta_ds) +{ +} + +static inline +void lim_update_session_eht_capable(struct mac_context *mac, + struct pe_session *session) +{ +} + +static inline void +lim_add_bss_eht_cfg(struct bss_params *add_bss, struct pe_session *session) +{ +} + +static inline void +lim_decide_eht_op(struct mac_context *mac_ctx, uint32_t *mlme_eht_ops, + struct pe_session *session) +{ +} + +static inline void +lim_update_stads_eht_capable(tpDphHashNode sta_ds, tpSirAssocReq assoc_req) +{ +} + +static inline void +lim_update_sta_eht_capable(struct mac_context *mac, + tpAddStaParams add_sta_params, + tpDphHashNode sta_ds, + struct pe_session *session_entry) +{ +} + +static inline void +lim_update_session_eht_capable_chan_switch(struct mac_context *mac, + struct pe_session *session, + uint32_t new_chan_freq) +{ +} + +static inline void +lim_update_bss_eht_capable(struct mac_context *mac, + struct bss_params *add_bss) +{ +} + +static inline void +lim_log_eht_cap(struct mac_context *mac, tDot11fIEeht_cap *eht_cap) +{ +} + +static inline void +lim_set_eht_caps(struct mac_context *mac, uint8_t *ie_start, + uint32_t num_bytes, uint8_t band, uint8_t vdev_id) +{ +} + +static inline QDF_STATUS +lim_send_eht_caps_ie(struct mac_context *mac_ctx, + enum QDF_OPMODE device_mode, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void +lim_log_eht_op(struct mac_context *mac, tDot11fIEeht_op *eht_ops, + struct pe_session *session) +{ +} + +static inline void +lim_update_stads_eht_caps(struct mac_context *mac_ctx, + tpDphHashNode sta_ds, tpSirAssocRsp assoc_rsp, + struct pe_session *session_entry, + tSchBeaconStruct *beacon) +{ +} + +static inline void +lim_update_stads_eht_bw_320mhz(struct pe_session *session, + tpDphHashNode sta_ds) +{ +} + +static inline bool +lim_is_session_chwidth_320mhz(struct pe_session *session) +{ + return false; +} + +static inline void +lim_update_eht_caps_mcs(struct mac_context *mac, struct pe_session *session) +{ +} + +static inline void +lim_update_des_chan_puncture(struct wlan_channel *des_chan, + struct ch_params *ch_params) +{ +} + +static inline void +lim_overwrite_sta_puncture(struct pe_session *session, + struct ch_params *ch_param) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_extract_per_link_id() - Extract Link ID per vdev and share with FW + * @session: pointer to PE session + * @add_bss: pointer to ADD BSS params + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_extract_per_link_id(struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp); + +/** + * lim_extract_ml_info() - Extract ML info and send with FW + * @session: pointer to PE session + * @add_bss: pointer to ADD BSS params + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_extract_ml_info(struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp); + +/** + * lim_intersect_ap_emlsr_caps() - Intersect AP and self STA EML capabilities + * @mac_ctx: Global MAC context + * @session: pointer to PE session + * @add_bss: pointer to ADD BSS params + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_intersect_ap_emlsr_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp); + +/** + * lim_extract_msd_caps() - Extract MLD AP MSD capabilities and assign + * the same caps to link vdev + * @mac_ctx: Global MAC context + * @session: pointer to PE session + * @add_bss: pointer to ADD BSS params + * @assoc_rsp: pointer to assoc response + * + * Return: None + */ +void lim_extract_msd_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp); +#else +static inline void +lim_extract_per_link_id(struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ +} + +static inline void +lim_extract_ml_info(struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ +} + +static inline void +lim_intersect_ap_emlsr_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ +} + +static inline void +lim_extract_msd_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct bss_params *add_bss, + tpSirAssocRsp assoc_rsp) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +/** + * lim_send_he_6g_band_caps_ie() - Send HE 6ghz band caps to FW + * @mac_ctx: Global MAC context + * @vdev_id: vdev id + * + * Send HE 6ghz band capabilities IE to firmware + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS lim_send_he_6g_band_caps_ie(struct mac_context *mac_ctx, + uint8_t vdev_id); +#else +static inline +QDF_STATUS lim_send_he_6g_band_caps_ie(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * lim_decrement_pending_mgmt_count: Decrement mgmt frame count + * @mac_ctx: Pointer to global MAC structure + * + * This function is used to decrement pe mgmt count once frame + * removed from queue + * + * Return: None + */ +void lim_decrement_pending_mgmt_count(struct mac_context *mac_ctx); + +/** + * lim_check_if_vendor_oui_match() - Check if the given OUI match in IE buffer + * @mac_ctx: MAC context + * @ie: IE buffer + * @ie_len: length of @ie + * + * This API is used to check if given vendor OUI + * matches in given IE buffer + * + * Return: True, if mataches. False otherwise + */ +bool lim_check_if_vendor_oui_match(struct mac_context *mac_ctx, + uint8_t *oui, uint8_t oui_len, + uint8_t *ie, uint8_t ie_len); + +QDF_STATUS lim_util_get_type_subtype(void *pkt, uint8_t *type, + uint8_t *subtype); + +/** + * lim_get_min_session_txrate() - Get the minimum rate supported in the session + * @session: Pointer to PE session + * @pre_auth_freq: Pointer to pre_auth_freq + * + * This API will find the minimum rate supported by the given PE session and + * return the enum rateid corresponding to the rate. + * + * Return: enum rateid + */ +enum rateid lim_get_min_session_txrate(struct pe_session *session, + qdf_freq_t *pre_auth_freq); + +/** + * lim_send_dfs_chan_sw_ie_update() - updates the channel switch IE in beacon + * template + * + * @mac_ctx - pointer to global mac context + * @session - A pointer to pesession + * Return None + */ +void lim_send_dfs_chan_sw_ie_update(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_process_ap_ecsa_timeout() -process ECSA timeout which decrement csa count + * in beacon and update beacon template in firmware + * + * @data - A pointer to pesession + * Return None + */ +void lim_process_ap_ecsa_timeout(void *session); + +/** + * lim_send_csa_tx_complete() - send csa tx complete event when beacon + * count decremented to zero + * + * @vdev_id - vdev_id + * Return None + */ +void lim_send_csa_tx_complete(uint8_t vdev_id); + +/** + * lim_is_csa_tx_pending() - check id csa tx ind not sent + * + * @vdev_id - vdev_id + * Return - true if csa tx ind is not sent else false + */ +bool lim_is_csa_tx_pending(uint8_t vdev_id); + +/** + * lim_send_stop_bss_failure_resp() -send failure delete bss resp to sme + * @mac_ctx: mac ctx + * @session: session pointer + * + * Return None + */ +void lim_send_stop_bss_failure_resp(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_delete_all_peers() -delete all connected peers + * @session: session pointer + * + * Return None + */ +void lim_delete_all_peers(struct pe_session *session); + +/** + * lim_send_vdev_stop() -send delete bss/stop vdev req + * @session: session pointer + * + * Return QDF_STATUS + */ +QDF_STATUS lim_send_vdev_stop(struct pe_session *session); + +/** + * lim_send_vdev_stop() -send delete bss/stop vdev req for STA + * @session: session pointer + * + * Return QDF_STATUS + */ +QDF_STATUS lim_sta_send_del_bss(struct pe_session *session); + +/** + * lim_send_start_bss_confirm() -send start bss confirm req + * @mac_ctx: pointer to global mac structure + * @start_cnf: start confirm structure pointer + * + * Return None + */ +void lim_send_start_bss_confirm(struct mac_context *mac_ctx, + tLimMlmStartCnf *start_cnf); + +/** + * lim_send_chan_switch_action_frame()- Send an action frame + * containing CSA IE or ECSA IE depending on the connected + * sta capability. + * + * @mac_ctx: pointer to global mac structure + * @new_channel_freq: new channel freq(Mhz) to switch to. + * @ch_bandwidth: ch bw of enum phy_ch_width + * @session_entry: pe session + * + * Return: void + */ +void lim_send_chan_switch_action_frame(struct mac_context *mac_ctx, + uint16_t new_channel_freq, + enum phy_ch_width ch_bandwidth, + struct pe_session *session_entry); + +/** + * send_extended_chan_switch_action_frame()- function to send ECSA + * action frame for each sta connected to SAP/GO and AP in case of + * STA . + * @mac_ctx: pointer to global mac structure + * @new_channel_freq: new channel to switch to. + * @ch_bandwidth: channel bw of type enum phy_ch_width + * @session_entry: pe session + * + * This function is called to send ECSA frame for STA/CLI and SAP/GO. + * + * Return: void + */ +void send_extended_chan_switch_action_frame(struct mac_context *mac_ctx, + uint16_t new_channel_freq, + enum phy_ch_width ch_bandwidth, + struct pe_session *session_entry); + +/** + * lim_process_obss_detection_ind() - Process obss detection indication + * @mac_ctx: Pointer to Global MAC structure. + * @obss_detection: obss detection info. + * + * Process obss detection indication and apply necessary protection for + * the given AP session. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_process_obss_detection_ind(struct mac_context *mac_ctx, + struct wmi_obss_detect_info + *obss_detection); + +/** + * lim_obss_send_detection_cfg() - Send obss detection configuration to firmware + * @mac_ctx: Pointer to Global MAC structure + * @session: Pointer to session + * @force: Force to send new configuration even if new cfg same as old + * + * Generate new cfg based on current protection status and send new cfg to + * firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_obss_send_detection_cfg(struct mac_context *mac_ctx, + struct pe_session *session, + bool force); + +/** + * lim_obss_generate_detection_config() - get new obss offload detection cfg + * @mac_ctx: Pointer to Global MAC structure + * @session: Pointer to session + * @cfg: Obss detection cfg buffer pointer + * + * Generate new cfg based on current protection status. + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_obss_generate_detection_config(struct mac_context *mac_ctx, + struct pe_session *session, + struct obss_detection_cfg *cfg); + +/** + * lim_enable_obss_detection_config() - Enable obss detection + * @mac_ctx: Pointer to Global MAC structure + * @session: Pointer to session + * + * This function will enable legacy obss detection (by starting timer) + * or also offload based detection based on support. + * + * Return: None + */ +void lim_enable_obss_detection_config(struct mac_context *mac_ctx, + struct pe_session *session); + +#ifdef WLAN_SUPPORT_TWT +void lim_set_peer_twt_cap(struct pe_session *session, struct s_ext_cap *ext_cap); +#else +static inline void lim_set_peer_twt_cap(struct pe_session *session, + struct s_ext_cap *ext_cap) +{ +} +#endif + +/** + * lim_rx_invalid_peer_process() - process rx invalid peer indication + * @mac_ctx: Pointer to Global MAC structure + * @lim_msg: Pointer to scheduler message + * + * This function will process the rx data invalid peer indication, + * if the vdev operation mode is SAP, then send the deauth mgmt frame + * to STA. + * + * Return: None + */ +void lim_rx_invalid_peer_process(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg); + +/** + * lim_req_send_delba_ind_process() - process send delba indication + * @mac_ctx: mac context + * @lim_msg: lim message + * + * This function will process the send delba indication from DP. + * + * Return: None + */ +void lim_req_send_delba_ind_process(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg); + +/** + * lim_send_beacon() - send beacon indication to firmware + * @mac_ctx: Pointer to Global MAC structure + * @session: session pointer + * + * Return: None + */ +void lim_send_beacon(struct mac_context *mac_ctx, struct pe_session *session); + +/** + * lim_ndi_mlme_vdev_up_transition() - Send event to transition NDI VDEV to UP + * @session: session pointer + * + * Return: None + */ +void lim_ndi_mlme_vdev_up_transition(struct pe_session *session); + +/** + * lim_sap_move_to_cac_wait_state() - move to cac wait state + * @sap_ctx: SAP context + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_sap_move_to_cac_wait_state(struct pe_session *session); + +/** + * lim_disconnect_complete - Deliver vdev disconnect complete event or + * STA send deleting bss + * @session: PE session pointer + * @del_bss: Whether to call lim_sta_send_del_bss + * + * API delivers vdev disconnect complete event + * + * Return: None + */ +void lim_disconnect_complete(struct pe_session *session, bool del_bss); + +/** + * lim_ap_mlme_vdev_rnr_notify() - SAP is changed, notify co-located sap to + * update RNR IE + * @session: PE session pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_ap_mlme_vdev_rnr_notify(struct pe_session *session); + +/** + * lim_sta_mlme_vdev_stop_send() - send VDEV stop + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes vdev stop + * + * Return: SUCCESS on successful completion of vdev stop + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_sta_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_sta_mlme_vdev_req_fail() - send VDEV start req failure + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes vdev stop + * + * Return: SUCCESS on successful completion of req failure operation + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_sta_mlme_vdev_req_fail(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_sta_mlme_vdev_start_send() - send VDEV start + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes vdev start + * + * Return: SUCCESS on successful completion of vdev start + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_sta_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_sta_mlme_vdev_restart_send() - send VDEV restart + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes vdev restart + * + * Return: SUCCESS on successful completion of vdev restart + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_sta_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_start_send() - Invokes VDEV start operation + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV start operation + * + * Return: SUCCESS on successful completion of start operation + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *event); +/* + * lim_ap_mlme_vdev_update_beacon() - Updates beacon + * @vdev_mlme_obj: VDEV MLME comp object + * @op: beacon update type + * @data_len: data size + * @data: event data + * + * API updates/allocates/frees the beacon + * + * Return: SUCCESS on successful update of beacon + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_update_beacon(struct vdev_mlme_obj *vdev_mlme, + enum beacon_update_op op, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_up_send() - VDEV up operation + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV up operations + * + * Return: SUCCESS on successful completion of up operation + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_disconnect_peers - Disconnect peers + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API trigger stations disconnection connected with AP + * + * Return: SUCCESS on successful invocation of station disconnection + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_disconnect_peers(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_stop_send - Invokes VDEV stop operation + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV stop operation + * + * Return: SUCCESS on successful completion of stop operation + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_restart_send - Invokes VDEV restart operation + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV restart operation + * + * Return: SUCCESS on successful completion of restart operation + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_restart_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_restart_send - Invokes VDEV sta disconnect operation + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV sta disconnect operation + * + * Return: SUCCESS on successful completion of sta disconnect operation + * FAILURE, if it fails due to any + */ +QDF_STATUS +lim_sta_mlme_vdev_sta_disconnect_start(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_ap_mlme_vdev_start_req_failed - handle vdev start req failure + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes on START fail response + * + * Return: SUCCESS on successful invocation of callback + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_ap_mlme_vdev_start_req_failed(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * lim_mon_mlme_vdev_start_send() - Invokes VDEV start operation + * @vdev_mlme_obj: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV start operation + * + * Return: SUCCESS on successful completion of start operation + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_mon_mlme_vdev_start_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *event); + +/** + * lim_get_capability_info() - Get capability information + * @mac: pointer to mac data + * @pcap: pointer to return capability information + * @pe_session: pointer to pe session + * + * Return: SUCCESS on successful get capability information + * FAILURE, if it fails due to any + */ +QDF_STATUS lim_get_capability_info(struct mac_context *mac, uint16_t *pCap, + struct pe_session *pe_session); + +/** + * lim_op_class_from_bandwidth() - get op class from bandwidth + * @mac_ctx: mac context + * @channel_freq: channel frequency MHz + * @ch_bandwidth: channel bandwidth + * @offset: second channel offfset + * + * This API can get the operating class based on channel freq, + * bandwidth and second channel offset. + * + * Return: op class + */ +uint8_t lim_op_class_from_bandwidth(struct mac_context *mac_ctx, + uint16_t channel_freq, + enum phy_ch_width ch_bandwidth, + enum offset_t offset); + +/** + * lim_flush_bssid() - flush bssid from scan cache + * @mac_ctx: pointer to mac data + * @bssid: bssid to be flushed + * + * Return: void + */ +void lim_flush_bssid(struct mac_context *mac_ctx, uint8_t *bssid); + +/** + * lim_is_sha384_akm() - Function to check if the negotiated AKM for the + * current session is based on sha384 key derivation function. + * @mac_ctx: pointer to mac data + * @akm: negotiated AKM for the current session + * + * Return: true if akm is sha384 based kdf or false + */ +bool lim_is_sha384_akm(enum ani_akm_type akm); + + +/** + * lim_pre_vdev_start() - set set vdev params from session + * @mac: pointer to mac context + * @mlme_obj: vdev mlme obj + * @session: pointer to pe session + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_pre_vdev_start(struct mac_context *mac, + struct vdev_mlme_obj *mlme_obj, + struct pe_session *session); + +/** + * lim_set_ch_phy_mode() - set channel phy mode + * @vdev: pointer to vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_set_ch_phy_mode(struct wlan_objmgr_vdev *vdev, uint8_t dot11mode); + +#if defined(CONFIG_BAND_6GHZ) && defined(WLAN_FEATURE_11AX) +/** + * lim_ap_check_6g_compatible_peer() - check all client support 6Ghz band + * @mac_ctx: mac context + * @session: pe session + * + * Return: void + */ +void lim_ap_check_6g_compatible_peer(struct mac_context *mac_ctx, + struct pe_session *session); +#else +static inline void lim_ap_check_6g_compatible_peer( + struct mac_context *mac_ctx, struct pe_session *session) +{} +#endif + +/** + * enum max_tx_power_interpretation + * @LOCAL_EIRP: Local power interpretation + * @LOCAL_EIRP_PSD: Local PSD power interpretation + * @REGULATORY_CLIENT_EIRP: Regulatory power interpretation + * @REGULATORY_CLIENT_EIRP_PSD: Regulatory PSD power interpretation + */ +enum max_tx_power_interpretation { + LOCAL_EIRP = 0, + LOCAL_EIRP_PSD, + REGULATORY_CLIENT_EIRP, + REGULATORY_CLIENT_EIRP_PSD, +}; + +/** + * lim_parse_tpe_ie() - get the power info from the TPE IE + * @mac_ctx: mac context + * @session: pe session + * @tpe_ies: list of TPE IEs + * @num_tpe_ies: number of TPE IEs in list + * @he_op: HE OP IE + * @has_tpe_updated: flag set to true only if the TPE values have changed + * + * Return: void + */ +void lim_parse_tpe_ie(struct mac_context *mac, struct pe_session *session, + tDot11fIEtransmit_power_env *tpe_ies, + uint8_t num_tpe_ies, tDot11fIEhe_op *he_op, + bool *has_tpe_updated); + +/** + * lim_process_tpe_ie_from_beacon() - get the TPE IE from the BSS descriptor + * @mac_ctx: mac context + * @session: pe session + * @bss_desc: pointer to BSS descriptor + * @has_tpe_updated: flag set to true only if the TPE values have changed + * + * Return: void + */ +void lim_process_tpe_ie_from_beacon(struct mac_context *mac, + struct pe_session *session, + struct bss_description *bss_desc, + bool *has_tpe_updated); + +/** + * lim_send_conc_params_update() - Function to check and update params based on + * STA/SAP concurrency.such as EDCA params + * and RTS profile. If updated, it will also + * also send the updated parameters to FW. + * + * Return: void + */ +void lim_send_conc_params_update(void); + +/** + * lim_is_self_and_peer_ocv_capable() - check whether OCV capable + * @mac: pointer to mac data + * @pe_session: pointer to pe session +.* @peer: peer mac address + * + * Return: true if both self and peer ocv capable + */ +bool +lim_is_self_and_peer_ocv_capable(struct mac_context *mac, + uint8_t *peer, + struct pe_session *pe_session); + +/** + * lim_fill_oci_params() - fill oci parameters + * @mac: pointer to mac data + * @session: pointer to pe session +.* @oci: pointer of tDot11fIEoci + * @peer: peer mac address + * @tx_chan_width: tx channel width in MHz + * + * Return: void + */ +void +lim_fill_oci_params(struct mac_context *mac, struct pe_session *session, + tDot11fIEoci *oci, uint8_t *peer, uint16_t *tx_chan_width); + +#ifdef WLAN_FEATURE_SAE +/** + * lim_process_sae_msg() - Process SAE message + * @mac: Global MAC pointer + * @body: Buffer pointer + * + * Return: None + */ +void lim_process_sae_msg(struct mac_context *mac, struct sir_sae_msg *body); + +/** + * lim_trigger_auth_req_sae() - sends SAE auth request to sme + * @mac_ctx: Global MAC pointer + * @session: pointer to pe session + * @peer_bssid: bssid to do SAE auth + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_trigger_auth_req_sae(struct mac_context *mac_ctx, + struct pe_session *session, + struct qdf_mac_addr *peer_bssid); +#else +static inline void lim_process_sae_msg(struct mac_context *mac, void *body) +{} + +static inline QDF_STATUS lim_trigger_auth_req_sae( + struct mac_context *mac_ctx, + struct pe_session *session, + struct qdf_mac_addr *peer_bssid) +{} +#endif + +/** + * lim_get_he_max_mcs_idx() - get max mcs index from he cap + * @ch_width: channel width + * @he_cap: pointer to tDot11fIEhe_cap + * + * Return: max mcs index from he cap + */ +uint8_t lim_get_he_max_mcs_idx(enum phy_ch_width ch_width, + tDot11fIEhe_cap *he_cap); + +/** + * lim_get_vht_max_mcs_idx() - get max mcs index from vht cap + * @vht_cap: pointer to tDot11fIEVHTCaps + * + * Return: max mcs index from vht cap + */ +uint8_t lim_get_vht_max_mcs_idx(tDot11fIEVHTCaps *vht_cap); + +/** + * lim_get_ht_max_mcs_idx() - get max mcs index from ht cap + * @ht_cap: pointer to tDot11fIEHTCaps + * + * Return: max mcs index from ht cap + */ +uint8_t lim_get_ht_max_mcs_idx(tDot11fIEHTCaps *ht_cap); + +/** + * lim_get_max_rate_idx() - get max rate index from tSirMacRateSet + * @rateset: pointer to tSirMacRateSet + * + * Return: max rate index from tSirMacRateSet + */ +uint8_t lim_get_max_rate_idx(tSirMacRateSet *rateset); + +/** + * lim_update_nss() - Function to update NSS + * @mac_ctx: pointer to Global Mac structure + * @sta_ds: pointer to tpDphHashNode + * @rx_nss: Rx NSS in operating mode notification + * @session: pointer to pe_session + * + * function to update NSS + * + * Return: None + */ +void lim_update_nss(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + uint8_t rx_nss, struct pe_session *session); + +/** + * lim_update_channel_width() - Function to update channel width + * @mac_ctx: pointer to Global Mac structure + * @sta_ptr: pointer to tpDphHashNode + * @session: pointer to pe_session + * @ch_width: Channel width in operating mode notification + * @new_ch_width: Final channel bandwifdth + * + * function to send WMI_PEER_SET_PARAM_CMDID to FW to update ch_width + * + * Return: Success or Failure + */ +bool lim_update_channel_width(struct mac_context *mac_ctx, + tpDphHashNode sta_ptr, + struct pe_session *session, + enum phy_ch_width ch_width, + enum phy_ch_width *new_ch_width); + +/** + * lim_get_vht_ch_width() - Function to get the VHT + * operating channel width based on frequency params + * + * @vht_cap: Pointer to VHT Caps IE. + * @vht_op: Pointer to VHT Operation IE. + * @ht_info: Pointer to HT Info IE. + * + * Return: VHT channel width + */ +uint8_t lim_get_vht_ch_width(tDot11fIEVHTCaps *vht_cap, + tDot11fIEVHTOperation *vht_op, + tDot11fIEHTInfo *ht_info); + +/* + * lim_set_tpc_power() - Function to compute and send TPC power level to the + * FW based on the opmode of the pe_session + * + * @mac_ctx: Pointer to Global MAC structure + * @pe_session: Pointer to session + * @bss_desc: Pointer to bss description + * + * Return: TPC status + */ +bool +lim_set_tpc_power(struct mac_context *mac_ctx, struct pe_session *session, + struct bss_description *bss_desc); + +/** + * lim_update_tx_power() - Function to update the TX power for + * the STA interface based on the SAP concurrency + * + * @mac_ctx: Pointer to Global mac structure + * @sap_session: Session pointer of the SAP + * @sta_session: Session pointer of the STA + * @restore_sta_power: Flag to update the new Tx power for STA + * + * Return: QDF_STATUS + */ +QDF_STATUS +lim_update_tx_power(struct mac_context *mac_ctx, struct pe_session *sap_session, + struct pe_session *sta_session, bool restore_sta_power); + +/** + * lim_skip_tpc_update_for_sta() - Function to check if the TPC set power + * needs to be skipped for STA. + * + * @mac_ctx: Pointer to Global mac structure + * @sta_session: Session pointer of the STA. + * @sap_session: Session pointer of the SAP + * + * Return: skip tpc for sta + */ +bool +lim_skip_tpc_update_for_sta(struct mac_context *mac, + struct pe_session *sta_session, + struct pe_session *sap_session); + +#ifdef FEATURE_WLAN_GC_SKIP_JOIN +static inline bool +lim_connect_skip_join_for_gc(struct pe_session *pe_session) +{ + if (pe_session->opmode == QDF_P2P_CLIENT_MODE) + return true; + else + return false; +} +#else +static inline bool +lim_connect_skip_join_for_gc(struct pe_session *pe_session) +{ + return false; +} +#endif + +/** + * lim_get_concurrent_session() - Function to get the concurrent session pointer + * + * @mac_ctx: Pointer to Global mac structure + * @vdev_id: vdev id + * @opmode: opmode of the interface + * + * Return: pe_session + */ +struct pe_session * +lim_get_concurrent_session(struct mac_context *mac_ctx, uint8_t vdev_id, + enum QDF_OPMODE opmode); + +/** + * lim_check_conc_power_for_csa() - Function to change the TX power + * of STA when channel switch happens in SAP + * + * @mac_ctx: Pointer to Global mac structure. + * @session: Session pointer of the SAP. + * + * Return: None + */ +void +lim_check_conc_power_for_csa(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_cleanup_power_change() - Function to reset the change_scc_power + * flag in concurrent SAP vdev + * + * @mac_ctx: Pointer to Global mac structure. + * @session: Session pointer of the interface + */ +void +lim_cleanup_power_change(struct mac_context *mac_ctx, + struct pe_session *session); + +/** + * lim_is_power_change_required_for_sta() - Function to check if the 6 GHz + * STA power level has to be changed + * + * @mac_ctx: Pointer to Global mac structure. + * @sta_session: Session pointer of STA. + * @sap_session: Session pointer of SAP. + * + * Return: restart required for sta + */ +bool +lim_is_power_change_required_for_sta(struct mac_context *mac_ctx, + struct pe_session *sta_session, + struct pe_session *sap_session); + +/** + * lim_update_tx_pwr_on_ctry_change_cb() - Callback to be invoked by regulatory + * module when country code changes (without channel change) OR if fcc + * constraint is set to true. + * This API calls TPC calculation API to recalculate and update the TX power. + * @vdev_id: vdev id + * + * Return: None + */ +void +lim_update_tx_pwr_on_ctry_change_cb(uint8_t vdev_id); + +/* + * lim_get_connected_chan_for_mode() - Get connected channel for given opmode + * in given frequency range. + * + * @psoc: Pointer to psoc object + * @opmode: Vdev opmode + * @freq: Frequency + * + * Return: Return connected channel in given frequcy range for given opmode. + */ +struct wlan_channel * +lim_get_connected_chan_for_mode(struct wlan_objmgr_psoc *psoc, + enum QDF_OPMODE opmode, + qdf_freq_t start_freq, + qdf_freq_t end_freq); + +/** + * lim_convert_vht_chwidth_to_phy_chwidth() - Convert VHT operation + * ch width into phy ch width + * + * @ch_width: VHT op channel width + * @is_40: is 40 MHz + * + * Return: phy chwidth + */ +enum phy_ch_width +lim_convert_vht_chwidth_to_phy_chwidth(uint8_t ch_width, bool is_40); + +/* + * lim_cmp_ssid() - Compare two SSIDs. + * @ssid: first ssid + * @pe_session: pointer to session + * + * Return: qdf_mem_cmp of ssids + */ +uint32_t lim_cmp_ssid(tSirMacSSid *ssid, struct pe_session *pe_session); + +/* + * lim_configure_fd_for_existing_6ghz_sap() - Based on the concurrent + * legacy SAP interface UP/DOWN, configure the FD for the 6 GHz SAPs. + * @session: pointer to pe_session + * @is_sap_starting: true if SAP is starting, false if SAP is stopping + * + * Return: None + */ +void +lim_configure_fd_for_existing_6ghz_sap(struct pe_session *session, + bool is_sap_starting); + +#ifdef WLAN_CHIPSET_STATS +/** + * lim_cp_stats_cstats_log_assoc_resp_evt() - Log chipset stats for assoc resp + * + * @session_entry: pointer to session object + * @dir: Direction + * @status_code: assoc/reassoc status + * @aid: association identifier + * @bssid: bssid + * @da: destination address + * @is_ht: is HT + * @is_vht: is VHT + * @is_he: is HE + * @is_eht: is EHT + * @is_reassoc: is reassoc frame + * + * Return : void + */ +void lim_cp_stats_cstats_log_assoc_resp_evt(struct pe_session *session_entry, + enum cstats_dir dir, + uint16_t status_code, uint16_t aid, + uint8_t *bssid, uint8_t *da, + bool is_ht, bool is_vht, bool is_he, + bool is_eht, bool is_reassoc); + +/** + * lim_cp_stats_cstats_log_auth_evt() - Log chipset stats for auth frames + * + * @pe_session: pointer to session object + * @dir: direction + * @algo: auth algorithm + * @seq: auth sequence + * @status: Status + * + * Return : void + */ +void lim_cp_stats_cstats_log_auth_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t algo, + uint16_t seq, uint16_t status); + +/** + * lim_cp_stats_cstats_log_deauth_evt() - Log chipset stats for deauth frames + * + * @pe_session: pointer to session object + * @dir: direction + * @reasonCode: reason code + * + * Return : void + */ +void lim_cp_stats_cstats_log_deauth_evt(struct pe_session *pe_session, + enum cstats_dir dir, + uint16_t reasonCode); + +/** + * lim_cp_stats_cstats_log_disassoc_evt() - Log chipset stats for disassoc frm + * + * @pe_session: pointer to session object + * @dir: direction + * @reasonCode: reason code + * + * Return : void + */ +void lim_cp_stats_cstats_log_disassoc_evt(struct pe_session *pe_session, + enum cstats_dir dir, + uint16_t reasonCode); + +/** + * lim_cp_stats_cstats_log_assoc_req_evt() - Log chipset stats for assoc req frm + * + * @pe_session: pointer to session object + * @dir: Direction + * @bssid: bssid + * @sa: source addr + * @ssid_len: ssid length + * @ssid: ssid + * @is_ht: is HT + * @is_vht: is VHT + * @is_he: is HE + * @is_eht: is EHT + * @is_reassoc: is reassociation request + * + * Return : void + */ +void lim_cp_stats_cstats_log_assoc_req_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint8_t *bssid, + uint8_t *sa, uint8_t ssid_len, + uint8_t *ssid, bool is_ht, + bool is_vht, bool is_he, + bool is_eht, bool is_reassoc); + +/** + * lim_cp_stats_cstats_log_disc_req_evt() : chipset stats for TDLS disc req + * + * @frm: pointer to tDot11fTDLSDisReq + * @pe_session: pointer to session object + * + * Return: void + */ +void lim_cp_stats_cstats_log_disc_req_evt(tDot11fTDLSDisReq *frm, + struct pe_session *pe_session); + +/** + * lim_cp_stats_cstats_log_disc_resp_evt() : chipset stats for TDLS disc resp + * + * @frm: pointer to tDot11fTDLSDisRsp + * @pe_session: pointer to session object + * + * Return: void + */ +void lim_cp_stats_cstats_log_disc_resp_evt(tDot11fTDLSDisRsp *frm, + struct pe_session *pe_session); + +/** + * lim_cp_stats_cstats_log_setup_req_evt() : chipset stats for TDLS setup req + * + * @frm: pointer to tDot11fTDLSSetupReq + * @pe_session: pointer to session object + * + * Return: void + */ +void lim_cp_stats_cstats_log_setup_req_evt(tDot11fTDLSSetupReq *frm, + struct pe_session *pe_session); + +/** + * lim_cp_stats_cstats_log_setup_resp_evt() : chipset stats for TDLS setup resp + * + * @frm: pointer to tDot11fTDLSSetupRsp + * @pe_session: pointer to session object + * + * Return: void + */ +void lim_cp_stats_cstats_log_setup_resp_evt(tDot11fTDLSSetupRsp *frm, + struct pe_session *pe_session); + +/** + * lim_cp_stats_cstats_log_setup_confirm_evt() : chipset stats for TDLS setup + * confirm + * + * @frm: pointer to tDot11fTDLSSetupCnf + * @pe_session: pointer to session object + * + * Return: void + */ +void lim_cp_stats_cstats_log_setup_confirm_evt(tDot11fTDLSSetupCnf *frm, + struct pe_session *pe_session); + +/** + * lim_cp_stats_cstats_log_tear_down_evt() : chipset stats for TDLS teardown + * + * @frm: pointer to tDot11fTDLSSetupCnf + * @pe_session: pointer to session object + * + * Return: void + */ +void lim_cp_stats_cstats_log_tear_down_evt(tDot11fTDLSTeardown *frm, + struct pe_session *pe_session); + +/** + * lim_cp_stats_cstats_log_csa_evt() : chipset stats for CSA event + * + * @pe_session: pointer to session object + * @dir: Direction of the event i.e TX/RX + * @target_freq: Target freq + * @target_ch_width: Target channel width + * @switch_mode: Switch mode + * + * Return: void + */ +void lim_cp_stats_cstats_log_csa_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t target_freq, + uint8_t target_ch_width, + uint8_t switch_mode); +#else +static inline void +lim_cp_stats_cstats_log_assoc_resp_evt(struct pe_session *session_entry, + enum cstats_dir dir, + uint16_t status_code, uint16_t aid, + uint8_t *bssid, uint8_t *da, + bool is_ht, bool is_vht, bool is_he, + bool is_eht, bool is_reassoc) +{ +} + +static inline void +lim_cp_stats_cstats_log_auth_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t algo, + uint16_t seq, uint16_t status) +{ +} + +static inline void +lim_cp_stats_cstats_log_deauth_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t reasonCode) +{ +} + +static inline void +lim_cp_stats_cstats_log_disassoc_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t reasonCode) +{ +} + +static inline void +lim_cp_stats_cstats_log_assoc_req_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint8_t *bssid, + uint8_t *sa, uint8_t ssid_len, + uint8_t *ssid, bool is_ht, + bool is_vht, bool is_he, + bool is_eht, bool is_reassoc) +{ +} + +static inline void +lim_cp_stats_cstats_log_disc_req_evt(tDot11fTDLSDisReq *frm, + struct pe_session *pe_session) +{ +} + +static inline void +lim_cp_stats_cstats_log_disc_resp_evt(tDot11fTDLSDisRsp *frm, + struct pe_session *pe_session) +{ +} + +static inline void +lim_cp_stats_cstats_log_setup_req_evt(tDot11fTDLSSetupReq *frm, + struct pe_session *pe_session) +{ +} + +static inline void +lim_cp_stats_cstats_log_setup_resp_evt(tDot11fTDLSSetupRsp *frm, + struct pe_session *pe_session) +{ +} + +static inline void +lim_cp_stats_cstats_log_setup_confirm_evt(tDot11fTDLSSetupCnf *frm, + struct pe_session *pe_session) +{ +} + +static inline void +lim_cp_stats_cstats_log_tear_down_evt(tDot11fTDLSTeardown *frm, + struct pe_session *pe_session) +{ +} + +static inline void +lim_cp_stats_cstats_log_csa_evt(struct pe_session *pe_session, + enum cstats_dir dir, uint16_t target_freq, + uint8_t target_ch_width, uint8_t switch_mode) +{ +} +#endif /* WLAN_CHIPSET_STATS */ + +#define MAX_TX_PSD_POWER 15 + +/** + * lim_get_tpe_ie_length() : Get the tpe ie length + * @ch_width: phy channel width + * @tpe_ie: pointer to dot11f TPE IE structure + * @num_tpe: number of TPE IE + * + * Return: tpe ie length + */ +uint16_t lim_get_tpe_ie_length(enum phy_ch_width ch_width, + tDot11fIEtransmit_power_env *tpe_ie, + uint16_t num_tpe); + +/** + * lim_fill_complete_tpe_ie() : fill tpe ie to target buffer + * @ch_width: phy channel width + * @tpe_ie_len: the total bytes to fill target buffer + * @tpe_ptr: pointer to dot11f TPE IE structure + * @num_tpe: number of TPE IE + * @target: the buffer to fill data + * + * Return: QDF_STATUS + */ +QDF_STATUS lim_fill_complete_tpe_ie(enum phy_ch_width ch_width, + uint16_t tpe_ie_len, + tDot11fIEtransmit_power_env *tpe_ptr, + uint16_t num_tpe, uint8_t *target); +#endif /* __LIM_UTILS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c new file mode 100644 index 0000000000..ce0cbfd2ef --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.c @@ -0,0 +1,500 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: nan_datapath.c + * + * MAC NAN Data path API implementation + */ + +#include "lim_utils.h" +#include "lim_api.h" +#include "lim_assoc_utils.h" +#include "nan_datapath.h" +#include "lim_types.h" +#include "lim_send_messages.h" +#include "wma_nan_datapath.h" +#include "os_if_nan.h" +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" + +/** + * lim_add_ndi_peer() - Function to add ndi peer + * @mac_ctx: handle to mac structure + * @vdev_id: vdev id on which peer is added + * @peer_mac_addr: peer to be added + * + * Return: QDF_STATUS_SUCCESS on success; error number otherwise + */ +static QDF_STATUS lim_add_ndi_peer(struct mac_context *mac_ctx, + uint32_t vdev_id, struct qdf_mac_addr peer_mac_addr) +{ + struct pe_session *session; + tpDphHashNode sta_ds; + uint16_t assoc_id, peer_idx; + QDF_STATUS status; + uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 }; + + if (!wlan_is_vdev_id_up(mac_ctx->pdev, vdev_id)) { + pe_err_rl("NDI vdev is not up"); + return QDF_STATUS_E_FAILURE; + } + + if (!qdf_mem_cmp(&zero_mac_addr, &peer_mac_addr.bytes[0], + QDF_MAC_ADDR_SIZE)) { + pe_err("Failing to add peer with all zero mac addr"); + return QDF_STATUS_E_FAILURE; + } + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session) { + /* couldn't find session */ + pe_err("Session not found for vdev_id: %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, + peer_mac_addr.bytes, + &assoc_id, &session->dph.dphHashTable); + /* peer exists, don't do anything */ + if (sta_ds) { + pe_err("NDI Peer already exists!!"); + return QDF_STATUS_SUCCESS; + } + pe_info("Need to create NDI Peer :" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac_addr.bytes)); + + ucfg_nan_set_peer_mc_list(session->vdev, peer_mac_addr); + + peer_idx = lim_assign_peer_idx(mac_ctx, session); + if (!peer_idx) { + pe_err("Invalid peer_idx: %d", peer_idx); + return QDF_STATUS_SUCCESS; + } + + sta_ds = dph_add_hash_entry(mac_ctx, peer_mac_addr.bytes, peer_idx, + &session->dph.dphHashTable); + if (!sta_ds) { + pe_err("Couldn't add dph entry"); + /* couldn't add dph entry */ + return QDF_STATUS_E_FAILURE; + } + + /* wma decides NDI mode from wma->interface struct */ + sta_ds->staType = STA_ENTRY_NDI_PEER; + status = lim_add_sta(mac_ctx, sta_ds, false, session); + if (QDF_STATUS_SUCCESS != status) { + /* couldn't add peer */ + pe_err("limAddSta failed status: %d", + status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_add_ndi_peer_converged(uint32_t vdev_id, + struct qdf_mac_addr peer_mac_addr) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return QDF_STATUS_E_NULL_VALUE; + + return lim_add_ndi_peer(mac_ctx, vdev_id, peer_mac_addr); +} + +/** + * lim_ndp_delete_peer_by_addr() - Delete NAN data peer, given addr and vdev_id + * @mac_ctx: handle to mac context + * @vdev_id: vdev_id on which peer was added + * @peer_ndi_mac_addr: mac addr of peer + * This function deletes a peer if there was NDP_Confirm with REJECT + * + * Return: None + */ +static void lim_ndp_delete_peer_by_addr(struct mac_context *mac_ctx, uint8_t vdev_id, + struct qdf_mac_addr peer_ndi_mac_addr) +{ + struct pe_session *session; + tpDphHashNode sta_ds; + uint16_t peer_idx; + uint8_t zero_mac_addr[QDF_MAC_ADDR_SIZE] = { 0, 0, 0, 0, 0, 0 }; + + if (!qdf_mem_cmp(&zero_mac_addr, &peer_ndi_mac_addr.bytes[0], + QDF_MAC_ADDR_SIZE)) { + pe_err("Failing to delete the peer with all zero mac addr"); + return; + } + + pe_info("deleting peer: "QDF_MAC_ADDR_FMT" confirm rejected", + QDF_MAC_ADDR_REF(peer_ndi_mac_addr.bytes)); + + session = pe_find_session_by_vdev_id(mac_ctx, vdev_id); + if (!session || (session->bssType != eSIR_NDI_MODE)) { + pe_err("PE session is NULL or non-NDI for sme session %d", + vdev_id); + return; + } + + sta_ds = dph_lookup_hash_entry(mac_ctx, peer_ndi_mac_addr.bytes, + &peer_idx, &session->dph.dphHashTable); + if (!sta_ds) { + pe_err("Unknown NDI Peer"); + return; + } + if (sta_ds->staType != STA_ENTRY_NDI_PEER) { + pe_err("Non-NDI Peer ignored"); + return; + } + /* + * Call lim_del_sta() with response required set true. Hence + * DphHashEntry will be deleted after receiving that response. + */ + + lim_del_sta(mac_ctx, sta_ds, true, session); +} + +void lim_ndp_delete_peers_by_addr_converged(uint8_t vdev_id, + struct qdf_mac_addr peer_ndi_mac_addr) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return; + + lim_ndp_delete_peer_by_addr(mac_ctx, vdev_id, peer_ndi_mac_addr); +} + +/** + * lim_ndp_delete_peers() - Delete NAN data peers + * @mac_ctx: handle to mac context + * @ndp_map: NDP instance/peer map + * @num_peers: number of peers entries in peer_map + * This function deletes a peer if there are no active NDPs left with that peer + * + * Return: None + */ +static void lim_ndp_delete_peers(struct mac_context *mac_ctx, + struct peer_ndp_map *ndp_map, uint8_t num_peers) +{ + tpDphHashNode sta_ds = NULL; + uint16_t deleted_num = 0; + int i, j; + struct pe_session *session; + struct qdf_mac_addr *deleted_peers; + uint16_t peer_idx; + bool found; + + deleted_peers = qdf_mem_malloc(num_peers * sizeof(*deleted_peers)); + if (!deleted_peers) + return; + + for (i = 0; i < num_peers; i++) { + pe_debug("ndp_map[%d]: MAC: " QDF_MAC_ADDR_FMT " num_active %d", + i, + QDF_MAC_ADDR_REF(ndp_map[i].peer_ndi_mac_addr.bytes), + ndp_map[i].num_active_ndp_sessions); + + /* Do not delete a peer with active NDPs */ + if (ndp_map[i].num_active_ndp_sessions > 0) + continue; + + session = pe_find_session_by_vdev_id(mac_ctx, + ndp_map[i].vdev_id); + if (!session || (session->bssType != eSIR_NDI_MODE)) { + pe_err("PE session is NULL or non-NDI for sme session %d", + ndp_map[i].vdev_id); + continue; + } + + /* Check if this peer is already in the deleted list */ + found = false; + for (j = 0; j < deleted_num && !found; j++) { + if (!qdf_mem_cmp( + &deleted_peers[j].bytes, + &ndp_map[i].peer_ndi_mac_addr.bytes, + QDF_MAC_ADDR_SIZE)) { + found = true; + break; + } + } + if (found) + continue; + + sta_ds = dph_lookup_hash_entry(mac_ctx, + ndp_map[i].peer_ndi_mac_addr.bytes, + &peer_idx, &session->dph.dphHashTable); + if (!sta_ds) { + pe_err("Unknown NDI Peer"); + continue; + } + if (sta_ds->staType != STA_ENTRY_NDI_PEER) { + pe_err("Non-NDI Peer ignored"); + continue; + } + /* + * Call lim_del_sta() with response required set true. + * Hence DphHashEntry will be deleted after receiving + * that response. + */ + lim_del_sta(mac_ctx, sta_ds, true, session); + qdf_copy_macaddr(&deleted_peers[deleted_num++], + &ndp_map[i].peer_ndi_mac_addr); + } + qdf_mem_free(deleted_peers); +} + +void lim_ndp_delete_peers_converged(struct peer_nan_datapath_map *ndp_map, + uint8_t num_peers) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return; + + lim_ndp_delete_peers(mac_ctx, (struct peer_ndp_map *)ndp_map, + num_peers); +} + +/** + * lim_process_ndi_del_sta_rsp() - Handle WDA_DELETE_STA_RSP in eLIM_NDI_ROLE + * @mac_ctx: Global MAC context + * @lim_msg: LIM message + * @pe_session: PE session + * + * Return: None + */ +void lim_process_ndi_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg, + struct pe_session *pe_session) +{ + tpDphHashNode sta_ds; + tpDeleteStaParams del_sta_params = (tpDeleteStaParams) lim_msg->bodyptr; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc = mac_ctx->psoc; + struct nan_datapath_peer_ind peer_ind; + + if (!del_sta_params) { + pe_err("del_sta_params is NULL"); + return; + } + if (!LIM_IS_NDI_ROLE(pe_session)) { + pe_err("Session %d is not NDI role", del_sta_params->assocId); + goto skip_event; + } + + sta_ds = dph_get_hash_entry(mac_ctx, del_sta_params->assocId, + &pe_session->dph.dphHashTable); + if (!sta_ds) { + pe_err("DPH Entry for STA %X is missing", + del_sta_params->assocId); + goto skip_event; + } + + if (QDF_STATUS_SUCCESS != del_sta_params->status) { + pe_err("DEL STA failed!"); + goto skip_event; + } + pe_info("Deleted STA AssocID %d MAC " QDF_MAC_ADDR_FMT, + sta_ds->assocId, + QDF_MAC_ADDR_REF(sta_ds->staAddr)); + + qdf_mem_copy(&peer_ind.peer_mac_addr.bytes, + sta_ds->staAddr, sizeof(tSirMacAddr)); + lim_release_peer_idx(mac_ctx, sta_ds->assocId, pe_session); + lim_delete_dph_hash_entry(mac_ctx, sta_ds->staAddr, sta_ds->assocId, + pe_session); + pe_session->limMlmState = eLIM_MLM_IDLE_STATE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + pe_session->smeSessionId, + WLAN_NAN_ID); + if (!vdev) { + pe_err("Failed to get vdev from id"); + goto skip_event; + } + ucfg_nan_datapath_event_handler(psoc, vdev, NDP_PEER_DEPARTED, + &peer_ind); + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + +skip_event: + qdf_mem_free(del_sta_params); + lim_msg->bodyptr = NULL; +} + +void lim_process_ndi_mlm_add_bss_rsp(struct mac_context *mac_ctx, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *session_entry) +{ + tLimMlmStartCnf mlm_start_cnf; + + if (!add_bss_rsp) { + pe_err("add_bss_rsp is NULL"); + return; + } + pe_debug("Status %d", add_bss_rsp->status); + if (QDF_IS_STATUS_SUCCESS(add_bss_rsp->status)) { + pe_debug("WDA_ADD_BSS_RSP returned QDF_STATUS_SUCCESS"); + session_entry->limMlmState = eLIM_MLM_BSS_STARTED_STATE; + MTRACE(mac_trace(mac_ctx, TRACE_CODE_MLM_STATE, + session_entry->peSessionId, + session_entry->limMlmState)); + session_entry->vdev_id = add_bss_rsp->vdev_id; + session_entry->limSystemRole = eLIM_NDI_ROLE; + session_entry->statypeForBss = STA_ENTRY_SELF; + /* Apply previously set configuration at HW */ + lim_apply_configuration(mac_ctx, session_entry); + mlm_start_cnf.resultCode = eSIR_SME_SUCCESS; + + /* Initialize peer ID pool */ + lim_init_peer_idxpool(mac_ctx, session_entry); + } else { + pe_err("WDA_ADD_BSS_REQ failed with status %d", + add_bss_rsp->status); + mlm_start_cnf.resultCode = eSIR_SME_HAL_SEND_MESSAGE_FAIL; + } + mlm_start_cnf.sessionId = session_entry->peSessionId; + lim_send_start_bss_confirm(mac_ctx, &mlm_start_cnf); +} + +void lim_ndi_del_bss_rsp(struct mac_context * mac_ctx, + struct del_bss_resp *del_bss, + struct pe_session *session_entry) +{ + tSirResultCodes rc = eSIR_SME_SUCCESS; + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + if (!del_bss) { + pe_err("NDI: DEL_BSS_RSP with no body!"); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + session_entry = pe_find_session_by_vdev_id(mac_ctx, del_bss->vdev_id); + if (!session_entry) { + pe_err("Session Does not exist for given sessionID"); + goto end; + } + + if (del_bss->status != QDF_STATUS_SUCCESS) { + pe_err("NDI: DEL_BSS_RSP error (%x)", del_bss->status); + rc = eSIR_SME_STOP_BSS_FAILURE; + goto end; + } + + session_entry->limMlmState = eLIM_MLM_IDLE_STATE; + +end: + /* Delete PE session once BSS is deleted */ + if (session_entry) { + lim_send_stop_bss_response(mac_ctx, + session_entry->vdev_id, + rc); + pe_delete_session(mac_ctx, session_entry); + session_entry = NULL; + } +} + +static QDF_STATUS lim_send_sme_ndp_add_sta_rsp(struct mac_context *mac_ctx, + struct pe_session *session, + tAddStaParams *add_sta_rsp) +{ + struct nan_datapath_peer_ind *new_peer_ind; + struct wlan_objmgr_psoc *psoc = mac_ctx->psoc; + struct wlan_objmgr_vdev *vdev; + + if (!add_sta_rsp) { + pe_debug("Invalid add_sta_rsp"); + return QDF_STATUS_E_INVAL; + } + + if (!psoc) { + pe_debug("Invalid psoc"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + add_sta_rsp->smesessionId, + WLAN_NAN_ID); + if (!vdev) { + pe_err("Failed to get vdev from id"); + return QDF_STATUS_E_INVAL; + } + + new_peer_ind = qdf_mem_malloc(sizeof(*new_peer_ind)); + if (!new_peer_ind) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(new_peer_ind->peer_mac_addr.bytes, add_sta_rsp->staMac, + sizeof(tSirMacAddr)); + + ucfg_nan_datapath_event_handler(psoc, vdev, NDP_NEW_PEER, new_peer_ind); + qdf_mem_free(new_peer_ind); + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + return QDF_STATUS_SUCCESS; +} + +/** + * lim_ndp_add_sta_rsp() - handles add sta rsp for NDP from WMA + * @mac_ctx: handle to mac structure + * @session: session pointer + * @add_sta_rsp: add sta response struct + * + * Return: None + */ +void lim_ndp_add_sta_rsp(struct mac_context *mac_ctx, struct pe_session *session, + tAddStaParams *add_sta_rsp) +{ + tpDphHashNode sta_ds; + uint16_t peer_idx; + + if (!add_sta_rsp) { + pe_err("Invalid add_sta_rsp"); + qdf_mem_free(add_sta_rsp); + return; + } + + SET_LIM_PROCESS_DEFD_MESGS(mac_ctx, true); + sta_ds = dph_lookup_hash_entry(mac_ctx, add_sta_rsp->staMac, &peer_idx, + &session->dph.dphHashTable); + if (!sta_ds) { + pe_err("NAN: ADD_STA_RSP for unknown MAC addr " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta_rsp->staMac)); + qdf_mem_free(add_sta_rsp); + return; + } + + if (add_sta_rsp->status != QDF_STATUS_SUCCESS) { + pe_err("NAN: ADD_STA_RSP error %x for MAC addr: "QDF_MAC_ADDR_FMT, + add_sta_rsp->status, + QDF_MAC_ADDR_REF(add_sta_rsp->staMac)); + /* delete the sta_ds allocated during ADD STA */ + lim_delete_dph_hash_entry(mac_ctx, add_sta_rsp->staMac, + peer_idx, session); + qdf_mem_free(add_sta_rsp); + return; + } + sta_ds->valid = 1; + sta_ds->mlmStaContext.mlmState = eLIM_MLM_LINK_ESTABLISHED_STATE; + lim_send_sme_ndp_add_sta_rsp(mac_ctx, session, add_sta_rsp); + qdf_mem_free(add_sta_rsp); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h new file mode 100644 index 0000000000..332a2d9cd0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/nan/nan_datapath.h @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: nan_datapath.h + * + * MAC NAN Data path API specification + */ + +#ifndef __MAC_NAN_DATAPATH_H +#define __MAC_NAN_DATAPATH_H + +#ifdef WLAN_FEATURE_NAN + +#include "sir_common.h" +#include "ani_global.h" +#include "sir_params.h" + +struct peer_nan_datapath_map; + +/** + * lim_process_ndi_mlm_add_bss_rsp() - Process ADD_BSS response for NDI + * @mac_ctx: Pointer to Global MAC structure + * @add_bss_rsp: Bss params including rsp data + * @session_entry: PE session + * + * Return: None + */ +void lim_process_ndi_mlm_add_bss_rsp(struct mac_context *mac_ctx, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *session_entry); +/* Handler for DEL BSS resp for NDI interface */ + +/** + * lim_ndi_del_bss_rsp() - Handler for DEL BSS resp for NDI interface + * @mac_ctx: handle to mac structure + * @del_bss: pointer to del bss response + * @session_entry: session entry + * + * Return: None + */ +void lim_ndi_del_bss_rsp(struct mac_context * mac_ctx, + struct del_bss_resp *del_bss, + struct pe_session *session_entry); + +void lim_ndp_add_sta_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tAddStaParams *add_sta_rsp); + +void lim_process_ndi_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg, + struct pe_session *pe_session); + +QDF_STATUS lim_add_ndi_peer_converged(uint32_t vdev_id, + struct qdf_mac_addr peer_mac_addr); + +void lim_ndp_delete_peers_converged(struct peer_nan_datapath_map *ndp_map, + uint8_t num_peers); + +void lim_ndp_delete_peers_by_addr_converged(uint8_t vdev_id, + struct qdf_mac_addr peer_ndi_mac_addr); + +#else +static inline +void lim_process_ndi_mlm_add_bss_rsp(struct mac_context *mac_ctx, + struct add_bss_rsp *add_bss_rsp, + struct pe_session *session_entry) +{ +} + +/** + * lim_ndi_del_bss_rsp() - Handler for DEL BSS resp for NDI interface + * @mac_ctx: handle to mac structure + * @del_bss: pointer to del bss response + * @session_entry: session entry + * + * Return: None + */ +static inline +void lim_ndi_del_bss_rsp(struct mac_context *mac_ctx, + struct del_bss_resp *del_bss, + struct pe_session *session_entry) +{ +} + +static inline +void lim_process_ndi_del_sta_rsp(struct mac_context *mac_ctx, + struct scheduler_msg *lim_msg, + struct pe_session *pe_session) +{ +} + +static inline +void lim_ndp_add_sta_rsp(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tAddStaParams *add_sta_rsp) +{ +} + +#endif /* WLAN_FEATURE_NAN */ + +#endif /* __MAC_NAN_DATAPATH_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c new file mode 100644 index 0000000000..5c65737b26 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/rrm/rrm_api.c @@ -0,0 +1,2690 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \file rrm_api.c + + \brief implementation for PE RRM APIs + + ========================================================================*/ + +/* $Header$ */ + + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "cds_api.h" +#include "wni_api.h" +#include "sir_api.h" +#include "ani_global.h" +#include "wni_cfg.h" +#include "lim_types.h" +#include "lim_utils.h" +#include "lim_send_sme_rsp_messages.h" +#include "parser_api.h" +#include "lim_send_messages.h" +#include "rrm_global.h" +#include "rrm_api.h" +#include "wlan_lmac_if_def.h" +#include "wlan_reg_services_api.h" +#include "wlan_cp_stats_utils_api.h" +#include "../../core/src/wlan_cp_stats_obj_mgr_handler.h" +#include "../../core/src/wlan_cp_stats_defs.h" +#include "cdp_txrx_host_stats.h" +#include "utils_mlo.h" +#include "wlan_mlo_mgr_sta.h" +#include + +#define MAX_CTRL_STAT_VDEV_ENTRIES 1 +#define MAX_CTRL_STAT_MAC_ADDR_ENTRIES 1 +#define MAX_RMM_STA_STATS_REQUESTED 2 +#define MIN_MEAS_DURATION_FOR_STA_STATS 10 + +/* Max passive scan dwell for wide band rrm scan, in milliseconds */ +#define RRM_SCAN_MAX_DWELL_TIME 110 + +/** + * rrm_cache_mgmt_tx_power() - Store Tx power for management frames. + * @mac: pointer to mac context + * @txPower: TX power + * @pe_session: per vdev pe context + * + * Return: None + */ +void +rrm_cache_mgmt_tx_power(struct mac_context *mac, int8_t txPower, + struct pe_session *pe_session) +{ + pe_debug("Cache Mgmt Tx Power: %d", txPower); + + if (!pe_session) + mac->rrm.rrmPEContext.txMgmtPower = txPower; + else + pe_session->txMgmtPower = txPower; +} + +/** + * rrm_get_mgmt_tx_power() - Get the Tx power for management frames. + * @mac: pointer to mac context + * @pe_session: per vdev pe context + * + * Return: TX power + */ +int8_t rrm_get_mgmt_tx_power(struct mac_context *mac, struct pe_session *pe_session) +{ + if (!pe_session) + return mac->rrm.rrmPEContext.txMgmtPower; + + pe_debug("tx mgmt pwr %d", pe_session->txMgmtPower); + + return pe_session->txMgmtPower; +} + +/** + * rrm_send_set_max_tx_power_req() - Send WMA_SET_MAX_TX_POWER_REQ message + * to change the max tx power. + * @mac: pointer to mac context + * @txPower: TX power to be set + * @pe_session: per vdev pe context + * + * Return: None + */ +QDF_STATUS +rrm_send_set_max_tx_power_req(struct mac_context *mac, int8_t txPower, + struct pe_session *pe_session) +{ + tpMaxTxPowerParams pMaxTxParams; + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + struct scheduler_msg msgQ = {0}; + + if (!pe_session) { + pe_err("Invalid parameters"); + return QDF_STATUS_E_FAILURE; + } + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (!pMaxTxParams) + return QDF_STATUS_E_NOMEM; + /* Allocated memory for pMaxTxParams...will be freed in other module */ + pMaxTxParams->power = txPower; + qdf_mem_copy(pMaxTxParams->bssId.bytes, pe_session->bssId, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(pMaxTxParams->selfStaMacAddr.bytes, + pe_session->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + msgQ.type = WMA_SET_MAX_TX_POWER_REQ; + msgQ.reserved = 0; + msgQ.bodyptr = pMaxTxParams; + msgQ.bodyval = 0; + + pe_debug("Sending WMA_SET_MAX_TX_POWER_REQ with power(%d) to HAL", + txPower); + + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("Posting WMA_SET_MAX_TX_POWER_REQ to HAL failed, reason=%X", + retCode); + qdf_mem_free(pMaxTxParams); + return retCode; + } + return retCode; +} + +/** + * rrm_set_max_tx_power_rsp() - Process WMA_SET_MAX_TX_POWER_RSP message + * @mac: pointer to mac context + * @limMsgQ: pointer to scheduler message + * + * Return: None + */ +QDF_STATUS rrm_set_max_tx_power_rsp(struct mac_context *mac, + struct scheduler_msg *limMsgQ) +{ + QDF_STATUS retCode = QDF_STATUS_SUCCESS; + tpMaxTxPowerParams pMaxTxParams = (tpMaxTxPowerParams) limMsgQ->bodyptr; + struct pe_session *pe_session; + uint8_t sessionId, i; + + if (qdf_is_macaddr_broadcast(&pMaxTxParams->bssId)) { + for (i = 0; i < mac->lim.maxBssId; i++) { + if (mac->lim.gpSession[i].valid == true) { + pe_session = &mac->lim.gpSession[i]; + rrm_cache_mgmt_tx_power(mac, pMaxTxParams->power, + pe_session); + } + } + } else { + pe_session = pe_find_session_by_bssid(mac, + pMaxTxParams->bssId.bytes, + &sessionId); + if (!pe_session) { + retCode = QDF_STATUS_E_FAILURE; + } else { + rrm_cache_mgmt_tx_power(mac, pMaxTxParams->power, + pe_session); + } + } + + qdf_mem_free(limMsgQ->bodyptr); + limMsgQ->bodyptr = NULL; + return retCode; +} + +/** + * rrm_calculate_and_fill_rcpi() - calculates and fills RCPI value + * @rcpi: pointer to hold calculated RCPI value + * @cur_rssi: value of current RSSI + * + * @return None + */ +static void rrm_calculate_and_fill_rcpi(uint8_t *rcpi, int8_t cur_rssi) +{ + /* 2008 11k spec reference: 18.4.8.5 RCPI Measurement */ + if (cur_rssi <= RCPI_LOW_RSSI_VALUE) + *rcpi = 0; + else if ((cur_rssi > RCPI_LOW_RSSI_VALUE) && (cur_rssi <= 0)) + *rcpi = CALCULATE_RCPI(cur_rssi); + else + *rcpi = RCPI_MAX_VALUE; +} + +/** + * rrm_process_link_measurement_request() - Processes the Link measurement + * request and send the report. + * @mac: pointer to mac context + * @pRxPacketInfo: pointer to packet info structure + * @pLinkReq: pointer to the Link request frame structure. + * @pe_session: session entry. + * + * Return: None + */ +QDF_STATUS +rrm_process_link_measurement_request(struct mac_context *mac, + uint8_t *pRxPacketInfo, + tDot11fLinkMeasurementRequest *pLinkReq, + struct pe_session *pe_session) +{ + tSirMacLinkReport LinkReport = {0}; + tpSirMacMgmtHdr pHdr; + int8_t currentRSSI = 0; + struct vdev_mlme_obj *mlme_obj; + struct wlan_lmac_if_reg_tx_ops *tx_ops; + uint8_t ap_pwr_constraint = 0; + + pe_debug("Received Link measurement request"); + + if (!pRxPacketInfo || !pLinkReq || !pe_session) { + pe_err("Invalid parameters - Ignoring the request"); + return QDF_STATUS_E_FAILURE; + } + pHdr = WMA_GET_RX_MAC_HEADER(pRxPacketInfo); + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* + * STA LPI + SAP VLP is supported. For this STA should operate in VLP + * power level of the SAP. + * If STA is operating in VLP power of SAP, do not update STA power. + */ + if (wlan_reg_is_ext_tpc_supported(mac->psoc) && + !pe_session->sta_follows_sap_power) { + ap_pwr_constraint = mlme_obj->reg_tpc_obj.ap_constraint_power; + mlme_obj->reg_tpc_obj.ap_constraint_power = + pLinkReq->MaxTxPower.maxTxPower; + /* Set is_power_constraint_abs to true to calculate tpc power */ + mlme_obj->reg_tpc_obj.is_power_constraint_abs = true; + lim_calculate_tpc(mac, pe_session); + + LinkReport.txPower = + mlme_obj->reg_tpc_obj.chan_power_info[0].tx_power; + /** If hardware limit received from FW is non zero, use it + * to limit the link tx power. + */ + if (mlme_obj->mgmt.generic.tx_pwrlimit) { + LinkReport.txPower = + QDF_MIN(LinkReport.txPower, + mlme_obj->mgmt.generic.tx_pwrlimit); + pe_debug("HW power limit: %d, Link tx power: %d", + mlme_obj->mgmt.generic.tx_pwrlimit, + LinkReport.txPower); + } + if (LinkReport.txPower < MIN_TX_PWR_CAP) + LinkReport.txPower = MIN_TX_PWR_CAP; + else if (LinkReport.txPower > MAX_TX_PWR_CAP) + LinkReport.txPower = MAX_TX_PWR_CAP; + + if (pLinkReq->MaxTxPower.maxTxPower != ap_pwr_constraint) { + tx_ops = wlan_reg_get_tx_ops(mac->psoc); + + if (tx_ops->set_tpc_power) + tx_ops->set_tpc_power(mac->psoc, + pe_session->vdev_id, + &mlme_obj->reg_tpc_obj); + } + } else if (!pe_session->sta_follows_sap_power) { + mlme_obj->reg_tpc_obj.reg_max[0] = + pe_session->def_max_tx_pwr; + mlme_obj->reg_tpc_obj.ap_constraint_power = + pLinkReq->MaxTxPower.maxTxPower; + + LinkReport.txPower = lim_get_max_tx_power(mac, mlme_obj); + + /** If firmware updated max tx power is non zero, respond to + * rrm link measurement request with min of firmware updated + * ap tx power and max power derived from lim_get_max_tx_power + * API. + */ + if (mlme_obj && mlme_obj->mgmt.generic.tx_pwrlimit) + LinkReport.txPower = QDF_MIN(LinkReport.txPower, + mlme_obj->mgmt.generic.tx_pwrlimit); + + if ((LinkReport.txPower != (uint8_t)pe_session->maxTxPower) && + (QDF_STATUS_SUCCESS == + rrm_send_set_max_tx_power_req(mac, LinkReport.txPower, + pe_session))) { + pe_warn("Local: %d", pe_session->maxTxPower); + pe_session->maxTxPower = LinkReport.txPower; + } + } + pe_warn_rl("Link Request Tx Pwr: %d Link Report Tx Pwr: %d", + pLinkReq->MaxTxPower.maxTxPower, LinkReport.txPower); + + LinkReport.dialogToken = pLinkReq->DialogToken.token; + LinkReport.rxAntenna = 0; + LinkReport.txAntenna = 0; + currentRSSI = WMA_GET_RX_RSSI_RAW(pRxPacketInfo); + + pe_info_rl("Received Link report frame with %d", currentRSSI); + + rrm_calculate_and_fill_rcpi(&LinkReport.rcpi, currentRSSI); + LinkReport.rsni = WMA_GET_RX_SNR(pRxPacketInfo); + + pe_debug("Sending Link report frame"); + + return lim_send_link_report_action_frame(mac, &LinkReport, pHdr->sa, + pe_session); +} + +/** + * rrm_process_neighbor_report_response() - Processes the Neighbor Report + * response from the peer AP. + * @mac: pointer to mac context + * @pNeighborRep: pointer to the Neighbor report frame structure. + * @pe_session: session entry. + * + * Return: None + */ +QDF_STATUS +rrm_process_neighbor_report_response(struct mac_context *mac, + tDot11fNeighborReportResponse *pNeighborRep, + struct pe_session *pe_session) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportInd pSmeNeighborRpt = NULL; + uint16_t length; + uint8_t i; + struct scheduler_msg mmhMsg = {0}; + + if (!pNeighborRep || !pe_session) { + pe_err("Invalid parameters"); + return status; + } + + pe_debug("Neighbor report response received"); + + /* Dialog token */ + if (mac->rrm.rrmPEContext.DialogToken != + pNeighborRep->DialogToken.token) { + pe_err("Dialog token mismatch in the received Neighbor report"); + return QDF_STATUS_E_FAILURE; + } + if (pNeighborRep->num_NeighborReport == 0) { + pe_err("No neighbor report in the frame...Dropping it"); + return QDF_STATUS_E_FAILURE; + } + pe_debug("RRM:received num neighbor reports: %d", + pNeighborRep->num_NeighborReport); + if (pNeighborRep->num_NeighborReport > MAX_SUPPORTED_NEIGHBOR_RPT) + pNeighborRep->num_NeighborReport = MAX_SUPPORTED_NEIGHBOR_RPT; + length = (sizeof(tSirNeighborReportInd)) + + (sizeof(tSirNeighborBssDescription) * + (pNeighborRep->num_NeighborReport - 1)); + + /* Prepare the request to send to SME. */ + pSmeNeighborRpt = qdf_mem_malloc(length); + if (!pSmeNeighborRpt) + return QDF_STATUS_E_NOMEM; + + /* Allocated memory for pSmeNeighborRpt...will be freed by other module */ + + for (i = 0; i < pNeighborRep->num_NeighborReport; i++) { + pSmeNeighborRpt->sNeighborBssDescription[i].length = sizeof(tSirNeighborBssDescription); /*+ any optional ies */ + qdf_mem_copy(pSmeNeighborRpt->sNeighborBssDescription[i].bssId, + pNeighborRep->NeighborReport[i].bssid, + sizeof(tSirMacAddr)); + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fApPreauthReachable = + pNeighborRep->NeighborReport[i].APReachability; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fSameSecurityMode = + pNeighborRep->NeighborReport[i].Security; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fSameAuthenticator = + pNeighborRep->NeighborReport[i].KeyScope; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapSpectrumMeasurement = + pNeighborRep->NeighborReport[i].SpecMgmtCap; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapQos = pNeighborRep->NeighborReport[i].QosCap; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapApsd = pNeighborRep->NeighborReport[i].apsd; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapRadioMeasurement = pNeighborRep->NeighborReport[i].rrm; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapDelayedBlockAck = + pNeighborRep->NeighborReport[i].DelayedBA; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fCapImmediateBlockAck = + pNeighborRep->NeighborReport[i].ImmBA; + pSmeNeighborRpt->sNeighborBssDescription[i].bssidInfo.rrmInfo. + fMobilityDomain = + pNeighborRep->NeighborReport[i].MobilityDomain; + + if (!wlan_reg_is_6ghz_supported(mac->psoc) && + (wlan_reg_is_6ghz_op_class(mac->pdev, + pNeighborRep->NeighborReport[i]. + regulatoryClass))) { + pe_err("channel belongs to 6 ghz spectrum, abort"); + qdf_mem_free(pSmeNeighborRpt); + return QDF_STATUS_E_FAILURE; + } + + pSmeNeighborRpt->sNeighborBssDescription[i].regClass = + pNeighborRep->NeighborReport[i].regulatoryClass; + pSmeNeighborRpt->sNeighborBssDescription[i].channel = + pNeighborRep->NeighborReport[i].channel; + pSmeNeighborRpt->sNeighborBssDescription[i].phyType = + pNeighborRep->NeighborReport[i].PhyType; + } + + pSmeNeighborRpt->messageType = eWNI_SME_NEIGHBOR_REPORT_IND; + pSmeNeighborRpt->length = length; + pSmeNeighborRpt->measurement_idx = DEFAULT_RRM_IDX; + pSmeNeighborRpt->sessionId = pe_session->smeSessionId; + pSmeNeighborRpt->numNeighborReports = pNeighborRep->num_NeighborReport; + qdf_mem_copy(pSmeNeighborRpt->bssId, pe_session->bssId, + sizeof(tSirMacAddr)); + + /* Send request to SME. */ + mmhMsg.type = pSmeNeighborRpt->messageType; + mmhMsg.bodyptr = pSmeNeighborRpt; + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmhMsg.type)); + lim_sys_process_mmh_msg_api(mac, &mmhMsg); + + return status; + +} + +/** + * rrm_process_neighbor_report_req() - Create a Neighbor report request + * and send it to peer. + * @mac: pointer to mac context + * @pNeighborReq: Neighbor report request params + * + * Return: None + */ +QDF_STATUS +rrm_process_neighbor_report_req(struct mac_context *mac, + tpSirNeighborReportReqInd pNeighborReq) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMacNeighborReportReq NeighborReportReq; + struct pe_session *pe_session; + uint8_t sessionId; + + if (!pNeighborReq) { + pe_err("NeighborReq is NULL"); + return QDF_STATUS_E_FAILURE; + } + pe_session = pe_find_session_by_bssid(mac, pNeighborReq->bssId, + &sessionId); + if (!pe_session) { + pe_err("session does not exist for given bssId"); + return QDF_STATUS_E_FAILURE; + } + + pe_debug("SSID present: %d", pNeighborReq->noSSID); + + qdf_mem_zero(&NeighborReportReq, sizeof(tSirMacNeighborReportReq)); + + NeighborReportReq.dialogToken = ++mac->rrm.rrmPEContext.DialogToken; + NeighborReportReq.ssid_present = !pNeighborReq->noSSID; + if (NeighborReportReq.ssid_present) { + qdf_mem_copy(&NeighborReportReq.ssid, &pNeighborReq->ucSSID, + sizeof(tSirMacSSid)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, + QDF_TRACE_LEVEL_DEBUG, + (uint8_t *) NeighborReportReq.ssid.ssId, + NeighborReportReq.ssid.length); + } + + status = + lim_send_neighbor_report_request_frame(mac, &NeighborReportReq, + pNeighborReq->bssId, + pe_session); + + return status; +} + +void rrm_get_country_code_from_connected_profile(struct mac_context *mac, + uint8_t vdev_id, + uint8_t *country_code) +{ + QDF_STATUS status; + + status = wlan_cm_get_country_code(mac->pdev, vdev_id, country_code); + + pe_debug("Country info from bcn:%c%c 0x%x", country_code[0], + country_code[1], country_code[2]); + + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_zero(country_code, REG_ALPHA2_LEN + 1); + + if (!country_code[0]) { + wlan_reg_read_current_country(mac->psoc, country_code); + country_code[2] = OP_CLASS_GLOBAL; + pe_debug("Current country info %c%c 0x%x", country_code[0], + country_code[1], country_code[2]); + } +} + +#ifdef CONNECTIVITY_DIAG_EVENT +/** + * wlan_diag_log_beacon_rpt_req_event() - Send Beacon Report Request logging + * event. + * @token: Dialog token + * @mode: Measurement mode + * @op_class: operating class + * @chan: channel number + * @req_mode: Request mode + * @duration: The duration over which the Beacon report was measured + * @pe_session: pe session pointer + */ +static void +wlan_diag_log_beacon_rpt_req_event(uint8_t token, uint8_t mode, + uint8_t op_class, uint8_t chan, + uint8_t req_mode, uint32_t duration, + struct pe_session *pe_session) +{ + WLAN_HOST_DIAG_EVENT_DEF(wlan_diag_event, struct wlan_diag_bcn_rpt); + + qdf_mem_zero(&wlan_diag_event, sizeof(wlan_diag_event)); + + wlan_diag_event.diag_cmn.vdev_id = wlan_vdev_get_id(pe_session->vdev); + wlan_diag_event.diag_cmn.timestamp_us = qdf_get_time_of_the_day_us(); + wlan_diag_event.diag_cmn.ktime_us = qdf_ktime_to_us(qdf_ktime_get()); + + wlan_diag_event.subtype = WLAN_CONN_DIAG_BCN_RPT_REQ_EVENT; + wlan_diag_event.version = DIAG_BCN_RPT_VERSION_2; + + if (mlo_is_mld_sta(pe_session->vdev)) + wlan_diag_event.band = + wlan_convert_freq_to_diag_band(pe_session->curr_op_freq); + + wlan_diag_event.meas_token = token; + wlan_diag_event.mode = mode; + wlan_diag_event.op_class = op_class; + wlan_diag_event.chan = chan; + wlan_diag_event.duration = duration; + wlan_diag_event.req_mode = req_mode; + + WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_BCN_RPT); +} +#else +static void +wlan_diag_log_beacon_rpt_req_event(uint8_t token, uint8_t mode, + uint8_t op_class, uint8_t chan, + uint8_t req_mode, uint32_t duration, + struct pe_session *pe_session) +{ +} +#endif + +#define ABS(x) ((x < 0) ? -x : x) + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +/** + * rrm_update_mac_cp_stats: update stats of rrm structure of mac + * @ev: cp stats event + * @mac_ctx: mac context + * + * Return: None + */ +static inline void +rrm_update_mac_cp_stats(struct infra_cp_stats_event *ev, + struct mac_context *mac_ctx) +{ + tpSirMacRadioMeasureReport rrm_report; + struct counter_stats *counter_stats; + struct group_id_0 ev_counter_stats; + struct mac_stats *mac_stats; + struct group_id_1 ev_mac_stats; + + rrm_report = &mac_ctx->rrm.rrmPEContext.rrm_sta_stats.rrm_report; + + counter_stats = + &rrm_report->report.statistics_report.group_stats.counter_stats; + mac_stats = + &rrm_report->report.statistics_report.group_stats.mac_stats; + + ev_counter_stats = ev->sta_stats->group.counter_stats; + ev_mac_stats = ev->sta_stats->group.mac_stats; + + switch (rrm_report->report.statistics_report.group_id) { + /* + * Assign count diff in mac rrm sta stats report. + * For first event callback stats will be same as + * send by FW because memset is done for mac rrm sta + * stats before sending rrm sta stats request to FW and + * for second request stats will be the diff of stats send + * by FW and previous stats. + */ + case STA_STAT_GROUP_ID_COUNTER_STATS: + counter_stats->failed_count = + ev_counter_stats.failed_count - + counter_stats->failed_count; + counter_stats->group_received_frame_count = + ev_counter_stats.group_received_frame_count - + counter_stats->group_received_frame_count; + counter_stats->fcs_error_count = + ev_counter_stats.fcs_error_count - + counter_stats->fcs_error_count; + counter_stats->transmitted_frame_count = + ev_counter_stats.transmitted_frame_count - + counter_stats->transmitted_frame_count; + break; + case STA_STAT_GROUP_ID_MAC_STATS: + mac_stats->rts_success_count = + ev_mac_stats.rts_success_count - + mac_stats->rts_success_count; + mac_stats->rts_failure_count = + ev_mac_stats.rts_failure_count - + mac_stats->rts_failure_count; + mac_stats->ack_failure_count = + ev_mac_stats.ack_failure_count - + mac_stats->ack_failure_count; + break; + default: + pe_debug("group id not supported"); + } + pe_nofl_debug("counter stats: group rx frame count %d failed_count %d fcs_error %d tx frame count %d mac stats: rts success count %d rts fail count %d ack fail count %d", + counter_stats->group_received_frame_count, + counter_stats->failed_count, + counter_stats->fcs_error_count, + counter_stats->transmitted_frame_count, + mac_stats->rts_success_count, + mac_stats->rts_failure_count, + mac_stats->ack_failure_count); +} + +/** + * rmm_sta_stats_response_cb: RRM sta stats response callback + * @ev: cp stats event + * @cookie: NULL + * + * Return: None + */ +static inline +void rmm_sta_stats_response_cb(struct infra_cp_stats_event *ev, void *cookie) +{ + struct mac_context *mac; + struct pe_session *session; + uint8_t vdev_id, index; + QDF_STATUS status; + tpRRMReq pcurrent_req; + tSirMacRadioMeasureReport *rrm_report; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) + return; + index = mac->rrm.rrmPEContext.rrm_sta_stats.index; + + /* Deregister callback registered in request */ + status = wlan_cp_stats_infra_cp_deregister_resp_cb(mac->psoc); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("failed to deregister callback %d", status); + + pcurrent_req = mac->rrm.rrmPEContext.pCurrentReq[index]; + if (!pcurrent_req) { + pe_err("Current request is NULL"); + qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats, + sizeof(mac->rrm.rrmPEContext.rrm_sta_stats)); + return; + } + + vdev_id = mac->rrm.rrmPEContext.rrm_sta_stats.vdev_id; + session = pe_find_session_by_vdev_id(mac, vdev_id); + if (!session) { + pe_err("Session does not exist for given vdev id %d", vdev_id); + rrm_cleanup(mac, mac->rrm.rrmPEContext.rrm_sta_stats.index); + return; + } + + rrm_report = &mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report; + rrm_update_mac_cp_stats(ev, mac); + + /* Update resp counter for every response to find second resp*/ + mac->rrm.rrmPEContext.rrm_sta_stats.rrm_sta_stats_res_count++; + /* Send current stats if meas duration is 0. */ + if (mac->rrm.rrmPEContext.rrm_sta_stats.rrm_sta_stats_res_count == + MAX_RMM_STA_STATS_REQUESTED || + !rrm_report->report.statistics_report.meas_duration) { + lim_send_radio_measure_report_action_frame( + mac, pcurrent_req->dialog_token, 1, true, + &mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report, + mac->rrm.rrmPEContext.rrm_sta_stats.peer, session); + + rrm_cleanup(mac, index); + } +} + +/** + * rrm_update_vdev_stats: Update RRM stats from DP + * @rrm_report: RRM Measurement Report + * @vdev_id: vdev_id + * + * Return: QDF STATUS + */ +static QDF_STATUS +rrm_update_vdev_stats(tpSirMacRadioMeasureReport rrm_report, uint8_t vdev_id) +{ + struct cdp_vdev_stats *stats; + QDF_STATUS status; + struct counter_stats *counter_stats; + struct mac_stats *mac_stats; + + counter_stats = + &rrm_report->report.statistics_report.group_stats.counter_stats; + mac_stats = + &rrm_report->report.statistics_report.group_stats.mac_stats; + + stats = qdf_mem_malloc(sizeof(*stats)); + if (!stats) + return QDF_STATUS_E_NOMEM; + + status = + cdp_host_get_vdev_stats(cds_get_context(QDF_MODULE_ID_SOC), + vdev_id, stats, true); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to get stats %d", status); + qdf_mem_free(stats); + return QDF_STATUS_E_FAILURE; + } + + pe_nofl_debug("counter stats count: fragment (tx: %d rx: %d) group tx: %llu mac stats count: retry : %d multiple retry: %d frame duplicate %d", + stats->tx.fragment_count, stats->rx.fragment_count, + stats->tx.mcast.num, stats->tx.retry_count, + stats->tx.multiple_retry_count, + stats->rx.duplicate_count); + + switch (rrm_report->report.statistics_report.group_id) { + case STA_STAT_GROUP_ID_COUNTER_STATS: + counter_stats->transmitted_fragment_count = + stats->tx.fragment_count - + counter_stats->transmitted_fragment_count; + counter_stats->received_fragment_count = + stats->rx.fragment_count - + counter_stats->received_fragment_count; + counter_stats->group_transmitted_frame_count = + stats->tx.mcast.num - + counter_stats->group_transmitted_frame_count; + break; + case STA_STAT_GROUP_ID_MAC_STATS: + mac_stats->retry_count = + stats->tx.retry_count - mac_stats->retry_count; + mac_stats->multiple_retry_count = + stats->tx.multiple_retry_count - + mac_stats->multiple_retry_count; + mac_stats->frame_duplicate_count = + stats->rx.duplicate_count - + mac_stats->frame_duplicate_count; + break; + } + qdf_mem_free(stats); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +rrm_send_sta_stats_req(struct mac_context *mac, + struct pe_session *session, + tSirMacAddr peer_mac) +{ + struct infra_cp_stats_cmd_info info = {0}; + get_infra_cp_stats_cb resp_cb = NULL; + void *context; + QDF_STATUS status; + tpSirMacRadioMeasureReport report; + + status = wlan_cp_stats_infra_cp_get_context(mac->psoc, &resp_cb, + &context); + if (resp_cb) { + pe_err("another request already in progress"); + return QDF_STATUS_E_FAILURE; + } + + info.request_cookie = NULL; + info.stats_id = TYPE_REQ_CTRL_PATH_RRM_STA_STAT; + info.action = ACTION_REQ_CTRL_PATH_STAT_GET; + info.infra_cp_stats_resp_cb = rmm_sta_stats_response_cb; + info.num_pdev_ids = 0; + info.num_vdev_ids = MAX_CTRL_STAT_VDEV_ENTRIES; + info.vdev_id[0] = wlan_vdev_get_id(session->vdev); + info.num_mac_addr_list = MAX_CTRL_STAT_MAC_ADDR_ENTRIES; + info.num_pdev_ids = 0; + /* + * FW doesn't send vdev id in response path. + * So, vdev id will be used to get session + * in callback. + */ + mac->rrm.rrmPEContext.rrm_sta_stats.vdev_id = + wlan_vdev_get_id(session->vdev); + qdf_mem_copy(&info.peer_mac_addr[0], peer_mac, QDF_MAC_ADDR_SIZE); + report = &mac->rrm.rrmPEContext.rrm_sta_stats.rrm_report; + + status = rrm_update_vdev_stats(report, wlan_vdev_get_id(session->vdev)); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to register resp callback: %d", status); + return status; + } + + status = wlan_cp_stats_infra_cp_register_resp_cb(mac->psoc, &info); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to register resp callback: %d", status); + return status; + } + + status = wlan_cp_stats_send_infra_cp_req(mac->psoc, &info); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to send stats request status: %d", status); + goto get_stats_fail; + } + + return QDF_STATUS_SUCCESS; + +get_stats_fail: + status = wlan_cp_stats_infra_cp_deregister_resp_cb(mac->psoc); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("failed to deregister callback %d", status); + return status; +} +#endif + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_max_meas_duration() - calculate max measurement duration for a + * rrm req + * @mac: global mac context + * @pe_session: per vdev pe context + * + * Return: max measurement duration + */ +static uint16_t rrm_get_max_meas_duration(struct mac_context *mac, + struct pe_session *pe_session) +{ + int8_t max_dur; + uint16_t max_meas_dur, sign; + + /* + * The logic here is to check the measurement duration passed in the + * beacon request. Following are the cases handled. + * Case 1: If measurement duration received in the beacon request is + * greater than the max measurement duration advertised in the RRM + * capabilities(Assoc Req), and Duration Mandatory bit is set to 1, + * REFUSE the beacon request. + * Case 2: If measurement duration received in the beacon request is + * greater than the max measurement duration advertised in the RRM + * capabilities(Assoc Req), and Duration Mandatory bit is set to 0, + * perform measurement for the duration advertised in the + * RRM capabilities + * maxMeasurementDuration = 2^(nonOperatingChanMax - 4) * BeaconInterval + */ + max_dur = mac->rrm.rrmPEContext.rrmEnabledCaps.nonOperatingChanMax - 4; + sign = (max_dur < 0) ? 1 : 0; + max_dur = (1L << ABS(max_dur)); + if (!sign) + max_meas_dur = + max_dur * pe_session->beaconParams.beaconInterval; + else + max_meas_dur = + pe_session->beaconParams.beaconInterval / max_dur; + + return max_meas_dur; +} + +/** + * rrm_process_sta_stats_report_req: Process RRM sta stats request + * @mac: mac context + * @pCurrentReq: Current RRM request + * @sta_stats_req: RRM Measurement Request + * @pe_session: pe session + * + * Return: rrm status + */ +static tRrmRetStatus +rrm_process_sta_stats_report_req(struct mac_context *mac, + tpRRMReq pCurrentReq, + tDot11fIEMeasurementRequest *sta_stats_req, + struct pe_session *pe_session) +{ + QDF_STATUS status; + uint16_t meas_duration = MIN_MEAS_DURATION_FOR_STA_STATS; + uint8_t max_meas_duration; + struct rrm_sta_stats *rrm_sta_statistics; + + max_meas_duration = rrm_get_max_meas_duration(mac, pe_session); + + /* + * Keep timer value atleast of 10 ms even if measurement duration + * provided in meas request is < 10 ms because FW takes some time to + * calculate and respond stats. + * Start timer of 10 ms even if meas duration is 0. + * To get stats from FW. + */ + if (sta_stats_req->measurement_request.sta_stats.meas_duration > + MIN_MEAS_DURATION_FOR_STA_STATS) + meas_duration = + sta_stats_req->measurement_request.sta_stats.meas_duration; + + if (meas_duration > max_meas_duration) { + if (sta_stats_req->durationMandatory) { + pe_nofl_err("Dropping the req: duration mandatory & max duration > meas duration"); + return eRRM_REFUSED; + } + meas_duration = max_meas_duration; + } + if (qdf_is_macaddr_broadcast((struct qdf_mac_addr *) + sta_stats_req->measurement_request.sta_stats.peer_mac_addr)) { + pe_err("Dropping req: broadcast address not supported"); + return eRRM_INCAPABLE; + } + + rrm_sta_statistics = &mac->rrm.rrmPEContext.rrm_sta_stats; + + rrm_sta_statistics->rrm_report.token = pCurrentReq->token; + rrm_sta_statistics->rrm_report.type = pCurrentReq->type; + rrm_sta_statistics->rrm_report.refused = 0; + rrm_sta_statistics->rrm_report.incapable = 0; + rrm_sta_statistics->rrm_report.report.statistics_report.group_id = + sta_stats_req->measurement_request.sta_stats.group_identity; + rrm_sta_statistics->rrm_report.report.statistics_report.meas_duration + = sta_stats_req->measurement_request.sta_stats.meas_duration; + + switch (sta_stats_req->measurement_request.sta_stats.group_identity) { + case STA_STAT_GROUP_ID_COUNTER_STATS: + case STA_STAT_GROUP_ID_MAC_STATS: + status = + rrm_send_sta_stats_req( + mac, pe_session, + sta_stats_req->measurement_request.sta_stats.peer_mac_addr); + if (!QDF_IS_STATUS_SUCCESS(status)) + return eRRM_REFUSED; + mac->lim.lim_timers.rrm_sta_stats_resp_timer.sessionId = + pe_session->peSessionId; + tx_timer_change(&mac->lim.lim_timers.rrm_sta_stats_resp_timer, + SYS_MS_TO_TICKS(meas_duration), 0); + /* Activate sta stats resp timer */ + if (tx_timer_activate( + &mac->lim.lim_timers.rrm_sta_stats_resp_timer) != + TX_SUCCESS) { + pe_err("failed to start sta stats timer"); + return eRRM_REFUSED; + } + break; + case STA_STAT_GROUP_ID_DELAY_STATS: + /* TODO: update access delay from scan IE */ + default: + pe_nofl_err("group id %d not supported", + sta_stats_req->measurement_request.sta_stats.group_identity); + return eRRM_INCAPABLE; + } + return eRRM_SUCCESS; +} + +void +rrm_process_rrm_sta_stats_request_failure(struct mac_context *mac, + struct pe_session *pe_session, + tSirMacAddr peer, + tRrmRetStatus status, uint8_t index) +{ + tpSirMacRadioMeasureReport p_report = NULL; + tpRRMReq p_current_req = mac->rrm.rrmPEContext.pCurrentReq[index]; + + if (!p_current_req) { + pe_err("Current request is NULL"); + return; + } + + p_report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (!p_report) + return; + p_report->token = p_current_req->token; + p_report->type = SIR_MAC_RRM_STA_STATISTICS_TYPE; + + pe_debug("Measurement index:%d status %d token %d", index, status, + p_report->token); + + switch (status) { + case eRRM_FAILURE: /* fallthrough */ + case eRRM_REFUSED: + p_report->refused = 1; + break; + case eRRM_INCAPABLE: + p_report->incapable = 1; + break; + default: + pe_err("Invalid RRM status, failed to send report"); + qdf_mem_free(p_report); + return; + } + + lim_send_radio_measure_report_action_frame(mac, + p_current_req->dialog_token, + 1, true, + p_report, peer, + pe_session); + + qdf_mem_free(p_report); +} + +/** + * rrm_check_other_sta_sats_req_in_progress: To check if any other sta stats req + * in progress + * @rrm_req: measurement request + * + * To avoid any conflict between multiple sta stats request at time of callback + * response from FW handle one sta stats request at a time. + * + * Return: true/false + */ +static bool +rrm_check_other_sta_sats_req_in_progress( + tDot11fRadioMeasurementRequest *rrm_req) +{ + uint8_t count = 0, i = 0; + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) { + if (rrm_req->MeasurementRequest[i].measurement_type == + SIR_MAC_RRM_STA_STATISTICS_TYPE) + count++; + if (count > 1) + return true; + } + return false; +} + +/** + * rrm_process_sta_stats_req: Process RRM sta stats request + * @mac: mac context + * @peer: peer mac + * @session_entry: pe session + * @radiomes_report: measurement report + * @rrm_req: measurement request + * @num_report: no of reports + * @index: index of request + * + * Return: QDF_STATUS + */ +static +QDF_STATUS rrm_process_sta_stats_req( + struct mac_context *mac, tSirMacAddr peer, + struct pe_session *session_entry, + tpSirMacRadioMeasureReport *radiomes_report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + tRrmRetStatus rrm_status = eRRM_SUCCESS; + tpRRMReq curr_req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (index >= MAX_MEASUREMENT_REQUEST) { + status = rrm_reject_req(radiomes_report, + rrm_req, num_report, index, + rrm_req->MeasurementRequest[0]. + measurement_type); + return status; + } + + if (rrm_check_other_sta_sats_req_in_progress(rrm_req)) { + pe_debug("another sta stats request already in progress"); + return QDF_STATUS_E_FAILURE; + } + + curr_req = qdf_mem_malloc(sizeof(*curr_req)); + if (!curr_req) { + mac->rrm.rrmPEContext.pCurrentReq[index] = NULL; + qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats, + sizeof(mac->rrm.rrmPEContext.rrm_sta_stats)); + return QDF_STATUS_E_NOMEM; + } + + curr_req->dialog_token = rrm_req->DialogToken.token; + curr_req->token = + rrm_req->MeasurementRequest[index].measurement_token; + curr_req->measurement_idx = index; + curr_req->type = rrm_req->MeasurementRequest[index].measurement_type; + + + qdf_mem_set(&mac->rrm.rrmPEContext.rrm_sta_stats, + sizeof(mac->rrm.rrmPEContext.rrm_sta_stats), 0); + + mac->rrm.rrmPEContext.rrm_sta_stats.index = index; + mac->rrm.rrmPEContext.pCurrentReq[index] = curr_req; + mac->rrm.rrmPEContext.num_active_request++; + qdf_mem_copy(mac->rrm.rrmPEContext.rrm_sta_stats.peer, + peer, + QDF_MAC_ADDR_SIZE); + + pe_debug("Processing sta stats Report req %d num_active_req:%d", + index, mac->rrm.rrmPEContext.num_active_request); + + rrm_status = rrm_process_sta_stats_report_req(mac, curr_req, + &rrm_req->MeasurementRequest[index], session_entry); + if (eRRM_SUCCESS != rrm_status) + goto failure; + + return QDF_STATUS_SUCCESS; +failure: + rrm_process_rrm_sta_stats_request_failure( + mac, session_entry, peer, rrm_status, index); + + rrm_cleanup(mac, index); + return QDF_STATUS_E_FAILURE; +} + +/** + * rrm_process_beacon_report_req() - Processes the Beacon report request + * from the peer AP + * @mac: pointer to mac context + * @pCurrentReq: pointer to the current Req comtext + * @pBeaconReq: pointer to the beacon report request IE from the peer + * @pe_session: session entry + * + * Return: None + */ +static tRrmRetStatus +rrm_process_beacon_report_req(struct mac_context *mac, + tpRRMReq pCurrentReq, + tDot11fIEMeasurementRequest *pBeaconReq, + struct pe_session *pe_session) +{ + struct scheduler_msg mmh_msg = {0}; + tpSirBeaconReportReqInd psbrr; + uint8_t num_rpt, idx_rpt; + uint16_t measDuration, maxMeasduration; + tDot11fIEAPChannelReport *ie_ap_chan_rpt; + uint8_t tmp_idx, buf_left, buf_cons; + uint16_t ch_ctr = 0; + char ch_buf[RRM_CH_BUF_LEN]; + char *tmp_buf = NULL; + uint8_t country[WNI_CFG_COUNTRY_CODE_LEN]; + uint8_t req_mode; + uint8_t i; + + if (!pe_session) { + pe_err("pe_session is NULL"); + return eRRM_INCAPABLE; + } + + if (wlan_policy_mgr_get_ll_lt_sap_vdev_id(mac->psoc) != WLAN_INVALID_VDEV_ID) { + pe_debug("RX: [802.11 BCN_RPT] reject req as ll_lt_sap is present"); + return eRRM_REFUSED; + } + + if (pBeaconReq->measurement_request.Beacon.rrm_reporting.present && + (pBeaconReq->measurement_request.Beacon.rrm_reporting.reporting_condition != 0)) { + /* Repeated measurement is not supported. This means number of repetitions should be zero.(Already checked) */ + /* All test case in VoWifi(as of version 0.36) use zero for number of repetitions. */ + /* Beacon reporting should not be included in request if number of repetitons is zero. */ + /* IEEE Std 802.11k-2008 Table 7-29g and section 11.10.8.1 */ + + pe_nofl_err("RX: [802.11 BCN_RPT] Dropping req: Reporting condition included is not zero"); + return eRRM_INCAPABLE; + } + + maxMeasduration = rrm_get_max_meas_duration(mac, pe_session); + if( pBeaconReq->measurement_request.Beacon.meas_mode == + eSIR_PASSIVE_SCAN) + maxMeasduration += 10; + + measDuration = pBeaconReq->measurement_request.Beacon.meas_duration; + + pe_nofl_rl_info("RX: [802.11 BCN_RPT] seq:%d SSID:" QDF_SSID_FMT " BSSID:" QDF_MAC_ADDR_FMT " Token:%d op_class:%d ch:%d meas_mode:%d meas_duration:%d max_meas_dur: %d", + mac->rrm.rrmPEContext.prev_rrm_report_seq_num, + QDF_SSID_REF( + pBeaconReq->measurement_request.Beacon.SSID.num_ssid, + pBeaconReq->measurement_request.Beacon.SSID.ssid), + QDF_MAC_ADDR_REF( + pBeaconReq->measurement_request.Beacon.BSSID), + pBeaconReq->measurement_token, + pBeaconReq->measurement_request.Beacon.regClass, + pBeaconReq->measurement_request.Beacon.channel, + pBeaconReq->measurement_request.Beacon.meas_mode, + measDuration, maxMeasduration); + + req_mode = (pBeaconReq->parallel << 0) | (pBeaconReq->enable << 1) | + (pBeaconReq->request << 2) | (pBeaconReq->report << 3) | + (pBeaconReq->durationMandatory << 4); + + wlan_diag_log_beacon_rpt_req_event(pBeaconReq->measurement_token, + pBeaconReq->measurement_request.Beacon.meas_mode, + pBeaconReq->measurement_request.Beacon.regClass, + pBeaconReq->measurement_request.Beacon.channel, + req_mode, measDuration, pe_session); + + if (measDuration == 0 && + pBeaconReq->measurement_request.Beacon.meas_mode != + eSIR_BEACON_TABLE) { + pe_nofl_err("RX: [802.11 BCN_RPT] Invalid measurement duration"); + return eRRM_REFUSED; + } + + if (maxMeasduration < measDuration) { + if (pBeaconReq->durationMandatory) { + pe_nofl_err("RX: [802.11 BCN_RPT] Dropping the req: duration mandatory & maxduration > measduration"); + return eRRM_REFUSED; + } + measDuration = maxMeasduration; + } + + pe_debug("measurement duration %d", measDuration); + + /* Cache the data required for sending report. */ + pCurrentReq->request.Beacon.reportingDetail = + pBeaconReq->measurement_request.Beacon.BcnReportingDetail. + present ? pBeaconReq->measurement_request.Beacon.BcnReportingDetail. + reportingDetail : BEACON_REPORTING_DETAIL_ALL_FF_IE; + + if (pBeaconReq->measurement_request.Beacon. + last_beacon_report_indication.present) { + pCurrentReq->request.Beacon.last_beacon_report_indication = + pBeaconReq->measurement_request.Beacon. + last_beacon_report_indication.last_fragment; + pe_debug("RX: [802.11 BCN_RPT] Last Bcn Report in the req: %d", + pCurrentReq->request.Beacon.last_beacon_report_indication); + } else { + pCurrentReq->request.Beacon.last_beacon_report_indication = 0; + pe_debug("RX: [802.11 BCN_RPT] Last Bcn rpt ind not present"); + } + + if (pBeaconReq->measurement_request.Beacon.RequestedInfo.present) { + if (!pBeaconReq->measurement_request.Beacon.RequestedInfo. + num_requested_eids) { + pe_debug("RX: [802.11 BCN_RPT]: Requested num of EID is 0"); + return eRRM_FAILURE; + } + pCurrentReq->request.Beacon.reqIes.pElementIds = + qdf_mem_malloc(sizeof(uint8_t) * + pBeaconReq->measurement_request.Beacon. + RequestedInfo.num_requested_eids); + if (!pCurrentReq->request.Beacon.reqIes.pElementIds) + return eRRM_FAILURE; + + pCurrentReq->request.Beacon.reqIes.num = + pBeaconReq->measurement_request.Beacon.RequestedInfo. + num_requested_eids; + qdf_mem_copy(pCurrentReq->request.Beacon.reqIes.pElementIds, + pBeaconReq->measurement_request.Beacon. + RequestedInfo.requested_eids, + pCurrentReq->request.Beacon.reqIes.num); + for (i = 0; i < pCurrentReq->request.Beacon.reqIes.num; i++) + pe_debug("RX: [802.11 BCN_RPT]:Requested EID is %d", + pBeaconReq->measurement_request.Beacon.RequestedInfo.requested_eids[i]); + } + + if (pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.present) { + if (!pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.num_req_element_id_ext) { + pe_err("RX: [802.11 BCN_RPT]: Requested num of Extn EID is 0"); + return eRRM_FAILURE; + } + if (pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.req_element_id != + WLAN_ELEMID_EXTN_ELEM) { + pe_err("RX: [802.11 BCN_RPT]: Extn Element ID is not 0xFF"); + return eRRM_FAILURE; + } + + pCurrentReq->request.Beacon.reqIes.ext_info.eid = + pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.req_element_id; + pCurrentReq->request.Beacon.reqIes.ext_info.num_eid_ext = + pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.num_req_element_id_ext; + qdf_mem_copy(pCurrentReq->request.Beacon.reqIes.ext_info.eid_ext, + pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.req_element_id_ext, + pCurrentReq->request.Beacon.reqIes.ext_info.num_eid_ext); + pe_debug("RX: [802.11 BCN_RPT]: EID is %d", + pCurrentReq->request.Beacon.reqIes.ext_info.eid); + pe_debug("RX: [802.11 BCN_RPT]:Num of Extn EID is %d", + pCurrentReq->request.Beacon.reqIes.ext_info.num_eid_ext); + for (i = 0; i < pCurrentReq->request.Beacon.reqIes.ext_info.num_eid_ext; i++) + pe_debug("RX: [802.11 BCN_RPT]:Requested Extn EID is %d", + pBeaconReq->measurement_request.Beacon.ExtRequestedInfo.req_element_id_ext[i]); + } + + /* Prepare the request to send to SME. */ + psbrr = qdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (!psbrr) + return eRRM_FAILURE; + + /* Alloc memory for pSmeBcnReportReq, will be freed by other modules */ + qdf_mem_copy(psbrr->bssId, pe_session->bssId, + sizeof(tSirMacAddr)); + psbrr->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + psbrr->length = sizeof(tSirBeaconReportReqInd); + psbrr->uDialogToken = pBeaconReq->measurement_token; + psbrr->msgSource = eRRM_MSG_SOURCE_11K; + psbrr->randomizationInterval = + SYS_TU_TO_MS(pBeaconReq->measurement_request.Beacon.randomization); + psbrr->measurement_idx = pCurrentReq->measurement_idx; + + if (!wlan_reg_is_6ghz_supported(mac->psoc) && + (wlan_reg_is_6ghz_op_class(mac->pdev, + pBeaconReq->measurement_request.Beacon.regClass))) { + pe_nofl_err("RX: [802.11 BCN_RPT] Ch belongs to 6 ghz spectrum, abort"); + qdf_mem_free(psbrr); + return eRRM_FAILURE; + } + + rrm_get_country_code_from_connected_profile(mac, pe_session->vdev_id, + country); + psbrr->channel_info.chan_num = + pBeaconReq->measurement_request.Beacon.channel; + psbrr->channel_info.reg_class = + pBeaconReq->measurement_request.Beacon.regClass; + if (psbrr->channel_info.chan_num && + psbrr->channel_info.chan_num != 255) { + psbrr->channel_info.chan_freq = + wlan_reg_country_chan_opclass_to_freq( + mac->pdev, + country, + psbrr->channel_info.chan_num, + psbrr->channel_info.reg_class, + false); + if (!psbrr->channel_info.chan_freq) { + pe_debug("invalid ch freq, chan_num %d", + psbrr->channel_info.chan_num); + qdf_mem_free(psbrr); + return eRRM_FAILURE; + } + } else { + psbrr->channel_info.chan_freq = 0; + } + sme_debug("opclass %d, ch %d freq %d AP's country code %c%c 0x%x index:%d", + psbrr->channel_info.reg_class, + psbrr->channel_info.chan_num, + psbrr->channel_info.chan_freq, + country[0], country[1], country[2], + psbrr->measurement_idx); + + psbrr->measurementDuration[0] = measDuration; + psbrr->fMeasurementtype[0] = + pBeaconReq->measurement_request.Beacon.meas_mode; + qdf_mem_copy(psbrr->macaddrBssid, + pBeaconReq->measurement_request.Beacon.BSSID, + sizeof(tSirMacAddr)); + + if (pBeaconReq->measurement_request.Beacon.SSID.present) { + psbrr->ssId.length = + pBeaconReq->measurement_request.Beacon.SSID.num_ssid; + qdf_mem_copy(psbrr->ssId.ssId, + pBeaconReq->measurement_request.Beacon.SSID.ssid, + psbrr->ssId.length); + } + + pCurrentReq->token = pBeaconReq->measurement_token; + + num_rpt = pBeaconReq->measurement_request.Beacon.num_APChannelReport; + for (idx_rpt = 0; idx_rpt < num_rpt; idx_rpt++) { + ie_ap_chan_rpt = + &pBeaconReq->measurement_request.Beacon.APChannelReport[idx_rpt]; + for (tmp_idx = 0; + tmp_idx < ie_ap_chan_rpt->num_channelList; + tmp_idx++) { + if (!wlan_reg_is_6ghz_supported(mac->psoc) && + (wlan_reg_is_6ghz_op_class(mac->pdev, + ie_ap_chan_rpt->regulatoryClass))) { + pe_nofl_err("RX: [802.11 BCN_RPT] Ch belongs to 6 ghz spectrum, abort"); + qdf_mem_free(psbrr); + return eRRM_FAILURE; + } + + psbrr->channel_list.chan_freq_lst[ch_ctr++] = + wlan_reg_country_chan_opclass_to_freq( + mac->pdev, country, + ie_ap_chan_rpt->channelList[tmp_idx], + ie_ap_chan_rpt->regulatoryClass, true); + + if (ch_ctr >= QDF_ARRAY_SIZE(psbrr->channel_list.chan_freq_lst)) + break; + } + if (ch_ctr >= QDF_ARRAY_SIZE(psbrr->channel_list.chan_freq_lst)) + break; + } + + psbrr->channel_list.num_channels = ch_ctr; + buf_left = sizeof(ch_buf); + tmp_buf = ch_buf; + for (idx_rpt = 0; idx_rpt < ch_ctr; idx_rpt++) { + buf_cons = qdf_snprint(tmp_buf, buf_left, "%d ", + psbrr->channel_list.chan_freq_lst[idx_rpt]); + buf_left -= buf_cons; + tmp_buf += buf_cons; + } + + if (ch_ctr) + pe_nofl_info("RX: [802.11 BCN_RPT] Ch-list:%s", ch_buf); + + /* Send request to SME. */ + mmh_msg.type = eWNI_SME_BEACON_REPORT_REQ_IND; + mmh_msg.bodyptr = psbrr; + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->peSessionId, mmh_msg.type)); + lim_sys_process_mmh_msg_api(mac, &mmh_msg); + return eRRM_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static uint8_t * +rrm_check_ml_ie(uint8_t *ies, uint16_t len, uint8_t *mlie_copy_len) +{ + uint8_t *ml_ie = NULL; + qdf_size_t ml_ie_total_len = 0; + uint8_t *mlie_copy = NULL; + uint8_t ml_common_info_length = 0; + uint8_t ml_bv_ie_len = 0; + + util_find_mlie(ies, len, &ml_ie, &ml_ie_total_len); + if (!ml_ie) { + mlo_debug("[802.11 BCN_RPT]: Not ML AP total_len:%d", len); + return NULL; + } + + mlo_debug("[802.11 BCN_RPT]: ML IE is present ml_ie_total_len:%zu", + ml_ie_total_len); + + util_get_mlie_common_info_len(ml_ie, ml_ie_total_len, + &ml_common_info_length); + + ml_bv_ie_len = sizeof(struct wlan_ie_multilink) + ml_common_info_length; + if (ml_bv_ie_len) { + mlie_copy = qdf_mem_malloc(ml_bv_ie_len); + if (!mlie_copy) { + mlo_err("malloc failed"); + goto end; + } + qdf_mem_copy(mlie_copy, ml_ie, ml_bv_ie_len); + mlie_copy[TAG_LEN_POS] = ml_bv_ie_len - sizeof(struct ie_header); + *mlie_copy_len = ml_bv_ie_len; + } + +end: + return mlie_copy; +} + +static bool +rrm_copy_ml_ie(uint8_t eid, uint8_t extn_eid, + uint8_t *ml_ie, uint16_t ml_len, uint8_t *pIes) +{ + if ((eid == WLAN_ELEMID_EXTN_ELEM || !eid) && + extn_eid == WLAN_EXTN_ELEMID_MULTI_LINK) { + if (ml_ie && ml_len && pIes) { + qdf_mem_copy(pIes, ml_ie, ml_len); + return true; + } + } + + return false; +} + +#else +static inline uint8_t * +rrm_check_ml_ie(uint8_t *ies, uint16_t len, uint8_t *mlie_copy_len) { + return NULL; +} + +static inline bool +rrm_copy_ml_ie(uint8_t eid, uint8_t extn_eid, uint8_t *ml_ie, + uint16_t ml_len, uint8_t *pIes) { + return false; +} +#endif +/** + * rrm_fill_beacon_ies() - Fills fixed fields and Ies in bss description to an + * array of uint8_t. + * @mac: pointer to mac context + * @pIes: pointer to the buffer that should be populated with ies. + * @pNumIes: returns the num of ies filled in this param. + * @pIesMaxSize: Max size of the buffer pIes. + * @eids: pointer to array of eids. If NULL, all ies will be populated. + * @numEids: number of elements in array eids. + * @eid: EID + * @extn_eids: pointer to array of ext eids + * @extn_eids_count: count of elements in array extn_eids + * @start_offset: Offset from where the IEs in the bss_desc should be parsed + * @bss_desc: pointer to Bss Description. + * + * Return: Remaining length of IEs in current bss_desc which are not included + * in pIes. + */ +static uint16_t +rrm_fill_beacon_ies(struct mac_context *mac, uint8_t *pIes, + uint8_t *pNumIes, uint8_t pIesMaxSize, uint8_t *eids, + uint8_t numEids, uint8_t eid, uint8_t *extn_eids, + uint8_t extn_eids_count, uint16_t start_offset, + struct bss_description *bss_desc) +{ + uint8_t *pBcnIes, i; + uint16_t BcnNumIes, total_ies_len, len; + uint16_t rem_len = 0; + uint8_t num_eids = 0; + uint8_t ml_len = 0; + uint8_t *ml_copy = NULL; + + if ((!pIes) || (!pNumIes) || (!bss_desc)) { + pe_err("Invalid parameters"); + return 0; + } + /* Make sure that if eid is null, numEids is set to zero. */ + num_eids = (!eids) ? 0 : numEids; + num_eids += (!extn_eids) ? 0 : extn_eids_count; + pe_err("extn_eids_count %d", extn_eids_count); + + total_ies_len = GET_IE_LEN_IN_BSS(bss_desc->length); + BcnNumIes = total_ies_len; + if (start_offset > BcnNumIes) { + pe_err("Invalid start offset %d Bcn IE len %d", + start_offset, total_ies_len); + return 0; + } + + pBcnIes = (uint8_t *)&bss_desc->ieFields[0]; + ml_copy = rrm_check_ml_ie(pBcnIes, total_ies_len, &ml_len); + pBcnIes += start_offset; + BcnNumIes = BcnNumIes - start_offset; + + *pNumIes = 0; + + /* + * If start_offset is 0, this is the first fragment of the current + * beacon. Include the Beacon Fixed Fields of length 12 bytes + * (BEACON_FRAME_IES_OFFSET) in the first fragment. + */ + if (start_offset == 0) { + *((uint32_t *)pIes) = bss_desc->timeStamp[0]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint32_t *)pIes) = bss_desc->timeStamp[1]; + *pNumIes += sizeof(uint32_t); + pIes += sizeof(uint32_t); + *((uint16_t *)pIes) = bss_desc->beaconInterval; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + *((uint16_t *)pIes) = bss_desc->capabilityInfo; + *pNumIes += sizeof(uint16_t); + pIes += sizeof(uint16_t); + } + + while (BcnNumIes >= 2) { + len = *(pBcnIes + 1); + len += 2; /* element id + length. */ + pe_debug("EID = %d, len = %d total = %d", + *pBcnIes, *(pBcnIes + 1), len); + if (*pBcnIes == WLAN_ELEMID_EXTN_ELEM && *(pBcnIes + 2) > 0) + pe_debug("Extended EID = %d", *(pBcnIes + 2)); + + if (BcnNumIes < len || len <= 2) { + pe_err("RRM: Invalid IE len:%d exp_len:%d", + len, BcnNumIes); + break; + } + + i = 0; + do { + if (((!eids) || (*pBcnIes == eids[i])) || + ((*pBcnIes == eid) && + (extn_eids && *(pBcnIes + 2) == extn_eids[i]))) { + if (((*pNumIes) + len) < pIesMaxSize) { + qdf_mem_copy(pIes, pBcnIes, len); + pIes += len; + *pNumIes += len; + } else { + if (rrm_copy_ml_ie(*pBcnIes, *(pBcnIes + 2), ml_copy, ml_len, pIes)) { + pIes += ml_len; + *pNumIes += ml_len; + start_offset = start_offset + len - ml_len; + } else { + /* + * If max size of fragment is reached, + * calculate the remaining length and + * break. For first fragment, account + * for the fixed fields also. + */ + rem_len = total_ies_len - *pNumIes - + start_offset; + if (start_offset == 0) + rem_len = rem_len + + BEACON_FRAME_IES_OFFSET; + pe_debug("rem_len %d ies added %d", + rem_len, *pNumIes); + } + } + break; + } + i++; + } while (i < num_eids); + + if (rem_len) + break; + + pBcnIes += len; + BcnNumIes -= len; + } + + if (ml_copy) + qdf_mem_free(ml_copy); + + pe_debug("Total length of Ies added = %d rem_len %d", + *pNumIes, rem_len); + + return rem_len; +} + +/** + * rrm_process_beacon_report_xmit() - create a rrm action frame + * @mac_ctx: Global pointer to MAC context + * @beacon_xmit_ind: Data for beacon report IE from SME. + * + * Create a Radio measurement report action frame and send it to peer. + * + * Return: QDF_STATUS + */ +QDF_STATUS +rrm_process_beacon_report_xmit(struct mac_context *mac_ctx, + tpSirBeaconReportXmitInd beacon_xmit_ind) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirMacRadioMeasureReport *report = NULL; + tSirMacBeaconReport *beacon_report; + struct bss_description *bss_desc; + tpRRMReq curr_req; + struct pe_session *session_entry; + uint8_t session_id, counter; + uint8_t i, j; + uint8_t bss_desc_count = 0; + uint8_t report_index = 0; + uint16_t rem_len = 0; + uint16_t offset = 0; + uint8_t frag_id = 0; + uint8_t num_frames, num_reports_in_frame, final_measurement_index; + uint32_t populated_beacon_report_size = 0; + uint32_t max_reports_in_frame = 0; + uint32_t radio_meas_rpt_size = 0, dot11_meas_rpt_size = 0; + bool is_last_measurement_frame; + + + if (!beacon_xmit_ind) { + pe_err("Received beacon_xmit_ind is NULL in PE"); + return QDF_STATUS_E_FAILURE; + } + + if (beacon_xmit_ind->measurement_idx >= + QDF_ARRAY_SIZE(mac_ctx->rrm.rrmPEContext.pCurrentReq)) { + pe_err("Received measurement_idx is out of range: %u - %zu", + beacon_xmit_ind->measurement_idx, + QDF_ARRAY_SIZE(mac_ctx->rrm.rrmPEContext.pCurrentReq)); + return QDF_STATUS_E_FAILURE; + } + + curr_req = mac_ctx->rrm.rrmPEContext. + pCurrentReq[beacon_xmit_ind->measurement_idx]; + if (!curr_req) { + pe_err("Received report xmit while there is no request pending in PE"); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + pe_debug("Received beacon report xmit indication on idx:%d", + beacon_xmit_ind->measurement_idx); + + /* + * Send empty report only if all channels on a measurement index has + * no scan results or if the AP requests for last beacon report + * indication and last channel of the last index has empty report + */ + if (beacon_xmit_ind->numBssDesc || curr_req->sendEmptyBcnRpt || + (beacon_xmit_ind->fMeasureDone && + curr_req->request.Beacon.last_beacon_report_indication && + (mac_ctx->rrm.rrmPEContext.num_active_request - 1) == 0)) { + beacon_xmit_ind->numBssDesc = (beacon_xmit_ind->numBssDesc == + RRM_BCN_RPT_NO_BSS_INFO) ? RRM_BCN_RPT_MIN_RPT : + beacon_xmit_ind->numBssDesc; + + session_entry = pe_find_session_by_bssid(mac_ctx, + beacon_xmit_ind->bssId, &session_id); + if (!session_entry) { + pe_err("TX: [802.11 BCN_RPT] Session does not exist for bssId:"QDF_MAC_ADDR_FMT"", + QDF_MAC_ADDR_REF(beacon_xmit_ind->bssId)); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + report = qdf_mem_malloc(MAX_BEACON_REPORTS * sizeof(*report)); + if (!report) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + for (i = 0; i < MAX_BEACON_REPORTS && + bss_desc_count < beacon_xmit_ind->numBssDesc; i++) { + beacon_report = &report[i].report.beaconReport; + /* + * If the scan result is NULL then send report request + * with option subelement as NULL. + */ + pe_debug("TX: [802.11 BCN_RPT] report %d bss %d", i, + bss_desc_count); + bss_desc = beacon_xmit_ind-> + pBssDescription[bss_desc_count]; + + /* Prepare the beacon report and send it to the peer.*/ + report[i].token = beacon_xmit_ind->uDialogToken; + report[i].refused = 0; + report[i].incapable = 0; + report[i].type = SIR_MAC_RRM_BEACON_TYPE; + + /* + * Valid response is included if the size of + * becon xmit is == size of beacon xmit ind + ies + */ + if (beacon_xmit_ind->length < sizeof(*beacon_xmit_ind)) + continue; + beacon_report->regClass = beacon_xmit_ind->regClass; + if (bss_desc) { + beacon_report->channel = + wlan_reg_freq_to_chan( + mac_ctx->pdev, + bss_desc->chan_freq); + qdf_mem_copy(beacon_report->measStartTime, + bss_desc->startTSF, + sizeof(bss_desc->startTSF)); + beacon_report->measDuration = + beacon_xmit_ind->duration; + beacon_report->phyType = bss_desc->nwType; + beacon_report->bcnProbeRsp = 1; + beacon_report->rsni = 0; + + rrm_calculate_and_fill_rcpi(&beacon_report->rcpi, + bss_desc->rssi); + beacon_report->antennaId = 0; + beacon_report->parentTSF = bss_desc->parentTSF; + qdf_mem_copy(beacon_report->bssid, + bss_desc->bssId, sizeof(tSirMacAddr)); + } + + pe_debug("TX: [802.11 BCN_RPT] reporting detail requested %d", + curr_req->request.Beacon.reportingDetail); + switch (curr_req->request.Beacon.reportingDetail) { + case BEACON_REPORTING_DETAIL_NO_FF_IE: + /* 0: No need to include any elements. */ + break; + case BEACON_REPORTING_DETAIL_ALL_FF_REQ_IE: + /* 1: Include all FFs and Requested Ies. */ + if (!bss_desc) + break; + + rem_len = rrm_fill_beacon_ies(mac_ctx, + (uint8_t *)&beacon_report->Ies[0], + (uint8_t *)&beacon_report->numIes, + BEACON_REPORT_MAX_IES, + curr_req->request.Beacon.reqIes. + pElementIds, + curr_req->request.Beacon.reqIes.num, + curr_req->request.Beacon.reqIes.ext_info.eid, + &curr_req->request.Beacon.reqIes.ext_info.eid_ext[0], + curr_req->request.Beacon.reqIes.ext_info.num_eid_ext, + offset, bss_desc); + break; + case BEACON_REPORTING_DETAIL_ALL_FF_IE: + /* 2: default - Include all FFs and all Ies. */ + default: + if (!bss_desc) + break; + + rem_len = rrm_fill_beacon_ies(mac_ctx, + (uint8_t *) &beacon_report->Ies[0], + (uint8_t *) &beacon_report->numIes, + BEACON_REPORT_MAX_IES, + NULL, + 0, + 0, + NULL, + 0, + offset, bss_desc); + break; + } + beacon_report->frame_body_frag_id.id = bss_desc_count; + beacon_report->frame_body_frag_id.frag_id = frag_id; + /* + * If remaining length is non-zero, the beacon needs to + * be fragmented only if the current request supports + * last beacon report indication. + * If last beacon report indication is not supported, + * truncate and move on to the next beacon. + */ + if (rem_len && + curr_req->request.Beacon. + last_beacon_report_indication) { + offset = GET_IE_LEN_IN_BSS( + bss_desc->length) - rem_len; + pe_debug("TX: [802.11 BCN_RPT] offset %d ie_len %lu rem_len %d frag_id %d", + offset, + GET_IE_LEN_IN_BSS(bss_desc->length), + rem_len, frag_id); + frag_id++; + beacon_report->frame_body_frag_id.more_frags = + true; + } else { + offset = 0; + beacon_report->frame_body_frag_id.more_frags = + false; + frag_id = 0; + bss_desc_count++; + pe_debug("TX: [802.11 BCN_RPT] No remaining IEs"); + } + + if (curr_req->request.Beacon.last_beacon_report_indication) + beacon_report->last_bcn_report_ind_support = 1; + + } + + pe_debug("TX: [802.11 BCN_RPT] Total reports filled %d, last bcn_rpt ind:%d", + i , curr_req->request.Beacon.last_beacon_report_indication); + + /* Calculate size of populated beacon reports */ + radio_meas_rpt_size = sizeof(tSirMacRadioMeasureReport); + populated_beacon_report_size = (i * radio_meas_rpt_size); + + /* Calculate num of mgmt frames to send */ + num_frames = populated_beacon_report_size / MAX_MGMT_MPDU_LEN; + if (populated_beacon_report_size % MAX_MGMT_MPDU_LEN) + num_frames++; + + /* Calculate num of maximum mgmt reports per frame */ + dot11_meas_rpt_size = sizeof(tDot11fRadioMeasurementReport); + max_reports_in_frame = MAX_MGMT_MPDU_LEN / dot11_meas_rpt_size; + + for (j = 0; j < num_frames; j++) { + num_reports_in_frame = QDF_MIN((i - report_index), + max_reports_in_frame); + + final_measurement_index = + mac_ctx->rrm.rrmPEContext.num_active_request; + is_last_measurement_frame = + ((j == num_frames - 1) && + beacon_xmit_ind->fMeasureDone && + !(final_measurement_index - 1)); + + lim_send_radio_measure_report_action_frame(mac_ctx, + curr_req->dialog_token, num_reports_in_frame, + is_last_measurement_frame, + &report[report_index], + beacon_xmit_ind->bssId, session_entry); + report_index += num_reports_in_frame; + } + curr_req->sendEmptyBcnRpt = false; + } + +end: + for (counter = 0; counter < beacon_xmit_ind->numBssDesc; counter++) + qdf_mem_free(beacon_xmit_ind->pBssDescription[counter]); + + if (beacon_xmit_ind->fMeasureDone) { + pe_debug("Measurement done idx:%d", + beacon_xmit_ind->measurement_idx); + rrm_cleanup(mac_ctx, beacon_xmit_ind->measurement_idx); + } + + if (report) + qdf_mem_free(report); + + return status; +} + +static void +rrm_process_beacon_request_failure(struct mac_context *mac, + struct pe_session *pe_session, + tSirMacAddr peer, + tRrmRetStatus status, uint8_t index) +{ + tpSirMacRadioMeasureReport pReport = NULL; + tpRRMReq pCurrentReq = mac->rrm.rrmPEContext.pCurrentReq[index]; + + if (!pCurrentReq) { + pe_err("Current request is NULL"); + return; + } + + pReport = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (!pReport) + return; + pReport->token = pCurrentReq->token; + pReport->type = SIR_MAC_RRM_BEACON_TYPE; + + pe_debug("Measurement index:%d status %d token %d", index, status, + pReport->token); + + switch (status) { + case eRRM_REFUSED: + pReport->refused = 1; + break; + case eRRM_INCAPABLE: + pReport->incapable = 1; + break; + default: + pe_err("RX [802.11 BCN_RPT] Beacon request processing failed no report sent"); + qdf_mem_free(pReport); + return; + } + + if (pCurrentReq->request.Beacon.last_beacon_report_indication) + pReport->report.beaconReport.last_bcn_report_ind_support = 1; + + lim_send_radio_measure_report_action_frame(mac, + pCurrentReq->dialog_token, + 1, true, + pReport, peer, + pe_session); + + qdf_mem_free(pReport); + return; +} + +/** + * rrm_process_beacon_req() - Update curr_req and report + * @mac_ctx: Global pointer to MAC context + * @peer: Macaddress of the peer requesting the radio measurement + * @session_entry: session entry + * @radiomes_report: Pointer to radio measurement report + * @rrm_req: Array of Measurement request IEs + * @num_report: No.of reports + * @index: Index for Measurement request + * + * Update structure sRRMReq and sSirMacRadioMeasureReport and pass it to + * rrm_process_beacon_report_req(). + * + * Return: QDF_STATUS + */ +static +QDF_STATUS rrm_process_beacon_req(struct mac_context *mac_ctx, tSirMacAddr peer, + struct pe_session *session_entry, + tpSirMacRadioMeasureReport *radiomes_report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + tRrmRetStatus rrm_status = eRRM_SUCCESS; + tpSirMacRadioMeasureReport report = NULL; + tpRRMReq curr_req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (index >= MAX_MEASUREMENT_REQUEST) { + status = rrm_reject_req(&report, rrm_req, num_report, index, + rrm_req->MeasurementRequest[0]. + measurement_type); + return status; + } + + curr_req = qdf_mem_malloc(sizeof(*curr_req)); + if (!curr_req) { + mac_ctx->rrm.rrmPEContext.pCurrentReq[index] = NULL; + return QDF_STATUS_E_NOMEM; + } + pe_debug("Processing Beacon Report request %d", index); + curr_req->dialog_token = rrm_req->DialogToken.token; + curr_req->token = + rrm_req->MeasurementRequest[index].measurement_token; + curr_req->sendEmptyBcnRpt = true; + curr_req->measurement_idx = index; + mac_ctx->rrm.rrmPEContext.pCurrentReq[index] = curr_req; + mac_ctx->rrm.rrmPEContext.num_active_request++; + pe_debug("Processing Bcn Report req %d num_active_req:%d", + index, mac_ctx->rrm.rrmPEContext.num_active_request); + rrm_status = rrm_process_beacon_report_req(mac_ctx, curr_req, + &rrm_req->MeasurementRequest[index], session_entry); + if (eRRM_SUCCESS != rrm_status) { + rrm_process_beacon_request_failure(mac_ctx, + session_entry, peer, rrm_status, index); + rrm_cleanup(mac_ctx, index); + } + + return QDF_STATUS_SUCCESS; +} + + +/** + * rrm_process_channel_load_req() - process channel load request from AP + * @mac: global mac context + * @pe_session: per-vdev PE context + * @curr_req: current measurement req in progress + * @peer: Macaddress of the peer requesting the radio measurement + * @chan_load_req: channel load request received from AP + * + * return tRrmRetStatus + */ +static tRrmRetStatus +rrm_process_channel_load_req(struct mac_context *mac, + struct pe_session *pe_session, + tpRRMReq curr_req, tSirMacAddr peer, + tDot11fIEMeasurementRequest *chan_load_req) +{ + struct scheduler_msg msg = {0}; + struct ch_load_ind *load_ind; + struct bw_ind_element bw_ind = {0}; + struct wide_bw_chan_switch wide_bw = {0}; + struct rrm_reporting rrm_report; + uint8_t op_class, channel; + uint16_t randomization_intv, meas_duration, max_meas_duration; + bool is_rrm_reporting, is_wide_bw_chan_switch; + uint8_t country[WNI_CFG_COUNTRY_CODE_LEN]; + qdf_freq_t chan_freq; + bool is_freq_enabled, is_bw_ind; + + if (wlan_policy_mgr_get_ll_lt_sap_vdev_id(mac->psoc) != WLAN_INVALID_VDEV_ID) { + pe_debug("RX:[802.11 CH_LOAD] reject req as ll_lt_sap is present"); + return eRRM_REFUSED; + } + + is_rrm_reporting = chan_load_req->measurement_request.channel_load.rrm_reporting.present; + is_wide_bw_chan_switch = chan_load_req->measurement_request.channel_load.wide_bw_chan_switch.present; + is_bw_ind = chan_load_req->measurement_request.channel_load.bw_indication.present; + + pe_debug("RX:[802.11 CH_LOAD] vdev: %d, is_rrm_reporting: %d, is_wide_bw_chan_switch: %d, is_bw_ind: %d", + pe_session->vdev_id, is_rrm_reporting, is_wide_bw_chan_switch, + is_bw_ind); + + if (is_rrm_reporting) { + rrm_report.threshold = chan_load_req->measurement_request.channel_load.rrm_reporting.threshold; + rrm_report.reporting_condition = chan_load_req->measurement_request.channel_load.rrm_reporting.reporting_condition; + pe_debug("RX:[802.11 CH_LOAD] threshold:%d reporting_c:%d", + rrm_report.threshold, rrm_report.reporting_condition); + if (rrm_report.reporting_condition != 0) { + pe_debug("RX:[802.11 CH_LOAD]: Dropping req"); + return eRRM_INCAPABLE; + } + } + + if (is_bw_ind) { + bw_ind.is_bw_ind_element = true; + bw_ind.channel_width = chan_load_req->measurement_request.channel_load.bw_indication.channel_width; + bw_ind.ccfi0 = chan_load_req->measurement_request.channel_load.bw_indication.ccfs0; + bw_ind.ccfi1 = chan_load_req->measurement_request.channel_load.bw_indication.ccfs1; + bw_ind.center_freq = wlan_reg_compute_6g_center_freq_from_cfi(bw_ind.ccfi0); + pe_debug("RX:[802.11 CH_LOAD] chan_width:%d ccfs0:%d, ccfs1:%d, center_freq:%d", + bw_ind.channel_width, bw_ind.ccfi0, + bw_ind.ccfi1, bw_ind.center_freq); + + if (bw_ind.channel_width == 0 || !bw_ind.ccfi0 || + bw_ind.channel_width < CH_WIDTH_320MHZ || !bw_ind.center_freq) { + pe_debug("Dropping req: invalid is_bw_ind_element IE"); + return eRRM_REFUSED; + } + } + + if (is_wide_bw_chan_switch) { + wide_bw.is_wide_bw_chan_switch = true; + wide_bw.channel_width = chan_load_req->measurement_request.channel_load.wide_bw_chan_switch.new_chan_width; + wide_bw.center_chan_freq0 = chan_load_req->measurement_request.channel_load.wide_bw_chan_switch.new_center_chan_freq0; + wide_bw.center_chan_freq1 = chan_load_req->measurement_request.channel_load.wide_bw_chan_switch.new_center_chan_freq1; + pe_debug("RX:[802.11 CH_LOAD] cw:%d ccf0:%d, ccf1:%d", + wide_bw.channel_width, wide_bw.center_chan_freq0, + wide_bw.center_chan_freq1); + if (wide_bw.channel_width < CH_WIDTH_20MHZ || + wide_bw.channel_width >= CH_WIDTH_320MHZ) { + pe_debug("Dropping req: invalid wide_bw IE"); + return eRRM_REFUSED; + } + } + + op_class = chan_load_req->measurement_request.channel_load.op_class; + channel = chan_load_req->measurement_request.channel_load.channel; + meas_duration = + chan_load_req->measurement_request.channel_load.meas_duration; + randomization_intv = + chan_load_req->measurement_request.channel_load.randomization_intv; + max_meas_duration = rrm_get_max_meas_duration(mac, pe_session); + + if (max_meas_duration < meas_duration) { + if (chan_load_req->durationMandatory) { + pe_nofl_err("RX:[802.11 CH_LOAD] Dropping the req: duration mandatory & max duration > meas duration"); + return eRRM_REFUSED; + } + meas_duration = max_meas_duration; + } + + pe_debug("RX:[802.11 CH_LOAD] vdev :%d, seq:%d Token:%d op_c:%d ch:%d meas_dur:%d, rand intv: %d, max_dur:%d", + pe_session->vdev_id, + mac->rrm.rrmPEContext.prev_rrm_report_seq_num, + chan_load_req->measurement_token, op_class, + channel, meas_duration, randomization_intv, + max_meas_duration); + + if (!meas_duration || meas_duration > RRM_SCAN_MAX_DWELL_TIME) + return eRRM_REFUSED; + + if (!wlan_reg_is_6ghz_supported(mac->psoc) && + (wlan_reg_is_6ghz_op_class(mac->pdev, op_class))) { + pe_debug("RX: [802.11 CH_LOAD] Ch belongs to 6 ghz spectrum, abort"); + return eRRM_INCAPABLE; + } + + rrm_get_country_code_from_connected_profile(mac, pe_session->vdev_id, + country); + chan_freq = wlan_reg_country_chan_opclass_to_freq(mac->pdev, + country, channel, + op_class, false); + if (!chan_freq) { + pe_debug("Invalid ch freq for country code %c%c 0x%x", + country[0], country[1], country[2]); + return eRRM_INCAPABLE; + } + + pe_debug("freq:%d, country code %c%c 0x%x", chan_freq, country[0], + country[1], country[2]); + + is_freq_enabled = wlan_reg_is_freq_enabled(mac->pdev, chan_freq, + REG_CURRENT_PWR_MODE); + if (!is_freq_enabled) { + pe_debug("No channels populated with requested operation class and current country, Hence abort the rrm operation"); + return eRRM_INCAPABLE; + } + + /* Prepare the request to send to SME. */ + load_ind = qdf_mem_malloc(sizeof(struct ch_load_ind)); + if (!load_ind) + return eRRM_FAILURE; + + qdf_mem_copy(load_ind->peer_addr.bytes, peer, + sizeof(struct qdf_mac_addr)); + load_ind->message_type = eWNI_SME_CHAN_LOAD_REQ_IND; + load_ind->length = sizeof(struct ch_load_ind); + load_ind->dialog_token = chan_load_req->measurement_token; + load_ind->msg_source = eRRM_MSG_SOURCE_11K; + load_ind->randomization_intv = SYS_TU_TO_MS(randomization_intv); + load_ind->measurement_idx = curr_req->measurement_idx; + load_ind->channel = channel; + load_ind->req_freq = chan_freq; + load_ind->op_class = op_class; + load_ind->meas_duration = meas_duration; + curr_req->token = chan_load_req->measurement_token; + + if (is_wide_bw_chan_switch) + load_ind->wide_bw = wide_bw; + + if (is_bw_ind) + load_ind->bw_ind = bw_ind; + + /* Send request to SME. */ + msg.type = eWNI_SME_CHAN_LOAD_REQ_IND; + msg.bodyptr = load_ind; + MTRACE(mac_trace(mac, TRACE_CODE_TX_SME_MSG, + pe_session->vdev_id, msg.type)); + lim_sys_process_mmh_msg_api(mac, &msg); + return eRRM_SUCCESS; +} + +/** + * rrm_process_chan_load_request_failure() - process channel load request + * in case of failure + * @mac: global mac context + * @pe_session: per-vdev PE context + * @peer: peer mac address + * @status:failure status of channel load request + * @index: request index + * + * return none + */ +static void +rrm_process_chan_load_request_failure(struct mac_context *mac, + struct pe_session *pe_session, + tSirMacAddr peer, + tRrmRetStatus status, uint8_t index) +{ + tpSirMacRadioMeasureReport report = NULL; + tpRRMReq curr_req = mac->rrm.rrmPEContext.pCurrentReq[index]; + + if (!curr_req) { + pe_debug("Current request is NULL"); + goto cleanup; + } + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (!report) + goto cleanup; + report->token = curr_req->token; + report->type = SIR_MAC_RRM_CHANNEL_LOAD_TYPE; + pe_debug("vdev:%d measurement index:%d status %d token %d", + pe_session->vdev_id, index, status, report->token); + switch (status) { + case eRRM_REFUSED: + case eRRM_FAILURE: + report->refused = 1; + break; + case eRRM_INCAPABLE: + report->incapable = 1; + break; + default: + goto free; + } + + lim_send_radio_measure_report_action_frame(mac, curr_req->dialog_token, + 1, true, report, peer, + pe_session); +free: + qdf_mem_free(report); +cleanup: + rrm_cleanup(mac, index); +} + +void +rrm_process_chan_load_report_xmit(struct mac_context *mac_ctx, + struct chan_load_xmit_ind *chan_load_ind) +{ + tSirMacRadioMeasureReport *report = NULL; + struct chan_load_report *channel_load_report; + tpRRMReq curr_req; + struct pe_session *session_entry; + uint8_t session_id, idx; + struct qdf_mac_addr sessionBssId; + + if (!chan_load_ind) { + pe_err("Received chan_load_xmit_ind is NULL in PE"); + return; + } + + idx = chan_load_ind->measurement_idx; + + if (idx >= QDF_ARRAY_SIZE(mac_ctx->rrm.rrmPEContext.pCurrentReq)) { + pe_err("Received measurement_idx is out of range: %u - %zu", + idx, + QDF_ARRAY_SIZE(mac_ctx->rrm.rrmPEContext.pCurrentReq)); + return; + } + + curr_req = mac_ctx->rrm.rrmPEContext.pCurrentReq[idx]; + if (!curr_req) { + pe_err("no request pending in PE"); + goto end; + } + + pe_debug("Received chan load report xmit indication on idx:%d", idx); + + sessionBssId = mac_ctx->rrm.rrmSmeContext[idx].sessionBssId; + + session_entry = pe_find_session_by_bssid(mac_ctx, sessionBssId.bytes, + &session_id); + if (!session_entry) { + pe_err("NULL session for bssId "QDF_MAC_ADDR_FMT"", + QDF_MAC_ADDR_REF(sessionBssId.bytes)); + goto end; + } + + if (!chan_load_ind->is_report_success) { + rrm_process_chan_load_request_failure(mac_ctx, session_entry, + sessionBssId.bytes, + eRRM_REFUSED, idx); + return; + } + + report = qdf_mem_malloc(sizeof(*report)); + if (!report) + goto end; + + /* Prepare the channel load report and send it to the peer.*/ + report->token = chan_load_ind->dialog_token; + report->refused = 0; + report->incapable = 0; + report->type = SIR_MAC_RRM_CHANNEL_LOAD_TYPE; + + channel_load_report = &report[0].report.channel_load_report; + channel_load_report->op_class = chan_load_ind->op_class; + channel_load_report->channel = chan_load_ind->channel; + channel_load_report->rrm_scan_tsf = chan_load_ind->rrm_scan_tsf; + channel_load_report->meas_duration = chan_load_ind->duration; + channel_load_report->chan_load = chan_load_ind->chan_load; + qdf_mem_copy(&channel_load_report->bw_ind, &chan_load_ind->bw_ind, + sizeof(channel_load_report->bw_ind)); + qdf_mem_copy(&channel_load_report->wide_bw, &chan_load_ind->wide_bw, + sizeof(channel_load_report->wide_bw)); + pe_err("send chan load report for bssId:" QDF_MAC_ADDR_FMT " reg_class:%d, channel:%d, measStartTime:%lu, measDuration:%d, chan_load:%d", + QDF_MAC_ADDR_REF(sessionBssId.bytes), + channel_load_report->op_class, + channel_load_report->channel, + channel_load_report->rrm_scan_tsf, + channel_load_report->meas_duration, + channel_load_report->chan_load); + + lim_send_radio_measure_report_action_frame(mac_ctx, + curr_req->dialog_token, 1, + true, &report[0], + sessionBssId.bytes, + session_entry); + +end: + pe_debug("Measurement done idx:%d", idx); + rrm_cleanup(mac_ctx, idx); + qdf_mem_free(report); + + return; +} + +/** + * rrm_process_chan_load_req() - process channel load request + * @mac_ctx: Global pointer to MAC context + * @session_entry: session entry + * @report: Pointer to radio measurement report + * @rrm_req: Array of Measurement request IEs + * @peer: mac address of the peer requesting the radio measurement + * @num_report: No.of reports + * @index: Index for Measurement request + * + * Update structure sRRMReq and struct chan_load_req_ind and pass it to + * rrm_process_channel_load_req(). + * + * Return: QDF_STATUS + */ +static QDF_STATUS +rrm_process_chan_load_req(struct mac_context *mac_ctx, + struct pe_session *session_entry, + tpSirMacRadioMeasureReport *report, + tDot11fRadioMeasurementRequest *rrm_req, + tSirMacAddr peer, uint8_t *num_report, int index) +{ + tRrmRetStatus rrm_status = eRRM_SUCCESS; + tpRRMReq curr_req; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (index >= MAX_MEASUREMENT_REQUEST) { + status = rrm_reject_req(report, rrm_req, num_report, index, + rrm_req->MeasurementRequest[0].measurement_type); + return status; + } + + curr_req = qdf_mem_malloc(sizeof(*curr_req)); + if (!curr_req) { + mac_ctx->rrm.rrmPEContext.pCurrentReq[index] = NULL; + return QDF_STATUS_E_NOMEM; + } + + curr_req->dialog_token = rrm_req->DialogToken.token; + curr_req->token = + rrm_req->MeasurementRequest[index].measurement_token; + curr_req->measurement_idx = index; + mac_ctx->rrm.rrmPEContext.pCurrentReq[index] = curr_req; + mac_ctx->rrm.rrmPEContext.num_active_request++; + pe_debug("Processing channel load req index: %d num_active_req:%d", + index, mac_ctx->rrm.rrmPEContext.num_active_request); + rrm_status = rrm_process_channel_load_req(mac_ctx, session_entry, + curr_req, peer, + &rrm_req->MeasurementRequest[index]); + if (eRRM_SUCCESS != rrm_status) + rrm_process_chan_load_request_failure(mac_ctx, session_entry, + peer, rrm_status, index); + + return QDF_STATUS_SUCCESS; +} + +/** + * update_rrm_report() - Set incapable bit + * @mac_ctx: Global pointer to MAC context + * @report: Pointer to radio measurement report + * @rrm_req: Array of Measurement request IEs + * @num_report: No.of reports + * @index: Index for Measurement request + * + * Send a report with incapabale bit set + * + * Return: QDF_STATUS + */ +static +QDF_STATUS update_rrm_report(struct mac_context *mac_ctx, + tpSirMacRadioMeasureReport *report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, int index) +{ + tpSirMacRadioMeasureReport rrm_report; + + if (!*report) { + /* + * Allocate memory to send reports for + * any subsequent requests. + */ + *report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport) * + (rrm_req->num_MeasurementRequest - index)); + if (!*report) + return QDF_STATUS_E_NOMEM; + pe_debug("rrm beacon type incapable of %d report", *num_report); + } + rrm_report = *report; + rrm_report[*num_report].incapable = 1; + rrm_report[*num_report].type = + rrm_req->MeasurementRequest[index].measurement_type; + rrm_report[*num_report].token = + rrm_req->MeasurementRequest[index].measurement_token; + (*num_report)++; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS rrm_reject_req(tpSirMacRadioMeasureReport *radiomes_report, + tDot11fRadioMeasurementRequest *rrm_req, + uint8_t *num_report, uint8_t index, + uint8_t measurement_type) +{ + tpSirMacRadioMeasureReport report; + + if (!*radiomes_report) { + /* + * Allocate memory to send reports for + * any subsequent requests. + */ + *radiomes_report = qdf_mem_malloc(sizeof(*report) * + (rrm_req->num_MeasurementRequest - index)); + if (!*radiomes_report) + return QDF_STATUS_E_NOMEM; + + pe_debug("rrm beacon refused of %d report, index: %d in beacon table", + *num_report, index); + } + report = *radiomes_report; + report[*num_report].refused = 1; + report[*num_report].type = measurement_type; + report[*num_report].token = + rrm_req->MeasurementRequest[index].measurement_token; + (*num_report)++; + + return QDF_STATUS_SUCCESS; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_process_radio_measurement_request - Process rrm request + * @mac_ctx: Global pointer to MAC context + * @peer: Macaddress of the peer requesting the radio measurement. + * @rrm_req: Array of Measurement request IEs + * @session_entry: session entry. + * + * Processes the Radio Resource Measurement request. + * + * Return: QDF_STATUS + */ +QDF_STATUS +rrm_process_radio_measurement_request(struct mac_context *mac_ctx, + tSirMacAddr peer, + tDot11fRadioMeasurementRequest *rrm_req, + struct pe_session *session_entry) +{ + uint8_t i, index; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirMacRadioMeasureReport report = NULL; + uint8_t num_report = 0; + bool reject = false; + + if (!rrm_req->num_MeasurementRequest) { + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (!report) + return QDF_STATUS_E_NOMEM; + pe_err("RX: [802.11 RRM] No requestIes in the measurement request, sending incapable report"); + report->incapable = 1; + num_report = 1; + lim_send_radio_measure_report_action_frame(mac_ctx, + rrm_req->DialogToken.token, num_report, true, + report, peer, session_entry); + qdf_mem_free(report); + return QDF_STATUS_E_FAILURE; + } + /* PF Fix */ + if (rrm_req->NumOfRepetitions.repetitions > 0) { + pe_info("RX: [802.11 RRM] number of repetitions %d, sending incapable report", + rrm_req->NumOfRepetitions.repetitions); + /* + * Send a report with incapable bit set. + * Not supporting repetitions. + */ + report = qdf_mem_malloc(sizeof(tSirMacRadioMeasureReport)); + if (!report) + return QDF_STATUS_E_NOMEM; + report->incapable = 1; + report->type = rrm_req->MeasurementRequest[0].measurement_type; + num_report = 1; + goto end; + } + + for (index = 0; index < MAX_MEASUREMENT_REQUEST; index++) { + if (mac_ctx->rrm.rrmPEContext.pCurrentReq[index]) { + reject = true; + pe_debug("RRM req for index: %d is already in progress", + index); + break; + } + } + + if (reject) { + for (i = 0; i < rrm_req->num_MeasurementRequest; i++) { + status = + rrm_reject_req(&report, rrm_req, &num_report, i, + rrm_req->MeasurementRequest[i]. + measurement_type); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Fail to Reject rrm req for index: %d", + i); + return status; + } + } + + goto end; + } + + /* + * Clear global beacon_rpt_chan_list before processing every new + * beacon report request. + */ + qdf_mem_zero(mac_ctx->rrm.rrmPEContext.beacon_rpt_chan_list, + sizeof(uint8_t) * MAX_NUM_CHANNELS); + mac_ctx->rrm.rrmPEContext.beacon_rpt_chan_num = 0; + + for (i = 0; i < rrm_req->num_MeasurementRequest; i++) { + switch (rrm_req->MeasurementRequest[i].measurement_type) { + case SIR_MAC_RRM_CHANNEL_LOAD_TYPE: + /* Process channel load request */ + status = rrm_process_chan_load_req(mac_ctx, + session_entry, + &report, + rrm_req, peer, + &num_report, i); + if (QDF_IS_STATUS_ERROR(status)) + return status; + break; + case SIR_MAC_RRM_BEACON_TYPE: + /* Process beacon request. */ + status = rrm_process_beacon_req(mac_ctx, peer, + session_entry, &report, + rrm_req, &num_report, + i); + if (QDF_IS_STATUS_ERROR(status)) + return status; + break; + case SIR_MAC_RRM_STA_STATISTICS_TYPE: + status = rrm_process_sta_stats_req(mac_ctx, peer, + session_entry, &report, + rrm_req, &num_report, + i); + break; + case SIR_MAC_RRM_LCI_TYPE: + case SIR_MAC_RRM_LOCATION_CIVIC_TYPE: + case SIR_MAC_RRM_FINE_TIME_MEAS_TYPE: + pe_debug("RRM with type: %d sent to userspace", + rrm_req->MeasurementRequest[i].measurement_type); + break; + default: + /* Send a report with incapabale bit set. */ + status = update_rrm_report(mac_ctx, &report, rrm_req, + &num_report, i); + if (QDF_STATUS_SUCCESS != status) + return status; + break; + } + } + +end: + if (report) { + lim_send_radio_measure_report_action_frame(mac_ctx, + rrm_req->DialogToken.token, num_report, true, + report, peer, session_entry); + qdf_mem_free(report); + } + return status; +} + +/** + * rrm_get_start_tsf() - Get the Start TSF. + * @mac: pointer to mac context + * @pStartTSF: store star TSF in this buffer. + * + * Return: None + */ +void rrm_get_start_tsf(struct mac_context *mac, uint32_t *pStartTSF) +{ + pStartTSF[0] = mac->rrm.rrmPEContext.startTSF[0]; + pStartTSF[1] = mac->rrm.rrmPEContext.startTSF[1]; + +} + +/* -------------------------------------------------------------------- */ +/** + * rrm_get_capabilities() - Returns a pointer to tpRRMCaps with all the + * caps enabled in RRM + * @mac: pointer to mac context + * @pe_session: pointer to pe session + * + * Return: pointer to tRRMCaps + */ +tpRRMCaps rrm_get_capabilities(struct mac_context *mac, struct pe_session *pe_session) +{ + return &mac->rrm.rrmPEContext.rrmEnabledCaps; +} + +/** + * rrm_initialize() - Initialize PE RRM parameters + * @mac: Pointer to mac context + * + * Return: QDF_STATUS + */ +QDF_STATUS rrm_initialize(struct mac_context *mac) +{ + tpRRMCaps pRRMCaps = &mac->rrm.rrmPEContext.rrmEnabledCaps; + uint8_t i; + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) + mac->rrm.rrmPEContext.pCurrentReq[i] = NULL; + + mac->rrm.rrmPEContext.txMgmtPower = 0; + mac->rrm.rrmPEContext.DialogToken = 0; + + mac->rrm.rrmPEContext.rrmEnable = 0; + mac->rrm.rrmPEContext.prev_rrm_report_seq_num = 0xFFFF; + mac->rrm.rrmPEContext.num_active_request = 0; + + qdf_mem_zero(pRRMCaps, sizeof(tRRMCaps)); + pRRMCaps->LinkMeasurement = 1; + pRRMCaps->NeighborRpt = 1; + pRRMCaps->BeaconPassive = 1; + pRRMCaps->BeaconActive = 1; + pRRMCaps->BeaconTable = 1; + pRRMCaps->APChanReport = 1; + pRRMCaps->fine_time_meas_rpt = 1; + pRRMCaps->lci_capability = 1; + pRRMCaps->ChannelLoad = 1; + pRRMCaps->statistics = 1; + + pRRMCaps->operatingChanMax = 3; + pRRMCaps->nonOperatingChanMax = 3; + + return QDF_STATUS_SUCCESS; +} + +void rrm_cleanup(struct mac_context *mac, uint8_t idx) +{ + tpRRMReq cur_rrm_req = NULL; + + if (mac->rrm.rrmPEContext.num_active_request) + mac->rrm.rrmPEContext.num_active_request--; + + cur_rrm_req = mac->rrm.rrmPEContext.pCurrentReq[idx]; + if (!cur_rrm_req) + return; + if (cur_rrm_req->request.Beacon.reqIes.num) { + qdf_mem_free(cur_rrm_req->request.Beacon.reqIes.pElementIds); + cur_rrm_req->request.Beacon.reqIes.pElementIds = NULL; + cur_rrm_req->request.Beacon.reqIes.num = 0; + } + + if (cur_rrm_req->type == SIR_MAC_RRM_STA_STATISTICS_TYPE) { + pe_debug("deactivate rrm sta stats timer"); + lim_deactivate_and_change_timer(mac, + eLIM_RRM_STA_STATS_RSP_TIMER); + qdf_mem_zero(&mac->rrm.rrmPEContext.rrm_sta_stats, + sizeof(mac->rrm.rrmPEContext.rrm_sta_stats)); + } + qdf_mem_free(cur_rrm_req); + mac->rrm.rrmPEContext.pCurrentReq[idx] = NULL; + + pe_debug("cleanup rrm req idx:%d, num_active_request:%d", + idx, mac->rrm.rrmPEContext.num_active_request); +} + +/** + * lim_update_rrm_capability() - Update PE context's rrm capability + * @mac_ctx: Global pointer to MAC context + * + * Update PE context's rrm capability + * + * Return: None + */ +void lim_update_rrm_capability(struct mac_context *mac_ctx) +{ + mac_ctx->rrm.rrmPEContext.rrmEnable = + mac_ctx->rrm.rrmConfig.rrm_enabled; + qdf_mem_copy(&mac_ctx->rrm.rrmPEContext.rrmEnabledCaps, + &mac_ctx->rrm.rrmConfig.rm_capability, + RMENABLEDCAP_MAX_LEN); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_api.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_api.c new file mode 100644 index 0000000000..2e7dae8cd1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_api.c @@ -0,0 +1,965 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sch_api.cc contains functions related to the API exposed + * by scheduler module + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#include "cds_api.h" +#include "ani_global.h" +#include "wni_cfg.h" + +#include "sir_mac_prot_def.h" +#include "sir_mac_prop_exts.h" +#include "sir_common.h" + +#include "lim_api.h" + +#include "sch_api.h" + +#include "lim_trace.h" +#include "lim_types.h" +#include "lim_utils.h" + +#include "wma_types.h" +#include "lim_mlo.h" + +#include +#include +#include +#include + +/* Fils Discovery Frame */ +/** + * struct fd_action_header - FILS Discovery Action frame header + * @action_header: WLAN Action frame header + * @fd_frame_cntl: FILS Discovery Frame Control + * @timestamp: Time stamp + * @bcn_interval: Beacon Interval + * @elem: variable len sub element fields + */ +struct fd_action_header { + struct action_frm_hdr action_header; + uint16_t fd_frame_cntl; + uint8_t timestamp[WLAN_TIMESTAMP_LEN]; + uint16_t bcn_interval; + uint8_t elem[]; +} qdf_packed; + +/** + * struct tpe_ie - Transmit Power Enevolpe IE + * @tpe_header: WLAN IE Header + * @max_tx_pwr_count: Maximum Transmit Power Count + * @max_tx_pwr_interpret: Maximum Transmit Power Interpretation + * @max_tx_pwr_category: Maximum Transmit Power category + * @tx_pwr_info: Transmit power Information + * @elem: variable len sub element fields + */ +struct tpe_ie { + struct ie_header tpe_header; + union { + struct { + uint8_t max_tx_pwr_count:3; + uint8_t max_tx_pwr_interpret:3; + uint8_t max_tx_pwr_category:2; + }; + uint8_t tx_pwr_info; + }; + uint8_t elem[]; +} qdf_packed; + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_notify_link_info() - notify partner link to update beacon template + * @pe_session: pointer to pe session + * + * Return: void + */ +static void lim_notify_link_info(struct pe_session *pe_session) +{ + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; + uint16_t vdev_count = 0; + int link; + + if (!pe_session->mlo_link_info.upt_bcn_mlo_ie && + !mlme_is_notify_co_located_ap_update_rnr(pe_session->vdev)) + return; + pe_session->mlo_link_info.upt_bcn_mlo_ie = false; + mlme_set_notify_co_located_ap_update_rnr(pe_session->vdev, false); + pe_debug("vdev id %d mlo notify beacon change info to partner link", + wlan_vdev_get_id(pe_session->vdev)); + lim_get_mlo_vdev_list(pe_session, &vdev_count, + wlan_vdev_list); + for (link = 0; link < vdev_count; link++) { + if (!wlan_vdev_list[link]) + continue; + if (wlan_vdev_list[link] == pe_session->vdev) { + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + lim_partner_link_info_change(wlan_vdev_list[link]); + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + } +} + +/** + * lim_update_sch_mlo_partner() - update partner information needed in mlo IE + * @mac: pointer to mac + * @pe_session: pointer to pe session + * @bcn_param: pointer to tpSendbeaconParams + * + * Return: void + */ +static void lim_update_sch_mlo_partner(struct mac_context *mac, + struct pe_session *pe_session, + tpSendbeaconParams bcn_param) +{ + int link; + struct ml_sch_partner_info *sch_info; + struct ml_bcn_partner_info *bcn_info; + + bcn_param->mlo_partner.num_links = mac->sch.sch_mlo_partner.num_links; + for (link = 0; link < mac->sch.sch_mlo_partner.num_links; link++) { + sch_info = &mac->sch.sch_mlo_partner.partner_info[link]; + bcn_info = &bcn_param->mlo_partner.partner_info[link]; + bcn_info->vdev_id = sch_info->vdev_id; + bcn_info->beacon_interval = sch_info->beacon_interval; + bcn_info->csa_switch_count_offset = sch_info->bcn_csa_cnt_ofst; + bcn_info->ext_csa_switch_count_offset = + sch_info->bcn_ext_csa_cnt_ofst; + } +} +#else +static void lim_notify_link_info(struct pe_session *pe_session) +{ +} + +static void lim_update_sch_mlo_partner(struct mac_context *mac, + struct pe_session *pe_session, + tpSendbeaconParams bcn_param) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * lim_fd_cap_channel_width320() - populate the capability field for + * 320 channel width in the fils discovery template + * @pe_session: pointer to pe session + * @fd_cap: pointer to fils discovery capability variable + * + * Return: void + */ +static void lim_fd_cap_channel_width320(struct pe_session *pe_session, + uint8_t *fd_cap) +{ + if (pe_session->ch_width == CH_WIDTH_320MHZ) { + *fd_cap |= (WLAN_FD_CHWIDTH_320 << WLAN_FD_CAP_BSS_CHWIDTH_S); + } else { + pe_err("channel width : %d is not supported", + pe_session->ch_width); + } +} + +/** + * lim_populate_fd_capability() - populate the capability field for + * EHT phymode in the fils discovery template + * @cur_phymode: current phymode + * @fd_cap: pointer to fils discovery capability variable + * + * Return: void + */ +static void lim_fd_cap_phymode_EHT(enum wlan_phymode phymode, uint8_t *fd_cap) +{ + switch (phymode) { + case WLAN_PHYMODE_11BEA_EHT20: + case WLAN_PHYMODE_11BEG_EHT20: + case WLAN_PHYMODE_11BEA_EHT40: + case WLAN_PHYMODE_11BEG_EHT40: + case WLAN_PHYMODE_11BEG_EHT40PLUS: + case WLAN_PHYMODE_11BEG_EHT40MINUS: + case WLAN_PHYMODE_11BEA_EHT80: + case WLAN_PHYMODE_11BEA_EHT160: + case WLAN_PHYMODE_11BEA_EHT320: + *fd_cap |= (WLAN_FD_CAP_PHY_INDEX_EHT << + WLAN_FD_CAP_PHY_INDEX_S); + break; + default: + *fd_cap |= (WLAN_FD_CAP_PHY_INDEX_NON_HT_OFDM << + WLAN_FD_CAP_PHY_INDEX_S); + break; + } +} +#else +static void lim_fd_cap_channel_width320(struct pe_session *pe_session, + uint8_t *fd_cap) +{ + pe_err("channel width : %d is not supported", pe_session->ch_width); +} + +static void lim_fd_cap_phymode_EHT(enum wlan_phymode phymode, uint8_t *fd_cap) +{ + *fd_cap |= (WLAN_FD_CAP_PHY_INDEX_NON_HT_OFDM << + WLAN_FD_CAP_PHY_INDEX_S); +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * lim_populate_fd_capability() - populate the capability field in the + * fils discovery template + * @pe_session: pointer to pe session + * @cur_phymode: current phymode + * @fd_cap: pointer to fils discovery capability array + * + * Return: void + */ +static void lim_populate_fd_capability(struct pe_session *pe_session, + enum wlan_phymode cur_phymode, + uint8_t *fd_cap) +{ + /* Setting ESS and Privacy bits */ + fd_cap[0] |= ((!WLAN_FD_CAP_ESS_ENABLE << WLAN_FD_CAP_ESS_S) | + ((pe_session->privacy) << WLAN_FD_CAP_PRIVACY_S)); + + /* Channel Width Selection */ + switch (pe_session->ch_width) { + case CH_WIDTH_20MHZ: + fd_cap[0] |= (WLAN_FD_CHWIDTH_20 << WLAN_FD_CAP_BSS_CHWIDTH_S); + break; + case CH_WIDTH_40MHZ: + fd_cap[0] |= (WLAN_FD_CHWIDTH_40 << WLAN_FD_CAP_BSS_CHWIDTH_S); + break; + case CH_WIDTH_80MHZ: + fd_cap[0] |= (WLAN_FD_CHWIDTH_80 << WLAN_FD_CAP_BSS_CHWIDTH_S); + break; + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + fd_cap[0] |= (WLAN_FD_CHWIDTH_160_80_80 << + WLAN_FD_CAP_BSS_CHWIDTH_S); + break; + default: + lim_fd_cap_channel_width320(pe_session, &fd_cap[0]); + break; + } + + /* Max Num of Spatial Steam */ + switch (pe_session->nss) { + case WLAN_FD_CAP_NSS_MODE_1: + case WLAN_FD_CAP_NSS_MODE_2: + fd_cap[0] |= ((pe_session->nss - 1) << WLAN_FD_CAP_NSS_S); + break; + case WLAN_FD_CAP_NSS_MODE_3: + case WLAN_FD_CAP_NSS_MODE_4: + case WLAN_FD_CAP_NSS_MODE_5: + case WLAN_FD_CAP_NSS_MODE_6: + case WLAN_FD_CAP_NSS_MODE_7: + case WLAN_FD_CAP_NSS_MODE_8: + fd_cap[0] |= (WLAN_FD_CAP_NSS_GTE_5 << WLAN_FD_CAP_NSS_S); + break; + default: + pe_err("NSS value: %d is not supported", pe_session->nss); + break; + } + + /* Set PHY index */ + switch (cur_phymode) { + case WLAN_PHYMODE_11AXA_HE20: + case WLAN_PHYMODE_11AXG_HE20: + case WLAN_PHYMODE_11AXA_HE40: + case WLAN_PHYMODE_11AXG_HE40: + case WLAN_PHYMODE_11AXG_HE40PLUS: + case WLAN_PHYMODE_11AXG_HE40MINUS: + case WLAN_PHYMODE_11AXA_HE80: + case WLAN_PHYMODE_11AXA_HE160: + case WLAN_PHYMODE_11AXA_HE80_80: + fd_cap[1] |= (WLAN_FD_CAP_PHY_INDEX_HE << + WLAN_FD_CAP_PHY_INDEX_S); + break; + case WLAN_PHYMODE_11AC_VHT20: + case WLAN_PHYMODE_11AC_VHT40: + case WLAN_PHYMODE_11AC_VHT80: + case WLAN_PHYMODE_11AC_VHT160: + case WLAN_PHYMODE_11AC_VHT80_80: + fd_cap[1] |= (WLAN_FD_CAP_PHY_INDEX_VHT << + WLAN_FD_CAP_PHY_INDEX_S); + break; + case WLAN_PHYMODE_11NA_HT20: + case WLAN_PHYMODE_11NG_HT20: + case WLAN_PHYMODE_11NG_HT40PLUS: + case WLAN_PHYMODE_11NG_HT40MINUS: + case WLAN_PHYMODE_11NG_HT40: + case WLAN_PHYMODE_11NA_HT40: + fd_cap[1] |= (WLAN_FD_CAP_PHY_INDEX_HT << + WLAN_FD_CAP_PHY_INDEX_S); + break; + default: + lim_fd_cap_phymode_EHT(cur_phymode, &fd_cap[1]); + break; + } + + /* FILS Min Rate */ + fd_cap[1] |= (WLAN_FD_CAP_MIN_RATE << WLAN_FD_CAP_MIN_RATE_S); +} + +/** + * lim_populate_fd_tmpl_frame() - populate the fils discovery frame + * @mac: pointer to mac structure + * @frm: pointer to fils discovery frame + * @pe_session:pointer to pe session + * @frame_size: pointer to fils discovery frame size + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +static QDF_STATUS lim_populate_fd_tmpl_frame(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t *frm, uint32_t *frame_size) +{ + uint16_t fd_cntl_subfield = 0; + struct fd_action_header *fd_header; + struct wlan_objmgr_vdev *vdev; + uint8_t fd_cap[WLAN_FD_CAP_LEN] = {0}; + uint8_t length = 0; + uint8_t ssid_len = 0, ssid[WLAN_SSID_MAX_LEN + 1] = {0}; + uint32_t shortssid; + uint16_t chwidth = pe_session->ch_width; + qdf_freq_t cur_chan_freq = pe_session->curr_op_freq; + struct wlan_channel *des_chan; + enum wlan_phymode cur_phymode; + uint16_t tpe_num = 0; + tDot11fIEtransmit_power_env tpe[WLAN_MAX_NUM_TPE_IE]; + struct tpe_ie *tpe_ie; + uint8_t i, idx; + tSirMacMgmtHdr *mac_hdr; + struct qdf_mac_addr broadcast_mac_addr = QDF_MAC_ADDR_BCAST_INIT; + + pe_debug("FD TMPL freq: %d chWidth: %d", cur_chan_freq, chwidth); + + vdev = pe_session->vdev; + if (!vdev) { + pe_err("VDEV is NULL"); + return QDF_STATUS_E_FAILURE; + } + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) { + pe_err("des_chan is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cur_phymode = des_chan->ch_phymode; + + lim_populate_mac_header(mac, frm, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_ACTION, broadcast_mac_addr.bytes, + pe_session->self_mac_addr); + mac_hdr = (tpSirMacMgmtHdr)frm; + sir_copy_mac_addr(mac_hdr->bssId, pe_session->bssId); + frm += sizeof(*mac_hdr); + *frame_size = sizeof(*mac_hdr); + + /* filling fd header */ + fd_header = (struct fd_action_header *)frm; + fd_header->action_header.action_category = ACTION_CATEGORY_PUBLIC; + fd_header->action_header.action_code = WLAN_ACTION_FILS_DISCOVERY; + + /* + * FILS DIscovery Frame Control Subfield - 2 byte + * Enable Short SSID + * When the Short SSID Indicator subfield is equal to 1, + * the SSID Length subfield is equal to 3 + */ + fd_cntl_subfield = WLAN_FD_SSID_LEN_PRES(WLAN_FD_FRAMECNTL_SHORTSSID_LEN); + fd_cntl_subfield |= WLAN_FD_FRAMECNTL_SHORTSSID; + + if (wlan_reg_is_6ghz_chan_freq(cur_chan_freq)) { + fd_cntl_subfield |= WLAN_FD_FRAMECNTL_CAP; + length = WLAN_FD_CAP_LEN; + } + + /* For 80+80 set Channel center freq segment 1 */ + if (IS_WLAN_PHYMODE_160MHZ(cur_phymode)) { + fd_cntl_subfield |= WLAN_FD_FRAMECNTL_CH_CENTERFREQ; + length += 1; + } + + /* Update the length field */ + /*Indicates length from FD cap to Mobility Domain */ + if (length) + fd_cntl_subfield |= WLAN_FD_FRAMECNTL_LEN_PRES; + + /* FD Control - 2 bytes */ + fd_header->fd_frame_cntl = qdf_cpu_to_le16(fd_cntl_subfield); + + /* Timestamp - 8 bytes */ + qdf_mem_zero(fd_header->timestamp, sizeof(fd_header->timestamp)); + + /* Beacon Interval - 2 bytes */ + fd_header->bcn_interval = + qdf_cpu_to_le16(pe_session->beaconParams.beaconInterval); + + *frame_size += sizeof(*fd_header); + + /* Variable length data */ + frm = &fd_header->elem[0]; + + /* Short SSID - 4 bytes */ + wlan_vdev_mlme_get_ssid(vdev, ssid, &ssid_len); + shortssid = wlan_construct_shortssid(ssid, ssid_len); + *(uint32_t *)frm = qdf_cpu_to_le32(shortssid); + frm += 4; + *frame_size += 4; + + /* Length - 1 byte */ + if (length) { + *frm = length; + pe_debug("length: %d", length); + frm++; + *frame_size += length + 1; + } + + /* FD Capabilities - 2 bytes */ + if (WLAN_FD_IS_CAP_PRESENT(fd_cntl_subfield)) { + lim_populate_fd_capability(pe_session, cur_phymode, &fd_cap[0]); + qdf_mem_copy(frm, fd_cap, WLAN_FD_CAP_LEN); + frm += WLAN_FD_CAP_LEN; + } + + /* Channel Center Freq Segment 1 - 1 byte */ + if (WLAN_FD_IS_FRAMECNTL_CH_CENTERFREQ(fd_cntl_subfield)) { + /* spec has seg0 and seg1 naming while we use seg1 and seg2 */ + *frm = des_chan->ch_freq_seg1; + frm++; + } + + /* Add TPE IE */ + if ((wlan_reg_is_6ghz_chan_freq(cur_chan_freq)) || + (pe_session->vhtCapability)) { + populate_dot11f_tx_power_env(mac, &tpe[0], chwidth, + cur_chan_freq, &tpe_num, false); + if (tpe_num > WLAN_MAX_NUM_TPE_IE) { + pe_err("tpe_num %d greater than max size", tpe_num); + return QDF_STATUS_E_FAILURE; + } + + for (idx = 0; idx < tpe_num; idx++) { + /* filling tpe_header header */ + tpe_ie = (struct tpe_ie *)frm; + tpe_ie->tpe_header.ie_id = WLAN_ELEMID_VHT_TX_PWR_ENVLP; + + if (tpe[idx].num_tx_power > WLAN_MAX_NUM_TPE_IE) { + pe_err("num_tx_power %d greater than max num", + tpe[idx].num_tx_power); + return QDF_STATUS_E_FAILURE; + } + + /* +1 for including tx power info */ + tpe_ie->tpe_header.ie_len = tpe[idx].num_tx_power + 1; + + if (tpe_ie->tpe_header.ie_len < WLAN_TPE_IE_MIN_LEN || + tpe_ie->tpe_header.ie_len > WLAN_TPE_IE_MAX_LEN) { + pe_err("tpe length %d less than min len or greater than max len", + tpe_ie->tpe_header.ie_len); + return QDF_STATUS_E_FAILURE; + } + + tpe_ie->max_tx_pwr_count = tpe[idx].max_tx_pwr_count; + tpe_ie->max_tx_pwr_interpret = + tpe[idx].max_tx_pwr_interpret; + tpe_ie->max_tx_pwr_category = + tpe[idx].max_tx_pwr_category; + frm = &tpe_ie->elem[0]; + + for (i = 0; i < tpe[idx].num_tx_power; i++) { + *frm = tpe[idx].tx_power[i]; + frm++; + } + + /* +2 for including element id and length */ + *frame_size += tpe_ie->tpe_header.ie_len + 2; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_send_fils_discovery_template() - send fils discovery template to + * target_if + * @mac: pointer to mac structure + * @pe_session:pe session + * + * return: status + */ +static QDF_STATUS lim_send_fils_discovery_template(struct mac_context *mac, + struct pe_session *pe_session) +{ + struct fils_discovery_tmpl_params *fd_params; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint32_t n_bytes = sizeof(*fd_params); + + fd_params = qdf_mem_malloc(n_bytes); + + if (!fd_params) + return QDF_STATUS_E_NOMEM; + + fd_params->vdev_id = pe_session->vdev_id; + + fd_params->frm = qdf_mem_malloc(SIR_MAX_FD_TMPL_SIZE); + if (!(fd_params->frm)) { + qdf_mem_free(fd_params); + return QDF_STATUS_E_NOMEM; + } + + status = lim_populate_fd_tmpl_frame(mac, pe_session, fd_params->frm, + &n_bytes); + + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("FAIL bytes %d retcode[%X]", n_bytes, status); + goto memfree; + } + + fd_params->tmpl_len = n_bytes; + fd_params->tmpl_len_aligned = roundup(fd_params->tmpl_len, + sizeof(uint32_t)); + + /* Sending data to wmi layer via target_if */ + status = target_if_vdev_mgr_send_fd_tmpl(pe_session->vdev, + fd_params); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("FAIL bytes %d retcode[%X]", n_bytes, status); + } + +memfree: + qdf_mem_free(fd_params->frm); + qdf_mem_free(fd_params); + return status; +} + +QDF_STATUS sch_send_beacon_req(struct mac_context *mac, uint8_t *beaconPayload, + uint16_t size, struct pe_session *pe_session, + enum sir_bcn_update_reason reason) +{ + struct scheduler_msg msgQ = {0}; + tpSendbeaconParams beaconParams = NULL; + QDF_STATUS retCode; + + if (LIM_IS_AP_ROLE(pe_session) && + (mac->sch.beacon_changed)) { + retCode = lim_send_probe_rsp_template_to_hal(mac, + pe_session, + &pe_session->DefProbeRspIeBitmap[0]); + if (QDF_STATUS_SUCCESS != retCode) + pe_err("FAILED to send probe response template with retCode %d", + retCode); + /*Fils Discovery Template */ + retCode = lim_send_fils_discovery_template(mac, pe_session); + if (QDF_STATUS_SUCCESS != retCode) + pe_err("FAILED to send fils discovery template retCode %d", + retCode); + } + + beaconParams = qdf_mem_malloc(sizeof(tSendbeaconParams)); + if (!beaconParams) + return QDF_STATUS_E_NOMEM; + + msgQ.type = WMA_SEND_BEACON_REQ; + + /* No Dialog Token reqd, as a response is not solicited */ + msgQ.reserved = 0; + + /* Fill in tSendbeaconParams members */ + qdf_mem_copy(beaconParams->bssId, pe_session->bssId, + sizeof(pe_session->bssId)); + + + beaconParams->timIeOffset = pe_session->schBeaconOffsetBegin; + if (pe_session->dfsIncludeChanSwIe) { + beaconParams->csa_count_offset = mac->sch.csa_count_offset; + beaconParams->ecsa_count_offset = mac->sch.ecsa_count_offset; + } + lim_update_sch_mlo_partner(mac, pe_session, beaconParams); + beaconParams->vdev_id = pe_session->smeSessionId; + beaconParams->reason = reason; + + /* p2pIeOffset should be atleast greater than timIeOffset */ + if ((mac->sch.p2p_ie_offset != 0) && + (mac->sch.p2p_ie_offset < + pe_session->schBeaconOffsetBegin)) { + pe_err("Invalid p2pIeOffset:[%d]", + mac->sch.p2p_ie_offset); + QDF_ASSERT(0); + qdf_mem_free(beaconParams); + return QDF_STATUS_E_FAILURE; + } + beaconParams->p2pIeOffset = mac->sch.p2p_ie_offset; + + if (size > SIR_MAX_BEACON_SIZE) { + pe_err("beacon size (%d) exceed host limit %d", + size, SIR_MAX_BEACON_SIZE); + QDF_ASSERT(0); + qdf_mem_free(beaconParams); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(beaconParams->beacon, beaconPayload, size); + + beaconParams->beaconLength = (uint32_t) size; + msgQ.bodyptr = beaconParams; + msgQ.bodyval = 0; + + MTRACE(mac_trace_msg_tx(mac, pe_session->peSessionId, msgQ.type)); + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) + pe_err("Posting SEND_BEACON_REQ to HAL failed, reason=%X", + retCode); + + if (QDF_IS_STATUS_SUCCESS(retCode)) { + if (wlan_vdev_mlme_is_mlo_ap(pe_session->vdev)) + lim_notify_link_info(pe_session); + else + lim_ap_mlme_vdev_rnr_notify(pe_session); + } + + return retCode; +} + +static uint32_t lim_remove_p2p_ie_from_add_ie(struct mac_context *mac, + struct pe_session *pe_session, + uint8_t *addIeWoP2pIe, + uint32_t *addnIELenWoP2pIe) +{ + uint32_t left = pe_session->add_ie_params.probeRespDataLen; + uint8_t *ptr = pe_session->add_ie_params.probeRespData_buff; + uint8_t elem_id, elem_len; + uint32_t offset = 0; + uint8_t eid = 0xDD; + + qdf_mem_copy(addIeWoP2pIe, ptr, left); + *addnIELenWoP2pIe = left; + + if (addIeWoP2pIe) { + while (left >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + left -= 2; + if (elem_len > left) { + pe_err("Invalid IEs"); + return QDF_STATUS_E_FAILURE; + } + if ((elem_id == eid) && + (!qdf_mem_cmp(&ptr[2], + "\x50\x6f\x9a\x09", 4))) { + left -= elem_len; + ptr += (elem_len + 2); + qdf_mem_copy(&addIeWoP2pIe[offset], ptr, left); + *addnIELenWoP2pIe -= (2 + elem_len); + } else { + left -= elem_len; + ptr += (elem_len + 2); + offset += 2 + elem_len; + } + } + } + return QDF_STATUS_SUCCESS; +} + +uint32_t lim_send_probe_rsp_template_to_hal(struct mac_context *mac, + struct pe_session *pe_session, + uint32_t *IeBitmap) +{ + struct scheduler_msg msgQ = {0}; + uint8_t *pFrame2Hal = pe_session->pSchProbeRspTemplate; + tpSendProbeRespParams pprobeRespParams = NULL; + uint32_t retCode = QDF_STATUS_E_FAILURE; + uint32_t nPayload, nBytes = 0, nStatus; + tpSirMacMgmtHdr pMacHdr; + uint32_t addnIEPresent = false; + uint8_t *addIE = NULL; + uint8_t *addIeWoP2pIe = NULL; + uint32_t addnIELenWoP2pIe = 0; + uint32_t retStatus; + tDot11fIEExtCap extracted_extcap; + bool extcap_present = false; + tDot11fProbeResponse *prb_rsp_frm; + QDF_STATUS status; + uint16_t addn_ielen = 0; + uint16_t mlo_ie_len; + + /* Check if probe response IE is present or not */ + addnIEPresent = (pe_session->add_ie_params.probeRespDataLen != 0); + if (addnIEPresent) { + /* + * probe response template should not have P2P IE. + * In case probe request has P2P IE or WPS IE, the + * probe request will be forwarded to the Host and + * Host will send the probe response. In other cases + * FW will send the probe response. So, if the template + * has P2P IE, the probe response sent to non P2P devices + * by the FW, may also have P2P IE which will fail + * P2P cert case 6.1.3 + */ + addIeWoP2pIe = qdf_mem_malloc(pe_session->add_ie_params. + probeRespDataLen); + if (!addIeWoP2pIe) + return QDF_STATUS_E_NOMEM; + + retStatus = lim_remove_p2p_ie_from_add_ie(mac, pe_session, + addIeWoP2pIe, &addnIELenWoP2pIe); + if (retStatus != QDF_STATUS_SUCCESS) { + qdf_mem_free(addIeWoP2pIe); + return QDF_STATUS_E_FAILURE; + } + + /* Probe rsp IE available */ + /*need to check the data length */ + addIE = qdf_mem_malloc(addnIELenWoP2pIe); + if (!addIE) { + qdf_mem_free(addIeWoP2pIe); + return QDF_STATUS_E_NOMEM; + } + addn_ielen = addnIELenWoP2pIe; + + if (addn_ielen <= WNI_CFG_PROBE_RSP_ADDNIE_DATA1_LEN && + addn_ielen && (nBytes + addn_ielen) <= SIR_MAX_PACKET_SIZE) + qdf_mem_copy(addIE, addIeWoP2pIe, addnIELenWoP2pIe); + + qdf_mem_free(addIeWoP2pIe); + + qdf_mem_zero((uint8_t *)&extracted_extcap, + sizeof(tDot11fIEExtCap)); + status = lim_strip_extcap_update_struct(mac, addIE, + &addn_ielen, &extracted_extcap); + if (QDF_STATUS_SUCCESS != status) { + pe_debug("extcap not extracted"); + } else { + extcap_present = true; + } + } + + /* + * Extcap IE now support variable length, merge Extcap IE from addn_ie + * may change the frame size. Therefore, MUST merge ExtCap IE before + * dot11f get packed payload size. + */ + prb_rsp_frm = &pe_session->probeRespFrame; + if (extcap_present) { + lim_merge_extcap_struct(&prb_rsp_frm->ExtCap, + &extracted_extcap, + true); + populate_dot11f_bcn_prot_extcaps(mac, pe_session, + &prb_rsp_frm->ExtCap); + } + + nStatus = dot11f_get_packed_probe_response_size(mac, + &pe_session->probeRespFrame, &nPayload); + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to calculate the packed size for a Probe Response (0x%08x)", + nStatus); + /* We'll fall back on the worst case scenario: */ + nPayload = sizeof(tDot11fProbeResponse); + } else if (DOT11F_WARNED(nStatus)) { + pe_err("There were warnings while calculating the packed size for a Probe Response (0x%08x)", + nStatus); + } + + mlo_ie_len = lim_get_frame_mlo_ie_len(pe_session); + nBytes += nPayload + sizeof(tSirMacMgmtHdr) + mlo_ie_len; + + if (addnIEPresent) { + if ((nBytes + addn_ielen) <= SIR_MAX_PROBE_RESP_SIZE) + nBytes += addn_ielen; + else + addnIEPresent = false; /* Dont include the IE. */ + } + + /* Make sure we are not exceeding allocated len */ + if (nBytes > SIR_MAX_PROBE_RESP_SIZE) { + pe_err("nBytes %d greater than max size", nBytes); + qdf_mem_free(addIE); + return QDF_STATUS_E_FAILURE; + } + + /* Paranoia: */ + qdf_mem_zero(pFrame2Hal, nBytes); + + /* Next, we fill out the buffer descriptor: */ + lim_populate_mac_header(mac, pFrame2Hal, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_PROBE_RSP, + pe_session->self_mac_addr, + pe_session->self_mac_addr); + + pMacHdr = (tpSirMacMgmtHdr) pFrame2Hal; + + sir_copy_mac_addr(pMacHdr->bssId, pe_session->bssId); + + /* That done, pack the Probe Response: */ + nStatus = + dot11f_pack_probe_response(mac, &pe_session->probeRespFrame, + pFrame2Hal + sizeof(tSirMacMgmtHdr), + nPayload, &nPayload); + + if (DOT11F_FAILED(nStatus)) { + pe_err("Failed to pack a Probe Response (0x%08x)", + nStatus); + + qdf_mem_free(addIE); + return retCode; /* allocated! */ + } else if (DOT11F_WARNED(nStatus)) { + pe_warn("There were warnings while packing a P" + "robe Response (0x%08x)", nStatus); + } + + if (mlo_ie_len) { + status = lim_fill_complete_mlo_ie(pe_session, mlo_ie_len, + pFrame2Hal + sizeof(tSirMacMgmtHdr) + + nPayload); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + nPayload += mlo_ie_len; + } + + if (addnIEPresent) { + qdf_mem_copy(&pFrame2Hal[nBytes - addn_ielen], + &addIE[0], addn_ielen); + } + + qdf_mem_free(addIE); + + pprobeRespParams = qdf_mem_malloc(sizeof(tSendProbeRespParams)); + if (!pprobeRespParams) { + pe_err("malloc failed for bytes %d", nBytes); + } else { + sir_copy_mac_addr(pprobeRespParams->bssId, pe_session->bssId); + qdf_mem_copy(pprobeRespParams->probeRespTemplate, + pFrame2Hal, nBytes); + pprobeRespParams->probeRespTemplateLen = nBytes; + qdf_mem_copy(pprobeRespParams->ucProxyProbeReqValidIEBmap, + IeBitmap, (sizeof(uint32_t) * 8)); + if (pe_session->opmode == QDF_P2P_GO_MODE && + cfg_p2p_is_go_ignore_non_p2p_probe_req(mac->psoc)) { + pe_debug("GO ignore non-P2P probe req"); + pprobeRespParams->go_ignore_non_p2p_probe_req = true; + } + + msgQ.type = WMA_SEND_PROBE_RSP_TMPL; + msgQ.reserved = 0; + msgQ.bodyptr = pprobeRespParams; + msgQ.bodyval = 0; + + retCode = wma_post_ctrl_msg(mac, &msgQ); + if (QDF_STATUS_SUCCESS != retCode) { + pe_err("FAIL bytes %d retcode[%X]", nBytes, retCode); + qdf_mem_free(pprobeRespParams); + } + } + + return retCode; +} + +/** + * sch_gen_timing_advert_frame() - Generate the TA frame and populate the buffer + * @mac: the global MAC context + * @self_addr: the self MAC address + * @buf: the buffer that will contain the frame + * @timestamp_offset: return for the offset of the timestamp field + * @time_value_offset: return for the time_value field in the TA IE + * + * Return: the length of the buffer on success and error code on failure. + */ +int sch_gen_timing_advert_frame(struct mac_context *mac_ctx, tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, uint32_t *time_value_offset) +{ + tDot11fTimingAdvertisementFrame frame = {}; + uint32_t payload_size, buf_size; + QDF_STATUS status; + uint32_t ret; + struct qdf_mac_addr wildcard_bssid = { + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, + }; + + /* Populate the TA fields */ + status = populate_dot11f_timing_advert_frame(mac_ctx, &frame); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("Error populating TA frame %x", status); + return qdf_status_to_os_return(status); + } + + ret = dot11f_get_packed_timing_advertisement_frame_size(mac_ctx, + &frame, &payload_size); + if (DOT11F_FAILED(ret)) { + pe_err("Error getting packed frame size %x", ret); + return -EINVAL; + } + if (DOT11F_WARNED(ret)) + pe_warn("Warning getting packed frame size"); + + buf_size = sizeof(tSirMacMgmtHdr) + payload_size; + *buf = qdf_mem_malloc(buf_size); + if (!*buf) + return -ENOMEM; + + payload_size = 0; + ret = dot11f_pack_timing_advertisement_frame(mac_ctx, &frame, + *buf + sizeof(tSirMacMgmtHdr), buf_size - + sizeof(tSirMacMgmtHdr), &payload_size); + pe_debug("TA payload size2 = %d", payload_size); + if (DOT11F_FAILED(ret)) { + pe_err("Error packing frame %x", ret); + goto fail; + } + if (DOT11F_WARNED(ret)) + pe_warn("Warning packing frame"); + + lim_populate_mac_header(mac_ctx, *buf, SIR_MAC_MGMT_FRAME, + SIR_MAC_MGMT_TIME_ADVERT, wildcard_bssid.bytes, self_addr); + + /* The timestamp field is right after the header */ + *timestamp_offset = sizeof(tSirMacMgmtHdr); + + *time_value_offset = sizeof(tSirMacMgmtHdr) + + sizeof(tDot11fFfTimeStamp) + sizeof(tDot11fFfCapabilities); + + /* Add the Country IE length */ + dot11f_get_packed_ie_country(mac_ctx, &frame.Country, + time_value_offset); + /* Add 2 for Country IE EID and Length fields */ + *time_value_offset += 2; + + /* Add the PowerConstraint IE size */ + if (frame.Country.present == 1) + *time_value_offset += 3; + + /* Add the offset inside TA IE */ + *time_value_offset += 3; + + return payload_size + sizeof(tSirMacMgmtHdr); + +fail: + qdf_mem_free(*buf); + *buf = NULL; + return -EINVAL; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c new file mode 100644 index 0000000000..589e4f7315 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_gen.c @@ -0,0 +1,1603 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file sch_beacon_gen.cc contains beacon generation related + * functions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_cfg.h" +#include "ani_global.h" +#include "sir_mac_prot_def.h" + +#include "lim_utils.h" +#include "lim_api.h" + +#include "wma_if.h" +#include "sch_api.h" + +#include "parser_api.h" +#include "wlan_utility.h" +#include "lim_mlo.h" + +/* Offset of Channel Switch count field in CSA/ECSA IE */ +#define SCH_CSA_SWITCH_COUNT_OFFSET 2 +#define SCH_ECSA_SWITCH_COUNT_OFFSET 3 + +const uint8_t p2p_oui[] = { 0x50, 0x6F, 0x9A, 0x9 }; + +/** + * sch_get_csa_ecsa_count_offset() - get the offset of Switch count field + * @ie: pointer to the beginning of IEs in the beacon frame buffer + * @ie_len: length of the IEs in the buffer + * @csa_count_offset: pointer to the csa_count_offset variable in the caller + * @ecsa_count_offset: pointer to the ecsa_count_offset variable in the caller + * + * Gets the offset of the switch count field in the CSA/ECSA IEs from the start + * of the IEs buffer. + * + * Return: None + */ +static void sch_get_csa_ecsa_count_offset(const uint8_t *ie, uint32_t ie_len, + uint32_t *csa_count_offset, + uint32_t *ecsa_count_offset) +{ + const uint8_t *ptr = ie; + uint8_t elem_id; + uint16_t elem_len; + uint32_t offset = 0; + + /* IE is not present */ + if (!ie_len) + return; + + while (ie_len >= 2) { + elem_id = ptr[0]; + elem_len = ptr[1]; + ie_len -= 2; + offset += 2; + + if (elem_id == DOT11F_EID_CHANSWITCHANN && + elem_len == 3) + *csa_count_offset = offset + + SCH_CSA_SWITCH_COUNT_OFFSET; + + if (elem_id == DOT11F_EID_EXT_CHAN_SWITCH_ANN && + elem_len == 4) + *ecsa_count_offset = offset + + SCH_ECSA_SWITCH_COUNT_OFFSET; + + if (ie_len < elem_len) + return; + + ie_len -= elem_len; + offset += elem_len; + ptr += (elem_len + 2); + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * lim_update_link_info() - update mlo_link_info + * @mac_ctx: mac context + * @session: pe session + * @bcn_1: pointer to tDot11fBeacon1 + * @bcn_2: pointer to tDot11fBeacon2 + * + * Return: void + */ +static void lim_update_link_info(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fBeacon1 *bcn_1, + tDot11fBeacon2 *bcn_2) +{ + struct mlo_link_ie *link_ie = &session->mlo_link_info.link_ie; + uint16_t offset; + uint8_t *ptr; + uint32_t n_bytes; + + session->mlo_link_info.upt_bcn_mlo_ie = false; + session->mlo_link_info.bss_param_change = false; + + if (qdf_mem_cmp(&link_ie->link_ds, &bcn_1->DSParams, + sizeof(bcn_1->DSParams))) { + qdf_mem_copy(&link_ie->link_ds, &bcn_1->DSParams, + sizeof(bcn_1->DSParams)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d DSParams changed, critical update", + wlan_vdev_get_id(session->vdev)); + } + + qdf_mem_copy(&link_ie->link_wmm_params, &bcn_2->WMMParams, + sizeof(bcn_2->WMMParams)); + + qdf_mem_copy(&link_ie->link_wmm_caps, &bcn_2->WMMCaps, + sizeof(bcn_2->WMMCaps)); + + if (qdf_mem_cmp(&link_ie->link_edca, &bcn_2->EDCAParamSet, + sizeof(bcn_2->EDCAParamSet))) { + qdf_mem_copy(&link_ie->link_edca, &bcn_2->EDCAParamSet, + sizeof(bcn_2->EDCAParamSet)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d EDCAParamSet changed, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_csa, &bcn_2->ChanSwitchAnn, + sizeof(bcn_2->ChanSwitchAnn))) { + session->mlo_link_info.upt_bcn_mlo_ie = true; + qdf_mem_copy(&link_ie->link_csa, &bcn_2->ChanSwitchAnn, + sizeof(bcn_2->ChanSwitchAnn)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d csa added, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_ecsa, &bcn_2->ext_chan_switch_ann, + sizeof(bcn_2->ext_chan_switch_ann))) { + session->mlo_link_info.upt_bcn_mlo_ie = true; + qdf_mem_copy(&link_ie->link_ecsa, &bcn_2->ext_chan_switch_ann, + sizeof(bcn_2->ext_chan_switch_ann)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d ecsa added, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_swt_time, &bcn_2->max_chan_switch_time, + sizeof(bcn_2->max_chan_switch_time))) { + session->mlo_link_info.upt_bcn_mlo_ie = true; + qdf_mem_copy(&link_ie->link_swt_time, + &bcn_2->max_chan_switch_time, + sizeof(bcn_2->max_chan_switch_time)); + pe_debug("vdev id %d max channel switch time added", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_quiet, &bcn_2->Quiet, + sizeof(bcn_2->Quiet))) { + session->mlo_link_info.upt_bcn_mlo_ie = true; + qdf_mem_copy(&link_ie->link_quiet, &bcn_2->Quiet, + sizeof(bcn_2->Quiet)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d quiet added, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_ht_info, &bcn_2->HTInfo, + sizeof(bcn_2->HTInfo))) { + qdf_mem_copy(&link_ie->link_ht_info, &bcn_2->HTInfo, + sizeof(bcn_2->HTInfo)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d HTInfo changed, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_vht_op, &bcn_2->VHTOperation, + sizeof(bcn_2->VHTOperation))) { + qdf_mem_copy(&link_ie->link_vht_op, &bcn_2->VHTOperation, + sizeof(bcn_2->VHTOperation)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d VHTOperation changed, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_he_op, &bcn_2->he_op, + sizeof(bcn_2->he_op))) { + qdf_mem_copy(&link_ie->link_he_op, &bcn_2->he_op, + sizeof(bcn_2->he_op)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d he_op changed, critical update", + wlan_vdev_get_id(session->vdev)); + } + + if (qdf_mem_cmp(&link_ie->link_eht_op, &bcn_2->eht_op, + sizeof(bcn_2->eht_op))) { + qdf_mem_copy(&link_ie->link_eht_op, &bcn_2->eht_op, + sizeof(bcn_2->eht_op)); + session->mlo_link_info.bss_param_change = true; + pe_debug("vdev id %d eht_op changed, critical update", + wlan_vdev_get_id(session->vdev)); + } + + /* + * MLOTD + * If max channel switch time is not exist, calculate one for partner + * link, if current link enters CAC + */ + + if (session->mlo_link_info.bcn_tmpl_exist) { + if (bcn_2->ChanSwitchAnn.present || + bcn_2->ext_chan_switch_ann.present || + bcn_2->Quiet.present || + bcn_2->WiderBWChanSwitchAnn.present || + bcn_2->ChannelSwitchWrapper.present || + bcn_2->OperatingMode.present || + bcn_2->bss_color_change.present) + session->mlo_link_info.bss_param_change = true; + if (session->mlo_link_info.bss_param_change) { + link_ie->bss_param_change_cnt++; + offset = sizeof(tAniBeaconStruct); + bcn_1->Capabilities.criticalUpdateFlag = 1; + ptr = session->pSchBeaconFrameBegin + offset; + dot11f_pack_beacon1(mac_ctx, bcn_1, ptr, + SIR_MAX_BEACON_SIZE - offset, + &n_bytes); + bcn_1->Capabilities.criticalUpdateFlag = 0; + mlme_set_notify_co_located_ap_update_rnr(session->vdev, + true); + } + } else { + //save one time + session->mlo_link_info.bcn_tmpl_exist = true; + session->mlo_link_info.link_ie.bss_param_change_cnt = 0; + qdf_mem_copy(&link_ie->link_cap, &bcn_1->Capabilities, + sizeof(bcn_1->Capabilities)); + qdf_mem_copy(&link_ie->link_qcn_ie, &bcn_2->qcn_ie, + sizeof(bcn_2->qcn_ie)); + qdf_mem_copy(&link_ie->link_ht_cap, &bcn_2->HTCaps, + sizeof(bcn_2->HTCaps)); + qdf_mem_copy(&link_ie->link_ext_cap, &bcn_2->ExtCap, + sizeof(bcn_2->ExtCap)); + qdf_mem_copy(&link_ie->link_vht_cap, &bcn_2->VHTCaps, + sizeof(bcn_2->VHTCaps)); + qdf_mem_copy(&link_ie->link_he_cap, &bcn_2->he_cap, + sizeof(bcn_2->he_cap)); + qdf_mem_copy(&link_ie->link_he_6ghz_band_cap, + &bcn_2->he_6ghz_band_cap, + sizeof(bcn_2->he_6ghz_band_cap)); + qdf_mem_copy(&link_ie->link_eht_cap, &bcn_2->eht_cap, + sizeof(bcn_2->eht_cap)); + } +} + +static void lim_upt_mlo_partner_info(struct mac_context *mac, + struct pe_session *session, + uint8_t *ie, uint32_t ie_len, + uint16_t ie_offset) +{ + const uint8_t *mlo_ie; + uint16_t subie_len; + const uint8_t *subie_sta_prof; + uint16_t subie_sta_prof_len; + int link; + struct ml_sch_partner_info *sch_info; + uint16_t per_sta_ofst = mac->sch.sch_mlo_partner.mlo_ie_link_info_ofst; + + mlo_ie = wlan_get_ext_ie_ptr_from_ext_id(MLO_IE_OUI_TYPE, + MLO_IE_OUI_SIZE, + ie, ie_len); + /* IE is not present */ + if (!mlo_ie) { + pe_err("no mlo ie in mlo ap vdev id %d", session->vdev_id); + return; + } + for (link = 0; link < mac->sch.sch_mlo_partner.num_links; link++) { + sch_info = &mac->sch.sch_mlo_partner.partner_info[link]; + if (!sch_info->link_info_sta_prof_ofst) + continue; + if (!sch_info->csa_ext_csa_exist) { + per_sta_ofst += 1; /* subelement ID */ + subie_len = mlo_ie[per_sta_ofst]; + per_sta_ofst += 1; /* length */ + per_sta_ofst += subie_len; /* payload of per sta info */ + continue; + } + subie_sta_prof = mlo_ie + per_sta_ofst + + sch_info->link_info_sta_prof_ofst; + per_sta_ofst += 1; /* subelement ID */ + subie_len = mlo_ie[per_sta_ofst]; + per_sta_ofst += 1; /* length */ + per_sta_ofst += subie_len; /* payload of per sta info */ + subie_sta_prof_len = subie_len + 2 - + sch_info->link_info_sta_prof_ofst; + sch_get_csa_ecsa_count_offset(subie_sta_prof, + subie_sta_prof_len, + &sch_info->bcn_csa_cnt_ofst, + &sch_info->bcn_ext_csa_cnt_ofst); + /* plus offset from IE of sta prof to ie */ + if (sch_info->bcn_csa_cnt_ofst) + sch_info->bcn_csa_cnt_ofst += ie_offset + + subie_sta_prof - ie; + if (sch_info->bcn_ext_csa_cnt_ofst) + sch_info->bcn_ext_csa_cnt_ofst += ie_offset + + subie_sta_prof - ie; + pe_debug("vdev %d mlo csa_count_offset %d ecsa_count_offset %d", + sch_info->vdev_id, sch_info->bcn_csa_cnt_ofst, + sch_info->bcn_ext_csa_cnt_ofst); + } +} +#else +static void lim_update_link_info(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fBeacon1 *bcn_1, + tDot11fBeacon2 *bcn_2) +{ +} + +static void lim_upt_mlo_partner_info(struct mac_context *mac, + struct pe_session *session, + uint8_t *ie, uint32_t ie_len, + uint16_t ie_offset) +{ +} +#endif + +static QDF_STATUS sch_get_p2p_ie_offset(uint8_t *pextra_ie, + uint32_t extra_ie_len, + uint16_t *pie_offset) +{ + uint8_t elem_id; + uint8_t elem_len; + uint8_t *ie_ptr = pextra_ie; + uint8_t oui_size = sizeof(p2p_oui); + uint32_t p2p_ie_offset = 0; + uint32_t left_len = extra_ie_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + *pie_offset = 0; + while (left_len > 2) { + elem_id = ie_ptr[0]; + elem_len = ie_ptr[1]; + left_len -= 2; + + if (elem_len > left_len) + return status; + + if ((elem_id == 0xDD) && (elem_len >= oui_size)) { + if (!qdf_mem_cmp(&ie_ptr[2], &p2p_oui, oui_size)) { + *pie_offset = p2p_ie_offset; + return QDF_STATUS_SUCCESS; + } + } + + left_len -= elem_len; + ie_ptr += (elem_len + 2); + p2p_ie_offset += (elem_len + 2); + }; + + return status; +} + +/** + * sch_append_addn_ie() - adds additional IEs to frame + * @mac_ctx: mac global context + * @session: pe session pointer + * @frm: frame where additional IE is to be added + * @bcn_size_left: beacon size left + * @num_bytes: final size + * @addn_ie: pointer to additional IE + * @addn_ielen: length of additional IE + * + * Return: status of operation + */ +static QDF_STATUS +sch_append_addn_ie(struct mac_context *mac_ctx, struct pe_session *session, + uint8_t *frm, uint32_t bcn_size_left, + uint32_t *num_bytes, uint8_t *addn_ie, uint16_t addn_ielen) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t add_ie[WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN]; + uint8_t *p2p_ie = NULL; + uint8_t noa_len = 0; + uint8_t noa_strm[SIR_MAX_NOA_ATTR_LEN + SIR_P2P_IE_HEADER_LEN]; + uint8_t ext_p2p_ie[DOT11F_IE_P2PBEACON_MAX_LEN + 2]; + bool valid_ie; + + valid_ie = (addn_ielen <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN && + addn_ielen && (addn_ielen <= bcn_size_left)); + if (!valid_ie) { + pe_err("addn_ielen %d exceed left %d", + addn_ielen, bcn_size_left); + return status; + } + + qdf_mem_zero(&ext_p2p_ie[0], DOT11F_IE_P2PBEACON_MAX_LEN + 2); + /* + * P2P IE extracted in wlan_hdd_add_hostapd_conf_vsie may not + * be at the end of additional IE buffer. The buffer sent to WMA + * expect P2P IE at the end of beacon buffer and will result in + * beacon corruption if P2P IE is not at end of beacon buffer. + */ + status = lim_strip_ie(mac_ctx, addn_ie, &addn_ielen, WLAN_ELEMID_VENDOR, + ONE_BYTE, SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE, + ext_p2p_ie, DOT11F_IE_P2PBEACON_MAX_LEN); + + qdf_mem_copy(&add_ie[0], addn_ie, addn_ielen); + + if (status == QDF_STATUS_SUCCESS && + ext_p2p_ie[0] == WLAN_ELEMID_VENDOR && + !qdf_mem_cmp(&ext_p2p_ie[2], SIR_MAC_P2P_OUI, + SIR_MAC_P2P_OUI_SIZE)) { + qdf_mem_copy(&add_ie[addn_ielen], ext_p2p_ie, + ext_p2p_ie[1] + 2); + addn_ielen += ext_p2p_ie[1] + 2; + } + + p2p_ie = (uint8_t *)limGetP2pIEPtr(mac_ctx, &add_ie[0], addn_ielen); + if ((p2p_ie) && !mac_ctx->beacon_offload) { + /* get NoA attribute stream P2P IE */ + noa_len = lim_get_noa_attr_stream(mac_ctx, noa_strm, session); + if (noa_len) { + if ((noa_len + addn_ielen) <= + WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + qdf_mem_copy(&add_ie[addn_ielen], noa_strm, + noa_len); + addn_ielen += noa_len; + p2p_ie[1] += noa_len; + } else { + pe_err("Not able to insert NoA because of length constraint"); + } + } + } + if (addn_ielen <= WNI_CFG_PROBE_RSP_BCN_ADDNIE_DATA_LEN) { + qdf_mem_copy(frm, &add_ie[0], addn_ielen); + *num_bytes = *num_bytes + addn_ielen; + } else { + pe_warn("Not able to insert because of len constraint %d", + addn_ielen); + } + return status; +} + +static void +populate_channel_switch_ann(struct mac_context *mac_ctx, + tDot11fBeacon2 *bcn, + struct pe_session *pe_session) +{ + populate_dot11f_chan_switch_ann(mac_ctx, &bcn->ChanSwitchAnn, + pe_session); + if (!pe_session->dfsIncludeChanWrapperIe) + return; + + populate_dot11f_chan_switch_wrapper(mac_ctx, + &bcn->ChannelSwitchWrapper, + pe_session); +} + +/** + * sch_get_tim_size() - Get TIM ie size + * @max_aid: Max AID value + * + * Return: TIM ie size + */ +static uint16_t sch_get_tim_size(uint32_t max_aid) +{ + uint16_t tim_size; + uint8_t N2; + + /** + * The TIM ie format: + * +----------+------+----------+-------------------------------------------------+ + * |Element ID|Length|DTIM Count|DTIM Period|Bitmap Control|Partial Virtual Bitmap| + * +----------+------+----------+-----------+--------------+----------------------+ + * 1 Byte 1 Byte 1Byte 1 Byte 1 Byte 0~255 Byte + * + * According to 80211 Spec, The Partial Virtual Bitmap field consists of octets + * numbered N1 to N2 of the traffic indication virtual bitmap, where N1 is the + * largest even number such that bits numbered 1 to (N1 * 8) – 1 in the traffic + * indication virtual bitmap are all 0, and N2 is the smallest number such that + * bits numbered (N2 + 1) * 8 to 2007 in the traffic indication virtual bitmap + * are all 0. In this case, the Bitmap Offset subfield value contains the number + * N1/2, and the Length field is set to (N2 – N1) + 4. Always start with AID 1 as + * minimum, N1 = (1 / 8) = 0. TIM size = length + 1Byte Element ID + 1Byte Length. + * The expression is reduced to (N2 - 0) + 4 + 2 = N2 + 6; + */ + N2 = max_aid / 8; + tim_size = N2 + 6; + + return tim_size; +} + +#ifdef SAP_MULTI_LINK_EMULATION +static void omit_caps_for_2link_sap(tDot11fBeacon2 *bcn_2) +{ + qdf_mem_zero(&bcn_2->HTCaps, sizeof(bcn_2->HTCaps)); + qdf_mem_zero(&bcn_2->EDCAParamSet, sizeof(bcn_2->EDCAParamSet)); + qdf_mem_zero(&bcn_2->PowerConstraints, sizeof(bcn_2->PowerConstraints)); + qdf_mem_zero(&bcn_2->TPCReport, sizeof(bcn_2->TPCReport)); + + pe_debug("Removed caps from beacon/probe rsp"); +} +#else +static inline void omit_caps_for_2link_sap(tDot11fBeacon2 *bcn_2) +{ +} +#endif + +/** + * sch_set_fixed_beacon_fields() - sets the fixed params in beacon frame + * @mac_ctx: mac global context + * @session: pe session entry + * @band: out param, band caclculated + * @opr_ch: operating channels + * + * Return: status of operation + */ + +QDF_STATUS +sch_set_fixed_beacon_fields(struct mac_context *mac_ctx, struct pe_session *session) +{ + tpAniBeaconStruct bcn_struct = (tpAniBeaconStruct) + session->pSchBeaconFrameBegin; + tpSirMacMgmtHdr mac; + uint16_t offset, bcn_size_left; + uint8_t *ptr; + tDot11fBeacon1 *bcn_1; + tDot11fBeacon2 *bcn_2; + uint32_t i, n_status, n_bytes; + bool wps_ap_enable = 0; + tDot11fIEWscProbeRes *wsc_prb_res; + uint8_t *extra_ie = NULL; + uint32_t extra_ie_len = 0; + uint16_t extra_ie_offset = 0; + uint16_t p2p_ie_offset = 0; + uint32_t csa_count_offset = 0; + uint32_t ecsa_count_offset = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool is_vht_enabled = false; + uint16_t addn_ielen = 0; + uint8_t *addn_ie = NULL; + tDot11fIEExtCap extracted_extcap; + bool extcap_present = true, addnie_present = false; + bool is_6ghz_chsw; + uint8_t *eht_op_ie = NULL, eht_op_ie_len = 0; + uint8_t *eht_cap_ie = NULL, eht_cap_ie_len = 0; + bool is_band_2g; + uint16_t ie_buf_size; + uint16_t mlo_ie_len = 0; + uint16_t tim_size; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + uint16_t tpe_ie_len = 0; + tDot11fIEtransmit_power_env *transmit_power_env = NULL; + uint16_t num_transmit_power_env = 0; + + tim_size = sch_get_tim_size(HAL_NUM_STA); + + bcn_1 = qdf_mem_malloc(sizeof(tDot11fBeacon1)); + if (!bcn_1) + return QDF_STATUS_E_NOMEM; + + bcn_2 = qdf_mem_malloc(sizeof(tDot11fBeacon2)); + if (!bcn_2) { + qdf_mem_free(bcn_1); + return QDF_STATUS_E_NOMEM; + } + + wsc_prb_res = qdf_mem_malloc(sizeof(tDot11fIEWscProbeRes)); + if (!wsc_prb_res) { + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + return QDF_STATUS_E_NOMEM; + } + /* + * First set the fixed fields: + * set the TFP headers, set the mac header + */ + qdf_mem_zero((uint8_t *) &bcn_struct->macHdr, sizeof(tSirMacMgmtHdr)); + mac = (tpSirMacMgmtHdr) &bcn_struct->macHdr; + mac->fc.type = SIR_MAC_MGMT_FRAME; + mac->fc.subType = SIR_MAC_MGMT_BEACON; + + for (i = 0; i < 6; i++) + mac->da[i] = 0xff; + + qdf_mem_copy(mac->sa, session->self_mac_addr, + sizeof(session->self_mac_addr)); + qdf_mem_copy(mac->bssId, session->bssId, sizeof(session->bssId)); + + mac->fc.fromDS = 0; + mac->fc.toDS = 0; + + /* Skip over the timestamp (it'll be updated later). */ + bcn_1->BeaconInterval.interval = + session->beaconParams.beaconInterval; + populate_dot11f_capabilities(mac_ctx, &bcn_1->Capabilities, session); + if (session->ssidHidden) { + bcn_1->SSID.present = 1; + /* rest of the fields are 0 for hidden ssid */ + if ((session->ssId.length) && + (session->ssidHidden == eHIDDEN_SSID_ZERO_CONTENTS)) + bcn_1->SSID.num_ssid = session->ssId.length; + } else { + populate_dot11f_ssid(mac_ctx, &session->ssId, &bcn_1->SSID); + } + + populate_dot11f_supp_rates(mac_ctx, POPULATE_DOT11F_RATES_OPERATIONAL, + &bcn_1->SuppRates, session); + populate_dot11f_ds_params(mac_ctx, &bcn_1->DSParams, + session->curr_op_freq); + + offset = sizeof(tAniBeaconStruct); + ptr = session->pSchBeaconFrameBegin + offset; + + if (LIM_IS_AP_ROLE(session)) { + /* Initialize the default IE bitmap to zero */ + qdf_mem_zero((uint8_t *) &(session->DefProbeRspIeBitmap), + (sizeof(uint32_t) * 8)); + + /* Initialize the default IE bitmap to zero */ + qdf_mem_zero((uint8_t *) &(session->probeRespFrame), + sizeof(session->probeRespFrame)); + + /* + * Can be efficiently updated whenever new IE added in Probe + * response in future + */ + if (lim_update_probe_rsp_template_ie_bitmap_beacon1(mac_ctx, + bcn_1, session) != QDF_STATUS_SUCCESS) + pe_err("Failed to build ProbeRsp template"); + } + + n_status = dot11f_pack_beacon1(mac_ctx, bcn_1, ptr, + SIR_MAX_BEACON_SIZE - offset, &n_bytes); + if (DOT11F_FAILED(n_status)) { + pe_err("Failed to packed a tDot11fBeacon1 (0x%08x)", + n_status); + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(n_status)) { + pe_warn("Warnings while packing a tDot11fBeacon1(0x%08x)", + n_status); + } + session->schBeaconOffsetBegin = offset + (uint16_t) n_bytes; + /* Initialize the 'new' fields at the end of the beacon */ + is_6ghz_chsw = + WLAN_REG_IS_6GHZ_CHAN_FREQ(session->curr_op_freq) || + WLAN_REG_IS_6GHZ_CHAN_FREQ + (session->gLimChannelSwitch.sw_target_freq); + if (session->limSystemRole == eLIM_AP_ROLE && + (session->dfsIncludeChanSwIe == true || + session->bw_update_include_ch_sw_ie == true)) { + if (!CHAN_HOP_ALL_BANDS_ENABLE || + session->lim_non_ecsa_cap_num == 0 || is_6ghz_chsw) { + tDot11fIEext_chan_switch_ann *ext_csa = + &bcn_2->ext_chan_switch_ann; + populate_dot_11_f_ext_chann_switch_ann(mac_ctx, + ext_csa, + session); + if (lim_is_session_eht_capable(session)) { + bcn_2->ChannelSwitchWrapper.present = 1; + populate_dot11f_bw_ind_element(mac_ctx, + session, + &bcn_2->ChannelSwitchWrapper.bw_ind_element); + } + } + if (session->lim_non_ecsa_cap_num && + !is_6ghz_chsw) + populate_channel_switch_ann(mac_ctx, bcn_2, session); + + } + + populate_dot11_supp_operating_classes(mac_ctx, + &bcn_2->SuppOperatingClasses, session); + populate_dot11f_country(mac_ctx, &bcn_2->Country, session); + if (bcn_1->Capabilities.qos) + populate_dot11f_edca_param_set(mac_ctx, &bcn_2->EDCAParamSet, + session); + + if (session->lim11hEnable) { + populate_dot11f_power_constraints(mac_ctx, + &bcn_2->PowerConstraints); + populate_dot11f_tpc_report(mac_ctx, &bcn_2->TPCReport, session); + /* Need to insert channel switch announcement here */ + if ((LIM_IS_AP_ROLE(session) || + LIM_IS_P2P_DEVICE_GO(session)) && + session->dfsIncludeChanSwIe && !is_6ghz_chsw) { + populate_channel_switch_ann(mac_ctx, bcn_2, session); + } + } + + if (bcn_2->ext_chan_switch_ann.present || bcn_2->ChanSwitchAnn.present) + populate_dot11f_max_chan_switch_time( + mac_ctx, &bcn_2->max_chan_switch_time, session); + + if (mac_ctx->rrm.rrmConfig.sap_rrm_enabled) + populate_dot11f_rrm_ie(mac_ctx, &bcn_2->RRMEnabledCap, + session); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* populate proprietary IE for MDM device operating in AP-MCC */ + populate_dot11f_avoid_channel_ie(mac_ctx, &bcn_2->QComVendorIE, + session); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (session->dot11mode != MLME_DOT11_MODE_11B) + populate_dot11f_erp_info(mac_ctx, &bcn_2->ERPInfo, session); + + populate_dot11f_qcn_ie(mac_ctx, session, &bcn_2->qcn_ie, + QCN_IE_ATTR_ID_ALL); + + if (session->htCapability) { + populate_dot11f_ht_caps(mac_ctx, session, &bcn_2->HTCaps); + populate_dot11f_ht_info(mac_ctx, &bcn_2->HTInfo, session); + } + if (session->vhtCapability) { + populate_dot11f_vht_caps(mac_ctx, session, &bcn_2->VHTCaps); + populate_dot11f_vht_operation(mac_ctx, session, + &bcn_2->VHTOperation); + is_vht_enabled = true; + /* following is for MU MIMO: we do not support it yet */ + /* + populate_dot11f_vht_ext_bss_load( mac_ctx, &bcn2.VHTExtBssLoad); + */ + } + + if (session->vhtCapability || + wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + transmit_power_env = qdf_mem_malloc( + WLAN_MAX_NUM_TPE_IE * + sizeof(tDot11fIEtransmit_power_env)); + if (!transmit_power_env) { + status = QDF_STATUS_E_NOMEM; + goto free_and_exit; + } + populate_dot11f_tx_power_env(mac_ctx, + transmit_power_env, + session->ch_width, + session->curr_op_freq, + &num_transmit_power_env, + false); + tpe_ie_len = lim_get_tpe_ie_length(session->ch_width, + transmit_power_env, + num_transmit_power_env); + } + + if (lim_is_session_he_capable(session)) { + populate_dot11f_he_caps(mac_ctx, session, + &bcn_2->he_cap); + populate_dot11f_he_operation(mac_ctx, session, + &bcn_2->he_op); + populate_dot11f_sr_info(mac_ctx, session, + &bcn_2->spatial_reuse); + populate_dot11f_he_6ghz_cap(mac_ctx, session, + &bcn_2->he_6ghz_band_cap); + populate_dot11f_he_bss_color_change(mac_ctx, session, + &bcn_2->bss_color_change); + } + + if (lim_is_session_eht_capable(session)) { + populate_dot11f_eht_caps(mac_ctx, session, &bcn_2->eht_cap); + populate_dot11f_eht_operation(mac_ctx, session, &bcn_2->eht_op); + } + + populate_dot11f_ext_cap(mac_ctx, is_vht_enabled, &bcn_2->ExtCap, + session); + + populate_dot11f_ext_supp_rates(mac_ctx, + POPULATE_DOT11F_RATES_OPERATIONAL, + &bcn_2->ExtSuppRates, session); + + if (session->pLimStartBssReq) { + populate_dot11f_wpa(mac_ctx, &session->pLimStartBssReq->rsnIE, + &bcn_2->WPA); + populate_dot11f_rsn_opaque(mac_ctx, + &session->pLimStartBssReq->rsnIE, + &bcn_2->RSNOpaque); + populate_dot11f_wapi(mac_ctx, &session->pLimStartBssReq->rsnIE, + &bcn_2->WAPI); + } + + if (session->limWmeEnabled) + populate_dot11f_wmm(mac_ctx, &bcn_2->WMMInfoAp, + &bcn_2->WMMParams, &bcn_2->WMMCaps, session); + + if (LIM_IS_AP_ROLE(session)) { + if (session->wps_state != SAP_WPS_DISABLED) { + populate_dot11f_beacon_wpsi_es(mac_ctx, + &bcn_2->WscBeacon, session); + } + } else { + wps_ap_enable = mac_ctx->mlme_cfg->wps_params.enable_wps & + WNI_CFG_WPS_ENABLE_AP; + if (wps_ap_enable) + populate_dot11f_wsc(mac_ctx, &bcn_2->WscBeacon); + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_BEGIN) { + populate_dot11f_wsc_registrar_info(mac_ctx, + &bcn_2->WscBeacon); + mac_ctx->lim.wscIeInfo.wscEnrollmentState = + eLIM_WSC_ENROLL_IN_PROGRESS; + } + + if (mac_ctx->lim.wscIeInfo.wscEnrollmentState == + eLIM_WSC_ENROLL_END) { + de_populate_dot11f_wsc_registrar_info(mac_ctx, + &bcn_2->WscBeacon); + mac_ctx->lim.wscIeInfo.wscEnrollmentState = + eLIM_WSC_ENROLL_NOOP; + } + } + + if (LIM_IS_AP_ROLE(session)) { + if (wlan_vdev_mlme_is_mlo_ap(session->vdev)) { + lim_update_link_info(mac_ctx, session, bcn_1, bcn_2); + mlo_ie_len = lim_send_bcn_frame_mlo(mac_ctx, session); + populate_dot11f_mlo_rnr( + mac_ctx, session, + &bcn_2->reduced_neighbor_report); + } else if (!wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + /* + * TD: If current AP is MLO, RNR IE is already populated + * More effor to populate RNR IE for + * MLO SAP + 6G legacy SAP + */ + populate_dot11f_6g_rnr(mac_ctx, session, + &bcn_2->reduced_neighbor_report); + } + /* + * Can be efficiently updated whenever new IE added in Probe + * response in future + */ + lim_update_probe_rsp_template_ie_bitmap_beacon2(mac_ctx, bcn_2, + &session->DefProbeRspIeBitmap[0], + &session->probeRespFrame); + + /* update probe response WPS IE instead of beacon WPS IE */ + if (session->wps_state != SAP_WPS_DISABLED) { + if (session->APWPSIEs.SirWPSProbeRspIE.FieldPresent) + populate_dot11f_probe_res_wpsi_es(mac_ctx, + wsc_prb_res, session); + else + wsc_prb_res->present = 0; + if (wsc_prb_res->present) { + set_probe_rsp_ie_bitmap( + &session->DefProbeRspIeBitmap[0], + SIR_MAC_WPA_EID); + qdf_mem_copy((void *) + &session->probeRespFrame.WscProbeRes, + (void *)wsc_prb_res, + sizeof(tDot11fIEWscProbeRes)); + } + } + } + + addnie_present = (session->add_ie_params.probeRespBCNDataLen != 0); + if (addnie_present) { + /* + * Strip HE cap/op from additional IE buffer if any, as they + * should be populated already. + */ + lim_strip_he_ies_from_add_ies(mac_ctx, session); + lim_strip_eht_ies_from_add_ies(mac_ctx, session); + lim_strip_wapi_ies_from_add_ies(mac_ctx, session); + + addn_ielen = session->add_ie_params.probeRespBCNDataLen; + addn_ie = qdf_mem_malloc(addn_ielen); + if (!addn_ie) { + status = QDF_STATUS_E_NOMEM; + goto free_and_exit; + } + qdf_mem_copy(addn_ie, + session->add_ie_params.probeRespBCNData_buff, + addn_ielen); + + qdf_mem_zero((uint8_t *)&extracted_extcap, + sizeof(tDot11fIEExtCap)); + status = lim_strip_extcap_update_struct(mac_ctx, addn_ie, + &addn_ielen, &extracted_extcap); + if (QDF_STATUS_SUCCESS != status) { + extcap_present = false; + pe_debug("extcap not extracted"); + } + /* merge extcap IE */ + if (extcap_present) { + lim_merge_extcap_struct(&bcn_2->ExtCap, + &extracted_extcap, + true); + populate_dot11f_bcn_prot_extcaps(mac_ctx, session, + &bcn_2->ExtCap); + } + } + + if (session->vhtCapability && session->gLimOperatingMode.present) { + populate_dot11f_operating_mode(mac_ctx, &bcn_2->OperatingMode, + session); + lim_strip_ie(mac_ctx, addn_ie, &addn_ielen, + WLAN_ELEMID_OP_MODE_NOTIFY, ONE_BYTE, NULL, 0, + NULL, SIR_MAC_VHT_OPMODE_SIZE - 2); + } + + omit_caps_for_2link_sap(bcn_2); + + n_status = dot11f_pack_beacon2(mac_ctx, bcn_2, + session->pSchBeaconFrameEnd, + SIR_MAX_BEACON_SIZE, &n_bytes); + if (DOT11F_FAILED(n_status)) { + pe_err("Failed to packed a tDot11fBeacon2 (0x%08x)", + n_status); + status = QDF_STATUS_E_FAILURE; + goto free_and_exit; + } else if (DOT11F_WARNED(n_status)) { + pe_err("Warnings while packing a tDot11fBeacon2(0x%08x)", + n_status); + } + + /* Strip EHT capabilities IE */ + if (lim_is_session_eht_capable(session)) { + ie_buf_size = n_bytes; + + eht_op_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!eht_op_ie) { + pe_err("malloc failed for eht_op_ie"); + status = QDF_STATUS_E_FAILURE; + goto free_and_exit; + } + + status = lim_strip_eht_op_ie(mac_ctx, + session->pSchBeaconFrameEnd, + &ie_buf_size, eht_op_ie); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to strip EHT op IE"); + qdf_mem_free(eht_op_ie); + status = QDF_STATUS_E_FAILURE; + goto free_and_exit; + } + + lim_ieee80211_pack_ehtop(eht_op_ie, bcn_2->eht_op, + bcn_2->VHTOperation, + bcn_2->he_op, + bcn_2->HTInfo); + eht_op_ie_len = eht_op_ie[1] + 2; + + /* Copy the EHT operation IE to the end of the frame */ + qdf_mem_copy(session->pSchBeaconFrameEnd + ie_buf_size, + eht_op_ie, eht_op_ie_len); + qdf_mem_free(eht_op_ie); + n_bytes = ie_buf_size + eht_op_ie_len; + + ie_buf_size = n_bytes; + eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (!eht_cap_ie) { + pe_err("malloc failed for eht_cap_ie"); + status = QDF_STATUS_E_FAILURE; + goto free_and_exit; + } + status = lim_strip_eht_cap_ie(mac_ctx, + session->pSchBeaconFrameEnd, + &ie_buf_size, eht_cap_ie); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to strip EHT cap IE"); + qdf_mem_free(eht_cap_ie); + status = QDF_STATUS_E_FAILURE; + goto free_and_exit; + } + + is_band_2g = + WLAN_REG_IS_24GHZ_CH_FREQ(session->curr_op_freq); + + lim_ieee80211_pack_ehtcap(eht_cap_ie, bcn_2->eht_cap, + bcn_2->he_cap, is_band_2g); + eht_cap_ie_len = eht_cap_ie[1] + 2; + + /* Copy the EHT cap IE to the end of the frame */ + qdf_mem_copy(session->pSchBeaconFrameEnd + ie_buf_size, + eht_cap_ie, eht_cap_ie_len); + + qdf_mem_free(eht_cap_ie); + n_bytes = ie_buf_size + eht_cap_ie_len; + } + + if (tpe_ie_len) { + status = lim_fill_complete_tpe_ie( + session->ch_width, tpe_ie_len, + transmit_power_env, + num_transmit_power_env, + session->pSchBeaconFrameEnd + n_bytes); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("assemble tpe ie error"); + tpe_ie_len = 0; + } + n_bytes += tpe_ie_len; + } + + if (mlo_ie_len) { + status = lim_fill_complete_mlo_ie(session, mlo_ie_len, + session->pSchBeaconFrameEnd + n_bytes); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("assemble ml ie error"); + mlo_ie_len = 0; + } + n_bytes += mlo_ie_len; + } + + /* Fill the CSA/ECSA count offsets if the IEs are present */ + mac_ctx->sch.ecsa_count_offset = 0; + mac_ctx->sch.csa_count_offset = 0; + if (session->dfsIncludeChanSwIe) + sch_get_csa_ecsa_count_offset(session->pSchBeaconFrameEnd, + n_bytes, + &csa_count_offset, + &ecsa_count_offset); + + if (csa_count_offset) + mac_ctx->sch.csa_count_offset = + session->schBeaconOffsetBegin + tim_size + + csa_count_offset; + if (ecsa_count_offset) + mac_ctx->sch.ecsa_count_offset = + session->schBeaconOffsetBegin + tim_size + + ecsa_count_offset; + + if (wlan_vdev_mlme_is_mlo_ap(session->vdev)) + lim_upt_mlo_partner_info(mac_ctx, session, + session->pSchBeaconFrameEnd, n_bytes, + session->schBeaconOffsetBegin + + tim_size); + + extra_ie = session->pSchBeaconFrameEnd + n_bytes; + extra_ie_offset = n_bytes; + + /* + * Max size left to append additional IE.= (MAX beacon size - TIM IE - + * beacon fix size (bcn_1 + header) - beacon variable size (bcn_1). + */ + bcn_size_left = SIR_MAX_BEACON_SIZE - tim_size - + session->schBeaconOffsetBegin - + (uint16_t)n_bytes; + + /* TODO: Append additional IE here. */ + if (addn_ielen > 0) + sch_append_addn_ie(mac_ctx, session, + session->pSchBeaconFrameEnd + n_bytes, + bcn_size_left, &n_bytes, + addn_ie, addn_ielen); + + session->schBeaconOffsetEnd = (uint16_t) n_bytes; + extra_ie_len = n_bytes - extra_ie_offset; + /* Get the p2p Ie Offset */ + status = sch_get_p2p_ie_offset(extra_ie, extra_ie_len, &p2p_ie_offset); + if (QDF_STATUS_SUCCESS == status) + /* Update the P2P Ie Offset */ + mac_ctx->sch.p2p_ie_offset = + session->schBeaconOffsetBegin + tim_size + + extra_ie_offset + p2p_ie_offset; + else + mac_ctx->sch.p2p_ie_offset = 0; + + pe_debug("vdev %d: beacon begin offset %d fixed size %d csa_count_offset %d ecsa_count_offset %d max_bcn_size_left %d addn_ielen %d beacon end offset %d HT %d VHT %d HE %d EHT %d", + session->vdev_id, offset, session->schBeaconOffsetBegin, + mac_ctx->sch.csa_count_offset, mac_ctx->sch.ecsa_count_offset, + bcn_size_left, addn_ielen, session->schBeaconOffsetEnd, + bcn_2->HTCaps.present, bcn_2->VHTCaps.present, + bcn_2->he_cap.present, bcn_2->eht_cap.present); + if (mac_ctx->sch.ecsa_count_offset || mac_ctx->sch.csa_count_offset) { + wlan_reg_read_current_country(mac_ctx->psoc, reg_cc); + pe_debug("ECSA/CSA : country:%s chan:%d freq %d width:%d reg:%d off:%d count %d mode %d", + reg_cc, session->gLimChannelSwitch.primaryChannel, + session->gLimChannelSwitch.sw_target_freq, + session->gLimChannelSwitch.ch_width, + bcn_2->ext_chan_switch_ann.present ? + bcn_2->ext_chan_switch_ann.new_reg_class : 0, + session->gLimChannelSwitch.sec_ch_offset, + session->gLimChannelSwitch.switchCount, + session->gLimChannelSwitch.switchMode); + } + mac_ctx->sch.beacon_changed = 1; + status = QDF_STATUS_SUCCESS; + +free_and_exit: + qdf_mem_free(bcn_1); + qdf_mem_free(bcn_2); + qdf_mem_free(wsc_prb_res); + qdf_mem_free(addn_ie); + qdf_mem_free(transmit_power_env); + + return status; +} + +QDF_STATUS +lim_update_probe_rsp_template_ie_bitmap_beacon1(struct mac_context *mac, + tDot11fBeacon1 *beacon1, + struct pe_session *pe_session) +{ + uint32_t *DefProbeRspIeBitmap; + tDot11fProbeResponse *prb_rsp; + + if (!pe_session) { + pe_debug("PESession is null!"); + return QDF_STATUS_E_FAILURE; + } + DefProbeRspIeBitmap = &pe_session->DefProbeRspIeBitmap[0]; + prb_rsp = &pe_session->probeRespFrame; + prb_rsp->BeaconInterval = beacon1->BeaconInterval; + qdf_mem_copy((void *)&prb_rsp->Capabilities, + (void *)&beacon1->Capabilities, + sizeof(beacon1->Capabilities)); + + /* SSID */ + if (beacon1->SSID.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_SSID); + /* populating it, because probe response has to go with SSID even in hidden case */ + populate_dot11f_ssid(mac, &pe_session->ssId, &prb_rsp->SSID); + } + /* supported rates */ + if (beacon1->SuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_RATES); + qdf_mem_copy((void *)&prb_rsp->SuppRates, + (void *)&beacon1->SuppRates, + sizeof(beacon1->SuppRates)); + + } + /* DS Parameter set */ + if (beacon1->DSParams.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_DSPARMS); + qdf_mem_copy((void *)&prb_rsp->DSParams, + (void *)&beacon1->DSParams, + sizeof(beacon1->DSParams)); + + } + + return QDF_STATUS_SUCCESS; +} + +void lim_update_probe_rsp_template_ie_bitmap_beacon2(struct mac_context *mac, + tDot11fBeacon2 *beacon2, + uint32_t *DefProbeRspIeBitmap, + tDot11fProbeResponse *prb_rsp) +{ + uint8_t i; + uint16_t num_tpe = beacon2->num_transmit_power_env; + + if (beacon2->Country.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_COUNTRY); + qdf_mem_copy((void *)&prb_rsp->Country, + (void *)&beacon2->Country, + sizeof(beacon2->Country)); + + } + /* Power constraint */ + if (beacon2->PowerConstraints.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_PWRCNSTR); + qdf_mem_copy((void *)&prb_rsp->PowerConstraints, + (void *)&beacon2->PowerConstraints, + sizeof(beacon2->PowerConstraints)); + + } + /* Channel Switch Annoouncement WLAN_ELEMID_CHANSWITCHANN */ + if (beacon2->ChanSwitchAnn.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_CHANSWITCHANN); + qdf_mem_copy((void *)&prb_rsp->ChanSwitchAnn, + (void *)&beacon2->ChanSwitchAnn, + sizeof(beacon2->ChanSwitchAnn)); + + } + + /* EXT Channel Switch Announcement CHNL_EXTENDED_SWITCH_ANN_EID*/ + if (beacon2->ext_chan_switch_ann.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_EXTCHANSWITCHANN); + qdf_mem_copy((void *)&prb_rsp->ext_chan_switch_ann, + (void *)&beacon2->ext_chan_switch_ann, + sizeof(beacon2->ext_chan_switch_ann)); + } + + /* Supported operating class */ + if (beacon2->SuppOperatingClasses.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_SUPP_OP_CLASS); + qdf_mem_copy((void *)&prb_rsp->SuppOperatingClasses, + (void *)&beacon2->SuppOperatingClasses, + sizeof(beacon2->SuppOperatingClasses)); + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (beacon2->QComVendorIE.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + SIR_MAC_QCOM_VENDOR_EID); + qdf_mem_copy((void *)&prb_rsp->QComVendorIE, + (void *)&beacon2->QComVendorIE, + sizeof(beacon2->QComVendorIE)); + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + /* ERP information */ + if (beacon2->ERPInfo.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_ERP); + qdf_mem_copy((void *)&prb_rsp->ERPInfo, + (void *)&beacon2->ERPInfo, + sizeof(beacon2->ERPInfo)); + + } + /* Extended supported rates */ + if (beacon2->ExtSuppRates.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_XRATES); + qdf_mem_copy((void *)&prb_rsp->ExtSuppRates, + (void *)&beacon2->ExtSuppRates, + sizeof(beacon2->ExtSuppRates)); + + } + + /* WPA */ + if (beacon2->WPA.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + qdf_mem_copy((void *)&prb_rsp->WPA, (void *)&beacon2->WPA, + sizeof(beacon2->WPA)); + + } + + /* RSN */ + if (beacon2->RSNOpaque.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_RSN); + qdf_mem_copy((void *)&prb_rsp->RSNOpaque, + (void *)&beacon2->RSNOpaque, + sizeof(beacon2->RSNOpaque)); + } + + /* WAPI */ + if (beacon2->WAPI.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_WAPI); + qdf_mem_copy((void *)&prb_rsp->WAPI, + (void *)&beacon2->WAPI, + sizeof(beacon2->WAPI)); + } + + /* EDCA Parameter set */ + if (beacon2->EDCAParamSet.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_EDCAPARMS); + qdf_mem_copy((void *)&prb_rsp->EDCAParamSet, + (void *)&beacon2->EDCAParamSet, + sizeof(beacon2->EDCAParamSet)); + + } + /* Vendor specific - currently no vendor specific IEs added */ + /* Requested IEs - currently we are not processing this will be added later */ + /* HT capability IE */ + if (beacon2->HTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_HTCAP_ANA); + qdf_mem_copy((void *)&prb_rsp->HTCaps, (void *)&beacon2->HTCaps, + sizeof(beacon2->HTCaps)); + } + /* HT Info IE */ + if (beacon2->HTInfo.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, WLAN_ELEMID_HTINFO_ANA); + qdf_mem_copy((void *)&prb_rsp->HTInfo, (void *)&beacon2->HTInfo, + sizeof(beacon2->HTInfo)); + } + if (beacon2->VHTCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_VHTCAP); + qdf_mem_copy((void *)&prb_rsp->VHTCaps, + (void *)&beacon2->VHTCaps, + sizeof(beacon2->VHTCaps)); + } + if (beacon2->VHTOperation.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_VHTOP); + qdf_mem_copy((void *)&prb_rsp->VHTOperation, + (void *)&beacon2->VHTOperation, + sizeof(beacon2->VHTOperation)); + } + + for (i = 0; i < num_tpe; i++) { + if (beacon2->transmit_power_env[i].present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_VHT_TX_PWR_ENVLP); + qdf_mem_copy((void *)&prb_rsp->transmit_power_env[i], + (void *)&beacon2->transmit_power_env[i], + sizeof(beacon2->transmit_power_env[i])); + } + } + prb_rsp->num_transmit_power_env = num_tpe; + + if (beacon2->VHTExtBssLoad.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_EXT_BSS_LOAD); + qdf_mem_copy((void *)&prb_rsp->VHTExtBssLoad, + (void *)&beacon2->VHTExtBssLoad, + sizeof(beacon2->VHTExtBssLoad)); + } + /* WMM IE */ + if (beacon2->WMMParams.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + qdf_mem_copy((void *)&prb_rsp->WMMParams, + (void *)&beacon2->WMMParams, + sizeof(beacon2->WMMParams)); + } + /* WMM capability - most of the case won't be present */ + if (beacon2->WMMCaps.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, SIR_MAC_WPA_EID); + qdf_mem_copy((void *)&prb_rsp->WMMCaps, + (void *)&beacon2->WMMCaps, + sizeof(beacon2->WMMCaps)); + } + + /* QCN IE - only for ll sap */ + if (beacon2->qcn_ie.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_VENDOR); + qdf_mem_copy((void *)&prb_rsp->qcn_ie, + (void *)&beacon2->qcn_ie, + sizeof(beacon2->qcn_ie)); + } + + /* Extended Capability */ + if (beacon2->ExtCap.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, DOT11F_EID_EXTCAP); + qdf_mem_copy((void *)&prb_rsp->ExtCap, + (void *)&beacon2->ExtCap, + sizeof(beacon2->ExtCap)); + } + + if (beacon2->he_cap.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_HE_CAP); + qdf_mem_copy((void *)&prb_rsp->he_cap, + (void *)&beacon2->he_cap, + sizeof(beacon2->he_cap)); + } + if (beacon2->he_op.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_HE_OP); + qdf_mem_copy((void *)&prb_rsp->he_op, + (void *)&beacon2->he_op, + sizeof(beacon2->he_op)); + } + + if (beacon2->spatial_reuse.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_SPATIAL_REUSE); + qdf_mem_copy((void *)&prb_rsp->spatial_reuse, + (void *)&beacon2->spatial_reuse, + sizeof(beacon2->spatial_reuse)); + } + + if (beacon2->he_6ghz_band_cap.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_HE_6GHZ_BAND_CAP); + qdf_mem_copy((void *)&prb_rsp->he_6ghz_band_cap, + (void *)&beacon2->he_6ghz_band_cap, + sizeof(beacon2->he_6ghz_band_cap)); + } + + if (beacon2->eht_cap.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_EHT_CAP); + qdf_mem_copy((void *)&prb_rsp->eht_cap, + (void *)&beacon2->eht_cap, + sizeof(beacon2->eht_cap)); + } + + if (beacon2->eht_op.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_EHT_OP); + qdf_mem_copy((void *)&prb_rsp->eht_op, + (void *)&beacon2->eht_op, + sizeof(beacon2->eht_op)); + } + + if (beacon2->mlo_ie.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_MLO_IE); + qdf_mem_copy((void *)&prb_rsp->mlo_ie, + (void *)&beacon2->mlo_ie, + sizeof(beacon2->mlo_ie)); + } + + if (beacon2->reduced_neighbor_report.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + DOT11F_EID_REDUCED_NEIGHBOR_REPORT); + qdf_mem_copy((void *)&prb_rsp->reduced_neighbor_report, + (void *)&beacon2->reduced_neighbor_report, + sizeof(beacon2->reduced_neighbor_report)); + } + + if (beacon2->TPCReport.present) { + set_probe_rsp_ie_bitmap(DefProbeRspIeBitmap, + WLAN_ELEMID_TPCREP); + qdf_mem_copy((void *)&prb_rsp->TPCReport, + (void *)&beacon2->TPCReport, + sizeof(beacon2->TPCReport)); + } + +} + +void set_probe_rsp_ie_bitmap(uint32_t *IeBitmap, uint32_t pos) +{ + uint32_t index, temp; + + index = pos >> 5; + if (index >= 8) { + return; + } + temp = IeBitmap[index]; + + temp |= 1 << (pos & 0x1F); + + IeBitmap[index] = temp; +} + +/** + * write_beacon_to_memory() - send the beacon to the wma + * @mac: pointer to mac structure + * @size: Size of the beacon to write to memory + * @length: Length field of the beacon to write to memory + * @pe_session: pe session + * @reason: beacon update reason + * + * return: success: QDF_STATUS_SUCCESS failure: QDF_STATUS_E_FAILURE + */ +static QDF_STATUS write_beacon_to_memory(struct mac_context *mac, uint16_t size, + uint16_t length, + struct pe_session *pe_session, + enum sir_bcn_update_reason reason) +{ + uint16_t i; + tpAniBeaconStruct pBeacon; + QDF_STATUS status; + + /* copy end of beacon only if length > 0 */ + if (length > 0) { + if (size + pe_session->schBeaconOffsetEnd > + SIR_MAX_BEACON_SIZE) { + pe_err("beacon tmp fail size %d BeaconOffsetEnd %d", + size, pe_session->schBeaconOffsetEnd); + return QDF_STATUS_E_FAILURE; + } + for (i = 0; i < pe_session->schBeaconOffsetEnd; i++) + pe_session->pSchBeaconFrameBegin[size++] = + pe_session->pSchBeaconFrameEnd[i]; + } + /* Update the beacon length */ + pBeacon = (tpAniBeaconStruct) pe_session->pSchBeaconFrameBegin; + /* Do not include the beaconLength indicator itself */ + if (length == 0) { + pBeacon->beaconLength = 0; + /* Dont copy entire beacon, Copy length field alone */ + size = 4; + } else + pBeacon->beaconLength = (uint32_t) size - sizeof(uint32_t); + + if (!mac->sch.beacon_changed) + return QDF_STATUS_E_FAILURE; + + status = sch_send_beacon_req(mac, pe_session->pSchBeaconFrameBegin, + size, pe_session, reason); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("sch_send_beacon_req() returned an error %d, size %d", + status, size); + mac->sch.beacon_changed = 0; + + return status; +} + +/** + * sch_generate_tim + * + * FUNCTION: + * Generate TIM + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param mac pointer to global mac structure + * @param **pPtr pointer to the buffer, where the TIM bit is to be written. + * @param *timLength pointer to limLength, which needs to be returned. + * @return None + */ +void sch_generate_tim(struct mac_context *mac, uint8_t **pPtr, uint16_t *timLength, + uint8_t dtimPeriod) +{ + uint8_t *ptr = *pPtr; + uint32_t val = 0; + uint32_t minAid = 1; /* Always start with AID 1 as minimum */ + uint32_t maxAid = HAL_NUM_STA; + /* Generate partial virtual bitmap */ + uint8_t N1 = minAid / 8; + uint8_t N2 = maxAid / 8; + + if (N1 & 1) + N1--; + + *timLength = N2 - N1 + 4; + val = dtimPeriod; + + /* + * Write 0xFF to firmware's field to detect firmware's mal-function + * early. DTIM count and bitmap control usually cannot be 0xFF, so it + * is easy to know that firmware never updated DTIM count/bitmap control + * field after host driver downloaded beacon template if end-user complaints + * that DTIM count and bitmapControl is 0xFF. + */ + *ptr++ = WLAN_ELEMID_TIM; + *ptr++ = (uint8_t) (*timLength); + /* location for dtimCount. will be filled in by FW. */ + *ptr++ = 0xFF; + *ptr++ = (uint8_t) val; + /* location for bitmap control. will be filled in by FW. */ + *ptr++ = 0xFF; + ptr += (N2 - N1 + 1); + + *pPtr = ptr; +} + +QDF_STATUS sch_process_pre_beacon_ind(struct mac_context *mac, + struct scheduler_msg *limMsg, + enum sir_bcn_update_reason reason) +{ + struct beacon_gen_params *pMsg = limMsg->bodyptr; + uint32_t beaconSize; + struct pe_session *pe_session; + uint8_t sessionId; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + pe_session = pe_find_session_by_bssid(mac, pMsg->bssid, &sessionId); + if (!pe_session) { + pe_err("session lookup fails"); + goto end; + } + + beaconSize = pe_session->schBeaconOffsetBegin; + + /* If SME is not in normal mode, no need to generate beacon */ + if (pe_session->limSmeState != eLIM_SME_NORMAL_STATE) { + pe_debug("PreBeaconInd received in invalid state: %d", + pe_session->limSmeState); + goto end; + } + + switch (GET_LIM_SYSTEM_ROLE(pe_session)) { + case eLIM_AP_ROLE: { + uint8_t *ptr = + &pe_session->pSchBeaconFrameBegin[pe_session-> + schBeaconOffsetBegin]; + uint16_t timLength = 0; + + if (pe_session->statypeForBss == STA_ENTRY_SELF) { + sch_generate_tim(mac, &ptr, &timLength, + pe_session->dtimPeriod); + beaconSize += 2 + timLength; + status = + write_beacon_to_memory(mac, (uint16_t) beaconSize, + (uint16_t) beaconSize, + pe_session, reason); + } else + pe_err("can not send beacon for PEER session entry"); + } + break; + + default: + pe_err("Error-PE has Receive PreBeconGenIndication when System is in %d role", + GET_LIM_SYSTEM_ROLE(pe_session)); + } + +end: + qdf_mem_free(pMsg); + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c new file mode 100644 index 0000000000..4822d6a0b4 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_beacon_process.c @@ -0,0 +1,1628 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file sch_beacon_process.cc contains beacon processing related + * functions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "cds_api.h" +#include "wni_cfg.h" + +#include "cfg_ucfg_api.h" +#include "lim_api.h" +#include "utils_api.h" +#include "sch_api.h" + +#include "lim_utils.h" +#include "lim_send_messages.h" +#include "rrm_api.h" +#include "lim_mlo.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#include "wma.h" + +#include "wlan_lmac_if_def.h" +#include "wlan_reg_services_api.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlme_main.h" +#include + +static void +ap_beacon_process_5_ghz(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, struct pe_session *session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + + if (!session->htCapability) + return; + + if (bcn_struct->chan_freq != session->curr_op_freq) + return; + + /* 11a (non HT) AP overlaps or */ + /* HT AP with HT op mode as mixed overlaps. */ + /* HT AP with HT op mode as overlap legacy overlaps. */ + if (!bcn_struct->HTInfo.present + || (eSIR_HT_OP_MODE_MIXED == bcn_struct->HTInfo.opMode) + || (eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode)) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11aParams)); + + if (session->gLimOverlap11aParams.numSta + && !session->gLimOverlap11aParams.protectionEnabled) { + lim_update_11a_protection(mac_ctx, true, true, + bcn_prm, session); + } + return; + } + /* HT AP with HT20 op mode overlaps. */ + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT != bcn_struct->HTInfo.opMode) + return; + + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlapHt20Params)); + + if (session->gLimOverlapHt20Params.numSta + && !session->gLimOverlapHt20Params.protectionEnabled) + lim_enable_ht20_protection(mac_ctx, true, true, + bcn_prm, session); +} + +static void +ap_beacon_process_24_ghz(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, struct pe_session *session, + uint32_t phy_mode) +{ + tpSirMacMgmtHdr mac_hdr = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + bool tmp_exp = false; + /* We are 11G AP. */ + if ((phy_mode == WNI_CFG_PHY_MODE_11G) && + (false == session->htCapability)) { + if (bcn_struct->chan_freq != session->curr_op_freq) + return; + + tmp_exp = (!bcn_struct->erpPresent && + !bcn_struct->HTInfo.present) || + /* if erp not present then 11B AP overlapping */ + (!mac_ctx->mlme_cfg->sta.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection || + bcn_struct->erpIEInfo.nonErpPresent)); + if (!tmp_exp) + return; +#ifdef FEATURE_WLAN_ESE + if (wlan_cm_get_ese_assoc(mac_ctx->pdev, session->vdev_id)) + pe_info("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d", + bcn_struct->erpPresent, + bcn_struct->erpIEInfo.useProtection, + bcn_struct->erpIEInfo.nonErpPresent); +#endif + lim_enable_overlap11g_protection(mac_ctx, bcn_prm, + mac_hdr, session); + return; + } + /* handling the case when HT AP has overlapping legacy BSS. */ + if (!session->htCapability) + return; + + if (bcn_struct->chan_freq != session->curr_op_freq) + return; + + tmp_exp = (!bcn_struct->erpPresent && !bcn_struct->HTInfo.present) || + /* if erp not present then 11B AP overlapping */ + (!mac_ctx->mlme_cfg->sta.ignore_peer_erp_info && + bcn_struct->erpPresent && + (bcn_struct->erpIEInfo.useProtection || + bcn_struct->erpIEInfo.nonErpPresent)); + if (tmp_exp) { +#ifdef FEATURE_WLAN_ESE + if (wlan_cm_get_ese_assoc(mac_ctx->pdev, session->vdev_id)) { + pe_info("[INFOLOG]ESE 11g erpPresent=%d useProtection=%d nonErpPresent=%d", + bcn_struct->erpPresent, + bcn_struct->erpIEInfo.useProtection, + bcn_struct->erpIEInfo.nonErpPresent); + } +#endif + lim_enable_overlap11g_protection(mac_ctx, bcn_prm, + mac_hdr, session); + } + /* 11g device overlaps */ + tmp_exp = bcn_struct->erpPresent + && !(bcn_struct->erpIEInfo.useProtection + || bcn_struct->erpIEInfo.nonErpPresent) + && !(bcn_struct->HTInfo.present); + if (tmp_exp) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11gParams)); + + if (session->gLimOverlap11gParams.numSta + && !session->gLimOverlap11gParams.protectionEnabled) + lim_enable_ht_protection_from11g(mac_ctx, true, true, + bcn_prm, session); + } + /* ht device overlaps. + * here we will check for HT related devices only which might need + * protection. check for 11b and 11g is already done in the previous + * blocks. so we will not check for HT operating mode as MIXED. + */ + if (!bcn_struct->HTInfo.present) + return; + + /* + * if we are not already in mixed mode or legacy mode as HT operating + * mode and received beacon has HT operating mode as legacy then we need + * to enable protection from 11g station. we don't need protection from + * 11b because if that's needed then our operating mode would have + * already been set to legacy in the previous blocks. + */ + if ((eSIR_HT_OP_MODE_OVERLAP_LEGACY == bcn_struct->HTInfo.opMode) && + !mac_ctx->mlme_cfg->sap_protection_cfg.ignore_peer_ht_opmode) { + if (eSIR_HT_OP_MODE_OVERLAP_LEGACY == mac_ctx->lim.gHTOperMode + || eSIR_HT_OP_MODE_MIXED == mac_ctx->lim.gHTOperMode) + return; + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlap11gParams)); + if (session->gLimOverlap11gParams.numSta + && !session->gLimOverlap11gParams.protectionEnabled) + lim_enable_ht_protection_from11g(mac_ctx, true, true, + bcn_prm, session); + return; + } + + if (eSIR_HT_OP_MODE_NO_LEGACY_20MHZ_HT == bcn_struct->HTInfo.opMode) { + lim_update_overlap_sta_param(mac_ctx, mac_hdr->bssId, + &(session->gLimOverlapHt20Params)); + if (session->gLimOverlapHt20Params.numSta + && !session->gLimOverlapHt20Params.protectionEnabled) + lim_enable_ht20_protection(mac_ctx, true, true, + bcn_prm, session); + } +} + +/** + * ap_beacon_process() - processes incoming beacons + * + * @mac_ctx: mac global context + * @rx_pkt_info: incoming beacon packet + * @bcn_struct: beacon struct + * @bcn_prm: beacon params + * @session: pe session entry + * + * Return: void + */ +static void +ap_beacon_process(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + tpSchBeaconStruct bcn_struct, + tpUpdateBeaconParams bcn_prm, struct pe_session *session) +{ + uint32_t phy_mode; + enum reg_wifi_band rf_band = REG_BAND_UNKNOWN; + /* Get RF band from session */ + rf_band = session->limRFBand; + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + + if (REG_BAND_5G == rf_band) + ap_beacon_process_5_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); + else if (REG_BAND_2G == rf_band) + ap_beacon_process_24_ghz(mac_ctx, rx_pkt_info, bcn_struct, + bcn_prm, session, phy_mode); +} + +/* -------------------------------------------------------------------- */ + +/* + * sch_bcn_process_sta() - Process the received beacon frame for sta + * @mac_ctx: mac_ctx + * @bcn: beacon struct + * @rx_pkt_info: received packet info + * @session: pe session pointer + * @beaconParams: update beacon params + * @sendProbeReq: out flag to indicate if probe rsp is to be sent + * @pMh: mac header + * + * Process the received beacon frame for sta + * + * Return: success of failure of operation + */ +static bool +sch_bcn_process_sta(struct mac_context *mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + struct pe_session *session, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + uint32_t bi; + tpDphHashNode sta = NULL; + QDF_STATUS status; + + /* + * This handles two cases: + * -- Infra STA receiving beacons from AP + */ + + /** + * This is the Beacon received from the AP we're currently associated + * with. Check if there are any changes in AP's capabilities + */ + if (bcn->chan_freq != session->curr_op_freq) { + pe_err("Channel Change freq from %d --> %d - Ignoring beacon!", + session->curr_op_freq, bcn->chan_freq); + return false; + } + + /* + * Ignore bcn as channel switch IE present and csa offload is enabled, + * as in CSA offload enabled case FW will send Event to switch channel + */ + if (bcn->channelSwitchPresent && wma_is_csa_offload_enabled()) { + pe_err_rl("Ignore bcn as channel switch IE present and csa offload is enabled"); + return false; + } + + lim_detect_change_in_ap_capabilities(mac_ctx, bcn, session, true); + beaconParams->bss_idx = session->vdev_id; + qdf_mem_copy((uint8_t *) &session->lastBeaconTimeStamp, + (uint8_t *) bcn->timeStamp, sizeof(uint64_t)); + session->currentBssBeaconCnt++; + if (session->bcon_dtim_period != bcn->tim.dtimPeriod) { + session->bcon_dtim_period = bcn->tim.dtimPeriod; + lim_send_set_dtim_period(mac_ctx, bcn->tim.dtimPeriod, + session); + } + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, + session->peSessionId, bcn->timeStamp[0])); + MTRACE(mac_trace(mac_ctx, TRACE_CODE_RX_MGMT_TSF, + session->peSessionId, bcn->timeStamp[1])); + + /* Read beacon interval session Entry */ + bi = session->beaconParams.beaconInterval; + if (bi != bcn->beaconInterval) { + pe_debug("Beacon interval changed from %d to %d", + bcn->beaconInterval, bi); + + bi = bcn->beaconInterval; + session->beaconParams.beaconInterval = (uint16_t) bi; + beaconParams->paramChangeBitmap |= PARAM_BCN_INTERVAL_CHANGED; + beaconParams->beaconInterval = (uint16_t) bi; + } + + if (bcn->cfPresent) { + if (!cfg_in_range(CFG_CFP_PERIOD, bcn->cfParamSet.cfpPeriod)) { + pe_err("Error in setting CFG item CFP Period"); + return false; + } + mac_ctx->mlme_cfg->rates.cfp_period = bcn->cfParamSet.cfpPeriod; + } + + /* No need to send DTIM Period and Count to HAL/SMAC */ + /* SMAC already parses TIM bit. */ + if (bcn->timPresent) { + if (cfg_in_range(CFG_DTIM_PERIOD, bcn->tim.dtimPeriod)) + mac_ctx->mlme_cfg->sap_cfg.dtim_interval = + bcn->tim.dtimPeriod; + } + + if (mac_ctx->lim.gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) + lim_decide_sta_protection(mac_ctx, bcn, beaconParams, session); + + if (bcn->erpPresent) { + if (bcn->erpIEInfo.barkerPreambleMode) + lim_enable_short_preamble(mac_ctx, false, + beaconParams, session); + else + lim_enable_short_preamble(mac_ctx, true, + beaconParams, session); + } + lim_update_short_slot(mac_ctx, bcn, beaconParams, session); + + sta = dph_get_hash_entry(mac_ctx, DPH_STA_HASH_INDEX_PEER, + &session->dph.dphHashTable); + if ((bcn->wmeEdcaPresent && session->limWmeEnabled) || + (bcn->edcaPresent && session->limQosEnabled)) { + if (bcn->edcaParams.qosInfo.count != + session->gLimEdcaParamSetCount) { + qdf_mem_copy(&sta->qos.peer_edca_params, + &bcn->edcaParams, + sizeof(bcn->edcaParams)); + status = sch_beacon_edca_process(mac_ctx, + &bcn->edcaParams, + session); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("EDCA parameter processing error"); + } else if (sta) { + /* If needed, downgrade the EDCA parameters */ + lim_set_active_edca_params(mac_ctx, + session->gLimEdcaParams, session); + lim_send_edca_params(mac_ctx, + session->gLimEdcaParamsActive, + session->vdev_id, false); + sch_qos_concurrency_update(); + } else { + pe_err("Self Entry missing in Hash Table"); + } + } + return true; + } + + if ((bcn->qosCapabilityPresent && session->limQosEnabled) + && (bcn->qosCapability.qosInfo.count != + session->gLimEdcaParamSetCount)) + *sendProbeReq = true; + + return true; +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void +sch_bcn_update_he_ies(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + struct pe_session *session, tpSchBeaconStruct bcn, + tpSirMacMgmtHdr mac_hdr) +{ + uint8_t session_bss_col_disabled_flag; + bool anything_changed = false; + + if (session->is_session_obss_color_collision_det_enabled) + return; + + if (session->he_op.present && bcn->he_op.present) { + if (bcn->vendor_he_bss_color_change.present && + (session->he_op.bss_color != + bcn->vendor_he_bss_color_change.new_color)) { + pe_debug("bss color changed from [%d] to [%d]", + session->he_op.bss_color, + bcn->vendor_he_bss_color_change.new_color); + session->he_op.bss_color = + bcn->vendor_he_bss_color_change.new_color; + anything_changed = true; + } + session_bss_col_disabled_flag = session->he_op.bss_col_disabled; + if (session_bss_col_disabled_flag != + bcn->he_op.bss_col_disabled) { + pe_debug("color disable flag changed from [%d] to [%d]", + session->he_op.bss_col_disabled, + bcn->he_op.bss_col_disabled); + session->he_op.bss_col_disabled = + bcn->he_op.bss_col_disabled; + anything_changed = true; + } + } + if (anything_changed) + lim_send_he_ie_update(mac_ctx, session); +} +#else +static void +sch_bcn_update_he_ies(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + struct pe_session *session, tpSchBeaconStruct bcn, + tpSirMacMgmtHdr mac_hdr) +{ + return; +} +#endif + +static void +sch_bcn_update_opmode_change(struct mac_context *mac_ctx, tpDphHashNode sta_ds, + struct pe_session *session, tpSchBeaconStruct bcn, + tpSirMacMgmtHdr mac_hdr) +{ + enum phy_ch_width ch_bw; + enum phy_ch_width ch_width = CH_WIDTH_20MHZ; + tDot11fIEVHTCaps *vht_caps = NULL; + tDot11fIEVHTOperation *vht_op = NULL; + uint8_t bcn_vht_chwidth = 0; + bool is_40 = false; + + /* + * Ignore opmode change during channel change The opmode will be updated + * with the beacons on new channel once the AP move to new channel. + */ + if (session->ch_switch_in_progress) { + pe_debug("Ignore opmode change as channel switch is in progress"); + return; + } + if (bcn->eht_op.eht_op_information_present) { + pe_debug("Ignore opmode change as there is EHT operation information"); + return; + } + + if (bcn->VHTCaps.present) { + vht_caps = &bcn->VHTCaps; + vht_op = &bcn->VHTOperation; + } else if (bcn->vendor_vht_ie.VHTCaps.present) { + vht_caps = &bcn->vendor_vht_ie.VHTCaps; + vht_op = &bcn->vendor_vht_ie.VHTOperation; + } + if (!session->vhtCapability || + !(bcn->OperatingMode.present || + (vht_op && vht_op->present && vht_caps))) + return; + + is_40 = bcn->HTInfo.present ? + bcn->HTInfo.recommendedTxWidthSet : false; + + if (bcn->OperatingMode.present) { + lim_update_nss(mac_ctx, sta_ds, bcn->OperatingMode.rxNSS, + session); + ch_width = bcn->OperatingMode.chanWidth; + pe_debug("OMN IE present in bcn/probe rsp, omn_ie_ch_width: %d", + ch_width); + lim_update_omn_ie_ch_width(session->vdev, ch_width); + + } else { + bcn_vht_chwidth = lim_get_vht_ch_width(vht_caps, vht_op, + &bcn->HTInfo); + ch_width = + lim_convert_vht_chwidth_to_phy_chwidth(bcn_vht_chwidth, + is_40); + } + + lim_update_channel_width(mac_ctx, sta_ds, session, ch_width, &ch_bw); +} + +#ifdef WLAN_FEATURE_SR +/** + * lim_detect_change_in_srp() - Detect change in SRP IE + * of the beacon + * + * @mac_ctx: global mac context + * @sta: pointer to sta node + * @session: pointer to LIM session + * @bcn: beacon from associated AP + * + * Detect change in SRP IE of the beacon and update the params + * accordingly. + * + * Return: None + */ +static void lim_detect_change_in_srp(struct mac_context *mac_ctx, + tpDphHashNode sta, + struct pe_session *session, + tpSchBeaconStruct bcn) +{ + tDot11fIEspatial_reuse sr_ie; + int32_t ret = 0; + + sr_ie = sta->parsed_ies.srp_ie; + if (sr_ie.present || bcn->srp_ie.present) { + ret = qdf_mem_cmp(&sr_ie, &bcn->srp_ie, + sizeof(tDot11fIEspatial_reuse)); + + if (ret) { + /* + * If SRP IE has changes, update the new params. + */ + sta->parsed_ies.srp_ie = bcn->srp_ie; + lim_update_vdev_sr_elements(session, sta); + + lim_handle_sr_cap(session->vdev, + SR_REASON_CODE_BCN_IE_CHANGE); + } + } +} +#else +static void lim_detect_change_in_srp(struct mac_context *mac_ctx, + tpDphHashNode sta, + struct pe_session *session, + tpSchBeaconStruct bcn) +{ +} +#endif + +static void +sch_bcn_process_sta_opmode(struct mac_context *mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + struct pe_session *session, + tUpdateBeaconParams *beaconParams, + uint8_t *sendProbeReq, tpSirMacMgmtHdr pMh) +{ + tpDphHashNode sta = NULL; + uint16_t aid; + + /* check for VHT capability */ + sta = dph_lookup_hash_entry(mac_ctx, pMh->sa, &aid, + &session->dph.dphHashTable); + if (!sta) + return; + sch_bcn_update_opmode_change(mac_ctx, sta, session, bcn, pMh); + sch_bcn_update_he_ies(mac_ctx, sta, session, bcn, pMh); + lim_detect_change_in_srp(mac_ctx, sta, session, bcn); + return; +} + +/** + * get_local_power_constraint_beacon() - extracts local constraint + * from beacon + * @bcn: beacon structure + * @local_constraint: local constraint pointer + * @is_power_constraint_abs: is power constraint absolute + * + * Return: None + */ +#ifdef FEATURE_WLAN_ESE +static void get_local_power_constraint_beacon( + tpSchBeaconStruct bcn, + int8_t *local_constraint, + bool *is_power_constraint_abs) +{ + if (bcn->eseTxPwr.present) { + *local_constraint = bcn->eseTxPwr.power_limit; + *is_power_constraint_abs = true; + } +} +#else +static void get_local_power_constraint_beacon( + tpSchBeaconStruct bcn, + int8_t *local_constraint, + bool *is_power_constraint_abs) +{ + +} +#endif + +static void __sch_beacon_process_for_session(struct mac_context *mac_ctx, + tpSchBeaconStruct bcn, + uint8_t *rx_pkt_info, + struct pe_session *session) +{ + tUpdateBeaconParams beaconParams; + uint8_t sendProbeReq = false; + tpSirMacMgmtHdr pMh = WMA_GET_RX_MAC_HEADER(rx_pkt_info); + int8_t local_constraint = 0; + uint32_t chan_freq = 0; + struct vdev_mlme_obj *mlme_obj; + struct wlan_lmac_if_reg_tx_ops *tx_ops; + bool ap_constraint_change = false, tpe_change = false; + bool allow_tpc = false; + int8_t regMax = 0, maxTxPower = 0; + QDF_STATUS status; + bool skip_tpe = false, is_sap_go_switched_ch; + enum reg_6g_ap_type pwr_type_6g; + uint8_t bpcc; + bool cu_flag = true; + bool is_power_constraint_abs = false; + + if (mlo_is_mld_sta(session->vdev)) { + cu_flag = false; + status = lim_get_bpcc_from_mlo_ie(bcn, &bpcc); + if (QDF_IS_STATUS_SUCCESS(status)) + cu_flag = lim_check_cu_happens(session->vdev, bpcc); + lim_process_ml_reconfig(mac_ctx, session, rx_pkt_info); + } + + if (!cu_flag) + return; + + qdf_mem_zero(&beaconParams, sizeof(tUpdateBeaconParams)); + beaconParams.paramChangeBitmap = 0; + + if (LIM_IS_STA_ROLE(session)) { + is_sap_go_switched_ch = + wlan_vdev_mlme_is_sap_go_move_before_sta(session->vdev); + if (is_sap_go_switched_ch) + policy_mgr_sta_sap_dfs_enforce_scc(mac_ctx->psoc, + session->vdev_id); + if (false == sch_bcn_process_sta(mac_ctx, bcn, rx_pkt_info, + session, &beaconParams, + &sendProbeReq, pMh)) + return; + } + + /* + * For vht session, if opermode ie or vht oper IE is present + * bandwidth change will be taken care using these vht IEs. + */ + if (!(session->vhtCapability && (bcn->OperatingMode.present || + bcn->VHTOperation.present)) && session->htCapability && + bcn->HTInfo.present) + lim_update_sta_run_time_ht_switch_chnl_params(mac_ctx, + &bcn->HTInfo, session); + + if (LIM_IS_STA_ROLE(session)) + sch_bcn_process_sta_opmode(mac_ctx, bcn, rx_pkt_info, session, + &beaconParams, &sendProbeReq, pMh); + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(session->vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return; + } + + if (!wlan_reg_is_6ghz_chan_freq(bcn->chan_freq)) { + skip_tpe = wlan_mlme_skip_tpe(mac_ctx->psoc); + } else { + if (!bcn->countryInfoParam.countryString[0]) { + pe_err("Channel is 6G but country IE not present"); + return; + } + if (bcn->he_op.oper_info_6g_present) { + session->ap_defined_power_type_6g = + bcn->he_op.oper_info_6g.info.reg_info; + if (session->ap_defined_power_type_6g < REG_INDOOR_AP || + session->ap_defined_power_type_6g > + REG_MAX_SUPP_AP_TYPE) { + session->ap_defined_power_type_6g = + REG_CURRENT_MAX_AP_TYPE; + pe_debug("AP power type is invalid, defaulting to MAX_AP_TYPE"); + } + } else { + pe_debug("AP power type is null, defaulting to MAX_AP_TYPE"); + session->ap_defined_power_type_6g = + REG_CURRENT_MAX_AP_TYPE; + } + + status = wlan_reg_get_best_6g_power_type( + mac_ctx->psoc, mac_ctx->pdev, &pwr_type_6g, + session->ap_defined_power_type_6g, + bcn->chan_freq); + if (QDF_IS_STATUS_ERROR(status)) + return; + + session->best_6g_power_type = pwr_type_6g; + mlme_set_best_6g_power_type(session->vdev, pwr_type_6g); + } + + /* + * STA LPI + SAP VLP is supported. For this STA should operate in VLP + * power level of the SAP. + * If STA is operating in VLP power of SAP, do not update STA power. + */ + if (wlan_reg_is_ext_tpc_supported(mac_ctx->psoc) && + !session->sta_follows_sap_power) { + tx_ops = wlan_reg_get_tx_ops(mac_ctx->psoc); + + lim_parse_tpe_ie(mac_ctx, session, bcn->transmit_power_env, + bcn->num_transmit_power_env, &bcn->he_op, + &tpe_change); + + if (mac_ctx->mlme_cfg->sta.allow_tpc_from_ap) { + get_local_power_constraint_beacon( + bcn, &local_constraint, + &is_power_constraint_abs); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + bcn->powerConstraintPresent) { + local_constraint = + bcn->localPowerConstraint.localPowerConstraints; + is_power_constraint_abs = false; + } + allow_tpc = true; + } + + if (allow_tpc && local_constraint != + mlme_obj->reg_tpc_obj.ap_constraint_power) { + mlme_obj->reg_tpc_obj.ap_constraint_power = + local_constraint; + mlme_obj->reg_tpc_obj.is_power_constraint_abs = + is_power_constraint_abs; + ap_constraint_change = true; + } + + if (ap_constraint_change || (tpe_change && !skip_tpe)) { + lim_calculate_tpc(mac_ctx, session); + + if (tx_ops->set_tpc_power) + tx_ops->set_tpc_power(mac_ctx->psoc, + session->vdev_id, + &mlme_obj->reg_tpc_obj); + } + } else if (!session->sta_follows_sap_power) { + /* Obtain the Max Tx power for the current regulatory */ + regMax = wlan_reg_get_channel_reg_power_for_freq( + mac_ctx->pdev, session->curr_op_freq); + local_constraint = regMax; + + if (mac_ctx->mlme_cfg->sta.allow_tpc_from_ap) { + get_local_power_constraint_beacon( + bcn, &local_constraint, + &is_power_constraint_abs); + + if (mac_ctx->rrm.rrmPEContext.rrmEnable && + bcn->powerConstraintPresent) { + local_constraint = regMax; + local_constraint -= + bcn->localPowerConstraint.localPowerConstraints; + is_power_constraint_abs = false; + + } + } + mlme_obj->reg_tpc_obj.is_power_constraint_abs = + is_power_constraint_abs; + mlme_obj->reg_tpc_obj.reg_max[0] = regMax; + mlme_obj->reg_tpc_obj.ap_constraint_power = local_constraint; + mlme_obj->reg_tpc_obj.frequency[0] = session->curr_op_freq; + + maxTxPower = lim_get_max_tx_power(mac_ctx, mlme_obj); + + /* If maxTxPower is increased or decreased */ + if (maxTxPower != session->maxTxPower) { + pe_debug("New maxTx power %d, old pwr %d", + maxTxPower, session->maxTxPower); + pe_debug("regMax %d, local %d", regMax, + local_constraint); + status = lim_send_set_max_tx_power_req(mac_ctx, + maxTxPower, + session); + if (status == QDF_STATUS_SUCCESS) + session->maxTxPower = maxTxPower; + } + } + /* Indicate to LIM that Beacon is received */ + if (bcn->HTInfo.present) { + chan_freq = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, + bcn->HTInfo.primaryChannel); + lim_received_hb_handler(mac_ctx, chan_freq, session); + } else + lim_received_hb_handler(mac_ctx, bcn->chan_freq, session); + + /* + * I don't know if any additional IE is required here. Currently, not + * include addIE. + */ + if (sendProbeReq) + lim_send_probe_req_mgmt_frame(mac_ctx, &session->ssId, + session->bssId, session->curr_op_freq, + session->self_mac_addr, session->dot11mode, NULL, NULL); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && beaconParams.paramChangeBitmap) { + pe_debug("Beacon for session[%d] got changed param change bitmap: 0x%x", + session->peSessionId, beaconParams.paramChangeBitmap); + lim_send_beacon_params(mac_ctx, &beaconParams, session); + } + + if ((session->opmode == QDF_P2P_CLIENT_MODE) && + session->send_p2p_conf_frame) { + lim_p2p_oper_chan_change_confirm_action_frame(mac_ctx, + session->bssId, + session); + session->send_p2p_conf_frame = false; + } + + lim_process_beacon_eht(mac_ctx, session, bcn); + lim_process_bcn_prb_rsp_t2lm(mac_ctx, session, bcn); +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void ap_update_bss_color_info(struct mac_context *mac_ctx, + struct pe_session *session, + uint8_t bss_color) +{ + if (!session) + return; + + if (bss_color < 1 || bss_color > 63) { + pe_warn("Invalid BSS color"); + return; + } + + session->bss_color_info[bss_color - 1].seen_count++; + session->bss_color_info[bss_color - 1].timestamp = + qdf_get_system_timestamp(); +} + +static uint8_t ap_get_new_bss_color(struct mac_context *mac_ctx, struct pe_session *session) +{ + int i; + uint8_t new_bss_color; + struct bss_color_info color_info; + qdf_time_t cur_timestamp; + + if (!session) + return 0; + + color_info = session->bss_color_info[0]; + new_bss_color = 0; + cur_timestamp = qdf_get_system_timestamp(); + for (i = 1; i < MAX_BSS_COLOR_VALUE; i++) { + if (session->bss_color_info[i].seen_count == 0) { + new_bss_color = i + 1; + return new_bss_color; + } + + if (color_info.seen_count > + session->bss_color_info[i].seen_count && + (cur_timestamp - session->bss_color_info[i]. + timestamp) > TIME_BEACON_NOT_UPDATED) { + color_info = session->bss_color_info[i]; + new_bss_color = i + 1; + } + } + pe_debug("new bss color: %d", new_bss_color); + return new_bss_color; +} + +static void sch_check_bss_color_ie(struct mac_context *mac_ctx, + struct pe_session *ap_session, + tSchBeaconStruct *bcn, + tUpdateBeaconParams *bcn_prm) +{ + /* check bss color in the beacon */ + if (ap_session->he_op.present && !ap_session->he_op.bss_color) { + if (bcn->he_op.present && + (bcn->he_op.bss_color == + ap_session->he_op.bss_color)) { + ap_session->he_op.bss_col_disabled = 1; + bcn_prm->paramChangeBitmap |= + PARAM_BSS_COLOR_CHANGED; + ap_session->he_bss_color_change.countdown = + BSS_COLOR_SWITCH_COUNTDOWN; + ap_session->he_bss_color_change.new_color = + ap_get_new_bss_color(mac_ctx, + ap_session); + ap_session->he_op.bss_color = ap_session-> + he_bss_color_change.new_color; + bcn_prm->bss_color = ap_session->he_op.bss_color; + bcn_prm->bss_color_disabled = + ap_session->he_op.bss_col_disabled; + ap_session->bss_color_changing = 1; + } else { + /* update info for the bss color */ + if (bcn->he_op.present) + ap_update_bss_color_info(mac_ctx, + ap_session, + bcn->he_op.bss_color); + } + } +} + +#else +static void sch_check_bss_color_ie(struct mac_context *mac_ctx, + struct pe_session *ap_session, + tSchBeaconStruct *bcn, + tUpdateBeaconParams *bcn_prm) +{ +} +#endif + +void sch_beacon_process_for_ap(struct mac_context *mac_ctx, + uint8_t session_id, + uint8_t *rx_pkt_info, + tSchBeaconStruct *bcn) +{ + struct pe_session *ap_session; + tUpdateBeaconParams bcn_prm; + + if (!bcn || !rx_pkt_info) { + pe_debug("bcn %pK or rx_pkt_info %pKis NULL", + bcn, rx_pkt_info); + return; + } + + ap_session = pe_find_session_by_session_id(mac_ctx, session_id); + if (!ap_session) + return; + + if (!LIM_IS_AP_ROLE(ap_session)) + return; + + qdf_mem_zero(&bcn_prm, sizeof(tUpdateBeaconParams)); + bcn_prm.paramChangeBitmap = 0; + + bcn_prm.bss_idx = ap_session->vdev_id; + + if (!ap_session->is_session_obss_color_collision_det_enabled) + sch_check_bss_color_ie(mac_ctx, ap_session, + bcn, &bcn_prm); + + if ((ap_session->gLimProtectionControl != + MLME_FORCE_POLICY_PROTECTION_DISABLE) && + !ap_session->is_session_obss_offload_enabled) + ap_beacon_process(mac_ctx, rx_pkt_info, + bcn, &bcn_prm, ap_session); + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) + && bcn_prm.paramChangeBitmap) { + /* Update the bcn and apply the new settings to HAL */ + sch_set_fixed_beacon_fields(mac_ctx, ap_session); + pe_debug("Beacon for PE session[%d] got changed", + ap_session->peSessionId); + pe_debug("sending beacon param change bitmap: 0x%x", + bcn_prm.paramChangeBitmap); + lim_send_beacon_params(mac_ctx, &bcn_prm, ap_session); + } +} + +#ifdef WLAN_BCN_RECV_FEATURE +/* + * sch_send_beacon_report() - To Fill beacon report for + * each beacon coming from connected peer and sends it + * to upper layer + * @mac_ctx: Mac context + * @beacon_struct: Pointing to beacon structure + * @session: pointer to the PE session + * + * Return: None + */ +static +void sch_send_beacon_report(struct mac_context *mac_ctx, + struct sSirProbeRespBeacon *beacon_struct, + struct pe_session *session) +{ + struct wlan_beacon_report beacon_report; + beacon_report_cb sme_bcn_cb; + + sme_bcn_cb = mac_ctx->lim.sme_bcn_rcv_callback; + if (!sme_bcn_cb) + return; + + if (!LIM_IS_STA_ROLE(session)) + return; + + if (sir_compare_mac_addr(session->bssId, beacon_struct->bssid)) { + /* Prepare beacon report from incoming beacon */ + qdf_mem_copy(beacon_report.bssid.bytes, beacon_struct->bssid, + sizeof(tSirMacAddr)); + + qdf_mem_copy(&beacon_report.time_stamp, + &beacon_struct->timeStamp, sizeof(qdf_time_t)); + beacon_report.beacon_interval = beacon_struct->beaconInterval; + beacon_report.frequency = beacon_struct->chan_freq; + + beacon_report.ssid.length = beacon_struct->ssId.length; + qdf_mem_copy(&beacon_report.ssid.ssid, + &beacon_struct->ssId.ssId, + beacon_report.ssid.length); + + beacon_report.boot_time = + qdf_do_div(qdf_get_monotonic_boottime(), + QDF_MC_TIMER_TO_MS_UNIT); + + beacon_report.vdev_id = session->vdev_id; + + /* Send report to upper layer */ + sme_bcn_cb(mac_ctx->hdd_handle, &beacon_report); + } +} + +#else +static inline +void sch_send_beacon_report(struct mac_context *mac_ctx, + struct sSirProbeRespBeacon *beacon_struct, + struct pe_session *session) +{ +} +#endif + +/** + * sch_beacon_process() - process the beacon frame + * @mac_ctx: mac global context + * @rx_pkt_info: pointer to buffer descriptor + * @session: pointer to the PE session + * + * Return: None + */ +void +sch_beacon_process(struct mac_context *mac_ctx, uint8_t *rx_pkt_info, + struct pe_session *session) +{ + static tSchBeaconStruct bcn; + + if (!session) + return; + + /* + * Drop the beacon/probe response from current connected AP in + * below cases to avoid responding to the changes in beacon(e.g. doing + * VDEV_RESTART to update to the latest capabilities), + * 1. vdev is not in connected state: vdev might be transitioning + * 2. Link switch is in progress: Current link or one of the partner + * links are getting replaced. + * + * New beacons/probe rsps can be considered once post these operations. + */ + if (LIM_IS_STA_ROLE(session) && + (!wlan_cm_is_vdev_connected(session->vdev) || + mlo_mgr_is_link_switch_in_progress(session->vdev))) { + pe_debug_rl("vdev %d, drop beacon", session->vdev_id); + return; + } + + /* Convert the beacon frame into a structure */ + if (sir_convert_beacon_frame2_struct(mac_ctx, (uint8_t *) rx_pkt_info, + &bcn) != QDF_STATUS_SUCCESS) { + pe_err_rl("beacon parsing failed"); + return; + } + + session->dtimPeriod = bcn.tim.dtimPeriod; + + sch_send_beacon_report(mac_ctx, &bcn, session); + __sch_beacon_process_for_session(mac_ctx, &bcn, rx_pkt_info, session); +} + +/** + * sch_beacon_edca_process(): Process the EDCA parameter set in the received + * beacon frame + * + * @mac_ctx: mac global context + * @edca: reference to edca parameters in beacon struct + * @session : pesession entry + * + * @return status of operation + */ +QDF_STATUS +sch_beacon_edca_process(struct mac_context *mac, tSirMacEdcaParamSetIE *edca, + struct pe_session *session) +{ + bool follow_ap_edca; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + host_log_qos_edca_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + if (!(mac->mlme_cfg)) { + pe_err("invalid mlme cfg"); + return QDF_STATUS_E_FAILURE; + } + + follow_ap_edca = mlme_get_follow_ap_edca_flag(session->vdev); + + session->gLimEdcaParamSetCount = edca->qosInfo.count; + session->gLimEdcaParams[QCA_WLAN_AC_BE] = edca->acbe; + session->gLimEdcaParams[QCA_WLAN_AC_BK] = edca->acbk; + session->gLimEdcaParams[QCA_WLAN_AC_VI] = edca->acvi; + session->gLimEdcaParams[QCA_WLAN_AC_VO] = edca->acvo; + + if (mac->mlme_cfg->edca_params.enable_edca_params && !follow_ap_edca) { + session->gLimEdcaParams[QCA_WLAN_AC_VO].aci.aifsn = + mac->mlme_cfg->edca_params.edca_ac_vo.vo_aifs; + session->gLimEdcaParams[QCA_WLAN_AC_VI].aci.aifsn = + mac->mlme_cfg->edca_params.edca_ac_vi.vi_aifs; + session->gLimEdcaParams[QCA_WLAN_AC_BK].aci.aifsn = + mac->mlme_cfg->edca_params.edca_ac_bk.bk_aifs; + session->gLimEdcaParams[QCA_WLAN_AC_BE].aci.aifsn = + mac->mlme_cfg->edca_params.edca_ac_be.be_aifs; + + session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.min = + mac->mlme_cfg->edca_params.edca_ac_vo.vo_cwmin; + session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.min = + mac->mlme_cfg->edca_params.edca_ac_vi.vi_cwmin; + session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.min = + mac->mlme_cfg->edca_params.edca_ac_bk.bk_cwmin; + session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.min = + mac->mlme_cfg->edca_params.edca_ac_be.be_cwmin; + + session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.max = + mac->mlme_cfg->edca_params.edca_ac_vo.vo_cwmax; + session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.max = + mac->mlme_cfg->edca_params.edca_ac_vi.vi_cwmax; + session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.max = + mac->mlme_cfg->edca_params.edca_ac_bk.bk_cwmax; + session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.max = + mac->mlme_cfg->edca_params.edca_ac_be.be_cwmax; + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_edca_pkt_type, + LOG_WLAN_QOS_EDCA_C); + if (log_ptr) { + log_ptr->aci_be = session->gLimEdcaParams[QCA_WLAN_AC_BE].aci.aci; + log_ptr->cw_be = + session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.max << 4 + | session->gLimEdcaParams[QCA_WLAN_AC_BE].cw.min; + log_ptr->txoplimit_be = + session->gLimEdcaParams[QCA_WLAN_AC_BE].txoplimit; + log_ptr->aci_bk = + session->gLimEdcaParams[QCA_WLAN_AC_BK].aci.aci; + log_ptr->cw_bk = + session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.max << 4 + | session->gLimEdcaParams[QCA_WLAN_AC_BK].cw.min; + log_ptr->txoplimit_bk = + session->gLimEdcaParams[QCA_WLAN_AC_BK].txoplimit; + log_ptr->aci_vi = + session->gLimEdcaParams[QCA_WLAN_AC_VI].aci.aci; + log_ptr->cw_vi = + session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.max << 4 + | session->gLimEdcaParams[QCA_WLAN_AC_VI].cw.min; + log_ptr->txoplimit_vi = + session->gLimEdcaParams[QCA_WLAN_AC_VI].txoplimit; + log_ptr->aci_vo = + session->gLimEdcaParams[QCA_WLAN_AC_VO].aci.aci; + log_ptr->cw_vo = + session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.max << 4 + | session->gLimEdcaParams[QCA_WLAN_AC_VO].cw.min; + log_ptr->txoplimit_vo = + session->gLimEdcaParams[QCA_WLAN_AC_VO].txoplimit; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pe_debug("Edca param enabled %d. Updating Local Params to: AC_BE: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d AC_BK: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d AC_VI: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d AC_VO: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + mac->mlme_cfg->edca_params.enable_edca_params, + session->gLimEdcaParams[0].aci.aifsn, + session->gLimEdcaParams[0].aci.acm, + session->gLimEdcaParams[0].cw.min, + session->gLimEdcaParams[0].cw.max, + session->gLimEdcaParams[0].txoplimit, + session->gLimEdcaParams[1].aci.aifsn, + session->gLimEdcaParams[1].aci.acm, + session->gLimEdcaParams[1].cw.min, + session->gLimEdcaParams[1].cw.max, + session->gLimEdcaParams[1].txoplimit, + session->gLimEdcaParams[2].aci.aifsn, + session->gLimEdcaParams[2].aci.acm, + session->gLimEdcaParams[2].cw.min, + session->gLimEdcaParams[2].cw.max, + session->gLimEdcaParams[2].txoplimit, + session->gLimEdcaParams[3].aci.aifsn, + session->gLimEdcaParams[3].aci.acm, + session->gLimEdcaParams[3].cw.min, + session->gLimEdcaParams[3].cw.max, + session->gLimEdcaParams[3].txoplimit); + + return QDF_STATUS_SUCCESS; +} + +void lim_enable_obss_detection_config(struct mac_context *mac_ctx, + struct pe_session *session) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!session) { + pe_err("Invalid session, protection not enabled"); + return; + } + + if (session->gLimProtectionControl == + MLME_FORCE_POLICY_PROTECTION_DISABLE) { + pe_err("protectiond disabled, force policy, session %d", + session->smeSessionId); + return; + } + + if (mac_ctx->mlme_cfg->obss_ht40.obss_detection_offload_enabled) { + status = lim_obss_send_detection_cfg(mac_ctx, session, true); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("vdev %d: offload enable failed, trying legacy", + session->smeSessionId); + session->is_session_obss_offload_enabled = false; + } else { + pe_debug("vdev %d: offload detection enabled", + session->smeSessionId); + session->is_session_obss_offload_enabled = true; + lim_obss_send_detection_cfg(mac_ctx, session, true); + } + } + + if (!mac_ctx->mlme_cfg->obss_ht40.obss_detection_offload_enabled || + QDF_IS_STATUS_ERROR(status)) { + status = qdf_mc_timer_start(&session-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("vdev %d: start timer failed", + session->smeSessionId); + else + pe_debug("vdev %d: legacy detection enabled", + session->smeSessionId); + } +} + +QDF_STATUS lim_obss_generate_detection_config(struct mac_context *mac_ctx, + struct pe_session *session, + struct obss_detection_cfg *cfg) +{ + uint32_t phy_mode; + enum reg_wifi_band rf_band = REG_BAND_UNKNOWN; + struct obss_detection_cfg *cur_detect; + + if (!mac_ctx || !session || !cfg) { + pe_err("Invalid params mac_ctx %pK, session %pK, cfg %pK", + mac_ctx, session, cfg); + return QDF_STATUS_E_INVAL; + } + + lim_get_phy_mode(mac_ctx, &phy_mode, session); + rf_band = session->limRFBand; + qdf_mem_zero(cfg, sizeof(*cfg)); + cur_detect = &session->current_obss_detection; + + pe_debug("band:%d, phy_mode:%d, ht_cap:%d, ht_oper_mode:%d", + rf_band, phy_mode, session->htCapability, + mac_ctx->lim.gHTOperMode); + pe_debug("assoc_sta: 11b:%d, 11g:%d, 11a:%d, ht20:%d", + session->gLim11bParams.protectionEnabled, + session->gLim11gParams.protectionEnabled, + session->gLim11aParams.protectionEnabled, + session->gLimHt20Params.protectionEnabled); + pe_debug("obss: 11b:%d, 11g:%d, 11a:%d, ht20:%d", + session->gLimOlbcParams.protectionEnabled, + session->gLimOverlap11gParams.protectionEnabled, + session->gLimOverlap11aParams.protectionEnabled, + session->gLimOverlapHt20Params.protectionEnabled); + pe_debug("detect: b_ap:%d, b_s:%d, g:%d, a:%d, htl:%d, htm:%d, ht20:%d", + cur_detect->obss_11b_ap_detect_mode, + cur_detect->obss_11b_sta_detect_mode, + cur_detect->obss_11g_ap_detect_mode, + cur_detect->obss_11a_detect_mode, + cur_detect->obss_ht_legacy_detect_mode, + cur_detect->obss_ht_mixed_detect_mode, + cur_detect->obss_ht_20mhz_detect_mode); + + if (rf_band == REG_BAND_2G) { + if ((phy_mode == WNI_CFG_PHY_MODE_11G || + session->htCapability) && + !session->gLim11bParams.protectionEnabled) { + if (!session->gLimOlbcParams.protectionEnabled && + !session->gLimOverlap11gParams.protectionEnabled) { + cfg->obss_11b_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + } else { + if (cur_detect->obss_11b_ap_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) + cfg->obss_11b_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + if (cur_detect->obss_11b_sta_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } + } else if (session->gLim11bParams.protectionEnabled) { + session->gLimOlbcParams.protectionEnabled = false; + } + + if (session->htCapability && + session->cfgProtection.overlapFromllg && + !session->gLim11gParams.protectionEnabled) { + if (!session->gLimOverlap11gParams.protectionEnabled) { + cfg->obss_11g_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + cfg->obss_ht_mixed_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + } else { + if (cur_detect->obss_11g_ap_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) + cfg->obss_11g_ap_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + if (cur_detect->obss_ht_legacy_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + if (cur_detect->obss_ht_mixed_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) + cfg->obss_ht_mixed_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } + } else if (session->gLim11gParams.protectionEnabled) { + session->gLimOverlap11gParams.protectionEnabled = false; + } + + /* INI related settings */ + if (mac_ctx->mlme_cfg->sta.ignore_peer_erp_info) + cfg->obss_11b_sta_detect_mode = + OBSS_OFFLOAD_DETECTION_DISABLED; + + if (mac_ctx->mlme_cfg->sap_protection_cfg.ignore_peer_ht_opmode) + cfg->obss_ht_legacy_detect_mode = + OBSS_OFFLOAD_DETECTION_DISABLED; + } + + if ((rf_band == REG_BAND_5G) && session->htCapability) { + if (!session->gLim11aParams.protectionEnabled) { + if (!session->gLimOverlap11aParams.protectionEnabled) + cfg->obss_11a_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + else if (cur_detect->obss_11a_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) + cfg->obss_11a_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } else { + session->gLimOverlap11aParams.protectionEnabled = false; + } + } + + if (((rf_band == REG_BAND_2G) || (rf_band == REG_BAND_5G)) && + session->htCapability) { + + if (!session->gLimHt20Params.protectionEnabled) { + if (!session->gLimOverlapHt20Params.protectionEnabled) { + cfg->obss_ht_20mhz_detect_mode = + OBSS_OFFLOAD_DETECTION_PRESENT; + } else if (cur_detect->obss_ht_20mhz_detect_mode == + OBSS_OFFLOAD_DETECTION_PRESENT) { + cfg->obss_ht_20mhz_detect_mode = + OBSS_OFFLOAD_DETECTION_ABSENT; + } + } else { + session->gLimOverlapHt20Params.protectionEnabled = + false; + } + } + + pe_debug("b_ap:%d, b_s:%d, g:%d, a:%d, ht_le:%d, ht_m:%d, ht_20:%d", + cfg->obss_11b_ap_detect_mode, + cfg->obss_11b_sta_detect_mode, + cfg->obss_11g_ap_detect_mode, + cfg->obss_11a_detect_mode, + cfg->obss_ht_legacy_detect_mode, + cfg->obss_ht_mixed_detect_mode, + cfg->obss_ht_20mhz_detect_mode); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_obss_send_detection_cfg(struct mac_context *mac_ctx, + struct pe_session *session, bool force) +{ + QDF_STATUS status; + struct obss_detection_cfg obss_cfg; + struct wmi_obss_detection_cfg_param *req_param; + + if (!session) { + pe_err("Invalid session"); + return QDF_STATUS_E_INVAL; + } + + if (!session->is_session_obss_offload_enabled) { + pe_debug("obss offload protectiond disabled, session %d", + session->smeSessionId); + /* Send success */ + return QDF_STATUS_SUCCESS; + } + + if (session->gLimProtectionControl == + MLME_FORCE_POLICY_PROTECTION_DISABLE) { + pe_debug("protectiond disabled, force from policy, session %d", + session->smeSessionId); + /* Send success */ + return QDF_STATUS_SUCCESS; + } + + status = lim_obss_generate_detection_config(mac_ctx, + session, + &obss_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to generate obss detection cfg, session %d", + session->smeSessionId); + return status; + } + + if (qdf_mem_cmp(&session->obss_offload_cfg, &obss_cfg, sizeof(obss_cfg)) + || force) { + struct scheduler_msg msg = {0}; + req_param = qdf_mem_malloc(sizeof(*req_param)); + if (!req_param) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(&session->obss_offload_cfg, &obss_cfg, + sizeof(obss_cfg)); + req_param->vdev_id = session->smeSessionId; + req_param->obss_detect_period_ms = OBSS_DETECTION_PERIOD_MS; + req_param->obss_11b_ap_detect_mode = + obss_cfg.obss_11b_ap_detect_mode; + req_param->obss_11b_sta_detect_mode = + obss_cfg.obss_11b_sta_detect_mode; + req_param->obss_11g_ap_detect_mode = + obss_cfg.obss_11g_ap_detect_mode; + req_param->obss_11a_detect_mode = + obss_cfg.obss_11a_detect_mode; + req_param->obss_ht_legacy_detect_mode = + obss_cfg.obss_ht_legacy_detect_mode; + req_param->obss_ht_20mhz_detect_mode = + obss_cfg.obss_ht_20mhz_detect_mode; + req_param->obss_ht_mixed_detect_mode = + obss_cfg.obss_ht_mixed_detect_mode; + + msg.type = WMA_OBSS_DETECTION_REQ; + msg.bodyptr = req_param; + msg.reserved = 0; + status = scheduler_post_message(QDF_MODULE_ID_PE, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(req_param); + return status; + } + } else { + pe_debug("Skipping WMA_OBSS_DETECTION_REQ, force = %d", force); + } + + return status; +} + +QDF_STATUS lim_process_obss_detection_ind(struct mac_context *mac_ctx, + struct wmi_obss_detect_info + *obss_detection) +{ + QDF_STATUS status; + uint32_t detect_masks; + uint32_t reason; + struct obss_detection_cfg *obss_cfg; + bool enable; + struct pe_session *session; + tUpdateBeaconParams bcn_prm; + enum reg_wifi_band rf_band = REG_BAND_UNKNOWN; + struct obss_detection_cfg *cur_detect; + + pe_debug("obss detect ind id %d, reason %d, msk 0x%x, " QDF_MAC_ADDR_FMT, + obss_detection->vdev_id, obss_detection->reason, + obss_detection->matched_detection_masks, + QDF_MAC_ADDR_REF(obss_detection->matched_bssid_addr)); + + session = pe_find_session_by_vdev_id(mac_ctx, obss_detection->vdev_id); + if (!session) { + pe_err("Failed to get session for id %d", + obss_detection->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!LIM_IS_AP_ROLE(session)) { + pe_err("session %d is not AP", obss_detection->vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!session->is_session_obss_offload_enabled) { + pe_err("Offload already disabled for session %d", + obss_detection->vdev_id); + return QDF_STATUS_SUCCESS; + } + + reason = obss_detection->reason; + detect_masks = obss_detection->matched_detection_masks; + + if (reason == OBSS_OFFLOAD_DETECTION_PRESENT) { + enable = true; + } else if (reason == OBSS_OFFLOAD_DETECTION_ABSENT) { + enable = false; + } else if (reason == OBSS_OFFLOAD_DETECTION_DISABLED) { + /* + * Most common reason for this event-type from firmware + * is insufficient memory. + * Disable offload OBSS detection and enable legacy-way + * of detecting OBSS by parsing beacons. + **/ + session->is_session_obss_offload_enabled = false; + pe_err("FW indicated obss offload disabled"); + pe_err("Enabling host based detection, session %d", + obss_detection->vdev_id); + + status = qdf_mc_timer_start(&session-> + protection_fields_reset_timer, + SCH_PROTECTION_RESET_TIME); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("cannot start protection reset timer"); + + return QDF_STATUS_SUCCESS; + } else { + pe_err("Invalid reason %d, session %d", + obss_detection->reason, + obss_detection->vdev_id); + return QDF_STATUS_E_INVAL; + } + + rf_band = session->limRFBand; + qdf_mem_zero(&bcn_prm, sizeof(bcn_prm)); + obss_cfg = &session->obss_offload_cfg; + cur_detect = &session->current_obss_detection; + + if (OBSS_DETECTION_IS_11B_AP(detect_masks)) { + if (reason != obss_cfg->obss_11b_ap_detect_mode || + rf_band != REG_BAND_2G) + goto wrong_detection; + + lim_enable11g_protection(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_11b_ap_detect_mode = reason; + } + if (OBSS_DETECTION_IS_11B_STA(detect_masks)) { + if (reason != obss_cfg->obss_11b_sta_detect_mode || + rf_band != REG_BAND_2G) + goto wrong_detection; + + lim_enable11g_protection(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_11b_sta_detect_mode = reason; + } + if (OBSS_DETECTION_IS_11G_AP(detect_masks)) { + if (reason != obss_cfg->obss_11g_ap_detect_mode || + rf_band != REG_BAND_2G) + goto wrong_detection; + + lim_enable_ht_protection_from11g(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_11g_ap_detect_mode = reason; + } + if (OBSS_DETECTION_IS_11A(detect_masks)) { + if (reason != obss_cfg->obss_11a_detect_mode || + rf_band != REG_BAND_5G) + goto wrong_detection; + + lim_update_11a_protection(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_11a_detect_mode = reason; + } + if (OBSS_DETECTION_IS_HT_LEGACY(detect_masks)) { + /* for 5GHz, we have only 11a detection, which covers legacy */ + if (reason != obss_cfg->obss_ht_legacy_detect_mode || + rf_band != REG_BAND_2G) + goto wrong_detection; + + lim_enable_ht_protection_from11g(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_ht_legacy_detect_mode = reason; + } + if (OBSS_DETECTION_IS_HT_MIXED(detect_masks)) { + /* for 5GHz, we have only 11a detection, which covers ht mix */ + if (reason != obss_cfg->obss_ht_mixed_detect_mode || + rf_band != REG_BAND_2G) + goto wrong_detection; + + lim_enable_ht_protection_from11g(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_ht_mixed_detect_mode = reason; + } + if (OBSS_DETECTION_IS_HT_20MHZ(detect_masks)) { + if (reason != obss_cfg->obss_ht_20mhz_detect_mode) + goto wrong_detection; + + lim_enable_ht20_protection(mac_ctx, enable, true, + &bcn_prm, session); + cur_detect->obss_ht_20mhz_detect_mode = reason; + } + + if ((false == mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) && + bcn_prm.paramChangeBitmap) { + /* Update the bcn and apply the new settings to HAL */ + sch_set_fixed_beacon_fields(mac_ctx, session); + pe_debug("Beacon for PE session: %d got changed: 0x%x", + session->smeSessionId, bcn_prm.paramChangeBitmap); + if (!QDF_IS_STATUS_SUCCESS(lim_send_beacon_params( + mac_ctx, &bcn_prm, session))) { + pe_err("Failed to send beacon param, session %d", + obss_detection->vdev_id); + return QDF_STATUS_E_FAULT; + } + } + + status = lim_obss_send_detection_cfg(mac_ctx, session, true); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to send obss detection cfg, session %d", + obss_detection->vdev_id); + return status; + } + + return QDF_STATUS_SUCCESS; + +wrong_detection: + /* + * We may get this wrong detection before FW can update latest cfg, + * So keeping log level debug + **/ + pe_debug("Wrong detection, session %d", obss_detection->vdev_id); + + return QDF_STATUS_E_INVAL; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_message.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_message.c new file mode 100644 index 0000000000..3251c6ff0d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_message.c @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "cds_api.h" +#include "sir_common.h" + +#include "wni_cfg.h" +#include "ani_global.h" +#include "lim_api.h" +#include "lim_send_messages.h" + +#include "sch_api.h" +#include "wlan_mlme_api.h" +#include +#include "lim_utils.h" + +/* / Minimum beacon interval allowed (in Kus) */ +#define SCH_BEACON_INTERVAL_MIN 10 + +/* / Maximum beacon interval allowed (in Kus) */ +#define SCH_BEACON_INTERVAL_MAX 10000 + +/* / convert the CW values into a uint16_t */ +#define GET_CW(pCw) ((uint16_t) ((*(pCw) << 8) + *((pCw) + 1))) + +/* Max debug string size for WMM in bytes */ +#define SCH_WMM_DEBUG_STRING_SIZE 512 + +/* local functions */ +static QDF_STATUS +get_wmm_local_params(struct mac_context *mac, + uint32_t params[][CFG_EDCA_DATA_LEN]); +static void +set_sch_edca_params(struct mac_context *mac, + uint32_t params[][CFG_EDCA_DATA_LEN], + struct pe_session *pe_session); + +/* -------------------------------------------------------------------- */ +/** + * sch_set_beacon_interval + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param None + * @return None + */ + +void sch_set_beacon_interval(struct mac_context *mac, + struct pe_session *pe_session) +{ + uint32_t bi; + + bi = pe_session->beaconParams.beaconInterval; + + if (bi < SCH_BEACON_INTERVAL_MIN || bi > SCH_BEACON_INTERVAL_MAX) { + pe_debug("Invalid beacon interval %d (should be [%d,%d]", bi, + SCH_BEACON_INTERVAL_MIN, SCH_BEACON_INTERVAL_MAX); + return; + } + + mac->sch.beacon_interval = (uint16_t) bi; +} + +void sch_edca_profile_update_all(struct mac_context *pmac) +{ + uint32_t i; + struct pe_session *psession_entry; + + for (i = 0; i < pmac->lim.maxBssId; i++) { + psession_entry = &pmac->lim.gpSession[i]; + if (psession_entry->valid) + sch_edca_profile_update(pmac, psession_entry); + } +} + +/** + * sch_get_params() - get the local or broadcast parameters based on the profile + * specified in the config params are delivered in this order: BE, BK, VI, VO + */ +static QDF_STATUS +sch_get_params(struct mac_context *mac, + uint32_t params[][CFG_EDCA_DATA_LEN], + uint8_t local) +{ + uint32_t val; + uint32_t i, idx; + uint32_t *prf; + struct wlan_mlme_edca_params *edca_params; + QDF_STATUS status; + uint8_t country_code_str[REG_ALPHA2_LEN + 1]; + uint32_t ani_l[] = {edca_ani_acbe_local, edca_ani_acbk_local, + edca_ani_acvi_local, edca_ani_acvo_local}; + + uint32_t wme_l[] = {edca_wme_acbe_local, edca_wme_acbk_local, + edca_wme_acvi_local, edca_wme_acvo_local}; + + uint32_t etsi_l[] = {edca_etsi_acbe_local, edca_etsi_acbk_local, + edca_etsi_acvi_local, edca_etsi_acvo_local}; + + uint32_t ani_b[] = {edca_ani_acbe_bcast, edca_ani_acbk_bcast, + edca_ani_acvi_bcast, edca_ani_acvo_bcast}; + + uint32_t wme_b[] = {edca_wme_acbe_bcast, edca_wme_acbk_bcast, + edca_wme_acvi_bcast, edca_wme_acvo_bcast}; + + uint32_t etsi_b[] = {edca_etsi_acbe_bcast, edca_etsi_acbk_bcast, + edca_etsi_acvi_bcast, edca_etsi_acvo_bcast}; + edca_params = &mac->mlme_cfg->edca_params; + + wlan_reg_get_cc_and_src(mac->psoc, country_code_str); + + if (cds_is_etsi_europe_country(country_code_str)) { + val = WNI_CFG_EDCA_PROFILE_ETSI_EUROPE; + pe_debug("switch to ETSI EUROPE profile country code %c%c", + country_code_str[0], country_code_str[1]); + } else { + val = mac->mlme_cfg->wmm_params.edca_profile; + } + if (val >= WNI_CFG_EDCA_PROFILE_MAX) { + pe_warn("Invalid EDCA_PROFILE %d, using %d instead", val, + WNI_CFG_EDCA_PROFILE_ANI); + val = WNI_CFG_EDCA_PROFILE_ANI; + } + + pe_debug("EdcaProfile: Using %d (%s)", val, + ((val == WNI_CFG_EDCA_PROFILE_WMM) ? "WMM" : "HiPerf")); + + if (local) { + switch (val) { + case WNI_CFG_EDCA_PROFILE_WMM: + prf = &wme_l[0]; + break; + case WNI_CFG_EDCA_PROFILE_ETSI_EUROPE: + prf = &etsi_l[0]; + break; + case WNI_CFG_EDCA_PROFILE_ANI: + default: + prf = &ani_l[0]; + break; + } + } else { + switch (val) { + case WNI_CFG_EDCA_PROFILE_WMM: + prf = &wme_b[0]; + break; + case WNI_CFG_EDCA_PROFILE_ETSI_EUROPE: + prf = &etsi_b[0]; + break; + case WNI_CFG_EDCA_PROFILE_ANI: + default: + prf = &ani_b[0]; + break; + } + } + + for (i = 0; i < 4; i++) { + uint8_t data[CFG_EDCA_DATA_LEN]; + + status = wlan_mlme_get_edca_params(edca_params, + (uint8_t *)&data[0], + (uint8_t)prf[i]); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Get failed for ac:%d", i); + return QDF_STATUS_E_FAILURE; + } + + for (idx = 0; idx < CFG_EDCA_DATA_LEN; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + pe_debug("GetParams: local=%d, profile = %d Done", local, val); + + return QDF_STATUS_SUCCESS; +} + +/** + * broadcast_wmm_of_concurrent_sta_session() - broadcasts wmm info + * @mac_ctx: mac global context + * @session: pesession entry + * + * Return: true if wmm param updated, false if wmm param not updated + */ +static bool +broadcast_wmm_of_concurrent_sta_session(struct mac_context *mac_ctx, + struct pe_session *session) +{ + uint8_t i, j; + struct pe_session *concurrent_session = NULL; + + for (i = 0; i < mac_ctx->lim.maxBssId; i++) { + /* + * Find another INFRA STA AP session on same operating channel. + * The session entry passed to this API is for GO/SoftAP session + * that is getting added currently + */ + if (!((mac_ctx->lim.gpSession[i].valid == true) && + (mac_ctx->lim.gpSession[i].peSessionId != + session->peSessionId) && + (mac_ctx->lim.gpSession[i].curr_op_freq == + session->curr_op_freq) && + (mac_ctx->lim.gpSession[i].limSystemRole == + eLIM_STA_ROLE))) + continue; + + concurrent_session = &(mac_ctx->lim.gpSession[i]); + break; + } + + if (!concurrent_session) + return false; + + if (!qdf_mem_cmp(session->gLimEdcaParamsBC, + concurrent_session->gLimEdcaParams, + sizeof(concurrent_session->gLimEdcaParams))) + return false; + + /* + * Once atleast one concurrent session on same channel is found and WMM + * broadcast params for current SoftAP/GO session updated, return + */ + for (j = 0; j < QCA_WLAN_AC_ALL; j++) { + session->gLimEdcaParamsBC[j].aci.acm = + concurrent_session->gLimEdcaParams[j].aci.acm; + session->gLimEdcaParamsBC[j].aci.aifsn = + concurrent_session->gLimEdcaParams[j].aci.aifsn; + session->gLimEdcaParamsBC[j].cw.min = + concurrent_session->gLimEdcaParams[j].cw.min; + session->gLimEdcaParamsBC[j].cw.max = + concurrent_session->gLimEdcaParams[j].cw.max; + session->gLimEdcaParamsBC[j].txoplimit = + concurrent_session->gLimEdcaParams[j].txoplimit; + pe_debug("QoSUpdateBCast changed again due to concurrent INFRA STA session: AC :%d: AIFSN: %d, ACM %d, CWmin %d, CWmax %d, TxOp %d", + j, session->gLimEdcaParamsBC[j].aci.aifsn, + session->gLimEdcaParamsBC[j].aci.acm, + session->gLimEdcaParamsBC[j].cw.min, + session->gLimEdcaParamsBC[j].cw.max, + session->gLimEdcaParamsBC[j].txoplimit); + } + return true; +} + +void sch_qos_update_broadcast(struct mac_context *mac, struct pe_session *pe_session) +{ + uint32_t params[4][CFG_EDCA_DATA_LEN]; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + uint8_t i; + bool updated = false; + QDF_STATUS status; + uint8_t *debug_str; + uint32_t len = 0; + + if (sch_get_params(mac, params, false) != QDF_STATUS_SUCCESS) { + pe_debug("QosUpdateBroadcast: failed"); + return; + } + lim_get_phy_mode(mac, &phyMode, pe_session); + + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = CFG_EDCA_PROFILE_TXOPG_IDX; + } else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = CFG_EDCA_PROFILE_TXOPA_IDX; + } + + debug_str = qdf_mem_malloc(SCH_WMM_DEBUG_STRING_SIZE); + if (!debug_str) + return; + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + if (pe_session->gLimEdcaParamsBC[i].aci.acm != + (uint8_t)params[i][CFG_EDCA_PROFILE_ACM_IDX]) { + pe_session->gLimEdcaParamsBC[i].aci.acm = + (uint8_t)params[i][CFG_EDCA_PROFILE_ACM_IDX]; + updated = true; + } + if (pe_session->gLimEdcaParamsBC[i].aci.aifsn != + (uint8_t)params[i][CFG_EDCA_PROFILE_AIFSN_IDX]) { + pe_session->gLimEdcaParamsBC[i].aci.aifsn = + (uint8_t)params[i][CFG_EDCA_PROFILE_AIFSN_IDX]; + updated = true; + } + if (pe_session->gLimEdcaParamsBC[i].cw.min != + convert_cw(GET_CW(¶ms[i][cwminidx]))) { + pe_session->gLimEdcaParamsBC[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + updated = true; + } + if (pe_session->gLimEdcaParamsBC[i].cw.max != + convert_cw(GET_CW(¶ms[i][cwmaxidx]))) { + pe_session->gLimEdcaParamsBC[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + updated = true; + } + if (pe_session->gLimEdcaParamsBC[i].txoplimit != + (uint16_t)params[i][txopidx]) { + pe_session->gLimEdcaParamsBC[i].txoplimit = + (uint16_t)params[i][txopidx]; + updated = true; + } + + len += qdf_scnprintf(debug_str + len, + SCH_WMM_DEBUG_STRING_SIZE - len, + "AC[%d]: AIFSN %d ACM %d CWmin %d CWmax %d TxOp %d, ", + i, pe_session->gLimEdcaParamsBC[i].aci.aifsn, + pe_session->gLimEdcaParamsBC[i].aci.acm, + pe_session->gLimEdcaParamsBC[i].cw.min, + pe_session->gLimEdcaParamsBC[i].cw.max, + pe_session->gLimEdcaParamsBC[i].txoplimit); + + } + + pe_nofl_debug("QosUpdBcast: mode %d, %s", phyMode, debug_str); + qdf_mem_free(debug_str); + + /* + * If there exists a concurrent STA-AP session, use its WMM + * params to broadcast in beacons. WFA Wifi Direct test plan + * 6.1.14 requirement + */ + if (broadcast_wmm_of_concurrent_sta_session(mac, pe_session)) + updated = true; + if (updated) + pe_session->gLimEdcaParamSetCount++; + + status = sch_set_fixed_beacon_fields(mac, pe_session); + if (QDF_IS_STATUS_ERROR(status)) + pe_err("Unable to set beacon fields!"); +} + +void sch_qos_update_local(struct mac_context *mac, struct pe_session *pe_session) +{ + + uint32_t params[4][CFG_EDCA_DATA_LEN]; + QDF_STATUS status; + + pe_debug("user_edca_set : %u", pe_session->user_edca_set); + /* If user preferred EDCA setting present, use it, do not default */ + if (pe_session->user_edca_set == 0) { + status = sch_get_params(mac, params, true /*local */); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("sch_get_params(local) failed"); + return; + } + + set_sch_edca_params(mac, params, pe_session); + } + + lim_set_active_edca_params(mac, pe_session->gLimEdcaParams, pe_session); + + /* For AP, the bssID is stored in LIM Global context. */ + lim_send_edca_params(mac, pe_session->gLimEdcaParamsActive, + pe_session->vdev_id, false); +} + +/** + * sch_set_default_edca_params() - This function sets the gLimEdcaParams to the + * default local wmm profile. + * @mac - Global mac context + * @pe_session - PE session + * + * return none + */ +void sch_set_default_edca_params(struct mac_context *mac, struct pe_session *pe_session) +{ + uint32_t params[4][CFG_EDCA_DATA_LEN]; + + if (get_wmm_local_params(mac, params) != QDF_STATUS_SUCCESS) { + pe_err("get_wmm_local_params() failed"); + return; + } + + set_sch_edca_params(mac, params, pe_session); + return; +} + +/** + * set_sch_edca_params() - This function fills in the gLimEdcaParams structure + * with the given edca params. + * @mac - global mac context + * @pe_session - PE session + * @params - EDCA parameters + * + * Return none + */ +static void +set_sch_edca_params(struct mac_context *mac, + uint32_t params[][CFG_EDCA_DATA_LEN], + struct pe_session *pe_session) +{ + uint32_t i; + uint32_t cwminidx, cwmaxidx, txopidx; + uint32_t phyMode; + + lim_get_phy_mode(mac, &phyMode, pe_session); + + /* if (mac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11G) */ + if (phyMode == WNI_CFG_PHY_MODE_11G) { + cwminidx = CFG_EDCA_PROFILE_CWMING_IDX; + cwmaxidx = CFG_EDCA_PROFILE_CWMAXG_IDX; + txopidx = CFG_EDCA_PROFILE_TXOPG_IDX; + } + /* else if (mac->lim.gLimPhyMode == WNI_CFG_PHY_MODE_11B) */ + else if (phyMode == WNI_CFG_PHY_MODE_11B) { + cwminidx = CFG_EDCA_PROFILE_CWMINB_IDX; + cwmaxidx = CFG_EDCA_PROFILE_CWMAXB_IDX; + txopidx = CFG_EDCA_PROFILE_TXOPB_IDX; + } else { + /* This can happen if mode is not set yet, assume 11a mode */ + cwminidx = CFG_EDCA_PROFILE_CWMINA_IDX; + cwmaxidx = CFG_EDCA_PROFILE_CWMAXA_IDX; + txopidx = CFG_EDCA_PROFILE_TXOPA_IDX; + } + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + pe_session->gLimEdcaParams[i].aci.acm = + (uint8_t)params[i][CFG_EDCA_PROFILE_ACM_IDX]; + pe_session->gLimEdcaParams[i].aci.aifsn = + (uint8_t)params[i][CFG_EDCA_PROFILE_AIFSN_IDX]; + pe_session->gLimEdcaParams[i].cw.min = + convert_cw(GET_CW(¶ms[i][cwminidx])); + pe_session->gLimEdcaParams[i].cw.max = + convert_cw(GET_CW(¶ms[i][cwmaxidx])); + pe_session->gLimEdcaParams[i].txoplimit = + (uint16_t)params[i][txopidx]; + } + return; +} + +/** + * get_wmm_local_params() - This function gets the WMM local edca parameters. + * @mac + * @params[][WNI_CFG_EDCA_ANI_ACBK_LOCAL_LEN] + * + * Return none + */ +static QDF_STATUS +get_wmm_local_params(struct mac_context *mac_ctx, + uint32_t params[][CFG_EDCA_DATA_LEN]) +{ + uint32_t i, idx; + QDF_STATUS status; + struct wlan_mlme_edca_params *edca_params; + uint32_t wme_l[] = {edca_wme_acbe_local, edca_wme_acbk_local, + edca_wme_acvi_local, edca_wme_acvo_local}; + + if (!mac_ctx->mlme_cfg) { + pe_err("NULL mlme cfg"); + return QDF_STATUS_E_FAILURE; + } + + edca_params = &mac_ctx->mlme_cfg->edca_params; + for (i = 0; i < 4; i++) { + uint8_t data[CFG_EDCA_DATA_LEN]; + + status = wlan_mlme_get_edca_params(edca_params, + (uint8_t *)&data[0], + (uint8_t)wme_l[i]); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Get failed for ac:[%d]", i); + return QDF_STATUS_E_FAILURE; + } + for (idx = 0; idx < CFG_EDCA_DATA_LEN; idx++) + params[i][idx] = (uint32_t) data[idx]; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sch_qos_concurrency_update() - This function updates the local and + * broadcast based on STA and SAP + * concurrency. It also updates the + * edcaParamSetCount, if Broadcast EDCA params are updated based on Concurrency. + * + * Return none + */ +void sch_qos_concurrency_update(void) +{ + lim_send_conc_params_update(); +} + +static void sch_qos_update_edca_pifs_param_for_ll_sap(struct mac_context *mac, + uint8_t vdev_id) +{ + struct wlan_edca_pifs_param_ie param = {0}; + enum host_edca_param_type edca_param_type = + HOST_EDCA_PARAM_TYPE_AGGRESSIVE; + + edca_param_type = mac->mlme_cfg->edca_params.edca_param_type; + wlan_mlme_set_edca_pifs_param(¶m, edca_param_type); + lim_send_edca_pifs_param(mac, ¶m, vdev_id); +} + +/** + * sch_edca_profile_update() - This function updates the local and broadcast + * EDCA params in the gLimEdcaParams structure. It also updates the + * edcaParamSetCount. + * + * @mac - global mac context + * + * Return none + */ +void sch_edca_profile_update(struct mac_context *mac, struct pe_session *pe_session) +{ + if (LIM_IS_AP_ROLE(pe_session)) { + sch_qos_update_local(mac, pe_session); + sch_qos_update_broadcast(mac, pe_session); + sch_qos_concurrency_update(); + + if (policy_mgr_is_vdev_ll_lt_sap( + mac->psoc, pe_session->vdev_id)) + sch_qos_update_edca_pifs_param_for_ll_sap( + mac, + pe_session->vdev_id); + } +} + +/* -------------------------------------------------------------------- */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h new file mode 100644 index 0000000000..da74ecf49f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/pe/sch/sch_sys_params.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011-2012, 2014, 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sch_sys_params.h contains scheduler parameter definitions + * + * Author: Sandesh Goel + * Date: 02/25/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#ifndef __SCH_SYS_PARAMS_H__ +#define __SCH_SYS_PARAMS_H__ + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h new file mode 100644 index 0000000000..1e3075f127 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/common/inc/wlan_qct_sys.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(WLAN_QCT_SYS_H__) +#define WLAN_QCT_SYS_H__ + +/**=========================================================================== + + \file wlan_qct_sys.h + + \brief System module API + + ==========================================================================*/ + +/* $HEADER$ */ + +/*--------------------------------------------------------------------------- + Include files + -------------------------------------------------------------------------*/ +#include +#include +#include + +struct mac_context; + +/*--------------------------------------------------------------------------- + Preprocessor definitions and constants + -------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + Type declarations + -------------------------------------------------------------------------*/ + +/** + * sys_rsp_cb() - SYS async response callback + * @user_data: context data for callback + * + * This is a protype for the callback function that SYS makes to various + * modules in the system. + * + * Return: None + */ +typedef void (*sys_rsp_cb)(void *user_data); + +/** + * sys_build_message_header() - to build the sys message header + * @msg_id: message id + * @msg: pointer to message context + * + * This function will initialize the SYS message header with the + * message type and any internal fields needed for a new SYS + * message. This function sets all but the message body, which is up + * to the caller to setup based on the specific message being built. + * + * NOTE: There are internal / reserved items in a SYS message that + * must be set correctly for the message to be recognized as a SYS + * message by the SYS message handlers. It is important for every SYS + * message to be setup / built / initialized through this function. + * + * Return: QDF_STATUS + */ +QDF_STATUS sys_build_message_header(SYS_MSG_ID msg_id, + struct scheduler_msg *msg); + +/** + * umac_stop() - send schedule message to mc thread to stop umac (sme and mac) + * + * Return: status of operation + */ +QDF_STATUS umac_stop(void); + +QDF_STATUS sys_mc_process_handler(struct scheduler_msg *msg); + +/** + * sys_process_mmh_msg() - api to process an mmh message + * @mac: pointer to mac context + * @msg: pointer to message + * + * This API is used to process an mmh message. + * + * NOTE WELL: Ownership of the @msg bodyptr, if present, is always + * transferred, and the caller must not attempt to dereference or free + * the bodyptr after invoking this API. + * + * Return: none + */ +void sys_process_mmh_msg(struct mac_context *mac, + struct scheduler_msg *msg); + +#endif /* WLAN_QCT_SYS_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c new file mode 100644 index 0000000000..bbff690457 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/common/src/wlan_qct_sys.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include /* needed for tSirMbMsg */ +#include /* needed for SIR_... message types */ +#include /* needed for WNI_... message types */ +#include "ani_global.h" +#include "wma_types.h" +#include "sme_api.h" +#include "mac_init_api.h" +#include "qdf_trace.h" + +/* + * Cookie for SYS messages. Note that anyone posting a SYS Message + * has to write the COOKIE in the reserved field of the message. The + * SYS Module relies on this COOKIE + */ +#define SYS_MSG_COOKIE 0xFACE + +/* SYS stop timeout 30 seconds */ +#define SYS_STOP_TIMEOUT (30000) +static qdf_event_t g_stop_evt; + +QDF_STATUS sys_build_message_header(SYS_MSG_ID msg_id, + struct scheduler_msg *msg) +{ + msg->type = msg_id; + msg->reserved = SYS_MSG_COOKIE; + + return QDF_STATUS_SUCCESS; +} + +/** + * umac_stop_complete_cb() - a callback when system stop completes + * @msg: pointer to actual message being handled + * + * this callback is used once system stop is completed. + * + * Return: QDF_STATUS + */ +#ifdef QDF_ENABLE_TRACING +static QDF_STATUS umac_stop_complete_cb(struct scheduler_msg *msg) +{ + qdf_event_t *stop_evt = msg->bodyptr; + QDF_STATUS qdf_status = qdf_event_set(stop_evt); + + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + + return qdf_status; +} +#else +static QDF_STATUS umac_stop_complete_cb(struct scheduler_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static inline QDF_STATUS umac_stop_flush_cb(struct scheduler_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * umac_stop() - To post stop message to system module + * + * This API is used post a stop message to system module + * + * Return: QDF_STATUS + */ +QDF_STATUS umac_stop(void) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg umac_stop_msg; + + /* Initialize the stop event */ + qdf_status = qdf_event_create(&g_stop_evt); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + return qdf_status; + + /* post a message to SYS module in MC to stop SME and MAC */ + sys_build_message_header(SYS_MSG_ID_UMAC_STOP, &umac_stop_msg); + + /* Save the user callback and user data */ + umac_stop_msg.callback = umac_stop_complete_cb; + umac_stop_msg.bodyptr = (void *)&g_stop_evt; + umac_stop_msg.flush_callback = umac_stop_flush_cb; + + /* post the message.. */ + qdf_status = scheduler_post_message(QDF_MODULE_ID_SYS, + QDF_MODULE_ID_SYS, + QDF_MODULE_ID_SYS, &umac_stop_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_status = QDF_STATUS_E_BADMSG; + + qdf_status = qdf_wait_single_event(&g_stop_evt, SYS_STOP_TIMEOUT); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + + qdf_status = qdf_event_destroy(&g_stop_evt); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + + return qdf_status; +} + +/** + * sys_mc_process_msg() - to process system mc thread messages + * @pMsg: message pointer + * + * This API is used to process the message + * + * Return: QDF_STATUS + */ +static QDF_STATUS sys_mc_process_msg(struct scheduler_msg *pMsg) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + mac_handle_t mac_handle; + + if (!pMsg) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "%s: NULL pointer to struct scheduler_msg", __func__); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + /* + * All 'new' SYS messages are identified by a cookie in the reserved + * field of the message as well as the message type. This prevents + * the possibility of overlap in the message types defined for new + * SYS messages with the 'legacy' message types. The legacy messages + * will not have this cookie in the reserved field + */ + if (SYS_MSG_COOKIE == pMsg->reserved) { + /* Process all the new SYS messages.. */ + switch (pMsg->type) { + case SYS_MSG_ID_UMAC_STOP: + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Processing SYS MC STOP"); + mac_handle = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_handle) + break; + + qdf_status = sme_stop(mac_handle); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + qdf_status = mac_stop(mac_handle); + QDF_ASSERT(QDF_IS_STATUS_SUCCESS(qdf_status)); + qdf_status = pMsg->callback(pMsg); + break; + case SYS_MSG_ID_DATA_STALL_MSG: + if (pMsg->callback) + qdf_status = pMsg->callback(pMsg); + + qdf_mem_free(pMsg->bodyptr); + break; + default: + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Unknown message type msgType= %d [0x%08x]", + pMsg->type, pMsg->type); + break; + + } + } else { + QDF_TRACE(QDF_MODULE_ID_SYS, + QDF_TRACE_LEVEL_ERROR, + "Rx SYS unknown MC msgtype= %d [0x%08X]", + pMsg->type, pMsg->type); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_BADMSG; + + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + } + return qdf_status; +} + +QDF_STATUS sys_mc_process_handler(struct scheduler_msg *msg) +{ + return sys_mc_process_msg(msg); +} + +void sys_process_mmh_msg(struct mac_context *mac, struct scheduler_msg *msg) +{ + QDF_MODULE_ID dest_module = QDF_MODULE_ID_SYS; + + if (!msg) { + QDF_ASSERT(0); + return; + } + + switch (msg->type) { + case eWNI_SME_SYS_READY_IND: + /* Forward this message to the PE module */ + dest_module = QDF_MODULE_ID_PE; + break; + default: + if ((msg->type >= eWNI_SME_MSG_TYPES_BEGIN) && + (msg->type <= eWNI_SME_MSG_TYPES_END)) { + dest_module = QDF_MODULE_ID_SME; + break; + } + + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Message of ID %d is not yet handled by SYS", + msg->type); + QDF_ASSERT(0); + } + + /* + * Post now the message to the appropriate module for handling + */ + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SYS, + QDF_MODULE_ID_SYS, + dest_module, + msg)) + qdf_mem_free(msg->bodyptr); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h new file mode 100644 index 0000000000..793b091843 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/platform/inc/sys_wrapper.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * @file VossWrapper.h + * + * @brief This header file contains the various structure definitions and + * function prototypes for the RTOS abstraction layer, implemented for VOSS + */ + +#ifndef __VOSS_WRAPPER_H +#define __VOSS_WRAPPER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/*--------------------------------------------------------------------------- + * Include Files + * ------------------------------------------------------------------------*/ + +#include "sir_types.h" +#include "sir_params.h" +#include "sys_def.h" +#include "qdf_mc_timer.h" +#include "qdf_types.h" +#include "qdf_trace.h" +#include "qdf_mem.h" + +/* Interlocked Compare Exchange related definitions */ + +/* Define basic constants for the ThreadX kernel. */ + +#define TX_AUTO_ACTIVATE 1 +#define TX_NO_ACTIVATE 0 + +/* API return values. */ +#define TX_SUCCESS 0x00 +#define TX_QUEUE_FULL 0x01 +/* ... */ +#define TX_NO_INSTANCE 0x0D +/* ... */ +#define TX_TIMER_ERROR 0x15 +#define TX_TICK_ERROR 0x16 +/* ... */ + +#ifndef true +#define true 1 +#endif + +#ifndef false +#define false 0 +#endif + +/* Following macro specifies the number of milliseconds which constitute 1 ThreadX timer tick. Used + for mimicking the ThreadX timer behaviour on VOSS. */ +/* Use the same MACRO used by firmware modules to calculate TICKs from mSec */ +/* Mismatch would cause wrong timer value to be programmed */ +#define TX_MSECS_IN_1_TICK SYS_TICK_DUR_MS + +/* Signature with which the TX_TIMER struct is initialized, when the timer is created */ +#define TX_AIRGO_TMR_SIGNATURE 0xDEADBEEF + +#ifdef TIMER_MANAGER +#define tx_timer_create(a, b, c, d, e, f, g, h) tx_timer_create_intern_debug((void *)a, b, c, d, e, f, g, h, __FILE__, __LINE__) +#else +#define tx_timer_create(a, b, c, d, e, f, g, h) tx_timer_create_intern((void *)a, b, c, d, e, f, g, h) +#endif + +/*--------------------------------------------------------------------*/ +/* Timer structure */ +/* This structure is used to implement ThreadX timer facility. Just */ +/* like ThreadX, timer expiration handler executes at the highest */ +/* possible priority level, i.e. DISPATCH_LEVEL. */ +/*--------------------------------------------------------------------*/ +typedef struct TX_TIMER_STRUCT { +#ifdef WLAN_DEBUG +#define TIMER_MAX_NAME_LEN 50 + char timerName[TIMER_MAX_NAME_LEN]; +#endif + uint8_t sessionId; + uint32_t expireInput; + uint64_t tmrSignature; + void (*pExpireFunc)(void *, uint32_t); + uint64_t initScheduleTimeInMsecs; + uint64_t rescheduleTimeInMsecs; + qdf_mc_timer_t qdf_timer; + + /* Pointer to the MAC global structure, which stores the context for the NIC, */ + /* for which this timer is supposed to operate. */ + void *mac; + +} TX_TIMER; + +#define TX_TIMER_VALID(timer) (timer.mac != 0) + +uint32_t tx_timer_activate(TX_TIMER *); +uint32_t tx_timer_change(TX_TIMER *, uint64_t, uint64_t); +uint32_t tx_timer_change_context(TX_TIMER *, uint32_t); +#ifdef TIMER_MANAGER +uint32_t tx_timer_create_intern_debug(void *, TX_TIMER *, + char *, void (*)(void *, + uint32_t), + uint32_t, uint64_t, + uint64_t, uint64_t, + char *fileName, + uint32_t lineNum); +#else +uint32_t tx_timer_create_intern(void *, TX_TIMER *, char *, + void (*)(void *, uint32_t), + uint32_t, uint64_t, uint64_t, + uint64_t); +#endif +uint32_t tx_timer_deactivate(TX_TIMER *); +uint32_t tx_timer_delete(TX_TIMER *); +bool tx_timer_running(TX_TIMER *); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c new file mode 100644 index 0000000000..c2b6fc7620 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c @@ -0,0 +1,458 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=========================================================================== + @file VossWrapper.c + + @brief This source file contains the various function definitions for the + RTOS abstraction layer, implemented for VOSS + ===========================================================================*/ + +/*=========================================================================== + + EDIT HISTORY FOR FILE + + This section contains comments describing changes made to the module. + Notice that changes are listed in reverse chronological order. + + $Header:$ $DateTime: $ $Author: $ + + when who what, where, why + -------- --- -------------------------------------------------------- + 03/31/09 sho Remove the use of qdf_timerIsActive flag as it is not + thread-safe + 02/17/08 sho Fix the timer callback function to work when it is called + after the timer has stopped due to a race condition. + 02/10/08 sho Refactor the TX timer to use VOS timer directly instead + of using VOS utility timer + 12/15/08 sho Resolved errors and warnings from the AMSS compiler when + this is ported from WM + 11/20/08 sho Renamed this to VosWrapper.c; remove all dependencies on + WM platform and allow this to work on all VOSS enabled + platform + 06/24/08 tbh Modified the file to remove the dependency on HDD files as + part of Gen6 bring up process. + 10/29/02 Neelay Das Created file. + + ===========================================================================*/ + +/*--------------------------------------------------------------------------- + * Include Files + * ------------------------------------------------------------------------*/ +#include "sys_wrapper.h" + +#ifdef WLAN_DEBUG +#define TIMER_NAME (timer_ptr->timerName) +#else +#define TIMER_NAME "N/A" +#endif + +/**--------------------------------------------------------------------- + * tx_timer_activate() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_activate(TX_TIMER *timer_ptr) +{ + QDF_STATUS status; + + /* Uncomment the asserts, if the intention is to debug the occurrence of the */ + /* following anomalous cnditions. */ + + /* Assert that the timer structure pointer passed, is not NULL */ + /* dbgAssert(timer_ptr); */ + + /* If the NIC is halting just spoof a successful timer activation, so that all */ + /* the timers can be cleaned up. */ + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + QDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + + } + /* Check for an uninitialized timer */ + QDF_ASSERT(0 != strlen(TIMER_NAME)); + + status = qdf_mc_timer_start(&timer_ptr->qdf_timer, + timer_ptr->initScheduleTimeInMsecs); + + if (QDF_STATUS_SUCCESS == status) { + return TX_SUCCESS; + } else if (QDF_STATUS_E_ALREADY == status) { + /* starting timer fails because timer is already started; this is okay */ + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG, + "Timer %s is already running\n", TIMER_NAME); + return TX_SUCCESS; + } else { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Timer %s fails to activate\n", TIMER_NAME); + return TX_TIMER_ERROR; + } +} /*** tx_timer_activate() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_change() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_change(TX_TIMER *timer_ptr, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + QDF_ASSERT(timer_ptr->tmrSignature == 0); + return TX_TIMER_ERROR; + } + /* changes cannot be applied until timer stops running */ + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&timer_ptr->qdf_timer)) { + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + return TX_SUCCESS; + } else { + return TX_TIMER_ERROR; + } +} /*** tx_timer_change() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_change_context() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_change_context(TX_TIMER *timer_ptr, + uint32_t expiration_input) +{ + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + QDF_ASSERT(timer_ptr->tmrSignature == 0); + + return TX_TIMER_ERROR; + } + /* changes cannot be applied until timer stops running */ + if (QDF_TIMER_STATE_STOPPED == + qdf_mc_timer_get_current_state(&timer_ptr->qdf_timer)) { + timer_ptr->expireInput = expiration_input; + return TX_SUCCESS; + } else { + return TX_TIMER_ERROR; + } +} /*** tx_timer_change() ***/ + +/**--------------------------------------------------------------------- + * tx_main_timer_func() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return None. + * + */ +static void tx_main_timer_func(void *functionContext) +{ + TX_TIMER *timer_ptr = (TX_TIMER *) functionContext; + + if (!timer_ptr) { + QDF_ASSERT(0); + return; + } + + if (!timer_ptr->pExpireFunc) { + QDF_ASSERT(0); + return; + } + + /* Now call the actual timer function, taking the function pointer, */ + /* from the timer structure. */ + (*timer_ptr->pExpireFunc)(timer_ptr->mac, timer_ptr->expireInput); + + /* check if this needs to be rescheduled */ + if (0 != timer_ptr->rescheduleTimeInMsecs) { + QDF_STATUS status; + + status = qdf_mc_timer_start(&timer_ptr->qdf_timer, + timer_ptr->rescheduleTimeInMsecs); + timer_ptr->rescheduleTimeInMsecs = 0; + + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_WARN, + "Unable to reschedule timer %s; status=%d", + TIMER_NAME, status); + } + } +} /*** tx_timer_change() ***/ + +#ifdef TIMER_MANAGER +uint32_t tx_timer_create_intern_debug(void *pMacGlobal, + TX_TIMER *timer_ptr, char *name_ptr, + void (*expiration_function)(void *, + uint32_t), + uint32_t expiration_input, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks, + uint64_t auto_activate, char *fileName, + uint32_t lineNum) +{ + QDF_STATUS status; + + if (!expiration_function) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL timer expiration"); + QDF_ASSERT(0); + return TX_TIMER_ERROR; + } + + if (!name_ptr) { + + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "NULL name pointer for timer"); + QDF_ASSERT(0); + return TX_TIMER_ERROR; + } + if (!initScheduleTimeInTicks) + return TX_TICK_ERROR; + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Initialize timer structure */ + timer_ptr->pExpireFunc = expiration_function; + timer_ptr->expireInput = expiration_input; + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + timer_ptr->mac = pMacGlobal; + + /* Set the flag indicating that the timer was created */ + timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE; + +#ifdef WLAN_DEBUG + /* Store the timer name */ + strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName)); +#endif /* Store the timer name, for Debug build only */ + + status = + qdf_mc_timer_init_debug(&timer_ptr->qdf_timer, QDF_TIMER_TYPE_SW, + tx_main_timer_func, (void *) timer_ptr, + fileName, lineNum); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Cannot create timer for %s\n", TIMER_NAME); + return TX_TIMER_ERROR; + } + + if (0 != rescheduleTimeInTicks) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_DEBUG, + "Creating periodic timer for %s\n", TIMER_NAME); + } + /* Activate this timer if required */ + if (auto_activate) { + tx_timer_activate(timer_ptr); + } + + return TX_SUCCESS; + +} /* ** tx_timer_create() *** / */ +#else +uint32_t tx_timer_create_intern(void *pMacGlobal, TX_TIMER *timer_ptr, + char *name_ptr, + void (*expiration_function)(void *, + uint32_t), + uint32_t expiration_input, + uint64_t initScheduleTimeInTicks, + uint64_t rescheduleTimeInTicks, + uint64_t auto_activate) +{ + QDF_STATUS status; + + if ((!name_ptr) || (!expiration_function)) + return TX_TIMER_ERROR; + + if (!initScheduleTimeInTicks) + return TX_TICK_ERROR; + + if (!timer_ptr) + return TX_TIMER_ERROR; + + /* Initialize timer structure */ + timer_ptr->pExpireFunc = expiration_function; + timer_ptr->expireInput = expiration_input; + timer_ptr->initScheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * initScheduleTimeInTicks; + timer_ptr->rescheduleTimeInMsecs = + TX_MSECS_IN_1_TICK * rescheduleTimeInTicks; + timer_ptr->mac = pMacGlobal; + + /* Set the flag indicating that the timer was created */ + timer_ptr->tmrSignature = TX_AIRGO_TMR_SIGNATURE; + +#ifdef WLAN_DEBUG + /* Store the timer name */ + strlcpy(timer_ptr->timerName, name_ptr, sizeof(timer_ptr->timerName)); +#endif /* Store the timer name, for Debug build only */ + + status = qdf_mc_timer_init(&timer_ptr->qdf_timer, QDF_TIMER_TYPE_SW, + tx_main_timer_func, (void *) timer_ptr); + if (QDF_STATUS_SUCCESS != status) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_ERROR, + "Cannot create timer for %s\n", TIMER_NAME); + return TX_TIMER_ERROR; + } + + if (0 != rescheduleTimeInTicks) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO, + "Creating periodic timer for %s\n", TIMER_NAME); + } + /* Activate this timer if required */ + if (auto_activate) { + tx_timer_activate(timer_ptr); + } + + return TX_SUCCESS; + +} /* ** tx_timer_create() *** / */ +#endif + +/**--------------------------------------------------------------------- + * tx_timer_deactivate() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +uint32_t tx_timer_deactivate(TX_TIMER *timer_ptr) +{ + QDF_STATUS vStatus; + + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + return TX_TIMER_ERROR; + } + /* if the timer is not running then we do not need to do anything here */ + vStatus = qdf_mc_timer_stop(&timer_ptr->qdf_timer); + if (QDF_STATUS_SUCCESS != vStatus) { + QDF_TRACE(QDF_MODULE_ID_SYS, QDF_TRACE_LEVEL_INFO_HIGH, + "Unable to stop timer %s; status =%d\n", + TIMER_NAME, vStatus); + } + + return TX_SUCCESS; + +} /*** tx_timer_deactivate() ***/ + +uint32_t tx_timer_delete(TX_TIMER *timer_ptr) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) { + return TX_TIMER_ERROR; + } + + qdf_mc_timer_destroy(&timer_ptr->qdf_timer); + timer_ptr->tmrSignature = 0; + + return TX_SUCCESS; +} /*** tx_timer_delete() ***/ + +/**--------------------------------------------------------------------- + * tx_timer_running() + * + * FUNCTION: + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param + * + * @return TX_SUCCESS. + * + */ +bool tx_timer_running(TX_TIMER *timer_ptr) +{ + /* Put a check for the free builds */ + if (TX_AIRGO_TMR_SIGNATURE != timer_ptr->tmrSignature) + return false; + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&timer_ptr->qdf_timer)) { + return true; + } + return false; + +} /*** tx_timer_running() ***/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h new file mode 100644 index 0000000000..640b25031f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_def.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2011-2014, 2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sys_def.h contains the common definitions used to bring up + * Sirius system. + * Author: V. K. Kandarpa + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ + +#ifndef __SYSDEF_H +#define __SYSDEF_H + +/* / Sirius system level definitions */ +/* NOTE: Do not program system timer tick duration to less than 1msec */ + +/* / System timer tick duration in nanoseconds */ +#define SYS_TICK_DUR_NS 10000000 /* 10ms */ +#define SYS_TICK_TO_MICRO_SECOND 10000 + +/* / System timer tick duration in milliseconds */ +#define SYS_TICK_DUR_MS (SYS_TICK_DUR_NS/1000000) + +/* / Macro to convert MS to Ticks */ +#define SYS_MS_TO_TICKS(x) ((x) / SYS_TICK_DUR_MS) + +/* / MS to Time Units */ +#define SYS_MS_TO_TU(x) ((x * 1000) >> 10) + +/* / TU to MS */ +#define SYS_TU_TO_MS(x) ((x << 10) / 1000) + +#endif /* __SYSDEF_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h new file mode 100644 index 0000000000..c3df87973c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_entry_func.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011-2012, 2014, 2017-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file sys_entry_func.h contains module entry functions definitions + * Author: V. K. Kandarpa + * Date: 04/13/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + */ +#ifndef __SYS_ENTRY_FUNC_H +#define __SYS_ENTRY_FUNC_H + +#include "ani_global.h" + +QDF_STATUS sys_init_globals(struct mac_context *mac); + +#endif /* __SYS_ENTRY_FUNC_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h new file mode 100644 index 0000000000..e587b384fc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/inc/sys_startup.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011-2014, 2017-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * sys_startup.h: System startup header file. + * Author: V. K. Kandarpa + * Date: 01/29/2002 + * + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ + +#ifndef __SYSSTARTUP_H +#define __SYSSTARTUP_H + +#include "sir_params.h" + +/* Defines */ + +/* Function */ + +/** + * sys_bbt_process_message_core() - to process BBT messages + * @mac_ctx: pointer to mac context + * @msg: message pointer + * @type: type of persona + * @subtype: subtype of persona + * + * This routine is to process some bbt messages + * + * Return: None + */ +QDF_STATUS sys_bbt_process_message_core(struct mac_context *mac_ctx, + struct scheduler_msg *msg, + uint32_t type, uint32_t subtype); + +#endif /* __SYSSTARTUP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c new file mode 100644 index 0000000000..9bb36df7f5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/mac_init_api.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * mac_init_api.c - This file has all the mac level init functions + * for all the defined threads at system level. + * Author: Dinesh Upadhyay + * Date: 04/23/2007 + * History:- + * Date: 04/08/2008 Modified by: Santosh Mandiganal + * Modification Information: Code to allocate and free the memory for DumpTable entry. + * -------------------------------------------------------------------------- + * + */ +/* Standard include files */ +#include "lim_api.h" /* lim_cleanup */ +#include "sir_types.h" +#include "sys_entry_func.h" +#include "mac_init_api.h" +#include "wlan_mlme_main.h" +#include "wlan_psoc_mlme_api.h" + +#ifdef TRACE_RECORD +#include "mac_trace.h" +#endif + +#ifdef WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +static struct mac_context *global_mac_context; + +static inline struct mac_context *mac_allocate_context_buffer(void) +{ + global_mac_context = qdf_mem_malloc(sizeof(*global_mac_context)); + + return global_mac_context; +} + +static inline void mac_free_context_buffer(void) +{ + qdf_mem_free(global_mac_context); + global_mac_context = NULL; +} +#else /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ +static struct mac_context global_mac_context; + +static inline struct mac_context *mac_allocate_context_buffer(void) +{ + return &global_mac_context; +} + +static inline void mac_free_context_buffer(void) +{ +} +#endif /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ + +QDF_STATUS mac_start(mac_handle_t mac_handle, + struct mac_start_params *params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac || !params) { + QDF_ASSERT(0); + status = QDF_STATUS_E_FAILURE; + return status; + } + + mac->gDriverType = params->driver_type; + + if (ANI_DRIVER_TYPE(mac) != QDF_DRIVER_TYPE_MFG) + status = pe_start(mac); + + return status; +} + +QDF_STATUS mac_stop(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + pe_stop(mac); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS mac_open(struct wlan_objmgr_psoc *psoc, mac_handle_t *mac_handle, + hdd_handle_t hdd_handle, struct cds_config_info *cds_cfg) +{ + struct mac_context *mac; + QDF_STATUS status; + struct wlan_mlme_psoc_ext_obj *mlme_ext_obj; + + QDF_BUG(mac_handle); + if (!mac_handle) + return QDF_STATUS_E_FAILURE; + + mac = mac_allocate_context_buffer(); + if (!mac) + return QDF_STATUS_E_NOMEM; + + /* + * Set various global fields of mac here + * (Could be platform dependent as some variables in mac are platform + * dependent) + */ + mac->hdd_handle = hdd_handle; + + status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_LEGACY_MAC_ID); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("PSOC get ref failure"); + goto free_mac_context; + } + + mac->psoc = psoc; + mlme_ext_obj = wlan_psoc_mlme_get_ext_hdl(psoc); + if (!mlme_ext_obj) { + pe_err("Failed to get MLME Obj"); + status = QDF_STATUS_E_FAILURE; + goto release_psoc_ref; + } + mac->mlme_cfg = &mlme_ext_obj->cfg; + + *mac_handle = MAC_HANDLE(mac); + + /* For Non-FTM cases this value will be reset during mac_start */ + if (cds_cfg->driver_type) + mac->gDriverType = QDF_DRIVER_TYPE_MFG; + + sys_init_globals(mac); + + /* FW: 0 to 2047 and Host: 2048 to 4095 */ + mac->mgmtSeqNum = WLAN_HOST_SEQ_NUM_MIN - 1; + mac->he_sgi_ltf_cfg_bit_mask = DEF_HE_AUTO_SGI_LTF; + mac->is_usr_cfg_amsdu_enabled = true; + + status = pe_open(mac, cds_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + QDF_DEBUG_PANIC("failed to open PE; status: %u", status); + goto release_psoc_ref; + } + + return QDF_STATUS_SUCCESS; + +release_psoc_ref: + wlan_objmgr_psoc_release_ref(psoc, WLAN_LEGACY_MAC_ID); + +free_mac_context: + mac_free_context_buffer(); + + return status; +} + +QDF_STATUS mac_close(mac_handle_t mac_handle) +{ + + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) + return QDF_STATUS_E_FAILURE; + + pe_close(mac); + + if (mac->pdev) { + wlan_objmgr_pdev_release_ref(mac->pdev, WLAN_LEGACY_MAC_ID); + mac->pdev = NULL; + } + wlan_objmgr_psoc_release_ref(mac->psoc, WLAN_LEGACY_MAC_ID); + mac->mlme_cfg = NULL; + mac->psoc = NULL; + qdf_mem_zero(mac, sizeof(*mac)); + mac_free_context_buffer(); + + return QDF_STATUS_SUCCESS; +} + +void mac_register_session_open_close_cb(mac_handle_t mac_handle, + csr_session_close_cb close_session, + csr_roam_complete_cb callback) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + mac->session_close_cb = close_session; + mac->session_roam_complete_cb = callback; +} + +#ifdef WLAN_BCN_RECV_FEATURE +void mac_register_bcn_report_send_cb(struct mac_context *mac, + beacon_report_cb cb) +{ + if (!mac) { + pe_err("Invalid MAC"); + return; + } + + mac->lim.sme_bcn_rcv_callback = cb; +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c new file mode 100644 index 0000000000..66870e8581 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/system/src/sys_entry_func.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2012-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * sys_entry_func.cc - This file has all the system level entry functions + * for all the defined threads at system level. + * Author: V. K. Kandarpa + * Date: 01/16/2002 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------------- + * + */ +/* Standard include files */ + +/* Application Specific include files */ +#include "sir_common.h" +#include "ani_global.h" + +#include "lim_api.h" +#include "sch_api.h" +#include "utils_api.h" + +#include "sys_def.h" +#include "sys_entry_func.h" +#include "sys_startup.h" +#include "lim_trace.h" +#include "wma_types.h" +#include "qdf_types.h" +#include "cds_packet.h" + +/** + * sys_init_globals + * + * FUNCTION: + * Initializes system level global parameters + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param struct mac_context *Sirius software parameter struct pointer + * @return None + */ + +QDF_STATUS sys_init_globals(struct mac_context *mac) +{ + + qdf_mem_zero((uint8_t *) &mac->sys, sizeof(mac->sys)); + + mac->sys.gSysEnableLinkMonitorMode = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sys_bbt_process_message_core(struct mac_context *mac_ctx, + struct scheduler_msg *msg, + uint32_t type, uint32_t subtype) +{ + uint32_t framecount; + QDF_STATUS ret; + void *bd_ptr; + tMgmtFrmDropReason dropreason; + cds_pkt_t *vos_pkt = (cds_pkt_t *) msg->bodyptr; + QDF_STATUS qdf_status = wma_ds_peek_rx_packet_info(vos_pkt, &bd_ptr); + + mac_ctx->sys.gSysBbtReceived++; + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + goto fail; + + mac_ctx->sys.gSysFrameCount[type][subtype]++; + framecount = mac_ctx->sys.gSysFrameCount[type][subtype]; + + if (type == SIR_MAC_MGMT_FRAME) { + tpSirMacMgmtHdr mac_hdr; + + /* + * Drop beacon frames in deferred state to avoid VOSS run out of + * message wrappers. + */ + if ((subtype == SIR_MAC_MGMT_BEACON) && + !GET_LIM_PROCESS_DEFD_MESGS(mac_ctx)) { + pe_debug("dropping received beacon in deferred state"); + goto fail; + } + + dropreason = lim_is_pkt_candidate_for_drop(mac_ctx, bd_ptr, + subtype); + if (eMGMT_DROP_NO_DROP != dropreason) { + pe_debug("Mgmt Frame %d being dropped, reason: %d\n", + subtype, dropreason); + MTRACE(mac_trace(mac_ctx, + TRACE_CODE_RX_MGMT_DROP, NO_SESSION, + dropreason)); + goto fail; + } + + mac_hdr = WMA_GET_RX_MAC_HEADER(bd_ptr); + if (subtype == SIR_MAC_MGMT_ASSOC_REQ) { + pe_debug("ASSOC REQ frame allowed: da: " QDF_MAC_ADDR_FMT ", sa: " QDF_MAC_ADDR_FMT ", bssid: " QDF_MAC_ADDR_FMT ", Assoc Req count so far: %d", + QDF_MAC_ADDR_REF(mac_hdr->da), + QDF_MAC_ADDR_REF(mac_hdr->sa), + QDF_MAC_ADDR_REF(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DEAUTH) { + pe_debug("DEAUTH frame allowed: da: " QDF_MAC_ADDR_FMT ", sa: " QDF_MAC_ADDR_FMT ", bssid: " QDF_MAC_ADDR_FMT ", DEAUTH count so far: %d", + QDF_MAC_ADDR_REF(mac_hdr->da), + QDF_MAC_ADDR_REF(mac_hdr->sa), + QDF_MAC_ADDR_REF(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + if (subtype == SIR_MAC_MGMT_DISASSOC) { + pe_debug("DISASSOC frame allowed: da: " QDF_MAC_ADDR_FMT ", sa: " QDF_MAC_ADDR_FMT ", bssid: " QDF_MAC_ADDR_FMT ", DISASSOC count so far: %d", + QDF_MAC_ADDR_REF(mac_hdr->da), + QDF_MAC_ADDR_REF(mac_hdr->sa), + QDF_MAC_ADDR_REF(mac_hdr->bssId), + mac_ctx->sys.gSysFrameCount[type][subtype]); + } + + /* Post the message to PE Queue */ + ret = lim_post_msg_api(mac_ctx, msg); + if (ret != QDF_STATUS_SUCCESS) { + pe_err("posting to LIM2 failed, ret %d\n", ret); + goto fail; + } + mac_ctx->sys.gSysBbtPostedToLim++; +#ifdef FEATURE_WLAN_ESE + } else if (type == SIR_MAC_DATA_FRAME) { + pe_debug("IAPP Frame..."); + /* Post the message to PE Queue */ + ret = lim_post_msg_api(mac_ctx, msg); + if (ret != QDF_STATUS_SUCCESS) { + pe_err("posting to LIM2 failed, ret: %d", ret); + goto fail; + } + mac_ctx->sys.gSysBbtPostedToLim++; +#endif + } else { + pe_debug("BBT received Invalid type: %d subtype: %d " + "LIM state %X", type, subtype, + lim_get_sme_state(mac_ctx)); + goto fail; + } + return QDF_STATUS_SUCCESS; +fail: + mac_ctx->sys.gSysBbtDropped++; + return QDF_STATUS_E_FAILURE; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h new file mode 100644 index 0000000000..2e38267cc3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/dot11fdefs.h @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2011-2012, 2014-2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 +#define DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 +/** + * \file dot11fdefs.h + * + * \brief C defines customizing our framesc-generated code + * + * + * + * + * 'framesc' generates code written in terms of a number of macros + * intended for customization. + * + * + */ + +#include "parser_api.h" + +/* This controls how the "dot11f" code copies memory */ +#define DOT11F_MEMCPY(ctx, dst, src, len) \ + qdf_mem_copy((uint8_t *)(dst), (uint8_t *)(src), (len)) + +/* This controls how the "dot11f" code compares memory */ +#define DOT11F_MEMCMP(ctx, lhs, rhs, len) \ + (qdf_mem_cmp((uint8_t *)(lhs), (uint8_t *)(rhs), (len))) + +#if defined(DBG) && (DBG != 0) + +# /* define DOT11F_ENABLE_LOGGING */ +# /* define DOT11F_DUMP_FRAMES */ +#define DOT11F_LOG_GATE (4) +#define FRAMES_SEV_FOR_FRAME(ctx, sig) \ + (DOT11F_ASSOCREQUEST == (sig) ? 3 : 5) + +#if defined(DOT11F_ENABLE_LOGGING) + +#define DOT11F_HAVE_LOG_MACROS + +#define FRAMES_LOG0(ctx, sev, fmt) \ + QDF_TRACE(QDF_MODULE_ID_PE, (sev), (fmt)); + +#define FRAMES_LOG1(ctx, sev, fmt, p1) \ + QDF_TRACE(QDF_MODULE_ID_PE, (sev), (fmt), (p1)); + +#define FRAMES_LOG2(ctx, sev, fmt, p1, p2) \ + QDF_TRACE(QDF_MODULE_ID_PE, (sev), (fmt), (p1), (p2)); + +#define FRAMES_LOG3(ctx, sev, fmt, p1, p2, p3) \ + QDF_TRACE(QDF_MODULE_ID_PE, (sev), (fmt), (p1), (p2), (p3)); + +#define FRAMES_DUMP(ctx, sev, p, n) \ + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, (sev), (p), (n); + +#endif /* #if defined( DOT11F_ENABLE_LOGGING ) */ + +#else + +#undef DOT11F_ENABLE_LOGGING +#undef DOT11F_DUMP_FRAMES +#define DOT11F_LOG_GATE (1) + +#endif + +/* #define DOT11F_ENABLE_DBG_BREAK ( 1 ) */ + +/* Local Variables: */ +/* fill-column: 72 */ +/* indent-tabs-mode: nil */ +/* show-trailing-whitespace: t */ +/* End: */ + +#endif /* DOT11FDEFS_H_82A7B72E_C36C_465D_82A7_139EA5322582 */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h new file mode 100644 index 0000000000..f9d55ab48d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/inc/utils_parser.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2011-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file utils_parser.h contains the utility function protos + * used internally by the parser + * Author: Chandra Modumudi + * Date: 02/11/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ +#ifndef __UTILS_PARSE_H__ +#define __UTILS_PARSE_H__ + +#include "qdf_types.h" +#include "sir_api.h" +#include "dot11f.h" +#include "utils_api.h" + +void convert_ssid(struct mac_context *, tSirMacSSid *, tDot11fIESSID *); +void convert_supp_rates(struct mac_context *, tSirMacRateSet *, tDot11fIESuppRates *); +void convert_fh_params(struct mac_context *, tSirMacFHParamSet *, + tDot11fIEFHParamSet *); +void convert_ext_supp_rates(struct mac_context *, tSirMacRateSet *, + tDot11fIEExtSuppRates *); +void convert_qos_caps(struct mac_context *, tSirMacQosCapabilityIE *, + tDot11fIEQOSCapsAp *); +void convert_qos_caps_station(struct mac_context *, tSirMacQosCapabilityStaIE *, + tDot11fIEQOSCapsStation *); +QDF_STATUS convert_wpa(struct mac_context *, tSirMacWpaInfo *, tDot11fIEWPA *); +QDF_STATUS convert_wpa_opaque(struct mac_context *, tSirMacWpaInfo *, + tDot11fIEWPAOpaque *); +QDF_STATUS convert_wapi_opaque(struct mac_context *, tSirMacWapiInfo *, + tDot11fIEWAPIOpaque *); +QDF_STATUS convert_rsn(struct mac_context *, tSirMacRsnInfo *, tDot11fIERSN *); +QDF_STATUS convert_rsn_opaque(struct mac_context *, tSirMacRsnInfo *, + tDot11fIERSNOpaque *); +void convert_power_caps(struct mac_context *, tSirMacPowerCapabilityIE *, + tDot11fIEPowerCaps *); +void convert_supp_channels(struct mac_context *, tSirMacSupportedChannelIE *, + tDot11fIESuppChannels *); +void convert_cf_params(struct mac_context *, tSirMacCfParamSet *, tDot11fIECFParams *); +void convert_tim(struct mac_context *, tSirMacTim *, tDot11fIETIM *); +void convert_country(struct mac_context *, tSirCountryInformation *, + tDot11fIECountry *); +void convert_wmm_params(struct mac_context *, tSirMacEdcaParamSetIE *, + tDot11fIEWMMParams *); +void convert_erp_info(struct mac_context *, tSirMacErpInfo *, tDot11fIEERPInfo *); +void convert_edca_param(struct mac_context *, tSirMacEdcaParamSetIE *, + tDot11fIEEDCAParamSet *); +void convert_mu_edca_param(struct mac_context * mac_ctx, + tSirMacEdcaParamSetIE *mu_edca, + tDot11fIEmu_edca_param_set *ie); +void convert_tspec(struct mac_context *, struct mac_tspec_ie *, + tDot11fIETSPEC *); +QDF_STATUS convert_tclas(struct mac_context *, tSirTclasInfo *, + tDot11fIETCLAS *); +void convert_wmmtspec(struct mac_context *, struct mac_tspec_ie *, + tDot11fIEWMMTSPEC *); +QDF_STATUS convert_wmmtclas(struct mac_context *, tSirTclasInfo *, + tDot11fIEWMMTCLAS *); +void convert_ts_delay(struct mac_context *, tSirMacTsDelayIE *, tDot11fIETSDelay *); +void convert_schedule(struct mac_context *, tSirMacScheduleIE *, tDot11fIESchedule *); +void convert_wmm_schedule(struct mac_context *, tSirMacScheduleIE *, + tDot11fIEWMMSchedule *); +QDF_STATUS convert_wsc_opaque(struct mac_context *, tSirAddie *, + tDot11fIEWscIEOpaque *); +QDF_STATUS convert_p2p_opaque(struct mac_context *, tSirAddie *, + tDot11fIEP2PIEOpaque *); +#ifdef WLAN_FEATURE_WFD +QDF_STATUS convert_wfd_opaque(struct mac_context *, tSirAddie *, + tDot11fIEWFDIEOpaque *); +#endif +void convert_qos_mapset_frame(struct mac_context *, struct qos_map_set *, + tDot11fIEQosMapSet *); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c new file mode 100644 index 0000000000..7193fc681e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/dot11f.c @@ -0,0 +1,35055 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * \file dot11f.c + * + * \brief Structures, functions & definitions for + * working with 802.11 Frames + * + * + * This file was automatically generated by 'framesc' + * Fri Nov 10 10:07:33 2023 from the following file(s): + * + * dot11f.frms + * + * PLEASE DON'T EDIT THIS FILE BY HAND! + * + */ + +#if !defined ANI_OS_TYPE_OSX && !defined ANI_OS_TYPE_LINUX && !defined ANI_OS_TYPE_ANDROID +#include /* For memcpy */ +#include /* For _vsnprintf */ +#include /* For offsetof */ +#endif + +#include +#include +#include "dot11fdefs.h" +#include "dot11f.h" + +#if defined(_MSC_VER) +#pragma warning (disable:4244) +#pragma warning (disable:4505) +#pragma warning (disable:4702) +#pragma warning (disable:4996)/* ... was declared deprecated */ +#endif /* Microsoft C/C++ */ + +typedef unsigned char tFRAMES_BOOL; +typedef void (*pfnGeneric_t)(void); + +typedef struct sFFDefn { + const char *name; + uint32_t offset; + uint16_t sig; + uint8_t size; +} tFFDefn; + +typedef struct sIEDefn { + uint32_t offset; + uint32_t presenceOffset; + uint32_t countOffset; + const char *name; + uint16_t arraybound; + uint16_t minSize; + uint16_t maxSize; + uint16_t sig; + unsigned char oui[5]; + unsigned char noui; + uint8_t eid; + uint8_t extn_eid; + tFRAMES_BOOL fMandatory; +} tIEDefn; + +#if !defined(countof) +#define countof(x) (sizeof((x)) / sizeof((x)[0])) +#endif + +#if !defined(DOT11F_MEMCPY) +#define DOT11F_MEMCPY(ctx, dst, src, len) \ + memcpy((dst), (src), (len)) +#endif + +#if !defined(DOT11F_MEMCMP) +#define DOT11F_MEMCMP(ctx, lhs, rhs, len) \ + memcmp((lhs), (rhs), (len)) +#endif + +#ifndef DOT11F_HAVE_LOG_SEVERITIES +#define FRLOG_OFF (0) +#define FRLOGP (1) +#define FRLOGE (2) +#define FRLOGW (3) +#define FRLOG1 (4) +#define FRLOG2 (5) +#define FRLOG3 (6) +#define FRLOG4 (7) +#endif + +#define FRFL(x) x + +#define FRAMES_LOG0(ctx, sev, fmt) +#define FRAMES_LOG1(ctx, sev, fmt, p1) +#define FRAMES_LOG2(ctx, sev, fmt, p1, p2) +#define FRAMES_LOG3(ctx, sev, fmt, p1, p2, p3) +#define FRAMES_LOG4(ctx, sev, fmt, p1, p2, p3, p4) +#define FRAMES_DUMP(ctx, sev, p, n) +#ifndef FRAMES_SEV_FOR_FRAME +#define FRAMES_SEV_FOR_FRAME(ctx, sig) FRLOG3 +#endif + +#if defined(DOT11F_ENABLE_DBG_BREAK) && defined (WIN32) +#define FRAMES_DBG_BREAK() { _asm int 3 } +#else +#define FRAMES_DBG_BREAK() +#endif + +#if !defined(DOT11F_PARAMETER_CHECK) +#if defined (DOT11F_HAVE_WIN32_API) + +#define DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm) \ + do { \ + if (!pBuf || IsBadReadPtr(pBuf, nBuf))\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pFrm || IsBadWritePtr(pFrm, nFrm))\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + } while (0) + +#define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ + do { \ + if (!pSrc || IsBadReadPtr(pSrc, 4))\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pBuf || IsBadWritePtr(pBuf, nBuf))\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!nBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (IsBadWritePtr(pnConsumed, 4))\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + } while (0) + +#else + +#define DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm) \ + if (!pBuf)\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pFrm)\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#define DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed) \ + if (!pSrc)\ + return DOT11F_BAD_INPUT_BUFFER; \ + if (!pBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!nBuf)\ + return DOT11F_BAD_OUTPUT_BUFFER; \ + if (!pnConsumed)\ + return DOT11F_BAD_OUTPUT_BUFFER \ + +#endif +#endif + +static void framesntohs(tpAniSirGlobal pCtx, + uint16_t *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) + DOT11F_MEMCPY(pCtx, (uint16_t *)pOut, pIn, 2); + else + *pOut = (uint16_t)(*pIn << 8) | *(pIn + 1); +#else + if (!fMsb) + *pOut = (uint16_t)(*pIn | (*(pIn + 1) << 8)); + else + DOT11F_MEMCPY(pCtx, (uint16_t *)pOut, pIn, 2); +#endif +} + +static void framesntohl(tpAniSirGlobal pCtx, + uint32_t *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) + DOT11F_MEMCPY(pCtx, (uint32_t *)pOut, pIn, 4); + else + *pOut = (uint32_t)(*pIn << 24) | + (*(pIn + 1) << 16) | + (*(pIn + 2) << 8) | + (*(pIn + 3)); +#else + if (!fMsb) + *pOut = (uint32_t)(*(pIn + 3) << 24) | + (*(pIn + 2) << 16) | + (*(pIn + 1) << 8) | + (*(pIn)); +else + *pOut = *(uint32_t *)pIn; +#endif +} + +static void framesntohq(tpAniSirGlobal pCtx, + tDOT11F_U64 *pOut, + uint8_t *pIn, + tFRAMES_BOOL fMsb) +{ +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + framesntohl(pCtx, &((*pOut)[0]), pIn, fMsb); + framesntohl(pCtx, &((*pOut)[1]), pIn + 4, fMsb); +#else + framesntohl(pCtx, &((*pOut)[1]), pIn, fMsb); + framesntohl(pCtx, &((*pOut)[0]), pIn + 4, fMsb); +#endif +} + +static void frameshtons(tpAniSirGlobal pCtx, + uint8_t *pOut, + uint16_t pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 2); + } else { + *pOut = (pIn & 0xff00) >> 8; + *(pOut + 1) = pIn & 0xff; + } +#else + if (!fMsb) { + *pOut = pIn & 0xff; + *(pOut + 1) = (pIn & 0xff00) >> 8; + } else { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 2); + } +#endif +} + +static void frameshtonl(tpAniSirGlobal pCtx, + uint8_t *pOut, + uint32_t pIn, + tFRAMES_BOOL fMsb) +{ + (void)pCtx; +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + if (!fMsb) { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 4); + } else { + *pOut = (pIn & 0xff000000) >> 24; + *(pOut + 1) = (pIn & 0x00ff0000) >> 16; + *(pOut + 2) = (pIn & 0x0000ff00) >> 8; + *(pOut + 3) = (pIn & 0x000000ff); + } +#else + if (!fMsb) { + *pOut = (pIn & 0x000000ff); + *(pOut + 1) = (pIn & 0x0000ff00) >> 8; + *(pOut + 2) = (pIn & 0x00ff0000) >> 16; + *(pOut + 3) = (pIn & 0xff000000) >> 24; + } else { + DOT11F_MEMCPY(pCtx, pOut, &pIn, 4); + } +#endif +} + +static void frameshtonq(tpAniSirGlobal pCtx, + uint8_t *pOut, + tDOT11F_U64 pIn, + tFRAMES_BOOL fMsb) +{ +#if defined (DOT11F_LITTLE_ENDIAN_HOST) + frameshtonl(pCtx, pOut, pIn[0], fMsb); + frameshtonl(pCtx, pOut + 4, pIn[1], fMsb); +#else + frameshtonl(pCtx, pOut + 4, pIn[1], fMsb); + frameshtonl(pCtx, pOut, pIn[0], fMsb); +#endif +} + +static const tIEDefn *find_ie_defn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe; + (void)pCtx; + + pIe = &(IEs[0]); + while (0xff != pIe->eid || pIe->extn_eid) { + if (*pBuf == pIe->eid) { + if (pIe->eid == 0xff) { + if ((nBuf > 2) && + (*(pBuf + 2)) == pIe->extn_eid) + return pIe; + } else { + if (0 == pIe->noui) + return pIe; + + if ((nBuf > (uint32_t)(pIe->noui + 2)) && + (!DOT11F_MEMCMP(pCtx, pBuf + 2, pIe->oui, + pIe->noui))) + return pIe; + } + } + + ++pIe; + } + + return NULL; +} + +static uint32_t get_container_ies_len(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + uint8_t *pnConsumed, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe, *pIeFirst; + uint8_t *pBufRemaining = pBuf; + uint32_t len = 0; + (void)pCtx; + + pIeFirst = &(IEs[0]); + + if (*pBufRemaining != pIeFirst->eid) + return DOT11F_INTERNAL_ERROR; + len += *(pBufRemaining+1); + pBufRemaining += len + 2; + len += 2; + while (len + 1 < nBuf) { + pIe = find_ie_defn(pCtx, pBufRemaining, nBuf - len, IEs); + if (NULL == pIe) + break; + if (pIe->eid == pIeFirst->eid) + break; + len += *(pBufRemaining + 1) + 2; + pBufRemaining += *(pBufRemaining + 1) + 2; + } + + if ((len > 0xFF) || (len > nBuf)) + return DOT11F_INTERNAL_ERROR; + *pnConsumed = len; + return DOT11F_PARSE_SUCCESS; + +} + + +static uint32_t unpack_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tFFDefn FFs[], + const tIEDefn IEs[], + uint8_t *pFrm, + size_t nFrm, + bool append_ie); +static uint32_t pack_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tFFDefn FFs[], + const tIEDefn IEs[]); +static uint32_t get_packed_size_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tIEDefn IEs[]); + +static uint32_t dot11f_unpack_tlv_common_func(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint16_t tlvlen, + uint8_t *pDstPresent, uint8_t *pDstField) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)tlvlen; /* Shutup the compiler */ + + *pDstPresent = 1; + *pDstField = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_common_func. */ + +static uint32_t dot11f_unpack_tlv_common_func2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint16_t tlvlen, + uint8_t *pDstPresent, uint16_t *pDstState) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)tlvlen; /* Shutup the compiler */ + + *pDstPresent = 1; + framesntohs(pCtx, pDstState, pBuf, 1); + (void)pCtx; + return status; + +} /* End dot11f_unpack_tlv_common_func2. */ + +static void dot11f_unpack_ff_common_func(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint16_t *pDstField) +{ + framesntohs(pCtx, pDstField, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_common_func. */ + +static uint32_t dot11f_unpack_ie_common_func(tpAniSirGlobal pCtx, uint8_t *pBuf, + uint8_t ielen, uint8_t *pDstPresent, + uint8_t *pDstField) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)ielen; + (void)pBuf; + if ((*pDstPresent)) + status = DOT11F_DUPLICATE_IE; + *pDstPresent = 1; + *pDstField = *pBuf; + (void)pCtx; + + return status; +} /* End dot11f_unpack_ie_common_func */ + +typedef struct sTLVDefn { + uint32_t offset; + uint32_t presenceOffset; + const char *name; + uint16_t sig; + uint32_t id; + uint32_t pec; + uint32_t minSize; + uint32_t maxSize; + uint8_t fMandatory; + uint8_t sType; + uint8_t sLen; + uint8_t fMsb; +} tTLVDefn; + +static const tTLVDefn *find_tlv_defn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[]) +{ + const tTLVDefn *pTlv; + uint32_t pec; + uint16_t id; + + pTlv = &(TLVs[0]); + (void)pCtx; + if (pTlv->sType == 2) + framesntohs(pCtx, &id, pBuf, 1); + else + id = *pBuf; + + while (0xffff != pTlv->id) { + if (id == pTlv->id) { + if (0 == pTlv->pec) + return pTlv; + + if (nBuf > 5) { + pec = ((*(pBuf + 4)) << 16) | + ((*(pBuf + 5)) << 8) | + *(pBuf + 6); + if (pec == pTlv->pec) + return pTlv; + } + } + + ++pTlv; + } + + return NULL; +} + +static uint32_t unpack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[], + uint8_t *pFrm, + size_t nFrm); +static uint32_t pack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tTLVDefn TLVs[], + uint32_t *pidx); +static uint32_t get_packed_size_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tTLVDefn TLVs[]); + +#define SigFfAID (0x0001) + +void dot11f_unpack_ff_action(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfAction *pDst) +{ + pDst->action = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_action. */ + +#define SigFfAction (0x0002) + +#define SigFfAuthAlgo (0x0003) + +#define SigFfAuthSeqNo (0x0004) + +#define SigFfBeaconInterval (0x0005) + +void dot11f_unpack_ff_capabilities(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCapabilities *pDst) +{ + uint16_t tmp0__; + framesntohs(pCtx, &tmp0__, pBuf, 0); + pDst->ess = tmp0__ >> 0 & 0x1; + pDst->ibss = tmp0__ >> 1 & 0x1; + pDst->cfPollable = tmp0__ >> 2 & 0x1; + pDst->cfPollReq = tmp0__ >> 3 & 0x1; + pDst->privacy = tmp0__ >> 4 & 0x1; + pDst->shortPreamble = tmp0__ >> 5 & 0x1; + pDst->criticalUpdateFlag = tmp0__ >> 6 & 0x1; + pDst->channelAgility = tmp0__ >> 7 & 0x1; + pDst->spectrumMgt = tmp0__ >> 8 & 0x1; + pDst->qos = tmp0__ >> 9 & 0x1; + pDst->shortSlotTime = tmp0__ >> 10 & 0x1; + pDst->apsd = tmp0__ >> 11 & 0x1; + pDst->rrm = tmp0__ >> 12 & 0x1; + pDst->dsssOfdm = tmp0__ >> 13 & 0x1; + pDst->delayedBA = tmp0__ >> 14 & 0x1; + pDst->immediateBA = tmp0__ >> 15 & 0x1; + (void)pCtx; +} /* End dot11f_unpack_ff_capabilities. */ + +#define SigFfCapabilities (0x0006) + +void dot11f_unpack_ff_category(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCategory *pDst) +{ + pDst->category = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_category. */ + +#define SigFfCategory (0x0007) + +void dot11f_unpack_ff_current_ap_address(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfCurrentAPAddress *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + (void)pCtx; +} /* End dot11f_unpack_ff_current_ap_address. */ + +#define SigFfCurrentAPAddress (0x0008) + +void dot11f_unpack_ff_dialog_token(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfDialogToken *pDst) +{ + pDst->token = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_dialog_token. */ + +#define SigFfDialogToken (0x0009) + +void dot11f_unpack_ff_link_margin(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfLinkMargin *pDst) +{ + pDst->linkMargin = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_link_margin. */ + +#define SigFfLinkMargin (0x000a) + +#define SigFfListenInterval (0x000b) + +void dot11f_unpack_ff_max_tx_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfMaxTxPower *pDst) +{ + pDst->maxTxPower = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_max_tx_power. */ + +#define SigFfMaxTxPower (0x000c) + +void dot11f_unpack_ff_num_of_repetitions(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfNumOfRepetitions *pDst) +{ + framesntohs(pCtx, &pDst->repetitions, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_num_of_repetitions. */ + +#define SigFfNumOfRepetitions (0x000d) + +void dot11f_unpack_ff_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfOperatingMode *pDst) +{ + uint8_t tmp1__; + tmp1__ = *pBuf; + pDst->chanWidth = tmp1__ >> 0 & 0x3; + pDst->reserved = tmp1__ >> 2 & 0x3; + pDst->rxNSS = tmp1__ >> 4 & 0x7; + pDst->rxNSSType = tmp1__ >> 7 & 0x1; + (void)pCtx; +} /* End dot11f_unpack_ff_operating_mode. */ + +#define SigFfOperatingMode (0x000e) + +void dot11f_unpack_ff_rcpi(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRCPI *pDst) +{ + pDst->rcpi = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rcpi. */ + +#define SigFfRCPI (0x000f) + +void dot11f_unpack_ff_rsni(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRSNI *pDst) +{ + pDst->rsni = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rsni. */ + +#define SigFfRSNI (0x0010) + +#define SigFfReason (0x0011) + +void dot11f_unpack_ff_rx_antenna_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfRxAntennaId *pDst) +{ + pDst->antennaId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_rx_antenna_id. */ + +#define SigFfRxAntennaId (0x0012) + +void dot11f_unpack_ff_sm_power_mode_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfSMPowerModeSet *pDst) +{ + uint8_t tmp2__; + tmp2__ = *pBuf; + pDst->PowerSave_En = tmp2__ >> 0 & 0x1; + pDst->Mode = tmp2__ >> 1 & 0x1; + pDst->reserved = tmp2__ >> 2 & 0x3f; + (void)pCtx; +} /* End dot11f_unpack_ff_sm_power_mode_set. */ + +#define SigFfSMPowerModeSet (0x0013) + +#define SigFfStatus (0x0014) + +void dot11f_unpack_ff_status_code(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfStatusCode *pDst) +{ + pDst->statusCode = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_status_code. */ + +#define SigFfStatusCode (0x0015) + +void dot11f_unpack_ff_tpc_ele_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTPCEleID *pDst) +{ + pDst->TPCId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tpc_ele_id. */ + +#define SigFfTPCEleID (0x0016) + +void dot11f_unpack_ff_tpc_ele_len(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTPCEleLen *pDst) +{ + pDst->TPCLen = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tpc_ele_len. */ + +#define SigFfTPCEleLen (0x0017) + +void dot11f_unpack_ff_ts_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTSInfo *pDst) +{ + uint32_t tmp3__; + framesntohl(pCtx, &tmp3__, pBuf, 0); + pDst->traffic_type = tmp3__ >> 0 & 0x1; + pDst->tsid = tmp3__ >> 1 & 0xf; + pDst->direction = tmp3__ >> 5 & 0x3; + pDst->access_policy = tmp3__ >> 7 & 0x3; + pDst->aggregation = tmp3__ >> 9 & 0x1; + pDst->psb = tmp3__ >> 10 & 0x1; + pDst->user_priority = tmp3__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp3__ >> 14 & 0x3; + pDst->schedule = tmp3__ >> 16 & 0x1; + pDst->unused = tmp3__ >> 17 & 0x7fff; + (void)pCtx; +} /* End dot11f_unpack_ff_ts_info. */ + +#define SigFfTSInfo (0x0018) + +void dot11f_unpack_ff_time_stamp(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTimeStamp *pDst) +{ + framesntohq(pCtx, &pDst->timestamp, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_time_stamp. */ + +#define SigFfTimeStamp (0x0019) + +void dot11f_unpack_ff_transaction_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTransactionId *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->transId, pBuf, 2); + (void)pCtx; +} /* End dot11f_unpack_ff_transaction_id. */ + +#define SigFfTransactionId (0x001a) + +void dot11f_unpack_ff_tx_antenna_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTxAntennaId *pDst) +{ + pDst->antennaId = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tx_antenna_id. */ + +#define SigFfTxAntennaId (0x001b) + +void dot11f_unpack_ff_tx_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfTxPower *pDst) +{ + pDst->txPower = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_tx_power. */ + +#define SigFfTxPower (0x001c) + +void dot11f_unpack_ff_vht_membership_status_array(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfVhtMembershipStatusArray *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->membershipStatusArray, pBuf, 8); + (void)pCtx; +} /* End dot11f_unpack_ff_vht_membership_status_array. */ + +#define SigFfVhtMembershipStatusArray (0x001d) + +void dot11f_unpack_ff_vht_user_position_array(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfVhtUserPositionArray *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->userPositionArray, pBuf, 16); + (void)pCtx; +} /* End dot11f_unpack_ff_vht_user_position_array. */ + +#define SigFfVhtUserPositionArray (0x001e) + +void dot11f_unpack_ff_addba_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfaddba_param_set *pDst) +{ + uint16_t tmp4__; + framesntohs(pCtx, &tmp4__, pBuf, 0); + pDst->amsdu_supp = tmp4__ >> 0 & 0x1; + pDst->policy = tmp4__ >> 1 & 0x1; + pDst->tid = tmp4__ >> 2 & 0xf; + pDst->buff_size = tmp4__ >> 6 & 0x3ff; + (void)pCtx; +} /* End dot11f_unpack_ff_addba_param_set. */ + +#define SigFfaddba_param_set (0x001f) + +void dot11f_unpack_ff_ba_start_seq_ctrl(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfba_start_seq_ctrl *pDst) +{ + uint16_t tmp5__; + framesntohs(pCtx, &tmp5__, pBuf, 0); + pDst->frag_number = tmp5__ >> 0 & 0xf; + pDst->ssn = tmp5__ >> 4 & 0xfff; + (void)pCtx; +} /* End dot11f_unpack_ff_ba_start_seq_ctrl. */ + +#define SigFfba_start_seq_ctrl (0x0020) + +void dot11f_unpack_ff_ba_timeout(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfba_timeout *pDst) +{ + framesntohs(pCtx, &pDst->timeout, pBuf, 0); + (void)pCtx; +} /* End dot11f_unpack_ff_ba_timeout. */ + +#define SigFfba_timeout (0x0021) + +void dot11f_unpack_ff_delba_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfdelba_param_set *pDst) +{ + uint16_t tmp6__; + framesntohs(pCtx, &tmp6__, pBuf, 0); + pDst->reserved = tmp6__ >> 0 & 0x7ff; + pDst->initiator = tmp6__ >> 11 & 0x1; + pDst->tid = tmp6__ >> 12 & 0xf; + (void)pCtx; +} /* End dot11f_unpack_ff_delba_param_set. */ + +#define SigFfdelba_param_set (0x0022) + +void dot11f_unpack_ff_ext_chan_switch_ann_action(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfext_chan_switch_ann_action *pDst) +{ + uint32_t tmp7__; + framesntohl(pCtx, &tmp7__, pBuf, 0); + pDst->switch_mode = tmp7__ >> 0 & 0xff; + pDst->op_class = tmp7__ >> 8 & 0xff; + pDst->new_channel = tmp7__ >> 16 & 0xff; + pDst->switch_count = tmp7__ >> 24 & 0xff; + (void)pCtx; +} /* End dot11f_unpack_ff_ext_chan_switch_ann_action. */ + +#define SigFfext_chan_switch_ann_action (0x0023) + +void dot11f_unpack_ff_p2p_action_oui(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfp2p_action_oui *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->oui_data, pBuf, 4); + (void)pCtx; +} /* End dot11f_unpack_ff_p2p_action_oui. */ + +#define SigFfp2p_action_oui (0x0024) + +void dot11f_unpack_ff_p2p_action_subtype(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfp2p_action_subtype *pDst) +{ + pDst->subtype = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_p2p_action_subtype. */ + +#define SigFfp2p_action_subtype (0x0025) + +void dot11f_unpack_ff_vendor_action_subtype(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfvendor_action_subtype *pDst) +{ + pDst->subtype = *pBuf; + (void)pCtx; +} /* End dot11f_unpack_ff_vendor_action_subtype. */ + +#define SigFfvendor_action_subtype (0x0026) + +void dot11f_unpack_ff_vendor_oui(tpAniSirGlobal pCtx, + uint8_t *pBuf, + tDot11fFfvendor_oui *pDst) +{ + DOT11F_MEMCPY(pCtx, pDst->oui_data, pBuf, 3); + (void)pCtx; +} /* End dot11f_unpack_ff_vendor_oui. */ + +#define SigFfvendor_oui (0x0027) + +uint32_t dot11f_unpack_tlv_authorized_ma_cs(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVAuthorizedMACs *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->mac, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_authorized_ma_cs. */ + +#define SigTlvAuthorizedMACs (0x0001) + + +#define SigTlvRequestToEnroll (0x0002) + + +uint32_t dot11f_unpack_tlv_version2(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVersion2 *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp8__; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp8__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->minor = tmp8__ >> 0 & 0xf; + pDst->major = tmp8__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_version2. */ + +#define SigTlvVersion2 (0x0003) + + +#define SigTlvAPSetupLocked (0x0004) + + +#define SigTlvAssociationState (0x0005) + + +#define SigTlvConfigMethods (0x0006) + + +#define SigTlvConfigurationError (0x0007) + + +uint32_t dot11f_unpack_tlv_device_name(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVDeviceName *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_device_name. */ + +#define SigTlvDeviceName (0x0008) + + +#define SigTlvDevicePasswordID (0x0009) + + +uint32_t dot11f_unpack_tlv_extended_listen_timing(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVExtendedListenTiming *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->availibilityPeriod, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->availibilityInterval, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_extended_listen_timing. */ + +#define SigTlvExtendedListenTiming (0x000a) + + +uint32_t dot11f_unpack_tlv_listen_channel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVListenChannel *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->countryString, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->regulatoryClass = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->channel = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_listen_channel. */ + +#define SigTlvListenChannel (0x000b) + + +uint32_t dot11f_unpack_tlv_manufacturer(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVManufacturer *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_name = (uint8_t)(tlvlen); + if (tlvlen > 64) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->name, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_manufacturer. */ + +#define SigTlvManufacturer (0x000c) + + +#define SigTlvMinorReasonCode (0x000d) + + +uint32_t dot11f_unpack_tlv_model_name(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVModelName *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_model_name. */ + +#define SigTlvModelName (0x000e) + + +uint32_t dot11f_unpack_tlv_model_number(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVModelNumber *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_model_number. */ + +#define SigTlvModelNumber (0x000f) + + +uint32_t dot11f_unpack_tlv_notice_of_absence(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVNoticeOfAbsence *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->index = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->CTSWindowOppPS = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->num_NoADesc = (uint8_t)(tlvlen); + if (tlvlen > 36) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->NoADesc, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_notice_of_absence. */ + +#define SigTlvNoticeOfAbsence (0x0010) + + +uint32_t dot11f_unpack_tlv_operating_channel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVOperatingChannel *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->countryString, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->regulatoryClass = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->channel = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_operating_channel. */ + +#define SigTlvOperatingChannel (0x0011) + + +uint32_t dot11f_unpack_tlv_p2_p_capability(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PCapability *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->deviceCapability = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->groupCapability = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_capability. */ + +#define SigTlvP2PCapability (0x0012) + + +uint32_t dot11f_unpack_tlv_p2_p_device_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PDeviceId *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_device_id. */ + +#define SigTlvP2PDeviceId (0x0013) + + +static const tTLVDefn TLVS_P2PDeviceInfo[] = { + { offsetof(tDot11fTLVP2PDeviceInfo, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 1, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_tlv_p2_p_device_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PDeviceInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->configMethod, pBuf, 0); + pBuf += 2; + tlvlen -= (uint8_t)2; + if (unlikely(tlvlen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->primaryDeviceType, pBuf, 8); + pBuf += 8; + tlvlen -= (uint8_t)8; + (void)pCtx; + status |= unpack_tlv_core(pCtx, + pBuf, + tlvlen, + TLVS_P2PDeviceInfo, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_tlv_p2_p_device_info. */ + +#define SigTlvP2PDeviceInfo (0x0014) + + +uint32_t dot11f_unpack_tlv_p2_p_group_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PGroupInfo *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_P2PClientInfoDesc = (uint8_t)(tlvlen); + DOT11F_MEMCPY(pCtx, pDst->P2PClientInfoDesc, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_group_info. */ + +#define SigTlvP2PGroupInfo (0x0015) + + +#define SigTlvP2PStatus (0x0016) + + +uint32_t dot11f_unpack_tlv_primary_device_type(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVPrimaryDeviceType *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)tlvlen; /* Shutup the compiler */ + pDst->present = 1; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->primary_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + if (unlikely(tlvlen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 4); + pBuf += 4; + tlvlen -= (uint8_t)4; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->sub_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_primary_device_type. */ + +#define SigTlvPrimaryDeviceType (0x0017) + + +#define SigTlvRFBands (0x0018) + + +uint32_t dot11f_unpack_tlv_request_device_type(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVRequestDeviceType *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->primary_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + if (unlikely(tlvlen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->oui, pBuf, 4); + pBuf += 4; + tlvlen -= (uint8_t)4; + if (unlikely(tlvlen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->sub_category, pBuf, 1); + pBuf += 2; + tlvlen -= (uint8_t)2; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_request_device_type. */ + +#define SigTlvRequestDeviceType (0x0019) + + +#define SigTlvRequestType (0x001a) + + +#define SigTlvResponseType (0x001b) + + +#define SigTlvSelectedRegistrar (0x001c) + + +#define SigTlvSelectedRegistrarConfigMethods (0x001d) + + +uint32_t dot11f_unpack_tlv_serial_number(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVSerialNumber *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + pDst->num_text = (uint8_t)(tlvlen); + if (tlvlen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_serial_number. */ + +#define SigTlvSerialNumber (0x001e) + + +uint32_t dot11f_unpack_tlv_uuid_e(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVUUID_E *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->uuid, pBuf, 16); + pBuf += 16; + tlvlen -= (uint8_t)16; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_uuid_e. */ + +#define SigTlvUUID_E (0x001f) + + +uint32_t dot11f_unpack_tlv_uuid_r(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVUUID_R *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->uuid, pBuf, 16); + pBuf += 16; + tlvlen -= (uint8_t)16; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_uuid_r. */ + +#define SigTlvUUID_R (0x0020) + + +static const tTLVDefn TLVS_VendorExtension[] = { + { offsetof(tDot11fTLVVendorExtension, Version2), + offsetof(tDot11fTLVVersion2, present), "Version2", SigTlvVersion2, + DOT11F_TLV_VERSION2, 0, 3, 3, 0, 1, 1, 1, }, + { offsetof(tDot11fTLVVendorExtension, AuthorizedMACs), + offsetof(tDot11fTLVAuthorizedMACs, present), "AuthorizedMACs", + SigTlvAuthorizedMACs, DOT11F_TLV_AUTHORIZEDMACS, 0, 8, 8, 0, 1, 1, 1, }, + { offsetof(tDot11fTLVVendorExtension, RequestToEnroll), + offsetof(tDot11fTLVRequestToEnroll, present), "RequestToEnroll", + SigTlvRequestToEnroll, DOT11F_TLV_REQUESTTOENROLL, + 0, 3, 3, 0, 1, 1, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_tlv_vendor_extension(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVendorExtension *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->vendorId, pBuf, 3); + pBuf += 3; + tlvlen -= (uint8_t)3; + (void)pCtx; + status |= unpack_tlv_core(pCtx, + pBuf, + tlvlen, + TLVS_VendorExtension, + (uint8_t *)pDst, + sizeof(*pDst)); + return status; +} /* End dot11f_unpack_tlv_vendor_extension. */ + +#define SigTlvVendorExtension (0x0021) + + +uint32_t dot11f_unpack_tlv_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVVersion *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp9__; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp9__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->minor = tmp9__ >> 0 & 0xf; + pDst->major = tmp9__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_version. */ + +#define SigTlvVersion (0x0022) + + +#define SigTlvWPSState (0x0023) + + +#define SigTlvassoc_disallowed (0x0024) + + +#define SigTlvassoc_retry_delay (0x0025) + + +#define SigTlvcellular_data_cap (0x0026) + + +#define SigTlvcellular_data_con_pref (0x0027) + + +uint32_t dot11f_unpack_tlv_ecsa_target_tsf_info_attr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVecsa_target_tsf_info_attr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->twt_ch_sw_mode = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohq(pCtx, &pDst->target_tsf, pBuf, 0); + pBuf += 8; + tlvlen -= (uint8_t)8; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_ecsa_target_tsf_info_attr. */ + +#define SigTlvecsa_target_tsf_info_attr (0x0028) + + +uint32_t dot11f_unpack_tlv_edca_pifs_param_attr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVedca_pifs_param_attr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->edca_param_type = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->num_data = (uint8_t)(tlvlen); + if (tlvlen > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_edca_pifs_param_attr. */ + +#define SigTlvedca_pifs_param_attr (0x0029) + + +#define SigTlvhe_2xltf_160mhz_supp (0x002a) + + +uint32_t dot11f_unpack_tlv_he_400ns_sgi_attr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVhe_400ns_sgi_attr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->he_ltf1x_400ns_sgi = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->he_ltf2x_400ns_sgi = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->he_ltf4x_400ns_sgi = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_he_400ns_sgi_attr. */ + +#define SigTlvhe_400ns_sgi_attr (0x002b) + + +#define SigTlvhe_dl_mumimo_attr (0x002c) + + +#define SigTlvhe_dl_ofdma_attr (0x002d) + + +uint32_t dot11f_unpack_tlv_he_mcs13_attr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVhe_mcs13_attr *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->he_mcs_12_13_supp_80 = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->he_mcs_12_13_supp_160 = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_he_mcs13_attr. */ + +#define SigTlvhe_mcs13_attr (0x002e) + + +#define SigTlvmbo_ap_cap (0x002f) + + +uint32_t dot11f_unpack_tlv_non_prefferd_chan_rep(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVnon_prefferd_chan_rep *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->oper_class = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + pDst->num_channel_report = (uint8_t)(tlvlen); + if (tlvlen > 254) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channel_report, pBuf, (tlvlen)); + pBuf += (tlvlen); + tlvlen -= (tlvlen); + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_non_prefferd_chan_rep. */ + +#define SigTlvnon_prefferd_chan_rep (0x0030) + + +uint32_t dot11f_unpack_tlv_oce_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVoce_cap *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp10__; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp10__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->oce_release = tmp10__ >> 0 & 0x7; + pDst->is_sta_cfon = tmp10__ >> 3 & 0x1; + pDst->non_oce_ap_present = tmp10__ >> 4 & 0x1; + pDst->reserved = tmp10__ >> 5 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_oce_cap. */ + +#define SigTlvoce_cap (0x0031) + + +uint32_t dot11f_unpack_tlv_qcn_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVqcn_version *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->sub_version = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_qcn_version. */ + +#define SigTlvqcn_version (0x0032) + + +uint32_t dot11f_unpack_tlv_reduced_wan_metrics(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVreduced_wan_metrics *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp11__; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp11__ = *pBuf; + pBuf += 1; + tlvlen -= 1; + pDst->downlink_av_cap = tmp11__ >> 0 & 0xf; + pDst->uplink_av_cap = tmp11__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_reduced_wan_metrics. */ + +#define SigTlvreduced_wan_metrics (0x0033) + + +uint32_t dot11f_unpack_tlv_rssi_assoc_rej(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVrssi_assoc_rej *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->delta_rssi = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + if (unlikely(tlvlen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->retry_delay = *pBuf; + pBuf += 1; + tlvlen -= (uint8_t)1; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_rssi_assoc_rej. */ + +#define SigTlvrssi_assoc_rej (0x0034) + + +#define SigTlvtrans_reasonp_attr (0x0035) + + +#define SigTlvtrans_rejectp_attr (0x0036) + + +#define SigTlvtransition_reason (0x0037) + + +#define SigTlvtransition_reject_reason (0x0038) + + +#define SigTlvvht_mcs11_attr (0x0039) + + +uint32_t dot11f_unpack_tlv_p2_p_interface(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint16_t tlvlen, + tDot11fTLVP2PInterface *pDst) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + pDst->present = 1; + if (unlikely(tlvlen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->P2PDeviceAddress, pBuf, 6); + pBuf += 6; + tlvlen -= (uint8_t)6; + (void)pCtx; + return status; +} /* End dot11f_unpack_tlv_p2_p_interface. */ + +#define SigTlvP2PInterface (0x003a) + + +#define SigTlvP2PManageability (0x003b) + + +uint32_t dot11f_unpack_ie_gtk(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEGTK *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp12__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp12__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->keyId = tmp12__ >> 0 & 0x3; + pDst->reserved = tmp12__ >> 2 & 0x3feb; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->keyLength = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->RSC, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + pDst->num_key = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->key, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_gtk. */ + +#define SigIeGTK (0x0001) + + +uint32_t dot11f_unpack_ie_igtk(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEIGTK *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->keyID, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->IPN, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->keyLength = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 24)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->key, pBuf, 24); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_igtk. */ + +#define SigIeIGTK (0x0002) + + +uint32_t dot11f_unpack_ie_r0_kh_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIER0KH_ID *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_PMK_R0_ID = (uint8_t)(ielen); + if (ielen > 48) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->PMK_R0_ID, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_r0_kh_id. */ + +#define SigIeR0KH_ID (0x0003) + + +uint32_t dot11f_unpack_ie_r1_kh_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIER1KH_ID *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->PMK_R1_ID, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_r1_kh_id. */ + +#define SigIeR1KH_ID (0x0004) + + +uint32_t dot11f_unpack_ie_ap_channel_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEAPChannelReport *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_channelList = (uint8_t)(ielen); + if (ielen > 50) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channelList, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ap_channel_report. */ + +#define SigIeAPChannelReport (0x0005) + + +uint32_t dot11f_unpack_ie_bcn_reporting_detail(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBcnReportingDetail *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->reportingDetail = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bcn_reporting_detail. */ + +#define SigIeBcnReportingDetail (0x0006) + + +uint32_t dot11f_unpack_ie_beacon_report_frm_body(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEBeaconReportFrmBody *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_reportedFields = (uint8_t)(ielen); + if (ielen > 224) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->reportedFields, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_beacon_report_frm_body. */ + +#define SigIeBeaconReportFrmBody (0x0007) + + +uint32_t dot11f_unpack_ie_condensed_country_str(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECondensedCountryStr *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->countryStr, pBuf, 2); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_condensed_country_str. */ + +#define SigIeCondensedCountryStr (0x0008) + + +uint32_t dot11f_unpack_ie_ExtRequestedInfo(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtRequestedInfo *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->req_element_id = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_req_element_id_ext = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->req_element_id_ext, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ExtRequestedInfo. */ + +#define SigIeExtRequestedInfo (0x0009) + + +uint32_t dot11f_unpack_ie_measurement_pilot(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementPilot *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurementPilot = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vendorSpecific = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->vendorSpecific, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_pilot. */ + +#define SigIeMeasurementPilot (0x000a) + + +uint32_t dot11f_unpack_ie_multi_bssid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMultiBssid *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->maxBSSIDIndicator = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vendorSpecific = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->vendorSpecific, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_multi_bssid. */ + +#define SigIeMultiBssid (0x000b) + + +uint32_t dot11f_unpack_ie_ric_data(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICData *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->Identifier = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->resourceDescCount = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->statusCode, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ric_data. */ + +#define SigIeRICData (0x000c) + + +uint32_t dot11f_unpack_ie_ric_descriptor(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICDescriptor *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->resourceType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_variableData = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->variableData, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ric_descriptor. */ + +#define SigIeRICDescriptor (0x000d) + + +uint32_t dot11f_unpack_ie_rrm_enabled_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERRMEnabledCap *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp13__; + uint8_t tmp14__; + uint8_t tmp15__; + uint8_t tmp16__; + uint8_t tmp17__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp13__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->LinkMeasurement = tmp13__ >> 0 & 0x1; + pDst->NeighborRpt = tmp13__ >> 1 & 0x1; + pDst->parallel = tmp13__ >> 2 & 0x1; + pDst->repeated = tmp13__ >> 3 & 0x1; + pDst->BeaconPassive = tmp13__ >> 4 & 0x1; + pDst->BeaconActive = tmp13__ >> 5 & 0x1; + pDst->BeaconTable = tmp13__ >> 6 & 0x1; + pDst->BeaconRepCond = tmp13__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp14__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->FrameMeasurement = tmp14__ >> 0 & 0x1; + pDst->ChannelLoad = tmp14__ >> 1 & 0x1; + pDst->NoiseHistogram = tmp14__ >> 2 & 0x1; + pDst->statistics = tmp14__ >> 3 & 0x1; + pDst->LCIMeasurement = tmp14__ >> 4 & 0x1; + pDst->LCIAzimuth = tmp14__ >> 5 & 0x1; + pDst->TCMCapability = tmp14__ >> 6 & 0x1; + pDst->triggeredTCM = tmp14__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp15__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APChanReport = tmp15__ >> 0 & 0x1; + pDst->RRMMIBEnabled = tmp15__ >> 1 & 0x1; + pDst->operatingChanMax = tmp15__ >> 2 & 0x7; + pDst->nonOperatinChanMax = tmp15__ >> 5 & 0x7; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp16__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->MeasurementPilot = tmp16__ >> 0 & 0x7; + pDst->MeasurementPilotEnabled = tmp16__ >> 3 & 0x1; + pDst->NeighborTSFOffset = tmp16__ >> 4 & 0x1; + pDst->RCPIMeasurement = tmp16__ >> 5 & 0x1; + pDst->RSNIMeasurement = tmp16__ >> 6 & 0x1; + pDst->BssAvgAccessDelay = tmp16__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp17__ = *pBuf; + pDst->BSSAvailAdmission = tmp17__ >> 0 & 0x1; + pDst->AntennaInformation = tmp17__ >> 1 & 0x1; + pDst->fine_time_meas_rpt = tmp17__ >> 2 & 0x1; + pDst->lci_capability = tmp17__ >> 3 & 0x1; + pDst->reserved = tmp17__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rrm_enabled_cap. */ + +#define SigIeRRMEnabledCap (0x000e) + + +uint32_t dot11f_unpack_ie_requested_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERequestedInfo *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_requested_eids = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->requested_eids, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_requested_info. */ + +#define SigIeRequestedInfo (0x000f) + + +uint32_t dot11f_unpack_ie_ssid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESSID *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) { + status = DOT11F_DUPLICATE_IE; + return status; + } + pDst->present = 1; + pDst->num_ssid = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ssid, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ssid. */ + +#define SigIeSSID (0x0010) + + +uint32_t dot11f_unpack_ie_schedule(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESchedule *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp18__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp18__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->aggregation = tmp18__ >> 0 & 0x1; + pDst->tsid = tmp18__ >> 1 & 0xf; + pDst->direction = tmp18__ >> 5 & 0x3; + pDst->reserved = tmp18__ >> 7 & 0x1ff; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->service_interval, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->max_service_dur, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->spec_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_schedule. */ + +#define SigIeSchedule (0x0011) + + +uint32_t dot11f_unpack_ie_tclas(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETCLAS *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->user_priority = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 0: + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.source, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.dest, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.EthParams.type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->info.IpParams.version) { + case 4: + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.source, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.dest, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.params.IpV4Params.DSCP = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.params.IpV4Params.proto = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.params.IpV4Params.reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 6: + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.source, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.dest, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.flow_label, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + break; + } + break; + case 2: + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.Params8021dq.tag_type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tclas. */ + +#define SigIeTCLAS (0x0012) + + +#define SigIeTCLASSPROC (0x0013) + + +uint32_t dot11f_unpack_ie_ts_delay(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSDelay *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->delay, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ts_delay. */ + +#define SigIeTSDelay (0x0014) + + +uint32_t dot11f_unpack_ie_tsf_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSFInfo *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->TsfOffset, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->BeaconIntvl, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tsf_info. */ + +#define SigIeTSFInfo (0x0015) + + +uint32_t dot11f_unpack_ie_tspec(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETSPEC *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp19__; + uint8_t tmp20__; + uint16_t tmp21__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp19__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->traffic_type = tmp19__ >> 0 & 0x1; + pDst->tsid = tmp19__ >> 1 & 0xf; + pDst->direction = tmp19__ >> 5 & 0x3; + pDst->access_policy = tmp19__ >> 7 & 0x3; + pDst->aggregation = tmp19__ >> 9 & 0x1; + pDst->psb = tmp19__ >> 10 & 0x1; + pDst->user_priority = tmp19__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp19__ >> 14 & 0x3; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp20__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->schedule = tmp20__ >> 0 & 0x1; + pDst->unused = tmp20__ >> 1 & 0x7f; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp21__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->size = tmp21__ >> 0 & 0x7fff; + pDst->fixed = tmp21__ >> 15 & 0x1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->max_msdu_size, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->min_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->max_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->inactivity_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->suspension_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->min_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->mean_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->peak_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->burst_size, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->delay_bound, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->min_phy_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->surplus_bw_allowance, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->medium_time, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tspec. */ + +#define SigIeTSPEC (0x0016) + + +uint32_t dot11f_unpack_ie_vht_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTCaps *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t tmp22__; + uint16_t tmp23__; + uint16_t tmp24__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp22__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->maxMPDULen = tmp22__ >> 0 & 0x3; + pDst->supportedChannelWidthSet = tmp22__ >> 2 & 0x3; + pDst->ldpcCodingCap = tmp22__ >> 4 & 0x1; + pDst->shortGI80MHz = tmp22__ >> 5 & 0x1; + pDst->shortGI160and80plus80MHz = tmp22__ >> 6 & 0x1; + pDst->txSTBC = tmp22__ >> 7 & 0x1; + pDst->rxSTBC = tmp22__ >> 8 & 0x7; + pDst->suBeamFormerCap = tmp22__ >> 11 & 0x1; + pDst->suBeamformeeCap = tmp22__ >> 12 & 0x1; + pDst->csnofBeamformerAntSup = tmp22__ >> 13 & 0x7; + pDst->numSoundingDim = tmp22__ >> 16 & 0x7; + pDst->muBeamformerCap = tmp22__ >> 19 & 0x1; + pDst->muBeamformeeCap = tmp22__ >> 20 & 0x1; + pDst->vhtTXOPPS = tmp22__ >> 21 & 0x1; + pDst->htcVHTCap = tmp22__ >> 22 & 0x1; + pDst->maxAMPDULenExp = tmp22__ >> 23 & 0x7; + pDst->vhtLinkAdaptCap = tmp22__ >> 26 & 0x3; + pDst->rxAntPattern = tmp22__ >> 28 & 0x1; + pDst->txAntPattern = tmp22__ >> 29 & 0x1; + pDst->extended_nss_bw_supp = tmp22__ >> 30 & 0x3; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->rxMCSMap, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp23__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->rxHighSupDataRate = tmp23__ >> 0 & 0x1fff; + pDst->max_nsts_total = tmp23__ >> 13 & 0x7; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->txMCSMap, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp24__, pBuf, 0); + pDst->txSupDataRate = tmp24__ >> 0 & 0x1fff; + pDst->vht_extended_nss_bw_cap = tmp24__ >> 13 & 0x1; + pDst->reserved = tmp24__ >> 14 & 0x3; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_caps. */ + +#define SigIeVHTCaps (0x0017) + + +uint32_t dot11f_unpack_ie_vht_operation(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTOperation *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->chanWidth = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->chan_center_freq_seg0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->chan_center_freq_seg1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->basicMCSSet, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_operation. */ + +#define SigIeVHTOperation (0x0018) + + +uint32_t dot11f_unpack_ie_wmm_schedule(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMSchedule *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp25__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp25__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->aggregation = tmp25__ >> 0 & 0x1; + pDst->tsid = tmp25__ >> 1 & 0xf; + pDst->direction = tmp25__ >> 5 & 0x3; + pDst->reserved = tmp25__ >> 7 & 0x1ff; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->service_interval, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->max_service_dur, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->spec_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_schedule. */ + +#define SigIeWMMSchedule (0x0019) + + +uint32_t dot11f_unpack_ie_wmmtclas(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTCLAS *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->user_priority = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 0: + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.source, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.EthParams.dest, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.EthParams.type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->info.IpParams.version) { + case 4: + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.source, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV4Params.dest, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV4Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.params.IpV4Params.DSCP = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.params.IpV4Params.proto = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->info.IpParams.params.IpV4Params.reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 6: + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.source, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.dest, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.src_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.IpParams.params.IpV6Params.dest_port, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.IpParams.params.IpV6Params.flow_label, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + break; + } + break; + case 2: + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->info.Params8021dq.tag_type, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtclas. */ + +#define SigIeWMMTCLAS (0x001a) + + +uint32_t dot11f_unpack_ie_wmmtclasproc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTCLASPROC *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->processing = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtclasproc. */ + +#define SigIeWMMTCLASPROC (0x001b) + + +uint32_t dot11f_unpack_ie_wmmts_delay(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTSDelay *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->delay, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmts_delay. */ + +#define SigIeWMMTSDelay (0x001c) + + +uint32_t dot11f_unpack_ie_wmmtspec(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMTSPEC *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp26__; + uint8_t tmp27__; + uint16_t tmp28__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp26__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->traffic_type = tmp26__ >> 0 & 0x1; + pDst->tsid = tmp26__ >> 1 & 0xf; + pDst->direction = tmp26__ >> 5 & 0x3; + pDst->access_policy = tmp26__ >> 7 & 0x3; + pDst->aggregation = tmp26__ >> 9 & 0x1; + pDst->psb = tmp26__ >> 10 & 0x1; + pDst->user_priority = tmp26__ >> 11 & 0x7; + pDst->tsinfo_ack_pol = tmp26__ >> 14 & 0x3; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp27__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->tsinfo_rsvd = tmp27__ >> 0 & 0x7f; + pDst->burst_size_defn = tmp27__ >> 7 & 0x1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp28__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->size = tmp28__ >> 0 & 0x7fff; + pDst->fixed = tmp28__ >> 15 & 0x1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->max_msdu_size, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->min_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->max_service_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->inactivity_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->suspension_int, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->service_start_time, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->min_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->mean_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->peak_data_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->burst_size, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->delay_bound, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->min_phy_rate, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->surplus_bw_allowance, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->medium_time, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmmtspec. */ + +#define SigIeWMMTSPEC (0x001d) + + +uint32_t dot11f_unpack_ie_wider_bw_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWiderBWChanSwitchAnn *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->newChanWidth = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->newCenterChanFreq0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->newCenterChanFreq1 = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wider_bw_chan_switch_ann. */ + +#define SigIeWiderBWChanSwitchAnn (0x001e) + + +uint32_t dot11f_unpack_ie_azimuth_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEazimuth_req *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->request = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_azimuth_req. */ + +#define SigIeazimuth_req (0x001f) + + +uint32_t dot11f_unpack_ie_beacon_report_frm_body_fragment_id(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEbeacon_report_frm_body_fragment_id *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp29__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp29__, pBuf, 0); + pDst->beacon_report_id = tmp29__ >> 0 & 0xff; + pDst->fragment_id_number = tmp29__ >> 8 & 0x7f; + pDst->more_fragments = tmp29__ >> 15 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_beacon_report_frm_body_fragment_id. */ + +#define SigIebeacon_report_frm_body_fragment_id (0x0020) + + +uint32_t dot11f_unpack_ie_bw_ind_element(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEbw_ind_element *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp30__; + uint8_t tmp31__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp30__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->reserved = tmp30__ >> 0 & 0x1; + pDst->disabled_sub_chan_bitmap_present = tmp30__ >> 1 & 0x1; + pDst->reserved_1 = tmp30__ >> 2 & 0x3f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp31__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->channel_width = tmp31__ >> 0 & 0x7; + pDst->reserved_2 = tmp31__ >> 3 & 0x1f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ccfs0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ccfs1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < pDst->disabled_sub_chan_bitmap_present * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->disabled_sub_chan_bitmap_present > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->disabled_sub_chan_bitmap, pBuf, (pDst->disabled_sub_chan_bitmap_present * 2)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bw_ind_element. */ + +#define SigIebw_ind_element (0x0021) + + +uint32_t dot11f_unpack_ie_bw_indication(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEbw_indication *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp32__; + uint8_t tmp33__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp32__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->reserved = tmp32__ >> 0 & 0x1; + pDst->disabled_sub_chan_bitmap_present = tmp32__ >> 1 & 0x1; + pDst->reserved_1 = tmp32__ >> 2 & 0x3f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp33__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->channel_width = tmp33__ >> 0 & 0x7; + pDst->reserved_2 = tmp33__ >> 3 & 0x1f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ccfs0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ccfs1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < pDst->disabled_sub_chan_bitmap_present * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->disabled_sub_chan_bitmap_present > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->disabled_sub_chan_bitmap, pBuf, (pDst->disabled_sub_chan_bitmap_present * 2)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bw_indication. */ + +#define SigIebw_indication (0x0022) + + +uint32_t dot11f_unpack_ie_last_beacon_report_indication(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIElast_beacon_report_indication *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->last_fragment = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_last_beacon_report_indication. */ + +#define SigIelast_beacon_report_indication (0x0023) + + +uint32_t dot11f_unpack_ie_max_age(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEmax_age *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->max_age, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_max_age. */ + +#define SigIemax_age (0x0024) + + +uint32_t dot11f_unpack_ie_mscs_status(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEmscs_status *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->status_code = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mscs_status. */ + +#define SigIemscs_status (0x0025) + + +static const tFFDefn FFS_neighbor_rpt[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_neighbor_rpt[] = { + { offsetof(tDot11fIEneighbor_rpt, TSFInfo), offsetof(tDot11fIETSFInfo, + present), 0, "TSFInfo", 0, 6, 6, SigIeTSFInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSFINFO, 0, 0, }, + { offsetof(tDot11fIEneighbor_rpt, CondensedCountryStr), + offsetof(tDot11fIECondensedCountryStr, present), 0, "CondensedCountryStr", + 0, 4, 4, SigIeCondensedCountryStr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CONDENSEDCOUNTRYSTR, 0, 0, }, + { offsetof(tDot11fIEneighbor_rpt, MeasurementPilot), + offsetof(tDot11fIEMeasurementPilot, present), 0, "MeasurementPilot", + 0, 3, 258, SigIeMeasurementPilot, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTPILOT, 0, 0, }, + { offsetof(tDot11fIEneighbor_rpt, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fIEneighbor_rpt, MultiBssid), + offsetof(tDot11fIEMultiBssid, present), 0, "MultiBssid", + 0, 3, 258, SigIeMultiBssid, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MULTIBSSID, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_neighbor_rpt(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEneighbor_rpt *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp34__; + uint8_t tmp35__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp34__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp34__ >> 0 & 0x3; + pDst->Security = tmp34__ >> 2 & 0x1; + pDst->KeyScope = tmp34__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp34__ >> 4 & 0x1; + pDst->QosCap = tmp34__ >> 5 & 0x1; + pDst->apsd = tmp34__ >> 6 & 0x1; + pDst->rrm = tmp34__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp35__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp35__ >> 0 & 0x1; + pDst->ImmBA = tmp35__ >> 1 & 0x1; + pDst->MobilityDomain = tmp35__ >> 2 & 0x1; + pDst->reserved = tmp35__ >> 3 & 0x1f; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->reserved1, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->PhyType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_neighbor_rpt, + IES_neighbor_rpt, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_neighbor_rpt. */ + +#define SigIeneighbor_rpt (0x0026) + + +uint32_t dot11f_unpack_ie_reporting_reason(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEreporting_reason *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp36__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp36__ = *pBuf; + pDst->failed_count = tmp36__ >> 0 & 0x1; + pDst->fcs_error = tmp36__ >> 1 & 0x1; + pDst->multiple_retry = tmp36__ >> 2 & 0x1; + pDst->frame_duplicate = tmp36__ >> 3 & 0x1; + pDst->rts_failure = tmp36__ >> 4 & 0x1; + pDst->ack_failure = tmp36__ >> 5 & 0x1; + pDst->retry = tmp36__ >> 6 & 0x1; + pDst->reserved = tmp36__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_reporting_reason. */ + +#define SigIereporting_reason (0x0027) + + +uint32_t dot11f_unpack_ie_req_mac_addr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEreq_mac_addr *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->addr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_req_mac_addr. */ + +#define SigIereq_mac_addr (0x0028) + + +uint32_t dot11f_unpack_ie_rrm_reporting(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIErrm_reporting *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->reporting_condition = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->threshold = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rrm_reporting. */ + +#define SigIerrm_reporting (0x0029) + + +uint32_t dot11f_unpack_ie_tclas_mask(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEtclas_mask *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->classifier_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->classifier_mask = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->classifier_type) { + case 4: + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->info.ip_param.reserved, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tclas_mask. */ + +#define SigIetclas_mask (0x002a) + + +uint32_t dot11f_unpack_ie_tgt_mac_addr(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEtgt_mac_addr *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->addr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tgt_mac_addr. */ + +#define SigIetgt_mac_addr (0x002b) + + +uint32_t dot11f_unpack_ie_transmit_power_env(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEtransmit_power_env *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp37__; + uint8_t tmp38__; + uint8_t tmp39__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp37__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->max_tx_pwr_count = tmp37__ >> 0 & 0x7; + pDst->max_tx_pwr_interpret = tmp37__ >> 3 & 0x7; + pDst->max_tx_pwr_category = tmp37__ >> 6 & 0x3; + pDst->num_tx_power = (uint8_t)(ielen); + if (ielen > 8) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tx_power, pBuf, (ielen)); + pBuf += (ielen); + ielen -= (ielen); + if (!ielen) { + return 0U; + } else { + switch (pDst->max_tx_pwr_interpret) { + case 0: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ext_max_tx_power.ext_max_tx_power_local_eirp.max_tx_power_for_320 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp38__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->ext_max_tx_power.ext_max_tx_power_local_psd.ext_count = tmp38__ >> 0 & 0xf; + pDst->ext_max_tx_power.ext_max_tx_power_local_psd.reserved = tmp38__ >> 4 & 0xf; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + break; + case 2: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ext_max_tx_power.ext_max_tx_power_reg_eirp.max_tx_power_for_320 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 3: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp39__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->ext_max_tx_power.ext_max_tx_power_reg_psd.ext_count = tmp39__ >> 0 & 0xf; + pDst->ext_max_tx_power.ext_max_tx_power_reg_psd.reserved = tmp39__ >> 4 & 0xf; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ext_max_tx_power.ext_max_tx_power_reg_psd.max_tx_psd_power, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + break; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_transmit_power_env. */ + +#define SigIetransmit_power_env (0x002c) + + +uint32_t dot11f_unpack_ie_wide_bw_chan_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEwide_bw_chan_switch *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->new_chan_width = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->new_center_chan_freq0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->new_center_chan_freq1 = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wide_bw_chan_switch. */ + +#define SigIewide_bw_chan_switch (0x002d) + + +uint32_t dot11f_unpack_ie_aid(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEAID *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->assocId, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_aid. */ + +#define SigIeAID (0x002e) + + +uint32_t dot11f_unpack_ie_cf_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECFParams *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->cfp_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->cfp_period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->cfp_maxduration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->cfp_durremaining, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_cf_params. */ + +#define SigIeCFParams (0x002f) + + +uint32_t dot11f_unpack_ie_challenge_text(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChallengeText *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_text = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->text, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_challenge_text. */ + +#define SigIeChallengeText (0x0030) + + +uint32_t dot11f_unpack_ie_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChanSwitchAnn *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->switchMode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->newChannel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->switchCount = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_chan_switch_ann. */ + +#define SigIeChanSwitchAnn (0x0031) + + +static const tFFDefn FFS_ChannelSwitchWrapper[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ChannelSwitchWrapper[] = { + { offsetof(tDot11fIEChannelSwitchWrapper, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fIEChannelSwitchWrapper, transmit_power_env), + offsetof(tDot11fIEtransmit_power_env, present), 0, "transmit_power_env", + 0, 4, 20, SigIetransmit_power_env, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TRANSMIT_POWER_ENV, 0, 0, }, + { offsetof(tDot11fIEChannelSwitchWrapper, bw_ind_element), + offsetof(tDot11fIEbw_ind_element, present), 0, "bw_ind_element", + 0, 6, 8, SigIebw_ind_element, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BW_IND_ELEMENT, 135, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEChannelSwitchWrapper *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_ChannelSwitchWrapper, + IES_ChannelSwitchWrapper, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_channel_switch_wrapper. */ + +#define SigIeChannelSwitchWrapper (0x0032) + + +uint32_t dot11f_unpack_ie_country(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIECountry *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->country, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + if (unlikely(ielen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->first_triplet, pBuf, 3); + pBuf += 3; + ielen -= (uint8_t)3; + if (!ielen) { + pDst->num_more_triplets = 0U; + return 0U; + } else { + pDst->num_more_triplets = (uint8_t)(ielen / 3); + if (ielen / 3 > 80) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->more_triplets, pBuf, (ielen)); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_country. */ + +#define SigIeCountry (0x0033) + + +#define SigIeDSParams (0x0034) + + +uint32_t dot11f_unpack_ie_edca_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEEDCAParamSet *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp40__; + uint8_t tmp41__; + uint8_t tmp42__; + uint8_t tmp43__; + uint8_t tmp44__; + uint8_t tmp45__; + uint8_t tmp46__; + uint8_t tmp47__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->qos = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->reserved = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp40__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp40__ >> 0 & 0xf; + pDst->acbe_acm = tmp40__ >> 4 & 0x1; + pDst->acbe_aci = tmp40__ >> 5 & 0x3; + pDst->unused1 = tmp40__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp41__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp41__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp41__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp42__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp42__ >> 0 & 0xf; + pDst->acbk_acm = tmp42__ >> 4 & 0x1; + pDst->acbk_aci = tmp42__ >> 5 & 0x3; + pDst->unused2 = tmp42__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp43__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp43__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp43__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp44__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp44__ >> 0 & 0xf; + pDst->acvi_acm = tmp44__ >> 4 & 0x1; + pDst->acvi_aci = tmp44__ >> 5 & 0x3; + pDst->unused3 = tmp44__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp45__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp45__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp45__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp46__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp46__ >> 0 & 0xf; + pDst->acvo_acm = tmp46__ >> 4 & 0x1; + pDst->acvo_aci = tmp46__ >> 5 & 0x3; + pDst->unused4 = tmp46__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp47__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp47__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp47__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_edca_param_set. */ + +#define SigIeEDCAParamSet (0x0035) + + +uint32_t dot11f_unpack_ie_erp_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEERPInfo *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp48__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp48__ = *pBuf; + pDst->non_erp_present = tmp48__ >> 0 & 0x1; + pDst->use_prot = tmp48__ >> 1 & 0x1; + pDst->barker_preamble = tmp48__ >> 2 & 0x1; + pDst->unused = tmp48__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_erp_info. */ + +#define SigIeERPInfo (0x0036) + + +uint32_t dot11f_unpack_ie_ese_cckm_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESECckmOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 20) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_cckm_opaque. */ + +#define SigIeESECckmOpaque (0x0037) + + +uint32_t dot11f_unpack_ie_ese_rad_mgmt_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESERadMgmtCap *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp49__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->mgmt_state = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp49__ = *pBuf; + pDst->mbssid_mask = tmp49__ >> 0 & 0x7; + pDst->reserved = tmp49__ >> 3 & 0x1f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_rad_mgmt_cap. */ + +#define SigIeESERadMgmtCap (0x0038) + + +uint32_t dot11f_unpack_ie_ese_traf_strm_met(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETrafStrmMet *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tsid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->state = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->msmt_interval, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_traf_strm_met. */ + +#define SigIeESETrafStrmMet (0x0039) + + +uint32_t dot11f_unpack_ie_ese_traf_strm_rate_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETrafStrmRateSet *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tsid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_tsrates = (uint8_t)(ielen); + if (ielen > 8) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tsrates, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_traf_strm_rate_set. */ + +#define SigIeESETrafStrmRateSet (0x003a) + + +uint32_t dot11f_unpack_ie_ese_txmit_power(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESETxmitPower *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->power_limit = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->reserved = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_txmit_power. */ + +#define SigIeESETxmitPower (0x003b) + + +uint32_t dot11f_unpack_ie_ese_version(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEESEVersion *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ese_version. */ + +#define SigIeESEVersion (0x003c) + + +uint32_t dot11f_unpack_ie_ext_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtCap *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + + if (!ielen) /* Check to ensure copying of ielen bytes */ + goto endUnpackIeExtCap; + pDst->num_bytes = (uint8_t)(ielen); + if (ielen > 15) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bytes, pBuf, (ielen)); + +endUnpackIeExtCap: + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_cap. */ + +#define SigIeExtCap (0x003d) + + +uint32_t dot11f_unpack_ie_ext_supp_rates(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEExtSuppRates *pDst, + bool append_ie) +{ + uint8_t i; + uint8_t rate_indx = 0; + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + for (i = 0; i < ielen; i++) { + if ((DOT11F_IS_BG_RATE(pBuf[i] & 0x7F)) && + (rate_indx < 12)) { + pDst->rates[rate_indx++] = pBuf[i]; + } + } + + if (rate_indx == 0) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + pDst->num_rates = rate_indx; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_supp_rates. */ + +#define SigIeExtSuppRates (0x003e) + + +uint32_t dot11f_unpack_ie_fh_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHParamSet *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->dwell_time, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->hop_set = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->hop_pattern = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->hop_index = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_param_set. */ + +#define SigIeFHParamSet (0x003f) + + +uint32_t dot11f_unpack_ie_fh_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHParams *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->radix = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->nchannels = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_params. */ + +#define SigIeFHParams (0x0040) + + +uint32_t dot11f_unpack_ie_fh_patt_table(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFHPattTable *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->flag = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->nsets = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->modulus = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_randtable = (uint8_t)(ielen); + if (ielen > 251) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->randtable, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fh_patt_table. */ + +#define SigIeFHPattTable (0x0041) + + +static const tFFDefn FFS_FTInfo[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_FTInfo[] = { + { offsetof(tDot11fIEFTInfo, R1KH_ID), offsetof(tDot11fIER1KH_ID, present), + 0, "R1KH_ID", 0, 8, 8, SigIeR1KH_ID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_R1KH_ID, 0, 0, }, + { offsetof(tDot11fIEFTInfo, GTK), offsetof(tDot11fIEGTK, present), 0, "GTK", + 0, 18, 45, SigIeGTK, {0, 0, 0, 0, 0}, 0, DOT11F_EID_GTK, 0, 0, }, + { offsetof(tDot11fIEFTInfo, R0KH_ID), offsetof(tDot11fIER0KH_ID, present), + 0, "R0KH_ID", 0, 3, 50, SigIeR0KH_ID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_R0KH_ID, 0, 0, }, + { offsetof(tDot11fIEFTInfo, IGTK), offsetof(tDot11fIEIGTK, present), 0, + "IGTK", 0, 35, 35, SigIeIGTK, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_IGTK, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_ft_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEFTInfo *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp50__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp50__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->reserved = tmp50__ >> 0 & 0xff; + pDst->IECount = tmp50__ >> 8 & 0xff; + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->MIC, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + if (unlikely(ielen < 32)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->Anonce, pBuf, 32); + pBuf += 32; + ielen -= (uint8_t)32; + if (unlikely(ielen < 32)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->Snonce, pBuf, 32); + pBuf += 32; + ielen -= (uint8_t)32; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_FTInfo, + IES_FTInfo, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_ft_info. */ + +#define SigIeFTInfo (0x0042) + + +uint32_t dot11f_unpack_ie_ht_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEHTCaps *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp51__; + uint8_t tmp52__; + uint16_t tmp53__; + uint32_t tmp54__; + uint8_t tmp55__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp51__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->advCodingCap = tmp51__ >> 0 & 0x1; + pDst->supportedChannelWidthSet = tmp51__ >> 1 & 0x1; + pDst->mimoPowerSave = tmp51__ >> 2 & 0x3; + pDst->greenField = tmp51__ >> 4 & 0x1; + pDst->shortGI20MHz = tmp51__ >> 5 & 0x1; + pDst->shortGI40MHz = tmp51__ >> 6 & 0x1; + pDst->txSTBC = tmp51__ >> 7 & 0x1; + pDst->rxSTBC = tmp51__ >> 8 & 0x3; + pDst->delayedBA = tmp51__ >> 10 & 0x1; + pDst->maximalAMSDUsize = tmp51__ >> 11 & 0x1; + pDst->dsssCckMode40MHz = tmp51__ >> 12 & 0x1; + pDst->psmp = tmp51__ >> 13 & 0x1; + pDst->stbcControlFrame = tmp51__ >> 14 & 0x1; + pDst->lsigTXOPProtection = tmp51__ >> 15 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp52__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->maxRxAMPDUFactor = tmp52__ >> 0 & 0x3; + pDst->mpduDensity = tmp52__ >> 2 & 0x7; + pDst->reserved1 = tmp52__ >> 5 & 0x7; + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->supportedMCSSet, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp53__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->pco = tmp53__ >> 0 & 0x1; + pDst->transitionTime = tmp53__ >> 1 & 0x3; + pDst->reserved2 = tmp53__ >> 3 & 0x1f; + pDst->mcsFeedback = tmp53__ >> 8 & 0x3; + pDst->reserved3 = tmp53__ >> 10 & 0x3f; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp54__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->txBF = tmp54__ >> 0 & 0x1; + pDst->rxStaggeredSounding = tmp54__ >> 1 & 0x1; + pDst->txStaggeredSounding = tmp54__ >> 2 & 0x1; + pDst->rxZLF = tmp54__ >> 3 & 0x1; + pDst->txZLF = tmp54__ >> 4 & 0x1; + pDst->implicitTxBF = tmp54__ >> 5 & 0x1; + pDst->calibration = tmp54__ >> 6 & 0x3; + pDst->explicitCSITxBF = tmp54__ >> 8 & 0x1; + pDst->explicitUncompressedSteeringMatrix = tmp54__ >> 9 & 0x1; + pDst->explicitBFCSIFeedback = tmp54__ >> 10 & 0x7; + pDst->explicitUncompressedSteeringMatrixFeedback = tmp54__ >> 13 & 0x7; + pDst->explicitCompressedSteeringMatrixFeedback = tmp54__ >> 16 & 0x7; + pDst->csiNumBFAntennae = tmp54__ >> 19 & 0x3; + pDst->uncompressedSteeringMatrixBFAntennae = tmp54__ >> 21 & 0x3; + pDst->compressedSteeringMatrixBFAntennae = tmp54__ >> 23 & 0x3; + pDst->reserved4 = tmp54__ >> 25 & 0x7f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp55__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->antennaSelection = tmp55__ >> 0 & 0x1; + pDst->explicitCSIFeedbackTx = tmp55__ >> 1 & 0x1; + pDst->antennaIndicesFeedbackTx = tmp55__ >> 2 & 0x1; + pDst->explicitCSIFeedback = tmp55__ >> 3 & 0x1; + pDst->antennaIndicesFeedback = tmp55__ >> 4 & 0x1; + pDst->rxAS = tmp55__ >> 5 & 0x1; + pDst->txSoundingPPDUs = tmp55__ >> 6 & 0x1; + pDst->reserved5 = tmp55__ >> 7 & 0x1; + pDst->num_rsvd = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rsvd, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht_caps. */ + +#define SigIeHTCaps (0x0043) + + +uint32_t dot11f_unpack_ie_ht_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEHTInfo *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp56__; + uint16_t tmp57__; + uint16_t tmp58__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->primaryChannel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp56__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->secondaryChannelOffset = tmp56__ >> 0 & 0x3; + pDst->recommendedTxWidthSet = tmp56__ >> 2 & 0x1; + pDst->rifsMode = tmp56__ >> 3 & 0x1; + pDst->controlledAccessOnly = tmp56__ >> 4 & 0x1; + pDst->serviceIntervalGranularity = tmp56__ >> 5 & 0x7; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp57__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->opMode = tmp57__ >> 0 & 0x3; + pDst->nonGFDevicesPresent = tmp57__ >> 2 & 0x1; + pDst->transmitBurstLimit = tmp57__ >> 3 & 0x1; + pDst->obssNonHTStaPresent = tmp57__ >> 4 & 0x1; + pDst->chan_center_freq_seg2 = tmp57__ >> 5 & 0xff; + pDst->reserved = tmp57__ >> 13 & 0x7; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp58__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->basicSTBCMCS = tmp58__ >> 0 & 0x7f; + pDst->dualCTSProtection = tmp58__ >> 7 & 0x1; + pDst->secondaryBeacon = tmp58__ >> 8 & 0x1; + pDst->lsigTXOPProtectionFullSupport = tmp58__ >> 9 & 0x1; + pDst->pcoActive = tmp58__ >> 10 & 0x1; + pDst->pcoPhase = tmp58__ >> 11 & 0x1; + pDst->reserved2 = tmp58__ >> 12 & 0xf; + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->basicMCSSet, pBuf, 16); + pBuf += 16; + ielen -= (uint8_t)16; + pDst->num_rsvd = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rsvd, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht_info. */ + +#define SigIeHTInfo (0x0044) + + +uint32_t dot11f_unpack_ie_link_identifier(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIELinkIdentifier *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->InitStaAddr, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->RespStaAddr, pBuf, 6); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_link_identifier. */ + +#define SigIeLinkIdentifier (0x0045) + + +static const tTLVDefn TLVS_MBO_IE[] = { + { offsetof(tDot11fIEMBO_IE, mbo_ap_cap), offsetof(tDot11fTLVmbo_ap_cap, + present), "mbo_ap_cap", SigTlvmbo_ap_cap, DOT11F_TLV_MBO_AP_CAP, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, non_prefferd_chan_rep), + offsetof(tDot11fTLVnon_prefferd_chan_rep, present), + "non_prefferd_chan_rep", SigTlvnon_prefferd_chan_rep, + DOT11F_TLV_NON_PREFFERD_CHAN_REP, 0, 6, 257, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, cellular_data_cap), + offsetof(tDot11fTLVcellular_data_cap, present), "cellular_data_cap", + SigTlvcellular_data_cap, DOT11F_TLV_CELLULAR_DATA_CAP, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, assoc_disallowed), + offsetof(tDot11fTLVassoc_disallowed, present), "assoc_disallowed", + SigTlvassoc_disallowed, DOT11F_TLV_ASSOC_DISALLOWED, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, cellular_data_con_pref), + offsetof(tDot11fTLVcellular_data_con_pref, present), + "cellular_data_con_pref", SigTlvcellular_data_con_pref, + DOT11F_TLV_CELLULAR_DATA_CON_PREF, 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, transition_reason), + offsetof(tDot11fTLVtransition_reason, present), "transition_reason", + SigTlvtransition_reason, DOT11F_TLV_TRANSITION_REASON, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, transition_reject_reason), + offsetof(tDot11fTLVtransition_reject_reason, present), + "transition_reject_reason", SigTlvtransition_reject_reason, + DOT11F_TLV_TRANSITION_REJECT_REASON, 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, assoc_retry_delay), + offsetof(tDot11fTLVassoc_retry_delay, present), "assoc_retry_delay", + SigTlvassoc_retry_delay, DOT11F_TLV_ASSOC_RETRY_DELAY, + 0, 4, 4, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, oce_cap), offsetof(tDot11fTLVoce_cap, + present), "oce_cap", SigTlvoce_cap, DOT11F_TLV_OCE_CAP, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, rssi_assoc_rej), + offsetof(tDot11fTLVrssi_assoc_rej, present), "rssi_assoc_rej", + SigTlvrssi_assoc_rej, DOT11F_TLV_RSSI_ASSOC_REJ, 0, 4, 4, 0, 1, 1, 0, }, + { offsetof(tDot11fIEMBO_IE, reduced_wan_metrics), + offsetof(tDot11fTLVreduced_wan_metrics, present), "reduced_wan_metrics", + SigTlvreduced_wan_metrics, DOT11F_TLV_REDUCED_WAN_METRICS, + 0, 3, 3, 0, 1, 1, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_MBO_IE(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMBO_IE *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_MBO_IE, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_MBO_IE. */ + +#define SigIeMBO_IE (0x0046) + + +static const tFFDefn FFS_reportchannel_load_report[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_reportchannel_load_report[] = { + { offsetof(tDot11fIEMeasurementReport, + report.channel_load_report.wide_bw_chan_switch), + offsetof(tDot11fIEwide_bw_chan_switch, present), 0, "wide_bw_chan_switch", + 0, 5, 5, SigIewide_bw_chan_switch, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WIDE_BW_CHAN_SWITCH, 0, 0, }, + { offsetof(tDot11fIEMeasurementReport, + report.channel_load_report.bw_indication), + offsetof(tDot11fIEbw_indication, present), 0, "bw_indication", + 0, 6, 8, SigIebw_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BW_INDICATION, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_reportBeacon[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_reportBeacon[] = { + { offsetof(tDot11fIEMeasurementReport, + report.Beacon.BeaconReportFrmBody), + offsetof(tDot11fIEBeaconReportFrmBody, present), 0, "BeaconReportFrmBody", + 0, 2, 226, SigIeBeaconReportFrmBody, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACONREPORTFRMBODY, 0, 0, }, + { offsetof(tDot11fIEMeasurementReport, + report.Beacon.beacon_report_frm_body_fragment_id), + offsetof(tDot11fIEbeacon_report_frm_body_fragment_id, present), 0, + "beacon_report_frm_body_fragment_id", + 0, 4, 4, SigIebeacon_report_frm_body_fragment_id, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BEACON_REPORT_FRM_BODY_FRAGMENT_ID, 0, 0, }, + { offsetof(tDot11fIEMeasurementReport, + report.Beacon.last_beacon_report_indication), + offsetof(tDot11fIElast_beacon_report_indication, present), 0, + "last_beacon_report_indication", + 0, 3, 3, SigIelast_beacon_report_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LAST_BEACON_REPORT_INDICATION, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_reportsta_stats[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_reportsta_stats[] = { + { offsetof(tDot11fIEMeasurementReport, + report.sta_stats.reporting_reason), offsetof(tDot11fIEreporting_reason, + present), 0, "reporting_reason", 0, 3, 3, SigIereporting_reason, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REPORTING_REASON, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementReport *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp59__; + uint8_t tmp60__; + uint8_t tmp61__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->token = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp59__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->late = tmp59__ >> 0 & 0x1; + pDst->incapable = tmp59__ >> 1 & 0x1; + pDst->refused = tmp59__ >> 2 & 0x1; + pDst->unused = tmp59__ >> 3 & 0x1f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (!ielen) { + return 0U; + } else { + switch (pDst->type) { + case 0: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.Basic.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohq(pCtx, &pDst->report.Basic.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.Basic.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp60__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Basic.bss = tmp60__ >> 0 & 0x1; + pDst->report.Basic.ofdm_preamble = tmp60__ >> 1 & 0x1; + pDst->report.Basic.unid_signal = tmp60__ >> 2 & 0x1; + pDst->report.Basic.rader = tmp60__ >> 3 & 0x1; + pDst->report.Basic.unmeasured = tmp60__ >> 4 & 0x1; + pDst->report.Basic.unused = tmp60__ >> 5 & 0x7; + break; + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.CCA.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohq(pCtx, &pDst->report.CCA.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.CCA.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.CCA.cca_busy_fraction = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 2: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohq(pCtx, &pDst->report.RPIHistogram.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.RPIHistogram.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi0_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi1_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi2_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi3_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi4_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi5_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi6_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.RPIHistogram.rpi7_density = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 3: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.channel_load_report.op_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.channel_load_report.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohq(pCtx, &pDst->report.channel_load_report.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.channel_load_report.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.channel_load_report.chan_load = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_reportchannel_load_report, + IES_reportchannel_load_report, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + case 5: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.Beacon.regClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.Beacon.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohq(pCtx, &pDst->report.Beacon.meas_start_time, pBuf, 0); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.Beacon.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp61__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->report.Beacon.condensed_PHY = tmp61__ >> 0 & 0x7f; + pDst->report.Beacon.reported_frame_type = tmp61__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.Beacon.RCPI = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.Beacon.RSNI = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->report.Beacon.BSSID, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.Beacon.antenna_id = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.Beacon.parent_TSF, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_reportBeacon, + IES_reportBeacon, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + case 7: + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.sta_stats.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.group_id = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->report.sta_stats.group_id) { + case 0: + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_fragment_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.group_transmitted_frame_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.failed_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.received_fragment_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.group_received_frame_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.fcs_error_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_frame_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + break; + case 1: + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_mac_stats.retry_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_mac_stats.multiple_retry_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_mac_stats.frame_duplicate_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_success_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_failure_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_mac_stats.ack_failure_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + break; + case 2: + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_transmitted_fragment_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_failed_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_retry_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_multiple_retry_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_frame_duplicate_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_rts_success_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_rts_failure_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_ack_failure_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_received_fragment_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_transmitted_frame_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_discarded_frame_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_mpdus_received_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_retries_received_count, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + break; + case 10: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.ap_average_access_delay = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_besteffort = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_background = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_video = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_voice = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.station_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.channel_utilization = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + } + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_reportsta_stats, + IES_reportsta_stats, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_report. */ + +#define SigIeMeasurementReport (0x0047) + + +static const tFFDefn FFS_measurement_requestchannel_load[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestchannel_load[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.channel_load.rrm_reporting), + offsetof(tDot11fIErrm_reporting, present), 0, "rrm_reporting", + 0, 4, 4, SigIerrm_reporting, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRM_REPORTING, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.channel_load.wide_bw_chan_switch), + offsetof(tDot11fIEwide_bw_chan_switch, present), 0, "wide_bw_chan_switch", + 0, 5, 5, SigIewide_bw_chan_switch, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WIDE_BW_CHAN_SWITCH, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.channel_load.bw_indication), + offsetof(tDot11fIEbw_indication, present), 0, "bw_indication", + 0, 6, 8, SigIebw_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BW_INDICATION, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_measurement_requestBeacon[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestBeacon[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.rrm_reporting), + offsetof(tDot11fIErrm_reporting, present), 0, "rrm_reporting", + 0, 4, 4, SigIerrm_reporting, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRM_REPORTING, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.BcnReportingDetail), + offsetof(tDot11fIEBcnReportingDetail, present), 0, "BcnReportingDetail", + 0, 3, 3, SigIeBcnReportingDetail, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BCNREPORTINGDETAIL, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.RequestedInfo), + offsetof(tDot11fIERequestedInfo, present), 0, "RequestedInfo", + 0, 2, 257, SigIeRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQUESTEDINFO, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.ExtRequestedInfo), + offsetof(tDot11fIEExtRequestedInfo, present), 0, "ExtRequestedInfo", + 0, 3, 258, SigIeExtRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTREQUESTEDINFO, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), + offsetof(tDot11fIEMeasurementRequest, measurement_request.Beacon.num_APChannelReport), "APChannelReport", 2, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, 0, DOT11F_EID_APCHANNELREPORT, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.Beacon.last_beacon_report_indication), + offsetof(tDot11fIElast_beacon_report_indication, present), 0, + "last_beacon_report_indication", + 0, 3, 3, SigIelast_beacon_report_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LAST_BEACON_REPORT_INDICATION, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_measurement_requestlci[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestlci[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.azimuth_req), offsetof(tDot11fIEazimuth_req, + present), 0, "azimuth_req", 0, 3, 3, SigIeazimuth_req, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_AZIMUTH_REQ, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.req_mac_addr), offsetof(tDot11fIEreq_mac_addr, + present), 0, "req_mac_addr", 0, 8, 8, SigIereq_mac_addr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQ_MAC_ADDR, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.tgt_mac_addr), offsetof(tDot11fIEtgt_mac_addr, + present), 0, "tgt_mac_addr", 0, 8, 8, SigIetgt_mac_addr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TGT_MAC_ADDR, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.lci.max_age), offsetof(tDot11fIEmax_age, present), 0, + "max_age", 0, 4, 4, SigIemax_age, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MAX_AGE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +static const tFFDefn FFS_measurement_requestftmrr[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_measurement_requestftmrr[] = { + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.ftmrr.neighbor_rpt), offsetof(tDot11fIEneighbor_rpt, + present), 0, "neighbor_rpt", 0, 15, 548, SigIeneighbor_rpt, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_NEIGHBOR_RPT, 0, 0, }, + { offsetof(tDot11fIEMeasurementRequest, + measurement_request.ftmrr.max_age), offsetof(tDot11fIEmax_age, present), + 0, "max_age", 0, 4, 4, SigIemax_age, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MAX_AGE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMeasurementRequest *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp62__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_token = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp62__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->parallel = tmp62__ >> 0 & 0x1; + pDst->enable = tmp62__ >> 1 & 0x1; + pDst->request = tmp62__ >> 2 & 0x1; + pDst->report = tmp62__ >> 3 & 0x1; + pDst->durationMandatory = tmp62__ >> 4 & 0x1; + pDst->unused = tmp62__ >> 5 & 0x7; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->measurement_type) { + case 0: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.Basic.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->measurement_request.Basic.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.Basic.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.CCA.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->measurement_request.CCA.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.CCA.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 2: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.RPIHistogram.channel_no = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->measurement_request.RPIHistogram.meas_start_time, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.RPIHistogram.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 3: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.channel_load.op_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.channel_load.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.channel_load.randomization_intv, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.channel_load.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestchannel_load, + IES_measurement_requestchannel_load, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + case 5: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.Beacon.regClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.Beacon.channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.Beacon.randomization, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.Beacon.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.Beacon.meas_mode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->measurement_request.Beacon.BSSID, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestBeacon, + IES_measurement_requestBeacon, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + case 8: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.lci.loc_subject = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestlci, + IES_measurement_requestlci, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + case 16: + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.ftmrr.random_interval, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.ftmrr.min_ap_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_measurement_requestftmrr, + IES_measurement_requestftmrr, + (uint8_t *)pDst, + sizeof(*pDst), append_ie); + break; + case 7: + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->measurement_request.sta_stats.peer_mac_addr, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.sta_stats.randomization, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->measurement_request.sta_stats.meas_duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->measurement_request.sta_stats.group_identity = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_measurement_request. */ + +#define SigIeMeasurementRequest (0x0048) + + +uint32_t dot11f_unpack_ie_mobility_domain(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEMobilityDomain *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp63__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->MDID, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp63__ = *pBuf; + pDst->overDSCap = tmp63__ >> 0 & 0x1; + pDst->resourceReqCap = tmp63__ >> 1 & 0x1; + pDst->reserved = tmp63__ >> 2 & 0x3f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mobility_domain. */ + +#define SigIeMobilityDomain (0x0049) + + +static const tFFDefn FFS_NeighborReport[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReport[] = { + { offsetof(tDot11fIENeighborReport, TSFInfo), offsetof(tDot11fIETSFInfo, + present), 0, "TSFInfo", 0, 6, 6, SigIeTSFInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSFINFO, 0, 0, }, + { offsetof(tDot11fIENeighborReport, CondensedCountryStr), + offsetof(tDot11fIECondensedCountryStr, present), 0, "CondensedCountryStr", + 0, 4, 4, SigIeCondensedCountryStr, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CONDENSEDCOUNTRYSTR, 0, 0, }, + { offsetof(tDot11fIENeighborReport, MeasurementPilot), + offsetof(tDot11fIEMeasurementPilot, present), 0, "MeasurementPilot", + 0, 3, 258, SigIeMeasurementPilot, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTPILOT, 0, 0, }, + { offsetof(tDot11fIENeighborReport, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fIENeighborReport, MultiBssid), + offsetof(tDot11fIEMultiBssid, present), 0, "MultiBssid", + 0, 3, 258, SigIeMultiBssid, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MULTIBSSID, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_neighbor_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIENeighborReport *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp64__; + uint8_t tmp65__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp64__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->APReachability = tmp64__ >> 0 & 0x3; + pDst->Security = tmp64__ >> 2 & 0x1; + pDst->KeyScope = tmp64__ >> 3 & 0x1; + pDst->SpecMgmtCap = tmp64__ >> 4 & 0x1; + pDst->QosCap = tmp64__ >> 5 & 0x1; + pDst->apsd = tmp64__ >> 6 & 0x1; + pDst->rrm = tmp64__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp65__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->DelayedBA = tmp65__ >> 0 & 0x1; + pDst->ImmBA = tmp65__ >> 1 & 0x1; + pDst->MobilityDomain = tmp65__ >> 2 & 0x1; + pDst->reserved = tmp65__ >> 3 & 0x1f; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->reserved1, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->regulatoryClass = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->PhyType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_NeighborReport, + IES_NeighborReport, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_neighbor_report. */ + +#define SigIeNeighborReport (0x004a) + + +uint32_t dot11f_unpack_ie_obss_scan_parameters(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEOBSSScanParameters *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->obssScanPassiveDwell, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->obssScanActiveDwell, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->bssChannelWidthTriggerScanInterval, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->obssScanPassiveTotalPerChannel, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->obssScanActiveTotalPerChannel, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->bssWidthChannelTransitionDelayFactor, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->obssScanActivityThreshold, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_obss_scan_parameters. */ + +#define SigIeOBSSScanParameters (0x004b) + + +uint32_t dot11f_unpack_ie_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEOperatingMode *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp66__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp66__ = *pBuf; + pDst->chanWidth = tmp66__ >> 0 & 0x3; + pDst->vht_160_80p80_supp = tmp66__ >> 2 & 0x1; + pDst->no_ldpc = tmp66__ >> 3 & 0x1; + pDst->rxNSS = tmp66__ >> 4 & 0x7; + pDst->rxNSSType = tmp66__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_operating_mode. */ + +#define SigIeOperatingMode (0x004c) + + +static const tTLVDefn TLVS_P2PAssocReq[] = { + { offsetof(tDot11fIEP2PAssocReq, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocReq, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocReq, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_assoc_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PAssocReq *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PAssocReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_assoc_req. */ + +#define SigIeP2PAssocReq (0x004d) + + +static const tTLVDefn TLVS_P2PAssocRes[] = { + { offsetof(tDot11fIEP2PAssocRes, P2PStatus), + offsetof(tDot11fTLVP2PStatus, present), "P2PStatus", SigTlvP2PStatus, + DOT11F_TLV_P2PSTATUS, 0, 4, 4, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PAssocRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_assoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PAssocRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PAssocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_assoc_res. */ + +#define SigIeP2PAssocRes (0x004e) + + +static const tTLVDefn TLVS_P2PBeacon[] = { + { offsetof(tDot11fIEP2PBeacon, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeacon, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeacon, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PBeacon *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PBeacon, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_beacon. */ + +#define SigIeP2PBeacon (0x004f) + + +static const tTLVDefn TLVS_P2PBeaconProbeRes[] = { + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PBeaconProbeRes, P2PGroupInfo), + offsetof(tDot11fTLVP2PGroupInfo, present), "P2PGroupInfo", + SigTlvP2PGroupInfo, DOT11F_TLV_P2PGROUPINFO, 0, 3, 1027, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_beacon_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PBeaconProbeRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PBeaconProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_beacon_probe_res. */ + +#define SigIeP2PBeaconProbeRes (0x0050) + + +static const tTLVDefn TLVS_P2PDeAuth[] = { + { offsetof(tDot11fIEP2PDeAuth, MinorReasonCode), + offsetof(tDot11fTLVMinorReasonCode, present), "MinorReasonCode", + SigTlvMinorReasonCode, DOT11F_TLV_MINORREASONCODE, + 0, 4, 4, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PDeAuth *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PDeAuth, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_de_auth. */ + +#define SigIeP2PDeAuth (0x0051) + + +static const tTLVDefn TLVS_P2PDisAssoc[] = { + { offsetof(tDot11fIEP2PDisAssoc, MinorReasonCode), + offsetof(tDot11fTLVMinorReasonCode, present), "MinorReasonCode", + SigTlvMinorReasonCode, DOT11F_TLV_MINORREASONCODE, + 0, 4, 4, 1, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_dis_assoc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PDisAssoc *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PDisAssoc, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_dis_assoc. */ + +#define SigIeP2PDisAssoc (0x0052) + + +uint32_t dot11f_unpack_ie_p2_pie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PIEOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_p2_pie_opaque. */ + +#define SigIeP2PIEOpaque (0x0053) + + +static const tTLVDefn TLVS_P2PProbeReq[] = { + { offsetof(tDot11fIEP2PProbeReq, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, P2PDeviceId), + offsetof(tDot11fTLVP2PDeviceId, present), "P2PDeviceId", + SigTlvP2PDeviceId, DOT11F_TLV_P2PDEVICEID, 0, 9, 9, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, ListenChannel), + offsetof(tDot11fTLVListenChannel, present), "ListenChannel", + SigTlvListenChannel, DOT11F_TLV_LISTENCHANNEL, 0, 8, 8, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeReq, OperatingChannel), + offsetof(tDot11fTLVOperatingChannel, present), "OperatingChannel", + SigTlvOperatingChannel, DOT11F_TLV_OPERATINGCHANNEL, + 0, 8, 8, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_probe_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PProbeReq *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PProbeReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_probe_req. */ + +#define SigIeP2PProbeReq (0x0054) + + +static const tTLVDefn TLVS_P2PProbeRes[] = { + { offsetof(tDot11fIEP2PProbeRes, P2PCapability), + offsetof(tDot11fTLVP2PCapability, present), "P2PCapability", + SigTlvP2PCapability, DOT11F_TLV_P2PCAPABILITY, 0, 5, 5, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, ExtendedListenTiming), + offsetof(tDot11fTLVExtendedListenTiming, present), + "ExtendedListenTiming", SigTlvExtendedListenTiming, + DOT11F_TLV_EXTENDEDLISTENTIMING, 0, 7, 7, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, NoticeOfAbsence), + offsetof(tDot11fTLVNoticeOfAbsence, present), "NoticeOfAbsence", + SigTlvNoticeOfAbsence, DOT11F_TLV_NOTICEOFABSENCE, + 0, 5, 41, 0, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, P2PDeviceInfo), + offsetof(tDot11fTLVP2PDeviceInfo, present), "P2PDeviceInfo", + SigTlvP2PDeviceInfo, DOT11F_TLV_P2PDEVICEINFO, 0, 19, 55, 1, 1, 2, 0, }, + { offsetof(tDot11fIEP2PProbeRes, P2PGroupInfo), + offsetof(tDot11fTLVP2PGroupInfo, present), "P2PGroupInfo", + SigTlvP2PGroupInfo, DOT11F_TLV_P2PGROUPINFO, 0, 3, 1027, 0, 1, 2, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_p2_p_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEP2PProbeRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_P2PProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_p2_p_probe_res. */ + +#define SigIeP2PProbeRes (0x0055) + + +uint32_t dot11f_unpack_ie_pti_control(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPTIControl *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tid = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->sequence_control, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pti_control. */ + +#define SigIePTIControl (0x0056) + + +uint32_t dot11f_unpack_ie_pu_buffer_status(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPUBufferStatus *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp67__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp67__ = *pBuf; + pDst->ac_bk_traffic_aval = tmp67__ >> 0 & 0x1; + pDst->ac_be_traffic_aval = tmp67__ >> 1 & 0x1; + pDst->ac_vi_traffic_aval = tmp67__ >> 2 & 0x1; + pDst->ac_vo_traffic_aval = tmp67__ >> 3 & 0x1; + pDst->reserved = tmp67__ >> 4 & 0xf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_pu_buffer_status. */ + +#define SigIePUBufferStatus (0x0057) + + +uint32_t dot11f_unpack_ie_power_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPowerCaps *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->minTxPower = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->maxTxPower = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_power_caps. */ + +#define SigIePowerCaps (0x0058) + + +uint32_t dot11f_unpack_ie_power_constraints(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEPowerConstraints *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->localPowerConstraints = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_power_constraints. */ + +#define SigIePowerConstraints (0x0059) + + +uint32_t dot11f_unpack_ie_qbss_load(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQBSSLoad *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->stacount, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->chautil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->avail, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qbss_load. */ + +#define SigIeQBSSLoad (0x005a) + + +uint32_t dot11f_unpack_ie_QComVendorIE(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQComVendorIE *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->channel = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_QComVendorIE. */ + +#define SigIeQComVendorIE (0x005b) + + +uint32_t dot11f_unpack_ie_qos_caps_ap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQOSCapsAp *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp68__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp68__ = *pBuf; + pDst->count = tmp68__ >> 0 & 0xf; + pDst->qack = tmp68__ >> 4 & 0x1; + pDst->qreq = tmp68__ >> 5 & 0x1; + pDst->txopreq = tmp68__ >> 6 & 0x1; + pDst->reserved = tmp68__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_ap. */ + +#define SigIeQOSCapsAp (0x005c) + + +uint32_t dot11f_unpack_ie_qos_caps_station(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQOSCapsStation *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp69__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp69__ = *pBuf; + pDst->acvo_uapsd = tmp69__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp69__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp69__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp69__ >> 3 & 0x1; + pDst->qack = tmp69__ >> 4 & 0x1; + pDst->max_sp_length = tmp69__ >> 5 & 0x3; + pDst->more_data_ack = tmp69__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_caps_station. */ + +#define SigIeQOSCapsStation (0x005d) + + +uint32_t dot11f_unpack_ie_qos_map_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQosMapSet *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_dscp_exceptions = (uint8_t)(ielen); + if (ielen > 58) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->dscp_exceptions, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_qos_map_set. */ + +#define SigIeQosMapSet (0x005e) + + +uint32_t dot11f_unpack_ie_quiet(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEQuiet *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->duration, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->offset, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_quiet. */ + +#define SigIeQuiet (0x005f) + + +uint32_t dot11f_unpack_ie_rcpiie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERCPIIE *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->rcpi = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rcpiie. */ + +#define SigIeRCPIIE (0x0060) + + +static const tFFDefn FFS_RICDataDesc[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RICDataDesc[] = { + { offsetof(tDot11fIERICDataDesc, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, 1, }, + { offsetof(tDot11fIERICDataDesc, RICDescriptor), + offsetof(tDot11fIERICDescriptor, present), 0, "RICDescriptor", + 0, 3, 258, SigIeRICDescriptor, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDESCRIPTOR, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, TSPEC), offsetof(tDot11fIETSPEC, + present), 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, TCLAS), offsetof(tDot11fIETCLAS, + present), offsetof(tDot11fIERICDataDesc, num_TCLAS), "TCLAS", + 2, 7, 45, SigIeTCLAS, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, TSDelay), offsetof(tDot11fIETSDelay, + present), 0, "TSDelay", 0, 6, 6, SigIeTSDelay, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSDELAY, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, Schedule), offsetof(tDot11fIESchedule, + present), 0, "Schedule", 0, 16, 16, SigIeSchedule, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SCHEDULE, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fIERICDataDesc, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMTSDelay), + offsetof(tDot11fIEWMMTSDelay, present), 0, "WMMTSDelay", + 0, 12, 12, SigIeWMMTSDelay, {0, 80, 242, 2, 8}, + 5, DOT11F_EID_WMMTSDELAY, 0, 0, }, + { offsetof(tDot11fIERICDataDesc, WMMSchedule), + offsetof(tDot11fIEWMMSchedule, present), 0, "WMMSchedule", + 0, 22, 22, SigIeWMMSchedule, {0, 80, 242, 2, 9}, + 5, DOT11F_EID_WMMSCHEDULE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_ric_data_desc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERICDataDesc *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_RICDataDesc, + IES_RICDataDesc, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_ric_data_desc. */ + +#define SigIeRICDataDesc (0x0061) + + +uint32_t dot11f_unpack_ie_rsn(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSN *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t def_cipher_suite[4] = {0x00, 0x0f, 0xac, 0x04}; + uint8_t def_akm_suite[4] = {0x00, 0x0f, 0xac, 0x01}; + + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (!ielen) { + pDst->RSN_Cap_present = 0U; + pDst->gp_mgmt_cipher_suite_present = 0U; + pDst->gp_cipher_suite_present = 1; + DOT11F_MEMCPY(pCtx, pDst->gp_cipher_suite, def_cipher_suite, 4); + pDst->pwise_cipher_suite_count = 1; + DOT11F_MEMCPY(pCtx, + pDst->pwise_cipher_suites, def_cipher_suite, 4); + pDst->akm_suite_cnt = 1; + DOT11F_MEMCPY(pCtx, pDst->akm_suite, def_akm_suite, 4); + pDst->pmkid_count = 0U; + return 0U; + } else { + pDst->gp_cipher_suite_present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->gp_cipher_suite, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + } + if (!ielen) { + pDst->RSN_Cap_present = 0U; + pDst->gp_mgmt_cipher_suite_present = 0U; + pDst->pwise_cipher_suite_count = 1; + DOT11F_MEMCPY(pCtx, + pDst->pwise_cipher_suites, def_cipher_suite, 4); + pDst->akm_suite_cnt = 1; + DOT11F_MEMCPY(pCtx, pDst->akm_suite, def_akm_suite, 4); + pDst->pmkid_count = 0U; + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->pwise_cipher_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (unlikely(ielen < pDst->pwise_cipher_suite_count * 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (!pDst->pwise_cipher_suite_count || + pDst->pwise_cipher_suite_count > 6) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->pwise_cipher_suites, pBuf, (pDst->pwise_cipher_suite_count * 4)); + pBuf += (pDst->pwise_cipher_suite_count * 4); + ielen -= (pDst->pwise_cipher_suite_count * 4); + if (!ielen) { + pDst->RSN_Cap_present = 0U; + pDst->gp_mgmt_cipher_suite_present = 0U; + pDst->akm_suite_cnt = 1; + DOT11F_MEMCPY(pCtx, pDst->akm_suite, def_akm_suite, 4); + pDst->pmkid_count = 0U; + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->akm_suite_cnt, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (unlikely(ielen < pDst->akm_suite_cnt * 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (!pDst->akm_suite_cnt || + pDst->akm_suite_cnt > 6) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->akm_suite, pBuf, (pDst->akm_suite_cnt * 4)); + pBuf += (pDst->akm_suite_cnt * 4); + ielen -= (pDst->akm_suite_cnt * 4); + if (!ielen) { + pDst->RSN_Cap_present = 0U; + pDst->gp_mgmt_cipher_suite_present = 0U; + pDst->pmkid_count = 0U; + return 0U; + } else { + pDst->RSN_Cap_present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->RSN_Cap, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (!ielen) { + pDst->gp_mgmt_cipher_suite_present = 0U; + pDst->pmkid_count = 0U; + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->pmkid_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (unlikely(ielen < pDst->pmkid_count * 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->pmkid_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->pmkid, pBuf, (pDst->pmkid_count * 16)); + pBuf += (pDst->pmkid_count * 16); + ielen -= (pDst->pmkid_count * 16); + if (!ielen) { + return 0U; + } else { + pDst->gp_mgmt_cipher_suite_present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->gp_mgmt_cipher_suite, pBuf, 4); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsn. */ + +#define SigIeRSN (0x0062) + + +uint32_t dot11f_unpack_ie_rsniie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSNIIE *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->rsni = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsniie. */ + +#define SigIeRSNIIE (0x0063) + + +uint32_t dot11f_unpack_ie_rsn_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIERSNOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_rsn_opaque. */ + +#define SigIeRSNOpaque (0x0064) + + +uint32_t dot11f_unpack_ie_supp_channels(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppChannels *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_bands = (uint8_t)(ielen / 2); + if (ielen > 48 * 2) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bands, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_channels. */ + +#define SigIeSuppChannels (0x0065) + + +uint32_t dot11f_unpack_ie_supp_operating_classes(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppOperatingClasses *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_classes = (uint8_t)(ielen); + if (ielen > 32) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->classes, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_operating_classes. */ + +#define SigIeSuppOperatingClasses (0x0066) + + +uint32_t dot11f_unpack_ie_supp_rates(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIESuppRates *pDst, + bool append_ie) +{ + uint8_t i; + uint8_t rate_indx = 0; + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + for (i = 0; i < ielen; i++) { + if ((DOT11F_IS_BG_RATE(pBuf[i] & 0x7F)) && + (rate_indx < 12)) { + pDst->rates[rate_indx++] = pBuf[i]; + } + } + + if (rate_indx == 0) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + pDst->num_rates = rate_indx; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_supp_rates. */ + +#define SigIeSuppRates (0x0067) + + +uint32_t dot11f_unpack_ie_tim(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETIM *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->dtim_count = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->dtim_period = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->bmpctl = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_vbmp = (uint8_t)(ielen); + if (ielen > 251) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->vbmp, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tim. */ + +#define SigIeTIM (0x0068) + + +uint32_t dot11f_unpack_ie_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETPCReport *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tx_power = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->link_margin = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tpc_report. */ + +#define SigIeTPCReport (0x0069) + + +uint32_t dot11f_unpack_ie_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETPCRequest *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_tpc_request. */ + +#define SigIeTPCRequest (0x006a) + + +uint32_t dot11f_unpack_ie_time_advertisement(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETimeAdvertisement *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->timing_capabilities = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 10)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->time_value, pBuf, 10); + pBuf += 10; + ielen -= (uint8_t)10; + if (unlikely(ielen < 5)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->time_error, pBuf, 5); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_time_advertisement. */ + +#define SigIeTimeAdvertisement (0x006b) + + +uint32_t dot11f_unpack_ie_timeout_interval(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIETimeoutInterval *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->timeoutType = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->timeoutValue, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_timeout_interval. */ + +#define SigIeTimeoutInterval (0x006c) + + +uint32_t dot11f_unpack_ie_vht_ext_bss_load(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVHTExtBssLoad *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->muMIMOCapStaCount = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ssUnderUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->FortyMHzUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->EightyMHzUtil = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->OneSixtyMHzUtil = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vht_ext_bss_load. */ + +#define SigIeVHTExtBssLoad (0x006d) + + +uint32_t dot11f_unpack_ie_vendor1_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVendor1IE *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vendor1_ie. */ + +#define SigIeVendor1IE (0x006e) + + +uint32_t dot11f_unpack_ie_vendor3_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEVendor3IE *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_vendor3_ie. */ + +#define SigIeVendor3IE (0x006f) + + +uint32_t dot11f_unpack_ie_wapi(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWAPI *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp70__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->akm_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < pDst->akm_suite_count * 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->akm_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->akm_suites, pBuf, (pDst->akm_suite_count * 4)); + pBuf += (pDst->akm_suite_count * 4); + ielen -= (pDst->akm_suite_count * 4); + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->unicast_cipher_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < pDst->unicast_cipher_suite_count * 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->unicast_cipher_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->unicast_cipher_suites, pBuf, (pDst->unicast_cipher_suite_count * 4)); + pBuf += (pDst->unicast_cipher_suite_count * 4); + ielen -= (pDst->unicast_cipher_suite_count * 4); + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->multicast_cipher_suite, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp70__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->preauth = tmp70__ >> 0 & 0x1; + pDst->reserved = tmp70__ >> 1 & 0x7fff; + if (!ielen) { + pDst->bkid_count = 0U; + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->bkid_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (unlikely(ielen < pDst->bkid_count * 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->bkid_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->bkid, pBuf, (pDst->bkid_count * 16)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wapi. */ + +#define SigIeWAPI (0x0070) + + +uint32_t dot11f_unpack_ie_wapi_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWAPIOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 253) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wapi_opaque. */ + +#define SigIeWAPIOpaque (0x0071) + + +uint32_t dot11f_unpack_ie_wfatpc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWFATPC *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->txPower = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->linkMargin = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wfatpc. */ + +#define SigIeWFATPC (0x0072) + + +uint32_t dot11f_unpack_ie_wfdie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWFDIEOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wfdie_opaque. */ + +#define SigIeWFDIEOpaque (0x0073) + + +uint32_t dot11f_unpack_ie_wmm_caps(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMCaps *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp71__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp71__ = *pBuf; + pDst->reserved = tmp71__ >> 0 & 0xf; + pDst->qack = tmp71__ >> 4 & 0x1; + pDst->queue_request = tmp71__ >> 5 & 0x1; + pDst->txop_request = tmp71__ >> 6 & 0x1; + pDst->more_ack = tmp71__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_caps. */ + +#define SigIeWMMCaps (0x0074) + + +uint32_t dot11f_unpack_ie_wmm_info_ap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMInfoAp *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp72__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp72__ = *pBuf; + pDst->param_set_count = tmp72__ >> 0 & 0xf; + pDst->reserved = tmp72__ >> 4 & 0x7; + pDst->uapsd = tmp72__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_ap. */ + +#define SigIeWMMInfoAp (0x0075) + + +uint32_t dot11f_unpack_ie_wmm_info_station(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMInfoStation *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp73__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp73__ = *pBuf; + pDst->acvo_uapsd = tmp73__ >> 0 & 0x1; + pDst->acvi_uapsd = tmp73__ >> 1 & 0x1; + pDst->acbk_uapsd = tmp73__ >> 2 & 0x1; + pDst->acbe_uapsd = tmp73__ >> 3 & 0x1; + pDst->reserved1 = tmp73__ >> 4 & 0x1; + pDst->max_sp_length = tmp73__ >> 5 & 0x3; + pDst->reserved2 = tmp73__ >> 7 & 0x1; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_info_station. */ + +#define SigIeWMMInfoStation (0x0076) + + +uint32_t dot11f_unpack_ie_wmm_params(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWMMParams *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp74__; + uint8_t tmp75__; + uint8_t tmp76__; + uint8_t tmp77__; + uint8_t tmp78__; + uint8_t tmp79__; + uint8_t tmp80__; + uint8_t tmp81__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->version = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->qosInfo = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->reserved2 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp74__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp74__ >> 0 & 0xf; + pDst->acbe_acm = tmp74__ >> 4 & 0x1; + pDst->acbe_aci = tmp74__ >> 5 & 0x3; + pDst->unused1 = tmp74__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp75__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp75__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp75__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acbe_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp76__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp76__ >> 0 & 0xf; + pDst->acbk_acm = tmp76__ >> 4 & 0x1; + pDst->acbk_aci = tmp76__ >> 5 & 0x3; + pDst->unused2 = tmp76__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp77__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp77__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp77__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acbk_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp78__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp78__ >> 0 & 0xf; + pDst->acvi_acm = tmp78__ >> 4 & 0x1; + pDst->acvi_aci = tmp78__ >> 5 & 0x3; + pDst->unused3 = tmp78__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp79__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp79__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp79__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acvi_txoplimit, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp80__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp80__ >> 0 & 0xf; + pDst->acvo_acm = tmp80__ >> 4 & 0x1; + pDst->acvo_aci = tmp80__ >> 5 & 0x3; + pDst->unused4 = tmp80__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp81__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp81__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp81__ >> 4 & 0xf; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->acvo_txoplimit, pBuf, 0); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wmm_params. */ + +#define SigIeWMMParams (0x0077) + + +uint32_t dot11f_unpack_ie_wpa(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWPA *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->version, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (pDst->version != 0x1) { + pDst->present = 0; + return status | DOT11F_BAD_FIXED_VALUE; + } + if (!ielen) { + pDst->multicast_cipher_present = 0U; + pDst->unicast_cipher_count = 0U; + pDst->auth_suite_count = 0U; + return 0U; + } else { + pDst->multicast_cipher_present = 1U; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->multicast_cipher, pBuf, 4); + pBuf += 4; + ielen -= (uint8_t)4; + } + if (!ielen) { + pDst->unicast_cipher_count = 0U; + pDst->auth_suite_count = 0U; + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->unicast_cipher_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (unlikely(ielen < pDst->unicast_cipher_count * 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->unicast_cipher_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->unicast_ciphers, pBuf, (pDst->unicast_cipher_count * 4)); + pBuf += (pDst->unicast_cipher_count * 4); + ielen -= (pDst->unicast_cipher_count * 4); + if (!ielen) { + pDst->auth_suite_count = 0U; + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->auth_suite_count, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + } + if (unlikely(ielen < pDst->auth_suite_count * 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->auth_suite_count > 4) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->auth_suites, pBuf, (pDst->auth_suite_count * 4)); + pBuf += (pDst->auth_suite_count * 4); + ielen -= (pDst->auth_suite_count * 4); + if (!ielen) { + return 0U; + } else { + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->caps, pBuf, 0); + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wpa. */ + +#define SigIeWPA (0x0078) + + +uint32_t dot11f_unpack_ie_wpa_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWPAOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wpa_opaque. */ + +#define SigIeWPAOpaque (0x0079) + + +static const tTLVDefn TLVS_WSC[] = { + { offsetof(tDot11fIEWSC, Version), offsetof(tDot11fTLVVersion, present), + "Version", SigTlvVersion, DOT11F_TLV_VERSION, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, WPSState), offsetof(tDot11fTLVWPSState, present), + "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, UUID_E), offsetof(tDot11fTLVUUID_E, present), + "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, UUID_R), offsetof(tDot11fTLVUUID_R, present), + "UUID_R", SigTlvUUID_R, DOT11F_TLV_UUID_R, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RFBands), offsetof(tDot11fTLVRFBands, present), + "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, AssociationState), + offsetof(tDot11fTLVAssociationState, present), "AssociationState", + SigTlvAssociationState, DOT11F_TLV_ASSOCIATIONSTATE, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ConfigurationError), + offsetof(tDot11fTLVConfigurationError, present), "ConfigurationError", + SigTlvConfigurationError, DOT11F_TLV_CONFIGURATIONERROR, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, Manufacturer), offsetof(tDot11fTLVManufacturer, + present), "Manufacturer", SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, + 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ModelName), offsetof(tDot11fTLVModelName, + present), "ModelName", SigTlvModelName, DOT11F_TLV_MODELNAME, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ModelNumber), offsetof(tDot11fTLVModelNumber, + present), "ModelNumber", SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, SerialNumber), offsetof(tDot11fTLVSerialNumber, + present), "SerialNumber", SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, DeviceName), offsetof(tDot11fTLVDeviceName, + present), "DeviceName", SigTlvDeviceName, DOT11F_TLV_DEVICENAME, + 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RequestType), offsetof(tDot11fTLVRequestType, + present), "RequestType", SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, ResponseType), offsetof(tDot11fTLVResponseType, + present), "ResponseType", SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWSC, RequestDeviceType), + offsetof(tDot11fTLVRequestDeviceType, present), "RequestDeviceType", + SigTlvRequestDeviceType, DOT11F_TLV_REQUESTDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWSC *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WSC, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc. */ + +#define SigIeWSC (0x007a) + + +static const tTLVDefn TLVS_WscAssocReq[] = { + { offsetof(tDot11fIEWscAssocReq, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocReq, RequestType), + offsetof(tDot11fTLVRequestType, present), "RequestType", + SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocReq, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscAssocReq *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscAssocReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_assoc_req. */ + +#define SigIeWscAssocReq (0x007b) + + +static const tTLVDefn TLVS_WscAssocRes[] = { + { offsetof(tDot11fIEWscAssocRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscAssocRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscAssocRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscAssocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_assoc_res. */ + +#define SigIeWscAssocRes (0x007c) + + +static const tTLVDefn TLVS_WscBeacon[] = { + { offsetof(tDot11fIEWscBeacon, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, WPSState), offsetof(tDot11fTLVWPSState, + present), "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeacon, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscBeacon *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscBeacon, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_beacon. */ + +#define SigIeWscBeacon (0x007d) + + +static const tTLVDefn TLVS_WscBeaconProbeRes[] = { + { offsetof(tDot11fIEWscBeaconProbeRes, Version), + offsetof(tDot11fTLVVersion, present), "Version", SigTlvVersion, + DOT11F_TLV_VERSION, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, WPSState), + offsetof(tDot11fTLVWPSState, present), "WPSState", SigTlvWPSState, + DOT11F_TLV_WPSSTATE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, UUID_E), + offsetof(tDot11fTLVUUID_E, present), "UUID_E", SigTlvUUID_E, + DOT11F_TLV_UUID_E, 0, 20, 20, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, SerialNumber), + offsetof(tDot11fTLVSerialNumber, present), "SerialNumber", + SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, RFBands), + offsetof(tDot11fTLVRFBands, present), "RFBands", SigTlvRFBands, + DOT11F_TLV_RFBANDS, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscBeaconProbeRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscBeaconProbeRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscBeaconProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_beacon_probe_res. */ + +#define SigIeWscBeaconProbeRes (0x007e) + + +uint32_t dot11f_unpack_ie_wsc_ie_opaque(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscIEOpaque *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 249) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_wsc_ie_opaque. */ + +#define SigIeWscIEOpaque (0x007f) + + +static const tTLVDefn TLVS_WscProbeReq[] = { + { offsetof(tDot11fIEWscProbeReq, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RequestType), + offsetof(tDot11fTLVRequestType, present), "RequestType", + SigTlvRequestType, DOT11F_TLV_REQUESTTYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, AssociationState), + offsetof(tDot11fTLVAssociationState, present), "AssociationState", + SigTlvAssociationState, DOT11F_TLV_ASSOCIATIONSTATE, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ConfigurationError), + offsetof(tDot11fTLVConfigurationError, present), "ConfigurationError", + SigTlvConfigurationError, DOT11F_TLV_CONFIGURATIONERROR, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeReq, RequestDeviceType), + offsetof(tDot11fTLVRequestDeviceType, present), "RequestDeviceType", + SigTlvRequestDeviceType, DOT11F_TLV_REQUESTDEVICETYPE, + 0, 12, 12, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_probe_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscProbeReq *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscProbeReq, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_probe_req. */ + +#define SigIeWscProbeReq (0x0080) + + +static const tTLVDefn TLVS_WscProbeRes[] = { + { offsetof(tDot11fIEWscProbeRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, WPSState), offsetof(tDot11fTLVWPSState, + present), "WPSState", SigTlvWPSState, DOT11F_TLV_WPSSTATE, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, APSetupLocked), + offsetof(tDot11fTLVAPSetupLocked, present), "APSetupLocked", + SigTlvAPSetupLocked, DOT11F_TLV_APSETUPLOCKED, 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SelectedRegistrar), + offsetof(tDot11fTLVSelectedRegistrar, present), "SelectedRegistrar", + SigTlvSelectedRegistrar, DOT11F_TLV_SELECTEDREGISTRAR, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, DevicePasswordID), + offsetof(tDot11fTLVDevicePasswordID, present), "DevicePasswordID", + SigTlvDevicePasswordID, DOT11F_TLV_DEVICEPASSWORDID, + 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SelectedRegistrarConfigMethods), + offsetof(tDot11fTLVSelectedRegistrarConfigMethods, present), + "SelectedRegistrarConfigMethods", SigTlvSelectedRegistrarConfigMethods, + DOT11F_TLV_SELECTEDREGISTRARCONFIGMETHODS, 0, 6, 6, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, UUID_E), offsetof(tDot11fTLVUUID_E, + present), "UUID_E", SigTlvUUID_E, DOT11F_TLV_UUID_E, + 0, 20, 20, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, Manufacturer), + offsetof(tDot11fTLVManufacturer, present), "Manufacturer", + SigTlvManufacturer, DOT11F_TLV_MANUFACTURER, 0, 4, 68, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ModelName), + offsetof(tDot11fTLVModelName, present), "ModelName", SigTlvModelName, + DOT11F_TLV_MODELNAME, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ModelNumber), + offsetof(tDot11fTLVModelNumber, present), "ModelNumber", + SigTlvModelNumber, DOT11F_TLV_MODELNUMBER, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, SerialNumber), + offsetof(tDot11fTLVSerialNumber, present), "SerialNumber", + SigTlvSerialNumber, DOT11F_TLV_SERIALNUMBER, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, PrimaryDeviceType), + offsetof(tDot11fTLVPrimaryDeviceType, present), "PrimaryDeviceType", + SigTlvPrimaryDeviceType, DOT11F_TLV_PRIMARYDEVICETYPE, + 0, 12, 12, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, DeviceName), + offsetof(tDot11fTLVDeviceName, present), "DeviceName", SigTlvDeviceName, + DOT11F_TLV_DEVICENAME, 0, 4, 36, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, ConfigMethods), + offsetof(tDot11fTLVConfigMethods, present), "ConfigMethods", + SigTlvConfigMethods, DOT11F_TLV_CONFIGMETHODS, 0, 6, 6, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, RFBands), offsetof(tDot11fTLVRFBands, + present), "RFBands", SigTlvRFBands, DOT11F_TLV_RFBANDS, + 0, 5, 5, 0, 2, 2, 1, }, + { offsetof(tDot11fIEWscProbeRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_probe_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscProbeRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscProbeRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_probe_res. */ + +#define SigIeWscProbeRes (0x0081) + + +static const tTLVDefn TLVS_WscReassocRes[] = { + { offsetof(tDot11fIEWscReassocRes, Version), offsetof(tDot11fTLVVersion, + present), "Version", SigTlvVersion, DOT11F_TLV_VERSION, + 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscReassocRes, ResponseType), + offsetof(tDot11fTLVResponseType, present), "ResponseType", + SigTlvResponseType, DOT11F_TLV_RESPONSETYPE, 0, 5, 5, 1, 2, 2, 1, }, + { offsetof(tDot11fIEWscReassocRes, VendorExtension), + offsetof(tDot11fTLVVendorExtension, present), "VendorExtension", + SigTlvVendorExtension, DOT11F_TLV_VENDOREXTENSION, + 0, 7, 21, 0, 2, 2, 1, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEWscReassocRes *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_WscReassocRes, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_wsc_reassoc_res. */ + +#define SigIeWscReassocRes (0x0082) + + +uint32_t dot11f_unpack_ie_addba_extn_element(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEaddba_extn_element *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp82__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp82__ = *pBuf; + pDst->no_fragmentation = tmp82__ >> 0 & 0x1; + pDst->he_frag_operation = tmp82__ >> 1 & 0x3; + pDst->reserved = tmp82__ >> 3 & 0x3; + pDst->extd_buff_size = tmp82__ >> 5 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_addba_extn_element. */ + +#define SigIeaddba_extn_element (0x0083) + + +uint32_t dot11f_unpack_ie_bss_color_change(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEbss_color_change *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp83__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->countdown = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp83__ = *pBuf; + pDst->new_color = tmp83__ >> 0 & 0x3f; + pDst->reserved = tmp83__ >> 6 & 0x3; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bss_color_change. */ + +#define SigIebss_color_change (0x0084) + + +uint32_t dot11f_unpack_ie_bss_max_idle_period(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEbss_max_idle_period *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp84__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->max_idle_period, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp84__ = *pBuf; + pDst->prot_keep_alive_reqd = tmp84__ >> 0 & 0x1; + pDst->reserved = tmp84__ >> 1 & 0x7f; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_bss_max_idle_period. */ + +#define SigIebss_max_idle_period (0x0085) + + +static const tFFDefn FFS_descriptor_element[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_descriptor_element[] = { + { offsetof(tDot11fIEdescriptor_element, tclas_mask), + offsetof(tDot11fIEtclas_mask, present), 0, "tclas_mask", + 0, 20, 20, SigIetclas_mask, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLAS_MASK, 89, 0, }, + { offsetof(tDot11fIEdescriptor_element, mscs_status), + offsetof(tDot11fIEmscs_status, present), 0, "mscs_status", + 0, 3, 3, SigIemscs_status, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MSCS_STATUS, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_descriptor_element(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEdescriptor_element *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->request_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->user_priority_control, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->stream_timeout, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_descriptor_element, + IES_descriptor_element, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_descriptor_element. */ + +#define SigIedescriptor_element (0x0086) + + +uint32_t dot11f_unpack_ie_dh_parameter_element(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEdh_parameter_element *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->group, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + pDst->num_public_key = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->public_key, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_dh_parameter_element. */ + +#define SigIedh_parameter_element (0x0087) + + +uint32_t dot11f_unpack_ie_eht_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEeht_cap *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp85__; + uint32_t tmp86__; + uint32_t tmp87__; + uint8_t tmp88__; + uint32_t tmp89__; + uint32_t tmp90__; + uint32_t tmp91__; + uint8_t tmp92__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp85__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->epcs_pri_access = tmp85__ >> 0 & 0x1; + pDst->eht_om_ctl = tmp85__ >> 1 & 0x1; + pDst->triggered_txop_sharing_mode1 = tmp85__ >> 2 & 0x1; + pDst->triggered_txop_sharing_mode2 = tmp85__ >> 3 & 0x1; + pDst->restricted_twt = tmp85__ >> 4 & 0x1; + pDst->scs_traffic_desc = tmp85__ >> 5 & 0x1; + pDst->max_mpdu_len = tmp85__ >> 6 & 0x3; + pDst->max_a_mpdu_len_exponent_ext = tmp85__ >> 8 & 0x1; + pDst->eht_trs_support = tmp85__ >> 9 & 0x1; + pDst->txop_return_support_txop_share_m2 = tmp85__ >> 10 & 0x1; + pDst->two_bqrs_support = tmp85__ >> 11 & 0x1; + pDst->eht_link_adaptation_support = tmp85__ >> 12 & 0x3; + pDst->reserved = tmp85__ >> 14 & 0x3; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp86__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->reserved2 = tmp86__ >> 0 & 0x1; + pDst->support_320mhz_6ghz = tmp86__ >> 1 & 0x1; + pDst->ru_242tone_wt_20mhz = tmp86__ >> 2 & 0x1; + pDst->ndp_4x_eht_ltf_3dot2_us_gi = tmp86__ >> 3 & 0x1; + pDst->partial_bw_mu_mimo = tmp86__ >> 4 & 0x1; + pDst->su_beamformer = tmp86__ >> 5 & 0x1; + pDst->su_beamformee = tmp86__ >> 6 & 0x1; + pDst->bfee_ss_le_80mhz = tmp86__ >> 7 & 0x7; + pDst->bfee_ss_160mhz = tmp86__ >> 10 & 0x7; + pDst->bfee_ss_320mhz = tmp86__ >> 13 & 0x7; + pDst->num_sounding_dim_le_80mhz = tmp86__ >> 16 & 0x7; + pDst->num_sounding_dim_160mhz = tmp86__ >> 19 & 0x7; + pDst->num_sounding_dim_320mhz = tmp86__ >> 22 & 0x7; + pDst->ng_16_su_feedback = tmp86__ >> 25 & 0x1; + pDst->ng_16_mu_feedback = tmp86__ >> 26 & 0x1; + pDst->cb_sz_4_2_su_feedback = tmp86__ >> 27 & 0x1; + pDst->cb_sz_7_5_su_feedback = tmp86__ >> 28 & 0x1; + pDst->trig_su_bforming_feedback = tmp86__ >> 29 & 0x1; + pDst->trig_mu_bforming_partial_bw_feedback = tmp86__ >> 30 & 0x1; + pDst->triggered_cqi_feedback = tmp86__ >> 31 & 0x1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp87__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->partial_bw_dl_mu_mimo = tmp87__ >> 0 & 0x1; + pDst->psr_based_sr = tmp87__ >> 1 & 0x1; + pDst->power_boost_factor = tmp87__ >> 2 & 0x1; + pDst->eht_mu_ppdu_4x_ltf_0_8_us_gi = tmp87__ >> 3 & 0x1; + pDst->max_nc = tmp87__ >> 4 & 0xf; + pDst->non_trig_cqi_feedback = tmp87__ >> 8 & 0x1; + pDst->tx_1024_4096_qam_lt_242_tone_ru = tmp87__ >> 9 & 0x1; + pDst->rx_1024_4096_qam_lt_242_tone_ru = tmp87__ >> 10 & 0x1; + pDst->ppet_present = tmp87__ >> 11 & 0x1; + pDst->common_nominal_pkt_padding = tmp87__ >> 12 & 0x3; + pDst->max_num_eht_ltf = tmp87__ >> 14 & 0x1f; + pDst->mcs_15 = tmp87__ >> 19 & 0xf; + pDst->eht_dup_6ghz = tmp87__ >> 23 & 0x1; + pDst->op_sta_rx_ndp_wider_bw_20mhz = tmp87__ >> 24 & 0x1; + pDst->non_ofdma_ul_mu_mimo_le_80mhz = tmp87__ >> 25 & 0x1; + pDst->non_ofdma_ul_mu_mimo_160mhz = tmp87__ >> 26 & 0x1; + pDst->non_ofdma_ul_mu_mimo_320mhz = tmp87__ >> 27 & 0x1; + pDst->mu_bformer_le_80mhz = tmp87__ >> 28 & 0x1; + pDst->mu_bformer_160mhz = tmp87__ >> 29 & 0x1; + pDst->mu_bformer_320mhz = tmp87__ >> 30 & 0x1; + pDst->tb_sounding_feedback_rl = tmp87__ >> 31 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp88__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->rx_1k_qam_in_wider_bw_dl_ofdma = tmp88__ >> 0 & 0x1; + pDst->rx_4k_qam_in_wider_bw_dl_ofdma = tmp88__ >> 1 & 0x1; + pDst->limited_cap_support_20mhz = tmp88__ >> 2 & 0x1; + pDst->triggered_mu_bf_full_bw_fb_and_dl_mumimo = tmp88__ >> 3 & 0x1; + pDst->mru_support_20mhz = tmp88__ >> 4 & 0x1; + pDst->reserved3 = tmp88__ >> 5 & 0x7; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp89__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->bw_20_rx_max_nss_for_mcs_0_to_7 = tmp89__ >> 0 & 0xf; + pDst->bw_20_tx_max_nss_for_mcs_0_to_7 = tmp89__ >> 4 & 0xf; + pDst->bw_20_rx_max_nss_for_mcs_8_and_9 = tmp89__ >> 8 & 0xf; + pDst->bw_20_tx_max_nss_for_mcs_8_and_9 = tmp89__ >> 12 & 0xf; + pDst->bw_20_rx_max_nss_for_mcs_10_and_11 = tmp89__ >> 16 & 0xf; + pDst->bw_20_tx_max_nss_for_mcs_10_and_11 = tmp89__ >> 20 & 0xf; + pDst->bw_20_rx_max_nss_for_mcs_12_and_13 = tmp89__ >> 24 & 0xf; + pDst->bw_20_tx_max_nss_for_mcs_12_and_13 = tmp89__ >> 28 & 0xf; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp90__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->bw_le_80_rx_max_nss_for_mcs_0_to_9 = tmp90__ >> 0 & 0xf; + pDst->bw_le_80_tx_max_nss_for_mcs_0_to_9 = tmp90__ >> 4 & 0xf; + pDst->bw_le_80_rx_max_nss_for_mcs_10_and_11 = tmp90__ >> 8 & 0xf; + pDst->bw_le_80_tx_max_nss_for_mcs_10_and_11 = tmp90__ >> 12 & 0xf; + pDst->bw_le_80_rx_max_nss_for_mcs_12_and_13 = tmp90__ >> 16 & 0xf; + pDst->bw_le_80_tx_max_nss_for_mcs_12_and_13 = tmp90__ >> 20 & 0xf; + pDst->bw_160_rx_max_nss_for_mcs_0_to_9 = tmp90__ >> 24 & 0xf; + pDst->bw_160_tx_max_nss_for_mcs_0_to_9 = tmp90__ >> 28 & 0xf; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp91__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->bw_160_rx_max_nss_for_mcs_10_and_11 = tmp91__ >> 0 & 0xf; + pDst->bw_160_tx_max_nss_for_mcs_10_and_11 = tmp91__ >> 4 & 0xf; + pDst->bw_160_rx_max_nss_for_mcs_12_and_13 = tmp91__ >> 8 & 0xf; + pDst->bw_160_tx_max_nss_for_mcs_12_and_13 = tmp91__ >> 12 & 0xf; + pDst->bw_320_rx_max_nss_for_mcs_0_to_9 = tmp91__ >> 16 & 0xf; + pDst->bw_320_tx_max_nss_for_mcs_0_to_9 = tmp91__ >> 20 & 0xf; + pDst->bw_320_rx_max_nss_for_mcs_10_and_11 = tmp91__ >> 24 & 0xf; + pDst->bw_320_tx_max_nss_for_mcs_10_and_11 = tmp91__ >> 28 & 0xf; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp92__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->bw_320_rx_max_nss_for_mcs_12_and_13 = tmp92__ >> 0 & 0xf; + pDst->bw_320_tx_max_nss_for_mcs_12_and_13 = tmp92__ >> 4 & 0xf; + switch (pDst->ppet_present) { + case 1: + pDst->ppet.ppe_threshold.num_ppe_th = (uint8_t)(ielen); + if (ielen > 62) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ppet.ppe_threshold.ppe_th, pBuf, (ielen)); + pBuf += (ielen); + ielen -= (ielen); + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_eht_cap. */ + +#define SigIeeht_cap (0x0088) + + +uint32_t dot11f_unpack_ie_eht_op(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEeht_op *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp93__; + uint32_t tmp94__; + uint8_t tmp95__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp93__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->eht_op_information_present = tmp93__ >> 0 & 0x1; + pDst->disabled_sub_chan_bitmap_present = tmp93__ >> 1 & 0x1; + pDst->eht_default_pe_duration = tmp93__ >> 2 & 0x1; + pDst->group_addr_bu_indication_limit = tmp93__ >> 3 & 0x1; + pDst->group_addr_bu_indication_exponent = tmp93__ >> 4 & 0x3; + pDst->reserved = tmp93__ >> 6 & 0x3; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp94__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->basic_rx_max_nss_for_mcs_0_to_7 = tmp94__ >> 0 & 0xf; + pDst->basic_tx_max_nss_for_mcs_0_to_7 = tmp94__ >> 4 & 0xf; + pDst->basic_rx_max_nss_for_mcs_8_and_9 = tmp94__ >> 8 & 0xf; + pDst->basic_tx_max_nss_for_mcs_8_and_9 = tmp94__ >> 12 & 0xf; + pDst->basic_rx_max_nss_for_mcs_10_and_11 = tmp94__ >> 16 & 0xf; + pDst->basic_tx_max_nss_for_mcs_10_and_11 = tmp94__ >> 20 & 0xf; + pDst->basic_rx_max_nss_for_mcs_12_and_13 = tmp94__ >> 24 & 0xf; + pDst->basic_tx_max_nss_for_mcs_12_and_13 = tmp94__ >> 28 & 0xf; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp95__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->channel_width = tmp95__ >> 0 & 0x7; + pDst->reserved_1 = tmp95__ >> 3 & 0x1f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ccfs0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->ccfs1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < pDst->disabled_sub_chan_bitmap_present * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->disabled_sub_chan_bitmap_present > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->disabled_sub_chan_bitmap, pBuf, (pDst->disabled_sub_chan_bitmap_present * 2)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_eht_op. */ + +#define SigIeeht_op (0x0089) + + +uint32_t dot11f_unpack_ie_esp_information(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEesp_information *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + if (ielen > 96) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_esp_information. */ + +#define SigIeesp_information (0x008a) + + +uint32_t dot11f_unpack_ie_ext_chan_switch_ann(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEext_chan_switch_ann *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->switch_mode = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->new_reg_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->new_channel = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->switch_count = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ext_chan_switch_ann. */ + +#define SigIeext_chan_switch_ann (0x008b) + + +uint32_t dot11f_unpack_ie_fils_assoc_delay_info(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_assoc_delay_info *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->assoc_delay_info = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_assoc_delay_info. */ + +#define SigIefils_assoc_delay_info (0x008c) + + +uint32_t dot11f_unpack_ie_fils_hlp_container(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_hlp_container *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->dest_mac, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->src_mac, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + pDst->num_hlp_packet = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->hlp_packet, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_hlp_container. */ + +#define SigIefils_hlp_container (0x008d) + + +uint32_t dot11f_unpack_ie_fils_indication(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_indication *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp96__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp96__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->public_key_identifiers_cnt = tmp96__ >> 0 & 0x7; + pDst->realm_identifiers_cnt = tmp96__ >> 3 & 0x7; + pDst->is_ip_config_supported = tmp96__ >> 6 & 0x1; + pDst->is_cache_id_present = tmp96__ >> 7 & 0x1; + pDst->is_hessid_present = tmp96__ >> 8 & 0x1; + pDst->is_fils_sk_auth_supported = tmp96__ >> 9 & 0x1; + pDst->is_fils_sk_auth_pfs_supported = tmp96__ >> 10 & 0x1; + pDst->is_pk_auth_supported = tmp96__ >> 11 & 0x1; + pDst->reserved = tmp96__ >> 12 & 0xf; + pDst->num_variable_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->variable_data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_indication. */ + +#define SigIefils_indication (0x008e) + + +uint32_t dot11f_unpack_ie_fils_kde(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_kde *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->key_rsc, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + pDst->num_kde_list = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->kde_list, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_kde. */ + +#define SigIefils_kde (0x008f) + + +uint32_t dot11f_unpack_ie_fils_key_confirmation(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_key_confirmation *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_key_auth = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->key_auth, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_key_confirmation. */ + +#define SigIefils_key_confirmation (0x0090) + + +uint32_t dot11f_unpack_ie_fils_nonce(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_nonce *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 16)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->nonce, pBuf, 16); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_nonce. */ + +#define SigIefils_nonce (0x0091) + + +uint32_t dot11f_unpack_ie_fils_public_key(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_public_key *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->key_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_public_key = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->public_key, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_public_key. */ + +#define SigIefils_public_key (0x0092) + + +uint32_t dot11f_unpack_ie_fils_session(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_session *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->session, pBuf, 8); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_session. */ + +#define SigIefils_session (0x0093) + + +uint32_t dot11f_unpack_ie_fils_wrapped_data(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfils_wrapped_data *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_wrapped_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->wrapped_data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fils_wrapped_data. */ + +#define SigIefils_wrapped_data (0x0094) + + +uint32_t dot11f_unpack_ie_fragment_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEfragment_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_fragment_ie. */ + +#define SigIefragment_ie (0x0095) + + +uint32_t dot11f_unpack_ie_he_6ghz_band_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEhe_6ghz_band_cap *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp97__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp97__, pBuf, 0); + pDst->min_mpdu_start_spacing = tmp97__ >> 0 & 0x7; + pDst->max_ampdu_len_exp = tmp97__ >> 3 & 0x7; + pDst->max_mpdu_len = tmp97__ >> 6 & 0x7; + pDst->sm_pow_save = tmp97__ >> 9 & 0x3; + pDst->rd_responder = tmp97__ >> 11 & 0x1; + pDst->rx_ant_pattern_consistency = tmp97__ >> 12 & 0x1; + pDst->tx_ant_pattern_consistency = tmp97__ >> 13 & 0x1; + pDst->reserved = tmp97__ >> 14 & 0x3; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_he_6ghz_band_cap. */ + +#define SigIehe_6ghz_band_cap (0x0096) + + +uint32_t dot11f_unpack_ie_he_cap(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEhe_cap *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t tmp98__; + uint16_t tmp99__; + uint32_t tmp100__; + uint32_t tmp101__; + uint16_t tmp102__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp98__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->htc_he = tmp98__ >> 0 & 0x1; + pDst->twt_request = tmp98__ >> 1 & 0x1; + pDst->twt_responder = tmp98__ >> 2 & 0x1; + pDst->fragmentation = tmp98__ >> 3 & 0x3; + pDst->max_num_frag_msdu_amsdu_exp = tmp98__ >> 5 & 0x7; + pDst->min_frag_size = tmp98__ >> 8 & 0x3; + pDst->trigger_frm_mac_pad = tmp98__ >> 10 & 0x3; + pDst->multi_tid_aggr_rx_supp = tmp98__ >> 12 & 0x7; + pDst->he_link_adaptation = tmp98__ >> 15 & 0x3; + pDst->all_ack = tmp98__ >> 17 & 0x1; + pDst->trigd_rsp_sched = tmp98__ >> 18 & 0x1; + pDst->a_bsr = tmp98__ >> 19 & 0x1; + pDst->broadcast_twt = tmp98__ >> 20 & 0x1; + pDst->ba_32bit_bitmap = tmp98__ >> 21 & 0x1; + pDst->mu_cascade = tmp98__ >> 22 & 0x1; + pDst->ack_enabled_multitid = tmp98__ >> 23 & 0x1; + pDst->reserved = tmp98__ >> 24 & 0x1; + pDst->omi_a_ctrl = tmp98__ >> 25 & 0x1; + pDst->ofdma_ra = tmp98__ >> 26 & 0x1; + pDst->max_ampdu_len_exp_ext = tmp98__ >> 27 & 0x3; + pDst->amsdu_frag = tmp98__ >> 29 & 0x1; + pDst->flex_twt_sched = tmp98__ >> 30 & 0x1; + pDst->rx_ctrl_frame = tmp98__ >> 31 & 0x1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp99__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->bsrp_ampdu_aggr = tmp99__ >> 0 & 0x1; + pDst->qtp = tmp99__ >> 1 & 0x1; + pDst->a_bqr = tmp99__ >> 2 & 0x1; + pDst->spatial_reuse_param_rspder = tmp99__ >> 3 & 0x1; + pDst->ndp_feedback_supp = tmp99__ >> 4 & 0x1; + pDst->ops_supp = tmp99__ >> 5 & 0x1; + pDst->amsdu_in_ampdu = tmp99__ >> 6 & 0x1; + pDst->multi_tid_aggr_tx_supp = tmp99__ >> 7 & 0x7; + pDst->he_sub_ch_sel_tx_supp = tmp99__ >> 10 & 0x1; + pDst->ul_2x996_tone_ru_supp = tmp99__ >> 11 & 0x1; + pDst->om_ctrl_ul_mu_data_dis_rx = tmp99__ >> 12 & 0x1; + pDst->he_dynamic_smps = tmp99__ >> 13 & 0x1; + pDst->punctured_sounding_supp = tmp99__ >> 14 & 0x1; + pDst->ht_vht_trg_frm_rx_supp = tmp99__ >> 15 & 0x1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp100__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->reserved2 = tmp100__ >> 0 & 0x1; + pDst->chan_width_0 = tmp100__ >> 1 & 0x1; + pDst->chan_width_1 = tmp100__ >> 2 & 0x1; + pDst->chan_width_2 = tmp100__ >> 3 & 0x1; + pDst->chan_width_3 = tmp100__ >> 4 & 0x1; + pDst->chan_width_4 = tmp100__ >> 5 & 0x1; + pDst->chan_width_5 = tmp100__ >> 6 & 0x1; + pDst->chan_width_6 = tmp100__ >> 7 & 0x1; + pDst->rx_pream_puncturing = tmp100__ >> 8 & 0xf; + pDst->device_class = tmp100__ >> 12 & 0x1; + pDst->ldpc_coding = tmp100__ >> 13 & 0x1; + pDst->he_1x_ltf_800_gi_ppdu = tmp100__ >> 14 & 0x1; + pDst->midamble_tx_rx_max_nsts = tmp100__ >> 15 & 0x3; + pDst->he_4x_ltf_3200_gi_ndp = tmp100__ >> 17 & 0x1; + pDst->tb_ppdu_tx_stbc_lt_80mhz = tmp100__ >> 18 & 0x1; + pDst->rx_stbc_lt_80mhz = tmp100__ >> 19 & 0x1; + pDst->doppler = tmp100__ >> 20 & 0x3; + pDst->ul_mu = tmp100__ >> 22 & 0x3; + pDst->dcm_enc_tx = tmp100__ >> 24 & 0x7; + pDst->dcm_enc_rx = tmp100__ >> 27 & 0x7; + pDst->ul_he_mu = tmp100__ >> 30 & 0x1; + pDst->su_beamformer = tmp100__ >> 31 & 0x1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &tmp101__, pBuf, 0); + pBuf += 4; + ielen -= 4; + pDst->su_beamformee = tmp101__ >> 0 & 0x1; + pDst->mu_beamformer = tmp101__ >> 1 & 0x1; + pDst->bfee_sts_lt_80 = tmp101__ >> 2 & 0x7; + pDst->bfee_sts_gt_80 = tmp101__ >> 5 & 0x7; + pDst->num_sounding_lt_80 = tmp101__ >> 8 & 0x7; + pDst->num_sounding_gt_80 = tmp101__ >> 11 & 0x7; + pDst->su_feedback_tone16 = tmp101__ >> 14 & 0x1; + pDst->mu_feedback_tone16 = tmp101__ >> 15 & 0x1; + pDst->codebook_su = tmp101__ >> 16 & 0x1; + pDst->codebook_mu = tmp101__ >> 17 & 0x1; + pDst->beamforming_feedback = tmp101__ >> 18 & 0x7; + pDst->he_er_su_ppdu = tmp101__ >> 21 & 0x1; + pDst->dl_mu_mimo_part_bw = tmp101__ >> 22 & 0x1; + pDst->ppet_present = tmp101__ >> 23 & 0x1; + pDst->srp = tmp101__ >> 24 & 0x1; + pDst->power_boost = tmp101__ >> 25 & 0x1; + pDst->he_ltf_800_gi_4x = tmp101__ >> 26 & 0x1; + pDst->max_nc = tmp101__ >> 27 & 0x7; + pDst->tb_ppdu_tx_stbc_gt_80mhz = tmp101__ >> 30 & 0x1; + pDst->rx_stbc_gt_80mhz = tmp101__ >> 31 & 0x1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp102__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->er_he_ltf_800_gi_4x = tmp102__ >> 0 & 0x1; + pDst->he_ppdu_20_in_40Mhz_2G = tmp102__ >> 1 & 0x1; + pDst->he_ppdu_20_in_160_80p80Mhz = tmp102__ >> 2 & 0x1; + pDst->he_ppdu_80_in_160_80p80Mhz = tmp102__ >> 3 & 0x1; + pDst->er_1x_he_ltf_gi = tmp102__ >> 4 & 0x1; + pDst->midamble_tx_rx_1x_he_ltf = tmp102__ >> 5 & 0x1; + pDst->dcm_max_bw = tmp102__ >> 6 & 0x3; + pDst->longer_than_16_he_sigb_ofdm_sym = tmp102__ >> 8 & 0x1; + pDst->non_trig_cqi_feedback = tmp102__ >> 9 & 0x1; + pDst->tx_1024_qam_lt_242_tone_ru = tmp102__ >> 10 & 0x1; + pDst->rx_1024_qam_lt_242_tone_ru = tmp102__ >> 11 & 0x1; + pDst->rx_full_bw_su_he_mu_compress_sigb = tmp102__ >> 12 & 0x1; + pDst->rx_full_bw_su_he_mu_non_cmpr_sigb = tmp102__ >> 13 & 0x1; + pDst->reserved3 = tmp102__ >> 14 & 0x3; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->reserved4 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->rx_he_mcs_map_lt_80, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->tx_he_mcs_map_lt_80, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + if (unlikely(ielen < pDst->chan_width_2 * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->chan_width_2 > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rx_he_mcs_map_160, pBuf, (pDst->chan_width_2 * 2)); + pBuf += (pDst->chan_width_2 * 2); + ielen -= (pDst->chan_width_2 * 2); + if (unlikely(ielen < pDst->chan_width_2 * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->chan_width_2 > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tx_he_mcs_map_160, pBuf, (pDst->chan_width_2 * 2)); + pBuf += (pDst->chan_width_2 * 2); + ielen -= (pDst->chan_width_2 * 2); + if (unlikely(ielen < pDst->chan_width_3 * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->chan_width_3 > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->rx_he_mcs_map_80_80, pBuf, (pDst->chan_width_3 * 2)); + pBuf += (pDst->chan_width_3 * 2); + ielen -= (pDst->chan_width_3 * 2); + if (unlikely(ielen < pDst->chan_width_3 * 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + if (pDst->chan_width_3 > 1) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tx_he_mcs_map_80_80, pBuf, (pDst->chan_width_3 * 2)); + pBuf += (pDst->chan_width_3 * 2); + ielen -= (pDst->chan_width_3 * 2); + switch (pDst->ppet_present) { + case 1: + pDst->ppet.ppe_threshold.num_ppe_th = (uint8_t)(ielen); + if (ielen > 25) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->ppet.ppe_threshold.ppe_th, pBuf, (ielen)); + pBuf += (ielen); + ielen -= (ielen); + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_he_cap. */ + +#define SigIehe_cap (0x0097) + + +uint32_t dot11f_unpack_ie_he_op(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEhe_op *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp103__; + uint8_t tmp104__; + uint8_t tmp105__; + uint8_t tmp106__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp103__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->default_pe = tmp103__ >> 0 & 0x7; + pDst->twt_required = tmp103__ >> 3 & 0x1; + pDst->txop_rts_threshold = tmp103__ >> 4 & 0x3ff; + pDst->vht_oper_present = tmp103__ >> 14 & 0x1; + pDst->co_located_bss = tmp103__ >> 15 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp104__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->er_su_disable = tmp104__ >> 0 & 0x1; + pDst->oper_info_6g_present = tmp104__ >> 1 & 0x1; + pDst->reserved2 = tmp104__ >> 2 & 0x3f; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp105__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->bss_color = tmp105__ >> 0 & 0x3f; + pDst->partial_bss_col = tmp105__ >> 6 & 0x1; + pDst->bss_col_disabled = tmp105__ >> 7 & 0x1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->basic_mcs_nss, pBuf, 2); + pBuf += 2; + ielen -= (uint8_t)2; + switch (pDst->vht_oper_present) { + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->vht_oper.info.chan_width = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->vht_oper.info.center_freq_seg0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->vht_oper.info.center_freq_seg1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + } + switch (pDst->co_located_bss) { + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->maxbssid_ind.info.data = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + } + switch (pDst->oper_info_6g_present) { + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->oper_info_6g.info.primary_ch = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp106__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->oper_info_6g.info.ch_width = tmp106__ >> 0 & 0x3; + pDst->oper_info_6g.info.dup_bcon = tmp106__ >> 2 & 0x1; + pDst->oper_info_6g.info.reg_info = tmp106__ >> 3 & 0x7; + pDst->oper_info_6g.info.reserved = tmp106__ >> 6 & 0x3; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->oper_info_6g.info.center_freq_seg0 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->oper_info_6g.info.center_freq_seg1 = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->oper_info_6g.info.min_rate = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_he_op. */ + +#define SigIehe_op (0x0098) + + +uint32_t dot11f_unpack_ie_hs20vendor_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEhs20vendor_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp107__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp107__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->dgaf_dis = tmp107__ >> 0 & 0x1; + pDst->hs_id_present = tmp107__ >> 1 & 0x3; + pDst->reserved = tmp107__ >> 3 & 0x1; + pDst->release_num = tmp107__ >> 4 & 0xf; + if (!ielen) { + return 0U; + } else { + switch (pDst->hs_id_present) { + case 1: + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->hs_id.pps_mo.pps_mo_id, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + case 2: + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &pDst->hs_id.anqp_domain.anqp_domain_id, pBuf, 0); + pBuf += 2; + ielen -= (uint8_t)2; + break; + } + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_hs20vendor_ie. */ + +#define SigIehs20vendor_ie (0x0099) + + +uint32_t dot11f_unpack_ie_ht2040_bss_coexistence(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEht2040_bss_coexistence *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp108__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp108__ = *pBuf; + pDst->info_request = tmp108__ >> 0 & 0x1; + pDst->forty_mhz_intolerant = tmp108__ >> 1 & 0x1; + pDst->twenty_mhz_bsswidth_req = tmp108__ >> 2 & 0x1; + pDst->obss_scan_exemption_req = tmp108__ >> 3 & 0x1; + pDst->obss_scan_exemption_grant = tmp108__ >> 4 & 0x1; + pDst->unused = tmp108__ >> 5 & 0x7; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_coexistence. */ + +#define SigIeht2040_bss_coexistence (0x009a) + + +uint32_t dot11f_unpack_ie_ht2040_bss_intolerant_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEht2040_bss_intolerant_report *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->operating_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + pDst->num_channel_list = (uint8_t)(ielen); + if (ielen > 50) { + pDst->present = 0; + return DOT11F_SKIPPED_BAD_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->channel_list, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_ht2040_bss_intolerant_report. */ + +#define SigIeht2040_bss_intolerant_report (0x009b) + + +uint32_t dot11f_unpack_ie_max_chan_switch_time(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEmax_chan_switch_time *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 3)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->switch_time, pBuf, 3); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_max_chan_switch_time. */ + +#define SigIemax_chan_switch_time (0x009c) + + +uint32_t dot11f_unpack_ie_mlo_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEmlo_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mlo_ie. */ + +#define SigIemlo_ie (0x009d) + + +uint32_t dot11f_unpack_ie_mu_edca_param_set(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEmu_edca_param_set *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp109__; + uint8_t tmp110__; + uint8_t tmp111__; + uint8_t tmp112__; + uint8_t tmp113__; + uint8_t tmp114__; + uint8_t tmp115__; + uint8_t tmp116__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->qos = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp109__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_aifsn = tmp109__ >> 0 & 0xf; + pDst->acbe_acm = tmp109__ >> 4 & 0x1; + pDst->acbe_aci = tmp109__ >> 5 & 0x3; + pDst->unused1 = tmp109__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp110__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbe_acwmin = tmp110__ >> 0 & 0xf; + pDst->acbe_acwmax = tmp110__ >> 4 & 0xf; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->acbe_muedca_timer = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp111__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_aifsn = tmp111__ >> 0 & 0xf; + pDst->acbk_acm = tmp111__ >> 4 & 0x1; + pDst->acbk_aci = tmp111__ >> 5 & 0x3; + pDst->unused2 = tmp111__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp112__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acbk_acwmin = tmp112__ >> 0 & 0xf; + pDst->acbk_acwmax = tmp112__ >> 4 & 0xf; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->acbk_muedca_timer = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp113__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_aifsn = tmp113__ >> 0 & 0xf; + pDst->acvi_acm = tmp113__ >> 4 & 0x1; + pDst->acvi_aci = tmp113__ >> 5 & 0x3; + pDst->unused3 = tmp113__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp114__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvi_acwmin = tmp114__ >> 0 & 0xf; + pDst->acvi_acwmax = tmp114__ >> 4 & 0xf; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->acvi_muedca_timer = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp115__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_aifsn = tmp115__ >> 0 & 0xf; + pDst->acvo_acm = tmp115__ >> 4 & 0x1; + pDst->acvo_aci = tmp115__ >> 5 & 0x3; + pDst->unused4 = tmp115__ >> 7 & 0x1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp116__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->acvo_acwmin = tmp116__ >> 0 & 0xf; + pDst->acvo_acwmax = tmp116__ >> 4 & 0xf; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->acvo_muedca_timer = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_mu_edca_param_set. */ + +#define SigIemu_edca_param_set (0x009e) + + +uint32_t dot11f_unpack_ie_non_inheritance(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEnon_inheritance *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_non_inheritance. */ + +#define SigIenon_inheritance (0x009f) + + +uint32_t dot11f_unpack_ie_oci(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEoci *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->op_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->prim_ch_num = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->freq_seg_1_ch_num = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_oci. */ + +#define SigIeoci (0x00a0) + + +uint32_t dot11f_unpack_ie_osen_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEosen_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_osen_ie. */ + +#define SigIeosen_ie (0x00a1) + + +static const tTLVDefn TLVS_qcn_ie[] = { + { offsetof(tDot11fIEqcn_ie, qcn_version), offsetof(tDot11fTLVqcn_version, + present), "qcn_version", SigTlvqcn_version, DOT11F_TLV_QCN_VERSION, + 0, 4, 4, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, vht_mcs11_attr), + offsetof(tDot11fTLVvht_mcs11_attr, present), "vht_mcs11_attr", + SigTlvvht_mcs11_attr, DOT11F_TLV_VHT_MCS11_ATTR, 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, he_400ns_sgi_attr), + offsetof(tDot11fTLVhe_400ns_sgi_attr, present), "he_400ns_sgi_attr", + SigTlvhe_400ns_sgi_attr, DOT11F_TLV_HE_400NS_SGI_ATTR, + 0, 5, 5, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, he_2xltf_160mhz_supp), + offsetof(tDot11fTLVhe_2xltf_160mhz_supp, present), + "he_2xltf_160mhz_supp", SigTlvhe_2xltf_160mhz_supp, + DOT11F_TLV_HE_2XLTF_160MHZ_SUPP, 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, he_dl_ofdma_attr), + offsetof(tDot11fTLVhe_dl_ofdma_attr, present), "he_dl_ofdma_attr", + SigTlvhe_dl_ofdma_attr, DOT11F_TLV_HE_DL_OFDMA_ATTR, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, trans_reasonp_attr), + offsetof(tDot11fTLVtrans_reasonp_attr, present), "trans_reasonp_attr", + SigTlvtrans_reasonp_attr, DOT11F_TLV_TRANS_REASONP_ATTR, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, trans_rejectp_attr), + offsetof(tDot11fTLVtrans_rejectp_attr, present), "trans_rejectp_attr", + SigTlvtrans_rejectp_attr, DOT11F_TLV_TRANS_REJECTP_ATTR, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, he_dl_mumimo_attr), + offsetof(tDot11fTLVhe_dl_mumimo_attr, present), "he_dl_mumimo_attr", + SigTlvhe_dl_mumimo_attr, DOT11F_TLV_HE_DL_MUMIMO_ATTR, + 0, 3, 3, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, he_mcs13_attr), + offsetof(tDot11fTLVhe_mcs13_attr, present), "he_mcs13_attr", + SigTlvhe_mcs13_attr, DOT11F_TLV_HE_MCS13_ATTR, 0, 4, 4, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, edca_pifs_param_attr), + offsetof(tDot11fTLVedca_pifs_param_attr, present), + "edca_pifs_param_attr", SigTlvedca_pifs_param_attr, + DOT11F_TLV_EDCA_PIFS_PARAM_ATTR, 0, 6, 7, 0, 1, 1, 0, }, + { offsetof(tDot11fIEqcn_ie, ecsa_target_tsf_info_attr), + offsetof(tDot11fTLVecsa_target_tsf_info_attr, present), + "ecsa_target_tsf_info_attr", SigTlvecsa_target_tsf_info_attr, + DOT11F_TLV_ECSA_TARGET_TSF_INFO_ATTR, 0, 11, 11, 0, 1, 1, 0, }, + {0, 0, NULL, 0, 0xffff, 0, 0, 0, 0, 0, 0}, +}; + +uint32_t dot11f_unpack_ie_qcn_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEqcn_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pBuf; (void)ielen; /* Shutup the compiler */ + pDst->present = 1; + status = unpack_tlv_core(pCtx, pBuf, ielen, + TLVS_qcn_ie, + (uint8_t *)pDst, sizeof(*pDst)); + return status; +} /* End dot11f_unpack_ie_qcn_ie. */ + +#define SigIeqcn_ie (0x00a2) + + +uint32_t dot11f_unpack_ie_reduced_neighbor_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEreduced_neighbor_report *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint16_t tmp117__; + uint16_t tmp118__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp117__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->tbtt_type = tmp117__ >> 0 & 0x3; + pDst->filtered_neighbor_ap = tmp117__ >> 2 & 0x1; + pDst->reserved = tmp117__ >> 3 & 0x1; + pDst->tbtt_info_count = tmp117__ >> 4 & 0xf; + pDst->tbtt_info_len = tmp117__ >> 8 & 0xff; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->op_class = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->channel_num = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + switch (pDst->tbtt_info_len) { + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_1.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 2: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_2.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_2.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 5: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_5.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->tbtt_info.tbtt_info_5.short_ssid, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + break; + case 6: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_6.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->tbtt_info.tbtt_info_6.short_ssid, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_6.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 7: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_7.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_7.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + break; + case 8: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_8.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_8.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_8.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 9: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_9.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_9.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_9.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_9.psd_20mhz = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 11: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_11.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_11.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->tbtt_info.tbtt_info_11.short_ssid, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + break; + case 12: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_12.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_12.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->tbtt_info.tbtt_info_12.short_ssid, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_12.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 13: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_13.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_13.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->tbtt_info.tbtt_info_13.short_ssid, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_13.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_13.psd_20mhz = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + case 16: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_16.tbtt_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 6)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->tbtt_info.tbtt_info_16.bssid, pBuf, 6); + pBuf += 6; + ielen -= (uint8_t)6; + if (unlikely(ielen < 4)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohl(pCtx, &pDst->tbtt_info.tbtt_info_16.short_ssid, pBuf, 0); + pBuf += 4; + ielen -= (uint8_t)4; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_16.bss_params = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_16.psd_20mhz = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->tbtt_info.tbtt_info_16.mld_id = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 2)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + framesntohs(pCtx, &tmp118__, pBuf, 0); + pBuf += 2; + ielen -= 2; + pDst->tbtt_info.tbtt_info_16.link_id = tmp118__ >> 0 & 0xf; + pDst->tbtt_info.tbtt_info_16.bss_param_change_cnt = tmp118__ >> 4 & 0xff; + pDst->tbtt_info.tbtt_info_16.all_updates_included = tmp118__ >> 12 & 0x1; + pDst->tbtt_info.tbtt_info_16.reserved = tmp118__ >> 13 & 0x7; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_reduced_neighbor_report. */ + +#define SigIereduced_neighbor_report (0x00a3) + + +uint32_t dot11f_unpack_ie_roaming_consortium_sel(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEroaming_consortium_sel *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_roaming_consortium_sel. */ + +#define SigIeroaming_consortium_sel (0x00a4) + + +uint32_t dot11f_unpack_ie_sec_chan_offset_ele(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEsec_chan_offset_ele *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->secondaryChannelOffset = *pBuf; + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_sec_chan_offset_ele. */ + +#define SigIesec_chan_offset_ele (0x00a5) + + +uint32_t dot11f_unpack_ie_spatial_reuse(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEspatial_reuse *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + uint8_t tmp119__; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + tmp119__ = *pBuf; + pBuf += 1; + ielen -= 1; + pDst->psr_disallow = tmp119__ >> 0 & 0x1; + pDst->non_srg_pd_sr_disallow = tmp119__ >> 1 & 0x1; + pDst->non_srg_offset_present = tmp119__ >> 2 & 0x1; + pDst->srg_info_present = tmp119__ >> 3 & 0x1; + pDst->sr_value15_allow = tmp119__ >> 4 & 0x1; + pDst->reserved = tmp119__ >> 5 & 0x7; + switch (pDst->non_srg_offset_present) { + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->non_srg_offset.info.non_srg_pd_max_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + break; + } + switch (pDst->srg_info_present) { + case 1: + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->srg_info.info.srg_pd_min_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->srg_info.info.srg_pd_max_offset = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->srg_info.info.srg_color, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + if (unlikely(ielen < 8)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + DOT11F_MEMCPY(pCtx, pDst->srg_info.info.srg_partial_bssid, pBuf, 8); + pBuf += 8; + ielen -= (uint8_t)8; + break; + } + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_spatial_reuse. */ + +#define SigIespatial_reuse (0x00a6) + + +uint32_t dot11f_unpack_ie_t2lm_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEt2lm_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + pDst->num_data = (uint8_t)(ielen); + DOT11F_MEMCPY(pCtx, pDst->data, pBuf, (ielen)); + (void)pCtx; + return status; +} /* End dot11f_unpack_ie_t2lm_ie. */ + +#define SigIet2lm_ie (0x00a7) + + +static const tFFDefn FFS_vendor_vht_ie[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_vendor_vht_ie[] = { + { offsetof(tDot11fIEvendor_vht_ie, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fIEvendor_vht_ie, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, }, +}; + +uint32_t dot11f_unpack_ie_vendor_vht_ie(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint8_t ielen, + tDot11fIEvendor_vht_ie *pDst, + bool append_ie) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void) pBuf; (void)ielen; /* Shutup the compiler */ + if (pDst->present) + return DOT11F_DUPLICATE_IE; + pDst->present = 1; + if (unlikely(ielen < 1)) { + pDst->present = 0; + return DOT11F_INCOMPLETE_IE; + } + + pDst->sub_type = *pBuf; + pBuf += 1; + ielen -= (uint8_t)1; + (void)pCtx; + status |= unpack_core(pCtx, + pBuf, + ielen, + FFS_vendor_vht_ie, + IES_vendor_vht_ie, + (uint8_t *)pDst, + sizeof(*pDst), + append_ie); + return status; +} /* End dot11f_unpack_ie_vendor_vht_ie. */ + +#define SigIevendor_vht_ie (0x00a8) + + +static const tFFDefn FFS_AddTSRequest[] = { + { "Category", offsetof(tDot11fAddTSRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fAddTSRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fAddTSRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AddTSRequest[] = { + { offsetof(tDot11fAddTSRequest, TSPEC), offsetof(tDot11fIETSPEC, present), + 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 0, 1, }, + { offsetof(tDot11fAddTSRequest, TCLAS), offsetof(tDot11fIETCLAS, present), + offsetof(tDot11fAddTSRequest, num_TCLAS), "TCLAS", 2, 7, 45, SigIeTCLAS, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, 0, }, + { offsetof(tDot11fAddTSRequest, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fAddTSRequest, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, 0, }, + { offsetof(tDot11fAddTSRequest, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, 0, }, + { offsetof(tDot11fAddTSRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AddTSRequest, IES_AddTSRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_add_ts_request. */ + +static const tFFDefn FFS_AddTSResponse[] = { + { "Category", offsetof(tDot11fAddTSResponse, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fAddTSResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fAddTSResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Status", offsetof(tDot11fAddTSResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AddTSResponse[] = { + { offsetof(tDot11fAddTSResponse, TSDelay), offsetof(tDot11fIETSDelay, + present), 0, "TSDelay", 0, 6, 6, SigIeTSDelay, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSDELAY, 0, 1, }, + { offsetof(tDot11fAddTSResponse, TSPEC), offsetof(tDot11fIETSPEC, + present), 0, "TSPEC", 0, 57, 57, SigIeTSPEC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TSPEC, 0, 1, }, + { offsetof(tDot11fAddTSResponse, TCLAS), offsetof(tDot11fIETCLAS, + present), offsetof(tDot11fAddTSResponse, num_TCLAS), "TCLAS", + 2, 7, 45, SigIeTCLAS, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TCLAS, 0, 0, }, + { offsetof(tDot11fAddTSResponse, TCLASSPROC), + offsetof(tDot11fIETCLASSPROC, present), 0, "TCLASSPROC", + 0, 3, 3, SigIeTCLASSPROC, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TCLASSPROC, 0, 0, }, + { offsetof(tDot11fAddTSResponse, Schedule), offsetof(tDot11fIESchedule, + present), 0, "Schedule", 0, 16, 16, SigIeSchedule, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SCHEDULE, 0, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTSDelay), + offsetof(tDot11fIEWMMTSDelay, present), 0, "WMMTSDelay", + 0, 12, 12, SigIeWMMTSDelay, {0, 80, 242, 2, 8}, + 5, DOT11F_EID_WMMTSDELAY, 0, 0, }, + { offsetof(tDot11fAddTSResponse, WMMSchedule), + offsetof(tDot11fIEWMMSchedule, present), 0, "WMMSchedule", + 0, 22, 22, SigIeWMMSchedule, {0, 80, 242, 2, 9}, + 5, DOT11F_EID_WMMSCHEDULE, 0, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTCLAS), offsetof(tDot11fIEWMMTCLAS, + present), offsetof(tDot11fAddTSResponse, num_WMMTCLAS), "WMMTCLAS", + 2, 13, 51, SigIeWMMTCLAS, {0, 80, 242, 2, 6}, + 5, DOT11F_EID_WMMTCLAS, 0, 0, }, + { offsetof(tDot11fAddTSResponse, WMMTCLASPROC), + offsetof(tDot11fIEWMMTCLASPROC, present), 0, "WMMTCLASPROC", + 0, 9, 9, SigIeWMMTCLASPROC, {0, 80, 242, 2, 7}, + 5, DOT11F_EID_WMMTCLASPROC, 0, 0, }, + { offsetof(tDot11fAddTSResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAddTSResponse *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AddTSResponse, IES_AddTSResponse, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_add_ts_response. */ + +static const tFFDefn FFS_AssocRequest[] = { + { "Capabilities", offsetof(tDot11fAssocRequest, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "ListenInterval", offsetof(tDot11fAssocRequest, ListenInterval), + SigFfListenInterval, DOT11F_FF_LISTENINTERVAL_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AssocRequest[] = { + { offsetof(tDot11fAssocRequest, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fAssocRequest, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fAssocRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fAssocRequest, PowerCaps), offsetof(tDot11fIEPowerCaps, + present), 0, "PowerCaps", 0, 4, 4, SigIePowerCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCAPS, 0, 0, }, + { offsetof(tDot11fAssocRequest, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 2, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, 0, }, + { offsetof(tDot11fAssocRequest, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { offsetof(tDot11fAssocRequest, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, 0, }, + { offsetof(tDot11fAssocRequest, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fAssocRequest, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fAssocRequest, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fAssocRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fAssocRequest, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fAssocRequest, fils_session), + offsetof(tDot11fIEfils_session, present), 0, "fils_session", + 0, 10, 10, SigIefils_session, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_SESSION, 4, 0, }, + { offsetof(tDot11fAssocRequest, fils_public_key), + offsetof(tDot11fIEfils_public_key, present), 0, "fils_public_key", + 0, 3, 258, SigIefils_public_key, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_PUBLIC_KEY, 12, 0, }, + { offsetof(tDot11fAssocRequest, fils_key_confirmation), + offsetof(tDot11fIEfils_key_confirmation, present), 0, + "fils_key_confirmation", 0, 2, 257, SigIefils_key_confirmation, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_FILS_KEY_CONFIRMATION, 3, 0, }, + { offsetof(tDot11fAssocRequest, fils_hlp_container), + offsetof(tDot11fIEfils_hlp_container, present), 0, "fils_hlp_container", + 0, 14, 269, SigIefils_hlp_container, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_HLP_CONTAINER, 5, 0, }, + { offsetof(tDot11fAssocRequest, bss_max_idle_period), + offsetof(tDot11fIEbss_max_idle_period, present), 0, "bss_max_idle_period", + 0, 5, 5, SigIebss_max_idle_period, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_MAX_IDLE_PERIOD, 0, 0, }, + { offsetof(tDot11fAssocRequest, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fAssocRequest, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fAssocRequest, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fAssocRequest, WAPIOpaque), + offsetof(tDot11fIEWAPIOpaque, present), 0, "WAPIOpaque", + 0, 8, 255, SigIeWAPIOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPIOPAQUE, 0, 0, }, + { offsetof(tDot11fAssocRequest, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, 0, }, + { offsetof(tDot11fAssocRequest, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 18, 60, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, 0, }, + { offsetof(tDot11fAssocRequest, fragment_ie), + offsetof(tDot11fIEfragment_ie, present), 0, "fragment_ie", + 0, 2, 257, SigIefragment_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FRAGMENT_IE, 0, 0, }, + { offsetof(tDot11fAssocRequest, dh_parameter_element), + offsetof(tDot11fIEdh_parameter_element, present), 0, + "dh_parameter_element", 0, 4, 259, SigIedh_parameter_element, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_DH_PARAMETER_ELEMENT, 32, 0, }, + { offsetof(tDot11fAssocRequest, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fAssocRequest, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fAssocRequest, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11fAssocRequest, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fAssocRequest, WPAOpaque), offsetof(tDot11fIEWPAOpaque, + present), 0, "WPAOpaque", 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 0, 0, }, + { offsetof(tDot11fAssocRequest, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fAssocRequest, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, 0, }, + { offsetof(tDot11fAssocRequest, WscIEOpaque), + offsetof(tDot11fIEWscIEOpaque, present), 0, "WscIEOpaque", + 0, 8, 255, SigIeWscIEOpaque, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCIEOPAQUE, 0, 0, }, + { offsetof(tDot11fAssocRequest, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fAssocRequest, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, 0, }, + { offsetof(tDot11fAssocRequest, P2PIEOpaque), + offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque", + 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PIEOPAQUE, 0, 0, }, + { offsetof(tDot11fAssocRequest, WFDIEOpaque), + offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque", + 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, + 4, DOT11F_EID_WFDIEOPAQUE, 0, 0, }, + { offsetof(tDot11fAssocRequest, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fAssocRequest, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, 0, }, + { offsetof(tDot11fAssocRequest, qcn_ie), offsetof(tDot11fIEqcn_ie, + present), 0, "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fAssocRequest, osen_ie), offsetof(tDot11fIEosen_ie, + present), 0, "osen_ie", 0, 6, 261, SigIeosen_ie, {80, 111, 154, 18, 0}, + 4, DOT11F_EID_OSEN_IE, 0, 0, }, + { offsetof(tDot11fAssocRequest, roaming_consortium_sel), + offsetof(tDot11fIEroaming_consortium_sel, present), 0, + "roaming_consortium_sel", 0, 6, 261, SigIeroaming_consortium_sel, + {80, 111, 154, 29, 0}, 4, DOT11F_EID_ROAMING_CONSORTIUM_SEL, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AssocRequest, IES_AssocRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_assoc_request. */ + +static const tFFDefn FFS_AssocResponse[] = { + { "Capabilities", offsetof(tDot11fAssocResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "Status", offsetof(tDot11fAssocResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "AID", offsetof(tDot11fAssocResponse, AID), SigFfAID, + DOT11F_FF_AID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_AssocResponse[] = { + { offsetof(tDot11fAssocResponse, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fAssocResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fAssocResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fAssocResponse, RCPIIE), offsetof(tDot11fIERCPIIE, + present), 0, "RCPIIE", 0, 3, 3, SigIeRCPIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RCPIIE, 0, 0, }, + { offsetof(tDot11fAssocResponse, RSNIIE), offsetof(tDot11fIERSNIIE, + present), 0, "RSNIIE", 0, 3, 3, SigIeRSNIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNIIE, 0, 0, }, + { offsetof(tDot11fAssocResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fAssocResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fAssocResponse, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fAssocResponse, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fAssocResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fAssocResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fAssocResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, 0, }, + { offsetof(tDot11fAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fAssocResponse, bss_max_idle_period), + offsetof(tDot11fIEbss_max_idle_period, present), 0, "bss_max_idle_period", + 0, 5, 5, SigIebss_max_idle_period, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_MAX_IDLE_PERIOD, 0, 0, }, + { offsetof(tDot11fAssocResponse, QosMapSet), offsetof(tDot11fIEQosMapSet, + present), 0, "QosMapSet", 0, 18, 60, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, 0, }, + { offsetof(tDot11fAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fAssocResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fAssocResponse, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fAssocResponse, fils_session), + offsetof(tDot11fIEfils_session, present), 0, "fils_session", + 0, 10, 10, SigIefils_session, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_SESSION, 4, 0, }, + { offsetof(tDot11fAssocResponse, fils_public_key), + offsetof(tDot11fIEfils_public_key, present), 0, "fils_public_key", + 0, 3, 258, SigIefils_public_key, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_PUBLIC_KEY, 12, 0, }, + { offsetof(tDot11fAssocResponse, fils_key_confirmation), + offsetof(tDot11fIEfils_key_confirmation, present), 0, + "fils_key_confirmation", 0, 2, 257, SigIefils_key_confirmation, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_FILS_KEY_CONFIRMATION, 3, 0, }, + { offsetof(tDot11fAssocResponse, fils_hlp_container), + offsetof(tDot11fIEfils_hlp_container, present), 0, "fils_hlp_container", + 0, 14, 269, SigIefils_hlp_container, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_HLP_CONTAINER, 5, 0, }, + { offsetof(tDot11fAssocResponse, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fAssocResponse, he_op), offsetof(tDot11fIEhe_op, + present), 0, "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + { offsetof(tDot11fAssocResponse, spatial_reuse), + offsetof(tDot11fIEspatial_reuse, present), 0, "spatial_reuse", + 0, 3, 22, SigIespatial_reuse, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SPATIAL_REUSE, 39, 0, }, + { offsetof(tDot11fAssocResponse, bss_color_change), + offsetof(tDot11fIEbss_color_change, present), 0, "bss_color_change", + 0, 4, 4, SigIebss_color_change, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_COLOR_CHANGE, 42, 0, }, + { offsetof(tDot11fAssocResponse, mu_edca_param_set), + offsetof(tDot11fIEmu_edca_param_set, present), 0, "mu_edca_param_set", + 0, 15, 15, SigIemu_edca_param_set, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MU_EDCA_PARAM_SET, 38, 0, }, + { offsetof(tDot11fAssocResponse, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fAssocResponse, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fAssocResponse, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, 0, }, + { offsetof(tDot11fAssocResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, 0, }, + { offsetof(tDot11fAssocResponse, fragment_ie), + offsetof(tDot11fIEfragment_ie, present), 0, "fragment_ie", + 0, 2, 257, SigIefragment_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FRAGMENT_IE, 0, 0, }, + { offsetof(tDot11fAssocResponse, fils_kde), offsetof(tDot11fIEfils_kde, + present), 0, "fils_kde", 0, 10, 265, SigIefils_kde, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_KDE, 7, 0, }, + { offsetof(tDot11fAssocResponse, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fAssocResponse, eht_op), offsetof(tDot11fIEeht_op, + present), 0, "eht_op", 0, 10, 12, SigIeeht_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_OP, 106, 0, }, + { offsetof(tDot11fAssocResponse, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fAssocResponse, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11fAssocResponse, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fAssocResponse, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, 0, }, + { offsetof(tDot11fAssocResponse, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fAssocResponse, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fAssocResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fAssocResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + { offsetof(tDot11fAssocResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fAssocResponse, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fAssocResponse, WscAssocRes), + offsetof(tDot11fIEWscAssocRes, present), 0, "WscAssocRes", + 0, 6, 37, SigIeWscAssocRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCASSOCRES, 0, 0, }, + { offsetof(tDot11fAssocResponse, P2PAssocRes), + offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes", + 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PASSOCRES, 0, 0, }, + { offsetof(tDot11fAssocResponse, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fAssocResponse, qcn_ie), offsetof(tDot11fIEqcn_ie, + present), 0, "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fAssocResponse, MBO_IE), offsetof(tDot11fIEMBO_IE, + present), 0, "MBO_IE", 0, 6, 295, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, 0, }, + { offsetof(tDot11fAssocResponse, reduced_neighbor_report), + offsetof(tDot11fIEreduced_neighbor_report, present), 0, + "reduced_neighbor_report", 0, 7, 22, SigIereduced_neighbor_report, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REDUCED_NEIGHBOR_REPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAssocResponse *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_AssocResponse, IES_AssocResponse, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_assoc_response. */ + +static const tFFDefn FFS_Authentication[] = { + { "AuthAlgo", offsetof(tDot11fAuthentication, AuthAlgo), SigFfAuthAlgo, + DOT11F_FF_AUTHALGO_LEN, }, + { "AuthSeqNo", offsetof(tDot11fAuthentication, AuthSeqNo), SigFfAuthSeqNo, + DOT11F_FF_AUTHSEQNO_LEN, }, + { "Status", offsetof(tDot11fAuthentication, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Authentication[] = { + { offsetof(tDot11fAuthentication, ChallengeText), + offsetof(tDot11fIEChallengeText, present), 0, "ChallengeText", + 0, 3, 255, SigIeChallengeText, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHALLENGETEXT, 0, 0, }, + { offsetof(tDot11fAuthentication, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { offsetof(tDot11fAuthentication, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fAuthentication, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fAuthentication, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fAuthentication, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fAuthentication, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, 0, }, + { offsetof(tDot11fAuthentication, fils_nonce), + offsetof(tDot11fIEfils_nonce, present), 0, "fils_nonce", + 0, 18, 18, SigIefils_nonce, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_NONCE, 13, 0, }, + { offsetof(tDot11fAuthentication, fils_session), + offsetof(tDot11fIEfils_session, present), 0, "fils_session", + 0, 10, 10, SigIefils_session, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_SESSION, 4, 0, }, + { offsetof(tDot11fAuthentication, fils_wrapped_data), + offsetof(tDot11fIEfils_wrapped_data, present), 0, "fils_wrapped_data", + 0, 2, 257, SigIefils_wrapped_data, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_WRAPPED_DATA, 8, 0, }, + { offsetof(tDot11fAuthentication, fils_assoc_delay_info), + offsetof(tDot11fIEfils_assoc_delay_info, present), 0, + "fils_assoc_delay_info", 0, 3, 3, SigIefils_assoc_delay_info, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_FILS_ASSOC_DELAY_INFO, 1, 0, }, + { offsetof(tDot11fAuthentication, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_authentication(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fAuthentication *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Authentication, IES_Authentication, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_authentication. */ + +static const tFFDefn FFS_Beacon[] = { + { "TimeStamp", offsetof(tDot11fBeacon, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fBeacon, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fBeacon, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon[] = { + { offsetof(tDot11fBeacon, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fBeacon, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fBeacon, FHParamSet), offsetof(tDot11fIEFHParamSet, + present), 0, "FHParamSet", 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, 0, }, + { offsetof(tDot11fBeacon, DSParams), offsetof(tDot11fIEDSParams, present), + 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, 0, }, + { offsetof(tDot11fBeacon, CFParams), offsetof(tDot11fIECFParams, present), + 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, 0, }, + { offsetof(tDot11fBeacon, TIM), offsetof(tDot11fIETIM, present), 0, "TIM", + 0, 6, 256, SigIeTIM, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIM, 0, 0, }, + { offsetof(tDot11fBeacon, Country), offsetof(tDot11fIECountry, present), 0, + "Country", 0, 8, 248, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fBeacon, FHParams), offsetof(tDot11fIEFHParams, present), + 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, 0, }, + { offsetof(tDot11fBeacon, FHPattTable), offsetof(tDot11fIEFHPattTable, + present), 0, "FHPattTable", 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, 0, }, + { offsetof(tDot11fBeacon, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, 0, }, + { offsetof(tDot11fBeacon, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fBeacon, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QUIET, 0, 0, }, + { offsetof(tDot11fBeacon, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, 0, }, + { offsetof(tDot11fBeacon, ERPInfo), offsetof(tDot11fIEERPInfo, present), 0, + "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, 0, }, + { offsetof(tDot11fBeacon, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, + present), 0, "ExtSuppRates", 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fBeacon, RSN), offsetof(tDot11fIERSN, present), 0, "RSN", + 0, 4, 132, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, 0, }, + { offsetof(tDot11fBeacon, QBSSLoad), offsetof(tDot11fIEQBSSLoad, present), + 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, 0, }, + { offsetof(tDot11fBeacon, EDCAParamSet), offsetof(tDot11fIEEDCAParamSet, + present), 0, "EDCAParamSet", 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fBeacon, QOSCapsAp), offsetof(tDot11fIEQOSCapsAp, + present), 0, "QOSCapsAp", 0, 3, 3, SigIeQOSCapsAp, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSAP, 0, 0, }, + { offsetof(tDot11fBeacon, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, 0, }, + { offsetof(tDot11fBeacon, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fBeacon, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fBeacon, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, 0, }, + { offsetof(tDot11fBeacon, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fBeacon, HTCaps), offsetof(tDot11fIEHTCaps, present), 0, + "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fBeacon, HTInfo), offsetof(tDot11fIEHTInfo, present), 0, + "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fBeacon, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, 0, }, + { offsetof(tDot11fBeacon, ExtCap), offsetof(tDot11fIEExtCap, present), 0, + "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fBeacon, VHTCaps), offsetof(tDot11fIEVHTCaps, present), 0, + "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fBeacon, VHTOperation), offsetof(tDot11fIEVHTOperation, + present), 0, "VHTOperation", 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fBeacon, transmit_power_env), + offsetof(tDot11fIEtransmit_power_env, present), + offsetof(tDot11fBeacon, num_transmit_power_env), "transmit_power_env", + 8, 4, 20, SigIetransmit_power_env, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TRANSMIT_POWER_ENV, 0, 0, }, + { offsetof(tDot11fBeacon, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 35, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, 0, }, + { offsetof(tDot11fBeacon, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, 0, }, + { offsetof(tDot11fBeacon, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fBeacon, fils_indication), + offsetof(tDot11fIEfils_indication, present), 0, "fils_indication", + 0, 6, 259, SigIefils_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_INDICATION, 0, 0, }, + { offsetof(tDot11fBeacon, max_chan_switch_time), + offsetof(tDot11fIEmax_chan_switch_time, present), 0, + "max_chan_switch_time", 0, 5, 5, SigIemax_chan_switch_time, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_MAX_CHAN_SWITCH_TIME, 52, 0, }, + { offsetof(tDot11fBeacon, esp_information), + offsetof(tDot11fIEesp_information, present), 0, "esp_information", + 0, 2, 98, SigIeesp_information, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ESP_INFORMATION, 11, 0, }, + { offsetof(tDot11fBeacon, he_cap), offsetof(tDot11fIEhe_cap, present), 0, + "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fBeacon, he_op), offsetof(tDot11fIEhe_op, present), 0, + "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + { offsetof(tDot11fBeacon, spatial_reuse), + offsetof(tDot11fIEspatial_reuse, present), 0, "spatial_reuse", + 0, 3, 22, SigIespatial_reuse, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SPATIAL_REUSE, 39, 0, }, + { offsetof(tDot11fBeacon, bss_color_change), + offsetof(tDot11fIEbss_color_change, present), 0, "bss_color_change", + 0, 4, 4, SigIebss_color_change, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_COLOR_CHANGE, 42, 0, }, + { offsetof(tDot11fBeacon, mu_edca_param_set), + offsetof(tDot11fIEmu_edca_param_set, present), 0, "mu_edca_param_set", + 0, 15, 15, SigIemu_edca_param_set, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MU_EDCA_PARAM_SET, 38, 0, }, + { offsetof(tDot11fBeacon, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fBeacon, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, 0, }, + { offsetof(tDot11fBeacon, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, 0, }, + { offsetof(tDot11fBeacon, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, 0, }, + { offsetof(tDot11fBeacon, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fBeacon, eht_cap), offsetof(tDot11fIEeht_cap, present), 0, + "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fBeacon, eht_op), offsetof(tDot11fIEeht_op, present), 0, + "eht_op", 0, 10, 12, SigIeeht_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_OP, 106, 0, }, + { offsetof(tDot11fBeacon, mlo_ie), offsetof(tDot11fIEmlo_ie, present), 0, + "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fBeacon, t2lm_ie), offsetof(tDot11fIEt2lm_ie, present), + offsetof(tDot11fBeacon, num_t2lm_ie), "t2lm_ie", 2, 5, 257, SigIet2lm_ie, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fBeacon, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, 0, }, + { offsetof(tDot11fBeacon, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, 0, }, + { offsetof(tDot11fBeacon, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fBeacon, WMMCaps), offsetof(tDot11fIEWMMCaps, present), 0, + "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fBeacon, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, 0, }, + { offsetof(tDot11fBeacon, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fBeacon, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + { offsetof(tDot11fBeacon, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 0, 0, }, + { offsetof(tDot11fBeacon, P2PBeacon), offsetof(tDot11fIEP2PBeacon, + present), 0, "P2PBeacon", 0, 6, 61, SigIeP2PBeacon, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACON, 0, 0, }, + { offsetof(tDot11fBeacon, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, 0, }, + { offsetof(tDot11fBeacon, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fBeacon, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, 0, }, + { offsetof(tDot11fBeacon, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, 0, }, + { offsetof(tDot11fBeacon, QComVendorIE), offsetof(tDot11fIEQComVendorIE, + present), 0, "QComVendorIE", 0, 7, 7, SigIeQComVendorIE, + {0, 160, 198, 0, 0}, 3, DOT11F_EID_QCOMVENDORIE, 0, 0, }, + { offsetof(tDot11fBeacon, MBO_IE), offsetof(tDot11fIEMBO_IE, present), 0, + "MBO_IE", 0, 6, 295, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, 0, }, + { offsetof(tDot11fBeacon, qcn_ie), offsetof(tDot11fIEqcn_ie, present), 0, + "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fBeacon, reduced_neighbor_report), + offsetof(tDot11fIEreduced_neighbor_report, present), 0, + "reduced_neighbor_report", 0, 7, 22, SigIereduced_neighbor_report, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REDUCED_NEIGHBOR_REPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon, IES_Beacon, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon. */ + +static const tFFDefn FFS_Beacon1[] = { + { "TimeStamp", offsetof(tDot11fBeacon1, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fBeacon1, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fBeacon1, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon1[] = { + { offsetof(tDot11fBeacon1, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fBeacon1, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fBeacon1, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon1(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon1 *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon1, IES_Beacon1, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon1. */ + +static const tFFDefn FFS_Beacon2[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Beacon2[] = { + { offsetof(tDot11fBeacon2, Country), offsetof(tDot11fIECountry, present), + 0, "Country", 0, 8, 248, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fBeacon2, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, 0, }, + { offsetof(tDot11fBeacon2, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fBeacon2, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QUIET, 0, 0, }, + { offsetof(tDot11fBeacon2, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, 0, }, + { offsetof(tDot11fBeacon2, ERPInfo), offsetof(tDot11fIEERPInfo, present), + 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, 0, }, + { offsetof(tDot11fBeacon2, ExtSuppRates), offsetof(tDot11fIEExtSuppRates, + present), 0, "ExtSuppRates", 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fBeacon2, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { offsetof(tDot11fBeacon2, EDCAParamSet), offsetof(tDot11fIEEDCAParamSet, + present), 0, "EDCAParamSet", 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fBeacon2, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, 0, }, + { offsetof(tDot11fBeacon2, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fBeacon2, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fBeacon2, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, 0, }, + { offsetof(tDot11fBeacon2, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fBeacon2, HTCaps), offsetof(tDot11fIEHTCaps, present), 0, + "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fBeacon2, HTInfo), offsetof(tDot11fIEHTInfo, present), 0, + "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fBeacon2, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, 0, }, + { offsetof(tDot11fBeacon2, ExtCap), offsetof(tDot11fIEExtCap, present), 0, + "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fBeacon2, VHTCaps), offsetof(tDot11fIEVHTCaps, present), + 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fBeacon2, VHTOperation), offsetof(tDot11fIEVHTOperation, + present), 0, "VHTOperation", 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fBeacon2, transmit_power_env), + offsetof(tDot11fIEtransmit_power_env, present), + offsetof(tDot11fBeacon2, num_transmit_power_env), "transmit_power_env", + 8, 4, 20, SigIetransmit_power_env, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TRANSMIT_POWER_ENV, 0, 0, }, + { offsetof(tDot11fBeacon2, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 35, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, 0, }, + { offsetof(tDot11fBeacon2, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, 0, }, + { offsetof(tDot11fBeacon2, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fBeacon2, fils_indication), + offsetof(tDot11fIEfils_indication, present), 0, "fils_indication", + 0, 6, 259, SigIefils_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_INDICATION, 0, 0, }, + { offsetof(tDot11fBeacon2, max_chan_switch_time), + offsetof(tDot11fIEmax_chan_switch_time, present), 0, + "max_chan_switch_time", 0, 5, 5, SigIemax_chan_switch_time, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_MAX_CHAN_SWITCH_TIME, 52, 0, }, + { offsetof(tDot11fBeacon2, esp_information), + offsetof(tDot11fIEesp_information, present), 0, "esp_information", + 0, 2, 98, SigIeesp_information, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ESP_INFORMATION, 11, 0, }, + { offsetof(tDot11fBeacon2, he_cap), offsetof(tDot11fIEhe_cap, present), 0, + "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fBeacon2, he_op), offsetof(tDot11fIEhe_op, present), 0, + "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + { offsetof(tDot11fBeacon2, spatial_reuse), + offsetof(tDot11fIEspatial_reuse, present), 0, "spatial_reuse", + 0, 3, 22, SigIespatial_reuse, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SPATIAL_REUSE, 39, 0, }, + { offsetof(tDot11fBeacon2, bss_color_change), + offsetof(tDot11fIEbss_color_change, present), 0, "bss_color_change", + 0, 4, 4, SigIebss_color_change, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_COLOR_CHANGE, 42, 0, }, + { offsetof(tDot11fBeacon2, mu_edca_param_set), + offsetof(tDot11fIEmu_edca_param_set, present), 0, "mu_edca_param_set", + 0, 15, 15, SigIemu_edca_param_set, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MU_EDCA_PARAM_SET, 38, 0, }, + { offsetof(tDot11fBeacon2, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fBeacon2, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, 0, }, + { offsetof(tDot11fBeacon2, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, 0, }, + { offsetof(tDot11fBeacon2, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, 0, }, + { offsetof(tDot11fBeacon2, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fBeacon2, eht_cap), offsetof(tDot11fIEeht_cap, present), + 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fBeacon2, eht_op), offsetof(tDot11fIEeht_op, present), 0, + "eht_op", 0, 10, 12, SigIeeht_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_OP, 106, 0, }, + { offsetof(tDot11fBeacon2, mlo_ie), offsetof(tDot11fIEmlo_ie, present), 0, + "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fBeacon2, t2lm_ie), offsetof(tDot11fIEt2lm_ie, present), + offsetof(tDot11fBeacon2, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fBeacon2, WPA), offsetof(tDot11fIEWPA, present), 0, "WPA", + 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, 0, }, + { offsetof(tDot11fBeacon2, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, 0, }, + { offsetof(tDot11fBeacon2, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fBeacon2, WMMCaps), offsetof(tDot11fIEWMMCaps, present), + 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fBeacon2, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fBeacon2, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + { offsetof(tDot11fBeacon2, WscBeacon), offsetof(tDot11fIEWscBeacon, + present), 0, "WscBeacon", 0, 6, 84, SigIeWscBeacon, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACON, 0, 0, }, + { offsetof(tDot11fBeacon2, P2PBeacon), offsetof(tDot11fIEP2PBeacon, + present), 0, "P2PBeacon", 0, 6, 61, SigIeP2PBeacon, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACON, 0, 0, }, + { offsetof(tDot11fBeacon2, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, 0, }, + { offsetof(tDot11fBeacon2, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fBeacon2, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, 0, }, + { offsetof(tDot11fBeacon2, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, 0, }, + { offsetof(tDot11fBeacon2, QComVendorIE), offsetof(tDot11fIEQComVendorIE, + present), 0, "QComVendorIE", 0, 7, 7, SigIeQComVendorIE, + {0, 160, 198, 0, 0}, 3, DOT11F_EID_QCOMVENDORIE, 0, 0, }, + { offsetof(tDot11fBeacon2, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, 0, }, + { offsetof(tDot11fBeacon2, qcn_ie), offsetof(tDot11fIEqcn_ie, present), 0, + "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fBeacon2, reduced_neighbor_report), + offsetof(tDot11fIEreduced_neighbor_report, present), 0, + "reduced_neighbor_report", 0, 7, 22, SigIereduced_neighbor_report, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REDUCED_NEIGHBOR_REPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon2(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeacon2 *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Beacon2, IES_Beacon2, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon2. */ + +static const tFFDefn FFS_BeaconIEs[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_BeaconIEs[] = { + { offsetof(tDot11fBeaconIEs, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fBeaconIEs, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fBeaconIEs, FHParamSet), offsetof(tDot11fIEFHParamSet, + present), 0, "FHParamSet", 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, 0, }, + { offsetof(tDot11fBeaconIEs, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, CFParams), offsetof(tDot11fIECFParams, + present), 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, TIM), offsetof(tDot11fIETIM, present), 0, + "TIM", 0, 6, 256, SigIeTIM, {0, 0, 0, 0, 0}, 0, DOT11F_EID_TIM, 0, 0, }, + { offsetof(tDot11fBeaconIEs, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 8, 248, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fBeaconIEs, FHParams), offsetof(tDot11fIEFHParams, + present), 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, FHPattTable), offsetof(tDot11fIEFHPattTable, + present), 0, "FHPattTable", 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fBeaconIEs, Quiet), offsetof(tDot11fIEQuiet, present), 0, + "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QUIET, 0, 0, }, + { offsetof(tDot11fBeaconIEs, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ERPInfo), offsetof(tDot11fIEERPInfo, + present), 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fBeaconIEs, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 4, 132, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, 0, }, + { offsetof(tDot11fBeaconIEs, QBSSLoad), offsetof(tDot11fIEQBSSLoad, + present), 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, 0, }, + { offsetof(tDot11fBeaconIEs, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fBeaconIEs, QOSCapsAp), offsetof(tDot11fIEQOSCapsAp, + present), 0, "QOSCapsAp", 0, 3, 3, SigIeQOSCapsAp, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSAP, 0, 0, }, + { offsetof(tDot11fBeaconIEs, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, 0, }, + { offsetof(tDot11fBeaconIEs, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fBeaconIEs, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, 0, }, + { offsetof(tDot11fBeaconIEs, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fBeaconIEs, HTCaps), offsetof(tDot11fIEHTCaps, present), + 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, HTInfo), offsetof(tDot11fIEHTInfo, present), + 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fBeaconIEs, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ExtCap), offsetof(tDot11fIEExtCap, present), + 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fBeaconIEs, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fBeaconIEs, transmit_power_env), + offsetof(tDot11fIEtransmit_power_env, present), + offsetof(tDot11fBeaconIEs, num_transmit_power_env), + "transmit_power_env", 8, 4, 20, SigIetransmit_power_env, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TRANSMIT_POWER_ENV, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 35, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, 0, }, + { offsetof(tDot11fBeaconIEs, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, 0, }, + { offsetof(tDot11fBeaconIEs, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, fils_indication), + offsetof(tDot11fIEfils_indication, present), 0, "fils_indication", + 0, 6, 259, SigIefils_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_INDICATION, 0, 0, }, + { offsetof(tDot11fBeaconIEs, max_chan_switch_time), + offsetof(tDot11fIEmax_chan_switch_time, present), 0, + "max_chan_switch_time", 0, 5, 5, SigIemax_chan_switch_time, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_MAX_CHAN_SWITCH_TIME, 52, 0, }, + { offsetof(tDot11fBeaconIEs, esp_information), + offsetof(tDot11fIEesp_information, present), 0, "esp_information", + 0, 2, 98, SigIeesp_information, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ESP_INFORMATION, 11, 0, }, + { offsetof(tDot11fBeaconIEs, he_cap), offsetof(tDot11fIEhe_cap, present), + 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fBeaconIEs, he_op), offsetof(tDot11fIEhe_op, present), 0, + "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + { offsetof(tDot11fBeaconIEs, spatial_reuse), + offsetof(tDot11fIEspatial_reuse, present), 0, "spatial_reuse", + 0, 3, 22, SigIespatial_reuse, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SPATIAL_REUSE, 39, 0, }, + { offsetof(tDot11fBeaconIEs, bss_color_change), + offsetof(tDot11fIEbss_color_change, present), 0, "bss_color_change", + 0, 4, 4, SigIebss_color_change, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_COLOR_CHANGE, 42, 0, }, + { offsetof(tDot11fBeaconIEs, mu_edca_param_set), + offsetof(tDot11fIEmu_edca_param_set, present), 0, "mu_edca_param_set", + 0, 15, 15, SigIemu_edca_param_set, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MU_EDCA_PARAM_SET, 38, 0, }, + { offsetof(tDot11fBeaconIEs, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fBeaconIEs, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, WAPI), offsetof(tDot11fIEWAPI, present), 0, + "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, 0, }, + { offsetof(tDot11fBeaconIEs, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fBeaconIEs, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fBeaconIEs, eht_op), offsetof(tDot11fIEeht_op, present), + 0, "eht_op", 0, 10, 12, SigIeeht_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_OP, 106, 0, }, + { offsetof(tDot11fBeaconIEs, mlo_ie), offsetof(tDot11fIEmlo_ie, present), + 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fBeaconIEs, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11fBeaconIEs, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fBeaconIEs, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, 0, }, + { offsetof(tDot11fBeaconIEs, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, 0, }, + { offsetof(tDot11fBeaconIEs, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ESEVersion), offsetof(tDot11fIEESEVersion, + present), 0, "ESEVersion", 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fBeaconIEs, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + { offsetof(tDot11fBeaconIEs, WscBeaconProbeRes), + offsetof(tDot11fIEWscBeaconProbeRes, present), 0, "WscBeaconProbeRes", + 0, 6, 319, SigIeWscBeaconProbeRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCBEACONPROBERES, 0, 0, }, + { offsetof(tDot11fBeaconIEs, P2PBeaconProbeRes), + offsetof(tDot11fIEP2PBeaconProbeRes, present), 0, "P2PBeaconProbeRes", + 0, 6, 1150, SigIeP2PBeaconProbeRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PBEACONPROBERES, 0, 0, }, + { offsetof(tDot11fBeaconIEs, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, QComVendorIE), + offsetof(tDot11fIEQComVendorIE, present), 0, "QComVendorIE", + 0, 7, 7, SigIeQComVendorIE, {0, 160, 198, 0, 0}, + 3, DOT11F_EID_QCOMVENDORIE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, MBO_IE), offsetof(tDot11fIEMBO_IE, present), + 0, "MBO_IE", 0, 6, 295, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, qcn_ie), offsetof(tDot11fIEqcn_ie, present), + 0, "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fBeaconIEs, reduced_neighbor_report), + offsetof(tDot11fIEreduced_neighbor_report, present), 0, + "reduced_neighbor_report", 0, 7, 22, SigIereduced_neighbor_report, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REDUCED_NEIGHBOR_REPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_beacon_i_es(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fBeaconIEs *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_BeaconIEs, IES_BeaconIEs, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_beacon_i_es. */ + +static const tFFDefn FFS_ChannelSwitch[] = { + { "Category", offsetof(tDot11fChannelSwitch, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fChannelSwitch, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ChannelSwitch[] = { + { offsetof(tDot11fChannelSwitch, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, 1, }, + { offsetof(tDot11fChannelSwitch, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, 0, }, + { offsetof(tDot11fChannelSwitch, WiderBWChanSwitchAnn), + offsetof(tDot11fIEWiderBWChanSwitchAnn, present), 0, + "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_channel_switch(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fChannelSwitch *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ChannelSwitch, IES_ChannelSwitch, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_channel_switch. */ + +static const tFFDefn FFS_DeAuth[] = { + { "Reason", offsetof(tDot11fDeAuth, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_DeAuth[] = { + { offsetof(tDot11fDeAuth, P2PDeAuth), offsetof(tDot11fIEP2PDeAuth, + present), 0, "P2PDeAuth", 0, 6, 10, SigIeP2PDeAuth, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PDEAUTH, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_de_auth(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDeAuth *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_DeAuth, IES_DeAuth, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_de_auth. */ + +static const tFFDefn FFS_DelTS[] = { + { "Category", offsetof(tDot11fDelTS, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fDelTS, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TSInfo", offsetof(tDot11fDelTS, TSInfo), SigFfTSInfo, + DOT11F_FF_TSINFO_LEN, }, + { "Reason", offsetof(tDot11fDelTS, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_DelTS[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDelTS *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_DelTS, IES_DelTS, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_del_ts. */ + +static const tFFDefn FFS_Disassociation[] = { + { "Reason", offsetof(tDot11fDisassociation, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_Disassociation[] = { + { offsetof(tDot11fDisassociation, P2PDisAssoc), + offsetof(tDot11fIEP2PDisAssoc, present), 0, "P2PDisAssoc", + 0, 6, 10, SigIeP2PDisAssoc, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PDISASSOC, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_disassociation(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fDisassociation *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_Disassociation, IES_Disassociation, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_disassociation. */ + +static const tFFDefn FFS_LinkMeasurementReport[] = { + { "Category", offsetof(tDot11fLinkMeasurementReport, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fLinkMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fLinkMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "TPCEleID", offsetof(tDot11fLinkMeasurementReport, TPCEleID), + SigFfTPCEleID, DOT11F_FF_TPCELEID_LEN, }, + { "TPCEleLen", offsetof(tDot11fLinkMeasurementReport, TPCEleLen), + SigFfTPCEleLen, DOT11F_FF_TPCELELEN_LEN, }, + { "TxPower", offsetof(tDot11fLinkMeasurementReport, TxPower), + SigFfTxPower, DOT11F_FF_TXPOWER_LEN, }, + { "LinkMargin", offsetof(tDot11fLinkMeasurementReport, LinkMargin), + SigFfLinkMargin, DOT11F_FF_LINKMARGIN_LEN, }, + { "RxAntennaId", offsetof(tDot11fLinkMeasurementReport, RxAntennaId), + SigFfRxAntennaId, DOT11F_FF_RXANTENNAID_LEN, }, + { "TxAntennaId", offsetof(tDot11fLinkMeasurementReport, TxAntennaId), + SigFfTxAntennaId, DOT11F_FF_TXANTENNAID_LEN, }, + { "RCPI", offsetof(tDot11fLinkMeasurementReport, RCPI), SigFfRCPI, + DOT11F_FF_RCPI_LEN, }, + { "RSNI", offsetof(tDot11fLinkMeasurementReport, RSNI), SigFfRSNI, + DOT11F_FF_RSNI_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_LinkMeasurementReport[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_link_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementReport *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_LinkMeasurementReport, IES_LinkMeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_link_measurement_report. */ + +static const tFFDefn FFS_LinkMeasurementRequest[] = { + { "Category", offsetof(tDot11fLinkMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fLinkMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fLinkMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "TxPower", offsetof(tDot11fLinkMeasurementRequest, TxPower), + SigFfTxPower, DOT11F_FF_TXPOWER_LEN, }, + { "MaxTxPower", offsetof(tDot11fLinkMeasurementRequest, MaxTxPower), + SigFfMaxTxPower, DOT11F_FF_MAXTXPOWER_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_LinkMeasurementRequest[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_link_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fLinkMeasurementRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_LinkMeasurementRequest, IES_LinkMeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_link_measurement_request. */ + +static const tFFDefn FFS_MeasurementReport[] = { + { "Category", offsetof(tDot11fMeasurementReport, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_MeasurementReport[] = { + { offsetof(tDot11fMeasurementReport, MeasurementReport), + offsetof(tDot11fIEMeasurementReport, present), 0, "MeasurementReport", + 0, 5, 60, SigIeMeasurementReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREPORT, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementReport *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_MeasurementReport, IES_MeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_measurement_report. */ + +static const tFFDefn FFS_MeasurementRequest[] = { + { "Category", offsetof(tDot11fMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_MeasurementRequest[] = { + { offsetof(tDot11fMeasurementRequest, MeasurementRequest), + offsetof(tDot11fIEMeasurementRequest, present), + offsetof(tDot11fMeasurementRequest, num_MeasurementRequest), + "MeasurementRequest", 4, 6, 18, SigIeMeasurementRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREQUEST, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fMeasurementRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_MeasurementRequest, IES_MeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_measurement_request. */ + +static const tFFDefn FFS_NeighborReportRequest[] = { + { "Category", offsetof(tDot11fNeighborReportRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fNeighborReportRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fNeighborReportRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReportRequest[] = { + { offsetof(tDot11fNeighborReportRequest, SSID), offsetof(tDot11fIESSID, + present), 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SSID, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_neighbor_report_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_NeighborReportRequest, IES_NeighborReportRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_neighbor_report_request. */ + +static const tFFDefn FFS_NeighborReportResponse[] = { + { "Category", offsetof(tDot11fNeighborReportResponse, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fNeighborReportResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fNeighborReportResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_NeighborReportResponse[] = { + { offsetof(tDot11fNeighborReportResponse, NeighborReport), + offsetof(tDot11fIENeighborReport, present), + offsetof(tDot11fNeighborReportResponse, num_NeighborReport), + "NeighborReport", 15, 15, 548, SigIeNeighborReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_NEIGHBORREPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_neighbor_report_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fNeighborReportResponse *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_NeighborReportResponse, IES_NeighborReportResponse, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_neighbor_report_response. */ + +static const tFFDefn FFS_OperatingMode[] = { + { "Category", offsetof(tDot11fOperatingMode, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fOperatingMode, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "OperatingMode", offsetof(tDot11fOperatingMode, OperatingMode), + SigFfOperatingMode, DOT11F_FF_OPERATINGMODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_OperatingMode[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_operating_mode(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fOperatingMode *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_OperatingMode, IES_OperatingMode, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_operating_mode. */ + +static const tFFDefn FFS_ProbeRequest[] = { + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ProbeRequest[] = { + { offsetof(tDot11fProbeRequest, SSID), offsetof(tDot11fIESSID, present), 0, + "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fProbeRequest, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fProbeRequest, RequestedInfo), + offsetof(tDot11fIERequestedInfo, present), 0, "RequestedInfo", + 0, 2, 257, SigIeRequestedInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_REQUESTEDINFO, 0, 0, }, + { offsetof(tDot11fProbeRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fProbeRequest, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, 0, }, + { offsetof(tDot11fProbeRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fProbeRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fProbeRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fProbeRequest, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fProbeRequest, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fProbeRequest, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fProbeRequest, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fProbeRequest, WscProbeReq), + offsetof(tDot11fIEWscProbeReq, present), 0, "WscProbeReq", + 0, 6, 286, SigIeWscProbeReq, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCPROBEREQ, 0, 0, }, + { offsetof(tDot11fProbeRequest, WFATPC), offsetof(tDot11fIEWFATPC, + present), 0, "WFATPC", 0, 9, 9, SigIeWFATPC, {0, 80, 242, 8, 0}, + 5, DOT11F_EID_WFATPC, 0, 0, }, + { offsetof(tDot11fProbeRequest, P2PProbeReq), + offsetof(tDot11fIEP2PProbeReq, present), 0, "P2PProbeReq", + 0, 6, 43, SigIeP2PProbeReq, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PPROBEREQ, 0, 0, }, + { offsetof(tDot11fProbeRequest, qcn_ie), offsetof(tDot11fIEqcn_ie, + present), 0, "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_probe_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ProbeRequest, IES_ProbeRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_probe_request. */ + +static const tFFDefn FFS_ProbeResponse[] = { + { "TimeStamp", offsetof(tDot11fProbeResponse, TimeStamp), SigFfTimeStamp, + DOT11F_FF_TIMESTAMP_LEN, }, + { "BeaconInterval", offsetof(tDot11fProbeResponse, BeaconInterval), + SigFfBeaconInterval, DOT11F_FF_BEACONINTERVAL_LEN, }, + { "Capabilities", offsetof(tDot11fProbeResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ProbeResponse[] = { + { offsetof(tDot11fProbeResponse, SSID), offsetof(tDot11fIESSID, present), + 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fProbeResponse, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fProbeResponse, FHParamSet), + offsetof(tDot11fIEFHParamSet, present), 0, "FHParamSet", + 0, 7, 7, SigIeFHParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMSET, 0, 0, }, + { offsetof(tDot11fProbeResponse, DSParams), offsetof(tDot11fIEDSParams, + present), 0, "DSParams", 0, 3, 3, SigIeDSParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DSPARAMS, 0, 0, }, + { offsetof(tDot11fProbeResponse, CFParams), offsetof(tDot11fIECFParams, + present), 0, "CFParams", 0, 8, 8, SigIeCFParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CFPARAMS, 0, 0, }, + { offsetof(tDot11fProbeResponse, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 8, 248, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fProbeResponse, FHParams), offsetof(tDot11fIEFHParams, + present), 0, "FHParams", 0, 4, 4, SigIeFHParams, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPARAMS, 0, 0, }, + { offsetof(tDot11fProbeResponse, FHPattTable), + offsetof(tDot11fIEFHPattTable, present), 0, "FHPattTable", + 0, 6, 257, SigIeFHPattTable, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FHPATTTABLE, 0, 0, }, + { offsetof(tDot11fProbeResponse, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, 0, }, + { offsetof(tDot11fProbeResponse, ChanSwitchAnn), + offsetof(tDot11fIEChanSwitchAnn, present), 0, "ChanSwitchAnn", + 0, 5, 5, SigIeChanSwitchAnn, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_CHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fProbeResponse, Quiet), offsetof(tDot11fIEQuiet, + present), 0, "Quiet", 0, 8, 8, SigIeQuiet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QUIET, 0, 0, }, + { offsetof(tDot11fProbeResponse, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, 0, }, + { offsetof(tDot11fProbeResponse, ERPInfo), offsetof(tDot11fIEERPInfo, + present), 0, "ERPInfo", 0, 3, 3, SigIeERPInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ERPINFO, 0, 0, }, + { offsetof(tDot11fProbeResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fProbeResponse, RSNOpaque), offsetof(tDot11fIERSNOpaque, + present), 0, "RSNOpaque", 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { offsetof(tDot11fProbeResponse, QBSSLoad), offsetof(tDot11fIEQBSSLoad, + present), 0, "QBSSLoad", 0, 7, 7, SigIeQBSSLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QBSSLOAD, 0, 0, }, + { offsetof(tDot11fProbeResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fProbeResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fProbeResponse, APChannelReport), + offsetof(tDot11fIEAPChannelReport, present), 0, "APChannelReport", + 0, 3, 53, SigIeAPChannelReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_APCHANNELREPORT, 0, 0, }, + { offsetof(tDot11fProbeResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fProbeResponse, ext_chan_switch_ann), + offsetof(tDot11fIEext_chan_switch_ann, present), 0, "ext_chan_switch_ann", + 0, 6, 6, SigIeext_chan_switch_ann, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXT_CHAN_SWITCH_ANN, 0, 0, }, + { offsetof(tDot11fProbeResponse, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fProbeResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fProbeResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fProbeResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, 0, }, + { offsetof(tDot11fProbeResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fProbeResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fProbeResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fProbeResponse, transmit_power_env), + offsetof(tDot11fIEtransmit_power_env, present), + offsetof(tDot11fProbeResponse, num_transmit_power_env), + "transmit_power_env", 8, 4, 20, SigIetransmit_power_env, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TRANSMIT_POWER_ENV, 0, 0, }, + { offsetof(tDot11fProbeResponse, ChannelSwitchWrapper), + offsetof(tDot11fIEChannelSwitchWrapper, present), 0, + "ChannelSwitchWrapper", 0, 2, 35, SigIeChannelSwitchWrapper, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_CHANNELSWITCHWRAPPER, 0, 0, }, + { offsetof(tDot11fProbeResponse, VHTExtBssLoad), + offsetof(tDot11fIEVHTExtBssLoad, present), 0, "VHTExtBssLoad", + 0, 7, 7, SigIeVHTExtBssLoad, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTEXTBSSLOAD, 0, 0, }, + { offsetof(tDot11fProbeResponse, fils_indication), + offsetof(tDot11fIEfils_indication, present), 0, "fils_indication", + 0, 6, 259, SigIefils_indication, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FILS_INDICATION, 0, 0, }, + { offsetof(tDot11fProbeResponse, max_chan_switch_time), + offsetof(tDot11fIEmax_chan_switch_time, present), 0, + "max_chan_switch_time", 0, 5, 5, SigIemax_chan_switch_time, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_MAX_CHAN_SWITCH_TIME, 52, 0, }, + { offsetof(tDot11fProbeResponse, esp_information), + offsetof(tDot11fIEesp_information, present), 0, "esp_information", + 0, 2, 98, SigIeesp_information, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ESP_INFORMATION, 11, 0, }, + { offsetof(tDot11fProbeResponse, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fProbeResponse, he_op), offsetof(tDot11fIEhe_op, + present), 0, "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + { offsetof(tDot11fProbeResponse, spatial_reuse), + offsetof(tDot11fIEspatial_reuse, present), 0, "spatial_reuse", + 0, 3, 22, SigIespatial_reuse, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SPATIAL_REUSE, 39, 0, }, + { offsetof(tDot11fProbeResponse, bss_color_change), + offsetof(tDot11fIEbss_color_change, present), 0, "bss_color_change", + 0, 4, 4, SigIebss_color_change, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_COLOR_CHANGE, 42, 0, }, + { offsetof(tDot11fProbeResponse, mu_edca_param_set), + offsetof(tDot11fIEmu_edca_param_set, present), 0, "mu_edca_param_set", + 0, 15, 15, SigIemu_edca_param_set, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MU_EDCA_PARAM_SET, 38, 0, }, + { offsetof(tDot11fProbeResponse, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fProbeResponse, sec_chan_offset_ele), + offsetof(tDot11fIEsec_chan_offset_ele, present), 0, "sec_chan_offset_ele", + 0, 3, 3, SigIesec_chan_offset_ele, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SEC_CHAN_OFFSET_ELE, 0, 0, }, + { offsetof(tDot11fProbeResponse, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, 0, }, + { offsetof(tDot11fProbeResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, 0, }, + { offsetof(tDot11fProbeResponse, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fProbeResponse, eht_op), offsetof(tDot11fIEeht_op, + present), 0, "eht_op", 0, 10, 12, SigIeeht_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_OP, 106, 0, }, + { offsetof(tDot11fProbeResponse, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fProbeResponse, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11fProbeResponse, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fProbeResponse, WPA), offsetof(tDot11fIEWPA, present), 0, + "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, 4, DOT11F_EID_WPA, 0, 0, }, + { offsetof(tDot11fProbeResponse, WMMInfoAp), offsetof(tDot11fIEWMMInfoAp, + present), 0, "WMMInfoAp", 0, 9, 9, SigIeWMMInfoAp, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOAP, 0, 0, }, + { offsetof(tDot11fProbeResponse, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fProbeResponse, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fProbeResponse, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, 0, }, + { offsetof(tDot11fProbeResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fProbeResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + { offsetof(tDot11fProbeResponse, WscProbeRes), + offsetof(tDot11fIEWscProbeRes, present), 0, "WscProbeRes", + 0, 6, 319, SigIeWscProbeRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCPROBERES, 0, 0, }, + { offsetof(tDot11fProbeResponse, P2PProbeRes), + offsetof(tDot11fIEP2PProbeRes, present), 0, "P2PProbeRes", + 0, 6, 1141, SigIeP2PProbeRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PPROBERES, 0, 0, }, + { offsetof(tDot11fProbeResponse, Vendor1IE), offsetof(tDot11fIEVendor1IE, + present), 0, "Vendor1IE", 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, Vendor3IE), offsetof(tDot11fIEVendor3IE, + present), 0, "Vendor3IE", 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, QComVendorIE), + offsetof(tDot11fIEQComVendorIE, present), 0, "QComVendorIE", + 0, 7, 7, SigIeQComVendorIE, {0, 160, 198, 0, 0}, + 3, DOT11F_EID_QCOMVENDORIE, 0, 0, }, + { offsetof(tDot11fProbeResponse, MBO_IE), offsetof(tDot11fIEMBO_IE, + present), 0, "MBO_IE", 0, 6, 295, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, qcn_ie), offsetof(tDot11fIEqcn_ie, + present), 0, "qcn_ie", 0, 6, 55, SigIeqcn_ie, {140, 253, 240, 1, 0}, + 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fProbeResponse, reduced_neighbor_report), + offsetof(tDot11fIEreduced_neighbor_report, present), 0, + "reduced_neighbor_report", 0, 7, 22, SigIereduced_neighbor_report, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REDUCED_NEIGHBOR_REPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_probe_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fProbeResponse *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ProbeResponse, IES_ProbeResponse, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_probe_response. */ + +static const tFFDefn FFS_QosMapConfigure[] = { + { "Category", offsetof(tDot11fQosMapConfigure, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fQosMapConfigure, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_QosMapConfigure[] = { + { offsetof(tDot11fQosMapConfigure, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 18, 60, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_qos_map_configure(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fQosMapConfigure *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_QosMapConfigure, IES_QosMapConfigure, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_qos_map_configure. */ + +static const tFFDefn FFS_RadioMeasurementReport[] = { + { "Category", offsetof(tDot11fRadioMeasurementReport, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fRadioMeasurementReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fRadioMeasurementReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RadioMeasurementReport[] = { + { offsetof(tDot11fRadioMeasurementReport, MeasurementReport), + offsetof(tDot11fIEMeasurementReport, present), + offsetof(tDot11fRadioMeasurementReport, num_MeasurementReport), + "MeasurementReport", 1, 5, 60, SigIeMeasurementReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREPORT, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_radio_measurement_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementReport *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_RadioMeasurementReport, IES_RadioMeasurementReport, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_radio_measurement_report. */ + +static const tFFDefn FFS_RadioMeasurementRequest[] = { + { "Category", offsetof(tDot11fRadioMeasurementRequest, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fRadioMeasurementRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fRadioMeasurementRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "NumOfRepetitions", offsetof(tDot11fRadioMeasurementRequest, + NumOfRepetitions), SigFfNumOfRepetitions, + DOT11F_FF_NUMOFREPETITIONS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_RadioMeasurementRequest[] = { + { offsetof(tDot11fRadioMeasurementRequest, MeasurementRequest), + offsetof(tDot11fIEMeasurementRequest, present), + offsetof(tDot11fRadioMeasurementRequest, num_MeasurementRequest), + "MeasurementRequest", 5, 6, 18, SigIeMeasurementRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MEASUREMENTREQUEST, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_radio_measurement_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fRadioMeasurementRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_RadioMeasurementRequest, IES_RadioMeasurementRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_radio_measurement_request. */ + +static const tFFDefn FFS_ReAssocRequest[] = { + { "Capabilities", offsetof(tDot11fReAssocRequest, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "ListenInterval", offsetof(tDot11fReAssocRequest, ListenInterval), + SigFfListenInterval, DOT11F_FF_LISTENINTERVAL_LEN, }, + { "CurrentAPAddress", offsetof(tDot11fReAssocRequest, CurrentAPAddress), + SigFfCurrentAPAddress, DOT11F_FF_CURRENTAPADDRESS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ReAssocRequest[] = { + { offsetof(tDot11fReAssocRequest, SSID), offsetof(tDot11fIESSID, present), + 0, "SSID", 0, 2, 34, SigIeSSID, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SSID, 0, 1, }, + { offsetof(tDot11fReAssocRequest, SuppRates), + offsetof(tDot11fIESuppRates, present), 0, "SuppRates", + 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fReAssocRequest, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fReAssocRequest, PowerCaps), + offsetof(tDot11fIEPowerCaps, present), 0, "PowerCaps", + 0, 4, 4, SigIePowerCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCAPS, 0, 0, }, + { offsetof(tDot11fReAssocRequest, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 2, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, 0, }, + { offsetof(tDot11fReAssocRequest, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, 0, }, + { offsetof(tDot11fReAssocRequest, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fReAssocRequest, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fReAssocRequest, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fReAssocRequest, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fReAssocRequest, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, 0, }, + { offsetof(tDot11fReAssocRequest, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fReAssocRequest, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fReAssocRequest, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fReAssocRequest, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fReAssocRequest, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, bss_max_idle_period), + offsetof(tDot11fIEbss_max_idle_period, present), 0, "bss_max_idle_period", + 0, 5, 5, SigIebss_max_idle_period, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_MAX_IDLE_PERIOD, 0, 0, }, + { offsetof(tDot11fReAssocRequest, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fReAssocRequest, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fReAssocRequest, WAPIOpaque), + offsetof(tDot11fIEWAPIOpaque, present), 0, "WAPIOpaque", + 0, 8, 255, SigIeWAPIOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPIOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, WAPI), offsetof(tDot11fIEWAPI, present), + 0, "WAPI", 0, 14, 112, SigIeWAPI, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_WAPI, 0, 0, }, + { offsetof(tDot11fReAssocRequest, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 18, 60, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, 0, }, + { offsetof(tDot11fReAssocRequest, ESECckmOpaque), + offsetof(tDot11fIEESECckmOpaque, present), 0, "ESECckmOpaque", + 0, 12, 26, SigIeESECckmOpaque, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESECCKMOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fReAssocRequest, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fReAssocRequest, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11fReAssocRequest, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fReAssocRequest, WPAOpaque), + offsetof(tDot11fIEWPAOpaque, present), 0, "WPAOpaque", + 0, 8, 255, SigIeWPAOpaque, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPAOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, WMMCaps), offsetof(tDot11fIEWMMCaps, + present), 0, "WMMCaps", 0, 9, 9, SigIeWMMCaps, {0, 80, 242, 2, 5}, + 5, DOT11F_EID_WMMCAPS, 0, 0, }, + { offsetof(tDot11fReAssocRequest, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, 0, }, + { offsetof(tDot11fReAssocRequest, WscIEOpaque), + offsetof(tDot11fIEWscIEOpaque, present), 0, "WscIEOpaque", + 0, 8, 255, SigIeWscIEOpaque, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCIEOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fReAssocRequest, ESEVersion), + offsetof(tDot11fIEESEVersion, present), 0, "ESEVersion", + 0, 7, 7, SigIeESEVersion, {0, 64, 150, 3, 0}, + 4, DOT11F_EID_ESEVERSION, 0, 0, }, + { offsetof(tDot11fReAssocRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fReAssocRequest, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fReAssocRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, 0, }, + { offsetof(tDot11fReAssocRequest, P2PIEOpaque), + offsetof(tDot11fIEP2PIEOpaque, present), 0, "P2PIEOpaque", + 0, 8, 255, SigIeP2PIEOpaque, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PIEOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, WFDIEOpaque), + offsetof(tDot11fIEWFDIEOpaque, present), 0, "WFDIEOpaque", + 0, 8, 255, SigIeWFDIEOpaque, {80, 111, 154, 10, 0}, + 4, DOT11F_EID_WFDIEOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fReAssocRequest, hs20vendor_ie), + offsetof(tDot11fIEhs20vendor_ie, present), 0, "hs20vendor_ie", + 0, 7, 9, SigIehs20vendor_ie, {80, 111, 154, 16, 0}, + 4, DOT11F_EID_HS20VENDOR_IE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_re_assoc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ReAssocRequest, IES_ReAssocRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_re_assoc_request. */ + +static const tFFDefn FFS_ReAssocResponse[] = { + { "Capabilities", offsetof(tDot11fReAssocResponse, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { "Status", offsetof(tDot11fReAssocResponse, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "AID", offsetof(tDot11fReAssocResponse, AID), SigFfAID, + DOT11F_FF_AID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ReAssocResponse[] = { + { offsetof(tDot11fReAssocResponse, SuppRates), + offsetof(tDot11fIESuppRates, present), 0, "SuppRates", + 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fReAssocResponse, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fReAssocResponse, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fReAssocResponse, RCPIIE), offsetof(tDot11fIERCPIIE, + present), 0, "RCPIIE", 0, 3, 3, SigIeRCPIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RCPIIE, 0, 0, }, + { offsetof(tDot11fReAssocResponse, RSNIIE), offsetof(tDot11fIERSNIIE, + present), 0, "RSNIIE", 0, 3, 3, SigIeRSNIIE, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNIIE, 0, 0, }, + { offsetof(tDot11fReAssocResponse, RRMEnabledCap), + offsetof(tDot11fIERRMEnabledCap, present), 0, "RRMEnabledCap", + 0, 7, 7, SigIeRRMEnabledCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RRMENABLEDCAP, 0, 0, }, + { offsetof(tDot11fReAssocResponse, RSNOpaque), + offsetof(tDot11fIERSNOpaque, present), 0, "RSNOpaque", + 0, 2, 255, SigIeRSNOpaque, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RSNOPAQUE, 0, 0, }, + { offsetof(tDot11fReAssocResponse, MobilityDomain), + offsetof(tDot11fIEMobilityDomain, present), 0, "MobilityDomain", + 0, 5, 5, SigIeMobilityDomain, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MOBILITYDOMAIN, 0, 0, }, + { offsetof(tDot11fReAssocResponse, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fReAssocResponse, RICDataDesc), + offsetof(tDot11fIERICDataDesc, present), + offsetof(tDot11fReAssocResponse, num_RICDataDesc), "RICDataDesc", + 2, 2, 550, SigIeRICDataDesc, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATADESC, 0, 0, }, + { offsetof(tDot11fReAssocResponse, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fReAssocResponse, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fReAssocResponse, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fReAssocResponse, OBSSScanParameters), + offsetof(tDot11fIEOBSSScanParameters, present), 0, "OBSSScanParameters", + 0, 16, 16, SigIeOBSSScanParameters, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OBSSSCANPARAMETERS, 0, 0, }, + { offsetof(tDot11fReAssocResponse, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fReAssocResponse, bss_max_idle_period), + offsetof(tDot11fIEbss_max_idle_period, present), 0, "bss_max_idle_period", + 0, 5, 5, SigIebss_max_idle_period, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_MAX_IDLE_PERIOD, 0, 0, }, + { offsetof(tDot11fReAssocResponse, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fReAssocResponse, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fReAssocResponse, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fReAssocResponse, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fReAssocResponse, he_op), offsetof(tDot11fIEhe_op, + present), 0, "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + { offsetof(tDot11fReAssocResponse, spatial_reuse), + offsetof(tDot11fIEspatial_reuse, present), 0, "spatial_reuse", + 0, 3, 22, SigIespatial_reuse, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SPATIAL_REUSE, 39, 0, }, + { offsetof(tDot11fReAssocResponse, bss_color_change), + offsetof(tDot11fIEbss_color_change, present), 0, "bss_color_change", + 0, 4, 4, SigIebss_color_change, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BSS_COLOR_CHANGE, 42, 0, }, + { offsetof(tDot11fReAssocResponse, mu_edca_param_set), + offsetof(tDot11fIEmu_edca_param_set, present), 0, "mu_edca_param_set", + 0, 15, 15, SigIemu_edca_param_set, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MU_EDCA_PARAM_SET, 38, 0, }, + { offsetof(tDot11fReAssocResponse, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + { offsetof(tDot11fReAssocResponse, QosMapSet), + offsetof(tDot11fIEQosMapSet, present), 0, "QosMapSet", + 0, 18, 60, SigIeQosMapSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSMAPSET, 0, 0, }, + { offsetof(tDot11fReAssocResponse, ESETxmitPower), + offsetof(tDot11fIEESETxmitPower, present), 0, "ESETxmitPower", + 0, 8, 8, SigIeESETxmitPower, {0, 64, 150, 0, 0}, + 4, DOT11F_EID_ESETXMITPOWER, 0, 0, }, + { offsetof(tDot11fReAssocResponse, eht_cap), offsetof(tDot11fIEeht_cap, + present), 0, "eht_cap", 0, 26, 88, SigIeeht_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_CAP, 108, 0, }, + { offsetof(tDot11fReAssocResponse, eht_op), offsetof(tDot11fIEeht_op, + present), 0, "eht_op", 0, 10, 12, SigIeeht_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EHT_OP, 106, 0, }, + { offsetof(tDot11fReAssocResponse, mlo_ie), offsetof(tDot11fIEmlo_ie, + present), 0, "mlo_ie", 0, 11, 257, SigIemlo_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_MLO_IE, 107, 0, }, + { offsetof(tDot11fReAssocResponse, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11fReAssocResponse, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + { offsetof(tDot11fReAssocResponse, WPA), offsetof(tDot11fIEWPA, present), + 0, "WPA", 0, 8, 50, SigIeWPA, {0, 80, 242, 1, 0}, + 4, DOT11F_EID_WPA, 0, 0, }, + { offsetof(tDot11fReAssocResponse, WMMParams), + offsetof(tDot11fIEWMMParams, present), 0, "WMMParams", + 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fReAssocResponse, ESERadMgmtCap), + offsetof(tDot11fIEESERadMgmtCap, present), 0, "ESERadMgmtCap", + 0, 8, 8, SigIeESERadMgmtCap, {0, 64, 150, 1, 0}, + 4, DOT11F_EID_ESERADMGMTCAP, 0, 0, }, + { offsetof(tDot11fReAssocResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + { offsetof(tDot11fReAssocResponse, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), offsetof(tDot11fReAssocResponse, num_WMMTSPEC), "WMMTSPEC", + 4, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fReAssocResponse, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, 0, }, + { offsetof(tDot11fReAssocResponse, WscReassocRes), + offsetof(tDot11fIEWscReassocRes, present), 0, "WscReassocRes", + 0, 6, 37, SigIeWscReassocRes, {0, 80, 242, 4, 0}, + 4, DOT11F_EID_WSCREASSOCRES, 0, 0, }, + { offsetof(tDot11fReAssocResponse, P2PAssocRes), + offsetof(tDot11fIEP2PAssocRes, present), 0, "P2PAssocRes", + 0, 6, 17, SigIeP2PAssocRes, {80, 111, 154, 9, 0}, + 4, DOT11F_EID_P2PASSOCRES, 0, 0, }, + { offsetof(tDot11fReAssocResponse, vendor_vht_ie), + offsetof(tDot11fIEvendor_vht_ie, present), 0, "vendor_vht_ie", + 0, 7, 28, SigIevendor_vht_ie, {0, 144, 76, 4, 0}, + 4, DOT11F_EID_VENDOR_VHT_IE, 0, 0, }, + { offsetof(tDot11fReAssocResponse, MBO_IE), offsetof(tDot11fIEMBO_IE, + present), 0, "MBO_IE", 0, 6, 295, SigIeMBO_IE, {80, 111, 154, 22, 0}, + 4, DOT11F_EID_MBO_IE, 0, 0, }, + { offsetof(tDot11fReAssocResponse, reduced_neighbor_report), + offsetof(tDot11fIEreduced_neighbor_report, present), 0, + "reduced_neighbor_report", 0, 7, 22, SigIereduced_neighbor_report, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_REDUCED_NEIGHBOR_REPORT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_re_assoc_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fReAssocResponse *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ReAssocResponse, IES_ReAssocResponse, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_re_assoc_response. */ + +static const tFFDefn FFS_SMPowerSave[] = { + { "Category", offsetof(tDot11fSMPowerSave, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSMPowerSave, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "SMPowerModeSet", offsetof(tDot11fSMPowerSave, SMPowerModeSet), + SigFfSMPowerModeSet, DOT11F_FF_SMPOWERMODESET_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SMPowerSave[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sm_power_save(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSMPowerSave *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SMPowerSave, IES_SMPowerSave, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_sm_power_save. */ + +static const tFFDefn FFS_SaQueryReq[] = { + { "Category", offsetof(tDot11fSaQueryReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSaQueryReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TransactionId", offsetof(tDot11fSaQueryReq, TransactionId), + SigFfTransactionId, DOT11F_FF_TRANSACTIONID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SaQueryReq[] = { + { offsetof(tDot11fSaQueryReq, oci), offsetof(tDot11fIEoci, present), 0, + "oci", 0, 5, 5, SigIeoci, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OCI, 54, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sa_query_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryReq *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SaQueryReq, IES_SaQueryReq, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_sa_query_req. */ + +static const tFFDefn FFS_SaQueryRsp[] = { + { "Category", offsetof(tDot11fSaQueryRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fSaQueryRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "TransactionId", offsetof(tDot11fSaQueryRsp, TransactionId), + SigFfTransactionId, DOT11F_FF_TRANSACTIONID_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_SaQueryRsp[] = { + { offsetof(tDot11fSaQueryRsp, oci), offsetof(tDot11fIEoci, present), 0, + "oci", 0, 5, 5, SigIeoci, {0, 0, 0, 0, 0}, 0, DOT11F_EID_OCI, 54, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_sa_query_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fSaQueryRsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_SaQueryRsp, IES_SaQueryRsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_sa_query_rsp. */ + +static const tFFDefn FFS_TDLSDisReq[] = { + { "Category", offsetof(tDot11fTDLSDisReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSDisReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSDisReq, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSDisReq[] = { + { offsetof(tDot11fTDLSDisReq, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_dis_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisReq *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSDisReq, IES_TDLSDisReq, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_dis_req. */ + +static const tFFDefn FFS_TDLSDisRsp[] = { + { "Category", offsetof(tDot11fTDLSDisRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSDisRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSDisRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSDisRsp, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSDisRsp[] = { + { offsetof(tDot11fTDLSDisRsp, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fTDLSDisRsp, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 2, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 4, 132, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, ExtCap), offsetof(tDot11fIEExtCap, present), + 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, FTInfo), offsetof(tDot11fIEFTInfo, present), + 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, HTCaps), offsetof(tDot11fIEHTCaps, present), + 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 1, }, + { offsetof(tDot11fTDLSDisRsp, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fTDLSDisRsp, he_cap), offsetof(tDot11fIEhe_cap, present), + 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_dis_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSDisRsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSDisRsp, IES_TDLSDisRsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_dis_rsp. */ + +static const tFFDefn FFS_TDLSPeerTrafficInd[] = { + { "Category", offsetof(tDot11fTDLSPeerTrafficInd, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSPeerTrafficInd, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSPeerTrafficInd, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSPeerTrafficInd[] = { + { offsetof(tDot11fTDLSPeerTrafficInd, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 1, }, + { offsetof(tDot11fTDLSPeerTrafficInd, PTIControl), + offsetof(tDot11fIEPTIControl, present), 0, "PTIControl", + 0, 5, 5, SigIePTIControl, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_PTICONTROL, 0, 0, }, + { offsetof(tDot11fTDLSPeerTrafficInd, PUBufferStatus), + offsetof(tDot11fIEPUBufferStatus, present), 0, "PUBufferStatus", + 0, 3, 3, SigIePUBufferStatus, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_PUBUFFERSTATUS, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficInd *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSPeerTrafficInd, IES_TDLSPeerTrafficInd, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_ind. */ + +static const tFFDefn FFS_TDLSPeerTrafficRsp[] = { + { "Category", offsetof(tDot11fTDLSPeerTrafficRsp, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSPeerTrafficRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSPeerTrafficRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSPeerTrafficRsp[] = { + { offsetof(tDot11fTDLSPeerTrafficRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSPeerTrafficRsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSPeerTrafficRsp, IES_TDLSPeerTrafficRsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_rsp. */ + +static const tFFDefn FFS_TDLSSetupCnf[] = { + { "Category", offsetof(tDot11fTDLSSetupCnf, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupCnf, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Status", offsetof(tDot11fTDLSSetupCnf, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupCnf, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupCnf[] = { + { offsetof(tDot11fTDLSSetupCnf, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 4, 132, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, EDCAParamSet), + offsetof(tDot11fIEEDCAParamSet, present), 0, "EDCAParamSet", + 0, 20, 20, SigIeEDCAParamSet, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EDCAPARAMSET, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, HTInfo), offsetof(tDot11fIEHTInfo, + present), 0, "HTInfo", 0, 24, 56, SigIeHTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTINFO, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, WMMParams), offsetof(tDot11fIEWMMParams, + present), 0, "WMMParams", 0, 26, 26, SigIeWMMParams, {0, 80, 242, 2, 1}, + 5, DOT11F_EID_WMMPARAMS, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, VHTOperation), + offsetof(tDot11fIEVHTOperation, present), 0, "VHTOperation", + 0, 7, 7, SigIeVHTOperation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTOPERATION, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fTDLSSetupCnf, he_op), offsetof(tDot11fIEhe_op, present), + 0, "he_op", 0, 8, 17, SigIehe_op, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_OP, 36, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_cnf(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupCnf *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupCnf, IES_TDLSSetupCnf, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_cnf. */ + +static const tFFDefn FFS_TDLSSetupReq[] = { + { "Category", offsetof(tDot11fTDLSSetupReq, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupReq, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupReq, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSSetupReq, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupReq[] = { + { offsetof(tDot11fTDLSSetupReq, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 1, }, + { offsetof(tDot11fTDLSSetupReq, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 8, 248, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 2, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 4, 132, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 1, }, + { offsetof(tDot11fTDLSSetupReq, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, AID), offsetof(tDot11fIEAID, present), 0, + "AID", 0, 4, 4, SigIeAID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_AID, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fTDLSSetupReq, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fTDLSSetupReq, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupReq *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupReq, IES_TDLSSetupReq, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_req. */ + +static const tFFDefn FFS_TDLSSetupRsp[] = { + { "Category", offsetof(tDot11fTDLSSetupRsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSSetupRsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Status", offsetof(tDot11fTDLSSetupRsp, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "DialogToken", offsetof(tDot11fTDLSSetupRsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Capabilities", offsetof(tDot11fTDLSSetupRsp, Capabilities), + SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSSetupRsp[] = { + { offsetof(tDot11fTDLSSetupRsp, SuppRates), offsetof(tDot11fIESuppRates, + present), 0, "SuppRates", 0, 2, 14, SigIeSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPRATES, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, Country), offsetof(tDot11fIECountry, + present), 0, "Country", 0, 8, 248, SigIeCountry, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ExtSuppRates), + offsetof(tDot11fIEExtSuppRates, present), 0, "ExtSuppRates", + 0, 3, 14, SigIeExtSuppRates, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTSUPPRATES, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, SuppChannels), + offsetof(tDot11fIESuppChannels, present), 0, "SuppChannels", + 0, 2, 98, SigIeSuppChannels, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_SUPPCHANNELS, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, RSN), offsetof(tDot11fIERSN, present), 0, + "RSN", 0, 4, 132, SigIeRSN, {0, 0, 0, 0, 0}, 0, DOT11F_EID_RSN, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ExtCap), offsetof(tDot11fIEExtCap, + present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, SuppOperatingClasses), + offsetof(tDot11fIESuppOperatingClasses, present), 0, + "SuppOperatingClasses", 0, 3, 34, SigIeSuppOperatingClasses, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_SUPPOPERATINGCLASSES, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, QOSCapsStation), + offsetof(tDot11fIEQOSCapsStation, present), 0, "QOSCapsStation", + 0, 3, 3, SigIeQOSCapsStation, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_QOSCAPSSTATION, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, TimeoutInterval), + offsetof(tDot11fIETimeoutInterval, present), 0, "TimeoutInterval", + 0, 7, 7, SigIeTimeoutInterval, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEOUTINTERVAL, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, RICData), offsetof(tDot11fIERICData, + present), 0, "RICData", 0, 6, 6, SigIeRICData, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_RICDATA, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, HTCaps), offsetof(tDot11fIEHTCaps, + present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, ht2040_bss_coexistence), + offsetof(tDot11fIEht2040_bss_coexistence, present), 0, + "ht2040_bss_coexistence", 0, 3, 3, SigIeht2040_bss_coexistence, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, WMMInfoStation), + offsetof(tDot11fIEWMMInfoStation, present), 0, "WMMInfoStation", + 0, 9, 9, SigIeWMMInfoStation, {0, 80, 242, 2, 0}, + 5, DOT11F_EID_WMMINFOSTATION, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, AID), offsetof(tDot11fIEAID, present), 0, + "AID", 0, 4, 4, SigIeAID, {0, 0, 0, 0, 0}, 0, DOT11F_EID_AID, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, VHTCaps), offsetof(tDot11fIEVHTCaps, + present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + { offsetof(tDot11fTDLSSetupRsp, he_cap), offsetof(tDot11fIEhe_cap, + present), 0, "he_cap", 0, 23, 56, SigIehe_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_CAP, 35, 0, }, + { offsetof(tDot11fTDLSSetupRsp, he_6ghz_band_cap), + offsetof(tDot11fIEhe_6ghz_band_cap, present), 0, "he_6ghz_band_cap", + 0, 4, 4, SigIehe_6ghz_band_cap, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HE_6GHZ_BAND_CAP, 59, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_setup_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSSetupRsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSSetupRsp, IES_TDLSSetupRsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_setup_rsp. */ + +static const tFFDefn FFS_TDLSTeardown[] = { + { "Category", offsetof(tDot11fTDLSTeardown, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTDLSTeardown, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "Reason", offsetof(tDot11fTDLSTeardown, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TDLSTeardown[] = { + { offsetof(tDot11fTDLSTeardown, FTInfo), offsetof(tDot11fIEFTInfo, + present), 0, "FTInfo", 0, 84, 222, SigIeFTInfo, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_FTINFO, 0, 0, }, + { offsetof(tDot11fTDLSTeardown, LinkIdentifier), + offsetof(tDot11fIELinkIdentifier, present), 0, "LinkIdentifier", + 0, 20, 20, SigIeLinkIdentifier, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_LINKIDENTIFIER, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tdls_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTDLSTeardown *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TDLSTeardown, IES_TDLSTeardown, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tdls_teardown. */ + +static const tFFDefn FFS_TPCReport[] = { + { "Category", offsetof(tDot11fTPCReport, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTPCReport, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTPCReport, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TPCReport[] = { + { offsetof(tDot11fTPCReport, TPCReport), offsetof(tDot11fIETPCReport, + present), 0, "TPCReport", 0, 4, 4, SigIeTPCReport, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREPORT, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tpc_report(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCReport *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TPCReport, IES_TPCReport, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tpc_report. */ + +static const tFFDefn FFS_TPCRequest[] = { + { "Category", offsetof(tDot11fTPCRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fTPCRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fTPCRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TPCRequest[] = { + { offsetof(tDot11fTPCRequest, TPCRequest), offsetof(tDot11fIETPCRequest, + present), 0, "TPCRequest", 0, 2, 2, SigIeTPCRequest, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TPCREQUEST, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_tpc_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTPCRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TPCRequest, IES_TPCRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_tpc_request. */ + +static const tFFDefn FFS_TimingAdvertisementFrame[] = { + { "TimeStamp", offsetof(tDot11fTimingAdvertisementFrame, TimeStamp), + SigFfTimeStamp, DOT11F_FF_TIMESTAMP_LEN, }, + { "Capabilities", offsetof(tDot11fTimingAdvertisementFrame, + Capabilities), SigFfCapabilities, DOT11F_FF_CAPABILITIES_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_TimingAdvertisementFrame[] = { + { offsetof(tDot11fTimingAdvertisementFrame, Country), + offsetof(tDot11fIECountry, present), 0, "Country", 0, 8, 248, SigIeCountry, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_COUNTRY, 0, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, PowerConstraints), + offsetof(tDot11fIEPowerConstraints, present), 0, "PowerConstraints", + 0, 3, 3, SigIePowerConstraints, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_POWERCONSTRAINTS, 0, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, TimeAdvertisement), + offsetof(tDot11fIETimeAdvertisement, present), 0, "TimeAdvertisement", + 0, 18, 18, SigIeTimeAdvertisement, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_TIMEADVERTISEMENT, 0, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, ExtCap), + offsetof(tDot11fIEExtCap, present), 0, "ExtCap", 0, 3, 17, SigIeExtCap, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_EXTCAP, 0, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, Vendor1IE), + offsetof(tDot11fIEVendor1IE, present), 0, "Vendor1IE", + 0, 5, 5, SigIeVendor1IE, {0, 16, 24, 0, 0}, + 3, DOT11F_EID_VENDOR1IE, 0, 0, }, + { offsetof(tDot11fTimingAdvertisementFrame, Vendor3IE), + offsetof(tDot11fIEVendor3IE, present), 0, "Vendor3IE", + 0, 5, 5, SigIeVendor3IE, {0, 22, 50, 0, 0}, + 3, DOT11F_EID_VENDOR3IE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_timing_advertisement_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fTimingAdvertisementFrame *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_TimingAdvertisementFrame, IES_TimingAdvertisementFrame, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_timing_advertisement_frame. */ + +static const tFFDefn FFS_VHTGidManagementActionFrame[] = { + { "Category", offsetof(tDot11fVHTGidManagementActionFrame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fVHTGidManagementActionFrame, Action), + SigFfAction, DOT11F_FF_ACTION_LEN, }, + { "VhtMembershipStatusArray", + offsetof(tDot11fVHTGidManagementActionFrame, VhtMembershipStatusArray), + SigFfVhtMembershipStatusArray, + DOT11F_FF_VHTMEMBERSHIPSTATUSARRAY_LEN, }, + { "VhtUserPositionArray", offsetof(tDot11fVHTGidManagementActionFrame, + VhtUserPositionArray), SigFfVhtUserPositionArray, + DOT11F_FF_VHTUSERPOSITIONARRAY_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_VHTGidManagementActionFrame[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fVHTGidManagementActionFrame *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_VHTGidManagementActionFrame, IES_VHTGidManagementActionFrame, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_vht_gid_management_action_frame. */ + +static const tFFDefn FFS_WMMAddTSRequest[] = { + { "Category", offsetof(tDot11fWMMAddTSRequest, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMAddTSRequest, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMAddTSRequest, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMAddTSRequest, StatusCode), + SigFfStatusCode, DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMAddTSRequest[] = { + { offsetof(tDot11fWMMAddTSRequest, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 1, }, + { offsetof(tDot11fWMMAddTSRequest, ESETrafStrmRateSet), + offsetof(tDot11fIEESETrafStrmRateSet, present), 0, "ESETrafStrmRateSet", + 0, 7, 15, SigIeESETrafStrmRateSet, {0, 64, 150, 8, 0}, + 4, DOT11F_EID_ESETRAFSTRMRATESET, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_add_ts_request(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSRequest *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMAddTSRequest, IES_WMMAddTSRequest, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_add_ts_request. */ + +static const tFFDefn FFS_WMMAddTSResponse[] = { + { "Category", offsetof(tDot11fWMMAddTSResponse, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMAddTSResponse, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMAddTSResponse, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMAddTSResponse, StatusCode), + SigFfStatusCode, DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMAddTSResponse[] = { + { offsetof(tDot11fWMMAddTSResponse, WMMTSPEC), + offsetof(tDot11fIEWMMTSPEC, present), 0, "WMMTSPEC", + 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 0, }, + { offsetof(tDot11fWMMAddTSResponse, ESETrafStrmMet), + offsetof(tDot11fIEESETrafStrmMet, present), 0, "ESETrafStrmMet", + 0, 10, 10, SigIeESETrafStrmMet, {0, 64, 150, 7, 0}, + 4, DOT11F_EID_ESETRAFSTRMMET, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_add_ts_response(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMAddTSResponse *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMAddTSResponse, IES_WMMAddTSResponse, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_add_ts_response. */ + +static const tFFDefn FFS_WMMDelTS[] = { + { "Category", offsetof(tDot11fWMMDelTS, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fWMMDelTS, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fWMMDelTS, DialogToken), SigFfDialogToken, + DOT11F_FF_DIALOGTOKEN_LEN, }, + { "StatusCode", offsetof(tDot11fWMMDelTS, StatusCode), SigFfStatusCode, + DOT11F_FF_STATUSCODE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_WMMDelTS[] = { + { offsetof(tDot11fWMMDelTS, WMMTSPEC), offsetof(tDot11fIEWMMTSPEC, + present), 0, "WMMTSPEC", 0, 63, 63, SigIeWMMTSPEC, {0, 80, 242, 2, 2}, + 5, DOT11F_EID_WMMTSPEC, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_wmm_del_ts(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fWMMDelTS *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_WMMDelTS, IES_WMMDelTS, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_wmm_del_ts. */ + +static const tFFDefn FFS_addba_req[] = { + { "Category", offsetof(tDot11faddba_req, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11faddba_req, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11faddba_req, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "addba_param_set", offsetof(tDot11faddba_req, addba_param_set), + SigFfaddba_param_set, DOT11F_FF_ADDBA_PARAM_SET_LEN, }, + { "ba_timeout", offsetof(tDot11faddba_req, ba_timeout), SigFfba_timeout, + DOT11F_FF_BA_TIMEOUT_LEN, }, + { "ba_start_seq_ctrl", offsetof(tDot11faddba_req, ba_start_seq_ctrl), + SigFfba_start_seq_ctrl, DOT11F_FF_BA_START_SEQ_CTRL_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_addba_req[] = { + { offsetof(tDot11faddba_req, addba_extn_element), + offsetof(tDot11fIEaddba_extn_element, present), 0, "addba_extn_element", + 0, 3, 3, SigIeaddba_extn_element, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ADDBA_EXTN_ELEMENT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_addba_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11faddba_req *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_addba_req, IES_addba_req, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_addba_req. */ + +static const tFFDefn FFS_addba_rsp[] = { + { "Category", offsetof(tDot11faddba_rsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11faddba_rsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11faddba_rsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Status", offsetof(tDot11faddba_rsp, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { "addba_param_set", offsetof(tDot11faddba_rsp, addba_param_set), + SigFfaddba_param_set, DOT11F_FF_ADDBA_PARAM_SET_LEN, }, + { "ba_timeout", offsetof(tDot11faddba_rsp, ba_timeout), SigFfba_timeout, + DOT11F_FF_BA_TIMEOUT_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_addba_rsp[] = { + { offsetof(tDot11faddba_rsp, addba_extn_element), + offsetof(tDot11fIEaddba_extn_element, present), 0, "addba_extn_element", + 0, 3, 3, SigIeaddba_extn_element, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_ADDBA_EXTN_ELEMENT, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_addba_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11faddba_rsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_addba_rsp, IES_addba_rsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_addba_rsp. */ + +static const tFFDefn FFS_delba_req[] = { + { "Category", offsetof(tDot11fdelba_req, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fdelba_req, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "delba_param_set", offsetof(tDot11fdelba_req, delba_param_set), + SigFfdelba_param_set, DOT11F_FF_DELBA_PARAM_SET_LEN, }, + { "Reason", offsetof(tDot11fdelba_req, Reason), SigFfReason, + DOT11F_FF_REASON_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_delba_req[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_delba_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fdelba_req *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_delba_req, IES_delba_req, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_delba_req. */ + +static const tFFDefn FFS_epcs_neg_req[] = { + { "Category", offsetof(tDot11fepcs_neg_req, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fepcs_neg_req, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fepcs_neg_req, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_epcs_neg_req[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_epcs_neg_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fepcs_neg_req *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_epcs_neg_req, IES_epcs_neg_req, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_epcs_neg_req. */ + +static const tFFDefn FFS_epcs_neg_rsp[] = { + { "Category", offsetof(tDot11fepcs_neg_rsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fepcs_neg_rsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fepcs_neg_rsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Status", offsetof(tDot11fepcs_neg_rsp, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_epcs_neg_rsp[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_epcs_neg_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fepcs_neg_rsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_epcs_neg_rsp, IES_epcs_neg_rsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_epcs_neg_rsp. */ + +static const tFFDefn FFS_epcs_teardown[] = { + { "Category", offsetof(tDot11fepcs_teardown, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fepcs_teardown, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_epcs_teardown[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_epcs_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fepcs_teardown *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_epcs_teardown, IES_epcs_teardown, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_epcs_teardown. */ + +static const tFFDefn FFS_ext_channel_switch_action_frame[] = { + { "Category", offsetof(tDot11fext_channel_switch_action_frame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fext_channel_switch_action_frame, Action), + SigFfAction, DOT11F_FF_ACTION_LEN, }, + { "ext_chan_switch_ann_action", + offsetof(tDot11fext_channel_switch_action_frame, + ext_chan_switch_ann_action), SigFfext_chan_switch_ann_action, + DOT11F_FF_EXT_CHAN_SWITCH_ANN_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ext_channel_switch_action_frame[] = { + { offsetof(tDot11fext_channel_switch_action_frame, + WiderBWChanSwitchAnn), offsetof(tDot11fIEWiderBWChanSwitchAnn, present), + 0, "WiderBWChanSwitchAnn", 0, 5, 5, SigIeWiderBWChanSwitchAnn, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_WIDERBWCHANSWITCHANN, 0, 0, }, + { offsetof(tDot11fext_channel_switch_action_frame, qcn_ie), + offsetof(tDot11fIEqcn_ie, present), 0, "qcn_ie", 0, 6, 55, SigIeqcn_ie, + {140, 253, 240, 1, 0}, 4, DOT11F_EID_QCN_IE, 0, 0, }, + { offsetof(tDot11fext_channel_switch_action_frame, bw_ind_element), + offsetof(tDot11fIEbw_ind_element, present), 0, "bw_ind_element", + 0, 6, 8, SigIebw_ind_element, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_BW_IND_ELEMENT, 135, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fext_channel_switch_action_frame *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ext_channel_switch_action_frame, IES_ext_channel_switch_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_ext_channel_switch_action_frame. */ + +static const tFFDefn FFS_ht2040_bss_coexistence_mgmt_action_frame[] = { + { "Category", offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + Category), SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + Action), SigFfAction, DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_ht2040_bss_coexistence_mgmt_action_frame[] = { + { offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + ht2040_bss_coexistence), offsetof(tDot11fIEht2040_bss_coexistence, + present), 0, "ht2040_bss_coexistence", + 0, 3, 3, SigIeht2040_bss_coexistence, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HT2040_BSS_COEXISTENCE, 0, 1, }, + { offsetof(tDot11fht2040_bss_coexistence_mgmt_action_frame, + ht2040_bss_intolerant_report), + offsetof(tDot11fIEht2040_bss_intolerant_report, present), 0, + "ht2040_bss_intolerant_report", + 0, 3, 53, SigIeht2040_bss_intolerant_report, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_HT2040_BSS_INTOLERANT_REPORT, 0, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_ht2040_bss_coexistence_mgmt_action_frame, IES_ht2040_bss_coexistence_mgmt_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame. */ + +static const tFFDefn FFS_mscs_request_action_frame[] = { + { "Category", offsetof(tDot11fmscs_request_action_frame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11fmscs_request_action_frame, Action), + SigFfAction, DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11fmscs_request_action_frame, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_mscs_request_action_frame[] = { + { offsetof(tDot11fmscs_request_action_frame, descriptor_element), + offsetof(tDot11fIEdescriptor_element, present), 0, "descriptor_element", + 0, 9, 32, SigIedescriptor_element, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_DESCRIPTOR_ELEMENT, 88, 1, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_mscs_request_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fmscs_request_action_frame *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_mscs_request_action_frame, IES_mscs_request_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_mscs_request_action_frame. */ + +static const tFFDefn FFS_p2p_oper_chan_change_confirm[] = { + { "Category", offsetof(tDot11fp2p_oper_chan_change_confirm, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "p2p_action_oui", offsetof(tDot11fp2p_oper_chan_change_confirm, + p2p_action_oui), SigFfp2p_action_oui, DOT11F_FF_P2P_ACTION_OUI_LEN, }, + { "p2p_action_subtype", offsetof(tDot11fp2p_oper_chan_change_confirm, + p2p_action_subtype), SigFfp2p_action_subtype, + DOT11F_FF_P2P_ACTION_SUBTYPE_LEN, }, + { "DialogToken", offsetof(tDot11fp2p_oper_chan_change_confirm, + DialogToken), SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_p2p_oper_chan_change_confirm[] = { + { offsetof(tDot11fp2p_oper_chan_change_confirm, HTCaps), + offsetof(tDot11fIEHTCaps, present), 0, "HTCaps", 0, 28, 60, SigIeHTCaps, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_HTCAPS, 0, 0, }, + { offsetof(tDot11fp2p_oper_chan_change_confirm, VHTCaps), + offsetof(tDot11fIEVHTCaps, present), 0, "VHTCaps", 0, 14, 14, SigIeVHTCaps, + {0, 0, 0, 0, 0}, 0, DOT11F_EID_VHTCAPS, 0, 0, }, + { offsetof(tDot11fp2p_oper_chan_change_confirm, OperatingMode), + offsetof(tDot11fIEOperatingMode, present), 0, "OperatingMode", + 0, 3, 3, SigIeOperatingMode, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_OPERATINGMODE, 0, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fp2p_oper_chan_change_confirm *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_p2p_oper_chan_change_confirm, IES_p2p_oper_chan_change_confirm, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_p2p_oper_chan_change_confirm. */ + +static const tFFDefn FFS_t2lm_neg_req[] = { + { "Category", offsetof(tDot11ft2lm_neg_req, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11ft2lm_neg_req, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11ft2lm_neg_req, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_t2lm_neg_req[] = { + { offsetof(tDot11ft2lm_neg_req, t2lm_ie), offsetof(tDot11fIEt2lm_ie, + present), offsetof(tDot11ft2lm_neg_req, num_t2lm_ie), "t2lm_ie", + 2, 5, 257, SigIet2lm_ie, {0, 0, 0, 0, 0}, + 0, DOT11F_EID_T2LM_IE, 109, 0, }, + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_t2lm_neg_req(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11ft2lm_neg_req *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_t2lm_neg_req, IES_t2lm_neg_req, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_t2lm_neg_req. */ + +static const tFFDefn FFS_t2lm_neg_rsp[] = { + { "Category", offsetof(tDot11ft2lm_neg_rsp, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11ft2lm_neg_rsp, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { "DialogToken", offsetof(tDot11ft2lm_neg_rsp, DialogToken), + SigFfDialogToken, DOT11F_FF_DIALOGTOKEN_LEN, }, + { "Status", offsetof(tDot11ft2lm_neg_rsp, Status), SigFfStatus, + DOT11F_FF_STATUS_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_t2lm_neg_rsp[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_t2lm_neg_rsp(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11ft2lm_neg_rsp *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_t2lm_neg_rsp, IES_t2lm_neg_rsp, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_t2lm_neg_rsp. */ + +static const tFFDefn FFS_t2lm_teardown[] = { + { "Category", offsetof(tDot11ft2lm_teardown, Category), SigFfCategory, + DOT11F_FF_CATEGORY_LEN, }, + { "Action", offsetof(tDot11ft2lm_teardown, Action), SigFfAction, + DOT11F_FF_ACTION_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_t2lm_teardown[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_t2lm_teardown(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11ft2lm_teardown *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_t2lm_teardown, IES_t2lm_teardown, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_t2lm_teardown. */ + +static const tFFDefn FFS_vendor_action_frame[] = { + { "Category", offsetof(tDot11fvendor_action_frame, Category), + SigFfCategory, DOT11F_FF_CATEGORY_LEN, }, + { "vendor_oui", offsetof(tDot11fvendor_action_frame, vendor_oui), + SigFfvendor_oui, DOT11F_FF_VENDOR_OUI_LEN, }, + { "vendor_action_subtype", offsetof(tDot11fvendor_action_frame, + vendor_action_subtype), SigFfvendor_action_subtype, + DOT11F_FF_VENDOR_ACTION_SUBTYPE_LEN, }, + { NULL, 0, 0, 0,}, +}; + +static const tIEDefn IES_vendor_action_frame[] = { + {0, 0, 0, NULL, 0, 0, 0, 0, {0, 0, 0, 0, 0}, 0, 0xff, 0, },}; + +uint32_t dot11f_unpack_vendor_action_frame(tpAniSirGlobal pCtx, + uint8_t *pBuf, uint32_t nBuf, + tDot11fvendor_action_frame *pFrm, bool append_ie) +{ + uint32_t i = 0; + uint32_t status = 0; + status = unpack_core(pCtx, pBuf, nBuf, + FFS_vendor_action_frame, IES_vendor_action_frame, + (uint8_t *)pFrm, sizeof(*pFrm), append_ie); + + (void)i; + return status; + +} /* End dot11f_unpack_vendor_action_frame. */ + +/** + * Note: If @append_ie is set TRUE, pFrm will not be reset to zero, + * but parsed IE's would be populated to pFrm with already + * populated IE's in pFrm + */ +static uint32_t unpack_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tFFDefn FFs[], + const tIEDefn IEs[], + uint8_t *pFrm, + size_t nFrm, + bool append_ie) +{ + const tFFDefn *pFf; + const tIEDefn *pIe; + uint8_t *pBufRemaining; + uint32_t nBufRemaining, status; + uint8_t eid, len, extn_eid; + tFRAMES_BOOL *pfFound; + uint32_t countOffset = 0; + + DOT11F_PARAMETER_CHECK(pBuf, nBuf, pFrm, nFrm); + (void)nFrm; + + (void)pCtx; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pIe = &IEs[0]; + while (!append_ie && (0xff != pIe->eid || pIe->extn_eid)) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + *pfFound = 0U; + if (pIe->countOffset) + *(uint16_t *)(pFrm + pIe->countOffset) = 0U; + ++pIe; + } + + pFf = &FFs[0]; + while (!append_ie && pFf->size) { + if (pFf->size > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("Fixed field %s is %d" + "bytes in size, but there are only %d bytes left i" + "n this frame.\n"), pFf->name, pFf->size, + nBufRemaining); + FRAMES_DBG_BREAK(); + return DOT11F_MISSING_FIXED_FIELD; + } + + switch (pFf->sig) { + + case SigFfAID: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAID *) + (pFrm + pFf->offset))->associd)); + break; + case SigFfAction: + dot11f_unpack_ff_action(pCtx, + pBufRemaining, (tDot11fFfAction *) + (pFrm + pFf->offset)); + break; + case SigFfAuthAlgo: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAuthAlgo *) + (pFrm + pFf->offset))->algo)); + break; + case SigFfAuthSeqNo: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfAuthSeqNo *) + (pFrm + pFf->offset))->no)); + break; + case SigFfBeaconInterval: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfBeaconInterval *) + (pFrm + pFf->offset))->interval)); + break; + case SigFfCapabilities: + dot11f_unpack_ff_capabilities(pCtx, + pBufRemaining, (tDot11fFfCapabilities *) + (pFrm + pFf->offset)); + break; + case SigFfCategory: + dot11f_unpack_ff_category(pCtx, + pBufRemaining, (tDot11fFfCategory *) + (pFrm + pFf->offset)); + break; + case SigFfCurrentAPAddress: + dot11f_unpack_ff_current_ap_address(pCtx, + pBufRemaining, (tDot11fFfCurrentAPAddress *) + (pFrm + pFf->offset)); + break; + case SigFfDialogToken: + dot11f_unpack_ff_dialog_token(pCtx, + pBufRemaining, (tDot11fFfDialogToken *) + (pFrm + pFf->offset)); + break; + case SigFfLinkMargin: + dot11f_unpack_ff_link_margin(pCtx, + pBufRemaining, (tDot11fFfLinkMargin *) + (pFrm + pFf->offset)); + break; + case SigFfListenInterval: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfListenInterval *) + (pFrm + pFf->offset))->interval)); + break; + case SigFfMaxTxPower: + dot11f_unpack_ff_max_tx_power(pCtx, + pBufRemaining, (tDot11fFfMaxTxPower *) + (pFrm + pFf->offset)); + break; + case SigFfNumOfRepetitions: + dot11f_unpack_ff_num_of_repetitions(pCtx, + pBufRemaining, (tDot11fFfNumOfRepetitions *) + (pFrm + pFf->offset)); + break; + case SigFfOperatingMode: + dot11f_unpack_ff_operating_mode(pCtx, + pBufRemaining, (tDot11fFfOperatingMode *) + (pFrm + pFf->offset)); + break; + case SigFfRCPI: + dot11f_unpack_ff_rcpi(pCtx, + pBufRemaining, (tDot11fFfRCPI *) + (pFrm + pFf->offset)); + break; + case SigFfRSNI: + dot11f_unpack_ff_rsni(pCtx, + pBufRemaining, (tDot11fFfRSNI *) + (pFrm + pFf->offset)); + break; + case SigFfReason: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfReason *) + (pFrm + pFf->offset))->code)); + break; + case SigFfRxAntennaId: + dot11f_unpack_ff_rx_antenna_id(pCtx, + pBufRemaining, (tDot11fFfRxAntennaId *) + (pFrm + pFf->offset)); + break; + case SigFfSMPowerModeSet: + dot11f_unpack_ff_sm_power_mode_set(pCtx, + pBufRemaining, (tDot11fFfSMPowerModeSet *) + (pFrm + pFf->offset)); + break; + case SigFfStatus: + dot11f_unpack_ff_common_func(pCtx, + pBufRemaining, (uint16_t *)&(((tDot11fFfStatus *) + (pFrm + pFf->offset))->status)); + break; + case SigFfStatusCode: + dot11f_unpack_ff_status_code(pCtx, + pBufRemaining, (tDot11fFfStatusCode *) + (pFrm + pFf->offset)); + break; + case SigFfTPCEleID: + dot11f_unpack_ff_tpc_ele_id(pCtx, + pBufRemaining, (tDot11fFfTPCEleID *) + (pFrm + pFf->offset)); + break; + case SigFfTPCEleLen: + dot11f_unpack_ff_tpc_ele_len(pCtx, + pBufRemaining, (tDot11fFfTPCEleLen *) + (pFrm + pFf->offset)); + break; + case SigFfTSInfo: + dot11f_unpack_ff_ts_info(pCtx, + pBufRemaining, (tDot11fFfTSInfo *) + (pFrm + pFf->offset)); + break; + case SigFfTimeStamp: + dot11f_unpack_ff_time_stamp(pCtx, + pBufRemaining, (tDot11fFfTimeStamp *) + (pFrm + pFf->offset)); + break; + case SigFfTransactionId: + dot11f_unpack_ff_transaction_id(pCtx, + pBufRemaining, (tDot11fFfTransactionId *) + (pFrm + pFf->offset)); + break; + case SigFfTxAntennaId: + dot11f_unpack_ff_tx_antenna_id(pCtx, + pBufRemaining, (tDot11fFfTxAntennaId *) + (pFrm + pFf->offset)); + break; + case SigFfTxPower: + dot11f_unpack_ff_tx_power(pCtx, + pBufRemaining, (tDot11fFfTxPower *) + (pFrm + pFf->offset)); + break; + case SigFfVhtMembershipStatusArray: + dot11f_unpack_ff_vht_membership_status_array(pCtx, + pBufRemaining, (tDot11fFfVhtMembershipStatusArray *) + (pFrm + pFf->offset)); + break; + case SigFfVhtUserPositionArray: + dot11f_unpack_ff_vht_user_position_array(pCtx, + pBufRemaining, (tDot11fFfVhtUserPositionArray *) + (pFrm + pFf->offset)); + break; + case SigFfaddba_param_set: + dot11f_unpack_ff_addba_param_set(pCtx, + pBufRemaining, (tDot11fFfaddba_param_set *) + (pFrm + pFf->offset)); + break; + case SigFfba_start_seq_ctrl: + dot11f_unpack_ff_ba_start_seq_ctrl(pCtx, + pBufRemaining, (tDot11fFfba_start_seq_ctrl *) + (pFrm + pFf->offset)); + break; + case SigFfba_timeout: + dot11f_unpack_ff_ba_timeout(pCtx, + pBufRemaining, (tDot11fFfba_timeout *) + (pFrm + pFf->offset)); + break; + case SigFfdelba_param_set: + dot11f_unpack_ff_delba_param_set(pCtx, + pBufRemaining, (tDot11fFfdelba_param_set *) + (pFrm + pFf->offset)); + break; + case SigFfext_chan_switch_ann_action: + dot11f_unpack_ff_ext_chan_switch_ann_action(pCtx, + pBufRemaining, (tDot11fFfext_chan_switch_ann_action *) + (pFrm + pFf->offset)); + break; + case SigFfp2p_action_oui: + dot11f_unpack_ff_p2p_action_oui(pCtx, + pBufRemaining, (tDot11fFfp2p_action_oui *) + (pFrm + pFf->offset)); + break; + case SigFfp2p_action_subtype: + dot11f_unpack_ff_p2p_action_subtype(pCtx, + pBufRemaining, (tDot11fFfp2p_action_subtype *) + (pFrm + pFf->offset)); + break; + case SigFfvendor_action_subtype: + dot11f_unpack_ff_vendor_action_subtype(pCtx, + pBufRemaining, (tDot11fFfvendor_action_subtype *) + (pFrm + pFf->offset)); + break; + case SigFfvendor_oui: + dot11f_unpack_ff_vendor_oui(pCtx, + pBufRemaining, (tDot11fFfvendor_oui *) + (pFrm + pFf->offset)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR: I don'" + "t know about the FF signature %d-- this is most " + "likely a 'framesc' bug.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += pFf->size; + nBufRemaining -= pFf->size; + ++pFf; + } + + while (nBufRemaining) { + if (1 == nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "only one byte remaining after it's fixed fields.\n")); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + pIe = find_ie_defn(pCtx, pBufRemaining, nBufRemaining, IEs); + + eid = *pBufRemaining++; --nBufRemaining; + len = *pBufRemaining++; --nBufRemaining; + if (pIe && pIe->extn_eid) { + extn_eid = *pBufRemaining++; --nBufRemaining; + len--; + } + + if (pIe && pIe->noui) { + if (pIe->noui > nBufRemaining) { + FRAMES_LOG4(pCtx, FRLOGW, FRFL("IE %d extn id %d reports " + "length %d, but it has an OUI of %d bytes.\n"), + eid, extn_eid, len, pIe->noui); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += pIe->noui; + nBufRemaining -= pIe->noui; + len -= pIe->noui; + } + + if (len > nBufRemaining) { + FRAMES_LOG4(pCtx, FRLOGW, FRFL("IE %d extn id %d reports length %" + "d, but there are only %d bytes remaining in this" + " frame.\n"), eid, extn_eid, len, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + if (pIe) { + if ((nBufRemaining < pIe->minSize - pIe->noui - 2U)) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must " + "be at least %d bytes in size, but " + "there are only %d bytes remaining in " + "this frame\n"), + pIe->name, pIe->minSize, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_IE; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } else { + if (len < pIe->minSize - pIe->noui - 2U) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must " + "be at least %d bytes in size, but " + "there are only %d bytes in the IE\n"), + pIe->name, pIe->minSize, (len + pIe->noui + 2U)); + goto skip_ie; + } + + if (len > pIe->maxSize - pIe->noui - 2U) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("The IE %s reports " + "an unexpectedly large size; it is presumably " + "more up-to-date than this parser, but this wa" + "rning may also indicate a corrupt frame.\n"), + pIe->name); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + } + + countOffset = ((0 != pIe->arraybound) * + (*(uint16_t *)(pFrm + pIe->countOffset))); + if (0 != pIe->arraybound && countOffset >= pIe->arraybound) { + status |= DOT11F_DUPLICATE_IE; + goto skip_ie; + } + switch (pIe->sig) { + case SigIeGTK: + status |= + dot11f_unpack_ie_gtk( + pCtx, pBufRemaining, len, + (tDot11fIEGTK *) + (pFrm + pIe->offset + + sizeof(tDot11fIEGTK) * + countOffset), + append_ie); + break; + case SigIeIGTK: + status |= + dot11f_unpack_ie_igtk( + pCtx, pBufRemaining, len, + (tDot11fIEIGTK *) + (pFrm + pIe->offset + + sizeof(tDot11fIEIGTK) * + countOffset), + append_ie); + break; + case SigIeR0KH_ID: + status |= + dot11f_unpack_ie_r0_kh_id( + pCtx, pBufRemaining, len, + (tDot11fIER0KH_ID *) + (pFrm + pIe->offset + + sizeof(tDot11fIER0KH_ID) * + countOffset), + append_ie); + break; + case SigIeR1KH_ID: + status |= + dot11f_unpack_ie_r1_kh_id( + pCtx, pBufRemaining, len, + (tDot11fIER1KH_ID *) + (pFrm + pIe->offset + + sizeof(tDot11fIER1KH_ID) * + countOffset), + append_ie); + break; + case SigIeAPChannelReport: + status |= + dot11f_unpack_ie_ap_channel_report( + pCtx, pBufRemaining, len, + (tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIEAPChannelReport) * + countOffset), + append_ie); + break; + case SigIeBcnReportingDetail: + status |= + dot11f_unpack_ie_bcn_reporting_detail( + pCtx, pBufRemaining, len, + (tDot11fIEBcnReportingDetail *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBcnReportingDetail) * + countOffset), + append_ie); + break; + case SigIeBeaconReportFrmBody: + status |= + dot11f_unpack_ie_beacon_report_frm_body( + pCtx, pBufRemaining, len, + (tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + + sizeof(tDot11fIEBeaconReportFrmBody) * + countOffset), + append_ie); + break; + case SigIeCondensedCountryStr: + status |= + dot11f_unpack_ie_condensed_country_str( + pCtx, pBufRemaining, len, + (tDot11fIECondensedCountryStr *) + (pFrm + pIe->offset + + sizeof(tDot11fIECondensedCountryStr) * + countOffset), + append_ie); + break; + case SigIeExtRequestedInfo: + status |= + dot11f_unpack_ie_ExtRequestedInfo( + pCtx, pBufRemaining, len, + (tDot11fIEExtRequestedInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtRequestedInfo) * + countOffset), + append_ie); + break; + case SigIeMeasurementPilot: + status |= + dot11f_unpack_ie_measurement_pilot( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementPilot) * + countOffset), + append_ie); + break; + case SigIeMultiBssid: + status |= + dot11f_unpack_ie_multi_bssid( + pCtx, pBufRemaining, len, + (tDot11fIEMultiBssid *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMultiBssid) * + countOffset), + append_ie); + break; + case SigIeRICData: + status |= + dot11f_unpack_ie_ric_data( + pCtx, pBufRemaining, len, + (tDot11fIERICData *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICData) * + countOffset), + append_ie); + break; + case SigIeRICDescriptor: + status |= + dot11f_unpack_ie_ric_descriptor( + pCtx, pBufRemaining, len, + (tDot11fIERICDescriptor *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICDescriptor) * + countOffset), + append_ie); + break; + case SigIeRRMEnabledCap: + status |= + dot11f_unpack_ie_rrm_enabled_cap( + pCtx, pBufRemaining, len, + (tDot11fIERRMEnabledCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIERRMEnabledCap) * + countOffset), + append_ie); + break; + case SigIeRequestedInfo: + status |= + dot11f_unpack_ie_requested_info( + pCtx, pBufRemaining, len, + (tDot11fIERequestedInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIERequestedInfo) * + countOffset), + append_ie); + break; + case SigIeSSID: + status |= + dot11f_unpack_ie_ssid( + pCtx, pBufRemaining, len, + (tDot11fIESSID *) + (pFrm + pIe->offset + + sizeof(tDot11fIESSID) * + countOffset), + append_ie); + break; + case SigIeSchedule: + status |= + dot11f_unpack_ie_schedule( + pCtx, pBufRemaining, len, + (tDot11fIESchedule *) + (pFrm + pIe->offset + + sizeof(tDot11fIESchedule) * + countOffset), + append_ie); + break; + case SigIeTCLAS: + status |= + dot11f_unpack_ie_tclas( + pCtx, pBufRemaining, len, + (tDot11fIETCLAS *) + (pFrm + pIe->offset + + sizeof(tDot11fIETCLAS) * + countOffset), + append_ie); + break; + case SigIeTCLASSPROC: + status |= dot11f_unpack_ie_common_func(pCtx, pBufRemaining, len, + (uint8_t *) &(((tDot11fIETCLASSPROC *)(pFrm + pIe->offset + sizeof(tDot11fIETCLASSPROC)*countOffset))->present), + (uint8_t *) &(((tDot11fIETCLASSPROC *)(pFrm + pIe->offset + sizeof(tDot11fIETCLASSPROC)*countOffset))->processing)); + break; + case SigIeTSDelay: + status |= + dot11f_unpack_ie_ts_delay( + pCtx, pBufRemaining, len, + (tDot11fIETSDelay *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSDelay) * + countOffset), + append_ie); + break; + case SigIeTSFInfo: + status |= + dot11f_unpack_ie_tsf_info( + pCtx, pBufRemaining, len, + (tDot11fIETSFInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSFInfo) * + countOffset), + append_ie); + break; + case SigIeTSPEC: + status |= + dot11f_unpack_ie_tspec( + pCtx, pBufRemaining, len, + (tDot11fIETSPEC *) + (pFrm + pIe->offset + + sizeof(tDot11fIETSPEC) * + countOffset), + append_ie); + break; + case SigIeVHTCaps: + status |= + dot11f_unpack_ie_vht_caps( + pCtx, pBufRemaining, len, + (tDot11fIEVHTCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTCaps) * + countOffset), + append_ie); + break; + case SigIeVHTOperation: + status |= + dot11f_unpack_ie_vht_operation( + pCtx, pBufRemaining, len, + (tDot11fIEVHTOperation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTOperation) * + countOffset), + append_ie); + break; + case SigIeWMMSchedule: + status |= + dot11f_unpack_ie_wmm_schedule( + pCtx, pBufRemaining, len, + (tDot11fIEWMMSchedule *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMSchedule) * + countOffset), + append_ie); + break; + case SigIeWMMTCLAS: + status |= + dot11f_unpack_ie_wmmtclas( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTCLAS *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTCLAS) * + countOffset), + append_ie); + break; + case SigIeWMMTCLASPROC: + status |= + dot11f_unpack_ie_wmmtclasproc( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTCLASPROC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTCLASPROC) * + countOffset), + append_ie); + break; + case SigIeWMMTSDelay: + status |= + dot11f_unpack_ie_wmmts_delay( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTSDelay *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTSDelay) * + countOffset), + append_ie); + break; + case SigIeWMMTSPEC: + status |= + dot11f_unpack_ie_wmmtspec( + pCtx, pBufRemaining, len, + (tDot11fIEWMMTSPEC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMTSPEC) * + countOffset), + append_ie); + break; + case SigIeWiderBWChanSwitchAnn: + status |= + dot11f_unpack_ie_wider_bw_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEWiderBWChanSwitchAnn *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWiderBWChanSwitchAnn) * + countOffset), + append_ie); + break; + case SigIeazimuth_req: + status |= + dot11f_unpack_ie_azimuth_req( + pCtx, pBufRemaining, len, + (tDot11fIEazimuth_req *) + (pFrm + pIe->offset + + sizeof(tDot11fIEazimuth_req) * + countOffset), + append_ie); + break; + case SigIebeacon_report_frm_body_fragment_id: + status |= + dot11f_unpack_ie_beacon_report_frm_body_fragment_id( + pCtx, pBufRemaining, len, + (tDot11fIEbeacon_report_frm_body_fragment_id *) + (pFrm + pIe->offset + + sizeof(tDot11fIEbeacon_report_frm_body_fragment_id) * + countOffset), + append_ie); + break; + case SigIebw_ind_element: + status |= + dot11f_unpack_ie_bw_ind_element( + pCtx, pBufRemaining, len, + (tDot11fIEbw_ind_element *) + (pFrm + pIe->offset + + sizeof(tDot11fIEbw_ind_element) * + countOffset), + append_ie); + break; + case SigIebw_indication: + status |= + dot11f_unpack_ie_bw_indication( + pCtx, pBufRemaining, len, + (tDot11fIEbw_indication *) + (pFrm + pIe->offset + + sizeof(tDot11fIEbw_indication) * + countOffset), + append_ie); + break; + case SigIelast_beacon_report_indication: + status |= + dot11f_unpack_ie_last_beacon_report_indication( + pCtx, pBufRemaining, len, + (tDot11fIElast_beacon_report_indication *) + (pFrm + pIe->offset + + sizeof(tDot11fIElast_beacon_report_indication) * + countOffset), + append_ie); + break; + case SigIemax_age: + status |= + dot11f_unpack_ie_max_age( + pCtx, pBufRemaining, len, + (tDot11fIEmax_age *) + (pFrm + pIe->offset + + sizeof(tDot11fIEmax_age) * + countOffset), + append_ie); + break; + case SigIemscs_status: + status |= + dot11f_unpack_ie_mscs_status( + pCtx, pBufRemaining, len, + (tDot11fIEmscs_status *) + (pFrm + pIe->offset + + sizeof(tDot11fIEmscs_status) * + countOffset), + append_ie); + break; + case SigIeneighbor_rpt: + status |= + dot11f_unpack_ie_neighbor_rpt( + pCtx, pBufRemaining, len, + (tDot11fIEneighbor_rpt *) + (pFrm + pIe->offset + + sizeof(tDot11fIEneighbor_rpt) * + countOffset), + append_ie); + break; + case SigIereporting_reason: + status |= + dot11f_unpack_ie_reporting_reason( + pCtx, pBufRemaining, len, + (tDot11fIEreporting_reason *) + (pFrm + pIe->offset + + sizeof(tDot11fIEreporting_reason) * + countOffset), + append_ie); + break; + case SigIereq_mac_addr: + status |= + dot11f_unpack_ie_req_mac_addr( + pCtx, pBufRemaining, len, + (tDot11fIEreq_mac_addr *) + (pFrm + pIe->offset + + sizeof(tDot11fIEreq_mac_addr) * + countOffset), + append_ie); + break; + case SigIerrm_reporting: + status |= + dot11f_unpack_ie_rrm_reporting( + pCtx, pBufRemaining, len, + (tDot11fIErrm_reporting *) + (pFrm + pIe->offset + + sizeof(tDot11fIErrm_reporting) * + countOffset), + append_ie); + break; + case SigIetclas_mask: + status |= + dot11f_unpack_ie_tclas_mask( + pCtx, pBufRemaining, len, + (tDot11fIEtclas_mask *) + (pFrm + pIe->offset + + sizeof(tDot11fIEtclas_mask) * + countOffset), + append_ie); + break; + case SigIetgt_mac_addr: + status |= + dot11f_unpack_ie_tgt_mac_addr( + pCtx, pBufRemaining, len, + (tDot11fIEtgt_mac_addr *) + (pFrm + pIe->offset + + sizeof(tDot11fIEtgt_mac_addr) * + countOffset), + append_ie); + break; + case SigIetransmit_power_env: + status |= + dot11f_unpack_ie_transmit_power_env( + pCtx, pBufRemaining, len, + (tDot11fIEtransmit_power_env *) + (pFrm + pIe->offset + + sizeof(tDot11fIEtransmit_power_env) * + countOffset), + append_ie); + break; + case SigIewide_bw_chan_switch: + status |= + dot11f_unpack_ie_wide_bw_chan_switch( + pCtx, pBufRemaining, len, + (tDot11fIEwide_bw_chan_switch *) + (pFrm + pIe->offset + + sizeof(tDot11fIEwide_bw_chan_switch) * + countOffset), + append_ie); + break; + case SigIeAID: + status |= + dot11f_unpack_ie_aid( + pCtx, pBufRemaining, len, + (tDot11fIEAID *) + (pFrm + pIe->offset + + sizeof(tDot11fIEAID) * + countOffset), + append_ie); + break; + case SigIeCFParams: + status |= + dot11f_unpack_ie_cf_params( + pCtx, pBufRemaining, len, + (tDot11fIECFParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIECFParams) * + countOffset), + append_ie); + break; + case SigIeChallengeText: + status |= + dot11f_unpack_ie_challenge_text( + pCtx, pBufRemaining, len, + (tDot11fIEChallengeText *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChallengeText) * + countOffset), + append_ie); + break; + case SigIeChanSwitchAnn: + status |= + dot11f_unpack_ie_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEChanSwitchAnn *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChanSwitchAnn) * + countOffset), + append_ie); + break; + case SigIeChannelSwitchWrapper: + status |= + dot11f_unpack_ie_channel_switch_wrapper( + pCtx, pBufRemaining, len, + (tDot11fIEChannelSwitchWrapper *) + (pFrm + pIe->offset + + sizeof(tDot11fIEChannelSwitchWrapper) * + countOffset), + append_ie); + break; + case SigIeCountry: + status |= + dot11f_unpack_ie_country( + pCtx, pBufRemaining, len, + (tDot11fIECountry *) + (pFrm + pIe->offset + + sizeof(tDot11fIECountry) * + countOffset), + append_ie); + break; + case SigIeDSParams: + status |= dot11f_unpack_ie_common_func(pCtx, pBufRemaining, len, + (uint8_t *) &(((tDot11fIEDSParams *)(pFrm + pIe->offset + sizeof(tDot11fIEDSParams)*countOffset))->present), + (uint8_t *) &(((tDot11fIEDSParams *)(pFrm + pIe->offset + sizeof(tDot11fIEDSParams)*countOffset))->curr_channel)); + break; + case SigIeEDCAParamSet: + status |= + dot11f_unpack_ie_edca_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEEDCAParamSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEEDCAParamSet) * + countOffset), + append_ie); + break; + case SigIeERPInfo: + status |= + dot11f_unpack_ie_erp_info( + pCtx, pBufRemaining, len, + (tDot11fIEERPInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEERPInfo) * + countOffset), + append_ie); + break; + case SigIeESECckmOpaque: + status |= + dot11f_unpack_ie_ese_cckm_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESECckmOpaque) * + countOffset), + append_ie); + break; + case SigIeESERadMgmtCap: + status |= + dot11f_unpack_ie_ese_rad_mgmt_cap( + pCtx, pBufRemaining, len, + (tDot11fIEESERadMgmtCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESERadMgmtCap) * + countOffset), + append_ie); + break; + case SigIeESETrafStrmMet: + status |= + dot11f_unpack_ie_ese_traf_strm_met( + pCtx, pBufRemaining, len, + (tDot11fIEESETrafStrmMet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETrafStrmMet) * + countOffset), + append_ie); + break; + case SigIeESETrafStrmRateSet: + status |= + dot11f_unpack_ie_ese_traf_strm_rate_set( + pCtx, pBufRemaining, len, + (tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETrafStrmRateSet) * + countOffset), + append_ie); + break; + case SigIeESETxmitPower: + status |= + dot11f_unpack_ie_ese_txmit_power( + pCtx, pBufRemaining, len, + (tDot11fIEESETxmitPower *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESETxmitPower) * + countOffset), + append_ie); + break; + case SigIeESEVersion: + status |= + dot11f_unpack_ie_ese_version( + pCtx, pBufRemaining, len, + (tDot11fIEESEVersion *) + (pFrm + pIe->offset + + sizeof(tDot11fIEESEVersion) * + countOffset), + append_ie); + break; + case SigIeExtCap: + status |= + dot11f_unpack_ie_ext_cap( + pCtx, pBufRemaining, len, + (tDot11fIEExtCap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtCap) * + countOffset), + append_ie); + break; + case SigIeExtSuppRates: + status |= + dot11f_unpack_ie_ext_supp_rates( + pCtx, pBufRemaining, len, + (tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + + sizeof(tDot11fIEExtSuppRates) * + countOffset), + append_ie); + break; + case SigIeFHParamSet: + status |= + dot11f_unpack_ie_fh_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEFHParamSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHParamSet) * + countOffset), + append_ie); + break; + case SigIeFHParams: + status |= + dot11f_unpack_ie_fh_params( + pCtx, pBufRemaining, len, + (tDot11fIEFHParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHParams) * + countOffset), + append_ie); + break; + case SigIeFHPattTable: + status |= + dot11f_unpack_ie_fh_patt_table( + pCtx, pBufRemaining, len, + (tDot11fIEFHPattTable *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFHPattTable) * + countOffset), + append_ie); + break; + case SigIeFTInfo: + status |= + dot11f_unpack_ie_ft_info( + pCtx, pBufRemaining, len, + (tDot11fIEFTInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEFTInfo) * + countOffset), + append_ie); + break; + case SigIeHTCaps: + status |= + dot11f_unpack_ie_ht_caps( + pCtx, pBufRemaining, len, + (tDot11fIEHTCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEHTCaps) * + countOffset), + append_ie); + break; + case SigIeHTInfo: + status |= + dot11f_unpack_ie_ht_info( + pCtx, pBufRemaining, len, + (tDot11fIEHTInfo *) + (pFrm + pIe->offset + + sizeof(tDot11fIEHTInfo) * + countOffset), + append_ie); + break; + case SigIeLinkIdentifier: + status |= + dot11f_unpack_ie_link_identifier( + pCtx, pBufRemaining, len, + (tDot11fIELinkIdentifier *) + (pFrm + pIe->offset + + sizeof(tDot11fIELinkIdentifier) * + countOffset), + append_ie); + break; + case SigIeMBO_IE: + status |= + dot11f_unpack_ie_MBO_IE( + pCtx, pBufRemaining, len, + (tDot11fIEMBO_IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMBO_IE) * + countOffset), + append_ie); + break; + case SigIeMeasurementReport: + status |= + dot11f_unpack_ie_measurement_report( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementReport) * + countOffset), + append_ie); + break; + case SigIeMeasurementRequest: + status |= + dot11f_unpack_ie_measurement_request( + pCtx, pBufRemaining, len, + (tDot11fIEMeasurementRequest *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMeasurementRequest) * + countOffset), + append_ie); + break; + case SigIeMobilityDomain: + status |= + dot11f_unpack_ie_mobility_domain( + pCtx, pBufRemaining, len, + (tDot11fIEMobilityDomain *) + (pFrm + pIe->offset + + sizeof(tDot11fIEMobilityDomain) * + countOffset), + append_ie); + break; + case SigIeNeighborReport: + status |= + dot11f_unpack_ie_neighbor_report( + pCtx, pBufRemaining, len, + (tDot11fIENeighborReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIENeighborReport) * + countOffset), + append_ie); + break; + case SigIeOBSSScanParameters: + status |= + dot11f_unpack_ie_obss_scan_parameters( + pCtx, pBufRemaining, len, + (tDot11fIEOBSSScanParameters *) + (pFrm + pIe->offset + + sizeof(tDot11fIEOBSSScanParameters) * + countOffset), + append_ie); + break; + case SigIeOperatingMode: + status |= + dot11f_unpack_ie_operating_mode( + pCtx, pBufRemaining, len, + (tDot11fIEOperatingMode *) + (pFrm + pIe->offset + + sizeof(tDot11fIEOperatingMode) * + countOffset), + append_ie); + break; + case SigIeP2PAssocReq: + status |= + dot11f_unpack_ie_p2_p_assoc_req( + pCtx, pBufRemaining, len, + (tDot11fIEP2PAssocReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PAssocReq) * + countOffset), + append_ie); + break; + case SigIeP2PAssocRes: + status |= + dot11f_unpack_ie_p2_p_assoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PAssocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PAssocRes) * + countOffset), + append_ie); + break; + case SigIeP2PBeacon: + status |= + dot11f_unpack_ie_p2_p_beacon( + pCtx, pBufRemaining, len, + (tDot11fIEP2PBeacon *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PBeacon) * + countOffset), + append_ie); + break; + case SigIeP2PBeaconProbeRes: + status |= + dot11f_unpack_ie_p2_p_beacon_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PBeaconProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PBeaconProbeRes) * + countOffset), + append_ie); + break; + case SigIeP2PDeAuth: + status |= + dot11f_unpack_ie_p2_p_de_auth( + pCtx, pBufRemaining, len, + (tDot11fIEP2PDeAuth *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PDeAuth) * + countOffset), + append_ie); + break; + case SigIeP2PDisAssoc: + status |= + dot11f_unpack_ie_p2_p_dis_assoc( + pCtx, pBufRemaining, len, + (tDot11fIEP2PDisAssoc *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PDisAssoc) * + countOffset), + append_ie); + break; + case SigIeP2PIEOpaque: + status |= + dot11f_unpack_ie_p2_pie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PIEOpaque) * + countOffset), + append_ie); + break; + case SigIeP2PProbeReq: + status |= + dot11f_unpack_ie_p2_p_probe_req( + pCtx, pBufRemaining, len, + (tDot11fIEP2PProbeReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PProbeReq) * + countOffset), + append_ie); + break; + case SigIeP2PProbeRes: + status |= + dot11f_unpack_ie_p2_p_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEP2PProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEP2PProbeRes) * + countOffset), + append_ie); + break; + case SigIePTIControl: + status |= + dot11f_unpack_ie_pti_control( + pCtx, pBufRemaining, len, + (tDot11fIEPTIControl *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPTIControl) * + countOffset), + append_ie); + break; + case SigIePUBufferStatus: + status |= + dot11f_unpack_ie_pu_buffer_status( + pCtx, pBufRemaining, len, + (tDot11fIEPUBufferStatus *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPUBufferStatus) * + countOffset), + append_ie); + break; + case SigIePowerCaps: + status |= + dot11f_unpack_ie_power_caps( + pCtx, pBufRemaining, len, + (tDot11fIEPowerCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPowerCaps) * + countOffset), + append_ie); + break; + case SigIePowerConstraints: + status |= + dot11f_unpack_ie_power_constraints( + pCtx, pBufRemaining, len, + (tDot11fIEPowerConstraints *) + (pFrm + pIe->offset + + sizeof(tDot11fIEPowerConstraints) * + countOffset), + append_ie); + break; + case SigIeQBSSLoad: + status |= + dot11f_unpack_ie_qbss_load( + pCtx, pBufRemaining, len, + (tDot11fIEQBSSLoad *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQBSSLoad) * + countOffset), + append_ie); + break; + case SigIeQComVendorIE: + status |= + dot11f_unpack_ie_QComVendorIE( + pCtx, pBufRemaining, len, + (tDot11fIEQComVendorIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQComVendorIE) * + countOffset), + append_ie); + break; + case SigIeQOSCapsAp: + status |= + dot11f_unpack_ie_qos_caps_ap( + pCtx, pBufRemaining, len, + (tDot11fIEQOSCapsAp *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQOSCapsAp) * + countOffset), + append_ie); + break; + case SigIeQOSCapsStation: + status |= + dot11f_unpack_ie_qos_caps_station( + pCtx, pBufRemaining, len, + (tDot11fIEQOSCapsStation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQOSCapsStation) * + countOffset), + append_ie); + break; + case SigIeQosMapSet: + status |= + dot11f_unpack_ie_qos_map_set( + pCtx, pBufRemaining, len, + (tDot11fIEQosMapSet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQosMapSet) * + countOffset), + append_ie); + break; + case SigIeQuiet: + status |= + dot11f_unpack_ie_quiet( + pCtx, pBufRemaining, len, + (tDot11fIEQuiet *) + (pFrm + pIe->offset + + sizeof(tDot11fIEQuiet) * + countOffset), + append_ie); + break; + case SigIeRCPIIE: + status |= + dot11f_unpack_ie_rcpiie( + pCtx, pBufRemaining, len, + (tDot11fIERCPIIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIERCPIIE) * + countOffset), + append_ie); + break; + case SigIeRICDataDesc: + /* reset the pointers back since this is a container IE and it doesn't have its own EID and Len. */ + pBufRemaining -= 2; + nBufRemaining += 2; + if (pIe && pIe->noui) { + pBufRemaining -= pIe->noui; + nBufRemaining += pIe->noui; + len += pIe->noui; + } + status |= get_container_ies_len(pCtx, pBufRemaining, nBufRemaining, &len, IES_RICDataDesc); + if (status != DOT11F_PARSE_SUCCESS && status != DOT11F_UNKNOWN_IES) + break; + status |= + dot11f_unpack_ie_ric_data_desc( + pCtx, pBufRemaining, len, + (tDot11fIERICDataDesc *) + (pFrm + pIe->offset + + sizeof(tDot11fIERICDataDesc) * + countOffset), + append_ie); + break; + case SigIeRSN: + status |= + dot11f_unpack_ie_rsn( + pCtx, pBufRemaining, len, + (tDot11fIERSN *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSN) * + countOffset), + append_ie); + break; + case SigIeRSNIIE: + status |= + dot11f_unpack_ie_rsniie( + pCtx, pBufRemaining, len, + (tDot11fIERSNIIE *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSNIIE) * + countOffset), + append_ie); + break; + case SigIeRSNOpaque: + status |= + dot11f_unpack_ie_rsn_opaque( + pCtx, pBufRemaining, len, + (tDot11fIERSNOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIERSNOpaque) * + countOffset), + append_ie); + break; + case SigIeSuppChannels: + status |= + dot11f_unpack_ie_supp_channels( + pCtx, pBufRemaining, len, + (tDot11fIESuppChannels *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppChannels) * + countOffset), + append_ie); + break; + case SigIeSuppOperatingClasses: + status |= + dot11f_unpack_ie_supp_operating_classes( + pCtx, pBufRemaining, len, + (tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppOperatingClasses) * + countOffset), + append_ie); + break; + case SigIeSuppRates: + status |= + dot11f_unpack_ie_supp_rates( + pCtx, pBufRemaining, len, + (tDot11fIESuppRates *) + (pFrm + pIe->offset + + sizeof(tDot11fIESuppRates) * + countOffset), + append_ie); + break; + case SigIeTIM: + status |= + dot11f_unpack_ie_tim( + pCtx, pBufRemaining, len, + (tDot11fIETIM *) + (pFrm + pIe->offset + + sizeof(tDot11fIETIM) * + countOffset), + append_ie); + break; + case SigIeTPCReport: + status |= + dot11f_unpack_ie_tpc_report( + pCtx, pBufRemaining, len, + (tDot11fIETPCReport *) + (pFrm + pIe->offset + + sizeof(tDot11fIETPCReport) * + countOffset), + append_ie); + break; + case SigIeTPCRequest: + status |= + dot11f_unpack_ie_tpc_request( + pCtx, pBufRemaining, len, + (tDot11fIETPCRequest *) + (pFrm + pIe->offset + + sizeof(tDot11fIETPCRequest) * + countOffset), + append_ie); + break; + case SigIeTimeAdvertisement: + status |= + dot11f_unpack_ie_time_advertisement( + pCtx, pBufRemaining, len, + (tDot11fIETimeAdvertisement *) + (pFrm + pIe->offset + + sizeof(tDot11fIETimeAdvertisement) * + countOffset), + append_ie); + break; + case SigIeTimeoutInterval: + status |= + dot11f_unpack_ie_timeout_interval( + pCtx, pBufRemaining, len, + (tDot11fIETimeoutInterval *) + (pFrm + pIe->offset + + sizeof(tDot11fIETimeoutInterval) * + countOffset), + append_ie); + break; + case SigIeVHTExtBssLoad: + status |= + dot11f_unpack_ie_vht_ext_bss_load( + pCtx, pBufRemaining, len, + (tDot11fIEVHTExtBssLoad *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVHTExtBssLoad) * + countOffset), + append_ie); + break; + case SigIeVendor1IE: + status |= + dot11f_unpack_ie_vendor1_ie( + pCtx, pBufRemaining, len, + (tDot11fIEVendor1IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVendor1IE) * + countOffset), + append_ie); + break; + case SigIeVendor3IE: + status |= + dot11f_unpack_ie_vendor3_ie( + pCtx, pBufRemaining, len, + (tDot11fIEVendor3IE *) + (pFrm + pIe->offset + + sizeof(tDot11fIEVendor3IE) * + countOffset), + append_ie); + break; + case SigIeWAPI: + status |= + dot11f_unpack_ie_wapi( + pCtx, pBufRemaining, len, + (tDot11fIEWAPI *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWAPI) * + countOffset), + append_ie); + break; + case SigIeWAPIOpaque: + status |= + dot11f_unpack_ie_wapi_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWAPIOpaque) * + countOffset), + append_ie); + break; + case SigIeWFATPC: + status |= + dot11f_unpack_ie_wfatpc( + pCtx, pBufRemaining, len, + (tDot11fIEWFATPC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWFATPC) * + countOffset), + append_ie); + break; + case SigIeWFDIEOpaque: + status |= + dot11f_unpack_ie_wfdie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWFDIEOpaque) * + countOffset), + append_ie); + break; + case SigIeWMMCaps: + status |= + dot11f_unpack_ie_wmm_caps( + pCtx, pBufRemaining, len, + (tDot11fIEWMMCaps *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMCaps) * + countOffset), + append_ie); + break; + case SigIeWMMInfoAp: + status |= + dot11f_unpack_ie_wmm_info_ap( + pCtx, pBufRemaining, len, + (tDot11fIEWMMInfoAp *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMInfoAp) * + countOffset), + append_ie); + break; + case SigIeWMMInfoStation: + status |= + dot11f_unpack_ie_wmm_info_station( + pCtx, pBufRemaining, len, + (tDot11fIEWMMInfoStation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMInfoStation) * + countOffset), + append_ie); + break; + case SigIeWMMParams: + status |= + dot11f_unpack_ie_wmm_params( + pCtx, pBufRemaining, len, + (tDot11fIEWMMParams *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWMMParams) * + countOffset), + append_ie); + break; + case SigIeWPA: + status |= + dot11f_unpack_ie_wpa( + pCtx, pBufRemaining, len, + (tDot11fIEWPA *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWPA) * + countOffset), + append_ie); + break; + case SigIeWPAOpaque: + status |= + dot11f_unpack_ie_wpa_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWPAOpaque) * + countOffset), + append_ie); + break; + case SigIeWSC: + status |= + dot11f_unpack_ie_wsc( + pCtx, pBufRemaining, len, + (tDot11fIEWSC *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWSC) * + countOffset), + append_ie); + break; + case SigIeWscAssocReq: + status |= + dot11f_unpack_ie_wsc_assoc_req( + pCtx, pBufRemaining, len, + (tDot11fIEWscAssocReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscAssocReq) * + countOffset), + append_ie); + break; + case SigIeWscAssocRes: + status |= + dot11f_unpack_ie_wsc_assoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscAssocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscAssocRes) * + countOffset), + append_ie); + break; + case SigIeWscBeacon: + status |= + dot11f_unpack_ie_wsc_beacon( + pCtx, pBufRemaining, len, + (tDot11fIEWscBeacon *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscBeacon) * + countOffset), + append_ie); + break; + case SigIeWscBeaconProbeRes: + status |= + dot11f_unpack_ie_wsc_beacon_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscBeaconProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscBeaconProbeRes) * + countOffset), + append_ie); + break; + case SigIeWscIEOpaque: + status |= + dot11f_unpack_ie_wsc_ie_opaque( + pCtx, pBufRemaining, len, + (tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscIEOpaque) * + countOffset), + append_ie); + break; + case SigIeWscProbeReq: + status |= + dot11f_unpack_ie_wsc_probe_req( + pCtx, pBufRemaining, len, + (tDot11fIEWscProbeReq *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscProbeReq) * + countOffset), + append_ie); + break; + case SigIeWscProbeRes: + status |= + dot11f_unpack_ie_wsc_probe_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscProbeRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscProbeRes) * + countOffset), + append_ie); + break; + case SigIeWscReassocRes: + status |= + dot11f_unpack_ie_wsc_reassoc_res( + pCtx, pBufRemaining, len, + (tDot11fIEWscReassocRes *) + (pFrm + pIe->offset + + sizeof(tDot11fIEWscReassocRes) * + countOffset), + append_ie); + break; + case SigIeaddba_extn_element: + status |= + dot11f_unpack_ie_addba_extn_element( + pCtx, pBufRemaining, len, + (tDot11fIEaddba_extn_element *) + (pFrm + pIe->offset + + sizeof(tDot11fIEaddba_extn_element) * + countOffset), + append_ie); + break; + case SigIebss_color_change: + status |= + dot11f_unpack_ie_bss_color_change( + pCtx, pBufRemaining, len, + (tDot11fIEbss_color_change *) + (pFrm + pIe->offset + + sizeof(tDot11fIEbss_color_change) * + countOffset), + append_ie); + break; + case SigIebss_max_idle_period: + status |= + dot11f_unpack_ie_bss_max_idle_period( + pCtx, pBufRemaining, len, + (tDot11fIEbss_max_idle_period *) + (pFrm + pIe->offset + + sizeof(tDot11fIEbss_max_idle_period) * + countOffset), + append_ie); + break; + case SigIedescriptor_element: + status |= + dot11f_unpack_ie_descriptor_element( + pCtx, pBufRemaining, len, + (tDot11fIEdescriptor_element *) + (pFrm + pIe->offset + + sizeof(tDot11fIEdescriptor_element) * + countOffset), + append_ie); + break; + case SigIedh_parameter_element: + status |= + dot11f_unpack_ie_dh_parameter_element( + pCtx, pBufRemaining, len, + (tDot11fIEdh_parameter_element *) + (pFrm + pIe->offset + + sizeof(tDot11fIEdh_parameter_element) * + countOffset), + append_ie); + break; + case SigIeeht_cap: + status |= + dot11f_unpack_ie_eht_cap( + pCtx, pBufRemaining, len, + (tDot11fIEeht_cap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEeht_cap) * + countOffset), + append_ie); + break; + case SigIeeht_op: + status |= + dot11f_unpack_ie_eht_op( + pCtx, pBufRemaining, len, + (tDot11fIEeht_op *) + (pFrm + pIe->offset + + sizeof(tDot11fIEeht_op) * + countOffset), + append_ie); + break; + case SigIeesp_information: + status |= + dot11f_unpack_ie_esp_information( + pCtx, pBufRemaining, len, + (tDot11fIEesp_information *) + (pFrm + pIe->offset + + sizeof(tDot11fIEesp_information) * + countOffset), + append_ie); + break; + case SigIeext_chan_switch_ann: + status |= + dot11f_unpack_ie_ext_chan_switch_ann( + pCtx, pBufRemaining, len, + (tDot11fIEext_chan_switch_ann *) + (pFrm + pIe->offset + + sizeof(tDot11fIEext_chan_switch_ann) * + countOffset), + append_ie); + break; + case SigIefils_assoc_delay_info: + status |= + dot11f_unpack_ie_fils_assoc_delay_info( + pCtx, pBufRemaining, len, + (tDot11fIEfils_assoc_delay_info *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_assoc_delay_info) * + countOffset), + append_ie); + break; + case SigIefils_hlp_container: + status |= + dot11f_unpack_ie_fils_hlp_container( + pCtx, pBufRemaining, len, + (tDot11fIEfils_hlp_container *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_hlp_container) * + countOffset), + append_ie); + break; + case SigIefils_indication: + status |= + dot11f_unpack_ie_fils_indication( + pCtx, pBufRemaining, len, + (tDot11fIEfils_indication *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_indication) * + countOffset), + append_ie); + break; + case SigIefils_kde: + status |= + dot11f_unpack_ie_fils_kde( + pCtx, pBufRemaining, len, + (tDot11fIEfils_kde *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_kde) * + countOffset), + append_ie); + break; + case SigIefils_key_confirmation: + status |= + dot11f_unpack_ie_fils_key_confirmation( + pCtx, pBufRemaining, len, + (tDot11fIEfils_key_confirmation *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_key_confirmation) * + countOffset), + append_ie); + break; + case SigIefils_nonce: + status |= + dot11f_unpack_ie_fils_nonce( + pCtx, pBufRemaining, len, + (tDot11fIEfils_nonce *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_nonce) * + countOffset), + append_ie); + break; + case SigIefils_public_key: + status |= + dot11f_unpack_ie_fils_public_key( + pCtx, pBufRemaining, len, + (tDot11fIEfils_public_key *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_public_key) * + countOffset), + append_ie); + break; + case SigIefils_session: + status |= + dot11f_unpack_ie_fils_session( + pCtx, pBufRemaining, len, + (tDot11fIEfils_session *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_session) * + countOffset), + append_ie); + break; + case SigIefils_wrapped_data: + status |= + dot11f_unpack_ie_fils_wrapped_data( + pCtx, pBufRemaining, len, + (tDot11fIEfils_wrapped_data *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfils_wrapped_data) * + countOffset), + append_ie); + break; + case SigIefragment_ie: + status |= + dot11f_unpack_ie_fragment_ie( + pCtx, pBufRemaining, len, + (tDot11fIEfragment_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEfragment_ie) * + countOffset), + append_ie); + break; + case SigIehe_6ghz_band_cap: + status |= + dot11f_unpack_ie_he_6ghz_band_cap( + pCtx, pBufRemaining, len, + (tDot11fIEhe_6ghz_band_cap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEhe_6ghz_band_cap) * + countOffset), + append_ie); + break; + case SigIehe_cap: + status |= + dot11f_unpack_ie_he_cap( + pCtx, pBufRemaining, len, + (tDot11fIEhe_cap *) + (pFrm + pIe->offset + + sizeof(tDot11fIEhe_cap) * + countOffset), + append_ie); + break; + case SigIehe_op: + status |= + dot11f_unpack_ie_he_op( + pCtx, pBufRemaining, len, + (tDot11fIEhe_op *) + (pFrm + pIe->offset + + sizeof(tDot11fIEhe_op) * + countOffset), + append_ie); + break; + case SigIehs20vendor_ie: + status |= + dot11f_unpack_ie_hs20vendor_ie( + pCtx, pBufRemaining, len, + (tDot11fIEhs20vendor_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEhs20vendor_ie) * + countOffset), + append_ie); + break; + case SigIeht2040_bss_coexistence: + status |= + dot11f_unpack_ie_ht2040_bss_coexistence( + pCtx, pBufRemaining, len, + (tDot11fIEht2040_bss_coexistence *) + (pFrm + pIe->offset + + sizeof(tDot11fIEht2040_bss_coexistence) * + countOffset), + append_ie); + break; + case SigIeht2040_bss_intolerant_report: + status |= + dot11f_unpack_ie_ht2040_bss_intolerant_report( + pCtx, pBufRemaining, len, + (tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + + sizeof(tDot11fIEht2040_bss_intolerant_report) * + countOffset), + append_ie); + break; + case SigIemax_chan_switch_time: + status |= + dot11f_unpack_ie_max_chan_switch_time( + pCtx, pBufRemaining, len, + (tDot11fIEmax_chan_switch_time *) + (pFrm + pIe->offset + + sizeof(tDot11fIEmax_chan_switch_time) * + countOffset), + append_ie); + break; + case SigIemlo_ie: + status |= + dot11f_unpack_ie_mlo_ie( + pCtx, pBufRemaining, len, + (tDot11fIEmlo_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEmlo_ie) * + countOffset), + append_ie); + break; + case SigIemu_edca_param_set: + status |= + dot11f_unpack_ie_mu_edca_param_set( + pCtx, pBufRemaining, len, + (tDot11fIEmu_edca_param_set *) + (pFrm + pIe->offset + + sizeof(tDot11fIEmu_edca_param_set) * + countOffset), + append_ie); + break; + case SigIenon_inheritance: + status |= + dot11f_unpack_ie_non_inheritance( + pCtx, pBufRemaining, len, + (tDot11fIEnon_inheritance *) + (pFrm + pIe->offset + + sizeof(tDot11fIEnon_inheritance) * + countOffset), + append_ie); + break; + case SigIeoci: + status |= + dot11f_unpack_ie_oci( + pCtx, pBufRemaining, len, + (tDot11fIEoci *) + (pFrm + pIe->offset + + sizeof(tDot11fIEoci) * + countOffset), + append_ie); + break; + case SigIeosen_ie: + status |= + dot11f_unpack_ie_osen_ie( + pCtx, pBufRemaining, len, + (tDot11fIEosen_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEosen_ie) * + countOffset), + append_ie); + break; + case SigIeqcn_ie: + status |= + dot11f_unpack_ie_qcn_ie( + pCtx, pBufRemaining, len, + (tDot11fIEqcn_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEqcn_ie) * + countOffset), + append_ie); + break; + case SigIereduced_neighbor_report: + status |= + dot11f_unpack_ie_reduced_neighbor_report( + pCtx, pBufRemaining, len, + (tDot11fIEreduced_neighbor_report *) + (pFrm + pIe->offset + + sizeof(tDot11fIEreduced_neighbor_report) * + countOffset), + append_ie); + break; + case SigIeroaming_consortium_sel: + status |= + dot11f_unpack_ie_roaming_consortium_sel( + pCtx, pBufRemaining, len, + (tDot11fIEroaming_consortium_sel *) + (pFrm + pIe->offset + + sizeof(tDot11fIEroaming_consortium_sel) * + countOffset), + append_ie); + break; + case SigIesec_chan_offset_ele: + status |= + dot11f_unpack_ie_sec_chan_offset_ele( + pCtx, pBufRemaining, len, + (tDot11fIEsec_chan_offset_ele *) + (pFrm + pIe->offset + + sizeof(tDot11fIEsec_chan_offset_ele) * + countOffset), + append_ie); + break; + case SigIespatial_reuse: + status |= + dot11f_unpack_ie_spatial_reuse( + pCtx, pBufRemaining, len, + (tDot11fIEspatial_reuse *) + (pFrm + pIe->offset + + sizeof(tDot11fIEspatial_reuse) * + countOffset), + append_ie); + break; + case SigIet2lm_ie: + status |= + dot11f_unpack_ie_t2lm_ie( + pCtx, pBufRemaining, len, + (tDot11fIEt2lm_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEt2lm_ie) * + countOffset), + append_ie); + break; + case SigIevendor_vht_ie: + status |= + dot11f_unpack_ie_vendor_vht_ie( + pCtx, pBufRemaining, len, + (tDot11fIEvendor_vht_ie *) + (pFrm + pIe->offset + + sizeof(tDot11fIEvendor_vht_ie) * + countOffset), + append_ie); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR" + ": I don't know about the IE signature %d" + "-- this is most likely a 'framesc' bug.\n"), + pIe->sig); + FRAMES_DBG_BREAK(); + return DOT11F_INTERNAL_ERROR; + } + if (pIe->arraybound) + (++(*(uint16_t *)(pFrm + pIe->countOffset))); + } + } else { + FRAMES_LOG3(pCtx, FRLOG3, FRFL("Skipping unknown IE %d extn ID %d" + " (length %d)\n"), eid, extn_eid, len); + FRAMES_DUMP(pCtx, FRLOG3, pBufRemaining - 2, len); + status |= DOT11F_UNKNOWN_IES; + } + +skip_ie: + pBufRemaining += len; + + if (len > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGW, FRFL("This IE extends past " + "the buffer as it was defined to us. This could" + "mean a corrupt frame, or just an incorrect leng" + "th parameter.\n")); + FRAMES_DBG_BREAK(); + status |= DOT11F_LAST_IE_TOO_LONG; + goto MandatoryCheck; + } + + nBufRemaining -= len; + + } + +MandatoryCheck: + pIe = &IEs[0]; + while (0xff != pIe->eid || pIe->extn_eid) { + if (pIe->fMandatory) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + if (!*pfFound) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("ERROR: The mandato" + "ry IE %s wasn't seen.\n"), + pIe->name); + FRAMES_DBG_BREAK(); + status |= DOT11F_MANDATORY_IE_MISSING; + } + } + ++pIe; + } + + return status; +} /* End unpack_core. */ + +static uint32_t unpack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pBuf, + uint32_t nBuf, + const tTLVDefn TLVs[], + uint8_t *pFrm, + size_t nFrm) +{ + const tTLVDefn *pTlv; + uint32_t nBufRemaining, status, npec; + uint16_t id, len; + uint8_t *pBufRemaining, *pfFound; + + (void)pCtx; /* Shutup the compiler */ + (void)nFrm; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + /* While we have data... */ + while (nBufRemaining) { + if (3 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer three byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + npec = 0U; + + /* Look for a matching TLV definition, */ + pTlv = find_tlv_defn(pCtx, pBufRemaining, nBufRemaining, TLVs); + /* consume the type, */ + if (pTlv) { + if (pTlv->sType == 2) { + framesntohs(pCtx, &id, pBufRemaining, pTlv->fMsb); + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + id = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + /* & length, */ + if (pTlv->sLen == 2) { + if (2 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer two byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + framesntohs(pCtx, &len, pBufRemaining, pTlv->fMsb); + pBufRemaining += 2; + nBufRemaining -= 2; + } else { + len = *pBufRemaining; + pBufRemaining += 1; + nBufRemaining -= 1; + } + } else { + if (TLVs[0].sType > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer LVs[0].sType byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + goto MandatoryCheck; + } + pBufRemaining += TLVs[0].sType; + nBufRemaining -= TLVs[0].sType; + if (2 > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGE, FRFL("This frame reports " + "fewer two byte(s) remaining.\n")); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + framesntohs(pCtx, &len, pBufRemaining, (TLVs[0].sType == 2)); + pBufRemaining += 2; + nBufRemaining -= 2; + } + + if (pTlv && pTlv->pec) { + npec = 3U; + if (3 > nBufRemaining) { + FRAMES_LOG2(pCtx, FRLOGW, FRFL("TLV %d reports length" + "%d, but it has a Private Enterprise Code (3 byte" + "s.\n"), id, len); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d bytes" + "of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + pBufRemaining += 3; + nBufRemaining -= 3; + len -= 3; + } + + /* Whether we found a hit or not, we can validate the reported */ + /* length of this TLV: */ + if (len > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("TLV %d reports length %" + "d, but there are only %d bytes remaining in this f" + "rame.\n"), id, len, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d bytes" + " of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + + /* Now, *if* we found a hit... */ + if (pTlv) { + if (len + (pTlv->sType + pTlv->sLen) < pTlv->minSize - npec) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but the size is only " + "%d bytes.\n"), + pTlv->name, pTlv->minSize, len); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } + if (nBufRemaining < pTlv->minSize - npec - (pTlv->sType + pTlv->sLen)) { + FRAMES_LOG3(pCtx, FRLOGW, FRFL("The IE %s must be " + "at least %d bytes in size, but there are only " + "%d bytes remaining in this frame.\n"), + pTlv->name, pTlv->minSize, nBufRemaining); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + status |= DOT11F_INCOMPLETE_TLV; + FRAMES_DBG_BREAK(); + goto MandatoryCheck; + } else if (len > pTlv->maxSize - npec - (pTlv->sType + pTlv->sLen)) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("The TLV %s reports " + "an illegally large size; this TLV is presumably" + "corrupt or otherwise invalid & will be skipped " + "ipped.\n"), pTlv->name); + FRAMES_DUMP(pCtx, FRLOG1, pBuf, nBuf); + FRAMES_LOG2(pCtx, FRLOG1, FRFL("We've parsed %d by" + "tes of this buffer, and show %d left.\n"), + pBufRemaining - pBuf, nBufRemaining); + FRAMES_DBG_BREAK(); + status |= DOT11F_SKIPPED_BAD_TLV; + } else { + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + status |= + dot11f_unpack_tlv_authorized_ma_cs(pCtx, + pBufRemaining, len, + (tDot11fTLVAuthorizedMACs *) + (pFrm + pTlv->offset)); + break; + case SigTlvRequestToEnroll: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->req)); + break; + case SigTlvVersion2: + status |= + dot11f_unpack_tlv_version2(pCtx, + pBufRemaining, len, + (tDot11fTLVVersion2 *) + (pFrm + pTlv->offset)); + break; + case SigTlvAPSetupLocked: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->fLocked)); + break; + case SigTlvAssociationState: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->state)); + break; + case SigTlvConfigMethods: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->methods)); + break; + case SigTlvConfigurationError: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->error)); + break; + case SigTlvDeviceName: + status |= + dot11f_unpack_tlv_device_name(pCtx, + pBufRemaining, len, + (tDot11fTLVDeviceName *) + (pFrm + pTlv->offset)); + break; + case SigTlvDevicePasswordID: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->id)); + break; + case SigTlvExtendedListenTiming: + status |= + dot11f_unpack_tlv_extended_listen_timing(pCtx, + pBufRemaining, len, + (tDot11fTLVExtendedListenTiming *) + (pFrm + pTlv->offset)); + break; + case SigTlvListenChannel: + status |= + dot11f_unpack_tlv_listen_channel(pCtx, + pBufRemaining, len, + (tDot11fTLVListenChannel *) + (pFrm + pTlv->offset)); + break; + case SigTlvManufacturer: + status |= + dot11f_unpack_tlv_manufacturer(pCtx, + pBufRemaining, len, + (tDot11fTLVManufacturer *) + (pFrm + pTlv->offset)); + break; + case SigTlvMinorReasonCode: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->minorReasonCode)); + break; + case SigTlvModelName: + status |= + dot11f_unpack_tlv_model_name(pCtx, + pBufRemaining, len, + (tDot11fTLVModelName *) + (pFrm + pTlv->offset)); + break; + case SigTlvModelNumber: + status |= + dot11f_unpack_tlv_model_number(pCtx, + pBufRemaining, len, + (tDot11fTLVModelNumber *) + (pFrm + pTlv->offset)); + break; + case SigTlvNoticeOfAbsence: + status |= + dot11f_unpack_tlv_notice_of_absence(pCtx, + pBufRemaining, len, + (tDot11fTLVNoticeOfAbsence *) + (pFrm + pTlv->offset)); + break; + case SigTlvOperatingChannel: + status |= + dot11f_unpack_tlv_operating_channel(pCtx, + pBufRemaining, len, + (tDot11fTLVOperatingChannel *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PCapability: + status |= + dot11f_unpack_tlv_p2_p_capability(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PCapability *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PDeviceId: + status |= + dot11f_unpack_tlv_p2_p_device_id(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PDeviceId *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PDeviceInfo: + status |= + dot11f_unpack_tlv_p2_p_device_info(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PDeviceInfo *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PGroupInfo: + status |= + dot11f_unpack_tlv_p2_p_group_info(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PGroupInfo *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PStatus: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->status)); + break; + case SigTlvPrimaryDeviceType: + status |= + dot11f_unpack_tlv_primary_device_type(pCtx, + pBufRemaining, len, + (tDot11fTLVPrimaryDeviceType *) + (pFrm + pTlv->offset)); + break; + case SigTlvRFBands: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->bands)); + break; + case SigTlvRequestDeviceType: + status |= + dot11f_unpack_tlv_request_device_type(pCtx, + pBufRemaining, len, + (tDot11fTLVRequestDeviceType *) + (pFrm + pTlv->offset)); + break; + case SigTlvRequestType: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->reqType)); + break; + case SigTlvResponseType: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->resType)); + break; + case SigTlvSelectedRegistrar: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->selected)); + break; + case SigTlvSelectedRegistrarConfigMethods: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->methods)); + break; + case SigTlvSerialNumber: + status |= + dot11f_unpack_tlv_serial_number(pCtx, + pBufRemaining, len, + (tDot11fTLVSerialNumber *) + (pFrm + pTlv->offset)); + break; + case SigTlvUUID_E: + status |= + dot11f_unpack_tlv_uuid_e(pCtx, + pBufRemaining, len, + (tDot11fTLVUUID_E *) + (pFrm + pTlv->offset)); + break; + case SigTlvUUID_R: + status |= + dot11f_unpack_tlv_uuid_r(pCtx, + pBufRemaining, len, + (tDot11fTLVUUID_R *) + (pFrm + pTlv->offset)); + break; + case SigTlvVendorExtension: + status |= + dot11f_unpack_tlv_vendor_extension(pCtx, + pBufRemaining, len, + (tDot11fTLVVendorExtension *) + (pFrm + pTlv->offset)); + break; + case SigTlvVersion: + status |= + dot11f_unpack_tlv_version(pCtx, + pBufRemaining, len, + (tDot11fTLVVersion *) + (pFrm + pTlv->offset)); + break; + case SigTlvWPSState: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->state)); + break; + case SigTlvassoc_disallowed: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVassoc_disallowed *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVassoc_disallowed *) + (pFrm + pTlv->offset))->reason_code)); + break; + case SigTlvassoc_retry_delay: + status |= + dot11f_unpack_tlv_common_func2(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVassoc_retry_delay *) + (pFrm + pTlv->offset))->present), + (uint16_t *)&(((tDot11fTLVassoc_retry_delay *) + (pFrm + pTlv->offset))->delay)); + break; + case SigTlvcellular_data_cap: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVcellular_data_cap *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVcellular_data_cap *) + (pFrm + pTlv->offset))->cellular_connectivity)); + break; + case SigTlvcellular_data_con_pref: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVcellular_data_con_pref *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVcellular_data_con_pref *) + (pFrm + pTlv->offset))->cellular_preference)); + break; + case SigTlvecsa_target_tsf_info_attr: + status |= + dot11f_unpack_tlv_ecsa_target_tsf_info_attr(pCtx, + pBufRemaining, len, + (tDot11fTLVecsa_target_tsf_info_attr *) + (pFrm + pTlv->offset)); + break; + case SigTlvedca_pifs_param_attr: + status |= + dot11f_unpack_tlv_edca_pifs_param_attr(pCtx, + pBufRemaining, len, + (tDot11fTLVedca_pifs_param_attr *) + (pFrm + pTlv->offset)); + break; + case SigTlvhe_2xltf_160mhz_supp: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVhe_2xltf_160mhz_supp *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVhe_2xltf_160mhz_supp *) + (pFrm + pTlv->offset))->he_2xltf_160MHz_supp)); + break; + case SigTlvhe_400ns_sgi_attr: + status |= + dot11f_unpack_tlv_he_400ns_sgi_attr(pCtx, + pBufRemaining, len, + (tDot11fTLVhe_400ns_sgi_attr *) + (pFrm + pTlv->offset)); + break; + case SigTlvhe_dl_mumimo_attr: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVhe_dl_mumimo_attr *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVhe_dl_mumimo_attr *) + (pFrm + pTlv->offset))->he_dl_mumimo_supp)); + break; + case SigTlvhe_dl_ofdma_attr: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVhe_dl_ofdma_attr *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVhe_dl_ofdma_attr *) + (pFrm + pTlv->offset))->he_dl_ofdma_supp)); + break; + case SigTlvhe_mcs13_attr: + status |= + dot11f_unpack_tlv_he_mcs13_attr(pCtx, + pBufRemaining, len, + (tDot11fTLVhe_mcs13_attr *) + (pFrm + pTlv->offset)); + break; + case SigTlvmbo_ap_cap: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVmbo_ap_cap *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVmbo_ap_cap *) + (pFrm + pTlv->offset))->mbo_cap_ind)); + break; + case SigTlvnon_prefferd_chan_rep: + status |= + dot11f_unpack_tlv_non_prefferd_chan_rep(pCtx, + pBufRemaining, len, + (tDot11fTLVnon_prefferd_chan_rep *) + (pFrm + pTlv->offset)); + break; + case SigTlvoce_cap: + status |= + dot11f_unpack_tlv_oce_cap(pCtx, + pBufRemaining, len, + (tDot11fTLVoce_cap *) + (pFrm + pTlv->offset)); + break; + case SigTlvqcn_version: + status |= + dot11f_unpack_tlv_qcn_version(pCtx, + pBufRemaining, len, + (tDot11fTLVqcn_version *) + (pFrm + pTlv->offset)); + break; + case SigTlvreduced_wan_metrics: + status |= + dot11f_unpack_tlv_reduced_wan_metrics(pCtx, + pBufRemaining, len, + (tDot11fTLVreduced_wan_metrics *) + (pFrm + pTlv->offset)); + break; + case SigTlvrssi_assoc_rej: + status |= + dot11f_unpack_tlv_rssi_assoc_rej(pCtx, + pBufRemaining, len, + (tDot11fTLVrssi_assoc_rej *) + (pFrm + pTlv->offset)); + break; + case SigTlvtrans_reasonp_attr: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVtrans_reasonp_attr *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVtrans_reasonp_attr *) + (pFrm + pTlv->offset))->transition_reasonp)); + break; + case SigTlvtrans_rejectp_attr: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVtrans_rejectp_attr *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVtrans_rejectp_attr *) + (pFrm + pTlv->offset))->transition_rejp)); + break; + case SigTlvtransition_reason: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVtransition_reason *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVtransition_reason *) + (pFrm + pTlv->offset))->transition_reason_code)); + break; + case SigTlvtransition_reject_reason: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVtransition_reject_reason *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVtransition_reject_reason *) + (pFrm + pTlv->offset))->transition_reject_code)); + break; + case SigTlvvht_mcs11_attr: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVvht_mcs11_attr *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVvht_mcs11_attr *) + (pFrm + pTlv->offset))->vht_mcs_10_11_supp)); + break; + case SigTlvP2PInterface: + status |= + dot11f_unpack_tlv_p2_p_interface(pCtx, + pBufRemaining, len, + (tDot11fTLVP2PInterface *) + (pFrm + pTlv->offset)); + break; + case SigTlvP2PManageability: + status |= + dot11f_unpack_tlv_common_func(pCtx, + pBufRemaining, len, + (uint8_t *)&(((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->present), + (uint8_t *)&(((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->manageability)); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR: I" + " don't know about the TLV signature %d-- thi" + "s is most likely a 'framesc' bug.\n"), + pTlv->sig); + FRAMES_DBG_BREAK(); + return DOT11F_INTERNAL_ERROR; + } /* End switch on sig. */ + } /* End if on length check. */ + + } else { + FRAMES_LOG2(pCtx, FRLOG3, FRFL("Skipping unknown TLV %d (" + "length %d)\n"), id, len); + FRAMES_DUMP(pCtx, FRLOG3, pBufRemaining - (pTlv->sType + pTlv->sLen), len); + status |= DOT11F_UNKNOWN_TLVS; + } + + /* Advance to the next TLV */ + pBufRemaining += len; + + if (len > nBufRemaining) { + FRAMES_LOG0(pCtx, FRLOGW, FRFL("This TLV extends past th" + "e buffer as it was defined to us. This could mean " + "a corrupt frame, or just an incorrect length parame" + "ter.\n")); + FRAMES_DBG_BREAK(); + status |= DOT11F_LAST_TLV_TOO_LONG; + goto MandatoryCheck; + } + + nBufRemaining -= len; + + } /* End iteration over TLVs.*/ + +MandatoryCheck: + pTlv = &TLVs[0]; + while (0xffff != pTlv->id) { + if (pTlv->fMandatory) { + pfFound = (uint8_t *)(pFrm + pTlv->offset + + pTlv->presenceOffset); + if (!*pfFound) { + FRAMES_LOG1(pCtx, FRLOGW, FRFL("ERROR: The mandatory " + "TLV %s wasn't seen.\n"), + pTlv->name); + FRAMES_DBG_BREAK(); + status |= DOT11F_MANDATORY_TLV_MISSING; + } + + } + ++pTlv; + } + + return status; +} /* End UnpacTlvkCore. */ +uint32_t dot11f_get_packed_ietclas(tpAniSirGlobal pCtx, + tDot11fIETCLAS *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 0: + *pnNeeded += 6; + *pnNeeded += 6; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + switch (pIe->info.IpParams.version) { + case 4: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 6: + *pnNeeded += 16; + *pnNeeded += 16; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 3; + break; + } + break; + case 2: + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ietclas. */ + +uint32_t dot11f_get_packed_iewmmtclas(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLAS *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 0: + *pnNeeded += 6; + *pnNeeded += 6; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + switch (pIe->info.IpParams.version) { + case 4: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 6: + *pnNeeded += 16; + *pnNeeded += 16; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 3; + break; + } + break; + case 2: + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iewmmtclas. */ + +uint32_t dot11f_get_packed_ie_neighbor_rpt(tpAniSirGlobal pCtx, + tDot11fIEneighbor_rpt *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_neighbor_rpt); + break; + } + return status; +} /* End dot11f_get_packed_ie_neighbor_rpt. */ + +uint32_t dot11f_get_packed_ie_tclas_mask(tpAniSirGlobal pCtx, + tDot11fIEtclas_mask *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->classifier_type) { + case 4: + *pnNeeded += 16; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_tclas_mask. */ + +uint32_t dot11f_get_packed_ie_transmit_power_env(tpAniSirGlobal pCtx, + tDot11fIEtransmit_power_env *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += pIe->num_tx_power; + if (pIe->max_tx_pwr_interpret) { + switch (pIe->max_tx_pwr_interpret) { + case 0: + *pnNeeded += 1; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + break; + case 2: + *pnNeeded += 1; + break; + case 3: + *pnNeeded += 1; + *pnNeeded += 8; + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_transmit_power_env. */ + +uint32_t dot11f_get_packed_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + tDot11fIEChannelSwitchWrapper *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_ChannelSwitchWrapper); + break; + } + return status; +} /* End dot11f_get_packed_ie_channel_switch_wrapper. */ + +uint32_t dot11f_get_packed_ie_country(tpAniSirGlobal pCtx, + tDot11fIECountry *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 3; + *pnNeeded += 3; + if (pIe->num_more_triplets) { + *pnNeeded += (pIe->num_more_triplets * 3); + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_country. */ + +uint32_t dot11f_get_packed_ieft_info(tpAniSirGlobal pCtx, + tDot11fIEFTInfo *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 16; + *pnNeeded += 32; + *pnNeeded += 32; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_FTInfo); + break; + } + return status; +} /* End dot11f_get_packed_ieft_info. */ + +uint32_t dot11f_get_packed_ie_MBO_IE(tpAniSirGlobal pCtx, + tDot11fIEMBO_IE *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_MBO_IE); + break; + } + return status; +} /* End dot11f_get_packed_ie_MBO_IE. */ + +uint32_t dot11f_get_packed_ie_measurement_report(tpAniSirGlobal pCtx, + tDot11fIEMeasurementReport *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + if (pIe->type) { + switch (pIe->type) { + case 0: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 3: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_reportchannel_load_report); + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 4; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_reportBeacon); + break; + case 7: + *pnNeeded += 2; + *pnNeeded += 1; + switch (pIe->report.sta_stats.group_id) { + case 0: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + break; + case 1: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + break; + case 2: + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + break; + case 10: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 1; + break; + } + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_reportsta_stats); + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_measurement_report. */ + +uint32_t dot11f_get_packed_ie_measurement_request(tpAniSirGlobal pCtx, + tDot11fIEMeasurementRequest *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->measurement_type) { + case 0: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 1: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 2; + break; + case 3: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 2; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestchannel_load); + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 6; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestBeacon); + break; + case 8: + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestlci); + break; + case 16: + *pnNeeded += 2; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, IES_measurement_requestftmrr); + break; + case 7: + *pnNeeded += 6; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += 1; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_measurement_request. */ + +uint32_t dot11f_get_packed_ie_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIENeighborReport *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_NeighborReport); + break; + } + return status; +} /* End dot11f_get_packed_ie_neighbor_report. */ + +uint32_t dot11f_get_packed_iep2_p_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PAssocReq); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_assoc_req. */ + +uint32_t dot11f_get_packed_iep2_p_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PAssocRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_assoc_res. */ + +uint32_t dot11f_get_packed_iep2_p_beacon(tpAniSirGlobal pCtx, + tDot11fIEP2PBeacon *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PBeacon); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_beacon. */ + +uint32_t dot11f_get_packed_iep2_p_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PBeaconProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PBeaconProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_beacon_probe_res. */ + +uint32_t dot11f_get_packed_iep2_p_de_auth(tpAniSirGlobal pCtx, + tDot11fIEP2PDeAuth *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PDeAuth); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_de_auth. */ + +uint32_t dot11f_get_packed_iep2_p_dis_assoc(tpAniSirGlobal pCtx, + tDot11fIEP2PDisAssoc *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PDisAssoc); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_dis_assoc. */ + +uint32_t dot11f_get_packed_iep2_p_probe_req(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PProbeReq); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_probe_req. */ + +uint32_t dot11f_get_packed_iep2_p_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_P2PProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_iep2_p_probe_res. */ + +uint32_t dot11f_get_packed_ieric_data_desc(tpAniSirGlobal pCtx, + tDot11fIERICDataDesc *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_RICDataDesc); + break; + } + return status; +} /* End dot11f_get_packed_ieric_data_desc. */ + +uint32_t dot11f_get_packed_iersn(tpAniSirGlobal pCtx, + tDot11fIERSN *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + if (pIe->gp_cipher_suite_present) { + + *pnNeeded += 4; + } else { + break; + } + if (pIe->pwise_cipher_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->pwise_cipher_suite_count * 4); + if (pIe->akm_suite_cnt) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->akm_suite_cnt * 4); + if (pIe->RSN_Cap_present) { + + *pnNeeded += 2; + } else { + break; + } + if (pIe->pmkid_count) { + *pnNeeded += 2; + } else { + if (pIe->gp_mgmt_cipher_suite_present) { + *pnNeeded += 2; + } + } + *pnNeeded += (pIe->pmkid_count * 16); + if (pIe->gp_mgmt_cipher_suite_present) { + + *pnNeeded += 4; + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iersn. */ + +uint32_t dot11f_get_packed_iewapi(tpAniSirGlobal pCtx, + tDot11fIEWAPI *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += (pIe->akm_suite_count * 4); + *pnNeeded += 2; + *pnNeeded += (pIe->unicast_cipher_suite_count * 4); + *pnNeeded += 4; + *pnNeeded += 2; + if (pIe->bkid_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->bkid_count * 16); + break; + } + return status; +} /* End dot11f_get_packed_iewapi. */ + +uint32_t dot11f_get_packed_iewpa(tpAniSirGlobal pCtx, + tDot11fIEWPA *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + if (pIe->multicast_cipher_present) { + + *pnNeeded += 4; + } else { + break; + } + if (pIe->unicast_cipher_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->unicast_cipher_count * 4); + if (pIe->auth_suite_count) { + *pnNeeded += 2; + } else { + break; + } + *pnNeeded += (pIe->auth_suite_count * 4); + if (pIe->caps) { + *pnNeeded += 2; + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_iewpa. */ + +uint32_t dot11f_get_packed_iewsc(tpAniSirGlobal pCtx, + tDot11fIEWSC *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WSC); + break; + } + return status; +} /* End dot11f_get_packed_iewsc. */ + +uint32_t dot11f_get_packed_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEWscAssocReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscAssocReq); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_assoc_req. */ + +uint32_t dot11f_get_packed_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscAssocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscAssocRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_assoc_res. */ + +uint32_t dot11f_get_packed_ie_wsc_beacon(tpAniSirGlobal pCtx, + tDot11fIEWscBeacon *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscBeacon); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_beacon. */ + +uint32_t dot11f_get_packed_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscBeaconProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscBeaconProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_beacon_probe_res. */ + +uint32_t dot11f_get_packed_ie_wsc_probe_req(tpAniSirGlobal pCtx, + tDot11fIEWscProbeReq *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscProbeReq); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_probe_req. */ + +uint32_t dot11f_get_packed_ie_wsc_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscProbeRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscProbeRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_probe_res. */ + +uint32_t dot11f_get_packed_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscReassocRes *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_WscReassocRes); + break; + } + return status; +} /* End dot11f_get_packed_ie_wsc_reassoc_res. */ + +uint32_t dot11f_get_packed_ie_descriptor_element(tpAniSirGlobal pCtx, + tDot11fIEdescriptor_element *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 4; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_descriptor_element); + break; + } + return status; +} /* End dot11f_get_packed_ie_descriptor_element. */ + +uint32_t dot11f_get_packed_ie_eht_cap(tpAniSirGlobal pCtx, + tDot11fIEeht_cap *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 1; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 1; + if (pIe->ppet_present) { + switch (pIe->ppet_present) { + case 1: + *pnNeeded += pIe->ppet.ppe_threshold.num_ppe_th; + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_eht_cap. */ + +uint32_t dot11f_get_packed_ie_he_cap(tpAniSirGlobal pCtx, + tDot11fIEhe_cap *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 4; + *pnNeeded += 4; + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 2; + *pnNeeded += 2; + *pnNeeded += (pIe->chan_width_2 * 2); + *pnNeeded += (pIe->chan_width_2 * 2); + *pnNeeded += (pIe->chan_width_3 * 2); + *pnNeeded += (pIe->chan_width_3 * 2); + if (pIe->ppet_present) { + switch (pIe->ppet_present) { + case 1: + *pnNeeded += pIe->ppet.ppe_threshold.num_ppe_th; + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_he_cap. */ + +uint32_t dot11f_get_packed_ie_he_op(tpAniSirGlobal pCtx, + tDot11fIEhe_op *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + if (pIe->vht_oper_present) { + switch (pIe->vht_oper_present) { + case 1: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + } + } + if (pIe->co_located_bss) { + switch (pIe->co_located_bss) { + case 1: + *pnNeeded += 1; + break; + } + } + if (pIe->oper_info_6g_present) { + switch (pIe->oper_info_6g_present) { + case 1: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + break; + } + } + break; + } + return status; +} /* End dot11f_get_packed_ie_he_op. */ + +uint32_t dot11f_get_packed_ie_hs20vendor_ie(tpAniSirGlobal pCtx, + tDot11fIEhs20vendor_ie *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + if (pIe->hs_id_present) { + switch (pIe->hs_id_present) { + case 1: + *pnNeeded += 2; + break; + case 2: + *pnNeeded += 2; + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_hs20vendor_ie. */ + +uint32_t dot11f_get_packed_ie_qcn_ie(tpAniSirGlobal pCtx, + tDot11fIEqcn_ie *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pIe, pnNeeded, + TLVS_qcn_ie); + break; + } + return status; +} /* End dot11f_get_packed_ie_qcn_ie. */ + +uint32_t dot11f_get_packed_ie_reduced_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIEreduced_neighbor_report *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 2; + *pnNeeded += 1; + *pnNeeded += 1; + switch (pIe->tbtt_info_len) { + case 1: + *pnNeeded += 1; + break; + case 2: + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 5: + *pnNeeded += 1; + *pnNeeded += 4; + break; + case 6: + *pnNeeded += 1; + *pnNeeded += 4; + *pnNeeded += 1; + break; + case 7: + *pnNeeded += 1; + *pnNeeded += 6; + break; + case 8: + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 1; + break; + case 9: + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 11: + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 4; + break; + case 12: + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 4; + *pnNeeded += 1; + break; + case 13: + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 4; + *pnNeeded += 1; + *pnNeeded += 1; + break; + case 16: + *pnNeeded += 1; + *pnNeeded += 6; + *pnNeeded += 4; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 2; + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_reduced_neighbor_report. */ + +uint32_t dot11f_get_packed_ie_spatial_reuse(tpAniSirGlobal pCtx, + tDot11fIEspatial_reuse *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + if (pIe->non_srg_offset_present) { + switch (pIe->non_srg_offset_present) { + case 1: + *pnNeeded += 1; + break; + } + } else { + break; + } + if (pIe->srg_info_present) { + switch (pIe->srg_info_present) { + case 1: + *pnNeeded += 1; + *pnNeeded += 1; + *pnNeeded += 8; + *pnNeeded += 8; + break; + } + } else { + break; + } + break; + } + return status; +} /* End dot11f_get_packed_ie_spatial_reuse. */ + +uint32_t dot11f_get_packed_ie_vendor_vht_ie(tpAniSirGlobal pCtx, + tDot11fIEvendor_vht_ie *pIe, uint32_t *pnNeeded) +{ + uint32_t status = DOT11F_PARSE_SUCCESS; + (void)pCtx; + while (pIe->present) { + *pnNeeded += 1; + status = get_packed_size_core(pCtx, (uint8_t *)pIe, pnNeeded, + IES_vendor_vht_ie); + break; + } + return status; +} /* End dot11f_get_packed_ie_vendor_vht_ie. */ + +uint32_t dot11f_get_packed_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AddTSRequest); + return status; +} /* End dot11f_get_packed_add_ts_request_size. */ + +uint32_t dot11f_get_packed_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AddTSResponse); + return status; +} /* End dot11f_get_packed_add_ts_response_size. */ + +uint32_t dot11f_get_packed_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AssocRequest); + return status; +} /* End dot11f_get_packed_assoc_request_size. */ + +uint32_t dot11f_get_packed_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_AssocResponse); + return status; +} /* End dot11f_get_packed_assoc_response_size. */ + +uint32_t dot11f_get_packed_authentication_size(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Authentication); + return status; +} /* End dot11f_get_packed_authentication_size. */ + +uint32_t dot11f_get_packed_beacon_size(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon); + return status; +} /* End dot11f_get_packed_beacon_size. */ + +uint32_t dot11f_get_packed_beacon1_size(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon1); + return status; +} /* End dot11f_get_packed_beacon1_size. */ + +uint32_t dot11f_get_packed_beacon2_size(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Beacon2); + return status; +} /* End dot11f_get_packed_beacon2_size. */ + +uint32_t dot11f_get_packed_beacon_i_es_size(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_BeaconIEs); + return status; +} /* End dot11f_get_packed_beacon_i_es_size. */ + +uint32_t dot11f_get_packed_channel_switch_size(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ChannelSwitch); + return status; +} /* End dot11f_get_packed_channel_switch_size. */ + +uint32_t dot11f_get_packed_de_auth_size(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_DeAuth); + return status; +} /* End dot11f_get_packed_de_auth_size. */ + +uint32_t dot11f_get_packed_del_ts_size(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_DelTS); + return status; +} /* End dot11f_get_packed_del_ts_size. */ + +uint32_t dot11f_get_packed_disassociation_size(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_Disassociation); + return status; +} /* End dot11f_get_packed_disassociation_size. */ + +uint32_t dot11f_get_packed_link_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 11; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_LinkMeasurementReport); + return status; +} /* End dot11f_get_packed_link_measurement_report_size. */ + +uint32_t dot11f_get_packed_link_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_LinkMeasurementRequest); + return status; +} /* End dot11f_get_packed_link_measurement_request_size. */ + +uint32_t dot11f_get_packed_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_MeasurementReport); + return status; +} /* End dot11f_get_packed_measurement_report_size. */ + +uint32_t dot11f_get_packed_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_MeasurementRequest); + return status; +} /* End dot11f_get_packed_measurement_request_size. */ + +uint32_t dot11f_get_packed_neighbor_report_request_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_NeighborReportRequest); + return status; +} /* End dot11f_get_packed_neighbor_report_request_size. */ + +uint32_t dot11f_get_packed_neighbor_report_response_size(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_NeighborReportResponse); + return status; +} /* End dot11f_get_packed_neighbor_report_response_size. */ + +uint32_t dot11f_get_packed_operating_mode_size(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_OperatingMode); + return status; +} /* End dot11f_get_packed_operating_mode_size. */ + +uint32_t dot11f_get_packed_probe_request_size(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 0; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ProbeRequest); + return status; +} /* End dot11f_get_packed_probe_request_size. */ + +uint32_t dot11f_get_packed_probe_response_size(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 12; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ProbeResponse); + return status; +} /* End dot11f_get_packed_probe_response_size. */ + +uint32_t dot11f_get_packed_qos_map_configure_size(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_QosMapConfigure); + return status; +} /* End dot11f_get_packed_qos_map_configure_size. */ + +uint32_t dot11f_get_packed_radio_measurement_report_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_RadioMeasurementReport); + return status; +} /* End dot11f_get_packed_radio_measurement_report_size. */ + +uint32_t dot11f_get_packed_radio_measurement_request_size(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_RadioMeasurementRequest); + return status; +} /* End dot11f_get_packed_radio_measurement_request_size. */ + +uint32_t dot11f_get_packed_re_assoc_request_size(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 10; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ReAssocRequest); + return status; +} /* End dot11f_get_packed_re_assoc_request_size. */ + +uint32_t dot11f_get_packed_re_assoc_response_size(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ReAssocResponse); + return status; +} /* End dot11f_get_packed_re_assoc_response_size. */ + +uint32_t dot11f_get_packed_sm_power_save_size(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SMPowerSave); + return status; +} /* End dot11f_get_packed_sm_power_save_size. */ + +uint32_t dot11f_get_packed_sa_query_req_size(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SaQueryReq); + return status; +} /* End dot11f_get_packed_sa_query_req_size. */ + +uint32_t dot11f_get_packed_sa_query_rsp_size(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_SaQueryRsp); + return status; +} /* End dot11f_get_packed_sa_query_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_dis_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSDisReq); + return status; +} /* End dot11f_get_packed_tdls_dis_req_size. */ + +uint32_t dot11f_get_packed_tdls_dis_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSDisRsp); + return status; +} /* End dot11f_get_packed_tdls_dis_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_peer_traffic_ind_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSPeerTrafficInd); + return status; +} /* End dot11f_get_packed_tdls_peer_traffic_ind_size. */ + +uint32_t dot11f_get_packed_tdls_peer_traffic_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSPeerTrafficRsp); + return status; +} /* End dot11f_get_packed_tdls_peer_traffic_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_setup_cnf_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupCnf); + return status; +} /* End dot11f_get_packed_tdls_setup_cnf_size. */ + +uint32_t dot11f_get_packed_tdls_setup_req_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupReq); + return status; +} /* End dot11f_get_packed_tdls_setup_req_size. */ + +uint32_t dot11f_get_packed_tdls_setup_rsp_size(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSSetupRsp); + return status; +} /* End dot11f_get_packed_tdls_setup_rsp_size. */ + +uint32_t dot11f_get_packed_tdls_teardown_size(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TDLSTeardown); + return status; +} /* End dot11f_get_packed_tdls_teardown_size. */ + +uint32_t dot11f_get_packed_tpc_report_size(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TPCReport); + return status; +} /* End dot11f_get_packed_tpc_report_size. */ + +uint32_t dot11f_get_packed_tpc_request_size(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TPCRequest); + return status; +} /* End dot11f_get_packed_tpc_request_size. */ + +uint32_t dot11f_get_packed_timing_advertisement_frame_size(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 10; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_TimingAdvertisementFrame); + return status; +} /* End dot11f_get_packed_timing_advertisement_frame_size. */ + +uint32_t dot11f_get_packed_vht_gid_management_action_frame_size(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 26; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_VHTGidManagementActionFrame); + return status; +} /* End dot11f_get_packed_vht_gid_management_action_frame_size. */ + +uint32_t dot11f_get_packed_wmm_add_ts_request_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMAddTSRequest); + return status; +} /* End dot11f_get_packed_wmm_add_ts_request_size. */ + +uint32_t dot11f_get_packed_wmm_add_ts_response_size(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMAddTSResponse); + return status; +} /* End dot11f_get_packed_wmm_add_ts_response_size. */ + +uint32_t dot11f_get_packed_wmm_del_ts_size(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 4; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_WMMDelTS); + return status; +} /* End dot11f_get_packed_wmm_del_ts_size. */ + +uint32_t dot11f_get_packed_addba_req_size(tpAniSirGlobal pCtx, + tDot11faddba_req *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 9; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_addba_req); + return status; +} /* End dot11f_get_packed_addba_req_size. */ + +uint32_t dot11f_get_packed_addba_rsp_size(tpAniSirGlobal pCtx, + tDot11faddba_rsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 9; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_addba_rsp); + return status; +} /* End dot11f_get_packed_addba_rsp_size. */ + +uint32_t dot11f_get_packed_delba_req_size(tpAniSirGlobal pCtx, + tDot11fdelba_req *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_delba_req); + return status; +} /* End dot11f_get_packed_delba_req_size. */ + +uint32_t dot11f_get_packed_epcs_neg_reqSize(tpAniSirGlobal pCtx, + tDot11fepcs_neg_req *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_epcs_neg_req); + return status; +} /* End dot11f_get_packed_epcs_neg_reqSize. */ + +uint32_t dot11f_get_packed_epcs_neg_rspSize(tpAniSirGlobal pCtx, + tDot11fepcs_neg_rsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_epcs_neg_rsp); + return status; +} /* End dot11f_get_packed_epcs_neg_rspSize. */ + +uint32_t dot11f_get_packed_epcs_teardownSize(tpAniSirGlobal pCtx, + tDot11fepcs_teardown *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_epcs_teardown); + return status; +} /* End dot11f_get_packed_epcs_teardownSize. */ + +uint32_t dot11f_get_packed_ext_channel_switch_action_frame_size(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 6; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ext_channel_switch_action_frame); + return status; +} /* End dot11f_get_packed_ext_channel_switch_action_frame_size. */ + +uint32_t dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_ht2040_bss_coexistence_mgmt_action_frame); + return status; +} /* End dot11f_get_packed_ht2040_bss_coexistence_mgmt_action_frameSize. */ + +uint32_t dot11f_get_packed_mscs_request_action_frameSize(tpAniSirGlobal pCtx, + tDot11fmscs_request_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_mscs_request_action_frame); + return status; +} /* End dot11f_get_packed_mscs_request_action_frameSize. */ + +uint32_t dot11f_get_packed_p2p_oper_chan_change_confirmSize(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 7; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_p2p_oper_chan_change_confirm); + return status; +} /* End dot11f_get_packed_p2p_oper_chan_change_confirmSize. */ + +uint32_t dot11f_get_packed_t2lm_neg_reqSize(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_req *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 3; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_t2lm_neg_req); + return status; +} /* End dot11f_get_packed_t2lm_neg_reqSize. */ + +uint32_t dot11f_get_packed_t2lm_neg_rspSize(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_rsp *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_t2lm_neg_rsp); + return status; +} /* End dot11f_get_packed_t2lm_neg_rspSize. */ + +uint32_t dot11f_get_packed_t2lm_teardownSize(tpAniSirGlobal pCtx, + tDot11ft2lm_teardown *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 2; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_t2lm_teardown); + return status; +} /* End dot11f_get_packed_t2lm_teardownSize. */ + +uint32_t dot11f_get_packed_vendor_action_frameSize(tpAniSirGlobal pCtx, + tDot11fvendor_action_frame *pFrm, uint32_t *pnNeeded) +{ + uint32_t status = 0; + *pnNeeded = 5; + status = get_packed_size_core(pCtx, (uint8_t *)pFrm, pnNeeded, + IES_vendor_action_frame); + return status; +} /* End dot11f_get_packed_vendor_action_frameSize. */ + +static uint32_t get_packed_size_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tIEDefn IEs[]) +{ + const tIEDefn *pIe; + uint16_t i, n; + uint32_t status; + tFRAMES_BOOL *pfFound; + uint32_t countOffset = 0; + uint32_t byteCount = 0; + uint8_t pIePresent = 0; + uint32_t offset = 0; + + status = DOT11F_PARSE_SUCCESS; + + (void)pCtx; /* Shutup the compiler if we have no FFs nor IEs... */ + i = 0; + n = 0; + pIe = &(IEs[0]); + while (0xff != pIe->eid || pIe->extn_eid) { + pfFound = (tFRAMES_BOOL *)(pFrm + pIe->offset + + pIe->presenceOffset); + if (*pfFound) { + countOffset = ((0 == pIe->arraybound) ? 1 : (*(uint16_t *)(pFrm + pIe->countOffset))); + for (i = 0U; i < countOffset; ++i) { + *pnNeeded += 2U + pIe->noui; + if (pIe->extn_eid) + (*pnNeeded)++; + byteCount = 0; + switch (pIe->sig) { + case SigIeGTK: + offset = sizeof(tDot11fIEGTK); + byteCount = ((tDot11fIEGTK *) + (pFrm + pIe->offset + offset * i))-> + num_key + 11; + pIePresent = ((tDot11fIEGTK *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeIGTK: + offset = sizeof(tDot11fIEIGTK); + byteCount = 33; + pIePresent = ((tDot11fIEIGTK *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeR0KH_ID: + offset = sizeof(tDot11fIER0KH_ID); + byteCount = ((tDot11fIER0KH_ID *) + (pFrm + pIe->offset + offset * i))-> + num_PMK_R0_ID; + pIePresent = ((tDot11fIER0KH_ID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeR1KH_ID: + offset = sizeof(tDot11fIER1KH_ID); + byteCount = 6; + pIePresent = ((tDot11fIER1KH_ID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeAPChannelReport: + offset = sizeof(tDot11fIEAPChannelReport); + byteCount = ((tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + offset * i))-> + num_channelList + 1; + pIePresent = ((tDot11fIEAPChannelReport *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBcnReportingDetail: + offset = sizeof(tDot11fIEBcnReportingDetail); + byteCount = 1; + pIePresent = ((tDot11fIEBcnReportingDetail *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeBeaconReportFrmBody: + offset = sizeof(tDot11fIEBeaconReportFrmBody); + byteCount = ((tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + offset * i))-> + num_reportedFields; + pIePresent = ((tDot11fIEBeaconReportFrmBody *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeCondensedCountryStr: + offset = sizeof(tDot11fIECondensedCountryStr); + byteCount = 2; + pIePresent = ((tDot11fIECondensedCountryStr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtRequestedInfo: + offset = sizeof(tDot11fIEExtRequestedInfo); + byteCount = ((tDot11fIEExtRequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + num_req_element_id_ext + 1; + pIePresent = ((tDot11fIEExtRequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMeasurementPilot: + offset = sizeof(tDot11fIEMeasurementPilot); + byteCount = ((tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + offset * i))-> + num_vendorSpecific + 1; + pIePresent = ((tDot11fIEMeasurementPilot *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMultiBssid: + offset = sizeof(tDot11fIEMultiBssid); + byteCount = ((tDot11fIEMultiBssid *) + (pFrm + pIe->offset + offset * i))-> + num_vendorSpecific + 1; + pIePresent = ((tDot11fIEMultiBssid *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICData: + offset = sizeof(tDot11fIERICData); + byteCount = 4; + pIePresent = ((tDot11fIERICData *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICDescriptor: + offset = sizeof(tDot11fIERICDescriptor); + byteCount = ((tDot11fIERICDescriptor *) + (pFrm + pIe->offset + offset * i))-> + num_variableData + 1; + pIePresent = ((tDot11fIERICDescriptor *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRRMEnabledCap: + offset = sizeof(tDot11fIERRMEnabledCap); + byteCount = 5; + pIePresent = ((tDot11fIERRMEnabledCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRequestedInfo: + offset = sizeof(tDot11fIERequestedInfo); + byteCount = ((tDot11fIERequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + num_requested_eids; + pIePresent = ((tDot11fIERequestedInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSSID: + offset = sizeof(tDot11fIESSID); + byteCount = ((tDot11fIESSID *) + (pFrm + pIe->offset + offset * i))-> + num_ssid; + pIePresent = ((tDot11fIESSID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSchedule: + offset = sizeof(tDot11fIESchedule); + byteCount = 14; + pIePresent = ((tDot11fIESchedule *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTCLAS: + offset = sizeof(tDot11fIETCLAS); + status |= + dot11f_get_packed_ietclas( + pCtx, (tDot11fIETCLAS *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeTCLASSPROC: + offset = sizeof(tDot11fIETCLASSPROC); + byteCount = 1; + pIePresent = ((tDot11fIETCLASSPROC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSDelay: + offset = sizeof(tDot11fIETSDelay); + byteCount = 4; + pIePresent = ((tDot11fIETSDelay *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSFInfo: + offset = sizeof(tDot11fIETSFInfo); + byteCount = 4; + pIePresent = ((tDot11fIETSFInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTSPEC: + offset = sizeof(tDot11fIETSPEC); + byteCount = 55; + pIePresent = ((tDot11fIETSPEC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTCaps: + offset = sizeof(tDot11fIEVHTCaps); + byteCount = 12; + pIePresent = ((tDot11fIEVHTCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTOperation: + offset = sizeof(tDot11fIEVHTOperation); + byteCount = 5; + pIePresent = ((tDot11fIEVHTOperation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMSchedule: + offset = sizeof(tDot11fIEWMMSchedule); + byteCount = 15; + pIePresent = ((tDot11fIEWMMSchedule *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTCLAS: + offset = sizeof(tDot11fIEWMMTCLAS); + status |= + dot11f_get_packed_iewmmtclas( + pCtx, (tDot11fIEWMMTCLAS *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWMMTCLASPROC: + offset = sizeof(tDot11fIEWMMTCLASPROC); + byteCount = 2; + pIePresent = ((tDot11fIEWMMTCLASPROC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTSDelay: + offset = sizeof(tDot11fIEWMMTSDelay); + byteCount = 5; + pIePresent = ((tDot11fIEWMMTSDelay *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMTSPEC: + offset = sizeof(tDot11fIEWMMTSPEC); + byteCount = 56; + pIePresent = ((tDot11fIEWMMTSPEC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWiderBWChanSwitchAnn: + offset = sizeof(tDot11fIEWiderBWChanSwitchAnn); + byteCount = 3; + pIePresent = ((tDot11fIEWiderBWChanSwitchAnn *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeazimuth_req: + offset = sizeof(tDot11fIEazimuth_req); + byteCount = 1; + pIePresent = ((tDot11fIEazimuth_req *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIebeacon_report_frm_body_fragment_id: + offset = sizeof(tDot11fIEbeacon_report_frm_body_fragment_id); + byteCount = 2; + pIePresent = ((tDot11fIEbeacon_report_frm_body_fragment_id *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIebw_ind_element: + offset = sizeof(tDot11fIEbw_ind_element); + byteCount = ((tDot11fIEbw_ind_element *) + (pFrm + pIe->offset + offset * i))-> + disabled_sub_chan_bitmap_present * 2 + 4; + pIePresent = ((tDot11fIEbw_ind_element *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIebw_indication: + offset = sizeof(tDot11fIEbw_indication); + byteCount = ((tDot11fIEbw_indication *) + (pFrm + pIe->offset + offset * i))-> + disabled_sub_chan_bitmap_present * 2 + 4; + pIePresent = ((tDot11fIEbw_indication *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIelast_beacon_report_indication: + offset = sizeof(tDot11fIElast_beacon_report_indication); + byteCount = 1; + pIePresent = ((tDot11fIElast_beacon_report_indication *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIemax_age: + offset = sizeof(tDot11fIEmax_age); + byteCount = 2; + pIePresent = ((tDot11fIEmax_age *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIemscs_status: + offset = sizeof(tDot11fIEmscs_status); + byteCount = 1; + pIePresent = ((tDot11fIEmscs_status *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeneighbor_rpt: + offset = sizeof(tDot11fIEneighbor_rpt); + status |= + dot11f_get_packed_ie_neighbor_rpt( + pCtx, (tDot11fIEneighbor_rpt *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIereporting_reason: + offset = sizeof(tDot11fIEreporting_reason); + byteCount = 1; + pIePresent = ((tDot11fIEreporting_reason *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIereq_mac_addr: + offset = sizeof(tDot11fIEreq_mac_addr); + byteCount = 6; + pIePresent = ((tDot11fIEreq_mac_addr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIerrm_reporting: + offset = sizeof(tDot11fIErrm_reporting); + byteCount = 2; + pIePresent = ((tDot11fIErrm_reporting *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIetclas_mask: + offset = sizeof(tDot11fIEtclas_mask); + status |= + dot11f_get_packed_ie_tclas_mask( + pCtx, (tDot11fIEtclas_mask *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIetgt_mac_addr: + offset = sizeof(tDot11fIEtgt_mac_addr); + byteCount = 6; + pIePresent = ((tDot11fIEtgt_mac_addr *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIetransmit_power_env: + offset = sizeof(tDot11fIEtransmit_power_env); + status |= + dot11f_get_packed_ie_transmit_power_env( + pCtx, (tDot11fIEtransmit_power_env *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIewide_bw_chan_switch: + offset = sizeof(tDot11fIEwide_bw_chan_switch); + byteCount = 3; + pIePresent = ((tDot11fIEwide_bw_chan_switch *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeAID: + offset = sizeof(tDot11fIEAID); + byteCount = 2; + pIePresent = ((tDot11fIEAID *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeCFParams: + offset = sizeof(tDot11fIECFParams); + byteCount = 6; + pIePresent = ((tDot11fIECFParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChallengeText: + offset = sizeof(tDot11fIEChallengeText); + byteCount = ((tDot11fIEChallengeText *) + (pFrm + pIe->offset + offset * i))-> + num_text; + pIePresent = ((tDot11fIEChallengeText *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChanSwitchAnn: + offset = sizeof(tDot11fIEChanSwitchAnn); + byteCount = 3; + pIePresent = ((tDot11fIEChanSwitchAnn *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeChannelSwitchWrapper: + offset = sizeof(tDot11fIEChannelSwitchWrapper); + status |= + dot11f_get_packed_ie_channel_switch_wrapper( + pCtx, (tDot11fIEChannelSwitchWrapper *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeCountry: + offset = sizeof(tDot11fIECountry); + status |= + dot11f_get_packed_ie_country( + pCtx, (tDot11fIECountry *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeDSParams: + offset = sizeof(tDot11fIEDSParams); + byteCount = 1; + pIePresent = ((tDot11fIEDSParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeEDCAParamSet: + offset = sizeof(tDot11fIEEDCAParamSet); + byteCount = 18; + pIePresent = ((tDot11fIEEDCAParamSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeERPInfo: + offset = sizeof(tDot11fIEERPInfo); + byteCount = 1; + pIePresent = ((tDot11fIEERPInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESECckmOpaque: + offset = sizeof(tDot11fIEESECckmOpaque); + byteCount = ((tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEESECckmOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESERadMgmtCap: + offset = sizeof(tDot11fIEESERadMgmtCap); + byteCount = 2; + pIePresent = ((tDot11fIEESERadMgmtCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETrafStrmMet: + offset = sizeof(tDot11fIEESETrafStrmMet); + byteCount = 4; + pIePresent = ((tDot11fIEESETrafStrmMet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETrafStrmRateSet: + offset = sizeof(tDot11fIEESETrafStrmRateSet); + byteCount = ((tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + offset * i))-> + num_tsrates + 1; + pIePresent = ((tDot11fIEESETrafStrmRateSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESETxmitPower: + offset = sizeof(tDot11fIEESETxmitPower); + byteCount = 2; + pIePresent = ((tDot11fIEESETxmitPower *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeESEVersion: + offset = sizeof(tDot11fIEESEVersion); + byteCount = 1; + pIePresent = ((tDot11fIEESEVersion *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtCap: + offset = sizeof(tDot11fIEExtCap); + byteCount = ((tDot11fIEExtCap *) + (pFrm + pIe->offset + offset * i))-> + num_bytes; + pIePresent = ((tDot11fIEExtCap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeExtSuppRates: + offset = sizeof(tDot11fIEExtSuppRates); + byteCount = ((tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + offset * i))-> + num_rates; + pIePresent = ((tDot11fIEExtSuppRates *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHParamSet: + offset = sizeof(tDot11fIEFHParamSet); + byteCount = 5; + pIePresent = ((tDot11fIEFHParamSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHParams: + offset = sizeof(tDot11fIEFHParams); + byteCount = 2; + pIePresent = ((tDot11fIEFHParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFHPattTable: + offset = sizeof(tDot11fIEFHPattTable); + byteCount = ((tDot11fIEFHPattTable *) + (pFrm + pIe->offset + offset * i))-> + num_randtable + 4; + pIePresent = ((tDot11fIEFHPattTable *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeFTInfo: + offset = sizeof(tDot11fIEFTInfo); + status |= + dot11f_get_packed_ieft_info( + pCtx, (tDot11fIEFTInfo *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeHTCaps: + offset = sizeof(tDot11fIEHTCaps); + byteCount = ((tDot11fIEHTCaps *) + (pFrm + pIe->offset + offset * i))-> + num_rsvd + 26; + pIePresent = ((tDot11fIEHTCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeHTInfo: + offset = sizeof(tDot11fIEHTInfo); + byteCount = ((tDot11fIEHTInfo *) + (pFrm + pIe->offset + offset * i))-> + num_rsvd + 22; + pIePresent = ((tDot11fIEHTInfo *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeLinkIdentifier: + offset = sizeof(tDot11fIELinkIdentifier); + byteCount = 18; + pIePresent = ((tDot11fIELinkIdentifier *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeMBO_IE: + offset = sizeof(tDot11fIEMBO_IE); + status |= + dot11f_get_packed_ie_MBO_IE( + pCtx, (tDot11fIEMBO_IE *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMeasurementReport: + offset = sizeof(tDot11fIEMeasurementReport); + status |= + dot11f_get_packed_ie_measurement_report( + pCtx, (tDot11fIEMeasurementReport *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMeasurementRequest: + offset = sizeof(tDot11fIEMeasurementRequest); + status |= + dot11f_get_packed_ie_measurement_request( + pCtx, (tDot11fIEMeasurementRequest *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeMobilityDomain: + offset = sizeof(tDot11fIEMobilityDomain); + byteCount = 3; + pIePresent = ((tDot11fIEMobilityDomain *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeNeighborReport: + offset = sizeof(tDot11fIENeighborReport); + status |= + dot11f_get_packed_ie_neighbor_report( + pCtx, (tDot11fIENeighborReport *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeOBSSScanParameters: + offset = sizeof(tDot11fIEOBSSScanParameters); + byteCount = 14; + pIePresent = ((tDot11fIEOBSSScanParameters *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeOperatingMode: + offset = sizeof(tDot11fIEOperatingMode); + byteCount = 1; + pIePresent = ((tDot11fIEOperatingMode *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeP2PAssocReq: + offset = sizeof(tDot11fIEP2PAssocReq); + status |= + dot11f_get_packed_iep2_p_assoc_req( + pCtx, (tDot11fIEP2PAssocReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PAssocRes: + offset = sizeof(tDot11fIEP2PAssocRes); + status |= + dot11f_get_packed_iep2_p_assoc_res( + pCtx, (tDot11fIEP2PAssocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PBeacon: + offset = sizeof(tDot11fIEP2PBeacon); + status |= + dot11f_get_packed_iep2_p_beacon( + pCtx, (tDot11fIEP2PBeacon *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PBeaconProbeRes: + offset = sizeof(tDot11fIEP2PBeaconProbeRes); + status |= + dot11f_get_packed_iep2_p_beacon_probe_res( + pCtx, (tDot11fIEP2PBeaconProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PDeAuth: + offset = sizeof(tDot11fIEP2PDeAuth); + status |= + dot11f_get_packed_iep2_p_de_auth( + pCtx, (tDot11fIEP2PDeAuth *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PDisAssoc: + offset = sizeof(tDot11fIEP2PDisAssoc); + status |= + dot11f_get_packed_iep2_p_dis_assoc( + pCtx, (tDot11fIEP2PDisAssoc *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PIEOpaque: + offset = sizeof(tDot11fIEP2PIEOpaque); + byteCount = ((tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEP2PIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeP2PProbeReq: + offset = sizeof(tDot11fIEP2PProbeReq); + status |= + dot11f_get_packed_iep2_p_probe_req( + pCtx, (tDot11fIEP2PProbeReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeP2PProbeRes: + offset = sizeof(tDot11fIEP2PProbeRes); + status |= + dot11f_get_packed_iep2_p_probe_res( + pCtx, (tDot11fIEP2PProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIePTIControl: + offset = sizeof(tDot11fIEPTIControl); + byteCount = 3; + pIePresent = ((tDot11fIEPTIControl *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePUBufferStatus: + offset = sizeof(tDot11fIEPUBufferStatus); + byteCount = 1; + pIePresent = ((tDot11fIEPUBufferStatus *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePowerCaps: + offset = sizeof(tDot11fIEPowerCaps); + byteCount = 2; + pIePresent = ((tDot11fIEPowerCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIePowerConstraints: + offset = sizeof(tDot11fIEPowerConstraints); + byteCount = 1; + pIePresent = ((tDot11fIEPowerConstraints *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQBSSLoad: + offset = sizeof(tDot11fIEQBSSLoad); + byteCount = 5; + pIePresent = ((tDot11fIEQBSSLoad *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQComVendorIE: + offset = sizeof(tDot11fIEQComVendorIE); + byteCount = 2; + pIePresent = ((tDot11fIEQComVendorIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQOSCapsAp: + offset = sizeof(tDot11fIEQOSCapsAp); + byteCount = 1; + pIePresent = ((tDot11fIEQOSCapsAp *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQOSCapsStation: + offset = sizeof(tDot11fIEQOSCapsStation); + byteCount = 1; + pIePresent = ((tDot11fIEQOSCapsStation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQosMapSet: + offset = sizeof(tDot11fIEQosMapSet); + byteCount = ((tDot11fIEQosMapSet *) + (pFrm + pIe->offset + offset * i))-> + num_dscp_exceptions; + pIePresent = ((tDot11fIEQosMapSet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeQuiet: + offset = sizeof(tDot11fIEQuiet); + byteCount = 6; + pIePresent = ((tDot11fIEQuiet *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRCPIIE: + offset = sizeof(tDot11fIERCPIIE); + byteCount = 1; + pIePresent = ((tDot11fIERCPIIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRICDataDesc: + offset = sizeof(tDot11fIERICDataDesc); + pnNeeded -= 2 ; /* Subtract the length and Oui as this is our container IE to group Ies and it doesn't have its own length and OUI. */ + status |= + dot11f_get_packed_ieric_data_desc( + pCtx, (tDot11fIERICDataDesc *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeRSN: + offset = sizeof(tDot11fIERSN); + status |= + dot11f_get_packed_iersn( + pCtx, (tDot11fIERSN *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeRSNIIE: + offset = sizeof(tDot11fIERSNIIE); + byteCount = 1; + pIePresent = ((tDot11fIERSNIIE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeRSNOpaque: + offset = sizeof(tDot11fIERSNOpaque); + byteCount = ((tDot11fIERSNOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIERSNOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppChannels: + offset = sizeof(tDot11fIESuppChannels); + byteCount = ((tDot11fIESuppChannels *) + (pFrm + pIe->offset + offset * i))-> + num_bands * 2; + pIePresent = ((tDot11fIESuppChannels *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppOperatingClasses: + offset = sizeof(tDot11fIESuppOperatingClasses); + byteCount = ((tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + offset * i))-> + num_classes; + pIePresent = ((tDot11fIESuppOperatingClasses *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeSuppRates: + offset = sizeof(tDot11fIESuppRates); + byteCount = ((tDot11fIESuppRates *) + (pFrm + pIe->offset + offset * i))-> + num_rates; + pIePresent = ((tDot11fIESuppRates *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTIM: + offset = sizeof(tDot11fIETIM); + byteCount = ((tDot11fIETIM *) + (pFrm + pIe->offset + offset * i))-> + num_vbmp + 3; + pIePresent = ((tDot11fIETIM *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTPCReport: + offset = sizeof(tDot11fIETPCReport); + byteCount = 2; + pIePresent = ((tDot11fIETPCReport *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTPCRequest: + offset = sizeof(tDot11fIETPCRequest); + byteCount = 0; + pIePresent = ((tDot11fIETPCRequest *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTimeAdvertisement: + offset = sizeof(tDot11fIETimeAdvertisement); + byteCount = 16; + pIePresent = ((tDot11fIETimeAdvertisement *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeTimeoutInterval: + offset = sizeof(tDot11fIETimeoutInterval); + byteCount = 5; + pIePresent = ((tDot11fIETimeoutInterval *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVHTExtBssLoad: + offset = sizeof(tDot11fIEVHTExtBssLoad); + byteCount = 5; + pIePresent = ((tDot11fIEVHTExtBssLoad *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVendor1IE: + offset = sizeof(tDot11fIEVendor1IE); + byteCount = 0; + pIePresent = ((tDot11fIEVendor1IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeVendor3IE: + offset = sizeof(tDot11fIEVendor3IE); + byteCount = 0; + pIePresent = ((tDot11fIEVendor3IE *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWAPI: + offset = sizeof(tDot11fIEWAPI); + status |= + dot11f_get_packed_iewapi( + pCtx, (tDot11fIEWAPI *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWAPIOpaque: + offset = sizeof(tDot11fIEWAPIOpaque); + byteCount = ((tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWAPIOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWFATPC: + offset = sizeof(tDot11fIEWFATPC); + byteCount = 2; + pIePresent = ((tDot11fIEWFATPC *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWFDIEOpaque: + offset = sizeof(tDot11fIEWFDIEOpaque); + byteCount = ((tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWFDIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMCaps: + offset = sizeof(tDot11fIEWMMCaps); + byteCount = 2; + pIePresent = ((tDot11fIEWMMCaps *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMInfoAp: + offset = sizeof(tDot11fIEWMMInfoAp); + byteCount = 2; + pIePresent = ((tDot11fIEWMMInfoAp *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMInfoStation: + offset = sizeof(tDot11fIEWMMInfoStation); + byteCount = 2; + pIePresent = ((tDot11fIEWMMInfoStation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWMMParams: + offset = sizeof(tDot11fIEWMMParams); + byteCount = 19; + pIePresent = ((tDot11fIEWMMParams *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWPA: + offset = sizeof(tDot11fIEWPA); + status |= + dot11f_get_packed_iewpa( + pCtx, (tDot11fIEWPA *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWPAOpaque: + offset = sizeof(tDot11fIEWPAOpaque); + byteCount = ((tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWPAOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWSC: + offset = sizeof(tDot11fIEWSC); + status |= + dot11f_get_packed_iewsc( + pCtx, (tDot11fIEWSC *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscAssocReq: + offset = sizeof(tDot11fIEWscAssocReq); + status |= + dot11f_get_packed_ie_wsc_assoc_req( + pCtx, (tDot11fIEWscAssocReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscAssocRes: + offset = sizeof(tDot11fIEWscAssocRes); + status |= + dot11f_get_packed_ie_wsc_assoc_res( + pCtx, (tDot11fIEWscAssocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscBeacon: + offset = sizeof(tDot11fIEWscBeacon); + status |= + dot11f_get_packed_ie_wsc_beacon( + pCtx, (tDot11fIEWscBeacon *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscBeaconProbeRes: + offset = sizeof(tDot11fIEWscBeaconProbeRes); + status |= + dot11f_get_packed_ie_wsc_beacon_probe_res( + pCtx, (tDot11fIEWscBeaconProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscIEOpaque: + offset = sizeof(tDot11fIEWscIEOpaque); + byteCount = ((tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEWscIEOpaque *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeWscProbeReq: + offset = sizeof(tDot11fIEWscProbeReq); + status |= + dot11f_get_packed_ie_wsc_probe_req( + pCtx, (tDot11fIEWscProbeReq *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscProbeRes: + offset = sizeof(tDot11fIEWscProbeRes); + status |= + dot11f_get_packed_ie_wsc_probe_res( + pCtx, (tDot11fIEWscProbeRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeWscReassocRes: + offset = sizeof(tDot11fIEWscReassocRes); + status |= + dot11f_get_packed_ie_wsc_reassoc_res( + pCtx, (tDot11fIEWscReassocRes *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeaddba_extn_element: + offset = sizeof(tDot11fIEaddba_extn_element); + byteCount = 1; + pIePresent = ((tDot11fIEaddba_extn_element *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIebss_color_change: + offset = sizeof(tDot11fIEbss_color_change); + byteCount = 2; + pIePresent = ((tDot11fIEbss_color_change *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIebss_max_idle_period: + offset = sizeof(tDot11fIEbss_max_idle_period); + byteCount = 3; + pIePresent = ((tDot11fIEbss_max_idle_period *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIedescriptor_element: + offset = sizeof(tDot11fIEdescriptor_element); + status |= + dot11f_get_packed_ie_descriptor_element( + pCtx, (tDot11fIEdescriptor_element *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIedh_parameter_element: + offset = sizeof(tDot11fIEdh_parameter_element); + byteCount = ((tDot11fIEdh_parameter_element *) + (pFrm + pIe->offset + offset * i))-> + num_public_key + 2; + pIePresent = ((tDot11fIEdh_parameter_element *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeeht_cap: + offset = sizeof(tDot11fIEeht_cap); + status |= + dot11f_get_packed_ie_eht_cap( + pCtx, (tDot11fIEeht_cap *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeeht_op: + offset = sizeof(tDot11fIEeht_op); + byteCount = ((tDot11fIEeht_op *) + (pFrm + pIe->offset + offset * i))-> + disabled_sub_chan_bitmap_present * 2 + 8; + pIePresent = ((tDot11fIEeht_op *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeesp_information: + offset = sizeof(tDot11fIEesp_information); + byteCount = ((tDot11fIEesp_information *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEesp_information *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeext_chan_switch_ann: + offset = sizeof(tDot11fIEext_chan_switch_ann); + byteCount = 4; + pIePresent = ((tDot11fIEext_chan_switch_ann *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_assoc_delay_info: + offset = sizeof(tDot11fIEfils_assoc_delay_info); + byteCount = 1; + pIePresent = ((tDot11fIEfils_assoc_delay_info *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_hlp_container: + offset = sizeof(tDot11fIEfils_hlp_container); + byteCount = ((tDot11fIEfils_hlp_container *) + (pFrm + pIe->offset + offset * i))-> + num_hlp_packet + 12; + pIePresent = ((tDot11fIEfils_hlp_container *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_indication: + offset = sizeof(tDot11fIEfils_indication); + byteCount = ((tDot11fIEfils_indication *) + (pFrm + pIe->offset + offset * i))-> + num_variable_data + 2; + pIePresent = ((tDot11fIEfils_indication *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_kde: + offset = sizeof(tDot11fIEfils_kde); + byteCount = ((tDot11fIEfils_kde *) + (pFrm + pIe->offset + offset * i))-> + num_kde_list + 8; + pIePresent = ((tDot11fIEfils_kde *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_key_confirmation: + offset = sizeof(tDot11fIEfils_key_confirmation); + byteCount = ((tDot11fIEfils_key_confirmation *) + (pFrm + pIe->offset + offset * i))-> + num_key_auth; + pIePresent = ((tDot11fIEfils_key_confirmation *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_nonce: + offset = sizeof(tDot11fIEfils_nonce); + byteCount = 16; + pIePresent = ((tDot11fIEfils_nonce *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_public_key: + offset = sizeof(tDot11fIEfils_public_key); + byteCount = ((tDot11fIEfils_public_key *) + (pFrm + pIe->offset + offset * i))-> + num_public_key + 1; + pIePresent = ((tDot11fIEfils_public_key *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_session: + offset = sizeof(tDot11fIEfils_session); + byteCount = 8; + pIePresent = ((tDot11fIEfils_session *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefils_wrapped_data: + offset = sizeof(tDot11fIEfils_wrapped_data); + byteCount = ((tDot11fIEfils_wrapped_data *) + (pFrm + pIe->offset + offset * i))-> + num_wrapped_data; + pIePresent = ((tDot11fIEfils_wrapped_data *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIefragment_ie: + offset = sizeof(tDot11fIEfragment_ie); + byteCount = ((tDot11fIEfragment_ie *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEfragment_ie *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIehe_6ghz_band_cap: + offset = sizeof(tDot11fIEhe_6ghz_band_cap); + byteCount = 2; + pIePresent = ((tDot11fIEhe_6ghz_band_cap *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIehe_cap: + offset = sizeof(tDot11fIEhe_cap); + status |= + dot11f_get_packed_ie_he_cap( + pCtx, (tDot11fIEhe_cap *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIehe_op: + offset = sizeof(tDot11fIEhe_op); + status |= + dot11f_get_packed_ie_he_op( + pCtx, (tDot11fIEhe_op *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIehs20vendor_ie: + offset = sizeof(tDot11fIEhs20vendor_ie); + status |= + dot11f_get_packed_ie_hs20vendor_ie( + pCtx, (tDot11fIEhs20vendor_ie *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeht2040_bss_coexistence: + offset = sizeof(tDot11fIEht2040_bss_coexistence); + byteCount = 1; + pIePresent = ((tDot11fIEht2040_bss_coexistence *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeht2040_bss_intolerant_report: + offset = sizeof(tDot11fIEht2040_bss_intolerant_report); + byteCount = ((tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + offset * i))-> + num_channel_list + 1; + pIePresent = ((tDot11fIEht2040_bss_intolerant_report *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIemax_chan_switch_time: + offset = sizeof(tDot11fIEmax_chan_switch_time); + byteCount = 3; + pIePresent = ((tDot11fIEmax_chan_switch_time *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIemlo_ie: + offset = sizeof(tDot11fIEmlo_ie); + byteCount = ((tDot11fIEmlo_ie *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEmlo_ie *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIemu_edca_param_set: + offset = sizeof(tDot11fIEmu_edca_param_set); + byteCount = 13; + pIePresent = ((tDot11fIEmu_edca_param_set *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIenon_inheritance: + offset = sizeof(tDot11fIEnon_inheritance); + byteCount = ((tDot11fIEnon_inheritance *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEnon_inheritance *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeoci: + offset = sizeof(tDot11fIEoci); + byteCount = 3; + pIePresent = ((tDot11fIEoci *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeosen_ie: + offset = sizeof(tDot11fIEosen_ie); + byteCount = ((tDot11fIEosen_ie *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEosen_ie *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIeqcn_ie: + offset = sizeof(tDot11fIEqcn_ie); + status |= + dot11f_get_packed_ie_qcn_ie( + pCtx, (tDot11fIEqcn_ie *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIereduced_neighbor_report: + offset = sizeof(tDot11fIEreduced_neighbor_report); + status |= + dot11f_get_packed_ie_reduced_neighbor_report( + pCtx, (tDot11fIEreduced_neighbor_report *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIeroaming_consortium_sel: + offset = sizeof(tDot11fIEroaming_consortium_sel); + byteCount = ((tDot11fIEroaming_consortium_sel *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEroaming_consortium_sel *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIesec_chan_offset_ele: + offset = sizeof(tDot11fIEsec_chan_offset_ele); + byteCount = 1; + pIePresent = ((tDot11fIEsec_chan_offset_ele *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIespatial_reuse: + offset = sizeof(tDot11fIEspatial_reuse); + status |= + dot11f_get_packed_ie_spatial_reuse( + pCtx, (tDot11fIEspatial_reuse *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + case SigIet2lm_ie: + offset = sizeof(tDot11fIEt2lm_ie); + byteCount = ((tDot11fIEt2lm_ie *) + (pFrm + pIe->offset + offset * i))-> + num_data; + pIePresent = ((tDot11fIEt2lm_ie *) + (pFrm + pIe->offset + offset * i))-> + present; + break; + case SigIevendor_vht_ie: + offset = sizeof(tDot11fIEvendor_vht_ie); + status |= + dot11f_get_packed_ie_vendor_vht_ie( + pCtx, (tDot11fIEvendor_vht_ie *) + (pFrm + pIe->offset + offset * i), + pnNeeded); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the IE signature %d; this is most l" + "ikely a bug in 'framesc'.\n"), pIe->sig); + return DOT11F_INTERNAL_ERROR; + } /*End of switch Case*/ + + if (byteCount && pIePresent) + *pnNeeded += byteCount; + } /*End of for loop*/ + } + ++pIe; + } + return status; + +} + +static uint32_t get_packed_size_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pFrm, + uint32_t *pnNeeded, + const tTLVDefn TLVs[]) +{ + const tTLVDefn *pTlv; + uint32_t status; + tFRAMES_BOOL *pfFound; + uint32_t byteCount = 0; + uint8_t pTlvPresent = 0; + + status = DOT11F_PARSE_SUCCESS; + + pTlv = &(TLVs[0]); + while (0xffff != pTlv->id) { + pfFound = (tFRAMES_BOOL *)(pFrm + pTlv->offset + + pTlv->presenceOffset); + if (*pfFound) { + *pnNeeded += (pTlv->sType + pTlv->sLen); + if (pTlv->pec) + *pnNeeded += 3U; + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + byteCount = 6; + pTlvPresent = ((tDot11fTLVAuthorizedMACs *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestToEnroll: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRequestToEnroll *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVersion2: + byteCount = 1; + pTlvPresent = ((tDot11fTLVVersion2 *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvAPSetupLocked: + byteCount = 1; + pTlvPresent = ((tDot11fTLVAPSetupLocked *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvAssociationState: + byteCount = 2; + pTlvPresent = ((tDot11fTLVAssociationState *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvConfigMethods: + byteCount = 2; + pTlvPresent = ((tDot11fTLVConfigMethods *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvConfigurationError: + byteCount = 2; + pTlvPresent = ((tDot11fTLVConfigurationError *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvDeviceName: + byteCount = ((tDot11fTLVDeviceName *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVDeviceName *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvDevicePasswordID: + byteCount = 2; + pTlvPresent = ((tDot11fTLVDevicePasswordID *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvExtendedListenTiming: + byteCount = 4; + pTlvPresent = ((tDot11fTLVExtendedListenTiming *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvListenChannel: + byteCount = 5; + pTlvPresent = ((tDot11fTLVListenChannel *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvManufacturer: + byteCount = ((tDot11fTLVManufacturer *)(pFrm + pTlv->offset))->num_name; + pTlvPresent = ((tDot11fTLVManufacturer *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvMinorReasonCode: + byteCount = 1; + pTlvPresent = ((tDot11fTLVMinorReasonCode *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvModelName: + byteCount = ((tDot11fTLVModelName *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVModelName *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvModelNumber: + byteCount = ((tDot11fTLVModelNumber *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVModelNumber *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvNoticeOfAbsence: + byteCount = ((tDot11fTLVNoticeOfAbsence *)(pFrm + pTlv->offset))->num_NoADesc+2; + pTlvPresent = ((tDot11fTLVNoticeOfAbsence *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvOperatingChannel: + byteCount = 5; + pTlvPresent = ((tDot11fTLVOperatingChannel *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PCapability: + byteCount = 2; + pTlvPresent = ((tDot11fTLVP2PCapability *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PDeviceId: + byteCount = 6; + pTlvPresent = ((tDot11fTLVP2PDeviceId *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PDeviceInfo: + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pFrm + pTlv->offset, pnNeeded, TLVS_P2PDeviceInfo); + byteCount = 16; + pTlvPresent = ((tDot11fTLVP2PDeviceInfo *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PGroupInfo: + byteCount = ((tDot11fTLVP2PGroupInfo *)(pFrm + pTlv->offset))->num_P2PClientInfoDesc; + pTlvPresent = ((tDot11fTLVP2PGroupInfo *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PStatus: + byteCount = 1; + pTlvPresent = ((tDot11fTLVP2PStatus *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvPrimaryDeviceType: + byteCount = 8; + pTlvPresent = ((tDot11fTLVPrimaryDeviceType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRFBands: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRFBands *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestDeviceType: + byteCount = 8; + pTlvPresent = ((tDot11fTLVRequestDeviceType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvRequestType: + byteCount = 1; + pTlvPresent = ((tDot11fTLVRequestType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvResponseType: + byteCount = 1; + pTlvPresent = ((tDot11fTLVResponseType *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSelectedRegistrar: + byteCount = 1; + pTlvPresent = ((tDot11fTLVSelectedRegistrar *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSelectedRegistrarConfigMethods: + byteCount = 2; + pTlvPresent = ((tDot11fTLVSelectedRegistrarConfigMethods *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvSerialNumber: + byteCount = ((tDot11fTLVSerialNumber *)(pFrm + pTlv->offset))->num_text; + pTlvPresent = ((tDot11fTLVSerialNumber *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvUUID_E: + byteCount = 16; + pTlvPresent = ((tDot11fTLVUUID_E *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvUUID_R: + byteCount = 16; + pTlvPresent = ((tDot11fTLVUUID_R *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVendorExtension: + status = get_packed_size_tlv_core(pCtx, (uint8_t *)pFrm + pTlv->offset, pnNeeded, TLVS_VendorExtension); + byteCount = 3; + pTlvPresent = ((tDot11fTLVVendorExtension *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvVersion: + byteCount = 1; + pTlvPresent = ((tDot11fTLVVersion *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvWPSState: + byteCount = 1; + pTlvPresent = ((tDot11fTLVWPSState *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvassoc_disallowed: + byteCount = 1; + pTlvPresent = ((tDot11fTLVassoc_disallowed *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvassoc_retry_delay: + byteCount = 2; + pTlvPresent = ((tDot11fTLVassoc_retry_delay *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvcellular_data_cap: + byteCount = 1; + pTlvPresent = ((tDot11fTLVcellular_data_cap *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvcellular_data_con_pref: + byteCount = 1; + pTlvPresent = ((tDot11fTLVcellular_data_con_pref *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvecsa_target_tsf_info_attr: + byteCount = 9; + pTlvPresent = ((tDot11fTLVecsa_target_tsf_info_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvedca_pifs_param_attr: + byteCount = ((tDot11fTLVedca_pifs_param_attr *)(pFrm + pTlv->offset))->num_data+1; + pTlvPresent = ((tDot11fTLVedca_pifs_param_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvhe_2xltf_160mhz_supp: + byteCount = 1; + pTlvPresent = ((tDot11fTLVhe_2xltf_160mhz_supp *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvhe_400ns_sgi_attr: + byteCount = 3; + pTlvPresent = ((tDot11fTLVhe_400ns_sgi_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvhe_dl_mumimo_attr: + byteCount = 1; + pTlvPresent = ((tDot11fTLVhe_dl_mumimo_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvhe_dl_ofdma_attr: + byteCount = 1; + pTlvPresent = ((tDot11fTLVhe_dl_ofdma_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvhe_mcs13_attr: + byteCount = 2; + pTlvPresent = ((tDot11fTLVhe_mcs13_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvmbo_ap_cap: + byteCount = 1; + pTlvPresent = ((tDot11fTLVmbo_ap_cap *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvnon_prefferd_chan_rep: + byteCount = ((tDot11fTLVnon_prefferd_chan_rep *)(pFrm + pTlv->offset))->num_channel_report+1; + pTlvPresent = ((tDot11fTLVnon_prefferd_chan_rep *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvoce_cap: + byteCount = 1; + pTlvPresent = ((tDot11fTLVoce_cap *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvqcn_version: + byteCount = 2; + pTlvPresent = ((tDot11fTLVqcn_version *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvreduced_wan_metrics: + byteCount = 1; + pTlvPresent = ((tDot11fTLVreduced_wan_metrics *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvrssi_assoc_rej: + byteCount = 2; + pTlvPresent = ((tDot11fTLVrssi_assoc_rej *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvtrans_reasonp_attr: + byteCount = 1; + pTlvPresent = ((tDot11fTLVtrans_reasonp_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvtrans_rejectp_attr: + byteCount = 1; + pTlvPresent = ((tDot11fTLVtrans_rejectp_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvtransition_reason: + byteCount = 1; + pTlvPresent = ((tDot11fTLVtransition_reason *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvtransition_reject_reason: + byteCount = 1; + pTlvPresent = ((tDot11fTLVtransition_reject_reason *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvvht_mcs11_attr: + byteCount = 1; + pTlvPresent = ((tDot11fTLVvht_mcs11_attr *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PInterface: + byteCount = 6; + pTlvPresent = ((tDot11fTLVP2PInterface *) + (pFrm + pTlv->offset))->present; + break; + case SigTlvP2PManageability: + byteCount = 1; + pTlvPresent = ((tDot11fTLVP2PManageability *) + (pFrm + pTlv->offset))->present; + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the TLV signature %d; this is most l" + "ikely a bug in 'framesc'.\n"), pTlv->sig); + return DOT11F_INTERNAL_ERROR; + } + if (pTlvPresent) { + *pnNeeded += byteCount; + } + } + ++pTlv; + } + return status; +} +void dot11f_pack_ff_aid(tpAniSirGlobal pCtx, + tDot11fFfAID *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->associd, 0); + (void)pCtx; +} /* End dot11f_pack_ff_aid. */ + +void dot11f_pack_ff_action(tpAniSirGlobal pCtx, + tDot11fFfAction *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->action; + (void)pCtx; +} /* End dot11f_pack_ff_action. */ + +void dot11f_pack_ff_auth_algo(tpAniSirGlobal pCtx, + tDot11fFfAuthAlgo *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->algo, 0); + (void)pCtx; +} /* End dot11f_pack_ff_auth_algo. */ + +void dot11f_pack_ff_auth_seq_no(tpAniSirGlobal pCtx, + tDot11fFfAuthSeqNo *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->no, 0); + (void)pCtx; +} /* End dot11f_pack_ff_auth_seq_no. */ + +void dot11f_pack_ff_beacon_interval(tpAniSirGlobal pCtx, + tDot11fFfBeaconInterval *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->interval, 0); + (void)pCtx; +} /* End dot11f_pack_ff_beacon_interval. */ + +void dot11f_pack_ff_capabilities(tpAniSirGlobal pCtx, + tDot11fFfCapabilities *pSrc, + uint8_t *pBuf) +{ + uint16_t tmp120__; + tmp120__ = 0U; + tmp120__ |= (pSrc->ess << 0); + tmp120__ |= (pSrc->ibss << 1); + tmp120__ |= (pSrc->cfPollable << 2); + tmp120__ |= (pSrc->cfPollReq << 3); + tmp120__ |= (pSrc->privacy << 4); + tmp120__ |= (pSrc->shortPreamble << 5); + tmp120__ |= (pSrc->criticalUpdateFlag << 6); + tmp120__ |= (pSrc->channelAgility << 7); + tmp120__ |= (pSrc->spectrumMgt << 8); + tmp120__ |= (pSrc->qos << 9); + tmp120__ |= (pSrc->shortSlotTime << 10); + tmp120__ |= (pSrc->apsd << 11); + tmp120__ |= (pSrc->rrm << 12); + tmp120__ |= (pSrc->dsssOfdm << 13); + tmp120__ |= (pSrc->delayedBA << 14); + tmp120__ |= (pSrc->immediateBA << 15); + frameshtons(pCtx, pBuf, tmp120__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_capabilities. */ + +void dot11f_pack_ff_category(tpAniSirGlobal pCtx, + tDot11fFfCategory *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->category; + (void)pCtx; +} /* End dot11f_pack_ff_category. */ + +void dot11f_pack_ff_current_ap_address(tpAniSirGlobal pCtx, + tDot11fFfCurrentAPAddress *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + (void)pCtx; +} /* End dot11f_pack_ff_current_ap_address. */ + +void dot11f_pack_ff_dialog_token(tpAniSirGlobal pCtx, + tDot11fFfDialogToken *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->token; + (void)pCtx; +} /* End dot11f_pack_ff_dialog_token. */ + +void dot11f_pack_ff_link_margin(tpAniSirGlobal pCtx, + tDot11fFfLinkMargin *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->linkMargin; + (void)pCtx; +} /* End dot11f_pack_ff_link_margin. */ + +void dot11f_pack_ff_listen_interval(tpAniSirGlobal pCtx, + tDot11fFfListenInterval *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->interval, 0); + (void)pCtx; +} /* End dot11f_pack_ff_listen_interval. */ + +void dot11f_pack_ff_max_tx_power(tpAniSirGlobal pCtx, + tDot11fFfMaxTxPower *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->maxTxPower; + (void)pCtx; +} /* End dot11f_pack_ff_max_tx_power. */ + +void dot11f_pack_ff_num_of_repetitions(tpAniSirGlobal pCtx, + tDot11fFfNumOfRepetitions *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->repetitions, 0); + (void)pCtx; +} /* End dot11f_pack_ff_num_of_repetitions. */ + +void dot11f_pack_ff_operating_mode(tpAniSirGlobal pCtx, + tDot11fFfOperatingMode *pSrc, + uint8_t *pBuf) +{ + uint8_t tmp121__; + tmp121__ = 0U; + tmp121__ |= (pSrc->chanWidth << 0); + tmp121__ |= (pSrc->reserved << 2); + tmp121__ |= (pSrc->rxNSS << 4); + tmp121__ |= (pSrc->rxNSSType << 7); + *pBuf = tmp121__; + (void)pCtx; +} /* End dot11f_pack_ff_operating_mode. */ + +void dot11f_pack_ff_rcpi(tpAniSirGlobal pCtx, + tDot11fFfRCPI *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->rcpi; + (void)pCtx; +} /* End dot11f_pack_ff_rcpi. */ + +void dot11f_pack_ff_rsni(tpAniSirGlobal pCtx, + tDot11fFfRSNI *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->rsni; + (void)pCtx; +} /* End dot11f_pack_ff_rsni. */ + +void dot11f_pack_ff_reason(tpAniSirGlobal pCtx, + tDot11fFfReason *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->code, 0); + (void)pCtx; +} /* End dot11f_pack_ff_reason. */ + +void dot11f_pack_ff_rx_antenna_id(tpAniSirGlobal pCtx, + tDot11fFfRxAntennaId *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->antennaId; + (void)pCtx; +} /* End dot11f_pack_ff_rx_antenna_id. */ + +void dot11f_pack_ff_sm_power_mode_set(tpAniSirGlobal pCtx, + tDot11fFfSMPowerModeSet *pSrc, + uint8_t *pBuf) +{ + uint8_t tmp122__; + tmp122__ = 0U; + tmp122__ |= (pSrc->PowerSave_En << 0); + tmp122__ |= (pSrc->Mode << 1); + tmp122__ |= (pSrc->reserved << 2); + *pBuf = tmp122__; + (void)pCtx; +} /* End dot11f_pack_ff_sm_power_mode_set. */ + +void dot11f_pack_ff_status(tpAniSirGlobal pCtx, + tDot11fFfStatus *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->status, 0); + (void)pCtx; +} /* End dot11f_pack_ff_status. */ + +void dot11f_pack_ff_status_code(tpAniSirGlobal pCtx, + tDot11fFfStatusCode *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->statusCode; + (void)pCtx; +} /* End dot11f_pack_ff_status_code. */ + +void dot11f_pack_ff_tpc_ele_id(tpAniSirGlobal pCtx, + tDot11fFfTPCEleID *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->TPCId; + (void)pCtx; +} /* End dot11f_pack_ff_tpc_ele_id. */ + +void dot11f_pack_ff_tpc_ele_len(tpAniSirGlobal pCtx, + tDot11fFfTPCEleLen *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->TPCLen; + (void)pCtx; +} /* End dot11f_pack_ff_tpc_ele_len. */ + +void dot11f_pack_ff_ts_info(tpAniSirGlobal pCtx, + tDot11fFfTSInfo *pSrc, + uint8_t *pBuf) +{ + uint32_t tmp123__; + tmp123__ = 0U; + tmp123__ |= (pSrc->traffic_type << 0); + tmp123__ |= (pSrc->tsid << 1); + tmp123__ |= (pSrc->direction << 5); + tmp123__ |= (pSrc->access_policy << 7); + tmp123__ |= (pSrc->aggregation << 9); + tmp123__ |= (pSrc->psb << 10); + tmp123__ |= (pSrc->user_priority << 11); + tmp123__ |= (pSrc->tsinfo_ack_pol << 14); + tmp123__ |= (pSrc->schedule << 16); + tmp123__ |= (pSrc->unused << 17); + frameshtonl(pCtx, pBuf, tmp123__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ts_info. */ + +void dot11f_pack_ff_time_stamp(tpAniSirGlobal pCtx, + tDot11fFfTimeStamp *pSrc, + uint8_t *pBuf) +{ + frameshtonq(pCtx, pBuf, pSrc->timestamp, 0); + (void)pCtx; +} /* End dot11f_pack_ff_time_stamp. */ + +void dot11f_pack_ff_transaction_id(tpAniSirGlobal pCtx, + tDot11fFfTransactionId *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->transId, 2); + (void)pCtx; +} /* End dot11f_pack_ff_transaction_id. */ + +void dot11f_pack_ff_tx_antenna_id(tpAniSirGlobal pCtx, + tDot11fFfTxAntennaId *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->antennaId; + (void)pCtx; +} /* End dot11f_pack_ff_tx_antenna_id. */ + +void dot11f_pack_ff_tx_power(tpAniSirGlobal pCtx, + tDot11fFfTxPower *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->txPower; + (void)pCtx; +} /* End dot11f_pack_ff_tx_power. */ + +void dot11f_pack_ff_vht_membership_status_array(tpAniSirGlobal pCtx, + tDot11fFfVhtMembershipStatusArray *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->membershipStatusArray, 8); + (void)pCtx; +} /* End dot11f_pack_ff_vht_membership_status_array. */ + +void dot11f_pack_ff_vht_user_position_array(tpAniSirGlobal pCtx, + tDot11fFfVhtUserPositionArray *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->userPositionArray, 16); + (void)pCtx; +} /* End dot11f_pack_ff_vht_user_position_array. */ + +void dot11f_pack_ff_addba_param_set(tpAniSirGlobal pCtx, + tDot11fFfaddba_param_set *pSrc, + uint8_t *pBuf) +{ + uint16_t tmp124__; + tmp124__ = 0U; + tmp124__ |= (pSrc->amsdu_supp << 0); + tmp124__ |= (pSrc->policy << 1); + tmp124__ |= (pSrc->tid << 2); + tmp124__ |= (pSrc->buff_size << 6); + frameshtons(pCtx, pBuf, tmp124__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_addba_param_set. */ + +void dot11f_pack_ff_ba_start_seq_ctrl(tpAniSirGlobal pCtx, + tDot11fFfba_start_seq_ctrl *pSrc, + uint8_t *pBuf) +{ + uint16_t tmp125__; + tmp125__ = 0U; + tmp125__ |= (pSrc->frag_number << 0); + tmp125__ |= (pSrc->ssn << 4); + frameshtons(pCtx, pBuf, tmp125__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ba_start_seq_ctrl. */ + +void dot11f_pack_ff_ba_timeout(tpAniSirGlobal pCtx, + tDot11fFfba_timeout *pSrc, + uint8_t *pBuf) +{ + frameshtons(pCtx, pBuf, pSrc->timeout, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ba_timeout. */ + +void dot11f_pack_ff_delba_param_set(tpAniSirGlobal pCtx, + tDot11fFfdelba_param_set *pSrc, + uint8_t *pBuf) +{ + uint16_t tmp126__; + tmp126__ = 0U; + tmp126__ |= (pSrc->reserved << 0); + tmp126__ |= (pSrc->initiator << 11); + tmp126__ |= (pSrc->tid << 12); + frameshtons(pCtx, pBuf, tmp126__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_delba_param_set. */ + +void dot11f_pack_ff_ext_chan_switch_ann_action(tpAniSirGlobal pCtx, + tDot11fFfext_chan_switch_ann_action *pSrc, + uint8_t *pBuf) +{ + uint32_t tmp127__; + tmp127__ = 0U; + tmp127__ |= (pSrc->switch_mode << 0); + tmp127__ |= (pSrc->op_class << 8); + tmp127__ |= (pSrc->new_channel << 16); + tmp127__ |= (pSrc->switch_count << 24); + frameshtonl(pCtx, pBuf, tmp127__, 0); + (void)pCtx; +} /* End dot11f_pack_ff_ext_chan_switch_ann_action. */ + +void dot11f_pack_ff_p2p_action_oui(tpAniSirGlobal pCtx, + tDot11fFfp2p_action_oui *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui_data, 4); + (void)pCtx; +} /* End dot11f_pack_ff_p2p_action_oui. */ + +void dot11f_pack_ff_p2p_action_subtype(tpAniSirGlobal pCtx, + tDot11fFfp2p_action_subtype *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->subtype; + (void)pCtx; +} /* End dot11f_pack_ff_p2p_action_subtype. */ + +void dot11f_pack_ff_vendor_action_subtype(tpAniSirGlobal pCtx, + tDot11fFfvendor_action_subtype *pSrc, + uint8_t *pBuf) +{ + *pBuf = pSrc->subtype; + (void)pCtx; +} /* End dot11f_pack_ff_vendor_action_subtype. */ + +void dot11f_pack_ff_vendor_oui(tpAniSirGlobal pCtx, + tDot11fFfvendor_oui *pSrc, + uint8_t *pBuf) +{ + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui_data, 3); + (void)pCtx; +} /* End dot11f_pack_ff_vendor_oui. */ + +uint32_t dot11f_pack_tlv_authorized_ma_cs(tpAniSirGlobal pCtx, + tDot11fTLVAuthorizedMACs *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->mac, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_authorized_ma_cs. */ + +uint32_t dot11f_pack_tlv_request_to_enroll(tpAniSirGlobal pCtx, + tDot11fTLVRequestToEnroll *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->req; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_to_enroll. */ + +uint32_t dot11f_pack_tlv_version2(tpAniSirGlobal pCtx, + tDot11fTLVVersion2 *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp128__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp128__ = 0U; + tmp128__ |= (pSrc->minor << 0); + tmp128__ |= (pSrc->major << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp128__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_version2. */ + +uint32_t dot11f_pack_tlv_ap_setup_locked(tpAniSirGlobal pCtx, + tDot11fTLVAPSetupLocked *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4183, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->fLocked; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_ap_setup_locked. */ + +uint32_t dot11f_pack_tlv_association_state(tpAniSirGlobal pCtx, + tDot11fTLVAssociationState *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4098, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->state, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_association_state. */ + +uint32_t dot11f_pack_tlv_config_methods(tpAniSirGlobal pCtx, + tDot11fTLVConfigMethods *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4104, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->methods, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_config_methods. */ + +uint32_t dot11f_pack_tlv_configuration_error(tpAniSirGlobal pCtx, + tDot11fTLVConfigurationError *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4105, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->error, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_configuration_error. */ + +uint32_t dot11f_pack_tlv_device_name(tpAniSirGlobal pCtx, + tDot11fTLVDeviceName *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4113, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_device_name. */ + +uint32_t dot11f_pack_tlv_device_password_id(tpAniSirGlobal pCtx, + tDot11fTLVDevicePasswordID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4114, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->id, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_device_password_id. */ + +uint32_t dot11f_pack_tlv_extended_listen_timing(tpAniSirGlobal pCtx, + tDot11fTLVExtendedListenTiming *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 7; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 8; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->availibilityPeriod, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->availibilityInterval, 0); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_extended_listen_timing. */ + +uint32_t dot11f_pack_tlv_listen_channel(tpAniSirGlobal pCtx, + tDot11fTLVListenChannel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 6; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryString, 3); + *pnConsumed += 3; + pBuf += 3; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_listen_channel. */ + +uint32_t dot11f_pack_tlv_manufacturer(tpAniSirGlobal pCtx, + tDot11fTLVManufacturer *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_name + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4129, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->name), pSrc->num_name); + *pnConsumed += pSrc->num_name; + pBuf += pSrc->num_name; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_manufacturer. */ + +uint32_t dot11f_pack_tlv_minor_reason_code(tpAniSirGlobal pCtx, + tDot11fTLVMinorReasonCode *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->minorReasonCode; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_minor_reason_code. */ + +uint32_t dot11f_pack_tlv_model_name(tpAniSirGlobal pCtx, + tDot11fTLVModelName *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4131, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_model_name. */ + +uint32_t dot11f_pack_tlv_model_number(tpAniSirGlobal pCtx, + tDot11fTLVModelNumber *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4132, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_model_number. */ + +uint32_t dot11f_pack_tlv_notice_of_absence(tpAniSirGlobal pCtx, + tDot11fTLVNoticeOfAbsence *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_NoADesc + 5) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 12; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->index; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->CTSWindowOppPS; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->NoADesc), pSrc->num_NoADesc); + *pnConsumed += pSrc->num_NoADesc; + pBuf += pSrc->num_NoADesc; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_notice_of_absence. */ + +uint32_t dot11f_pack_tlv_operating_channel(tpAniSirGlobal pCtx, + tDot11fTLVOperatingChannel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 17; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryString, 3); + *pnConsumed += 3; + pBuf += 3; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_operating_channel. */ + +uint32_t dot11f_pack_tlv_p2_p_capability(tpAniSirGlobal pCtx, + tDot11fTLVP2PCapability *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 2; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->deviceCapability; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->groupCapability; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_capability. */ + +uint32_t dot11f_pack_tlv_p2_p_device_id(tpAniSirGlobal pCtx, + tDot11fTLVP2PDeviceId *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 9; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_device_id. */ + +uint32_t dot11f_pack_tlv_p2_p_device_info(tpAniSirGlobal pCtx, + tDot11fTLVP2PDeviceInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + uint32_t idx = 0; + nNeeded += 19; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 13; + pBuf += 1; nBuf -= 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->configMethod, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->primaryDeviceType, 8); + *pnConsumed += 8; + pBuf += 8; + status |= pack_tlv_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + TLVS_P2PDeviceInfo, &idx); + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return status; +} /* End dot11f_pack_tlv_p2_p_device_info. */ + +uint32_t dot11f_pack_tlv_p2_p_group_info(tpAniSirGlobal pCtx, + tDot11fTLVP2PGroupInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_P2PClientInfoDesc + 3) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 14; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->P2PClientInfoDesc), pSrc->num_P2PClientInfoDesc); + *pnConsumed += pSrc->num_P2PClientInfoDesc; + pBuf += pSrc->num_P2PClientInfoDesc; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_group_info. */ + +uint32_t dot11f_pack_tlv_p2_p_status(tpAniSirGlobal pCtx, + tDot11fTLVP2PStatus *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 0; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->status; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_status. */ + +uint32_t dot11f_pack_tlv_primary_device_type(tpAniSirGlobal pCtx, + tDot11fTLVPrimaryDeviceType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 12; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4180, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->primary_category, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->sub_category, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_primary_device_type. */ + +uint32_t dot11f_pack_tlv_rf_bands(tpAniSirGlobal pCtx, + tDot11fTLVRFBands *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4156, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->bands; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_rf_bands. */ + +uint32_t dot11f_pack_tlv_request_device_type(tpAniSirGlobal pCtx, + tDot11fTLVRequestDeviceType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 12; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4202, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->primary_category, 1); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->oui, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->sub_category, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_device_type. */ + +uint32_t dot11f_pack_tlv_request_type(tpAniSirGlobal pCtx, + tDot11fTLVRequestType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4154, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->reqType; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_request_type. */ + +uint32_t dot11f_pack_tlv_response_type(tpAniSirGlobal pCtx, + tDot11fTLVResponseType *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4155, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->resType; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_response_type. */ + +uint32_t dot11f_pack_tlv_selected_registrar(tpAniSirGlobal pCtx, + tDot11fTLVSelectedRegistrar *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4161, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->selected; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_selected_registrar. */ + +uint32_t dot11f_pack_tlv_selected_registrar_config_methods(tpAniSirGlobal pCtx, + tDot11fTLVSelectedRegistrarConfigMethods *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4179, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + frameshtons(pCtx, pBuf, pSrc->methods, 1); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_selected_registrar_config_methods. */ + +uint32_t dot11f_pack_tlv_serial_number(tpAniSirGlobal pCtx, + tDot11fTLVSerialNumber *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_text + 4) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4162, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + pBuf += pSrc->num_text; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_serial_number. */ + +uint32_t dot11f_pack_tlv_uuid_e(tpAniSirGlobal pCtx, + tDot11fTLVUUID_E *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 20; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4167, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->uuid, 16); + *pnConsumed += 16; + pBuf += 16; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_uuid_e. */ + +uint32_t dot11f_pack_tlv_uuid_r(tpAniSirGlobal pCtx, + tDot11fTLVUUID_R *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 20; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4168, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->uuid, 16); + *pnConsumed += 16; + pBuf += 16; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_uuid_r. */ + +uint32_t dot11f_pack_tlv_vendor_extension(tpAniSirGlobal pCtx, + tDot11fTLVVendorExtension *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + uint32_t idx = 0; + nNeeded += 7; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4169, 1); + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; nBuf -= 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->vendorId, 3); + *pnConsumed += 3; + pBuf += 3; + status |= pack_tlv_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + TLVS_VendorExtension, &idx); + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return status; +} /* End dot11f_pack_tlv_vendor_extension. */ + +uint32_t dot11f_pack_tlv_version(tpAniSirGlobal pCtx, + tDot11fTLVVersion *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp129__; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4170, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + tmp129__ = 0U; + tmp129__ |= (pSrc->minor << 0); + tmp129__ |= (pSrc->major << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp129__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_version. */ + +uint32_t dot11f_pack_tlv_wps_state(tpAniSirGlobal pCtx, + tDot11fTLVWPSState *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + frameshtons(pCtx, pBuf, 4164, 1); + pBuf += 2; *pnConsumed += 2; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->state; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 4, 1); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_wps_state. */ + +uint32_t dot11f_pack_tlv_assoc_disallowed(tpAniSirGlobal pCtx, + tDot11fTLVassoc_disallowed *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 4; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->reason_code; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_assoc_disallowed. */ + +uint32_t dot11f_pack_tlv_assoc_retry_delay(tpAniSirGlobal pCtx, + tDot11fTLVassoc_retry_delay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 8; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + frameshtons(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 2; + pBuf += 2; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_assoc_retry_delay. */ + +uint32_t dot11f_pack_tlv_cellular_data_cap(tpAniSirGlobal pCtx, + tDot11fTLVcellular_data_cap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->cellular_connectivity; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_cellular_data_cap. */ + +uint32_t dot11f_pack_tlv_cellular_data_con_pref(tpAniSirGlobal pCtx, + tDot11fTLVcellular_data_con_pref *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 5; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->cellular_preference; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_cellular_data_con_pref. */ + +uint32_t dot11f_pack_tlv_ecsa_target_tsf_info_attr(tpAniSirGlobal pCtx, + tDot11fTLVecsa_target_tsf_info_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 11; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 14; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->twt_ch_sw_mode; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->target_tsf, 0); + *pnConsumed += 8; + pBuf += 8; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_ecsa_target_tsf_info_attr. */ + +uint32_t dot11f_pack_tlv_edca_pifs_param_attr(tpAniSirGlobal pCtx, + tDot11fTLVedca_pifs_param_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_data + 3) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 13; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->edca_param_type; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + pBuf += pSrc->num_data; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_edca_pifs_param_attr. */ + +uint32_t dot11f_pack_tlv_he_2xltf_160mhz_supp(tpAniSirGlobal pCtx, + tDot11fTLVhe_2xltf_160mhz_supp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 4; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->he_2xltf_160MHz_supp; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_he_2xltf_160mhz_supp. */ + +uint32_t dot11f_pack_tlv_he_400ns_sgi_attr(tpAniSirGlobal pCtx, + tDot11fTLVhe_400ns_sgi_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 3; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->he_ltf1x_400ns_sgi; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->he_ltf2x_400ns_sgi; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->he_ltf4x_400ns_sgi; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_he_400ns_sgi_attr. */ + +uint32_t dot11f_pack_tlv_he_dl_mumimo_attr(tpAniSirGlobal pCtx, + tDot11fTLVhe_dl_mumimo_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 8; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->he_dl_mumimo_supp; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_he_dl_mumimo_attr. */ + +uint32_t dot11f_pack_tlv_he_dl_ofdma_attr(tpAniSirGlobal pCtx, + tDot11fTLVhe_dl_ofdma_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 5; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->he_dl_ofdma_supp; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_he_dl_ofdma_attr. */ + +uint32_t dot11f_pack_tlv_he_mcs13_attr(tpAniSirGlobal pCtx, + tDot11fTLVhe_mcs13_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 9; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->he_mcs_12_13_supp_80; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->he_mcs_12_13_supp_160; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_he_mcs13_attr. */ + +uint32_t dot11f_pack_tlv_mbo_ap_cap(tpAniSirGlobal pCtx, + tDot11fTLVmbo_ap_cap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->mbo_cap_ind; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_mbo_ap_cap. */ + +uint32_t dot11f_pack_tlv_non_prefferd_chan_rep(tpAniSirGlobal pCtx, + tDot11fTLVnon_prefferd_chan_rep *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channel_report + 3) ; + + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 2; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->oper_class; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channel_report), pSrc->num_channel_report); + *pnConsumed += pSrc->num_channel_report; + pBuf += pSrc->num_channel_report; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_non_prefferd_chan_rep. */ + +uint32_t dot11f_pack_tlv_oce_cap(tpAniSirGlobal pCtx, + tDot11fTLVoce_cap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp130__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 101; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp130__ = 0U; + tmp130__ |= (pSrc->oce_release << 0); + tmp130__ |= (pSrc->is_sta_cfon << 3); + tmp130__ |= (pSrc->non_oce_ap_present << 4); + tmp130__ |= (pSrc->reserved << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp130__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_oce_cap. */ + +uint32_t dot11f_pack_tlv_qcn_version(tpAniSirGlobal pCtx, + tDot11fTLVqcn_version *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 1; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->sub_version; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_qcn_version. */ + +uint32_t dot11f_pack_tlv_reduced_wan_metrics(tpAniSirGlobal pCtx, + tDot11fTLVreduced_wan_metrics *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp131__; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 103; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + tmp131__ = 0U; + tmp131__ |= (pSrc->downlink_av_cap << 0); + tmp131__ |= (pSrc->uplink_av_cap << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp131__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_reduced_wan_metrics. */ + +uint32_t dot11f_pack_tlv_rssi_assoc_rej(tpAniSirGlobal pCtx, + tDot11fTLVrssi_assoc_rej *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 102; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->delta_rssi; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->retry_delay; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_rssi_assoc_rej. */ + +uint32_t dot11f_pack_tlv_trans_reasonp_attr(tpAniSirGlobal pCtx, + tDot11fTLVtrans_reasonp_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 6; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->transition_reasonp; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_trans_reasonp_attr. */ + +uint32_t dot11f_pack_tlv_trans_rejectp_attr(tpAniSirGlobal pCtx, + tDot11fTLVtrans_rejectp_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 7; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->transition_rejp; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_trans_rejectp_attr. */ + +uint32_t dot11f_pack_tlv_transition_reason(tpAniSirGlobal pCtx, + tDot11fTLVtransition_reason *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 6; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->transition_reason_code; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_transition_reason. */ + +uint32_t dot11f_pack_tlv_transition_reject_reason(tpAniSirGlobal pCtx, + tDot11fTLVtransition_reject_reason *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 7; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->transition_reject_code; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_transition_reject_reason. */ + +uint32_t dot11f_pack_tlv_vht_mcs11_attr(tpAniSirGlobal pCtx, + tDot11fTLVvht_mcs11_attr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 2; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 1; *pnConsumed += 1; + *pBuf = pSrc->vht_mcs_10_11_supp; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + *pTlvLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_vht_mcs11_attr. */ + +uint32_t dot11f_pack_tlv_p2_p_interface(tpAniSirGlobal pCtx, + tDot11fTLVP2PInterface *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 9; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 16; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->P2PDeviceAddress, 6); + *pnConsumed += 6; + pBuf += 6; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_interface. */ + +uint32_t dot11f_pack_tlv_p2_p_manageability(tpAniSirGlobal pCtx, + tDot11fTLVP2PManageability *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pTlvLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + while (pSrc->present) { + *pBuf = 10; + pBuf += 1; *pnConsumed += 1; + pTlvLen = pBuf; + pBuf += 2; *pnConsumed += 2; + *pBuf = pSrc->manageability; + *pnConsumed += 1; + pBuf += 1; + break; + } + (void)pCtx; + if (pTlvLen) { + frameshtons(pCtx, pTlvLen, *pnConsumed - nConsumedOnEntry - 3, 0); + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_tlv_p2_p_manageability. */ + +uint32_t dot11f_pack_ie_gtk(tpAniSirGlobal pCtx, + tDot11fIEGTK *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp132__; + nNeeded += (pSrc->num_key + 11); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp132__ = 0U; + tmp132__ |= (pSrc->keyId << 0); + tmp132__ |= (pSrc->reserved << 2); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp132__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + *pBuf = pSrc->keyLength; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RSC, 8); + *pnConsumed += 8; + pBuf += 8; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->key), pSrc->num_key); + *pnConsumed += pSrc->num_key; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_gtk. */ + +uint32_t dot11f_pack_ie_igtk(tpAniSirGlobal pCtx, + tDot11fIEIGTK *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 33; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->keyID, 2); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->IPN, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->keyLength; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->key, 24); + *pnConsumed += 24; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_igtk. */ + +uint32_t dot11f_pack_ie_r0_kh_id(tpAniSirGlobal pCtx, + tDot11fIER0KH_ID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_PMK_R0_ID; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->PMK_R0_ID), pSrc->num_PMK_R0_ID); + *pnConsumed += pSrc->num_PMK_R0_ID; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_r0_kh_id. */ + +uint32_t dot11f_pack_ie_r1_kh_id(tpAniSirGlobal pCtx, + tDot11fIER1KH_ID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->PMK_R1_ID, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_r1_kh_id. */ + +uint32_t dot11f_pack_ie_ap_channel_report(tpAniSirGlobal pCtx, + tDot11fIEAPChannelReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channelList + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 51; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channelList), pSrc->num_channelList); + *pnConsumed += pSrc->num_channelList; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ap_channel_report. */ + +uint32_t dot11f_pack_ie_bcn_reporting_detail(tpAniSirGlobal pCtx, + tDot11fIEBcnReportingDetail *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->reportingDetail; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bcn_reporting_detail. */ + +uint32_t dot11f_pack_ie_beacon_report_frm_body(tpAniSirGlobal pCtx, + tDot11fIEBeaconReportFrmBody *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_reportedFields; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->reportedFields), pSrc->num_reportedFields); + *pnConsumed += pSrc->num_reportedFields; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_beacon_report_frm_body. */ + +uint32_t dot11f_pack_ie_condensed_country_str(tpAniSirGlobal pCtx, + tDot11fIECondensedCountryStr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->countryStr, 2); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_condensed_country_str. */ + +uint32_t dot11f_pack_ie_ExtRequestedInfo(tpAniSirGlobal pCtx, + tDot11fIEExtRequestedInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_req_element_id_ext + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 11; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->req_element_id; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->req_element_id_ext), pSrc->num_req_element_id_ext); + *pnConsumed += pSrc->num_req_element_id_ext; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ExtRequestedInfo. */ + +uint32_t dot11f_pack_ie_measurement_pilot(tpAniSirGlobal pCtx, + tDot11fIEMeasurementPilot *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vendorSpecific + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 66; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->measurementPilot; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vendorSpecific), pSrc->num_vendorSpecific); + *pnConsumed += pSrc->num_vendorSpecific; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_measurement_pilot. */ + +uint32_t dot11f_pack_ie_multi_bssid(tpAniSirGlobal pCtx, + tDot11fIEMultiBssid *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vendorSpecific + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 71; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->maxBSSIDIndicator; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vendorSpecific), pSrc->num_vendorSpecific); + *pnConsumed += pSrc->num_vendorSpecific; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_multi_bssid. */ + +uint32_t dot11f_pack_ie_ric_data(tpAniSirGlobal pCtx, + tDot11fIERICData *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 57; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->Identifier; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->resourceDescCount; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->statusCode, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ric_data. */ + +uint32_t dot11f_pack_ie_ric_descriptor(tpAniSirGlobal pCtx, + tDot11fIERICDescriptor *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_variableData + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 75; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->resourceType; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->variableData), pSrc->num_variableData); + *pnConsumed += pSrc->num_variableData; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ric_descriptor. */ + +uint32_t dot11f_pack_ie_rrm_enabled_cap(tpAniSirGlobal pCtx, + tDot11fIERRMEnabledCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp133__; + uint8_t tmp134__; + uint8_t tmp135__; + uint8_t tmp136__; + uint8_t tmp137__; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 70; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp133__ = 0U; + tmp133__ |= (pSrc->LinkMeasurement << 0); + tmp133__ |= (pSrc->NeighborRpt << 1); + tmp133__ |= (pSrc->parallel << 2); + tmp133__ |= (pSrc->repeated << 3); + tmp133__ |= (pSrc->BeaconPassive << 4); + tmp133__ |= (pSrc->BeaconActive << 5); + tmp133__ |= (pSrc->BeaconTable << 6); + tmp133__ |= (pSrc->BeaconRepCond << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp133__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp134__ = 0U; + tmp134__ |= (pSrc->FrameMeasurement << 0); + tmp134__ |= (pSrc->ChannelLoad << 1); + tmp134__ |= (pSrc->NoiseHistogram << 2); + tmp134__ |= (pSrc->statistics << 3); + tmp134__ |= (pSrc->LCIMeasurement << 4); + tmp134__ |= (pSrc->LCIAzimuth << 5); + tmp134__ |= (pSrc->TCMCapability << 6); + tmp134__ |= (pSrc->triggeredTCM << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp134__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp135__ = 0U; + tmp135__ |= (pSrc->APChanReport << 0); + tmp135__ |= (pSrc->RRMMIBEnabled << 1); + tmp135__ |= (pSrc->operatingChanMax << 2); + tmp135__ |= (pSrc->nonOperatinChanMax << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp135__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp136__ = 0U; + tmp136__ |= (pSrc->MeasurementPilot << 0); + tmp136__ |= (pSrc->MeasurementPilotEnabled << 3); + tmp136__ |= (pSrc->NeighborTSFOffset << 4); + tmp136__ |= (pSrc->RCPIMeasurement << 5); + tmp136__ |= (pSrc->RSNIMeasurement << 6); + tmp136__ |= (pSrc->BssAvgAccessDelay << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp136__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp137__ = 0U; + tmp137__ |= (pSrc->BSSAvailAdmission << 0); + tmp137__ |= (pSrc->AntennaInformation << 1); + tmp137__ |= (pSrc->fine_time_meas_rpt << 2); + tmp137__ |= (pSrc->lci_capability << 3); + tmp137__ |= (pSrc->reserved << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp137__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rrm_enabled_cap. */ + +uint32_t dot11f_pack_ie_requested_info(tpAniSirGlobal pCtx, + tDot11fIERequestedInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_requested_eids; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 10; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->requested_eids), pSrc->num_requested_eids); + *pnConsumed += pSrc->num_requested_eids; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_requested_info. */ + +uint32_t dot11f_pack_ie_ssid(tpAniSirGlobal pCtx, + tDot11fIESSID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_ssid; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 0; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->ssid), pSrc->num_ssid); + *pnConsumed += pSrc->num_ssid; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ssid. */ + +uint32_t dot11f_pack_ie_schedule(tpAniSirGlobal pCtx, + tDot11fIESchedule *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp138__; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 15; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp138__ = 0U; + tmp138__ |= (pSrc->aggregation << 0); + tmp138__ |= (pSrc->tsid << 1); + tmp138__ |= (pSrc->direction << 5); + tmp138__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp138__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_interval, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->max_service_dur, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->spec_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_schedule. */ + +uint32_t dot11f_pack_ie_tclas(tpAniSirGlobal pCtx, + tDot11fIETCLAS *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ietclas(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 14; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->user_priority; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.source, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.dest, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->info.EthParams.type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->info.IpParams.version; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.source, 4); + *pnConsumed += 4; + pBuf += 4; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->info.IpParams.params.IpV4Params.DSCP; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.proto; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 6: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.source, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest, 16); + *pnConsumed += 16; + pBuf += 16; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.flow_label, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->info.Params8021dq.tag_type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_tclas. */ + +uint32_t dot11f_pack_ie_tclassproc(tpAniSirGlobal pCtx, + tDot11fIETCLASSPROC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 44; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->processing; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tclassproc. */ + +uint32_t dot11f_pack_ie_ts_delay(tpAniSirGlobal pCtx, + tDot11fIETSDelay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 43; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtonl(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ts_delay. */ + +uint32_t dot11f_pack_ie_tsf_info(tpAniSirGlobal pCtx, + tDot11fIETSFInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->TsfOffset, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->BeaconIntvl, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tsf_info. */ + +uint32_t dot11f_pack_ie_tspec(tpAniSirGlobal pCtx, + tDot11fIETSPEC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp139__; + uint8_t tmp140__; + uint16_t tmp141__; + nNeeded += 55; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 13; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp139__ = 0U; + tmp139__ |= (pSrc->traffic_type << 0); + tmp139__ |= (pSrc->tsid << 1); + tmp139__ |= (pSrc->direction << 5); + tmp139__ |= (pSrc->access_policy << 7); + tmp139__ |= (pSrc->aggregation << 9); + tmp139__ |= (pSrc->psb << 10); + tmp139__ |= (pSrc->user_priority << 11); + tmp139__ |= (pSrc->tsinfo_ack_pol << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp139__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp140__ = 0U; + tmp140__ |= (pSrc->schedule << 0); + tmp140__ |= (pSrc->unused << 1); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp140__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp141__ = 0U; + tmp141__ |= (pSrc->size << 0); + tmp141__ |= (pSrc->fixed << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp141__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->max_msdu_size, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->min_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->max_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->inactivity_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->suspension_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->mean_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->peak_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->burst_size, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->delay_bound, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_phy_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->surplus_bw_allowance, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->medium_time, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tspec. */ + +uint32_t dot11f_pack_ie_vht_caps(tpAniSirGlobal pCtx, + tDot11fIEVHTCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t tmp142__; + uint16_t tmp143__; + uint16_t tmp144__; + nNeeded += 12; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 191; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp142__ = 0U; + tmp142__ |= (pSrc->maxMPDULen << 0); + tmp142__ |= (pSrc->supportedChannelWidthSet << 2); + tmp142__ |= (pSrc->ldpcCodingCap << 4); + tmp142__ |= (pSrc->shortGI80MHz << 5); + tmp142__ |= (pSrc->shortGI160and80plus80MHz << 6); + tmp142__ |= (pSrc->txSTBC << 7); + tmp142__ |= (pSrc->rxSTBC << 8); + tmp142__ |= (pSrc->suBeamFormerCap << 11); + tmp142__ |= (pSrc->suBeamformeeCap << 12); + tmp142__ |= (pSrc->csnofBeamformerAntSup << 13); + tmp142__ |= (pSrc->numSoundingDim << 16); + tmp142__ |= (pSrc->muBeamformerCap << 19); + tmp142__ |= (pSrc->muBeamformeeCap << 20); + tmp142__ |= (pSrc->vhtTXOPPS << 21); + tmp142__ |= (pSrc->htcVHTCap << 22); + tmp142__ |= (pSrc->maxAMPDULenExp << 23); + tmp142__ |= (pSrc->vhtLinkAdaptCap << 26); + tmp142__ |= (pSrc->rxAntPattern << 28); + tmp142__ |= (pSrc->txAntPattern << 29); + tmp142__ |= (pSrc->extended_nss_bw_supp << 30); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp142__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + frameshtons(pCtx, pBuf, pSrc->rxMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp143__ = 0U; + tmp143__ |= (pSrc->rxHighSupDataRate << 0); + tmp143__ |= (pSrc->max_nsts_total << 13); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp143__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->txMCSMap, 0); + *pnConsumed += 2; + pBuf += 2; + tmp144__ = 0U; + tmp144__ |= (pSrc->txSupDataRate << 0); + tmp144__ |= (pSrc->vht_extended_nss_bw_cap << 13); + tmp144__ |= (pSrc->reserved << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp144__, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + nBuf -= 2 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_caps. */ + +uint32_t dot11f_pack_ie_vht_operation(tpAniSirGlobal pCtx, + tDot11fIEVHTOperation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 192; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->chanWidth; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chan_center_freq_seg0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->chan_center_freq_seg1; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->basicMCSSet, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_operation. */ + +uint32_t dot11f_pack_ie_wmm_schedule(tpAniSirGlobal pCtx, + tDot11fIEWMMSchedule *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp145__; + nNeeded += 15; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp145__ = 0U; + tmp145__ |= (pSrc->aggregation << 0); + tmp145__ |= (pSrc->tsid << 1); + tmp145__ |= (pSrc->direction << 5); + tmp145__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp145__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_interval, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->max_service_dur, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->spec_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_schedule. */ + +uint32_t dot11f_pack_ie_wmmtclas(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLAS *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewmmtclas(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->user_priority; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 0: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.source, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.EthParams.dest, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->info.EthParams.type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->info.IpParams.version; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->info.IpParams.version) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.source, 4); + *pnConsumed += 4; + pBuf += 4; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest, 4); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV4Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->info.IpParams.params.IpV4Params.DSCP; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.proto; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->info.IpParams.params.IpV4Params.reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 6: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.source, 10); + *pnConsumed += 10; + pBuf += 10; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest, 10); + *pnConsumed += 10; + pBuf += 10; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.src_port, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.dest_port, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.IpParams.params.IpV6Params.flow_label, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->info.Params8021dq.tag_type, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wmmtclas. */ + +uint32_t dot11f_pack_ie_wmmtclasproc(tpAniSirGlobal pCtx, + tDot11fIEWMMTCLASPROC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x7; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->processing; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmtclasproc. */ + +uint32_t dot11f_pack_ie_wmmts_delay(tpAniSirGlobal pCtx, + tDot11fIEWMMTSDelay *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->delay, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmts_delay. */ + +uint32_t dot11f_pack_ie_wmmtspec(tpAniSirGlobal pCtx, + tDot11fIEWMMTSPEC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp146__; + uint8_t tmp147__; + uint16_t tmp148__; + nNeeded += 38; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp146__ = 0U; + tmp146__ |= (pSrc->traffic_type << 0); + tmp146__ |= (pSrc->tsid << 1); + tmp146__ |= (pSrc->direction << 5); + tmp146__ |= (pSrc->access_policy << 7); + tmp146__ |= (pSrc->aggregation << 9); + tmp146__ |= (pSrc->psb << 10); + tmp146__ |= (pSrc->user_priority << 11); + tmp146__ |= (pSrc->tsinfo_ack_pol << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp146__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp147__ = 0U; + tmp147__ |= (pSrc->tsinfo_rsvd << 0); + tmp147__ |= (pSrc->burst_size_defn << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp147__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp148__ = 0U; + tmp148__ |= (pSrc->size << 0); + tmp148__ |= (pSrc->fixed << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp148__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + frameshtons(pCtx, pBuf, pSrc->max_msdu_size, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->min_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->max_service_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->inactivity_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->suspension_int, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->service_start_time, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->mean_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->peak_data_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->burst_size, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->delay_bound, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->min_phy_rate, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtons(pCtx, pBuf, pSrc->surplus_bw_allowance, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->medium_time, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmmtspec. */ + +uint32_t dot11f_pack_ie_wider_bw_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEWiderBWChanSwitchAnn *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 194; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->newChanWidth; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newCenterChanFreq0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newCenterChanFreq1; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wider_bw_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_azimuth_req(tpAniSirGlobal pCtx, + tDot11fIEazimuth_req *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->request; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_azimuth_req. */ + +uint32_t dot11f_pack_ie_beacon_report_frm_body_fragment_id(tpAniSirGlobal pCtx, + tDot11fIEbeacon_report_frm_body_fragment_id *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp149__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp149__ = 0U; + tmp149__ |= (pSrc->beacon_report_id << 0); + tmp149__ |= (pSrc->fragment_id_number << 8); + tmp149__ |= (pSrc->more_fragments << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp149__, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + nBuf -= 2 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_beacon_report_frm_body_fragment_id. */ + +uint32_t dot11f_pack_ie_bw_ind_element(tpAniSirGlobal pCtx, + tDot11fIEbw_ind_element *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp150__; + uint8_t tmp151__; + nNeeded += (pSrc->disabled_sub_chan_bitmap_present * 2 + 4); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 135; + ++pBuf; ++(*pnConsumed); + tmp150__ = 0U; + tmp150__ |= (pSrc->reserved << 0); + tmp150__ |= (pSrc->disabled_sub_chan_bitmap_present << 1); + tmp150__ |= (pSrc->reserved_1 << 2); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp150__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp151__ = 0U; + tmp151__ |= (pSrc->channel_width << 0); + tmp151__ |= (pSrc->reserved_2 << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp151__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->ccfs0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->ccfs1; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->disabled_sub_chan_bitmap), (pSrc->disabled_sub_chan_bitmap_present * 2)); + *pnConsumed += (pSrc->disabled_sub_chan_bitmap_present * 2); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bw_ind_element. */ + +uint32_t dot11f_pack_ie_bw_indication(tpAniSirGlobal pCtx, + tDot11fIEbw_indication *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp152__; + uint8_t tmp153__; + nNeeded += (pSrc->disabled_sub_chan_bitmap_present * 2 + 4); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 164; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp152__ = 0U; + tmp152__ |= (pSrc->reserved << 0); + tmp152__ |= (pSrc->disabled_sub_chan_bitmap_present << 1); + tmp152__ |= (pSrc->reserved_1 << 2); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp152__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp153__ = 0U; + tmp153__ |= (pSrc->channel_width << 0); + tmp153__ |= (pSrc->reserved_2 << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp153__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->ccfs0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->ccfs1; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->disabled_sub_chan_bitmap), (pSrc->disabled_sub_chan_bitmap_present * 2)); + *pnConsumed += (pSrc->disabled_sub_chan_bitmap_present * 2); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bw_indication. */ + +uint32_t dot11f_pack_ie_last_beacon_report_indication(tpAniSirGlobal pCtx, + tDot11fIElast_beacon_report_indication *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 164; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->last_fragment; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_last_beacon_report_indication. */ + +uint32_t dot11f_pack_ie_max_age(tpAniSirGlobal pCtx, + tDot11fIEmax_age *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->max_age, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_max_age. */ + +uint32_t dot11f_pack_ie_mscs_status(tpAniSirGlobal pCtx, + tDot11fIEmscs_status *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 76; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->status_code; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_mscs_status. */ + +uint32_t dot11f_pack_ie_neighbor_rpt(tpAniSirGlobal pCtx, + tDot11fIEneighbor_rpt *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp154__; + uint8_t tmp155__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_neighbor_rpt(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 52; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + tmp154__ = 0U; + tmp154__ |= (pSrc->APReachability << 0); + tmp154__ |= (pSrc->Security << 2); + tmp154__ |= (pSrc->KeyScope << 3); + tmp154__ |= (pSrc->SpecMgmtCap << 4); + tmp154__ |= (pSrc->QosCap << 5); + tmp154__ |= (pSrc->apsd << 6); + tmp154__ |= (pSrc->rrm << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp154__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp155__ = 0U; + tmp155__ |= (pSrc->DelayedBA << 0); + tmp155__ |= (pSrc->ImmBA << 1); + tmp155__ |= (pSrc->MobilityDomain << 2); + tmp155__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp155__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->reserved1, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->PhyType; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_neighbor_rpt, + IES_neighbor_rpt); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_neighbor_rpt. */ + +uint32_t dot11f_pack_ie_reporting_reason(tpAniSirGlobal pCtx, + tDot11fIEreporting_reason *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp156__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp156__ = 0U; + tmp156__ |= (pSrc->failed_count << 0); + tmp156__ |= (pSrc->fcs_error << 1); + tmp156__ |= (pSrc->multiple_retry << 2); + tmp156__ |= (pSrc->frame_duplicate << 3); + tmp156__ |= (pSrc->rts_failure << 4); + tmp156__ |= (pSrc->ack_failure << 5); + tmp156__ |= (pSrc->retry << 6); + tmp156__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp156__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_reporting_reason. */ + +uint32_t dot11f_pack_ie_req_mac_addr(tpAniSirGlobal pCtx, + tDot11fIEreq_mac_addr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->addr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_req_mac_addr. */ + +uint32_t dot11f_pack_ie_rrm_reporting(tpAniSirGlobal pCtx, + tDot11fIErrm_reporting *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->reporting_condition; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->threshold; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rrm_reporting. */ + +uint32_t dot11f_pack_ie_tclas_mask(tpAniSirGlobal pCtx, + tDot11fIEtclas_mask *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_tclas_mask(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 89; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->classifier_type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->classifier_mask; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->classifier_type) { + case 4: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->info.ip_param.reserved, 16); + *pnConsumed += 16; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_tclas_mask. */ + +uint32_t dot11f_pack_ie_tgt_mac_addr(tpAniSirGlobal pCtx, + tDot11fIEtgt_mac_addr *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->addr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tgt_mac_addr. */ + +uint32_t dot11f_pack_ie_transmit_power_env(tpAniSirGlobal pCtx, + tDot11fIEtransmit_power_env *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp157__; + uint8_t tmp158__; + uint8_t tmp159__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_transmit_power_env(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 195; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp157__ = 0U; + tmp157__ |= (pSrc->max_tx_pwr_count << 0); + tmp157__ |= (pSrc->max_tx_pwr_interpret << 3); + tmp157__ |= (pSrc->max_tx_pwr_category << 6); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp157__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->tx_power), pSrc->num_tx_power); + *pnConsumed += pSrc->num_tx_power; + pBuf += pSrc->num_tx_power; + if (pSrc->max_tx_pwr_interpret) { + switch (pSrc->max_tx_pwr_interpret) { + case 0: + *pBuf = pSrc->ext_max_tx_power.ext_max_tx_power_local_eirp.max_tx_power_for_320; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 1: + tmp158__ = 0U; + tmp158__ |= (pSrc->ext_max_tx_power.ext_max_tx_power_local_psd.ext_count << 0); + tmp158__ |= (pSrc->ext_max_tx_power.ext_max_tx_power_local_psd.reserved << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp158__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->ext_max_tx_power.ext_max_tx_power_local_psd.max_tx_psd_power, 8); + *pnConsumed += 8; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->ext_max_tx_power.ext_max_tx_power_reg_eirp.max_tx_power_for_320; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 3: + tmp159__ = 0U; + tmp159__ |= (pSrc->ext_max_tx_power.ext_max_tx_power_reg_psd.ext_count << 0); + tmp159__ |= (pSrc->ext_max_tx_power.ext_max_tx_power_reg_psd.reserved << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp159__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->ext_max_tx_power.ext_max_tx_power_reg_psd.max_tx_psd_power, 8); + *pnConsumed += 8; + /* fieldsEndFlag = 1 */ + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_transmit_power_env. */ + +uint32_t dot11f_pack_ie_wide_bw_chan_switch(tpAniSirGlobal pCtx, + tDot11fIEwide_bw_chan_switch *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 163; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->new_chan_width; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_center_chan_freq0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_center_chan_freq1; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wide_bw_chan_switch. */ + +uint32_t dot11f_pack_ie_aid(tpAniSirGlobal pCtx, + tDot11fIEAID *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 197; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->assocId, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_aid. */ + +uint32_t dot11f_pack_ie_cf_params(tpAniSirGlobal pCtx, + tDot11fIECFParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->cfp_count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->cfp_period; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->cfp_maxduration, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->cfp_durremaining, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_cf_params. */ + +uint32_t dot11f_pack_ie_challenge_text(tpAniSirGlobal pCtx, + tDot11fIEChallengeText *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_text; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 16; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->text), pSrc->num_text); + *pnConsumed += pSrc->num_text; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_challenge_text. */ + +uint32_t dot11f_pack_ie_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEChanSwitchAnn *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 37; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->switchMode; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->newChannel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->switchCount; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_channel_switch_wrapper(tpAniSirGlobal pCtx, + tDot11fIEChannelSwitchWrapper *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_channel_switch_wrapper(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 196; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_ChannelSwitchWrapper, + IES_ChannelSwitchWrapper); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_channel_switch_wrapper. */ + +uint32_t dot11f_pack_ie_country(tpAniSirGlobal pCtx, + tDot11fIECountry *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_country(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 7; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->country, 3); + *pnConsumed += 3; + pBuf += 3; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->first_triplet, 3); + *pnConsumed += 3; + pBuf += 3; + if (pSrc->num_more_triplets) { + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->more_triplets), (pSrc->num_more_triplets * 3)); + *pnConsumed += (pSrc->num_more_triplets * 3); + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_country. */ + +uint32_t dot11f_pack_ie_ds_params(tpAniSirGlobal pCtx, + tDot11fIEDSParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->curr_channel; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ds_params. */ + +uint32_t dot11f_pack_ie_edca_param_set(tpAniSirGlobal pCtx, + tDot11fIEEDCAParamSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp160__; + uint8_t tmp161__; + uint8_t tmp162__; + uint8_t tmp163__; + uint8_t tmp164__; + uint8_t tmp165__; + uint8_t tmp166__; + uint8_t tmp167__; + nNeeded += 18; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 12; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->qos; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved; + *pnConsumed += 1; + pBuf += 1; + tmp160__ = 0U; + tmp160__ |= (pSrc->acbe_aifsn << 0); + tmp160__ |= (pSrc->acbe_acm << 4); + tmp160__ |= (pSrc->acbe_aci << 5); + tmp160__ |= (pSrc->unused1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp160__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp161__ = 0U; + tmp161__ |= (pSrc->acbe_acwmin << 0); + tmp161__ |= (pSrc->acbe_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp161__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp162__ = 0U; + tmp162__ |= (pSrc->acbk_aifsn << 0); + tmp162__ |= (pSrc->acbk_acm << 4); + tmp162__ |= (pSrc->acbk_aci << 5); + tmp162__ |= (pSrc->unused2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp162__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp163__ = 0U; + tmp163__ |= (pSrc->acbk_acwmin << 0); + tmp163__ |= (pSrc->acbk_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp163__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp164__ = 0U; + tmp164__ |= (pSrc->acvi_aifsn << 0); + tmp164__ |= (pSrc->acvi_acm << 4); + tmp164__ |= (pSrc->acvi_aci << 5); + tmp164__ |= (pSrc->unused3 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp164__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp165__ = 0U; + tmp165__ |= (pSrc->acvi_acwmin << 0); + tmp165__ |= (pSrc->acvi_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp165__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp166__ = 0U; + tmp166__ |= (pSrc->acvo_aifsn << 0); + tmp166__ |= (pSrc->acvo_acm << 4); + tmp166__ |= (pSrc->acvo_aci << 5); + tmp166__ |= (pSrc->unused4 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp166__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp167__ = 0U; + tmp167__ |= (pSrc->acvo_acwmin << 0); + tmp167__ |= (pSrc->acvo_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp167__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvo_txoplimit, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_edca_param_set. */ + +uint32_t dot11f_pack_ie_erp_info(tpAniSirGlobal pCtx, + tDot11fIEERPInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp168__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 42; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp168__ = 0U; + tmp168__ |= (pSrc->non_erp_present << 0); + tmp168__ |= (pSrc->use_prot << 1); + tmp168__ |= (pSrc->barker_preamble << 2); + tmp168__ |= (pSrc->unused << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp168__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_erp_info. */ + +uint32_t dot11f_pack_ie_ese_cckm_opaque(tpAniSirGlobal pCtx, + tDot11fIEESECckmOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 156; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_cckm_opaque. */ + +uint32_t dot11f_pack_ie_ese_rad_mgmt_cap(tpAniSirGlobal pCtx, + tDot11fIEESERadMgmtCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp169__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->mgmt_state; + *pnConsumed += 1; + pBuf += 1; + tmp169__ = 0U; + tmp169__ |= (pSrc->mbssid_mask << 0); + tmp169__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp169__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_rad_mgmt_cap. */ + +uint32_t dot11f_pack_ie_ese_traf_strm_met(tpAniSirGlobal pCtx, + tDot11fIEESETrafStrmMet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x7; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tsid; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->state; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->msmt_interval, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_traf_strm_met. */ + +uint32_t dot11f_pack_ie_ese_traf_strm_rate_set(tpAniSirGlobal pCtx, + tDot11fIEESETrafStrmRateSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_tsrates + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tsid; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->tsrates), pSrc->num_tsrates); + *pnConsumed += pSrc->num_tsrates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_traf_strm_rate_set. */ + +uint32_t dot11f_pack_ie_ese_txmit_power(tpAniSirGlobal pCtx, + tDot11fIEESETxmitPower *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 150; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->power_limit; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_txmit_power. */ + +uint32_t dot11f_pack_ie_ese_version(tpAniSirGlobal pCtx, + tDot11fIEESEVersion *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x40; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x96; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x3; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ese_version. */ + +uint32_t dot11f_pack_ie_ext_cap(tpAniSirGlobal pCtx, + tDot11fIEExtCap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bytes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 127; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bytes), pSrc->num_bytes); + *pnConsumed += pSrc->num_bytes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_cap. */ + +uint32_t dot11f_pack_ie_ext_supp_rates(tpAniSirGlobal pCtx, + tDot11fIEExtSuppRates *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_rates; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 50; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rates), pSrc->num_rates); + *pnConsumed += pSrc->num_rates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_supp_rates. */ + +uint32_t dot11f_pack_ie_fh_param_set(tpAniSirGlobal pCtx, + tDot11fIEFHParamSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 2; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->dwell_time, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->hop_set; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->hop_pattern; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->hop_index; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_param_set. */ + +uint32_t dot11f_pack_ie_fh_params(tpAniSirGlobal pCtx, + tDot11fIEFHParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 8; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->radix; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->nchannels; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_params. */ + +uint32_t dot11f_pack_ie_fh_patt_table(tpAniSirGlobal pCtx, + tDot11fIEFHPattTable *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_randtable + 4); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 9; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->flag; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->nsets; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->modulus; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->randtable), pSrc->num_randtable); + *pnConsumed += pSrc->num_randtable; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fh_patt_table. */ + +uint32_t dot11f_pack_ie_ft_info(tpAniSirGlobal pCtx, + tDot11fIEFTInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp170__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ieft_info(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 55; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + tmp170__ = 0U; + tmp170__ |= (pSrc->reserved << 0); + tmp170__ |= (pSrc->IECount << 8); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp170__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->MIC, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->Anonce, 32); + *pnConsumed += 32; + pBuf += 32; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->Snonce, 32); + *pnConsumed += 32; + pBuf += 32; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_FTInfo, + IES_FTInfo); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_ft_info. */ + +uint32_t dot11f_pack_ie_ht_caps(tpAniSirGlobal pCtx, + tDot11fIEHTCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp171__; + uint8_t tmp172__; + uint16_t tmp173__; + uint32_t tmp174__; + uint8_t tmp175__; + nNeeded += (pSrc->num_rsvd + 26); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 45; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp171__ = 0U; + tmp171__ |= (pSrc->advCodingCap << 0); + tmp171__ |= (pSrc->supportedChannelWidthSet << 1); + tmp171__ |= (pSrc->mimoPowerSave << 2); + tmp171__ |= (pSrc->greenField << 4); + tmp171__ |= (pSrc->shortGI20MHz << 5); + tmp171__ |= (pSrc->shortGI40MHz << 6); + tmp171__ |= (pSrc->txSTBC << 7); + tmp171__ |= (pSrc->rxSTBC << 8); + tmp171__ |= (pSrc->delayedBA << 10); + tmp171__ |= (pSrc->maximalAMSDUsize << 11); + tmp171__ |= (pSrc->dsssCckMode40MHz << 12); + tmp171__ |= (pSrc->psmp << 13); + tmp171__ |= (pSrc->stbcControlFrame << 14); + tmp171__ |= (pSrc->lsigTXOPProtection << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp171__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp172__ = 0U; + tmp172__ |= (pSrc->maxRxAMPDUFactor << 0); + tmp172__ |= (pSrc->mpduDensity << 2); + tmp172__ |= (pSrc->reserved1 << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp172__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->supportedMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + tmp173__ = 0U; + tmp173__ |= (pSrc->pco << 0); + tmp173__ |= (pSrc->transitionTime << 1); + tmp173__ |= (pSrc->reserved2 << 3); + tmp173__ |= (pSrc->mcsFeedback << 8); + tmp173__ |= (pSrc->reserved3 << 10); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp173__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp174__ = 0U; + tmp174__ |= (pSrc->txBF << 0); + tmp174__ |= (pSrc->rxStaggeredSounding << 1); + tmp174__ |= (pSrc->txStaggeredSounding << 2); + tmp174__ |= (pSrc->rxZLF << 3); + tmp174__ |= (pSrc->txZLF << 4); + tmp174__ |= (pSrc->implicitTxBF << 5); + tmp174__ |= (pSrc->calibration << 6); + tmp174__ |= (pSrc->explicitCSITxBF << 8); + tmp174__ |= (pSrc->explicitUncompressedSteeringMatrix << 9); + tmp174__ |= (pSrc->explicitBFCSIFeedback << 10); + tmp174__ |= (pSrc->explicitUncompressedSteeringMatrixFeedback << 13); + tmp174__ |= (pSrc->explicitCompressedSteeringMatrixFeedback << 16); + tmp174__ |= (pSrc->csiNumBFAntennae << 19); + tmp174__ |= (pSrc->uncompressedSteeringMatrixBFAntennae << 21); + tmp174__ |= (pSrc->compressedSteeringMatrixBFAntennae << 23); + tmp174__ |= (pSrc->reserved4 << 25); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp174__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp175__ = 0U; + tmp175__ |= (pSrc->antennaSelection << 0); + tmp175__ |= (pSrc->explicitCSIFeedbackTx << 1); + tmp175__ |= (pSrc->antennaIndicesFeedbackTx << 2); + tmp175__ |= (pSrc->explicitCSIFeedback << 3); + tmp175__ |= (pSrc->antennaIndicesFeedback << 4); + tmp175__ |= (pSrc->rxAS << 5); + tmp175__ |= (pSrc->txSoundingPPDUs << 6); + tmp175__ |= (pSrc->reserved5 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp175__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rsvd), pSrc->num_rsvd); + *pnConsumed += pSrc->num_rsvd; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht_caps. */ + +uint32_t dot11f_pack_ie_ht_info(tpAniSirGlobal pCtx, + tDot11fIEHTInfo *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp176__; + uint16_t tmp177__; + uint16_t tmp178__; + nNeeded += (pSrc->num_rsvd + 22); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 61; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->primaryChannel; + *pnConsumed += 1; + pBuf += 1; + tmp176__ = 0U; + tmp176__ |= (pSrc->secondaryChannelOffset << 0); + tmp176__ |= (pSrc->recommendedTxWidthSet << 2); + tmp176__ |= (pSrc->rifsMode << 3); + tmp176__ |= (pSrc->controlledAccessOnly << 4); + tmp176__ |= (pSrc->serviceIntervalGranularity << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp176__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp177__ = 0U; + tmp177__ |= (pSrc->opMode << 0); + tmp177__ |= (pSrc->nonGFDevicesPresent << 2); + tmp177__ |= (pSrc->transmitBurstLimit << 3); + tmp177__ |= (pSrc->obssNonHTStaPresent << 4); + tmp177__ |= (pSrc->chan_center_freq_seg2 << 5); + tmp177__ |= (pSrc->reserved << 13); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp177__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp178__ = 0U; + tmp178__ |= (pSrc->basicSTBCMCS << 0); + tmp178__ |= (pSrc->dualCTSProtection << 7); + tmp178__ |= (pSrc->secondaryBeacon << 8); + tmp178__ |= (pSrc->lsigTXOPProtectionFullSupport << 9); + tmp178__ |= (pSrc->pcoActive << 10); + tmp178__ |= (pSrc->pcoPhase << 11); + tmp178__ |= (pSrc->reserved2 << 12); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp178__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->basicMCSSet, 16); + *pnConsumed += 16; + pBuf += 16; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rsvd), pSrc->num_rsvd); + *pnConsumed += pSrc->num_rsvd; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht_info. */ + +uint32_t dot11f_pack_ie_link_identifier(tpAniSirGlobal pCtx, + tDot11fIELinkIdentifier *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 18; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 101; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->InitStaAddr, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RespStaAddr, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_link_identifier. */ + +uint32_t dot11f_pack_ie_MBO_IE(tpAniSirGlobal pCtx, + tDot11fIEMBO_IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_MBO_IE(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x16; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_MBO_IE + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_MBO_IE. */ + +uint32_t dot11f_pack_ie_measurement_report(tpAniSirGlobal pCtx, + tDot11fIEMeasurementReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp179__; + uint8_t tmp180__; + uint8_t tmp181__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_measurement_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 39; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->token; + *pnConsumed += 1; + pBuf += 1; + tmp179__ = 0U; + tmp179__ |= (pSrc->late << 0); + tmp179__ |= (pSrc->incapable << 1); + tmp179__ |= (pSrc->refused << 2); + tmp179__ |= (pSrc->unused << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp179__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + if (pSrc->type) { + switch (pSrc->type) { + case 0: + *pBuf = pSrc->report.Basic.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.Basic.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.Basic.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + tmp180__ = 0U; + tmp180__ |= (pSrc->report.Basic.bss << 0); + tmp180__ |= (pSrc->report.Basic.ofdm_preamble << 1); + tmp180__ |= (pSrc->report.Basic.unid_signal << 2); + tmp180__ |= (pSrc->report.Basic.rader << 3); + tmp180__ |= (pSrc->report.Basic.unmeasured << 4); + tmp180__ |= (pSrc->report.Basic.unused << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp180__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + case 1: + *pBuf = pSrc->report.CCA.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.CCA.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.CCA.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.CCA.cca_busy_fraction; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->report.RPIHistogram.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.RPIHistogram.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.RPIHistogram.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.RPIHistogram.rpi0_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi1_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi2_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi3_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi4_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi5_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi6_density; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.RPIHistogram.rpi7_density; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 3: + *pBuf = pSrc->report.channel_load_report.op_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.channel_load_report.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.channel_load_report.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.channel_load_report.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.channel_load_report.chan_load; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_reportchannel_load_report, + IES_reportchannel_load_report); + break; + case 5: + *pBuf = pSrc->report.Beacon.regClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.Beacon.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtonq(pCtx, pBuf, pSrc->report.Beacon.meas_start_time, 0); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->report.Beacon.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + tmp181__ = 0U; + tmp181__ |= (pSrc->report.Beacon.condensed_PHY << 0); + tmp181__ |= (pSrc->report.Beacon.reported_frame_type << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp181__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->report.Beacon.RCPI; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.Beacon.RSNI; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->report.Beacon.BSSID, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->report.Beacon.antenna_id; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->report.Beacon.parent_TSF, 0); + *pnConsumed += 4; + pBuf += 4; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_reportBeacon, + IES_reportBeacon); + break; + case 7: + frameshtons(pCtx, pBuf, pSrc->report.sta_stats.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.sta_stats.group_id; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->report.sta_stats.group_id) { + case 0: + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_fragment_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.group_transmitted_frame_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.failed_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.received_fragment_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.group_received_frame_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.fcs_error_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_frame_count, 0); + *pnConsumed += 4; + pBuf += 4; + break; + case 1: + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_mac_stats.retry_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_mac_stats.multiple_retry_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_mac_stats.frame_duplicate_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_success_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_failure_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_mac_stats.ack_failure_count, 0); + *pnConsumed += 4; + pBuf += 4; + break; + case 2: + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_transmitted_fragment_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_failed_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_retry_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_multiple_retry_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_frame_duplicate_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_rts_success_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_rts_failure_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_ack_failure_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_received_fragment_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_transmitted_frame_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_discarded_frame_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_mpdus_received_count, 0); + *pnConsumed += 4; + pBuf += 4; + frameshtonl(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_qos_counter.qos_retries_received_count, 0); + *pnConsumed += 4; + pBuf += 4; + break; + case 10: + *pBuf = pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.ap_average_access_delay; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_besteffort; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_background; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_video; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_voice; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.station_count, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.channel_utilization; + *pnConsumed += 1; + pBuf += 1; + break; + } + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_reportsta_stats, + IES_reportsta_stats); + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_measurement_report. */ + +uint32_t dot11f_pack_ie_measurement_request(tpAniSirGlobal pCtx, + tDot11fIEMeasurementRequest *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp182__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_measurement_request(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 38; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->measurement_token; + *pnConsumed += 1; + pBuf += 1; + tmp182__ = 0U; + tmp182__ |= (pSrc->parallel << 0); + tmp182__ |= (pSrc->enable << 1); + tmp182__ |= (pSrc->request << 2); + tmp182__ |= (pSrc->report << 3); + tmp182__ |= (pSrc->durationMandatory << 4); + tmp182__ |= (pSrc->unused << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp182__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->measurement_type; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->measurement_type) { + case 0: + *pBuf = pSrc->measurement_request.Basic.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.Basic.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Basic.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 1: + *pBuf = pSrc->measurement_request.CCA.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.CCA.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.CCA.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->measurement_request.RPIHistogram.channel_no; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.RPIHistogram.meas_start_time, 8); + *pnConsumed += 8; + pBuf += 8; + frameshtons(pCtx, pBuf, pSrc->measurement_request.RPIHistogram.meas_duration, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 3: + *pBuf = pSrc->measurement_request.channel_load.op_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->measurement_request.channel_load.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->measurement_request.channel_load.randomization_intv, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->measurement_request.channel_load.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestchannel_load, + IES_measurement_requestchannel_load); + break; + case 5: + *pBuf = pSrc->measurement_request.Beacon.regClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->measurement_request.Beacon.channel; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Beacon.randomization, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->measurement_request.Beacon.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->measurement_request.Beacon.meas_mode; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.Beacon.BSSID, 6); + *pnConsumed += 6; + pBuf += 6; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestBeacon, + IES_measurement_requestBeacon); + break; + case 8: + *pBuf = pSrc->measurement_request.lci.loc_subject; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestlci, + IES_measurement_requestlci); + break; + case 16: + frameshtons(pCtx, pBuf, pSrc->measurement_request.ftmrr.random_interval, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->measurement_request.ftmrr.min_ap_count; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_measurement_requestftmrr, + IES_measurement_requestftmrr); + break; + case 7: + DOT11F_MEMCPY(pCtx, pBuf, pSrc->measurement_request.sta_stats.peer_mac_addr, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtons(pCtx, pBuf, pSrc->measurement_request.sta_stats.randomization, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->measurement_request.sta_stats.meas_duration, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->measurement_request.sta_stats.group_identity; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_measurement_request. */ + +uint32_t dot11f_pack_ie_mobility_domain(tpAniSirGlobal pCtx, + tDot11fIEMobilityDomain *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp183__; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 54; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->MDID, 0); + *pnConsumed += 2; + pBuf += 2; + tmp183__ = 0U; + tmp183__ |= (pSrc->overDSCap << 0); + tmp183__ |= (pSrc->resourceReqCap << 1); + tmp183__ |= (pSrc->reserved << 2); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp183__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_mobility_domain. */ + +uint32_t dot11f_pack_ie_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIENeighborReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp184__; + uint8_t tmp185__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_neighbor_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 52; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->bssid, 6); + *pnConsumed += 6; + pBuf += 6; + tmp184__ = 0U; + tmp184__ |= (pSrc->APReachability << 0); + tmp184__ |= (pSrc->Security << 2); + tmp184__ |= (pSrc->KeyScope << 3); + tmp184__ |= (pSrc->SpecMgmtCap << 4); + tmp184__ |= (pSrc->QosCap << 5); + tmp184__ |= (pSrc->apsd << 6); + tmp184__ |= (pSrc->rrm << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp184__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp185__ = 0U; + tmp185__ |= (pSrc->DelayedBA << 0); + tmp185__ |= (pSrc->ImmBA << 1); + tmp185__ |= (pSrc->MobilityDomain << 2); + tmp185__ |= (pSrc->reserved << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp185__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->reserved1, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->regulatoryClass; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->PhyType; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_NeighborReport, + IES_NeighborReport); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_neighbor_report. */ + +uint32_t dot11f_pack_ie_obss_scan_parameters(tpAniSirGlobal pCtx, + tDot11fIEOBSSScanParameters *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 14; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 74; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->obssScanPassiveDwell, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActiveDwell, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->bssChannelWidthTriggerScanInterval, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanPassiveTotalPerChannel, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActiveTotalPerChannel, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->bssWidthChannelTransitionDelayFactor, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->obssScanActivityThreshold, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_obss_scan_parameters. */ + +uint32_t dot11f_pack_ie_operating_mode(tpAniSirGlobal pCtx, + tDot11fIEOperatingMode *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp186__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 199; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp186__ = 0U; + tmp186__ |= (pSrc->chanWidth << 0); + tmp186__ |= (pSrc->vht_160_80p80_supp << 2); + tmp186__ |= (pSrc->no_ldpc << 3); + tmp186__ |= (pSrc->rxNSS << 4); + tmp186__ |= (pSrc->rxNSSType << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp186__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_operating_mode. */ + +uint32_t dot11f_pack_ie_p2_p_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_assoc_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PAssocReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_assoc_req. */ + +uint32_t dot11f_pack_ie_p2_p_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEP2PAssocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_assoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PAssocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_assoc_res. */ + +uint32_t dot11f_pack_ie_p2_p_beacon(tpAniSirGlobal pCtx, + tDot11fIEP2PBeacon *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_beacon(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PBeacon + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_beacon. */ + +uint32_t dot11f_pack_ie_p2_p_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PBeaconProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_beacon_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PBeaconProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_beacon_probe_res. */ + +uint32_t dot11f_pack_ie_p2_p_de_auth(tpAniSirGlobal pCtx, + tDot11fIEP2PDeAuth *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_de_auth(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PDeAuth + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_de_auth. */ + +uint32_t dot11f_pack_ie_p2_p_dis_assoc(tpAniSirGlobal pCtx, + tDot11fIEP2PDisAssoc *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_dis_assoc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PDisAssoc + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_dis_assoc. */ + +uint32_t dot11f_pack_ie_p2_pie_opaque(tpAniSirGlobal pCtx, + tDot11fIEP2PIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_p2_pie_opaque. */ + +uint32_t dot11f_pack_ie_p2_p_probe_req(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_probe_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PProbeReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_probe_req. */ + +uint32_t dot11f_pack_ie_p2_p_probe_res(tpAniSirGlobal pCtx, + tDot11fIEP2PProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iep2_p_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x9; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_P2PProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_p2_p_probe_res. */ + +uint32_t dot11f_pack_ie_pti_control(tpAniSirGlobal pCtx, + tDot11fIEPTIControl *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 105; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tid; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->sequence_control, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_pti_control. */ + +uint32_t dot11f_pack_ie_pu_buffer_status(tpAniSirGlobal pCtx, + tDot11fIEPUBufferStatus *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp187__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 106; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp187__ = 0U; + tmp187__ |= (pSrc->ac_bk_traffic_aval << 0); + tmp187__ |= (pSrc->ac_be_traffic_aval << 1); + tmp187__ |= (pSrc->ac_vi_traffic_aval << 2); + tmp187__ |= (pSrc->ac_vo_traffic_aval << 3); + tmp187__ |= (pSrc->reserved << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp187__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_pu_buffer_status. */ + +uint32_t dot11f_pack_ie_power_caps(tpAniSirGlobal pCtx, + tDot11fIEPowerCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 33; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->minTxPower; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->maxTxPower; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_power_caps. */ + +uint32_t dot11f_pack_ie_power_constraints(tpAniSirGlobal pCtx, + tDot11fIEPowerConstraints *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 32; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->localPowerConstraints; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_power_constraints. */ + +uint32_t dot11f_pack_ie_qbss_load(tpAniSirGlobal pCtx, + tDot11fIEQBSSLoad *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 11; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->stacount, 0); + *pnConsumed += 2; + pBuf += 2; + *pBuf = pSrc->chautil; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->avail, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qbss_load. */ + +uint32_t dot11f_pack_ie_QComVendorIE(tpAniSirGlobal pCtx, + tDot11fIEQComVendorIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xa0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xc6; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->type; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_QComVendorIE. */ + +uint32_t dot11f_pack_ie_qos_caps_ap(tpAniSirGlobal pCtx, + tDot11fIEQOSCapsAp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp188__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp188__ = 0U; + tmp188__ |= (pSrc->count << 0); + tmp188__ |= (pSrc->qack << 4); + tmp188__ |= (pSrc->qreq << 5); + tmp188__ |= (pSrc->txopreq << 6); + tmp188__ |= (pSrc->reserved << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp188__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_caps_ap. */ + +uint32_t dot11f_pack_ie_qos_caps_station(tpAniSirGlobal pCtx, + tDot11fIEQOSCapsStation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp189__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 46; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp189__ = 0U; + tmp189__ |= (pSrc->acvo_uapsd << 0); + tmp189__ |= (pSrc->acvi_uapsd << 1); + tmp189__ |= (pSrc->acbk_uapsd << 2); + tmp189__ |= (pSrc->acbe_uapsd << 3); + tmp189__ |= (pSrc->qack << 4); + tmp189__ |= (pSrc->max_sp_length << 5); + tmp189__ |= (pSrc->more_data_ack << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp189__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_caps_station. */ + +uint32_t dot11f_pack_ie_qos_map_set(tpAniSirGlobal pCtx, + tDot11fIEQosMapSet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_dscp_exceptions; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 110; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->dscp_exceptions), pSrc->num_dscp_exceptions); + *pnConsumed += pSrc->num_dscp_exceptions; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_qos_map_set. */ + +uint32_t dot11f_pack_ie_quiet(tpAniSirGlobal pCtx, + tDot11fIEQuiet *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 6; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 40; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->period; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->duration, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->offset, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_quiet. */ + +uint32_t dot11f_pack_ie_rcpiie(tpAniSirGlobal pCtx, + tDot11fIERCPIIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 53; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->rcpi; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rcpiie. */ + +uint32_t dot11f_pack_ie_ric_data_desc(tpAniSirGlobal pCtx, + tDot11fIERICDataDesc *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ieric_data_desc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_RICDataDesc, + IES_RICDataDesc); + break; + } + (void)pCtx; + return status; +} /* End dot11f_pack_ie_ric_data_desc. */ + +uint32_t dot11f_pack_ie_rsn(tpAniSirGlobal pCtx, + tDot11fIERSN *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iersn(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 48; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + if (pSrc->gp_cipher_suite_present) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->gp_cipher_suite, 4); + *pnConsumed += 4; + pBuf += 4; + } else { + break; + } + if (pSrc->pwise_cipher_suite_count) { + frameshtons(pCtx, pBuf, pSrc->pwise_cipher_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->pwise_cipher_suites), (pSrc->pwise_cipher_suite_count * 4)); + *pnConsumed += (pSrc->pwise_cipher_suite_count * 4); + pBuf += (pSrc->pwise_cipher_suite_count * 4); + if (pSrc->akm_suite_cnt) { + frameshtons(pCtx, pBuf, pSrc->akm_suite_cnt, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->akm_suite), (pSrc->akm_suite_cnt * 4)); + *pnConsumed += (pSrc->akm_suite_cnt * 4); + pBuf += (pSrc->akm_suite_cnt * 4); + if (pSrc->RSN_Cap_present) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->RSN_Cap, 2); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + if (pSrc->pmkid_count) { + frameshtons(pCtx, pBuf, pSrc->pmkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + if (pSrc->gp_mgmt_cipher_suite_present) { + frameshtons(pCtx, pBuf, pSrc->pmkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->pmkid), (pSrc->pmkid_count * 16)); + *pnConsumed += (pSrc->pmkid_count * 16); + pBuf += (pSrc->pmkid_count * 16); + if (pSrc->gp_mgmt_cipher_suite_present) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->gp_mgmt_cipher_suite, 4); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_rsn. */ + +uint32_t dot11f_pack_ie_rsniie(tpAniSirGlobal pCtx, + tDot11fIERSNIIE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 65; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->rsni; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rsniie. */ + +uint32_t dot11f_pack_ie_rsn_opaque(tpAniSirGlobal pCtx, + tDot11fIERSNOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 48; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_rsn_opaque. */ + +uint32_t dot11f_pack_ie_supp_channels(tpAniSirGlobal pCtx, + tDot11fIESuppChannels *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_bands * 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 36; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bands), (pSrc->num_bands * 2)); + *pnConsumed += (pSrc->num_bands * 2); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_channels. */ + +uint32_t dot11f_pack_ie_supp_operating_classes(tpAniSirGlobal pCtx, + tDot11fIESuppOperatingClasses *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_classes; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 59; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->classes), pSrc->num_classes); + *pnConsumed += pSrc->num_classes; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_operating_classes. */ + +uint32_t dot11f_pack_ie_supp_rates(tpAniSirGlobal pCtx, + tDot11fIESuppRates *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_rates; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rates), pSrc->num_rates); + *pnConsumed += pSrc->num_rates; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_supp_rates. */ + +uint32_t dot11f_pack_ie_tim(tpAniSirGlobal pCtx, + tDot11fIETIM *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_vbmp + 3); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 5; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->dtim_count; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->dtim_period; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->bmpctl; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->vbmp), pSrc->num_vbmp); + *pnConsumed += pSrc->num_vbmp; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tim. */ + +uint32_t dot11f_pack_ie_tpc_report(tpAniSirGlobal pCtx, + tDot11fIETPCReport *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 35; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->tx_power; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->link_margin; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tpc_report. */ + +uint32_t dot11f_pack_ie_tpc_request(tpAniSirGlobal pCtx, + tDot11fIETPCRequest *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 34; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_tpc_request. */ + +uint32_t dot11f_pack_ie_time_advertisement(tpAniSirGlobal pCtx, + tDot11fIETimeAdvertisement *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 16; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 69; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->timing_capabilities; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->time_value, 10); + *pnConsumed += 10; + pBuf += 10; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->time_error, 5); + *pnConsumed += 5; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_time_advertisement. */ + +uint32_t dot11f_pack_ie_timeout_interval(tpAniSirGlobal pCtx, + tDot11fIETimeoutInterval *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 56; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->timeoutType; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->timeoutValue, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_timeout_interval. */ + +uint32_t dot11f_pack_ie_vht_ext_bss_load(tpAniSirGlobal pCtx, + tDot11fIEVHTExtBssLoad *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 5; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 193; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->muMIMOCapStaCount; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->ssUnderUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->FortyMHzUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->EightyMHzUtil; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->OneSixtyMHzUtil; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vht_ext_bss_load. */ + +uint32_t dot11f_pack_ie_vendor1_ie(tpAniSirGlobal pCtx, + tDot11fIEVendor1IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x10; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x18; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vendor1_ie. */ + +uint32_t dot11f_pack_ie_vendor3_ie(tpAniSirGlobal pCtx, + tDot11fIEVendor3IE *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 0; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x16; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x32; + ++pBuf; ++(*pnConsumed); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_vendor3_ie. */ + +uint32_t dot11f_pack_ie_wapi(tpAniSirGlobal pCtx, + tDot11fIEWAPI *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp190__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewapi(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 68; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->akm_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->akm_suites), (pSrc->akm_suite_count * 4)); + *pnConsumed += (pSrc->akm_suite_count * 4); + pBuf += (pSrc->akm_suite_count * 4); + frameshtons(pCtx, pBuf, pSrc->unicast_cipher_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->unicast_cipher_suites), (pSrc->unicast_cipher_suite_count * 4)); + *pnConsumed += (pSrc->unicast_cipher_suite_count * 4); + pBuf += (pSrc->unicast_cipher_suite_count * 4); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher_suite, 4); + *pnConsumed += 4; + pBuf += 4; + tmp190__ = 0U; + tmp190__ |= (pSrc->preauth << 0); + tmp190__ |= (pSrc->reserved << 1); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp190__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + if (pSrc->bkid_count) { + frameshtons(pCtx, pBuf, pSrc->bkid_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->bkid), (pSrc->bkid_count * 16)); + *pnConsumed += (pSrc->bkid_count * 16); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wapi. */ + +uint32_t dot11f_pack_ie_wapi_opaque(tpAniSirGlobal pCtx, + tDot11fIEWAPIOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 68; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wapi_opaque. */ + +uint32_t dot11f_pack_ie_wfatpc(tpAniSirGlobal pCtx, + tDot11fIEWFATPC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x8; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->txPower; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->linkMargin; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wfatpc. */ + +uint32_t dot11f_pack_ie_wfdie_opaque(tpAniSirGlobal pCtx, + tDot11fIEWFDIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xa; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wfdie_opaque. */ + +uint32_t dot11f_pack_ie_wmm_caps(tpAniSirGlobal pCtx, + tDot11fIEWMMCaps *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp191__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x5; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp191__ = 0U; + tmp191__ |= (pSrc->reserved << 0); + tmp191__ |= (pSrc->qack << 4); + tmp191__ |= (pSrc->queue_request << 5); + tmp191__ |= (pSrc->txop_request << 6); + tmp191__ |= (pSrc->more_ack << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp191__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_caps. */ + +uint32_t dot11f_pack_ie_wmm_info_ap(tpAniSirGlobal pCtx, + tDot11fIEWMMInfoAp *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp192__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp192__ = 0U; + tmp192__ |= (pSrc->param_set_count << 0); + tmp192__ |= (pSrc->reserved << 4); + tmp192__ |= (pSrc->uapsd << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp192__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_info_ap. */ + +uint32_t dot11f_pack_ie_wmm_info_station(tpAniSirGlobal pCtx, + tDot11fIEWMMInfoStation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp193__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + tmp193__ = 0U; + tmp193__ |= (pSrc->acvo_uapsd << 0); + tmp193__ |= (pSrc->acvi_uapsd << 1); + tmp193__ |= (pSrc->acbk_uapsd << 2); + tmp193__ |= (pSrc->acbe_uapsd << 3); + tmp193__ |= (pSrc->reserved1 << 4); + tmp193__ |= (pSrc->max_sp_length << 5); + tmp193__ |= (pSrc->reserved2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp193__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_info_station. */ + +uint32_t dot11f_pack_ie_wmm_params(tpAniSirGlobal pCtx, + tDot11fIEWMMParams *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp194__; + uint8_t tmp195__; + uint8_t tmp196__; + uint8_t tmp197__; + uint8_t tmp198__; + uint8_t tmp199__; + uint8_t tmp200__; + uint8_t tmp201__; + nNeeded += 19; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->version; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->qosInfo; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->reserved2; + *pnConsumed += 1; + pBuf += 1; + tmp194__ = 0U; + tmp194__ |= (pSrc->acbe_aifsn << 0); + tmp194__ |= (pSrc->acbe_acm << 4); + tmp194__ |= (pSrc->acbe_aci << 5); + tmp194__ |= (pSrc->unused1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp194__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp195__ = 0U; + tmp195__ |= (pSrc->acbe_acwmin << 0); + tmp195__ |= (pSrc->acbe_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp195__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbe_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp196__ = 0U; + tmp196__ |= (pSrc->acbk_aifsn << 0); + tmp196__ |= (pSrc->acbk_acm << 4); + tmp196__ |= (pSrc->acbk_aci << 5); + tmp196__ |= (pSrc->unused2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp196__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp197__ = 0U; + tmp197__ |= (pSrc->acbk_acwmin << 0); + tmp197__ |= (pSrc->acbk_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp197__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acbk_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp198__ = 0U; + tmp198__ |= (pSrc->acvi_aifsn << 0); + tmp198__ |= (pSrc->acvi_acm << 4); + tmp198__ |= (pSrc->acvi_aci << 5); + tmp198__ |= (pSrc->unused3 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp198__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp199__ = 0U; + tmp199__ |= (pSrc->acvi_acwmin << 0); + tmp199__ |= (pSrc->acvi_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp199__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvi_txoplimit, 0); + *pnConsumed += 2; + pBuf += 2; + tmp200__ = 0U; + tmp200__ |= (pSrc->acvo_aifsn << 0); + tmp200__ |= (pSrc->acvo_acm << 4); + tmp200__ |= (pSrc->acvo_aci << 5); + tmp200__ |= (pSrc->unused4 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp200__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp201__ = 0U; + tmp201__ |= (pSrc->acvo_acwmin << 0); + tmp201__ |= (pSrc->acvo_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp201__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + frameshtons(pCtx, pBuf, pSrc->acvo_txoplimit, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wmm_params. */ + +uint32_t dot11f_pack_ie_wpa(tpAniSirGlobal pCtx, + tDot11fIEWPA *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_iewpa(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->version, 0); + *pnConsumed += 2; + pBuf += 2; + if (pSrc->multicast_cipher_present) { + DOT11F_MEMCPY(pCtx, pBuf, pSrc->multicast_cipher, 4); + *pnConsumed += 4; + pBuf += 4; + } else { + break; + } + if (pSrc->unicast_cipher_count) { + frameshtons(pCtx, pBuf, pSrc->unicast_cipher_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->unicast_ciphers), (pSrc->unicast_cipher_count * 4)); + *pnConsumed += (pSrc->unicast_cipher_count * 4); + pBuf += (pSrc->unicast_cipher_count * 4); + if (pSrc->auth_suite_count) { + frameshtons(pCtx, pBuf, pSrc->auth_suite_count, 0); + *pnConsumed += 2; + pBuf += 2; + } else { + break; + } + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->auth_suites), (pSrc->auth_suite_count * 4)); + *pnConsumed += (pSrc->auth_suite_count * 4); + pBuf += (pSrc->auth_suite_count * 4); + if (pSrc->caps) { + frameshtons(pCtx, pBuf, pSrc->caps, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_wpa. */ + +uint32_t dot11f_pack_ie_wpa_opaque(tpAniSirGlobal pCtx, + tDot11fIEWPAOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wpa_opaque. */ + +uint32_t dot11f_pack_ie_wsc(tpAniSirGlobal pCtx, + tDot11fIEWSC *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_iewsc(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WSC + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc. */ + +uint32_t dot11f_pack_ie_wsc_assoc_req(tpAniSirGlobal pCtx, + tDot11fIEWscAssocReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_assoc_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscAssocReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_assoc_req. */ + +uint32_t dot11f_pack_ie_wsc_assoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscAssocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_assoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscAssocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_assoc_res. */ + +uint32_t dot11f_pack_ie_wsc_beacon(tpAniSirGlobal pCtx, + tDot11fIEWscBeacon *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_beacon(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscBeacon + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_beacon. */ + +uint32_t dot11f_pack_ie_wsc_beacon_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscBeaconProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_beacon_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscBeaconProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_beacon_probe_res. */ + +uint32_t dot11f_pack_ie_wsc_ie_opaque(tpAniSirGlobal pCtx, + tDot11fIEWscIEOpaque *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_wsc_ie_opaque. */ + +uint32_t dot11f_pack_ie_wsc_probe_req(tpAniSirGlobal pCtx, + tDot11fIEWscProbeReq *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_probe_req(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscProbeReq + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_probe_req. */ + +uint32_t dot11f_pack_ie_wsc_probe_res(tpAniSirGlobal pCtx, + tDot11fIEWscProbeRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_probe_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscProbeRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_probe_res. */ + +uint32_t dot11f_pack_ie_wsc_reassoc_res(tpAniSirGlobal pCtx, + tDot11fIEWscReassocRes *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_wsc_reassoc_res(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf2; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_WscReassocRes + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_wsc_reassoc_res. */ + +uint32_t dot11f_pack_ie_addba_extn_element(tpAniSirGlobal pCtx, + tDot11fIEaddba_extn_element *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp202__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 159; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp202__ = 0U; + tmp202__ |= (pSrc->no_fragmentation << 0); + tmp202__ |= (pSrc->he_frag_operation << 1); + tmp202__ |= (pSrc->reserved << 3); + tmp202__ |= (pSrc->extd_buff_size << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp202__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_addba_extn_element. */ + +uint32_t dot11f_pack_ie_bss_color_change(tpAniSirGlobal pCtx, + tDot11fIEbss_color_change *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp203__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 42; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->countdown; + *pnConsumed += 1; + pBuf += 1; + tmp203__ = 0U; + tmp203__ |= (pSrc->new_color << 0); + tmp203__ |= (pSrc->reserved << 6); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp203__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bss_color_change. */ + +uint32_t dot11f_pack_ie_bss_max_idle_period(tpAniSirGlobal pCtx, + tDot11fIEbss_max_idle_period *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp204__; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 90; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + frameshtons(pCtx, pBuf, pSrc->max_idle_period, 0); + *pnConsumed += 2; + pBuf += 2; + tmp204__ = 0U; + tmp204__ |= (pSrc->prot_keep_alive_reqd << 0); + tmp204__ |= (pSrc->reserved << 1); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp204__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_bss_max_idle_period. */ + +uint32_t dot11f_pack_ie_descriptor_element(tpAniSirGlobal pCtx, + tDot11fIEdescriptor_element *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_descriptor_element(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 88; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = pSrc->request_type; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->user_priority_control, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtonl(pCtx, pBuf, pSrc->stream_timeout, 0); + *pnConsumed += 4; + pBuf += 4; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_descriptor_element, + IES_descriptor_element); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_descriptor_element. */ + +uint32_t dot11f_pack_ie_dh_parameter_element(tpAniSirGlobal pCtx, + tDot11fIEdh_parameter_element *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_public_key + 2); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 32; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->group, 2); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->public_key), pSrc->num_public_key); + *pnConsumed += pSrc->num_public_key; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_dh_parameter_element. */ + +uint32_t dot11f_pack_ie_eht_cap(tpAniSirGlobal pCtx, + tDot11fIEeht_cap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp205__; + uint32_t tmp206__; + uint32_t tmp207__; + uint8_t tmp208__; + uint32_t tmp209__; + uint32_t tmp210__; + uint32_t tmp211__; + uint8_t tmp212__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_eht_cap(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 108; + ++pBuf; ++(*pnConsumed); + tmp205__ = 0U; + tmp205__ |= (pSrc->epcs_pri_access << 0); + tmp205__ |= (pSrc->eht_om_ctl << 1); + tmp205__ |= (pSrc->triggered_txop_sharing_mode1 << 2); + tmp205__ |= (pSrc->triggered_txop_sharing_mode2 << 3); + tmp205__ |= (pSrc->restricted_twt << 4); + tmp205__ |= (pSrc->scs_traffic_desc << 5); + tmp205__ |= (pSrc->max_mpdu_len << 6); + tmp205__ |= (pSrc->max_a_mpdu_len_exponent_ext << 8); + tmp205__ |= (pSrc->eht_trs_support << 9); + tmp205__ |= (pSrc->txop_return_support_txop_share_m2 << 10); + tmp205__ |= (pSrc->two_bqrs_support << 11); + tmp205__ |= (pSrc->eht_link_adaptation_support << 12); + tmp205__ |= (pSrc->reserved << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp205__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp206__ = 0U; + tmp206__ |= (pSrc->reserved2 << 0); + tmp206__ |= (pSrc->support_320mhz_6ghz << 1); + tmp206__ |= (pSrc->ru_242tone_wt_20mhz << 2); + tmp206__ |= (pSrc->ndp_4x_eht_ltf_3dot2_us_gi << 3); + tmp206__ |= (pSrc->partial_bw_mu_mimo << 4); + tmp206__ |= (pSrc->su_beamformer << 5); + tmp206__ |= (pSrc->su_beamformee << 6); + tmp206__ |= (pSrc->bfee_ss_le_80mhz << 7); + tmp206__ |= (pSrc->bfee_ss_160mhz << 10); + tmp206__ |= (pSrc->bfee_ss_320mhz << 13); + tmp206__ |= (pSrc->num_sounding_dim_le_80mhz << 16); + tmp206__ |= (pSrc->num_sounding_dim_160mhz << 19); + tmp206__ |= (pSrc->num_sounding_dim_320mhz << 22); + tmp206__ |= (pSrc->ng_16_su_feedback << 25); + tmp206__ |= (pSrc->ng_16_mu_feedback << 26); + tmp206__ |= (pSrc->cb_sz_4_2_su_feedback << 27); + tmp206__ |= (pSrc->cb_sz_7_5_su_feedback << 28); + tmp206__ |= (pSrc->trig_su_bforming_feedback << 29); + tmp206__ |= (pSrc->trig_mu_bforming_partial_bw_feedback << 30); + tmp206__ |= (pSrc->triggered_cqi_feedback << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp206__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp207__ = 0U; + tmp207__ |= (pSrc->partial_bw_dl_mu_mimo << 0); + tmp207__ |= (pSrc->psr_based_sr << 1); + tmp207__ |= (pSrc->power_boost_factor << 2); + tmp207__ |= (pSrc->eht_mu_ppdu_4x_ltf_0_8_us_gi << 3); + tmp207__ |= (pSrc->max_nc << 4); + tmp207__ |= (pSrc->non_trig_cqi_feedback << 8); + tmp207__ |= (pSrc->tx_1024_4096_qam_lt_242_tone_ru << 9); + tmp207__ |= (pSrc->rx_1024_4096_qam_lt_242_tone_ru << 10); + tmp207__ |= (pSrc->ppet_present << 11); + tmp207__ |= (pSrc->common_nominal_pkt_padding << 12); + tmp207__ |= (pSrc->max_num_eht_ltf << 14); + tmp207__ |= (pSrc->mcs_15 << 19); + tmp207__ |= (pSrc->eht_dup_6ghz << 23); + tmp207__ |= (pSrc->op_sta_rx_ndp_wider_bw_20mhz << 24); + tmp207__ |= (pSrc->non_ofdma_ul_mu_mimo_le_80mhz << 25); + tmp207__ |= (pSrc->non_ofdma_ul_mu_mimo_160mhz << 26); + tmp207__ |= (pSrc->non_ofdma_ul_mu_mimo_320mhz << 27); + tmp207__ |= (pSrc->mu_bformer_le_80mhz << 28); + tmp207__ |= (pSrc->mu_bformer_160mhz << 29); + tmp207__ |= (pSrc->mu_bformer_320mhz << 30); + tmp207__ |= (pSrc->tb_sounding_feedback_rl << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp207__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp208__ = 0U; + tmp208__ |= (pSrc->rx_1k_qam_in_wider_bw_dl_ofdma << 0); + tmp208__ |= (pSrc->rx_4k_qam_in_wider_bw_dl_ofdma << 1); + tmp208__ |= (pSrc->limited_cap_support_20mhz << 2); + tmp208__ |= (pSrc->triggered_mu_bf_full_bw_fb_and_dl_mumimo << 3); + tmp208__ |= (pSrc->mru_support_20mhz << 4); + tmp208__ |= (pSrc->reserved3 << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp208__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp209__ = 0U; + tmp209__ |= (pSrc->bw_20_rx_max_nss_for_mcs_0_to_7 << 0); + tmp209__ |= (pSrc->bw_20_tx_max_nss_for_mcs_0_to_7 << 4); + tmp209__ |= (pSrc->bw_20_rx_max_nss_for_mcs_8_and_9 << 8); + tmp209__ |= (pSrc->bw_20_tx_max_nss_for_mcs_8_and_9 << 12); + tmp209__ |= (pSrc->bw_20_rx_max_nss_for_mcs_10_and_11 << 16); + tmp209__ |= (pSrc->bw_20_tx_max_nss_for_mcs_10_and_11 << 20); + tmp209__ |= (pSrc->bw_20_rx_max_nss_for_mcs_12_and_13 << 24); + tmp209__ |= (pSrc->bw_20_tx_max_nss_for_mcs_12_and_13 << 28); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp209__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp210__ = 0U; + tmp210__ |= (pSrc->bw_le_80_rx_max_nss_for_mcs_0_to_9 << 0); + tmp210__ |= (pSrc->bw_le_80_tx_max_nss_for_mcs_0_to_9 << 4); + tmp210__ |= (pSrc->bw_le_80_rx_max_nss_for_mcs_10_and_11 << 8); + tmp210__ |= (pSrc->bw_le_80_tx_max_nss_for_mcs_10_and_11 << 12); + tmp210__ |= (pSrc->bw_le_80_rx_max_nss_for_mcs_12_and_13 << 16); + tmp210__ |= (pSrc->bw_le_80_tx_max_nss_for_mcs_12_and_13 << 20); + tmp210__ |= (pSrc->bw_160_rx_max_nss_for_mcs_0_to_9 << 24); + tmp210__ |= (pSrc->bw_160_tx_max_nss_for_mcs_0_to_9 << 28); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp210__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp211__ = 0U; + tmp211__ |= (pSrc->bw_160_rx_max_nss_for_mcs_10_and_11 << 0); + tmp211__ |= (pSrc->bw_160_tx_max_nss_for_mcs_10_and_11 << 4); + tmp211__ |= (pSrc->bw_160_rx_max_nss_for_mcs_12_and_13 << 8); + tmp211__ |= (pSrc->bw_160_tx_max_nss_for_mcs_12_and_13 << 12); + tmp211__ |= (pSrc->bw_320_rx_max_nss_for_mcs_0_to_9 << 16); + tmp211__ |= (pSrc->bw_320_tx_max_nss_for_mcs_0_to_9 << 20); + tmp211__ |= (pSrc->bw_320_rx_max_nss_for_mcs_10_and_11 << 24); + tmp211__ |= (pSrc->bw_320_tx_max_nss_for_mcs_10_and_11 << 28); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp211__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp212__ = 0U; + tmp212__ |= (pSrc->bw_320_rx_max_nss_for_mcs_12_and_13 << 0); + tmp212__ |= (pSrc->bw_320_tx_max_nss_for_mcs_12_and_13 << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp212__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + if (pSrc->ppet_present) { + switch (pSrc->ppet_present) { + case 1: + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->ppet.ppe_threshold.ppe_th), pSrc->ppet.ppe_threshold.num_ppe_th); + *pnConsumed += pSrc->ppet.ppe_threshold.num_ppe_th; + /* fieldsEndFlag = 1 */ + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_eht_cap. */ + +uint32_t dot11f_pack_ie_eht_op(tpAniSirGlobal pCtx, + tDot11fIEeht_op *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp213__; + uint32_t tmp214__; + uint8_t tmp215__; + nNeeded += (pSrc->disabled_sub_chan_bitmap_present * 2 + 8); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 106; + ++pBuf; ++(*pnConsumed); + tmp213__ = 0U; + tmp213__ |= (pSrc->eht_op_information_present << 0); + tmp213__ |= (pSrc->disabled_sub_chan_bitmap_present << 1); + tmp213__ |= (pSrc->eht_default_pe_duration << 2); + tmp213__ |= (pSrc->group_addr_bu_indication_limit << 3); + tmp213__ |= (pSrc->group_addr_bu_indication_exponent << 4); + tmp213__ |= (pSrc->reserved << 6); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp213__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp214__ = 0U; + tmp214__ |= (pSrc->basic_rx_max_nss_for_mcs_0_to_7 << 0); + tmp214__ |= (pSrc->basic_tx_max_nss_for_mcs_0_to_7 << 4); + tmp214__ |= (pSrc->basic_rx_max_nss_for_mcs_8_and_9 << 8); + tmp214__ |= (pSrc->basic_tx_max_nss_for_mcs_8_and_9 << 12); + tmp214__ |= (pSrc->basic_rx_max_nss_for_mcs_10_and_11 << 16); + tmp214__ |= (pSrc->basic_tx_max_nss_for_mcs_10_and_11 << 20); + tmp214__ |= (pSrc->basic_rx_max_nss_for_mcs_12_and_13 << 24); + tmp214__ |= (pSrc->basic_tx_max_nss_for_mcs_12_and_13 << 28); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp214__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp215__ = 0U; + tmp215__ |= (pSrc->channel_width << 0); + tmp215__ |= (pSrc->reserved_1 << 3); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp215__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->ccfs0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->ccfs1; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->disabled_sub_chan_bitmap), (pSrc->disabled_sub_chan_bitmap_present * 2)); + *pnConsumed += (pSrc->disabled_sub_chan_bitmap_present * 2); + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_eht_op. */ + +uint32_t dot11f_pack_ie_esp_information(tpAniSirGlobal pCtx, + tDot11fIEesp_information *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 11; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_esp_information. */ + +uint32_t dot11f_pack_ie_ext_chan_switch_ann(tpAniSirGlobal pCtx, + tDot11fIEext_chan_switch_ann *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 4; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 60; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->switch_mode; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_reg_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->new_channel; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->switch_count; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ext_chan_switch_ann. */ + +uint32_t dot11f_pack_ie_fils_assoc_delay_info(tpAniSirGlobal pCtx, + tDot11fIEfils_assoc_delay_info *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 1; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->assoc_delay_info; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_assoc_delay_info. */ + +uint32_t dot11f_pack_ie_fils_hlp_container(tpAniSirGlobal pCtx, + tDot11fIEfils_hlp_container *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_hlp_packet + 12); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 5; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->dest_mac, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->src_mac, 6); + *pnConsumed += 6; + pBuf += 6; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->hlp_packet), pSrc->num_hlp_packet); + *pnConsumed += pSrc->num_hlp_packet; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_hlp_container. */ + +uint32_t dot11f_pack_ie_fils_indication(tpAniSirGlobal pCtx, + tDot11fIEfils_indication *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp216__; + nNeeded += (pSrc->num_variable_data + 2); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 240; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp216__ = 0U; + tmp216__ |= (pSrc->public_key_identifiers_cnt << 0); + tmp216__ |= (pSrc->realm_identifiers_cnt << 3); + tmp216__ |= (pSrc->is_ip_config_supported << 6); + tmp216__ |= (pSrc->is_cache_id_present << 7); + tmp216__ |= (pSrc->is_hessid_present << 8); + tmp216__ |= (pSrc->is_fils_sk_auth_supported << 9); + tmp216__ |= (pSrc->is_fils_sk_auth_pfs_supported << 10); + tmp216__ |= (pSrc->is_pk_auth_supported << 11); + tmp216__ |= (pSrc->reserved << 12); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp216__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->variable_data), pSrc->num_variable_data); + *pnConsumed += pSrc->num_variable_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_indication. */ + +uint32_t dot11f_pack_ie_fils_kde(tpAniSirGlobal pCtx, + tDot11fIEfils_kde *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_kde_list + 8); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 7; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->key_rsc, 8); + *pnConsumed += 8; + pBuf += 8; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->kde_list), pSrc->num_kde_list); + *pnConsumed += pSrc->num_kde_list; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_kde. */ + +uint32_t dot11f_pack_ie_fils_key_confirmation(tpAniSirGlobal pCtx, + tDot11fIEfils_key_confirmation *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_key_auth; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 3; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->key_auth), pSrc->num_key_auth); + *pnConsumed += pSrc->num_key_auth; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_key_confirmation. */ + +uint32_t dot11f_pack_ie_fils_nonce(tpAniSirGlobal pCtx, + tDot11fIEfils_nonce *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 16; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 13; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->nonce, 16); + *pnConsumed += 16; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_nonce. */ + +uint32_t dot11f_pack_ie_fils_public_key(tpAniSirGlobal pCtx, + tDot11fIEfils_public_key *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_public_key + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 12; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->key_type; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->public_key), pSrc->num_public_key); + *pnConsumed += pSrc->num_public_key; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_public_key. */ + +uint32_t dot11f_pack_ie_fils_session(tpAniSirGlobal pCtx, + tDot11fIEfils_session *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 8; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 4; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->session, 8); + *pnConsumed += 8; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_session. */ + +uint32_t dot11f_pack_ie_fils_wrapped_data(tpAniSirGlobal pCtx, + tDot11fIEfils_wrapped_data *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_wrapped_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 8; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->wrapped_data), pSrc->num_wrapped_data); + *pnConsumed += pSrc->num_wrapped_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fils_wrapped_data. */ + +uint32_t dot11f_pack_ie_fragment_ie(tpAniSirGlobal pCtx, + tDot11fIEfragment_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 242; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_fragment_ie. */ + +uint32_t dot11f_pack_ie_he_6ghz_band_cap(tpAniSirGlobal pCtx, + tDot11fIEhe_6ghz_band_cap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp217__; + nNeeded += 2; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 59; + ++pBuf; ++(*pnConsumed); + tmp217__ = 0U; + tmp217__ |= (pSrc->min_mpdu_start_spacing << 0); + tmp217__ |= (pSrc->max_ampdu_len_exp << 3); + tmp217__ |= (pSrc->max_mpdu_len << 6); + tmp217__ |= (pSrc->sm_pow_save << 9); + tmp217__ |= (pSrc->rd_responder << 11); + tmp217__ |= (pSrc->rx_ant_pattern_consistency << 12); + tmp217__ |= (pSrc->tx_ant_pattern_consistency << 13); + tmp217__ |= (pSrc->reserved << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp217__, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + nBuf -= 2 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_he_6ghz_band_cap. */ + +uint32_t dot11f_pack_ie_he_cap(tpAniSirGlobal pCtx, + tDot11fIEhe_cap *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t tmp218__; + uint16_t tmp219__; + uint32_t tmp220__; + uint32_t tmp221__; + uint16_t tmp222__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_he_cap(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 35; + ++pBuf; ++(*pnConsumed); + tmp218__ = 0U; + tmp218__ |= (pSrc->htc_he << 0); + tmp218__ |= (pSrc->twt_request << 1); + tmp218__ |= (pSrc->twt_responder << 2); + tmp218__ |= (pSrc->fragmentation << 3); + tmp218__ |= (pSrc->max_num_frag_msdu_amsdu_exp << 5); + tmp218__ |= (pSrc->min_frag_size << 8); + tmp218__ |= (pSrc->trigger_frm_mac_pad << 10); + tmp218__ |= (pSrc->multi_tid_aggr_rx_supp << 12); + tmp218__ |= (pSrc->he_link_adaptation << 15); + tmp218__ |= (pSrc->all_ack << 17); + tmp218__ |= (pSrc->trigd_rsp_sched << 18); + tmp218__ |= (pSrc->a_bsr << 19); + tmp218__ |= (pSrc->broadcast_twt << 20); + tmp218__ |= (pSrc->ba_32bit_bitmap << 21); + tmp218__ |= (pSrc->mu_cascade << 22); + tmp218__ |= (pSrc->ack_enabled_multitid << 23); + tmp218__ |= (pSrc->reserved << 24); + tmp218__ |= (pSrc->omi_a_ctrl << 25); + tmp218__ |= (pSrc->ofdma_ra << 26); + tmp218__ |= (pSrc->max_ampdu_len_exp_ext << 27); + tmp218__ |= (pSrc->amsdu_frag << 29); + tmp218__ |= (pSrc->flex_twt_sched << 30); + tmp218__ |= (pSrc->rx_ctrl_frame << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp218__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp219__ = 0U; + tmp219__ |= (pSrc->bsrp_ampdu_aggr << 0); + tmp219__ |= (pSrc->qtp << 1); + tmp219__ |= (pSrc->a_bqr << 2); + tmp219__ |= (pSrc->spatial_reuse_param_rspder << 3); + tmp219__ |= (pSrc->ndp_feedback_supp << 4); + tmp219__ |= (pSrc->ops_supp << 5); + tmp219__ |= (pSrc->amsdu_in_ampdu << 6); + tmp219__ |= (pSrc->multi_tid_aggr_tx_supp << 7); + tmp219__ |= (pSrc->he_sub_ch_sel_tx_supp << 10); + tmp219__ |= (pSrc->ul_2x996_tone_ru_supp << 11); + tmp219__ |= (pSrc->om_ctrl_ul_mu_data_dis_rx << 12); + tmp219__ |= (pSrc->he_dynamic_smps << 13); + tmp219__ |= (pSrc->punctured_sounding_supp << 14); + tmp219__ |= (pSrc->ht_vht_trg_frm_rx_supp << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp219__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp220__ = 0U; + tmp220__ |= (pSrc->reserved2 << 0); + tmp220__ |= (pSrc->chan_width_0 << 1); + tmp220__ |= (pSrc->chan_width_1 << 2); + tmp220__ |= (pSrc->chan_width_2 << 3); + tmp220__ |= (pSrc->chan_width_3 << 4); + tmp220__ |= (pSrc->chan_width_4 << 5); + tmp220__ |= (pSrc->chan_width_5 << 6); + tmp220__ |= (pSrc->chan_width_6 << 7); + tmp220__ |= (pSrc->rx_pream_puncturing << 8); + tmp220__ |= (pSrc->device_class << 12); + tmp220__ |= (pSrc->ldpc_coding << 13); + tmp220__ |= (pSrc->he_1x_ltf_800_gi_ppdu << 14); + tmp220__ |= (pSrc->midamble_tx_rx_max_nsts << 15); + tmp220__ |= (pSrc->he_4x_ltf_3200_gi_ndp << 17); + tmp220__ |= (pSrc->tb_ppdu_tx_stbc_lt_80mhz << 18); + tmp220__ |= (pSrc->rx_stbc_lt_80mhz << 19); + tmp220__ |= (pSrc->doppler << 20); + tmp220__ |= (pSrc->ul_mu << 22); + tmp220__ |= (pSrc->dcm_enc_tx << 24); + tmp220__ |= (pSrc->dcm_enc_rx << 27); + tmp220__ |= (pSrc->ul_he_mu << 30); + tmp220__ |= (pSrc->su_beamformer << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp220__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp221__ = 0U; + tmp221__ |= (pSrc->su_beamformee << 0); + tmp221__ |= (pSrc->mu_beamformer << 1); + tmp221__ |= (pSrc->bfee_sts_lt_80 << 2); + tmp221__ |= (pSrc->bfee_sts_gt_80 << 5); + tmp221__ |= (pSrc->num_sounding_lt_80 << 8); + tmp221__ |= (pSrc->num_sounding_gt_80 << 11); + tmp221__ |= (pSrc->su_feedback_tone16 << 14); + tmp221__ |= (pSrc->mu_feedback_tone16 << 15); + tmp221__ |= (pSrc->codebook_su << 16); + tmp221__ |= (pSrc->codebook_mu << 17); + tmp221__ |= (pSrc->beamforming_feedback << 18); + tmp221__ |= (pSrc->he_er_su_ppdu << 21); + tmp221__ |= (pSrc->dl_mu_mimo_part_bw << 22); + tmp221__ |= (pSrc->ppet_present << 23); + tmp221__ |= (pSrc->srp << 24); + tmp221__ |= (pSrc->power_boost << 25); + tmp221__ |= (pSrc->he_ltf_800_gi_4x << 26); + tmp221__ |= (pSrc->max_nc << 27); + tmp221__ |= (pSrc->tb_ppdu_tx_stbc_gt_80mhz << 30); + tmp221__ |= (pSrc->rx_stbc_gt_80mhz << 31); + if (unlikely(nBuf < 4)) + return DOT11F_INCOMPLETE_IE; + + frameshtonl(pCtx, pBuf, tmp221__, 0); + *pnConsumed += 4; + pBuf += 4; + nBuf -= 4 ; + tmp222__ = 0U; + tmp222__ |= (pSrc->er_he_ltf_800_gi_4x << 0); + tmp222__ |= (pSrc->he_ppdu_20_in_40Mhz_2G << 1); + tmp222__ |= (pSrc->he_ppdu_20_in_160_80p80Mhz << 2); + tmp222__ |= (pSrc->he_ppdu_80_in_160_80p80Mhz << 3); + tmp222__ |= (pSrc->er_1x_he_ltf_gi << 4); + tmp222__ |= (pSrc->midamble_tx_rx_1x_he_ltf << 5); + tmp222__ |= (pSrc->dcm_max_bw << 6); + tmp222__ |= (pSrc->longer_than_16_he_sigb_ofdm_sym << 8); + tmp222__ |= (pSrc->non_trig_cqi_feedback << 9); + tmp222__ |= (pSrc->tx_1024_qam_lt_242_tone_ru << 10); + tmp222__ |= (pSrc->rx_1024_qam_lt_242_tone_ru << 11); + tmp222__ |= (pSrc->rx_full_bw_su_he_mu_compress_sigb << 12); + tmp222__ |= (pSrc->rx_full_bw_su_he_mu_non_cmpr_sigb << 13); + tmp222__ |= (pSrc->reserved3 << 14); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp222__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + *pBuf = pSrc->reserved4; + *pnConsumed += 1; + pBuf += 1; + frameshtons(pCtx, pBuf, pSrc->rx_he_mcs_map_lt_80, 0); + *pnConsumed += 2; + pBuf += 2; + frameshtons(pCtx, pBuf, pSrc->tx_he_mcs_map_lt_80, 0); + *pnConsumed += 2; + pBuf += 2; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rx_he_mcs_map_160), (pSrc->chan_width_2 * 2)); + *pnConsumed += (pSrc->chan_width_2 * 2); + pBuf += (pSrc->chan_width_2 * 2); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->tx_he_mcs_map_160), (pSrc->chan_width_2 * 2)); + *pnConsumed += (pSrc->chan_width_2 * 2); + pBuf += (pSrc->chan_width_2 * 2); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->rx_he_mcs_map_80_80), (pSrc->chan_width_3 * 2)); + *pnConsumed += (pSrc->chan_width_3 * 2); + pBuf += (pSrc->chan_width_3 * 2); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->tx_he_mcs_map_80_80), (pSrc->chan_width_3 * 2)); + *pnConsumed += (pSrc->chan_width_3 * 2); + pBuf += (pSrc->chan_width_3 * 2); + if (pSrc->ppet_present) { + switch (pSrc->ppet_present) { + case 1: + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->ppet.ppe_threshold.ppe_th), pSrc->ppet.ppe_threshold.num_ppe_th); + *pnConsumed += pSrc->ppet.ppe_threshold.num_ppe_th; + /* fieldsEndFlag = 1 */ + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_he_cap. */ + +uint32_t dot11f_pack_ie_he_op(tpAniSirGlobal pCtx, + tDot11fIEhe_op *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp223__; + uint8_t tmp224__; + uint8_t tmp225__; + uint8_t tmp226__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_he_op(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 36; + ++pBuf; ++(*pnConsumed); + tmp223__ = 0U; + tmp223__ |= (pSrc->default_pe << 0); + tmp223__ |= (pSrc->twt_required << 3); + tmp223__ |= (pSrc->txop_rts_threshold << 4); + tmp223__ |= (pSrc->vht_oper_present << 14); + tmp223__ |= (pSrc->co_located_bss << 15); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp223__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + tmp224__ = 0U; + tmp224__ |= (pSrc->er_su_disable << 0); + tmp224__ |= (pSrc->oper_info_6g_present << 1); + tmp224__ |= (pSrc->reserved2 << 2); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp224__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp225__ = 0U; + tmp225__ |= (pSrc->bss_color << 0); + tmp225__ |= (pSrc->partial_bss_col << 6); + tmp225__ |= (pSrc->bss_col_disabled << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp225__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->basic_mcs_nss, 2); + *pnConsumed += 2; + pBuf += 2; + if (pSrc->vht_oper_present) { + switch (pSrc->vht_oper_present) { + case 1: + *pBuf = pSrc->vht_oper.info.chan_width; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->vht_oper.info.center_freq_seg0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->vht_oper.info.center_freq_seg1; + *pnConsumed += 1; + pBuf += 1; + break; + } + } + if (pSrc->co_located_bss) { + switch (pSrc->co_located_bss) { + case 1: + *pBuf = pSrc->maxbssid_ind.info.data; + *pnConsumed += 1; + pBuf += 1; + break; + } + } + if (pSrc->oper_info_6g_present) { + switch (pSrc->oper_info_6g_present) { + case 1: + *pBuf = pSrc->oper_info_6g.info.primary_ch; + *pnConsumed += 1; + pBuf += 1; + tmp226__ = 0U; + tmp226__ |= (pSrc->oper_info_6g.info.ch_width << 0); + tmp226__ |= (pSrc->oper_info_6g.info.dup_bcon << 2); + tmp226__ |= (pSrc->oper_info_6g.info.reg_info << 3); + tmp226__ |= (pSrc->oper_info_6g.info.reserved << 6); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp226__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->oper_info_6g.info.center_freq_seg0; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->oper_info_6g.info.center_freq_seg1; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->oper_info_6g.info.min_rate; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_he_op. */ + +uint32_t dot11f_pack_ie_hs20vendor_ie(tpAniSirGlobal pCtx, + tDot11fIEhs20vendor_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp227__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_hs20vendor_ie(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x10; + ++pBuf; ++(*pnConsumed); + tmp227__ = 0U; + tmp227__ |= (pSrc->dgaf_dis << 0); + tmp227__ |= (pSrc->hs_id_present << 1); + tmp227__ |= (pSrc->reserved << 3); + tmp227__ |= (pSrc->release_num << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp227__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + if (pSrc->hs_id_present) { + switch (pSrc->hs_id_present) { + case 1: + frameshtons(pCtx, pBuf, pSrc->hs_id.pps_mo.pps_mo_id, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + case 2: + frameshtons(pCtx, pBuf, pSrc->hs_id.anqp_domain.anqp_domain_id, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_hs20vendor_ie. */ + +uint32_t dot11f_pack_ie_ht2040_bss_coexistence(tpAniSirGlobal pCtx, + tDot11fIEht2040_bss_coexistence *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp228__; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 72; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp228__ = 0U; + tmp228__ |= (pSrc->info_request << 0); + tmp228__ |= (pSrc->forty_mhz_intolerant << 1); + tmp228__ |= (pSrc->twenty_mhz_bsswidth_req << 2); + tmp228__ |= (pSrc->obss_scan_exemption_req << 3); + tmp228__ |= (pSrc->obss_scan_exemption_grant << 4); + tmp228__ |= (pSrc->unused << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp228__; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + nBuf -= 1 ; + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht2040_bss_coexistence. */ + +uint32_t dot11f_pack_ie_ht2040_bss_intolerant_report(tpAniSirGlobal pCtx, + tDot11fIEht2040_bss_intolerant_report *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += (pSrc->num_channel_list + 1); + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 73; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->operating_class; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->channel_list), pSrc->num_channel_list); + *pnConsumed += pSrc->num_channel_list; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_ht2040_bss_intolerant_report. */ + +uint32_t dot11f_pack_ie_max_chan_switch_time(tpAniSirGlobal pCtx, + tDot11fIEmax_chan_switch_time *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 52; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, pSrc->switch_time, 3); + *pnConsumed += 3; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_max_chan_switch_time. */ + +uint32_t dot11f_pack_ie_mlo_ie(tpAniSirGlobal pCtx, + tDot11fIEmlo_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 107; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_mlo_ie. */ + +uint32_t dot11f_pack_ie_mu_edca_param_set(tpAniSirGlobal pCtx, + tDot11fIEmu_edca_param_set *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp229__; + uint8_t tmp230__; + uint8_t tmp231__; + uint8_t tmp232__; + uint8_t tmp233__; + uint8_t tmp234__; + uint8_t tmp235__; + uint8_t tmp236__; + nNeeded += 13; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 38; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->qos; + *pnConsumed += 1; + pBuf += 1; + tmp229__ = 0U; + tmp229__ |= (pSrc->acbe_aifsn << 0); + tmp229__ |= (pSrc->acbe_acm << 4); + tmp229__ |= (pSrc->acbe_aci << 5); + tmp229__ |= (pSrc->unused1 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp229__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp230__ = 0U; + tmp230__ |= (pSrc->acbe_acwmin << 0); + tmp230__ |= (pSrc->acbe_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp230__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acbe_muedca_timer; + *pnConsumed += 1; + pBuf += 1; + tmp231__ = 0U; + tmp231__ |= (pSrc->acbk_aifsn << 0); + tmp231__ |= (pSrc->acbk_acm << 4); + tmp231__ |= (pSrc->acbk_aci << 5); + tmp231__ |= (pSrc->unused2 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp231__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp232__ = 0U; + tmp232__ |= (pSrc->acbk_acwmin << 0); + tmp232__ |= (pSrc->acbk_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp232__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acbk_muedca_timer; + *pnConsumed += 1; + pBuf += 1; + tmp233__ = 0U; + tmp233__ |= (pSrc->acvi_aifsn << 0); + tmp233__ |= (pSrc->acvi_acm << 4); + tmp233__ |= (pSrc->acvi_aci << 5); + tmp233__ |= (pSrc->unused3 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp233__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp234__ = 0U; + tmp234__ |= (pSrc->acvi_acwmin << 0); + tmp234__ |= (pSrc->acvi_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp234__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acvi_muedca_timer; + *pnConsumed += 1; + pBuf += 1; + tmp235__ = 0U; + tmp235__ |= (pSrc->acvo_aifsn << 0); + tmp235__ |= (pSrc->acvo_acm << 4); + tmp235__ |= (pSrc->acvo_aci << 5); + tmp235__ |= (pSrc->unused4 << 7); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp235__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + tmp236__ = 0U; + tmp236__ |= (pSrc->acvo_acwmin << 0); + tmp236__ |= (pSrc->acvo_acwmax << 4); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp236__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + *pBuf = pSrc->acvo_muedca_timer; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_mu_edca_param_set. */ + +uint32_t dot11f_pack_ie_non_inheritance(tpAniSirGlobal pCtx, + tDot11fIEnon_inheritance *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 56; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_non_inheritance. */ + +uint32_t dot11f_pack_ie_oci(tpAniSirGlobal pCtx, + tDot11fIEoci *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 3; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 54; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->op_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->prim_ch_num; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->freq_seg_1_ch_num; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_oci. */ + +uint32_t dot11f_pack_ie_osen_ie(tpAniSirGlobal pCtx, + tDot11fIEosen_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x12; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_osen_ie. */ + +uint32_t dot11f_pack_ie_qcn_ie(tpAniSirGlobal pCtx, + tDot11fIEqcn_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t n, idx = 0, idxlast; + uint32_t nConsumedSoFar, nConsumedNow; + uint32_t status = DOT11F_PARSE_SUCCESS; + uint32_t nNeeded = 0U; + status = dot11f_get_packed_ie_qcn_ie(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + (void)pCtx; + if (pSrc->present) { + do { + nConsumedSoFar = *pnConsumed; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x8c; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xfd; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0xf0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x1; + ++pBuf; --nBuf; ++(*pnConsumed); + n = (255 - 4) < nBuf ? (255 - 4) : nBuf; + nConsumedNow = *pnConsumed; + idxlast = idx; + status = pack_tlv_core(pCtx, (uint8_t *)pSrc, pBuf, n, + pnConsumed, + TLVS_qcn_ie + + idx, &idx); + nConsumedNow = *pnConsumed - nConsumedNow; + *pIeLen = *pnConsumed - nConsumedSoFar - 2; + pBuf += nConsumedNow; + nBuf -= nConsumedNow; + } while (DOT11F_BUFFER_OVERFLOW == status && idxlast != idx); + } + return status; +} /* End dot11f_pack_ie_qcn_ie. */ + +uint32_t dot11f_pack_ie_reduced_neighbor_report(tpAniSirGlobal pCtx, + tDot11fIEreduced_neighbor_report *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint16_t tmp237__; + uint16_t tmp238__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_reduced_neighbor_report(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 201; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + tmp237__ = 0U; + tmp237__ |= (pSrc->tbtt_type << 0); + tmp237__ |= (pSrc->filtered_neighbor_ap << 2); + tmp237__ |= (pSrc->reserved << 3); + tmp237__ |= (pSrc->tbtt_info_count << 4); + tmp237__ |= (pSrc->tbtt_info_len << 8); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp237__, 0); + *pnConsumed += 2; + pBuf += 2; + nBuf -= 2 ; + *pBuf = pSrc->op_class; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->channel_num; + *pnConsumed += 1; + pBuf += 1; + switch (pSrc->tbtt_info_len) { + case 1: + *pBuf = pSrc->tbtt_info.tbtt_info_1.tbtt_offset; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 2: + *pBuf = pSrc->tbtt_info.tbtt_info_2.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->tbtt_info.tbtt_info_2.bss_params; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 5: + *pBuf = pSrc->tbtt_info.tbtt_info_5.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_5.short_ssid, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + case 6: + *pBuf = pSrc->tbtt_info.tbtt_info_6.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + frameshtonl(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_6.short_ssid, 0); + *pnConsumed += 4; + pBuf += 4; + *pBuf = pSrc->tbtt_info.tbtt_info_6.bss_params; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 7: + *pBuf = pSrc->tbtt_info.tbtt_info_7.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_7.bssid, 6); + *pnConsumed += 6; + /* fieldsEndFlag = 1 */ + break; + case 8: + *pBuf = pSrc->tbtt_info.tbtt_info_8.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_8.bssid, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->tbtt_info.tbtt_info_8.bss_params; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 9: + *pBuf = pSrc->tbtt_info.tbtt_info_9.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_9.bssid, 6); + *pnConsumed += 6; + pBuf += 6; + *pBuf = pSrc->tbtt_info.tbtt_info_9.bss_params; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->tbtt_info.tbtt_info_9.psd_20mhz; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 11: + *pBuf = pSrc->tbtt_info.tbtt_info_11.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_11.bssid, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtonl(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_11.short_ssid, 0); + *pnConsumed += 4; + /* fieldsEndFlag = 1 */ + break; + case 12: + *pBuf = pSrc->tbtt_info.tbtt_info_12.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_12.bssid, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtonl(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_12.short_ssid, 0); + *pnConsumed += 4; + pBuf += 4; + *pBuf = pSrc->tbtt_info.tbtt_info_12.bss_params; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 13: + *pBuf = pSrc->tbtt_info.tbtt_info_13.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_13.bssid, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtonl(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_13.short_ssid, 0); + *pnConsumed += 4; + pBuf += 4; + *pBuf = pSrc->tbtt_info.tbtt_info_13.bss_params; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->tbtt_info.tbtt_info_13.psd_20mhz; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + case 16: + *pBuf = pSrc->tbtt_info.tbtt_info_16.tbtt_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_16.bssid, 6); + *pnConsumed += 6; + pBuf += 6; + frameshtonl(pCtx, pBuf, pSrc->tbtt_info.tbtt_info_16.short_ssid, 0); + *pnConsumed += 4; + pBuf += 4; + *pBuf = pSrc->tbtt_info.tbtt_info_16.bss_params; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->tbtt_info.tbtt_info_16.psd_20mhz; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->tbtt_info.tbtt_info_16.mld_id; + *pnConsumed += 1; + pBuf += 1; + tmp238__ = 0U; + tmp238__ |= (pSrc->tbtt_info.tbtt_info_16.link_id << 0); + tmp238__ |= (pSrc->tbtt_info.tbtt_info_16.bss_param_change_cnt << 4); + tmp238__ |= (pSrc->tbtt_info.tbtt_info_16.all_updates_included << 12); + tmp238__ |= (pSrc->tbtt_info.tbtt_info_16.reserved << 13); + if (unlikely(nBuf < 2)) + return DOT11F_INCOMPLETE_IE; + + frameshtons(pCtx, pBuf, tmp238__, 0); + *pnConsumed += 2; + /* fieldsEndFlag = 1 */ + nBuf -= 2 ; + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_reduced_neighbor_report. */ + +uint32_t dot11f_pack_ie_roaming_consortium_sel(tpAniSirGlobal pCtx, + tDot11fIEroaming_consortium_sel *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x50; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x6f; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x9a; + ++pBuf; ++(*pnConsumed); + *pBuf = 0x1d; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_roaming_consortium_sel. */ + +uint32_t dot11f_pack_ie_sec_chan_offset_ele(tpAniSirGlobal pCtx, + tDot11fIEsec_chan_offset_ele *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += 1; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 62; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = pSrc->secondaryChannelOffset; + *pnConsumed += 1; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_sec_chan_offset_ele. */ + +uint32_t dot11f_pack_ie_spatial_reuse(tpAniSirGlobal pCtx, + tDot11fIEspatial_reuse *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint8_t tmp239__; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_spatial_reuse(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 39; + ++pBuf; ++(*pnConsumed); + tmp239__ = 0U; + tmp239__ |= (pSrc->psr_disallow << 0); + tmp239__ |= (pSrc->non_srg_pd_sr_disallow << 1); + tmp239__ |= (pSrc->non_srg_offset_present << 2); + tmp239__ |= (pSrc->srg_info_present << 3); + tmp239__ |= (pSrc->sr_value15_allow << 4); + tmp239__ |= (pSrc->reserved << 5); + if (unlikely(nBuf < 1)) + return DOT11F_INCOMPLETE_IE; + + *pBuf = tmp239__; + *pnConsumed += 1; + pBuf += 1; + nBuf -= 1 ; + if (pSrc->non_srg_offset_present) { + switch (pSrc->non_srg_offset_present) { + case 1: + *pBuf = pSrc->non_srg_offset.info.non_srg_pd_max_offset; + *pnConsumed += 1; + pBuf += 1; + break; + } + } else { + break; + } + if (pSrc->srg_info_present) { + switch (pSrc->srg_info_present) { + case 1: + *pBuf = pSrc->srg_info.info.srg_pd_min_offset; + *pnConsumed += 1; + pBuf += 1; + *pBuf = pSrc->srg_info.info.srg_pd_max_offset; + *pnConsumed += 1; + pBuf += 1; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->srg_info.info.srg_color, 8); + *pnConsumed += 8; + pBuf += 8; + DOT11F_MEMCPY(pCtx, pBuf, pSrc->srg_info.info.srg_partial_bssid, 8); + *pnConsumed += 8; + /* fieldsEndFlag = 1 */ + break; + } + } else { + break; + } + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_spatial_reuse. */ + +uint32_t dot11f_pack_ie_t2lm_ie(tpAniSirGlobal pCtx, + tDot11fIEt2lm_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + nNeeded += pSrc->num_data; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 255; + ++pBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; ++(*pnConsumed); + *pBuf = 109; + ++pBuf; ++(*pnConsumed); + DOT11F_MEMCPY(pCtx, pBuf, &(pSrc->data), pSrc->num_data); + *pnConsumed += pSrc->num_data; + /* fieldsEndFlag = 1 */ + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return DOT11F_PARSE_SUCCESS; +} /* End dot11f_pack_ie_t2lm_ie. */ + +uint32_t dot11f_pack_ie_vendor_vht_ie(tpAniSirGlobal pCtx, + tDot11fIEvendor_vht_ie *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed) +{ + uint8_t *pIeLen = 0; + uint32_t nConsumedOnEntry = *pnConsumed; + uint32_t nNeeded = 0U; + uint32_t status = DOT11F_PARSE_SUCCESS; + status = dot11f_get_packed_ie_vendor_vht_ie(pCtx, pSrc, &nNeeded); + if (!DOT11F_SUCCEEDED(status)) + return status; + while (pSrc->present) { + if (nNeeded > nBuf) + return DOT11F_BUFFER_OVERFLOW; + *pBuf = 221; + ++pBuf; --nBuf; ++(*pnConsumed); + pIeLen = pBuf; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x0; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x90; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4c; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = 0x4; + ++pBuf; --nBuf; ++(*pnConsumed); + *pBuf = pSrc->sub_type; + *pnConsumed += 1; + pBuf += 1; + status = pack_core(pCtx, + (uint8_t *)pSrc, + pBuf, + nBuf, + pnConsumed, + FFS_vendor_vht_ie, + IES_vendor_vht_ie); + break; + } + (void)pCtx; + if (pIeLen) { + *pIeLen = *pnConsumed - nConsumedOnEntry - 2; + } + return status; +} /* End dot11f_pack_ie_vendor_vht_ie. */ + +uint32_t dot11f_pack_add_ts_request(tpAniSirGlobal pCtx, + tDot11fAddTSRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AddTSRequest, IES_AddTSRequest); + + return status; + +} /* End dot11f_unpack_add_ts_request. */ + +uint32_t dot11f_pack_add_ts_response(tpAniSirGlobal pCtx, + tDot11fAddTSResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AddTSResponse, IES_AddTSResponse); + + return status; + +} /* End dot11f_unpack_add_ts_response. */ + +uint32_t dot11f_pack_assoc_request(tpAniSirGlobal pCtx, + tDot11fAssocRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AssocRequest, IES_AssocRequest); + + return status; + +} /* End dot11f_unpack_assoc_request. */ + +uint32_t dot11f_pack_assoc_response(tpAniSirGlobal pCtx, + tDot11fAssocResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_AssocResponse, IES_AssocResponse); + + return status; + +} /* End dot11f_unpack_assoc_response. */ + +uint32_t dot11f_pack_authentication(tpAniSirGlobal pCtx, + tDot11fAuthentication *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Authentication, IES_Authentication); + + return status; + +} /* End dot11f_unpack_authentication. */ + +uint32_t dot11f_pack_beacon(tpAniSirGlobal pCtx, + tDot11fBeacon *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon, IES_Beacon); + + return status; + +} /* End dot11f_unpack_beacon. */ + +uint32_t dot11f_pack_beacon1(tpAniSirGlobal pCtx, + tDot11fBeacon1 *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon1, IES_Beacon1); + + return status; + +} /* End dot11f_unpack_beacon1. */ + +uint32_t dot11f_pack_beacon2(tpAniSirGlobal pCtx, + tDot11fBeacon2 *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Beacon2, IES_Beacon2); + + return status; + +} /* End dot11f_unpack_beacon2. */ + +uint32_t dot11f_pack_beacon_i_es(tpAniSirGlobal pCtx, + tDot11fBeaconIEs *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_BeaconIEs, IES_BeaconIEs); + + return status; + +} /* End dot11f_unpack_beacon_i_es. */ + +uint32_t dot11f_pack_channel_switch(tpAniSirGlobal pCtx, + tDot11fChannelSwitch *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ChannelSwitch, IES_ChannelSwitch); + + return status; + +} /* End dot11f_unpack_channel_switch. */ + +uint32_t dot11f_pack_de_auth(tpAniSirGlobal pCtx, + tDot11fDeAuth *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_DeAuth, IES_DeAuth); + + return status; + +} /* End dot11f_unpack_de_auth. */ + +uint32_t dot11f_pack_del_ts(tpAniSirGlobal pCtx, + tDot11fDelTS *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_DelTS, IES_DelTS); + + return status; + +} /* End dot11f_unpack_del_ts. */ + +uint32_t dot11f_pack_disassociation(tpAniSirGlobal pCtx, + tDot11fDisassociation *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_Disassociation, IES_Disassociation); + + return status; + +} /* End dot11f_unpack_disassociation. */ + +uint32_t dot11f_pack_link_measurement_report(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_LinkMeasurementReport, IES_LinkMeasurementReport); + + return status; + +} /* End dot11f_unpack_link_measurement_report. */ + +uint32_t dot11f_pack_link_measurement_request(tpAniSirGlobal pCtx, + tDot11fLinkMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_LinkMeasurementRequest, IES_LinkMeasurementRequest); + + return status; + +} /* End dot11f_unpack_link_measurement_request. */ + +uint32_t dot11f_pack_measurement_report(tpAniSirGlobal pCtx, + tDot11fMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_MeasurementReport, IES_MeasurementReport); + + return status; + +} /* End dot11f_unpack_measurement_report. */ + +uint32_t dot11f_pack_measurement_request(tpAniSirGlobal pCtx, + tDot11fMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_MeasurementRequest, IES_MeasurementRequest); + + return status; + +} /* End dot11f_unpack_measurement_request. */ + +uint32_t dot11f_pack_neighbor_report_request(tpAniSirGlobal pCtx, + tDot11fNeighborReportRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_NeighborReportRequest, IES_NeighborReportRequest); + + return status; + +} /* End dot11f_unpack_neighbor_report_request. */ + +uint32_t dot11f_pack_neighbor_report_response(tpAniSirGlobal pCtx, + tDot11fNeighborReportResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_NeighborReportResponse, IES_NeighborReportResponse); + + return status; + +} /* End dot11f_unpack_neighbor_report_response. */ + +uint32_t dot11f_pack_operating_mode(tpAniSirGlobal pCtx, + tDot11fOperatingMode *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_OperatingMode, IES_OperatingMode); + + return status; + +} /* End dot11f_unpack_operating_mode. */ + +uint32_t dot11f_pack_probe_request(tpAniSirGlobal pCtx, + tDot11fProbeRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ProbeRequest, IES_ProbeRequest); + + return status; + +} /* End dot11f_unpack_probe_request. */ + +uint32_t dot11f_pack_probe_response(tpAniSirGlobal pCtx, + tDot11fProbeResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ProbeResponse, IES_ProbeResponse); + + return status; + +} /* End dot11f_unpack_probe_response. */ + +uint32_t dot11f_pack_qos_map_configure(tpAniSirGlobal pCtx, + tDot11fQosMapConfigure *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_QosMapConfigure, IES_QosMapConfigure); + + return status; + +} /* End dot11f_unpack_qos_map_configure. */ + +uint32_t dot11f_pack_radio_measurement_report(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_RadioMeasurementReport, IES_RadioMeasurementReport); + + return status; + +} /* End dot11f_unpack_radio_measurement_report. */ + +uint32_t dot11f_pack_radio_measurement_request(tpAniSirGlobal pCtx, + tDot11fRadioMeasurementRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_RadioMeasurementRequest, IES_RadioMeasurementRequest); + + return status; + +} /* End dot11f_unpack_radio_measurement_request. */ + +uint32_t dot11f_pack_re_assoc_request(tpAniSirGlobal pCtx, + tDot11fReAssocRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ReAssocRequest, IES_ReAssocRequest); + + return status; + +} /* End dot11f_unpack_re_assoc_request. */ + +uint32_t dot11f_pack_re_assoc_response(tpAniSirGlobal pCtx, + tDot11fReAssocResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ReAssocResponse, IES_ReAssocResponse); + + return status; + +} /* End dot11f_unpack_re_assoc_response. */ + +uint32_t dot11f_pack_sm_power_save(tpAniSirGlobal pCtx, + tDot11fSMPowerSave *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SMPowerSave, IES_SMPowerSave); + + return status; + +} /* End dot11f_unpack_sm_power_save. */ + +uint32_t dot11f_pack_sa_query_req(tpAniSirGlobal pCtx, + tDot11fSaQueryReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SaQueryReq, IES_SaQueryReq); + + return status; + +} /* End dot11f_unpack_sa_query_req. */ + +uint32_t dot11f_pack_sa_query_rsp(tpAniSirGlobal pCtx, + tDot11fSaQueryRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_SaQueryRsp, IES_SaQueryRsp); + + return status; + +} /* End dot11f_unpack_sa_query_rsp. */ + +uint32_t dot11f_pack_tdls_dis_req(tpAniSirGlobal pCtx, + tDot11fTDLSDisReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSDisReq, IES_TDLSDisReq); + + return status; + +} /* End dot11f_unpack_tdls_dis_req. */ + +uint32_t dot11f_pack_tdls_dis_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSDisRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSDisRsp, IES_TDLSDisRsp); + + return status; + +} /* End dot11f_unpack_tdls_dis_rsp. */ + +uint32_t dot11f_pack_tdls_peer_traffic_ind(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficInd *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSPeerTrafficInd, IES_TDLSPeerTrafficInd); + + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_ind. */ + +uint32_t dot11f_pack_tdls_peer_traffic_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSPeerTrafficRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSPeerTrafficRsp, IES_TDLSPeerTrafficRsp); + + return status; + +} /* End dot11f_unpack_tdls_peer_traffic_rsp. */ + +uint32_t dot11f_pack_tdls_setup_cnf(tpAniSirGlobal pCtx, + tDot11fTDLSSetupCnf *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupCnf, IES_TDLSSetupCnf); + + return status; + +} /* End dot11f_unpack_tdls_setup_cnf. */ + +uint32_t dot11f_pack_tdls_setup_req(tpAniSirGlobal pCtx, + tDot11fTDLSSetupReq *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupReq, IES_TDLSSetupReq); + + return status; + +} /* End dot11f_unpack_tdls_setup_req. */ + +uint32_t dot11f_pack_tdls_setup_rsp(tpAniSirGlobal pCtx, + tDot11fTDLSSetupRsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSSetupRsp, IES_TDLSSetupRsp); + + return status; + +} /* End dot11f_unpack_tdls_setup_rsp. */ + +uint32_t dot11f_pack_tdls_teardown(tpAniSirGlobal pCtx, + tDot11fTDLSTeardown *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TDLSTeardown, IES_TDLSTeardown); + + return status; + +} /* End dot11f_unpack_tdls_teardown. */ + +uint32_t dot11f_pack_tpc_report(tpAniSirGlobal pCtx, + tDot11fTPCReport *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TPCReport, IES_TPCReport); + + return status; + +} /* End dot11f_unpack_tpc_report. */ + +uint32_t dot11f_pack_tpc_request(tpAniSirGlobal pCtx, + tDot11fTPCRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TPCRequest, IES_TPCRequest); + + return status; + +} /* End dot11f_unpack_tpc_request. */ + +uint32_t dot11f_pack_timing_advertisement_frame(tpAniSirGlobal pCtx, + tDot11fTimingAdvertisementFrame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_TimingAdvertisementFrame, IES_TimingAdvertisementFrame); + + return status; + +} /* End dot11f_unpack_timing_advertisement_frame. */ + +uint32_t dot11f_pack_vht_gid_management_action_frame(tpAniSirGlobal pCtx, + tDot11fVHTGidManagementActionFrame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_VHTGidManagementActionFrame, IES_VHTGidManagementActionFrame); + + return status; + +} /* End dot11f_unpack_vht_gid_management_action_frame. */ + +uint32_t dot11f_pack_wmm_add_ts_request(tpAniSirGlobal pCtx, + tDot11fWMMAddTSRequest *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMAddTSRequest, IES_WMMAddTSRequest); + + return status; + +} /* End dot11f_unpack_wmm_add_ts_request. */ + +uint32_t dot11f_pack_wmm_add_ts_response(tpAniSirGlobal pCtx, + tDot11fWMMAddTSResponse *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMAddTSResponse, IES_WMMAddTSResponse); + + return status; + +} /* End dot11f_unpack_wmm_add_ts_response. */ + +uint32_t dot11f_pack_wmm_del_ts(tpAniSirGlobal pCtx, + tDot11fWMMDelTS *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_WMMDelTS, IES_WMMDelTS); + + return status; + +} /* End dot11f_unpack_wmm_del_ts. */ + +uint32_t dot11f_pack_addba_req(tpAniSirGlobal pCtx, + tDot11faddba_req *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_addba_req, IES_addba_req); + + return status; + +} /* End dot11f_unpack_addba_req. */ + +uint32_t dot11f_pack_addba_rsp(tpAniSirGlobal pCtx, + tDot11faddba_rsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_addba_rsp, IES_addba_rsp); + + return status; + +} /* End dot11f_unpack_addba_rsp. */ + +uint32_t dot11f_pack_delba_req(tpAniSirGlobal pCtx, + tDot11fdelba_req *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_delba_req, IES_delba_req); + + return status; + +} /* End dot11f_unpack_delba_req. */ + +uint32_t dot11f_pack_epcs_neg_req(tpAniSirGlobal pCtx, + tDot11fepcs_neg_req *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_epcs_neg_req, IES_epcs_neg_req); + + return status; + +} /* End dot11f_unpack_epcs_neg_req. */ + +uint32_t dot11f_pack_epcs_neg_rsp(tpAniSirGlobal pCtx, + tDot11fepcs_neg_rsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_epcs_neg_rsp, IES_epcs_neg_rsp); + + return status; + +} /* End dot11f_unpack_epcs_neg_rsp. */ + +uint32_t dot11f_pack_epcs_teardown(tpAniSirGlobal pCtx, + tDot11fepcs_teardown *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_epcs_teardown, IES_epcs_teardown); + + return status; + +} /* End dot11f_unpack_epcs_teardown. */ + +uint32_t dot11f_pack_ext_channel_switch_action_frame(tpAniSirGlobal pCtx, + tDot11fext_channel_switch_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ext_channel_switch_action_frame, IES_ext_channel_switch_action_frame); + + return status; + +} /* End dot11f_unpack_ext_channel_switch_action_frame. */ + +uint32_t dot11f_pack_ht2040_bss_coexistence_mgmt_action_frame(tpAniSirGlobal pCtx, + tDot11fht2040_bss_coexistence_mgmt_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_ht2040_bss_coexistence_mgmt_action_frame, IES_ht2040_bss_coexistence_mgmt_action_frame); + + return status; + +} /* End dot11f_unpack_ht2040_bss_coexistence_mgmt_action_frame. */ + +uint32_t dot11f_pack_mscs_request_action_frame(tpAniSirGlobal pCtx, + tDot11fmscs_request_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_mscs_request_action_frame, IES_mscs_request_action_frame); + + return status; + +} /* End dot11f_unpack_mscs_request_action_frame. */ + +uint32_t dot11f_pack_p2p_oper_chan_change_confirm(tpAniSirGlobal pCtx, + tDot11fp2p_oper_chan_change_confirm *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_p2p_oper_chan_change_confirm, IES_p2p_oper_chan_change_confirm); + + return status; + +} /* End dot11f_unpack_p2p_oper_chan_change_confirm. */ + +uint32_t dot11f_pack_t2lm_neg_req(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_req *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_t2lm_neg_req, IES_t2lm_neg_req); + + return status; + +} /* End dot11f_unpack_t2lm_neg_req. */ + +uint32_t dot11f_pack_t2lm_neg_rsp(tpAniSirGlobal pCtx, + tDot11ft2lm_neg_rsp *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_t2lm_neg_rsp, IES_t2lm_neg_rsp); + + return status; + +} /* End dot11f_unpack_t2lm_neg_rsp. */ + +uint32_t dot11f_pack_t2lm_teardown(tpAniSirGlobal pCtx, + tDot11ft2lm_teardown *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_t2lm_teardown, IES_t2lm_teardown); + + return status; + +} /* End dot11f_unpack_t2lm_teardown. */ + +uint32_t dot11f_pack_vendor_action_frame(tpAniSirGlobal pCtx, + tDot11fvendor_action_frame *pFrm, + uint8_t *pBuf, uint32_t nBuf, uint32_t *pnConsumed) +{ + uint32_t i = 0; + uint32_t status = 0; + (void)i; + *pnConsumed = 0U; + status = pack_core(pCtx, (uint8_t *)pFrm, pBuf, nBuf, pnConsumed, + FFS_vendor_action_frame, IES_vendor_action_frame); + + return status; + +} /* End dot11f_unpack_vendor_action_frame. */ + +static uint32_t pack_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tFFDefn FFs[], + const tIEDefn IEs[]) +{ + const tFFDefn *pFf; + const tIEDefn *pIe; + tFRAMES_BOOL *pfFound; + uint8_t *pBufRemaining; + uint16_t i; + uint32_t nBufRemaining, status, len; + uint32_t countOffset = 0; + + (void)pCtx; /* Shutup the compiler if we have no FFs nor IEs... */ + i = 0; + + DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed); + + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pFf = &(FFs[0]); + while (pFf->size) { + if (pFf->size > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The Fixed Field %s req" + "uires %d bytes, but there are only %d remaining.\n"), + pFf->name, pFf->size, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + switch (pFf->sig) { + case SigFfAID: + dot11f_pack_ff_aid( + pCtx, (tDot11fFfAID *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAction: + dot11f_pack_ff_action( + pCtx, (tDot11fFfAction *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAuthAlgo: + dot11f_pack_ff_auth_algo( + pCtx, (tDot11fFfAuthAlgo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfAuthSeqNo: + dot11f_pack_ff_auth_seq_no( + pCtx, (tDot11fFfAuthSeqNo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfBeaconInterval: + dot11f_pack_ff_beacon_interval( + pCtx, (tDot11fFfBeaconInterval *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCapabilities: + dot11f_pack_ff_capabilities( + pCtx, (tDot11fFfCapabilities *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCategory: + dot11f_pack_ff_category( + pCtx, (tDot11fFfCategory *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfCurrentAPAddress: + dot11f_pack_ff_current_ap_address( + pCtx, (tDot11fFfCurrentAPAddress *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfDialogToken: + dot11f_pack_ff_dialog_token( + pCtx, (tDot11fFfDialogToken *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfLinkMargin: + dot11f_pack_ff_link_margin( + pCtx, (tDot11fFfLinkMargin *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfListenInterval: + dot11f_pack_ff_listen_interval( + pCtx, (tDot11fFfListenInterval *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfMaxTxPower: + dot11f_pack_ff_max_tx_power( + pCtx, (tDot11fFfMaxTxPower *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfNumOfRepetitions: + dot11f_pack_ff_num_of_repetitions( + pCtx, (tDot11fFfNumOfRepetitions *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfOperatingMode: + dot11f_pack_ff_operating_mode( + pCtx, (tDot11fFfOperatingMode *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRCPI: + dot11f_pack_ff_rcpi( + pCtx, (tDot11fFfRCPI *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRSNI: + dot11f_pack_ff_rsni( + pCtx, (tDot11fFfRSNI *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfReason: + dot11f_pack_ff_reason( + pCtx, (tDot11fFfReason *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfRxAntennaId: + dot11f_pack_ff_rx_antenna_id( + pCtx, (tDot11fFfRxAntennaId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfSMPowerModeSet: + dot11f_pack_ff_sm_power_mode_set( + pCtx, (tDot11fFfSMPowerModeSet *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfStatus: + dot11f_pack_ff_status( + pCtx, (tDot11fFfStatus *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfStatusCode: + dot11f_pack_ff_status_code( + pCtx, (tDot11fFfStatusCode *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTPCEleID: + dot11f_pack_ff_tpc_ele_id( + pCtx, (tDot11fFfTPCEleID *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTPCEleLen: + dot11f_pack_ff_tpc_ele_len( + pCtx, (tDot11fFfTPCEleLen *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTSInfo: + dot11f_pack_ff_ts_info( + pCtx, (tDot11fFfTSInfo *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTimeStamp: + dot11f_pack_ff_time_stamp( + pCtx, (tDot11fFfTimeStamp *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTransactionId: + dot11f_pack_ff_transaction_id( + pCtx, (tDot11fFfTransactionId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTxAntennaId: + dot11f_pack_ff_tx_antenna_id( + pCtx, (tDot11fFfTxAntennaId *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfTxPower: + dot11f_pack_ff_tx_power( + pCtx, (tDot11fFfTxPower *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfVhtMembershipStatusArray: + dot11f_pack_ff_vht_membership_status_array( + pCtx, (tDot11fFfVhtMembershipStatusArray *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfVhtUserPositionArray: + dot11f_pack_ff_vht_user_position_array( + pCtx, (tDot11fFfVhtUserPositionArray *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfaddba_param_set: + dot11f_pack_ff_addba_param_set( + pCtx, (tDot11fFfaddba_param_set *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfba_start_seq_ctrl: + dot11f_pack_ff_ba_start_seq_ctrl( + pCtx, (tDot11fFfba_start_seq_ctrl *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfba_timeout: + dot11f_pack_ff_ba_timeout( + pCtx, (tDot11fFfba_timeout *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfdelba_param_set: + dot11f_pack_ff_delba_param_set( + pCtx, (tDot11fFfdelba_param_set *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfext_chan_switch_ann_action: + dot11f_pack_ff_ext_chan_switch_ann_action( + pCtx, (tDot11fFfext_chan_switch_ann_action *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfp2p_action_oui: + dot11f_pack_ff_p2p_action_oui( + pCtx, (tDot11fFfp2p_action_oui *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfp2p_action_subtype: + dot11f_pack_ff_p2p_action_subtype( + pCtx, (tDot11fFfp2p_action_subtype *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfvendor_action_subtype: + dot11f_pack_ff_vendor_action_subtype( + pCtx, (tDot11fFfvendor_action_subtype *) + (pSrc + pFf->offset), pBufRemaining); + break; + case SigFfvendor_oui: + dot11f_pack_ff_vendor_oui( + pCtx, (tDot11fFfvendor_oui *) + (pSrc + pFf->offset), pBufRemaining); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the Fixed Field %d; this is most l" + "ikely a bug in 'framesg'.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += pFf->size; + nBufRemaining -= pFf->size; + *pnConsumed += pFf->size; + ++pFf; + + } + + pIe = &(IEs[0]); + while (0xff != pIe->eid || pIe->extn_eid) { + pfFound = (tFRAMES_BOOL *)(pSrc + pIe->offset + + pIe->presenceOffset); + if (*pfFound && pIe->minSize > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The IE %s takes at le" + "ast %d bytes, but there are only %d left in the b" + "uffer.\n"), pIe->name, pIe->minSize, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + + countOffset = ((0 == pIe->arraybound) ? 1 : *(uint16_t *)(pSrc + pIe->countOffset)); + for (i = 0; i < countOffset; ++i) { + len = 0U; + switch (pIe->sig) { + case SigIeGTK: + status |= + dot11f_pack_ie_gtk( + pCtx, (tDot11fIEGTK *) + (pSrc + pIe->offset + + sizeof(tDot11fIEGTK) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeIGTK: + status |= + dot11f_pack_ie_igtk( + pCtx, (tDot11fIEIGTK *) + (pSrc + pIe->offset + + sizeof(tDot11fIEIGTK) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeR0KH_ID: + status |= + dot11f_pack_ie_r0_kh_id( + pCtx, (tDot11fIER0KH_ID *) + (pSrc + pIe->offset + + sizeof(tDot11fIER0KH_ID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeR1KH_ID: + status |= + dot11f_pack_ie_r1_kh_id( + pCtx, (tDot11fIER1KH_ID *) + (pSrc + pIe->offset + + sizeof(tDot11fIER1KH_ID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeAPChannelReport: + status |= + dot11f_pack_ie_ap_channel_report( + pCtx, (tDot11fIEAPChannelReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIEAPChannelReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBcnReportingDetail: + status |= + dot11f_pack_ie_bcn_reporting_detail( + pCtx, (tDot11fIEBcnReportingDetail *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBcnReportingDetail) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeBeaconReportFrmBody: + status |= + dot11f_pack_ie_beacon_report_frm_body( + pCtx, (tDot11fIEBeaconReportFrmBody *) + (pSrc + pIe->offset + + sizeof(tDot11fIEBeaconReportFrmBody) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCondensedCountryStr: + status |= + dot11f_pack_ie_condensed_country_str( + pCtx, (tDot11fIECondensedCountryStr *) + (pSrc + pIe->offset + + sizeof(tDot11fIECondensedCountryStr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtRequestedInfo: + status |= + dot11f_pack_ie_ExtRequestedInfo( + pCtx, (tDot11fIEExtRequestedInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtRequestedInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementPilot: + status |= + dot11f_pack_ie_measurement_pilot( + pCtx, (tDot11fIEMeasurementPilot *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementPilot) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMultiBssid: + status |= + dot11f_pack_ie_multi_bssid( + pCtx, (tDot11fIEMultiBssid *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMultiBssid) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICData: + status |= + dot11f_pack_ie_ric_data( + pCtx, (tDot11fIERICData *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICData) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICDescriptor: + status |= + dot11f_pack_ie_ric_descriptor( + pCtx, (tDot11fIERICDescriptor *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICDescriptor) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRRMEnabledCap: + status |= + dot11f_pack_ie_rrm_enabled_cap( + pCtx, (tDot11fIERRMEnabledCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIERRMEnabledCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRequestedInfo: + status |= + dot11f_pack_ie_requested_info( + pCtx, (tDot11fIERequestedInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIERequestedInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSSID: + status |= + dot11f_pack_ie_ssid( + pCtx, (tDot11fIESSID *) + (pSrc + pIe->offset + + sizeof(tDot11fIESSID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSchedule: + status |= + dot11f_pack_ie_schedule( + pCtx, (tDot11fIESchedule *) + (pSrc + pIe->offset + + sizeof(tDot11fIESchedule) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTCLAS: + status |= + dot11f_pack_ie_tclas( + pCtx, (tDot11fIETCLAS *) + (pSrc + pIe->offset + + sizeof(tDot11fIETCLAS) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTCLASSPROC: + status |= + dot11f_pack_ie_tclassproc( + pCtx, (tDot11fIETCLASSPROC *) + (pSrc + pIe->offset + + sizeof(tDot11fIETCLASSPROC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSDelay: + status |= + dot11f_pack_ie_ts_delay( + pCtx, (tDot11fIETSDelay *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSDelay) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSFInfo: + status |= + dot11f_pack_ie_tsf_info( + pCtx, (tDot11fIETSFInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSFInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTSPEC: + status |= + dot11f_pack_ie_tspec( + pCtx, (tDot11fIETSPEC *) + (pSrc + pIe->offset + + sizeof(tDot11fIETSPEC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTCaps: + status |= + dot11f_pack_ie_vht_caps( + pCtx, (tDot11fIEVHTCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTOperation: + status |= + dot11f_pack_ie_vht_operation( + pCtx, (tDot11fIEVHTOperation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTOperation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMSchedule: + status |= + dot11f_pack_ie_wmm_schedule( + pCtx, (tDot11fIEWMMSchedule *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMSchedule) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTCLAS: + status |= + dot11f_pack_ie_wmmtclas( + pCtx, (tDot11fIEWMMTCLAS *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTCLAS) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTCLASPROC: + status |= + dot11f_pack_ie_wmmtclasproc( + pCtx, (tDot11fIEWMMTCLASPROC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTCLASPROC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTSDelay: + status |= + dot11f_pack_ie_wmmts_delay( + pCtx, (tDot11fIEWMMTSDelay *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTSDelay) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMTSPEC: + status |= + dot11f_pack_ie_wmmtspec( + pCtx, (tDot11fIEWMMTSPEC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMTSPEC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWiderBWChanSwitchAnn: + status |= + dot11f_pack_ie_wider_bw_chan_switch_ann( + pCtx, (tDot11fIEWiderBWChanSwitchAnn *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWiderBWChanSwitchAnn) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeazimuth_req: + status |= + dot11f_pack_ie_azimuth_req( + pCtx, (tDot11fIEazimuth_req *) + (pSrc + pIe->offset + + sizeof(tDot11fIEazimuth_req) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIebeacon_report_frm_body_fragment_id: + status |= + dot11f_pack_ie_beacon_report_frm_body_fragment_id( + pCtx, (tDot11fIEbeacon_report_frm_body_fragment_id *) + (pSrc + pIe->offset + + sizeof(tDot11fIEbeacon_report_frm_body_fragment_id) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIebw_ind_element: + status |= + dot11f_pack_ie_bw_ind_element( + pCtx, (tDot11fIEbw_ind_element *) + (pSrc + pIe->offset + + sizeof(tDot11fIEbw_ind_element) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIebw_indication: + status |= + dot11f_pack_ie_bw_indication( + pCtx, (tDot11fIEbw_indication *) + (pSrc + pIe->offset + + sizeof(tDot11fIEbw_indication) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIelast_beacon_report_indication: + status |= + dot11f_pack_ie_last_beacon_report_indication( + pCtx, (tDot11fIElast_beacon_report_indication *) + (pSrc + pIe->offset + + sizeof(tDot11fIElast_beacon_report_indication) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIemax_age: + status |= + dot11f_pack_ie_max_age( + pCtx, (tDot11fIEmax_age *) + (pSrc + pIe->offset + + sizeof(tDot11fIEmax_age) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIemscs_status: + status |= + dot11f_pack_ie_mscs_status( + pCtx, (tDot11fIEmscs_status *) + (pSrc + pIe->offset + + sizeof(tDot11fIEmscs_status) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeneighbor_rpt: + status |= + dot11f_pack_ie_neighbor_rpt( + pCtx, (tDot11fIEneighbor_rpt *) + (pSrc + pIe->offset + + sizeof(tDot11fIEneighbor_rpt) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIereporting_reason: + status |= + dot11f_pack_ie_reporting_reason( + pCtx, (tDot11fIEreporting_reason *) + (pSrc + pIe->offset + + sizeof(tDot11fIEreporting_reason) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIereq_mac_addr: + status |= + dot11f_pack_ie_req_mac_addr( + pCtx, (tDot11fIEreq_mac_addr *) + (pSrc + pIe->offset + + sizeof(tDot11fIEreq_mac_addr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIerrm_reporting: + status |= + dot11f_pack_ie_rrm_reporting( + pCtx, (tDot11fIErrm_reporting *) + (pSrc + pIe->offset + + sizeof(tDot11fIErrm_reporting) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIetclas_mask: + status |= + dot11f_pack_ie_tclas_mask( + pCtx, (tDot11fIEtclas_mask *) + (pSrc + pIe->offset + + sizeof(tDot11fIEtclas_mask) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIetgt_mac_addr: + status |= + dot11f_pack_ie_tgt_mac_addr( + pCtx, (tDot11fIEtgt_mac_addr *) + (pSrc + pIe->offset + + sizeof(tDot11fIEtgt_mac_addr) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIetransmit_power_env: + status |= + dot11f_pack_ie_transmit_power_env( + pCtx, (tDot11fIEtransmit_power_env *) + (pSrc + pIe->offset + + sizeof(tDot11fIEtransmit_power_env) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIewide_bw_chan_switch: + status |= + dot11f_pack_ie_wide_bw_chan_switch( + pCtx, (tDot11fIEwide_bw_chan_switch *) + (pSrc + pIe->offset + + sizeof(tDot11fIEwide_bw_chan_switch) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeAID: + status |= + dot11f_pack_ie_aid( + pCtx, (tDot11fIEAID *) + (pSrc + pIe->offset + + sizeof(tDot11fIEAID) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCFParams: + status |= + dot11f_pack_ie_cf_params( + pCtx, (tDot11fIECFParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIECFParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChallengeText: + status |= + dot11f_pack_ie_challenge_text( + pCtx, (tDot11fIEChallengeText *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChallengeText) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChanSwitchAnn: + status |= + dot11f_pack_ie_chan_switch_ann( + pCtx, (tDot11fIEChanSwitchAnn *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChanSwitchAnn) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeChannelSwitchWrapper: + status |= + dot11f_pack_ie_channel_switch_wrapper( + pCtx, (tDot11fIEChannelSwitchWrapper *) + (pSrc + pIe->offset + + sizeof(tDot11fIEChannelSwitchWrapper) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeCountry: + status |= + dot11f_pack_ie_country( + pCtx, (tDot11fIECountry *) + (pSrc + pIe->offset + + sizeof(tDot11fIECountry) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeDSParams: + status |= + dot11f_pack_ie_ds_params( + pCtx, (tDot11fIEDSParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEDSParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeEDCAParamSet: + status |= + dot11f_pack_ie_edca_param_set( + pCtx, (tDot11fIEEDCAParamSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEEDCAParamSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeERPInfo: + status |= + dot11f_pack_ie_erp_info( + pCtx, (tDot11fIEERPInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEERPInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESECckmOpaque: + status |= + dot11f_pack_ie_ese_cckm_opaque( + pCtx, (tDot11fIEESECckmOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESECckmOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESERadMgmtCap: + status |= + dot11f_pack_ie_ese_rad_mgmt_cap( + pCtx, (tDot11fIEESERadMgmtCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESERadMgmtCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETrafStrmMet: + status |= + dot11f_pack_ie_ese_traf_strm_met( + pCtx, (tDot11fIEESETrafStrmMet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETrafStrmMet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETrafStrmRateSet: + status |= + dot11f_pack_ie_ese_traf_strm_rate_set( + pCtx, (tDot11fIEESETrafStrmRateSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETrafStrmRateSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESETxmitPower: + status |= + dot11f_pack_ie_ese_txmit_power( + pCtx, (tDot11fIEESETxmitPower *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESETxmitPower) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeESEVersion: + status |= + dot11f_pack_ie_ese_version( + pCtx, (tDot11fIEESEVersion *) + (pSrc + pIe->offset + + sizeof(tDot11fIEESEVersion) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtCap: + status |= + dot11f_pack_ie_ext_cap( + pCtx, (tDot11fIEExtCap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtCap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeExtSuppRates: + status |= + dot11f_pack_ie_ext_supp_rates( + pCtx, (tDot11fIEExtSuppRates *) + (pSrc + pIe->offset + + sizeof(tDot11fIEExtSuppRates) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHParamSet: + status |= + dot11f_pack_ie_fh_param_set( + pCtx, (tDot11fIEFHParamSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHParamSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHParams: + status |= + dot11f_pack_ie_fh_params( + pCtx, (tDot11fIEFHParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFHPattTable: + status |= + dot11f_pack_ie_fh_patt_table( + pCtx, (tDot11fIEFHPattTable *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFHPattTable) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeFTInfo: + status |= + dot11f_pack_ie_ft_info( + pCtx, (tDot11fIEFTInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEFTInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeHTCaps: + status |= + dot11f_pack_ie_ht_caps( + pCtx, (tDot11fIEHTCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEHTCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeHTInfo: + status |= + dot11f_pack_ie_ht_info( + pCtx, (tDot11fIEHTInfo *) + (pSrc + pIe->offset + + sizeof(tDot11fIEHTInfo) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeLinkIdentifier: + status |= + dot11f_pack_ie_link_identifier( + pCtx, (tDot11fIELinkIdentifier *) + (pSrc + pIe->offset + + sizeof(tDot11fIELinkIdentifier) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMBO_IE: + status |= + dot11f_pack_ie_MBO_IE( + pCtx, (tDot11fIEMBO_IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMBO_IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementReport: + status |= + dot11f_pack_ie_measurement_report( + pCtx, (tDot11fIEMeasurementReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMeasurementRequest: + status |= + dot11f_pack_ie_measurement_request( + pCtx, (tDot11fIEMeasurementRequest *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMeasurementRequest) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeMobilityDomain: + status |= + dot11f_pack_ie_mobility_domain( + pCtx, (tDot11fIEMobilityDomain *) + (pSrc + pIe->offset + + sizeof(tDot11fIEMobilityDomain) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeNeighborReport: + status |= + dot11f_pack_ie_neighbor_report( + pCtx, (tDot11fIENeighborReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIENeighborReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeOBSSScanParameters: + status |= + dot11f_pack_ie_obss_scan_parameters( + pCtx, (tDot11fIEOBSSScanParameters *) + (pSrc + pIe->offset + + sizeof(tDot11fIEOBSSScanParameters) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeOperatingMode: + status |= + dot11f_pack_ie_operating_mode( + pCtx, (tDot11fIEOperatingMode *) + (pSrc + pIe->offset + + sizeof(tDot11fIEOperatingMode) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PAssocReq: + status |= + dot11f_pack_ie_p2_p_assoc_req( + pCtx, (tDot11fIEP2PAssocReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PAssocReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PAssocRes: + status |= + dot11f_pack_ie_p2_p_assoc_res( + pCtx, (tDot11fIEP2PAssocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PAssocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PBeacon: + status |= + dot11f_pack_ie_p2_p_beacon( + pCtx, (tDot11fIEP2PBeacon *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PBeacon) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PBeaconProbeRes: + status |= + dot11f_pack_ie_p2_p_beacon_probe_res( + pCtx, (tDot11fIEP2PBeaconProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PBeaconProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PDeAuth: + status |= + dot11f_pack_ie_p2_p_de_auth( + pCtx, (tDot11fIEP2PDeAuth *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PDeAuth) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PDisAssoc: + status |= + dot11f_pack_ie_p2_p_dis_assoc( + pCtx, (tDot11fIEP2PDisAssoc *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PDisAssoc) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PIEOpaque: + status |= + dot11f_pack_ie_p2_pie_opaque( + pCtx, (tDot11fIEP2PIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PProbeReq: + status |= + dot11f_pack_ie_p2_p_probe_req( + pCtx, (tDot11fIEP2PProbeReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PProbeReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeP2PProbeRes: + status |= + dot11f_pack_ie_p2_p_probe_res( + pCtx, (tDot11fIEP2PProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEP2PProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePTIControl: + status |= + dot11f_pack_ie_pti_control( + pCtx, (tDot11fIEPTIControl *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPTIControl) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePUBufferStatus: + status |= + dot11f_pack_ie_pu_buffer_status( + pCtx, (tDot11fIEPUBufferStatus *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPUBufferStatus) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePowerCaps: + status |= + dot11f_pack_ie_power_caps( + pCtx, (tDot11fIEPowerCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPowerCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIePowerConstraints: + status |= + dot11f_pack_ie_power_constraints( + pCtx, (tDot11fIEPowerConstraints *) + (pSrc + pIe->offset + + sizeof(tDot11fIEPowerConstraints) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQBSSLoad: + status |= + dot11f_pack_ie_qbss_load( + pCtx, (tDot11fIEQBSSLoad *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQBSSLoad) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQComVendorIE: + status |= + dot11f_pack_ie_QComVendorIE( + pCtx, (tDot11fIEQComVendorIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQComVendorIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQOSCapsAp: + status |= + dot11f_pack_ie_qos_caps_ap( + pCtx, (tDot11fIEQOSCapsAp *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQOSCapsAp) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQOSCapsStation: + status |= + dot11f_pack_ie_qos_caps_station( + pCtx, (tDot11fIEQOSCapsStation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQOSCapsStation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQosMapSet: + status |= + dot11f_pack_ie_qos_map_set( + pCtx, (tDot11fIEQosMapSet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQosMapSet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeQuiet: + status |= + dot11f_pack_ie_quiet( + pCtx, (tDot11fIEQuiet *) + (pSrc + pIe->offset + + sizeof(tDot11fIEQuiet) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRCPIIE: + status |= + dot11f_pack_ie_rcpiie( + pCtx, (tDot11fIERCPIIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIERCPIIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRICDataDesc: + status |= + dot11f_pack_ie_ric_data_desc( + pCtx, (tDot11fIERICDataDesc *) + (pSrc + pIe->offset + + sizeof(tDot11fIERICDataDesc) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSN: + status |= + dot11f_pack_ie_rsn( + pCtx, (tDot11fIERSN *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSN) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSNIIE: + status |= + dot11f_pack_ie_rsniie( + pCtx, (tDot11fIERSNIIE *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSNIIE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeRSNOpaque: + status |= + dot11f_pack_ie_rsn_opaque( + pCtx, (tDot11fIERSNOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIERSNOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppChannels: + status |= + dot11f_pack_ie_supp_channels( + pCtx, (tDot11fIESuppChannels *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppChannels) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppOperatingClasses: + status |= + dot11f_pack_ie_supp_operating_classes( + pCtx, (tDot11fIESuppOperatingClasses *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppOperatingClasses) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeSuppRates: + status |= + dot11f_pack_ie_supp_rates( + pCtx, (tDot11fIESuppRates *) + (pSrc + pIe->offset + + sizeof(tDot11fIESuppRates) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTIM: + status |= + dot11f_pack_ie_tim( + pCtx, (tDot11fIETIM *) + (pSrc + pIe->offset + + sizeof(tDot11fIETIM) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTPCReport: + status |= + dot11f_pack_ie_tpc_report( + pCtx, (tDot11fIETPCReport *) + (pSrc + pIe->offset + + sizeof(tDot11fIETPCReport) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTPCRequest: + status |= + dot11f_pack_ie_tpc_request( + pCtx, (tDot11fIETPCRequest *) + (pSrc + pIe->offset + + sizeof(tDot11fIETPCRequest) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTimeAdvertisement: + status |= + dot11f_pack_ie_time_advertisement( + pCtx, (tDot11fIETimeAdvertisement *) + (pSrc + pIe->offset + + sizeof(tDot11fIETimeAdvertisement) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeTimeoutInterval: + status |= + dot11f_pack_ie_timeout_interval( + pCtx, (tDot11fIETimeoutInterval *) + (pSrc + pIe->offset + + sizeof(tDot11fIETimeoutInterval) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVHTExtBssLoad: + status |= + dot11f_pack_ie_vht_ext_bss_load( + pCtx, (tDot11fIEVHTExtBssLoad *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVHTExtBssLoad) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVendor1IE: + status |= + dot11f_pack_ie_vendor1_ie( + pCtx, (tDot11fIEVendor1IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVendor1IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeVendor3IE: + status |= + dot11f_pack_ie_vendor3_ie( + pCtx, (tDot11fIEVendor3IE *) + (pSrc + pIe->offset + + sizeof(tDot11fIEVendor3IE) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWAPI: + status |= + dot11f_pack_ie_wapi( + pCtx, (tDot11fIEWAPI *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWAPI) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWAPIOpaque: + status |= + dot11f_pack_ie_wapi_opaque( + pCtx, (tDot11fIEWAPIOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWAPIOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWFATPC: + status |= + dot11f_pack_ie_wfatpc( + pCtx, (tDot11fIEWFATPC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWFATPC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWFDIEOpaque: + status |= + dot11f_pack_ie_wfdie_opaque( + pCtx, (tDot11fIEWFDIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWFDIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMCaps: + status |= + dot11f_pack_ie_wmm_caps( + pCtx, (tDot11fIEWMMCaps *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMCaps) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMInfoAp: + status |= + dot11f_pack_ie_wmm_info_ap( + pCtx, (tDot11fIEWMMInfoAp *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMInfoAp) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMInfoStation: + status |= + dot11f_pack_ie_wmm_info_station( + pCtx, (tDot11fIEWMMInfoStation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMInfoStation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWMMParams: + status |= + dot11f_pack_ie_wmm_params( + pCtx, (tDot11fIEWMMParams *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWMMParams) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWPA: + status |= + dot11f_pack_ie_wpa( + pCtx, (tDot11fIEWPA *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWPA) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWPAOpaque: + status |= + dot11f_pack_ie_wpa_opaque( + pCtx, (tDot11fIEWPAOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWPAOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWSC: + status |= + dot11f_pack_ie_wsc( + pCtx, (tDot11fIEWSC *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWSC) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscAssocReq: + status |= + dot11f_pack_ie_wsc_assoc_req( + pCtx, (tDot11fIEWscAssocReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscAssocReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscAssocRes: + status |= + dot11f_pack_ie_wsc_assoc_res( + pCtx, (tDot11fIEWscAssocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscAssocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscBeacon: + status |= + dot11f_pack_ie_wsc_beacon( + pCtx, (tDot11fIEWscBeacon *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscBeacon) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscBeaconProbeRes: + status |= + dot11f_pack_ie_wsc_beacon_probe_res( + pCtx, (tDot11fIEWscBeaconProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscBeaconProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscIEOpaque: + status |= + dot11f_pack_ie_wsc_ie_opaque( + pCtx, (tDot11fIEWscIEOpaque *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscIEOpaque) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscProbeReq: + status |= + dot11f_pack_ie_wsc_probe_req( + pCtx, (tDot11fIEWscProbeReq *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscProbeReq) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscProbeRes: + status |= + dot11f_pack_ie_wsc_probe_res( + pCtx, (tDot11fIEWscProbeRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscProbeRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeWscReassocRes: + status |= + dot11f_pack_ie_wsc_reassoc_res( + pCtx, (tDot11fIEWscReassocRes *) + (pSrc + pIe->offset + + sizeof(tDot11fIEWscReassocRes) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeaddba_extn_element: + status |= + dot11f_pack_ie_addba_extn_element( + pCtx, (tDot11fIEaddba_extn_element *) + (pSrc + pIe->offset + + sizeof(tDot11fIEaddba_extn_element) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIebss_color_change: + status |= + dot11f_pack_ie_bss_color_change( + pCtx, (tDot11fIEbss_color_change *) + (pSrc + pIe->offset + + sizeof(tDot11fIEbss_color_change) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIebss_max_idle_period: + status |= + dot11f_pack_ie_bss_max_idle_period( + pCtx, (tDot11fIEbss_max_idle_period *) + (pSrc + pIe->offset + + sizeof(tDot11fIEbss_max_idle_period) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIedescriptor_element: + status |= + dot11f_pack_ie_descriptor_element( + pCtx, (tDot11fIEdescriptor_element *) + (pSrc + pIe->offset + + sizeof(tDot11fIEdescriptor_element) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIedh_parameter_element: + status |= + dot11f_pack_ie_dh_parameter_element( + pCtx, (tDot11fIEdh_parameter_element *) + (pSrc + pIe->offset + + sizeof(tDot11fIEdh_parameter_element) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeeht_cap: + status |= + dot11f_pack_ie_eht_cap( + pCtx, (tDot11fIEeht_cap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEeht_cap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeeht_op: + status |= + dot11f_pack_ie_eht_op( + pCtx, (tDot11fIEeht_op *) + (pSrc + pIe->offset + + sizeof(tDot11fIEeht_op) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeesp_information: + status |= + dot11f_pack_ie_esp_information( + pCtx, (tDot11fIEesp_information *) + (pSrc + pIe->offset + + sizeof(tDot11fIEesp_information) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeext_chan_switch_ann: + status |= + dot11f_pack_ie_ext_chan_switch_ann( + pCtx, (tDot11fIEext_chan_switch_ann *) + (pSrc + pIe->offset + + sizeof(tDot11fIEext_chan_switch_ann) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_assoc_delay_info: + status |= + dot11f_pack_ie_fils_assoc_delay_info( + pCtx, (tDot11fIEfils_assoc_delay_info *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_assoc_delay_info) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_hlp_container: + status |= + dot11f_pack_ie_fils_hlp_container( + pCtx, (tDot11fIEfils_hlp_container *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_hlp_container) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_indication: + status |= + dot11f_pack_ie_fils_indication( + pCtx, (tDot11fIEfils_indication *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_indication) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_kde: + status |= + dot11f_pack_ie_fils_kde( + pCtx, (tDot11fIEfils_kde *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_kde) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_key_confirmation: + status |= + dot11f_pack_ie_fils_key_confirmation( + pCtx, (tDot11fIEfils_key_confirmation *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_key_confirmation) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_nonce: + status |= + dot11f_pack_ie_fils_nonce( + pCtx, (tDot11fIEfils_nonce *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_nonce) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_public_key: + status |= + dot11f_pack_ie_fils_public_key( + pCtx, (tDot11fIEfils_public_key *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_public_key) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_session: + status |= + dot11f_pack_ie_fils_session( + pCtx, (tDot11fIEfils_session *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_session) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefils_wrapped_data: + status |= + dot11f_pack_ie_fils_wrapped_data( + pCtx, (tDot11fIEfils_wrapped_data *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfils_wrapped_data) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIefragment_ie: + status |= + dot11f_pack_ie_fragment_ie( + pCtx, (tDot11fIEfragment_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEfragment_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIehe_6ghz_band_cap: + status |= + dot11f_pack_ie_he_6ghz_band_cap( + pCtx, (tDot11fIEhe_6ghz_band_cap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEhe_6ghz_band_cap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIehe_cap: + status |= + dot11f_pack_ie_he_cap( + pCtx, (tDot11fIEhe_cap *) + (pSrc + pIe->offset + + sizeof(tDot11fIEhe_cap) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIehe_op: + status |= + dot11f_pack_ie_he_op( + pCtx, (tDot11fIEhe_op *) + (pSrc + pIe->offset + + sizeof(tDot11fIEhe_op) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIehs20vendor_ie: + status |= + dot11f_pack_ie_hs20vendor_ie( + pCtx, (tDot11fIEhs20vendor_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEhs20vendor_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeht2040_bss_coexistence: + status |= + dot11f_pack_ie_ht2040_bss_coexistence( + pCtx, (tDot11fIEht2040_bss_coexistence *) + (pSrc + pIe->offset + + sizeof(tDot11fIEht2040_bss_coexistence) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeht2040_bss_intolerant_report: + status |= + dot11f_pack_ie_ht2040_bss_intolerant_report( + pCtx, (tDot11fIEht2040_bss_intolerant_report *) + (pSrc + pIe->offset + + sizeof(tDot11fIEht2040_bss_intolerant_report) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIemax_chan_switch_time: + status |= + dot11f_pack_ie_max_chan_switch_time( + pCtx, (tDot11fIEmax_chan_switch_time *) + (pSrc + pIe->offset + + sizeof(tDot11fIEmax_chan_switch_time) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIemlo_ie: + status |= + dot11f_pack_ie_mlo_ie( + pCtx, (tDot11fIEmlo_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEmlo_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIemu_edca_param_set: + status |= + dot11f_pack_ie_mu_edca_param_set( + pCtx, (tDot11fIEmu_edca_param_set *) + (pSrc + pIe->offset + + sizeof(tDot11fIEmu_edca_param_set) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIenon_inheritance: + status |= + dot11f_pack_ie_non_inheritance( + pCtx, (tDot11fIEnon_inheritance *) + (pSrc + pIe->offset + + sizeof(tDot11fIEnon_inheritance) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeoci: + status |= + dot11f_pack_ie_oci( + pCtx, (tDot11fIEoci *) + (pSrc + pIe->offset + + sizeof(tDot11fIEoci) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeosen_ie: + status |= + dot11f_pack_ie_osen_ie( + pCtx, (tDot11fIEosen_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEosen_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeqcn_ie: + status |= + dot11f_pack_ie_qcn_ie( + pCtx, (tDot11fIEqcn_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEqcn_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIereduced_neighbor_report: + status |= + dot11f_pack_ie_reduced_neighbor_report( + pCtx, (tDot11fIEreduced_neighbor_report *) + (pSrc + pIe->offset + + sizeof(tDot11fIEreduced_neighbor_report) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIeroaming_consortium_sel: + status |= + dot11f_pack_ie_roaming_consortium_sel( + pCtx, (tDot11fIEroaming_consortium_sel *) + (pSrc + pIe->offset + + sizeof(tDot11fIEroaming_consortium_sel) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIesec_chan_offset_ele: + status |= + dot11f_pack_ie_sec_chan_offset_ele( + pCtx, (tDot11fIEsec_chan_offset_ele *) + (pSrc + pIe->offset + + sizeof(tDot11fIEsec_chan_offset_ele) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIespatial_reuse: + status |= + dot11f_pack_ie_spatial_reuse( + pCtx, (tDot11fIEspatial_reuse *) + (pSrc + pIe->offset + + sizeof(tDot11fIEspatial_reuse) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIet2lm_ie: + status |= + dot11f_pack_ie_t2lm_ie( + pCtx, (tDot11fIEt2lm_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEt2lm_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + case SigIevendor_vht_ie: + status |= + dot11f_pack_ie_vendor_vht_ie( + pCtx, (tDot11fIEvendor_vht_ie *) + (pSrc + pIe->offset + + sizeof(tDot11fIEvendor_vht_ie) * i), + pBufRemaining, nBufRemaining, &len); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don" + "'t know about the IE %d; this is most likely a b" + "ug in 'framesc'.\n"), pFf->sig); + return DOT11F_INTERNAL_ERROR; + } + + pBufRemaining += len; + nBufRemaining -= len; + *pnConsumed += len; + } + + ++pIe; + + } + + return status; + +} + +static uint32_t pack_tlv_core(tpAniSirGlobal pCtx, + uint8_t *pSrc, + uint8_t *pBuf, + uint32_t nBuf, + uint32_t *pnConsumed, + const tTLVDefn TLVs[], + uint32_t *pidx) +{ + const tTLVDefn *pTlv; + tFRAMES_BOOL *pfFound; + uint8_t *pBufRemaining; + uint32_t nBufRemaining, status, len; + + DOT11F_PARAMETER_CHECK2(pSrc, pBuf, nBuf, pnConsumed); + + (void)pCtx; + status = DOT11F_PARSE_SUCCESS; + pBufRemaining = pBuf; + nBufRemaining = nBuf; + + pTlv = &(TLVs[0]); + while (0xffff != pTlv->id) { + pfFound = (tFRAMES_BOOL *)(pSrc + pTlv->offset + + pTlv->presenceOffset); + if (*pfFound && pTlv->minSize > nBufRemaining) { + FRAMES_LOG3(pCtx, FRLOGE, FRFL("The TLV %s takes at least" + " %d bytes, but there are only %d left in the buffer." + "\n"), pTlv->name, pTlv->minSize, nBufRemaining); + return DOT11F_BUFFER_OVERFLOW; + } + + len = 0U; + + if (*pfFound) { + switch (pTlv->sig) { + case SigTlvAuthorizedMACs: + status |= + dot11f_pack_tlv_authorized_ma_cs( + pCtx, (tDot11fTLVAuthorizedMACs *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestToEnroll: + status |= + dot11f_pack_tlv_request_to_enroll( + pCtx, (tDot11fTLVRequestToEnroll *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVersion2: + status |= + dot11f_pack_tlv_version2( + pCtx, (tDot11fTLVVersion2 *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvAPSetupLocked: + status |= + dot11f_pack_tlv_ap_setup_locked( + pCtx, (tDot11fTLVAPSetupLocked *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvAssociationState: + status |= + dot11f_pack_tlv_association_state( + pCtx, (tDot11fTLVAssociationState *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvConfigMethods: + status |= + dot11f_pack_tlv_config_methods( + pCtx, (tDot11fTLVConfigMethods *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvConfigurationError: + status |= + dot11f_pack_tlv_configuration_error( + pCtx, (tDot11fTLVConfigurationError *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvDeviceName: + status |= + dot11f_pack_tlv_device_name( + pCtx, (tDot11fTLVDeviceName *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvDevicePasswordID: + status |= + dot11f_pack_tlv_device_password_id( + pCtx, (tDot11fTLVDevicePasswordID *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvExtendedListenTiming: + status |= + dot11f_pack_tlv_extended_listen_timing( + pCtx, (tDot11fTLVExtendedListenTiming *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvListenChannel: + status |= + dot11f_pack_tlv_listen_channel( + pCtx, (tDot11fTLVListenChannel *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvManufacturer: + status |= + dot11f_pack_tlv_manufacturer( + pCtx, (tDot11fTLVManufacturer *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvMinorReasonCode: + status |= + dot11f_pack_tlv_minor_reason_code( + pCtx, (tDot11fTLVMinorReasonCode *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvModelName: + status |= + dot11f_pack_tlv_model_name( + pCtx, (tDot11fTLVModelName *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvModelNumber: + status |= + dot11f_pack_tlv_model_number( + pCtx, (tDot11fTLVModelNumber *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvNoticeOfAbsence: + status |= + dot11f_pack_tlv_notice_of_absence( + pCtx, (tDot11fTLVNoticeOfAbsence *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvOperatingChannel: + status |= + dot11f_pack_tlv_operating_channel( + pCtx, (tDot11fTLVOperatingChannel *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PCapability: + status |= + dot11f_pack_tlv_p2_p_capability( + pCtx, (tDot11fTLVP2PCapability *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PDeviceId: + status |= + dot11f_pack_tlv_p2_p_device_id( + pCtx, (tDot11fTLVP2PDeviceId *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PDeviceInfo: + status |= + dot11f_pack_tlv_p2_p_device_info( + pCtx, (tDot11fTLVP2PDeviceInfo *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PGroupInfo: + status |= + dot11f_pack_tlv_p2_p_group_info( + pCtx, (tDot11fTLVP2PGroupInfo *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PStatus: + status |= + dot11f_pack_tlv_p2_p_status( + pCtx, (tDot11fTLVP2PStatus *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvPrimaryDeviceType: + status |= + dot11f_pack_tlv_primary_device_type( + pCtx, (tDot11fTLVPrimaryDeviceType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRFBands: + status |= + dot11f_pack_tlv_rf_bands( + pCtx, (tDot11fTLVRFBands *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestDeviceType: + status |= + dot11f_pack_tlv_request_device_type( + pCtx, (tDot11fTLVRequestDeviceType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvRequestType: + status |= + dot11f_pack_tlv_request_type( + pCtx, (tDot11fTLVRequestType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvResponseType: + status |= + dot11f_pack_tlv_response_type( + pCtx, (tDot11fTLVResponseType *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSelectedRegistrar: + status |= + dot11f_pack_tlv_selected_registrar( + pCtx, (tDot11fTLVSelectedRegistrar *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSelectedRegistrarConfigMethods: + status |= + dot11f_pack_tlv_selected_registrar_config_methods( + pCtx, (tDot11fTLVSelectedRegistrarConfigMethods *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvSerialNumber: + status |= + dot11f_pack_tlv_serial_number( + pCtx, (tDot11fTLVSerialNumber *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvUUID_E: + status |= + dot11f_pack_tlv_uuid_e( + pCtx, (tDot11fTLVUUID_E *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvUUID_R: + status |= + dot11f_pack_tlv_uuid_r( + pCtx, (tDot11fTLVUUID_R *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVendorExtension: + status |= + dot11f_pack_tlv_vendor_extension( + pCtx, (tDot11fTLVVendorExtension *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvVersion: + status |= + dot11f_pack_tlv_version( + pCtx, (tDot11fTLVVersion *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvWPSState: + status |= + dot11f_pack_tlv_wps_state( + pCtx, (tDot11fTLVWPSState *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvassoc_disallowed: + status |= + dot11f_pack_tlv_assoc_disallowed( + pCtx, (tDot11fTLVassoc_disallowed *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvassoc_retry_delay: + status |= + dot11f_pack_tlv_assoc_retry_delay( + pCtx, (tDot11fTLVassoc_retry_delay *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvcellular_data_cap: + status |= + dot11f_pack_tlv_cellular_data_cap( + pCtx, (tDot11fTLVcellular_data_cap *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvcellular_data_con_pref: + status |= + dot11f_pack_tlv_cellular_data_con_pref( + pCtx, (tDot11fTLVcellular_data_con_pref *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvecsa_target_tsf_info_attr: + status |= + dot11f_pack_tlv_ecsa_target_tsf_info_attr( + pCtx, (tDot11fTLVecsa_target_tsf_info_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvedca_pifs_param_attr: + status |= + dot11f_pack_tlv_edca_pifs_param_attr( + pCtx, (tDot11fTLVedca_pifs_param_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvhe_2xltf_160mhz_supp: + status |= + dot11f_pack_tlv_he_2xltf_160mhz_supp( + pCtx, (tDot11fTLVhe_2xltf_160mhz_supp *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvhe_400ns_sgi_attr: + status |= + dot11f_pack_tlv_he_400ns_sgi_attr( + pCtx, (tDot11fTLVhe_400ns_sgi_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvhe_dl_mumimo_attr: + status |= + dot11f_pack_tlv_he_dl_mumimo_attr( + pCtx, (tDot11fTLVhe_dl_mumimo_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvhe_dl_ofdma_attr: + status |= + dot11f_pack_tlv_he_dl_ofdma_attr( + pCtx, (tDot11fTLVhe_dl_ofdma_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvhe_mcs13_attr: + status |= + dot11f_pack_tlv_he_mcs13_attr( + pCtx, (tDot11fTLVhe_mcs13_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvmbo_ap_cap: + status |= + dot11f_pack_tlv_mbo_ap_cap( + pCtx, (tDot11fTLVmbo_ap_cap *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvnon_prefferd_chan_rep: + status |= + dot11f_pack_tlv_non_prefferd_chan_rep( + pCtx, (tDot11fTLVnon_prefferd_chan_rep *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvoce_cap: + status |= + dot11f_pack_tlv_oce_cap( + pCtx, (tDot11fTLVoce_cap *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvqcn_version: + status |= + dot11f_pack_tlv_qcn_version( + pCtx, (tDot11fTLVqcn_version *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvreduced_wan_metrics: + status |= + dot11f_pack_tlv_reduced_wan_metrics( + pCtx, (tDot11fTLVreduced_wan_metrics *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvrssi_assoc_rej: + status |= + dot11f_pack_tlv_rssi_assoc_rej( + pCtx, (tDot11fTLVrssi_assoc_rej *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvtrans_reasonp_attr: + status |= + dot11f_pack_tlv_trans_reasonp_attr( + pCtx, (tDot11fTLVtrans_reasonp_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvtrans_rejectp_attr: + status |= + dot11f_pack_tlv_trans_rejectp_attr( + pCtx, (tDot11fTLVtrans_rejectp_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvtransition_reason: + status |= + dot11f_pack_tlv_transition_reason( + pCtx, (tDot11fTLVtransition_reason *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvtransition_reject_reason: + status |= + dot11f_pack_tlv_transition_reject_reason( + pCtx, (tDot11fTLVtransition_reject_reason *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvvht_mcs11_attr: + status |= + dot11f_pack_tlv_vht_mcs11_attr( + pCtx, (tDot11fTLVvht_mcs11_attr *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PInterface: + status |= + dot11f_pack_tlv_p2_p_interface( + pCtx, (tDot11fTLVP2PInterface *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + case SigTlvP2PManageability: + status |= + dot11f_pack_tlv_p2_p_manageability( + pCtx, (tDot11fTLVP2PManageability *) + (pSrc + pTlv->offset), pBufRemaining, + nBufRemaining, &len); + break; + default: + FRAMES_LOG1(pCtx, FRLOGE, FRFL("INTERNAL ERROR-- I don't " + "know about the TLV %d; this is most likely a bug in " + "'framesc'.\n"), pTlv->sig); + return DOT11F_INTERNAL_ERROR; + } + + } /* End if on *pfFound */ + pBufRemaining += len; + nBufRemaining -= len; + *pnConsumed += len; + ++pTlv; + if (len) + ++*pidx; + } + + return status; + +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c new file mode 100644 index 0000000000..a6b412da88 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/mac_trace.c @@ -0,0 +1,642 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/**========================================================================= + + \file mac_trace.c + + \brief implementation for trace related APIs + + \author Sunit Bhatia + + ========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ + +#include "mac_trace.h" +#include "wma_types.h" +#include "csr_internal.h" +#include "lim_global.h" +#include "lim_types.h" +#include "qdf_mem.h" +#include "qdf_trace.h" +#include "wma_if.h" +#include "wma.h" + +/** + * mac_trace_getcsr_roam_state() - Get the csr roam state + * @csr_roam_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_getcsr_roam_state(uint16_t csr_roam_state) +{ + switch (csr_roam_state) { + CASE_RETURN_STRING(eCSR_ROAMING_STATE_STOP); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_IDLE); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_JOINING); + CASE_RETURN_STRING(eCSR_ROAMING_STATE_JOINED); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_getcsr_roam_sub_state() - Get the csr roam sub state + * @csr_roam_sub_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_getcsr_roam_sub_state(uint16_t csr_roam_sub_state) +{ + switch (csr_roam_sub_state) { + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_NONE); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_START_BSS_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DISASSOC_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_STOP_BSS_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_DEAUTH_REQ); + CASE_RETURN_STRING(eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_sme_state() - Get the lim sme state + * @lim_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_lim_sme_state(uint16_t lim_state) +{ + switch (lim_state) { + CASE_RETURN_STRING(eLIM_SME_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_SME_IDLE_STATE); + CASE_RETURN_STRING(eLIM_SME_SUSPEND_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_JOIN_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_JOIN_FAILURE_STATE); + CASE_RETURN_STRING(eLIM_SME_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_SME_LINK_EST_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_PRE_AUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DISASSOC_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_DEAUTH_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_START_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_WT_STOP_BSS_STATE); + CASE_RETURN_STRING(eLIM_SME_NORMAL_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_lim_mlm_state() - Get the lim mlm state + * @mlm_state: State in numeric form + * + * This function will return a string equivalent of the state. + * + * Return: String equivalent of the state. + **/ +uint8_t *mac_trace_get_lim_mlm_state(uint16_t mlm_state) +{ + switch (mlm_state) { + CASE_RETURN_STRING(eLIM_MLM_OFFLINE_STATE); + CASE_RETURN_STRING(eLIM_MLM_IDLE_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_JOIN_BEACON_STATE); + CASE_RETURN_STRING(eLIM_MLM_JOINED_STATE); + CASE_RETURN_STRING(eLIM_MLM_BSS_STARTED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME2_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME3_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_AUTH_FRAME4_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTH_RSP_TIMEOUT_STATE); + CASE_RETURN_STRING(eLIM_MLM_AUTHENTICATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_REASSOC_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_ASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_REASSOCIATED_STATE); + CASE_RETURN_STRING(eLIM_MLM_LINK_ESTABLISHED_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ASSOC_CNF_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_BSS_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_ASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_REASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_BSS_RSP_PREASSOC_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_ADD_STA_RSP_STATE); + CASE_RETURN_STRING(eLIM_MLM_WT_DEL_STA_RSP_STATE); + + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +#ifdef TRACE_RECORD +/** + * mac_trace_get_sme_msg_string() - Get the msg + * @sme_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_sme_msg_string(uint16_t sme_msg) +{ + switch (sme_msg) { + CASE_RETURN_STRING(eWNI_SME_SYS_READY_IND); + CASE_RETURN_STRING(eWNI_SME_JOIN_REQ); + CASE_RETURN_STRING(eWNI_SME_JOIN_RSP); + CASE_RETURN_STRING(eWNI_SME_SETCONTEXT_RSP); + CASE_RETURN_STRING(eWNI_SME_REASSOC_REQ); + CASE_RETURN_STRING(eWNI_SME_REASSOC_RSP); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_REQ); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_RSP); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_IND); + CASE_RETURN_STRING(eWNI_SME_DISASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_REQ); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_RSP); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_IND); + CASE_RETURN_STRING(eWNI_SME_DISCONNECT_DONE_IND); + CASE_RETURN_STRING(eWNI_SME_START_BSS_REQ); + CASE_RETURN_STRING(eWNI_SME_START_BSS_RSP); + CASE_RETURN_STRING(eWNI_SME_ASSOC_IND); + CASE_RETURN_STRING(eWNI_SME_ASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_SWITCH_CHL_IND); + CASE_RETURN_STRING(eWNI_SME_STOP_BSS_REQ); + CASE_RETURN_STRING(eWNI_SME_STOP_BSS_RSP); + CASE_RETURN_STRING(eWNI_SME_DEAUTH_CNF); + CASE_RETURN_STRING(eWNI_SME_MIC_FAILURE_IND); + CASE_RETURN_STRING(eWNI_SME_ADDTS_REQ); + CASE_RETURN_STRING(eWNI_SME_MSCS_REQ); + CASE_RETURN_STRING(eWNI_SME_ADDTS_RSP); + CASE_RETURN_STRING(eWNI_SME_DELTS_REQ); + CASE_RETURN_STRING(eWNI_SME_DELTS_RSP); + CASE_RETURN_STRING(eWNI_SME_DELTS_IND); + CASE_RETURN_STRING(eWNI_SME_ASSOC_IND_UPPER_LAYER); + CASE_RETURN_STRING(eWNI_SME_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_UPPER_LAYER_ASSOC_CNF); + CASE_RETURN_STRING(eWNI_SME_SESSION_UPDATE_PARAM); + CASE_RETURN_STRING(eWNI_SME_CHNG_MCC_BEACON_INTERVAL); + CASE_RETURN_STRING(eWNI_SME_GET_SNR_REQ); + CASE_RETURN_STRING(eWNI_SME_LINK_STATUS_IND); + CASE_RETURN_STRING(eWNI_SME_RRM_MSG_TYPE_BEGIN); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_NEIGHBOR_REPORT_IND); + CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_BEACON_REPORT_RESP_XMIT_IND); + CASE_RETURN_STRING(eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND); + CASE_RETURN_STRING(eWNI_SME_CHAN_LOAD_REQ_IND); + CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_REQ); + CASE_RETURN_STRING(eWNI_SME_FT_AGGR_QOS_RSP); +#if defined FEATURE_WLAN_ESE + CASE_RETURN_STRING(eWNI_SME_ESE_ADJACENT_AP_REPORT); +#endif + CASE_RETURN_STRING(eWNI_SME_REGISTER_MGMT_FRAME_REQ); + CASE_RETURN_STRING(eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE); + CASE_RETURN_STRING(eWNI_SME_MAX_ASSOC_EXCEEDED); +#ifdef WLAN_FEATURE_GTK_OFFLOAD + CASE_RETURN_STRING(eWNI_PMC_GTK_OFFLOAD_GETINFO_RSP); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + CASE_RETURN_STRING(eWNI_SME_DFS_RADAR_FOUND); + CASE_RETURN_STRING(eWNI_SME_CHANNEL_CHANGE_REQ); + CASE_RETURN_STRING(eWNI_SME_CHANNEL_CHANGE_RSP); + CASE_RETURN_STRING(eWNI_SME_START_BEACON_REQ); + CASE_RETURN_STRING(eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ); + CASE_RETURN_STRING(eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND); + CASE_RETURN_STRING(eWNI_SME_STATS_EXT_EVENT); + CASE_RETURN_STRING(eWNI_SME_UPDATE_ADDITIONAL_IES); + CASE_RETURN_STRING(eWNI_SME_MODIFY_ADDITIONAL_IES); +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + CASE_RETURN_STRING(eWNI_SME_AUTO_SHUTDOWN_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_SET_HT_2040_MODE); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(eWNI_SME_TDLS_SEND_MGMT_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_SEND_MGMT_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_ADD_STA_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_ADD_STA_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_STA_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_STA_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_STA_IND); + CASE_RETURN_STRING(eWNI_SME_TDLS_DEL_ALL_PEER_IND); + CASE_RETURN_STRING(eWNI_SME_MGMT_FRM_TX_COMPLETION_IND); + CASE_RETURN_STRING(eWNI_SME_TDLS_LINK_ESTABLISH_REQ); + CASE_RETURN_STRING(eWNI_SME_TDLS_LINK_ESTABLISH_RSP); + CASE_RETURN_STRING(eWNI_SME_TDLS_SHOULD_DISCOVER); + CASE_RETURN_STRING(eWNI_SME_TDLS_SHOULD_TEARDOWN); + CASE_RETURN_STRING(eWNI_SME_TDLS_PEER_DISCONNECTED); +#endif + CASE_RETURN_STRING(eWNI_SME_UNPROT_MGMT_FRM_IND); + CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_REQ); + CASE_RETURN_STRING(eWNI_SME_GET_TSM_STATS_RSP); + CASE_RETURN_STRING(eWNI_SME_TSM_IE_IND); + CASE_RETURN_STRING(eWNI_SME_SET_HW_MODE_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_HW_MODE_RESP); + CASE_RETURN_STRING(eWNI_SME_HW_MODE_TRANS_IND); + CASE_RETURN_STRING(eWNI_SME_NSS_UPDATE_REQ); + CASE_RETURN_STRING(eWNI_SME_NSS_UPDATE_RSP); + CASE_RETURN_STRING(eWNI_SME_REGISTER_MGMT_FRAME_CB); + CASE_RETURN_STRING(eWNI_SME_HT40_OBSS_SCAN_IND); +#ifdef WLAN_FEATURE_NAN + CASE_RETURN_STRING(eWNI_SME_NAN_EVENT); +#endif +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(eWNI_SME_READY_TO_EXTWOW_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_MSG_GET_TEMPERATURE_IND); + CASE_RETURN_STRING(eWNI_SME_SNR_IND); +#ifdef FEATURE_WLAN_EXTSCAN + CASE_RETURN_STRING(eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND); + CASE_RETURN_STRING(eWNI_SME_EPNO_NETWORK_FOUND_IND); +#endif + CASE_RETURN_STRING(eWNI_SME_SET_THERMAL_LEVEL_IND); + CASE_RETURN_STRING(eWNI_SME_OCB_SET_CONFIG_RSP); + CASE_RETURN_STRING(eWNI_SME_OCB_GET_TSF_TIMER_RSP); + CASE_RETURN_STRING(eWNI_SME_DCC_GET_STATS_RSP); + CASE_RETURN_STRING(eWNI_SME_DCC_UPDATE_NDL_RSP); + CASE_RETURN_STRING(eWNI_SME_DCC_STATS_EVENT); + CASE_RETURN_STRING(eWNI_SME_SET_DUAL_MAC_CFG_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_DUAL_MAC_CFG_RESP); + CASE_RETURN_STRING(eWNI_SME_SET_IE_REQ); + CASE_RETURN_STRING(eWNI_SME_EXT_CHANGE_CHANNEL); + CASE_RETURN_STRING(eWNI_SME_EXT_CHANGE_CHANNEL_IND); + CASE_RETURN_STRING(eWNI_SME_SET_ANTENNA_MODE_REQ); + CASE_RETURN_STRING(eWNI_SME_SET_ANTENNA_MODE_RESP); + CASE_RETURN_STRING(eWNI_SME_TSF_EVENT); + CASE_RETURN_STRING(eWNI_SME_MON_INIT_SESSION); + CASE_RETURN_STRING(eWNI_SME_MON_DEINIT_SESSION); + CASE_RETURN_STRING(eWNI_SME_PDEV_SET_HT_VHT_IE); + CASE_RETURN_STRING(eWNI_SME_SET_VDEV_IES_PER_BAND); + CASE_RETURN_STRING(eWNI_SME_SEND_DISASSOC_FRAME); + CASE_RETURN_STRING(eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE); + CASE_RETURN_STRING(eWNI_SME_DEFAULT_SCAN_IE); + CASE_RETURN_STRING(eWNI_SME_LOST_LINK_INFO_IND); + CASE_RETURN_STRING(eWNI_SME_GET_PEER_INFO_EXT_IND); + CASE_RETURN_STRING(eWNI_SME_RSO_CMD_STATUS_IND); + CASE_RETURN_STRING(eWNI_SME_TRIGGER_SAE); + CASE_RETURN_STRING(eWNI_SME_SEND_MGMT_FRAME_TX); + CASE_RETURN_STRING(eWNI_SME_SEND_SAE_MSG); + CASE_RETURN_STRING(eWNI_SME_CSA_RESTART_REQ); + CASE_RETURN_STRING(eWNI_SME_CSA_RESTART_RSP); + CASE_RETURN_STRING(eWNI_SME_MSG_TYPES_END); + CASE_RETURN_STRING(eWNI_SME_HIDDEN_SSID_RESTART_RSP); + CASE_RETURN_STRING(eWNI_SME_STA_CSA_CONTINUE_REQ); + CASE_RETURN_STRING(eWNI_SME_ANTENNA_ISOLATION_RSP); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} +#endif + +/** + * mac_trace_get_wma_msg_string() - Get the msg + * @wma_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_wma_msg_string(uint16_t wma_msg) +{ + switch (wma_msg) { + CASE_RETURN_STRING(WMA_ADD_STA_REQ); + CASE_RETURN_STRING(WMA_ADD_STA_RSP); + CASE_RETURN_STRING(WMA_DELETE_STA_REQ); + CASE_RETURN_STRING(WMA_DELETE_STA_RSP); + CASE_RETURN_STRING(WMA_ADD_BSS_REQ); + CASE_RETURN_STRING(WMA_DELETE_BSS_REQ); + CASE_RETURN_STRING(WMA_DELETE_BSS_HO_FAIL_REQ); + CASE_RETURN_STRING(WMA_DELETE_BSS_RSP); + CASE_RETURN_STRING(WMA_DELETE_BSS_HO_FAIL_RSP); + CASE_RETURN_STRING(WMA_SEND_BEACON_REQ); + CASE_RETURN_STRING(WMA_SET_BSSKEY_RSP); + CASE_RETURN_STRING(WMA_SET_STAKEY_RSP); + CASE_RETURN_STRING(WMA_UPDATE_EDCA_PROFILE_IND); + + CASE_RETURN_STRING(WMA_UPDATE_BEACON_IND); + CASE_RETURN_STRING(WMA_CHNL_SWITCH_REQ); + CASE_RETURN_STRING(WMA_ADD_TS_REQ); + CASE_RETURN_STRING(WMA_DEL_TS_REQ); + CASE_RETURN_STRING(WMA_MISSED_BEACON_IND); + + CASE_RETURN_STRING(WMA_SWITCH_CHANNEL_RSP); + CASE_RETURN_STRING(WMA_P2P_NOA_ATTR_IND); + CASE_RETURN_STRING(WMA_PWR_SAVE_CFG); + + CASE_RETURN_STRING(WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND); + CASE_RETURN_STRING(WMA_SET_STA_BCASTKEY_RSP); + CASE_RETURN_STRING(WMA_ADD_TS_RSP); + CASE_RETURN_STRING(WMA_DPU_MIC_ERROR); + + CASE_RETURN_STRING(WMA_TIMER_CHIP_MONITOR_TIMEOUT); + CASE_RETURN_STRING(WMA_TIMER_TRAFFIC_ACTIVITY_REQ); + CASE_RETURN_STRING(WMA_TIMER_ADC_RSSI_STATS); +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(WMA_TSM_STATS_REQ); + CASE_RETURN_STRING(WMA_TSM_STATS_RSP); +#endif + CASE_RETURN_STRING(WMA_HT40_OBSS_SCAN_IND); + CASE_RETURN_STRING(WMA_SET_MIMOPS_REQ); + CASE_RETURN_STRING(WMA_SET_MIMOPS_RSP); + CASE_RETURN_STRING(WMA_SYS_READY_IND); + CASE_RETURN_STRING(WMA_SET_TX_POWER_REQ); + CASE_RETURN_STRING(WMA_SET_TX_POWER_RSP); + CASE_RETURN_STRING(WMA_GET_TX_POWER_REQ); + + CASE_RETURN_STRING(WMA_ENABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_DISABLE_UAPSD_REQ); + CASE_RETURN_STRING(WMA_SET_KEY_DONE); + + CASE_RETURN_STRING(WMA_BTC_SET_CFG); + CASE_RETURN_STRING(WMA_HANDLE_FW_MBOX_RSP); + CASE_RETURN_STRING(WMA_SEND_PROBE_RSP_TMPL); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_REQ); + CASE_RETURN_STRING(WMA_SET_HOST_OFFLOAD); + CASE_RETURN_STRING(WMA_SET_KEEP_ALIVE); +#ifdef WLAN_NS_OFFLOAD + CASE_RETURN_STRING(WMA_SET_NS_OFFLOAD); +#endif /* WLAN_NS_OFFLOAD */ + CASE_RETURN_STRING(WMA_WLAN_SUSPEND_IND); + CASE_RETURN_STRING(WMA_WLAN_RESUME_REQ); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(WMA_WLAN_EXT_WOW); + CASE_RETURN_STRING(WMA_WLAN_SET_APP_TYPE1_PARAMS); + CASE_RETURN_STRING(WMA_WLAN_SET_APP_TYPE2_PARAMS); +#endif + CASE_RETURN_STRING(WMA_MSG_TYPES_END); + CASE_RETURN_STRING(WMA_AGGR_QOS_REQ); + CASE_RETURN_STRING(WMA_AGGR_QOS_RSP); + CASE_RETURN_STRING(WMA_ROAM_PRE_AUTH_STATUS); +#ifdef WLAN_FEATURE_PACKET_FILTERING + CASE_RETURN_STRING(WMA_8023_MULTICAST_LIST_REQ); + CASE_RETURN_STRING(WMA_RECEIVE_FILTER_SET_FILTER_REQ); + CASE_RETURN_STRING + (WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ); + CASE_RETURN_STRING + (WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP); + CASE_RETURN_STRING(WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +#ifdef WLAN_FEATURE_GTK_OFFLOAD + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_REQ); + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_GETINFO_REQ); + CASE_RETURN_STRING(WMA_GTK_OFFLOAD_GETINFO_RSP); +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + CASE_RETURN_STRING(WMA_SET_TM_LEVEL_REQ); + CASE_RETURN_STRING(WMA_UPDATE_OP_MODE); + CASE_RETURN_STRING(WMA_UPDATE_MEMBERSHIP); + CASE_RETURN_STRING(WMA_UPDATE_USERPOS); + CASE_RETURN_STRING(WMA_UPDATE_CHAN_LIST_REQ); + CASE_RETURN_STRING(WMA_CLI_SET_CMD); +#ifndef REMOVE_PKT_LOG + CASE_RETURN_STRING(WMA_PKTLOG_ENABLE_REQ); +#endif +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STRING(WMA_SET_PLM_REQ); +#endif + CASE_RETURN_STRING(WMA_RATE_UPDATE_IND); + CASE_RETURN_STRING(WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_UPDATE_TDLS_PEER_STATE); +#endif + CASE_RETURN_STRING(WMA_ADD_PERIODIC_TX_PTRN_IND); + CASE_RETURN_STRING(WMA_TX_POWER_LIMIT); + CASE_RETURN_STRING(WMA_DHCP_START_IND); + CASE_RETURN_STRING(WMA_DHCP_STOP_IND); +#ifdef FEATURE_WLAN_CH_AVOID + CASE_RETURN_STRING(WMA_CH_AVOID_UPDATE_REQ); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + CASE_RETURN_STRING(WMA_SET_AUTO_SHUTDOWN_TIMER_REQ); +#endif + CASE_RETURN_STRING(WMA_INIT_THERMAL_INFO_CMD); + CASE_RETURN_STRING(WMA_SET_THERMAL_LEVEL); + CASE_RETURN_STRING(WMA_SET_SAP_INTRABSS_DIS); + CASE_RETURN_STRING(SIR_HAL_SET_BASE_MACADDR_IND); + CASE_RETURN_STRING(WMA_LINK_STATUS_GET_REQ); +#ifdef DHCP_SERVER_OFFLOAD + CASE_RETURN_STRING(WMA_SET_DHCP_SERVER_OFFLOAD_CMD); +#endif + CASE_RETURN_STRING(WMA_OCB_SET_CONFIG_CMD); + CASE_RETURN_STRING(WMA_OCB_SET_UTC_TIME_CMD); + CASE_RETURN_STRING(WMA_OCB_START_TIMING_ADVERT_CMD); + CASE_RETURN_STRING(WMA_OCB_STOP_TIMING_ADVERT_CMD); + CASE_RETURN_STRING(WMA_OCB_GET_TSF_TIMER_CMD); + CASE_RETURN_STRING(WMA_DCC_GET_STATS_CMD); + CASE_RETURN_STRING(WMA_DCC_CLEAR_STATS_CMD); + CASE_RETURN_STRING(WMA_DCC_UPDATE_NDL_CMD); + CASE_RETURN_STRING(WMA_SET_IE_INFO); + CASE_RETURN_STRING(WMA_GW_PARAM_UPDATE_REQ); + CASE_RETURN_STRING(WMA_ADD_BCN_FILTER_CMDID); + CASE_RETURN_STRING(WMA_REMOVE_BCN_FILTER_CMDID); + CASE_RETURN_STRING(WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS); + CASE_RETURN_STRING(WDA_APF_GET_CAPABILITIES_REQ); + CASE_RETURN_STRING(WMA_ROAM_SYNC_TIMEOUT); + CASE_RETURN_STRING(WMA_SET_PDEV_IE_REQ); + CASE_RETURN_STRING(WMA_SEND_FREQ_RANGE_CONTROL_IND); + CASE_RETURN_STRING(WMA_POWER_DEBUG_STATS_REQ); + CASE_RETURN_STRING(SIR_HAL_SET_MAS); + CASE_RETURN_STRING(SIR_HAL_SET_MIRACAST); + CASE_RETURN_STRING(SIR_HAL_CONFIG_STATS_FACTOR); + CASE_RETURN_STRING(SIR_HAL_CONFIG_GUARD_TIME); + CASE_RETURN_STRING(SIR_HAL_START_STOP_LOGGING); + CASE_RETURN_STRING(SIR_HAL_FLUSH_LOG_TO_FW); + CASE_RETURN_STRING(SIR_HAL_SET_PCL_TO_FW); + CASE_RETURN_STRING(SIR_HAL_PDEV_SET_HW_MODE); + CASE_RETURN_STRING(SIR_HAL_PDEV_DUAL_MAC_CFG_REQ); + CASE_RETURN_STRING(WMA_RADAR_DETECTED_IND); + CASE_RETURN_STRING(WMA_TIMER_TRAFFIC_STATS_IND); + CASE_RETURN_STRING(WMA_EXCLUDE_UNENCRYPTED_IND); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_RSP); + CASE_RETURN_STRING(WMA_SET_DTIM_PERIOD); + CASE_RETURN_STRING(WMA_SET_MAX_TX_POWER_PER_BAND_REQ); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_SET_TDLS_LINK_ESTABLISH_REQ); + CASE_RETURN_STRING(WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP); +#endif + CASE_RETURN_STRING(WMA_CSA_OFFLOAD_EVENT); + CASE_RETURN_STRING(WMA_UPDATE_RX_NSS); +#ifdef WLAN_FEATURE_NAN + CASE_RETURN_STRING(WMA_NAN_REQUEST); +#endif +#ifdef WLAN_SUPPORT_TWT + CASE_RETURN_STRING(WMA_TWT_ADD_DIALOG_REQUEST); + CASE_RETURN_STRING(WMA_TWT_DEL_DIALOG_REQUEST); + CASE_RETURN_STRING(WMA_TWT_PAUSE_DIALOG_REQUEST); + CASE_RETURN_STRING(WMA_TWT_RESUME_DIALOG_REQUEST); + CASE_RETURN_STRING(WMA_TWT_NUDGE_DIALOG_REQUEST); +#endif + CASE_RETURN_STRING(WMA_RX_SCAN_EVENT); + CASE_RETURN_STRING(WMA_DEL_PERIODIC_TX_PTRN_IND); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING(WMA_TDLS_SHOULD_DISCOVER_CMD); + CASE_RETURN_STRING(WMA_TDLS_SHOULD_TEARDOWN_CMD); + CASE_RETURN_STRING(WMA_TDLS_PEER_DISCONNECTED_CMD); +#endif + CASE_RETURN_STRING(WMA_DFS_BEACON_TX_SUCCESS_IND); + CASE_RETURN_STRING(WMA_DISASSOC_TX_COMP); + CASE_RETURN_STRING(WMA_DEAUTH_TX_COMP); + CASE_RETURN_STRING(WMA_MODEM_POWER_STATE_IND); +#ifdef WLAN_FEATURE_STATS_EXT + CASE_RETURN_STRING(WMA_STATS_EXT_REQUEST); +#endif + CASE_RETURN_STRING(WMA_GET_TEMPERATURE_REQ); +#ifdef FEATURE_WLAN_EXTSCAN + CASE_RETURN_STRING(WMA_EXTSCAN_GET_CAPABILITIES_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_START_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_STOP_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ); + CASE_RETURN_STRING(WMA_EXTSCAN_GET_CACHED_RESULTS_REQ); + CASE_RETURN_STRING(WMA_SET_EPNO_LIST_REQ); + CASE_RETURN_STRING(WMA_SET_PASSPOINT_LIST_REQ); + CASE_RETURN_STRING(WMA_RESET_PASSPOINT_LIST_REQ); +#endif /* FEATURE_WLAN_EXTSCAN */ +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_CLEAR_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_SET_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_GET_REQ); + CASE_RETURN_STRING(WMA_LINK_LAYER_STATS_RESULTS_RSP); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + CASE_RETURN_STRING(WMA_SET_SCAN_MAC_OUI_REQ); + CASE_RETURN_STRING(WMA_TSF_GPIO_PIN); +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + CASE_RETURN_STRING(WMA_LED_FLASHING_REQ); +#endif +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + CASE_RETURN_STRING(WMA_UPDATE_Q2Q_IE_IND); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + CASE_RETURN_STRING(WMA_SET_RSSI_MONITOR_REQ); + CASE_RETURN_STRING(WMA_SET_WISA_PARAMS); + CASE_RETURN_STRING(WMA_SET_WOW_PULSE_CMD); + CASE_RETURN_STRING(WMA_GET_RCPI_REQ); + CASE_RETURN_STRING(WMA_SET_DBS_SCAN_SEL_CONF_PARAMS); + CASE_RETURN_STRING(WMA_GET_ROAM_SCAN_STATS); + CASE_RETURN_STRING(WMA_PEER_CREATE_RESPONSE); +#ifdef FW_THERMAL_THROTTLE_SUPPORT + CASE_RETURN_STRING(WMA_SET_THERMAL_THROTTLE_CFG); + CASE_RETURN_STRING(WMA_SET_THERMAL_MGMT); +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + CASE_RETURN_STRING(WMA_UPDATE_EDCA_PIFS_PARAM_IND); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +#ifdef TRACE_RECORD +/** + * mac_trace_get_lim_msg_string() - Get the msg + * @lim_msg: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_lim_msg_string(uint16_t lim_msg) +{ + switch (lim_msg) { + CASE_RETURN_STRING(SIR_BB_XPORT_MGMT_MSG); + CASE_RETURN_STRING(SIR_LIM_DELETE_STA_CONTEXT_IND); + CASE_RETURN_STRING(SIR_LIM_UPDATE_BEACON); + CASE_RETURN_STRING(SIR_LIM_JOIN_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_ASSOC_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_REASSOC_FAIL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_HEART_BEAT_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_ADDTS_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_LINK_TEST_DURATION_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_CNF_WAIT_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_WPS_OVERLAP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_FT_PREAUTH_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_DISASSOC_ACK_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_RETRY_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_AUTH_SAE_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_RRM_STA_STATS_RSP_TIMEOUT); + CASE_RETURN_STRING(SIR_LIM_MSG_TYPES_END); + CASE_RETURN_STRING(LIM_MLM_SCAN_REQ); + CASE_RETURN_STRING(LIM_MLM_SCAN_CNF); + CASE_RETURN_STRING(LIM_MLM_START_CNF); + CASE_RETURN_STRING(LIM_MLM_JOIN_REQ); + CASE_RETURN_STRING(LIM_MLM_JOIN_CNF); + CASE_RETURN_STRING(LIM_MLM_AUTH_REQ); + CASE_RETURN_STRING(LIM_MLM_AUTH_CNF); + CASE_RETURN_STRING(LIM_MLM_AUTH_IND); + CASE_RETURN_STRING(LIM_MLM_ASSOC_REQ); + CASE_RETURN_STRING(LIM_MLM_ASSOC_CNF); + CASE_RETURN_STRING(LIM_MLM_ASSOC_IND); + CASE_RETURN_STRING(LIM_MLM_DISASSOC_REQ); + CASE_RETURN_STRING(LIM_MLM_DISASSOC_CNF); + CASE_RETURN_STRING(LIM_MLM_DISASSOC_IND); + CASE_RETURN_STRING(LIM_MLM_REASSOC_CNF); + CASE_RETURN_STRING(LIM_MLM_REASSOC_IND); + CASE_RETURN_STRING(LIM_MLM_DEAUTH_REQ); + CASE_RETURN_STRING(LIM_MLM_DEAUTH_CNF); + CASE_RETURN_STRING(LIM_MLM_DEAUTH_IND); + CASE_RETURN_STRING(LIM_MLM_TSPEC_REQ); + CASE_RETURN_STRING(LIM_MLM_TSPEC_CNF); + CASE_RETURN_STRING(LIM_MLM_SETKEYS_CNF); + CASE_RETURN_STRING(LIM_MLM_LINK_TEST_STOP_REQ); + CASE_RETURN_STRING(LIM_MLM_PURGE_STA_IND); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +/** + * mac_trace_get_info_log_string() - Get the log info + * @info_log: message type in numeric form + * + * This function will return a string equivalent of the message. + * + * Return: String equivalent of the message type. + **/ +uint8_t *mac_trace_get_info_log_string(uint16_t info_log) +{ + switch (info_log) { + CASE_RETURN_STRING(eLOG_NODROP_MISSED_BEACON_SCENARIO); + CASE_RETURN_STRING(eLOG_PROC_DEAUTH_FRAME_SCENARIO); + default: + return (uint8_t *) "UNKNOWN"; + break; + } +} + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm new file mode 100644 index 0000000000..4f6d0daa26 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parse_mac_trace.cmm @@ -0,0 +1,1022 @@ +;Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. + +;Permission to use, copy, modify, and/or distribute this software for +;any purpose with or without fee is hereby granted, provided that the +;above copyright notice and this permission notice appear in all +;copies. + +;THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +;WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +;WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +;AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +;DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +;PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +;TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +;PERFORMANCE OF THIS SOFTWARE. + +;parse_qdf_trace.cmm - This script parses QDF trace table and produces an output +;containing the details of table records(max. 4000 records) with their enums. +;The modules whose qdf trace records are covered in this script are: HDD, +;SME,PE,WMA,WMI. +;This script picks up the enums for module ID, code and data part from the dump +;only, for the records of modules: SME,PE,WMA and WMI. For HDD module, code type +;enums are hardcoded in script(hddcodetype). +;The script also relies on message id's placed in interface header file of +;the driver for the message types(enums) like: halmsgtype, limmsgtype, mgmttype +;and WMI_EVT_ID. +;For the above message id's, if some message ID's are changed later, since they +;do not use symbols from dump, this script might show incorrect data. +;So message ID's(hard-coded in script) should always be in sync with the driver code. + +;How to use the script:- +;1.Collect a crash dump and generate a Crash Report using CrashScope. +;2.Open Crash Report then select APPS, listed under Load dumps in simulator and +;load it(It will load the dump in trace32 simulator). +;3.After load completion change the directory to parse_qdf_trace.cmm script +;containing directory(using cd command at bottom space of simulator). +;4.To run the script on the loaded dump, enter command: "do parse_qdf_trace.cmm". +;5.select a folder, create a file and select it to store the output of script. + +;Author: +;Date: 06/30/2020 +;History:- +;Date Modified by Modification Information +;-------------------------------------------------------------------- + + +ENTRY &FILE + +IF "&FILE"=="" +( +DIALOG.file *.txt +ENTRY &FILE +) + +OPEN #1 "&FILE" /Create /Write /Append + +;present in legacy code script +;added and removed enums to sync with current driver code +Var.NEW char [0x21C][50] \halmsgtype + +Var.SET \halmsgtype[0x20]="SIR_HAL_RADAR_DETECTED_IND" +Var.SET \halmsgtype[0x21]="SIR_HAL_ADD_STA_REQ" +Var.SET \halmsgtype[0x22]="SIR_HAL_ADD_STA_RSP" +Var.SET \halmsgtype[0x23]="SIR_HAL_DELETE_STA_REQ" +Var.SET \halmsgtype[0x24]="SIR_HAL_DELETE_STA_RSP" +Var.SET \halmsgtype[0x25]="SIR_HAL_ADD_BSS_REQ" +;6 unused +Var.SET \halmsgtype[0x27]="SIR_HAL_DELETE_BSS_REQ" +Var.SET \halmsgtype[0x28]="SIR_HAL_DELETE_BSS_RSP" +;9 to 16 unused +Var.SET \halmsgtype[0x31]="SIR_HAL_SEND_BEACON_REQ" +;18 unused +Var.SET \halmsgtype[0x33]="SIR_HAL_SET_BSSKEY_RSP" +;20 unused +Var.SET \halmsgtype[0x35]="SIR_HAL_SET_STAKEY_RSP" +Var.SET \halmsgtype[0x36]="SIR_HAL_UPDATE_EDCA_PROFILE_IND" +Var.SET \halmsgtype[0x37]="SIR_HAL_UPDATE_BEACON_IND" +;24 unused +Var.SET \halmsgtype[0x39]="SIR_HAL_CHNL_SWITCH_REQ" +Var.SET \halmsgtype[0x3A]="SIR_HAL_ADD_TS_REQ" +Var.SET \halmsgtype[0x3B]="SIR_HAL_DEL_TS_REQ" +;28 to 33 macros unused +Var.SET \halmsgtype[0x42]="SIR_HAL_MISSED_BEACON_IND" +Var.SET \halmsgtype[0x43]="SIR_HAL_SWITCH_CHANNEL_RSP" +Var.SET \halmsgtype[0x44]="SIR_HAL_PWR_SAVE_CFG" +;37 to 42 unused +Var.SET \halmsgtype[0x4B]="SIR_HAL_IBSS_STA_ADD" +Var.SET \halmsgtype[0x4C]="SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND" +Var.SET \halmsgtype[0x4D]="SIR_HAL_SET_LINK_STATE" +Var.SET \halmsgtype[0x4E]="SIR_HAL_DELETE_BSS_HO_FAIL_REQ" +Var.SET \halmsgtype[0x4F]="SIR_HAL_DELETE_BSS_HO_FAIL_RSP" +;48 to 57 unused +Var.SET \halmsgtype[0x5A]="SIR_HAL_SET_STA_BCASTKEY_REQ" +Var.SET \halmsgtype[0x5B]="SIR_HAL_SET_STA_BCASTKEY_RSP" +Var.SET \halmsgtype[0x5C]="SIR_HAL_ADD_TS_RSP" +Var.SET \halmsgtype[0x5D]="SIR_HAL_DPU_MIC_ERROR" +;62 unused +Var.SET \halmsgtype[0x5F]="SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT" +Var.SET \halmsgtype[0x60]="SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ" +Var.SET \halmsgtype[0x61]="SIR_HAL_TIMER_ADC_RSSI_STATS" +;66 unused +Var.SET \halmsgtype[0x63]="SIR_HAL_SET_MIMOPS_REQ" +Var.SET \halmsgtype[0x64]="SIR_HAL_SET_MIMOPS_RSP" +Var.SET \halmsgtype[0x65]="SIR_HAL_SYS_READY_IND" +Var.SET \halmsgtype[0x66]="SIR_HAL_SET_TX_POWER_REQ" +Var.SET \halmsgtype[0x67]="SIR_HAL_SET_TX_POWER_RSP" +Var.SET \halmsgtype[0x68]="SIR_HAL_GET_TX_POWER_REQ" +;73 to 89 unused +Var.SET \halmsgtype[0x7A]="SIR_HAL_SET_KEY_DONE" +Var.SET \halmsgtype[0x7B]="SIR_HAL_BTC_SET_CFG" +;92 unused +Var.SET \halmsgtype[0x7D]="SIR_HAL_HANDLE_FW_MBOX_RSP" +Var.SET \halmsgtype[0x7E]="SIR_HAL_SEND_PROBE_RSP_TMPL" +Var.SET \halmsgtype[0x7F]="SIR_LIM_ADDR2_MISS_IND" +;96 & 97 unused +Var.SET \halmsgtype[0x82]="SIR_HAL_SET_MAX_TX_POWER_REQ" +Var.SET \halmsgtype[0x83]="SIR_HAL_SET_MAX_TX_POWER_RSP" +Var.SET \halmsgtype[0x84]="SIR_HAL_SET_HOST_OFFLOAD" +;101 t0 108 unused +Var.SET \halmsgtype[0x8D]="SIR_HAL_AGGR_QOS_REQ" +Var.SET \halmsgtype[0x8E]="SIR_HAL_AGGR_QOS_RSP" +;111 unused +Var.SET \halmsgtype[0x90]="SIR_HAL_P2P_NOA_ATTR_IND" +;113 to 114 unused +Var.SET \halmsgtype[0x93]="SIR_HAL_WLAN_SUSPEND_IND" +Var.SET \halmsgtype[0x94]="SIR_HAL_WLAN_RESUME_REQ" +Var.SET \halmsgtype[0x95]="SIR_HAL_SET_KEEP_ALIVE" +Var.SET \halmsgtype[0x96]="SIR_HAL_SET_NS_OFFLOAD" +;119 unused +Var.SET \halmsgtype[0x98]="SIR_HAL_SOC_ANTENNA_MODE_REQ" +Var.SET \halmsgtype[0x99]="SIR_HAL_SOC_ANTENNA_MODE_RESP" +;122 unused +;#ifdef WLAN_FEATURE_PACKET_FILTERING +Var.SET \halmsgtype[0x9B]="SIR_HAL_8023_MULTICAST_LIST_REQ" +Var.SET \halmsgtype[0x9C]="SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ" +Var.SET \halmsgtype[0x9D]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ" +Var.SET \halmsgtype[0x9E]="SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP" +Var.SET \halmsgtype[0x9F]="SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ" +;#endif /* WLAN_FEATURE_PACKET_FILTERING */ +;128 unused +;#ifdef WLAN_FEATURE_GTK_OFFLOAD +Var.SET \halmsgtype[0xA1]="SIR_HAL_GTK_OFFLOAD_REQ" +Var.SET \halmsgtype[0xA2]="SIR_HAL_GTK_OFFLOAD_GETINFO_REQ" +Var.SET \halmsgtype[0xA3]="SIR_HAL_GTK_OFFLOAD_GETINFO_RSP" +;#endif /* WLAN_FEATURE_GTK_OFFLOAD */ +;#ifdef FEATURE_WLAN_ESE +Var.SET \halmsgtype[0xA4]="SIR_HAL_TSM_STATS_REQ" +Var.SET \halmsgtype[0xA5]="SIR_HAL_TSM_STATS_RSP" +;#endif +Var.SET \halmsgtype[0xA6]="SIR_HAL_SET_TM_LEVEL_REQ" +Var.SET \halmsgtype[0xA7]="SIR_HAL_UPDATE_OP_MODE" +;136 & 137 unused +Var.SET \halmsgtype[0xAA]="SIR_HAL_ROAM_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xAB]="SIR_HAL_ROAM_PRE_AUTH_STATUS_IND" +;140 unused +Var.SET \halmsgtype[0xAD]="SIR_HAL_TRAFFIC_STATS_IND" +;#ifdef WLAN_FEATURE_11W +Var.SET \halmsgtype[0xAE]="SIR_HAL_EXCLUDE_UNENCRYPTED_IND" +;#endif +;#ifdef FEATURE_WLAN_TDLS +Var.SET \halmsgtype[0xAF]="SIR_HAL_TDLS_LINK_ESTABLISH_REQ" +Var.SET \halmsgtype[0xB0]="SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP" +;145 unused +;#endif +Var.SET \halmsgtype[0xB2]="SIR_HAL_STOP_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xB3]="SIR_HAL_RX_SCAN_EVENT" +Var.SET \halmsgtype[0xB4]="SIR_HAL_DHCP_START_IND" +Var.SET \halmsgtype[0xB5]="SIR_HAL_DHCP_STOP_IND" +;150 unused +Var.SET \halmsgtype[0xB7]="SIR_HAL_LPHB_CONF_IND" +Var.SET \halmsgtype[0xB8]="SIR_HAL_ADD_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xB9]="SIR_HAL_DEL_PERIODIC_TX_PTRN_IND" +Var.SET \halmsgtype[0xBA]="SIR_HAL_PDEV_DUAL_MAC_CFG_REQ" +Var.SET \halmsgtype[0xBB]="SIR_HAL_PDEV_MAC_CFG_RESP" +;156 and 158 unused +Var.SET \halmsgtype[0xBF]="SIR_HAL_RATE_UPDATE_IND" +Var.SET \halmsgtype[0xC0]="SIR_HAL_FLUSH_LOG_TO_FW" +Var.SET \halmsgtype[0xC1]="SIR_HAL_PDEV_SET_PCL_TO_FW" +;#ifdef WLAN_MWS_INFO_DEBUGFS +Var.SET \halmsgtype[0xC2]="SIR_HAL_GET_MWS_COEX_INFO_REQ" +;#endif /* WLAN_MWS_INFO_DEBUGFS */ +Var.SET \halmsgtype[0xC3]="SIR_HAL_CLI_SET_CMD" +;#ifndef REMOVE_PKT_LOG +Var.SET \halmsgtype[0xC4]="SIR_HAL_PKTLOG_ENABLE_REQ" +;#endif +;165 unused +Var.SET \halmsgtype[0xC6]="SIR_HAL_START_SCAN_OFFLOAD_REQ" +Var.SET \halmsgtype[0xC7]="SIR_HAL_UPDATE_CHAN_LIST_REQ" +;168 unused +Var.SET \halmsgtype[0xC9]="SIR_CSA_OFFLOAD_EVENT" +Var.SET \halmsgtype[0xCA]="SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ" +;171 unused +Var.SET \halmsgtype[0xCC]="SIR_HAL_UPDATE_MEMBERSHIP" +Var.SET \halmsgtype[0xCD]="SIR_HAL_UPDATE_USERPOS" +;#ifdef FEATURE_WLAN_TDLS +;174 unused +Var.SET \halmsgtype[0xCF]="SIR_HAL_UPDATE_TDLS_PEER_STATE" +Var.SET \halmsgtype[0xD0]="SIR_HAL_TDLS_SHOULD_DISCOVER" +Var.SET \halmsgtype[0xD1]="SIR_HAL_TDLS_SHOULD_TEARDOWN" +Var.SET \halmsgtype[0xD2]="SIR_HAL_TDLS_PEER_DISCONNECTED" +;#endif +Var.SET \halmsgtype[0xD3]="SIR_HAL_BEACON_TX_SUCCESS_IND" +;180 to 184 unused +Var.SET \halmsgtype[0xD9]="SIR_HAL_INIT_THERMAL_INFO_CMD" +Var.SET \halmsgtype[0xDA]="SIR_HAL_SET_THERMAL_LEVEL" +;#ifdef FEATURE_WLAN_ESE +Var.SET \halmsgtype[0xDB]="SIR_HAL_SET_PLM_REQ" +;#endif +Var.SET \halmsgtype[0xDC]="SIR_HAL_SET_TX_POWER_LIMIT" +Var.SET \halmsgtype[0xDD]="SIR_HAL_SET_SAP_INTRABSS_DIS" +Var.SET \halmsgtype[0xDE]="SIR_HAL_MODEM_POWER_STATE_IND" +Var.SET \halmsgtype[0xDF]="SIR_HAL_DISASSOC_TX_COMP" +Var.SET \halmsgtype[0xE0]="SIR_HAL_DEAUTH_TX_COMP" +Var.SET \halmsgtype[0xE1]="SIR_HAL_UPDATE_RX_NSS" +;#ifdef WLAN_FEATURE_STATS_EXT +Var.SET \halmsgtype[0xE2]="SIR_HAL_STATS_EXT_REQUEST" +;195 to 197 unused +Var.SET \halmsgtype[0xE6]="SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ" +Var.SET \halmsgtype[0xE7]="SIR_HAL_EXTSCAN_START_REQ" +Var.SET \halmsgtype[0xE8]="SIR_HAL_EXTSCAN_STOP_REQ" +Var.SET \halmsgtype[0xE9]="SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ" +Var.SET \halmsgtype[0xEA]="SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ" +Var.SET \halmsgtype[0xEB]="SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ" +Var.SET \halmsgtype[0xEC]="SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ" +Var.SET \halmsgtype[0xED]="SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ" +;#endif /* FEATURE_WLAN_EXTSCAN */ +;#ifdef FEATURE_WLAN_CH_AVOID +Var.SET \halmsgtype[0xEE]="SIR_HAL_CH_AVOID_UPDATE_REQ" +;#endif +;#ifdef WLAN_FEATURE_LINK_LAYER_STATS +Var.SET \halmsgtype[0xEF]="SIR_HAL_LL_STATS_CLEAR_REQ" +Var.SET \halmsgtype[0xF0]="SIR_HAL_LL_STATS_SET_REQ" +Var.SET \halmsgtype[0xF1]="SIR_HAL_LL_STATS_GET_REQ" +Var.SET \halmsgtype[0xF2]="SIR_HAL_LL_STATS_RESULTS_RSP" +;211 unused +Var.SET \halmsgtype[0xF4]="SIR_HAL_NAN_REQUEST" +;#endif /* WLAN_FEATURE_NAN */ +;#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +Var.SET \halmsgtype[0xF5]="SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ" +;#endif +Var.SET \halmsgtype[0xF6]="SIR_HAL_SET_BASE_MACADDR_IND" +;215 unused +Var.SET \halmsgtype[0xF8]="SIR_HAL_LINK_STATUS_GET_REQ" +;#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +Var.SET \halmsgtype[0xF9]="SIR_HAL_CONFIG_EXT_WOW" +Var.SET \halmsgtype[0xFA]="SIR_HAL_CONFIG_APP_TYPE1_PARAMS" +Var.SET \halmsgtype[0xFB]="SIR_HAL_CONFIG_APP_TYPE2_PARAMS" +;#endif +Var.SET \halmsgtype[0xFC]="SIR_HAL_GET_TEMPERATURE_REQ" +Var.SET \halmsgtype[0xFD]="SIR_HAL_SET_SCAN_MAC_OUI_REQ" +;#ifdef DHCP_SERVER_OFFLOAD +Var.SET \halmsgtype[0xFE]="SIR_HAL_SET_DHCP_SERVER_OFFLOAD" +;#endif /* DHCP_SERVER_OFFLOAD */ +Var.SET \halmsgtype[0xFF]="SIR_HAL_LED_FLASHING_REQ" +;224 unused +;#ifdef WLAN_FEATURE_ROAM_OFFLOAD +Var.SET \halmsgtype[0x101]="SIR_HAL_ROAM_OFFLOAD_SYNCH_IND" +Var.SET \halmsgtype[0x102]="SIR_HAL_ROAM_OFFLOAD_SYNCH_FAIL" +Var.SET \halmsgtype[0x103]="SIR_HAL_ROAM_INVOKE" +;#endif +;228 unused +Var.SET \halmsgtype[0x105]="SIR_HAL_SET_MAS" +Var.SET \halmsgtype[0x106]="SIR_HAL_SET_MIRACAST" +;#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +Var.SET \halmsgtype[0x107]="SIR_HAL_UPDATE_Q2Q_IE_IND" +;#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +Var.SET \halmsgtype[0x108]="SIR_HAL_CONFIG_STATS_FACTOR" +Var.SET \halmsgtype[0x109]="SIR_HAL_CONFIG_GUARD_TIME" +;234 unused +Var.SET \halmsgtype[0x10B]="SIR_HAL_ENTER_PS_REQ" +Var.SET \halmsgtype[0x10C]="SIR_HAL_EXIT_PS_REQ" +Var.SET \halmsgtype[0x10D]="SIR_HAL_ENABLE_UAPSD_REQ" +Var.SET \halmsgtype[0x10E]="SIR_HAL_DISABLE_UAPSD_REQ" +Var.SET \halmsgtype[0x10F]="SIR_HAL_GATEWAY_PARAM_UPDATE_REQ" +;240 to 312 unused +Var.SET \halmsgtype[0x159]="SIR_HAL_SET_EPNO_LIST_REQ" +;314 and 315 unused +Var.SET \halmsgtype[0x15C]="SIR_HAL_SET_PASSPOINT_LIST_REQ" +Var.SET \halmsgtype[0x15D]="SIR_HAL_RESET_PASSPOINT_LIST_REQ" +;318 unused +Var.SET \halmsgtype[0x15F]="SIR_HAL_OCB_SET_CONFIG_CMD" +Var.SET \halmsgtype[0x160]="SIR_HAL_OCB_SET_UTC_TIME_CMD" +Var.SET \halmsgtype[0x161]="SIR_HAL_OCB_START_TIMING_ADVERT_CMD" +Var.SET \halmsgtype[0x162]="SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD" +Var.SET \halmsgtype[0x163]="SIR_HAL_OCB_GET_TSF_TIMER_CMD" +Var.SET \halmsgtype[0x164]="SIR_HAL_DCC_GET_STATS_CMD" +Var.SET \halmsgtype[0x165]="SIR_HAL_DCC_CLEAR_STATS_CMD" +Var.SET \halmsgtype[0x166]="SIR_HAL_DCC_UPDATE_NDL_CMD" +;327 unused +Var.SET \halmsgtype[0x168]="SIR_HAL_START_STOP_LOGGING" +Var.SET \halmsgtype[0x169]="SIR_HAL_PDEV_SET_HW_MODE" +Var.SET \halmsgtype[0x16A]="SIR_HAL_PDEV_SET_HW_MODE_RESP" +Var.SET \halmsgtype[0x16B]="SIR_HAL_PDEV_HW_MODE_TRANS_IND" +Var.SET \halmsgtype[0x16C]="SIR_HAL_BAD_PEER_TX_CTL_INI_CMD" +Var.SET \halmsgtype[0x16D]="SIR_HAL_SET_RSSI_MONITOR_REQ" +Var.SET \halmsgtype[0x16E]="SIR_HAL_SET_IE_INFO" +Var.SET \halmsgtype[0x16F]="SIR_HAL_LRO_CONFIG_CMD" +;336 unused +Var.SET \halmsgtype[0x171]="SIR_HAL_HT40_OBSS_SCAN_IND" +Var.SET \halmsgtype[0x172]="SIR_HAL_TSF_GPIO_PIN_REQ" +Var.SET \halmsgtype[0x173]="SIR_HAL_ADD_BCN_FILTER_CMDID" +Var.SET \halmsgtype[0x174]="SIR_HAL_REMOVE_BCN_FILTER_CMDID" +Var.SET \halmsgtype[0x175]="SIR_HAL_APF_GET_CAPABILITIES_REQ" +Var.SET \halmsgtype[0x176]="SIR_HAL_APF_SET_INSTRUCTIONS_REQ" +Var.SET \halmsgtype[0x177]="SIR_HAL_SET_WISA_PARAMS" +Var.SET \halmsgtype[0x178]="SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS" +Var.SET \halmsgtype[0x179]="SIR_HAL_SET_PDEV_IE_REQ" +;346 to 359 unused +Var.SET \halmsgtype[0x188]="SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND" +;361 unused +Var.SET \halmsgtype[0x18A]="SIR_HAL_POWER_DBG_CMD" +Var.SET \halmsgtype[0x18B]="SIR_HAL_SET_DTIM_PERIOD" +;364 unused +Var.SET \halmsgtype[0x18D]="SIR_HAL_SHORT_RETRY_LIMIT_CNT" +Var.SET \halmsgtype[0x18E]="SIR_HAL_LONG_RETRY_LIMIT_CNT" +Var.SET \halmsgtype[0x18F]="SIR_HAL_UPDATE_TX_FAIL_CNT_TH" +Var.SET \halmsgtype[0x190]="SIR_HAL_POWER_DEBUG_STATS_REQ" +Var.SET \halmsgtype[0x191]="SIR_HAL_SET_WOW_PULSE_CMD" +;370 unused +Var.SET \halmsgtype[0x193]="SIR_HAL_SET_PER_ROAM_CONFIG_CMD" +Var.SET \halmsgtype[0x194]="SIR_HAL_RX_CHN_STATUS_EVENT" +Var.SET \halmsgtype[0x195]="SIR_HAL_GET_RCPI_REQ" +;374 to 377 unused +;#ifdef WLAN_FEATURE_LINK_LAYER_STATS +Var.SET \halmsgtype[0x19A]="SIR_HAL_LL_STATS_EXT_SET_THRESHOLD" +;#endif +;Var.SET \halmsgtype[0x19B]="SIR_HAL_SET_DBS_SCAN_SEL_PARAMS" +;379 +Var.SET \halmsgtype[0x19B]="SIR_HAL_HIDDEN_SSID_RESTART_RSP" +;379 +Var.SET \halmsgtype[0x19C]="SIR_HAL_INIT_ROAM_OFFLOAD_PARAM" +;381 to 386 unused +Var.SET \halmsgtype[0x1A3]="SIR_HAL_GET_PEER_INFO_EXT" +Var.SET \halmsgtype[0x1A4]="SIR_HAL_SET_ARP_STATS_REQ" +Var.SET \halmsgtype[0x1A5]="SIR_HAL_GET_ARP_STATS_REQ" +Var.SET \halmsgtype[0x1A6]="SIR_HAL_SET_LIMIT_OFF_CHAN" +Var.SET \halmsgtype[0x1A7]="SIR_HAL_SET_DEL_PMKID_CACHE" +Var.SET \halmsgtype[0x1A8]="SIR_HAL_HLP_IE_INFO" +Var.SET \halmsgtype[0x1A9]="SIR_HAL_OBSS_DETECTION_REQ" +Var.SET \halmsgtype[0x1AA]="SIR_HAL_OBSS_DETECTION_INFO" +Var.SET \halmsgtype[0x1AB]="SIR_HAL_INVOKE_NEIGHBOR_REPORT" +Var.SET \halmsgtype[0x1AC]="SIR_HAL_OBSS_COLOR_COLLISION_REQ" +Var.SET \halmsgtype[0x1AD]="SIR_HAL_OBSS_COLOR_COLLISION_INFO" +Var.SET \halmsgtype[0x1AE]="SIR_HAL_SEND_ADDBA_REQ" +Var.SET \halmsgtype[0x1AF]="SIR_HAL_GET_ROAM_SCAN_STATS" +Var.SET \halmsgtype[0x1B0]="SIR_HAL_SEND_AP_VDEV_UP" +Var.SET \halmsgtype[0x1B1]="SIR_HAL_SEND_BCN_RSP" +Var.SET \halmsgtype[0x1B2]="SIR_HAL_CFG_VENDOR_ACTION_TB_PPDU" +Var.SET \halmsgtype[0x1B3]="SIR_HAL_BEACON_DEBUG_STATS_REQ" +Var.SET \halmsgtype[0x1B4]="SIR_HAL_ROAM_BLACKLIST_MSG" +Var.SET \halmsgtype[0x1B5]="SIR_HAL_SET_MOTION_DET_CONFIG" +Var.SET \halmsgtype[0x1B6]="SIR_HAL_SET_MOTION_DET_ENABLE" +Var.SET \halmsgtype[0x1B7]="SIR_HAL_SET_MOTION_DET_BASE_LINE_CONFIG" +Var.SET \halmsgtype[0x1B8]="SIR_HAL_SET_MOTION_DET_BASE_LINE_ENABLE" +Var.SET \halmsgtype[0x1B9]="SIR_HAL_SET_THERMAL_THROTTLE_CFG" +Var.SET \halmsgtype[0x1BA]="SIR_HAL_SET_THERMAL_MGMT" +Var.SET \halmsgtype[0x1BB]="SIR_HAL_SEND_PEER_UNMAP_CONF" +Var.SET \halmsgtype[0x1BC]="SIR_HAL_GET_ISOLATION" +Var.SET \halmsgtype[0x1BD]="SIR_HAL_SET_ROAM_TRIGGERS" +Var.SET \halmsgtype[0x1BE]="SIR_HAL_ROAM_SCAN_CH_REQ" +Var.SET \halmsgtype[0x1BF]="SIR_HAL_REQ_SEND_DELBA_REQ_IND" +Var.SET \halmsgtype[0x1C0]="SIR_HAL_SEND_MAX_TX_POWER" +Var.SET \halmsgtype[0x1FF]="SIR_HAL_MSG_TYPES_END" + +;present in legacy code script +;added and removed enums to sync with current driver code +Var.NEW char [256][50] \limmsgtype + +Var.SET \limmsgtype[0xB4]="SIR_BB_XPORT_MGMT_MSG" +;5 and 0x10 unused +Var.SET \limmsgtype[0xC1]="SIR_LIM_DELETE_STA_CONTEXT_IND" +;0x12 unused +Var.SET \limmsgtype[0xC3]="SIR_LIM_UPDATE_BEACON" +Var.SET \limmsgtype[0xC5]="SIR_LIM_RX_INVALID_PEER" +;D0: 0 and 1 unused +Var.SET \limmsgtype[0xD2]="SIR_LIM_JOIN_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD3]="SIR_LIM_AUTH_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD4]="SIR_LIM_AUTH_RSP_TIMEOUT" +Var.SET \limmsgtype[0xD5]="SIR_LIM_ASSOC_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD6]="SIR_LIM_REASSOC_FAIL_TIMEOUT" +Var.SET \limmsgtype[0xD7]="SIR_LIM_HEART_BEAT_TIMEOUT" +;8, 9 and A unused +Var.SET \limmsgtype[0xDB]="SIR_LIM_PROBE_HB_FAILURE_TIMEOUT" +Var.SET \limmsgtype[0xDC]="SIR_LIM_ADDTS_RSP_TIMEOUT" +;0xD to 0x12 unused +Var.SET \limmsgtype[0xE3]="SIR_LIM_LINK_TEST_DURATION_TIMEOUT" +;0x14 to 0x16 unused +Var.SET \limmsgtype[0xE7]="SIR_LIM_CNF_WAIT_TIMEOUT" +;0x18 unused +Var.SET \limmsgtype[0xE9]="SIR_LIM_UPDATE_OLBC_CACHEL_TIMEOUT" +;0x1A, 0x1B, 0x1C unused +Var.SET \limmsgtype[0xED]="SIR_LIM_WPS_OVERLAP_TIMEOUT" +Var.SET \limmsgtype[0xEE]="SIR_LIM_FT_PREAUTH_RSP_TIMEOUT" +;0x21 and 0x22 unused +Var.SET \limmsgtype[0xF3]="SIR_LIM_BEACON_GEN_IND" +;0x24 , 0x25 unused +Var.SET \limmsgtype[0xF6]="SIR_LIM_DISASSOC_ACK_TIMEOUT" +Var.SET \limmsgtype[0xF7]="SIR_LIM_DEAUTH_ACK_TIMEOUT" +Var.SET \limmsgtype[0xF8]="SIR_LIM_PERIODIC_JOIN_PROBE_REQ_TIMEOUT" +;0x29, 0x2A, 0x2B and 0x2C unused +Var.SET \limmsgtype[0xFD]="SIR_LIM_AUTH_RETRY_TIMEOUT" +Var.SET \limmsgtype[0xFE]="SIR_LIM_AUTH_SAE_TIMEOUT" +Var.SET \limmsgtype[0xFF]="SIR_LIM_MSG_TYPES_END" + + +;present in legacy code script +;added and removed enums to sync with current driver code +Var.NEW char [16][50] \mgmttype + +Var.SET \mgmttype[0x0]="SIR_MAC_MGMT_ASSOC_REQ" +Var.SET \mgmttype[0x1]="SIR_MAC_MGMT_ASSOC_RSP" +Var.SET \mgmttype[0x2]="SIR_MAC_MGMT_REASSOC_REQ" +Var.SET \mgmttype[0x3]="SIR_MAC_MGMT_REASSOC_RSP" +Var.SET \mgmttype[0x4]="SIR_MAC_MGMT_PROBE_REQ" +Var.SET \mgmttype[0x5]="SIR_MAC_MGMT_PROBE_RSP" +Var.SET \mgmttype[0x6]="SIR_MAC_MGMT_TIME_ADVERT" +Var.SET \mgmttype[0x8]="SIR_MAC_MGMT_BEACON" +Var.SET \mgmttype[0x9]="SIR_MAC_MGMT_ATIM" +Var.SET \mgmttype[0xA]="SIR_MAC_MGMT_DISASSOC" +Var.SET \mgmttype[0xB]="SIR_MAC_MGMT_AUTH" +Var.SET \mgmttype[0xC]="SIR_MAC_MGMT_DEAUTH" +Var.SET \mgmttype[0xD]="SIR_MAC_MGMT_ACTION" +Var.SET \mgmttype[0xF]="SIR_MAC_MGMT_RESERVED15" + +;present in legacy code script +;added and removed enums to sync with current driver code +Var.NEW char [256][100] \hddcodetype + +Var.SET \hddcodetype[0x00]="TRACE_CODE_HDD_OPEN_REQUEST" +Var.SET \hddcodetype[0x01]="TRACE_CODE_HDD_STOP_REQUEST" +Var.SET \hddcodetype[0x02]="TRACE_CODE_HDD_TX_TIMEOUT" +Var.SET \hddcodetype[0x03]="TRACE_CODE_HDD_P2P_DEV_ADDR_IOCTL" +Var.SET \hddcodetype[0x04]="TRACE_CODE_HDD_SETSUSPENDMODE_IOCTL" +Var.SET \hddcodetype[0x05]="TRACE_CODE_HDD_SETROAMTRIGGER_IOCTL" +Var.SET \hddcodetype[0x06]="TRACE_CODE_HDD_GETROAMTRIGGER_IOCTL" +Var.SET \hddcodetype[0x07]="TRACE_CODE_HDD_SETROAMSCANPERIOD_IOCTL" +Var.SET \hddcodetype[0x08]="TRACE_CODE_HDD_GETROAMSCANPERIOD_IOCTL" +Var.SET \hddcodetype[0x09]="TRACE_CODE_HDD_SETROAMDELTA_IOCTL" +Var.SET \hddcodetype[0x0A]="TRACE_CODE_HDD_GETROAMDELTA_IOCTL" +Var.SET \hddcodetype[0x0B]="TRACE_CODE_HDD_GETBAND_IOCTL" +Var.SET \hddcodetype[0x0C]="TRACE_CODE_HDD_GETCOUNTRYREV_IOCTL" +Var.SET \hddcodetype[0x0D]="TRACE_CODE_HDD_SETROAMSCANCHANNELS_IOCTL" +Var.SET \hddcodetype[0x0E]="TRACE_CODE_HDD_GETROAMSCANCHANNELS_IOCTL" +Var.SET \hddcodetype[0x0F]="TRACE_CODE_HDD_HOSTAPD_OPEN_REQUEST" +Var.SET \hddcodetype[0x10]="TRACE_CODE_HDD_HOSTAPD_STOP_REQUEST" +Var.SET \hddcodetype[0x11]="TRACE_CODE_HDD_HOSTAPD_UNINIT_REQUEST" +Var.SET \hddcodetype[0x12]="TRACE_CODE_HDD_SOFTAP_TX_TIMEOUT" +Var.SET \hddcodetype[0x13]="TRACE_CODE_HDD_HOSTAPD_SET_MAC_ADDR" +Var.SET \hddcodetype[0x14]="TRACE_CODE_HDD_HOSTAPD_P2P_SET_NOA_IOCTL" +Var.SET \hddcodetype[0x15]="TRACE_CODE_HDD_HOSTAPD_P2P_SET_PS_IOCTL" +Var.SET \hddcodetype[0x16]="TRACE_CODE_HDD_HOSTAPD_SET_SAP_CHANNEL_LIST_IOCTL" +Var.SET \hddcodetype[0x17]="TRACE_CODE_HDD_ADD_VIRTUAL_INTF" +Var.SET \hddcodetype[0x18]="TRACE_CODE_HDD_DEL_VIRTUAL_INTF" +Var.SET \hddcodetype[0x19]="TRACE_CODE_HDD_CHANGE_VIRTUAL_INTF" +Var.SET \hddcodetype[0x1A]="TRACE_CODE_HDD_CFG80211_START_AP" +Var.SET \hddcodetype[0x1B]="TRACE_CODE_HDD_CFG80211_CHANGE_BEACON" +Var.SET \hddcodetype[0x1C]="TRACE_CODE_HDD_CFG80211_STOP_AP" +Var.SET \hddcodetype[0x1D]="TRACE_CODE_HDD_CFG80211_CHANGE_BSS" +Var.SET \hddcodetype[0x1E]="TRACE_CODE_HDD_CFG80211_ADD_KEY" +Var.SET \hddcodetype[0x1F]="TRACE_CODE_HDD_CFG80211_GET_KEY" +Var.SET \hddcodetype[0x20]="TRACE_CODE_HDD_CFG80211_SET_DEFAULT_KEY" +Var.SET \hddcodetype[0x21]="TRACE_CODE_HDD_CFG80211_CONNECT" +Var.SET \hddcodetype[0x22]="TRACE_CODE_HDD_CFG80211_DISCONNECT" +Var.SET \hddcodetype[0x23]="TRACE_CODE_HDD_CFG80211_JOIN_IBSS" +Var.SET \hddcodetype[0x24]="TRACE_CODE_HDD_CFG80211_LEAVE_IBSS" +Var.SET \hddcodetype[0x25]="TRACE_CODE_HDD_CFG80211_SET_WIPHY_PARAMS" +Var.SET \hddcodetype[0x26]="TRACE_CODE_HDD_CFG80211_SET_TXPOWER" +Var.SET \hddcodetype[0x27]="TRACE_CODE_HDD_CFG80211_GET_TXPOWER" +Var.SET \hddcodetype[0x28]="TRACE_CODE_HDD_CFG80211_SET_CHANNEL" +Var.SET \hddcodetype[0x29]="TRACE_CODE_HDD_CFG80211_ADD_BEACON" +Var.SET \hddcodetype[0x2A]="TRACE_CODE_HDD_CFG80211_SET_BEACON" +Var.SET \hddcodetype[0x2B]="TRACE_CODE_HDD_CFG80211_CHANGE_IFACE" +Var.SET \hddcodetype[0x2C]="TRACE_CODE_HDD_CHANGE_STATION" +Var.SET \hddcodetype[0x2D]="TRACE_CODE_HDD_CFG80211_UPDATE_BSS" +Var.SET \hddcodetype[0x2E]="TRACE_CODE_HDD_CFG80211_SCAN" +Var.SET \hddcodetype[0x2F]="TRACE_CODE_HDD_REMAIN_ON_CHANNEL" +Var.SET \hddcodetype[0x30]="TRACE_CODE_HDD_REMAINCHANREADYHANDLER" +Var.SET \hddcodetype[0x31]="TRACE_CODE_HDD_CFG80211_CANCEL_REMAIN_ON_CHANNEL" +Var.SET \hddcodetype[0x32]="TRACE_CODE_HDD_ACTION" +Var.SET \hddcodetype[0x33]="TRACE_CODE_HDD_MGMT_TX_CANCEL_WAIT" +Var.SET \hddcodetype[0x34]="TRACE_CODE_HDD_CFG80211_GET_STA" +Var.SET \hddcodetype[0x35]="TRACE_CODE_HDD_CFG80211_SET_POWER_MGMT" +Var.SET \hddcodetype[0x36]="TRACE_CODE_HDD_CFG80211_DEL_STA" +Var.SET \hddcodetype[0x37]="TRACE_CODE_HDD_CFG80211_ADD_STA" +Var.SET \hddcodetype[0x38]="TRACE_CODE_HDD_CFG80211_SET_PMKSA" +Var.SET \hddcodetype[0x39]="TRACE_CODE_HDD_CFG80211_UPDATE_FT_IES" +Var.SET \hddcodetype[0x3A]="TRACE_CODE_HDD_CFG80211_TDLS_MGMT" +Var.SET \hddcodetype[0x3B]="TRACE_CODE_HDD_CFG80211_TDLS_OPER" +Var.SET \hddcodetype[0x3C]="TRACE_CODE_HDD_CFG80211_SET_REKEY_DATA" +Var.SET \hddcodetype[0x3D]="TRACE_CODE_HDD_UNSUPPORTED_IOCTL" +Var.SET \hddcodetype[0x3E]="TRACE_CODE_HDD_SETROAMSCANCHANNELMINTIME_IOCTL" +Var.SET \hddcodetype[0x3F]="TRACE_CODE_HDD_GETROAMSCANCHANNELMINTIME_IOCTL" +Var.SET \hddcodetype[0x40]="TRACE_CODE_HDD_STORE_JOIN_REQ" +Var.SET \hddcodetype[0x41]="TRACE_CODE_HDD_CLEAR_JOIN_REQ" +Var.SET \hddcodetype[0x42]="TRACE_CODE_HDD_ISSUE_JOIN_REQ" +Var.SET \hddcodetype[0x43]="TRACE_CODE_HDD_CFG80211_RESUME_WLAN" +Var.SET \hddcodetype[0x44]="TRACE_CODE_HDD_CFG80211_SUSPEND_WLAN" +Var.SET \hddcodetype[0x45]="TRACE_CODE_HDD_CFG80211_SET_MAC_ACL" +Var.SET \hddcodetype[0x46]="TRACE_CODE_HDD_CFG80211_TESTMODE" +Var.SET \hddcodetype[0x47]="TRACE_CODE_HDD_CFG80211_DUMP_SURVEY" +Var.SET \hddcodetype[0x48]="TRACE_CODE_HDD_CFG80211_SCHED_SCAN_START" +Var.SET \hddcodetype[0x49]="TRACE_CODE_HDD_CFG80211_SCHED_SCAN_STOP" +Var.SET \hddcodetype[0x4A]="TRACE_CODE_HDD_CFG80211_DEL_PMKSA" +Var.SET \hddcodetype[0x4B]="TRACE_CODE_HDD_SEND_MGMT_TX" +;New CFG80211 enums to be added before this comment +;TRACE_CODE_HDD_RX_SME_MSG is used as code for MTRACE commands +;and also update the below index value +Var.SET \hddcodetype[0x4C]="TRACE_CODE_HDD_RX_SME_MSG" + +&TRACETYPESIZE=v.value(sizeof(qdf_trace_record_t)) +&TRACESIZE=v.value(sizeof(g_qdf_trace_tbl)) +&TRACEMAXINDEX=v.value(&TRACESIZE/&TRACETYPESIZE) + + +&HEAD=v.value(g_qdf_trace_data.head) +&TAIL=v.value(g_qdf_trace_data.tail) +&NUM=v.value(g_qdf_trace_data.num) +&num_last=v.value(g_qdf_trace_data.num_since_last_dump) +&enable=v.value(g_qdf_trace_data.enable) + + +IF ((&HEAD>=&TRACEMAXINDEX)||(&TAIL>=&TRACEMAXINDEX)||(&TAIL==&HEAD)) +( + GOTO ENDSCRIPT +) + +&INDEX=&HEAD + +TRACESTART: + +WRITE #1 "INDEX " &INDEX + +&QTIME=v.value(g_qdf_trace_tbl[&INDEX].qtime) +&TIME=v.value(g_qdf_trace_tbl[&INDEX].time) +&MODULE=v.value(g_qdf_trace_tbl[&INDEX].module) +&CODE=v.value(g_qdf_trace_tbl[&INDEX].code) +&SESSION=v.value(g_qdf_trace_tbl[&INDEX].session) +&DATA=v.value(g_qdf_trace_tbl[&INDEX].data) +&PID=v.value(g_qdf_trace_tbl[&INDEX].pid) + + +WRITE #1 "CODE: " &CODE +WRITE #1 "TIME: " &TIME +WRITE #1 "QTIME: " &QTIME +WRITE #1 "MODULE: " &MODULE +WRITE #1 "DATA: " &DATA +WRITE #1 "PID: " &PID + +Var.NEW QDF_MODULE_ID \module +Var.Set \module=&MODULE +Var.Write #1 "MODULE_NAME: " \module + +;added WMI module script code +;WMI module +IF (&MODULE==0x31) +( + &tmp = v.value(&CODE&0x7F) + &tmp1 = v.value(&CODE>>7) + &tmp2 = v.value(&tmp1<<12) + &code = v.value(&tmp|&tmp2) + + IF (&DATA==0x0) + ( + Var.NEW WMI_CMD_ID \wmicmdcode + Var.Set \wmicmdcode=&code + Var.Write #1 "CODE_wmicmdcode: " \wmicmdcode " [" %Hex &code "]" + ) + ELSE + ( + Var.Write #1 "CODE_wmievtcode: " %STRING \WMI_EVT_ID[&code] " [" %Hex &code "]" + ) + + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +;present in legacy code script +;modified If condition to accommodate 0x4C enum +;HDD_Module +IF (&MODULE==0x33) +( + + IF ((&CODE>=0x0)&&(&CODE<=0x4C)) + ( + Var.Write #1 "CODE: " %STRING \hddcodetype[&CODE] " [" %Hex &CODE "]" + WRITE #1 "DATA: " &DATA + ) + ELSE + ( + IF (&CODE==0x4B) + ( + Var.NEW eRoamCmdStatus \csrstatus + Var.Set \csrstatus=&DATA + Var.Write #1 "DATA_csrstatus: "\csrstatus " [" %Hex &DATA "]" + ) + ELSE + ( + WRITE #1 "CODE: " &CODE + WRITE #1 "DATA: " &DATA + ) + ) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +;present in legacy code script +;modified different If condition for the code msgs. +;added If condition for particular data msgs. +;SME_Module +IF (&MODULE==0x34) +( + IF ((&CODE>=0x0)&&(&CODE<=0x60)) + ( + Var.NEW enum smecodetype \smecode + Var.Set \smecode=&CODE + Var.Write #1 "CODE: " \smecode " [" %Hex &CODE "]" + ) + ELSE + ( + IF ((&CODE>=0xFA)&&(&CODE<=0xFC)) + ( + Var.NEW enum smecodetype \smecode + Var.Set \smecode=&CODE + Var.Write #1 "CODE: " \smecode " [" %Hex &CODE "]" + ) + IF ((&CODE>=0x1000)&&(&CODE<0x1400)) + ( + &code= v.value(&CODE-0x1000) + Var.Write #1 "CODE: " %STRING \halmsgtype[&code] " [" %Hex &code "]" + ) + IF ((&CODE>=0x1400)&&(&CODE<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&CODE + Var.Write #1 "CODE: " \smemsg " [" %Hex &CODE "]" + ) + ) + IF ((&DATA>=0x1000)&&(&DATA<=0x11C0)) + ( + &data= v.value(&DATA-0x1000) + Var.Write #1 "DATA_\halmsgtype: " %STRING \halmsgtype[&data] " [" %Hex &data "]" + ) + ELSE + ( + WRITE #1 "DATA: " &DATA + ) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +;present in legacy code script +;modified If conditions to sync with driver code. +;added If conditions for halmsgtype, limmsgtype, mlmmsgtype and +;wnimsgtype code types. Inside those If condition added +;conditions for their data part. +;PE_Module +IF (&MODULE==0x35) +( + IF (&CODE>=0x0)&&(&CODE<=0xF) + ( + Var.NEW enum pecodetype \pecode + Var.Set \pecode=&CODE + Var.Write #1 "CODE: " \pecode " [" %Hex &CODE "]" + ) + +;PEcodetype code +;0 TRACE_CODE_MLM_STATE + IF (&CODE==0x0) + ( + Var.NEW tLimMlmStates \mlmstate + Var.Set \mlmstate=&DATA + Var.Write #1 "DATA_mlmstate: " \mlmstate " [" %Hex &DATA "]" + ) + +;1 TRACE_CODE_SME_STATE + IF (&CODE==0x1) + ( + Var.NEW tLimSmeStates \smestate + Var.Set \smestate=&DATA + Var.Write #1 "DATA_smestate: " \smestate " [" %Hex &DATA "]" + ) + +;2 TRACE_CODE_TX_MGMT + IF (&CODE==0x2) + ( + WRITE #1 "DATA: " &DATA + ) + +;3 TRACE_CODE_RX_MGMT + IF (&CODE==0x3) + ( + &SERIAL=v.value(&DATA>>16) + &SUBTYPE=v.value(&DATA&0xFF) + IF (&SUBTYPE<=0xF) + ( + Var.Write #1 "DATA_mgmttype: " %STRING \mgmttype[&SUBTYPE] + WRITE #1 "SEQ NUM: " &SERIAL + ) + else + ( + WRITE #1 "INCORRECT DATA" + ) + ) + +;4 TRACE_CODE_RX_MGMT_TSF + IF (&CODE==0x4) + ( + WRITE #1 "BEACON TS: " &DATA + ) + +;5 TRACE_CODE_TX_COMPLETE + IF (&CODE==0x5) + ( + Var.Write #1 "DATA_mgmttype: " %STRING \mgmttype[&DATA] " [" %Hex &DATA "]" + ) + +;6 TRACE_CODE_TX_SME_MSG + IF (&CODE==0x6) + ( + &MOD=v.value(&DATA>>8) + &MSG=v.value(&DATA&0xFF) + IF (&DATA>=0x1300)&&(&DATA<=13FE) + ( + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" + ) + IF (&MOD==0x14)&&(&DATA>=0x1400) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &DATA "]" + ) + ) + +;7 TRACE_CODE_RX_SME_MSG + IF (&CODE==0x7) + ( + &MOD=v.value(&DATA>>8) + IF (&MOD==0x14) + ( + IF (&DATA>=0x1400)&&(&DATA<=0x14A3) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &DATA "]" + ) + ) + ) + +;8 TRACE_CODE_TX_WMA_MSG + IF (&CODE==0x8) + ( + &MOD=v.value(&DATA>>8) + &MSG=v.value(&DATA&0xFFF) + IF (&MOD==0x10) + ( + Var.Write #1 "DATA_halmsgtype: " %STRING \halmsgtype[&MSG] " [" %Hex &MSG "]" + ) + ) + +;9 TRACE_CODE_RX_WMA_MSG + IF (&CODE==0x9) + ( + &MOD=v.value(&DATA>>8) + &MSG=v.value(&DATA&0xFFF) + IF (&MOD==0x10) + ( + Var.Write #1 "DATA_halmsgtype: " %STRING \halmsgtype[&MSG] " [" %Hex &MSG "]" + ) + ) + +;10 TRACE_CODE_TX_LIM_MSG + IF (&CODE==0xA) + ( + IF ((&DATA>=0x3E8)&&(&DATA<=0x410)) + ( + Var.NEW enum mlmmsgtype \mlmmsg + Var.Set \mlmmsg=&DATA + Var.Write #1 "DATA_mlmmsgtype: " \mlmmsg " [" %Hex &DATA "]" + ) + IF (&DATA>=0x1300)&&(&DATA<=13FE) + ( + &MSG=v.value(&DATA&0xFF) + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" + ) + &DATA=v.value(&DATA&0xFFFF) + IF ((&DATA>=0x1400)&&(&DATA<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &DATA "]" + ) + ) + +;11 TRACE_CODE_RX_LIM_MSG + IF (&CODE==0xB) + ( + IF (&DATA>=0x1300)&&(&DATA<=13FE) + ( + &MSG=v.value(&DATA&0xFF) + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&MSG] " [" %Hex &MSG "]" + ) + &DATA=v.value(&DATA&0xFFFF) + IF (&DATA>=0x1400)&&(&DATA<=14A3) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &DATA "]" + ) + ) + +;12 TRACE_CODE_RX_MGMT_DROP + IF (&CODE==0xC) + ( + Var.NEW tMgmtFrmDropReason \dropreason + Var.Set \dropreason=&DATA + Var.Write #1 "DATA_dropreason: " \dropreason " [" %Hex &DATA "]" + ) + +;13/14 TRACE_CODE_TIMER_ACTIVATE/DEACTIVATE + IF (&CODE==0xD)||(&CODE==0xE) + ( + IF (&DATA>=0x0)&&(&DATA<=0x16) + ( + Var.NEW enum limtimertype \limtimermsg + Var.Set \limtimermsg=&DATA + Var.Write #1 "DATA_limtimertype: " \limtimermsg " [" %Hex &DATA "]" + ) + IF (&DATA>=0x1400)&&(&DATA<=14A3) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&DATA + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &DATA "]" + ) + ) + +;HalMsgType code + IF (&CODE>=0x1020)&&(&CODE<=0x11C0) + ( + &code=v.value(&CODE-0x1000) + Var.Write #1 "CODE_halmsgtype: " %STRING \halmsgtype[&code] " [" %Hex &code "]" + + &data=v.value(&DATA&0xFFFF) + IF ((&data>=0x1000)&&(&data<=11C0)) + ( + &val=v.value(&data-0x1000) + Var.Write #1 "DATA_halmsgtype: " %STRING \halmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1300)&&(&data<=13FE)) + ( + &val=v.value(&data-0x1300) + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1400)&&(&data<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&data + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &data "]" + ) + ) + +;WniMsgType code + IF (&CODE>=0x1400)&&(&CODE<=0x14A3) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&CODE + Var.Write #1 "CODE_eWniMsgTypes: " \smemsg " [" %Hex &CODE "]" + + &data=v.value(&DATA&0xFFFF) + IF ((&data>=0x1000)&&(&data<=11C0)) + ( + &val=v.value(&data-0x1000) + Var.Write #1 "DATA_halmsgtype: " %STRING \halmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1300)&&(&data<=13FE)) + ( + &val=v.value(&data-0x1300) + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1400)&&(&data<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&data + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &data "]" + ) + ) + +;Limmsgtype code + IF ((&CODE>=0x1300)&&(&CODE<=13FE)) + ( + &code=v.value(&CODE-0x1300) + Var.Write #1 "CODE_limmsgtype: " %STRING \limmsgtype[&code] " [" %Hex &code "]" + + &data=v.value(&DATA&0xFFFF) + IF ((&data>=0x1000)&&(&data<=11C0)) + ( + &val=v.value(&data-0x1000) + Var.Write #1 "DATA_halmsgtype: " %STRING \halmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1300)&&(&data<=13FE)) + ( + &val=v.value(&data-0x1300) + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1400)&&(&data<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&data + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &data "]" + ) + ) + +;mlmmsgtype code + IF ((&CODE>=0x3E8)&&(&CODE<=0x410)) + ( + Var.NEW enum mlmmsgtype \mlmmsg + Var.Set \mlmmsg=&CODE + Var.Write #1 "CODE_mlmmsgtype: " \mlmmsg " [" %Hex &CODE "]" + + &data=v.value(&DATA&0xFFFF) + IF ((&data>=0x3E8)&&(&data<=0x410)) + ( + Var.NEW enum mlmmsgtype \mlmmsg + Var.Set \mlmmsg=&data + Var.Write #1 "DATA_mlmmsgtype: " \mlmmsg " [" %Hex &data "]" + ) + IF ((&data>=0x1000)&&(&data<=11C0)) + ( + &val=v.value(&data-0x1000) + Var.Write #1 "DATA_halmsgtype: " %STRING \halmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1300)&&(&data<=13FE)) + ( + &val=v.value(&data-0x1300) + Var.Write #1 "DATA_limmsgtype: " %STRING \limmsgtype[&val] " [" %Hex &val "]" + ) + IF ((&data>=0x1400)&&(&data<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&data + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &data "]" + ) + ) + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +;added WMA module script code +;WMA module +IF (&MODULE==0x36) +( + IF ((&CODE>=0x0)&&(&CODE<=0x60)) + ( + Var.NEW enum wmamsgtype \wmacode + Var.Set \wmacode=&CODE + Var.Write #1 "CODE: " \wmacode " [" %Hex &CODE "]" + ) + IF ((&CODE>=0x1000)&&(&CODE<0x1400)) + ( + &code= v.value(&CODE-0x1000) + Var.Write #1 "CODE: " %STRING \halmsgtype[&code] " [" %Hex &code "]" + ) + IF ((&CODE>=0x1400)&&(&CODE<=14A3)) + ( + Var.NEW enum eWniMsgTypes \smemsg + Var.Set \smemsg=&CODE + Var.Write #1 "DATA_eWniMsgTypes: " \smemsg " [" %Hex &CODE "]" + ) + WRITE #1 "DATA: " &DATA + + IF (&SESSION==0xFF) + ( + WRITE #1 "NO SESSION" + ) + ELSE + ( + WRITE #1 "SESSION: " &SESSION + ) +) + +WRITE #1 " " + +&INDEX=v.value((&INDEX+1)%(&TRACEMAXINDEX)) + + IF (&INDEX!=&HEAD) + ( + GOTO TRACESTART + ) + + + +ENDSCRIPT: +CLOSE #1 +ENDDO diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c new file mode 100644 index 0000000000..5a1893860d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/parser_api.c @@ -0,0 +1,13240 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * This file parser_api.cc contains the code for parsing + * 802.11 messages. + * Author: Pierre Vandwalle + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "sir_api.h" +#include "ani_global.h" +#include "parser_api.h" +#include "lim_utils.h" +#include "utils_parser.h" +#include "lim_ser_des_utils.h" +#include "sch_api.h" +#include "wmm_apsd.h" +#include "rrm_api.h" + +#include "cds_regdomain.h" +#include "qdf_crypto.h" +#include "lim_process_fils.h" +#include "wlan_utility.h" +#include "wifi_pos_api.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_api.h" +#include "wlan_reg_services_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_twt_cfg_ext_api.h" +#include +#ifdef WLAN_FEATURE_11BE_MLO +#include +#include +#endif +#ifdef WLAN_FEATURE_11BE +#include "wlan_epcs_api.h" +#include +#endif +#include "wlan_mlo_mgr_link_switch.h" + +#define RSN_OUI_SIZE 4 +/* ////////////////////////////////////////////////////////////////////// */ +void swap_bit_field16(uint16_t in, uint16_t *out) +{ +#ifdef ANI_LITTLE_BIT_ENDIAN + *out = in; +#else /* Big-Endian... */ + *out = ((in & 0x8000) >> 15) | + ((in & 0x4000) >> 13) | + ((in & 0x2000) >> 11) | + ((in & 0x1000) >> 9) | + ((in & 0x0800) >> 7) | + ((in & 0x0400) >> 5) | + ((in & 0x0200) >> 3) | + ((in & 0x0100) >> 1) | + ((in & 0x0080) << 1) | + ((in & 0x0040) << 3) | + ((in & 0x0020) << 5) | + ((in & 0x0010) << 7) | + ((in & 0x0008) << 9) | + ((in & 0x0004) << 11) | + ((in & 0x0002) << 13) | ((in & 0x0001) << 15); +#endif /* ANI_LITTLE_BIT_ENDIAN */ +} + +static inline void __print_wmm_params(struct mac_context *mac, + tDot11fIEWMMParams *pWmm) +{ + pe_nofl_debug("WMM: BE: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d, " + "BK: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d, " + "VI: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d, " + "VO: aifsn %d, acm %d, aci %d, cwmin %d, cwmax %d, txop %d", + pWmm->acbe_aifsn, pWmm->acbe_acm, pWmm->acbe_aci, + pWmm->acbe_acwmin, pWmm->acbe_acwmax, + pWmm->acbe_txoplimit, + pWmm->acbk_aifsn, pWmm->acbk_acm, pWmm->acbk_aci, + pWmm->acbk_acwmin, pWmm->acbk_acwmax, + pWmm->acbk_txoplimit, + pWmm->acvi_aifsn, pWmm->acvi_acm, pWmm->acvi_aci, + pWmm->acvi_acwmin, pWmm->acvi_acwmax, + pWmm->acvi_txoplimit, + pWmm->acvo_aifsn, pWmm->acvo_acm, pWmm->acvo_aci, + pWmm->acvo_acwmin, pWmm->acvo_acwmax, + pWmm->acvo_txoplimit); +} + +/* ////////////////////////////////////////////////////////////////////// */ +/* Functions for populating "dot11f" style IEs */ + +/* return: >= 0, the starting location of the IE in rsnIEdata inside tSirRSNie */ +/* < 0, cannot find */ +int find_ie_location(struct mac_context *mac, tpSirRSNie pRsnIe, uint8_t EID) +{ + int idx, ieLen, bytesLeft; + int ret_val = -1; + + /* Here's what's going on: 'rsnIe' looks like this: */ + + /* typedef struct sSirRSNie */ + /* { */ + /* uint16_t length; */ + /* uint8_t rsnIEdata[WLAN_MAX_IE_LEN+2]; */ + /* } tSirRSNie, *tpSirRSNie; */ + + /* other code records both the WPA & RSN IEs (including their EIDs & */ + /* lengths) into the array 'rsnIEdata'. We may have: */ + + /* With WAPI support, there may be 3 IEs here */ + /* It can be only WPA IE, or only RSN IE or only WAPI IE */ + /* Or two or all three of them with no particular ordering */ + + /* The if/then/else statements that follow are here to figure out */ + /* whether we have the WPA IE, and where it is if we *do* have it. */ + + /* Save the first IE length */ + ieLen = pRsnIe->rsnIEdata[1] + 2; + idx = 0; + bytesLeft = pRsnIe->length; + + while (1) { + if (EID == pRsnIe->rsnIEdata[idx]) + /* Found it */ + return idx; + if (EID != pRsnIe->rsnIEdata[idx] && + /* & if no more IE, */ + bytesLeft <= (uint16_t)(ieLen)) + return ret_val; + + bytesLeft -= ieLen; + ieLen = pRsnIe->rsnIEdata[idx + 1] + 2; + idx += ieLen; + } + + return ret_val; +} + +QDF_STATUS +populate_dot11f_capabilities(struct mac_context *mac, + tDot11fFfCapabilities *pDot11f, + struct pe_session *pe_session) +{ + uint16_t cfg; + QDF_STATUS nSirStatus; + + nSirStatus = lim_get_capability_info(mac, &cfg, pe_session); + if (QDF_STATUS_SUCCESS != nSirStatus) { + pe_err("Failed to retrieve the Capabilities bitfield from CFG status: %d", + nSirStatus); + return nSirStatus; + } + + swap_bit_field16(cfg, (uint16_t *) pDot11f); + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_capabilities. */ + +/** + * populate_dot_11_f_ext_chann_switch_ann() - Function to populate ECS + * @mac_ptr: Pointer to PMAC structure + * @dot_11_ptr: ECS element + * @session_entry: PE session entry + * + * This function is used to populate the extended channel switch element + * + * Return: None + */ +void populate_dot_11_f_ext_chann_switch_ann(struct mac_context *mac_ptr, + tDot11fIEext_chan_switch_ann *dot_11_ptr, + struct pe_session *session_entry) +{ + uint8_t ch_offset; + uint32_t sw_target_freq; + uint8_t primary_channel; + enum phy_ch_width ch_width; + + ch_width = session_entry->gLimChannelSwitch.ch_width; + ch_offset = session_entry->gLimChannelSwitch.sec_ch_offset; + + dot_11_ptr->switch_mode = session_entry->gLimChannelSwitch.switchMode; + sw_target_freq = session_entry->gLimChannelSwitch.sw_target_freq; + primary_channel = session_entry->gLimChannelSwitch.primaryChannel; + dot_11_ptr->new_reg_class = + lim_op_class_from_bandwidth(mac_ptr, sw_target_freq, ch_width, + ch_offset); + dot_11_ptr->new_channel = + session_entry->gLimChannelSwitch.primaryChannel; + dot_11_ptr->switch_count = + session_entry->gLimChannelSwitch.switchCount; + dot_11_ptr->present = 1; +} + +#define TIME_UNIT 1024 //time unit (TU): A measurement of time equal to 1024 us +void +populate_dot11f_max_chan_switch_time(struct mac_context *mac, + tDot11fIEmax_chan_switch_time *pDot11f, + struct pe_session *pe_session) +{ + uint32_t switch_time = pe_session->cac_duration_ms; + + if (!switch_time) { + pDot11f->present = 0; + return; + } + + switch_time = qdf_do_div(switch_time * 1000, TIME_UNIT); + + pDot11f->switch_time[0] = switch_time & 0xff; + pDot11f->switch_time[1] = (switch_time >> 8) & 0xff; + pDot11f->switch_time[2] = (switch_time >> 16) & 0xff; + + pDot11f->present = 1; +} + +void populate_dot11f_non_inheritance( + struct mac_context *mac_ctx, + tDot11fIEnon_inheritance *non_inheritance, + uint8_t *non_inher_ie_lists, + uint8_t *non_inher_ext_ie_lists, + uint8_t non_inher_len, uint8_t non_inher_ext_len) +{ + uint8_t *non_inher_data; + + non_inher_data = non_inheritance->data; + non_inheritance->num_data = 0; + non_inheritance->present = 1; + *non_inher_data++ = non_inher_len; + non_inheritance->num_data++; + qdf_mem_copy(non_inher_data, + non_inher_ie_lists, + non_inher_len); + non_inher_data += non_inher_len; + non_inheritance->num_data += non_inher_len; + *non_inher_data++ = non_inher_ext_len; + non_inheritance->num_data++; + qdf_mem_copy(non_inher_data, + non_inher_ext_ie_lists, + non_inher_ext_len); + non_inheritance->num_data += non_inher_ext_len; +} + +void +populate_dot11f_chan_switch_ann(struct mac_context *mac, + tDot11fIEChanSwitchAnn *pDot11f, + struct pe_session *pe_session) +{ + pDot11f->switchMode = pe_session->gLimChannelSwitch.switchMode; + pDot11f->newChannel = pe_session->gLimChannelSwitch.primaryChannel; + pDot11f->switchCount = + (uint8_t) pe_session->gLimChannelSwitch.switchCount; + + pDot11f->present = 1; +} + +/** + * populate_dot11_supp_operating_classes() - Function to populate supported + * operating class IE + * @mac_ptr: Pointer to PMAC structure + * @dot_11_ptr: Operating class element + * @session_entry: PE session entry + * + * Return: None + */ +void +populate_dot11_supp_operating_classes(struct mac_context *mac_ptr, + tDot11fIESuppOperatingClasses *dot_11_ptr, + struct pe_session *session_entry) +{ + uint8_t ch_offset; + + if (session_entry->ch_width == CH_WIDTH_80MHZ) { + ch_offset = BW80; + } else { + switch (session_entry->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_offset = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_offset = BW40_LOW_PRIMARY; + break; + default: + ch_offset = BW20; + break; + } + } + + wlan_reg_dmn_get_curr_opclasses(&dot_11_ptr->num_classes, + &dot_11_ptr->classes[1]); + dot_11_ptr->classes[0] = + lim_op_class_from_bandwidth(mac_ptr, + session_entry->curr_op_freq, + session_entry->ch_width, + ch_offset); + dot_11_ptr->num_classes++; + dot_11_ptr->present = 1; +} + +void +populate_dot11f_tx_power_env(struct mac_context *mac, + tDot11fIEtransmit_power_env *tpe_ptr, + enum phy_ch_width chan_width, uint32_t chan_freq, + uint16_t *num_tpe, bool is_chan_switch) +{ + uint8_t count; + uint16_t eirp_power, reg_power; + int power_for_bss; + bool add_eirp_power = false; + struct ch_params chan_params; + bool psd_tpe = false; + uint32_t bw_threshold, bw_val; + int num_tpe_ies = 0; + uint32_t num_tx_power, num_tx_power_psd; + uint32_t max_tx_pwr_count, max_tx_pwr_count_psd; + qdf_freq_t psd_start_freq; + + if (!wlan_reg_is_6ghz_chan_freq(chan_freq)) { + psd_tpe = false; + } else { + wlan_reg_get_client_power_for_6ghz_ap(mac->pdev, + REG_DEFAULT_CLIENT, + chan_freq, + &psd_tpe, + ®_power, &eirp_power); + pe_debug("chan_freq %d, reg_power %d, psd_power %d", + chan_freq, reg_power, eirp_power); + } + + switch (chan_width) { + case CH_WIDTH_20MHZ: + max_tx_pwr_count = 0; + max_tx_pwr_count_psd = 1; + num_tx_power = 1; + num_tx_power_psd = 1; + break; + + case CH_WIDTH_40MHZ: + max_tx_pwr_count = 1; + max_tx_pwr_count_psd = 2; + num_tx_power = 2; + num_tx_power_psd = 2; + break; + + case CH_WIDTH_80MHZ: + max_tx_pwr_count = 2; + max_tx_pwr_count_psd = 3; + num_tx_power = 3; + num_tx_power_psd = 4; + break; + + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + max_tx_pwr_count = 3; + max_tx_pwr_count_psd = 4; + num_tx_power = 4; + num_tx_power_psd = 8; + break; + default: + return; + } + + if (!psd_tpe) { + reg_power = wlan_reg_get_channel_reg_power_for_freq( + mac->pdev, chan_freq); + + tpe_ptr->present = 1; + tpe_ptr->max_tx_pwr_count = max_tx_pwr_count; + tpe_ptr->max_tx_pwr_interpret = 0; + tpe_ptr->max_tx_pwr_category = 0; + tpe_ptr->num_tx_power = num_tx_power; + for (count = 0; count < num_tx_power; count++) + tpe_ptr->tx_power[count] = reg_power; + + num_tpe_ies++; + tpe_ptr++; + } else { + + bw_val = wlan_reg_get_bw_value(chan_width); + bw_threshold = 20; + power_for_bss = eirp_power + 13; + + while ((reg_power > power_for_bss) && + (bw_threshold < bw_val)) { + bw_threshold = 2 * bw_threshold; + power_for_bss += 3; + } + if (bw_threshold < bw_val) + add_eirp_power = true; + + pe_debug("bw_threshold %d", bw_threshold); + + if (add_eirp_power) { + tpe_ptr->present = 1; + tpe_ptr->max_tx_pwr_count = max_tx_pwr_count; + tpe_ptr->max_tx_pwr_interpret = 2; + tpe_ptr->max_tx_pwr_category = 0; + tpe_ptr->num_tx_power = num_tx_power; + for (count = 0; count < num_tx_power; count++) { + tpe_ptr->tx_power[count] = reg_power * 2; + pe_debug("non-psd default TPE %d %d", + count, tpe_ptr->tx_power[count]); + } + num_tpe_ies++; + tpe_ptr++; + } + + wlan_reg_get_client_power_for_6ghz_ap(mac->pdev, + REG_SUBORDINATE_CLIENT, + chan_freq, + &psd_tpe, + ®_power, + &eirp_power); + + if (reg_power) { + bw_val = wlan_reg_get_bw_value(chan_width); + bw_threshold = 20; + power_for_bss = eirp_power + 13; + + while ((reg_power > power_for_bss) && + (bw_threshold < bw_val)) { + bw_threshold = 2 * bw_threshold; + power_for_bss += 3; + } + if (bw_threshold < bw_val) + add_eirp_power = true; + + if (add_eirp_power) { + tpe_ptr->present = 1; + tpe_ptr->max_tx_pwr_count = max_tx_pwr_count; + tpe_ptr->max_tx_pwr_interpret = 2; + tpe_ptr->max_tx_pwr_category = 1; + tpe_ptr->num_tx_power = num_tx_power; + for (count = 0; count < num_tx_power; count++) { + tpe_ptr->tx_power[count] = + reg_power * 2; + pe_debug("non-psd subord TPE %d %d", + count, + tpe_ptr->tx_power[count]); + } + num_tpe_ies++; + tpe_ptr++; + } + } + + tpe_ptr->present = 1; + tpe_ptr->max_tx_pwr_count = max_tx_pwr_count_psd; + tpe_ptr->max_tx_pwr_interpret = 3; + tpe_ptr->max_tx_pwr_category = 0; + tpe_ptr->num_tx_power = num_tx_power_psd; + + chan_params.ch_width = chan_width; + bw_val = wlan_reg_get_bw_value(chan_width); + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, chan_freq, + chan_freq, &chan_params, + REG_CURRENT_PWR_MODE); + + if (chan_params.mhz_freq_seg1) + psd_start_freq = + chan_params.mhz_freq_seg1 - bw_val / 2 + 10; + else + psd_start_freq = + chan_params.mhz_freq_seg0 - bw_val / 2 + 10; + + for (count = 0; count < num_tx_power_psd; count++) { + wlan_reg_get_client_power_for_6ghz_ap( + mac->pdev, + REG_DEFAULT_CLIENT, + psd_start_freq + + 20 * count, + &psd_tpe, + ®_power, + &eirp_power); + tpe_ptr->tx_power[count] = eirp_power * 2; + pe_debug("psd default TPE %d %d", + count, tpe_ptr->tx_power[count]); + } + num_tpe_ies++; + tpe_ptr++; + + wlan_reg_get_client_power_for_6ghz_ap(mac->pdev, + REG_SUBORDINATE_CLIENT, + chan_freq, + &psd_tpe, + ®_power, + &eirp_power); + + if (eirp_power) { + tpe_ptr->present = 1; + tpe_ptr->max_tx_pwr_count = max_tx_pwr_count_psd; + tpe_ptr->max_tx_pwr_interpret = 3; + tpe_ptr->max_tx_pwr_category = 1; + tpe_ptr->num_tx_power = num_tx_power_psd; + + for (count = 0; count < num_tx_power_psd; count++) { + wlan_reg_get_client_power_for_6ghz_ap( + mac->pdev, + REG_SUBORDINATE_CLIENT, + psd_start_freq + + 20 * count, + &psd_tpe, + ®_power, + &eirp_power); + tpe_ptr->tx_power[count] = eirp_power * 2; + pe_debug("psd subord TPE %d %d", + count, tpe_ptr->tx_power[count]); + } + num_tpe_ies++; + tpe_ptr++; + } + } + *num_tpe = num_tpe_ies; +} + +void +populate_dot11f_chan_switch_wrapper(struct mac_context *mac, + tDot11fIEChannelSwitchWrapper *pDot11f, + struct pe_session *pe_session) +{ + uint16_t num_tpe; + /* + * The new country subelement is present only when + * 1. AP performs Extended Channel switching to new country. + * 2. New Operating Class table or a changed set of operating + * classes relative to the contents of the country element sent + * in the beacons. + * + * In the current scenario Channel Switch wrapper IE is included + * when we a radar is found and the AP does a channel change in + * the same regulatory domain(No country change or Operating class + * table). So, we do not need to include the New Country IE. + * + * Transmit Power Envlope Subelement is optional + * in Channel Switch Wrapper IE. So, not setting + * the TPE subelement. We include only WiderBWChanSwitchAnn. + */ + pDot11f->present = 1; + + /* + * Add the Wide Channel Bandwidth Sublement. + */ + pDot11f->WiderBWChanSwitchAnn.newChanWidth = + pe_session->gLimWiderBWChannelSwitch.newChanWidth; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq0 = + pe_session->gLimWiderBWChannelSwitch.newCenterChanFreq0; + pDot11f->WiderBWChanSwitchAnn.newCenterChanFreq1 = + pe_session->gLimWiderBWChannelSwitch.newCenterChanFreq1; + pDot11f->WiderBWChanSwitchAnn.present = 1; + + /* + * Add the Transmit power Envelope Sublement. + */ + if (pe_session->vhtCapability) { + populate_dot11f_tx_power_env(mac, + &pDot11f->transmit_power_env, + pe_session->gLimChannelSwitch.ch_width, + pe_session->gLimChannelSwitch.sw_target_freq, + &num_tpe, true); + } +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +void +populate_dot11f_avoid_channel_ie(struct mac_context *mac_ctx, + tDot11fIEQComVendorIE *dot11f, + struct pe_session *pe_session) +{ + if (!pe_session->sap_advertise_avoid_ch_ie) + return; + + dot11f->present = true; + dot11f->type = QCOM_VENDOR_IE_MCC_AVOID_CH; + dot11f->channel = wlan_reg_freq_to_chan( + mac_ctx->pdev, pe_session->curr_op_freq); +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +QDF_STATUS +populate_dot11f_country(struct mac_context *mac, + tDot11fIECountry *ctry_ie, struct pe_session *pe_session) +{ + uint8_t code[REG_ALPHA2_LEN + 1]; + uint8_t cur_triplet_num_chans = 0; + int chan_enum, chan_num; + struct regulatory_channel *sec_cur_chan_list; + struct regulatory_channel *cur_chan, *start, *prev; + uint8_t buffer_triplets[81][3]; + uint8_t i, j, num_triplets = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool six_gig_started = false; + uint8_t band_bitmap; + uint32_t band_capability; + uint8_t chan_spacing_for_2ghz = 1; + uint8_t chan_spacing_for_5ghz_6ghz = 4; + struct mlme_legacy_priv *mlme_priv = NULL; + + sec_cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * + sizeof(*sec_cur_chan_list)); + if (!sec_cur_chan_list) + return QDF_STATUS_E_NOMEM; + + if (pe_session) { + mlme_priv = wlan_vdev_mlme_get_ext_hdl(pe_session->vdev); + if (!mlme_priv) { + pe_err("Invalid mlme priv object"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + } + + if (!pe_session || + (mlme_priv && mlme_priv->country_ie_for_all_band)) { + status = wlan_mlme_get_band_capability(mac->psoc, + &band_capability); + if (QDF_IS_STATUS_ERROR(status)) { + pe_err("Failed to get MLME Band Capability"); + goto out; + } + band_bitmap = (uint8_t)band_capability; + } else { + if (pe_session->limRFBand == REG_BAND_UNKNOWN) { + pe_err("Wrong reg band for country info"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + band_bitmap = BIT(pe_session->limRFBand); + } + + chan_num = wlan_reg_get_secondary_band_channel_list( + mac->pdev, + band_bitmap, + sec_cur_chan_list); + if (!chan_num) { + pe_err("failed to get cur_chan list"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + wlan_reg_read_current_country(mac->psoc, code); + qdf_mem_copy(ctry_ie->country, code, REG_ALPHA2_LEN); + + /* advertise global operating class */ + ctry_ie->country[REG_ALPHA2_LEN] = 0x04; + + start = NULL; + prev = NULL; + for (chan_enum = 0; chan_enum < chan_num; chan_enum++) { + cur_chan = &sec_cur_chan_list[chan_enum]; + + if (cur_chan->chan_flags & REGULATORY_CHAN_DISABLED) + continue; + + if (wlan_reg_is_6ghz_chan_freq(cur_chan->center_freq) && + !six_gig_started) { + buffer_triplets[num_triplets][0] = OP_CLASS_ID_201; + buffer_triplets[num_triplets][1] = OP_CLASS_131; + num_triplets++; + six_gig_started = true; + } + + if (start && prev && + ((prev->chan_num + chan_spacing_for_2ghz == + cur_chan->chan_num) || + (prev->chan_num + chan_spacing_for_5ghz_6ghz == + cur_chan->chan_num)) && + start->tx_power == cur_chan->tx_power) { + /* Can use same entry */ + prev = cur_chan; + cur_triplet_num_chans++; + continue; + } + + if (start && prev) { + /* Save as entry */ + buffer_triplets[num_triplets][0] = start->chan_num; + buffer_triplets[num_triplets][1] = + cur_triplet_num_chans + 1; + buffer_triplets[num_triplets][2] = start->tx_power; + start = NULL; + cur_triplet_num_chans = 0; + + num_triplets++; + if (num_triplets > 80) { + pe_err("Triplets number exceed max size"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + } + + if ((chan_enum == NUM_CHANNELS - 1) && (six_gig_started)) { + buffer_triplets[num_triplets][0] = OP_CLASS_ID_201; + buffer_triplets[num_triplets][1] = OP_CLASS_132; + num_triplets++; + + buffer_triplets[num_triplets][0] = OP_CLASS_ID_201; + buffer_triplets[num_triplets][1] = OP_CLASS_133; + num_triplets++; + + buffer_triplets[num_triplets][0] = OP_CLASS_ID_201; + buffer_triplets[num_triplets][1] = OP_CLASS_134; + num_triplets++; + } + + /* Start new group */ + start = cur_chan; + prev = cur_chan; + } + + if (start) { + buffer_triplets[num_triplets][0] = start->chan_num; + buffer_triplets[num_triplets][1] = cur_triplet_num_chans + 1; + buffer_triplets[num_triplets][2] = start->tx_power; + num_triplets++; + } + + if (!num_triplets) { + /* at-least one triplet should be present */ + pe_err("No triplet present"); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + ctry_ie->num_more_triplets = num_triplets - 1; + ctry_ie->first_triplet[0] = buffer_triplets[0][0]; + ctry_ie->first_triplet[1] = buffer_triplets[0][1]; + ctry_ie->first_triplet[2] = buffer_triplets[0][2]; + + for (i = 0; i < ctry_ie->num_more_triplets; i++) { + for (j = 0; j < 3; j++) { + ctry_ie->more_triplets[i][j] = buffer_triplets[i+1][j]; + } + } + ctry_ie->present = 1; + +out: + qdf_mem_free(sec_cur_chan_list); + return status; +} /* End populate_dot11f_country. */ + +/** + * populate_dot11f_ds_params() - To populate DS IE params + * @mac_ctx: Pointer to global mac context + * @dot11f_param: pointer to DS params IE + * @freq: freq + * + * This routine will populate DS param in management frame like + * beacon, probe response, and etc. + * + * Return: Overall success + */ +QDF_STATUS +populate_dot11f_ds_params(struct mac_context *mac_ctx, + tDot11fIEDSParams *dot11f_param, qdf_freq_t freq) +{ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) { + /* .11b/g mode PHY => Include the DS Parameter Set IE: */ + dot11f_param->curr_channel = wlan_reg_freq_to_chan( + mac_ctx->pdev, + freq); + dot11f_param->present = 1; + } + + return QDF_STATUS_SUCCESS; +} + +#define SET_AIFSN(aifsn) (((aifsn) < 2) ? 2 : (aifsn)) + +void +populate_dot11f_edca_param_set(struct mac_context *mac, + tDot11fIEEDCAParamSet *pDot11f, + struct pe_session *pe_session) +{ + + if (pe_session->limQosEnabled) { + /* change to bitwise operation, after this is fixed in frames. */ + pDot11f->qos = + (uint8_t) (0xf0 & + (pe_session->gLimEdcaParamSetCount << 4)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pDot11f->acbe_aifsn = + (0xf & + SET_AIFSN(pe_session->gLimEdcaParamsBC[0].aci.aifsn)); + pDot11f->acbe_acm = + (0x1 & pe_session->gLimEdcaParamsBC[0].aci.acm); + pDot11f->acbe_aci = (0x3 & QCA_WLAN_AC_BE); + pDot11f->acbe_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[0].cw.min); + pDot11f->acbe_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[0].cw.max); + pDot11f->acbe_txoplimit = + pe_session->gLimEdcaParamsBC[0].txoplimit; + + pDot11f->acbk_aifsn = + (0xf & + SET_AIFSN(pe_session->gLimEdcaParamsBC[1].aci.aifsn)); + pDot11f->acbk_acm = + (0x1 & pe_session->gLimEdcaParamsBC[1].aci.acm); + pDot11f->acbk_aci = (0x3 & QCA_WLAN_AC_BK); + pDot11f->acbk_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[1].cw.min); + pDot11f->acbk_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[1].cw.max); + pDot11f->acbk_txoplimit = + pe_session->gLimEdcaParamsBC[1].txoplimit; + + pDot11f->acvi_aifsn = + (0xf & + SET_AIFSN(pe_session->gLimEdcaParamsBC[2].aci.aifsn)); + pDot11f->acvi_acm = + (0x1 & pe_session->gLimEdcaParamsBC[2].aci.acm); + pDot11f->acvi_aci = (0x3 & QCA_WLAN_AC_VI); + pDot11f->acvi_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[2].cw.min); + pDot11f->acvi_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[2].cw.max); + pDot11f->acvi_txoplimit = + pe_session->gLimEdcaParamsBC[2].txoplimit; + + pDot11f->acvo_aifsn = + (0xf & + SET_AIFSN(pe_session->gLimEdcaParamsBC[3].aci.aifsn)); + pDot11f->acvo_acm = + (0x1 & pe_session->gLimEdcaParamsBC[3].aci.acm); + pDot11f->acvo_aci = (0x3 & QCA_WLAN_AC_VO); + pDot11f->acvo_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[3].cw.min); + pDot11f->acvo_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[3].cw.max); + pDot11f->acvo_txoplimit = + pe_session->gLimEdcaParamsBC[3].txoplimit; + + pDot11f->present = 1; + } + +} /* End PopluateDot11fEDCAParamSet. */ + +QDF_STATUS +populate_dot11f_erp_info(struct mac_context *mac, + tDot11fIEERPInfo *pDot11f, struct pe_session *pe_session) +{ + uint32_t val; + enum reg_wifi_band rfBand = REG_BAND_UNKNOWN; + + lim_get_rf_band_new(mac, &rfBand, pe_session); + if (REG_BAND_2G == rfBand) { + pDot11f->present = 1; + + val = pe_session->cfgProtection.fromllb; + if (!val) { + pe_err("11B protection not enabled. Not populating ERP IE %d", + val); + return QDF_STATUS_SUCCESS; + } + + if (pe_session->gLim11bParams.protectionEnabled) { + pDot11f->non_erp_present = 1; + pDot11f->use_prot = 1; + } + + if (pe_session->gLimOlbcParams.protectionEnabled) { + /* FIXME_PROTECTION: we should be setting non_erp present also. */ + /* check the test plan first. */ + pDot11f->use_prot = 1; + } + + if ((pe_session->gLimNoShortParams.numNonShortPreambleSta) + || !pe_session->beaconParams.fShortPreamble) { + pDot11f->barker_preamble = 1; + + } + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_erp_info. */ + +QDF_STATUS +populate_dot11f_ext_supp_rates(struct mac_context *mac, uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f, + struct pe_session *pe_session) +{ + qdf_size_t n_rates = 0; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + /* Use the ext rates present in session entry whenever nChannelNum is set to OPERATIONAL + else use the ext supported rate set from CFG, which is fixed and does not change dynamically and is used for + sending mgmt frames (lile probe req) which need to go out before any session is present. + */ + if (POPULATE_DOT11F_RATES_OPERATIONAL == nChannelNum) { + if (pe_session) { + n_rates = pe_session->extRateSet.numRates; + qdf_mem_copy(rates, pe_session->extRateSet.rate, + n_rates); + } else { + pe_err("no session context exists while populating Operational Rate Set"); + } + } else if (HIGHEST_24GHZ_CHANNEL_NUM >= nChannelNum) { + if (!pe_session) { + pe_err("null pe_session"); + return QDF_STATUS_E_INVAL; + } + + n_rates = mlme_get_ext_opr_rate(pe_session->vdev, rates, + sizeof(rates)); + } + + if (0 != n_rates) { + pe_debug("ext supp rates present, num %d", (uint8_t)n_rates); + pDot11f->num_rates = (uint8_t)n_rates; + qdf_mem_copy(pDot11f->rates, rates, n_rates); + pDot11f->present = 1; + } + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_ext_supp_rates. */ + +QDF_STATUS +populate_dot11f_ext_supp_rates1(struct mac_context *mac, + uint8_t nChannelNum, + tDot11fIEExtSuppRates *pDot11f) +{ + qdf_size_t nRates; + QDF_STATUS nsir_status; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + if (14 < nChannelNum) { + pDot11f->present = 0; + return QDF_STATUS_SUCCESS; + } + /* N.B. I have *no* idea why we're calling 'wlan_cfg_get_str' with an argument */ + /* of WNI_CFG_SUPPORTED_RATES_11A here, but that's what was done */ + /* previously & I'm afraid to change it! */ + nRates = SIR_MAC_MAX_NUMBER_OF_RATES; + nsir_status = wlan_mlme_get_cfg_str( + rates, + &mac->mlme_cfg->rates.supported_11a, + &nRates); + if (QDF_IS_STATUS_ERROR(nsir_status)) { + pe_err("Failed to retrieve nItem from CFG status: %d", + (nsir_status)); + return nsir_status; + } + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + qdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return QDF_STATUS_SUCCESS; +} /* populate_dot11f_ext_supp_rates1. */ + +QDF_STATUS +populate_dot11f_ht_caps(struct mac_context *mac, + struct pe_session *pe_session, tDot11fIEHTCaps *pDot11f) +{ + qdf_size_t ncfglen; + QDF_STATUS nSirStatus; + uint8_t disable_high_ht_mcs_2x2 = 0; + struct ch_params ch_params = {0}; + uint8_t cb_mode; + + tSirMacTxBFCapabilityInfo *pTxBFCapabilityInfo; + tSirMacASCapabilityInfo *pASCapabilityInfo; + struct mlme_ht_capabilities_info *ht_cap_info; + struct mlme_vht_capabilities_info *vht_cap_info; + + ht_cap_info = &mac->mlme_cfg->ht_caps.ht_cap_info; + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + + pDot11f->mimoPowerSave = ht_cap_info->mimo_power_save; + pDot11f->greenField = ht_cap_info->green_field; + pDot11f->delayedBA = ht_cap_info->delayed_ba; + pDot11f->maximalAMSDUsize = ht_cap_info->maximal_amsdu_size; + pDot11f->dsssCckMode40MHz = ht_cap_info->dsss_cck_mode_40_mhz; + pDot11f->psmp = ht_cap_info->psmp; + pDot11f->stbcControlFrame = ht_cap_info->stbc_control_frame; + pDot11f->lsigTXOPProtection = ht_cap_info->l_sig_tx_op_protection; + + /* All sessionized entries will need the check below */ + if (!pe_session) { /* Only in case of NO session */ + pDot11f->supportedChannelWidthSet = + ht_cap_info->supported_channel_width_set; + pDot11f->advCodingCap = ht_cap_info->adv_coding_cap; + pDot11f->txSTBC = ht_cap_info->tx_stbc; + pDot11f->rxSTBC = ht_cap_info->rx_stbc; + pDot11f->shortGI20MHz = ht_cap_info->short_gi_20_mhz; + pDot11f->shortGI40MHz = ht_cap_info->short_gi_40_mhz; + } else { + cb_mode = lim_get_cb_mode_for_freq(mac, pe_session, + pe_session->curr_op_freq); + if (WLAN_REG_IS_24GHZ_CH_FREQ(pe_session->curr_op_freq) && + LIM_IS_STA_ROLE(pe_session) && + cb_mode != WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) { + pDot11f->supportedChannelWidthSet = 1; + ch_params.ch_width = CH_WIDTH_40MHZ; + wlan_reg_set_channel_params_for_pwrmode( + mac->pdev, pe_session->curr_op_freq, 0, + &ch_params, REG_CURRENT_PWR_MODE); + if (ch_params.ch_width != CH_WIDTH_40MHZ) + pDot11f->supportedChannelWidthSet = 0; + } else if (LIM_IS_STA_ROLE(pe_session)) { + if (pe_session->ch_width == CH_WIDTH_20MHZ) + pDot11f->supportedChannelWidthSet = 0; + else + pDot11f->supportedChannelWidthSet = 1; + } else { + pDot11f->supportedChannelWidthSet = + pe_session->htSupportedChannelWidthSet; + } + + pDot11f->advCodingCap = pe_session->ht_config.adv_coding_cap; + pDot11f->txSTBC = pe_session->ht_config.tx_stbc; + pDot11f->rxSTBC = pe_session->ht_config.rx_stbc; + pDot11f->shortGI20MHz = pe_session->ht_config.short_gi_20_mhz; + pDot11f->shortGI40MHz = pe_session->ht_config.short_gi_40_mhz; + } + + /* Ensure that shortGI40MHz is Disabled if supportedChannelWidthSet is + eHT_CHANNEL_WIDTH_20MHZ */ + if (pDot11f->supportedChannelWidthSet == eHT_CHANNEL_WIDTH_20MHZ) { + pDot11f->shortGI40MHz = 0; + } + + pDot11f->maxRxAMPDUFactor = + mac->mlme_cfg->ht_caps.ampdu_params.max_rx_ampdu_factor; + pDot11f->mpduDensity = + mac->mlme_cfg->ht_caps.ampdu_params.mpdu_density; + pDot11f->reserved1 = mac->mlme_cfg->ht_caps.ampdu_params.reserved; + + ncfglen = SIZE_OF_SUPPORTED_MCS_SET; + nSirStatus = wlan_mlme_get_cfg_str( + pDot11f->supportedMCSSet, + &mac->mlme_cfg->rates.supported_mcs_set, + &ncfglen); + if (QDF_IS_STATUS_ERROR(nSirStatus)) { + pe_err("Failed to retrieve nItem from CFG status: %d", + (nSirStatus)); + return nSirStatus; + } + + if (pe_session) { + disable_high_ht_mcs_2x2 = + mac->mlme_cfg->rates.disable_high_ht_mcs_2x2; + if (pe_session->nss == NSS_1x1_MODE) { + pDot11f->supportedMCSSet[1] = 0; + pDot11f->txSTBC = 0; + } else if (wlan_reg_is_24ghz_ch_freq( + pe_session->curr_op_freq) && + disable_high_ht_mcs_2x2 && + (pe_session->opmode == QDF_STA_MODE)) { + pe_debug("Disabling high HT MCS [%d]", + disable_high_ht_mcs_2x2); + pDot11f->supportedMCSSet[1] = + (pDot11f->supportedMCSSet[1] >> + disable_high_ht_mcs_2x2); + } + } + + /* If STA mode, session supported NSS > 1 and + * SMPS enabled publish HT SMPS IE + */ + if (pe_session && + LIM_IS_STA_ROLE(pe_session) && + (mac->mlme_cfg->ht_caps.enable_smps) && + (!pe_session->supported_nss_1x1)) { + pe_debug("Add SM power save IE: %d", + mac->mlme_cfg->ht_caps.smps); + pDot11f->mimoPowerSave = mac->mlme_cfg->ht_caps.smps; + } + + pDot11f->pco = mac->mlme_cfg->ht_caps.ext_cap_info.pco; + pDot11f->transitionTime = + mac->mlme_cfg->ht_caps.ext_cap_info.transition_time; + pDot11f->mcsFeedback = + mac->mlme_cfg->ht_caps.ext_cap_info.mcs_feedback; + + pTxBFCapabilityInfo = + (tSirMacTxBFCapabilityInfo *)&vht_cap_info->tx_bf_cap; + pDot11f->txBF = pTxBFCapabilityInfo->txBF; + pDot11f->rxStaggeredSounding = pTxBFCapabilityInfo->rxStaggeredSounding; + pDot11f->txStaggeredSounding = pTxBFCapabilityInfo->txStaggeredSounding; + pDot11f->rxZLF = pTxBFCapabilityInfo->rxZLF; + pDot11f->txZLF = pTxBFCapabilityInfo->txZLF; + pDot11f->implicitTxBF = pTxBFCapabilityInfo->implicitTxBF; + pDot11f->calibration = pTxBFCapabilityInfo->calibration; + pDot11f->explicitCSITxBF = pTxBFCapabilityInfo->explicitCSITxBF; + pDot11f->explicitUncompressedSteeringMatrix = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrix; + pDot11f->explicitBFCSIFeedback = + pTxBFCapabilityInfo->explicitBFCSIFeedback; + pDot11f->explicitUncompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitUncompressedSteeringMatrixFeedback; + pDot11f->explicitCompressedSteeringMatrixFeedback = + pTxBFCapabilityInfo->explicitCompressedSteeringMatrixFeedback; + pDot11f->csiNumBFAntennae = pTxBFCapabilityInfo->csiNumBFAntennae; + pDot11f->uncompressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->uncompressedSteeringMatrixBFAntennae; + pDot11f->compressedSteeringMatrixBFAntennae = + pTxBFCapabilityInfo->compressedSteeringMatrixBFAntennae; + + pASCapabilityInfo = (tSirMacASCapabilityInfo *)&vht_cap_info->as_cap; + pDot11f->antennaSelection = pASCapabilityInfo->antennaSelection; + pDot11f->explicitCSIFeedbackTx = + pASCapabilityInfo->explicitCSIFeedbackTx; + pDot11f->antennaIndicesFeedbackTx = + pASCapabilityInfo->antennaIndicesFeedbackTx; + pDot11f->explicitCSIFeedback = pASCapabilityInfo->explicitCSIFeedback; + pDot11f->antennaIndicesFeedback = + pASCapabilityInfo->antennaIndicesFeedback; + pDot11f->rxAS = pASCapabilityInfo->rxAS; + pDot11f->txSoundingPPDUs = pASCapabilityInfo->txSoundingPPDUs; + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_ht_caps. */ + +#define SEC_CHANNEL_OFFSET 20 + +ePhyChanBondState wlan_get_cb_mode(struct mac_context *mac, + qdf_freq_t ch_freq, + tDot11fBeaconIEs *ie_struct, + struct pe_session *pe_session) +{ + ePhyChanBondState cb_mode = PHY_SINGLE_CHANNEL_CENTERED; + uint32_t sec_ch_freq = 0; + uint32_t self_cb_mode; + struct ch_params ch_params = {0}; + + self_cb_mode = lim_get_cb_mode_for_freq(mac, pe_session, ch_freq); + if (self_cb_mode == WNI_CFG_CHANNEL_BONDING_MODE_DISABLE) + return PHY_SINGLE_CHANNEL_CENTERED; + + if (pe_session->dot11mode == MLME_DOT11_MODE_11A || + pe_session->dot11mode == MLME_DOT11_MODE_11G || + pe_session->dot11mode == MLME_DOT11_MODE_11B) + return PHY_SINGLE_CHANNEL_CENTERED; + + if (!(ie_struct->HTCaps.present && (eHT_CHANNEL_WIDTH_40MHZ == + ie_struct->HTCaps.supportedChannelWidthSet))) { + return PHY_SINGLE_CHANNEL_CENTERED; + } + + /* In Case WPA2 and TKIP is the only one cipher suite in Pairwise */ + if ((ie_struct->RSN.present && + (ie_struct->RSN.pwise_cipher_suite_count == 1) && + !qdf_mem_cmp(&(ie_struct->RSN.pwise_cipher_suites[0][0]), + "\x00\x0f\xac\x02", 4)) || + /* In Case only WPA1 is supported and TKIP is + * the only one cipher suite in Unicast. + */ + (!ie_struct->RSN.present && (ie_struct->WPA.present && + (ie_struct->WPA.unicast_cipher_count == 1) && + !qdf_mem_cmp(&(ie_struct->WPA.unicast_ciphers[0][0]), + "\x00\x50\xf2\x02", 4)))) { + pe_debug("No channel bonding in TKIP mode"); + return PHY_SINGLE_CHANNEL_CENTERED; + } + + if (!ie_struct->HTInfo.present) + return PHY_SINGLE_CHANNEL_CENTERED; + + pe_debug("ch freq %d scws %u rtws %u sco %u", ch_freq, + ie_struct->HTCaps.supportedChannelWidthSet, + ie_struct->HTInfo.recommendedTxWidthSet, + ie_struct->HTInfo.secondaryChannelOffset); + + if (ie_struct->HTInfo.recommendedTxWidthSet == eHT_CHANNEL_WIDTH_40MHZ) + cb_mode = ie_struct->HTInfo.secondaryChannelOffset; + else + cb_mode = PHY_SINGLE_CHANNEL_CENTERED; + + switch (cb_mode) { + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + sec_ch_freq = ch_freq + SEC_CHANNEL_OFFSET; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + sec_ch_freq = ch_freq - SEC_CHANNEL_OFFSET; + break; + default: + break; + } + + if (cb_mode != PHY_SINGLE_CHANNEL_CENTERED) { + ch_params.ch_width = CH_WIDTH_40MHZ; + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, ch_freq, + sec_ch_freq, &ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params.ch_width == CH_WIDTH_20MHZ || + ch_params.sec_ch_offset != cb_mode) { + pe_err("ch freq %d :: Supported HT BW %d and cbmode %d, APs HT BW %d and cbmode %d, so switch to 20Mhz", + ch_freq, ch_params.ch_width, + ch_params.sec_ch_offset, + ie_struct->HTInfo.recommendedTxWidthSet, + cb_mode); + cb_mode = PHY_SINGLE_CHANNEL_CENTERED; + } + } + + return cb_mode; +} + +void lim_log_vht_cap(struct mac_context *mac, tDot11fIEVHTCaps *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + pe_debug("maxMPDULen (2): %d", pDot11f->maxMPDULen); + pe_debug("supportedChannelWidthSet (2): %d", + pDot11f->supportedChannelWidthSet); + pe_debug("ldpcCodingCap (1): %d", + pDot11f->ldpcCodingCap); + pe_debug("shortGI80MHz (1): %d", pDot11f->shortGI80MHz); + pe_debug("shortGI160and80plus80MHz (1): %d", + pDot11f->shortGI160and80plus80MHz); + pe_debug("txSTBC (1): %d", pDot11f->txSTBC); + pe_debug("rxSTBC (3): %d", pDot11f->rxSTBC); + pe_debug("suBeamFormerCap (1): %d", + pDot11f->suBeamFormerCap); + pe_debug("suBeamformeeCap (1): %d", + pDot11f->suBeamformeeCap); + pe_debug("csnofBeamformerAntSup (3): %d", + pDot11f->csnofBeamformerAntSup); + pe_debug("numSoundingDim (3): %d", + pDot11f->numSoundingDim); + pe_debug("muBeamformerCap (1): %d", + pDot11f->muBeamformerCap); + pe_debug("muBeamformeeCap (1): %d", + pDot11f->muBeamformeeCap); + pe_debug("vhtTXOPPS (1): %d", pDot11f->vhtTXOPPS); + pe_debug("htcVHTCap (1): %d", pDot11f->htcVHTCap); + pe_debug("maxAMPDULenExp (3): %d", + pDot11f->maxAMPDULenExp); + pe_debug("vhtLinkAdaptCap (2): %d", + pDot11f->vhtLinkAdaptCap); + pe_debug("rxAntPattern (1): %d", + pDot11f->rxAntPattern; + pe_debug("txAntPattern (1): %d", + pDot11f->txAntPattern); + pe_debug("reserved1 (2): %d", pDot11f->reserved1); + pe_debug("rxMCSMap (16): %d", pDot11f->rxMCSMap); + pe_debug("rxHighSupDataRate (13): %d", + pDot11f->rxHighSupDataRate); + pe_debug("reserved2(3): %d", pDot11f->reserved2); + pe_debug("txMCSMap (16): %d", pDot11f->txMCSMap); + pe_debug("txSupDataRate (13): %d"), + pDot11f->txSupDataRate; + pe_debug("reserved3 (3): %d", pDot11f->reserved3); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_vht_operation(struct mac_context *mac, + tDot11fIEVHTOperation *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + pe_debug("chanWidth: %d", pDot11f->chanWidth); + pe_debug("chan_center_freq_seg0: %d", + pDot11f->chan_center_freq_seg0); + pe_debug("chan_center_freq_seg1: %d", + pDot11f->chan_center_freq_seg1); + pe_debug("basicMCSSet: %d", pDot11f->basicMCSSet); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_operating_mode(struct mac_context *mac, + tDot11fIEOperatingMode *pDot11f) +{ +#ifdef DUMP_MGMT_CNTNTS + pe_debug("ChanWidth: %d", pDot11f->chanWidth); + pe_debug("reserved: %d", pDot11f->reserved); + pe_debug("rxNSS: %d", pDot11f->rxNSS); + pe_debug("rxNSS Type: %d", pDot11f->rxNSSType); +#endif /* DUMP_MGMT_CNTNTS */ +} + +static void lim_log_qos_map_set(struct mac_context *mac, + struct qos_map_set *pQosMapSet) +{ + if (pQosMapSet->num_dscp_exceptions > QOS_MAP_MAX_EX) + pQosMapSet->num_dscp_exceptions = QOS_MAP_MAX_EX; + + pe_debug("num of dscp exceptions: %d", pQosMapSet->num_dscp_exceptions); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + pQosMapSet->dscp_exceptions, + sizeof(pQosMapSet->dscp_exceptions)); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + pQosMapSet->dscp_range, + sizeof(pQosMapSet->dscp_range)); +} + +QDF_STATUS +populate_dot11f_vht_caps(struct mac_context *mac, + struct pe_session *pe_session, tDot11fIEVHTCaps *pDot11f) +{ + uint32_t nCfgValue = 0; + struct mlme_vht_capabilities_info *vht_cap_info; + + if (!(mac->mlme_cfg)) { + pe_err("invalid mlme cfg"); + return QDF_STATUS_E_FAILURE; + } + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + + pDot11f->present = 1; + + nCfgValue = vht_cap_info->ampdu_len; + pDot11f->maxMPDULen = (nCfgValue & 0x0003); + + nCfgValue = vht_cap_info->supp_chan_width; + pDot11f->supportedChannelWidthSet = (nCfgValue & 0x0003); + + nCfgValue = 0; + /* With VHT it suffices if we just examine HT */ + if (pe_session) { + if (lim_is_he_6ghz_band(pe_session)) { + pDot11f->present = 0; + return QDF_STATUS_SUCCESS; + } + + if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) { + pDot11f->supportedChannelWidthSet = 0; + } else { + if (pe_session->ch_width <= CH_WIDTH_80MHZ) + pDot11f->supportedChannelWidthSet = 0; + } + + if (pe_session->ht_config.adv_coding_cap) + pDot11f->ldpcCodingCap = + pe_session->vht_config.ldpc_coding; + + pDot11f->shortGI80MHz = + pe_session->vht_config.shortgi80; + + if (pDot11f->supportedChannelWidthSet) + pDot11f->shortGI160and80plus80MHz = + pe_session->vht_config.shortgi160and80plus80; + + if (pe_session->ht_config.tx_stbc) + pDot11f->txSTBC = pe_session->vht_config.tx_stbc; + + if (pe_session->ht_config.rx_stbc) + pDot11f->rxSTBC = pe_session->vht_config.rx_stbc; + + pDot11f->suBeamformeeCap = + pe_session->vht_config.su_beam_formee; + if (pe_session->vht_config.su_beam_formee) { + pDot11f->muBeamformeeCap = + pe_session->vht_config.mu_beam_formee; + pDot11f->csnofBeamformerAntSup = + pe_session->vht_config.csnof_beamformer_antSup; + } else { + pDot11f->muBeamformeeCap = 0; + } + pDot11f->suBeamFormerCap = + pe_session->vht_config.su_beam_former; + + pDot11f->vhtTXOPPS = pe_session->vht_config.vht_txops; + + pDot11f->numSoundingDim = + pe_session->vht_config.num_soundingdim; + + pDot11f->htcVHTCap = pe_session->vht_config.htc_vhtcap; + + pDot11f->rxAntPattern = pe_session->vht_config.rx_antpattern; + + pDot11f->txAntPattern = pe_session->vht_config.tx_antpattern; + pDot11f->extended_nss_bw_supp = + pe_session->vht_config.extended_nss_bw_supp; + + pDot11f->maxAMPDULenExp = + pe_session->vht_config.max_ampdu_lenexp; + + pDot11f->vhtLinkAdaptCap = + pe_session->vht_config.vht_link_adapt; + } else { + nCfgValue = vht_cap_info->ldpc_coding_cap; + pDot11f->ldpcCodingCap = (nCfgValue & 0x0001); + + nCfgValue = vht_cap_info->short_gi_80mhz; + pDot11f->shortGI80MHz = (nCfgValue & 0x0001); + + if (pDot11f->supportedChannelWidthSet) { + nCfgValue = vht_cap_info->short_gi_160mhz; + pDot11f->shortGI160and80plus80MHz = (nCfgValue & 0x0001); + } + + nCfgValue = vht_cap_info->tx_stbc; + pDot11f->txSTBC = (nCfgValue & 0x0001); + + nCfgValue = vht_cap_info->rx_stbc; + pDot11f->rxSTBC = (nCfgValue & 0x0007); + + nCfgValue = vht_cap_info->su_bformee; + pDot11f->suBeamformeeCap = (nCfgValue & 0x0001); + + nCfgValue = vht_cap_info->enable_mu_bformee; + pDot11f->muBeamformeeCap = (nCfgValue & 0x0001); + + nCfgValue = vht_cap_info->su_bformer; + pDot11f->suBeamFormerCap = (nCfgValue & 0x0001); + + nCfgValue = vht_cap_info->tx_bfee_ant_supp; + pDot11f->csnofBeamformerAntSup = (nCfgValue & 0x0007); + + nCfgValue = vht_cap_info->txop_ps; + pDot11f->vhtTXOPPS = (nCfgValue & 0x0001); + + nCfgValue = vht_cap_info->num_soundingdim; + pDot11f->numSoundingDim = (nCfgValue & 0x0007); + + nCfgValue = vht_cap_info->htc_vhtc; + pDot11f->htcVHTCap = (nCfgValue & 0x0001); + + pDot11f->rxAntPattern = vht_cap_info->rx_antpattern; + + pDot11f->txAntPattern = vht_cap_info->tx_antpattern; + + nCfgValue = vht_cap_info->ampdu_len_exponent; + pDot11f->maxAMPDULenExp = (nCfgValue & 0x0007); + + nCfgValue = vht_cap_info->link_adap_cap; + pDot11f->vhtLinkAdaptCap = (nCfgValue & 0x0003); + + pDot11f->extended_nss_bw_supp = + vht_cap_info->extended_nss_bw_supp; + } + + pDot11f->max_nsts_total = vht_cap_info->max_nsts_total; + pDot11f->vht_extended_nss_bw_cap = + vht_cap_info->vht_extended_nss_bw_cap; + + nCfgValue = vht_cap_info->mu_bformer; + pDot11f->muBeamformerCap = (nCfgValue & 0x0001); + + + nCfgValue = vht_cap_info->rx_mcs_map; + pDot11f->rxMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = vht_cap_info->rx_supp_data_rate; + pDot11f->rxHighSupDataRate = (nCfgValue & 0x00001FFF); + + nCfgValue = vht_cap_info->tx_mcs_map; + pDot11f->txMCSMap = (nCfgValue & 0x0000FFFF); + + nCfgValue = vht_cap_info->tx_supp_data_rate; + pDot11f->txSupDataRate = (nCfgValue & 0x00001FFF); + + if (pe_session) { + if (pe_session->nss == NSS_1x1_MODE) { + pDot11f->txMCSMap |= DISABLE_NSS2_MCS; + pDot11f->rxMCSMap |= DISABLE_NSS2_MCS; + pDot11f->txSupDataRate = + VHT_TX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + pDot11f->rxHighSupDataRate = + VHT_RX_HIGHEST_SUPPORTED_DATA_RATE_1_1; + if (!pe_session->ch_width && + !vht_cap_info->enable_vht20_mcs9 && + ((pDot11f->txMCSMap & VHT_1x1_MCS_MASK) == + VHT_1x1_MCS9_MAP)) { + DISABLE_VHT_MCS_9(pDot11f->txMCSMap, + NSS_1x1_MODE); + DISABLE_VHT_MCS_9(pDot11f->rxMCSMap, + NSS_1x1_MODE); + } + pDot11f->txSTBC = 0; + } else { + if (!pe_session->ch_width && + !vht_cap_info->enable_vht20_mcs9 && + ((pDot11f->txMCSMap & VHT_2x2_MCS_MASK) == + VHT_2x2_MCS9_MAP)) { + DISABLE_VHT_MCS_9(pDot11f->txMCSMap, + NSS_2x2_MODE); + DISABLE_VHT_MCS_9(pDot11f->rxMCSMap, + NSS_2x2_MODE); + } + } + } + + lim_log_vht_cap(mac, pDot11f); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_vht_operation(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEVHTOperation *pDot11f) +{ + uint32_t mcs_set; + struct mlme_vht_capabilities_info *vht_cap_info; + enum reg_wifi_band band; + uint8_t band_mask; + struct ch_params ch_params = {0}; + qdf_freq_t sec_chan_freq = 0; + + if (!pe_session || !pe_session->vhtCapability) + return QDF_STATUS_SUCCESS; + + band = wlan_reg_freq_to_band(pe_session->curr_op_freq); + band_mask = 1 << band; + + ch_params.ch_width = pe_session->ch_width; + ch_params.mhz_freq_seg0 = + wlan_reg_chan_band_to_freq(mac->pdev, + pe_session->ch_center_freq_seg0, + band_mask); + + if (pe_session->ch_center_freq_seg1) + ch_params.mhz_freq_seg1 = + wlan_reg_chan_band_to_freq(mac->pdev, + pe_session->ch_center_freq_seg1, + band_mask); + + if (band == (REG_BAND_2G) && ch_params.ch_width == CH_WIDTH_40MHZ) { + if (ch_params.mhz_freq_seg0 == pe_session->curr_op_freq + 10) + sec_chan_freq = pe_session->curr_op_freq + 20; + if (ch_params.mhz_freq_seg0 == pe_session->curr_op_freq - 10) + sec_chan_freq = pe_session->curr_op_freq - 20; + } + + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + pe_session->curr_op_freq, + sec_chan_freq, &ch_params, + REG_CURRENT_PWR_MODE); + + pDot11f->present = 1; + + if (pe_session->ch_width > CH_WIDTH_40MHZ) { + pDot11f->chanWidth = 1; + pDot11f->chan_center_freq_seg0 = + ch_params.center_freq_seg0; + if (pe_session->ch_width == CH_WIDTH_80P80MHZ || + pe_session->ch_width == CH_WIDTH_160MHZ) + pDot11f->chan_center_freq_seg1 = + ch_params.center_freq_seg1; + else + pDot11f->chan_center_freq_seg1 = 0; + } else { + pDot11f->chanWidth = 0; + pDot11f->chan_center_freq_seg0 = 0; + pDot11f->chan_center_freq_seg1 = 0; + } + + vht_cap_info = &mac->mlme_cfg->vht_caps.vht_cap_info; + mcs_set = vht_cap_info->basic_mcs_set; + mcs_set = (mcs_set & 0xFFFC) | vht_cap_info->rx_mcs; + + if (pe_session->nss == NSS_1x1_MODE) + mcs_set |= 0x000C; + else + mcs_set = (mcs_set & 0xFFF3) | (vht_cap_info->rx_mcs2x2 << 2); + + pDot11f->basicMCSSet = (uint16_t)mcs_set; + lim_log_vht_operation(mac, pDot11f); + + return QDF_STATUS_SUCCESS; + +} + +QDF_STATUS +populate_dot11f_ext_cap(struct mac_context *mac, + bool isVHTEnabled, tDot11fIEExtCap *pDot11f, + struct pe_session *pe_session) +{ + struct s_ext_cap *p_ext_cap; + + pDot11f->present = 1; + + if (!pe_session) { + pe_debug("11MC - enabled for non-SAP cases"); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else if (pe_session->sap_dot11mc) { + pe_debug("11MC support enabled"); + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + } else { + if (eLIM_AP_ROLE != pe_session->limSystemRole) + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + else + pDot11f->num_bytes = DOT11F_IE_EXTCAP_MIN_LEN; + } + + p_ext_cap = (struct s_ext_cap *)pDot11f->bytes; + if (isVHTEnabled == true) + p_ext_cap->oper_mode_notification = 1; + + if (mac->mlme_cfg->gen.rtt3_enabled) { + uint32_t ftm = ucfg_wifi_pos_get_ftm_cap(mac->psoc); + if (!pe_session || LIM_IS_STA_ROLE(pe_session)) { + p_ext_cap->fine_time_meas_initiator = + (ftm & WMI_FW_STA_RTT_INITR) ? 1 : 0; + p_ext_cap->fine_time_meas_responder = + (ftm & WMI_FW_STA_RTT_RESPR) ? 1 : 0; + } else if (LIM_IS_AP_ROLE(pe_session)) { + p_ext_cap->fine_time_meas_initiator = + (ftm & WMI_FW_AP_RTT_INITR) ? 1 : 0; + p_ext_cap->fine_time_meas_responder = + (ftm & WMI_FW_AP_RTT_RESPR) ? 1 : 0; + } + } +#ifdef QCA_HT_2040_COEX + if (mac->roam.configParam.obssEnabled) + p_ext_cap->bss_coexist_mgmt_support = 1; +#endif + p_ext_cap->ext_chan_switch = 1; + + if (pe_session && pe_session->enable_bcast_probe_rsp) + p_ext_cap->fils_capability = 1; + + if (pe_session && pe_session->is_mbssid_enabled) + p_ext_cap->multi_bssid = 1; + + /* Beacon Protection Enabled : This field is reserved for STA */ + if (pe_session && (pe_session->opmode == QDF_SAP_MODE || + pe_session->opmode == QDF_P2P_GO_MODE)) { + p_ext_cap->beacon_protection_enable = pe_session ? + mlme_get_bigtk_support(pe_session->vdev) : false; + } + if (pe_session) + populate_dot11f_twt_extended_caps(mac, pe_session, pDot11f); + + /* Need to calculate the num_bytes based on bits set */ + if (pDot11f->present) + pDot11f->num_bytes = lim_compute_ext_cap_ie_length(pDot11f); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11AX +static void populate_dot11f_qcn_ie_he_params(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEqcn_ie *qcn_ie, + uint8_t attr_id) +{ + uint16_t mcs_12_13_supp = 0; + + if (!lim_is_session_he_capable(pe_session)) + return; + + /* To fix WAPI IoT issue.*/ + if (pe_session->encryptType == eSIR_ED_WPI) + return; + + if (wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq)) { + if (!(LIM_IS_AP_ROLE(pe_session) && + pe_session->ch_width == CH_WIDTH_40MHZ && + (mac->mlme_cfg->he_caps.disable_sap_mcs_12_13 & + BIT(DISABLE_MCS_12_13_2G_40M)))) + mcs_12_13_supp = mac->mlme_cfg->he_caps.he_mcs_12_13_supp_2g; + } else { + mcs_12_13_supp = mac->mlme_cfg->he_caps.he_mcs_12_13_supp_5g; + } + + if (!mcs_12_13_supp) + return; + + qcn_ie->present = 1; + qcn_ie->he_mcs13_attr.present = 1; + qcn_ie->he_mcs13_attr.he_mcs_12_13_supp_80 = mcs_12_13_supp & 0xFF; + qcn_ie->he_mcs13_attr.he_mcs_12_13_supp_160 = mcs_12_13_supp >> 8; +} +#else /* WLAN_FEATURE_11AX */ +static void populate_dot11f_qcn_ie_he_params(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEqcn_ie *qcn_ie, + uint8_t attr_id) +{} +#endif /* WLAN_FEATURE_11AX */ + +void populate_dot11f_bss_max_idle(struct mac_context *mac, + struct pe_session *session, + tDot11fIEbss_max_idle_period *max_idle_ie) +{ + max_idle_ie->present = 0; + if (lim_is_session_he_capable(session) && + mac->mlme_cfg->sta.bss_max_idle_period) { + max_idle_ie->present = 1; + max_idle_ie->max_idle_period = + mac->mlme_cfg->sta.bss_max_idle_period; + max_idle_ie->prot_keep_alive_reqd = session->limRmfEnabled; + } +} + +void populate_dot11f_edca_pifs_param_set(struct mac_context *mac, + tDot11fIEqcn_ie *qcn_ie) +{ + struct wlan_edca_pifs_param_ie param = {0}; + struct edca_param *eparam; + struct pifs_param *pparam; + uint8_t edca_param_type; + + qcn_ie->present = 1; + qcn_ie->edca_pifs_param_attr.present = 1; + + edca_param_type = mac->mlme_cfg->edca_params.edca_param_type; + wlan_mlme_set_edca_pifs_param(¶m, edca_param_type); + qcn_ie->edca_pifs_param_attr.edca_param_type = edca_param_type; + + if (edca_param_type == HOST_EDCA_PARAM_TYPE_AGGRESSIVE) { + qcn_ie->edca_pifs_param_attr.num_data = sizeof(*eparam); + eparam = (struct edca_param *)qcn_ie->edca_pifs_param_attr.data; + qdf_mem_copy(eparam, ¶m.edca_pifs_param.eparam, + sizeof(*eparam)); + } else if (edca_param_type == HOST_EDCA_PARAM_TYPE_PIFS) { + qcn_ie->edca_pifs_param_attr.num_data = sizeof(*pparam); + pparam = (struct pifs_param *)qcn_ie->edca_pifs_param_attr.data; + qdf_mem_copy(pparam, ¶m.edca_pifs_param.pparam, + sizeof(*pparam)); + } +} + +void populate_dot11f_qcn_ie(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEqcn_ie *qcn_ie, + uint8_t attr_id) +{ + qcn_ie->present = 0; + if (mac->mlme_cfg->sta.qcn_ie_support && + ((attr_id == QCN_IE_ATTR_ID_ALL) || + (attr_id == QCN_IE_ATTR_ID_VERSION))) { + qcn_ie->present = 1; + qcn_ie->qcn_version.present = 1; + qcn_ie->qcn_version.version = QCN_IE_VERSION_SUPPORTED; + qcn_ie->qcn_version.sub_version = QCN_IE_SUBVERSION_SUPPORTED; + } + if (pe_session->vhtCapability && + mac->mlme_cfg->vht_caps.vht_cap_info.vht_mcs_10_11_supp) { + qcn_ie->present = 1; + qcn_ie->vht_mcs11_attr.present = 1; + qcn_ie->vht_mcs11_attr.vht_mcs_10_11_supp = 1; + } + + populate_dot11f_qcn_ie_he_params(mac, pe_session, qcn_ie, attr_id); + if (policy_mgr_is_vdev_ll_lt_sap(mac->psoc, pe_session->vdev_id)) { + pe_debug("Populate edca/pifs param ie for ll sap"); + populate_dot11f_edca_pifs_param_set(mac, qcn_ie); + } +} + +QDF_STATUS +populate_dot11f_operating_mode(struct mac_context *mac, + tDot11fIEOperatingMode *pDot11f, + struct pe_session *pe_session) +{ + pDot11f->present = 1; + + pDot11f->chanWidth = pe_session->gLimOperatingMode.chanWidth; + pDot11f->rxNSS = pe_session->gLimOperatingMode.rxNSS; + pDot11f->rxNSSType = pe_session->gLimOperatingMode.rxNSSType; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_ht_info(struct mac_context *mac, + tDot11fIEHTInfo *pDot11f, struct pe_session *pe_session) +{ + qdf_size_t ncfglen; + QDF_STATUS nSirStatus; + + if (!pe_session) { + pe_err("Invalid session entry"); + return QDF_STATUS_E_FAILURE; + } + + pDot11f->primaryChannel = wlan_reg_freq_to_chan( + mac->pdev, pe_session->curr_op_freq); + + pDot11f->secondaryChannelOffset = + pe_session->htSecondaryChannelOffset; + pDot11f->recommendedTxWidthSet = + pe_session->htRecommendedTxWidthSet; + pDot11f->rifsMode = pe_session->beaconParams.fRIFSMode; + pDot11f->controlledAccessOnly = + mac->mlme_cfg->ht_caps.info_field_1.controlled_access_only; + pDot11f->serviceIntervalGranularity = + mac->lim.gHTServiceIntervalGranularity; + + if (LIM_IS_AP_ROLE(pe_session)) { + pDot11f->opMode = pe_session->htOperMode; + pDot11f->nonGFDevicesPresent = + pe_session->beaconParams.llnNonGFCoexist; + pDot11f->obssNonHTStaPresent = + pe_session->beaconParams.gHTObssMode; + pDot11f->reserved = 0; + } else { + pDot11f->opMode = 0; + pDot11f->nonGFDevicesPresent = 0; + pDot11f->obssNonHTStaPresent = 0; + pDot11f->reserved = 0; + } + + pDot11f->basicSTBCMCS = mac->lim.gHTSTBCBasicMCS; + pDot11f->dualCTSProtection = mac->lim.gHTDualCTSProtection; + pDot11f->secondaryBeacon = mac->lim.gHTSecondaryBeacon; + pDot11f->lsigTXOPProtectionFullSupport = + pe_session->beaconParams.fLsigTXOPProtectionFullSupport; + pDot11f->pcoActive = mac->lim.gHTPCOActive; + pDot11f->pcoPhase = mac->lim.gHTPCOPhase; + pDot11f->reserved2 = 0; + + ncfglen = SIZE_OF_BASIC_MCS_SET; + nSirStatus = wlan_mlme_get_cfg_str(pDot11f->basicMCSSet, + &mac->mlme_cfg->rates.basic_mcs_set, + &ncfglen); + if (QDF_IS_STATUS_ERROR(nSirStatus)) { + pe_err("Failed to retrieve nItem from CFG status: %d", + (nSirStatus)); + return nSirStatus; + } + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_ht_info. */ + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +populate_dot11f_measurement_report0(struct mac_context *mac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_BASIC_MEASUREMENT_TYPE; + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End PopulatedDot11fMeasurementReport0. */ +QDF_STATUS +populate_dot11f_measurement_report1(struct mac_context *mac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_CCA_MEASUREMENT_TYPE; + pDot11f->present = 1; + return QDF_STATUS_SUCCESS; +} /* End PopulatedDot11fMeasurementReport1. */ +QDF_STATUS +populate_dot11f_measurement_report2(struct mac_context *mac, + tpSirMacMeasReqActionFrame pReq, + tDot11fIEMeasurementReport *pDot11f) +{ + pDot11f->token = pReq->measReqIE.measToken; + pDot11f->late = 0; + pDot11f->incapable = 0; + pDot11f->refused = 1; + pDot11f->type = SIR_MAC_RPI_MEASUREMENT_TYPE; + pDot11f->present = 1; + return QDF_STATUS_SUCCESS; +} /* End PopulatedDot11fMeasurementReport2. */ +#endif + +void +populate_dot11f_power_caps(struct mac_context *mac, + tDot11fIEPowerCaps *pCaps, + uint8_t nAssocType, struct pe_session *pe_session) +{ + struct vdev_mlme_obj *mlme_obj; + + pCaps->minTxPower = pe_session->min_11h_pwr; + pCaps->maxTxPower = pe_session->maxTxPower; + + /* Use firmware updated max tx power if non zero */ + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(pe_session->vdev); + if (mlme_obj && mlme_obj->mgmt.generic.tx_pwrlimit) + pCaps->maxTxPower = mlme_obj->mgmt.generic.tx_pwrlimit; + + pCaps->present = 1; +} /* End populate_dot11f_power_caps. */ + +QDF_STATUS +populate_dot11f_power_constraints(struct mac_context *mac, + tDot11fIEPowerConstraints *pDot11f) +{ + pDot11f->localPowerConstraints = + mac->mlme_cfg->power.local_power_constraint; + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_power_constraints. */ + +void +populate_dot11f_qos_caps_station(struct mac_context *mac, struct pe_session *pe_session, + tDot11fIEQOSCapsStation *pDot11f) +{ + uint8_t max_sp_length = 0; + + max_sp_length = mac->mlme_cfg->wmm_params.max_sp_length; + + pDot11f->more_data_ack = 0; + pDot11f->max_sp_length = max_sp_length; + pDot11f->qack = 0; + + if (mac->lim.gUapsdEnable) { + pDot11f->acbe_uapsd = + LIM_UAPSD_GET(ACBE, pe_session->gUapsdPerAcBitmask); + pDot11f->acbk_uapsd = + LIM_UAPSD_GET(ACBK, pe_session->gUapsdPerAcBitmask); + pDot11f->acvi_uapsd = + LIM_UAPSD_GET(ACVI, pe_session->gUapsdPerAcBitmask); + pDot11f->acvo_uapsd = + LIM_UAPSD_GET(ACVO, pe_session->gUapsdPerAcBitmask); + } + pDot11f->present = 1; +} /* End PopulatedDot11fQOSCaps. */ + +QDF_STATUS +populate_dot11f_rsn(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIERSN *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(mac, pRsnIe, DOT11F_EID_RSN); + if (0 <= idx) { + status = dot11f_unpack_ie_rsn(mac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f, false); + if (DOT11F_FAILED(status)) { + pe_err("Parse failure in Populate Dot11fRSN (0x%08x)", + status); + return QDF_STATUS_E_FAILURE; + } + pe_debug("status 0x%08x", status); + } + + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_rsn. */ + +QDF_STATUS populate_dot11f_rsn_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, + tDot11fIERSNOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(mac, pRsnIe, DOT11F_EID_RSN); + if (0 <= idx) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1]; + qdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2, /* EID, len */ + pRsnIe->rsnIEdata[idx + 1]); + } + } + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_rsn_opaque. */ + +#if defined(FEATURE_WLAN_WAPI) + +QDF_STATUS +populate_dot11f_wapi(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIEWAPI *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(mac, pRsnIe, DOT11F_EID_WAPI); + if (0 <= idx) { + status = dot11f_unpack_ie_wapi(mac, pRsnIe->rsnIEdata + idx + 2, /* EID, length */ + pRsnIe->rsnIEdata[idx + 1], + pDot11f, false); + if (DOT11F_FAILED(status)) { + pe_err("Parse failure (0x%08x)", status); + return QDF_STATUS_E_FAILURE; + } + pe_debug("status 0x%08x", status); + } + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_wapi. */ + +QDF_STATUS populate_dot11f_wapi_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, + tDot11fIEWAPIOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(mac, pRsnIe, DOT11F_EID_WAPI); + if (0 <= idx) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1]; + qdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2, /* EID, len */ + pRsnIe->rsnIEdata[idx + 1]); + } + } + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_wapi_opaque. */ + +#endif /* defined(FEATURE_WLAN_WAPI) */ + +void +populate_dot11f_ssid(struct mac_context *mac, + tSirMacSSid *pInternal, tDot11fIESSID *pDot11f) +{ + pDot11f->present = 1; + pDot11f->num_ssid = pInternal->length; + if (pInternal->length) { + qdf_mem_copy((uint8_t *) pDot11f->ssid, + (uint8_t *) &pInternal->ssId, pInternal->length); + } +} /* End populate_dot11f_ssid. */ + +QDF_STATUS populate_dot11f_ssid2(struct pe_session *pe_session, + tDot11fIESSID *pDot11f) +{ + qdf_mem_copy(pDot11f->ssid, pe_session->ssId.ssId, + pe_session->ssId.length); + pDot11f->num_ssid = pe_session->ssId.length; + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_ssid2. */ + +void +populate_dot11f_schedule(tSirMacScheduleIE *pSchedule, + tDot11fIESchedule *pDot11f) +{ + pDot11f->aggregation = pSchedule->info.aggregation; + pDot11f->tsid = pSchedule->info.tsid; + pDot11f->direction = pSchedule->info.direction; + pDot11f->reserved = pSchedule->info.rsvd; + pDot11f->service_start_time = pSchedule->svcStartTime; + pDot11f->service_interval = pSchedule->svcInterval; + pDot11f->max_service_dur = pSchedule->maxSvcDuration; + pDot11f->spec_interval = pSchedule->specInterval; + + pDot11f->present = 1; +} /* End populate_dot11f_schedule. */ + +void +populate_dot11f_supp_channels(struct mac_context *mac, + tDot11fIESuppChannels *pDot11f, + uint8_t nAssocType, struct pe_session *pe_session) +{ + uint8_t i, j = 0; + uint8_t *p; + struct supported_channels supportedChannels; + uint8_t channel, opclass, base_opclass; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + wlan_add_supported_5Ghz_channels(mac->psoc, mac->pdev, + supportedChannels.channelList, + &supportedChannels.numChnl, + false); + + p = supportedChannels.channelList; + pDot11f->num_bands = supportedChannels.numChnl; + + wlan_reg_read_current_country(mac->psoc, reg_cc); + for (i = 0U; i < pDot11f->num_bands; i++) { + base_opclass = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, + p[i], BW20); + pDot11f->bands[j][0] = p[i]; + pDot11f->bands[j][1] = 1; + channel = p[i]; + while (i + 1 < pDot11f->num_bands && (p[i + 1] == channel + 4)) { + opclass = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, + p[i + 1], BW20); + if (base_opclass != opclass) + goto skip; + pDot11f->bands[j][1]++; + channel = p[++i]; + } +skip: + j++; + } + + pDot11f->num_bands = j; + pDot11f->present = 1; + +} /* End populate_dot11f_supp_channels. */ + +QDF_STATUS +populate_dot11f_supp_rates(struct mac_context *mac, + uint8_t nChannelNum, + tDot11fIESuppRates *pDot11f, + struct pe_session *pe_session) +{ + QDF_STATUS nsir_status; + qdf_size_t nRates; + uint8_t rates[SIR_MAC_MAX_NUMBER_OF_RATES]; + + /* Use the operational rates present in session entry whenever + * nChannelNum is set to OPERATIONAL else use the supported + * rate set from CFG, which is fixed and does not change + * dynamically and is used for sending mgmt frames (lile probe + * req) which need to go out before any session is present. + */ + if (POPULATE_DOT11F_RATES_OPERATIONAL == nChannelNum) { + if (pe_session) { + nRates = pe_session->rateSet.numRates; + qdf_mem_copy(rates, pe_session->rateSet.rate, + nRates); + } else { + pe_err("no session context exists while populating Operational Rate Set"); + nRates = 0; + } + } else if (14 >= nChannelNum) { + nRates = SIR_MAC_MAX_NUMBER_OF_RATES; + nsir_status = wlan_mlme_get_cfg_str( + rates, + &mac->mlme_cfg->rates.supported_11b, + &nRates); + if (QDF_IS_STATUS_ERROR(nsir_status)) { + pe_err("Failed to retrieve nItem from CFG status: %d", + (nsir_status)); + return nsir_status; + } + } else { + nRates = SIR_MAC_MAX_NUMBER_OF_RATES; + nsir_status = wlan_mlme_get_cfg_str( + rates, + &mac->mlme_cfg->rates.supported_11a, + &nRates); + if (QDF_IS_STATUS_ERROR(nsir_status)) { + pe_err("Failed to retrieve nItem from CFG status: %d", + (nsir_status)); + return nsir_status; + } + } + + if (0 != nRates) { + pDot11f->num_rates = (uint8_t) nRates; + qdf_mem_copy(pDot11f->rates, rates, nRates); + pDot11f->present = 1; + } + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_supp_rates. */ + +/** + * populate_dot11f_rates_tdls() - populate supported rates and + * extended supported rates IE. + * @p_mac: Pointer to global mac context + * @p_supp_rates: pointer to supported rates IE + * @p_ext_supp_rates: pointer to extended supported rates IE + * @curr_oper_channel: current operating channel + * + * This function populates the supported rates and extended supported + * rates IE based in the STA capability. If the number of rates + * supported is less than MAX_NUM_SUPPORTED_RATES, only supported rates + * IE is populated. + * + * Return: QDF_STATUS QDF_STATUS_SUCCESS on Success and QDF_STATUS_E_FAILURE + * on failure. + */ + +QDF_STATUS +populate_dot11f_rates_tdls(struct mac_context *p_mac, + tDot11fIESuppRates *p_supp_rates, + tDot11fIEExtSuppRates *p_ext_supp_rates, + uint8_t curr_oper_channel) +{ + tSirMacRateSet temp_rateset; + tSirMacRateSet temp_rateset2; + uint32_t i; + uint32_t self_dot11mode = 0; + qdf_size_t num_rates; + + self_dot11mode = p_mac->mlme_cfg->dot11_mode.dot11_mode; + + /** + * Include 11b rates only when the device configured in + * auto, 11a/b/g or 11b_only and also if current base + * channel is 5 GHz then no need to advertise the 11b rates. + * If devices move to 2.4GHz off-channel then they can communicate + * in 11g rates i.e. (6, 9, 12, 18, 24, 36 and 54). + */ + pe_debug("Current operating channel %d self_dot11mode = %d", + curr_oper_channel, self_dot11mode); + + if ((curr_oper_channel <= SIR_11B_CHANNEL_END) && + ((self_dot11mode == MLME_DOT11_MODE_ALL) || + (self_dot11mode == MLME_DOT11_MODE_11A) || + (self_dot11mode == MLME_DOT11_MODE_11AC) || + (self_dot11mode == MLME_DOT11_MODE_11N) || + (self_dot11mode == MLME_DOT11_MODE_11G) || + (self_dot11mode == MLME_DOT11_MODE_11B))) { + num_rates = p_mac->mlme_cfg->rates.supported_11b.len; + wlan_mlme_get_cfg_str((uint8_t *)&temp_rateset.rate, + &p_mac->mlme_cfg->rates.supported_11b, + &num_rates); + temp_rateset.numRates = (uint8_t)num_rates; + } else { + temp_rateset.numRates = 0; + } + + /* Include 11a rates when the device configured in non-11b mode */ + if (!IS_DOT11_MODE_11B(self_dot11mode)) { + num_rates = p_mac->mlme_cfg->rates.supported_11a.len; + wlan_mlme_get_cfg_str((uint8_t *)&temp_rateset2.rate, + &p_mac->mlme_cfg->rates.supported_11a, + &num_rates); + temp_rateset2.numRates = (uint8_t)num_rates; + } else { + temp_rateset2.numRates = 0; + } + + if ((temp_rateset.numRates + temp_rateset2.numRates) > + SIR_MAC_MAX_NUMBER_OF_RATES) { + pe_err("more than %d rates in CFG", + SIR_MAC_MAX_NUMBER_OF_RATES); + return QDF_STATUS_E_FAILURE; + } + + /** + * copy all rates in temp_rateset, + * there are SIR_MAC_MAX_NUMBER_OF_RATES rates max + */ + for (i = 0; i < temp_rateset2.numRates; i++) + temp_rateset.rate[i + temp_rateset.numRates] = + temp_rateset2.rate[i]; + + temp_rateset.numRates += temp_rateset2.numRates; + + if (temp_rateset.numRates <= MAX_NUM_SUPPORTED_RATES) { + p_supp_rates->num_rates = temp_rateset.numRates; + qdf_mem_copy(p_supp_rates->rates, temp_rateset.rate, + p_supp_rates->num_rates); + p_supp_rates->present = 1; + } else { /* Populate extended capability as well */ + p_supp_rates->num_rates = MAX_NUM_SUPPORTED_RATES; + qdf_mem_copy(p_supp_rates->rates, temp_rateset.rate, + p_supp_rates->num_rates); + p_supp_rates->present = 1; + + p_ext_supp_rates->num_rates = temp_rateset.numRates - + MAX_NUM_SUPPORTED_RATES; + qdf_mem_copy(p_ext_supp_rates->rates, + (uint8_t *)temp_rateset.rate + + MAX_NUM_SUPPORTED_RATES, + p_ext_supp_rates->num_rates); + p_ext_supp_rates->present = 1; + } + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_rates_tdls */ + + +QDF_STATUS +populate_dot11f_tpc_report(struct mac_context *mac, + tDot11fIETPCReport *pDot11f, struct pe_session *pe_session) +{ + uint16_t staid; + uint8_t tx_power; + QDF_STATUS nSirStatus; + + nSirStatus = lim_get_mgmt_staid(mac, &staid, pe_session); + if (QDF_STATUS_SUCCESS != nSirStatus) { + pe_err("Failed to get the STAID in Populate Dot11fTPCReport; lim_get_mgmt_staid returned status %d", + nSirStatus); + return QDF_STATUS_E_FAILURE; + } + tx_power = wlan_reg_get_channel_reg_power_for_freq( + mac->pdev, pe_session->curr_op_freq); + pDot11f->tx_power = tx_power; + pDot11f->link_margin = 0; + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_tpc_report. */ + +void populate_dot11f_ts_info(struct mac_ts_info *pInfo, + tDot11fFfTSInfo *pDot11f) +{ + pDot11f->traffic_type = pInfo->traffic.trafficType; + pDot11f->tsid = pInfo->traffic.tsid; + pDot11f->direction = pInfo->traffic.direction; + pDot11f->access_policy = pInfo->traffic.accessPolicy; + pDot11f->aggregation = pInfo->traffic.aggregation; + pDot11f->psb = pInfo->traffic.psb; + pDot11f->user_priority = pInfo->traffic.userPrio; + pDot11f->tsinfo_ack_pol = pInfo->traffic.ackPolicy; + pDot11f->schedule = pInfo->schedule.schedule; +} /* End PopulatedDot11fTSInfo. */ + +void populate_dot11f_wmm(struct mac_context *mac, + tDot11fIEWMMInfoAp *pInfo, + tDot11fIEWMMParams *pParams, + tDot11fIEWMMCaps *pCaps, struct pe_session *pe_session) +{ + if (pe_session->limWmeEnabled) { + populate_dot11f_wmm_params(mac, pParams, + pe_session); + if (pe_session->limWsmEnabled) + populate_dot11f_wmm_caps(pCaps); + } +} /* End populate_dot11f_wmm. */ + +void populate_dot11f_wmm_caps(tDot11fIEWMMCaps *pCaps) +{ + pCaps->version = SIR_MAC_OUI_VERSION_1; + pCaps->qack = 0; + pCaps->queue_request = 1; + pCaps->txop_request = 0; + pCaps->more_ack = 0; + pCaps->present = 1; +} /* End PopulateDot11fWmmCaps. */ + +#ifdef FEATURE_WLAN_ESE +#ifdef WLAN_FEATURE_HOST_ROAM +void populate_dot11f_re_assoc_tspec(struct mac_context *mac, + tDot11fReAssocRequest *pReassoc, + struct pe_session *pe_session) +{ + uint8_t numTspecs = 0, idx; + tTspecInfo *pTspec = NULL; + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(pe_session->vdev); + if (!mlme_priv) + return; + + numTspecs = mlme_priv->connect_info.ese_tspec_info.numTspecs; + pTspec = &mlme_priv->connect_info.ese_tspec_info.tspec[0]; + pReassoc->num_WMMTSPEC = numTspecs; + if (numTspecs) { + for (idx = 0; idx < numTspecs; idx++) { + populate_dot11f_wmmtspec(&pTspec->tspec, + &pReassoc->WMMTSPEC[idx]); + pTspec->tspec.mediumTime = 0; + pTspec++; + } + } +} +#endif +void ese_populate_wmm_tspec(struct mac_tspec_ie *source, + ese_wmm_tspec_ie *dest) +{ + dest->traffic_type = source->tsinfo.traffic.trafficType; + dest->tsid = source->tsinfo.traffic.tsid; + dest->direction = source->tsinfo.traffic.direction; + dest->access_policy = source->tsinfo.traffic.accessPolicy; + dest->aggregation = source->tsinfo.traffic.aggregation; + dest->psb = source->tsinfo.traffic.psb; + dest->user_priority = source->tsinfo.traffic.userPrio; + dest->tsinfo_ack_pol = source->tsinfo.traffic.ackPolicy; + dest->burst_size_defn = source->tsinfo.traffic.burstSizeDefn; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + dest->size = (source->nomMsduSz & SIZE_MASK); + dest->fixed = (source->nomMsduSz & FIXED_MASK) ? 1 : 0; + dest->max_msdu_size = source->maxMsduSz; + dest->min_service_int = source->minSvcInterval; + dest->max_service_int = source->maxSvcInterval; + dest->inactivity_int = source->inactInterval; + dest->suspension_int = source->suspendInterval; + dest->service_start_time = source->svcStartTime; + dest->min_data_rate = source->minDataRate; + dest->mean_data_rate = source->meanDataRate; + dest->peak_data_rate = source->peakDataRate; + dest->burst_size = source->maxBurstSz; + dest->delay_bound = source->delayBound; + dest->min_phy_rate = source->minPhyRate; + dest->surplus_bw_allowance = source->surplusBw; + dest->medium_time = source->mediumTime; +} + +#endif + +void populate_dot11f_wmm_info_ap(struct mac_context *mac, tDot11fIEWMMInfoAp *pInfo, + struct pe_session *pe_session) +{ + pInfo->version = SIR_MAC_OUI_VERSION_1; + + /* WMM Specification 3.1.3, 3.2.3 */ + pInfo->param_set_count = (0xf & pe_session->gLimEdcaParamSetCount); + if (LIM_IS_AP_ROLE(pe_session)) + pInfo->uapsd = (0x1 & pe_session->apUapsdEnable); + else + pInfo->uapsd = (0x1 & mac->lim.gUapsdEnable); + + pInfo->present = 1; +} + +void populate_dot11f_wmm_info_station_per_session(struct mac_context *mac, + struct pe_session *pe_session, + tDot11fIEWMMInfoStation *pInfo) +{ + uint8_t max_sp_length = 0; + + max_sp_length = mac->mlme_cfg->wmm_params.max_sp_length; + pInfo->version = SIR_MAC_OUI_VERSION_1; + pInfo->acvo_uapsd = + LIM_UAPSD_GET(ACVO, pe_session->gUapsdPerAcBitmask); + pInfo->acvi_uapsd = + LIM_UAPSD_GET(ACVI, pe_session->gUapsdPerAcBitmask); + pInfo->acbk_uapsd = + LIM_UAPSD_GET(ACBK, pe_session->gUapsdPerAcBitmask); + pInfo->acbe_uapsd = + LIM_UAPSD_GET(ACBE, pe_session->gUapsdPerAcBitmask); + + pInfo->max_sp_length = max_sp_length; + pInfo->present = 1; +} + +void populate_dot11f_wmm_params(struct mac_context *mac, + tDot11fIEWMMParams *pParams, + struct pe_session *pe_session) +{ + pParams->version = SIR_MAC_OUI_VERSION_1; + + if (LIM_IS_AP_ROLE(pe_session)) + pParams->qosInfo = + (pe_session-> + apUapsdEnable << 7) | ((uint8_t) (0x0f & pe_session-> + gLimEdcaParamSetCount)); + else + pParams->qosInfo = + (mac->lim. + gUapsdEnable << 7) | ((uint8_t) (0x0f & pe_session-> + gLimEdcaParamSetCount)); + + /* Fill each EDCA parameter set in order: be, bk, vi, vo */ + pParams->acbe_aifsn = + (0xf & SET_AIFSN(pe_session->gLimEdcaParamsBC[0].aci.aifsn)); + pParams->acbe_acm = (0x1 & pe_session->gLimEdcaParamsBC[0].aci.acm); + pParams->acbe_aci = (0x3 & QCA_WLAN_AC_BE); + pParams->acbe_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[0].cw.min); + pParams->acbe_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[0].cw.max); + pParams->acbe_txoplimit = pe_session->gLimEdcaParamsBC[0].txoplimit; + + pParams->acbk_aifsn = + (0xf & SET_AIFSN(pe_session->gLimEdcaParamsBC[1].aci.aifsn)); + pParams->acbk_acm = (0x1 & pe_session->gLimEdcaParamsBC[1].aci.acm); + pParams->acbk_aci = (0x3 & QCA_WLAN_AC_BK); + pParams->acbk_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[1].cw.min); + pParams->acbk_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[1].cw.max); + pParams->acbk_txoplimit = pe_session->gLimEdcaParamsBC[1].txoplimit; + + if (LIM_IS_AP_ROLE(pe_session)) + pParams->acvi_aifsn = + (0xf & pe_session->gLimEdcaParamsBC[2].aci.aifsn); + else + pParams->acvi_aifsn = + (0xf & + SET_AIFSN(pe_session->gLimEdcaParamsBC[2].aci.aifsn)); + + pParams->acvi_acm = (0x1 & pe_session->gLimEdcaParamsBC[2].aci.acm); + pParams->acvi_aci = (0x3 & QCA_WLAN_AC_VI); + pParams->acvi_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[2].cw.min); + pParams->acvi_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[2].cw.max); + pParams->acvi_txoplimit = pe_session->gLimEdcaParamsBC[2].txoplimit; + + if (LIM_IS_AP_ROLE(pe_session)) + pParams->acvo_aifsn = + (0xf & pe_session->gLimEdcaParamsBC[3].aci.aifsn); + else + pParams->acvo_aifsn = + (0xf & + SET_AIFSN(pe_session->gLimEdcaParamsBC[3].aci.aifsn)); + + pParams->acvo_acm = (0x1 & pe_session->gLimEdcaParamsBC[3].aci.acm); + pParams->acvo_aci = (0x3 & QCA_WLAN_AC_VO); + pParams->acvo_acwmin = + (0xf & pe_session->gLimEdcaParamsBC[3].cw.min); + pParams->acvo_acwmax = + (0xf & pe_session->gLimEdcaParamsBC[3].cw.max); + pParams->acvo_txoplimit = pe_session->gLimEdcaParamsBC[3].txoplimit; + + pParams->present = 1; + +} /* End populate_dot11f_wmm_params. */ + +QDF_STATUS +populate_dot11f_wpa(struct mac_context *mac, + tpSirRSNie pRsnIe, tDot11fIEWPA *pDot11f) +{ + uint32_t status; + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(mac, pRsnIe, DOT11F_EID_WPA); + if (0 <= idx) { + status = dot11f_unpack_ie_wpa(mac, pRsnIe->rsnIEdata + idx + 2 + 4, /* EID, length, OUI */ + pRsnIe->rsnIEdata[idx + 1] - 4, /* OUI */ + pDot11f, false); + if (DOT11F_FAILED(status)) { + pe_err("Parse failure in Populate Dot11fWPA (0x%08x)", + status); + return QDF_STATUS_E_FAILURE; + } + } + } + + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_wpa. */ + +QDF_STATUS populate_dot11f_wpa_opaque(struct mac_context *mac, + tpSirRSNie pRsnIe, + tDot11fIEWPAOpaque *pDot11f) +{ + int idx; + + if (pRsnIe->length) { + idx = find_ie_location(mac, pRsnIe, DOT11F_EID_WPA); + if (0 <= idx) { + pDot11f->present = 1; + pDot11f->num_data = pRsnIe->rsnIEdata[idx + 1] - 4; + qdf_mem_copy(pDot11f->data, pRsnIe->rsnIEdata + idx + 2 + 4, /* EID, len, OUI */ + pRsnIe->rsnIEdata[idx + 1] - 4); /* OUI */ + } + } + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_wpa_opaque. */ + +/* ////////////////////////////////////////////////////////////////////// */ + +QDF_STATUS +sir_convert_probe_req_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, tpSirProbeReq pProbeReq) +{ + uint32_t status; + tDot11fProbeRequest *pr; + + pr = qdf_mem_malloc(sizeof(*pr)); + if (!pr) { + pe_err("malloc failed for probe request"); + return QDF_STATUS_E_FAILURE; + } + + /* Ok, zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pProbeReq, sizeof(tSirProbeReq)); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_request(mac, pFrame, nFrame, pr, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse a Probe Request (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + qdf_mem_free(pr); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking a Probe Request (0x%08x, %d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fProbeRequestto' a 'tSirProbeReq'... */ + if (!pr->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + pProbeReq->ssidPresent = 1; + convert_ssid(mac, &pProbeReq->ssId, &pr->SSID); + } + + if (!pr->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + qdf_mem_free(pr); + return QDF_STATUS_E_FAILURE; + } else { + pProbeReq->suppRatesPresent = 1; + convert_supp_rates(mac, &pProbeReq->supportedRates, + &pr->SuppRates); + } + + if (pr->ExtSuppRates.present) { + pProbeReq->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pProbeReq->extendedRates, + &pr->ExtSuppRates); + } + + if (pr->HTCaps.present) + qdf_mem_copy(&pProbeReq->HTCaps, &pr->HTCaps, + sizeof(tDot11fIEHTCaps)); + + if (pr->WscProbeReq.present) { + pProbeReq->wscIePresent = 1; + memcpy(&pProbeReq->probeReqWscIeInfo, &pr->WscProbeReq, + sizeof(tDot11fIEWscProbeReq)); + } + if (pr->VHTCaps.present) + qdf_mem_copy(&pProbeReq->VHTCaps, &pr->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + + if (pr->P2PProbeReq.present) + pProbeReq->p2pIePresent = 1; + + if (pr->he_cap.present) + qdf_mem_copy(&pProbeReq->he_cap, &pr->he_cap, + sizeof(tDot11fIEhe_cap)); + + qdf_mem_free(pr); + + return QDF_STATUS_SUCCESS; +} /* End sir_convert_probe_req_frame2_struct. */ + + +/** + * sir_validate_and_rectify_ies() - API to check malformed frame + * @mac_ctx: mac context + * @mgmt_frame: pointer to management frame + * @frame_bytes: no of bytes in frame + * @missing_rsn_bytes: missing rsn bytes + * + * The frame would contain fixed IEs of 12 bytes followed by variable IEs + * (Tagged elements). Every Tagged IE has tag number, tag length and data. + * Tag length indicates the size of data in bytes. + * This function checks for size of Frame received with the sum of all IEs. + * And also rectifies missing optional fields in IE. + * + * NOTE : Presently this function rectifies RSN capability in RSN IE, can + * be extended to rectify other optional fields in other IEs. + * + * Return: 0 on success, error number otherwise. + */ +QDF_STATUS +sir_validate_and_rectify_ies(struct mac_context *mac_ctx, + uint8_t *mgmt_frame, + uint32_t frame_bytes, + uint32_t *missing_rsn_bytes) +{ + uint32_t length = SIZE_OF_FIXED_PARAM; + uint8_t *ref_frame = NULL; + + /* Frame contains atleast one IE */ + if (frame_bytes > (SIZE_OF_FIXED_PARAM + + SIZE_OF_TAG_PARAM_NUM + SIZE_OF_TAG_PARAM_LEN)) { + while (length < frame_bytes) { + /* ref frame points to next IE */ + ref_frame = mgmt_frame + length; + length += (uint32_t)(SIZE_OF_TAG_PARAM_NUM + + SIZE_OF_TAG_PARAM_LEN + + (*(ref_frame + SIZE_OF_TAG_PARAM_NUM))); + } + if (length != frame_bytes) { + /* + * Workaround : Some APs may not include RSN + * Capability but the length of which is included in + * RSN IE length. This may cause in updating RSN + * Capability with junk value. To avoid this, add RSN + * Capability value with default value. + */ + if (ref_frame && (*ref_frame == RSNIEID) && + (length == (frame_bytes + + RSNIE_CAPABILITY_LEN))) { + /* Assume RSN Capability as 00 */ + qdf_mem_set((uint8_t *)(mgmt_frame + + (frame_bytes)), + RSNIE_CAPABILITY_LEN, + DEFAULT_RSNIE_CAP_VAL); + *missing_rsn_bytes = RSNIE_CAPABILITY_LEN; + pe_debug("Added RSN Capability to RSNIE as 0x00 0x00"); + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + +void sir_copy_caps_info(struct mac_context *mac_ctx, tDot11fFfCapabilities caps, + tpSirProbeRespBeacon pProbeResp) +{ + pProbeResp->capabilityInfo.ess = caps.ess; + pProbeResp->capabilityInfo.ibss = caps.ibss; + pProbeResp->capabilityInfo.cfPollable = caps.cfPollable; + pProbeResp->capabilityInfo.cfPollReq = caps.cfPollReq; + pProbeResp->capabilityInfo.privacy = caps.privacy; + pProbeResp->capabilityInfo.shortPreamble = caps.shortPreamble; + pProbeResp->capabilityInfo.criticalUpdateFlag = caps.criticalUpdateFlag; + pProbeResp->capabilityInfo.channelAgility = caps.channelAgility; + pProbeResp->capabilityInfo.spectrumMgt = caps.spectrumMgt; + pProbeResp->capabilityInfo.qos = caps.qos; + pProbeResp->capabilityInfo.shortSlotTime = caps.shortSlotTime; + pProbeResp->capabilityInfo.apsd = caps.apsd; + pProbeResp->capabilityInfo.rrm = caps.rrm; + pProbeResp->capabilityInfo.dsssOfdm = caps.dsssOfdm; + pProbeResp->capabilityInfo.delayedBA = caps.delayedBA; + pProbeResp->capabilityInfo.immediateBA = caps.immediateBA; +} + +#ifdef WLAN_FEATURE_FILS_SK +static void populate_dot11f_fils_rsn(struct mac_context *mac_ctx, + tDot11fIERSNOpaque *p_dot11f, + uint8_t *rsn_ie) +{ + pe_debug("FILS RSN IE length %d", rsn_ie[1]); + if (rsn_ie[1]) { + p_dot11f->present = 1; + p_dot11f->num_data = rsn_ie[1]; + qdf_mem_copy(p_dot11f->data, &rsn_ie[2], rsn_ie[1]); + } +} + +void populate_dot11f_fils_params(struct mac_context *mac_ctx, + tDot11fAssocRequest *frm, + struct pe_session *pe_session) +{ + struct pe_fils_session *fils_info = pe_session->fils_info; + + /* Populate RSN IE with FILS AKM */ + populate_dot11f_fils_rsn(mac_ctx, &frm->RSNOpaque, + fils_info->rsn_ie); + + /* Populate FILS session IE */ + frm->fils_session.present = true; + qdf_mem_copy(frm->fils_session.session, + fils_info->fils_session, FILS_SESSION_LENGTH); + + /* Populate FILS Key confirmation IE */ + if (fils_info->key_auth_len) { + frm->fils_key_confirmation.present = true; + frm->fils_key_confirmation.num_key_auth = + fils_info->key_auth_len; + + qdf_mem_copy(frm->fils_key_confirmation.key_auth, + fils_info->key_auth, fils_info->key_auth_len); + } +} + +/** + * update_fils_data: update fils params from beacon/probe response + * @fils_ind: pointer to sir_fils_indication + * @fils_indication: pointer to tDot11fIEfils_indication + * + * Return: None + */ +void update_fils_data(struct sir_fils_indication *fils_ind, + tDot11fIEfils_indication *fils_indication) +{ + uint8_t *data; + uint8_t remaining_data = fils_indication->num_variable_data; + + data = fils_indication->variable_data; + fils_ind->is_present = true; + fils_ind->is_ip_config_supported = + fils_indication->is_ip_config_supported; + fils_ind->is_fils_sk_auth_supported = + fils_indication->is_fils_sk_auth_supported; + fils_ind->is_fils_sk_auth_pfs_supported = + fils_indication->is_fils_sk_auth_pfs_supported; + fils_ind->is_pk_auth_supported = + fils_indication->is_pk_auth_supported; + if (fils_indication->is_cache_id_present) { + if (remaining_data < SIR_CACHE_IDENTIFIER_LEN) { + pe_err("Failed to copy Cache Identifier, Invalid remaining data %d", + remaining_data); + return; + } + fils_ind->cache_identifier.is_present = true; + qdf_mem_copy(fils_ind->cache_identifier.identifier, + data, SIR_CACHE_IDENTIFIER_LEN); + data = data + SIR_CACHE_IDENTIFIER_LEN; + remaining_data = remaining_data - SIR_CACHE_IDENTIFIER_LEN; + } + if (fils_indication->is_hessid_present) { + if (remaining_data < SIR_HESSID_LEN) { + pe_err("Failed to copy HESSID, Invalid remaining data %d", + remaining_data); + return; + } + fils_ind->hessid.is_present = true; + qdf_mem_copy(fils_ind->hessid.hessid, + data, SIR_HESSID_LEN); + data = data + SIR_HESSID_LEN; + remaining_data = remaining_data - SIR_HESSID_LEN; + } + if (fils_indication->realm_identifiers_cnt) { + if (remaining_data < (fils_indication->realm_identifiers_cnt * + SIR_REALM_LEN)) { + pe_err("Failed to copy Realm Identifier, Invalid remaining data %d realm_cnt %d", + remaining_data, + fils_indication->realm_identifiers_cnt); + return; + } + fils_ind->realm_identifier.is_present = true; + fils_ind->realm_identifier.realm_cnt = + fils_indication->realm_identifiers_cnt; + qdf_mem_copy(fils_ind->realm_identifier.realm, + data, fils_ind->realm_identifier.realm_cnt * + SIR_REALM_LEN); + } +} +#endif + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void update_bss_color_change_ie_from_probe_rsp( + tDot11fProbeResponse *prb_frm, + tpSirProbeRespBeacon prb_rsp_struct) +{ + if (prb_frm->bss_color_change.present) { + pe_debug("11AX: HE BSS color change present"); + qdf_mem_copy(&prb_rsp_struct->vendor_he_bss_color_change, + &prb_frm->bss_color_change, + sizeof(tDot11fIEbss_color_change)); + } +} +#else +static inline void update_bss_color_change_ie_from_probe_rsp( + tDot11fProbeResponse *prb_frm, + tpSirProbeRespBeacon prb_rsp_struct) +{} +#endif + +#ifdef WLAN_FEATURE_11BE +static void +sir_convert_probe_frame2_eht_struct(tDot11fProbeResponse *pr, + tpSirProbeRespBeacon p_probe_resp) +{ + if (pr->eht_cap.present) { + qdf_mem_copy(&p_probe_resp->eht_cap, &pr->eht_cap, + sizeof(tDot11fIEeht_cap)); + } +} +#else +static inline void +sir_convert_probe_frame2_eht_struct(tDot11fProbeResponse *pr, + tpSirProbeRespBeacon p_probe_resp) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_convert_probe_frame2_mlo_struct(uint8_t *pframe, + uint32_t nframe, + tDot11fProbeResponse *pr, + tpSirProbeRespBeacon p_probe_resp) +{ + uint32_t status; + uint8_t *ml_ie; + qdf_size_t ml_ie_total_len; + + if (pr->mlo_ie.present) { + status = util_find_mlie(pframe + WLAN_PROBE_RESP_IES_OFFSET, + nframe - WLAN_PROBE_RESP_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_SUCCESS(status)) { + sir_convert_mlo_probe_rsp_frame2_struct(ml_ie, + ml_ie_total_len, + &p_probe_resp->mlo_ie); + } + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +sir_convert_probe_frame2_mlo_struct(uint8_t *pframe, + uint32_t nframe, + tDot11fProbeResponse *pr, + tpSirProbeRespBeacon p_probe_resp) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_convert_probe_frame2_t2lm_struct(tDot11fProbeResponse *pr, + tpSirProbeRespBeacon bcn_struct) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_t2lm_context *t2lm_ctx; + /* add 3 bytes for extn_ie_header */ + uint8_t ie[DOT11F_IE_T2LM_IE_MAX_LEN + 3]; + struct wlan_t2lm_info t2lm; + uint8_t i; + + t2lm_ctx = &bcn_struct->t2lm_ctx; + qdf_mem_zero(&t2lm_ctx->established_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + qdf_mem_zero(&t2lm_ctx->upcoming_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + if (!pr->num_t2lm_ie) + return status; + + pe_debug("Number of T2LM IEs in probe rsp %d", pr->num_t2lm_ie); + for (i = 0; i < pr->num_t2lm_ie; i++) { + qdf_mem_zero(&ie[0], DOT11F_IE_T2LM_IE_MAX_LEN + 3); + qdf_mem_zero(&t2lm, sizeof(struct wlan_t2lm_info)); + ie[ID_POS] = WLAN_ELEMID_EXTN_ELEM; + ie[TAG_LEN_POS] = pr->t2lm_ie[i].num_data + 1; + ie[IDEXT_POS] = WLAN_EXTN_ELEMID_T2LM; + qdf_mem_copy(&ie[3], &pr->t2lm_ie[i].data[0], + pr->t2lm_ie[i].num_data); + + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &ie[0], pr->t2lm_ie[i].num_data + 3); + + if (ie[TAG_LEN_POS] + 2 > DOT11F_IE_T2LM_IE_MAX_LEN + 3) { + pe_debug("Invalid T2LM IE length"); + return QDF_STATUS_E_PROTO; + } + + status = wlan_mlo_parse_t2lm_info(&ie[0], &t2lm); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Parse T2LM IE fail"); + return status; + } + + if (!t2lm.mapping_switch_time_present && + t2lm.expected_duration_present) { + qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm, + sizeof(struct wlan_t2lm_info)); + pe_debug("Parse established T2LM IE success"); + } else if (t2lm.mapping_switch_time_present) { + qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm, + sizeof(struct wlan_t2lm_info)); + pe_debug("Parse upcoming T2LM IE success"); + } + pe_debug("Parse T2LM IE success"); + } + return status; +} +#else +static inline QDF_STATUS +sir_convert_probe_frame2_t2lm_struct(tDot11fProbeResponse *pr, + tpSirProbeRespBeacon bcn_struct) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS sir_convert_probe_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, + tpSirProbeRespBeacon pProbeResp) +{ + uint32_t status; + tDot11fProbeResponse *pr; + + /* Ok, zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pProbeResp, sizeof(tSirProbeRespBeacon)); + + pr = qdf_mem_malloc(sizeof(tDot11fProbeResponse)); + if (!pr) + return QDF_STATUS_E_NOMEM; + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_probe_response(mac, pFrame, nFrame, pr, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse a Probe Response (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + pFrame, nFrame); + qdf_mem_free(pr); + return QDF_STATUS_E_FAILURE; + } + /* & "transliterate" from a 'tDot11fProbeResponse' to a 'tSirProbeRespBeacon'... */ + + /* Timestamp */ + qdf_mem_copy((uint8_t *) pProbeResp->timeStamp, + (uint8_t *) &pr->TimeStamp, sizeof(tSirMacTimeStamp)); + + /* Beacon Interval */ + pProbeResp->beaconInterval = pr->BeaconInterval.interval; + + sir_copy_caps_info(mac, pr->Capabilities, pProbeResp); + + if (!pr->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + pProbeResp->ssidPresent = 1; + convert_ssid(mac, &pProbeResp->ssId, &pr->SSID); + } + + if (!pr->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pProbeResp->suppRatesPresent = 1; + convert_supp_rates(mac, &pProbeResp->supportedRates, + &pr->SuppRates); + } + + if (pr->ExtSuppRates.present) { + pProbeResp->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pProbeResp->extendedRates, + &pr->ExtSuppRates); + } + + if (pr->CFParams.present) { + pProbeResp->cfPresent = 1; + convert_cf_params(mac, &pProbeResp->cfParamSet, &pr->CFParams); + } + + if (pr->Country.present) { + pProbeResp->countryInfoPresent = 1; + convert_country(mac, &pProbeResp->countryInfoParam, + &pr->Country); + } + + if (pr->EDCAParamSet.present) { + pProbeResp->edcaPresent = 1; + convert_edca_param(mac, &pProbeResp->edcaParams, + &pr->EDCAParamSet); + } + + if (pr->ChanSwitchAnn.present) { + pProbeResp->channelSwitchPresent = 1; + qdf_mem_copy(&pProbeResp->channelSwitchIE, &pr->ChanSwitchAnn, + sizeof(pProbeResp->channelSwitchIE)); + } + + if (pr->ext_chan_switch_ann.present) { + pProbeResp->ext_chan_switch_present = 1; + qdf_mem_copy(&pProbeResp->ext_chan_switch, + &pr->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pr->SuppOperatingClasses.present) { + pProbeResp->supp_operating_class_present = 1; + qdf_mem_copy(&pProbeResp->supp_operating_classes, + &pr->SuppOperatingClasses, + sizeof(tDot11fIESuppOperatingClasses)); + } + + if (pr->sec_chan_offset_ele.present) { + pProbeResp->sec_chan_offset_present = 1; + qdf_mem_copy(&pProbeResp->sec_chan_offset, + &pr->sec_chan_offset_ele, + sizeof(pProbeResp->sec_chan_offset)); + } + + if (pr->TPCReport.present) { + pProbeResp->tpcReportPresent = 1; + qdf_mem_copy(&pProbeResp->tpcReport, &pr->TPCReport, + sizeof(tDot11fIETPCReport)); + } + + if (pr->PowerConstraints.present) { + pProbeResp->powerConstraintPresent = 1; + qdf_mem_copy(&pProbeResp->localPowerConstraint, + &pr->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } + + if (pr->Quiet.present) { + pProbeResp->quietIEPresent = 1; + qdf_mem_copy(&pProbeResp->quietIE, &pr->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pr->HTCaps.present) { + qdf_mem_copy(&pProbeResp->HTCaps, &pr->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pr->HTInfo.present) { + qdf_mem_copy(&pProbeResp->HTInfo, &pr->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + + if (pr->he_op.oper_info_6g_present) { + pProbeResp->chan_freq = wlan_reg_chan_band_to_freq(mac->pdev, + pr->he_op.oper_info_6g.info.primary_ch, + BIT(REG_BAND_6G)); + } else if (pr->DSParams.present) { + pProbeResp->dsParamsPresent = 1; + pProbeResp->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, pr->DSParams.curr_channel); + } else if (pr->HTInfo.present) { + pProbeResp->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, pr->HTInfo.primaryChannel); + } + + if (pr->RSNOpaque.present) { + pProbeResp->rsnPresent = 1; + convert_rsn_opaque(mac, &pProbeResp->rsn, &pr->RSNOpaque); + } + + if (pr->WPA.present) { + pProbeResp->wpaPresent = 1; + convert_wpa(mac, &pProbeResp->wpa, &pr->WPA); + } + + if (pr->WMMParams.present) { + pProbeResp->wmeEdcaPresent = 1; + convert_wmm_params(mac, &pProbeResp->edcaParams, &pr->WMMParams); + } + + if (pr->WMMInfoAp.present) { + pProbeResp->wmeInfoPresent = 1; + pe_debug("WMM Information Element present in Probe Response Frame!"); + } + + if (pr->WMMCaps.present) { + pProbeResp->wsmCapablePresent = 1; + } + + if (pr->ERPInfo.present) { + pProbeResp->erpPresent = 1; + convert_erp_info(mac, &pProbeResp->erpIEInfo, &pr->ERPInfo); + } + if (pr->MobilityDomain.present) { + /* MobilityDomain */ + pProbeResp->mdiePresent = 1; + qdf_mem_copy((uint8_t *) &(pProbeResp->mdie[0]), + (uint8_t *) &(pr->MobilityDomain.MDID), + sizeof(uint16_t)); + pProbeResp->mdie[2] = + ((pr->MobilityDomain.overDSCap << 0) | (pr->MobilityDomain. + resourceReqCap << + 1)); + pe_debug("mdie=%02x%02x%02x", + (unsigned int)pProbeResp->mdie[0], + (unsigned int)pProbeResp->mdie[1], + (unsigned int)pProbeResp->mdie[2]); + } + +#if defined FEATURE_WLAN_ESE + if (pr->ESEVersion.present) + pProbeResp->is_ese_ver_ie_present = 1; + if (pr->QBSSLoad.present) { + qdf_mem_copy(&pProbeResp->QBSSLoad, &pr->QBSSLoad, + sizeof(tDot11fIEQBSSLoad)); + } +#endif + if (pr->P2PProbeRes.present) { + qdf_mem_copy(&pProbeResp->P2PProbeRes, &pr->P2PProbeRes, + sizeof(tDot11fIEP2PProbeRes)); + } + if (pr->VHTCaps.present) { + qdf_mem_copy(&pProbeResp->VHTCaps, &pr->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr->VHTOperation.present) { + qdf_mem_copy(&pProbeResp->VHTOperation, &pr->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pr->VHTExtBssLoad.present) { + qdf_mem_copy(&pProbeResp->VHTExtBssLoad, &pr->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + pProbeResp->Vendor1IEPresent = pr->Vendor1IE.present; + pProbeResp->Vendor3IEPresent = pr->Vendor3IE.present; + + pProbeResp->vendor_vht_ie.present = pr->vendor_vht_ie.present; + if (pr->vendor_vht_ie.present) + pProbeResp->vendor_vht_ie.sub_type = pr->vendor_vht_ie.sub_type; + if (pr->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pProbeResp->vendor_vht_ie.VHTCaps, + &pr->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pr->vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pProbeResp->vendor_vht_ie.VHTOperation, + &pr->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + /* Update HS 2.0 Information Element */ + if (pr->hs20vendor_ie.present) { + pe_debug("HS20 Indication Element Present, rel#:%u, id:%u", + pr->hs20vendor_ie.release_num, + pr->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&pProbeResp->hs20vendor_ie, + &pr->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(pr->hs20vendor_ie.hs_id)); + if (pr->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&pProbeResp->hs20vendor_ie.hs_id, + &pr->hs20vendor_ie.hs_id, + sizeof(pr->hs20vendor_ie.hs_id)); + } + if (pr->MBO_IE.present) { + pProbeResp->MBO_IE_present = true; + if (pr->MBO_IE.cellular_data_cap.present) + pProbeResp->MBO_capability = + pr->MBO_IE.cellular_data_cap.cellular_connectivity; + + if (pr->MBO_IE.assoc_disallowed.present) { + pProbeResp->assoc_disallowed = true; + pProbeResp->assoc_disallowed_reason = + pr->MBO_IE.assoc_disallowed.reason_code; + } + } + + if (pr->qcn_ie.present) + qdf_mem_copy(&pProbeResp->qcn_ie, &pr->qcn_ie, + sizeof(tDot11fIEqcn_ie)); + + if (pr->he_cap.present) { + qdf_mem_copy(&pProbeResp->he_cap, &pr->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (pr->he_op.present) { + qdf_mem_copy(&pProbeResp->he_op, &pr->he_op, + sizeof(tDot11fIEhe_op)); + } + + sir_convert_probe_frame2_eht_struct(pr, pProbeResp); + update_bss_color_change_ie_from_probe_rsp(pr, pProbeResp); + sir_convert_probe_frame2_mlo_struct(pFrame, nFrame, pr, pProbeResp); + sir_convert_probe_frame2_t2lm_struct(pr, pProbeResp); + + qdf_mem_free(pr); + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_probe_frame2_struct. */ + +#ifdef WLAN_FEATURE_11BE +static void +sir_convert_assoc_req_frame2_eht_struct(tDot11fAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ + if (ar->eht_cap.present) + qdf_mem_copy(&p_assoc_req->eht_cap, &ar->eht_cap, + sizeof(tDot11fIEeht_cap)); +} +#else +static inline void +sir_convert_assoc_req_frame2_eht_struct(tDot11fAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_convert_assoc_req_frame2_mlo_struct(uint8_t *pframe, + uint32_t nframe, + tDot11fAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ + uint8_t *ml_ie; + qdf_size_t ml_ie_total_len; + struct qdf_mac_addr mld_mac_addr; + uint32_t status; + + if (ar->mlo_ie.present) { + status = util_find_mlie(pframe + WLAN_ASSOC_REQ_IES_OFFSET, + nframe - WLAN_ASSOC_REQ_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + + if (QDF_IS_STATUS_SUCCESS(status)) { + util_get_bvmlie_persta_partner_info(ml_ie, + ml_ie_total_len, + &p_assoc_req->mlo_info); + util_get_bvmlie_mldmacaddr(ml_ie, ml_ie_total_len, + &mld_mac_addr); + qdf_mem_copy(p_assoc_req->mld_mac, mld_mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + pe_debug("Partner link count: %d, MLD mac addr: " QDF_MAC_ADDR_FMT, + p_assoc_req->mlo_info.num_partner_links, + QDF_MAC_ADDR_REF(p_assoc_req->mld_mac)); + } else { + pe_debug("Do not find mlie"); + } + } + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +sir_convert_assoc_req_frame2_mlo_struct(uint8_t *pFrame, + uint32_t nFrame, + tDot11fAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +enum wlan_status_code +sir_convert_assoc_req_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + tDot11fAssocRequest *ar; + uint32_t status; + + ar = qdf_mem_malloc(sizeof(tDot11fAssocRequest)); + if (!ar) + return STATUS_UNSPECIFIED_FAILURE; + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_assoc_request(mac, pFrame, nFrame, ar, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse an Association Request (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + qdf_mem_free(ar); + return STATUS_UNSPECIFIED_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking an Association Request (0x%08x, %d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAssocRequest' to a 'tSirAssocReq'... */ + + /* make sure this is seen as an assoc request */ + pAssocReq->reassocRequest = 0; + + /* Capabilities */ + pAssocReq->capabilityInfo.ess = ar->Capabilities.ess; + pAssocReq->capabilityInfo.ibss = ar->Capabilities.ibss; + pAssocReq->capabilityInfo.cfPollable = ar->Capabilities.cfPollable; + pAssocReq->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq; + pAssocReq->capabilityInfo.privacy = ar->Capabilities.privacy; + pAssocReq->capabilityInfo.shortPreamble = + ar->Capabilities.shortPreamble; + pAssocReq->capabilityInfo.criticalUpdateFlag = + ar->Capabilities.criticalUpdateFlag; + pAssocReq->capabilityInfo.channelAgility = + ar->Capabilities.channelAgility; + pAssocReq->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt; + pAssocReq->capabilityInfo.qos = ar->Capabilities.qos; + pAssocReq->capabilityInfo.shortSlotTime = + ar->Capabilities.shortSlotTime; + pAssocReq->capabilityInfo.apsd = ar->Capabilities.apsd; + pAssocReq->capabilityInfo.rrm = ar->Capabilities.rrm; + pAssocReq->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm; + pAssocReq->capabilityInfo.delayedBA = ar->Capabilities.delayedBA; + pAssocReq->capabilityInfo.immediateBA = ar->Capabilities.immediateBA; + + /* Listen Interval */ + pAssocReq->listenInterval = ar->ListenInterval.interval; + + /* SSID */ + if (ar->SSID.present) { + pAssocReq->ssidPresent = 1; + convert_ssid(mac, &pAssocReq->ssId, &ar->SSID); + } + /* Supported Rates */ + if (ar->SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(mac, &pAssocReq->supportedRates, + &ar->SuppRates); + } + /* Extended Supported Rates */ + if (ar->ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pAssocReq->extendedRates, + &ar->ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar->QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(mac, &pAssocReq->qosCapability, + &ar->QOSCapsStation); + } + /* WPA */ + if (ar->WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(mac, &pAssocReq->wpa, &ar->WPAOpaque); + } +#ifdef FEATURE_WLAN_WAPI + if (ar->WAPIOpaque.present) { + pAssocReq->wapiPresent = 1; + convert_wapi_opaque(mac, &pAssocReq->wapi, &ar->WAPIOpaque); + } +#endif + /* RSN */ + if (ar->RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(mac, &pAssocReq->rsn, &ar->RSNOpaque); + } + /* WSC IE */ + if (ar->WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(mac, &pAssocReq->addIE, &ar->WscIEOpaque); + } + + if (ar->P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(mac, &pAssocReq->addIE, &ar->P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar->WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(mac, &pAssocReq->addIE, &ar->WFDIEOpaque); + } +#endif + + /* Power Capabilities */ + if (ar->PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(mac, &pAssocReq->powerCapability, + &ar->PowerCaps); + } + /* Supported Channels */ + if (ar->SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(mac, &pAssocReq->supportedChannels, + &ar->SuppChannels); + } + + if (ar->HTCaps.present) { + qdf_mem_copy(&pAssocReq->HTCaps, &ar->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar->WMMInfoStation.present) { + pAssocReq->wmeInfoPresent = 1; + qdf_mem_copy(&pAssocReq->WMMInfoStation, &ar->WMMInfoStation, + sizeof(tDot11fIEWMMInfoStation)); + + } + + if (ar->WMMCaps.present) + pAssocReq->wsmCapablePresent = 1; + + if (!pAssocReq->ssidPresent) { + pe_debug("Received Assoc without SSID IE"); + qdf_mem_free(ar); + return STATUS_UNSPECIFIED_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + pe_debug("Received Assoc without supp rate IE"); + qdf_mem_free(ar); + return STATUS_ASSOC_DENIED_RATES; + } + if (ar->VHTCaps.present) { + qdf_mem_copy(&pAssocReq->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log_vht_cap(mac, &pAssocReq->VHTCaps); + } + if (ar->OperatingMode.present) { + qdf_mem_copy(&pAssocReq->operMode, &ar->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + lim_log_operating_mode(mac, &pAssocReq->operMode); + } + if (ar->ExtCap.present) { + struct s_ext_cap *ext_cap; + + qdf_mem_copy(&pAssocReq->ExtCap, &ar->ExtCap, + sizeof(tDot11fIEExtCap)); + ext_cap = (struct s_ext_cap *)&pAssocReq->ExtCap.bytes; + pe_debug("timingMeas: %d, finetimingMeas Init: %d, Resp: %d", + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + if (ar->SuppOperatingClasses.present) { + uint8_t num_classes = ar->SuppOperatingClasses.num_classes; + + if (num_classes > sizeof(ar->SuppOperatingClasses.classes)) + num_classes = + sizeof(ar->SuppOperatingClasses.classes); + qdf_mem_copy(&pAssocReq->supp_operating_classes, + &ar->SuppOperatingClasses, + sizeof(tDot11fIESuppOperatingClasses)); + } + + pAssocReq->vendor_vht_ie.present = ar->vendor_vht_ie.present; + if (ar->vendor_vht_ie.present) { + pAssocReq->vendor_vht_ie.sub_type = ar->vendor_vht_ie.sub_type; + if (ar->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pAssocReq->vendor_vht_ie.VHTCaps, + &ar->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log_vht_cap(mac, &pAssocReq->VHTCaps); + } + } + if (ar->qcn_ie.present) + qdf_mem_copy(&pAssocReq->qcn_ie, &ar->qcn_ie, + sizeof(tDot11fIEqcn_ie)); + if (ar->bss_max_idle_period.present) { + qdf_mem_copy(&pAssocReq->bss_max_idle_period, + &ar->bss_max_idle_period, + sizeof(tDot11fIEbss_max_idle_period)); + } + if (ar->he_cap.present) + qdf_mem_copy(&pAssocReq->he_cap, &ar->he_cap, + sizeof(tDot11fIEhe_cap)); + + if (ar->he_6ghz_band_cap.present) + qdf_mem_copy(&pAssocReq->he_6ghz_band_cap, + &ar->he_6ghz_band_cap, + sizeof(tDot11fIEhe_6ghz_band_cap)); + + sir_convert_assoc_req_frame2_eht_struct(ar, pAssocReq); + sir_convert_assoc_req_frame2_mlo_struct(pFrame, nFrame, ar, pAssocReq); + + pe_debug("ht %d vht %d opmode %d vendor vht %d he %d he 6ghband %d eht %d", + ar->HTCaps.present, ar->VHTCaps.present, + ar->OperatingMode.present, ar->vendor_vht_ie.VHTCaps.present, + ar->he_cap.present, ar->he_6ghz_band_cap.present, + ar->eht_cap.present); + + qdf_mem_free(ar); + return STATUS_SUCCESS; + +} /* End sir_convert_assoc_req_frame2_struct. */ + +QDF_STATUS dot11f_parse_assoc_response(struct mac_context *mac_ctx, + uint8_t *p_buf, uint32_t n_buf, + tDot11fAssocResponse *p_frm, + bool append_ie) +{ + uint32_t status; + + status = dot11f_unpack_assoc_response(mac_ctx, p_buf, + n_buf, p_frm, append_ie); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse an Association Response (0x%08x, %d bytes):", + status, n_buf); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + p_buf, n_buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_FILS_SK +/** + * fils_convert_assoc_rsp_frame2_struct() - Copy FILS IE's to Assoc rsp struct + * @ar: frame parser Assoc response struct + * @pAssocRsp: LIM Assoc response + * + * Return: None + */ +static void fils_convert_assoc_rsp_frame2_struct(tDot11fAssocResponse *ar, + tpSirAssocRsp pAssocRsp) +{ + if (ar->fils_session.present) { + pe_debug("fils session IE present"); + pAssocRsp->fils_session.present = true; + qdf_mem_copy(pAssocRsp->fils_session.session, + ar->fils_session.session, + DOT11F_IE_FILS_SESSION_MAX_LEN); + } + + if (ar->fils_key_confirmation.present) { + pe_debug("fils key conf IE present"); + pAssocRsp->fils_key_auth.num_key_auth = + ar->fils_key_confirmation.num_key_auth; + qdf_mem_copy(pAssocRsp->fils_key_auth.key_auth, + ar->fils_key_confirmation.key_auth, + pAssocRsp->fils_key_auth.num_key_auth); + } + + if (ar->fils_kde.present) { + pe_debug("fils kde IE present %d", + ar->fils_kde.num_kde_list); + pAssocRsp->fils_kde.num_kde_list = + ar->fils_kde.num_kde_list; + qdf_mem_copy(pAssocRsp->fils_kde.key_rsc, + ar->fils_kde.key_rsc, KEY_RSC_LEN); + qdf_mem_copy(&pAssocRsp->fils_kde.kde_list, + &ar->fils_kde.kde_list, + pAssocRsp->fils_kde.num_kde_list); + } + + if (ar->fils_hlp_container.present) { + pe_debug("FILS HLP container IE present"); + sir_copy_mac_addr(pAssocRsp->dst_mac.bytes, + ar->fils_hlp_container.dest_mac); + sir_copy_mac_addr(pAssocRsp->src_mac.bytes, + ar->fils_hlp_container.src_mac); + pAssocRsp->hlp_data_len = ar->fils_hlp_container.num_hlp_packet; + qdf_mem_copy(pAssocRsp->hlp_data, + ar->fils_hlp_container.hlp_packet, + pAssocRsp->hlp_data_len); + + if (ar->fragment_ie.present) { + pe_debug("FILS fragment ie present"); + qdf_mem_copy(pAssocRsp->hlp_data + + pAssocRsp->hlp_data_len, + ar->fragment_ie.data, + ar->fragment_ie.num_data); + pAssocRsp->hlp_data_len += ar->fragment_ie.num_data; + } + } +} +#else +static inline void fils_convert_assoc_rsp_frame2_struct(tDot11fAssocResponse + *ar, tpSirAssocRsp + pAssocRsp) +{ } +#endif + +QDF_STATUS wlan_parse_ftie_sha384(uint8_t *frame, uint32_t frame_len, + struct sSirAssocRsp *assoc_rsp) +{ + const uint8_t *ie, *ie_end, *pos; + uint8_t ie_len, remaining_ie_len; + struct wlan_sha384_ftinfo_subelem *ft_subelem; + + ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_FTINFO, frame, frame_len); + if (!ie) { + pe_err("FT IE not present"); + return QDF_STATUS_E_FAILURE; + } + + if (!ie[1]) { + pe_err("FT IE length is zero"); + return QDF_STATUS_E_FAILURE; + } + + ie_len = ie[1]; + if (ie_len < sizeof(struct wlan_sha384_ftinfo)) { + pe_err("Invalid FTIE len:%d", ie_len); + return QDF_STATUS_E_FAILURE; + } + remaining_ie_len = ie_len; + pos = ie + 2; + qdf_mem_copy(&assoc_rsp->sha384_ft_info, pos, + sizeof(struct wlan_sha384_ftinfo)); + ie_end = ie + ie_len; + pos += sizeof(struct wlan_sha384_ftinfo); + remaining_ie_len -= sizeof(struct wlan_sha384_ftinfo); + ft_subelem = &assoc_rsp->sha384_ft_subelem; + qdf_mem_zero(ft_subelem, sizeof(*ft_subelem)); + while (ie_end - pos >= 2) { + uint8_t id, len; + + id = *pos++; + len = *pos++; + /* Subtract data length(len) + 1 bytes for + * Subelement ID + 1 bytes for length from + * remaining FTIE buffer len (ie_len). + * Subelement Parameter(s) field : + * Subelement ID Length Data + * Octets: 1 1 variable + */ + if (len < 1 || remaining_ie_len < (len + 2)) { + pe_err("Invalid FT subelem length"); + return QDF_STATUS_E_FAILURE; + } + + remaining_ie_len -= (len + 2); + + switch (id) { + case FTIE_SUBELEM_R1KH_ID: + if (len != FTIE_R1KH_LEN) { + pe_err("Invalid R1KH-ID length: %d", + len); + return QDF_STATUS_E_FAILURE; + } + ft_subelem->r1kh_id.present = 1; + qdf_mem_copy(ft_subelem->r1kh_id.PMK_R1_ID, + pos, FTIE_R1KH_LEN); + break; + case FTIE_SUBELEM_GTK: + if (ft_subelem->gtk) { + qdf_mem_zero(ft_subelem->gtk, + ft_subelem->gtk_len); + ft_subelem->gtk_len = 0; + qdf_mem_free(ft_subelem->gtk); + } + ft_subelem->gtk = qdf_mem_malloc(len); + if (!ft_subelem->gtk) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(ft_subelem->gtk, pos, len); + ft_subelem->gtk_len = len; + break; + case FTIE_SUBELEM_R0KH_ID: + if (len < 1 || len > FTIE_R0KH_MAX_LEN) { + pe_err("Invalid R0KH-ID length: %d", + len); + return QDF_STATUS_E_FAILURE; + } + ft_subelem->r0kh_id.present = 1; + ft_subelem->r0kh_id.num_PMK_R0_ID = len; + qdf_mem_copy(ft_subelem->r0kh_id.PMK_R0_ID, + pos, len); + break; + case FTIE_SUBELEM_IGTK: + if (ft_subelem->igtk) { + qdf_mem_zero(ft_subelem->igtk, + ft_subelem->igtk_len); + ft_subelem->igtk_len = 0; + qdf_mem_free(ft_subelem->igtk); + } + ft_subelem->igtk = qdf_mem_malloc(len); + if (!ft_subelem->igtk) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(ft_subelem->igtk, pos, len); + ft_subelem->igtk_len = len; + + break; + default: + pe_debug("Unknown subelem id %d len:%d", + id, len); + break; + } + pos += len; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE +static void +sir_convert_assoc_resp_frame2_eht_struct(tDot11fAssocResponse *ar, + tpSirAssocRsp p_assoc_rsp) +{ + if (ar->eht_cap.present) + qdf_mem_copy(&p_assoc_rsp->eht_cap, &ar->eht_cap, + sizeof(tDot11fIEeht_cap)); + + if (ar->eht_op.present) + qdf_mem_copy(&p_assoc_rsp->eht_op, &ar->eht_op, + sizeof(tDot11fIEeht_op)); +} +#else +static inline void +sir_convert_assoc_resp_frame2_eht_struct(tDot11fAssocResponse *ar, + tpSirAssocRsp p_assoc_rsp) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_copy_assoc_rsp_partner_info_to_session(struct pe_session *session_entry, + struct mlo_partner_info *partner_info) +{ + uint16_t i, partner_idx = 0, j, link_id; + struct mlo_link_info *link_info; + struct mlo_partner_info *ml_partner_info = + &session_entry->ml_partner_info; + + link_info = mlo_mgr_get_ap_link(session_entry->vdev); + if (!link_info) + return QDF_STATUS_E_FAILURE; + + /* Clear the Partner info already filled from the join request */ + qdf_mem_zero(ml_partner_info, sizeof(*ml_partner_info)); + for (i = 1; i < WLAN_MAX_ML_BSS_LINKS; i++) { + link_id = link_info[i].link_id; + for (j = 0; j < partner_info->num_partner_links; j++) { + if (partner_info->partner_link_info[j].link_id != + link_id) + continue; + + ml_partner_info->partner_link_info[partner_idx++] = + partner_info->partner_link_info[j]; + break; + } + } + ml_partner_info->num_partner_links = partner_idx; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +sir_convert_assoc_resp_frame2_mlo_struct(struct mac_context *mac, + uint8_t *frame, + uint32_t frame_len, + struct pe_session *session_entry, + tDot11fAssocResponse *ar, + tpSirAssocRsp p_assoc_rsp) +{ + uint8_t *ml_ie; + qdf_size_t ml_ie_total_len; + struct wlan_mlo_ie *ml_ie_info; + bool link_id_found; + uint8_t link_id; + bool eml_cap_found, msd_cap_found; + uint16_t eml_cap; + uint16_t msd_cap; + struct qdf_mac_addr mld_mac_addr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mlo_partner_info partner_info; + + if (!ar->mlo_ie.present) + return status; + + status = util_find_mlie(frame + WLAN_ASSOC_RSP_IES_OFFSET, + frame_len - WLAN_ASSOC_RSP_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + ml_ie_info = &p_assoc_rsp->mlo_ie.mlo_ie; + util_get_bvmlie_persta_partner_info(ml_ie, ml_ie_total_len, + &partner_info); + + sir_copy_assoc_rsp_partner_info_to_session(session_entry, + &partner_info); + + if (!wlan_cm_is_roam_sync_in_progress(mac->psoc, + session_entry->vdev_id)) { + session_entry->ml_partner_info.num_partner_links = + QDF_MIN( + session_entry->ml_partner_info.num_partner_links, + session_entry->lim_join_req->partner_info.num_partner_links); + } + util_get_bvmlie_mldmacaddr(ml_ie, ml_ie_total_len, + &mld_mac_addr); + qdf_mem_copy(ml_ie_info->mld_mac_addr, + mld_mac_addr.bytes, QDF_MAC_ADDR_SIZE); + + util_get_mlie_common_info_len(ml_ie, ml_ie_total_len, + &ml_ie_info->common_info_length); + + util_get_bvmlie_primary_linkid(ml_ie, ml_ie_total_len, + &link_id_found, &link_id); + util_get_bvmlie_msd_cap(ml_ie, ml_ie_total_len, + &msd_cap_found, &msd_cap); + if (msd_cap_found) { + ml_ie_info->medium_sync_delay_info_present = + msd_cap_found; + ml_ie_info->medium_sync_delay_info.medium_sync_duration = + QDF_GET_BITS( + msd_cap, + WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_DURATION_IDX, + WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_DURATION_BITS); + ml_ie_info->medium_sync_delay_info.medium_sync_ofdm_ed_thresh = + QDF_GET_BITS( + msd_cap, + WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_OFDMEDTHRESH_IDX, + WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_OFDMEDTHRESH_BITS); + ml_ie_info->medium_sync_delay_info.medium_sync_max_txop_num = + QDF_GET_BITS( + msd_cap, + WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_MAXTXOPS_IDX, + WLAN_ML_BV_CINFO_MEDMSYNCDELAYINFO_MAXTXOPS_BITS); + } + util_get_bvmlie_eml_cap(ml_ie, ml_ie_total_len, + &eml_cap_found, &eml_cap); + if (eml_cap_found) { + ml_ie_info->eml_capab_present = eml_cap_found; + ml_ie_info->eml_capabilities_info.emlsr_support = + QDF_GET_BITS(eml_cap, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRSUPPORT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRSUPPORT_BITS); + + ml_ie_info->eml_capabilities_info.transition_timeout = + QDF_GET_BITS(eml_cap, + WLAN_ML_BV_CINFO_EMLCAP_TRANSTIMEOUT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_TRANSTIMEOUT_BITS); + } + + ml_ie_info->num_sta_profile = + session_entry->ml_partner_info.num_partner_links; + ml_ie_info->link_id_info_present = link_id_found; + ml_ie_info->link_id = link_id; + + pe_debug("vdev:%d Partner link count: %d, Link id: %d, MLD mac addr: " QDF_MAC_ADDR_FMT, + session_entry->vdev_id, + ml_ie_info->num_sta_profile, ml_ie_info->link_id, + QDF_MAC_ADDR_REF(ml_ie_info->mld_mac_addr)); + + return status; +} + +static QDF_STATUS +sir_convert_assoc_resp_frame2_t2lm_struct(struct mac_context *mac, + uint8_t *frame, + uint32_t frame_len, + struct pe_session *session_entry, + tDot11fAssocResponse *ar, + tpSirAssocRsp p_assoc_rsp) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_t2lm_context *t2lm_ctx; + /* add 3 bytes for extn_ie_header */ + uint8_t ie[DOT11F_IE_T2LM_IE_MAX_LEN + 3]; + struct wlan_t2lm_info t2lm; + uint8_t i; + + t2lm_ctx = &p_assoc_rsp->t2lm_ctx; + qdf_mem_zero(&t2lm_ctx->established_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + qdf_mem_zero(&t2lm_ctx->upcoming_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + if (!ar->num_t2lm_ie) { + pe_debug("T2LM IEs not present"); + return status; + } + + pe_debug("Number of T2LM IEs in assoc resp %d", ar->num_t2lm_ie); + for (i = 0; i < ar->num_t2lm_ie; i++) { + qdf_mem_zero(&ie[0], DOT11F_IE_T2LM_IE_MAX_LEN + 3); + qdf_mem_zero(&t2lm, sizeof(struct wlan_t2lm_info)); + ie[ID_POS] = WLAN_ELEMID_EXTN_ELEM; + ie[TAG_LEN_POS] = ar->t2lm_ie[i].num_data + 1; + ie[IDEXT_POS] = WLAN_EXTN_ELEMID_T2LM; + qdf_mem_copy(&ie[3], &ar->t2lm_ie[i].data[0], + ar->t2lm_ie[i].num_data); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &ie[0], ar->t2lm_ie[i].num_data + 3); + + if (ie[TAG_LEN_POS] + 2 > DOT11F_IE_T2LM_IE_MAX_LEN + 3) { + pe_debug("Invalid T2LM IE length"); + return QDF_STATUS_E_PROTO; + } + + status = wlan_mlo_parse_t2lm_info(&ie[0], &t2lm); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Parse T2LM IE fail"); + return status; + } + + if (!t2lm.mapping_switch_time_present && + t2lm.expected_duration_present) { + qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm, + sizeof(struct wlan_t2lm_info)); + pe_debug("Parse established T2LM IE success"); + } else if (t2lm.mapping_switch_time_present) { + qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm, + sizeof(struct wlan_t2lm_info)); + pe_debug("Parse upcoming T2LM IE success"); + } + pe_debug("Parse T2LM IE success"); + } + return status; +} + +#else +static inline QDF_STATUS +sir_convert_assoc_resp_frame2_mlo_struct(struct mac_context *mac, + uint8_t *frame, + uint32_t frame_len, + struct pe_session *session_entry, + tDot11fAssocResponse *ar, + tpSirAssocRsp p_assoc_rsp) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +sir_convert_assoc_resp_frame2_t2lm_struct(struct mac_context *mac, + uint8_t *frame, + uint32_t frame_len, + struct pe_session *session_entry, + tDot11fAssocResponse *ar, + tpSirAssocRsp p_assoc_rsp) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef WLAN_FEATURE_SR +static void sir_convert_assoc_resp_frame2_sr(tpSirAssocRsp pAssocRsp, + tDot11fAssocResponse *ar) +{ + if (ar->spatial_reuse.present) + qdf_mem_copy(&pAssocRsp->srp_ie, &ar->spatial_reuse, + sizeof(tDot11fIEspatial_reuse)); +} +#else +static inline void sir_convert_assoc_resp_frame2_sr(tpSirAssocRsp pAssocRsp, + tDot11fAssocResponse *ar) +{ +} +#endif + +QDF_STATUS +sir_convert_assoc_resp_frame2_struct(struct mac_context *mac, + struct pe_session *session_entry, + uint8_t *frame, uint32_t frame_len, + tpSirAssocRsp pAssocRsp) +{ + tDot11fAssocResponse *ar; + enum ani_akm_type auth_type; + uint32_t status, ie_len; + QDF_STATUS qdf_status; + uint8_t cnt = 0; + bool sha384_akm; + uint8_t *ie_ptr; + uint16_t status_code; + + ar = qdf_mem_malloc(sizeof(*ar)); + if (!ar) + return QDF_STATUS_E_FAILURE; + + status_code = sir_read_u16(frame + + SIR_MAC_ASSOC_RSP_STATUS_CODE_OFFSET); + if (lim_is_fils_connection(session_entry) && status_code) + pe_debug("FILS: assoc reject Status code:%d", status_code); + + /* + * decrypt the cipher text using AEAD decryption, if association + * response status code is successful, else the don't do AEAD decryption + * since AP doesn't include FILS session IE when association reject is + * sent + */ + if (lim_is_fils_connection(session_entry) && !status_code) { + status = aead_decrypt_assoc_rsp(mac, session_entry, + ar, frame, &frame_len); + if (!QDF_IS_STATUS_SUCCESS(status)) { + pe_err("FILS assoc rsp AEAD decrypt fails"); + qdf_mem_free(ar); + return QDF_STATUS_E_FAILURE; + } + } + + status = dot11f_parse_assoc_response(mac, frame, frame_len, ar, false); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(ar); + return status; + } + + /* Capabilities */ + pAssocRsp->capabilityInfo.ess = ar->Capabilities.ess; + pAssocRsp->capabilityInfo.ibss = ar->Capabilities.ibss; + pAssocRsp->capabilityInfo.cfPollable = ar->Capabilities.cfPollable; + pAssocRsp->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq; + pAssocRsp->capabilityInfo.privacy = ar->Capabilities.privacy; + pAssocRsp->capabilityInfo.shortPreamble = + ar->Capabilities.shortPreamble; + pAssocRsp->capabilityInfo.criticalUpdateFlag = + ar->Capabilities.criticalUpdateFlag; + pAssocRsp->capabilityInfo.channelAgility = + ar->Capabilities.channelAgility; + pAssocRsp->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt; + pAssocRsp->capabilityInfo.qos = ar->Capabilities.qos; + pAssocRsp->capabilityInfo.shortSlotTime = + ar->Capabilities.shortSlotTime; + pAssocRsp->capabilityInfo.apsd = ar->Capabilities.apsd; + pAssocRsp->capabilityInfo.rrm = ar->Capabilities.rrm; + pAssocRsp->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm; + pAssocRsp->capabilityInfo.delayedBA = ar->Capabilities.delayedBA; + pAssocRsp->capabilityInfo.immediateBA = ar->Capabilities.immediateBA; + + pAssocRsp->status_code = ar->Status.status; + pAssocRsp->aid = ar->AID.associd; + + if (ar->TimeoutInterval.present) { + pAssocRsp->TimeoutInterval.present = 1; + pAssocRsp->TimeoutInterval.timeoutType = + ar->TimeoutInterval.timeoutType; + pAssocRsp->TimeoutInterval.timeoutValue = + ar->TimeoutInterval.timeoutValue; + } + + if (!ar->SuppRates.present) { + pAssocRsp->suppRatesPresent = 0; + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pAssocRsp->suppRatesPresent = 1; + convert_supp_rates(mac, &pAssocRsp->supportedRates, + &ar->SuppRates); + } + + if (ar->ExtSuppRates.present) { + pAssocRsp->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pAssocRsp->extendedRates, + &ar->ExtSuppRates); + } + + if (ar->EDCAParamSet.present) { + pAssocRsp->edcaPresent = 1; + convert_edca_param(mac, &pAssocRsp->edca, &ar->EDCAParamSet); + } + if (ar->WMMParams.present) { + pAssocRsp->wmeEdcaPresent = 1; + convert_wmm_params(mac, &pAssocRsp->edca, &ar->WMMParams); + } + + if (ar->HTCaps.present) + qdf_mem_copy(&pAssocRsp->HTCaps, &ar->HTCaps, + sizeof(tDot11fIEHTCaps)); + + if (ar->HTInfo.present) + qdf_mem_copy(&pAssocRsp->HTInfo, &ar->HTInfo, + sizeof(tDot11fIEHTInfo)); + + if (ar->RRMEnabledCap.present) { + qdf_mem_copy(&pAssocRsp->rrm_caps, &ar->RRMEnabledCap, + sizeof(tDot11fIERRMEnabledCap)); + } + if (ar->MobilityDomain.present) { + /* MobilityDomain */ + pAssocRsp->mdiePresent = 1; + qdf_mem_copy((uint8_t *) &(pAssocRsp->mdie[0]), + (uint8_t *) &(ar->MobilityDomain.MDID), + sizeof(uint16_t)); + pAssocRsp->mdie[2] = ((ar->MobilityDomain.overDSCap << 0) | + (ar->MobilityDomain.resourceReqCap << 1)); + pe_debug("new mdie=%02x%02x%02x", + (unsigned int)pAssocRsp->mdie[0], + (unsigned int)pAssocRsp->mdie[1], + (unsigned int)pAssocRsp->mdie[2]); + } + + /* + * If the connection is based on SHA384 AKM suite, + * then the length of MIC is 24 bytes, but frame parser + * has FTIE MIC of 16 bytes only. This results in parsing FTIE + * failure and R0KH and R1KH are not sent to firmware over RSO + * command. Frame parser doesn't have + * info on the connected AKM. So parse the FTIE again if + * AKM is sha384 based and extract the R0KH and R1KH using the new + * parsing logic. + */ + auth_type = session_entry->connected_akm; + sha384_akm = lim_is_sha384_akm(auth_type); + ie_ptr = frame + FIXED_PARAM_OFFSET_ASSOC_RSP; + ie_len = frame_len - FIXED_PARAM_OFFSET_ASSOC_RSP; + if (sha384_akm) { + qdf_status = wlan_parse_ftie_sha384(ie_ptr, ie_len, pAssocRsp); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + pe_err("FT IE parsing failed status:%d", status); + } else { + pe_debug("FT: R0KH present:%d len:%d R1KH present%d", + pAssocRsp->sha384_ft_subelem.r0kh_id.present, + pAssocRsp->sha384_ft_subelem.r0kh_id.num_PMK_R0_ID, + pAssocRsp->sha384_ft_subelem.r1kh_id.present); + ar->FTInfo.present = false; + } + } else if (ar->FTInfo.present) { + pe_debug("FT: R0KH present:%d, len:%d R1KH present:%d", + ar->FTInfo.R0KH_ID.present, + ar->FTInfo.R0KH_ID.num_PMK_R0_ID, + ar->FTInfo.R1KH_ID.present); + pAssocRsp->ftinfoPresent = 1; + qdf_mem_copy(&pAssocRsp->FTInfo, &ar->FTInfo, + sizeof(tDot11fIEFTInfo)); + } + + if (ar->num_RICDataDesc && ar->num_RICDataDesc <= 2) { + for (cnt = 0; cnt < ar->num_RICDataDesc; cnt++) { + if (ar->RICDataDesc[cnt].present) { + qdf_mem_copy(&pAssocRsp->RICData[cnt], + &ar->RICDataDesc[cnt], + sizeof(tDot11fIERICDataDesc)); + } + } + pAssocRsp->num_RICData = ar->num_RICDataDesc; + pAssocRsp->ricPresent = true; + } + +#ifdef FEATURE_WLAN_ESE + if (ar->num_WMMTSPEC) { + pAssocRsp->num_tspecs = ar->num_WMMTSPEC; + for (cnt = 0; cnt < ar->num_WMMTSPEC; cnt++) { + qdf_mem_copy(&pAssocRsp->TSPECInfo[cnt], + &ar->WMMTSPEC[cnt], + sizeof(tDot11fIEWMMTSPEC)); + } + pAssocRsp->tspecPresent = true; + } + + if (ar->ESETrafStrmMet.present) { + pAssocRsp->tsmPresent = 1; + qdf_mem_copy(&pAssocRsp->tsmIE.tsid, + &ar->ESETrafStrmMet.tsid, + sizeof(struct ese_tsm_ie)); + } +#endif + if (ar->bss_max_idle_period.present) + qdf_mem_copy(&pAssocRsp->bss_max_idle_period, + &ar->bss_max_idle_period, + sizeof(tDot11fIEbss_max_idle_period)); + + if (ar->VHTCaps.present) { + qdf_mem_copy(&pAssocRsp->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log_vht_cap(mac, &pAssocRsp->VHTCaps); + } + if (ar->VHTOperation.present) { + qdf_mem_copy(&pAssocRsp->VHTOperation, &ar->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + lim_log_vht_operation(mac, &pAssocRsp->VHTOperation); + } + + if (ar->ExtCap.present) { + struct s_ext_cap *ext_cap; + + qdf_mem_copy(&pAssocRsp->ExtCap, &ar->ExtCap, + sizeof(tDot11fIEExtCap)); + ext_cap = (struct s_ext_cap *)&pAssocRsp->ExtCap.bytes; + pe_debug("timingMeas: %d, finetimingMeas Init: %d, Resp: %d", + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + + if (ar->OperatingMode.present) { + qdf_mem_copy(&pAssocRsp->oper_mode_ntf, &ar->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } + + if (ar->QosMapSet.present) { + pAssocRsp->QosMapSet.present = 1; + convert_qos_mapset_frame(mac, &pAssocRsp->QosMapSet, + &ar->QosMapSet); + lim_log_qos_map_set(mac, &pAssocRsp->QosMapSet); + } + + pAssocRsp->vendor_vht_ie.present = ar->vendor_vht_ie.present; + if (ar->vendor_vht_ie.present) + pAssocRsp->vendor_vht_ie.sub_type = ar->vendor_vht_ie.sub_type; + if (ar->OBSSScanParameters.present) { + qdf_mem_copy(&pAssocRsp->obss_scanparams, + &ar->OBSSScanParameters, + sizeof(struct sDot11fIEOBSSScanParameters)); + } + if (ar->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTCaps, + &ar->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + lim_log_vht_cap(mac, &pAssocRsp->VHTCaps); + } + if (ar->vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pAssocRsp->vendor_vht_ie.VHTOperation, + &ar->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + lim_log_vht_operation(mac, &pAssocRsp->VHTOperation); + } + + if (ar->qcn_ie.present) + qdf_mem_copy(&pAssocRsp->qcn_ie, &ar->qcn_ie, + sizeof(tDot11fIEqcn_ie)); + if (ar->he_cap.present) { + qdf_mem_copy(&pAssocRsp->he_cap, &ar->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (ar->he_op.present) + qdf_mem_copy(&pAssocRsp->he_op, &ar->he_op, + sizeof(tDot11fIEhe_op)); + + sir_convert_assoc_resp_frame2_sr(pAssocRsp, ar); + + if (ar->he_6ghz_band_cap.present) + qdf_mem_copy(&pAssocRsp->he_6ghz_band_cap, + &ar->he_6ghz_band_cap, + sizeof(tDot11fIEhe_6ghz_band_cap)); + + if (ar->mu_edca_param_set.present) { + pAssocRsp->mu_edca_present = true; + convert_mu_edca_param(mac, &pAssocRsp->mu_edca, + &ar->mu_edca_param_set); + } + + if (ar->MBO_IE.present && ar->MBO_IE.rssi_assoc_rej.present) + qdf_mem_copy(&pAssocRsp->rssi_assoc_rej, + &ar->MBO_IE.rssi_assoc_rej, + sizeof(tDot11fTLVrssi_assoc_rej)); + + sir_convert_assoc_resp_frame2_eht_struct(ar, pAssocRsp); + fils_convert_assoc_rsp_frame2_struct(ar, pAssocRsp); + sir_convert_assoc_resp_frame2_mlo_struct(mac, frame, frame_len, + session_entry, ar, pAssocRsp); + sir_convert_assoc_resp_frame2_t2lm_struct(mac, frame, frame_len, + session_entry, ar, pAssocRsp); + pe_debug("ht %d vht %d vendor vht: cap %d op %d, he %d he 6ghband %d eht %d eht320 %d, max idle: present %d val %d, he mu edca %d wmm %d qos %d mlo %d", + ar->HTCaps.present, ar->VHTCaps.present, + ar->vendor_vht_ie.VHTCaps.present, + ar->vendor_vht_ie.VHTOperation.present, ar->he_cap.present, + ar->he_6ghz_band_cap.present, ar->eht_cap.present, + pAssocRsp->eht_cap.support_320mhz_6ghz, + ar->bss_max_idle_period.present, + pAssocRsp->bss_max_idle_period.max_idle_period, + ar->mu_edca_param_set.present, ar->WMMParams.present, + ar->QosMapSet.present, + ar->mlo_ie.present); + + if (ar->WMMParams.present) + __print_wmm_params(mac, &ar->WMMParams); + + qdf_mem_free(ar); + return QDF_STATUS_SUCCESS; +} /* End sir_convert_assoc_resp_frame2_struct. */ + +#ifdef WLAN_FEATURE_11BE +static void +sir_convert_reassoc_req_frame2_eht_struct(tDot11fReAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ + if (ar->eht_cap.present) { + qdf_mem_copy(&p_assoc_req->eht_cap, &ar->eht_cap, + sizeof(tDot11fIEeht_cap)); + pe_debug("Received Assoc Req with EHT Capability IE"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &p_assoc_req->eht_cap, + sizeof(tDot11fIEeht_cap)); + } +} +#else +static inline void +sir_convert_reassoc_req_frame2_eht_struct(tDot11fReAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_convert_reassoc_req_frame2_mlo_struct(uint8_t *pframe, uint32_t nframe, + tDot11fReAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ + uint8_t *ml_ie; + qdf_size_t ml_ie_total_len; + struct qdf_mac_addr mld_mac_addr; + uint32_t status = QDF_STATUS_SUCCESS; + + if (ar->mlo_ie.present) { + status = util_find_mlie(pframe + WLAN_REASSOC_REQ_IES_OFFSET, + nframe - WLAN_ASSOC_REQ_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_SUCCESS(status)) { + util_get_bvmlie_persta_partner_info(ml_ie, + ml_ie_total_len, + &p_assoc_req->mlo_info); + + util_get_bvmlie_mldmacaddr(ml_ie, ml_ie_total_len, + &mld_mac_addr); + qdf_mem_copy(p_assoc_req->mld_mac, mld_mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + } else { + pe_debug("Do not find ml ie"); + } + } + return status; +} +#else +static QDF_STATUS +sir_convert_reassoc_req_frame2_mlo_struct(uint8_t *pframe, uint32_t nframe, + tDot11fReAssocRequest *ar, + tpSirAssocReq p_assoc_req) +{ + return QDF_STATUS_SUCCESS; +} +#endif +enum wlan_status_code +sir_convert_reassoc_req_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, tpSirAssocReq pAssocReq) +{ + tDot11fReAssocRequest *ar; + uint32_t status; + + ar = qdf_mem_malloc(sizeof(*ar)); + if (!ar) + return STATUS_UNSPECIFIED_FAILURE; + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_re_assoc_request(mac, pFrame, nFrame, + ar, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse a Re-association Request (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + qdf_mem_free(ar); + return STATUS_UNSPECIFIED_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking a Re-association Request (0x%08x, %d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fReAssocRequest' to a 'tSirAssocReq'... */ + + /* make sure this is seen as a re-assoc request */ + pAssocReq->reassocRequest = 1; + + /* Capabilities */ + pAssocReq->capabilityInfo.ess = ar->Capabilities.ess; + pAssocReq->capabilityInfo.ibss = ar->Capabilities.ibss; + pAssocReq->capabilityInfo.cfPollable = ar->Capabilities.cfPollable; + pAssocReq->capabilityInfo.cfPollReq = ar->Capabilities.cfPollReq; + pAssocReq->capabilityInfo.privacy = ar->Capabilities.privacy; + pAssocReq->capabilityInfo.shortPreamble = ar->Capabilities.shortPreamble; + pAssocReq->capabilityInfo.criticalUpdateFlag = + ar->Capabilities.criticalUpdateFlag; + pAssocReq->capabilityInfo.channelAgility = + ar->Capabilities.channelAgility; + pAssocReq->capabilityInfo.spectrumMgt = ar->Capabilities.spectrumMgt; + pAssocReq->capabilityInfo.qos = ar->Capabilities.qos; + pAssocReq->capabilityInfo.shortSlotTime = ar->Capabilities.shortSlotTime; + pAssocReq->capabilityInfo.apsd = ar->Capabilities.apsd; + pAssocReq->capabilityInfo.rrm = ar->Capabilities.rrm; + pAssocReq->capabilityInfo.dsssOfdm = ar->Capabilities.dsssOfdm; + pAssocReq->capabilityInfo.delayedBA = ar->Capabilities.delayedBA; + pAssocReq->capabilityInfo.immediateBA = ar->Capabilities.immediateBA; + + /* Listen Interval */ + pAssocReq->listenInterval = ar->ListenInterval.interval; + + /* SSID */ + if (ar->SSID.present) { + pAssocReq->ssidPresent = 1; + convert_ssid(mac, &pAssocReq->ssId, &ar->SSID); + } + /* Supported Rates */ + if (ar->SuppRates.present) { + pAssocReq->suppRatesPresent = 1; + convert_supp_rates(mac, &pAssocReq->supportedRates, + &ar->SuppRates); + } + /* Extended Supported Rates */ + if (ar->ExtSuppRates.present) { + pAssocReq->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pAssocReq->extendedRates, + &ar->ExtSuppRates); + } + /* QOS Capabilities: */ + if (ar->QOSCapsStation.present) { + pAssocReq->qosCapabilityPresent = 1; + convert_qos_caps_station(mac, &pAssocReq->qosCapability, + &ar->QOSCapsStation); + } + /* WPA */ + if (ar->WPAOpaque.present) { + pAssocReq->wpaPresent = 1; + convert_wpa_opaque(mac, &pAssocReq->wpa, &ar->WPAOpaque); + } + /* RSN */ + if (ar->RSNOpaque.present) { + pAssocReq->rsnPresent = 1; + convert_rsn_opaque(mac, &pAssocReq->rsn, &ar->RSNOpaque); + } + + /* Power Capabilities */ + if (ar->PowerCaps.present) { + pAssocReq->powerCapabilityPresent = 1; + convert_power_caps(mac, &pAssocReq->powerCapability, + &ar->PowerCaps); + } + /* Supported Channels */ + if (ar->SuppChannels.present) { + pAssocReq->supportedChannelsPresent = 1; + convert_supp_channels(mac, &pAssocReq->supportedChannels, + &ar->SuppChannels); + } + + if (ar->HTCaps.present) { + qdf_mem_copy(&pAssocReq->HTCaps, &ar->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (ar->WMMInfoStation.present) { + pAssocReq->wmeInfoPresent = 1; + qdf_mem_copy(&pAssocReq->WMMInfoStation, &ar->WMMInfoStation, + sizeof(tDot11fIEWMMInfoStation)); + + } + + if (ar->WMMCaps.present) + pAssocReq->wsmCapablePresent = 1; + + if (!pAssocReq->ssidPresent) { + pe_debug("Received Assoc without SSID IE"); + qdf_mem_free(ar); + return STATUS_UNSPECIFIED_FAILURE; + } + + if (!pAssocReq->suppRatesPresent && !pAssocReq->extendedRatesPresent) { + pe_debug("Received Assoc without supp rate IE"); + qdf_mem_free(ar); + return STATUS_ASSOC_DENIED_RATES; + } + /* Why no call to 'updateAssocReqFromPropCapability' here, like */ + /* there is in 'sir_convert_assoc_req_frame2_struct'? */ + + /* WSC IE */ + if (ar->WscIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wsc_opaque(mac, &pAssocReq->addIE, &ar->WscIEOpaque); + } + + if (ar->P2PIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_p2p_opaque(mac, &pAssocReq->addIE, &ar->P2PIEOpaque); + } +#ifdef WLAN_FEATURE_WFD + if (ar->WFDIEOpaque.present) { + pAssocReq->addIEPresent = 1; + convert_wfd_opaque(mac, &pAssocReq->addIE, &ar->WFDIEOpaque); + } +#endif + if (ar->SuppOperatingClasses.present) { + uint8_t num_classes = ar->SuppOperatingClasses.num_classes; + + if (num_classes > sizeof(ar->SuppOperatingClasses.classes)) + num_classes = + sizeof(ar->SuppOperatingClasses.classes); + qdf_mem_copy(&pAssocReq->supp_operating_classes, + &ar->SuppOperatingClasses, + sizeof(tDot11fIESuppOperatingClasses)); + QDF_TRACE_HEX_DUMP( + QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + ar->SuppOperatingClasses.classes, num_classes); + } + if (ar->VHTCaps.present) { + qdf_mem_copy(&pAssocReq->VHTCaps, &ar->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (ar->OperatingMode.present) { + qdf_mem_copy(&pAssocReq->operMode, &ar->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + pe_warn("Received Assoc Req with Operating Mode IE"); + lim_log_operating_mode(mac, &pAssocReq->operMode); + } + if (ar->ExtCap.present) { + struct s_ext_cap *ext_cap; + + qdf_mem_copy(&pAssocReq->ExtCap, &ar->ExtCap, + sizeof(tDot11fIEExtCap)); + ext_cap = (struct s_ext_cap *)&pAssocReq->ExtCap.bytes; + pe_debug("timingMeas: %d, finetimingMeas Init: %d, Resp: %d", + ext_cap->timing_meas, ext_cap->fine_time_meas_initiator, + ext_cap->fine_time_meas_responder); + } + if (ar->he_cap.present) { + qdf_mem_copy(&pAssocReq->he_cap, &ar->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (ar->he_6ghz_band_cap.present) { + qdf_mem_copy(&pAssocReq->he_6ghz_band_cap, + &ar->he_6ghz_band_cap, + sizeof(tDot11fIEhe_6ghz_band_cap)); + } + + sir_convert_reassoc_req_frame2_eht_struct(ar, pAssocReq); + sir_convert_reassoc_req_frame2_mlo_struct(pFrame, nFrame, + ar, pAssocReq); + pe_debug("ht %d vht %d opmode %d vendor vht %d he %d he 6ghband %d eht %d", + ar->HTCaps.present, ar->VHTCaps.present, + ar->OperatingMode.present, ar->vendor_vht_ie.VHTCaps.present, + ar->he_cap.present, ar->he_6ghz_band_cap.present, + ar->eht_cap.present); + qdf_mem_free(ar); + + return STATUS_SUCCESS; + +} /* End sir_convert_reassoc_req_frame2_struct. */ + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS +sir_beacon_ie_ese_bcn_report(struct mac_context *mac, + uint8_t *pPayload, const uint32_t nPayload, + uint8_t **outIeBuf, uint32_t *pOutIeLen) +{ + tDot11fBeaconIEs *pBies = NULL; + uint32_t status = QDF_STATUS_SUCCESS; + QDF_STATUS retStatus = QDF_STATUS_SUCCESS; + tSirEseBcnReportMandatoryIe eseBcnReportMandatoryIe; + + /* To store how many bytes are required to be allocated + for Bcn report mandatory Ies */ + uint16_t numBytes = 0, freeBytes = 0; + uint8_t *pos = NULL; + uint32_t freq; + + freq = WMA_GET_RX_FREQ(pPayload); + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) &eseBcnReportMandatoryIe, + sizeof(eseBcnReportMandatoryIe)); + pBies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (!pBies) + return QDF_STATUS_E_NOMEM; + qdf_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(mac, pPayload, nPayload, + pBies, false); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse Beacon IEs (0x%08x, %d bytes):", + status, nPayload); + qdf_mem_free(pBies); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking Beacon IEs (0x%08x, %d bytes):", + status, nPayload); + } + + status = lim_strip_and_decode_eht_op(pPayload + WLAN_BEACON_IES_OFFSET, + nPayload - WLAN_BEACON_IES_OFFSET, + &pBies->eht_op, + pBies->VHTOperation, + pBies->he_op, + pBies->HTInfo); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + qdf_mem_free(pBies); + return status; + } + + status = lim_strip_and_decode_eht_cap(pPayload + WLAN_BEACON_IES_OFFSET, + nPayload - WLAN_BEACON_IES_OFFSET, + &pBies->eht_cap, + pBies->he_cap, + freq); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + qdf_mem_free(pBies); + return status; + } + + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'eseBcnReportMandatoryIe'... */ + if (!pBies->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + eseBcnReportMandatoryIe.ssidPresent = 1; + convert_ssid(mac, &eseBcnReportMandatoryIe.ssId, &pBies->SSID); + /* 1 for EID, 1 for length and length bytes */ + numBytes += 1 + 1 + eseBcnReportMandatoryIe.ssId.length; + } + + if (!pBies->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + eseBcnReportMandatoryIe.suppRatesPresent = 1; + convert_supp_rates(mac, &eseBcnReportMandatoryIe.supportedRates, + &pBies->SuppRates); + numBytes += + 1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates; + } + + if (pBies->FHParamSet.present) { + eseBcnReportMandatoryIe.fhParamPresent = 1; + convert_fh_params(mac, &eseBcnReportMandatoryIe.fhParamSet, + &pBies->FHParamSet); + numBytes += 1 + 1 + WLAN_FH_PARAM_IE_MAX_LEN; + } + + if (pBies->DSParams.present) { + eseBcnReportMandatoryIe.dsParamsPresent = 1; + eseBcnReportMandatoryIe.dsParamSet.channelNumber = + pBies->DSParams.curr_channel; + numBytes += 1 + 1 + WLAN_DS_PARAM_IE_MAX_LEN; + } + + if (pBies->CFParams.present) { + eseBcnReportMandatoryIe.cfPresent = 1; + convert_cf_params(mac, &eseBcnReportMandatoryIe.cfParamSet, + &pBies->CFParams); + numBytes += 1 + 1 + WLAN_CF_PARAM_IE_MAX_LEN; + } + + if (pBies->TIM.present) { + eseBcnReportMandatoryIe.timPresent = 1; + eseBcnReportMandatoryIe.tim.dtimCount = pBies->TIM.dtim_count; + eseBcnReportMandatoryIe.tim.dtimPeriod = pBies->TIM.dtim_period; + eseBcnReportMandatoryIe.tim.bitmapControl = pBies->TIM.bmpctl; + /* As per the ESE spec, May truncate and report first 4 octets only */ + numBytes += 1 + 1 + SIR_MAC_TIM_EID_MIN; + } + + if (pBies->RRMEnabledCap.present) { + eseBcnReportMandatoryIe.rrmPresent = 1; + qdf_mem_copy(&eseBcnReportMandatoryIe.rmEnabledCapabilities, + &pBies->RRMEnabledCap, + sizeof(tDot11fIERRMEnabledCap)); + numBytes += 1 + 1 + WLAN_RM_CAPABILITY_IE_MAX_LEN; + } + + *outIeBuf = qdf_mem_malloc(numBytes); + if (!*outIeBuf) { + qdf_mem_free(pBies); + return QDF_STATUS_E_NOMEM; + } + pos = *outIeBuf; + *pOutIeLen = numBytes; + freeBytes = numBytes; + + /* Start filling the output Ie with Mandatory IE information */ + /* Fill SSID IE */ + if (eseBcnReportMandatoryIe.ssidPresent) { + if (freeBytes < (1 + 1 + eseBcnReportMandatoryIe.ssId.length)) { + pe_err("Insufficient memory to copy SSID"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = WLAN_ELEMID_SSID; + pos++; + *pos = eseBcnReportMandatoryIe.ssId.length; + pos++; + qdf_mem_copy(pos, + (uint8_t *) eseBcnReportMandatoryIe.ssId.ssId, + eseBcnReportMandatoryIe.ssId.length); + pos += eseBcnReportMandatoryIe.ssId.length; + freeBytes -= (1 + 1 + eseBcnReportMandatoryIe.ssId.length); + } + + /* Fill Supported Rates IE */ + if (eseBcnReportMandatoryIe.suppRatesPresent) { + if (freeBytes < + (1 + 1 + eseBcnReportMandatoryIe.supportedRates.numRates)) { + pe_err("Insufficient memory to copy Rates IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + if (eseBcnReportMandatoryIe.supportedRates.numRates <= + WLAN_SUPPORTED_RATES_IE_MAX_LEN) { + *pos = WLAN_ELEMID_RATES; + pos++; + *pos = eseBcnReportMandatoryIe.supportedRates.numRates; + pos++; + qdf_mem_copy(pos, + (uint8_t *) eseBcnReportMandatoryIe.supportedRates. + rate, + eseBcnReportMandatoryIe.supportedRates.numRates); + pos += eseBcnReportMandatoryIe.supportedRates.numRates; + freeBytes -= + (1 + 1 + + eseBcnReportMandatoryIe.supportedRates.numRates); + } + } + + /* Fill FH Parameter set IE */ + if (eseBcnReportMandatoryIe.fhParamPresent) { + if (freeBytes < (1 + 1 + WLAN_FH_PARAM_IE_MAX_LEN)) { + pe_err("Insufficient memory to copy FHIE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = WLAN_ELEMID_FHPARMS; + pos++; + *pos = WLAN_FH_PARAM_IE_MAX_LEN; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.fhParamSet, + WLAN_FH_PARAM_IE_MAX_LEN); + pos += WLAN_FH_PARAM_IE_MAX_LEN; + freeBytes -= (1 + 1 + WLAN_FH_PARAM_IE_MAX_LEN); + } + + /* Fill DS Parameter set IE */ + if (eseBcnReportMandatoryIe.dsParamsPresent) { + if (freeBytes < (1 + 1 + WLAN_DS_PARAM_IE_MAX_LEN)) { + pe_err("Insufficient memory to copy DS IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = WLAN_ELEMID_DSPARMS; + pos++; + *pos = WLAN_DS_PARAM_IE_MAX_LEN; + pos++; + *pos = eseBcnReportMandatoryIe.dsParamSet.channelNumber; + pos += WLAN_DS_PARAM_IE_MAX_LEN; + freeBytes -= (1 + 1 + WLAN_DS_PARAM_IE_MAX_LEN); + } + + /* Fill CF Parameter set */ + if (eseBcnReportMandatoryIe.cfPresent) { + if (freeBytes < (1 + 1 + WLAN_CF_PARAM_IE_MAX_LEN)) { + pe_err("Insufficient memory to copy CF IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = WLAN_ELEMID_CFPARMS; + pos++; + *pos = WLAN_CF_PARAM_IE_MAX_LEN; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.cfParamSet, + WLAN_CF_PARAM_IE_MAX_LEN); + pos += WLAN_CF_PARAM_IE_MAX_LEN; + freeBytes -= (1 + 1 + WLAN_CF_PARAM_IE_MAX_LEN); + } + + /* Fill TIM IE */ + if (eseBcnReportMandatoryIe.timPresent) { + if (freeBytes < (1 + 1 + SIR_MAC_TIM_EID_MIN)) { + pe_err("Insufficient memory to copy TIM IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = WLAN_ELEMID_TIM; + pos++; + *pos = SIR_MAC_TIM_EID_MIN; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe.tim, + SIR_MAC_TIM_EID_MIN); + pos += SIR_MAC_TIM_EID_MIN; + freeBytes -= (1 + 1 + SIR_MAC_TIM_EID_MIN); + } + + /* Fill RM Capability IE */ + if (eseBcnReportMandatoryIe.rrmPresent) { + if (freeBytes < (1 + 1 + WLAN_RM_CAPABILITY_IE_MAX_LEN)) { + pe_err("Insufficient memory to copy RRM IE"); + retStatus = QDF_STATUS_E_FAILURE; + goto err_bcnrep; + } + *pos = WLAN_ELEMID_RRM; + pos++; + *pos = WLAN_RM_CAPABILITY_IE_MAX_LEN; + pos++; + qdf_mem_copy(pos, + (uint8_t *) &eseBcnReportMandatoryIe. + rmEnabledCapabilities, + WLAN_RM_CAPABILITY_IE_MAX_LEN); + freeBytes -= (1 + 1 + WLAN_RM_CAPABILITY_IE_MAX_LEN); + } + + if (freeBytes != 0) { + pe_err("Mismatch in allocation and copying of IE in Bcn Rep"); + retStatus = QDF_STATUS_E_FAILURE; + } + +err_bcnrep: + /* The message counter would not be incremented in case of + * returning failure and hence next time, this function gets + * called, it would be using the same msg ctr for a different + * BSS.So, it is good to clear the memory allocated for a BSS + * that is returning failure.On success, the caller would take + * care of freeing up the memory*/ + if (retStatus == QDF_STATUS_E_FAILURE) { + qdf_mem_free(*outIeBuf); + *outIeBuf = NULL; + } + + qdf_mem_free(pBies); + return retStatus; +} + +#endif /* FEATURE_WLAN_ESE */ + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void update_bss_color_change_from_beacon_ies(tDot11fBeaconIEs *bcn_ies, + tpSirProbeRespBeacon bcn_struct) +{ + if (bcn_ies->bss_color_change.present) { + qdf_mem_copy(&bcn_struct->vendor_he_bss_color_change, + &bcn_ies->bss_color_change, + sizeof(tDot11fIEbss_color_change)); + } +} +#else +static inline void update_bss_color_change_from_beacon_ies( + tDot11fBeaconIEs *bcn_ies, + tpSirProbeRespBeacon bcn_struct) +{} +#endif + +QDF_STATUS +sir_parse_beacon_ie(struct mac_context *mac, + tpSirProbeRespBeacon pBeaconStruct, + uint8_t *pPayload, uint32_t nPayload) +{ + tDot11fBeaconIEs *pBies; + uint32_t status; + uint32_t freq; + + freq = WMA_GET_RX_FREQ(pPayload); + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon)); + + pBies = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (!pBies) + return QDF_STATUS_E_NOMEM; + qdf_mem_zero(pBies, sizeof(tDot11fBeaconIEs)); + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon_i_es(mac, pPayload, nPayload, + pBies, false); + + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse Beacon IEs (0x%08x, %d bytes):", + status, nPayload); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pPayload, nPayload); + qdf_mem_free(pBies); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("warnings (0x%08x, %d bytes):", status, nPayload); + } + + status = lim_strip_and_decode_eht_op(pPayload, + nPayload, + &pBies->eht_op, + pBies->VHTOperation, + pBies->he_op, + pBies->HTInfo); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + qdf_mem_free(pBies); + return QDF_STATUS_E_FAILURE; + } + + status = lim_strip_and_decode_eht_cap(pPayload, + nPayload, + &pBies->eht_cap, + pBies->he_cap, + freq); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + qdf_mem_free(pBies); + return QDF_STATUS_E_FAILURE; + } + + /* & "transliterate" from a 'tDot11fBeaconIEs' to a 'tSirProbeRespBeacon'... */ + if (!pBies->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(mac, &pBeaconStruct->ssId, &pBies->SSID); + } + + if (!pBies->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(mac, &pBeaconStruct->supportedRates, + &pBies->SuppRates); + } + + if (pBies->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pBeaconStruct->extendedRates, + &pBies->ExtSuppRates); + } + + if (pBies->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(mac, &pBeaconStruct->cfParamSet, + &pBies->CFParams); + } + + if (pBies->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(mac, &pBeaconStruct->tim, &pBies->TIM); + } + + if (pBies->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(mac, &pBeaconStruct->countryInfoParam, + &pBies->Country); + } + /* 11h IEs */ + if (pBies->TPCReport.present) { + pBeaconStruct->tpcReportPresent = 1; + qdf_mem_copy(&pBeaconStruct->tpcReport, + &pBies->TPCReport, sizeof(tDot11fIETPCReport)); + } + + if (pBies->PowerConstraints.present) { + pBeaconStruct->powerConstraintPresent = 1; + qdf_mem_copy(&pBeaconStruct->localPowerConstraint, + &pBies->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } +#ifdef FEATURE_WLAN_ESE + if (pBies->ESEVersion.present) + pBeaconStruct->is_ese_ver_ie_present = 1; + if (pBies->ESETxmitPower.present) { + pBeaconStruct->eseTxPwr.present = 1; + pBeaconStruct->eseTxPwr.power_limit = + pBies->ESETxmitPower.power_limit; + } + if (pBies->QBSSLoad.present) { + qdf_mem_copy(&pBeaconStruct->QBSSLoad, &pBies->QBSSLoad, + sizeof(tDot11fIEQBSSLoad)); + } +#endif + + if (pBies->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(mac, &pBeaconStruct->edcaParams, + &pBies->EDCAParamSet); + } + /* QOS Capabilities: */ + if (pBies->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(mac, &pBeaconStruct->qosCapability, + &pBies->QOSCapsAp); + } + + if (pBies->ChanSwitchAnn.present) { + pBeaconStruct->channelSwitchPresent = 1; + qdf_mem_copy(&pBeaconStruct->channelSwitchIE, + &pBies->ChanSwitchAnn, + sizeof(pBeaconStruct->channelSwitchIE)); + } + + if (pBies->SuppOperatingClasses.present) { + pBeaconStruct->supp_operating_class_present = 1; + qdf_mem_copy(&pBeaconStruct->supp_operating_classes, + &pBies->SuppOperatingClasses, + sizeof(tDot11fIESuppOperatingClasses)); + } + + if (pBies->ext_chan_switch_ann.present) { + pBeaconStruct->ext_chan_switch_present = 1; + qdf_mem_copy(&pBeaconStruct->ext_chan_switch, + &pBies->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pBies->sec_chan_offset_ele.present) { + pBeaconStruct->sec_chan_offset_present = 1; + qdf_mem_copy(&pBeaconStruct->sec_chan_offset, + &pBies->sec_chan_offset_ele, + sizeof(pBeaconStruct->sec_chan_offset)); + } + + if (pBies->Quiet.present) { + pBeaconStruct->quietIEPresent = 1; + qdf_mem_copy(&pBeaconStruct->quietIE, &pBies->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pBies->HTCaps.present) { + qdf_mem_copy(&pBeaconStruct->HTCaps, &pBies->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pBies->HTInfo.present) { + qdf_mem_copy(&pBeaconStruct->HTInfo, &pBies->HTInfo, + sizeof(tDot11fIEHTInfo)); + } + + if (pBies->he_op.oper_info_6g_present) { + pBeaconStruct->chan_freq = wlan_reg_chan_band_to_freq(mac->pdev, + pBies->he_op.oper_info_6g.info.primary_ch, + BIT(REG_BAND_6G)); + } else if (pBies->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, + pBies->DSParams.curr_channel); + } else if (pBies->HTInfo.present) { + pBeaconStruct->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, + pBies->HTInfo.primaryChannel); + } + + if (pBies->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(mac, &pBeaconStruct->rsn, &pBies->RSN); + } + + if (pBies->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(mac, &pBeaconStruct->wpa, &pBies->WPA); + } + + if (pBies->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(mac, &pBeaconStruct->edcaParams, + &pBies->WMMParams); + qdf_mem_copy(&pBeaconStruct->wmm_params, &pBies->WMMParams, + sizeof(tDot11fIEWMMParams)); + } + + if (pBies->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + } + + if (pBies->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBies->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(mac, &pBeaconStruct->erpIEInfo, + &pBies->ERPInfo); + } + if (pBies->VHTCaps.present) { + pBeaconStruct->VHTCaps.present = 1; + qdf_mem_copy(&pBeaconStruct->VHTCaps, &pBies->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBies->VHTOperation.present) { + pBeaconStruct->VHTOperation.present = 1; + qdf_mem_copy(&pBeaconStruct->VHTOperation, &pBies->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBies->VHTExtBssLoad.present) { + pBeaconStruct->VHTExtBssLoad.present = 1; + qdf_mem_copy(&pBeaconStruct->VHTExtBssLoad, + &pBies->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + if (pBies->OperatingMode.present) { + pBeaconStruct->OperatingMode.present = 1; + qdf_mem_copy(&pBeaconStruct->OperatingMode, + &pBies->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } + if (pBies->MobilityDomain.present) { + pBeaconStruct->mdiePresent = 1; + qdf_mem_copy(pBeaconStruct->mdie, &pBies->MobilityDomain.MDID, + SIR_MDIE_SIZE); + } + + pBeaconStruct->Vendor1IEPresent = pBies->Vendor1IE.present; + pBeaconStruct->Vendor3IEPresent = pBies->Vendor3IE.present; + pBeaconStruct->vendor_vht_ie.present = pBies->vendor_vht_ie.present; + if (pBies->vendor_vht_ie.present) + pBeaconStruct->vendor_vht_ie.sub_type = + pBies->vendor_vht_ie.sub_type; + + if (pBies->vendor_vht_ie.VHTCaps.present) { + pBeaconStruct->vendor_vht_ie.VHTCaps.present = 1; + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTCaps, + &pBies->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBies->vendor_vht_ie.VHTOperation.present) { + pBeaconStruct->vendor_vht_ie.VHTOperation.present = 1; + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTOperation, + &pBies->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBies->ExtCap.present) { + qdf_mem_copy(&pBeaconStruct->ext_cap, &pBies->ExtCap, + sizeof(tDot11fIEExtCap)); + } + /* Update HS 2.0 Information Element */ + if (pBies->hs20vendor_ie.present) { + pe_debug("HS20 Indication Element Present, rel#:%u, id:%u", + pBies->hs20vendor_ie.release_num, + pBies->hs20vendor_ie.hs_id_present); + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie, + &pBies->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(pBies->hs20vendor_ie.hs_id)); + if (pBies->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie.hs_id, + &pBies->hs20vendor_ie.hs_id, + sizeof(pBies->hs20vendor_ie.hs_id)); + } + + if (pBies->MBO_IE.present) { + pBeaconStruct->MBO_IE_present = true; + if (pBies->MBO_IE.cellular_data_cap.present) + pBeaconStruct->MBO_capability = + pBies->MBO_IE.cellular_data_cap.cellular_connectivity; + + if (pBies->MBO_IE.assoc_disallowed.present) { + pBeaconStruct->assoc_disallowed = true; + pBeaconStruct->assoc_disallowed_reason = + pBies->MBO_IE.assoc_disallowed.reason_code; + } + } + + if (pBies->qcn_ie.present) + qdf_mem_copy(&pBeaconStruct->qcn_ie, &pBies->qcn_ie, + sizeof(tDot11fIEqcn_ie)); + + if (pBies->he_cap.present) { + qdf_mem_copy(&pBeaconStruct->he_cap, &pBies->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (pBies->he_op.present) { + qdf_mem_copy(&pBeaconStruct->he_op, &pBies->he_op, + sizeof(tDot11fIEhe_op)); + } + + if (pBies->eht_cap.present) { + qdf_mem_copy(&pBeaconStruct->eht_cap, &pBies->eht_cap, + sizeof(tDot11fIEeht_cap)); + } + if (pBies->eht_op.present) { + qdf_mem_copy(&pBeaconStruct->eht_op, &pBies->eht_op, + sizeof(tDot11fIEeht_op)); + } + + update_bss_color_change_from_beacon_ies(pBies, pBeaconStruct); + + qdf_mem_free(pBies); + return QDF_STATUS_SUCCESS; +} /* End sir_parse_beacon_ie. */ + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +static void convert_bcon_bss_color_change_ie(tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ + if (bcn_frm->bss_color_change.present) { + pe_debug("11AX: HE BSS color change present"); + qdf_mem_copy(&bcn_struct->vendor_he_bss_color_change, + &bcn_frm->bss_color_change, + sizeof(tDot11fIEbss_color_change)); + } +} +#else +static inline void convert_bcon_bss_color_change_ie(tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{} +#endif + +#ifdef WLAN_FEATURE_SR +static void sir_convert_beacon_frame2_sr_struct(tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ + if (bcn_frm->spatial_reuse.present) + qdf_mem_copy(&bcn_struct->srp_ie, &bcn_frm->spatial_reuse, + sizeof(tDot11fIEspatial_reuse)); +} +#else +static inline void +sir_convert_beacon_frame2_sr_struct(tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_convert_beacon_frame2_t2lm_struct(tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_t2lm_context *t2lm_ctx; + /* add 3 bytes for extn_ie_header */ + uint8_t ie[DOT11F_IE_T2LM_IE_MAX_LEN + 3]; + struct wlan_t2lm_info t2lm; + uint8_t i; + + t2lm_ctx = &bcn_struct->t2lm_ctx; + qdf_mem_zero(&t2lm_ctx->established_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_ctx->established_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + qdf_mem_zero(&t2lm_ctx->upcoming_t2lm.t2lm, + sizeof(struct wlan_t2lm_info)); + t2lm_ctx->upcoming_t2lm.t2lm.direction = WLAN_T2LM_INVALID_DIRECTION; + + if (!bcn_frm->num_t2lm_ie) + return status; + + pe_debug("Number of T2LM IEs in beacon %d", bcn_frm->num_t2lm_ie); + for (i = 0; i < bcn_frm->num_t2lm_ie; i++) { + qdf_mem_zero(&ie[0], DOT11F_IE_T2LM_IE_MAX_LEN + 3); + qdf_mem_zero(&t2lm, sizeof(struct wlan_t2lm_info)); + ie[ID_POS] = WLAN_ELEMID_EXTN_ELEM; + ie[TAG_LEN_POS] = bcn_frm->t2lm_ie[i].num_data + 1; + ie[IDEXT_POS] = WLAN_EXTN_ELEMID_T2LM; + qdf_mem_copy(&ie[3], &bcn_frm->t2lm_ie[i].data[0], + bcn_frm->t2lm_ie[i].num_data); + qdf_trace_hex_dump(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + &ie[0], bcn_frm->t2lm_ie[i].num_data + 3); + + if (ie[TAG_LEN_POS] + 2 > DOT11F_IE_T2LM_IE_MAX_LEN + 3) { + pe_debug("Invalid T2LM IE length"); + return QDF_STATUS_E_PROTO; + } + + status = wlan_mlo_parse_t2lm_info(&ie[0], &t2lm); + if (QDF_IS_STATUS_ERROR(status)) { + pe_debug("Parse T2LM IE fail"); + return status; + } + + if (!t2lm.mapping_switch_time_present && + t2lm.expected_duration_present) { + qdf_mem_copy(&t2lm_ctx->established_t2lm.t2lm, &t2lm, + sizeof(struct wlan_t2lm_info)); + pe_debug("Parse established T2LM IE success"); + } else if (t2lm.mapping_switch_time_present) { + qdf_mem_copy(&t2lm_ctx->upcoming_t2lm.t2lm, &t2lm, + sizeof(struct wlan_t2lm_info)); + pe_debug("Parse upcoming T2LM IE success"); + } + pe_debug("Parse T2LM IE success"); + } + return status; +} +#else +static inline QDF_STATUS +sir_convert_beacon_frame2_t2lm_struct(tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +sir_convert_beacon_frame2_mlo_struct(uint8_t *pframe, uint32_t nframe, + tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ + uint8_t *ml_ie, *sta_prof; + qdf_size_t ml_ie_total_len; + uint8_t common_info_len = 0; + struct mlo_partner_info partner_info; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t bpcc; + bool bpcc_found; + bool ext_mld_cap_found = false; + uint16_t ext_mld_cap = 0; + + if (bcn_frm->mlo_ie.present) { + status = util_find_mlie(pframe + WLAN_BEACON_IES_OFFSET, + nframe - WLAN_BEACON_IES_OFFSET, + &ml_ie, &ml_ie_total_len); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = util_get_bvmlie_persta_partner_info( + ml_ie, + ml_ie_total_len, + &partner_info); + if (QDF_IS_STATUS_ERROR(status)) + return status; + bcn_struct->mlo_ie.mlo_ie.num_sta_profile = + partner_info.num_partner_links; + util_get_mlie_common_info_len(ml_ie, ml_ie_total_len, + &common_info_len); + sta_prof = ml_ie + sizeof(struct wlan_ie_multilink) + + common_info_len; + + lim_store_mlo_ie_raw_info(ml_ie, sta_prof, + ml_ie_total_len, + &bcn_struct->mlo_ie.mlo_ie); + + util_get_bvmlie_ext_mld_cap_op_info(ml_ie, + ml_ie_total_len, + &ext_mld_cap_found, + &ext_mld_cap); + if (ext_mld_cap_found) { + bcn_struct->mlo_ie.mlo_ie.ext_mld_capab_and_op_info.rec_max_simultaneous_links = + QDF_GET_BITS( + ext_mld_cap, + WLAN_ML_BV_CINFO_EXTMLDCAPINFO_RECOM_MAX_SIMULT_LINKS_IDX, + WLAN_ML_BV_CINFO_EXTMLDCAPINFO_RECOM_MAX_SIMULT_LINKS_BITS); + } + util_get_bvmlie_bssparamchangecnt(ml_ie, + ml_ie_total_len, + &bpcc_found, &bpcc); + bcn_struct->mlo_ie.mlo_ie.bss_param_change_cnt_present = + bpcc_found; + bcn_struct->mlo_ie.mlo_ie.bss_param_change_count = bpcc; + bcn_struct->mlo_ie.mlo_ie_present = true; + } + } + + return status; +} +#else +static inline QDF_STATUS +sir_convert_beacon_frame2_mlo_struct(uint8_t *pframe, uint32_t nframe, + tDot11fBeacon *bcn_frm, + tpSirProbeRespBeacon bcn_struct) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +sir_convert_beacon_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + tpSirProbeRespBeacon pBeaconStruct) +{ + tDot11fBeacon *pBeacon; + uint32_t status, nPayload; + uint8_t *pPayload; + tpSirMacMgmtHdr pHdr; + uint32_t freq; + + pPayload = WMA_GET_RX_MPDU_DATA(pFrame); + nPayload = WMA_GET_RX_PAYLOAD_LEN(pFrame); + pHdr = WMA_GET_RX_MAC_HEADER(pFrame); + freq = WMA_GET_RX_FREQ(pFrame); + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pBeaconStruct, sizeof(tSirProbeRespBeacon)); + + pBeacon = qdf_mem_malloc_atomic(sizeof(tDot11fBeacon)); + if (!pBeacon) + return QDF_STATUS_E_NOMEM; + + /* get the MAC address out of the BD, */ + qdf_mem_copy(pBeaconStruct->bssid, pHdr->sa, 6); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_beacon(mac, pPayload, nPayload, pBeacon, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse Beacon IEs (0x%08x, %d bytes):", + status, nPayload); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + pPayload, nPayload); + qdf_mem_free(pBeacon); + return QDF_STATUS_E_FAILURE; + } + + status = lim_strip_and_decode_eht_op(pPayload + WLAN_BEACON_IES_OFFSET, + nPayload - WLAN_BEACON_IES_OFFSET, + &pBeacon->eht_op, + pBeacon->VHTOperation, + pBeacon->he_op, + pBeacon->HTInfo); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + qdf_mem_free(pBeacon); + return QDF_STATUS_E_FAILURE; + } + + status = lim_strip_and_decode_eht_cap(pPayload + WLAN_BEACON_IES_OFFSET, + nPayload - WLAN_BEACON_IES_OFFSET, + &pBeacon->eht_cap, + pBeacon->he_cap, + freq); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + qdf_mem_free(pBeacon); + return QDF_STATUS_E_FAILURE; + } + + /* & "transliterate" from a 'tDot11fBeacon' to a 'tSirProbeRespBeacon'... */ + /* Timestamp */ + qdf_mem_copy((uint8_t *) pBeaconStruct->timeStamp, + (uint8_t *) &pBeacon->TimeStamp, + sizeof(tSirMacTimeStamp)); + + /* Beacon Interval */ + pBeaconStruct->beaconInterval = pBeacon->BeaconInterval.interval; + + /* Capabilities */ + pBeaconStruct->capabilityInfo.ess = pBeacon->Capabilities.ess; + pBeaconStruct->capabilityInfo.ibss = pBeacon->Capabilities.ibss; + pBeaconStruct->capabilityInfo.cfPollable = + pBeacon->Capabilities.cfPollable; + pBeaconStruct->capabilityInfo.cfPollReq = + pBeacon->Capabilities.cfPollReq; + pBeaconStruct->capabilityInfo.privacy = pBeacon->Capabilities.privacy; + pBeaconStruct->capabilityInfo.shortPreamble = + pBeacon->Capabilities.shortPreamble; + pBeaconStruct->capabilityInfo.criticalUpdateFlag = + pBeacon->Capabilities.criticalUpdateFlag; + pBeaconStruct->capabilityInfo.channelAgility = + pBeacon->Capabilities.channelAgility; + pBeaconStruct->capabilityInfo.spectrumMgt = + pBeacon->Capabilities.spectrumMgt; + pBeaconStruct->capabilityInfo.qos = pBeacon->Capabilities.qos; + pBeaconStruct->capabilityInfo.shortSlotTime = + pBeacon->Capabilities.shortSlotTime; + pBeaconStruct->capabilityInfo.apsd = pBeacon->Capabilities.apsd; + pBeaconStruct->capabilityInfo.rrm = pBeacon->Capabilities.rrm; + pBeaconStruct->capabilityInfo.dsssOfdm = pBeacon->Capabilities.dsssOfdm; + pBeaconStruct->capabilityInfo.delayedBA = + pBeacon->Capabilities.delayedBA; + pBeaconStruct->capabilityInfo.immediateBA = + pBeacon->Capabilities.immediateBA; + + if (!pBeacon->SSID.present) { + pe_debug("Mandatory IE SSID not present!"); + } else { + pBeaconStruct->ssidPresent = 1; + convert_ssid(mac, &pBeaconStruct->ssId, &pBeacon->SSID); + } + + if (!pBeacon->SuppRates.present) { + pe_debug_rl("Mandatory IE Supported Rates not present!"); + } else { + pBeaconStruct->suppRatesPresent = 1; + convert_supp_rates(mac, &pBeaconStruct->supportedRates, + &pBeacon->SuppRates); + } + + if (pBeacon->ExtSuppRates.present) { + pBeaconStruct->extendedRatesPresent = 1; + convert_ext_supp_rates(mac, &pBeaconStruct->extendedRates, + &pBeacon->ExtSuppRates); + } + + if (pBeacon->CFParams.present) { + pBeaconStruct->cfPresent = 1; + convert_cf_params(mac, &pBeaconStruct->cfParamSet, + &pBeacon->CFParams); + } + + if (pBeacon->TIM.present) { + pBeaconStruct->timPresent = 1; + convert_tim(mac, &pBeaconStruct->tim, &pBeacon->TIM); + } + + if (pBeacon->Country.present) { + pBeaconStruct->countryInfoPresent = 1; + convert_country(mac, &pBeaconStruct->countryInfoParam, + &pBeacon->Country); + } + /* QOS Capabilities: */ + if (pBeacon->QOSCapsAp.present) { + pBeaconStruct->qosCapabilityPresent = 1; + convert_qos_caps(mac, &pBeaconStruct->qosCapability, + &pBeacon->QOSCapsAp); + } + + if (pBeacon->EDCAParamSet.present) { + pBeaconStruct->edcaPresent = 1; + convert_edca_param(mac, &pBeaconStruct->edcaParams, + &pBeacon->EDCAParamSet); + } + + if (pBeacon->ChanSwitchAnn.present) { + pBeaconStruct->channelSwitchPresent = 1; + qdf_mem_copy(&pBeaconStruct->channelSwitchIE, + &pBeacon->ChanSwitchAnn, + sizeof(pBeaconStruct->channelSwitchIE)); + } + + if (pBeacon->ext_chan_switch_ann.present) { + pBeaconStruct->ext_chan_switch_present = 1; + qdf_mem_copy(&pBeaconStruct->ext_chan_switch, + &pBeacon->ext_chan_switch_ann, + sizeof(tDot11fIEext_chan_switch_ann)); + } + + if (pBeacon->sec_chan_offset_ele.present) { + pBeaconStruct->sec_chan_offset_present = 1; + qdf_mem_copy(&pBeaconStruct->sec_chan_offset, + &pBeacon->sec_chan_offset_ele, + sizeof(pBeaconStruct->sec_chan_offset)); + } + + if (pBeacon->TPCReport.present) { + pBeaconStruct->tpcReportPresent = 1; + qdf_mem_copy(&pBeaconStruct->tpcReport, &pBeacon->TPCReport, + sizeof(tDot11fIETPCReport)); + } + + if (pBeacon->PowerConstraints.present) { + pBeaconStruct->powerConstraintPresent = 1; + qdf_mem_copy(&pBeaconStruct->localPowerConstraint, + &pBeacon->PowerConstraints, + sizeof(tDot11fIEPowerConstraints)); + } + + if (pBeacon->Quiet.present) { + pBeaconStruct->quietIEPresent = 1; + qdf_mem_copy(&pBeaconStruct->quietIE, &pBeacon->Quiet, + sizeof(tDot11fIEQuiet)); + } + + if (pBeacon->HTCaps.present) { + qdf_mem_copy(&pBeaconStruct->HTCaps, &pBeacon->HTCaps, + sizeof(tDot11fIEHTCaps)); + } + + if (pBeacon->HTInfo.present) { + qdf_mem_copy(&pBeaconStruct->HTInfo, &pBeacon->HTInfo, + sizeof(tDot11fIEHTInfo)); + + } + + if (pBeacon->he_op.oper_info_6g_present) { + pBeaconStruct->chan_freq = wlan_reg_chan_band_to_freq(mac->pdev, + pBeacon->he_op.oper_info_6g.info.primary_ch, + BIT(REG_BAND_6G)); + pBeaconStruct->ap_power_type = + pBeacon->he_op.oper_info_6g.info.reg_info; + } else if (pBeacon->DSParams.present) { + pBeaconStruct->dsParamsPresent = 1; + pBeaconStruct->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, + pBeacon->DSParams.curr_channel); + } else if (pBeacon->HTInfo.present) { + pBeaconStruct->chan_freq = + wlan_reg_legacy_chan_to_freq(mac->pdev, + pBeacon->HTInfo.primaryChannel); + } else { + pBeaconStruct->chan_freq = WMA_GET_RX_FREQ(pFrame); + pe_debug_rl("In Beacon No Channel info"); + } + + if (pBeacon->RSN.present) { + pBeaconStruct->rsnPresent = 1; + convert_rsn(mac, &pBeaconStruct->rsn, &pBeacon->RSN); + } + + if (pBeacon->WPA.present) { + pBeaconStruct->wpaPresent = 1; + convert_wpa(mac, &pBeaconStruct->wpa, &pBeacon->WPA); + } + + if (pBeacon->WMMParams.present) { + pBeaconStruct->wmeEdcaPresent = 1; + convert_wmm_params(mac, &pBeaconStruct->edcaParams, + &pBeacon->WMMParams); + } + + if (pBeacon->WMMInfoAp.present) { + pBeaconStruct->wmeInfoPresent = 1; + pe_debug("WMM Info present in Beacon Frame!"); + } + + if (pBeacon->WMMCaps.present) { + pBeaconStruct->wsmCapablePresent = 1; + } + + if (pBeacon->ERPInfo.present) { + pBeaconStruct->erpPresent = 1; + convert_erp_info(mac, &pBeaconStruct->erpIEInfo, + &pBeacon->ERPInfo); + } + if (pBeacon->MobilityDomain.present) { + /* MobilityDomain */ + pBeaconStruct->mdiePresent = 1; + qdf_mem_copy((uint8_t *) &(pBeaconStruct->mdie[0]), + (uint8_t *) &(pBeacon->MobilityDomain.MDID), + sizeof(uint16_t)); + pBeaconStruct->mdie[2] = + ((pBeacon->MobilityDomain.overDSCap << 0) | (pBeacon-> + MobilityDomain. + resourceReqCap + << 1)); + } + +#ifdef FEATURE_WLAN_ESE + if (pBeacon->ESEVersion.present) + pBeaconStruct->is_ese_ver_ie_present = 1; + if (pBeacon->ESETxmitPower.present) { + /* copy ESE TPC info element */ + pBeaconStruct->eseTxPwr.present = 1; + qdf_mem_copy(&pBeaconStruct->eseTxPwr, + &pBeacon->ESETxmitPower, + sizeof(tDot11fIEESETxmitPower)); + } + if (pBeacon->QBSSLoad.present) { + qdf_mem_copy(&pBeaconStruct->QBSSLoad, + &pBeacon->QBSSLoad, sizeof(tDot11fIEQBSSLoad)); + } +#endif + if (pBeacon->VHTCaps.present) { + qdf_mem_copy(&pBeaconStruct->VHTCaps, &pBeacon->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBeacon->VHTOperation.present) { + qdf_mem_copy(&pBeaconStruct->VHTOperation, + &pBeacon->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + if (pBeacon->VHTExtBssLoad.present) { + qdf_mem_copy(&pBeaconStruct->VHTExtBssLoad, + &pBeacon->VHTExtBssLoad, + sizeof(tDot11fIEVHTExtBssLoad)); + } + if (pBeacon->OperatingMode.present) { + qdf_mem_copy(&pBeaconStruct->OperatingMode, + &pBeacon->OperatingMode, + sizeof(tDot11fIEOperatingMode)); + } + if (pBeacon->WiderBWChanSwitchAnn.present) { + pBeaconStruct->WiderBWChanSwitchAnnPresent = 1; + qdf_mem_copy(&pBeaconStruct->WiderBWChanSwitchAnn, + &pBeacon->WiderBWChanSwitchAnn, + sizeof(tDot11fIEWiderBWChanSwitchAnn)); + } + + pBeaconStruct->Vendor1IEPresent = pBeacon->Vendor1IE.present; + pBeaconStruct->Vendor3IEPresent = pBeacon->Vendor3IE.present; + + pBeaconStruct->vendor_vht_ie.present = pBeacon->vendor_vht_ie.present; + if (pBeacon->vendor_vht_ie.present) { + pBeaconStruct->vendor_vht_ie.sub_type = + pBeacon->vendor_vht_ie.sub_type; + } + + if (pBeacon->vendor_vht_ie.VHTCaps.present) { + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTCaps, + &pBeacon->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)); + } + if (pBeacon->vendor_vht_ie.VHTOperation.present) { + qdf_mem_copy(&pBeaconStruct->vendor_vht_ie.VHTOperation, + &pBeacon->VHTOperation, + sizeof(tDot11fIEVHTOperation)); + } + /* Update HS 2.0 Information Element */ + if (pBeacon->hs20vendor_ie.present) { + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie, + &pBeacon->hs20vendor_ie, + sizeof(tDot11fIEhs20vendor_ie) - + sizeof(pBeacon->hs20vendor_ie.hs_id)); + if (pBeacon->hs20vendor_ie.hs_id_present) + qdf_mem_copy(&pBeaconStruct->hs20vendor_ie.hs_id, + &pBeacon->hs20vendor_ie.hs_id, + sizeof(pBeacon->hs20vendor_ie.hs_id)); + } +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (pBeacon->QComVendorIE.present) { + pBeaconStruct->AvoidChannelIE.present = + pBeacon->QComVendorIE.present; + pBeaconStruct->AvoidChannelIE.type = + pBeacon->QComVendorIE.type; + pBeaconStruct->AvoidChannelIE.channel = + pBeacon->QComVendorIE.channel; + } +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + if (pBeacon->OBSSScanParameters.present) { + qdf_mem_copy(&pBeaconStruct->obss_scanparams, + &pBeacon->OBSSScanParameters, + sizeof(struct sDot11fIEOBSSScanParameters)); + } + if (pBeacon->MBO_IE.present) { + pBeaconStruct->MBO_IE_present = true; + if (pBeacon->MBO_IE.cellular_data_cap.present) + pBeaconStruct->MBO_capability = + pBeacon->MBO_IE.cellular_data_cap.cellular_connectivity; + + if (pBeacon->MBO_IE.assoc_disallowed.present) { + pBeaconStruct->assoc_disallowed = true; + pBeaconStruct->assoc_disallowed_reason = + pBeacon->MBO_IE.assoc_disallowed.reason_code; + } + } + + if (pBeacon->qcn_ie.present) + qdf_mem_copy(&pBeaconStruct->qcn_ie, &pBeacon->qcn_ie, + sizeof(tDot11fIEqcn_ie)); + + if (pBeacon->he_cap.present) { + qdf_mem_copy(&pBeaconStruct->he_cap, + &pBeacon->he_cap, + sizeof(tDot11fIEhe_cap)); + } + if (pBeacon->he_op.present) { + qdf_mem_copy(&pBeaconStruct->he_op, + &pBeacon->he_op, + sizeof(tDot11fIEhe_op)); + } + + if (pBeacon->eht_cap.present) + qdf_mem_copy(&pBeaconStruct->eht_cap, &pBeacon->eht_cap, + sizeof(tDot11fIEeht_cap)); + if (pBeacon->eht_op.present) + qdf_mem_copy(&pBeaconStruct->eht_op, &pBeacon->eht_op, + sizeof(tDot11fIEeht_op)); + + pBeaconStruct->num_transmit_power_env = pBeacon->num_transmit_power_env; + if (pBeacon->num_transmit_power_env) { + qdf_mem_copy(pBeaconStruct->transmit_power_env, + pBeacon->transmit_power_env, + pBeacon->num_transmit_power_env * + sizeof(tDot11fIEtransmit_power_env)); + } + + convert_bcon_bss_color_change_ie(pBeacon, pBeaconStruct); + sir_convert_beacon_frame2_mlo_struct(pPayload, nPayload, pBeacon, + pBeaconStruct); + sir_convert_beacon_frame2_t2lm_struct(pBeacon, pBeaconStruct); + sir_convert_beacon_frame2_sr_struct(pBeacon, pBeaconStruct); + + qdf_mem_free(pBeacon); + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_beacon_frame2_struct. */ + +#ifdef WLAN_FEATURE_FILS_SK + +/* update_ftie_in_fils_conf() - API to update fils info from auth + * response packet from AP + * @auth: auth packet pointer received from AP + * @auth_frame: data structure needs to be updated + * + * Return: None + */ +static void +update_ftie_in_fils_conf(tDot11fAuthentication *auth, + tpSirMacAuthFrameBody auth_frame) +{ + /** + * Copy the FTIE sent by the AP in the auth request frame. + * This is required for FT-FILS connection. + * This FTIE will be sent in Assoc request frame without + * any modification. + */ + if (auth->FTInfo.present) { + pe_debug("FT-FILS: r0kh_len:%d r1kh_present:%d", + auth->FTInfo.R0KH_ID.num_PMK_R0_ID, + auth->FTInfo.R1KH_ID.present); + + auth_frame->ft_ie.present = 1; + if (auth->FTInfo.R1KH_ID.present) { + qdf_mem_copy(auth_frame->ft_ie.r1kh_id, + auth->FTInfo.R1KH_ID.PMK_R1_ID, + FT_R1KH_ID_LEN); + } + + if (auth->FTInfo.R0KH_ID.present) { + qdf_mem_copy(auth_frame->ft_ie.r0kh_id, + auth->FTInfo.R0KH_ID.PMK_R0_ID, + auth->FTInfo.R0KH_ID.num_PMK_R0_ID); + auth_frame->ft_ie.r0kh_id_len = + auth->FTInfo.R0KH_ID.num_PMK_R0_ID; + } + + if (auth_frame->ft_ie.gtk_ie.present) { + pe_debug("FT-FILS: GTK present"); + qdf_mem_copy(&auth_frame->ft_ie.gtk_ie, + &auth->FTInfo.GTK, + sizeof(struct mac_ft_gtk_ie)); + } + + if (auth_frame->ft_ie.igtk_ie.present) { + pe_debug("FT-FILS: IGTK present"); + qdf_mem_copy(&auth_frame->ft_ie.igtk_ie, + &auth->FTInfo.IGTK, + sizeof(struct mac_ft_igtk_ie)); + } + + qdf_mem_copy(auth_frame->ft_ie.anonce, auth->FTInfo.Anonce, + FT_NONCE_LEN); + qdf_mem_copy(auth_frame->ft_ie.snonce, auth->FTInfo.Snonce, + FT_NONCE_LEN); + + qdf_mem_copy(auth_frame->ft_ie.mic, auth->FTInfo.MIC, + FT_MIC_LEN); + auth_frame->ft_ie.element_count = auth->FTInfo.IECount; + } +} + +/* sir_update_auth_frame2_struct_fils_conf: API to update fils info from auth + * packet type 2 + * @auth: auth packet pointer received from AP + * @auth_frame: data structure needs to be updated + * + * Return: None + */ +static void +sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth, + tpSirMacAuthFrameBody auth_frame) +{ + if (auth->AuthAlgo.algo != SIR_FILS_SK_WITHOUT_PFS) + return; + + if (auth->fils_assoc_delay_info.present) + auth_frame->assoc_delay_info = + auth->fils_assoc_delay_info.assoc_delay_info; + + if (auth->fils_session.present) + qdf_mem_copy(auth_frame->session, auth->fils_session.session, + SIR_FILS_SESSION_LENGTH); + + if (auth->fils_nonce.present) + qdf_mem_copy(auth_frame->nonce, auth->fils_nonce.nonce, + SIR_FILS_NONCE_LENGTH); + + if (auth->fils_wrapped_data.present) { + qdf_mem_copy(auth_frame->wrapped_data, + auth->fils_wrapped_data.wrapped_data, + auth->fils_wrapped_data.num_wrapped_data); + auth_frame->wrapped_data_len = + auth->fils_wrapped_data.num_wrapped_data; + } + if (auth->RSNOpaque.present) { + qdf_mem_copy(auth_frame->rsn_ie.info, auth->RSNOpaque.data, + auth->RSNOpaque.num_data); + auth_frame->rsn_ie.length = auth->RSNOpaque.num_data; + } + + update_ftie_in_fils_conf(auth, auth_frame); + +} +#else +static void sir_update_auth_frame2_struct_fils_conf(tDot11fAuthentication *auth, + tpSirMacAuthFrameBody auth_frame) +{ } +#endif + +QDF_STATUS +sir_convert_auth_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, tpSirMacAuthFrameBody pAuth) +{ + static tDot11fAuthentication auth; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pAuth, sizeof(tSirMacAuthFrameBody)); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_authentication(mac, pFrame, nFrame, + &auth, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse an Authentication frame (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking an Authentication frame (0x%08x, %d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAuthentication' to a 'tSirMacAuthFrameBody'... */ + pAuth->authAlgoNumber = auth.AuthAlgo.algo; + pAuth->authTransactionSeqNumber = auth.AuthSeqNo.no; + pAuth->authStatusCode = auth.Status.status; + + if (auth.ChallengeText.present) { + pAuth->type = WLAN_ELEMID_CHALLENGE; + pAuth->length = auth.ChallengeText.num_text; + qdf_mem_copy(pAuth->challengeText, auth.ChallengeText.text, + auth.ChallengeText.num_text); + } + + /* Copy MLO IE presence flag to pAuth in case of ML connection */ + pAuth->is_mlo_ie_present = auth.mlo_ie.present; + /* The minimum length is set to 9 based on below calculation + * Multi-Link Control Field => 2 Bytes + * Minimum CInfo Field => CInfo Length (1 Byte) + MLD Addr (6 Bytes) + * min_len = 2 + 1 + 6 + * MLD Offset = min_len - (2 + 1) + */ + if (pAuth->is_mlo_ie_present && auth.mlo_ie.num_data >= 9) { + qdf_copy_macaddr(&pAuth->peer_mld, + (struct qdf_mac_addr *)(auth.mlo_ie.data + 3)); + } + + sir_update_auth_frame2_struct_fils_conf(&auth, pAuth); + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_auth_frame2_struct. */ + +QDF_STATUS +sir_convert_addts_rsp2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, tSirAddtsRspInfo *pAddTs) +{ + tDot11fAddTSResponse addts = { {0} }; + tDot11fWMMAddTSResponse wmmaddts = { {0} }; + uint8_t j; + uint16_t i; + uint32_t status; + + if (QOS_ADD_TS_RSP != *(pFrame + 1)) { + pe_err("Action of %d; this is not supported & is probably an error", + *(pFrame + 1)); + return QDF_STATUS_E_FAILURE; + } + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pAddTs, sizeof(tSirAddtsRspInfo)); + qdf_mem_zero((uint8_t *) &addts, sizeof(tDot11fAddTSResponse)); + qdf_mem_zero((uint8_t *) &wmmaddts, sizeof(tDot11fWMMAddTSResponse)); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case ACTION_CATEGORY_QOS: + status = + dot11f_unpack_add_ts_response(mac, pFrame, nFrame, + &addts, false); + break; + case ACTION_CATEGORY_WMM: + status = + dot11f_unpack_wmm_add_ts_response(mac, pFrame, nFrame, + &wmmaddts, false); + break; + default: + pe_err("Category of %d; this is not supported & is probably an error", + *pFrame); + return QDF_STATUS_E_FAILURE; + } + + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse an Add TS Response frame (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking an Add TS Response frame (0x%08x,%d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fAddTSResponse' or a */ + /* 'tDot11WMMAddTSResponse' to a 'tSirMacAddtsRspInfo'... */ + if (ACTION_CATEGORY_QOS == *pFrame) { + pAddTs->dialogToken = addts.DialogToken.token; + pAddTs->status = (enum wlan_status_code)addts.Status.status; + + if (addts.TSDelay.present) { + convert_ts_delay(mac, &pAddTs->delay, &addts.TSDelay); + } + /* TS Delay is present iff status indicates its presence */ + if (pAddTs->status == STATUS_TS_NOT_CREATED && + !addts.TSDelay.present) { + pe_warn("Missing TSDelay IE"); + } + + if (addts.TSPEC.present) { + convert_tspec(mac, &pAddTs->tspec, &addts.TSPEC); + } else { + pe_err("Mandatory TSPEC element missing in Add TS Response"); + return QDF_STATUS_E_FAILURE; + } + + if (addts.num_TCLAS) { + pAddTs->numTclas = (uint8_t) addts.num_TCLAS; + + for (i = 0U; i < addts.num_TCLAS; ++i) { + if (QDF_STATUS_SUCCESS != + convert_tclas(mac, &(pAddTs->tclasInfo[i]), + &(addts.TCLAS[i]))) { + pe_err("Failed to convert a TCLAS IE"); + return QDF_STATUS_E_FAILURE; + } + } + } + + if (addts.TCLASSPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.TCLASSPROC.processing; + } +#ifdef FEATURE_WLAN_ESE + if (addts.ESETrafStrmMet.present) { + pAddTs->tsmPresent = 1; + qdf_mem_copy(&pAddTs->tsmIE.tsid, + &addts.ESETrafStrmMet.tsid, + sizeof(struct ese_tsm_ie)); + } +#endif + if (addts.Schedule.present) { + pAddTs->schedulePresent = 1; + convert_schedule(mac, &pAddTs->schedule, + &addts.Schedule); + } + + if (addts.WMMSchedule.present) { + pAddTs->schedulePresent = 1; + convert_wmm_schedule(mac, &pAddTs->schedule, + &addts.WMMSchedule); + } + + if (addts.WMMTSPEC.present) { + pAddTs->wsmTspecPresent = 1; + convert_wmmtspec(mac, &pAddTs->tspec, &addts.WMMTSPEC); + } + + if (addts.num_WMMTCLAS) { + j = (uint8_t) (pAddTs->numTclas + addts.num_WMMTCLAS); + if (SIR_MAC_TCLASIE_MAXNUM < j) + j = SIR_MAC_TCLASIE_MAXNUM; + + for (i = pAddTs->numTclas; i < j; ++i) { + if (QDF_STATUS_SUCCESS != + convert_wmmtclas(mac, + &(pAddTs->tclasInfo[i]), + &(addts.WMMTCLAS[i]))) { + pe_err("Failed to convert a TCLAS IE"); + return QDF_STATUS_E_FAILURE; + } + } + } + + if (addts.WMMTCLASPROC.present) { + pAddTs->tclasProcPresent = 1; + pAddTs->tclasProc = addts.WMMTCLASPROC.processing; + } + + if (1 < pAddTs->numTclas && (!pAddTs->tclasProcPresent)) { + pe_err("%d TCLAS IE but not TCLASPROC IE", + pAddTs->numTclas); + return QDF_STATUS_E_FAILURE; + } + } else { + pAddTs->dialogToken = wmmaddts.DialogToken.token; + pAddTs->status = + (enum wlan_status_code)wmmaddts.StatusCode.statusCode; + + if (wmmaddts.WMMTSPEC.present) { + pAddTs->wmeTspecPresent = 1; + convert_wmmtspec(mac, &pAddTs->tspec, + &wmmaddts.WMMTSPEC); + } else { + pe_err("Mandatory WME TSPEC element missing!"); + return QDF_STATUS_E_FAILURE; + } + +#ifdef FEATURE_WLAN_ESE + if (wmmaddts.ESETrafStrmMet.present) { + pAddTs->tsmPresent = 1; + qdf_mem_copy(&pAddTs->tsmIE.tsid, + &wmmaddts.ESETrafStrmMet.tsid, + sizeof(struct ese_tsm_ie)); + } +#endif + + } + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_addts_rsp2_struct. */ + +QDF_STATUS +sir_convert_delts_req2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, struct delts_req_info *pDelTs) +{ + tDot11fDelTS delts = { {0} }; + tDot11fWMMDelTS wmmdelts = { {0} }; + uint32_t status; + + if (QOS_DEL_TS_REQ != *(pFrame + 1)) { + pe_err("sirConvertDeltsRsp2Struct invoked " + "with an Action of %d; this is not " + "supported & is probably an error", + *(pFrame + 1)); + return QDF_STATUS_E_FAILURE; + } + /* Zero-init our [out] parameter, */ + qdf_mem_zero(pDelTs, sizeof(*pDelTs)); + + /* delegate to the framesc-generated code, */ + switch (*pFrame) { + case ACTION_CATEGORY_QOS: + status = dot11f_unpack_del_ts(mac, pFrame, nFrame, + &delts, false); + break; + case ACTION_CATEGORY_WMM: + status = dot11f_unpack_wmm_del_ts(mac, pFrame, nFrame, + &wmmdelts, false); + break; + default: + pe_err("sirConvertDeltsRsp2Struct invoked " + "with a Category of %d; this is not" + " supported & is probably an error", + *pFrame); + return QDF_STATUS_E_FAILURE; + } + + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse an Del TS Request frame (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking an Del TS Request frame (0x%08x,%d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fDelTSResponse' or a */ + /* 'tDot11WMMDelTSResponse' to a 'tSirMacDeltsReqInfo'... */ + if (ACTION_CATEGORY_QOS == *pFrame) { + pDelTs->tsinfo.traffic.trafficType = + (uint16_t) delts.TSInfo.traffic_type; + pDelTs->tsinfo.traffic.tsid = (uint16_t) delts.TSInfo.tsid; + pDelTs->tsinfo.traffic.direction = + (uint16_t) delts.TSInfo.direction; + pDelTs->tsinfo.traffic.accessPolicy = + (uint16_t) delts.TSInfo.access_policy; + pDelTs->tsinfo.traffic.aggregation = + (uint16_t) delts.TSInfo.aggregation; + pDelTs->tsinfo.traffic.psb = (uint16_t) delts.TSInfo.psb; + pDelTs->tsinfo.traffic.userPrio = + (uint16_t) delts.TSInfo.user_priority; + pDelTs->tsinfo.traffic.ackPolicy = + (uint16_t) delts.TSInfo.tsinfo_ack_pol; + + pDelTs->tsinfo.schedule.schedule = + (uint8_t) delts.TSInfo.schedule; + } else { + if (wmmdelts.WMMTSPEC.present) { + pDelTs->wmeTspecPresent = 1; + convert_wmmtspec(mac, &pDelTs->tspec, + &wmmdelts.WMMTSPEC); + } else { + pe_err("Mandatory WME TSPEC element missing!"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_delts_req2_struct. */ + +QDF_STATUS +sir_convert_qos_map_configure_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + uint32_t nFrame, + struct qos_map_set *pQosMapSet) +{ + tDot11fQosMapConfigure mapConfigure; + uint32_t status; + + status = + dot11f_unpack_qos_map_configure(mac, pFrame, nFrame, + &mapConfigure, false); + if (DOT11F_FAILED(status) || !mapConfigure.QosMapSet.present) { + pe_err("Failed to parse Qos Map Configure frame (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking Qos Map Configure frame (0x%08x, %d bytes):", + status, nFrame); + } + pQosMapSet->present = mapConfigure.QosMapSet.present; + convert_qos_mapset_frame(mac, pQosMapSet, &mapConfigure.QosMapSet); + lim_log_qos_map_set(mac, pQosMapSet); + return QDF_STATUS_SUCCESS; +} + +#ifdef ANI_SUPPORT_11H +QDF_STATUS +sir_convert_tpc_req_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + tpSirMacTpcReqActionFrame pTpcReqFrame, + uint32_t nFrame) +{ + tDot11fTPCRequest req; + uint32_t status; + + qdf_mem_zero((uint8_t *) pTpcReqFrame, + sizeof(tSirMacTpcReqActionFrame)); + status = dot11f_unpack_tpc_request(mac, pFrame, nFrame, &req, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse a TPC Request frame (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking a TPC Request frame (0x%08x, %d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fTPCRequest' to a */ + /* 'tSirMacTpcReqActionFrame'... */ + pTpcReqFrame->actionHeader.category = req.Category.category; + pTpcReqFrame->actionHeader.actionID = req.Action.action; + pTpcReqFrame->actionHeader.dialogToken = req.DialogToken.token; + if (req.TPCRequest.present) { + pTpcReqFrame->type = DOT11F_EID_TPCREQUEST; + pTpcReqFrame->length = 0; + } else { + pe_warn("!!!Rcv TPC Req of invalid type!"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} /* End sir_convert_tpc_req_frame2_struct. */ +QDF_STATUS +sir_convert_meas_req_frame2_struct(struct mac_context *mac, + uint8_t *pFrame, + tpSirMacMeasReqActionFrame pMeasReqFrame, + uint32_t nFrame) +{ + tDot11fMeasurementRequest mr; + uint32_t status; + + /* Zero-init our [out] parameter, */ + qdf_mem_zero((uint8_t *) pMeasReqFrame, + sizeof(tpSirMacMeasReqActionFrame)); + + /* delegate to the framesc-generated code, */ + status = dot11f_unpack_measurement_request(mac, pFrame, + nFrame, &mr, false); + if (DOT11F_FAILED(status)) { + pe_err("Failed to parse a Measurement Request frame (0x%08x, %d bytes):", + status, nFrame); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_ERROR, + pFrame, nFrame); + return QDF_STATUS_E_FAILURE; + } else if (DOT11F_WARNED(status)) { + pe_debug("There were warnings while unpacking a Measurement Request frame (0x%08x, %d bytes):", + status, nFrame); + } + /* & "transliterate" from a 'tDot11fMeasurementRequest' to a */ + /* 'tpSirMacMeasReqActionFrame'... */ + pMeasReqFrame->actionHeader.category = mr.Category.category; + pMeasReqFrame->actionHeader.actionID = mr.Action.action; + pMeasReqFrame->actionHeader.dialogToken = mr.DialogToken.token; + + if (0 == mr.num_MeasurementRequest) { + pe_err("Missing mandatory IE in Measurement Request Frame"); + return QDF_STATUS_E_FAILURE; + } else if (1 < mr.num_MeasurementRequest) { + pe_warn( + FL("Warning: dropping extra Measurement Request IEs!")); + } + + pMeasReqFrame->measReqIE.type = DOT11F_EID_MEASUREMENTREQUEST; + pMeasReqFrame->measReqIE.length = DOT11F_IE_MEASUREMENTREQUEST_MIN_LEN; + pMeasReqFrame->measReqIE.measToken = + mr.MeasurementRequest[0].measurement_token; + pMeasReqFrame->measReqIE.measReqMode = + (mr.MeasurementRequest[0].reserved << 3) | (mr. + MeasurementRequest[0]. + enable << 2) | (mr. + MeasurementRequest + [0]. + request + << 1) | + (mr.MeasurementRequest[0].report /*<< 0 */); + pMeasReqFrame->measReqIE.measType = + mr.MeasurementRequest[0].measurement_type; + + pMeasReqFrame->measReqIE.measReqField.channelNumber = + mr.MeasurementRequest[0].channel_no; + + qdf_mem_copy(pMeasReqFrame->measReqIE.measReqField.measStartTime, + mr.MeasurementRequest[0].meas_start_time, 8); + + pMeasReqFrame->measReqIE.measReqField.measDuration = + mr.MeasurementRequest[0].meas_duration; + + return QDF_STATUS_SUCCESS; + +} /* End sir_convert_meas_req_frame2_struct. */ +#endif + +void populate_dot11f_tspec(struct mac_tspec_ie *pOld, tDot11fIETSPEC *pDot11f) +{ + pDot11f->traffic_type = pOld->tsinfo.traffic.trafficType; + pDot11f->tsid = pOld->tsinfo.traffic.tsid; + pDot11f->direction = pOld->tsinfo.traffic.direction; + pDot11f->access_policy = pOld->tsinfo.traffic.accessPolicy; + pDot11f->aggregation = pOld->tsinfo.traffic.aggregation; + pDot11f->psb = pOld->tsinfo.traffic.psb; + pDot11f->user_priority = pOld->tsinfo.traffic.userPrio; + pDot11f->tsinfo_ack_pol = pOld->tsinfo.traffic.ackPolicy; + pDot11f->schedule = pOld->tsinfo.schedule.schedule; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + pDot11f->size = (pOld->nomMsduSz & 0x7fff); + pDot11f->fixed = (pOld->nomMsduSz & 0x8000) ? 1 : 0; + pDot11f->max_msdu_size = pOld->maxMsduSz; + pDot11f->min_service_int = pOld->minSvcInterval; + pDot11f->max_service_int = pOld->maxSvcInterval; + pDot11f->inactivity_int = pOld->inactInterval; + pDot11f->suspension_int = pOld->suspendInterval; + pDot11f->service_start_time = pOld->svcStartTime; + pDot11f->min_data_rate = pOld->minDataRate; + pDot11f->mean_data_rate = pOld->meanDataRate; + pDot11f->peak_data_rate = pOld->peakDataRate; + pDot11f->burst_size = pOld->maxBurstSz; + pDot11f->delay_bound = pOld->delayBound; + pDot11f->min_phy_rate = pOld->minPhyRate; + pDot11f->surplus_bw_allowance = pOld->surplusBw; + pDot11f->medium_time = pOld->mediumTime; + + pDot11f->present = 1; + +} /* End populate_dot11f_tspec. */ + +#ifdef WLAN_FEATURE_MSCS +void +populate_dot11f_mscs_dec_element(struct mscs_req_info *mscs_req, + tDot11fmscs_request_action_frame *dot11f) +{ + dot11f->descriptor_element.request_type = + mscs_req->dec.request_type; + dot11f->descriptor_element.user_priority_control = + mscs_req->dec.user_priority_control; + dot11f->descriptor_element.stream_timeout = + mscs_req->dec.stream_timeout; + dot11f->descriptor_element.tclas_mask.classifier_type = + mscs_req->dec.tclas_mask.classifier_type; + dot11f->descriptor_element.tclas_mask.classifier_mask = + mscs_req->dec.tclas_mask.classifier_mask; + + dot11f->descriptor_element.present = 1; + dot11f->descriptor_element.tclas_mask.present = 1; + +} /* End populate_dot11f_descriptor_element */ +#endif + +void populate_dot11f_wmmtspec(struct mac_tspec_ie *pOld, + tDot11fIEWMMTSPEC *pDot11f) +{ + pDot11f->traffic_type = pOld->tsinfo.traffic.trafficType; + pDot11f->tsid = pOld->tsinfo.traffic.tsid; + pDot11f->direction = pOld->tsinfo.traffic.direction; + pDot11f->access_policy = pOld->tsinfo.traffic.accessPolicy; + pDot11f->aggregation = pOld->tsinfo.traffic.aggregation; + pDot11f->psb = pOld->tsinfo.traffic.psb; + pDot11f->user_priority = pOld->tsinfo.traffic.userPrio; + pDot11f->tsinfo_ack_pol = pOld->tsinfo.traffic.ackPolicy; + pDot11f->burst_size_defn = pOld->tsinfo.traffic.burstSizeDefn; + /* As defined in IEEE 802.11-2007, section 7.3.2.30 + * Nominal MSDU size: Bit[0:14]=Size, Bit[15]=Fixed + */ + pDot11f->size = (pOld->nomMsduSz & 0x7fff); + pDot11f->fixed = (pOld->nomMsduSz & 0x8000) ? 1 : 0; + pDot11f->max_msdu_size = pOld->maxMsduSz; + pDot11f->min_service_int = pOld->minSvcInterval; + pDot11f->max_service_int = pOld->maxSvcInterval; + pDot11f->inactivity_int = pOld->inactInterval; + pDot11f->suspension_int = pOld->suspendInterval; + pDot11f->service_start_time = pOld->svcStartTime; + pDot11f->min_data_rate = pOld->minDataRate; + pDot11f->mean_data_rate = pOld->meanDataRate; + pDot11f->peak_data_rate = pOld->peakDataRate; + pDot11f->burst_size = pOld->maxBurstSz; + pDot11f->delay_bound = pOld->delayBound; + pDot11f->min_phy_rate = pOld->minPhyRate; + pDot11f->surplus_bw_allowance = pOld->surplusBw; + pDot11f->medium_time = pOld->mediumTime; + + pDot11f->version = 1; + pDot11f->present = 1; + +} /* End populate_dot11f_wmmtspec. */ + +#if defined(FEATURE_WLAN_ESE) +/* Fill the ESE version currently supported */ +void populate_dot11f_ese_version(tDot11fIEESEVersion *pESEVersion) +{ + pESEVersion->present = 1; + pESEVersion->version = ESE_VERSION_SUPPORTED; +} + +/* Fill the ESE ie for the station. */ +/* The State is Normal (1) */ +/* The MBSSID for station is set to 0. */ +void populate_dot11f_ese_rad_mgmt_cap(tDot11fIEESERadMgmtCap *pESERadMgmtCap) +{ + pESERadMgmtCap->present = 1; + pESERadMgmtCap->mgmt_state = RM_STATE_NORMAL; + pESERadMgmtCap->mbssid_mask = 0; + pESERadMgmtCap->reserved = 0; +} + +QDF_STATUS +populate_dot11f_ese_cckm_opaque(struct mac_context *mac, + struct mlme_connect_info *connect_info, + tDot11fIEESECckmOpaque *pDot11f) +{ + int idx; + tSirRSNie ie; + + if (connect_info->cckm_ie_len && + connect_info->cckm_ie_len < DOT11F_IE_RSN_MAX_LEN) { + qdf_mem_copy(ie.rsnIEdata, connect_info->cckm_ie, + connect_info->cckm_ie_len); + ie.length = connect_info->cckm_ie_len; + idx = find_ie_location(mac, &ie, DOT11F_EID_ESECCKMOPAQUE); + if (idx >= 0) { + pDot11f->present = 1; + /* Dont include OUI */ + pDot11f->num_data = ie.rsnIEdata[idx + 1] - 4; + qdf_mem_copy(pDot11f->data, ie.rsnIEdata + idx + 2 + 4, /* EID,len,OUI */ + ie.rsnIEdata[idx + 1] - 4); /* Skip OUI */ + } + } + return QDF_STATUS_SUCCESS; +} /* End populate_dot11f_ese_cckm_opaque. */ + +void populate_dot11_tsrsie(struct mac_context *mac, + struct ese_tsrs_ie *pOld, + tDot11fIEESETrafStrmRateSet *pDot11f, + uint8_t rate_length) +{ + pDot11f->tsid = pOld->tsid; + qdf_mem_copy(pDot11f->tsrates, pOld->rates, rate_length); + pDot11f->num_tsrates = rate_length; + pDot11f->present = 1; +} +#endif + +QDF_STATUS +populate_dot11f_tclas(struct mac_context *mac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pDot11f) +{ + pDot11f->user_priority = pOld->tclas.userPrio; + pDot11f->classifier_type = pOld->tclas.classifierType; + pDot11f->classifier_mask = pOld->tclas.classifierMask; + + switch (pDot11f->classifier_type) { + case SIR_MAC_TCLASTYPE_ETHERNET: + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.source, + (uint8_t *) &pOld->tclasParams.eth.srcAddr, 6); + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.dest, + (uint8_t *) &pOld->tclasParams.eth.dstAddr, 6); + pDot11f->info.EthParams.type = pOld->tclasParams.eth.type; + break; + case SIR_MAC_TCLASTYPE_TCPUDPIP: + pDot11f->info.IpParams.version = pOld->version; + if (SIR_MAC_TCLAS_IPV4 == pDot11f->info.IpParams.version) { + qdf_mem_copy(pDot11f->info.IpParams.params.IpV4Params. + source, pOld->tclasParams.ipv4.srcIpAddr, + 4); + qdf_mem_copy(pDot11f->info.IpParams.params.IpV4Params. + dest, pOld->tclasParams.ipv4.dstIpAddr, 4); + pDot11f->info.IpParams.params.IpV4Params.src_port = + pOld->tclasParams.ipv4.srcPort; + pDot11f->info.IpParams.params.IpV4Params.dest_port = + pOld->tclasParams.ipv4.dstPort; + pDot11f->info.IpParams.params.IpV4Params.DSCP = + pOld->tclasParams.ipv4.dscp; + pDot11f->info.IpParams.params.IpV4Params.proto = + pOld->tclasParams.ipv4.protocol; + pDot11f->info.IpParams.params.IpV4Params.reserved = + pOld->tclasParams.ipv4.rsvd; + } else { + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.source, + (uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, 16); + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.dest, + (uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, 16); + pDot11f->info.IpParams.params.IpV6Params.src_port = + pOld->tclasParams.ipv6.srcPort; + pDot11f->info.IpParams.params.IpV6Params.dest_port = + pOld->tclasParams.ipv6.dstPort; + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.flow_label, + (uint8_t *) pOld->tclasParams.ipv6. + flowLabel, 3); + } + break; + case SIR_MAC_TCLASTYPE_8021DQ: + pDot11f->info.Params8021dq.tag_type = + pOld->tclasParams.t8021dq.tag; + break; + default: + pe_err("Bad TCLAS type %d", pDot11f->classifier_type); + return QDF_STATUS_E_FAILURE; + } + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_tclas. */ + +QDF_STATUS +populate_dot11f_wmmtclas(struct mac_context *mac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pDot11f) +{ + pDot11f->version = 1; + pDot11f->user_priority = pOld->tclas.userPrio; + pDot11f->classifier_type = pOld->tclas.classifierType; + pDot11f->classifier_mask = pOld->tclas.classifierMask; + + switch (pDot11f->classifier_type) { + case SIR_MAC_TCLASTYPE_ETHERNET: + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.source, + (uint8_t *) &pOld->tclasParams.eth.srcAddr, 6); + qdf_mem_copy((uint8_t *) &pDot11f->info.EthParams.dest, + (uint8_t *) &pOld->tclasParams.eth.dstAddr, 6); + pDot11f->info.EthParams.type = pOld->tclasParams.eth.type; + break; + case SIR_MAC_TCLASTYPE_TCPUDPIP: + pDot11f->info.IpParams.version = pOld->version; + if (SIR_MAC_TCLAS_IPV4 == pDot11f->info.IpParams.version) { + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV4Params.source, + (uint8_t *) pOld->tclasParams.ipv4. + srcIpAddr, 4); + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV4Params.dest, + (uint8_t *) pOld->tclasParams.ipv4. + dstIpAddr, 4); + pDot11f->info.IpParams.params.IpV4Params.src_port = + pOld->tclasParams.ipv4.srcPort; + pDot11f->info.IpParams.params.IpV4Params.dest_port = + pOld->tclasParams.ipv4.dstPort; + pDot11f->info.IpParams.params.IpV4Params.DSCP = + pOld->tclasParams.ipv4.dscp; + pDot11f->info.IpParams.params.IpV4Params.proto = + pOld->tclasParams.ipv4.protocol; + pDot11f->info.IpParams.params.IpV4Params.reserved = + pOld->tclasParams.ipv4.rsvd; + } else { + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.source, + (uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, 16); + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.dest, + (uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, 16); + pDot11f->info.IpParams.params.IpV6Params.src_port = + pOld->tclasParams.ipv6.srcPort; + pDot11f->info.IpParams.params.IpV6Params.dest_port = + pOld->tclasParams.ipv6.dstPort; + qdf_mem_copy((uint8_t *) &pDot11f->info.IpParams. + params.IpV6Params.flow_label, + (uint8_t *) pOld->tclasParams.ipv6. + flowLabel, 3); + } + break; + case SIR_MAC_TCLASTYPE_8021DQ: + pDot11f->info.Params8021dq.tag_type = + pOld->tclasParams.t8021dq.tag; + break; + default: + pe_err("Bad TCLAS type %d in populate_dot11f_tclas", + pDot11f->classifier_type); + return QDF_STATUS_E_FAILURE; + } + + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; + +} /* End populate_dot11f_wmmtclas. */ + +QDF_STATUS populate_dot11f_wsc(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f) +{ + + uint32_t wpsState; + + pDot11f->Version.present = 1; + pDot11f->Version.major = 0x01; + pDot11f->Version.minor = 0x00; + + wpsState = mac->mlme_cfg->wps_params.wps_state; + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) wpsState; + + pDot11f->APSetupLocked.present = 0; + + pDot11f->SelectedRegistrar.present = 0; + + pDot11f->DevicePasswordID.present = 0; + + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + pDot11f->UUID_E.present = 0; + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_wsc_registrar_info(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(mac->lim.wscIeInfo); + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + (uint16_t)mac->mlme_cfg->wps_params.wps_device_password_id; + + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pWscIeInfo->selectedRegistrarConfigMethods; + + /* UUID_E and RF Bands are applicable only for dual band AP */ + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS de_populate_dot11f_wsc_registrar_info(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f) +{ + pDot11f->APSetupLocked.present = 0; + pDot11f->SelectedRegistrar.present = 0; + pDot11f->DevicePasswordID.present = 0; + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_probe_res_wpsi_es(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f, + struct pe_session *pe_session) +{ + + tSirWPSProbeRspIE *pSirWPSProbeRspIE; + + pSirWPSProbeRspIE = &pe_session->APWPSIEs.SirWPSProbeRspIE; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSProbeRspIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSProbeRspIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_STATE_PRESENT) { + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) pSirWPSProbeRspIE->wpsState; + } else + pDot11f->WPSState.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_APSETUPLOCK_PRESENT) { + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = + pSirWPSProbeRspIE->APSetupLocked; + } else + pDot11f->APSetupLocked.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SELECTEDREGISTRA_PRESENT) { + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = + pSirWPSProbeRspIE->SelectedRegistra; + } else + pDot11f->SelectedRegistrar.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_DEVICEPASSWORDID_PRESENT) { + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + pSirWPSProbeRspIE->DevicePasswordID; + } else + pDot11f->DevicePasswordID.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SELECTEDREGISTRACFGMETHOD_PRESENT) { + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pSirWPSProbeRspIE->SelectedRegistraCfgMethod; + } else + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_RESPONSETYPE_PRESENT) { + pDot11f->ResponseType.present = 1; + pDot11f->ResponseType.resType = pSirWPSProbeRspIE->ResponseType; + } else + pDot11f->ResponseType.present = 0; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_UUIDE_PRESENT) { + pDot11f->UUID_E.present = 1; + qdf_mem_copy(pDot11f->UUID_E.uuid, pSirWPSProbeRspIE->UUID_E, + WNI_CFG_WPS_UUID_LEN); + } else + pDot11f->UUID_E.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MANUFACTURE_PRESENT) { + pDot11f->Manufacturer.present = 1; + pDot11f->Manufacturer.num_name = + pSirWPSProbeRspIE->Manufacture.num_name; + qdf_mem_copy(pDot11f->Manufacturer.name, + pSirWPSProbeRspIE->Manufacture.name, + pSirWPSProbeRspIE->Manufacture.num_name); + } else + pDot11f->Manufacturer.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MODELNUMBER_PRESENT) { + pDot11f->ModelName.present = 1; + pDot11f->ModelName.num_text = + pSirWPSProbeRspIE->ModelName.num_text; + qdf_mem_copy(pDot11f->ModelName.text, + pSirWPSProbeRspIE->ModelName.text, + pDot11f->ModelName.num_text); + } else + pDot11f->ModelName.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_MODELNUMBER_PRESENT) { + pDot11f->ModelNumber.present = 1; + pDot11f->ModelNumber.num_text = + pSirWPSProbeRspIE->ModelNumber.num_text; + qdf_mem_copy(pDot11f->ModelNumber.text, + pSirWPSProbeRspIE->ModelNumber.text, + pDot11f->ModelNumber.num_text); + } else + pDot11f->ModelNumber.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_SERIALNUMBER_PRESENT) { + pDot11f->SerialNumber.present = 1; + pDot11f->SerialNumber.num_text = + pSirWPSProbeRspIE->SerialNumber.num_text; + qdf_mem_copy(pDot11f->SerialNumber.text, + pSirWPSProbeRspIE->SerialNumber.text, + pDot11f->SerialNumber.num_text); + } else + pDot11f->SerialNumber.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_PRIMARYDEVICETYPE_PRESENT) { + pDot11f->PrimaryDeviceType.present = 1; + qdf_mem_copy(pDot11f->PrimaryDeviceType.oui, + pSirWPSProbeRspIE->PrimaryDeviceOUI, + sizeof(pSirWPSProbeRspIE->PrimaryDeviceOUI)); + pDot11f->PrimaryDeviceType.primary_category = + (uint16_t) pSirWPSProbeRspIE->PrimaryDeviceCategory; + pDot11f->PrimaryDeviceType.sub_category = + (uint16_t) pSirWPSProbeRspIE->DeviceSubCategory; + } else + pDot11f->PrimaryDeviceType.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_DEVICENAME_PRESENT) { + pDot11f->DeviceName.present = 1; + pDot11f->DeviceName.num_text = + pSirWPSProbeRspIE->DeviceName.num_text; + qdf_mem_copy(pDot11f->DeviceName.text, + pSirWPSProbeRspIE->DeviceName.text, + pDot11f->DeviceName.num_text); + } else + pDot11f->DeviceName.present = 0; + + if (pSirWPSProbeRspIE-> + FieldPresent & SIR_WPS_PROBRSP_CONFIGMETHODS_PRESENT) { + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + pSirWPSProbeRspIE->ConfigMethod; + } else + pDot11f->ConfigMethods.present = 0; + + if (pSirWPSProbeRspIE->FieldPresent & SIR_WPS_PROBRSP_RF_BANDS_PRESENT) { + pDot11f->RFBands.present = 1; + pDot11f->RFBands.bands = pSirWPSProbeRspIE->RFBand; + } else + pDot11f->RFBands.present = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_beacon_wpsi_es(struct mac_context *mac, + tDot11fIEWscBeacon *pDot11f, + struct pe_session *pe_session) +{ + + tSirWPSBeaconIE *pSirWPSBeaconIE; + + pSirWPSBeaconIE = &pe_session->APWPSIEs.SirWPSBeaconIE; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_PROBRSP_VER_PRESENT) { + pDot11f->present = 1; + pDot11f->Version.present = 1; + pDot11f->Version.major = + (uint8_t) ((pSirWPSBeaconIE->Version & 0xF0) >> 4); + pDot11f->Version.minor = + (uint8_t) (pSirWPSBeaconIE->Version & 0x0F); + } else { + pDot11f->present = 0; + pDot11f->Version.present = 0; + } + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_STATE_PRESENT) { + + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) pSirWPSBeaconIE->wpsState; + } else + pDot11f->WPSState.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_APSETUPLOCK_PRESENT) { + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pSirWPSBeaconIE->APSetupLocked; + } else + pDot11f->APSetupLocked.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_SELECTEDREGISTRA_PRESENT) { + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = + pSirWPSBeaconIE->SelectedRegistra; + } else + pDot11f->SelectedRegistrar.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_DEVICEPASSWORDID_PRESENT) { + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + pSirWPSBeaconIE->DevicePasswordID; + } else + pDot11f->DevicePasswordID.present = 0; + + if (pSirWPSBeaconIE-> + FieldPresent & SIR_WPS_BEACON_SELECTEDREGISTRACFGMETHOD_PRESENT) { + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pSirWPSBeaconIE->SelectedRegistraCfgMethod; + } else + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_UUIDE_PRESENT) { + pDot11f->UUID_E.present = 1; + qdf_mem_copy(pDot11f->UUID_E.uuid, pSirWPSBeaconIE->UUID_E, + WNI_CFG_WPS_UUID_LEN); + } else + pDot11f->UUID_E.present = 0; + + if (pSirWPSBeaconIE->FieldPresent & SIR_WPS_BEACON_RF_BANDS_PRESENT) { + pDot11f->RFBands.present = 1; + pDot11f->RFBands.bands = pSirWPSBeaconIE->RFBand; + } else + pDot11f->RFBands.present = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_wsc_in_probe_res(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f) +{ + uint32_t cfgStrLen; + uint32_t val; + uint32_t wpsVersion, wpsState; + + wpsVersion = mac->mlme_cfg->wps_params.wps_version; + + pDot11f->Version.present = 1; + pDot11f->Version.major = (uint8_t) ((wpsVersion & 0xF0) >> 4); + pDot11f->Version.minor = (uint8_t) (wpsVersion & 0x0F); + + wpsState = mac->mlme_cfg->wps_params.wps_state; + pDot11f->WPSState.present = 1; + pDot11f->WPSState.state = (uint8_t) wpsState; + + pDot11f->APSetupLocked.present = 0; + + pDot11f->SelectedRegistrar.present = 0; + + pDot11f->DevicePasswordID.present = 0; + + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + pDot11f->ResponseType.present = 1; + if ((mac->lim.wscIeInfo.reqType == REQ_TYPE_REGISTRAR) || + (mac->lim.wscIeInfo.reqType == REQ_TYPE_WLAN_MANAGER_REGISTRAR)) { + pDot11f->ResponseType.resType = RESP_TYPE_ENROLLEE_OPEN_8021X; + } else { + pDot11f->ResponseType.resType = RESP_TYPE_AP; + } + + /* UUID is a 16 byte long binary*/ + pDot11f->UUID_E.present = 1; + *pDot11f->UUID_E.uuid = '\0'; + + wlan_mlme_get_wps_uuid(&mac->mlme_cfg->wps_params, + pDot11f->UUID_E.uuid); + + pDot11f->Manufacturer.present = 1; + cfgStrLen = sizeof(pDot11f->Manufacturer.name); + if (wlan_mlme_get_manufacturer_name(mac->psoc, + pDot11f->Manufacturer.name, + &cfgStrLen) != QDF_STATUS_SUCCESS) { + pDot11f->Manufacturer.num_name = 0; + } else { + pDot11f->Manufacturer.num_name = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ModelName.present = 1; + cfgStrLen = sizeof(pDot11f->ModelName.text); + if (wlan_mlme_get_model_name(mac->psoc, + pDot11f->ModelName.text, + &cfgStrLen) != QDF_STATUS_SUCCESS) { + pDot11f->ModelName.num_text = 0; + } else { + pDot11f->ModelName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ModelNumber.present = 1; + cfgStrLen = sizeof(pDot11f->ModelNumber.text); + if (wlan_mlme_get_model_number(mac->psoc, + pDot11f->ModelNumber.text, + &cfgStrLen) != QDF_STATUS_SUCCESS) { + pDot11f->ModelNumber.num_text = 0; + } else { + pDot11f->ModelNumber.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->SerialNumber.present = 1; + cfgStrLen = sizeof(pDot11f->SerialNumber.text); + if (wlan_mlme_get_manufacture_product_version + (mac->psoc, + pDot11f->SerialNumber.text, + &cfgStrLen) != QDF_STATUS_SUCCESS) { + pDot11f->SerialNumber.num_text = 0; + } else { + pDot11f->SerialNumber.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->PrimaryDeviceType.present = 1; + + pDot11f->PrimaryDeviceType.primary_category = + (uint16_t)mac->mlme_cfg->wps_params.wps_primary_device_category; + + val = mac->mlme_cfg->wps_params.wps_primary_device_oui; + *(pDot11f->PrimaryDeviceType.oui) = + (uint8_t) ((val >> 24) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 1) = + (uint8_t) ((val >> 16) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 2) = + (uint8_t) ((val >> 8) & 0xff); + *(pDot11f->PrimaryDeviceType.oui + 3) = + (uint8_t) ((val & 0xff)); + + pDot11f->PrimaryDeviceType.sub_category = + (uint16_t)mac->mlme_cfg->wps_params.wps_device_sub_category; + + + pDot11f->DeviceName.present = 1; + cfgStrLen = sizeof(pDot11f->DeviceName.text); + if (wlan_mlme_get_manufacture_product_name(mac->psoc, + pDot11f->DeviceName.text, + &cfgStrLen) != + QDF_STATUS_SUCCESS) { + pDot11f->DeviceName.num_text = 0; + } else { + pDot11f->DeviceName.num_text = + (uint8_t) (cfgStrLen & 0x000000FF); + } + + pDot11f->ConfigMethods.present = 1; + pDot11f->ConfigMethods.methods = + (uint16_t)(mac->mlme_cfg->wps_params.wps_cfg_method & + 0x0000FFFF); + + pDot11f->RFBands.present = 0; + + pDot11f->present = 1; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_wsc_registrar_info_in_probe_res(struct mac_context *mac, + tDot11fIEWscProbeRes *pDot11f) +{ + const struct sLimWscIeInfo *const pWscIeInfo = &(mac->lim.wscIeInfo); + + pDot11f->APSetupLocked.present = 1; + pDot11f->APSetupLocked.fLocked = pWscIeInfo->apSetupLocked; + + pDot11f->SelectedRegistrar.present = 1; + pDot11f->SelectedRegistrar.selected = pWscIeInfo->selectedRegistrar; + + pDot11f->DevicePasswordID.present = 1; + pDot11f->DevicePasswordID.id = + (uint16_t)mac->mlme_cfg->wps_params.wps_device_password_id; + + pDot11f->SelectedRegistrarConfigMethods.present = 1; + pDot11f->SelectedRegistrarConfigMethods.methods = + pWscIeInfo->selectedRegistrarConfigMethods; + + /* UUID_E and RF Bands are applicable only for dual band AP */ + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +de_populate_dot11f_wsc_registrar_info_in_probe_res(struct mac_context *mac, + tDot11fIEWscProbeRes * + pDot11f) +{ + pDot11f->APSetupLocked.present = 0; + pDot11f->SelectedRegistrar.present = 0; + pDot11f->DevicePasswordID.present = 0; + pDot11f->SelectedRegistrarConfigMethods.present = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11_assoc_res_p2p_ie(struct mac_context *mac, + tDot11fIEP2PAssocRes *pDot11f, + tpSirAssocReq pRcvdAssocReq) +{ + const uint8_t *p2pIe; + + p2pIe = limGetP2pIEPtr(mac, pRcvdAssocReq->addIE.addIEdata, + pRcvdAssocReq->addIE.length); + if (p2pIe) { + pDot11f->present = 1; + pDot11f->P2PStatus.present = 1; + pDot11f->P2PStatus.status = QDF_STATUS_SUCCESS; + pDot11f->ExtendedListenTiming.present = 0; + } + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS populate_dot11f_wfatpc(struct mac_context *mac, + tDot11fIEWFATPC *pDot11f, uint8_t txPower, + uint8_t linkMargin) +{ + pDot11f->txPower = txPower; + pDot11f->linkMargin = linkMargin; + pDot11f->present = 1; + + return QDF_STATUS_SUCCESS; +} + +void +populate_dot11f_chan_load_report(struct mac_context *mac, + tDot11fIEMeasurementReport *dot11f, + struct chan_load_report *channel_load_report) +{ + dot11f->report.channel_load_report.op_class = + channel_load_report->op_class; + dot11f->report.channel_load_report.channel = + channel_load_report->channel; + qdf_mem_copy(dot11f->report.channel_load_report.meas_start_time, + &channel_load_report->rrm_scan_tsf, + sizeof(dot11f->report.channel_load_report.meas_start_time)); + dot11f->report.channel_load_report.meas_duration = + channel_load_report->meas_duration; + dot11f->report.channel_load_report.chan_load = + channel_load_report->chan_load; + + if (channel_load_report->wide_bw.is_wide_bw_chan_switch) { + dot11f->report.channel_load_report.wide_bw_chan_switch.present = 1; + dot11f->report.channel_load_report.wide_bw_chan_switch.new_chan_width = channel_load_report->wide_bw.channel_width; + dot11f->report.channel_load_report.wide_bw_chan_switch.new_center_chan_freq0 = channel_load_report->wide_bw.center_chan_freq0; + dot11f->report.channel_load_report.wide_bw_chan_switch.new_center_chan_freq1 = channel_load_report->wide_bw.center_chan_freq1; + } + + if (channel_load_report->bw_ind.is_bw_ind_element) { + dot11f->report.channel_load_report.bw_indication.present = 1; + dot11f->report.channel_load_report.bw_indication.channel_width = channel_load_report->bw_ind.channel_width; + dot11f->report.channel_load_report.bw_indication.ccfs0 = channel_load_report->bw_ind.center_freq_seg0; + dot11f->report.channel_load_report.bw_indication.ccfs1 = channel_load_report->bw_ind.center_freq_seg1; + } + + pe_debug("regClass %d chan %d meas_time %lu meas_dur %d, chan_load %d", + dot11f->report.channel_load_report.op_class, + dot11f->report.channel_load_report.channel, + channel_load_report->rrm_scan_tsf, + dot11f->report.channel_load_report.meas_duration, + dot11f->report.channel_load_report.chan_load); +} + +static void +populate_dot11f_rrm_counter_stats(tDot11fIEMeasurementReport *pdot11f, + struct counter_stats *counter_stats, + bool *reporting_reason_present) +{ + tDot11fIEreporting_reason *reporting_reason; + + reporting_reason = &pdot11f->report.sta_stats.reporting_reason; + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_fragment_count = + counter_stats->transmitted_fragment_count; + + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.group_transmitted_frame_count = + counter_stats->group_transmitted_frame_count; + + if (counter_stats->failed_count) { + reporting_reason->failed_count = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.failed_count = + counter_stats->failed_count; + + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.received_fragment_count = + counter_stats->received_fragment_count; + + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.group_received_frame_count = + counter_stats->group_received_frame_count; + + if (counter_stats->fcs_error_count) { + reporting_reason->fcs_error = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.fcs_error_count = + counter_stats->fcs_error_count; + + pdot11f->report.sta_stats.statsgroupdata.dot11_counter_stats.transmitted_frame_count = + counter_stats->transmitted_frame_count; +} + +static void +populate_dot11f_rrm_mac_stats(tDot11fIEMeasurementReport *pdot11f, + struct mac_stats *mac_stats, + bool *reporting_reason_present) +{ + tDot11fIEreporting_reason *reporting_reason; + + reporting_reason = &pdot11f->report.sta_stats.reporting_reason; + if (mac_stats->retry_count) { + reporting_reason->retry = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.retry_count = + mac_stats->retry_count; + + if (mac_stats->multiple_retry_count) { + reporting_reason->multiple_retry = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.multiple_retry_count = + mac_stats->multiple_retry_count; + + if (mac_stats->frame_duplicate_count) { + reporting_reason->frame_duplicate = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.frame_duplicate_count = + mac_stats->frame_duplicate_count; + + pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_success_count = + mac_stats->rts_success_count; + + if (mac_stats->rts_failure_count) { + reporting_reason->rts_failure = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.rts_failure_count = + mac_stats->rts_failure_count; + + if (mac_stats->ack_failure_count) { + reporting_reason->ack_failure = 1; + *reporting_reason_present = true; + } + pdot11f->report.sta_stats.statsgroupdata.dot11_mac_stats.ack_failure_count = + mac_stats->ack_failure_count; +} + +static void +populate_dot11f_rrm_access_delay_stats( + tDot11fIEMeasurementReport *pdot11f, + struct access_delay_stats *access_delay_stats) +{ + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.ap_average_access_delay = + access_delay_stats->ap_average_access_delay; + + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_besteffort = + access_delay_stats->average_access_delay_besteffort; + + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_background = + access_delay_stats->average_access_delay_background; + + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_video = + access_delay_stats->average_access_delay_video; + + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.average_access_delay_voice = + access_delay_stats->average_access_delay_voice; + + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.station_count = + access_delay_stats->station_count; + + pdot11f->report.sta_stats.statsgroupdata.dot11_bss_average_access_delay.channel_utilization = + access_delay_stats->channel_utilization; +} + +QDF_STATUS +populate_dot11f_rrm_sta_stats_report( + struct mac_context *mac, tDot11fIEMeasurementReport *pdot11f, + struct statistics_report *statistics_report) +{ + struct counter_stats counter_stats; + struct mac_stats mac_stats; + struct access_delay_stats access_delay_stats; + bool reporting_reason_present = false; + + counter_stats = statistics_report->group_stats.counter_stats; + mac_stats = statistics_report->group_stats.mac_stats; + access_delay_stats = statistics_report->group_stats.access_delay_stats; + + pdot11f->report.sta_stats.meas_duration = + statistics_report->meas_duration; + pdot11f->report.sta_stats.group_id = statistics_report->group_id; + pdot11f->report.sta_stats.reporting_reason.present = 0; + + switch (statistics_report->group_id) { + case STA_STAT_GROUP_ID_COUNTER_STATS: + populate_dot11f_rrm_counter_stats(pdot11f, &counter_stats, + &reporting_reason_present); + break; + case STA_STAT_GROUP_ID_MAC_STATS: + populate_dot11f_rrm_mac_stats(pdot11f, &mac_stats, + &reporting_reason_present); + break; + case STA_STAT_GROUP_ID_DELAY_STATS: + populate_dot11f_rrm_access_delay_stats(pdot11f, + &access_delay_stats); + break; + default: + pe_err("group id not supported %d", + statistics_report->group_id); + return QDF_STATUS_SUCCESS; + } + if (reporting_reason_present) + pdot11f->report.sta_stats.reporting_reason.present = 1; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_beacon_report(struct mac_context *mac, + tDot11fIEMeasurementReport *pDot11f, + tSirMacBeaconReport *pBeaconReport, + bool is_last_frame) +{ + tDot11fIEbeacon_report_frm_body_fragment_id *frm_body_frag_id; + + pDot11f->report.Beacon.regClass = pBeaconReport->regClass; + pDot11f->report.Beacon.channel = pBeaconReport->channel; + qdf_mem_copy(pDot11f->report.Beacon.meas_start_time, + pBeaconReport->measStartTime, + sizeof(pDot11f->report.Beacon.meas_start_time)); + pDot11f->report.Beacon.meas_duration = pBeaconReport->measDuration; + pDot11f->report.Beacon.condensed_PHY = pBeaconReport->phyType; + pDot11f->report.Beacon.reported_frame_type = + !pBeaconReport->bcnProbeRsp; + pDot11f->report.Beacon.RCPI = pBeaconReport->rcpi; + pDot11f->report.Beacon.RSNI = pBeaconReport->rsni; + qdf_mem_copy(pDot11f->report.Beacon.BSSID, pBeaconReport->bssid, + sizeof(tSirMacAddr)); + pDot11f->report.Beacon.antenna_id = pBeaconReport->antennaId; + pDot11f->report.Beacon.parent_TSF = pBeaconReport->parentTSF; + + if (pBeaconReport->numIes) { + pDot11f->report.Beacon.BeaconReportFrmBody.present = 1; + qdf_mem_copy(pDot11f->report.Beacon.BeaconReportFrmBody. + reportedFields, pBeaconReport->Ies, + pBeaconReport->numIes); + pDot11f->report.Beacon.BeaconReportFrmBody.num_reportedFields = + pBeaconReport->numIes; + } + + if (pBeaconReport->last_bcn_report_ind_support) { + pe_debug("Including Last Beacon Report in RRM Frame"); + frm_body_frag_id = &pDot11f->report.Beacon. + beacon_report_frm_body_fragment_id; + + frm_body_frag_id->present = 1; + frm_body_frag_id->beacon_report_id = + pBeaconReport->frame_body_frag_id.id; + frm_body_frag_id->fragment_id_number = + pBeaconReport->frame_body_frag_id.frag_id; + frm_body_frag_id->more_fragments = + pBeaconReport->frame_body_frag_id.more_frags; + + pDot11f->report.Beacon.last_beacon_report_indication.present = + 1; + + pDot11f->report.Beacon.last_beacon_report_indication. + last_fragment = is_last_frame; + pe_debug("id %d frag_id %d more_frags %d is_last_frame %d", + frm_body_frag_id->beacon_report_id, + frm_body_frag_id->fragment_id_number, + frm_body_frag_id->more_fragments, + is_last_frame); + } + return QDF_STATUS_SUCCESS; + +} + +QDF_STATUS populate_dot11f_rrm_ie(struct mac_context *mac, + tDot11fIERRMEnabledCap *pDot11f, + struct pe_session *pe_session) +{ + tpRRMCaps pRrmCaps; + uint8_t *bytes; + + pRrmCaps = rrm_get_capabilities(mac, pe_session); + + pDot11f->LinkMeasurement = pRrmCaps->LinkMeasurement; + pDot11f->NeighborRpt = pRrmCaps->NeighborRpt; + pDot11f->parallel = pRrmCaps->parallel; + pDot11f->repeated = pRrmCaps->repeated; + pDot11f->BeaconPassive = pRrmCaps->BeaconPassive; + pDot11f->BeaconActive = pRrmCaps->BeaconActive; + pDot11f->BeaconTable = pRrmCaps->BeaconTable; + pDot11f->BeaconRepCond = pRrmCaps->BeaconRepCond; + pDot11f->FrameMeasurement = pRrmCaps->FrameMeasurement; + pDot11f->ChannelLoad = pRrmCaps->ChannelLoad; + pDot11f->NoiseHistogram = pRrmCaps->NoiseHistogram; + pDot11f->statistics = pRrmCaps->statistics; + pDot11f->LCIMeasurement = pRrmCaps->LCIMeasurement; + pDot11f->LCIAzimuth = pRrmCaps->LCIAzimuth; + pDot11f->TCMCapability = pRrmCaps->TCMCapability; + pDot11f->triggeredTCM = pRrmCaps->triggeredTCM; + pDot11f->APChanReport = pRrmCaps->APChanReport; + pDot11f->RRMMIBEnabled = pRrmCaps->RRMMIBEnabled; + pDot11f->operatingChanMax = pRrmCaps->operatingChanMax; + pDot11f->nonOperatinChanMax = pRrmCaps->nonOperatingChanMax; + pDot11f->MeasurementPilot = pRrmCaps->MeasurementPilot; + pDot11f->MeasurementPilotEnabled = pRrmCaps->MeasurementPilotEnabled; + pDot11f->NeighborTSFOffset = pRrmCaps->NeighborTSFOffset; + pDot11f->RCPIMeasurement = pRrmCaps->RCPIMeasurement; + pDot11f->RSNIMeasurement = pRrmCaps->RSNIMeasurement; + pDot11f->BssAvgAccessDelay = pRrmCaps->BssAvgAccessDelay; + pDot11f->BSSAvailAdmission = pRrmCaps->BSSAvailAdmission; + pDot11f->AntennaInformation = pRrmCaps->AntennaInformation; + pDot11f->fine_time_meas_rpt = pRrmCaps->fine_time_meas_rpt; + pDot11f->lci_capability = pRrmCaps->lci_capability; + pDot11f->reserved = pRrmCaps->reserved; + + bytes = (uint8_t *) pDot11f + 1; /* ignore present field */ + pe_debug("RRM Enabled Cap IE: %02x %02x %02x %02x %02x", + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]); + + pDot11f->present = 1; + return QDF_STATUS_SUCCESS; +} + +void populate_mdie(struct mac_context *mac, + tDot11fIEMobilityDomain *pDot11f, + uint8_t mdie[]) +{ + pDot11f->present = 1; + pDot11f->MDID = (uint16_t) ((mdie[1] << 8) | (mdie[0])); + + /* Plugfest fix */ + pDot11f->overDSCap = (mdie[2] & 0x01); + pDot11f->resourceReqCap = ((mdie[2] >> 1) & 0x01); + +} + +#ifdef WLAN_FEATURE_FILS_SK +void populate_fils_ft_info(struct mac_context *mac, tDot11fIEFTInfo *ft_info, + struct pe_session *pe_session) +{ + struct pe_fils_session *ft_fils_info = pe_session->fils_info; + + if (!ft_fils_info) + return; + + if (!ft_fils_info->ft_ie.present) { + ft_info->present = 0; + pe_err("FT IE doesn't exist"); + return; + } + + ft_info->IECount = ft_fils_info->ft_ie.element_count; + + qdf_mem_copy(ft_info->MIC, ft_fils_info->ft_ie.mic, + FT_MIC_LEN); + + qdf_mem_copy(ft_info->Anonce, ft_fils_info->ft_ie.anonce, + FT_NONCE_LEN); + + qdf_mem_copy(ft_info->Snonce, ft_fils_info->ft_ie.snonce, + FT_NONCE_LEN); + + if (ft_fils_info->ft_ie.r0kh_id_len > 0) { + ft_info->R0KH_ID.present = 1; + qdf_mem_copy(ft_info->R0KH_ID.PMK_R0_ID, + ft_fils_info->ft_ie.r0kh_id, + ft_fils_info->ft_ie.r0kh_id_len); + ft_info->R0KH_ID.num_PMK_R0_ID = + ft_fils_info->ft_ie.r0kh_id_len; + } + + ft_info->R1KH_ID.present = 1; + qdf_mem_copy(ft_info->R1KH_ID.PMK_R1_ID, + ft_fils_info->ft_ie.r1kh_id, + FT_R1KH_ID_LEN); + + qdf_mem_copy(&ft_info->GTK, &ft_fils_info->ft_ie.gtk_ie, + sizeof(struct mac_ft_gtk_ie)); + qdf_mem_copy(&ft_info->IGTK, &ft_fils_info->ft_ie.igtk_ie, + sizeof(struct mac_ft_igtk_ie)); + + ft_info->present = 1; +} +#endif + +void populate_dot11f_assoc_rsp_rates(struct mac_context *mac, + tDot11fIESuppRates *pSupp, + tDot11fIEExtSuppRates *pExt, + uint16_t *_11bRates, uint16_t *_11aRates) +{ + uint8_t num_supp = 0, num_ext = 0; + uint8_t i, j; + + for (i = 0; (i < SIR_NUM_11B_RATES && _11bRates[i]); i++, num_supp++) { + pSupp->rates[num_supp] = (uint8_t) _11bRates[i]; + } + for (j = 0; (j < SIR_NUM_11A_RATES && _11aRates[j]); j++) { + if (num_supp < 8) + pSupp->rates[num_supp++] = (uint8_t) _11aRates[j]; + else + pExt->rates[num_ext++] = (uint8_t) _11aRates[j]; + } + + if (num_supp) { + pSupp->num_rates = num_supp; + pSupp->present = 1; + } + if (num_ext) { + pExt->num_rates = num_ext; + pExt->present = 1; + } +} + +void populate_dot11f_timeout_interval(struct mac_context *mac, + tDot11fIETimeoutInterval *pDot11f, + uint8_t type, uint32_t value) +{ + pDot11f->present = 1; + pDot11f->timeoutType = type; + pDot11f->timeoutValue = value; +} + +/** + * populate_dot11f_timing_advert_frame() - Populate the TA mgmt frame fields + * @mac_ctx: the MAC context + * @frame: pointer to the TA frame + * + * Return: The SIR status. + */ +QDF_STATUS +populate_dot11f_timing_advert_frame(struct mac_context *mac_ctx, + tDot11fTimingAdvertisementFrame *frame) +{ + uint32_t val = 0; + + /* Capabilities */ + val = mac_ctx->mlme_cfg->wep_params.is_privacy_enabled; + if (val) + frame->Capabilities.privacy = 1; + + if (mac_ctx->mlme_cfg->ht_caps.short_preamble) + frame->Capabilities.shortPreamble = 1; + + if (mac_ctx->mlme_cfg->gen.enabled_11h) + frame->Capabilities.spectrumMgt = 1; + + if (mac_ctx->mlme_cfg->wmm_params.qos_enabled) + frame->Capabilities.qos = 1; + + if (mac_ctx->mlme_cfg->roam_scoring.apsd_enabled) + frame->Capabilities.apsd = 1; + + val = mac_ctx->mlme_cfg->feature_flags.enable_block_ack; + frame->Capabilities.delayedBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + frame->Capabilities.immediateBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + /* Country */ + populate_dot11f_country(mac_ctx, &frame->Country, NULL); + + /* PowerConstraints */ + frame->PowerConstraints.localPowerConstraints = + mac_ctx->mlme_cfg->power.local_power_constraint; + + frame->PowerConstraints.present = 1; + + /* TimeAdvertisement */ + frame->TimeAdvertisement.present = 1; + frame->TimeAdvertisement.timing_capabilities = 1; + + return QDF_STATUS_SUCCESS; +} + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_FEATURE_11AX) +#ifdef WLAN_TWT_CONV_SUPPORTED +static bool +twt_get_requestor_flag(struct mac_context *mac) +{ + bool req_flag = false; + + wlan_twt_cfg_get_req_flag(mac->psoc, &req_flag); + return req_flag; +} + +static bool +twt_get_responder_flag(struct mac_context *mac) +{ + bool res_flag = false; + + wlan_twt_cfg_get_res_flag(mac->psoc, &res_flag); + return res_flag; +} +#else +static bool +twt_get_requestor_flag(struct mac_context *mac) +{ + return mac->mlme_cfg->twt_cfg.req_flag; +} + +static bool +twt_get_responder_flag(struct mac_context *mac) +{ + return mac->mlme_cfg->twt_cfg.res_flag; +} +#endif +#endif + +#ifdef WLAN_FEATURE_11AX +#ifdef WLAN_SUPPORT_TWT +static void +populate_dot11f_twt_he_cap(struct mac_context *mac, + struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + bool twt_requestor = false; + bool twt_responder = false; + bool bcast_requestor = false; + bool bcast_responder = false; + + wlan_twt_get_bcast_requestor_cfg(mac->psoc, &bcast_requestor); + bcast_requestor = bcast_requestor && + !mac->mlme_cfg->twt_cfg.disable_btwt_usr_cfg; + wlan_twt_get_bcast_responder_cfg(mac->psoc, &bcast_responder); + wlan_twt_get_requestor_cfg(mac->psoc, &twt_requestor); + wlan_twt_get_responder_cfg(mac->psoc, &twt_responder); + + he_cap->broadcast_twt = 0; + if (session->opmode == QDF_STA_MODE || + session->opmode == QDF_SAP_MODE) { + he_cap->twt_request = + twt_requestor && twt_get_requestor_flag(mac); + he_cap->twt_responder = + twt_responder && twt_get_responder_flag(mac); + } + + if (session->opmode == QDF_STA_MODE) { + he_cap->broadcast_twt = bcast_requestor; + } else if (session->opmode == QDF_SAP_MODE) { + he_cap->broadcast_twt = bcast_responder; + } +} +#else +static inline void +populate_dot11f_twt_he_cap(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + he_cap->broadcast_twt = 0; +} +#endif + +/** + * populate_dot11f_he_caps() - pouldate HE Capability IE + * @mac_ctx: Global MAC context + * @session: PE session + * @he_cap: pointer to HE capability IE + * + * Populdate the HE capability IE based on the session. + */ +QDF_STATUS populate_dot11f_he_caps(struct mac_context *mac_ctx, struct pe_session *session, + tDot11fIEhe_cap *he_cap) +{ + uint8_t *ppet; + uint32_t value = 0; + + he_cap->present = 1; + + if (!session) { + qdf_mem_copy(he_cap, &mac_ctx->mlme_cfg->he_caps.dot11_he_cap, + sizeof(tDot11fIEhe_cap)); + return QDF_STATUS_SUCCESS; + } + + /** TODO: String items needs attention. **/ + qdf_mem_copy(he_cap, &session->he_config, sizeof(*he_cap)); + if (he_cap->ppet_present) { + value = WNI_CFG_HE_PPET_LEN; + /* if session is present, populate PPET based on band */ + if (!wlan_reg_is_24ghz_ch_freq(session->curr_op_freq)) + qdf_mem_copy(he_cap->ppet.ppe_threshold.ppe_th, + mac_ctx->mlme_cfg->he_caps.he_ppet_5g, + value); + else + qdf_mem_copy(he_cap->ppet.ppe_threshold.ppe_th, + mac_ctx->mlme_cfg->he_caps.he_ppet_2g, + value); + + ppet = he_cap->ppet.ppe_threshold.ppe_th; + he_cap->ppet.ppe_threshold.num_ppe_th = + lim_truncate_ppet(ppet, value); + } else { + he_cap->ppet.ppe_threshold.num_ppe_th = 0; + } + populate_dot11f_twt_he_cap(mac_ctx, session, he_cap); + + if (wlan_reg_is_5ghz_ch_freq(session->curr_op_freq) || + wlan_reg_is_6ghz_chan_freq(session->curr_op_freq)) { + if (session->ch_width <= CH_WIDTH_80MHZ) { + he_cap->chan_width_2 = 0; + he_cap->chan_width_3 = 0; + } else if (session->ch_width == CH_WIDTH_160MHZ) { + he_cap->chan_width_3 = 0; + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_he_caps_by_band(struct mac_context *mac_ctx, + bool is_2g, + tDot11fIEhe_cap *he_cap, + struct pe_session *session) +{ + if (is_2g) + qdf_mem_copy(he_cap, &mac_ctx->he_cap_2g, sizeof(*he_cap)); + else + qdf_mem_copy(he_cap, &mac_ctx->he_cap_5g, sizeof(*he_cap)); + + if (session) + populate_dot11f_twt_he_cap(mac_ctx, session, he_cap); + + return QDF_STATUS_SUCCESS; +} + +/** + * populate_dot11f_he_operation() - pouldate HE Operation IE + * @mac_ctx: Global MAC context + * @session: PE session + * @he_op: pointer to HE Operation IE + * + * Populdate the HE Operation IE based on the session. + */ +QDF_STATUS +populate_dot11f_he_operation(struct mac_context *mac_ctx, + struct pe_session *session, tDot11fIEhe_op *he_op) +{ + enum reg_6g_ap_type ap_pwr_type; + qdf_mem_copy(he_op, &session->he_op, sizeof(*he_op)); + + he_op->present = 1; + he_op->vht_oper_present = 0; + if (session->he_6ghz_band) { + he_op->oper_info_6g_present = 1; + if (session->bssType != eSIR_INFRA_AP_MODE) { + he_op->oper_info_6g.info.ch_width = session->ch_width; + he_op->oper_info_6g.info.center_freq_seg0 = + session->ch_center_freq_seg0; + if (session->ch_width == CH_WIDTH_80P80MHZ || + session->ch_width == CH_WIDTH_160MHZ) { + he_op->oper_info_6g.info.center_freq_seg1 = + session->ch_center_freq_seg1; + he_op->oper_info_6g.info.ch_width = + CH_WIDTH_160MHZ; + } else { + he_op->oper_info_6g.info.center_freq_seg1 = 0; + } + } + he_op->oper_info_6g.info.primary_ch = + wlan_reg_freq_to_chan(mac_ctx->pdev, + session->curr_op_freq); + he_op->oper_info_6g.info.dup_bcon = 0; + he_op->oper_info_6g.info.min_rate = 0; + wlan_reg_get_cur_6g_ap_pwr_type(mac_ctx->pdev, &ap_pwr_type); + he_op->oper_info_6g.info.reg_info = ap_pwr_type; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_sr_info(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEspatial_reuse *sr_info) +{ + uint8_t non_srg_pd_offset; + uint8_t sr_ctrl = wlan_vdev_mlme_get_sr_ctrl(session->vdev); + bool sr_enabled = wlan_vdev_mlme_get_he_spr_enabled(session->vdev); + + if (!sr_enabled) + return QDF_STATUS_SUCCESS; + + sr_info->present = 1; + sr_info->psr_disallow = 1; + sr_info->srg_info_present = 0; + sr_info->non_srg_offset_present = 0; + sr_info->non_srg_pd_sr_disallow = !!(sr_ctrl & + WLAN_HE_NON_SRG_PD_SR_DISALLOWED); + + if ((!sr_info->non_srg_pd_sr_disallow) && + (sr_ctrl & WLAN_HE_NON_SRG_OFFSET_PRESENT)) { + non_srg_pd_offset = + wlan_vdev_mlme_get_non_srg_pd_offset(session->vdev); + sr_info->non_srg_offset_present = 1; + sr_info->non_srg_offset.info.non_srg_pd_max_offset = + non_srg_pd_offset; + } + + if (sr_ctrl & WLAN_HE_SIGA_SR_VAL15_ALLOWED) + sr_info->sr_value15_allow = 1; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_he_6ghz_cap(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEhe_6ghz_band_cap *he_6g_cap) +{ + struct mlme_ht_capabilities_info *ht_cap_info; + struct mlme_vht_capabilities_info *vht_cap_info; + + if (session && !session->he_6ghz_band) + return QDF_STATUS_SUCCESS; + + ht_cap_info = &mac_ctx->mlme_cfg->ht_caps.ht_cap_info; + vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + + he_6g_cap->present = 1; + he_6g_cap->min_mpdu_start_spacing = + mac_ctx->mlme_cfg->ht_caps.ampdu_params.mpdu_density; + if (session) + he_6g_cap->max_ampdu_len_exp = + session->vht_config.max_ampdu_lenexp; + else + he_6g_cap->max_ampdu_len_exp = + vht_cap_info->ampdu_len_exponent & 0x7; + he_6g_cap->max_mpdu_len = vht_cap_info->ampdu_len; + he_6g_cap->sm_pow_save = ht_cap_info->mimo_power_save; + he_6g_cap->rd_responder = 0; + he_6g_cap->rx_ant_pattern_consistency = 0; + he_6g_cap->tx_ant_pattern_consistency = 0; + + lim_log_he_6g_cap(mac_ctx, he_6g_cap); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * populate_dot11f_he_bss_color_change() - pouldate HE BSS color change IE + * @mac_ctx: Global MAC context + * @session: PE session + * @he_bss_color: pointer to HE BSS color change IE + * + * Populdate the HE BSS color change IE based on the session. + */ +QDF_STATUS +populate_dot11f_he_bss_color_change(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbss_color_change *he_bss_color) +{ + if (!session->bss_color_changing) { + he_bss_color->present = 0; + return QDF_STATUS_SUCCESS; + } + + he_bss_color->present = 1; + he_bss_color->countdown = session->he_bss_color_change.countdown; + he_bss_color->new_color = session->he_bss_color_change.new_color; + + lim_log_he_bss_color(mac_ctx, he_bss_color); + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_11AX_BSS_COLOR */ +#endif /* WLAN_FEATURE_11AX */ + +#ifdef WLAN_FEATURE_11BE + +/** + * lim_get_ext_ie_ptr_from_ext_id() - Find out ext ie + * @ie: source ie address + * @ie_len: source ie length + * @oui: oui buffer + * @oui_size: oui size + * + * This API is used to find out ext ie from ext id + * + * Return: vendor ie address - success + * NULL - failure + */ +static +const uint8_t *lim_get_ext_ie_ptr_from_ext_id(const uint8_t *ie, + uint16_t ie_len, + const uint8_t *oui, + uint8_t oui_size) +{ + return wlan_get_ext_ie_ptr_from_ext_id(oui, oui_size, + ie, ie_len); +} + +/* EHT Operation */ +/* 1 byte ext id, 1 byte eht op params, 4 bytes basic EHT MCS and NSS set*/ +#define EHTOP_FIXED_LEN 6 + +#define EHTOP_PARAMS_INFOP_IDX 0 +#define EHTOP_PARAMS_INFOP_BITS 1 + +#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_IDX 1 +#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_BITS 1 + +#define EHTOP_INFO_CHANWIDTH_IDX 0 +#define EHTOP_INFO_CHANWIDTH_BITS 3 + +#define WLAN_MAX_DISABLED_SUB_CHAN_BITMAP 2 + +#define ehtop_ie_set(eht_op, index, num_bits, val) \ + QDF_SET_BITS((*eht_op), qdf_do_div_rem(index, 8),\ + (num_bits), (val)) +#define ehtop_ie_get(eht_op, index, num_bits) \ + QDF_GET_BITS((eht_op), qdf_do_div_rem(index, 8), \ + (num_bits)) + +/* byte 0 */ +#define EHTOP_PARAMS_INFOP_GET_FROM_IE(__eht_op_params) \ + ehtop_ie_get(__eht_op_params, \ + EHTOP_PARAMS_INFOP_IDX, \ + EHTOP_PARAMS_INFOP_BITS) +#define EHTOP_PARAMS_INFOP_SET_TO_IE(__eht_op_params, __value) \ + ehtop_ie_set(&__eht_op_params, \ + EHTOP_PARAMS_INFOP_IDX, \ + EHTOP_PARAMS_INFOP_BITS, __value) + +#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_GET_FROM_IE(__eht_op_params) \ + ehtop_ie_get(__eht_op_params, \ + EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_IDX, \ + EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_BITS) +#define EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_SET_TO_IE(__eht_op_params, __value) \ + ehtop_ie_set(&__eht_op_params, \ + EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_IDX, \ + EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_BITS, \ + __value) + +#define EHTOP_PARAMS_EHT_DEF_PE_DURATION_GET_FROM_IE(__eht_op_params) \ + ehtop_ie_get(__eht_op_params, \ + EHTOP_DEFAULT_PE_DURATION_IDX, \ + EHTOP_DEFAULT_PE_DURATION_BITS) +#define EHTOP_PARAMS_EHT_DEF_PE_DURATION_SET_TO_IE(__eht_op_params, __value) \ + ehtop_ie_set(&__eht_op_params, \ + EHTOP_DEFAULT_PE_DURATION_IDX, \ + EHTOP_DEFAULT_PE_DURATION_BITS, __value) + +#define EHTOP_PARAMS_GROUP_ADDR_BU_IND_LIMIT_GET_FROM_IE(__eht_op_params) \ + ehtop_ie_get(__eht_op_params, \ + EHTOP_GRP_ADDRESSED_BU_IND_LIMIT_IDX, \ + EHTOP_GRP_ADDRESSED_BU_IND_LIMIT_BITS) +#define EHTOP_PARAMS_GROUP_ADDR_BU_IND_LIMIT_SET_TO_IE(__eht_op_params, __value) \ + ehtop_ie_set(&__eht_op_params, \ + EHTOP_GRP_ADDRESSED_BU_IND_LIMIT_IDX, \ + EHTOP_GRP_ADDRESSED_BU_IND_LIMIT_BITS, \ + __value) + +#define EHTOP_PARAMS_GROUP_ADDR_BU_IND_EXPONENT_GET_FROM_IE(__eht_op_params) \ + ehtop_ie_get(__eht_op_params, \ + EHTOP_GRP_ADDRESSED_BU_IND_EXPONENT_IDX, \ + EHTOP_GRP_ADDRESSED_BU_IND_EXPONENT_BITS) +#define EHTOP_PARAMS_GROUP_ADDR_BU_IND_EXPONENT_SET_TO_IE(__eht_op_params, __value) \ + ehtop_ie_set(&__eht_op_params, \ + EHTOP_GRP_ADDRESSED_BU_IND_EXPONENT_IDX, \ + EHTOP_GRP_ADDRESSED_BU_IND_EXPONENT_BITS, \ + __value) + +#define EHTOP_INFO_CHANWIDTH_GET_FROM_IE(__eht_op_control) \ + ehtop_ie_get(__eht_op_control, \ + EHTOP_INFO_CHANWIDTH_IDX, \ + EHTOP_INFO_CHANWIDTH_BITS) +#define EHTOP_INFO_CHANWIDTH_SET_TO_IE(__eht_op_control, __value) \ + ehtop_ie_set(&__eht_op_control, \ + EHTOP_INFO_CHANWIDTH_IDX, \ + EHTOP_INFO_CHANWIDTH_BITS, __value) + +/* 1 byte ext id, 2 bytes mac cap, 9 bytes phy cap */ +#define EHTCAP_FIXED_LEN 12 +#define EHTCAP_MACBYTE_IDX0 0 +#define EHTCAP_MACBYTE_IDX1 1 + +#define EHTCAP_PHYBYTE_IDX0 0 +#define EHTCAP_PHYBYTE_IDX1 1 +#define EHTCAP_PHYBYTE_IDX2 2 +#define EHTCAP_PHYBYTE_IDX3 3 +#define EHTCAP_PHYBYTE_IDX4 4 +#define EHTCAP_PHYBYTE_IDX5 5 +#define EHTCAP_PHYBYTE_IDX6 6 +#define EHTCAP_PHYBYTE_IDX7 7 +#define EHTCAP_PHYBYTE_IDX8 8 + +#define WLAN_IE_HDR_LEN 2 + +enum EHT_TXRX_MCS_NSS_IDX { + EHTCAP_TXRX_MCS_NSS_IDX0, + EHTCAP_TXRX_MCS_NSS_IDX1, + EHTCAP_TXRX_MCS_NSS_IDX2, + EHTCAP_TXRX_MCS_NSS_IDXMAX, +}; + +enum EHT_PER_BW_TXRX_MCS_NSS_MAP_IDX { + EHTCAP_TXRX_MCS_NSS_IDX_ONLY20, + EHTCAP_TXRX_MCS_NSS_IDX_80, + EHTCAP_TXRX_MCS_NSS_IDX_160, + EHTCAP_TXRX_MCS_NSS_IDX_320, + EHTCAP_TXRX_MCS_NSS_IDX_MAX, +}; + +#define EHT_MCS_MAP_RX_MCS_0_9_IDX 0 +#define EHT_MCS_MAP_RX_MCS_0_9_BITS 4 +#define EHT_MCS_MAP_TX_MCS_0_9_IDX 4 +#define EHT_MCS_MAP_TX_MCS_0_9_BITS 4 +#define EHT_MCS_MAP_RX_MCS_10_11_IDX 8 +#define EHT_MCS_MAP_RX_MCS_10_11_BITS 4 +#define EHT_MCS_MAP_TX_MCS_10_11_IDX 12 +#define EHT_MCS_MAP_TX_MCS_10_11_BITS 4 +#define EHT_MCS_MAP_RX_MCS_12_13_IDX 16 +#define EHT_MCS_MAP_RX_MCS_12_13_BITS 4 +#define EHT_MCS_MAP_TX_MCS_12_13_IDX 20 +#define EHT_MCS_MAP_TX_MCS_12_13_BITS 4 + +#define EHT_MCS_MAP_20_ONLY_RX_MCS_0_7_IDX 0 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_0_7_BITS 4 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_0_7_IDX 4 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_0_7_BITS 4 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_8_9_IDX 8 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_8_9_BITS 4 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_8_9_IDX 12 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_8_9_BITS 4 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_10_11_IDX 16 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_10_11_BITS 4 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_10_11_IDX 20 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_10_11_BITS 4 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_12_13_IDX 24 +#define EHT_MCS_MAP_20_ONLY_RX_MCS_12_13_BITS 4 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_12_13_IDX 28 +#define EHT_MCS_MAP_20_ONLY_TX_MCS_12_13_BITS 4 + +#define EHT_TXMCS_MAP_MCS_0_7_IDX 0 +#define EHT_TXMCS_MAP_MCS_0_7_BITS 4 +#define EHT_TXMCS_MAP_MCS_8_9_IDX 4 +#define EHT_TXMCS_MAP_MCS_8_9_BITS 4 +#define EHT_TXMCS_MAP_MCS_10_11_IDX 8 +#define EHT_TXMCS_MAP_MCS_10_11_BITS 4 +#define EHT_TXMCS_MAP_MCS_12_13_IDX 12 +#define EHT_TXMCS_MAP_MCS_12_13_BITS 4 + +#define EHT_RXMCS_MAP_MCS_0_7_IDX 0 +#define EHT_RXMCS_MAP_MCS_0_7_BITS 4 +#define EHT_RXMCS_MAP_MCS_8_9_IDX 4 +#define EHT_RXMCS_MAP_MCS_8_9_BITS 4 +#define EHT_RXMCS_MAP_MCS_10_11_IDX 8 +#define EHT_RXMCS_MAP_MCS_10_11_BITS 4 +#define EHT_RXMCS_MAP_MCS_12_13_IDX 12 +#define EHT_RXMCS_MAP_MCS_12_13_BITS 4 + +#define EHT_MCS_MAP_LEN 3 +#define EHT_MCS_MAP_BW20_ONLY_LEN 4 + +#define ehtcap_ie_set(eht_cap, index, num_bits, val) \ + QDF_SET_BITS((*eht_cap), qdf_do_div_rem(index, 8),\ + (num_bits), (val)) +#define ehtcap_ie_get(eht_cap, index, num_bits) \ + QDF_GET_BITS((eht_cap), qdf_do_div_rem(index, 8), \ + (num_bits)) + +/* byte 0 */ +#define EHTCAP_MAC_EPCSPRIACCESS_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_EPCSPRIACCESS_IDX, \ + EHTCAP_MAC_EPCSPRIACCESS_BITS) +#define EHTCAP_MAC_EPCSPRIACCESS_SET_TO_IE(__eht_cap_mac, __value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_EPCSPRIACCESS_IDX, \ + EHTCAP_MAC_EPCSPRIACCESS_BITS, __value) + +#define EHTCAP_MAC_EHTOMCTRL_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_EHTOMCTRL_IDX, \ + EHTCAP_MAC_EHTOMCTRL_BITS) +#define EHTCAP_MAC_EHTOMCTRL_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_EHTOMCTRL_IDX, \ + EHTCAP_MAC_EHTOMCTRL_BITS, value) + +#define EHTCAP_MAC_TRIGTXOP_MODE1_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE1_IDX, \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE1_BITS) +#define EHTCAP_MAC_TRIGTXOP_MODE1_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE1_IDX, \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE1_BITS, \ + value) + +#define EHTCAP_MAC_TRIGTXOP_MODE2_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE2_IDX, \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE2_BITS) +#define EHTCAP_MAC_TRIGTXOP_MODE2_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE2_IDX, \ + EHTCAP_MAC_TRIGGERED_TXOP_MODE2_BITS, \ + value) + +#define EHTCAP_MAC_RESTRICTED_TWT_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_RESTRICTED_TWT_IDX, \ + EHTCAP_MAC_RESTRICTED_TWT_BITS) +#define EHTCAP_MAC_RESTRICTED_TWT_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_RESTRICTED_TWT_IDX, \ + EHTCAP_MAC_RESTRICTED_TWT_BITS, value) + +#define EHTCAP_MAC_SCS_TRAFFIC_DESC_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_SCS_TRAFFIC_DESC_IDX, \ + EHTCAP_MAC_SCS_TRAFFIC_DESC_BITS) +#define EHTCAP_MAC_SCS_TRAFFIC_DESC_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_SCS_TRAFFIC_DESC_IDX, \ + EHTCAP_MAC_SCS_TRAFFIC_DESC_BITS, value) + +#define EHTCAP_MAC_MAX_MPDU_LEN_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_MAX_MPDU_LEN_IDX, \ + EHTCAP_MAC_MAX_MPDU_LEN_BITS) +#define EHTCAP_MAC_MAX_MPDU_LEN_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX0], \ + EHTCAP_MAC_MAX_MPDU_LEN_IDX, \ + EHTCAP_MAC_MAX_MPDU_LEN_BITS, value) + +#define EHTCAP_MAC_MAX_A_MPDU_LEN_EXPONENT_EXT_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_MAX_A_MPDU_LEN_IDX, \ + EHTCAP_MAC_MAX_A_MPDU_LEN_BITS) +#define EHTCAP_MAC_MAX_A_MPDU_LEN_EXPONENT_EXT_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_MAX_A_MPDU_LEN_IDX, \ + EHTCAP_MAC_MAX_A_MPDU_LEN_BITS, value) + +#define EHTCAP_MAC_EHT_TRS_SUPPORT_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_TRS_SUPPORT_IDX, \ + EHTCAP_MAC_TRS_SUPPORT_BITS) +#define EHTCAP_MAC_EHT_TRS_SUPPORT_SET_TO_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_TRS_SUPPORT_IDX, \ + EHTCAP_MAC_TRS_SUPPORT_BITS, value) + +#define EHTCAP_MAC_TXOP_RETURN_SUPPORT_SHARE_M2_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_TXOP_RET_SUPPP_IN_SHARING_MODE2_IDX, \ + EHTCAP_MAC_TXOP_RET_SUPPP_IN_SHARING_MODE2_BITS) +#define EHTCAP_MAC_TXOP_RETURN_SUPPORT_SHARE_M2_SET_FROM_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_TXOP_RET_SUPPP_IN_SHARING_MODE2_IDX, \ + EHTCAP_MAC_TXOP_RET_SUPPP_IN_SHARING_MODE2_BITS, \ + value) + +#define EHTCAP_MAC_TWO_BQRS_SUPP_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_TWO_BQRS_SUPP_IDX, \ + EHTCAP_MAC_TWO_BQRS_SUPP_BITS) +#define EHTCAP_MAC_TWO_BQRS_SUPP_SET_FROM_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_TWO_BQRS_SUPP_IDX, \ + EHTCAP_MAC_TWO_BQRS_SUPP_BITS, \ + value) + +#define EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_GET_FROM_IE(__eht_cap_mac) \ + ehtcap_ie_get(__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_IDX, \ + EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_BITS) +#define EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_SET_FROM_IE(__eht_cap_mac, value) \ + ehtcap_ie_set(&__eht_cap_mac[EHTCAP_MACBYTE_IDX1], \ + EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_IDX, \ + EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_BITS, \ + value) + +/* byte 0 */ +#define EHTCAP_PHY_320MHZIN6GHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_320MHZIN6GHZ_IDX, \ + EHTCAP_PHY_320MHZIN6GHZ_BITS) +#define EHTCAP_PHY_320MHZIN6GHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_320MHZIN6GHZ_IDX, \ + EHTCAP_PHY_320MHZIN6GHZ_BITS, value) + +#define EHTCAP_PHY_242TONERUBWGT20MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_242TONERUBWLT20MHZ_IDX, \ + EHTCAP_PHY_242TONERUBWLT20MHZ_BITS) +#define EHTCAP_PHY_242TONERUBWGT20MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_242TONERUBWLT20MHZ_IDX, \ + EHTCAP_PHY_242TONERUBWLT20MHZ_BITS, value) + +#define EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_IDX, \ + EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_BITS) +#define EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_IDX, \ + EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_BITS, \ + value) + +#define EHTCAP_PHY_PARTIALBWULMU_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_PARTIALBWULMU_IDX, \ + EHTCAP_PHY_PARTIALBWULMU_BITS) +#define EHTCAP_PHY_PARTIALBWULMU_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_PARTIALBWULMU_IDX, \ + EHTCAP_PHY_PARTIALBWULMU_BITS, value) + +#define EHTCAP_PHY_SUBFMR_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_SUBFMR_IDX, \ + EHTCAP_PHY_SUBFMR_BITS) +#define EHTCAP_PHY_SUBFMR_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_SUBFMR_IDX, \ + EHTCAP_PHY_SUBFMR_BITS, value) + +#define EHTCAP_PHY_SUBFME_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_SUBFME_IDX, \ + EHTCAP_PHY_SUBFME_BITS) +#define EHTCAP_PHY_SUBFME_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_SUBFME_IDX, \ + EHTCAP_PHY_SUBFME_BITS, value) + +#define EHTCAP_PHY_BFMESSLT80MHZ_GET_FROM_IE_BYTE0(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_BFMESSLT80MHZ_IDX, \ + 1) +#define EHTCAP_PHY_BFMESSLT80MHZ_SET_TO_IE_BYTE0(__eht_cap_phy, __value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX0], \ + EHTCAP_PHY_BFMESSLT80MHZ_IDX, \ + 1, __value) + +/* byte 1 */ +#define EHTCAP_PHY_BFMESSLT80MHZ_GET_FROM_IE_BYTE1(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX1], \ + 8, \ + 2) +#define EHTCAP_PHY_BFMESSLT80MHZ_SET_TO_IE_BYTE1(__eht_cap_phy, __value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX1], \ + 8, \ + 2, __value) +#define EHTCAP_PHY_BFMESS160MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX1], \ + EHTCAP_PHY_BFMESS160MHZ_IDX, \ + EHTCAP_PHY_BFMESS160MHZ_BITS) +#define EHTCAP_PHY_BFMESS160MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX1], \ + EHTCAP_PHY_BFMESS160MHZ_IDX, \ + EHTCAP_PHY_BFMESS160MHZ_BITS, value) + +#define EHTCAP_PHY_BFMESS320MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX1], \ + EHTCAP_PHY_BFMESS320MHZ_IDX, \ + EHTCAP_PHY_BFMESS320MHZ_BITS) +#define EHTCAP_PHY_BFMESS320MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX1], \ + EHTCAP_PHY_BFMESS320MHZ_IDX, \ + EHTCAP_PHY_BFMESS320MHZ_BITS, value) + +/* byte 2 */ +#define EHTCAP_PHY_NUMSOUNDLT80MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX2], \ + EHTCAP_PHY_NUMSOUNDLT80MHZ_IDX, \ + EHTCAP_PHY_NUMSOUNDLT80MHZ_BITS) +#define EHTCAP_PHY_NUMSOUNDLT80MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX2], \ + EHTCAP_PHY_NUMSOUNDLT80MHZ_IDX, \ + EHTCAP_PHY_NUMSOUNDLT80MHZ_BITS, value) + +#define EHTCAP_PHY_NUMSOUND160MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX2], \ + EHTCAP_PHY_NUMSOUND160MHZ_IDX, \ + EHTCAP_PHY_NUMSOUND160MHZ_BITS) +#define EHTCAP_PHY_NUMSOUND160MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX2], \ + EHTCAP_PHY_NUMSOUND160MHZ_IDX, \ + EHTCAP_PHY_NUMSOUND160MHZ_BITS, value) + +#define EHTCAP_PHY_NUMSOUND320MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX2], \ + EHTCAP_PHY_NUMSOUND320MHZ_IDX, \ + EHTCAP_PHY_NUMSOUND320MHZ_BITS) +#define EHTCAP_PHY_NUMSOUND320MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX2], \ + EHTCAP_PHY_NUMSOUND320MHZ_IDX, \ + EHTCAP_PHY_NUMSOUND320MHZ_BITS, value) + +/* byte 3 */ +#define EHTCAP_PHY_NG16SUFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_NG16SUFB_IDX, \ + EHTCAP_PHY_NG16SUFB_BITS) +#define EHTCAP_PHY_NG16SUFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_NG16SUFB_IDX, \ + EHTCAP_PHY_NG16SUFB_BITS, value) + +#define EHTCAP_PHY_NG16MUFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_NG16MUFB_IDX, \ + EHTCAP_PHY_NG16MUFB_BITS) +#define EHTCAP_PHY_NG16MUFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_NG16MUFB_IDX, \ + EHTCAP_PHY_NG16MUFB_BITS, value) + +#define EHTCAP_PHY_CODBK42SUFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_CODBK42SUFB_IDX, \ + EHTCAP_PHY_CODBK42SUFB_BITS) +#define EHTCAP_PHY_CODBK42SUFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_CODBK42SUFB_IDX, \ + EHTCAP_PHY_CODBK42SUFB_BITS, value) + +#define EHTCAP_PHY_CODBK75MUFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_CODBK75MUFB_IDX, \ + EHTCAP_PHY_CODBK75MUFB_BITS) +#define EHTCAP_PHY_CODBK75MUFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_CODBK75MUFB_IDX, \ + EHTCAP_PHY_CODBK75MUFB_BITS, value) + +#define EHTCAP_PHY_TRIGSUBFFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_TRIGSUBFFB_IDX, \ + EHTCAP_PHY_TRIGSUBFFB_BITS) +#define EHTCAP_PHY_TRIGSUBFFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_TRIGSUBFFB_IDX, \ + EHTCAP_PHY_TRIGSUBFFB_BITS, value) + +#define EHTCAP_PHY_TRIGMUBFPARTBWFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_TRIGMUBFPARTBWFB_IDX, \ + EHTCAP_PHY_TRIGMUBFPARTBWFB_BITS) +#define EHTCAP_PHY_TRIGMUBFPARTBWFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_TRIGMUBFPARTBWFB_IDX, \ + EHTCAP_PHY_TRIGMUBFPARTBWFB_BITS, value) + +#define EHTCAP_PHY_TRIGCQIFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_TRIGCQIFB_IDX, \ + EHTCAP_PHY_TRIGCQIFB_BITS) +#define EHTCAP_PHY_TRIGCQIFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX3], \ + EHTCAP_PHY_TRIGCQIFB_IDX, \ + EHTCAP_PHY_TRIGCQIFB_BITS, value) + +/* byte 4 */ +#define EHTCAP_PHY_PARTBWDLMUMIMO_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_PARTBWDLMUMIMO_IDX, \ + EHTCAP_PHY_PARTBWDLMUMIMO_BITS) +#define EHTCAP_PHY_PARTBWDLMUMIMO_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_PARTBWDLMUMIMO_IDX, \ + EHTCAP_PHY_PARTBWDLMUMIMO_BITS, value) + +#define EHTCAP_PHY_PSRSR_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_PSRSR_IDX, \ + EHTCAP_PHY_PSRSR_BITS) +#define EHTCAP_PHY_PSRSR_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_PSRSR_IDX, \ + EHTCAP_PHY_PSRSR_BITS, value) + +#define EHTCAP_PHY_PWRBSTFACTOR_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_PWRBSTFACTOR_IDX, \ + EHTCAP_PHY_PWRBSTFACTOR_BITS) +#define EHTCAP_PHY_PWRBSTFACTOR_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_PWRBSTFACTOR_IDX, \ + EHTCAP_PHY_PWRBSTFACTOR_BITS, value) + +#define EHTCAP_PHY_4XEHTMULTFAND800NSGI_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_4XEHTLTFAND800NSGI_IDX, \ + EHTCAP_PHY_4XEHTLTFAND800NSGI_BITS) +#define EHTCAP_PHY_4XEHTMULTFAND800NSGI_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_4XEHTLTFAND800NSGI_IDX, \ + EHTCAP_PHY_4XEHTLTFAND800NSGI_BITS, value) + +#define EHTCAP_PHY_MAXNC_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_MAXNC_IDX, \ + EHTCAP_PHY_MAXNC_BITS) +#define EHTCAP_PHY_MAXNC_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX4], \ + EHTCAP_PHY_MAXNC_IDX, \ + EHTCAP_PHY_MAXNC_BITS, value) + +/* byte 5 */ +#define EHTCAP_PHY_NONTRIGCQIFB_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_NONTRIGCQIFB_IDX, \ + EHTCAP_PHY_NONTRIGCQIFB_BITS) +#define EHTCAP_PHY_NONTRIGCQIFB_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_NONTRIGCQIFB_IDX, \ + EHTCAP_PHY_NONTRIGCQIFB_BITS, value) + +#define EHTCAP_PHY_TX1024AND4096QAMLT242TONERU_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_IDX, \ + EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_BITS) +#define EHTCAP_PHY_TX1024AND4096QAMLT242TONERU_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_IDX, \ + EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_BITS, \ + value) + +#define EHTCAP_PHY_RX1024AND4096QAMLT242TONERU_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_IDX, \ + EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_BITS) +#define EHTCAP_PHY_RX1024AND4096QAMLT242TONERU_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_IDX, \ + EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_BITS, \ + value) + +#define EHTCAP_PHY_PPETHRESPRESENT_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_PPETHRESPRESENT_IDX, \ + EHTCAP_PHY_PPETHRESPRESENT_BITS) +#define EHTCAP_PHY_PPETHRESPRESENT_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_PPETHRESPRESENT_IDX, \ + EHTCAP_PHY_PPETHRESPRESENT_BITS, value) + +#define EHTCAP_PHY_CMNNOMPKTPAD_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_CMNNOMPKTPAD_IDX, \ + EHTCAP_PHY_CMNNOMPKTPAD_BITS) +#define EHTCAP_PHY_CMNNOMPKTPAD_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_CMNNOMPKTPAD_IDX, \ + EHTCAP_PHY_CMNNOMPKTPAD_BITS, value) + +#define EHTCAP_PHY_MAXNUMEHTLTF_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_MAXNUMEHTLTF_IDX, \ + EHTCAP_PHY_MAXNUMEHTLTF_BITS) +#define EHTCAP_PHY_MAXNUMEHTLTF_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX5], \ + EHTCAP_PHY_MAXNUMEHTLTF_IDX, \ + EHTCAP_PHY_MAXNUMEHTLTF_BITS, value) + +/* byte 6 */ +#define EHTCAP_PHY_SUPMCS15_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX6], \ + EHTCAP_PHY_SUPMCS15_IDX, \ + EHTCAP_PHY_SUPMCS15_BITS) +#define EHTCAP_PHY_SUPMCS15_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX6], \ + EHTCAP_PHY_SUPMCS15_IDX, \ + EHTCAP_PHY_SUPMCS15_BITS, value) + +#define EHTCAP_PHY_EHTDUPIN6GHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX6], \ + EHTCAP_PHY_EHTDUPIN6GHZ_IDX, \ + EHTCAP_PHY_EHTDUPIN6GHZ_BITS) +#define EHTCAP_PHY_EHTDUPIN6GHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX6], \ + EHTCAP_PHY_EHTDUPIN6GHZ_IDX, \ + EHTCAP_PHY_EHTDUPIN6GHZ_BITS, value) + +/* byte 7 */ +#define EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_IDX, \ + EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_BITS) +#define EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_IDX, \ + EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_BITS, \ + value) + +#define EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_IDX, \ + EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_BITS) +#define EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_IDX, \ + EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_BITS, \ + value) + +#define EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_IDX, \ + EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_BITS) +#define EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_IDX, \ + EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_BITS, \ + value) + +#define EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_IDX, \ + EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_BITS) +#define EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_IDX, \ + EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_BITS, \ + value) + +#define EHTCAP_PHY_MUBFMRLT80MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_MUBFMRLT80MHZ_IDX, \ + EHTCAP_PHY_MUBFMRLT80MHZ_BITS) +#define EHTCAP_PHY_MUBFMRLT80MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_MUBFMRLT80MHZ_IDX, \ + EHTCAP_PHY_MUBFMRLT80MHZ_BITS, value) + +#define EHTCAP_PHY_MUBFMR160MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_MUBFMR160MHZ_IDX, \ + EHTCAP_PHY_MUBFMR160MHZ_BITS) +#define EHTCAP_PHY_MUBFMR160MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_MUBFMR160MHZ_IDX, \ + EHTCAP_PHY_MUBFMR160MHZ_BITS, value) + +#define EHTCAP_PHY_MUBFMR320MHZ_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_MUBFMR320MHZ_IDX, \ + EHTCAP_PHY_MUBFMR320MHZ_BITS) +#define EHTCAP_PHY_MUBFMR320MHZ_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_MUBFMR320MHZ_IDX, \ + EHTCAP_PHY_MUBFMR320MHZ_BITS, value) + +#define EHTCAP_PHY_TB_SOUNDING_FB_RL_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_TB_SOUNDING_FEEDBACK_RL_IDX, \ + EHTCAP_PHY_TB_SOUNDING_FEEDBACK_RL_BITS) +#define EHTCAP_PHY_TB_SOUNDING_FB_RL_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX7], \ + EHTCAP_PHY_TB_SOUNDING_FEEDBACK_RL_IDX, \ + EHTCAP_PHY_TB_SOUNDING_FEEDBACK_RL_BITS, \ + value) +#define EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_IDX, \ + EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_BITS) +#define EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_IDX, \ + EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_BITS, \ + value) + +#define EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_IDX, \ + EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_BITS) +#define EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_IDX, \ + EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_BITS, \ + value) + +#define EHTCAP_PHY_20MHZ_ONLY_CAPS_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_20MHZ_ONLY_CAPS_IDX, \ + EHTCAP_PHY_20MHZ_ONLY_CAPS_BITS) +#define EHTCAP_PHY_20MHZ_ONLY_CAPS_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_20MHZ_ONLY_CAPS_IDX, \ + EHTCAP_PHY_20MHZ_ONLY_CAPS_BITS, \ + value) + +#define EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FL_BW_FB_DLMUMIMO_IDX, \ + EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FL_BW_FB_DLMUMIMO_BITS) + +#define EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FL_BW_FB_DLMUMIMO_IDX, \ + EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FL_BW_FB_DLMUMIMO_BITS, \ + value) + +#define EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_GET_FROM_IE(__eht_cap_phy) \ + ehtcap_ie_get(__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_IDX, \ + EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_BITS) +#define EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_SET_TO_IE(__eht_cap_phy, value) \ + ehtcap_ie_set(&__eht_cap_phy[EHTCAP_PHYBYTE_IDX8], \ + EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_IDX, \ + EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_BITS, \ + value) +static +QDF_STATUS lim_ieee80211_unpack_ehtop(const uint8_t *eht_op_ie, + tDot11fIEeht_op *dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info) +{ + struct wlan_ie_ehtops *ehtop = (struct wlan_ie_ehtops *)eht_op_ie; + uint8_t i; + + if (!eht_op_ie || !(ehtop->elem_id == DOT11F_EID_EHT_OP && + ehtop->elem_id_extn == 0x6a)) { + pe_err("Invalid EHT op IE"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_zero(dot11f_eht_op, (sizeof(tDot11fIEeht_op))); + + dot11f_eht_op->present = 1; + dot11f_eht_op->eht_op_information_present = + EHTOP_PARAMS_INFOP_GET_FROM_IE(ehtop->ehtop_param); + + dot11f_eht_op->disabled_sub_chan_bitmap_present = + EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_GET_FROM_IE( + ehtop->ehtop_param); + + dot11f_eht_op->eht_default_pe_duration = + EHTOP_PARAMS_EHT_DEF_PE_DURATION_GET_FROM_IE( + ehtop->ehtop_param); + + dot11f_eht_op->group_addr_bu_indication_limit = + EHTOP_PARAMS_GROUP_ADDR_BU_IND_LIMIT_GET_FROM_IE( + ehtop->ehtop_param); + + dot11f_eht_op->group_addr_bu_indication_exponent = + EHTOP_PARAMS_GROUP_ADDR_BU_IND_EXPONENT_GET_FROM_IE( + ehtop->ehtop_param); + + dot11f_eht_op->basic_rx_max_nss_for_mcs_0_to_7 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_0_7, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_tx_max_nss_for_mcs_0_to_7 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_0_7, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_rx_max_nss_for_mcs_8_and_9 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_8_9, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_tx_max_nss_for_mcs_8_and_9 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_8_9, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_rx_max_nss_for_mcs_10_and_11 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_10_11, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_tx_max_nss_for_mcs_10_and_11 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_10_11, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_rx_max_nss_for_mcs_12_and_13 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_12_13, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_op->basic_tx_max_nss_for_mcs_12_and_13 = + ehtop_ie_get(ehtop->basic_mcs_nss_set.max_nss_mcs_12_13, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS); + + if (dot11f_eht_op->eht_op_information_present) { + dot11f_eht_op->channel_width = + EHTOP_INFO_CHANWIDTH_GET_FROM_IE(ehtop->control); + + dot11f_eht_op->ccfs0 = ehtop->ccfs0; + + dot11f_eht_op->ccfs1 = ehtop->ccfs1; + + if (dot11f_eht_op->disabled_sub_chan_bitmap_present) { + for (i = 0; i < WLAN_MAX_DISABLED_SUB_CHAN_BITMAP; + i++) { + dot11f_eht_op->disabled_sub_chan_bitmap[0][i] = + ehtop->disabled_sub_chan_bitmap[i]; + } + } + } + + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS lim_ieee80211_unpack_ehtcap(const uint8_t *eht_cap_ie, + tDot11fIEeht_cap *dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, + bool is_band_2g) +{ + struct wlan_ie_ehtcaps *ehtcap = (struct wlan_ie_ehtcaps *)eht_cap_ie; + uint32_t idx = 0; + uint32_t mcs_map_len; + + if (!eht_cap_ie || !(ehtcap->elem_id == DOT11F_EID_EHT_CAP && + ehtcap->elem_id_extn == 0x6c)) { + pe_err("Invalid EHT cap IE"); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_zero(dot11f_eht_cap, (sizeof(tDot11fIEeht_cap))); + + dot11f_eht_cap->present = 1; + dot11f_eht_cap->epcs_pri_access = + EHTCAP_MAC_EPCSPRIACCESS_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->eht_om_ctl = + EHTCAP_MAC_EHTOMCTRL_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->triggered_txop_sharing_mode1 = + EHTCAP_MAC_TRIGTXOP_MODE1_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->triggered_txop_sharing_mode2 = + EHTCAP_MAC_TRIGTXOP_MODE2_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->restricted_twt = + EHTCAP_MAC_RESTRICTED_TWT_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->scs_traffic_desc = + EHTCAP_MAC_SCS_TRAFFIC_DESC_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->max_mpdu_len = + EHTCAP_MAC_MAX_MPDU_LEN_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->max_a_mpdu_len_exponent_ext = + EHTCAP_MAC_MAX_A_MPDU_LEN_EXPONENT_EXT_GET_FROM_IE( + ehtcap->eht_mac_cap); + + dot11f_eht_cap->eht_trs_support = + EHTCAP_MAC_EHT_TRS_SUPPORT_GET_FROM_IE(ehtcap->eht_mac_cap); + + dot11f_eht_cap->txop_return_support_txop_share_m2 = + EHTCAP_MAC_TXOP_RETURN_SUPPORT_SHARE_M2_GET_FROM_IE( + ehtcap->eht_mac_cap); + dot11f_eht_cap->two_bqrs_support = + EHTCAP_MAC_TWO_BQRS_SUPP_GET_FROM_IE( + ehtcap->eht_mac_cap); + + dot11f_eht_cap->eht_link_adaptation_support = + EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_GET_FROM_IE( + ehtcap->eht_mac_cap); + + dot11f_eht_cap->support_320mhz_6ghz = + EHTCAP_PHY_320MHZIN6GHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->ru_242tone_wt_20mhz = + EHTCAP_PHY_242TONERUBWGT20MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->ndp_4x_eht_ltf_3dot2_us_gi = + EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->partial_bw_mu_mimo = + EHTCAP_PHY_PARTIALBWULMU_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->su_beamformer = + EHTCAP_PHY_SUBFMR_GET_FROM_IE(ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->su_beamformee = + EHTCAP_PHY_SUBFME_GET_FROM_IE(ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->bfee_ss_le_80mhz = + EHTCAP_PHY_BFMESSLT80MHZ_GET_FROM_IE_BYTE0( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->bfee_ss_le_80mhz |= + (EHTCAP_PHY_BFMESSLT80MHZ_GET_FROM_IE_BYTE1( + ehtcap->eht_phy_cap.phy_cap_bytes) << 1); + dot11f_eht_cap->bfee_ss_160mhz = + EHTCAP_PHY_BFMESS160MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->bfee_ss_320mhz = + EHTCAP_PHY_BFMESS320MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->num_sounding_dim_le_80mhz = + EHTCAP_PHY_NUMSOUNDLT80MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->num_sounding_dim_160mhz = + EHTCAP_PHY_NUMSOUND160MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->num_sounding_dim_320mhz = + EHTCAP_PHY_NUMSOUND320MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->ng_16_su_feedback = + EHTCAP_PHY_NG16SUFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->ng_16_mu_feedback = + EHTCAP_PHY_NG16MUFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->cb_sz_4_2_su_feedback = + EHTCAP_PHY_CODBK42SUFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->cb_sz_7_5_su_feedback = + EHTCAP_PHY_CODBK75MUFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->trig_su_bforming_feedback = + EHTCAP_PHY_TRIGSUBFFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->trig_mu_bforming_partial_bw_feedback = + EHTCAP_PHY_TRIGMUBFPARTBWFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->triggered_cqi_feedback = + EHTCAP_PHY_TRIGCQIFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->partial_bw_dl_mu_mimo = + EHTCAP_PHY_PARTBWDLMUMIMO_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->psr_based_sr = + EHTCAP_PHY_PSRSR_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->power_boost_factor = + EHTCAP_PHY_PWRBSTFACTOR_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->eht_mu_ppdu_4x_ltf_0_8_us_gi = + EHTCAP_PHY_4XEHTMULTFAND800NSGI_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->max_nc = + EHTCAP_PHY_MAXNC_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->non_trig_cqi_feedback = + EHTCAP_PHY_NONTRIGCQIFB_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->tx_1024_4096_qam_lt_242_tone_ru = + EHTCAP_PHY_TX1024AND4096QAMLT242TONERU_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->rx_1024_4096_qam_lt_242_tone_ru = + EHTCAP_PHY_RX1024AND4096QAMLT242TONERU_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->ppet_present = + EHTCAP_PHY_PPETHRESPRESENT_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->common_nominal_pkt_padding = + EHTCAP_PHY_CMNNOMPKTPAD_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->max_num_eht_ltf = + EHTCAP_PHY_MAXNUMEHTLTF_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->mcs_15 = + EHTCAP_PHY_SUPMCS15_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->eht_dup_6ghz = + EHTCAP_PHY_EHTDUPIN6GHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->op_sta_rx_ndp_wider_bw_20mhz = + EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->non_ofdma_ul_mu_mimo_le_80mhz = + EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->non_ofdma_ul_mu_mimo_160mhz = + EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->non_ofdma_ul_mu_mimo_320mhz = + EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->mu_bformer_le_80mhz = + EHTCAP_PHY_MUBFMRLT80MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->mu_bformer_160mhz = + EHTCAP_PHY_MUBFMR160MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->mu_bformer_320mhz = + EHTCAP_PHY_MUBFMR320MHZ_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->tb_sounding_feedback_rl = + EHTCAP_PHY_TB_SOUNDING_FB_RL_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->rx_1k_qam_in_wider_bw_dl_ofdma = + EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->rx_4k_qam_in_wider_bw_dl_ofdma = + EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->limited_cap_support_20mhz = + EHTCAP_PHY_20MHZ_ONLY_CAPS_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->triggered_mu_bf_full_bw_fb_and_dl_mumimo = + EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + dot11f_eht_cap->mru_support_20mhz = + EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_GET_FROM_IE( + ehtcap->eht_phy_cap.phy_cap_bytes); + + /* Fill EHT MCS and NSS set field */ + if ((is_band_2g && !dot11f_he_cap.chan_width_0) || + (!is_band_2g && !dot11f_he_cap.chan_width_1 && + !dot11f_he_cap.chan_width_2 && !dot11f_he_cap.chan_width_3)) { + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + } else { + if ((is_band_2g && dot11f_he_cap.chan_width_0) || + (!is_band_2g && dot11f_he_cap.chan_width_1)) { + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7 = + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9; + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9 = + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9; + + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7 = + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9; + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9 = + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9; + idx++; + + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 = + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11; + + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 = + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11; + idx++; + + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + dot11f_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 = + dot11f_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13; + + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + dot11f_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 = + dot11f_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13; + idx++; + } + + if (dot11f_he_cap.chan_width_2 == 1) { + dot11f_eht_cap->bw_160_rx_max_nss_for_mcs_0_to_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_160_tx_max_nss_for_mcs_0_to_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + } + + if (dot11f_eht_cap->support_320mhz_6ghz) { + dot11f_eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_320_tx_max_nss_for_mcs_0_to_9 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + + dot11f_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS); + + dot11f_eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13 = + ehtcap_ie_get(ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS); + idx++; + } + } + + /* Fill in TxRx EHT NSS & MCS support */ + mcs_map_len = idx; + //ehtcap->elem_len = EHTCAP_FIXED_LEN + mcs_map_len; + //ehtcaplen = ehtcap->elem_len + WLAN_IE_HDR_LEN; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_strip_and_decode_eht_cap(uint8_t *ie, uint16_t ie_len, + tDot11fIEeht_cap *dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, + uint16_t freq) +{ + const uint8_t *eht_cap_ie; + bool is_band_2g; + QDF_STATUS status; + + eht_cap_ie = lim_get_ext_ie_ptr_from_ext_id(ie, ie_len, + EHT_CAP_OUI_TYPE, + EHT_CAP_OUI_SIZE); + + if (!eht_cap_ie) + return QDF_STATUS_SUCCESS; + + is_band_2g = WLAN_REG_IS_24GHZ_CH_FREQ(freq); + + status = lim_ieee80211_unpack_ehtcap(eht_cap_ie, dot11f_eht_cap, + dot11f_he_cap, + is_band_2g); + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void lim_ieee80211_pack_ehtcap(uint8_t *ie, tDot11fIEeht_cap dot11f_eht_cap, + tDot11fIEhe_cap dot11f_he_cap, bool is_band_2g) +{ + struct wlan_ie_ehtcaps *ehtcap = (struct wlan_ie_ehtcaps *)ie; + uint32_t ehtcaplen; + uint32_t val, idx = 0; + bool chwidth_320; + uint32_t mcs_map_len; + + if (!ie) { + pe_err("ie is null"); + return; + } + + /* deduct the variable size fields before + * memsetting hecap to 0 + */ + qdf_mem_zero(ehtcap, + (sizeof(struct wlan_ie_ehtcaps))); + + ehtcap->elem_id = DOT11F_EID_EHT_CAP; + /* elem id + len = 2 bytes readjust based on + * mcs-nss and ppet fields + */ + qdf_mem_copy(&ehtcap->elem_id_extn, EHT_CAP_OUI_TYPE, EHT_CAP_OUI_SIZE); + + val = dot11f_eht_cap.epcs_pri_access; + EHTCAP_MAC_EPCSPRIACCESS_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.eht_om_ctl; + EHTCAP_MAC_EHTOMCTRL_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.triggered_txop_sharing_mode1; + EHTCAP_MAC_TRIGTXOP_MODE1_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.triggered_txop_sharing_mode2; + EHTCAP_MAC_TRIGTXOP_MODE2_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.restricted_twt; + EHTCAP_MAC_RESTRICTED_TWT_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.scs_traffic_desc; + EHTCAP_MAC_SCS_TRAFFIC_DESC_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.max_mpdu_len; + EHTCAP_MAC_MAX_MPDU_LEN_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.max_a_mpdu_len_exponent_ext; + EHTCAP_MAC_MAX_A_MPDU_LEN_EXPONENT_EXT_SET_TO_IE(ehtcap->eht_mac_cap, + val); + + val = dot11f_eht_cap.eht_trs_support; + EHTCAP_MAC_EHT_TRS_SUPPORT_SET_TO_IE(ehtcap->eht_mac_cap, val); + + val = dot11f_eht_cap.txop_return_support_txop_share_m2; + EHTCAP_MAC_TXOP_RETURN_SUPPORT_SHARE_M2_SET_FROM_IE(ehtcap->eht_mac_cap, + val); + val = dot11f_eht_cap.two_bqrs_support; + EHTCAP_MAC_TWO_BQRS_SUPP_SET_FROM_IE(ehtcap->eht_mac_cap, + val); + + val = dot11f_eht_cap.eht_link_adaptation_support; + EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_SET_FROM_IE(ehtcap->eht_mac_cap, + val); + + chwidth_320 = dot11f_eht_cap.support_320mhz_6ghz; + EHTCAP_PHY_320MHZIN6GHZ_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, + chwidth_320); + + val = dot11f_eht_cap.ru_242tone_wt_20mhz; + EHTCAP_PHY_242TONERUBWGT20MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.ndp_4x_eht_ltf_3dot2_us_gi; + EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.partial_bw_mu_mimo; + EHTCAP_PHY_PARTIALBWULMU_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.su_beamformer; + EHTCAP_PHY_SUBFMR_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.su_beamformee; + EHTCAP_PHY_SUBFME_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.bfee_ss_le_80mhz; + EHTCAP_PHY_BFMESSLT80MHZ_SET_TO_IE_BYTE0( + ehtcap->eht_phy_cap.phy_cap_bytes, + val & 1); + + EHTCAP_PHY_BFMESSLT80MHZ_SET_TO_IE_BYTE1( + ehtcap->eht_phy_cap.phy_cap_bytes, + (val >> 1)); + val = dot11f_eht_cap.bfee_ss_160mhz; + EHTCAP_PHY_BFMESS160MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.bfee_ss_320mhz; + EHTCAP_PHY_BFMESS320MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.num_sounding_dim_le_80mhz; + EHTCAP_PHY_NUMSOUNDLT80MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.num_sounding_dim_160mhz; + EHTCAP_PHY_NUMSOUND160MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.num_sounding_dim_320mhz; + EHTCAP_PHY_NUMSOUND320MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.ng_16_su_feedback; + EHTCAP_PHY_NG16SUFB_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.ng_16_mu_feedback; + EHTCAP_PHY_NG16MUFB_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.cb_sz_4_2_su_feedback; + EHTCAP_PHY_CODBK42SUFB_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.cb_sz_7_5_su_feedback; + EHTCAP_PHY_CODBK75MUFB_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.trig_su_bforming_feedback; + EHTCAP_PHY_TRIGSUBFFB_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.trig_mu_bforming_partial_bw_feedback; + EHTCAP_PHY_TRIGMUBFPARTBWFB_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.triggered_cqi_feedback; + EHTCAP_PHY_TRIGCQIFB_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.partial_bw_dl_mu_mimo; + EHTCAP_PHY_PARTBWDLMUMIMO_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.psr_based_sr; + EHTCAP_PHY_PSRSR_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.power_boost_factor; + EHTCAP_PHY_PWRBSTFACTOR_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.eht_mu_ppdu_4x_ltf_0_8_us_gi; + EHTCAP_PHY_4XEHTMULTFAND800NSGI_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.max_nc; + EHTCAP_PHY_MAXNC_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.non_trig_cqi_feedback; + EHTCAP_PHY_NONTRIGCQIFB_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.tx_1024_4096_qam_lt_242_tone_ru; + EHTCAP_PHY_TX1024AND4096QAMLT242TONERU_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.rx_1024_4096_qam_lt_242_tone_ru; + EHTCAP_PHY_RX1024AND4096QAMLT242TONERU_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.ppet_present; + EHTCAP_PHY_PPETHRESPRESENT_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.common_nominal_pkt_padding; + EHTCAP_PHY_CMNNOMPKTPAD_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.max_num_eht_ltf; + EHTCAP_PHY_MAXNUMEHTLTF_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.mcs_15; + EHTCAP_PHY_SUPMCS15_SET_TO_IE(ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.eht_dup_6ghz; + EHTCAP_PHY_EHTDUPIN6GHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.op_sta_rx_ndp_wider_bw_20mhz; + EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.non_ofdma_ul_mu_mimo_le_80mhz; + EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.non_ofdma_ul_mu_mimo_160mhz; + EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.non_ofdma_ul_mu_mimo_320mhz; + EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.mu_bformer_le_80mhz; + EHTCAP_PHY_MUBFMRLT80MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.mu_bformer_160mhz; + EHTCAP_PHY_MUBFMR160MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.mu_bformer_320mhz; + EHTCAP_PHY_MUBFMR320MHZ_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.tb_sounding_feedback_rl; + EHTCAP_PHY_TB_SOUNDING_FB_RL_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.rx_1k_qam_in_wider_bw_dl_ofdma; + EHTCAP_PHY_RX_1K_QAM_IN_WIDER_BW_DL_OFDMA_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.rx_4k_qam_in_wider_bw_dl_ofdma; + EHTCAP_PHY_RX_4K_QAM_IN_WIDER_BW_DL_OFDMA_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.limited_cap_support_20mhz; + EHTCAP_PHY_20MHZ_ONLY_CAPS_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.triggered_mu_bf_full_bw_fb_and_dl_mumimo; + EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + val = dot11f_eht_cap.mru_support_20mhz; + EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_SET_TO_IE( + ehtcap->eht_phy_cap.phy_cap_bytes, val); + + /* Fill EHT MCS and NSS set field */ + if ((is_band_2g && !dot11f_he_cap.chan_width_0) || + (!is_band_2g && !dot11f_he_cap.chan_width_1 && + !dot11f_he_cap.chan_width_2 && !dot11f_he_cap.chan_width_3)) { + val = dot11f_eht_cap.bw_20_rx_max_nss_for_mcs_0_to_7; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_20_tx_max_nss_for_mcs_0_to_7; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_20_rx_max_nss_for_mcs_8_and_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_20_tx_max_nss_for_mcs_8_and_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_20_rx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_20_tx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_20_rx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_20_tx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + } else { + if ((is_band_2g && dot11f_he_cap.chan_width_0) || + (!is_band_2g && dot11f_he_cap.chan_width_1)) { + val = dot11f_eht_cap.bw_le_80_rx_max_nss_for_mcs_0_to_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_le_80_tx_max_nss_for_mcs_0_to_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_le_80_rx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_le_80_tx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_le_80_rx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_le_80_tx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + } + + if (dot11f_he_cap.chan_width_2 == 1) { + val = dot11f_eht_cap.bw_160_rx_max_nss_for_mcs_0_to_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_160_tx_max_nss_for_mcs_0_to_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_160_rx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_160_tx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_160_rx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_160_tx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + } + + if (chwidth_320) { + val = dot11f_eht_cap.bw_320_rx_max_nss_for_mcs_0_to_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_320_tx_max_nss_for_mcs_0_to_9; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_320_rx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_320_tx_max_nss_for_mcs_10_and_11; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + + val = dot11f_eht_cap.bw_320_rx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_RX_MCS_NSS_MAP_IDX, + EHTCAP_RX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_cap.bw_320_tx_max_nss_for_mcs_12_and_13; + ehtcap_ie_set(&ehtcap->mcs_nss_map_bytes[idx], + EHTCAP_TX_MCS_NSS_MAP_IDX, + EHTCAP_TX_MCS_NSS_MAP_BITS, val); + idx++; + } + } + + /* Fill in TxRx EHT NSS & MCS support */ + mcs_map_len = idx; + ehtcap->elem_len = EHTCAP_FIXED_LEN + mcs_map_len; + ehtcaplen = ehtcap->elem_len + WLAN_IE_HDR_LEN; +} + +#ifdef WLAN_SUPPORT_TWT +static void +populate_dot11f_rtwt_eht_cap(struct mac_context *mac, + tDot11fIEeht_cap *eht_cap) +{ + bool restricted_support = false; + + wlan_twt_get_rtwt_support(mac->psoc, &restricted_support); + + pe_debug("rTWT support: %d", restricted_support); + + eht_cap->restricted_twt = restricted_support; +} +#else +static inline void +populate_dot11f_rtwt_eht_cap(struct mac_context *mac, + tDot11fIEeht_cap *eht_cap) +{ + eht_cap->restricted_twt = false; +} +#endif +static void +populate_dot11f_revise_eht_caps(struct pe_session *session, + tDot11fIEeht_cap *eht_cap) +{ + if (session->ch_width != CH_WIDTH_320MHZ) + eht_cap->support_320mhz_6ghz = 0; + + if (wlan_epcs_get_config(session->vdev)) + eht_cap->epcs_pri_access = 1; + else + eht_cap->epcs_pri_access = 0; +} + +QDF_STATUS populate_dot11f_eht_caps(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEeht_cap *eht_cap) +{ + eht_cap->present = 1; + + if (!session) { + qdf_mem_copy(eht_cap, + &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap, + sizeof(tDot11fIEeht_cap)); + return QDF_STATUS_SUCCESS; + } + + /** TODO: String items needs attention. **/ + qdf_mem_copy(eht_cap, &session->eht_config, sizeof(*eht_cap)); + populate_dot11f_revise_eht_caps(session, eht_cap); + + populate_dot11f_rtwt_eht_cap(mac_ctx, eht_cap); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +populate_dot11f_eht_caps_by_band(struct mac_context *mac_ctx, + bool is_2g, tDot11fIEeht_cap *eht_cap, + struct pe_session *session) +{ + pe_debug("is_2g %d", is_2g); + if (is_2g) + qdf_mem_copy(eht_cap, + &mac_ctx->eht_cap_2g, + sizeof(tDot11fIEeht_cap)); + else + qdf_mem_copy(eht_cap, + &mac_ctx->eht_cap_5g, + sizeof(tDot11fIEeht_cap)); + if (session) + populate_dot11f_revise_eht_caps(session, eht_cap); + + populate_dot11f_rtwt_eht_cap(mac_ctx, eht_cap); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS lim_strip_and_decode_eht_op(uint8_t *ie, uint16_t ie_len, + tDot11fIEeht_op *dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info) +{ + const uint8_t *eht_op_ie; + QDF_STATUS status; + + eht_op_ie = lim_get_ext_ie_ptr_from_ext_id(ie, ie_len, + EHT_OP_OUI_TYPE, + EHT_OP_OUI_SIZE); + + if (!eht_op_ie) + return QDF_STATUS_SUCCESS; + + status = lim_ieee80211_unpack_ehtop(eht_op_ie, dot11f_eht_op, + dot11f_vht_op, dot11f_he_op, + dot11f_ht_info); + + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void lim_ieee80211_pack_ehtop(uint8_t *ie, tDot11fIEeht_op dot11f_eht_op, + tDot11fIEVHTOperation dot11f_vht_op, + tDot11fIEhe_op dot11f_he_op, + tDot11fIEHTInfo dot11f_ht_info) +{ + struct wlan_ie_ehtops *ehtop = (struct wlan_ie_ehtops *)ie; + uint32_t val; + uint32_t i; + uint32_t eht_op_info_len = 0; + uint32_t ehtoplen; + bool diff_chan_width = false; + + if (!ie) { + pe_err("ie is null"); + return; + } + + qdf_mem_zero(ehtop, (sizeof(struct wlan_ie_ehtops))); + + ehtop->elem_id = DOT11F_EID_EHT_OP; + + qdf_mem_copy(&ehtop->elem_id_extn, EHT_OP_OUI_TYPE, EHT_OP_OUI_SIZE); + + if (dot11f_he_op.present && dot11f_he_op.oper_info_6g_present && + (dot11f_he_op.oper_info_6g.info.ch_width != + dot11f_eht_op.channel_width)) { + diff_chan_width = true; + } else if (dot11f_vht_op.present && + (dot11f_vht_op.chanWidth != dot11f_eht_op.channel_width)) { + diff_chan_width = true; + } else if (dot11f_ht_info.present && + (dot11f_ht_info.recommendedTxWidthSet != + dot11f_eht_op.channel_width)) { + diff_chan_width = true; + } + + if (diff_chan_width) { + val = dot11f_eht_op.eht_op_information_present; + EHTOP_PARAMS_INFOP_SET_TO_IE(ehtop->ehtop_param, val); + } + + val = dot11f_eht_op.eht_default_pe_duration; + EHTOP_PARAMS_EHT_DEF_PE_DURATION_SET_TO_IE(ehtop->ehtop_param, val); + + val = dot11f_eht_op.group_addr_bu_indication_limit; + EHTOP_PARAMS_GROUP_ADDR_BU_IND_LIMIT_SET_TO_IE(ehtop->ehtop_param, val); + + val = dot11f_eht_op.group_addr_bu_indication_exponent; + EHTOP_PARAMS_GROUP_ADDR_BU_IND_EXPONENT_SET_TO_IE(ehtop->ehtop_param, + val); + + val = dot11f_eht_op.basic_rx_max_nss_for_mcs_0_to_7; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_0_7, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS, val); + val = dot11f_eht_op.basic_tx_max_nss_for_mcs_0_to_7; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_0_7, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_op.basic_rx_max_nss_for_mcs_8_and_9; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_8_9, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS, val); + val = dot11f_eht_op.basic_tx_max_nss_for_mcs_8_and_9; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_8_9, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_op.basic_rx_max_nss_for_mcs_10_and_11; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_10_11, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS, val); + val = dot11f_eht_op.basic_tx_max_nss_for_mcs_10_and_11; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_10_11, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS, val); + + val = dot11f_eht_op.basic_rx_max_nss_for_mcs_12_and_13; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_12_13, + EHTOP_RX_MCS_NSS_MAP_IDX, + EHTOP_RX_MCS_NSS_MAP_BITS, val); + val = dot11f_eht_op.basic_tx_max_nss_for_mcs_12_and_13; + ehtop_ie_set(&ehtop->basic_mcs_nss_set.max_nss_mcs_12_13, + EHTOP_TX_MCS_NSS_MAP_IDX, + EHTOP_TX_MCS_NSS_MAP_BITS, val); + + if (EHTOP_PARAMS_INFOP_GET_FROM_IE(ehtop->ehtop_param)) { + val = dot11f_eht_op.channel_width; + EHTOP_INFO_CHANWIDTH_SET_TO_IE(ehtop->control, val); + + ehtop->ccfs0 = dot11f_eht_op.ccfs0; + + ehtop->ccfs1 = dot11f_eht_op.ccfs1; + /*1 byte for Control, 1 byte for CCFS0, 1 bytes for CCFS1*/ + eht_op_info_len += 3; + + if (dot11f_eht_op.disabled_sub_chan_bitmap_present) { + val = dot11f_eht_op.disabled_sub_chan_bitmap_present; + EHTOP_PARAMS_DISABLEDSUBCHANBITMAPP_SET_TO_IE(ehtop->ehtop_param, val); + + eht_op_info_len += WLAN_MAX_DISABLED_SUB_CHAN_BITMAP; + + for (i = 0; i < WLAN_MAX_DISABLED_SUB_CHAN_BITMAP; i++) + ehtop->disabled_sub_chan_bitmap[i] = + dot11f_eht_op.disabled_sub_chan_bitmap[0][i]; + } + } + + ehtop->elem_len = EHTOP_FIXED_LEN + eht_op_info_len; + ehtoplen = ehtop->elem_len + WLAN_IE_HDR_LEN; +} + +QDF_STATUS populate_dot11f_eht_operation(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEeht_op *eht_op) +{ + enum phy_ch_width oper_ch_width; + + qdf_mem_copy(eht_op, &session->eht_op, sizeof(*eht_op)); + + eht_op->present = 1; + + eht_op->eht_op_information_present = 1; + + oper_ch_width = wlan_mlme_get_ap_oper_ch_width(session->vdev); + if (oper_ch_width == CH_WIDTH_320MHZ) { + eht_op->channel_width = WLAN_EHT_CHWIDTH_320; + eht_op->ccfs0 = session->ch_center_freq_seg0; + eht_op->ccfs1 = session->ch_center_freq_seg1; + } else if (oper_ch_width == CH_WIDTH_160MHZ || + oper_ch_width == CH_WIDTH_80P80MHZ) { + eht_op->channel_width = WLAN_EHT_CHWIDTH_160; + eht_op->ccfs0 = session->ch_center_freq_seg0; + eht_op->ccfs1 = session->ch_center_freq_seg1; + } else if (oper_ch_width == CH_WIDTH_80MHZ) { + eht_op->channel_width = WLAN_EHT_CHWIDTH_80; + eht_op->ccfs0 = session->ch_center_freq_seg0; + eht_op->ccfs1 = 0; + } else if (oper_ch_width == CH_WIDTH_40MHZ) { + eht_op->channel_width = WLAN_EHT_CHWIDTH_40; + eht_op->ccfs0 = session->ch_center_freq_seg0; + eht_op->ccfs1 = 0; + } else if (oper_ch_width == CH_WIDTH_20MHZ) { + eht_op->channel_width = WLAN_EHT_CHWIDTH_20; + eht_op->ccfs0 = session->ch_center_freq_seg0; + eht_op->ccfs1 = 0; + } + + lim_log_eht_op(mac_ctx, eht_op, session); + + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS populate_dot11f_bw_ind_element(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEbw_ind_element *bw_ind) +{ + tLimChannelSwitchInfo *ch_switch; + + ch_switch = &session->gLimChannelSwitch; + bw_ind->present = true; + bw_ind->channel_width = wlan_mlme_convert_phy_ch_width_to_eht_op_bw( + ch_switch->ch_width); + if (ch_switch->puncture_bitmap) { + bw_ind->disabled_sub_chan_bitmap_present = 1; + bw_ind->disabled_sub_chan_bitmap[0][0] = + QDF_GET_BITS(ch_switch->puncture_bitmap, 0, 8); + bw_ind->disabled_sub_chan_bitmap[0][1] = + QDF_GET_BITS(ch_switch->puncture_bitmap, 8, 8); + } + bw_ind->ccfs0 = ch_switch->ch_center_freq_seg0; + bw_ind->ccfs1 = ch_switch->ch_center_freq_seg1; + + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_FEATURE_11BE */ + +#ifdef WLAN_FEATURE_11BE_MLO +QDF_STATUS +populate_dot11f_probe_req_mlo_ie(struct mac_context *mac, + struct pe_session *session) +{ + struct wlan_mlo_ie *mlo_ie; + uint8_t *p_ml_ie, *sta_data; + uint16_t len_remaining, sta_len_left; + struct wlan_mlo_sta_profile *sta_pro; + int num_sta_pro = 0; + struct mlo_partner_info partner_info; + uint8_t link; + + if (!session || !session->vdev || !session->vdev->mlo_dev_ctx) { + pe_err("Null value"); + return QDF_STATUS_E_NULL_VALUE; + } + + mlo_ie = &session->mlo_ie; + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + + /* set length later */ + *p_ml_ie++ = 0; + len_remaining--; + + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + /* Set ML IE multi link control bitmap: + * ML probe variant type = 1 + * In presence bitmap, set MLD ID presence bit = 1 + */ + mlo_ie->type = WLAN_ML_VARIANT_PROBEREQ; + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, 1); + + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + /* common info length is 2 */ + *p_ml_ie++ = 2; + len_remaining--; + + /* mld id is always 0 for tx link for SAP or AP */ + *p_ml_ie++ = 0; + len_remaining--; + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + if (wlan_vdev_mlme_cap_get(session->vdev, + WLAN_VDEV_C_EXCL_STA_PROF_PRB_REQ)) { + pe_debug("Do not populate sta profile in MLO IE"); + goto no_sta_prof; + } + + partner_info = session->lim_join_req->partner_info; + for (link = 0; link < partner_info.num_partner_links; link++) { + sta_pro = &mlo_ie->sta_profile[num_sta_pro]; + sta_data = sta_pro->data; + sta_len_left = sizeof(sta_pro->data); + + *sta_data++ = WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE; + sta_len_left--; + /* length of subelement, filled at last */ + *sta_data++ = 0; + sta_len_left--; + + QDF_SET_BITS(*(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS, + partner_info.partner_link_info[link].link_id); + + QDF_SET_BITS(*(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS, + 1); + sta_data += WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE; + sta_len_left -= WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_SIZE; + + sta_pro->num_data = sta_data - sta_pro->data; + sta_pro->data[TAG_LEN_POS] = sta_pro->num_data - MIN_IE_LEN; + + num_sta_pro++; + } + +no_sta_prof: + mlo_ie->num_sta_profile = num_sta_pro; + session->lim_join_req->is_ml_probe_req_sent = true; + + return QDF_STATUS_SUCCESS; +} + +#if defined(SAP_MULTI_LINK_EMULATION) +QDF_STATUS populate_dot11f_assoc_rsp_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tpDphHashNode sta, + tDot11fAssocResponse *frm) +{ + struct wlan_mlo_ie *mlo_ie; + struct wlan_mlo_sta_profile *sta_pro; + tpSirAssocReq assoc_req; + uint8_t *sta_data; + uint32_t sta_len_left; + uint8_t common_info_len = 0; + uint8_t *p_ml_ie; + uint16_t len_remaining; + uint16_t presence_bitmap = 0; + uint16_t sta_prof_len; + uint8_t sta_prof_[] = {0x00, 0xff, 0xf1, 0x01, 0x13, 0x02, 0x03, 0x7f, 0x95, 0xaf, 0x62, 0x64, 0x00, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x31, 0x04, 0x00, 0x00, 0x01, 0x08, 0x8c, 0x12, 0x98, 0x24, 0xb0, + 0x48, 0x60, 0x6c, 0x07, 0x0a, 0x55, 0x53, 0x04, 0xc9, 0x83, 0x00, 0x01, 0x3b, 0x00, 0x00, 0x20, + 0x01, 0x00, 0x23, 0x02, 0x0a, 0x00, 0x32, 0x01, 0xfb, 0x7f, 0x0b, 0x04, 0x00, 0x4f, 0x02, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x40, 0x19, 0xc3, 0x02, 0x58, 0x0a, 0xc3, 0x02, 0x18, 0xfe, 0xff, 0x23, + 0x23, 0x0d, 0x01, 0x08, 0x1a, 0x40, 0x10, 0x00, 0x63, 0x40, 0x88, 0x1f, 0x43, 0x81, 0x1c, 0x11, + 0x08, 0x00, 0xaa, 0xff, 0xaa, 0xff, 0x7b, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, + 0x1c, 0xc7, 0x71, 0xff, 0x0c, 0x24, 0xf4, 0x3f, 0x02, 0x28, 0xfc, 0xff, 0x25, 0x00, 0x25, 0x00, + 0x01, 0xff, 0x0e, 0x26, 0x00, 0x03, 0xa4, 0xff, 0x27, 0xa4, 0xff, 0x42, 0x43, 0xff, 0x62, 0x32, + 0xff, 0xff, 0x03, 0x3b, 0xb8, 0x36, 0xff, 0x0f, 0x6c, 0x17, 0x00, 0xe0, 0x03, 0x03, 0x00, 0x18, + 0x76, 0xd8, 0x12, 0x00, 0x44, 0x44, 0x44, 0xff, 0x06, 0x6a, 0x04, 0x11, 0x00, 0x00, 0x00}; + QDF_STATUS status; + + if (!mac_ctx || !session || !frm) + return QDF_STATUS_E_NULL_VALUE; + + mlo_ie = &session->mlo_ie; + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + /* set length later */ + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + mlo_ie->type = 0; + /* Common Info Length*/ + common_info_len += WLAN_ML_BV_CINFO_LENGTH_SIZE; + qdf_mem_copy(mlo_ie->mld_mac_addr, + session->vdev->mlo_dev_ctx->mld_addr.bytes, + sizeof(mlo_ie->mld_mac_addr)); + common_info_len += QDF_MAC_ADDR_SIZE; + + mlo_ie->link_id_info_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P; + mlo_ie->link_id = wlan_vdev_get_link_id(session->vdev); + common_info_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; + + mlo_ie->bss_param_change_cnt_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P; + mlo_ie->bss_param_change_count = + session->mlo_link_info.link_ie.bss_param_change_cnt; + common_info_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE; + + mlo_ie->mld_capab_and_op_present = 1; + mlo_ie->mld_id_present = 1; + mlo_ie->ext_mld_capab_and_op_present = 1; + common_info_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P; + + common_info_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_EMLCAP_P; + + common_info_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P; + + mlo_ie->common_info_length = common_info_len; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = common_info_len; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + QDF_SET_BITS(*p_ml_ie, WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, + WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS, mlo_ie->link_id); + p_ml_ie++; + len_remaining--; + + *p_ml_ie++ = mlo_ie->bss_param_change_count; + len_remaining--; + + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + + if (mlo_ie->mld_capab_and_op_present) { + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_BITS, + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_BITS, + mlo_ie->mld_capab_and_op_info.tid_link_map_supported); + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + } + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + sta_prof_[5] = session->self_mac_addr[0]; + sta_prof_[6] = session->self_mac_addr[1]; + sta_prof_[7] = session->self_mac_addr[2]; + sta_prof_[8] = session->self_mac_addr[3]; + + sta_prof_[9] = 0xaf; + sta_prof_[10] = 0x62; + + sta_pro = &mlo_ie->sta_profile[0]; + sta_data = sta_pro->data; + sta_len_left = sizeof(sta_pro->data); + + sta_prof_len = ARRAY_SIZE(sta_prof_); + qdf_mem_copy(sta_data, sta_prof_, sta_prof_len); + sta_data += sta_prof_len; + sta_len_left -= sta_prof_len; + + sta_pro->num_data = sta_data - sta_pro->data; + pe_debug("num data: %d, sta_prof_len: %d, sta_data len: %d", + sta_pro->num_data, sta_prof_len, sizeof(sta_pro->data)); + sta_pro->data[TAG_LEN_POS] = sta_pro->num_data - MIN_IE_LEN; + + mlo_ie->num_sta_profile = 1; + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = 1; + + if (sta_pro->num_data > WLAN_MAX_IE_LEN + MIN_IE_LEN) { + sta_pro->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN; + status = + lim_add_frag_ie_for_sta_profile(sta_pro->data, + &sta_pro->num_data); + if (status != QDF_STATUS_SUCCESS) { + pe_debug("add frg ie for sta profile error."); + sta_pro->num_data = + WLAN_MAX_IE_LEN + MIN_IE_LEN; + } + } else { + sta_pro->data[TAG_LEN_POS] = + sta_pro->num_data - MIN_IE_LEN; + } + assoc_req = session->parsedAssocReq[sta->assocId]; + + pe_debug("num partner links: %d", assoc_req->mlo_info.num_partner_links); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_bcn_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct wlan_mlo_ie *mlo_ie; + struct wlan_mlo_sta_profile *sta_pro; + uint16_t vdev_count; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; + uint16_t tmp_offset = 0; + struct ml_sch_partner_info *tmp_info; + struct mlo_sch_partner_links *sch_info; + uint8_t *sta_data; + uint8_t common_info_length = 0; + uint8_t *p_ml_ie; + uint16_t len_remaining; + uint16_t presence_bitmap = 0; + uint32_t sta_len_left; + QDF_STATUS status; + uint16_t sta_prof_len; + uint8_t sta_prof_[] = {0x00, 0xff, 0xf1, 0x01, 0x13, 0x02, 0x03, 0x7f, 0x95, 0xaf, 0x62, 0x64, 0x00, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x11, 0x05, 0x01, 0x08, 0x8c, 0x12, 0x98, 0x24, 0xb0, + 0x48, 0x60, 0x6c, 0x07, 0x0a, 0x55, 0x53, 0x04, 0xc9, 0x83, 0x00, 0x01, 0x3b, 0x00, 0x00, 0x20, + 0x01, 0x00, 0x23, 0x02, 0x0a, 0x00, 0x32, 0x01, 0xfb, 0x7f, 0x0b, 0x04, 0x00, 0x4f, 0x02, 0x00, + 0x00, 0x00, 0x40, 0x00, 0x40, 0x19, 0xc3, 0x02, 0x58, 0x0a, 0xc3, 0x02, 0x18, 0xfe, 0xff, 0x23, + 0x23, 0x0d, 0x01, 0x08, 0x1a, 0x40, 0x10, 0x00, 0x63, 0x40, 0x88, 0x1f, 0x43, 0x81, 0x1c, 0x11, + 0x08, 0x00, 0xaa, 0xff, 0xaa, 0xff, 0x7b, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, 0x1c, 0xc7, 0x71, + 0x1c, 0xc7, 0x71, 0xff, 0x0c, 0x24, 0xf4, 0x3f, 0x02, 0x28, 0xfc, 0xff, 0x25, 0x00, 0x25, 0x00, + 0x01, 0xff, 0x0e, 0x26, 0x00, 0x03, 0xa4, 0xff, 0x27, 0xa4, 0xff, 0x42, 0x43, 0xff, 0x62, 0x32, + 0xff, 0xff, 0x03, 0x3b, 0xb8, 0x36, 0xff, 0x0f, 0x6c, 0x17, 0x00, 0xe0, 0x03, 0x03, 0x00, 0x18, + 0x76, 0xd8, 0x12, 0x00, 0x44, 0x44, 0x44, 0xff, 0x06, 0x6a, 0x04, 0x11, 0x00, 0x00, 0x00}; + if (!mac_ctx || !session) + return QDF_STATUS_E_NULL_VALUE; + + mlo_ie = &session->mlo_ie; + + /* Common Info Length */ + common_info_length += WLAN_ML_BV_CINFO_LENGTH_SIZE; + qdf_mem_zero(&mac_ctx->sch.sch_mlo_partner, + sizeof(mac_ctx->sch.sch_mlo_partner)); + sch_info = &mac_ctx->sch.sch_mlo_partner; + mlo_ie->type = 0; + tmp_offset += 1; /* Element ID */ + tmp_offset += 1; /* length */ + tmp_offset += 1; /* Element ID extension */ + tmp_offset += 2; /* Multi-link control */ + qdf_mem_copy(mlo_ie->mld_mac_addr, + session->vdev->mlo_dev_ctx->mld_addr.bytes, + sizeof(mlo_ie->mld_mac_addr)); + tmp_offset += 1; /* Common Info Length */ + tmp_offset += 6; /* mld mac addr */ + common_info_length += QDF_MAC_ADDR_SIZE; + mlo_ie->link_id_info_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P; + mlo_ie->link_id = wlan_vdev_get_link_id(session->vdev); + tmp_offset += 1; /* link id */ + common_info_length += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; + mlo_ie->bss_param_change_cnt_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P; + mlo_ie->bss_param_change_count = + session->mlo_link_info.link_ie.bss_param_change_cnt; + tmp_offset += 1; /* bss parameters change count */ + common_info_length += WLAN_ML_BSSPARAMCHNGCNT_SIZE; + + tmp_offset += 2;/* MLD Parameters */ + mlo_ie->mld_capab_and_op_present = 1; + mlo_ie->mld_id_present = 1; + mlo_ie->ext_mld_capab_and_op_present = 1; + sch_info->num_links = 1; + common_info_length += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P; + + tmp_offset += 2; + common_info_length += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_EMLCAP_P; + + tmp_offset += 2; + common_info_length += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MEDIUMSYNCDELAYINFO_P; + + lim_get_mlo_vdev_list(session, &vdev_count, wlan_vdev_list); + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = + vdev_count; + + mlo_ie->mld_capab_and_op_info.tid_link_map_supported = 1; + + mlo_ie->common_info_length = common_info_length; + sch_info->mlo_ie_link_info_ofst = tmp_offset; + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = common_info_length; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + QDF_SET_BITS(*p_ml_ie, WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, + WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS, + mlo_ie->link_id); + p_ml_ie++; + len_remaining--; + + *p_ml_ie++ = mlo_ie->bss_param_change_count; + len_remaining--; + + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + + if (mlo_ie->mld_capab_and_op_present) { + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_BITS, + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_BITS, + mlo_ie->mld_capab_and_op_info.tid_link_map_supported); + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + } + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + sta_prof_[5] = session->self_mac_addr[0]; + sta_prof_[6] = session->self_mac_addr[1]; + sta_prof_[7] = session->self_mac_addr[2]; + sta_prof_[8] = session->self_mac_addr[3]; + + sta_prof_[9] = 0xaf; + sta_prof_[10] = 0x62; + + sta_pro = &mlo_ie->sta_profile[0]; + sta_data = sta_pro->data; + sta_len_left = sizeof(sta_pro->data); + + sta_prof_len = ARRAY_SIZE(sta_prof_); + qdf_mem_copy(sta_data, sta_prof_, sta_prof_len); + sta_data += sta_prof_len; + sta_len_left -= sta_prof_len; + sch_info->num_links = 1; + mlo_ie->num_sta_profile = 1; + + sta_pro->num_data = sta_data - sta_pro->data; + pe_debug("num data: %d, sta_prof_len: %d, sta_data len: %d", + sta_pro->num_data, sta_prof_len, sizeof(sta_pro->data)); + sta_pro->data[TAG_LEN_POS] = sta_pro->num_data - MIN_IE_LEN; + tmp_info = &sch_info->partner_info[0]; + tmp_info->link_info_sta_prof_ofst = sta_prof_len; + + mlo_ie->num_sta_profile = 1; + status = QDF_STATUS_SUCCESS; + + return status; +} +#else +QDF_STATUS populate_dot11f_assoc_rsp_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session, + tpDphHashNode sta, + tDot11fAssocResponse *frm) +{ + int link; + int num_sta_pro = 0; + struct wlan_mlo_ie *mlo_ie; + struct wlan_mlo_sta_profile *sta_pro; + struct mlo_link_ie_info *link_info; + struct mlo_link_ie *link_ie; + tpSirAssocReq assoc_req; + tpSirAssocReq link_assoc_req; + const uint8_t *reported_p2p_ie; + uint8_t non_inher_ie_lists[255]; + uint8_t non_inher_len; + uint8_t non_inher_ext_len; + uint8_t non_inher_ext_ie_lists[255]; + bool same_ie, reported_vendor_vht_ie_pres; + bool reported_wmm_caps_pres, reported_wmm_param_pres; + tDot11fIEvendor_vht_ie vendor_vht_ie; + tpDphHashNode link_sta; + tDot11fIESuppRates supp_rates; + tDot11fIEExtSuppRates ext_supp_rates; + uint8_t lle_mode; + struct pe_session *link_session; + uint16_t assoc_id = 0; + uint8_t link_id; + uint8_t *sta_addr; + uint8_t *sta_data; + uint32_t sta_len_left; + uint32_t sta_len_consumed; + tDot11fFfStatus sta_status; + tDot11fIEP2PAssocRes sta_p2p_assoc_res; + tDot11fIEnon_inheritance sta_non_inheritance; + uint8_t common_info_len = 0, len = 0; + uint8_t *p_ml_ie; + uint16_t len_remaining; + uint16_t presence_bitmap = 0; + QDF_STATUS status; + + if (!mac_ctx || !session || !frm) + return QDF_STATUS_E_NULL_VALUE; + + mlo_ie = &session->mlo_ie; + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + /* set length later */ + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + mlo_ie->type = 0; + /* Common Info Length*/ + common_info_len += WLAN_ML_BV_CINFO_LENGTH_SIZE; + qdf_mem_copy(mlo_ie->mld_mac_addr, + session->vdev->mlo_dev_ctx->mld_addr.bytes, + sizeof(mlo_ie->mld_mac_addr)); + common_info_len += QDF_MAC_ADDR_SIZE; + + mlo_ie->link_id_info_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P; + mlo_ie->link_id = wlan_vdev_get_link_id(session->vdev); + common_info_len += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; + + mlo_ie->bss_param_change_cnt_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P; + mlo_ie->bss_param_change_count = + session->mlo_link_info.link_ie.bss_param_change_cnt; + common_info_len += WLAN_ML_BSSPARAMCHNGCNT_SIZE; + + mlo_ie->mld_capab_and_op_present = 0; + mlo_ie->mld_id_present = 0; + mlo_ie->ext_mld_capab_and_op_present = 0; + + mlo_ie->common_info_length = common_info_len; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = common_info_len; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + QDF_SET_BITS(*p_ml_ie, WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, + WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS, mlo_ie->link_id); + p_ml_ie++; + len_remaining--; + + *p_ml_ie++ = mlo_ie->bss_param_change_count; + len_remaining--; + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + assoc_req = session->parsedAssocReq[sta->assocId]; + if (!assoc_req) + goto no_partner; + + for (link = 0; link < assoc_req->mlo_info.num_partner_links; link++) { + lle_mode = 0; + sta_pro = &mlo_ie->sta_profile[num_sta_pro]; + link_id = assoc_req->mlo_info.partner_link_info[link].link_id; + link_session = pe_find_partner_session_by_link_id(session, + link_id); + if (!link_session) + continue; + link_info = &link_session->mlo_link_info; + link_ie = &link_info->link_ie; + sta_addr = + assoc_req->mlo_info.partner_link_info[link].link_addr.bytes; + link_sta = dph_lookup_hash_entry( + mac_ctx, + sta_addr, + &assoc_id, + &link_session->dph.dphHashTable); + if (!link_sta) { + lim_mlo_release_vdev_ref(link_session->vdev); + continue; + } + link_assoc_req = + link_session->parsedAssocReq[link_sta->assocId]; + sta_data = sta_pro->data; + sta_len_left = sizeof(sta_pro->data); + + *sta_data++ = WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE; + /* set length later */ + *sta_data++ = 0; + sta_len_left -= 2; + + QDF_SET_BITS( + *(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS, + link_id); + QDF_SET_BITS( + *(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS, + 1); + QDF_SET_BITS( + *(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS, + 1); + QDF_SET_BITS( + *(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS, + 1); + QDF_SET_BITS( + *(uint16_t *)sta_data, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS, + 1); + /* sta control */ + sta_data += 2; + sta_len_left -= 2; + + /* + * 1 Bytes for STA Info Length + 6 bytes for STA MAC Address + + * 2 Bytes for Becon Interval + 2 Bytes for DTIM Info + */ + len = WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE + + QDF_MAC_ADDR_SIZE + WLAN_BEACONINTERVAL_LEN + + sizeof(struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo); + *sta_data = len; + + /* STA Info Length */ + sta_data += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; + sta_len_left -= WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; + + /*mac addr*/ + qdf_mem_copy(sta_data, link_session->self_mac_addr, + QDF_MAC_ADDR_SIZE); + sta_data += QDF_MAC_ADDR_SIZE; + sta_len_left -= QDF_MAC_ADDR_SIZE; + /* Beacon interval */ + *(uint16_t *)sta_data = + link_session->beaconParams.beaconInterval; + sta_data += WLAN_BEACONINTERVAL_LEN; + sta_len_left -= WLAN_BEACONINTERVAL_LEN; + /* DTIM populated by FW */ + sta_data += sizeof( + struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo); + sta_len_left -= sizeof( + struct wlan_ml_bv_linfo_perstaprof_stainfo_dtiminfo); + /* Capabilities */ + dot11f_pack_ff_capabilities(mac_ctx, &link_ie->link_cap, + sta_data); + sta_data += WLAN_CAPABILITYINFO_LEN; + sta_len_left -= WLAN_CAPABILITYINFO_LEN; + /* status */ + sta_status.status = 0; + dot11f_pack_ff_status(mac_ctx, &sta_status, sta_data); + sta_data += WLAN_STATUSCODE_LEN; + sta_len_left -= WLAN_STATUSCODE_LEN; + + qdf_mem_zero(non_inher_ie_lists, sizeof(non_inher_ie_lists)); + qdf_mem_zero(non_inher_ext_ie_lists, + sizeof(non_inher_ext_ie_lists)); + qdf_mem_zero(&supp_rates, sizeof(tDot11fIESuppRates)); + qdf_mem_zero(&ext_supp_rates, sizeof(tDot11fIEExtSuppRates)); + qdf_mem_zero(&sta_p2p_assoc_res, sizeof(tDot11fIEP2PAssocRes)); + qdf_mem_zero(&sta_non_inheritance, + sizeof(tDot11fIEnon_inheritance)); + non_inher_len = 0; + non_inher_ext_len = 0; + + populate_dot11f_assoc_rsp_rates( + mac_ctx, &supp_rates, + &ext_supp_rates, + link_sta->supportedRates.llbRates, + link_sta->supportedRates.llaRates); + if ((supp_rates.present && frm->SuppRates.present && + qdf_mem_cmp(&supp_rates, &frm->SuppRates, + sizeof(supp_rates))) || + (supp_rates.present && !frm->SuppRates.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_supp_rates(mac_ctx, &supp_rates, + sta_data, + sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->SuppRates.present && !supp_rates.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_SUPPRATES; + } + + if (link_session->limQosEnabled && link_sta->lleEnabled) { + lle_mode = 1; + if ((link_ie->link_edca.present && + frm->EDCAParamSet.present && + qdf_mem_cmp(&link_ie->link_edca, + &frm->EDCAParamSet, + sizeof(link_ie->link_edca))) || + (link_ie->link_edca.present && + !frm->EDCAParamSet.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_edca_param_set( + mac_ctx, &link_ie->link_edca, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->EDCAParamSet.present && + !link_ie->link_edca.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_EDCAPARAMSET; + } + } + + if ((link_ie->link_ht_cap.present && frm->HTCaps.present && + qdf_mem_cmp(&link_ie->link_ht_cap, &frm->HTCaps, + sizeof(tDot11fIEHTCaps))) || + (link_ie->link_ht_cap.present && !frm->HTCaps.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_ht_caps( + mac_ctx, &link_ie->link_ht_cap, + sta_data, sta_len_left, &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->HTCaps.present && + !link_ie->link_ht_cap.present) { + non_inher_ie_lists[non_inher_len++] = DOT11F_EID_HTCAPS; + } + + if ((ext_supp_rates.present && frm->ExtSuppRates.present && + qdf_mem_cmp(&ext_supp_rates, &frm->ExtSuppRates, + sizeof(ext_supp_rates))) || + (ext_supp_rates.present && !frm->ExtSuppRates.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_ext_supp_rates( + mac_ctx, &ext_supp_rates, sta_data, + sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->SuppRates.present && !ext_supp_rates.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_EXTSUPPRATES; + } + + if ((link_ie->link_ht_info.present && frm->HTInfo.present && + qdf_mem_cmp(&link_ie->link_ht_info, &frm->HTInfo, + sizeof(tDot11fIEHTInfo))) || + (link_ie->link_ht_info.present && !frm->HTInfo.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_ht_info( + mac_ctx, &link_ie->link_ht_info, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->HTInfo.present && + !link_ie->link_ht_info.present) { + non_inher_ie_lists[non_inher_len++] = DOT11F_EID_HTINFO; + } + + if ((link_ie->link_ext_cap.present && frm->ExtCap.present && + qdf_mem_cmp(&link_ie->link_ext_cap, &frm->ExtCap, + sizeof(tDot11fIEExtCap))) || + (link_ie->link_ext_cap.present && !frm->ExtCap.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_ext_cap( + mac_ctx, &link_ie->link_ext_cap, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->ExtCap.present && + !link_ie->link_ext_cap.present) { + non_inher_ie_lists[non_inher_len++] = DOT11F_EID_EXTCAP; + } + + if ((link_ie->link_vht_cap.present && frm->VHTCaps.present && + qdf_mem_cmp(&link_ie->link_vht_cap, &frm->VHTCaps, + sizeof(frm->VHTCaps))) || + (link_ie->link_vht_cap.present && !frm->VHTCaps.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_vht_caps( + mac_ctx, &link_ie->link_vht_cap, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->VHTCaps.present && + !link_ie->link_vht_cap.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_VHTCAPS; + } + + if ((link_ie->link_vht_op.present && + frm->VHTOperation.present && + qdf_mem_cmp(&link_ie->link_vht_op, &frm->VHTOperation, + sizeof(tDot11fIEVHTOperation))) || + (link_ie->link_vht_op.present && + !frm->VHTOperation.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_vht_operation( + mac_ctx, &link_ie->link_vht_op, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->VHTOperation.present && + !link_ie->link_vht_op.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_VHTOPERATION; + } + /* Check every 221 EID whether it's the same with assoc link */ + same_ie = false; + // P2PAssocRes is different or not + if (link_assoc_req) + reported_p2p_ie = limGetP2pIEPtr( + mac_ctx, + link_assoc_req->addIE.addIEdata, + link_assoc_req->addIE.length); + else + reported_p2p_ie = NULL; + if ((reported_p2p_ie && frm->P2PAssocRes.present) || + (!reported_p2p_ie && !frm->P2PAssocRes.present)) + same_ie = true; + // vendor_vht_ie is different or not + reported_vendor_vht_ie_pres = + link_session->vhtCapability && + link_session->vendor_vht_sap && + link_assoc_req && + link_assoc_req->vendor_vht_ie.VHTCaps.present; + if (same_ie && frm->vendor_vht_ie.VHTCaps.present && + reported_vendor_vht_ie_pres) { + if (qdf_mem_cmp(&link_ie->link_vht_cap, + &frm->vendor_vht_ie.VHTCaps, + sizeof(tDot11fIEVHTCaps)) || + qdf_mem_cmp(&link_ie->link_vht_op, + &frm->vendor_vht_ie.VHTOperation, + sizeof(tDot11fIEVHTOperation))) + same_ie = false; + + } else if (same_ie && ((frm->vendor_vht_ie.VHTCaps.present && + !reported_vendor_vht_ie_pres) || + (!frm->vendor_vht_ie.VHTCaps.present && + reported_vendor_vht_ie_pres))) { + same_ie = false; + } + // qcn ie is different or not + if (same_ie && link_ie->link_qcn_ie.present && + frm->qcn_ie.present) { + if (qdf_mem_cmp(&link_ie->link_qcn_ie, &frm->qcn_ie, + sizeof(tDot11fIEqcn_ie))) + same_ie = false; + } else if (same_ie && ((link_ie->link_qcn_ie.present && + !frm->qcn_ie.present) || + (!link_ie->link_qcn_ie.present && + frm->qcn_ie.present))) { + same_ie = false; + } + /* wmm param and wmm caps are different or not*/ + reported_wmm_caps_pres = false; + reported_wmm_param_pres = false; + if (!lle_mode && link_session->limWmeEnabled && + link_sta->wmeEnabled) { + if (link_ie->link_wmm_params.present) + reported_wmm_param_pres = true; + + if (link_sta->wsmEnabled && + link_ie->link_wmm_caps.present) + reported_wmm_caps_pres = true; + } + if (same_ie && reported_wmm_param_pres && + frm->WMMParams.present) { + if (qdf_mem_cmp(&link_ie->link_wmm_params, + &frm->WMMParams, + sizeof(link_ie->link_wmm_params))) + same_ie = false; + } else if (same_ie && ((reported_wmm_param_pres && + !frm->WMMParams.present) || + (!reported_wmm_param_pres && + frm->WMMParams.present))) { + same_ie = false; + } + if (same_ie && reported_wmm_caps_pres && + frm->WMMCaps.present) { + if (qdf_mem_cmp(&link_ie->link_wmm_caps, + &frm->WMMCaps, + sizeof(link_ie->link_wmm_caps))) + same_ie = false; + } else if (same_ie && ((reported_wmm_caps_pres && + !frm->WMMCaps.present) || + (!reported_wmm_caps_pres && + frm->WMMCaps.present))) { + same_ie = false; + } + /* + * Nothing need to do if all 221 ie in the reported assoc resp + * are the same with reporting assoc resp. + */ + if (!same_ie) { + if (reported_p2p_ie && link_assoc_req) { + populate_dot11_assoc_res_p2p_ie( + mac_ctx, + &sta_p2p_assoc_res, + link_assoc_req); + sta_len_consumed = 0; + dot11f_pack_ie_p2_p_assoc_res( + mac_ctx, &sta_p2p_assoc_res, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } + if (reported_vendor_vht_ie_pres) { + qdf_mem_zero(&vendor_vht_ie, + sizeof(vendor_vht_ie)); + vendor_vht_ie.present = 1; + vendor_vht_ie.sub_type = + link_session->vendor_specific_vht_ie_sub_type; + populate_dot11f_vht_caps( + mac_ctx, link_session, + &vendor_vht_ie.VHTCaps); + populate_dot11f_vht_operation( + mac_ctx, link_session, + &vendor_vht_ie.VHTOperation); + + sta_len_consumed = 0; + dot11f_pack_ie_vendor_vht_ie( + mac_ctx, &vendor_vht_ie, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } + sta_len_consumed = 0; + dot11f_pack_ie_qcn_ie( + mac_ctx, &link_ie->link_qcn_ie, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + if (reported_wmm_param_pres) { + sta_len_consumed = 0; + dot11f_pack_ie_wmm_params( + mac_ctx, + &link_ie->link_wmm_params, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } + if (reported_wmm_caps_pres) { + sta_len_consumed = 0; + dot11f_pack_ie_wmm_caps( + mac_ctx, + &link_ie->link_wmm_caps, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } + /* + * if there is no 221 IE in partner link + * while there is such IE in current link + * include 221 in the non inheritance IE lists + */ + if (!reported_p2p_ie && + !link_ie->link_qcn_ie.present && + !reported_vendor_vht_ie_pres && + !reported_wmm_caps_pres && !reported_wmm_param_pres) + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_QCN_IE; + } + + if ((link_ie->link_he_cap.present && frm->he_cap.present && + qdf_mem_cmp(&link_ie->link_he_cap, &frm->he_cap, + sizeof(frm->he_cap))) || + (link_ie->link_he_cap.present && !frm->he_cap.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_he_cap( + mac_ctx, &link_ie->link_he_cap, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->he_cap.present && + !link_ie->link_he_cap.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_HECAP; + } + + if ((link_ie->link_he_op.present && frm->he_op.present && + qdf_mem_cmp(&link_ie->link_he_op, &frm->he_op, + sizeof(tDot11fIEhe_op))) || + (link_ie->link_he_op.present && !frm->he_op.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_he_op( + mac_ctx, &link_ie->link_he_op, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->he_op.present && !link_ie->link_he_op.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_HEOP; + } + if ((link_ie->link_he_6ghz_band_cap.present && + frm->he_6ghz_band_cap.present && + qdf_mem_cmp(&link_ie->link_he_6ghz_band_cap, + &frm->he_6ghz_band_cap, + sizeof(tDot11fIEhe_6ghz_band_cap))) || + (link_ie->link_he_6ghz_band_cap.present && + !frm->he_6ghz_band_cap.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_he_6ghz_band_cap( + mac_ctx, &link_ie->link_he_6ghz_band_cap, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->he_6ghz_band_cap.present && + !link_ie->link_he_6ghz_band_cap.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_HE_6G_CAP; + } + if ((link_ie->link_eht_op.present && frm->eht_op.present && + qdf_mem_cmp(&link_ie->link_eht_op, &frm->eht_op, + sizeof(tDot11fIEeht_op))) || + (link_ie->link_eht_op.present && !frm->eht_op.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_eht_op( + mac_ctx, &link_ie->link_eht_op, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->eht_op.present && + !link_ie->link_eht_op.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_EHTOP; + } + if ((link_ie->link_eht_cap.present && frm->eht_cap.present && + qdf_mem_cmp(&link_ie->link_eht_cap, &frm->eht_cap, + sizeof(frm->eht_cap))) || + (link_ie->link_eht_cap.present && !frm->eht_cap.present)) { + sta_len_consumed = 0; + dot11f_pack_ie_eht_cap( + mac_ctx, &link_ie->link_eht_cap, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } else if (frm->eht_cap.present && + !link_ie->link_eht_cap.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_EHTCAP; + } + populate_dot11f_non_inheritance(mac_ctx, &sta_non_inheritance, + non_inher_ie_lists, + non_inher_ext_ie_lists, + non_inher_len, + non_inher_ext_len); + if (sta_non_inheritance.present) { + sta_len_consumed = 0; + dot11f_pack_ie_non_inheritance( + mac_ctx, &sta_non_inheritance, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + } + sta_pro->num_data = sta_data - sta_pro->data; + if (sta_pro->num_data > WLAN_MAX_IE_LEN + MIN_IE_LEN) { + sta_pro->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN; + status = + lim_add_frag_ie_for_sta_profile(sta_pro->data, + &sta_pro->num_data); + if (status != QDF_STATUS_SUCCESS) { + pe_debug("add frg ie for sta profile error."); + sta_pro->num_data = + WLAN_MAX_IE_LEN + MIN_IE_LEN; + } + } else { + sta_pro->data[TAG_LEN_POS] = + sta_pro->num_data - MIN_IE_LEN; + } + lim_mlo_release_vdev_ref(link_session->vdev); + num_sta_pro++; + } + +no_partner: + mlo_ie->num_sta_profile = num_sta_pro; + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = num_sta_pro; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_bcn_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session) +{ + int link; + int num_sta_pro = 0; + struct wlan_mlo_ie *mlo_ie; + struct wlan_mlo_sta_profile *sta_pro; + struct mlo_link_ie *link_ie; + uint16_t vdev_count; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; + struct pe_session *link_session; + uint16_t tmp_offset = 0; + struct ml_sch_partner_info *tmp_info; + struct mlo_sch_partner_links *sch_info; + uint8_t *sta_data; + uint32_t sta_len_left; + uint32_t sta_len_consumed; + uint8_t common_info_length = 0; + uint8_t *p_ml_ie; + uint16_t len_remaining; + uint16_t presence_bitmap = 0; + bool sta_pro_present; + QDF_STATUS status; + + if (!mac_ctx || !session) + return QDF_STATUS_E_NULL_VALUE; + + mlo_ie = &session->mlo_ie; + + /* Common Info Length */ + common_info_length += WLAN_ML_BV_CINFO_LENGTH_SIZE; + qdf_mem_zero(&mac_ctx->sch.sch_mlo_partner, + sizeof(mac_ctx->sch.sch_mlo_partner)); + sch_info = &mac_ctx->sch.sch_mlo_partner; + mlo_ie->type = 0; + tmp_offset += 1; /* Element ID */ + tmp_offset += 1; /* length */ + tmp_offset += 1; /* Element ID extension */ + tmp_offset += 2; /* Multi-link control */ + qdf_mem_copy(mlo_ie->mld_mac_addr, + session->vdev->mlo_dev_ctx->mld_addr.bytes, + sizeof(mlo_ie->mld_mac_addr)); + tmp_offset += 1; /* Common Info Length */ + tmp_offset += 6; /* mld mac addr */ + common_info_length += QDF_MAC_ADDR_SIZE; + mlo_ie->link_id_info_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_LINKIDINFO_P; + mlo_ie->link_id = wlan_vdev_get_link_id(session->vdev); + tmp_offset += 1; /* link id */ + common_info_length += WLAN_ML_BV_CINFO_LINKIDINFO_SIZE; + mlo_ie->bss_param_change_cnt_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P; + mlo_ie->bss_param_change_count = + session->mlo_link_info.link_ie.bss_param_change_cnt; + tmp_offset += 1; /* bss parameters change count */ + common_info_length += WLAN_ML_BSSPARAMCHNGCNT_SIZE; + mlo_ie->mld_capab_and_op_present = 0; + mlo_ie->mld_id_present = 0; + mlo_ie->ext_mld_capab_and_op_present = 0; + sch_info->num_links = 0; + + lim_get_mlo_vdev_list(session, &vdev_count, wlan_vdev_list); + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = + vdev_count - 1; + + mlo_ie->common_info_length = common_info_length; + sch_info->mlo_ie_link_info_ofst = tmp_offset; + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = common_info_length; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + QDF_SET_BITS(*p_ml_ie, WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_IDX, + WLAN_ML_BV_CINFO_LINKIDINFO_LINKID_BITS, + mlo_ie->link_id); + p_ml_ie++; + len_remaining--; + + *p_ml_ie++ = mlo_ie->bss_param_change_count; + len_remaining--; + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + for (link = 0; link < vdev_count; link++) { + if (!wlan_vdev_list[link]) + continue; + if (wlan_vdev_list[link] == session->vdev) { + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + if (!wlan_vdev_mlme_is_mlo_ap(wlan_vdev_list[link])) { + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + link_session = pe_find_session_by_vdev_id( + mac_ctx, wlan_vdev_list[link]->vdev_objmgr.vdev_id); + if (!link_session) { + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + sta_pro = &mlo_ie->sta_profile[num_sta_pro]; + link_ie = &link_session->mlo_link_info.link_ie; + tmp_info = &sch_info->partner_info[sch_info->num_links++]; + tmp_info->vdev_id = wlan_vdev_get_id(wlan_vdev_list[link]); + tmp_info->beacon_interval = + link_session->beaconParams.beaconInterval; + sta_pro_present = false; + sta_data = sta_pro->data; + sta_len_left = sizeof(sta_pro->data); + *sta_data++ = WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE; + *sta_data++ = 0; + sta_data += 2; /* sta control */ + sta_len_left -= 4; + tmp_offset = 1; /* sub element id */ + tmp_offset += 1; /* length */ + if (link_ie->link_csa.present) { + sta_len_consumed = 0; + dot11f_pack_ie_chan_switch_ann(mac_ctx, + &link_ie->link_csa, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + sta_pro_present = true; + tmp_info->csa_ext_csa_exist = true; + } + if (link_ie->link_ecsa.present) { + sta_len_consumed = 0; + dot11f_pack_ie_ext_chan_switch_ann(mac_ctx, + &link_ie->link_ecsa, + sta_data, + sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + sta_pro_present = true; + tmp_info->csa_ext_csa_exist = true; + } + if (link_ie->link_quiet.present) { + sta_len_consumed = 0; + dot11f_pack_ie_quiet(mac_ctx, &link_ie->link_quiet, + sta_data, sta_len_left, + &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + sta_pro_present = true; + } + if (link_ie->link_swt_time.present) { + sta_len_consumed = 0; + dot11f_pack_ie_max_chan_switch_time( + mac_ctx, &link_ie->link_swt_time, sta_data, + sta_len_left, &sta_len_consumed); + sta_data += sta_len_consumed; + sta_len_left -= sta_len_consumed; + sta_pro_present = true; + } + if (sta_pro_present) { + sta_pro->num_data = sta_data - sta_pro->data; + if (sta_pro->num_data > WLAN_MAX_IE_LEN + MIN_IE_LEN) { + sta_pro->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN; + status = + lim_add_frag_ie_for_sta_profile(sta_pro->data, + &sta_pro->num_data); + if (status != QDF_STATUS_SUCCESS) { + pe_debug("STA profile flag error"); + sta_pro->num_data = + WLAN_MAX_IE_LEN + MIN_IE_LEN; + } + } else { + sta_pro->data[TAG_LEN_POS] = + sta_pro->num_data - MIN_IE_LEN; + } + QDF_SET_BITS( + *(uint16_t *)(sta_pro->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS, + wlan_vdev_get_link_id(link_session->vdev)); + + num_sta_pro++; + tmp_offset += 2; /* sta control */ + tmp_info->link_info_sta_prof_ofst = tmp_offset; + } + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + } + mlo_ie->num_sta_profile = num_sta_pro; + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS populate_dot11f_tdls_mgmt_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *session) +{ + struct wlan_mlo_ie *mlo_ie; + uint8_t *p_ml_ie; + uint16_t len_remaining; + uint16_t presence_bitmap = 0; + uint8_t common_info_length = 0; + + if (!mac_ctx || !session) + return QDF_STATUS_E_NULL_VALUE; + + mlo_ie = &session->mlo_ie; + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + *p_ml_ie++ = 0; + len_remaining--; + + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + common_info_length += WLAN_ML_BV_CINFO_LENGTH_SIZE; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_BSSPARAMCHANGECNT_P; + common_info_length += WLAN_ML_BSSPARAMCHNGCNT_SIZE; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, WLAN_ML_VARIANT_TDLS); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = common_info_length; + len_remaining--; + + qdf_mem_copy(p_ml_ie, session->vdev->mlo_dev_ctx->mld_addr.bytes, + QDF_MAC_ADDR_SIZE); + + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + return QDF_STATUS_SUCCESS; +} + +#if defined (SAP_MULTI_LINK_EMULATION) +static void populate_2link_rnr_info(struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f) +{ + tSirMacAddr fake_mac_addr; + + qdf_mem_copy(fake_mac_addr, session->self_mac_addr, sizeof(tSirMacAddr)); + + pe_debug(QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(fake_mac_addr)); + + dot11f->present = 1; + dot11f->op_class = 131; + dot11f->channel_num = 37; + + dot11f->tbtt_info_count = 0; + dot11f->tbtt_info_len = 16; + + fake_mac_addr[4] = 0xaf; + fake_mac_addr[5] = 0x62; + qdf_mem_copy(dot11f->tbtt_info.tbtt_info_16.bssid, + fake_mac_addr, sizeof(tSirMacAddr)); + dot11f->tbtt_info.tbtt_info_16.mld_id = 0; + dot11f->tbtt_info.tbtt_info_16.link_id = 1; + + dot11f->tbtt_info.tbtt_info_16.bss_params = 0x4e; + dot11f->tbtt_info.tbtt_info_16.short_ssid = 0x558df58e; + dot11f->tbtt_info.tbtt_info_16.psd_20mhz = 0xfe; + + dot11f->tbtt_info.tbtt_info_16.bss_param_change_cnt = + session->mlo_link_info.link_ie.bss_param_change_cnt; + + pe_debug("Populated rnr IE..."); +} +#else +static inline void populate_2link_rnr_info(struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f) +{ +} +#endif + +void populate_dot11f_mlo_rnr(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f) +{ + int link; + uint16_t vdev_count; + struct wlan_objmgr_vdev *wlan_vdev_list[WLAN_UMAC_MLO_MAX_VDEVS]; + struct pe_session *link_session; + bool rnr_populated = false; + + lim_get_mlo_vdev_list(session, &vdev_count, wlan_vdev_list); + for (link = 0; link < vdev_count; link++) { + if (!wlan_vdev_list[link]) + continue; + if (wlan_vdev_list[link] == session->vdev) { + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + if (!wlan_vdev_mlme_is_mlo_ap(wlan_vdev_list[link])) { + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + link_session = pe_find_session_by_vdev_id( + mac_ctx, wlan_vdev_get_id(wlan_vdev_list[link])); + if (!link_session) { + pe_debug("vdev id %d pe session is not created", + wlan_vdev_get_id(wlan_vdev_list[link])); + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + continue; + } + if (!rnr_populated) { + populate_dot11f_rnr_tbtt_info_16(mac_ctx, session, + link_session, dot11f); + pe_debug("mlo vdev id %d populate vdev id %d link id %d op class %d chan num %d in RNR IE", + wlan_vdev_get_id(session->vdev), + wlan_vdev_get_id(wlan_vdev_list[link]), + dot11f->tbtt_info.tbtt_info_16.link_id, + dot11f->op_class, dot11f->channel_num); + rnr_populated = true; + } + lim_mlo_release_vdev_ref(wlan_vdev_list[link]); + } + + populate_2link_rnr_info(session, dot11f); + +} + +void populate_dot11f_rnr_tbtt_info_16(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f) +{ + uint8_t reg_class; + uint8_t ch_offset; + + dot11f->present = 1; + dot11f->tbtt_type = 0; + if (rnr_session->ch_width == CH_WIDTH_80MHZ) { + ch_offset = BW80; + } else { + switch (rnr_session->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_offset = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_offset = BW40_LOW_PRIMARY; + break; + default: + ch_offset = BW20; + break; + } + } + + reg_class = lim_op_class_from_bandwidth(mac_ctx, + rnr_session->curr_op_freq, + rnr_session->ch_width, + ch_offset); + + dot11f->op_class = reg_class; + dot11f->channel_num = wlan_reg_freq_to_chan(mac_ctx->pdev, + rnr_session->curr_op_freq); + dot11f->tbtt_info_count = 0; + dot11f->tbtt_info_len = 16; + qdf_mem_copy(dot11f->tbtt_info.tbtt_info_16.bssid, + rnr_session->self_mac_addr, sizeof(tSirMacAddr)); + dot11f->tbtt_info.tbtt_info_16.mld_id = 0; + dot11f->tbtt_info.tbtt_info_16.link_id = wlan_vdev_get_link_id( + rnr_session->vdev); + dot11f->tbtt_info.tbtt_info_16.bss_param_change_cnt = + rnr_session->mlo_link_info.link_ie.bss_param_change_cnt; +} + +QDF_STATUS +populate_dot11f_mlo_caps(struct mac_context *mac_ctx, + struct pe_session *session, + struct wlan_mlo_ie *mlo_ie) +{ + uint8_t *mld_addr; + uint8_t common_info_len = 0; + + mlo_ie->type = 0; + /* Common Info Length */ + common_info_len += WLAN_ML_BV_CINFO_LENGTH_SIZE; + mld_addr = wlan_vdev_mlme_get_mldaddr(session->vdev); + qdf_mem_copy(&mlo_ie->mld_mac_addr, mld_addr, + sizeof(mlo_ie->mld_mac_addr)); + common_info_len += QDF_MAC_ADDR_SIZE; + mlo_ie->link_id_info_present = 0; + + mlo_ie->bss_param_change_cnt_present = 0; + mlo_ie->medium_sync_delay_info_present = 0; + + if (wlan_vdev_mlme_cap_get(session->vdev, WLAN_VDEV_C_EMLSR_CAP)) { + mlo_ie->eml_capab_present = 1; + mlo_ie->eml_capabilities_info.emlmr_support = 0; + mlo_ie->eml_capabilities_info.emlsr_support = 1; + common_info_len += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + } else { + mlo_ie->eml_capab_present = 0; + } + + common_info_len += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + mlo_ie->ext_mld_capab_and_op_present = 0; + mlo_ie->mld_id_present = 0; + mlo_ie->mld_capab_and_op_present = 1; + mlo_ie->mld_capab_and_op_info.tid_link_map_supported = + wlan_mlme_get_t2lm_negotiation_supported(mac_ctx->psoc); + mlo_ie->reserved = 0; + mlo_ie->reserved_1 = 0; + mlo_ie->common_info_length = common_info_len; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +sir_convert_mlo_probe_rsp_frame2_struct(uint8_t *ml_ie, + uint32_t ml_ie_total_len, + struct sir_multi_link_ie *mlo_ie_ptr) +{ + bool link_id_found; + uint8_t link_id; + bool bss_param_change_cnt_found; + uint8_t bss_param_change_cnt; + struct qdf_mac_addr mld_mac_addr; + uint8_t *sta_prof; + + if (!ml_ie) + return QDF_STATUS_E_NULL_VALUE; + + if (!ml_ie_total_len) + return QDF_STATUS_E_NULL_VALUE; + + qdf_mem_zero((uint8_t *)mlo_ie_ptr, sizeof(*mlo_ie_ptr)); + + util_get_mlie_common_info_len(ml_ie, ml_ie_total_len, + &mlo_ie_ptr->mlo_ie.common_info_length); + + sta_prof = ml_ie + sizeof(struct wlan_ie_multilink) + + mlo_ie_ptr->mlo_ie.common_info_length; + lim_store_mlo_ie_raw_info(ml_ie, sta_prof, + ml_ie_total_len, &mlo_ie_ptr->mlo_ie); + + util_get_bvmlie_mldmacaddr(ml_ie, ml_ie_total_len, &mld_mac_addr); + qdf_mem_copy(mlo_ie_ptr->mlo_ie.mld_mac_addr, mld_mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + + util_get_bvmlie_primary_linkid(ml_ie, ml_ie_total_len, + &link_id_found, &link_id); + mlo_ie_ptr->mlo_ie.link_id_info_present = link_id_found; + mlo_ie_ptr->mlo_ie.link_id = link_id; + + util_get_bvmlie_bssparamchangecnt(ml_ie, ml_ie_total_len, + &bss_param_change_cnt_found, + &bss_param_change_cnt); + mlo_ie_ptr->mlo_ie.bss_param_change_cnt_present = + bss_param_change_cnt_found; + mlo_ie_ptr->mlo_ie.bss_param_change_count = bss_param_change_cnt; + mlo_ie_ptr->mlo_ie_present = true; + + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(WLAN_FEATURE_11AX) && defined(WLAN_SUPPORT_TWT) +QDF_STATUS populate_dot11f_twt_extended_caps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEExtCap *dot11f) +{ + struct s_ext_cap *p_ext_cap; + bool twt_responder = false; + bool twt_requestor = false; + + if (pe_session->opmode == QDF_STA_MODE && + !pe_session->enable_session_twt_support) { + return QDF_STATUS_SUCCESS; + } + + dot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + p_ext_cap = (struct s_ext_cap *)dot11f->bytes; + dot11f->present = 1; + + if (pe_session->opmode == QDF_STA_MODE) { + wlan_twt_get_requestor_cfg(mac_ctx->psoc, &twt_requestor); + p_ext_cap->twt_requestor_support = + twt_requestor && twt_get_requestor_flag(mac_ctx); + } + + if (pe_session->opmode == QDF_SAP_MODE) { + wlan_twt_get_responder_cfg(mac_ctx->psoc, &twt_responder); + p_ext_cap->twt_responder_support = + twt_responder && twt_get_responder_flag(mac_ctx); + } + + dot11f->num_bytes = lim_compute_ext_cap_ie_length(dot11f); + if (!dot11f->num_bytes) { + dot11f->present = 0; + pe_debug("ext ie length become 0, disable the ext caps"); + } + + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * wlan_fill_single_pmk_ap_cap_from_scan_entry() - WAP3_SPMK VSIE from scan + * entry + * @mac_ctx: pointer to mac_context + * @bss_desc: BSS Descriptor + * @scan_entry: scan entry + * + * Return: None + */ +static void +wlan_fill_single_pmk_ap_cap_from_scan_entry(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + struct scan_cache_entry *scan_entry) +{ + bss_desc->is_single_pmk = + util_scan_entry_single_pmk(mac_ctx->psoc, scan_entry) && + mac_ctx->mlme_cfg->lfr.sae_single_pmk_feature_enabled; +} +#else +static inline void +wlan_fill_single_pmk_ap_cap_from_scan_entry(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + struct scan_cache_entry *scan_entry) +{ +} +#endif + +QDF_STATUS wlan_parse_bss_description_ies(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs *ie_struct) +{ + int ie_len = wlan_get_ielen_from_bss_description(bss_desc); + QDF_STATUS status; + + if (ie_len <= 0 || !ie_struct) { + pe_err("BSS description has invalid IE : %d", ie_len); + return QDF_STATUS_E_FAILURE; + } + if (DOT11F_FAILED(dot11f_unpack_beacon_i_es + (mac_ctx, (uint8_t *)bss_desc->ieFields, + ie_len, ie_struct, false))) { + pe_err("Beacon IE parsing failed"); + return QDF_STATUS_E_FAILURE; + } + + status = lim_strip_and_decode_eht_op((uint8_t *)bss_desc->ieFields, + ie_len, &ie_struct->eht_op, + ie_struct->VHTOperation, + ie_struct->he_op, + ie_struct->HTInfo); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht op"); + return QDF_STATUS_E_FAILURE; + } + + status = lim_strip_and_decode_eht_cap((uint8_t *)bss_desc->ieFields, + ie_len, &ie_struct->eht_cap, + ie_struct->he_cap, + bss_desc->chan_freq); + if (status != QDF_STATUS_SUCCESS) { + pe_err("Failed to extract eht cap"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_get_parsed_bss_description_ies(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs **ie_struct) +{ + QDF_STATUS status; + + if (!bss_desc || !ie_struct) + return QDF_STATUS_E_INVAL; + + *ie_struct = qdf_mem_malloc(sizeof(tDot11fBeaconIEs)); + if (!*ie_struct) + return QDF_STATUS_E_NOMEM; + + status = wlan_parse_bss_description_ies(mac_ctx, bss_desc, + *ie_struct); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(*ie_struct); + *ie_struct = NULL; + } + + return status; +} + +void +wlan_populate_basic_rates(tSirMacRateSet *rate_set, bool is_ofdm_rates, + bool is_basic_rates) +{ + uint8_t ofdm_rates[8] = { + SIR_MAC_RATE_6, + SIR_MAC_RATE_9, + SIR_MAC_RATE_12, + SIR_MAC_RATE_18, + SIR_MAC_RATE_24, + SIR_MAC_RATE_36, + SIR_MAC_RATE_48, + SIR_MAC_RATE_54 + }; + uint8_t cck_rates[4] = { + SIR_MAC_RATE_1, + SIR_MAC_RATE_2, + SIR_MAC_RATE_5_5, + SIR_MAC_RATE_11 + }; + + if (is_ofdm_rates == true) { + rate_set->numRates = 8; + qdf_mem_copy(rate_set->rate, ofdm_rates, sizeof(ofdm_rates)); + if (is_basic_rates) { + rate_set->rate[0] |= WLAN_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= WLAN_DOT11_BASIC_RATE_MASK; + rate_set->rate[4] |= WLAN_DOT11_BASIC_RATE_MASK; + } + pe_debug("Default OFDM Rates"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + rate_set->rate, rate_set->numRates); + } else { + rate_set->numRates = 4; + qdf_mem_copy(rate_set->rate, cck_rates, sizeof(cck_rates)); + if (is_basic_rates) { + rate_set->rate[0] |= WLAN_DOT11_BASIC_RATE_MASK; + rate_set->rate[1] |= WLAN_DOT11_BASIC_RATE_MASK; + rate_set->rate[2] |= WLAN_DOT11_BASIC_RATE_MASK; + rate_set->rate[3] |= WLAN_DOT11_BASIC_RATE_MASK; + } + pe_debug("Default CCK Rates"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_PE, QDF_TRACE_LEVEL_DEBUG, + rate_set->rate, rate_set->numRates); + } +} + +/** + * wlan_is_aggregate_rate_supported() - to check if aggregate rate is supported + * @mac_ctx: pointer to mac context + * @rate: A rate in units of 500kbps + * + * + * The rate encoding is just as in 802.11 Information Elements, except + * that the high bit is \em not interpreted as indicating a Basic Rate, + * and proprietary rates are allowed, too. + * + * Note that if the adapter's dot11Mode is g, we don't restrict the + * rates. According to hwReadEepromParameters, this will happen when: + * ... the card is configured for ALL bands through the property + * page. If this occurs, and the card is not an ABG card ,then this + * code is setting the dot11Mode to assume the mode that the + * hardware can support. For example, if the card is an 11BG card + * and we are configured to support ALL bands, then we change the + * dot11Mode to 11g because ALL in this case is only what the + * hardware can support. + * + * Return: true if the adapter is currently capable of supporting this rate + */ + +static bool wlan_is_aggregate_rate_supported(struct mac_context *mac_ctx, + uint16_t rate) +{ + bool supported = false; + uint16_t idx, new_rate; + enum mlme_dot11_mode self_dot11_mode = + mac_ctx->mlme_cfg->dot11_mode.dot11_mode; + + /* In case basic rate flag is set */ + new_rate = BITS_OFF(rate, WLAN_DOT11_BASIC_RATE_MASK); + if (self_dot11_mode == MLME_DOT11_MODE_11A) { + switch (new_rate) { + case SUPP_RATE_6_MBPS: + case SUPP_RATE_9_MBPS: + case SUPP_RATE_12_MBPS: + case SUPP_RATE_18_MBPS: + case SUPP_RATE_24_MBPS: + case SUPP_RATE_36_MBPS: + case SUPP_RATE_48_MBPS: + case SUPP_RATE_54_MBPS: + supported = true; + break; + default: + supported = false; + break; + } + } else if (self_dot11_mode == MLME_DOT11_MODE_11B) { + switch (new_rate) { + case SUPP_RATE_1_MBPS: + case SUPP_RATE_2_MBPS: + case SUPP_RATE_5_MBPS: + case SUPP_RATE_11_MBPS: + supported = true; + break; + default: + supported = false; + break; + } + } else if (!mac_ctx->roam.configParam.ProprietaryRatesEnabled) { + switch (new_rate) { + case SUPP_RATE_1_MBPS: + case SUPP_RATE_2_MBPS: + case SUPP_RATE_5_MBPS: + case SUPP_RATE_6_MBPS: + case SUPP_RATE_9_MBPS: + case SUPP_RATE_11_MBPS: + case SUPP_RATE_12_MBPS: + case SUPP_RATE_18_MBPS: + case SUPP_RATE_24_MBPS: + case SUPP_RATE_36_MBPS: + case SUPP_RATE_48_MBPS: + case SUPP_RATE_54_MBPS: + supported = true; + break; + default: + supported = false; + break; + } + } else if (new_rate == SUPP_RATE_1_MBPS || + new_rate == SUPP_RATE_2_MBPS || + new_rate == SUPP_RATE_5_MBPS || + new_rate == SUPP_RATE_11_MBPS) + supported = true; + else { + idx = 0x1; + + switch (new_rate) { + case SUPP_RATE_6_MBPS: + supported = g_phy_rates_suppt[0][idx]; + break; + case SUPP_RATE_9_MBPS: + supported = g_phy_rates_suppt[1][idx]; + break; + case SUPP_RATE_12_MBPS: + supported = g_phy_rates_suppt[2][idx]; + break; + case SUPP_RATE_18_MBPS: + supported = g_phy_rates_suppt[3][idx]; + break; + case SUPP_RATE_20_MBPS: + supported = g_phy_rates_suppt[4][idx]; + break; + case SUPP_RATE_24_MBPS: + supported = g_phy_rates_suppt[5][idx]; + break; + case SUPP_RATE_36_MBPS: + supported = g_phy_rates_suppt[6][idx]; + break; + case SUPP_RATE_40_MBPS: + supported = g_phy_rates_suppt[7][idx]; + break; + case SUPP_RATE_42_MBPS: + supported = g_phy_rates_suppt[8][idx]; + break; + case SUPP_RATE_48_MBPS: + supported = g_phy_rates_suppt[9][idx]; + break; + case SUPP_RATE_54_MBPS: + supported = g_phy_rates_suppt[10][idx]; + break; + case SUPP_RATE_72_MBPS: + supported = g_phy_rates_suppt[11][idx]; + break; + case SUPP_RATE_80_MBPS: + supported = g_phy_rates_suppt[12][idx]; + break; + case SUPP_RATE_84_MBPS: + supported = g_phy_rates_suppt[13][idx]; + break; + case SUPP_RATE_96_MBPS: + supported = g_phy_rates_suppt[14][idx]; + break; + case SUPP_RATE_108_MBPS: + supported = g_phy_rates_suppt[15][idx]; + break; + case SUPP_RATE_120_MBPS: + supported = g_phy_rates_suppt[16][idx]; + break; + case SUPP_RATE_126_MBPS: + supported = g_phy_rates_suppt[17][idx]; + break; + case SUPP_RATE_144_MBPS: + supported = g_phy_rates_suppt[18][idx]; + break; + case SUPP_RATE_160_MBPS: + supported = g_phy_rates_suppt[19][idx]; + break; + case SUPP_RATE_168_MBPS: + supported = g_phy_rates_suppt[20][idx]; + break; + case SUPP_RATE_192_MBPS: + supported = g_phy_rates_suppt[21][idx]; + break; + case SUPP_RATE_216_MBPS: + supported = g_phy_rates_suppt[22][idx]; + break; + case SUPP_RATE_240_MBPS: + supported = g_phy_rates_suppt[23][idx]; + break; + default: + supported = false; + break; + } + } + + return supported; +} + +bool wlan_rates_is_dot11_rate_supported(struct mac_context *mac_ctx, + uint8_t rate) +{ + uint16_t n = BITS_OFF(rate, WLAN_DOT11_BASIC_RATE_MASK); + + return wlan_is_aggregate_rate_supported(mac_ctx, n); +} + +bool wlan_check_rate_bitmap(uint8_t rate, uint16_t rate_bitmap) +{ + uint16_t n = BITS_OFF(rate, WLAN_DOT11_BASIC_RATE_MASK); + + switch (n) { + case SIR_MAC_RATE_1: + rate_bitmap &= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + rate_bitmap &= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + rate_bitmap &= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + rate_bitmap &= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + rate_bitmap &= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + rate_bitmap &= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + rate_bitmap &= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + rate_bitmap &= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + rate_bitmap &= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + rate_bitmap &= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + rate_bitmap &= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + rate_bitmap &= SIR_MAC_RATE_54_BITMAP; + break; + } + return !!rate_bitmap; +} + +void wlan_add_rate_bitmap(uint8_t rate, uint16_t *rate_bitmap) +{ + uint16_t n = BITS_OFF(rate, CSR_DOT11_BASIC_RATE_MASK); + + switch (n) { + case SIR_MAC_RATE_1: + *rate_bitmap |= SIR_MAC_RATE_1_BITMAP; + break; + case SIR_MAC_RATE_2: + *rate_bitmap |= SIR_MAC_RATE_2_BITMAP; + break; + case SIR_MAC_RATE_5_5: + *rate_bitmap |= SIR_MAC_RATE_5_5_BITMAP; + break; + case SIR_MAC_RATE_11: + *rate_bitmap |= SIR_MAC_RATE_11_BITMAP; + break; + case SIR_MAC_RATE_6: + *rate_bitmap |= SIR_MAC_RATE_6_BITMAP; + break; + case SIR_MAC_RATE_9: + *rate_bitmap |= SIR_MAC_RATE_9_BITMAP; + break; + case SIR_MAC_RATE_12: + *rate_bitmap |= SIR_MAC_RATE_12_BITMAP; + break; + case SIR_MAC_RATE_18: + *rate_bitmap |= SIR_MAC_RATE_18_BITMAP; + break; + case SIR_MAC_RATE_24: + *rate_bitmap |= SIR_MAC_RATE_24_BITMAP; + break; + case SIR_MAC_RATE_36: + *rate_bitmap |= SIR_MAC_RATE_36_BITMAP; + break; + case SIR_MAC_RATE_48: + *rate_bitmap |= SIR_MAC_RATE_48_BITMAP; + break; + case SIR_MAC_RATE_54: + *rate_bitmap |= SIR_MAC_RATE_54_BITMAP; + break; + } +} + +static bool is_ofdm_rates(uint16_t rate) +{ + uint16_t n = BITS_OFF(rate, WLAN_DOT11_BASIC_RATE_MASK); + + switch (n) { + case SIR_MAC_RATE_6: + case SIR_MAC_RATE_9: + case SIR_MAC_RATE_12: + case SIR_MAC_RATE_18: + case SIR_MAC_RATE_24: + case SIR_MAC_RATE_36: + case SIR_MAC_RATE_48: + case SIR_MAC_RATE_54: + return true; + default: + break; + } + + return false; +} + +QDF_STATUS wlan_get_rate_set(struct mac_context *mac, + tDot11fBeaconIEs *ie_struct, + struct pe_session *pe_session) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i; + uint8_t *dst_rate; + uint16_t rateBitmap = 0; + bool is_24ghz_freq; + tSirMacRateSet *op_rate; + tSirMacRateSet *ext_rate; + tSirMacRateSet rate_set; + + + if (!pe_session) { + pe_err("pe session is NULL"); + return QDF_STATUS_E_INVAL; + } + op_rate = &pe_session->rateSet; + ext_rate = &pe_session->extRateSet; + is_24ghz_freq = wlan_reg_is_24ghz_ch_freq(pe_session->curr_op_freq); + + qdf_mem_zero(op_rate, sizeof(tSirMacRateSet)); + qdf_mem_zero(ext_rate, sizeof(tSirMacRateSet)); + qdf_mem_zero(&rate_set, sizeof(tSirMacRateSet)); + QDF_ASSERT(ie_struct); + + /* + * Originally, we thought that for 11a networks, the 11a rates + * are always in the Operational Rate set & for 11b and 11g + * networks, the 11b rates appear in the Operational Rate set. + * Consequently, in either case, we would blindly put the rates + * we support into our Operational Rate set. + * (including the basic rates, which we've already verified are + * supported earlier in the roaming decision). + * However, it turns out that this is not always the case. + * Some AP's (e.g. D-Link DI-784) ram 11g rates into the + * Operational Rate set too. Now, we're a little more careful. + */ + dst_rate = op_rate->rate; + if (ie_struct->SuppRates.present) { + for (i = 0; i < ie_struct->SuppRates.num_rates; i++) { + if (!is_24ghz_freq && + !is_ofdm_rates(ie_struct->SuppRates.rates[i])) + continue; + + if (wlan_rates_is_dot11_rate_supported(mac, + ie_struct->SuppRates.rates[i]) && + !wlan_check_rate_bitmap( + ie_struct->SuppRates.rates[i], + rateBitmap)) { + wlan_add_rate_bitmap(ie_struct->SuppRates. + rates[i], &rateBitmap); + *dst_rate++ = ie_struct->SuppRates.rates[i]; + op_rate->numRates++; + } + } + } + /* + * If there are Extended Rates in the beacon, we will reflect the + * extended rates that we support in our Extended Operational Rate + * set. + */ + if (ie_struct->ExtSuppRates.present) { + dst_rate = ext_rate->rate; + for (i = 0; i < ie_struct->ExtSuppRates.num_rates; i++) { + if (wlan_rates_is_dot11_rate_supported(mac, + ie_struct->ExtSuppRates.rates[i]) && + !wlan_check_rate_bitmap( + ie_struct->ExtSuppRates.rates[i], + rateBitmap)) { + *dst_rate++ = ie_struct->ExtSuppRates.rates[i]; + ext_rate->numRates++; + } + } + } + if (!op_rate->numRates) { + dst_rate = op_rate->rate; + wlan_populate_basic_rates(&rate_set, !is_24ghz_freq, true); + for (i = 0; i < rate_set.numRates; i++) { + if (!wlan_check_rate_bitmap(rate_set.rate[i], + rateBitmap)) { + wlan_add_rate_bitmap(rate_set.rate[i], + &rateBitmap); + *dst_rate++ = rate_set.rate[i]; + op_rate->numRates++; + } + } + if (!is_24ghz_freq) + return QDF_STATUS_SUCCESS; + + wlan_populate_basic_rates(&rate_set, true, false); + for (i = op_rate->numRates; + i < WLAN_SUPPORTED_RATES_IE_MAX_LEN; i++) { + if (!wlan_check_rate_bitmap(rate_set.rate[i], + rateBitmap)) { + wlan_add_rate_bitmap(rate_set.rate[i], + &rateBitmap); + *dst_rate++ = rate_set.rate[i]; + op_rate->numRates++; + } + } + } + if (op_rate->numRates > 0 || ext_rate->numRates > 0) + status = QDF_STATUS_SUCCESS; + + return status; +} + +uint32_t wlan_get_11h_power_constraint(struct mac_context *mac_ctx, + tDot11fIEPowerConstraints *constraints) +{ + uint32_t local_power_constraint = 0; + + /* + * check if .11h support is enabled, if not, + * the power constraint is 0. + */ + if (mac_ctx->mlme_cfg->gen.enabled_11h && constraints->present) + local_power_constraint = constraints->localPowerConstraints; + + return local_power_constraint; +} + +#ifdef WLAN_FEATURE_FILS_SK +static void wlan_update_bss_with_fils_data(struct mac_context *mac_ctx, + struct scan_cache_entry *scan_entry, + struct bss_description *bss_descr) +{ + int ret; + tDot11fIEfils_indication *fils_indication; + struct sir_fils_indication *fils_ind; + + if (!scan_entry->ie_list.fils_indication) + return; + + fils_indication = qdf_mem_malloc(sizeof(*fils_indication)); + if (!fils_indication) { + pe_err("malloc failed for fils_indication"); + return; + } + + ret = dot11f_unpack_ie_fils_indication(mac_ctx, + scan_entry->ie_list.fils_indication + + SIR_FILS_IND_ELEM_OFFSET, + *(scan_entry->ie_list.fils_indication + 1), + fils_indication, false); + if (DOT11F_FAILED(ret)) { + pe_err("unpack failed ret: 0x%x", ret); + qdf_mem_free(fils_indication); + return; + } + + fils_ind = qdf_mem_malloc(sizeof(*fils_ind)); + if (!fils_ind) { + pe_err("malloc failed for fils_ind"); + qdf_mem_free(fils_indication); + return; + } + + update_fils_data(fils_ind, fils_indication); + if (fils_ind->realm_identifier.realm_cnt > SIR_MAX_REALM_COUNT) + fils_ind->realm_identifier.realm_cnt = SIR_MAX_REALM_COUNT; + + bss_descr->fils_info_element.realm_cnt = + fils_ind->realm_identifier.realm_cnt; + qdf_mem_copy(bss_descr->fils_info_element.realm, + fils_ind->realm_identifier.realm, + bss_descr->fils_info_element.realm_cnt * SIR_REALM_LEN); + pe_debug("FILS: bssid:" QDF_MAC_ADDR_FMT "is_present:%d cache_id[0x%x%x]", + QDF_MAC_ADDR_REF(bss_descr->bssId), + fils_ind->cache_identifier.is_present, + fils_ind->cache_identifier.identifier[0], + fils_ind->cache_identifier.identifier[1]); + if (fils_ind->cache_identifier.is_present) { + bss_descr->fils_info_element.is_cache_id_present = true; + qdf_mem_copy(bss_descr->fils_info_element.cache_id, + fils_ind->cache_identifier.identifier, CACHE_ID_LEN); + } + if (fils_ind->is_fils_sk_auth_supported) + bss_descr->fils_info_element.is_fils_sk_supported = true; + + qdf_mem_free(fils_ind); + qdf_mem_free(fils_indication); +} +#else +static void wlan_update_bss_with_fils_data(struct mac_context *mac_ctx, + struct scan_cache_entry *scan_entry, + struct bss_description *bss_descr) +{ } +#endif + +QDF_STATUS +wlan_fill_bss_desc_from_scan_entry(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + struct scan_cache_entry *scan_entry) +{ + uint8_t *ie_ptr; + uint32_t ie_len; + tpSirMacMgmtHdr hdr; + tDot11fBeaconIEs *bcn_ies; + QDF_STATUS status; + + hdr = (tpSirMacMgmtHdr)scan_entry->raw_frame.ptr; + + ie_len = util_scan_entry_ie_len(scan_entry); + ie_ptr = util_scan_entry_ie_data(scan_entry); + + bss_desc->length = (uint16_t) (offsetof(struct bss_description, + ieFields[0]) - sizeof(bss_desc->length) + ie_len); + + qdf_mem_copy(bss_desc->bssId, scan_entry->bssid.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(bss_desc->timeStamp, + scan_entry->tsf_info.data, 8); + + bss_desc->beaconInterval = scan_entry->bcn_int; + bss_desc->capabilityInfo = scan_entry->cap_info.value; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(scan_entry->channel.chan_freq) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(scan_entry->channel.chan_freq)) + bss_desc->nwType = eSIR_11A_NW_TYPE; + else if (scan_entry->phy_mode == WLAN_PHYMODE_11B) + bss_desc->nwType = eSIR_11B_NW_TYPE; + else + bss_desc->nwType = eSIR_11G_NW_TYPE; + + bss_desc->rssi = scan_entry->rssi_raw; + bss_desc->rssi_raw = scan_entry->rssi_raw; + + /* channel frequency what peer sent in beacon/probersp. */ + bss_desc->chan_freq = scan_entry->channel.chan_freq; + bss_desc->startTSF[0] = + mac_ctx->rrm.rrmPEContext.startTSF[0]; + bss_desc->startTSF[1] = + mac_ctx->rrm.rrmPEContext.startTSF[1]; + bss_desc->parentTSF = + scan_entry->rrm_parent_tsf; + bss_desc->fProbeRsp = (scan_entry->frm_subtype == + MGMT_SUBTYPE_PROBE_RESP); + bss_desc->adaptive_11r_ap = scan_entry->adaptive_11r_ap; + bss_desc->is_ml_ap = + util_scan_entry_bv_ml_ie(scan_entry) ? true : false; + + bss_desc->mbo_oce_enabled_ap = + util_scan_entry_mbo_oce(scan_entry) ? true : false; + + wlan_fill_single_pmk_ap_cap_from_scan_entry(mac_ctx, bss_desc, + scan_entry); + + qdf_mem_copy(&bss_desc->mbssid_info, &scan_entry->mbssid_info, + sizeof(struct scan_mbssid_info)); + + qdf_mem_copy((uint8_t *) &bss_desc->ieFields, ie_ptr, ie_len); + + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &bcn_ies); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + if (bcn_ies->MobilityDomain.present) { + bss_desc->mdiePresent = true; + qdf_mem_copy((uint8_t *)&(bss_desc->mdie[0]), + (uint8_t *)&(bcn_ies->MobilityDomain.MDID), + sizeof(uint16_t)); + bss_desc->mdie[2] = + ((bcn_ies->MobilityDomain.overDSCap << 0) | + (bcn_ies->MobilityDomain.resourceReqCap << 1)); + } + + wlan_update_bss_with_fils_data(mac_ctx, scan_entry, bss_desc); + + qdf_mem_free(bcn_ies); + + return QDF_STATUS_SUCCESS; +} + +uint16_t +wlan_get_ielen_from_bss_description(struct bss_description *bss_desc) +{ + uint16_t ielen, ieFields_offset; + + ieFields_offset = GET_FIELD_OFFSET(struct bss_description, ieFields); + + if (!bss_desc) { + pe_err_rl("Bss_desc is NULL"); + return 0; + } + + if (bss_desc->length <= (ieFields_offset - sizeof(bss_desc->length))) { + pe_err_rl("Invalid bss_desc len:%d ie_fields_offset:%d", + bss_desc->length, ieFields_offset); + return 0; + } + + /* + * Length of BSS description is without length of + * length itself and length of pointer + * that holds ieFields + * + * <------------sizeof(struct bss_description)--------------------> + * +--------+---------------------------------+---------------+ + * | length | other fields | pointer to IEs| + * +--------+---------------------------------+---------------+ + * ^ + * ieFields + */ + + ielen = (uint16_t)(bss_desc->length + sizeof(bss_desc->length) - + ieFields_offset); + + return ielen; +} + +QDF_STATUS populate_dot11f_btm_extended_caps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct sDot11fIEExtCap *dot11f) +{ + struct s_ext_cap *p_ext_cap; + QDF_STATUS status; + bool is_disable_btm; + struct cm_roam_values_copy temp; + + dot11f->num_bytes = DOT11F_IE_EXTCAP_MAX_LEN; + p_ext_cap = (struct s_ext_cap *)dot11f->bytes; + dot11f->present = 1; + + status = cm_akm_roam_allowed(mac_ctx->psoc, pe_session->vdev); + if (QDF_IS_STATUS_ERROR(status)) { + p_ext_cap->bss_transition = 0; + pe_debug("vdev:%d, Disable btm for roaming not suppprted", + pe_session->vdev_id); + } + + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, pe_session->vdev_id, + IS_DISABLE_BTM, &temp); + is_disable_btm = temp.bool_value; + if (is_disable_btm) { + pe_debug("vdev:%d, Disable BTM as BTM roam disabled by user", + pe_session->vdev_id); + p_ext_cap->bss_transition = 0; + } + + if (!pe_session->lim_join_req) + goto compute_len; + + if (p_ext_cap->bss_transition && !cm_is_open_mode(pe_session->vdev) && + pe_session->lim_join_req->bssDescription.mbo_oce_enabled_ap && + !pe_session->limRmfEnabled) { + pe_debug("vdev:%d, Disable BTM as MBO AP doesn't support PMF", + pe_session->vdev_id); + p_ext_cap->bss_transition = 0; + } + +compute_len: + dot11f->num_bytes = lim_compute_ext_cap_ie_length(dot11f); + if (!dot11f->num_bytes) { + dot11f->present = 0; + pe_debug("ext ie length become 0, disable the ext caps"); + } + + wlan_cm_set_assoc_btm_cap(pe_session->vdev, p_ext_cap->bss_transition); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * populate_dot11f_mlo_partner_sta_cap() - populate mlo sta partner capability + * @mac: mac + * @pDot11f: tDot11fFfCapabilities + * + * Return: QDF_STATUS + */ +static QDF_STATUS +populate_dot11f_mlo_partner_sta_cap(struct mac_context *mac, + tDot11fFfCapabilities *pDot11f) +{ + uint16_t cap = 0; + uint32_t val = 0; + tpSirMacCapabilityInfo pcap_info; + + pcap_info = (tpSirMacCapabilityInfo)∩ + + pcap_info->ess = 1; /* ESS bit */ + + if (mac->mlme_cfg->wep_params.is_privacy_enabled) + pcap_info->privacy = 1; + + /* Short preamble bit */ + if (mac->mlme_cfg->ht_caps.short_preamble) + pcap_info->shortPreamble = + mac->mlme_cfg->ht_caps.short_preamble; + + /* criticalUpdateFlag bit */ + pcap_info->criticalUpdateFlag = 0; + + /* Channel agility bit */ + pcap_info->channelAgility = 0; + + /* Short slot time bit */ + if (mac->mlme_cfg->feature_flags.enable_short_slot_time_11g) + pcap_info->shortSlotTime = 1; + + /* Spectrum Management bit */ + if (mac->mlme_cfg->gen.enabled_11h) + pcap_info->spectrumMgt = 1; + /* QoS bit */ + if (mac->mlme_cfg->wmm_params.qos_enabled) + pcap_info->qos = 1; + + /* APSD bit */ + if (mac->mlme_cfg->roam_scoring.apsd_enabled) + pcap_info->apsd = 1; + + pcap_info->rrm = mac->rrm.rrmConfig.rrm_enabled; + /* DSSS-OFDM */ + /* FIXME : no config defined yet. */ + + /* Block ack bit */ + val = mac->mlme_cfg->feature_flags.enable_block_ack; + pcap_info->delayedBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_DELAYED) & 1); + pcap_info->immediateBA = + (uint16_t)((val >> WNI_CFG_BLOCK_ACK_ENABLED_IMMEDIATE) & 1); + + swap_bit_field16(cap, (uint16_t *)pDot11f); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_auth_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct wlan_mlo_ie *mlo_ie) +{ + struct qdf_mac_addr *mld_addr; + uint8_t *p_ml_ie; + uint16_t len_remaining; + + pe_debug("Populate Auth MLO IEs"); + + mlo_ie->type = 0; + + mlo_ie->common_info_length = WLAN_ML_BV_CINFO_LENGTH_SIZE; + mld_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr( + pe_session->vdev); + qdf_mem_copy(&mlo_ie->mld_mac_addr, mld_addr, QDF_MAC_ADDR_SIZE); + mlo_ie->common_info_length += QDF_MAC_ADDR_SIZE; + + pe_debug("MLD mac addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mld_addr->bytes)); + + mlo_ie->link_id_info_present = 0; + mlo_ie->bss_param_change_cnt_present = 0; + mlo_ie->medium_sync_delay_info_present = 0; + mlo_ie->eml_capab_present = 0; + mlo_ie->mld_capab_and_op_present = 0; + mlo_ie->mld_id_present = 0; + mlo_ie->ext_mld_capab_and_op_present = 0; + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = mlo_ie->common_info_length; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mlo_ie->mld_mac_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_assoc_req_mlo_ie(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fAssocRequest *frm) +{ + uint8_t link; + uint8_t num_sta_prof = 0, total_sta_prof; + struct wlan_mlo_ie *mlo_ie; + struct wlan_mlo_sta_profile *sta_prof; + struct mlo_link_info *link_info = NULL; + struct mlo_partner_info *partner_info; + struct qdf_mac_addr *mld_addr; + struct wlan_mlo_dev_context *mlo_dev_ctx; + tSirMacRateSet b_rates; + tSirMacRateSet e_rates; + uint8_t non_inher_len; + uint8_t non_inher_ie_lists[255]; + uint8_t non_inher_ext_len; + uint8_t non_inher_ext_ie_lists[255]; + qdf_freq_t chan_freq = 0; + uint8_t chan; + uint8_t op_class; + uint8_t *p_sta_prof; + uint8_t *p_ml_ie; + uint32_t len_consumed; + uint16_t len_remaining, len; + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + tDot11fIEnon_inheritance sta_prof_non_inherit; + tDot11fFfCapabilities mlo_cap; + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tDot11fIEExtCap ext_cap; + tDot11fIEhe_cap he_caps; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_cap; + tDot11fIEeht_cap eht_caps; + tDot11fIESuppRates supp_rates; + tDot11fIEExtSuppRates ext_supp_rates; + struct wlan_mlo_eml_cap eml_cap = {0}; + uint16_t presence_bitmap = 0; + bool is_2g; + uint32_t value = 0; + uint8_t *ppet, cb_mode; + uint8_t *eht_cap_ie = NULL; + bool sta_prof_he_ie = false; + + if (!mac_ctx || !pe_session || !frm) + return QDF_STATUS_E_NULL_VALUE; + + psoc = wlan_vdev_get_psoc(pe_session->vdev); + if (!psoc) { + pe_err("Invalid psoc"); + return QDF_STATUS_E_FAILURE; + } + + pe_debug("Populate Assoc req MLO IEs"); + + mlo_ie = &pe_session->mlo_ie; + + mlo_ie->type = 0; + mlo_ie->common_info_length = WLAN_ML_BV_CINFO_LENGTH_SIZE; + mld_addr = + (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(pe_session->vdev); + qdf_mem_copy(&mlo_ie->mld_mac_addr, mld_addr, QDF_MAC_ADDR_SIZE); + mlo_ie->common_info_length += QDF_MAC_ADDR_SIZE; + + mlo_ie->link_id_info_present = 0; + mlo_ie->bss_param_change_cnt_present = 0; + mlo_ie->medium_sync_delay_info_present = 0; + mlo_ie->eml_capab_present = 0; + mlo_ie->mld_capab_and_op_present = 1; + mlo_ie->mld_id_present = 0; + mlo_ie->ext_mld_capab_and_op_present = 0; + + if (!pe_session->lim_join_req) + return QDF_STATUS_E_FAILURE; + + partner_info = &pe_session->lim_join_req->partner_info; + + if (mlo_ie->mld_capab_and_op_present) { + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P; + mlo_ie->common_info_length += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = + QDF_MIN(partner_info->num_partner_links, + wlan_mlme_get_sta_mlo_simultaneous_links(psoc)); + pe_debug("max_simultaneous_link_num %d", + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num); + mlo_ie->mld_capab_and_op_info.srs_support = 0; + mlo_ie->mld_capab_and_op_info.tid_link_map_supported = + wlan_mlme_get_t2lm_negotiation_supported(mac_ctx->psoc); + mlo_ie->mld_capab_and_op_info.str_freq_separation = 0; + mlo_ie->mld_capab_and_op_info.aar_support = 0; + } + + /* Check if STA supports EMLSR and vendor command prefers EMLSR mode */ + if (wlan_vdev_mlme_cap_get(pe_session->vdev, WLAN_VDEV_C_EMLSR_CAP)) { + wlan_mlme_get_eml_params(psoc, &eml_cap); + mlo_ie->eml_capab_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_EMLCAP_P; + mlo_ie->common_info_length += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + mlo_ie->eml_capabilities_info.emlsr_support = + eml_cap.emlsr_supp; + mlo_ie->eml_capabilities_info.emlmr_support = + eml_cap.emlmr_supp; + mlo_ie->eml_capabilities_info.transition_timeout = 0; + mlo_ie->eml_capabilities_info.emlsr_padding_delay = + eml_cap.emlsr_pad_delay; + mlo_ie->eml_capabilities_info.emlsr_transition_delay = + eml_cap.emlsr_trans_delay; + } + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + /* element ID, length and extension element ID */ + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + /* length will set later */ + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = mlo_ie->common_info_length; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mld_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + if (mlo_ie->eml_capab_present) { + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRSUPPORT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRSUPPORT_BITS, + mlo_ie->eml_capabilities_info.emlsr_support); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLSR_PADDINGDELAY_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSR_PADDINGDELAY_BITS, + mlo_ie->eml_capabilities_info.emlsr_padding_delay); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRTRANSDELAY_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRTRANSDELAY_BITS, + mlo_ie->eml_capabilities_info.emlsr_transition_delay); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRSUPPORT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRSUPPORT_BITS, + mlo_ie->eml_capabilities_info.emlmr_support); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRDELAY_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRDELAY_BITS, + mlo_ie->eml_capabilities_info.emlmr_delay); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_TRANSTIMEOUT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_TRANSTIMEOUT_BITS, + mlo_ie->eml_capabilities_info.transition_timeout); + + p_ml_ie += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_EMLCAP_SIZE; + } + + pe_debug("EMLSR support: %d, padding delay: %d, transition delay: %d", + mlo_ie->eml_capabilities_info.emlsr_support, + mlo_ie->eml_capabilities_info.emlsr_padding_delay, + mlo_ie->eml_capabilities_info.emlsr_transition_delay); + + if (mlo_ie->mld_capab_and_op_present) { + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_BITS, + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_BITS, + mlo_ie->mld_capab_and_op_info.tid_link_map_supported); + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + } + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + + /* find out number of links from bcn or prb rsp */ + total_sta_prof = partner_info->num_partner_links; + + mlo_dev_ctx = pe_session->vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + pe_err("mlo_dev_ctx is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + for (link = 0; + link < total_sta_prof && total_sta_prof != num_sta_prof; + link++) { + struct mlo_link_info *ml_link_info; + + if (!partner_info->num_partner_links) + continue; + + sta_prof = &mlo_ie->sta_profile[num_sta_prof]; + link_info = &partner_info->partner_link_info[link]; + p_sta_prof = sta_prof->data; + len_remaining = sizeof(sta_prof->data); + ml_link_info = + mlo_mgr_get_ap_link_by_link_id( + pe_session->vdev->mlo_dev_ctx, + link_info->link_id); + if (!ml_link_info) + continue; + + /* subelement ID 0, length(sta_prof->num_data - 2) */ + *p_sta_prof++ = WLAN_ML_LINFO_SUBELEMID_PERSTAPROFILE; + *p_sta_prof++ = 0; + len_remaining -= 2; + + qdf_mem_zero(non_inher_ie_lists, sizeof(non_inher_ie_lists)); + qdf_mem_zero(non_inher_ext_ie_lists, + sizeof(non_inher_ext_ie_lists)); + non_inher_len = 0; + non_inher_ext_len = 0; + + QDF_SET_BITS(*(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_LINKID_BITS, + link_info->link_id); + QDF_SET_BITS(*(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_CMPLTPROF_BITS, + 1); + QDF_SET_BITS(*(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_MACADDRP_BITS, + 1); + /* 2 Bytes for sta control field*/ + p_sta_prof += 2; + len_remaining -= 2; + + /* 1 Bytes for STA Info Length + 6 bytes for STA MAC Address*/ + len = WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE + + QDF_MAC_ADDR_SIZE; + *p_sta_prof = len; + + /* 1 Byte for STA Info Length */ + p_sta_prof += WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; + len_remaining -= + WLAN_ML_BV_LINFO_PERSTAPROF_STAINFO_LENGTH_SIZE; + + /* Copying sta mac address in sta info field */ + qdf_mem_copy(p_sta_prof, ml_link_info->link_addr.bytes, + QDF_MAC_ADDR_SIZE); + p_sta_prof += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + pe_debug("Sta profile mac: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(ml_link_info->link_addr.bytes)); + + /* TBD : populate beacon_interval, dtim_info + * nstr_link_pair_present, nstr_bitmap_size + */ + QDF_SET_BITS(*(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_BCNINTP_BITS, + 0); + QDF_SET_BITS(*(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_DTIMINFOP_BITS, + 0); + QDF_SET_BITS( + *(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRLINKPRP_BITS, + 0); + QDF_SET_BITS(*(uint16_t *)(sta_prof->data + MIN_IE_LEN), + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_IDX, + WLAN_ML_BV_LINFO_PERSTAPROF_STACTRL_NSTRBMSZ_BITS, + 0); + + qdf_mem_zero(&mlo_cap, sizeof(tDot11fFfCapabilities)); + qdf_mem_zero(&b_rates, sizeof(b_rates)); + qdf_mem_zero(&e_rates, sizeof(e_rates)); + qdf_mem_zero(&supp_rates, sizeof(supp_rates)); + qdf_mem_zero(&ext_supp_rates, sizeof(ext_supp_rates)); + qdf_mem_zero(&sta_prof_non_inherit, + sizeof(tDot11fIEnon_inheritance)); + qdf_mem_zero(&ht_caps, sizeof(tDot11fIEHTCaps)); + qdf_mem_zero(&ext_cap, sizeof(tDot11fIEExtCap)); + qdf_mem_zero(&vht_caps, sizeof(tDot11fIEVHTCaps)); + qdf_mem_zero(&he_caps, sizeof(tDot11fIEhe_cap)); + qdf_mem_zero(&he_6ghz_band_cap, + sizeof(tDot11fIEhe_6ghz_band_cap)); + qdf_mem_zero(&eht_caps, sizeof(tDot11fIEeht_cap)); + + // TBD: mlo_capab, supported oper classes + populate_dot11f_mlo_partner_sta_cap(mac_ctx, &mlo_cap); + dot11f_pack_ff_capabilities(mac_ctx, &mlo_cap, p_sta_prof); + p_sta_prof += WLAN_CAPABILITYINFO_LEN; + len_remaining -= WLAN_CAPABILITYINFO_LEN; + + wlan_get_chan_by_bssid_from_rnr(pe_session->vdev, + pe_session->cm_id, + &link_info->link_addr, + &chan, &op_class); + if (!chan) + wlan_get_chan_by_link_id_from_rnr(pe_session->vdev, + pe_session->cm_id, + link_info->link_id, + &chan, &op_class); + if (!chan) { + pe_err("Invalid parter link id %d link mac: " QDF_MAC_ADDR_FMT, + link_info->link_id, + QDF_MAC_ADDR_REF(link_info->link_addr.bytes)); + continue; + } + chan_freq = wlan_reg_chan_opclass_to_freq_auto(chan, op_class, + false); + is_2g = WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq); + if (is_2g) { + wlan_populate_basic_rates(&b_rates, false, true); + wlan_populate_basic_rates(&e_rates, true, false); + } else { + wlan_populate_basic_rates(&b_rates, true, true); + } + + if ((b_rates.numRates && frm->SuppRates.present && + (qdf_mem_cmp(frm->SuppRates.rates, b_rates.rate, + b_rates.numRates))) || (b_rates.numRates && + !frm->SuppRates.present)) { + supp_rates.num_rates = b_rates.numRates; + qdf_mem_copy(supp_rates.rates, b_rates.rate, + b_rates.numRates); + supp_rates.present = 1; + len_consumed = 0; + dot11f_pack_ie_supp_rates(mac_ctx, &supp_rates, + p_sta_prof, len_remaining, + &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else if (frm->SuppRates.present && !b_rates.numRates) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_SUPPRATES; + } + + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) { + cb_mode = lim_get_cb_mode_for_freq(mac_ctx, pe_session, + chan_freq); + populate_dot11f_ht_caps(mac_ctx, NULL, &ht_caps); + if (!cb_mode) { + ht_caps.supportedChannelWidthSet = 0; + ht_caps.shortGI40MHz = 0; + } else { + ht_caps.supportedChannelWidthSet = 1; + ht_caps.shortGI40MHz = 1; + } + } + + if ((ht_caps.present && frm->HTCaps.present && + qdf_mem_cmp(&ht_caps, &frm->HTCaps, sizeof(ht_caps))) || + (ht_caps.present && !frm->HTCaps.present)) { + len_consumed = 0; + dot11f_pack_ie_ht_caps(mac_ctx, &ht_caps, p_sta_prof, + len_remaining, &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else if (frm->HTCaps.present && !ht_caps.present) { + non_inher_ie_lists[non_inher_len++] = DOT11F_EID_HTCAPS; + } + + if ((e_rates.numRates && frm->ExtSuppRates.present && + (qdf_mem_cmp(frm->ExtSuppRates.rates, e_rates.rate, + e_rates.numRates))) || (e_rates.numRates && + !frm->ExtSuppRates.present)) { + ext_supp_rates.num_rates = e_rates.numRates; + qdf_mem_copy(ext_supp_rates.rates, e_rates.rate, + e_rates.numRates); + ext_supp_rates.present = 1; + len_consumed = 0; + dot11f_pack_ie_ext_supp_rates(mac_ctx, &ext_supp_rates, + p_sta_prof, + len_remaining, + &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else if (frm->ExtSuppRates.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_EXTSUPPRATES; + } + + populate_dot11f_ext_cap(mac_ctx, true, &ext_cap, NULL); + populate_dot11f_btm_extended_caps(mac_ctx, pe_session, + &ext_cap); + if ((ext_cap.present && frm->ExtCap.present && + qdf_mem_cmp(&ext_cap, &frm->ExtCap, sizeof(ext_cap))) || + (ext_cap.present && !frm->ExtCap.present)) { + len_consumed = 0; + dot11f_pack_ie_ext_cap(mac_ctx, &ext_cap, p_sta_prof, + len_remaining, &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else if (ext_cap.present && !frm->ExtCap.present) { + non_inher_ie_lists[non_inher_len++] = DOT11F_EID_EXTCAP; + } + + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) + populate_dot11f_vht_caps(mac_ctx, NULL, &vht_caps); + if ((vht_caps.present && frm->VHTCaps.present && + qdf_mem_cmp(&vht_caps, &frm->VHTCaps, sizeof(vht_caps))) || + (vht_caps.present && !frm->VHTCaps.present)) { + len_consumed = 0; + dot11f_pack_ie_vht_caps(mac_ctx, &vht_caps, p_sta_prof, + len_remaining, &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else if (frm->VHTCaps.present && !vht_caps.present) { + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_VHTCAPS; + } + + populate_dot11f_he_caps_by_band(mac_ctx, is_2g, &he_caps, + pe_session); + if (he_caps.ppet_present) { + value = WNI_CFG_HE_PPET_LEN; + if (!is_2g) + qdf_mem_copy(he_caps.ppet.ppe_threshold.ppe_th, + mac_ctx->mlme_cfg->he_caps.he_ppet_5g, + value); + else + qdf_mem_copy(he_caps.ppet.ppe_threshold.ppe_th, + mac_ctx->mlme_cfg->he_caps.he_ppet_2g, + value); + + ppet = he_caps.ppet.ppe_threshold.ppe_th; + he_caps.ppet.ppe_threshold.num_ppe_th = + lim_truncate_ppet(ppet, value); + } else { + he_caps.ppet.ppe_threshold.num_ppe_th = 0; + } + if ((he_caps.present && frm->he_cap.present && + qdf_mem_cmp(&he_caps, &frm->he_cap, sizeof(he_caps))) || + (he_caps.present && !frm->he_cap.present)) { + len_consumed = 0; + dot11f_pack_ie_he_cap(mac_ctx, &he_caps, p_sta_prof, + len_remaining, &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + sta_prof_he_ie = true; + } else if (frm->he_cap.present && !he_caps.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_HECAP; + } + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) + populate_dot11f_he_6ghz_cap(mac_ctx, NULL, + &he_6ghz_band_cap); + if ((he_6ghz_band_cap.present && + frm->he_6ghz_band_cap.present && + qdf_mem_cmp(&he_6ghz_band_cap, &frm->he_6ghz_band_cap, + sizeof(he_6ghz_band_cap))) || + (he_6ghz_band_cap.present && + !frm->he_6ghz_band_cap.present)) { + len_consumed = 0; + dot11f_pack_ie_he_6ghz_band_cap( + mac_ctx, &he_6ghz_band_cap, p_sta_prof, + len_remaining, &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else if (frm->he_6ghz_band_cap.present && + !he_6ghz_band_cap.present) { + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_HE_6G_CAP; + } + populate_dot11f_eht_caps_by_band(mac_ctx, is_2g, &eht_caps, + NULL); + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) + eht_caps.support_320mhz_6ghz = 0; + + if ((eht_caps.present && frm->eht_cap.present && + qdf_mem_cmp(&eht_caps, &frm->eht_cap, sizeof(eht_caps))) || + (eht_caps.present && !frm->eht_cap.present) || + sta_prof_he_ie) { + eht_cap_ie = qdf_mem_malloc(WLAN_MAX_IE_LEN + 2); + if (eht_cap_ie) { + len_consumed = 0; + lim_ieee80211_pack_ehtcap(eht_cap_ie, eht_caps, + he_caps, is_2g); + len_consumed = eht_cap_ie[1] + 2; + + qdf_mem_copy(p_sta_prof, eht_cap_ie, + len_consumed); + qdf_mem_free(eht_cap_ie); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } else { + pe_err("malloc failed for eht_cap_ie"); + } + } else if (frm->eht_cap.present && !eht_caps.present) { + pe_debug("eht non inher"); + non_inher_ext_ie_lists[non_inher_ext_len++] = + WLAN_EXTN_ELEMID_EHTCAP; + } else { + pe_debug("eht ie not included"); + } + if (frm->OperatingMode.present) { + pe_info("opmode in assoc req, add to non inher list"); + non_inher_ie_lists[non_inher_len++] = + DOT11F_EID_OPERATINGMODE; + } + + populate_dot11f_non_inheritance( + mac_ctx, &sta_prof_non_inherit, + non_inher_ie_lists, non_inher_ext_ie_lists, + non_inher_len, non_inher_ext_len); + if (sta_prof_non_inherit.present) { + len_consumed = 0; + dot11f_pack_ie_non_inheritance( + mac_ctx, &sta_prof_non_inherit, + p_sta_prof, len_remaining, &len_consumed); + p_sta_prof += len_consumed; + len_remaining -= len_consumed; + } + sta_prof->num_data = p_sta_prof - sta_prof->data; + if (sta_prof->num_data > WLAN_MAX_IE_LEN + MIN_IE_LEN) { + sta_prof->data[TAG_LEN_POS] = WLAN_MAX_IE_LEN; + status = + lim_add_frag_ie_for_sta_profile(sta_prof->data, + &sta_prof->num_data); + if (status != QDF_STATUS_SUCCESS) { + pe_debug("STA profile frag error"); + sta_prof->num_data = + WLAN_MAX_IE_LEN + MIN_IE_LEN; + } + } else { + sta_prof->data[TAG_LEN_POS] = + sta_prof->num_data - MIN_IE_LEN; + } + num_sta_prof++; + } + mlo_ie->num_sta_profile = num_sta_prof; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS populate_dot11f_mlo_ie(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + struct wlan_mlo_ie *mlo_ie) +{ + struct qdf_mac_addr *mld_addr; + uint8_t *p_ml_ie; + uint16_t len_remaining; + struct wlan_objmgr_psoc *psoc; + struct wlan_mlo_eml_cap eml_cap = {0}; + uint16_t presence_bitmap = 0; + bool emlsr_cap, emlsr_enabled = false; + bool aux_emlsr_support = false; + + if (!mac_ctx || !mlo_ie) + return QDF_STATUS_E_NULL_VALUE; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + pe_err("Invalid psoc"); + return QDF_STATUS_E_FAILURE; + } + + mlo_ie->type = 0; + mlo_ie->common_info_length = WLAN_ML_BV_CINFO_LENGTH_SIZE; + mld_addr = + (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + qdf_mem_copy(&mlo_ie->mld_mac_addr, mld_addr, QDF_MAC_ADDR_SIZE); + mlo_ie->common_info_length += QDF_MAC_ADDR_SIZE; + + mlo_ie->link_id_info_present = 0; + mlo_ie->bss_param_change_cnt_present = 0; + mlo_ie->medium_sync_delay_info_present = 0; + mlo_ie->eml_capab_present = 0; + mlo_ie->mld_capab_and_op_present = 1; + mlo_ie->mld_id_present = 0; + mlo_ie->ext_mld_capab_and_op_present = 0; + + if (mlo_ie->mld_capab_and_op_present) { + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_MLDCAPANDOP_P; + mlo_ie->common_info_length += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num = + wlan_mlme_get_sta_mlo_simultaneous_links(psoc); + mlo_ie->mld_capab_and_op_info.srs_support = 0; + mlo_ie->mld_capab_and_op_info.tid_link_map_supported = + wlan_mlme_get_t2lm_negotiation_supported(mac_ctx->psoc); + mlo_ie->mld_capab_and_op_info.str_freq_separation = 0; + mlo_ie->mld_capab_and_op_info.aar_support = 0; + } + + /* Check if HW supports eMLSR mode */ + emlsr_cap = policy_mgr_is_hw_emlsr_capable(mac_ctx->psoc); + + /* Check if vendor command chooses eMLSR mode */ + wlan_mlme_get_emlsr_mode_enabled(mac_ctx->psoc, &emlsr_enabled); + + /* check if aux elmsr capable */ + aux_emlsr_support = wlan_mlme_is_aux_emlsr_support(mac_ctx->psoc, + WLAN_MLME_HW_MODE_MAX); + + /* Check if STA supports EMLSR and vendor command prefers EMLSR mode */ + if ((emlsr_cap && emlsr_enabled) || + aux_emlsr_support) { + wlan_mlme_get_eml_params(psoc, &eml_cap); + mlo_ie->eml_capab_present = 1; + presence_bitmap |= WLAN_ML_BV_CTRL_PBM_EMLCAP_P; + mlo_ie->common_info_length += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + mlo_ie->eml_capabilities_info.emlsr_support = + eml_cap.emlsr_supp; + mlo_ie->eml_capabilities_info.emlmr_support = + eml_cap.emlmr_supp; + mlo_ie->eml_capabilities_info.transition_timeout = 0; + mlo_ie->eml_capabilities_info.emlsr_padding_delay = + eml_cap.emlsr_pad_delay; + mlo_ie->eml_capabilities_info.emlsr_transition_delay = + eml_cap.emlsr_trans_delay; + } + + p_ml_ie = mlo_ie->data; + len_remaining = sizeof(mlo_ie->data); + + /* element ID, length and extension element ID */ + *p_ml_ie++ = WLAN_ELEMID_EXTN_ELEM; + len_remaining--; + /* length will set later */ + *p_ml_ie++ = 0; + len_remaining--; + *p_ml_ie++ = WLAN_EXTN_ELEMID_MULTI_LINK; + len_remaining--; + + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_TYPE_IDX, + WLAN_ML_CTRL_TYPE_BITS, mlo_ie->type); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, WLAN_ML_CTRL_PBM_IDX, + WLAN_ML_CTRL_PBM_BITS, presence_bitmap); + p_ml_ie += WLAN_ML_CTRL_SIZE; + len_remaining -= WLAN_ML_CTRL_SIZE; + + *p_ml_ie++ = mlo_ie->common_info_length; + len_remaining--; + + qdf_mem_copy(p_ml_ie, mld_addr, QDF_MAC_ADDR_SIZE); + p_ml_ie += QDF_MAC_ADDR_SIZE; + len_remaining -= QDF_MAC_ADDR_SIZE; + + if (mlo_ie->eml_capab_present) { + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRSUPPORT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRSUPPORT_BITS, + mlo_ie->eml_capabilities_info.emlsr_support); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLSR_PADDINGDELAY_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSR_PADDINGDELAY_BITS, + mlo_ie->eml_capabilities_info.emlsr_padding_delay); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRTRANSDELAY_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLSRTRANSDELAY_BITS, + mlo_ie->eml_capabilities_info.emlsr_transition_delay); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRSUPPORT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRSUPPORT_BITS, + mlo_ie->eml_capabilities_info.emlmr_support); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRDELAY_IDX, + WLAN_ML_BV_CINFO_EMLCAP_EMLMRDELAY_BITS, + mlo_ie->eml_capabilities_info.emlmr_delay); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_EMLCAP_TRANSTIMEOUT_IDX, + WLAN_ML_BV_CINFO_EMLCAP_TRANSTIMEOUT_BITS, + mlo_ie->eml_capabilities_info.transition_timeout); + + p_ml_ie += WLAN_ML_BV_CINFO_EMLCAP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_EMLCAP_SIZE; + } + + if (mlo_ie->mld_capab_and_op_present) { + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_MAXSIMULLINKS_BITS, + mlo_ie->mld_capab_and_op_info.max_simultaneous_link_num); + QDF_SET_BITS(*(uint16_t *)p_ml_ie, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_IDX, + WLAN_ML_BV_CINFO_MLDCAPANDOP_TIDTOLINKMAPNEGSUPPORT_BITS, + mlo_ie->mld_capab_and_op_info.tid_link_map_supported); + p_ml_ie += WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + len_remaining -= WLAN_ML_BV_CINFO_MLDCAPANDOP_SIZE; + } + + mlo_ie->num_data = p_ml_ie - mlo_ie->data; + pe_debug("VDEV %d ML-IE common info len %d eMLSR support %d pad_delay %d, trans_delay %d", + wlan_vdev_get_id(vdev), mlo_ie->num_data, + mlo_ie->eml_capabilities_info.emlsr_support, + mlo_ie->eml_capabilities_info.emlsr_padding_delay, + mlo_ie->eml_capabilities_info.emlsr_transition_delay); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS +populate_dot11f_rnr_tbtt_info(struct mac_context *mac_ctx, + struct pe_session *pe_session, + struct pe_session *rnr_session, + tDot11fIEreduced_neighbor_report *dot11f, + uint8_t tbtt_len) +{ + uint8_t reg_class; + uint8_t ch_offset; + uint8_t psd_power; + + dot11f->present = 1; + dot11f->tbtt_type = 0; + if (rnr_session->ch_width == CH_WIDTH_80MHZ) { + ch_offset = BW80; + } else { + switch (rnr_session->htSecondaryChannelOffset) { + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + ch_offset = BW40_HIGH_PRIMARY; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + ch_offset = BW40_LOW_PRIMARY; + break; + default: + ch_offset = BW20; + break; + } + } + + reg_class = lim_op_class_from_bandwidth(mac_ctx, + rnr_session->curr_op_freq, + rnr_session->ch_width, + ch_offset); + + psd_power = wlan_mlme_get_sap_psd_for_20mhz(rnr_session->vdev); + + dot11f->op_class = reg_class; + dot11f->channel_num = wlan_reg_freq_to_chan(mac_ctx->pdev, + rnr_session->curr_op_freq); + dot11f->tbtt_info_count = 0; + dot11f->tbtt_info_len = tbtt_len; + + switch (tbtt_len) { + case 7: + dot11f->tbtt_info.tbtt_info_7.tbtt_offset = + WLAN_RNR_TBTT_OFFSET_INVALID; + qdf_mem_copy(dot11f->tbtt_info.tbtt_info_7.bssid, + rnr_session->self_mac_addr, sizeof(tSirMacAddr)); + break; + case 9: + dot11f->tbtt_info.tbtt_info_9.tbtt_offset = + WLAN_RNR_TBTT_OFFSET_INVALID; + qdf_mem_copy(dot11f->tbtt_info.tbtt_info_9.bssid, + rnr_session->self_mac_addr, sizeof(tSirMacAddr)); + dot11f->tbtt_info.tbtt_info_9.bss_params = + WLAN_RNR_BSS_PARAM_COLOCATED_AP; + if (!lim_cmp_ssid(&rnr_session->ssId, pe_session)) + dot11f->tbtt_info.tbtt_info_9.bss_params |= + WLAN_RNR_BSS_PARAM_SAME_SSID; + if (psd_power) + dot11f->tbtt_info.tbtt_info_9.psd_20mhz = psd_power; + else + dot11f->tbtt_info.tbtt_info_9.psd_20mhz = 127; + break; + case 13: + dot11f->tbtt_info.tbtt_info_13.tbtt_offset = + WLAN_RNR_TBTT_OFFSET_INVALID; + qdf_mem_copy(dot11f->tbtt_info.tbtt_info_13.bssid, + rnr_session->self_mac_addr, sizeof(tSirMacAddr)); + + dot11f->tbtt_info.tbtt_info_13.short_ssid = + wlan_construct_shortssid(rnr_session->ssId.ssId, + rnr_session->ssId.length); + + dot11f->tbtt_info.tbtt_info_13.bss_params = + WLAN_RNR_BSS_PARAM_COLOCATED_AP; + if (!lim_cmp_ssid(&rnr_session->ssId, pe_session)) + dot11f->tbtt_info.tbtt_info_13.bss_params |= + WLAN_RNR_BSS_PARAM_SAME_SSID; + + if (psd_power) + dot11f->tbtt_info.tbtt_info_13.psd_20mhz = psd_power; + else + dot11f->tbtt_info.tbtt_info_13.psd_20mhz = 127; + break; + default: + dot11f->tbtt_info_len = 0; + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * lim_is_6g_vdev() - loop every vdev to populate 6g vdev id + * @psoc: pointer to psoc + * @obj: vdev + * @args: vdev list to record 6G vdev id + * + * Return: void + */ +static void lim_is_6g_vdev(struct wlan_objmgr_psoc *psoc, void *obj, void *args) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)obj; + uint8_t *vdev_id_list = (uint8_t *)args; + int i; + + if (!vdev || (wlan_vdev_mlme_get_opmode(vdev) != QDF_SAP_MODE)) + return; + if (QDF_IS_STATUS_ERROR(wlan_vdev_chan_config_valid(vdev))) + return; + if (!wlan_reg_is_6ghz_chan_freq(wlan_get_operation_chan_freq(vdev))) + return; + + for (i = 0; i < MAX_NUMBER_OF_CONC_CONNECTIONS; i++) { + if (vdev_id_list[i] == INVALID_VDEV_ID) { + vdev_id_list[i] = wlan_vdev_get_id(vdev); + break; + } + } +} + +void populate_dot11f_6g_rnr(struct mac_context *mac_ctx, + struct pe_session *session, + tDot11fIEreduced_neighbor_report *dot11f) +{ + struct pe_session *co_session; + struct wlan_objmgr_psoc *psoc; + int vdev_id; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + + if (!session || !mac_ctx || !dot11f || !session->vdev) { + pe_err("Invalid params"); + return; + } + + psoc = wlan_vdev_get_psoc(session->vdev); + if (!psoc) { + pe_err("Invalid psoc"); + return; + } + + for (vdev_id = 0; vdev_id < MAX_NUMBER_OF_CONC_CONNECTIONS; vdev_id++) + vdev_id_list[vdev_id] = INVALID_VDEV_ID; + + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + lim_is_6g_vdev, + vdev_id_list, 1, + WLAN_LEGACY_MAC_ID); + + if (vdev_id_list[0] == INVALID_VDEV_ID) + return; + + co_session = pe_find_session_by_vdev_id(mac_ctx, + vdev_id_list[0]); + if (!co_session) { + pe_err("Invalid co located session"); + return; + } + populate_dot11f_rnr_tbtt_info(mac_ctx, session, co_session, dot11f, + CURRENT_RNR_TBTT_INFO_LEN); + pe_debug("vdev id %d populate RNR IE with 6G vdev id %d op class %d chan num %d", + wlan_vdev_get_id(session->vdev), + wlan_vdev_get_id(co_session->vdev), + dot11f->op_class, dot11f->channel_num); +} + +QDF_STATUS populate_dot11f_bcn_prot_extcaps(struct mac_context *mac_ctx, + struct pe_session *pe_session, + tDot11fIEExtCap *dot11f) +{ + struct s_ext_cap *p_ext_cap; + + /* + * Some legacy STA might not connect with SAP broadcasting + * EXTCAP with size greater than 8bytes. + * In such cases, disable the beacon protection only if + * a) disable_sap_bcn_prot ini is set + * b) The SAP is not operating in 6 GHz or 11be profile + * where BP is mandatory. + */ + if (pe_session->opmode != QDF_SAP_MODE || + !wlan_mlme_is_bcn_prot_disabled_for_sap(mac_ctx->psoc) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(pe_session->curr_op_freq) || + pe_session->dot11mode > MLME_DOT11_MODE_11AX_ONLY) + return QDF_STATUS_SUCCESS; + + p_ext_cap = (struct s_ext_cap *)dot11f->bytes; + if (!dot11f->present || !p_ext_cap->beacon_protection_enable) + return QDF_STATUS_SUCCESS; + + p_ext_cap->beacon_protection_enable = 0; + dot11f->num_bytes = lim_compute_ext_cap_ie_length(dot11f); + + return QDF_STATUS_SUCCESS; +} +/* parser_api.c ends here. */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c new file mode 100644 index 0000000000..ab30ec3358 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/mac/src/sys/legacy/src/utils/src/utils_parser.c @@ -0,0 +1,690 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * + * This file utils_parser.cc contains the code for parsing + * 802.11 messages. + * Author: Pierre Vandwalle + * Date: 03/18/02 + * History:- + * Date Modified by Modification Information + * -------------------------------------------------------------------- + * + */ + +#include "ani_global.h" +#include "utils_parser.h" +#include "lim_ser_des_utils.h" + +void convert_ssid(struct mac_context *mac, tSirMacSSid *pOld, tDot11fIESSID *pNew) +{ + pOld->length = pNew->num_ssid; + qdf_mem_copy(pOld->ssId, pNew->ssid, pNew->num_ssid); +} + +void convert_supp_rates(struct mac_context *mac, + tSirMacRateSet *pOld, tDot11fIESuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + qdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_ext_supp_rates(struct mac_context *mac, + tSirMacRateSet *pOld, tDot11fIEExtSuppRates *pNew) +{ + pOld->numRates = pNew->num_rates; + qdf_mem_copy(pOld->rate, pNew->rates, pNew->num_rates); +} + +void convert_qos_caps(struct mac_context *mac, + tSirMacQosCapabilityIE *pOld, tDot11fIEQOSCapsAp *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.count = pNew->count; +} + +void convert_qos_caps_station(struct mac_context *mac, + tSirMacQosCapabilityStaIE *pOld, + tDot11fIEQOSCapsStation *pNew) +{ + pOld->type = 46; + pOld->length = 1; + + pOld->qosInfo.moreDataAck = pNew->more_data_ack; + pOld->qosInfo.maxSpLen = pNew->max_sp_length; + pOld->qosInfo.qack = pNew->qack; + pOld->qosInfo.acbe_uapsd = pNew->acbe_uapsd; + pOld->qosInfo.acbk_uapsd = pNew->acbk_uapsd; + pOld->qosInfo.acvi_uapsd = pNew->acvi_uapsd; + pOld->qosInfo.acvo_uapsd = pNew->acvo_uapsd; +} + +QDF_STATUS convert_wpa(struct mac_context *mac, + tSirMacWpaInfo *pOld, tDot11fIEWPA *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into an */ + /* array... */ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + + status = dot11f_pack_ie_wpa(mac, pNew, buffer, nbuffer, &written); + if (DOT11F_FAILED(status)) { + pe_err("Failed to re-pack the WPA IE (0x%0x8)", status); + return QDF_STATUS_E_FAILURE; + } + + pOld->length = (uint8_t) written - 2; + qdf_mem_copy(pOld->info, buffer + 2, pOld->length); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS convert_wpa_opaque(struct mac_context *mac, + tSirMacWpaInfo *pOld, tDot11fIEWPAOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the OUI! */ + pOld->length = pNew->num_data + 4; + pOld->info[0] = 0x00; + pOld->info[1] = 0x50; + pOld->info[2] = 0xf2; + pOld->info[3] = 0x01; + qdf_mem_copy(pOld->info + 4, pNew->data, pNew->num_data); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_WAPI +QDF_STATUS convert_wapi_opaque(struct mac_context *mac, + tSirMacWapiInfo *pOld, + tDot11fIEWAPIOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the OUI! */ + pOld->length = pNew->num_data; + qdf_mem_copy(pOld->info, pNew->data, pNew->num_data); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS convert_wsc_opaque(struct mac_context *mac, + tSirAddie *pOld, tDot11fIEWscIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint16_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x00; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0xf2; + pOld->addIEdata[curAddIELen++] = 0x04; + qdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS convert_p2p_opaque(struct mac_context *mac, + tSirAddie *pOld, tDot11fIEP2PIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint16_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0x6f; + pOld->addIEdata[curAddIELen++] = 0x9A; + pOld->addIEdata[curAddIELen++] = 0x09; + qdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_WFD +QDF_STATUS convert_wfd_opaque(struct mac_context *mac, + tSirAddie *pOld, tDot11fIEWFDIEOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. Note that we need to explicitly add the vendorIE and OUI ! */ + uint16_t curAddIELen = pOld->length; + + pOld->length = curAddIELen + pNew->num_data + 6; + pOld->addIEdata[curAddIELen++] = 0xdd; + pOld->addIEdata[curAddIELen++] = pNew->num_data + 4; + pOld->addIEdata[curAddIELen++] = 0x50; + pOld->addIEdata[curAddIELen++] = 0x6f; + pOld->addIEdata[curAddIELen++] = 0x9A; + pOld->addIEdata[curAddIELen++] = 0x0a; + qdf_mem_copy(pOld->addIEdata + curAddIELen, pNew->data, pNew->num_data); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS convert_rsn(struct mac_context *mac, + tSirMacRsnInfo *pOld, tDot11fIERSN *pNew) +{ + uint8_t buffer[257]; + uint32_t status, written = 0, nbuffer = 257; + + status = dot11f_pack_ie_rsn(mac, pNew, buffer, nbuffer, &written); + if (DOT11F_FAILED(status)) { + pe_err("Failed to re-pack the RSN IE (0x%0x8)", status); + return QDF_STATUS_E_FAILURE; + } + + pOld->length = (uint8_t) written - 2; + qdf_mem_copy(pOld->info, buffer + 2, pOld->length); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS convert_rsn_opaque(struct mac_context *mac, + tSirMacRsnInfo *pOld, tDot11fIERSNOpaque *pNew) +{ + /* This is awful, I know, but the old code just rammed the IE into */ + /* an opaque array. */ + pOld->length = pNew->num_data; + qdf_mem_copy(pOld->info, pNew->data, pOld->length); + + return QDF_STATUS_SUCCESS; +} + +void convert_power_caps(struct mac_context *mac, + tSirMacPowerCapabilityIE *pOld, + tDot11fIEPowerCaps *pNew) +{ + pOld->type = 33; + pOld->length = 2; + pOld->minTxPower = pNew->minTxPower; + pOld->maxTxPower = pNew->maxTxPower; +} + +void convert_supp_channels(struct mac_context *mac, + tSirMacSupportedChannelIE *pOld, + tDot11fIESuppChannels *pNew) +{ + pOld->type = 36; + pOld->length = (pNew->num_bands * 2); + qdf_mem_copy((uint8_t *) pOld->supportedChannels, + (uint8_t *) pNew->bands, pOld->length); +} + +void convert_cf_params(struct mac_context *mac, + tSirMacCfParamSet *pOld, tDot11fIECFParams *pNew) +{ + pOld->cfpCount = pNew->cfp_count; + pOld->cfpPeriod = pNew->cfp_period; + pOld->cfpMaxDuration = pNew->cfp_maxduration; + pOld->cfpDurRemaining = pNew->cfp_durremaining; +} + +void convert_fh_params(struct mac_context *mac, + tSirMacFHParamSet *pOld, tDot11fIEFHParamSet *pNew) +{ + pOld->dwellTime = pNew->dwell_time; + pOld->hopSet = pNew->hop_set; + pOld->hopPattern = pNew->hop_pattern; + pOld->hopIndex = pNew->hop_index; +} + +void convert_tim(struct mac_context *mac, tSirMacTim *pOld, tDot11fIETIM *pNew) +{ + pOld->dtimCount = pNew->dtim_count; + pOld->dtimPeriod = pNew->dtim_period; + pOld->bitmapControl = pNew->bmpctl; + pOld->bitmapLength = pNew->num_vbmp; + + qdf_mem_copy(pOld->bitmap, pNew->vbmp, pNew->num_vbmp); +} + +void convert_country(struct mac_context *mac, + tSirCountryInformation *pOld, tDot11fIECountry *pNew) +{ + uint8_t i = 0; + + qdf_mem_copy(pOld->countryString, pNew->country, COUNTRY_STRING_LENGTH); + + pOld->numIntervals = pNew->num_more_triplets; + + pOld->channelTransmitPower[i].channelNumber = pNew->first_triplet[0]; + pOld->channelTransmitPower[i].numChannel = pNew->first_triplet[1]; + pOld->channelTransmitPower[i].maxTransmitPower = pNew->first_triplet[2]; + + for (i = 0; i < pNew->num_more_triplets; i++) { + pOld->channelTransmitPower[i+1].channelNumber = + pNew->more_triplets[i][0]; + pOld->channelTransmitPower[i+1].numChannel = + pNew->more_triplets[i][1]; + pOld->channelTransmitPower[i+1].maxTransmitPower = + pNew->more_triplets[i][2]; + } +} + +void convert_wmm_params(struct mac_context *mac, + tSirMacEdcaParamSetIE *pOld, tDot11fIEWMMParams *pNew) +{ + pOld->type = 221; + pOld->length = 24; + + qdf_mem_copy((uint8_t *) &pOld->qosInfo, (uint8_t *) &pNew->qosInfo, + 1); + + pOld->acbe.aci.aifsn = pNew->acbe_aifsn; + pOld->acbe.aci.acm = pNew->acbe_acm; + pOld->acbe.aci.aci = pNew->acbe_aci; + pOld->acbe.cw.min = pNew->acbe_acwmin; + pOld->acbe.cw.max = pNew->acbe_acwmax; + pOld->acbe.txoplimit = pNew->acbe_txoplimit; + + pOld->acbk.aci.aifsn = pNew->acbk_aifsn; + pOld->acbk.aci.acm = pNew->acbk_acm; + pOld->acbk.aci.aci = pNew->acbk_aci; + pOld->acbk.cw.min = pNew->acbk_acwmin; + pOld->acbk.cw.max = pNew->acbk_acwmax; + pOld->acbk.txoplimit = pNew->acbk_txoplimit; + + pOld->acvi.aci.aifsn = pNew->acvi_aifsn; + pOld->acvi.aci.acm = pNew->acvi_acm; + pOld->acvi.aci.aci = pNew->acvi_aci; + pOld->acvi.cw.min = pNew->acvi_acwmin; + pOld->acvi.cw.max = pNew->acvi_acwmax; + pOld->acvi.txoplimit = pNew->acvi_txoplimit; + + pOld->acvo.aci.aifsn = pNew->acvo_aifsn; + pOld->acvo.aci.acm = pNew->acvo_acm; + pOld->acvo.aci.aci = pNew->acvo_aci; + pOld->acvo.cw.min = pNew->acvo_acwmin; + pOld->acvo.cw.max = pNew->acvo_acwmax; + pOld->acvo.txoplimit = pNew->acvo_txoplimit; +} + +void convert_erp_info(struct mac_context *mac, + tSirMacErpInfo *pOld, tDot11fIEERPInfo *pNew) +{ + pOld->nonErpPresent = pNew->non_erp_present; + pOld->useProtection = pNew->use_prot; + pOld->barkerPreambleMode = pNew->barker_preamble; +} + +void convert_edca_param(struct mac_context *mac, + tSirMacEdcaParamSetIE *pOld, + tDot11fIEEDCAParamSet *pNew) +{ + pOld->type = 12; + pOld->length = 20; + + qdf_mem_copy((uint8_t *) &pOld->qosInfo, (uint8_t *) &pNew->qos, 1); + + pOld->acbe.aci.aifsn = pNew->acbe_aifsn; + pOld->acbe.aci.acm = pNew->acbe_acm; + pOld->acbe.aci.aci = pNew->acbe_aci; + pOld->acbe.cw.min = pNew->acbe_acwmin; + pOld->acbe.cw.max = pNew->acbe_acwmax; + pOld->acbe.txoplimit = pNew->acbe_txoplimit; + + pOld->acbk.aci.aifsn = pNew->acbk_aifsn; + pOld->acbk.aci.acm = pNew->acbk_acm; + pOld->acbk.aci.aci = pNew->acbk_aci; + pOld->acbk.cw.min = pNew->acbk_acwmin; + pOld->acbk.cw.max = pNew->acbk_acwmax; + pOld->acbk.txoplimit = pNew->acbk_txoplimit; + + pOld->acvi.aci.aifsn = pNew->acvi_aifsn; + pOld->acvi.aci.acm = pNew->acvi_acm; + pOld->acvi.aci.aci = pNew->acvi_aci; + pOld->acvi.cw.min = pNew->acvi_acwmin; + pOld->acvi.cw.max = pNew->acvi_acwmax; + pOld->acvi.txoplimit = pNew->acvi_txoplimit; + + pOld->acvo.aci.aifsn = pNew->acvo_aifsn; + pOld->acvo.aci.acm = pNew->acvo_acm; + pOld->acvo.aci.aci = pNew->acvo_aci; + pOld->acvo.cw.min = pNew->acvo_acwmin; + pOld->acvo.cw.max = pNew->acvo_acwmax; + pOld->acvo.txoplimit = pNew->acvo_txoplimit; + +} + +void convert_mu_edca_param(struct mac_context *mac_ctx, + tSirMacEdcaParamSetIE *mu_edca, + tDot11fIEmu_edca_param_set *ie) +{ + qdf_mem_copy((uint8_t *) &mu_edca->qosInfo, (uint8_t *) &ie->qos, 1); + + mu_edca->acbe.aci.aifsn = ie->acbe_aifsn; + mu_edca->acbe.aci.acm = ie->acbe_acm; + mu_edca->acbe.aci.aci = ie->acbe_aci; + mu_edca->acbe.cw.min = ie->acbe_acwmin; + mu_edca->acbe.cw.max = ie->acbe_acwmax; + mu_edca->acbe.mu_edca_timer = ie->acbe_muedca_timer; + + mu_edca->acbk.aci.aifsn = ie->acbk_aifsn; + mu_edca->acbk.aci.acm = ie->acbk_acm; + mu_edca->acbk.aci.aci = ie->acbk_aci; + mu_edca->acbk.cw.min = ie->acbk_acwmin; + mu_edca->acbk.cw.max = ie->acbk_acwmax; + mu_edca->acbk.mu_edca_timer = ie->acbk_muedca_timer; + + mu_edca->acvi.aci.aifsn = ie->acvi_aifsn; + mu_edca->acvi.aci.acm = ie->acvi_acm; + mu_edca->acvi.aci.aci = ie->acvi_aci; + mu_edca->acvi.cw.min = ie->acvi_acwmin; + mu_edca->acvi.cw.max = ie->acvi_acwmax; + mu_edca->acvi.mu_edca_timer = ie->acvi_muedca_timer; + + mu_edca->acvo.aci.aifsn = ie->acvo_aifsn; + mu_edca->acvo.aci.acm = ie->acvo_acm; + mu_edca->acvo.aci.aci = ie->acvo_aci; + mu_edca->acvo.cw.min = ie->acvo_acwmin; + mu_edca->acvo.cw.max = ie->acvo_acwmax; + mu_edca->acvo.mu_edca_timer = ie->acvo_muedca_timer; + +} + +void convert_tspec(struct mac_context *mac, + struct mac_tspec_ie *pOld, tDot11fIETSPEC *pNew) +{ + pOld->tsinfo.traffic.trafficType = (uint16_t) pNew->traffic_type; + pOld->tsinfo.traffic.tsid = (uint16_t) pNew->tsid; + pOld->tsinfo.traffic.direction = (uint16_t) pNew->direction; + pOld->tsinfo.traffic.accessPolicy = (uint16_t) pNew->access_policy; + pOld->tsinfo.traffic.aggregation = (uint16_t) pNew->aggregation; + pOld->tsinfo.traffic.psb = (uint16_t) pNew->psb; + pOld->tsinfo.traffic.userPrio = (uint16_t) pNew->user_priority; + pOld->tsinfo.traffic.ackPolicy = (uint16_t) pNew->tsinfo_ack_pol; + + pOld->tsinfo.schedule.schedule = (uint8_t) pNew->schedule; + + pOld->nomMsduSz = pNew->size; + pOld->maxMsduSz = pNew->max_msdu_size; + pOld->minSvcInterval = pNew->min_service_int; + pOld->maxSvcInterval = pNew->max_service_int; + pOld->inactInterval = pNew->inactivity_int; + pOld->suspendInterval = pNew->suspension_int; + pOld->svcStartTime = pNew->service_start_time; + pOld->minDataRate = pNew->min_data_rate; + pOld->meanDataRate = pNew->mean_data_rate; + pOld->peakDataRate = pNew->peak_data_rate; + pOld->maxBurstSz = pNew->burst_size; + pOld->delayBound = pNew->delay_bound; + pOld->minPhyRate = pNew->min_phy_rate; + pOld->surplusBw = pNew->surplus_bw_allowance; + pOld->mediumTime = pNew->medium_time; +} + +QDF_STATUS convert_tclas(struct mac_context *mac, + tSirTclasInfo *pOld, tDot11fIETCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_ietclas(mac, pNew, &length))) { + return QDF_STATUS_E_FAILURE; + } + + pOld->tclas.type = DOT11F_EID_TCLAS; + pOld->tclas.length = (uint8_t) length; + pOld->tclas.userPrio = pNew->user_priority; + pOld->tclas.classifierType = pNew->classifier_type; + pOld->tclas.classifierMask = pNew->classifier_mask; + + switch (pNew->classifier_type) { + case 0: + qdf_mem_copy(pOld->tclasParams.eth.srcAddr, + pNew->info.EthParams.source, 6); + qdf_mem_copy(pOld->tclasParams.eth.dstAddr, + pNew->info.EthParams.dest, 6); + pOld->tclasParams.eth.type = pNew->info.EthParams.type; + break; + case 1: + pOld->version = pNew->info.IpParams.version; + if (4 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv4.version = 4; + qdf_mem_copy(pOld->tclasParams.ipv4.srcIpAddr, + pNew->info.IpParams.params.IpV4Params. + source, 4); + qdf_mem_copy(pOld->tclasParams.ipv4.dstIpAddr, + pNew->info.IpParams.params.IpV4Params.dest, + 4); + pOld->tclasParams.ipv4.srcPort = + pNew->info.IpParams.params.IpV4Params.src_port; + pOld->tclasParams.ipv4.dstPort = + pNew->info.IpParams.params.IpV4Params.dest_port; + pOld->tclasParams.ipv4.dscp = + pNew->info.IpParams.params.IpV4Params.DSCP; + pOld->tclasParams.ipv4.protocol = + pNew->info.IpParams.params.IpV4Params.proto; + pOld->tclasParams.ipv4.rsvd = + pNew->info.IpParams.params.IpV4Params.reserved; + } else if (6 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv6.version = 6; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.source, 16); + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.dest, 16); + pOld->tclasParams.ipv6.srcPort = + pNew->info.IpParams.params.IpV6Params.src_port; + pOld->tclasParams.ipv6.dstPort = + pNew->info.IpParams.params.IpV6Params.dest_port; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + flowLabel, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.flow_label, 3); + } else { + return QDF_STATUS_E_FAILURE; + } + break; + case 2: + pOld->tclasParams.t8021dq.tag = + pNew->info.Params8021dq.tag_type; + break; + default: + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void convert_wmmtspec(struct mac_context *mac, + struct mac_tspec_ie *pOld, tDot11fIEWMMTSPEC *pNew) +{ + pOld->tsinfo.traffic.trafficType = (uint16_t) pNew->traffic_type; + pOld->tsinfo.traffic.tsid = (uint16_t) pNew->tsid; + pOld->tsinfo.traffic.direction = (uint16_t) pNew->direction; + pOld->tsinfo.traffic.accessPolicy = (uint16_t) pNew->access_policy; + pOld->tsinfo.traffic.aggregation = (uint16_t) pNew->aggregation; + pOld->tsinfo.traffic.psb = (uint16_t) pNew->psb; + pOld->tsinfo.traffic.userPrio = (uint16_t) pNew->user_priority; + pOld->tsinfo.traffic.ackPolicy = (uint16_t) pNew->tsinfo_ack_pol; + pOld->nomMsduSz = (pNew->fixed << 15) | pNew->size; + pOld->maxMsduSz = pNew->max_msdu_size; + pOld->minSvcInterval = pNew->min_service_int; + pOld->maxSvcInterval = pNew->max_service_int; + pOld->inactInterval = pNew->inactivity_int; + pOld->suspendInterval = pNew->suspension_int; + pOld->svcStartTime = pNew->service_start_time; + pOld->minDataRate = pNew->min_data_rate; + pOld->meanDataRate = pNew->mean_data_rate; + pOld->peakDataRate = pNew->peak_data_rate; + pOld->maxBurstSz = pNew->burst_size; + pOld->delayBound = pNew->delay_bound; + pOld->minPhyRate = pNew->min_phy_rate; + pOld->surplusBw = pNew->surplus_bw_allowance; + pOld->mediumTime = pNew->medium_time; +} + +QDF_STATUS convert_wmmtclas(struct mac_context *mac, + tSirTclasInfo *pOld, tDot11fIEWMMTCLAS *pNew) +{ + uint32_t length = 0; + + if (DOT11F_FAILED(dot11f_get_packed_iewmmtclas(mac, pNew, &length))) { + return QDF_STATUS_E_FAILURE; + } + + pOld->tclas.type = DOT11F_EID_WMMTCLAS; + pOld->tclas.length = (uint8_t) length; + pOld->tclas.userPrio = pNew->user_priority; + pOld->tclas.classifierType = pNew->classifier_type; + pOld->tclas.classifierMask = pNew->classifier_mask; + + switch (pNew->classifier_type) { + case 0: + qdf_mem_copy(pOld->tclasParams.eth.srcAddr, + pNew->info.EthParams.source, 6); + qdf_mem_copy(pOld->tclasParams.eth.dstAddr, + pNew->info.EthParams.dest, 6); + pOld->tclasParams.eth.type = pNew->info.EthParams.type; + break; + case 1: + pOld->version = pNew->info.IpParams.version; + if (4 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv4.version = 4; + qdf_mem_copy(pOld->tclasParams.ipv4.srcIpAddr, + pNew->info.IpParams.params.IpV4Params. + source, 4); + qdf_mem_copy(pOld->tclasParams.ipv4.dstIpAddr, + pNew->info.IpParams.params.IpV4Params.dest, + 4); + pOld->tclasParams.ipv4.srcPort = + pNew->info.IpParams.params.IpV4Params.src_port; + pOld->tclasParams.ipv4.dstPort = + pNew->info.IpParams.params.IpV4Params.dest_port; + pOld->tclasParams.ipv4.dscp = + pNew->info.IpParams.params.IpV4Params.DSCP; + pOld->tclasParams.ipv4.protocol = + pNew->info.IpParams.params.IpV4Params.proto; + pOld->tclasParams.ipv4.rsvd = + pNew->info.IpParams.params.IpV4Params.reserved; + } else if (6 == pNew->info.IpParams.version) { + pOld->tclasParams.ipv6.version = 6; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + srcIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.source, 16); + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + dstIpAddr, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.dest, 16); + pOld->tclasParams.ipv6.srcPort = + pNew->info.IpParams.params.IpV6Params.src_port; + pOld->tclasParams.ipv6.dstPort = + pNew->info.IpParams.params.IpV6Params.dest_port; + qdf_mem_copy((uint8_t *) pOld->tclasParams.ipv6. + flowLabel, + (uint8_t *) pNew->info.IpParams.params. + IpV6Params.flow_label, 3); + } else { + return QDF_STATUS_E_FAILURE; + } + break; + case 2: + pOld->tclasParams.t8021dq.tag = + pNew->info.Params8021dq.tag_type; + break; + default: + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void convert_ts_delay(struct mac_context *mac, + tSirMacTsDelayIE *pOld, tDot11fIETSDelay *pNew) +{ + pOld->type = DOT11F_EID_TSDELAY; + pOld->length = 4U; + pOld->delay = pNew->delay; +} + +void convert_schedule(struct mac_context *mac, + tSirMacScheduleIE *pOld, tDot11fIESchedule *pNew) +{ + pOld->type = DOT11F_EID_SCHEDULE; + pOld->length = DOT11F_IE_SCHEDULE_MIN_LEN; + + pOld->info.aggregation = pNew->aggregation; + pOld->info.tsid = pNew->tsid; + pOld->info.direction = pNew->direction; + + pOld->svcStartTime = pNew->service_start_time; + pOld->svcInterval = pNew->service_interval; + pOld->specInterval = pNew->spec_interval; +} + +void convert_wmm_schedule(struct mac_context *mac, + tSirMacScheduleIE *pOld, tDot11fIEWMMSchedule *pNew) +{ + pOld->type = DOT11F_EID_WMMSCHEDULE; + pOld->length = DOT11F_IE_WMMSCHEDULE_MIN_LEN; + + pOld->info.aggregation = pNew->aggregation; + pOld->info.tsid = pNew->tsid; + pOld->info.direction = pNew->direction; + + pOld->svcStartTime = pNew->service_start_time; + pOld->svcInterval = pNew->service_interval; + pOld->specInterval = pNew->spec_interval; +} + +void convert_qos_mapset_frame(struct mac_context *mac, struct qos_map_set *qos, + tDot11fIEQosMapSet *dot11f_ie) +{ + uint8_t i, j = 0; + uint8_t dot11_dscp_exception_sz; + + if (dot11f_ie->num_dscp_exceptions < DOT11F_IE_QOSMAPSET_MIN_LEN || + dot11f_ie->num_dscp_exceptions % 2) { + pe_debug("Invalid num_dscp_exceptions %d", + dot11f_ie->num_dscp_exceptions); + return; + } + + dot11_dscp_exception_sz = dot11f_ie->num_dscp_exceptions - + DOT11F_IE_QOSMAPSET_MIN_LEN; + qos->num_dscp_exceptions = dot11_dscp_exception_sz / 2; + if (qos->num_dscp_exceptions > QOS_MAP_MAX_EX) + qos->num_dscp_exceptions = QOS_MAP_MAX_EX; + + for (i = 0; i < qos->num_dscp_exceptions && + j < dot11_dscp_exception_sz - 1; i++) { + qos->dscp_exceptions[i][0] = dot11f_ie->dscp_exceptions[j++]; + qos->dscp_exceptions[i][1] = dot11f_ie->dscp_exceptions[j++]; + } + + for (i = 0; i < QOS_MAP_RANGE_NUM && + j < dot11f_ie->num_dscp_exceptions - 1; i++) { + qos->dscp_range[i][0] = dot11f_ie->dscp_exceptions[j++]; + qos->dscp_range[i][1] = dot11f_ie->dscp_exceptions[j++]; + } +} + +/* utils_parser.c ends here. */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/inc/pld_common.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/inc/pld_common.h new file mode 100644 index 0000000000..d04d28697c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/inc/pld_common.h @@ -0,0 +1,2130 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_COMMON_H__ +#define __PLD_COMMON_H__ + +#include +#include +#include +#include + +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss2.h" +#else +#include +#endif + +#ifdef CNSS_UTILS +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss_utils.h" +#else +#include +#endif +#endif + +#define PLD_IMAGE_FILE "athwlan.bin" +#define PLD_UTF_FIRMWARE_FILE "utf.bin" +#define PLD_BOARD_DATA_FILE "fakeboar.bin" +#define PLD_OTP_FILE "otp.bin" +#define PLD_SETUP_FILE "athsetup.bin" +#define PLD_EPPING_FILE "epping.bin" +#define PLD_EVICTED_FILE "" +#define PLD_MHI_STATE_L0 1 + +#define TOTAL_DUMP_SIZE 0x00200000 + +#ifdef CNSS_MEM_PRE_ALLOC +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss_prealloc.h" +#else +#include +#endif +#endif + +#define PLD_LIMIT_LOG_FOR_SEC 6 +/** + * __PLD_TRACE_RATE_LIMITED() - rate limited version of PLD_TRACE + * @params: parameters to pass through to PLD_TRACE + * + * This API prevents logging a message more than once in PLD_LIMIT_LOG_FOR_SEC + * seconds. This means any subsequent calls to this API from the same location + * within PLD_LIMIT_LOG_FOR_SEC seconds will be dropped. + * + * Return: None + */ +#define __PLD_TRACE_RATE_LIMITED(params...)\ + do {\ + static ulong __last_ticks;\ + ulong __ticks = jiffies;\ + if (time_after(__ticks,\ + __last_ticks + (HZ * PLD_LIMIT_LOG_FOR_SEC))) {\ + pr_err(params);\ + __last_ticks = __ticks;\ + } \ + } while (0) + +#define pld_err_rl(params...) __PLD_TRACE_RATE_LIMITED(params) + +/** + * enum pld_bus_type - bus type + * @PLD_BUS_TYPE_NONE: invalid bus type, only return in error cases + * @PLD_BUS_TYPE_PCIE: PCIE bus + * @PLD_BUS_TYPE_SNOC: SNOC bus + * @PLD_BUS_TYPE_SDIO: SDIO bus + * @PLD_BUS_TYPE_USB : USB bus + * @PLD_BUS_TYPE_SNOC_FW_SIM : SNOC FW SIM bus + * @PLD_BUS_TYPE_PCIE_FW_SIM : PCIE FW SIM bus + * @PLD_BUS_TYPE_IPCI : IPCI bus + * @PLD_BUS_TYPE_IPCI_FW_SIM : IPCI FW SIM bus + */ +enum pld_bus_type { + PLD_BUS_TYPE_NONE = -1, + PLD_BUS_TYPE_PCIE = 0, + PLD_BUS_TYPE_SNOC, + PLD_BUS_TYPE_SDIO, + PLD_BUS_TYPE_USB, + PLD_BUS_TYPE_SNOC_FW_SIM, + PLD_BUS_TYPE_PCIE_FW_SIM, + PLD_BUS_TYPE_IPCI, + PLD_BUS_TYPE_IPCI_FW_SIM, +}; + +#define PLD_MAX_FIRMWARE_SIZE (1 * 1024 * 1024) + +/** + * enum pld_bus_width_type - bus bandwidth + * @PLD_BUS_WIDTH_NONE: don't vote for bus bandwidth + * @PLD_BUS_WIDTH_IDLE: vote for idle bandwidth + * @PLD_BUS_WIDTH_LOW: vote for low bus bandwidth + * @PLD_BUS_WIDTH_MEDIUM: vote for medium bus bandwidth + * @PLD_BUS_WIDTH_HIGH: vote for high bus bandwidth + * @PLD_BUS_WIDTH_MID_HIGH: vote for mid high bus bandwidth + * @PLD_BUS_WIDTH_VERY_HIGH: vote for very high bus bandwidth + * @PLD_BUS_WIDTH_ULTRA_HIGH: vote for ultra high bus bandwidth + * @PLD_BUS_WIDTH_LOW_LATENCY: vote for low latency bus bandwidth + * @PLD_BUS_WIDTH_MAX: + */ +enum pld_bus_width_type { + PLD_BUS_WIDTH_NONE, + PLD_BUS_WIDTH_IDLE, + PLD_BUS_WIDTH_LOW, + PLD_BUS_WIDTH_MEDIUM, + PLD_BUS_WIDTH_HIGH, + PLD_BUS_WIDTH_VERY_HIGH, + PLD_BUS_WIDTH_ULTRA_HIGH, + PLD_BUS_WIDTH_MAX, + PLD_BUS_WIDTH_LOW_LATENCY, + PLD_BUS_WIDTH_MID_HIGH, +}; + +#define PLD_MAX_FILE_NAME NAME_MAX + +/** + * struct pld_fw_files - WLAN FW file names + * @image_file: WLAN FW image file + * @board_data: WLAN FW board data file + * @otp_data: WLAN FW OTP file + * @utf_file: WLAN FW UTF file + * @utf_board_data: WLAN FW UTF board data file + * @epping_file: WLAN FW EPPING mode file + * @evicted_data: WLAN FW evicted file + * @setup_file: WLAN FW setup file + * @ibss_image_file: WLAN FW IBSS mode file + * + * pld_fw_files is used to store WLAN FW file names + */ +struct pld_fw_files { + char image_file[PLD_MAX_FILE_NAME]; + char board_data[PLD_MAX_FILE_NAME]; + char otp_data[PLD_MAX_FILE_NAME]; + char utf_file[PLD_MAX_FILE_NAME]; + char utf_board_data[PLD_MAX_FILE_NAME]; + char epping_file[PLD_MAX_FILE_NAME]; + char evicted_data[PLD_MAX_FILE_NAME]; + char setup_file[PLD_MAX_FILE_NAME]; + char ibss_image_file[PLD_MAX_FILE_NAME]; +}; + +/** + * enum pld_platform_cap_flag - platform capability flag + * @PLD_HAS_EXTERNAL_SWREG: has external regulator + * @PLD_HAS_UART_ACCESS: has UART access + * @PLD_HAS_DRV_SUPPORT: has PCIe DRV support + */ +enum pld_platform_cap_flag { + PLD_HAS_EXTERNAL_SWREG = 0x01, + PLD_HAS_UART_ACCESS = 0x02, + PLD_HAS_DRV_SUPPORT = 0x04, +}; + +/** + * enum pld_wfc_mode - WFC Mode + * @PLD_WFC_MODE_OFF: WFC Inactive + * @PLD_WFC_MODE_ON: WFC Active + */ +enum pld_wfc_mode { + PLD_WFC_MODE_OFF, + PLD_WFC_MODE_ON, +}; + +/** + * struct pld_platform_cap - platform capabilities + * @cap_flag: capabilities flag + * + * pld_platform_cap provides platform capabilities which are + * extracted from DTS. + */ +struct pld_platform_cap { + u32 cap_flag; +}; + +/** + * enum pld_uevent - PLD uevent event types + * @PLD_FW_DOWN: firmware is down + * @PLD_FW_CRASHED: firmware has crashed + * @PLD_FW_RECOVERY_START: firmware is starting recovery + * @PLD_FW_HANG_EVENT: firmware update hang event + * @PLD_BUS_EVENT: update bus/link event + * @PLD_SMMU_FAULT: SMMU fault + * @PLD_SYS_REBOOT: system is rebooting + */ +enum pld_uevent { + PLD_FW_DOWN, + PLD_FW_CRASHED, + PLD_FW_RECOVERY_START, + PLD_FW_HANG_EVENT, + PLD_BUS_EVENT, + PLD_SMMU_FAULT, + PLD_SYS_REBOOT, +}; + +/** + * enum pld_bus_event - PLD bus event types + * @PLD_BUS_EVENT_PCIE_LINK_DOWN: PCIe link is down + * @PLD_BUS_EVENT_INVALID: invalid event type + */ + +enum pld_bus_event { + PLD_BUS_EVENT_PCIE_LINK_DOWN = 0, + + PLD_BUS_EVENT_INVALID = 0xFFFF, +}; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * enum pld_device_config - Get PLD device config + * @PLD_IPA_DISABLED: IPA is disabled + */ +enum pld_device_config { + PLD_IPA_DISABLED, +}; +#endif + +/** + * struct pld_uevent_data - uevent status received from platform driver + * @uevent: uevent type + * @fw_down: FW down info + * @hang_data: FW hang data + * @bus_data: bus related data + */ +struct pld_uevent_data { + enum pld_uevent uevent; + union { + struct { + bool crashed; + } fw_down; + struct { + void *hang_event_data; + u16 hang_event_data_len; + } hang_data; + struct { + enum pld_bus_event etype; + void *event_data; + } bus_data; + }; +}; + +/** + * struct pld_ce_tgt_pipe_cfg - copy engine target pipe configuration + * @pipe_num: pipe number + * @pipe_dir: pipe direction + * @nentries: number of entries + * @nbytes_max: max number of bytes + * @flags: flags + * @reserved: reserved + * + * pld_ce_tgt_pipe_cfg is used to store copy engine target pipe + * configuration. + */ +struct pld_ce_tgt_pipe_cfg { + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; + u32 reserved; +}; + +/** + * struct pld_ce_svc_pipe_cfg - copy engine service pipe configuration + * @service_id: service ID + * @pipe_dir: pipe direction + * @pipe_num: pipe number + * + * pld_ce_svc_pipe_cfg is used to store copy engine service pipe + * configuration. + */ +struct pld_ce_svc_pipe_cfg { + u32 service_id; + u32 pipe_dir; + u32 pipe_num; +}; + +/** + * struct pld_shadow_reg_cfg - shadow register configuration + * @ce_id: copy engine ID + * @reg_offset: register offset + * + * pld_shadow_reg_cfg is used to store shadow register configuration. + */ +struct pld_shadow_reg_cfg { + u16 ce_id; + u16 reg_offset; +}; + +/** + * struct pld_shadow_reg_v2_cfg - shadow register version 2 configuration + * @addr: shadow register physical address + * + * pld_shadow_reg_v2_cfg is used to store shadow register version 2 + * configuration. + */ +struct pld_shadow_reg_v2_cfg { + u32 addr; +}; + +#ifdef CONFIG_SHADOW_V3 +struct pld_shadow_reg_v3_cfg { + u32 addr; +}; +#endif + +/** + * struct pld_rri_over_ddr_cfg - rri_over_ddr configuration + * @base_addr_low: lower 32bit + * @base_addr_high: higher 32bit + * + * pld_rri_over_ddr_cfg_s is used in Genoa to pass rri_over_ddr configuration + * to firmware to update ring/write index in host DDR. + */ +struct pld_rri_over_ddr_cfg { + u32 base_addr_low; + u32 base_addr_high; +}; + +/** + * struct pld_wlan_enable_cfg - WLAN FW configuration + * @num_ce_tgt_cfg: number of CE target configuration + * @ce_tgt_cfg: CE target configuration + * @num_ce_svc_pipe_cfg: number of CE service configuration + * @ce_svc_cfg: CE service configuration + * @num_shadow_reg_cfg: number of shadow register configuration + * @shadow_reg_cfg: shadow register configuration + * @num_shadow_reg_v2_cfg: number of shadow register version 2 configuration + * @shadow_reg_v2_cfg: shadow register version 2 configuration + * @rri_over_ddr_cfg_valid: valid flag for rri_over_ddr config + * @rri_over_ddr_cfg: rri over ddr config + * @num_shadow_reg_v3_cfg: number of shadow register version 3 configuration + * @shadow_reg_v3_cfg: shadow register version 3 configuration + * + * pld_wlan_enable_cfg stores WLAN FW configurations. It will be + * passed to WLAN FW when WLAN host driver calls wlan_enable. + */ +struct pld_wlan_enable_cfg { + u32 num_ce_tgt_cfg; + struct pld_ce_tgt_pipe_cfg *ce_tgt_cfg; + u32 num_ce_svc_pipe_cfg; + struct pld_ce_svc_pipe_cfg *ce_svc_cfg; + u32 num_shadow_reg_cfg; + struct pld_shadow_reg_cfg *shadow_reg_cfg; + u32 num_shadow_reg_v2_cfg; + struct pld_shadow_reg_v2_cfg *shadow_reg_v2_cfg; + bool rri_over_ddr_cfg_valid; + struct pld_rri_over_ddr_cfg rri_over_ddr_cfg; +#ifdef CONFIG_SHADOW_V3 + u32 num_shadow_reg_v3_cfg; + struct pld_shadow_reg_v3_cfg *shadow_reg_v3_cfg; +#endif +}; + +/** + * enum pld_driver_mode - WLAN host driver mode + * @PLD_MISSION: mission mode + * @PLD_FTM: FTM mode + * @PLD_EPPING: EPPING mode + * @PLD_WALTEST: WAL test mode, FW standalone test mode + * @PLD_OFF: OFF mode + * @PLD_COLDBOOT_CALIBRATION: Cold Boot Calibration Mode + * @PLD_FTM_COLDBOOT_CALIBRATION: Cold Boot Calibration for FTM Mode + */ +enum pld_driver_mode { + PLD_MISSION, + PLD_FTM, + PLD_EPPING, + PLD_WALTEST, + PLD_OFF, + PLD_COLDBOOT_CALIBRATION = 7, + PLD_FTM_COLDBOOT_CALIBRATION = 10 +}; + +/** + * struct pld_device_version - WLAN device version info + * @family_number: family number of WLAN SOC HW + * @device_number: device number of WLAN SOC HW + * @major_version: major version of WLAN SOC HW + * @minor_version: minor version of WLAN SOC HW + * + * pld_device_version is used to store WLAN device version info + */ + +struct pld_device_version { + u32 family_number; + u32 device_number; + u32 major_version; + u32 minor_version; +}; + +/** + * struct pld_dev_mem_info - WLAN device memory info + * @start: start address of the memory block + * @size: size of the memory block + * + * pld_dev_mem_info is used to store WLAN device memory info + */ +struct pld_dev_mem_info { + u64 start; + u64 size; +}; + +/** + * enum pld_wlan_hw_nss_info - WLAN HW nss info + * @PLD_WLAN_HW_CAP_NSS_UNSPECIFIED: nss info not specified + * @PLD_WLAN_HW_CAP_NSS_1x1: supported nss link 1x1 + * @PLD_WLAN_HW_CAP_NSS_2x2: supported nss link 2x2 + */ +enum pld_wlan_hw_nss_info { + PLD_WLAN_HW_CAP_NSS_UNSPECIFIED, + PLD_WLAN_HW_CAP_NSS_1x1, + PLD_WLAN_HW_CAP_NSS_2x2 +}; + +/** + * enum pld_wlan_hw_channel_bw_info - WLAN HW channel bw info + * @PLD_WLAN_HW_CHANNEL_BW_UNSPECIFIED: bw info not specified + * @PLD_WLAN_HW_CHANNEL_BW_80MHZ: supported bw 80MHZ + * @PLD_WLAN_HW_CHANNEL_BW_160MHZ: supported bw 160MHZ + */ +enum pld_wlan_hw_channel_bw_info { + PLD_WLAN_HW_CHANNEL_BW_UNSPECIFIED, + PLD_WLAN_HW_CHANNEL_BW_80MHZ, + PLD_WLAN_HW_CHANNEL_BW_160MHZ +}; + +/** + * enum pld_wlan_hw_qam_info - WLAN HW qam info + * @PLD_WLAN_HW_QAM_UNSPECIFIED: QAM info not specified + * @PLD_WLAN_HW_QAM_1K: 1K QAM supported + * @PLD_WLAN_HW_QAM_4K: 4K QAM supported + */ +enum pld_wlan_hw_qam_info { + PLD_WLAN_HW_QAM_UNSPECIFIED, + PLD_WLAN_HW_QAM_1K, + PLD_WLAN_HW_QAM_4K +}; + +/** + * struct pld_wlan_hw_cap_info - WLAN HW cap info + * @nss: nss info + * @bw: bw info + * @qam: qam info + */ +struct pld_wlan_hw_cap_info { + enum pld_wlan_hw_nss_info nss; + enum pld_wlan_hw_channel_bw_info bw; + enum pld_wlan_hw_qam_info qam; +}; + +#define PLD_MAX_TIMESTAMP_LEN 32 +#define PLD_WLFW_MAX_BUILD_ID_LEN 128 +#define PLD_MAX_DEV_MEM_NUM 4 + +/** + * struct pld_soc_info - SOC information + * @v_addr: virtual address of preallocated memory + * @p_addr: physical address of preallcoated memory + * @chip_id: chip ID + * @chip_family: chip family + * @board_id: board ID + * @soc_id: SOC ID + * @fw_version: FW version + * @fw_build_timestamp: FW build timestamp + * @device_version: WLAN device version info + * @dev_mem_info: WLAN device memory info + * @fw_build_id: Firmware build identifier + * @hw_cap_info: WLAN HW capabilities info + * + * pld_soc_info is used to store WLAN SOC information. + */ +struct pld_soc_info { + void __iomem *v_addr; + phys_addr_t p_addr; + u32 chip_id; + u32 chip_family; + u32 board_id; + u32 soc_id; + u32 fw_version; + char fw_build_timestamp[PLD_MAX_TIMESTAMP_LEN + 1]; + struct pld_device_version device_version; + struct pld_dev_mem_info dev_mem_info[PLD_MAX_DEV_MEM_NUM]; + char fw_build_id[PLD_WLFW_MAX_BUILD_ID_LEN + 1]; + struct pld_wlan_hw_cap_info hw_cap_info; +}; + +/** + * enum pld_recovery_reason - WLAN host driver recovery reason + * @PLD_REASON_DEFAULT: default + * @PLD_REASON_LINK_DOWN: PCIe link down + */ +enum pld_recovery_reason { + PLD_REASON_DEFAULT, + PLD_REASON_LINK_DOWN +}; + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM +/** + * enum pld_wlan_time_sync_trigger_type - WLAN time sync trigger type + * @PLD_TRIGGER_POSITIVE_EDGE: Positive edge trigger + * @PLD_TRIGGER_NEGATIVE_EDGE: Negative edge trigger + */ +enum pld_wlan_time_sync_trigger_type { + PLD_TRIGGER_POSITIVE_EDGE, + PLD_TRIGGER_NEGATIVE_EDGE +}; +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ + +/* MAX channel avoid ranges supported in PLD */ +#define PLD_CH_AVOID_MAX_RANGE 4 + +/** + * struct pld_ch_avoid_freq_type + * @start_freq: start freq (MHz) + * @end_freq: end freq (Mhz) + */ +struct pld_ch_avoid_freq_type { + uint32_t start_freq; + uint32_t end_freq; +}; + +/** + * struct pld_ch_avoid_ind_type + * @ch_avoid_range_cnt: count + * @avoid_freq_range: avoid freq range array + */ +struct pld_ch_avoid_ind_type { + uint32_t ch_avoid_range_cnt; + struct pld_ch_avoid_freq_type + avoid_freq_range[PLD_CH_AVOID_MAX_RANGE]; +}; + +/** + * struct pld_driver_ops - driver callback functions + * @probe: required operation, will be called when device is detected + * @remove: required operation, will be called when device is removed + * @idle_shutdown: required operation, will be called when device is doing + * idle shutdown after interface inactivity timer has fired + * @idle_restart: required operation, will be called when device is doing + * idle restart after idle shutdown + * @shutdown: optional operation, will be called during SSR + * @reinit: optional operation, will be called during SSR + * @crash_shutdown: optional operation, will be called when a crash is + * detected + * @suspend: required operation, will be called for power management + * is enabled + * @resume: required operation, will be called for power management + * is enabled + * @reset_resume: required operation, will be called for power management + * is enabled + * @modem_status: optional operation, will be called when platform driver + * sending modem power status to WLAN FW + * @uevent: optional operation, will be called when platform driver + * updating driver status + * @collect_driver_dump: optional operation, will be called during SSR to + * collect driver memory dump + * @runtime_suspend: optional operation, prepare the device for a condition + * in which it won't be able to communicate with the CPU(s) + * and RAM due to power management. + * @runtime_resume: optional operation, put the device into the fully + * active state in response to a wakeup event generated by + * hardware or at the request of software. + * @suspend_noirq: optional operation, complete the actions started by suspend() + * @resume_noirq: optional operation, prepare for the execution of resume() + * @set_curr_therm_cdev_state: optional operation, will be called when there is + * change in the thermal level triggered by the thermal + * subsystem thus requiring mitigation actions. This will + * be called every time there is a change in the state + * and after driver load. + */ +struct pld_driver_ops { + int (*probe)(struct device *dev, + enum pld_bus_type bus_type, + void *bdev, void *id); + void (*remove)(struct device *dev, + enum pld_bus_type bus_type); + int (*idle_shutdown)(struct device *dev, + enum pld_bus_type bus_type); + int (*idle_restart)(struct device *dev, + enum pld_bus_type bus_type); + void (*shutdown)(struct device *dev, + enum pld_bus_type bus_type); + int (*reinit)(struct device *dev, + enum pld_bus_type bus_type, + void *bdev, void *id); + void (*crash_shutdown)(struct device *dev, + enum pld_bus_type bus_type); + int (*suspend)(struct device *dev, + enum pld_bus_type bus_type, + pm_message_t state); + int (*resume)(struct device *dev, + enum pld_bus_type bus_type); + int (*reset_resume)(struct device *dev, + enum pld_bus_type bus_type); + void (*modem_status)(struct device *dev, + enum pld_bus_type bus_type, + int state); + void (*uevent)(struct device *dev, struct pld_uevent_data *uevent); +#ifdef WLAN_FEATURE_SSR_DRIVER_DUMP + int (*collect_driver_dump)(struct device *dev, + enum pld_bus_type bus_type, + struct cnss_ssr_driver_dump_entry + *input_array, + size_t *num_entries_loaded); +#endif + int (*runtime_suspend)(struct device *dev, + enum pld_bus_type bus_type); + int (*runtime_resume)(struct device *dev, + enum pld_bus_type bus_type); + int (*suspend_noirq)(struct device *dev, + enum pld_bus_type bus_type); + int (*resume_noirq)(struct device *dev, + enum pld_bus_type bus_type); + int (*set_curr_therm_cdev_state)(struct device *dev, + unsigned long state, + int mon_id); +}; + +/** + * pld_init() - Initialize PLD module + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_init(void); + +/** + * pld_deinit() - Uninitialize PLD module + * + * Return: void + */ +void pld_deinit(void); + +/** + * pld_set_mode() - set driver mode in PLD module + * @mode: driver mode + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_set_mode(u8 mode); + +/** + * pld_register_driver() - Register driver to kernel + * @ops: Callback functions that will be registered to kernel + * + * This function should be called when other modules want to + * register platform driver callback functions to kernel. The + * probe() is expected to be called after registration if the + * device is online. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_register_driver(struct pld_driver_ops *ops); + +/** + * pld_unregister_driver() - Unregister driver to kernel + * + * This function should be called when other modules want to + * unregister callback functions from kernel. The remove() is + * expected to be called after registration. + * + * Return: void + */ +void pld_unregister_driver(void); + +/** + * pld_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode); + +/** + * pld_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode); + +/** + * pld_set_fw_log_mode() - Set FW debug log mode + * @dev: device + * @fw_log_mode: 0 for No log, 1 for WMI, 2 for DIAG + * + * Switch Fw debug log mode between DIAG logging and WMI logging. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_set_fw_log_mode(struct device *dev, u8 fw_log_mode); + +/** + * pld_get_default_fw_files() - Get default FW file names + * @pfw_files: buffer for FW file names + * + * Return default FW file names to the buffer. + * + * Return: void + */ +void pld_get_default_fw_files(struct pld_fw_files *pfw_files); + +/** + * pld_get_fw_files_for_target() - Get FW file names + * @dev: device + * @pfw_files: buffer for FW file names + * @target_type: target type + * @target_version: target version + * + * Return target specific FW file names to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); + +/** + * pld_prevent_l1() - Prevent PCIe enter L1 state + * @dev: device + * + * Prevent PCIe enter L1 and L1ss states + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_prevent_l1(struct device *dev); + +/** + * pld_allow_l1() - Allow PCIe enter L1 state + * @dev: device + * + * Allow PCIe enter L1 and L1ss states + * + * Return: void + */ +void pld_allow_l1(struct device *dev); + +/** + * pld_set_pcie_gen_speed() - Set PCIE gen speed + * @dev: device + * @pcie_gen_speed: Required PCIE gen speed + * + * Send required PCIE Gen speed to platform driver + * + * Return: 0 for success. Negative error codes. + */ +int pld_set_pcie_gen_speed(struct device *dev, u8 pcie_gen_speed); + +/** + * pld_is_pci_link_down() - Notification for pci link down event + * @dev: device + * + * Notify platform that pci link is down. + * + * Return: void + */ +void pld_is_pci_link_down(struct device *dev); + +/** + * pld_get_bus_reg_dump() - Get bus reg dump + * @dev: device + * @buf: buffer for hang data + * @len: len of hang data + * + * Get pci reg dump for hang data. + * + * Return: void + */ +void pld_get_bus_reg_dump(struct device *dev, uint8_t *buf, uint32_t len); + +int pld_shadow_control(struct device *dev, bool enable); + +/** + * pld_schedule_recovery_work() - Schedule recovery work + * @dev: device + * @reason: recovery reason + * + * Schedule a system self recovery work. + * + * Return: void + */ +void pld_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason); + +/** + * pld_wlan_hw_enable() - Enable WLAN HW + * + * This function enables WLAN HW. If WLAN is secured disabled at boot all wlan + * boot time activities are deferred. This is used to run deferred activities + * after wlan is enabled. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_hw_enable(void); + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM +/** + * pld_get_audio_wlan_timestamp() - Get audio timestamp + * @dev: device pointer + * @type: trigger type + * @ts: audio timestamp + * + * This API can be used to get audio timestamp. + * + * Return: 0 if trigger to get audio timestamp is successful + * Non zero failure code for errors + */ +int pld_get_audio_wlan_timestamp(struct device *dev, + enum pld_wlan_time_sync_trigger_type type, + uint64_t *ts); +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ + +#ifdef CNSS_UTILS +#ifdef CNSS_UTILS_VENDOR_UNSAFE_CHAN_API_SUPPORT +/** + * pld_get_wlan_unsafe_channel_sap() - Get vendor unsafe ch freq ranges + * @dev: device + * @ch_avoid_ranges: unsafe freq channel ranges + * + * Get vendor specific unsafe channel frequency ranges + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges); +#else +static inline +int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + return 0; +} +#endif + +/** + * pld_set_wlan_unsafe_channel() - Set unsafe channel + * @dev: device + * @unsafe_ch_list: unsafe channel list + * @ch_count: number of channel + * + * Return: 0 for success + * Non zero failure code for errors + */ +static inline int pld_set_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, + u16 ch_count) +{ + return cnss_utils_set_wlan_unsafe_channel(dev, unsafe_ch_list, + ch_count); +} +/** + * pld_get_wlan_unsafe_channel() - Get unsafe channel + * @dev: device + * @unsafe_ch_list: buffer to unsafe channel list + * @ch_count: number of channel + * @buf_len: buffer length + * + * Return WLAN unsafe channel to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static inline int pld_get_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + return cnss_utils_get_wlan_unsafe_channel(dev, unsafe_ch_list, + ch_count, buf_len); +} +/** + * pld_wlan_set_dfs_nol() - Set DFS info + * @dev: device + * @info: DFS info + * @info_len: info length + * + * Return: 0 for success + * Non zero failure code for errors + */ +static inline int pld_wlan_set_dfs_nol(struct device *dev, void *info, + u16 info_len) +{ + return cnss_utils_wlan_set_dfs_nol(dev, info, info_len); +} +/** + * pld_wlan_get_dfs_nol() - Get DFS info + * @dev: device + * @info: buffer to DFS info + * @info_len: info length + * + * Return DFS info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static inline int pld_wlan_get_dfs_nol(struct device *dev, + void *info, u16 info_len) +{ + return cnss_utils_wlan_get_dfs_nol(dev, info, info_len); +} +/** + * pld_get_wlan_mac_address() - API to query MAC address from Platform + * Driver + * @dev: Device Structure + * @num: Pointer to number of MAC address supported + * + * Platform Driver can have MAC address stored. This API needs to be used + * to get those MAC address + * + * Return: Pointer to the list of MAC address + */ +static inline uint8_t *pld_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + return cnss_utils_get_wlan_mac_address(dev, num); +} + +/** + * pld_get_wlan_derived_mac_address() - API to query derived MAC address + * from platform Driver + * @dev: Device Structure + * @num: Pointer to number of MAC address supported + * + * Platform Driver can have MAC address stored. This API needs to be used + * to get those MAC address + * + * Return: Pointer to the list of MAC address + */ +static inline uint8_t *pld_get_wlan_derived_mac_address(struct device *dev, + uint32_t *num) +{ + return cnss_utils_get_wlan_derived_mac_address(dev, num); +} + +/** + * pld_increment_driver_load_cnt() - Maintain driver load count + * @dev: device + * + * This function maintain a count which get increase whenever wiphy + * is registered + * + * Return: void + */ +static inline void pld_increment_driver_load_cnt(struct device *dev) +{ + cnss_utils_increment_driver_load_cnt(dev); +} +/** + * pld_get_driver_load_cnt() - get driver load count + * @dev: device + * + * This function provide total wiphy registration count from starting + * + * Return: driver load count + */ +static inline int pld_get_driver_load_cnt(struct device *dev) +{ + return cnss_utils_get_driver_load_cnt(dev); +} +#else +static inline int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + return 0; +} + +static inline int pld_set_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, + u16 ch_count) +{ + return 0; +} +static inline int pld_get_wlan_unsafe_channel(struct device *dev, + u16 *unsafe_ch_list, + u16 *ch_count, u16 buf_len) +{ + *ch_count = 0; + + return 0; +} +static inline int pld_wlan_set_dfs_nol(struct device *dev, + void *info, u16 info_len) +{ + return -EINVAL; +} +static inline int pld_wlan_get_dfs_nol(struct device *dev, + void *info, u16 info_len) +{ + return -EINVAL; +} +static inline uint8_t *pld_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} + +static inline uint8_t *pld_get_wlan_derived_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} + +static inline void pld_increment_driver_load_cnt(struct device *dev) {} +static inline int pld_get_driver_load_cnt(struct device *dev) +{ + return -EINVAL; +} +#endif + +/** + * pld_wlan_pm_control() - WLAN PM control on PCIE + * @dev: device + * @vote: 0 for enable PCIE PC, 1 for disable PCIE PC + * + * This is for PCIE power collapse control during suspend/resume. + * When PCIE power collapse is disabled, WLAN FW can access memory + * through PCIE when system is suspended. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_wlan_pm_control(struct device *dev, bool vote); + +/** + * pld_get_virt_ramdump_mem() - Get virtual ramdump memory + * @dev: device + * @size: buffer to virtual memory size + * + * Return: virtual ramdump memory address + */ +void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size); + +/** + * pld_release_virt_ramdump_mem() - Release virtual ramdump memory + * @dev: device + * @address: buffer to virtual memory address + * + * Return: void + */ +void pld_release_virt_ramdump_mem(struct device *dev, void *address); + +/** + * pld_device_crashed() - Notification for device crash event + * @dev: device + * + * Notify subsystem a device crashed event. A subsystem restart + * is expected to happen after calling this function. + * + * Return: void + */ +void pld_device_crashed(struct device *dev); + +/** + * pld_device_self_recovery() - Device self recovery + * @dev: device + * @reason: recovery reason + * + * Return: void + */ +void pld_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason); + +/** + * pld_intr_notify_q6() - Notify Q6 FW interrupts + * @dev: device + * + * Notify Q6 that a FW interrupt is triggered. + * + * Return: void + */ +void pld_intr_notify_q6(struct device *dev); + +/** + * pld_request_pm_qos() - Request system PM + * @dev: device + * @qos_val: request value + * + * It votes for the value of aggregate QoS expectations. + * + * Return: void + */ +void pld_request_pm_qos(struct device *dev, u32 qos_val); + +/** + * pld_remove_pm_qos() - Remove system PM + * @dev: device + * + * Remove the vote request for Qos expectations. + * + * Return: void + */ +void pld_remove_pm_qos(struct device *dev); + +/** + * pld_request_bus_bandwidth() - Request bus bandwidth + * @dev: device + * @bandwidth: bus bandwidth + * + * Votes for HIGH/MEDIUM/LOW bus bandwidth. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_request_bus_bandwidth(struct device *dev, int bandwidth); + +/** + * pld_get_platform_cap() - Get platform capabilities + * @dev: device + * @cap: buffer to the capabilities + * + * Return capabilities to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap); + +/** + * pld_get_sha_hash() - Get sha hash number + * @dev: device + * @data: input data + * @data_len: data length + * @hash_idx: hash index + * @out: output buffer + * + * Return computed hash to the out buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out); + +/** + * pld_get_fw_ptr() - Get secure FW memory address + * @dev: device + * + * Return: secure memory address + */ +void *pld_get_fw_ptr(struct device *dev); + +/** + * pld_auto_suspend() - Auto suspend + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_auto_suspend(struct device *dev); + +/** + * pld_auto_resume() - Auto resume + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_auto_resume(struct device *dev); + +/** + * pld_force_wake_request() - Request vote to assert WAKE register + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_force_wake_request(struct device *dev); + +/** + * pld_is_direct_link_supported() - Get whether direct_link is supported + * by FW or not + * @dev: device + * + * Return: true if supported + * false on failure or if not supported + */ +bool pld_is_direct_link_supported(struct device *dev); + +/** + * pld_force_wake_request_sync() - Request to awake MHI synchronously + * @dev: device + * @timeout_us: timeout in micro-sec request to wake + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_force_wake_request_sync(struct device *dev, int timeout_us); + +/** + * pld_exit_power_save() - Send EXIT_POWER_SAVE QMI to FW + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_exit_power_save(struct device *dev); + +/** + * pld_is_device_awake() - Check if it's ready to access MMIO registers + * @dev: device + * + * Return: True for device awake + * False for device not awake + * Negative failure code for errors + */ +int pld_is_device_awake(struct device *dev); + +/** + * pld_force_wake_release() - Release vote to assert WAKE register + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_force_wake_release(struct device *dev); + +/** + * pld_ce_request_irq() - Register IRQ for CE + * @dev: device + * @ce_id: CE number + * @handler: IRQ callback function + * @flags: IRQ flags + * @name: IRQ name + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ce_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, void *ctx); + +/** + * pld_ce_free_irq() - Free IRQ for CE + * @dev: device + * @ce_id: CE number + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx); + +/** + * pld_enable_irq() - Enable IRQ for CE + * @dev: device + * @ce_id: CE number + * + * Return: void + */ +void pld_enable_irq(struct device *dev, unsigned int ce_id); + +/** + * pld_disable_irq() - Disable IRQ for CE + * @dev: device + * @ce_id: CE number + * + * Return: void + */ +void pld_disable_irq(struct device *dev, unsigned int ce_id); + +/** + * pld_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_get_soc_info(struct device *dev, struct pld_soc_info *info); + +/** + * pld_get_mhi_state() - Get MHI state Info + * @dev: device + * + * MHI state can be determined by reading this address. + * + * Return: MHI state + */ +int pld_get_mhi_state(struct device *dev); + +/** + * pld_is_pci_ep_awake() - Check if PCI EP is L0 state + * @dev: device + * + * Return: True for PCI EP awake + * False for PCI EP not awake + * Negative failure code for errors + */ +int pld_is_pci_ep_awake(struct device *dev); + +/** + * pld_get_ce_id() - Get CE number for the provided IRQ + * @dev: device + * @irq: IRQ number + * + * Return: CE number + */ +int pld_get_ce_id(struct device *dev, int irq); + +/** + * pld_get_irq() - Get IRQ number for given CE ID + * @dev: device + * @ce_id: CE ID + * + * Return: IRQ number + */ +int pld_get_irq(struct device *dev, int ce_id); + +/** + * pld_lock_reg_window() - Lock register window spinlock + * @dev: device pointer + * @flags: variable pointer to save CPU states + * + * It uses spinlock_bh so avoid calling in top half context. + * + * Return: void + */ +void pld_lock_reg_window(struct device *dev, unsigned long *flags); + +/** + * pld_unlock_reg_window() - Unlock register window spinlock + * @dev: device pointer + * @flags: variable pointer to save CPU states + * + * It uses spinlock_bh so avoid calling in top half context. + * + * Return: void + */ +void pld_unlock_reg_window(struct device *dev, unsigned long *flags); + +/** + * pld_get_pci_slot() - Get PCI slot of attached device + * @dev: device + * + * Return: pci slot + */ +int pld_get_pci_slot(struct device *dev); + +/** + * pld_power_on() - Power on WLAN hardware + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_power_on(struct device *dev); + +/** + * pld_power_off() - Power off WLAN hardware + * @dev: device + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_power_off(struct device *dev); + +/** + * pld_athdiag_read() - Read data from WLAN FW + * @dev: device + * @offset: address offset + * @memtype: memory type + * @datalen: data length + * @output: output buffer + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_athdiag_read(struct device *dev, uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *output); + +/** + * pld_athdiag_write() - Write data to WLAN FW + * @dev: device + * @offset: address offset + * @memtype: memory type + * @datalen: data length + * @input: input buffer + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_athdiag_write(struct device *dev, uint32_t offset, uint32_t memtype, + uint32_t datalen, uint8_t *input); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * pld_smmu_get_domain() - Get SMMU domain + * @dev: device + * + * Return: Pointer to the domain + */ +void *pld_smmu_get_domain(struct device *dev); +#else +/** + * pld_smmu_get_mapping() - Get SMMU mapping context + * @dev: device + * + * Return: Pointer to the mapping context + */ +void *pld_smmu_get_mapping(struct device *dev); +#endif + +/** + * pld_smmu_map() - Map SMMU + * @dev: device + * @paddr: physical address that needs to map to + * @iova_addr: IOVA address + * @size: size to be mapped + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +struct kobject *pld_get_wifi_kobj(struct device *dev); +#else +static inline struct kobject *pld_get_wifi_kobj(struct device *dev) +{ + return NULL; +} +#endif + +/** + * pld_smmu_unmap() - Unmap SMMU + * @dev: device + * @iova_addr: IOVA address to be unmapped + * @size: size to be unmapped + * + * Return: 0 for success + * Non zero failure code for errors + */ +#ifdef CONFIG_SMMU_S1_UNMAP +int pld_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size); +#else +static inline int pld_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return 0; +} +#endif + +/** + * pld_get_user_msi_assignment() - Get MSI assignment information + * @dev: device structure + * @user_name: name of the user who requests the MSI assignment + * @num_vectors: number of the MSI vectors assigned for the user + * @user_base_data: MSI base data assigned for the user, this equals to + * endpoint base data from config space plus base vector + * @base_vector: base MSI vector (offset) number assigned for the user + * + * Return: 0 for success + * Negative failure code for errors + */ +int pld_get_user_msi_assignment(struct device *dev, char *user_name, + int *num_vectors, uint32_t *user_base_data, + uint32_t *base_vector); + +/** + * pld_get_msi_irq() - Get MSI IRQ number used for request_irq() + * @dev: device structure + * @vector: MSI vector (offset) number + * + * Return: Positive IRQ number for success + * Negative failure code for errors + */ +int pld_get_msi_irq(struct device *dev, unsigned int vector); + +/** + * pld_get_msi_address() - Get the MSI address + * @dev: device structure + * @msi_addr_low: lower 32-bit of the address + * @msi_addr_high: higher 32-bit of the address + * + * Return: Void + */ +void pld_get_msi_address(struct device *dev, uint32_t *msi_addr_low, + uint32_t *msi_addr_high); + +/** + * pld_is_drv_connected() - Check if DRV subsystem is connected + * @dev: device structure + * + * Return: 1 DRV is connected + * 0 DRV is not connected + * Non zero failure code for errors + */ +int pld_is_drv_connected(struct device *dev); + +/** + * pld_socinfo_get_serial_number() - Get SOC serial number + * @dev: device + * + * Return: SOC serial number + */ +unsigned int pld_socinfo_get_serial_number(struct device *dev); + +/** + * pld_is_qmi_disable() - Check QMI support is present or not + * @dev: device + * + * Return: 1 QMI is not supported + * 0 QMI is supported + * Non zero failure code for errors + */ +int pld_is_qmi_disable(struct device *dev); + +/** + * pld_is_fw_down() - Check WLAN fw is down or not + * + * @dev: device + * + * This API will be called to check if WLAN FW is down or not. + * + * Return: 0 FW is not down + * Otherwise FW is down + * Always return 0 for unsupported bus type + */ +int pld_is_fw_down(struct device *dev); + +/** + * pld_force_assert_target() - Send a force assert request to FW. + * @dev: device pointer + * + * This can use various sideband requests available at platform driver to + * initiate a FW assert. + * + * Context: Any context + * Return: + * 0 - force assert of FW is triggered successfully. + * -EOPNOTSUPP - force assert is not supported. + * Other non-zero codes - other failures or errors + */ +int pld_force_assert_target(struct device *dev); + +/** + * pld_force_collect_target_dump() - Collect FW dump after asserting FW. + * @dev: device pointer + * + * This API will send force assert request to FW and wait till FW dump has + * been collected. + * + * Context: Process context only since this is a blocking call. + * Return: + * 0 - FW dump is collected successfully. + * -EOPNOTSUPP - forcing assert and collecting FW dump is not supported. + * -ETIMEDOUT - FW dump collection is timed out for any reason. + * Other non-zero codes - other failures or errors + */ +int pld_force_collect_target_dump(struct device *dev); + +/** + * pld_qmi_send_get() - Indicate certain data to be sent over QMI + * @dev: device pointer + * + * This API can be used to indicate certain data to be sent over QMI. + * pld_qmi_send() is expected to be called later. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_qmi_send_get(struct device *dev); + +/** + * pld_qmi_send_put() - Indicate response sent over QMI has been processed + * @dev: device pointer + * + * This API can be used to indicate response of the data sent over QMI has + * been processed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_qmi_send_put(struct device *dev); + +/** + * pld_qmi_send() - Send data request over QMI + * @dev: device pointer + * @type: type of the send data operation + * @cmd: buffer pointer of send data request command + * @cmd_len: size of the command buffer + * @cb_ctx: context pointer if any to pass back in callback + * @cb: callback pointer to pass response back + * + * This API can be used to send data request over QMI. + * + * Return: 0 if data request sends successfully + * Non zero failure code for errors + */ +int pld_qmi_send(struct device *dev, int type, void *cmd, + int cmd_len, void *cb_ctx, + int (*cb)(void *ctx, void *event, int event_len)); + +/** + * pld_qmi_indication() - Send data request over QMI + * @dev: device pointer + * @cb_ctx: context pointer if any to pass back in callback + * @cb: callback pointer to pass response back + * + * This API can be used to register for QMI events. + * + * Return: 0 if registration is successful + * Non zero failure code for errors + */ +int pld_qmi_indication(struct device *dev, void *cb_ctx, + int (*cb)(void *ctx, uint16_t type, + void *event, int event_len)); + +/** + * pld_is_fw_dump_skipped() - get fw dump skipped status. + * @dev: device + * + * The subsys ssr status help the driver to decide whether to skip + * the FW memory dump when FW assert. + * For SDIO case, the memory dump progress takes 1 minutes to + * complete, which is not acceptable in SSR enabled. + * + * Return: true if need to skip FW dump. + */ +bool pld_is_fw_dump_skipped(struct device *dev); + +/** + * pld_is_low_power_mode() - Check WLAN fw is in low power + * @dev: device + * + * This API will be called to check if WLAN FW is in low power or not. + * Low power means either Deep Sleep or Hibernate state. + * + * Return: 0 FW is not in low power mode + * Otherwise FW is low power mode + * Always return 0 for unsupported bus type + */ +#ifdef CONFIG_ENABLE_LOW_POWER_MODE +int pld_is_low_power_mode(struct device *dev); +#else +static inline int pld_is_low_power_mode(struct device *dev) +{ + return 0; +} +#endif + +/** + * pld_is_pdr() - Check WLAN PD is Restarted + * @dev: device + * + * Help the driver decide whether FW down is due to + * WLAN PD Restart. + * + * Return: 1 WLAN PD is Restarted + * 0 WLAN PD is not Restarted + */ +int pld_is_pdr(struct device *dev); + +/** + * pld_is_fw_rejuvenate() - Check WLAN fw is rejuvenating + * @dev: device + * + * Help the driver decide whether FW down is due to + * SSR or FW rejuvenate. + * + * Return: 1 FW is rejuvenating + * 0 FW is not rejuvenating + */ +int pld_is_fw_rejuvenate(struct device *dev); + +/** + * pld_have_platform_driver_support() - check if platform driver support + * @dev: device + * + * Return: true if platform driver support. + */ +bool pld_have_platform_driver_support(struct device *dev); + +/** + * pld_idle_shutdown - request idle shutdown callback from platform driver + * @dev: pointer to struct dev + * @shutdown_cb: pointer to hdd psoc idle shutdown callback handler + * + * Return: 0 for success and non-zero negative error code for failure + */ +int pld_idle_shutdown(struct device *dev, + int (*shutdown_cb)(struct device *dev)); + +/** + * pld_idle_restart - request idle restart callback from platform driver + * @dev: pointer to struct dev + * @restart_cb: pointer to hdd psoc idle restart callback handler + * + * Return: 0 for success and non-zero negative error code for failure + */ +int pld_idle_restart(struct device *dev, + int (*restart_cb)(struct device *dev)); + +/** + * pld_srng_devm_request_irq() - Register IRQ for SRNG + * @dev: device + * @irq: IRQ number + * @handler: IRQ callback function + * @irqflags: IRQ flags + * @name: IRQ name + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_srng_devm_request_irq(struct device *dev, int irq, + irq_handler_t handler, + unsigned long irqflags, + const char *name, + void *ctx); + +/** + * pld_srng_request_irq() - Register IRQ for SRNG + * @dev: device + * @irq: IRQ number + * @handler: IRQ callback function + * @irqflags: IRQ flags + * @name: IRQ name + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_srng_request_irq(struct device *dev, int irq, irq_handler_t handler, + unsigned long irqflags, + const char *name, + void *ctx); + +/** + * pld_srng_free_irq() - Free IRQ for SRNG + * @dev: device + * @irq: IRQ number + * @ctx: IRQ context + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_srng_free_irq(struct device *dev, int irq, void *ctx); + +/** + * pld_srng_enable_irq() - Enable IRQ for SRNG + * @dev: device + * @irq: IRQ number + * + * Return: void + */ +void pld_srng_enable_irq(struct device *dev, int irq); + +/** + * pld_srng_disable_irq() - Disable IRQ for SRNG + * @dev: device + * @irq: IRQ number + * + * Return: void + */ +void pld_srng_disable_irq(struct device *dev, int irq); + +/** + * pld_srng_disable_irq_sync() - Synchronouus disable IRQ for SRNG + * @dev: device + * @irq: IRQ number + * + * Return: void + */ +void pld_srng_disable_irq_sync(struct device *dev, int irq); + +/** + * pld_pci_read_config_word() - Read PCI config + * @pdev: pci device + * @offset: Config space offset + * @val : Value + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pci_read_config_word(struct pci_dev *pdev, int offset, uint16_t *val); + +/** + * pld_pci_write_config_word() - Write PCI config + * @pdev: pci device + * @offset: Config space offset + * @val : Value + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pci_write_config_word(struct pci_dev *pdev, int offset, uint16_t val); + +/** + * pld_pci_read_config_dword() - Read PCI config + * @pdev: pci device + * @offset: Config space offset + * @val : Value + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pci_read_config_dword(struct pci_dev *pdev, int offset, uint32_t *val); + +/** + * pld_pci_write_config_dword() - Write PCI config + * @pdev: pci device + * @offset: Config space offset + * @val : Value + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pci_write_config_dword(struct pci_dev *pdev, int offset, uint32_t val); + +/** + * pld_thermal_register() - Register the thermal device with the thermal system + * @dev: The device structure + * @state: The max state to be configured on registration + * @mon_id: Thermal cooling device ID + * + * Return: Error code on error + */ +int pld_thermal_register(struct device *dev, unsigned long state, int mon_id); + +/** + * pld_thermal_unregister() - Unregister the device with the thermal system + * @dev: The device structure + * @mon_id: Thermal cooling device ID + * + * Return: None + */ +void pld_thermal_unregister(struct device *dev, int mon_id); + +/** + * pld_set_wfc_mode() - Sent WFC mode to FW via platform driver + * @dev: The device structure + * @wfc_mode: WFC Modes (0 => Inactive, 1 => Active) + * + * Return: Error code on error + */ +int pld_set_wfc_mode(struct device *dev, enum pld_wfc_mode wfc_mode); + +/** + * pld_bus_width_type_to_str() - Helper function to convert PLD bandwidth level + * to string + * @level: PLD bus width level + * + * Return: String corresponding to input "level" + */ +const char *pld_bus_width_type_to_str(enum pld_bus_width_type level); + +/** + * pld_get_thermal_state() - Get the current thermal state from the PLD + * @dev: The device structure + * @thermal_state: param to store the current thermal state + * @mon_id: Thermal cooling device ID + * + * Return: Non-zero code for error; zero for success + */ +int pld_get_thermal_state(struct device *dev, unsigned long *thermal_state, + int mon_id); + +/** + * pld_set_tsf_sync_period() - Set TSF sync period + * @dev: device + * @val: TSF sync time value + * + * Return: void + */ +void pld_set_tsf_sync_period(struct device *dev, u32 val); + +/** + * pld_reset_tsf_sync_period() - Reset TSF sync period + * @dev: device + * + * Return: void + */ +void pld_reset_tsf_sync_period(struct device *dev); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * pld_is_ipa_offload_disabled() - Check if IPA offload is enabled or not + * @dev: The device structure + * + * Return: Non-zero code for IPA offload disable; zero for IPA offload enable + */ +int pld_is_ipa_offload_disabled(struct device *dev); +#else +static inline +int pld_is_ipa_offload_disabled(struct device *dev) +{ + return 0; +} +#endif + +#if defined(CNSS_MEM_PRE_ALLOC) && defined(FEATURE_SKB_PRE_ALLOC) + +/** + * pld_nbuf_pre_alloc() - get allocated nbuf from platform driver. + * @size: Netbuf requested size + * + * Return: nbuf or NULL if no memory + */ +static inline struct sk_buff *pld_nbuf_pre_alloc(size_t size) +{ + struct sk_buff *skb = NULL; + + if (size >= WCNSS_PRE_SKB_ALLOC_GET_THRESHOLD) + skb = wcnss_skb_prealloc_get(size); + + return skb; +} + +/** + * pld_nbuf_pre_alloc_free() - free the nbuf allocated in platform driver. + * @skb: Pointer to network buffer + * + * Return: TRUE if the nbuf is freed + */ +static inline int pld_nbuf_pre_alloc_free(struct sk_buff *skb) +{ + return wcnss_skb_prealloc_put(skb); +} +#else +static inline struct sk_buff *pld_nbuf_pre_alloc(size_t size) +{ + return NULL; +} +static inline int pld_nbuf_pre_alloc_free(struct sk_buff *skb) +{ + return 0; +} +#endif + +#ifdef CONFIG_AFC_SUPPORT +/** + * pld_send_buffer_to_afcmem() - Send afc data to afc memory + * @dev: The device structure + * @afcdb: Pointer to afc data buffer + * @len: Length of afc data + * @slotid: Slot id of afc memory + * + * Return: Non-zero code for error; zero for success + */ +int pld_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb, + uint32_t len, uint8_t slotid); + +/** + * pld_reset_afcmem() - Reset afc data in afc memory + * @dev: The device structure + * @slotid: Slot id of afc memory + * + * Return: Non-zero code for error; zero for success + */ +int pld_reset_afcmem(struct device *dev, uint8_t slotid); +#else +static inline +int pld_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb, + uint32_t len, uint8_t slotid) +{ + return -EINVAL; +} + +static inline +int pld_reset_afcmem(struct device *dev, uint8_t slotid) +{ + return -EINVAL; +} +#endif + +/** + * pld_get_bus_type() - Bus type of the device + * @dev: device + * + * Return: PLD bus type + */ +enum pld_bus_type pld_get_bus_type(struct device *dev); + +static inline int pfrm_devm_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, + void *ctx) +{ + return pld_srng_devm_request_irq(dev, ce_id, handler, flags, name, ctx); +} + +static inline int pfrm_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, + void *ctx) +{ + return pld_srng_request_irq(dev, ce_id, handler, flags, name, ctx); +} + +static inline int pfrm_free_irq(struct device *dev, int irq, void *ctx) +{ + return pld_srng_free_irq(dev, irq, ctx); +} + +static inline void pfrm_enable_irq(struct device *dev, int irq) +{ + pld_srng_enable_irq(dev, irq); +} + +static inline void pfrm_disable_irq_nosync(struct device *dev, int irq) +{ + pld_srng_disable_irq(dev, irq); +} + +static inline void pfrm_disable_irq(struct device *dev, int irq) +{ + pld_srng_disable_irq_sync(dev, irq); +} + +static inline int pfrm_read_config_word(struct pci_dev *pdev, int offset, + uint16_t *val) +{ + return pld_pci_read_config_word(pdev, offset, val); +} + +static inline int pfrm_write_config_word(struct pci_dev *pdev, int offset, + uint16_t val) +{ + return pld_pci_write_config_word(pdev, offset, val); +} + +static inline int pfrm_read_config_dword(struct pci_dev *pdev, int offset, + uint32_t *val) +{ + return pld_pci_read_config_dword(pdev, offset, val); +} + +static inline int pfrm_write_config_dword(struct pci_dev *pdev, int offset, + uint32_t val) +{ + return pld_pci_write_config_dword(pdev, offset, val); +} + +static inline bool pld_get_enable_intx(struct device *dev) +{ + return false; +} + +/** + * pld_is_one_msi()- whether one MSI is used or not + * @dev: device structure + * + * Return: true if it is one MSI + */ +bool pld_is_one_msi(struct device *dev); + +#ifdef FEATURE_DIRECT_LINK +/** + * pld_audio_smmu_map()- Map memory region into Audio SMMU CB + * @dev: pointer to device structure + * @paddr: physical address + * @iova: DMA address + * @size: memory region size + * + * Return: 0 on success else failure code + */ +int pld_audio_smmu_map(struct device *dev, phys_addr_t paddr, dma_addr_t iova, + size_t size); + +/** + * pld_audio_smmu_unmap()- Remove memory region mapping from Audio SMMU CB + * @dev: pointer to device structure + * @iova: DMA address + * @size: memory region size + * + * Return: None + */ +void pld_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size); +#else +static inline +int pld_audio_smmu_map(struct device *dev, phys_addr_t paddr, dma_addr_t iova, + size_t size) +{ + return 0; +} + +static inline +void pld_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_common.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_common.c new file mode 100644 index 0000000000..970d47cdab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_common.c @@ -0,0 +1,2849 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#define pr_fmt(fmt) "wlan_pld:%s:%d:: " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLD_SDIO_CNSS +#include +#endif +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss2.h" +#else +#include +#endif +#endif + +#ifdef CONFIG_CNSS_OUT_OF_TREE +#ifdef CONFIG_PLD_SNOC_ICNSS +#ifdef CONFIG_PLD_SNOC_ICNSS2 +#include "icnss2.h" +#else +#include "icnss.h" +#endif +#endif +#ifdef CONFIG_PLD_IPCI_ICNSS +#include "icnss2.h" +#endif +#else +#ifdef CONFIG_PLD_SNOC_ICNSS +#ifdef CONFIG_PLD_SNOC_ICNSS2 +#include +#else +#include +#endif +#endif +#ifdef CONFIG_PLD_IPCI_ICNSS +#include +#endif +#endif + +#include "pld_pcie.h" +#include "pld_ipci.h" +#include "pld_pcie_fw_sim.h" +#include "pld_snoc_fw_sim.h" +#include "pld_snoc.h" +#include "pld_sdio.h" +#include "pld_usb.h" +#include "qwlan_version.h" + +#define PLD_PCIE_REGISTERED BIT(0) +#define PLD_SNOC_REGISTERED BIT(1) +#define PLD_SDIO_REGISTERED BIT(2) +#define PLD_USB_REGISTERED BIT(3) +#define PLD_SNOC_FW_SIM_REGISTERED BIT(4) +#define PLD_PCIE_FW_SIM_REGISTERED BIT(5) +#define PLD_IPCI_REGISTERED BIT(6) + +#define PLD_BUS_MASK 0xf + +static struct pld_context *pld_ctx; + +int pld_init(void) +{ + struct pld_context *pld_context; + + pld_context = kzalloc(sizeof(*pld_context), GFP_KERNEL); + if (!pld_context) + return -ENOMEM; + + spin_lock_init(&pld_context->pld_lock); + + INIT_LIST_HEAD(&pld_context->dev_list); + + pld_ctx = pld_context; + + return 0; +} + +void pld_deinit(void) +{ + struct dev_node *dev_node; + struct pld_context *pld_context; + unsigned long flags; + + pld_context = pld_ctx; + if (!pld_context) { + pld_ctx = NULL; + return; + } + + spin_lock_irqsave(&pld_context->pld_lock, flags); + while (!list_empty(&pld_context->dev_list)) { + dev_node = list_first_entry(&pld_context->dev_list, + struct dev_node, list); + list_del(&dev_node->list); + kfree(dev_node); + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + kfree(pld_context); + + pld_ctx = NULL; +} + +int pld_set_mode(u8 mode) +{ + if (!pld_ctx) + return -ENOMEM; + + pld_ctx->mode = mode; + return 0; +} + +struct pld_context *pld_get_global_context(void) +{ + return pld_ctx; +} + +int pld_add_dev(struct pld_context *pld_context, + struct device *dev, struct device *ifdev, + enum pld_bus_type type) +{ + unsigned long flags; + struct dev_node *dev_node; + + dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL); + if (!dev_node) + return -ENOMEM; + + dev_node->dev = dev; + dev_node->ifdev = ifdev; + dev_node->bus_type = type; + + spin_lock_irqsave(&pld_context->pld_lock, flags); + list_add_tail(&dev_node->list, &pld_context->dev_list); + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + return 0; +} + +void pld_del_dev(struct pld_context *pld_context, + struct device *dev) +{ + unsigned long flags; + struct dev_node *dev_node, *tmp; + + spin_lock_irqsave(&pld_context->pld_lock, flags); + list_for_each_entry_safe(dev_node, tmp, &pld_context->dev_list, list) { + if (dev_node->dev == dev) { + list_del(&dev_node->list); + kfree(dev_node); + } + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); +} + +static struct dev_node *pld_get_dev_node(struct device *dev) +{ + struct pld_context *pld_context; + struct dev_node *dev_node; + unsigned long flags; + + pld_context = pld_get_global_context(); + + if (!dev || !pld_context) { + pr_err("Invalid info: dev %pK, context %pK\n", + dev, pld_context); + return NULL; + } + + spin_lock_irqsave(&pld_context->pld_lock, flags); + list_for_each_entry(dev_node, &pld_context->dev_list, list) { + if (dev_node->dev == dev) { + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + return dev_node; + } + } + spin_unlock_irqrestore(&pld_context->pld_lock, flags); + + return NULL; +} + +enum pld_bus_type pld_get_bus_type(struct device *dev) +{ + struct dev_node *dev_node = pld_get_dev_node(dev); + + if (dev_node) + return dev_node->bus_type; + else + return PLD_BUS_TYPE_NONE; +} + +/** + * pld_get_if_dev() - Bus interface/pipe dev of the device + * @dev: device + * + * Return: Bus sub-interface or pipe dev. + */ +static struct device *pld_get_if_dev(struct device *dev) +{ + struct dev_node *dev_node = pld_get_dev_node(dev); + + if (dev_node) + return dev_node->ifdev; + else + return NULL; +} + +int pld_register_driver(struct pld_driver_ops *ops) +{ + int ret = 0; + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) { + pr_err("global context is NULL\n"); + ret = -ENODEV; + goto out; + } + + if (pld_context->ops) { + pr_err("driver already registered\n"); + ret = -EEXIST; + goto out; + } + + if (!ops || !ops->probe || !ops->remove || + !ops->suspend || !ops->resume) { + pr_err("Required callback functions are missing\n"); + ret = -EINVAL; + goto out; + } + + pld_context->ops = ops; + pld_context->pld_driver_state = 0; + + ret = pld_pcie_register_driver(); + if (ret) { + pld_err_rl("Fail to register pcie driver\n"); + goto fail_pcie; + } + pld_context->pld_driver_state |= PLD_PCIE_REGISTERED; + + ret = pld_snoc_register_driver(); + if (ret) { + pld_err_rl("Fail to register snoc driver\n"); + goto fail_snoc; + } + pld_context->pld_driver_state |= PLD_SNOC_REGISTERED; + + ret = pld_sdio_register_driver(); + if (ret) { + pr_err("Fail to register sdio driver\n"); + goto fail_sdio; + } + pld_context->pld_driver_state |= PLD_SDIO_REGISTERED; + + ret = pld_snoc_fw_sim_register_driver(); + if (ret) { + pr_err("Fail to register snoc fw sim driver\n"); + goto fail_snoc_fw_sim; + } + pld_context->pld_driver_state |= PLD_SNOC_FW_SIM_REGISTERED; + + ret = pld_pcie_fw_sim_register_driver(); + if (ret) { + pr_err("Fail to register pcie fw sim driver\n"); + goto fail_pcie_fw_sim; + } + pld_context->pld_driver_state |= PLD_PCIE_FW_SIM_REGISTERED; + + ret = pld_usb_register_driver(); + if (ret) { + pr_err("Fail to register usb driver\n"); + goto fail_usb; + } + pld_context->pld_driver_state |= PLD_USB_REGISTERED; + + ret = pld_ipci_register_driver(); + if (ret) { + pld_err_rl("Fail to register ipci driver\n"); + goto fail_ipci; + } + pld_context->pld_driver_state |= PLD_IPCI_REGISTERED; + + return ret; + +fail_ipci: + pld_usb_unregister_driver(); +fail_usb: + pld_pcie_fw_sim_unregister_driver(); +fail_pcie_fw_sim: + pld_snoc_fw_sim_unregister_driver(); +fail_snoc_fw_sim: + pld_sdio_unregister_driver(); +fail_sdio: + pld_snoc_unregister_driver(); +fail_snoc: + pld_pcie_unregister_driver(); +fail_pcie: + pld_context->pld_driver_state = 0; + pld_context->ops = NULL; +out: + return ret; +} + +void pld_unregister_driver(void) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) { + pr_err("global context is NULL\n"); + return; + } + + if (!pld_context->ops) { + pr_err("driver not registered\n"); + return; + } + + pld_pcie_unregister_driver(); + pld_snoc_fw_sim_unregister_driver(); + pld_pcie_fw_sim_unregister_driver(); + pld_snoc_unregister_driver(); + pld_sdio_unregister_driver(); + pld_usb_unregister_driver(); + pld_ipci_unregister_driver(); + + pld_context->pld_driver_state = 0; + + pld_context->ops = NULL; +} + +int pld_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode) +{ + int ret = 0; + struct device *ifdev; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_wlan_enable(dev, config, mode, + QWLAN_VERSIONSTR); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_wlan_enable(dev, config, mode, + QWLAN_VERSIONSTR); + break; + case PLD_BUS_TYPE_SDIO: + ret = pld_sdio_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); + break; + case PLD_BUS_TYPE_USB: + ifdev = pld_get_if_dev(dev); + ret = pld_usb_wlan_enable(ifdev, config, mode, + QWLAN_VERSIONSTR); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_wlan_enable(dev, config, mode, QWLAN_VERSIONSTR); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_disable(dev, mode); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_wlan_disable(dev, mode); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_wlan_disable(dev, mode); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_wlan_disable(dev, mode); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_wlan_disable(dev, mode); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_wlan_hw_enable(void) +{ + return pld_pcie_wlan_hw_enable(); +} + +int pld_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_set_fw_log_mode(dev, fw_log_mode); + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_set_fw_log_mode(dev, fw_log_mode); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_set_fw_log_mode(dev, fw_log_mode); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +void pld_get_default_fw_files(struct pld_fw_files *pfw_files) +{ + memset(pfw_files, 0, sizeof(*pfw_files)); + + strlcpy(pfw_files->image_file, PREFIX PLD_IMAGE_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->board_data, PREFIX PLD_BOARD_DATA_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->otp_data, PREFIX PLD_OTP_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_file, PREFIX PLD_UTF_FIRMWARE_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->utf_board_data, PREFIX PLD_BOARD_DATA_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->epping_file, PREFIX PLD_EPPING_FILE, + PLD_MAX_FILE_NAME); + strlcpy(pfw_files->setup_file, PREFIX PLD_SETUP_FILE, + PLD_MAX_FILE_NAME); +} + +int pld_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_fw_files_for_target(dev, pfw_files, + target_type, + target_version); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + ret = pld_sdio_get_fw_files_for_target(pfw_files, + target_type, + target_version); + break; + case PLD_BUS_TYPE_USB: + ret = pld_usb_get_fw_files_for_target(pfw_files, + target_type, + target_version); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_prevent_l1(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_prevent_l1(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_prevent_l1(dev); + break; + default: + ret = -EINVAL; + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +void pld_allow_l1(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_allow_l1(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + case PLD_BUS_TYPE_IPCI: + pld_ipci_allow_l1(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +int pld_get_mhi_state(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + ret = PLD_MHI_STATE_L0; + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_mhi_state(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + return ret; +} + +int pld_set_pcie_gen_speed(struct device *dev, u8 pcie_gen_speed) +{ + int ret = -EINVAL; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_set_gen_speed(dev, pcie_gen_speed); + break; + default: + pr_err("Invalid device type\n"); + break; + } + return ret; +} + +void pld_is_pci_link_down(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + pld_pcie_link_down(dev); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_get_bus_reg_dump(struct device *dev, uint8_t *buf, uint32_t len) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + pld_pcie_get_reg_dump(dev, buf, len); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_schedule_recovery_work(dev, reason); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +int pld_wlan_pm_control(struct device *dev, bool vote) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_wlan_pm_control(dev, vote); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +void *pld_get_virt_ramdump_mem(struct device *dev, unsigned long *size) +{ + void *mem = NULL; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + mem = pld_pcie_get_virt_ramdump_mem(dev, size); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + mem = pld_sdio_get_virt_ramdump_mem(dev, size); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return mem; +} + +void pld_release_virt_ramdump_mem(struct device *dev, void *address) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_release_virt_ramdump_mem(address); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + pld_sdio_release_virt_ramdump_mem(address); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_device_crashed(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_device_crashed(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + pld_sdio_device_crashed(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_device_self_recovery(dev, reason); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + pld_sdio_device_self_recovery(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_intr_notify_q6(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_intr_notify_q6(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_request_pm_qos(struct device *dev, u32 qos_val) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_request_pm_qos(dev, qos_val); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_remove_pm_qos(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_remove_pm_qos(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +int pld_request_bus_bandwidth(struct device *dev, int bandwidth) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_request_bus_bandwidth(dev, bandwidth); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + /* To do Add call cns API */ + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +bool pld_is_direct_link_supported(struct device *dev) +{ + bool ret = false; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_is_direct_link_supported(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + case PLD_BUS_TYPE_SDIO: + default: + break; + } + + return ret; +} + +int pld_get_platform_cap(struct device *dev, struct pld_platform_cap *cap) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_platform_cap(dev, cap); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_get_platform_cap(dev, cap); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_sha_hash(dev, data, data_len, + hash_idx, out); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +void *pld_get_fw_ptr(struct device *dev) +{ + void *ptr = NULL; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ptr = pld_pcie_get_fw_ptr(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ptr; +} + +int pld_auto_suspend(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_auto_suspend(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_auto_resume(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_auto_resume(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_force_wake_request(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_force_wake_request(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_force_wake_request(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_force_wake_request_sync(struct device *dev, int timeout_us) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_force_wake_request_sync(dev, timeout_us); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_exit_power_save(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_exit_power_save(dev); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_exit_power_save(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_is_device_awake(struct device *dev) +{ + int ret = true; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_is_device_awake(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_is_device_awake(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_is_pci_ep_awake(struct device *dev) +{ + int ret = true; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + ret = -ENOTSUPP; + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_is_pci_ep_awake(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_force_wake_release(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_force_wake_release(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_force_wake_release(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_ce_request_irq(struct device *dev, unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, const char *name, void *ctx) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_ce_request_irq(dev, ce_id, + handler, flags, name, ctx); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_ce_request_irq(dev, ce_id, + handler, flags, name, ctx); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_ce_free_irq(struct device *dev, unsigned int ce_id, void *ctx) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_ce_free_irq(dev, ce_id, ctx); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_ce_free_irq(dev, ce_id, ctx); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_PCIE: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +void pld_enable_irq(struct device *dev, unsigned int ce_id) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + pld_snoc_enable_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + pld_snoc_fw_sim_enable_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_disable_irq(struct device *dev, unsigned int ce_id) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + pld_snoc_disable_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + pld_snoc_fw_sim_disable_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +int pld_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int ret = 0; + memset(info, 0, sizeof(*info)); + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_soc_info(dev, info); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_get_soc_info(dev, info); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_get_soc_info(dev, info); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_soc_info(dev, info); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_get_soc_info(dev, info); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_get_ce_id(struct device *dev, int irq) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_ce_id(dev, irq); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_get_ce_id(dev, irq); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_ce_id(dev, irq); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_get_irq(struct device *dev, int ce_id) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_get_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_get_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_get_irq(dev, ce_id); + break; + case PLD_BUS_TYPE_PCIE: + default: + ret = -EINVAL; + break; + } + + return ret; +} + +void pld_lock_reg_window(struct device *dev, unsigned long *flags) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_lock_reg_window(dev, flags); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_unlock_reg_window(struct device *dev, unsigned long *flags) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_unlock_reg_window(dev, flags); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +int pld_get_pci_slot(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_pci_slot(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_power_on(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + /* cnss platform driver handles PCIe SoC + * power on/off sequence so let CNSS driver + * handle the power on sequence for PCIe SoC + */ + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_power_on(dev); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_power_on(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_power_off(struct device *dev) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + /* cnss platform driver handles PCIe SoC + * power on/off sequence so let CNSS driver + * handle the power off sequence for PCIe SoC + */ + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_power_off(dev); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_power_off(dev); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_athdiag_read(dev, offset, memtype, + datalen, output); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_athdiag_read(dev, offset, memtype, + datalen, output); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + ret = pld_usb_athdiag_read(dev, offset, memtype, + datalen, output); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_athdiag_read(dev, offset, memtype, + datalen, output); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + int ret = 0; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_athdiag_write(dev, offset, memtype, + datalen, input); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_athdiag_write(dev, offset, memtype, + datalen, input); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + ret = pld_usb_athdiag_write(dev, offset, memtype, + datalen, input); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_athdiag_write(dev, offset, memtype, + datalen, input); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +void *pld_smmu_get_domain(struct device *dev) +{ + void *ptr = NULL; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ptr = pld_snoc_smmu_get_domain(dev); + break; + case PLD_BUS_TYPE_PCIE: + ptr = pld_pcie_smmu_get_domain(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + ptr = pld_ipci_smmu_get_domain(dev); + break; + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ptr; +} +#else +void *pld_smmu_get_mapping(struct device *dev) +{ + void *ptr = NULL; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ptr = pld_snoc_smmu_get_mapping(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_PCIE: + ptr = pld_pcie_smmu_get_mapping(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ptr; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +struct kobject *pld_get_wifi_kobj(struct device *dev) +{ + struct kobject *wifi_kobj = NULL; + + wifi_kobj = pld_pcie_get_wifi_kobj(dev); + + return wifi_kobj; +} +#endif + +int pld_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_smmu_map(dev, paddr, iova_addr, size); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_smmu_map(dev, paddr, iova_addr, size); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_smmu_map(dev, paddr, iova_addr, size); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +#ifdef CONFIG_SMMU_S1_UNMAP +int pld_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_smmu_unmap(dev, iova_addr, size); + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_smmu_unmap(dev, iova_addr, size); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_smmu_unmap(dev, iova_addr, size); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} +#endif + +int pld_get_user_msi_assignment(struct device *dev, char *user_name, + int *num_vectors, uint32_t *user_base_data, + uint32_t *base_vector) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_user_msi_assignment(dev, user_name, + num_vectors, + user_base_data, + base_vector); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_get_user_msi_assignment(dev, user_name, + num_vectors, + user_base_data, + base_vector); + break; + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_get_user_msi_assignment(dev, user_name, + num_vectors, + user_base_data, + base_vector); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_srng_devm_request_irq(struct device *dev, int irq, + irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_data) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = devm_request_irq(dev, irq, handler, irqflags, + devname, dev_data); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_request_irq(dev, irq, handler, + irqflags, devname, + dev_data); + break; + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + case PLD_BUS_TYPE_IPCI: + ret = devm_request_irq(dev, irq, handler, irqflags, + devname, dev_data); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_srng_request_irq(struct device *dev, int irq, irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_data) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = request_irq(irq, handler, irqflags, devname, dev_data); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_request_irq(dev, irq, handler, + irqflags, devname, + dev_data); + break; + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + case PLD_BUS_TYPE_IPCI: + ret = request_irq(irq, handler, irqflags, devname, dev_data); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_srng_free_irq(struct device *dev, int irq, void *dev_data) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + free_irq(irq, dev_data); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_free_irq(dev, irq, dev_data); + break; + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + case PLD_BUS_TYPE_IPCI: + free_irq(irq, dev_data); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +void pld_srng_enable_irq(struct device *dev, int irq) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + pld_pcie_fw_sim_enable_irq(dev, irq); + break; + case PLD_BUS_TYPE_PCIE: + enable_irq(irq); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + enable_irq(irq); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_srng_disable_irq(struct device *dev, int irq) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + pld_pcie_fw_sim_disable_irq(dev, irq); + break; + case PLD_BUS_TYPE_PCIE: + disable_irq_nosync(irq); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + disable_irq_nosync(irq); + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_srng_disable_irq_sync(struct device *dev, int irq) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + pld_pcie_fw_sim_disable_irq(dev, irq); + break; + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_IPCI: + disable_irq(irq); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +int pld_pci_read_config_word(struct pci_dev *pdev, int offset, uint16_t *val) +{ + int ret = 0; + + switch (pld_get_bus_type(&pdev->dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_read_config_word(&pdev->dev, offset, val); + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_PCIE: + ret = pci_read_config_word(pdev, offset, val); + break; + case PLD_BUS_TYPE_SDIO: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_pci_write_config_word(struct pci_dev *pdev, int offset, uint16_t val) +{ + int ret = 0; + + switch (pld_get_bus_type(&pdev->dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + ret = pci_write_config_word(pdev, offset, val); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_pci_read_config_dword(struct pci_dev *pdev, int offset, uint32_t *val) +{ + int ret = 0; + + switch (pld_get_bus_type(&pdev->dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + ret = pci_read_config_dword(pdev, offset, val); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_pci_write_config_dword(struct pci_dev *pdev, int offset, uint32_t val) +{ + int ret = 0; + + switch (pld_get_bus_type(&pdev->dev)) { + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + ret = pci_write_config_dword(pdev, offset, val); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_get_msi_irq(struct device *dev, unsigned int vector) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_get_msi_irq(dev, vector); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = pld_pcie_fw_sim_get_msi_irq(dev, vector); + break; + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + ret = -ENODEV; + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_get_msi_irq(dev, vector); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +void pld_get_msi_address(struct device *dev, uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_get_msi_address(dev, msi_addr_low, msi_addr_high); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + pld_pcie_fw_sim_get_msi_address(dev, msi_addr_low, + msi_addr_high); + break; + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + pr_err("Not supported on type %d\n", type); + break; + case PLD_BUS_TYPE_IPCI: + pld_ipci_get_msi_address(dev, msi_addr_low, msi_addr_high); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } +} + +int pld_is_drv_connected(struct device *dev) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + int ret = 0; + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_is_drv_connected(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +unsigned int pld_socinfo_get_serial_number(struct device *dev) +{ + unsigned int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_socinfo_get_serial_number(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_PCIE: + pr_err("Not supported on type %d\n", type); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return ret; +} + +int pld_is_qmi_disable(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_is_qmi_disable(dev); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SDIO: + pr_err("Not supported on type %d\n", type); + ret = -EINVAL; + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +int pld_is_fw_down(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + struct device *ifdev; + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_is_fw_down(dev); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + ret = pld_snoc_fw_sim_is_fw_down(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_is_fw_down(dev); + break; + case PLD_BUS_TYPE_SDIO: + break; + case PLD_BUS_TYPE_USB: + ifdev = pld_get_if_dev(dev); + ret = pld_usb_is_fw_down(ifdev); + break; + case PLD_BUS_TYPE_IPCI: + ret = pld_ipci_is_fw_down(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +#ifdef CONFIG_ENABLE_LOW_POWER_MODE +int pld_is_low_power_mode(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_is_low_power_mode(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_IPCI: + default: + break; + } + return ret; +} +#endif + +int pld_force_assert_target(struct device *dev) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + return pld_snoc_force_assert_target(dev); + case PLD_BUS_TYPE_PCIE: + return pld_pcie_force_assert_target(dev); + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + return -EOPNOTSUPP; + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SDIO: + return -EINVAL; + case PLD_BUS_TYPE_IPCI: + return pld_ipci_force_assert_target(dev); + default: + pr_err("Invalid device type %d\n", type); + return -EINVAL; + } +} + +int pld_force_collect_target_dump(struct device *dev) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + return pld_pcie_collect_rddm(dev); + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + return -EOPNOTSUPP; + default: + pr_err("Invalid device type %d\n", type); + return -EINVAL; + } +} + +int pld_qmi_send_get(struct device *dev) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + return pld_pcie_qmi_send_get(dev); + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + return 0; + default: + pr_err("Invalid device type %d\n", type); + return -EINVAL; + } +} + +int pld_qmi_send_put(struct device *dev) +{ + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + return pld_pcie_qmi_send_put(dev); + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + return 0; + default: + pr_err("Invalid device type %d\n", type); + return -EINVAL; + } +} + +int pld_qmi_send(struct device *dev, int type, void *cmd, + int cmd_len, void *cb_ctx, + int (*cb)(void *ctx, void *event, int event_len)) +{ + enum pld_bus_type bus_type = pld_get_bus_type(dev); + + switch (bus_type) { + case PLD_BUS_TYPE_PCIE: + return pld_pcie_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb); + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + return -EINVAL; + case PLD_BUS_TYPE_IPCI: + return pld_ipci_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb); + default: + pr_err("Invalid device type %d\n", bus_type); + return -EINVAL; + } +} + +int pld_qmi_indication(struct device *dev, void *cb_ctx, + int (*cb)(void *ctx, uint16_t type, + void *event, int event_len)) +{ + enum pld_bus_type bus_type = pld_get_bus_type(dev); + + switch (bus_type) { + case PLD_BUS_TYPE_PCIE: + return pld_pcie_register_qmi_ind(dev, cb_ctx, cb); + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + return -EINVAL; + default: + pr_err("Invalid device type %d\n", bus_type); + return -EINVAL; + } +} + +bool pld_is_fw_dump_skipped(struct device *dev) +{ + bool ret = false; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SDIO: + ret = pld_sdio_is_fw_dump_skipped(); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_IPCI: + default: + break; + } + return ret; +} + +int pld_is_pdr(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_is_pdr(); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_IPCI: + default: + break; + } + return ret; +} + +int pld_is_fw_rejuvenate(struct device *dev) +{ + int ret = 0; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_is_fw_rejuvenate(); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_IPCI: + default: + break; + } + return ret; +} + +bool pld_have_platform_driver_support(struct device *dev) +{ + bool ret = false; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_platform_driver_support(); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + ret = true; + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_IPCI: + ret = true; + break; + case PLD_BUS_TYPE_SDIO: + ret = pld_sdio_platform_driver_support(); + break; + default: + pr_err("Invalid device type\n"); + break; + } + + return ret; +} + +int pld_idle_shutdown(struct device *dev, + int (*shutdown_cb)(struct device *dev)) +{ + int errno = -EINVAL; + enum pld_bus_type type; + + if (!shutdown_cb) + return -EINVAL; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + errno = shutdown_cb(dev); + break; + case PLD_BUS_TYPE_SNOC: + errno = pld_snoc_idle_shutdown(dev); + break; + case PLD_BUS_TYPE_PCIE: + errno = pld_pcie_idle_shutdown(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + errno = pld_pcie_fw_sim_idle_shutdown(dev); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + errno = pld_snoc_fw_sim_idle_shutdown(dev); + break; + case PLD_BUS_TYPE_IPCI: + errno = pld_ipci_idle_shutdown(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} + +int pld_idle_restart(struct device *dev, + int (*restart_cb)(struct device *dev)) +{ + int errno = -EINVAL; + enum pld_bus_type type; + + if (!restart_cb) + return -EINVAL; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + errno = restart_cb(dev); + break; + case PLD_BUS_TYPE_SNOC: + errno = pld_snoc_idle_restart(dev); + break; + case PLD_BUS_TYPE_PCIE: + errno = pld_pcie_idle_restart(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + errno = pld_pcie_fw_sim_idle_restart(dev); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + errno = pld_snoc_fw_sim_idle_restart(dev); + break; + case PLD_BUS_TYPE_IPCI: + errno = pld_ipci_idle_restart(dev); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} + +int pld_thermal_register(struct device *dev, + unsigned long max_state, int mon_id) +{ + int errno = -EINVAL; + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_PCIE: + errno = pld_pci_thermal_register(dev, max_state, mon_id); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + errno = pld_pcie_fw_sim_thermal_register(dev, max_state, + mon_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + errno = pld_ipci_thermal_register(dev, max_state, mon_id); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} + +void pld_thermal_unregister(struct device *dev, int mon_id) +{ + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_PCIE: + pld_pci_thermal_unregister(dev, mon_id); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + pld_pcie_fw_sim_thermal_unregister(dev, mon_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + pld_ipci_thermal_unregister(dev, mon_id); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } +} + +int pld_set_wfc_mode(struct device *dev, enum pld_wfc_mode wfc_mode) +{ + int errno = -ENOTSUPP; + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_IPCI: + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_PCIE: + errno = pld_pcie_set_wfc_mode(dev, wfc_mode); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} +const char *pld_bus_width_type_to_str(enum pld_bus_width_type level) +{ + switch (level) { + /* initialize the wlan sub system */ + case PLD_BUS_WIDTH_NONE: + return "NONE"; + case PLD_BUS_WIDTH_IDLE: + return "IDLE"; + case PLD_BUS_WIDTH_LOW: + return "LOW"; + case PLD_BUS_WIDTH_MEDIUM: + return "MEDIUM"; + case PLD_BUS_WIDTH_HIGH: + return "HIGH"; + case PLD_BUS_WIDTH_MID_HIGH: + return "MID_HIGH"; + case PLD_BUS_WIDTH_VERY_HIGH: + return "VERY_HIGH"; + case PLD_BUS_WIDTH_ULTRA_HIGH: + return "ULTRA_HIGH"; + case PLD_BUS_WIDTH_LOW_LATENCY: + return "LOW_LAT"; + default: + if (level > PLD_BUS_WIDTH_ULTRA_HIGH) + return "SUPER_HIGH"; + else + return "INVAL"; + } +} + +int pld_get_thermal_state(struct device *dev, unsigned long *thermal_state, + int mon_id) +{ + int errno = -EINVAL; + enum pld_bus_type type; + + type = pld_get_bus_type(dev); + switch (type) { + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC: + break; + case PLD_BUS_TYPE_PCIE: + errno = pld_pci_get_thermal_state(dev, thermal_state, mon_id); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI_FW_SIM: + errno = pld_pcie_fw_sim_get_thermal_state(dev, thermal_state, + mon_id); + break; + case PLD_BUS_TYPE_SNOC_FW_SIM: + break; + case PLD_BUS_TYPE_IPCI: + errno = pld_ipci_get_thermal_state(dev, thermal_state, mon_id); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return errno; +} + +#ifdef CNSS_UTILS_VENDOR_UNSAFE_CHAN_API_SUPPORT +int pld_get_wlan_unsafe_channel_sap( + struct device *dev, struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + struct cnss_ch_avoid_ind_type cnss_ch_avoid; + int ret; + int i; + + if (!ch_avoid_ranges) + return -EINVAL; + cnss_ch_avoid.ch_avoid_range_cnt = 0; + ret = cnss_utils_get_wlan_unsafe_channel_sap(dev, &cnss_ch_avoid); + if (ret) + return ret; + + for (i = 0; + i < PLD_CH_AVOID_MAX_RANGE && + i < cnss_ch_avoid.ch_avoid_range_cnt; i++) { + ch_avoid_ranges->avoid_freq_range[i].start_freq = + cnss_ch_avoid.avoid_freq_range[i].start_freq; + ch_avoid_ranges->avoid_freq_range[i].end_freq = + cnss_ch_avoid.avoid_freq_range[i].end_freq; + } + ch_avoid_ranges->ch_avoid_range_cnt = i; + if (i < cnss_ch_avoid.ch_avoid_range_cnt) + pr_err("unexpected cnss ch_avoid_range_cnt %d", + cnss_ch_avoid.ch_avoid_range_cnt); + + return 0; +} +#endif + +void pld_set_tsf_sync_period(struct device *dev, u32 val) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_set_tsf_sync_period(dev, val); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +void pld_reset_tsf_sync_period(struct device *dev) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_reset_tsf_sync_period(dev); + break; + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_SNOC: + case PLD_BUS_TYPE_IPCI: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + break; + default: + pr_err("Invalid device type\n"); + break; + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +int pld_is_ipa_offload_disabled(struct device *dev) +{ + unsigned long dev_cfg = 0; + + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_SNOC: + dev_cfg = pld_snoc_get_device_config(); + break; + case PLD_BUS_TYPE_IPCI: + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + pr_err("Not supported on type %d\n", type); + break; + default: + pr_err("Invalid device type %d\n", type); + break; + } + + return test_bit(PLD_IPA_DISABLED, &dev_cfg); +} +#endif + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM +int pld_get_audio_wlan_timestamp(struct device *dev, + enum pld_wlan_time_sync_trigger_type type, + uint64_t *ts) +{ + int ret = 0; + enum pld_bus_type bus_type; + + bus_type = pld_get_bus_type(dev); + switch (bus_type) { + case PLD_BUS_TYPE_SNOC: + ret = pld_snoc_get_audio_wlan_timestamp(dev, type, ts); + break; + case PLD_BUS_TYPE_PCIE: + case PLD_BUS_TYPE_SNOC_FW_SIM: + case PLD_BUS_TYPE_PCIE_FW_SIM: + case PLD_BUS_TYPE_IPCI_FW_SIM: + case PLD_BUS_TYPE_SDIO: + case PLD_BUS_TYPE_USB: + case PLD_BUS_TYPE_IPCI: + break; + default: + ret = -EINVAL; + break; + } + return ret; +} +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ + +bool pld_is_one_msi(struct device *dev) +{ + bool ret = false; + enum pld_bus_type type = pld_get_bus_type(dev); + + switch (type) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_is_one_msi(dev); + break; + default: + break; + } + + return ret; +} + +#ifdef CONFIG_AFC_SUPPORT +int pld_send_buffer_to_afcmem(struct device *dev, const uint8_t *afcdb, + uint32_t len, uint8_t slotid) +{ + return cnss_send_buffer_to_afcmem(dev, afcdb, len, slotid); +} + +int pld_reset_afcmem(struct device *dev, uint8_t slotid) +{ + return cnss_reset_afcmem(dev, slotid); +} +#endif + +#ifdef FEATURE_DIRECT_LINK +int pld_audio_smmu_map(struct device *dev, phys_addr_t paddr, dma_addr_t iova, + size_t size) +{ + int ret; + + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + ret = pld_pcie_audio_smmu_map(dev, paddr, iova, size); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +void pld_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size) +{ + switch (pld_get_bus_type(dev)) { + case PLD_BUS_TYPE_PCIE: + pld_pcie_audio_smmu_unmap(dev, iova, size); + break; + default: + break; + } +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_internal.h new file mode 100644 index 0000000000..01e94de5f3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_internal.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_COMMON_I_H__ +#define __PLD_COMMON_I_H__ + +#include "pld_common.h" + +struct dev_node { + struct device *dev; + struct device *ifdev; + struct list_head list; + enum pld_bus_type bus_type; +}; + +struct pld_context { + struct pld_driver_ops *ops; + spinlock_t pld_lock; + struct list_head dev_list; + uint32_t pld_driver_state; + uint8_t mode; +}; + +/** + * pld_get_global_context() - Get global context of PLD + * + * Return: PLD global context + */ +struct pld_context *pld_get_global_context(void); + +/** + * pld_add_dev() - Add dev node to global context + * @pld_context: PLD global context + * @dev: device + * @ifdev: interface device + * @type: Bus type + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_add_dev(struct pld_context *pld_context, + struct device *dev, struct device *ifdev, + enum pld_bus_type type); + +/** + * pld_del_dev() - Delete dev node from global context + * @pld_context: PLD global context + * @dev: device + * + * Return: void + */ +void pld_del_dev(struct pld_context *pld_context, + struct device *dev); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_ipci.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_ipci.c new file mode 100644 index 0000000000..89615bd96e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_ipci.c @@ -0,0 +1,674 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_PLD_IPCI_ICNSS +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "icnss2.h" +#else +#include +#endif +#endif + +#include "pld_internal.h" +#include "pld_ipci.h" +#include "osif_psoc_sync.h" + +#ifdef CONFIG_PLD_IPCI_ICNSS + +#define WCN6750_DEVICE_ID 0x6750 +#define WCN6450_DEVICE_ID 0x6450 +/** + * pld_ipci_probe() - Probe function for platform driver + * @dev: device + * + * The probe function will be called when platform device + * is detected. + * + * Return: int + */ +static int pld_ipci_probe(struct device *dev) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, dev, NULL, PLD_BUS_TYPE_IPCI); + if (ret) + goto out; + + return pld_context->ops->probe(dev, PLD_BUS_TYPE_IPCI, + NULL, NULL); + +out: + return ret; +} + +/** + * pld_ipci_remove() - Remove function for platform device + * @dev: device + * + * The remove function will be called when platform device + * is disconnected + * + * Return: void + */ +static void pld_ipci_remove(struct device *dev) +{ + struct pld_context *pld_context; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync); + if (errno) + return; + + osif_psoc_sync_unregister(dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC); + + pld_del_dev(pld_context, dev); + +out: + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); +} + +/** + * pld_ipci_reinit() - SSR re-initialize function for platform device + * @dev: device + * + * During subsystem restart(SSR), this function will be called to + * re-initialize platform device. + * + * Return: int + */ +static int pld_ipci_reinit(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(dev, PLD_BUS_TYPE_IPCI, + NULL, NULL); + + return -ENODEV; +} + +/** + * pld_ipci_shutdown() - SSR shutdown function for platform device + * @dev: device + * + * During SSR, this function will be called to shutdown platform device. + * + * Return: void + */ +static void pld_ipci_shutdown(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(dev, PLD_BUS_TYPE_IPCI); +} + +/** + * pld_ipci_crash_shutdown() - Crash shutdown function for platform device + * @dev: device + * + * This function will be called when a crash is detected, it will shutdown + * platform device. + * + * Return: void + */ +static void pld_ipci_crash_shutdown(void *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_IPCI); +} + +/** + * pld_ipci_pm_suspend() - PM suspend callback function for power management + * @dev: device + * + * This function is to suspend the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_ipci_pm_suspend(struct device *dev) +{ + struct pld_context *pld_context; + pm_message_t state; + + state.event = PM_EVENT_SUSPEND; + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, PLD_BUS_TYPE_IPCI, state); +} + +/** + * pld_ipci_pm_resume() - PM resume callback function for power management + * @dev: device + * + * This function is to resume the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_ipci_pm_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_IPCI); +} + +/** + * pld_ipci_suspend_noirq() - Complete the actions started by suspend() + * @dev: device + * + * Complete the actions started by suspend(). Carry out any + * additional operations required for suspending the device that might be + * racing with its driver's interrupt handler, which is guaranteed not to + * run while suspend_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_ipci_suspend_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->suspend_noirq) + return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_IPCI); + return 0; +} + +/** + * pld_ipci_resume_noirq() - Prepare for the execution of resume() + * @dev: device + * + * Prepare for the execution of resume() by carrying out any + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_ipci_resume_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->resume_noirq) + return pld_context->ops->resume_noirq(dev, PLD_BUS_TYPE_IPCI); + + return 0; +} + +/** + * pld_ipci_runtime_suspend() - Runtime suspend callback for power management + * @dev: device + * + * This function is to runtime suspend the platform device when power management + * is enabled. + * + * Return: status + */ +static int pld_ipci_runtime_suspend(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops && pld_context->ops->runtime_suspend) + return pld_context->ops->runtime_suspend(dev, + PLD_BUS_TYPE_IPCI); + + return 0; +} + +/** + * pld_ipci_runtime_resume() - Runtime resume callback for power management + * @dev: device + * + * This function is to runtime resume the platform device when power management + * is enabled. + * + * Return: status + */ +static int pld_ipci_runtime_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops && pld_context->ops->runtime_resume) + return pld_context->ops->runtime_resume(dev, PLD_BUS_TYPE_IPCI); + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static int pld_update_hang_evt_data(struct icnss_uevent_hang_data *evt_data, + struct pld_uevent_data *data) +{ + if (!evt_data || !data) + return -EINVAL; + + data->hang_data.hang_event_data = evt_data->hang_event_data; + data->hang_data.hang_event_data_len = evt_data->hang_event_data_len; + return 0; +} + +static int pld_ipci_uevent(struct device *dev, + struct icnss_uevent_data *uevent) +{ + struct pld_context *pld_context; + struct icnss_uevent_fw_down_data *uevent_data = NULL; + struct pld_uevent_data data = {0}; + struct icnss_uevent_hang_data *hang_data = NULL; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (!pld_context->ops->uevent) + goto out; + + if (!uevent) + return -EINVAL; + + switch (uevent->uevent) { + case ICNSS_UEVENT_FW_CRASHED: + data.uevent = PLD_FW_CRASHED; + break; + case ICNSS_UEVENT_FW_DOWN: + if (!uevent->data) + return -EINVAL; + uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_FW_DOWN; + data.fw_down.crashed = uevent_data->crashed; + break; + case ICNSS_UEVENT_HANG_DATA: + if (!uevent->data) + return -EINVAL; + hang_data = (struct icnss_uevent_hang_data *)uevent->data; + data.uevent = PLD_FW_HANG_EVENT; + pld_update_hang_evt_data(hang_data, &data); + break; + case ICNSS_UEVENT_SMMU_FAULT: + if (!uevent->data) + return -EINVAL; + uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_SMMU_FAULT; + data.fw_down.crashed = uevent_data->crashed; + break; + default: + goto out; + } + + pld_context->ops->uevent(dev, &data); +out: + return 0; +} +#else +static int pld_ipci_uevent(struct device *dev, + struct icnss_uevent_data *uevent) +{ + struct pld_context *pld_context; + struct icnss_uevent_fw_down_data *uevent_data = NULL; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (!pld_context->ops->uevent) + goto out; + + if (!uevent) + return -EINVAL; + + switch (uevent->uevent) { + case ICNSS_UEVENT_FW_CRASHED: + data.uevent = PLD_FW_CRASHED; + break; + case ICNSS_UEVENT_FW_DOWN: + if (!uevent->data) + return -EINVAL; + uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_FW_DOWN; + data.fw_down.crashed = uevent_data->crashed; + break; + default: + goto out; + } + + pld_context->ops->uevent(dev, &data); +out: + return 0; +} +#endif + +/** + * pld_ipci_idle_restart_cb() - Perform idle restart + * @dev: platform device + * + * This function will be called if there is an idle restart request + * + * Return: int + */ +static int pld_ipci_idle_restart_cb(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->idle_restart) + return pld_context->ops->idle_restart(dev, + PLD_BUS_TYPE_IPCI); + + return -ENODEV; +} + +/** + * pld_ipci_idle_shutdown_cb() - Perform idle shutdown + * @dev: PCIE device + * + * This function will be called if there is an idle shutdown request + * + * Return: int + */ +static int pld_ipci_idle_shutdown_cb(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->shutdown) + return pld_context->ops->idle_shutdown(dev, + PLD_BUS_TYPE_IPCI); + + return -ENODEV; +} + +/** + * pld_ipci_set_thermal_state() - Set thermal state for thermal mitigation + * @dev: device + * @thermal_state: Thermal state set by thermal subsystem + * @mon_id: Thermal cooling device ID + * + * This function will be called when thermal subsystem notifies platform + * driver about change in thermal state. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_ipci_set_thermal_state(struct device *dev, + unsigned long thermal_state, + int mon_id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->set_curr_therm_cdev_state) + return pld_context->ops->set_curr_therm_cdev_state(dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + +#ifdef MULTI_IF_NAME +#define PLD_IPCI_OPS_NAME "pld_ipci_" MULTI_IF_NAME +#else +#define PLD_IPCI_OPS_NAME "pld_ipci" +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +static struct device_info pld_ipci_dev_info[] = { +#ifdef QCA_WIFI_QCA6750 + { "wcn6750", WCN6750_DEVICE_ID }, +#elif defined(QCA_WIFI_WCN6450) + { "wcn6450", WCN6450_DEVICE_ID }, +#endif + { { 0 } } +}; +#endif + +struct icnss_driver_ops pld_ipci_ops = { + .name = PLD_IPCI_OPS_NAME, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + .dev_info = pld_ipci_dev_info, +#endif + .probe = pld_ipci_probe, + .remove = pld_ipci_remove, + .shutdown = pld_ipci_shutdown, + .reinit = pld_ipci_reinit, + .crash_shutdown = pld_ipci_crash_shutdown, + .pm_suspend = pld_ipci_pm_suspend, + .pm_resume = pld_ipci_pm_resume, + .suspend_noirq = pld_ipci_suspend_noirq, + .resume_noirq = pld_ipci_resume_noirq, + .runtime_suspend = pld_ipci_runtime_suspend, + .runtime_resume = pld_ipci_runtime_resume, + .uevent = pld_ipci_uevent, + .idle_restart = pld_ipci_idle_restart_cb, + .idle_shutdown = pld_ipci_idle_shutdown_cb, + .set_therm_cdev_state = pld_ipci_set_thermal_state, +}; + +int pld_ipci_register_driver(void) +{ + return icnss_register_driver(&pld_ipci_ops); +} + +void pld_ipci_unregister_driver(void) +{ + icnss_unregister_driver(&pld_ipci_ops); +} + +#ifdef CONFIG_SHADOW_V3 +static inline void +pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg *cfg, + struct pld_wlan_enable_cfg *config) +{ + cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg; + cfg->shadow_reg_v3_cfg = (struct icnss_shadow_reg_v3_cfg *) + config->shadow_reg_v3_cfg; +} +#else +static inline void +pld_ipci_populate_shadow_v3_cfg(struct icnss_wlan_enable_cfg *cfg, + struct pld_wlan_enable_cfg *config) +{ +} +#endif + +int pld_ipci_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct icnss_wlan_enable_cfg cfg; + enum icnss_driver_mode icnss_mode; + + if (!dev) + return -ENODEV; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg; + cfg.shadow_reg_v2_cfg = (struct icnss_shadow_reg_v2_cfg *) + config->shadow_reg_v2_cfg; + cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid; + if (config->rri_over_ddr_cfg_valid) { + cfg.rri_over_ddr_cfg.base_addr_low = + config->rri_over_ddr_cfg.base_addr_low; + cfg.rri_over_ddr_cfg.base_addr_high = + config->rri_over_ddr_cfg.base_addr_high; + } + + pld_ipci_populate_shadow_v3_cfg(&cfg, config); + + switch (mode) { + case PLD_FTM: + icnss_mode = ICNSS_FTM; + break; + case PLD_EPPING: + icnss_mode = ICNSS_EPPING; + break; + default: + icnss_mode = ICNSS_MISSION; + break; + } + + return icnss_wlan_enable(dev, &cfg, icnss_mode, host_version); +} + +int pld_ipci_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + if (!dev) + return -ENODEV; + + return icnss_wlan_disable(dev, ICNSS_OFF); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +static void pld_ipci_populate_hw_cap_info(struct icnss_soc_info *icnss_info, + struct pld_soc_info *info) +{ + /*WLAN HW cap info*/ + info->hw_cap_info.nss = + (enum pld_wlan_hw_nss_info)icnss_info->rd_card_chain_cap; + info->hw_cap_info.bw = + (enum pld_wlan_hw_channel_bw_info)icnss_info->phy_he_channel_width_cap; + info->hw_cap_info.qam = + (enum pld_wlan_hw_qam_info)icnss_info->phy_qam_cap; +} +#else +static void pld_ipci_populate_hw_cap_info(struct icnss_soc_info *icnss_info, + struct pld_soc_info *info) +{ +} +#endif + +int pld_ipci_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int errno; + struct icnss_soc_info icnss_info = {0}; + + if (!info || !dev) + return -ENODEV; + + errno = icnss_get_soc_info(dev, &icnss_info); + if (errno) + return errno; + + info->v_addr = icnss_info.v_addr; + info->p_addr = icnss_info.p_addr; + info->chip_id = icnss_info.chip_id; + info->chip_family = icnss_info.chip_family; + info->board_id = icnss_info.board_id; + info->soc_id = icnss_info.soc_id; + info->fw_version = icnss_info.fw_version; + strlcpy(info->fw_build_timestamp, icnss_info.fw_build_timestamp, + sizeof(info->fw_build_timestamp)); + strlcpy(info->fw_build_id, icnss_info.fw_build_id, + sizeof(info->fw_build_id)); + + pld_ipci_populate_hw_cap_info(&icnss_info, info); + + return 0; +} + +/* + * pld_ipci_get_irq() - Get irq by ce_id + * @dev: device + * @ce_id: CE id for which irq is requested + * + * Return irq number. + * + * Return: irq number for success + * Non zero failure code for errors + */ +int pld_ipci_get_irq(struct device *dev, int ce_id) +{ + uint32_t msi_data_start; + uint32_t msi_data_count; + uint32_t msi_irq_start; + uint32_t msi_data; + int ret; + + ret = icnss_get_user_msi_assignment(dev, "CE", &msi_data_count, + &msi_data_start, &msi_irq_start); + if (ret) + return ret; + + msi_data = (ce_id % msi_data_count) + msi_irq_start; + ret = icnss_get_msi_irq(dev, msi_data); + + return ret; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_ipci.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_ipci.h new file mode 100644 index 0000000000..1af0882d07 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_ipci.h @@ -0,0 +1,440 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_IPCI_H__ +#define __PLD_IPCI_H__ + +#ifdef CONFIG_PLD_IPCI_ICNSS +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "icnss2.h" +#else +#include +#endif +#endif +#include "pld_internal.h" + +#ifndef CONFIG_PLD_IPCI_ICNSS +static inline int pld_ipci_register_driver(void) +{ + return 0; +} + +static inline void pld_ipci_unregister_driver(void) +{ +} + +static inline int pld_ipci_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} + +static inline int pld_ipci_wlan_disable(struct device *dev, + enum pld_driver_mode mode) +{ + return 0; +} + +static inline int pld_ipci_get_soc_info(struct device *dev, + struct pld_soc_info *info) +{ + return 0; +} + +static inline int pld_ipci_power_on(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_power_off(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_idle_restart(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_idle_shutdown(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_force_assert_target(struct device *dev) +{ + return -EINVAL; +} + +static inline int pld_ipci_get_user_msi_assignment(struct device *dev, + char *user_name, + int *num_vectors, + uint32_t *user_base_data, + uint32_t *base_vector) +{ + return 0; +} + +static inline int pld_ipci_get_msi_irq(struct device *dev, unsigned int vector) +{ + return 0; +} + +static inline void pld_ipci_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ +} + +static inline int pld_ipci_is_fw_down(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + return 0; +} + +static inline void *pld_ipci_smmu_get_domain(struct device *dev) +{ + return NULL; +} + +static inline int pld_ipci_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + return 0; +} + +static inline int pld_ipci_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return 0; +} + +static inline int pld_ipci_force_wake_request(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_force_wake_release(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_is_device_awake(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return 0; +} + +static inline int pld_ipci_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return 0; +} + +static inline int +pld_ipci_qmi_send(struct device *dev, int type, void *cmd, + int cmd_len, void *cb_ctx, + int (*cb)(void *ctx, void *event, int event_len)) +{ + return 0; +} + +static inline int pld_ipci_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return 0; +} + +static inline void pld_ipci_thermal_unregister(struct device *dev, + int mon_id) +{ +} + +static inline int pld_ipci_get_thermal_state(struct device *dev, + unsigned long *thermal_state, + int mon_id) +{ + return 0; +} + +static inline int pld_ipci_exit_power_save(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_prevent_l1(struct device *dev) +{ + return 0; +} + +static inline void pld_ipci_allow_l1(struct device *dev) +{ +} + +static inline int pld_ipci_mhi_state(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_is_pci_ep_awake(struct device *dev) +{ + return 0; +} + +static inline int pld_ipci_get_irq(struct device *dev, int ce_id) +{ + return 0; +} +#else +/** + * pld_ipci_register_driver() - Register platform device callback functions + * + * Return: int + */ +int pld_ipci_register_driver(void); + +/** + * pld_ipci_unregister_driver() - Unregister platform device callback functions + * + * Return: void + */ +void pld_ipci_unregister_driver(void); + +/** + * pld_ipci_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ipci_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); + +/** + * pld_ipci_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ipci_wlan_disable(struct device *dev, enum pld_driver_mode mode); + +/** + * pld_ipci_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_ipci_get_soc_info(struct device *dev, struct pld_soc_info *info); +int pld_ipci_get_irq(struct device *dev, int ce_id); + +static inline int pld_ipci_power_on(struct device *dev) +{ + return icnss_power_on(dev); +} + +static inline int pld_ipci_power_off(struct device *dev) +{ + return icnss_power_off(dev); +} + +static inline int pld_ipci_idle_restart(struct device *dev) +{ + return icnss_idle_restart(dev); +} + +static inline int pld_ipci_idle_shutdown(struct device *dev) +{ + return icnss_idle_shutdown(dev); +} + +static inline int pld_ipci_force_assert_target(struct device *dev) +{ + return icnss_trigger_recovery(dev); +} + +static inline int pld_ipci_get_user_msi_assignment(struct device *dev, + char *user_name, + int *num_vectors, + uint32_t *user_base_data, + uint32_t *base_vector) +{ + return icnss_get_user_msi_assignment(dev, user_name, num_vectors, + user_base_data, base_vector); +} + +static inline int pld_ipci_get_msi_irq(struct device *dev, unsigned int vector) +{ + return icnss_get_msi_irq(dev, vector); +} + +static inline void pld_ipci_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ + icnss_get_msi_address(dev, msi_addr_low, msi_addr_high); +} + +static inline int pld_ipci_is_fw_down(struct device *dev) +{ + return icnss_is_fw_down(); +} + +static inline int pld_ipci_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + return icnss_set_fw_log_mode(dev, fw_log_mode); +} + +static inline void *pld_ipci_smmu_get_domain(struct device *dev) +{ + return icnss_smmu_get_domain(dev); +} + +static inline int pld_ipci_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + return icnss_smmu_map(dev, paddr, iova_addr, size); +} + +#ifdef CONFIG_SMMU_S1_UNMAP +static inline int pld_ipci_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return icnss_smmu_unmap(dev, iova_addr, size); +} + +#else +static inline int pld_ipci_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return 0; +} +#endif + +static inline int pld_ipci_force_wake_request(struct device *dev) +{ + return icnss_force_wake_request(dev); +} + +static inline int pld_ipci_force_wake_release(struct device *dev) +{ + return icnss_force_wake_release(dev); +} + +static inline int pld_ipci_is_device_awake(struct device *dev) +{ + return icnss_is_device_awake(dev); +} + +static inline int pld_ipci_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return icnss_athdiag_read(dev, offset, memtype, datalen, output); +} + +static inline int pld_ipci_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return icnss_athdiag_write(dev, offset, memtype, datalen, input); +} + +static inline int +pld_ipci_qmi_send(struct device *dev, int type, void *cmd, + int cmd_len, void *cb_ctx, + int (*cb)(void *ctx, void *event, int event_len)) +{ + return icnss_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb); +} + +static inline int pld_ipci_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return icnss_thermal_cdev_register(dev, max_state, mon_id); +} + +static inline void pld_ipci_thermal_unregister(struct device *dev, + int mon_id) +{ + icnss_thermal_cdev_unregister(dev, mon_id); +} + +static inline int pld_ipci_get_thermal_state(struct device *dev, + unsigned long *thermal_state, + int mon_id) +{ + return icnss_get_curr_therm_cdev_state(dev, thermal_state, mon_id); +} + +static inline int pld_ipci_exit_power_save(struct device *dev) +{ + return icnss_exit_power_save(dev); +} + +static inline int pld_ipci_prevent_l1(struct device *dev) +{ + return icnss_prevent_l1(dev); +} + +static inline void pld_ipci_allow_l1(struct device *dev) +{ + icnss_allow_l1(dev); +} + +static inline int pld_ipci_is_pci_ep_awake(struct device *dev) +{ + return icnss_is_pci_ep_awake(dev); +} + +static inline int pld_ipci_mhi_state(struct device *dev) +{ + return icnss_get_mhi_state(dev); +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie.c new file mode 100644 index 0000000000..0f917e2863 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie.c @@ -0,0 +1,1037 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss2.h" +#else +#include +#endif +#endif + +#include "pld_internal.h" +#include "pld_pcie.h" +#include "osif_psoc_sync.h" + +#ifdef CONFIG_PCI + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define CE_COUNT_MAX 12 +#else +#define CE_COUNT_MAX 8 +#endif + +#if defined(CONFIG_PLD_PCIE_CNSS) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +#ifndef CHIP_VERSION +#define CHIP_VERSION CNSS_CHIP_VER_ANY +#endif +#endif + +/** + * pld_pcie_probe() - Probe function for PCIE platform driver + * @pdev: PCIE device + * @id: PCIE device ID table + * + * The probe function will be called when PCIE device provided + * in the ID table is detected. + * + * Return: int + */ +static int pld_pcie_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, &pdev->dev, NULL, PLD_BUS_TYPE_PCIE); + if (ret) + goto out; + + return pld_context->ops->probe(&pdev->dev, + PLD_BUS_TYPE_PCIE, pdev, (void *)id); + +out: + return ret; +} + + +/** + * pld_pcie_remove() - Remove function for PCIE device + * @pdev: PCIE device + * + * The remove function will be called when PCIE device is disconnected + * + * Return: void + */ +static void pld_pcie_remove(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync); + +#ifdef ENFORCE_PLD_REMOVE + if (errno && errno != -EINVAL) + return; +#else + if (errno) + return; +#endif + + osif_psoc_sync_unregister(&pdev->dev); + + if (psoc_sync) + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE); + + pld_del_dev(pld_context, &pdev->dev); + +out: + if (psoc_sync) { + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); + } +} + +/** + * pld_pcie_set_thermal_state() - Set thermal state for thermal mitigation + * @pdev: PCIE device + * @thermal_state: Thermal state set by thermal subsystem + * @mon_id: Thermal cooling device ID + * + * This function will be called when thermal subsystem notifies platform + * driver about change in thermal state. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_set_thermal_state(struct pci_dev *pdev, + unsigned long thermal_state, + int mon_id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->set_curr_therm_cdev_state) + return pld_context->ops->set_curr_therm_cdev_state(&pdev->dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + +#ifdef CONFIG_PLD_PCIE_CNSS +/** + * pld_pcie_idle_restart_cb() - Perform idle restart + * @pdev: PCIE device + * @id: PCIE device ID + * + * This function will be called if there is an idle restart request + * + * Return: int + */ +static int pld_pcie_idle_restart_cb(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->idle_restart) + return pld_context->ops->idle_restart(&pdev->dev, + PLD_BUS_TYPE_PCIE); + + return -ENODEV; +} + +/** + * pld_pcie_idle_shutdown_cb() - Perform idle shutdown + * @pdev: PCIE device + * + * This function will be called if there is an idle shutdown request + * + * Return: int + */ +static int pld_pcie_idle_shutdown_cb(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + return pld_context->ops->idle_shutdown(&pdev->dev, + PLD_BUS_TYPE_PCIE); + + return -ENODEV; +} + +/** + * pld_pcie_reinit() - SSR re-initialize function for PCIE device + * @pdev: PCIE device + * @id: PCIE device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize PCIE device. + * + * Return: int + */ +static int pld_pcie_reinit(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(&pdev->dev, + PLD_BUS_TYPE_PCIE, pdev, (void *)id); + + return -ENODEV; +} + +/** + * pld_pcie_shutdown() - SSR shutdown function for PCIE device + * @pdev: PCIE device + * + * During SSR, this function will be called to shutdown PCIE device. + * + * Return: void + */ +static void pld_pcie_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); +} + +/** + * pld_pcie_crash_shutdown() - Crash shutdown function for PCIE device + * @pdev: PCIE device + * + * This function will be called when a crash is detected, it will shutdown + * the PCIE device. + * + * Return: void + */ +static void pld_pcie_crash_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(&pdev->dev, PLD_BUS_TYPE_PCIE); +} + +/** + * pld_pcie_notify_handler() - Modem state notification callback function + * @pdev: PCIE device + * @state: modem power state + * + * This function will be called when there's a modem power state change. + * + * Return: void + */ +static void pld_pcie_notify_handler(struct pci_dev *pdev, int state) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->modem_status) + pld_context->ops->modem_status(&pdev->dev, + PLD_BUS_TYPE_PCIE, state); +} + +/** + * pld_pcie_uevent() - update wlan driver status callback function + * @pdev: PCIE device + * @status: driver uevent status + * + * This function will be called when platform driver wants to update wlan + * driver's status. + * + * Return: void + */ +static void pld_pcie_uevent(struct pci_dev *pdev, uint32_t status) +{ + struct pld_context *pld_context; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return; + + switch (status) { + case CNSS_RECOVERY: + data.uevent = PLD_FW_RECOVERY_START; + break; + case CNSS_FW_DOWN: + data.uevent = PLD_FW_DOWN; + break; + case CNSS_SYS_REBOOT: + data.uevent = PLD_SYS_REBOOT; + break; + default: + goto out; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + +out: + return; +} + +#ifdef WLAN_FEATURE_SSR_DRIVER_DUMP +static int +pld_pcie_collect_driver_dump(struct pci_dev *pdev, + struct cnss_ssr_driver_dump_entry *input_array, + size_t *num_entries) +{ + struct pld_context *pld_context; + struct pld_driver_ops *ops; + int ret = -EINVAL; + + pld_context = pld_get_global_context(); + ops = pld_context->ops; + if (ops->collect_driver_dump) { + ret = ops->collect_driver_dump(&pdev->dev, + PLD_BUS_TYPE_PCIE, + input_array, + num_entries); + } + return ret; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +/** + * pld_bus_event_type_convert() - Convert enum cnss_bus_event_type + * to enum pld_bus_event + * @etype: enum cnss_bus_event_type value + * + * This function will convert enum cnss_bus_event_type to + * enum pld_bus_event. + * + * Return: enum pld_bus_event + */ +static inline +enum pld_bus_event pld_bus_event_type_convert(enum cnss_bus_event_type etype) +{ + enum pld_bus_event pld_etype = PLD_BUS_EVENT_INVALID; + + switch (etype) { + case BUS_EVENT_PCI_LINK_DOWN: + pld_etype = PLD_BUS_EVENT_PCIE_LINK_DOWN; + break; + default: + break; + } + + return pld_etype; +} + +/** + * pld_pcie_update_event() - update wlan driver status callback function + * @pdev: PCIE device + * @uevent_data: driver uevent data + * + * This function will be called when platform driver wants to update wlan + * driver's status. + * + * Return: 0 for success, non zero for error code + */ +static int pld_pcie_update_event(struct pci_dev *pdev, + struct cnss_uevent_data *uevent_data) +{ + struct pld_context *pld_context; + struct pld_uevent_data data = {0}; + struct cnss_hang_event *hang_event; + + pld_context = pld_get_global_context(); + + if (!pld_context || !uevent_data) + return -EINVAL; + + switch (uevent_data->status) { + case CNSS_HANG_EVENT: + if (!uevent_data->data) + return -EINVAL; + hang_event = (struct cnss_hang_event *)uevent_data->data; + data.uevent = PLD_FW_HANG_EVENT; + data.hang_data.hang_event_data = hang_event->hang_event_data; + data.hang_data.hang_event_data_len = + hang_event->hang_event_data_len; + break; + case CNSS_BUS_EVENT: + { + struct cnss_bus_event *bus_evt = uevent_data->data; + + if (!bus_evt) + return -EINVAL; + + data.uevent = PLD_BUS_EVENT; + + /* Process uevent_data->data if any */ + data.bus_data.etype = + pld_bus_event_type_convert(bus_evt->etype); + data.bus_data.event_data = bus_evt->event_data; + break; + } + default: + return 0; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + + return 0; +} +#endif + +#ifdef FEATURE_RUNTIME_PM +/** + * pld_pcie_runtime_suspend() - PM runtime suspend + * @pdev: PCIE device + * + * PM runtime suspend callback function. + * + * Return: int + */ +static int pld_pcie_runtime_suspend(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->runtime_suspend) + return pld_context->ops->runtime_suspend(&pdev->dev, + PLD_BUS_TYPE_PCIE); + + return -ENODEV; +} + +/** + * pld_pcie_runtime_resume() - PM runtime resume + * @pdev: PCIE device + * + * PM runtime resume callback function. + * + * Return: int + */ +static int pld_pcie_runtime_resume(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->runtime_resume) + return pld_context->ops->runtime_resume(&pdev->dev, + PLD_BUS_TYPE_PCIE); + + return -ENODEV; +} +#endif + +#ifdef FEATURE_GET_DRIVER_MODE +/** + * pld_pcie_get_mode() - Get current WLAN driver mode + * + * This function is to get current driver mode + * + * Return: mission mode or ftm mode + */ +static +enum cnss_driver_mode pld_pcie_get_mode(void) +{ + struct pld_context *pld_ctx = pld_get_global_context(); + enum cnss_driver_mode cnss_mode = CNSS_MISSION; + + if (!pld_ctx) + return cnss_mode; + + switch (pld_ctx->mode) { + case QDF_GLOBAL_MISSION_MODE: + cnss_mode = CNSS_MISSION; + break; + case QDF_GLOBAL_WALTEST_MODE: + cnss_mode = CNSS_WALTEST; + break; + case QDF_GLOBAL_FTM_MODE: + cnss_mode = CNSS_FTM; + break; + case QDF_GLOBAL_COLDBOOT_CALIB_MODE: + cnss_mode = CNSS_CALIBRATION; + break; + case QDF_GLOBAL_EPPING_MODE: + cnss_mode = CNSS_EPPING; + break; + case QDF_GLOBAL_QVIT_MODE: + cnss_mode = CNSS_QVIT; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_mode; +} +#endif +#endif + +#ifdef CONFIG_PM +#ifdef CONFIG_PLD_PCIE_CNSS +/** + * pld_pcie_suspend() - Suspend callback function for power management + * @pdev: PCIE device + * @state: power state + * + * This function is to suspend the PCIE device when power management is + * enabled. + * + * Return: void + */ +static int pld_pcie_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(&pdev->dev, + PLD_BUS_TYPE_PCIE, state); +} + +/** + * pld_pcie_resume() - Resume callback function for power management + * @pdev: PCIE device + * + * This function is to resume the PCIE device when power management is + * enabled. + * + * Return: void + */ +static int pld_pcie_resume(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_PCIE); +} + +/** + * pld_pcie_suspend_noirq() - Complete the actions started by suspend() + * @pdev: PCI device + * + * Complete the actions started by suspend(). Carry out any additional + * operations required for suspending the device that might be racing + * with its driver's interrupt handler, which is guaranteed not to run + * while suspend_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_suspend_noirq(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->suspend_noirq) + return pld_context->ops-> + suspend_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE); + return 0; +} + +/** + * pld_pcie_resume_noirq() - Prepare for the execution of resume() + * @pdev: PCI device + * + * Prepare for the execution of resume() by carrying out any additional + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_resume_noirq(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->resume_noirq) + return pld_context->ops-> + resume_noirq(&pdev->dev, PLD_BUS_TYPE_PCIE); + return 0; +} +#else +/** + * pld_pcie_pm_suspend() - Suspend callback function for power management + * @dev: device + * + * This function is to suspend the PCIE device when power management is + * enabled. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_pm_suspend(struct device *dev) +{ + struct pld_context *pld_context; + + pm_message_t state = { .event = PM_EVENT_SUSPEND }; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, PLD_BUS_TYPE_PCIE, state); +} + +/** + * pld_pcie_pm_resume() - Resume callback function for power management + * @dev: device + * + * This function is to resume the PCIE device when power management is + * enabled. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_pm_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_PCIE); +} + +/** + * pld_pcie_pm_suspend_noirq() - Complete the actions started by suspend() + * @dev: device + * + * Complete the actions started by suspend(). Carry out any additional + * operations required for suspending the device that might be racing + * with its driver's interrupt handler, which is guaranteed not to run + * while suspend_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_pm_suspend_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->suspend_noirq) + return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_PCIE); + return 0; +} + +/** + * pld_pcie_pm_resume_noirq() - Prepare for the execution of resume() + * @dev: device + * + * Prepare for the execution of resume() by carrying out any additional + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_pm_resume_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->resume_noirq) + return pld_context->ops-> + resume_noirq(dev, PLD_BUS_TYPE_PCIE); + return 0; +} +#endif +#endif + +static struct pci_device_id pld_pcie_id_table[] = { +#ifdef CONFIG_AR6320_SUPPORT + { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, +#elif defined(QCA_WIFI_QCA6290) + { 0x17cb, 0x1100, PCI_ANY_ID, PCI_ANY_ID }, +#elif defined(QCA_WIFI_QCA6390) + { 0x17cb, 0x1101, PCI_ANY_ID, PCI_ANY_ID }, +#elif defined(QCA_WIFI_QCA6490) + { 0x17cb, 0x1103, PCI_ANY_ID, PCI_ANY_ID }, +#elif defined(QCA_WIFI_KIWI) +#if defined(QCA_WIFI_PEACH) + { 0x17cb, 0x110E, PCI_ANY_ID, PCI_ANY_ID }, +#elif defined(QCA_WIFI_MANGO) + { 0x17cb, 0x110A, PCI_ANY_ID, PCI_ANY_ID }, +#else + { 0x17cb, 0x1107, PCI_ANY_ID, PCI_ANY_ID }, +#endif +#elif defined(QCN7605_SUPPORT) + { 0x17cb, 0x1102, PCI_ANY_ID, PCI_ANY_ID }, +#else + { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID }, +#endif + { 0 } +}; + +#ifdef MULTI_IF_NAME +#define PLD_PCIE_OPS_NAME "pld_pcie_" MULTI_IF_NAME +#else +#define PLD_PCIE_OPS_NAME "pld_pcie" +#endif + +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef FEATURE_RUNTIME_PM +struct cnss_wlan_runtime_ops runtime_pm_ops = { + .runtime_suspend = pld_pcie_runtime_suspend, + .runtime_resume = pld_pcie_runtime_resume, +}; +#endif + +struct cnss_wlan_driver pld_pcie_ops = { + .name = PLD_PCIE_OPS_NAME, + .id_table = pld_pcie_id_table, + .probe = pld_pcie_probe, + .remove = pld_pcie_remove, + .idle_restart = pld_pcie_idle_restart_cb, + .idle_shutdown = pld_pcie_idle_shutdown_cb, + .reinit = pld_pcie_reinit, + .shutdown = pld_pcie_shutdown, + .crash_shutdown = pld_pcie_crash_shutdown, + .modem_status = pld_pcie_notify_handler, + .update_status = pld_pcie_uevent, +#ifdef WLAN_FEATURE_SSR_DRIVER_DUMP + .collect_driver_dump = pld_pcie_collect_driver_dump, +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) + .update_event = pld_pcie_update_event, +#endif +#ifdef CONFIG_PM + .suspend = pld_pcie_suspend, + .resume = pld_pcie_resume, + .suspend_noirq = pld_pcie_suspend_noirq, + .resume_noirq = pld_pcie_resume_noirq, +#endif +#ifdef FEATURE_RUNTIME_PM + .runtime_ops = &runtime_pm_ops, +#endif +#ifdef FEATURE_GET_DRIVER_MODE + .get_driver_mode = pld_pcie_get_mode, +#endif +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + .chip_version = CHIP_VERSION, +#endif + .set_therm_cdev_state = pld_pcie_set_thermal_state, +}; + +int pld_pcie_register_driver(void) +{ + return cnss_wlan_register_driver(&pld_pcie_ops); +} + +void pld_pcie_unregister_driver(void) +{ + cnss_wlan_unregister_driver(&pld_pcie_ops); +} +#else +#ifdef CONFIG_PM +static const struct dev_pm_ops pld_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pld_pcie_pm_suspend, pld_pcie_pm_resume) + .suspend_noirq = pld_pcie_pm_suspend_noirq, + .resume_noirq = pld_pcie_pm_resume_noirq, +}; +#endif + +struct pci_driver pld_pcie_ops = { + .name = PLD_PCIE_OPS_NAME, + .id_table = pld_pcie_id_table, + .probe = pld_pcie_probe, + .remove = pld_pcie_remove, + .driver = { +#ifdef CONFIG_PM + .pm = &pld_pm_ops, +#endif + }, +}; + +int pld_pcie_register_driver(void) +{ + return pci_register_driver(&pld_pcie_ops); +} + +void pld_pcie_unregister_driver(void) +{ + pci_unregister_driver(&pld_pcie_ops); +} +#endif + +int pld_pcie_get_ce_id(struct device *dev, int irq) +{ + int ce_id = irq - 100; + + if (ce_id < CE_COUNT_MAX && ce_id >= 0) + return ce_id; + + return -EINVAL; +} + +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef CONFIG_SHADOW_V3 +static inline void +pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg, + struct pld_wlan_enable_cfg *config) +{ + cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg; + cfg->shadow_reg_v3_cfg = (struct cnss_shadow_reg_v3_cfg *) + config->shadow_reg_v3_cfg; +} +#else +static inline void +pld_pcie_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg, + struct pld_wlan_enable_cfg *config) +{ +} +#endif +int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct cnss_wlan_enable_cfg cfg; + enum cnss_driver_mode cnss_mode; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg; + cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *) + config->shadow_reg_v2_cfg; + cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid; + if (config->rri_over_ddr_cfg_valid) { + cfg.rri_over_ddr_cfg.base_addr_low = + config->rri_over_ddr_cfg.base_addr_low; + cfg.rri_over_ddr_cfg.base_addr_high = + config->rri_over_ddr_cfg.base_addr_high; + } + + pld_pcie_populate_shadow_v3_cfg(&cfg, config); + + switch (mode) { + case PLD_FTM: + cnss_mode = CNSS_FTM; + break; + case PLD_EPPING: + cnss_mode = CNSS_EPPING; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version); +} + +int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + return cnss_wlan_disable(dev, CNSS_OFF); +} + +int pld_pcie_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + int ret = 0; + struct cnss_fw_files cnss_fw_files; + + if (!pfw_files) + return -ENODEV; + + memset(pfw_files, 0, sizeof(*pfw_files)); + + ret = cnss_get_fw_files_for_target(dev, &cnss_fw_files, + target_type, target_version); + if (ret) + return ret; + + scnprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.image_file); + scnprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.board_data); + scnprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.otp_data); + scnprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.utf_file); + scnprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.utf_board_data); + scnprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.epping_file); + scnprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.evicted_data); + + return 0; +} + +int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap) +{ + int ret = 0; + struct cnss_platform_cap cnss_cap; + + if (!cap) + return -ENODEV; + + ret = cnss_get_platform_cap(dev, &cnss_cap); + if (ret) + return ret; + + memcpy(cap, &cnss_cap, sizeof(*cap)); + return 0; +} + +int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int ret = 0, i; + struct cnss_soc_info cnss_info = {0}; + + if (!info) + return -ENODEV; + + ret = cnss_get_soc_info(dev, &cnss_info); + if (ret) + return ret; + + info->v_addr = cnss_info.va; + info->p_addr = cnss_info.pa; + info->chip_id = cnss_info.chip_id; + info->chip_family = cnss_info.chip_family; + info->board_id = cnss_info.board_id; + info->soc_id = cnss_info.soc_id; + info->fw_version = cnss_info.fw_version; + strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp, + sizeof(info->fw_build_timestamp)); + info->device_version.family_number = + cnss_info.device_version.family_number; + info->device_version.device_number = + cnss_info.device_version.device_number; + info->device_version.major_version = + cnss_info.device_version.major_version; + info->device_version.minor_version = + cnss_info.device_version.minor_version; + for (i = 0; i < PLD_MAX_DEV_MEM_NUM; i++) { + info->dev_mem_info[i].start = cnss_info.dev_mem_info[i].start; + info->dev_mem_info[i].size = cnss_info.dev_mem_info[i].size; + } + strlcpy(info->fw_build_id, cnss_info.fw_build_id, + sizeof(info->fw_build_id)); + + return 0; +} + +void pld_pcie_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason) +{ + enum cnss_recovery_reason cnss_reason; + + switch (reason) { + case PLD_REASON_LINK_DOWN: + cnss_reason = CNSS_REASON_LINK_DOWN; + break; + default: + cnss_reason = CNSS_REASON_DEFAULT; + break; + } + cnss_schedule_recovery(dev, cnss_reason); +} + +void pld_pcie_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason) +{ + enum cnss_recovery_reason cnss_reason; + + switch (reason) { + case PLD_REASON_LINK_DOWN: + cnss_reason = CNSS_REASON_LINK_DOWN; + break; + default: + cnss_reason = CNSS_REASON_DEFAULT; + break; + } + cnss_self_recovery(dev, cnss_reason); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +int pld_pcie_set_wfc_mode(struct device *dev, + enum pld_wfc_mode wfc_mode) +{ + struct cnss_wfc_cfg cfg; + int ret; + + switch (wfc_mode) { + case PLD_WFC_MODE_OFF: + cfg.mode = CNSS_WFC_MODE_OFF; + break; + case PLD_WFC_MODE_ON: + cfg.mode = CNSS_WFC_MODE_ON; + break; + default: + ret = -EINVAL; + goto out; + } + + ret = cnss_set_wfc_mode(dev, cfg); +out: + return ret; +} +#endif +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie.h new file mode 100644 index 0000000000..6ace9e0d82 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie.h @@ -0,0 +1,999 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_PCIE_H__ +#define __PLD_PCIE_H__ + +#ifdef CONFIG_PLD_PCIE_CNSS +#ifdef CONFIG_CNSS_OUT_OF_TREE +#include "cnss2.h" +#else +#include +#endif +#endif +#include +#include "pld_internal.h" + +#ifdef DYNAMIC_SINGLE_CHIP +#define PREFIX DYNAMIC_SINGLE_CHIP "/" +#else + +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME "/" +#else +#define PREFIX "" +#endif + +#endif + +#if !defined(HIF_PCI) || defined(CONFIG_PLD_PCIE_FW_SIM) +static inline int pld_pcie_register_driver(void) +{ + return 0; +} + +static inline void pld_pcie_unregister_driver(void) +{ +} + +static inline int pld_pcie_get_ce_id(struct device *dev, int irq) +{ + return 0; +} +#else +/** + * pld_pcie_register_driver() - Register PCIE device callback functions + * + * Return: int + */ +int pld_pcie_register_driver(void); + +/** + * pld_pcie_unregister_driver() - Unregister PCIE device callback functions + * + * Return: void + */ +void pld_pcie_unregister_driver(void); + +/** + * pld_pcie_get_ce_id() - Get CE number for the provided IRQ + * @dev: device + * @irq: IRQ number + * + * Return: CE number + */ +int pld_pcie_get_ce_id(struct device *dev, int irq); +#endif + +#ifndef CONFIG_PLD_PCIE_CNSS +static inline int pld_pcie_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} + +static inline int pld_pcie_wlan_disable(struct device *dev, + enum pld_driver_mode mode) +{ + return 0; +} + +static inline int pld_pcie_wlan_hw_enable(void) +{ + return 0; +} + +#else + +/** + * pld_pcie_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); + +/** + * pld_pcie_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_wlan_disable(struct device *dev, enum pld_driver_mode mode); + +#ifdef FEATURE_CNSS_HW_SECURE_DISABLE +static inline int pld_pcie_wlan_hw_enable(void) +{ + return cnss_wlan_hw_enable(); +} +#else +static inline int pld_pcie_wlan_hw_enable(void) +{ + return -EINVAL; +} +#endif +#endif + +#if defined(CONFIG_PLD_PCIE_CNSS) +static inline int pld_pcie_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + return cnss_set_fw_log_mode(dev, fw_log_mode); +} + +static inline void pld_pcie_intr_notify_q6(struct device *dev) +{ +} +#else +static inline int pld_pcie_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + return 0; +} + +static inline void pld_pcie_intr_notify_q6(struct device *dev) +{ +} +#endif + +#if (!defined(CONFIG_PLD_PCIE_CNSS)) || (!defined(CONFIG_CNSS_SECURE_FW)) +static inline int pld_pcie_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out) +{ + return 0; +} + +static inline void *pld_pcie_get_fw_ptr(struct device *dev) +{ + return NULL; +} +#else +static inline int pld_pcie_get_sha_hash(struct device *dev, const u8 *data, + u32 data_len, u8 *hash_idx, u8 *out) +{ + return cnss_get_sha_hash(data, data_len, hash_idx, out); +} + +static inline void *pld_pcie_get_fw_ptr(struct device *dev) +{ + return cnss_get_fw_ptr(); +} +#endif + +#ifdef CONFIG_PLD_PCIE_CNSS +static inline int pld_pcie_wlan_pm_control(struct device *dev, bool vote) +{ + return cnss_wlan_pm_control(dev, vote); +} +#else +static inline int pld_pcie_wlan_pm_control(struct device *dev, bool vote) +{ + return 0; +} +#endif + +#ifndef CONFIG_PLD_PCIE_CNSS +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static inline void *pld_pcie_smmu_get_domain(struct device *dev) +{ + return NULL; +} +#else +static inline void *pld_pcie_smmu_get_mapping(struct device *dev) +{ + return NULL; +} +#endif + +static inline int +pld_pcie_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + return 0; +} + +static inline int +pld_pcie_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size) +{ + return 0; +} + +static inline int +pld_pcie_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + pld_get_default_fw_files(pfw_files); + return 0; +} + +static inline int pld_pcie_prevent_l1(struct device *dev) +{ + return 0; +} + +static inline void pld_pcie_allow_l1(struct device *dev) +{ +} + +static inline int pld_pcie_set_gen_speed(struct device *dev, u8 pcie_gen_speed) +{ + return 0; +} + + +static inline void pld_pcie_link_down(struct device *dev) +{ +} + +static inline int pld_pcie_get_reg_dump(struct device *dev, uint8_t *buf, + uint32_t len) +{ + return 0; +} + +static inline int pld_pcie_is_fw_down(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return 0; +} + +static inline int pld_pcie_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return 0; +} + +static inline void +pld_pcie_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason) +{ +} + +static inline void *pld_pcie_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + size_t length = 0; + int flags = GFP_KERNEL; + + length = TOTAL_DUMP_SIZE; + + if (!size) + return NULL; + + *size = (unsigned long)length; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + return kzalloc(length, flags); +} + +static inline void pld_pcie_release_virt_ramdump_mem(void *address) +{ + kfree(address); +} + +static inline void pld_pcie_device_crashed(struct device *dev) +{ +} + +static inline void pld_pcie_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason) +{ +} + +static inline void pld_pcie_request_pm_qos(struct device *dev, u32 qos_val) +{ +} + +static inline void pld_pcie_remove_pm_qos(struct device *dev) +{ +} + +static inline void pld_pcie_set_tsf_sync_period(struct device *dev, u32 val) +{ +} + +static inline void pld_pcie_reset_tsf_sync_period(struct device *dev) +{ +} + +static inline int pld_pcie_request_bus_bandwidth(struct device *dev, + int bandwidth) +{ + return 0; +} + +static inline int pld_pcie_get_platform_cap(struct device *dev, + struct pld_platform_cap *cap) +{ + return 0; +} + +static inline int pld_pcie_get_soc_info(struct device *dev, + struct pld_soc_info *info) +{ + return 0; +} + +static inline int pld_pcie_auto_suspend(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_auto_resume(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_force_wake_request(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_force_wake_request_sync(struct device *dev, + int timeout_us) +{ + return 0; +} + +static inline int pld_pcie_is_device_awake(struct device *dev) +{ + return true; +} + +static inline int pld_pcie_force_wake_release(struct device *dev) +{ + return 0; +} + +static inline void pld_pcie_lock_reg_window(struct device *dev, + unsigned long *flags) +{ +} + +static inline void pld_pcie_unlock_reg_window(struct device *dev, + unsigned long *flags) +{ +} + +static inline int pld_pcie_get_pci_slot(struct device *dev) +{ + return 0; +} + +static inline struct kobject *pld_pcie_get_wifi_kobj(struct device *dev) +{ + return NULL; +} + +static inline int pld_pcie_power_on(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_power_off(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_idle_restart(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_idle_shutdown(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_force_assert_target(struct device *dev) +{ + return -EINVAL; +} + +static inline int pld_pcie_collect_rddm(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_qmi_send_get(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_qmi_send_put(struct device *dev) +{ + return 0; +} + +static inline int +pld_pcie_qmi_send(struct device *dev, int type, void *cmd, + int cmd_len, void *cb_ctx, + int (*cb)(void *ctx, void *event, int event_len)) +{ + return -EINVAL; +} + +static inline int +pld_pcie_register_qmi_ind(struct device *dev, void *cb_ctx, + int (*cb)(void *ctx, uint16_t type, + void *event, int event_len)) +{ + return -EINVAL; +} + +static inline int pld_pcie_get_user_msi_assignment(struct device *dev, + char *user_name, + int *num_vectors, + uint32_t *user_base_data, + uint32_t *base_vector) +{ + return -EINVAL; +} + +static inline int pld_pcie_get_msi_irq(struct device *dev, unsigned int vector) +{ + return 0; +} + +static inline bool pld_pcie_is_one_msi(struct device *dev) +{ + return false; +} + +static inline void pld_pcie_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ + return; +} + +static inline int pld_pcie_is_drv_connected(struct device *dev) +{ + return 0; +} + +static inline bool pld_pcie_platform_driver_support(void) +{ + return false; +} + +static inline bool pld_pcie_is_direct_link_supported(struct device *dev) +{ + return false; +} + +static inline +int pld_pcie_audio_smmu_map(struct device *dev, phys_addr_t paddr, + dma_addr_t iova, size_t size) +{ + return 0; +} + +static inline +void pld_pcie_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size) +{ +} + +static inline int pld_pcie_set_wfc_mode(struct device *dev, + enum pld_wfc_mode wfc_mode) +{ + return 0; +} + +static inline int pld_pci_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return 0; +} + +static inline void pld_pci_thermal_unregister(struct device *dev, + int mon_id) +{ +} + +static inline int pld_pci_get_thermal_state(struct device *dev, + unsigned long *thermal_state, + int mon_id) +{ + return 0; +} + +#else +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +int pld_pcie_set_wfc_mode(struct device *dev, + enum pld_wfc_mode wfc_mode); +#else +static inline int pld_pcie_set_wfc_mode(struct device *dev, + enum pld_wfc_mode wfc_mode) +{ + return 0; +} +#endif + +/** + * pld_pcie_get_fw_files_for_target() - Get FW file names + * @dev: device + * @pfw_files: buffer for FW file names + * @target_type: target type + * @target_version: target version + * + * Return target specific FW file names to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_get_fw_files_for_target(struct device *dev, + struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); + +/** + * pld_pcie_get_platform_cap() - Get platform capabilities + * @dev: device + * @cap: buffer to the capabilities + * + * Return capabilities to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_get_platform_cap(struct device *dev, struct pld_platform_cap *cap); + +/** + * pld_pcie_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_get_soc_info(struct device *dev, struct pld_soc_info *info); + +/** + * pld_pcie_schedule_recovery_work() - schedule recovery work + * @dev: device + * @reason: recovery reason + * + * Return: void + */ +void pld_pcie_schedule_recovery_work(struct device *dev, + enum pld_recovery_reason reason); + +/** + * pld_pcie_device_self_recovery() - device self recovery + * @dev: device + * @reason: recovery reason + * + * Return: void + */ +void pld_pcie_device_self_recovery(struct device *dev, + enum pld_recovery_reason reason); +static inline int pld_pcie_collect_rddm(struct device *dev) +{ + return cnss_force_collect_rddm(dev); +} + +static inline int pld_pcie_qmi_send_get(struct device *dev) +{ + return cnss_qmi_send_get(dev); +} + +static inline int pld_pcie_qmi_send_put(struct device *dev) +{ + return cnss_qmi_send_put(dev); +} + +static inline int +pld_pcie_qmi_send(struct device *dev, int type, void *cmd, + int cmd_len, void *cb_ctx, + int (*cb)(void *ctx, void *event, int event_len)) +{ + return cnss_qmi_send(dev, type, cmd, cmd_len, cb_ctx, cb); +} + +#if defined(WLAN_CHIPSET_STATS) && \ + (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +static inline int +pld_pcie_register_qmi_ind(struct device *dev, void *cb_ctx, + int (*cb)(void *ctx, uint16_t type, + void *event, int event_len)) +{ + return cnss_register_driver_async_data_cb(dev, cb_ctx, cb); +} +#else +static inline int +pld_pcie_register_qmi_ind(struct device *dev, void *cb_ctx, + int (*cb)(void *ctx, uint16_t type, + void *event, int event_len)) +{ + return 0; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static inline void *pld_pcie_smmu_get_domain(struct device *dev) +{ + return cnss_smmu_get_domain(dev); +} +#else +static inline void *pld_pcie_smmu_get_mapping(struct device *dev) +{ + return cnss_smmu_get_mapping(dev); +} +#endif + +static inline int +pld_pcie_smmu_map(struct device *dev, + phys_addr_t paddr, uint32_t *iova_addr, size_t size) +{ + return cnss_smmu_map(dev, paddr, iova_addr, size); +} + +#ifdef CONFIG_SMMU_S1_UNMAP +static inline int +pld_pcie_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size) +{ + return cnss_smmu_unmap(dev, iova_addr, size); +} +#else /* !CONFIG_SMMU_S1_UNMAP */ +static inline int +pld_pcie_smmu_unmap(struct device *dev, uint32_t iova_addr, size_t size) +{ + return 0; +} +#endif /* CONFIG_SMMU_S1_UNMAP */ + +static inline int pld_pcie_prevent_l1(struct device *dev) +{ + return cnss_pci_prevent_l1(dev); +} + +static inline void pld_pcie_allow_l1(struct device *dev) +{ + cnss_pci_allow_l1(dev); +} + +#ifdef PCIE_GEN_SWITCH +/** + * pld_pcie_set_gen_speed() - Wrapper for platform API to set PCIE gen speed + * @dev: device + * @pcie_gen_speed: PCIE gen speed required + * + * Send required PCIE Gen speed to platform driver + * + * Return: 0 for success. Negative error codes. + */ +static inline int pld_pcie_set_gen_speed(struct device *dev, u8 pcie_gen_speed) +{ + return cnss_set_pcie_gen_speed(dev, pcie_gen_speed); +} +#else +static inline int pld_pcie_set_gen_speed(struct device *dev, u8 pcie_gen_speed) +{ + return 0; +} +#endif + +static inline void pld_pcie_link_down(struct device *dev) +{ + cnss_pci_link_down(dev); +} + +#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) && \ + (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0))) +static inline int pld_pcie_get_reg_dump(struct device *dev, uint8_t *buf, + uint32_t len) +{ + return cnss_pci_get_reg_dump(dev, buf, len); +} +#else +static inline int pld_pcie_get_reg_dump(struct device *dev, uint8_t *buf, + uint32_t len) +{ + return 0; +} +#endif + +static inline int pld_pcie_is_fw_down(struct device *dev) +{ + return cnss_pci_is_device_down(dev); +} + +static inline int pld_pcie_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return cnss_athdiag_read(dev, offset, memtype, datalen, output); +} + +static inline int pld_pcie_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return cnss_athdiag_write(dev, offset, memtype, datalen, input); +} + +static inline void *pld_pcie_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + return cnss_get_virt_ramdump_mem(dev, size); +} + +static inline void pld_pcie_release_virt_ramdump_mem(void *address) +{ +} + +static inline void pld_pcie_device_crashed(struct device *dev) +{ + cnss_device_crashed(dev); +} + +static inline void pld_pcie_request_pm_qos(struct device *dev, u32 qos_val) +{ + cnss_request_pm_qos(dev, qos_val); +} + +static inline void pld_pcie_remove_pm_qos(struct device *dev) +{ + cnss_remove_pm_qos(dev); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +static inline void pld_pcie_set_tsf_sync_period(struct device *dev, u32 val) +{ + cnss_update_time_sync_period(dev, val); +} + +static inline void pld_pcie_reset_tsf_sync_period(struct device *dev) +{ + cnss_reset_time_sync_period(dev); +} +#else +static inline void pld_pcie_set_tsf_sync_period(struct device *dev, u32 val) +{ +} + +static inline void pld_pcie_reset_tsf_sync_period(struct device *dev) +{ +} +#endif +static inline int pld_pcie_request_bus_bandwidth(struct device *dev, + int bandwidth) +{ + return cnss_request_bus_bandwidth(dev, bandwidth); +} + +static inline int pld_pcie_auto_suspend(struct device *dev) +{ + return cnss_auto_suspend(dev); +} + +static inline int pld_pcie_auto_resume(struct device *dev) +{ + return cnss_auto_resume(dev); +} + +static inline int pld_pcie_force_wake_request(struct device *dev) +{ + return cnss_pci_force_wake_request(dev); +} + +static inline int pld_pcie_force_wake_request_sync(struct device *dev, + int timeout_us) +{ + return cnss_pci_force_wake_request_sync(dev, timeout_us); +} + +static inline int pld_pcie_is_device_awake(struct device *dev) +{ + return cnss_pci_is_device_awake(dev); +} + +static inline int pld_pcie_force_wake_release(struct device *dev) +{ + return cnss_pci_force_wake_release(dev); +} + +static inline void pld_pcie_lock_reg_window(struct device *dev, + unsigned long *flags) +{ + cnss_pci_lock_reg_window(dev, flags); +} + +static inline void pld_pcie_unlock_reg_window(struct device *dev, + unsigned long *flags) +{ + cnss_pci_unlock_reg_window(dev, flags); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static inline int pld_pcie_get_pci_slot(struct device *dev) +{ + return cnss_get_pci_slot(dev); +} +#else +static inline int pld_pcie_get_pci_slot(struct device *dev) +{ + return 0; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +static inline struct kobject *pld_pcie_get_wifi_kobj(struct device *dev) +{ + return cnss_get_wifi_kobj(dev); +} +#else +static inline struct kobject *pld_pcie_get_wifi_kobj(struct device *dev) +{ + return NULL; +} +#endif + +static inline int pld_pcie_power_on(struct device *dev) +{ + return cnss_power_up(dev); +} + +static inline int pld_pcie_power_off(struct device *dev) +{ + return cnss_power_down(dev); +} + +static inline int pld_pcie_idle_restart(struct device *dev) +{ + return cnss_idle_restart(dev); +} + +static inline int pld_pcie_idle_shutdown(struct device *dev) +{ + return cnss_idle_shutdown(dev); +} + +static inline int pld_pcie_force_assert_target(struct device *dev) +{ + return cnss_force_fw_assert(dev); +} + +static inline int pld_pcie_get_user_msi_assignment(struct device *dev, + char *user_name, + int *num_vectors, + uint32_t *user_base_data, + uint32_t *base_vector) +{ + return cnss_get_user_msi_assignment(dev, user_name, num_vectors, + user_base_data, base_vector); +} + +static inline int pld_pcie_get_msi_irq(struct device *dev, unsigned int vector) +{ + return cnss_get_msi_irq(dev, vector); +} + +#ifdef WLAN_ONE_MSI_VECTOR +static inline bool pld_pcie_is_one_msi(struct device *dev) +{ + return cnss_is_one_msi(dev); +} +#else +static inline bool pld_pcie_is_one_msi(struct device *dev) +{ + return false; +} +#endif + +static inline void pld_pcie_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ + cnss_get_msi_address(dev, msi_addr_low, msi_addr_high); +} + +static inline int pld_pcie_is_drv_connected(struct device *dev) +{ + return cnss_pci_is_drv_connected(dev); +} + +static inline bool pld_pcie_platform_driver_support(void) +{ + return true; +} + +static inline int pld_pci_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return cnss_thermal_cdev_register(dev, max_state, mon_id); +} + +static inline void pld_pci_thermal_unregister(struct device *dev, + int mon_id) +{ + cnss_thermal_cdev_unregister(dev, mon_id); +} + +static inline int pld_pci_get_thermal_state(struct device *dev, + unsigned long *thermal_state, + int mon_id) +{ + return cnss_get_curr_therm_cdev_state(dev, thermal_state, mon_id); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) +static inline bool pld_pcie_is_direct_link_supported(struct device *dev) +{ + return cnss_get_fw_cap(dev, CNSS_FW_CAP_DIRECT_LINK_SUPPORT); +} + +static inline +int pld_pcie_audio_smmu_map(struct device *dev, phys_addr_t paddr, + dma_addr_t iova, size_t size) +{ + return cnss_audio_smmu_map(dev, paddr, iova, size); +} + +static inline +void pld_pcie_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size) +{ + cnss_audio_smmu_unmap(dev, iova, size); +} +#else +static inline bool pld_pcie_is_direct_link_supported(struct device *dev) +{ + return false; +} + +static inline +int pld_pcie_audio_smmu_map(struct device *dev, phys_addr_t paddr, + dma_addr_t iova, size_t size) +{ + return 0; +} + +static inline +void pld_pcie_audio_smmu_unmap(struct device *dev, dma_addr_t iova, size_t size) +{ +} +#endif +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie_fw_sim.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie_fw_sim.c new file mode 100644 index 0000000000..a90590fb38 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie_fw_sim.c @@ -0,0 +1,818 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include "osif_psoc_sync.h" + +#include "pld_pcie_fw_sim.h" + +#if defined(CONFIG_PLD_PCIE_FW_SIM) || defined(CONFIG_PLD_IPCIE_FW_SIM) + +#ifdef QCA_WIFI_3_0_ADRASTEA +#define CE_COUNT_MAX 12 +#else +#define CE_COUNT_MAX 8 +#endif + +#endif + +#ifdef CONFIG_PLD_IPCIE_FW_SIM +/** + * pld_pcie_fw_sim_probe() - Probe function for PCIE platform driver + * @pdev: PCIE device + * @id: PCIE device ID table + * + * The probe function will be called when PCIE device provided + * in the ID table is detected. + * + * Return: int + */ +static int pld_pcie_fw_sim_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, &pdev->dev, NULL, + PLD_BUS_TYPE_IPCI_FW_SIM); + if (ret) + goto out; + + return pld_context->ops->probe(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM, NULL, NULL); + +out: + return ret; +} + +/** + * pld_pcie_fw_sim_remove() - Remove function for PCIE device + * @pdev: PCIE device + * + * The remove function will be called when PCIE device is disconnected + * + * Return: void + */ +static void pld_pcie_fw_sim_remove(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync); + if (errno) + return; + + osif_psoc_sync_unregister(&pdev->dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_IPCI_FW_SIM); + + pld_del_dev(pld_context, &pdev->dev); + +out: + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); +} + +/** + * pld_pcie_fw_sim_idle_restart_cb() - Perform idle restart + * @pdev: PCIE device + * @id: PCIE device ID + * + * This function will be called if there is an idle restart request + * + * Return: int + */ +static int pld_pcie_fw_sim_idle_restart_cb(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->idle_restart) + return pld_context->ops->idle_restart(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM); + + return -ENODEV; +} + +/** + * pld_pcie_fw_sim_idle_shutdown_cb() - Perform idle shutdown + * @pdev: PCIE device + * + * This function will be called if there is an idle shutdown request + * + * Return: int + */ +static int pld_pcie_fw_sim_idle_shutdown_cb(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + return pld_context->ops->idle_shutdown(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM); + + return -ENODEV; +} + +/** + * pld_pcie_fw_sim_reinit() - SSR re-initialize function for PCIE device + * @pdev: PCIE device + * @id: PCIE device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize pcie device. + * + * Return: int + */ +static int pld_pcie_fw_sim_reinit(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM, NULL, NULL); + + return -ENODEV; +} + +/** + * pld_pcie_fw_sim_shutdown() - SSR shutdown function for PCIE device + * @pdev: PCIE device + * + * During SSR, this function will be called to shutdown PCIE device. + * + * Return: void + */ +static void pld_pcie_fw_sim_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM); +} + +/** + * pld_pcie_fw_sim_crash_shutdown() - Crash shutdown function for PCIE device + * @pdev: PCIE device + * + * This function will be called when a crash is detected, it will shutdown + * the PCIE device. + * + * Return: void + */ +static void pld_pcie_fw_sim_crash_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM); +} + +/** + * pld_pcie_fw_sim_notify_handler() - Modem state notification callback function + * @pdev: PCIE device + * @state: modem power state + * + * This function will be called when there's a modem power state change. + * + * Return: void + */ +static void pld_pcie_fw_sim_notify_handler(struct pci_dev *pdev, int state) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->modem_status) + pld_context->ops->modem_status(&pdev->dev, + PLD_BUS_TYPE_IPCI_FW_SIM, state); +} + +/** + * pld_pcie_fw_sim_uevent() - update wlan driver status callback function + * @pdev: PCIE device + * @status: driver uevent status + * + * This function will be called when platform driver wants to update wlan + * driver's status. + * + * Return: void + */ +static void pld_pcie_fw_sim_uevent(struct pci_dev *pdev, uint32_t status) +{ + struct pld_context *pld_context; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return; + + switch (status) { + case CNSS_RECOVERY: + data.uevent = PLD_FW_RECOVERY_START; + break; + case CNSS_FW_DOWN: + data.uevent = PLD_FW_DOWN; + break; + default: + goto out; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + +out: + return; +} + +/** + * pld_pcie_fw_sim_set_thermal_state: Set thermal state for thermal mitigation + * @dev: device + * @thermal_state: Thermal state set by thermal subsystem + * @mon_id: Thermal cooling device ID + * + * This function will be called when thermal subsystem notifies platform + * driver about change in thermal state. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_fw_sim_set_thermal_state(struct device *dev, + unsigned long thermal_state, + int mon_id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->set_curr_therm_cdev_state) + return pld_context->ops->set_curr_therm_cdev_state(dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + +static struct pci_device_id pld_pcie_fw_sim_id_table[] = { + { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +#ifdef MULTI_IF_NAME +#define PLD_PCIE_FW_SIM_OPS_NAME "pld_ipcie_fw_sim_" MULTI_IF_NAME +#else +#define PLD_PCIE_FW_SIM_OPS_NAME "pld_ipcie_fw_sim" +#endif + +#endif + +#ifdef CONFIG_PLD_PCIE_FW_SIM +/** + * pld_pcie_fw_sim_probe() - Probe function for PCIE platform driver + * @pdev: PCIE device + * @id: PCIE device ID table + * + * The probe function will be called when PCIE device provided + * in the ID table is detected. + * + * Return: int + */ +static int pld_pcie_fw_sim_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, &pdev->dev, NULL, + PLD_BUS_TYPE_PCIE_FW_SIM); + if (ret) + goto out; + + return pld_context->ops->probe(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM, pdev, (void *)id); + +out: + return ret; +} + +/** + * pld_pcie_fw_sim_remove() - Remove function for PCIE device + * @pdev: PCIE device + * + * The remove function will be called when PCIE device is disconnected + * + * Return: void + */ +static void pld_pcie_fw_sim_remove(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync); + if (errno) + return; + + osif_psoc_sync_unregister(&pdev->dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_PCIE_FW_SIM); + + pld_del_dev(pld_context, &pdev->dev); + +out: + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); +} + +/** + * pld_pcie_fw_sim_idle_restart_cb() - Perform idle restart + * @pdev: PCIE device + * @id: PCIE device ID + * + * This function will be called if there is an idle restart request + * + * Return: int + */ +static int pld_pcie_fw_sim_idle_restart_cb(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->idle_restart) + return pld_context->ops->idle_restart(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM); + + return -ENODEV; +} + +/** + * pld_pcie_fw_sim_idle_shutdown_cb() - Perform idle shutdown + * @pdev: PCIE device + * + * This function will be called if there is an idle shutdown request + * + * Return: int + */ +static int pld_pcie_fw_sim_idle_shutdown_cb(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + return pld_context->ops->idle_shutdown(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM); + + return -ENODEV; +} + +/** + * pld_pcie_fw_sim_reinit() - SSR re-initialize function for PCIE device + * @pdev: PCIE device + * @id: PCIE device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize pcie device. + * + * Return: int + */ +static int pld_pcie_fw_sim_reinit(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM, pdev, (void *)id); + + return -ENODEV; +} + +/** + * pld_pcie_fw_sim_shutdown() - SSR shutdown function for PCIE device + * @pdev: PCIE device + * + * During SSR, this function will be called to shutdown PCIE device. + * + * Return: void + */ +static void pld_pcie_fw_sim_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM); +} + +/** + * pld_pcie_fw_sim_crash_shutdown() - Crash shutdown function for PCIE device + * @pdev: PCIE device + * + * This function will be called when a crash is detected, it will shutdown + * the PCIE device. + * + * Return: void + */ +static void pld_pcie_fw_sim_crash_shutdown(struct pci_dev *pdev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM); +} + +/** + * pld_pcie_fw_sim_notify_handler() - Modem state notification callback function + * @pdev: PCIE device + * @state: modem power state + * + * This function will be called when there's a modem power state change. + * + * Return: void + */ +static void pld_pcie_fw_sim_notify_handler(struct pci_dev *pdev, int state) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->modem_status) + pld_context->ops->modem_status(&pdev->dev, + PLD_BUS_TYPE_PCIE_FW_SIM, state); +} + +/** + * pld_pcie_fw_sim_uevent() - update wlan driver status callback function + * @pdev: PCIE device + * @status: driver uevent status + * + * This function will be called when platform driver wants to update wlan + * driver's status. + * + * Return: void + */ +static void pld_pcie_fw_sim_uevent(struct pci_dev *pdev, uint32_t status) +{ + struct pld_context *pld_context; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return; + + switch (status) { + case CNSS_RECOVERY: + data.uevent = PLD_FW_RECOVERY_START; + break; + case CNSS_FW_DOWN: + data.uevent = PLD_FW_DOWN; + break; + default: + goto out; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + +out: + return; +} + +/** + * pld_pcie_fw_sim_set_thermal_state: Set thermal state for thermal mitigation + * @dev: device + * @thermal_state: Thermal state set by thermal subsystem + * @mon_id: Thermal cooling device ID + * + * This function will be called when thermal subsystem notifies platform + * driver about change in thermal state. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_pcie_fw_sim_set_thermal_state(struct device *dev, + unsigned long thermal_state, + int mon_id) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->set_curr_therm_cdev_state) + return pld_context->ops->set_curr_therm_cdev_state(dev, + thermal_state, + mon_id); + + return -ENOTSUPP; +} + +static struct pci_device_id pld_pcie_fw_sim_id_table[] = { + { 0x168c, 0x003c, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x003e, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x0041, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0xabcd, PCI_ANY_ID, PCI_ANY_ID }, + { 0x168c, 0x7021, PCI_ANY_ID, PCI_ANY_ID }, + { 0 } +}; + +#ifdef MULTI_IF_NAME +#define PLD_PCIE_FW_SIM_OPS_NAME "pld_pcie_fw_sim_" MULTI_IF_NAME +#else +#define PLD_PCIE_FW_SIM_OPS_NAME "pld_pcie_fw_sim" +#endif + +#endif + +#if defined(CONFIG_PLD_PCIE_FW_SIM) || defined(CONFIG_PLD_IPCIE_FW_SIM) +struct cnss_wlan_driver pld_pcie_fw_sim_ops = { + .name = PLD_PCIE_FW_SIM_OPS_NAME, + .id_table = pld_pcie_fw_sim_id_table, + .probe = pld_pcie_fw_sim_probe, + .remove = pld_pcie_fw_sim_remove, + .idle_restart = pld_pcie_fw_sim_idle_restart_cb, + .idle_shutdown = pld_pcie_fw_sim_idle_shutdown_cb, + .reinit = pld_pcie_fw_sim_reinit, + .shutdown = pld_pcie_fw_sim_shutdown, + .crash_shutdown = pld_pcie_fw_sim_crash_shutdown, + .modem_status = pld_pcie_fw_sim_notify_handler, + .update_status = pld_pcie_fw_sim_uevent, + .set_therm_cdev_state = pld_pcie_fw_sim_set_thermal_state, +}; + +/** + * pld_pcie_fw_sim_register_driver() - Register PCIE device callback functions + * + * Return: int + */ +int pld_pcie_fw_sim_register_driver(void) +{ + return cnss_fw_sim_wlan_register_driver(&pld_pcie_fw_sim_ops); +} + +/** + * pld_pcie_fw_sim_unregister_driver() - Unregister PCIE device callback + * functions + * + * Return: void + */ +void pld_pcie_fw_sim_unregister_driver(void) +{ + cnss_fw_sim_wlan_unregister_driver(&pld_pcie_fw_sim_ops); +} + +#ifdef CONFIG_SHADOW_V3 +static inline void +pld_pcie_fw_sim_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg, + struct pld_wlan_enable_cfg *config) +{ + cfg->num_shadow_reg_v3_cfg = config->num_shadow_reg_v3_cfg; + cfg->shadow_reg_v3_cfg = (struct cnss_shadow_reg_v3_cfg *) + config->shadow_reg_v3_cfg; +} +#else +static inline void +pld_pcie_fw_sim_populate_shadow_v3_cfg(struct cnss_wlan_enable_cfg *cfg, + struct pld_wlan_enable_cfg *config) +{ +} +#endif + +/** + * pld_pcie_fw_sim_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_fw_sim_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + struct cnss_wlan_enable_cfg cfg; + enum cnss_driver_mode cnss_mode; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct cnss_ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct cnss_ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct cnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + cfg.num_shadow_reg_v2_cfg = config->num_shadow_reg_v2_cfg; + cfg.shadow_reg_v2_cfg = (struct cnss_shadow_reg_v2_cfg *) + config->shadow_reg_v2_cfg; + cfg.rri_over_ddr_cfg_valid = config->rri_over_ddr_cfg_valid; + if (config->rri_over_ddr_cfg_valid) { + cfg.rri_over_ddr_cfg.base_addr_low = + config->rri_over_ddr_cfg.base_addr_low; + cfg.rri_over_ddr_cfg.base_addr_high = + config->rri_over_ddr_cfg.base_addr_high; + } + + pld_pcie_fw_sim_populate_shadow_v3_cfg(&cfg, config); + + switch (mode) { + case PLD_FTM: + cnss_mode = CNSS_FTM; + break; + case PLD_EPPING: + cnss_mode = CNSS_EPPING; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_fw_sim_wlan_enable(dev, &cfg, cnss_mode, host_version); +} + +/** + * pld_pcie_fw_sim_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_fw_sim_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + return cnss_fw_sim_wlan_disable(dev, CNSS_OFF); +} + +/** + * pld_pcie_fw_sim_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_fw_sim_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int ret = 0, i; + struct cnss_soc_info cnss_info = {0}; + + if (!info) + return -ENODEV; + + ret = cnss_fw_sim_get_soc_info(dev, &cnss_info); + if (ret) + return ret; + + info->v_addr = cnss_info.va; + info->p_addr = cnss_info.pa; + info->chip_id = cnss_info.chip_id; + info->chip_family = cnss_info.chip_family; + info->board_id = cnss_info.board_id; + info->soc_id = cnss_info.soc_id; + info->fw_version = cnss_info.fw_version; + strlcpy(info->fw_build_timestamp, cnss_info.fw_build_timestamp, + sizeof(info->fw_build_timestamp)); + info->device_version.family_number = + cnss_info.device_version.family_number; + info->device_version.device_number = + cnss_info.device_version.device_number; + info->device_version.major_version = + cnss_info.device_version.major_version; + info->device_version.minor_version = + cnss_info.device_version.minor_version; + for (i = 0; i < PLD_MAX_DEV_MEM_NUM; i++) { + info->dev_mem_info[i].start = cnss_info.dev_mem_info[i].start; + info->dev_mem_info[i].size = cnss_info.dev_mem_info[i].size; + } + + return 0; +} + +/** + * pld_pcie_fw_sim_get_platform_cap() - Get platform capabilities + * @dev: device + * @cap: buffer to the capabilities + * + * Return capabilities to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_pcie_fw_sim_get_platform_cap(struct device *dev, + struct pld_platform_cap *cap) +{ + int ret = 0; + struct cnss_platform_cap cnss_cap; + + if (!cap) + return -ENODEV; + + ret = cnss_fw_sim_get_platform_cap(dev, &cnss_cap); + if (ret) + return ret; + + memcpy(cap, &cnss_cap, sizeof(*cap)); + return 0; +} + +/* + * pld_pcie_get_irq() - Get irq by ce_id + * @dev: device + * @ce_id: CE id for which irq is requested + * + * Return irq number. + * + * Return: irq number for success + * Non zero failure code for errors + */ +int pld_pcie_fw_sim_get_irq(struct device *dev, int ce_id) +{ + uint32_t msi_data_start; + uint32_t msi_data_count; + uint32_t msi_irq_start; + uint32_t msi_data; + int ret; + + ret = cnss_fw_sim_get_user_msi_assignment(dev, "CE", + &msi_data_count, + &msi_data_start, + &msi_irq_start); + if (ret) + return ret; + + msi_data = (ce_id % msi_data_count) + msi_irq_start; + ret = cnss_fw_sim_get_msi_irq(dev, msi_data); + + return ret; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie_fw_sim.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie_fw_sim.h new file mode 100644 index 0000000000..ac0627fff0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_pcie_fw_sim.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_PCIE_FW_SIM_H__ +#define __PLD_PCIE_FW_SIM_H__ + +#include "pld_internal.h" + +#if !defined(CONFIG_PLD_PCIE_FW_SIM) && !defined(CONFIG_PLD_IPCIE_FW_SIM) + +static inline int pld_pcie_fw_sim_register_driver(void) +{ + return 0; +} + +static inline void pld_pcie_fw_sim_unregister_driver(void) +{ +} + +static inline int pld_pcie_fw_sim_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *cfg, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_wlan_disable(struct device *dev, + enum pld_driver_mode mode) +{ + return 0; +} + +static inline void pld_pcie_fw_sim_link_down(struct device *dev) +{ +} + +static inline int pld_pcie_fw_sim_is_fw_down(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_get_platform_cap(struct device *dev, + struct pld_platform_cap *cap) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_get_soc_info(struct device *dev, + struct pld_soc_info *info) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_get_user_msi_assignment(struct device *dev, + char *user_name, + int *num_vectors, + uint32_t *base_data, + uint32_t *base_vector) +{ + return -EINVAL; +} + +static inline int pld_pcie_fw_sim_get_msi_irq(struct device *dev, + unsigned int vector) +{ + return 0; +} + +static inline void pld_pcie_fw_sim_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ +} + +static inline int pld_pcie_fw_sim_request_irq(struct device *dev, int irq, + irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_data) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_read_config_word(struct device *dev, + int offset, uint16_t *val) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_free_irq(struct device *dev, + unsigned int ce_id, void *ctx) +{ + return 0; +} + +static inline void pld_pcie_fw_sim_enable_irq(struct device *dev, + unsigned int irq) +{ +} + +static inline void pld_pcie_fw_sim_disable_irq(struct device *dev, + unsigned int irq) +{ +} + +static inline int pld_pcie_fw_sim_idle_shutdown(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_idle_restart(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return 0; +} + +static inline void pld_pcie_fw_sim_thermal_unregister(struct device *dev, + int mon_id) +{ +} + +static inline int pld_pcie_fw_sim_get_thermal_state(struct device *dev, + unsigned long *therm_state, + int mon_id) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_exit_power_save(struct device *dev) +{ + return 0; +} + +static inline int pld_pcie_fw_sim_get_irq(struct device *dev, int ce_id) +{ + return 0; +} +#else +#include + +int pld_pcie_fw_sim_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version); +int pld_pcie_fw_sim_wlan_disable(struct device *dev, enum pld_driver_mode mode); +int pld_pcie_fw_sim_register_driver(void); +void pld_pcie_fw_sim_unregister_driver(void); +int pld_pcie_fw_sim_get_platform_cap(struct device *dev, + struct pld_platform_cap *cap); +int pld_pcie_fw_sim_get_soc_info(struct device *dev, struct pld_soc_info *info); +int pld_pcie_fw_sim_get_irq(struct device *dev, int ce_id); + +static inline int pld_pcie_fw_sim_get_user_msi_assignment(struct device *dev, + char *user_name, + int *num_vectors, + uint32_t *base_data, + uint32_t *base_vector) +{ + return cnss_fw_sim_get_user_msi_assignment(dev, user_name, num_vectors, + base_data, base_vector); +} + +static inline int pld_pcie_fw_sim_get_msi_irq(struct device *dev, + unsigned int vector) +{ + return cnss_fw_sim_get_msi_irq(dev, vector); +} + +static inline void pld_pcie_fw_sim_get_msi_address(struct device *dev, + uint32_t *msi_addr_low, + uint32_t *msi_addr_high) +{ + cnss_fw_sim_get_msi_address(dev, msi_addr_low, msi_addr_high); +} + +static inline int pld_pcie_fw_sim_request_irq(struct device *dev, int irq, + irq_handler_t handler, + unsigned long irqflags, + const char *devname, + void *dev_data) +{ + return cnss_fw_sim_request_irq(dev, irq, handler, + irqflags, devname, dev_data); +} + +static inline int pld_pcie_fw_sim_read_config_word(struct device *dev, + int offset, uint16_t *val) +{ + return cnss_fw_sim_read_config_word(dev, offset, val); +} + +static inline int pld_pcie_fw_sim_free_irq(struct device *dev, + int irq, void *dev_data) +{ + return cnss_fw_sim_free_irq(dev, irq, dev_data); +} + +static inline void pld_pcie_fw_sim_enable_irq(struct device *dev, int irq) +{ + cnss_fw_sim_enable_irq(dev, irq); +} + +static inline void pld_pcie_fw_sim_disable_irq(struct device *dev, int irq) +{ + cnss_fw_sim_disable_irq(dev, irq); +} + +static inline int pld_pcie_fw_sim_idle_shutdown(struct device *dev) +{ + return cnss_fw_sim_idle_shutdown(dev); +} + +static inline int pld_pcie_fw_sim_idle_restart(struct device *dev) +{ + return cnss_fw_sim_idle_restart(dev); +} + +static inline int pld_pcie_fw_sim_thermal_register(struct device *dev, + unsigned long max_state, + int mon_id) +{ + return cnss_fw_sim_thermal_cdev_register(dev, max_state, mon_id); +} + +static inline void pld_pcie_fw_sim_thermal_unregister(struct device *dev, + int mon_id) +{ + cnss_fw_sim_thermal_cdev_unregister(dev, mon_id); +} + +static inline int pld_pcie_fw_sim_get_thermal_state(struct device *dev, + unsigned long *therm_state, + int mon_id) +{ + return cnss_fw_sim_get_curr_therm_cdev_state(dev, therm_state, + mon_id); +} + +static inline int pld_pcie_fw_sim_exit_power_save(struct device *dev) +{ + return cnss_fw_sim_exit_power_save(dev); +} + +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_sdio.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_sdio.c new file mode 100644 index 0000000000..2ffc06696e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_sdio.c @@ -0,0 +1,544 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#ifdef CONFIG_PLD_SDIO_CNSS +#include +#endif +#ifdef CONFIG_PLD_SDIO_CNSS2 +#include +#endif + +#include "pld_common.h" +#include "pld_internal.h" +#include "pld_sdio.h" +#include "osif_psoc_sync.h" + +#ifdef CONFIG_SDIO +/* SDIO manufacturer ID and Codes */ +#define MANUFACTURER_ID_AR6320_BASE 0x500 +#define MANUFACTURER_ID_QCA9377_BASE 0x700 +#define MANUFACTURER_ID_QCA9379_BASE 0x800 +#define MANUFACTURER_CODE 0x271 + +#ifndef CONFIG_CNSS +static const struct pld_fw_files fw_files_qca6174_fw_1_1 = { + PREFIX "qwlan11.bin", PREFIX "bdwlan11.bin", PREFIX "otp11.bin", + PREFIX "utf11.bin", PREFIX "utfbd11.bin", PREFIX "qsetup11.bin", + PREFIX "epping11.bin", ""}; +static const struct pld_fw_files fw_files_qca6174_fw_2_0 = { + PREFIX "qwlan20.bin", PREFIX "bdwlan20.bin", PREFIX "otp20.bin", + PREFIX "utf20.bin", PREFIX "utfbd20.bin", PREFIX "qsetup20.bin", + PREFIX "epping20.bin", ""}; +static const struct pld_fw_files fw_files_qca6174_fw_1_3 = { + PREFIX "qwlan13.bin", PREFIX "bdwlan13.bin", PREFIX "otp13.bin", + PREFIX "utf13.bin", PREFIX "utfbd13.bin", PREFIX "qsetup13.bin", + PREFIX "epping13.bin", ""}; +static const struct pld_fw_files fw_files_qca6174_fw_3_0 = { + PREFIX "qwlan30.bin", PREFIX "bdwlan30.bin", PREFIX "otp30.bin", + PREFIX "utf30.bin", PREFIX "utfbd30.bin", PREFIX "qsetup30.bin", + PREFIX "epping30.bin", PREFIX "qwlan30i.bin"}; +static const struct pld_fw_files fw_files_default = { + PREFIX "qwlan.bin", PREFIX "bdwlan.bin", PREFIX "otp.bin", + PREFIX "utf.bin", PREFIX "utfbd.bin", PREFIX "qsetup.bin", + PREFIX "epping.bin", ""}; +#endif + +/** + * pld_sdio_probe() - Probe function for SDIO platform driver + * @sdio_func: pointer to sdio device function + * @id: SDIO device ID table + * + * The probe function will be called when SDIO device provided + * in the ID table is detected. + * + * Return: int + */ +static int pld_sdio_probe(struct sdio_func *sdio_func, + const struct sdio_device_id *id) +{ + struct pld_context *pld_context; + struct device *dev; + int ret; + + pld_context = pld_get_global_context(); + if (!pld_context || !sdio_func) { + ret = -ENODEV; + goto out; + } + + dev = &sdio_func->dev; + ret = pld_add_dev(pld_context, dev, NULL, PLD_BUS_TYPE_SDIO); + if (ret) + goto out; + + return pld_context->ops->probe(dev, PLD_BUS_TYPE_SDIO, + sdio_func, (void *)id); + +out: + return ret; +} + + +/** + * pld_sdio_remove() - Remove function for SDIO device + * @sdio_func: pointer to sdio device function + * + * The remove function will be called when SDIO device is disconnected + * + * Return: void + */ +static void pld_sdio_remove(struct sdio_func *sdio_func) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync); + if (errno) + return; + + osif_psoc_sync_unregister(dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SDIO); + pld_del_dev(pld_context, dev); + +out: + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); +} + +#ifdef CONFIG_PLD_SDIO_CNSS +/** + * pld_sdio_reinit() - SSR re-initialize function for SDIO device + * @sdio_func: pointer to sdio device function + * @id: SDIO device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize SDIO device. + * + * Return: int + */ +static int pld_sdio_reinit(struct sdio_func *sdio_func, + const struct sdio_device_id *id) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SDIO, + sdio_func, (void *)id); + + return -ENODEV; +} + +/** + * pld_sdio_shutdown() - SSR shutdown function for SDIO device + * @sdio_func: pointer to sdio device function + * + * During SSR, this function will be called to shutdown SDIO device. + * + * Return: void + */ +static void pld_sdio_shutdown(struct sdio_func *sdio_func) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SDIO); +} + +/** + * pld_sdio_crash_shutdown() - Crash shutdown function for SDIO device + * @sdio_func: pointer to sdio device function + * + * This function will be called when a crash is detected, it will shutdown + * the SDIO device. + * + * Return: void + */ +static void pld_sdio_crash_shutdown(struct sdio_func *sdio_func) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SDIO); +} + +#endif + +#ifdef CONFIG_PM +/** + * pld_sdio_suspend() - Suspend callback function for power management + * @dev: SDIO device + * + * This function is to suspend the SDIO device when power management is + * enabled. + * + * Return: void + */ +static int pld_sdio_suspend(struct device *dev) +{ + struct pld_context *pld_context; + pm_message_t state = { .event = PM_EVENT_SUSPEND }; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, + PLD_BUS_TYPE_SDIO, state); +} + +/** + * pld_sdio_resume() - Resume callback function for power management + * @dev: SDIO device + * + * This function is to resume the SDIO device when power management is + * enabled. + * + * Return: void + */ +static int pld_sdio_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_SDIO); +} +#endif + +static struct sdio_device_id pld_sdio_id_table[] = { + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_AR6320_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9377_BASE | 0xF))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x0))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x1))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x2))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x3))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x4))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x5))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x6))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x7))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x8))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0x9))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xA))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xB))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xC))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xD))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xE))}, + {SDIO_DEVICE(MANUFACTURER_CODE, (MANUFACTURER_ID_QCA9379_BASE | 0xF))}, + {}, +}; + +#ifdef CONFIG_PLD_SDIO_CNSS2 +/** + * pld_sdio_reinit() - SSR re-initialize function for SDIO device + * @sdio_func: pointer to sdio device function + * @id: SDIO device ID + * + * During subsystem restart(SSR), this function will be called to + * re-initialize SDIO device. + * + * Return: int + */ +static int pld_sdio_reinit(struct sdio_func *sdio_func, + const struct sdio_device_id *id) +{ + /* TODO */ + return -ENODEV; +} + +/** + * pld_sdio_shutdown() - SSR shutdown function for SDIO device + * @sdio_func: pointer to sdio device function + * + * During SSR, this function will be called to shutdown SDIO device. + * + * Return: void + */ +static void pld_sdio_shutdown(struct sdio_func *sdio_func) +{ + /* TODO */ +} + +/** + * pld_sdio_crash_shutdown() - Crash shutdown function for SDIO device + * @sdio_func: pointer to sdio device function + * + * This function will be called when a crash is detected, it will shutdown + * the SDIO device. + * + * Return: void + */ +static void pld_sdio_crash_shutdown(struct sdio_func *sdio_func) +{ + /* TODO */ +} + +static void pld_sdio_uevent(struct sdio_func *sdio_func, uint32_t status) +{ + struct pld_context *pld_context; + struct device *dev = &sdio_func->dev; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + switch (status) { + case CNSS_RECOVERY: + data.uevent = PLD_FW_RECOVERY_START; + break; + case CNSS_FW_DOWN: + data.uevent = PLD_FW_DOWN; + break; + default: + goto out; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(dev, &data); +out: + return; +} + +struct cnss_sdio_wlan_driver pld_sdio_ops = { + .name = "pld_sdio", + .id_table = pld_sdio_id_table, + .probe = pld_sdio_probe, + .remove = pld_sdio_remove, + .reinit = pld_sdio_reinit, + .shutdown = pld_sdio_shutdown, + .crash_shutdown = pld_sdio_crash_shutdown, + .update_status = pld_sdio_uevent, +#ifdef CONFIG_PM + .suspend = pld_sdio_suspend, + .resume = pld_sdio_resume, +#endif +}; + +int pld_sdio_register_driver(void) +{ + return cnss_sdio_wlan_register_driver(&pld_sdio_ops); +} + +void pld_sdio_unregister_driver(void) +{ + cnss_sdio_wlan_unregister_driver(&pld_sdio_ops); +} + +int pld_sdio_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct cnss_wlan_enable_cfg cfg; + enum cnss_driver_mode cnss_mode; + + switch (mode) { + case PLD_FTM: + cnss_mode = CNSS_FTM; + break; + case PLD_EPPING: + cnss_mode = CNSS_EPPING; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version); +} + +#else + +#ifdef CONFIG_PM +static const struct dev_pm_ops pld_device_pm_ops = { + .suspend = pld_sdio_suspend, + .resume = pld_sdio_resume, +}; +#endif + +struct sdio_driver pld_sdio_ops = { + .name = "pld_sdio", + .id_table = pld_sdio_id_table, + .probe = pld_sdio_probe, + .remove = pld_sdio_remove, +#if defined(CONFIG_PM) + .drv = { + .pm = &pld_device_pm_ops, + } +#endif +}; + +int pld_sdio_register_driver(void) +{ + return sdio_register_driver(&pld_sdio_ops); +} + +void pld_sdio_unregister_driver(void) +{ + sdio_unregister_driver(&pld_sdio_ops); +} +#endif + +#ifdef CONFIG_PLD_SDIO_CNSS +#ifdef CONFIG_TUFELLO_DUAL_FW_SUPPORT +static inline int pld_sdio_is_tufello_dual_fw_supported(void) +{ + return 1; +} +#else +static inline int pld_sdio_is_tufello_dual_fw_supported(void) +{ + return 0; +#endif +} + +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + int ret = 0; + struct cnss_fw_files cnss_fw_files; + + if (!pfw_files) + return -ENODEV; + + memset(pfw_files, 0, sizeof(*pfw_files)); + + if (target_version == PLD_QCA9377_REV1_1_VERSION) { + cnss_get_qca9377_fw_files(&cnss_fw_files, PLD_MAX_FILE_NAME, + pld_sdio_is_tufello_dual_fw_supported()); + } else { + ret = cnss_get_fw_files_for_target(&cnss_fw_files, + target_type, target_version); + } + if (0 != ret) + return ret; + + snprintf(pfw_files->image_file, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.image_file); + snprintf(pfw_files->board_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.board_data); + snprintf(pfw_files->otp_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.otp_data); + snprintf(pfw_files->utf_file, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.utf_file); + snprintf(pfw_files->utf_board_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.utf_board_data); + snprintf(pfw_files->epping_file, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.epping_file); + snprintf(pfw_files->evicted_data, PLD_MAX_FILE_NAME, PREFIX "%s", + cnss_fw_files.evicted_data); + + return ret; +} +#else +#ifdef CONFIG_TUFELLO_DUAL_FW_SUPPORT +static inline void get_qca9377_fw_files(struct pld_fw_files *pfw_files, + u32 size) +{ + memcpy(pfw_files, &fw_files_default, sizeof(*pfw_files)); +} +#else +static inline void get_qca9377_fw_files(struct pld_fw_files *pfw_files, + u32 size) +{ + memcpy(pfw_files, &fw_files_qca6174_fw_3_0, sizeof(*pfw_files)); +} +#endif + +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + if (!pfw_files) + return -ENODEV; + + switch (target_version) { + case PLD_AR6320_REV1_VERSION: + case PLD_AR6320_REV1_1_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_1_1, sizeof(*pfw_files)); + break; + case PLD_AR6320_REV1_3_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_1_3, sizeof(*pfw_files)); + break; + case PLD_AR6320_REV2_1_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_2_0, sizeof(*pfw_files)); + break; + case PLD_AR6320_REV3_VERSION: + case PLD_AR6320_REV3_2_VERSION: + memcpy(pfw_files, &fw_files_qca6174_fw_3_0, sizeof(*pfw_files)); + break; + case PLD_QCA9377_REV1_1_VERSION: + case PLD_QCA9379_REV1_VERSION: + get_qca9377_fw_files(pfw_files, sizeof(*pfw_files)); + break; + default: + memcpy(pfw_files, &fw_files_default, sizeof(*pfw_files)); + pr_err("%s version mismatch 0x%X ", + __func__, target_version); + break; + } + + return 0; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_sdio.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_sdio.h new file mode 100644 index 0000000000..33a30962be --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_sdio.h @@ -0,0 +1,333 @@ +/* + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_SDIO_H__ +#define __PLD_SDIO_H__ + +#ifdef CONFIG_PLD_SDIO_CNSS +#include +#endif +#include "pld_common.h" + +#ifdef DYNAMIC_SINGLE_CHIP +#define PREFIX DYNAMIC_SINGLE_CHIP "/" +#else + +#ifdef MULTI_IF_NAME +#define PREFIX MULTI_IF_NAME "/" +#else +#define PREFIX "" +#endif + +#endif + +#define PLD_QCA9377_REV1_1_VERSION 0x5020001 +#define PLD_QCA9379_REV1_VERSION 0x5040000 + +#ifndef CONFIG_CNSS +#define PLD_AR6004_VERSION_REV1_3 0x31c8088a +#define PLD_AR9888_REV2_VERSION 0x4100016c +#define PLD_AR6320_REV1_VERSION 0x5000000 +#define PLD_AR6320_REV1_1_VERSION 0x5000001 +#define PLD_AR6320_REV1_3_VERSION 0x5000003 +#define PLD_AR6320_REV2_1_VERSION 0x5010000 +#define PLD_AR6320_REV3_VERSION 0x5020000 +#define PLD_AR6320_REV3_2_VERSION 0x5030000 +#define PLD_AR6320_DEV_VERSION 0x1000000 + + +#endif + +#ifndef CONFIG_SDIO +static inline int pld_sdio_register_driver(void) +{ + return 0; +} + +static inline void pld_sdio_unregister_driver(void) +{ +} + +static inline +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + return 0; +} +static inline uint8_t *pld_sdio_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} +#else +/** + * pld_sdio_register_driver() - Register SDIO device callback functions + * + * Return: int + */ +int pld_sdio_register_driver(void); + +/** + * pld_sdio_unregister_driver() - Unregister SDIO device callback functions + * + * Return: void + */ +void pld_sdio_unregister_driver(void); + +/** + * pld_sdio_get_fw_files_for_target() - Get FW file names + * @pfw_files: buffer for FW file names + * @target_type: target type + * @target_version: target version + * + * Return target specific FW file names to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_sdio_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version); +#ifdef CONFIG_CNSS +static inline uint8_t *pld_sdio_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + return cnss_common_get_wlan_mac_address(dev, num); +} +#else +static inline uint8_t *pld_sdio_get_wlan_mac_address(struct device *dev, + uint32_t *num) +{ + *num = 0; + return NULL; +} +#endif +#endif + +#ifdef CONFIG_PLD_SDIO_CNSS +static inline void *pld_sdio_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + return cnss_common_get_virt_ramdump_mem(dev, size); +} + +static inline void pld_sdio_release_virt_ramdump_mem(void *address) +{ +} + +static inline void pld_sdio_device_crashed(struct device *dev) +{ + cnss_common_device_crashed(dev); +} +static inline bool pld_sdio_is_fw_dump_skipped(void) +{ + return cnss_get_restart_level() == CNSS_RESET_SUBSYS_COUPLED; +} + +static inline void pld_sdio_device_self_recovery(struct device *dev) +{ + cnss_common_device_self_recovery(dev); +} + +static inline bool pld_sdio_platform_driver_support(void) +{ + return true; +} +#else +static inline void *pld_sdio_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + size_t length = 0; + int flags = GFP_KERNEL; + + length = TOTAL_DUMP_SIZE; + + if (!size) + return NULL; + + *size = (unsigned long)length; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + return kzalloc(length, flags); +} + +static inline void pld_sdio_release_virt_ramdump_mem(void *address) +{ + kfree(address); +} + +static inline void pld_sdio_device_crashed(struct device *dev) +{ +} +static inline bool pld_sdio_is_fw_dump_skipped(void) +{ + return false; +} + +static inline void pld_sdio_device_self_recovery(struct device *dev) +{ +} + +static inline bool pld_sdio_platform_driver_support(void) +{ + return false; +} +#endif + +#ifdef CONFIG_PLD_SDIO_CNSS +/** + * pld_hif_sdio_get_virt_ramdump_mem() - Get virtual ramdump memory + * @dev: device + * @size: buffer to virtual memory size + * + * Return: virtual ramdump memory address + */ +static inline void *pld_hif_sdio_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + return cnss_common_get_virt_ramdump_mem(dev, size); +} + +/** + * pld_hif_sdio_release_ramdump_mem() - Release virtual ramdump memory + * @address: virtual ramdump memory address + * + * Return: void + */ +static inline void pld_hif_sdio_release_ramdump_mem(unsigned long *address) +{ +} +#else +#ifdef CONFIG_PLD_SDIO_CNSS2 +#include + +/** + * pld_sdio_get_sdio_al_client_handle() - Get the sdio al client handle + * @func: SDIO function pointer + * + * Return: On success return client handle from al via cnss, else NULL + */ +static inline struct sdio_al_client_handle *pld_sdio_get_sdio_al_client_handle +( +struct sdio_func *func +) +{ + if (!func) + return NULL; + + return cnss_sdio_wlan_get_sdio_al_client_handle(func); +} + +/** + * pld_sdio_register_sdio_al_channel() - Register channel with sdio al + * @al_client: SDIO al client handle + * @ch_data: SDIO client channel data + * + * Return: Channel handle on success, else null + */ +static inline struct sdio_al_channel_handle *pld_sdio_register_sdio_al_channel +( +struct sdio_al_client_handle *al_client, +struct sdio_al_channel_data *ch_data +) +{ + if (!al_client || !ch_data) + return NULL; + + return cnss_sdio_wlan_register_sdio_al_channel(ch_data); +} + +/** + * pld_sdio_unregister_sdio_al_channel() - Unregister the sdio al channel + * @ch_handle: SDIO al channel handle + * + * Return: None + */ +static inline void pld_sdio_unregister_sdio_al_channel +( +struct sdio_al_channel_handle *ch_handle +) +{ + cnss_sdio_wlan_unregister_sdio_al_channel(ch_handle); +} + +/** + * pld_sdio_wlan_enable() - Enable WLAN + * @dev: device + * @config: NA + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_sdio_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +#else +static inline int pld_sdio_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} +#endif /* CONFIG_PLD_SDIO_CNSS2 */ + +/** + * pld_hif_sdio_get_virt_ramdump_mem() - Get virtual ramdump memory + * @dev: device + * @size: buffer to virtual memory size + * + * Return: virtual ramdump memory address + */ +static inline void *pld_hif_sdio_get_virt_ramdump_mem(struct device *dev, + unsigned long *size) +{ + size_t length = 0; + int flags = GFP_KERNEL; + + length = TOTAL_DUMP_SIZE; + + if (size) + *size = (unsigned long)length; + + if (in_interrupt() || irqs_disabled() || in_atomic()) + flags = GFP_ATOMIC; + + return kzalloc(length, flags); +} + +/** + * pld_hif_sdio_release_ramdump_mem() - Release virtual ramdump memory + * @address: virtual ramdump memory address + * + * Return: void + */ +static inline void pld_hif_sdio_release_ramdump_mem(unsigned long *address) +{ + if (address) + kfree(address); +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc.c new file mode 100644 index 0000000000..17a689253a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc.c @@ -0,0 +1,502 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_CNSS_OUT_OF_TREE +#ifdef CONFIG_PLD_SNOC_ICNSS +#ifdef CONFIG_PLD_SNOC_ICNSS2 +#include "icnss2.h" +#else +#include "icnss.h" +#endif +#endif +#else +#ifdef CONFIG_PLD_SNOC_ICNSS +#ifdef CONFIG_PLD_SNOC_ICNSS2 +#include +#else +#include +#endif +#endif +#endif + +#include "pld_internal.h" +#include "pld_snoc.h" +#include "osif_psoc_sync.h" + +#ifdef CONFIG_PLD_SNOC_ICNSS + +#define ADRASTEA_DEVICE_ID 0xabcd + +/** + * pld_snoc_idle_restart_cb() - Perform idle restart + * @dev: platform device + * + * This function will be called if there is an idle restart request + * + * Return: int + **/ +static int pld_snoc_idle_restart_cb(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->idle_restart) + return pld_context->ops->idle_restart(dev, PLD_BUS_TYPE_SNOC); + + return -ENODEV; +} + +/** + * pld_snoc_idle_shutdown_cb() - Perform idle shutdown + * @dev: PCIE device + * + * This function will be called if there is an idle shutdown request + * + * Return: int + */ +static int pld_snoc_idle_shutdown_cb(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + return pld_context->ops->idle_shutdown(dev, PLD_BUS_TYPE_SNOC); + + return -ENODEV; +} + +/** + * pld_snoc_probe() - Probe function for platform driver + * @dev: device + * + * The probe function will be called when platform device + * is detected. + * + * Return: int + */ +static int pld_snoc_probe(struct device *dev) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, dev, NULL, PLD_BUS_TYPE_SNOC); + if (ret) + goto out; + + return pld_context->ops->probe(dev, PLD_BUS_TYPE_SNOC, + NULL, NULL); + +out: + return ret; +} + +/** + * pld_snoc_remove() - Remove function for platform device + * @dev: device + * + * The remove function will be called when platform device + * is disconnected + * + * Return: void + */ +static void pld_snoc_remove(struct device *dev) +{ + struct pld_context *pld_context; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(dev, &psoc_sync); + if (errno) + return; + + osif_psoc_sync_unregister(dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC); + + pld_del_dev(pld_context, dev); + +out: + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); +} + +/** + * pld_snoc_reinit() - SSR re-initialize function for platform device + * @dev: device + * + * During subsystem restart(SSR), this function will be called to + * re-initialize platform device. + * + * Return: int + */ +static int pld_snoc_reinit(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SNOC, + NULL, NULL); + + return -ENODEV; +} + +/** + * pld_snoc_shutdown() - SSR shutdown function for platform device + * @dev: device + * + * During SSR, this function will be called to shutdown platform device. + * + * Return: void + */ +static void pld_snoc_shutdown(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SNOC); +} + +/** + * pld_snoc_crash_shutdown() - Crash shutdown function for platform device + * @dev: device + * + * This function will be called when a crash is detected, it will shutdown + * platform device. + * + * Return: void + */ +static void pld_snoc_crash_shutdown(void *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SNOC); +} + +/** + * pld_snoc_pm_suspend() - PM suspend callback function for power management + * @dev: device + * + * This function is to suspend the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_snoc_pm_suspend(struct device *dev) +{ + struct pld_context *pld_context; + pm_message_t state; + + state.event = PM_EVENT_SUSPEND; + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, PLD_BUS_TYPE_SNOC, state); +} + +/** + * pld_snoc_pm_resume() - PM resume callback function for power management + * @dev: device + * + * This function is to resume the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_snoc_pm_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_SNOC); +} + +/** + * pld_snoc_suspend_noirq() - Complete the actions started by suspend() + * @dev: device + * + * Complete the actions started by suspend(). Carry out any + * additional operations required for suspending the device that might be + * racing with its driver's interrupt handler, which is guaranteed not to + * run while suspend_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_snoc_suspend_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->suspend_noirq) + return pld_context->ops->suspend_noirq(dev, PLD_BUS_TYPE_SNOC); + return 0; +} + +/** + * pld_snoc_resume_noirq() - Prepare for the execution of resume() + * @dev: device + * + * Prepare for the execution of resume() by carrying out any + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_snoc_resume_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->resume_noirq) + return pld_context->ops->resume_noirq(dev, PLD_BUS_TYPE_SNOC); + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static int pld_update_hang_evt_data(struct icnss_uevent_hang_data *evt_data, + struct pld_uevent_data *data) +{ + if (!evt_data || !data) + return -EINVAL; + + data->hang_data.hang_event_data = evt_data->hang_event_data; + data->hang_data.hang_event_data_len = evt_data->hang_event_data_len; + return 0; +} + +static int pld_snoc_uevent(struct device *dev, + struct icnss_uevent_data *uevent) +{ + struct pld_context *pld_context; + struct icnss_uevent_fw_down_data *fw_down_data = NULL; + struct icnss_uevent_hang_data *hang_data = NULL; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (!pld_context->ops->uevent) + goto out; + + if (!uevent) + return -EINVAL; + + switch (uevent->uevent) { + case ICNSS_UEVENT_FW_CRASHED: + data.uevent = PLD_FW_CRASHED; + break; + case ICNSS_UEVENT_FW_DOWN: + if (!uevent->data) + return -EINVAL; + fw_down_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_FW_DOWN; + data.fw_down.crashed = fw_down_data->crashed; + break; + case ICNSS_UEVENT_HANG_DATA: + if (!uevent->data) + return -EINVAL; + hang_data = (struct icnss_uevent_hang_data *)uevent->data; + data.uevent = PLD_FW_HANG_EVENT; + pld_update_hang_evt_data(hang_data, &data); + break; + default: + goto out; + } + + pld_context->ops->uevent(dev, &data); +out: + return 0; +} +#else +static int pld_snoc_uevent(struct device *dev, + struct icnss_uevent_data *uevent) +{ + struct pld_context *pld_context; + struct icnss_uevent_fw_down_data *fw_down_data = NULL; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (!pld_context->ops->uevent) + goto out; + + if (!uevent) + return -EINVAL; + + switch (uevent->uevent) { + case ICNSS_UEVENT_FW_CRASHED: + data.uevent = PLD_FW_CRASHED; + break; + case ICNSS_UEVENT_FW_DOWN: + if (!uevent->data) + return -EINVAL; + fw_down_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_FW_DOWN; + data.fw_down.crashed = fw_down_data->crashed; + break; + default: + goto out; + } + + pld_context->ops->uevent(dev, &data); +out: + return 0; +} +#endif + +#ifdef MULTI_IF_NAME +#define PLD_SNOC_OPS_NAME "pld_snoc_" MULTI_IF_NAME +#else +#define PLD_SNOC_OPS_NAME "pld_snoc" +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) +static struct device_info pld_snoc_dev_info[] = { + { "ADRASTEA", ADRASTEA_DEVICE_ID }, + { 0 } +}; +#endif + +struct icnss_driver_ops pld_snoc_ops = { + .name = PLD_SNOC_OPS_NAME, +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)) + .dev_info = pld_snoc_dev_info, +#endif + .probe = pld_snoc_probe, + .remove = pld_snoc_remove, + .shutdown = pld_snoc_shutdown, + .reinit = pld_snoc_reinit, + .crash_shutdown = pld_snoc_crash_shutdown, + .pm_suspend = pld_snoc_pm_suspend, + .pm_resume = pld_snoc_pm_resume, + .suspend_noirq = pld_snoc_suspend_noirq, + .resume_noirq = pld_snoc_resume_noirq, + .uevent = pld_snoc_uevent, + .idle_restart = pld_snoc_idle_restart_cb, + .idle_shutdown = pld_snoc_idle_shutdown_cb, +}; + +int pld_snoc_register_driver(void) +{ + return icnss_register_driver(&pld_snoc_ops); +} + +void pld_snoc_unregister_driver(void) +{ + icnss_unregister_driver(&pld_snoc_ops); +} + +int pld_snoc_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct icnss_wlan_enable_cfg cfg; + enum icnss_driver_mode icnss_mode; + + if (!dev) + return -ENODEV; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + + switch (mode) { + case PLD_FTM: + icnss_mode = ICNSS_FTM; + break; + case PLD_EPPING: + icnss_mode = ICNSS_EPPING; + break; + default: + icnss_mode = ICNSS_MISSION; + break; + } + + return icnss_wlan_enable(dev, &cfg, icnss_mode, host_version); +} + +int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + if (!dev) + return -ENODEV; + + return icnss_wlan_disable(dev, ICNSS_OFF); +} + +int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int errno; + struct icnss_soc_info icnss_info = {0}; + + if (!info || !dev) + return -ENODEV; + + errno = icnss_get_soc_info(dev, &icnss_info); + if (errno) + return errno; + + info->v_addr = icnss_info.v_addr; + info->p_addr = icnss_info.p_addr; + info->chip_id = icnss_info.chip_id; + info->chip_family = icnss_info.chip_family; + info->board_id = icnss_info.board_id; + info->soc_id = icnss_info.soc_id; + info->fw_version = icnss_info.fw_version; + strlcpy(info->fw_build_timestamp, icnss_info.fw_build_timestamp, + sizeof(info->fw_build_timestamp)); + + return 0; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc.h new file mode 100644 index 0000000000..cd6ecb826c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc.h @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_SNOC_H__ +#define __PLD_SNOC_H__ + +#ifdef CONFIG_CNSS_OUT_OF_TREE +#ifdef CONFIG_PLD_SNOC_ICNSS +#ifdef CONFIG_PLD_SNOC_ICNSS2 +#include "icnss2.h" +#else +#include "icnss.h" +#endif +#endif +#else +#ifdef CONFIG_PLD_SNOC_ICNSS +#ifdef CONFIG_PLD_SNOC_ICNSS2 +#include +#else +#include +#endif +#endif +#endif + +#include "pld_internal.h" + +#ifndef CONFIG_PLD_SNOC_ICNSS +static inline int pld_snoc_register_driver(void) +{ + return 0; +} + +static inline void pld_snoc_unregister_driver(void) +{ +} +static inline int pld_snoc_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + return 0; +} +static inline int pld_snoc_wlan_disable(struct device *dev, + enum pld_driver_mode mode) +{ + return 0; +} +static inline int pld_snoc_ce_request_irq(struct device *dev, + unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, + const char *name, void *ctx) +{ + return 0; +} +static inline int pld_snoc_ce_free_irq(struct device *dev, + unsigned int ce_id, void *ctx) +{ + return 0; +} +static inline void pld_snoc_enable_irq(struct device *dev, unsigned int ce_id) +{ +} +static inline void pld_snoc_disable_irq(struct device *dev, unsigned int ce_id) +{ +} +static inline int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + return 0; +} +static inline int pld_snoc_get_ce_id(struct device *dev, int irq) +{ + return 0; +} +static inline int pld_snoc_power_on(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_power_off(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_get_irq(struct device *dev, int ce_id) +{ + return 0; +} +static inline int pld_snoc_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return 0; +} +static inline int pld_snoc_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static inline void *pld_snoc_smmu_get_domain(struct device *dev) +{ + return NULL; +} + +#else +static inline void *pld_snoc_smmu_get_mapping(struct device *dev) +{ + return NULL; +} +#endif + +static inline int pld_snoc_idle_restart(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_idle_shutdown(struct device *dev) +{ + return 0; +} + +static inline unsigned long pld_snoc_get_device_config(void) +{ + return 0; +} + +static inline int pld_snoc_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + return 0; +} + +static inline int pld_snoc_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return 0; +} + +static inline +unsigned int pld_snoc_socinfo_get_serial_number(struct device *dev) +{ + return 0; +} +static inline int pld_snoc_is_qmi_disable(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_is_fw_down(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_is_low_power_mode(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + return 0; +} +static inline int pld_snoc_force_assert_target(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_is_pdr(void) +{ + return 0; +} + +static inline int pld_snoc_is_fw_rejuvenate(void) +{ + return 0; +} + +static inline void pld_snoc_block_shutdown(bool status) +{ +} + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM +static inline int +pld_snoc_get_audio_wlan_timestamp(struct device *dev, + enum pld_wlan_time_sync_trigger_type type, + uint64_t *ts) +{ + return 0; +} +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ + +#else +/** + * pld_snoc_register_driver() - Register platform device callback functions + * + * Return: int + */ +int pld_snoc_register_driver(void); + +/** + * pld_snoc_unregister_driver() - Unregister platform device callback functions + * + * Return: void + */ +void pld_snoc_unregister_driver(void); + +/** + * pld_snoc_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); + +/** + * pld_snoc_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_wlan_disable(struct device *dev, enum pld_driver_mode mode); + +/** + * pld_snoc_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_get_soc_info(struct device *dev, struct pld_soc_info *info); + +#ifdef FEATURE_WLAN_TIME_SYNC_FTM +/** + * pld_snoc_get_audio_wlan_timestamp() - Get audio timestamp + * @dev: device + * @type: trigger type + * @ts: timestamp + * + * Return audio timestamp to the ts. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static inline int +pld_snoc_get_audio_wlan_timestamp(struct device *dev, + enum pld_wlan_time_sync_trigger_type type, + uint64_t *ts) +{ + if (!dev) + return -ENODEV; + + return 0; +} +#endif /* FEATURE_WLAN_TIME_SYNC_FTM */ +static inline int pld_snoc_ce_request_irq(struct device *dev, + unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, + const char *name, void *ctx) +{ + if (!dev) + return -ENODEV; + + return icnss_ce_request_irq(dev, ce_id, handler, flags, name, ctx); +} + +static inline int pld_snoc_ce_free_irq(struct device *dev, + unsigned int ce_id, void *ctx) +{ + if (!dev) + return -ENODEV; + + return icnss_ce_free_irq(dev, ce_id, ctx); +} + +static inline void pld_snoc_enable_irq(struct device *dev, unsigned int ce_id) +{ + if (dev) + icnss_enable_irq(dev, ce_id); +} + +static inline void pld_snoc_disable_irq(struct device *dev, unsigned int ce_id) +{ + if (dev) + icnss_disable_irq(dev, ce_id); +} + +static inline int pld_snoc_get_ce_id(struct device *dev, int irq) +{ + if (!dev) + return -ENODEV; + + return icnss_get_ce_id(dev, irq); +} + +static inline int pld_snoc_get_irq(struct device *dev, int ce_id) +{ + if (!dev) + return -ENODEV; + + return icnss_get_irq(dev, ce_id); +} + +static inline int pld_snoc_power_on(struct device *dev) +{ + return icnss_power_on(dev); +} +static inline int pld_snoc_power_off(struct device *dev) +{ + return icnss_power_off(dev); +} +static inline int pld_snoc_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return icnss_athdiag_read(dev, offset, memtype, datalen, output); +} +static inline int pld_snoc_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return icnss_athdiag_write(dev, offset, memtype, datalen, input); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)) +static inline void *pld_snoc_smmu_get_domain(struct device *dev) +{ + return icnss_smmu_get_domain(dev); +} + +#else +static inline void *pld_snoc_smmu_get_mapping(struct device *dev) +{ + return icnss_smmu_get_mapping(dev); +} +#endif + +static inline int pld_snoc_smmu_map(struct device *dev, phys_addr_t paddr, + uint32_t *iova_addr, size_t size) +{ + return icnss_smmu_map(dev, paddr, iova_addr, size); +} + +#ifdef CONFIG_SMMU_S1_UNMAP +static inline int pld_snoc_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return icnss_smmu_unmap(dev, iova_addr, size); +} + +#else +static inline int pld_snoc_smmu_unmap(struct device *dev, + uint32_t iova_addr, size_t size) +{ + return 0; +} +#endif + +static inline +unsigned int pld_snoc_socinfo_get_serial_number(struct device *dev) +{ + return icnss_socinfo_get_serial_number(dev); +} + +static inline int pld_snoc_is_fw_down(struct device *dev) +{ + return icnss_is_fw_down(); +} + +#ifdef CONFIG_ENABLE_LOW_POWER_MODE +static inline int pld_snoc_is_low_power_mode(struct device *dev) +{ + return icnss_is_low_power(); +} +#else +static inline int pld_snoc_is_low_power_mode(struct device *dev) +{ + return 0; +} +#endif + +static inline int pld_snoc_is_qmi_disable(struct device *dev) +{ + if (!dev) + return -ENODEV; + + return icnss_is_qmi_disable(dev); +} + +static inline int pld_snoc_set_fw_log_mode(struct device *dev, u8 fw_log_mode) +{ + if (!dev) + return -ENODEV; + + return icnss_set_fw_log_mode(dev, fw_log_mode); +} + +static inline int pld_snoc_force_assert_target(struct device *dev) +{ + return icnss_trigger_recovery(dev); +} + +static inline int pld_snoc_is_pdr(void) +{ + return icnss_is_pdr(); +} + +static inline int pld_snoc_is_fw_rejuvenate(void) +{ + return icnss_is_rejuvenate(); +} + +static inline void pld_snoc_block_shutdown(bool status) +{ + icnss_block_shutdown(status); +} + +static inline int pld_snoc_idle_restart(struct device *dev) +{ + return icnss_idle_restart(dev); +} + +static inline int pld_snoc_idle_shutdown(struct device *dev) +{ + return icnss_idle_shutdown(dev); +} + +static inline unsigned long pld_snoc_get_device_config(void) +{ + return icnss_get_device_config(); +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc_fw_sim.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc_fw_sim.c new file mode 100644 index 0000000000..6287a9ec80 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc_fw_sim.c @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "pld_snoc_fw_sim.h" + +#ifdef CONFIG_PLD_SNOC_FW_SIM +/** + * pld_snoc_fw_sim_probe() - Probe function for platform driver + * @dev: device + * + * The probe function will be called when platform device + * is detected. + * + * Return: int + */ +static int pld_snoc_fw_sim_probe(struct device *dev) +{ + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, dev, NULL, PLD_BUS_TYPE_SNOC_FW_SIM); + if (ret) + goto out; + + return pld_context->ops->probe(dev, PLD_BUS_TYPE_SNOC_FW_SIM, + NULL, NULL); + +out: + return ret; +} + +/** + * pld_snoc_fw_sim_remove() - Remove function for platform device + * @dev: device + * + * The remove function will be called when platform device + * is disconnected + * + * Return: void + */ +static void pld_snoc_fw_sim_remove(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + + if (!pld_context) + return; + + pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC_FW_SIM); + + pld_del_dev(pld_context, dev); +} + +/** + * pld_snoc_fw_sim_reinit() - SSR re-initialize function for platform device + * @dev: device + * + * During subsystem restart(SSR), this function will be called to + * re-initialize platform device. + * + * Return: int + */ +static int pld_snoc_fw_sim_reinit(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SNOC_FW_SIM, + NULL, NULL); + + return -ENODEV; +} + +/** + * pld_snoc_fw_sim_shutdown() - SSR shutdown function for platform device + * @dev: device + * + * During SSR, this function will be called to shutdown platform device. + * + * Return: void + */ +static void pld_snoc_fw_sim_shutdown(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SNOC_FW_SIM); +} + +/** + * pld_snoc_fw_sim_crash_shutdown() -Crash shutdown function for platform device + * @dev: device + * + * This function will be called when a crash is detected, it will shutdown + * platform device. + * + * Return: void + */ +static void pld_snoc_fw_sim_crash_shutdown(void *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (pld_context->ops->crash_shutdown) + pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SNOC_FW_SIM); +} + +/** + * pld_snoc_fw_sim_pm_suspend() - PM suspend callback function for power + * management + * @dev: device + * + * This function is to suspend the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_snoc_fw_sim_pm_suspend(struct device *dev) +{ + struct pld_context *pld_context; + pm_message_t state; + + state.event = PM_EVENT_SUSPEND; + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(dev, PLD_BUS_TYPE_SNOC_FW_SIM, state); +} + +/** + * pld_snoc_fw_sim_pm_resume() -PM resume callback function for power management + * @dev: device + * + * This function is to resume the platform device when power management + * is enabled. + * + * Return: void + */ +static int pld_snoc_fw_sim_pm_resume(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(dev, PLD_BUS_TYPE_SNOC_FW_SIM); +} + +/** + * pld_snoc_fw_sim_suspend_noirq() - Complete the actions started by suspend() + * @dev: device + * + * Complete the actions started by suspend(). Carry out any + * additional operations required for suspending the device that might be + * racing with its driver's interrupt handler, which is guaranteed not to + * run while suspend_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_snoc_fw_sim_suspend_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->suspend_noirq) + return pld_context->ops->suspend_noirq(dev, + PLD_BUS_TYPE_SNOC_FW_SIM); + return 0; +} + +/** + * pld_snoc_fw_sim_resume_noirq() - Prepare for the execution of resume() + * @dev: device + * + * Prepare for the execution of resume() by carrying out any + * operations required for resuming the device that might be racing with + * its driver's interrupt handler, which is guaranteed not to run while + * resume_noirq() is being executed. + * + * Return: 0 for success + * Non zero failure code for errors + */ +static int pld_snoc_fw_sim_resume_noirq(struct device *dev) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (pld_context->ops->resume_noirq) + return pld_context->ops->resume_noirq(dev, + PLD_BUS_TYPE_SNOC_FW_SIM); + + return 0; +} + +static int pld_snoc_fw_sim_uevent(struct device *dev, + struct icnss_uevent_data *uevent) +{ + struct pld_context *pld_context; + struct icnss_uevent_fw_down_data *uevent_data = NULL; + struct pld_uevent_data data = {0}; + + pld_context = pld_get_global_context(); + if (!pld_context) + return -EINVAL; + + if (!pld_context->ops->uevent) + return 0; + + if (!uevent) + return -EINVAL; + + switch (uevent->uevent) { + case ICNSS_UEVENT_FW_CRASHED: + data.uevent = PLD_FW_CRASHED; + break; + case ICNSS_UEVENT_FW_DOWN: + if (!uevent->data) + return -EINVAL; + uevent_data = (struct icnss_uevent_fw_down_data *)uevent->data; + data.uevent = PLD_FW_DOWN; + data.fw_down.crashed = uevent_data->crashed; + break; + default: + return 0; + } + + pld_context->ops->uevent(dev, &data); + return 0; +} + +#ifdef MULTI_IF_NAME +#define PLD_SNOC_FW_SIM_OPS_NAME "pld_snoc_fw_sim_" MULTI_IF_NAME +#else +#define PLD_SNOC_FW_SIM_OPS_NAME "pld_snoc_fw_sim" +#endif + +struct icnss_driver_ops pld_snoc_fw_sim_ops = { + .name = PLD_SNOC_FW_SIM_OPS_NAME, + .probe = pld_snoc_fw_sim_probe, + .remove = pld_snoc_fw_sim_remove, + .shutdown = pld_snoc_fw_sim_shutdown, + .reinit = pld_snoc_fw_sim_reinit, + .crash_shutdown = pld_snoc_fw_sim_crash_shutdown, + .pm_suspend = pld_snoc_fw_sim_pm_suspend, + .pm_resume = pld_snoc_fw_sim_pm_resume, + .suspend_noirq = pld_snoc_fw_sim_suspend_noirq, + .resume_noirq = pld_snoc_fw_sim_resume_noirq, + .uevent = pld_snoc_fw_sim_uevent, +}; + +/** + * pld_snoc_fw_sim_register_driver() - Register platform device callback + * functions + * + * Return: int + */ +int pld_snoc_fw_sim_register_driver(void) +{ + return icnss_register_driver(&pld_snoc_fw_sim_ops); +} + +/** + * pld_snoc_fw_sim_unregister_driver() - Unregister platform device callback + * functions + * + * Return: void + */ +void pld_snoc_fw_sim_unregister_driver(void) +{ + icnss_unregister_driver(&pld_snoc_fw_sim_ops); +} + +/** + * pld_snoc_fw_sim_wlan_enable() - Enable WLAN + * @dev: device + * @config: WLAN configuration data + * @mode: WLAN mode + * @host_version: host software version + * + * This function enables WLAN FW. It passed WLAN configuration data, + * WLAN mode and host software version to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_fw_sim_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + struct icnss_wlan_enable_cfg cfg; + enum icnss_driver_mode icnss_mode; + + if (!dev) + return -ENODEV; + + cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg; + cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *) + config->ce_tgt_cfg; + cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg; + cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *) + config->ce_svc_cfg; + cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg; + cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *) + config->shadow_reg_cfg; + + switch (mode) { + case PLD_FTM: + icnss_mode = ICNSS_FTM; + break; + case PLD_EPPING: + icnss_mode = ICNSS_EPPING; + break; + default: + icnss_mode = ICNSS_MISSION; + break; + } + + return icnss_wlan_enable(dev, &cfg, icnss_mode, host_version); +} + +/** + * pld_snoc_fw_sim_wlan_disable() - Disable WLAN + * @dev: device + * @mode: WLAN mode + * + * This function disables WLAN FW. It passes WLAN mode to FW. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_fw_sim_wlan_disable(struct device *dev, enum pld_driver_mode mode) +{ + if (!dev) + return -ENODEV; + + return icnss_wlan_disable(dev, ICNSS_OFF); +} + +/** + * pld_snoc_fw_sim_get_soc_info() - Get SOC information + * @dev: device + * @info: buffer to SOC information + * + * Return SOC info to the buffer. + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_snoc_fw_sim_get_soc_info(struct device *dev, struct pld_soc_info *info) +{ + int ret = 0; + struct icnss_soc_info icnss_info; + + if (!info || !dev) + return -ENODEV; + + ret = icnss_get_soc_info(dev, &icnss_info); + if (0 != ret) + return ret; + + memcpy(info, &icnss_info, sizeof(*info)); + return 0; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc_fw_sim.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc_fw_sim.h new file mode 100644 index 0000000000..72c4f10108 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_snoc_fw_sim.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __PLD_SNOC_FW_SIM_H__ +#define __PLD_SNOC_FW_SIM_H__ + +#include "pld_internal.h" + +#ifndef CONFIG_PLD_SNOC_FW_SIM +static inline int pld_snoc_fw_sim_register_driver(void) +{ + return 0; +} + +static inline void pld_snoc_fw_sim_unregister_driver(void) +{ +} + +static inline int pld_snoc_fw_sim_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *cfg, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_wlan_disable(struct device *dev, + enum pld_driver_mode mode) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_ce_request_irq(struct device *dev, + unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, + const char *name, void *ctx) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_ce_free_irq(struct device *dev, + unsigned int ce_id, void *ctx) +{ + return 0; +} + +static inline void pld_snoc_fw_sim_enable_irq(struct device *dev, + unsigned int ce_id) +{ +} + +static inline void pld_snoc_fw_sim_disable_irq(struct device *dev, + unsigned int ce_id) +{ +} + +static inline int pld_snoc_fw_sim_get_soc_info(struct device *dev, + struct pld_soc_info *info) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_get_ce_id(struct device *dev, int irq) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_get_irq(struct device *dev, int ce_id) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_is_fw_down(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_idle_shutdown(struct device *dev) +{ + return 0; +} + +static inline int pld_snoc_fw_sim_idle_restart(struct device *dev) +{ + return 0; +} + +#else +#include + +int pld_snoc_fw_sim_register_driver(void); +void pld_snoc_fw_sim_unregister_driver(void); +int pld_snoc_fw_sim_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version); +int pld_snoc_fw_sim_wlan_disable(struct device *dev, enum pld_driver_mode mode); +int pld_snoc_fw_sim_get_soc_info(struct device *dev, struct pld_soc_info *info); + +static inline int pld_snoc_fw_sim_ce_request_irq(struct device *dev, + unsigned int ce_id, + irqreturn_t (*handler)(int, void *), + unsigned long flags, + const char *name, void *ctx) +{ + if (!dev) + return -ENODEV; + + return icnss_ce_request_irq(dev, ce_id, handler, flags, name, ctx); +} + +static inline int pld_snoc_fw_sim_ce_free_irq(struct device *dev, + unsigned int ce_id, void *ctx) +{ + if (!dev) + return -ENODEV; + + return icnss_ce_free_irq(dev, ce_id, ctx); +} + +static inline void pld_snoc_fw_sim_enable_irq(struct device *dev, + unsigned int ce_id) +{ + if (dev) + icnss_enable_irq(dev, ce_id); +} + +static inline void pld_snoc_fw_sim_disable_irq(struct device *dev, + unsigned int ce_id) +{ + if (dev) + icnss_disable_irq(dev, ce_id); +} + +static inline int pld_snoc_fw_sim_get_ce_id(struct device *dev, int irq) +{ + if (!dev) + return -ENODEV; + + return icnss_get_ce_id(dev, irq); +} + +static inline int pld_snoc_fw_sim_get_irq(struct device *dev, int ce_id) +{ + if (!dev) + return -ENODEV; + + return icnss_get_irq(dev, ce_id); +} + +static inline int pld_snoc_fw_sim_is_fw_down(struct device *dev) +{ + return icnss_is_fw_down(); +} + +static inline int pld_snoc_fw_sim_idle_shutdown(struct device *dev) +{ + return icnss_idle_shutdown(dev); +} + +static inline int pld_snoc_fw_sim_idle_restart(struct device *dev) +{ + return icnss_idle_restart(dev); +} + +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_usb.c b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_usb.c new file mode 100644 index 0000000000..8cd6ac193f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_usb.c @@ -0,0 +1,393 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "pld_usb.h" +#include "pld_internal.h" + +#include +#include +#include +#include +#include +#include +#include "osif_psoc_sync.h" + +#ifdef CONFIG_PLD_USB_CNSS +#include +#endif + + +#define VENDOR_ATHR 0x0CF3 +static struct usb_device_id pld_usb_id_table[] = { + {USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ATHR, 0x9378, 0xFF, 0xFF, 0xFF)}, + {USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ATHR, 0x9379, 0xFF, 0xFF, 0xFF)}, + {} /* Terminating entry */ +}; + +atomic_t pld_usb_reg_done; + +/** + * pld_usb_probe() - pld_usb_probe + * @interface: pointer to usb_interface structure + * @id: pointer to usb_device_id obtained from the enumerated device + * + * Return: int 0 on success and errno on failure. + */ +static int pld_usb_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct usb_device *pdev = interface_to_usbdev(interface); + struct pld_context *pld_context; + int ret = 0; + + pld_context = pld_get_global_context(); + if (!pld_context) { + ret = -ENODEV; + goto out; + } + + ret = pld_add_dev(pld_context, &pdev->dev, &interface->dev, + PLD_BUS_TYPE_USB); + if (ret) + goto out; + + ret = pld_context->ops->probe(&pdev->dev, + PLD_BUS_TYPE_USB, interface, (void *)id); + if (ret != 0) { + pr_err("%s, probe returned %d", __func__, ret); + atomic_set(&pld_usb_reg_done, false); + } else { + atomic_set(&pld_usb_reg_done, true); + } + +out: + return ret; +} + +/** + * pld_usb_remove() - Remove function for USB device + * @interface: pointer to usb_interface for the usb device being removed + * + * Return: void + */ +static void pld_usb_remove(struct usb_interface *interface) +{ + struct usb_device *pdev = interface_to_usbdev(interface); + struct pld_context *pld_context; + int errno; + struct osif_psoc_sync *psoc_sync; + + errno = osif_psoc_sync_trans_start_wait(&pdev->dev, &psoc_sync); + if (errno) + return; + + osif_psoc_sync_unregister(&pdev->dev); + osif_psoc_sync_wait_for_ops(psoc_sync); + + pld_context = pld_get_global_context(); + + if (!pld_context) + goto out; + + if (atomic_read(&pld_usb_reg_done) != true) { + pr_info("%s: already de-registered!\n", __func__); + goto out; + } + + pld_context->ops->remove(&pdev->dev, PLD_BUS_TYPE_USB); + + pld_del_dev(pld_context, &pdev->dev); + + atomic_set(&pld_usb_reg_done, false); +out: + osif_psoc_sync_trans_stop(psoc_sync); + osif_psoc_sync_destroy(psoc_sync); + + pr_info("%s: done!\n", __func__); +} + +/** + * pld_usb_suspend() - Suspend callback function for power management + * @interface: pointer to usb_interface for the usb device + * @state: power state + * + * This function is to suspend the PCIE device when power management is + * enabled. + * + * Return: void + */ +static int pld_usb_suspend(struct usb_interface *interface, + pm_message_t state) +{ + struct usb_device *pdev = interface_to_usbdev(interface); + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + return pld_context->ops->suspend(&pdev->dev, PLD_BUS_TYPE_USB, state); +} + +/** + * pld_usb_resume() - Resume callback function for power management + * @interface: pointer to usb_interface for the usb device + * + * This function is to resume the USB device when power management is + * enabled. + * + * Return: void + */ +static int pld_usb_resume(struct usb_interface *interface) +{ + struct pld_context *pld_context; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + return pld_context->ops->resume(&pdev->dev, PLD_BUS_TYPE_USB); +} + +/** + * pld_usb_reset_resume() - pld_usb_reset_resume + * @interface: pointer to usb_interface for the usb device + * + * Return: void + */ +static int pld_usb_reset_resume(struct usb_interface *interface) +{ + struct pld_context *pld_context; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + return pld_context->ops->reset_resume(&pdev->dev, PLD_BUS_TYPE_USB); +} + +#ifdef CONFIG_PLD_USB_CNSS +/** + * pld_usb_reinit() - SSR re-initialize function for USB device + * @interface: Pointer to struct usb_interface + * @id: Pointer to USB device ID + * + * Return: int + */ +static int pld_usb_reinit(struct usb_interface *interface, + const struct usb_device_id *id) +{ + struct pld_context *pld_context; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + if (pld_context->ops->reinit) + return pld_context->ops->reinit(&pdev->dev, PLD_BUS_TYPE_USB, + interface, (void *)id); + + return -ENODEV; +} + +/** + * pld_usb_shutdown() - SSR shutdown function for USB device + * @interface: Pointer to struct usb_interface + * + * Return: void + */ +static void pld_usb_shutdown(struct usb_interface *interface) +{ + struct pld_context *pld_context; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + if (pld_context->ops->shutdown) + pld_context->ops->shutdown(&pdev->dev, PLD_BUS_TYPE_USB); +} + +/** + * pld_usb_uevent() - update wlan driver status callback function + * @interface: USB interface + * @status: driver uevent status + * + * This function will be called when platform driver wants to update wlan + * driver's status. + * + * Return: void + */ +static void pld_usb_uevent(struct usb_interface *interface, uint32_t status) +{ + struct pld_context *pld_context; + struct pld_uevent_data data = {0}; + struct usb_device *pdev = interface_to_usbdev(interface); + + pld_context = pld_get_global_context(); + if (!pld_context) + return; + + switch (status) { + case CNSS_RECOVERY: + data.uevent = PLD_FW_RECOVERY_START; + break; + case CNSS_FW_DOWN: + data.uevent = PLD_FW_DOWN; + break; + default: + goto out; + } + + if (pld_context->ops->uevent) + pld_context->ops->uevent(&pdev->dev, &data); + +out: + return; +} +struct cnss_usb_wlan_driver pld_usb_ops = { + .name = "pld_usb_cnss", + .id_table = pld_usb_id_table, + .probe = pld_usb_probe, + .remove = pld_usb_remove, + .shutdown = pld_usb_shutdown, + .reinit = pld_usb_reinit, + .update_status = pld_usb_uevent, +#ifdef CONFIG_PM + .suspend = pld_usb_suspend, + .resume = pld_usb_resume, + .reset_resume = pld_usb_reset_resume, +#endif +}; + +int pld_usb_register_driver(void) +{ + pr_info("%s usb_register\n", __func__); + return cnss_usb_wlan_register_driver(&pld_usb_ops); +} + +void pld_usb_unregister_driver(void) +{ + cnss_usb_wlan_unregister_driver(&pld_usb_ops); + pr_info("%s usb_deregister done!\n", __func__); +} + +int pld_usb_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + struct cnss_wlan_enable_cfg cfg; + enum cnss_driver_mode cnss_mode; + + switch (mode) { + case PLD_FTM: + cnss_mode = CNSS_FTM; + break; + case PLD_EPPING: + cnss_mode = CNSS_EPPING; + break; + default: + cnss_mode = CNSS_MISSION; + break; + } + return cnss_wlan_enable(dev, &cfg, cnss_mode, host_version); +} + +int pld_usb_is_fw_down(struct device *dev) +{ + return cnss_usb_is_device_down(dev); +} + +int pld_usb_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return cnss_athdiag_read(dev, offset, memtype, datalen, output); +} + +int pld_usb_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return cnss_athdiag_write(dev, offset, memtype, datalen, input); +} + +#else /* CONFIG_PLD_USB_CNSS */ + +struct usb_driver pld_usb_ops = { + .name = "pld_usb", + .id_table = pld_usb_id_table, + .probe = pld_usb_probe, + .disconnect = pld_usb_remove, +#ifdef CONFIG_PM + .suspend = pld_usb_suspend, + .resume = pld_usb_resume, + .reset_resume = pld_usb_reset_resume, +#endif + .supports_autosuspend = true, +}; + +int pld_usb_register_driver(void) +{ + int status; + + usb_register(&pld_usb_ops); + + if (atomic_read(&pld_usb_reg_done) == true) { + status = 0; + } else { + usb_deregister(&pld_usb_ops); + status = -1; + } + + pr_info("%s usb_register %s, status %d\n", __func__, + (status == 0) ? "done" : "failed", status); + + return status; +} + +void pld_usb_unregister_driver(void) +{ + struct pld_context *pld_context; + + pld_context = pld_get_global_context(); + if (atomic_read(&pld_usb_reg_done) == false) + return; + + pld_context->ops->remove(NULL, PLD_BUS_TYPE_USB); + + atomic_set(&pld_usb_reg_done, false); + usb_deregister(&pld_usb_ops); + pr_info("%s usb_deregister done!\n", __func__); +} + +int pld_usb_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version) +{ + return 0; +} + +int pld_usb_is_fw_down(struct device *dev) +{ + return 0; +} + +int pld_usb_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return 0; +} + +int pld_usb_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return 0; +} + +#endif /* CONFIG_PLD_USB_CNSS */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_usb.h b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_usb.h new file mode 100644 index 0000000000..4915fff134 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/pld/src/pld_usb.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2016-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __PLD_USB_H__ +#define __PLD_USB_H__ + +#include "pld_common.h" + +#ifdef HIF_USB +/** + * pld_usb_register_driver() - registration routine for wlan usb drive + * + * Return: int negative error code on failure and 0 on success + */ +int pld_usb_register_driver(void); + +/** + * pld_usb_unregister_driver() - de-registration routine for wlan usb driver + * + * Return: void + */ +void pld_usb_unregister_driver(void); + +int pld_usb_get_ce_id(int irq); +int pld_usb_wlan_enable(struct device *dev, struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, const char *host_version); +int pld_usb_is_fw_down(struct device *dev); + +/** + * pld_usb_athdiag_read() - Read data from WLAN FW through USB interface + * @dev: pointer of device + * @offset: address offset + * @memtype: memory type + * @datalen: data length + * @output: pointer of output buffer + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_usb_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output); + +/** + * pld_usb_athdiag_write() - Write data to WLAN FW through USB interface + * @dev: pointer of device + * @offset: address offset + * @memtype: memory type + * @datalen: data length + * @input: pointer of input buffer + * + * Return: 0 for success + * Non zero failure code for errors + */ +int pld_usb_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input); + +#else +static inline int pld_usb_register_driver(void) +{ + return 0; +} + +static inline void pld_usb_unregister_driver(void) +{} + +static inline int pld_usb_wlan_enable(struct device *dev, + struct pld_wlan_enable_cfg *config, + enum pld_driver_mode mode, + const char *host_version) +{ + return 0; +} + +static inline int pld_usb_is_fw_down(struct device *dev) +{ + return 0; +} + +static inline int pld_usb_athdiag_read(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *output) +{ + return 0; +} + +static inline int pld_usb_athdiag_write(struct device *dev, uint32_t offset, + uint32_t memtype, uint32_t datalen, + uint8_t *input) +{ + return 0; +} +#endif + +static inline int +pld_usb_get_fw_files_for_target(struct pld_fw_files *pfw_files, + u32 target_type, u32 target_version) +{ + pld_get_default_fw_files(pfw_files); + return 0; +} + +#endif /*__PLD_USB_H__*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/inc/sap_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sap/inc/sap_api.h new file mode 100644 index 0000000000..c281b6aa81 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/inc/sap_api.h @@ -0,0 +1,1997 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_QCT_WLANSAP_H +#define WLAN_QCT_WLANSAP_H + +/* + * W L A N S O F T A P P A L L A Y E R + * E X T E R N A L A P I + * + * DESCRIPTION + * This file contains the external API exposed by the wlan SAP PAL layer + * module. + */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "cds_api.h" +#include "cds_packet.h" +#include "qdf_types.h" + +#include "sme_api.h" +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * defines and enum + *--------------------------------------------------------------------------*/ +#define MAX_ACL_MAC_ADDRESS 32 +#define AUTO_CHANNEL_SELECT 0 +#define MAX_ASSOC_IND_IE_LEN 255 +#define MAX_ASSOC_REQ_IE_LEN 2000 +#define ASSOC_REQ_IE_OFFSET 4 + +/* defines for WPS config states */ +#define SAP_WPS_DISABLED 0 +#define SAP_WPS_ENABLED_UNCONFIGURED 1 +#define SAP_WPS_ENABLED_CONFIGURED 2 + +#define MAX_CHANNEL_LIST_LEN 256 +#ifndef QDF_MAX_NO_OF_SAP_MODE +#define QDF_MAX_NO_OF_SAP_MODE 2 /* max # of SAP */ +#endif +#define SAP_MAX_NUM_SESSION 5 +#define SAP_MAX_OBSS_STA_CNT 1 /* max # of OBSS STA */ +#define SAP_ACS_WEIGHT_MAX (26664) +/* ACS will mark non ACS channels(filtered by PCL) or channels not in + * ACS scan list to SAP_ACS_WEIGHT_MAX. + * But the filtered channel still need a reasonable weight to + * calculate the combined weight for ACS bw 40/80/160/320. + * Assign SAP_ACS_WEIGHT_ADJUSTABLE to such channels and update it + * with reasonable weight after all channels weight are computed. + */ +#define SAP_ACS_WEIGHT_ADJUSTABLE (SAP_ACS_WEIGHT_MAX - 1) + +#define SAP_DEFAULT_24GHZ_CHANNEL (6) +#define SAP_DEFAULT_5GHZ_CHANNEL (40) +#define SAP_CHANNEL_NOT_SELECTED (0) + +#define SAP_PRE_CAC_IFNAME "precac" + +/*-------------------------------------------------------------------------- + * reasonCode taken from 802.11 standard. + * ------------------------------------------------------------------------*/ + +typedef enum { + eSAP_RC_RESERVED0, /*0 */ + eSAP_RC_UNSPECIFIED, /*1 */ + eSAP_RC_PREV_AUTH_INVALID, /*2 */ + eSAP_RC_STA_LEFT_DEAUTH, /*3 */ + eSAP_RC_INACTIVITY_DISASSOC, /*4 */ + eSAP_RC_AP_CAPACITY_FULL, /*5 */ + eSAP_RC_CLS2_FROM_NON_AUTH_STA, /*6 */ + eSAP_RC_CLS3_FROM_NON_AUTH_STA, /*7 */ + eSAP_RC_STA_LEFT_DISASSOC, /*8 */ + eSAP_RC_STA_NOT_AUTH, /*9 */ + eSAP_RC_PC_UNACCEPTABLE, /*10 */ + eSAP_RC_SC_UNACCEPTABLE, /*11 */ + eSAP_RC_RESERVED1, /*12 */ + eSAP_RC_INVALID_IE, /*13 */ + eSAP_RC_MIC_FAIL, /*14 */ + eSAP_RC_4_WAY_HANDSHAKE_TO, /*15 */ + eSAP_RC_GO_KEY_HANDSHAKE_TO, /*16 */ + eSAP_RC_IE_MISMATCH, /*17 */ + eSAP_RC_INVALID_GRP_CHIPHER, /*18 */ + eSAP_RC_INVALID_PAIR_CHIPHER, /*19 */ + eSAP_RC_INVALID_AKMP, /*20 */ + eSAP_RC_UNSUPPORTED_RSN, /*21 */ + eSAP_RC_INVALID_RSN, /*22 */ + eSAP_RC_1X_AUTH_FAILED, /*23 */ + eSAP_RC_CHIPER_SUITE_REJECTED, /*24 */ +} eSapReasonCode; + +typedef enum { + eSAP_ACCEPT_UNLESS_DENIED = 0, + eSAP_DENY_UNLESS_ACCEPTED = 1, + /* this type is added to support accept & deny list at the same time */ + eSAP_SUPPORT_ACCEPT_AND_DENY = 2, + /*In this mode all MAC addresses are allowed to connect */ + eSAP_ALLOW_ALL = 3, +} eSapMacAddrACL; + +typedef enum { + SAP_DENY_LIST = 0, /* List of mac addresses NOT allowed to assoc */ + SAP_ALLOW_LIST = 1, /* List of mac addresses allowed to assoc */ +} eSapACLType; + +typedef enum { + ADD_STA_TO_ACL = 0, /* cmd to add STA to access control list */ + DELETE_STA_FROM_ACL = 1, /* cmd to del STA from access control list */ + /* only add STA to ACL, do not trigger deauth */ + ADD_STA_TO_ACL_NO_DEAUTH = 2, + /* only delete STA from ACL, do not trigger deauth */ + DELETE_STA_FROM_ACL_NO_DEAUTH = 3, +} eSapACLCmdType; + +typedef enum { + eSAP_START_BSS_EVENT = 0, /* Event sent when BSS is started */ + eSAP_STOP_BSS_EVENT, /* Event sent when BSS is stopped */ + eSAP_STA_ASSOC_IND, /* Indicate assoc req to upper layers */ + /* + * Event sent when we have successfully associated a station and + * upper layer needs to allocate a context + */ + eSAP_STA_ASSOC_EVENT, + /* + * Event sent when we have successfully reassociated a station and + * upper layer needs to allocate a context + */ + eSAP_STA_REASSOC_EVENT, + /* + * Event sent when associated a station has disassociated as a + * result of various conditions + */ + eSAP_STA_DISASSOC_EVENT, + /* Event sent when user called wlansap_set_key_sta */ + eSAP_STA_SET_KEY_EVENT, + /* Event sent whenever there is MIC failure detected */ + eSAP_STA_MIC_FAILURE_EVENT, + /* Event send on WPS PBC probe request is received */ + eSAP_WPS_PBC_PROBE_REQ_EVENT, + eSAP_DISCONNECT_ALL_P2P_CLIENT, + eSAP_MAC_TRIG_STOP_BSS_EVENT, + /* + * Event send when a STA in neither allow list or deny list tries to + * associate in softap mode + */ + eSAP_UNKNOWN_STA_JOIN, + /* Event send when a new STA is rejected association since softAP + * max assoc limit has reached + */ + eSAP_MAX_ASSOC_EXCEEDED, + eSAP_CHANNEL_CHANGE_EVENT, + eSAP_DFS_CAC_START, + eSAP_DFS_CAC_INTERRUPTED, + eSAP_DFS_CAC_END, + eSAP_DFS_RADAR_DETECT, + /* No ch available after DFS RADAR detect */ + eSAP_DFS_NO_AVAILABLE_CHANNEL, + eSAP_STOP_BSS_DUE_TO_NO_CHNL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + eSAP_ACS_CHANNEL_SELECTED, + eSAP_ECSA_CHANGE_CHAN_IND, + eSAP_DFS_NEXT_CHANNEL_REQ, + /* Event sent channel switch status to upper layer */ + eSAP_CHANNEL_CHANGE_RESP, +} eSapHddEvent; + +typedef enum { + eSAP_OPEN_SYSTEM, + eSAP_SHARED_KEY, + eSAP_AUTO_SWITCH +} eSapAuthType; + +typedef enum { + /* Disassociation was internally initiated from CORE stack */ + eSAP_MAC_INITATED_DISASSOC = 0x10000, + /* + * Disassociation was internally initiated from host by + * invoking wlansap_disassoc_sta call + */ + eSAP_USR_INITATED_DISASSOC +} eSapDisassocReason; + +typedef enum { + eSAP_DFS_NOL_CLEAR, + eSAP_DFS_NOL_RANDOMIZE, +} eSapDfsNolType; + +/*--------------------------------------------------------------------------- + SAP PAL "status" and "reason" error code defines + ---------------------------------------------------------------------------*/ +typedef enum { + eSAP_STATUS_SUCCESS, /* Success. */ + eSAP_STATUS_FAILURE, /* General Failure. */ + /* Channel not selected during initial scan. */ + eSAP_START_BSS_CHANNEL_NOT_SELECTED, + eSAP_ERROR_MAC_START_FAIL, /* Failed to start Infra BSS */ +} eSapStatus; + +/*--------------------------------------------------------------------------- + SAP PAL "status" and "reason" error code defines + ---------------------------------------------------------------------------*/ +typedef enum { + eSAP_WPSPBC_OVERLAP_IN120S, /* Overlap */ + /* no WPS probe request in 120 second */ + eSAP_WPSPBC_NO_WPSPBC_PROBE_REQ_IN120S, + /* One WPS probe request in 120 second */ + eSAP_WPSPBC_ONE_WPSPBC_PROBE_REQ_IN120S, +} eWPSPBCOverlap; + +/*--------------------------------------------------------------------------- + SAP Associated station types + ---------------------------------------------------------------------------*/ +typedef enum { + eSTA_TYPE_NONE = 0x00000000, /* No station type */ + eSTA_TYPE_INFRA = 0x00000001, /* legacy station */ + eSTA_TYPE_P2P_CLI = 0x00000002, /* p2p client */ +} eStationType; + +/*---------------------------------------------------------------------------- + * Typedefs + * -------------------------------------------------------------------------*/ +typedef struct sap_StartBssCompleteEvent_s { + uint8_t status; + uint32_t operating_chan_freq; + enum phy_ch_width ch_width; + uint16_t staId; /* self StaID */ + uint8_t sessionId; /* SoftAP SME session ID */ +} tSap_StartBssCompleteEvent; + +typedef struct sap_StopBssCompleteEvent_s { + uint8_t status; +} tSap_StopBssCompleteEvent; + +typedef struct sap_StationAssocIndication_s { + struct qdf_mac_addr staMac; + uint8_t staId; + uint8_t status; + /* Required for indicating the frames to upper layer */ + uint32_t assocReqLength; + uint8_t *assocReqPtr; + bool fWmmEnabled; + uint8_t ecsa_capable; + uint32_t owe_ie_len; + uint8_t *owe_ie; +} tSap_StationAssocIndication; + +typedef struct sap_StationAssocReassocCompleteEvent_s { + struct qdf_mac_addr staMac; + eStationType staType; + uint8_t staId; + uint8_t status; + uint8_t *ies; + uint32_t ies_len; + uint32_t status_code; + bool wmmEnabled; + uint8_t timingMeasCap; + struct oem_channel_info chan_info; + bool ampdu; + bool sgi_enable; + bool tx_stbc; + bool rx_stbc; + tSirMacHTChannelWidth ch_width; + enum sir_sme_phy_mode mode; + uint8_t max_supp_idx; + uint8_t max_ext_idx; + uint8_t max_mcs_idx; + uint8_t max_real_mcs_idx; + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + uint8_t ecsa_capable; + uint32_t ext_cap; + uint8_t supported_band; + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + bool eht_caps_present; + tSirMacCapabilityInfo capability_info; + bool he_caps_present; + struct qdf_mac_addr sta_mld; +} tSap_StationAssocReassocCompleteEvent; + +typedef struct sap_StationDisassocCompleteEvent_s { + struct qdf_mac_addr staMac; + uint8_t staId; /* STAID should not be used */ + uint8_t status; + uint32_t status_code; + uint32_t reason_code; + eSapDisassocReason reason; + int rssi; + int tx_rate; + int rx_rate; + uint32_t rx_mc_bc_cnt; + uint32_t rx_retry_cnt; +} tSap_StationDisassocCompleteEvent; + +typedef struct sap_StationSetKeyCompleteEvent_s { + uint8_t status; + struct qdf_mac_addr peerMacAddr; +} tSap_StationSetKeyCompleteEvent; + +/*struct corresponding to SAP_STA_MIC_FAILURE_EVENT */ +typedef struct sap_StationMICFailureEvent_s { + struct qdf_mac_addr srcMacAddr; /* address used to compute MIC */ + struct qdf_mac_addr staMac; /* taMacAddr transmitter address */ + struct qdf_mac_addr dstMacAddr; + bool multicast; + uint8_t IV1; /* first byte of IV */ + uint8_t keyId; /* second byte of IV */ + uint8_t TSC[SIR_CIPHER_SEQ_CTR_SIZE]; /* sequence number */ + +} tSap_StationMICFailureEvent; + +typedef struct sap_WPSPBCProbeReqEvent_s { + uint8_t status; + /* module id that was passed in wlansap_get_assoc_stations API */ + QDF_MODULE_ID module; + tSirWPSPBCProbeReq WPSPBCProbeReq; +} tSap_WPSPBCProbeReqEvent; + +typedef struct sap_SendActionCnf_s { + eSapStatus actionSendSuccess; +} tSap_SendActionCnf; + +typedef struct sap_UnknownSTAJoinEvent_s { + struct qdf_mac_addr macaddr; +} tSap_UnknownSTAJoinEvent; + +typedef struct sap_MaxAssocExceededEvent_s { + struct qdf_mac_addr macaddr; +} tSap_MaxAssocExceededEvent; + +/** + * struct sap_ch_selected_s - structure to hold the selected channels + * @pri_ch_freq: Holds the ACS selected primary channel frequency + * @ht_sec_ch_freq: Holds the ACS selected secondary ht channel frequency + * @vht_seg0_center_ch_freq: Holds the ACS selected center channel of vht seg0 + * @vht_seg1_center_ch_freq: Holds the ACS selected center channel of vht seg1 + * @ch_width: Holds the ACS selected channel bandwidth + * + * Holds the primary and secondary channel selected by ACS and is + * used to send it to the HDD. + */ +struct sap_ch_selected_s { + uint32_t pri_ch_freq; + uint32_t ht_sec_ch_freq; + uint16_t vht_seg0_center_ch_freq; + uint16_t vht_seg1_center_ch_freq; + uint16_t ch_width; +}; + +/** + * struct sap_acs_scan_complete_event - acs scan complete event + * @status: status of acs scan + * @freq_list: acs scan channel frequency list + * @num_of_channels: number of channels + */ +struct sap_acs_scan_complete_event { + uint8_t status; + uint32_t *freq_list; + uint8_t num_of_channels; +}; + +/** + * struct sap_ch_change_ind - channel change indication + * @new_chan_freq: channel frequency to change to + */ +struct sap_ch_change_ind { + uint32_t new_chan_freq; +}; + +/** + * struct sap_ch_change_rsp - channel change response + * @sap_ch_selected: channel parameters of new channel + * @ch_change_rsp_status: channel change response status + */ +struct sap_ch_change_rsp { + struct sap_ch_selected_s sap_ch_selected; + eSapStatus ch_change_rsp_status; +}; + +/* + * This struct will be filled in and passed to sap_event_cb that is + * provided during wlansap_start_bss call The event id corresponding to + * structure in the union is defined in comment next to the structure + */ + +struct sap_event { + eSapHddEvent sapHddEventCode; + union { + /*SAP_START_BSS_EVENT */ + tSap_StartBssCompleteEvent sapStartBssCompleteEvent; + /*SAP_STOP_BSS_EVENT */ + tSap_StopBssCompleteEvent sapStopBssCompleteEvent; + /*SAP_ASSOC_INDICATION */ + tSap_StationAssocIndication sapAssocIndication; + /*SAP_STA_ASSOC_EVENT, SAP_STA_REASSOC_EVENT */ + tSap_StationAssocReassocCompleteEvent + sapStationAssocReassocCompleteEvent; + /*SAP_STA_DISASSOC_EVENT */ + tSap_StationDisassocCompleteEvent + sapStationDisassocCompleteEvent; + /*SAP_STA_SET_KEY_EVENT */ + tSap_StationSetKeyCompleteEvent sapStationSetKeyCompleteEvent; + /*SAP_STA_MIC_FAILURE_EVENT */ + tSap_StationMICFailureEvent sapStationMICFailureEvent; + /*eSAP_WPS_PBC_PROBE_REQ_EVENT */ + tSap_WPSPBCProbeReqEvent sapPBCProbeReqEvent; + tSap_SendActionCnf sapActionCnf; + /* eSAP_UNKNOWN_STA_JOIN */ + tSap_UnknownSTAJoinEvent sapUnknownSTAJoin; + /* eSAP_MAX_ASSOC_EXCEEDED */ + tSap_MaxAssocExceededEvent sapMaxAssocExceeded; + struct sap_ch_selected_s sap_ch_selected; + struct sap_ch_change_ind sap_chan_cng_ind; + struct sap_ch_change_rsp sap_chan_cng_rsp; + struct sap_acs_scan_complete_event sap_acs_scan_comp; + } sapevt; +}; + +typedef struct sap_SSID { + uint8_t length; + uint8_t ssId[WLAN_SSID_MAX_LEN]; +} qdf_packed tSap_SSID_t; + +typedef struct sap_SSIDInfo { + tSap_SSID_t ssid; /* SSID of the AP */ + /* SSID should/shouldn't be bcast in probe RSP & beacon */ + uint8_t ssidHidden; +} qdf_packed tSap_SSIDInfo_t; + +/** + * struct master_acs - acs attributes received from userspace + * @hw_mode: hw mode + * @ht: ht flag + * @ht40: ht40 flag + * @vht: vht flag + * @eht: eht flag + * @ch_width: channel bandwidth + */ +struct master_acs { + uint8_t hw_mode; + uint8_t ht; + uint8_t ht40; + uint8_t vht; + uint8_t eht; + uint16_t ch_width; +}; + +struct sap_acs_cfg { + /* ACS Algo Input */ + uint8_t acs_mode; + eCsrPhyMode hw_mode; + qdf_freq_t start_ch_freq; + qdf_freq_t end_ch_freq; + qdf_freq_t *freq_list; + uint8_t ch_list_count; + qdf_freq_t *master_freq_list; + uint8_t master_ch_list_count; + bool master_ch_list_updated; +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + uint8_t skip_scan_status; + uint32_t skip_scan_range1_stch; + uint32_t skip_scan_range1_endch; + uint32_t skip_scan_range2_stch; + uint32_t skip_scan_range2_endch; +#endif + + uint16_t ch_width; + uint32_t pcl_chan_freq[NUM_CHANNELS]; + uint8_t pcl_channels_weight_list[NUM_CHANNELS]; + uint32_t pcl_ch_count; + uint8_t is_ht_enabled; + uint8_t is_vht_enabled; + /* ACS Algo Output */ + uint32_t pri_ch_freq; + uint32_t ht_sec_ch_freq; + uint32_t vht_seg0_center_ch_freq; + uint32_t vht_seg1_center_ch_freq; + uint32_t band; +#ifdef WLAN_FEATURE_11BE + bool is_eht_enabled; + uint16_t acs_puncture_bitmap; +#endif + bool skip_acs_scan; + uint32_t last_scan_ageout_time; + struct master_acs master_acs_cfg; +}; + +/* + * enum sap_acs_dfs_mode- state of DFS mode + * @ACS_DFS_MODE_NONE: DFS mode attribute is not valid + * @ACS_DFS_MODE_ENABLE: DFS mode is enabled + * @ACS_DFS_MODE_DISABLE: DFS mode is disabled + * @ACS_DFS_MODE_DEPRIORITIZE: Deprioritize DFS channels in scanning + */ +enum sap_acs_dfs_mode { + ACS_DFS_MODE_NONE, + ACS_DFS_MODE_ENABLE, + ACS_DFS_MODE_DISABLE, + ACS_DFS_MODE_DEPRIORITIZE +}; + +struct sap_config { + tSap_SSIDInfo_t SSIDinfo; + eCsrPhyMode sap_orig_hw_mode; /* Previous wireless Mode */ + eCsrPhyMode SapHw_mode; /* Wireless Mode */ + eSapMacAddrACL SapMacaddr_acl; + struct qdf_mac_addr accept_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + struct qdf_mac_addr deny_mac[MAX_ACL_MAC_ADDRESS]; /* MAC filtering */ + struct qdf_mac_addr self_macaddr; /* self macaddress or BSSID */ + uint32_t chan_freq; /* Operation channel frequency */ + uint32_t sec_ch_freq; + struct ch_params ch_params; + enum phy_ch_width ch_width_orig; + uint8_t dtim_period; /* dtim interval */ + uint16_t num_accept_mac; + uint16_t num_deny_mac; + /* Max ie length 255 * 2(WPA+RSN) + 2 bytes(vendor specific ID) * 2 */ + uint8_t RSNWPAReqIE[(WLAN_MAX_IE_LEN * 2) + 4]; + eSapAuthType authType; + tCsrAuthList akm_list; + bool privacy; + /* 0 - disabled, 1 - not configured , 2 - configured */ + uint8_t wps_state; + uint16_t RSNWPAReqIELength; /* The byte count in the pWPAReqIE */ + uint32_t beacon_int; /* Beacon Interval */ + enum QDF_OPMODE persona; /* Tells us which persona, GO or AP */ + bool enOverLapCh; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + struct sap_acs_cfg acs_cfg; + uint16_t probeRespIEsBufferLen; + /* buffer for addn ies comes from hostapd */ + void *pProbeRespIEsBuffer; + uint16_t assocRespIEsLen; + /* buffer for addn ies comes from hostapd */ + void *pAssocRespIEsBuffer; + uint16_t probeRespBcnIEsLen; + /* buffer for addn ies comes from hostapd */ + void *pProbeRespBcnIEsBuffer; + uint16_t beacon_tx_rate; + uint8_t *vendor_ie; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + bool require_h2e; + enum sap_acs_dfs_mode acs_dfs_mode; + struct hdd_channel_info *channel_info; + uint32_t channel_info_count; + bool dfs_cac_offload; +#ifdef WLAN_SUPPORT_TWT + bool cfg80211_twt_responder; +#endif +#ifdef WLAN_FEATURE_11BE_MLO + bool mlo_sap; + uint8_t link_id; + uint8_t num_link; +#endif + qdf_freq_t last_acs_freq; + qdf_time_t last_acs_complete_time; +}; + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +typedef enum { + eSAP_DO_NEW_ACS_SCAN, + eSAP_DO_PAR_ACS_SCAN, + eSAP_SKIP_ACS_SCAN +} tSap_skip_acs_scan; +#endif + +typedef enum { + eSAP_DFS_DO_NOT_SKIP_CAC, + eSAP_DFS_SKIP_CAC +} eSapDfsCACState_t; + +typedef enum { + eSAP_DFS_CHANNEL_USABLE, + eSAP_DFS_CHANNEL_AVAILABLE, + eSAP_DFS_CHANNEL_UNAVAILABLE +} eSapDfsChanStatus_t; + +typedef struct sSapDfsNolInfo { + uint8_t dfs_channel_number; + eSapDfsChanStatus_t radar_status_flag; + uint64_t radar_found_timestamp; +} tSapDfsNolInfo; + +typedef struct sSapDfsInfo { + qdf_mc_timer_t sap_dfs_cac_timer; + /* + * New channel frequency to move to when a Radar is + * detected on current Channel + */ + uint32_t target_chan_freq; + uint8_t ignore_cac; + uint32_t user_provided_target_chan_freq; + + /* + * Requests for Channel Switch Announcement IE + * generation and transmission + */ + uint8_t csaIERequired; + uint8_t is_dfs_cac_timer_running; + /* + * New channel width and new channel bonding mode + * will only be updated via channel fallback mechanism + */ + enum phy_ch_width orig_chanWidth; + enum phy_ch_width new_chanWidth; + struct ch_params new_ch_params; + + /* + * sap_operating_channel_location holds SAP indoor, + * outdoor location information. Currently, if this + * param is set this Indoor/outdoor channel interop + * restriction will only be implemented for JAPAN + * regulatory domain. + * + * 0 - Indicates that location unknown + * (or) SAP Indoor/outdoor interop is allowed + * + * 1 - Indicates device is operating on Indoor channels + * and SAP cannot pick next random channel from outdoor + * list of channels when a radar is found on current operating + * DFS channel. + * + * 2 - Indicates device is operating on Outdoor Channels + * and SAP cannot pick next random channel from indoor + * list of channels when a radar is found on current + * operating DFS channel. + */ + uint8_t sap_operating_chan_preferred_location; + + /* + * Flag to indicate if DFS test mode is enabled and + * channel switch is disabled. + */ + uint8_t disable_dfs_ch_switch; + uint16_t tx_leakage_threshold; + /* beacon count before channel switch */ + uint8_t sap_ch_switch_beacon_cnt; + uint8_t sap_ch_switch_mode; + uint16_t reduced_beacon_interval; + uint8_t vdev_id; +} tSapDfsInfo; + +/* MAX number of CAC channels to be recorded */ +#define MAX_NUM_OF_CAC_HISTORY 8 + +/** + * struct prev_cac_result - previous cac result + * @ap_start_time: ap start timestamp + * @ap_end_time: ap stop or cac end timestamp + * @cac_complete: cac complete without found radar event + * @cac_ch_param: ap channel parameters + */ +struct prev_cac_result { + uint64_t ap_start_time; + uint64_t ap_end_time; + bool cac_complete; + struct ch_params cac_ch_param; +}; + +/** + * struct dfs_radar_history - radar found history element + * @time: timestamp in us from system boot + * @radar_found: radar found or not + * @ch_freq: channel frequency in Mhz + */ +struct dfs_radar_history { + uint64_t time; + bool radar_found; + uint16_t ch_freq; +}; + +#ifdef DCS_INTERFERENCE_DETECTION +/** + * struct sap_dcs_info - record sap dcs information. + * @wlan_interference_mitigation_enable: wlan interference mitigation + * is enabled per vdev. + * @is_vdev_starting: is vdev doing restart because of dcs. + */ +struct sap_dcs_info { + bool wlan_interference_mitigation_enable[WLAN_MAX_VDEVS]; + bool is_vdev_starting[WLAN_MAX_VDEVS]; +}; +#endif + +struct sap_ctx_list { + void *sap_context; + enum QDF_OPMODE sapPersona; +}; + +typedef struct tagSapStruct { + /* Information Required for SAP DFS Master mode */ + tSapDfsInfo SapDfsInfo; + struct sap_ctx_list sapCtxList[SAP_MAX_NUM_SESSION]; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + bool acs_with_more_param; + bool enable_dfs_phy_error_logs; + uint8_t one_time_csa_count; +#ifdef DCS_INTERFERENCE_DETECTION + struct sap_dcs_info dcs_info; +#endif +} tSapStruct, *tpSapStruct; + +/* + * struct sap_context - per-BSS Context for SAP + * + * struct sap_context is used to share per-BSS context between SAP and + * its clients. A context is generated by sap_create_ctx() and is + * destroyed by sap_destroy_ctx(). During the lifetime of the BSS the + * SAP context is passed as the primary parameter to SAP APIs. Note + * that by design the contents of the structure are opaque to the + * clients and a SAP context pointer must only be dereferenced by SAP. + */ +struct sap_context; + +/** + * wlansap_roam_callback() - API to get the events for SAP persona + * @ctx: callback context registered with SME (sap context is registered) + * @csr_roam_info: pointer to SME CSR roam info structure + * @roam_status: status of the event reported by SME to SAP + * @roam_result: result of the event reported by SME to SAP + * + * Any activity like start_bss, stop_bss, and etc for SAP persona + * happens, SME reports the result of those events to SAP through this + * callback. + * + * Return: QDF_STATUS based on overall result + */ +QDF_STATUS wlansap_roam_callback(void *ctx, + struct csr_roam_info *csr_roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); + +/** + * sap_create_ctx() - API to create the sap context + * + * This API assigns the sap context from global sap context pool + * stored in gp_sap_ctx[i] array. + * + * Return: Pointer to the SAP context, or NULL if a context could not + * be allocated + */ +struct sap_context *sap_create_ctx(void); + +/** + * sap_destroy_ctx - API to destroy the sap context + * @sap_ctx: Pointer to the SAP context + * + * This API puts back the given sap context to global sap context pool which + * makes current sap session's sap context invalid. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS sap_destroy_ctx(struct sap_context *sap_ctx); + +/** + * sap_init_ctx - Initialize the sap context + * @sap_ctx: Pointer to the SAP context + * @mode: Device mode + * @addr: MAC address of the SAP + * @session_id: Pointer to the session id + * @reinit: if called as part of reinit + * + * sap_create_ctx() allocates the sap context which is uninitialized. + * This API needs to be called to properly initialize the sap context + * which is just created. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: BSS could not be started + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS sap_init_ctx(struct sap_context *sap_ctx, + enum QDF_OPMODE mode, + uint8_t *addr, uint32_t session_id, bool reinit); + +/** + * sap_deinit_ctx() - De-initialize the sap context + * @sap_ctx: Pointer to the SAP context + * + * When SAP session is about to close, this API needs to be called + * to de-initialize all the members of sap context structure, so that + * nobody can accidentally start using the sap context. + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: BSS could not be stopped + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS sap_deinit_ctx(struct sap_context *sap_ctx); + +/** + * sap_is_auto_channel_select() - is channel AUTO_CHANNEL_SELECT + * @sapcontext: Pointer to the SAP context + * + * Return: true on AUTO_CHANNEL_SELECT, false otherwise + */ +bool sap_is_auto_channel_select(struct sap_context *sapcontext); + +QDF_STATUS wlansap_global_init(void); +QDF_STATUS wlansap_global_deinit(void); +typedef QDF_STATUS (*sap_event_cb)(struct sap_event *sap_event, + void *user_context); + +/** + * wlansap_is_channel_in_nol_list() - This API checks if channel is + * in nol list + * @sap_ctx: SAP context pointer + * @chan_freq: channel frequency + * @chanBondState: channel bonding state + * + * Return: True if the channel is in the NOL list, false otherwise + */ +bool wlansap_is_channel_in_nol_list(struct sap_context *sap_ctx, + qdf_freq_t chan_freq, + ePhyChanBondState chanBondState); + +/** + * wlansap_is_channel_leaking_in_nol() - This API checks if channel is leaking + * in nol list + * @sap_ctx: SAP context pointer + * @chan_freq: channel frequency + * @chan_bw: channel bandwidth + * + * Return: True/False + */ +bool wlansap_is_channel_leaking_in_nol(struct sap_context *sap_ctx, + uint16_t chan_freq, + uint8_t chan_bw); + +/** + * wlansap_start_bss() - start BSS + * @sap_ctx: Pointer to the SAP context + * @sap_event_cb: Callback function in HDD called by SAP to inform HDD + * about SAP results + * @config: Pointer to configuration structure passed down from + * HDD(HostApd for Android) + * @user_context: Parameter that will be passed back in all the SAP callback + * events. + * + * This api function provides SAP FSM event eWLAN_SAP_PHYSICAL_LINK_CREATE for + * starting AP BSS + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_start_bss(struct sap_context *sap_ctx, + sap_event_cb sap_event_cb, + struct sap_config *config, void *user_context); + +/** + * wlansap_stop_bss() - stop BSS. + * @sap_ctx: Pointer to SAP context + * + * This api function provides SAP FSM event eSAP_HDD_STOP_INFRA_BSS for + * stopping AP BSS + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_stop_bss(struct sap_context *sap_ctx); + +/** + * wlan_sap_update_next_channel() - Update next channel configured using vendor + * command in SAP context + * @sap_ctx: SAP context + * @channel: channel number + * @chan_bw: channel width + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_update_next_channel(struct sap_context *sap_ctx, + uint8_t channel, + enum phy_ch_width chan_bw); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * wlansap_check_cc_intf() - Get interfering concurrent channel + * @sap_ctx: SAP context pointer + * + * Determine if a concurrent channel is interfering. + * + * Return: Channel freq (Mhz) of the interfering channel, or 0 if none. + */ +uint16_t wlansap_check_cc_intf(struct sap_context *sap_ctx); +#endif + +/** + * wlansap_set_mac_acl() - set MAC list entry in ACL. + * @sap_ctx: Pointer to the SAP context + * @config: Pointer to SAP config. + * + * This api function provides SAP to set mac list entry in accept list as well + * as deny list + * + * Return: The result code associated with performing the operation + * QDF_STATUS_E_FAULT: Pointer to SAP cb is NULL; + * access would cause a page fault + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_set_mac_acl(struct sap_context *sap_ctx, + struct sap_config *config); + +/** + * wlansap_disassoc_sta() - initiate disassociation of station. + * @sap_ctx: Pointer to the SAP context + * @p_del_sta_params: pointer to station deletion parameters + * + * This api function provides for Ap App/HDD initiated disassociation of station + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_disassoc_sta(struct sap_context *sap_ctx, + struct csr_del_sta_params *p_del_sta_params); + +/** + * wlansap_deauth_sta() - Ap App/HDD initiated deauthentication of station + * @sap_ctx: Pointer to the SAP context + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * This api function provides for Ap App/HDD initiated deauthentication of + * station + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_deauth_sta(struct sap_context *sap_ctx, + struct csr_del_sta_params *pDelStaParams); + +/** + * wlansap_set_channel_change_with_csa() - Set channel change with CSA + * @sap_ctx: Pointer to SAP context + * @target_chan_freq: Target channel frequency + * @target_bw: Target bandwidth + * @strict: if true switch to the requested channel always, fail + * otherwise + * + * This api function does a channel change to the target channel specified. + * CSA IE is included in the beacons before doing a channel change. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_set_channel_change_with_csa(struct sap_context *sap_ctx, + uint32_t target_chan_freq, + enum phy_ch_width target_bw, + bool strict); + + +/** + * wlan_sap_getstation_ie_information() - RSNIE Population + * @sap_ctx: Pointer to the SAP context + * @len: Length of @buf + * @buf: RSNIE IE data + * + * Populate RSN IE from CSR to HDD context + * + * Return: QDF_STATUS enumeration + */ + +QDF_STATUS wlan_sap_getstation_ie_information(struct sap_context *sap_ctx, + uint32_t *len, uint8_t *buf); + +/** + * wlansap_clear_acl() - Clear all ACLs + * @sap_ctx: Pointer to the SAP context + * + * Return: QDF_STATUS. If success the ACLs were cleared, otherwise an + * error occurred. + */ +QDF_STATUS wlansap_clear_acl(struct sap_context *sap_ctx); + +/** + * wlansap_get_acl_accept_list() - Get ACL accept list + * @sap_ctx: Pointer to the SAP context + * @pAcceptList: Pointer to the buffer to store the ACL accept list + * @nAcceptList: Pointer to the location to store the number of + * entries in the ACL accept list. + * + * Return: QDF_STATUS. If success the data was returned, otherwise an + * error occurred. + */ +QDF_STATUS wlansap_get_acl_accept_list(struct sap_context *sap_ctx, + struct qdf_mac_addr *pAcceptList, + uint16_t *nAcceptList); + +/** + * wlansap_is_channel_present_in_acs_list() - Freq present in ACS list or not + * @freq: Frequency to be searched + * @ch_freq_list: channel frequency list. + * @ch_count: Channel frequency list count + * + * Return: True is found, false otherwise + */ +bool wlansap_is_channel_present_in_acs_list(uint32_t freq, + uint32_t *ch_freq_list, + uint8_t ch_count); + +/** + * wlansap_get_acl_deny_list() - Get ACL deny list + * @sap_ctx: Pointer to the SAP context + * @pDenyList: Pointer to the buffer to store the ACL deny list + * @nDenyList: Pointer to the location to store the number of + * entries in the ACL deny list. + * + * Return: QDF_STATUS. If success the data was returned, otherwise an + * error occurred. + */ +QDF_STATUS wlansap_get_acl_deny_list(struct sap_context *sap_ctx, + struct qdf_mac_addr *pDenyList, + uint16_t *nDenyList); + +/** + * wlansap_set_acl_mode() - Set the SAP ACL mode + * @sap_ctx: The SAP context pointer + * @mode: the desired ACL mode + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_set_acl_mode(struct sap_context *sap_ctx, + eSapMacAddrACL mode); + +/** + * wlansap_get_acl_mode() - Get the SAP ACL mode + * @sap_ctx: The SAP context pointer + * @mode: Pointer where to return the current ACL mode + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_get_acl_mode(struct sap_context *sap_ctx, + eSapMacAddrACL *mode); + +/** + * wlansap_modify_acl() - Update ACL entries + * @sap_ctx: Pointer to the SAP context + * @peer_sta_mac: peer sta mac to be updated. + * @list_type: allow/Deny list type. + * @cmd: command to be executed on ACL. + * + * This function is called when a peer needs to be added or deleted from the + * allow/deny ACL + * + * Return: Status + */ +QDF_STATUS wlansap_modify_acl(struct sap_context *sap_ctx, + uint8_t *peer_sta_mac, + eSapACLType list_type, eSapACLCmdType cmd); + +/** + * wlansap_channel_change_request() - Send channel change request + * @sap_ctx: Pointer to the SAP context + * @target_chan_freq: Target channel + * + * This API is used to send an Indication to SME/PE to change the + * current operating channel to a different target channel. + * + * The Channel change will be issued by SAP under the following + * scenarios. + * 1. A radar indication is received during SAP CAC WAIT STATE and + * channel change is required. + * 2. A radar indication is received during SAP STARTED STATE and + * channel change is required. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + * + */ +QDF_STATUS wlansap_channel_change_request(struct sap_context *sap_ctx, + uint32_t target_chan_freq); + +/** + * wlansap_get_sec_channel() - get the secondary sap channel + * @sec_ch_offset: secondary channel offset. + * @op_chan_freq: Operating sap channel frequency. + * @sec_chan_freq: channel frequency to be filled. + * + * This API will get the secondary sap channel from the offset, and + * operating channel. + * + * Return: None + * + */ +void wlansap_get_sec_channel(uint8_t sec_ch_offset, + uint32_t op_chan_freq, + uint32_t *sec_chan_freq); + +/** + * wlansap_start_beacon_req() - Send Start Beaconing Request + * @sap_ctx: Pointer to the SAP context + * + * This API is used to send an Indication to SME/PE to start + * beaconing on the current operating channel. + * + * When SAP is started on DFS channel and when ADD BSS RESP is received + * LIM temporarily holds off Beaconing for SAP to do CAC WAIT. When + * CAC WAIT is done SAP resumes the Beacon Tx by sending a start beacon + * request to LIM. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_start_beacon_req(struct sap_context *sap_ctx); + +/** + * wlansap_dfs_send_csa_ie_request() - Send CSA IE + * @sap_ctx: Pointer to the SAP context + * + * This API is used to send channel switch announcement request to PE + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success + */ +QDF_STATUS wlansap_dfs_send_csa_ie_request(struct sap_context *sap_ctx); + +/** + * wlansap_get_dfs_ignore_cac() - Get ignore_cac value + * @mac_handle: Opaque handle to the global MAC context + * @ignore_cac: Location to store ignore_cac value + * + * This API is used to Get the value of ignore_cac value + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_get_dfs_ignore_cac(mac_handle_t mac_handle, + uint8_t *ignore_cac); + +/** + * wlansap_set_dfs_ignore_cac() - Set ignore_cac value + * @mac_handle: Opaque handle to the global MAC context + * @ignore_cac: value to set for ignore_cac variable in DFS global structure. + * + * This API is used to Set the value of ignore_cac value + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_set_dfs_ignore_cac(mac_handle_t mac_handle, + uint8_t ignore_cac); +/** + * wlansap_get_dfs_cac_state() - Get cac_state value + * @mac_handle: Opaque handle to the global MAC context + * @sap_context: sap adapter context + * @cac_state: Location to store cac_state value + * + * This API is used to Get the value of current cac state + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_get_dfs_cac_state(mac_handle_t mac_handle, + struct sap_context *sap_context, + bool *cac_state); + +/** + * wlansap_get_csa_chanwidth_from_phymode() - function to populate + * channel width from user configured phymode for csa + * @sap_context: sap adapter context + * @chan_freq: target channel frequency (MHz) + * @tgt_ch_params: target new channel bw parameters to be updated + * + * Return: phy_ch_width + */ +enum phy_ch_width +wlansap_get_csa_chanwidth_from_phymode(struct sap_context *sap_context, + uint32_t chan_freq, + struct ch_params *tgt_ch_params); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +QDF_STATUS +wlan_sap_set_channel_avoidance(mac_handle_t mac_handle, + bool sap_channel_avoidance); +#endif + +/** + * wlan_sap_set_acs_with_more_param() - sets acs_with_more_param ini param + * @mac_handle: Opaque handle to the global MAC context + * @acs_with_more_param: ini parameter value + * + * Return: The QDF_STATUS code. + */ +QDF_STATUS +wlan_sap_set_acs_with_more_param(mac_handle_t mac_handle, + bool acs_with_more_param); + +/** + * wlansap_set_dfs_preferred_channel_location() - set dfs preferred channel + * @mac_handle: Opaque handle to the global MAC context + * + * This API is used to set sap preferred channels location + * to resetrict the DFS random channel selection algorithm + * either Indoor/Outdoor channels only. + * dfs_Preferred_Channels_location : + * 0 - Indicates No preferred channel location restrictions + * 1 - Indicates SAP Indoor Channels operation only. + * 2 - Indicates SAP Outdoor Channels operation only. + * + * Return: The QDF_STATUS code associated with performing the operation + * QDF_STATUS_SUCCESS: Success and error code otherwise. + */ +QDF_STATUS wlansap_set_dfs_preferred_channel_location(mac_handle_t mac_handle); + +/** + * wlansap_set_dfs_target_chnl() - Set target channel + * @mac_handle: Opaque handle for the global MAC context + * @target_chan_freq: target channel frequency to be set + * + * This API is used to set next target chnl as provided channel. + * you can provide any valid channel to this API. + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_set_dfs_target_chnl(mac_handle_t mac_handle, + uint32_t target_chan_freq); + +/** + * wlan_sap_get_phymode() - Returns sap phymode. + * @sap_ctx: Pointer to Sap Context. + * + * This function provides the SAP current phymode. + * + * Return: phymode + */ +eCsrPhyMode wlan_sap_get_phymode(struct sap_context *sap_ctx); + +/** + * wlan_sap_get_concurrent_bw() - Returns SAP BW based on concurrent channel & + * STA DFS channel + * @pdev: Pointer to Pdev + * @psoc: Pointer to Psoc + * @con_ch_freq: interfering concurrent channel + * @channel_width: Channel width + * + * Return: Channel width. If STA is not present on con_ch_freq, it returns + * max of STA BW and 80 Mhz. If STA is not connected in dfs chan or STA + *........BW is not 160 Mhz (which includes DFS channel), then it will return + * BW maximum of STA BW and 80 Mhz. If DFS STA is present, then return + * BW as min of 80 and STA BW. + */ +enum phy_ch_width wlan_sap_get_concurrent_bw(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc, + qdf_freq_t con_ch_freq, + enum phy_ch_width channel_width); + +/** + * wlan_sap_get_vht_ch_width() - Returns SAP VHT channel width. + * @sap_ctx: Pointer to Sap Context + * + * This function provides the SAP current VHT channel with. + * + * Return: VHT channel width + */ +uint32_t wlan_sap_get_vht_ch_width(struct sap_context *sap_ctx); + +/** + * wlan_sap_get_ch_params() - get ch params + * @sap_ctx: Pointer to Sap Context + * @ch_params: returned ch_params + * + * This function get sap's ch_params + * + * Return: true for success + */ +bool wlan_sap_get_ch_params(struct sap_context *sap_ctx, + struct ch_params *ch_params); + +/** + * wlan_sap_set_sap_ctx_acs_cfg() - Sets acs cfg + * @sap_ctx: Pointer to Sap Context + * @sap_config: Pointer to sap config + * + * This function sets the acs cfg in sap context. + * + * Return: None + */ +void wlan_sap_set_sap_ctx_acs_cfg(struct sap_context *sap_ctx, + struct sap_config *sap_config); + +void sap_config_acs_result(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint32_t sec_ch_freq); + +QDF_STATUS wlansap_update_sap_config_add_ie(struct sap_config *config, + const uint8_t *pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType); + +QDF_STATUS wlansap_reset_sap_config_add_ie(struct sap_config *config, + eUpdateIEsType updateType); + +void wlansap_extend_to_acs_range(mac_handle_t mac_handle, + uint32_t *start_ch_freq, + uint32_t *end_ch_freq, + uint32_t *bandStartChannel, + uint32_t *bandEndChannel); + +#ifdef WLAN_FEATURE_SON +/** + * wlansap_son_update_sap_config_phymode() - update sap config according to + * phy_mode. This API is for son, + * There is no band switching when + * son phy mode is changed. + * @vdev: Pointer to vdev object + * @config: Pointer to sap config + * @phy_mode: pointer to phy mode + * + * Return: QDF_STATUS + */ +QDF_STATUS +wlansap_son_update_sap_config_phymode(struct wlan_objmgr_vdev *vdev, + struct sap_config *config, + enum qca_wlan_vendor_phy_mode phy_mode); +#endif + +/** + * wlansap_set_dfs_nol() - Set dfs nol + * @sap_ctx: SAP context + * @conf: set type + * + * Return: QDF_STATUS + */ +#ifdef DFS_COMPONENT_ENABLE +QDF_STATUS wlansap_set_dfs_nol(struct sap_context *sap_ctx, + eSapDfsNolType conf); +#else +static inline QDF_STATUS wlansap_set_dfs_nol(struct sap_context *sap_ctx, + eSapDfsNolType conf) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wlan_sap_set_dfs_pri_multiplier() - Set dfs_pri_multiplier + * @mac_handle: Opaque handle to the global MAC context + * + * Return: none + */ +#ifdef DFS_PRI_MULTIPLIER +void wlan_sap_set_dfs_pri_multiplier(mac_handle_t mac_handle); +#else +static inline void wlan_sap_set_dfs_pri_multiplier(mac_handle_t mac_handle) +{ +} +#endif + +/** + * wlan_sap_set_vendor_acs() - Set vendor specific acs in sap context + * @sap_context: SAP context + * @is_vendor_acs: if vendor specific acs is enabled + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_sap_set_vendor_acs(struct sap_context *sap_context, + bool is_vendor_acs); + +/** + * wlansap_populate_del_sta_params() - populate delete station parameter + * @mac: Pointer to peer mac address. + * @reason_code: Reason code for the disassoc/deauth. + * @subtype: Subtype points to either disassoc/deauth frame. + * @params: Parameters to be populated. + * + * This API is used to populate delete station parameter structure + * + * Return: none + */ +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct csr_del_sta_params *params); + +/** + * wlansap_acs_chselect() - Initiates acs channel selection + * @sap_context: Pointer to SAP context structure + * @acs_event_callback: Callback function in hdd called by sap + * to inform hdd about channel selection result + * @config: Pointer to configuration structure + * passed down from hdd + * @pusr_context: Parameter that will be passed back in all + * the sap callback events. + * + * This function serves as an api for hdd to initiate acs scan pre + * start bss. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS wlansap_acs_chselect(struct sap_context *sap_context, + sap_event_cb acs_event_callback, + struct sap_config *config, + void *pusr_context); + +/** + * sap_undo_acs() - Undo acs i.e free the allocated ch lists + * @sap_context: pointer to the SAP context + * @sap_cfg: pointer to the SAP confid structure + * + * This function will free the memory allocated to the sap ctx channel list, acs + * cfg ch list and master ch list. + * + * Return: None + */ +void sap_undo_acs(struct sap_context *sap_context, struct sap_config *sap_cfg); + +/** + * wlansap_get_chan_width() - get sap channel width. + * @sap_ctx: pointer to the SAP context + * + * This function get channel width of sap. + * + * Return: sap channel width + */ +uint32_t wlansap_get_chan_width(struct sap_context *sap_ctx); + +/** + * wlansap_get_max_bw_by_phymode() - get max channel width based on phymode + * @sap_ctx: pointer to the SAP context + * + * This function get max channel width of sap based on phymode. + * + * Return: channel width + */ +enum phy_ch_width +wlansap_get_max_bw_by_phymode(struct sap_context *sap_ctx); + +/* + * wlansap_set_invalid_session() - set session ID to invalid + * @sap_ctx: pointer to the SAP context + * + * This function sets session ID to invalid + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_set_invalid_session(struct sap_context *sap_ctx); + +/* + * wlansap_set_invalid_session() - Release vdev ref taken by sap context + * @sap_ctx: pointer to the SAP context + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_release_vdev_ref(struct sap_context *sap_ctx); + +/** + * sap_get_cac_dur_dfs_region() - get cac duration and dfs region. + * @sap_ctx: sap context + * @cac_duration_ms: pointer to cac duration + * @dfs_region: pointer to dfs region + * @chan_freq: channel frequency + * @ch_params: pointer to ch_params + * + * Get cac duration and dfs region. + * + * Return: None + */ +void sap_get_cac_dur_dfs_region(struct sap_context *sap_ctx, + uint32_t *cac_duration_ms, + uint32_t *dfs_region, + qdf_freq_t chan_freq, + struct ch_params *ch_params); + +/** + * sap_clear_global_dfs_param() - Reset global dfs param of sap ctx + * @mac_handle: pointer to mac handle + * @sap_ctx: sap context + * + * This API resets global dfs param of sap ctx. + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_clear_global_dfs_param(mac_handle_t mac_handle, + struct sap_context *sap_ctx); + +/** + * sap_dfs_set_current_channel() - Set current channel params in dfs component + * @sap_ctx: sap context + * + * Set current channel params in dfs component, this info will be used to mark + * the channels in nol when radar is detected. + * + * Return: None + */ +void sap_dfs_set_current_channel(void *sap_ctx); + +/** + * wlansap_cleanup_cac_timer() - Force cleanup DFS CAC timer + * @sap_ctx: sap context + * + * Force cleanup DFS CAC timer when reset all adapters. It will not + * check concurrency SAP since just called when reset all adapters. + * + * Return: None + */ +void wlansap_cleanup_cac_timer(struct sap_context *sap_ctx); + +/** + * wlansap_update_owe_info() - Update OWE info + * @sap_ctx: sap context + * @peer: peer mac + * @ie: IE from hostapd + * @ie_len: IE length + * @owe_status: status from hostapd + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_update_owe_info(struct sap_context *sap_ctx, + uint8_t *peer, const uint8_t *ie, + uint32_t ie_len, uint16_t owe_status); + +/** + * wlansap_update_ft_info() - Update FT info + * @sap_ctx: sap context + * @peer: peer mac + * @ie: IE from hostapd + * @ie_len: IE length + * @ft_status: wlan status codes + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_update_ft_info(struct sap_context *sap_ctx, + uint8_t *peer, const uint8_t *ie, + uint32_t ie_len, uint16_t ft_status); + +/** + * wlansap_filter_ch_based_acs() -filter out channel based on acs + * @sap_ctx: sap context + * @ch_freq_list: pointer to channel frequency list + * @ch_cnt: channel number of channel list + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_filter_ch_based_acs(struct sap_context *sap_ctx, + uint32_t *ch_freq_list, + uint32_t *ch_cnt); + +/** + * wlansap_is_6ghz_included_in_acs_range() - check 6ghz channel included in + * ACS range + * @sap_ctx: sap context + * + * Return: QDF_STATUS + */ +bool wlansap_is_6ghz_included_in_acs_range(struct sap_context *sap_ctx); + +/** + * wlansap_get_safe_channel_from_pcl_and_acs_range() - Get safe channel for SAP + * restart + * @sap_ctx: sap context + * @ch_width: selected channel bandwdith + * + * Get a safe channel to restart SAP. PCL already takes into account the + * unsafe channels. So, the PCL is validated with the ACS range to provide + * a safe channel for the SAP to restart. + * + * Return: Chan freq num to restart SAP in case of success. In case of any + * failure, the channel number returned is zero. + */ +uint32_t +wlansap_get_safe_channel_from_pcl_and_acs_range(struct sap_context *sap_ctx, + enum phy_ch_width *ch_width); + +/** + * wlansap_get_safe_channel_from_pcl_for_sap() - Get safe and active channel + * for SAP restart + * @sap_ctx: sap context + * + * Get a safe and active channel to restart SAP. PCL already takes into account + * the unsafe channels. + * + * Return: Chan freq num to restart SAP in case of success. In case of any + * failure, the channel number returned is zero. + */ +uint32_t wlansap_get_safe_channel_from_pcl_for_sap(struct sap_context *sap_ctx); + +/** + * wlansap_get_chan_band_restrict() - get new chan for band change + * @sap_ctx: sap context pointer + * @csa_reason: channel switch reason to update + * + * Sap/p2p go channel switch from 5G to 2G by CSA when 5G band disabled to + * avoid conflict with modem N79. + * Sap/p2p go channel restore to 5G channel when 5G band enabled. + * Note: csa_reason is only updated when channel is disabled or band is + * restricted, so it must be initialized to a default value beforehand + * + * Return - restart channel in MHZ + */ +qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx, + enum sap_csa_reason_code *csa_reason); + +/** + * wlansap_override_csa_strict_for_sap() - check user CSA strict or not + * @mac_handle: Opaque handle to the global MAC context + * @sap_ctx: sap context + * @target_chan_freq: target channel frequency in MHz + * @strict: CSA strict flag + * + * If force SCC enabled, user trigger SAP CSA and target channel + * doesn't cause MCC with existing STA/CLI, then override strict flag to + * true, so that driver can skip the overlap interference check and + * allow the CSA go through. This is to allow SAP/GO force SCC in + * same band. + * + * Return: true if CSA is strict, otherwise false + */ +bool +wlansap_override_csa_strict_for_sap(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint32_t target_chan_freq, + bool strict); + +/** + * wlansap_validate_channel_post_csa() - Check SAP channel unsafe or not + * after CSA + * @mac_handle: global MAC context + * @sap_ctx: SAP context + * + * Return: bool + */ +bool wlansap_validate_channel_post_csa(mac_handle_t mac_handle, + struct sap_context *sap_ctx); + +/** + * sap_get_csa_reason_str() - Get csa reason in string + * @reason: sap reason enum value + * + * Return: string reason + */ +const char *sap_get_csa_reason_str(enum sap_csa_reason_code reason); + +#ifdef FEATURE_RADAR_HISTORY +/** + * wlansap_query_radar_history() - get radar history info + * @mac_handle: mac context + * @radar_history: radar history buffer to be returned + * @count: total history count + * + * The API will return the dfs nol list(Radar found history) and + * CAC history (no Radar found). + * + * Return - QDF_STATUS + */ +QDF_STATUS +wlansap_query_radar_history(mac_handle_t mac_handle, + struct dfs_radar_history **radar_history, + uint32_t *count); +#endif + +#ifdef DCS_INTERFERENCE_DETECTION +/** + * wlansap_dcs_set_vdev_wlan_interference_mitigation() - set wlan + * interference mitigation enable information per vdev + * @sap_context: sap context + * @wlan_interference_mitigation_enable: wlan interference mitigation + * enable or not + * + * This function is used to set whether wlan interference mitigation + * enable or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( + struct sap_context *sap_context, + bool wlan_interference_mitigation_enable); + +/** + * wlansap_dcs_set_wlan_interference_mitigation_on_band() - set wlan + * interference mitigation enable information based on band information + * @sap_context: sap context + * @sap_cfg: sap config + * + * This function is used to set whether wlan interference mitigation + * enable or not based on band information + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_dcs_set_wlan_interference_mitigation_on_band( + struct sap_context *sap_context, + struct sap_config *sap_cfg); + +/** + * wlansap_dcs_set_vdev_starting() - set vdev starting + * @sap_context: sap context + * @vdev_starting: vdev in starting states + * + * This function is used to set whether vdev starting or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_dcs_set_vdev_starting(struct sap_context *sap_context, + bool vdev_starting); + +/** + * wlansap_dcs_is_wlan_interference_mitigation_enabled() - get wlan interference + * mitigation enabled information + * @sap_context: sap context + * + * This function is used to get wlan interference mitigation enabled information + * with given sap + * + * Return: true if wlan interference mitigation is enabled with given sap + */ +bool wlansap_dcs_is_wlan_interference_mitigation_enabled( + struct sap_context *sap_context); + +/** + * wlansap_dcs_get_freq() - get dcs channel frequency + * @sap_context: sap context + * + * This function is used to get dcs channel frequency with give sap + * + * Return: sap dcs channel frequency + */ +qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context); +#else +static inline QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( + struct sap_context *sap_context, + bool wlan_interference_mitigation_enable) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlansap_dcs_set_wlan_interference_mitigation_on_band( + struct sap_context *sap_context, + struct sap_config *sap_cfg) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wlansap_dcs_set_vdev_starting( + struct sap_context *sap_context, bool vdev_starting) +{ + return QDF_STATUS_SUCCESS; +} + +static inline bool wlansap_dcs_is_wlan_interference_mitigation_enabled( + struct sap_context *sap_context) +{ + return false; +} + +static inline qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context) +{ + return 0; +} +#endif + +/** + * wlansap_filter_vendor_unsafe_ch_freq() - filter sap acs ch list by + * vendor unsafe ch freq ranges + * @sap_context: sap context + * @sap_config: sap conifg + * + * This function is used to filter out unsafe channel frequency from acs + * channel frequency list based on vendor unsafe channel frequency ranges. + * + * Return: true if vendor unsafe ch range is present, otherwise false + */ +bool wlansap_filter_vendor_unsafe_ch_freq( + struct sap_context *sap_context, struct sap_config *sap_config); + +/** + * wlansap_dump_acs_ch_freq() - print acs channel frequency + * @sap_context: sap context + * + * This function is used to print acs channel frequecny + * + * Return: None + */ +void wlansap_dump_acs_ch_freq(struct sap_context *sap_context); + +/** + * wlansap_set_acs_ch_freq() - set acs channel frequency + * @sap_context: sap context + * @ch_freq: ch_freq to be set + * + * This function is used to set acs channel frequency + * + * Return: None + */ +void wlansap_set_acs_ch_freq(struct sap_context *sap_context, + qdf_freq_t ch_freq); + +/** + * sap_acquire_vdev_ref() - Increment reference count for vdev object + * @psoc: Object Manager PSoC object + * @sap_ctx: to store vdev object pointer + * @session_id: used to get vdev object + * + * This function is used to increment vdev object reference count and store + * vdev pointer in sap_ctx. + * + * Return: QDF_STATUS_SUCCESS - If able to get vdev object reference + * else qdf status failure codes + */ +QDF_STATUS sap_acquire_vdev_ref(struct wlan_objmgr_psoc *psoc, + struct sap_context *sap_ctx, + uint8_t session_id); + +/** + * sap_dump_acs_channel() - dump acs channel list + * @acs_cfg: acs config + * + * This function dump acs channel list + * + * Return: void. + */ +void sap_dump_acs_channel(struct sap_acs_cfg *acs_cfg); + +/** + * sap_release_vdev_ref() - Decrement reference count for vdev object + * @sap_ctx: for which vdev reference is to be decremented + * + * Return: None + */ +void sap_release_vdev_ref(struct sap_context *sap_ctx); + +#ifdef CONFIG_AFC_SUPPORT +/** + * sap_afc_dcs_sel_chan() - API to select best SAP best channel/bandwidth with + * channel ACS weighted algorithm + * @sap_ctx: SAP context handle + * @cur_freq: SAP current home channel frequency + * @cur_bw: SAP current channel bandwidth + * @pref_bw: pointer to channel bandwidth prefer to set as input, and target + * channel bandwidth can set as output + * + * Return: target home channel frequency selected + */ +qdf_freq_t sap_afc_dcs_sel_chan(struct sap_context *sap_ctx, + qdf_freq_t cur_freq, + enum phy_ch_width cur_bw, + enum phy_ch_width *pref_bw); +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * sap_phymode_is_eht() - Is sap phymode EHT + * @phymode: phy mode + * + * Return: true if phy mode is EHT + */ +bool sap_phymode_is_eht(eCsrPhyMode phymode); + +/** + * sap_acs_is_puncture_applicable() - Is static puncturing applicable according + * to ACS configure of given sap acs config. + * @acs_cfg: pointer to sap_acs_cfg + * + * Return: true if static puncturing is applicable to given sap acs config. + */ +bool sap_acs_is_puncture_applicable(struct sap_acs_cfg *acs_cfg); + +/** + * sap_acs_set_puncture_support() - Set puncturing support according + * to ACS configure of given sap. + * @sap_ctx: Pointer to SAP Context + * @ch_params: pointer to ch_params + * + * Return: void. + */ +void sap_acs_set_puncture_support(struct sap_context *sap_ctx, + struct ch_params *ch_params); +#else +static inline bool sap_phymode_is_eht(eCsrPhyMode phymode) +{ + return false; +} + +static inline bool sap_acs_is_puncture_applicable(struct sap_acs_cfg *acs_cfg) +{ + return false; +} + +static inline void sap_acs_set_puncture_support(struct sap_context *sap_ctx, + struct ch_params *ch_params) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * sap_cac_end_notify() - Notify CAC end to HDD + * @mac_handle: Opaque handle to the global MAC context + * @roamInfo: pointer to the struct csr_roam_info + * + * Function will be called to notify eSAP_DFS_CAC_END event to HDD + * + * Return: QDF_STATUS_SUCCESS if the notification was sent, otherwise + * an appropriate QDF_STATUS error + */ +QDF_STATUS sap_cac_end_notify(mac_handle_t mac_handle, + struct csr_roam_info *roamInfo); + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +static inline bool sap_is_acs_scan_optimize_enable(void) +{ + return true; +} + +void wlansap_process_chan_info_event(struct sap_context *sap_ctx, + struct csr_roam_info *roam_info); +#else +static inline bool sap_is_acs_scan_optimize_enable(void) +{ + return false; +} + +static inline +void wlansap_process_chan_info_event(struct sap_context *sap_ctx, + struct csr_roam_info *roam_info) +{ +} +#endif + +/** + * wlansap_update_ll_lt_sap_acs_result() - Update acs result of LL_LT_SAP + * @sap_ctx: sap context + * @last_acs_freq: last acs frequency to be set + * + * This function is used to update stored acs channel frequency + * + * Return: None + */ +void wlansap_update_ll_lt_sap_acs_result(struct sap_context *sap_ctx, + qdf_freq_t last_acs_freq); + +/** + * wlansap_update_sap_chan_list() - set channel list of sap + * @sap_config: sap config + * @freq_list: freq list sent by userspace + * @count: valid freq count + * + * Return: 0 on success, else error number + */ +int wlansap_update_sap_chan_list(struct sap_config *sap_config, + qdf_freq_t *freq_list, uint16_t count); + +/** + * wlansap_sort_channel_list() - Sort channel list + * @vdev_id: Vdev Id + * @list: List of channels which needs to sort + * @ch_info: Fill sorted channels list in ch_info + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_sort_channel_list(uint8_t vdev_id, qdf_list_t *list, + struct sap_sel_ch_info *ch_info); + +/** + * wlansap_free_chan_info() - API to free allocated memory + * @ch_param: Pointer to sap_sel_ch_info structure + * + * Return: None + */ +void wlansap_free_chan_info(struct sap_sel_ch_info *ch_param); + +/** + * wlansap_get_user_config_acs_ch_list() - Get user config ACS channel list + * @vdev_id: Vdev Id + * @filter: Filter to apply to get scan result + * + * Return: None + */ +void wlansap_get_user_config_acs_ch_list(uint8_t vdev_id, + struct scan_filter *filter); +#ifdef __cplusplus +} +#endif +#endif /* #ifndef WLAN_QCT_WLANSAP_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_api_link_cntl.c b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_api_link_cntl.c new file mode 100644 index 0000000000..9a1764e5fe --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_api_link_cntl.c @@ -0,0 +1,1763 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=========================================================================== + + s a p A p i L i n k C n t l . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + Link Control functions. + + The functions externalized by this module are to be called ONLY by other + WLAN modules (HDD) + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "qdf_trace.h" +/* Pick up the CSR callback definition */ +#include "csr_api.h" +#include "ani_global.h" +#include "csr_inside_api.h" +#include "sme_api.h" +/* SAP Internal API header file */ +#include "sap_internal.h" +#include "wlan_policy_mgr_api.h" +#include "wma.h" +#include +#include +#include "wlan_reg_services_api.h" +#include +#include +#include "wlan_pre_cac_api.h" +#include +#include + +/* IF MGR API header file */ +#include "wlan_if_mgr_ucfg_api.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ +#define SAP_DEBUG + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Externalized Function Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +#if defined(WLAN_FEATURE_11BE) +static inline bool sap_acs_cfg_is_chwidth_320mhz(uint16_t width) +{ + return width == CH_WIDTH_320MHZ; +} +#else +static inline bool sap_acs_cfg_is_chwidth_320mhz(uint16_t width) +{ + return false; +} +#endif + +#ifdef WLAN_FEATURE_11BE +static void sap_acs_set_puncture_bitmap(struct sap_context *sap_ctx, + struct ch_params *ch_params) +{ + sap_debug("ccfs0 %d ch_width %d, punct 0x%x", + ch_params->center_freq_seg0, + ch_params->ch_width, + ch_params->reg_punc_bitmap); + sap_ctx->acs_cfg->acs_puncture_bitmap = ch_params->reg_punc_bitmap; +} +#else +static void sap_acs_set_puncture_bitmap(struct sap_context *sap_ctx, + struct ch_params *ch_params) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * sap_config_acs_result : Generate ACS result params based on ch constraints + * @sap_ctx: pointer to SAP context data struct + * @mac_handle: Opaque handle to the global MAC context + * @sec_ch_freq: Secondary channel frequency + * + * This function calculates the ACS result params: ht sec channel, vht channel + * information and channel bonding based on selected ACS channel. + * + * Return: None + */ + +void sap_config_acs_result(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint32_t sec_ch_freq) +{ + struct ch_params ch_params = {0}; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + enum phy_ch_width new_ch_width; + + ch_params.ch_width = sap_ctx->acs_cfg->ch_width; + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(&ch_params, true); + + new_ch_width = + wlan_sap_get_concurrent_bw(mac_ctx->pdev, mac_ctx->psoc, + sap_ctx->acs_cfg->pri_ch_freq, + ch_params.ch_width); + sap_debug("new_ch_width:%d", new_ch_width); + ch_params.ch_width = new_ch_width; + + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, sap_ctx->acs_cfg->pri_ch_freq, + sec_ch_freq, &ch_params, REG_CURRENT_PWR_MODE); + sap_ctx->acs_cfg->ch_width = ch_params.ch_width; + if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_40MHZ || + WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ctx->acs_cfg->pri_ch_freq)) + sap_ctx->acs_cfg->vht_seg0_center_ch_freq = + ch_params.mhz_freq_seg0; + else + sap_ctx->acs_cfg->vht_seg0_center_ch_freq = 0; + + if (sap_ctx->acs_cfg->ch_width == CH_WIDTH_80P80MHZ || + (sap_ctx->acs_cfg->ch_width == CH_WIDTH_160MHZ) || + sap_acs_cfg_is_chwidth_320mhz(sap_ctx->acs_cfg->ch_width)) + sap_ctx->acs_cfg->vht_seg1_center_ch_freq = + ch_params.mhz_freq_seg1; + else + sap_ctx->acs_cfg->vht_seg1_center_ch_freq = 0; + + if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq - 20; + else if (ch_params.sec_ch_offset == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + sap_ctx->acs_cfg->ht_sec_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq + 20; + else + sap_ctx->acs_cfg->ht_sec_ch_freq = 0; + + sap_acs_set_puncture_bitmap(sap_ctx, &ch_params); +} + +/** + * sap_hdd_signal_event_handler() - routine to inform hostapd via callback + * @ctx: pointer to sap context which was passed to callback + * + * this routine will be registered as callback to sme_close_session, so upon + * closure of sap session it notifies the hostapd + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_hdd_signal_event_handler(void *ctx) +{ + struct sap_context *sap_ctx = ctx; + QDF_STATUS status; + + if (!sap_ctx) { + sap_err("sap context is not valid"); + return QDF_STATUS_E_FAILURE; + } + status = sap_signal_hdd_event(sap_ctx, NULL, + sap_ctx->sap_state, + (void *) sap_ctx->sap_status); + return status; +} + +/** + * acs_scan_done_status_str() - parse scan status to string + * @status: scan status + * + * This function parse scan status to string + * + * Return: status string + * + */ +static const char *acs_scan_done_status_str(eCsrScanStatus status) +{ + switch (status) { + case eCSR_SCAN_SUCCESS: + return "Success"; + case eCSR_SCAN_FAILURE: + return "Failure"; + case eCSR_SCAN_ABORT: + return "Abort"; + case eCSR_SCAN_FOUND_PEER: + return "Found peer"; + default: + return "Unknown"; + } +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +static void wlansap_send_acs_success_event(struct sap_context *sap_ctx, + uint32_t scan_id) +{ + if (scan_id) { + sap_debug("Sending ACS Scan skip event"); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_ACS_SCAN_SUCCESS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } else { + sap_debug("ACS scanid: %d (skipped ACS SCAN)", scan_id); + } +} +#else +static inline void wlansap_send_acs_success_event(struct sap_context *sap_ctx, + uint32_t scan_id) +{ +} +#endif + +static uint32_t +wlansap_calculate_chan_from_scan_result(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint32_t scan_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + qdf_list_t *list = NULL; + struct scan_filter *filter; + uint32_t oper_channel = SAP_CHANNEL_NOT_SELECTED; + + filter = qdf_mem_malloc(sizeof(*filter)); + + if (filter) { + if (sap_ctx->partial_acs_scan) + filter->age_threshold = + sap_ctx->acs_cfg->last_scan_ageout_time; + else + filter->age_threshold = qdf_get_time_of_the_day_ms() - + sap_ctx->acs_req_timestamp; + } + + list = wlan_scan_get_result(mac_ctx->pdev, filter); + + if (filter) + qdf_mem_free(filter); + + if (list) + sap_debug("num_entries %d", qdf_list_size(list)); + + wlansap_send_acs_success_event(sap_ctx, scan_id); + + oper_channel = sap_select_channel(mac_handle, sap_ctx, list); + wlan_scan_purge_results(list); + + return oper_channel; +} + +static void +wlansap_filter_unsafe_ch(struct wlan_objmgr_psoc *psoc, + struct sap_context *sap_ctx) +{ + uint16_t i; + uint16_t num_safe_ch = 0; + uint32_t freq; + + /* + * There are two channel list, one acs cfg channel list, and one + * sap_ctx->freq_list, the unsafe channels for acs cfg is updated here + * and the sap_ctx->freq list would be handled in sap_chan_sel_init + * which would consider more params other than unsafe channels. + * So the two lists now would be in sync. But in case the ACS weight + * calculation does not get through due to no scan result or no chan + * selected, or any other reason, the default channel is chosen which + * would contain the channels in acs cfg. Now since the scan takes time + * there could be channels present in acs cfg that could become unsafe + * in the mean time, so it is better to filter out those channels from + * the acs channel list before choosing one of them as a default channel + */ + for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++) { + freq = sap_ctx->acs_cfg->freq_list[i]; + if (!policy_mgr_is_sap_freq_allowed(psoc, + wlan_vdev_mlme_get_opmode(sap_ctx->vdev), + freq)) { + sap_debug("remove freq %d from acs list", freq); + continue; + } + /* Add only allowed channels to the acs cfg ch list */ + sap_ctx->acs_cfg->freq_list[num_safe_ch++] = + sap_ctx->acs_cfg->freq_list[i]; + } + + sap_debug("Updated ACS ch list len %d", num_safe_ch); + sap_ctx->acs_cfg->ch_list_count = num_safe_ch; +} + +static void +wlan_sap_filter_non_preferred_channels(struct wlan_objmgr_pdev *pdev, + struct sap_context *sap_ctx) +{ + uint16_t i; + uint16_t num_ch = 0; + bool preferred_freq_found = false; + + for (i = 0; i < sap_ctx->acs_cfg->ch_list_count; i++) { + if (sap_ctx->acs_cfg->freq_list[i] == 2467 || + sap_ctx->acs_cfg->freq_list[i] == 2472 || + sap_ctx->acs_cfg->freq_list[i] == 2477) { + sap_debug("Skip freq %d if preferred freq present", + sap_ctx->acs_cfg->freq_list[i]); + continue; + } + sap_ctx->acs_cfg->freq_list[num_ch++] = + sap_ctx->acs_cfg->freq_list[i]; + preferred_freq_found = true; + } + + if (!preferred_freq_found) { + sap_debug("No preferred freq, list unchanged"); + return; + } + sap_debug("preferred frequencies found updated ACS ch list len %d", + num_ch); + sap_ctx->acs_cfg->ch_list_count = num_ch; +} + +QDF_STATUS wlansap_pre_start_bss_acs_scan_callback(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint8_t sessionid, + uint32_t scanid, + eCsrScanStatus scan_status) +{ + uint32_t oper_channel = SAP_CHANNEL_NOT_SELECTED; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + host_log_acs_scan_done(acs_scan_done_status_str(scan_status), + sessionid, scanid); + + if (sap_ctx->optimize_acs_chan_selected) { + sap_debug("SAP channel selected using first clean channel, ignore scan complete event"); + return QDF_STATUS_SUCCESS; + } + + /* This has to be done before the ACS selects default channel */ + wlansap_filter_unsafe_ch(mac_ctx->psoc, sap_ctx); + + wlan_sap_filter_non_preferred_channels(mac_ctx->pdev, sap_ctx); + if (!sap_ctx->acs_cfg->ch_list_count) { + oper_channel = + sap_select_default_oper_chan(mac_ctx, + sap_ctx->acs_cfg); + sap_ctx->chan_freq = oper_channel; + sap_ctx->acs_cfg->pri_ch_freq = oper_channel; + sap_config_acs_result(mac_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch_freq); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; + goto close_session; + } + if (eCSR_SCAN_SUCCESS != scan_status) { + sap_err("CSR scan_status = eCSR_SCAN_ABORT/FAILURE (%d), choose default channel", + scan_status); + oper_channel = + sap_select_default_oper_chan(mac_ctx, + sap_ctx->acs_cfg); + wlansap_set_acs_ch_freq(sap_ctx, oper_channel); + sap_ctx->acs_cfg->pri_ch_freq = oper_channel; + sap_config_acs_result(mac_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch_freq); + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; + goto close_session; + } + sap_debug("CSR scan_status = eCSR_SCAN_SUCCESS (%d)", scan_status); + + oper_channel = wlansap_calculate_chan_from_scan_result(mac_handle, + sap_ctx, scanid); + + if (oper_channel == SAP_CHANNEL_NOT_SELECTED) { + sap_info("No suitable channel, so select default channel"); + oper_channel = sap_select_default_oper_chan(mac_ctx, + sap_ctx->acs_cfg); + } + + wlansap_set_acs_ch_freq(sap_ctx, oper_channel); + sap_ctx->acs_cfg->pri_ch_freq = oper_channel; + sap_config_acs_result(mac_handle, sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch_freq); + + wlansap_dump_acs_ch_freq(sap_ctx); + + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; +close_session: +#ifdef SOFTAP_CHANNEL_RANGE + if (sap_ctx->freq_list) { + /* + * Always free up the memory for + * channel selection whatever + * the result + */ + qdf_mem_free(sap_ctx->freq_list); + sap_ctx->freq_list = NULL; + sap_ctx->num_of_channel = 0; + } +#endif + sap_hdd_signal_event_handler(sap_ctx); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_roam_process_ch_change_success() - handles the case for + * eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS in function wlansap_roam_callback() + * + * @mac_ctx: mac global context + * @sap_ctx: sap context + * @csr_roam_info: raom info struct + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_ch_change_success(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct csr_roam_info *csr_roam_info, + QDF_STATUS *ret_status) +{ + struct sap_sm_event sap_event; + QDF_STATUS qdf_status; + bool is_ch_dfs = false; + uint32_t target_chan_freq; + eSapDfsCACState_t cac_state = eSAP_DFS_DO_NOT_SKIP_CAC; + + /* + * Channel change is successful. If the new channel is a DFS channel, + * then we will to perform channel availability check for 60 seconds + */ + sap_nofl_debug("sap_fsm: vdev %d: sapdfs: SAP CSA: freq %d state %d evt freq %d", + sap_ctx->vdev_id, + mac_ctx->sap.SapDfsInfo.target_chan_freq, + sap_ctx->fsm_state, + csr_roam_info->channelChangeRespEvent->new_op_freq); + target_chan_freq = mac_ctx->sap.SapDfsInfo.target_chan_freq; + /* If SAP is not in starting or started state don't proceed further */ + if (sap_ctx->fsm_state == SAP_INIT || + sap_ctx->fsm_state == SAP_STOPPING) { + sap_info("sap_fsm: vdev %d: sapdfs: state %d, not starting SAP after channel change", + sap_ctx->vdev_id, sap_ctx->fsm_state); + return; + } + + if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) { + struct ch_params ch_params = {0}; + + wlan_reg_set_create_punc_bitmap(&ch_params, true); + ch_params.ch_width = sap_ctx->ch_params.ch_width; + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac_ctx->pdev, + target_chan_freq, + &ch_params, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + target_chan_freq, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + sap_ctx->ch_params.mhz_freq_seg1, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, target_chan_freq)) + is_ch_dfs = true; + } + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ctx->chan_freq)) + is_ch_dfs = false; + + sap_ctx->fsm_state = SAP_STARTING; + sap_debug("sap_fsm: vdev %d: => SAP_STARTING", sap_ctx->vdev_id); + sap_ctx->chan_freq = target_chan_freq; + /* check if currently selected channel is a DFS channel */ + if (is_ch_dfs && wlan_pre_cac_complete_get(sap_ctx->vdev)) { + sap_ctx->sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } else if (is_ch_dfs) { + if (sap_plus_sap_cac_skip(mac_ctx, sap_ctx, + sap_ctx->chan_freq)) + cac_state = eSAP_DFS_SKIP_CAC; + if ((false == mac_ctx->sap.SapDfsInfo.ignore_cac) && + (cac_state == eSAP_DFS_DO_NOT_SKIP_CAC) && + policy_mgr_get_dfs_master_dynamic_enabled( + mac_ctx->psoc, + sap_ctx->sessionId)) { + /* DFS Channel */ + sap_event.event = eSAP_DFS_CHANNEL_CAC_START; + sap_event.params = csr_roam_info; + sap_event.u1 = 0; + sap_event.u2 = 0; + } else { + sap_ctx->sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } + } else { + /* non-DFS channel */ + sap_ctx->sap_radar_found_status = false; + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_event.u1 = eCSR_ROAM_INFRA_IND; + sap_event.u2 = eCSR_ROAM_RESULT_INFRA_STARTED; + } + + /* Handle the event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_roam_process_dfs_chansw_update() - handles the case for + * eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS in wlansap_roam_callback() + * + * @mac_handle: opaque handle to the global MAC context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: void + */ +static void +wlansap_roam_process_dfs_chansw_update(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + QDF_STATUS *ret_status) +{ + uint8_t intf; + QDF_STATUS qdf_status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t dfs_beacon_start_req = 0; + bool sap_scc_dfs; + + if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch) { + sap_err("sapdfs: DFS channel switch disabled"); + /* + * Send a beacon start request to PE. CSA IE required flag from + * beacon template will be cleared by now. A new beacon template + * with no CSA IE will be sent to firmware. + */ + dfs_beacon_start_req = true; + wlan_pre_cac_complete_set(sap_ctx->vdev, false); + *ret_status = sme_roam_start_beacon_req(mac_handle, + sap_ctx->bssid, + dfs_beacon_start_req); + return; + } + /* + * Irrespective of whether the channel switch IE was sent out + * successfully or not, SAP should still vacate the channel immediately + */ + if (sap_ctx->fsm_state != SAP_STARTED) { + /* Further actions to be taken here */ + sap_warn("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state", + sap_ctx->fsm_state); + return; + } + sap_ctx->is_chan_change_inprogress = true; + /* + * The associated stations have been informed to move to a different + * channel. However, the AP may not always select the advertised channel + * for operation if the radar is seen. In that case, the stations will + * experience link-loss and return back through scanning if they wish to + */ + + /* + * Send channel change request. From spec it is required that the AP + * should continue to operate in the same mode as it is operating + * currently. For e.g. 20/40/80 MHz operation + */ + if (mac_ctx->sap.SapDfsInfo.target_chan_freq) { + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(&sap_ctx->ch_params, + true); + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + mac_ctx->sap.SapDfsInfo.target_chan_freq, + 0, &sap_ctx->ch_params, REG_CURRENT_PWR_MODE); + } + + /* + * Fetch the number of SAP interfaces. If the number of sap Interface + * more than one then we will make is_sap_ready_for_chnl_chng to true + * for that sapctx. If there is only one SAP interface then process + * immediately. If Dual BAND SAP OR SBS in different mac, is enabled + * then also process immediately, as in this case the both SAP will be + * in different band and channel change on one SAP doesn't mean channel + * change on other interface. + * + * For example, + * Let's say SAP(2G) + SAP(5G-DFS) is initial connection which triggered + * DualBand HW mode and if SAP(5G-DFS) is moving to some channel then + * SAP(2G) doesn't need to move. + * + * If both SAPs are not doing SCC DFS then each of them can change the + * channel independently. Channel change of one SAP became dependent + * second SAP's channel change due to some previous platform's single + * radio limitation. + * + * For DCS case, SAP will do channel switch one by one. + * + */ + sap_scc_dfs = sap_is_conc_sap_doing_scc_dfs(mac_handle, sap_ctx); + if (sap_get_total_number_sap_intf(mac_handle) <= 1 || + policy_mgr_is_current_hwmode_dbs(mac_ctx->psoc) || + policy_mgr_is_current_hwmode_sbs(mac_ctx->psoc) || + sap_ctx->csa_reason == CSA_REASON_DCS || + !sap_scc_dfs) { + /* + * Most likely, radar has been detected and SAP wants to + * change the channel + */ + qdf_status = wlansap_channel_change_request(sap_ctx, + mac_ctx->sap.SapDfsInfo.target_chan_freq); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; + return; + } + + sap_ctx->is_sap_ready_for_chnl_chng = true; + /* + * now check if the con-current sap interface is ready + * for channel change. If yes then we issue channel change for + * both the SAPs. If no then simply return success & we will + * issue channel change when second AP's 5 CSA beacon Tx is + * completed. + * + * This check is added to take care of following scenario: + * if SAP1 + SAP2 is doing DFS SCC and radar is detected on that channel + * then SAP1 sends 5 beacons with CSA/ECSA IE and wait for SAP2 to + * finish sending 5 beacons. if SAP1 changes channel before SAP2 finish + * sending beacons then it ends up in + * (SAP1 new channel + SAP2 old channel) MCC with DFS scenario + * which causes some of the stability issues in old platforms. + */ + if (false == + is_concurrent_sap_ready_for_channel_change(mac_handle, sap_ctx)) { + sap_debug("sapdfs: sapctx[%pK] ready but not concurrent sap", + sap_ctx); + *ret_status = QDF_STATUS_SUCCESS; + return; + } + + /* Issue channel change req for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context; + + if (!((QDF_SAP_MODE == mac_ctx->sap.sapCtxList[intf].sapPersona || + QDF_P2P_GO_MODE == mac_ctx->sap.sapCtxList[intf].sapPersona) + && (mac_ctx->sap.sapCtxList[intf].sap_context))) + continue; + sap_context = mac_ctx->sap.sapCtxList[intf].sap_context; + sap_debug("sapdfs:issue chnl change for sapctx[%pK]", + sap_context); + /* + * Most likely, radar has been detected and SAP wants to + * change the channel + */ + qdf_status = wlansap_channel_change_request(sap_context, + mac_ctx->sap.SapDfsInfo.target_chan_freq); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sap_err("post chnl chng req failed, sap[%pK]", sap_ctx); + *ret_status = QDF_STATUS_E_FAILURE; + } else { + sap_context->is_sap_ready_for_chnl_chng = false; + } + } + return; +} + +/** + * wlansap_roam_process_dfs_radar_found() - handles the case for + * eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND in wlansap_roam_callback() + * + * @mac_ctx: mac global context + * @sap_ctx: sap context + * @ret_status: update return status + * + * Return: result of operation + */ +static void +wlansap_roam_process_dfs_radar_found(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + QDF_STATUS *ret_status) +{ + QDF_STATUS qdf_status; + struct sap_sm_event sap_event; + + if (sap_is_dfs_cac_wait_state(sap_ctx)) { + if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch) { + sap_err("sapdfs: DFS channel switch disabled"); + return; + } + if (!sap_ctx->sap_radar_found_status) { + sap_err("sapdfs: sap_radar_found_status is false"); + return; + } + + sap_debug("sapdfs:Posting event eSAP_DFS_CHANNEL_CAC_RADAR_FOUND"); + /* + * If Radar is found, while in DFS CAC WAIT State then post stop + * and destroy the CAC timer and post a + * eSAP_DFS_CHANNEL_CAC_RADAR_FOUND to sapFsm. + */ + if (!sap_ctx->dfs_cac_offload) { + qdf_mc_timer_stop(&mac_ctx-> + sap.SapDfsInfo.sap_dfs_cac_timer); + qdf_mc_timer_destroy(&mac_ctx-> + sap.SapDfsInfo.sap_dfs_cac_timer); + } + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + mac_ctx->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + + /* + * User space is already indicated the CAC start and if + * CAC end on this channel is not indicated, the user + * space will be in some undefined state (e.g., UI frozen) + */ + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_CAC_INTERRUPTED, + (void *) eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + sap_err("Failed to send CAC end"); + /* Want to still proceed and try to switch channel. + * Lets try not to be on the DFS channel + */ + } + + sap_event.event = eSAP_DFS_CHANNEL_CAC_RADAR_FOUND; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; + return; + } + if (sap_ctx->fsm_state == SAP_STARTED) { + sap_debug("sapdfs:Posting event eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START"); + + /* + * Radar found on the operating channel in STARTED state, + * new operating channel has already been selected. Send + * request to SME-->PE for sending CSA IE + */ + sap_event.event = eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + *ret_status = QDF_STATUS_E_FAILURE; + return; + } + /* Further actions to be taken here */ + sap_err("eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND received in (%d) state", + sap_ctx->fsm_state); + + return; +} + +/** + * wlansap_roam_process_infra_assoc_ind() - handles the case for + * eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND in wlansap_roam_callback() + * + * @sap_ctx: sap context + * @roam_result: roam result + * @csr_roam_info: roam info struct + * @ret_status: update return status + * + * Return: result of operation + */ +static void +wlansap_roam_process_infra_assoc_ind(struct sap_context *sap_ctx, + eCsrRoamResult roam_result, + struct csr_roam_info *csr_roam_info, + QDF_STATUS *ret_status) +{ + QDF_STATUS qdf_status; + + sap_debug("CSR roam_result = eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND (%d)", + roam_result); + sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen; + if (sap_ctx->nStaWPARSnReqIeLength) + qdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, csr_roam_info->prsnIE, + sap_ctx->nStaWPARSnReqIeLength); + /* MAC filtering */ + qdf_status = sap_is_peer_mac_allowed(sap_ctx, + (uint8_t *) csr_roam_info->peerMac.bytes); + + if (QDF_STATUS_SUCCESS == qdf_status) { + qdf_status = sap_signal_hdd_event(sap_ctx, + csr_roam_info, eSAP_STA_ASSOC_IND, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sap_err("CSR roam_result = (%d) MAC ("QDF_MAC_ADDR_FMT") fail", + roam_result, QDF_MAC_ADDR_REF( + csr_roam_info->peerMac.bytes)); + *ret_status = QDF_STATUS_E_FAILURE; + } + } else { + sap_warn("CSR roam_result = (%d) MAC ("QDF_MAC_ADDR_FMT") not allowed", + roam_result, + QDF_MAC_ADDR_REF(csr_roam_info->peerMac.bytes)); + *ret_status = QDF_STATUS_E_FAILURE; + } + return; +} + +static void wlansap_update_vendor_acs_chan(struct mac_context *mac_ctx, + struct sap_context *sap_ctx) +{ + int intf; + + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return; + } + + mac_ctx->sap.SapDfsInfo.target_chan_freq = + wlan_reg_legacy_chan_to_freq( + mac_ctx->pdev, + sap_ctx->dfs_vendor_channel); + + mac_ctx->sap.SapDfsInfo.new_chanWidth = + sap_ctx->dfs_vendor_chan_bw; + mac_ctx->sap.SapDfsInfo.new_ch_params.ch_width = + sap_ctx->dfs_vendor_chan_bw; + + if (mac_ctx->sap.SapDfsInfo.target_chan_freq != 0) { + sap_cac_reset_notify(MAC_HANDLE(mac_ctx)); + return; + } + /* App failed to provide new channel, try random channel algo */ + sap_warn("Failed to get channel from userspace"); + + /* Issue stopbss for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context; + + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].sap_context != + NULL) { + sap_context = + mac_ctx->sap.sapCtxList[intf].sap_context; + sap_err("sapdfs: no available channel for sapctx[%pK], StopBss", + sap_context); + wlansap_stop_bss(sap_context); + } + } +} + +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * sap_check_and_process_forcescc_for_go_plus_go() - find if other p2p + * go is there and needs to be moved to current p2p go's channel. + * + * @cur_sap_ctx: current sap context + * + * Return: None + */ +static void +sap_check_and_process_forcescc_for_go_plus_go( + struct sap_context *cur_sap_ctx) +{ + struct sap_context *sap_ctx; + struct mac_context *mac_ctx; + uint8_t i; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + sap_ctx = mac_ctx->sap.sapCtxList[i].sap_context; + if (sap_ctx && + QDF_P2P_GO_MODE == mac_ctx->sap.sapCtxList[i].sapPersona && + sap_ctx->is_forcescc_restart_required && + cur_sap_ctx->sessionId != sap_ctx->sessionId) { + sap_debug("update chan_freq %d of sessionId %d with chan_freq %d", + sap_ctx->chan_freq, sap_ctx->sessionId, + cur_sap_ctx->chan_freq); + policy_mgr_process_forcescc_for_go( + mac_ctx->psoc, sap_ctx->sessionId, + cur_sap_ctx->chan_freq, + cur_sap_ctx->ch_params.ch_width, + PM_P2P_GO_MODE); + sap_ctx->is_forcescc_restart_required = false; + break; + } + } +} + +/** + * sap_check_and_process_go_force_scc() - find if other p2p go/cli/sta + * is there and needs force scc. + * @sap_ctx: current sap context + * + * Return: None + */ +static void +sap_check_and_process_go_force_scc(struct sap_context *sap_ctx) +{ + struct mac_context *mac_ctx; + uint32_t con_freq; + enum phy_ch_width ch_width; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return; + } + if (sap_ctx->vdev->vdev_mlme.vdev_opmode == + QDF_P2P_GO_MODE && + wlan_vdev_get_peer_count(sap_ctx->vdev) == 2 && + policy_mgr_mode_specific_connection_count( + mac_ctx->psoc, PM_P2P_GO_MODE, NULL) > 1) { + sap_check_and_process_forcescc_for_go_plus_go(sap_ctx); + return; + } + policy_mgr_fetch_existing_con_info(mac_ctx->psoc, sap_ctx->sessionId, + sap_ctx->chan_freq, + &existing_vdev_mode, + &con_freq, &ch_width); + + if (sap_ctx->vdev->vdev_mlme.vdev_opmode == QDF_P2P_GO_MODE && + policy_mgr_go_scc_enforced(mac_ctx->psoc) && + !policy_mgr_is_go_scc_strict(mac_ctx->psoc) && + wlan_vdev_get_peer_count(sap_ctx->vdev) == 2 && + (existing_vdev_mode == PM_P2P_CLIENT_MODE || + existing_vdev_mode == PM_STA_MODE)){ + policy_mgr_process_forcescc_for_go(mac_ctx->psoc, + sap_ctx->sessionId, + con_freq, ch_width, + existing_vdev_mode); + } +} +#else +static inline void +sap_check_and_process_forcescc_for_go_plus_go( + struct sap_context *cur_sap_ctx) +{} +static inline void +sap_check_and_process_go_force_scc(struct sap_context *sap_ctx) +{} +#endif + +/** + * sap_is_csa_restart_state() - check if sap is in csa restart state + * @psoc: PSOC object + * @sap_ctx: sap context to check + * + * Return: true if sap is in csa restart state + */ +static bool sap_is_csa_restart_state(struct wlan_objmgr_psoc *psoc, + struct sap_context *sap_ctx) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + if (!psoc || !sap_ctx) { + sap_err("Invalid params"); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + sap_ctx->sessionId, + WLAN_DFS_ID); + if (!vdev) { + sap_err("vdev is NULL for vdev_id: %u", sap_ctx->sessionId); + return false; + } + + status = wlan_vdev_mlme_is_csa_restart(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID); + + return QDF_IS_STATUS_SUCCESS(status); +} + +#ifdef PRE_CAC_SUPPORT +static void wlan_sap_pre_cac_radar_ind(struct sap_context *sap_ctx, + struct mac_context *mac_ctx) +{ + qdf_mc_timer_t *dfs_timer = &mac_ctx->sap.SapDfsInfo.sap_dfs_cac_timer; + + sap_debug("sapdfs: Radar detect on pre cac:%d", sap_ctx->sessionId); + if (!sap_ctx->dfs_cac_offload) { + qdf_mc_timer_stop(dfs_timer); + qdf_mc_timer_destroy(dfs_timer); + } + mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + mac_ctx->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + + wlan_pre_cac_handle_radar_ind(sap_ctx->vdev); +} +#else +static inline void +wlan_sap_pre_cac_radar_ind(struct sap_context *sap_ctx, + struct mac_context *mac_ctx) +{ +} +#endif + +QDF_STATUS wlansap_roam_callback(void *ctx, + struct csr_roam_info *csr_roam_info, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result) +{ + /* sap_ctx value */ + struct sap_context *sap_ctx = ctx; + /* State machine event */ + struct sap_sm_event sap_event; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + uint8_t intf; + + if (QDF_IS_STATUS_ERROR(wlansap_context_get(sap_ctx))) + return QDF_STATUS_E_FAILURE; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + wlansap_context_put(sap_ctx); + return QDF_STATUS_E_NOMEM; + } + sap_debug("CSR roam_status = %s(%d), roam_result = %s(%d)", + get_e_roam_cmd_status_str(roam_status), roam_status, + get_e_csr_roam_result_str(roam_result), roam_result); + + mac_handle = MAC_HANDLE(mac_ctx); + + switch (roam_status) { + case eCSR_ROAM_INFRA_IND: + if (roam_result == eCSR_ROAM_RESULT_INFRA_START_FAILED) { + /* Fill in the event structure */ + sap_event.event = eSAP_MAC_START_FAILS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_LOSTLINK: + break; + case eCSR_ROAM_MIC_ERROR_IND: + break; + case eCSR_ROAM_SET_KEY_COMPLETE: + if (roam_result == eCSR_ROAM_RESULT_FAILURE) + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_WPS_PBC_PROBE_REQ_IND: + break; + case eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS: + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_DISCONNECT_ALL_P2P_CLIENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_SEND_P2P_STOP_BSS: + sap_debug("Received stopbss"); + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_MAC_TRIG_STOP_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_CHANNEL_COMPLETE_IND: + sap_debug("Received new channel from app"); + wlansap_update_vendor_acs_chan(mac_ctx, sap_ctx); + break; + + case eCSR_ROAM_DFS_RADAR_IND: + sap_debug("Rcvd Radar Indication on sap ch freq %d, session %d", + sap_ctx->chan_freq, sap_ctx->sessionId); + + if (!policy_mgr_get_dfs_master_dynamic_enabled( + mac_ctx->psoc, sap_ctx->sessionId)) { + sap_debug("Ignore the Radar indication"); + goto EXIT; + } + + if (sap_ctx->fsm_state != SAP_STARTED && + !sap_is_dfs_cac_wait_state(sap_ctx)) { + sap_debug("Ignore Radar event in sap state %d cac wait state %d", + sap_ctx->fsm_state, + sap_is_dfs_cac_wait_state(sap_ctx)); + goto EXIT; + } + + if (sap_ctx->fsm_state == SAP_STARTED && + sap_is_csa_restart_state(mac_ctx->psoc, sap_ctx)) { + sap_debug("Ignore Radar event in csa restart state"); + goto EXIT; + } + + if (!sap_chan_bond_dfs_sub_chan( + sap_ctx, sap_ctx->chan_freq, + PHY_CHANNEL_BONDING_STATE_MAX)) { + sap_debug("Ignore Radar event for sap ch freq: %d", + sap_ctx->chan_freq); + goto EXIT; + } + + if (wlan_pre_cac_get_status(mac_ctx->psoc)) { + wlan_sap_pre_cac_radar_ind(sap_ctx, mac_ctx); + break; + } + + sap_debug("sapdfs: Indicate eSAP_DFS_RADAR_DETECT to HDD"); + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_RADAR_DETECT, + (void *) eSAP_STATUS_SUCCESS); + mac_ctx->sap.SapDfsInfo.target_chan_freq = + sap_indicate_radar(sap_ctx); + + /* if there is an assigned next channel hopping */ + if (0 < mac_ctx->sap.SapDfsInfo.user_provided_target_chan_freq) { + mac_ctx->sap.SapDfsInfo.target_chan_freq = + mac_ctx->sap.SapDfsInfo.user_provided_target_chan_freq; + mac_ctx->sap.SapDfsInfo.user_provided_target_chan_freq = + 0; + } + /* if external acs enabled */ + if (sap_ctx->vendor_acs_dfs_lte_enabled && + !mac_ctx->sap.SapDfsInfo.target_chan_freq) { + /* Return from here, processing will be done later */ + goto EXIT; + } + if (mac_ctx->sap.SapDfsInfo.target_chan_freq != 0) { + sap_cac_reset_notify(mac_handle); + break; + } + /* Issue stopbss for each sapctx */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context; + + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].sap_context != + NULL) { + sap_context = + mac_ctx->sap.sapCtxList[intf].sap_context; + if (!wlan_reg_is_passive_or_disable_for_pwrmode( + mac_ctx->pdev, + sap_context->chan_freq, + REG_CURRENT_PWR_MODE)) + continue; + sap_debug("Vdev %d no channel available , stop bss", + sap_context->sessionId); + sap_signal_hdd_event(sap_context, NULL, + eSAP_STOP_BSS_DUE_TO_NO_CHNL, + (void *) eSAP_STATUS_SUCCESS); + } + } + break; + case eCSR_ROAM_DFS_CHAN_SW_NOTIFY: + sap_debug("Received Chan Sw Update Notification"); + break; + case eCSR_ROAM_SET_CHANNEL_RSP: + sap_debug("Received set channel response"); + ucfg_if_mgr_deliver_event(sap_ctx->vdev, + WLAN_IF_MGR_EV_AP_CSA_COMPLETE, + NULL); + break; + case eCSR_ROAM_CAC_COMPLETE_IND: + sap_debug("Received cac complete indication"); + break; + case eCSR_ROAM_EXT_CHG_CHNL_IND: + sap_debug("Received set channel Indication"); + break; + case eCSR_ROAM_CHANNEL_INFO_EVENT_IND: + wlansap_process_chan_info_event(sap_ctx, csr_roam_info); + break; + default: + break; + } + + switch (roam_result) { + case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND: + if (csr_roam_info) + wlansap_roam_process_infra_assoc_ind(sap_ctx, + roam_result, + csr_roam_info, &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF: + if (!csr_roam_info) { + sap_err("csr_roam_info is NULL"); + qdf_ret_status = QDF_STATUS_E_NULL_VALUE; + break; + } + sap_ctx->nStaWPARSnReqIeLength = csr_roam_info->rsnIELen; + if (sap_ctx->nStaWPARSnReqIeLength) + qdf_mem_copy(sap_ctx->pStaWpaRsnReqIE, + csr_roam_info->prsnIE, + sap_ctx->nStaWPARSnReqIeLength); + + /* Fill in the event structure */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_ASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_DEAUTH_IND: + case eCSR_ROAM_RESULT_DISASSOC_IND: + /* Fill in the event structure */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_MIC_ERROR_GROUP: + /* + * Fill in the event structure + * TODO: support for group key MIC failure event to be handled + */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_MIC_ERROR_UNICAST: + /* + * Fill in the event structure + * TODO: support for unicast key MIC failure event to be handled + */ + qdf_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_MIC_FAILURE_EVENT, + (void *) NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case eCSR_ROAM_RESULT_AUTHENTICATED: + /* Fill in the event structure */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_SUCCESS); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_INFRA_STARTED: + if (!csr_roam_info) { + sap_err("csr_roam_info is NULL"); + qdf_ret_status = QDF_STATUS_E_NULL_VALUE; + break; + } + /* + * In the current implementation, hostapd is not aware that + * drive will support DFS. Hence, driver should inform + * eSAP_MAC_START_BSS_SUCCESS to upper layers and then perform + * CAC underneath + */ + sap_event.event = eSAP_MAC_START_BSS_SUCCESS; + sap_event.params = csr_roam_info; + sap_ctx->sap_sta_id = csr_roam_info->staId; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_INFRA_STOPPED: + /* Fill in the event structure */ + sap_event.event = eSAP_MAC_READY_FOR_CONNECTIONS; + sap_event.params = csr_roam_info; + sap_event.u1 = roam_status; + sap_event.u2 = roam_result; + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND: + /* + * Fill in the event structure + * TODO: support for group key MIC failure event to be handled + */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_WPS_PBC_PROBE_REQ_EVENT, + (void *) NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + case eCSR_ROAM_RESULT_FORCED: + /* + * This event can be used to inform hdd about user triggered + * disassoc event + * Fill in the event structure + */ + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_DISASSOC_EVENT, + (void *) eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_NONE: + /* + * This event can be used to inform hdd about user triggered + * disassoc event + * Fill in the event structure + */ + if (roam_status == eCSR_ROAM_SET_KEY_COMPLETE) { + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_STA_SET_KEY_EVENT, + (void *) eSAP_STATUS_SUCCESS); + /* + * After set key if this is the first peer connecting to new GO + * then check for peer count (which is self peer + peer count) + * and take decision for GO+GO, STA+GO and CLI+GO force SCC + */ + sap_check_and_process_go_force_scc(sap_ctx); + } + break; + case eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED: + /* Fill in the event structure */ + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_MAX_ASSOC_EXCEEDED, + NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + + break; + case eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND: + if (!policy_mgr_get_dfs_master_dynamic_enabled( + mac_ctx->psoc, sap_ctx->sessionId)) + break; + wlansap_roam_process_dfs_radar_found(mac_ctx, sap_ctx, + &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_CSA_RESTART_RSP: + qdf_ret_status = wlansap_dfs_send_csa_ie_request(sap_ctx); + + if (!QDF_IS_STATUS_SUCCESS(qdf_ret_status)) + sap_debug("CSR roam_result = eCSR_ROAM_RESULT_CSA_RESTART_RSP %d", + roam_result); + break; + case eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS: + wlansap_roam_process_dfs_chansw_update(mac_handle, sap_ctx, + &qdf_ret_status); + break; + case eCSR_ROAM_RESULT_CAC_END_IND: + sap_dfs_cac_timer_callback(mac_handle); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS: + wlansap_roam_process_ch_change_success(mac_ctx, sap_ctx, + csr_roam_info, &qdf_ret_status); + + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) + qdf_ret_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_CHANNEL_CHANGE_RESP, + (void *)eSAP_STATUS_FAILURE); + else + qdf_ret_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_CHANNEL_CHANGE_RESP, + (void *)eSAP_STATUS_SUCCESS); + break; + case eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE: + qdf_ret_status = + sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_CHANNEL_CHANGE_RESP, + (void *)eSAP_STATUS_FAILURE); + break; + case eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND: + qdf_status = sap_signal_hdd_event(sap_ctx, csr_roam_info, + eSAP_ECSA_CHANGE_CHAN_IND, NULL); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_ret_status = QDF_STATUS_E_FAILURE; + break; + default: + sap_err("CSR roam_result = %s (%d) not handled", + get_e_csr_roam_result_str(roam_result), + roam_result); + break; + } +EXIT: + wlansap_context_put(sap_ctx); + return qdf_ret_status; +} + +void sap_scan_event_callback(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + uint32_t scan_id; + uint8_t session_id; + bool success = false; + eCsrScanStatus scan_status = eCSR_SCAN_FAILURE; + mac_handle_t mac_handle; + QDF_STATUS status; + + /* + * It may happen that the SAP was deleted before the scan + * cb was called. Here the sap context which was passed as an + * arg to the ACS cb is used after free then, and there is no way + * currently to validate the pointer. Now try get vdev ref before + * the weight calculation algo kicks in, and return if the + * reference cannot be taken to avoid use after free for SAP-context + */ + status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_LEGACY_SAP_ID); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Hotspot fail, vdev ref get error"); + return; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SAP_ID); + + session_id = wlan_vdev_get_id(vdev); + scan_id = event->scan_id; + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + return; + + qdf_mtrace(QDF_MODULE_ID_SCAN, QDF_MODULE_ID_SAP, event->type, + event->vdev_id, event->scan_id); + + if (!util_is_scan_completed(event, &success)) + return; + + if (success) + scan_status = eCSR_SCAN_SUCCESS; + + wlansap_pre_start_bss_acs_scan_callback(mac_handle, + arg, session_id, + scan_id, scan_status); +} + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +#define WLAN_INVALID_PDEV_ID 0xFFFFFFFF +/** + * sap_mark_freq_as_clean(): This API marks a channel is clean which means + * we didn't see any AP's on this channel + * @clean_channel_array: array of chan enum containing that chan free or not + * @freq: freq for which flag needs to be updated + * + * Return: void + */ +static +void sap_mark_freq_as_clean(bool *clean_channel_array, + qdf_freq_t freq) +{ + uint32_t ch_index; + ch_index = wlan_reg_get_chan_enum_for_freq(freq); + if (ch_index >= INVALID_CHANNEL) + return; + clean_channel_array[ch_index] = true; +} + +/** + * sap_is_prev_n_freqs_free(): previous frequencies free or not based on channel + * width + * @clean_channel_array: array of chan enum containing that chan free or not + * @curr_index: Chan enum of current scanned channel + * @prev_n_freq_count: no. of freq to be monitored based on BW + * @range: Bonded channel freq range + * + *Return: true if previous channels free else false + */ +static +bool sap_is_prev_n_freqs_free(bool *clean_channel_array, uint32_t curr_index, + uint32_t prev_n_freq_count, + const struct bonded_channel_freq *range) +{ + uint32_t index; + uint32_t min_index = wlan_reg_get_chan_enum_for_freq(range->start_freq); + uint32_t max_index = wlan_reg_get_chan_enum_for_freq(range->end_freq); + if (max_index >= INVALID_CHANNEL || + min_index >= INVALID_CHANNEL) + return false; + if (curr_index > max_index || curr_index < min_index) { + sap_debug("invalid chan index %d", curr_index); + return false; + } + /* + * curr_index will be present in range, so bonded freq + * range can be checked to decide curr_index is best + * available channel or not. + */ + for (index = min_index; index > 0 && index <= max_index; + index++) { + if (!clean_channel_array[index]) { + sap_debug("chan_index %d not free", index); + return false; + } + } + if ((index - min_index) < prev_n_freq_count) { + sap_debug("previous %d are not validated", prev_n_freq_count); + return false; + } + + return true; +} + +/** + * is_freq_allowed_for_sap(): is frequency allowed to start SAP + * @pdev: object manager pdev + * @clean_channel_array: array of chan enum containing that chan free or not + * @freq: Scanned frequency + * @ch_width: phy channel width + * @vdev: object manager vdev + * + * Return: true if frequency is allowed based on BW else false. + */ +static +bool is_freq_allowed_for_sap(struct wlan_objmgr_pdev *pdev, + bool *clean_channel_array, + qdf_freq_t freq, enum phy_ch_width ch_width, + struct wlan_objmgr_vdev *vdev) { + uint16_t min_bw = 0; + uint16_t max_bw = 0; + uint16_t curr_bw; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status; + const struct bonded_channel_freq *range = NULL; + uint32_t curr_index = wlan_reg_get_chan_enum_for_freq(freq); + if (curr_index >= INVALID_CHANNEL) + return false; + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + sap_err("invalid psoc"); + return false; + } + if (wlan_mlme_get_ap_policy(vdev) == + HOST_CONCURRENT_AP_POLICY_UNSPECIFIED) { + sap_debug("low latency sap is not present"); + return false; + } + /* + * Don't allow frequency that can be shared with 2 GHz frequency + * on same MAC. + */ + if (policy_mgr_2_freq_always_on_same_mac + (psoc, wlan_reg_min_24ghz_chan_freq(), freq)) { + sap_debug("frequency can be shared by 2G MAC"); + return false; + } + + status = + wlan_reg_get_min_max_bw_for_chan_index(pdev, curr_index, &min_bw, + &max_bw); + if (status != QDF_STATUS_SUCCESS) { + sap_err("get bw for curr channel failed"); + return false; + } + curr_bw = wlan_reg_get_bw_value(ch_width); + if (curr_bw < min_bw || curr_bw > max_bw) { + sap_debug("frequency doesn't support configured bw"); + return false; + } + range = wlan_reg_get_bonded_chan_entry(freq, ch_width, 0); + if (!range) { + sap_debug("Invalid freq range for freq: %d and ch_width: %d", + freq, ch_width); + return false; + } + sap_debug("freq range for bw %d is %d-%d", ch_width, range->start_freq, + range->end_freq); + + switch (ch_width) { + case CH_WIDTH_40MHZ: + return sap_is_prev_n_freqs_free(clean_channel_array, + curr_index, 40/20, + range); + case CH_WIDTH_80MHZ: + return sap_is_prev_n_freqs_free(clean_channel_array, + curr_index, 80/20, + range); + case CH_WIDTH_160MHZ: + return sap_is_prev_n_freqs_free(clean_channel_array, + curr_index, 160/20, + range); + case CH_WIDTH_320MHZ: + return sap_is_prev_n_freqs_free(clean_channel_array, + curr_index, 320/20, + range); + default: + return false; + } + return false; +} + +void wlansap_process_chan_info_event(struct sap_context *sap_ctx, + struct csr_roam_info *roam_info) +{ + struct mac_context *mac; + struct scan_filter *filter; + qdf_list_t *list = NULL; + enum channel_state state; + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return; + } + + if (!hdd_sap_is_acs_in_progress(sap_ctx->vdev)) + return; + + if (SAP_INIT != sap_ctx->fsm_state) + return; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(roam_info->chan_info_freq)) + return; + + state = wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, roam_info->chan_info_freq, + REG_CURRENT_PWR_MODE); + if (state != CHANNEL_STATE_ENABLE) + return; + + if (sap_ctx->optimize_acs_chan_selected) + return; + + if (!sap_ctx->acs_cfg) { + sap_debug("acs_cfg is null"); + return; + } + + /* If chan_info_freq is not preferred band's freq + * do not select it as ACS result. + */ + if (sap_ctx->acs_cfg->ch_list_count && + !wlan_reg_is_same_band_freqs( + sap_ctx->acs_cfg->freq_list[ + sap_ctx->acs_cfg->ch_list_count - 1], + roam_info->chan_info_freq)) + return; + /* Confirm the freq is in ACS list. */ + if (!wlansap_is_channel_present_in_acs_list( + roam_info->chan_info_freq, + sap_ctx->acs_cfg->freq_list, + sap_ctx->acs_cfg->ch_list_count)) + return; + /* For 6 GHz, do not select non PSC channel */ + if (wlan_reg_is_6ghz_chan_freq( + roam_info->chan_info_freq) && + !wlan_reg_is_6ghz_psc_chan_freq( + roam_info->chan_info_freq)) + return; + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return; + + filter->age_threshold = qdf_get_time_of_the_day_ms() - + sap_ctx->acs_req_timestamp; + filter->num_of_channels = 1; + filter->chan_freq_list[0] = roam_info->chan_info_freq; + + list = ucfg_scan_get_result(mac->pdev, filter); + qdf_mem_free(filter); + if (!list) + return; + + if (qdf_list_size(list)) + goto exit; + + if (!policy_mgr_is_sap_freq_allowed(mac->psoc, + wlan_vdev_mlme_get_opmode(sap_ctx->vdev), + roam_info->chan_info_freq)) + goto exit; + if (sap_ctx->acs_cfg->ch_width > CH_WIDTH_20MHZ) { + sap_mark_freq_as_clean(sap_ctx->clean_channel_array, + roam_info->chan_info_freq); + if (!is_freq_allowed_for_sap(mac->pdev, + sap_ctx->clean_channel_array, + roam_info->chan_info_freq, + sap_ctx->acs_cfg->ch_width, + sap_ctx->vdev)) { + goto exit; + } + } + + sap_debug("ACS Best channel %d as no beacon/probe rsp found\n", + roam_info->chan_info_freq); + + sap_ctx->optimize_acs_chan_selected = true; + + wlan_abort_scan(mac->pdev, WLAN_INVALID_PDEV_ID, + sap_ctx->sessionId, INVALID_SCAN_ID, false); + + wlansap_set_acs_ch_freq(sap_ctx, roam_info->chan_info_freq); + sap_ctx->acs_cfg->pri_ch_freq = roam_info->chan_info_freq; + sap_config_acs_result(MAC_HANDLE(mac), sap_ctx, + sap_ctx->acs_cfg->ht_sec_ch_freq); + + wlansap_dump_acs_ch_freq(sap_ctx); + + sap_ctx->sap_state = eSAP_ACS_CHANNEL_SELECTED; + sap_ctx->sap_status = eSAP_STATUS_SUCCESS; + + if (sap_ctx->freq_list) { + qdf_mem_free(sap_ctx->freq_list); + sap_ctx->freq_list = NULL; + sap_ctx->num_of_channel = 0; + } + + sap_hdd_signal_event_handler(sap_ctx); + +exit: + ucfg_scan_purge_results(list); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_ch_select.c b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_ch_select.c new file mode 100644 index 0000000000..db1b852e5e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_ch_select.c @@ -0,0 +1,3214 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=========================================================================== + + s a p C h S e l e c t . C + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + functions for channel selection. + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_trace.h" +#include "csr_api.h" +#include "sme_api.h" +#include "sap_ch_select.h" +#include "sap_internal.h" +#ifdef ANI_OS_TYPE_QNX +#include "stdio.h" +#endif +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +#include "lim_utils.h" +#include "parser_api.h" +#include +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ +#include "cds_utils.h" +#include "pld_common.h" +#include "wlan_reg_services_api.h" +#include +#include +#include + +/*-------------------------------------------------------------------------- + Function definitions + --------------------------------------------------------------------------*/ + +/*-------------------------------------------------------------------------- + Defines + --------------------------------------------------------------------------*/ +#define SAP_DEBUG + +#define IS_RSSI_VALID(extRssi, rssi) \ + ( \ + ((extRssi < rssi) ? true : false) \ + ) + +#define SET_ACS_BAND(acs_band, sap_ctx) \ +{ \ + if (sap_ctx->acs_cfg->start_ch_freq <= \ + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484) && \ + sap_ctx->acs_cfg->end_ch_freq <= \ + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484)) \ + acs_band = eCSR_DOT11_MODE_11g; \ + else if (sap_ctx->acs_cfg->start_ch_freq >= \ + WLAN_REG_CH_TO_FREQ(CHAN_ENUM_2484))\ + acs_band = eCSR_DOT11_MODE_11a; \ + else \ + acs_band = eCSR_DOT11_MODE_abg; \ +} + +#define ACS_WEIGHT_AMOUNT_LOCAL 240 + +#define ACS_WEIGHT_AMOUNT_CONFIG(weights) \ + (((weights) & 0xf) + \ + (((weights) & 0xf0) >> 4) + \ + (((weights) & 0xf00) >> 8) + \ + (((weights) & 0xf000) >> 12) + \ + (((weights) & 0xf0000) >> 16) + \ + (((weights) & 0xf00000) >> 20) + \ + (((weights) & 0xf000000) >> 24)) + +/* + * LSH/RSH 4 to enhance the accurate since + * need to do modulation to ACS_WEIGHT_AMOUNT_LOCAL. + */ +#define ACS_WEIGHT_COMPUTE(weights, weight, factor, base) \ + (((((((((weight) << 4) * ACS_WEIGHT_AMOUNT_LOCAL * (factor)) + \ + (ACS_WEIGHT_AMOUNT_CONFIG((weights)) >> 1)) / \ + ACS_WEIGHT_AMOUNT_CONFIG((weights))) + \ + ((base) >> 1)) / (base)) + 8) >> 4) + +#define ACS_WEIGHT_CFG_TO_LOCAL(weights, weight) \ + (((((((weight) << 4) * ACS_WEIGHT_AMOUNT_LOCAL) + \ + (ACS_WEIGHT_AMOUNT_CONFIG((weights)) >> 1)) / \ + ACS_WEIGHT_AMOUNT_CONFIG((weights))) + 8) >> 4) + +#define ACS_WEIGHT_SOFTAP_RSSI_CFG(weights) \ + ((weights) & 0xf) + +#define ACS_WEIGHT_SOFTAP_COUNT_CFG(weights) \ + (((weights) & 0xf0) >> 4) + +#define ACS_WEIGHT_SOFTAP_NOISE_FLOOR_CFG(weights) \ + (((weights) & 0xf00) >> 8) + +#define ACS_WEIGHT_SOFTAP_CHANNEL_FREE_CFG(weights) \ + (((weights) & 0xf000) >> 12) + +#define ACS_WEIGHT_SOFTAP_TX_POWER_RANGE_CFG(weights) \ + (((weights) & 0xf0000) >> 16) + +#define ACS_WEIGHT_SOFTAP_TX_POWER_THROUGHPUT_CFG(weights) \ + (((weights) & 0xf00000) >> 20) + +#define ACS_WEIGHT_SOFTAP_REG_MAX_POWER_CFG(weights) \ + (((weights) & 0xf000000) >> 24) + +typedef struct { + uint16_t chStartNum; + uint32_t weight; +} sapAcsChannelInfo; + +sapAcsChannelInfo acs_ht40_channels5_g[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {44, SAP_ACS_WEIGHT_MAX}, + {52, SAP_ACS_WEIGHT_MAX}, + {60, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, + {108, SAP_ACS_WEIGHT_MAX}, + {116, SAP_ACS_WEIGHT_MAX}, + {124, SAP_ACS_WEIGHT_MAX}, + {132, SAP_ACS_WEIGHT_MAX}, + {140, SAP_ACS_WEIGHT_MAX}, + {149, SAP_ACS_WEIGHT_MAX}, + {157, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_ht80_channels[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {52, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, + {116, SAP_ACS_WEIGHT_MAX}, + {132, SAP_ACS_WEIGHT_MAX}, + {149, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_vht160_channels[] = { + {36, SAP_ACS_WEIGHT_MAX}, + {100, SAP_ACS_WEIGHT_MAX}, +}; + +sapAcsChannelInfo acs_ht40_channels24_g[] = { + {1, SAP_ACS_WEIGHT_MAX}, + {2, SAP_ACS_WEIGHT_MAX}, + {3, SAP_ACS_WEIGHT_MAX}, + {4, SAP_ACS_WEIGHT_MAX}, + {9, SAP_ACS_WEIGHT_MAX}, +}; + +#define CHANNEL_165 165 + +/* rssi discount for channels in PCL */ +#define PCL_RSSI_DISCOUNT 10 + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * sap_check_n_add_channel() - checks and add given channel in sap context's + * avoid_channels_info struct + * @sap_ctx: sap context. + * @new_channel: channel to be added to sap_ctx's avoid ch info + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function will add channels + * to that list after checking for duplicates. + * + * Return: true: if channel was added or already present + * else false: if channel list was already full. + */ +static bool +sap_check_n_add_channel(struct sap_context *sap_ctx, + uint8_t new_channel) +{ + uint8_t i = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + + for (i = 0; i < sizeof(ie_info->channels); i++) { + if (ie_info->channels[i] == new_channel) + break; + + if (ie_info->channels[i] == 0) { + ie_info->channels[i] = new_channel; + break; + } + } + if (i == sizeof(ie_info->channels)) + return false; + else + return true; +} +/** + * sap_check_n_add_overlapped_chnls() - checks & add overlapped channels + * to primary channel in 2.4Ghz band. + * @sap_ctx: sap context. + * @primary_channel: primary channel to be avoided. + * + * sap_ctx contains sap_avoid_ch_info struct containing the list of channels on + * which MDM device's AP with MCC was detected. This function will add channels + * to that list after checking for duplicates. + * + * Return: true: if channel was added or already present + * else false: if channel list was already full. + */ +static bool +sap_check_n_add_overlapped_chnls(struct sap_context *sap_ctx, + uint8_t primary_channel) +{ + uint8_t i = 0, j = 0, upper_chnl = 0, lower_chnl = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + /* + * if primary channel less than channel 1 or out of 2g band then + * no further process is required. return true in this case. + */ + if (primary_channel < CHANNEL_1 || primary_channel > CHANNEL_14) + return true; + + /* lower channel is one channel right before primary channel */ + lower_chnl = primary_channel - 1; + /* upper channel is one channel right after primary channel */ + upper_chnl = primary_channel + 1; + + /* lower channel needs to be non-zero, zero is not valid channel */ + if (lower_chnl > (CHANNEL_1 - 1)) { + for (i = 0; i < sizeof(ie_info->channels); i++) { + if (ie_info->channels[i] == lower_chnl) + break; + if (ie_info->channels[i] == 0) { + ie_info->channels[i] = lower_chnl; + break; + } + } + } + /* upper channel needs to be atleast last channel in 2.4Ghz band */ + if (upper_chnl < (CHANNEL_14 + 1)) { + for (j = 0; j < sizeof(ie_info->channels); j++) { + if (ie_info->channels[j] == upper_chnl) + break; + if (ie_info->channels[j] == 0) { + ie_info->channels[j] = upper_chnl; + break; + } + } + } + if (i == sizeof(ie_info->channels) || j == sizeof(ie_info->channels)) + return false; + else + return true; +} + +/** + * sap_process_avoid_ie() - processes the detected Q2Q IE + * context's avoid_channels_info struct + * @mac_ctx: pointer to mac_context structure + * @sap_ctx: sap context. + * @scan_list: scan results for ACS scan. + * @spect_info: spectrum weights array to update + * + * Detection of Q2Q IE indicates presence of another MDM device with its AP + * operating in MCC mode. This function parses the scan results and processes + * the Q2Q IE if found. It then extracts the channels and populates them in + * sap_ctx struct. It also increases the weights of those channels so that + * ACS logic will avoid those channels in its selection algorithm. + * + * Return: void + */ +static void +sap_process_avoid_ie(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + qdf_list_t *scan_list, + struct sap_sel_ch_info *spect_info) +{ + const uint8_t *temp_ptr = NULL; + uint8_t i = 0; + struct sAvoidChannelIE *avoid_ch_ie; + struct sap_ch_info *spect_ch = NULL; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + struct scan_cache_node *cur_node = NULL; + uint32_t chan_freq; + + spect_ch = spect_info->ch_info; + + if (scan_list) + qdf_list_peek_front(scan_list, &cur_lst); + + while (cur_lst) { + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, + node); + + temp_ptr = wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_QCOM_VENDOR_OUI, + SIR_MAC_QCOM_VENDOR_SIZE, + util_scan_entry_ie_data(cur_node->entry), + util_scan_entry_ie_len(cur_node->entry)); + + if (temp_ptr) { + avoid_ch_ie = (struct sAvoidChannelIE *)temp_ptr; + if (avoid_ch_ie->type != + QCOM_VENDOR_IE_MCC_AVOID_CH) { + qdf_list_peek_next(scan_list, + cur_lst, &next_lst); + cur_lst = next_lst; + next_lst = NULL; + continue; + } + + sap_ctx->sap_detected_avoid_ch_ie.present = 1; + + chan_freq = + wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, + avoid_ch_ie->channel); + + sap_debug("Q2Q-IE avoid freq = %d", chan_freq); + /* add this channel to to_avoid channel list */ + sap_check_n_add_channel(sap_ctx, avoid_ch_ie->channel); + sap_check_n_add_overlapped_chnls(sap_ctx, + avoid_ch_ie->channel); + /* + * Mark weight of these channel present in IE to MAX + * so that ACS logic will to avoid thse channels + */ + for (i = 0; i < spect_info->num_ch; i++) { + if (spect_ch[i].chan_freq != chan_freq) + continue; + /* + * weight is set more than max so that, + * in the case of other channels being + * assigned max weight due to noise, + * they may be preferred over channels + * with Q2Q IE. + */ + spect_ch[i].weight = SAP_ACS_WEIGHT_MAX + 1; + spect_ch[i].weight_copy = + SAP_ACS_WEIGHT_MAX + 1; + break; + } + } + + qdf_list_peek_next(scan_list, cur_lst, &next_lst); + cur_lst = next_lst; + next_lst = NULL; + } +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * sap_select_preferred_channel_from_channel_list() - to calc best channel + * @best_ch_freq: best chan freq already calculated among all the channels + * @sap_ctx: sap context + * @spectinfo_param: Pointer to sap_sel_ch_info structure + * + * This function calculates the best channel among the configured channel list. + * If channel list not configured then returns the best channel calculated + * among all the channel list. + * + * Return: uint32_t best channel frequency + */ +static +uint32_t sap_select_preferred_channel_from_channel_list(uint32_t best_ch_freq, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *spectinfo_param) +{ + /* + * If Channel List is not Configured don't do anything + * Else return the Best Channel from the Channel List + */ + if ((!sap_ctx->acs_cfg->freq_list) || + (!spectinfo_param) || + (!sap_ctx->acs_cfg->ch_list_count)) + return best_ch_freq; + + if (wlansap_is_channel_present_in_acs_list(best_ch_freq, + sap_ctx->acs_cfg->freq_list, + sap_ctx->acs_cfg->ch_list_count)) + return best_ch_freq; + + return SAP_CHANNEL_NOT_SELECTED; +} + +/** + * sap_chan_sel_init() - Initialize channel select + * @mac: Opaque handle to the global MAC context + * @ch_info_params: Pointer to tSapChSelSpectInfo structure + * @sap_ctx: Pointer to SAP Context + * @ignore_acs_range: Whether ignore channel which is out of acs range + * + * Function sap_chan_sel_init allocates the memory, initializes the + * structures used by the channel selection algorithm + * + * Return: bool Success or FAIL + */ +static bool sap_chan_sel_init(struct mac_context *mac, + struct sap_sel_ch_info *ch_info_params, + struct sap_context *sap_ctx, + bool ignore_acs_range) +{ + struct sap_ch_info *ch_info = NULL; + uint32_t *ch_list = NULL; + uint16_t num_chan = 0; + bool include_dfs_ch = true; + uint8_t sta_sap_scc_on_dfs_chnl_config_value; + bool ch_support_puncture; + + ch_info_params->num_ch = + mac->scan.base_channels.numChannels; + + /* Allocate memory for weight computation of 2.4GHz */ + ch_info = qdf_mem_malloc((ch_info_params->num_ch) * + sizeof(*ch_info)); + if (!ch_info) + return false; + + /* Initialize the pointers in the DfsParams to the allocated memory */ + ch_info_params->ch_info = ch_info; + + ch_list = mac->scan.base_channels.channel_freq_list; + + policy_mgr_get_sta_sap_scc_on_dfs_chnl(mac->psoc, + &sta_sap_scc_on_dfs_chnl_config_value); +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + if (sap_ctx->dfs_ch_disable == true) + include_dfs_ch = false; +#endif + if (!mac->mlme_cfg->dfs_cfg.dfs_master_capable || + ACS_DFS_MODE_DISABLE == sap_ctx->dfs_mode) + include_dfs_ch = false; + + /* Fill the channel number in the spectrum in the operating freq band */ + for (num_chan = 0; + num_chan < ch_info_params->num_ch; + num_chan++, ch_list++, ch_info++) { + ch_support_puncture = false; + ch_info->chan_freq = *ch_list; + /* Initialise for all channels */ + ch_info->rssi_agr = SOFTAP_MIN_RSSI; + /* Initialise max ACS weight for all channels */ + ch_info->weight = SAP_ACS_WEIGHT_MAX; + + /* check if the channel is in NOL denylist */ + if (sap_dfs_is_channel_in_nol_list( + sap_ctx, *ch_list, + PHY_SINGLE_CHANNEL_CENTERED)) { + if (sap_acs_is_puncture_applicable(sap_ctx->acs_cfg)) { + sap_debug_rl("freq %d is in NOL list, can be punctured", + *ch_list); + ch_support_puncture = true; + } else { + sap_debug_rl("freq %d is in NOL list", + *ch_list); + continue; + } + } + + if (!include_dfs_ch || + (sta_sap_scc_on_dfs_chnl_config_value == + PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED && + !policy_mgr_is_sta_sap_scc(mac->psoc, + ch_info->chan_freq))) { + if (wlan_reg_is_dfs_for_freq(mac->pdev, + ch_info->chan_freq)) { + sap_debug("DFS Ch %d not considered for ACS. include_dfs_ch %u, sta_sap_scc_on_dfs_chnl_config_value %d", + *ch_list, include_dfs_ch, + sta_sap_scc_on_dfs_chnl_config_value); + continue; + } + } + + if (!policy_mgr_is_sap_freq_allowed(mac->psoc, + wlan_vdev_mlme_get_opmode(sap_ctx->vdev), *ch_list)) { + if (sap_acs_is_puncture_applicable(sap_ctx->acs_cfg)) { + sap_info("freq %d is not allowed, can be punctured", + *ch_list); + ch_support_puncture = true; + } else { + sap_info("Skip freq %d", *ch_list); + continue; + } + } + + /* OFDM rates are not supported on frequency 2484 */ + if (*ch_list == 2484 && + eCSR_DOT11_MODE_11b != sap_ctx->phyMode) + continue; + + /* Skip DSRC channels */ + if (wlan_reg_is_dsrc_freq(ch_info->chan_freq)) + continue; + + /* Skip indoor channels for non-scc indoor scenario*/ + if (!policy_mgr_is_sap_go_interface_allowed_on_indoor( + mac->pdev, + sap_ctx->sessionId, + *ch_list)) { + sap_debug("Do not allow SAP on indoor frequency %u", + *ch_list); + continue; + } + + /* + * Skip the channels which are not in ACS config from user + * space + */ + if (!ignore_acs_range && + !wlansap_is_channel_present_in_acs_list( + *ch_list, sap_ctx->acs_cfg->freq_list, + sap_ctx->acs_cfg->ch_list_count)) { + if (wlansap_is_channel_present_in_acs_list( + ch_info->chan_freq, + sap_ctx->acs_cfg->master_freq_list, + sap_ctx->acs_cfg->master_ch_list_count)) + ch_info->weight = SAP_ACS_WEIGHT_ADJUSTABLE; + continue; + } + + ch_info->valid = true; + if (!ch_support_puncture) + ch_info->weight = 0; + } + + return true; +} + +/** + * sapweight_rssi_count() - calculates the channel weight due to rssi + * and data count(here number of BSS observed) + * @sap_ctx : Softap context + * @rssi : Max signal strength received from a BSS for the channel + * @count : Number of BSS observed in the channel + * + * Return: uint32_t Calculated channel weight based on above two + */ +static +uint32_t sapweight_rssi_count(struct sap_context *sap_ctx, int8_t rssi, + uint16_t count) +{ + int32_t rssiWeight = 0; + int32_t countWeight = 0; + uint32_t rssicountWeight = 0; + uint8_t softap_rssi_weight_cfg, softap_count_weight_cfg; + uint8_t softap_rssi_weight_local, softap_count_weight_local; + + softap_rssi_weight_cfg = + ACS_WEIGHT_SOFTAP_RSSI_CFG(sap_ctx->auto_channel_select_weight); + + softap_count_weight_cfg = + ACS_WEIGHT_SOFTAP_COUNT_CFG(sap_ctx->auto_channel_select_weight); + + softap_rssi_weight_local = + ACS_WEIGHT_CFG_TO_LOCAL(sap_ctx->auto_channel_select_weight, + softap_rssi_weight_cfg); + + softap_count_weight_local = + ACS_WEIGHT_CFG_TO_LOCAL(sap_ctx->auto_channel_select_weight, + softap_count_weight_cfg); + + /* Weight from RSSI */ + rssiWeight = ACS_WEIGHT_COMPUTE(sap_ctx->auto_channel_select_weight, + softap_rssi_weight_cfg, + rssi - SOFTAP_MIN_RSSI, + SOFTAP_MAX_RSSI - SOFTAP_MIN_RSSI); + + if (rssiWeight > softap_rssi_weight_local) + rssiWeight = softap_rssi_weight_local; + + else if (rssiWeight < 0) + rssiWeight = 0; + + /* Weight from data count */ + countWeight = ACS_WEIGHT_COMPUTE(sap_ctx->auto_channel_select_weight, + softap_count_weight_cfg, + count - SOFTAP_MIN_COUNT, + SOFTAP_MAX_COUNT - SOFTAP_MIN_COUNT); + + if (countWeight > softap_count_weight_local) + countWeight = softap_count_weight_local; + + rssicountWeight = rssiWeight + countWeight; + + return rssicountWeight; +} + +/** + * sap_get_channel_status() - get channel info via channel number + * @p_mac: Pointer to Global MAC structure + * @chan_freq: channel frequency + * + * Return: chan status info + */ +static struct channel_status *sap_get_channel_status + (struct mac_context *p_mac, uint32_t chan_freq) +{ + if (!p_mac->sap.acs_with_more_param) + return NULL; + + return ucfg_mc_cp_stats_get_channel_status(p_mac->pdev, chan_freq); +} + +#ifndef WLAN_FEATURE_SAP_ACS_OPTIMIZE +/** + * sap_clear_channel_status() - clear chan info + * @p_mac: Pointer to Global MAC structure + * + * Return: none + */ +static void sap_clear_channel_status(struct mac_context *p_mac) +{ + if (!p_mac->sap.acs_with_more_param) + return; + + ucfg_mc_cp_stats_clear_channel_status(p_mac->pdev); +} +#else +static void sap_clear_channel_status(struct mac_context *p_mac) +{ +} +#endif + +/** + * sap_weight_channel_noise_floor() - compute noise floor weight + * @sap_ctx: sap context + * @channel_stat: Pointer to chan status info + * + * Return: channel noise floor weight + */ +static uint32_t sap_weight_channel_noise_floor(struct sap_context *sap_ctx, + struct channel_status + *channel_stat) +{ + uint32_t noise_floor_weight; + uint8_t softap_nf_weight_cfg; + uint8_t softap_nf_weight_local; + + softap_nf_weight_cfg = + ACS_WEIGHT_SOFTAP_NOISE_FLOOR_CFG + (sap_ctx->auto_channel_select_weight); + + softap_nf_weight_local = + ACS_WEIGHT_CFG_TO_LOCAL(sap_ctx->auto_channel_select_weight, + softap_nf_weight_cfg); + + if (!channel_stat || channel_stat->channel_freq == 0) + return softap_nf_weight_local; + + noise_floor_weight = (channel_stat->noise_floor == 0) ? 0 : + (ACS_WEIGHT_COMPUTE( + sap_ctx->auto_channel_select_weight, + softap_nf_weight_cfg, + channel_stat->noise_floor - + SOFTAP_MIN_NF, + SOFTAP_MAX_NF - SOFTAP_MIN_NF)); + + if (noise_floor_weight > softap_nf_weight_local) + noise_floor_weight = softap_nf_weight_local; + + sap_debug("nf=%d, nfwc=%d, nfwl=%d, nfw=%d freq=%d", + channel_stat->noise_floor, + softap_nf_weight_cfg, softap_nf_weight_local, + noise_floor_weight, channel_stat->channel_freq); + + return noise_floor_weight; +} + +/** + * sap_weight_channel_free() - compute channel free weight + * @sap_ctx: sap context + * @channel_stat: Pointer to chan status info + * + * Return: channel free weight + */ +static uint32_t sap_weight_channel_free(struct sap_context *sap_ctx, + struct channel_status + *channel_stat) +{ + uint32_t channel_free_weight; + uint8_t softap_channel_free_weight_cfg; + uint8_t softap_channel_free_weight_local; + uint32_t rx_clear_count = 0; + uint32_t cycle_count = 0; + + softap_channel_free_weight_cfg = + ACS_WEIGHT_SOFTAP_CHANNEL_FREE_CFG + (sap_ctx->auto_channel_select_weight); + + softap_channel_free_weight_local = + ACS_WEIGHT_CFG_TO_LOCAL(sap_ctx->auto_channel_select_weight, + softap_channel_free_weight_cfg); + + if (!channel_stat || channel_stat->channel_freq == 0) + return softap_channel_free_weight_local; + + rx_clear_count = channel_stat->rx_clear_count - + channel_stat->tx_frame_count - + channel_stat->rx_frame_count; + cycle_count = channel_stat->cycle_count; + + /* LSH 4, otherwise it is always 0. */ + channel_free_weight = (cycle_count == 0) ? 0 : + (ACS_WEIGHT_COMPUTE( + sap_ctx->auto_channel_select_weight, + softap_channel_free_weight_cfg, + ((rx_clear_count << 8) + + (cycle_count >> 1))/cycle_count - + (SOFTAP_MIN_CHNFREE << 8), + (SOFTAP_MAX_CHNFREE - + SOFTAP_MIN_CHNFREE) << 8)); + + if (channel_free_weight > softap_channel_free_weight_local) + channel_free_weight = softap_channel_free_weight_local; + + sap_debug_rl("rcc=%d, cc=%d, tc=%d, rc=%d, cfwc=%d, cfwl=%d, cfw=%d", + rx_clear_count, cycle_count, + channel_stat->tx_frame_count, + channel_stat->rx_frame_count, + softap_channel_free_weight_cfg, + softap_channel_free_weight_local, + channel_free_weight); + + return channel_free_weight; +} + +/** + * sap_weight_channel_txpwr_range() - compute channel tx power range weight + * @sap_ctx: sap context + * @channel_stat: Pointer to chan status info + * + * Return: tx power range weight + */ +static uint32_t sap_weight_channel_txpwr_range(struct sap_context *sap_ctx, + struct channel_status + *channel_stat) +{ + uint32_t txpwr_weight_low_speed; + uint8_t softap_txpwr_range_weight_cfg; + uint8_t softap_txpwr_range_weight_local; + + softap_txpwr_range_weight_cfg = + ACS_WEIGHT_SOFTAP_TX_POWER_RANGE_CFG + (sap_ctx->auto_channel_select_weight); + + softap_txpwr_range_weight_local = + ACS_WEIGHT_CFG_TO_LOCAL(sap_ctx->auto_channel_select_weight, + softap_txpwr_range_weight_cfg); + + if (!channel_stat || channel_stat->channel_freq == 0) + return softap_txpwr_range_weight_local; + + + txpwr_weight_low_speed = (channel_stat->chan_tx_pwr_range == 0) ? 0 : + (ACS_WEIGHT_COMPUTE( + sap_ctx->auto_channel_select_weight, + softap_txpwr_range_weight_cfg, + SOFTAP_MAX_TXPWR - + channel_stat->chan_tx_pwr_range, + SOFTAP_MAX_TXPWR - SOFTAP_MIN_TXPWR)); + + if (txpwr_weight_low_speed > softap_txpwr_range_weight_local) + txpwr_weight_low_speed = softap_txpwr_range_weight_local; + + sap_debug_rl("tpr=%d, tprwc=%d, tprwl=%d, tprw=%d", + channel_stat->chan_tx_pwr_range, + softap_txpwr_range_weight_cfg, + softap_txpwr_range_weight_local, + txpwr_weight_low_speed); + + return txpwr_weight_low_speed; +} + +/** + * sap_weight_channel_txpwr_tput() - compute channel tx power + * throughput weight + * @sap_ctx: sap context + * @channel_stat: Pointer to chan status info + * + * Return: tx power throughput weight + */ +static uint32_t sap_weight_channel_txpwr_tput(struct sap_context *sap_ctx, + struct channel_status + *channel_stat) +{ + uint32_t txpwr_weight_high_speed; + uint8_t softap_txpwr_tput_weight_cfg; + uint8_t softap_txpwr_tput_weight_local; + + softap_txpwr_tput_weight_cfg = + ACS_WEIGHT_SOFTAP_TX_POWER_THROUGHPUT_CFG + (sap_ctx->auto_channel_select_weight); + + softap_txpwr_tput_weight_local = + ACS_WEIGHT_CFG_TO_LOCAL(sap_ctx->auto_channel_select_weight, + softap_txpwr_tput_weight_cfg); + + if (!channel_stat || channel_stat->channel_freq == 0) + return softap_txpwr_tput_weight_local; + + txpwr_weight_high_speed = (channel_stat->chan_tx_pwr_throughput == 0) + ? 0 : (ACS_WEIGHT_COMPUTE( + sap_ctx->auto_channel_select_weight, + softap_txpwr_tput_weight_cfg, + SOFTAP_MAX_TXPWR - + channel_stat->chan_tx_pwr_throughput, + SOFTAP_MAX_TXPWR - SOFTAP_MIN_TXPWR)); + + if (txpwr_weight_high_speed > softap_txpwr_tput_weight_local) + txpwr_weight_high_speed = softap_txpwr_tput_weight_local; + + sap_debug_rl("tpt=%d, tptwc=%d, tptwl=%d, tptw=%d", + channel_stat->chan_tx_pwr_throughput, + softap_txpwr_tput_weight_cfg, + softap_txpwr_tput_weight_local, + txpwr_weight_high_speed); + + return txpwr_weight_high_speed; +} + +/** + * sap_weight_channel_status() - compute chan status weight + * @sap_ctx: sap context + * @channel_stat: Pointer to chan status info + * + * Return: chan status weight + */ +static +uint32_t sap_weight_channel_status(struct sap_context *sap_ctx, + struct channel_status *channel_stat) +{ + return sap_weight_channel_noise_floor(sap_ctx, channel_stat) + + sap_weight_channel_free(sap_ctx, channel_stat) + + sap_weight_channel_txpwr_range(sap_ctx, channel_stat) + + sap_weight_channel_txpwr_tput(sap_ctx, channel_stat); +} + +/** + * sap_update_rssi_bsscount() - updates bss count and rssi effect. + * + * @ch_info: Channel Information + * @offset: Channel Offset + * @sap_24g: Channel is in 2.4G or 5G + * @ch_start: the start of channel array + * @ch_end: the end of channel array + * + * sap_update_rssi_bsscount updates bss count and rssi effect based + * on the channel offset. + * + * Return: None. + */ + +static void sap_update_rssi_bsscount(struct sap_ch_info *ch_info, + int32_t offset, bool sap_24g, + struct sap_ch_info *ch_start, + struct sap_ch_info *ch_end) +{ + struct sap_ch_info *chan_info = NULL; + int32_t rssi, rsssi_effect; + + chan_info = (ch_info + offset); + if (chan_info && chan_info >= ch_start && + chan_info < ch_end) { + if (!WLAN_REG_IS_SAME_BAND_FREQS(ch_info->chan_freq, + chan_info->chan_freq)) + return; + ++chan_info->bss_count; + switch (offset) { + case -1: + case 1: + rsssi_effect = sap_24g ? + SAP_24GHZ_FIRST_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND1_RSSI_EFFECT_PRIMARY; + break; + case -2: + case 2: + rsssi_effect = sap_24g ? + SAP_24GHZ_SEC_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND2_RSSI_EFFECT_PRIMARY; + break; + case -3: + case 3: + rsssi_effect = sap_24g ? + SAP_24GHZ_THIRD_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND3_RSSI_EFFECT_PRIMARY; + break; + case -4: + case 4: + rsssi_effect = sap_24g ? + SAP_24GHZ_FOURTH_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY : + SAP_SUBBAND4_RSSI_EFFECT_PRIMARY; + break; + case -5: + case 5: + rsssi_effect = SAP_SUBBAND5_RSSI_EFFECT_PRIMARY; + break; + case -6: + case 6: + rsssi_effect = SAP_SUBBAND6_RSSI_EFFECT_PRIMARY; + break; + case -7: + case 7: + rsssi_effect = SAP_SUBBAND7_RSSI_EFFECT_PRIMARY; + break; + default: + rsssi_effect = 0; + break; + } + + rssi = ch_info->rssi_agr + rsssi_effect; + if (IS_RSSI_VALID(chan_info->rssi_agr, rssi)) + chan_info->rssi_agr = rssi; + if (chan_info->rssi_agr < SOFTAP_MIN_RSSI) + chan_info->rssi_agr = SOFTAP_MIN_RSSI; + } +} + +/** + * sap_update_rssi_bsscount_vht_5G() - updates bss count and rssi effect. + * + * @spect_ch: Channel Information + * @offset: Channel Offset + * @num_ch: no.of channels + * @ch_start: the start of spect ch array + * @ch_end: the end of spect ch array + * + * sap_update_rssi_bsscount_vht_5G updates bss count and rssi effect based + * on the channel offset. + * + * Return: None. + */ + +static void sap_update_rssi_bsscount_vht_5G( + struct sap_ch_info *spect_ch, + int32_t offset, + uint16_t num_ch, + struct sap_ch_info *ch_start, + struct sap_ch_info *ch_end) +{ + int32_t ch_offset; + uint16_t i, cnt; + + if (!offset) + return; + if (offset > 0) + cnt = num_ch; + else + cnt = num_ch + 1; + for (i = 0; i < cnt; i++) { + ch_offset = offset + i; + if (ch_offset == 0) + continue; + sap_update_rssi_bsscount(spect_ch, ch_offset, false, + ch_start, ch_end); + } +} +/** + * sap_interference_rssi_count_5G() - sap_interference_rssi_count + * considers the Adjacent channel rssi and + * data count(here number of BSS observed) + * @spect_ch: Channel Information + * @chan_width: Channel width parsed from beacon IE + * @sec_chan_offset: Secondary Channel Offset + * @ch_freq0: frequency_0 for the given channel. + * @ch_freq1: frequency_1 for the given channel. + * @op_chan_freq: Operating channel frequency. + * @ch_start: the start of spect ch array + * @ch_end: the end of spect ch array + * + * sap_interference_rssi_count_5G considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * + * Return: NA. + */ + +static void sap_interference_rssi_count_5G(struct sap_ch_info *spect_ch, + uint16_t chan_width, + uint16_t sec_chan_offset, + uint32_t ch_freq0, + uint32_t ch_freq1, + uint32_t op_chan_freq, + struct sap_ch_info *ch_start, + struct sap_ch_info *ch_end) +{ + uint16_t num_ch; + int32_t offset = 0; + + sap_debug("freq = %d, ch width = %d, ch_freq0 = %d ch_freq1 = %d", + op_chan_freq, chan_width, ch_freq0, ch_freq1); + + switch (chan_width) { + case eHT_CHANNEL_WIDTH_40MHZ: + switch (sec_chan_offset) { + /* Above the Primary Channel */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + sap_update_rssi_bsscount(spect_ch, 1, false, + ch_start, ch_end); + return; + + /* Below the Primary channel */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + sap_update_rssi_bsscount(spect_ch, -1, false, + ch_start, ch_end); + return; + } + return; + case eHT_CHANNEL_WIDTH_80MHZ: + case eHT_CHANNEL_WIDTH_80P80MHZ: + num_ch = 3; + if ((ch_freq0 - op_chan_freq) == 30) { + offset = 1; + } else if ((ch_freq0 - op_chan_freq) == 10) { + offset = -1; + } else if ((ch_freq0 - op_chan_freq) == -10) { + offset = -2; + } else if ((ch_freq0 - op_chan_freq) == -30) { + offset = -3; + } + break; + case eHT_CHANNEL_WIDTH_160MHZ: + num_ch = 7; + if ((ch_freq0 - op_chan_freq) == 70) + offset = 1; + else if ((ch_freq0 - op_chan_freq) == 50) + offset = -1; + else if ((ch_freq0 - op_chan_freq) == 30) + offset = -2; + else if ((ch_freq0 - op_chan_freq) == 10) + offset = -3; + else if ((ch_freq0 - op_chan_freq) == -10) + offset = -4; + else if ((ch_freq0 - op_chan_freq) == -30) + offset = -5; + else if ((ch_freq0 - op_chan_freq) == -50) + offset = -6; + else if ((ch_freq0 - op_chan_freq) == -70) + offset = -7; + break; + default: + return; + } + + sap_update_rssi_bsscount_vht_5G(spect_ch, offset, num_ch, ch_start, + ch_end); +} + +/** + * sap_interference_rssi_count() - sap_interference_rssi_count + * considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * @spect_ch: Channel Information + * @ch_start: the start of spect ch array + * @ch_end: the end of spect ch array + * @mac: Opaque handle to the global MAC context + * + * sap_interference_rssi_count considers the Adjacent channel rssi + * and data count(here number of BSS observed) + * + * Return: None. + */ + +static void sap_interference_rssi_count(struct sap_ch_info *spect_ch, + struct sap_ch_info *ch_start, + struct sap_ch_info *ch_end, + struct mac_context *mac) +{ + if (!spect_ch) { + sap_err("spect_ch is NULL"); + return; + } + + switch (wlan_reg_freq_to_chan(mac->pdev, spect_ch->chan_freq)) { + case CHANNEL_1: + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + ch_start, ch_end); + break; + + case CHANNEL_2: + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + ch_start, ch_end); + break; + case CHANNEL_3: + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + ch_start, ch_end); + break; + case CHANNEL_4: + sap_update_rssi_bsscount(spect_ch, -3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + ch_start, ch_end); + break; + + case CHANNEL_5: + case CHANNEL_6: + case CHANNEL_7: + case CHANNEL_8: + case CHANNEL_9: + case CHANNEL_10: + sap_update_rssi_bsscount(spect_ch, -4, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 4, true, + ch_start, ch_end); + break; + + case CHANNEL_11: + sap_update_rssi_bsscount(spect_ch, -4, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 3, true, + ch_start, ch_end); + break; + + case CHANNEL_12: + sap_update_rssi_bsscount(spect_ch, -4, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 2, true, + ch_start, ch_end); + break; + + case CHANNEL_13: + sap_update_rssi_bsscount(spect_ch, -4, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, 1, true, + ch_start, ch_end); + break; + + case CHANNEL_14: + sap_update_rssi_bsscount(spect_ch, -4, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -3, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -2, true, + ch_start, ch_end); + sap_update_rssi_bsscount(spect_ch, -1, true, + ch_start, ch_end); + break; + + default: + break; + } +} + +/** + * ch_in_pcl() - Is channel in the Preferred Channel List (PCL) + * @sap_ctx: SAP context which contains the current PCL + * @ch_freq: Input channel number to be checked + * + * Check if a channel is in the preferred channel list + * + * Return: True if channel is in PCL, else False + */ +static bool ch_in_pcl(struct sap_context *sap_ctx, uint32_t ch_freq) +{ + uint32_t i; + + for (i = 0; i < sap_ctx->acs_cfg->pcl_ch_count; i++) { + if (ch_freq == sap_ctx->acs_cfg->pcl_chan_freq[i]) + return true; + } + + return false; +} + +/** + * sap_upd_chan_spec_params() - sap_upd_chan_spec_params + * updates channel parameters obtained from Beacon + * @scan_entry: Beacon structure populated by scan + * @ch_width: Channel width + * @sec_ch_offset: Secondary Channel Offset + * @center_freq0: Central frequency 0 for the given channel + * @center_freq1: Central frequency 1 for the given channel + * + * sap_upd_chan_spec_params updates the spectrum channels based on the + * scan_entry + * + * Return: NA. + */ +static void +sap_upd_chan_spec_params(struct scan_cache_node *scan_entry, + tSirMacHTChannelWidth *ch_width, + uint16_t *sec_ch_offset, + uint32_t *center_freq0, + uint32_t *center_freq1) +{ + enum wlan_phymode phy_mode; + struct channel_info *chan; + + phy_mode = util_scan_entry_phymode(scan_entry->entry); + chan = util_scan_entry_channel(scan_entry->entry); + + if (IS_WLAN_PHYMODE_160MHZ(phy_mode)) { + if (phy_mode == WLAN_PHYMODE_11AC_VHT80_80 || + phy_mode == WLAN_PHYMODE_11AXA_HE80_80) { + *ch_width = eHT_CHANNEL_WIDTH_80P80MHZ; + *center_freq0 = chan->cfreq0; + *center_freq1 = chan->cfreq1; + } else { + *ch_width = eHT_CHANNEL_WIDTH_160MHZ; + if (chan->cfreq1) + *center_freq0 = chan->cfreq1; + else + *center_freq0 = chan->cfreq0; + } + + } else if (IS_WLAN_PHYMODE_80MHZ(phy_mode)) { + *ch_width = eHT_CHANNEL_WIDTH_80MHZ; + *center_freq0 = chan->cfreq0; + } else if (IS_WLAN_PHYMODE_40MHZ(phy_mode)) { + if (chan->cfreq0 > chan->chan_freq) + *sec_ch_offset = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + else + *sec_ch_offset = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + *ch_width = eHT_CHANNEL_WIDTH_40MHZ; + *center_freq0 = chan->cfreq0; + } else { + *ch_width = eHT_CHANNEL_WIDTH_20MHZ; + } +} + +/** + * sap_weight_channel_reg_max_power() - API to calculate channel weight of max + * tx power allowed + * @sap_ctx: SAP context + * @freq: channel frequency + * + * This function get channel tx power limit from secondary current channel + * list and calculate weight with power factor configure + * + * Return: channel power weight + */ +static uint32_t +sap_weight_channel_reg_max_power(struct sap_context *sap_ctx, qdf_freq_t freq) +{ + struct wlan_objmgr_pdev *pdev; + int32_t power_weight; + uint8_t power_weight_cfg, power_weight_local; + uint16_t eirp_pwr, psd_pwr; + bool is_psd; + uint32_t chan_flags; + QDF_STATUS status; + + power_weight_cfg = ACS_WEIGHT_SOFTAP_REG_MAX_POWER_CFG( + sap_ctx->auto_channel_select_weight); + + /* reg max power factor not configure, return zero weight */ + if (!power_weight_cfg) + return 0; + + power_weight_local = ACS_WEIGHT_CFG_TO_LOCAL( + sap_ctx->auto_channel_select_weight, power_weight_cfg); + + if (!sap_ctx->vdev) { + sap_err("sap ctx vdev is null."); + return power_weight_local; + } + pdev = wlan_vdev_get_pdev(sap_ctx->vdev); + status = wlan_reg_get_chan_pwr_attr_from_secondary_list_for_freq( + pdev, freq, &is_psd, &eirp_pwr, &psd_pwr, &chan_flags); + if (status != QDF_STATUS_SUCCESS) { + sap_err("fail to get power attribute."); + return power_weight_local; + } + + if (eirp_pwr > REG_MAX_EIRP_POWER) { + sap_debug("eirp_pwr %d exceed max", eirp_pwr); + eirp_pwr = REG_MAX_EIRP_POWER; + } + if (eirp_pwr < REG_MIN_EIRP_POWER) { + sap_debug("eirp_pwr %d below min", eirp_pwr); + eirp_pwr = REG_MIN_EIRP_POWER; + } + + power_weight = ACS_WEIGHT_COMPUTE( + sap_ctx->auto_channel_select_weight, + power_weight_cfg, + REG_MAX_EIRP_POWER - eirp_pwr, + REG_MAX_EIRP_POWER - REG_MIN_EIRP_POWER); + + if (power_weight > power_weight_local) + power_weight = power_weight_local; + else if (power_weight < 0) + power_weight = 0; + + return power_weight; +} + +static void +sap_normalize_channel_weight_with_factors(struct mac_context *mac, + struct sap_ch_info *spect_ch) +{ + uint32_t normalized_weight; + uint8_t normalize_factor = 100; + uint8_t dfs_normalize_factor; + uint32_t chan_freq, i; + struct acs_weight *weight_list = + mac->mlme_cfg->acs.normalize_weight_chan; + struct acs_weight_range *range_list = + mac->mlme_cfg->acs.normalize_weight_range; + bool freq_present_in_list = false; + + chan_freq = spect_ch->chan_freq; + + /* Check if the freq is present in range list */ + for (i = 0; i < mac->mlme_cfg->acs.num_weight_range; i++) { + if (chan_freq >= range_list[i].start_freq && + chan_freq <= range_list[i].end_freq) { + normalize_factor = range_list[i].normalize_weight; + sap_debug_rl("Range list, freq %d normalize weight factor %d", + chan_freq, normalize_factor); + freq_present_in_list = true; + } + } + + /* Check if user wants a special factor for this freq */ + for (i = 0; i < mac->mlme_cfg->acs.normalize_weight_num_chan; i++) { + if (chan_freq == weight_list[i].chan_freq) { + normalize_factor = weight_list[i].normalize_weight; + sap_debug("freq %d normalize weight factor %d", + chan_freq, normalize_factor); + freq_present_in_list = true; + } + } + + if (wlan_reg_is_dfs_for_freq(mac->pdev, chan_freq)) { + dfs_normalize_factor = MLME_GET_DFS_CHAN_WEIGHT( + mac->mlme_cfg->acs.np_chan_weightage); + if (freq_present_in_list) + normalize_factor = qdf_min(dfs_normalize_factor, + normalize_factor); + else + normalize_factor = dfs_normalize_factor; + freq_present_in_list = true; + sap_debug_rl("DFS channel weightage %d min %d", + dfs_normalize_factor, normalize_factor); + } + + if (freq_present_in_list) { + normalized_weight = + ((SAP_ACS_WEIGHT_MAX - spect_ch->weight) * + (100 - normalize_factor)) / 100; + sap_debug_rl("freq %d old weight %d new weight %d", + chan_freq, spect_ch->weight, + spect_ch->weight + normalized_weight); + spect_ch->weight += normalized_weight; + } +} + +/** + * sap_update_6ghz_max_weight() - Update 6 GHz channel max weight + * @ch_info_params: Pointer to the sap_sel_ch_info structure + * @max_valid_weight: max valid weight on 6 GHz channels + * + * If ACS frequency list includes 6 GHz channels, the user prefers + * to start SAP on 6 GHz as much as possible. The acs logic in + * sap_chan_sel_init will mark channel weight to Max weight value + * of SAP_ACS_WEIGHT_MAX if channel is no in ACS channel list(filtered + * by PCL). + * In ACS bw 160 case, sometime the combined weight of 8 channels + * on 6 GHz(some of them have weight SAP_ACS_WEIGHT_MAX) + * may higher than 5 GHz channels and finally select 5 GHz channel. + * This API is to update the 6 GHz weight to max valid weight in + * 6 GHz instead of value SAP_ACS_WEIGHT_MAX. All those channels have + * special weight value SAP_ACS_WEIGHT_ADJUSTABLE which is assigned + * sap_chan_sel_init. + * + * Return: void + */ +static void sap_update_6ghz_max_weight(struct sap_sel_ch_info *ch_info_params, + uint32_t max_valid_weight) +{ + uint8_t chn_num; + struct sap_ch_info *pspect_ch; + + sap_debug("max_valid_weight_on_6ghz_channels %d", + max_valid_weight); + if (!max_valid_weight) + return; + for (chn_num = 0; chn_num < ch_info_params->num_ch; + chn_num++) { + pspect_ch = &ch_info_params->ch_info[chn_num]; + if (!wlan_reg_is_6ghz_chan_freq(pspect_ch->chan_freq)) + continue; + if (pspect_ch->weight == SAP_ACS_WEIGHT_ADJUSTABLE) { + pspect_ch->weight = max_valid_weight; + pspect_ch->weight_copy = pspect_ch->weight; + } + } +} + +/** + * sap_update_5ghz_low_freq_weight() - Update weight of 5GHz low frequency + * @psoc: Pointer to psoc + * @ch_info_params: Pointer to sap_sel_ch_info structure + * + * This api helps to lower the 5GHz low frequency weight by + * SAP_NORMALISE_ACS_WEIGHT so that it will get more preference to get + * selected during ACS. + * + * Return: void + */ +static void sap_update_5ghz_low_freq_weight( + struct wlan_objmgr_psoc *psoc, + struct sap_sel_ch_info *ch_info_params) +{ + uint8_t ch_num; + qdf_freq_t freq; + uint32_t weight; + + if (!policy_mgr_is_hw_sbs_capable(psoc)) + return; + + for (ch_num = 0; ch_num < ch_info_params->num_ch; ch_num++) { + freq = ch_info_params->ch_info[ch_num].chan_freq; + weight = ch_info_params->ch_info[ch_num].weight; + if (policy_mgr_is_given_freq_5g_low(psoc, freq)) { + /* + * Lower the weight by SAP_NORMALISE_ACS_WEIGHT i.e 5% + * from channel weight itself. Later if required, modify + * this value. + * Here are the few observation captured which results + * to go with SAP_NORMALISE_ACS_WEIGHT. + * + * +-----------+-------------+------------+---------------+--------------------------------------+ + * | freq | bss_count | rssi | weight | observation | + * +---------------------------------------------------------------------------------------------+ + * | 5G low | >6 | -76 - -56 | 17419 - 17774 | Diff b/w 5G low & 5G high min weight | + * | 5G high | <4 | -100 - -50 | 16842 - 17685 | is ~5% of 5G low min weight | + * | | | | | | + * | 5G low | >6 | -77 - -54 | 17419 - 17730 | Diff b/w 5G low & 5G high min weight | + * | 5G high | <4 | -100 - -50 | 16842 - 17552 | is ~5% of 5G low min weight | + * | | | | | | + * | 5G low | >5 | -77 - -57 | 17286 - 17552 | Diff b/w 5G low & 5G high min weight | + * | 5G high | <4 | -100 - -50 | 16842 - 17596 | is ~5% of 5G low min weight | + * +-----------+-------------+------------+---------------+--------------------------------------+ + */ + + weight = weight - ((weight * SAP_NORMALISE_ACS_WEIGHT ) / 100); + ch_info_params->ch_info[ch_num].weight = weight; + } + } +} + +/** + * sap_compute_spect_weight() - Compute spectrum weight + * @ch_info_params: Pointer to the tSpectInfoParams structure + * @mac: Pointer to mac_context struucture + * @scan_list: Pointer to channel list + * @sap_ctx: Context of the SAP + * + * Main function for computing the weight of each channel in the + * spectrum based on the RSSI value of the BSSes on the channel + * and number of BSS + */ +static void sap_compute_spect_weight(struct sap_sel_ch_info *ch_info_params, + struct mac_context *mac, + qdf_list_t *scan_list, + struct sap_context *sap_ctx) +{ + int8_t rssi = 0; + uint8_t chn_num = 0; + struct sap_ch_info *ch_info = ch_info_params->ch_info; + tSirMacHTChannelWidth ch_width = 0; + uint16_t secondaryChannelOffset; + uint32_t center_freq0, center_freq1, chan_freq; + uint8_t i; + bool found; + struct sap_ch_info *ch_start = ch_info_params->ch_info; + struct sap_ch_info *ch_end = ch_info_params->ch_info + + ch_info_params->num_ch; + qdf_list_node_t *cur_lst = NULL, *next_lst = NULL; + struct scan_cache_node *cur_node = NULL; + uint32_t rssi_bss_weight = 0, chan_status_weight = 0, power_weight = 0; + uint32_t max_valid_weight_6ghz = 0; + + sap_debug("Computing spectral weight"); + + if (scan_list) + qdf_list_peek_front(scan_list, &cur_lst); + while (cur_lst) { + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, + node); + ch_info = ch_info_params->ch_info; + /* Defining the default values, so that any value will hold the default values */ + + secondaryChannelOffset = PHY_SINGLE_CHANNEL_CENTERED; + center_freq0 = 0; + center_freq1 = 0; + + chan_freq = + util_scan_entry_channel_frequency(cur_node->entry); + + sap_upd_chan_spec_params(cur_node, &ch_width, + &secondaryChannelOffset, + ¢er_freq0, ¢er_freq1); + + /* Processing for each tCsrScanResultInfo in the tCsrScanResult DLink list */ + for (chn_num = 0; chn_num < ch_info_params->num_ch; + chn_num++) { + + if (chan_freq != ch_info->chan_freq) { + ch_info++; + continue; + } + + if (ch_info->rssi_agr < cur_node->entry->rssi_raw) + ch_info->rssi_agr = cur_node->entry->rssi_raw; + + ++ch_info->bss_count; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) + sap_interference_rssi_count(ch_info, ch_start, + ch_end, mac); + else + sap_interference_rssi_count_5G( + ch_info, ch_width, secondaryChannelOffset, + center_freq0, center_freq1, chan_freq, + ch_start, ch_end); + + ch_info++; + break; + + } + + qdf_list_peek_next(scan_list, cur_lst, &next_lst); + cur_lst = next_lst; + next_lst = NULL; + } + + /* Calculate the weights for all channels in the spectrum ch_info */ + ch_info = ch_info_params->ch_info; + + for (chn_num = 0; chn_num < (ch_info_params->num_ch); + chn_num++) { + + /* + rssi : Maximum received signal strength among all BSS on that channel + bss_count : Number of BSS on that channel + */ + + rssi = (int8_t)ch_info->rssi_agr; + if (ch_in_pcl(sap_ctx, ch_info->chan_freq)) + rssi -= PCL_RSSI_DISCOUNT; + + if (rssi < SOFTAP_MIN_RSSI) + rssi = SOFTAP_MIN_RSSI; + + if (ch_info->weight == SAP_ACS_WEIGHT_MAX || + ch_info->weight == SAP_ACS_WEIGHT_ADJUSTABLE) { + ch_info->weight_copy = ch_info->weight; + goto debug_info; + } + + /* There may be channels in scanlist, which were not sent to + * FW for scanning as part of ACS scan list, but they do have an + * effect on the neighbouring channels, so they help to find a + * suitable channel, but there weight should be max as they were + * and not meant to be included in the ACS scan results. + * So just assign RSSI as -100, bsscount as 0, and weight as max + * to them, so that they always stay low in sorting of best + * channels which were included in ACS scan list + */ + found = false; + for (i = 0; i < sap_ctx->num_of_channel; i++) { + if (ch_info->chan_freq == sap_ctx->freq_list[i]) { + /* Scan channel was included in ACS scan list */ + found = true; + break; + } + } + + rssi_bss_weight = 0; + chan_status_weight = 0; + power_weight = 0; + if (found) { + rssi_bss_weight = sapweight_rssi_count( + sap_ctx, + rssi, + ch_info->bss_count); + chan_status_weight = sap_weight_channel_status( + sap_ctx, + sap_get_channel_status( + mac, ch_info->chan_freq)); + power_weight = sap_weight_channel_reg_max_power( + sap_ctx, ch_info->chan_freq); + ch_info->weight = SAPDFS_NORMALISE_1000 * + (rssi_bss_weight + chan_status_weight + + power_weight); + } else { + if (wlansap_is_channel_present_in_acs_list( + ch_info->chan_freq, + sap_ctx->acs_cfg->master_freq_list, + sap_ctx->acs_cfg->master_ch_list_count)) + ch_info->weight = SAP_ACS_WEIGHT_ADJUSTABLE; + else + ch_info->weight = SAP_ACS_WEIGHT_MAX; + ch_info->rssi_agr = SOFTAP_MIN_RSSI; + rssi = SOFTAP_MIN_RSSI; + ch_info->bss_count = SOFTAP_MIN_COUNT; + } + + sap_normalize_channel_weight_with_factors(mac, ch_info); + + if (ch_info->weight > SAP_ACS_WEIGHT_MAX) + ch_info->weight = SAP_ACS_WEIGHT_MAX; + ch_info->weight_copy = ch_info->weight; + +debug_info: + if (wlan_reg_is_6ghz_chan_freq(ch_info->chan_freq) && + ch_info->weight < SAP_ACS_WEIGHT_ADJUSTABLE && + max_valid_weight_6ghz < ch_info->weight) + max_valid_weight_6ghz = ch_info->weight; + + sap_debug("freq %d valid %d weight %d(%d,%d,%d) rssi %d bss %d", + ch_info->chan_freq, ch_info->valid, + ch_info->weight, rssi_bss_weight, + chan_status_weight, power_weight, + ch_info->rssi_agr, ch_info->bss_count); + + ch_info++; + } + sap_update_6ghz_max_weight(ch_info_params, + max_valid_weight_6ghz); + + if (policy_mgr_is_vdev_ll_lt_sap(mac->psoc, sap_ctx->vdev_id)) + sap_update_5ghz_low_freq_weight(mac->psoc, ch_info_params); + + sap_clear_channel_status(mac); +} + +void sap_chan_sel_exit(struct sap_sel_ch_info *ch_info_params) +{ + /* Free all the allocated memory */ + qdf_mem_free(ch_info_params->ch_info); +} + +/*========================================================================== + FUNCTION sap_sort_chl_weight + + DESCRIPTION + Function to sort the channels with the least weight first for 20MHz channels + + DEPENDENCIES + NA. + + PARAMETERS + + IN + ch_info_params : Pointer to the tSapChSelSpectInfo structure + + RETURN VALUE + void : NULL + + SIDE EFFECTS + ============================================================================*/ +static void sap_sort_chl_weight(struct sap_sel_ch_info *ch_info_params) +{ + struct sap_ch_info temp; + + struct sap_ch_info *ch_info = NULL; + uint32_t i = 0, j = 0, min_weight_index = 0; + + ch_info = ch_info_params->ch_info; + for (i = 0; i < ch_info_params->num_ch; i++) { + min_weight_index = i; + for (j = i + 1; j < ch_info_params->num_ch; j++) { + if (ch_info[j].weight < + ch_info[min_weight_index].weight) { + min_weight_index = j; + } else if (ch_info[j].weight == + ch_info[min_weight_index].weight) { + if (ch_info[j].bss_count < + ch_info[min_weight_index].bss_count) + min_weight_index = j; + } + } + if (min_weight_index != i) { + qdf_mem_copy(&temp, &ch_info[min_weight_index], + sizeof(*ch_info)); + qdf_mem_copy(&ch_info[min_weight_index], &ch_info[i], + sizeof(*ch_info)); + qdf_mem_copy(&ch_info[i], &temp, sizeof(*ch_info)); + } + } +} + +/** + * sap_override_6ghz_psc_minidx() - override mindex to 6 GHz PSC channel's idx + * @mac_ctx: pointer to max context + * @spectinfo: Pointer to array of tSach_infoInfo + * @count: number of tSach_infoInfo element to search + * @minidx: index to be overridden + * + * Return: QDF STATUS + */ +static void +sap_override_6ghz_psc_minidx(struct mac_context *mac_ctx, + struct sap_ch_info *spectinfo, + uint8_t count, + uint8_t *minidx) +{ + uint8_t i; + + if (!mac_ctx->mlme_cfg->acs.acs_prefer_6ghz_psc) + return; + + for (i = 0; i < count; i++) { + if (wlan_reg_is_6ghz_chan_freq( + spectinfo[i].chan_freq) && + wlan_reg_is_6ghz_psc_chan_freq( + spectinfo[i].chan_freq)) { + *minidx = i; + return; + } + } +} + +/** + * sap_sort_chl_weight_80_mhz() - to sort the channels with the least weight + * @mac_ctx: pointer to max context + * @sap_ctx: Pointer to the struct sap_context *structure + * @ch_info_params: Pointer to the tSapChSelSpectInfo structure + * Function to sort the channels with the least weight first for HT80 channels + * + * Return: QDF STATUS + */ +static QDF_STATUS +sap_sort_chl_weight_80_mhz(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *ch_info_params) +{ + uint8_t i, j; + struct sap_ch_info *chan_info; + uint8_t minIdx; + struct ch_params acs_ch_params = {0}; + int8_t center_freq_diff; + uint32_t combined_weight; + uint32_t min_ch_weight; + uint32_t valid_chans = 0; + bool has_valid; + + chan_info = ch_info_params->ch_info; + + for (j = 0; j < ch_info_params->num_ch; j++) { + + if (chan_info[j].weight_calc_done) + continue; + + acs_ch_params.ch_width = CH_WIDTH_80MHZ; + sap_acs_set_puncture_support(sap_ctx, &acs_ch_params); + + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + chan_info[j].chan_freq, + 0, &acs_ch_params, + REG_CURRENT_PWR_MODE); + + /* Check if the freq supports 80 Mhz */ + if (acs_ch_params.ch_width != CH_WIDTH_80MHZ) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 4; + chan_info[j].weight_calc_done = true; + continue; + } + + center_freq_diff = acs_ch_params.mhz_freq_seg0 - + chan_info[j].chan_freq; + + /* This channel frequency does not have all channels */ + if (center_freq_diff != 30) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 4; + chan_info[j].weight_calc_done = true; + continue; + } + + /* no other freq left for 80 Mhz operation in spectrum */ + if (j + 3 > ch_info_params->num_ch) + continue; + + /* Check whether all frequencies are present for 80 Mhz */ + + if (!(((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) && + ((chan_info[j].chan_freq + 40) == + chan_info[j + 2].chan_freq) && + ((chan_info[j].chan_freq + 60) == + chan_info[j + 3].chan_freq))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same HT80 width + */ + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 4; + chan_info[j].weight_calc_done = true; + if ((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) { + chan_info[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 4; + chan_info[j + 1].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 40) == + chan_info[j + 2].chan_freq) { + chan_info[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 4; + chan_info[j + 2].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 60) == + chan_info[j + 3].chan_freq) { + chan_info[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 4; + chan_info[j + 3].weight_calc_done = true; + } + + continue; + } + + /* We have 4 channels to calculate cumulative weight */ + + combined_weight = chan_info[j].weight + + chan_info[j + 1].weight + + chan_info[j + 2].weight + + chan_info[j + 3].weight; + + min_ch_weight = chan_info[j].weight; + minIdx = 0; + has_valid = false; + + for (i = 0; i < 4; i++) { + if (min_ch_weight > chan_info[j + i].weight) { + min_ch_weight = chan_info[j + i].weight; + minIdx = i; + } + chan_info[j + i].weight = SAP_ACS_WEIGHT_MAX * 4; + chan_info[j + i].weight_calc_done = true; + if (chan_info[j + i].valid) + has_valid = true; + } + sap_override_6ghz_psc_minidx(mac_ctx, &chan_info[j], 4, + &minIdx); + + chan_info[j + minIdx].weight = combined_weight; + if (has_valid) + valid_chans++; + + sap_debug("best freq = %d for 80mhz center freq %d combined weight = %d valid %d cnt %d", + chan_info[j + minIdx].chan_freq, + acs_ch_params.mhz_freq_seg0, + combined_weight, has_valid, valid_chans); + } + + if (!valid_chans) { + sap_debug("no valid chan bonding with CH_WIDTH_80MHZ"); + return QDF_STATUS_E_INVAL; + } + + sap_sort_chl_weight(ch_info_params); + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_sort_chl_weight_160_mhz() - to sort the channels with the least weight + * @mac_ctx: pointer to max context + * @sap_ctx: Pointer to the struct sap_context *structure + * @ch_info_params: Pointer to the tSapChSelSpectInfo structure + * + * Function to sort the channels with the least weight first for VHT160 channels + * + * Return: QDF STATUS + */ +static QDF_STATUS +sap_sort_chl_weight_160_mhz(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *ch_info_params) +{ + uint8_t i, j; + struct sap_ch_info *chan_info; + uint8_t minIdx; + struct ch_params acs_ch_params = {0}; + int8_t center_freq_diff; + uint32_t combined_weight; + uint32_t min_ch_weight; + uint32_t valid_chans = 0; + bool has_valid; + + chan_info = ch_info_params->ch_info; + + for (j = 0; j < ch_info_params->num_ch; j++) { + + if (chan_info[j].weight_calc_done) + continue; + + acs_ch_params.ch_width = CH_WIDTH_160MHZ; + sap_acs_set_puncture_support(sap_ctx, &acs_ch_params); + + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + chan_info[j].chan_freq, + 0, &acs_ch_params, + REG_CURRENT_PWR_MODE); + + /* Check if the freq supports 160 Mhz */ + if (acs_ch_params.ch_width != CH_WIDTH_160MHZ) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 8; + chan_info[j].weight_calc_done = true; + continue; + } + + center_freq_diff = acs_ch_params.mhz_freq_seg1 - + chan_info[j].chan_freq; + + /* This channel frequency does not have all channels */ + if (center_freq_diff != 70) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 8; + chan_info[j].weight_calc_done = true; + continue; + } + + /* no other freq left for 160 Mhz operation in spectrum */ + if (j + 7 > ch_info_params->num_ch) + continue; + + /* Check whether all frequencies are present for 160 Mhz */ + + if (!(((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) && + ((chan_info[j].chan_freq + 40) == + chan_info[j + 2].chan_freq) && + ((chan_info[j].chan_freq + 60) == + chan_info[j + 3].chan_freq) && + ((chan_info[j].chan_freq + 80) == + chan_info[j + 4].chan_freq) && + ((chan_info[j].chan_freq + 100) == + chan_info[j + 5].chan_freq) && + ((chan_info[j].chan_freq + 120) == + chan_info[j + 6].chan_freq) && + ((chan_info[j].chan_freq + 140) == + chan_info[j + 7].chan_freq))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same VHT160 width + */ + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 8; + chan_info[j].weight_calc_done = true; + if ((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) { + chan_info[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 1].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 40) == + chan_info[j + 2].chan_freq) { + chan_info[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 2].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 60) == + chan_info[j + 3].chan_freq) { + chan_info[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 3].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 80) == + chan_info[j + 4].chan_freq) { + chan_info[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 4].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 100) == + chan_info[j + 5].chan_freq) { + chan_info[j + 5].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 5].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 120) == + chan_info[j + 6].chan_freq) { + chan_info[j + 6].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 6].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 140) == + chan_info[j + 7].chan_freq) { + chan_info[j + 7].weight = + SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + 7].weight_calc_done = true; + } + + continue; + } + + /* We have 8 channels to calculate cumulative weight */ + + combined_weight = chan_info[j].weight + + chan_info[j + 1].weight + + chan_info[j + 2].weight + + chan_info[j + 3].weight + + chan_info[j + 4].weight + + chan_info[j + 5].weight + + chan_info[j + 6].weight + + chan_info[j + 7].weight; + + min_ch_weight = chan_info[j].weight; + minIdx = 0; + has_valid = false; + + for (i = 0; i < 8; i++) { + if (min_ch_weight > chan_info[j + i].weight) { + min_ch_weight = chan_info[j + i].weight; + minIdx = i; + } + chan_info[j + i].weight = SAP_ACS_WEIGHT_MAX * 8; + chan_info[j + i].weight_calc_done = true; + if (chan_info[j + i].valid) + has_valid = true; + } + sap_override_6ghz_psc_minidx(mac_ctx, &chan_info[j], 8, + &minIdx); + + chan_info[j + minIdx].weight = combined_weight; + if (has_valid) + valid_chans++; + + sap_debug("best freq = %d for 160mhz center freq %d combined weight = %d valid %d cnt %d", + chan_info[j + minIdx].chan_freq, + acs_ch_params.mhz_freq_seg1, + combined_weight, has_valid, valid_chans); + } + + if (!valid_chans) { + sap_debug("no valid chan bonding with CH_WIDTH_160MHZ"); + return QDF_STATUS_E_INVAL; + } + + sap_sort_chl_weight(ch_info_params); + + return QDF_STATUS_SUCCESS; +} + +#if defined(WLAN_FEATURE_11BE) +/** + * sap_sort_chl_weight_320_mhz() - to sort the channels with the least weight + * @mac_ctx: pointer to max context + * @sap_ctx: Pointer to the struct sap_context *structure + * @ch_info_params: Pointer to the tSapChSelSpectInfo structure + * + * Function to sort the channels with the least weight first for 320MHz channels + * + * Return: QDF STATUS + */ +static QDF_STATUS +sap_sort_chl_weight_320_mhz(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *ch_info_params) +{ + uint8_t i, j; + struct sap_ch_info *chan_info; + uint8_t minIdx; + struct ch_params acs_ch_params = {0}; + uint32_t combined_weight; + uint32_t min_ch_weight; + uint32_t valid_chans = 0; + bool has_valid; + + chan_info = ch_info_params->ch_info; + + for (j = 0; j < ch_info_params->num_ch; j++) { + if (chan_info[j].weight_calc_done) + continue; + + qdf_mem_zero(&acs_ch_params, sizeof(acs_ch_params)); + acs_ch_params.ch_width = CH_WIDTH_320MHZ; + sap_acs_set_puncture_support(sap_ctx, &acs_ch_params); + + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + chan_info[j].chan_freq, + 0, &acs_ch_params, + REG_CURRENT_PWR_MODE); + + /* Check if the freq supports 320 Mhz */ + if (acs_ch_params.ch_width != CH_WIDTH_320MHZ) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 16; + chan_info[j].weight_calc_done = true; + continue; + } + + /* no other freq left for 320 Mhz operation in spectrum */ + if (j + 15 > ch_info_params->num_ch) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 16; + chan_info[j].weight_calc_done = true; + continue; + } + + /* Check whether all frequencies are present for 160 Mhz */ + + if (!(((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) && + ((chan_info[j].chan_freq + 40) == + chan_info[j + 2].chan_freq) && + ((chan_info[j].chan_freq + 60) == + chan_info[j + 3].chan_freq) && + ((chan_info[j].chan_freq + 80) == + chan_info[j + 4].chan_freq) && + ((chan_info[j].chan_freq + 100) == + chan_info[j + 5].chan_freq) && + ((chan_info[j].chan_freq + 120) == + chan_info[j + 6].chan_freq) && + ((chan_info[j].chan_freq + 140) == + chan_info[j + 7].chan_freq) && + ((chan_info[j].chan_freq + 160) == + chan_info[j + 8].chan_freq) && + ((chan_info[j].chan_freq + 180) == + chan_info[j + 9].chan_freq) && + ((chan_info[j].chan_freq + 200) == + chan_info[j + 10].chan_freq) && + ((chan_info[j].chan_freq + 220) == + chan_info[j + 11].chan_freq) && + ((chan_info[j].chan_freq + 240) == + chan_info[j + 12].chan_freq) && + ((chan_info[j].chan_freq + 260) == + chan_info[j + 13].chan_freq) && + ((chan_info[j].chan_freq + 280) == + chan_info[j + 14].chan_freq) && + ((chan_info[j].chan_freq + 300) == + chan_info[j + 15].chan_freq))) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same ETH320 width + */ + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 16; + chan_info[j].weight_calc_done = true; + if ((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) { + chan_info[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 1].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 40) == + chan_info[j + 2].chan_freq) { + chan_info[j + 2].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 2].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 60) == + chan_info[j + 3].chan_freq) { + chan_info[j + 3].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 3].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 80) == + chan_info[j + 4].chan_freq) { + chan_info[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 4].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 100) == + chan_info[j + 5].chan_freq) { + chan_info[j + 5].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 5].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 120) == + chan_info[j + 6].chan_freq) { + chan_info[j + 6].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 6].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 140) == + chan_info[j + 7].chan_freq) { + chan_info[j + 7].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 7].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 160) == + chan_info[j + 8].chan_freq) { + chan_info[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 8].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 180) == + chan_info[j + 9].chan_freq) { + chan_info[j + 9].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 9].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 200) == + chan_info[j + 10].chan_freq) { + chan_info[j + 10].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 10].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 220) == + chan_info[j + 11].chan_freq) { + chan_info[j + 11].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 11].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 240) == + chan_info[j + 12].chan_freq) { + chan_info[j + 12].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 12].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 260) == + chan_info[j + 13].chan_freq) { + chan_info[j + 13].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 13].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 280) == + chan_info[j + 14].chan_freq) { + chan_info[j + 14].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 14].weight_calc_done = true; + } + if ((chan_info[j].chan_freq + 300) == + chan_info[j + 15].chan_freq) { + chan_info[j + 15].weight = + SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + 15].weight_calc_done = true; + } + + continue; + } + + /* We have 16 channels to calculate cumulative weight */ + combined_weight = chan_info[j].weight + + chan_info[j + 1].weight + + chan_info[j + 2].weight + + chan_info[j + 3].weight + + chan_info[j + 4].weight + + chan_info[j + 5].weight + + chan_info[j + 6].weight + + chan_info[j + 7].weight + + chan_info[j + 8].weight + + chan_info[j + 9].weight + + chan_info[j + 10].weight + + chan_info[j + 11].weight + + chan_info[j + 12].weight + + chan_info[j + 13].weight + + chan_info[j + 14].weight + + chan_info[j + 15].weight; + + min_ch_weight = chan_info[j].weight; + minIdx = 0; + has_valid = false; + for (i = 0; i < 16; i++) { + if (min_ch_weight > chan_info[j + i].weight) { + min_ch_weight = chan_info[j + i].weight; + minIdx = i; + } + chan_info[j + i].weight = SAP_ACS_WEIGHT_MAX * 16; + chan_info[j + i].weight_calc_done = true; + if (chan_info[j + i].valid) + has_valid = true; + } + sap_override_6ghz_psc_minidx(mac_ctx, &chan_info[j], 16, + &minIdx); + + chan_info[j + minIdx].weight = combined_weight; + if (has_valid) + valid_chans++; + + sap_debug("best freq = %d for 320mhz center freq %d combined weight = %d valid %d cnt %d", + chan_info[j + minIdx].chan_freq, + acs_ch_params.mhz_freq_seg1, + combined_weight, + has_valid, valid_chans); + } + + if (!valid_chans) { + sap_debug("no valid chan bonding with CH_WIDTH_320MHZ"); + return QDF_STATUS_E_INVAL; + } + + sap_sort_chl_weight(ch_info_params); + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * sap_allocate_max_weight_40_mhz_24_g() - allocate max weight for 40Mhz + * to all 2.4Ghz channels + * @spect_info_params: Pointer to the tSapChSelSpectInfo structure + * + * Return: none + */ +static void +sap_allocate_max_weight_40_mhz_24_g(struct sap_sel_ch_info *spect_info_params) +{ + struct sap_ch_info *spect_info; + uint8_t j; + + /* + * Assign max weight for 40Mhz (SAP_ACS_WEIGHT_MAX * 2) to all + * 2.4 Ghz channels + */ + spect_info = spect_info_params->ch_info; + for (j = 0; j < spect_info_params->num_ch; j++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(spect_info[j].chan_freq)) + spect_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } +} + +/** + * sap_allocate_max_weight_40_mhz() - allocate max weight for 40Mhz + * to all 5Ghz channels + * @spect_info_params: Pointer to the tSapChSelSpectInfo structure + * + * Return: none + */ +static void +sap_allocate_max_weight_40_mhz(struct sap_sel_ch_info *spect_info_params) +{ + struct sap_ch_info *spect_info; + uint8_t j; + + /* + * Assign max weight for 40Mhz (SAP_ACS_WEIGHT_MAX * 2) to all + * 5 Ghz channels + */ + spect_info = spect_info_params->ch_info; + for (j = 0; j < spect_info_params->num_ch; j++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(spect_info[j].chan_freq) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(spect_info[j].chan_freq)) + spect_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } +} + +/** + * sap_sort_chl_weight_ht40_24_g() - To sort channel with the least weight + * @mac_ctx: Pointer to mac_ctx + * @ch_info_params: Pointer to the sap_sel_ch_info structure + * @domain: Regulatory domain + * + * Function to sort the channels with the least weight first for HT40 channels + * + * Return: none + */ +static void sap_sort_chl_weight_ht40_24_g( + struct mac_context *mac_ctx, + struct sap_sel_ch_info *ch_info_params, + v_REGDOMAIN_t domain) +{ + uint8_t i, j; + struct sap_ch_info *chan_info; + uint32_t tmp_weight1, tmp_weight2; + uint32_t ht40plus2gendch = 0; + uint32_t channel; + uint32_t chan_freq; + + chan_info = ch_info_params->ch_info; + /* + * for each HT40 channel, calculate the combined weight of the + * two 20MHz weight + */ + for (i = 0; i < ARRAY_SIZE(acs_ht40_channels24_g); i++) { + for (j = 0; j < ch_info_params->num_ch; j++) { + channel = wlan_reg_freq_to_chan(mac_ctx->pdev, + chan_info[j].chan_freq); + if (channel == acs_ht40_channels24_g[i].chStartNum) + break; + } + if (j == ch_info_params->num_ch) + continue; + + if (!((chan_info[j].chan_freq + 20) == + chan_info[j + 4].chan_freq)) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + continue; + } + /* + * check if there is another channel combination possibility + * e.g., {1, 5} & {5, 9} + */ + if ((chan_info[j + 4].chan_freq + 20) == + chan_info[j + 8].chan_freq) { + /* need to compare two channel pairs */ + tmp_weight1 = chan_info[j].weight + + chan_info[j + 4].weight; + tmp_weight2 = chan_info[j + 4].weight + + chan_info[j + 8].weight; + if (tmp_weight1 <= tmp_weight2) { + if (chan_info[j].weight <= + chan_info[j + 4].weight) { + chan_info[j].weight = + tmp_weight1; + chan_info[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + chan_info[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + chan_info[j + 4].weight = + tmp_weight1; + /* for secondary channel selection */ + chan_info[j].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + chan_info[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } else { + if (chan_info[j + 4].weight <= + chan_info[j + 8].weight) { + chan_info[j + 4].weight = + tmp_weight2; + chan_info[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + /* for secondary channel selection */ + chan_info[j + 8].weight = + SAP_ACS_WEIGHT_MAX * 2 + - 1; + } else { + chan_info[j + 8].weight = + tmp_weight2; + chan_info[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + chan_info[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } else { + tmp_weight1 = chan_info[j].weight_copy + + chan_info[j + 4].weight_copy; + if (chan_info[j].weight_copy <= + chan_info[j + 4].weight_copy) { + chan_info[j].weight = tmp_weight1; + chan_info[j + 4].weight = + SAP_ACS_WEIGHT_MAX * 2; + } else { + chan_info[j + 4].weight = tmp_weight1; + chan_info[j].weight = + SAP_ACS_WEIGHT_MAX * 2; + } + } + } + /* + * Every channel should be checked. Add the check for the omissive + * channel. Mark the channel whose combination can't satisfy 40MHZ + * as max value, so that it will be sorted to the bottom. + */ + if (REGDOMAIN_FCC == domain) + ht40plus2gendch = HT40PLUS_2G_FCC_CH_END; + else + ht40plus2gendch = HT40PLUS_2G_EURJAP_CH_END; + for (i = HT40MINUS_2G_CH_START; i <= ht40plus2gendch; i++) { + chan_freq = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, i); + for (j = 0; j < ch_info_params->num_ch; j++) { + if (chan_info[j].chan_freq == chan_freq && + ((chan_info[j].chan_freq + 20) != + chan_info[j + 4].chan_freq) && + ((chan_info[j].chan_freq - 20) != + chan_info[j - 4].chan_freq)) + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + } + for (i = ht40plus2gendch + 1; i <= HT40MINUS_2G_CH_END; i++) { + chan_freq = wlan_reg_legacy_chan_to_freq(mac_ctx->pdev, i); + for (j = 0; j < ch_info_params->num_ch; j++) { + if (chan_info[j].chan_freq == chan_freq && + (chan_info[j].chan_freq - 20) != + chan_info[j - 4].chan_freq) + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + } + } + + chan_info = ch_info_params->ch_info; + for (j = 0; j < (ch_info_params->num_ch); j++) { + QDF_TRACE(QDF_MODULE_ID_SAP, QDF_TRACE_LEVEL_TRACE, + "%s: freq = %d weight = %d rssi = %d bss count = %d", + __func__, chan_info->chan_freq, chan_info->weight, + chan_info->rssi_agr, chan_info->bss_count); + + chan_info++; + } + + sap_sort_chl_weight(ch_info_params); +} + +/** + * sap_sort_chl_weight_40_mhz() - To sort 5 GHz channel in 40 MHz bandwidth + * @mac_ctx: mac context handle + * @sap_ctx: pointer to SAP context + * @ch_info_params: pointer to the tSapChSelSpectInfo structure + * + * Return: QDF STATUS + */ +static QDF_STATUS +sap_sort_chl_weight_40_mhz(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *ch_info_params) +{ + uint8_t i, j; + struct sap_ch_info *chan_info; + uint8_t minIdx; + struct ch_params acs_ch_params = {0}; + int8_t center_freq_diff; + uint32_t combined_weight; + uint32_t min_ch_weight; + uint32_t valid_chans = 0; + bool has_valid; + + chan_info = ch_info_params->ch_info; + + for (j = 0; j < ch_info_params->num_ch; j++) { + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_info[j].chan_freq)) + continue; + + if (chan_info[j].weight_calc_done) + continue; + + acs_ch_params.ch_width = CH_WIDTH_40MHZ; + + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + chan_info[j].chan_freq, + 0, &acs_ch_params, + REG_CURRENT_PWR_MODE); + + /* Check if the freq supports 40 Mhz */ + if (acs_ch_params.ch_width != CH_WIDTH_40MHZ) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + chan_info[j].weight_calc_done = true; + continue; + } + + center_freq_diff = acs_ch_params.mhz_freq_seg0 - + chan_info[j].chan_freq; + + /* This channel frequency does not have all channels */ + if (center_freq_diff != 10) { + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + chan_info[j].weight_calc_done = true; + continue; + } + + /* no other freq left for 40 Mhz operation in spectrum */ + if (j + 1 > ch_info_params->num_ch) + continue; + + /* Check whether all frequencies are present for 40 Mhz */ + + if (!((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq)) { + /* + * some channels does not exist in pSectInfo array, + * skip this channel and those in the same 40 width + */ + chan_info[j].weight = SAP_ACS_WEIGHT_MAX * 2; + chan_info[j].weight_calc_done = true; + + if ((chan_info[j].chan_freq + 20) == + chan_info[j + 1].chan_freq) { + chan_info[j + 1].weight = + SAP_ACS_WEIGHT_MAX * 2; + chan_info[j + 1].weight_calc_done = true; + } + + continue; + } + + /* We have 2 channels to calculate cumulative weight */ + + combined_weight = chan_info[j].weight + + chan_info[j + 1].weight; + + min_ch_weight = chan_info[j].weight; + minIdx = 0; + has_valid = false; + + for (i = 0; i < 2; i++) { + if (min_ch_weight > chan_info[j + i].weight) { + min_ch_weight = chan_info[j + i].weight; + minIdx = i; + } + chan_info[j + i].weight = SAP_ACS_WEIGHT_MAX * 2; + chan_info[j + i].weight_calc_done = true; + if (chan_info[j + i].valid) + has_valid = true; + } + sap_override_6ghz_psc_minidx(mac_ctx, &chan_info[j], 2, + &minIdx); + + chan_info[j + minIdx].weight = combined_weight; + if (has_valid) + valid_chans++; + + sap_debug("best freq = %d for 40mhz center freq %d combined weight = %d valid %d cnt %d", + chan_info[j + minIdx].chan_freq, + acs_ch_params.mhz_freq_seg0, + combined_weight, has_valid, valid_chans); + } + + if (!valid_chans) { + sap_debug("no valid chan bonding with CH_WIDTH_40MHZ"); + return QDF_STATUS_E_INVAL; + } + + sap_sort_chl_weight(ch_info_params); + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_restore_chan_weight() - Restore every channel weight to original + * @spect_info: pointer to the tSapChSelSpectInfo structure + * + * Return: None + */ +static void sap_restore_chan_weight(struct sap_sel_ch_info *spect_info) +{ + uint32_t i; + struct sap_ch_info *spect_ch = spect_info->ch_info; + + for (i = 0; i < spect_info->num_ch; i++) { + spect_ch->weight = spect_ch->weight_copy; + spect_ch->weight_calc_done = false; + spect_ch++; + } +} + +/** + * sap_sort_chl_weight_all() - Function to sort the channels with the least + * weight first + * @mac_ctx: Pointer to mac_ctx structure + * @sap_ctx: Pointer to sap_context structure + * @ch_info_params: Pointer to the sap_sel_ch_info structure + * @operating_band: Operating Band + * @domain: Regulatory domain + * @bw: Bandwidth + * + * Return: NULL + */ +static void sap_sort_chl_weight_all(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *ch_info_params, + uint32_t operating_band, + v_REGDOMAIN_t domain, + enum phy_ch_width *bw) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum phy_ch_width ch_width = *bw; + +next_bw: + switch (ch_width) { + case CH_WIDTH_40MHZ: + /* + * Assign max weight to all 5Ghz channels when operating band + * is 11g and to all 2.4Ghz channels when operating band is 11a + * or 11abg to avoid selection in ACS algorithm for starting SAP + */ + if (eCSR_DOT11_MODE_11g == operating_band) { + sap_allocate_max_weight_40_mhz(ch_info_params); + sap_sort_chl_weight_ht40_24_g( + mac_ctx, + ch_info_params, + domain); + } else { + sap_allocate_max_weight_40_mhz_24_g(ch_info_params); + status = sap_sort_chl_weight_40_mhz(mac_ctx, + sap_ctx, + ch_info_params); + } + break; + case CH_WIDTH_80MHZ: + case CH_WIDTH_80P80MHZ: + status = sap_sort_chl_weight_80_mhz(mac_ctx, + sap_ctx, + ch_info_params); + break; + case CH_WIDTH_160MHZ: + status = sap_sort_chl_weight_160_mhz(mac_ctx, + sap_ctx, + ch_info_params); + break; +#if defined(WLAN_FEATURE_11BE) + case CH_WIDTH_320MHZ: + status = sap_sort_chl_weight_320_mhz(mac_ctx, + sap_ctx, + ch_info_params); + break; +#endif + case CH_WIDTH_20MHZ: + default: + /* Sorting the channels as per weights as 20MHz channels */ + sap_sort_chl_weight(ch_info_params); + status = QDF_STATUS_SUCCESS; + } + + if (status != QDF_STATUS_SUCCESS) { + ch_width = wlan_reg_get_next_lower_bandwidth(ch_width); + sap_restore_chan_weight(ch_info_params); + goto next_bw; + } + + if (ch_width != *bw) { + sap_info("channel width change from %d to %d", *bw, ch_width); + *bw = ch_width; + } +} + +/** + * sap_is_ch_non_overlap() - returns true if non-overlapping channel + * @sap_ctx: Sap context + * @ch: channel number + * + * Returns: true if non-overlapping (1, 6, 11) channel, false otherwise + */ +static bool sap_is_ch_non_overlap(struct sap_context *sap_ctx, uint16_t ch) +{ + if (sap_ctx->enableOverLapCh) + return true; + + if ((ch == CHANNEL_1) || (ch == CHANNEL_6) || (ch == CHANNEL_11)) + return true; + + return false; +} + +static enum phy_ch_width +sap_acs_next_lower_bandwidth(enum phy_ch_width ch_width) +{ + if (ch_width <= CH_WIDTH_20MHZ || + ch_width == CH_WIDTH_5MHZ || + ch_width == CH_WIDTH_10MHZ || + ch_width >= CH_WIDTH_INVALID) + return CH_WIDTH_INVALID; + + return wlan_reg_get_next_lower_bandwidth(ch_width); +} + +void sap_sort_channel_list(struct mac_context *mac_ctx, uint8_t vdev_id, + qdf_list_t *ch_list, struct sap_sel_ch_info *ch_info, + v_REGDOMAIN_t *domain, uint32_t *operating_band) +{ + uint8_t country[CDS_COUNTRY_CODE_LEN + 1]; + struct sap_context *sap_ctx; + enum phy_ch_width cur_bw; + v_REGDOMAIN_t reg_domain; + uint32_t op_band; + + sap_ctx = mac_ctx->sap.sapCtxList[vdev_id].sap_context; + cur_bw = sap_ctx->acs_cfg->ch_width; + + /* Initialize the structure pointed by spect_info */ + if (!sap_chan_sel_init(mac_ctx, ch_info, sap_ctx, false)) { + sap_err("vdev %d ch select initialization failed", vdev_id); + return; + } + + /* Compute the weight of the entire spectrum in the operating band */ + sap_compute_spect_weight(ch_info, mac_ctx, ch_list, sap_ctx); + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* process avoid channel IE to collect all channels to avoid */ + sap_process_avoid_ie(mac_ctx, sap_ctx, ch_list, ch_info); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + wlan_reg_read_current_country(mac_ctx->psoc, country); + wlan_reg_get_domain_from_country_code(®_domain, country, + SOURCE_DRIVER); + + SET_ACS_BAND(op_band, sap_ctx); + + /* Sort the ch lst as per the computed weights, lesser weight first. */ + sap_sort_chl_weight_all(mac_ctx, sap_ctx, ch_info, op_band, + reg_domain, &cur_bw); + sap_ctx->acs_cfg->ch_width = cur_bw; + + if (domain) + *domain = reg_domain; + if (operating_band) + *operating_band = op_band; +} + +uint32_t sap_select_channel(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + qdf_list_t *scan_list) +{ + /* DFS param object holding all the data req by the algo */ + struct sap_sel_ch_info spect_info_obj = { NULL, 0 }; + struct sap_sel_ch_info *spect_info = &spect_info_obj; + uint8_t best_ch_num = SAP_CHANNEL_NOT_SELECTED; + uint32_t best_ch_weight = SAP_ACS_WEIGHT_MAX; + uint32_t ht40plus2gendch = 0; + v_REGDOMAIN_t domain; + uint8_t count; + uint32_t operating_band = 0; + struct mac_context *mac_ctx; + uint32_t best_chan_freq = 0; + + mac_ctx = MAC_CONTEXT(mac_handle); + + sap_sort_channel_list(mac_ctx, sap_ctx->vdev_id, scan_list, + spect_info, &domain, &operating_band); + + /*Loop till get the best channel in the given range */ + for (count = 0; count < spect_info->num_ch; count++) { + if (!spect_info->ch_info[count].valid) + continue; + + best_chan_freq = spect_info->ch_info[count].chan_freq; + /* check if best_ch_num is in preferred channel list */ + best_chan_freq = + sap_select_preferred_channel_from_channel_list( + best_chan_freq, sap_ctx, spect_info); + /* if not in preferred ch lst, go to nxt best ch */ + if (best_chan_freq == SAP_CHANNEL_NOT_SELECTED) + continue; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* + * Weight of the channels(device's AP is operating) + * increased to MAX+1 so that they will be chosen only + * when there is no other best channel to choose + */ + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(best_chan_freq) && + sap_check_in_avoid_ch_list(sap_ctx, + wlan_reg_freq_to_chan(mac_ctx->pdev, best_chan_freq))) { + best_chan_freq = SAP_CHANNEL_NOT_SELECTED; + continue; + } +#endif + + /* Give preference to Non-overlap channels */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(best_chan_freq) && + !sap_is_ch_non_overlap(sap_ctx, + wlan_reg_freq_to_chan(mac_ctx->pdev, best_chan_freq))) { + sap_debug("freq %d is overlapping, skipped", + best_chan_freq); + continue; + } + + best_ch_weight = spect_info->ch_info[count].weight; + sap_debug("Freq = %d selected as best frequency weight = %d", + best_chan_freq, best_ch_weight); + + break; + } + + /* + * in case the best channel selected is not in PCL and there is another + * channel which has same weightage and is in PCL, choose the one in + * PCL + */ + if (!ch_in_pcl(sap_ctx, best_chan_freq)) { + uint32_t cal_chan_freq, cal_chan_weight; + + enum phy_ch_width pref_bw = sap_ctx->acs_cfg->ch_width; +next_bw: + sap_debug("check bw %d", pref_bw); + for (count = 0; count < spect_info->num_ch; count++) { + struct ch_params ch_params = {0}; + + if (!spect_info->ch_info[count].valid) + continue; + + cal_chan_freq = spect_info->ch_info[count].chan_freq; + cal_chan_weight = spect_info->ch_info[count].weight; + /* skip pcl channel whose weight is bigger than best */ + if (!ch_in_pcl(sap_ctx, cal_chan_freq) || + (cal_chan_weight > best_ch_weight)) + continue; + + if (best_chan_freq == cal_chan_freq) + continue; + + if (sap_select_preferred_channel_from_channel_list( + cal_chan_freq, sap_ctx, + spect_info) + == SAP_CHANNEL_NOT_SELECTED) + continue; + ch_params.ch_width = pref_bw; + sap_acs_set_puncture_support(sap_ctx, &ch_params); + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, cal_chan_freq, 0, &ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params.ch_width != pref_bw) + continue; + best_chan_freq = cal_chan_freq; + sap_ctx->acs_cfg->ch_width = pref_bw; + sap_debug("Changed best freq to %d Preferred freq bw %d", + best_chan_freq, pref_bw); + break; + } + if (count == spect_info->num_ch) { + pref_bw = sap_acs_next_lower_bandwidth(pref_bw); + if (pref_bw != CH_WIDTH_INVALID) + goto next_bw; + } + } + + sap_ctx->acs_cfg->pri_ch_freq = best_chan_freq; + + /* Below code is for 2.4Ghz freq, so freq to channel is safe here */ + + /* determine secondary channel for 2.4G channel 5, 6, 7 in HT40 */ + if ((operating_band != eCSR_DOT11_MODE_11g) || + (sap_ctx->acs_cfg->ch_width != CH_WIDTH_40MHZ)) + goto sap_ch_sel_end; + + best_ch_num = wlan_reg_freq_to_chan(mac_ctx->pdev, best_chan_freq); + + if (REGDOMAIN_FCC == domain) + ht40plus2gendch = HT40PLUS_2G_FCC_CH_END; + else + ht40plus2gendch = HT40PLUS_2G_EURJAP_CH_END; + if ((best_ch_num >= HT40MINUS_2G_CH_START) && + (best_ch_num <= ht40plus2gendch)) { + int weight_below, weight_above, i; + struct sap_ch_info *pspect_info; + + weight_below = weight_above = SAP_ACS_WEIGHT_MAX; + pspect_info = spect_info->ch_info; + for (i = 0; i < spect_info->num_ch; i++) { + if (pspect_info[i].chan_freq == (best_chan_freq - 20)) + weight_below = pspect_info[i].weight; + if (pspect_info[i].chan_freq == (best_ch_num + 20)) + weight_above = pspect_info[i].weight; + } + + if (weight_below < weight_above) + sap_ctx->acs_cfg->ht_sec_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq - 20; + else + sap_ctx->acs_cfg->ht_sec_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq + 20; + } else if (best_ch_num >= 1 && best_ch_num <= 4) { + sap_ctx->acs_cfg->ht_sec_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq + 20; + } else if (best_ch_num >= ht40plus2gendch && best_ch_num <= + HT40MINUS_2G_CH_END) { + sap_ctx->acs_cfg->ht_sec_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq - 20; + } else if (best_ch_num == 14) { + sap_ctx->acs_cfg->ht_sec_ch_freq = 0; + } + sap_ctx->sec_ch_freq = sap_ctx->acs_cfg->ht_sec_ch_freq; + +sap_ch_sel_end: + /* Free all the allocated memory */ + sap_chan_sel_exit(spect_info); + + return best_chan_freq; +} + +#ifdef CONFIG_AFC_SUPPORT +/** + * sap_max_weight_invalidate_2ghz_channels() - Invalidate 2 GHz channel and set + * max channel weight + * @spect_info: pointer to array of channel spectrum info + * + * Return: None + */ +static void +sap_max_weight_invalidate_2ghz_channels(struct sap_sel_ch_info *spect_info) +{ + uint32_t i; + struct sap_ch_info *spect_ch; + + spect_ch = spect_info->ch_info; + for (i = 0; i < spect_info->num_ch; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(spect_ch[i].chan_freq)) { + spect_ch[i].weight = SAP_ACS_WEIGHT_MAX; + spect_ch[i].valid = false; + } + } +} + +/** + * sap_compute_spect_max_power_weight() - Compute channel weight use max power + * factor + * @spect_info: pointer to SAP channel select structure of spectrum info + * @mac: mac context + * @sap_ctx: pointer to SAP context + * + * Return: None + */ +static void +sap_compute_spect_max_power_weight(struct sap_sel_ch_info *spect_info, + struct mac_context *mac, + struct sap_context *sap_ctx) +{ + uint32_t i; + struct sap_ch_info *spect_ch = spect_info->ch_info; + + for (i = 0; i < spect_info->num_ch; i++) { + if (spect_ch[i].weight == SAP_ACS_WEIGHT_MAX) { + spect_ch[i].weight_copy = spect_ch[i].weight; + continue; + } + spect_ch[i].weight = SAPDFS_NORMALISE_1000 * + sap_weight_channel_reg_max_power(sap_ctx, + spect_ch[i].chan_freq); + + sap_normalize_channel_weight_with_factors(mac, &spect_ch[i]); + + if (spect_ch[i].weight > SAP_ACS_WEIGHT_MAX) + spect_ch[i].weight = SAP_ACS_WEIGHT_MAX; + spect_ch[i].weight_copy = spect_ch[i].weight; + + sap_debug("freq = %d, weight = %d", + spect_ch[i].chan_freq, spect_ch[i].weight); + } +} + +/** + * sap_afc_dcs_target_chan() - Select best channel frequency from sorted list + * @mac_ctx: pointer to mac context + * @sap_ctx: pointer to SAP context + * @spect_info: pointer to SAP channel select structure of spectrum info + * @cur_freq: SAP current home channel frequency + * @cur_bw: SAP current channel bandwidth + * @pref_bw: SAP target channel bandwidth can switch to + * + * Return: Best home channel frequency, if no available channel return 0. + */ +static qdf_freq_t +sap_afc_dcs_target_chan(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + struct sap_sel_ch_info *spect_info, + qdf_freq_t cur_freq, + enum phy_ch_width cur_bw, + enum phy_ch_width pref_bw) +{ + uint32_t i, best_weight; + qdf_freq_t best_chan_freq; + struct sap_ch_info *spect_ch = spect_info->ch_info; + + best_weight = spect_ch[0].weight; + best_chan_freq = spect_ch[0].chan_freq; + + /* + * If current channel is already best channel and no bandwidth + * change, return the current channel so no channel switch happen. + */ + if (cur_bw == pref_bw) { + for (i = 1; i < spect_info->num_ch; i++) { + if (!spect_ch[i].valid) + continue; + if (spect_ch[i].weight <= best_weight) { + sap_debug("best freq = %d, weight = %d", + spect_ch[i].chan_freq, + spect_ch[i].weight); + if (spect_ch[i].chan_freq == cur_freq) + return cur_freq; + } + } + } + + return best_chan_freq; +} + +#ifdef WLAN_FEATURE_AFC_DCS_SKIP_ACS_RANGE +/** + * is_sap_afc_dcs_skip_acs() - API to get whether to skip ACS range + * when doing automatically channel selection for AFC DCS. + * @sap_ctx: SAP context pointer + * + * Return: True if skip ACS range and can select channel out of it. + */ +static bool is_sap_afc_dcs_skip_acs(struct sap_context *sap_ctx) +{ + struct sap_acs_cfg *acs_cfg; + uint32_t i; + + if (!sap_ctx || !sap_ctx->acs_cfg) + return false; + + acs_cfg = sap_ctx->acs_cfg; + for (i = 0; i < acs_cfg->ch_list_count; i++) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(acs_cfg->freq_list[i])) + return false; + } + return true; +} +#else +static bool is_sap_afc_dcs_skip_acs(struct sap_context *sap_ctx) +{ + return false; +} +#endif + +qdf_freq_t sap_afc_dcs_sel_chan(struct sap_context *sap_ctx, + qdf_freq_t cur_freq, + enum phy_ch_width cur_bw, + enum phy_ch_width *pref_bw) +{ + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + struct sap_sel_ch_info spect_info_obj = {NULL, 0}; + struct sap_sel_ch_info *spect_info = &spect_info_obj; + qdf_freq_t target_freq; + + if (!sap_ctx || !pref_bw) + return SAP_CHANNEL_NOT_SELECTED; + + if (!sap_ctx->acs_cfg || !sap_ctx->acs_cfg->acs_mode) { + sap_debug("SAP session id %d acs not enable", + sap_ctx->sessionId); + return SAP_CHANNEL_NOT_SELECTED; + } + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) + return SAP_CHANNEL_NOT_SELECTED; + + /* + * If AFC response received after SAP started, SP channels are + * not included in current ACS range, ignore ACS range check + * in this scenario so that SAP can move to new SP channel. + */ + sap_chan_sel_init(mac_ctx, spect_info, sap_ctx, + is_sap_afc_dcs_skip_acs(sap_ctx)); + + sap_max_weight_invalidate_2ghz_channels(spect_info); + + sap_compute_spect_max_power_weight(spect_info, mac_ctx, sap_ctx); + + sap_sort_chl_weight_all(mac_ctx, sap_ctx, spect_info, + eCSR_DOT11_MODE_11a, REGDOMAIN_FCC, pref_bw); + + target_freq = sap_afc_dcs_target_chan(mac_ctx, + sap_ctx, + spect_info, + cur_freq, + cur_bw, + *pref_bw); + sap_chan_sel_exit(spect_info); + return target_freq; +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_ch_select.h b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_ch_select.h new file mode 100644 index 0000000000..e34e3c823f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_ch_select.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2012-2015, 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SAP_CH_SELECT_H) +#define __SAP_CH_SELECT_H + +/*=========================================================================== + + sapChSelect.h + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP modules + functions for channel selection. + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "ani_global.h" +/*-------------------------------------------------------------------------- + defines and enum + --------------------------------------------------------------------------*/ + +#define SAPDFS_NORMALISE_1000 (1000/9) /* Case of spec20 with channel diff = 0 */ +#define SOFTAP_MIN_RSSI (-100) +#define SOFTAP_MAX_RSSI (0) +#define SOFTAP_MIN_COUNT (0) +#define SOFTAP_MAX_COUNT (60) + +#define SOFTAP_MIN_NF (-120) +#define SOFTAP_MAX_NF (-60) +#define SOFTAP_MIN_CHNFREE (0) +#define SOFTAP_MAX_CHNFREE (1) +#define SOFTAP_MIN_TXPWR (0) +#define SOFTAP_MAX_TXPWR (63) + +#define REG_MAX_EIRP_POWER 36 +#define REG_MIN_EIRP_POWER 14 + +#define SAP_NORMALISE_ACS_WEIGHT 5 + +/* In HT40/VHT80, Effect of primary Channel RSSi on Subband1 */ +#define SAP_SUBBAND1_RSSI_EFFECT_PRIMARY (-20) +/* In VHT80, Effect of primary Channel RSSI on Subband2 */ +#define SAP_SUBBAND2_RSSI_EFFECT_PRIMARY (-30) +/* In VHT80, Effect of Primary Channel RSSI on Subband3 */ +#define SAP_SUBBAND3_RSSI_EFFECT_PRIMARY (-40) +/* In VHT80, Effect of Primary Channel RSSI on Subband4 */ +#define SAP_SUBBAND4_RSSI_EFFECT_PRIMARY (-50) +/* In VHT80, Effect of Primary Channel RSSI on Subband5 */ +#define SAP_SUBBAND5_RSSI_EFFECT_PRIMARY (-60) +/* In VHT80, Effect of Primary Channel RSSI on Subband6 */ +#define SAP_SUBBAND6_RSSI_EFFECT_PRIMARY (-70) +/* In VHT80, Effect of Primary Channel RSSI on Subband7 */ +#define SAP_SUBBAND7_RSSI_EFFECT_PRIMARY (-80) + +#define SAP_24GHZ_FIRST_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-10) /* In 2.4GHZ, Effect of Primary Channel RSSI on First Overlapping Channel */ +#define SAP_24GHZ_SEC_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-20) /* In 2.4GHZ, Effect of Primary Channel RSSI on Second Overlapping Channel */ +#define SAP_24GHZ_THIRD_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-30) /* In 2.4GHZ, Effect of Primary Channel RSSI on Third Overlapping Channel */ +#define SAP_24GHZ_FOURTH_OVERLAP_CHAN_RSSI_EFFECT_PRIMARY (-40) /* In 2.4GHZ, Effect of Primary Channel RSSI on Fourth Overlapping Channel */ + +typedef enum { + CHANNEL_1 = 1, + CHANNEL_2, + CHANNEL_3, + CHANNEL_4, + CHANNEL_5, + CHANNEL_6, + CHANNEL_7, + CHANNEL_8, + CHANNEL_9, + CHANNEL_10, + CHANNEL_11, + CHANNEL_12, + CHANNEL_13, + CHANNEL_14 +} tSapChannel; +#endif /* if !defined __SAP_CH_SELECT_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_fsm.c b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_fsm.c new file mode 100644 index 0000000000..440f49fe65 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_fsm.c @@ -0,0 +1,5081 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/*=========================================================================== + + s a p F s m . C + + OVERVIEW: + + This software unit holds the implementation of the WLAN SAP Finite + State Machine modules + + DEPENDENCIES: + + Are listed for each API below. + ===========================================================================*/ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "sap_internal.h" +#include +#include +#include +#include +/* Pick up the SME API definitions */ +#include "sme_api.h" +/* Pick up the PMC API definitions */ +#include "cds_utils.h" +#include "cds_ieee80211_common_i.h" +#include "cds_reg_service.h" +#include "qdf_util.h" +#include "wlan_policy_mgr_api.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_reg_services_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include "cfg_ucfg_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "wlan_vdev_mgr_utils_api.h" +#include "wlan_pre_cac_api.h" +#include +#include +#include "wlan_ll_sap_api.h" + +/*---------------------------------------------------------------------------- + * Preprocessor Definitions and Constants + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Type Declarations + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Global Data Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Static Variable Definitions + * -------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + * Static Function Declarations and Definitions + * -------------------------------------------------------------------------*/ +#ifdef SOFTAP_CHANNEL_RANGE +static QDF_STATUS sap_get_freq_list(struct sap_context *sap_ctx, + uint32_t **freq_list, + uint8_t *num_ch); +#endif + +/*========================================================================== + FUNCTION sapStopDfsCacTimer + + DESCRIPTION + Function to sttop the DFS CAC timer when SAP is stopped + DEPENDENCIES + NA. + + PARAMETERS + + IN + sap_ctx: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +static int sap_stop_dfs_cac_timer(struct sap_context *sap_ctx); + +/*========================================================================== + FUNCTION sapStartDfsCacTimer + + DESCRIPTION + Function to start the DFS CAC timer when SAP is started on DFS Channel + DEPENDENCIES + NA. + + PARAMETERS + + IN + sap_ctx: SAP Context + RETURN VALUE + DFS Timer start status + SIDE EFFECTS + ============================================================================*/ + +static int sap_start_dfs_cac_timer(struct sap_context *sap_ctx); + +/** sap_hdd_event_to_string() - convert hdd event to string + * @event: eSapHddEvent event type + * + * This function converts eSapHddEvent into string + * + * Return: string for the @event. + */ +static uint8_t *sap_hdd_event_to_string(eSapHddEvent event) +{ + switch (event) { + CASE_RETURN_STRING(eSAP_START_BSS_EVENT); + CASE_RETURN_STRING(eSAP_STOP_BSS_EVENT); + CASE_RETURN_STRING(eSAP_STA_ASSOC_IND); + CASE_RETURN_STRING(eSAP_STA_ASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_REASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_DISASSOC_EVENT); + CASE_RETURN_STRING(eSAP_STA_SET_KEY_EVENT); + CASE_RETURN_STRING(eSAP_STA_MIC_FAILURE_EVENT); + CASE_RETURN_STRING(eSAP_WPS_PBC_PROBE_REQ_EVENT); + CASE_RETURN_STRING(eSAP_DISCONNECT_ALL_P2P_CLIENT); + CASE_RETURN_STRING(eSAP_MAC_TRIG_STOP_BSS_EVENT); + CASE_RETURN_STRING(eSAP_UNKNOWN_STA_JOIN); + CASE_RETURN_STRING(eSAP_MAX_ASSOC_EXCEEDED); + CASE_RETURN_STRING(eSAP_CHANNEL_CHANGE_EVENT); + CASE_RETURN_STRING(eSAP_DFS_CAC_START); + CASE_RETURN_STRING(eSAP_DFS_CAC_INTERRUPTED); + CASE_RETURN_STRING(eSAP_DFS_CAC_END); + CASE_RETURN_STRING(eSAP_DFS_RADAR_DETECT); + CASE_RETURN_STRING(eSAP_DFS_NO_AVAILABLE_CHANNEL); +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + CASE_RETURN_STRING(eSAP_ACS_SCAN_SUCCESS_EVENT); +#endif + CASE_RETURN_STRING(eSAP_ACS_CHANNEL_SELECTED); + CASE_RETURN_STRING(eSAP_ECSA_CHANGE_CHAN_IND); + default: + return "eSAP_HDD_EVENT_UNKNOWN"; + } +} + +#ifdef QCA_DFS_BW_PUNCTURE +/** + * sap_is_chan_change_needed() - Check if SAP channel change needed + * @sap_ctx: sap context. + * + * Even some 20 MHz sub channel disabled for nol, if puncture pattern is valid, + * SAP still can keep current channel width and primary channel, don't need + * change channel. + * + * Return: bool, true: channel change needed + */ +static bool +sap_is_chan_change_needed(struct sap_context *sap_ctx) +{ + uint8_t ch_wd; + uint16_t pri_freq_puncture = 0; + struct ch_params *ch_params; + QDF_STATUS status; + struct mac_context *mac_ctx; + + if (!sap_phymode_is_eht(sap_ctx->phyMode)) { + sap_debug("phy mode: 0x%x", sap_ctx->phyMode); + return true; + } + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return true; + } + + ch_params = &mac_ctx->sap.SapDfsInfo.new_ch_params; + if (mac_ctx->sap.SapDfsInfo.orig_chanWidth == 0) { + ch_wd = sap_ctx->ch_width_orig; + mac_ctx->sap.SapDfsInfo.orig_chanWidth = ch_wd; + } else { + ch_wd = mac_ctx->sap.SapDfsInfo.orig_chanWidth; + } + + ch_params->ch_width = ch_wd; + + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(ch_params, true); + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + sap_ctx->chan_freq, + 0, + ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params->ch_width == sap_ctx->ch_params.ch_width) { + status = wlan_reg_extract_puncture_by_bw(ch_params->ch_width, + ch_params->reg_punc_bitmap, + sap_ctx->chan_freq, + ch_params->mhz_freq_seg1, + CH_WIDTH_20MHZ, + &pri_freq_puncture); + if (QDF_IS_STATUS_SUCCESS(status) && !pri_freq_puncture) { + sap_debug("Eht valid puncture : 0x%x, keep freq %d", + ch_params->reg_punc_bitmap, + sap_ctx->chan_freq); + mac_ctx->sap.SapDfsInfo.new_chanWidth = + ch_params->ch_width; + return false; + } + } + + return true; +} +#else +static inline bool +sap_is_chan_change_needed(struct sap_context *sap_ctx) +{ + return true; +} +#endif + +#ifdef DFS_COMPONENT_ENABLE +/** + * sap_random_channel_sel() - This function randomly pick up an available + * channel + * @sap_ctx: sap context. + * + * This function first eliminates invalid channel, then selects random channel + * using following algorithm: + * + * Return: channel frequency picked + */ +static qdf_freq_t sap_random_channel_sel(struct sap_context *sap_ctx) +{ + uint16_t chan_freq; + uint8_t ch_wd; + struct wlan_objmgr_pdev *pdev = NULL; + struct ch_params *ch_params; + uint32_t hw_mode, flag = 0; + struct mac_context *mac_ctx; + struct dfs_acs_info acs_info = {0}; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return 0; + } + + pdev = mac_ctx->pdev; + if (!pdev) { + sap_err("null pdev"); + return 0; + } + + ch_params = &mac_ctx->sap.SapDfsInfo.new_ch_params; + if (mac_ctx->sap.SapDfsInfo.orig_chanWidth == 0) { + ch_wd = sap_ctx->ch_width_orig; + mac_ctx->sap.SapDfsInfo.orig_chanWidth = ch_wd; + } else { + ch_wd = mac_ctx->sap.SapDfsInfo.orig_chanWidth; + } + + ch_params->ch_width = ch_wd; + if (sap_ctx->acs_cfg) { + acs_info.acs_mode = sap_ctx->acs_cfg->acs_mode; + acs_info.chan_freq_list = sap_ctx->acs_cfg->master_freq_list; + acs_info.num_of_channel = + sap_ctx->acs_cfg->master_ch_list_count; + } else { + acs_info.acs_mode = false; + } + + if (mac_ctx->mlme_cfg->dfs_cfg.dfs_prefer_non_dfs) + flag |= DFS_RANDOM_CH_FLAG_NO_DFS_CH; + if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_japan_w53) + flag |= DFS_RANDOM_CH_FLAG_NO_JAPAN_W53_CH; + if (mac_ctx->sap.SapDfsInfo.sap_operating_chan_preferred_location + == 1) + flag |= DFS_RANDOM_CH_FLAG_NO_UPEER_5G_CH; + else if (mac_ctx->sap.SapDfsInfo. + sap_operating_chan_preferred_location == 2) + flag |= DFS_RANDOM_CH_FLAG_NO_LOWER_5G_CH; + + /* + * Dont choose 6ghz channel currently as legacy clients won't be able to + * scan them. In future create an ini if any customer wants 6ghz freq + * to be prioritize over 5ghz/2.4ghz. + * Currently for SAP there is a high chance of 6ghz being selected as + * an op frequency as PCL will have only 5, 6ghz freq as preferred for + * standalone SAP, and 6ghz channels being high in number. + */ + flag |= DFS_RANDOM_CH_FLAG_NO_6GHZ_CH; + + if (sap_ctx->candidate_freq && + sap_ctx->chan_freq != sap_ctx->candidate_freq && + !utils_dfs_is_freq_in_nol(pdev, sap_ctx->candidate_freq)) { + chan_freq = sap_ctx->candidate_freq; + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(ch_params, true); + wlan_reg_set_channel_params_for_pwrmode(pdev, chan_freq, 0, + ch_params, + REG_CURRENT_PWR_MODE); + sap_debug("random chan select candidate freq=%d", chan_freq); + sap_ctx->candidate_freq = 0; + } else if (QDF_IS_STATUS_ERROR( + utils_dfs_get_vdev_random_channel_for_freq( + pdev, sap_ctx->vdev, flag, ch_params, + &hw_mode, &chan_freq, &acs_info))) { + /* No available channel found */ + sap_err("No available channel found!!!"); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, + (void *)eSAP_STATUS_SUCCESS); + return 0; + } + + mac_ctx->sap.SapDfsInfo.new_chanWidth = ch_params->ch_width; + sap_ctx->ch_params.ch_width = ch_params->ch_width; + sap_ctx->ch_params.sec_ch_offset = ch_params->sec_ch_offset; + sap_ctx->ch_params.center_freq_seg0 = ch_params->center_freq_seg0; + sap_ctx->ch_params.center_freq_seg1 = ch_params->center_freq_seg1; + return chan_freq; +} +#else +static uint8_t sap_random_channel_sel(struct sap_context *sap_ctx) +{ + return 0; +} +#endif + +/** + * sap_is_channel_bonding_etsi_weather_channel() - check weather chan bonding. + * @sap_ctx: sap context. + * @chan_freq: chan frequency + * @ch_params: pointer to ch_params + * + * Check if given channel and channel params are bonded to weather radar + * channel in ETSI domain. + * + * Return: True if bonded to weather channel in ETSI + */ +static bool +sap_is_channel_bonding_etsi_weather_channel(struct sap_context *sap_ctx, + qdf_freq_t chan_freq, + struct ch_params *ch_params) +{ + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(sap_ctx->vdev); + + if (IS_CH_BONDING_WITH_WEATHER_CH(wlan_reg_freq_to_chan(pdev, + chan_freq)) && + ch_params->ch_width != CH_WIDTH_20MHZ) + return true; + + return false; +} + +/* + * sap_get_bonding_channels() - get bonding channels from primary channel. + * @sap_ctx: Handle to SAP context. + * @chan_freq: Channel frequency to get bonded channels. + * @freq_list: Bonded channel frequency list + * @size: Max bonded channels + * @chanBondState: The channel bonding mode of the passed channel. + * + * Return: Number of sub channels + */ +static uint8_t sap_get_bonding_channels(struct sap_context *sap_ctx, + qdf_freq_t chan_freq, + qdf_freq_t *freq_list, uint8_t size, + ePhyChanBondState chanBondState) +{ + uint8_t num_freq; + + if (!freq_list) + return 0; + + if (size < MAX_BONDED_CHANNELS) + return 0; + + switch (chanBondState) { + case PHY_SINGLE_CHANNEL_CENTERED: + num_freq = 1; + freq_list[0] = chan_freq; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + num_freq = 2; + freq_list[0] = chan_freq - 20; + freq_list[1] = chan_freq; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + num_freq = 2; + freq_list[0] = chan_freq; + freq_list[1] = chan_freq + 20; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + num_freq = 4; + freq_list[0] = chan_freq; + freq_list[1] = chan_freq + 20; + freq_list[2] = chan_freq + 40; + freq_list[3] = chan_freq + 60; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + num_freq = 4; + freq_list[0] = chan_freq - 20; + freq_list[1] = chan_freq; + freq_list[2] = chan_freq + 20; + freq_list[3] = chan_freq + 40; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + num_freq = 4; + freq_list[0] = chan_freq - 40; + freq_list[1] = chan_freq - 20; + freq_list[2] = chan_freq; + freq_list[3] = chan_freq + 20; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + num_freq = 4; + freq_list[0] = chan_freq - 60; + freq_list[1] = chan_freq - 40; + freq_list[2] = chan_freq - 20; + freq_list[3] = chan_freq; + break; + default: + num_freq = 1; + freq_list[0] = chan_freq; + break; + } + + return num_freq; +} + +/** + * sap_ch_params_to_bonding_channels() - get bonding channels from channel param + * @ch_params: channel params ( bw, pri and sec channel info) + * @freq_list: bonded channel frequency list + * + * Return: Number of sub channel frequencies + */ +static uint8_t sap_ch_params_to_bonding_channels( + struct ch_params *ch_params, + qdf_freq_t *freq_list) +{ + qdf_freq_t center_freq = ch_params->mhz_freq_seg0; + uint8_t num_freq = 0; + + switch (ch_params->ch_width) { + case CH_WIDTH_160MHZ: + num_freq = 8; + center_freq = ch_params->mhz_freq_seg1; + freq_list[0] = center_freq - 70; + freq_list[1] = center_freq - 50; + freq_list[2] = center_freq - 30; + freq_list[3] = center_freq - 10; + freq_list[4] = center_freq + 10; + freq_list[5] = center_freq + 30; + freq_list[6] = center_freq + 50; + freq_list[7] = center_freq + 70; + break; + case CH_WIDTH_80P80MHZ: + num_freq = 8; + freq_list[0] = center_freq - 30; + freq_list[1] = center_freq - 10; + freq_list[2] = center_freq + 10; + freq_list[3] = center_freq + 30; + + center_freq = ch_params->mhz_freq_seg1; + freq_list[4] = center_freq - 30; + freq_list[5] = center_freq - 10; + freq_list[6] = center_freq + 10; + freq_list[7] = center_freq + 30; + break; + case CH_WIDTH_80MHZ: + num_freq = 4; + freq_list[0] = center_freq - 30; + freq_list[1] = center_freq - 10; + freq_list[2] = center_freq + 10; + freq_list[3] = center_freq + 30; + break; + case CH_WIDTH_40MHZ: + num_freq = 2; + freq_list[0] = center_freq - 10; + freq_list[1] = center_freq + 10; + break; + default: + num_freq = 1; + freq_list[0] = center_freq; + break; + } + + return num_freq; +} + +/** + * sap_operating_on_dfs() - check current sap operating on dfs + * @mac_ctx: mac ctx + * @sap_ctx: SAP context + * + * Return: true if any sub channel is dfs channel + */ +static +bool sap_operating_on_dfs(struct mac_context *mac_ctx, + struct sap_context *sap_ctx) +{ + struct wlan_channel *chan; + + if (!sap_ctx->vdev) { + sap_debug("vdev invalid"); + return false; + } + + chan = wlan_vdev_get_active_channel(sap_ctx->vdev); + if (!chan) { + sap_debug("Couldn't get vdev active channel"); + return false; + } + + if (chan->ch_flagext & (IEEE80211_CHAN_DFS | + IEEE80211_CHAN_DFS_CFREQ2)) + return true; + + return false; +} + +bool sap_plus_sap_cac_skip(struct mac_context *mac, + struct sap_context *sap_ctx, + qdf_freq_t chan_freq) +{ + uint8_t intf; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context = + mac->sap.sapCtxList[intf].sap_context; + + if (!sap_context || sap_context == sap_ctx) + continue; + if (mac->sap.sapCtxList[intf].sapPersona != QDF_SAP_MODE && + mac->sap.sapCtxList[intf].sapPersona != QDF_P2P_GO_MODE) + continue; + if (sap_context->isCacEndNotified && + sap_context->chan_freq == chan_freq && + sap_operating_on_dfs(mac, sap_context)) { + sap_debug("SAP vid %d CAC can skip due to CAC completed on other SAP vid %d", + sap_ctx->sessionId, sap_context->sessionId); + return true; + } + } + + return false; +} + +/** + * is_wlansap_cac_required_for_chan() - Is cac required for given channel + * @mac_ctx: mac ctx + * @sap_ctx: sap context + * @chan_freq: given channel + * @ch_params: pointer to ch_params + * + * Return: True if cac is required for given channel + */ +static bool +is_wlansap_cac_required_for_chan(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + qdf_freq_t chan_freq, + struct ch_params *ch_params) +{ + bool is_ch_dfs = false; + bool cac_required; + uint8_t vdev_id_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t freq_list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint8_t sta_cnt, i; + eSapDfsCACState_t cac_state = eSAP_DFS_DO_NOT_SKIP_CAC; + + if (ch_params->ch_width == CH_WIDTH_160MHZ) { + wlan_reg_set_create_punc_bitmap(ch_params, true); + if (wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac_ctx->pdev, + chan_freq, + ch_params, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else if (ch_params->ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + chan_freq, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + ch_params->mhz_freq_seg1, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_ch_dfs = true; + } else { + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, chan_freq)) + is_ch_dfs = true; + } + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq)) + is_ch_dfs = false; + if (is_ch_dfs && sap_plus_sap_cac_skip(mac_ctx, sap_ctx, chan_freq)) + cac_state = eSAP_DFS_SKIP_CAC; + sap_debug("vdev id %d chan %d is_ch_dfs %d pre_cac_complete %d ignore_cac %d cac_state %d", + sap_ctx->sessionId, chan_freq, is_ch_dfs, + wlan_pre_cac_complete_get(sap_ctx->vdev), + mac_ctx->sap.SapDfsInfo.ignore_cac, + cac_state); + + if (!is_ch_dfs || wlan_pre_cac_complete_get(sap_ctx->vdev) || + mac_ctx->sap.SapDfsInfo.ignore_cac || + cac_state == eSAP_DFS_SKIP_CAC) + cac_required = false; + else + cac_required = true; + + if (cac_required) { + sta_cnt = + policy_mgr_get_mode_specific_conn_info(mac_ctx->psoc, + freq_list, + vdev_id_list, + PM_STA_MODE); + + for (i = 0; i < sta_cnt; i++) { + if (chan_freq == freq_list[i]) { + sap_debug("STA vdev id %d exists, ignore CAC", + vdev_id_list[i]); + cac_required = false; + } + } + } + + return cac_required; +} + +void sap_get_cac_dur_dfs_region(struct sap_context *sap_ctx, + uint32_t *cac_duration_ms, + uint32_t *dfs_region, + qdf_freq_t chan_freq, + struct ch_params *ch_params) +{ + int i; + qdf_freq_t freq_list[MAX_BONDED_CHANNELS]; + uint8_t num_freq; + struct mac_context *mac; + bool cac_required; + + *cac_duration_ms = 0; + if (!sap_ctx) { + sap_err("null sap_ctx"); + return; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return; + } + + wlan_reg_get_dfs_region(mac->pdev, dfs_region); + cac_required = is_wlansap_cac_required_for_chan(mac, sap_ctx, + chan_freq, ch_params); + + if (!cac_required) { + sap_debug("cac is not required"); + return; + } + *cac_duration_ms = DEFAULT_CAC_TIMEOUT; + + if (*dfs_region != DFS_ETSI_REGION) { + sap_debug("sapdfs: default cac duration"); + return; + } + + if (sap_is_channel_bonding_etsi_weather_channel(sap_ctx, chan_freq, + ch_params)) { + *cac_duration_ms = ETSI_WEATHER_CH_CAC_TIMEOUT; + sap_debug("sapdfs: bonding_etsi_weather_channel"); + return; + } + + qdf_mem_zero(freq_list, sizeof(freq_list)); + num_freq = sap_ch_params_to_bonding_channels(ch_params, freq_list); + for (i = 0; i < num_freq; i++) { + if (IS_ETSI_WEATHER_FREQ(freq_list[i])) { + *cac_duration_ms = ETSI_WEATHER_CH_CAC_TIMEOUT; + sap_debug("sapdfs: ch freq=%d is etsi weather channel", + freq_list[i]); + return; + } + } + +} + +void sap_dfs_set_current_channel(void *ctx) +{ + struct sap_context *sap_ctx = ctx; + uint8_t vht_seg0 = sap_ctx->ch_params.center_freq_seg0; + uint8_t vht_seg1 = sap_ctx->ch_params.center_freq_seg1; + struct wlan_objmgr_pdev *pdev; + struct mac_context *mac_ctx; + uint32_t use_nol = 0; + int error; + bool is_dfs; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return; + } + + pdev = mac_ctx->pdev; + if (!pdev) { + sap_err("null pdev"); + return; + } + + is_dfs = wlan_mlme_check_chan_param_has_dfs(pdev, + &sap_ctx->ch_params, + sap_ctx->chan_freq); + + sap_debug("freq=%d, dfs %d seg0=%d, seg1=%d, bw %d", + sap_ctx->chan_freq, is_dfs, vht_seg0, vht_seg1, + sap_ctx->ch_params.ch_width); + + if (is_dfs) { + if (policy_mgr_concurrent_beaconing_sessions_running( + mac_ctx->psoc)) { + uint16_t con_ch_freq; + mac_handle_t handle = MAC_HANDLE(mac_ctx); + + con_ch_freq = + sme_get_beaconing_concurrent_operation_channel( + handle, sap_ctx->sessionId); + if (!con_ch_freq || + !wlan_reg_is_dfs_for_freq(pdev, + con_ch_freq)) + tgt_dfs_get_radars(pdev); + } else { + tgt_dfs_get_radars(pdev); + } + tgt_dfs_set_phyerr_filter_offload(pdev); + + if (mac_ctx->mlme_cfg->dfs_cfg.dfs_disable_channel_switch) + tgt_dfs_control(pdev, DFS_SET_USENOL, &use_nol, + sizeof(uint32_t), NULL, NULL, &error); + } +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * sap_check_in_avoid_ch_list() - checks if given channel present is channel + * avoidance list + * + * @sap_ctx: sap context. + * @channel: channel to be checked in sap_ctx's avoid ch list + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function checks if given + * channel is present in that list. + * + * Return: true, if channel was present, false othersie. + */ +bool sap_check_in_avoid_ch_list(struct sap_context *sap_ctx, uint8_t channel) +{ + uint8_t i = 0; + struct sap_avoid_channels_info *ie_info = + &sap_ctx->sap_detected_avoid_ch_ie; + for (i = 0; i < sizeof(ie_info->channels); i++) + if (ie_info->channels[i] == channel) + return true; + return false; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * sap_dfs_is_channel_in_nol_list() - given bonded channel is available + * @sap_context: Handle to SAP context. + * @channel_freq: Channel freq on which availability should be checked. + * @chan_bondState: The channel bonding mode of the passed channel. + * + * This function Checks if a given bonded channel is available or + * usable for DFS operation. + * + * Return: false if channel is available, true if channel is in NOL. + */ +bool +sap_dfs_is_channel_in_nol_list(struct sap_context *sap_context, + qdf_freq_t channel_freq, + ePhyChanBondState chan_bondState) +{ + int i; + struct mac_context *mac_ctx; + qdf_freq_t freq_list[MAX_BONDED_CHANNELS]; + uint8_t num_ch_freq; + struct wlan_objmgr_pdev *pdev = NULL; + enum channel_state ch_state; + qdf_freq_t ch_freq; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return false; + } + + pdev = mac_ctx->pdev; + if (!pdev) { + sap_err("null pdev"); + return false; + } + + sap_context->ch_params.mhz_freq_seg0 = + wlan_reg_legacy_chan_to_freq( + pdev, + sap_context->ch_params.center_freq_seg0); + sap_context->ch_params.mhz_freq_seg1 = + wlan_reg_legacy_chan_to_freq( + pdev, + sap_context->ch_params.center_freq_seg1); + + /* get the bonded channels */ + if (channel_freq == sap_context->chan_freq && + chan_bondState >= PHY_CHANNEL_BONDING_STATE_MAX) + num_ch_freq = sap_ch_params_to_bonding_channels( + &sap_context->ch_params, freq_list); + else + num_ch_freq = sap_get_bonding_channels( + sap_context, channel_freq, + freq_list, MAX_BONDED_CHANNELS, + chan_bondState); + + /* check for NOL, first on will break the loop */ + for (i = 0; i < num_ch_freq; i++) { + ch_freq = freq_list[i]; + + ch_state = + wlan_reg_get_channel_state_from_secondary_list_for_freq( + pdev, ch_freq); + if (CHANNEL_STATE_ENABLE != ch_state && + CHANNEL_STATE_DFS != ch_state) { + sap_err_rl("Invalid ch freq = %d, ch state=%d", ch_freq, + ch_state); + return true; + } + } /* loop for bonded channels */ + + return false; +} + +bool +sap_chan_bond_dfs_sub_chan(struct sap_context *sap_context, + qdf_freq_t channel_freq, + ePhyChanBondState bond_state) +{ + int i; + struct mac_context *mac_ctx; + qdf_freq_t freq_list[MAX_BONDED_CHANNELS]; + uint8_t num_freq; + struct wlan_objmgr_pdev *pdev; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return false; + } + + pdev = mac_ctx->pdev; + if (!pdev) { + sap_err("null pdev"); + return false; + } + + if (wlan_reg_chan_has_dfs_attribute_for_freq(pdev, channel_freq)) + return true; + + /* get the bonded channels */ + if (channel_freq == sap_context->chan_freq && + bond_state >= PHY_CHANNEL_BONDING_STATE_MAX) + num_freq = sap_ch_params_to_bonding_channels( + &sap_context->ch_params, freq_list); + else + num_freq = sap_get_bonding_channels( + sap_context, channel_freq, freq_list, + MAX_BONDED_CHANNELS, bond_state); + + for (i = 0; i < num_freq; i++) { + if (wlan_reg_chan_has_dfs_attribute_for_freq(pdev, freq_list[i])) { + sap_debug("sub ch freq=%d is dfs in %d", + freq_list[i], channel_freq); + return true; + } + } + + return false; +} + +uint32_t sap_select_default_oper_chan(struct mac_context *mac_ctx, + struct sap_acs_cfg *acs_cfg) +{ + uint16_t i; + uint32_t freq0 = 0, freq1 = 0, freq2 = 0, default_freq; + + if (!acs_cfg) + return 0; + + if (!acs_cfg->ch_list_count || !acs_cfg->freq_list) { + if (mac_ctx->mlme_cfg->acs.force_sap_start) { + sap_debug("SAP forced, freq selected %d", + acs_cfg->master_freq_list[0]); + return acs_cfg->master_freq_list[0]; + } else { + sap_debug("No channel left for operation"); + return 0; + } + } + /* + * There could be both 2.4Ghz and 5ghz channels present in the list + * based upon the Hw mode received from hostapd, it is always better + * to chose a default 5ghz operating channel than 2.4ghz, as it can + * provide a better throughput, latency than 2.4ghz. Also 40 Mhz is + * rare in 2.4ghz band, so 5ghz should be preferred. If we get a 5Ghz + * chan in the acs cfg ch list , we should go for that first else the + * default channel can be 2.4ghz. + * Add check regulatory channel state before select the channel. + */ + + for (i = 0; i < acs_cfg->ch_list_count; i++) { + enum channel_state state = + wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, acs_cfg->freq_list[i], + REG_CURRENT_PWR_MODE); + if (!freq0 && state == CHANNEL_STATE_ENABLE && + WLAN_REG_IS_5GHZ_CH_FREQ(acs_cfg->freq_list[i])) { + freq0 = acs_cfg->freq_list[i]; + break; + } else if (!freq1 && state == CHANNEL_STATE_DFS && + WLAN_REG_IS_5GHZ_CH_FREQ(acs_cfg->freq_list[i])) { + freq1 = acs_cfg->freq_list[i]; + } else if (!freq2 && state == CHANNEL_STATE_ENABLE) { + freq2 = acs_cfg->freq_list[i]; + } + } + default_freq = freq0; + if (!default_freq) + default_freq = freq1; + if (!default_freq) + default_freq = freq2; + if (!default_freq) + default_freq = acs_cfg->freq_list[0]; + + sap_debug("default freq %d chosen from %d %d %d %d", default_freq, + freq0, freq1, freq2, acs_cfg->freq_list[0]); + + return default_freq; +} + +static bool is_mcc_preferred(struct sap_context *sap_context, + uint32_t con_ch_freq) +{ + /* + * If SAP ACS channel list is 1-11 and STA is on non-preferred + * channel i.e. 12, 13, 14 then MCC is unavoidable. This is because + * if SAP is started on 12,13,14 some clients may not be able to + * join dependending on their regulatory country. + */ + if ((con_ch_freq >= 2467) && (con_ch_freq <= 2484) && + (sap_context->acs_cfg->start_ch_freq >= 2412 && + sap_context->acs_cfg->end_ch_freq <= 2462)) { + sap_debug("conc ch freq %d & sap acs ch list is 1-11, prefer mcc", + con_ch_freq); + return true; + } + + return false; +} + +/** + * sap_process_force_scc_with_go_start() - Check GO force SCC or not + * @psoc: psoc object + * @sap_context: sap_context + * + * This function checks the current SAP MCC or not with the GO's home channel. + * If it is, skip the GO's force SCC. The SAP will do force SCC after + * GO's started. + * + * Return: true if skip GO's force SCC + */ +static bool +sap_process_force_scc_with_go_start(struct wlan_objmgr_psoc *psoc, + struct sap_context *sap_context) +{ + uint8_t existing_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + uint32_t con_freq; + enum phy_ch_width ch_width; + + if (sap_context->cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL) + return false; + + existing_vdev_id = + policy_mgr_fetch_existing_con_info(psoc, + sap_context->sessionId, + sap_context->chan_freq, + &existing_vdev_mode, + &con_freq, &ch_width); + if (existing_vdev_id < WLAN_UMAC_VDEV_ID_MAX && + existing_vdev_mode == PM_SAP_MODE) { + sap_debug("concurrent sap vdev: %d on freq %d, skip GO force scc", + existing_vdev_id, con_freq); + return true; + } + + return false; +} + +#ifdef WLAN_FEATURE_P2P_P2P_STA +/** + * sap_set_forcescc_required() - set force scc flag for provided p2p go vdev + * + * @vdev_id: vdev_id for which flag needs to be set + * + * Return: None + */ +static void sap_set_forcescc_required(uint8_t vdev_id) +{ + struct mac_context *mac_ctx; + struct sap_context *sap_ctx; + uint8_t i = 0; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + sap_ctx = mac_ctx->sap.sapCtxList[i].sap_context; + if (QDF_P2P_GO_MODE == mac_ctx->sap.sapCtxList[i].sapPersona && + sap_ctx->sessionId == vdev_id) { + sap_debug("update forcescc restart for vdev %d", + vdev_id); + sap_ctx->is_forcescc_restart_required = true; + } + } +} + +/** + * sap_process_liberal_scc_for_go() - based on existing connections this + * function decides current go should start on provided channel or not and + * sets force scc required bit for existing GO. + * + * @sap_context: sap_context + * + * Return: bool + */ +static bool sap_process_liberal_scc_for_go(struct sap_context *sap_context) +{ + uint8_t existing_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + uint32_t con_freq; + enum phy_ch_width ch_width; + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) { + sap_alert("invalid MAC handle"); + return true; + } + + existing_vdev_id = + policy_mgr_fetch_existing_con_info( + mac_ctx->psoc, + sap_context->sessionId, + sap_context->chan_freq, + &existing_vdev_mode, + &con_freq, &ch_width); + + if (existing_vdev_id < + WLAN_UMAC_VDEV_ID_MAX && + existing_vdev_mode == PM_P2P_GO_MODE) { + sap_debug("set forcescc flag for go vdev: %d", + existing_vdev_id); + sap_set_forcescc_required( + existing_vdev_id); + return true; + } + if (existing_vdev_id < WLAN_UMAC_VDEV_ID_MAX && + (existing_vdev_mode == PM_STA_MODE || + existing_vdev_mode == PM_P2P_CLIENT_MODE)) { + sap_debug("don't override channel, start go on %d", + sap_context->chan_freq); + return true; + } + + return false; +} +#else +static bool sap_process_liberal_scc_for_go(struct sap_context *sap_context) +{ + return false; +} +#endif + +QDF_STATUS +sap_validate_chan(struct sap_context *sap_context, + bool pre_start_bss, + bool check_for_connection_update) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + uint32_t con_ch_freq; + bool sta_sap_scc_on_dfs_chan; + uint32_t sta_go_bit_mask = QDF_STA_MASK | QDF_P2P_GO_MASK; + uint32_t sta_sap_bit_mask = QDF_STA_MASK | QDF_SAP_MASK; + uint32_t concurrent_state; + bool go_force_scc; + struct ch_params ch_params = {0}; + bool is_go_scc_strict = false; + bool start_sap_on_provided_freq = false; + enum QDF_OPMODE opmode = QDF_SAP_MODE; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) { + /* we have a serious problem */ + sap_alert("invalid MAC handle"); + return QDF_STATUS_E_FAULT; + } + + if (!sap_context->chan_freq) { + sap_err("Invalid channel"); + return QDF_STATUS_E_FAILURE; + } + + if (policy_mgr_is_vdev_ll_lt_sap(mac_ctx->psoc, sap_context->vdev_id)) { + sap_context->chan_freq = wlan_ll_lt_sap_override_freq( + mac_ctx->psoc, + sap_context->vdev_id, + sap_context->chan_freq); + return QDF_STATUS_SUCCESS; + } + + if (sap_context->vdev) + opmode = wlan_vdev_mlme_get_opmode(sap_context->vdev); + + if (opmode == QDF_P2P_GO_MODE) { + /* + * check whether go_force_scc is enabled or not. + * If it not enabled then don't any force scc on existing go and + * new p2p go vdevs. + * Otherwise, if it is enabled then check whether it's in strict + * mode or liberal mode. + * For strict mode, do force scc on newly p2p go to existing vdev + * channel. + * For liberal first form new p2p go on requested channel and + * follow below rules: + * a.) If Existing vdev mode is P2P GO Once set key is done, do + * force scc for existing p2p go and move that go to new p2p + * go's channel. + * + * b.) If Existing vdev mode is P2P CLI/STA Once set key is + * done, do force scc for p2p go and move go to cli/sta channel. + */ + go_force_scc = policy_mgr_go_scc_enforced(mac_ctx->psoc); + sap_debug("go force scc enabled %d", go_force_scc); + + if (sap_process_force_scc_with_go_start(mac_ctx->psoc, + sap_context)) + goto validation_done; + + if (go_force_scc) { + is_go_scc_strict = + policy_mgr_is_go_scc_strict(mac_ctx->psoc); + if (!is_go_scc_strict) { + sap_debug("liberal mode is enabled"); + start_sap_on_provided_freq = + sap_process_liberal_scc_for_go(sap_context); + if (start_sap_on_provided_freq) + goto validation_done; + } + } else { + goto validation_done; + } + } + + concurrent_state = policy_mgr_get_concurrency_mode(mac_ctx->psoc); + if (policy_mgr_concurrent_beaconing_sessions_running(mac_ctx->psoc) || + ((concurrent_state & sta_sap_bit_mask) == sta_sap_bit_mask) || + ((concurrent_state & sta_go_bit_mask) == sta_go_bit_mask)) { +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + sap_context->chan_freq)) { + sap_warn("DFS not supported in STA_AP Mode"); + return QDF_STATUS_E_ABORTED; + } +#endif +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + if (sap_context->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_DISABLE) { + con_ch_freq = sme_check_concurrent_channel_overlap( + mac_handle, + sap_context->chan_freq, + sap_context->phyMode, + sap_context->cc_switch_mode, + sap_context->sessionId); + sap_debug("After check overlap: sap freq %d con freq:%d", + sap_context->chan_freq, con_ch_freq); + /* + * For non-DBS platform, a 2.4Ghz can become a 5Ghz freq + * so lets used max BW in that case, if it remain 2.4Ghz + * then BW will be limited to 20 anyway + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_context->chan_freq)) + ch_params.ch_width = CH_WIDTH_MAX; + else + ch_params = sap_context->ch_params; + + if (sap_context->cc_switch_mode != + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) { + if (QDF_IS_STATUS_ERROR( + policy_mgr_valid_sap_conc_channel_check( + mac_ctx->psoc, &con_ch_freq, + sap_context->chan_freq, + sap_context->sessionId, + &ch_params))) { + sap_warn("SAP can't start (no MCC)"); + return QDF_STATUS_E_ABORTED; + } + } + /* if CH width didn't change fallback to original */ + if (ch_params.ch_width == CH_WIDTH_MAX) + ch_params = sap_context->ch_params; + + sap_debug("After check concurrency: con freq:%d", + con_ch_freq); + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan( + mac_ctx->psoc); + if (con_ch_freq && + (policy_mgr_sta_sap_scc_on_lte_coex_chan( + mac_ctx->psoc) || + policy_mgr_is_safe_channel( + mac_ctx->psoc, con_ch_freq)) && + (!wlan_mlme_check_chan_param_has_dfs( + mac_ctx->pdev, &ch_params, + con_ch_freq) || + sta_sap_scc_on_dfs_chan)) { + if (is_mcc_preferred(sap_context, con_ch_freq)) + goto validation_done; + + sap_debug("Override ch freq %d (bw %d) to %d (bw %d) due to CC Intf", + sap_context->chan_freq, + sap_context->ch_params.ch_width, + con_ch_freq, ch_params.ch_width); + sap_context->chan_freq = con_ch_freq; + sap_context->ch_params = ch_params; + } + } +#endif + } +validation_done: + sap_debug("for configured channel, Ch_freq = %d", + sap_context->chan_freq); + + /* + * Don't check if the frequency is allowed or not if SAP is started + * in fixed channel, or WLAN CH AVOID EXT feature explicit restrict + * SAP start on unsafe channel. + */ + + if ((sap_context->acs_cfg->acs_mode || + policy_mgr_restrict_sap_on_unsafe_chan(mac_ctx->psoc)) && + !policy_mgr_is_sap_freq_allowed(mac_ctx->psoc, opmode, + sap_context->chan_freq)) { + sap_warn("Abort SAP start due to unsafe channel"); + return QDF_STATUS_E_ABORTED; + } + + if (check_for_connection_update) { + /* This wait happens in the hostapd context. The event + * is set in the MC thread context. + */ + qdf_status = + policy_mgr_update_and_wait_for_connection_update( + mac_ctx->psoc, sap_context->sessionId, + sap_context->chan_freq, + POLICY_MGR_UPDATE_REASON_START_AP); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + } + + if (pre_start_bss) { + sap_info("ACS end due to Ch override. Sel Ch freq = %d", + sap_context->chan_freq); + sap_context->acs_cfg->pri_ch_freq = sap_context->chan_freq; + sap_context->acs_cfg->ch_width = + sap_context->ch_width_orig; + sap_config_acs_result(mac_handle, sap_context, 0); + return QDF_STATUS_E_CANCELED; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE + +static void sap_sort_freq_list(struct chan_list *list, + uint8_t num_ch) +{ + int i, j, temp; + + for (i = 0; i < num_ch - 1; i++) { + for (j = 0 ; j < num_ch - i - 1; j++) { + if (list->chan[j].freq < list->chan[j + 1].freq) { + temp = list->chan[j].freq; + list->chan[j].freq = list->chan[j + 1].freq; + list->chan[j + 1].freq = temp; + } + } + } +} + +/** + * sap_acs_scan_freq_list_optimize() - optimize the ACS scan freq list based + * on when last scan was performed on particular frequency. If last scan + * performed on particular frequency is less than configured last_scan_ageout + * time, then skip that frequency from ACS scan freq list. + * + * @sap_ctx: sap context + * @list: ACS scan frequency list + * @ch_count: number of frequency in list + * + * Return: None + */ +static void sap_acs_scan_freq_list_optimize(struct sap_context *sap_ctx, + struct chan_list *list, + uint8_t *ch_count) +{ + int loop_count = 0, j = 0; + uint32_t ts_last_scan; + + sap_ctx->partial_acs_scan = false; + + while (loop_count < *ch_count) { + ts_last_scan = scm_get_last_scan_time_per_channel( + sap_ctx->vdev, list->chan[loop_count].freq); + + if (qdf_system_time_before( + qdf_get_time_of_the_day_ms(), + ts_last_scan + sap_ctx->acs_cfg->last_scan_ageout_time)) { + sap_info("ACS chan %d skipped from scan as last scan ts %lu\n", + list->chan[loop_count].freq, + qdf_get_time_of_the_day_ms() - ts_last_scan); + + for (j = loop_count; j < *ch_count - 1; j++) + list->chan[j].freq = list->chan[j + 1].freq; + + (*ch_count)--; + sap_ctx->partial_acs_scan = true; + continue; + } + loop_count++; + } + if (*ch_count == 0) + sap_info("All ACS freq channels are scanned recently, skip ACS scan\n"); + else + sap_sort_freq_list(list, *ch_count); +} +#else +static void sap_acs_scan_freq_list_optimize(struct sap_context *sap_ctx, + struct chan_list *list, + uint8_t *ch_count) +{ +} +#endif + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +/** + * sap_reset_clean_freq_array() - clear freq array that contains info + * channel is free or not + * @sap_context: sap context + * + * Return: void + */ +static +void sap_reset_clean_freq_array(struct sap_context *sap_context) +{ + memset(sap_context->clean_channel_array, 0, NUM_CHANNELS); +} +#else +static inline +void sap_reset_clean_freq_array(struct sap_context *sap_context) +{} +#endif + +/** + * wlansap_set_aux_scan_ctrl_ext_flag() - update aux scan policy + * @req: pointer to scan request + * + * Set aux scan bits in scan_ctrl_ext_flag value depending on scan type + * + * Return: None + */ +static void wlansap_set_aux_scan_ctrl_ext_flag(struct scan_start_request *req) +{ + sap_debug("Set Reliable Scan Flag"); + req->scan_req.scan_ctrl_flags_ext |= + SCAN_FLAG_EXT_AUX_RELIABLE_SCAN; +} + +QDF_STATUS sap_channel_sel(struct sap_context *sap_context) +{ + QDF_STATUS qdf_ret_status; + struct mac_context *mac_ctx; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev = NULL; + uint8_t i, j; + uint32_t *freq_list = NULL; + uint8_t num_of_channels = 0; + mac_handle_t mac_handle; + uint32_t con_ch_freq; + uint8_t vdev_id; + uint32_t scan_id; + uint32_t default_op_freq; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + return QDF_STATUS_E_FAULT; + + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAILURE; + } + if (sap_context->fsm_state != SAP_STARTED && sap_context->chan_freq) + return sap_validate_chan(sap_context, true, false); + + if (policy_mgr_concurrent_beaconing_sessions_running(mac_ctx->psoc) || + ((sap_context->cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) && + (policy_mgr_mode_specific_connection_count(mac_ctx->psoc, + PM_SAP_MODE, NULL) || + policy_mgr_mode_specific_connection_count(mac_ctx->psoc, + PM_P2P_GO_MODE, + NULL)))) { + con_ch_freq = sme_get_beaconing_concurrent_operation_channel( + mac_handle, sap_context->sessionId); +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + if (con_ch_freq) + sap_context->dfs_ch_disable = true; +#endif + } + + if ((policy_mgr_get_concurrency_mode(mac_ctx->psoc) == + (QDF_STA_MASK | QDF_SAP_MASK)) || + ((sap_context->cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_FORCE_PREFERRED_WITHOUT_DISCONNECTION) && + (policy_mgr_get_concurrency_mode(mac_ctx->psoc) == + (QDF_STA_MASK | QDF_P2P_GO_MASK)))) { +#ifdef FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE + sap_context->dfs_ch_disable = true; +#endif + } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + sap_debug("skip_acs_status = %d", + sap_context->acs_cfg->skip_scan_status); + if (sap_context->acs_cfg->skip_scan_status != + eSAP_SKIP_ACS_SCAN) { +#endif + + if (sap_context->freq_list) { + qdf_mem_free(sap_context->freq_list); + sap_context->freq_list = NULL; + sap_context->num_of_channel = 0; + } + + sap_get_freq_list(sap_context, &freq_list, &num_of_channels); + if (!num_of_channels || !freq_list) { + sap_err("No freq sutiable for SAP in current list, SAP failed"); + return QDF_STATUS_E_FAILURE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + qdf_mem_free(freq_list); + return QDF_STATUS_E_NOMEM; + } + + vdev_id = sap_context->sessionId; + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sap_err("Invalid vdev objmgr"); + qdf_mem_free(freq_list); + qdf_mem_free(req); + return QDF_STATUS_E_INVAL; + } + + /* Initiate a SCAN request */ + wlan_scan_init_default_params(vdev, req); + scan_id = wlan_scan_get_scan_id(mac_ctx->psoc); + req->scan_req.scan_id = scan_id; + req->scan_req.vdev_id = vdev_id; + req->scan_req.scan_f_passive = false; + req->scan_req.scan_req_id = sap_context->req_id; + req->scan_req.scan_priority = SCAN_PRIORITY_HIGH; + req->scan_req.scan_f_bcast_probe = true; + for (i = 0, j = 0; i < num_of_channels; i++) { + if (wlan_reg_is_6ghz_chan_freq(freq_list[i]) && + !wlan_reg_is_6ghz_psc_chan_freq(freq_list[i])) + continue; + req->scan_req.chan_list.chan[j++].freq = freq_list[i]; + } + req->scan_req.chan_list.num_chan = j; + sap_context->freq_list = freq_list; + sap_context->num_of_channel = num_of_channels; + sap_context->optimize_acs_chan_selected = false; + sap_reset_clean_freq_array(sap_context); + /* Set requestType to Full scan */ + + /* + * send partial channels to be scanned in SCAN request if + * vendor command included last scan ageout time to be used to + * optimize the SAP bring up time + */ + if (sap_context->acs_cfg->last_scan_ageout_time) + sap_acs_scan_freq_list_optimize( + sap_context, &req->scan_req.chan_list, + &req->scan_req.chan_list.num_chan); + + if (!req->scan_req.chan_list.num_chan) { + sap_info("## SKIPPED ACS SCAN"); + sap_context->acs_cfg->skip_acs_scan = true; + wlansap_pre_start_bss_acs_scan_callback( + mac_handle, sap_context, sap_context->sessionId, + 0, eCSR_SCAN_SUCCESS); + qdf_mem_free(req); + qdf_ret_status = QDF_STATUS_SUCCESS; + goto release_vdev_ref; + } + + sap_context->acs_req_timestamp = qdf_get_time_of_the_day_ms(); + + if (wlan_scan_get_aux_support(mac_ctx->psoc)) + wlansap_set_aux_scan_ctrl_ext_flag(req); + qdf_ret_status = wlan_scan_start(req); + if (qdf_ret_status != QDF_STATUS_SUCCESS) { + sap_err("scan request fail %d!!!", qdf_ret_status); + sap_info("SAP Configuring default ch, Ch_freq=%d", + sap_context->chan_freq); + default_op_freq = sap_select_default_oper_chan( + mac_ctx, sap_context->acs_cfg); + wlansap_set_acs_ch_freq(sap_context, default_op_freq); + + if (sap_context->freq_list) { + wlansap_set_acs_ch_freq( + sap_context, sap_context->freq_list[0]); + qdf_mem_free(sap_context->freq_list); + sap_context->freq_list = NULL; + sap_context->num_of_channel = 0; + } + /* + * In case of ACS req before start Bss, + * return failure so that the calling + * function can use the default channel. + */ + qdf_ret_status = QDF_STATUS_E_FAILURE; + goto release_vdev_ref; + } else { + wlansap_dump_acs_ch_freq(sap_context); + host_log_acs_scan_start(scan_id, vdev_id); + } + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + } else { + sap_context->acs_cfg->skip_scan_status = eSAP_SKIP_ACS_SCAN; + } + + if (sap_context->acs_cfg->skip_scan_status == eSAP_SKIP_ACS_SCAN) { + sap_err("## SKIPPED ACS SCAN"); + wlansap_pre_start_bss_acs_scan_callback(mac_handle, + sap_context, sap_context->sessionId, 0, + eCSR_SCAN_SUCCESS); + } +#endif + + wlansap_dump_acs_ch_freq(sap_context); + + qdf_ret_status = QDF_STATUS_SUCCESS; + +release_vdev_ref: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return qdf_ret_status; +} + +/** + * sap_find_valid_concurrent_session() - to find valid concurrent session + * @mac_handle: Opaque handle to the global MAC context + * + * This API will check if any valid concurrent SAP session is present + * + * Return: pointer to sap context of valid concurrent session + */ +static struct sap_context * +sap_find_valid_concurrent_session(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t intf = 0; + struct sap_context *sap_ctx; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].sap_context) { + sap_ctx = mac_ctx->sap.sapCtxList[intf].sap_context; + if (sap_ctx->fsm_state != SAP_INIT) + return sap_ctx; + } + } + + return NULL; +} + +QDF_STATUS sap_clear_global_dfs_param(mac_handle_t mac_handle, + struct sap_context *sap_ctx) +{ + struct sap_context *con_sap_ctx; + + con_sap_ctx = sap_find_valid_concurrent_session(mac_handle); + if (con_sap_ctx && WLAN_REG_IS_5GHZ_CH_FREQ(con_sap_ctx->chan_freq)) { + sap_debug("conc session exists, no need to clear dfs struct"); + return QDF_STATUS_SUCCESS; + } + /* + * CAC timer will be initiated and started only when SAP starts + * on DFS channel and it will be stopped and destroyed + * immediately once the radar detected or timedout. So + * as per design CAC timer should be destroyed after stop + */ + wlansap_cleanup_cac_timer(sap_ctx); + sap_cac_reset_notify(mac_handle); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_acquire_vdev_ref(struct wlan_objmgr_psoc *psoc, + struct sap_context *sap_ctx, + uint8_t session_id) +{ + struct wlan_objmgr_vdev *vdev; + + if (sap_ctx->vdev) { + sap_err("Invalid vdev obj in sap context"); + return QDF_STATUS_E_FAULT; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id, + WLAN_LEGACY_SAP_ID); + if (!vdev) { + sap_err("vdev is NULL for vdev_id: %u", session_id); + return QDF_STATUS_E_FAILURE; + } + + sap_ctx->vdev = vdev; + return QDF_STATUS_SUCCESS; +} + +void sap_release_vdev_ref(struct sap_context *sap_ctx) +{ + struct wlan_objmgr_vdev *vdev; + + if (!sap_ctx) { + sap_debug("Invalid SAP pointer"); + return; + } + + vdev = sap_ctx->vdev; + if (vdev) { + sap_ctx->vdev = NULL; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SAP_ID); + } +} + +QDF_STATUS sap_set_session_param(mac_handle_t mac_handle, + struct sap_context *sapctx, + uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + int i; + + sapctx->sessionId = session_id; + wlan_pre_cac_set_status(sapctx->vdev, false); + wlan_pre_cac_complete_set(sapctx->vdev, false); + wlan_pre_cac_set_freq_before_pre_cac(sapctx->vdev, 0); + + /* When SSR, SAP will restart, clear the old context,sessionId */ + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (mac_ctx->sap.sapCtxList[i].sap_context == sapctx) + mac_ctx->sap.sapCtxList[i].sap_context = NULL; + } + + mac_ctx->sap.sapCtxList[sapctx->sessionId].sap_context = sapctx; + mac_ctx->sap.sapCtxList[sapctx->sessionId].sapPersona = + wlan_get_opmode_from_vdev_id(mac_ctx->pdev, session_id); + sap_debug("Initializing sap_ctx = %pK with session = %d", + sapctx, session_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_clear_session_param(mac_handle_t mac_handle, + struct sap_context *sapctx, + uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (sapctx->sessionId >= SAP_MAX_NUM_SESSION) + return QDF_STATUS_E_FAILURE; + + mac_ctx->sap.sapCtxList[sapctx->sessionId].sap_context = NULL; + mac_ctx->sap.sapCtxList[sapctx->sessionId].sapPersona = + QDF_MAX_NO_OF_MODE; + sap_clear_global_dfs_param(mac_handle, sapctx); + + sap_err("Set sapCtxList null for session %d", sapctx->sessionId); + qdf_mem_zero(sapctx, sizeof(*sapctx)); + sapctx->sessionId = WLAN_UMAC_VDEV_ID_MAX; + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11AX +static uint16_t he_mcs_12_13_support(void) +{ + struct mac_context *mac_ctx; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return 0; + } + + return mac_ctx->mlme_cfg->he_caps.he_mcs_12_13_supp_5g; +} +#else +static inline uint16_t he_mcs_12_13_support(void) +{ + return 0; +} +#endif + +static bool is_mcs13_ch_width(enum phy_ch_width ch_width) +{ + if ((ch_width == CH_WIDTH_320MHZ) || + (ch_width == CH_WIDTH_160MHZ) || + (ch_width == CH_WIDTH_80P80MHZ)) + return true; + + return false; +} + +/** + * sap_update_mcs_rate() - Update SAP MCS rate + * @sap_ctx: pointer to sap Context + * @is_start: Start or stop SAP + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sap_update_mcs_rate(struct sap_context *sap_ctx, bool is_start) +{ + uint32_t default_mcs[] = {26, 0x3fff}; + uint32_t fixed_mcs[] = {26, 0x1fff}; + bool disable_mcs13_support = false; + uint16_t he_mcs_12_13_supp; + struct mac_context *mac_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_INVAL; + } + + he_mcs_12_13_supp = he_mcs_12_13_support(); + disable_mcs13_support = cfg_get(mac_ctx->psoc, + CFG_DISABLE_MCS13_SUPPORT); + sap_debug("session id %d, disable mcs13 support %d, he_mcs_12_13 %d, start %d, disabled_mcs13 %d, ch width %d", + sap_ctx->sessionId, disable_mcs13_support, + he_mcs_12_13_supp, + is_start, sap_ctx->disabled_mcs13, + sap_ctx->ch_params.ch_width); + + if (!disable_mcs13_support || + !he_mcs_12_13_supp) + return status; + + if (!is_start && !sap_ctx->disabled_mcs13) + return status; + + if (!is_mcs13_ch_width(sap_ctx->ch_params.ch_width)) + return status; + + if (is_start) { + status = sme_send_unit_test_cmd(sap_ctx->sessionId, + 10, 2, fixed_mcs); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Set fixed mcs rate failed, session %d", + sap_ctx->sessionId); + } else { + sap_ctx->disabled_mcs13 = true; + } + } else { + status = sme_send_unit_test_cmd(sap_ctx->sessionId, + 10, 2, default_mcs); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Set default mcs rate failed, session %d", + sap_ctx->sessionId); + } else { + sap_ctx->disabled_mcs13 = false; + } + } + + return status; +} + +/** + * sap_goto_stopping() - Processing of SAP FSM stopping state + * @sap_ctx: pointer to sap Context + * + * Return: QDF_STATUS code associated with performing the operation + */ +static QDF_STATUS sap_goto_stopping(struct sap_context *sap_ctx) +{ + QDF_STATUS status; + struct mac_context *mac_ctx; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + /* we have a serious problem */ + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + sap_update_mcs_rate(sap_ctx, false); + qdf_mem_zero(&sap_ctx->sap_bss_cfg, sizeof(sap_ctx->sap_bss_cfg)); + + status = sme_roam_stop_bss(MAC_HANDLE(mac_ctx), sap_ctx->sessionId); + if (status != QDF_STATUS_SUCCESS) { + sap_err("Calling sme_roam_stop_bss status = %d", status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_goto_init() - Function for setting the SAP FSM to init state + * @sap_ctx: pointer to sap context + * + * Return: QDF_STATUS code associated with performing the operation + */ +static QDF_STATUS sap_goto_init(struct sap_context *sap_ctx) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct sap_sm_event sap_event; + /* Processing has to be coded */ + + /* + * Clean up stations from TL etc as AP BSS is shut down + * then set event + */ + + /* hardcoded event */ + sap_event.event = eSAP_MAC_READY_FOR_CONNECTIONS; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + + return qdf_status; +} + +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE +/** + * sap_handle_acs_scan_event() - handle acs scan event for SAP + * @sap_context: ptSapContext + * @sap_event: struct sap_event + * @status: status of acs scan + * + * The function is to handle the eSAP_ACS_SCAN_SUCCESS_EVENT event. + * + * Return: void + */ +static void sap_handle_acs_scan_event(struct sap_context *sap_context, + struct sap_event *sap_event, eSapStatus status) +{ + sap_event->sapHddEventCode = eSAP_ACS_SCAN_SUCCESS_EVENT; + sap_event->sapevt.sap_acs_scan_comp.status = status; + sap_event->sapevt.sap_acs_scan_comp.num_of_channels = + sap_context->num_of_channel; + sap_event->sapevt.sap_acs_scan_comp.freq_list = + sap_context->freq_list; +} +#else +static void sap_handle_acs_scan_event(struct sap_context *sap_context, + struct sap_event *sap_event, eSapStatus status) +{ +} +#endif + +#define DH_OUI_TYPE "\x20" +#define DH_OUI_TYPE_SIZE (1) +/** + * sap_fill_owe_ie_in_assoc_ind() - Fill OWE IE in assoc indication + * Function to fill OWE IE in assoc indication + * @assoc_ind: SAP STA association indication + * @sme_assoc_ind: SME association indication + * @reassoc: True if it is reassoc frame + * + * This function is to get OWE IEs (RSN IE, DH IE etc) from assoc request + * and fill them in association indication. + * + * Return: true for success and false for failure + */ +static bool sap_fill_owe_ie_in_assoc_ind(tSap_StationAssocIndication *assoc_ind, + struct assoc_ind *sme_assoc_ind, + bool reassoc) +{ + uint32_t owe_ie_len, rsn_ie_len, dh_ie_len; + const uint8_t *rsn_ie, *dh_ie; + uint8_t *assoc_req_ie; + uint16_t assoc_req_ie_len; + + if (reassoc) { + if (assoc_ind->assocReqLength < WLAN_REASSOC_REQ_IES_OFFSET) { + sap_err("Invalid reassoc req"); + return false; + } + + assoc_req_ie = assoc_ind->assocReqPtr + + WLAN_REASSOC_REQ_IES_OFFSET; + assoc_req_ie_len = assoc_ind->assocReqLength - + WLAN_REASSOC_REQ_IES_OFFSET; + } else { + if (assoc_ind->assocReqLength < WLAN_ASSOC_REQ_IES_OFFSET) { + sap_err("Invalid assoc req"); + return false; + } + + assoc_req_ie = assoc_ind->assocReqPtr + + WLAN_ASSOC_REQ_IES_OFFSET; + assoc_req_ie_len = assoc_ind->assocReqLength - + WLAN_ASSOC_REQ_IES_OFFSET; + } + rsn_ie = wlan_get_ie_ptr_from_eid(DOT11F_EID_RSN, + assoc_req_ie, assoc_req_ie_len); + if (!rsn_ie) { + sap_err("RSN IE is not present"); + return false; + } + rsn_ie_len = rsn_ie[1] + 2; + if (rsn_ie_len < DOT11F_IE_RSN_MIN_LEN || + rsn_ie_len > DOT11F_IE_RSN_MAX_LEN) { + sap_err("Invalid RSN IE len %d", rsn_ie_len); + return false; + } + + dh_ie = wlan_get_ext_ie_ptr_from_ext_id(DH_OUI_TYPE, DH_OUI_TYPE_SIZE, + assoc_req_ie, assoc_req_ie_len); + if (!dh_ie) { + sap_err("DH IE is not present"); + return false; + } + dh_ie_len = dh_ie[1] + 2; + if (dh_ie_len < DOT11F_IE_DH_PARAMETER_ELEMENT_MIN_LEN || + dh_ie_len > DOT11F_IE_DH_PARAMETER_ELEMENT_MAX_LEN) { + sap_err("Invalid DH IE len %d", dh_ie_len); + return false; + } + + sap_debug("rsn_ie_len = %d, dh_ie_len = %d", rsn_ie_len, dh_ie_len); + + owe_ie_len = rsn_ie_len + dh_ie_len; + assoc_ind->owe_ie = qdf_mem_malloc(owe_ie_len); + if (!assoc_ind->owe_ie) + return false; + + qdf_mem_copy(assoc_ind->owe_ie, rsn_ie, rsn_ie_len); + qdf_mem_copy(assoc_ind->owe_ie + rsn_ie_len, dh_ie, dh_ie_len); + assoc_ind->owe_ie_len = owe_ie_len; + + return true; +} + +/** + * sap_save_owe_pending_assoc_ind() - Save pending assoc indication + * Function to save pending assoc indication in SAP context + * @sap_ctx: SAP context + * @sme_assoc_ind: SME association indication + * + * This function is to save pending assoc indication in linked list + * in SAP context. + * + * Return: true for success and false for failure + */ +static bool sap_save_owe_pending_assoc_ind(struct sap_context *sap_ctx, + struct assoc_ind *sme_assoc_ind) +{ + struct owe_assoc_ind *assoc_ind; + QDF_STATUS status; + + assoc_ind = qdf_mem_malloc(sizeof(*assoc_ind)); + if (!assoc_ind) + return false; + assoc_ind->assoc_ind = sme_assoc_ind; + status = qdf_list_insert_back(&sap_ctx->owe_pending_assoc_ind_list, + &assoc_ind->node); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(assoc_ind); + return false; + } + + return true; +} + +static bool sap_save_ft_pending_assoc_ind(struct sap_context *sap_ctx, + struct assoc_ind *sme_assoc_ind) +{ + struct ft_assoc_ind *assoc_ind; + QDF_STATUS status; + + assoc_ind = qdf_mem_malloc(sizeof(*assoc_ind)); + if (!assoc_ind) + return false; + assoc_ind->assoc_ind = sme_assoc_ind; + status = qdf_list_insert_back(&sap_ctx->ft_pending_assoc_ind_list, + &assoc_ind->node); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(assoc_ind); + return false; + } + qdf_event_set(&sap_ctx->ft_pending_event); + + return true; +} + +#ifdef FEATURE_RADAR_HISTORY +/* Last cac result */ +static struct prev_cac_result prev_cac_history; + +/** + * sap_update_cac_history() - record SAP Radar found result in last + * "active" or CAC period + * @mac_ctx: mac context + * @sap_ctx: sap context + * @event_id: sap event + * + * The function is to save the dfs channel information + * If SAP has been "active" or "CAC" on DFS channel for 60s and + * no found radar event. + * + * Return: void + */ +static void +sap_update_cac_history(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + eSapHddEvent event_id) +{ + struct prev_cac_result *cac_result = &sap_ctx->cac_result; + + switch (event_id) { + case eSAP_START_BSS_EVENT: + case eSAP_CHANNEL_CHANGE_RESP: + case eSAP_DFS_CAC_START: + if (sap_operating_on_dfs(mac_ctx, sap_ctx)) { + qdf_mem_zero(cac_result, + sizeof(struct prev_cac_result)); + if (!sap_ctx->ch_params.mhz_freq_seg0) { + sap_debug("invalid seq0"); + return; + } + cac_result->ap_start_time = + qdf_get_monotonic_boottime(); + cac_result->cac_ch_param = sap_ctx->ch_params; + sap_debug("ap start(CAC) (%d, %d) bw %d", + cac_result->cac_ch_param.mhz_freq_seg0, + cac_result->cac_ch_param.mhz_freq_seg1, + cac_result->cac_ch_param.ch_width); + } + break; + case eSAP_DFS_RADAR_DETECT: + qdf_mem_zero(cac_result, + sizeof(struct prev_cac_result)); + break; + case eSAP_DFS_CAC_END: + case eSAP_STOP_BSS_EVENT: + if (cac_result->ap_start_time) { + uint64_t diff_ms; + + cac_result->ap_end_time = + qdf_get_monotonic_boottime(); + diff_ms = qdf_do_div(cac_result->ap_end_time - + cac_result->ap_start_time, 1000); + if (diff_ms < DEFAULT_CAC_TIMEOUT - 5000) { + if (event_id == eSAP_STOP_BSS_EVENT) + qdf_mem_zero( + cac_result, + sizeof(struct prev_cac_result)); + sap_debug("ap cac dur %llu ms", diff_ms); + break; + } + cac_result->cac_complete = true; + qdf_mem_copy(&prev_cac_history, cac_result, + sizeof(struct prev_cac_result)); + sap_debug("ap cac saved %llu ms %llu (%d, %d) bw %d", + diff_ms, + cac_result->ap_end_time, + cac_result->cac_ch_param.mhz_freq_seg0, + cac_result->cac_ch_param.mhz_freq_seg1, + cac_result->cac_ch_param.ch_width); + if (event_id == eSAP_STOP_BSS_EVENT) + qdf_mem_zero(cac_result, + sizeof(struct prev_cac_result)); + } + break; + default: + break; + } +} + +/** + * find_ch_freq_in_radar_hist() - check channel frequency existing + * in radar history buffer + * @radar_result: radar history buffer + * @count: radar history element number + * @ch_freq: channel frequency + * + * Return: bool + */ +static +bool find_ch_freq_in_radar_hist(struct dfs_radar_history *radar_result, + uint32_t count, uint16_t ch_freq) +{ + while (count) { + if (radar_result->ch_freq == ch_freq) + return true; + radar_result++; + count--; + } + + return false; +} + +/** + * sap_append_cac_history() - Add CAC history to list + * @mac_ctx: pointer to mac context + * @radar_result: radar history buffer + * @idx: current radar history element number + * @max_elems: max elements number of radar history buffer. + * + * This function is to add the CAC history to radar history list. + * + * Return: void + */ +static +void sap_append_cac_history(struct mac_context *mac_ctx, + struct dfs_radar_history *radar_result, + uint32_t *idx, uint32_t max_elems) +{ + struct prev_cac_result *cac_result = &prev_cac_history; + struct ch_params ch_param = cac_result->cac_ch_param; + uint32_t count = *idx; + + if (!cac_result->cac_complete || !cac_result->ap_end_time) { + sap_debug("cac hist empty"); + return; + } + + if (ch_param.ch_width <= CH_WIDTH_20MHZ) { + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + ch_param.mhz_freq_seg0) && + !find_ch_freq_in_radar_hist(radar_result, count, + ch_param.mhz_freq_seg0) && + *idx < max_elems) { + radar_result[*idx].ch_freq = ch_param.mhz_freq_seg0; + radar_result[*idx].time = cac_result->ap_end_time; + radar_result[*idx].radar_found = false; + sap_debug("radar hist[%d] freq %d time %llu no radar", + *idx, ch_param.mhz_freq_seg0, + cac_result->ap_end_time); + (*idx)++; + } + } else { + uint16_t chan_cfreq; + enum channel_state state; + const struct bonded_channel_freq *bonded_chan_ptr = NULL; + + state = wlan_reg_get_5g_bonded_channel_and_state_for_pwrmode + (mac_ctx->pdev, ch_param.mhz_freq_seg0, + ch_param.ch_width, &bonded_chan_ptr, + REG_CURRENT_PWR_MODE, NO_SCHANS_PUNC); + if (!bonded_chan_ptr || state == CHANNEL_STATE_INVALID) { + sap_debug("invalid freq %d", ch_param.mhz_freq_seg0); + return; + } + + chan_cfreq = bonded_chan_ptr->start_freq; + while (chan_cfreq <= bonded_chan_ptr->end_freq) { + state = wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, chan_cfreq, + REG_CURRENT_PWR_MODE); + if (state == CHANNEL_STATE_INVALID) { + sap_debug("invalid ch freq %d", + chan_cfreq); + chan_cfreq = chan_cfreq + 20; + continue; + } + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + chan_cfreq) && + !find_ch_freq_in_radar_hist(radar_result, count, + chan_cfreq) && + *idx < max_elems) { + radar_result[*idx].ch_freq = chan_cfreq; + radar_result[*idx].time = + cac_result->ap_end_time; + radar_result[*idx].radar_found = false; + sap_debug("radar hist[%d] freq %d time %llu no radar", + *idx, chan_cfreq, + cac_result->ap_end_time); + (*idx)++; + } + chan_cfreq = chan_cfreq + 20; + } + } +} + +QDF_STATUS +wlansap_query_radar_history(mac_handle_t mac_handle, + struct dfs_radar_history **radar_history, + uint32_t *count) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct dfsreq_nolinfo *nol_info; + uint32_t i; + uint32_t hist_count; + struct dfs_radar_history *radar_result; + + nol_info = qdf_mem_malloc(sizeof(struct dfsreq_nolinfo)); + if (!nol_info) + return QDF_STATUS_E_NOMEM; + + ucfg_dfs_getnol(mac_ctx->pdev, nol_info); + + hist_count = nol_info->dfs_ch_nchans + MAX_NUM_OF_CAC_HISTORY; + radar_result = qdf_mem_malloc(sizeof(struct dfs_radar_history) * + hist_count); + if (!radar_result) { + qdf_mem_free(nol_info); + return QDF_STATUS_E_NOMEM; + } + + for (i = 0; i < nol_info->dfs_ch_nchans && i < DFS_CHAN_MAX; i++) { + radar_result[i].ch_freq = nol_info->dfs_nol[i].nol_freq; + radar_result[i].time = nol_info->dfs_nol[i].nol_start_us; + radar_result[i].radar_found = true; + sap_debug("radar hist[%d] freq %d time %llu radar", + i, nol_info->dfs_nol[i].nol_freq, + nol_info->dfs_nol[i].nol_start_us); + } + + sap_append_cac_history(mac_ctx, radar_result, &i, hist_count); + sap_debug("hist count %d cur %llu", i, qdf_get_monotonic_boottime()); + + *radar_history = radar_result; + *count = i; + qdf_mem_free(nol_info); + + return QDF_STATUS_SUCCESS; +} +#else +static inline void +sap_update_cac_history(struct mac_context *mac_ctx, + struct sap_context *sap_ctx, + eSapHddEvent event_id) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static inline +bool sap_check_peer_for_peer_null_mldaddr(struct wlan_objmgr_peer *peer) +{ + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)peer->mldaddr)) + return true; + else + return false; +} +#else +static inline +bool sap_check_peer_for_peer_null_mldaddr(struct wlan_objmgr_peer *peer) +{ + return true; +} +#endif + +static +QDF_STATUS sap_populate_peer_assoc_info(struct mac_context *mac_ctx, + struct csr_roam_info *csr_roaminfo, + struct sap_event *sap_ap_event) +{ + struct wlan_objmgr_peer *peer; + tSap_StationAssocReassocCompleteEvent *reassoc_complete; + + reassoc_complete = + &sap_ap_event->sapevt.sapStationAssocReassocCompleteEvent; + + peer = wlan_objmgr_get_peer_by_mac(mac_ctx->psoc, + csr_roaminfo->peerMac.bytes, + WLAN_LEGACY_MAC_ID); + if (!peer) { + sap_err("Peer object not found"); + return QDF_STATUS_E_FAILURE; + } + + sap_debug("mlo peer assoc:%d", wlan_peer_mlme_is_assoc_peer(peer)); + + if (sap_check_peer_for_peer_null_mldaddr(peer) || + wlan_peer_mlme_is_assoc_peer(peer)) { + if (csr_roaminfo->assocReqLength < ASSOC_REQ_IE_OFFSET) { + sap_err("Invalid assoc request length:%d", + csr_roaminfo->assocReqLength); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + return QDF_STATUS_E_INVAL; + } + reassoc_complete->ies_len = (csr_roaminfo->assocReqLength - + ASSOC_REQ_IE_OFFSET); + reassoc_complete->ies = (csr_roaminfo->assocReqPtr + + ASSOC_REQ_IE_OFFSET); + /* skip current AP address in reassoc frame */ + if (csr_roaminfo->fReassocReq) { + reassoc_complete->ies_len -= QDF_MAC_ADDR_SIZE; + reassoc_complete->ies += QDF_MAC_ADDR_SIZE; + } + } + + if (csr_roaminfo->addIELen) { + if (wlan_get_vendor_ie_ptr_from_oui( + SIR_MAC_P2P_OUI, SIR_MAC_P2P_OUI_SIZE, + csr_roaminfo->paddIE, csr_roaminfo->addIELen)) { + reassoc_complete->staType = eSTA_TYPE_P2P_CLI; + } else { + reassoc_complete->staType = eSTA_TYPE_INFRA; + } + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_MAC_ID); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +sap_reassoc_mld_copy(struct csr_roam_info *csr_roaminfo, + tSap_StationAssocReassocCompleteEvent *reassoc_complete) +{ + qdf_copy_macaddr(&reassoc_complete->sta_mld, + &csr_roaminfo->peer_mld); + sap_debug("reassoc_complete->staMld: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(reassoc_complete->sta_mld.bytes)); +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +sap_reassoc_mld_copy(struct csr_roam_info *csr_roaminfo, + tSap_StationAssocReassocCompleteEvent *reassoc_complete) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +/** + * sap_signal_hdd_event() - send event notification + * @sap_ctx: Sap Context + * @csr_roaminfo: Pointer to CSR roam information + * @sap_hddevent: SAP HDD event + * @context: to pass the element for future support + * + * Function for HDD to send the event notification using callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_signal_hdd_event(struct sap_context *sap_ctx, + struct csr_roam_info *csr_roaminfo, eSapHddEvent sap_hddevent, + void *context) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct sap_event *sap_ap_event; + struct mac_context *mac_ctx; + struct oem_channel_info *chaninfo; + tSap_StationAssocIndication *assoc_ind; + tSap_StartBssCompleteEvent *bss_complete; + struct sap_ch_selected_s *acs_selected; + tSap_StationAssocReassocCompleteEvent *reassoc_complete; + tSap_StationDisassocCompleteEvent *disassoc_comp; + tSap_StationSetKeyCompleteEvent *key_complete; + tSap_StationMICFailureEvent *mic_failure; + + /* Format the Start BSS Complete event to return... */ + if (!sap_ctx->sap_event_cb) + return QDF_STATUS_E_FAILURE; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAILURE; + } + + sap_ap_event = qdf_mem_malloc(sizeof(*sap_ap_event)); + if (!sap_ap_event) + return QDF_STATUS_E_NOMEM; + + sap_debug("SAP event callback event = %s", + sap_hdd_event_to_string(sap_hddevent)); + + switch (sap_hddevent) { + case eSAP_STA_ASSOC_IND: + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + /* TODO - Indicate the assoc request indication to OS */ + sap_ap_event->sapHddEventCode = eSAP_STA_ASSOC_IND; + assoc_ind = &sap_ap_event->sapevt.sapAssocIndication; + + qdf_copy_macaddr(&assoc_ind->staMac, &csr_roaminfo->peerMac); + assoc_ind->staId = csr_roaminfo->staId; + assoc_ind->status = 0; + /* Required for indicating the frames to upper layer */ + assoc_ind->assocReqLength = csr_roaminfo->assocReqLength; + assoc_ind->assocReqPtr = csr_roaminfo->assocReqPtr; + assoc_ind->fWmmEnabled = csr_roaminfo->wmmEnabledSta; + assoc_ind->ecsa_capable = csr_roaminfo->ecsa_capable; + if (csr_roaminfo->owe_pending_assoc_ind) { + if (!sap_fill_owe_ie_in_assoc_ind(assoc_ind, + csr_roaminfo->owe_pending_assoc_ind, + csr_roaminfo->fReassocReq)) { + sap_err("Failed to fill OWE IE"); + qdf_mem_free(csr_roaminfo-> + owe_pending_assoc_ind); + csr_roaminfo->owe_pending_assoc_ind = NULL; + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + if (!sap_save_owe_pending_assoc_ind(sap_ctx, + csr_roaminfo->owe_pending_assoc_ind)) { + sap_err("Failed to save assoc ind"); + qdf_mem_free(csr_roaminfo-> + owe_pending_assoc_ind); + csr_roaminfo->owe_pending_assoc_ind = NULL; + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + csr_roaminfo->owe_pending_assoc_ind = NULL; + } + + if (csr_roaminfo->ft_pending_assoc_ind) { + if (!sap_save_ft_pending_assoc_ind(sap_ctx, + csr_roaminfo->ft_pending_assoc_ind)) { + sap_err("Failed to save ft assoc ind"); + qdf_mem_free(csr_roaminfo->ft_pending_assoc_ind); + csr_roaminfo->ft_pending_assoc_ind = NULL; + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + csr_roaminfo->ft_pending_assoc_ind = NULL; + } + break; + case eSAP_START_BSS_EVENT: + sap_ap_event->sapHddEventCode = eSAP_START_BSS_EVENT; + bss_complete = &sap_ap_event->sapevt.sapStartBssCompleteEvent; + + bss_complete->sessionId = sap_ctx->sessionId; + if (bss_complete->sessionId == WLAN_UMAC_VDEV_ID_MAX) { + sap_err("Invalid sessionId"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + + bss_complete->status = (eSapStatus) context; + bss_complete->staId = sap_ctx->sap_sta_id; + + sap_debug("(eSAP_START_BSS_EVENT): staId = %d", + bss_complete->staId); + + bss_complete->operating_chan_freq = sap_ctx->chan_freq; + bss_complete->ch_width = sap_ctx->ch_params.ch_width; + if (QDF_IS_STATUS_SUCCESS(bss_complete->status)) { + sap_update_cac_history(mac_ctx, sap_ctx, + sap_hddevent); + sap_update_mcs_rate(sap_ctx, true); + } + break; + case eSAP_DFS_CAC_START: + case eSAP_DFS_CAC_INTERRUPTED: + case eSAP_DFS_CAC_END: + case eSAP_DFS_RADAR_DETECT: + case eSAP_DFS_NO_AVAILABLE_CHANNEL: + sap_ap_event->sapHddEventCode = sap_hddevent; + sap_ap_event->sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + sap_update_cac_history(mac_ctx, sap_ctx, + sap_hddevent); + break; + case eSAP_ACS_SCAN_SUCCESS_EVENT: + sap_handle_acs_scan_event(sap_ctx, sap_ap_event, + (eSapStatus)context); + break; + case eSAP_ACS_CHANNEL_SELECTED: + sap_ap_event->sapHddEventCode = sap_hddevent; + acs_selected = &sap_ap_event->sapevt.sap_ch_selected; + if (eSAP_STATUS_SUCCESS == (eSapStatus)context) { + acs_selected->pri_ch_freq = + sap_ctx->acs_cfg->pri_ch_freq; + acs_selected->ht_sec_ch_freq = + sap_ctx->acs_cfg->ht_sec_ch_freq; + acs_selected->ch_width = sap_ctx->acs_cfg->ch_width; + acs_selected->vht_seg0_center_ch_freq = + sap_ctx->acs_cfg->vht_seg0_center_ch_freq; + acs_selected->vht_seg1_center_ch_freq = + sap_ctx->acs_cfg->vht_seg1_center_ch_freq; + } else if (eSAP_STATUS_FAILURE == (eSapStatus)context) { + acs_selected->pri_ch_freq = 0; + } + break; + + case eSAP_STOP_BSS_EVENT: + sap_ap_event->sapHddEventCode = eSAP_STOP_BSS_EVENT; + sap_ap_event->sapevt.sapStopBssCompleteEvent.status = + (eSapStatus) context; + break; + + case eSAP_STA_ASSOC_EVENT: + case eSAP_STA_REASSOC_EVENT: + + if (!csr_roaminfo) { + sap_err("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + if (sap_ctx->fsm_state == SAP_STOPPING) { + sap_err("SAP is stopping, not able to handle any incoming (re)assoc req"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_ABORTED; + } + + qdf_status = sap_populate_peer_assoc_info(mac_ctx, csr_roaminfo, + sap_ap_event); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + + reassoc_complete = + &sap_ap_event->sapevt.sapStationAssocReassocCompleteEvent; + + if (csr_roaminfo->fReassocReq) + sap_ap_event->sapHddEventCode = eSAP_STA_REASSOC_EVENT; + else + sap_ap_event->sapHddEventCode = eSAP_STA_ASSOC_EVENT; + + qdf_copy_macaddr(&reassoc_complete->staMac, + &csr_roaminfo->peerMac); + sap_reassoc_mld_copy(csr_roaminfo, reassoc_complete); + reassoc_complete->staId = csr_roaminfo->staId; + reassoc_complete->status_code = csr_roaminfo->status_code; + + /* also fill up the channel info from the csr_roamInfo */ + chaninfo = &reassoc_complete->chan_info; + + chaninfo->mhz = csr_roaminfo->chan_info.mhz; + chaninfo->info = csr_roaminfo->chan_info.info; + chaninfo->band_center_freq1 = + csr_roaminfo->chan_info.band_center_freq1; + chaninfo->band_center_freq2 = + csr_roaminfo->chan_info.band_center_freq2; + chaninfo->reg_info_1 = + csr_roaminfo->chan_info.reg_info_1; + chaninfo->reg_info_2 = + csr_roaminfo->chan_info.reg_info_2; + chaninfo->nss = csr_roaminfo->chan_info.nss; + chaninfo->rate_flags = csr_roaminfo->chan_info.rate_flags; + + reassoc_complete->wmmEnabled = csr_roaminfo->wmmEnabledSta; + reassoc_complete->status = (eSapStatus) context; + reassoc_complete->timingMeasCap = csr_roaminfo->timingMeasCap; + reassoc_complete->ampdu = csr_roaminfo->ampdu; + reassoc_complete->sgi_enable = csr_roaminfo->sgi_enable; + reassoc_complete->tx_stbc = csr_roaminfo->tx_stbc; + reassoc_complete->rx_stbc = csr_roaminfo->rx_stbc; + reassoc_complete->ch_width = csr_roaminfo->ch_width; + reassoc_complete->mode = csr_roaminfo->mode; + reassoc_complete->max_supp_idx = csr_roaminfo->max_supp_idx; + reassoc_complete->max_ext_idx = csr_roaminfo->max_ext_idx; + reassoc_complete->max_mcs_idx = csr_roaminfo->max_mcs_idx; + reassoc_complete->max_real_mcs_idx = + csr_roaminfo->max_real_mcs_idx; + reassoc_complete->rx_mcs_map = csr_roaminfo->rx_mcs_map; + reassoc_complete->tx_mcs_map = csr_roaminfo->tx_mcs_map; + reassoc_complete->ecsa_capable = csr_roaminfo->ecsa_capable; + reassoc_complete->ext_cap = csr_roaminfo->ext_cap; + reassoc_complete->supported_band = csr_roaminfo->supported_band; + if (csr_roaminfo->ht_caps.present) + reassoc_complete->ht_caps = csr_roaminfo->ht_caps; + if (csr_roaminfo->vht_caps.present) + reassoc_complete->vht_caps = csr_roaminfo->vht_caps; + reassoc_complete->he_caps_present = + csr_roaminfo->he_caps_present; + reassoc_complete->eht_caps_present = + csr_roaminfo->eht_caps_present; + reassoc_complete->capability_info = + csr_roaminfo->capability_info; + + break; + + case eSAP_STA_DISASSOC_EVENT: + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + sap_ap_event->sapHddEventCode = eSAP_STA_DISASSOC_EVENT; + disassoc_comp = + &sap_ap_event->sapevt.sapStationDisassocCompleteEvent; + + qdf_copy_macaddr(&disassoc_comp->staMac, + &csr_roaminfo->peerMac); + disassoc_comp->staId = csr_roaminfo->staId; + if (csr_roaminfo->reasonCode == eCSR_ROAM_RESULT_FORCED) + disassoc_comp->reason = eSAP_USR_INITATED_DISASSOC; + else + disassoc_comp->reason = eSAP_MAC_INITATED_DISASSOC; + + disassoc_comp->status_code = csr_roaminfo->status_code; + disassoc_comp->status = (eSapStatus) context; + disassoc_comp->rssi = csr_roaminfo->rssi; + disassoc_comp->rx_rate = csr_roaminfo->rx_rate; + disassoc_comp->tx_rate = csr_roaminfo->tx_rate; + disassoc_comp->rx_mc_bc_cnt = csr_roaminfo->rx_mc_bc_cnt; + disassoc_comp->rx_retry_cnt = csr_roaminfo->rx_retry_cnt; + disassoc_comp->reason_code = csr_roaminfo->disassoc_reason; + break; + + case eSAP_STA_SET_KEY_EVENT: + + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + sap_ap_event->sapHddEventCode = eSAP_STA_SET_KEY_EVENT; + key_complete = + &sap_ap_event->sapevt.sapStationSetKeyCompleteEvent; + key_complete->status = (eSapStatus) context; + qdf_copy_macaddr(&key_complete->peerMacAddr, + &csr_roaminfo->peerMac); + break; + + case eSAP_STA_MIC_FAILURE_EVENT: + + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + sap_ap_event->sapHddEventCode = eSAP_STA_MIC_FAILURE_EVENT; + mic_failure = &sap_ap_event->sapevt.sapStationMICFailureEvent; + + qdf_mem_copy(&mic_failure->srcMacAddr, + csr_roaminfo->u.pMICFailureInfo->srcMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(&mic_failure->staMac.bytes, + csr_roaminfo->u.pMICFailureInfo->taMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(&mic_failure->dstMacAddr.bytes, + csr_roaminfo->u.pMICFailureInfo->dstMacAddr, + sizeof(tSirMacAddr)); + mic_failure->multicast = + csr_roaminfo->u.pMICFailureInfo->multicast; + mic_failure->IV1 = csr_roaminfo->u.pMICFailureInfo->IV1; + mic_failure->keyId = csr_roaminfo->u.pMICFailureInfo->keyId; + qdf_mem_copy(mic_failure->TSC, + csr_roaminfo->u.pMICFailureInfo->TSC, + SIR_CIPHER_SEQ_CTR_SIZE); + break; + + case eSAP_WPS_PBC_PROBE_REQ_EVENT: + + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + sap_ap_event->sapHddEventCode = eSAP_WPS_PBC_PROBE_REQ_EVENT; + + qdf_mem_copy(&sap_ap_event->sapevt.sapPBCProbeReqEvent. + WPSPBCProbeReq, csr_roaminfo->u.pWPSPBCProbeReq, + sizeof(tSirWPSPBCProbeReq)); + break; + + case eSAP_DISCONNECT_ALL_P2P_CLIENT: + sap_ap_event->sapHddEventCode = eSAP_DISCONNECT_ALL_P2P_CLIENT; + sap_ap_event->sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_MAC_TRIG_STOP_BSS_EVENT: + sap_ap_event->sapHddEventCode = eSAP_MAC_TRIG_STOP_BSS_EVENT; + sap_ap_event->sapevt.sapActionCnf.actionSendSuccess = + (eSapStatus) context; + break; + + case eSAP_UNKNOWN_STA_JOIN: + sap_ap_event->sapHddEventCode = eSAP_UNKNOWN_STA_JOIN; + qdf_mem_copy((void *)sap_ap_event->sapevt.sapUnknownSTAJoin. + macaddr.bytes, (void *) context, + QDF_MAC_ADDR_SIZE); + break; + + case eSAP_MAX_ASSOC_EXCEEDED: + + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + sap_ap_event->sapHddEventCode = eSAP_MAX_ASSOC_EXCEEDED; + qdf_copy_macaddr(&sap_ap_event->sapevt. + sapMaxAssocExceeded.macaddr, + &csr_roaminfo->peerMac); + break; + + case eSAP_CHANNEL_CHANGE_EVENT: + /* + * Reconfig ACS result info. For DFS AP-AP Mode Sec AP ACS + * follows pri AP + */ + sap_ctx->acs_cfg->pri_ch_freq = sap_ctx->chan_freq; + sap_ctx->acs_cfg->ch_width = + sap_ctx->ch_params.ch_width; + sap_config_acs_result(MAC_HANDLE(mac_ctx), sap_ctx, + sap_ctx->sec_ch_freq); + + sap_ap_event->sapHddEventCode = eSAP_CHANNEL_CHANGE_EVENT; + + acs_selected = &sap_ap_event->sapevt.sap_ch_selected; + acs_selected->pri_ch_freq = sap_ctx->chan_freq; + acs_selected->ht_sec_ch_freq = sap_ctx->sec_ch_freq; + acs_selected->ch_width = + sap_ctx->acs_cfg->ch_width; + acs_selected->vht_seg0_center_ch_freq = + sap_ctx->acs_cfg->vht_seg0_center_ch_freq; + acs_selected->vht_seg1_center_ch_freq = + sap_ctx->acs_cfg->vht_seg1_center_ch_freq; + break; + + case eSAP_ECSA_CHANGE_CHAN_IND: + + if (!csr_roaminfo) { + sap_debug("Invalid CSR Roam Info"); + qdf_mem_free(sap_ap_event); + return QDF_STATUS_E_INVAL; + } + sap_debug("SAP event callback event = %s", + "eSAP_ECSA_CHANGE_CHAN_IND"); + sap_ap_event->sapHddEventCode = eSAP_ECSA_CHANGE_CHAN_IND; + sap_ap_event->sapevt.sap_chan_cng_ind.new_chan_freq = + csr_roaminfo->target_chan_freq; + break; + case eSAP_DFS_NEXT_CHANNEL_REQ: + sap_debug("SAP event callback event = %s", + "eSAP_DFS_NEXT_CHANNEL_REQ"); + sap_ap_event->sapHddEventCode = eSAP_DFS_NEXT_CHANNEL_REQ; + break; + case eSAP_STOP_BSS_DUE_TO_NO_CHNL: + sap_ap_event->sapHddEventCode = eSAP_STOP_BSS_DUE_TO_NO_CHNL; + sap_debug("stopping session_id:%d, bssid:"QDF_MAC_ADDR_FMT", chan_freq:%d", + sap_ctx->sessionId, + QDF_MAC_ADDR_REF(sap_ctx->self_mac_addr), + sap_ctx->chan_freq); + break; + + case eSAP_CHANNEL_CHANGE_RESP: + sap_ap_event->sapHddEventCode = eSAP_CHANNEL_CHANGE_RESP; + sap_ap_event->sapevt.sap_chan_cng_rsp.ch_change_rsp_status = + (eSapStatus)context; + acs_selected = + &sap_ap_event->sapevt.sap_chan_cng_rsp.sap_ch_selected; + acs_selected->pri_ch_freq = sap_ctx->chan_freq; + acs_selected->ht_sec_ch_freq = sap_ctx->sec_ch_freq; + acs_selected->ch_width = + sap_ctx->ch_params.ch_width; + acs_selected->vht_seg0_center_ch_freq = + sap_ctx->ch_params.mhz_freq_seg0; + acs_selected->vht_seg1_center_ch_freq = + sap_ctx->ch_params.mhz_freq_seg1; + sap_update_cac_history(mac_ctx, sap_ctx, + sap_hddevent); + sap_debug("SAP event callback event = %s", + "eSAP_CHANNEL_CHANGE_RESP"); + break; + + default: + sap_err("SAP Unknown callback event = %d", sap_hddevent); + break; + } + qdf_status = (*sap_ctx->sap_event_cb) + (sap_ap_event, sap_ctx->user_context); + + qdf_mem_free(sap_ap_event); + + return qdf_status; +} + +bool sap_is_dfs_cac_wait_state(struct sap_context *sap_ctx) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + + if (!sap_ctx) { + sap_err("Invalid sap context"); + return false; + } + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + return false; + + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return false; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + sap_ctx->sessionId, + WLAN_DFS_ID); + if (!vdev) { + sap_err("vdev is NULL for vdev_id: %u", sap_ctx->sessionId); + return false; + } + + status = wlan_vdev_is_dfs_cac_wait(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_DFS_ID); + + return QDF_IS_STATUS_SUCCESS(status); +} + +/** + * sap_find_cac_wait_session() - Get context of a SAP session in CAC wait state + * @handle: Global MAC handle + * + * Finds and gets the context of a SAP session in CAC wait state. + * + * Return: Valid SAP context on success, else NULL + */ +static struct sap_context *sap_find_cac_wait_session(mac_handle_t handle) +{ + struct mac_context *mac = MAC_CONTEXT(handle); + uint8_t i = 0; + struct sap_context *sap_ctx; + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + sap_ctx = mac->sap.sapCtxList[i].sap_context; + if (((QDF_SAP_MODE == mac->sap.sapCtxList[i].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[i].sapPersona)) && + (sap_is_dfs_cac_wait_state(sap_ctx))) { + sap_debug("found SAP in cac wait state"); + return sap_ctx; + } + if (sap_ctx) { + sap_debug("sapdfs: mode:%d intf:%d state:%d", + mac->sap.sapCtxList[i].sapPersona, i, + sap_ctx->fsm_state); + } + } + + return NULL; +} + +void sap_cac_reset_notify(mac_handle_t mac_handle) +{ + uint8_t intf = 0; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context = + mac->sap.sapCtxList[intf].sap_context; + if (((QDF_SAP_MODE == mac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[intf].sapPersona)) + && mac->sap.sapCtxList[intf].sap_context) { + sap_context->isCacStartNotified = false; + sap_context->isCacEndNotified = false; + } + } +} + +/** + * sap_cac_start_notify() - Notify CAC start to HDD + * @mac_handle: Opaque handle to the global MAC context + * + * Function will be called to notify eSAP_DFS_CAC_START event to HDD + * + * Return: QDF_STATUS_SUCCESS if the notification was sent, otherwise + * an appropriate QDF_STATUS error + */ +static QDF_STATUS sap_cac_start_notify(mac_handle_t mac_handle) +{ + uint8_t intf = 0; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context = + mac->sap.sapCtxList[intf].sap_context; + + if (((QDF_SAP_MODE == mac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[intf].sapPersona)) + && mac->sap.sapCtxList[intf].sap_context && + (false == sap_context->isCacStartNotified)) { + /* Don't start CAC for non-dfs channel, its violation */ + if (!sap_operating_on_dfs( + mac, + mac->sap.sapCtxList[intf].sap_context)) + continue; + sap_debug("sapdfs: Signaling eSAP_DFS_CAC_START to HDD for sapctx[%pK]", + sap_context); + + qdf_status = sap_signal_hdd_event(sap_context, NULL, + eSAP_DFS_CAC_START, + (void *) + eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + sap_err("Failed setting isCacStartNotified on interface[%d]", + intf); + return qdf_status; + } + sap_context->isCacStartNotified = true; + } + } + return qdf_status; +} + +#ifdef PRE_CAC_SUPPORT +/** + * wlansap_pre_cac_end_notify() - Update pre cac end to upper layer + * @sap_context: SAP context + * @mac: Global MAC structure + * @intf: Interface number + * + * Notifies pre cac end to upper layer + * + * Return: None + */ +static void wlansap_pre_cac_end_notify(struct sap_context *sap_context, + struct mac_context *mac, + uint8_t intf) +{ + sap_context->isCacEndNotified = true; + sap_context->sap_radar_found_status = false; + sap_context->fsm_state = SAP_STARTED; + sap_warn("sap_fsm: vdev %d => SAP_STARTED, pre cac end notify on %d", + sap_context->vdev_id, intf); + wlan_pre_cac_handle_cac_end(sap_context->vdev); +} +#endif + +QDF_STATUS sap_cac_end_notify(mac_handle_t mac_handle, + struct csr_roam_info *roamInfo) +{ + uint8_t intf; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + bool is_acs; + + /* + * eSAP_DFS_CHANNEL_CAC_END: + * CAC Period elapsed and there was no radar + * found so, SAP can continue beaconing. + * sap_radar_found_status is set to 0 + */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *sap_context = + mac->sap.sapCtxList[intf].sap_context; + + if (((QDF_SAP_MODE == mac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[intf].sapPersona)) + && mac->sap.sapCtxList[intf].sap_context && + (false == sap_context->isCacEndNotified) && + sap_is_dfs_cac_wait_state(sap_context)) { + sap_context = mac->sap.sapCtxList[intf].sap_context; + /* Don't check CAC for non-dfs channel */ + if (!sap_operating_on_dfs( + mac, + mac->sap.sapCtxList[intf].sap_context)) + continue; + + /* If this is an end notification of a pre cac, the + * SAP must not start beaconing and must delete the + * temporary interface created for pre cac and switch + * the original SAP to the pre CAC channel. + */ + if (wlan_pre_cac_get_status(mac->psoc)) { + wlansap_pre_cac_end_notify(sap_context, + mac, intf); + /* pre CAC is not allowed with any concurrency. + * So, we can break from here. + */ + break; + } + + qdf_status = sap_signal_hdd_event(sap_context, NULL, + eSAP_DFS_CAC_END, + (void *) + eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + sap_err("failed setting isCacEndNotified on interface[%d]", + intf); + return qdf_status; + } + sap_context->isCacEndNotified = true; + sap_context->sap_radar_found_status = false; + sap_debug("sapdfs: Start beacon request on sapctx[%pK]", + sap_context); + + /* Start beaconing on the new channel */ + wlansap_start_beacon_req(sap_context); + + /* Transition from SAP_STARTING to SAP_STARTED + * (both without substates) + */ + sap_context->fsm_state = SAP_STARTED; + sap_debug("sap_fsm: vdev %d: SAP_STARTING => SAP_STARTED, freq %d", + sap_context->vdev_id, sap_context->chan_freq); + + /*Action code for transition */ + qdf_status = sap_signal_hdd_event(sap_context, roamInfo, + eSAP_START_BSS_EVENT, + (void *) + eSAP_STATUS_SUCCESS); + if (QDF_STATUS_SUCCESS != qdf_status) { + sap_err("Failed setting isCacEndNotified on interface[%d]", + intf); + return qdf_status; + } + + /* + * CAC wait prevent SAP restart, check if need + * restart SAP after CAC end + */ + is_acs = sap_context->acs_cfg && + sap_context->acs_cfg->acs_mode; + policy_mgr_check_concurrent_intf_and_restart_sap(mac->psoc, + is_acs); + } + } + + return qdf_status; +} + +/** + * sap_validate_dfs_nol() - Validate SAP channel with NOL list + * @sap_ctx: SAP context + * @mac_ctx: pointer to mac context + * + * Function will be called to validate SAP channel and bonded sub channels + * included in DFS NOL or not. + * + * Return: QDF_STATUS_SUCCESS for NOT in NOL + */ +static QDF_STATUS sap_validate_dfs_nol(struct sap_context *sap_ctx, + struct mac_context *mac_ctx) +{ + bool b_leak_chan = false; + uint16_t temp_freq; + uint16_t sap_freq; + enum channel_state ch_state; + bool is_chan_nol = false; + + sap_freq = sap_ctx->chan_freq; + temp_freq = sap_freq; + utils_dfs_mark_leaking_chan_for_freq(mac_ctx->pdev, + sap_ctx->ch_params.ch_width, 1, + &temp_freq); + + /* + * if selelcted channel has leakage to channels + * in NOL, the temp_freq will be reset + */ + b_leak_chan = (temp_freq != sap_freq); + /* + * check if channel is in DFS_NOL or if the channel + * has leakage to the channels in NOL + */ + + if (sap_phymode_is_eht(sap_ctx->phyMode)) { + ch_state = + wlan_reg_get_channel_state_from_secondary_list_for_freq( + mac_ctx->pdev, sap_freq); + if (CHANNEL_STATE_ENABLE != ch_state && + CHANNEL_STATE_DFS != ch_state) { + sap_err_rl("Invalid sap freq = %d, ch state=%d", + sap_freq, ch_state); + is_chan_nol = true; + } + } else { + is_chan_nol = sap_dfs_is_channel_in_nol_list( + sap_ctx, sap_ctx->chan_freq, + PHY_CHANNEL_BONDING_STATE_MAX); + } + + if (is_chan_nol || b_leak_chan) { + qdf_freq_t chan_freq; + + /* find a new available channel */ + chan_freq = sap_random_channel_sel(sap_ctx); + if (!chan_freq) { + /* No available channel found */ + sap_err("No available channel found!!!"); + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, + (void *)eSAP_STATUS_SUCCESS); + return QDF_STATUS_E_FAULT; + } + + sap_debug("ch_freq %d is in NOL, start bss on new freq %d", + sap_ctx->chan_freq, chan_freq); + + sap_ctx->chan_freq = chan_freq; + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(&sap_ctx->ch_params, + true); + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + sap_ctx->chan_freq, + sap_ctx->sec_ch_freq, + &sap_ctx->ch_params, + REG_CURRENT_PWR_MODE); + } + + return QDF_STATUS_SUCCESS; +} + +static void sap_validate_chanmode_and_chwidth(struct mac_context *mac_ctx, + struct sap_context *sap_ctx) +{ + uint32_t orig_phymode; + enum phy_ch_width orig_ch_width; + + orig_ch_width = sap_ctx->ch_params.ch_width; + orig_phymode = sap_ctx->phyMode; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(sap_ctx->chan_freq) && + (sap_ctx->phyMode == eCSR_DOT11_MODE_11g || + sap_ctx->phyMode == eCSR_DOT11_MODE_11g_ONLY)) { + sap_ctx->phyMode = eCSR_DOT11_MODE_11a; + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_ctx->chan_freq) && + (sap_ctx->phyMode == eCSR_DOT11_MODE_11a)) { + sap_ctx->phyMode = eCSR_DOT11_MODE_11g; + } + + if (sap_ctx->ch_params.ch_width > CH_WIDTH_20MHZ && + (sap_ctx->phyMode == eCSR_DOT11_MODE_abg || + sap_ctx->phyMode == eCSR_DOT11_MODE_11a || + sap_ctx->phyMode == eCSR_DOT11_MODE_11g || + sap_ctx->phyMode == eCSR_DOT11_MODE_11b)) { + sap_ctx->ch_params.ch_width = CH_WIDTH_20MHZ; + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + sap_ctx->chan_freq, + sap_ctx->ch_params.sec_ch_offset, + &sap_ctx->ch_params, + REG_CURRENT_PWR_MODE); + } else if (sap_ctx->ch_params.ch_width > CH_WIDTH_40MHZ && + sap_ctx->phyMode == eCSR_DOT11_MODE_11n) { + sap_ctx->ch_params.ch_width = CH_WIDTH_40MHZ; + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + sap_ctx->chan_freq, + sap_ctx->ch_params.sec_ch_offset, + &sap_ctx->ch_params, + REG_CURRENT_PWR_MODE); + } + + if (orig_ch_width != sap_ctx->ch_params.ch_width || + orig_phymode != sap_ctx->phyMode) + sap_info("Freq %d Updated BW %d -> %d , phymode %d -> %d", + sap_ctx->chan_freq, orig_ch_width, + sap_ctx->ch_params.ch_width, + orig_phymode, sap_ctx->phyMode); +} + +static bool +wlansap_is_power_change_required(struct mac_context *mac_ctx, + qdf_freq_t sap_freq) +{ + struct wlan_objmgr_vdev *sta_vdev; + uint8_t sta_vdev_id; + enum hw_mode_bandwidth ch_wd; + uint8_t country[CDS_COUNTRY_CODE_LEN + 1]; + enum channel_state state; + uint32_t ap_pwr_type_6g = 0; + bool indoor_ch_support = false; + + if (!mac_ctx || !mac_ctx->psoc || !mac_ctx->pdev) + return false; + + if (!policy_mgr_is_sta_present_on_freq(mac_ctx->psoc, &sta_vdev_id, + sap_freq, &ch_wd)) { + return false; + } + + sta_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + sta_vdev_id, + WLAN_LEGACY_SAP_ID); + if (!sta_vdev) + return false; + + ap_pwr_type_6g = wlan_mlme_get_6g_ap_power_type(sta_vdev); + + wlan_objmgr_vdev_release_ref(sta_vdev, WLAN_LEGACY_SAP_ID); + + if (ap_pwr_type_6g == REG_VERY_LOW_POWER_AP) + return false; + ucfg_mlme_get_indoor_channel_support(mac_ctx->psoc, &indoor_ch_support); + + if (ap_pwr_type_6g == REG_INDOOR_AP && indoor_ch_support) { + sap_debug("STA is connected to Indoor AP and indoor concurrency is supported"); + return false; + } + + wlan_reg_read_current_country(mac_ctx->psoc, country); + if (!wlan_reg_ctry_support_vlp(country)) { + sap_debug("Device country doesn't support VLP"); + return false; + } + + state = wlan_reg_get_channel_state_for_pwrmode(mac_ctx->pdev, + sap_freq, REG_AP_VLP); + + return state & CHANNEL_STATE_ENABLE; +} + +/** + * sap_goto_starting() - Trigger softap start + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @mac_handle: Opaque handle to the global MAC context + * + * This function triggers start of softap. Before starting, it can select + * new channel if given channel has leakage or if given channel in DFS_NOL. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_goto_starting(struct sap_context *sap_ctx, + struct sap_sm_event *sap_event, + struct mac_context *mac_ctx, + mac_handle_t mac_handle) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct bss_dot11_config dot11_cfg = {0}; + tSirMacRateSet *opr_rates = &sap_ctx->sap_bss_cfg.operationalRateSet; + tSirMacRateSet *ext_rates = &sap_ctx->sap_bss_cfg.extendedRateSet; + uint8_t h2e; + + /* + * check if channel is in DFS_NOL or if the channel + * has leakage to the channels in NOL. + */ + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ctx->chan_freq)) { + qdf_status = sap_validate_dfs_nol(sap_ctx, mac_ctx); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + return qdf_status; + } else if (!policy_mgr_get_ap_6ghz_capable(mac_ctx->psoc, + sap_ctx->sessionId, NULL)) { + return QDF_STATUS_E_FAILURE; + } else if (wlansap_is_power_change_required(mac_ctx, + sap_ctx->chan_freq)) { + wlan_set_tpc_update_required_for_sta(sap_ctx->vdev, true); + } + + /* + * when AP2 is started while AP1 is performing ACS, we may not + * have the AP1 channel yet.So here after the completion of AP2 + * ACS check if AP1 ACS resulting channel is DFS and if yes + * override AP2 ACS scan result with AP1 DFS channel + */ + if (policy_mgr_concurrent_beaconing_sessions_running(mac_ctx->psoc)) { + uint32_t con_ch_freq; + uint16_t con_ch; + + con_ch_freq = sme_get_beaconing_concurrent_operation_channel( + mac_handle, sap_ctx->sessionId); + con_ch = wlan_reg_freq_to_chan(mac_ctx->pdev, con_ch_freq); + /* Overwrite second AP's channel with first only when: + * 1. If operating mode is single mac + * 2. or if 2nd AP is coming up on 5G band channel + */ + if ((!policy_mgr_is_hw_dbs_capable(mac_ctx->psoc) || + WLAN_REG_IS_5GHZ_CH_FREQ(sap_ctx->chan_freq)) && + con_ch && + wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + con_ch_freq)) { + sap_ctx->chan_freq = con_ch_freq; + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap( + &sap_ctx->ch_params, true); + wlan_reg_set_channel_params_for_pwrmode( + mac_ctx->pdev, + con_ch_freq, 0, + &sap_ctx->ch_params, + REG_CURRENT_PWR_MODE); + } + } + + sap_validate_chanmode_and_chwidth(mac_ctx, sap_ctx); + /* Channel selected. Now can sap_goto_starting */ + sap_ctx->fsm_state = SAP_STARTING; + sap_debug("sap_fsm: vdev %d: SAP_INIT => SAP_STARTING, phyMode %d bw %d", + sap_ctx->vdev_id, sap_ctx->phyMode, + sap_ctx->ch_params.ch_width); + /* Specify the channel */ + sap_get_cac_dur_dfs_region(sap_ctx, + &sap_ctx->sap_bss_cfg.cac_duration_ms, + &sap_ctx->sap_bss_cfg.dfs_regdomain, + sap_ctx->chan_freq, + &sap_ctx->ch_params); + mlme_set_cac_required(sap_ctx->vdev, + !!sap_ctx->sap_bss_cfg.cac_duration_ms); + + sap_ctx->sap_bss_cfg.oper_ch_freq = sap_ctx->chan_freq; + sap_ctx->sap_bss_cfg.vht_channel_width = sap_ctx->ch_params.ch_width; + sap_ctx->sap_bss_cfg.center_freq_seg0 = + sap_ctx->ch_params.center_freq_seg0; + sap_ctx->sap_bss_cfg.center_freq_seg1 = + sap_ctx->ch_params.center_freq_seg1; + sap_ctx->sap_bss_cfg.sec_ch_offset = sap_ctx->ch_params.sec_ch_offset; + + dot11_cfg.vdev_id = sap_ctx->sessionId; + dot11_cfg.bss_op_ch_freq = sap_ctx->chan_freq; + dot11_cfg.phy_mode = sap_ctx->phyMode; + dot11_cfg.privacy = sap_ctx->sap_bss_cfg.privacy; + + qdf_mem_copy(dot11_cfg.opr_rates.rate, + opr_rates->rate, opr_rates->numRates); + dot11_cfg.opr_rates.numRates = opr_rates->numRates; + + qdf_mem_copy(dot11_cfg.ext_rates.rate, + ext_rates->rate, ext_rates->numRates); + dot11_cfg.ext_rates.numRates = ext_rates->numRates; + + sme_get_network_params(mac_ctx, &dot11_cfg); + + sap_ctx->sap_bss_cfg.nwType = dot11_cfg.nw_type; + sap_ctx->sap_bss_cfg.dot11mode = dot11_cfg.dot11_mode; + + if (dot11_cfg.opr_rates.numRates) { + qdf_mem_copy(opr_rates->rate, + dot11_cfg.opr_rates.rate, + dot11_cfg.opr_rates.numRates); + opr_rates->numRates = dot11_cfg.opr_rates.numRates; + } else { + qdf_mem_zero(opr_rates, sizeof(tSirMacRateSet)); + } + + if (dot11_cfg.ext_rates.numRates) { + qdf_mem_copy(ext_rates->rate, + dot11_cfg.ext_rates.rate, + dot11_cfg.ext_rates.numRates); + ext_rates->numRates = dot11_cfg.ext_rates.numRates; + } else { + qdf_mem_zero(ext_rates, sizeof(tSirMacRateSet)); + } + + if (sap_ctx->require_h2e) { + h2e = WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_SAE_H2E; + if (ext_rates->numRates < SIR_MAC_MAX_NUMBER_OF_RATES) { + ext_rates->rate[ext_rates->numRates] = h2e; + ext_rates->numRates++; + sap_debug("H2E bss membership add to ext support rate"); + } else if (opr_rates->numRates < SIR_MAC_MAX_NUMBER_OF_RATES) { + opr_rates->rate[opr_rates->numRates] = h2e; + opr_rates->numRates++; + sap_debug("H2E bss membership add to support rate"); + } else { + sap_err("rates full, can not add H2E bss membership"); + } + } + sap_dfs_set_current_channel(sap_ctx); + /* Reset radar found flag before start sap, the flag will + * be set when radar found in CAC wait. + */ + sap_ctx->sap_radar_found_status = false; + + sap_debug("session: %d", sap_ctx->sessionId); + + qdf_status = sme_start_bss(mac_handle, sap_ctx->sessionId, + &sap_ctx->sap_bss_cfg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sap_err("Failed to issue sme_roam_connect"); + + return qdf_status; +} + +/** + * sap_fsm_cac_start() - start cac wait timer + * @sap_ctx: SAP context + * @mac_ctx: global MAC context + * @mac_handle: Opaque handle to the global MAC context + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_cac_start(struct sap_context *sap_ctx, + struct mac_context *mac_ctx, + mac_handle_t mac_handle) +{ + if (!mac_ctx->sap.SapDfsInfo.is_dfs_cac_timer_running) { + sap_debug("sapdfs: starting dfs cac timer on sapctx[%pK]", + sap_ctx); + sap_start_dfs_cac_timer(sap_ctx); + } + + return sap_cac_start_notify(mac_handle); +} + +/** + * sap_fsm_state_init() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @mac_handle: Opaque handle to the global MAC context + * + * This function is called for state transition from "SAP_INIT" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_init(struct sap_context *sap_ctx, + struct sap_sm_event *sap_event, + struct mac_context *mac_ctx, + mac_handle_t mac_handle) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_START_INFRA_BSS) { + /* init dfs channel nol */ + sap_init_dfs_channel_nol_list(sap_ctx); + + /* + * Perform sme_ScanRequest. This scan request is post start bss + * request so, set the third to false. + */ + qdf_status = sap_validate_chan(sap_ctx, false, true); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sap_err("vdev %d: channel is not valid!", + sap_ctx->vdev_id); + goto exit; + } + + qdf_status = sap_goto_starting(sap_ctx, sap_event, + mac_ctx, mac_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) + sap_err("vdev %d: sap_goto_starting failed", + sap_ctx->vdev_id); + } else { + sap_err("sap_fsm: vdev %d: SAP_INIT, invalid event %d", + sap_ctx->vdev_id, msg); + } + +exit: + return qdf_status; +} + +/** + * sap_fsm_handle_radar_during_cac() - uhandle radar event during cac + * @sap_ctx: SAP context + * @mac_ctx: global MAC context + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_handle_radar_during_cac(struct sap_context *sap_ctx, + struct mac_context *mac_ctx) +{ + uint8_t intf; + + if (mac_ctx->sap.SapDfsInfo.target_chan_freq) { + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(&sap_ctx->ch_params, + true); + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, + mac_ctx->sap.SapDfsInfo.target_chan_freq, 0, + &sap_ctx->ch_params, REG_CURRENT_PWR_MODE); + } else { + sap_err("Invalid target channel freq %d", + mac_ctx->sap.SapDfsInfo.target_chan_freq); + return QDF_STATUS_E_FAILURE; + } + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *t_sap_ctx; + + t_sap_ctx = mac_ctx->sap.sapCtxList[intf].sap_context; + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + t_sap_ctx && t_sap_ctx->fsm_state != SAP_INIT) { + if (!sap_operating_on_dfs(mac_ctx, t_sap_ctx)) + continue; + t_sap_ctx->is_chan_change_inprogress = true; + /* + * eSAP_DFS_CHANNEL_CAC_RADAR_FOUND: + * A Radar is found on current DFS Channel + * while in CAC WAIT period So, do a channel + * switch to randomly selected target channel. + * Send the Channel change message to SME/PE. + * sap_radar_found_status is set to 1 + */ + wlansap_channel_change_request(t_sap_ctx, + mac_ctx->sap.SapDfsInfo.target_chan_freq); + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_fsm_handle_start_failure() - handle sap start failure + * @sap_ctx: SAP context + * @msg: event msg + * @mac_handle: Opaque handle to the global MAC context + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_handle_start_failure(struct sap_context *sap_ctx, + uint32_t msg, + mac_handle_t mac_handle) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Stop the CAC timer only in following conditions + * single AP: if there is a single AP then stop timer + * multiple APs: incase of multiple APs, make sure that + * all APs are down. + */ + if (!sap_find_valid_concurrent_session(mac_handle)) { + sap_debug("sapdfs: no sessions are valid, stopping timer"); + sap_stop_dfs_cac_timer(sap_ctx); + } + /* Transition from SAP_STARTING to SAP_STOPPING */ + sap_ctx->fsm_state = SAP_STOPPING; + sap_debug("sap_fsm: vdev %d: SAP_STARTING => SAP_STOPPING, start is in progress", + sap_ctx->vdev_id); + qdf_status = sap_goto_stopping(sap_ctx); + } else { + /* + * Transition from SAP_STARTING to SAP_INIT + * (both without substates) + */ + sap_ctx->fsm_state = SAP_INIT; + sap_debug("sap_fsm: vdev %d: SAP_STARTING => SAP_INIT", + sap_ctx->vdev_id); + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_START_BSS_EVENT, + (void *) + eSAP_STATUS_FAILURE); + qdf_status = sap_goto_init(sap_ctx); + } + + return qdf_status; +} + +/** + * sap_propagate_cac_events() - Indicate CAC START/END event + * @sap_ctx: SAP context + * + * This function is to indicate CAC START/END event if CAC process + * is skipped. + * + * Return: void + */ +static void sap_propagate_cac_events(struct sap_context *sap_ctx) +{ + QDF_STATUS qdf_status; + + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_CAC_START, + (void *) + eSAP_STATUS_SUCCESS); + if (qdf_status != QDF_STATUS_SUCCESS) { + sap_err("Failed to indicate CAC START vdev %d", + sap_ctx->sessionId); + return; + } + + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_CAC_END, + (void *) + eSAP_STATUS_SUCCESS); + if (qdf_status != QDF_STATUS_SUCCESS) { + sap_debug("Failed to indicate CAC End vdev %d", + sap_ctx->sessionId); + } +} + +static void sap_check_and_update_vdev_ch_params(struct sap_context *sap_ctx) +{ + struct wlan_channel *chan; + enum phy_ch_width orig_ch_width; + + chan = wlan_vdev_get_active_channel(sap_ctx->vdev); + if (!chan) { + sap_debug("Couldn't get vdev active channel"); + return; + } + if (sap_ctx->ch_params.ch_width == chan->ch_width) + return; + + orig_ch_width = sap_ctx->ch_params.ch_width; + + sap_ctx->ch_params.ch_width = chan->ch_width; + sap_ctx->ch_params.center_freq_seg0 = chan->ch_freq_seg1; + sap_ctx->ch_params.center_freq_seg1 = chan->ch_freq_seg2; + sap_ctx->ch_params.mhz_freq_seg0 = chan->ch_cfreq1; + sap_ctx->ch_params.mhz_freq_seg1 = chan->ch_cfreq2; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(sap_ctx->chan_freq) && + (chan->ch_width == CH_WIDTH_40MHZ)) { + if (sap_ctx->chan_freq < chan->ch_freq_seg1) + sap_ctx->ch_params.sec_ch_offset = LOW_PRIMARY_CH; + else + sap_ctx->ch_params.sec_ch_offset = HIGH_PRIMARY_CH; + } + sap_debug("updated BW %d -> %d", orig_ch_width, + sap_ctx->ch_params.ch_width); +} + +/** + * sap_fsm_send_csa_restart_req() - send csa start event + * @mac_ctx: mac ctx + * @sap_ctx: SAP context + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +sap_fsm_send_csa_restart_req(struct mac_context *mac_ctx, + struct sap_context *sap_ctx) +{ + QDF_STATUS status; + + status = policy_mgr_check_and_set_hw_mode_for_channel_switch( + mac_ctx->psoc, sap_ctx->sessionId, + mac_ctx->sap.SapDfsInfo.target_chan_freq, + POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_SAP); + + /* + * If hw_mode_status is QDF_STATUS_E_FAILURE, mean HW + * mode change was required but driver failed to set HW + * mode so ignore CSA for the channel. + */ + if (status == QDF_STATUS_E_FAILURE) { + sap_err("HW change required but failed to set hw mode"); + return status; + } + + /* + * If hw_mode_status is QDF_STATUS_SUCCESS mean HW mode + * change was required and was successfully requested so + * the channel switch will continue after HW mode change + * completion. + */ + if (QDF_IS_STATUS_SUCCESS(status)) { + sap_info("Channel change will continue after HW mode change"); + return QDF_STATUS_SUCCESS; + } + + return sme_csa_restart(mac_ctx, sap_ctx->sessionId); +} + +bool wlansap_validate_channel_post_csa(mac_handle_t mac_handle, + struct sap_context *sap_ctx) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (((!sap_ctx->acs_cfg || !sap_ctx->acs_cfg->acs_mode) && + (!policy_mgr_restrict_sap_on_unsafe_chan(mac_ctx->psoc) || + target_psoc_get_sap_coex_fixed_chan_cap( + wlan_psoc_get_tgt_if_handle(mac_ctx->psoc)))) || + (policy_mgr_is_sap_freq_allowed(mac_ctx->psoc, + wlan_vdev_mlme_get_opmode(sap_ctx->vdev), + sap_ctx->chan_freq) && + !wlan_reg_is_disable_for_pwrmode(mac_ctx->pdev, sap_ctx->chan_freq, + REG_CURRENT_PWR_MODE))) + return true; + sap_debug("sap vdev %d on unsafe ch freq %d", + sap_ctx->sessionId, sap_ctx->chan_freq); + + return false; +} + +/** + * sap_fsm_state_starting() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @mac_handle: Opaque handle to the global MAC context + * + * This function is called for state transition from "SAP_STARTING" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_starting(struct sap_context *sap_ctx, + struct sap_sm_event *sap_event, + struct mac_context *mac_ctx, + mac_handle_t mac_handle) +{ + uint32_t msg = sap_event->event; + struct csr_roam_info *roam_info = + (struct csr_roam_info *) (sap_event->params); + tSapDfsInfo *sap_dfs_info; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint8_t is_dfs = false; + uint32_t sap_chan_freq; + uint32_t ch_cfreq1 = 0; + enum reg_wifi_band band; + eSapDfsCACState_t cac_state = eSAP_DFS_DO_NOT_SKIP_CAC; + + if (msg == eSAP_MAC_START_BSS_SUCCESS) { + /* + * Update sap_ctx->ch_params from vdev to make up with any BW + * change in lower layer + */ + sap_check_and_update_vdev_ch_params(sap_ctx); + + /* + * Transition from SAP_STARTING to SAP_STARTED + * (both without substates) + */ + sap_ctx->fsm_state = SAP_STARTED; + sap_debug("sap_fsm: vdev %d: SAP_STARTING => SAP_STARTED, freq %d ch_width %d", + sap_ctx->vdev_id, sap_ctx->chan_freq, + sap_ctx->ch_params.ch_width); + + if (sap_ctx->is_chan_change_inprogress) { + /* SAP channel change request processing is completed */ + qdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_CHANNEL_CHANGE_EVENT, + (void *)eSAP_STATUS_SUCCESS); + sap_ctx->is_chan_change_inprogress = false; + } else { + sap_debug("vdev %d notify hostapd about chan freq selection: %d", + sap_ctx->vdev_id, sap_ctx->chan_freq); + qdf_status = + sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_CHANNEL_CHANGE_EVENT, + (void *)eSAP_STATUS_SUCCESS); + /* Action code for transition */ + qdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *) eSAP_STATUS_SUCCESS); + } + sap_chan_freq = sap_ctx->chan_freq; + band = wlan_reg_freq_to_band(sap_ctx->chan_freq); + if (sap_ctx->ch_params.center_freq_seg1) + ch_cfreq1 = wlan_reg_chan_band_to_freq( + mac_ctx->pdev, + sap_ctx->ch_params.center_freq_seg1, + BIT(band)); + + /* + * The upper layers have been informed that AP is up and + * running, however, the AP is still not beaconing, until + * CAC is done if the operating channel is DFS + */ + if (sap_ctx->ch_params.ch_width == CH_WIDTH_160MHZ) { + struct ch_params ch_params = {0}; + + wlan_reg_set_create_punc_bitmap(&ch_params, true); + ch_params.ch_width = CH_WIDTH_160MHZ; + is_dfs = + wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac_ctx->pdev, + sap_chan_freq, + &ch_params, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS; + } else if (sap_ctx->ch_params.ch_width == CH_WIDTH_80P80MHZ) { + if (wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + sap_chan_freq, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS || + wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + ch_cfreq1, + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_DFS) + is_dfs = true; + } else { + /* Indoor channels are also marked DFS, therefore + * check if the channel has REGULATORY_CHAN_RADAR + * channel flag to identify if the channel is DFS + */ + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + sap_chan_freq)) + is_dfs = true; + } + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ctx->chan_freq)) + is_dfs = false; + + sap_debug("vdev %d freq %d, is_dfs %d", sap_ctx->vdev_id, + sap_ctx->chan_freq, is_dfs); + if (is_dfs) { + sap_dfs_info = &mac_ctx->sap.SapDfsInfo; + if (sap_plus_sap_cac_skip(mac_ctx, sap_ctx, + sap_chan_freq)) + cac_state = eSAP_DFS_SKIP_CAC; + if ((false == sap_dfs_info->ignore_cac) && + (cac_state == eSAP_DFS_DO_NOT_SKIP_CAC) && + !wlan_pre_cac_complete_get(sap_ctx->vdev) && + policy_mgr_get_dfs_master_dynamic_enabled( + mac_ctx->psoc, + sap_ctx->sessionId)) { + sap_ctx->fsm_state = SAP_STARTING; + sap_debug("sap_fsm: vdev %d: SAP_STARTED => SAP_STARTING to start cac timer", + sap_ctx->vdev_id); + qdf_status = sap_fsm_cac_start(sap_ctx, mac_ctx, + mac_handle); + } else { + sap_debug("vdev %d skip cac timer", + sap_ctx->vdev_id); + sap_ctx->sap_radar_found_status = false; + /* + * If hostapd starts AP on dfs channel, + * hostapd will wait for CAC START/CAC END + * event and finish AP start process. + * If we skip CAC timer, we will need to + * indicate the CAC event even though driver + * doesn't perform CAC. + */ + sap_propagate_cac_events(sap_ctx); + + wlansap_start_beacon_req(sap_ctx); + } + } + } else if (msg == eSAP_MAC_START_FAILS || + msg == eSAP_HDD_STOP_INFRA_BSS) { + qdf_status = sap_fsm_handle_start_failure(sap_ctx, msg, + mac_handle); + } else if (msg == eSAP_OPERATING_CHANNEL_CHANGED) { + /* The operating channel has changed, update hostapd */ + sap_ctx->chan_freq = mac_ctx->sap.SapDfsInfo.target_chan_freq; + + sap_ctx->fsm_state = SAP_STARTED; + sap_debug("sap_fsm: vdev %d: SAP_STARTING => SAP_STARTED", + sap_ctx->vdev_id); + + /* Indicate change in the state to upper layers */ + qdf_status = sap_signal_hdd_event(sap_ctx, roam_info, + eSAP_START_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } else if (msg == eSAP_DFS_CHANNEL_CAC_RADAR_FOUND) { + qdf_status = sap_fsm_handle_radar_during_cac(sap_ctx, mac_ctx); + } else if (msg == eSAP_DFS_CHANNEL_CAC_END) { + if (sap_ctx->vdev && + wlan_util_vdev_mgr_get_cac_timeout_for_vdev(sap_ctx->vdev)) { + qdf_status = sap_cac_end_notify(mac_handle, roam_info); + } else { + sap_debug("vdev %d cac duration is zero", + sap_ctx->vdev_id); + qdf_status = QDF_STATUS_SUCCESS; + } + } else if (msg == eSAP_DFS_CHANNEL_CAC_START) { + if (sap_ctx->is_chan_change_inprogress) { + sap_signal_hdd_event(sap_ctx, + NULL, + eSAP_CHANNEL_CHANGE_EVENT, + (void *)eSAP_STATUS_SUCCESS); + sap_ctx->is_chan_change_inprogress = false; + } + qdf_status = sap_fsm_cac_start(sap_ctx, mac_ctx, mac_handle); + } else { + sap_err("sap_fsm: vdev %d: SAP_STARTING, invalid event %d", + sap_ctx->vdev_id, msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_started() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * + * This function is called for state transition from "SAP_STARTED" + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_fsm_state_started(struct sap_context *sap_ctx, + struct sap_sm_event *sap_event, + struct mac_context *mac_ctx) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * Transition from SAP_STARTED to SAP_STOPPING + * (both without substates) + */ + sap_ctx->fsm_state = SAP_STOPPING; + sap_debug("sap_fsm: vdev %d: SAP_STARTED => SAP_STOPPING", + sap_ctx->vdev_id); + qdf_status = sap_goto_stopping(sap_ctx); + } else if (eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START == msg) { + uint8_t intf; + if (!mac_ctx->sap.SapDfsInfo.target_chan_freq) { + sap_err("Invalid target channel freq %d", + mac_ctx->sap.SapDfsInfo.target_chan_freq); + return qdf_status; + } + + /* + * Radar is seen on the current operating channel + * send CSA IE for all associated stations + * Request for CSA IE transmission + */ + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + struct sap_context *temp_sap_ctx; + + if (((QDF_SAP_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona) || + (QDF_P2P_GO_MODE == + mac_ctx->sap.sapCtxList[intf].sapPersona)) && + mac_ctx->sap.sapCtxList[intf].sap_context) { + temp_sap_ctx = + mac_ctx->sap.sapCtxList[intf].sap_context; + /* + * Radar won't come on non-dfs channel, so + * no need to move them + */ + if (!sap_operating_on_dfs( + mac_ctx, temp_sap_ctx)) { + sap_debug("vdev %d freq %d (state %d) is not DFS or disabled so continue", + temp_sap_ctx->sessionId, + temp_sap_ctx->chan_freq, + wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + temp_sap_ctx->chan_freq, + REG_CURRENT_PWR_MODE)); + continue; + } + sap_debug("vdev %d switch freq %d -> %d", + temp_sap_ctx->sessionId, + temp_sap_ctx->chan_freq, + mac_ctx->sap.SapDfsInfo.target_chan_freq); + qdf_status = + sap_fsm_send_csa_restart_req(mac_ctx, + temp_sap_ctx); + } + } + } else { + sap_err("sap_fsm: vdev %d: SAP_STARTED, invalid event %d", + sap_ctx->vdev_id, msg); + } + + return qdf_status; +} + +/** + * sap_fsm_state_stopping() - utility function called from sap fsm + * @sap_ctx: SAP context + * @sap_event: SAP event buffer + * @mac_ctx: global MAC context + * @mac_handle: Opaque handle to the global MAC context + * + * This function is called for state transition from "SAP_STOPPING" + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sap_fsm_state_stopping(struct sap_context *sap_ctx, + struct sap_sm_event *sap_event, + struct mac_context *mac_ctx, + mac_handle_t mac_handle) +{ + uint32_t msg = sap_event->event; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + if (msg == eSAP_MAC_READY_FOR_CONNECTIONS) { + /* + * Transition from SAP_STOPPING to SAP_INIT + * (both without substates) + */ + sap_ctx->fsm_state = SAP_INIT; + sap_debug("sap_fsm: vdev %d: SAP_STOPPING => SAP_INIT", + sap_ctx->vdev_id); + + /* Close the SME session */ + qdf_status = sap_signal_hdd_event(sap_ctx, NULL, + eSAP_STOP_BSS_EVENT, + (void *)eSAP_STATUS_SUCCESS); + } else if (msg == eSAP_HDD_STOP_INFRA_BSS) { + /* + * In case the SAP is already in stopping case and + * we get a STOP request, return success. + */ + sap_debug("vdev %d SAP already in Stopping state", + sap_ctx->vdev_id); + qdf_status = QDF_STATUS_SUCCESS; + } else { + sap_err("sap_fsm: vdev %d: SAP_STOPPING, invalid event %d", + sap_ctx->vdev_id, msg); + } + + return qdf_status; +} + +/** + * sap_fsm() - SAP statem machine entry function + * @sap_ctx: SAP context + * @sap_event: SAP event + * + * SAP state machine entry function + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_fsm(struct sap_context *sap_ctx, struct sap_sm_event *sap_event) +{ + /* + * Retrieve the phy link state machine structure + * from the sap_ctx value + * state var that keeps track of state machine + */ + enum sap_fsm_state state_var = sap_ctx->fsm_state; + uint32_t msg = sap_event->event; /* State machine input event message */ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAILURE; + } + mac_handle = MAC_HANDLE(mac_ctx); + + sap_debug("vdev %d: state %d event %d", sap_ctx->vdev_id, state_var, + msg); + + switch (state_var) { + case SAP_INIT: + qdf_status = sap_fsm_state_init(sap_ctx, sap_event, + mac_ctx, mac_handle); + break; + + case SAP_STARTING: + qdf_status = sap_fsm_state_starting(sap_ctx, sap_event, + mac_ctx, mac_handle); + break; + + case SAP_STARTED: + qdf_status = sap_fsm_state_started(sap_ctx, sap_event, + mac_ctx); + break; + + case SAP_STOPPING: + qdf_status = sap_fsm_state_stopping(sap_ctx, sap_event, + mac_ctx, mac_handle); + break; + } + return qdf_status; +} + +void sap_sort_mac_list(struct qdf_mac_addr *macList, uint16_t size) +{ + uint16_t outer, inner; + struct qdf_mac_addr temp; + int32_t nRes = -1; + + if ((!macList) || (size > MAX_ACL_MAC_ADDRESS)) { + sap_err("either buffer is NULL or size = %d is more", size); + return; + } + + for (outer = 0; outer < size; outer++) { + for (inner = 0; inner < size - 1; inner++) { + nRes = + qdf_mem_cmp((macList + inner)->bytes, + (macList + inner + 1)->bytes, + QDF_MAC_ADDR_SIZE); + if (nRes > 0) { + qdf_mem_copy(temp.bytes, + (macList + inner + 1)->bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy((macList + inner + 1)->bytes, + (macList + inner)->bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy((macList + inner)->bytes, + temp.bytes, QDF_MAC_ADDR_SIZE); + } + } + } +} + +bool +sap_search_mac_list(struct qdf_mac_addr *macList, + uint16_t num_mac, uint8_t *peerMac, + uint16_t *index) +{ + int32_t nRes = -1, nStart = 0, nEnd, nMiddle; + + nEnd = num_mac - 1; + + if ((!macList) || (num_mac > MAX_ACL_MAC_ADDRESS)) { + sap_err("either buffer is NULL or size = %d is more", num_mac); + return false; + } + + while (nStart <= nEnd) { + nMiddle = (nStart + nEnd) / 2; + nRes = + qdf_mem_cmp(&macList[nMiddle], peerMac, + QDF_MAC_ADDR_SIZE); + + if (0 == nRes) { + sap_debug("search SUCC"); + /* "index equals NULL" means the caller does not need the */ + /* index value of the peerMac being searched */ + if (index) { + *index = (uint16_t)nMiddle; + sap_debug("index %d", *index); + } + return true; + } + if (nRes < 0) + nStart = nMiddle + 1; + else + nEnd = nMiddle - 1; + } + + sap_debug("search not succ"); + return false; +} + +void sap_add_mac_to_acl(struct qdf_mac_addr *macList, + uint16_t *size, uint8_t *peerMac) +{ + int32_t nRes = -1; + int i; + + sap_debug("add acl entered"); + + if (!macList || *size > MAX_ACL_MAC_ADDRESS) { + sap_debug("either buffer is NULL or size = %d is incorrect", + *size); + return; + } + + for (i = ((*size) - 1); i >= 0; i--) { + nRes = + qdf_mem_cmp(&macList[i], peerMac, QDF_MAC_ADDR_SIZE); + if (nRes > 0) { + /* Move alphabetically greater mac addresses one index down to allow for insertion + of new mac in sorted order */ + qdf_mem_copy((macList + i + 1)->bytes, + (macList + i)->bytes, QDF_MAC_ADDR_SIZE); + } else { + break; + } + } + /* This should also take care of if the element is the first to be added in the list */ + qdf_mem_copy((macList + i + 1)->bytes, peerMac, QDF_MAC_ADDR_SIZE); + /* increment the list size */ + (*size)++; +} + +void sap_remove_mac_from_acl(struct qdf_mac_addr *macList, + uint16_t *size, uint16_t index) +{ + int i; + + sap_debug("remove acl entered"); + /* + * Return if the list passed is empty. Ideally this should never happen + * since this funcn is always called after sap_search_mac_list to get + * the index of the mac addr to be removed and this will only get + * called if the search is successful. Still no harm in having the check + */ + if ((!macList) || (*size == 0) || + (*size > MAX_ACL_MAC_ADDRESS)) { + sap_err("either buffer is NULL or size %d is incorrect", + *size); + return; + } + for (i = index; i < ((*size) - 1); i++) { + /* Move mac addresses starting from "index" passed one index up to delete the void + created by deletion of a mac address in ACL */ + qdf_mem_copy((macList + i)->bytes, (macList + i + 1)->bytes, + QDF_MAC_ADDR_SIZE); + } + /* The last space should be made empty since all mac addresses moved one step up */ + qdf_mem_zero((macList + (*size) - 1)->bytes, QDF_MAC_ADDR_SIZE); + /* reduce the list size by 1 */ + (*size)--; +} + +void sap_print_acl(struct qdf_mac_addr *macList, uint16_t size) +{ + uint16_t i; + uint8_t *macArray; + + sap_debug("print acl entered"); + + if ((!macList) || (size == 0) || (size > MAX_ACL_MAC_ADDRESS)) { + sap_err("Either buffer is NULL or size %d is incorrect", size); + return; + } + + for (i = 0; i < size; i++) { + macArray = (macList + i)->bytes; + sap_debug("** ACL entry %i - " QDF_MAC_ADDR_FMT, i, + QDF_MAC_ADDR_REF(macArray)); + } + return; +} + +QDF_STATUS sap_is_peer_mac_allowed(struct sap_context *sap_ctx, + uint8_t *peerMac) +{ + if (eSAP_ALLOW_ALL == sap_ctx->eSapMacAddrAclMode) + return QDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sap_ctx->acceptMacList, sap_ctx->nAcceptMac, peerMac, NULL)) + return QDF_STATUS_SUCCESS; + + if (sap_search_mac_list + (sap_ctx->denyMacList, sap_ctx->nDenyMac, peerMac, NULL)) { + sap_err("Peer " QDF_MAC_ADDR_FMT " in deny list", + QDF_MAC_ADDR_REF(peerMac)); + return QDF_STATUS_E_FAILURE; + } + /* A new station CAN associate, unless in deny list. Less stringent mode */ + if (eSAP_ACCEPT_UNLESS_DENIED == sap_ctx->eSapMacAddrAclMode) + return QDF_STATUS_SUCCESS; + + /* A new station CANNOT associate, unless in accept list. More stringent mode */ + if (eSAP_DENY_UNLESS_ACCEPTED == sap_ctx->eSapMacAddrAclMode) { + sap_debug("Peer " QDF_MAC_ADDR_FMT + " denied, Mac filter mode is eSAP_DENY_UNLESS_ACCEPTED", + QDF_MAC_ADDR_REF(peerMac)); + return QDF_STATUS_E_FAILURE; + } + + /* The new STA is neither in accept list nor in deny list. In this case, deny the association + * but send a wifi event notification indicating the mac address being denied + */ + if (eSAP_SUPPORT_ACCEPT_AND_DENY == sap_ctx->eSapMacAddrAclMode) { + sap_signal_hdd_event(sap_ctx, NULL, eSAP_UNKNOWN_STA_JOIN, + (void *) peerMac); + sap_debug("Peer " QDF_MAC_ADDR_FMT + " denied, Mac filter mode is eSAP_SUPPORT_ACCEPT_AND_DENY", + QDF_MAC_ADDR_REF(peerMac)); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +void sap_dump_acs_channel(struct sap_acs_cfg *acs_cfg) +{ + uint32_t buf_len = 0, len = 0, i; + uint8_t *chan_buff = NULL; + + /* + * Buffer of (num channel * 5) + 1 to consider the 4 char freq + * and 1 space after it for each channel and 1 to end the string + * with NULL. + */ + buf_len = (acs_cfg->ch_list_count * 5) + 1; + chan_buff = qdf_mem_malloc(buf_len); + if (!chan_buff) + return; + + for (i = 0; i < acs_cfg->ch_list_count; i++) + len += qdf_scnprintf(chan_buff + len, buf_len - len, + " %d", acs_cfg->freq_list[i]); + + sap_nofl_debug("ACS freq list[%d]:%s", + acs_cfg->ch_list_count, chan_buff); + qdf_mem_free(chan_buff); +} + +#ifdef SOFTAP_CHANNEL_RANGE +/** + * sap_get_freq_list() - get the list of channel frequency + * @sap_ctx: sap context + * @freq_list: pointer to channel list array + * @num_ch: pointer to number of channels. + * + * This function populates the list of channel frequency for scanning. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sap_get_freq_list(struct sap_context *sap_ctx, + uint32_t **freq_list, + uint8_t *num_ch) +{ + uint8_t loop_count; + uint32_t *list; + uint8_t ch_count; + uint8_t dfs_master_enable; + uint32_t start_ch_freq, band_start_ch; + uint32_t end_ch_freq, band_end_ch; + uint32_t en_lte_coex; + struct mac_context *mac_ctx; + uint16_t ch_width; + uint8_t normalize_factor = 100; + uint32_t chan_freq; + struct acs_weight *weight_list; + struct acs_weight_range *range_list; + bool freq_present_in_list = false; + uint8_t i; + bool srd_chan_enabled; + enum QDF_OPMODE vdev_opmode; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + *num_ch = 0; + *freq_list = NULL; + return QDF_STATUS_E_FAULT; + } + + weight_list = mac_ctx->mlme_cfg->acs.normalize_weight_chan; + range_list = mac_ctx->mlme_cfg->acs.normalize_weight_range; + + dfs_master_enable = mac_ctx->mlme_cfg->dfs_cfg.dfs_master_capable; + if (sap_ctx->dfs_mode == ACS_DFS_MODE_DISABLE) + dfs_master_enable = false; + + start_ch_freq = sap_ctx->acs_cfg->start_ch_freq; + end_ch_freq = sap_ctx->acs_cfg->end_ch_freq; + ch_width = sap_ctx->acs_cfg->ch_width; + + sap_debug("startChannel %d, EndChannel %d, ch_width %d, HW:%d", + start_ch_freq, end_ch_freq, ch_width, + sap_ctx->acs_cfg->hw_mode); + + wlansap_extend_to_acs_range(MAC_HANDLE(mac_ctx), + &start_ch_freq, &end_ch_freq, + &band_start_ch, &band_end_ch); + + sap_debug("expanded startChannel %d,EndChannel %d band_start_ch %d, band_end_ch %d", + start_ch_freq, end_ch_freq, band_start_ch, band_end_ch); + + en_lte_coex = mac_ctx->mlme_cfg->sap_cfg.enable_lte_coex; + + /* Check if LTE coex is enabled and 2.4GHz is selected */ + if (en_lte_coex && (band_start_ch == CHAN_ENUM_2412) && + (band_end_ch == CHAN_ENUM_2484)) { + /* Set 2.4GHz upper limit to channel 9 for LTE COEX */ + band_end_ch = CHAN_ENUM_2452; + } + + /* Allocate the max number of channel supported */ + list = qdf_mem_malloc((NUM_CHANNELS) * sizeof(uint32_t)); + if (!list) { + *num_ch = 0; + *freq_list = NULL; + return QDF_STATUS_E_NOMEM; + } + + /* Search for the Active channels in the given range */ + ch_count = 0; + for (loop_count = band_start_ch; loop_count <= band_end_ch; + loop_count++) { + chan_freq = WLAN_REG_CH_TO_FREQ(loop_count); + + /* go to next channel if rf_channel is out of range */ + if (start_ch_freq > WLAN_REG_CH_TO_FREQ(loop_count) || + end_ch_freq < WLAN_REG_CH_TO_FREQ(loop_count)) + continue; + /* + * go to next channel if none of these condition pass + * - DFS scan enabled and chan not in CHANNEL_STATE_DISABLE + * - DFS scan disable but chan in CHANNEL_STATE_ENABLE + */ + if (!(((true == mac_ctx->scan.fEnableDFSChnlScan) && + wlan_reg_get_channel_state_from_secondary_list_for_freq( + mac_ctx->pdev, WLAN_REG_CH_TO_FREQ(loop_count))) + || + ((false == mac_ctx->scan.fEnableDFSChnlScan) && + (CHANNEL_STATE_ENABLE == + wlan_reg_get_channel_state_from_secondary_list_for_freq( + mac_ctx->pdev, WLAN_REG_CH_TO_FREQ(loop_count))) + ))) + continue; + + /* check if the channel is in NOL denylist */ + if (!WLAN_REG_IS_6GHZ_CHAN_FREQ(WLAN_REG_CH_TO_FREQ( + loop_count))) { + if (sap_dfs_is_channel_in_nol_list( + sap_ctx, + chan_freq, + PHY_SINGLE_CHANNEL_CENTERED)) { + sap_debug("Ch freq %d in NOL list", chan_freq); + continue; + } + } + /* Skip DSRC channels */ + if (wlan_reg_is_dsrc_freq(WLAN_REG_CH_TO_FREQ(loop_count))) + continue; + + /* + * Skip the channels which are not in ACS config from user + * space + */ + if (!wlansap_is_channel_present_in_acs_list( + chan_freq, + sap_ctx->acs_cfg->freq_list, + sap_ctx->acs_cfg->ch_list_count)) + continue; + /* Dont scan DFS channels in case of MCC disallowed + * As it can result in SAP starting on DFS channel + * resulting MCC on DFS channel + */ + if (wlan_reg_is_dfs_in_secondary_list_for_freq( + mac_ctx->pdev, + WLAN_REG_CH_TO_FREQ(loop_count))) { + if (!dfs_master_enable) + continue; + if (wlansap_dcs_is_wlan_interference_mitigation_enabled( + sap_ctx)) + sap_debug("dfs chan_freq %d added when dcs enabled", + WLAN_REG_CH_TO_FREQ(loop_count)); + else if (policy_mgr_disallow_mcc( + mac_ctx->psoc, + WLAN_REG_CH_TO_FREQ(loop_count))) + continue; + normalize_factor = + MLME_GET_DFS_CHAN_WEIGHT( + mac_ctx->mlme_cfg->acs.np_chan_weightage); + freq_present_in_list = true; + } + + vdev_opmode = wlan_vdev_mlme_get_opmode(sap_ctx->vdev); + wlan_mlme_get_srd_master_mode_for_vdev(mac_ctx->psoc, + vdev_opmode, + &srd_chan_enabled); + + if (!srd_chan_enabled && + wlan_reg_is_etsi_srd_chan_for_freq( + mac_ctx->pdev, + WLAN_REG_CH_TO_FREQ(loop_count))) { + sap_debug("vdev opmode %d not allowed on SRD freq %d", + vdev_opmode, WLAN_REG_CH_TO_FREQ(loop_count)); + continue; + } + + /* Check if the freq is present in range list */ + for (i = 0; i < mac_ctx->mlme_cfg->acs.num_weight_range; i++) { + if (chan_freq >= range_list[i].start_freq && + chan_freq <= range_list[i].end_freq) { + normalize_factor = + range_list[i].normalize_weight; + sap_debug("Range list, freq %d normalize weight factor %d", + chan_freq, normalize_factor); + freq_present_in_list = true; + } + } + + for (i = 0; + i < mac_ctx->mlme_cfg->acs.normalize_weight_num_chan; + i++) { + if (chan_freq == weight_list[i].chan_freq) { + normalize_factor = + weight_list[i].normalize_weight; + sap_debug("freq %d normalize weight factor %d", + chan_freq, normalize_factor); + freq_present_in_list = true; + } + } + + /* This would mean that the user does not want this freq */ + if (freq_present_in_list && !normalize_factor) { + sap_debug("chan_freq %d ecluded normalize weight 0", + chan_freq); + freq_present_in_list = false; + continue; + } +#ifdef FEATURE_WLAN_AP_AP_ACS_OPTIMIZE + if (sap_ctx->acs_cfg->skip_scan_status == + eSAP_DO_PAR_ACS_SCAN) { + uint32_t ch_freq; + + ch_freq = WLAN_REG_CH_TO_FREQ(loop_count); + if ((ch_freq >= + sap_ctx->acs_cfg->skip_scan_range1_stch && + ch_freq <= + sap_ctx->acs_cfg->skip_scan_range1_endch) || + (ch_freq >= + sap_ctx->acs_cfg->skip_scan_range2_stch && + ch_freq <= + sap_ctx->acs_cfg->skip_scan_range2_endch)) { + list[ch_count] = + WLAN_REG_CH_TO_FREQ(loop_count); + ch_count++; + sap_debug("%d %d added to ACS ch range", + ch_count, ch_freq); + } else { + sap_debug("%d %d skipped from ACS ch range", + ch_count, ch_freq); + } + } else { + list[ch_count] = WLAN_REG_CH_TO_FREQ(loop_count); + ch_count++; + sap_debug("%d added to ACS ch range", ch_count); + } +#else + list[ch_count] = WLAN_REG_CH_TO_FREQ(loop_count); + ch_count++; +#endif + } + if (!ch_count) { + sap_info("No active channels present for the current region"); + /* + * LTE COEX: channel range outside the restricted 2.4GHz + * band limits + */ + if (en_lte_coex && + start_ch_freq > WLAN_REG_CH_TO_FREQ(band_end_ch)) + sap_info("SAP can't be started as due to LTE COEX"); + } + + /* return the channel list and number of channels to scan */ + *num_ch = ch_count; + if (ch_count != 0) { + *freq_list = list; + } else { + *freq_list = NULL; + qdf_mem_free(list); + return QDF_STATUS_SUCCESS; + } + + for (loop_count = 0; loop_count < ch_count; loop_count++) { + sap_ctx->acs_cfg->freq_list[loop_count] = list[loop_count]; + } + sap_ctx->acs_cfg->ch_list_count = ch_count; + sap_dump_acs_channel(sap_ctx->acs_cfg); + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef DFS_COMPONENT_ENABLE +qdf_freq_t sap_indicate_radar(struct sap_context *sap_ctx) +{ + qdf_freq_t chan_freq = 0; + struct mac_context *mac; + + if (!sap_ctx) { + sap_err("null sap_ctx"); + return 0; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return 0; + } + + /* + * SAP needs to generate Channel Switch IE + * if the radar is found in the STARTED state + */ + if (sap_ctx->fsm_state == SAP_STARTED) + mac->sap.SapDfsInfo.csaIERequired = true; + + if (mac->mlme_cfg->dfs_cfg.dfs_disable_channel_switch) { + mac->sap.SapDfsInfo.new_chanWidth = + sap_ctx->ch_params.ch_width; + sap_debug("DFS channel switch disabled, CSA to same ch %d wd %d", + sap_ctx->chan_freq, sap_ctx->ch_params.ch_width); + return sap_ctx->chan_freq; + } + + /* set the Radar Found flag in SapDfsInfo */ + sap_ctx->sap_radar_found_status = true; + + chan_freq = wlan_pre_cac_get_freq_before_pre_cac(sap_ctx->vdev); + if (chan_freq) { + sap_info("sapdfs: set chan freq before pre cac %d as target chan", + chan_freq); + return chan_freq; + } + + if (sap_ctx->vendor_acs_dfs_lte_enabled && (QDF_STATUS_SUCCESS == + sap_signal_hdd_event(sap_ctx, NULL, eSAP_DFS_NEXT_CHANNEL_REQ, + (void *) eSAP_STATUS_SUCCESS))) + return 0; + + if (!sap_is_chan_change_needed(sap_ctx)) + return sap_ctx->chan_freq; + + chan_freq = sap_random_channel_sel(sap_ctx); + if (!chan_freq) + sap_signal_hdd_event(sap_ctx, NULL, + eSAP_DFS_NO_AVAILABLE_CHANNEL, (void *) eSAP_STATUS_SUCCESS); + + sap_warn("sapdfs: New selected target freq is [%d]", chan_freq); + + return chan_freq; +} +#endif + +/* + * CAC timer callback function. + * Post eSAP_DFS_CHANNEL_CAC_END event to sap_fsm(). + */ +void sap_dfs_cac_timer_callback(void *data) +{ + struct sap_context *sap_ctx; + struct sap_sm_event sap_event; + mac_handle_t mac_handle = data; + struct mac_context *mac; + + if (!mac_handle) { + sap_err("Invalid mac_handle"); + return; + } + mac = MAC_CONTEXT(mac_handle); + sap_ctx = sap_find_cac_wait_session(mac_handle); + if (!sap_ctx) { + sap_err("no SAP contexts in wait state"); + return; + } + + if (mac->sap.SapDfsInfo.vdev_id != sap_ctx->vdev_id) { + sap_err("vdev mismatch sap_ctx->vdev_id %d mac->sap.SapDfsInfo.vdev_id %d", + sap_ctx->vdev_id, mac->sap.SapDfsInfo.vdev_id); + return; + } + + /* + * SAP may not be in CAC wait state, when the timer runs out. + * if following flag is set, then timer is in initialized state, + * destroy timer here. + */ + if (mac->sap.SapDfsInfo.is_dfs_cac_timer_running == true) { + if (!sap_ctx->dfs_cac_offload) + qdf_mc_timer_destroy( + &mac->sap.SapDfsInfo.sap_dfs_cac_timer); + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + mac->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + } + + /* + * CAC Complete, post eSAP_DFS_CHANNEL_CAC_END to sap_fsm + */ + sap_debug("sapdfs: Sending eSAP_DFS_CHANNEL_CAC_END for target_chan_freq = %d on sapctx[%pK]", + sap_ctx->chan_freq, sap_ctx); + + sap_event.event = eSAP_DFS_CHANNEL_CAC_END; + sap_event.params = 0; + sap_event.u1 = 0; + sap_event.u2 = 0; + + sap_fsm(sap_ctx, &sap_event); +} + +/* + * Function to stop the DFS CAC Timer + */ +static int sap_stop_dfs_cac_timer(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + + if (!sap_ctx) + return 0; + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return 0; + } + + if (mac->sap.SapDfsInfo.vdev_id != sap_ctx->vdev_id) { + sap_err("Invalid vdev Id sap_ctx_vdev_id %d mac_ctx vdev id %d", + sap_ctx->vdev_id, mac->sap.SapDfsInfo.vdev_id); + return 0; + } + + if (sap_ctx->dfs_cac_offload) { + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + mac->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + return 0; + } + + if (QDF_TIMER_STATE_RUNNING != + qdf_mc_timer_get_current_state(&mac->sap.SapDfsInfo. + sap_dfs_cac_timer)) { + return 0; + } + + qdf_mc_timer_stop(&mac->sap.SapDfsInfo.sap_dfs_cac_timer); + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + mac->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + qdf_mc_timer_destroy(&mac->sap.SapDfsInfo.sap_dfs_cac_timer); + + return 0; +} + +/* + * Function to start the DFS CAC Timer + * when SAP is started on a DFS channel + */ +static int sap_start_dfs_cac_timer(struct sap_context *sap_ctx) +{ + QDF_STATUS status; + uint32_t cac_dur; + struct mac_context *mac; + enum dfs_reg dfs_region; + + if (!sap_ctx) { + sap_err("null sap_ctx"); + return 0; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return 0; + } + /* start time only when is_dfs_cac_timer_running is not running */ + if (mac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + sap_err("Invalid state is_dfs_cac_timer_running"); + return 0; + } + + if (sap_ctx->dfs_cac_offload) { + sap_debug("cac timer offloaded to firmware"); + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = true; + mac->sap.SapDfsInfo.vdev_id = sap_ctx->vdev_id; + return 1; + } + + sap_get_cac_dur_dfs_region(sap_ctx, &cac_dur, &dfs_region, + sap_ctx->chan_freq, &sap_ctx->ch_params); + if (0 == cac_dur) + return 0; + +#ifdef QCA_WIFI_EMULATION + cac_dur = cac_dur / 100; +#endif + sap_debug("sapdfs: SAP_DFS_CHANNEL_CAC_START on CH freq %d, CAC_DUR-%d sec", + sap_ctx->chan_freq, cac_dur / 1000); + + qdf_mc_timer_init(&mac->sap.SapDfsInfo.sap_dfs_cac_timer, + QDF_TIMER_TYPE_SW, + sap_dfs_cac_timer_callback, MAC_HANDLE(mac)); + + /* Start the CAC timer */ + status = qdf_mc_timer_start(&mac->sap.SapDfsInfo.sap_dfs_cac_timer, + cac_dur); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("failed to start cac timer"); + goto destroy_timer; + } + + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = true; + mac->sap.SapDfsInfo.vdev_id = sap_ctx->vdev_id; + + return 0; + +destroy_timer: + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = false; + mac->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + qdf_mc_timer_destroy(&mac->sap.SapDfsInfo.sap_dfs_cac_timer); + + return 1; +} + +/* + * This function initializes the NOL list + * parameters required to track the radar + * found DFS channels in the current Reg. Domain . + */ +QDF_STATUS sap_init_dfs_channel_nol_list(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + + if (!sap_ctx) { + sap_err("Invalid SAP context"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + utils_dfs_init_nol(mac->pdev); + + return QDF_STATUS_SUCCESS; +} + +/** + * sap_is_active() - Check SAP active or not by sap_context object + * @sap_ctx: Pointer to the SAP context + * + * Return: true if SAP is active + */ +static bool sap_is_active(struct sap_context *sap_ctx) +{ + return sap_ctx->fsm_state != SAP_INIT; +} + +/* + * This function will calculate how many interfaces + * have sap persona and returns total number of sap persona. + */ +uint8_t sap_get_total_number_sap_intf(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + uint8_t intf = 0; + uint8_t intf_count = 0; + struct sap_context *sap_context; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == mac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[intf].sapPersona)) + && mac->sap.sapCtxList[intf].sap_context) { + sap_context = + mac->sap.sapCtxList[intf].sap_context; + if (!sap_is_active(sap_context)) + continue; + intf_count++; + } + } + return intf_count; +} + +/** + * is_concurrent_sap_ready_for_channel_change() - to check all saps are ready + * for channel change + * @mac_handle: Opaque handle to the global MAC context + * @sap_ctx: sap context for which this function has been called + * + * This function will find the concurrent sap context apart from + * passed sap context and return its channel change ready status + * + * + * Return: true if other SAP personas are ready to channel switch else false + */ +bool is_concurrent_sap_ready_for_channel_change(mac_handle_t mac_handle, + struct sap_context *sap_ctx) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sap_context *sap_context; + uint8_t intf = 0; + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if (((QDF_SAP_MODE == mac->sap.sapCtxList[intf].sapPersona) + || + (QDF_P2P_GO_MODE == mac->sap.sapCtxList[intf].sapPersona)) + && mac->sap.sapCtxList[intf].sap_context) { + sap_context = + mac->sap.sapCtxList[intf].sap_context; + if (!sap_is_active(sap_context)) + continue; + if (sap_context == sap_ctx) { + sap_err("sapCtx matched [%pK]", sap_ctx); + continue; + } else { + sap_err("concurrent sapCtx[%pK] didn't matche with [%pK]", + sap_context, sap_ctx); + return sap_context->is_sap_ready_for_chnl_chng; + } + } + } + return false; +} + +/** + * sap_is_conc_sap_doing_scc_dfs() - check if conc SAPs are doing SCC DFS + * @mac_handle: Opaque handle to the global MAC context + * @given_sapctx: current SAP persona's channel + * + * If provided SAP's channel is DFS then Loop through each SAP or GO persona and + * check if other beaconing entity's channel is same DFS channel. If they are + * same then concurrent sap is doing SCC DFS. + * + * Return: true if two or more beaconing entities doing SCC DFS else false + */ +bool sap_is_conc_sap_doing_scc_dfs(mac_handle_t mac_handle, + struct sap_context *given_sapctx) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sap_context *sap_ctx; + uint8_t intf = 0, scc_dfs_counter = 0; + qdf_freq_t ch_freq; + + ch_freq = given_sapctx->chan_freq; + /* + * current SAP persona's channel itself is not DFS, so no need to check + * what other persona's channel is + */ + if (!wlan_reg_is_dfs_for_freq(mac->pdev, + ch_freq)) { + sap_debug("skip this loop as provided channel is non-dfs"); + return false; + } + + for (intf = 0; intf < SAP_MAX_NUM_SESSION; intf++) { + if ((QDF_SAP_MODE != mac->sap.sapCtxList[intf].sapPersona) && + (QDF_P2P_GO_MODE != mac->sap.sapCtxList[intf].sapPersona)) + continue; + if (!mac->sap.sapCtxList[intf].sap_context) + continue; + sap_ctx = mac->sap.sapCtxList[intf].sap_context; + if (!sap_is_active(sap_ctx)) + continue; + /* if same SAP contexts then skip to next context */ + if (sap_ctx == given_sapctx) + continue; + if (given_sapctx->chan_freq == sap_ctx->chan_freq) + scc_dfs_counter++; + } + + /* Found atleast two of the beaconing entities doing SCC DFS */ + if (scc_dfs_counter) + return true; + + return false; +} + +/** + * sap_build_start_bss_config() - Fill the start bss request for SAP + * @sap_bss_cfg: start bss config + * @config: sap config + * + * This function fills the start bss request for SAP + * + * Return: None + */ +void +sap_build_start_bss_config(struct start_bss_config *sap_bss_cfg, + struct sap_config *config) +{ + qdf_mem_zero(&sap_bss_cfg->ssId.ssId, sizeof(sap_bss_cfg->ssId.ssId)); + sap_bss_cfg->ssId.length = config->SSIDinfo.ssid.length; + qdf_mem_copy(&sap_bss_cfg->ssId.ssId, config->SSIDinfo.ssid.ssId, + config->SSIDinfo.ssid.length); + + if (config->authType == eSAP_SHARED_KEY) + sap_bss_cfg->authType = eSIR_SHARED_KEY; + else if (config->authType == eSAP_OPEN_SYSTEM) + sap_bss_cfg->authType = eSIR_OPEN_SYSTEM; + else + sap_bss_cfg->authType = eSIR_AUTO_SWITCH; + + sap_bss_cfg->beaconInterval = (uint16_t)config->beacon_int; + sap_bss_cfg->privacy = config->privacy; + sap_bss_cfg->ssidHidden = config->SSIDinfo.ssidHidden; + sap_bss_cfg->dtimPeriod = config->dtim_period; + sap_bss_cfg->wps_state = config->wps_state; + sap_bss_cfg->beacon_tx_rate = config->beacon_tx_rate; + + /* RSNIE */ + sap_bss_cfg->rsnIE.length = config->RSNWPAReqIELength; + if (config->RSNWPAReqIELength) + qdf_mem_copy(sap_bss_cfg->rsnIE.rsnIEdata, + config->RSNWPAReqIE, config->RSNWPAReqIELength); + + /* Probe response IE */ + if (config->probeRespIEsBufferLen > 0 && + config->pProbeRespIEsBuffer) { + sap_bss_cfg->add_ie_params.probeRespDataLen = + config->probeRespIEsBufferLen; + sap_bss_cfg->add_ie_params.probeRespData_buff = + config->pProbeRespIEsBuffer; + } else { + sap_bss_cfg->add_ie_params.probeRespDataLen = 0; + sap_bss_cfg->add_ie_params.probeRespData_buff = NULL; + } + + /*assoc resp IE */ + if (config->assocRespIEsLen > 0 && config->pAssocRespIEsBuffer) { + sap_bss_cfg->add_ie_params.assocRespDataLen = + config->assocRespIEsLen; + sap_bss_cfg->add_ie_params.assocRespData_buff = + config->pAssocRespIEsBuffer; + } else { + sap_bss_cfg->add_ie_params.assocRespDataLen = 0; + sap_bss_cfg->add_ie_params.assocRespData_buff = NULL; + } + + if (config->probeRespBcnIEsLen > 0 && + config->pProbeRespBcnIEsBuffer) { + sap_bss_cfg->add_ie_params.probeRespBCNDataLen = + config->probeRespBcnIEsLen; + sap_bss_cfg->add_ie_params.probeRespBCNData_buff = + config->pProbeRespBcnIEsBuffer; + } else { + sap_bss_cfg->add_ie_params.probeRespBCNDataLen = 0; + sap_bss_cfg->add_ie_params.probeRespBCNData_buff = NULL; + } + + if (config->supported_rates.numRates) { + qdf_mem_copy(sap_bss_cfg->operationalRateSet.rate, + config->supported_rates.rate, + config->supported_rates.numRates); + sap_bss_cfg->operationalRateSet.numRates = + config->supported_rates.numRates; + } + + if (config->extended_rates.numRates) { + qdf_mem_copy(sap_bss_cfg->extendedRateSet.rate, + config->extended_rates.rate, + config->extended_rates.numRates); + sap_bss_cfg->extendedRateSet.numRates = + config->extended_rates.numRates; + } + + return; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_fsm_ext.h b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_fsm_ext.h new file mode 100644 index 0000000000..648af1c807 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_fsm_ext.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2014, 2018-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* This file is generated from btampFsm.cdd - do not edit manually*/ +/* Generated on: Thu Oct 16 15:40:39 PDT 2008 */ + +#ifndef __SAPFSM_EXT_H__ +#define __SAPFSM_EXT_H__ + +/* Events that can be sent to the SAP state-machine */ +typedef enum { + eSAP_TIMER_CONNECT_ACCEPT_TIMEOUT = 0U, + eSAP_MAC_CONNECT_COMPLETED, + eSAP_MAC_CONNECT_INDICATION, + eSAP_MAC_KEY_SET_SUCCESS, + eSAP_RSN_FAILURE, + eSAP_HDD_START_INFRA_BSS, + eSAP_MAC_READY_FOR_CONNECTIONS, + eSAP_MAC_START_BSS_SUCCESS, + eSAP_MAC_START_BSS_FAILURE, + eSAP_RSN_SUCCESS, + eSAP_MAC_START_FAILS, + eSAP_HDD_STOP_INFRA_BSS, + eSAP_WRITE_REMOTE_AMP_ASSOC, + eSAP_DFS_CHANNEL_CAC_START, + eSAP_DFS_CHANNEL_CAC_RADAR_FOUND, + eSAP_DFS_CHANNEL_CAC_END, + eSAP_DFS_CHNL_SWITCH_ANNOUNCEMENT_START, + eSAP_OPERATING_CHANNEL_CHANGED, + eSAP_NO_MSG +} eSapMsg_t; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_internal.h new file mode 100644 index 0000000000..6a3d06f16b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_internal.h @@ -0,0 +1,561 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_QCT_WLANSAP_INTERNAL_H +#define WLAN_QCT_WLANSAP_INTERNAL_H + +/* + * This file contains the internal API exposed by the wlan SAP PAL layer + * module. + */ + +#include "cds_api.h" +#include "cds_packet.h" + +/* Pick up the CSR API definitions */ +#include "csr_api.h" +#include "sap_api.h" +#include "sap_fsm_ext.h" +#include "sap_ch_select.h" +#include +#include +#include "wlan_vdev_mlme_main.h" +#include "wlan_vdev_mlme_api.h" + +/* DFS Non Occupancy Period =30 minutes, in microseconds */ +#define SAP_DFS_NON_OCCUPANCY_PERIOD (30 * 60 * 1000 * 1000) + +#define SAP_DEBUG + +#define IS_ETSI_WEATHER_FREQ(_freq) ((_freq >= 5600) && (_freq <= 5650)) +#define IS_CH_BONDING_WITH_WEATHER_CH(_ch) (_ch == 116) +#define IS_CHAN_JAPAN_INDOOR(_ch) ((_ch >= 36) && (_ch <= 64)) +#define IS_CHAN_JAPAN_OUTDOOR(_ch)((_ch >= 100) && (_ch <= 140)) +#define DEFAULT_CAC_TIMEOUT (60 * 1000) /* msecs - 1 min */ +#define ETSI_WEATHER_CH_CAC_TIMEOUT (10 * 60 * 1000) /* msecs - 10 min */ +#define SAP_CHAN_PREFERRED_INDOOR 1 +#define SAP_CHAN_PREFERRED_OUTDOOR 2 + +/*SAP Specific logging*/ + +#define sap_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_SAP, params) +#define sap_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_SAP, params) +#define sap_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_SAP, params) +#define sap_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_SAP, params) +#define sap_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_SAP, params) + +#define sap_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_SAP, params) +#define sap_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_SAP, params) +#define sap_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_SAP, params) +#define sap_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_SAP, params) +#define sap_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_SAP, params) + +#define sap_alert_rl(params...) QDF_TRACE_FATAL_RL(QDF_MODULE_ID_SAP, params) +#define sap_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_SAP, params) +#define sap_warn_rl(params...) QDF_TRACE_WARN_RL(QDF_MODULE_ID_SAP, params) +#define sap_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_SAP, params) +#define sap_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_SAP, params) + +/*---------------------------------------------------------------------------- + * Typedefs + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Type Declarations - For internal SAP context information + * -------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------- + * Opaque SAP context Type Declaration + * -------------------------------------------------------------------------*/ +/* We were only using this syntax, when this was truly opaque. */ +/* (I.E., it was defined in a different file.) */ + +/** + * enum sap_fsm_state - SAP FSM states for Access Point role + * @SAP_INIT: init state + * @SAP_STARTING: starting phase + * @SAP_STARTED: up and running + * @SAP_STOPPING: about to stop and transitions to init + */ +enum sap_fsm_state { + SAP_INIT, + SAP_STARTING, + SAP_STARTED, + SAP_STOPPING +}; + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/* + * In a setup having two MDM both operating in AP+AP MCC scenario + * if both the AP decides to use same or close channel set, CTS to + * self, mechanism is causing issues with connectivity. For this, its + * proposed that 2nd MDM devices which comes up later should detect + * presence of first MDM device via special Q2Q IE present in becon + * and avoid those channels mentioned in IE. + * + * Following struct will keep this info in sapCtx struct, and will be used + * to avoid such channels in Random Channel Select in case of radar ind. + */ +struct sap_avoid_channels_info { + bool present; + uint8_t channels[CFG_VALID_CHANNEL_LIST_LEN]; +}; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +#define MAX_VLAN 4 +struct sap_context { + + /* Include the current channel frequency of AP */ + uint32_t chan_freq; + uint32_t sec_ch_freq; + +#ifdef DCS_INTERFERENCE_DETECTION + qdf_freq_t dcs_ch_freq; +#endif + union { + uint8_t sessionId; + uint8_t vdev_id; + }; + uint8_t sap_radar_found_status; + + /* vdev object corresponding to sessionId */ + struct wlan_objmgr_vdev *vdev; + + /* Include the associations MAC addresses */ + uint8_t self_mac_addr[CDS_MAC_ADDRESS_LEN]; + struct start_bss_config sap_bss_cfg; + + /* SAP event Callback to hdd */ + sap_event_cb sap_event_cb; + + /* + * Include the state machine structure here, state var that keeps + * track of state machine + */ + enum sap_fsm_state fsm_state; + enum sap_csa_reason_code csa_reason; + + /* Actual storage for AP and self (STA) SSID */ + tCsrSSIDInfo SSIDList[2]; + + /* Actual storage for AP bssid */ + struct qdf_mac_addr bssid; + + /* Mac filtering settings */ + eSapMacAddrACL eSapMacAddrAclMode; + struct qdf_mac_addr acceptMacList[MAX_ACL_MAC_ADDRESS]; + uint16_t nAcceptMac; + struct qdf_mac_addr denyMacList[MAX_ACL_MAC_ADDRESS]; + uint16_t nDenyMac; + + void *user_context; + + uint32_t nStaWPARSnReqIeLength; + uint8_t pStaWpaRsnReqIE[MAX_ASSOC_IND_IE_LEN]; + + eCsrPhyMode phyMode; + uint32_t *freq_list; + uint8_t num_of_channel; + uint16_t ch_width_orig; + struct ch_params ch_params; + uint32_t chan_freq_before_switch_band; + enum phy_ch_width chan_width_before_switch_band; + uint32_t auto_channel_select_weight; + bool enableOverLapCh; + struct sap_acs_cfg *acs_cfg; + + qdf_time_t acs_req_timestamp; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + +#if defined(FEATURE_WLAN_STA_AP_MODE_DFS_DISABLE) + bool dfs_ch_disable; +#endif + bool isCacEndNotified; + bool isCacStartNotified; + bool is_sap_ready_for_chnl_chng; +#ifdef FEATURE_RADAR_HISTORY + struct prev_cac_result cac_result; +#endif +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + /* + * In a setup having two MDM both operating in AP+AP MCC scenario + * if both the AP decides to use same or close channel set, CTS to + * self, mechanism is causing issues with connectivity. For this, its + * proposed that 2nd MDM devices which comes up later should detect + * presence of first MDM device via special Q2Q IE present in becon + * and avoid those channels mentioned in IE. + * + * this struct contains the list of channels on which another MDM AP + * in MCC mode were detected. + */ + struct sap_avoid_channels_info sap_detected_avoid_ch_ie; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + /* + * sap_state, sap_status are created + * to inform upper layers about ACS scan status. + * Don't use these members for any other purposes. + */ + eSapHddEvent sap_state; + eSapStatus sap_status; + uint32_t roc_ind_scan_id; + bool vendor_acs_dfs_lte_enabled; + uint8_t dfs_vendor_channel; + uint8_t dfs_vendor_chan_bw; + uint16_t beacon_tx_rate; + enum sap_acs_dfs_mode dfs_mode; + wlan_scan_requester req_id; + uint8_t sap_sta_id; + bool dfs_cac_offload; + bool is_chan_change_inprogress; + /* Disabled mcs13 by sap or not */ + bool disabled_mcs13; + qdf_list_t owe_pending_assoc_ind_list; + qdf_list_t ft_pending_assoc_ind_list; + qdf_event_t ft_pending_event; + uint32_t freq_before_ch_switch; + struct ch_params ch_params_before_ch_switch; +#ifdef WLAN_FEATURE_P2P_P2P_STA +/* + *This param is used for GO+GO force scc logic where after + *setkey first GO will move to latest GO's channel + */ + bool is_forcescc_restart_required; +#endif + qdf_freq_t candidate_freq; +#ifdef FEATURE_WLAN_CH_AVOID_EXT + uint32_t restriction_mask; +#endif + bool require_h2e; + bool partial_acs_scan; + bool optimize_acs_chan_selected; +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +/* + * This param is used to track clean channels where there + * is no AP found on these channels + */ + bool clean_channel_array[NUM_CHANNELS]; +#endif +#ifdef QCA_MULTIPASS_SUPPORT + uint16_t vlan_map[2 * MAX_VLAN]; +#endif +}; + +/*---------------------------------------------------------------------------- + * External declarations for global context + * -------------------------------------------------------------------------*/ + +/** + * struct sap_sm_event - SAP state machine event definition + * @params: A VOID pointer type for all possible inputs + * @event: State machine input event message + * @u1: Introduced to handle csr_roam_complete_cb roamStatus + * @u2: Introduced to handle csr_roam_complete_cb roamResult + */ +struct sap_sm_event { + void *params; + uint32_t event; + uint32_t u1; + uint32_t u2; +}; + +/*---------------------------------------------------------------------------- + * Function Declarations and Documentation + * -------------------------------------------------------------------------*/ + +/** + * sap_get_mac_context() - Get a pointer to the global MAC context + * + * Return: pointer to the global MAC context, or NULL if the MAC + * context is no longer registered + */ +static inline struct mac_context *sap_get_mac_context(void) +{ + return cds_get_context(QDF_MODULE_ID_PE); +} + +QDF_STATUS wlansap_context_get(struct sap_context *ctx); +void wlansap_context_put(struct sap_context *ctx); + +/** + * wlansap_pre_start_bss_acs_scan_callback() - callback for scan results + * @mac_handle: the mac_handle passed in with the scan request + * @sap_ctx: the SAP context pointer. + * @scanid: scan id passed + * @sessionid: session identifier + * @scan_status: status of scan -success, failure or abort + * + * Api for scan callback. This function is invoked as a result of scan + * completion and reports the scan results. + * + * Return: The QDF_STATUS code associated with performing the operation + */ +QDF_STATUS wlansap_pre_start_bss_acs_scan_callback(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint8_t sessionid, + uint32_t scanid, + eCsrScanStatus scan_status); + +/** + * sap_chan_sel_exit() - Exit function for free out the allocated memory, + * @ch_info_params: Pointer to sap_sel_ch_info structure + * + * Return: None + */ +void sap_chan_sel_exit(struct sap_sel_ch_info *ch_info_params); + +/** + * sap_sort_channel_list() - Sort channel list based on channel weight + * @mac_ctx: Pointer to mac_context + * @vdev_id: Vdev ID + * @ch_list: Pointer to qdf_list_t + * @ch_info: Pointer to sap_sel_ch_info structure + * @domain: Regulatory Domain + * @operating_band: Operating band + * + * Return: None + * + */ +void +sap_sort_channel_list(struct mac_context *mac_ctx, uint8_t vdev_id, + qdf_list_t *ch_list, struct sap_sel_ch_info *ch_info, + v_REGDOMAIN_t *domain, uint32_t *operating_band); + +/** + * sap_select_channel() - select SAP channel + * @mac_handle: Opaque handle to the global MAC context + * @sap_ctx: Sap context + * @scan_list: scan entry list + * + * Runs a algorithm to select the best channel to operate in based on BSS + * rssi and bss count on each channel + * + * Returns: channel frequency if success, 0 otherwise + */ +uint32_t sap_select_channel(mac_handle_t mac_handle, struct sap_context *sap_ctx, + qdf_list_t *scan_list); + +QDF_STATUS +sap_signal_hdd_event(struct sap_context *sap_ctx, + struct csr_roam_info *pCsrRoamInfo, + eSapHddEvent sapHddevent, void *); + +QDF_STATUS sap_fsm(struct sap_context *sap_ctx, struct sap_sm_event *sap_event); + +QDF_STATUS +sap_is_peer_mac_allowed(struct sap_context *sap_ctx, uint8_t *peerMac); + +void +sap_sort_mac_list(struct qdf_mac_addr *macList, uint16_t size); + +void +sap_add_mac_to_acl(struct qdf_mac_addr *macList, uint16_t *size, + uint8_t *peerMac); + +void +sap_remove_mac_from_acl(struct qdf_mac_addr *macList, uint16_t *size, + uint16_t index); + +void +sap_print_acl(struct qdf_mac_addr *macList, uint16_t size); + +bool +sap_search_mac_list(struct qdf_mac_addr *macList, uint16_t num_mac, + uint8_t *peerMac, uint16_t *index); + +QDF_STATUS sap_init_dfs_channel_nol_list(struct sap_context *sap_ctx); + +bool sap_dfs_is_channel_in_nol_list(struct sap_context *sap_ctx, + qdf_freq_t chan_freq, + ePhyChanBondState chanBondState); +void sap_dfs_cac_timer_callback(void *data); + +/** + * sap_cac_reset_notify() - BSS cleanup notification handler + * @mac_handle: Opaque handle to the global MAC context + * + * This function should be called upon stop bss indication to clean up + * DFS global structure. + */ +void sap_cac_reset_notify(mac_handle_t mac_handle); + +bool is_concurrent_sap_ready_for_channel_change(mac_handle_t mac_handle, + struct sap_context *sap_ctx); + +bool sap_is_conc_sap_doing_scc_dfs(mac_handle_t mac_handle, + struct sap_context *given_sapctx); + +uint8_t sap_get_total_number_sap_intf(mac_handle_t mac_handle); + +/** + * sap_channel_sel - Function for initiating scan request for ACS + * @sap_context: Sap Context value. + * + * Initiates Scan for ACS to pick a channel. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS sap_channel_sel(struct sap_context *sap_context); + +/** + * sap_validate_chan - Function validate the channel and forces SCC + * @sap_context: Sap Context value. + * @pre_start_bss: if its called pre start BSS with valid channel. + * @check_for_connection_update: true, check and wait for connection update + * false, do not perform connection update + * + * validate and update the channel in case of force SCC. + * + * Return: The QDF_STATUS code associated with performing the operation. + */ +QDF_STATUS +sap_validate_chan(struct sap_context *sap_context, + bool pre_start_bss, + bool check_for_connection_update); + +/** + * sap_check_in_avoid_ch_list() - checks if given channel present is channel + * avoidance list + * avoid_channels_info struct + * @sap_ctx: sap context. + * @channel: channel to be checked in sap_ctx's avoid ch list + * + * sap_ctx contains sap_avoid_ch_info strcut containing the list of channels on + * which MDM device's AP with MCC was detected. This function checks if given + * channel is present in that list. + * + * Return: true, if channel was present, false othersie. + */ +bool +sap_check_in_avoid_ch_list(struct sap_context *sap_ctx, uint8_t channel); + +/** + * sap_set_session_param() - set sap related param to sap context and global var + * @mac_handle: Opaque handle to the global MAC context + * @sapctx: pointer to sapctx + * @session_id: session id for sap + * + * This API will set appropriate softap parameters to sap context + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_set_session_param(mac_handle_t mac_handle, + struct sap_context *sapctx, + uint32_t session_id); + +/** + * sap_clear_session_param() - clear sap related param from sap context + * @mac_handle: Opaque handle to the global MAC context + * @sapctx: pointer to sapctx + * @session_id: session id for sap + * + * This API will clear appropriate softap parameters from sap context + * + * Return: QDF_STATUS + */ +QDF_STATUS sap_clear_session_param(mac_handle_t mac_handle, + struct sap_context *sapctx, + uint32_t session_id); + +void sap_scan_event_callback(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg); + +#ifdef DFS_COMPONENT_ENABLE +/** + * sap_indicate_radar() - Process radar indication + * @sap_ctx: pointer to sap context + * + * process radar indication. + * + * Return: frequency to which sap wishes to switch. + */ +qdf_freq_t sap_indicate_radar(struct sap_context *sap_ctx); +#else +static inline qdf_freq_t sap_indicate_radar(struct sap_context *sap_ctx) +{ + return 0; +} +#endif + +/** + * sap_select_default_oper_chan() - Select AP mode default operating channel + * @mac_ctx: mac context + * @acs_cfg: pointer to ACS config info + * + * Select AP mode default operating channel based on ACS hw mode and channel + * range configuration when ACS scan fails due to some reasons, such as scan + * timeout, etc. + * + * Return: Selected operating channel frequency + */ +uint32_t sap_select_default_oper_chan(struct mac_context *mac_ctx, + struct sap_acs_cfg *acs_cfg); + +/* + * sap_is_dfs_cac_wait_state() - check if sap is in cac wait state + * @sap_ctx: sap context to check + * + * Return: true if sap is in cac wait state + */ +bool sap_is_dfs_cac_wait_state(struct sap_context *sap_ctx); + +/** + * sap_chan_bond_dfs_sub_chan - check bonded channel includes dfs sub chan + * @sap_context: Handle to SAP context. + * @channel_freq: chan whose bonded chan will be checked + * @bond_state: The channel bonding mode of the passed channel. + * + * This function checks if a given bonded channel includes dfs sub chan. + * + * Return: true if at least one dfs sub chan is bonded, otherwise false + */ +bool +sap_chan_bond_dfs_sub_chan(struct sap_context *sap_context, + qdf_freq_t channel_freq, + ePhyChanBondState bond_state); + +/** + * sap_plus_sap_cac_skip() - Check current sap can skip CAC or not + * in SAP+SAP concurrency + * @mac: mac ctx + * @sap_ctx: SAP context + * @chan_freq: SAP channel frequency + * + * All APs are done with CAC timer, all APs should start beaconing. + * Lets assume AP1 and AP2 started beaconing on DFS channel, Now lets + * say AP1 goes down and comes back on same DFS channel. In this case + * AP1 shouldn't start CAC timer and start beacon immediately because + * AP2 is already beaconing on this channel. This case will be handled + * by checking CAC completion on AP2. + * + * Return: true if current SAP can skip CAC + */ +bool sap_plus_sap_cac_skip(struct mac_context *mac, + struct sap_context *sap_ctx, + qdf_freq_t chan_freq); + +void +sap_build_start_bss_config(struct start_bss_config *sap_bss_cfg, + struct sap_config *config); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_module.c b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_module.c new file mode 100644 index 0000000000..c58c1f514f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sap/src/sap_module.c @@ -0,0 +1,4458 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * sap_module.c + * OVERVIEW: + * This software unit holds the implementation of the WLAN SAP modules + * functions providing EXTERNAL APIs. It is also where the global SAP module + * context gets initialised + * DEPENDENCIES: + * Are listed for each API below. + */ + +/* $Header$ */ + +/*---------------------------------------------------------------------------- + * Include Files + * -------------------------------------------------------------------------*/ +#include "qdf_trace.h" +#include "qdf_util.h" +#include "qdf_atomic.h" +/* Pick up the sme callback registration API */ +#include "sme_api.h" + +/* SAP API header file */ + +#include "sap_internal.h" +#include "sme_inside.h" +#include "cds_ieee80211_common_i.h" +#include "cds_regdomain.h" +#include "wlan_policy_mgr_api.h" +#include +#include "wlan_reg_services_api.h" +#include +#include +#include +#include +#include "cfg_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_vdev_mgr_interface.h" +#include "pld_common.h" +#include "wlan_pre_cac_api.h" +#include "target_if.h" + +#define SAP_DEBUG +static struct sap_context *gp_sap_ctx[SAP_MAX_NUM_SESSION]; +static qdf_atomic_t sap_ctx_ref_count[SAP_MAX_NUM_SESSION]; +static qdf_mutex_t sap_context_lock; + +/** + * wlansap_global_init() - Initialize SAP globals + * + * Initializes the SAP global data structures + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_global_init(void) +{ + uint32_t i; + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create(&sap_context_lock))) { + sap_err("failed to init sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + gp_sap_ctx[i] = NULL; + qdf_atomic_init(&sap_ctx_ref_count[i]); + } + + sap_debug("sap global context initialized"); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_global_deinit() - De-initialize SAP globals + * + * De-initializes the SAP global data structures + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_global_deinit(void) +{ + uint32_t i; + + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i]) { + sap_err("we could be leaking context:%d", i); + } + gp_sap_ctx[i] = NULL; + qdf_atomic_init(&sap_ctx_ref_count[i]); + } + + if (QDF_IS_STATUS_ERROR(qdf_mutex_destroy(&sap_context_lock))) { + sap_err("failed to destroy sap_context_lock"); + return QDF_STATUS_E_FAULT; + } + + sap_debug("sap global context deinitialized"); + + return QDF_STATUS_SUCCESS; +} + +/** + * wlansap_save_context() - Save the context in global SAP context + * @ctx: SAP context to be stored + * + * Stores the given SAP context in the global SAP context array + * + * Return: QDF_STATUS + */ +static QDF_STATUS wlansap_save_context(struct sap_context *ctx) +{ + uint32_t i; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (!gp_sap_ctx[i]) { + gp_sap_ctx[i] = ctx; + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + sap_debug("sap context saved at index: %d", i); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + sap_err("failed to save sap context"); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_context_get() - Verify SAP context and increment ref count + * @ctx: Context to be checked + * + * Verifies the SAP context and increments the reference count maintained for + * the corresponding SAP context. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlansap_context_get(struct sap_context *ctx) +{ + uint32_t i; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (ctx && (gp_sap_ctx[i] == ctx)) { + qdf_atomic_inc(&sap_ctx_ref_count[i]); + qdf_mutex_release(&sap_context_lock); + return QDF_STATUS_SUCCESS; + } + } + qdf_mutex_release(&sap_context_lock); + + sap_debug("sap session is not valid"); + return QDF_STATUS_E_FAILURE; +} + +/** + * wlansap_context_put() - Check the reference count and free SAP context + * @ctx: SAP context to be checked and freed + * + * Checks the reference count and frees the SAP context + * + * Return: None + */ +void wlansap_context_put(struct sap_context *ctx) +{ + uint32_t i; + + if (!ctx) + return; + + qdf_mutex_acquire(&sap_context_lock); + for (i = 0; i < SAP_MAX_NUM_SESSION; i++) { + if (gp_sap_ctx[i] == ctx) { + if (qdf_atomic_dec_and_test(&sap_ctx_ref_count[i])) { + if (ctx->freq_list) { + qdf_mem_free(ctx->freq_list); + ctx->freq_list = NULL; + ctx->num_of_channel = 0; + } + qdf_mem_free(ctx); + gp_sap_ctx[i] = NULL; + sap_debug("sap session freed: %d", i); + } + qdf_mutex_release(&sap_context_lock); + return; + } + } + qdf_mutex_release(&sap_context_lock); +} + +struct sap_context *sap_create_ctx(void) +{ + struct sap_context *sap_ctx; + QDF_STATUS status; + + sap_ctx = qdf_mem_malloc(sizeof(*sap_ctx)); + if (!sap_ctx) + return NULL; + + /* Clean up SAP control block, initialize all values */ + /* Save the SAP context pointer */ + status = wlansap_save_context(sap_ctx); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("failed to save SAP context"); + qdf_mem_free(sap_ctx); + return NULL; + } + sap_debug("Exit"); + + return sap_ctx; +} /* sap_create_ctx */ + +static QDF_STATUS wlansap_owe_init(struct sap_context *sap_ctx) +{ + qdf_list_create(&sap_ctx->owe_pending_assoc_ind_list, 0); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wlansap_ft_init(struct sap_context *sap_ctx) +{ + qdf_list_create(&sap_ctx->ft_pending_assoc_ind_list, 0); + qdf_event_create(&sap_ctx->ft_pending_event); + + return QDF_STATUS_SUCCESS; +} + +static void wlansap_owe_cleanup(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + struct owe_assoc_ind *owe_assoc_ind; + struct assoc_ind *assoc_ind = NULL; + qdf_list_node_t *node = NULL, *next_node = NULL; + QDF_STATUS status; + + if (!sap_ctx) { + sap_err("Invalid SAP context"); + return; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&sap_ctx->owe_pending_assoc_ind_list, + &node)) { + sap_debug("Failed to find assoc ind list"); + return; + } + + while (node) { + qdf_list_peek_next(&sap_ctx->owe_pending_assoc_ind_list, + node, &next_node); + owe_assoc_ind = qdf_container_of(node, struct owe_assoc_ind, + node); + status = qdf_list_remove_node( + &sap_ctx->owe_pending_assoc_ind_list, + node); + if (status == QDF_STATUS_SUCCESS) { + assoc_ind = owe_assoc_ind->assoc_ind; + qdf_mem_free(owe_assoc_ind); + assoc_ind->owe_ie = NULL; + assoc_ind->owe_ie_len = 0; + assoc_ind->owe_status = STATUS_UNSPECIFIED_FAILURE; + status = sme_update_owe_info(mac, assoc_ind); + qdf_mem_free(assoc_ind); + } else { + sap_err("Failed to remove assoc ind"); + } + node = next_node; + next_node = NULL; + } +} + +static void wlansap_ft_cleanup(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + struct ft_assoc_ind *ft_assoc_ind; + struct assoc_ind *assoc_ind = NULL; + qdf_list_node_t *node = NULL, *next_node = NULL; + QDF_STATUS status; + + if (!sap_ctx) { + sap_err("Invalid SAP context"); + return; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&sap_ctx->ft_pending_assoc_ind_list, + &node)) { + sap_debug("Failed to find assoc ind list"); + return; + } + + while (node) { + qdf_list_peek_next(&sap_ctx->ft_pending_assoc_ind_list, + node, &next_node); + ft_assoc_ind = qdf_container_of(node, struct ft_assoc_ind, + node); + status = qdf_list_remove_node( + &sap_ctx->ft_pending_assoc_ind_list, node); + if (status == QDF_STATUS_SUCCESS) { + assoc_ind = ft_assoc_ind->assoc_ind; + qdf_mem_free(ft_assoc_ind); + assoc_ind->ft_ie = NULL; + assoc_ind->ft_ie_len = 0; + assoc_ind->ft_status = STATUS_UNSPECIFIED_FAILURE; + qdf_mem_free(assoc_ind); + } else { + sap_err("Failed to remove assoc ind"); + } + node = next_node; + next_node = NULL; + } +} + +static void wlansap_owe_deinit(struct sap_context *sap_ctx) +{ + qdf_list_destroy(&sap_ctx->owe_pending_assoc_ind_list); +} + +static void wlansap_ft_deinit(struct sap_context *sap_ctx) +{ + qdf_list_destroy(&sap_ctx->ft_pending_assoc_ind_list); + qdf_event_destroy(&sap_ctx->ft_pending_event); +} + +QDF_STATUS sap_init_ctx(struct sap_context *sap_ctx, + enum QDF_OPMODE mode, + uint8_t *addr, uint32_t session_id, bool reinit) +{ + QDF_STATUS status; + struct mac_context *mac; + + sap_debug("wlansap_start invoked successfully"); + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->csa_reason = CSA_REASON_UNKNOWN; + qdf_mem_copy(sap_ctx->self_mac_addr, addr, QDF_MAC_ADDR_SIZE); + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_INVAL; + } + + status = sap_set_session_param(MAC_HANDLE(mac), sap_ctx, session_id); + if (QDF_STATUS_SUCCESS != status) { + sap_err("Calling sap_set_session_param status = %d", status); + return QDF_STATUS_E_FAILURE; + } + /* Register with scan component only during init */ + if (!reinit) + sap_ctx->req_id = + wlan_scan_register_requester(mac->psoc, "SAP", + sap_scan_event_callback, sap_ctx); + + if (!reinit) { + status = wlansap_owe_init(sap_ctx); + if (QDF_STATUS_SUCCESS != status) { + sap_err("OWE init failed"); + return QDF_STATUS_E_FAILURE; + } + status = wlansap_ft_init(sap_ctx); + if (QDF_STATUS_SUCCESS != status) { + sap_err("FT init failed"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_deinit_ctx(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + + /* Sanity check - Extract SAP control block */ + sap_debug("wlansap_stop invoked successfully "); + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + wlansap_ft_cleanup(sap_ctx); + wlansap_ft_deinit(sap_ctx); + wlansap_owe_cleanup(sap_ctx); + wlansap_owe_deinit(sap_ctx); + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + wlan_scan_unregister_requester(mac->psoc, sap_ctx->req_id); + + if (sap_ctx->freq_list) { + qdf_mem_free(sap_ctx->freq_list); + sap_ctx->freq_list = NULL; + sap_ctx->num_of_channel = 0; + } + + if (sap_ctx->sessionId != WLAN_UMAC_VDEV_ID_MAX) { + /* empty queues/lists/pkts if any */ + sap_clear_session_param(MAC_HANDLE(mac), sap_ctx, + sap_ctx->sessionId); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sap_destroy_ctx(struct sap_context *sap_ctx) +{ + sap_debug("Enter"); + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + /* Cleanup SAP control block */ + /* + * wlansap_context_put will release actual sap_ctx memory + * allocated during sap_create_ctx + */ + wlansap_context_put(sap_ctx); + + return QDF_STATUS_SUCCESS; +} /* sap_destroy_ctx */ + +bool wlansap_is_channel_in_nol_list(struct sap_context *sap_ctx, + qdf_freq_t chan_freq, + ePhyChanBondState chanBondState) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer from pCtx"); + return QDF_STATUS_E_FAULT; + } + + return sap_dfs_is_channel_in_nol_list(sap_ctx, chan_freq, + chanBondState); +} + +static QDF_STATUS wlansap_mark_leaking_channel(struct wlan_objmgr_pdev *pdev, + uint16_t *leakage_adjusted_lst, + uint8_t chan_bw) +{ + + return utils_dfs_mark_leaking_chan_for_freq(pdev, chan_bw, 1, + leakage_adjusted_lst); +} + +bool wlansap_is_channel_leaking_in_nol(struct sap_context *sap_ctx, + uint16_t chan_freq, + uint8_t chan_bw) +{ + struct mac_context *mac_ctx; + uint16_t leakage_adjusted_lst[1]; + + leakage_adjusted_lst[0] = chan_freq; + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + if (QDF_IS_STATUS_ERROR(wlansap_mark_leaking_channel(mac_ctx->pdev, + leakage_adjusted_lst, chan_bw))) + return true; + + if (!leakage_adjusted_lst[0]) + return true; + + return false; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t wlansap_check_cc_intf(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + uint16_t intf_ch_freq; + eCsrPhyMode phy_mode; + uint8_t vdev_id; + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return 0; + } + phy_mode = sap_ctx->phyMode; + vdev_id = sap_ctx->sessionId; + intf_ch_freq = sme_check_concurrent_channel_overlap( + MAC_HANDLE(mac), + sap_ctx->chan_freq, + phy_mode, + sap_ctx->cc_switch_mode, + vdev_id); + return intf_ch_freq; +} +#endif + + /** + * wlansap_set_scan_acs_channel_params() - Config scan and channel parameters. + * config: Pointer to the SAP config + * psap_ctx: Pointer to the SAP Context. + * pusr_context: Parameter that will be passed + * back in all the SAP callback events. + * + * This api function is used to copy Scan and Channel parameters from sap + * config to sap context. + * + * Return: The result code associated with + * performing the operation + */ +static QDF_STATUS +wlansap_set_scan_acs_channel_params(struct sap_config *config, + struct sap_context *psap_ctx, + void *pusr_context) +{ + struct mac_context *mac; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t auto_channel_select_weight; + + if (!config) { + sap_err("Invalid config passed "); + return QDF_STATUS_E_FAULT; + } + + if (!psap_ctx) { + sap_err("Invalid config passed "); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_INVAL; + } + + /* Channel selection is auto or configured */ + wlansap_set_acs_ch_freq(psap_ctx, config->chan_freq); + psap_ctx->dfs_mode = config->acs_dfs_mode; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + psap_ctx->cc_switch_mode = config->cc_switch_mode; +#endif + status = ucfg_mlme_get_auto_channel_weight( + mac->psoc, + &auto_channel_select_weight); + + if (!QDF_IS_STATUS_SUCCESS(status)) + sap_err("get_auto_channel_weight failed"); + + psap_ctx->auto_channel_select_weight = auto_channel_select_weight; + sap_debug("auto_channel_select_weight %d", + psap_ctx->auto_channel_select_weight); + + psap_ctx->user_context = pusr_context; + psap_ctx->enableOverLapCh = config->enOverLapCh; + psap_ctx->acs_cfg = &config->acs_cfg; + psap_ctx->ch_width_orig = config->acs_cfg.ch_width; + psap_ctx->sec_ch_freq = config->sec_ch_freq; + qdf_mem_copy(psap_ctx->self_mac_addr, + config->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + + return status; +} + +eCsrPhyMode wlan_sap_get_phymode(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer from ctx"); + return 0; + } + return sap_ctx->phyMode; +} + +enum phy_ch_width wlan_sap_get_concurrent_bw(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_psoc *psoc, + qdf_freq_t con_ch_freq, + enum phy_ch_width channel_width) +{ + enum hw_mode_bandwidth sta_ch_width; + enum phy_ch_width sta_chan_width = CH_WIDTH_20MHZ; + bool scc_sta_present, is_con_chan_dfs = false; + bool is_con_sta_indoor = false; + uint8_t sta_vdev_id; + uint8_t sta_sap_scc_on_dfs_chnl; + uint8_t sta_count = 0; + bool is_hw_dbs_capable = false; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(con_ch_freq)) + return channel_width; + + if (wlan_reg_is_6ghz_chan_freq(con_ch_freq)) + return channel_width; + + /* sta_count is to check if there is STA present on any other + * channel freq irrespective of concurrent channel. + */ + sta_count = policy_mgr_mode_specific_connection_count( + psoc, + PM_STA_MODE, + NULL); + scc_sta_present = policy_mgr_is_sta_present_on_freq(psoc, + &sta_vdev_id, + con_ch_freq, + &sta_ch_width); + if (scc_sta_present) { + sta_chan_width = policy_mgr_get_ch_width(sta_ch_width); + sap_debug("sta_chan_width:%d, channel_width:%d", + sta_chan_width, channel_width); + if (wlan_reg_is_dfs_for_freq(pdev, con_ch_freq) || + sta_chan_width == CH_WIDTH_160MHZ) + is_con_chan_dfs = true; + else if (WLAN_REG_IS_5GHZ_CH_FREQ(con_ch_freq) && + wlan_reg_is_freq_indoor(pdev, con_ch_freq)) + is_con_sta_indoor = true; + } + + policy_mgr_get_sta_sap_scc_on_dfs_chnl(psoc, &sta_sap_scc_on_dfs_chnl); + is_hw_dbs_capable = policy_mgr_is_hw_dbs_capable(psoc); + sap_debug("sta_sap_scc_on_dfs_chnl:%d, is_hw_dbs_capable:%d, sta_count:%d, scc_sta_present:%d", + sta_sap_scc_on_dfs_chnl, + is_hw_dbs_capable, sta_count, scc_sta_present); + + /* + * In indoor concurrency cases, limit the channel width with the STA + * interface bandwidth. Since, only the bonded channels are active + * channels. + */ + if (is_con_sta_indoor) { + channel_width = QDF_MIN(sta_chan_width, channel_width); + sap_debug("STA + SAP on indoor channels"); + return channel_width; + } else if (!is_con_chan_dfs) { + /* Handle "Active channel" concurrency/standalone SAP */ + sap_debug("STA + SAP/GO or standalone SAP on active channel"); + if (scc_sta_present) + return QDF_MAX(sta_chan_width, CH_WIDTH_80MHZ); + else if (sta_count) + return QDF_MIN(channel_width, CH_WIDTH_80MHZ); + return channel_width; + } + + /* Handle "DBS/non-DBS + dfs channels" concurrency */ + if (is_con_chan_dfs) { + switch (sta_sap_scc_on_dfs_chnl) { + case PM_STA_SAP_ON_DFS_MASTER_MODE_FLEX: + if (scc_sta_present) { + sap_debug("STA+SAP/GO: limit the SAP channel width"); + return QDF_MIN(sta_chan_width, channel_width); + } + + sap_debug("Standalone SAP/GO: set BW coming in start req"); + return channel_width; + case PM_STA_SAP_ON_DFS_MASTER_MODE_DISABLED: + if (scc_sta_present) { + sap_debug("STA present: Limit the SAP channel width"); + channel_width = QDF_MIN(sta_chan_width, + channel_width); + return channel_width; + } + /* + * sta_sap_scc_on_dfs_chnl = 1, DFS master is disabled. + * If STA not present (SAP single), the SAP (160Mhz) is + * not allowed on DFS, so limit SAP to 80Mhz. + */ + sap_debug("Limit Standalone SAP/GO to 80Mhz"); + return QDF_MIN(channel_width, CH_WIDTH_80MHZ); + case PM_STA_SAP_ON_DFS_DEFAULT: + default: + /* + * sta_sap_scc_on_dfs_chnl = 0, not allow STA+SAP SCC on DFS. + * Limit SAP to 80Mhz if STA present. + */ + if (sta_count) { + sap_debug("STA present, Limit SAP/GO to 80Mhz"); + return QDF_MIN(channel_width, CH_WIDTH_80MHZ); + } + break; + } + } + + sap_debug("Single SAP/GO: set BW coming in SAP/GO start req"); + return channel_width; + +} + +uint32_t wlan_sap_get_vht_ch_width(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return 0; + } + + return sap_ctx->ch_params.ch_width; +} + +bool wlan_sap_get_ch_params(struct sap_context *sap_ctx, + struct ch_params *ch_params) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return false; + } + + *ch_params = sap_ctx->ch_params; + return true; +} + +/** + * wlan_sap_validate_channel_switch() - validate target channel switch w.r.t + * concurreny rules set to avoid channel interference. + * @mac_handle: Opaque handle to the global MAC context + * @sap_ch_freq: channel to switch + * @sap_context: sap session context + * + * Return: true if there is no channel interference else return false + */ +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +static bool wlan_sap_validate_channel_switch(mac_handle_t mac_handle, + uint32_t sap_ch_freq, + struct sap_context *sap_context) +{ + return sme_validate_sap_channel_switch( + mac_handle, + sap_ch_freq, + sap_context->phyMode, + sap_context->cc_switch_mode, + sap_context->sessionId); +} +#else +static bool wlan_sap_validate_channel_switch(mac_handle_t mac_handle, + uint32_t sap_ch_freq, + struct sap_context *sap_context) +{ + return true; +} +#endif + +void wlan_sap_set_sap_ctx_acs_cfg(struct sap_context *sap_ctx, + struct sap_config *sap_config) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return; + } + + sap_ctx->acs_cfg = &sap_config->acs_cfg; +} + +QDF_STATUS wlansap_start_bss(struct sap_context *sap_ctx, + sap_event_cb sap_event_cb, + struct sap_config *config, void *user_context) +{ + struct sap_sm_event sap_event; /* State machine event */ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + uint32_t auto_channel_select_weight = + cfg_default(CFG_AUTO_CHANNEL_SELECT_WEIGHT); + int reduced_beacon_interval; + struct mac_context *pmac = NULL; + int sap_chanswitch_beacon_cnt; + bool sap_chanswitch_mode; + + if (!sap_ctx) { + sap_info("Invalid SAP context"); + return QDF_STATUS_E_FAULT; + } + + pmac = sap_get_mac_context(); + if (!pmac) { + sap_err("Invalid sap MAC context"); + qdf_status = QDF_STATUS_E_INVAL; + goto fail; + } + + sap_ctx->fsm_state = SAP_INIT; + sap_debug("sap_fsm: vdev %d: => SAP_INIT", sap_ctx->vdev_id); + + qdf_status = wlan_set_vdev_crypto_prarams_from_ie( + sap_ctx->vdev, + config->RSNWPAReqIE, + config->RSNWPAReqIELength); + if (QDF_IS_STATUS_ERROR(qdf_status)) + sap_debug("Failed to set crypto params from IE"); + + /* Channel selection is auto or configured */ + sap_ctx->chan_freq = config->chan_freq; + sap_ctx->dfs_mode = config->acs_dfs_mode; + sap_ctx->ch_params = config->ch_params; + sap_ctx->ch_width_orig = config->ch_width_orig; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + sap_ctx->cc_switch_mode = config->cc_switch_mode; +#endif + + qdf_status = ucfg_mlme_get_auto_channel_weight( + pmac->psoc, + &auto_channel_select_weight); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sap_err("get_auto_channel_weight failed"); + + sap_ctx->auto_channel_select_weight = auto_channel_select_weight; + + sap_ctx->user_context = user_context; + sap_ctx->enableOverLapCh = config->enOverLapCh; + sap_ctx->acs_cfg = &config->acs_cfg; + sap_ctx->sec_ch_freq = config->sec_ch_freq; + sap_ctx->dfs_cac_offload = config->dfs_cac_offload; + sap_ctx->isCacStartNotified = false; + sap_ctx->isCacEndNotified = false; + sap_ctx->is_chan_change_inprogress = false; + sap_ctx->disabled_mcs13 = false; + sap_ctx->phyMode = config->SapHw_mode; + sap_ctx->csa_reason = CSA_REASON_UNKNOWN; + sap_ctx->require_h2e = config->require_h2e; + qdf_mem_copy(sap_ctx->bssid.bytes, config->self_macaddr.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(sap_ctx->self_mac_addr, + config->self_macaddr.bytes, QDF_MAC_ADDR_SIZE); + /* + * Set the DFS Test Mode setting + * Set beacon channel count before channel switch + */ + qdf_status = ucfg_mlme_get_sap_chn_switch_bcn_count( + pmac->psoc, + &sap_chanswitch_beacon_cnt); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sap_err("ucfg_mlme_get_sap_chn_switch_bcn_count fail, set def"); + + pmac->sap.SapDfsInfo.sap_ch_switch_beacon_cnt = + sap_chanswitch_beacon_cnt; + pmac->sap.SapDfsInfo.sap_ch_switch_mode = + sap_chanswitch_beacon_cnt; + + qdf_status = ucfg_mlme_get_sap_channel_switch_mode( + pmac->psoc, + &sap_chanswitch_mode); + if (QDF_IS_STATUS_ERROR(qdf_status)) + sap_err("ucfg_mlme_get_sap_channel_switch_mode, set def"); + + pmac->sap.SapDfsInfo.sap_ch_switch_mode = sap_chanswitch_mode; + pmac->sap.sapCtxList[sap_ctx->sessionId].sap_context = sap_ctx; + pmac->sap.sapCtxList[sap_ctx->sessionId].sapPersona = + config->persona; + + qdf_status = ucfg_mlme_get_sap_reduces_beacon_interval( + pmac->psoc, + &reduced_beacon_interval); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sap_err("ucfg_mlme_get_sap_reduces_beacon_interval fail"); + + pmac->sap.SapDfsInfo.reduced_beacon_interval = + reduced_beacon_interval; + sap_debug("SAP: auth ch select weight:%d chswitch bcn cnt:%d chswitch mode:%d reduced bcn intv:%d", + sap_ctx->auto_channel_select_weight, + sap_chanswitch_beacon_cnt, + pmac->sap.SapDfsInfo.sap_ch_switch_mode, + pmac->sap.SapDfsInfo.reduced_beacon_interval); + + /* Copy MAC filtering settings to sap context */ + sap_ctx->eSapMacAddrAclMode = config->SapMacaddr_acl; + qdf_mem_copy(sap_ctx->acceptMacList, config->accept_mac, + sizeof(config->accept_mac)); + sap_ctx->nAcceptMac = config->num_accept_mac; + sap_sort_mac_list(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + qdf_mem_copy(sap_ctx->denyMacList, config->deny_mac, + sizeof(config->deny_mac)); + sap_ctx->nDenyMac = config->num_deny_mac; + sap_sort_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac); + sap_ctx->beacon_tx_rate = config->beacon_tx_rate; + + /* Fill in the event structure for FSM */ + sap_event.event = eSAP_HDD_START_INFRA_BSS; + sap_event.params = 0; /* pSapPhysLinkCreate */ + + /* Store the HDD callback in SAP context */ + sap_ctx->sap_event_cb = sap_event_cb; + + sap_ctx->sap_bss_cfg.vdev_id = sap_ctx->sessionId; + sap_build_start_bss_config(&sap_ctx->sap_bss_cfg, config); + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); +fail: + if (QDF_IS_STATUS_ERROR(qdf_status)) + qdf_mem_zero(&sap_ctx->sap_bss_cfg, + sizeof(sap_ctx->sap_bss_cfg)); + return qdf_status; +} /* wlansap_start_bss */ + +QDF_STATUS wlansap_set_mac_acl(struct sap_context *sap_ctx, + struct sap_config *config) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + sap_debug("wlansap_set_mac_acl"); + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + /* Copy MAC filtering settings to sap context */ + sap_ctx->eSapMacAddrAclMode = config->SapMacaddr_acl; + + if (eSAP_DENY_UNLESS_ACCEPTED == sap_ctx->eSapMacAddrAclMode) { + qdf_mem_copy(sap_ctx->acceptMacList, + config->accept_mac, + sizeof(config->accept_mac)); + sap_ctx->nAcceptMac = config->num_accept_mac; + sap_sort_mac_list(sap_ctx->acceptMacList, + sap_ctx->nAcceptMac); + } else if (eSAP_ACCEPT_UNLESS_DENIED == sap_ctx->eSapMacAddrAclMode) { + qdf_mem_copy(sap_ctx->denyMacList, config->deny_mac, + sizeof(config->deny_mac)); + sap_ctx->nDenyMac = config->num_deny_mac; + sap_sort_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac); + } + + return qdf_status; +} /* wlansap_set_mac_acl */ + +QDF_STATUS wlansap_stop_bss(struct sap_context *sap_ctx) +{ + struct sap_sm_event sap_event; /* State machine event */ + QDF_STATUS qdf_status; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + /* Fill in the event structure for FSM */ + sap_event.event = eSAP_HDD_STOP_INFRA_BSS; + sap_event.params = 0; + + /* Handle event */ + qdf_status = sap_fsm(sap_ctx, &sap_event); + + return qdf_status; +} + +/* This routine will set the mode of operation for ACL dynamically*/ +QDF_STATUS wlansap_set_acl_mode(struct sap_context *sap_ctx, + eSapMacAddrACL mode) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->eSapMacAddrAclMode = mode; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_get_acl_mode(struct sap_context *sap_ctx, + eSapMacAddrACL *mode) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + *mode = sap_ctx->eSapMacAddrAclMode; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_get_acl_accept_list(struct sap_context *sap_ctx, + struct qdf_mac_addr *pAcceptList, + uint16_t *nAcceptList) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + memcpy(pAcceptList, sap_ctx->acceptMacList, + (sap_ctx->nAcceptMac * QDF_MAC_ADDR_SIZE)); + *nAcceptList = sap_ctx->nAcceptMac; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_get_acl_deny_list(struct sap_context *sap_ctx, + struct qdf_mac_addr *pDenyList, + uint16_t *nDenyList) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer from p_cds_gctx"); + return QDF_STATUS_E_FAULT; + } + + memcpy(pDenyList, sap_ctx->denyMacList, + (sap_ctx->nDenyMac * QDF_MAC_ADDR_SIZE)); + *nDenyList = sap_ctx->nDenyMac; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_clear_acl(struct sap_context *sap_ctx) +{ + uint16_t i; + + if (!sap_ctx) { + return QDF_STATUS_E_RESOURCES; + } + + for (i = 0; i < sap_ctx->nDenyMac; i++) { + qdf_mem_zero((sap_ctx->denyMacList + i)->bytes, + QDF_MAC_ADDR_SIZE); + } + + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + sap_ctx->nDenyMac = 0; + + for (i = 0; i < sap_ctx->nAcceptMac; i++) { + qdf_mem_zero((sap_ctx->acceptMacList + i)->bytes, + QDF_MAC_ADDR_SIZE); + } + + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + sap_ctx->nAcceptMac = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_modify_acl(struct sap_context *sap_ctx, + uint8_t *peer_sta_mac, + eSapACLType list_type, eSapACLCmdType cmd) +{ + bool sta_allow_list = false, sta_deny_list = false; + uint16_t staWLIndex, staBLIndex; + + if (!sap_ctx) { + sap_err("Invalid SAP Context"); + return QDF_STATUS_E_FAULT; + } + if (qdf_mem_cmp(sap_ctx->bssid.bytes, peer_sta_mac, + QDF_MAC_ADDR_SIZE) == 0) { + sap_err("requested peer mac is "QDF_MAC_ADDR_FMT + "our own SAP BSSID. Do not denylist or allowlist this BSSID", + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_E_FAULT; + } + sap_debug("Modify ACL entered\n" "Before modification of ACL\n" + "size of accept and deny lists %d %d", sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + sap_debug("*** ALLOW LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + sap_debug("*** DENY LIST ***"); + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + + /* the expectation is a mac addr will not be in both the lists + * at the same time. It is the responsibility of userspace to + * ensure this + */ + sta_allow_list = + sap_search_mac_list(sap_ctx->acceptMacList, sap_ctx->nAcceptMac, + peer_sta_mac, &staWLIndex); + sta_deny_list = + sap_search_mac_list(sap_ctx->denyMacList, sap_ctx->nDenyMac, + peer_sta_mac, &staBLIndex); + + if (sta_allow_list && sta_deny_list) { + sap_err("Peer mac " QDF_MAC_ADDR_FMT + " found in allow and deny lists." + "Initial lists passed incorrect. Cannot execute this command.", + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + + } + sap_debug("cmd %d", cmd); + + switch (list_type) { + case SAP_ALLOW_LIST: + if (cmd == ADD_STA_TO_ACL || cmd == ADD_STA_TO_ACL_NO_DEAUTH) { + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nAcceptMac == MAX_ACL_MAC_ADDRESS) { + sap_err("Allow list is already maxed out. Cannot accept " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + if (sta_allow_list) { + /* + * Do nothing if already present in allow + * list. Just print a warning + */ + sap_warn("MAC address already present in allow list " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_SUCCESS; + } + if (sta_deny_list) { + /* + * remove it from deny list before adding + * to the allow list + */ + sap_warn("STA present in deny list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + } + sap_debug("... Now add to the allow list"); + sap_add_mac_to_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + peer_sta_mac); + sap_debug("size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL || + cmd == DELETE_STA_FROM_ACL_NO_DEAUTH) { + if (sta_allow_list) { + + struct csr_del_sta_params delStaParams; + + sap_info("Delete from allow list"); + sap_remove_mac_from_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + staWLIndex); + /* If a client is deleted from allow list and */ + /* it is connected, send deauth + */ + if (cmd == DELETE_STA_FROM_ACL) { + wlansap_populate_del_sta_params( + peer_sta_mac, + eCsrForcedDeauthSta, + SIR_MAC_MGMT_DEAUTH, + &delStaParams); + wlansap_deauth_sta(sap_ctx, + &delStaParams); + sap_debug("size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } + } else { + sap_warn("MAC address to be deleted is not present in the allow list " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + } else { + sap_err("Invalid cmd type passed"); + return QDF_STATUS_E_FAILURE; + } + break; + + case SAP_DENY_LIST: + + if (cmd == ADD_STA_TO_ACL || cmd == ADD_STA_TO_ACL_NO_DEAUTH) { + struct csr_del_sta_params delStaParams; + /* error check */ + /* if list is already at max, return failure */ + if (sap_ctx->nDenyMac == MAX_ACL_MAC_ADDRESS) { + sap_err("Deny list is already maxed out. Cannot accept " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + if (sta_deny_list) { + /* + * Do nothing if already present in + * allow list + */ + sap_warn("MAC address already present in deny list " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_SUCCESS; + } + if (sta_allow_list) { + /* + * remove it from allow list before adding to + * the deny list + */ + sap_warn("Present in allow list so first remove from it"); + sap_remove_mac_from_acl(sap_ctx->acceptMacList, + &sap_ctx->nAcceptMac, + staWLIndex); + } + /* If we are adding a client to the deny list; */ + /* if its connected, send deauth + */ + if (cmd == ADD_STA_TO_ACL) { + wlansap_populate_del_sta_params( + peer_sta_mac, + eCsrForcedDeauthSta, + SIR_MAC_MGMT_DEAUTH, + &delStaParams); + wlansap_deauth_sta(sap_ctx, &delStaParams); + } + sap_info("... Now add to deny list"); + sap_add_mac_to_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, peer_sta_mac); + sap_debug("size of accept and deny lists %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else if (cmd == DELETE_STA_FROM_ACL || + cmd == DELETE_STA_FROM_ACL_NO_DEAUTH) { + if (sta_deny_list) { + sap_info("Delete from deny list"); + sap_remove_mac_from_acl(sap_ctx->denyMacList, + &sap_ctx->nDenyMac, + staBLIndex); + sap_debug("no accept and deny mac %d %d", + sap_ctx->nAcceptMac, + sap_ctx->nDenyMac); + } else { + sap_warn("MAC address to be deleted is not present in the deny list " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_sta_mac)); + return QDF_STATUS_E_FAILURE; + } + } else { + sap_err("Invalid cmd type passed"); + return QDF_STATUS_E_FAILURE; + } + break; + + default: + { + sap_err("Invalid list type passed %d", list_type); + return QDF_STATUS_E_FAILURE; + } + } + sap_debug("After modification of ACL"); + sap_debug("*** ALLOW LIST ***"); + sap_print_acl(sap_ctx->acceptMacList, sap_ctx->nAcceptMac); + sap_debug("*** DENY LIST ***"); + sap_print_acl(sap_ctx->denyMacList, sap_ctx->nDenyMac); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_disassoc_sta(struct sap_context *sap_ctx, + struct csr_del_sta_params *params) +{ + struct mac_context *mac; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + return sme_roam_disconnect_sta(MAC_HANDLE(mac), sap_ctx->sessionId, + params); +} + +QDF_STATUS wlansap_deauth_sta(struct sap_context *sap_ctx, + struct csr_del_sta_params *params) +{ + struct mac_context *mac; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + return sme_roam_deauth_sta(MAC_HANDLE(mac), sap_ctx->sessionId, + params); +} + +#if defined(WLAN_FEATURE_11BE) +static enum phy_ch_width +wlansap_get_target_eht_phy_ch_width(void) +{ + uint32_t max_fw_bw = sme_get_eht_ch_width(); + + if (max_fw_bw == WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ) + return CH_WIDTH_320MHZ; + else if (max_fw_bw == WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + return CH_WIDTH_160MHZ; + else + return CH_WIDTH_80MHZ; +} +#else /* !WLAN_FEATURE_11BE */ +static enum phy_ch_width +wlansap_get_target_eht_phy_ch_width(void) +{ + return CH_WIDTH_20MHZ; +} +#endif /* WLAN_FEATURE_11BE */ + +static enum phy_ch_width +wlansap_5g_original_bw_validate( + struct sap_context *sap_context, + uint32_t chan_freq, + enum phy_ch_width ch_width) +{ + if (sap_context->csa_reason != CSA_REASON_USER_INITIATED && + sap_context->csa_reason != CSA_REASON_PRE_CAC_SUCCESS && + WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq) && + ch_width >= CH_WIDTH_160MHZ && + sap_context->ch_width_orig < CH_WIDTH_160MHZ) + ch_width = CH_WIDTH_80MHZ; + + return ch_width; +} + +/** + * wlansap_2g_original_bw_validate() - validate bw for sap on 2.4 GHz + * @sap_context: sap context + * @chan_freq: channel frequency + * @ch_width: band width + * @sec_ch_freq: secondary channel frequency + * + * If initial SAP starts on 2.4 GHz HT40/HT20 mode, driver honors it. + * + * Return: new bandwidth + */ +static enum phy_ch_width +wlansap_2g_original_bw_validate(struct sap_context *sap_context, + uint32_t chan_freq, + enum phy_ch_width ch_width, + qdf_freq_t *sec_ch_freq) +{ + if (sap_context->csa_reason == CSA_REASON_UNKNOWN && + WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq) && + sap_context->ch_width_orig == CH_WIDTH_40MHZ) { + ch_width = CH_WIDTH_40MHZ; + if (sap_context->ch_params.sec_ch_offset == LOW_PRIMARY_CH) + *sec_ch_freq = chan_freq + 20; + else if (sap_context->ch_params.sec_ch_offset == + HIGH_PRIMARY_CH) + *sec_ch_freq = chan_freq - 20; + else + *sec_ch_freq = 0; + } + + return ch_width; +} + +enum phy_ch_width +wlansap_get_csa_chanwidth_from_phymode(struct sap_context *sap_context, + uint32_t chan_freq, + struct ch_params *tgt_ch_params) +{ + enum phy_ch_width ch_width, concurrent_bw = 0; + struct mac_context *mac; + struct ch_params ch_params = {0}; + uint32_t channel_bonding_mode = 0; + qdf_freq_t sec_ch_freq = 0; + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return CH_WIDTH_20MHZ; + } + + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq)) { + /* + * currently OBSS scan is done in hostapd, so to avoid + * SAP coming up in HT40 on channel switch we are + * disabling channel bonding in 2.4Ghz. + */ + ch_width = wlansap_2g_original_bw_validate( + sap_context, chan_freq, CH_WIDTH_20MHZ, + &sec_ch_freq); + } else { + wlan_mlme_get_channel_bonding_5ghz(mac->psoc, + &channel_bonding_mode); + if (policy_mgr_is_vdev_ll_lt_sap(mac->psoc, + sap_context->vdev_id) || + (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq) && + !channel_bonding_mode)) + ch_width = CH_WIDTH_20MHZ; + else + ch_width = wlansap_get_max_bw_by_phymode(sap_context); + + ch_width = wlansap_5g_original_bw_validate( + sap_context, chan_freq, ch_width); + concurrent_bw = wlan_sap_get_concurrent_bw( + mac->pdev, mac->psoc, chan_freq, + ch_width); + ch_width = QDF_MIN(ch_width, concurrent_bw); + if (tgt_ch_params) + ch_width = QDF_MIN(ch_width, tgt_ch_params->ch_width); + + if (ch_width == CH_WIDTH_320MHZ) + ch_width = wlan_mlme_get_ap_oper_ch_width( + sap_context->vdev); + } + ch_params.ch_width = ch_width; + if (sap_phymode_is_eht(sap_context->phyMode)) + wlan_reg_set_create_punc_bitmap(&ch_params, true); + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, chan_freq, + sec_ch_freq, &ch_params, + REG_CURRENT_PWR_MODE); + ch_width = ch_params.ch_width; + if (tgt_ch_params) + *tgt_ch_params = ch_params; + sap_nofl_debug("csa freq %d bw %d (phymode %d con bw %d tgt bw %d orig %d reason %d) channel bonding 5g %d", + chan_freq, ch_width, + sap_context->phyMode, + concurrent_bw, + tgt_ch_params ? tgt_ch_params->ch_width : CH_WIDTH_MAX, + sap_context->ch_width_orig, + sap_context->csa_reason, + channel_bonding_mode); + + return ch_width; +} + +/** + * sap_start_csa_restart() - send csa start event + * @mac: mac ctx + * @sap_ctx: SAP context + * + * Return: QDF_STATUS + */ +static inline void sap_start_csa_restart(struct mac_context *mac, + struct sap_context *sap_ctx) +{ + sme_csa_restart(mac, sap_ctx->sessionId); +} + +/** + * sap_get_csa_reason_str() - Get csa reason in string + * @reason: sap reason enum value + * + * Return: string reason + */ +const char *sap_get_csa_reason_str(enum sap_csa_reason_code reason) +{ + switch (reason) { + case CSA_REASON_UNKNOWN: + return "UNKNOWN"; + case CSA_REASON_STA_CONNECT_DFS_TO_NON_DFS: + return "STA_CONNECT_DFS_TO_NON_DFS"; + case CSA_REASON_USER_INITIATED: + return "USER_INITIATED"; + case CSA_REASON_PEER_ACTION_FRAME: + return "PEER_ACTION_FRAME"; + case CSA_REASON_PRE_CAC_SUCCESS: + return "PRE_CAC_SUCCESS"; + case CSA_REASON_CONCURRENT_STA_CHANGED_CHANNEL: + return "CONCURRENT_STA_CHANGED_CHANNEL"; + case CSA_REASON_UNSAFE_CHANNEL: + return "UNSAFE_CHANNEL"; + case CSA_REASON_LTE_COEX: + return "LTE_COEX"; + case CSA_REASON_CONCURRENT_NAN_EVENT: + return "CONCURRENT_NAN_EVENT"; + case CSA_REASON_BAND_RESTRICTED: + return "BAND_RESTRICTED"; + case CSA_REASON_DCS: + return "DCS"; + case CSA_REASON_CHAN_DISABLED: + return "DISABLED"; + case CSA_REASON_CHAN_PASSIVE: + return "PASSIVE"; + case CSA_REASON_GO_BSS_STARTED: + return "GO_BSS_STARTED"; + case CSA_REASON_SAP_ACS: + return "CSA_REASON_SAP_ACS"; + case CSA_REASON_SAP_FIX_CH_CONC_WITH_GO: + return "SAP_FIX_CH_CONC_WITH_GO"; + case CSA_REASON_CONCURRENT_LL_LT_SAP_EVENT: + return "CONCURRENT_LL_LT_SAP_EVENT"; + default: + return "UNKNOWN"; + } +} + +/** + * wlansap_set_chan_params_for_csa() - Update sap channel parameters + * for channel switch + * @mac: mac ctx + * @sap_ctx: sap context + * @target_chan_freq: target channel frequency in MHz + * @target_bw: target bandwidth + * + * Return: QDF_STATUS_SUCCESS for success. + */ +static QDF_STATUS +wlansap_set_chan_params_for_csa(struct mac_context *mac, + struct sap_context *sap_ctx, + uint32_t target_chan_freq, + enum phy_ch_width target_bw) +{ + struct ch_params tmp_ch_params = {0}; + + tmp_ch_params.ch_width = target_bw; + mac->sap.SapDfsInfo.new_chanWidth = + wlansap_get_csa_chanwidth_from_phymode(sap_ctx, + target_chan_freq, + &tmp_ch_params); + /* + * Copy the requested target channel + * to sap context. + */ + mac->sap.SapDfsInfo.target_chan_freq = target_chan_freq; + mac->sap.SapDfsInfo.new_ch_params.ch_width = + mac->sap.SapDfsInfo.new_chanWidth; + + /* By this time, the best bandwidth is calculated for + * the given target channel. Now, if there was a + * request from user to move to a selected bandwidth, + * we can see if it can be honored. + * + * Ex1: BW80 was selected for the target channel and + * user wants BW40, it can be allowed + * Ex2: BW40 was selected for the target channel and + * user wants BW80, it cannot be allowed for the given + * target channel. + * + * So, the MIN of the selected channel bandwidth and + * user input is used for the bandwidth + */ + if (target_bw != CH_WIDTH_MAX) { + sap_nofl_debug("SAP CSA: target bw:%d new width:%d", + target_bw, + mac->sap.SapDfsInfo.new_ch_params.ch_width); + mac->sap.SapDfsInfo.new_ch_params.ch_width = + mac->sap.SapDfsInfo.new_chanWidth = + QDF_MIN(mac->sap.SapDfsInfo.new_ch_params.ch_width, + target_bw); + } + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(&sap_ctx->ch_params, true); + wlan_reg_set_channel_params_for_pwrmode( + mac->pdev, target_chan_freq, 0, + &mac->sap.SapDfsInfo.new_ch_params, + REG_CURRENT_PWR_MODE); + + return QDF_STATUS_SUCCESS; +} + +bool +wlansap_override_csa_strict_for_sap(mac_handle_t mac_handle, + struct sap_context *sap_ctx, + uint32_t target_chan_freq, + bool strict) +{ + uint8_t existing_vdev_id = WLAN_UMAC_VDEV_ID_MAX; + enum policy_mgr_con_mode existing_vdev_mode = PM_MAX_NUM_OF_MODE; + uint32_t con_freq; + enum phy_ch_width ch_width; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (!mac_ctx || !sap_ctx->vdev || + wlan_vdev_mlme_get_opmode(sap_ctx->vdev) != QDF_SAP_MODE) + return strict; + + if (sap_ctx->csa_reason != CSA_REASON_USER_INITIATED) + return strict; + + if (!policy_mgr_is_force_scc(mac_ctx->psoc)) + return strict; + + existing_vdev_id = + policy_mgr_fetch_existing_con_info( + mac_ctx->psoc, + sap_ctx->sessionId, + target_chan_freq, + &existing_vdev_mode, + &con_freq, &ch_width); + if (existing_vdev_id < WLAN_UMAC_VDEV_ID_MAX && + (existing_vdev_mode == PM_STA_MODE || + existing_vdev_mode == PM_P2P_CLIENT_MODE)) + return strict; + + return true; +} + +QDF_STATUS wlansap_set_channel_change_with_csa(struct sap_context *sap_ctx, + uint32_t target_chan_freq, + enum phy_ch_width target_bw, + bool strict) +{ + struct mac_context *mac; + mac_handle_t mac_handle; + bool valid; + QDF_STATUS status, hw_mode_status; + bool sta_sap_scc_on_dfs_chan; + bool is_dfs; + struct ch_params tmp_ch_params = {0}; + enum channel_state state; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + mac_handle = MAC_HANDLE(mac); + + if (((sap_ctx->acs_cfg && sap_ctx->acs_cfg->acs_mode) || + policy_mgr_restrict_sap_on_unsafe_chan(mac->psoc) || + sap_ctx->csa_reason != CSA_REASON_USER_INITIATED) && + !policy_mgr_is_sap_freq_allowed(mac->psoc, + wlan_vdev_mlme_get_opmode(sap_ctx->vdev), + target_chan_freq)) { + sap_err("%u is unsafe channel freq", target_chan_freq); + return QDF_STATUS_E_FAULT; + } + sap_nofl_debug("SAP CSA: %d BW %d ---> %d BW %d conn on 5GHz:%d, csa_reason:%s(%d) strict %d vdev %d", + sap_ctx->chan_freq, sap_ctx->ch_params.ch_width, + target_chan_freq, target_bw, + policy_mgr_is_any_mode_active_on_band_along_with_session( + mac->psoc, sap_ctx->sessionId, POLICY_MGR_BAND_5), + sap_get_csa_reason_str(sap_ctx->csa_reason), + sap_ctx->csa_reason, strict, sap_ctx->sessionId); + + state = wlan_reg_get_channel_state_for_pwrmode(mac->pdev, + target_chan_freq, + REG_CURRENT_PWR_MODE); + if (state == CHANNEL_STATE_DISABLE || state == CHANNEL_STATE_INVALID) { + sap_nofl_debug("invalid target freq %d state %d", + target_chan_freq, state); + return QDF_STATUS_E_INVAL; + } + + sta_sap_scc_on_dfs_chan = + policy_mgr_is_sta_sap_scc_allowed_on_dfs_chan(mac->psoc); + + tmp_ch_params.ch_width = target_bw; + wlansap_get_csa_chanwidth_from_phymode(sap_ctx, + target_chan_freq, + &tmp_ch_params); + if (target_bw != CH_WIDTH_MAX) { + tmp_ch_params.ch_width = + QDF_MIN(tmp_ch_params.ch_width, target_bw); + sap_nofl_debug("target ch_width %d to %d ", target_bw, + tmp_ch_params.ch_width); + } + + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(&tmp_ch_params, true); + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, target_chan_freq, 0, + &tmp_ch_params, + REG_CURRENT_PWR_MODE); + if (sap_ctx->chan_freq == target_chan_freq && + sap_ctx->ch_params.ch_width == tmp_ch_params.ch_width) { + sap_nofl_debug("target freq and bw %d not changed", + tmp_ch_params.ch_width); + return QDF_STATUS_E_FAULT; + } + is_dfs = wlan_mlme_check_chan_param_has_dfs( + mac->pdev, &tmp_ch_params, + target_chan_freq); + /* + * Now, validate if the passed channel is valid in the + * current regulatory domain. + */ + if (!is_dfs || + (!policy_mgr_is_any_mode_active_on_band_along_with_session( + mac->psoc, sap_ctx->sessionId, + POLICY_MGR_BAND_5) || + sta_sap_scc_on_dfs_chan || + sap_ctx->csa_reason == CSA_REASON_DCS)) { + /* + * validate target channel switch w.r.t various concurrency + * rules set. + */ + if (!strict) { + valid = wlan_sap_validate_channel_switch(mac_handle, + target_chan_freq, + sap_ctx); + if (!valid) { + sap_err("Channel freq switch to %u is not allowed due to concurrent channel interference", + target_chan_freq); + return QDF_STATUS_E_FAULT; + } + } + /* + * Post a CSA IE request to SAP state machine with + * target channel information and also CSA IE required + * flag set in sap_ctx only, if SAP is in SAP_STARTED + * state. + */ + if (sap_ctx->fsm_state == SAP_STARTED) { + status = wlansap_set_chan_params_for_csa( + mac, sap_ctx, target_chan_freq, + target_bw); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + hw_mode_status = + policy_mgr_check_and_set_hw_mode_for_channel_switch( + mac->psoc, sap_ctx->sessionId, + target_chan_freq, + POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_SAP); + + /* + * If hw_mode_status is QDF_STATUS_E_FAILURE, mean HW + * mode change was required but driver failed to set HW + * mode so ignore CSA for the channel. + */ + if (hw_mode_status == QDF_STATUS_E_FAILURE) { + sap_err("HW change required but failed to set hw mode"); + return hw_mode_status; + } + + status = policy_mgr_reset_chan_switch_complete_evt( + mac->psoc); + if (QDF_IS_STATUS_ERROR(status)) { + policy_mgr_check_n_start_opportunistic_timer( + mac->psoc); + return status; + } + + /* + * Set the CSA IE required flag. + */ + mac->sap.SapDfsInfo.csaIERequired = true; + + /* + * Set the radar found status to allow the channel + * change to happen same as in the case of a radar + * detection. Since, this will allow SAP to be in + * correct state and also resume the netif queues + * that were suspended in HDD before the channel + * request was issued. + */ + sap_ctx->sap_radar_found_status = true; + sap_cac_reset_notify(mac_handle); + + /* + * If hw_mode_status is QDF_STATUS_SUCCESS mean HW mode + * change was required and was successfully requested so + * the channel switch will continue after HW mode change + * completion. + */ + if (QDF_IS_STATUS_SUCCESS(hw_mode_status)) { + sap_info("Channel change will continue after HW mode change"); + return QDF_STATUS_SUCCESS; + } + /* + * If hw_mode_status is QDF_STATUS_E_NOSUPPORT or + * QDF_STATUS_E_ALREADY (not QDF_STATUS_E_FAILURE and + * not QDF_STATUS_SUCCESS), mean DBS is not supported or + * required HW mode is already set, So contunue with + * CSA from here. + */ + sap_start_csa_restart(mac, sap_ctx); + } else { + sap_err("Failed to request Channel Change, since SAP is not in SAP_STARTED state"); + return QDF_STATUS_E_FAULT; + } + + } else { + sap_err("Channel freq = %d is not valid in the current" + "regulatory domain, is_dfs %d", target_chan_freq, + is_dfs); + + return QDF_STATUS_E_FAULT; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_sap_getstation_ie_information(struct sap_context *sap_ctx, + uint32_t *len, uint8_t *buf) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + uint32_t ie_len = 0; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + if (len) { + ie_len = *len; + *len = sap_ctx->nStaWPARSnReqIeLength; + sap_info("WPAIE len : %x", *len); + if ((buf) && (ie_len >= sap_ctx->nStaWPARSnReqIeLength)) { + qdf_mem_copy(buf, + sap_ctx->pStaWpaRsnReqIE, + sap_ctx->nStaWPARSnReqIeLength); + sap_info("WPAIE: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(buf)); + qdf_status = QDF_STATUS_SUCCESS; + } + } + return qdf_status; +} + +QDF_STATUS wlan_sap_update_next_channel(struct sap_context *sap_ctx, + uint8_t channel, + enum phy_ch_width chan_bw) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + sap_ctx->dfs_vendor_channel = channel; + sap_ctx->dfs_vendor_chan_bw = chan_bw; + + return QDF_STATUS_SUCCESS; +} + +void wlansap_get_sec_channel(uint8_t sec_ch_offset, + uint32_t op_chan_freq, + uint32_t *sec_chan_freq) +{ + switch (sec_ch_offset) { + case LOW_PRIMARY_CH: + *sec_chan_freq = op_chan_freq + 20; + break; + case HIGH_PRIMARY_CH: + *sec_chan_freq = op_chan_freq - 20; + break; + default: + *sec_chan_freq = 0; + } +} + +#ifdef WLAN_FEATURE_11BE +static void +wlansap_fill_channel_change_puncture(struct channel_change_req *req, + struct ch_params *ch_param) +{ + req->target_punc_bitmap = ch_param->reg_punc_bitmap; +} +#else +static inline void +wlansap_fill_channel_change_puncture(struct channel_change_req *req, + struct ch_params *ch_param) +{ +} +#endif + +/** + * wlansap_fill_channel_change_request() - Fills the channel change request + * @sap_ctx: sap context + * @req: pointer to change channel request + * + * This function fills the channel change request for SAP + * + * Return: None + */ +static void +wlansap_fill_channel_change_request(struct sap_context *sap_ctx, + struct channel_change_req *req) +{ + struct mac_context *mac_ctx = sap_get_mac_context(); + struct bss_dot11_config dot11_cfg = {0}; + uint8_t h2e; + + dot11_cfg.vdev_id = sap_ctx->sessionId; + dot11_cfg.bss_op_ch_freq = sap_ctx->chan_freq; + dot11_cfg.phy_mode = sap_ctx->phyMode; + dot11_cfg.privacy = sap_ctx->sap_bss_cfg.privacy; + + /* Rates configured from start_bss will have + * hostapd rates if hostapd chan rates are enabled + */ + qdf_mem_copy(dot11_cfg.opr_rates.rate, + sap_ctx->sap_bss_cfg.operationalRateSet.rate, + sap_ctx->sap_bss_cfg.operationalRateSet.numRates); + dot11_cfg.opr_rates.numRates = + sap_ctx->sap_bss_cfg.operationalRateSet.numRates; + + qdf_mem_copy(dot11_cfg.ext_rates.rate, + sap_ctx->sap_bss_cfg.extendedRateSet.rate, + sap_ctx->sap_bss_cfg.extendedRateSet.numRates); + dot11_cfg.ext_rates.numRates = + sap_ctx->sap_bss_cfg.extendedRateSet.numRates; + sme_get_network_params(mac_ctx, &dot11_cfg); + + req->vdev_id = sap_ctx->sessionId; + req->target_chan_freq = sap_ctx->chan_freq; + req->sec_ch_offset = sap_ctx->ch_params.sec_ch_offset; + req->ch_width = sap_ctx->ch_params.ch_width; + req->center_freq_seg0 = sap_ctx->ch_params.center_freq_seg0; + req->center_freq_seg1 = sap_ctx->ch_params.center_freq_seg1; + wlansap_fill_channel_change_puncture(req, &sap_ctx->ch_params); + + req->dot11mode = dot11_cfg.dot11_mode; + req->nw_type = dot11_cfg.nw_type; + + sap_get_cac_dur_dfs_region(sap_ctx, + &req->cac_duration_ms, + &req->dfs_regdomain, + sap_ctx->chan_freq, + &sap_ctx->ch_params); + mlme_set_cac_required(sap_ctx->vdev, + !!req->cac_duration_ms); + + /* Update the rates in sap_bss_cfg for subsequent channel switch */ + if (dot11_cfg.opr_rates.numRates) { + qdf_mem_copy(req->opr_rates.rate, + dot11_cfg.opr_rates.rate, + dot11_cfg.opr_rates.numRates); + qdf_mem_copy(sap_ctx->sap_bss_cfg.operationalRateSet.rate, + dot11_cfg.opr_rates.rate, + dot11_cfg.opr_rates.numRates); + req->opr_rates.numRates = dot11_cfg.opr_rates.numRates; + sap_ctx->sap_bss_cfg.operationalRateSet.numRates = + dot11_cfg.opr_rates.numRates; + } else { + qdf_mem_zero(&sap_ctx->sap_bss_cfg.operationalRateSet, + sizeof(tSirMacRateSet)); + } + + if (dot11_cfg.ext_rates.numRates) { + qdf_mem_copy(req->ext_rates.rate, + dot11_cfg.ext_rates.rate, + dot11_cfg.ext_rates.numRates); + qdf_mem_copy(sap_ctx->sap_bss_cfg.extendedRateSet.rate, + dot11_cfg.ext_rates.rate, + dot11_cfg.ext_rates.numRates); + req->ext_rates.numRates = dot11_cfg.ext_rates.numRates; + sap_ctx->sap_bss_cfg.extendedRateSet.numRates = + dot11_cfg.ext_rates.numRates; + } else { + qdf_mem_zero(&sap_ctx->sap_bss_cfg.extendedRateSet, + sizeof(tSirMacRateSet)); + } + + if (sap_ctx->require_h2e) { + h2e = WLAN_BASIC_RATE_MASK | + WLAN_BSS_MEMBERSHIP_SELECTOR_SAE_H2E; + if (req->ext_rates.numRates < SIR_MAC_MAX_NUMBER_OF_RATES) { + req->ext_rates.rate[req->ext_rates.numRates] = h2e; + req->ext_rates.numRates++; + sap_debug("H2E bss membership add to ext support rate"); + } else if (req->opr_rates.numRates < + SIR_MAC_MAX_NUMBER_OF_RATES) { + req->opr_rates.rate[req->opr_rates.numRates] = h2e; + req->opr_rates.numRates++; + sap_debug("H2E bss membership add to support rate"); + } else { + sap_err("rates full, can not add H2E bss membership"); + } + } + return; +} + +QDF_STATUS wlansap_channel_change_request(struct sap_context *sap_ctx, + uint32_t target_chan_freq) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx; + eCsrPhyMode phy_mode; + struct ch_params *ch_params; + struct channel_change_req *ch_change_req; + + if (!target_chan_freq) { + sap_err("channel 0 requested"); + return QDF_STATUS_E_FAULT; + } + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + phy_mode = sap_ctx->phyMode; + + /* Update phy_mode if the target channel is in the other band */ + if (WLAN_REG_IS_5GHZ_CH_FREQ(target_chan_freq) && + ((phy_mode == eCSR_DOT11_MODE_11g) || + (phy_mode == eCSR_DOT11_MODE_11g_ONLY))) + phy_mode = eCSR_DOT11_MODE_11a; + else if (WLAN_REG_IS_24GHZ_CH_FREQ(target_chan_freq) && + (phy_mode == eCSR_DOT11_MODE_11a)) + phy_mode = eCSR_DOT11_MODE_11g; + sap_ctx->phyMode = phy_mode; + + if (!sap_ctx->chan_freq) { + sap_err("Invalid channel list"); + return QDF_STATUS_E_FAULT; + } + /* + * We are getting channel bonding mode from sapDfsInfor structure + * because we've implemented channel width fallback mechanism for DFS + * which will result in channel width changing dynamically. + */ + ch_params = &mac_ctx->sap.SapDfsInfo.new_ch_params; + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap(ch_params, true); + wlan_reg_set_channel_params_for_pwrmode(mac_ctx->pdev, target_chan_freq, + 0, ch_params, + REG_CURRENT_PWR_MODE); + sap_ctx->ch_params_before_ch_switch = sap_ctx->ch_params; + sap_ctx->freq_before_ch_switch = sap_ctx->chan_freq; + /* Update the channel as this will be used to + * send event to supplicant + */ + sap_ctx->ch_params = *ch_params; + sap_ctx->chan_freq = target_chan_freq; + wlansap_get_sec_channel(ch_params->sec_ch_offset, sap_ctx->chan_freq, + &sap_ctx->sec_ch_freq); + sap_dfs_set_current_channel(sap_ctx); + + ch_change_req = qdf_mem_malloc(sizeof(struct channel_change_req)); + if (!ch_change_req) + return QDF_STATUS_E_FAILURE; + + wlansap_fill_channel_change_request(sap_ctx, ch_change_req); + + status = sme_send_channel_change_req(MAC_HANDLE(mac_ctx), + ch_change_req); + qdf_mem_free(ch_change_req); + sap_debug("chan_freq:%d phy_mode %d width:%d offset:%d seg0:%d seg1:%d", + sap_ctx->chan_freq, phy_mode, ch_params->ch_width, + ch_params->sec_ch_offset, ch_params->center_freq_seg0, + ch_params->center_freq_seg1); + if (policy_mgr_update_indoor_concurrency(mac_ctx->psoc, + wlan_vdev_get_id(sap_ctx->vdev), + sap_ctx->freq_before_ch_switch, + DISCONNECT_WITH_CONCURRENCY)) + wlan_reg_recompute_current_chan_list(mac_ctx->psoc, + mac_ctx->pdev); + + return status; +} + +QDF_STATUS wlansap_start_beacon_req(struct sap_context *sap_ctx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t dfs_cac_wait_status; + struct mac_context *mac; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + /* No Radar was found during CAC WAIT, So start Beaconing */ + if (!sap_ctx->sap_radar_found_status) { + /* CAC Wait done without any Radar Detection */ + dfs_cac_wait_status = true; + wlan_pre_cac_complete_set(sap_ctx->vdev, false); + status = sme_roam_start_beacon_req(MAC_HANDLE(mac), + sap_ctx->bssid, + dfs_cac_wait_status); + } + + return status; +} + +QDF_STATUS wlansap_dfs_send_csa_ie_request(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + uint32_t new_cac_ms; + uint32_t dfs_region; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + mac->sap.SapDfsInfo.new_ch_params.ch_width = + mac->sap.SapDfsInfo.new_chanWidth; + if (sap_phymode_is_eht(sap_ctx->phyMode)) + wlan_reg_set_create_punc_bitmap( + &mac->sap.SapDfsInfo.new_ch_params, true); + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + mac->sap.SapDfsInfo.target_chan_freq, + 0, &mac->sap.SapDfsInfo.new_ch_params, + REG_CURRENT_PWR_MODE); + + sap_get_cac_dur_dfs_region(sap_ctx, &new_cac_ms, &dfs_region, + mac->sap.SapDfsInfo.target_chan_freq, + &mac->sap.SapDfsInfo.new_ch_params); + mlme_set_cac_required(sap_ctx->vdev, !!new_cac_ms); + sap_debug("chan freq:%d req:%d width:%d off:%d cac %d", + mac->sap.SapDfsInfo.target_chan_freq, + mac->sap.SapDfsInfo.csaIERequired, + mac->sap.SapDfsInfo.new_ch_params.ch_width, + mac->sap.SapDfsInfo.new_ch_params.sec_ch_offset, + new_cac_ms); + + return sme_roam_csa_ie_request(MAC_HANDLE(mac), + sap_ctx->bssid, + mac->sap.SapDfsInfo.target_chan_freq, + mac->sap.SapDfsInfo.csaIERequired, + &mac->sap.SapDfsInfo.new_ch_params, + new_cac_ms); +} + +QDF_STATUS wlansap_get_dfs_ignore_cac(mac_handle_t mac_handle, + uint8_t *ignore_cac) +{ + struct mac_context *mac = NULL; + + if (mac_handle) { + mac = MAC_CONTEXT(mac_handle); + } else { + sap_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + + *ignore_cac = mac->sap.SapDfsInfo.ignore_cac; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_set_dfs_ignore_cac(mac_handle_t mac_handle, + uint8_t ignore_cac) +{ + struct mac_context *mac = NULL; + + if (mac_handle) { + mac = MAC_CONTEXT(mac_handle); + } else { + sap_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + + mac->sap.SapDfsInfo.ignore_cac = (ignore_cac >= true) ? + true : false; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_get_dfs_cac_state(mac_handle_t mac_handle, + struct sap_context *sapcontext, + bool *cac_state) +{ + struct mac_context *mac = NULL; + + if (mac_handle) { + mac = MAC_CONTEXT(mac_handle); + } else { + sap_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + if (!sapcontext) { + sap_err("Invalid sapcontext pointer"); + return QDF_STATUS_E_FAULT; + } + + *cac_state = sap_is_dfs_cac_wait_state(sapcontext); + + return QDF_STATUS_SUCCESS; +} + +bool sap_is_auto_channel_select(struct sap_context *sapcontext) +{ + if (!sapcontext) { + sap_err("Invalid SAP pointer"); + return false; + } + return sapcontext->chan_freq == AUTO_CHANNEL_SELECT; +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wlan_sap_set_channel_avoidance() - sets sap mcc channel avoidance ini param + * @mac_handle: Opaque handle to the global MAC context + * @sap_channel_avoidance: ini parameter value + * + * sets sap mcc channel avoidance ini param, to be called in sap_start + * + * Return: success of failure of operation + */ +QDF_STATUS +wlan_sap_set_channel_avoidance(mac_handle_t mac_handle, + bool sap_channel_avoidance) +{ + struct mac_context *mac_ctx = NULL; + + if (mac_handle) { + mac_ctx = MAC_CONTEXT(mac_handle); + } else { + sap_err("mac_handle or mac_ctx pointer NULL"); + return QDF_STATUS_E_FAULT; + } + mac_ctx->sap.sap_channel_avoidance = sap_channel_avoidance; + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +QDF_STATUS +wlan_sap_set_acs_with_more_param(mac_handle_t mac_handle, + bool acs_with_more_param) +{ + struct mac_context *mac_ctx; + + if (mac_handle) { + mac_ctx = MAC_CONTEXT(mac_handle); + } else { + sap_err("mac_handle or mac_ctx pointer NULL"); + return QDF_STATUS_E_FAULT; + } + mac_ctx->sap.acs_with_more_param = acs_with_more_param; + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlansap_set_dfs_preferred_channel_location(mac_handle_t mac_handle) +{ + struct mac_context *mac = NULL; + QDF_STATUS status; + enum dfs_reg dfs_region; + uint8_t dfs_preferred_channels_location = 0; + + if (mac_handle) { + mac = MAC_CONTEXT(mac_handle); + } else { + sap_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + + wlan_reg_get_dfs_region(mac->pdev, &dfs_region); + + /* + * The Indoor/Outdoor only random channel selection + * restriction is currently enforeced only for + * JAPAN regulatory domain. + */ + ucfg_mlme_get_pref_chan_location(mac->psoc, + &dfs_preferred_channels_location); + sap_debug("dfs_preferred_channels_location %d dfs region %d", + dfs_preferred_channels_location, dfs_region); + + if (dfs_region == DFS_MKK_REGION || + dfs_region == DFS_MKKN_REGION) { + mac->sap.SapDfsInfo.sap_operating_chan_preferred_location = + dfs_preferred_channels_location; + sap_debug("sapdfs:Set Preferred Operating Channel location=%d", + mac->sap.SapDfsInfo. + sap_operating_chan_preferred_location); + + status = QDF_STATUS_SUCCESS; + } else { + sap_debug("sapdfs:NOT JAPAN REG, Invalid Set preferred chans location"); + + status = QDF_STATUS_E_FAULT; + } + + return status; +} + +QDF_STATUS wlansap_set_dfs_target_chnl(mac_handle_t mac_handle, + uint32_t target_chan_freq) +{ + struct mac_context *mac = NULL; + + if (mac_handle) { + mac = MAC_CONTEXT(mac_handle); + } else { + sap_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + if (target_chan_freq > 0) { + mac->sap.SapDfsInfo.user_provided_target_chan_freq = + target_chan_freq; + } else { + mac->sap.SapDfsInfo.user_provided_target_chan_freq = 0; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlansap_update_sap_config_add_ie(struct sap_config *config, + const uint8_t *pAdditionIEBuffer, + uint16_t additionIELength, + eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t bufferValid = false; + uint16_t bufferLength = 0; + uint8_t *pBuffer = NULL; + + if (!config) { + return QDF_STATUS_E_FAULT; + } + + if ((pAdditionIEBuffer) && (additionIELength != 0)) { + /* initialize the buffer pointer so that pe can copy */ + if (additionIELength > 0) { + bufferLength = additionIELength; + pBuffer = qdf_mem_malloc(bufferLength); + if (!pBuffer) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(pBuffer, pAdditionIEBuffer, bufferLength); + bufferValid = true; + sap_debug("update_type: %d", updateType); + qdf_trace_hex_dump(QDF_MODULE_ID_SAP, + QDF_TRACE_LEVEL_DEBUG, pBuffer, bufferLength); + } + } + + switch (updateType) { + case eUPDATE_IE_PROBE_BCN: + if (config->pProbeRespBcnIEsBuffer) + qdf_mem_free(config->pProbeRespBcnIEsBuffer); + if (bufferValid) { + config->probeRespBcnIEsLen = bufferLength; + config->pProbeRespBcnIEsBuffer = pBuffer; + } else { + config->probeRespBcnIEsLen = 0; + config->pProbeRespBcnIEsBuffer = NULL; + } + break; + case eUPDATE_IE_PROBE_RESP: + if (config->pProbeRespIEsBuffer) + qdf_mem_free(config->pProbeRespIEsBuffer); + if (bufferValid) { + config->probeRespIEsBufferLen = bufferLength; + config->pProbeRespIEsBuffer = pBuffer; + } else { + config->probeRespIEsBufferLen = 0; + config->pProbeRespIEsBuffer = NULL; + } + break; + case eUPDATE_IE_ASSOC_RESP: + if (config->pAssocRespIEsBuffer) + qdf_mem_free(config->pAssocRespIEsBuffer); + if (bufferValid) { + config->assocRespIEsLen = bufferLength; + config->pAssocRespIEsBuffer = pBuffer; + } else { + config->assocRespIEsLen = 0; + config->pAssocRespIEsBuffer = NULL; + } + break; + default: + sap_debug("No matching buffer type %d", updateType); + if (pBuffer) + qdf_mem_free(pBuffer); + break; + } + + return status; +} + +QDF_STATUS +wlansap_reset_sap_config_add_ie(struct sap_config *config, + eUpdateIEsType updateType) +{ + if (!config) { + sap_err("Invalid Config pointer"); + return QDF_STATUS_E_FAULT; + } + + switch (updateType) { + case eUPDATE_IE_ALL: /*only used to reset */ + case eUPDATE_IE_PROBE_RESP: + if (config->pProbeRespIEsBuffer) { + qdf_mem_free(config->pProbeRespIEsBuffer); + config->probeRespIEsBufferLen = 0; + config->pProbeRespIEsBuffer = NULL; + } + if (eUPDATE_IE_ALL != updateType) + break; + fallthrough; + case eUPDATE_IE_ASSOC_RESP: + if (config->pAssocRespIEsBuffer) { + qdf_mem_free(config->pAssocRespIEsBuffer); + config->assocRespIEsLen = 0; + config->pAssocRespIEsBuffer = NULL; + } + if (eUPDATE_IE_ALL != updateType) + break; + fallthrough; + case eUPDATE_IE_PROBE_BCN: + if (config->pProbeRespBcnIEsBuffer) { + qdf_mem_free(config->pProbeRespBcnIEsBuffer); + config->probeRespBcnIEsLen = 0; + config->pProbeRespBcnIEsBuffer = NULL; + } + if (eUPDATE_IE_ALL != updateType) + break; + fallthrough; + default: + if (eUPDATE_IE_ALL != updateType) + sap_err("Invalid buffer type %d", updateType); + break; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_SON +QDF_STATUS +wlansap_son_update_sap_config_phymode(struct wlan_objmgr_vdev *vdev, + struct sap_config *config, + enum qca_wlan_vendor_phy_mode phy_mode) +{ + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_channel *des_chan; + + if (!vdev || !config) { + sap_err("Invalid input parameters"); + return QDF_STATUS_E_FAULT; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + sap_err("Invalid pdev parameters"); + return QDF_STATUS_E_FAULT; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + sap_err("Invalid psoc parameters"); + return QDF_STATUS_E_FAULT; + } + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) { + sap_err("Invalid desired channel"); + return QDF_STATUS_E_FAULT; + } + config->sap_orig_hw_mode = config->SapHw_mode; + config->ch_width_orig = config->ch_params.ch_width; + switch (phy_mode) { + case QCA_WLAN_VENDOR_PHY_MODE_11A: + config->SapHw_mode = eCSR_DOT11_MODE_11a; + config->ch_params.ch_width = CH_WIDTH_20MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11B: + config->SapHw_mode = eCSR_DOT11_MODE_11b; + config->ch_params.ch_width = CH_WIDTH_20MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11G: + config->SapHw_mode = eCSR_DOT11_MODE_11g; + config->ch_params.ch_width = CH_WIDTH_20MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AGN: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT20: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT20: + config->SapHw_mode = eCSR_DOT11_MODE_11n; + config->ch_params.ch_width = CH_WIDTH_20MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NG_HT40: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11NA_HT40: + config->SapHw_mode = eCSR_DOT11_MODE_11n; + config->ch_params.ch_width = CH_WIDTH_40MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT20: + config->SapHw_mode = eCSR_DOT11_MODE_11ac; + config->ch_params.ch_width = CH_WIDTH_20MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40MINUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT40: + config->SapHw_mode = eCSR_DOT11_MODE_11ac; + config->ch_params.ch_width = CH_WIDTH_40MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT80: + config->SapHw_mode = eCSR_DOT11_MODE_11ac; + config->ch_params.ch_width = CH_WIDTH_80MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AC_VHT160: + config->SapHw_mode = eCSR_DOT11_MODE_11ac; + config->ch_params.ch_width = CH_WIDTH_160MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE20: + config->SapHw_mode = eCSR_DOT11_MODE_11ax; + config->ch_params.ch_width = CH_WIDTH_20MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40PLUS: + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE40MINUS: + config->SapHw_mode = eCSR_DOT11_MODE_11ax; + config->ch_params.ch_width = CH_WIDTH_40MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE80: + config->SapHw_mode = eCSR_DOT11_MODE_11ax; + config->ch_params.ch_width = CH_WIDTH_80MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_11AX_HE160: + config->SapHw_mode = eCSR_DOT11_MODE_11ax; + config->ch_params.ch_width = CH_WIDTH_160MHZ; + break; + case QCA_WLAN_VENDOR_PHY_MODE_AUTO: + config->SapHw_mode = eCSR_DOT11_MODE_AUTO; + break; + default: + sap_err("Invalid phy mode %d to configure", phy_mode); + break; + } + + if (sap_phymode_is_eht(config->SapHw_mode)) + wlan_reg_set_create_punc_bitmap(&config->ch_params, true); + if (config->ch_params.ch_width == CH_WIDTH_80P80MHZ && + ucfg_mlme_get_restricted_80p80_bw_supp(psoc)) { + if (!((config->ch_params.center_freq_seg0 == 138 && + config->ch_params.center_freq_seg1 == 155) || + (config->ch_params.center_freq_seg1 == 138 && + config->ch_params.center_freq_seg0 == 155))) { + sap_debug("Falling back to 80 from 80p80 as non supported freq_seq0 %d and freq_seq1 %d", + config->ch_params.mhz_freq_seg0, + config->ch_params.mhz_freq_seg1); + config->ch_params.center_freq_seg1 = 0; + config->ch_params.mhz_freq_seg1 = 0; + config->ch_width_orig = CH_WIDTH_80MHZ; + config->ch_params.ch_width = config->ch_width_orig; + } + } + + config->chan_freq = des_chan->ch_freq; + config->sec_ch_freq = 0; + if (WLAN_REG_IS_24GHZ_CH_FREQ(des_chan->ch_freq) && + config->ch_params.ch_width == CH_WIDTH_40MHZ && + des_chan->ch_width == CH_WIDTH_40MHZ) { + if (des_chan->ch_cfreq1 == des_chan->ch_freq + BW_10_MHZ) + config->sec_ch_freq = des_chan->ch_freq + BW_20_MHZ; + if (des_chan->ch_cfreq1 == des_chan->ch_freq - BW_10_MHZ) + config->sec_ch_freq = des_chan->ch_freq - BW_20_MHZ; + } + wlan_reg_set_channel_params_for_pwrmode(pdev, config->chan_freq, + config->sec_ch_freq, + &config->ch_params, + REG_CURRENT_PWR_MODE); + + return QDF_STATUS_SUCCESS; +} +#endif + +#define ACS_WLAN_20M_CH_INC 20 +#define ACS_2G_EXTEND ACS_WLAN_20M_CH_INC +#define ACS_5G_EXTEND (ACS_WLAN_20M_CH_INC * 3) + +#ifdef CONFIG_BAND_6GHZ +static void wlansap_update_start_range_6ghz( + uint32_t *start_ch_freq, uint32_t *bandStartChannel) +{ + *bandStartChannel = MIN_6GHZ_CHANNEL; + *start_ch_freq = (*start_ch_freq - ACS_5G_EXTEND) > + wlan_reg_ch_to_freq(MIN_6GHZ_CHANNEL) ? + (*start_ch_freq - ACS_5G_EXTEND) : + wlan_reg_ch_to_freq(MIN_6GHZ_CHANNEL); +} + +static void wlansap_update_end_range_6ghz( + uint32_t *end_ch_freq, uint32_t *bandEndChannel) +{ + *bandEndChannel = MAX_6GHZ_CHANNEL; + *end_ch_freq = (*end_ch_freq + ACS_5G_EXTEND) <= + wlan_reg_ch_to_freq(MAX_6GHZ_CHANNEL) ? + (*end_ch_freq + ACS_5G_EXTEND) : + wlan_reg_ch_to_freq(MAX_6GHZ_CHANNEL); +} +#else +static void wlansap_update_start_range_6ghz( + uint32_t *start_ch_freq, uint32_t *bandStartChannel) +{ +} + +static void wlansap_update_end_range_6ghz( + uint32_t *end_ch_freq, uint32_t *bandEndChannel) +{ +} +#endif + +/*========================================================================== + FUNCTION wlansap_extend_to_acs_range + + DESCRIPTION Function extends give channel range to consider ACS chan bonding + + DEPENDENCIES PARAMETERS + + IN /OUT + * start_ch_freq : ACS extend start ch + * end_ch_freq : ACS extended End ch + * bandStartChannel: Band start ch + * bandEndChannel : Band end ch + + RETURN VALUE NONE + + SIDE EFFECTS + ============================================================================*/ +void wlansap_extend_to_acs_range(mac_handle_t mac_handle, + uint32_t *start_ch_freq, + uint32_t *end_ch_freq, + uint32_t *bandStartChannel, + uint32_t *bandEndChannel) +{ + uint32_t tmp_start_ch_freq = 0, tmp_end_ch_freq = 0; + struct mac_context *mac_ctx; + + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) { + sap_err("Invalid mac_ctx"); + return; + } + if (*start_ch_freq <= wlan_reg_ch_to_freq(CHAN_ENUM_2484)) { + *bandStartChannel = CHAN_ENUM_2412; + tmp_start_ch_freq = *start_ch_freq > + wlan_reg_ch_to_freq(CHAN_ENUM_2432) ? + (*start_ch_freq - ACS_2G_EXTEND) : + wlan_reg_ch_to_freq(CHAN_ENUM_2412); + } else if (*start_ch_freq <= wlan_reg_ch_to_freq(CHAN_ENUM_5885)) { + *bandStartChannel = CHAN_ENUM_5180; + tmp_start_ch_freq = (*start_ch_freq - ACS_5G_EXTEND) > + wlan_reg_ch_to_freq(CHAN_ENUM_5180) ? + (*start_ch_freq - ACS_5G_EXTEND) : + wlan_reg_ch_to_freq(CHAN_ENUM_5180); + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(*start_ch_freq)) { + tmp_start_ch_freq = *start_ch_freq; + wlansap_update_start_range_6ghz(&tmp_start_ch_freq, + bandStartChannel); + } else { + *bandStartChannel = CHAN_ENUM_2412; + tmp_start_ch_freq = *start_ch_freq > + wlan_reg_ch_to_freq(CHAN_ENUM_2432) ? + (*start_ch_freq - ACS_2G_EXTEND) : + wlan_reg_ch_to_freq(CHAN_ENUM_2412); + sap_err("unexpected start freq %d", + *start_ch_freq); + } + + if (*end_ch_freq <= wlan_reg_ch_to_freq(CHAN_ENUM_2484)) { + *bandEndChannel = CHAN_ENUM_2484; + tmp_end_ch_freq = (*end_ch_freq + ACS_2G_EXTEND) <= + wlan_reg_ch_to_freq(CHAN_ENUM_2484) ? + (*end_ch_freq + ACS_2G_EXTEND) : + wlan_reg_ch_to_freq(CHAN_ENUM_2484); + } else if (*end_ch_freq <= wlan_reg_ch_to_freq(CHAN_ENUM_5885)) { + *bandEndChannel = CHAN_ENUM_5885; + tmp_end_ch_freq = (*end_ch_freq + ACS_5G_EXTEND) <= + wlan_reg_ch_to_freq(CHAN_ENUM_5885) ? + (*end_ch_freq + ACS_5G_EXTEND) : + wlan_reg_ch_to_freq(CHAN_ENUM_5885); + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(*end_ch_freq)) { + tmp_end_ch_freq = *end_ch_freq; + wlansap_update_end_range_6ghz(&tmp_end_ch_freq, + bandEndChannel); + } else { + *bandEndChannel = CHAN_ENUM_5885; + tmp_end_ch_freq = (*end_ch_freq + ACS_5G_EXTEND) <= + wlan_reg_ch_to_freq(CHAN_ENUM_5885) ? + (*end_ch_freq + ACS_5G_EXTEND) : + wlan_reg_ch_to_freq(CHAN_ENUM_5885); + + sap_err("unexpected end freq %d", *end_ch_freq); + } + *start_ch_freq = tmp_start_ch_freq; + *end_ch_freq = tmp_end_ch_freq; + /* Note if the ACS range include only DFS channels, do not cross range + * Active scanning in adjacent non DFS channels results in transmission + * spikes in DFS spectrum channels which is due to emission spill. + * Remove the active channels from extend ACS range for DFS only range + */ + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, *start_ch_freq)) { + while (!wlan_reg_is_dfs_for_freq( + mac_ctx->pdev, + tmp_start_ch_freq) && + tmp_start_ch_freq < *start_ch_freq) + tmp_start_ch_freq += ACS_WLAN_20M_CH_INC; + + *start_ch_freq = tmp_start_ch_freq; + } + if (wlan_reg_is_dfs_for_freq(mac_ctx->pdev, *end_ch_freq)) { + while (!wlan_reg_is_dfs_for_freq( + mac_ctx->pdev, + tmp_end_ch_freq) && + tmp_end_ch_freq > *end_ch_freq) + tmp_end_ch_freq -= ACS_WLAN_20M_CH_INC; + + *end_ch_freq = tmp_end_ch_freq; + } +} + +QDF_STATUS wlan_sap_set_vendor_acs(struct sap_context *sap_context, + bool is_vendor_acs) +{ + if (!sap_context) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + sap_context->vendor_acs_dfs_lte_enabled = is_vendor_acs; + + return QDF_STATUS_SUCCESS; +} + +#ifdef DFS_COMPONENT_ENABLE +QDF_STATUS wlansap_set_dfs_nol(struct sap_context *sap_ctx, + eSapDfsNolType conf) +{ + struct mac_context *mac; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + if (conf == eSAP_DFS_NOL_CLEAR) { + struct wlan_objmgr_pdev *pdev; + + sap_err("clear the DFS NOL"); + + pdev = mac->pdev; + if (!pdev) { + sap_err("null pdev"); + return QDF_STATUS_E_FAULT; + } + utils_dfs_clear_nol_channels(pdev); + } else if (conf == eSAP_DFS_NOL_RANDOMIZE) { + sap_err("Randomize the DFS NOL"); + + } else { + sap_err("unsupported type %d", conf); + } + + return QDF_STATUS_SUCCESS; +} +#endif + +void wlansap_populate_del_sta_params(const uint8_t *mac, + uint16_t reason_code, + uint8_t subtype, + struct csr_del_sta_params *params) +{ + if (!mac) + qdf_set_macaddr_broadcast(¶ms->peerMacAddr); + else + qdf_mem_copy(params->peerMacAddr.bytes, mac, + QDF_MAC_ADDR_SIZE); + + if (reason_code == 0) + params->reason_code = REASON_DEAUTH_NETWORK_LEAVING; + else + params->reason_code = reason_code; + + if (subtype == SIR_MAC_MGMT_DEAUTH || subtype == SIR_MAC_MGMT_DISASSOC) + params->subtype = subtype; + else + params->subtype = SIR_MAC_MGMT_DEAUTH; + + sap_debug("Delete STA with RC:%hu subtype:%hhu MAC::" QDF_MAC_ADDR_FMT, + params->reason_code, params->subtype, + QDF_MAC_ADDR_REF(params->peerMacAddr.bytes)); +} + +void sap_undo_acs(struct sap_context *sap_ctx, struct sap_config *sap_cfg) +{ + struct sap_acs_cfg *acs_cfg; + + if (!sap_ctx) + return; + + acs_cfg = &sap_cfg->acs_cfg; + if (!acs_cfg) + return; + + if (acs_cfg->freq_list) { + sap_debug("Clearing ACS cfg ch freq list"); + qdf_mem_free(acs_cfg->freq_list); + acs_cfg->freq_list = NULL; + } + if (acs_cfg->master_freq_list) { + sap_debug("Clearing master ACS cfg chan freq list"); + qdf_mem_free(acs_cfg->master_freq_list); + acs_cfg->master_freq_list = NULL; + } + if (sap_ctx->freq_list) { + sap_debug("Clearing sap context ch freq list"); + qdf_mem_free(sap_ctx->freq_list); + sap_ctx->freq_list = NULL; + } + acs_cfg->ch_list_count = 0; + acs_cfg->master_ch_list_count = 0; + acs_cfg->acs_mode = false; + acs_cfg->master_ch_list_updated = false; + sap_ctx->num_of_channel = 0; + wlansap_dcs_set_vdev_wlan_interference_mitigation(sap_ctx, false); +} + +QDF_STATUS wlansap_acs_chselect(struct sap_context *sap_context, + sap_event_cb acs_event_callback, + struct sap_config *config, + void *pusr_context) +{ + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP pointer"); + + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + sap_context->acs_cfg = &config->acs_cfg; + sap_context->ch_width_orig = config->acs_cfg.ch_width; + if (sap_context->fsm_state != SAP_STARTED) + sap_context->phyMode = config->acs_cfg.hw_mode; + + /* + * Now, configure the scan and ACS channel params + * to issue a scan request. + */ + wlansap_set_scan_acs_channel_params(config, sap_context, + pusr_context); + + /* + * Copy the HDD callback function to report the + * ACS result after scan in SAP context callback function. + */ + sap_context->sap_event_cb = acs_event_callback; + + /* + * Issue the scan request. This scan request is + * issued before the start BSS is done so + * + * 1. No need to pass the second parameter + * as the SAP state machine is not started yet + * and there is no need for any event posting. + * + * 2. Set third parameter to TRUE to indicate the + * channel selection function to register a + * different scan callback function to process + * the results pre start BSS. + */ + qdf_status = sap_channel_sel(sap_context); + + if (QDF_STATUS_E_ABORTED == qdf_status) { + sap_err("DFS not supported in the current operating mode"); + return QDF_STATUS_E_FAILURE; + } else if (QDF_STATUS_E_CANCELED == qdf_status) { + /* + * ERROR is returned when either the SME scan request + * failed or ACS is overridden due to other constrainst + * So send selected channel to HDD + */ + sap_err("Scan Req Failed/ACS Overridden"); + sap_err("Selected channel frequency = %d", + sap_context->chan_freq); + + return sap_signal_hdd_event(sap_context, NULL, + eSAP_ACS_CHANNEL_SELECTED, + (void *) eSAP_STATUS_SUCCESS); + } + + return qdf_status; +} + +/** + * wlan_sap_enable_phy_error_logs() - Enable DFS phy error logs + * @mac_handle: Opaque handle to the global MAC context + * @enable_log: value to set + * + * Since the frequency of DFS phy error is very high, enabling logs for them + * all the times can cause crash and will also create lot of useless logs + * causing difficulties in debugging other issue. This function will be called + * from iwpriv cmd to enable such logs temporarily. + * + * Return: void + */ +void wlan_sap_enable_phy_error_logs(mac_handle_t mac_handle, + uint32_t enable_log) +{ + int error; + + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->sap.enable_dfs_phy_error_logs = !!enable_log; + tgt_dfs_control(mac_ctx->pdev, DFS_SET_DEBUG_LEVEL, &enable_log, + sizeof(uint32_t), NULL, NULL, &error); +} + +#ifdef DFS_PRI_MULTIPLIER +void wlan_sap_set_dfs_pri_multiplier(mac_handle_t mac_handle) +{ + int error; + + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + tgt_dfs_control(mac_ctx->pdev, DFS_SET_PRI_MULTIPILER, + &mac_ctx->mlme_cfg->dfs_cfg.dfs_pri_multiplier, + sizeof(uint32_t), NULL, NULL, &error); +} +#endif + +uint32_t wlansap_get_chan_width(struct sap_context *sap_ctx) +{ + return wlan_sap_get_vht_ch_width(sap_ctx); +} + +enum phy_ch_width +wlansap_get_max_bw_by_phymode(struct sap_context *sap_ctx) +{ + uint32_t max_fw_bw; + enum phy_ch_width ch_width; + + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return CH_WIDTH_20MHZ; + } + + if (sap_ctx->phyMode == eCSR_DOT11_MODE_11ac || + sap_ctx->phyMode == eCSR_DOT11_MODE_11ac_ONLY || + sap_ctx->phyMode == eCSR_DOT11_MODE_11ax || + sap_ctx->phyMode == eCSR_DOT11_MODE_11ax_ONLY || + CSR_IS_DOT11_PHY_MODE_11BE(sap_ctx->phyMode) || + CSR_IS_DOT11_PHY_MODE_11BE_ONLY(sap_ctx->phyMode)) { + max_fw_bw = sme_get_vht_ch_width(); + if (max_fw_bw >= WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ) + ch_width = CH_WIDTH_160MHZ; + else + ch_width = CH_WIDTH_80MHZ; + if (CSR_IS_DOT11_PHY_MODE_11BE(sap_ctx->phyMode) || + CSR_IS_DOT11_PHY_MODE_11BE_ONLY(sap_ctx->phyMode)) + ch_width = + QDF_MAX(wlansap_get_target_eht_phy_ch_width(), + ch_width); + } else if (sap_ctx->phyMode == eCSR_DOT11_MODE_11n || + sap_ctx->phyMode == eCSR_DOT11_MODE_11n_ONLY) { + ch_width = CH_WIDTH_40MHZ; + } else { + /* For legacy 11a mode return 20MHz */ + ch_width = CH_WIDTH_20MHZ; + } + + return ch_width; +} + +QDF_STATUS wlansap_set_invalid_session(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAILURE; + } + + sap_ctx->sessionId = WLAN_UMAC_VDEV_ID_MAX; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_release_vdev_ref(struct sap_context *sap_ctx) +{ + if (!sap_ctx) { + sap_err("Invalid SAP pointer"); + return QDF_STATUS_E_FAILURE; + } + + sap_release_vdev_ref(sap_ctx); + + return QDF_STATUS_SUCCESS; +} + +void wlansap_cleanup_cac_timer(struct sap_context *sap_ctx) +{ + struct mac_context *mac; + + if (!sap_ctx) { + sap_debug("Invalid SAP context"); + return; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return; + } + + if (mac->sap.SapDfsInfo.vdev_id != sap_ctx->vdev_id) { + sap_err("sapdfs, force cleanup vdev mismatch sap vdev id %d mac_ctx vdev id %d", + sap_ctx->vdev_id, mac->sap.SapDfsInfo.vdev_id); + return; + } + + if (mac->sap.SapDfsInfo.is_dfs_cac_timer_running) { + mac->sap.SapDfsInfo.is_dfs_cac_timer_running = 0; + mac->sap.SapDfsInfo.vdev_id = WLAN_INVALID_VDEV_ID; + + if (!sap_ctx->dfs_cac_offload) { + qdf_mc_timer_stop( + &mac->sap.SapDfsInfo.sap_dfs_cac_timer); + qdf_mc_timer_destroy( + &mac->sap.SapDfsInfo.sap_dfs_cac_timer); + sap_debug("sapdfs, force cleanup running dfs cac timer vdev id %d", + sap_ctx->vdev_id); + } + } +} + +#define DH_OUI_TYPE (0x20) +/** + * wlansap_validate_owe_ie() - validate OWE IE + * @ie: IE buffer + * @remaining_ie_len: remaining IE length + * + * Return: validated IE length, negative for failure + */ +static int wlansap_validate_owe_ie(const uint8_t *ie, uint32_t remaining_ie_len) +{ + uint8_t ie_id, ie_len, ie_ext_id = 0; + + if (remaining_ie_len < 2) { + sap_err("IE too short"); + return -EINVAL; + } + + ie_id = ie[0]; + ie_len = ie[1]; + + /* IEs that we are expecting in OWE IEs + * - RSN IE + * - DH IE + */ + switch (ie_id) { + case DOT11F_EID_RSN: + if (ie_len < DOT11F_IE_RSN_MIN_LEN || + ie_len > DOT11F_IE_RSN_MAX_LEN) { + sap_err("Invalid RSN IE len %d", ie_len); + return -EINVAL; + } + ie_len += 2; + break; + case DOT11F_EID_DH_PARAMETER_ELEMENT: + ie_ext_id = ie[2]; + if (ie_ext_id != DH_OUI_TYPE) { + sap_err("Invalid DH IE ID %d", ie_ext_id); + return -EINVAL; + } + if (ie_len < DOT11F_IE_DH_PARAMETER_ELEMENT_MIN_LEN || + ie_len > DOT11F_IE_DH_PARAMETER_ELEMENT_MAX_LEN) { + sap_err("Invalid DH IE len %d", ie_len); + return -EINVAL; + } + ie_len += 2; + break; + default: + sap_err("Invalid IE %d", ie_id); + return -EINVAL; + } + + if (ie_len > remaining_ie_len) { + sap_err("Invalid IE len"); + return -EINVAL; + } + + return ie_len; +} + +/** + * wlansap_validate_owe_ies() - validate OWE IEs + * @ie: IE buffer + * @ie_len: IE length + * + * Return: true if validated + */ +static bool wlansap_validate_owe_ies(const uint8_t *ie, uint32_t ie_len) +{ + const uint8_t *remaining_ie = ie; + uint32_t remaining_ie_len = ie_len; + int validated_len; + bool validated = true; + + while (remaining_ie_len) { + validated_len = wlansap_validate_owe_ie(remaining_ie, + remaining_ie_len); + if (validated_len < 0) { + validated = false; + break; + } + remaining_ie += validated_len; + remaining_ie_len -= validated_len; + } + + return validated; +} + +QDF_STATUS wlansap_update_owe_info(struct sap_context *sap_ctx, + uint8_t *peer, const uint8_t *ie, + uint32_t ie_len, uint16_t owe_status) +{ + struct mac_context *mac; + struct owe_assoc_ind *owe_assoc_ind; + struct assoc_ind *assoc_ind = NULL; + qdf_list_node_t *node = NULL, *next_node = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!wlansap_validate_owe_ies(ie, ie_len)) { + sap_err("Invalid OWE IE"); + return QDF_STATUS_E_FAULT; + } + + if (!sap_ctx) { + sap_err("Invalid SAP context"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&sap_ctx->owe_pending_assoc_ind_list, + &next_node)) { + sap_err("Failed to find assoc ind list"); + return QDF_STATUS_E_FAILURE; + } + + do { + node = next_node; + owe_assoc_ind = qdf_container_of(node, struct owe_assoc_ind, + node); + if (qdf_mem_cmp(peer, + owe_assoc_ind->assoc_ind->peerMacAddr, + QDF_MAC_ADDR_SIZE) == 0) { + status = qdf_list_remove_node( + &sap_ctx->owe_pending_assoc_ind_list, + node); + if (status != QDF_STATUS_SUCCESS) { + sap_err("Failed to remove assoc ind"); + return status; + } + assoc_ind = owe_assoc_ind->assoc_ind; + qdf_mem_free(owe_assoc_ind); + break; + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&sap_ctx->owe_pending_assoc_ind_list, + node, &next_node)); + + if (assoc_ind) { + assoc_ind->owe_ie = ie; + assoc_ind->owe_ie_len = ie_len; + assoc_ind->owe_status = owe_status; + status = sme_update_owe_info(mac, assoc_ind); + qdf_mem_free(assoc_ind); + } + + return status; +} + +QDF_STATUS wlansap_update_ft_info(struct sap_context *sap_ctx, + uint8_t *peer, const uint8_t *ie, + uint32_t ie_len, uint16_t ft_status) +{ + struct mac_context *mac; + struct ft_assoc_ind *ft_assoc_ind; + struct assoc_ind *assoc_ind = NULL; + qdf_list_node_t *node = NULL, *next_node = NULL; + QDF_STATUS status; + + if (!sap_ctx) { + sap_err("Invalid SAP context"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + status = qdf_wait_single_event(&sap_ctx->ft_pending_event, + 500); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sap_err("wait for ft pending event timeout"); + wlansap_ft_cleanup(sap_ctx); + return QDF_STATUS_E_FAULT; + } + + if (QDF_STATUS_SUCCESS != + qdf_list_peek_front(&sap_ctx->ft_pending_assoc_ind_list, + &next_node)) { + sap_err("Failed to find ft assoc ind list"); + return QDF_STATUS_E_FAILURE; + } + + do { + node = next_node; + ft_assoc_ind = qdf_container_of(node, struct ft_assoc_ind, node); + if (qdf_mem_cmp(peer, + ft_assoc_ind->assoc_ind->peerMacAddr, + QDF_MAC_ADDR_SIZE) == 0) { + status = qdf_list_remove_node(&sap_ctx->ft_pending_assoc_ind_list, + node); + if (status != QDF_STATUS_SUCCESS) { + sap_err("Failed to remove ft assoc ind"); + return status; + } + assoc_ind = ft_assoc_ind->assoc_ind; + qdf_mem_free(ft_assoc_ind); + break; + } + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&sap_ctx->ft_pending_assoc_ind_list, + node, &next_node)); + + if (assoc_ind) { + assoc_ind->ft_ie = ie; + assoc_ind->ft_ie_len = ie_len; + assoc_ind->ft_status = ft_status; + status = sme_update_ft_info(mac, assoc_ind); + qdf_mem_free(assoc_ind); + } + return status; +} + +bool wlansap_is_channel_present_in_acs_list(uint32_t freq, + uint32_t *ch_freq_list, + uint8_t ch_count) +{ + uint8_t i; + + for(i = 0; i < ch_count; i++) + if (ch_freq_list[i] == freq) + return true; + + return false; +} + +QDF_STATUS wlansap_filter_ch_based_acs(struct sap_context *sap_ctx, + uint32_t *ch_freq_list, + uint32_t *ch_cnt) +{ + size_t ch_index; + size_t target_ch_cnt = 0; + + if (!sap_ctx || !ch_freq_list || !ch_cnt) { + sap_err("NULL parameters"); + return QDF_STATUS_E_FAULT; + } + + if (!sap_ctx->acs_cfg->acs_mode) { + sap_debug("acs not enabled, no filtering required"); + return QDF_STATUS_SUCCESS; + } else if (!sap_ctx->acs_cfg->master_freq_list || + !sap_ctx->acs_cfg->master_ch_list_count) { + sap_err("Empty acs channel list"); + return QDF_STATUS_E_FAULT; + } + + for (ch_index = 0; ch_index < *ch_cnt; ch_index++) { + if (wlansap_is_channel_present_in_acs_list( + ch_freq_list[ch_index], + sap_ctx->acs_cfg->master_freq_list, + sap_ctx->acs_cfg->master_ch_list_count)) + ch_freq_list[target_ch_cnt++] = ch_freq_list[ch_index]; + } + + *ch_cnt = target_ch_cnt; + + return QDF_STATUS_SUCCESS; +} + +bool wlansap_is_6ghz_included_in_acs_range(struct sap_context *sap_ctx) +{ + uint32_t i; + uint32_t *ch_freq_list; + + if (!sap_ctx || !sap_ctx->acs_cfg || + !sap_ctx->acs_cfg->master_freq_list || + !sap_ctx->acs_cfg->master_ch_list_count) { + sap_err("NULL parameters"); + return false; + } + ch_freq_list = sap_ctx->acs_cfg->master_freq_list; + for (i = 0; i < sap_ctx->acs_cfg->master_ch_list_count; i++) { + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq_list[i])) + return true; + } + return false; +} + +#if defined(FEATURE_WLAN_CH_AVOID) +/** + * wlansap_select_chan_with_best_bandwidth() - Select channel with + * max possible band width + * @sap_ctx: sap context + * @ch_freq_list: candidate channel frequency list + * @ch_cnt: count of channel frequency in list + * @selected_freq: selected channel frequency + * @selected_ch_width: selected channel width + * + * Return: QDF_STATUS_SUCCESS if better channel selected + */ +static QDF_STATUS +wlansap_select_chan_with_best_bandwidth(struct sap_context *sap_ctx, + uint32_t *ch_freq_list, + uint32_t ch_cnt, + uint32_t *selected_freq, + enum phy_ch_width *selected_ch_width) +{ + struct mac_context *mac; + struct ch_params ch_params = {0}; + enum phy_ch_width ch_width; + uint32_t center_freq, bw_val, bw_start, bw_end; + uint16_t i, j; + uint16_t unsafe_chan[NUM_CHANNELS] = {0}; + uint16_t unsafe_chan_cnt = 0; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!selected_ch_width || !selected_freq) + return QDF_STATUS_E_INVAL; + + if (!qdf_ctx) { + sap_err("invalid qdf_ctx"); + return QDF_STATUS_E_INVAL; + } + + if (!sap_ctx) { + sap_err("invalid sap_ctx"); + return QDF_STATUS_E_INVAL; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_INVAL; + } + + if (policy_mgr_mode_specific_connection_count(mac->psoc, + PM_STA_MODE, + NULL) || + policy_mgr_mode_specific_connection_count(mac->psoc, + PM_P2P_CLIENT_MODE, + NULL) || + policy_mgr_mode_specific_connection_count(mac->psoc, + PM_P2P_GO_MODE, + NULL)) { + sap_debug("sta/p2p mode active, skip!"); + return QDF_STATUS_E_INVAL; + } + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(uint16_t) * NUM_CHANNELS); + unsafe_chan_cnt = QDF_MIN(unsafe_chan_cnt, NUM_CHANNELS); + if (!unsafe_chan_cnt) + return QDF_STATUS_E_INVAL; + + ch_width = sap_ctx->ch_width_orig; +next_lower_bw: + for (i = 0; i < ch_cnt; i++) { + if (!WLAN_REG_IS_SAME_BAND_FREQS(sap_ctx->chan_freq, + ch_freq_list[i])) + continue; + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(ch_freq_list[i]) && + !WLAN_REG_IS_6GHZ_PSC_CHAN_FREQ(ch_freq_list[i])) + continue; + qdf_mem_zero(&ch_params, sizeof(ch_params)); + ch_params.ch_width = ch_width; + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + ch_freq_list[i], + 0, &ch_params, + REG_CURRENT_PWR_MODE); + if (!WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq_list[i]) && + wlan_reg_get_5g_bonded_channel_state_for_pwrmode(mac->pdev, + ch_freq_list[i], + &ch_params, + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_ENABLE) + continue; + + bw_val = wlan_reg_get_bw_value(ch_params.ch_width); + if (!ch_params.mhz_freq_seg0) + continue; + if (bw_val < wlan_reg_get_bw_value(ch_width)) + continue; + if (ch_params.mhz_freq_seg1) + center_freq = ch_params.mhz_freq_seg1; + else + center_freq = ch_params.mhz_freq_seg0; + + bw_start = center_freq - bw_val / 2 + 10; + bw_end = center_freq + bw_val / 2 - 10; + for (j = 0; j < unsafe_chan_cnt; j++) + if (unsafe_chan[j] >= bw_start && + unsafe_chan[j] <= bw_end) + break; + + if (j < unsafe_chan_cnt) { + sap_debug("ch_freq %d bw %d bw start %d, bw end %d unsafe %d", + ch_freq_list[i], bw_val, bw_start, bw_end, + unsafe_chan[j]); + continue; + } + sap_debug("ch_freq %d bw %d bw start %d, bw end %d", + ch_freq_list[i], bw_val, bw_start, bw_end); + /* found freq/bw pair which is safe for used as sap channel + * avoidance csa target channel/bandwidth. + */ + *selected_freq = ch_freq_list[i]; + *selected_ch_width = ch_params.ch_width; + sap_debug("selected freq %d bw %d", *selected_freq, + *selected_ch_width); + + return QDF_STATUS_SUCCESS; + } + + ch_width = wlan_reg_get_next_lower_bandwidth(ch_width); + if (!(wlan_reg_get_bw_value(ch_width) < 20 || + ch_width == CH_WIDTH_INVALID)) + goto next_lower_bw; + + return QDF_STATUS_E_INVAL; +} + +/** + * wlansap_get_safe_channel() - Get safe channel from current regulatory + * @sap_ctx: Pointer to SAP context + * @ch_width: selected channel bandwdith + * @pref_band: Preferred channel band for sap + * + * This function is used to get safe channel from current regulatory valid + * channels to restart SAP if failed to get safe channel from PCL. + * + * Return: Chan freq num to restart SAP in case of success. In case of any + * failure, the channel number returned is zero. + */ +static uint32_t +wlansap_get_safe_channel(struct sap_context *sap_ctx, + enum phy_ch_width *ch_width, + enum reg_wifi_band pref_band) +{ + struct mac_context *mac; + uint32_t pcl_freqs[NUM_CHANNELS]; + QDF_STATUS status; + mac_handle_t mac_handle; + uint32_t pcl_len = 0, i; + uint32_t selected_freq; + enum policy_mgr_con_mode mode; + uint32_t first_valid_dfs_5g_freq = 0; + uint32_t first_valid_non_dfs_5g_freq = 0; + uint32_t first_valid_6g_freq = 0; + + if (!sap_ctx) { + sap_err("NULL parameter"); + return INVALID_CHANNEL_ID; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return INVALID_CHANNEL_ID; + } + mac_handle = MAC_HANDLE(mac); + + mode = policy_mgr_qdf_opmode_to_pm_con_mode(mac->psoc, + QDF_SAP_MODE, + sap_ctx->vdev_id); + /* get the channel list for current domain */ + status = policy_mgr_get_valid_chans(mac->psoc, pcl_freqs, &pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Error in getting valid channels"); + return INVALID_CHANNEL_ID; + } + + status = wlansap_filter_ch_based_acs(sap_ctx, pcl_freqs, &pcl_len); + + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("failed to filter ch from acs %d", status); + return INVALID_CHANNEL_ID; + } + + if (pcl_len) { + status = policy_mgr_get_valid_chans_from_range(mac->psoc, + pcl_freqs, + &pcl_len, + mode); + if (QDF_IS_STATUS_ERROR(status) || !pcl_len) { + sap_err("failed to get valid channel: %d len %d", + status, pcl_len); + return INVALID_CHANNEL_ID; + } + + status = + wlansap_select_chan_with_best_bandwidth(sap_ctx, + pcl_freqs, + pcl_len, + &selected_freq, + ch_width); + if (QDF_IS_STATUS_SUCCESS(status)) + return selected_freq; + + for (i = 0; i < pcl_len; i++) { + if (!first_valid_non_dfs_5g_freq && + wlan_reg_is_5ghz_ch_freq(pcl_freqs[i])) { + if (!wlan_reg_is_dfs_in_secondary_list_for_freq( + mac->pdev, + pcl_freqs[i])) { + first_valid_non_dfs_5g_freq = pcl_freqs[i]; + if (pref_band == REG_BAND_5G) + break; + } else if (!first_valid_dfs_5g_freq) { + first_valid_dfs_5g_freq = pcl_freqs[i]; + } + } + if (!first_valid_6g_freq && + wlan_reg_is_6ghz_chan_freq(pcl_freqs[i])) { + first_valid_6g_freq = pcl_freqs[i]; + if (pref_band == REG_BAND_6G) + break; + } + } + + selected_freq = pcl_freqs[0]; + + if (pref_band == REG_BAND_6G) { + if (first_valid_6g_freq) + selected_freq = first_valid_6g_freq; + else if (first_valid_non_dfs_5g_freq) + selected_freq = first_valid_non_dfs_5g_freq; + else if (first_valid_dfs_5g_freq) + selected_freq = first_valid_dfs_5g_freq; + } else if (pref_band == REG_BAND_5G) { + if (first_valid_non_dfs_5g_freq) + selected_freq = first_valid_non_dfs_5g_freq; + else if (first_valid_dfs_5g_freq) + selected_freq = first_valid_dfs_5g_freq; + } + + sap_debug("select %d from valid channel list, pref band = %d", + selected_freq, pref_band); + return selected_freq; + } + + return INVALID_CHANNEL_ID; +} +#else +/** + * wlansap_select_chan_with_best_bandwidth() - Select channel with + * max possible band width + * @sap_ctx: sap context + * @ch_freq_list: candidate channel frequency list + * @ch_cnt: count of channel frequency in list + * @selected_freq: selected channel frequency + * @selected_ch_width: selected channel width + * + * Return: QDF_STATUS_SUCCESS if better channel selected + */ +static inline QDF_STATUS +wlansap_select_chan_with_best_bandwidth(struct sap_context *sap_ctx, + uint32_t *ch_freq_list, + uint32_t ch_cnt, + uint32_t *selected_freq, + enum phy_ch_width *selected_ch_width) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +/** + * wlansap_get_safe_channel() - Get safe channel from current regulatory + * @sap_ctx: Pointer to SAP context + * @ch_width: selected channel width + * @pref_band: Preferred channel band for sap + * + * This function is used to get safe channel from current regulatory valid + * channels to restart SAP if failed to get safe channel from PCL. + * + * Return: Channel number to restart SAP in case of success. In case of any + * failure, the channel number returned is zero. + */ +static uint8_t +wlansap_get_safe_channel(struct sap_context *sap_ctx, + enum phy_ch_width *ch_width, + enum reg_wifi_band pref_band) +{ + return 0; +} +#endif + +uint32_t +wlansap_get_safe_channel_from_pcl_and_acs_range(struct sap_context *sap_ctx, + enum phy_ch_width *ch_width) +{ + struct mac_context *mac; + struct sir_pcl_list pcl = {0}; + uint32_t pcl_freqs[NUM_CHANNELS] = {0}; + uint32_t select_freq; + QDF_STATUS status; + mac_handle_t mac_handle; + uint32_t pcl_len = 0; + enum policy_mgr_con_mode mode; + + if (!sap_ctx) { + sap_err("NULL parameter"); + return INVALID_CHANNEL_ID; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return INVALID_CHANNEL_ID; + } + mac_handle = MAC_HANDLE(mac); + + if (policy_mgr_get_connection_count(mac->psoc) == 1) { + sap_debug("only SAP present return best channel from ACS list"); + return wlansap_get_safe_channel(sap_ctx, ch_width, REG_BAND_6G); + } + + mode = policy_mgr_qdf_opmode_to_pm_con_mode(mac->psoc, QDF_SAP_MODE, + sap_ctx->vdev_id); + + status = + policy_mgr_get_pcl_for_scc_in_same_mode(mac->psoc, mode, + pcl_freqs, &pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), + sap_ctx->sessionId); + + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Get PCL failed"); + return INVALID_CHANNEL_ID; + } + + if (pcl_len) { + status = wlansap_filter_ch_based_acs(sap_ctx, pcl_freqs, + &pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("failed to filter ch from acs %d", status); + return INVALID_CHANNEL_ID; + } + + if (wlansap_select_chan_with_best_bandwidth(sap_ctx, + pcl_freqs, + pcl_len, + &select_freq, + ch_width) == + QDF_STATUS_SUCCESS) + return select_freq; + + if (pcl_len) { + sap_debug("select %d from valid ch freq list", + pcl_freqs[0]); + return pcl_freqs[0]; + } + sap_debug("no safe channel from PCL found in ACS range"); + } else { + sap_debug("pcl length is zero!"); + } + + /* + * In some scenarios, like hw dbs disabled, sap+sap case, if operating + * channel is unsafe channel, the pcl may be empty, instead of return, + * try to choose a safe channel from acs range. + */ + return wlansap_get_safe_channel(sap_ctx, ch_width, REG_BAND_6G); +} + +static uint32_t wlansap_get_2g_first_safe_chan_freq(struct sap_context *sap_ctx) +{ + uint32_t i; + uint32_t freq; + enum channel_state state; + struct regulatory_channel *cur_chan_list; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + uint32_t *acs_freq_list; + uint8_t acs_list_count; + + pdev = sap_ctx->vdev->vdev_objmgr.wlan_pdev; + psoc = pdev->pdev_objmgr.wlan_psoc; + + cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * + sizeof(struct regulatory_channel)); + if (!cur_chan_list) + return TWOG_CHAN_6_IN_MHZ; + + if (wlan_reg_get_current_chan_list(pdev, cur_chan_list) != + QDF_STATUS_SUCCESS) { + freq = TWOG_CHAN_6_IN_MHZ; + goto err; + } + + acs_freq_list = sap_ctx->acs_cfg->master_freq_list; + acs_list_count = sap_ctx->acs_cfg->master_ch_list_count; + for (i = 0; i < NUM_CHANNELS; i++) { + freq = cur_chan_list[i].center_freq; + state = wlan_reg_get_channel_state_for_pwrmode( + pdev, freq, + REG_CURRENT_PWR_MODE); + if (state != CHANNEL_STATE_DISABLE && + state != CHANNEL_STATE_PASSIVE && + state != CHANNEL_STATE_INVALID && + wlan_reg_is_24ghz_ch_freq(freq) && + policy_mgr_is_safe_channel(psoc, freq) && + wlansap_is_channel_present_in_acs_list(freq, + acs_freq_list, + acs_list_count)) { + sap_debug("found a 2g channel: %d", freq); + goto err; + } + } + + freq = TWOG_CHAN_6_IN_MHZ; +err: + qdf_mem_free(cur_chan_list); + return freq; +} + +uint32_t wlansap_get_safe_channel_from_pcl_for_sap(struct sap_context *sap_ctx) +{ + struct wlan_objmgr_pdev *pdev; + struct mac_context *mac; + struct sir_pcl_list pcl = {0}; + uint32_t pcl_freqs[NUM_CHANNELS] = {0}; + QDF_STATUS status; + uint32_t pcl_len = 0; + enum policy_mgr_con_mode mode; + + if (!sap_ctx) { + sap_err("NULL parameter"); + return INVALID_CHANNEL_ID; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return INVALID_CHANNEL_ID; + } + + pdev = sap_ctx->vdev->vdev_objmgr.wlan_pdev; + if (!pdev) { + sap_err("NULL pdev"); + } + + mode = policy_mgr_qdf_opmode_to_pm_con_mode(mac->psoc, QDF_SAP_MODE, + sap_ctx->vdev_id); + + status = policy_mgr_get_pcl_for_vdev_id(mac->psoc, mode, + pcl_freqs, &pcl_len, + pcl.weight_list, + QDF_ARRAY_SIZE(pcl.weight_list), + sap_ctx->sessionId); + + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Get PCL failed"); + return INVALID_CHANNEL_ID; + } + + if (pcl_len) { + status = policy_mgr_filter_passive_ch(pdev, pcl_freqs, + &pcl_len); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("failed to filter passive channels"); + return INVALID_CHANNEL_ID; + } + + if (pcl_len) { + sap_debug("select %d from valid ch freq list", + pcl_freqs[0]); + return pcl_freqs[0]; + } + sap_debug("no active channels found in PCL"); + } else { + sap_debug("pcl length is zero!"); + } + + if (mode == PM_LL_LT_SAP_MODE) + return INVALID_CHANNEL_ID; + + return wlansap_get_2g_first_safe_chan_freq(sap_ctx); +} + +int wlansap_update_sap_chan_list(struct sap_config *sap_config, + qdf_freq_t *freq_list, uint16_t count) +{ + uint32_t *acs_cfg_freq_list; + uint32_t *master_freq_list; + uint32_t i; + bool old_acs_2g_only = true, acs_2g_only_new = true; + + acs_cfg_freq_list = qdf_mem_malloc(count * sizeof(uint32_t)); + if (!acs_cfg_freq_list) + return -ENOMEM; + if (sap_config->acs_cfg.ch_list_count) { + qdf_mem_free(sap_config->acs_cfg.freq_list); + sap_config->acs_cfg.freq_list = NULL; + sap_config->acs_cfg.ch_list_count = 0; + } + sap_config->acs_cfg.freq_list = acs_cfg_freq_list; + + master_freq_list = qdf_mem_malloc(count * sizeof(uint32_t)); + if (!master_freq_list) + return -ENOMEM; + + if (sap_config->acs_cfg.master_ch_list_count) { + for (i = 0; i < sap_config->acs_cfg.master_ch_list_count; i++) + if (sap_config->acs_cfg.master_freq_list && + !WLAN_REG_IS_24GHZ_CH_FREQ( + sap_config->acs_cfg.master_freq_list[i])) { + old_acs_2g_only = false; + break; + } + qdf_mem_free(sap_config->acs_cfg.master_freq_list); + sap_config->acs_cfg.master_freq_list = NULL; + sap_config->acs_cfg.master_ch_list_count = 0; + } + sap_config->acs_cfg.master_freq_list = master_freq_list; + + qdf_mem_copy(sap_config->acs_cfg.freq_list, freq_list, + sizeof(freq_list[0]) * count); + qdf_mem_copy(sap_config->acs_cfg.master_freq_list, freq_list, + sizeof(freq_list[0]) * count); + sap_config->acs_cfg.master_ch_list_count = count; + sap_config->acs_cfg.ch_list_count = count; + for (i = 0; i < sap_config->acs_cfg.master_ch_list_count; i++) + if (sap_config->acs_cfg.master_freq_list && + !WLAN_REG_IS_24GHZ_CH_FREQ( + sap_config->acs_cfg.master_freq_list[i])) { + acs_2g_only_new = false; + break; + } + /* If SAP initially started on world mode, the SAP ACS master channel + * list will only contain 2.4 GHz channels. When country code changed + * from world mode to non world mode, the master_ch_list will + * be updated by this API from userspace and the list will include + * 2.4 GHz + 5/6 GHz normally. If this transition happens, we set + * master_ch_list_updated flag. And later only if the flag is set, + * wlansap_get_chan_band_restrict will be invoked to select new SAP + * channel frequency based on PCL. + */ + sap_config->acs_cfg.master_ch_list_updated = + old_acs_2g_only && !acs_2g_only_new; + sap_dump_acs_channel(&sap_config->acs_cfg); + + return 0; +} + +/** + * wlansap_get_valid_freq() - To get valid freq for sap csa + * @psoc: psoc object + * @sap_ctx: sap context + * @freq: pointer to valid freq + * + * If sap master channel list is updated from 2G only to 2G+5G/6G, + * this API will find new SAP channel frequency likely 5G/6G to have + * better performance for SAP. This happens when SAP started in + * world mode, later country code change to non world mode. + * + * Return: None + */ +static +void wlansap_get_valid_freq(struct wlan_objmgr_psoc *psoc, + struct sap_context *sap_ctx, + qdf_freq_t *freq) +{ + uint8_t i, j; + struct mac_context *mac; + struct sir_pcl_list pcl = {0}; + uint32_t *pcl_freqs; + QDF_STATUS status; + uint32_t pcl_len = 0; + + if (!sap_ctx->acs_cfg || !sap_ctx->acs_cfg->master_ch_list_count) + return; + + if (!sap_ctx->acs_cfg->master_ch_list_updated) + return; + + sap_ctx->acs_cfg->master_ch_list_updated = false; + + pcl_freqs = qdf_mem_malloc(NUM_CHANNELS * sizeof(uint32_t)); + if (!pcl_freqs) + return; + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + goto done; + } + status = policy_mgr_reset_sap_mandatory_channels(psoc); + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("failed to reset mandatory channels"); + goto done; + } + status = policy_mgr_get_pcl_for_vdev_id(mac->psoc, PM_SAP_MODE, + pcl_freqs, &pcl_len, + pcl.weight_list, + NUM_CHANNELS, + sap_ctx->sessionId); + + if (QDF_IS_STATUS_ERROR(status)) { + sap_err("Get PCL failed for session %d", sap_ctx->sessionId); + goto done; + } + for (i = 0; i < pcl_len; i++) { + for (j = 0; j < sap_ctx->acs_cfg->master_ch_list_count; j++) { + /* + * To keep valid freq list order same as pcl weightage + * order pcl list index is compared with all the freq + * provided by set wifi config. + */ + if (sap_ctx->acs_cfg->master_freq_list[j] == + pcl_freqs[i]) { + *freq = pcl_freqs[i]; + goto done; + } + } + } +done: + qdf_mem_free(pcl_freqs); + pcl_freqs = NULL; +} + +qdf_freq_t wlansap_get_chan_band_restrict(struct sap_context *sap_ctx, + enum sap_csa_reason_code *csa_reason) +{ + uint32_t restart_freq; + uint16_t intf_ch_freq; + uint32_t phy_mode; + struct mac_context *mac; + uint8_t cc_mode; + uint8_t vdev_id; + enum reg_wifi_band sap_band; + enum band_info band; + bool sta_sap_scc_on_indoor_channel; + qdf_freq_t freq = 0; + struct ch_params ch_params = {0}; + + if (!sap_ctx) { + sap_err("sap_ctx NULL parameter"); + return 0; + } + + if (!csa_reason) { + sap_err("csa_reason is NULL"); + return 0; + } + + if (cds_is_driver_recovering()) + return 0; + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) + return 0; + + if (ucfg_reg_get_band(mac->pdev, &band) != QDF_STATUS_SUCCESS) { + sap_err("Failed to get current band config"); + return 0; + } + sta_sap_scc_on_indoor_channel = + policy_mgr_get_sta_sap_scc_allowed_on_indoor_chnl(mac->psoc); + sap_band = wlan_reg_freq_to_band(sap_ctx->chan_freq); + + sap_debug("SAP/Go current band: %d, pdev band capability: %d, cur freq %d (is valid %d), prev freq %d (is valid %d)", + sap_band, band, sap_ctx->chan_freq, + wlan_reg_is_enable_in_secondary_list_for_freq(mac->pdev, + sap_ctx->chan_freq), + sap_ctx->chan_freq_before_switch_band, + wlan_reg_is_enable_in_secondary_list_for_freq(mac->pdev, + sap_ctx->chan_freq_before_switch_band)); + + if (sap_band == REG_BAND_5G && band == BIT(REG_BAND_2G)) { + sap_ctx->chan_freq_before_switch_band = sap_ctx->chan_freq; + sap_ctx->chan_width_before_switch_band = + sap_ctx->ch_params.ch_width; + sap_debug("Save chan info before switch: %d, width: %d", + sap_ctx->chan_freq, sap_ctx->ch_params.ch_width); + restart_freq = wlansap_get_2g_first_safe_chan_freq(sap_ctx); + if (restart_freq == 0) { + sap_debug("use default chan 6"); + restart_freq = TWOG_CHAN_6_IN_MHZ; + } + *csa_reason = CSA_REASON_BAND_RESTRICTED; + } else if (sap_band == REG_BAND_2G && (band & BIT(REG_BAND_5G))) { + if (sap_ctx->chan_freq_before_switch_band) { + if (!wlan_reg_is_disable_in_secondary_list_for_freq( + mac->pdev, + sap_ctx->chan_freq_before_switch_band)) { + restart_freq = + sap_ctx->chan_freq_before_switch_band; + sap_debug("Restore chan freq: %d", + restart_freq); + *csa_reason = CSA_REASON_BAND_RESTRICTED; + } else { + enum reg_wifi_band pref_band; + + pref_band = + wlan_reg_freq_to_band( + sap_ctx->chan_freq_before_switch_band); + restart_freq = + policy_mgr_get_alternate_channel_for_sap( + mac->psoc, + sap_ctx->sessionId, + sap_ctx->chan_freq, + pref_band); + if (restart_freq) { + sap_debug("restart SAP on freq %d", + restart_freq); + *csa_reason = + CSA_REASON_BAND_RESTRICTED; + } else { + sap_debug("Did not get valid freq for band %d remain on same channel", + pref_band); + return 0; + } + } + } else { + wlansap_get_valid_freq(mac->psoc, sap_ctx, &freq); + if (!freq) + return 0; + + restart_freq = freq; + sap_debug("restart SAP on freq %d", + restart_freq); + *csa_reason = CSA_REASON_BAND_RESTRICTED; + } + } else if (wlan_reg_is_disable_in_secondary_list_for_freq( + mac->pdev, + sap_ctx->chan_freq) && + !utils_dfs_is_freq_in_nol(mac->pdev, sap_ctx->chan_freq)) { + sap_debug("channel is disabled"); + *csa_reason = CSA_REASON_CHAN_DISABLED; + return wlansap_get_safe_channel_from_pcl_and_acs_range(sap_ctx, + NULL); + } else if (wlan_reg_is_passive_for_freq(mac->pdev, + sap_ctx->chan_freq)) { + sap_ctx->chan_freq_before_switch_band = sap_ctx->chan_freq; + sap_ctx->chan_width_before_switch_band = + sap_ctx->ch_params.ch_width; + sap_debug("Save chan info before switch: %d, width: %d", + sap_ctx->chan_freq, sap_ctx->ch_params.ch_width); + sap_debug("channel is passive"); + *csa_reason = CSA_REASON_CHAN_PASSIVE; + return wlansap_get_safe_channel_from_pcl_for_sap(sap_ctx); + } else if (!policy_mgr_is_sap_freq_allowed(mac->psoc, + wlan_vdev_mlme_get_opmode(sap_ctx->vdev), + sap_ctx->chan_freq)) { + sap_debug("channel is unsafe"); + *csa_reason = CSA_REASON_UNSAFE_CHANNEL; + return wlansap_get_safe_channel_from_pcl_and_acs_range(sap_ctx, + NULL); + } else if (sap_band == REG_BAND_6G && + wlan_reg_get_keep_6ghz_sta_cli_connection(mac->pdev)) { + ch_params.ch_width = sap_ctx->ch_params.ch_width; + wlan_reg_set_channel_params_for_pwrmode(mac->pdev, + sap_ctx->chan_freq, + 0, &ch_params, + REG_CURRENT_PWR_MODE); + if (sap_ctx->ch_params.ch_width != ch_params.ch_width) { + sap_debug("Bonded 6GHz channels are disabled"); + *csa_reason = CSA_REASON_BAND_RESTRICTED; + return wlansap_get_safe_channel_from_pcl_and_acs_range( + sap_ctx, NULL); + } else { + sap_debug("No need switch SAP/Go channel"); + return sap_ctx->chan_freq; + } + } else { + sap_debug("No need switch SAP/Go channel"); + return sap_ctx->chan_freq; + } + cc_mode = sap_ctx->cc_switch_mode; + phy_mode = sap_ctx->phyMode; + vdev_id = wlan_vdev_get_id(sap_ctx->vdev); + intf_ch_freq = sme_check_concurrent_channel_overlap( + MAC_HANDLE(mac), + restart_freq, + phy_mode, + cc_mode, vdev_id); + if (intf_ch_freq) + restart_freq = intf_ch_freq; + if (restart_freq == sap_ctx->chan_freq) + restart_freq = 0; + + if (restart_freq) + sap_debug("vdev: %d, CSA target freq: %d", vdev_id, + restart_freq); + + return restart_freq; +} + +static inline bool +wlansap_ch_in_avoid_ranges(uint32_t ch_freq, + struct pld_ch_avoid_ind_type *ch_avoid_ranges) +{ + uint32_t i; + + for (i = 0; i < ch_avoid_ranges->ch_avoid_range_cnt; i++) { + if (ch_freq >= + ch_avoid_ranges->avoid_freq_range[i].start_freq && + ch_freq <= + ch_avoid_ranges->avoid_freq_range[i].end_freq) + return true; + } + + return false; +} + +bool wlansap_filter_vendor_unsafe_ch_freq( + struct sap_context *sap_context, struct sap_config *sap_config) +{ + struct pld_ch_avoid_ind_type ch_avoid_ranges; + uint32_t i, j; + int ret; + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + struct mac_context *mac; + uint32_t count; + + if (!qdf_ctx) + return false; + mac = sap_get_mac_context(); + if (!mac) + return false; + + count = policy_mgr_get_sap_mode_count(mac->psoc, NULL); + + if (count != policy_mgr_get_connection_count(mac->psoc)) + return false; + + ch_avoid_ranges.ch_avoid_range_cnt = 0; + ret = pld_get_wlan_unsafe_channel_sap(qdf_ctx->dev, &ch_avoid_ranges); + if (ret) { + sap_debug("failed to get vendor unsafe ch range, ret %d", ret); + return false; + } + if (!ch_avoid_ranges.ch_avoid_range_cnt) + return false; + for (i = 0; i < ch_avoid_ranges.ch_avoid_range_cnt; i++) { + sap_debug("vendor unsafe range[%d] %d %d", i, + ch_avoid_ranges.avoid_freq_range[i].start_freq, + ch_avoid_ranges.avoid_freq_range[i].end_freq); + } + for (i = 0, j = 0; i < sap_config->acs_cfg.ch_list_count; i++) { + if (!wlansap_ch_in_avoid_ranges( + sap_config->acs_cfg.freq_list[i], + &ch_avoid_ranges)) + sap_config->acs_cfg.freq_list[j++] = + sap_config->acs_cfg.freq_list[i]; + } + sap_config->acs_cfg.ch_list_count = j; + + return true; +} + +#ifdef DCS_INTERFERENCE_DETECTION +QDF_STATUS wlansap_dcs_set_vdev_wlan_interference_mitigation( + struct sap_context *sap_context, + bool wlan_interference_mitigation_enable) +{ + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + mac->sap.dcs_info. + wlan_interference_mitigation_enable[sap_context->sessionId] = + wlan_interference_mitigation_enable; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlansap_dcs_set_wlan_interference_mitigation_on_band( + struct sap_context *sap_context, + struct sap_config *sap_cfg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool wlan_interference_mitigation_enable = false; + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sap_cfg->acs_cfg.pri_ch_freq)) + wlan_interference_mitigation_enable = true; + + status = wlansap_dcs_set_vdev_wlan_interference_mitigation( + sap_context, + wlan_interference_mitigation_enable); + return status; +} + +QDF_STATUS wlansap_dcs_set_vdev_starting(struct sap_context *sap_context, + bool vdev_starting) +{ + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return QDF_STATUS_E_FAULT; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAULT; + } + + mac->sap.dcs_info.is_vdev_starting[sap_context->sessionId] = + vdev_starting; + + return QDF_STATUS_SUCCESS; +} + +bool wlansap_dcs_is_wlan_interference_mitigation_enabled( + struct sap_context *sap_context) +{ + struct mac_context *mac; + + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return false; + } + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return false; + } + + return mac->sap.dcs_info. + wlan_interference_mitigation_enable[sap_context->sessionId]; +} + +qdf_freq_t wlansap_dcs_get_freq(struct sap_context *sap_context) +{ + if (!sap_context) { + sap_err("Invalid SAP context pointer"); + return false; + } + + return sap_context->dcs_ch_freq; +} + +void wlansap_dump_acs_ch_freq(struct sap_context *sap_context) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + if (sap_context->fsm_state == SAP_STARTED) + sap_info("ACS dump DCS freq=%d", sap_context->dcs_ch_freq); + else + sap_info("ACS dump ch_freq=%d", sap_context->chan_freq); +} + +void wlansap_set_acs_ch_freq(struct sap_context *sap_context, + qdf_freq_t ch_freq) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + if (sap_context->fsm_state == SAP_STARTED) { + sap_context->dcs_ch_freq = ch_freq; + sap_debug("ACS configuring dcs_ch_freq=%d", + sap_context->dcs_ch_freq); + } else { + sap_context->chan_freq = ch_freq; + sap_debug("ACS configuring ch_freq=%d", + sap_context->chan_freq); + } +} +#else +void wlansap_dump_acs_ch_freq(struct sap_context *sap_context) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + sap_info("ACS dump ch_freq=%d", sap_context->chan_freq); +} + +void wlansap_set_acs_ch_freq(struct sap_context *sap_context, + qdf_freq_t ch_freq) +{ + if (!sap_context) { + sap_err("Invalid sap_debug"); + return; + } + + sap_context->chan_freq = ch_freq; + sap_debug("ACS configuring ch_freq=%d", sap_context->chan_freq); +} +#endif + +#ifdef WLAN_FEATURE_11BE +bool sap_phymode_is_eht(eCsrPhyMode phymode) +{ + return CSR_IS_DOT11_PHY_MODE_11BE(phymode) || + CSR_IS_DOT11_PHY_MODE_11BE_ONLY(phymode); +} + +bool sap_acs_is_puncture_applicable(struct sap_acs_cfg *acs_cfg) +{ + bool is_eht_bw_80 = false; + + if (!acs_cfg) { + sap_err("Invalid parameters"); + return is_eht_bw_80; + } + + switch (acs_cfg->ch_width) { + case CH_WIDTH_80MHZ: + case CH_WIDTH_80P80MHZ: + case CH_WIDTH_160MHZ: + case CH_WIDTH_320MHZ: + is_eht_bw_80 = acs_cfg->is_eht_enabled; + break; + default: + break; + } + + return is_eht_bw_80; +} + +void sap_acs_set_puncture_support(struct sap_context *sap_ctx, + struct ch_params *ch_params) +{ + if (!sap_ctx || !ch_params) { + sap_err("Invalid parameters"); + return; + } + + if (sap_acs_is_puncture_applicable(sap_ctx->acs_cfg)) + ch_params->is_create_punc_bitmap = true; +} +#endif + +void wlansap_update_ll_lt_sap_acs_result(struct sap_context *sap_ctx, + qdf_freq_t last_acs_freq) +{ + struct mac_context *mac; + + mac = sap_get_mac_context(); + if (!mac) { + sap_err("Invalid MAC context"); + return; + } + + if (!sap_ctx) { + sap_err("Invalid sap context"); + return; + } + + wlansap_set_acs_ch_freq(sap_ctx, last_acs_freq); + sap_ctx->acs_cfg->pri_ch_freq = last_acs_freq; + sap_ctx->acs_cfg->ht_sec_ch_freq = 0; +} + +QDF_STATUS wlansap_sort_channel_list(uint8_t vdev_id, qdf_list_t *list, + struct sap_sel_ch_info *ch_info) +{ + struct mac_context *mac_ctx; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return QDF_STATUS_E_FAILURE; + } + + sap_sort_channel_list(mac_ctx, vdev_id, list, + ch_info, NULL, NULL); + + return QDF_STATUS_SUCCESS; +} + +void wlansap_free_chan_info(struct sap_sel_ch_info *ch_param) +{ + sap_chan_sel_exit(ch_param); +} + +void wlansap_get_user_config_acs_ch_list(uint8_t vdev_id, + struct scan_filter *filter) +{ + struct mac_context *mac_ctx; + struct sap_context *sap_ctx; + uint8_t ch_count = 0; + + mac_ctx = sap_get_mac_context(); + if (!mac_ctx) { + sap_err("Invalid MAC context"); + return; + } + + if (vdev_id >= SAP_MAX_NUM_SESSION) + return; + + sap_ctx = mac_ctx->sap.sapCtxList[vdev_id].sap_context; + + if (!sap_ctx) { + sap_err("vdev %d sap_ctx is NULL", vdev_id); + return; + } + + ch_count = sap_ctx->acs_cfg->master_ch_list_count; + + if (!ch_count || ch_count > NUM_CHANNELS) + return; + + filter->num_of_channels = ch_count; + qdf_mem_copy(filter->chan_freq_list, sap_ctx->acs_cfg->master_freq_list, + filter->num_of_channels * + sizeof(filter->chan_freq_list[0])); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_api.h new file mode 100644 index 0000000000..8bda50ee01 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_api.h @@ -0,0 +1,993 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * \file csr_api.h + * + * Exports and types for the Common Scan and Roaming Module interfaces. + */ + +#ifndef CSRAPI_H__ +#define CSRAPI_H__ + +#include "sir_api.h" +#include "sir_mac_prot_def.h" +#include "csr_link_list.h" +#include "wlan_scan_public_structs.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_main.h" + +#define CSR_INVALID_SCANRESULT_HANDLE (NULL) + +/* Length to print MAC 12 char + 5 ":" + 2 space + mld string */ +#define MAC_ADDR_DUMP_LEN 26 + +enum csr_akm_type { + /* never used */ + eCSR_AUTH_TYPE_NONE, + /* MAC layer authentication types */ + eCSR_AUTH_TYPE_OPEN_SYSTEM, + eCSR_AUTH_TYPE_SHARED_KEY, + eCSR_AUTH_TYPE_SAE, + eCSR_AUTH_TYPE_AUTOSWITCH, + + /* Upper layer authentication types */ + eCSR_AUTH_TYPE_WPA, + eCSR_AUTH_TYPE_WPA_PSK, + eCSR_AUTH_TYPE_WPA_NONE, + + eCSR_AUTH_TYPE_RSN, + eCSR_AUTH_TYPE_RSN_PSK, + eCSR_AUTH_TYPE_FT_RSN, + eCSR_AUTH_TYPE_FT_RSN_PSK, +#ifdef FEATURE_WLAN_WAPI + eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE, + eCSR_AUTH_TYPE_WAPI_WAI_PSK, +#endif /* FEATURE_WLAN_WAPI */ + eCSR_AUTH_TYPE_CCKM_WPA, + eCSR_AUTH_TYPE_CCKM_RSN, + eCSR_AUTH_TYPE_RSN_PSK_SHA256, + eCSR_AUTH_TYPE_RSN_8021X_SHA256, + eCSR_AUTH_TYPE_FILS_SHA256, + eCSR_AUTH_TYPE_FILS_SHA384, + eCSR_AUTH_TYPE_FT_FILS_SHA256, + eCSR_AUTH_TYPE_FT_FILS_SHA384, + eCSR_AUTH_TYPE_DPP_RSN, + eCSR_AUTH_TYPE_OWE, + eCSR_AUTH_TYPE_SUITEB_EAP_SHA256, + eCSR_AUTH_TYPE_SUITEB_EAP_SHA384, + eCSR_AUTH_TYPE_OSEN, + eCSR_AUTH_TYPE_FT_SAE, + eCSR_AUTH_TYPE_FT_SUITEB_EAP_SHA384, + eCSR_AUTH_TYPE_SAE_EXT_KEY, + eCSR_AUTH_TYPE_FT_SAE_EXT_KEY, + eCSR_NUM_OF_SUPPORT_AUTH_TYPE, + eCSR_AUTH_TYPE_FAILED = 0xff, + eCSR_AUTH_TYPE_UNKNOWN = eCSR_AUTH_TYPE_FAILED, + +}; + +typedef enum { + eCSR_ENCRYPT_TYPE_NONE, + eCSR_ENCRYPT_TYPE_WEP40_STATICKEY, + eCSR_ENCRYPT_TYPE_WEP104_STATICKEY, + eCSR_ENCRYPT_TYPE_WEP40, + eCSR_ENCRYPT_TYPE_WEP104, + eCSR_ENCRYPT_TYPE_TKIP, + eCSR_ENCRYPT_TYPE_AES,/* CCMP */ +#ifdef FEATURE_WLAN_WAPI + /* WAPI */ + eCSR_ENCRYPT_TYPE_WPI, +#endif /* FEATURE_WLAN_WAPI */ + eCSR_ENCRYPT_TYPE_KRK, + eCSR_ENCRYPT_TYPE_BTK, + eCSR_ENCRYPT_TYPE_AES_CMAC, + eCSR_ENCRYPT_TYPE_AES_GMAC_128, + eCSR_ENCRYPT_TYPE_AES_GMAC_256, + eCSR_ENCRYPT_TYPE_AES_GCMP, + eCSR_ENCRYPT_TYPE_AES_GCMP_256, + eCSR_ENCRYPT_TYPE_ANY, + eCSR_NUM_OF_ENCRYPT_TYPE = eCSR_ENCRYPT_TYPE_ANY, + + eCSR_ENCRYPT_TYPE_FAILED = 0xff, + eCSR_ENCRYPT_TYPE_UNKNOWN = eCSR_ENCRYPT_TYPE_FAILED, + +} eCsrEncryptionType; + +typedef enum { + /* 11a/b/g only, no HT, no proprietary */ + eCSR_DOT11_MODE_abg = 0x0001, + eCSR_DOT11_MODE_11a = 0x0002, + eCSR_DOT11_MODE_11b = 0x0004, + eCSR_DOT11_MODE_11g = 0x0008, + eCSR_DOT11_MODE_11n = 0x0010, + eCSR_DOT11_MODE_11g_ONLY = 0x0020, + eCSR_DOT11_MODE_11n_ONLY = 0x0040, + eCSR_DOT11_MODE_11b_ONLY = 0x0080, + eCSR_DOT11_MODE_11ac = 0x0100, + eCSR_DOT11_MODE_11ac_ONLY = 0x0200, + /* + * This is for WIFI test. It is same as eWNIAPI_MAC_PROTOCOL_ALL + * It is for CSR internal use + */ + eCSR_DOT11_MODE_AUTO = 0x0400, + eCSR_DOT11_MODE_11ax = 0x0800, + eCSR_DOT11_MODE_11ax_ONLY = 0x1000, + eCSR_DOT11_MODE_11be = 0x2000, + eCSR_DOT11_MODE_11be_ONLY = 0x4000, + + /* specify the number of maximum bits for phyMode */ + eCSR_NUM_PHY_MODE = 18, +} eCsrPhyMode; + +#ifdef WLAN_FEATURE_11BE +#define CSR_IS_DOT11_PHY_MODE_11BE(dot11mode) \ + ((dot11mode) == eCSR_DOT11_MODE_11be) +#define CSR_IS_DOT11_PHY_MODE_11BE_ONLY(dot11mode) \ + ((dot11mode) == eCSR_DOT11_MODE_11be_ONLY) +#else +#define CSR_IS_DOT11_PHY_MODE_11BE(dot11mode) 0 +#define CSR_IS_DOT11_PHY_MODE_11BE_ONLY(dot11mode) 0 +#endif + +/** + * enum eCsrRoamBssType - BSS type in CSR operations + * @eCSR_BSS_TYPE_INFRASTRUCTURE: Infrastructure station + * @eCSR_BSS_TYPE_INFRA_AP: SoftAP + * @eCSR_BSS_TYPE_NDI: NAN datapath interface + * @eCSR_BSS_TYPE_ANY: any BSS type + */ +typedef enum { + eCSR_BSS_TYPE_INFRASTRUCTURE, + eCSR_BSS_TYPE_INFRA_AP, + eCSR_BSS_TYPE_NDI, + eCSR_BSS_TYPE_ANY, +} eCsrRoamBssType; + +typedef enum { + eCSR_SCAN_SUCCESS, + eCSR_SCAN_FAILURE, + eCSR_SCAN_ABORT, + eCSR_SCAN_FOUND_PEER, +} eCsrScanStatus; + +typedef enum { + eCSR_BW_20MHz_VAL = 20, + eCSR_BW_40MHz_VAL = 40, + eCSR_BW_80MHz_VAL = 80, + eCSR_BW_160MHz_VAL = 160 +} eCSR_BW_Val; + +typedef enum { + eCSR_INI_SINGLE_CHANNEL_CENTERED = 0, + eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY = 1, + eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY = 3, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED = 4, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED = 5, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED = 6, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW = 7, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW = 8, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH = 9, + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH = 10, + eCSR_INI_CHANNEL_BONDING_STATE_MAX = 11 +} eIniChanBondState; + +typedef struct tagCsrChannelInfo { + uint8_t numOfChannels; + uint32_t *freq_list; +} tCsrChannelInfo, *tpCsrChannelInfo; + +typedef enum { + eHIDDEN_SSID_NOT_IN_USE, + eHIDDEN_SSID_ZERO_LEN, + eHIDDEN_SSID_ZERO_CONTENTS +} tHiddenssId; + +typedef struct tagCsrSSIDInfo { + tSirMacSSid SSID; + tHiddenssId ssidHidden; +} tCsrSSIDInfo; + +typedef struct tagCsrSSIDs { + uint32_t numOfSSIDs; + tCsrSSIDInfo *SSIDList; /* To be allocated for array of SSIDs */ +} tCsrSSIDs; + +typedef struct tagCsrBSSIDs { + uint32_t numOfBSSIDs; + struct qdf_mac_addr *bssid; +} tCsrBSSIDs; + +typedef struct tagCsrScanResultInfo { + /* + * Carry the IEs for the current BSSDescription. + * A pointer to tDot11fBeaconIEs. Maybe NULL for start BSS. + */ + void *pvIes; + tAniSSID ssId; + unsigned long timer; /* timer is variable for hidden SSID timer */ + /* + * This member must be the last in the structure because the + * end of struct bss_description is an + * array with nonknown size at this time */ + struct bss_description BssDescriptor; +} tCsrScanResultInfo; + +typedef struct tagCsrAuthList { + uint32_t numEntries; + enum csr_akm_type authType[eCSR_NUM_OF_SUPPORT_AUTH_TYPE]; +} tCsrAuthList, *tpCsrAuthList; + +typedef struct sCsrChannel_ { + uint8_t numChannels; + uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; +} sCsrChannel; + +typedef struct sCsrChnPower_ { + uint32_t first_chan_freq; + uint8_t numChannels; + uint8_t maxtxPower; +} sCsrChnPower; + +typedef struct tagCsr11dinfo { + sCsrChannel Channels; + /* max power channel list */ + sCsrChnPower ChnPower[CFG_VALID_CHANNEL_LIST_LEN]; +} tCsr11dinfo; + +typedef enum { + /* CSR is done lostlink roaming and still cannot reconnect */ + eCSR_ROAM_LOSTLINK = 12, + /* + * TKIP MIC error detected, callback gets a pointer + * to struct mic_failure_ind + */ + eCSR_ROAM_MIC_ERROR_IND = 14, + eCSR_ROAM_SET_KEY_COMPLETE = 17, + /* BSS in SoftAP mode status indication */ + eCSR_ROAM_INFRA_IND = 18, + eCSR_ROAM_WPS_PBC_PROBE_REQ_IND = 19, + /* Disaconnect all the clients */ + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS = 31, + /* Stopbss triggered from SME due to different */ + eCSR_ROAM_SEND_P2P_STOP_BSS = 32, + /* beacon interval */ + eCSR_ROAM_UNPROT_MGMT_FRAME_IND = 33, + +#ifdef FEATURE_WLAN_ESE + eCSR_ROAM_TSM_IE_IND = 34, + eCSR_ROAM_ESE_ADJ_AP_REPORT_IND = 36, + eCSR_ROAM_ESE_BCN_REPORT_IND = 37, +#endif /* FEATURE_WLAN_ESE */ + + /* Radar indication from lower layers */ + eCSR_ROAM_DFS_RADAR_IND = 38, + eCSR_ROAM_SET_CHANNEL_RSP = 39, + + /* Channel sw update notification */ + eCSR_ROAM_DFS_CHAN_SW_NOTIFY = 40, + eCSR_ROAM_EXT_CHG_CHNL_IND = 41, + eCSR_ROAM_STA_CHANNEL_SWITCH = 42, + eCSR_ROAM_NDP_STATUS_UPDATE = 43, + eCSR_ROAM_CHANNEL_COMPLETE_IND = 47, + eCSR_ROAM_CAC_COMPLETE_IND = 48, + eCSR_ROAM_SAE_COMPUTE = 49, + eCSR_ROAM_CHANNEL_INFO_EVENT_IND = 50, +} eRoamCmdStatus; + +/* comment inside indicates what roaming callback gets */ +typedef enum { + eCSR_ROAM_RESULT_NONE, + eCSR_ROAM_RESULT_SUCCESS = eCSR_ROAM_RESULT_NONE, + /* + * If roamStatus is eCSR_ROAM_ASSOCIATION_COMPLETION, + * struct csr_roam_info's bss_desc may pass back + */ + eCSR_ROAM_RESULT_FAILURE, + /* Pass back pointer to struct csr_roam_info */ + eCSR_ROAM_RESULT_ASSOCIATED, + eCSR_ROAM_RESULT_NOT_ASSOCIATED, + eCSR_ROAM_RESULT_MIC_FAILURE, + eCSR_ROAM_RESULT_FORCED, + eCSR_ROAM_RESULT_DISASSOC_IND, + eCSR_ROAM_RESULT_DEAUTH_IND, + eCSR_ROAM_RESULT_CAP_CHANGED, + eCSR_ROAM_RESULT_LOSTLINK, + eCSR_ROAM_RESULT_MIC_ERROR_UNICAST, + eCSR_ROAM_RESULT_MIC_ERROR_GROUP, + eCSR_ROAM_RESULT_AUTHENTICATED, + eCSR_ROAM_RESULT_NEW_RSN_BSS, +#ifdef FEATURE_WLAN_WAPI + eCSR_ROAM_RESULT_NEW_WAPI_BSS, +#endif /* FEATURE_WLAN_WAPI */ + /* INFRA started successfully */ + eCSR_ROAM_RESULT_INFRA_STARTED, + /* INFRA start failed */ + eCSR_ROAM_RESULT_INFRA_START_FAILED, + /* INFRA stopped */ + eCSR_ROAM_RESULT_INFRA_STOPPED, + /* A station joining INFRA AP */ + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND, + /* A station joined INFRA AP */ + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF, + /* INFRA disassociated */ + eCSR_ROAM_RESULT_INFRA_DISASSOCIATED, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_SEND_ACTION_FAIL, + /* peer rejected assoc because max assoc limit reached */ + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED, + /* Assoc rejected due to concurrent session running on a diff channel */ + eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL, + /* TDLS events */ + eCSR_ROAM_RESULT_ADD_TDLS_PEER, + eCSR_ROAM_RESULT_UPDATE_TDLS_PEER, + eCSR_ROAM_RESULT_DELETE_TDLS_PEER, + eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND, + eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND, + eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP, + eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER, + eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN, + eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED, + eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION, + eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS, + eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE, + eCSR_ROAM_RESULT_CSA_RESTART_RSP, + eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS, + eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND, + + eCSR_ROAM_RESULT_NDI_CREATE_RSP, + eCSR_ROAM_RESULT_NDI_DELETE_RSP, + eCSR_ROAM_RESULT_NDP_INITIATOR_RSP, + eCSR_ROAM_RESULT_NDP_NEW_PEER_IND, + eCSR_ROAM_RESULT_NDP_CONFIRM_IND, + eCSR_ROAM_RESULT_NDP_INDICATION, + eCSR_ROAM_RESULT_NDP_SCHED_UPDATE_RSP, + eCSR_ROAM_RESULT_NDP_RESPONDER_RSP, + eCSR_ROAM_RESULT_NDP_END_RSP, + eCSR_ROAM_RESULT_NDP_PEER_DEPARTED_IND, + eCSR_ROAM_RESULT_NDP_END_IND, + eCSR_ROAM_RESULT_CAC_END_IND, + /* If Scan for SSID failed to found proper BSS */ + eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE, + eCSR_ROAM_RESULT_INVOKE_FAILED, +} eCsrRoamResult; + +typedef enum { + /* Not associated in Infra or participating in an Ad-hoc */ + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED, + /* Participating in WDS network in AP/STA mode but not connected yet */ + eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED, + /* Participating in a WDS network and connected peer to peer */ + eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED, + /* Participating in a Infra network in AP not yet in connected state */ + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED, + /* Participating in a Infra network and connected to a peer */ + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED, + /* NAN Data interface not started */ + eCSR_CONNECT_STATE_TYPE_NDI_NOT_STARTED, + /* NAN Data interface started */ + eCSR_CONNECT_STATE_TYPE_NDI_STARTED, +} eCsrConnectState; + +typedef enum { + eCSR_OPERATING_CHANNEL_ALL = 0, + eCSR_OPERATING_CHANNEL_AUTO = eCSR_OPERATING_CHANNEL_ALL, + eCSR_OPERATING_CHANNEL_ANY = eCSR_OPERATING_CHANNEL_ALL, +} eOperationChannel; + +typedef enum { + /* + * Roaming because HDD requested for reassoc by changing one of the + * fields in tCsrRoamModifyProfileFields. OR Roaming because SME + * requested for reassoc by changing one of the fields in + * tCsrRoamModifyProfileFields. + */ + eCsrRoamReasonStaCapabilityChanged, + /* + * Roaming because SME requested for reassoc to a different AP, + * as part of inter AP handoff. + */ + eCsrRoamReasonBetterAP, + /* + * Roaming because SME requested it as the link is lost - placeholder, + * will clean it up once handoff code gets in + */ + eCsrRoamReasonSmeIssuedForLostLink, + +} eCsrRoamReasonCodes; + +/* + * Following fields might need modification dynamically once STA is up + * & running & this'd trigger reassoc. + */ +typedef struct tagCsrRoamModifyProfileFields { + /* + * during connect this specifies ACs U-APSD is to be setup + * for (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored). + * During assoc response this COULD carry confirmation of what + * ACs U-APSD got setup for. Later if an APP looking for APSD, + * SME-QoS might need to modify this field + */ + uint8_t uapsd_mask; +} tCsrRoamModifyProfileFields; + +struct csr_roam_profile { + tCsrSSIDs SSIDs; + tCsrBSSIDs BSSIDs; + /* this is bit mask of all the needed phy mode defined in eCsrPhyMode */ + uint32_t phyMode; + eCsrRoamBssType BSSType; + tCsrChannelInfo ChannelInfo; + uint32_t op_freq; + struct ch_params ch_params; + /* If this is 0, SME will fill in for caller. */ + uint16_t beaconInterval; + /* + * during connect this specifies ACs U-APSD is to be setup + * for (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored). + * During assoc resp this'd carry cnf of what ACs U-APSD got setup for + */ + uint8_t uapsd_mask; + uint32_t nRSNReqIELength; /* The byte count in the pRSNReqIE */ + uint8_t *pRSNReqIE; /* If not null,it's IE byte stream for RSN */ + uint8_t privacy; + tAniAuthType csr80211AuthType; + uint32_t dtimPeriod; + bool chan_switch_hostapd_rate_enabled; + uint16_t cfg_protection; + uint8_t wps_state; + enum QDF_OPMODE csrPersona; + /* addIe params */ + struct add_ie_params add_ie_params; + uint16_t beacon_tx_rate; + tSirMacRateSet supported_rates; + tSirMacRateSet extended_rates; + bool require_h2e; + uint32_t cac_duration_ms; + uint32_t dfs_regdomain; +}; + +struct csr_config_params { + /* keep this uint32_t. This gets converted to ePhyChannelBondState */ + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + eCsrPhyMode phyMode; + uint32_t HeartbeatThresh50; + enum wmm_user_mode WMMSupportMode; + bool Is11eSupportEnabled; + bool ProprietaryRatesEnabled; + /* to set MCC Enable/Disable mode */ + uint8_t fEnableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + /* + * To allow MCC GO different B.I than STA's. + * NOTE: make sure if RIVA firmware can handle this combination before + * enabling this at the moment, this flag is provided only to pass + * Wi-Fi Cert. 5.1.12 + */ + uint8_t fAllowMCCGODiffBI; + tCsr11dinfo Csr11dinfo; + /* + * Customer wants to optimize the scan time. Avoiding scans(passive) + * on DFS channels while swipping through both bands can save some time + * (apprx 1.3 sec) + */ + uint8_t fEnableDFSChnlScan; + bool send_smps_action; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + bool obssEnabled; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + + uint8_t max_intf_count; + uint32_t f_sta_miracast_mcc_rest_time_val; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + bool sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + enum force_1x1_type is_force_1x1; + bool wep_tkip_in_he; +}; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#define DEFAULT_REASSOC_FAILURE_TIMEOUT 1000 +#endif + +struct csr_roam_info { + uint32_t nFrameLength; + uint8_t frameType; + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, + * in that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; + bool fReassocReq; /* set to true if for re-association */ + struct qdf_mac_addr bssid; + struct qdf_mac_addr peerMac; + tSirResultCodes status_code; + /* this'd be our own defined or sent from otherBSS(per 802.11spec) */ + uint32_t reasonCode; + + uint8_t disassoc_reason; + + uint8_t staId; /* Peer stationId when connected */ + /* false means auth needed from supplicant. true means authenticated */ + bool fAuthRequired; + uint8_t rsnIELen; + uint8_t *prsnIE; + uint8_t wapiIELen; + uint8_t *pwapiIE; + uint8_t addIELen; + uint8_t *paddIE; + union { + tSirMicFailureInfo *pMICFailureInfo; + tSirWPSPBCProbeReq *pWPSPBCProbeReq; + } u; + bool wmmEnabledSta; /* set to true if WMM enabled STA */ +#ifdef FEATURE_WLAN_ESE + struct tsm_ie tsm_ie; + uint16_t tsmRoamDelay; + struct ese_bcn_report_rsp *pEseBcnReportRsp; +#endif + /* Required for indicating the frames to upper layer */ + uint32_t assocReqLength; + uint8_t *assocReqPtr; + tSirChanChangeResponse *channelChangeRespEvent; + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; + struct oem_channel_info chan_info; + uint32_t target_chan_freq; + +#ifdef WLAN_FEATURE_NAN + union { + struct ndi_create_rsp ndi_create_params; + struct ndi_delete_rsp ndi_delete_params; + } ndp; +#endif + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + bool he_caps_present; + bool eht_caps_present; + bool ampdu; + bool sgi_enable; + bool tx_stbc; + bool rx_stbc; + tSirMacHTChannelWidth ch_width; + enum sir_sme_phy_mode mode; + uint8_t max_supp_idx; + uint8_t max_ext_idx; + uint8_t max_real_mcs_idx; + uint8_t max_mcs_idx; + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + /* Extended capabilities of STA */ + uint8_t ecsa_capable; + uint32_t ext_cap; + uint8_t supported_band; + int rssi; + int tx_rate; + int rx_rate; + tSirMacCapabilityInfo capability_info; + uint32_t rx_mc_bc_cnt; + uint32_t rx_retry_cnt; +#ifdef WLAN_FEATURE_SAE + struct sir_sae_info *sae_info; +#endif + struct assoc_ind *owe_pending_assoc_ind; + struct assoc_ind *ft_pending_assoc_ind; + + struct qdf_mac_addr peer_mld; +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE + uint32_t chan_info_freq; +#endif +}; + +typedef struct sSirSmeAssocIndToUpperLayerCnf { + uint16_t messageType; /* eWNI_SME_ASSOC_CNF */ + uint16_t length; + uint8_t sessionId; + tSirResultCodes status_code; + tSirMacAddr bssId; /* Self BSSID */ + tSirMacAddr peerMacAddr; + uint16_t aid; + uint8_t wmmEnabledSta; /* set to true if WMM enabled STA */ + tSirRSNie rsnIE; /* RSN IE received from peer */ + tSirWAPIie wapiIE; /* WAPI IE received from peer */ + tSirAddie addIE; /* this can be WSC and/or P2P IE */ + uint8_t reassocReq; /* set to true if reassoc */ + /* Timing and fine Timing measurement capability clubbed together */ + uint8_t timingMeasCap; + struct oem_channel_info chan_info; + uint8_t target_channel; + bool ampdu; + bool sgi_enable; + bool tx_stbc; + tSirMacHTChannelWidth ch_width; + enum sir_sme_phy_mode mode; + bool rx_stbc; + uint8_t max_supp_idx; + uint8_t max_ext_idx; + uint8_t max_mcs_idx; + uint8_t max_real_mcs_idx; + uint8_t rx_mcs_map; + uint8_t tx_mcs_map; + /* Extended capabilities of STA */ + uint8_t ecsa_capable; + uint32_t ext_cap; + uint8_t supported_band; + + uint32_t ies_len; + uint8_t *ies; + tDot11fIEHTCaps ht_caps; + tDot11fIEVHTCaps vht_caps; + tSirMacCapabilityInfo capability_info; + bool he_caps_present; + bool eht_caps_present; +#ifdef WLAN_FEATURE_11BE_MLO + tSirMacAddr peer_mld_addr; +#endif +} tSirSmeAssocIndToUpperLayerCnf, *tpSirSmeAssocIndToUpperLayerCnf; + +typedef struct tagCsrSummaryStatsInfo { + uint32_t snr; + int8_t rssi; + uint32_t retry_cnt[4]; + uint32_t multiple_retry_cnt[4]; + uint32_t tx_frm_cnt[4]; + /* uint32_t num_rx_frm_crc_err; same as rx_error_cnt */ + /* uint32_t num_rx_frm_crc_ok; same as rx_frm_cnt */ + uint32_t rx_frm_cnt; + uint32_t frm_dup_cnt; + uint32_t fail_cnt[4]; + uint32_t rts_fail_cnt; + uint32_t ack_fail_cnt; + uint32_t rts_succ_cnt; + uint32_t rx_discard_cnt; + uint32_t rx_error_cnt; + uint32_t tx_byte_cnt; + +} tCsrSummaryStatsInfo; + +typedef struct tagCsrGlobalClassAStatsInfo { + uint8_t tx_nss; + uint8_t rx_nss; + uint8_t rx_preamble; + uint8_t rx_bw; + uint32_t max_pwr; + uint32_t tx_rate; + uint32_t rx_rate; + /* mcs index for HT20 and HT40 rates */ + uint32_t tx_mcs_index; + uint32_t rx_mcs_index; + enum tx_rate_info tx_mcs_rate_flags; + enum tx_rate_info rx_mcs_rate_flags; + uint8_t tx_dcm; + uint8_t rx_dcm; + enum txrate_gi tx_gi; + enum txrate_gi rx_gi; + /* to diff between HT20 & HT40 rates;short & long guard interval */ + enum tx_rate_info tx_rx_rate_flags; + +} tCsrGlobalClassAStatsInfo; + +typedef struct tagCsrGlobalClassDStatsInfo { + uint32_t tx_uc_frm_cnt; + uint32_t tx_mc_frm_cnt; + uint32_t tx_bc_frm_cnt; + uint32_t rx_uc_frm_cnt; + uint32_t rx_mc_frm_cnt; + uint32_t rx_bc_frm_cnt; + uint32_t tx_uc_byte_cnt[4]; + uint32_t tx_mc_byte_cnt; + uint32_t tx_bc_byte_cnt; + uint32_t rx_uc_byte_cnt[4]; + uint32_t rx_mc_byte_cnt; + uint32_t rx_bc_byte_cnt; + uint32_t rx_byte_cnt; + uint32_t num_rx_bytes_crc_ok; + uint32_t rx_rate; + +} tCsrGlobalClassDStatsInfo; + +/** + * struct csr_per_chain_rssi_stats_info - stores chain rssi + * @rssi: array containing rssi for all chains + * @peer_mac_addr: peer mac address + */ +struct csr_per_chain_rssi_stats_info { + int8_t rssi[NUM_CHAINS_MAX]; + tSirMacAddr peer_mac_addr; +}; + +typedef void *tScanResultHandle; + +typedef enum { + REASSOC = 0, + FASTREASSOC = 1, + CONNECT_CMD_USERSPACE = 2, +} handoff_src; + +typedef struct tagCsrHandoffRequest { + struct qdf_mac_addr bssid; + uint32_t ch_freq; + uint8_t src; /* To check if its a REASSOC or a FASTREASSOC IOCTL */ +} tCsrHandoffRequest; + +#ifdef FEATURE_WLAN_ESE +typedef struct tagCsrEseBeaconReqParams { + uint16_t measurementToken; + uint32_t ch_freq; + uint8_t scanMode; + uint16_t measurementDuration; +} tCsrEseBeaconReqParams, *tpCsrEseBeaconReqParams; + +typedef struct tagCsrEseBeaconReq { + uint8_t numBcnReqIe; + tCsrEseBeaconReqParams bcnReq[SIR_ESE_MAX_MEAS_IE_REQS]; +} tCsrEseBeaconReq, *tpCsrEseBeaconReq; +#endif /* FEATURE_WLAN_ESE */ + +struct csr_del_sta_params { + struct qdf_mac_addr peerMacAddr; + struct qdf_mac_addr peer_mld_addr; + uint16_t reason_code; + uint8_t subtype; +}; + +/* Struct bss_dot11_config - Dot11 parameters for + * SAP operation + * @vdev_id: vdev id + * @privacy: privacy config + * @phy_mode: phy mode + * @bss_op_ch_freq: operational frequency + * @dot11_mode: dot11 mode + * @nw_type: network type + * @p_band: operating band + * @opr_rates: operational rates + * @ext_rates: extended rates + */ +struct bss_dot11_config { + uint8_t vdev_id; + uint8_t privacy; + eCsrPhyMode phy_mode; + uint32_t bss_op_ch_freq; + uint8_t dot11_mode; + tSirNwType nw_type; + enum reg_wifi_band p_band; + tSirMacRateSet opr_rates; + tSirMacRateSet ext_rates; +}; + +typedef QDF_STATUS (*csr_roam_complete_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct csr_roam_info *param, + eRoamCmdStatus roam_status, + eCsrRoamResult roam_result); +typedef QDF_STATUS (*csr_session_close_cb)(uint8_t session_id); + +#define CSR_IS_ANY_BSS_TYPE(pProfile) (eCSR_BSS_TYPE_ANY == \ + (pProfile)->BSSType) +#define CSR_IS_INFRA_AP(pProfile) (eCSR_BSS_TYPE_INFRA_AP == \ + (pProfile)->BSSType) +#ifdef WLAN_FEATURE_NAN +#define CSR_IS_NDI(profile) (eCSR_BSS_TYPE_NDI == (profile)->BSSType) +#else +#define CSR_IS_NDI(profile) (false) +#endif + +#ifdef WLAN_FEATURE_NAN +#define CSR_IS_CONN_NDI(profile) (eCSR_BSS_TYPE_NDI == (profile)->BSSType) +#else +#define CSR_IS_CONN_NDI(profile) (false) +#endif + +QDF_STATUS csr_set_channels(struct mac_context *mac, + struct csr_config_params *pParam); + +/* enum to string conversion for debug output */ +const char *get_e_roam_cmd_status_str(eRoamCmdStatus val); +const char *get_e_csr_roam_result_str(eCsrRoamResult val); +const char *csr_phy_mode_str(eCsrPhyMode phy_mode); + +#ifdef FEATURE_WLAN_ESE +typedef void (*tCsrTsmStatsCallback)(tAniTrafStrmMetrics tsmMetrics, + void *pContext); +#endif /* FEATURE_WLAN_ESE */ +typedef void (*tCsrSnrCallback)(int8_t snr, void *pContext); + +typedef void (*csr_readyToSuspendCallback)(void *pContext, bool suspended); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +typedef void (*csr_readyToExtWoWCallback)(void *pContext, bool status); +#endif +typedef void (*csr_link_status_callback)(uint8_t status, void *context); + +typedef void (*sme_get_raom_scan_ch_callback)( + hdd_handle_t hdd_handle, + struct roam_scan_ch_resp *roam_ch, + void *context); + +#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) && \ + defined(CONNECTIVITY_PKTLOG) +/** + * csr_packetdump_timer_stop() - stops packet dump timer + * + * This function is used to stop packet dump timer + * + * Return: None + * + */ +void csr_packetdump_timer_stop(void); + +/** + * csr_packetdump_timer_start() - start packet dump timer + * + * This function is used to start packet dump timer + * + * Return: None + * + */ +void csr_packetdump_timer_start(void); +#else +static inline void csr_packetdump_timer_stop(void) {} +static inline void csr_packetdump_timer_start(void) {} +#endif + +/** + * csr_update_owe_info() - Update OWE info + * @mac: mac context + * @assoc_ind: assoc ind + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_update_owe_info(struct mac_context *mac, + struct assoc_ind *assoc_ind); + +/** + * csr_update_ft_info() - Update FT info + * @mac: mac context + * @assoc_ind: assoc ind + * + * Return: QDF_STATUS + */ + +QDF_STATUS csr_update_ft_info(struct mac_context *mac, + struct assoc_ind *assoc_ind); + +typedef void (*csr_ani_callback)(int8_t *ani, void *context); + +/* + * csr_convert_to_reg_phy_mode() - CSR API to convert CSR phymode into + * regulatory phymode + * @csr_phy_mode: csr phymode with type eCsrPhyMode + * @freq: current operating frequency + * + * This API is used to convert a phymode from CSR to a phymode from regulatory + * + * Return: regulatory phymode that is comparable to input + */ +enum reg_phymode csr_convert_to_reg_phy_mode(eCsrPhyMode csr_phy_mode, + qdf_freq_t freq); + +/* + * csr_convert_from_reg_phy_mode() - CSR API to convert regulatory phymode into + * CSR phymode + * @reg_phymode: regulatory phymode + * + * This API is used to convert a regulatory phymode to a CSR phymode + * + * Return: eCSR phymode that is comparable to input + */ +eCsrPhyMode csr_convert_from_reg_phy_mode(enum reg_phymode phymode); + +/* + * csr_update_beacon() - CSR API to update beacon template + * @mac: mac context + * + * This API is used to update beacon template to FW + * + * Return: None + */ +void csr_update_beacon(struct mac_context *mac); + +/** + * csr_fill_enc_type() - converts crypto cipher set to csr specific cipher type + * @cipher_type: output csr cipher type + * @ cipherset:input cipher set + * + * Return: None + */ +void csr_fill_enc_type(eCsrEncryptionType *cipher_type, uint32_t cipherset); + +/** + * csr_fill_auth_type() - auth mode set to csr specific auth type + * @auth_type: output csr auth type + * @ authmodeset: authmode set + * @akm: akm + * @ucastcipherset: ucastcipherset + * + * Return: None + */ +void csr_fill_auth_type(enum csr_akm_type *auth_type, + uint32_t authmodeset, uint32_t akm, + uint32_t ucastcipherset); + +/** + * csr_phy_mode_to_dot11mode() - converts phy mode to dot11 mode + * @phy_mode: wlan phy mode + * + * Return: csr_cfgdot11mode + */ +enum csr_cfgdot11mode csr_phy_mode_to_dot11mode(enum wlan_phymode phy_mode); + +/* + * csr_mlme_vdev_disconnect_all_p2p_client_event() - Callback for MLME module + * to send a disconnect all P2P event to the SAP event handler + * @vdev_id: vdev id of SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_mlme_vdev_disconnect_all_p2p_client_event(uint8_t vdev_id); + +/* + * csr_mlme_vdev_stop_bss() - Callback for MLME module to send a stop BSS event + * to the SAP event handler + * @vdev_id: vdev id of SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_mlme_vdev_stop_bss(uint8_t vdev_id); + +/* + * csr_mlme_get_concurrent_operation_freq() - Callback for MLME module to + * get the concurrent operation frequency + * + * Return: concurrent frequency + */ +qdf_freq_t csr_mlme_get_concurrent_operation_freq(void); + +/* csr_convert_mode_to_nw_type() - CSR API to convert dot11 mode + * to network type. + * + * @dot11_mode: dot11 mode + * @band: reg band + * + * Return: network type + */ +tSirNwType +csr_convert_mode_to_nw_type(enum csr_cfgdot11mode dot11_mode, + enum reg_wifi_band band); + +/* + * csr_roam_get_phy_mode_band_for_bss() - CSR API to get phy mode and + * band for particular dot11 config + * @mac : mac context + * @dot11_cfg : pointer to the dot11 config + * + * Return : Void + */ +enum csr_cfgdot11mode +csr_roam_get_phy_mode_band_for_bss(struct mac_context *mac, + struct bss_dot11_config *dot11_cfg); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_internal.h new file mode 100644 index 0000000000..13e95d3fc8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_internal.h @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * \file csr_internal.h + * + * Define internal data structure for MAC. + */ +#ifndef CSRINTERNAL_H__ +#define CSRINTERNAL_H__ + +#include "qdf_status.h" +#include "qdf_lock.h" + +#include "qdf_mc_timer.h" +#include "csr_support.h" +#include "cds_reg_service.h" +#include "wlan_scan_public_structs.h" +#include "wlan_cm_roam_api.h" +#include "sir_types.h" +#include "wlan_mlme_public_struct.h" + +/* No of sessions to be supported, and a session is for Infra, BT-AMP */ +#define CSR_IS_SESSION_VALID(mac, sessionId) \ + ((sessionId) < WLAN_MAX_VDEVS && \ + (mac != NULL) && \ + ((mac)->roam.roamSession != NULL) && \ + (mac)->roam.roamSession[(sessionId)].sessionActive) + +#define CSR_GET_SESSION(mac, sessionId) \ + (sessionId < WLAN_MAX_VDEVS ? \ + &(mac)->roam.roamSession[(sessionId)] : NULL) + +#define CSR_IS_SESSION_ANY(sessionId) (sessionId == SME_SESSION_ID_ANY) +#define CSR_IS_DFS_CH_ROAM_ALLOWED(mac_ctx) \ + ( \ + ((((mac_ctx)->mlme_cfg->lfr.roaming_dfs_channel) != \ + ROAMING_DFS_CHANNEL_DISABLED) ? true : false) \ + ) +#define CSR_IS_ROAM_PREFER_5GHZ(mac) \ + ( \ + ((mac)->mlme_cfg->lfr.roam_prefer_5ghz) \ + ) + +/* Used to determine what to set to the MLME_DOT11_MODE */ +enum csr_cfgdot11mode { + eCSR_CFG_DOT11_MODE_ABG, + eCSR_CFG_DOT11_MODE_11A, + eCSR_CFG_DOT11_MODE_11B, + eCSR_CFG_DOT11_MODE_11G, + eCSR_CFG_DOT11_MODE_11N, + eCSR_CFG_DOT11_MODE_11AC, + eCSR_CFG_DOT11_MODE_11G_ONLY, + eCSR_CFG_DOT11_MODE_11N_ONLY, + eCSR_CFG_DOT11_MODE_11AC_ONLY, + /* This value can never set to CFG. Its for CSR's internal use */ + eCSR_CFG_DOT11_MODE_AUTO, + eCSR_CFG_DOT11_MODE_11AX, + eCSR_CFG_DOT11_MODE_11AX_ONLY, + eCSR_CFG_DOT11_MODE_11BE, + eCSR_CFG_DOT11_MODE_11BE_ONLY, + eCSR_CFG_DOT11_MODE_MAX, +}; + +enum csr_roam_reason { + eCsrForcedDisassocSta = 1, + eCsrForcedDeauthSta, +}; + +enum csr_roam_substate { + eCSR_ROAM_SUBSTATE_NONE = 0, + eCSR_ROAM_SUBSTATE_START_BSS_REQ, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + /* max is 15 unless the bitfield is expanded... */ +}; + +enum csr_roam_state { + eCSR_ROAMING_STATE_STOP = 0, + eCSR_ROAMING_STATE_IDLE, + eCSR_ROAMING_STATE_JOINING, + eCSR_ROAMING_STATE_JOINED, +}; + +enum csr_join_state { + eCsrContinueRoaming, + eCsrStopRoaming, +}; + +enum csr_roam_wmstatus_changetypes { + eCsrDisassociated, + eCsrDeauthenticated +}; + +struct csr_channel { + uint8_t numChannels; + uint32_t channel_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; +}; + +struct roam_cmd { + enum csr_roam_reason roamReason; + tSirMacAddr peerMac; + struct qdf_mac_addr peer_mld_addr; + enum wlan_reason_code reason; +}; + +struct wmstatus_changecmd { + enum csr_roam_wmstatus_changetypes Type; + union { + struct deauth_ind DeauthIndMsg; + struct disassoc_ind DisassocIndMsg; + } u; + +}; + +struct csr_config { + uint32_t channelBondingMode24GHz; + uint32_t channelBondingMode5GHz; + eCsrPhyMode phyMode; + enum csr_cfgdot11mode uCfgDot11Mode; + uint32_t HeartbeatThresh50; + enum wmm_user_mode WMMSupportMode; + bool Is11eSupportEnabled; + bool ProprietaryRatesEnabled; + bool fenableMCCMode; + bool mcc_rts_cts_prot_enable; + bool mcc_bcast_prob_resp_enable; + uint8_t fAllowMCCGODiffBI; + uint32_t nVhtChannelWidth; + bool send_smps_action; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + uint8_t cc_switch_mode; +#endif + bool obssEnabled; + uint8_t conc_custom_rule1; + uint8_t conc_custom_rule2; + uint8_t is_sta_connection_in_5gz_enabled; + enum force_1x1_type is_force_1x1; + bool wep_tkip_in_he; +}; + +struct csr_channel_powerinfo { + tListElem link; + uint32_t first_chan_freq; + uint8_t numChannels; + uint8_t txPower; + uint8_t interChannelOffset; +}; + +struct csr_scanstruct { + struct csr_channel channels11d; + struct channel_power defaultPowerTable[CFG_VALID_CHANNEL_LIST_LEN]; + struct csr_channel base_channels; /* The channel base to work on */ + tDblLinkList channelPowerInfoList24; + tDblLinkList channelPowerInfoList5G; + /* + * Customer wants to optimize the scan time. Avoiding scans(passive) + * on DFS channels while swipping through both bands can save some time + * (apprx 1.3 sec) + */ + uint8_t fEnableDFSChnlScan; + bool fcc_constraint; + bool pending_channel_list_req; +}; + +/* + * Save the connected information. This structure + connectedProfile + * should contain all information about the connection + */ +struct csr_roam_connectedinfo { + uint32_t nBeaconLength; + uint32_t nAssocReqLength; + uint32_t nAssocRspLength; + /* len of the parsed RIC resp IEs received in reassoc response */ + uint32_t nRICRspLength; +#ifdef FEATURE_WLAN_ESE + uint32_t nTspecIeLength; +#endif + /* + * Point to a buffer contain the beacon, assoc req, assoc rsp frame, in + * that order user needs to use nBeaconLength, nAssocReqLength, + * nAssocRspLength to desice where each frame starts and ends. + */ + uint8_t *pbFrames; +}; + +/** + * struct csr_disconnect_stats - Disconnect Stats per session + * @disconnection_cnt: total no. of disconnections + * @disconnection_by_app: diconnections triggered by application + * @disassoc_by_peer: disassoc sent by peer + * @deauth_by_peer: deauth sent by peer + * @bmiss: disconnect triggered by beacon miss + * @peer_kickout: disconnect triggered by peer kickout + */ +struct csr_disconnect_stats { + uint32_t disconnection_cnt; + uint32_t disconnection_by_app; + uint32_t disassoc_by_peer; + uint32_t deauth_by_peer; + uint32_t bmiss; + uint32_t peer_kickout; +}; + +/** + * struct csr_roam_session - CSR per-vdev context + * @vdev_id: ID of the vdev for which this entry is applicable + * @cb_mode: channel bonding mode + * @bcn_int: beacon interval + * @update_bcn_int: updated beacon interval + * @is_bcn_recv_start: Allow to process bcn recv indication + * @beacon_report_do_not_resume: Do not resume the beacon reporting after scan + */ +struct csr_roam_session { + uint8_t vdev_id; + bool sessionActive; /* true if it is used */ + + eCsrConnectState connectState; + struct csr_roam_connectedinfo connectedInfo; + tCsrRoamModifyProfileFields modifyProfileFields; + /* + * to remember some parameters needed for START_BSS. + * All member must be set every time we try to join + */ + ePhyChanBondState cb_mode; + uint16_t bcn_int; + bool update_bcn_int; + +#ifdef WLAN_BCN_RECV_FEATURE + bool is_bcn_recv_start; + bool beacon_report_do_not_resume; +#endif +#ifdef FEATURE_WLAN_ESE + bool isPrevApInfoValid; + uint32_t roamTS1; +#endif + bool ch_switch_in_progress; + uint8_t nss; + bool dhcp_done; + struct csr_disconnect_stats disconnect_stats; +}; + +struct csr_roamstruct { + struct csr_config configParam; + enum csr_roam_state curState[WLAN_MAX_VDEVS]; + enum csr_roam_substate curSubState[WLAN_MAX_VDEVS]; + /* + * This may or may not have the up-to-date valid channel list. It is + * used to get CFG_VALID_CHANNEL_LIST and not alloc mem all time + */ + int32_t sPendingCommands; + struct csr_roam_session *roamSession; +#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) && \ + defined(CONNECTIVITY_PKTLOG) + qdf_mc_timer_t packetdump_timer; +#endif + spinlock_t roam_state_lock; +}; + +#define CSR_IS_ROAM_STATE(mac, state, sessionId) \ + ((state) == (mac)->roam.curState[sessionId]) +#define CSR_IS_ROAM_STOP(mac, sessionId) \ + CSR_IS_ROAM_STATE((mac), eCSR_ROAMING_STATE_STOP, sessionId) +#define CSR_IS_ROAM_JOINING(mac, sessionId) \ + CSR_IS_ROAM_STATE(mac, eCSR_ROAMING_STATE_JOINING, sessionId) +#define CSR_IS_ROAM_JOINED(mac, sessionId) \ + CSR_IS_ROAM_STATE(mac, eCSR_ROAMING_STATE_JOINED, sessionId) +#define CSR_IS_ROAM_SUBSTATE(mac, subState, sessionId) \ + ((subState) == (mac)->roam.curSubState[sessionId]) +#define CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(mac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((mac), eCSR_ROAM_SUBSTATE_DISASSOC_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(mac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((mac), \ + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(mac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((mac), \ + eCSR_ROAM_SUBSTATE_START_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((mac), \ + eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, sessionId) +#define CSR_IS_ROAM_SUBSTATE_WAITFORKEY(mac, sessionId) \ + CSR_IS_ROAM_SUBSTATE((mac), \ + eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, sessionId) + +#define CSR_IS_PHY_MODE_DUAL_BAND(phyMode) \ + ((eCSR_DOT11_MODE_abg & (phyMode)) || \ + (eCSR_DOT11_MODE_11n & (phyMode)) || \ + (eCSR_DOT11_MODE_11ac & (phyMode)) || \ + (eCSR_DOT11_MODE_11ax & (phyMode)) || \ + (eCSR_DOT11_MODE_11be & (phyMode)) || \ + (eCSR_DOT11_MODE_AUTO & (phyMode))) + +#define CSR_IS_DOT11_MODE_11N(dot11mode) \ + ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11N) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AC) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11N_ONLY) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AX) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) + +#define CSR_IS_DOT11_MODE_11AC(dot11mode) \ + ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AC) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AC_ONLY) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AX) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) + +#define CSR_IS_DOT11_MODE_11AX(dot11mode) \ + ((dot11mode == eCSR_CFG_DOT11_MODE_AUTO) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AX) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11AX_ONLY) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11BE) || \ + (dot11mode == eCSR_CFG_DOT11_MODE_11BE_ONLY)) + +#define CSR_IS_DOT11_MODE_11BE(dot11mode) \ + (((dot11mode) == eCSR_CFG_DOT11_MODE_AUTO) || \ + ((dot11mode) == eCSR_CFG_DOT11_MODE_11BE) || \ + ((dot11mode) == eCSR_CFG_DOT11_MODE_11BE_ONLY)) + +#ifdef WLAN_FEATURE_11BE +#define CSR_IS_CFG_DOT11_PHY_MODE_11BE(dot11mode) \ + ((dot11mode) == eCSR_CFG_DOT11_MODE_11BE) + +#define CSR_IS_CFG_DOT11_PHY_MODE_11BE_ONLY(dot11mode) \ + ((dot11mode) == eCSR_CFG_DOT11_MODE_11BE_ONLY) +#else +#define CSR_IS_CFG_DOT11_PHY_MODE_11BE(dot11mode) 0 +#define CSR_IS_CFG_DOT11_PHY_MODE_11BE_ONLY(dot11mode) 0 +#endif +/* + * this function returns true if the NIC is operating exclusively in + * the 2.4 GHz band, meaning. it is NOT operating in the 5.0 GHz band. + */ +#define CSR_IS_24_BAND_ONLY(mac) \ + (BIT(REG_BAND_2G) == (mac)->mlme_cfg->gen.band) + +#define CSR_IS_5G_BAND_ONLY(mac) \ + (BIT(REG_BAND_5G) == (mac)->mlme_cfg->gen.band) + +#define CSR_IS_RADIO_DUAL_BAND(mac) \ + ((BIT(REG_BAND_2G) | BIT(REG_BAND_5G)) == \ + (mac)->mlme_cfg->gen.band_capability) + +#define CSR_IS_RADIO_BG_ONLY(mac) \ + (BIT(REG_BAND_2G) == (mac)->mlme_cfg->gen.band_capability) + +/* + * this function returns true if the NIC is operating exclusively in the 5.0 GHz + * band, meaning. it is NOT operating in the 2.4 GHz band + */ +#define CSR_IS_RADIO_A_ONLY(mac) \ + (BAND_5G == (mac)->mlme_cfg->gen.band_capability) +/* this function returns true if the NIC is operating in both bands. */ +#define CSR_IS_OPEARTING_DUAL_BAND(mac) \ + ((BAND_ALL == (mac)->mlme_cfg->gen.band_capability) && \ + (BAND_ALL == (mac)->mlme_cfg->gen.band)) +/* + * this function returns true if the NIC can operate in the 5.0 GHz band + * (could operate in the 2.4 GHz band also) + */ +#define CSR_IS_OPERATING_A_BAND(mac) \ + (CSR_IS_OPEARTING_DUAL_BAND((mac)) || \ + CSR_IS_RADIO_A_ONLY((mac)) || CSR_IS_5G_BAND_ONLY((mac))) + +/* + * this function returns true if the NIC can operate in the 2.4 GHz band + * (could operate in the 5.0 GHz band also). + */ +#define CSR_IS_OPERATING_BG_BAND(mac) \ + (CSR_IS_OPEARTING_DUAL_BAND((mac)) || \ + CSR_IS_RADIO_BG_ONLY((mac)) || CSR_IS_24_BAND_ONLY((mac))) + +#define CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) \ + (mac->mlme_cfg->wmm_params.wmm_tspec_element.ts_acm_is_off) + +/** + * csr_get_vdev_dot11_mode() - get the supported dot11mode by vdev + * @mac_ctx: pointer to global mac structure + * @vdev_id: vdev id + * @curr_dot11_mode: Current dot11 mode + * + * The function return the min of supported dot11 mode and vdev type dot11mode + * for given vdev type. + * + * Return:csr_cfgdot11mode + */ +enum csr_cfgdot11mode +csr_get_vdev_dot11_mode(struct mac_context *mac, + uint8_t vdev_id, + enum csr_cfgdot11mode curr_dot11_mode); + +QDF_STATUS csr_get_channel_and_power_list(struct mac_context *mac); + +QDF_STATUS csr_set_modify_profile_fields(struct mac_context *mac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +QDF_STATUS csr_get_modify_profile_fields(struct mac_context *mac, + uint32_t sessionId, tCsrRoamModifyProfileFields * + pModifyProfileFields); +void csr_set_global_cfgs(struct mac_context *mac); +void csr_set_default_dot11_mode(struct mac_context *mac); +bool csr_is_conn_state_disconnected(struct mac_context *mac, + uint8_t vdev_id); +bool csr_is_conn_state_connected(struct mac_context *mac, + uint32_t sessionId); +bool csr_is_conn_state_wds(struct mac_context *mac, uint32_t sessionId); +bool csr_is_conn_state_connected_wds(struct mac_context *mac, + uint32_t sessionId); +bool csr_is_conn_state_disconnected_wds(struct mac_context *mac, + uint32_t sessionId); +bool csr_is_any_session_in_connect_state(struct mac_context *mac); +bool csr_is_all_session_disconnected(struct mac_context *mac); + +bool csr_is_infra_ap_started(struct mac_context *mac); +bool csr_is_conn_state_connected_infra_ap(struct mac_context *mac, + uint32_t sessionId); +QDF_STATUS csr_get_snr(struct mac_context *mac, tCsrSnrCallback callback, + struct qdf_mac_addr bssId, void *pContext); +QDF_STATUS csr_get_config_param(struct mac_context *mac, + struct csr_config_params *pParam); +QDF_STATUS csr_change_default_config_param(struct mac_context *mac, + struct csr_config_params *pParam); +QDF_STATUS csr_msg_processor(struct mac_context *mac, void *msg_buf); +QDF_STATUS csr_open(struct mac_context *mac); +QDF_STATUS csr_init_chan_list(struct mac_context *mac); +QDF_STATUS csr_close(struct mac_context *mac); +QDF_STATUS csr_start(struct mac_context *mac); +QDF_STATUS csr_stop(struct mac_context *mac); +QDF_STATUS csr_ready(struct mac_context *mac); + +/** + * csr_get_concurrent_operation_freq() - To get concurrent operating freq + * @mac_ctx: Pointer to mac context + * + * This routine will return operating freq on FIRST BSS that is + * active/operating to be used for concurrency mode. + * If other BSS is not up or not connected it will return 0 + * + * Return: uint32_t + */ +uint32_t csr_get_concurrent_operation_freq(struct mac_context *mac_ctx); + +/** + * csr_get_beaconing_concurrent_channel() - To get concurrent operating channel + * frequency of beaconing interface + * @mac_ctx: Pointer to mac context + * @vdev_id_to_skip: channel of which vdev id to skip + * + * This routine will return operating channel of active AP/GO channel + * and will skip the channel of vdev_id_to_skip. + * If other no requested mode is active it will return 0 + * + * Return: uint32_t + */ +uint32_t csr_get_beaconing_concurrent_channel(struct mac_context *mac_ctx, + uint8_t vdev_id_to_skip); + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * csr_check_concurrent_channel_overlap() - To check concurrent overlap chnls + * @mac: Pointer to mac context + * @sap_freq: Requested SAP freq + * @sap_phymode: SAP phy mode + * @cc_switch_mode: concurrent switch mode + * @vdev_id: vdev id of SAP/GO requesting + * + * This routine will be called to check concurrent overlap channels + * + * Return: uint16_t + */ +uint16_t csr_check_concurrent_channel_overlap(struct mac_context *mac, + uint32_t sap_freq, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode, uint8_t vdev_id); +#endif + +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(struct mac_context *mac, uint8_t sessionId); + +#ifdef FEATURE_WLAN_ESE +/* Returns whether the current association is a ESE assoc or not */ +bool csr_roam_is_ese_assoc(struct mac_context *mac, uint32_t sessionId); +QDF_STATUS csr_get_tsm_stats(struct mac_context *mac, + tCsrTsmStatsCallback callback, + struct qdf_mac_addr bssId, + void *pContext, uint8_t tid); +#endif + +/** + * csr_send_channel_change_req() - Post channel change request to LIM + * @mac : mac context + * @req : channel change request + * + * This API is primarily used to post Channel Change Req for SAP + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_send_channel_change_req(struct mac_context *mac, + struct channel_change_req *req); + +/* Post Beacon Tx Start Indication */ +QDF_STATUS csr_roam_start_beacon_req(struct mac_context *mac, + struct qdf_mac_addr bssid, uint8_t dfsCacWaitStatus); + +/** + * csr_roam_send_chan_sw_ie_request() - Request to transmit CSA IE + * @mac_ctx: Global MAC context + * @bssid: BSSID + * @target_chan_freq: Channel frequency on which to send the IE + * @csa_ie_reqd: Include/Exclude CSA IE. + * @ch_params: operating Channel related information + * @new_cac_ms: cac duration of new channel + * + * This function sends request to transmit channel switch announcement + * IE to lower layers + * + * Return: success or failure + **/ +QDF_STATUS csr_roam_send_chan_sw_ie_request(struct mac_context *mac, + struct qdf_mac_addr bssid, + uint32_t target_chan_freq, + uint8_t csaIeReqd, + struct ch_params *ch_params, + uint32_t new_cac_ms); + +QDF_STATUS csr_roam_modify_add_ies(struct mac_context *mac, + tSirModifyIE *pModifyIE, + eUpdateIEsType updateType); +QDF_STATUS +csr_roam_update_add_ies(struct mac_context *mac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); + +bool csr_nonscan_active_ll_remove_entry( + struct mac_context *mac_ctx, + tListElem *pEntryToRemove, bool inter_locked); +tListElem *csr_nonscan_active_ll_peek_head( + struct mac_context *mac_ctx, + bool inter_locked); +tListElem *csr_nonscan_pending_ll_peek_head( + struct mac_context *mac_ctx, + bool inter_locked); +tListElem *csr_nonscan_pending_ll_next( + struct mac_context *mac_ctx, + tListElem *entry, bool inter_locked); + +/** + * csr_purge_pdev_all_ser_cmd_list() - purge all scan and non-scan + * active and pending cmds for all vdevs in pdev + * @mac_ctx: pointer to global MAC context + * + * Return : none + */ +void csr_purge_pdev_all_ser_cmd_list(struct mac_context *mac_ctx); + +void csr_roam_substate_change( + struct mac_context *mac, enum csr_roam_substate + NewSubstate, uint32_t sessionId); + +bool csr_is_ndi_started(struct mac_context *mac_ctx, uint32_t session_id); + +QDF_STATUS csr_roam_update_config( + struct mac_context *mac_ctx, uint8_t session_id, + uint16_t capab, uint32_t value); + +/** + * csr_is_mcc_channel() - check if using the channel results into MCC + * @mac_ctx: pointer to global MAC context + * @chan_freq: channel frequency to check for MCC scenario + * + * Return : true if channel causes MCC, else false + */ +bool csr_is_mcc_channel(struct mac_context *mac_ctx, uint32_t chan_freq); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * csr_roam_auth_offload_callback() - Registered CSR Callback function to handle + * WPA3 roam pre-auth event from firmware. + * @mac_ctx: Global mac context pointer + * @vdev_id: Vdev id + * @bssid: candidate AP bssid + * @akm: candidate AKM + */ +QDF_STATUS +csr_roam_auth_offload_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm); +#else +static inline QDF_STATUS +csr_roam_auth_offload_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +/** + * csr_invoke_neighbor_report_request - Send neighbor report invoke command to + * WMA + * @mac_ctx: MAC context + * @session_id: session id + * + * API called from IW to invoke neighbor report request to WMA then to FW + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_invoke_neighbor_report_request(uint8_t session_id, + struct sRrmNeighborReq *neighbor_report_req, + bool send_resp_to_host); + +/** + * csr_set_vdev_ies_per_band() - sends the per band IEs to vdev + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev_id for which IE is targeted + * @device_mode: vdev mode + * + * Return: None + */ +void csr_set_vdev_ies_per_band(mac_handle_t mac_handle, uint8_t vdev_id, + enum QDF_OPMODE device_mode); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_link_list.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_link_list.h new file mode 100644 index 0000000000..7fe62b7687 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_link_list.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2011-2012, 2014-2016, 2018-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * \file csr_link_list.h + * + * Exports and types for the Common link list interfaces. + */ + +#ifndef CSR_LINK_LIST_H__ +#define CSR_LINK_LIST_H__ + +#include "qdf_lock.h" +#include "qdf_mc_timer.h" +#include "cds_api.h" +#include "sir_types.h" +#include "qdf_util.h" + +#define LL_ACCESS_LOCK true +#define LL_ACCESS_NOLOCK false + +typedef struct tagListElem { + struct tagListElem *last; + struct tagListElem *next; +} tListElem; + +typedef enum { + LIST_FLAG_CLOSE = 0, + LIST_FLAG_OPEN = 0xa1b2c4d7, +} tListFlag; + +/* This is a circular double link list */ +typedef struct tagDblLinkList { + tListElem ListHead; + qdf_mutex_t Lock; + uint32_t Count; + tListFlag Flag; +} tDblLinkList; + +/* + * To get the address of an object of (type) base on the (address) + * of one of its (field) + */ +#define GET_BASE_ADDR(address, type, field) \ + (qdf_container_of(address, type, field)) +/* To get the offset of (field) inside structure (type) */ +#define GET_FIELD_OFFSET(type, field) (qdf_offsetof(type, field)) +#define GET_ROUND_UP(_Field, _Boundary) \ + (((_Field) + ((_Boundary) - 1)) & ~((_Boundary) - 1)) +#define csrIsListEmpty(pHead) ((pHead)->next == (pHead)) + +uint32_t csr_ll_count(tDblLinkList *pList); +QDF_STATUS csr_ll_open(tDblLinkList *pList); +void csr_ll_close(tDblLinkList *pList); +void csr_ll_lock(tDblLinkList *pList); +void csr_ll_unlock(tDblLinkList *pList); +bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked); +void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +/* This function put pNewEntry before pEntry. Caller should have found pEntry */ +void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry, + tListElem *pNewEntry, bool fInterlocked); +tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked); +tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked); +bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove, + bool fInterlocked); +void csr_ll_purge(tDblLinkList *pList, bool fInterlocked); +/* csr_ll_next return NULL if reaching the end or list is empty */ +tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked); +bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_support.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_support.h new file mode 100644 index 0000000000..c4c13d84cb --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/csr_support.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * \file csr_support.h + * + * Exports and types for the Common Scan and Roaming supporting interfaces. + */ +#ifndef CSR_SUPPORT_H__ +#define CSR_SUPPORT_H__ + +#include "csr_link_list.h" +#include "csr_api.h" +#include "cds_reg_service.h" + +#ifdef FEATURE_WLAN_WAPI +#define CSR_WAPI_OUI_SIZE (4) +#endif /* FEATURE_WLAN_WAPI */ + +#define CSR_RSN_OUI_SIZE (4) +#define CSR_WPA_OUI_SIZE (4) + +#define CSR_DOT11_SUPPORTED_RATES_MAX (12) +#define CSR_DOT11_EXTENDED_SUPPORTED_RATES_MAX (8) + +#define CSR_DOT11_BASIC_RATE_MASK WLAN_DOT11_BASIC_RATE_MASK + +/** + * struct csr_timer_info - CSR-specific timer context + * @mac: Global MAC context associated with the timer + * @vdev_id: Session associated with the timer + */ +struct csr_timer_info { + struct mac_context *mac; + uint8_t vdev_id; +}; + +#define CSR_IS_QOS_BSS(pIes) \ + ((pIes)->WMMParams.present || (pIes)->WMMInfoAp.present) + +uint32_t csr_get_frag_thresh(struct mac_context *mac_ctx); +uint32_t csr_get_rts_thresh(struct mac_context *mac_ctx); + +bool csr_is_bssid_match(struct qdf_mac_addr *pProfBssid, + struct qdf_mac_addr *BssBssid); +/* + * This function will allocate memory for the parsed IEs to the caller. + * Caller must free the memory. after it is done with the data only if + * this function succeeds + */ +QDF_STATUS csr_get_parsed_bss_description_ies(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs **ppIEStruct); + +/** + * csr_is_auth_type_ese() - Checks whether Auth type is ESE or not + * @AuthType: Authentication type + * + * Return: true, if auth type is ese, false otherwise + */ +bool csr_is_auth_type_ese(enum csr_akm_type AuthType); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_api.h new file mode 100644 index 0000000000..0fcb67b499 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_api.h @@ -0,0 +1,4803 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SME_API_H) +#define __SME_API_H + +/* + * file smeApi.h + * + * brief prototype for SME APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "csr_api.h" +#include "qdf_lock.h" +#include "qdf_types.h" +#include "sir_api.h" +#include "cds_regdomain.h" +#include "sme_internal.h" +#include "wma_tgt_cfg.h" +#include "wma_fips_public_structs.h" +#include "wma_sar_public_structs.h" +#include "wma_if.h" +#include "wlan_mlme_public_struct.h" +#include "sme_rrm_internal.h" +#include "sir_types.h" +#include "scheduler_api.h" +#include "wlan_serialization_legacy_api.h" +#include +#include "wmi_unified.h" +#include "wmi_unified_param.h" +#include "wlan_cm_roam_public_struct.h" + +/*-------------------------------------------------------------------------- + Preprocessor definitions and constants + ------------------------------------------------------------------------*/ + +#define sme_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_SME, params) +#define sme_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_SME, params) +#define sme_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_SME, params) +#define sme_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_SME, params) +#define sme_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_SME, params) + +#define sme_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_SME, params) +#define sme_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_SME, params) +#define sme_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_SME, params) +#define sme_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_SME, params) +#define sme_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_SME, params) + +#define sme_alert_rl(params...) QDF_TRACE_FATAL_RL(QDF_MODULE_ID_SME, params) +#define sme_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_SME, params) +#define sme_warn_rl(params...) QDF_TRACE_WARN_RL(QDF_MODULE_ID_SME, params) +#define sme_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_SME, params) +#define sme_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_SME, params) + +#define SME_ENTER() QDF_TRACE_ENTER(QDF_MODULE_ID_SME, "enter") +#define SME_EXIT() QDF_TRACE_EXIT(QDF_MODULE_ID_SME, "exit") + +#define SME_SESSION_ID_ANY 50 +#define SME_SESSION_ID_BROADCAST 0xFF + +#define SME_INVALID_COUNTRY_CODE "XX" +#define INVALID_ROAM_ID 0 + +#define SME_SET_CHANNEL_REG_POWER(reg_info_1, val) do { \ + reg_info_1 &= 0xff00ffff; \ + reg_info_1 |= ((val & 0xff) << 16); \ +} while (0) + +#define SME_SET_CHANNEL_MAX_TX_POWER(reg_info_2, val) do { \ + reg_info_2 &= 0xffff00ff; \ + reg_info_2 |= ((val & 0xff) << 8); \ +} while (0) + +#define SME_CONFIG_TO_ROAM_CONFIG 1 +#define ROAM_CONFIG_TO_SME_CONFIG 2 + +#define NUM_OF_BANDS 2 + +#define SUPPORTED_CRYPTO_CAPS 0x3FFFF + +#define SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE (30*1000) +#define SME_CMD_TIMEOUT_VALUE (SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE + 1000) + +/* AP start timeout = vdev start + 2 sec */ +#define SME_CMD_VDEV_START_BSS_TIMEOUT (START_RESPONSE_TIMER + 2000) +#define SME_CMD_START_BSS_TIMEOUT (SME_CMD_VDEV_START_BSS_TIMEOUT + 1000) + +/* AP stop timeout = vdev stop + self peer delete + 1 sec */ +#define SME_CMD_STOP_BSS_CMD_TIMEOUT (STOP_RESPONSE_TIMER + \ + SIR_DELETE_STA_TIMEOUT + 1000) +#define SME_CMD_STOP_BSS_TIMEOUT (SME_CMD_STOP_BSS_CMD_TIMEOUT + 1000) + +/* Peer disconnect timeout = peer delete + 1 sec */ +#define SME_CMD_PEER_DISCONNECT_TIMEOUT (SIR_DELETE_STA_TIMEOUT + 1000) +#define SME_PEER_DISCONNECT_TIMEOUT (SME_CMD_PEER_DISCONNECT_TIMEOUT + 1000) + +#define SME_CMD_GET_DISCONNECT_STATS_TIMEOUT 200 +#define SME_CMD_ADD_DEL_TS_TIMEOUT (4 * 1000) + +/* + * POLICY_MGR_SER_CMD_TIMEOUT should be same as SME_CMD_POLICY_MGR_CMD_TIMEOUT + * if SME_CMD_POLICY_MGR_CMD_TIMEOUT is changed change + * POLICY_MGR_SER_CMD_TIMEOUT as well. + */ +#define SME_CMD_POLICY_MGR_CMD_TIMEOUT (SIR_VDEV_PLCY_MGR_TIMEOUT + 1000) +#define SME_POLICY_MGR_CMD_TIMEOUT (SME_CMD_POLICY_MGR_CMD_TIMEOUT + 1000) + +#define SME_VDEV_DELETE_CMD_TIMEOUT (DELETE_RESPONSE_TIMER + \ + PEER_DELETE_ALL_RESPONSE_TIMER + 2000) +#define SME_CMD_VDEV_CREATE_DELETE_TIMEOUT QDF_MAX(13000, \ + SME_VDEV_DELETE_CMD_TIMEOUT + 1) + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +struct sme_config_params { + struct csr_config_params csr_config; +}; + +#ifdef FEATURE_WLAN_TDLS +#define BW_20_OFFSET_BIT 0 +#define BW_40_OFFSET_BIT 1 +#define BW_80_OFFSET_BIT 2 +#define BW_160_OFFSET_BIT 3 +#endif /* FEATURE_WLAN_TDLS */ + +struct wmi_twt_add_dialog_param; +struct wmi_twt_del_dialog_param; + +/* Thermal Mitigation*/ +typedef struct { + uint16_t smeMinTempThreshold; + uint16_t smeMaxTempThreshold; +} tSmeThermalLevelInfo; + +typedef enum { + SME_AC_BK = 0, + SME_AC_BE = 1, + SME_AC_VI = 2, + SME_AC_VO = 3 +} sme_ac_enum_type; + +/* + * Enumeration of the various TSPEC directions + * From 802.11e/WMM specifications + */ +enum sme_qos_wmm_dir_type { + SME_QOS_WMM_TS_DIR_UPLINK = 0, + SME_QOS_WMM_TS_DIR_DOWNLINK = 1, + SME_QOS_WMM_TS_DIR_RESV = 2, /* Reserved */ + SME_QOS_WMM_TS_DIR_BOTH = 3, +}; + +/** + * struct sme_oem_capability - OEM capability to be exchanged between host + * and userspace + * @ftm_rr: FTM range report capability bit + * @lci_capability: LCI capability bit + * @reserved1: reserved + * @reserved2: reserved + */ +struct sme_oem_capability { + uint32_t ftm_rr:1; + uint32_t lci_capability:1; + uint32_t reserved1:30; + uint32_t reserved2; +}; + +/** + * struct sme_5g_pref_params : 5G preference params to be read from ini + * @rssi_boost_threshold_5g: RSSI threshold above which 5 GHz is favored + * @rssi_boost_factor_5g: Factor by which 5GHz RSSI is boosted + * @max_rssi_boost_5g: Maximum boost that can be applied to 5GHz RSSI + * @rssi_penalize_threshold_5g: RSSI threshold below which 5G is not favored + * @rssi_penalize_factor_5g: Factor by which 5GHz RSSI is penalized + * @max_rssi_penalize_5g: Maximum penalty that can be applied to 5G RSSI + */ +struct sme_5g_band_pref_params { + int8_t rssi_boost_threshold_5g; + uint8_t rssi_boost_factor_5g; + uint8_t max_rssi_boost_5g; + int8_t rssi_penalize_threshold_5g; + uint8_t rssi_penalize_factor_5g; + uint8_t max_rssi_penalize_5g; +}; + +#define MAX_CANDIDATE_INFO 10 + +/** + * struct bss_candidate_info - Candidate bss information + * + * @bssid : BSSID of candidate bss + * @status : status code for candidate bss + */ +struct bss_candidate_info { + struct qdf_mac_addr bssid; + uint32_t status; +}; + +/* + * MBO transition reason codes + */ +enum { + MBO_TRANSITION_REASON_UNSPECIFIED, + MBO_TRANSITION_REASON_EXCESSIVE_FRAME_LOSS_RATE, + MBO_TRANSITION_REASON_EXCESSIVE_DELAY_FOR_CURRENT_TRAFFIC, + MBO_TRANSITION_REASON_INSUFFICIENT_BANDWIDTH_FOR_CURRENT_TRAFFIC, + MBO_TRANSITION_REASON_LOAD_BALANCING, + MBO_TRANSITION_REASON_LOW_RSSI, + MBO_TRANSITION_REASON_RECEIVED_EXCESSIVE_RETRANSMISSIONS, + MBO_TRANSITION_REASON_HIGH_INTERFERENCE, + MBO_TRANSITION_REASON_GRAY_ZONE, + MBO_TRANSITION_REASON_TRANSITIONING_TO_PREMIUM_AP, +}; + +/*------------------------------------------------------------------------- + Function declarations and documentation + ------------------------------------------------------------------------*/ +QDF_STATUS sme_open(mac_handle_t mac_handle); +QDF_STATUS sme_init_chan_list(mac_handle_t mac_handle, enum country_src cc_src); +QDF_STATUS sme_close(mac_handle_t mac_handle); +QDF_STATUS sme_start(mac_handle_t mac_handle); + +/** + * sme_stop() - Stop all SME modules and put them at idle state + * @mac_handle: Opaque handle to the MAC context + * + * The function stops each module in SME. Upon return, all modules are + * at idle state ready to start. + * + * This is a synchronous call + * + * Return: QDF_STATUS_SUCCESS if SME is stopped. Other status means + * SME failed to stop one or more modules but caller should + * still consider SME is stopped. + */ +QDF_STATUS sme_stop(mac_handle_t mac_handle); + +/** + * sme_populate_nss_chain_params() - fill vdev nss chain params from ini + * @mac_handle: The handle returned by mac_open. + * @vdev_ini_cfg: pointer to the structure to be filled + * @device_mode: device mode (eg STA, SAP etc.) + * @rf_chains_supported: number of chains supported by fw(updated during + * service ready event) + * + * This API will fill the nss chain params for the particular vdev from ini + * configuration for the respective vdev. + * + * Return: none + */ +void sme_populate_nss_chain_params(mac_handle_t mac_handle, + struct wlan_mlme_nss_chains *vdev_ini_cfg, + enum QDF_OPMODE device_mode, + uint8_t rf_chains_supported); + +/** + * sme_store_nss_chains_cfg_in_vdev() - fill vdev nss chain params from ini + * @vdev: Pointer to vdev obj + * @vdev_ini_cfg: pointer to the structure the values are to be filled from + * + * This API will copy the nss chain params for the particular vdev from ini + * configuration to the respective vdev's dynamic, and ini config. + * + * Return: none + */ +void +sme_store_nss_chains_cfg_in_vdev(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_nss_chains *vdev_ini_cfg); + +/** + * sme_modify_nss_chains_tgt_cfg() - Change the nss in ini for + * particular opmode, and band, according to the chain config supported by FW. + * @mac_handle: The handle returned by mac_open. + * @vdev_op_mode: vdev operation mode. + * @band:- band for which user wants to change nss. + * + * This API will change the nss in ini (for eg. rx_nss_2g) in the mlme cfg i.e + * the global config structure kept in mac context, according to the max + * supported chains per band which is got as part of ext service ready event. + * + * Return: none + */ +void +sme_modify_nss_chains_tgt_cfg(mac_handle_t mac_handle, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band); + +/** + * sme_update_nss_in_mlme_cfg() - Change the nss in ini(rx_nss_(band)) for + * particular opmode, and band. + * @mac_handle: The handle returned by mac_open. + * @rx_nss: new value of rx nss that user wants to change. + * @tx_nss: new value of tx nss that user wants to change. + * @vdev_op_mode: vdev operation mode. + * @band:- band for which user wants to change nss. + * + * This API will change the nss in ini (for eg. rx_nss_2g) in the mlme cfg i.e + * the global config structure kept in mac context. + * + * Return: none + */ +void +sme_update_nss_in_mlme_cfg(mac_handle_t mac_handle, + uint8_t rx_nss, uint8_t tx_nss, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band); + +/** + * sme_nss_chains_update() - validate and send the user params to fw + * @mac_handle: The handle returned by mac_open. + * @user_cfg: pointer to the structure to be validated and sent to fw + * @vdev_id: vdev id + * + * + * This API will validate the config, and if found correct will update the + * config in dynamic config, and send to the fw. + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_nss_chains_update(mac_handle_t mac_handle, + struct wlan_mlme_nss_chains *user_cfg, + uint8_t vdev_id); + +/** + * sme_update_bfer_caps_as_per_nss_chains() - Update beamformer caps as per nss + * chains. + * @mac_handle: The handle returned by mac_open + * @cfg: wma target config + * + * This API will update beamformer capability as per nss chains + * + * Return: None + */ +void +sme_update_bfer_caps_as_per_nss_chains(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg); + +/** + * sme_vdev_create() - Create vdev for given persona + * @mac_handle: The handle returned by mac_open + * @vdev_params: params required for vdev creation + * + * This API will create the object manager vdev and in the same + * context vdev mlme object manager notification is invoked, which + * will send the vdev create to the firmware. + * + * If the vdev creation is successful the following object is referenced + * by below modules: + * 1) WLAN_OBJMGR_ID + * 2) WLAN_LEGACY_SME_ID + * + * Return: Newly created Vdev object or NULL incase in any error + */ +struct wlan_objmgr_vdev *sme_vdev_create(mac_handle_t mac_handle, + struct wlan_vdev_create_params *vdev_params); + + +/** + * sme_vdev_post_vdev_create_setup() - setup the lower layers for the new vdev + * @mac_handle: The handle returned by mac_open + * @vdev: Object manager vdev + * + * This api will setup the csr/mlme/wma layer for the newly created vdev. + * + * If the post vdev setup is successful, we will have following vdev refs + * 1) WLAN_OBJMGR_ID for self peer + * 2) WLAN_LEGACY_WMA_ID for vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_vdev_post_vdev_create_setup(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev); + +/** + * sme_send_multi_pdev_vdev_set_params() - setup lower layers for the new vdev + * @param_type: enum of type mlme_dev_setparam + * @dev_id: stores device(pdev/vdev) id + * @param: points to an array of @n_params + * @n_params: stores number params that we are sending together with @param + * Return: QDF_STATUS + */ +QDF_STATUS +sme_send_multi_pdev_vdev_set_params(enum mlme_dev_setparam param_type, + uint8_t dev_id, + struct dev_set_param *param, + uint8_t n_params); + +/** + * sme_validate_txrx_chain_mask() - validates txrx chain mask + * @paramid: Rx/Tx chain mask param id + * @paramvalue: param value + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_validate_txrx_chain_mask(uint32_t paramid, uint32_t paramvalue); + +/** + * sme_vdev_set_data_tx_callback() - Set dp vdev tx callback + * @vdev: Object manager vdev + * + * This api will setup the dp vdev tx data callbaack. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_vdev_set_data_tx_callback(struct wlan_objmgr_vdev *vdev); + +/** + * sme_vdev_delete() - Delete vdev for given id + * @mac_handle: The handle returned by mac_open. + * @vdev: VDEV Object + * + * This is a synchronous API. This API needs to be called to delete vdev + * in SME module before terminating the session completely. + * + * The following modules releases their reference to the vdev object: + * 1) WLAN_LEGACY_WMA_ID + * 2) WLAN_LEGACY_SME_ID + * + * Return: QDF_STATUS_SUCCESS - vdev is deleted. + * QDF_STATUS_E_INVAL when failed to delete vdev. + */ +QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev); + +/** + * sme_cleanup_session() - clean up sme session info for vdev + * @mac_handle: mac handle + * @vdev_id: vdev id + * + * Return: none + */ +void sme_cleanup_session(mac_handle_t mac_handle, uint8_t vdev_id); + +/** + * sme_update_roam_params() - Store/Update the roaming params + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev ID + * @src_rso_config: The source to copy + * @src_rso_usr_cfg: The source to copy + * @update_param: Type of parameter to be updated + * + * Return: Return the status of the updation. + */ +QDF_STATUS sme_update_roam_params(mac_handle_t mac_handle, + uint8_t vdev_id, + struct rso_config_params *src_rso_config, + struct rso_user_config *src_rso_usr_cfg, + int update_param); +QDF_STATUS sme_update_config(mac_handle_t mac_handle, + struct sme_config_params *pSmeConfigParams); + +QDF_STATUS sme_set11dinfo(mac_handle_t mac_handle, + struct sme_config_params *pSmeConfigParams); +QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle); + +#ifdef WLAN_BCN_RECV_FEATURE +/* + * sme_register_bcn_report_pe_cb() - Register SME callback + * @mac_handle: The handle returned by mac_open. + * @cb: cb of type beacon_report_cb + * + * This function Register SME callback in order to send + * beacon report to upper layer + * + * Return QDF_STATUS_SUCCESS - + */ +QDF_STATUS +sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb); +#else +static inline QDF_STATUS +sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_ser_cmd_callback() - callback from serialization module + * @cmd: serialization command + * @reason: reason why serialization module has given this callback + * + * Serialization module will give callback to SME for why it triggered + * the callback + * + * Return: QDF_STATUS_SUCCESS + */ +QDF_STATUS sme_ser_cmd_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason); + +/* + * sme_process_msg() - The main message processor for SME. + * @mac: The global mac context + * @msg: The message to be processed. + * + * This function is called by a message dispatcher when to process a message + * targeted for SME. + * This is a synchronous call + * + * Return: QDF_STATUS_SUCCESS - SME successfully processed the message. + * Other status means SME failed to process the message to HAL. + */ +QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg); + +QDF_STATUS sme_mc_process_handler(struct scheduler_msg *msg); + +/** + * sme_roam_ndi_stop() - API to request stop ndi + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * + * Return: QDF Status success or failure + */ +QDF_STATUS sme_roam_ndi_stop(mac_handle_t mac_handle, uint8_t vdev_id); + +void sme_dhcp_done_ind(mac_handle_t mac_handle, uint8_t session_id); + +/* + * sme_roam_stop_bss() - To stop BSS for Soft AP. This is an asynchronous API. + * @mac_handle - Global structure + * @vdev_id - vdev id of SoftAP + * + * Return: QDF Status success or failure + */ +QDF_STATUS sme_roam_stop_bss(mac_handle_t mac_handle, uint8_t vdev_id); +QDF_STATUS sme_roam_disconnect_sta(mac_handle_t mac_handle, uint8_t sessionId, + struct csr_del_sta_params *p_del_sta_params); +QDF_STATUS sme_roam_deauth_sta(mac_handle_t mac_handle, uint8_t sessionId, + struct csr_del_sta_params *pDelStaParams); + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * sme_multi_client_ll_rsp_register_callback() - Register multi client low + * latency callback + * @mac_handle: Opaque handle to the MAC context + * @latency_level_event_handler_cb: Function to be invoked for low latency + * event + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_multi_client_ll_rsp_register_callback(mac_handle_t mac_handle, + void (*latency_level_event_handler_cb) + (const struct latency_level_data *event_data, + uint8_t vdev_id)); + +/** + * sme_multi_client_ll_rsp_deregister_callback() - De Register multi client + * low latency callback + * @mac_handle: Opaque handle to the MAC context + * + * Return: void + */ +void sme_multi_client_ll_rsp_deregister_callback(mac_handle_t mac_handle); +#else +static inline QDF_STATUS +sme_multi_client_ll_rsp_register_callback(mac_handle_t mac_handle, + void (*latency_level_event_handler_cb) + (const void *event_data, + uint8_t vdev_id)) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +void sme_multi_client_ll_rsp_deregister_callback(mac_handle_t mac_handle) +{} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_set_roam_scan_ch_event_cb() - Register roam scan ch callback + * @mac_handle: Opaque handle to the MAC context + * @cb: callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle, + sme_get_raom_scan_ch_callback cb); + +/** + * sme_get_roam_scan_ch() -API to get roam scan channels + * @mac_handle: Pointer to mac handle + * @sta_id: vdev id + * @pcontext: pointer to the context + * + * Extract number of frequencies and frequency list from chan_info and print + * to the logs. + * + * Return: None + */ +QDF_STATUS +sme_get_roam_scan_ch(mac_handle_t mac_handle, + uint8_t vdev_id, void *pcontext); + +/** + * sme_get_pmk_info(): A wrapper function to request CSR to save PMK + * @mac_handle: Global structure + * @session_id: SME session_id + * @pmk_cache: pointer to a structure of pmk + * + * Return: none + */ +void sme_get_pmk_info(mac_handle_t mac_handle, uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache); + +/** + * sme_roam_set_psk_pmk - Set the PMK to vdev cache + * @mac_handle: Opaque Mac handle + * @pmksa: Pointer to pmksa cache + * @vdev_id: Vdev id + * @update_to_fw: Send RSO update config command to firmware to update + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_roam_set_psk_pmk(mac_handle_t mac_handle, + struct wlan_crypto_pmksa *pmksa, + uint8_t vdev_id, bool update_to_fw); + +/** + * sme_set_pmk_cache_ft() - a wrapper function to request CSR to save MDID + * This is a synchronous call. + * @mac_handle: Global structure + * @session_id: SME session id + * @pmk_cache: pointer to pmk cache structure wlan_crypto_pmksa + * + * Return: QDF_STATUS -status whether MDID is set or not + */ +QDF_STATUS sme_set_pmk_cache_ft(mac_handle_t mac_handle, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache); +#else +static inline +void sme_get_pmk_info(mac_handle_t mac_handle, uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache) +{} + +static inline QDF_STATUS +sme_get_roam_scan_ch(mac_handle_t mac_handle, + uint8_t vdev_id, void *pcontext) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle, + void *cb) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +QDF_STATUS sme_roam_set_psk_pmk(mac_handle_t mac_handle, + struct wlan_crypto_pmksa *pmksa, + uint8_t vdev_id, bool update_to_fw) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS sme_set_pmk_cache_ft(mac_handle_t mac_handle, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + +QDF_STATUS sme_get_config_param(mac_handle_t mac_handle, + struct sme_config_params *pParam); +QDF_STATUS sme_get_snr(mac_handle_t mac_handle, + tCsrSnrCallback callback, + struct qdf_mac_addr bssId, void *pContext); +#ifdef FEATURE_WLAN_ESE +QDF_STATUS sme_get_tsm_stats(mac_handle_t mac_handle, + tCsrTsmStatsCallback callback, + struct qdf_mac_addr bssId, + void *pContext, uint8_t tid); +QDF_STATUS sme_set_ese_beacon_request(mac_handle_t mac_handle, + const uint8_t sessionId, + const tCsrEseBeaconReq *in_req); + +/** + * sme_set_plm_request() - set plm request + * @mac_handle: Opaque handle to the global MAC context + * @req: Pointer to input plm request + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_plm_request(mac_handle_t mac_handle, + struct plm_req_params *req); +#endif /*FEATURE_WLAN_ESE */ + +#ifdef FEATURE_OEM_DATA_SUPPORT +QDF_STATUS sme_register_oem_data_rsp_callback(mac_handle_t mac_handle, + sme_send_oem_data_rsp_msg callback); +void sme_deregister_oem_data_rsp_callback(mac_handle_t mac_handle); + +#else +static inline +QDF_STATUS sme_register_oem_data_rsp_callback(mac_handle_t mac_handle, + void *callback) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void sme_deregister_oem_data_rsp_callback(mac_handle_t mac_handle) +{ +} + +#endif + +QDF_STATUS sme_generic_change_country_code(mac_handle_t mac_handle, + uint8_t *pCountry); + + +/** + * sme_update_channel_list() - Update configured channel list to fwr + * This is a synchronous API. + * @mac_handle: Opaque handle to the global MAC context. + * + * Return: QDF_STATUS SUCCESS. + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_update_channel_list(mac_handle_t mac_handle); + +QDF_STATUS sme_dhcp_start_ind(mac_handle_t mac_handle, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +QDF_STATUS sme_dhcp_stop_ind(mac_handle_t mac_handle, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId); +QDF_STATUS sme_neighbor_report_request(mac_handle_t mac_handle, + uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); + +/** + * sme_register_pagefault_cb() - Register cb to handle host action on pagefault + * @mac_handle: Opaque handle to the global MAC context. + * @hdd_pagefault_action_cb: Callback which needs to be registered + * + * Return: None + */ +void +sme_register_pagefault_cb(mac_handle_t mac_handle, + QDF_STATUS (*hdd_pagefault_action_cb)(void *buf, + uint32_t buf_len)); + +/** + * sme_deregister_ssr_on_pagefault_cb() - Deregister cb to trigger SSR on + * pagefault + * @mac_handle: Opaque handle to the global MAC context. + * + * Return: None + */ +void sme_deregister_ssr_on_pagefault_cb(mac_handle_t mac_handle); + +#ifdef FEATURE_OEM_DATA +/** + * sme_oem_data_cmd() - the wrapper to send oem data cmd to wma + * @mac_handle: Opaque handle to the global MAC context. + * @@oem_data_event_handler_cb: callback to be registered + * @oem_data: the pointer of oem data + * @vdev id: vdev id to fetch adapter + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle, + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data, + uint8_t vdev_id), + struct oem_data *oem_data, + uint8_t vdev_id); + +/** + * sme_oem_event_deinit() - function to deregister cb for oem event + * @mac_handle: Opaque handle to the global MAC context + * + * Return: None + */ +void sme_oem_event_deinit(mac_handle_t mac_handle); + +/** + * sme_async_oem_event_init() - function to register cb for async oem event + * @mac_handle: Opaque handle to the global MAC context + * @@oem_data_async_event_handler_cb: callback to be registered + * + * Return: None + */ +void sme_async_oem_event_init(mac_handle_t mac_handle, + void (*oem_data_async_event_handler_cb) + (const struct oem_data *oem_event_data)); +/** + * sme_async_oem_event_deinit() - function to deregister cb for async oem event + * @mac_handle: Opaque handle to the global MAC context + * + * Return: None + */ +void sme_async_oem_event_deinit(mac_handle_t mac_handle); +#else +static inline void sme_async_oem_event_init( + mac_handle_t mac_handle, + void (*oem_data_async_event_handler_cb) + (void *oem_event_data)) +{ +} + +static inline void sme_async_oem_event_deinit(mac_handle_t mac_handle) +{ +} +#endif + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_oem_req_cmd() - send oem request cmd to WMA + * @mac_handle: Opaque handle to the global MAC context + * @oem_req: OEM data request + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle, + struct oem_data_req *oem_req); +QDF_STATUS sme_oem_update_capability(mac_handle_t mac_handle, + struct sme_oem_capability *cap); +QDF_STATUS sme_oem_get_capability(mac_handle_t mac_handle, + struct sme_oem_capability *cap); +#endif /*FEATURE_OEM_DATA_SUPPORT */ +QDF_STATUS sme_change_mcc_beacon_interval(uint8_t sessionId); +QDF_STATUS sme_set_host_offload(mac_handle_t mac_handle, uint8_t sessionId, + struct sir_host_offload_req *pRequest); +QDF_STATUS sme_set_keep_alive(mac_handle_t mac_handle, uint8_t sessionId, + struct keep_alive_req *pRequest); +QDF_STATUS sme_get_operation_channel(mac_handle_t mac_handle, + uint32_t *chan_freq, + uint8_t sessionId); +QDF_STATUS sme_register_mgmt_frame(mac_handle_t mac_handle, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +QDF_STATUS sme_deregister_mgmt_frame(mac_handle_t mac_handle, + uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen); +/** + * sme_change_sap_csa_count() - Set CSA count + * @count: CSA count to be set + * + * Routine sets CSA count in CSA IE when channel switch + * is triggered + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_change_sap_csa_count(uint8_t count); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +QDF_STATUS sme_configure_ext_wow(mac_handle_t mac_handle, + tpSirExtWoWParams wlanExtParams, + csr_readyToSuspendCallback callback, + void *callbackContext); +QDF_STATUS sme_configure_app_type1_params(mac_handle_t mac_handle, + tpSirAppType1Params wlanAppType1Params); +QDF_STATUS sme_configure_app_type2_params(mac_handle_t mac_handle, + tpSirAppType2Params wlanAppType2Params); +#endif +/** + * sme_get_beaconing_concurrent_operation_channel() - To get concurrent + * operating channel frequency of beaconing interface + * @mac_handle: Pointer to mac context + * @vdev_id_to_skip: channel of which vdev id to skip + * + * This routine will return operating channel of active AP/GO channel + * and will skip the channel of vdev_id_to_skip. + * If other no requested mode is active it will return 0 + * + * Return: uint32_t + */ +uint32_t sme_get_beaconing_concurrent_operation_channel(mac_handle_t mac_handle, + uint8_t vdev_id_to_skip); +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * sme_check_concurrent_channel_overlap() - Get interfering concurrent channel + * @mac_handle: SAP context pointer + * @sap_ch_freq: SAP home channel frequency + * @sapPhyMode: sap phymode + * @cc_switch_mode: force scc channel switch mode + * @vdev_id: vdev id + * + * Determine if a concurrent channel is interfering. + * + * Return: Channel freq (Mhz) of the interfering channel, or 0 if none. + */ +uint16_t sme_check_concurrent_channel_overlap(mac_handle_t mac_handle, + uint16_t sap_ch_freq, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode, + uint8_t vdev_id); +#endif + +/** + * sme_get_cfg_valid_channels() - To get valid channel list + * @valid_ch_freq: pointer to array which save the valid channel list + * @len: the length of the valid channel list + * + * Return: QDF status + */ +QDF_STATUS sme_get_cfg_valid_channels(uint32_t *valid_ch_freq, uint32_t *len); + +#ifdef WLAN_FEATURE_PACKET_FILTERING +QDF_STATUS sme_8023_multicast_list(mac_handle_t mac_handle, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs); +#endif /* WLAN_FEATURE_PACKET_FILTERING */ +uint16_t sme_chn_to_freq(uint8_t chanNum); + +/* + * sme_is_channel_valid() - validate a channel against current regdmn + * To check if the channel is valid for currently established domain + * This is a synchronous API. + * + * mac_handle - The handle returned by mac_open. + * chan_freq - channel to verify + * + * Return: true/false, true if channel is valid + */ +bool sme_is_channel_valid(mac_handle_t mac_handle, uint32_t chan_freq); + +QDF_STATUS sme_set_max_tx_power(mac_handle_t mac_handle, + struct qdf_mac_addr pBssid, + struct qdf_mac_addr pSelfMacAddress, int8_t dB); +QDF_STATUS sme_set_max_tx_power_per_band(enum band_info band, int8_t db); +QDF_STATUS sme_set_tx_power(mac_handle_t mac_handle, uint8_t sessionId, + struct qdf_mac_addr bssid, + enum QDF_OPMODE dev_mode, int power); +QDF_STATUS sme_set_custom_mac_addr(tSirMacAddr customMacAddr); +QDF_STATUS sme_hide_ssid(mac_handle_t mac_handle, uint8_t sessionId, + uint8_t ssidHidden); + +/** + * sme_set_listen_interval() - Set the listen interval + * @mac_handle: The handle returned by mac_open + * @vdev_id: vdev identifier + * + * Return: None + */ +void sme_set_listen_interval(mac_handle_t mac_handle, uint8_t vdev_id); + +/** + * sme_update_roam_scan_n_probes() - Update no.of roam scan probes + * @mac_handle: The handle returned by mac_open + * @vdev_id: vdev identifier + * @probes: number of probe requests to be sent out + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_roam_scan_n_probes(mac_handle_t mac_handle, + uint8_t vdev_id, + const uint8_t probes); + +/** + * sme_update_roam_scan_home_away_time() - Update roam scan Home away time + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev identifier + * @roam_scan_home_away_time: Scan home away time + * @send_offload_cmd: If it's true, the command is sent to firmware, + * otherwise the command is not sent to firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_update_roam_scan_home_away_time(mac_handle_t mac_handle, uint8_t vdev_id, + const uint16_t roam_scan_home_away_time, + const bool send_offload_cmd); + +/** + * sme_get_roam_scan_n_probes() - get Roam scan number of probes + * @mac_handle: The handle returned by mac_open + * @vdev_id: vdev identifier + * @roam_scan_n_probes: Buffer to fill the number of probes. + * Valid only if the return status is success. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_roam_scan_n_probes(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t *roam_scan_n_probes); + +/** + * sme_update_roam_rssi_diff() - Update RoamRssiDiff + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev identifier + * @roam_rssi_diff: Minimum rssi difference between potential candidate and + * current AP. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_roam_rssi_diff(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t roam_rssi_diff); + +QDF_STATUS sme_update_wes_mode(mac_handle_t mac_handle, bool isWESModeEnabled, + uint8_t sessionId); + +QDF_STATUS sme_update_is_fast_roam_ini_feature_enabled(mac_handle_t mac_handle, + uint8_t sessionId, + const bool + isFastRoamIniFeatureEnabled); + +QDF_STATUS sme_stop_roaming(mac_handle_t mac_handle, uint8_t sessionId, + uint8_t reason, + enum wlan_cm_rso_control_requestor requestor); + +QDF_STATUS sme_start_roaming(mac_handle_t mac_handle, uint8_t sessionId, + uint8_t reason, + enum wlan_cm_rso_control_requestor requestor); + +/** + * sme_roaming_in_progress() - check if roaming is in progress + * @mac_handle - The handle returned by mac_open + * @vdev_id: vdev id + * + * Return: true or false + */ +bool sme_roaming_in_progress(mac_handle_t mac_handle, uint8_t vdev_id); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS sme_update_is_ese_feature_enabled(mac_handle_t mac_handle, + uint8_t sessionId, + const bool isEseIniFeatureEnabled); +#endif /* FEATURE_WLAN_ESE */ +QDF_STATUS sme_set_roam_rescan_rssi_diff(mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff); + +QDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff( + mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nOpportunisticThresholdDiff); + +/** + * sme_set_neighbor_lookup_rssi_threshold() - update neighbor lookup rssi thr + * @mac_handle: The handle returned by mac_open + * @vdev_id: vdev identifier + * @neighbor_lookup_rssi_threshold: Neighbor lookup rssi threshold + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_neighbor_lookup_rssi_threshold(mac_handle_t mac_handle, + uint8_t vdev_id, + uint8_t neighbor_lookup_rssi_threshold); + +QDF_STATUS sme_set_neighbor_scan_refresh_period(mac_handle_t mac_handle, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod); + +QDF_STATUS sme_update_empty_scan_refresh_period(mac_handle_t mac_handle, + uint8_t sessionId, uint16_t empty_scan_refresh_period); +/** + * sme_update_full_roam_scan_period() - Send full roam scan period to SME + * @mac_handle: Opaque handle to the MAC context + * @vdev_id: vdev id + * @full_roam_scan_period: Idle period in seconds between two successive + * full channel roam scans + * + * Updated full scan period in roam info and a roam_offload_scan request. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_full_roam_scan_period(mac_handle_t mac_handle, + uint8_t vdev_id, + uint32_t full_roam_scan_period); + +/** + * sme_modify_roam_cand_sel_criteria() - Modify candidate selection criteria + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev Identifier + * @enable_scoring_for_roam: Carries enable/disable indication + * + * Enable/disable scoring for roam candidate selection based on the value of + * enable_scoring_for_roam. Below is the description of enable/disable, + * Disable-0: Disable scoring for roam candidate selection. Roaming + * shall fallback to legacy selection criteria, only RSSI. + * Enable-1 : Enable scoring for roam candidate selection. + * + * Return: Success or failure + */ +QDF_STATUS +sme_modify_roam_cand_sel_criteria(mac_handle_t mac_handle, + uint8_t vdev_id, + bool enable_scoring_for_roam); + +/** + * sme_roam_control_restore_default_config - Restore roam config to default + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev Identifier + * + * Restore enable_scoring_for_roam, emptyScanRefreshPeriod, + * full_roam_scan_period to their default values and send RSO command to + * firmware with the updated values. + * + * Return: Success or failure + */ +QDF_STATUS sme_roam_control_restore_default_config(mac_handle_t mac_handle, + uint8_t vdev_id); + +QDF_STATUS sme_set_neighbor_scan_min_chan_time(mac_handle_t mac_handle, + const uint16_t nNeighborScanMinChanTime, + uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_max_chan_time(mac_handle_t mac_handle, + uint8_t sessionId, + const uint16_t nNeighborScanMaxChanTime); +uint32_t sme_get_current_roam_state(mac_handle_t mac_handle, uint8_t sessionId); +uint32_t sme_get_current_roam_sub_state(mac_handle_t mac_handle, + uint8_t sessionId); +uint32_t sme_get_lim_sme_state(mac_handle_t mac_handle); +uint32_t sme_get_lim_mlm_state(mac_handle_t mac_handle); +bool sme_is_lim_session_valid(mac_handle_t mac_handle, uint8_t sessionId); +uint32_t sme_get_lim_sme_session_state(mac_handle_t mac_handle, + uint8_t sessionId); +uint32_t sme_get_lim_mlm_session_state(mac_handle_t mac_handle, + uint8_t sessionId); +QDF_STATUS sme_set_neighbor_scan_period(mac_handle_t mac_handle, + uint8_t sessionId, + const uint16_t nNeighborScanPeriod); +QDF_STATUS sme_set_roam_bmiss_first_bcnt(mac_handle_t mac_handle, + uint8_t sessionId, const uint8_t nRoamBmissFirstBcnt); +QDF_STATUS sme_set_roam_bmiss_final_bcnt(mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt); +QDF_STATUS sme_change_roam_scan_channel_list(mac_handle_t mac_handle, + uint8_t sessionId, + uint32_t *channel_freq_list, + uint8_t numChannels); + +/** + * sme_update_roam_scan_freq_list() - Update roam scan freq list + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev identifier + * @freq_list: List of frequencies to be configured + * @num_channels: Number of frequencies to be configured + * @freq_list_type: Type of frequency list to be configured to + * + * Update the frequencies from freq_list to the corresponding channel list + * in neighborRoamInfo + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_update_roam_scan_freq_list(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t *freq_list, uint8_t num_chan, + uint32_t freq_list_type); +QDF_STATUS sme_get_roam_scan_channel_list(mac_handle_t mac_handle, + uint32_t *freq_list, + uint8_t *pNumChannels, + uint8_t sessionId); + +bool sme_is_feature_supported_by_fw(enum cap_bitmap feature); + +QDF_STATUS sme_set_phy_mode(mac_handle_t mac_handle, eCsrPhyMode phyMode); +eCsrPhyMode sme_get_phy_mode(mac_handle_t mac_handle); +uint32_t sme_get_11b_data_duration(mac_handle_t mac_handle, + uint32_t chan_freq); + +QDF_STATUS sme_add_periodic_tx_ptrn(mac_handle_t mac_handle, + tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams); +QDF_STATUS sme_del_periodic_tx_ptrn(mac_handle_t mac_handle, + tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams); +QDF_STATUS sme_send_rate_update_ind(mac_handle_t mac_handle, + tSirRateUpdateInd *rateUpdateParams); +void sme_get_command_q_status(mac_handle_t mac_handle); + +/** + * sme_set_wlm_latency_level() - Used to set the latency level to fw + * @mac_handle: mac handle + * @vdev_id: vdev id + * @latency_level: latency level to be set in FW + * @client_id_bitmap: client id bitmap + * @force_reset: flag to reset latency level + * + * Return QDF_STATUS + */ +QDF_STATUS sme_set_wlm_latency_level(mac_handle_t mac_handle, + uint16_t vdev_id, uint16_t latency_level, + uint32_t client_id_bitmap, + bool force_reset); + +/* + * SME API to enable/disable idle mode powersave + * This should be called only if powersave offload + * is enabled + */ +QDF_STATUS sme_set_idle_powersave_config(bool value); +QDF_STATUS sme_notify_modem_power_state(mac_handle_t mac_handle, + uint32_t value); + +/** + * sme_set_peer_ampdu() - API to set peer A-MPDU count to target + * @mac_handle: mac handle + * @vdev_id: vdev id + * @peer_mac: peer mac address + * @cfg: A-MPDU count to configure + * + * Return: 0 if success, otherwise error code + */ +int sme_set_peer_ampdu(mac_handle_t mac_handle, uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, uint16_t cfg); + +/*SME API to convert convert the ini value to the ENUM used in csr and MAC*/ +ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value); +int sme_update_ht_config(mac_handle_t mac_handle, uint8_t sessionId, + uint16_t htCapab, + int value); +int16_t sme_get_ht_config(mac_handle_t mac_handle, uint8_t session_id, + uint16_t ht_capab); +#ifdef QCA_HT_2040_COEX +QDF_STATUS sme_notify_ht2040_mode(mac_handle_t mac_handle, + struct qdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type); +QDF_STATUS sme_set_ht2040_mode(mac_handle_t mac_handle, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled); + +/** + * sme_get_ht2040_mode() - get ht operation mode + * @mac_handle: pointer to mac context + * @vdev_id: vdev id + * @channel_type: channel type to provide + * + * Return QDF_STATUS + */ +QDF_STATUS sme_get_ht2040_mode(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelType *channel_type); +#endif + +/** + * sme_get_reg_info() - To get tx power information + * @mac_handle: Opaque handle to the global MAC context + * @chan_freq: channel freq + * @regInfo1: first reg info to fill + * @regInfo2: second reg info to fill + * + * This routine will give you tx power information + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_reg_info(mac_handle_t mac_handle, uint32_t chan_freq, + uint32_t *regInfo1, uint32_t *regInfo2); + +#ifdef FEATURE_WLAN_CH_AVOID +QDF_STATUS sme_ch_avoid_update_req(mac_handle_t mac_handle); +#else +static inline +QDF_STATUS sme_ch_avoid_update_req(mac_handle_t mac_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * sme_set_auto_shutdown_cb() - Register auto shutdown evt handler + * @mac_handle: Handle to the global MAC context + * @callback_fn: callback function to be invoked when an auto shutdown + * event is received + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_auto_shutdown_cb(mac_handle_t mac_handle, + void (*callback_fn)(void)); + +QDF_STATUS sme_set_auto_shutdown_timer(mac_handle_t mac_handle, + uint32_t timer_value); +#endif + +QDF_STATUS sme_roam_start_beacon_req(mac_handle_t mac_handle, + struct qdf_mac_addr bssid, + uint8_t dfsCacWaitStatus); + +QDF_STATUS sme_csa_restart(struct mac_context *mac_ctx, uint8_t session_id); + +/** + * sme_roam_csa_ie_request() - request CSA IE transmission from PE + * @mac_handle: handle returned by mac_open + * @bssid: SAP bssid + * @target_chan_freq: target channel frequency information + * @csaIeReqd: CSA IE Request + * @ch_params: channel information + * @new_cac_ms: cac duration of new channel + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_roam_csa_ie_request(mac_handle_t mac_handle, + struct qdf_mac_addr bssid, + uint32_t target_chan_freq, uint8_t csaIeReqd, + struct ch_params *ch_params, + uint32_t new_cac_ms); + +/** + * sme_set_addba_accept() - Allow/Reject the ADDBA req session + * @mac_handle: handle returned by mac_open + * @session_id: sme session id + * @value: Allow/Reject AddBA session + * + * Allows/Rejects the ADDBA req session + * + * Return: 0 on success else errno + */ +int sme_set_addba_accept(mac_handle_t mac_handle, uint8_t session_id, + int value); + +QDF_STATUS sme_init_thermal_info(mac_handle_t mac_handle); + +QDF_STATUS sme_set_thermal_level(mac_handle_t mac_handle, uint8_t level); +QDF_STATUS sme_txpower_limit(mac_handle_t mac_handle, + struct tx_power_limit *psmetx); + +/** + * sme_get_link_speed() - Retrieve current link speed + * @mac_handle: Global MAC handle + * @req: Link speed request structure + * @context: User context to be passed back when invoking @cb + * @cb: Callback function to be invoked with link speed results + * + * Return: QDF_STATUS_SUCCESS if the request was accepted, otherwise + * an appropriate error status. + */ +QDF_STATUS sme_get_link_speed(mac_handle_t mac_handle, + struct link_speed_info *req, + void *context, + sme_link_speed_cb cb); + +QDF_STATUS sme_modify_add_ie(mac_handle_t mac_handle, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType); +QDF_STATUS sme_update_add_ie(mac_handle_t mac_handle, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType); +QDF_STATUS sme_update_connect_debug(mac_handle_t mac_handle, + uint32_t set_value); + +/** + * sme_bss_type_to_string() - converts bss type to string. + * @bss_type: bss type enum + * + * Return: printable string for bss type + */ +const char *sme_bss_type_to_string(const uint8_t bss_type); +QDF_STATUS sme_ap_disable_intra_bss_fwd(mac_handle_t mac_handle, + uint8_t sessionId, + bool disablefwd); + +/** + * sme_send_unit_test_cmd() - send unit test command to lower layer + * @session_id: sme session id to be filled while forming the command + * @module_id: module id given by user to be filled in the command + * @arg_count: number of argument count + * @arg: pointer to argument list + * + * This API exposed to HDD layer which takes the argument from user and sends + * down to lower layer for further processing + * + * Return: QDF_STATUS based on overall success + */ +QDF_STATUS sme_send_unit_test_cmd(uint32_t vdev_id, uint32_t module_id, + uint32_t arg_count, uint32_t *arg); + +typedef struct sStatsExtRequestReq { + uint32_t request_data_len; + uint8_t *request_data; +} tStatsExtRequestReq, *tpStatsExtRequestReq; + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * sme_stats_ext_register_callback() - Register stats ext callback + * @mac_handle: Opaque handle to the MAC context + * @callback: Function to be invoked for stats ext events + * + * This function is called to register the callback that send vendor + * event for stats ext + */ +void sme_stats_ext_register_callback(mac_handle_t mac_handle, + stats_ext_cb callback); + +/** + * sme_stats_ext_deregister_callback() - Deregister stats ext callback + * @mac_handle: Opaque handle to the MAC context + * + * This function is called to deregister the callback that send vendor + * event for stats ext + */ +void sme_stats_ext_deregister_callback(mac_handle_t mac_handle); + +/** + * sme_stats_ext2_register_callback() - Register stats ext2 callback + * @mac_handle: Opaque handle to the MAC context + * @callback: Function to be invoked for stats ext2 events + * + * This function will register a callback for frame aggregation failure + * indications processing. + * + * Return: void + */ +void sme_stats_ext2_register_callback(mac_handle_t mac_handle, + stats_ext2_cb callback); + +QDF_STATUS sme_stats_ext_request(uint8_t session_id, + tpStatsExtRequestReq input); +#else +static inline void +sme_stats_ext_register_callback(mac_handle_t mac_handle, + stats_ext_cb callback) +{ +} + +static inline void +sme_stats_ext_deregister_callback(mac_handle_t mac_handle) +{ +} + +static inline void +sme_stats_ext2_register_callback(mac_handle_t mac_handle, + stats_ext2_cb callback) +{ +} +#endif /* WLAN_FEATURE_STATS_EXT */ +QDF_STATUS sme_update_dfs_scan_mode(mac_handle_t mac_handle, + uint8_t sessionId, + uint8_t allowDFSChannelRoam); +uint8_t sme_get_dfs_scan_mode(mac_handle_t mac_handle); + +/** + * sme_get_valid_channels_by_band() - to fetch valid channels filtered by band + * @mac_handle: Opaque handle to the global MAC context + * @wifi_band: RF band information + * @valid_chan_list: output array to store channel info + * @valid_chan_len: output number of channels + * + * SME API to fetch all valid channels filtered by band + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_valid_channels_by_band(mac_handle_t mac_handle, + uint8_t wifi_band, + uint32_t *valid_chan_list, + uint8_t *valid_chan_len); + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * sme_ext_scan_get_capabilities() - SME API to fetch extscan capabilities + * @mac_handle: Opaque handle to the MAC context + * @params: extscan capabilities request structure + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_ext_scan_get_capabilities(mac_handle_t mac_handle, + struct extscan_capabilities_params *params); + +/** + * sme_ext_scan_start() - SME API to issue extscan start + * @mac_handle: Opaque handle to the MAC context + * @params: extscan start structure + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_ext_scan_start(mac_handle_t mac_handle, + struct wifi_scan_cmd_req_params *params); + +/** + * sme_ext_scan_stop() - SME API to issue extscan stop + * @mac_handle: Opaque handle to the MAC context + * @params: extscan stop structure + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ext_scan_stop(mac_handle_t mac_handle, + struct extscan_stop_req_params *params); + +/** + * sme_set_bss_hotlist() - SME API to set BSSID hotlist + * @mac_handle: Opaque handle to the MAC context + * @params: extscan set hotlist structure + * + * Handles the request to set the BSSID hotlist in firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_bss_hotlist(mac_handle_t mac_handle, + struct extscan_bssid_hotlist_set_params *params); + +/** + * sme_reset_bss_hotlist() - SME API to reset BSSID hotlist + * @mac_handle: Opaque handle to the MAC context + * @params: extscan reset hotlist structure + * + * Handles the request to reset the BSSID hotlist in firmware. + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_reset_bss_hotlist(mac_handle_t mac_handle, + struct extscan_bssid_hotlist_reset_params *params); + +/** + * sme_set_significant_change() - SME API to set significant change + * @mac_handle: Opaque handle to the MAC context + * @params: extscan set significant change structure + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_significant_change(mac_handle_t mac_handle, + struct extscan_set_sig_changereq_params *params); + +/** + * sme_reset_significant_change() - SME API to reset significant change + * @mac_handle: Opaque handle to the MAC context + * @params: extscan reset significant change structure + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_reset_significant_change(mac_handle_t mac_handle, + struct extscan_capabilities_reset_params *params); + +/** + * sme_get_cached_results() - SME API to get cached results + * @mac_handle: Opaque handle to the MAC context + * @params: extscan get cached results structure + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_get_cached_results(mac_handle_t mac_handle, + struct extscan_cached_result_params *params); + +/** + * sme_set_epno_list() - set epno network list + * @mac_handle: Opaque handle to the MAC context + * @params: request message + * + * This function sends an Enhanced PNO configuration to firmware. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_epno_list(mac_handle_t mac_handle, + struct wifi_enhanced_pno_params *params); + +/** + * sme_set_passpoint_list() - set passpoint network list + * @mac_handle: Opaque handle to the MAC context + * @params: set passpoint list request parameters + * + * This function constructs the cds message and fill in message type, + * bodyptr with @params and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_passpoint_list(mac_handle_t mac_handle, + struct wifi_passpoint_req_param *params); + +/** + * sme_reset_passpoint_list() - reset passpoint network list + * @mac_handle: Opaque handle to the MAC context + * @params: reset passpoint list request parameters + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_reset_passpoint_list(mac_handle_t mac_handle, + struct wifi_passpoint_req_param *params); + +QDF_STATUS sme_ext_scan_register_callback(mac_handle_t mac_handle, + ext_scan_ind_cb ext_scan_ind_cb); +#else +static inline +QDF_STATUS sme_ext_scan_register_callback(mac_handle_t mac_handle, + ext_scan_ind_cb ext_scan_ind_cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_EXTSCAN */ + +/** + * sme_get_vht_ch_width() - SME API to get the max supported FW chan width + * + * Return: Max channel width supported by FW (eg. 20, 40, 80, 160, 80+80) + */ +uint32_t sme_get_vht_ch_width(void); + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +QDF_STATUS sme_ll_stats_clear_req(mac_handle_t mac_handle, + tSirLLStatsClearReq * pclearStatsReq); +QDF_STATUS sme_ll_stats_set_req(mac_handle_t mac_handle, + tSirLLStatsSetReq *psetStatsReq); + +/** + * sme_ll_stats_get_req() - SME API to get the Link Layer Statistics + * @mac_handle: Global MAC handle + * @get_stats_req: Link Layer get stats request params structure + * @context: Callback context + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ll_stats_get_req(mac_handle_t mac_handle, + tSirLLStatsGetReq *get_stats_req, + void *context); + +/** + * sme_radio_tx_mem_free() - SME API to free the ll_stats memory + * + * Return: None + */ +void sme_radio_tx_mem_free(void); + +/** + * sme_set_link_layer_stats_ind_cb() - + * SME API to trigger the stats are available after get request + * @mac_handle: MAC handle + * @callback: HDD callback which needs to be invoked after + * getting status notification from FW + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_link_layer_stats_ind_cb(mac_handle_t mac_handle, + link_layer_stats_cb callback); + +QDF_STATUS sme_set_link_layer_ext_cb(mac_handle_t mac_handle, + void (*ll_stats_ext_cb)(hdd_handle_t callback_ctx, + tSirLLStatsResults * rsp)); +QDF_STATUS sme_reset_link_layer_stats_ind_cb(mac_handle_t mac_handle); +QDF_STATUS sme_ll_stats_set_thresh(mac_handle_t mac_handle, + struct sir_ll_ext_stats_threshold *threshold); +#else /* WLAN_FEATURE_LINK_LAYER_STATS */ +static inline QDF_STATUS +sme_set_link_layer_ext_cb(mac_handle_t mac_handle, void (*ll_stats_ext_cb) + (hdd_handle_t callback_ctx, tSirLLStatsResults + *rsp)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +sme_set_link_layer_stats_ind_cb(mac_handle_t mac_handle, + link_layer_stats_cb callback) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +sme_reset_link_layer_stats_ind_cb(mac_handle_t mac_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +QDF_STATUS sme_set_wisa_params(mac_handle_t mac_handle, + struct sir_wisa_params *wisa_params); +QDF_STATUS sme_get_link_status(mac_handle_t mac_handle, + csr_link_status_callback callback, + void *context, uint8_t session_id); +QDF_STATUS sme_get_temperature(mac_handle_t mac_handle, + void *tempContext, + void (*pCallbackfn)(int temperature, + void *pContext)); + +/** + * sme_set_scanning_mac_oui() - SME API to set scanning mac oui + * @mac_handle: MAC Handle + * @scan_mac_oui: Scanning Mac Oui + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_scanning_mac_oui(mac_handle_t mac_handle, + struct scan_mac_oui *scan_mac_oui); + +#ifdef DHCP_SERVER_OFFLOAD +/** + * sme_set_dhcp_srv_offload() - Set DHCP server offload + * @mac_handle: Handle to the global MAC context + * @dhcp_srv_info : DHCP server offload info struct + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_dhcp_srv_offload(mac_handle_t mac_handle, + struct dhcp_offload_info_params *dhcp_srv_info); +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +QDF_STATUS sme_set_led_flashing(mac_handle_t mac_handle, uint8_t type, + uint32_t x0, uint32_t x1); +#endif +QDF_STATUS sme_enable_dfs_chan_scan(mac_handle_t mac_handle, uint8_t dfs_flag); +QDF_STATUS sme_set_mas(uint32_t val); +QDF_STATUS sme_set_miracast(mac_handle_t mac_handle, uint8_t filter_type); +QDF_STATUS sme_ext_change_freq(mac_handle_t mac_handle, qdf_freq_t freq, + uint8_t session_id); + +QDF_STATUS sme_configure_stats_avg_factor(mac_handle_t mac_handle, + uint8_t session_id, + uint16_t stats_avg_factor); + +QDF_STATUS sme_configure_guard_time(mac_handle_t mac_handle, uint8_t session_id, + uint32_t guard_time); + +QDF_STATUS sme_wifi_start_logger(mac_handle_t mac_handle, + struct sir_wifi_start_log start_log); + +/** + * sme_is_any_session_in_middle_of_roaming() - check if roaming is in progress + * @mac_handle: MAC Handle + * + * Checks if any SME session is in middle of roaming + * + * Return: true if roaming is in progress else false + */ +bool sme_is_any_session_in_middle_of_roaming(mac_handle_t mac_handle); + +/** + * sme_send_flush_logs_cmd_to_fw() - Initiate command to FW to flush logs + * + * This function will initiate a command to firmware to flush their logs. + * This should normally be done in response to an anomaly detected by the + * host. + * + * Return: QDF_STATUS_SUCCESS if the command was sent, otherwise an + * appropriate QDF_STATUS error + */ +QDF_STATUS sme_send_flush_logs_cmd_to_fw(void); + +/** + * sme_enable_uapsd_for_ac() - enable uapsd for access category request to WMA + * @ac: access category + * @tid: tid value + * @pri: user priority + * @srvc_int: service interval + * @sus_int: suspend interval + * @dir: tspec direction + * @psb: PSB value + * @sessionId: session id + * @delay_interval: delay interval + * + * Return: QDF status + */ +QDF_STATUS sme_enable_uapsd_for_ac(sme_ac_enum_type ac, uint8_t tid, + uint8_t pri, uint32_t srvc_int, + uint32_t sus_int, + enum sme_qos_wmm_dir_type dir, + uint8_t psb, uint32_t sessionId, + uint32_t delay_interval); + +/** + * sme_disable_uapsd_for_ac() - disable uapsd access category request to WMA + * @ac: access category + * @sessionId: session id + * + * Return: QDF status + */ +QDF_STATUS sme_disable_uapsd_for_ac(sme_ac_enum_type ac, uint32_t sessionId); + +#ifdef FEATURE_RSSI_MONITOR +QDF_STATUS sme_set_rssi_monitoring(mac_handle_t mac_handle, + struct rssi_monitor_param *input); + +/** + * sme_set_rssi_threshold_breached_cb() - Set RSSI threshold breached callback + * @mac_handle: global MAC handle + * @cb: callback function pointer + * + * This function registers the RSSI threshold breached callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, + rssi_threshold_breached_cb cb); +#else /* FEATURE_RSSI_MONITOR */ +static inline +QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, + rssi_threshold_breached_cb cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif +/** + * sme_reset_rssi_threshold_breached_cb() - Reset RSSI threshold breached + * callback + * @mac_handle: global MAC handle + * + * This function de-registers the RSSI threshold breached callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_reset_rssi_threshold_breached_cb(mac_handle_t mac_handle); + +QDF_STATUS sme_register_mgmt_frame_ind_callback(mac_handle_t mac_handle, + sir_mgmt_frame_ind_callback callback); + +QDF_STATUS sme_update_nss(mac_handle_t mac_handle, uint8_t nss); +void sme_update_user_configured_nss(mac_handle_t mac_handle, uint8_t nss); + +bool sme_is_any_session_in_connected_state(mac_handle_t mac_handle); + +QDF_STATUS sme_pdev_set_hw_mode(struct policy_mgr_hw_mode msg); + +/** + * sme_nss_update_request() - Send beacon template update to FW with new + * nss value + * @mac_handle: Handle returned by macOpen + * @vdev_id: the session id + * @new_nss: the new nss value + * @ch_width: channel width, optional value + * @cback: hdd callback + * @next_action: next action to happen at policy mgr after beacon update + * @original_vdev_id: original request hwmode change vdev id + * @request_id: request id + * + * Sends the command to CSR to send to PE + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_nss_update_request(uint32_t vdev_id, + uint8_t new_nss, uint8_t ch_width, + policy_mgr_nss_update_cback cback, + uint8_t next_action, + struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, + uint32_t request_id); + +/** + * sme_sap_update_ch_width() - Update SAP ch_width + * @psoc: Psoc object + * @vdev_id: the session id + * @ch_width: channel width to be updated + * @reason: Reason for ch_width update + * @conc_vdev_id: Concurrent connection vdev_id that is causing ch_width update + * @request_id: request id + * + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS +sme_sap_update_ch_width(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width ch_width, + enum policy_mgr_conn_update_reason reason, + uint8_t conc_vdev_id, uint32_t request_id); + +QDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + uint32_t vdev_id); +QDF_STATUS sme_soc_set_dual_mac_config(struct policy_mgr_dual_mac_config msg); +QDF_STATUS sme_soc_set_antenna_mode(mac_handle_t mac_handle, + struct sir_antenna_mode_param *msg); + +void sme_setdef_dot11mode(mac_handle_t mac_handle); + +/** + * sme_update_tx_bfee_supp() - sets the Tx Bfee support + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: Tx Bfee config value + * + * Return: 0 on success else err code + */ +int sme_update_tx_bfee_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_update_tx_bfee_nsts() - sets the Tx Bfee nsts + * @mac_handle: MAC handle + * @session_id: SME session id + * @usr_cfg_val: user config value + * @nsts_val: Tx Bfee nsts config value + * + * Return: 0 on success else err code + */ +int sme_update_tx_bfee_nsts(mac_handle_t mac_handle, uint8_t session_id, + uint8_t usr_cfg_val, uint8_t nsts_val); + +void wlan_sap_enable_phy_error_logs(mac_handle_t mac_handle, + uint32_t enable_log); +#ifdef WLAN_FEATURE_DSRC +int sme_ocb_gen_timing_advert_frame(mac_handle_t mac_handle, + tSirMacAddr self_addr, + uint8_t **buf, uint32_t *timestamp_offset, + uint32_t *time_value_offset); + +#else +static inline +int sme_ocb_gen_timing_advert_frame(mac_handle_t mac_handle, + tSirMacAddr self_addr, uint8_t **buf, + uint32_t *timestamp_offset, + uint32_t *time_value_offset) +{ + return 0; +} + +#endif + +void sme_add_set_thermal_level_callback(mac_handle_t mac_handle, + sme_set_thermal_level_callback callback); + +void sme_update_tgt_services(mac_handle_t mac_handle, + struct wma_tgt_services *cfg); + +bool sme_validate_sap_channel_switch(mac_handle_t mac_handle, + uint32_t sap_ch_freq, eCsrPhyMode sap_phy_mode, + uint8_t cc_switch_mode, + uint8_t vdev_id); + +bool sme_is_session_id_valid(mac_handle_t mac_handle, uint32_t session_id); + +#ifdef FEATURE_WLAN_TDLS +void sme_get_opclass(mac_handle_t mac_handle, uint8_t channel, + uint8_t bw_offset, uint8_t *opclass); +#else +static inline void +sme_get_opclass(mac_handle_t mac_handle, uint8_t channel, uint8_t bw_offset, + uint8_t *opclass) +{ +} +#endif + +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS sme_gateway_param_update(mac_handle_t mac_handle, + struct gateway_update_req_param *request); +#endif + +void sme_update_fine_time_measurement_capab(mac_handle_t mac_handle, + uint8_t session_id, + uint32_t val); +QDF_STATUS sme_ht40_stop_obss_scan(mac_handle_t mac_handle, uint32_t vdev_id); +QDF_STATUS sme_set_fw_test(struct set_fwtest_params *fw_test); +QDF_STATUS sme_set_tsfcb(mac_handle_t mac_handle, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx); + +QDF_STATUS sme_reset_tsfcb(mac_handle_t mac_handle); + +#if defined(WLAN_FEATURE_TSF) && !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) +QDF_STATUS sme_set_tsf_gpio(mac_handle_t mac_handle, uint32_t pinvalue); +#endif + +#ifdef WLAN_BCN_RECV_FEATURE +/** + * sme_handle_bcn_recv_start() - Enable fw to start sending + * beacons of the current connected AP + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: SME session id + * @nth_value: Beacon report period + * @do_not_resume: beacon reporting resume after a pause is completed + * + * This function remove beacon filter. It allow fw to send + * all beacons from connected peer to driver. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, + uint32_t vdev_id, + uint32_t nth_value, + bool do_not_resume); + +/** + * sme_is_beacon_report_started() - Check bcn recv started + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * + * This function is to check beacon report started or not. + * + * Return: true on success + */ +bool sme_is_beacon_report_started(mac_handle_t mac_handle, + uint32_t session_id); + +/** + * sme_is_beacon_reporting_do_not_resume() - Check auto resume allowed or not + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * + * This function is to check auto resume of beacon reporting is allowed or not. + * + * Return: true on success + */ +bool sme_is_beacon_reporting_do_not_resume(mac_handle_t mac_handle, + uint32_t session_id); + +/** + * stop_beacon_report() - To stop beacon report + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * + * Return: None + */ +void sme_stop_beacon_report(mac_handle_t mac_handle, + uint32_t session_id); + +#else +static inline +bool sme_is_beacon_report_started(mac_handle_t mac_handle, + uint32_t session_id) +{ + return true; +} + +static inline +bool sme_is_beacon_reporting_do_not_resume(mac_handle_t mac_handle, + uint32_t session_id) +{ + return false; +} + +static inline +void sme_stop_beacon_report(mac_handle_t mac_handle, + uint32_t session_id) +{ +} + +#endif + +QDF_STATUS sme_add_beacon_filter(mac_handle_t mac_handle, + uint32_t session_id, uint32_t *ie_map); +QDF_STATUS sme_remove_beacon_filter(mac_handle_t mac_handle, + uint32_t session_id); + +#ifdef FEATURE_WLAN_APF +/** + * sme_get_apf_capabilities() - Get APF capabilities + * @mac_handle: Opaque handle to the global MAC context + * @callback: Callback function to be called with the result + * @context: Opaque context to be used by the caller to associate the + * request with the response + * + * This function constructs the cds message and fill in message type, + * post the same to WDA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_get_apf_capabilities(mac_handle_t mac_handle, + apf_get_offload_cb callback, + void *context); + +/** + * sme_set_apf_instructions() - Set APF apf filter instructions. + * @mac_handle: Opaque handle to the global MAC context + * @apf_set_offload: struct to set apf filter instructions. + * + * APFv2 (Legacy APF) API to set the APF packet filter. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_apf_instructions(mac_handle_t mac_handle, + struct sir_apf_set_offload + *apf_set_offload); + +/** + * sme_set_apf_enable_disable - Send apf enable/disable cmd + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * @apf_enable: true: Enable APF Int., false: Disable APF Int. + * + * API to either enable or disable the APF interpreter. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_apf_enable_disable(mac_handle_t mac_handle, uint8_t vdev_id, + bool apf_enable); + +/** + * sme_apf_write_work_memory - Write into the apf work memory + * @mac_handle: Opaque handle to the global MAC context + * @write_params: APF parameters for the write operation + * + * API for writing into the APF work memory. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_apf_write_work_memory(mac_handle_t mac_handle, + struct wmi_apf_write_memory_params + *write_params); + +/** + * sme_apf_read_work_memory - Read part of apf work memory + * @mac_handle: Opaque handle to the global MAC context + * @read_params: APF parameters for the get operation + * @callback: callback to handle the the read response + * + * API for issuing a APF read memory request. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS +sme_apf_read_work_memory(mac_handle_t mac_handle, + struct wmi_apf_read_memory_params *read_params, + apf_read_mem_cb callback); + +#endif /* FEATURE_WLAN_APF */ + +uint32_t sme_get_wni_dot11_mode(mac_handle_t mac_handle); +QDF_STATUS sme_create_mon_session(mac_handle_t mac_handle, uint8_t *bssid, + uint8_t vdev_id); + +/** + * sme_delete_mon_session() - post message to delete PE session for mon_mode + * operation + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: sme session id + * + * Return: QDF_STATUS_SUCCESS on success, non-zero error code on failure. + */ +QDF_STATUS sme_delete_mon_session(mac_handle_t mac_handle, uint8_t vdev_id); + +/** + * sme_set_vdev_ies_per_band() - sends the per band IEs to vdev + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev_id for which IE is targeted + * @device_mode: vdev mode + * + * Return: None + */ +void sme_set_vdev_ies_per_band(mac_handle_t mac_handle, uint8_t vdev_id, + enum QDF_OPMODE device_mode); + +void sme_set_pdev_ht_vht_ies(mac_handle_t mac_handle, bool enable2x2); + +/** + * sme_get_sap_vdev_type_nss() - get the sap nss per vdev type + * @mac_handle: Opaque handle to the global MAC context + * @vdev_nss: Pointer to vdev_nss + * @band: 5G or 2.4G band + * + * Get SAP vdev nss + * + * Return: None + */ +void sme_get_sap_vdev_type_nss(mac_handle_t mac_handle, uint8_t *vdev_nss, + enum band_info band); + +/** + * sme_update_vdev_type_nss() - sets the nss per vdev type + * @mac_handle: Opaque handle to the global MAC context + * @max_supp_nss: max_supported Nss + * @band: 5G or 2.4G band + * + * Sets the per band Nss for each vdev type based on INI and configured + * chain mask value. + * + * Return: None + */ +void sme_update_vdev_type_nss(mac_handle_t mac_handle, uint8_t max_supp_nss, + enum nss_chains_band_info band); + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +void sme_register_p2p_lo_event(mac_handle_t mac_handle, void *context, + p2p_lo_callback callback); +#else +static inline void sme_register_p2p_lo_event(mac_handle_t mac_handle, + void *context, + p2p_lo_callback callback) +{ +} +#endif + +QDF_STATUS sme_process_mac_pwr_dbg_cmd(mac_handle_t mac_handle, + uint32_t session_id, + struct sir_mac_pwr_dbg_cmd* + dbg_args); + +void sme_get_vdev_type_nss(enum QDF_OPMODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g); +void sme_send_disassoc_req_frame(mac_handle_t mac_handle, + uint8_t session_id, uint8_t *peer_mac, + uint16_t reason, uint8_t wait_for_ack); +QDF_STATUS sme_update_access_policy_vendor_ie(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t *vendor_ie, + int access_policy); + +/** + * sme_set_peer_param() - set peer param + * @vdev_id: vdev ID + * @peer_addr: peer MAC address + * @param_id: param ID to be updated + * @param_Value: paraam value + * + * This SME API is used to send the peer param to WMA to be sent to FW. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_peer_param(uint8_t *peer_addr, uint32_t param_id, + uint32_t param_value, uint32_t vdev_id); + +QDF_STATUS sme_update_sta_roam_policy(mac_handle_t mac_handle, + enum sta_roam_policy_dfs_mode dfs_mode, + bool skip_unsafe_channels, + uint8_t session_id, uint8_t sap_operating_band); +QDF_STATUS sme_enable_disable_chanavoidind_event(mac_handle_t mac_handle, + uint8_t set_value); +QDF_STATUS sme_set_default_scan_ie(mac_handle_t mac_handle, uint16_t session_id, + uint8_t *ie_data, uint16_t ie_len); +/** + * sme_set_check_assoc_disallowed() - API to update assoc disallowed + * @mac_handle: Opaque handle to the global MAC context + * @check_assoc_disallowed: assoc disallowed check value + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_check_assoc_disallowed(mac_handle_t mac_handle, + bool check_assoc_disallowed); + +/** + * sme_update_session_param() - API to update PE session param + * @mac_handle: Opaque handle to the global MAC context + * @session_id: Session ID + * @param_type: Param type to be updated + * @param_val: Param value to be update + * + * Note: this setting will not persist over reboots. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_session_param(mac_handle_t mac_handle, uint8_t session_id, + uint32_t param_type, uint32_t param_val); +#ifdef WLAN_FEATURE_FIPS +/** + * sme_fips_request() - Perform a FIPS certification operation + * @mac_handle: Opaque handle to the global MAC context + * @param: The FIPS certification parameters + * @callback: Callback function to invoke with the results + * @context: Opaque context to pass back to caller in the callback + * + * Return: QDF_STATUS_SUCCESS if the request is successfully sent + * to firmware for processing, otherwise an error status. + */ +QDF_STATUS sme_fips_request(mac_handle_t mac_handle, struct fips_params *param, + wma_fips_cb callback, void *context); +#else +static inline +QDF_STATUS sme_fips_request(mac_handle_t mac_handle, struct fips_params *param, + wma_fips_cb callback, void *context) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_FIPS */ + +/** + * sme_set_cts2self_for_p2p_go() - sme function to set ini params to FW. + * @mac_handle: Opaque handle to the global MAC context + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_cts2self_for_p2p_go(mac_handle_t mac_handle); + +QDF_STATUS sme_update_tx_fail_cnt_threshold(mac_handle_t mac_handle, + uint8_t session_id, uint32_t tx_fail_count); + +/** + * sme_neighbor_roam_is11r_assoc() - Check if association type is 11R + * @mac_handle: MAC_HANDLE handle + * @session_id: session id + * + * Return: true if 11r Association, false otherwise. + */ +bool sme_neighbor_roam_is11r_assoc(mac_handle_t mac_handle, uint8_t session_id); + +/** + * sme_update_sta_inactivity_timeout(): Update sta_inactivity_timeout to FW + * @mac_handle: Handle returned by mac_open + * @sta_inactivity_timer: struct for sta inactivity timer + * + * If a station does not send anything in sta_inactivity_timeout seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. +*/ +QDF_STATUS sme_update_sta_inactivity_timeout(mac_handle_t mac_handle, + struct sme_sta_inactivity_timeout *sta_inactivity_timer); + +/** + * sme_set_lost_link_info_cb() - plug in callback function for receiving + * @mac_handle: Opaque handle to the MAC context + * @cb: callback function + * + * Return: HAL status + */ +QDF_STATUS sme_set_lost_link_info_cb(mac_handle_t mac_handle, + lost_link_info_cb cb); + +/** + * sme_update_new_channel_event() - update new channel event for sapFsm + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_update_new_channel_event(mac_handle_t mac_handle, + uint8_t session_id); +#ifdef WLAN_POWER_DEBUG +/** + * sme_reset_power_debug_stats_cb() - SME API to reset Power debug stats cb + * @mac_handle: Opaque handle to the global MAC context + * + * Resets the power stats callback and context to NULL + * + * Return: None + */ +void sme_reset_power_debug_stats_cb(mac_handle_t mac_handle); + +/** + * sme_power_debug_stats_req() - SME API to collect Power debug stats + * @mac_handle: Opaque handle to the global MAC context + * @callback_fn: Pointer to the callback function for Power stats event + * @power_stats_context: Pointer to context + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_power_debug_stats_req( + mac_handle_t mac_handle, + void (*callback_fn)(struct power_stats_response *response, + void *context), + void *power_stats_context); +#endif + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +/** + * sme_beacon_debug_stats_req() - SME API to collect beacon debug stats + * @vdev_id: Vdev id on which stats is being requested + * @callback_fn: Pointer to the callback function for beacon stats event + * @beacon_stats_context: Pointer to context + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_beacon_debug_stats_req( + mac_handle_t mac_handle, uint32_t vdev_id, + void (*callback_fn)(struct bcn_reception_stats_rsp + *response, void *context), + void *beacon_stats_context); +#endif + +/** + * sme_get_sar_power_limits() - get SAR limits + * @mac_handle: Opaque handle to the global MAC context + * @callback: Callback function to invoke with the results + * @context: Opaque context to pass back to caller in the callback + * + * Return: QDF_STATUS_SUCCESS if the request is successfully sent + * to firmware for processing, otherwise an error status. + */ +QDF_STATUS sme_get_sar_power_limits(mac_handle_t mac_handle, + wma_sar_cb callback, void *context); + +/** + * sme_set_sar_power_limits() - set sar limits + * @mac_handle: Opaque handle to the global MAC context + * @sar_limit_cmd: struct to send sar limit cmd. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_sar_power_limits(mac_handle_t mac_handle, + struct sar_limit_cmd_params *sar_limit_cmd); + +/** + * sme_send_coex_config_cmd() - Send COEX config params + * @coex_cfg_params: struct to coex config params + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_coex_config_cmd(struct coex_config_params *coex_cfg_params); + +#ifdef WLAN_FEATURE_WOW_PULSE +QDF_STATUS sme_set_wow_pulse(struct wow_pulse_mode *wow_pulse_set_info); +#endif + +/* ARP DEBUG STATS */ +QDF_STATUS sme_set_nud_debug_stats(mac_handle_t mac_handle, + struct set_arp_stats_params + *set_stats_param); +QDF_STATUS sme_get_nud_debug_stats(mac_handle_t mac_handle, + struct get_arp_stats_params + *get_stats_param); +QDF_STATUS sme_set_nud_debug_stats_cb(mac_handle_t mac_handle, + void (*cb)(void *, struct rsp_stats *, void *context), + void *context); + +/** + * sme_set_del_peers_ind_callback() - Register del peers ind callback + * @mac_handle - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback to mac + * + * Return: QDF_STATUS + */ +void +sme_set_del_peers_ind_callback(mac_handle_t mac_handle, + void (*callback)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id)); + +/** + * sme_set_chan_info_callback() - Register chan info callback + * @mac_handle - MAC global handle + * @callback_routine - callback routine from HDD + * + * This API is invoked by HDD to register its callback to mac + * + * Return: QDF_STATUS + */ +void sme_set_chan_info_callback(mac_handle_t mac_handle, + void (*callback)(struct scan_chan_info *chan_info)); + +#ifdef WLAN_FEATURE_CAL_FAILURE_TRIGGER +/** + * sme_set_cal_failure_event_cb() - Register calibration failure event callback + * @mac_handle - MAC global handle + * @callback - calibration failure event callback from HDD + * + * This API is invoked by HDD to register its callback to mac + * + * Return: None + */ +void sme_set_cal_failure_event_cb( + mac_handle_t mac_handle, + void (*callback)(uint8_t cal_type, uint8_t reason)); +#else +static inline void +sme_set_cal_failure_event_cb(mac_handle_t mac_handle, + void (*callback)(uint8_t cal_type, uint8_t reason)) +{ +} +#endif + +/** + * sme_get_rssi_snr_by_bssid() - gets the rssi and snr by bssid from scan cache + * @mac_handle: handle returned by mac_open + * @bssid: bssid to look for in scan cache + * @rssi: rssi value found + * @snr: snr value found + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_rssi_snr_by_bssid(mac_handle_t mac_handle, + const uint8_t *bssid, int8_t *rssi, + int8_t *snr); + +/** + * sme_register_tx_queue_cb(): Register tx queue callback + * @mac_handle: Opaque handle for MAC context + * @tx_queue_cb: Transmit Queues callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_register_tx_queue_cb(mac_handle_t mac_handle, + tx_queue_cb tx_queue_cb); + +/** + * sme_deregister_tx_queue_cb() - Deregister the tx queue callback + * @mac_handle: Opaque handle for MAC context + * + * Return: QDF status + */ +QDF_STATUS sme_deregister_tx_queue_cb(mac_handle_t mac_handle); + +/** + * sme_rso_cmd_status_cb() - Set RSO cmd status callback + * @mac_handle: Opaque handle for the MAC context + * @cb: HDD Callback to rso command status read + * + * This function is used to save HDD RSO Command status callback in MAC + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_rso_cmd_status_cb(mac_handle_t mac_handle, + rso_cmd_status_cb cb); + +/** + * sme_register_set_connection_info_cb() - Register connection + * info callback + * @mac_handle - MAC global handle + * @set_connection_info_cb - callback routine from HDD to set + * connection info flag + * @get_connection_info_cb - callback routine from HDD to get + * connection info + * + * This API is invoked by HDD to register its callback to mac + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_register_set_connection_info_cb(mac_handle_t mac_handle, + bool (*set_connection_info_cb)(bool), + bool (*get_connection_info_cb)(uint8_t *session_id, + enum scan_reject_states *reason)); + +/** + * sme_set_dbs_scan_selection_config() - Update DBS scan selection + * configuration + * @mac_handle: The handle returned by macOpen + * @params: wmi_dbs_scan_sel_params config + * + * Return: QDF_STATUS if DBS scan selection update + * configuration success else failure status + */ +QDF_STATUS sme_set_dbs_scan_selection_config(mac_handle_t mac_handle, + struct wmi_dbs_scan_sel_params *params); + +/** + * sme_store_pdev() - store pdev + * @mac_handle - MAC global handle + * @pdev - pdev ptr + * + * Return: QDF_STATUS + */ +void sme_store_pdev(mac_handle_t mac_handle, struct wlan_objmgr_pdev *pdev); + +/** + * sme_set_reorder_timeout() - set reorder timeout value + * including Voice,Video,Besteffort,Background parameters + * @mac_handle: Opaque handle to the global MAC context + * @reg: struct sir_set_rx_reorder_timeout_val + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_set_reorder_timeout(mac_handle_t mac_handle, + struct sir_set_rx_reorder_timeout_val *req); + +/** + * sme_set_rx_set_blocksize() - set blocksize value + * including mac_addr and win_limit parameters + * @mac_handle: Opaque handle to the global MAC context + * @reg: struct sir_peer_set_rx_blocksize + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ + +QDF_STATUS sme_set_rx_set_blocksize(mac_handle_t mac_handle, + struct sir_peer_set_rx_blocksize *req); + +/** + * sme_get_rcpi() - gets the rcpi value for peer mac addr + * @mac_handle: handle returned by mac_open + * @rcpi: rcpi request containing peer mac addr, callback and related info + * + * This function posts the rcpi measurement request message to wma queue + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_rcpi(mac_handle_t mac_handle, struct sme_rcpi_req *rcpi); + +/** + * sme_set_chip_pwr_save_fail_cb() - set chip power save failure callback + * @mac_handle: opaque handle to the MAC context + * @cb: callback function pointer + * + * This function stores the chip power save failure callback function. + * + * Return: QDF_STATUS enumeration. + */ + +QDF_STATUS sme_set_chip_pwr_save_fail_cb(mac_handle_t mac_handle, + pwr_save_fail_cb cb); +/** + * sme_cli_set_command() - SME wrapper API over WMA "set" command + * processor cmd + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval: parameter value + * @vpdev: parameter category + * + * Command handler for set operations + * + * Return: 0 on success, errno on failure + */ +int sme_cli_set_command(int vdev_id, int param_id, int sval, int vpdev); + +/** + * sme_set_bt_activity_info_cb - set the callback handler for bt events + * @mac_handle: handle returned by mac_open + * @cb: callback handler + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_bt_activity_info_cb(mac_handle_t mac_handle, + bt_activity_info_cb cb); + +/** + * sme_set_enable_mem_deep_sleep - set the mem deep sleep config to FW + * @mac_handle: handle returned by mac_open + * @vdev_id: vdev id + * + * Return: 0 for success else failure code + */ +int sme_set_enable_mem_deep_sleep(mac_handle_t mac_handle, int vdev_id); + +/** + * sme_set_cck_tx_fir_override - set the CCK TX FIR Override to FW + * @mac_handle: handle returned by mac_open + * @vdev_id: vdev id + * + * Return: 0 for success else failure code + */ +int sme_set_cck_tx_fir_override(mac_handle_t mac_handle, int vdev_id); + +/** + * sme_set_smps_cfg() - set SMPS config params + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @param_val: parameter value + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ + +QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id, + uint32_t param_val); + +/** + * sme_get_chain_rssi() - Get chain rssi + * @mac_handle: Opaque handle to the global MAC context + * @input: get chain rssi req params + * @callback: Callback function to be called with the result + * @context: Opaque context to be used by the caller to associate the + * request with the response + * + * This function constructs the cds message and fill in message type, + * post the same to WDA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_get_chain_rssi(mac_handle_t mac_handle, + struct get_chain_rssi_req_params *input, + get_chain_rssi_callback callback, + void *context); + +/** + * sme_get_isolation() - sme api to get antenna isolation + * @mac_handle: hal handle for getting global mac struct + * @context: context of callback function + * @callbackfn: hdd callback function when receive response + * + * This function will send WMA_GET_ISOLATION to WMA + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_get_isolation(mac_handle_t mac_handle, + void *context, + sme_get_isolation_cb callbackfn); + +#ifdef FEATURE_FW_STATE +/** + * sme_get_fw_state() - Get fw state + * @mac_handle: Opaque handle to the global MAC context + * @callback: Callback function to be called with the result + * @context: Opaque context to be used by the caller to associate the + * request with the response + * + * This function constructs the cds message and fill in message type, + * post the same to WDA. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_get_fw_state(mac_handle_t mac_handle, + fw_state_callback callback, + void *context); +#endif /* FEATURE_FW_STATE */ + +/** + * sme_get_mac_context() - sme api to get the pmac context + * + * This function will return the pmac context + * + * Return: pointer to pmac context + */ +struct mac_context *sme_get_mac_context(void); + +/** + * sme_display_disconnect_stats() - Display per session Disconnect stats + * @mac_handle: Opaque handle to the global MAC context + * session_id: SME session id + * + * Return: None + */ +void sme_display_disconnect_stats(mac_handle_t mac_handle, uint8_t session_id); + +#ifdef WLAN_FEATURE_MSCS +/** + * sme_send_mscs_action_frame() - Send MSCS action frame + * @vdev_id: sme vdev_id + * + * This function is used to send down the mscs request to PE + * + * Return: None + */ +void sme_send_mscs_action_frame(uint8_t vdev_id); +#endif + +/** + * sme_process_msg_callback() - process callback message from LIM + * @mac: global mac context + * @msg: scheduler message + * + * This function process the callback messages from LIM. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_process_msg_callback(struct mac_context *mac, + struct scheduler_msg *msg); + +/** + * sme_set_bmiss_bcnt() - set bmiss config parameters + * @vdev_id: virtual device for the command + * @first_cnt: bmiss first value + * @final_cnt: bmiss final value + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_set_bmiss_bcnt(uint32_t vdev_id, uint32_t first_cnt, + uint32_t final_cnt); + +/** + * sme_send_limit_off_channel_params() - send limit off channel parameters + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * @is_tos_active: tos active or inactive + * @max_off_chan_time: max off channel time + * @rest_time: rest time + * @skip_dfs_chan: skip dfs channel + * + * This function sends command to WMA for setting limit off channel command + * parameters. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_send_limit_off_channel_params(mac_handle_t mac_handle, + uint8_t vdev_id, + bool is_tos_active, + uint32_t max_off_chan_time, + uint32_t rest_time, + bool skip_dfs_chan); + +#ifdef FEATURE_WLAN_DYNAMIC_CVM +/** + * sme_set_vc_mode_config() - Set voltage corner config to FW. + * @bitmap: Bitmap that refers to voltage corner config with + * different phymode and bw configuration + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_vc_mode_config(uint32_t vc_bitmap); +#endif + +/** + * sme_set_del_pmkid_cache() - API to update PMKID cache + * @psoc: psoc common object + * @session_id: Session id + * @pmk_cache_info: Pointer to PMK cache info + * @is_add: boolean that implies whether to add or delete PMKID entry + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_del_pmkid_cache(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache_info, + bool is_add); + +/** + * sme_clear_sae_single_pmk_info() - Clear sae_single_pmk onfo + * @psoc: Psoc object + * @session_id: session id + * @pmk_cache_info: pmk cache info + * + * This function will clear sae_single_pmk info while processing delete pmk + * command from userspace. + * + * Return: None + */ +void sme_clear_sae_single_pmk_info(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache_info); + +/** + * sme_send_hlp_ie_info() - API to send HLP IE info to fw + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * @if_addr: IP address + * + * This API is used to send HLP IE info along with IP address + * to fw if LFR3 is enabled. + * + * Return: None + */ +void sme_send_hlp_ie_info(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t if_addr); + +/** + * sme_send_rso_connect_params() - Updates the assoc IEs to csr_roam_session + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * + * When the user space updates the assoc IEs or FILS auth type or FILS ERP info, + * host driver needs to send these updated parameters to firmware via + * RSO update command. + * + * Return: None + */ +QDF_STATUS sme_send_rso_connect_params(mac_handle_t mac_handle, + uint8_t vdev_id); + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * sme_set_he_bss_color() - Sets the HE BSS color + * + * @mac_handle: The handle returned by mac_open + * @session_id: session_id of the request + * @bss_color: HE BSS color value to set + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_he_bss_color(mac_handle_t mac_handle, uint8_t session_id, + uint8_t bss_color); +/** + * sme_reconfig_obss_scan_param() - reconfig obss scan param + * + * @mac_handle: The handle returned by mac_open + * @session_id: session_id of the request + * @is_scan_reconfig: true if modify OBSS scan periodicity, otherwise false + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_reconfig_obss_scan_param(mac_handle_t mac_handle, + uint8_t session_id, + bool is_scan_reconfig); +#else +static inline +QDF_STATUS sme_set_he_bss_color(mac_handle_t mac_handle, uint8_t session_id, + uint8_t bss_color) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS sme_reconfig_obss_scan_param(mac_handle_t mac_handle, + uint8_t session_id, + bool is_scan_reconfig) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_is_conn_state_connected() -- check if SME connection state is connected + * @mac_handle: Opaque handle to the global MAC context + * @session_id: current Session Id + * + * This API checks if the current SME connection state is connected for the + * given session id. + * + * Return: True if connected, false if any other state. + */ +bool sme_is_conn_state_connected(mac_handle_t mac_handle, uint8_t session_id); + +/** + * sme_get_bss_transition_status() - get bss transition status all candidates + * @mac_handle: handle returned by mac_open + * @transition_reason : Transition reason + * @bssid: bssid to get BSS transition status + * @info : bss candidate information + * @n_candidates : number of candidates + * @is_bt_in_progress: bt activity indicator + * + * Return: QDF_STATUS_SUCCESS on success otherwise a QDF_STATUS error + */ +QDF_STATUS sme_get_bss_transition_status(mac_handle_t mac_handle, + uint8_t transition_reason, + struct qdf_mac_addr *bssid, + struct bss_candidate_info *info, + uint16_t n_candidates, + bool is_bt_in_progress); + +/** + * sme_unpack_rsn_ie: wrapper to unpack RSN IE and update def RSN params + * if optional fields are not present. + * @mac_handle: handle returned by mac_open + * @buf: rsn ie buffer pointer + * @buf_len: rsn ie buffer length + * @rsn_ie: outframe rsn ie structure + * @append_ie: flag to indicate if the rsn_ie need to be appended from buf + * + * Return: parse status + */ +uint32_t sme_unpack_rsn_ie(mac_handle_t mac_handle, uint8_t *buf, + uint8_t buf_len, tDot11fIERSN *rsn_ie, + bool append_ie); + +/** + * sme_unpack_assoc_rsp() - wrapper to unpack assoc response + * @mac_handle: handle returned by mac_open + * @rsp: Pointer to connect rsp + * @assoc_resp: output assoc response structure + * + * Return: parse status + */ +QDF_STATUS sme_unpack_assoc_rsp(mac_handle_t mac_handle, + struct wlan_cm_connect_resp *rsp, + struct sDot11fAssocResponse *assoc_resp); + +/** + * sme_get_hs20vendor_ie() - wrapper to unpack beacon/probe response + * @mac_handle: handle returned by mac_open + * @frame: beacon/probe response response buffer pointer + * @frame_len: beacone probe/ response buffer length + * @hs20vendor_ie: output hs20vendor_ie structure + * + * Return: None + */ +void sme_get_hs20vendor_ie(mac_handle_t mac_handle, uint8_t *frame, + uint32_t frame_len, + tDot11fIEhs20vendor_ie *hs20vendor_ie); + +/** + * sme_add_qcn_ie: Adds QCN IE data to IE buffer + * @mac_handle: handle returned by mac_open + * @ie_data: ie buffer pointer + * @ie_len: ie length pointer + * + * Return: none + */ +void sme_add_qcn_ie(mac_handle_t mac_handle, uint8_t *ie_data, + uint16_t *ie_len); + +/** + * sme_get_oper_chan_freq - gets the operating channel freq + * @vdev: vdev handle + * + * Return: operating channel frequency + */ +int16_t sme_get_oper_chan_freq(struct wlan_objmgr_vdev *vdev); + +/** + * sme_get_oper_ch_width - gets the operating channel width + * @vdev: vdev handle + * + * Return: operating channel width + */ +enum phy_ch_width sme_get_oper_ch_width(struct wlan_objmgr_vdev *vdev); + +/** + * sme_get_oper_ch_width - gets the secondary channel frequency + * @vdev: vdev handle + * @sec20chan_freq: secondary channel frequency + * + * Return: secondary channel frequency + */ +int sme_get_sec20chan_freq_mhz(struct wlan_objmgr_vdev *vdev, + uint16_t *sec20chan_freq); + +/** + * sme_send_mgmt_tx() - Sends mgmt frame from CSR to LIM + * @mac_handle: The handle returned by mac_open + * @session_id: session id + * @buf: pointer to frame + * @len: frame length + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_mgmt_tx(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *buf, uint32_t len); + +#ifdef WLAN_FEATURE_SAE +/** + * sme_handle_sae_msg() - Sends SAE message received from supplicant + * @mac_handle: The handle returned by mac_open + * @session_id: session id + * @sae_status: status of SAE authentication + * @peer_mac_addr: mac address of the peer to be authenticated + * @pmkid: PMKID derived at the end of SAE authentication + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_handle_sae_msg(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t sae_status, + struct qdf_mac_addr peer_mac_addr, + const uint8_t *pmkid); +#else +static inline +QDF_STATUS sme_handle_sae_msg(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t sae_status, + struct qdf_mac_addr peer_mac_addr, + const uint8_t *pmkid) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_set_ba_buff_size() - sets BA buffer size + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @buff_size: BA buffer size + * + * Return: 0 on success else err code + */ +int sme_set_ba_buff_size(mac_handle_t mac_handle, uint8_t session_id, + uint16_t buff_size); + +/** + * sme_send_addba_req() - send ADDBA request with user config + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @tid: tid val for BA session + * @buff_size: BA buffer size + * + * Return: 0 on success else err code + */ +int sme_send_addba_req(mac_handle_t mac_handle, uint8_t session_id, uint8_t tid, + uint16_t buff_size); + +/** + * sme_set_no_ack_policy() - Sets no ack policy for AC + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @val: no ack policy value + * @ac: access category + * + * Return: 0 on success else err code + */ +int sme_set_no_ack_policy(mac_handle_t mac_handle, uint8_t session_id, + uint8_t val, uint8_t ac); + +/** + * sme_set_auto_rate_he_sgi() - Sets SGI for auto rate + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: SGI configuration value + * + * Return: 0 on success else err code + */ +int sme_set_auto_rate_he_sgi(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_set_auto_rate_ldpc() - Sets LDPC for auto rate + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @ldpc_disable: LDPC configuration value + * + * Return: 0 on success else err code + */ +int sme_set_auto_rate_ldpc(mac_handle_t mac_handle, uint8_t session_id, + uint8_t ldpc_disable); + +/** + * sme_set_auto_rate_he_ltf() - Sets HE LTF for auto rate + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: LTF configuration value + * + * Return: 0 on success else err code + */ +int sme_set_auto_rate_he_ltf(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +#ifdef WLAN_FEATURE_11BE +/** + * sme_update_tgt_eht_cap() - sets the EHT caps to pmac + * @mac_handle: Pointer to MAC handle + * @cfg: Pointer to WMA target CFG + * @eht_cap_ini: Pointer to EHT CAP configured by INI + * + * Return: None + */ +void sme_update_tgt_eht_cap(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg, + tDot11fIEeht_cap *eht_cap_ini); + +/** + * sme_update_eht_cap_nss() - sets the nss based on user request + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @nss: no.of spatial streams value + * + * Return: None + */ +void sme_update_eht_cap_nss(mac_handle_t mac_handle, uint8_t session_id, + uint8_t nss); + +/** + * sme_set_eht_bw_cap() - sets the EHT 320 MHz bandwidth capability + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * @chwidth: channel width + * + * Return: None + */ +void sme_set_eht_bw_cap(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelWidth chwidth); + +/** + * sme_update_eht_cap_mcs() - updates EHT MCS capability based on user request + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @mcs: MCS value + * + * Return: None + */ +void sme_update_eht_cap_mcs(mac_handle_t mac_handle, uint8_t session_id, + uint8_t mcs); + +/** + * sme_update_eht_om_ctrl_supp() - sets the EHT OM control capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: EHT OM control config + * + * Return: 0 on success else err code + */ +int sme_update_eht_om_ctrl_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); +#else +static inline void sme_update_tgt_eht_cap(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg, + tDot11fIEeht_cap *eht_cap_ini) +{} + +static inline void sme_update_eht_cap_nss(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t nss) +{} + +static inline void sme_set_eht_bw_cap(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelWidth chwidth) +{} +static inline void sme_update_eht_cap_mcs(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t mcs) +{} + +static inline +int sme_update_eht_om_ctrl_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} +#endif + +struct omi_ctrl_tx { + uint32_t omi_in_vht:1; + uint32_t omi_in_he:1; + uint32_t a_ctrl_id:4; + uint32_t rx_nss:3; + uint32_t ch_bw:2; + uint32_t ul_mu_dis:1; + uint32_t tx_nsts:3; + uint32_t er_su_dis:1; + uint32_t dl_mu_mimo_resound:1; + uint32_t ul_mu_data_dis:1; + uint32_t eht_rx_nss_ext:1; + uint32_t eht_ch_bw_ext:1; + uint32_t eht_tx_nss_ext:1; + uint32_t reserved:11; +}; + +#ifdef WLAN_FEATURE_11AX +/** + * sme_update_tgt_he_cap() - sets the HE caps to pmac + * @mac_handle: Pointer to MAC handle + * @cfg: Pointer to WMA target CFG + * @he_cap_ini: Pointer to HE CAP configured by INI + * + * Return: None + */ +void sme_update_tgt_he_cap(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg, + tDot11fIEhe_cap *he_cap_ini); + +/** + * sme_update_he_cap_nss() - sets the nss based on user request + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @nss: no.of spatial streams value + * + * Return: None + */ +void sme_update_he_cap_nss(mac_handle_t mac_handle, uint8_t session_id, + uint8_t nss); + +/** + * sme_update_he_tx_bfee_supp() - sets the HE Tx Bfee support + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: Tx Bfee config value + * + * Return: 0 on success else err code + */ +int sme_update_he_tx_bfee_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_update_he_tx_bfee_nsts() - sets the HE Tx Bfee NSTS + * @mac_handle: MAC handle + * @session_id: SME session id + * @cfg_val: Tx Bfee NSTS value + * + * Return: 0 on success else err code + */ +int sme_update_he_tx_bfee_nsts(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_set_he_tx_bf_cbf_rates() - sets the HE Tx Bfee CBF frame rates to FW + * @session_id: SME session id + * + * Return: None + */ +void sme_set_he_tx_bf_cbf_rates(uint8_t session_id); + +/** + * sme_config_su_ppdu_queue() - Configures SU PPDU queue enable/disable in FW + * @session_id: SME session id + * @enable: Enable/Disable config + * + * Return: None + */ +void sme_config_su_ppdu_queue(uint8_t session_id, bool enable); + +/** + * sme_update_he_mcs() - sets the HE MCS based on user request + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @he_mcs: HE MCS value + * + * Return: 0 on success else err code + */ +int sme_update_he_mcs(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_mcs); + +/** + * sme_update_he_trigger_frm_mac_pad() - sets the HE MAC padding capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: HE MAC padding duration value + * + * Return: 0 on success else err code + */ +int sme_update_he_trigger_frm_mac_pad(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_update_he_om_ctrl_supp() - sets the HE OM control capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: HE OM control config + * + * Return: 0 on success else err code + */ +int sme_update_he_om_ctrl_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +#define A_CTRL_ID_OMI 0x1 + +void sme_reset_he_om_ctrl(mac_handle_t mac_handle); + +/** + * sme_config_action_tx_in_tb_ppdu() - Sends action frame in TB PPDU cfg to FW + * @mac_handle: Pointer to MAC handle + * @session_id: SME session id + * @cfg_val: configuration setting value + * + * Return: 0 on success else err code + */ +int sme_config_action_tx_in_tb_ppdu(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_send_he_om_ctrl_update() - Send HE OM ctrl Tx cmd to FW + * @mac_handle: Pointer to mac handle + * @session_id: SME session id + * @omi_data: OMI control data + * + * Return: 0 on success else err code + */ +int sme_send_he_om_ctrl_update(mac_handle_t mac_handle, uint8_t session_id, + struct omi_ctrl_tx *omi_data); + +/** + * sme_set_he_om_ctrl_param() - Update HE OM control params for OMI Tx + * @mac_handle: Pointer to mac handle + * @session_id: SME session id + * @param: HE om control parameter + * @cfg_val: HE OM control parameter config value + * + * Return: 0 on success else err code + */ +int sme_set_he_om_ctrl_param(mac_handle_t mac_handle, uint8_t session_id, + enum qca_wlan_vendor_attr_he_omi_tx param, + uint8_t cfg_val); + +/** + * sme_set_usr_cfg_mu_edca() - sets the user cfg MU EDCA params flag + * @mac_handle: Opaque handle to the global MAC context + * @val: value to be set + * + * Return: none + */ +void sme_set_usr_cfg_mu_edca(mac_handle_t mac_handle, bool val); + +/** + * sme_set_he_mu_edca_def_cfg() - sets the default MU EDCA params values + * @mac_handle: Opaque handle to the global MAC context + * + * Return: none + */ +void sme_set_he_mu_edca_def_cfg(mac_handle_t mac_handle); + +/** + * sme_update_he_htc_he_supp() - Update +HTC-HE support in HE capabilities + * @mac_handle: Pointer to mac handle + * @session_id: SME session id + * @cfg_val: config setting + * + * Return: 0 on success else err code + */ +int sme_update_he_htc_he_supp(mac_handle_t mac_handle, uint8_t session_id, + bool cfg_val); + +/** + * sme_update_mu_edca_params() - updates MU EDCA params values + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * + * Return: 0 on success else err code + */ +int sme_update_mu_edca_params(mac_handle_t mac_handle, uint8_t session_id); + +/** + * sme_update_he_tx_stbc_cap() - Sets the HE Tx STBC capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @value: set value + * + * Return: 0 on success else err code + */ +int sme_update_he_tx_stbc_cap(mac_handle_t mac_handle, uint8_t session_id, + int value); + +/** + * sme_update_he_rx_stbc_cap() - Sets the HE Rx STBC capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @value: set value + * + * Return: 0 on success else err code + */ +int sme_update_he_rx_stbc_cap(mac_handle_t mac_handle, uint8_t session_id, + int value); + +/** + * sme_update_he_frag_supp() - sets the HE fragmentation support + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @he_frag: HE fragmention support value + * + * Return: 0 on success else err code + */ +int sme_update_he_frag_supp(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_frag); + +/** + * sme_update_he_ldpc_supp() - sets the HE LDPC support + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @he_ldpc: HE LDPC support value + * + * Return: 0 on success else err code + */ +int sme_update_he_ldpc_supp(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_ldpc); + +/** + * sme_update_he_capabilities() - Update the session HE capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: set value + * @cfg_id: HE cap cfg id + * + * Return: 0 on success else err code + */ +int sme_update_he_capabilities(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val, uint8_t cfg_id); + +/** + * sme_update_he_twt_req_support() - Sets twt request capability + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: set value + * + * Return: 0 on success else err code + */ +int sme_update_he_twt_req_support(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_update_he_full_ul_mumimo() - Configure full bandwidth of ul mu-mimo + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @value: set value + * + * Return: 0 on success else err code + */ +int sme_update_he_full_ul_mumimo(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val); +#else +static inline void sme_update_tgt_he_cap(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg, + tDot11fIEhe_cap *he_cap_ini) +{} +static inline void sme_update_he_cap_nss(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t nss) +{} +static inline int sme_update_he_mcs(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_mcs) +{ + return 0; +} + +static inline void sme_set_he_mu_edca_def_cfg(mac_handle_t mac_handle) +{ +} + +static inline int sme_update_mu_edca_params(mac_handle_t mac_handle, + uint8_t session_id) +{ + return 0; +} + +static inline int sme_update_he_trigger_frm_mac_pad(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + +static inline int sme_update_he_om_ctrl_supp(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + + +static inline int +sme_set_he_om_ctrl_param(mac_handle_t mac_handle, uint8_t session_id, + enum qca_wlan_vendor_attr_he_omi_tx param, + uint8_t cfg_val) +{ + return 0; +} + +static inline void sme_reset_he_om_ctrl(mac_handle_t mac_handle) +{ +} + +static inline int sme_config_action_tx_in_tb_ppdu(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + +static inline int sme_update_he_htc_he_supp(mac_handle_t mac_handle, + uint8_t session_id, + bool cfg_val) +{ + return 0; +} + +static inline int +sme_send_he_om_ctrl_update(mac_handle_t mac_handle, uint8_t session_id, + struct omi_ctrl_tx *omi_data) +{ + return 0; +} +static inline void sme_set_usr_cfg_mu_edca(mac_handle_t mac_handle, bool val) +{ +} + +static inline int sme_update_he_tx_stbc_cap(mac_handle_t mac_handle, + uint8_t session_id, + int value) +{ + return 0; +} + +static inline int sme_update_he_rx_stbc_cap(mac_handle_t mac_handle, + uint8_t session_id, + int value) +{ + return 0; +} + +static inline int sme_update_he_frag_supp(mac_handle_t mac_handle, + uint8_t session_id, + uint16_t he_frag) +{ + return 0; +} + +static inline int sme_update_he_ldpc_supp(mac_handle_t mac_handle, + uint8_t session_id, + uint16_t he_ldpc) +{ + return 0; +} + +static inline int sme_update_he_tx_bfee_supp(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} +static inline int sme_update_he_tx_bfee_nsts(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + +static inline void sme_set_he_tx_bf_cbf_rates(uint8_t session_id) +{ +} + +static inline void sme_config_su_ppdu_queue(uint8_t session_id, bool enable) +{ +} + +static inline int sme_update_he_twt_req_support(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + +static inline int sme_update_he_capabilities(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val, + uint8_t cfg_id) +{ + return 0; +} + +static inline int sme_update_he_full_ul_mumimo(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + +#endif + +/** + * sme_update_session_txq_edca_params() - sets the configured + * internal EDCA params values + * + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * @txq_edca_params: edca parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_update_session_txq_edca_params(mac_handle_t mac_handle, uint8_t session_id, + tSirMacEdcaParamRecord *txq_edca_params); + +/** + * sme_is_sta_key_exchange_in_progress() - checks whether the STA/P2P client + * session has key exchange in progress + * + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * + * Return: true - if key exchange in progress + * false - if not in progress + */ +bool sme_is_sta_key_exchange_in_progress(mac_handle_t mac_handle, + uint8_t session_id); + +/* + * sme_validate_channel_list() - Validate the given channel list + * @mac_handle: Opaque handle to the global MAC context + * @chan_freq_list: Pointer to the channel list + * @num_channels: number of channels present in the chan_list + * + * Validates the given channel list with base channels in mac context + * + * Return: True if all channels in the list are valid, false otherwise + */ +bool sme_validate_channel_list(mac_handle_t mac_handle, + uint32_t *chan_freq_list, + uint8_t num_channels); + +/** + * sme_set_amsdu() - set amsdu enable/disable based on user cfg + * @mac_handle: Opaque handle to the global MAC context + * @enable: enable or disable + * + * Return: None + */ +void sme_set_amsdu(mac_handle_t mac_handle, bool enable); + +/** + * sme_set_pmf_wep_cfg() - set user cfg for PMF setting + * @mac_handle: Opaque handle to the global MAC context + * @pmf_wep_cfg: PMF configuration + * + * Return: None + */ +void sme_set_pmf_wep_cfg(mac_handle_t mac_handle, uint8_t pmf_wep_cfg); + +/** + * sme_set_cfg_disable_tx() - set user cfg to disable data and mgmt tx + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev id + * @val: configuration value + * + * Return: None + */ +void sme_set_cfg_disable_tx(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val); +/** + * sme_set_bss_max_idle_period() - Configure the bss max idle period + * @mac_handle: Opaque handle to the global MAC context + * @cfg_val: bss max idle period + * + * Return: None + */ +void sme_set_bss_max_idle_period(mac_handle_t mac_handle, uint16_t cfg_val); + +#ifdef WLAN_FEATURE_11AX +void sme_set_he_testbed_def(mac_handle_t mac_handle, uint8_t vdev_id); +void sme_reset_he_caps(mac_handle_t mac_handle, uint8_t vdev_id); +void sme_set_he_bw_cap(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelWidth chwidth); +/** + * sme_set_ru_242_tone_tx_cfg() - set ru 242 tone tx user cfg + * @mac_handle: Opaque handle to the global MAC context + * @cfg_val: enable or disable + * + * Return: None + */ +void sme_set_ru_242_tone_tx_cfg(mac_handle_t mac_handle, uint8_t cfg_val); + +/** + * sme_check_enable_ru_242_tx() - check usr cfg and enable ru 242 tone tx + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * + * Return: None + */ +void sme_check_enable_ru_242_tx(mac_handle_t mac_handle, uint8_t vdev_id); + +#else +static inline void sme_set_he_testbed_def(mac_handle_t mac_handle, + uint8_t vdev_id) +{ +} +static inline void sme_reset_he_caps(mac_handle_t mac_handle, uint8_t vdev_id) +{ +} + +static inline void sme_set_he_bw_cap(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelWidth chwidth) +{ +} +static inline void sme_check_enable_ru_242_tx(mac_handle_t mac_handle, + uint8_t vdev_id) +{ +} + +static inline void sme_set_ru_242_tone_tx_cfg(mac_handle_t mac_handle, + uint8_t cfg_val) +{ +} +#endif + +/** + * sme_set_nss_capability() - sets HE, EHT NSS capability based on user request + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * @nss: Number of spatial streams value + * @op_mode: Operation mode of the vdev + * + * Return: None + */ +void sme_set_nss_capability(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t nss, enum QDF_OPMODE op_mode); + +/** + * enum sme_eht_tx_bfee_cap_type - EHT TX Beamformee capability type + * @EHT_TX_BFEE_ENABLE: TX beamformee enable + * @EHT_TX_BFEE_SS_80MHZ: TX beamformee for 80 MHz + * @EHT_TX_BFEE_SS_160MHZ: TX beamformee for 160 MHz + * @EHT_TX_BFEE_SS_320MHZ: TX beamformee for 320 MHz + * @EHT_TX_BFEE_SOUNDING_FEEDBACK_RATELIMIT: TX beamformee sounding feedback + * ratelimit + */ +enum sme_eht_tx_bfee_cap_type { + EHT_TX_BFEE_ENABLE = 1, + EHT_TX_BFEE_SS_80MHZ = 2, + EHT_TX_BFEE_SS_160MHZ = 3, + EHT_TX_BFEE_SS_320MHZ = 4, + EHT_TX_BFEE_SOUNDING_FEEDBACK_RATELIMIT = 5, +}; + +#ifdef WLAN_FEATURE_11BE +/** + * sme_set_eht_testbed_def() - set eht testbed default + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * + * Return: None + */ +void sme_set_eht_testbed_def(mac_handle_t mac_handle, uint8_t vdev_id); + +/** + * sme_reset_eht_caps() - reset eht capabilities + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * + * Return: None + */ +void sme_reset_eht_caps(mac_handle_t mac_handle, uint8_t vdev_id); + +/** + * sme_set_mlo_max_links() - set mlo max links + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * @val: value to be set + * + * Return: None + */ +void sme_set_mlo_max_links(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val); + +/** + * sme_set_mlo_max_simultaneous_links() - set mlo max simultaneous links + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * @val: value to set + * + * Return: None + */ +void sme_set_mlo_max_simultaneous_links(mac_handle_t mac_handle, + uint8_t vdev_id, uint8_t val); + +/** + * sme_set_mlo_assoc_link_band() - set mlo assoc link band + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: VDEV id + * @val: value to be set + * + * Return: None + */ +void sme_set_mlo_assoc_link_band(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val); + +/** + * sme_activate_mlo_links() - Force active ML links based on user + * requested link mac address + * + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * @num_links: number of links to be forced active + * @active_link_addr: link mac address of (up to 2) links to be forced active + * + * Return: void + */ +void sme_activate_mlo_links(mac_handle_t mac_handle, uint8_t session_id, + uint8_t num_links, + struct qdf_mac_addr active_link_addr[2]); + +/** + * sme_update_eht_caps() - Update the session EHT caps + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: Set value + * @cap_type: EHT TX beamformee capability type + * @op_mode: Operation mode of the vdev + * + * Return: 0 on success otherwise error code + */ +int sme_update_eht_caps(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val, enum sme_eht_tx_bfee_cap_type cap_type, + enum QDF_OPMODE op_mode); +/** + * sme_send_vdev_pause_for_bcn_period() - Send vdev pause indication to FW + * @mac_handle: Opaque handle to the global MAC context + * @session_id: SME session id + * @cfg_val: Set vdev pause duration + * + * Return: 0 on success otherwise error code + */ +int sme_send_vdev_pause_for_bcn_period(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val); + +/** + * sme_set_per_link_ba_mode() - sets BA mode for each STA MLD link + * @mac_handle: Opaque handle to the global MAC context + * @val: BA mode + * + * Return: None + */ +void sme_set_per_link_ba_mode(mac_handle_t mac_handle, uint8_t val); +#else +static inline void sme_set_eht_testbed_def(mac_handle_t mac_handle, + uint8_t vdev_id) +{ +} + +static inline +void sme_reset_eht_caps(mac_handle_t mac_handle, uint8_t vdev_id) +{ +} + +static inline +void sme_set_mlo_max_links(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val) +{ +} + +static inline +void sme_set_mlo_assoc_link_band(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val) +{ +} + +static inline +void sme_set_mlo_max_simultaneous_links(mac_handle_t mac_handle, + uint8_t vdev_id, uint8_t val) +{ +} + +static inline +int sme_update_eht_caps(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val, enum sme_eht_tx_bfee_cap_type cap_type, + enum QDF_OPMODE op_mode) +{ + return 0; +} + +static inline +int sme_send_vdev_pause_for_bcn_period(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + return 0; +} + +static inline +void sme_activate_mlo_links(mac_handle_t mac_handle, uint8_t session_id, + uint8_t num_links, + struct qdf_mac_addr active_link_addr[2]) +{ +} + +static inline +void sme_set_per_link_ba_mode(mac_handle_t mac_handle, uint8_t val) +{} +#endif + +/** + * sme_get_mcs_idx() - gets mcs index + * @raw_rate: raw rate from fw + * @rate_flags: rate flags + * @is_he_mcs_12_13_supported: is he mcs12/13 supported + * @nss: number of nss + * @dcm: dcm will be calculated from rate + * @guard_interval: guard interval info from rate + * @mcs_rate_flags: mcs rate flag + * + * Return: return mcs index + */ +uint8_t sme_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags, + bool is_he_mcs_12_13_supported, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flags); + +#ifdef WLAN_SUPPORT_TWT + +/** + * sme_test_config_twt_terminate() - send TWT del dialog wmi command + * to firmware + * @params: TWT del dialog parameters + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS +sme_test_config_twt_terminate(struct wmi_twt_del_dialog_param *params); + +/** + * sme_test_config_twt_setup() - send TWT add dialog wmi command + * to firmware + * @params: TWT add dialog parameters + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS sme_test_config_twt_setup(struct wmi_twt_add_dialog_param *params); + +/** + * sme_clear_twt_complete_cb() - Initialize TWT callbacks + * @mac_handle: MAC handle + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS sme_clear_twt_complete_cb(mac_handle_t mac_handle); + +/** + * sme_register_twt_callbacks() - TWT enable registrar + * @mac_handle: MAC handle + * @twt_cb: TWT callbacks + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS sme_register_twt_callbacks(mac_handle_t mac_handle, + struct twt_callbacks *twt_cb); + +/** + * sme_add_dialog_cmd() - Register callback and send TWT add dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_add_dialog_cb: Function callback to handle add_dialog event + * @twt_params: TWT add dialog parameters + * @context: TWT context + * + * Return: QDF Status + */ +QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle, + twt_add_dialog_cb twt_add_dialog_cb, + struct wmi_twt_add_dialog_param *twt_params, + void *context); + +/** + * sme_del_dialog_cmd() - Register callback and send TWT del dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_del_dialog_cb: Function callback to handle del_dialog event + * @twt_params: TWT del dialog parameters + * @context: TWT context + * + * Return: QDF Status + */ +QDF_STATUS sme_del_dialog_cmd(mac_handle_t mac_handle, + twt_del_dialog_cb del_dialog_cb, + struct wmi_twt_del_dialog_param *twt_params, + void *context); + +/** + * sme_sap_del_dialog_cmd() - Register callback and send TWT del dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_del_dialog_cb: Function callback to handle del_dialog event + * @twt_params: TWT del dialog parameters + * + * Return: QDF Status + */ +QDF_STATUS sme_sap_del_dialog_cmd(mac_handle_t mac_handle, + twt_del_dialog_cb del_dialog_cb, + struct wmi_twt_del_dialog_param *twt_params); + +/** + * sme_pause_dialog_cmd() - Register callback and send TWT pause dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_params: TWT pause dialog parameters + * @context: TWT context + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS +sme_pause_dialog_cmd(mac_handle_t mac_handle, + struct wmi_twt_pause_dialog_cmd_param *twt_params, + void *context); + +/** + * sme_nudge_dialog_cmd() - Register callback and send TWT nudge dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_params: TWT nudge dialog parameters + * @context: TWT context + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS +sme_nudge_dialog_cmd(mac_handle_t mac_handle, + struct wmi_twt_nudge_dialog_cmd_param *twt_params, + void *context); + +/** + * sme_resume_dialog_cmd() - Register callback and send TWT resume dialog + * command to firmware + * @mac_handle: MAC handle + * @twt_params: TWT resume dialog parameters + * @context: TWT context + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +QDF_STATUS +sme_resume_dialog_cmd(mac_handle_t mac_handle, + struct wmi_twt_resume_dialog_cmd_param *twt_params, + void *context); + +/** + * sme_twt_update_beacon_template() - API to send beacon update to fw + * @mac_handle: MAC handle + * + * Return: None + */ +void sme_twt_update_beacon_template(mac_handle_t mac_handle); + +#else + +static inline +QDF_STATUS sme_test_config_twt_setup(struct wmi_twt_add_dialog_param *params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline QDF_STATUS +sme_test_config_twt_terminate(struct wmi_twt_del_dialog_param *params) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline +void sme_twt_update_beacon_template(mac_handle_t mac_handle) +{ +} + +#endif + +#ifdef WLAN_UNIT_TEST +/** + * sme_get_sta_cxn_info() - This function populates all the connection + * information which is formed by DUT-STA to AP + * by calling CSR helper API. + * @mac_ctx: pointer to mac context + * @session: pointer to sta session + * @conn_profile: pointer to connected DUTSTA-REFAP profile + * @buf: pointer to char buffer to write all the connection information. + * @buf_size: maximum size of the provided buffer + * + * Returns: QDF_STATUS + */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +QDF_STATUS sme_get_sta_cxn_info(mac_handle_t mac_handle, uint32_t session_id, + char *buf, uint32_t buf_sz); +#else +static inline QDF_STATUS +sme_get_sta_cxn_info(mac_handle_t mac_handle, uint32_t session_id, + char *buf, uint32_t buf_sz) +{ + qdf_scnprintf(buf, buf_sz, + "\nDiag macro disable, ask vendor to enable"); + return QDF_STATUS_SUCCESS; +} +#endif +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * sme_add_key_btk() - Add BTK key + * @mac_handle: MAC handle + * @session_id: SME session identifier + * @key: key material + * @key_len: length of the key + * + * Return: 0 on success and negative value for failure + */ +int sme_add_key_btk(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *key, const int key_len); + +#else +static inline int sme_add_key_btk(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *key, const int key_len) +{ + return 0; +} +#endif + +#ifdef FEATURE_WLAN_ESE +/** + * sme_add_key_krk() - Add KRK key + * @mac_handle: MAC handle + * @session_id: SME session identifier + * @key: key material + * @key_len: length of the key + * + * Return: 0 on success and negative value for failure + */ +int sme_add_key_krk(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *key, const int key_len); + +#else + +static inline int sme_add_key_krk(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *key, const int key_len) +{ + return 0; +} +#endif + +/** + * sme_get_roam_scan_stats() - Send roam scan stats cmd to wma + * @mac_handle: handle returned by mac_open + * @cb: call-back invoked for roam scan stats response + * @context: context of callback + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_get_roam_scan_stats(mac_handle_t mac_handle, roam_scan_stats_cb cb, + void *context, uint32_t vdev_id); + +/** + * sme_update_score_config() - Update the Scoring Config from MLME + * @mac_handle: Mac Handle + * @phy_mode: Phymode to be used + * @num_rf_chains: num of RF chains supported by HW + * + * Return: None + */ +void sme_update_score_config(mac_handle_t mac_handle, eCsrPhyMode phy_mode, + uint8_t num_rf_chains); + +/** + * sme_enable_fw_module_log_level() - enable fw module log level + * @mac_handle: handle returned by mac_open + * @vdev_id: vdev id + * + * Return: None + */ +void sme_enable_fw_module_log_level(mac_handle_t mac_handle, int vdev_id); + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * sme_motion_det_cfg - motion detection configuration + * @vdev_id: vdev id + * @time_t1: Time T1 for motion detection in msecs + * @time_t2: Time T2 for motion detection in msecs + * @n1: number of packets for coarse detection + * @n2: number of packets for fine detection + * @time_t1_gap: gap between packets in coarse detection in msecs + * @time_t2_gap: gap between packets in fine detection in msecs + * @coarse_k: number of times fine motion detection has to be performed for + * coarse detection + * @fine_k: number of times fine motion detection has to be performed for + * fine detection + * @coarse_q: number of times motion is expected to be detected for success + * case in coarse detection + * @fine_q: number of times motion is expected to be detected for success + * case in fine detection + * @md_coarse_thr_high: higher threshold value (in percent) from host to FW, + * which will be used in coarse detection phase of motion + * detection. This is the threshold for the correlation of + * the old RF local-scattering environment with current RF + * local-scattering environment. Value of 100(%) indicates + * that neither the transceiver nor any nearby objects + * have changed position + * @md_fine_thr_high: higher threshold value (in percent) from host to FW, which + * will be used in fine detection phase of motion detection. + * This is the threshold for correlation between the old and + * current RF environments, as explained above + * @md_coarse_thr_low: lower threshold value (in percent) for immediate + * detection of motion in coarse detection phase. This is + * the threshold for correlation between the old and current + * RF environments, as explained above + * @md_fine_thr_low: lower threshold value (in percent) for immediate detection + * of motion in fine detection phase. This is the threshold + * for correlation between the old and current RF + * environments, as explained above + * @eSME_TDLS_PEER_REMOVE_MAC_ADDR: remove peer mac from connection table + */ + +struct sme_motion_det_cfg { + uint8_t vdev_id; + uint32_t time_t1; + uint32_t time_t2; + uint32_t n1; + uint32_t n2; + uint32_t time_t1_gap; + uint32_t time_t2_gap; + uint32_t coarse_K; + uint32_t fine_K; + uint32_t coarse_Q; + uint32_t fine_Q; + uint8_t md_coarse_thr_high; + uint8_t md_fine_thr_high; + uint8_t md_coarse_thr_low; + uint8_t md_fine_thr_low; +}; + +/** + * sme_motion_det_base_line_cfg - motion detection base line configuration + * @vdev_id : vdev id + * @bl_time_t: time T for baseline (in ms), every bl_time_t, bl_n pkts are sent + * @bl_packet_gap: gap between packets for baseline in msecs + * bl_n: number of packets to be sent during one baseline + * bl_num_meas: number of times the baseline measurement to be done + */ +struct sme_motion_det_base_line_cfg { + uint8_t vdev_id; + uint32_t bl_time_t; + uint32_t bl_packet_gap; + uint32_t bl_n; + uint32_t bl_num_meas; +}; + +/** + * sme_motion_det_en - Start/Stop motion detection + * @vdev_id: vdev_id + * @enable: start = 1, stop =0 + */ +struct sme_motion_det_en { + uint8_t vdev_id; + bool enable; +}; + +/** + * sme_motion_det_base_line_en - Start/Stop motion detection base line + * @vdev_id: vdev_id + * @enable: start = 1, stop =0 + */ +struct sme_motion_det_base_line_en { + uint8_t vdev_id; + bool enable; +}; + +/** + * sme_motion_det_config - Post motion detection configuration msg to scheduler + * @mac_handle: mac handle + * @motion_det_cfg: motion detection configuration + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_config(mac_handle_t mac_handle, + struct sme_motion_det_cfg *motion_det_cfg); + +/** + * sme_motion_det_enable - Post motion detection start/stop msg to scheduler + * @mac_handle: mac handle + * @motion_det_en: motion detection start/stop + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_enable(mac_handle_t mac_handle, + struct sme_motion_det_en *motion_det_en); + +/** + * sme_motion_det_base_line_config - Post md baselining cfg msg to scheduler + * @mac_handle: mac handle + * @motion_det_base_line_cfg: motion detection baselining configuration + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_base_line_config( + mac_handle_t mac_handle, + struct sme_motion_det_base_line_cfg *motion_det_base_line_cfg); + +/** + * sme_motion_det_base_line_enable - Post md baselining enable msg to scheduler + * @mac_handle: mac handle + * @motion_det_base_line_en: motion detection baselining start/stop + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_base_line_enable( + mac_handle_t mac_handle, + struct sme_motion_det_base_line_en *motion_det_base_line_en); + +/** + * sme_set_md_host_evt_cb - Register/set motion detection callback + * @mac_handle: mac handle + * @callback_fn: motion detection callback function pointer + * @hdd_ctx: hdd context + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_set_md_host_evt_cb +( + mac_handle_t mac_handle, + QDF_STATUS (*callback_fn)(void *ctx, struct sir_md_evt *event), + void *hdd_ctx +); + +/** + * sme_set_md_bl_evt_cb - Register/set motion detection baseline callback + * @mac_handle: mac handle + * @callback_fn: callback function pointer + * @hdd_ctx: hdd context + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_set_md_bl_evt_cb +( + mac_handle_t mac_handle, + QDF_STATUS (*callback_fn)(void *ctx, struct sir_md_bl_evt *event), + void *hdd_ctx +); +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +/** + * sme_set_thermal_throttle_cfg() - SME API to set the thermal throttle + * configuration parameters + * @mac_handle: Opaque handle to the global MAC context + * @therm_params: Thermal_params + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_throttle_cfg(mac_handle_t mac_handle, + struct thermal_mitigation_params *therm_params); + +/** + * sme_set_thermal_mgmt() - SME API to set the thermal management params + * @mac_handle: Opaque handle to the global MAC context + * @lower_thresh_deg: Lower threshold value of Temperature + * @higher_thresh_deg: Higher threshold value of Temperature + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_mgmt(mac_handle_t mac_handle, + uint16_t lower_thresh_deg, + uint16_t higher_thresh_deg); +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + +/** + * sme_update_hidden_ssid_status_cb() - cb fun to update hidden ssid stats + * @mac_handle: mac handler + * @cb: cb of type hidden_ssid_cb + */ +QDF_STATUS sme_update_hidden_ssid_status_cb(mac_handle_t mac_handle, + hidden_ssid_cb cb); + +/** + * sme_update_owe_info() - Update OWE info + * @mac: mac context + * @assoc_ind: assoc ind + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_owe_info(struct mac_context *mac, + struct assoc_ind *assoc_ind); + +/** + * sme_update_ft_info() - Update FT info + * @mac: mac context + * @assoc_ind: assoc ind + * + * Return: QDF_STATUS + */ + +QDF_STATUS sme_update_ft_info(struct mac_context *mac, + struct assoc_ind *assoc_ind); + +#ifdef WLAN_MWS_INFO_DEBUGFS +/** + * sme_get_mws_coex_info() - SME API to get the coex information + * @mac_handle: mac handler + * @vdev_id: Vdev_id + * @cmd_id: enum mws_coex_cmdid which information is needed. + * @callback_fn: Callback function + * @context: callback context + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id, + uint32_t cmd_id, void (*callback_fn)(void *coex_info_data, + void *context, + wmi_mws_coex_cmd_id + cmd_id), + void *context); +#endif /* WLAN_MWS_INFO_DEBUGFS */ + +#ifdef WLAN_BCN_RECV_FEATURE +/** + * sme_register_bcn_recv_pause_ind_cb() - Register pause ind cb + * mac_handle: man handler + * cb: callback function to HDD + * + * This function register HDD callback in order to indicate beacon + * receive pause indication to userspace. + * + * return QDF_STATUS of cb registration + */ +QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle, + beacon_pause_cb cb); + +#else +static inline +QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle, + beacon_pause_cb cb) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_set_disconnect_ies() - set disconnect IEs + * @mac_handle: handle returned by mac_open + * @vdev_id: vdev id + * @ie_data: Disconnect IE data + * @ie_len: Disconnect IE length + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_disconnect_ies(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t *ie_data, uint16_t ie_len); + +/** + * sme_set_vdev_sw_retry() - set sw retry threshold per vdev + * @vdev_id: vdev id + * @sw_retry_count: sw retry number + * @retry_type: SW vdev retry type + * + * This function calls WMA api to send the sw retry threshold per vdev. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_set_vdev_sw_retry(uint8_t vdev_id, uint8_t sw_retry_count, + wmi_vdev_custom_sw_retry_type_t sw_retry_type); + +/** + * sme_set_roam_config_enable() - Cache roam config status in SME + * @mac_handle: Opaque handle to the MAC context + * @vdev_id: vdev id + * @roam_control_enable: Carries a non-zero value if the current set request is + * for enable, otherwise carries a 0. + * + * Cache control roam config enable/disable status in SME so that the + * userspace can query for the status based on a vdev/session at any time. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_roam_config_enable(mac_handle_t mac_handle, + uint8_t vdev_id, + uint8_t roam_control_enable); + +/** + * sme_send_vendor_btm_params - Send vendor btm params to FW + * @hdd_ctx: HDD context + * @vdev_id: vdev id + * + * Send roam trigger param to firmware if valid. + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_send_vendor_btm_params(mac_handle_t mac_handle, uint8_t vdev_id); + +/** + * sme_get_roam_config_status() - Get roam config status from SME + * @mac_handle: Opaque handle to the MAC context + * @vdev_id: vdev id + * @config_status: Pointer of a buffer to fill the status + * + * Get the cached control roam config status in SME and copy to status. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_roam_config_status(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t *config_status); + +/** + * sme_get_full_roam_scan_period_global() - get global full scan refresh period + * @mac_handle: The handle returned by mac_open + * + * Return: Full roam scan period configured through ini + */ +uint16_t sme_get_full_roam_scan_period_global(mac_handle_t mac_handle); + +/** + * sme_get_full_roam_scan_period() - Get full roam scan period + * @mac_handle: Opaque handle to the MAC context + * @vdev_id: vdev id + * @full_roam_scan_period: Pointer of a buffer to fill the full roam scan period + * + * Get the full scan period cached in neighborRoamInfo and fill in the given + * buffer full_roam_scan_period. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_full_roam_scan_period(mac_handle_t mac_handle, + uint8_t vdev_id, + uint32_t *full_roam_scan_period); + +/** + * sme_check_for_duplicate_session() - check for duplicate session + * @mac_handle: Opaque handle to the MAC context + * @mac_list: List of mac address of peers. + * + * Check for duplicate mac address is available on other vdev. + * The list pointed by @mac_list has to be NULL terminated. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_check_for_duplicate_session(mac_handle_t mac_handle, + uint8_t **mac_list); +#ifdef FEATURE_ANI_LEVEL_REQUEST +/* + * sme_get_ani_level() - + * A wrapper function that client calls to register a callback to get ani level + * + * @mac_handle - pointer to mac handle + * @freqs - frequencies for which ANI level has to be fetched + * @num_freqs - number of frequencies + * @callback - SME sends back the ani level using the callback + * @context - user context to be passed back along with the callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs, + uint8_t num_freqs, void (*callback)( + struct wmi_host_ani_level_event *ani, uint8_t num, + void *context), void *context); +#endif /* FEATURE_ANI_LEVEL_REQUEST */ + +/* + * sme_vdev_self_peer_delete_resp() - Response for self peer delete + * @del_vdev_params: parameters for which vdev self peer has been deleted + * + * This function is called by the lower level function as a response to + * vdev self peer delete request. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_vdev_self_peer_delete_resp(struct del_vdev_params *param); + +/** + * sme_vdev_del_resp() - Vdev delete response function + * @vdev_id: vdevid which has been deleted + * + * This function is called by the lower level function as a response to + * vdev delete request + * + * Return: None + */ +void sme_vdev_del_resp(uint8_t vdev_id); + +#ifdef FEATURE_MONITOR_MODE_SUPPORT +/** + * sme_set_monitor_mode_cb() - Register monitor mode vdev up operation callback + * @mac_handle: Opaque handle to the MAC context + * @monitor_mode_cb: callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_monitor_mode_cb(mac_handle_t mac_handle, + void (*monitor_mode_cb)(uint8_t vdev_id)); + +/* + * sme_process_monitor_mode_vdev_up_evt() - Handle vdev up completion + * @vdev_id: vdev id + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_process_monitor_mode_vdev_up_evt(uint8_t vdev_id); +#else +static inline +QDF_STATUS sme_set_monitor_mode_cb(mac_handle_t mac_handle, + void (*monitor_mode_cb)(uint8_t vdev_id)) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +sme_process_monitor_mode_vdev_up_evt(uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) +/** + * sme_set_beacon_latency_event_cb() - Register beacon latency IE callback + * @mac_handle: Opaque handle to the MAC context + * @beacon_latency_event_cb: callback to be registered + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_beacon_latency_event_cb(mac_handle_t mac_handle, + void (*beacon_latency_event_cb) + (uint32_t latency_level)); +#else +static inline QDF_STATUS +sme_set_beacon_latency_event_cb(mac_handle_t mac_handle, + void (*beacon_latency_event_cb) + (uint32_t latency_level)) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_fill_enc_type() - converts crypto cipher set to csr specific cipher type + * @cipher_type: output csr cipher type + * @ cipherset:input cipher set + * + * Return: None + */ + +void sme_fill_enc_type(eCsrEncryptionType *cipher_type, + uint32_t cipherset); + +/** + * sme_fill_auth_type() - converts auth mode set to csr specific auth type + * @auth_type: output csr auth type + * @ authmodeset: authmode set + * @akm: akm + * @ucastcipherset: ucastcipherset + * + * Return: None + */ +void sme_fill_auth_type(enum csr_akm_type *auth_type, + uint32_t authmodeset, uint32_t akm, + uint32_t ucastcipherset); + +/** + * sme_phy_mode_to_dot11mode() - converts phy mode to dot11 mode + * @phy_mode: wlan phy mode + * + * Return: csr_cfgdot11mode + */ +enum csr_cfgdot11mode sme_phy_mode_to_dot11mode(enum wlan_phymode phy_mode); + +#ifdef WLAN_FEATURE_11BE +/** + * sme_get_eht_ch_width() - SME API to get max supported EHT chan width by FW + * + * Return: Max EHT channel width supported by FW (eg. 80, 160, 320) + */ +uint32_t sme_get_eht_ch_width(void); +#else /* !WLAN_FEATURE_11BE */ +static inline uint32_t sme_get_eht_ch_width(void) +{ + return 0; +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * sme_switch_channel() - Request to switch channel + * @mac_handle: Opaque handle to the MAC context + * @bssid: current connected bssid + * @chan_freq: new channel frequency + * @chan_width: new channel width + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_switch_channel(mac_handle_t mac_handle, + struct qdf_mac_addr *bssid, + qdf_freq_t chan_freq, + enum phy_ch_width chan_width); + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +/** + * sme_send_set_mac_addr() - Send set MAC address command to FW + * @mac_addr: VDEV MAC address + * @mld_addr: VDEV MLD address + * @vdev: Pointer to object manager VDEV + * + * API to send set MAC address request command to FW + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_set_mac_addr(struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + struct wlan_objmgr_vdev *vdev); + +/** + * sme_update_vdev_mac_addr() - Update VDEV MAC address + * @vdev: Objmgr VDEV pointer + * @mac_addr: VDEV MAC address + * @mld_addr: VDEV MLD address + * @update_sta_self_peer: Flag to check self peer MAC address or not. + * @update_mld_addr: Flag to check if MLD address update needed or not. + * @req_status: Status of the set MAC address request to the FW + * + * API to update MLME structures with new MAC address. This will be invoked + * after receiving success status form the FW for the set MAC address request + * command. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_vdev_mac_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + bool update_sta_self_peer, + bool update_mld_addr, int req_status); +#endif + +/** + * sme_get_network_params() - SME API to get dot11 config for SAP + * functionality + *@mac_ctx: mac context + *@dot11_cfg : pointer to dot11 config + * + * Return : QDF_STATUS + */ +QDF_STATUS sme_get_network_params(struct mac_context *mac_ctx, + struct bss_dot11_config *dot11_cfg); + +/** + * sme_start_bss() -A wrapper function to request CSR to + * inititiate start bss + * @mac_handle: mac hancle + * @vdev_id: vdev id + * @bss_config: pointer to start bss config + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_start_bss(mac_handle_t mac_handle, uint8_t vdev_id, + struct start_bss_config *bss_config); + +/** + * sme_sap_ser_callback() - callback from serialization module + * @cmd: serialization command + * @reason: reason why serialization module has given this callback + * + * Serialization module will give callback to SME for why it triggered + * the callback + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_sap_ser_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason); + +/** + *sme_fill_channel_change_request() - SME API to fill the channel + * change request for monitor mode + * @mac_handle: mac handle + * @req: pointer to change channel request message + * @phy_mode: phy mode of the vdev + * + * Return: QDF_STATUS + */ +void sme_fill_channel_change_request(mac_handle_t mac_handle, + struct channel_change_req *req, + eCsrPhyMode phy_mode); + +/** + * sme_send_channel_change_req() - SME API to post channel change + * request to LIM + * @mac_handle: mac handle + * @req: pointer to change channel request message + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_channel_change_req(mac_handle_t mac_handle, + struct channel_change_req *req); + +/** + * sme_update_beacon_country_ie() - SME API to update beacon + * country ie + * @mac_handle: mac handle + * @vdev_id: vdev id + * @country_ie_for_all_band: country ie should take all band channel + * or only the current band channel + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_beacon_country_ie(mac_handle_t mac_handle, + uint8_t vdev_id, + bool country_ie_for_all_band); + +#endif /* #if !defined( __SME_API_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_inside.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_inside.h new file mode 100644 index 0000000000..c9ce6591b2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_inside.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SMEINSIDE_H) +#define __SMEINSIDE_H + +/** + * \file sme_inside.h + * + * \brief prototype for SME structures and APIs used insside SME + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_status.h" +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "sir_api.h" +#include "csr_internal.h" +#include "sme_qos_api.h" +#include "sme_qos_internal.h" + +#include "sme_rrm_api.h" +#include "wlan_serialization_legacy_api.h" +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +/* + * In case MAX num of STA are connected to SAP, switching off SAP causes + * two SME cmd to be enqueued for each STA. Keeping SME total cmds as following + * to make sure we have space for these cmds + some additional cmds. + */ +#define SME_TOTAL_COMMAND (HAL_NUM_STA * 3) + +typedef struct sGenericQosCmd { + struct sme_qos_wmmtspecinfo tspecInfo; + enum qca_wlan_ac_type ac; + uint8_t tspec_mask; +} tGenericQosCmd; + +/** + * struct s_nss_update_cmd - Format of nss update request + * @new_nss: new nss value + * @ch_width: new channel width - optional + * @session_id: Session ID + * @set_hw_mode_cb: HDD nss update callback + * @context: Adapter context + * @next_action: Action to be taken after nss update + * @reason: reason for nss update + * @original_vdev_id: original request hwmode change vdev id + * @request_id: request id for connection manager + */ +struct s_nss_update_cmd { + uint32_t new_nss; + uint32_t ch_width; + uint32_t session_id; + void *nss_update_cb; + void *context; + uint8_t next_action; + enum policy_mgr_conn_update_reason reason; + uint32_t original_vdev_id; + uint32_t request_id; +}; + +/** + * struct sir_sap_ch_width_update_cmd - Format of ch_width update request + * @ch_width: new channel width + * @vdev_id: vdev ID + * @reason: reason for ch_width update + * @conc_vdev_id: Concurrent connection vdev_id that is causing ch_width update + * @request_id: request id for connection manager + */ +struct sir_sap_ch_width_update_cmd { + uint32_t ch_width; + uint32_t vdev_id; + enum policy_mgr_conn_update_reason reason; + uint32_t conc_vdev_id; + uint32_t request_id; +}; + +typedef struct tagSmeCmd { + tListElem Link; + eSmeCommandType command; + uint32_t cmd_id; + uint32_t vdev_id; + union { + struct roam_cmd roamCmd; + struct wmstatus_changecmd wmStatusChangeCmd; + tGenericQosCmd qosCmd; + struct policy_mgr_hw_mode set_hw_mode_cmd; + struct s_nss_update_cmd nss_update_cmd; + struct policy_mgr_dual_mac_config set_dual_mac_cmd; + struct sir_antenna_mode_param set_antenna_mode_cmd; + struct sir_sap_ch_width_update_cmd bw_update_cmd; + } u; +} tSmeCmd; + +/*-------------------------------------------------------------------------- + Internal to SME + ------------------------------------------------------------------------*/ +/** + * csr_get_cmd_type() - to convert sme command type to serialization cmd type + * @sme_cmd: sme command pointer + * + * This API will convert SME command type to serialization command type which + * new serialization module understands + * + * Return: serialization cmd type based on sme command type + */ +enum wlan_serialization_cmd_type csr_get_cmd_type(tSmeCmd *sme_cmd); +/** + * csr_set_serialization_params_to_cmd() - take sme params and create new + * serialization command + * @mac_ctx: pointer to mac context + * @sme_cmd: sme command pointer + * @cmd: serialization command pointer + * @high_priority: if command is high priority + * + * Return: QDF_STATUS_SUCCESS or QDF_STATUS_E_FAILURE + */ +QDF_STATUS csr_set_serialization_params_to_cmd(struct mac_context *mac_ctx, + tSmeCmd *sme_cmd, struct wlan_serialization_command *cmd, + uint8_t high_priority); +tSmeCmd *sme_get_command_buffer(struct mac_context *mac); +void sme_release_command(struct mac_context *mac, tSmeCmd *pCmd); +bool qos_process_command(struct mac_context *mac, tSmeCmd *pCommand); +void qos_release_command(struct mac_context *mac, tSmeCmd *pCommand); +QDF_STATUS csr_roam_process_command(struct mac_context *mac, tSmeCmd *pCommand); + +/** + * csr_roam_wm_status_change_complete() - Remove WM status change command + * from SME active command list + * @mac_ctx: global mac context + * @session_id: session id + * + * This API removes WM status change command from SME active command list + * if present. + * + * Return: void + */ +void csr_roam_wm_status_change_complete(struct mac_context *mac_ctx, + uint8_t session_id); +void csr_roam_process_wm_status_change_command(struct mac_context *mac, + tSmeCmd *pCommand); + +void csr_reinit_roam_cmd(struct mac_context *mac, tSmeCmd *pCommand); +void csr_reinit_wm_status_change_cmd(struct mac_context *mac, + tSmeCmd *pCommand); + +QDF_STATUS sme_acquire_global_lock(struct sme_context *sme); +QDF_STATUS sme_release_global_lock(struct sme_context *sme); + +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue); +void csr_process_set_dual_mac_config(struct mac_context *mac, tSmeCmd *command); +void csr_process_set_antenna_mode(struct mac_context *mac, tSmeCmd *command); +void csr_process_set_hw_mode(struct mac_context *mac, tSmeCmd *command); +void csr_process_nss_update_req(struct mac_context *mac, tSmeCmd *command); +void csr_process_sap_ch_width_update(struct mac_context *mac, tSmeCmd *command); +#endif /* #if !defined( __SMEINSIDE_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_internal.h new file mode 100644 index 0000000000..340d817d27 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_internal.h @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SMEINTERNAL_H) +#define __SMEINTERNAL_H + +/** + * \file sme_internal.h + * + * \brief prototype for SME internal structures and APIs used for SME and MAC + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_status.h" +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "host_diag_core_event.h" +#include "csr_link_list.h" +#include "sme_power_save.h" +#include "wmi_unified.h" +#include "wmi_unified_param.h" + +struct wma_twt_add_dialog_complete_event; +struct wmi_twt_add_dialog_complete_event_param; +struct wmi_twt_enable_complete_event_param; +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ + +/* Mask can be only have one bit set */ +typedef enum eSmeCommandType { + eSmeNoCommand = 0, + /* this is not a command, it is to identify this is a CSR command */ + eSmeCsrCommandMask = 0x10000, + eSmeCommandRoam, + eSmeCommandWmStatusChange, + /* QOS */ + eSmeQosCommandMask = 0x40000, /* To identify Qos commands */ + eSmeCommandAddTs, + eSmeCommandDelTs, + e_sme_command_set_hw_mode, + e_sme_command_nss_update, + e_sme_command_set_dual_mac_config, + e_sme_command_set_antenna_mode, + e_sme_command_sap_ch_width_update, +} eSmeCommandType; + +typedef enum eSmeState { + SME_STATE_STOP, + SME_STATE_START, + SME_STATE_READY, +} eSmeState; + +#define SME_IS_START(mac) (SME_STATE_STOP != (mac)->sme.state) +#define SME_IS_READY(mac) (SME_STATE_READY == (mac)->sme.state) + +/** + * struct stats_ext_event - stats_ext_event payload + * @vdev_id: ID of the vdev for the stats + * @event_data_len: length of the @event_data + * @event_data: actual ext stats + */ +struct stats_ext_event { + uint32_t vdev_id; + uint32_t event_data_len; + uint8_t event_data[]; +}; + +/** + * typedef stats_ext_cb - stats ext callback + * @hdd_handle: Opaque handle to the HDD context + * @data: stats ext payload from firmware + */ +typedef void (*stats_ext_cb)(hdd_handle_t hdd_handle, + struct stats_ext_event *data); + +/** + * typedef stats_ext2_cb - stats ext2 callback + * @hdd_handle: Opaque handle to the HDD context + * @data: stats ext2 payload from firmware + */ +typedef void (*stats_ext2_cb)(hdd_handle_t hdd_handle, + struct sir_sme_rx_aggr_hole_ind *data); + +#define MAX_ACTIVE_CMD_STATS 16 + +typedef struct sActiveCmdStats { + eSmeCommandType command; + uint32_t reason; + uint32_t sessionId; + uint64_t timestamp; +} tActiveCmdStats; + +typedef struct sSelfRecoveryStats { + tActiveCmdStats activeCmdStats[MAX_ACTIVE_CMD_STATS]; + uint8_t cmdStatsIndx; +} tSelfRecoveryStats; + +typedef void (*link_layer_stats_cb)(hdd_handle_t hdd_handle, + int indication_type, + tSirLLStatsResults *results, + void *cookie); + +typedef void (*ext_scan_ind_cb)(hdd_handle_t hdd_handle, + const uint16_t, void *); + +/** + * typedef sme_link_speed_cb - sme_get_link_speed() callback function + * @info: link speed information + * @context: user context supplied to sme_get_link_speed() + * + * This is the signature of a callback function whose addresses is + * passed as the asynchronous callback function to sme_get_link_speed(). + */ + +typedef void (*sme_link_speed_cb)(struct link_speed_info *info, + void *context); + +typedef void (*ocb_callback)(void *context, void *response); +typedef void (*sme_set_thermal_level_callback)(hdd_handle_t hdd_handle, + u_int8_t level); +typedef void (*p2p_lo_callback)(void *context, + struct sir_p2p_lo_event *event); +#ifdef FEATURE_OEM_DATA_SUPPORT +typedef void (*sme_send_oem_data_rsp_msg)(struct oem_data_rsp *); +#endif + +#ifdef WLAN_SUPPORT_TWT +/** + * typedef twt_enable_cb - TWT enable callback signature. + * @hdd_handle: Opaque HDD handle + * @params: TWT enable complete event parameters. + */ +typedef +void (*twt_enable_cb)(hdd_handle_t hdd_handle, + struct wmi_twt_enable_complete_event_param *params); + +/** + * typedef twt_disable_cb - TWT enable callback signature. + * @hdd_handle: Opaque HDD handle + */ +typedef void (*twt_disable_cb)(hdd_handle_t hdd_handle); + +/** + * typedef twt_add_dialog_cb - TWT add dialog callback signature. + * @psoc: Pointer to global psoc + * @add_dialog_evt: pointer to event buf containing twt response parameters + * @renego_fail: Flag to indicate if its re-negotiation failure case + */ +typedef +void (*twt_add_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wma_twt_add_dialog_complete_event *add_dialog_evt, + bool renego_fail); + +/** + * typedef twt_del_dialog_cb - TWT delete dialog callback signature. + * @psoc: Pointer to global psoc + * @params: TWT delete dialog complete event parameters. + */ +typedef void (*twt_del_dialog_cb)( + struct wlan_objmgr_psoc *psoc, + struct wmi_twt_del_dialog_complete_event_param *params); + +/** + * typedef twt_pause_dialog_cb - TWT pause dialog callback signature. + * @psoc: Pointer to global psoc + * @params: TWT pause dialog complete event parameters. + */ +typedef +void (*twt_pause_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_pause_dialog_complete_event_param *params); + +/** + * typedef twt_nudge_dialog_cb - TWT nudge dialog callback signature. + * @psoc: Pointer to global psoc + * @params: TWT nudge dialog complete event parameters. + */ +typedef +void (*twt_nudge_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_nudge_dialog_complete_event_param *params); + +/** + * typedef twt_resume_dialog_cb - TWT resume dialog callback signature. + * @psoc: Pointer to global psoc + * @params: TWT resume dialog complete event parameters. + */ +typedef +void (*twt_resume_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_resume_dialog_complete_event_param *params); + +/** + * typedef twt_notify_cb - TWT notify callback signature. + * @psoc: Pointer to global psoc + * @params: TWT twt notify event parameters. + */ +typedef +void (*twt_notify_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_notify_event_param *params); + +/** + * typedef twt_ack_comp_cb - TWT ack callback signature. + * @params: TWT ack complete event parameters. + * @context: TWT context + */ +typedef +void (*twt_ack_comp_cb)(struct wmi_twt_ack_complete_event_param *params, + void *context); + +/** + * struct twt_callbacks - TWT response callback pointers + * @twt_enable_cb: TWT enable completion callback + * @twt_disable_cb: TWT disable completion callback + * @twt_add_dialog_cb: TWT add dialog completion callback + * @twt_del_dialog_cb: TWT delete dialog completion callback + * @twt_pause_dialog_cb: TWT pause dialog completion callback + * @twt_resume_dialog_cb: TWT resume dialog completion callback + * @twt_notify_cb: TWT notify event callback + * @twt_nudge_dialog_cb: TWT nudge dialog completion callback + * @twt_ack_comp_cb: TWT ack completion callback + */ +struct twt_callbacks { + void (*twt_enable_cb)(hdd_handle_t hdd_handle, + struct wmi_twt_enable_complete_event_param *params); + void (*twt_disable_cb)(hdd_handle_t hdd_handle); + void (*twt_add_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wma_twt_add_dialog_complete_event *add_dialog_event, + bool renego); + void (*twt_del_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_del_dialog_complete_event_param *params); + void (*twt_pause_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_pause_dialog_complete_event_param *params); + void (*twt_resume_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_resume_dialog_complete_event_param *params); + void (*twt_notify_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_notify_event_param *params); + void (*twt_nudge_dialog_cb)(struct wlan_objmgr_psoc *psoc, + struct wmi_twt_nudge_dialog_complete_event_param *params); + void (*twt_ack_comp_cb)(struct wmi_twt_ack_complete_event_param *params, + void *context); +}; +#endif + +#ifdef FEATURE_WLAN_APF +/** + * typedef apf_get_offload_cb - APF offload callback signature + * @context: Opaque context that the client can use to associate the + * callback with the request + * @caps: APF offload capabilities as reported by firmware + */ +struct sir_apf_get_offload; +typedef void (*apf_get_offload_cb)(void *context, + struct sir_apf_get_offload *caps); + +/** + * typedef apf_read_mem_cb - APF read memory response callback + * @context: Opaque context that the client can use to associate the + * callback with the request + * @evt: APF read memory response event parameters + */ +typedef void (*apf_read_mem_cb)(void *context, + struct wmi_apf_read_memory_resp_event_params + *evt); +#endif /* FEATURE_WLAN_APF */ + +/** + * typedef rssi_threshold_breached_cb - RSSI threshold breach callback + * @hdd_handle: Opaque handle to the HDD context + * @event: The RSSI breach event + */ +typedef void (*rssi_threshold_breached_cb)(hdd_handle_t hdd_handle, + struct rssi_breach_event *event); + +/** + * typedef get_chain_rssi_callback - get chain rssi callback + * @context: Opaque context that the client can use to associate the + * callback with the request + * @data: chain rssi result reported by firmware + */ +struct chain_rssi_result; +typedef void (*get_chain_rssi_callback)(void *context, + struct chain_rssi_result *data); + +#ifdef FEATURE_FW_STATE +/** + * typedef fw_state_callback - get firmware state callback + * @context: Opaque context that the client can use to associate the + * callback with the request + */ +typedef void (*fw_state_callback)(void *context); +#endif /* FEATURE_FW_STATE */ + +typedef void (*tx_queue_cb)(hdd_handle_t hdd_handle, uint32_t vdev_id, + enum netif_action_type action, + enum netif_reason_type reason); + +/** + * typedef pwr_save_fail_cb - power save fail callback function + * @hdd_handle: HDD handle registered with SME + * @params: failure parameters + */ +struct chip_pwr_save_fail_detected_params; +typedef void (*pwr_save_fail_cb)(hdd_handle_t hdd_handle, + struct chip_pwr_save_fail_detected_params *params); + +/** + * typedef bt_activity_info_cb - bluetooth activity callback function + * @hdd_handle: HDD handle registered with SME + * @bt_activity: bluetooth activity information + */ +typedef void (*bt_activity_info_cb)(hdd_handle_t hdd_handle, + uint32_t bt_activity); + +/** + * typedef rso_cmd_status_cb - RSO command status callback function + * @hdd_handle: HDD handle registered with SME + * @rso_status: Status of the operation + */ +typedef void (*rso_cmd_status_cb)(hdd_handle_t hdd_handle, + struct rso_cmd_status *rso_status); + +/** + * typedef lost_link_info_cb - lost link indication callback function + * @hdd_handle: HDD handle registered with SME + * @lost_link_info: Information about the lost link + */ +typedef void (*lost_link_info_cb)(hdd_handle_t hdd_handle, + struct sir_lost_link_info *lost_link_info); +/** + * typedef hidden_ssid_cb - hidden ssid rsp callback fun + * @hdd_handle: HDD handle registered with SME + * @vdev_id: Vdev Id + */ +typedef void (*hidden_ssid_cb)(hdd_handle_t hdd_handle, + uint8_t vdev_id); + +/** + * typedef bcn_report_cb - recv bcn callback fun + * @hdd_handle: HDD handle registered with SME + * @beacon_report: Beacon report structure + */ +typedef QDF_STATUS (*beacon_report_cb) + (hdd_handle_t hdd_handle, struct wlan_beacon_report *beacon_report); + +/** + * beacon_pause_cb : scan start callback fun + * @hdd_handler: HDD handler + * @vdev_id: vdev id + * @type: scan event type + * @is_disconnected: Driver is in dis connected state or not + */ +typedef void (*beacon_pause_cb)(hdd_handle_t hdd_handle, + uint8_t vdev_id, + enum scan_event_type type, + bool is_disconnected); + +/** + * typedef sme_get_isolation_cb - get isolation callback fun + * @param: isolation result reported by firmware + * @pcontext: Opaque context that the client can use to associate the + * callback with the request + */ +typedef void (*sme_get_isolation_cb)(struct sir_isolation_resp *param, + void *pcontext); + +#ifdef WLAN_FEATURE_MOTION_DETECTION +typedef QDF_STATUS (*md_host_evt_cb)(void *hdd_ctx, struct sir_md_evt *event); +typedef QDF_STATUS (*md_bl_evt_cb)(void *hdd_ctx, struct sir_md_bl_evt *event); +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +struct sme_context { + eSmeState state; + qdf_mutex_t sme_global_lock; + uint32_t sme_cmd_count; + /* following pointer contains array of pointers for tSmeCmd* */ + void **sme_cmd_buf_addr; + tDblLinkList sme_cmd_freelist; /* preallocated roam cmd list */ + void *ll_stats_context; + link_layer_stats_cb link_layer_stats_cb; + void (*link_layer_stats_ext_cb)(hdd_handle_t callback_ctx, + tSirLLStatsResults *rsp); +#ifdef WLAN_POWER_DEBUG + void *power_debug_stats_context; + void (*power_stats_resp_callback)(struct power_stats_response *rsp, + void *callback_context); + void (*sme_power_debug_stats_callback)( + struct mac_context *mac, + struct power_stats_response *response); +#endif +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS + void *beacon_stats_context; + void (*beacon_stats_resp_callback)(struct bcn_reception_stats_rsp *rsp, + void *callback_context); +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + void (*auto_shutdown_cb)(void); +#endif + /* Maximum interfaces allowed by the host */ + uint8_t max_intf_count; + stats_ext_cb stats_ext_cb; + stats_ext2_cb stats_ext2_cb; + /* linkspeed callback */ + sme_link_speed_cb link_speed_cb; + void *link_speed_context; + + sme_get_isolation_cb get_isolation_cb; + void *get_isolation_cb_context; +#ifdef FEATURE_WLAN_EXTSCAN + ext_scan_ind_cb ext_scan_ind_cb; +#endif /* FEATURE_WLAN_EXTSCAN */ + csr_link_status_callback link_status_callback; + void *link_status_context; + int (*get_tsf_cb)(void *pcb_cxt, struct stsf *ptsf); + void *get_tsf_cxt; + /* get temperature event context and callback */ + void *temperature_cb_context; + void (*temperature_cb)(int temperature, void *context); + uint8_t miracast_value; + struct ps_global_info ps_global_info; + rssi_threshold_breached_cb rssi_threshold_breached_cb; + sme_set_thermal_level_callback set_thermal_level_cb; + void *apf_get_offload_context; +#ifdef FEATURE_P2P_LISTEN_OFFLOAD + p2p_lo_callback p2p_lo_event_callback; + void *p2p_lo_event_context; +#endif +#ifdef FEATURE_OEM_DATA_SUPPORT + sme_send_oem_data_rsp_msg oem_data_rsp_callback; +#endif + lost_link_info_cb lost_link_info_cb; + + bool (*set_connection_info_cb)(bool); + bool (*get_connection_info_cb)(uint8_t *session_id, + enum scan_reject_states *reason); + rso_cmd_status_cb rso_cmd_status_cb; + pwr_save_fail_cb chip_power_save_fail_cb; + bt_activity_info_cb bt_activity_info_cb; + void *get_arp_stats_context; + void (*get_arp_stats_cb)(void *, struct rsp_stats *, void *); + get_chain_rssi_callback get_chain_rssi_cb; + void *get_chain_rssi_context; +#ifdef FEATURE_FW_STATE + fw_state_callback fw_state_cb; + void *fw_state_context; +#endif /* FEATURE_FW_STATE */ + tx_queue_cb tx_queue_cb; +#ifdef WLAN_SUPPORT_TWT + twt_enable_cb twt_enable_cb; + twt_disable_cb twt_disable_cb; + twt_add_dialog_cb twt_add_dialog_cb; + twt_del_dialog_cb twt_del_dialog_cb; + twt_pause_dialog_cb twt_pause_dialog_cb; + twt_nudge_dialog_cb twt_nudge_dialog_cb; + twt_resume_dialog_cb twt_resume_dialog_cb; + twt_notify_cb twt_notify_cb; + twt_ack_comp_cb twt_ack_comp_cb; + void *twt_ack_context_cb; +#endif +#ifdef FEATURE_WLAN_APF + apf_get_offload_cb apf_get_offload_cb; + apf_read_mem_cb apf_read_mem_cb; +#endif +#ifdef WLAN_FEATURE_MOTION_DETECTION + md_host_evt_cb md_host_evt_cb; + md_bl_evt_cb md_bl_evt_cb; + void *md_ctx; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + /* hidden ssid rsp callback */ + hidden_ssid_cb hidden_ssid_cb; +#ifdef WLAN_MWS_INFO_DEBUGFS + void *mws_coex_info_ctx; + void (*mws_coex_info_state_resp_callback)(void *coex_info_data, + void *context, + wmi_mws_coex_cmd_id cmd_id); +#endif /* WLAN_MWS_INFO_DEBUGFS */ + +#ifdef WLAN_BCN_RECV_FEATURE + beacon_report_cb beacon_report_cb; + beacon_pause_cb beacon_pause_cb; +#endif +#ifdef FEATURE_OEM_DATA + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data, + uint8_t vdev_id); + uint8_t oem_data_vdev_id; + /* async oem event callback */ + void (*oem_data_async_event_handler_cb) + (const struct oem_data *oem_event_data); +#endif + + QDF_STATUS (*pagefault_action_cb)(void *buf, uint32_t data); + +#ifdef MULTI_CLIENT_LL_SUPPORT + void (*latency_level_event_handler_cb) + (const struct latency_level_data *event_data, + uint8_t vdev_id); +#endif + + sme_get_raom_scan_ch_callback roam_scan_ch_callback; + void *roam_scan_ch_get_context; +#ifdef FEATURE_MONITOR_MODE_SUPPORT + void (*monitor_mode_cb)(uint8_t vdev_id); +#endif +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) + void (*beacon_latency_event_cb)(uint32_t latency_level); +#endif + QDF_STATUS (*sme_vdev_del_cb)(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev); +}; + +#endif /* #if !defined( __SMEINTERNAL_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_nan_datapath.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_nan_datapath.h new file mode 100644 index 0000000000..e7677acae1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_nan_datapath.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: sme_nan_datapath.h + * + * SME NAN Data path API specification + */ + +#ifndef __SME_NAN_DATAPATH_H +#define __SME_NAN_DATAPATH_H + +#include "csr_inside_api.h" + +#ifdef WLAN_FEATURE_NAN +void csr_roam_update_ndp_return_params(struct mac_context *mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct csr_roam_info *roam_info); + +#else /* WLAN_FEATURE_NAN */ + +static inline void csr_roam_update_ndp_return_params(struct mac_context *mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct csr_roam_info *roam_info) +{ +} + +#endif /* WLAN_FEATURE_NAN */ + +#endif /* __SME_NAN_DATAPATH_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_power_save.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_power_save.h new file mode 100644 index 0000000000..81952a7fa2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_power_save.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SME_POWER_SAVE_H) +#define __SME_POWER_SAVE_H +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_system_defs.h" +#include "sir_api.h" + +/* + * Auto Ps Entry User default timeout value, used instead of negative timeouts + * from user space - 5000ms + */ +#define AUTO_PS_ENTRY_USER_TIMER_DEFAULT_VALUE 5000 +#define AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE 1000 +#define AUTO_PS_DEFER_TIMEOUT_MS 1500 + +#ifdef QCA_WIFI_EMULATION +/* + * Auto Ps timeout for emulation targets. + */ +#define AUTO_PS_EMULATION_TIMEOUT 11 +#endif + +/** + * struct ps_global_info - global struct for Power save information + * @ps_params: maintain power save state and USAPD params + * @remain_in_power_active_till_dhcp: remain in Power active till DHCP completes + */ +struct ps_global_info { + struct ps_params ps_params[WLAN_MAX_VDEVS]; +}; + +/** + * enum sme_ps_cmd: power save message to send WMA + * @SME_PS_ENABLE: For power save enable. + * @SME_PS_DISABLE: for Power save disable. + * @SME_PS_UAPSD_ENABLE; for UAPSD enable. + * @SME_PS_UAPSD_DISABLE: for UAPSD disable. + * @SME_PS_WOWL_ENTER: for WOWL Enter. + * @SME_PS_WOWL_EXIT: for WOWL Exit. + * @SME_PS_WOWL_ADD_BCAST_PTRN: Add bcst WOWL pattern. + * @SME_PS_WOWL_DEL_BCAST_PTRN: Del Bcsr Wowl Pattern. + */ +enum sme_ps_cmd { + SME_PS_ENABLE = 0, + SME_PS_DISABLE, + SME_PS_UAPSD_ENABLE, + SME_PS_UAPSD_DISABLE, + SME_PS_WOWL_ENTER, + SME_PS_WOWL_EXIT, + SME_PS_WOWL_ADD_BCAST_PTRN, + SME_PS_WOWL_DEL_BCAST_PTRN, +}; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_power_save_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_power_save_api.h new file mode 100644 index 0000000000..31a8a3c025 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_power_save_api.h @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SME_POWER_SAVE_API_H) +#define __SME_POWER_SAVE_API_H + +#include "sme_power_save.h" +#include "ani_global.h" +#include "sme_inside.h" + +QDF_STATUS sme_ps_enable_disable(mac_handle_t mac_handle, uint32_t session_id, + enum sme_ps_cmd command); + +QDF_STATUS sme_ps_timer_flush_sync(mac_handle_t mac_handle, + uint8_t session_id); + +QDF_STATUS sme_ps_uapsd_enable(mac_handle_t mac_handle, uint32_t session_id); + +QDF_STATUS sme_ps_uapsd_disable(mac_handle_t mac_handle, uint32_t session_id); + +QDF_STATUS sme_enable_sta_ps_check(struct mac_context *mac_ctx, + uint32_t session_id, + enum sme_ps_cmd command); + +QDF_STATUS sme_ps_process_command(struct mac_context *mac_ctx, + uint32_t session_id, + enum sme_ps_cmd command); + +/** + * sme_ps_set_powersave(): Set powersave state + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev Id + * @allow_power_save: allow powersave or not + * @timeout: timeout period in ms + * @ap_supports_immediate_power_save: ap support immediate powersave + * + * Returns: QDF_STATUS + */ +QDF_STATUS sme_ps_set_powersave(mac_handle_t mac_handle, + uint8_t vdev_id, bool allow_power_save, + uint32_t timeout, + bool ap_supports_immediate_power_save); + +/** + * sme_ps_update(): Update current powersave state to target + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: vdev Id + * + * Returns: QDF_STATUS + */ +QDF_STATUS sme_ps_update(mac_handle_t mac_handle, uint32_t vdev_id); + +void sme_set_tspec_uapsd_mask_per_session(struct mac_context *mac_ctx, + struct mac_ts_info *ts_info, + uint8_t session_id); + +QDF_STATUS sme_ps_start_uapsd(mac_handle_t mac_handle, uint32_t session_id); +QDF_STATUS sme_set_ps_host_offload(mac_handle_t mac_handle, + struct sir_host_offload_req *request, + uint8_t session_id); + +#ifdef WLAN_NS_OFFLOAD +QDF_STATUS sme_set_ps_ns_offload(mac_handle_t mac_handle, + struct sir_host_offload_req *request, + uint8_t session_id); + +#endif /* WLAN_NS_OFFLOAD */ +/* / Post a message to PE module */ +QDF_STATUS sme_post_pe_message(struct mac_context *mac_ctx, + struct scheduler_msg *pMsg); + +/** + * sme_ps_enable_auto_ps_timer(): Enable power-save auto timer with timeout + * @mac_handle: Opaque handle to the global MAC context + * @session_id: adapter session Id + * @timeout: timeout period in ms + * + * Returns: QDF_STATUS + */ +QDF_STATUS sme_ps_enable_auto_ps_timer(mac_handle_t mac_handle, + uint32_t sessionId, uint32_t timeout); +QDF_STATUS sme_ps_disable_auto_ps_timer(mac_handle_t mac_handle, + uint32_t sessionId); + +QDF_STATUS sme_ps_open(mac_handle_t mac_handle); + +QDF_STATUS sme_ps_open_per_session(mac_handle_t mac_handle, + uint32_t session_id); + +void sme_auto_ps_entry_timer_expired(void *ps_param); +QDF_STATUS sme_ps_close(mac_handle_t mac_handle); +QDF_STATUS sme_ps_close_per_session(mac_handle_t mac_handle, + uint32_t session_id); +#endif /* #if !defined(__SME_POWER_SAVE_API_H) */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_qos_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_qos_api.h new file mode 100644 index 0000000000..09d4993f15 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_qos_api.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2014-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SME_QOSAPI_H) +#define __SME_QOSAPI_H + +/** + * \file sme_qos_api.h + * + * \brief prototype for SME QoS APIs + */ + +/* Include Files */ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_global.h" +#include "sir_api.h" + +/* Pre-processor Definitions */ +#define SME_QOS_UAPSD_VO 0x01 +#define SME_QOS_UAPSD_VI 0x02 +#define SME_QOS_UAPSD_BE 0x08 +#define SME_QOS_UAPSD_BK 0x04 + +/* Enumeration of the various QoS status types that would be reported to HDD */ +enum sme_qos_statustype { + /* + * async: once PE notifies successful TSPEC negotiation, or CSR notifies + * for successful reassoc, notifies HDD with current QoS Params + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND = 0, + /* sync: only when App asked for APSD & it's already set with ACM = 0 */ + SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY, + /* sync or async: in case of async notify HDD with current QoS Params */ + SME_QOS_STATUS_SETUP_FAILURE_RSP, + /* sync */ + SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP, + /* sync: AP doesn't support QoS (WMM) */ + SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP, + /* sync: either req has been sent down to PE or just buffered in SME */ + SME_QOS_STATUS_SETUP_REQ_PENDING_RSP, + /* + * async: in case of flow aggregation, if the new TSPEC negotiation + * is successful, OR, notify existing flows that TSPEC is modified with + * current QoS Params + */ + SME_QOS_STATUS_SETUP_MODIFIED_IND, + /* sync: no APSD asked for & ACM = 0 */ + SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode right away + * (QDF_STATUS_PMC_PENDING) + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode at all + * (QDF_STATUS_E_FAILURE) + */ + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED, + /* + * sync: req has been sent down to PE in case of delts or addts + * for remain flows, OR if the AC doesn't have APSD or ACM + * async: once the downgrade req for QoS params is successful + */ + SME_QOS_STATUS_RELEASE_SUCCESS_RSP = 100, + /* sync or async: in case of async notify HDD with current QoS Param */ + SME_QOS_STATUS_RELEASE_FAILURE_RSP, + /* async: AP sent DELTS indication */ + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + /* + * sync: an addts req has been sent down to PE to downgrade the + * QoS params or just buffered in SME + */ + SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP, + /* sync */ + SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP, + /* + * async: for QoS modify request if modification is successful, + * notifies HDD with current QoS Params + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND = 200, + /* sync: only when App asked for APSD & it's already set with ACM = 0 */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY, + /* sync or async: in case of async notify HDD with current QoS Param */ + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP, + /* sync: either req has been sent down to PE or just buffered in SME */ + SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP, + /* sync: no APSD asked for & ACM = 0 */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP, + /* sync */ + SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode right away + * (QDF_STATUS_PMC_PENDING) + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_PENDING, + /* + * async: In case of UAPSD, once PE notifies successful TSPEC + * negotiation, or CSR notifies for successful reassoc to SME-QoS, + * notify HDD if PMC can't put the module in UAPSD mode at all + * (QDF_STATUS_E_FAILURE) + */ + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED, + /* sync: STA is handing off to a new AP */ + SME_QOS_STATUS_HANDING_OFF = 300, + /* async:powersave mode changed by PMC from UAPSD to Full power */ + SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND = 400, + /* async:powersave mode changed by PMC from Full power to UAPSD */ + SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, + +}; + +#define WLAN_MAX_DSCP 0x3f + +/* + * Enumeration of the various User priority (UP) types + * From 802.1D/802.11e/WMM specifications (all refer to same table) + */ +enum sme_qos_wmmuptype { + SME_QOS_WMM_UP_BE = 0, + SME_QOS_WMM_UP_BK = 1, + SME_QOS_WMM_UP_RESV = 2, /* Reserved */ + SME_QOS_WMM_UP_EE = 3, + SME_QOS_WMM_UP_CL = 4, + SME_QOS_WMM_UP_VI = 5, + SME_QOS_WMM_UP_VO = 6, + SME_QOS_WMM_UP_NC = 7, + SME_QOS_WMM_UP_MAX +}; + +/* + * Enumeration of the various TSPEC ack policies. + * From 802.11 WMM specification + */ +enum sme_qos_wmmack_policytype { + SME_QOS_WMM_TS_ACK_POLICY_NORMAL_ACK = 0, + SME_QOS_WMM_TS_ACK_POLICY_RESV1 = 1, + SME_QOS_WMM_TS_ACK_POLICY_RESV2 = 2, /* Reserved */ + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK = 3, + +}; + +/* + * TS Info field in the WMM TSPEC + * See suggestive values above + */ +struct sme_qos_wmmts_infotype { + uint8_t burst_size_defn; + enum sme_qos_wmmack_policytype ack_policy; + enum sme_qos_wmmuptype up; /* User priority */ + uint8_t psb; /* power-save bit */ + enum sme_qos_wmm_dir_type direction; /* Direction */ + uint8_t tid; /* TID : To be filled up by SME-QoS */ +}; + +/* The WMM TSPEC Element (from the WMM spec)*/ +struct sme_qos_wmmtspecinfo { + struct sme_qos_wmmts_infotype ts_info; + uint16_t nominal_msdu_size; + uint16_t maximum_msdu_size; + uint32_t min_service_interval; + uint32_t max_service_interval; + uint32_t inactivity_interval; + uint32_t suspension_interval; + uint32_t svc_start_time; + uint32_t min_data_rate; + uint32_t mean_data_rate; + uint32_t peak_data_rate; + uint32_t max_burst_size; + uint32_t delay_bound; + uint32_t min_phy_rate; + uint16_t surplus_bw_allowance; + uint16_t medium_time; +}; + +static inline enum sme_qos_wmmuptype qca_wlan_ac_to_sme_qos(u8 priority) +{ + switch (priority) { + case QCA_WLAN_AC_BE: + return SME_QOS_WMM_UP_BE; + case QCA_WLAN_AC_BK: + return SME_QOS_WMM_UP_BK; + case QCA_WLAN_AC_VI: + return SME_QOS_WMM_UP_VI; + case QCA_WLAN_AC_VO: + return SME_QOS_WMM_UP_VO; + default: + return SME_QOS_WMM_UP_BE; + } +} + +/* External APIs */ +typedef QDF_STATUS (*sme_QosCallback)(mac_handle_t mac_handle, void *HDDcontext, + struct sme_qos_wmmtspecinfo *pCurrentQoSInfo, + enum sme_qos_statustype status, uint32_t QosFlowID); +enum sme_qos_statustype sme_qos_setup_req(mac_handle_t mac_handle, + uint32_t sessionId, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + enum sme_qos_wmmuptype UPType, + uint32_t *pQosFlowID); +enum sme_qos_statustype sme_qos_modify_req(mac_handle_t mac_handle, + struct sme_qos_wmmtspecinfo *pQoSInfo, uint32_t QosFlowID); +enum sme_qos_statustype sme_qos_release_req(mac_handle_t mac_handle, + uint8_t session_id, + uint32_t QosFlowID); +bool sme_qos_is_ts_info_ack_policy_valid(mac_handle_t mac_handle, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint8_t sessionId); +void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff); +QDF_STATUS sme_update_dsc_pto_up_mapping(mac_handle_t mac_handle, + enum sme_qos_wmmuptype *dscpmapping, uint8_t sessionId); + +QDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(struct mac_context *mac_ctx, + uint32_t session_id); +QDF_STATUS sme_offload_qos_process_into_uapsd_mode(struct mac_context *mac_ctx, + uint32_t session_id); + + +#endif /* #if !defined( __SME_QOSAPI_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_qos_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_qos_internal.h new file mode 100644 index 0000000000..469c4ca460 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_qos_internal.h @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2014-2019, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SMEQOSINTERNAL_H) +#define __SMEQOSINTERNAL_H + +/** + * \file sme_qos_internal.h + * + * \brief prototype for SME QoS APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sme_qos_api.h" +#include "sme_internal.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +#define SME_QOS_AP_SUPPORTS_APSD 0x80 + +/*--------------------------------------------------------------------------- + Enumeration of the various CSR event indication types that would be reported + by CSR + ---------------------------------------------------------------------------*/ +typedef enum { + SME_QOS_CSR_JOIN_REQ = 0, + SME_QOS_CSR_ASSOC_COMPLETE, + SME_QOS_CSR_REASSOC_REQ, + SME_QOS_CSR_REASSOC_COMPLETE, + SME_QOS_CSR_REASSOC_FAILURE, + SME_QOS_CSR_DISCONNECT_REQ, + SME_QOS_CSR_DISCONNECT_IND, + SME_QOS_CSR_HANDOFF_ASSOC_REQ, + SME_QOS_CSR_HANDOFF_COMPLETE, + SME_QOS_CSR_PREAUTH_SUCCESS_IND, + SME_QOS_CSR_SET_KEY_SUCCESS_IND, + SME_QOS_CSR_DISCONNECT_ROAM_COMPLETE, +} sme_qos_csr_event_indType; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +typedef enum { + SME_QOS_DIAG_ADDTS_REQ = 0, + SME_QOS_DIAG_ADDTS_RSP, + SME_QOS_DIAG_DELTS +} sme_QosDiagQosEventSubtype; + +typedef enum { + SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED = 0, + SME_QOS_DIAG_ADDTS_INVALID_PARAMS, + SME_QOS_DIAG_ADDTS_RESERVED, + SME_QOS_DIAG_ADDTS_REFUSED, + SME_QOS_DIAG_USER_REQUESTED, + SME_QOS_DIAG_DELTS_IND_FROM_AP, + +} sme_QosDiagQosEventReasonCode; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +/*--------------------------------------------------------------------------- + The association information structure to be passed by CSR after assoc or + reassoc is done + ---------------------------------------------------------------------------*/ +typedef struct { + struct bss_description *bss_desc; + uint8_t uapsd_mask; +} sme_QosAssocInfo; + +/*-------------------------------------------------------------------------- + External APIs for CSR - Internal to SME + ------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_open(struct mac_context *mac); +QDF_STATUS sme_qos_close(struct mac_context *mac); +QDF_STATUS sme_qos_msg_processor(struct mac_context *mac, uint16_t msg_type, + void *msg_buf); + +/*-------------------------------------------------------------------------- + Internal APIs for CSR + ------------------------------------------------------------------------*/ +QDF_STATUS sme_qos_csr_event_ind(struct mac_context *mac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info); +uint8_t sme_qos_get_acm_mask(struct mac_context *mac, + struct bss_description *pSirBssDesc, tDot11fBeaconIEs *pIes); +#ifdef FEATURE_WLAN_ESE +uint8_t sme_qos_ese_retrieve_tspec_info(struct mac_context *mac, uint8_t sessionId, + tTspecInfo * pTspecInfo); +#endif + +#endif /* #if !defined( __SMEQOSINTERNAL_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_rrm_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_rrm_api.h new file mode 100644 index 0000000000..3f8ab5a568 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_rrm_api.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2014-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SMERRMAPI_H) +#define __SMERRMAPI_H + +/** + * \file sme_rrm_api.h + * + * \brief prototype for SME RRM APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "ani_global.h" +#include "sir_api.h" +#include "sme_internal.h" +#include "sme_rrm_internal.h" + +QDF_STATUS sme_rrm_msg_processor(struct mac_context *mac, uint16_t msg_type, + void *msg_buf); +QDF_STATUS rrm_close(struct mac_context *mac); +QDF_STATUS rrm_open(struct mac_context *mac); +QDF_STATUS sme_rrm_neighbor_report_request(struct mac_context *mac, + uint8_t sessionId, tpRrmNeighborReq pNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo); +QDF_STATUS sme_rrm_process_beacon_report_req_ind(struct mac_context *mac, + void *msg_buf); + +/** + * rrm_start() - start the RRM module + * @mac_ctx: The handle returned by mac_open. + * + * Return: QDF_STATUS + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS rrm_start(struct mac_context *mac_ctx); + +/** + * rrm_stop() - stop the RRM module + * @mac_ctx: The handle returned by mac_open. + * + * Return: QDF_STATUS + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS rrm_stop(struct mac_context *mac_ctx); + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_rrm_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_rrm_internal.h new file mode 100644 index 0000000000..1ff958a44c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_rrm_internal.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011-2012, 2014-2018, 2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#if !defined(__SMERRMINTERNAL_H) +#define __SMERRMINTERNAL_H + +/** + * \file sme_rrm_internal.h + * + * \brief prototype for SME RRM APIs + */ + +/*-------------------------------------------------------------------------- + Include Files + ------------------------------------------------------------------------*/ +#include "qdf_lock.h" +#include "qdf_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "rrm_global.h" + +/*-------------------------------------------------------------------------- + Type declarations + ------------------------------------------------------------------------*/ +typedef struct sRrmNeighborReportDesc { + tListElem List; + tSirNeighborBssDescription *pNeighborBssDescription; + uint32_t roamScore; + uint8_t sessionId; +} tRrmNeighborReportDesc, *tpRrmNeighborReportDesc; + +typedef void (*NeighborReportRspCallback)(void *context, + QDF_STATUS qdf_status); + +typedef struct sRrmNeighborRspCallbackInfo { + uint32_t timeout; /* in ms.. min value is 10 (10ms) */ + NeighborReportRspCallback neighborRspCallback; + void *neighborRspCallbackContext; +} tRrmNeighborRspCallbackInfo, *tpRrmNeighborRspCallbackInfo; + +typedef struct sRrmNeighborRequestControlInfo { + /* To check whether a neighbor req is already sent & response pending */ + bool isNeighborRspPending; + qdf_mc_timer_t neighborRspWaitTimer; + tRrmNeighborRspCallbackInfo neighborRspCallbackInfo; +} tRrmNeighborRequestControlInfo, *tpRrmNeighborRequestControlInfo; + +/** + * enum rrm_measurement_type: measurement type + * @RRM_CHANNEL_LOAD: measurement type for channel load req + * @RRM_BEACON_REPORT: measurement type for beacon report request + */ +enum rrm_measurement_type { + RRM_CHANNEL_LOAD = 0, + RRM_BEACON_REPORT = 1, +}; + +/** + * enum channel_load_req_info: channel load request info + * @channel: channel for which the host receives the channel load req from AP + * @req_chan_width: channel width for which the host receives the channel load + * req from AP + * @rrm_scan_tsf: to store jiffies for RRM scan to process chan load req + * @bw_ind: Contains info for Bandwidth Indication IE + * @wide_bw: Contains info for Wide Bandwidth Channel IE + */ +struct channel_load_req_info { + uint8_t channel; + qdf_freq_t req_freq; + enum phy_ch_width req_chan_width; + qdf_time_t rrm_scan_tsf; + struct bw_ind_element bw_ind; + struct wide_bw_chan_switch wide_bw; +}; + +typedef struct sRrmSMEContext { + uint16_t token; + struct qdf_mac_addr sessionBssId; + uint8_t regClass; + uint8_t measurement_idx; + enum rrm_measurement_type measurement_type; + struct channel_load_req_info chan_load_req_info; + /* list of all channels to be measured. */ + tCsrChannelInfo channelList; + uint8_t currentIndex; + /* SSID used in the measuring beacon report. */ + tAniSSID ssId; + tSirMacAddr bssId; /* bssid used for beacon report measurement. */ + /* Randomization interval to be used in subsequent measurements. */ + uint16_t randnIntvl; + uint16_t duration[SIR_ESE_MAX_MEAS_IE_REQS]; + uint8_t measMode[SIR_ESE_MAX_MEAS_IE_REQS]; + uint32_t scan_id; + tDblLinkList neighborReportCache; + tRrmNeighborRequestControlInfo neighborReqControlInfo; + +#ifdef FEATURE_WLAN_ESE + tCsrEseBeaconReq eseBcnReqInfo; + bool eseBcnReqInProgress; +#endif /* FEATURE_WLAN_ESE */ + tRrmMsgReqSource msgSource; + wlan_scan_requester req_id; +} tRrmSMEContext, *tpRrmSMEContext; + +typedef struct sRrmNeighborReq { + uint8_t no_ssid; + tSirMacSSid ssid; + bool neighbor_report_offload; +} tRrmNeighborReq, *tpRrmNeighborReq; + +/** + * sme_rrm_issue_scan_req() - To issue rrm scan request + * @mac_ctx: pointer to mac context + * + * This routine is called to issue rrm scan request + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_rrm_issue_scan_req(struct mac_context *mac_ctx, uint8_t idx); + +#endif /* #if !defined( __SMERRMINTERNAL_H ) */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_trace.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_trace.h new file mode 100644 index 0000000000..ca7f654d9b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/sme_trace.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * \sme_trace.h + * + * \brief definition for trace related APIs + */ + +#ifndef __SME_TRACE_H__ +#define __SME_TRACE_H__ + +#include "mac_trace.h" + +#define NO_SESSION 0xFF +enum smecodetype { + TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, + TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, + TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN, + TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, + TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT, + TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE, + TRACE_CODE_SME_RX_HDD_ROAM_REASSOC, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, + TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE, + TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE, + TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, + TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS, + TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE, + TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE, + TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE, + TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE, + TRACE_CODE_SME_RX_HDD_SIGNAL_POWER_EVENT, + TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER, + TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER, + TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED, + TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER, + TRACE_CODE_SME_RX_HDD_REQUEST_BMPS, + TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG, + TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY, + TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN, + TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN, + TRACE_CODE_SME_RX_HDD_ENTER_WOWL, + TRACE_CODE_SME_RX_HDD_EXIT_WOWL, + TRACE_CODE_SME_RX_HDD_SET_KEY, + TRACE_CODE_SME_RX_HDD_REMOVE_KEY, + TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE, + TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY, + TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ, + TRACE_CODE_SME_RX_HDD_DBG_READREG, + TRACE_CODE_SME_RX_HDD_DBG_WRITEREG, + TRACE_CODE_SME_RX_HDD_DBG_READMEM, + TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM, + TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, + TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD, + TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD, + TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD, + TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN, + TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, + TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN, + TRACE_CODE_SME_RX_HDD_SEND_ACTION, + TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN, + TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL, + TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND, + TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ, +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2, +#endif + TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW, + TRACE_CODE_SME_RX_HDD_SET_TXPOW, + TRACE_CODE_SME_RX_HDD_SET_TMLEVEL, + TRACE_CODE_SME_RX_HDD_CAPS_EXCH, + TRACE_CODE_SME_RX_HDD_DISABLE_CAP, + TRACE_CODE_SME_RX_HDD_GET_DEFCCNV, + TRACE_CODE_SME_RX_HDD_GET_CURCC, + TRACE_CODE_SME_RX_HDD_RESET_PW5G, + TRACE_CODE_SME_RX_HDD_UPDATE_RP5G, + TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND, + TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF, + TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF, + TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED, + TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE, + TRACE_CODE_SME_RX_HDD_SET_SCANCTRL, + TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES, + TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME, + TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ, + TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA, +#ifdef FEATURE_WLAN_TDLS + TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM, + TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ, + TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME, + TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA, + TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA, + TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA, +#endif + TRACE_CODE_SME_RX_HDD_PREF_NET_LIST, + TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE, + TRACE_CODE_SME_RX_HDD_SEND_MGMT_TX, + /* + * New trace commands to be added before this comment not at the end + * Trace codes for SME commands + */ + TRACE_CODE_SME_COMMAND = 250, + TRACE_CODE_SME_TX_WMA_MSG, + TRACE_CODE_SME_RX_WMA_MSG, +}; + +void sme_trace_init(struct mac_context *mac); +#endif /* __SME_TRACE_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h new file mode 100644 index 0000000000..4702eb2ce9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/inc/wlan_ps_wow_diag.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_PS_WOW_DIAG_H_ +#define _WLAN_PS_WOW_DIAG_H_ + +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + +typedef enum { + WLAN_BMPS_ENTER_REQ = 0, + WLAN_UAPSD_START_REQ = 1, + WLAN_UAPSD_STOP_REQ = 2, + WLAN_ENTER_STANDBY_REQ = 3, + WLAN_ENTER_DEEP_SLEEP_REQ = 4, + WLAN_START_BMPS_AUTO_TIMER_REQ = 5, + WLAN_STOP_BMPS_AUTO_TIMER_REQ = 6, + WLAN_ENTER_FULL_POWER_REQ = 7, + WLAN_PMC_CURRENT_STATE = 8, + WLAN_PS_MODE_ENABLE_REQ = 9, + WLAN_PS_MODE_DISABLE_REQ = 10, + WLAN_WINMOB_D_POWER_STATE = 11, + WLAN_BMPS_DTIM_PERIOD = 12, + WLAN_BMPS_FINAL_LI = 13, + WLAN_BMPS_SET_CONFIG = 14, + +} wlan_ps_evt_subtype_t; + +/* maps directly to eRequestFullPowerReason */ +typedef enum { + /* PE received a MAX_MISSED_BEACON_IND */ + WLAN_MISSED_BEACON_IND_RCVD, + /* PE received a SIR_HAL_BMPS_STATUS_IND */ + WLAN_BMPS_STATUS_IND_RCVD, + /* BMPS mode was disabled by HDD in SME */ + WLAN_BMPS_MODE_DISABLED, + /* Link has been disconnected requested by HDD */ + WLAN_LINK_DISCONNECTED_BY_HDD, + /* Disconnect due to linklost or requested by peer */ + WLAN_LINK_DISCONNECTED_BY_OTHER, + /* HDD request full power for some reason */ + WLAN_FULL_PWR_NEEDED_BY_HDD, + /* BAP request full power for BT_AMP */ + WLAN_FULL_PWR_NEEDED_BY_BAP, + /* CSR requests full power */ + WLAN_FULL_PWR_NEEDED_BY_CSR, + /* QOS requests full power */ + WLAN_FULL_PWR_NEEDED_BY_QOS, + /* No specific reason. General reason code */ + WLAN_REASON_OTHER +} wlan_ps_full_power_request_reason_t; + +/* maps directly to ePmcState */ +typedef enum { + WLAN_PMC_STOPPED, /* PMC is stopped */ + WLAN_PMC_FULL_POWER, /* full power */ + WLAN_PMC_LOW_POWER, /* low power */ + WLAN_PMC_REQUEST_BMPS, /* requesting BMPS */ + WLAN_PMC_BMPS, /* in BMPS */ + WLAN_PMC_REQUEST_FULL_POWER, /* requesting full power */ + WLAN_PMC_REQUEST_START_UAPSD, /* requesting Start UAPSD */ + WLAN_PMC_REQUEST_STOP_UAPSD, /* requesting Stop UAPSD */ + WLAN_PMC_UAPSD, /* in UAPSD */ + WLAN_PMC_REQUEST_STANDBY, /* requesting standby mode */ + WLAN_PMC_STANDBY, /* in standby mode */ + WLAN_PMC_REQUEST_ENTER_WOWL, /* requesting enter WOWL */ + WLAN_PMC_REQUEST_EXIT_WOWL, /* requesting exit WOWL */ + WLAN_PMC_WOWL /* Chip in WOWL mode */ +} wlan_ps_pmc_current_state_t; + +/* maps directly to ePmcPowerSavingMode */ +typedef enum { + WLAN_IDLE_MODE_POWER_SAVE, /* Idle Mode Power Save (IMPS) */ + WLAN_BEACON_MODE_POWER_SAVE, /* Beacon Mode Power Save (BMPS) */ + WLAN_SPATIAL_MULTIPLEX_POWER_SAVE, /* Spatial Multiplexing Power Save */ + WLAN_UAPSD_MODE_POWER_SAVE, /* Unscheduled Auto PS Delivery Mode */ + WLAN_STANDBY_MODE_POWER_SAVE, /* Standby Power Save Mode */ + WLAN_WOWL_MODE_POWER_SAVE /* Wake-on-Wireless Power Save Mode */ +} wlan_ps_enable_disable_ps_mode_t; + +typedef enum { + WLAN_D0, + WLAN_D1, + WLAN_D2, + WLAN_D3, + WLAN_D4 +} wlan_ps_winmob_d_power_state_t; + +typedef enum { + WLAN_WOW_ENTER_REQ = 0, + WLAN_WOW_EXIT_REQ = 1, + WLAN_WOW_DEL_PTRN_REQ = 2, + WLAN_WOW_WAKEUP = 3 +} wlan_ps_wow_evt_subtype_t; + +typedef enum { + WLAN_WOW_TYPE_NONE, + WLAN_WOW_TYPE_MAGIC_PKT_ONLY, + WLAN_WOW_TYPE_PTRN_BYTE_MATCH_ONLY, + WLAN_WOW_TYPE_MAGIC_PKT_PTRN_BYTE_MATCH, +} wlan_ps_wow_type_t; + +typedef enum { + WLAN_WOW_MAGIC_PKT_MATCH, + WLAN_WOW_PTRN_BYTE_MATCH +} wlan_ps_wos_wakeup_cause_t; + +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#endif /* _WLAN_PS_WOW_DIAG_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_api.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_api.c new file mode 100644 index 0000000000..8ea404c4fa --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_api.c @@ -0,0 +1,17103 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: sme_api.c + * + * Definitions for SME APIs + */ + +/* Include Files */ +#include +#include +#include "sme_api.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "csr_internal.h" +#include "wma_types.h" +#include "wma_if.h" +#include "wma.h" +#include "wma_fips_api.h" +#include "wma_fw_state.h" +#include "qdf_trace.h" +#include "sme_trace.h" +#include "qdf_types.h" +#include "qdf_util.h" +#include "qdf_trace.h" +#include "cds_utils.h" +#include "sap_api.h" +#include "mac_trace.h" +#include "cds_regdomain.h" +#include "sme_power_save_api.h" +#include "wma.h" +#include "wma_twt.h" +#include "sch_api.h" +#include "sme_nan_datapath.h" +#include "csr_api.h" +#include "wlan_reg_services_api.h" +#include +#include "wlan_reg_ucfg_api.h" +#include "ol_txrx.h" +#include "wifi_pos_api.h" +#include "net/cfg80211.h" +#include "wifi_pos_pasn_api.h" +#include +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_main.h" +#include "cfg_ucfg_api.h" +#include "wlan_fwol_ucfg_api.h" +#include +#include "wlan_crypto_global_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_psoc_mlme_api.h" +#include "mac_init_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_cm_tgt_if_tx_api.h" +#include "wlan_cm_api.h" +#include "wlan_mlme_twt_public_struct.h" +#include "wlan_mlme_twt_api.h" +#include "wlan_mlme_twt_ucfg_api.h" +#include "parser_api.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include +#include "wlan_cm_roam_ucfg_api.h" +#include +#include +#include +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_wifi_pos_interface.h" +#include "wlan_cp_stats_mc_ucfg_api.h" +#include "wlan_psoc_mlme_ucfg_api.h" +#include +#include "wma_eht.h" +#include "wlan_policy_mgr_ll_sap.h" +#include "wlan_vdev_mgr_ucfg_api.h" +#include "wlan_vdev_mlme_main.h" +#include "wlan_tdls_api.h" + +static QDF_STATUS init_sme_cmd_list(struct mac_context *mac); + +static void sme_disconnect_connected_sessions(struct mac_context *mac, + enum wlan_reason_code reason); + +static QDF_STATUS sme_handle_generic_change_country_code(struct mac_context *mac, + void *msg_buf); + +static QDF_STATUS sme_process_nss_update_resp(struct mac_context *mac, uint8_t *msg); + +/* Channel Change Response Indication Handler */ +static QDF_STATUS sme_process_channel_change_resp(struct mac_context *mac, + uint16_t msg_type, void *msg_buf); + +static QDF_STATUS sme_stats_ext_event(struct mac_context *mac, + struct stats_ext_event *msg); + +static QDF_STATUS sme_fw_state_resp(struct mac_context *mac); + +/* Internal SME APIs */ +QDF_STATUS sme_acquire_global_lock(struct sme_context *sme) +{ + if (!sme) + return QDF_STATUS_E_INVAL; + + return qdf_mutex_acquire(&sme->sme_global_lock); +} + +QDF_STATUS sme_release_global_lock(struct sme_context *sme) +{ + if (!sme) + return QDF_STATUS_E_INVAL; + + return qdf_mutex_release(&sme->sme_global_lock); +} + +struct mac_context *sme_get_mac_context(void) +{ + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + return NULL; + + mac_ctx = MAC_CONTEXT(mac_handle); + + return mac_ctx; +} + +/** + * sme_process_set_hw_mode_resp() - Process set HW mode response + * @mac: Global MAC pointer + * @msg: HW mode response + * + * Processes the HW mode response and invokes the HDD callback + * to process further + */ +static QDF_STATUS sme_process_set_hw_mode_resp(struct mac_context *mac, uint8_t *msg) +{ + tListElem *entry; + tSmeCmd *command = NULL; + bool found; + policy_mgr_pdev_set_hw_mode_cback callback = NULL; + struct sir_set_hw_mode_resp *param; + enum policy_mgr_conn_update_reason reason; + + uint32_t session_id; + uint32_t request_id; + + param = (struct sir_set_hw_mode_resp *)msg; + if (!param) { + sme_err("HW mode resp param is NULL"); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (!entry) { + sme_err("No cmd found in active list"); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sme_err("Base address is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_hw_mode != command->command) { + sme_err("Command mismatch!"); + return QDF_STATUS_E_FAILURE; + } + + callback = command->u.set_hw_mode_cmd.set_hw_mode_cb; + reason = command->u.set_hw_mode_cmd.reason; + session_id = command->u.set_hw_mode_cmd.session_id; + request_id = command->u.set_hw_mode_cmd.request_id; + + sme_debug("reason: %d session: %d", + command->u.set_hw_mode_cmd.reason, + command->u.set_hw_mode_cmd.session_id); + + if (!callback) { + sme_err("Callback does not exist"); + goto end; + } + + if (!param) { + sme_err("Callback failed since HW mode params is NULL"); + goto end; + } + + /* Irrespective of the reason for which the hw mode change request + * was issued, the policy manager connection table needs to be updated + * with the new vdev-mac id mapping, tx/rx spatial streams etc., if the + * set hw mode was successful. + */ + callback(param->status, + param->cfgd_hw_mode_index, + param->num_vdev_mac_entries, + param->vdev_mac_map, + command->u.set_hw_mode_cmd.next_action, + command->u.set_hw_mode_cmd.reason, + command->u.set_hw_mode_cmd.session_id, + command->u.set_hw_mode_cmd.context, + command->u.set_hw_mode_cmd.request_id); + if (!CSR_IS_SESSION_VALID(mac, session_id)) { + sme_err("session %d is invalid", session_id); + goto end; + } + + if (reason == POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA) { + sme_debug("Continue channel switch for STA on vdev %d", + session_id); + csr_sta_continue_csa(mac, session_id); + } + + if (reason == POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_SAP) { + sme_debug("Continue channel switch for SAP on vdev %d", + session_id); + csr_csa_restart(mac, session_id); + } + + if (reason == POLICY_MGR_UPDATE_REASON_STA_CONNECT || + reason == POLICY_MGR_UPDATE_REASON_LFR2_ROAM) { + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + sme_debug("Continue connect/reassoc on vdev %d reason %d status %d cm_id 0x%x", + session_id, reason, param->status, request_id); + if (param->status == SET_HW_MODE_STATUS_OK || + param->status == SET_HW_MODE_STATUS_ALREADY) + status = QDF_STATUS_SUCCESS; + + wlan_cm_handle_hw_mode_change_resp(mac->pdev, session_id, + request_id, + status); + } + +end: + found = csr_nonscan_active_ll_remove_entry(mac, entry, + LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the available command list */ + csr_release_command(mac, command); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_process_hw_mode_trans_ind() - Process HW mode transition indication + * @mac: Global MAC pointer + * @msg: HW mode transition response + * + * Processes the HW mode transition indication and invoke the HDD callback + * to process further + */ +static QDF_STATUS sme_process_hw_mode_trans_ind(struct mac_context *mac, + uint8_t *msg) +{ + struct cm_hw_mode_trans_ind *param; + + param = (struct cm_hw_mode_trans_ind *)msg; + if (!param) { + sme_err("HW mode trans ind param is NULL"); + return QDF_STATUS_E_FAILURE; + } + + policy_mgr_hw_mode_transition_cb(param->old_hw_mode_index, + param->new_hw_mode_index, + param->num_vdev_mac_entries, + param->vdev_mac_map, param->num_freq_map, param->mac_freq_map, + mac->psoc); + + return QDF_STATUS_SUCCESS; +} + +/** + * free_sme_cmds() - This function frees memory allocated for SME commands + * @mac_ctx: Pointer to Global MAC structure + * + * This function frees memory allocated for SME commands + * + * @Return: void + */ +static void free_sme_cmds(struct mac_context *mac_ctx) +{ + uint32_t idx; + + if (!mac_ctx->sme.sme_cmd_buf_addr) + return; + + for (idx = 0; idx < mac_ctx->sme.sme_cmd_count; idx++) + qdf_mem_free(mac_ctx->sme.sme_cmd_buf_addr[idx]); + + qdf_mem_free(mac_ctx->sme.sme_cmd_buf_addr); + mac_ctx->sme.sme_cmd_buf_addr = NULL; +} + +static QDF_STATUS init_sme_cmd_list(struct mac_context *mac) +{ + QDF_STATUS status; + tSmeCmd *cmd; + uint32_t cmd_idx; + uint32_t sme_cmd_ptr_ary_sz; + + mac->sme.sme_cmd_count = SME_TOTAL_COMMAND; + + status = csr_ll_open(&mac->sme.sme_cmd_freelist); + if (!QDF_IS_STATUS_SUCCESS(status)) + goto end; + + /* following pointer contains array of pointers for tSmeCmd* */ + sme_cmd_ptr_ary_sz = sizeof(void *) * mac->sme.sme_cmd_count; + mac->sme.sme_cmd_buf_addr = qdf_mem_malloc(sme_cmd_ptr_ary_sz); + if (!mac->sme.sme_cmd_buf_addr) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + status = QDF_STATUS_SUCCESS; + for (cmd_idx = 0; cmd_idx < mac->sme.sme_cmd_count; cmd_idx++) { + /* + * Since total size of all commands together can be huge chunk + * of memory, allocate SME cmd individually. These SME CMDs are + * moved between pending and active queues. And these freeing of + * these queues just manipulates the list but does not actually + * frees SME CMD pointers. Hence store each SME CMD address in + * the array, sme.sme_cmd_buf_addr. This will later facilitate + * freeing up of all SME CMDs with just a for loop. + */ + cmd = qdf_mem_malloc(sizeof(*cmd)); + if (!cmd) { + status = QDF_STATUS_E_NOMEM; + free_sme_cmds(mac); + goto end; + } + mac->sme.sme_cmd_buf_addr[cmd_idx] = cmd; + csr_ll_insert_tail(&mac->sme.sme_cmd_freelist, + &cmd->Link, LL_ACCESS_LOCK); + } + +end: + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("Failed to initialize sme command list: %d", status); + + return status; +} + +void sme_release_command(struct mac_context *mac_ctx, tSmeCmd *sme_cmd) +{ + sme_cmd->command = eSmeNoCommand; + csr_ll_insert_tail(&mac_ctx->sme.sme_cmd_freelist, &sme_cmd->Link, + LL_ACCESS_LOCK); +} + +static QDF_STATUS free_sme_cmd_list(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_ll_close(&mac->sme.sme_cmd_freelist); + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) + goto done; + + free_sme_cmds(mac); + + status = sme_release_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) + sme_err("Failed to release the lock status: %d", status); +done: + return status; +} + +static void dump_csr_command_info(struct mac_context *mac, tSmeCmd *pCmd) +{ + switch (pCmd->command) { + case eSmeCommandRoam: + sme_debug("roam command reason is %d", + pCmd->u.roamCmd.roamReason); + break; + + case eSmeCommandWmStatusChange: + sme_debug("WMStatusChange command type is %d", + pCmd->u.wmStatusChangeCmd.Type); + break; + + default: + sme_debug("default: Unhandled command %d", + pCmd->command); + break; + } +} + +tSmeCmd *sme_get_command_buffer(struct mac_context *mac) +{ + tSmeCmd *pRetCmd = NULL, *pTempCmd = NULL; + tListElem *pEntry; + static int sme_command_queue_full; + + pEntry = csr_ll_remove_head(&mac->sme.sme_cmd_freelist, LL_ACCESS_LOCK); + + /* If we can get another MS Msg buffer, then we are ok. Just + * link the entry onto the linked list. (We are using the + * linked list to keep track of the message buffers). + */ + if (pEntry) { + pRetCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* reset when free list is available */ + sme_command_queue_full = 0; + } else { + int idx = 1; + + /* Cannot change pRetCmd here since it needs to return later. */ + pEntry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (pEntry) + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + + sme_err("Out of command buffer.... command (0x%X) stuck", + (pTempCmd) ? pTempCmd->command : eSmeNoCommand); + if (pTempCmd) { + if (eSmeCsrCommandMask & pTempCmd->command) + /* CSR command is stuck. See what the reason + * code is for that command + */ + dump_csr_command_info(mac, pTempCmd); + } /* if(pTempCmd) */ + + /* dump what is in the pending queue */ + pEntry = + csr_nonscan_pending_ll_peek_head(mac, + LL_ACCESS_NOLOCK); + while (pEntry && !sme_command_queue_full) { + pTempCmd = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + /* Print only 1st five commands from pending queue. */ + if (idx <= 5) + sme_err("Out of command buffer.... SME pending command #%d (0x%X)", + idx, pTempCmd->command); + idx++; + if (eSmeCsrCommandMask & pTempCmd->command) + /* CSR command is stuck. See what the reason + * code is for that command + */ + dump_csr_command_info(mac, pTempCmd); + pEntry = csr_nonscan_pending_ll_next(mac, pEntry, + LL_ACCESS_NOLOCK); + } + + if (mac->mlme_cfg->gen.fatal_event_trigger) + cds_flush_logs(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_HOST_DRIVER, + WLAN_LOG_REASON_SME_OUT_OF_CMD_BUF, + false, + mac->mlme_cfg->gen.self_recovery); + else + cds_trigger_recovery(QDF_GET_MSG_BUFF_FAILURE); + } + + /* memset to zero */ + if (pRetCmd) { + qdf_mem_zero((uint8_t *)&pRetCmd->command, + sizeof(pRetCmd->command)); + qdf_mem_zero((uint8_t *)&pRetCmd->vdev_id, + sizeof(pRetCmd->vdev_id)); + qdf_mem_zero((uint8_t *)&pRetCmd->u, sizeof(pRetCmd->u)); + } + + return pRetCmd; +} + +/** + * sme_ser_handle_active_cmd() - handle command activation callback from + * new serialization module + * @cmd: pointer to new serialization command + * + * This API is to handle command activation callback from new serialization + * callback + * + * Return: QDF_STATUS_SUCCESS + */ +static +QDF_STATUS sme_ser_handle_active_cmd(struct wlan_serialization_command *cmd) +{ + tSmeCmd *sme_cmd; + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool do_continue; + + if (!cmd) { + sme_err("No serialization command found"); + return QDF_STATUS_E_FAILURE; + } + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (mac_handle) + mac_ctx = MAC_CONTEXT(mac_handle); + else + return QDF_STATUS_E_FAILURE; + + sme_cmd = cmd->umac_cmd; + if (!sme_cmd) { + sme_err("No SME command found"); + return QDF_STATUS_E_FAILURE; + } + + switch (sme_cmd->command) { + case eSmeCommandRoam: + status = csr_roam_process_command(mac_ctx, sme_cmd); + break; + case eSmeCommandWmStatusChange: + csr_roam_process_wm_status_change_command(mac_ctx, + sme_cmd); + break; + + case eSmeCommandAddTs: + case eSmeCommandDelTs: +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + do_continue = qos_process_command(mac_ctx, sme_cmd); + if (do_continue) + status = QDF_STATUS_E_FAILURE; +#endif + break; + case e_sme_command_set_hw_mode: + csr_process_set_hw_mode(mac_ctx, sme_cmd); + break; + case e_sme_command_nss_update: + csr_process_nss_update_req(mac_ctx, sme_cmd); + break; + case e_sme_command_set_dual_mac_config: + csr_process_set_dual_mac_config(mac_ctx, sme_cmd); + break; + case e_sme_command_set_antenna_mode: + csr_process_set_antenna_mode(mac_ctx, sme_cmd); + break; + case e_sme_command_sap_ch_width_update: + csr_process_sap_ch_width_update(mac_ctx, sme_cmd); + break; + default: + /* something is wrong */ + sme_err("unknown command %d", sme_cmd->command); + status = QDF_STATUS_E_FAILURE; + break; + } + return status; +} + +static void sme_dump_peer_disconnect_timeout_info(tSmeCmd *sme_cmd) +{ + struct wmstatus_changecmd *wms_cmd; + struct qdf_mac_addr peer_macaddr = QDF_MAC_ADDR_ZERO_INIT; + struct qdf_mac_addr peer_mld_addr = QDF_MAC_ADDR_ZERO_INIT; + char mld_log_str[MAC_ADDR_DUMP_LEN] = {0}; + + if (sme_cmd->command == eSmeCommandRoam && + (sme_cmd->u.roamCmd.roamReason == eCsrForcedDisassocSta || + sme_cmd->u.roamCmd.roamReason == eCsrForcedDeauthSta)) { + qdf_mem_copy(peer_macaddr.bytes, sme_cmd->u.roamCmd.peerMac, + QDF_MAC_ADDR_SIZE); + if (!qdf_is_macaddr_zero(&sme_cmd->u.roamCmd.peer_mld_addr)) + qdf_copy_macaddr(&peer_mld_addr, + &sme_cmd->u.roamCmd.peer_mld_addr); + } else if (sme_cmd->command == eSmeCommandWmStatusChange) { + wms_cmd = &sme_cmd->u.wmStatusChangeCmd; + if (wms_cmd->Type == eCsrDisassociated) { + qdf_copy_macaddr( + &peer_macaddr, + &wms_cmd->u.DisassocIndMsg.peer_macaddr); + if (!qdf_is_macaddr_zero( + &wms_cmd->u.DisassocIndMsg.peer_mld_addr)) + qdf_copy_macaddr( + &peer_mld_addr, + &wms_cmd->u.DisassocIndMsg.peer_mld_addr); + } else if (wms_cmd->Type == eCsrDeauthenticated) { + qdf_copy_macaddr( + &peer_macaddr, + &wms_cmd->u.DeauthIndMsg.peer_macaddr); + if (!qdf_is_macaddr_zero( + &wms_cmd->u.DeauthIndMsg.peer_mld_addr)) + qdf_copy_macaddr( + &peer_mld_addr, + &wms_cmd->u.DeauthIndMsg.peer_mld_addr); + } + } + + if (!qdf_is_macaddr_zero(&peer_mld_addr)) + qdf_scnprintf(mld_log_str, MAC_ADDR_DUMP_LEN, + " mld: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mld_addr.bytes)); + + if (!qdf_is_macaddr_zero(&peer_macaddr)) + sme_err("vdev %d cmd %d timeout for peer " QDF_MAC_ADDR_FMT "%s", + sme_cmd->vdev_id, sme_cmd->command, + QDF_MAC_ADDR_REF(peer_macaddr.bytes), mld_log_str); + +} + +QDF_STATUS sme_ser_cmd_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSmeCmd *sme_cmd; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (mac_handle) + mac_ctx = MAC_CONTEXT(mac_handle); + else + return QDF_STATUS_E_FAILURE; + + /* + * Do not acquire lock here as sme global lock is already acquired in + * caller or MC thread context + */ + if (!cmd) { + sme_err("serialization command is null"); + return QDF_STATUS_E_FAILURE; + } + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + status = sme_ser_handle_active_cmd(cmd); + break; + case WLAN_SER_CB_CANCEL_CMD: + if (cmd->cmd_type == WLAN_SER_CMD_SET_HW_MODE) + policy_mgr_reset_hw_mode_change(mac_ctx->psoc); + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + if (cmd->vdev) + wlan_objmgr_vdev_release_ref(cmd->vdev, + WLAN_LEGACY_SME_ID); + sme_cmd = cmd->umac_cmd; + csr_release_command_buffer(mac_ctx, sme_cmd); + break; + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + sme_cmd = cmd->umac_cmd; + if (sme_cmd && (sme_cmd->command == eSmeCommandRoam || + sme_cmd->command == eSmeCommandWmStatusChange)) { + sme_dump_peer_disconnect_timeout_info(sme_cmd); + qdf_trigger_self_recovery(mac_ctx->psoc, + QDF_ACTIVE_LIST_TIMEOUT); + } + + if (cmd->cmd_type == WLAN_SER_CMD_SET_HW_MODE) + policy_mgr_reset_hw_mode_change(mac_ctx->psoc); + break; + default: + sme_debug("unknown reason code"); + return QDF_STATUS_E_FAILURE; + } + return status; +} + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * sme_get_sessionid_from_activelist() - gets vdev_id + * @mac: mac context + * + * This function is used to get session id from sme command + * active list + * + * Return: returns vdev_id + */ +static uint32_t sme_get_sessionid_from_activelist(struct mac_context *mac) +{ + tListElem *entry; + tSmeCmd *command; + uint32_t vdev_id = WLAN_UMAC_VDEV_ID_MAX; + + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (entry) { + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + vdev_id = command->vdev_id; + } + + return vdev_id; +} + +/** + * sme_state_info_dump() - prints state information of sme layer + * @buf: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of sme layer + * + * Return: None + */ +static void sme_state_info_dump(char **buf_ptr, uint16_t *size) +{ + uint8_t vdev_id, active_session_id; + mac_handle_t mac_handle; + struct mac_context *mac; + uint16_t len = 0; + char *buf = *buf_ptr; + enum QDF_OPMODE op_mode; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) { + return; + } + + mac = MAC_CONTEXT(mac_handle); + + active_session_id = sme_get_sessionid_from_activelist(mac); + if (active_session_id != WLAN_UMAC_VDEV_ID_MAX) { + len += qdf_scnprintf(buf + len, *size - len, + "\n active command sessionid %d", active_session_id); + } + + for (vdev_id = 0; vdev_id < WLAN_MAX_VDEVS; vdev_id++) { + if (CSR_IS_SESSION_VALID(mac, vdev_id)) { + op_mode = wlan_get_opmode_from_vdev_id(mac->pdev, + vdev_id); + if (op_mode != QDF_STA_MODE && + op_mode != QDF_P2P_CLIENT_MODE) + continue; + if (cm_is_vdevid_connected(mac->pdev, vdev_id)) { + len += qdf_scnprintf(buf + len, *size - len, + "\n RoamState: %d", mac->roam.curState[vdev_id]); + len += qdf_scnprintf(buf + len, *size - len, + "\n RoamSubState: %d", mac->roam.curSubState[vdev_id]); + } + } + } + + *size -= len; + *buf_ptr += len; +} + +/** + * sme_register_debug_callback() - registration function sme layer + * to print sme state information + * + * Return: None + */ +static void sme_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_SME, &sme_state_info_dump); +} +#else /* WLAN_FEATURE_MEMDUMP_ENABLE */ +static void sme_register_debug_callback(void) +{ +} +#endif /* WLAN_FEATURE_MEMDUMP_ENABLE */ + +#ifdef WLAN_POWER_DEBUG +static void sme_power_debug_stats_cb(struct mac_context *mac, + struct power_stats_response *response) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (mac->sme.power_stats_resp_callback) + mac->sme.power_stats_resp_callback( + response, + mac->sme.power_debug_stats_context); + else + sme_err("Null hdd cb"); + mac->sme.power_stats_resp_callback = NULL; + mac->sme.power_debug_stats_context = NULL; + sme_release_global_lock(&mac->sme); + } +} + +static void sme_register_power_debug_stats_cb(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.sme_power_debug_stats_callback = + sme_power_debug_stats_cb; + sme_release_global_lock(&mac->sme); + } +} + +static void sme_unregister_power_debug_stats_cb(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.sme_power_debug_stats_callback = NULL; + sme_release_global_lock(&mac->sme); + } +} +#else +static inline void sme_register_power_debug_stats_cb(struct mac_context *mac) +{ +} + +static inline void sme_unregister_power_debug_stats_cb(struct mac_context *mac) +{ +} +#endif + +static void +sme_register_vdev_delete_callback(struct mac_context *mac) +{ + mac->sme.sme_vdev_del_cb = sme_vdev_delete; +} + +/* Global APIs */ + +/** + * sme_open() - Initialize all SME modules and put them at idle state + * @mac_handle: The handle returned by mac_open + * + * The function initializes each module inside SME, PMC, CSR, etc. Upon + * successfully return, all modules are at idle state ready to start. + * smeOpen must be called before any other SME APIs can be involved. + * smeOpen must be called after mac_open. + * + * Return: QDF_STATUS_SUCCESS - SME is successfully initialized. + * Other status means SME is failed to be initialized + */ +QDF_STATUS sme_open(mac_handle_t mac_handle) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + mac->sme.state = SME_STATE_STOP; + if (!QDF_IS_STATUS_SUCCESS(qdf_mutex_create( + &mac->sme.sme_global_lock))) { + sme_err("Init lock failed"); + return QDF_STATUS_E_FAILURE; + } + status = csr_open(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("csr_open failed, status: %d", status); + return status; + } + + status = sme_ps_open(mac_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_ps_open failed with status: %d", status); + return status; + } + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_open(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Qos open, status: %d", status); + return status; + } +#endif + status = init_sme_cmd_list(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + status = rrm_open(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("rrm_open failed, status: %d", status); + return status; + } + sme_trace_init(mac); + sme_register_debug_callback(); + sme_register_power_debug_stats_cb(mac); + sme_register_vdev_delete_callback(mac); + + return status; +} + +/* + * sme_init_chan_list, triggers channel setup based on country code. + */ +QDF_STATUS sme_init_chan_list(mac_handle_t mac_handle, enum country_src cc_src) +{ + struct mac_context *pmac = MAC_CONTEXT(mac_handle); + + if ((cc_src == SOURCE_USERSPACE) && + (pmac->mlme_cfg->sap_cfg.country_code_priority)) { + pmac->mlme_cfg->gen.enabled_11d = false; + } + + return csr_init_chan_list(pmac); +} + +/* + * sme_set11dinfo() - Set the 11d information about valid channels + * and there power using information from nvRAM + * This function is called only for AP. + * + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open. + * pSmeConfigParams - a pointer to a caller allocated object of + * struct sme_config_params. + * + * Return QDF_STATUS_SUCCESS - SME update the config parameters successfully. + * + * Other status means SME is failed to update the config parameters. + */ + +QDF_STATUS sme_set11dinfo(mac_handle_t mac_handle, + struct sme_config_params *pSmeConfigParams) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO, NO_SESSION, 0)); + if (!pSmeConfigParams) { + sme_err("SME config params empty"); + return status; + } + + status = csr_set_channels(mac_ctx, &pSmeConfigParams->csr_config); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("csr_set_channels failed with status: %d", status); + + return status; +} + +/** + * sme_update_fine_time_measurement_capab() - Update the FTM capabitlies from + * incoming val + * @mac_handle: Opaque handle to the global MAC context + * @val: New FTM capability value + * + * Return: None + */ +void sme_update_fine_time_measurement_capab(mac_handle_t mac_handle, + uint8_t session_id, + uint32_t val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + + ucfg_wifi_pos_set_ftm_cap(mac_ctx->psoc, val); + + if (!val) { + mac_ctx->rrm.rrmPEContext.rrmEnabledCaps.fine_time_meas_rpt = 0; + ((tpRRMCaps)mac_ctx->rrm.rrmConfig. + rm_capability)->fine_time_meas_rpt = 0; + } else { + mac_ctx->rrm.rrmPEContext.rrmEnabledCaps.fine_time_meas_rpt = 1; + ((tpRRMCaps)mac_ctx->rrm.rrmConfig. + rm_capability)->fine_time_meas_rpt = 1; + } + + /* Inform this RRM IE change to FW */ + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_roam_update_cfg(mac_ctx->psoc, session_id, + REASON_CONNECT_IES_CHANGED); + sme_release_global_lock(&mac_ctx->sme); + } +} + +/* + * sme_update_config() - Change configurations for all SME modules + * The function updates some configuration for modules in SME, CSR, etc + * during SMEs close open sequence. + * Modules inside SME apply the new configuration at the next transaction. + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open. + * pSmeConfigParams - a pointer to a caller allocated object of + * struct sme_config_params. + * Return QDF_STATUS_SUCCESS - SME update the config parameters successfully. + * Other status means SME is failed to update the config parameters. + */ +QDF_STATUS sme_update_config(mac_handle_t mac_handle, + struct sme_config_params *pSmeConfigParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG, NO_SESSION, + 0)); + if (!pSmeConfigParams) { + sme_err("SME config params empty"); + return status; + } + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("SME lock error %d", status); + return status; + } + + status = csr_change_default_config_param(mac, &pSmeConfigParams-> + csr_config); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("csr_change_default_config_param failed status: %d", + status); + + /* For SOC, CFG is set before start We don't want to apply global CFG + * in connect state because that may cause some side affect + */ + if (csr_is_all_session_disconnected(mac)) + csr_set_global_cfgs(mac); + + sme_release_global_lock(&mac->sme); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_roam_params(mac_handle_t mac_handle, + uint8_t vdev_id, + struct rso_config_params *src_rso_config, + struct rso_user_config *src_rso_usr_cfg, + int update_param) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + uint8_t i; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct rso_config_params *dst_rso_usr_cfg; + struct rso_user_config *rso_usr_cfg; + struct wlan_objmgr_vdev *vdev; + + mlme_obj = mlme_get_psoc_ext_obj(mac_ctx->psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + dst_rso_usr_cfg = &mlme_obj->cfg.lfr.rso_user_config; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + rso_usr_cfg = wlan_cm_get_rso_user_config(vdev); + + if (!rso_usr_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return QDF_STATUS_E_FAILURE; + } + + switch (update_param) { + case REASON_ROAM_EXT_SCAN_PARAMS_CHANGED: + mac_ctx->mlme_cfg->lfr.rssi_boost_threshold_5g = + src_rso_config->raise_rssi_thresh_5g; + mac_ctx->mlme_cfg->lfr.rssi_penalize_threshold_5g = + src_rso_config->drop_rssi_thresh_5g; + mac_ctx->mlme_cfg->lfr.rssi_boost_factor_5g = + src_rso_config->raise_factor_5g; + mac_ctx->mlme_cfg->lfr.rssi_penalize_factor_5g = + src_rso_config->drop_factor_5g; + mac_ctx->mlme_cfg->lfr.max_rssi_boost_5g = + src_rso_config->max_raise_rssi_5g; + dst_rso_usr_cfg->alert_rssi_threshold = + src_rso_config->alert_rssi_threshold; + dst_rso_usr_cfg->rssi_diff = src_rso_config->rssi_diff; + mac_ctx->mlme_cfg->lfr.enable_5g_band_pref = true; + break; + case REASON_ROAM_SET_SSID_ALLOWED: + qdf_mem_zero(&rso_usr_cfg->ssid_allowed_list, + sizeof(struct wlan_ssid) * MAX_SSID_ALLOWED_LIST); + rso_usr_cfg->num_ssid_allowed_list = + src_rso_usr_cfg->num_ssid_allowed_list; + for (i = 0; i < rso_usr_cfg->num_ssid_allowed_list; i++) { + rso_usr_cfg->ssid_allowed_list[i].length = + src_rso_usr_cfg->ssid_allowed_list[i].length; + qdf_mem_copy(rso_usr_cfg->ssid_allowed_list[i].ssid, + src_rso_usr_cfg->ssid_allowed_list[i].ssid, + rso_usr_cfg->ssid_allowed_list[i].length); + } + break; + case REASON_ROAM_SET_FAVORED_BSSID: + qdf_mem_zero(&dst_rso_usr_cfg->bssid_favored, + sizeof(struct qdf_mac_addr) * MAX_BSSID_FAVORED); + dst_rso_usr_cfg->num_bssid_favored = + src_rso_config->num_bssid_favored; + for (i = 0; i < dst_rso_usr_cfg->num_bssid_favored; i++) { + qdf_copy_macaddr(&dst_rso_usr_cfg->bssid_favored[i], + &src_rso_config->bssid_favored[i]); + dst_rso_usr_cfg->bssid_favored_factor[i] = + src_rso_config->bssid_favored_factor[i]; + } + break; + case REASON_ROAM_GOOD_RSSI_CHANGED: + dst_rso_usr_cfg->good_rssi_roam = + src_rso_config->good_rssi_roam; + break; + default: + break; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_roam_update_cfg(mac_ctx->psoc, vdev_id, update_param); + sme_release_global_lock(&mac_ctx->sme); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return 0; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + +/** + * sme_process_ready_to_ext_wow() - inform ready to ExtWoW indication. + * @mac: Global MAC context + * @indication: ready to Ext WoW indication from lower layer + * + * On getting ready to Ext WoW indication, this function calls callback + * registered (HDD callback) with SME to inform ready to ExtWoW indication. + * + * Return: None + */ +static void sme_process_ready_to_ext_wow(struct mac_context *mac, + tpSirReadyToExtWoWInd indication) +{ + if (!mac) { + sme_err("mac is null"); + return; + } + + if (mac->readyToExtWoWCallback) { + mac->readyToExtWoWCallback(mac->readyToExtWoWContext, + indication->status); + mac->readyToExtWoWCallback = NULL; + mac->readyToExtWoWContext = NULL; + } + +} +#endif + +/* + * sme_hdd_ready_ind() - SME sends eWNI_SME_SYS_READY_IND to PE to inform + * that the NIC is ready tio run. + * The function is called by HDD at the end of initialization stage so PE/HAL + * can enable the NIC to running state. + * This is a synchronous call + * + * @mac_handle - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - eWNI_SME_SYS_READY_IND is sent to PE + * successfully. + * Other status means SME failed to send the message to PE. + */ +QDF_STATUS sme_hdd_ready_ind(mac_handle_t mac_handle) +{ + struct sme_ready_req *msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND, NO_SESSION, 0)); + do { + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) + return QDF_STATUS_E_NOMEM; + + msg->messageType = eWNI_SME_SYS_READY_IND; + msg->length = sizeof(*msg); + msg->sme_msg_cb = sme_process_msg_callback; + msg->stop_roaming_cb = sme_stop_roaming; + msg->csr_roam_auth_event_handle_cb = + csr_roam_auth_offload_callback; + status = u_mac_post_ctrl_msg(mac_handle, (tSirMbMsg *)msg); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("u_mac_post_ctrl_msg failed to send eWNI_SME_SYS_READY_IND"); + break; + } + + status = csr_ready(mac); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("csr_ready failed with status: %d", status); + break; + } + + mac->sme.state = SME_STATE_READY; + } while (0); + + return status; +} + +#ifdef WLAN_BCN_RECV_FEATURE +QDF_STATUS +sme_register_bcn_report_pe_cb(mac_handle_t mac_handle, beacon_report_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + sme_err("Invalid mac context"); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac_register_bcn_report_send_cb(mac, cb); + sme_release_global_lock(&mac->sme); + } + + return status; +} +#endif + +#ifdef WLAN_CONV_SPECTRAL_ENABLE +static QDF_STATUS sme_register_spectral_cb(struct mac_context *mac_ctx) +{ + struct spectral_legacy_cbacks spectral_cb = {0}; + QDF_STATUS status; + + spectral_cb.vdev_get_chan_freq = sme_get_oper_chan_freq; + spectral_cb.vdev_get_ch_width = sme_get_oper_ch_width; + spectral_cb.vdev_get_sec20chan_freq_mhz = sme_get_sec20chan_freq_mhz; + status = spectral_register_legacy_cb(mac_ctx->psoc, &spectral_cb); + + return status; +} +#else +static QDF_STATUS sme_register_spectral_cb(struct mac_context *mac_ctx) +{ + return QDF_STATUS_SUCCESS; +} +#endif +/* + * sme_start() - Put all SME modules at ready state. + * The function starts each module in SME, PMC, CSR, etc. . Upon + * successfully return, all modules are ready to run. + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open. + * Return QDF_STATUS_SUCCESS - SME is ready. + * Other status means SME is failed to start + */ +QDF_STATUS sme_start(mac_handle_t mac_handle) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct policy_mgr_sme_cbacks sme_cbacks; + + do { + status = csr_start(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("csr_start failed status: %d", status); + break; + } + sme_cbacks.sme_get_nss_for_vdev = sme_get_vdev_type_nss; + sme_cbacks.sme_nss_update_request = sme_nss_update_request; + sme_cbacks.sme_pdev_set_hw_mode = sme_pdev_set_hw_mode; + sme_cbacks.sme_soc_set_dual_mac_config = + sme_soc_set_dual_mac_config; + sme_cbacks.sme_change_mcc_beacon_interval = + sme_change_mcc_beacon_interval; + sme_cbacks.sme_rso_start_cb = sme_start_roaming; + sme_cbacks.sme_rso_stop_cb = sme_stop_roaming; + sme_cbacks.sme_change_sap_csa_count = sme_change_sap_csa_count; + sme_cbacks.sme_sap_update_ch_width = sme_sap_update_ch_width; + status = policy_mgr_register_sme_cb(mac->psoc, &sme_cbacks); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to register sme cb with Policy Manager: %d", + status); + break; + } + sme_register_spectral_cb(mac); + mac->sme.state = SME_STATE_START; + + /* START RRM */ + status = rrm_start(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to start RRM"); + break; + } + } while (0); + return status; +} + +static QDF_STATUS dfs_msg_processor(struct mac_context *mac, + struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info *roam_info; + tSirSmeCSAIeTxCompleteRsp *csa_ie_tx_complete_rsp; + uint32_t session_id = 0; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_NOMEM; + + switch (msg->type) { + case eWNI_SME_DFS_RADAR_FOUND: + { + session_id = policy_mgr_get_dfs_beaconing_session_id(mac->psoc); + if (!CSR_IS_SESSION_VALID(mac, session_id)) { + sme_err("Invalid vdev %d", session_id); + qdf_mem_free(roam_info); + return QDF_STATUS_E_FAILURE; + } + roam_status = eCSR_ROAM_DFS_RADAR_IND; + roam_result = eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND; + sme_debug("sapdfs: Radar indication event occurred"); + break; + } + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + { + csa_ie_tx_complete_rsp = + (tSirSmeCSAIeTxCompleteRsp *) msg->bodyptr; + if (!csa_ie_tx_complete_rsp) { + sme_err("eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND null msg"); + qdf_mem_free(roam_info); + return QDF_STATUS_E_FAILURE; + } + session_id = csa_ie_tx_complete_rsp->sessionId; + roam_status = eCSR_ROAM_DFS_CHAN_SW_NOTIFY; + roam_result = eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS; + break; + } + case eWNI_SME_DFS_CAC_COMPLETE: + { + session_id = msg->bodyval; + roam_status = eCSR_ROAM_CAC_COMPLETE_IND; + roam_result = eCSR_ROAM_RESULT_CAC_END_IND; + sme_debug("sapdfs: Received eWNI_SME_DFS_CAC_COMPLETE vdev %d", + session_id); + break; + } + case eWNI_SME_CSA_RESTART_RSP: + { + session_id = msg->bodyval; + roam_status = 0; + roam_result = eCSR_ROAM_RESULT_CSA_RESTART_RSP; + sme_debug("sapdfs: Received eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_REQ vdev %d", + session_id); + break; + } + default: + { + sme_err("Invalid DFS message: 0x%x", msg->type); + qdf_mem_free(roam_info); + status = QDF_STATUS_E_FAILURE; + return status; + } + } + + /* Indicate Radar Event to SAP */ + csr_roam_call_callback(mac, session_id, roam_info, + roam_status, roam_result); + qdf_mem_free(roam_info); + return status; +} + +/* + * Handle the unprotected management frame indication from LIM and + * forward it to HDD. + */ +static QDF_STATUS +sme_unprotected_mgmt_frm_ind(struct mac_context *mac, + tpSirSmeUnprotMgmtFrameInd pSmeMgmtFrm) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info *roam_info; + uint32_t SessionId = pSmeMgmtFrm->sessionId; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_NOMEM; + + roam_info->nFrameLength = pSmeMgmtFrm->frameLen; + roam_info->pbFrames = pSmeMgmtFrm->frameBuf; + roam_info->frameType = pSmeMgmtFrm->frameType; + + /* forward the mgmt frame to HDD */ + csr_roam_call_callback(mac, SessionId, roam_info, + eCSR_ROAM_UNPROT_MGMT_FRAME_IND, 0); + + qdf_mem_free(roam_info); + + return status; +} + +QDF_STATUS sme_update_new_channel_event(mac_handle_t mac_handle, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_info *roamInfo; + eRoamCmdStatus roamStatus; + eCsrRoamResult roamResult; + + roamInfo = qdf_mem_malloc(sizeof(*roamInfo)); + if (!roamInfo) + return QDF_STATUS_E_FAILURE; + + roamStatus = eCSR_ROAM_CHANNEL_COMPLETE_IND; + roamResult = eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND; + sme_debug("sapdfs: Updated new channel event"); + + /* Indicate channel Event to SAP */ + csr_roam_call_callback(mac, session_id, roamInfo, + roamStatus, roamResult); + + qdf_mem_free(roamInfo); + return status; +} + + +/** + * sme_extended_change_channel_ind()- function to indicate ECSA + * action frame is received in lim to SAP + * @mac_ctx: pointer to global mac structure + * @msg_buf: contain new channel and session id. + * + * This function is called to post ECSA action frame + * receive event to SAP. + * + * Return: success if msg indicated to SAP else return failure + */ +static QDF_STATUS sme_extended_change_channel_ind(struct mac_context *mac_ctx, + void *msg_buf) +{ + struct sir_sme_ext_cng_chan_ind *ext_chan_ind; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t session_id = 0; + struct csr_roam_info *roam_info; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + + ext_chan_ind = msg_buf; + if (!ext_chan_ind) { + sme_err("ext_chan_ind is NULL"); + return QDF_STATUS_E_FAILURE; + } + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_NOMEM; + + session_id = ext_chan_ind->session_id; + roam_info->target_chan_freq = ext_chan_ind->new_chan_freq; + roam_status = eCSR_ROAM_EXT_CHG_CHNL_IND; + roam_result = eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND; + sme_debug("sapdfs: Received eWNI_SME_EXT_CHANGE_CHANNEL_IND for session id [%d]", + session_id); + + /* Indicate Ext Channel Change event to SAP */ + csr_roam_call_callback(mac_ctx, session_id, roam_info, + roam_status, roam_result); + qdf_mem_free(roam_info); + return status; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_update_is_ese_feature_enabled() - enable/disable ESE support at runtime + * @mac_handle: Opaque handle to the global MAC context + * @sessionId: session id + * @isEseIniFeatureEnabled: ese ini enabled + * + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * isEseIniFeatureEnabled. This is a synchronous call + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_update_is_ese_feature_enabled(mac_handle_t mac_handle, + uint8_t sessionId, const bool isEseIniFeatureEnabled) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + + if (mac->mlme_cfg->lfr.ese_enabled == + isEseIniFeatureEnabled) { + sme_debug("ESE Mode is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + mac->mlme_cfg->lfr.ese_enabled, isEseIniFeatureEnabled); + return QDF_STATUS_SUCCESS; + } + + sme_debug("vdev %d EseEnabled is changed from %d to %d", sessionId, + mac->mlme_cfg->lfr.ese_enabled, isEseIniFeatureEnabled); + mac->mlme_cfg->lfr.ese_enabled = isEseIniFeatureEnabled; + mlme_set_supplicant_disabled_roaming(mac->psoc, sessionId, + !isEseIniFeatureEnabled); + if (isEseIniFeatureEnabled) + wlan_cm_roam_state_change(mac->pdev, sessionId, + WLAN_ROAM_RSO_ENABLED, + REASON_CONNECT); + else + wlan_cm_roam_state_change(mac->pdev, sessionId, + WLAN_ROAM_RSO_STOPPED, + REASON_SUPPLICANT_DISABLED_ROAMING); + + if (true == isEseIniFeatureEnabled) + mac->mlme_cfg->lfr.fast_transition_enabled = true; + + if (mac->mlme_cfg->lfr.roam_scan_offload_enabled) { + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_roam_update_cfg(mac->psoc, sessionId, + REASON_ESE_INI_CFG_CHANGED); + sme_release_global_lock(&mac->sme); + } else { + return status; + } + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_set_plm_request(mac_handle_t mac_handle, + struct plm_req_params *req) +{ + QDF_STATUS status; + bool ret = false; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + uint32_t ch_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t count, valid_count = 0; + struct scheduler_msg msg = {0}; + struct csr_roam_session *session; + struct plm_req_params *body; + uint32_t ch_freq; + + if (!req) + return QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + session = CSR_GET_SESSION(mac, req->vdev_id); + if (!session) { + sme_err("session for vdev %d not found", req->vdev_id); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!session->sessionActive) { + sme_err("Invalid vdev %d", req->vdev_id); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + /* per contract must make a copy of the params when messaging */ + body = qdf_mem_malloc(sizeof(*body)); + + if (!body) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + *body = *req; + + if (!body->enable) + goto send_plm_start; + /* validating channel numbers */ + for (count = 0; count < body->plm_num_ch; count++) { + ch_freq = body->plm_ch_freq_list[count]; + ret = csr_is_supported_channel(mac, ch_freq); + if (!ret) { + /* Not supported, ignore the channel */ + sme_debug("Unsupported freq %d ignored for PLM", + ch_freq); + continue; + } + + if (ch_freq > 2477) { + enum channel_state state = + wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, ch_freq, + REG_CURRENT_PWR_MODE); + + if (state == CHANNEL_STATE_DFS) { + /* DFS channel is provided, no PLM bursts can be + * transmitted. Ignoring these channels. + */ + sme_debug("DFS channel %d ignored for PLM", + ch_freq); + continue; + } + } + ch_freq_list[valid_count++] = ch_freq; + } /* End of for () */ + + /* Copying back the valid channel list to plm struct */ + qdf_mem_zero(body->plm_ch_freq_list, body->plm_num_ch); + if (valid_count) + qdf_mem_copy(body->plm_ch_freq_list, ch_freq_list, valid_count); + /* All are invalid channels, FW need to send the PLM + * report with "incapable" bit set. + */ + body->plm_num_ch = valid_count; + +send_plm_start: + /* PLM START */ + msg.type = WMA_SET_PLM_REQ; + msg.reserved = 0; + msg.bodyptr = body; + + if (!QDF_IS_STATUS_SUCCESS(scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + sme_err("Not able to post WMA_SET_PLM_REQ to WMA"); + sme_release_global_lock(&mac->sme); + qdf_mem_free(body); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_tsm_ie_ind() - sme tsm ie indication + * @mac: Global mac context + * @pSmeTsmIeInd: Pointer to tsm ie indication + * + * Handle the tsm ie indication from LIM and forward it to HDD. + * + * Return: QDF_STATUS enumeration + */ +static QDF_STATUS sme_tsm_ie_ind(struct mac_context *mac, + struct tsm_ie_ind *pSmeTsmIeInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info *roam_info; + uint32_t SessionId = pSmeTsmIeInd->sessionId; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_NOMEM; + + roam_info->tsm_ie.tsid = pSmeTsmIeInd->tsm_ie.tsid; + roam_info->tsm_ie.state = pSmeTsmIeInd->tsm_ie.state; + roam_info->tsm_ie.msmt_interval = pSmeTsmIeInd->tsm_ie.msmt_interval; + /* forward the tsm ie information to HDD */ + csr_roam_call_callback(mac, SessionId, roam_info, + eCSR_ROAM_TSM_IE_IND, 0); + qdf_mem_free(roam_info); + return status; +} + +/** + * sme_set_ese_beacon_request() - set ese beacon request + * @mac_handle: Opaque handle to the global MAC context + * @sessionId: session id + * @in_req: Ese beacon report request + * + * function to set ESE beacon request parameters + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_ese_beacon_request(mac_handle_t mac_handle, + const uint8_t sessionId, + const tCsrEseBeaconReq *in_req) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + tpSirBeaconReportReqInd sme_bcn_rpt_req = NULL; + const tCsrEseBeaconReqParams *bcn_req = NULL; + uint8_t counter = 0; + tpRrmSMEContext sme_rrm_ctx = &mac->rrm.rrmSmeContext[0]; + + if (sme_rrm_ctx->eseBcnReqInProgress == true) { + sme_err("A Beacon Report Req is already in progress"); + return QDF_STATUS_E_RESOURCES; + } + + /* Store the info in RRM context */ + qdf_mem_copy(&sme_rrm_ctx->eseBcnReqInfo, in_req, + sizeof(tCsrEseBeaconReq)); + + /* Prepare the request to send to SME. */ + sme_bcn_rpt_req = qdf_mem_malloc(sizeof(tSirBeaconReportReqInd)); + if (!sme_bcn_rpt_req) + return QDF_STATUS_E_NOMEM; + + sme_rrm_ctx->eseBcnReqInProgress = true; + + sme_debug("Sending Beacon Report Req to SME"); + + sme_bcn_rpt_req->messageType = eWNI_SME_BEACON_REPORT_REQ_IND; + sme_bcn_rpt_req->length = sizeof(tSirBeaconReportReqInd); + wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, + (struct qdf_mac_addr *)&sme_bcn_rpt_req->bssId); + sme_bcn_rpt_req->channel_info.chan_num = 255; + sme_bcn_rpt_req->channel_list.num_channels = in_req->numBcnReqIe; + sme_bcn_rpt_req->msgSource = eRRM_MSG_SOURCE_ESE_UPLOAD; + sme_bcn_rpt_req->measurement_idx = 0; + + for (counter = 0; counter < in_req->numBcnReqIe; counter++) { + bcn_req = &in_req->bcnReq[counter]; + sme_bcn_rpt_req->fMeasurementtype[counter] = + bcn_req->scanMode; + sme_bcn_rpt_req->measurementDuration[counter] = + SYS_TU_TO_MS(bcn_req->measurementDuration); + sme_bcn_rpt_req->channel_list.chan_freq_lst[counter] = + bcn_req->ch_freq; + } + + status = sme_rrm_process_beacon_report_req_ind(mac, sme_bcn_rpt_req); + + if (status != QDF_STATUS_SUCCESS) + sme_rrm_ctx->eseBcnReqInProgress = false; + + qdf_mem_free(sme_bcn_rpt_req); + + return status; +} + +/** + * sme_get_tsm_stats() - SME get tsm stats + * @mac_handle: Opaque handle to the global MAC context + * @callback: SME sends back the requested stats using the callback + * @staId: The station ID for which the stats is requested for + * @bssId: bssid + * @pContext: user context to be passed back along with the callback + * @tid: Traffic id + * + * API register a callback to get TSM Stats. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_get_tsm_stats(mac_handle_t mac_handle, + tCsrTsmStatsCallback callback, + struct qdf_mac_addr bssId, + void *pContext, uint8_t tid) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_tsm_stats(mac, callback, + bssId, pContext, + tid); + sme_release_global_lock(&mac->sme); + } + return status; +} +#endif /* FEATURE_WLAN_ESE */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_get_roam_scan_ch(mac_handle_t mac_handle, + uint8_t vdev_id, void *pcontext) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + msg.type = WMA_ROAM_SCAN_CH_REQ; + msg.bodyval = vdev_id; + mac->sme.roam_scan_ch_get_context = pcontext; + + if (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Posting message %d failed", + WMA_ROAM_SCAN_CH_REQ); + mac->sme.roam_scan_ch_get_context = NULL; + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_process_dual_mac_config_resp() - Process set Dual mac config response + * @mac: Global MAC pointer + * @msg: Dual mac config response + * + * Processes the dual mac configuration response and invokes the HDD callback + * to process further + */ +static QDF_STATUS sme_process_dual_mac_config_resp(struct mac_context *mac, + uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + dual_mac_cb callback = NULL; + struct sir_dual_mac_config_resp *param; + + param = (struct sir_dual_mac_config_resp *)msg; + if (!param) { + sme_err("Dual mac config resp param is NULL"); + /* Not returning. Need to check if active command list + * needs to be freed + */ + } + + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (!entry) { + sme_err("No cmd found in active list"); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sme_err("Base address is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_dual_mac_config != command->command) { + sme_err("Command mismatch!"); + return QDF_STATUS_E_FAILURE; + } + + callback = command->u.set_dual_mac_cmd.set_dual_mac_cb; + if (callback) { + if (!param) { + sme_err("Callback failed-Dual mac config is NULL"); + } else { + sme_debug("Calling HDD callback for Dual mac config"); + callback(param->status, + command->u.set_dual_mac_cmd.scan_config, + command->u.set_dual_mac_cmd.fw_mode_config); + } + } else { + sme_err("Callback does not exist"); + } + + found = csr_nonscan_active_ll_remove_entry(mac, entry, LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the available command list */ + csr_release_command(mac, command); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS sme_set_roam_scan_ch_event_cb(mac_handle_t mac_handle, + sme_get_raom_scan_ch_callback cb) +{ + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + mac->sme.roam_scan_ch_callback = cb; + sme_release_global_lock(&mac->sme); + + return qdf_status; +} + +/** + * sme_process_roam_scan_ch_list_resp() - Process get roam scan ch list + * response + * @mac: Global MAC pointer + * @msgbuf: pointer to roam scan ch list response + * + * This function checks the roam scan chan list message is for command + * response or a async event and accordingly data is given to user space. + * callback to process further + */ +static void +sme_process_roam_scan_ch_list_resp(struct mac_context *mac, + struct roam_scan_ch_resp *roam_ch) +{ + sme_get_raom_scan_ch_callback callback = + mac->sme.roam_scan_ch_callback; + + if (!roam_ch) + return; + + if (callback) + callback(mac->hdd_handle, roam_ch, + mac->sme.roam_scan_ch_get_context); +} +#else +static void +sme_process_roam_scan_ch_list_resp(tpAniSirGlobal mac, + struct roam_scan_ch_resp *roam_ch) +{ +} +#endif + +/** + * sme_process_antenna_mode_resp() - Process set antenna mode + * response + * @mac: Global MAC pointer + * @msg: antenna mode response + * + * Processes the antenna mode response and invokes the HDD + * callback to process further + */ +static QDF_STATUS sme_process_antenna_mode_resp(struct mac_context *mac, + uint8_t *msg) +{ + tListElem *entry; + tSmeCmd *command; + bool found; + void *context = NULL; + antenna_mode_cb callback; + struct sir_antenna_mode_resp *param; + + param = (struct sir_antenna_mode_resp *)msg; + if (!param) + sme_err("set antenna mode resp is NULL"); + /* Not returning. Need to check if active command list + * needs to be freed + */ + + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (!entry) { + sme_err("No cmd found in active list"); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sme_err("Base address is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_set_antenna_mode != command->command) { + sme_err("Command mismatch!"); + return QDF_STATUS_E_FAILURE; + } + + context = command->u.set_antenna_mode_cmd.set_antenna_mode_ctx; + callback = command->u.set_antenna_mode_cmd.set_antenna_mode_resp; + if (callback) { + if (!param) + sme_err("Set antenna mode call back is NULL"); + else + callback(param->status, context); + } else { + sme_err("Callback does not exist"); + } + + found = csr_nonscan_active_ll_remove_entry(mac, entry, LL_ACCESS_LOCK); + if (found) + /* Now put this command back on the available command list */ + csr_release_command(mac, command); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_SUPPORT_TWT +/** + * sme_sap_twt_is_command_in_progress() - Based on the input peer mac address + * invoke the appropriate function to check if the given command is in progress + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * @cmd: command + * + * If the input @peer_mac is a broadcast MAC address then the expectation is + * to iterate through the list of all peers and check for any given @dialog_id + * if the command @cmd is in progress. + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * For ex: If TWT teardown command is issued on a particular @dialog_id and + * non-broadcast peer mac and FW response is not yet received then for that + * particular @dialog_id and @peer_mac, TWT teardown is the active command, + * then if the driver receives another TWT teardown request with broadcast + * peer mac, then API mlme_twt_any_peer_cmd_in_progress() shall iterate + * through the list of all peers and returns command in progress as true. + * + * If the input @peer_mac is a non-broadcast MAC address then + * mlme_sap_twt_peer_is_cmd_in_progress() shall check only for that + * particular @peer_mac and @dialog_id. + * + * Return: true if command is in progress, false otherwise + */ +static bool +sme_sap_twt_is_command_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + if (qdf_is_macaddr_broadcast(peer_mac)) { + return mlme_twt_any_peer_cmd_in_progress(psoc, vdev_id, + dialog_id, cmd); + } else { + return mlme_sap_twt_peer_is_cmd_in_progress(psoc, peer_mac, + dialog_id, cmd); + } +} + +/** + * sme_sap_add_twt_session() - Based on the input peer mac address + * invoke the appropriate function to add dialog_id to the TWT session context + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * + * If the input @peer_mac is a broadcast MAC address then there is nothing + * to do, because the initialized structure is already in the expected format + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * + * If the input @peer_mac is a non-broadcast MAC address then + * mlme_add_twt_session() shall add the @dialog_id to the @peer_mac + * TWT session context. + * + * Return: None + */ +static void +sme_sap_add_twt_session(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + if (!qdf_is_macaddr_broadcast(peer_mac)) + mlme_add_twt_session(psoc, peer_mac, dialog_id); +} + +/** + * sme_sap_set_twt_command_in_progress() - Based on the input peer mac address + * invoke the appropriate function to set the command is in progress + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * @cmd: command + * + * If the input @peer_mac is a broadcast MAC address then the expectation is + * to iterate through the list of all peers and set the active command to @cmd + * for the given @dialog_id + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * For ex: If TWT teardown command is issued on broadcast @peer_mac, then + * it is same as issuing TWT teardown for all the peers (all TWT sessions). + * Invoking mlme_sap_set_twt_all_peers_cmd_in_progress() shall iterate through + * all the peers and set the active command to @cmd. + * + * If the input @peer_mac is a non-broadcast MAC address then + * mlme_set_twt_command_in_progress() shall set the active command to @cmd + * only for that particular @peer_mac and @dialog_id. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sme_sap_set_twt_command_in_progress(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id, + enum wlan_twt_commands cmd) +{ + if (qdf_is_macaddr_broadcast(peer_mac)) { + return mlme_sap_set_twt_all_peers_cmd_in_progress(psoc, + vdev_id, + dialog_id, + cmd); + } else { + return mlme_set_twt_command_in_progress(psoc, peer_mac, + dialog_id, cmd); + } +} + +/** + * sme_sap_init_twt_context() - Based on the input peer mac address + * invoke the appropriate function to initialize the TWT session context + * @psoc: Pointer to psoc object + * @vdev_id: Vdev id + * @peer_mac: Peer MAC address + * @dialog_id: Dialog id + * + * If the input @peer_mac is a broadcast MAC address then the expectation is + * to iterate through the list of all peers and initialize the TWT session + * context + * Note: If @peer_mac is broadcast MAC address then @dialog_id shall always + * be TWT_ALL_SESSIONS_DIALOG_ID. + * For ex: If TWT teardown command is issued on broadcast @peer_mac, then + * it is same as issuing TWT teardown for all the peers (all TWT sessions). + * Then active command for all the peers is set to @WLAN_TWT_TERMINATE. + * Upon receiving the TWT teardown WMI event, mlme_init_all_peers_twt_context() + * shall iterate through the list of all peers and initializes the TWT session + * context back to its initial state. + * + * If the input @peer_mac is a non-broadcast MAC address then + * mlme_init_twt_context() shall initialize the TWT session context + * only for that particular @peer_mac and @dialog_id. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sme_sap_init_twt_context(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, + uint8_t dialog_id) +{ + if (qdf_is_macaddr_broadcast(peer_mac)) { + return mlme_init_all_peers_twt_context(psoc, vdev_id, + dialog_id); + } else { + return mlme_init_twt_context(psoc, peer_mac, dialog_id); + } +} + +/** + * sme_process_twt_add_renego_failure() - Process TWT re-negotiation failure + * + * @mac: Global MAC pointer + * @add_dialog_event: pointer to event buf containing twt response parameters + * + * Return: None + */ +static void +sme_process_twt_add_renego_failure(struct mac_context *mac, + struct wma_twt_add_dialog_complete_event *add_dialog_event) +{ + twt_add_dialog_cb callback; + + /* Reset the active TWT command to none */ + mlme_set_twt_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id, WLAN_TWT_NONE); + + callback = mac->sme.twt_add_dialog_cb; + if (callback) + callback(mac->psoc, add_dialog_event, true); +} + +/** + * sme_process_twt_add_initial_nego() - Process initial TWT setup or + * re-negotiation successful setup + * @mac: Global MAC pointer + * @add_dialog_event: pointer to event buf containing twt response parameters + * + * Return: None + */ +static void +sme_process_twt_add_initial_nego(struct mac_context *mac, + struct wma_twt_add_dialog_complete_event *add_dialog_event) +{ + twt_add_dialog_cb callback; + + callback = mac->sme.twt_add_dialog_cb; + if (callback) + callback(mac->psoc, add_dialog_event, false); + + /* Reset the active TWT command to none */ + mlme_set_twt_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id, WLAN_TWT_NONE); + + if (add_dialog_event->params.status) { + /* Clear the stored TWT dialog ID as TWT setup failed */ + ucfg_mlme_init_twt_context(mac->psoc, (struct qdf_mac_addr *) + add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id); + return; + } + + ucfg_mlme_set_twt_setup_done(mac->psoc, (struct qdf_mac_addr *) + add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id, true); + + ucfg_mlme_set_twt_session_state( + mac->psoc, + (struct qdf_mac_addr *)add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id, + WLAN_TWT_SETUP_STATE_ACTIVE); +} + +/** + * sme_process_twt_add_dialog_event() - Process twt add dialog event + * response from firmware + * @mac: Global MAC pointer + * @add_dialog_event: pointer to event buf containing twt response parameters + * + * Return: None + */ +static void +sme_process_twt_add_dialog_event(struct mac_context *mac, + struct wma_twt_add_dialog_complete_event + *add_dialog_event) +{ + bool is_evt_allowed; + bool setup_done; + enum WMI_HOST_ADD_TWT_STATUS status = add_dialog_event->params.status; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + twt_add_dialog_cb callback; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, + add_dialog_event->params.vdev_id); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + switch (opmode) { + case QDF_SAP_MODE: + callback = mac->sme.twt_add_dialog_cb; + if (callback) + callback(mac->psoc, add_dialog_event, false); + break; + case QDF_STA_MODE: + is_evt_allowed = mlme_twt_is_command_in_progress( + mac->psoc, (struct qdf_mac_addr *) + add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id, + WLAN_TWT_SETUP, &active_cmd); + + if (!is_evt_allowed) { + sme_debug("Drop TWT add dialog event for dialog_id:%d status:%d active_cmd:%d", + add_dialog_event->params.dialog_id, status, + active_cmd); + sme_release_global_lock(&mac->sme); + return; + } + + setup_done = ucfg_mlme_is_twt_setup_done( + mac->psoc, (struct qdf_mac_addr *) + add_dialog_event->params.peer_macaddr, + add_dialog_event->params.dialog_id); + sme_debug("setup_done:%d status:%d", setup_done, status); + + if (setup_done && status) { + /*This is re-negotiation failure case */ + sme_process_twt_add_renego_failure(mac, + add_dialog_event); + } else { + sme_process_twt_add_initial_nego(mac, + add_dialog_event); + } + break; + default: + sme_debug("TWT Setup is not supported on %s", + qdf_opmode_str(opmode)); + } + + sme_release_global_lock(&mac->sme); + return; +} + +static bool +sme_is_twt_teardown_failed(enum WMI_HOST_DEL_TWT_STATUS teardown_status) +{ + switch (teardown_status) { + case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_NOT_EXIST: + case WMI_HOST_DEL_TWT_STATUS_INVALID_PARAM: + case WMI_HOST_DEL_TWT_STATUS_DIALOG_ID_BUSY: + case WMI_HOST_DEL_TWT_STATUS_NO_RESOURCE: + case WMI_HOST_DEL_TWT_STATUS_NO_ACK: + case WMI_HOST_DEL_TWT_STATUS_UNKNOWN_ERROR: + return true; + default: + return false; + } + + return false; +} + +static void +sme_process_sta_twt_del_dialog_event( + struct mac_context *mac, + struct wmi_twt_del_dialog_complete_event_param *param) +{ + twt_del_dialog_cb callback; + bool is_evt_allowed, usr_cfg_ps_enable; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + is_evt_allowed = mlme_twt_is_command_in_progress( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_TERMINATE, &active_cmd); + + if (!is_evt_allowed && + param->dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + param->status != WMI_HOST_DEL_TWT_STATUS_ROAMING && + param->status != WMI_HOST_DEL_TWT_STATUS_PEER_INIT_TEARDOWN && + param->status != WMI_HOST_DEL_TWT_STATUS_CONCURRENCY) { + sme_debug("Drop TWT Del dialog event for dialog_id:%d status:%d active_cmd:%d", + param->dialog_id, param->status, active_cmd); + + return; + } + + usr_cfg_ps_enable = mlme_get_user_ps(mac->psoc, param->vdev_id); + if (!usr_cfg_ps_enable && + param->status == WMI_HOST_DEL_TWT_STATUS_OK) + param->status = WMI_HOST_DEL_TWT_STATUS_PS_DISABLE_TEARDOWN; + + callback = mac->sme.twt_del_dialog_cb; + if (callback) + callback(mac->psoc, param); + + if (param->status == WMI_HOST_DEL_TWT_STATUS_ROAMING || + param->status == WMI_HOST_DEL_TWT_STATUS_CONCURRENCY) + mlme_twt_set_wait_for_notify(mac->psoc, param->vdev_id, true); + + /* Reset the active TWT command to none */ + mlme_set_twt_command_in_progress(mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_NONE); + + if (sme_is_twt_teardown_failed(param->status)) + return; + + ucfg_mlme_set_twt_setup_done(mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + false); + + ucfg_mlme_set_twt_session_state(mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED); + + mlme_init_twt_context(mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id); +} + +/** + * sme_process_twt_del_dialog_event() - Process twt del dialog event + * response from firmware + * @mac: Global MAC pointer + * @param: pointer to wmi_twt_del_dialog_complete_event_param buffer + * + * Return: None + */ +static void +sme_process_twt_del_dialog_event( + struct mac_context *mac, + struct wmi_twt_del_dialog_complete_event_param *param) +{ + twt_del_dialog_cb callback; + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, param->vdev_id); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + switch (opmode) { + case QDF_SAP_MODE: + callback = mac->sme.twt_del_dialog_cb; + if (callback) + callback(mac->psoc, param); + + /* + * If this is an unsolicited TWT del event initiated from the + * peer, then no need to clear the active command in progress + */ + if (param->status != + WMI_HOST_DEL_TWT_STATUS_PEER_INIT_TEARDOWN) { + /* Reset the active TWT command to none */ + sme_sap_set_twt_command_in_progress(mac->psoc, + param->vdev_id, + (struct qdf_mac_addr *)param->peer_macaddr, + param->dialog_id, WLAN_TWT_NONE); + sme_sap_init_twt_context(mac->psoc, param->vdev_id, + (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id); + } + break; + case QDF_STA_MODE: + sme_process_sta_twt_del_dialog_event(mac, param); + break; + default: + sme_debug("TWT Teardown is not supported on %s", + qdf_opmode_str(opmode)); + } + + sme_release_global_lock(&mac->sme); + return; +} + +/** + * sme_process_twt_pause_dialog_event() - Process twt pause dialog event + * response from firmware + * @mac: Global MAC pointer + * @param: pointer to wmi_twt_pause_dialog_complete_event_param buffer + * + * Return: None + */ +static void +sme_process_twt_pause_dialog_event( + struct mac_context *mac, + struct wmi_twt_pause_dialog_complete_event_param *param) +{ + twt_pause_dialog_cb callback; + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, param->vdev_id); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + switch (opmode) { + case QDF_SAP_MODE: + callback = mac->sme.twt_pause_dialog_cb; + if (callback) + callback(mac->psoc, param); + break; + case QDF_STA_MODE: + callback = mac->sme.twt_pause_dialog_cb; + if (callback) + callback(mac->psoc, param); + + ucfg_mlme_set_twt_session_state( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_SETUP_STATE_SUSPEND); + + /*Reset the active TWT command to none */ + mlme_set_twt_command_in_progress( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_NONE); + break; + default: + sme_debug("TWT Pause is not supported on %s", + qdf_opmode_str(opmode)); + } + + sme_release_global_lock(&mac->sme); + return; +} + +/** + * sme_process_twt_nudge_dialog_event() - Process twt nudge dialog event + * response from firmware + * @mac: Global MAC pointer + * @param: pointer to wmi_twt_nudge_dialog_complete_event_param buffer + * + * Return: None + */ +static void +sme_process_twt_nudge_dialog_event(struct mac_context *mac, + struct wmi_twt_nudge_dialog_complete_event_param *param) +{ + twt_nudge_dialog_cb callback; + bool is_evt_allowed; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + enum QDF_OPMODE opmode; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, param->vdev_id); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + switch (opmode) { + case QDF_SAP_MODE: + callback = mac->sme.twt_nudge_dialog_cb; + if (callback) + callback(mac->psoc, param); + break; + case QDF_STA_MODE: + is_evt_allowed = mlme_twt_is_command_in_progress( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_NUDGE, &active_cmd); + if (!is_evt_allowed && + param->dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + sme_debug("Nudge event dropped active_cmd:%d", + active_cmd); + goto fail; + } + + callback = mac->sme.twt_nudge_dialog_cb; + if (callback) + callback(mac->psoc, param); + /* Reset the active TWT command to none */ + mlme_set_twt_command_in_progress( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_NONE); + break; + default: + sme_debug("TWT Nudge is not supported on %s", + qdf_opmode_str(opmode)); + } + +fail: + sme_release_global_lock(&mac->sme); + return; +} + +/** + * sme_process_twt_resume_dialog_event() - Process twt resume dialog event + * response from firmware + * @mac: Global MAC pointer + * @param: pointer to wmi_twt_resume_dialog_complete_event_param buffer + * + * Return: None + */ +static void +sme_process_twt_resume_dialog_event( + struct mac_context *mac, + struct wmi_twt_resume_dialog_complete_event_param *param) +{ + twt_resume_dialog_cb callback; + QDF_STATUS qdf_status = QDF_STATUS_E_FAILURE; + enum QDF_OPMODE opmode; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, param->vdev_id); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return; + + switch (opmode) { + case QDF_SAP_MODE: + callback = mac->sme.twt_resume_dialog_cb; + if (callback) + callback(mac->psoc, param); + break; + case QDF_STA_MODE: + callback = mac->sme.twt_resume_dialog_cb; + if (callback) + callback(mac->psoc, param); + + ucfg_mlme_set_twt_session_state( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_SETUP_STATE_ACTIVE); + + /* Reset the active TWT command to none */ + mlme_set_twt_command_in_progress( + mac->psoc, (struct qdf_mac_addr *) + param->peer_macaddr, param->dialog_id, + WLAN_TWT_NONE); + break; + default: + sme_debug("TWT Resume is not supported on %s", + qdf_opmode_str(opmode)); + } + + sme_release_global_lock(&mac->sme); + return; +} + +/** + * sme_process_twt_notify_event() - Process twt ready for setup notification + * event from firmware + * @mac: Global MAC pointer + * @twt_notify_event: pointer to event buf containing twt notify parameters + * + * Return: None + */ +static void +sme_process_twt_notify_event(struct mac_context *mac, + struct wmi_twt_notify_event_param *notify_event) +{ + twt_notify_cb callback; + + mlme_twt_set_wait_for_notify(mac->psoc, notify_event->vdev_id, false); + callback = mac->sme.twt_notify_cb; + if (callback) + callback(mac->psoc, notify_event); +} + +/** + * sme_twt_update_beacon_template() - API to send beacon update to fw + * @mac: Global MAC pointer + * + * Return: None + */ +void sme_twt_update_beacon_template(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + csr_update_beacon(mac); +} + +#else +static void +sme_process_twt_add_dialog_event(struct mac_context *mac, + struct wma_twt_add_dialog_complete_event *add_dialog_event) +{ +} + +static void +sme_process_twt_del_dialog_event( + struct mac_context *mac, + struct wmi_twt_del_dialog_complete_event_param *param) +{ +} + +static void +sme_process_twt_pause_dialog_event(struct mac_context *mac, + struct wmi_twt_pause_dialog_complete_event_param *param) +{ +} + +static void +sme_process_twt_resume_dialog_event(struct mac_context *mac, + struct wmi_twt_resume_dialog_complete_event_param *param) +{ +} + +static void +sme_process_twt_nudge_dialog_event(struct mac_context *mac, + struct wmi_twt_nudge_dialog_complete_event_param *param) +{ +} + +static void +sme_process_twt_notify_event(struct mac_context *mac, + struct wmi_twt_notify_event_param *notify_event) +{ +} +#endif + +static void sme_link_lost_ind(struct mac_context *mac, + struct sir_lost_link_info *ind) +{ + struct cm_roam_values_copy src_cfg = {}; + + if (ind) { + src_cfg.int_value = ind->rssi; + wlan_cm_roam_cfg_set_value(mac->psoc, ind->vdev_id, + LOST_LINK_RSSI, &src_cfg); + } + if (mac->sme.lost_link_info_cb) + mac->sme.lost_link_info_cb(mac->hdd_handle, ind); +} + +#ifdef WLAN_FEATURE_SAP_ACS_OPTIMIZE +static void sme_indicate_chan_info_event(struct mac_context *mac, + struct channel_status *chan_stats, + uint8_t vdev_id) +{ + struct csr_roam_info *roam_info; + struct wlan_objmgr_vdev *vdev; + eRoamCmdStatus roam_status; + eCsrRoamResult roam_result; + enum QDF_OPMODE mode; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev not found for vdev %d", vdev_id); + return; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + if (mode != QDF_SAP_MODE) + return; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + + roam_info->chan_info_freq = chan_stats->channel_freq; + roam_status = eCSR_ROAM_CHANNEL_INFO_EVENT_IND; + roam_result = eCSR_ROAM_RESULT_NONE; + + /* Indicate channel info event to SAP */ + csr_roam_call_callback(mac, vdev_id, roam_info, + roam_status, roam_result); + + qdf_mem_free(roam_info); +} +#else +static void sme_indicate_chan_info_event(struct mac_context *mac, + struct channel_status *chan_stats, + uint8_t vdev_id) +{ +} +#endif + +static void sme_process_chan_info_event(struct mac_context *mac, + struct channel_status *chan_stats, + uint8_t vdev_id) +{ + if (!chan_stats) { + sme_err("Chan info report is NULL\n"); + return; + } + + wlan_cp_stats_update_chan_info(mac->psoc, chan_stats, vdev_id); + + sme_indicate_chan_info_event(mac, chan_stats, vdev_id); +} + +/** + * sme_process_sap_ch_width_update_rsp() - Process ch_width update response + * @mac: Global MAC pointer + * @msg: ch_width update response + * + * Processes the ch_width update response and invokes the HDD + * callback to process further + */ +static QDF_STATUS +sme_process_sap_ch_width_update_rsp(struct mac_context *mac, uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + struct sir_bcn_update_rsp *param; + enum policy_mgr_conn_update_reason reason; + uint32_t request_id; + uint8_t vdev_id; + QDF_STATUS status = QDF_STATUS_E_NOMEM; + + param = (struct sir_bcn_update_rsp *)msg; + if (!param) + sme_err("ch_width update resp param is NULL"); + /* Not returning. Need to check if active command list + * needs to be freed + */ + + if (param && param->reason != REASON_CH_WIDTH_UPDATE) { + sme_err("reason not ch_width update"); + return QDF_STATUS_E_INVAL; + } + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (!entry) { + sme_err("No cmd found in active list"); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sme_err("Base address is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_sap_ch_width_update != command->command) { + sme_err("Command mismatch!"); + return QDF_STATUS_E_FAILURE; + } + reason = command->u.bw_update_cmd.reason; + request_id = command->u.bw_update_cmd.request_id; + vdev_id = command->u.bw_update_cmd.conc_vdev_id; + if (param) + status = param->status; + sme_debug("vdev %d reason %d status %d cm_id 0x%x", + vdev_id, reason, status, request_id); + + if (reason == POLICY_MGR_UPDATE_REASON_CHANNEL_SWITCH_STA) { + sme_debug("Continue channel switch for STA on vdev %d", + vdev_id); + csr_sta_continue_csa(mac, vdev_id); + } else if (reason == POLICY_MGR_UPDATE_REASON_STA_CONNECT) { + sme_debug("Continue connect/reassoc on vdev %d reason %d status %d cm_id 0x%x", + vdev_id, reason, status, request_id); + wlan_cm_handle_hw_mode_change_resp(mac->pdev, vdev_id, + request_id, status); + } + + policy_mgr_set_connection_update(mac->psoc); + + found = csr_nonscan_active_ll_remove_entry(mac, entry, LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the available command list */ + csr_release_command(mac, command); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_process_msg(struct mac_context *mac, struct scheduler_msg *pMsg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!pMsg) { + sme_err("Empty message for SME"); + return status; + } + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + return status; + } + if (!SME_IS_START(mac)) { + sme_debug("message type %d in stop state ignored", pMsg->type); + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + goto release_lock; + } + switch (pMsg->type) { + case eWNI_SME_ADDTS_RSP: + case eWNI_SME_DELTS_RSP: + case eWNI_SME_DELTS_IND: + case eWNI_SME_FT_AGGR_QOS_RSP: + /* QoS */ + if (pMsg->bodyptr) { +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_msg_processor(mac, pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); +#endif + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_NEIGHBOR_REPORT_IND: + case eWNI_SME_BEACON_REPORT_REQ_IND: + case eWNI_SME_CHAN_LOAD_REQ_IND: + if (pMsg->bodyptr) { + status = sme_rrm_msg_processor(mac, pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_VDEV_DELETE_RSP: + if (pMsg->bodyptr) + sme_vdev_self_peer_delete_resp(pMsg->bodyptr); + else + sme_err("Empty message for: %d", pMsg->type); + break; + case eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE: + if (pMsg->bodyptr) { + status = sme_handle_generic_change_country_code( + (void *)mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_UNPROT_MGMT_FRM_IND: + if (pMsg->bodyptr) { + sme_unprotected_mgmt_frm_ind(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_TSM_IE_IND: + if (pMsg->bodyptr) { + sme_tsm_ie_ind(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; +#endif /* FEATURE_WLAN_ESE */ +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case eWNI_SME_READY_TO_EXTWOW_IND: + if (pMsg->bodyptr) { + sme_process_ready_to_ext_wow(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; +#endif +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case eWNI_SME_AUTO_SHUTDOWN_IND: + if (mac->sme.auto_shutdown_cb) { + sme_debug("Auto shutdown notification"); + mac->sme.auto_shutdown_cb(); + } + break; +#endif + case eWNI_SME_DFS_RADAR_FOUND: + case eWNI_SME_DFS_CAC_COMPLETE: + case eWNI_SME_DFS_CSAIE_TX_COMPLETE_IND: + case eWNI_SME_CSA_RESTART_RSP: + status = dfs_msg_processor(mac, pMsg); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CHANNEL_CHANGE_RSP: + if (pMsg->bodyptr) { + status = sme_process_channel_change_resp(mac, + pMsg->type, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_STATS_EXT_EVENT: + status = sme_stats_ext_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_FW_STATUS_IND: + status = sme_fw_state_resp(mac); + break; + case eWNI_SME_TSF_EVENT: + if (mac->sme.get_tsf_cb) { + mac->sme.get_tsf_cb(mac->sme.get_tsf_cxt, + (struct stsf *)pMsg->bodyptr); + } + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_LINK_STATUS_IND: + { + tAniGetLinkStatus *pLinkStatus = + (tAniGetLinkStatus *) pMsg->bodyptr; + if (pLinkStatus) { + if (mac->sme.link_status_callback) + mac->sme.link_status_callback( + pLinkStatus->linkStatus, + mac->sme.link_status_context); + + mac->sme.link_status_callback = NULL; + mac->sme.link_status_context = NULL; + qdf_mem_free(pLinkStatus); + } + break; + } + case eWNI_SME_MSG_GET_TEMPERATURE_IND: + if (mac->sme.temperature_cb) + mac->sme.temperature_cb(pMsg->bodyval, + mac->sme.temperature_cb_context); + break; + case eWNI_SME_SNR_IND: + { + tAniGetSnrReq *pSnrReq = (tAniGetSnrReq *) pMsg->bodyptr; + + if (pSnrReq) { + if (pSnrReq->snrCallback) { + ((tCsrSnrCallback) + (pSnrReq->snrCallback))(pSnrReq->snr, + pSnrReq->pDevContext); + } + qdf_mem_free(pSnrReq); + } + break; + } +#ifdef FEATURE_WLAN_EXTSCAN + case eWNI_SME_EXTSCAN_FULL_SCAN_RESULT_IND: + if (mac->sme.ext_scan_ind_cb) + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_FULL_SCAN_RESULT_IND, + pMsg->bodyptr); + else + sme_err("callback not registered to process: %d", + pMsg->type); + + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_EPNO_NETWORK_FOUND_IND: + if (mac->sme.ext_scan_ind_cb) + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EPNO_NETWORK_FOUND_IND, + pMsg->bodyptr); + else + sme_err("callback not registered to process: %d", + pMsg->type); + + qdf_mem_free(pMsg->bodyptr); + break; +#endif + case eWNI_SME_SET_HW_MODE_RESP: + if (pMsg->bodyptr) { + status = sme_process_set_hw_mode_resp(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_HW_MODE_TRANS_IND: + if (pMsg->bodyptr) { + status = sme_process_hw_mode_trans_ind(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_NSS_UPDATE_RSP: + if (pMsg->bodyptr) { + status = sme_process_nss_update_resp(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_SET_DUAL_MAC_CFG_RESP: + if (pMsg->bodyptr) { + status = sme_process_dual_mac_config_resp(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_SET_THERMAL_LEVEL_IND: + if (mac->sme.set_thermal_level_cb) + mac->sme.set_thermal_level_cb(mac->hdd_handle, + pMsg->bodyval); + break; + case eWNI_SME_EXT_CHANGE_CHANNEL_IND: + status = sme_extended_change_channel_ind(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_SET_ANTENNA_MODE_RESP: + if (pMsg->bodyptr) { + status = sme_process_antenna_mode_resp(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_LOST_LINK_INFO_IND: + sme_link_lost_ind(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_RSO_CMD_STATUS_IND: + if (mac->sme.rso_cmd_status_cb) + mac->sme.rso_cmd_status_cb(mac->hdd_handle, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWMI_SME_LL_STATS_IND: + if (mac->sme.link_layer_stats_ext_cb) + mac->sme.link_layer_stats_ext_cb(mac->hdd_handle, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_BT_ACTIVITY_INFO_IND: + if (mac->sme.bt_activity_info_cb) + mac->sme.bt_activity_info_cb(mac->hdd_handle, + pMsg->bodyval); + break; + case eWNI_SME_HIDDEN_SSID_RESTART_RSP: + if (mac->sme.hidden_ssid_cb) + mac->sme.hidden_ssid_cb(mac->hdd_handle, pMsg->bodyval); + else + sme_err("callback is NULL"); + break; + case eWNI_SME_ANTENNA_ISOLATION_RSP: + if (pMsg->bodyptr) { + if (mac->sme.get_isolation_cb) + mac->sme.get_isolation_cb( + (struct sir_isolation_resp *)pMsg->bodyptr, + mac->sme.get_isolation_cb_context); + qdf_mem_free(pMsg->bodyptr); + } else { + sme_err("Empty message for: %d", pMsg->type); + } + break; + case eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT: + sme_process_roam_scan_ch_list_resp(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_MONITOR_MODE_VDEV_UP: + status = sme_process_monitor_mode_vdev_up_evt(pMsg->bodyval); + break; + case eWNI_SME_TWT_ADD_DIALOG_EVENT: + sme_process_twt_add_dialog_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_TWT_DEL_DIALOG_EVENT: + sme_process_twt_del_dialog_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_TWT_PAUSE_DIALOG_EVENT: + sme_process_twt_pause_dialog_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_TWT_RESUME_DIALOG_EVENT: + sme_process_twt_resume_dialog_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_TWT_NUDGE_DIALOG_EVENT: + sme_process_twt_nudge_dialog_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_TWT_NOTIFY_EVENT: + sme_process_twt_notify_event(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_START_BSS_RSP: + csr_roam_roaming_state_start_bss_rsp_processor(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_STOP_BSS_RSP: + csr_roam_roaming_state_stop_bss_rsp_processor(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_CHAN_INFO_EVENT: + sme_process_chan_info_event(mac, pMsg->bodyptr, pMsg->bodyval); + qdf_mem_free(pMsg->bodyptr); + break; + case eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP: + status = sme_process_sap_ch_width_update_rsp(mac, + pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + break; + default: + + if ((pMsg->type >= eWNI_SME_MSG_TYPES_BEGIN) + && (pMsg->type <= eWNI_SME_MSG_TYPES_END)) { + /* CSR */ + if (pMsg->bodyptr) { + status = csr_msg_processor(mac, pMsg->bodyptr); + qdf_mem_free(pMsg->bodyptr); + } else + sme_err("Empty message for: %d", pMsg->type); + } else { + sme_warn("Unknown message type: %d", pMsg->type); + if (pMsg->bodyptr) + qdf_mem_free(pMsg->bodyptr); + } + } /* switch */ +release_lock: + sme_release_global_lock(&mac->sme); + return status; +} + +QDF_STATUS sme_mc_process_handler(struct scheduler_msg *msg) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + + if (!mac_ctx) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return sme_process_msg(mac_ctx, msg); +} + +/** + * sme_process_nss_update_resp() - Process nss update response + * @mac: Global MAC pointer + * @msg: nss update response + * + * Processes the nss update response and invokes the HDD + * callback to process further + */ +static QDF_STATUS sme_process_nss_update_resp(struct mac_context *mac, uint8_t *msg) +{ + tListElem *entry = NULL; + tSmeCmd *command = NULL; + bool found; + policy_mgr_nss_update_cback callback = NULL; + struct sir_bcn_update_rsp *param; + + param = (struct sir_bcn_update_rsp *)msg; + if (!param) + sme_err("nss update resp param is NULL"); + /* Not returning. Need to check if active command list + * needs to be freed + */ + + if (param && param->reason != REASON_NSS_UPDATE) { + sme_err("reason not NSS update"); + return QDF_STATUS_E_INVAL; + } + entry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (!entry) { + sme_err("No cmd found in active list"); + return QDF_STATUS_E_FAILURE; + } + + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (!command) { + sme_err("Base address is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (e_sme_command_nss_update != command->command) { + sme_err("Command mismatch!"); + return QDF_STATUS_E_FAILURE; + } + + callback = command->u.nss_update_cmd.nss_update_cb; + if (callback) { + if (!param) + sme_err("Callback failed since nss update params is NULL"); + else + callback(command->u.nss_update_cmd.context, + param->status, + param->vdev_id, + command->u.nss_update_cmd.next_action, + command->u.nss_update_cmd.reason, + command->u.nss_update_cmd.original_vdev_id, + command->u.nss_update_cmd.request_id); + } else { + sme_err("Callback does not exist"); + } + + found = csr_nonscan_active_ll_remove_entry(mac, entry, LL_ACCESS_LOCK); + if (found) { + /* Now put this command back on the available command list */ + csr_release_command(mac, command); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_stop(mac_handle_t mac_handle) +{ + QDF_STATUS status; + QDF_STATUS ret_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = rrm_stop(mac); + if (QDF_IS_STATUS_ERROR(status)) { + ret_status = status; + sme_err("rrm_stop failed with status: %d", status); + } + + status = csr_stop(mac); + if (QDF_IS_STATUS_ERROR(status)) { + ret_status = status; + sme_err("csr_stop failed with status: %d", status); + } + + mac->sme.state = SME_STATE_STOP; + + return ret_status; +} + +/* + * sme_close() - Release all SME modules and their resources. + * The function release each module in SME, PMC, CSR, etc. . Upon + * return, all modules are at closed state. + * + * No SME APIs can be involved after smeClose except smeOpen. + * smeClose must be called before mac_close. + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open + * Return QDF_STATUS_SUCCESS - SME is successfully close. + * + * Other status means SME is failed to be closed but caller still cannot + * call any other SME functions except smeOpen. + */ +QDF_STATUS sme_close(mac_handle_t mac_handle) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS fail_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) + return QDF_STATUS_E_FAILURE; + + sme_unregister_power_debug_stats_cb(mac); + + status = csr_close(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("csr_close failed with status: %d", status); + fail_status = status; + } +#ifndef WLAN_MDM_CODE_REDUCTION_OPT + status = sme_qos_close(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Qos close failed with status: %d", status); + fail_status = status; + } +#endif + status = sme_ps_close(mac_handle); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_ps_close failed status: %d", status); + fail_status = status; + } + + status = rrm_close(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("RRM close failed with status: %d", status); + fail_status = status; + } + + free_sme_cmd_list(mac); + + status = qdf_mutex_destroy(&mac->sme.sme_global_lock); + if (!QDF_IS_STATUS_SUCCESS(status)) + fail_status = QDF_STATUS_E_FAILURE; + + mac->sme.state = SME_STATE_STOP; + + return fail_status; +} + +eCsrPhyMode sme_get_phy_mode(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->roam.configParam.phyMode; +} + +QDF_STATUS sme_get_network_params(struct mac_context *mac, + struct bss_dot11_config *dot11_cfg) +{ + enum csr_cfgdot11mode dot11_mode; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool chan_switch_hostapd_rate_enabled = true; + uint8_t mcc_to_scc_switch = 0; + enum QDF_OPMODE opmode; + + if (!mac) + return status; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + ucfg_mlme_get_sap_chan_switch_rate_enabled(mac->psoc, + &chan_switch_hostapd_rate_enabled); + ucfg_policy_mgr_get_mcc_scc_switch(mac->psoc, + &mcc_to_scc_switch); + + if (mcc_to_scc_switch != QDF_MCC_TO_SCC_SWITCH_DISABLE) + chan_switch_hostapd_rate_enabled = false; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, + dot11_cfg->vdev_id); + dot11_mode = + csr_roam_get_phy_mode_band_for_bss(mac, dot11_cfg); + + dot11_cfg->dot11_mode = + csr_translate_to_wni_cfg_dot11_mode(mac, dot11_mode); + + dot11_cfg->nw_type = + csr_convert_mode_to_nw_type(dot11_mode, dot11_cfg->p_band); + + /* If INI is enabled, use the rates from hostapd */ + if (!cds_is_sub_20_mhz_enabled() && chan_switch_hostapd_rate_enabled && + (dot11_cfg->opr_rates.numRates || dot11_cfg->ext_rates.numRates)) { + sme_err("Use the rates from the hostapd"); + } else { /* Populate new rates */ + dot11_cfg->ext_rates.numRates = 0; + dot11_cfg->opr_rates.numRates = 0; + + switch (dot11_cfg->nw_type) { + case eSIR_11A_NW_TYPE: + wlan_populate_basic_rates(&dot11_cfg->opr_rates, + true, true); + break; + case eSIR_11B_NW_TYPE: + wlan_populate_basic_rates(&dot11_cfg->opr_rates, + false, true); + break; + case eSIR_11G_NW_TYPE: + if ((opmode == QDF_P2P_CLIENT_MODE) || + (opmode == QDF_P2P_GO_MODE) || + (dot11_mode == eCSR_CFG_DOT11_MODE_11G_ONLY)) { + wlan_populate_basic_rates(&dot11_cfg->opr_rates, + true, true); + } else { + wlan_populate_basic_rates(&dot11_cfg->opr_rates, + false, true); + wlan_populate_basic_rates(&dot11_cfg->ext_rates, + true, false); + } + break; + default: + sme_release_global_lock(&mac->sme); + sme_err("Unknown network type %d", dot11_cfg->nw_type); + return QDF_STATUS_E_FAILURE; + } + } + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_start_bss(mac_handle_t mac_handle, uint8_t vdev_id, + struct start_bss_config *bss_config) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) + return QDF_STATUS_E_FAILURE; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_CONNECT, vdev_id, 0)); + + if (!CSR_IS_SESSION_VALID(mac, vdev_id)) { + sme_err("Invalid sessionID: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = csr_bss_start(mac, vdev_id, bss_config); + sme_release_global_lock(&mac->sme); + + return status; +} + +/* + * sme_set_phy_mode() - + * Changes the PhyMode. + * + * mac_handle - The handle returned by mac_open. + * phyMode new phyMode which is to set + * Return QDF_STATUS SUCCESS. + */ +QDF_STATUS sme_set_phy_mode(mac_handle_t mac_handle, eCsrPhyMode phyMode) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + mac->roam.configParam.phyMode = phyMode; + mac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(false, + mac->roam.configParam.phyMode); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_get_11b_data_duration() - + * returns 11b data duration via channel freq. + * + * mac_handle - The handle returned by mac_open. + * chan_freq - channel frequency + * + * Return - 11b data duration on success else 0 + */ +uint32_t sme_get_11b_data_duration(mac_handle_t mac_handle, uint32_t chan_freq) +{ + uint32_t rx_11b_data_duration = 0; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct channel_status *chan_status = + ucfg_mc_cp_stats_get_channel_status(mac->pdev, chan_freq); + + if (chan_status) + rx_11b_data_duration = chan_status->rx_11b_mode_data_duration; + + return rx_11b_data_duration; +} + +QDF_STATUS sme_roam_ndi_stop(mac_handle_t mac_handle, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT, vdev_id, + 0)); + + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_debug("Invalid sessionID: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = csr_roam_ndi_stop(mac_ctx, vdev_id); + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +/* sme_dhcp_done_ind() - send dhcp done ind + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * + * Return: void. + */ +void sme_dhcp_done_ind(mac_handle_t mac_handle, uint8_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + if (!mac_ctx) + return; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("Session: %d not found", session_id); + return; + } + session->dhcp_done = true; +} + +QDF_STATUS sme_roam_stop_bss(mac_handle_t mac_handle, uint8_t vdev_id) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = csr_roam_issue_stop_bss_cmd(mac, vdev_id, + eCSR_BSS_TYPE_INFRA_AP); + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_roam_disconnect_sta() - disassociate a station + * @mac_handle: Global structure + * @sessionId: SessionId of SoftAP + * @p_del_sta_params: Pointer to parameters of the station to disassoc + * + * To disassociate a station. This is an asynchronous API. + * + * Return: QDF_STATUS_SUCCESS on success.Roam callback will + * be called to indicate actual result. + */ +QDF_STATUS sme_roam_disconnect_sta(mac_handle_t mac_handle, uint8_t sessionId, + struct csr_del_sta_params *p_del_sta_params) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + QDF_ASSERT(0); + return status; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac, sessionId)) + status = csr_roam_issue_disassociate_sta_cmd(mac, + sessionId, p_del_sta_params); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/** + * sme_roam_deauth_sta() - deauthenticate a station + * @mac_handle: Global structure + * @sessionId: SessionId of SoftAP + * @pDelStaParams: Pointer to parameters of the station to deauthenticate + * + * To disassociate a station. This is an asynchronous API. + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS error + * code on error. Roam callback will be called to indicate actual + * result + */ +QDF_STATUS sme_roam_deauth_sta(mac_handle_t mac_handle, uint8_t sessionId, + struct csr_del_sta_params *pDelStaParams) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + QDF_ASSERT(0); + return status; + } + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA, + sessionId, pDelStaParams->reason_code)); + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac, sessionId)) + status = + csr_roam_issue_deauth_sta_cmd(mac, sessionId, + pDelStaParams); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void sme_get_pmk_info(mac_handle_t mac_handle, uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status = sme_acquire_global_lock(&mac_ctx->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id)) + csr_get_pmk_info(mac_ctx, session_id, pmk_cache); + sme_release_global_lock(&mac_ctx->sme); + } +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * sme_roam_set_psk_pmk() - a wrapper function to request CSR to save PSK/PMK + * This is a synchronous call. + * @mac_handle: Global structure + * @vdev_id: vdev id + * @pmksa : PMK entry + * @update_to_fw: True - send RSO update to firmware after updating + * session->psk_pmk. + * False - Copy the pmk to session->psk_pmk and return + * + * Return: QDF_STATUS - status whether PSK/PMK is set or not + */ +QDF_STATUS sme_roam_set_psk_pmk(mac_handle_t mac_handle, + struct wlan_crypto_pmksa *pmksa, + uint8_t vdev_id, bool update_to_fw) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (CSR_IS_SESSION_VALID(mac, vdev_id)) + status = csr_roam_set_psk_pmk(mac, pmksa, vdev_id, + update_to_fw); + else + status = QDF_STATUS_E_INVAL; + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_set_pmk_cache_ft(mac_handle_t mac_handle, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_pmk_cache_ft(mac, vdev_id, pmk_cache); + sme_release_global_lock(&mac->sme); + } + return status; +} +#endif + +/* + * sme_get_config_param() - + * A wrapper function that HDD calls to get the global settings + * currently maintained by CSR. + * This is a synchronous call. + * + * pParam - caller allocated memory + * Return QDF_STATUS + */ +QDF_STATUS sme_get_config_param(mac_handle_t mac_handle, + struct sme_config_params *pParam) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM, NO_SESSION, 0)); + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_config_param(mac, &pParam->csr_config); + if (status != QDF_STATUS_SUCCESS) { + sme_err("csr_get_config_param failed"); + sme_release_global_lock(&mac->sme); + return status; + } + sme_release_global_lock(&mac->sme); + } + + return status; +} + +uint32_t sme_get_vht_ch_width(void) +{ + return wma_get_vht_ch_width(); +} + +#ifdef WLAN_FEATURE_11BE +uint32_t sme_get_eht_ch_width(void) +{ + return wma_get_eht_ch_width(); +} +#endif + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * sme_register_oem_data_rsp_callback() - Register a routine of + * type send_oem_data_rsp_msg + * @mac_handle: Handle returned by mac_open. + * @callback: Callback to send response + * to oem application. + * + * sme_oem_data_rsp_callback is used to register sme_send_oem_data_rsp_msg + * callback function. + * + * Return: QDF_STATUS. + */ +QDF_STATUS sme_register_oem_data_rsp_callback(mac_handle_t mac_handle, + sme_send_oem_data_rsp_msg callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *pmac = MAC_CONTEXT(mac_handle); + + pmac->sme.oem_data_rsp_callback = callback; + + return status; + +} + +/** + * sme_deregister_oem_data_rsp_callback() - De-register OEM datarsp callback + * @mac_handle: Handler return by mac_open + * This function De-registers the OEM data response callback to SME + * + * Return: None + */ +void sme_deregister_oem_data_rsp_callback(mac_handle_t mac_handle) +{ + struct mac_context *pmac; + + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return; + } + pmac = MAC_CONTEXT(mac_handle); + + pmac->sme.oem_data_rsp_callback = NULL; +} + +/** + * sme_oem_update_capability() - update UMAC's oem related capability. + * @mac_handle: Handle returned by mac_open + * @oem_cap: pointer to oem_capability + * + * This function updates OEM capability to UMAC. Currently RTT + * related capabilities are updated. More capabilities can be + * added in future. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_update_capability(mac_handle_t mac_handle, + struct sme_oem_capability *cap) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *pmac = MAC_CONTEXT(mac_handle); + uint8_t *bytes; + + bytes = pmac->rrm.rrmConfig.rm_capability; + + if (cap->ftm_rr) + bytes[4] |= RM_CAP_FTM_RANGE_REPORT; + if (cap->lci_capability) + bytes[4] |= RM_CAP_CIVIC_LOC_MEASUREMENT; + + return status; +} + +/** + * sme_oem_get_capability() - get oem capability + * @mac_handle: Handle returned by mac_open + * @oem_cap: pointer to oem_capability + * + * This function is used to get the OEM capability from UMAC. + * Currently RTT related capabilities are received. More + * capabilities can be added in future. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_oem_get_capability(mac_handle_t mac_handle, + struct sme_oem_capability *cap) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *pmac = MAC_CONTEXT(mac_handle); + uint8_t *bytes; + + bytes = pmac->rrm.rrmConfig.rm_capability; + + cap->ftm_rr = bytes[4] & RM_CAP_FTM_RANGE_REPORT; + cap->lci_capability = bytes[4] & RM_CAP_CIVIC_LOC_MEASUREMENT; + + return status; +} +#endif + +/* + * sme_get_snr() - + * A wrapper function that client calls to register a callback to get SNR + * + * callback - SME sends back the requested stats using the callback + * staId - The station ID for which the stats is requested for + * pContext - user context to be passed back along with the callback + * p_cds_context - cds context + * \return QDF_STATUS + */ +QDF_STATUS sme_get_snr(mac_handle_t mac_handle, + tCsrSnrCallback callback, + struct qdf_mac_addr bssId, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_get_snr(mac, callback, bssId, pContext); + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_get_link_status(mac_handle_t mac_handle, + csr_link_status_callback callback, + void *context, uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + tAniGetLinkStatus *msg; + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + msg->msgType = WMA_LINK_STATUS_GET_REQ; + msg->msgLen = sizeof(*msg); + msg->sessionId = session_id; + mac->sme.link_status_context = context; + mac->sme.link_status_callback = callback; + + message.type = WMA_LINK_STATUS_GET_REQ; + message.bodyptr = msg; + message.reserved = 0; + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("post msg failed, %d", status); + qdf_mem_free(msg); + mac->sme.link_status_context = NULL; + mac->sme.link_status_callback = NULL; + } + + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/* + * sme_generic_change_country_code() - + * Change Country code from upperlayer during WLAN driver operation. + * This is a synchronous API. + * + * mac_handle - The handle returned by mac_open. + * pCountry New Country Code String + * reg_domain regulatory domain + * Return QDF_STATUS SUCCESS. + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_generic_change_country_code(mac_handle_t mac_handle, + uint8_t *pCountry) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + tAniGenericChangeCountryCodeReq *pMsg; + + if (!mac) { + sme_err("mac is null"); + return status; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg = qdf_mem_malloc(sizeof(tAniGenericChangeCountryCodeReq)); + if (!pMsg) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE; + pMsg->msgLen = + (uint16_t) sizeof(tAniGenericChangeCountryCodeReq); + qdf_mem_copy(pMsg->countryCode, pCountry, 2); + pMsg->countryCode[2] = ' '; + + msg.type = eWNI_SME_GENERIC_CHANGE_COUNTRY_CODE; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &msg)) { + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/* + * sme_dhcp_start_ind() - + * API to signal the FW about the DHCP Start event. + * + * mac_handle: Opaque handle to the global MAC context. + * device_mode - mode(AP,SAP etc) of the device. + * macAddr - MAC address of the adapter. + * sessionId - session ID. + * Return QDF_STATUS SUCCESS. + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_dhcp_start_ind(mac_handle_t mac_handle, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + tAniDHCPInd *pMsg; + struct csr_roam_session *pSession; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("Session: %d not found", sessionId); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + pSession->dhcp_done = false; + + pMsg = qdf_mem_malloc(sizeof(tAniDHCPInd)); + if (!pMsg) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + pMsg->msgType = WMA_DHCP_START_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniDHCPInd); + pMsg->device_mode = device_mode; + qdf_mem_copy(pMsg->adapterMacAddr.bytes, macAddr, + QDF_MAC_ADDR_SIZE); + wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, + &pMsg->peerMacAddr); + + message.type = WMA_DHCP_START_IND; + message.bodyptr = pMsg; + message.reserved = 0; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, message.type)); + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Post DHCP Start MSG fail"); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_dhcp_stop_ind() - + * API to signal the FW about the DHCP complete event. + * + * mac_handle: Opaque handle to the global MAC context. + * device_mode - mode(AP, SAP etc) of the device. + * macAddr - MAC address of the adapter. + * sessionId - session ID. + * Return QDF_STATUS SUCCESS. + * FAILURE or RESOURCES The API finished and failed. + */ +QDF_STATUS sme_dhcp_stop_ind(mac_handle_t mac_handle, + uint8_t device_mode, + uint8_t *macAddr, uint8_t sessionId) +{ + QDF_STATUS status; + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + tAniDHCPInd *pMsg; + struct csr_roam_session *pSession; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("Session: %d not found", sessionId); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + pSession->dhcp_done = true; + + pMsg = qdf_mem_malloc(sizeof(tAniDHCPInd)); + if (!pMsg) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + pMsg->msgType = WMA_DHCP_STOP_IND; + pMsg->msgLen = (uint16_t) sizeof(tAniDHCPInd); + pMsg->device_mode = device_mode; + qdf_mem_copy(pMsg->adapterMacAddr.bytes, macAddr, + QDF_MAC_ADDR_SIZE); + + wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, + &pMsg->peerMacAddr); + + message.type = WMA_DHCP_STOP_IND; + message.bodyptr = pMsg; + message.reserved = 0; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, message.type)); + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Post DHCP Stop MSG fail"); + qdf_mem_free(pMsg); + status = QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_neighbor_report_request() - + * API to request neighbor report. + * + * mac_handle - The handle returned by mac_open. + * pRrmNeighborReq - Pointer to a caller allocated object of type + * tRrmNeighborReq. Caller owns the memory and is + * responsible for freeing it. + * Return QDF_STATUS + * QDF_STATUS_E_FAILURE - failure + * QDF_STATUS_SUCCESS success + */ +QDF_STATUS sme_neighbor_report_request( + mac_handle_t mac_handle, + uint8_t sessionId, + tpRrmNeighborReq pRrmNeighborReq, + tpRrmNeighborRspCallbackInfo callbackInfo) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ, NO_SESSION, + 0)); + + if (pRrmNeighborReq->neighbor_report_offload) { + status = csr_invoke_neighbor_report_request(sessionId, + pRrmNeighborReq, + false); + return status; + } + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&mac->sme)) { + status = + sme_rrm_neighbor_report_request(mac, sessionId, + pRrmNeighborReq, callbackInfo); + sme_release_global_lock(&mac->sme); + } + + return status; +} + +void +sme_register_pagefault_cb(mac_handle_t mac_handle, + QDF_STATUS (*hdd_pagefault_action_cb)(void *buf, + uint32_t data)) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + SME_ENTER(); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.pagefault_action_cb = hdd_pagefault_action_cb; + sme_release_global_lock(&mac->sme); + } + + SME_EXIT(); +} + +void sme_deregister_ssr_on_pagefault_cb(mac_handle_t mac_handle) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + SME_ENTER(); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.pagefault_action_cb = NULL; + sme_release_global_lock(&mac->sme); + } + + SME_EXIT(); +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +QDF_STATUS sme_oem_req_cmd(mac_handle_t mac_handle, + struct oem_data_req *oem_req) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct oem_data_req *oem_data_req; + void *wma_handle; + + SME_ENTER(); + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + oem_data_req = qdf_mem_malloc(sizeof(*oem_data_req)); + if (!oem_data_req) + return QDF_STATUS_E_NOMEM; + + oem_data_req->data_len = oem_req->data_len; + oem_data_req->data = qdf_mem_malloc(oem_data_req->data_len); + if (!oem_data_req->data) { + qdf_mem_free(oem_data_req); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(oem_data_req->data, oem_req->data, + oem_data_req->data_len); + + status = wma_start_oem_req_cmd(wma_handle, oem_data_req); + + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("Post oem data request msg fail"); + else + sme_debug("OEM request(length: %d) sent to WMA", + oem_data_req->data_len); + + if (oem_data_req->data_len) + qdf_mem_free(oem_data_req->data); + qdf_mem_free(oem_data_req); + + SME_EXIT(); + return status; +} +#endif /*FEATURE_OEM_DATA_SUPPORT */ + +#ifdef FEATURE_OEM_DATA +QDF_STATUS sme_oem_data_cmd(mac_handle_t mac_handle, + void (*oem_data_event_handler_cb) + (const struct oem_data *oem_event_data, + uint8_t vdev_id), + struct oem_data *oem_data, + uint8_t vdev_id) +{ + QDF_STATUS status; + void *wma_handle; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + SME_ENTER(); + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.oem_data_event_handler_cb = oem_data_event_handler_cb; + mac->sme.oem_data_vdev_id = vdev_id; + sme_release_global_lock(&mac->sme); + } + status = wma_start_oem_data_cmd(wma_handle, oem_data); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("fail to call wma_start_oem_data_cmd."); + + SME_EXIT(); + return status; +} + +void sme_oem_event_deinit(mac_handle_t mac_handle) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + SME_ENTER(); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.oem_data_event_handler_cb = NULL; + mac->sme.oem_data_vdev_id = WMA_INVALID_VDEV_ID; + sme_release_global_lock(&mac->sme); + } + + SME_EXIT(); +} + +void sme_async_oem_event_init(mac_handle_t mac_handle, + void (*oem_data_async_event_handler_cb) + (const struct oem_data *oem_event_data)) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + SME_ENTER(); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.oem_data_async_event_handler_cb = + oem_data_async_event_handler_cb; + sme_release_global_lock(&mac->sme); + } + + SME_EXIT(); +} + +void sme_async_oem_event_deinit(mac_handle_t mac_handle) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + SME_ENTER(); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.oem_data_async_event_handler_cb = NULL; + sme_release_global_lock(&mac->sme); + } + + SME_EXIT(); +} +#endif + +#define STA_NSS_CHAINS_SHIFT 0 +#define SAP_NSS_CHAINS_SHIFT 3 +#define P2P_GO_NSS_CHAINS_SHIFT 6 +#define P2P_CLI_CHAINS_SHIFT 9 +#define TDLS_NSS_CHAINS_SHIFT 12 +#define IBSS_NSS_CHAINS_SHIFT 15 +#define P2P_DEV_NSS_CHAINS_SHIFT 18 +#define OCB_NSS_CHAINS_SHIFT 21 +#define NAN_NSS_CHAIN_SHIFT 24 +#define NSS_CHAIN_MASK 0x7 +#define GET_VDEV_NSS_CHAIN(x, y) (((x) >> (y)) & NSS_CHAIN_MASK) + +static uint8_t sme_get_nss_chain_shift(enum QDF_OPMODE device_mode) +{ + switch (device_mode) { + case QDF_STA_MODE: + return STA_NSS_CHAINS_SHIFT; + case QDF_SAP_MODE: + return SAP_NSS_CHAINS_SHIFT; + case QDF_P2P_GO_MODE: + return P2P_GO_NSS_CHAINS_SHIFT; + case QDF_P2P_CLIENT_MODE: + return P2P_CLI_CHAINS_SHIFT; + case QDF_IBSS_MODE: + return IBSS_NSS_CHAINS_SHIFT; + case QDF_P2P_DEVICE_MODE: + return P2P_DEV_NSS_CHAINS_SHIFT; + case QDF_OCB_MODE: + return OCB_NSS_CHAINS_SHIFT; + case QDF_TDLS_MODE: + return TDLS_NSS_CHAINS_SHIFT; + + default: + sme_err("Device mode %d invalid", device_mode); + return STA_NSS_CHAINS_SHIFT; + } +} + +static void +sme_check_nss_chain_ini_param(struct wlan_mlme_nss_chains *vdev_ini_cfg, + uint8_t rf_chains_supported, + enum nss_chains_band_info band) +{ + vdev_ini_cfg->rx_nss[band] = QDF_MIN(vdev_ini_cfg->rx_nss[band], + rf_chains_supported); + vdev_ini_cfg->tx_nss[band] = QDF_MIN(vdev_ini_cfg->tx_nss[band], + rf_chains_supported); +} + +static void +sme_fill_nss_chain_params(struct mac_context *mac_ctx, + struct wlan_mlme_nss_chains *vdev_ini_cfg, + enum QDF_OPMODE device_mode, + enum nss_chains_band_info band, + uint8_t rf_chains_supported) +{ + uint8_t nss_chain_shift; + uint8_t max_supported_nss; + enum coex_btc_chain_mode btc_chain_mode; + struct wlan_mlme_nss_chains *nss_chains_ini_cfg = + &mac_ctx->mlme_cfg->nss_chains_ini_cfg; + QDF_STATUS status; + + nss_chain_shift = sme_get_nss_chain_shift(device_mode); + max_supported_nss = mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2 ? + MAX_VDEV_NSS : 1; + + /* + * If target supports Antenna sharing, set NSS to 1 for 2.4GHz band for + * NDI vdev. + */ + if (device_mode == QDF_NDI_MODE && mac_ctx->mlme_cfg->gen.as_enabled && + band == NSS_CHAINS_BAND_2GHZ) + max_supported_nss = NSS_1x1_MODE; + + status = ucfg_coex_psoc_get_btc_chain_mode(mac_ctx->psoc, + &btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to get BT coex chain mode"); + btc_chain_mode = WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + } + + if (band == NSS_CHAINS_BAND_2GHZ && + (btc_chain_mode == WLAN_COEX_BTC_CHAIN_MODE_FDD || + btc_chain_mode == WLAN_COEX_BTC_CHAIN_MODE_HYBRID)) + max_supported_nss = NSS_1x1_MODE; + + /* If the fw doesn't support two chains, num rf chains can max be 1 */ + vdev_ini_cfg->num_rx_chains[band] = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->num_rx_chains[band], + nss_chain_shift), rf_chains_supported); + + vdev_ini_cfg->num_tx_chains[band] = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->num_tx_chains[band], + nss_chain_shift), rf_chains_supported); + + /* If 2x2 mode is disabled, then max rx, tx nss can be 1 */ + vdev_ini_cfg->rx_nss[band] = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->rx_nss[band], + nss_chain_shift), max_supported_nss); + + vdev_ini_cfg->tx_nss[band] = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->tx_nss[band], + nss_chain_shift), max_supported_nss); + + vdev_ini_cfg->num_tx_chains_11a = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->num_tx_chains_11a, + nss_chain_shift), rf_chains_supported); + + /* If the fw doesn't support two chains, num rf chains can max be 1 */ + vdev_ini_cfg->num_tx_chains_11b = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->num_tx_chains_11b, + nss_chain_shift), rf_chains_supported); + + vdev_ini_cfg->num_tx_chains_11g = + QDF_MIN(GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->num_tx_chains_11g, + nss_chain_shift), rf_chains_supported); + + vdev_ini_cfg->disable_rx_mrc[band] = + nss_chains_ini_cfg->disable_rx_mrc[band]; + + vdev_ini_cfg->disable_tx_mrc[band] = + nss_chains_ini_cfg->disable_tx_mrc[band]; + /* + * Check whether the rx/tx nss is greater than the number of rf chains + * supported by FW, if so downgrade the nss to the number of chains + * supported, as higher nss cannot be supported with less chains. + */ + sme_check_nss_chain_ini_param(vdev_ini_cfg, rf_chains_supported, + band); + +} + +void sme_populate_nss_chain_params(mac_handle_t mac_handle, + struct wlan_mlme_nss_chains *vdev_ini_cfg, + enum QDF_OPMODE device_mode, + uint8_t rf_chains_supported) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + enum nss_chains_band_info band; + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) + sme_fill_nss_chain_params(mac_ctx, vdev_ini_cfg, + device_mode, band, + rf_chains_supported); +} + +void +sme_store_nss_chains_cfg_in_vdev(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_nss_chains *vdev_ini_cfg) +{ + struct wlan_mlme_nss_chains *ini_cfg; + struct wlan_mlme_nss_chains *dynamic_cfg; + + if (!vdev) { + sme_err("Invalid vdev"); + return; + } + + ini_cfg = mlme_get_ini_vdev_config(vdev); + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + + if (!ini_cfg || !dynamic_cfg) { + sme_err("Nss chains ini/dynamic config NULL vdev_id %d", + vdev->vdev_objmgr.vdev_id); + return; + } + + *ini_cfg = *vdev_ini_cfg; + *dynamic_cfg = *vdev_ini_cfg; +} + +static void +sme_populate_user_config(struct wlan_mlme_nss_chains *dynamic_cfg, + struct wlan_mlme_nss_chains *user_cfg, + struct wlan_mlme_nss_chains *ini_cfg, + enum nss_chains_band_info band) +{ + if (!user_cfg->num_rx_chains[band]) + user_cfg->num_rx_chains[band] = + dynamic_cfg->num_rx_chains[band]; + + if (!user_cfg->num_tx_chains[band]) + user_cfg->num_tx_chains[band] = + dynamic_cfg->num_tx_chains[band]; + + if (!user_cfg->rx_nss[band]) + user_cfg->rx_nss[band] = + dynamic_cfg->rx_nss[band]; + + if (!user_cfg->tx_nss[band]) + user_cfg->tx_nss[band] = + dynamic_cfg->tx_nss[band]; + + if (!user_cfg->num_tx_chains_11a) { + user_cfg->num_tx_chains_11a = + QDF_MIN(user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ], + ini_cfg->num_tx_chains_11a); + } + + if (!user_cfg->num_tx_chains_11b) { + user_cfg->num_tx_chains_11b = + QDF_MIN(user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ], + ini_cfg->num_tx_chains_11b); + } + + if (!user_cfg->num_tx_chains_11g) { + user_cfg->num_tx_chains_11g = + QDF_MIN(user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ], + ini_cfg->num_tx_chains_11g); + } + + if (!user_cfg->disable_rx_mrc[band]) + user_cfg->disable_rx_mrc[band] = + dynamic_cfg->disable_rx_mrc[band]; + + if (!user_cfg->disable_tx_mrc[band]) + user_cfg->disable_tx_mrc[band] = + dynamic_cfg->disable_tx_mrc[band]; +} + +static QDF_STATUS +sme_validate_from_ini_config(struct wlan_mlme_nss_chains *user_cfg, + struct wlan_mlme_nss_chains *ini_cfg, + enum nss_chains_band_info band) +{ + if (user_cfg->num_rx_chains[band] > + ini_cfg->num_rx_chains[band]) + return QDF_STATUS_E_FAILURE; + + if (user_cfg->num_tx_chains[band] > + ini_cfg->num_tx_chains[band]) + return QDF_STATUS_E_FAILURE; + + if (user_cfg->rx_nss[band] > + ini_cfg->rx_nss[band]) + return QDF_STATUS_E_FAILURE; + + if (user_cfg->tx_nss[band] > + ini_cfg->tx_nss[band]) + return QDF_STATUS_E_FAILURE; + + if (user_cfg->num_tx_chains_11a > + ini_cfg->num_tx_chains_11a) + return QDF_STATUS_E_FAILURE; + + if (user_cfg->num_tx_chains_11b > + ini_cfg->num_tx_chains_11b) + return QDF_STATUS_E_FAILURE; + + if (user_cfg->num_tx_chains_11g > + ini_cfg->num_tx_chains_11g) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +sme_validate_user_nss_chain_params( + struct wlan_mlme_nss_chains *user_cfg, + enum nss_chains_band_info band) +{ + /* Reject as 2x1 modes are not supported in chains yet */ + + if (user_cfg->num_tx_chains[band] > + user_cfg->num_rx_chains[band]) + return QDF_STATUS_E_FAILURE; + + /* Also if mode is 2x2, we cant have chains as 1x1, or 1x2, or 2x1 */ + + if (user_cfg->tx_nss[band] > + user_cfg->num_tx_chains[band]) + user_cfg->num_tx_chains[band] = + user_cfg->tx_nss[band]; + + if (user_cfg->rx_nss[band] > + user_cfg->num_rx_chains[band]) + user_cfg->num_rx_chains[band] = + user_cfg->rx_nss[band]; + + /* + * It may happen that already chains are in 1x1 mode and nss too + * is in 1x1 mode, but the tx 11a/b/g chains in user config comes + * as 2x1, or 1x2 which cannot support respective mode, as tx chains + * for respective band have max of 1x1 only, so these cannot exceed + * respective band num tx chains. + */ + + if (user_cfg->num_tx_chains_11a > + user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]) + user_cfg->num_tx_chains_11a = + user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]; + + if (user_cfg->num_tx_chains_11b > + user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]) + user_cfg->num_tx_chains_11b = + user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]; + + if (user_cfg->num_tx_chains_11g > + user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]) + user_cfg->num_tx_chains_11g = + user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]; + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +sme_validate_nss_chains_config(struct wlan_objmgr_vdev *vdev, + struct wlan_mlme_nss_chains *user_cfg, + struct wlan_mlme_nss_chains *dynamic_cfg) +{ + enum nss_chains_band_info band; + struct wlan_mlme_nss_chains *ini_cfg; + QDF_STATUS status; + + ini_cfg = mlme_get_ini_vdev_config(vdev); + if (!ini_cfg) { + sme_err("nss chain ini config NULL"); + return QDF_STATUS_E_FAILURE; + } + + for (band = NSS_CHAINS_BAND_2GHZ; band < NSS_CHAINS_BAND_MAX; band++) { + sme_populate_user_config(dynamic_cfg, + user_cfg, ini_cfg, band); + status = sme_validate_from_ini_config(user_cfg, + ini_cfg, + band); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Validation from ini config failed"); + return QDF_STATUS_E_FAILURE; + } + status = sme_validate_user_nss_chain_params(user_cfg, + band); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("User cfg validation failed"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +static bool +sme_is_nss_update_allowed(struct wlan_mlme_chain_cfg chain_cfg, + uint8_t rx_nss, uint8_t tx_nss, + enum nss_chains_band_info band) +{ + switch (band) { + case NSS_CHAINS_BAND_2GHZ: + if (rx_nss > chain_cfg.max_rx_chains_2g) + return false; + if (tx_nss > chain_cfg.max_tx_chains_2g) + return false; + break; + case NSS_CHAINS_BAND_5GHZ: + if (rx_nss > chain_cfg.max_rx_chains_5g) + return false; + if (tx_nss > chain_cfg.max_tx_chains_5g) + return false; + break; + default: + sme_err("Unknown Band nss change not allowed"); + return false; + } + return true; +} + +static void sme_modify_chains_in_mlme_cfg(mac_handle_t mac_handle, + uint8_t rx_chains, + uint8_t tx_chains, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band) +{ + uint8_t nss_shift; + uint32_t nss_mask = 0x7; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + nss_shift = sme_get_nss_chain_shift(vdev_op_mode); + + mac_ctx->mlme_cfg->nss_chains_ini_cfg.num_rx_chains[band] &= + ~(nss_mask << nss_shift); + mac_ctx->mlme_cfg->nss_chains_ini_cfg.num_rx_chains[band] |= + (rx_chains << nss_shift); + mac_ctx->mlme_cfg->nss_chains_ini_cfg.num_tx_chains[band] &= + ~(nss_mask << nss_shift); + mac_ctx->mlme_cfg->nss_chains_ini_cfg.num_tx_chains[band] |= + (tx_chains << nss_shift); + sme_debug("rx chains %d tx chains %d changed for vdev mode %d for band %d", + rx_chains, tx_chains, vdev_op_mode, band); +} + +static void +sme_modify_nss_in_mlme_cfg(mac_handle_t mac_handle, + uint8_t rx_nss, uint8_t tx_nss, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band) +{ + uint8_t nss_shift; + uint32_t nss_mask = 0x7; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (!sme_is_nss_update_allowed(mac_ctx->fw_chain_cfg, rx_nss, tx_nss, + band)) { + sme_debug("Nss modification failed, fw doesn't support this nss %d", + rx_nss); + return; + } + + nss_shift = sme_get_nss_chain_shift(vdev_op_mode); + + mac_ctx->mlme_cfg->nss_chains_ini_cfg.rx_nss[band] &= + ~(nss_mask << nss_shift); + mac_ctx->mlme_cfg->nss_chains_ini_cfg.rx_nss[band] |= + (rx_nss << nss_shift); + mac_ctx->mlme_cfg->nss_chains_ini_cfg.tx_nss[band] &= + ~(nss_mask << nss_shift); + mac_ctx->mlme_cfg->nss_chains_ini_cfg.tx_nss[band] |= + (tx_nss << nss_shift); + sme_debug("rx nss %d tx nss %d changed for vdev mode %d for band %d", + rx_nss, tx_nss, vdev_op_mode, band); +} + +void +sme_modify_nss_chains_tgt_cfg(mac_handle_t mac_handle, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band) +{ + uint8_t ini_rx_nss; + uint8_t ini_tx_nss; + uint8_t max_supported_rx_nss = MAX_VDEV_NSS; + uint8_t max_supported_tx_nss = MAX_VDEV_NSS; + uint8_t ini_rx_chains; + uint8_t ini_tx_chains; + uint8_t max_supported_rx_chains = MAX_VDEV_CHAINS; + uint8_t max_supported_tx_chains = MAX_VDEV_CHAINS; + + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_mlme_nss_chains *nss_chains_ini_cfg = + &mac_ctx->mlme_cfg->nss_chains_ini_cfg; + uint8_t nss_shift = sme_get_nss_chain_shift(vdev_op_mode); + struct wlan_mlme_chain_cfg chain_cfg = mac_ctx->fw_chain_cfg; + + ini_rx_nss = GET_VDEV_NSS_CHAIN(nss_chains_ini_cfg->rx_nss[band], + nss_shift); + ini_tx_nss = GET_VDEV_NSS_CHAIN(nss_chains_ini_cfg->tx_nss[band], + nss_shift); + + if (band == NSS_CHAINS_BAND_2GHZ) { + max_supported_rx_nss = chain_cfg.max_rx_chains_2g; + max_supported_tx_nss = chain_cfg.max_tx_chains_2g; + } else if (band == NSS_CHAINS_BAND_5GHZ) { + max_supported_rx_nss = chain_cfg.max_rx_chains_5g; + max_supported_tx_nss = chain_cfg.max_tx_chains_5g; + } + + max_supported_rx_nss = QDF_MIN(ini_rx_nss, max_supported_rx_nss); + if (!max_supported_rx_nss) + return; + + max_supported_tx_nss = QDF_MIN(ini_tx_nss, max_supported_tx_nss); + if (!max_supported_tx_nss) + return; + + ini_rx_chains = GET_VDEV_NSS_CHAIN(nss_chains_ini_cfg-> + num_rx_chains[band], + nss_shift); + ini_tx_chains = GET_VDEV_NSS_CHAIN(nss_chains_ini_cfg-> + num_tx_chains[band], + nss_shift); + + if (band == NSS_CHAINS_BAND_2GHZ) { + max_supported_rx_chains = chain_cfg.max_rx_chains_2g; + max_supported_tx_chains = chain_cfg.max_tx_chains_2g; + } else if (band == NSS_CHAINS_BAND_5GHZ) { + max_supported_rx_chains = chain_cfg.max_rx_chains_5g; + max_supported_tx_chains = chain_cfg.max_tx_chains_5g; + } + + max_supported_rx_chains = QDF_MIN(ini_rx_chains, + max_supported_rx_chains); + if (!max_supported_rx_chains) + return; + + max_supported_tx_chains = QDF_MIN(ini_tx_chains, + max_supported_tx_chains); + if (!max_supported_tx_chains) + return; + + sme_modify_chains_in_mlme_cfg(mac_handle, max_supported_rx_chains, + max_supported_tx_chains, vdev_op_mode, + band); + sme_modify_nss_in_mlme_cfg(mac_handle, max_supported_rx_nss, + max_supported_tx_nss, vdev_op_mode, band); +} + +void +sme_update_nss_in_mlme_cfg(mac_handle_t mac_handle, + uint8_t rx_nss, uint8_t tx_nss, + enum QDF_OPMODE vdev_op_mode, + enum nss_chains_band_info band) +{ + /* + * If device mode is P2P-DEVICE, then we want P2P to come in that + * particular nss, then we should change the nss of P@P-CLI, and GO + * and we are unaware that for what will be the device mode after + * negotiation yet. + */ + + if (vdev_op_mode == QDF_P2P_DEVICE_MODE || + vdev_op_mode == QDF_P2P_CLIENT_MODE || + vdev_op_mode == QDF_P2P_GO_MODE) { + sme_modify_nss_in_mlme_cfg(mac_handle, rx_nss, tx_nss, + QDF_P2P_CLIENT_MODE, band); + sme_modify_nss_in_mlme_cfg(mac_handle, rx_nss, tx_nss, + QDF_P2P_GO_MODE, band); + sme_modify_nss_in_mlme_cfg(mac_handle, rx_nss, tx_nss, + QDF_P2P_DEVICE_MODE, band); + } else + sme_modify_nss_in_mlme_cfg(mac_handle, rx_nss, tx_nss, + vdev_op_mode, band); +} + +static void sme_dump_nss_cfg(struct wlan_mlme_nss_chains *user_cfg) +{ + sme_debug("num_tx_chains 2g %d 5g %d", + user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ], + user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]); + + sme_debug("num_rx_chains 2g %d 5g %d", + user_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ], + user_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ]); + + sme_debug("tx_nss 2g %d 5g %d", + user_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ], + user_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ]); + sme_debug("rx_nss 2g %d 5g %d", + user_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ], + user_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ]); + sme_debug("num_tx_chains_11b %d", + user_cfg->num_tx_chains_11b); + sme_debug("num_tx_chains_11g %d", + user_cfg->num_tx_chains_11g); + sme_debug("num_tx_chains_11a %d", + user_cfg->num_tx_chains_11a); +} + +QDF_STATUS +sme_nss_chains_update(mac_handle_t mac_handle, + struct wlan_mlme_nss_chains *user_cfg, + uint8_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wlan_mlme_nss_chains *dynamic_cfg; + struct wlan_objmgr_vdev *vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_SME_ID); + uint8_t ll_lt_sap_vdev_id; + + if (!vdev) { + sme_err("Got NULL vdev obj, returning"); + return QDF_STATUS_E_FAILURE; + } + + ll_lt_sap_vdev_id = + wlan_policy_mgr_get_ll_lt_sap_vdev_id(mac_ctx->psoc); + if (ll_lt_sap_vdev_id != WLAN_INVALID_VDEV_ID) { + sme_info_rl("LL_LT_SAP vdev %d present, chainmask config not allowed", + ll_lt_sap_vdev_id); + goto release_ref; + } + + if (QDF_STATUS_SUCCESS == wlan_is_tdls_session_present(vdev)) { + sme_debug("TDLS session exists"); + status = QDF_STATUS_E_FAILURE; + goto release_ref; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) + goto release_ref; + + dynamic_cfg = mlme_get_dynamic_vdev_config(vdev); + if (!dynamic_cfg) { + sme_err("nss chain dynamic config NULL"); + status = QDF_STATUS_E_FAILURE; + goto release_lock; + } + + status = sme_validate_nss_chains_config(vdev, user_cfg, + dynamic_cfg); + sme_debug("dynamic_cfg"); + sme_dump_nss_cfg(dynamic_cfg); + sme_debug("user_cfg"); + sme_dump_nss_cfg(user_cfg); + + if (QDF_IS_STATUS_ERROR(status)) + goto release_lock; + + if (!qdf_mem_cmp(dynamic_cfg, user_cfg, + sizeof(struct wlan_mlme_nss_chains))) { + sme_debug("current config same as user config"); + status = QDF_STATUS_SUCCESS; + goto release_lock; + } + sme_debug("User params verified, sending to fw vdev id %d", vdev_id); + + status = wma_vdev_nss_chain_params_send(vdev->vdev_objmgr.vdev_id, + user_cfg); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("params sent failed to fw vdev id %d", vdev_id); + goto release_lock; + } + + *dynamic_cfg = *user_cfg; + +release_lock: + sme_release_global_lock(&mac_ctx->sme); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return status; +} + +#ifdef WLAN_FEATURE_11AX +static void sme_update_bfer_he_cap(struct wma_tgt_cfg *cfg) +{ + cfg->he_cap_5g.su_beamformer = 0; +} +#else +static void sme_update_bfer_he_cap(struct wma_tgt_cfg *cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +static void sme_update_bfer_eht_cap(struct wma_tgt_cfg *cfg) +{ + cfg->eht_cap_5g.su_beamformer = 0; +} +#else +static void sme_update_bfer_eht_cap(struct wma_tgt_cfg *cfg) +{ +} +#endif + +void sme_update_bfer_caps_as_per_nss_chains(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg) +{ + uint8_t max_supported_tx_chains = MAX_VDEV_CHAINS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_mlme_nss_chains *nss_chains_ini_cfg = + &mac_ctx->mlme_cfg->nss_chains_ini_cfg; + uint8_t ini_tx_chains; + + ini_tx_chains = GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ], + SAP_NSS_CHAINS_SHIFT); + + max_supported_tx_chains = + mac_ctx->fw_chain_cfg.max_tx_chains_5g; + + max_supported_tx_chains = QDF_MIN(ini_tx_chains, + max_supported_tx_chains); + if (!max_supported_tx_chains) + return; + + if (max_supported_tx_chains == 1) { + sme_debug("ini support %d and firmware support %d", + ini_tx_chains, + mac_ctx->fw_chain_cfg.max_tx_chains_5g); + if (mac_ctx->fw_chain_cfg.max_tx_chains_5g == 1) { + cfg->vht_cap.vht_su_bformer = 0; + sme_update_bfer_he_cap(cfg); + sme_update_bfer_eht_cap(cfg); + } + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.su_bformer = 0; + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.num_soundingdim = 0; + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.mu_bformer = 0; + } +} + +QDF_STATUS sme_vdev_post_vdev_create_setup(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *vdev_mlme; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t vdev_id; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + sme_err("Failed to get vdev mlme obj!"); + QDF_BUG(0); + return status; + } + + vdev_id = wlan_vdev_get_id(vdev); + status = wma_post_vdev_create_setup(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to setup wma for vdev: %d", vdev_id); + return status; + } + + status = csr_setup_vdev_session(vdev_mlme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to setup CSR layer for vdev: %d", vdev_id); + goto cleanup_wma; + } + + wlan_vdev_set_dot11mode(mac_ctx->mlme_cfg, vdev->vdev_mlme.vdev_opmode, + vdev_mlme); + + status = mlme_vdev_self_peer_create(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to create vdev selfpeer for vdev:%d", vdev_id); + goto csr_cleanup_vdev_session; + } + + return status; + +csr_cleanup_vdev_session: + csr_cleanup_vdev_session(mac_ctx, vdev_id); +cleanup_wma: + wma_cleanup_vdev(vdev); + return status; +} + +QDF_STATUS sme_vdev_set_data_tx_callback(struct wlan_objmgr_vdev *vdev) +{ + return wma_vdev_set_data_tx_callback(vdev); +} + +struct wlan_objmgr_vdev +*sme_vdev_create(mac_handle_t mac_handle, + struct wlan_vdev_create_params *vdev_params) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_objmgr_vdev *vdev; + + sme_debug("addr:"QDF_MAC_ADDR_FMT" opmode:%d", + QDF_MAC_ADDR_REF(vdev_params->macaddr), + vdev_params->opmode); + + vdev = wlan_objmgr_vdev_obj_create(mac_ctx->pdev, vdev_params); + if (!vdev) { + sme_err("Failed to create vdev object"); + return NULL; + } + + if (wlan_objmgr_vdev_try_get_ref(vdev, WLAN_LEGACY_SME_ID) != + QDF_STATUS_SUCCESS) { + wlan_objmgr_vdev_obj_delete(vdev); + return NULL; + } + + cm_utf_attach(vdev); + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_OPEN_SESSION, + wlan_vdev_get_id(vdev), 0)); + + return vdev; +} + +void sme_vdev_del_resp(uint8_t vdev_id) +{ + mac_handle_t mac_handle; + struct mac_context *mac; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) { + QDF_ASSERT(0); + return; + } + + mac = MAC_CONTEXT(mac_handle); + csr_cleanup_vdev_session(mac, vdev_id); + + if (mac->session_close_cb) + mac->session_close_cb(vdev_id); +} + +QDF_STATUS sme_vdev_self_peer_delete_resp(struct del_vdev_params *del_vdev_req) +{ + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + + vdev = del_vdev_req->vdev; + if (!vdev) { + qdf_mem_free(del_vdev_req); + return QDF_STATUS_E_INVAL; + } + + if (vdev->obj_state == WLAN_OBJ_STATE_LOGICALLY_DELETED) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + wma_debug("vdev delete"); + } else { + wlan_vdev_mlme_notify_set_mac_addr_response(vdev, + del_vdev_req->status); + wma_debug("mac update"); + } + + status = del_vdev_req->status; + qdf_mem_free(del_vdev_req); + return status; +} + +QDF_STATUS sme_vdev_delete(mac_handle_t mac_handle, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + uint8_t *self_peer_macaddr, vdev_id = wlan_vdev_get_id(vdev); + struct scheduler_msg self_peer_delete_msg = {0}; + struct del_vdev_params *del_self_peer; + bool is_pasn_peer_delete_all_required; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CLOSE_SESSION, vdev_id, 0)); + + is_pasn_peer_delete_all_required = + wlan_wifi_pos_pasn_peer_delete_all(mac->psoc, vdev_id); + if (is_pasn_peer_delete_all_required) { + sme_info("Resume vdev delete after pasn peers deletion"); + return QDF_STATUS_SUCCESS; + } + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_prepare_vdev_delete(mac, vdev); + sme_release_global_lock(&mac->sme); + } + + /* + * While this vdev delete is invoked we will still have following + * references held: + * WLAN_LEGACY_WMA_ID -- 1 + * WLAN_LEGACY_SME_ID -- 1 + * WLAN_OBJMGR_ID -- 2 + * Following message will release the self and delete the self peer + * and release the wma references so the objmgr and wma_legacy will be + * released because of this. + * + * In the message callback the legacy_sme reference will be released + * resulting in the last reference of vdev object and sending the + * vdev_delete to firmware. + */ + status = wlan_objmgr_vdev_obj_delete(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + sme_nofl_err("Failed to mark vdev as logical delete %d", + status); + return status; + } + + cm_utf_detach(vdev); + + del_self_peer = qdf_mem_malloc(sizeof(*del_self_peer)); + if (!del_self_peer) + return QDF_STATUS_E_NOMEM; + + self_peer_macaddr = wlan_vdev_mlme_get_mldaddr(vdev); + if (qdf_is_macaddr_zero((struct qdf_mac_addr *)self_peer_macaddr)) + self_peer_macaddr = wlan_vdev_mlme_get_macaddr(vdev); + + del_self_peer->vdev = vdev; + del_self_peer->vdev_id = wlan_vdev_get_id(vdev); + qdf_mem_copy(del_self_peer->self_mac_addr, self_peer_macaddr, + sizeof(tSirMacAddr)); + + self_peer_delete_msg.bodyptr = del_self_peer; + self_peer_delete_msg.callback = mlme_vdev_self_peer_delete; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_MLME, + QDF_MODULE_ID_TARGET_IF, + &self_peer_delete_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to post vdev selfpeer for vdev:%d", vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + qdf_mem_free(del_self_peer); + } + + return status; +} + +void sme_cleanup_session(mac_handle_t mac_handle, uint8_t vdev_id) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return; + csr_cleanup_vdev_session(mac, vdev_id); + sme_release_global_lock(&mac->sme); +} + +/* + * sme_change_mcc_beacon_interval() - + * To update P2P-GO beaconInterval. This function should be called after + * disassociating all the station is done + * This is an asynchronous API. + * + * @sessionId: Session Identifier + * Return QDF_STATUS SUCCESS + * FAILURE or RESOURCES + * The API finished and failed. + */ +QDF_STATUS sme_change_mcc_beacon_interval(uint8_t sessionId) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx = sme_get_mac_context(); + + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + return status; + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_send_chng_mcc_beacon_interval(mac_ctx, + sessionId); + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +QDF_STATUS sme_change_sap_csa_count(uint8_t count) +{ + struct mac_context *mac_ctx = sme_get_mac_context(); + + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + mac_ctx->sap.one_time_csa_count = count; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_host_offload(): API to set the host offload feature. + * @mac_handle: The handle returned by mac_open. + * @sessionId: Session Identifier + * @request: Pointer to the offload request. + * + * Return QDF_STATUS + */ +QDF_STATUS sme_set_host_offload(mac_handle_t mac_handle, uint8_t sessionId, + struct sir_host_offload_req *request) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD, sessionId, 0)); + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { +#ifdef WLAN_NS_OFFLOAD + if (SIR_IPV6_NS_OFFLOAD == request->offloadType) { + status = sme_set_ps_ns_offload(mac_handle, request, + sessionId); + } else +#endif /* WLAN_NS_OFFLOAD */ + { + status = sme_set_ps_host_offload(mac_handle, request, + sessionId); + } + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/* + * sme_set_keep_alive() - + * API to set the Keep Alive feature. + * + * mac_handle - The handle returned by mac_open. + * request - Pointer to the Keep Alive request. + * Return QDF_STATUS + */ +QDF_STATUS sme_set_keep_alive(mac_handle_t mac_handle, uint8_t session_id, + struct keep_alive_req *request) +{ + struct keep_alive_req *request_buf; + struct scheduler_msg msg = {0}; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!CSR_IS_SESSION_VALID(mac, session_id)) { + sme_err("invalid vdev %d", session_id); + return QDF_STATUS_E_INVAL; + } + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (!request_buf) + return QDF_STATUS_E_NOMEM; + + wlan_mlme_get_bssid_vdev_id(mac->pdev, session_id, + &request->bssid); + qdf_mem_copy(request_buf, request, sizeof(*request_buf)); + + sme_debug("vdev %d buff TP %d input TP %d ", session_id, + request_buf->timePeriod, request->timePeriod); + request_buf->sessionId = session_id; + + msg.type = WMA_SET_KEEP_ALIVE; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err("Not able to post WMA_SET_KEEP_ALIVE message to WMA"); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_get_operation_channel() - + * API to get current channel on which STA is parked his function gives + * channel information only of infra station + * + * mac_handle, pointer to memory location and sessionId + * Returns QDF_STATUS_SUCCESS + * QDF_STATUS_E_FAILURE + */ +QDF_STATUS sme_get_operation_channel(mac_handle_t mac_handle, + uint32_t *chan_freq, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (CSR_IS_SESSION_VALID(mac, sessionId)) { + *chan_freq = wlan_get_operation_chan_freq_vdev_id(mac->pdev, + sessionId); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_E_FAILURE; +} /* sme_get_operation_channel ends here */ + +/** + * sme_register_mgmt_frame_ind_callback() - Register a callback for + * management frame indication to PE. + * + * @mac_handle: Opaque handle to the global MAC context + * @callback: callback pointer to be registered + * + * This function is used to register a callback for management + * frame indication to PE. + * + * Return: Success if msg is posted to PE else Failure. + */ +QDF_STATUS sme_register_mgmt_frame_ind_callback(mac_handle_t mac_handle, + sir_mgmt_frame_ind_callback callback) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct sir_sme_mgmt_frame_cb_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS == + sme_acquire_global_lock(&mac_ctx->sme)) { + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + msg->message_type = eWNI_SME_REGISTER_MGMT_FRAME_CB; + msg->length = sizeof(*msg); + + msg->callback = callback; + status = umac_send_mb_message_to_mac(msg); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + return QDF_STATUS_E_FAILURE; +} + +/* + * sme_RegisterMgtFrame() - + * To register management frame of specified type and subtype. + * + * frameType - type of the frame that needs to be passed to HDD. + * matchData - data which needs to be matched before passing frame + * to HDD. + * matchDataLen - Length of matched data. + * Return QDF_STATUS + */ +QDF_STATUS sme_register_mgmt_frame(mac_handle_t mac_handle, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + struct register_mgmt_frame *pMsg; + uint16_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, + sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sme_err("Session %d not found", sessionId); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && + !pSession->sessionActive) { + sme_err("Invalid Sessionid"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*pMsg) + matchLen; + + pMsg = qdf_mem_malloc(len); + if (!pMsg) + status = QDF_STATUS_E_NOMEM; + else { + pMsg->messageType = eWNI_SME_REGISTER_MGMT_FRAME_REQ; + pMsg->length = len; + pMsg->sessionId = sessionId; + pMsg->registerFrame = true; + pMsg->frameType = frameType; + pMsg->matchLen = matchLen; + qdf_mem_copy(pMsg->matchData, matchData, matchLen); + status = umac_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_DeregisterMgtFrame() - + * To De-register management frame of specified type and subtype. + * + * frameType - type of the frame that needs to be passed to HDD. + * matchData - data which needs to be matched before passing frame + * to HDD. + * matchDataLen - Length of matched data. + * Return QDF_STATUS + */ +QDF_STATUS sme_deregister_mgmt_frame(mac_handle_t mac_handle, uint8_t sessionId, + uint16_t frameType, uint8_t *matchData, + uint16_t matchLen) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR, sessionId, + 0)); + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + struct register_mgmt_frame *pMsg; + uint16_t len; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, + sessionId); + + if (!CSR_IS_SESSION_ANY(sessionId) && !pSession) { + sme_err("Session %d not found", sessionId); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_ANY(sessionId) && + !pSession->sessionActive) { + sme_err("Invalid Sessionid"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*pMsg) + matchLen; + + pMsg = qdf_mem_malloc(len); + if (!pMsg) + status = QDF_STATUS_E_NOMEM; + else { + pMsg->messageType = eWNI_SME_REGISTER_MGMT_FRAME_REQ; + pMsg->length = len; + pMsg->registerFrame = false; + pMsg->frameType = frameType; + pMsg->matchLen = matchLen; + qdf_mem_copy(pMsg->matchData, matchData, matchLen); + status = umac_send_mb_message_to_mac(pMsg); + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +/** + * sme_prepare_mgmt_tx() - Prepares mgmt frame + * @mac_handle: The handle returned by mac_open + * @vdev_id: vdev id + * @buf: pointer to frame + * @len: frame length + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_prepare_mgmt_tx(mac_handle_t mac_handle, + uint8_t vdev_id, + const uint8_t *buf, uint32_t len) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sir_mgmt_msg *msg; + uint16_t msg_len; + struct scheduler_msg sch_msg = {0}; + + sme_debug("prepares auth frame"); + + msg_len = sizeof(*msg) + len; + msg = qdf_mem_malloc(msg_len); + if (!msg) { + status = QDF_STATUS_E_NOMEM; + } else { + msg->type = eWNI_SME_SEND_MGMT_FRAME_TX; + msg->msg_len = msg_len; + msg->vdev_id = vdev_id; + msg->data = (uint8_t *)msg + sizeof(*msg); + qdf_mem_copy(msg->data, buf, len); + + sch_msg.type = eWNI_SME_SEND_MGMT_FRAME_TX; + sch_msg.bodyptr = msg; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &sch_msg); + } + return status; +} + +QDF_STATUS sme_send_mgmt_tx(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *buf, uint32_t len) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = sme_prepare_mgmt_tx(mac_handle, session_id, buf, len); + sme_release_global_lock(&mac->sme); + } + + return status; +} + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * sme_configure_ext_wow() - configure Extr WoW + * @mac_handle - The handle returned by mac_open. + * @wlanExtParams - Depicts the wlan Ext params. + * @callback - ext_wow callback to be registered. + * @callback_context - ext_wow callback context + * + * SME will pass this request to lower mac to configure Extr WoW + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_ext_wow(mac_handle_t mac_handle, + tpSirExtWoWParams wlanExtParams, + csr_readyToExtWoWCallback callback, + void *callback_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + tpSirExtWoWParams MsgPtr = qdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return QDF_STATUS_E_NOMEM; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW, NO_SESSION, 0)); + + mac->readyToExtWoWCallback = callback; + mac->readyToExtWoWContext = callback_context; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + /* serialize the req through MC thread */ + qdf_mem_copy(MsgPtr, wlanExtParams, sizeof(*MsgPtr)); + message.bodyptr = MsgPtr; + message.type = WMA_WLAN_EXT_WOW; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->readyToExtWoWCallback = NULL; + mac->readyToExtWoWContext = NULL; + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + mac->readyToExtWoWCallback = NULL; + mac->readyToExtWoWContext = NULL; + qdf_mem_free(MsgPtr); + } + + return status; +} + +/* + * sme_configure_app_type1_params() - + * SME will pass this request to lower mac to configure Indoor WoW parameters. + * + * mac_handle - The handle returned by mac_open. + * wlanAppType1Params- Depicts the wlan App Type 1(Indoor) params + * Return QDF_STATUS + */ +QDF_STATUS sme_configure_app_type1_params(mac_handle_t mac_handle, + tpSirAppType1Params wlanAppType1Params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + tpSirAppType1Params MsgPtr = qdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return QDF_STATUS_E_NOMEM; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1, NO_SESSION, + 0)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + qdf_mem_copy(MsgPtr, wlanAppType1Params, sizeof(*MsgPtr)); + message.bodyptr = MsgPtr; + message.type = WMA_WLAN_SET_APP_TYPE1_PARAMS; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + qdf_mem_free(MsgPtr); + } + + return status; +} + +/* + * sme_configure_app_type2_params() - + * SME will pass this request to lower mac to configure Indoor WoW parameters. + * + * mac_handle - The handle returned by mac_open. + * wlanAppType2Params- Depicts the wlan App Type 2 (Outdoor) params + * Return QDF_STATUS + */ +QDF_STATUS sme_configure_app_type2_params(mac_handle_t mac_handle, + tpSirAppType2Params wlanAppType2Params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + tpSirAppType2Params MsgPtr = qdf_mem_malloc(sizeof(*MsgPtr)); + + if (!MsgPtr) + return QDF_STATUS_E_NOMEM; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2, NO_SESSION, + 0)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* serialize the req through MC thread */ + qdf_mem_copy(MsgPtr, wlanAppType2Params, sizeof(*MsgPtr)); + message.bodyptr = MsgPtr; + message.type = WMA_WLAN_SET_APP_TYPE2_PARAMS; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(MsgPtr); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + qdf_mem_free(MsgPtr); + } + + return status; +} +#endif + +uint32_t sme_get_beaconing_concurrent_operation_channel(mac_handle_t mac_handle, + uint8_t vdev_id_to_skip) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + uint32_t chan_freq = 0; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + chan_freq = csr_get_beaconing_concurrent_channel(mac, + vdev_id_to_skip); + sme_debug("Other Concurrent Chan_freq: %d skipped vdev_id %d", + chan_freq, vdev_id_to_skip); + sme_release_global_lock(&mac->sme); + } + + return chan_freq; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +uint16_t sme_check_concurrent_channel_overlap(mac_handle_t mac_handle, + uint16_t sap_ch_freq, + eCsrPhyMode sapPhyMode, + uint8_t cc_switch_mode, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + uint16_t intf_ch_freq = 0; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + intf_ch_freq = csr_check_concurrent_channel_overlap( + mac, sap_ch_freq, sapPhyMode, cc_switch_mode, vdev_id); + sme_release_global_lock(&mac->sme); + } + + return intf_ch_freq; +} +#endif + +/** + * sme_set_tsfcb() - Set callback for TSF capture + * @mac_handle: Handler return by mac_open + * @cb_fn: Callback function pointer + * @db_ctx: Callback data + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsfcb(mac_handle_t mac_handle, + int (*cb_fn)(void *cb_ctx, struct stsf *ptsf), void *cb_ctx) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.get_tsf_cb = cb_fn; + mac->sme.get_tsf_cxt = cb_ctx; + sme_release_global_lock(&mac->sme); + } + return status; +} + +/** + * sme_reset_tsfcb() - Reset callback for TSF capture + * @mac_handle: Handler return by mac_open + * + * This function reset the tsf capture callback to SME + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_reset_tsfcb(mac_handle_t mac_handle) +{ + struct mac_context *mac; + QDF_STATUS status; + + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return QDF_STATUS_E_INVAL; + } + mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.get_tsf_cb = NULL; + mac->sme.get_tsf_cxt = NULL; + sme_release_global_lock(&mac->sme); + } + return status; +} + +#if defined(WLAN_FEATURE_TSF) && !defined(WLAN_FEATURE_TSF_PLUS_NOIRQ) +/* + * sme_set_tsf_gpio() - set gpio pin that be toggled when capture tsf + * @mac_handle: Handler return by mac_open + * @pinvalue: gpio pin id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_tsf_gpio(mac_handle_t mac_handle, uint32_t pinvalue) +{ + QDF_STATUS status; + struct scheduler_msg tsf_msg = {0}; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + tsf_msg.type = WMA_TSF_GPIO_PIN; + tsf_msg.reserved = 0; + tsf_msg.bodyval = pinvalue; + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &tsf_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Unable to post WMA_TSF_GPIO_PIN"); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return status; +} +#endif + +QDF_STATUS sme_get_cfg_valid_channels(uint32_t *valid_ch_freq, uint32_t *len) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = sme_get_mac_context(); + uint32_t *valid_ch_freq_list; + uint32_t i; + + if (!mac_ctx) { + sme_err("Invalid MAC context"); + return QDF_STATUS_E_FAILURE; + } + + valid_ch_freq_list = qdf_mem_malloc(CFG_VALID_CHANNEL_LIST_LEN * + sizeof(uint32_t)); + if (!valid_ch_freq_list) + return QDF_STATUS_E_NOMEM; + + status = csr_get_cfg_valid_channels(mac_ctx, valid_ch_freq_list, len); + + for (i = 0; i < *len; i++) + valid_ch_freq[i] = valid_ch_freq_list[i]; + + qdf_mem_free(valid_ch_freq_list); + + return status; +} + +/** + * sme_handle_generic_change_country_code() - handles country ch req + * @mac_ctx: mac global context + * @msg: request msg packet + * + * If Supplicant country code is priority than 11d is disabled. + * If 11D is enabled, we update the country code after every scan. + * Hence when Supplicant country code is priority, we don't need 11D info. + * Country code from Supplicant is set as current country code. + * + * Return: status of operation + */ +static QDF_STATUS +sme_handle_generic_change_country_code(struct mac_context *mac_ctx, + void *msg_buf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + /* get the channels based on new cc */ + status = csr_get_channel_and_power_list(mac_ctx); + + if (status != QDF_STATUS_SUCCESS) { + sme_err("fail to get Channels"); + return status; + } + + /* reset info based on new cc, and we are done */ + csr_apply_channel_power_info_wrapper(mac_ctx); + csr_update_beacon(mac_ctx); + + csr_scan_filter_results(mac_ctx); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_channel_list(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Update umac channel (enable/disable) from cds channels */ + status = csr_get_channel_and_power_list(mac_ctx); + if (status != QDF_STATUS_SUCCESS) { + sme_err("fail to get Channels"); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + + csr_apply_channel_power_info_wrapper(mac_ctx); + csr_scan_filter_results(mac_ctx); + sme_release_global_lock(&mac_ctx->sme); + /* release the sme lock before we call cm disconnect */ + sme_disconnect_connected_sessions(mac_ctx, + REASON_OPER_CHANNEL_USER_DISABLED); + } + + return status; +} + +/** + * sme_search_in_base_ch_freq_lst() - is given ch_freq in base ch freq + * @mac_ctx: mac global context + * @chan_freq: current channel freq + * + * Return: true if given ch_freq is in base ch freq + */ +static bool sme_search_in_base_ch_freq_lst( + struct mac_context *mac_ctx, uint32_t chan_freq) +{ + uint8_t i; + struct csr_channel *ch_lst_info; + + ch_lst_info = &mac_ctx->scan.base_channels; + for (i = 0; i < ch_lst_info->numChannels; i++) { + if (ch_lst_info->channel_freq_list[i] == chan_freq) + return true; + } + + return false; +} + +/** + * sme_disconnect_connected_sessions() - Disconnect STA and P2P client session + * if channel is not supported + * @mac_ctx: mac global context + * @reason: Mac Disconnect reason code as per @enum wlan_reason_code + * + * If new country code does not support the channel on which STA/P2P client + * is connected, it sends the disconnect to the AP/P2P GO + * + * Return: void + */ +static void sme_disconnect_connected_sessions(struct mac_context *mac_ctx, + enum wlan_reason_code reason) +{ + uint8_t vdev_id, found = false; + qdf_freq_t chan_freq; + enum QDF_OPMODE op_mode; + struct wlan_objmgr_vdev *vdev; + + for (vdev_id = 0; vdev_id < WLAN_MAX_VDEVS; vdev_id++) { + op_mode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + /* check only for STA and CLI */ + if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE) + continue; + + chan_freq = + wlan_get_operation_chan_freq_vdev_id(mac_ctx->pdev, + vdev_id); + if (!chan_freq) + continue; + found = false; + sme_debug("Current Operating channel : %d, vdev_id :%d", + chan_freq, vdev_id); + found = sme_search_in_base_ch_freq_lst(mac_ctx, chan_freq); + if (!found) { + sme_debug("Disconnect Session: %d", vdev_id); + /* do not call cm disconnect while holding Sme lock */ + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev_id %d", + vdev_id); + return; + } + mlo_disconnect(vdev, CM_MLME_DISCONNECT, reason, NULL); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + } + } +} + +#ifdef WLAN_FEATURE_PACKET_FILTERING +QDF_STATUS sme_8023_multicast_list(mac_handle_t mac_handle, uint8_t sessionId, + tpSirRcvFltMcAddrList pMulticastAddrs) +{ + tpSirRcvFltMcAddrList request_buf; + struct scheduler_msg msg = {0}; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *pSession = NULL; + + sme_debug("ulMulticastAddrCnt: %d, multicastAddr[0]: %pK", + pMulticastAddrs->ulMulticastAddrCnt, + pMulticastAddrs->multicastAddr[0].bytes); + + /* Find the connected Infra / P2P_client connected session */ + pSession = CSR_GET_SESSION(mac, sessionId); + if (!CSR_IS_SESSION_VALID(mac, sessionId) || + (!cm_is_vdevid_connected(mac->pdev, sessionId) && + !csr_is_ndi_started(mac, sessionId))) { + sme_err("Unable to find the vdev %d", sessionId); + return QDF_STATUS_E_FAILURE; + } + + request_buf = qdf_mem_malloc(sizeof(tSirRcvFltMcAddrList)); + if (!request_buf) + return QDF_STATUS_E_NOMEM; + + if (!cm_is_vdevid_connected(mac->pdev, sessionId) && + !csr_is_ndi_started(mac, sessionId)) { + sme_err("Request ignored, session %d is not connected or started", + sessionId); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(request_buf, pMulticastAddrs, + sizeof(tSirRcvFltMcAddrList)); + + wlan_mlme_get_mac_vdev_id(mac->pdev, sessionId, + &request_buf->self_macaddr); + wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, &request_buf->bssid); + + msg.type = WMA_8023_MULTICAST_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + sessionId, msg.type)); + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Not able to post WMA_8023_MULTICAST_LIST message to WMA"); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + +bool sme_is_channel_valid(mac_handle_t mac_handle, uint32_t chan_freq) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool valid = false; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + + valid = wlan_roam_is_channel_valid(&mac->mlme_cfg->reg, + chan_freq); + + sme_release_global_lock(&mac->sme); + } + + return valid; +} + +/* + * sme_set_max_tx_power_per_band() - + * Set the Maximum Transmit Power specific to band dynamically. + * Note: this setting will not persist over reboots. + * + * band + * power to set in dB + * Return QDF_STATUS + */ +QDF_STATUS sme_set_max_tx_power_per_band(enum band_info band, int8_t dB) +{ + struct scheduler_msg msg = {0}; + tpMaxTxPowerPerBandParams pMaxTxPowerPerBandParams = NULL; + + pMaxTxPowerPerBandParams = + qdf_mem_malloc(sizeof(tMaxTxPowerPerBandParams)); + if (!pMaxTxPowerPerBandParams) + return QDF_STATUS_E_NOMEM; + + pMaxTxPowerPerBandParams->power = dB; + pMaxTxPowerPerBandParams->bandInfo = band; + + msg.type = WMA_SET_MAX_TX_POWER_PER_BAND_REQ; + msg.reserved = 0; + msg.bodyptr = pMaxTxPowerPerBandParams; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Not able to post WMA_SET_MAX_TX_POWER_PER_BAND_REQ"); + qdf_mem_free(pMaxTxPowerPerBandParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_set_max_tx_power() - + * Set the Maximum Transmit Power dynamically. Note: this setting will + * not persist over reboots. + * + * mac_handle + * pBssid BSSID to set the power cap for + * pBssid pSelfMacAddress self MAC Address + * pBssid power to set in dB + * Return QDF_STATUS + */ +QDF_STATUS sme_set_max_tx_power(mac_handle_t mac_handle, + struct qdf_mac_addr pBssid, + struct qdf_mac_addr pSelfMacAddress, int8_t dB) +{ + struct scheduler_msg msg = {0}; + tpMaxTxPowerParams pMaxTxParams = NULL; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW, NO_SESSION, 0)); + pMaxTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (!pMaxTxParams) + return QDF_STATUS_E_NOMEM; + + qdf_copy_macaddr(&pMaxTxParams->bssId, &pBssid); + qdf_copy_macaddr(&pMaxTxParams->selfStaMacAddr, &pSelfMacAddress); + pMaxTxParams->power = dB; + + msg.type = WMA_SET_MAX_TX_POWER_REQ; + msg.reserved = 0; + msg.bodyptr = pMaxTxParams; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Not able to post WMA_SET_MAX_TX_POWER_REQ message to WMA"); + qdf_mem_free(pMaxTxParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void sme_set_listen_interval(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct pe_session *session = NULL; + uint8_t val = 0; + + session = pe_find_session_by_vdev_id(mac, vdev_id); + if (!session) { + sme_err("Session lookup fails for vdev %d", vdev_id); + return; + } + + val = session->dtimPeriod; + pe_debug("Listen interval: %d vdev id: %d", val, vdev_id); + wma_vdev_set_listen_interval(vdev_id, val); +} + +/* + * sme_set_custom_mac_addr() - + * Set the customer Mac Address. + * + * customMacAddr customer MAC Address + * Return QDF_STATUS + */ +QDF_STATUS sme_set_custom_mac_addr(tSirMacAddr customMacAddr) +{ + struct scheduler_msg msg = {0}; + tSirMacAddr *pBaseMacAddr; + + pBaseMacAddr = qdf_mem_malloc(sizeof(tSirMacAddr)); + if (!pBaseMacAddr) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(*pBaseMacAddr, customMacAddr, sizeof(tSirMacAddr)); + + msg.type = SIR_HAL_SET_BASE_MACADDR_IND; + msg.reserved = 0; + msg.bodyptr = pBaseMacAddr; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Not able to post SIR_HAL_SET_BASE_MACADDR_IND message to WMA"); + qdf_mem_free(pBaseMacAddr); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_set_tx_power() - + * Set Transmit Power dynamically. + * + * mac_handle + * sessionId Target Session ID + * BSSID + * dev_mode dev_mode such as station, P2PGO, SAP + * dBm power to set + * Return QDF_STATUS + */ +QDF_STATUS sme_set_tx_power(mac_handle_t mac_handle, uint8_t sessionId, + struct qdf_mac_addr pBSSId, + enum QDF_OPMODE dev_mode, int dBm) +{ + struct scheduler_msg msg = {0}; + tpMaxTxPowerParams pTxParams = NULL; + int8_t power = (int8_t) dBm; + + MTRACE(qdf_trace(QDF_MODULE_ID_SME, + TRACE_CODE_SME_RX_HDD_SET_TXPOW, sessionId, 0)); + + /* make sure there is no overflow */ + if ((int)power != dBm) { + sme_err("error, invalid power = %d", dBm); + return QDF_STATUS_E_FAILURE; + } + + pTxParams = qdf_mem_malloc(sizeof(tMaxTxPowerParams)); + if (!pTxParams) + return QDF_STATUS_E_NOMEM; + + qdf_copy_macaddr(&pTxParams->bssId, &pBSSId); + pTxParams->power = power; /* unit is dBm */ + pTxParams->dev_mode = dev_mode; + msg.type = WMA_SET_TX_POWER_REQ; + msg.reserved = 0; + msg.bodyptr = pTxParams; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + qdf_mem_free(pTxParams); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_set_check_assoc_disallowed(mac_handle_t mac_handle, + bool check_assoc_disallowed) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to acquire sme lock; status: %d", status); + return status; + } + wlan_cm_set_check_assoc_disallowed(mac->psoc, check_assoc_disallowed); + sme_release_global_lock(&mac->sme); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_session_param(mac_handle_t mac_handle, uint8_t session_id, + uint32_t param_type, uint32_t param_val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint16_t len; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + struct sir_update_session_param *msg; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, + session_id); + + if (!session) { + sme_err("Session: %d not found", session_id); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + + if (!session->sessionActive) + QDF_ASSERT(0); + + len = sizeof(*msg); + msg = qdf_mem_malloc(len); + if (!msg) + status = QDF_STATUS_E_NOMEM; + else { + msg->message_type = eWNI_SME_SESSION_UPDATE_PARAM; + msg->length = len; + msg->vdev_id = session_id; + msg->param_type = param_type; + msg->param_val = param_val; + status = umac_send_mb_message_to_mac(msg); + } + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +QDF_STATUS sme_update_roam_scan_n_probes(mac_handle_t mac_handle, + uint8_t vdev_id, + const uint8_t probes) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = probes; + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + SCAN_N_PROBE, + &src_config); +} + +QDF_STATUS +sme_update_roam_scan_home_away_time(mac_handle_t mac_handle, uint8_t vdev_id, + const uint16_t roam_scan_home_away_time, + const bool send_offload_cmd) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.bool_value = send_offload_cmd; + src_config.uint_value = roam_scan_home_away_time; + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + SCAN_HOME_AWAY, &src_config); +} + +/** + * sme_ext_change_freq()- function to post send ECSA + * action frame to csr. + * @mac_handle: Opaque handle to the global MAC context + * @channel freq: new channel freq to switch + * @session_id: senssion it should be sent on. + * + * This function is called to post ECSA frame to csr. + * + * Return: success if msg is sent else return failure + */ +QDF_STATUS sme_ext_change_freq(mac_handle_t mac_handle, qdf_freq_t ch_freq, + uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t channel_state; + + sme_err("Set Channel freq: %d", ch_freq); + + channel_state = wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + ch_freq, + REG_CURRENT_PWR_MODE); + + if (CHANNEL_STATE_DISABLE == channel_state) { + sme_err("Invalid channel freq: %d", ch_freq); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + + if (QDF_STATUS_SUCCESS == status) { + /* update the channel list to the firmware */ + status = csr_send_ext_change_freq(mac_ctx, + ch_freq, session_id); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +QDF_STATUS sme_get_roam_scan_n_probes(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t *roam_scan_n_probes) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(mac->psoc, vdev_id, SCAN_N_PROBE, &temp); + *roam_scan_n_probes = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_update_roam_rssi_diff(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t roam_rssi_diff) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = roam_rssi_diff; + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + ROAM_RSSI_DIFF, &src_config); +} + +QDF_STATUS sme_send_rso_connect_params(mac_handle_t mac_handle, + uint8_t vdev_id) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (vdev_id >= WLAN_MAX_VDEVS) { + sme_err("Invalid sme vdev id: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!mac->mlme_cfg->lfr.lfr_enabled) { + sme_debug("lfr enabled %d", mac->mlme_cfg->lfr.lfr_enabled); + return QDF_STATUS_E_PERM; + } + + if (wlan_is_roam_offload_enabled(mac->mlme_cfg->lfr)) { + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Updating fils config to fw"); + wlan_roam_update_cfg(mac->psoc, vdev_id, + REASON_FILS_PARAMS_CHANGED); + sme_release_global_lock(&mac->sme); + } else { + sme_err("Failed to acquire SME lock"); + } + } else { + sme_debug("LFR3 not enabled"); + return QDF_STATUS_E_INVAL; + } + + return status; +} + +#ifdef WLAN_FEATURE_FILS_SK +void sme_send_hlp_ie_info(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t if_addr) +{ + int i; + struct scheduler_msg msg; + QDF_STATUS status; + struct hlp_params *params; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session = CSR_GET_SESSION(mac, vdev_id); + struct mlme_legacy_priv *mlme_priv; + struct wlan_objmgr_vdev *vdev; + + if (!session) { + sme_err("session NULL"); + return; + } + + if (!mac->mlme_cfg->lfr.lfr_enabled) { + sme_debug("Fast roam is disabled"); + return; + } + if (!csr_is_conn_state_connected(mac, vdev_id)) { + sme_debug("vdev not connected"); + return; + } + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev_id %d", vdev_id); + qdf_mem_free(params); + return; + } + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + qdf_mem_free(params); + return; + } + if ((mlme_priv->connect_info.hlp_ie_len + + QDF_IPV4_ADDR_SIZE) > FILS_MAX_HLP_DATA_LEN) { + sme_err("HLP IE len exceeds %d", + mlme_priv->connect_info.hlp_ie_len); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + qdf_mem_free(params); + return; + } + + params->vdev_id = vdev_id; + params->hlp_ie_len = + mlme_priv->connect_info.hlp_ie_len + QDF_IPV4_ADDR_SIZE; + + for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++) + params->hlp_ie[i] = (if_addr >> (i * 8)) & 0xFF; + + qdf_mem_copy(params->hlp_ie + QDF_IPV4_ADDR_SIZE, + mlme_priv->connect_info.hlp_ie, + mlme_priv->connect_info.hlp_ie_len); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + msg.type = SIR_HAL_HLP_IE_INFO; + msg.reserved = 0; + msg.bodyptr = params; + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + sme_err("sme lock acquire fails"); + qdf_mem_free(params); + return; + } + + if (!QDF_IS_STATUS_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg))) { + sme_err("Not able to post WMA_HLP_IE_INFO message to HAL"); + sme_release_global_lock(&mac->sme); + qdf_mem_free(params); + return; + } + + sme_release_global_lock(&mac->sme); +} + +#else +inline void sme_send_hlp_ie_info(mac_handle_t mac_handle, uint8_t vdev_id, + struct csr_roam_profile *profile, uint32_t if_addr) +{} +#endif + +/* + * sme_update_wes_mode() - + * Update WES Mode + * This function is called through dynamic setConfig callback function + * to configure isWESModeEnabled + * + * mac_handle: Opaque handle to the global MAC context + * isWESModeEnabled - WES mode + * sessionId - Session Identifier + * Return QDF_STATUS_SUCCESS - SME update isWESModeEnabled config successfully. + * Other status means SME is failed to update isWESModeEnabled. + */ + +QDF_STATUS sme_update_wes_mode(mac_handle_t mac_handle, bool isWESModeEnabled, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= WLAN_MAX_VDEVS) { + sme_err("Invalid vdev %d", sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("LFR runtime successfully set WES Mode to %d - old value is %d", + isWESModeEnabled, + mac->mlme_cfg->lfr.wes_mode_enabled); + mac->mlme_cfg->lfr.wes_mode_enabled = isWESModeEnabled; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/* + * sme_update_is_fast_roam_ini_feature_enabled() - enable/disable LFR + * support at runtime + * It is used at in the REG_DYNAMIC_VARIABLE macro definition of + * isFastRoamIniFeatureEnabled. + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return QDF_STATUS_SUCCESS - SME update isFastRoamIniFeatureEnabled config + * successfully. + * Other status means SME is failed to update isFastRoamIniFeatureEnabled. + */ +QDF_STATUS sme_update_is_fast_roam_ini_feature_enabled(mac_handle_t mac_handle, + uint8_t sessionId, const bool isFastRoamIniFeatureEnabled) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (mac->mlme_cfg->lfr.lfr_enabled == + isFastRoamIniFeatureEnabled) { + sme_debug("FastRoam is already enabled or disabled, nothing to do (returning) old(%d) new(%d)", + mac->mlme_cfg->lfr.lfr_enabled, + isFastRoamIniFeatureEnabled); + return QDF_STATUS_SUCCESS; + } + + sme_debug("FastRoamEnabled is changed from %d to %d", + mac->mlme_cfg->lfr.lfr_enabled, + isFastRoamIniFeatureEnabled); + mac->mlme_cfg->lfr.lfr_enabled = isFastRoamIniFeatureEnabled; + mlme_set_supplicant_disabled_roaming(mac->psoc, sessionId, + !isFastRoamIniFeatureEnabled); + if (isFastRoamIniFeatureEnabled) + wlan_cm_roam_state_change(mac->pdev, sessionId, + WLAN_ROAM_RSO_ENABLED, + REASON_CONNECT); + else + wlan_cm_roam_state_change(mac->pdev, sessionId, + WLAN_ROAM_RSO_STOPPED, + REASON_SUPPLICANT_DISABLED_ROAMING); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +int sme_add_key_krk(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *key, const int key_len) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + + if (key_len < WMI_KRK_KEY_LEN) { + sme_warn("Invalid KRK keylength [= %d]", key_len); + return -EINVAL; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("incorrect session/vdev ID"); + return -EINVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, session_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev %d", session_id); + return QDF_STATUS_E_INVAL; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(rso_cfg->krk, key, WMI_KRK_KEY_LEN); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + return 0; +} +#endif + +#if defined(FEATURE_WLAN_ESE) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +int sme_add_key_btk(mac_handle_t mac_handle, uint8_t session_id, + const uint8_t *key, const int key_len) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + + if (key_len < WMI_BTK_KEY_LEN) { + sme_warn("Invalid BTK keylength [= %d]", key_len); + return -EINVAL; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("incorrect session/vdev ID"); + return -EINVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, session_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev %d", session_id); + return QDF_STATUS_E_INVAL; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(rso_cfg->btk, key, WMI_BTK_KEY_LEN); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + /* + * KRK and BTK are updated by upper layer back to back. Send + * updated KRK and BTK together to FW here. + */ + wlan_roam_update_cfg(mac_ctx->psoc, session_id, + REASON_ROAM_PSK_PMK_CHANGED); + + return 0; +} +#endif + +QDF_STATUS sme_stop_roaming(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t reason, + enum wlan_cm_rso_control_requestor requestor) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac, vdev_id); + if (!session) { + sme_err("ROAM: incorrect vdev ID %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return wlan_cm_disable_rso(mac->pdev, vdev_id, requestor, reason); +} + +QDF_STATUS sme_start_roaming(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t reason, + enum wlan_cm_rso_control_requestor requestor) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return wlan_cm_enable_rso(mac->pdev, vdev_id, requestor, reason); +} + +bool sme_roaming_in_progress(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac, vdev_id); + if (!session) { + sme_err("ROAM: incorrect vdev ID %d", vdev_id); + return false; + } + + return wlan_cm_roaming_in_progress(mac->pdev, vdev_id); +} + +/* + * sme_set_roam_opportunistic_scan_threshold_diff() - + * Update Opportunistic Scan threshold diff + * This function is called through dynamic setConfig callback function + * to configure nOpportunisticThresholdDiff + * + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * nOpportunisticThresholdDiff - Opportunistic Scan threshold diff + * Return QDF_STATUS_SUCCESS - SME update nOpportunisticThresholdDiff config + * successfully. + * else SME is failed to update nOpportunisticThresholdDiff. + */ +QDF_STATUS sme_set_roam_opportunistic_scan_threshold_diff( + mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nOpportunisticThresholdDiff) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = cm_neighbor_roam_update_config(mac->pdev, sessionId, + nOpportunisticThresholdDiff, + REASON_OPPORTUNISTIC_THRESH_DIFF_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->mlme_cfg->lfr.opportunistic_scan_threshold_diff = + nOpportunisticThresholdDiff; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_set_roam_rescan_rssi_diff() - Update roam rescan rssi diff + * This function is called through dynamic setConfig callback function + * to configure nRoamRescanRssiDiff + * + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * nRoamRescanRssiDiff - roam rescan rssi diff + * Return QDF_STATUS_SUCCESS - SME update nRoamRescanRssiDiff config + * successfully. + * else SME is failed to update nRoamRescanRssiDiff. + */ +QDF_STATUS sme_set_roam_rescan_rssi_diff(mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nRoamRescanRssiDiff) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = cm_neighbor_roam_update_config(mac->pdev, sessionId, + nRoamRescanRssiDiff, + REASON_ROAM_RESCAN_RSSI_DIFF_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) + mac->mlme_cfg->lfr.roam_rescan_rssi_diff = + nRoamRescanRssiDiff; + + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_set_roam_bmiss_first_bcnt() - + * Update Roam count for first beacon miss + * This function is called through dynamic setConfig callback function + * to configure nRoamBmissFirstBcnt + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * nRoamBmissFirstBcnt - Roam first bmiss count + * Return QDF_STATUS_SUCCESS - SME update nRoamBmissFirstBcnt + * successfully. + * else SME is failed to update nRoamBmissFirstBcnt + */ +QDF_STATUS sme_set_roam_bmiss_first_bcnt(mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nRoamBmissFirstBcnt) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = cm_neighbor_roam_update_config(mac->pdev, sessionId, + nRoamBmissFirstBcnt, + REASON_ROAM_BMISS_FIRST_BCNT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->mlme_cfg->lfr.roam_bmiss_first_bcnt = + nRoamBmissFirstBcnt; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_set_roam_bmiss_final_bcnt() - + * Update Roam count for final beacon miss + * This function is called through dynamic setConfig callback function + * to configure nRoamBmissFinalBcnt + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * nRoamBmissFinalBcnt - Roam final bmiss count + * Return QDF_STATUS_SUCCESS - SME update nRoamBmissFinalBcnt + * successfully. + * else SME is failed to update nRoamBmissFinalBcnt + */ +QDF_STATUS sme_set_roam_bmiss_final_bcnt(mac_handle_t mac_handle, + uint8_t sessionId, + const uint8_t nRoamBmissFinalBcnt) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = cm_neighbor_roam_update_config(mac->pdev, sessionId, + nRoamBmissFinalBcnt, + REASON_ROAM_BMISS_FINAL_BCNT_CHANGED); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->mlme_cfg->lfr.roam_bmiss_final_bcnt = + nRoamBmissFinalBcnt; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS +sme_set_neighbor_lookup_rssi_threshold(mac_handle_t mac_handle, + uint8_t vdev_id, + uint8_t neighbor_lookup_rssi_threshold) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + + if (vdev_id >= WLAN_MAX_VDEVS) { + sme_err("Invalid vdev_id: %u", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + cm_neighbor_roam_update_config(mac->pdev, vdev_id, + neighbor_lookup_rssi_threshold, + REASON_LOOKUP_THRESH_CHANGED); + sme_release_global_lock(&mac->sme); + return status; +} + +/* + * sme_set_neighbor_scan_refresh_period() - set neighbor scan results + * refresh period + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return QDF_STATUS_SUCCESS - SME update config successful. + * Other status means SME is failed to update + */ +QDF_STATUS sme_set_neighbor_scan_refresh_period(mac_handle_t mac_handle, + uint8_t sessionId, uint16_t neighborScanResultsRefreshPeriod) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = neighborScanResultsRefreshPeriod; + return wlan_cm_roam_cfg_set_value(mac->psoc, sessionId, + NEIGHBOUR_SCAN_REFRESH_PERIOD, + &src_config); +} + +/* + * sme_update_empty_scan_refresh_period + * Update empty_scan_refresh_period + * This function is called through dynamic setConfig callback function + * to configure empty_scan_refresh_period + * Usage: adb shell iwpriv wlan0 setConfig + * empty_scan_refresh_period=[0 .. 60] + * + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * empty_scan_refresh_period - scan period following empty scan results. + * Return Success or failure + */ + +QDF_STATUS sme_update_empty_scan_refresh_period(mac_handle_t mac_handle, + uint8_t sessionId, uint16_t + empty_scan_refresh_period) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = empty_scan_refresh_period; + return wlan_cm_roam_cfg_set_value(mac->psoc, sessionId, + EMPTY_SCAN_REFRESH_PERIOD, + &src_config); +} + +QDF_STATUS sme_update_full_roam_scan_period(mac_handle_t mac_handle, + uint8_t vdev_id, + uint32_t full_roam_scan_period) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = full_roam_scan_period; + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + FULL_ROAM_SCAN_PERIOD, &src_config); +} + +QDF_STATUS +sme_modify_roam_cand_sel_criteria(mac_handle_t mac_handle, + uint8_t vdev_id, + bool enable_scoring_for_roam) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.bool_value = enable_scoring_for_roam; + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + ENABLE_SCORING_FOR_ROAM, &src_config); +} + +QDF_STATUS sme_roam_control_restore_default_config(mac_handle_t mac_handle, + uint8_t vdev_id) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (vdev_id >= WLAN_MAX_VDEVS) { + sme_err("Invalid vdev_id: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + return cm_roam_control_restore_default_config(mac->pdev, vdev_id); +} + +/* + * sme_set_neighbor_scan_min_chan_time() - + * Update nNeighborScanMinChanTime + * This function is called through dynamic setConfig callback function + * to configure gNeighborScanChannelMinTime + * Usage: adb shell iwpriv wlan0 setConfig + * gNeighborScanChannelMinTime=[0 .. 60] + * + * mac_handle: Opaque handle to the global MAC context + * nNeighborScanMinChanTime - Channel minimum dwell time + * sessionId - Session Identifier + * Return Success or failure + */ +QDF_STATUS sme_set_neighbor_scan_min_chan_time(mac_handle_t mac_handle, + const uint16_t + nNeighborScanMinChanTime, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = nNeighborScanMinChanTime; + return wlan_cm_roam_cfg_set_value(mac->psoc, sessionId, + SCAN_MIN_CHAN_TIME, &src_config); +} + +/* + * sme_set_neighbor_scan_max_chan_time() - + * Update nNeighborScanMaxChanTime + * This function is called through dynamic setConfig callback function + * to configure gNeighborScanChannelMaxTime + * Usage: adb shell iwpriv wlan0 setConfig + * gNeighborScanChannelMaxTime=[0 .. 60] + * + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * nNeighborScanMinChanTime - Channel maximum dwell time + * Return Success or failure + */ +QDF_STATUS sme_set_neighbor_scan_max_chan_time(mac_handle_t mac_handle, + uint8_t sessionId, + const uint16_t + nNeighborScanMaxChanTime) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = nNeighborScanMaxChanTime; + return wlan_cm_roam_cfg_set_value(mac->psoc, sessionId, + SCAN_MAX_CHAN_TIME, &src_config); +} + +/* + * sme_get_current_roam_state() - + * get current roam state + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - current roam state + */ +uint32_t sme_get_current_roam_state(mac_handle_t mac_handle, uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->roam.curState[sessionId]; +} + +/* + * sme_get_current_roam_sub_state() - + * \brief get neighbor roam sub state + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - current roam sub state + */ +uint32_t sme_get_current_roam_sub_state(mac_handle_t mac_handle, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->roam.curSubState[sessionId]; +} + +/* + * sme_get_lim_sme_state() - + * get Lim Sme state + * + * mac_handle - The handle returned by mac_open. + * Return uint32_t - Lim Sme state + */ +uint32_t sme_get_lim_sme_state(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->lim.gLimSmeState; +} + +/* + * sme_get_lim_mlm_state() - + * get Lim Mlm state + * + * mac_handle - The handle returned by mac_open. + * Return uint32_t - Lim Mlm state + */ +uint32_t sme_get_lim_mlm_state(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->lim.gLimMlmState; +} + +/* + * sme_is_lim_session_valid() - + * is Lim session valid + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return bool - true or false + */ +bool sme_is_lim_session_valid(mac_handle_t mac_handle, uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (sessionId > mac->lim.maxBssId) + return false; + + return mac->lim.gpSession[sessionId].valid; +} + +/* + * sme_get_lim_sme_session_state() - + * get Lim Sme session state + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - Lim Sme session state + */ +uint32_t sme_get_lim_sme_session_state(mac_handle_t mac_handle, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->lim.gpSession[sessionId].limSmeState; +} + +/* + * sme_get_lim_mlm_session_state() - + * \brief get Lim Mlm session state + * + * mac_handle - The handle returned by mac_open. + * sessionId - Session Identifier + * Return uint32_t - Lim Mlm session state + */ +uint32_t sme_get_lim_mlm_session_state(mac_handle_t mac_handle, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->lim.gpSession[sessionId].limMlmState; +} + +/* + * sme_set_neighbor_scan_period() - + * Update nNeighborScanPeriod + * This function is called through dynamic setConfig callback function + * to configure nNeighborScanPeriod + * Usage: adb shell iwpriv wlan0 setConfig + * nNeighborScanPeriod=[0 .. 1000] + * + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * nNeighborScanPeriod - neighbor scan period + * Return Success or failure + */ +QDF_STATUS sme_set_neighbor_scan_period(mac_handle_t mac_handle, + uint8_t sessionId, + const uint16_t nNeighborScanPeriod) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + src_config.uint_value = nNeighborScanPeriod; + return wlan_cm_roam_cfg_set_value(mac->psoc, sessionId, + NEIGHBOR_SCAN_PERIOD, + &src_config); +} + +static bool sme_validate_freq_list(mac_handle_t mac_handle, + uint32_t *freq_list, + uint8_t num_channels) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t i = 0, j; + bool found; + struct csr_channel *ch_lst_info = &mac_ctx->scan.base_channels; + + if (!freq_list || !num_channels) { + sme_err("Freq list empty %pK or num_channels is 0", freq_list); + return false; + } + + while (i < num_channels) { + found = false; + for (j = 0; j < ch_lst_info->numChannels; j++) { + if (ch_lst_info->channel_freq_list[j] == freq_list[i]) { + found = true; + break; + } + } + + if (!found) { + sme_debug("Invalid frequency %u", freq_list[i]); + return false; + } + + i++; + } + + return true; +} + +QDF_STATUS +sme_update_roam_scan_freq_list(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t *freq_list, uint8_t num_chan, + uint32_t freq_list_type) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + if (!sme_validate_freq_list(mac_handle, freq_list, num_chan)) { + sme_err("List contains invalid channel(s)"); + return QDF_STATUS_E_INVAL; + } + + /* + * NCHO Frequency configurations: + * If ADDROAMSCANFREQUENCIES command is given, then freq_list_type is + * QCA_PREFERRED_SCAN_FREQ_LIST. + * If SETROAMSCANFREQUENCIES command is given, then freq_list_type is + * QCA_SPECIFIC_SCAN_FREQ_LIST. + * + * If new channels are configured with type as STATIC(specific freq + * list): + * - FW clears both static & dynamic list. + * - FW adds new channels to static & dynamic lists(both list contains + * only new channels) + * + * If Host configures new channels with type as DYNAMIC(preferred freq + * list): + * - FW clears the static list and adds new channels(Static list + * contains only new channels) + * - FW will not clear dynamic list. New channels will be + * appended(Dynamic list contains old+new channels) + */ + + src_config.chan_info.freq_list = freq_list; + src_config.chan_info.num_chan = num_chan; + if (freq_list_type == QCA_PREFERRED_SCAN_FREQ_LIST) + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + ROAM_PREFERRED_CHAN, + &src_config); + else + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + ROAM_SPECIFIC_CHAN, + &src_config); +} + +/** + * sme_get_roam_scan_channel_list() - To get roam scan channel list + * @mac_handle: Opaque handle to the global MAC context + * @freq_list: Output channel freq list + * @pNumChannels: Output number of channels + * @sessionId: Session Identifier + * + * To get roam scan channel list This is a synchronous call + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_roam_scan_channel_list(mac_handle_t mac_handle, + uint32_t *freq_list, uint8_t *pNumChannels, + uint8_t sessionId) +{ + int i = 0, chan_cnt = 0; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct rso_chan_info *chan_info; + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + + if (sessionId >= WLAN_MAX_VDEVS) { + sme_err("Invalid sme vdev %d", sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac->pdev, sessionId, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev %d", sessionId); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_INVAL; + } + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + sme_release_global_lock(&mac->sme); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return QDF_STATUS_E_INVAL; + } + cfg_params = &rso_cfg->cfg_param; + chan_info = &cfg_params->specific_chan_info; + if (chan_info->num_chan) { + *pNumChannels = chan_info->num_chan; + for (i = 0; i < (*pNumChannels) && + i < WNI_CFG_VALID_CHANNEL_LIST_LEN; i++) + freq_list[i] = chan_info->freq_list[i]; + + *pNumChannels = i; + } else { + chan_info = &cfg_params->pref_chan_info; + *pNumChannels = chan_info->num_chan; + if (chan_info->num_chan) { + for (chan_cnt = 0; chan_cnt < (*pNumChannels) && + chan_cnt < WNI_CFG_VALID_CHANNEL_LIST_LEN; + chan_cnt++) + freq_list[chan_cnt] = + chan_info->freq_list[chan_cnt]; + } + + if (rso_cfg->occupied_chan_lst.num_chan) { + for (i = 0; i < rso_cfg->occupied_chan_lst.num_chan && + chan_cnt < CFG_VALID_CHANNEL_LIST_LEN; i++) + freq_list[chan_cnt++] = + rso_cfg->occupied_chan_lst.freq_list[i]; + } + + *pNumChannels = chan_cnt; + if (!(chan_info->num_chan || + rso_cfg->occupied_chan_lst.num_chan)) { + sme_info("Roam Scan channel list is NOT yet initialized"); + *pNumChannels = 0; + status = QDF_STATUS_E_INVAL; + } + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_is_feature_supported_by_fw() - check if feature is supported by FW + * @feature: enum value of requested feature. + * + * Return: 1 if supported; 0 otherwise + */ +bool sme_is_feature_supported_by_fw(enum cap_bitmap feature) +{ + return IS_FEATURE_SUPPORTED_BY_FW(feature); +} + +QDF_STATUS sme_get_link_speed(mac_handle_t mac_handle, + struct link_speed_info *req, + void *context, + sme_link_speed_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac; + void *wma_handle; + + if (!mac_handle || !cb || !req) { + sme_err("Invalid parameter"); + return QDF_STATUS_E_FAILURE; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + mac = MAC_CONTEXT(mac_handle); + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Failed to acquire global lock"); + return QDF_STATUS_E_FAILURE; + } + + mac->sme.link_speed_context = context; + mac->sme.link_speed_cb = cb; + status = wma_get_link_speed(wma_handle, req); + sme_release_global_lock(&mac->sme); + return status; +} + +QDF_STATUS sme_get_isolation(mac_handle_t mac_handle, void *context, + sme_get_isolation_cb callbackfn) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + + if (!callbackfn) { + sme_err("Indication Call back is NULL"); + return QDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + mac->sme.get_isolation_cb = callbackfn; + mac->sme.get_isolation_cb_context = context; + message.bodyptr = NULL; + message.type = WMA_GET_ISOLATION; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("failed to post WMA_GET_ISOLATION"); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return status; +} + +/*convert the ini value to the ENUM used in csr and MAC for CB state*/ +ePhyChanBondState sme_get_cb_phy_state_from_cb_ini_value(uint32_t cb_ini_value) +{ + return csr_convert_cb_ini_value_to_phy_cb_state(cb_ini_value); +} + +/** + * sme_add_periodic_tx_ptrn() - Add Periodic TX Pattern + * @mac_handle: Opaque handle to the global MAC context + * @addPeriodicTxPtrnParams: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +sme_add_periodic_tx_ptrn(mac_handle_t mac_handle, + struct sSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sSirAddPeriodicTxPtrn *req_msg; + struct scheduler_msg msg = {0}; + + SME_ENTER(); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + *req_msg = *addPeriodicTxPtrnParams; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WMA_ADD_PERIODIC_TX_PTRN_IND; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_del_periodic_tx_ptrn() - Delete Periodic TX Pattern + * @mac_handle: Opaque handle to the global MAC context + * @delPeriodicTxPtrnParams: request message + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +sme_del_periodic_tx_ptrn(mac_handle_t mac_handle, + struct sSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sSirDelPeriodicTxPtrn *req_msg; + struct scheduler_msg msg = {0}; + + SME_ENTER(); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + *req_msg = *delPeriodicTxPtrnParams; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + msg.bodyptr = req_msg; + msg.type = WMA_DEL_PERIODIC_TX_PTRN_IND; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +QDF_STATUS sme_multi_client_ll_rsp_register_callback(mac_handle_t mac_handle, + void (*latency_level_event_handler_cb) + (const struct latency_level_data *event_data, + uint8_t vdev_id)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.latency_level_event_handler_cb = + latency_level_event_handler_cb; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +void sme_multi_client_ll_rsp_deregister_callback(mac_handle_t mac_handle) +{ + sme_multi_client_ll_rsp_register_callback(mac_handle, NULL); +} + +/** + * sme_fill_multi_client_info() - Fill multi client info + * @param:latency leevel param + * @client_id_bitmap: bitmap for host clients + * @force_reset: force reset bit to clear latency level for all clients + * + * Return: none + */ +static void +sme_fill_multi_client_info(struct wlm_latency_level_param *params, + uint32_t client_id_bitmap, bool force_reset) +{ + params->client_id_bitmask = client_id_bitmap; + params->force_reset = force_reset; +} +#else +static inline void +sme_fill_multi_client_info(struct wlm_latency_level_param *params, + uint32_t client_id_bitmap, bool force_reset) +{ +} +#endif + +QDF_STATUS sme_set_wlm_latency_level(mac_handle_t mac_handle, + uint16_t session_id, uint16_t latency_level, + uint32_t client_id_bitmap, + bool force_reset) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlm_latency_level_param params; + void *wma = cds_get_context(QDF_MODULE_ID_WMA); + + SME_ENTER(); + + if (!wma) + return QDF_STATUS_E_FAILURE; + + if (!mac_ctx->mlme_cfg->wlm_config.latency_enable) { + sme_err("WLM latency level setting is disabled"); + return QDF_STATUS_E_FAILURE; + } + if (!wma) { + sme_err("wma is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (session_id == WLAN_INVALID_LINK_ID) { + sme_err("Invalid vdev_id[%u]", session_id); + return QDF_STATUS_E_FAILURE; + } + + params.wlm_latency_level = latency_level; + params.wlm_latency_flags = + mac_ctx->mlme_cfg->wlm_config.latency_flags[latency_level]; + params.vdev_id = session_id; + sme_fill_multi_client_info(¶ms, client_id_bitmap, force_reset); + + status = wma_set_wlm_latency_level(wma, ¶ms); + + return status; +} + +void sme_get_command_q_status(mac_handle_t mac_handle) +{ + tSmeCmd *pTempCmd = NULL; + struct mac_context *mac; + struct wlan_serialization_command *cmd; + + if (!mac_handle) + return; + + mac = MAC_CONTEXT(mac_handle); + + sme_debug("smeCmdPendingList has %d commands", + wlan_serialization_get_pending_list_count(mac->psoc, false)); + cmd = wlan_serialization_peek_head_active_cmd_using_psoc(mac->psoc, + false); + if (cmd) + sme_debug("Active commaned is %d cmd id %d source %d", + cmd->cmd_type, cmd->cmd_id, cmd->source); + if (!cmd || cmd->source != WLAN_UMAC_COMP_MLME) + return; + + pTempCmd = cmd->umac_cmd; + if (pTempCmd) { + if (eSmeCsrCommandMask & pTempCmd->command) + /* CSR command is stuck. See what the reason code is + * for that command + */ + dump_csr_command_info(mac, pTempCmd); + } +} + +#ifdef WLAN_FEATURE_DSRC +/** + * sme_ocb_gen_timing_advert_frame() - generate TA frame and populate the buffer + * @mac_handle: Opaque handle to the global MAC context + * @self_addr: the self MAC address + * @buf: the buffer that will contain the frame + * @timestamp_offset: return for the offset of the timestamp field + * @time_value_offset: return for the time_value field in the TA IE + * + * Return: the length of the buffer on success and error code on failure. + */ +int sme_ocb_gen_timing_advert_frame(mac_handle_t mac_handle, + tSirMacAddr self_addr, uint8_t **buf, + uint32_t *timestamp_offset, + uint32_t *time_value_offset) +{ + int template_length; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + template_length = sch_gen_timing_advert_frame(mac_ctx, self_addr, buf, + timestamp_offset, + time_value_offset); + return template_length; +} +#endif + +QDF_STATUS sme_notify_modem_power_state(mac_handle_t mac_handle, uint32_t value) +{ + struct scheduler_msg msg = {0}; + tpSirModemPowerStateInd request_buf; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) + return QDF_STATUS_E_FAILURE; + + request_buf = qdf_mem_malloc(sizeof(tSirModemPowerStateInd)); + if (!request_buf) + return QDF_STATUS_E_NOMEM; + + request_buf->param = value; + + msg.type = WMA_MODEM_POWER_STATE_IND; + msg.reserved = 0; + msg.bodyptr = request_buf; + if (!QDF_IS_STATUS_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg))) { + sme_err("Not able to post WMA_MODEM_POWER_STATE_IND message to WMA"); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS sme_notify_ht2040_mode(mac_handle_t mac_handle, + struct qdf_mac_addr macAddrSTA, + uint8_t sessionId, + uint8_t channel_type) +{ + struct scheduler_msg msg = {0}; + tUpdateVHTOpMode *pHtOpMode = NULL; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) + return QDF_STATUS_E_FAILURE; + + pHtOpMode = qdf_mem_malloc(sizeof(tUpdateVHTOpMode)); + if (!pHtOpMode) + return QDF_STATUS_E_NOMEM; + + switch (channel_type) { + case eHT_CHAN_HT20: + pHtOpMode->opMode = eHT_CHANNEL_WIDTH_20MHZ; + break; + + case eHT_CHAN_HT40MINUS: + case eHT_CHAN_HT40PLUS: + pHtOpMode->opMode = eHT_CHANNEL_WIDTH_40MHZ; + break; + + default: + sme_err("Invalid OP mode %d", channel_type); + qdf_mem_free(pHtOpMode); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_copy(pHtOpMode->peer_mac, macAddrSTA.bytes, + sizeof(tSirMacAddr)); + pHtOpMode->smesessionId = sessionId; + + msg.type = WMA_UPDATE_OP_MODE; + msg.reserved = 0; + msg.bodyptr = pHtOpMode; + if (QDF_IS_STATUS_ERROR + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg))) { + sme_err("Not able to post WMA_UPDATE_OP_MODE message to WMA"); + qdf_mem_free(pHtOpMode); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("vdev %d OP mode: %d", sessionId, pHtOpMode->opMode); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_set_ht2040_mode() - + * To update HT Operation beacon IE. + * + * Return QDF_STATUS SUCCESS + * FAILURE or RESOURCES + * The API finished and failed. + */ +QDF_STATUS sme_set_ht2040_mode(mac_handle_t mac_handle, uint8_t sessionId, + uint8_t channel_type, bool obssEnabled) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + ePhyChanBondState cb_mode; + struct csr_roam_session *session = CSR_GET_SESSION(mac, sessionId); + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Session not valid for session id %d", sessionId); + return QDF_STATUS_E_INVAL; + } + session = CSR_GET_SESSION(mac, sessionId); + sme_debug("Update HT operation beacon IE, channel_type=%d cur cbmode %d", + channel_type, session->cb_mode); + + switch (channel_type) { + case eHT_CHAN_HT20: + if (session->cb_mode == PHY_SINGLE_CHANNEL_CENTERED) + return QDF_STATUS_SUCCESS; + cb_mode = PHY_SINGLE_CHANNEL_CENTERED; + break; + case eHT_CHAN_HT40MINUS: + if (session->cb_mode != PHY_SINGLE_CHANNEL_CENTERED) + return QDF_STATUS_SUCCESS; + cb_mode = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + case eHT_CHAN_HT40PLUS: + if (session->cb_mode != PHY_SINGLE_CHANNEL_CENTERED) + return QDF_STATUS_SUCCESS; + cb_mode = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + default: + sme_err("Error!!! Invalid HT20/40 mode !"); + return QDF_STATUS_E_FAILURE; + } + session->cb_mode = cb_mode; + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_set_ht2040_mode(mac, sessionId, + cb_mode, obssEnabled); + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_get_ht2040_mode(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelType *channel_type) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + if (!CSR_IS_SESSION_VALID(mac, vdev_id)) { + sme_err("Session not valid for session id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + session = CSR_GET_SESSION(mac, vdev_id); + sme_debug("Get HT operation beacon IE, channel_type=%d cur cbmode %d", + *channel_type, session->cb_mode); + + switch (session->cb_mode) { + case PHY_SINGLE_CHANNEL_CENTERED: + *channel_type = eHT_CHAN_HT20; + break; + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + *channel_type = eHT_CHAN_HT40MINUS; + break; + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + *channel_type = eHT_CHAN_HT40PLUS; + break; + default: + sme_err("Error!!! Invalid HT20/40 mode !"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#endif + +/* + * SME API to enable/disable idle mode powersave + * This should be called only if powersave offload + * is enabled + */ +QDF_STATUS sme_set_idle_powersave_config(bool value) +{ + void *wmaContext = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wmaContext) + return QDF_STATUS_E_FAILURE; + + if (QDF_STATUS_SUCCESS != wma_set_idle_ps_config(wmaContext, value)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +int16_t sme_get_ht_config(mac_handle_t mac_handle, uint8_t vdev_id, + uint16_t ht_capab) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, vdev_id); + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_ht_config ht_cap_info; + + if (!pSession) { + sme_err("pSession is NULL"); + return -EIO; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return -EIO; + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return -EIO; + } + ht_cap_info.caps = vdev_mlme->proto.ht_info.ht_caps; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + return ht_cap_info.ht_caps.adv_coding_cap; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + return ht_cap_info.ht_caps.tx_stbc; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + return ht_cap_info.ht_caps.rx_stbc; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + return ht_cap_info.ht_caps.short_gi_20_mhz; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + return ht_cap_info.ht_caps.short_gi_40_mhz; + default: + sme_err("invalid ht capability"); + return -EIO; + } +} + +/** + * sme_validate_peer_ampdu_cfg() - Function to validate peer A-MPDU configure + * @peer: peer object + * @cfg: peer A-MPDU configure value + * + * Return: true if success, otherwise false + */ +static bool sme_validate_peer_ampdu_cfg(struct wlan_objmgr_peer *peer, + uint16_t cfg) +{ + if (!cfg) { + sme_debug("peer ampdu count 0"); + return false; + } + + if (wlan_peer_get_peer_type(peer) == WLAN_PEER_SELF) { + sme_debug("self peer"); + return false; + } + + return true; +} + +int sme_set_peer_ampdu(mac_handle_t mac_handle, uint8_t vdev_id, + struct qdf_mac_addr *peer_mac, uint16_t cfg) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + struct wlan_objmgr_peer *peer_obj; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev null"); + return -EINVAL; + } + + status = wlan_vdev_is_up(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + sme_debug("vdev id %d not up", vdev_id); + goto release_vdev_ref; + } + peer_obj = wlan_objmgr_vdev_find_peer_by_mac(vdev, + peer_mac->bytes, + WLAN_LEGACY_SME_ID); + if (!peer_obj) { + sme_debug("vdev id %d peer not found "QDF_MAC_ADDR_FMT, + vdev_id, + QDF_MAC_ADDR_REF(peer_mac->bytes)); + status = QDF_STATUS_E_FAILURE; + goto release_vdev_ref; + } + + if (!sme_validate_peer_ampdu_cfg(peer_obj, cfg)) { + status = QDF_STATUS_E_INVAL; + goto release_peer_ref; + } + status = sme_set_peer_param(peer_mac->bytes, + WMI_HOST_PEER_AMPDU, + cfg, + vdev_id); +release_peer_ref: + wlan_objmgr_peer_release_ref(peer_obj, WLAN_LEGACY_SME_ID); +release_vdev_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return qdf_status_to_os_return(status); +} + +int sme_update_ht_config(mac_handle_t mac_handle, uint8_t vdev_id, + uint16_t htCapab, int value) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, vdev_id); + struct wlan_ht_config ht_cap_info; + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *vdev_mlme; + + if (!pSession) { + sme_err("pSession is NULL"); + return -EIO; + } + + if (QDF_STATUS_SUCCESS != wma_set_htconfig(vdev_id, htCapab, value)) { + sme_err("Failed to set ht capability in target"); + return -EIO; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return -EIO; + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return -EIO; + } + ht_cap_info.caps = vdev_mlme->proto.ht_info.ht_caps; + + switch (htCapab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + ht_cap_info.ht_caps.adv_coding_cap = value; + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + ht_cap_info.ht_caps.tx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + ht_cap_info.ht_caps.rx_stbc = value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + value = value ? 1 : 0; /* HT SGI can be only 1 or 0 */ + ht_cap_info.ht_caps.short_gi_20_mhz = value; + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + value = value ? 1 : 0; /* HT SGI can be only 1 or 0 */ + ht_cap_info.ht_caps.short_gi_40_mhz = value; + break; + } + vdev_mlme->proto.ht_info.ht_caps = ht_cap_info.caps; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + csr_roam_update_config(mac, vdev_id, htCapab, value); + return 0; +} + +int sme_set_addba_accept(mac_handle_t mac_handle, uint8_t session_id, int value) +{ + struct sme_addba_accept *addba_accept; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + addba_accept = qdf_mem_malloc(sizeof(*addba_accept)); + if (!addba_accept) + return -EIO; + + addba_accept->session_id = session_id; + addba_accept->addba_accept = value; + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = eWNI_SME_SET_ADDBA_ACCEPT; + msg.reserved = 0; + msg.bodyptr = addba_accept; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Not able to post addba reject"); + qdf_mem_free(addba_accept); + return -EIO; + } + return 0; +} + +int sme_set_ba_buff_size(mac_handle_t mac_handle, uint8_t session_id, + uint16_t buff_size) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + if (!buff_size) { + sme_err("invalid buff size %d", buff_size); + return -EINVAL; + } + mac_ctx->usr_cfg_ba_buff_size = buff_size; + sme_debug("addba buff size is set to %d", + mac_ctx->usr_cfg_ba_buff_size); + + return 0; +} + +#define DEFAULT_BA_BUFF_SIZE 64 +int sme_send_addba_req(mac_handle_t mac_handle, uint8_t session_id, uint8_t tid, + uint16_t buff_size) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint16_t ba_buff = 0; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct send_add_ba_req *send_ba_req; + + if (!cm_is_vdevid_connected(mac_ctx->pdev, session_id)) { + sme_err("STA not infra/connected state session_id: %d", + session_id); + return -EINVAL; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session is invalid"); + return -EINVAL; + } + send_ba_req = qdf_mem_malloc(sizeof(*send_ba_req)); + if (!send_ba_req) + return -EIO; + + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, session_id, + (struct qdf_mac_addr *)&send_ba_req->mac_addr); + ba_buff = buff_size; + if (!buff_size) { + if (mac_ctx->usr_cfg_ba_buff_size) + ba_buff = mac_ctx->usr_cfg_ba_buff_size; + else + ba_buff = DEFAULT_BA_BUFF_SIZE; + } + send_ba_req->param.vdev_id = session_id; + send_ba_req->param.tidno = tid; + send_ba_req->param.buffersize = ba_buff; + msg.type = WMA_SEND_ADDBA_REQ; + msg.bodyptr = send_ba_req; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (QDF_STATUS_SUCCESS != status) { + qdf_mem_free(send_ba_req); + return -EIO; + } + sme_debug("ADDBA_REQ sent to FW: tid %d buff_size %d", tid, ba_buff); + + return 0; +} + +int sme_set_no_ack_policy(mac_handle_t mac_handle, uint8_t session_id, + uint8_t val, uint8_t ac) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t i, set_val; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + if (ac > QCA_WLAN_AC_ALL) { + sme_err("invalid ac val %d", ac); + return -EINVAL; + } + if (val) + set_val = 1; + else + set_val = 0; + if (ac == QCA_WLAN_AC_ALL) { + for (i = 0; i < ac; i++) + mac_ctx->no_ack_policy_cfg[i] = set_val; + } else { + mac_ctx->no_ack_policy_cfg[ac] = set_val; + } + sme_debug("no ack is set to %d for ac %d", set_val, ac); + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = eWNI_SME_UPDATE_EDCA_PROFILE; + msg.reserved = 0; + msg.bodyval = session_id; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Not able to post update edca profile"); + return -EIO; + } + + return 0; +} + +int sme_set_auto_rate_he_ltf(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint32_t set_val; + uint32_t bit_mask = 0; + int status; + + if (cfg_val > QCA_WLAN_HE_LTF_4X) { + sme_err("invalid HE LTF cfg %d", cfg_val); + return -EINVAL; + } + + /*set the corresponding HE LTF cfg BIT*/ + if (cfg_val == QCA_WLAN_HE_LTF_AUTO) + bit_mask = HE_LTF_ALL; + else + bit_mask = (1 << (cfg_val - 1)); + + set_val = mac_ctx->he_sgi_ltf_cfg_bit_mask; + + SET_AUTO_RATE_HE_LTF_VAL(set_val, bit_mask); + + mac_ctx->he_sgi_ltf_cfg_bit_mask = set_val; + status = wma_cli_set_command(session_id, + wmi_vdev_param_autorate_misc_cfg, + set_val, VDEV_CMD); + if (status) { + sme_err("failed to set he_ltf_sgi"); + return status; + } + + sme_debug("HE SGI_LTF is set to 0x%08X", + mac_ctx->he_sgi_ltf_cfg_bit_mask); + + return 0; +} + +int sme_set_auto_rate_he_sgi(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint32_t set_val; + uint32_t sgi_bit_mask = 0; + int status; + + if ((cfg_val > AUTO_RATE_GI_3200NS) || + (cfg_val < AUTO_RATE_GI_400NS)) { + sme_err("invalid auto rate GI cfg %d", cfg_val); + return -EINVAL; + } + + sgi_bit_mask = (1 << cfg_val); + + set_val = mac_ctx->he_sgi_ltf_cfg_bit_mask; + SET_AUTO_RATE_SGI_VAL(set_val, sgi_bit_mask); + + mac_ctx->he_sgi_ltf_cfg_bit_mask = set_val; + status = wma_cli_set_command(session_id, + wmi_vdev_param_autorate_misc_cfg, + set_val, VDEV_CMD); + if (status) { + sme_err("failed to set he_ltf_sgi"); + return status; + } + + sme_debug("auto rate HE SGI_LTF is set to 0x%08X", + mac_ctx->he_sgi_ltf_cfg_bit_mask); + + return 0; +} + +int sme_set_auto_rate_ldpc(mac_handle_t mac_handle, uint8_t session_id, + uint8_t ldpc_disable) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint32_t set_val; + int status; + + set_val = mac_ctx->he_sgi_ltf_cfg_bit_mask; + + set_val |= (ldpc_disable << AUTO_RATE_LDPC_DIS_BIT); + + status = wma_cli_set_command(session_id, + wmi_vdev_param_autorate_misc_cfg, + set_val, VDEV_CMD); + if (status) { + sme_err("failed to set auto rate LDPC cfg"); + return status; + } + + sme_debug("auto rate misc cfg set to 0x%08X", set_val); + + return 0; +} + +#define HT20_SHORT_GI_MCS7_RATE 722 +/* + * sme_send_rate_update_ind() - + * API to Update rate + * + * mac_handle - The handle returned by mac_open + * rateUpdateParams - Pointer to rate update params + * Return QDF_STATUS + */ +QDF_STATUS sme_send_rate_update_ind(mac_handle_t mac_handle, + tSirRateUpdateInd *rateUpdateParams) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + struct scheduler_msg msg = {0}; + tSirRateUpdateInd *rate_upd = qdf_mem_malloc(sizeof(tSirRateUpdateInd)); + + if (!rate_upd) + return QDF_STATUS_E_FAILURE; + + *rate_upd = *rateUpdateParams; + + if (rate_upd->mcastDataRate24GHz == HT20_SHORT_GI_MCS7_RATE) + rate_upd->mcastDataRate24GHzTxFlag = + TX_RATE_HT20 | TX_RATE_SGI; + else if (rate_upd->reliableMcastDataRate == + HT20_SHORT_GI_MCS7_RATE) + rate_upd->reliableMcastDataRateTxFlag = + TX_RATE_HT20 | TX_RATE_SGI; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(rate_upd); + return status; + } + + msg.type = WMA_RATE_UPDATE_IND; + msg.bodyptr = rate_upd; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Not able to post WMA_RATE_UPDATE_IND to WMA!"); + qdf_mem_free(rate_upd); + status = QDF_STATUS_E_FAILURE; + } + + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_update_access_policy_vendor_ie() - update vendor ie and access policy. + * @mac_handle: Pointer to the mac context + * @vdev_id: vdev_id + * @vendor_ie: vendor ie + * @access_policy: vendor ie access policy + * + * This function updates the vendor ie and access policy to lim. + * + * Return: success or failure. + */ +QDF_STATUS sme_update_access_policy_vendor_ie(mac_handle_t mac_handle, + uint8_t vdev_id, + uint8_t *vendor_ie, + int access_policy) +{ + struct sme_update_access_policy_vendor_ie *msg; + uint16_t msg_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + msg_len = sizeof(*msg); + + msg = qdf_mem_malloc(msg_len); + if (!msg) { + return QDF_STATUS_E_NOMEM; + } + + msg->msg_type = (uint16_t)eWNI_SME_UPDATE_ACCESS_POLICY_VENDOR_IE; + msg->length = (uint16_t)msg_len; + + qdf_mem_copy(&msg->ie[0], vendor_ie, sizeof(msg->ie)); + + msg->vdev_id = vdev_id; + msg->access_policy = access_policy; + + sme_debug("vdev_id: %hu, access_policy: %d", vdev_id, access_policy); + status = umac_send_mb_message_to_mac(msg); + + return status; +} + +/** + * sme_update_sta_inactivity_timeout(): Update sta_inactivity_timeout to FW + * @mac_handle: Handle returned by mac_open + * @session_id: Session ID on which sta_inactivity_timeout needs + * to be updated to FW + * @sta_inactivity_timeout: sta inactivity timeout. + * + * If a station does not send anything in sta_inactivity_timeout seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_update_sta_inactivity_timeout(mac_handle_t mac_handle, + struct sme_sta_inactivity_timeout *sta_inactivity_timer) +{ + struct sme_sta_inactivity_timeout *inactivity_time; + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + inactivity_time = qdf_mem_malloc(sizeof(*inactivity_time)); + if (!inactivity_time) + return QDF_STATUS_E_FAILURE; + + sme_debug("sta_inactivity_timeout: %d", + sta_inactivity_timer->sta_inactivity_timeout); + inactivity_time->session_id = sta_inactivity_timer->session_id; + inactivity_time->sta_inactivity_timeout = + sta_inactivity_timer->sta_inactivity_timeout; + + wma_update_sta_inactivity_timeout(wma_handle, inactivity_time); + qdf_mem_free(inactivity_time); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_get_reg_info(mac_handle_t mac_handle, uint32_t chan_freq, + uint32_t *regInfo1, uint32_t *regInfo2) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i; + bool found = false; + + *regInfo1 = 0; + *regInfo2 = 0; + + for (i = 0; i < CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (mac->scan.defaultPowerTable[i].center_freq == chan_freq) { + SME_SET_CHANNEL_REG_POWER(*regInfo1, + mac->scan.defaultPowerTable[i].tx_power); + + SME_SET_CHANNEL_MAX_TX_POWER(*regInfo2, + mac->scan.defaultPowerTable[i].tx_power); + found = true; + break; + } + } + if (!found) + status = QDF_STATUS_E_FAILURE; + + return status; +} + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +QDF_STATUS sme_set_auto_shutdown_cb(mac_handle_t mac_handle, + void (*callback_fn)(void)) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + sme_info("Plug in Auto shutdown event callback"); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + if (callback_fn) + mac->sme.auto_shutdown_cb = callback_fn; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +/* + * sme_set_auto_shutdown_timer() - + * API to set auto shutdown timer value in FW. + * + * mac_handle - The handle returned by mac_open + * timer_val - The auto shutdown timer value to be set + * Return Configuration message posting status, SUCCESS or Fail + */ +QDF_STATUS sme_set_auto_shutdown_timer(mac_handle_t mac_handle, + uint32_t timer_val) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct auto_shutdown_cmd *auto_sh_cmd; + struct scheduler_msg message = {0}; + + auto_sh_cmd = qdf_mem_malloc(sizeof(*auto_sh_cmd)); + if (!auto_sh_cmd) + return QDF_STATUS_E_NOMEM; + + + auto_sh_cmd->timer_val = timer_val; + + /* serialize the req through MC thread */ + message.bodyptr = auto_sh_cmd; + message.type = WMA_SET_AUTO_SHUTDOWN_TIMER_REQ; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Post Auto shutdown MSG fail"); + qdf_mem_free(auto_sh_cmd); + return QDF_STATUS_E_FAILURE; + } + + return status; +} +#endif + +#ifdef FEATURE_WLAN_CH_AVOID +/* + * sme_ch_avoid_update_req() - + * API to request channel avoidance update from FW. + * + * mac_handle - The handle returned by mac_open + * update_type - The update_type parameter of this request call + * Return Configuration message posting status, SUCCESS or Fail + */ +QDF_STATUS sme_ch_avoid_update_req(mac_handle_t mac_handle) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + tSirChAvoidUpdateReq *cauReq; + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + cauReq = qdf_mem_malloc(sizeof(tSirChAvoidUpdateReq)); + if (!cauReq) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + cauReq->reserved_param = 0; + + /* serialize the req through MC thread */ + message.bodyptr = cauReq; + message.type = WMA_CH_AVOID_UPDATE_REQ; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("Post Ch Avoid Update MSG fail"); + qdf_mem_free(cauReq); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_debug("Posted Ch Avoid Update MSG"); + sme_release_global_lock(&mac->sme); + } + + return status; +} +#endif + +/** + * sme_set_miracast() - Function to set miracast value to UMAC + * @mac_handle: Handle returned by macOpen + * @filter_type: 0-Disabled, 1-Source, 2-sink + * + * This function passes down the value of miracast set by + * framework to UMAC + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +QDF_STATUS sme_set_miracast(mac_handle_t mac_handle, uint8_t filter_type) +{ + struct scheduler_msg msg = {0}; + uint32_t *val; + struct mac_context *mac_ptr = MAC_CONTEXT(mac_handle); + + if (!mac_ptr) { + sme_err("Invalid pointer"); + return QDF_STATUS_E_INVAL; + } + + val = qdf_mem_malloc(sizeof(*val)); + if (!val) + return QDF_STATUS_E_NOMEM; + + *val = filter_type; + + msg.type = SIR_HAL_SET_MIRACAST; + msg.reserved = 0; + msg.bodyptr = val; + + if (!QDF_IS_STATUS_SUCCESS( + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + sme_err("Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!"); + qdf_mem_free(val); + return QDF_STATUS_E_FAILURE; + } + + mac_ptr->sme.miracast_value = filter_type; + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_mas() - Function to set MAS value to UMAC + * @val: 1-Enable, 0-Disable + * + * This function passes down the value of MAS to the UMAC. A + * value of 1 will enable MAS and a value of 0 will disable MAS + * + * Return: Configuration message posting status, SUCCESS or Fail + * + */ +QDF_STATUS sme_set_mas(uint32_t val) +{ + struct scheduler_msg msg = {0}; + uint32_t *ptr_val; + + ptr_val = qdf_mem_malloc(sizeof(*ptr_val)); + if (!ptr_val) + return QDF_STATUS_E_NOMEM; + + *ptr_val = val; + + msg.type = SIR_HAL_SET_MAS; + msg.reserved = 0; + msg.bodyptr = ptr_val; + + if (!QDF_IS_STATUS_SUCCESS( + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + sme_err("Not able to post WDA_SET_MAS_ENABLE_DISABLE to WMA!"); + qdf_mem_free(ptr_val); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_send_channel_change_req(mac_handle_t mac_handle, + struct channel_change_req *req) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_send_channel_change_req(mac, req); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_process_channel_change_resp() - + * API to Indicate Channel change response message to SAP. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_process_channel_change_resp(struct mac_context *mac, + uint16_t msg_type, void *msg_buf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_info *roam_info; + eCsrRoamResult roamResult; + uint8_t session_id; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_NOMEM; + + roam_info->channelChangeRespEvent = + (struct sSirChanChangeResponse *)msg_buf; + + session_id = roam_info->channelChangeRespEvent->sessionId; + + if (roam_info->channelChangeRespEvent->channelChangeStatus == + QDF_STATUS_SUCCESS) { + sme_debug("sapdfs: Received success for vdev %d", session_id); + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS; + } else { + sme_debug("sapdfs: Received failure for vdev %d", session_id); + roamResult = eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE; + } + + csr_roam_call_callback(mac, session_id, roam_info, + eCSR_ROAM_SET_CHANNEL_RSP, roamResult); + + qdf_mem_free(roam_info); + + return status; +} + +/* + * sme_roam_start_beacon_req() - + * API to Indicate LIM to start Beacon Tx after SAP CAC Wait is completed. + * + * mac_handle - The handle returned by mac_open + * sessionId - session ID + * dfsCacWaitStatus - CAC WAIT status flag + * Return QDF_STATUS + */ +QDF_STATUS sme_roam_start_beacon_req(mac_handle_t mac_handle, + struct qdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_start_beacon_req(mac, bssid, + dfsCacWaitStatus); + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_csa_restart(struct mac_context *mac_ctx, uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_csa_restart(mac_ctx, session_id); + sme_release_global_lock(&mac_ctx->sme); + } + + return status; +} + +QDF_STATUS sme_roam_csa_ie_request(mac_handle_t mac_handle, + struct qdf_mac_addr bssid, + uint32_t target_chan_freq, uint8_t csaIeReqd, + struct ch_params *ch_params, + uint32_t new_cac_ms) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_send_chan_sw_ie_request(mac, bssid, + target_chan_freq, + csaIeReqd, ch_params, + new_cac_ms); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_init_thermal_info() - + * SME API to initialize the thermal mitigation parameters + * + * mac_handle + * thermalParam : thermal mitigation parameters + * Return QDF_STATUS + */ +QDF_STATUS sme_init_thermal_info(mac_handle_t mac_handle) +{ + t_thermal_mgmt *pWmaParam; + struct scheduler_msg msg = {0}; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct wlan_fwol_thermal_temp thermal_temp = {0}; + QDF_STATUS status; + + pWmaParam = qdf_mem_malloc(sizeof(t_thermal_mgmt)); + if (!pWmaParam) + return QDF_STATUS_E_NOMEM; + + status = ucfg_fwol_get_thermal_temp(mac->psoc, &thermal_temp); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + pWmaParam->thermalMgmtEnabled = thermal_temp.thermal_mitigation_enable; + pWmaParam->throttlePeriod = thermal_temp.throttle_period; + + pWmaParam->throttle_duty_cycle_tbl[0] = + thermal_temp.throttle_dutycycle_level[0]; + pWmaParam->throttle_duty_cycle_tbl[1] = + thermal_temp.throttle_dutycycle_level[1]; + pWmaParam->throttle_duty_cycle_tbl[2] = + thermal_temp.throttle_dutycycle_level[2]; + pWmaParam->throttle_duty_cycle_tbl[3] = + thermal_temp.throttle_dutycycle_level[3]; + pWmaParam->throttle_duty_cycle_tbl[4] = + thermal_temp.throttle_dutycycle_level[4]; + pWmaParam->throttle_duty_cycle_tbl[5] = + thermal_temp.throttle_dutycycle_level[5]; + + pWmaParam->thermalLevels[0].minTempThreshold = + thermal_temp.thermal_temp_min_level[0]; + pWmaParam->thermalLevels[0].maxTempThreshold = + thermal_temp.thermal_temp_max_level[0]; + pWmaParam->thermalLevels[1].minTempThreshold = + thermal_temp.thermal_temp_min_level[1]; + pWmaParam->thermalLevels[1].maxTempThreshold = + thermal_temp.thermal_temp_max_level[1]; + pWmaParam->thermalLevels[2].minTempThreshold = + thermal_temp.thermal_temp_min_level[2]; + pWmaParam->thermalLevels[2].maxTempThreshold = + thermal_temp.thermal_temp_max_level[2]; + pWmaParam->thermalLevels[3].minTempThreshold = + thermal_temp.thermal_temp_min_level[3]; + pWmaParam->thermalLevels[3].maxTempThreshold = + thermal_temp.thermal_temp_max_level[3]; + pWmaParam->thermalLevels[4].minTempThreshold = + thermal_temp.thermal_temp_min_level[4]; + pWmaParam->thermalLevels[4].maxTempThreshold = + thermal_temp.thermal_temp_max_level[4]; + pWmaParam->thermalLevels[5].minTempThreshold = + thermal_temp.thermal_temp_min_level[5]; + pWmaParam->thermalLevels[5].maxTempThreshold = + thermal_temp.thermal_temp_max_level[5]; + pWmaParam->thermal_action = thermal_temp.thermal_action; + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&mac->sme)) { + msg.type = WMA_INIT_THERMAL_INFO_CMD; + msg.bodyptr = pWmaParam; + + if (!QDF_IS_STATUS_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + sme_err("Not able to post WMA_SET_THERMAL_INFO_CMD to WMA!"); + qdf_mem_free(pWmaParam); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; + } + qdf_mem_free(pWmaParam); + return QDF_STATUS_E_FAILURE; +} + +/** + * sme_add_set_thermal_level_callback() - Plug in set thermal level callback + * @mac_handle: Handle returned by macOpen + * @callback: sme_set_thermal_level_callback + * + * Plug in set thermal level callback + * + * Return: none + */ +void sme_add_set_thermal_level_callback(mac_handle_t mac_handle, + sme_set_thermal_level_callback callback) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + mac->sme.set_thermal_level_cb = callback; +} + +/** + * sme_set_thermal_level() - SME API to set the thermal mitigation level + * @mac_handle: Opaque handle to the global MAC context + * @level: Thermal mitigation level + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_level(mac_handle_t mac_handle, uint8_t level) +{ + struct scheduler_msg msg = {0}; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + if (QDF_STATUS_SUCCESS == sme_acquire_global_lock(&mac->sme)) { + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = WMA_SET_THERMAL_LEVEL; + msg.bodyval = level; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Not able to post WMA_SET_THERMAL_LEVEL to WMA!"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; + } + return QDF_STATUS_E_FAILURE; +} + +/* + * sme_txpower_limit() - + * SME API to set txpower limits + * + * mac_handle + * psmetx : power limits for 2g/5g + * Return QDF_STATUS + */ +QDF_STATUS sme_txpower_limit(mac_handle_t mac_handle, + struct tx_power_limit *psmetx) +{ + QDF_STATUS status; + struct scheduler_msg message = {0}; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct tx_power_limit *tx_power_limit; + + tx_power_limit = qdf_mem_malloc(sizeof(*tx_power_limit)); + if (!tx_power_limit) + return QDF_STATUS_E_FAILURE; + + *tx_power_limit = *psmetx; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(tx_power_limit); + return status; + } + + message.type = WMA_TX_POWER_LIMIT; + message.bodyptr = tx_power_limit; + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("not able to post WMA_TX_POWER_LIMIT"); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(tx_power_limit); + } + + sme_release_global_lock(&mac->sme); + + return status; +} + +QDF_STATUS sme_update_connect_debug(mac_handle_t mac_handle, uint32_t set_value) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + mac->mlme_cfg->gen.debug_packet_log = set_value; + return status; +} + +/* + * sme_ap_disable_intra_bss_fwd() - + * SME will send message to WMA to set Intra BSS in txrx + * + * mac_handle - The handle returned by mac_open + * sessionId - session id ( vdev id) + * disablefwd - bool value that indicate disable intrabss fwd disable + * Return QDF_STATUS + */ +QDF_STATUS sme_ap_disable_intra_bss_fwd(mac_handle_t mac_handle, + uint8_t sessionId, + bool disablefwd) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + int status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + tpDisableIntraBssFwd pSapDisableIntraFwd = NULL; + + /* Prepare the request to send to SME. */ + pSapDisableIntraFwd = qdf_mem_malloc(sizeof(tDisableIntraBssFwd)); + if (!pSapDisableIntraFwd) + return QDF_STATUS_E_NOMEM; + + pSapDisableIntraFwd->sessionId = sessionId; + pSapDisableIntraFwd->disableintrabssfwd = disablefwd; + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(pSapDisableIntraFwd); + return QDF_STATUS_E_FAILURE; + } + /* serialize the req through MC thread */ + message.bodyptr = pSapDisableIntraFwd; + message.type = WMA_SET_SAP_INTRABSS_DIS; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (QDF_IS_STATUS_ERROR(status)) { + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(pSapDisableIntraFwd); + } + sme_release_global_lock(&mac->sme); + + return status; +} + +#ifdef WLAN_FEATURE_STATS_EXT + +void sme_stats_ext_register_callback(mac_handle_t mac_handle, + stats_ext_cb callback) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + sme_err("Invalid mac context"); + return; + } + + mac->sme.stats_ext_cb = callback; +} + +void sme_stats_ext_deregister_callback(mac_handle_t mac_handle) +{ + sme_stats_ext_register_callback(mac_handle, NULL); +} + +void sme_stats_ext2_register_callback(mac_handle_t mac_handle, + stats_ext2_cb callback) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + sme_err("Invalid mac context"); + return; + } + + mac->sme.stats_ext2_cb = callback; +} + +/* + * sme_stats_ext_request() - + * Function called when HDD receives STATS EXT vendor command from userspace + * + * sessionID - vdevID for the stats ext request + * input - Stats Ext Request structure ptr + * Return QDF_STATUS + */ +QDF_STATUS sme_stats_ext_request(uint8_t session_id, tpStatsExtRequestReq input) +{ + struct scheduler_msg msg = {0}; + tpStatsExtRequest data; + size_t data_len; + + data_len = sizeof(tStatsExtRequest) + input->request_data_len; + data = qdf_mem_malloc(data_len); + if (!data) + return QDF_STATUS_E_NOMEM; + + data->vdev_id = session_id; + data->request_data_len = input->request_data_len; + if (input->request_data_len) + qdf_mem_copy(data->request_data, + input->request_data, input->request_data_len); + + msg.type = WMA_STATS_EXT_REQUEST; + msg.reserved = 0; + msg.bodyptr = data; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Not able to post WMA_STATS_EXT_REQUEST message to WMA"); + qdf_mem_free(data); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_stats_ext_event() - eWNI_SME_STATS_EXT_EVENT processor + * @mac: Global MAC context + * @msg: "stats ext" message + + * This callback function called when SME received eWNI_SME_STATS_EXT_EVENT + * response from WMA + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_stats_ext_event(struct mac_context *mac, + struct stats_ext_event *msg) +{ + if (!msg) { + sme_err("Null msg"); + return QDF_STATUS_E_FAILURE; + } + + if (mac->sme.stats_ext_cb) + mac->sme.stats_ext_cb(mac->hdd_handle, msg); + + return QDF_STATUS_SUCCESS; +} + +#else + +static QDF_STATUS sme_stats_ext_event(struct mac_context *mac, + struct stats_ext_event *msg) +{ + return QDF_STATUS_SUCCESS; +} + +#endif + +#ifdef FEATURE_FW_STATE +QDF_STATUS sme_get_fw_state(mac_handle_t mac_handle, + fw_state_callback callback, + void *context) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + tp_wma_handle wma_handle; + + SME_ENTER(); + + mac_ctx->sme.fw_state_cb = callback; + mac_ctx->sme.fw_state_context = context; + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + status = wma_get_fw_state(wma_handle); + + SME_EXIT(); + return status; +} + +/** + * sme_fw_state_resp() - eWNI_SME_FW_STATUS_IND processor + * @mac: Global MAC context + + * This callback function called when SME received eWNI_SME_FW_STATUS_IND + * response from WMA + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_fw_state_resp(struct mac_context *mac) +{ + if (mac->sme.fw_state_cb) + mac->sme.fw_state_cb(mac->sme.fw_state_context); + mac->sme.fw_state_cb = NULL; + mac->sme.fw_state_context = NULL; + + return QDF_STATUS_SUCCESS; +} + +#else /* FEATURE_FW_STATE */ +static QDF_STATUS sme_fw_state_resp(struct mac_context *mac) +{ + return QDF_STATUS_SUCCESS; +} + +#endif /* FEATURE_FW_STATE */ + +/* + * sme_update_dfs_scan_mode() - + * Update DFS roam scan mode + * This function is called through dynamic setConfig callback function + * to configure allowDFSChannelRoam. + * mac_handle: Opaque handle to the global MAC context + * sessionId - Session Identifier + * allowDFSChannelRoam - DFS roaming scan mode 0 (disable), + * 1 (passive), 2 (active) + * Return QDF_STATUS_SUCCESS - SME update DFS roaming scan config + * successfully. + * Other status means SME failed to update DFS roaming scan config. + */ +QDF_STATUS sme_update_dfs_scan_mode(mac_handle_t mac_handle, uint8_t sessionId, + uint8_t allowDFSChannelRoam) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (sessionId >= WLAN_MAX_VDEVS) { + sme_err("Invalid vdev %d", sessionId); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("LFR runtime successfully set AllowDFSChannelRoam Mode to %d - old value is %d", + allowDFSChannelRoam, + mac->mlme_cfg->lfr.roaming_dfs_channel); + mac->mlme_cfg->lfr.roaming_dfs_channel = + allowDFSChannelRoam; + if (mac->mlme_cfg->lfr.roam_scan_offload_enabled) + wlan_roam_update_cfg(mac->psoc, sessionId, + REASON_ROAM_DFS_SCAN_MODE_CHANGED); + + sme_release_global_lock(&mac->sme); + } + + + return status; +} + +/* + * sme_get_dfs_scan_mode() - get DFS roam scan mode + * This is a synchronous call + * + * mac_handle - The handle returned by mac_open. + * Return DFS roaming scan mode 0 (disable), 1 (passive), 2 (active) + */ +uint8_t sme_get_dfs_scan_mode(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->mlme_cfg->lfr.roaming_dfs_channel; +} + +/* + * sme_modify_add_ie() - + * This function sends msg to updates the additional IE buffers in PE + * + * mac_handle - global structure + * pModifyIE - pointer to tModifyIE structure + * updateType - type of buffer + * Return Success or failure + */ +QDF_STATUS sme_modify_add_ie(mac_handle_t mac_handle, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_modify_add_ies(mac, pModifyIE, updateType); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/* + * sme_update_add_ie() - + * This function sends msg to updates the additional IE buffers in PE + * + * mac_handle - global structure + * pUpdateIE - pointer to structure tUpdateIE + * updateType - type of buffer + * Return Success or failure + */ +QDF_STATUS sme_update_add_ie(mac_handle_t mac_handle, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_roam_update_add_ies(mac, pUpdateIE, updateType); + sme_release_global_lock(&mac->sme); + } + return status; +} + +/** + * sme_update_dsc_pto_up_mapping() + * @mac_handle: Opaque handle to the global MAC context + * @dscpmapping: pointer to DSCP mapping structure + * @sessionId: SME session id + * + * This routine is called to update dscp mapping + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_update_dsc_pto_up_mapping(mac_handle_t mac_handle, + enum sme_qos_wmmuptype *dscpmapping, + uint8_t sessionId) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t i, j; + struct csr_roam_session *pCsrSession = NULL; + struct pe_session *pSession = NULL; + struct qos_map_set *pqosmapset; + + pCsrSession = CSR_GET_SESSION(mac, sessionId); + if (!pCsrSession) { + sme_err("Session lookup fails for dvev %d", sessionId); + return QDF_STATUS_E_FAILURE; + } + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Invalid session Id %u", sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession = pe_find_session_by_vdev_id(mac, sessionId); + + if (!pSession) + return QDF_STATUS_E_FAILURE; + + pqosmapset = &pSession->QosMapSet; + if (!pqosmapset->present) + return QDF_STATUS_E_FAILURE; + + for (i = 0; i < SME_QOS_WMM_UP_MAX; i++) { + for (j = pqosmapset->dscp_range[i][0]; + j <= pqosmapset->dscp_range[i][1] && j <= WLAN_MAX_DSCP; + j++) + dscpmapping[j] = i; + } + for (i = 0; i < pqosmapset->num_dscp_exceptions; i++) + if (pqosmapset->dscp_exceptions[i][0] <= WLAN_MAX_DSCP && + pqosmapset->dscp_exceptions[i][1] < SME_QOS_WMM_UP_MAX) + dscpmapping[pqosmapset->dscp_exceptions[i][0]] = + pqosmapset->dscp_exceptions[i][1]; + + return status; +} + +QDF_STATUS sme_get_valid_channels_by_band(mac_handle_t mac_handle, + uint8_t wifi_band, + uint32_t *valid_chan_list, + uint8_t *valid_chan_len) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t chan_freq_list[CFG_VALID_CHANNEL_LIST_LEN] = { 0 }; + uint8_t num_channels = 0; + uint8_t i = 0; + uint32_t valid_channels = CFG_VALID_CHANNEL_LIST_LEN; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (!valid_chan_list || !valid_chan_len) { + sme_err("Output channel list/NumChannels is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (wifi_band >= WIFI_BAND_MAX) { + sme_err("Invalid wifi Band: %d", wifi_band); + return QDF_STATUS_E_INVAL; + } + + status = sme_get_cfg_valid_channels(&chan_freq_list[0], + &valid_channels); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Fail to get valid channel list (err=%d)", status); + return status; + } + + switch (wifi_band) { + case WIFI_BAND_UNSPECIFIED: + sme_debug("Unspec Band, return all %d valid channels", + valid_channels); + num_channels = valid_channels; + for (i = 0; i < valid_channels; i++) + valid_chan_list[i] = chan_freq_list[i]; + break; + + case WIFI_BAND_BG: + sme_debug("WIFI_BAND_BG (2.4 GHz)"); + for (i = 0; i < valid_channels; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq_list[i])) + valid_chan_list[num_channels++] = + chan_freq_list[i]; + } + break; + + case WIFI_BAND_A: + sme_debug("WIFI_BAND_A (5 GHz without DFS)"); + for (i = 0; i < valid_channels; i++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq_list[i]) && + !wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + chan_freq_list[i])) + valid_chan_list[num_channels++] = + chan_freq_list[i]; + } + break; + + case WIFI_BAND_ABG: + sme_debug("WIFI_BAND_ABG (2.4 GHz + 5 GHz; no DFS)"); + for (i = 0; i < valid_channels; i++) { + if ((WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq_list[i]) || + WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq_list[i])) && + !wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + chan_freq_list[i])) + valid_chan_list[num_channels++] = + chan_freq_list[i]; + } + break; + + case WIFI_BAND_A_DFS_ONLY: + sme_debug("WIFI_BAND_A_DFS (5 GHz DFS only)"); + for (i = 0; i < valid_channels; i++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq_list[i]) && + wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + chan_freq_list[i])) + valid_chan_list[num_channels++] = + chan_freq_list[i]; + } + break; + + case WIFI_BAND_A_WITH_DFS: + sme_debug("WIFI_BAND_A_WITH_DFS (5 GHz with DFS)"); + for (i = 0; i < valid_channels; i++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq_list[i])) + valid_chan_list[num_channels++] = + chan_freq_list[i]; + } + break; + + case WIFI_BAND_ABG_WITH_DFS: + sme_debug("WIFI_BAND_ABG_WITH_DFS (2.4 GHz+5 GHz with DFS)"); + for (i = 0; i < valid_channels; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_freq_list[i]) || + WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq_list[i])) + valid_chan_list[num_channels++] = + chan_freq_list[i]; + } + break; + + default: + sme_err("Unknown wifi Band: %d", wifi_band); + return QDF_STATUS_E_INVAL; + } + *valid_chan_len = num_channels; + + return status; +} + +#ifdef FEATURE_WLAN_EXTSCAN + +QDF_STATUS +sme_ext_scan_get_capabilities(mac_handle_t mac_handle, + struct extscan_capabilities_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_capabilities_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_GET_CAPABILITIES_REQ; + qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS +sme_ext_scan_start(mac_handle_t mac_handle, + struct wifi_scan_cmd_req_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct wifi_scan_cmd_req_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_START_REQ; + qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS sme_ext_scan_stop(mac_handle_t mac_handle, + struct extscan_stop_req_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_stop_req_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_STOP_REQ; + qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS +sme_set_bss_hotlist(mac_handle_t mac_handle, + struct extscan_bssid_hotlist_set_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_bssid_hotlist_set_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ; + qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS +sme_reset_bss_hotlist(mac_handle_t mac_handle, + struct extscan_bssid_hotlist_reset_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_bssid_hotlist_reset_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type)); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS +sme_set_significant_change(mac_handle_t mac_handle, + struct extscan_set_sig_changereq_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_set_sig_changereq_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS +sme_reset_significant_change(mac_handle_t mac_handle, + struct extscan_capabilities_reset_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_capabilities_reset_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type)); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + + return status; +} + +QDF_STATUS +sme_get_cached_results(mac_handle_t mac_handle, + struct extscan_cached_result_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct extscan_cached_result_params *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + + *bodyptr = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_EXTSCAN_GET_CACHED_RESULTS_REQ; + qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + return status; +} + +QDF_STATUS sme_set_epno_list(mac_handle_t mac_handle, + struct wifi_enhanced_pno_params *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct wifi_enhanced_pno_params *req_msg; + int len; + + SME_ENTER(); + + /* per contract must make a copy of the params when messaging */ + len = sizeof(*req_msg) + + (params->num_networks * sizeof(req_msg->networks[0])); + + req_msg = qdf_mem_malloc(len); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(req_msg, params, len); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + message.bodyptr = req_msg; + message.type = WMA_SET_EPNO_LIST_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + + return status; +} + +QDF_STATUS sme_set_passpoint_list(mac_handle_t mac_handle, + struct wifi_passpoint_req_param *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct wifi_passpoint_req_param *req_msg; + int len; + + SME_ENTER(); + + len = sizeof(*req_msg) + + (params->num_networks * sizeof(params->networks[0])); + req_msg = qdf_mem_malloc(len); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(req_msg, params, len); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + message.bodyptr = req_msg; + message.type = WMA_SET_PASSPOINT_LIST_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +QDF_STATUS sme_reset_passpoint_list(mac_handle_t mac_handle, + struct wifi_passpoint_req_param *params) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct wifi_passpoint_req_param *req_msg; + + SME_ENTER(); + + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + *req_msg = *params; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + message.bodyptr = req_msg; + message.type = WMA_RESET_PASSPOINT_LIST_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", + status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + return status; +} + +QDF_STATUS sme_ext_scan_register_callback(mac_handle_t mac_handle, + ext_scan_ind_cb ext_scan_ind_cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.ext_scan_ind_cb = ext_scan_ind_cb; + sme_release_global_lock(&mac->sme); + } + return status; +} +#endif /* FEATURE_WLAN_EXTSCAN */ + +/** + * sme_send_wisa_params(): Pass WISA mode to WMA + * @mac_handle: Opaque handle to the global MAC context + * @wisa_params: pointer to WISA params struct + * @sessionId: SME session id + * + * Pass WISA params to WMA + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_wisa_params(mac_handle_t mac_handle, + struct sir_wisa_params *wisa_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct sir_wisa_params *cds_msg_wisa_params; + + cds_msg_wisa_params = qdf_mem_malloc(sizeof(struct sir_wisa_params)); + if (!cds_msg_wisa_params) + return QDF_STATUS_E_NOMEM; + + *cds_msg_wisa_params = *wisa_params; + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(cds_msg_wisa_params); + return QDF_STATUS_E_FAILURE; + } + message.bodyptr = cds_msg_wisa_params; + message.type = WMA_SET_WISA_PARAMS; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(cds_msg_wisa_params); + sme_release_global_lock(&mac->sme); + return status; +} + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +void sme_radio_tx_mem_free(void) +{ + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + sme_err("Invalid wma handle"); + return; + } + wma_unified_radio_tx_mem_free(wma_handle); +} + +/* + * sme_ll_stats_clear_req() - + * SME API to clear Link Layer Statistics + * + * mac_handle + * pclearStatsReq: Link Layer clear stats request params structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ll_stats_clear_req(mac_handle_t mac_handle, + tSirLLStatsClearReq *pclearStatsReq) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + tSirLLStatsClearReq *clear_stats_req; + + sme_debug("staId = %u statsClearReqMask = 0x%X stopReq = %u", + pclearStatsReq->staId, pclearStatsReq->statsClearReqMask, + pclearStatsReq->stopReq); + if (!sme_is_session_id_valid(mac_handle, pclearStatsReq->staId)) { + sme_err("invalid staId %d", pclearStatsReq->staId); + return QDF_STATUS_E_INVAL; + } + + clear_stats_req = qdf_mem_malloc(sizeof(*clear_stats_req)); + if (!clear_stats_req) + return QDF_STATUS_E_NOMEM; + + *clear_stats_req = *pclearStatsReq; + + /* Serialize the req through MC thread */ + message.bodyptr = clear_stats_req; + message.type = WMA_LINK_LAYER_STATS_CLEAR_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type)); + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("not able to post WMA_LL_STATS_CLEAR_REQ"); + qdf_mem_free(clear_stats_req); + } + + return qdf_status; +} + +/* + * sme_ll_stats_set_req() - + * SME API to set the Link Layer Statistics + * + * mac_handle + * psetStatsReq: Link Layer set stats request params structure + * Return QDF_STATUS + */ +QDF_STATUS sme_ll_stats_set_req(mac_handle_t mac_handle, tSirLLStatsSetReq + *psetStatsReq) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + tSirLLStatsSetReq *set_stats_req; + + sme_debug("MPDU Size = %u Aggressive Stats Collections = %u", + psetStatsReq->mpduSizeThreshold, + psetStatsReq->aggressiveStatisticsGathering); + + set_stats_req = qdf_mem_malloc(sizeof(*set_stats_req)); + if (!set_stats_req) + return QDF_STATUS_E_NOMEM; + + *set_stats_req = *psetStatsReq; + + /* Serialize the req through MC thread */ + message.bodyptr = set_stats_req; + message.type = WMA_LINK_LAYER_STATS_SET_REQ; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type)); + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("not able to post WMA_LL_STATS_SET_REQ"); + qdf_mem_free(set_stats_req); + } + + return qdf_status; +} + +QDF_STATUS sme_ll_stats_get_req(mac_handle_t mac_handle, + tSirLLStatsGetReq *get_stats_req, + void *context) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + tSirLLStatsGetReq *ll_stats_get_req; + + ll_stats_get_req = qdf_mem_malloc(sizeof(*ll_stats_get_req)); + if (!ll_stats_get_req) + return QDF_STATUS_E_NOMEM; + + *ll_stats_get_req = *get_stats_req; + + mac->sme.ll_stats_context = context; + /* Serialize the req through MC thread */ + message.bodyptr = ll_stats_get_req; + message.type = WMA_LINK_LAYER_STATS_GET_REQ; + qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Not able to post WMA_LL_STATS_GET_REQ"); + qdf_mem_free(ll_stats_get_req); + } + + return status; +} + +QDF_STATUS sme_set_link_layer_stats_ind_cb(mac_handle_t mac_handle, + link_layer_stats_cb callback) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.link_layer_stats_cb = callback; + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock error"); + } + + return status; +} + +/** + * sme_set_link_layer_ext_cb() - Register callback for link layer statistics + * @mac_handle: Mac global handle + * @ll_stats_ext_cb: HDD callback which needs to be invoked after getting + * status notification from FW + * + * Return: QDF_STATUS + */ +QDF_STATUS +sme_set_link_layer_ext_cb(mac_handle_t mac_handle, + void (*ll_stats_ext_cb)(hdd_handle_t callback_ctx, + tSirLLStatsResults *rsp)) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (status == QDF_STATUS_SUCCESS) { + mac->sme.link_layer_stats_ext_cb = ll_stats_ext_cb; + sme_release_global_lock(&mac->sme); + } else + sme_err("sme_qcquire_global_lock error"); + return status; +} + +/** + * sme_reset_link_layer_stats_ind_cb() - SME API to reset link layer stats + * indication + * @mac_handle: Opaque handle to the global MAC context + * + * This function reset's the link layer stats indication + * + * Return: QDF_STATUS Enumeration + */ + +QDF_STATUS sme_reset_link_layer_stats_ind_cb(mac_handle_t mac_handle) +{ + QDF_STATUS status; + struct mac_context *pmac; + + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return QDF_STATUS_E_INVAL; + } + pmac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&pmac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + pmac->sme.link_layer_stats_cb = NULL; + sme_release_global_lock(&pmac->sme); + } else + sme_err("sme_acquire_global_lock error"); + + return status; +} + +/** + * sme_ll_stats_set_thresh - set threshold for mac counters + * @mac_handle: Opaque handle to the global MAC context + * @threshold, threshold for mac counters + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_ll_stats_set_thresh(mac_handle_t mac_handle, + struct sir_ll_ext_stats_threshold *threshold) +{ + QDF_STATUS status; + struct scheduler_msg message = {0}; + struct sir_ll_ext_stats_threshold *thresh; + + if (!threshold) { + sme_err("threshold is not valid"); + return QDF_STATUS_E_INVAL; + } + + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return QDF_STATUS_E_INVAL; + } + + thresh = qdf_mem_malloc(sizeof(*thresh)); + if (!thresh) + return QDF_STATUS_E_NOMEM; + + *thresh = *threshold; + + /* Serialize the req through MC thread */ + message.bodyptr = thresh; + message.type = WDA_LINK_LAYER_STATS_SET_THRESHOLD; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type)); + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("not able to post WDA_LL_STATS_GET_REQ"); + qdf_mem_free(thresh); + } + + return status; +} + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef WLAN_POWER_DEBUG +void sme_reset_power_debug_stats_cb(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac_ctx->sme.power_debug_stats_context = NULL; + mac_ctx->sme.power_stats_resp_callback = NULL; + sme_release_global_lock(&mac_ctx->sme); + } +} + +QDF_STATUS sme_power_debug_stats_req( + mac_handle_t mac_handle, + void (*callback_fn)(struct power_stats_response *response, + void *context), + void *power_stats_context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (!callback_fn) { + sme_err("Indication callback did not registered"); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_FAILURE; + } + + if (mac_ctx->sme.power_debug_stats_context || + mac_ctx->sme.power_stats_resp_callback) { + sme_err("Already one power stats req in progress"); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_ALREADY; + } + mac_ctx->sme.power_debug_stats_context = power_stats_context; + mac_ctx->sme.power_stats_resp_callback = callback_fn; + msg.bodyptr = NULL; + msg.type = WMA_POWER_DEBUG_STATS_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("not able to post WDA_POWER_DEBUG_STATS_REQ"); + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} +#endif + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +QDF_STATUS sme_beacon_debug_stats_req( + mac_handle_t mac_handle, uint32_t vdev_id, + void (*callback_fn)(struct bcn_reception_stats_rsp + *response, void *context), + void *beacon_stats_context) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint32_t *val; + struct scheduler_msg msg = {0}; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (!callback_fn) { + sme_err("Indication callback did not registered"); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_FAILURE; + } + + if (!mac_ctx->bcn_reception_stats && + !mac_ctx->mlme_cfg->gen.enable_beacon_reception_stats) { + sme_err("Beacon Reception stats not supported"); + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOSUPPORT; + } + + val = qdf_mem_malloc(sizeof(*val)); + if (!val) { + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + + *val = vdev_id; + mac_ctx->sme.beacon_stats_context = beacon_stats_context; + mac_ctx->sme.beacon_stats_resp_callback = callback_fn; + msg.bodyptr = val; + msg.type = WMA_BEACON_DEBUG_STATS_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("not able to post WMA_BEACON_DEBUG_STATS_REQ"); + qdf_mem_free(val); + } + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} +#endif + +/** + * sme_get_temperature() - SME API to get the pdev temperature + * @mac_handle: Handle to global MAC context + * @cb_context: temperature callback context + * @cb: callback function with response (temperature) + * Return: QDF_STATUS + */ +QDF_STATUS sme_get_temperature(mac_handle_t mac_handle, + void *cb_context, + void (*cb)(int temperature, + void *context)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + if ((!cb) && + (!mac->sme.temperature_cb)) { + sme_err("Indication Call back did not registered"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_FAILURE; + } else if (cb) { + mac->sme.temperature_cb_context = cb_context; + mac->sme.temperature_cb = cb; + } + /* serialize the req through MC thread */ + message.bodyptr = NULL; + message.type = WMA_GET_TEMPERATURE_REQ; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Post Get Temperature msg fail"); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_set_scanning_mac_oui(mac_handle_t mac_handle, + struct scan_mac_oui *scan_mac_oui) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct scan_mac_oui *bodyptr; + + /* per contract must make a copy of the params when messaging */ + bodyptr = qdf_mem_malloc(sizeof(*bodyptr)); + if (!bodyptr) + return QDF_STATUS_E_NOMEM; + *bodyptr = *scan_mac_oui; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + message.bodyptr = bodyptr; + message.type = WMA_SET_SCAN_MAC_OUI_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + sme_release_global_lock(&mac->sme); + } + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failure: %d", status); + qdf_mem_free(bodyptr); + } + + return status; +} + +#ifdef DHCP_SERVER_OFFLOAD +QDF_STATUS +sme_set_dhcp_srv_offload(mac_handle_t mac_handle, + struct dhcp_offload_info_params *dhcp_srv_info) +{ + struct scheduler_msg message = {0}; + struct dhcp_offload_info_params *payload; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + payload = qdf_mem_malloc(sizeof(*payload)); + if (!payload) + return QDF_STATUS_E_NOMEM; + + *payload = *dhcp_srv_info; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == status) { + /* serialize the req through MC thread */ + message.type = WMA_SET_DHCP_SERVER_OFFLOAD_CMD; + message.bodyptr = payload; + + if (!QDF_IS_STATUS_SUCCESS + (scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message))) { + sme_err("WMA_SET_DHCP_SERVER_OFFLOAD_CMD failed"); + qdf_mem_free(payload); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock error!"); + qdf_mem_free(payload); + } + + return status; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +QDF_STATUS sme_send_unit_test_cmd(uint32_t vdev_id, uint32_t module_id, + uint32_t arg_count, uint32_t *arg) +{ + return wma_form_unit_test_cmd_and_send(vdev_id, module_id, + arg_count, arg); +} + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +/* + * sme_set_led_flashing() - + * API to set the Led flashing parameters. + * + * mac_handle - The handle returned by mac_open. + * x0, x1 - led flashing parameters + * Return QDF_STATUS + */ +QDF_STATUS sme_set_led_flashing(mac_handle_t mac_handle, uint8_t type, + uint32_t x0, uint32_t x1) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct flashing_req_params *ledflashing; + + ledflashing = qdf_mem_malloc(sizeof(*ledflashing)); + if (!ledflashing) + return QDF_STATUS_E_NOMEM; + + ledflashing->req_id = 0; + ledflashing->pattern_id = type; + ledflashing->led_x0 = x0; + ledflashing->led_x1 = x1; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = ledflashing; + message.type = WMA_LED_FLASHING_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + sme_release_global_lock(&mac->sme); + } + if (!QDF_IS_STATUS_SUCCESS(status)) + qdf_mem_free(ledflashing); + + return status; +} +#endif + +/** + * sme_enable_dfS_chan_scan() - set DFS channel scan enable/disable + * @mac_handle: corestack handler + * @dfs_flag: flag indicating dfs channel enable/disable + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_dfs_chan_scan(mac_handle_t mac_handle, uint8_t dfs_flag) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac; + + if (!mac_handle) { + sme_err("mac_handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + mac = MAC_CONTEXT(mac_handle); + + mac->scan.fEnableDFSChnlScan = dfs_flag; + + return status; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH +/** + * sme_validate_sap_channel_switch() - validate target channel switch w.r.t + * concurreny rules set to avoid channel interference. + * @mac_handle: Opaque handle to the global MAC context + * @sap_ch - channel to switch + * @sap_phy_mode - phy mode of SAP + * @cc_switch_mode - concurreny switch mode + * @vdev_id - vdev id. + * + * Return: true if there is no channel interference else return false + */ +bool sme_validate_sap_channel_switch(mac_handle_t mac_handle, + uint32_t sap_ch_freq, + eCsrPhyMode sap_phy_mode, + uint8_t cc_switch_mode, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session = CSR_GET_SESSION(mac, vdev_id); + uint16_t intf_channel_freq = 0; + + if (!session) + return false; + + session->ch_switch_in_progress = true; + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + intf_channel_freq = csr_check_concurrent_channel_overlap( + mac, sap_ch_freq, sap_phy_mode, cc_switch_mode, + vdev_id); + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock error!"); + session->ch_switch_in_progress = false; + return false; + } + + session->ch_switch_in_progress = false; + return (intf_channel_freq == 0) ? true : false; +} +#endif + +/** + * sme_configure_stats_avg_factor() - function to config avg. stats factor + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session ID + * @stats_avg_factor: average stats factor + * + * This function configures the stats avg factor in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_stats_avg_factor(mac_handle_t mac_handle, + uint8_t session_id, + uint16_t stats_avg_factor) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sir_stats_avg_factor *stats_factor; + + stats_factor = qdf_mem_malloc(sizeof(*stats_factor)); + if (!stats_factor) + return QDF_STATUS_E_NOMEM; + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + stats_factor->vdev_id = session_id; + stats_factor->stats_avg_factor = stats_avg_factor; + + /* serialize the req through MC thread */ + msg.type = SIR_HAL_CONFIG_STATS_FACTOR; + msg.bodyptr = stats_factor; + + if (!QDF_IS_STATUS_SUCCESS( + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg))) { + sme_err("Not able to post SIR_HAL_CONFIG_STATS_FACTOR to WMA!"); + qdf_mem_free(stats_factor); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock error!"); + qdf_mem_free(stats_factor); + } + + return status; +} + +/** + * sme_configure_guard_time() - function to configure guard time + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * @guard_time: guard time + * + * This function configures the guard time in firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_configure_guard_time(mac_handle_t mac_handle, uint8_t session_id, + uint32_t guard_time) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sir_guard_time_request *g_time; + + g_time = qdf_mem_malloc(sizeof(*g_time)); + if (!g_time) + return QDF_STATUS_E_NOMEM; + + status = sme_acquire_global_lock(&mac->sme); + + if (QDF_STATUS_SUCCESS == status) { + + g_time->vdev_id = session_id; + g_time->guard_time = guard_time; + + /* serialize the req through MC thread */ + msg.type = SIR_HAL_CONFIG_GUARD_TIME; + msg.bodyptr = g_time; + + if (!QDF_IS_STATUS_SUCCESS( + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg))) { + sme_err("Not able to post SIR_HAL_CONFIG_GUARD_TIME to WMA!"); + qdf_mem_free(g_time); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock error!"); + qdf_mem_free(g_time); + } + + return status; +} + +/* + * sme_wifi_start_logger() - Send the start/stop logging command to WMA + * to either start/stop logging + * @mac_handle: Opaque handle to the global MAC context + * @start_log: Structure containing the wifi start logger params + * + * This function sends the start/stop logging command to WMA + * + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_wifi_start_logger(mac_handle_t mac_handle, + struct sir_wifi_start_log start_log) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg message = {0}; + struct sir_wifi_start_log *req_msg; + uint32_t len; + + len = sizeof(*req_msg); + req_msg = qdf_mem_malloc(len); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + req_msg->verbose_level = start_log.verbose_level; + req_msg->is_iwpriv_command = start_log.is_iwpriv_command; + req_msg->ring_id = start_log.ring_id; + req_msg->ini_triggered = start_log.ini_triggered; + req_msg->user_triggered = start_log.user_triggered; + req_msg->size = start_log.size; + req_msg->is_pktlog_buff_clear = start_log.is_pktlog_buff_clear; + + message.bodyptr = req_msg; + message.type = SIR_HAL_START_STOP_LOGGING; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", status); + qdf_mem_free(req_msg); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +bool sme_is_any_session_in_middle_of_roaming(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t session_id; + + for (session_id = 0; session_id < WLAN_MAX_VDEVS; session_id++) { + if (CSR_IS_SESSION_VALID(mac_ctx, session_id) && + wlan_cm_host_roam_in_progress(mac_ctx->psoc, session_id)) + return true; + } + + return false; +} + +/* + * sme_send_flush_logs_cmd_to_fw() - Flush FW logs + * + * This function is used to send the command that will + * be used to flush the logs in the firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_send_flush_logs_cmd_to_fw(void) +{ + QDF_STATUS status; + struct scheduler_msg message = {0}; + + /* Serialize the req through MC thread */ + message.bodyptr = NULL; + message.type = SIR_HAL_FLUSH_LOG_TO_FW; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", status); + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +QDF_STATUS sme_enable_uapsd_for_ac(sme_ac_enum_type ac, uint8_t tid, + uint8_t pri, uint32_t srvc_int, + uint32_t sus_int, + enum sme_qos_wmm_dir_type dir, + uint8_t psb, uint32_t sessionId, + uint32_t delay_interval) +{ + void *wma_handle; + t_wma_trigger_uapsd_params uapsd_params; + enum uapsd_ac access_category; + + if (!psb) { + sme_debug("No need to configure auto trigger:psb is 0"); + return QDF_STATUS_SUCCESS; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + switch (ac) { + case SME_AC_BK: + access_category = UAPSD_BK; + break; + case SME_AC_BE: + access_category = UAPSD_BE; + break; + case SME_AC_VI: + access_category = UAPSD_VI; + break; + case SME_AC_VO: + access_category = UAPSD_VO; + break; + default: + return QDF_STATUS_E_FAILURE; + } + + uapsd_params.wmm_ac = access_category; + uapsd_params.user_priority = pri; + uapsd_params.service_interval = srvc_int; + uapsd_params.delay_interval = delay_interval; + uapsd_params.suspend_interval = sus_int; + + if (QDF_STATUS_SUCCESS != + wma_trigger_uapsd_params(wma_handle, sessionId, &uapsd_params)) { + sme_err("Failed to Trigger Uapsd params for vdev %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_disable_uapsd_for_ac(sme_ac_enum_type ac, uint32_t sessionId) +{ + void *wma_handle; + enum uapsd_ac access_category; + + switch (ac) { + case SME_AC_BK: + access_category = UAPSD_BK; + break; + case SME_AC_BE: + access_category = UAPSD_BE; + break; + case SME_AC_VI: + access_category = UAPSD_VI; + break; + case SME_AC_VO: + access_category = UAPSD_VO; + break; + default: + return QDF_STATUS_E_FAILURE; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (QDF_STATUS_SUCCESS != + wma_disable_uapsd_per_ac(wma_handle, sessionId, access_category)) { + sme_err("Failed to disable uapsd for ac %d for vdev %d", + ac, sessionId); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +static void sme_vdev_ht_tx_stbc(struct mac_context *mac_ctx, + bool ht_tx_stbc, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_ht_config ht_cap_info; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return; + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + ht_cap_info.caps = vdev_mlme->proto.ht_info.ht_caps; + + ht_cap_info.ht_caps.tx_stbc = ht_tx_stbc; + vdev_mlme->proto.ht_info.ht_caps = ht_cap_info.caps; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} + +/** + * sme_update_nss() - SME API to change the number for spatial streams + * (1 or 2) + * @mac_handle: Handle returned by mac open + * @nss: Number of spatial streams + * + * This function is used to update the number of spatial streams supported. + * + * Return: Success upon successfully changing nss else failure + * + */ +QDF_STATUS sme_update_nss(mac_handle_t mac_handle, uint8_t nss) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint32_t i; + struct mlme_ht_capabilities_info *ht_cap_info; + struct mlme_vht_capabilities_info *vht_cap_info; + + vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + + status = sme_acquire_global_lock(&mac_ctx->sme); + + if (QDF_STATUS_SUCCESS == status) { + vht_cap_info->enable2x2 = (nss == 1) ? 0 : 1; + + /* get the HT capability info*/ + ht_cap_info = &mac_ctx->mlme_cfg->ht_caps.ht_cap_info; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (CSR_IS_SESSION_VALID(mac_ctx, i)) { + sme_vdev_ht_tx_stbc(mac_ctx, + ht_cap_info->tx_stbc, i); + } + } + + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +/** + * sme_update_user_configured_nss() - sets the nss based on user request + * @mac_handle: Opaque handle to the global MAC context + * @nss: number of streams + * + * Return: None + */ +void sme_update_user_configured_nss(mac_handle_t mac_handle, uint8_t nss) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->user_configured_nss = nss; +} + +int sme_update_tx_bfee_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->mlme_cfg->vht_caps.vht_cap_info.su_bformee = cfg_val; + + return sme_update_he_tx_bfee_supp(mac_handle, session_id, cfg_val); +} + +int sme_update_tx_bfee_nsts(mac_handle_t mac_handle, uint8_t session_id, + uint8_t usr_cfg_val, uint8_t nsts_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t nsts_set_val; + struct mlme_vht_capabilities_info *vht_cap_info; + + vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + mac_ctx->usr_cfg_tx_bfee_nsts = usr_cfg_val; + if (usr_cfg_val) + nsts_set_val = usr_cfg_val; + else + nsts_set_val = nsts_val; + + vht_cap_info->tx_bfee_ant_supp = nsts_set_val; + + if (usr_cfg_val) + sme_set_he_tx_bf_cbf_rates(session_id); + + return sme_update_he_tx_bfee_nsts(mac_handle, session_id, nsts_set_val); +} + +#ifdef WLAN_FEATURE_11BE +void sme_update_tgt_eht_cap(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg, + tDot11fIEeht_cap *eht_cap_ini) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + qdf_mem_copy(&mac_ctx->eht_cap_2g, + &cfg->eht_cap_2g, + sizeof(tDot11fIEeht_cap)); + + qdf_mem_copy(&mac_ctx->eht_cap_5g, + &cfg->eht_cap_5g, + sizeof(tDot11fIEeht_cap)); + + qdf_mem_copy(&mac_ctx->eht_cap_2g_orig, + &mac_ctx->eht_cap_2g, + sizeof(tDot11fIEeht_cap)); + + qdf_mem_copy(&mac_ctx->eht_cap_5g_orig, + &mac_ctx->eht_cap_5g, + sizeof(tDot11fIEeht_cap)); +} + +void sme_set_eht_bw_cap(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelWidth chwidth) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_debug("No session for id %d", vdev_id); + return; + } + sme_debug("Config EHT caps for BW %d", chwidth); + mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap.support_320mhz_6ghz = 0; + + if (chwidth < eHT_CHANNEL_WIDTH_320MHZ) { + sme_debug("EHT caps config not required for bw: %d", chwidth); + return; + } + + mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap.support_320mhz_6ghz = 1; + qdf_mem_copy(&mac_ctx->eht_cap_5g, + &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap, + sizeof(tDot11fIEeht_cap)); + + csr_update_session_eht_cap(mac_ctx, session); +} + +int sme_update_eht_om_ctrl_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap.eht_om_ctl = cfg_val; + mac_ctx->eht_cap_2g.eht_om_ctl = cfg_val; + mac_ctx->eht_cap_5g.eht_om_ctl = cfg_val; + + csr_update_session_eht_cap(mac_ctx, session); + + return 0; +} +#endif + +#ifdef WLAN_FEATURE_11AX +void sme_update_tgt_he_cap(mac_handle_t mac_handle, + struct wma_tgt_cfg *cfg, + tDot11fIEhe_cap *he_cap_ini) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + qdf_mem_copy(&mac_ctx->he_cap_2g, + &cfg->he_cap_2g, + sizeof(tDot11fIEhe_cap)); + + qdf_mem_copy(&mac_ctx->he_cap_5g, + &cfg->he_cap_5g, + sizeof(tDot11fIEhe_cap)); + + if (!mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_pream_puncturing) { + sme_debug("feature is disabled via INI, FW caps 2G:%d, 5G:%d", + mac_ctx->he_cap_2g.rx_pream_puncturing, + mac_ctx->he_cap_5g.rx_pream_puncturing); + + mac_ctx->he_cap_2g.rx_pream_puncturing = 0; + mac_ctx->he_cap_5g.rx_pream_puncturing = 0; + } + + if (!mac_ctx->mlme_cfg->he_caps.enable_ul_mimo) { + sme_debug("feature is disabled via INI, FW caps 2G:%d, 5G:%d", + mac_ctx->he_cap_2g.ul_mu, mac_ctx->he_cap_5g.ul_mu); + mac_ctx->he_cap_2g.ul_mu = 0; + mac_ctx->he_cap_5g.ul_mu = 0; + } + + /* modify HE Caps field according to INI setting */ + mac_ctx->he_cap_2g.bfee_sts_lt_80 = + QDF_MIN(cfg->he_cap_2g.bfee_sts_lt_80, + he_cap_ini->bfee_sts_lt_80); + + mac_ctx->he_cap_5g.bfee_sts_lt_80 = + QDF_MIN(cfg->he_cap_5g.bfee_sts_lt_80, + he_cap_ini->bfee_sts_lt_80); + + if (!mac_ctx->mlme_cfg->vht_caps.vht_cap_info.enable2x2) { + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80 = HE_SET_MCS_4_NSS( + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80, + HE_MCS_DISABLE, 2); + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80 = HE_SET_MCS_4_NSS( + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80, + HE_MCS_DISABLE, 2); + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80 = HE_SET_MCS_4_NSS( + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80, + HE_MCS_DISABLE, 2); + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80 = HE_SET_MCS_4_NSS( + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80, + HE_MCS_DISABLE, 2); + } + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80 = HE_INTERSECT_MCS( + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80); + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80 = HE_INTERSECT_MCS( + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_lt_80); + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80 = HE_INTERSECT_MCS( + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80); + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80 = HE_INTERSECT_MCS( + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_lt_80); + + qdf_mem_copy(&mac_ctx->he_cap_2g_orig, + &mac_ctx->he_cap_2g, + sizeof(tDot11fIEhe_cap)); + + qdf_mem_copy(&mac_ctx->he_cap_5g_orig, + &mac_ctx->he_cap_5g, + sizeof(tDot11fIEhe_cap)); + +} + +void sme_update_he_cap_nss(mac_handle_t mac_handle, uint8_t session_id, + uint8_t nss) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *csr_session; + uint32_t tx_mcs_map = 0; + uint32_t rx_mcs_map = 0; + uint32_t mcs_map = 0; + + if (!nss || (nss > 2)) { + sme_err("invalid Nss value nss %d", nss); + return; + } + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + if (!csr_session) { + sme_err("No session for id %d", session_id); + return; + } + rx_mcs_map = + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80; + tx_mcs_map = + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_lt_80; + mcs_map = rx_mcs_map & 0x3; + + if (nss == 1) { + tx_mcs_map = HE_SET_MCS_4_NSS(tx_mcs_map, HE_MCS_DISABLE, 2); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, HE_MCS_DISABLE, 2); + } else { + tx_mcs_map = HE_SET_MCS_4_NSS(tx_mcs_map, mcs_map, 2); + rx_mcs_map = HE_SET_MCS_4_NSS(rx_mcs_map, mcs_map, 2); + } + sme_debug("new HE Nss MCS MAP: Rx 0x%0X, Tx: 0x%0X", + rx_mcs_map, tx_mcs_map); + if (cfg_in_range(CFG_HE_RX_MCS_MAP_LT_80, rx_mcs_map)) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80 = + rx_mcs_map; + if (cfg_in_range(CFG_HE_TX_MCS_MAP_LT_80, tx_mcs_map)) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_lt_80 = + tx_mcs_map; + if (cfg_in_range(CFG_HE_RX_MCS_MAP_160, rx_mcs_map)) + qdf_mem_copy(mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160, + &rx_mcs_map, sizeof(uint16_t)); + if (cfg_in_range(CFG_HE_TX_MCS_MAP_160, tx_mcs_map)) + qdf_mem_copy(mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160, + &tx_mcs_map, sizeof(uint16_t)); + + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80 = rx_mcs_map; + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80 = tx_mcs_map; + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80 = rx_mcs_map; + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80 = tx_mcs_map; + qdf_mem_copy(mac_ctx->he_cap_5g.rx_he_mcs_map_160, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_160, + sizeof(uint16_t)); + qdf_mem_copy(mac_ctx->he_cap_5g.tx_he_mcs_map_160, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_160, + sizeof(uint16_t)); + csr_update_session_he_cap(mac_ctx, csr_session); + +} + +int sme_update_he_mcs(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_mcs) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *csr_session; + uint16_t mcs_val = 0; + uint16_t mcs_map = HE_MCS_ALL_DISABLED; + uint16_t mcs_map_cfg; + uint8_t nss = 0, i; + uint16_t mcs_mask = 0x3; + + csr_session = CSR_GET_SESSION(mac_ctx, session_id); + if (!csr_session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + + mcs_map_cfg = + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80; + for (nss = 0; nss < VHT_MAX_NSS; nss++) { + if ((mcs_map_cfg & mcs_mask) == mcs_mask) + break; + mcs_mask = (mcs_mask << 2); + } + if (nss > 2) + nss = 2; + + if ((he_mcs & 0x3) == HE_MCS_DISABLE) { + sme_err("Invalid HE MCS 0x%0x, can't disable 0-7 for 1ss", + he_mcs); + return -EINVAL; + } + mcs_val = he_mcs & 0x3; + switch (he_mcs) { + case HE_80_MCS0_7: + case HE_80_MCS0_9: + case HE_80_MCS0_11: + for (i = 1; i <= nss; i++) + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, i); + + sme_debug("HE 80 nss: %d, mcs: 0x%0X", nss, mcs_map); + if (cfg_in_range(CFG_HE_TX_MCS_MAP_LT_80, mcs_map)) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_lt_80 = mcs_map; + if (cfg_in_range(CFG_HE_RX_MCS_MAP_LT_80, mcs_map)) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_lt_80 = mcs_map; + mac_ctx->he_cap_2g.tx_he_mcs_map_lt_80 = mcs_map; + mac_ctx->he_cap_2g.rx_he_mcs_map_lt_80 = mcs_map; + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80 = mcs_map; + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80 = mcs_map; + break; + + case HE_160_MCS0_7: + case HE_160_MCS0_9: + case HE_160_MCS0_11: + for (i = 1; i <= nss; i++) + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, i); + + sme_debug("HE 160 nss: %d, mcs: 0x%0X", nss, mcs_map); + if (cfg_in_range(CFG_HE_TX_MCS_MAP_160, mcs_map)) + qdf_mem_copy(mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160, &mcs_map, + sizeof(uint16_t)); + if (cfg_in_range(CFG_HE_RX_MCS_MAP_160, mcs_map)) + qdf_mem_copy(mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160, &mcs_map, + sizeof(uint16_t)); + qdf_mem_copy(mac_ctx->he_cap_5g.tx_he_mcs_map_160, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_160, + sizeof(uint16_t)); + qdf_mem_copy(mac_ctx->he_cap_5g.rx_he_mcs_map_160, + mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_160, + sizeof(uint16_t)); + break; + + case HE_80p80_MCS0_7: + case HE_80p80_MCS0_9: + case HE_80p80_MCS0_11: + mcs_map = HE_SET_MCS_4_NSS(mcs_map, mcs_val, 1); + if (cfg_in_range(CFG_HE_TX_MCS_MAP_80_80, mcs_map)) + qdf_mem_copy(mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + tx_he_mcs_map_80_80, &mcs_map, + sizeof(uint16_t)); + if (cfg_in_range(CFG_HE_RX_MCS_MAP_80_80, mcs_map)) + qdf_mem_copy(mac_ctx->mlme_cfg->he_caps.dot11_he_cap. + rx_he_mcs_map_80_80, &mcs_map, + sizeof(uint16_t)); + break; + + default: + sme_err("Invalid HE MCS 0x%0x", he_mcs); + return -EINVAL; + } + sme_debug("new HE MCS 0x%0x", mcs_map); + sme_set_vdev_ies_per_band(mac_handle, session_id, QDF_STA_MODE); + csr_update_session_he_cap(mac_ctx, csr_session); + + return 0; +} + +void sme_set_usr_cfg_mu_edca(mac_handle_t mac_handle, bool val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->usr_cfg_mu_edca_params = val; +} + +int sme_update_mu_edca_params(mac_handle_t mac_handle, uint8_t session_id) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = WNI_SME_UPDATE_MU_EDCA_PARAMS; + msg.reserved = 0; + msg.bodyval = session_id; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Not able to post update edca profile"); + return -EIO; + } + + return 0; +} + +void sme_set_he_mu_edca_def_cfg(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t i; + + sme_debug("Set MU EDCA params to default"); + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + mac_ctx->usr_mu_edca_params[i].aci.aifsn = MU_EDCA_DEF_AIFSN; + mac_ctx->usr_mu_edca_params[i].aci.aci = i; + mac_ctx->usr_mu_edca_params[i].cw.max = MU_EDCA_DEF_CW_MAX; + mac_ctx->usr_mu_edca_params[i].cw.min = MU_EDCA_DEF_CW_MIN; + mac_ctx->usr_mu_edca_params[i].mu_edca_timer = + MU_EDCA_DEF_TIMER; + } +} + +int sme_update_he_capabilities(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val, uint8_t cfg_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + tDot11fIEhe_cap *cfg_he_cap; + tDot11fIEhe_cap *he_cap_orig; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + cfg_he_cap = &mac_ctx->mlme_cfg->he_caps.dot11_he_cap; + he_cap_orig = &mac_ctx->mlme_cfg->he_caps.he_cap_orig; + + switch (cfg_id) { + case QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_BCAST_TWT_SUPPORT: + if (cfg_val) { + mac_ctx->mlme_cfg->twt_cfg.disable_btwt_usr_cfg = false; + cfg_he_cap->broadcast_twt = he_cap_orig->broadcast_twt; + } else { + cfg_he_cap->broadcast_twt = 0; + mac_ctx->mlme_cfg->twt_cfg.disable_btwt_usr_cfg = true; + } + break; + case QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_RX_CTRL_FRAME_TO_MBSS: + if (cfg_val) + cfg_he_cap->rx_ctrl_frame = he_cap_orig->rx_ctrl_frame; + else + cfg_he_cap->rx_ctrl_frame = 0; + break; + case QCA_WLAN_VENDOR_ATTR_WIFI_TEST_CONFIG_PUNCTURED_PREAMBLE_RX: + if (cfg_val) + cfg_he_cap->rx_pream_puncturing = + he_cap_orig->rx_pream_puncturing; + else + cfg_he_cap->rx_pream_puncturing = 0; + break; + default: + sme_debug("default: Unhandled cfg %d", cfg_id); + return -EINVAL; + } + + sme_debug("HE cap: cfg id %d, cfg val %d", cfg_id, cfg_val); + csr_update_session_he_cap(mac_ctx, session); + return 0; +} + +int sme_update_he_tx_bfee_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (cfg_val <= 1) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.su_beamformee = cfg_val; + else + return -EINVAL; + + csr_update_session_he_cap(mac_ctx, session); + return 0; +} + +int sme_update_he_trigger_frm_mac_pad(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (cfg_in_range(CFG_HE_TRIG_PAD, cfg_val)) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.trigger_frm_mac_pad = + cfg_val; + else + return -EINVAL; + + csr_update_session_he_cap(mac_ctx, session); + return 0; + +} + +int sme_update_he_om_ctrl_supp(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.omi_a_ctrl = cfg_val; + mac_ctx->he_cap_2g.omi_a_ctrl = cfg_val; + mac_ctx->he_cap_5g.omi_a_ctrl = cfg_val; + + csr_update_session_he_cap(mac_ctx, session); + return 0; +} + +int sme_update_he_htc_he_supp(mac_handle_t mac_handle, uint8_t session_id, + bool cfg_val) +{ + + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.htc_he = cfg_val; + csr_update_session_he_cap(mac_ctx, session); + + return 0; +} + +static QDF_STATUS +sme_validate_session_for_cap_update(struct mac_context *mac_ctx, + uint8_t session_id, + struct csr_roam_session *session) +{ + if (!session) { + sme_err("Session does not exist, Session_id: %d", session_id); + return QDF_STATUS_E_INVAL; + } + + if (!cm_is_vdevid_connected(mac_ctx->pdev, session_id)) { + sme_debug("STA is not connected, Session_id: %d", session_id); + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +int sme_send_he_om_ctrl_update(mac_handle_t mac_handle, uint8_t session_id, + struct omi_ctrl_tx *omi_data) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + void *wma_handle; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + uint32_t param_val = 0; + qdf_freq_t op_chan_freq; + qdf_freq_t freq_seg_0; + enum phy_ch_width ch_width; + struct qdf_mac_addr connected_bssid; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return -EIO; + + status = sme_validate_session_for_cap_update(mac_ctx, session_id, + session); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + wlan_get_op_chan_freq_info_vdev_id(mac_ctx->pdev, session_id, + &op_chan_freq, &freq_seg_0, + &ch_width); + + if (!omi_data) { + sme_err("OMI data is NULL"); + return -EIO; + } + + omi_data->a_ctrl_id = A_CTRL_ID_OMI; + + if (mac_ctx->he_om_ctrl_cfg_nss_set) + omi_data->rx_nss = mac_ctx->he_om_ctrl_cfg_nss; + else + omi_data->rx_nss = session->nss - 1; + + if (mac_ctx->he_om_ctrl_cfg_tx_nsts_set) + omi_data->tx_nsts = mac_ctx->he_om_ctrl_cfg_tx_nsts; + else + omi_data->tx_nsts = session->nss - 1; + + if (mac_ctx->he_om_ctrl_cfg_bw_set) + omi_data->ch_bw = mac_ctx->he_om_ctrl_cfg_bw; + else + omi_data->ch_bw = ch_width; + + omi_data->ul_mu_dis = mac_ctx->he_om_ctrl_cfg_ul_mu_dis; + omi_data->ul_mu_data_dis = mac_ctx->he_om_ctrl_ul_mu_data_dis; + omi_data->omi_in_vht = 0x1; + omi_data->omi_in_he = 0x1; + + sme_debug("OMI: BW %d TxNSTS %d RxNSS %d ULMU %d, OMI_VHT %d, OMI_HE %d", + omi_data->ch_bw, omi_data->tx_nsts, omi_data->rx_nss, + omi_data->ul_mu_dis, omi_data->omi_in_vht, + omi_data->omi_in_he); + sme_debug("EHT OMI: BW %d rx nss %d tx nss %d", omi_data->eht_ch_bw_ext, + omi_data->eht_rx_nss_ext, omi_data->eht_tx_nss_ext); + + qdf_mem_copy(¶m_val, omi_data, sizeof(param_val)); + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, session_id, + &connected_bssid); + sme_debug("param val %08X, bssid:"QDF_MAC_ADDR_FMT, param_val, + QDF_MAC_ADDR_REF(connected_bssid.bytes)); + status = wma_set_peer_param(wma_handle, + connected_bssid.bytes, + WMI_PEER_PARAM_XMIT_OMI, + param_val, session_id); + if (QDF_STATUS_SUCCESS != status) { + sme_err("set_peer_param_cmd returned %d", status); + return -EIO; + } + + return 0; +} + +int sme_set_he_om_ctrl_param(mac_handle_t mac_handle, uint8_t session_id, + enum qca_wlan_vendor_attr_he_omi_tx param, + uint8_t cfg_val) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + qdf_freq_t op_chan_freq; + qdf_freq_t freq_seg_0; + enum phy_ch_width ch_width; + + status = sme_validate_session_for_cap_update(mac_ctx, session_id, + session); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + wlan_get_op_chan_freq_info_vdev_id(mac_ctx->pdev, session_id, + &op_chan_freq, &freq_seg_0, + &ch_width); + + switch(param) { + case QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DISABLE: + sme_debug("Set OM ctrl UL MU dis to %d", cfg_val); + mac_ctx->he_om_ctrl_cfg_ul_mu_dis = cfg_val; + break; + case QCA_WLAN_VENDOR_ATTR_HE_OMI_RX_NSS: + if ((cfg_val + 1) > session->nss) { + sme_debug("OMI Nss %d is > connected Nss %d", + cfg_val, session->nss); + mac_ctx->he_om_ctrl_cfg_nss_set = false; + return 0; + } + sme_debug("Set OM ctrl Rx Nss cfg to %d", cfg_val); + mac_ctx->he_om_ctrl_cfg_nss_set = true; + mac_ctx->he_om_ctrl_cfg_nss = cfg_val; + break; + case QCA_WLAN_VENDOR_ATTR_HE_OMI_CH_BW: + if (cfg_val > ch_width) { + sme_debug("OMI BW %d is > connected BW %d", + cfg_val, ch_width); + mac_ctx->he_om_ctrl_cfg_bw_set = false; + return 0; + } + sme_debug("Set OM ctrl BW cfg to %d", cfg_val); + mac_ctx->he_om_ctrl_cfg_bw_set = true; + mac_ctx->he_om_ctrl_cfg_bw = cfg_val; + break; + case QCA_WLAN_VENDOR_ATTR_HE_OMI_TX_NSTS: + if ((cfg_val + 1) > session->nss) { + sme_debug("OMI NSTS %d is > connected Nss %d", + cfg_val, session->nss); + mac_ctx->he_om_ctrl_cfg_tx_nsts_set = false; + return 0; + } + sme_debug("Set OM ctrl tx nsts cfg to %d", cfg_val); + mac_ctx->he_om_ctrl_cfg_tx_nsts_set = true; + mac_ctx->he_om_ctrl_cfg_tx_nsts = cfg_val; + break; + case QCA_WLAN_VENDOR_ATTR_HE_OMI_ULMU_DATA_DISABLE: + sme_debug("Set OM ctrl UL MU data dis to %d", cfg_val); + mac_ctx->he_om_ctrl_ul_mu_data_dis = cfg_val; + break; + default: + sme_debug("Invalid OMI param %d", param); + return -EINVAL; + } + + return 0; +} + +void sme_reset_he_om_ctrl(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->he_om_ctrl_cfg_bw_set = false; + mac_ctx->he_om_ctrl_cfg_nss_set = false; + mac_ctx->he_om_ctrl_cfg_bw = 0; + mac_ctx->he_om_ctrl_cfg_nss = 0; + mac_ctx->he_om_ctrl_cfg_ul_mu_dis = false; + mac_ctx->he_om_ctrl_cfg_tx_nsts_set = false; + mac_ctx->he_om_ctrl_cfg_tx_nsts = 0; + mac_ctx->he_om_ctrl_ul_mu_data_dis = false; +} + +int sme_config_action_tx_in_tb_ppdu(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + struct sir_cfg_action_frm_tb_ppdu *cfg_msg; + + if (!cm_is_vdevid_connected(mac_ctx->pdev, session_id)) { + sme_debug("STA is not connected, Session_id: %d", session_id); + return -EINVAL; + } + + cfg_msg = qdf_mem_malloc(sizeof(*cfg_msg)); + if (!cfg_msg) + return -EIO; + + cfg_msg->type = WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU; + cfg_msg->vdev_id = session_id; + cfg_msg->cfg = cfg_val; + + msg.bodyptr = cfg_msg; + msg.type = WNI_SME_CFG_ACTION_FRM_HE_TB_PPDU; + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Failed to send CFG_ACTION_FRAME_IN_TB_PPDU to PE %d", + status); + qdf_mem_free(cfg_msg); + return -EIO; + } + + return 0; +} + +int sme_update_he_tx_bfee_nsts(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (cfg_in_range(CFG_HE_BFEE_STS_LT80, cfg_val)) { + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.bfee_sts_lt_80 = + cfg_val; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.bfee_sts_gt_80 = + cfg_val; + } else { + return -EINVAL; + } + + + csr_update_session_he_cap(mac_ctx, session); + return 0; +} + +void sme_set_he_tx_bf_cbf_rates(uint8_t session_id) +{ + uint32_t tx_bf_cbf_rates_5g[] = {91, 1, 0, 3, 2, 4, 0}; + uint32_t tx_bf_cbf_rates_2g[] = {91, 1, 1, 3, 1, 3, 0}; + QDF_STATUS status; + + status = wma_form_unit_test_cmd_and_send(session_id, 0x48, 7, + tx_bf_cbf_rates_5g); + if (QDF_STATUS_SUCCESS != status) + sme_err("send_unit_test_cmd returned %d", status); + + status = wma_form_unit_test_cmd_and_send(session_id, 0x48, 7, + tx_bf_cbf_rates_2g); + if (QDF_STATUS_SUCCESS != status) + sme_err("send_unit_test_cmd returned %d", status); +} + +void sme_config_su_ppdu_queue(uint8_t session_id, bool enable) +{ + uint32_t su_ppdu_enable[] = {69, 1, 1, 1}; + uint32_t su_ppdu_disable[] = {69, 1, 1, 0}; + QDF_STATUS status; + + if (enable) { + sme_debug("Send Tx SU PPDU queue ENABLE cmd to FW"); + status = wma_form_unit_test_cmd_and_send(session_id, 0x48, 4, + su_ppdu_enable); + } else { + sme_debug("Send Tx SU PPDU queue DISABLE cmd to FW"); + status = wma_form_unit_test_cmd_and_send(session_id, 0x48, 4, + su_ppdu_disable); + } + if (QDF_STATUS_SUCCESS != status) + sme_err("send_unit_test_cmd returned %d", status); +} + +int sme_update_he_tx_stbc_cap(mac_handle_t mac_handle, uint8_t session_id, + int value) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + uint32_t he_cap_val = 0; + + he_cap_val = value ? 1 : 0; + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (he_cap_val <= 1) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tb_ppdu_tx_stbc_lt_80mhz + = he_cap_val; + else + return -EINVAL; + if (he_cap_val <= 1) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tb_ppdu_tx_stbc_gt_80mhz + = he_cap_val; + else + return -EINVAL; + csr_update_session_he_cap(mac_ctx, session); + return 0; +} + +int sme_update_he_rx_stbc_cap(mac_handle_t mac_handle, uint8_t session_id, + int value) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + uint32_t he_cap_val = 0; + + he_cap_val = value ? 1 : 0; + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (he_cap_val <= 1) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_stbc_lt_80mhz = + he_cap_val; + else + return -EINVAL; + if (he_cap_val <= 1) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_stbc_gt_80mhz = + he_cap_val; + else + return -EINVAL; + csr_update_session_he_cap(mac_ctx, session); + return 0; +} + +int sme_update_he_frag_supp(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_frag) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (cfg_in_range(CFG_HE_FRAGMENTATION, he_frag)) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.fragmentation = he_frag; + else + return -EINVAL; + + csr_update_session_he_cap(mac_ctx, session); + return 0; + +} + +int sme_update_he_ldpc_supp(mac_handle_t mac_handle, uint8_t session_id, + uint16_t he_ldpc) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + if (he_ldpc <= 1) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ldpc_coding = he_ldpc; + else + return -EINVAL; + + csr_update_session_he_cap(mac_ctx, session); + return 0; + +} + +int sme_update_he_twt_req_support(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.twt_request = cfg_val; + + csr_update_session_he_cap(mac_ctx, session); + + return 0; +} + +int sme_update_he_full_ul_mumimo(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ul_mu = cfg_val; + + csr_update_session_he_cap(mac_ctx, session); + + return 0; +} +#endif + +QDF_STATUS +sme_update_session_txq_edca_params(mac_handle_t mac_handle, + uint8_t session_id, + tSirMacEdcaParamRecord *txq_edca_params) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct sir_update_session_txq_edca_param *msg; + struct pe_session *pe_session; + + pe_session = pe_find_session_by_vdev_id(mac_ctx, session_id); + if (!pe_session) { + pe_warn("Session does not exist for given session_id %d", + session_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_AGAIN; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) { + sme_release_global_lock(&mac_ctx->sme); + return QDF_STATUS_E_NOMEM; + } + + msg->message_type = eWNI_SME_UPDATE_SESSION_EDCA_TXQ_PARAMS; + msg->vdev_id = session_id; + qdf_mem_copy(&msg->txq_edca_params, txq_edca_params, + sizeof(tSirMacEdcaParamRecord)); + msg->length = sizeof(*msg); + + status = umac_send_mb_message_to_mac(msg); + + sme_release_global_lock(&mac_ctx->sme); + if (status != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_IO; + + pe_session->user_edca_set = 1; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_nud_debug_stats_cb() - set nud debug stats callback + * @mac_handle: Opaque handle to the global MAC context + * @cb: callback function pointer + * @context: callback context + * + * This function stores nud debug stats callback function. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_set_nud_debug_stats_cb(mac_handle_t mac_handle, + void (*cb)(void *, struct rsp_stats *, void *), + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac; + + if (!mac_handle) { + sme_err("mac_handle is not valid"); + return QDF_STATUS_E_INVAL; + } + mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + return status; + } + + mac->sme.get_arp_stats_cb = cb; + mac->sme.get_arp_stats_context = context; + sme_release_global_lock(&mac->sme); + return status; +} + +/** + * sme_is_any_session_in_connected_state() - SME wrapper API to + * check if any session is in connected state or not. + * + * @mac_handle: Handle returned by mac open + * + * This function is used to check if any valid sme session is in + * connected state or not. + * + * Return: true if any session is connected, else false. + * + */ +bool sme_is_any_session_in_connected_state(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + bool ret = false; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + ret = csr_is_any_session_in_connect_state(mac_ctx); + sme_release_global_lock(&mac_ctx->sme); + } + return ret; +} + +QDF_STATUS sme_set_chip_pwr_save_fail_cb(mac_handle_t mac_handle, + pwr_save_fail_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (status != QDF_STATUS_SUCCESS) { + sme_err("sme_AcquireGlobalLock failed!(status=%d)", status); + return status; + } + mac->sme.chip_power_save_fail_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} + +#ifdef FEATURE_RSSI_MONITOR +/** + * sme_set_rssi_monitoring() - set rssi monitoring + * @mac_handle: Opaque handle to the global MAC context + * @input: request message + * + * This function constructs the vos message and fill in message type, + * bodyptr with @input and posts it to WDA queue. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS sme_set_rssi_monitoring(mac_handle_t mac_handle, + struct rssi_monitor_param *input) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg message = {0}; + struct rssi_monitor_param *req_msg; + + SME_ENTER(); + req_msg = qdf_mem_malloc(sizeof(*req_msg)); + if (!req_msg) + return QDF_STATUS_E_NOMEM; + + *req_msg = *input; + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", status); + qdf_mem_free(req_msg); + return status; + } + + /* Serialize the req through MC thread */ + message.bodyptr = req_msg; + message.type = WMA_SET_RSSI_MONITOR_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", status); + qdf_mem_free(req_msg); + } + sme_release_global_lock(&mac->sme); + + return status; +} + +QDF_STATUS sme_set_rssi_threshold_breached_cb(mac_handle_t mac_handle, + rssi_threshold_breached_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac; + + mac = MAC_CONTEXT(mac_handle); + if (!mac) { + sme_err("Invalid mac context"); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("sme_acquire_global_lock failed!(status=%d)", + status); + return status; + } + + mac->sme.rssi_threshold_breached_cb = cb; + sme_release_global_lock(&mac->sme); + return status; +} +#endif /* FEATURE_RSSI_MONITOR */ + +QDF_STATUS sme_reset_rssi_threshold_breached_cb(mac_handle_t mac_handle) +{ + return sme_set_rssi_threshold_breached_cb(mac_handle, NULL); +} + +/* + * sme_pdev_set_hw_mode() - Send WMI_PDEV_SET_HW_MODE_CMDID to the WMA + * @mac_handle: Handle returned by macOpen + * @msg: HW mode structure containing hw mode and callback details + * + * Sends the command to CSR to send WMI_PDEV_SET_HW_MODE_CMDID to FW + * Return: QDF_STATUS_SUCCESS on successful posting + */ +QDF_STATUS sme_pdev_set_hw_mode(struct policy_mgr_hw_mode msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = sme_get_mac_context(); + tSmeCmd *cmd = NULL; + + if (!mac) { + sme_err("mac is NULL"); + return QDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to acquire lock"); + return QDF_STATUS_E_RESOURCES; + } + + cmd = csr_get_command_buffer(mac); + if (!cmd) { + sme_err("Get command buffer failed"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_hw_mode; + cmd->vdev_id = msg.session_id; + cmd->u.set_hw_mode_cmd.hw_mode_index = msg.hw_mode_index; + cmd->u.set_hw_mode_cmd.set_hw_mode_cb = msg.set_hw_mode_cb; + cmd->u.set_hw_mode_cmd.reason = msg.reason; + cmd->u.set_hw_mode_cmd.session_id = msg.session_id; + cmd->u.set_hw_mode_cmd.next_action = msg.next_action; + cmd->u.set_hw_mode_cmd.action = msg.action; + cmd->u.set_hw_mode_cmd.context = msg.context; + cmd->u.set_hw_mode_cmd.request_id = msg.request_id; + + sme_debug("Queuing set hw mode to CSR, session: %d reason: %d request_id: %x", + cmd->u.set_hw_mode_cmd.session_id, + cmd->u.set_hw_mode_cmd.reason, + cmd->u.set_hw_mode_cmd.request_id); + csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_nss_update_request(uint32_t vdev_id, + uint8_t new_nss, uint8_t ch_width, + policy_mgr_nss_update_cback cback, + uint8_t next_action, struct wlan_objmgr_psoc *psoc, + enum policy_mgr_conn_update_reason reason, + uint32_t original_vdev_id, uint32_t request_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = sme_get_mac_context(); + tSmeCmd *cmd = NULL; + + if (!mac) { + sme_err("mac is null"); + return status; + } + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + cmd = csr_get_command_buffer(mac); + if (!cmd) { + sme_err("Get command buffer failed"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + cmd->command = e_sme_command_nss_update; + /* Sessionized modules may require this info */ + cmd->vdev_id = vdev_id; + cmd->u.nss_update_cmd.new_nss = new_nss; + cmd->u.nss_update_cmd.ch_width = ch_width; + cmd->u.nss_update_cmd.session_id = vdev_id; + cmd->u.nss_update_cmd.nss_update_cb = cback; + cmd->u.nss_update_cmd.context = psoc; + cmd->u.nss_update_cmd.next_action = next_action; + cmd->u.nss_update_cmd.reason = reason; + cmd->u.nss_update_cmd.original_vdev_id = original_vdev_id; + cmd->u.nss_update_cmd.request_id = request_id; + + sme_debug("Queuing e_sme_command_nss_update to CSR:vdev (%d %d) ss %d r %d req id %x", + vdev_id, original_vdev_id, new_nss, reason, request_id); + csr_queue_sme_command(mac, cmd, false); + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS +sme_sap_update_ch_width(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + enum phy_ch_width ch_width, + enum policy_mgr_conn_update_reason reason, + uint8_t conc_vdev_id, uint32_t request_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = sme_get_mac_context(); + tSmeCmd *cmd = NULL; + + if (!mac) { + sme_err("mac is null"); + return status; + } + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + cmd = csr_get_command_buffer(mac); + if (!cmd) { + sme_err("Get command buffer failed"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + cmd->command = e_sme_command_sap_ch_width_update; + /* Sessionized modules may require this info */ + cmd->vdev_id = vdev_id; + cmd->u.bw_update_cmd.ch_width = ch_width; + cmd->u.bw_update_cmd.vdev_id = vdev_id; + cmd->u.bw_update_cmd.reason = reason; + cmd->u.bw_update_cmd.request_id = request_id; + cmd->u.bw_update_cmd.conc_vdev_id = conc_vdev_id; + + sme_debug("vdev %d ch_width: %d reason: %d", vdev_id, ch_width, reason); + csr_queue_sme_command(mac, cmd, false); + sme_release_global_lock(&mac->sme); + + return status; +} + +/** + * sme_soc_set_dual_mac_config() - Set dual mac configurations + * @mac_handle: Handle returned by macOpen + * @msg: Structure containing the dual mac config parameters + * + * Queues configuration information to CSR to configure + * WLAN firmware for the dual MAC features + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_soc_set_dual_mac_config(struct policy_mgr_dual_mac_config msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = sme_get_mac_context(); + tSmeCmd *cmd; + + if (!mac) { + sme_err("mac is null"); + return QDF_STATUS_E_FAILURE; + } + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to acquire lock"); + return QDF_STATUS_E_RESOURCES; + } + + cmd = csr_get_command_buffer(mac); + if (!cmd) { + sme_err("Get command buffer failed"); + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_dual_mac_config; + cmd->u.set_dual_mac_cmd.scan_config = msg.scan_config; + cmd->u.set_dual_mac_cmd.fw_mode_config = msg.fw_mode_config; + cmd->u.set_dual_mac_cmd.set_dual_mac_cb = msg.set_dual_mac_cb; + + sme_debug("set_dual_mac_config scan_config: %x fw_mode_config: %x", + cmd->u.set_dual_mac_cmd.scan_config, + cmd->u.set_dual_mac_cmd.fw_mode_config); + status = csr_queue_sme_command(mac, cmd, false); + + sme_release_global_lock(&mac->sme); + return status; +} + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * sme_gateway_param_update() - to update gateway parameters with WMA + * @mac_handle: Opaque handle to the global MAC context + * @gw_params: request parameters from HDD + * + * Return: QDF_STATUS + * + * This routine will update gateway parameters to WMA + */ +QDF_STATUS sme_gateway_param_update(mac_handle_t mac_handle, + struct gateway_update_req_param *gw_params) +{ + QDF_STATUS qdf_status; + struct scheduler_msg message = {0}; + struct gateway_update_req_param *request_buf; + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (!request_buf) + return QDF_STATUS_E_NOMEM; + + *request_buf = *gw_params; + + message.type = WMA_GW_PARAM_UPDATE_REQ; + message.reserved = 0; + message.bodyptr = request_buf; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Not able to post WMA_GW_PARAM_UPDATE_REQ message to HAL"); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * sme_soc_set_antenna_mode() - set antenna mode + * @mac_handle: Handle returned by macOpen + * @msg: Structure containing the antenna mode parameters + * + * Send the command to CSR to send + * WMI_SOC_SET_ANTENNA_MODE_CMDID to FW + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_soc_set_antenna_mode(mac_handle_t mac_handle, + struct sir_antenna_mode_param *msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + tSmeCmd *cmd; + + if (!msg) { + sme_err("antenna mode mesg is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to acquire lock"); + return QDF_STATUS_E_RESOURCES; + } + + cmd = csr_get_command_buffer(mac); + if (!cmd) { + sme_release_global_lock(&mac->sme); + sme_err("Get command buffer failed"); + return QDF_STATUS_E_NULL_VALUE; + } + + cmd->command = e_sme_command_set_antenna_mode; + cmd->u.set_antenna_mode_cmd = *msg; + + sme_debug("Antenna mode rx_chains: %d tx_chains: %d", + cmd->u.set_antenna_mode_cmd.num_rx_chains, + cmd->u.set_antenna_mode_cmd.num_tx_chains); + + csr_queue_sme_command(mac, cmd, false); + sme_release_global_lock(&mac->sme); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_set_peer_authorized() - call peer authorized callback + * @peer_addr: peer mac address + * @vdev_id: vdev id + * + * Return: QDF Status + */ +QDF_STATUS sme_set_peer_authorized(uint8_t *peer_addr, + uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_set_peer_param(wma_handle, peer_addr, + WMI_HOST_PEER_AUTHORIZE, 1, vdev_id); +} + +/** + * sme_setdef_dot11mode() - Updates mac with default dot11mode + * @mac_handle: Global MAC pointer + * + * Return: NULL. + */ +void sme_setdef_dot11mode(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + csr_set_default_dot11_mode(mac_ctx); +} + +/** + * sme_update_tgt_services() - update the target services config. + * @mac_handle: Opaque handle to the global MAC context. + * @cfg: wma_tgt_services parameters. + * + * update the target services config. + * + * Return: None. + */ +void sme_update_tgt_services(mac_handle_t mac_handle, + struct wma_tgt_services *cfg) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(mac_ctx->psoc); + if (!mlme_obj) + return; + + mac_ctx->obss_scan_offload = cfg->obss_scan_offload; + mac_ctx->mlme_cfg->gen.as_enabled = cfg->lte_coex_ant_share; + mac_ctx->beacon_offload = cfg->beacon_offload; + mac_ctx->pmf_offload = cfg->pmf_offload; + mlme_obj->cfg.lfr.rso_user_config.is_fils_roaming_supported = + cfg->is_fils_roaming_supported; + mac_ctx->is_11k_offload_supported = + cfg->is_11k_offload_supported; + sme_debug("obss_scan_offload: %d pmf_offload: %d fils_roam support %d 11k_offload %d", + mac_ctx->obss_scan_offload, mac_ctx->pmf_offload, + mlme_obj->cfg.lfr.rso_user_config.is_fils_roaming_supported, + mac_ctx->is_11k_offload_supported); + mac_ctx->bcn_reception_stats = cfg->bcn_reception_stats; +} + +/** + * sme_is_session_id_valid() - Check if the session id is valid + * @mac_handle: Opaque handle to the global MAC context + * @session_id: Session id + * + * Checks if the session id is valid or not + * + * Return: True is the session id is valid, false otherwise + */ +bool sme_is_session_id_valid(mac_handle_t mac_handle, uint32_t session_id) +{ + struct mac_context *mac; + + if (mac_handle) { + mac = MAC_CONTEXT(mac_handle); + } else { + sme_err("null mac pointer"); + return false; + } + + if (CSR_IS_SESSION_VALID(mac, session_id)) + return true; + + return false; +} + +#ifdef FEATURE_WLAN_TDLS + +/** + * sme_get_opclass() - determine operating class + * @mac_handle: Opaque handle to the global MAC context + * @channel: channel id + * @bw_offset: bandwidth offset + * @opclass: pointer to operating class + * + * Function will determine operating class from regdm_get_opclass_from_channel + * + * Return: none + */ +void sme_get_opclass(mac_handle_t mac_handle, uint8_t channel, + uint8_t bw_offset, uint8_t *opclass) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + wlan_reg_read_current_country(mac_ctx->psoc, reg_cc); + /* redgm opclass table contains opclass for 40MHz low primary, + * 40MHz high primary and 20MHz. No support for 80MHz yet. So + * first we will check if bit for 40MHz is set and if so find + * matching opclass either with low primary or high primary + * (a channel would never be in both) and then search for opclass + * matching 20MHz, else for any BW. + */ + if (bw_offset & (1 << BW_40_OFFSET_BIT)) { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, channel, BW40_LOW_PRIMARY); + if (!(*opclass)) { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, channel, BW40_HIGH_PRIMARY); + } + } else if (bw_offset & (1 << BW_20_OFFSET_BIT)) { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, channel, BW20); + } else { + *opclass = wlan_reg_dmn_get_opclass_from_channel( + reg_cc, channel, BWALL); + } +} +#endif + +/** + * sme_set_fw_test() - set fw test + * @fw_test: fw test param + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_set_fw_test(struct set_fwtest_params *fw_test) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_process_fw_test_cmd(wma_handle, fw_test); +} + +/** + * sme_ht40_stop_obss_scan() - ht40 obss stop scan + * @mac_handle: mac handle + * @vdev_id: vdev identifier + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_ht40_stop_obss_scan(mac_handle_t mac_handle, uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + wma_ht40_stop_obss_scan(wma_handle, vdev_id); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_BCN_RECV_FEATURE +QDF_STATUS sme_handle_bcn_recv_start(mac_handle_t mac_handle, + uint32_t vdev_id, uint32_t nth_value, + bool do_not_resume) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + QDF_STATUS status; + int ret; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_err("vdev_id %d not found", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("CSR session not valid: %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (session->is_bcn_recv_start) { + sme_release_global_lock(&mac_ctx->sme); + sme_err("Beacon receive already started"); + return QDF_STATUS_SUCCESS; + } + session->is_bcn_recv_start = true; + session->beacon_report_do_not_resume = do_not_resume; + sme_release_global_lock(&mac_ctx->sme); + } + + /* + * Allows fw to send beacons of connected AP to driver. + * MSB set : means fw do not wakeup host in wow mode + * LSB set: Value of beacon report period (say n), Means fw sends nth + * beacons of connected AP to HOST + */ + ret = sme_cli_set_command(vdev_id, + wmi_vdev_param_nth_beacon_to_host, + nth_value, VDEV_CMD); + if (ret) { + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + session->is_bcn_recv_start = false; + session->beacon_report_do_not_resume = false; + sme_release_global_lock(&mac_ctx->sme); + } + sme_err("wmi_vdev_param_nth_beacon_to_host %d", ret); + status = qdf_status_from_os_return(ret); + } + + return status; +} + +void sme_stop_beacon_report(mac_handle_t mac_handle, uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + QDF_STATUS status; + int ret; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("vdev_id %d not found", session_id); + return; + } + + ret = sme_cli_set_command(session_id, + wmi_vdev_param_nth_beacon_to_host, 0, + VDEV_CMD); + if (ret) + sme_err("wmi_vdev_param_nth_beacon_to_host command failed to FW"); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + session->is_bcn_recv_start = false; + session->beacon_report_do_not_resume = false; + sme_release_global_lock(&mac_ctx->sme); + } +} + +bool sme_is_beacon_report_started(mac_handle_t mac_handle, uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("vdev_id %d not found", session_id); + return false; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session not valid: %d", session_id); + return false; + } + + return session->is_bcn_recv_start; +} + +bool sme_is_beacon_reporting_do_not_resume(mac_handle_t mac_handle, + uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("vdev_id %d not found", session_id); + return false; + } + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session not valid: %d", session_id); + return false; + } + + return session->beacon_report_do_not_resume; +} +#endif + +/** + * sme_add_beacon_filter() - set the beacon filter configuration + * @mac_handle: The handle returned by macOpen + * @session_id: session id + * @ie_map: bitwise array of IEs + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_add_beacon_filter(mac_handle_t mac_handle, + uint32_t session_id, + uint32_t *ie_map) +{ + struct scheduler_msg message = {0}; + QDF_STATUS qdf_status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct beacon_filter_param *filter_param; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session not valid: %d", session_id); + return QDF_STATUS_E_FAILURE; + } + + filter_param = qdf_mem_malloc(sizeof(*filter_param)); + if (!filter_param) + return QDF_STATUS_E_FAILURE; + + filter_param->vdev_id = session_id; + + qdf_mem_copy(filter_param->ie_map, ie_map, + SIR_BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(uint32_t)); + + message.type = WMA_ADD_BCN_FILTER_CMDID; + message.bodyptr = filter_param; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Not able to post msg to WDA!"); + + qdf_mem_free(filter_param); + } + return qdf_status; +} + +/** + * sme_remove_beacon_filter() - set the beacon filter configuration + * @mac_handle: The handle returned by macOpen + * @session_id: session id + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_remove_beacon_filter(mac_handle_t mac_handle, + uint32_t session_id) +{ + struct scheduler_msg message = {0}; + QDF_STATUS qdf_status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct beacon_filter_param *filter_param; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session not valid: %d", session_id); + return QDF_STATUS_E_FAILURE; + } + + filter_param = qdf_mem_malloc(sizeof(*filter_param)); + if (!filter_param) + return QDF_STATUS_E_FAILURE; + + filter_param->vdev_id = session_id; + + message.type = WMA_REMOVE_BCN_FILTER_CMDID; + message.bodyptr = filter_param; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Not able to post msg to WDA!"); + + qdf_mem_free(filter_param); + } + return qdf_status; +} + +/** + * sme_send_disassoc_req_frame - send disassoc req + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * @peer_mac: peer mac address + * @reason: reason for disassociation + * wait_for_ack: wait for acknowledgment + * + * function to send disassoc request to lim + * + * return: none + */ +void sme_send_disassoc_req_frame(mac_handle_t mac_handle, uint8_t session_id, + uint8_t *peer_mac, uint16_t reason, + uint8_t wait_for_ack) +{ + struct sme_send_disassoc_frm_req *msg; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) + return; + + msg->msg_type = eWNI_SME_SEND_DISASSOC_FRAME; + msg->length = sizeof(*msg); + msg->vdev_id = session_id; + qdf_mem_copy(msg->peer_mac, peer_mac, QDF_MAC_ADDR_SIZE); + msg->reason = reason; + msg->wait_for_ack = wait_for_ack; + + qdf_status = umac_send_mb_message_to_mac(msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) + sme_err("umac_send_mb_message_to_mac failed, %d", + qdf_status); +} + +#ifdef FEATURE_WLAN_APF +QDF_STATUS sme_get_apf_capabilities(mac_handle_t mac_handle, + apf_get_offload_cb callback, + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context * mac_ctx = MAC_CONTEXT(mac_handle); + struct scheduler_msg cds_msg = {0}; + + SME_ENTER(); + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + /* Serialize the req through MC thread */ + mac_ctx->sme.apf_get_offload_cb = callback; + mac_ctx->sme.apf_get_offload_context = context; + cds_msg.bodyptr = NULL; + cds_msg.type = WDA_APF_GET_CAPABILITIES_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &cds_msg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Post apf get offload msg fail"); + status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac_ctx->sme); + } + + SME_EXIT(); + return status; +} + +QDF_STATUS sme_set_apf_instructions(mac_handle_t mac_handle, + struct sir_apf_set_offload *req) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_set_apf_instructions(wma_handle, req); +} + +QDF_STATUS sme_set_apf_enable_disable(mac_handle_t mac_handle, uint8_t vdev_id, + bool apf_enable) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_send_apf_enable_cmd(wma_handle, vdev_id, apf_enable); +} + +QDF_STATUS +sme_apf_write_work_memory(mac_handle_t mac_handle, + struct wmi_apf_write_memory_params *write_params) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_send_apf_write_work_memory_cmd(wma_handle, write_params); +} + +QDF_STATUS +sme_apf_read_work_memory(mac_handle_t mac_handle, + struct wmi_apf_read_memory_params *read_params, + apf_read_mem_cb callback) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + void *wma_handle; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.apf_read_mem_cb = callback; + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock failed"); + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_send_apf_read_work_memory_cmd(wma_handle, read_params); +} +#endif /* FEATURE_WLAN_APF */ + +/** + * sme_get_wni_dot11_mode() - return configured wni dot11mode + * @mac_handle: Opaque handle to the global MAC context + * + * Return: wni dot11 mode. + */ +uint32_t sme_get_wni_dot11_mode(mac_handle_t mac_handle) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + return csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + mac_ctx->roam.configParam.uCfgDot11Mode); +} + +/** + * sme_create_mon_session() - post message to create PE session for monitormode + * operation + * @mac_handle: Opaque handle to the global MAC context + * @bssid: pointer to bssid + * @vdev_id: sme session id + * + * Return: QDF_STATUS_SUCCESS on success, non-zero error code on failure. + */ +QDF_STATUS sme_create_mon_session(mac_handle_t mac_handle, uint8_t *bss_id, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_create_session *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (msg) { + msg->type = eWNI_SME_MON_INIT_SESSION; + msg->vdev_id = vdev_id; + msg->msg_len = sizeof(*msg); + qdf_mem_copy(msg->bss_id.bytes, bss_id, QDF_MAC_ADDR_SIZE); + status = umac_send_mb_message_to_mac(msg); + } + return status; +} + +QDF_STATUS sme_delete_mon_session(mac_handle_t mac_handle, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sir_delete_session *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (msg) { + msg->type = eWNI_SME_MON_DEINIT_SESSION; + msg->vdev_id = vdev_id; + msg->msg_len = sizeof(*msg); + status = umac_send_mb_message_to_mac(msg); + } + + return status; +} + +void +sme_set_del_peers_ind_callback(mac_handle_t mac_handle, + void (*callback)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id)) +{ + struct mac_context *mac; + + if (!mac_handle) { + QDF_ASSERT(0); + return; + } + mac = MAC_CONTEXT(mac_handle); + mac->del_peers_ind_cb = callback; +} + +void sme_set_chan_info_callback(mac_handle_t mac_handle, + void (*callback)(struct scan_chan_info *chan_info)) +{ + struct mac_context *mac; + + if (!mac_handle) { + QDF_ASSERT(0); + return; + } + mac = MAC_CONTEXT(mac_handle); + mac->chan_info_cb = callback; +} + +#ifdef WLAN_FEATURE_CAL_FAILURE_TRIGGER +void sme_set_cal_failure_event_cb( + mac_handle_t mac_handle, + void (*callback)(uint8_t cal_type, uint8_t reason)) +{ + struct mac_context *mac; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!mac_handle) { + QDF_ASSERT(0); + return; + } + mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->cal_failure_event_cb = callback; + sme_release_global_lock(&mac->sme); + } else { + sme_err("sme_acquire_global_lock failed"); + } +} +#endif + +void sme_set_vdev_ies_per_band(mac_handle_t mac_handle, uint8_t vdev_id, + enum QDF_OPMODE device_mode) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + csr_set_vdev_ies_per_band(mac_handle, vdev_id, + device_mode); + sme_release_global_lock(&mac_ctx->sme); + } +} + +/** + * sme_set_pdev_ht_vht_ies() - sends the set pdev IE req + * @mac_handle: Opaque handle to the global MAC context + * @enable2x2: 1x1 or 2x2 mode. + * + * Sends the set pdev IE req with Nss value. + * + * Return: None + */ +void sme_set_pdev_ht_vht_ies(mac_handle_t mac_handle, bool enable2x2) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct sir_set_ht_vht_cfg *ht_vht_cfg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!((mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (mac_ctx->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY))) + return; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + ht_vht_cfg = qdf_mem_malloc(sizeof(*ht_vht_cfg)); + if (!ht_vht_cfg) { + sme_release_global_lock(&mac_ctx->sme); + return; + } + + ht_vht_cfg->pdev_id = 0; + if (enable2x2) + ht_vht_cfg->nss = 2; + else + ht_vht_cfg->nss = 1; + ht_vht_cfg->dot11mode = + (uint8_t)csr_translate_to_wni_cfg_dot11_mode(mac_ctx, + mac_ctx->roam.configParam.uCfgDot11Mode); + + ht_vht_cfg->msg_type = eWNI_SME_PDEV_SET_HT_VHT_IE; + ht_vht_cfg->len = sizeof(*ht_vht_cfg); + sme_debug("SET_HT_VHT_IE with nss: %d, dot11mode: %d", + ht_vht_cfg->nss, + ht_vht_cfg->dot11mode); + status = umac_send_mb_message_to_mac(ht_vht_cfg); + if (QDF_STATUS_SUCCESS != status) + sme_err("Send SME_PDEV_SET_HT_VHT_IE fail"); + + sme_release_global_lock(&mac_ctx->sme); + } +} + +void sme_get_sap_vdev_type_nss(mac_handle_t mac_handle, uint8_t *vdev_nss, + enum band_info band) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (band == BAND_5G) + *vdev_nss = mac_ctx->vdev_type_nss_5g.sap; + else + *vdev_nss = mac_ctx->vdev_type_nss_2g.sap; +} + +void sme_update_vdev_type_nss(mac_handle_t mac_handle, uint8_t max_supp_nss, + enum nss_chains_band_info band) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct vdev_type_nss *vdev_nss; + + struct wlan_mlme_nss_chains *nss_chains_ini_cfg = + &mac_ctx->mlme_cfg->nss_chains_ini_cfg; + + if (band == NSS_CHAINS_BAND_5GHZ) + vdev_nss = &mac_ctx->vdev_type_nss_5g; + else + vdev_nss = &mac_ctx->vdev_type_nss_2g; + + vdev_nss->sta = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + STA_NSS_CHAINS_SHIFT)); + vdev_nss->sap = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + SAP_NSS_CHAINS_SHIFT)); + vdev_nss->p2p_go = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + P2P_GO_NSS_CHAINS_SHIFT)); + vdev_nss->p2p_cli = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + P2P_CLI_CHAINS_SHIFT)); + vdev_nss->p2p_dev = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + P2P_DEV_NSS_CHAINS_SHIFT)); + vdev_nss->ibss = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + IBSS_NSS_CHAINS_SHIFT)); + vdev_nss->tdls = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + TDLS_NSS_CHAINS_SHIFT)); + vdev_nss->ocb = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + OCB_NSS_CHAINS_SHIFT)); + vdev_nss->nan = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + NAN_NSS_CHAIN_SHIFT)); + vdev_nss->ndi = QDF_MIN(max_supp_nss, GET_VDEV_NSS_CHAIN( + nss_chains_ini_cfg-> + rx_nss[band], + NAN_NSS_CHAIN_SHIFT)); + + sme_debug("band %d NSS:sta %d sap %d cli %d go %d dev %d ibss %d tdls %d ocb %d nan %d", + band, vdev_nss->sta, vdev_nss->sap, vdev_nss->p2p_cli, + vdev_nss->p2p_go, vdev_nss->p2p_dev, vdev_nss->ibss, + vdev_nss->tdls, vdev_nss->ocb, vdev_nss->nan); +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +#define MAX_BSS_COLOR_VAL 63 +#define MIN_BSS_COLOR_VAL 1 + +QDF_STATUS sme_set_he_bss_color(mac_handle_t mac_handle, uint8_t session_id, + uint8_t bss_color) + +{ + struct sir_set_he_bss_color *bss_color_msg; + uint8_t len; + + if (!mac_handle) { + sme_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + + sme_debug("Set HE bss_color %d", bss_color); + + if (bss_color < MIN_BSS_COLOR_VAL || bss_color > MAX_BSS_COLOR_VAL) { + sme_debug("Invalid HE bss_color %d", bss_color); + return QDF_STATUS_E_INVAL; + } + len = sizeof(*bss_color_msg); + bss_color_msg = qdf_mem_malloc(len); + if (!bss_color_msg) + return QDF_STATUS_E_NOMEM; + + bss_color_msg->message_type = eWNI_SME_SET_HE_BSS_COLOR; + bss_color_msg->length = len; + bss_color_msg->vdev_id = session_id; + bss_color_msg->bss_color = bss_color; + return umac_send_mb_message_to_mac(bss_color_msg); +} + +QDF_STATUS sme_reconfig_obss_scan_param(mac_handle_t mac_handle, + uint8_t session_id, + bool is_scan_reconfig) +{ + struct sir_cfg_obss_scan *obss_scan_msg; + uint8_t len; + + if (!mac_handle) { + sme_err("Invalid mac_handle pointer"); + return QDF_STATUS_E_FAULT; + } + + len = sizeof(*obss_scan_msg); + obss_scan_msg = qdf_mem_malloc(len); + if (!obss_scan_msg) + return QDF_STATUS_E_NOMEM; + + obss_scan_msg->message_type = eWNI_SME_RECONFIG_OBSS_SCAN_PARAM; + obss_scan_msg->length = len; + obss_scan_msg->vdev_id = session_id; + obss_scan_msg->is_scan_reconfig = is_scan_reconfig; + return umac_send_mb_message_to_mac(obss_scan_msg); +} +#endif + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * sme_register_p2p_lo_event() - Register for the p2p lo event + * @mac_handle: Opaque handle to the global MAC context + * @context: the context of the call + * @callback: the callback to hdd + * + * This function registers the callback function for P2P listen + * offload stop event. + * + * Return: none + */ +void sme_register_p2p_lo_event(mac_handle_t mac_handle, void *context, + p2p_lo_callback callback) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_acquire_global_lock(&mac->sme); + mac->sme.p2p_lo_event_callback = callback; + mac->sme.p2p_lo_event_context = context; + sme_release_global_lock(&mac->sme); +} +#endif + +/** + * sme_process_mac_pwr_dbg_cmd() - enable mac pwr debugging + * @mac_handle: The handle returned by macOpen + * @session_id: session id + * @dbg_args: args for mac pwr debug command + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_process_mac_pwr_dbg_cmd(mac_handle_t mac_handle, + uint32_t session_id, + struct sir_mac_pwr_dbg_cmd *dbg_args) +{ + struct scheduler_msg message = {0}; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct sir_mac_pwr_dbg_cmd *req; + int i; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session not valid: %d", session_id); + return QDF_STATUS_E_FAILURE; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_FAILURE; + + req->module_id = dbg_args->module_id; + req->pdev_id = dbg_args->pdev_id; + req->num_args = dbg_args->num_args; + for (i = 0; i < req->num_args; i++) + req->args[i] = dbg_args->args[i]; + + message.type = SIR_HAL_POWER_DBG_CMD; + message.bodyptr = req; + + if (!QDF_IS_STATUS_SUCCESS(scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message))) { + sme_err("Not able to post msg to WDA!"); + qdf_mem_free(req); + } + return QDF_STATUS_SUCCESS; +} +/** + * sme_get_vdev_type_nss() - gets the nss per vdev type + * @dev_mode: connection type. + * @nss2g: Pointer to the 2G Nss parameter. + * @nss5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on connection type. + * + * Return: None + */ +void sme_get_vdev_type_nss(enum QDF_OPMODE dev_mode, + uint8_t *nss_2g, uint8_t *nss_5g) +{ + csr_get_vdev_type_nss(dev_mode, nss_2g, nss_5g); +} + +/** + * sme_update_sta_roam_policy() - update sta roam policy for + * unsafe and DFS channels. + * @mac_handle: Opaque handle to the global MAC context + * @dfs_mode: dfs mode which tell if dfs channel needs to be + * skipped or not + * @skip_unsafe_channels: Param to tell if driver needs to + * skip unsafe channels or not. + * @vdev_id: vdev_id + * @sap_operating_band: Band on which SAP is operating + * + * sme_update_sta_roam_policy update sta rome policies to csr + * this function will call csrUpdateChannelList as well + * to include/exclude DFS channels and unsafe channels. + * + * Return: eHAL_STATUS_SUCCESS or non-zero on failure. + */ +QDF_STATUS sme_update_sta_roam_policy(mac_handle_t mac_handle, + enum sta_roam_policy_dfs_mode dfs_mode, + bool skip_unsafe_channels, + uint8_t vdev_id, + uint8_t sap_operating_band) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + if (!mac_ctx) { + sme_err("mac_ctx is null"); + return QDF_STATUS_E_FAILURE; + } + + mlme_obj = mlme_get_psoc_ext_obj(mac_ctx->psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + + mlme_obj->cfg.lfr.rso_user_config.policy_params.dfs_mode = + dfs_mode; + mlme_obj->cfg.lfr.rso_user_config.policy_params.skip_unsafe_channels = + skip_unsafe_channels; + mlme_obj->cfg.lfr.rso_user_config.policy_params.sap_operating_band = + sap_operating_band; + + status = csr_update_channel_list(mac_ctx); + if (QDF_STATUS_SUCCESS != status) { + sme_err("failed to update the supported channel list"); + } + + if (mac_ctx->mlme_cfg->lfr.roam_scan_offload_enabled) { + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + wlan_roam_update_cfg(mac_ctx->psoc, vdev_id, + REASON_ROAM_SCAN_STA_ROAM_POLICY_CHANGED); + sme_release_global_lock(&mac_ctx->sme); + } + } + + return status; +} + +/** + * sme_enable_disable_chanavoidind_event - configure ca event ind + * @mac_handle: Opaque handle to the global MAC context + * @set_value: enable/disable + * + * function to enable/disable chan avoidance indication + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_disable_chanavoidind_event(mac_handle_t mac_handle, + uint8_t set_value) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + + if (!mac_ctx->mlme_cfg->gen.optimize_ca_event) { + sme_debug("optimize_ca_event not enabled in ini"); + return QDF_STATUS_E_NOSUPPORT; + } + + sme_debug("set_value: %d", set_value); + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_STATUS_SUCCESS == status) { + qdf_mem_zero(&msg, sizeof(struct scheduler_msg)); + msg.type = WMA_SEND_FREQ_RANGE_CONTROL_IND; + msg.bodyval = set_value; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + sme_release_global_lock(&mac_ctx->sme); + return status; + } + return status; +} + +/* + * sme_set_default_scan_ie() - API to send default scan IE to LIM + * @mac_handle: Opaque handle to the global MAC context + * @session_id: current session ID + * @ie_data: Pointer to Scan IE data + * @ie_len: Length of @ie_data + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_default_scan_ie(mac_handle_t mac_handle, uint16_t session_id, + uint8_t *ie_data, uint16_t ie_len) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct hdd_default_scan_ie *set_ie_params; + + if (!ie_data) + return QDF_STATUS_E_INVAL; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + set_ie_params = qdf_mem_malloc(sizeof(*set_ie_params)); + if (!set_ie_params) + status = QDF_STATUS_E_NOMEM; + else { + set_ie_params->message_type = eWNI_SME_DEFAULT_SCAN_IE; + set_ie_params->length = sizeof(*set_ie_params); + set_ie_params->vdev_id = session_id; + set_ie_params->ie_len = ie_len; + qdf_mem_copy(set_ie_params->ie_data, ie_data, ie_len); + status = umac_send_mb_message_to_mac(set_ie_params); + } + sme_release_global_lock(&mac_ctx->sme); + } + return status; +} + +QDF_STATUS sme_get_sar_power_limits(mac_handle_t mac_handle, + wma_sar_cb callback, void *context) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_get_sar_limit(wma_handle, callback, context); +} + +QDF_STATUS sme_set_sar_power_limits(mac_handle_t mac_handle, + struct sar_limit_cmd_params *sar_limit_cmd) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_set_sar_limit(wma_handle, sar_limit_cmd); +} + +QDF_STATUS sme_send_coex_config_cmd(struct coex_config_params *coex_cfg_params) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_send_coex_config_cmd(wma_handle, coex_cfg_params); +} + +#ifdef WLAN_FEATURE_FIPS +QDF_STATUS sme_fips_request(mac_handle_t mac_handle, struct fips_params *param, + wma_fips_cb callback, void *context) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_fips_request(wma_handle, param, callback, context); +} +#endif + +QDF_STATUS sme_set_cts2self_for_p2p_go(mac_handle_t mac_handle) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (QDF_STATUS_SUCCESS != + wma_set_cts2self_for_p2p_go(wma_handle, true)) { + sme_err("Failed to set cts2self for p2p GO to firmware"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_update_tx_fail_cnt_threshold() - update tx fail count Threshold + * @mac_handle: Handle returned by mac_open + * @session_id: Session ID on which tx fail count needs to be updated to FW + * @tx_fail_count: Count for tx fail threshold after which FW will disconnect + * + * This function is used to set tx fail count threshold to firmware. + * firmware will issue disocnnect with peer device once this threshold is + * reached. + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS sme_update_tx_fail_cnt_threshold(mac_handle_t mac_handle, + uint8_t session_id, + uint32_t tx_fail_count) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct sme_tx_fail_cnt_threshold *tx_fail_cnt; + struct scheduler_msg msg = {0}; + + tx_fail_cnt = qdf_mem_malloc(sizeof(*tx_fail_cnt)); + if (!tx_fail_cnt) + return QDF_STATUS_E_FAILURE; + + sme_debug("session_id: %d tx_fail_count: %d", + session_id, tx_fail_count); + tx_fail_cnt->session_id = session_id; + tx_fail_cnt->tx_fail_cnt_threshold = tx_fail_count; + + qdf_mem_zero(&msg, sizeof(struct scheduler_msg)); + msg.type = SIR_HAL_UPDATE_TX_FAIL_CNT_TH; + msg.reserved = 0; + msg.bodyptr = tx_fail_cnt; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Not able to post Tx fail count message to WDA"); + qdf_mem_free(tx_fail_cnt); + } + return status; +} + +QDF_STATUS sme_set_lost_link_info_cb(mac_handle_t mac_handle, + lost_link_info_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.lost_link_info_cb = cb; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +bool sme_neighbor_roam_is11r_assoc(mac_handle_t mac_handle, uint8_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy config; + + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, session_id, IS_11R_CONNECTION, + &config); + + return config.bool_value; +} + +#ifdef WLAN_FEATURE_WOW_PULSE +/** + * sme_set_wow_pulse() - set wow pulse info + * @wow_pulse_set_info: wow_pulse_mode structure pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_wow_pulse(struct wow_pulse_mode *wow_pulse_set_info) +{ + struct scheduler_msg message = {0}; + QDF_STATUS status; + struct wow_pulse_mode *wow_pulse_set_cmd; + + if (!wow_pulse_set_info) { + sme_err("invalid wow_pulse_set_info pointer"); + return QDF_STATUS_E_FAILURE; + } + + wow_pulse_set_cmd = qdf_mem_malloc(sizeof(*wow_pulse_set_cmd)); + if (!wow_pulse_set_cmd) + return QDF_STATUS_E_NOMEM; + + *wow_pulse_set_cmd = *wow_pulse_set_info; + + message.type = WMA_SET_WOW_PULSE_CMD; + message.bodyptr = wow_pulse_set_cmd; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Not able to post msg to WDA!"); + qdf_mem_free(wow_pulse_set_cmd); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} +#endif + +QDF_STATUS sme_get_rssi_snr_by_bssid(mac_handle_t mac_handle, + const uint8_t *bssid, + int8_t *rssi, int8_t *snr) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct qdf_mac_addr mac_addr; + + qdf_mem_copy(mac_addr.bytes, + bssid, sizeof(struct qdf_mac_addr)); + status = cm_get_rssi_snr_by_bssid(mac_ctx->pdev, &mac_addr, rssi, snr); + + sme_debug("status %d snr: %d, rssi: %d", status, + snr ? *snr : 0, rssi ? *rssi: 0); + + return status; +} + +void sme_clear_sae_single_pmk_info(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache_info) +{ + struct wlan_crypto_pmksa *pmksa; + struct wlan_objmgr_vdev *vdev; + struct wlan_crypto_pmksa pmk_to_del; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, session_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("Invalid vdev"); + return; + } + pmksa = wlan_crypto_get_pmksa(vdev, &pmk_cache_info->bssid); + if (!pmksa) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + qdf_mem_copy(&pmk_to_del.pmk, pmksa->pmk, pmksa->pmk_len); + pmk_to_del.pmk_len = pmksa->pmk_len; + csr_clear_sae_single_pmk(psoc, session_id, &pmk_to_del); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} + +QDF_STATUS sme_set_del_pmkid_cache(struct wlan_objmgr_psoc *psoc, + uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache_info, + bool is_add) +{ + struct wmi_unified_pmk_cache *pmk_cache; + struct scheduler_msg msg; + + pmk_cache = qdf_mem_malloc(sizeof(*pmk_cache)); + if (!pmk_cache) + return QDF_STATUS_E_NOMEM; + + qdf_mem_zero(pmk_cache, sizeof(*pmk_cache)); + + pmk_cache->vdev_id = session_id; + + if (!pmk_cache_info) { + pmk_cache->is_flush_all = true; + csr_clear_sae_single_pmk(psoc, session_id, NULL); + goto send_flush_cmd; + } + + if (!pmk_cache_info->ssid_len) { + pmk_cache->cat_flag = WMI_PMK_CACHE_CAT_FLAG_BSSID; + WMI_CHAR_ARRAY_TO_MAC_ADDR(pmk_cache_info->bssid.bytes, + &pmk_cache->bssid); + } else { + pmk_cache->cat_flag = WMI_PMK_CACHE_CAT_FLAG_SSID_CACHE_ID; + pmk_cache->ssid.length = pmk_cache_info->ssid_len; + qdf_mem_copy(pmk_cache->ssid.ssid, + pmk_cache_info->ssid, + pmk_cache->ssid.length); + } + pmk_cache->cache_id = (uint32_t) (pmk_cache_info->cache_id[0] << 8 | + pmk_cache_info->cache_id[1]); + + if (is_add) + pmk_cache->action_flag = WMI_PMK_CACHE_ACTION_FLAG_ADD_ENTRY; + else + pmk_cache->action_flag = WMI_PMK_CACHE_ACTION_FLAG_DEL_ENTRY; + + pmk_cache->pmkid_len = PMKID_LEN; + qdf_mem_copy(pmk_cache->pmkid, pmk_cache_info->pmkid, + PMKID_LEN); + + pmk_cache->pmk_len = pmk_cache_info->pmk_len; + qdf_mem_copy(pmk_cache->pmk, pmk_cache_info->pmk, + pmk_cache->pmk_len); + +send_flush_cmd: + msg.type = SIR_HAL_SET_DEL_PMKID_CACHE; + msg.reserved = 0; + msg.bodyptr = pmk_cache; + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err("Not able to post message to WDA"); + if (pmk_cache) { + qdf_mem_zero(pmk_cache, sizeof(*pmk_cache)); + qdf_mem_free(pmk_cache); + } + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/* ARP DEBUG STATS */ + +/** + * sme_set_nud_debug_stats() - sme api to set nud debug stats + * @mac_handle: Opaque handle to the global MAC context + * @set_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_set_nud_debug_stats(mac_handle_t mac_handle, + struct set_arp_stats_params + *set_stats_param) +{ + struct set_arp_stats_params *arp_set_param; + struct scheduler_msg msg; + + arp_set_param = qdf_mem_malloc(sizeof(*arp_set_param)); + if (!arp_set_param) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(arp_set_param, set_stats_param, sizeof(*arp_set_param)); + + msg.type = WMA_SET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_set_param; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err("Not able to post message to WDA"); + qdf_mem_free(arp_set_param); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_get_nud_debug_stats() - sme api to get nud debug stats + * @mac_handle: Opaque handle to the global MAC context + * @get_stats_param: pointer to set stats param + * + * Return: Return QDF_STATUS. + */ +QDF_STATUS sme_get_nud_debug_stats(mac_handle_t mac_handle, + struct get_arp_stats_params + *get_stats_param) +{ + struct get_arp_stats_params *arp_get_param; + struct scheduler_msg msg; + + arp_get_param = qdf_mem_malloc(sizeof(*arp_get_param)); + if (!arp_get_param) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(arp_get_param, get_stats_param, sizeof(*arp_get_param)); + + msg.type = WMA_GET_ARP_STATS_REQ; + msg.reserved = 0; + msg.bodyptr = arp_get_param; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err("Not able to post message to WDA"); + qdf_mem_free(arp_get_param); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_set_peer_param(uint8_t *peer_addr, uint32_t param_id, + uint32_t param_value, uint32_t vdev_id) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_set_peer_param(wma_handle, peer_addr, param_id, + param_value, vdev_id); +} + +QDF_STATUS sme_register_set_connection_info_cb(mac_handle_t mac_handle, + bool (*set_connection_info_cb)(bool), + bool (*get_connection_info_cb)(uint8_t *session_id, + enum scan_reject_states *reason)) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.set_connection_info_cb = set_connection_info_cb; + mac->sme.get_connection_info_cb = get_connection_info_cb; + sme_release_global_lock(&mac->sme); + } + return status; +} + +QDF_STATUS sme_rso_cmd_status_cb(mac_handle_t mac_handle, + rso_cmd_status_cb cb) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + mac->sme.rso_cmd_status_cb = cb; + sme_debug("Registered RSO command status callback"); + return status; +} + +QDF_STATUS sme_set_dbs_scan_selection_config(mac_handle_t mac_handle, + struct wmi_dbs_scan_sel_params *params) +{ + struct scheduler_msg message = {0}; + QDF_STATUS status; + struct wmi_dbs_scan_sel_params *dbs_scan_params; + uint32_t i; + + if (0 == params->num_clients) { + sme_err("Num of clients is 0"); + return QDF_STATUS_E_FAILURE; + } + + dbs_scan_params = qdf_mem_malloc(sizeof(*dbs_scan_params)); + if (!dbs_scan_params) + return QDF_STATUS_E_NOMEM; + + dbs_scan_params->num_clients = params->num_clients; + dbs_scan_params->pdev_id = params->pdev_id; + for (i = 0; i < params->num_clients; i++) { + dbs_scan_params->module_id[i] = params->module_id[i]; + dbs_scan_params->num_dbs_scans[i] = params->num_dbs_scans[i]; + dbs_scan_params->num_non_dbs_scans[i] = + params->num_non_dbs_scans[i]; + } + message.type = WMA_SET_DBS_SCAN_SEL_CONF_PARAMS; + message.bodyptr = dbs_scan_params; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Not able to post msg to WMA!"); + qdf_mem_free(dbs_scan_params); + } + + return status; +} + +QDF_STATUS sme_get_rcpi(mac_handle_t mac_handle, struct sme_rcpi_req *rcpi) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + struct sme_rcpi_req *rcpi_req; + + rcpi_req = qdf_mem_malloc(sizeof(*rcpi_req)); + if (!rcpi_req) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(rcpi_req, rcpi, sizeof(*rcpi_req)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + msg.bodyptr = rcpi_req; + msg.type = WMA_GET_RCPI_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + sme_release_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("post get rcpi req failed"); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(rcpi_req); + } + } else { + qdf_mem_free(rcpi_req); + } + + return status; +} + +void sme_store_pdev(mac_handle_t mac_handle, struct wlan_objmgr_pdev *pdev) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + void *wma_handle; + QDF_STATUS status; + + status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_LEGACY_MAC_ID); + if (QDF_STATUS_SUCCESS != status) { + mac_ctx->pdev = NULL; + return; + } + mac_ctx->pdev = pdev; + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return; + + wma_store_pdev(wma_handle, pdev); + pdev->pdev_nif.pdev_fw_caps |= SUPPORTED_CRYPTO_CAPS; +} + +QDF_STATUS sme_register_tx_queue_cb(mac_handle_t mac_handle, + tx_queue_cb tx_queue_cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.tx_queue_cb = tx_queue_cb; + sme_release_global_lock(&mac->sme); + sme_debug("Tx queue callback set"); + } + + return status; +} + +QDF_STATUS sme_deregister_tx_queue_cb(mac_handle_t mac_handle) +{ + return sme_register_tx_queue_cb(mac_handle, NULL); +} + +#ifdef WLAN_SUPPORT_TWT + +QDF_STATUS sme_test_config_twt_setup(struct wmi_twt_add_dialog_param *params) +{ + t_wma_handle *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_twt_process_add_dialog(wma_handle, params); +} + +QDF_STATUS +sme_test_config_twt_terminate(struct wmi_twt_del_dialog_param *params) +{ + t_wma_handle *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + return wma_twt_process_del_dialog(wma_handle, params); +} + +QDF_STATUS sme_clear_twt_complete_cb(mac_handle_t mac_handle) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.twt_add_dialog_cb = NULL; + mac->sme.twt_del_dialog_cb = NULL; + mac->sme.twt_pause_dialog_cb = NULL; + mac->sme.twt_resume_dialog_cb = NULL; + mac->sme.twt_notify_cb = NULL; + mac->sme.twt_nudge_dialog_cb = NULL; + mac->sme.twt_ack_comp_cb = NULL; + sme_release_global_lock(&mac->sme); + + sme_debug("TWT: callbacks Initialized"); + } + + return status; +} + +QDF_STATUS sme_register_twt_callbacks(mac_handle_t mac_handle, + struct twt_callbacks *twt_cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.twt_enable_cb = twt_cb->twt_enable_cb; + mac->sme.twt_add_dialog_cb = twt_cb->twt_add_dialog_cb; + mac->sme.twt_del_dialog_cb = twt_cb->twt_del_dialog_cb; + mac->sme.twt_pause_dialog_cb = twt_cb->twt_pause_dialog_cb; + mac->sme.twt_resume_dialog_cb = twt_cb->twt_resume_dialog_cb; + mac->sme.twt_disable_cb = twt_cb->twt_disable_cb; + mac->sme.twt_notify_cb = twt_cb->twt_notify_cb; + mac->sme.twt_nudge_dialog_cb = twt_cb->twt_nudge_dialog_cb; + mac->sme.twt_ack_comp_cb = twt_cb->twt_ack_comp_cb; + sme_release_global_lock(&mac->sme); + sme_debug("TWT: callbacks registered"); + } + + return status; +} + +QDF_STATUS sme_add_dialog_cmd(mac_handle_t mac_handle, + twt_add_dialog_cb twt_add_dialog_cb, + struct wmi_twt_add_dialog_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg twt_msg = {0}; + bool is_twt_cmd_in_progress, is_twt_notify_in_progress; + bool usr_cfg_ps_enable; + QDF_STATUS status; + void *wma_handle; + struct wmi_twt_add_dialog_param *cmd_params; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + SME_ENTER(); + + usr_cfg_ps_enable = mlme_get_user_ps(mac->psoc, twt_params->vdev_id); + if (!usr_cfg_ps_enable) { + sme_debug("Power save mode disable"); + return QDF_STATUS_E_AGAIN; + } + + is_twt_notify_in_progress = mlme_is_twt_notify_in_progress( + mac->psoc, twt_params->vdev_id); + + if (is_twt_notify_in_progress) { + sme_debug("Waiting for TWT Notify"); + return QDF_STATUS_E_BUSY; + } + + is_twt_cmd_in_progress = mlme_twt_is_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_ANY, &active_cmd); + if (is_twt_cmd_in_progress) { + sme_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + /*bodyptr should be freeable*/ + cmd_params = qdf_mem_malloc(sizeof(*cmd_params)); + if (!cmd_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to register add dialog callback"); + qdf_mem_free(cmd_params); + return status; + } + + /* + * Add the dialog id to TWT context to drop back to back + * commands + */ + mlme_add_twt_session(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + mlme_set_twt_command_in_progress(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_SETUP); + + /* Serialize the req through MC thread */ + mac->sme.twt_add_dialog_cb = twt_add_dialog_cb; + mac->sme.twt_ack_context_cb = context; + twt_msg.bodyptr = cmd_params; + twt_msg.type = WMA_TWT_ADD_DIALOG_REQUEST; + sme_release_global_lock(&mac->sme); + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &twt_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Post twt add dialog msg fail"); + mlme_set_twt_command_in_progress(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NONE); + mlme_init_twt_context(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + qdf_mem_free(cmd_params); + } + + SME_EXIT(); + return status; +} + +QDF_STATUS sme_del_dialog_cmd(mac_handle_t mac_handle, + twt_del_dialog_cb del_dialog_cb, + struct wmi_twt_del_dialog_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg twt_msg = {0}; + bool is_twt_cmd_in_progress; + QDF_STATUS status; + void *wma_handle; + struct wmi_twt_del_dialog_param *cmd_params; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + SME_ENTER(); + + is_twt_cmd_in_progress = + mlme_twt_is_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_SETUP, &active_cmd) || + mlme_twt_is_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_TERMINATE, + &active_cmd); + if (is_twt_cmd_in_progress) { + sme_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + /*bodyptr should be freeable*/ + cmd_params = qdf_mem_malloc(sizeof(*cmd_params)); + if (!cmd_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to acquire SME global lock"); + qdf_mem_free(cmd_params); + return status; + } + + mlme_set_twt_command_in_progress(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_TERMINATE); + + /* Serialize the req through MC thread */ + mac->sme.twt_del_dialog_cb = del_dialog_cb; + mac->sme.twt_ack_context_cb = context; + twt_msg.bodyptr = cmd_params; + twt_msg.type = WMA_TWT_DEL_DIALOG_REQUEST; + sme_release_global_lock(&mac->sme); + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &twt_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Post twt del dialog msg fail"); + mlme_set_twt_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NONE); + qdf_mem_free(cmd_params); + } + + SME_EXIT(); + return status; +} + +QDF_STATUS sme_sap_del_dialog_cmd(mac_handle_t mac_handle, + twt_del_dialog_cb del_dialog_cb, + struct wmi_twt_del_dialog_param *twt_params) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg twt_msg = {0}; + bool is_twt_cmd_in_progress; + QDF_STATUS status; + void *wma_handle; + struct wmi_twt_del_dialog_param *cmd_params; + + SME_ENTER(); + + is_twt_cmd_in_progress = + sme_sap_twt_is_command_in_progress(mac->psoc, + twt_params->vdev_id, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_TERMINATE); + + if (is_twt_cmd_in_progress) { + sme_debug("Already TWT teardown command is in progress"); + return QDF_STATUS_E_PENDING; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + /* bodyptr should be freeable */ + cmd_params = qdf_mem_malloc(sizeof(*cmd_params)); + if (!cmd_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(cmd_params); + sme_err("Failed to acquire SME global lock"); + return status; + } + + /* + * Add the dialog id to TWT context to drop back to back + * commands + */ + sme_sap_add_twt_session(mac->psoc, twt_params->vdev_id, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + + sme_sap_set_twt_command_in_progress(mac->psoc, twt_params->vdev_id, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_TERMINATE); + + /* Serialize the req through MC thread */ + mac->sme.twt_del_dialog_cb = del_dialog_cb; + twt_msg.bodyptr = cmd_params; + twt_msg.type = WMA_TWT_DEL_DIALOG_REQUEST; + sme_release_global_lock(&mac->sme); + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &twt_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Post twt del dialog msg fail"); + sme_sap_set_twt_command_in_progress(mac->psoc, + twt_params->vdev_id, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NONE); + sme_sap_init_twt_context(mac->psoc, + twt_params->vdev_id, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id); + qdf_mem_free(cmd_params); + } + + SME_EXIT(); + return status; +} + +QDF_STATUS +sme_pause_dialog_cmd(mac_handle_t mac_handle, + struct wmi_twt_pause_dialog_cmd_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct wmi_twt_pause_dialog_cmd_param *cmd_params; + struct scheduler_msg twt_msg = {0}; + bool is_twt_cmd_in_progress; + QDF_STATUS status; + void *wma_handle; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + SME_ENTER(); + + is_twt_cmd_in_progress = mlme_twt_is_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_ANY, &active_cmd); + if (is_twt_cmd_in_progress) { + sme_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + /*bodyptr should be freeable*/ + cmd_params = qdf_mem_malloc(sizeof(*cmd_params)); + if (!cmd_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to register pause dialog callback"); + qdf_mem_free(cmd_params); + return status; + } + + mlme_set_twt_command_in_progress(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_SUSPEND); + + /* Serialize the req through MC thread */ + mac->sme.twt_ack_context_cb = context; + twt_msg.bodyptr = cmd_params; + twt_msg.type = WMA_TWT_PAUSE_DIALOG_REQUEST; + sme_release_global_lock(&mac->sme); + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &twt_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Post twt pause dialog msg fail"); + mlme_set_twt_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NONE); + qdf_mem_free(cmd_params); + } + + SME_EXIT(); + return status; +} + +QDF_STATUS +sme_nudge_dialog_cmd(mac_handle_t mac_handle, + struct wmi_twt_nudge_dialog_cmd_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct wmi_twt_nudge_dialog_cmd_param *cmd_params; + struct scheduler_msg twt_msg = {0}; + bool is_twt_cmd_in_progress; + QDF_STATUS status; + void *wma_handle; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + SME_ENTER(); + + is_twt_cmd_in_progress = mlme_twt_is_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_ANY, &active_cmd); + if (is_twt_cmd_in_progress) { + sme_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + sme_err("wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /*bodyptr should be freeable*/ + cmd_params = qdf_mem_malloc(sizeof(*cmd_params)); + if (!cmd_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to register nudge dialog callback"); + qdf_mem_free(cmd_params); + return status; + } + + mlme_set_twt_command_in_progress(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NUDGE); + + /* Serialize the req through MC thread */ + mac->sme.twt_ack_context_cb = context; + twt_msg.bodyptr = cmd_params; + twt_msg.type = WMA_TWT_NUDGE_DIALOG_REQUEST; + sme_release_global_lock(&mac->sme); + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &twt_msg); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Post twt nudge dialog msg fail"); + mlme_set_twt_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NONE); + qdf_mem_free(cmd_params); + } + + SME_EXIT(); + return status; +} + +QDF_STATUS +sme_resume_dialog_cmd(mac_handle_t mac_handle, + struct wmi_twt_resume_dialog_cmd_param *twt_params, + void *context) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct wmi_twt_resume_dialog_cmd_param *cmd_params; + struct scheduler_msg twt_msg = {0}; + bool is_twt_cmd_in_progress; + QDF_STATUS status; + void *wma_handle; + enum wlan_twt_commands active_cmd = WLAN_TWT_NONE; + + SME_ENTER(); + + is_twt_cmd_in_progress = mlme_twt_is_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_ANY, &active_cmd); + if (is_twt_cmd_in_progress) { + sme_debug("Already TWT command:%d is in progress", active_cmd); + return QDF_STATUS_E_PENDING; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + /*bodyptr should be freeable*/ + cmd_params = qdf_mem_malloc(sizeof(*cmd_params)); + if (!cmd_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(cmd_params, twt_params, sizeof(*cmd_params)); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to register resume dialog callback"); + qdf_mem_free(cmd_params); + return status; + } + + mlme_set_twt_command_in_progress(mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_RESUME); + + /* Serialize the req through MC thread */ + mac->sme.twt_ack_context_cb = context; + twt_msg.bodyptr = cmd_params; + twt_msg.type = WMA_TWT_RESUME_DIALOG_REQUEST; + sme_release_global_lock(&mac->sme); + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &twt_msg); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Post twt resume dialog msg fail"); + mlme_set_twt_command_in_progress( + mac->psoc, + (struct qdf_mac_addr *)twt_params->peer_macaddr, + twt_params->dialog_id, WLAN_TWT_NONE); + qdf_mem_free(cmd_params); + } + + SME_EXIT(); + return status; +} +#endif + +QDF_STATUS sme_set_smps_cfg(uint32_t vdev_id, uint32_t param_id, + uint32_t param_val) +{ + return wma_configure_smps_params(vdev_id, param_id, param_val); +} + +QDF_STATUS sme_set_reorder_timeout(mac_handle_t mac_handle, + struct sir_set_rx_reorder_timeout_val *req) +{ + QDF_STATUS status; + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + status = wma_set_rx_reorder_timeout_val(wma_handle, req); + + return status; +} + +QDF_STATUS sme_set_rx_set_blocksize(mac_handle_t mac_handle, + struct sir_peer_set_rx_blocksize *req) +{ + QDF_STATUS status; + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + status = wma_set_rx_blocksize(wma_handle, req); + + return status; +} + +int sme_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) +{ + return wma_cli_set_command(vdev_id, param_id, sval, vpdev); +} + +int sme_set_enable_mem_deep_sleep(mac_handle_t mac_handle, int vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + return wma_cli_set_command(vdev_id, wmi_pdev_param_hyst_en, + mac_ctx->mlme_cfg->gen.memory_deep_sleep, + PDEV_CMD); +} + +int sme_set_cck_tx_fir_override(mac_handle_t mac_handle, int vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + return wma_cli_set_command(vdev_id, + wmi_pdev_param_enable_cck_txfir_override, + mac_ctx->mlme_cfg->gen.cck_tx_fir_override, + PDEV_CMD); +} + +QDF_STATUS sme_set_bt_activity_info_cb(mac_handle_t mac_handle, + bt_activity_info_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.bt_activity_info_cb = cb; + sme_release_global_lock(&mac->sme); + sme_debug("bt activity info callback set"); + } + + return status; +} + +QDF_STATUS sme_get_chain_rssi(mac_handle_t mac_handle, + struct get_chain_rssi_req_params *input, + get_chain_rssi_callback callback, + void *context) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + tp_wma_handle wma_handle; + + SME_ENTER(); + + if (!input) { + sme_err("Invalid req params"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx->sme.get_chain_rssi_cb = callback; + mac_ctx->sme.get_chain_rssi_context = context; + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + wma_get_chain_rssi(wma_handle, input); + + SME_EXIT(); + return status; +} + +QDF_STATUS sme_process_msg_callback(struct mac_context *mac, + struct scheduler_msg *msg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!msg) { + sme_err("Empty message for SME Msg callback"); + return status; + } + status = sme_process_msg(mac, msg); + return status; +} + +void sme_display_disconnect_stats(mac_handle_t mac_handle, uint8_t session_id) +{ + struct csr_roam_session *session; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("%s Invalid session id: %d", __func__, session_id); + return; + } + + session = CSR_GET_SESSION(mac_ctx, session_id); + if (!session) { + sme_err("%s Failed to get session for id: %d", + __func__, session_id); + return; + } + + sme_nofl_info("Total No. of Disconnections: %d", + session->disconnect_stats.disconnection_cnt); + + sme_nofl_info("No. of Disconnects Triggered by Application: %d", + session->disconnect_stats.disconnection_by_app); + + sme_nofl_info("No. of Disassoc Sent by Peer: %d", + session->disconnect_stats.disassoc_by_peer); + + sme_nofl_info("No. of Deauth Sent by Peer: %d", + session->disconnect_stats.deauth_by_peer); + + sme_nofl_info("No. of Disconnections due to Beacon Miss: %d", + session->disconnect_stats.bmiss); + + sme_nofl_info("No. of Disconnections due to Peer Kickout: %d", + session->disconnect_stats.peer_kickout); +} + +#ifdef FEATURE_WLAN_DYNAMIC_CVM + /** + * sme_set_vc_mode_config() - Set voltage corner config to FW + * @bitmap: Bitmap that refers to voltage corner config with + * different phymode and bw configuration + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_vc_mode_config(uint32_t vc_bitmap) +{ + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (QDF_STATUS_SUCCESS != + wma_set_vc_mode_config(wma_handle, vc_bitmap)) { + sme_err("Failed to set Voltage Control config to FW"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * sme_set_bmiss_bcnt() - set bmiss config parameters + * @vdev_id: virtual device for the command + * @first_cnt: bmiss first value + * @final_cnt: bmiss final value + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_set_bmiss_bcnt(uint32_t vdev_id, uint32_t first_cnt, + uint32_t final_cnt) +{ + return wma_config_bmiss_bcnt_params(vdev_id, first_cnt, final_cnt); +} + +QDF_STATUS sme_send_limit_off_channel_params(mac_handle_t mac_handle, + uint8_t vdev_id, + bool is_tos_active, + uint32_t max_off_chan_time, + uint32_t rest_time, + bool skip_dfs_chan) +{ + struct sir_limit_off_chan *cmd; + struct scheduler_msg msg = {0}; + + cmd = qdf_mem_malloc(sizeof(*cmd)); + if (!cmd) + return QDF_STATUS_E_NOMEM; + + cmd->vdev_id = vdev_id; + cmd->is_tos_active = is_tos_active; + cmd->max_off_chan_time = max_off_chan_time; + cmd->rest_time = rest_time; + cmd->skip_dfs_chans = skip_dfs_chan; + + msg.type = WMA_SET_LIMIT_OFF_CHAN; + msg.reserved = 0; + msg.bodyptr = cmd; + + if (!QDF_IS_STATUS_SUCCESS(scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg))) { + sme_err("Not able to post WMA_SET_LIMIT_OFF_CHAN to WMA"); + qdf_mem_free(cmd); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +uint32_t sme_unpack_rsn_ie(mac_handle_t mac_handle, uint8_t *buf, + uint8_t buf_len, tDot11fIERSN *rsn_ie, + bool append_ie) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + return dot11f_unpack_ie_rsn(mac_ctx, buf, buf_len, rsn_ie, append_ie); +} + +QDF_STATUS sme_unpack_assoc_rsp(mac_handle_t mac_handle, + struct wlan_cm_connect_resp *rsp, + struct sDot11fAssocResponse *assoc_resp) +{ + QDF_STATUS status; + uint8_t ies_offset = WLAN_ASSOC_RSP_IES_OFFSET; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + status = dot11f_parse_assoc_response(mac_ctx, + rsp->connect_ies.assoc_rsp.ptr, + rsp->connect_ies.assoc_rsp.len, + assoc_resp, false); + + lim_strip_and_decode_eht_cap(rsp->connect_ies.assoc_rsp.ptr + ies_offset, + rsp->connect_ies.assoc_rsp.len - ies_offset, + &assoc_resp->eht_cap, + assoc_resp->he_cap, + rsp->freq); + return status; +} + +void sme_get_hs20vendor_ie(mac_handle_t mac_handle, uint8_t *frame, + uint32_t frame_len, + struct sDot11fIEhs20vendor_ie *hs20vendor_ie) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct sSirProbeRespBeacon *beacon_probe_resp = + qdf_mem_malloc(sizeof(struct sSirProbeRespBeacon)); + + if (!beacon_probe_resp) + return; + + sir_parse_beacon_ie(mac_ctx, beacon_probe_resp, frame, frame_len); + + qdf_mem_copy(hs20vendor_ie, &beacon_probe_resp->hs20vendor_ie, + sizeof(struct sDot11fIEhs20vendor_ie)); + + qdf_mem_free(beacon_probe_resp); +} + +void sme_add_qcn_ie(mac_handle_t mac_handle, uint8_t *ie_data, + uint16_t *ie_len) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + static const uint8_t qcn_ie[] = {WLAN_ELEMID_VENDOR, 8, + 0x8C, 0xFD, 0xF0, 0x1, + QCN_IE_VERSION_SUBATTR_ID, + QCN_IE_VERSION_SUBATTR_DATA_LEN, + QCN_IE_VERSION_SUPPORTED, + QCN_IE_SUBVERSION_SUPPORTED}; + + if (!mac_ctx->mlme_cfg->sta.qcn_ie_support) { + sme_debug("QCN IE is not supported"); + return; + } + + if (((*ie_len) + sizeof(qcn_ie)) > MAX_DEFAULT_SCAN_IE_LEN) { + sme_err("IE buffer not enough for QCN IE"); + return; + } + + qdf_mem_copy(ie_data + (*ie_len), qcn_ie, sizeof(qcn_ie)); + (*ie_len) += sizeof(qcn_ie); +} + +#ifdef FEATURE_BSS_TRANSITION +/** + * sme_get_status_for_candidate() - Get bss transition status for candidate + * @mac_handle: Opaque handle to the global MAC context + * @conn_bss: connected bss scan entry + * @candidate_bss: candidate bss scan entry + * @info: candiadate bss information + * @trans_reason: transition reason code + * @is_bt_in_progress: bt activity indicator + * + * Return : true if candidate is rejected and reject reason is filled + * @info->status. Otherwise returns false. + */ +static bool sme_get_status_for_candidate(mac_handle_t mac_handle, + struct scan_cache_entry *conn_bss, + struct scan_cache_entry *candidate_bss, + struct bss_candidate_info *info, + uint8_t trans_reason, + bool is_bt_in_progress) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_mlme_mbo *mbo_cfg; + int8_t current_rssi_mcc_thres; + uint32_t bss_chan_freq, conn_bss_chan_freq; + bool bss_chan_safe, conn_bss_chan_safe; + + if (!(mac_ctx->mlme_cfg)) { + pe_err("mlme cfg is NULL"); + return false; + } + mbo_cfg = &mac_ctx->mlme_cfg->mbo_cfg; + + /* + * Low RSSI based rejection + * If candidate rssi is less than mbo_candidate_rssi_thres and connected + * bss rssi is greater than mbo_current_rssi_thres, then reject the + * candidate with MBO reason code 4. + */ + if ((candidate_bss->rssi_raw < mbo_cfg->mbo_candidate_rssi_thres) && + (conn_bss->rssi_raw > mbo_cfg->mbo_current_rssi_thres)) { + sme_err("Candidate BSS " QDF_MAC_ADDR_FMT " has LOW RSSI(%d), hence reject", + QDF_MAC_ADDR_REF(candidate_bss->bssid.bytes), + candidate_bss->rssi_raw); + info->status = QCA_STATUS_REJECT_LOW_RSSI; + return true; + } + + if (trans_reason == MBO_TRANSITION_REASON_LOAD_BALANCING || + trans_reason == MBO_TRANSITION_REASON_TRANSITIONING_TO_PREMIUM_AP) { + bss_chan_freq = candidate_bss->channel.chan_freq; + conn_bss_chan_freq = conn_bss->channel.chan_freq; + /* + * MCC rejection + * If moving to candidate's channel will result in MCC scenario + * and the rssi of connected bss is greater than + * mbo_current_rssi_mss_thres, then reject the candidate with + * MBO reason code 3. + */ + current_rssi_mcc_thres = mbo_cfg->mbo_current_rssi_mcc_thres; + if ((conn_bss->rssi_raw > current_rssi_mcc_thres) && + csr_is_mcc_channel(mac_ctx, bss_chan_freq)) { + sme_err("Candidate BSS " QDF_MAC_ADDR_FMT " causes MCC, hence reject", + QDF_MAC_ADDR_REF(candidate_bss->bssid.bytes)); + info->status = + QCA_STATUS_REJECT_INSUFFICIENT_QOS_CAPACITY; + return true; + } + + /* + * BT coex rejection + * If AP is trying to move the client from 5G to 2.4G and moving + * to 2.4G will result in BT coex and candidate channel rssi is + * less than mbo_candidate_rssi_btc_thres, then reject the + * candidate with MBO reason code 2. + */ + if (WLAN_REG_IS_5GHZ_CH_FREQ(conn_bss_chan_freq) && + WLAN_REG_IS_24GHZ_CH_FREQ(bss_chan_freq) && + is_bt_in_progress && + (candidate_bss->rssi_raw < mbo_cfg->mbo_candidate_rssi_btc_thres)) { + sme_err("Candidate BSS " QDF_MAC_ADDR_FMT " causes BT coex, hence reject", + QDF_MAC_ADDR_REF(candidate_bss->bssid.bytes)); + info->status = + QCA_STATUS_REJECT_EXCESSIVE_DELAY_EXPECTED; + return true; + } + + /* + * LTE coex rejection + * If moving to candidate's channel can cause LTE coex, then + * reject the candidate with MBO reason code 5. + */ + conn_bss_chan_safe = policy_mgr_is_safe_channel( + mac_ctx->psoc, conn_bss_chan_freq); + bss_chan_safe = policy_mgr_is_safe_channel( + mac_ctx->psoc, bss_chan_freq); + + if (conn_bss_chan_safe && !bss_chan_safe) { + sme_err("High interference expected if transitioned to BSS " + QDF_MAC_ADDR_FMT " hence reject", + QDF_MAC_ADDR_REF(candidate_bss->bssid.bytes)); + info->status = + QCA_STATUS_REJECT_HIGH_INTERFERENCE; + return true; + } + } + + return false; +} + +QDF_STATUS sme_get_bss_transition_status(mac_handle_t mac_handle, + uint8_t transition_reason, + struct qdf_mac_addr *bssid, + struct bss_candidate_info *info, + uint16_t n_candidates, + bool is_bt_in_progress) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t i; + qdf_list_t *bssid_list = NULL, *candidate_list = NULL; + struct scan_cache_node *conn_bss = NULL, *candidate_bss = NULL; + qdf_list_node_t *cur_lst = NULL; + + if (!n_candidates || !info) { + sme_err("No candidate info available"); + return QDF_STATUS_E_INVAL; + } + + /* Get the connected BSS descriptor */ + status = csr_scan_get_result_for_bssid(mac_ctx, bssid, &bssid_list); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("connected BSS: " QDF_MAC_ADDR_FMT " not present in scan db", + QDF_MAC_ADDR_REF(bssid->bytes)); + goto purge; + } + qdf_list_peek_front(bssid_list, &cur_lst); + if (!cur_lst) { + sme_err("Failed to peek connected BSS : " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid->bytes)); + goto purge; + } + + conn_bss = + qdf_container_of(cur_lst, struct scan_cache_node, node); + + for (i = 0; i < n_candidates; i++) { + /* Get candidate BSS descriptors */ + status = csr_scan_get_result_for_bssid(mac_ctx, &info[i].bssid, + &candidate_list); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("BSS " QDF_MAC_ADDR_FMT " not present in scan db", + QDF_MAC_ADDR_REF(info[i].bssid.bytes)); + info[i].status = QCA_STATUS_REJECT_UNKNOWN; + continue; + } + cur_lst = NULL; + qdf_list_peek_front(candidate_list, &cur_lst); + if (!cur_lst) { + sme_err("Failed to peek candidate: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(info[i].bssid.bytes)); + goto next; + } + + candidate_bss = + qdf_container_of(cur_lst, struct scan_cache_node, node); + if (!sme_get_status_for_candidate(mac_handle, + conn_bss->entry, + candidate_bss->entry, + &info[i], transition_reason, + is_bt_in_progress)) { + /* + * If status is not over written, it means it is a + * candidate for accept. + */ + info[i].status = QCA_STATUS_ACCEPT; + } +next: + wlan_scan_purge_results(candidate_list); + candidate_list = NULL; + } + + /* success */ + status = QDF_STATUS_SUCCESS; + +purge: + if (bssid_list) + wlan_scan_purge_results(bssid_list); + if (candidate_list) + wlan_scan_purge_results(candidate_list); + + return status; +} +#endif /* FEATURE_BSS_TRANSITION */ + +bool sme_is_conn_state_connected(mac_handle_t mac_handle, uint8_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + return csr_is_conn_state_connected(mac_ctx, session_id); +} + +int16_t sme_get_oper_chan_freq(struct wlan_objmgr_vdev *vdev) +{ + uint8_t vdev_id; + struct csr_roam_session *session; + struct mac_context *mac_ctx; + mac_handle_t mac_handle; + + if (!vdev) { + sme_err("Invalid vdev id is passed"); + return 0; + } + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + return 0; + + mac_ctx = MAC_CONTEXT(mac_handle); + vdev_id = wlan_vdev_get_id(vdev); + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("Invalid vdev id is passed"); + return 0; + } + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + return wlan_get_operation_chan_freq(vdev); +} + +enum phy_ch_width sme_get_oper_ch_width(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_channel *des_chan; + + if (!vdev) { + sme_err("Invalid vdev id is passed"); + return CH_WIDTH_INVALID; + } + + des_chan = wlan_vdev_mlme_get_des_chan(vdev); + if (!des_chan) { + sme_debug("NULL des_chan"); + return CH_WIDTH_INVALID; + } + + return des_chan->ch_width; + +} + +int sme_get_sec20chan_freq_mhz(struct wlan_objmgr_vdev *vdev, + uint16_t *sec20chan_freq) +{ + uint8_t vdev_id; + + vdev_id = wlan_vdev_get_id(vdev); + /* Need to extend */ + return 0; +} + +#ifdef WLAN_FEATURE_SAE +QDF_STATUS sme_handle_sae_msg(mac_handle_t mac_handle, + uint8_t session_id, + uint8_t sae_status, + struct qdf_mac_addr peer_mac_addr, + const uint8_t *pmkid) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct sir_sae_msg *sae_msg; + struct scheduler_msg sch_msg = {0}; + struct wmi_roam_auth_status_params *params; + struct csr_roam_session *csr_session; + enum QDF_OPMODE opmode; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + csr_session = CSR_GET_SESSION(mac, session_id); + if (!csr_session) { + sme_err("session %d not found", session_id); + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + + /* Update the status to SME in below cases + * 1. SAP mode: Always + * 2. STA mode: When the device is not in joined state + * + * If the device is in joined state, send the status to WMA which + * is meant for roaming. + */ + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, session_id); + if ((opmode == QDF_SAP_MODE) || (opmode == QDF_P2P_GO_MODE) || + !CSR_IS_ROAM_JOINED(mac, session_id)) { + sae_msg = qdf_mem_malloc(sizeof(*sae_msg)); + if (!sae_msg) { + qdf_status = QDF_STATUS_E_NOMEM; + goto error; + } + + sae_msg->message_type = eWNI_SME_SEND_SAE_MSG; + sae_msg->length = sizeof(*sae_msg); + sae_msg->vdev_id = session_id; + sae_msg->sae_status = sae_status; + sae_msg->result_code = eSIR_SME_AUTH_REFUSED; + qdf_mem_copy(sae_msg->peer_mac_addr, + peer_mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + qdf_mem_zero(sae_msg->pmkid, PMKID_LEN); + if (pmkid) + qdf_mem_copy(sae_msg->pmkid, pmkid, PMKID_LEN); + sme_debug("SAE: sae_status %d vdev_id %d Peer: " + QDF_MAC_ADDR_FMT, sae_msg->sae_status, + sae_msg->vdev_id, + QDF_MAC_ADDR_REF(sae_msg->peer_mac_addr)); + + sch_msg.type = eWNI_SME_SEND_SAE_MSG; + sch_msg.bodyptr = sae_msg; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + &sch_msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + qdf_mem_free(sae_msg); + goto error; + } + } else { + /* + * For WPA3 SAE roaming, external auth offload is enabled. The + * firmware will send preauth start event after candidate + * selection. The supplicant will perform the SAE authentication + * and will send the auth status, PMKID in the external auth + * cmd. + * + * csr roam state is CSR_ROAM_STATE_JOINED. So this SAE + * external auth event is for wpa3 roam pre-auth offload. + * + * Post the preauth status to WMA. + */ + params = qdf_mem_malloc(sizeof(*params)); + if (!params) { + qdf_status = QDF_STATUS_E_NOMEM; + goto error; + } + + params->vdev_id = session_id; + params->preauth_status = sae_status; + qdf_copy_macaddr(¶ms->bssid, &peer_mac_addr); + + qdf_mem_zero(params->pmkid, PMKID_LEN); + if (pmkid) + qdf_mem_copy(params->pmkid, pmkid, PMKID_LEN); + + sch_msg.type = WMA_ROAM_PRE_AUTH_STATUS; + sch_msg.bodyptr = params; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &sch_msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("WMA_ROAM_PRE_AUTH_STATUS cmd posting failed"); + qdf_mem_free(params); + } + } +error: + sme_release_global_lock(&mac->sme); + + return qdf_status; +} +#endif + +bool sme_is_sta_key_exchange_in_progress(mac_handle_t mac_handle, + uint8_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid session id: %d", session_id); + return false; + } + + return CSR_IS_WAIT_FOR_KEY(mac_ctx, session_id); +} + +bool sme_validate_channel_list(mac_handle_t mac_handle, + uint32_t *chan_freq_list, + uint8_t num_channels) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t i = 0; + uint8_t j; + bool found; + struct csr_channel *ch_lst_info = &mac_ctx->scan.base_channels; + + if (!chan_freq_list || !num_channels) { + sme_err("Chan list empty %pK or num_channels is 0", + chan_freq_list); + return false; + } + + while (i < num_channels) { + found = false; + for (j = 0; j < ch_lst_info->numChannels; j++) { + if (ch_lst_info->channel_freq_list[j] == + chan_freq_list[i]) { + found = true; + break; + } + } + + if (!found) { + sme_debug("Invalid channel %d", chan_freq_list[i]); + return false; + } + + i++; + } + + return true; +} + +void sme_set_pmf_wep_cfg(mac_handle_t mac_handle, uint8_t pmf_wep) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->is_usr_cfg_pmf_wep = pmf_wep; +} + +void sme_set_cfg_disable_tx(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + int ret_val; + + sme_debug("Block Tx %d", val); + if (val) { + if (mac->sme.tx_queue_cb) { + sme_debug("Blocking the Tx queue"); + mac->sme.tx_queue_cb(mac->hdd_handle, vdev_id, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + } else { + if (mac->sme.tx_queue_cb) { + sme_debug("Enable the Tx queue"); + mac->sme.tx_queue_cb(mac->hdd_handle, vdev_id, + WLAN_START_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + } + } + + ret_val = wma_cli_set_command(vdev_id, + wmi_vdev_param_prohibit_data_mgmt, + val, VDEV_CMD); + if (ret_val) + sme_err("Failed to set firmware, errno %d", ret_val); + + mac->usr_cfg_disable_rsp_tx = val; +} + +void sme_set_amsdu(mac_handle_t mac_handle, bool enable) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + mac_ctx->is_usr_cfg_amsdu_enabled = enable; +} + +void sme_set_bss_max_idle_period(mac_handle_t mac_handle, uint16_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + mac_ctx->mlme_cfg->sta.bss_max_idle_period = cfg_val; +} + +#ifdef WLAN_FEATURE_11BE +static void sme_set_eht_mcs_info(struct mac_context *mac_ctx) +{ + if (mac_ctx->usr_eht_testbed_cfg) { + mac_ctx->eht_cap_2g.bw_le_80_rx_max_nss_for_mcs_0_to_9 = 1; + mac_ctx->eht_cap_2g.bw_le_80_tx_max_nss_for_mcs_0_to_9 = 1; + } +} +#else +#ifdef WLAN_FEATURE_11AX +static void sme_set_eht_mcs_info(struct mac_context *mac_ctx) +{ +} +#endif +#endif + +#ifdef WLAN_FEATURE_11AX +void sme_set_he_bw_cap(mac_handle_t mac_handle, uint8_t vdev_id, + enum eSirMacHTChannelWidth chwidth) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_debug("No session for id %d", vdev_id); + return; + } + sme_debug("Config HE caps for BW %d", chwidth); + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_0 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_1 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_2 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_3 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_4 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_5 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_6 = 0; + + mac_ctx->he_cap_2g.chan_width_0 = 0; + mac_ctx->he_cap_2g.chan_width_1 = 0; + mac_ctx->he_cap_2g.chan_width_2 = 0; + mac_ctx->he_cap_2g.chan_width_3 = 0; + mac_ctx->he_cap_2g.chan_width_4 = 0; + mac_ctx->he_cap_2g.chan_width_5 = 0; + mac_ctx->he_cap_2g.chan_width_6 = 0; + + mac_ctx->he_cap_5g.chan_width_0 = 0; + mac_ctx->he_cap_5g.chan_width_1 = 0; + mac_ctx->he_cap_5g.chan_width_2 = 0; + mac_ctx->he_cap_5g.chan_width_3 = 0; + mac_ctx->he_cap_5g.chan_width_4 = 0; + mac_ctx->he_cap_5g.chan_width_5 = 0; + mac_ctx->he_cap_5g.chan_width_6 = 0; + + switch (chwidth) { + case eHT_CHANNEL_WIDTH_160MHZ: + case eHT_CHANNEL_WIDTH_320MHZ: + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_1 = 1; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_2 = 1; + *((uint16_t *) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_160) = + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_he_mcs_map_lt_80; + *((uint16_t *) + mac_ctx->he_cap_5g.rx_he_mcs_map_160) = + mac_ctx->he_cap_5g.rx_he_mcs_map_lt_80; + *((uint16_t *) + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_160) = + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_he_mcs_map_lt_80; + *((uint16_t *) + mac_ctx->he_cap_5g.tx_he_mcs_map_160) = + mac_ctx->he_cap_5g.tx_he_mcs_map_lt_80; + mac_ctx->he_cap_5g.chan_width_1 = 1; + mac_ctx->he_cap_5g.chan_width_2 = 1; + fallthrough; + case eHT_CHANNEL_WIDTH_80MHZ: + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_1 = 1; + mac_ctx->he_cap_5g.chan_width_1 = 1; + fallthrough; + case eHT_CHANNEL_WIDTH_40MHZ: + sme_set_eht_mcs_info(mac_ctx); + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_0 = 1; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_1 = 1; + mac_ctx->he_cap_2g.chan_width_0 = 1; + mac_ctx->he_cap_5g.chan_width_1 = 1; + fallthrough; + case eHT_CHANNEL_WIDTH_20MHZ: + break; + default: + sme_debug("Config BW %d not handled", chwidth); + } + csr_update_session_he_cap(mac_ctx, session); +} + +void sme_check_enable_ru_242_tx(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + int ret; + + sme_debug("Config VDEV for RU 242 Tx, usr cfg %d", + mac_ctx->usr_cfg_ru_242_tone_tx); + if (mac_ctx->usr_cfg_ru_242_tone_tx) { + ret = wma_cli_set_command(vdev_id, wmi_vdev_param_chwidth, + 0, VDEV_CMD); + if (ret) + sme_err("Failed to set VDEV BW to 20MHz"); + } +} + +void sme_set_ru_242_tone_tx_cfg(mac_handle_t mac_handle, uint8_t cfg_val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + mac_ctx->usr_cfg_ru_242_tone_tx = cfg_val; +} + +void sme_set_he_testbed_def(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + QDF_STATUS status; + uint32_t prevent_pm[] = {29, 1}; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_debug("No session for id %d", vdev_id); + return; + } + sme_debug("set HE testbed defaults"); + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.htc_he = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.amsdu_in_ampdu = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.twt_request = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.broadcast_twt = 0; + mac_ctx->mlme_cfg->twt_cfg.disable_btwt_usr_cfg = true; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_ctrl_frame = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.omi_a_ctrl = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_ppdu_20_in_160_80p80Mhz = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_ppdu_20_in_40Mhz_2G = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_ppdu_80_in_160_80p80Mhz = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.dcm_enc_tx = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.dcm_enc_rx = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ul_mu = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.max_nc = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.trigger_frm_mac_pad = + QCA_WLAN_HE_16US_OF_PROCESS_TIME; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.flex_twt_sched = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ofdma_ra = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_4x_ltf_3200_gi_ndp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.qtp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.bsrp_ampdu_aggr = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.a_bqr = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_sub_ch_sel_tx_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ndp_feedback_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ops_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.srp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.power_boost = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.num_sounding_lt_80 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.num_sounding_gt_80 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.dl_mu_mimo_part_bw = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.non_trig_cqi_feedback = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.tx_1024_qam_lt_242_tone_ru = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_1024_qam_lt_242_tone_ru = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_full_bw_su_he_mu_compress_sigb = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_full_bw_su_he_mu_non_cmpr_sigb = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.su_beamformer = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.multi_tid_aggr_rx_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.multi_tid_aggr_tx_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_dynamic_smps = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.punctured_sounding_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ht_vht_trg_frm_rx_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.su_feedback_tone16 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.mu_feedback_tone16 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.codebook_su = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.codebook_mu = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.ul_2x996_tone_ru_supp = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.beamforming_feedback = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.he_er_su_ppdu = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.dl_mu_mimo_part_bw = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.rx_pream_puncturing = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_0 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_1 = 1; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_2 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_3 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_4 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_5 = 0; + mac_ctx->mlme_cfg->he_caps.dot11_he_cap.chan_width_6 = 0; + csr_update_session_he_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->he_cap_2g, + &mac_ctx->mlme_cfg->he_caps.dot11_he_cap, + sizeof(tDot11fIEhe_cap)); + + mac_ctx->he_cap_2g.chan_width_1 = 0; + ucfg_mlme_set_channel_bonding_24ghz(mac_ctx->psoc, 0); + qdf_mem_copy(&mac_ctx->he_cap_5g, + &mac_ctx->mlme_cfg->he_caps.dot11_he_cap, + sizeof(tDot11fIEhe_cap)); + status = ucfg_mlme_set_enable_bcast_probe_rsp(mac_ctx->psoc, false); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Failed not set enable bcast probe resp info, %d", + status); + status = sme_send_unit_test_cmd(vdev_id, 77, 2, prevent_pm); + if (QDF_STATUS_SUCCESS != status) + sme_err("prevent pm cmd send failed"); + status = wma_cli_set_command(vdev_id, + wmi_vdev_param_enable_bcast_probe_response, + 0, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Failed to set enable bcast probe resp in FW, %d", + status); + + mac_ctx->mlme_cfg->sta.usr_disabled_roaming = true; + mac_ctx->mlme_cfg->sta.bss_max_idle_period = 0; +} + +void sme_reset_he_caps(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + QDF_STATUS status; + uint32_t prevent_pm[] = {29, 0}; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + sme_debug("reset HE caps"); + mac_ctx->mlme_cfg->he_caps.dot11_he_cap = + mac_ctx->mlme_cfg->he_caps.he_cap_orig; + csr_update_session_he_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->he_cap_2g, + &mac_ctx->he_cap_2g_orig, + sizeof(tDot11fIEhe_cap)); + qdf_mem_copy(&mac_ctx->he_cap_5g, + &mac_ctx->he_cap_5g_orig, + sizeof(tDot11fIEhe_cap)); + ucfg_mlme_set_channel_bonding_24ghz(mac_ctx->psoc, 1); + wlan_cm_set_check_6ghz_security(mac_ctx->psoc, true); + status = sme_send_unit_test_cmd(vdev_id, 77, 2, prevent_pm); + + if (QDF_STATUS_SUCCESS != status) + sme_err("prevent PM reset cmd send failed"); + + mac_ctx->mlme_cfg->twt_cfg.disable_btwt_usr_cfg = false; + status = ucfg_mlme_set_enable_bcast_probe_rsp(mac_ctx->psoc, true); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Failed not set enable bcast probe resp info, %d", + status); + + status = wma_cli_set_command(vdev_id, + wmi_vdev_param_enable_bcast_probe_response, + 1, VDEV_CMD); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Failed to set enable bcast probe resp in FW, %d", + status); + mac_ctx->is_usr_cfg_pmf_wep = PMF_CORRECT_KEY; + mac_ctx->mlme_cfg->sta.bss_max_idle_period = + mac_ctx->mlme_cfg->sta.sta_keep_alive_period; + + if (mac_ctx->usr_cfg_disable_rsp_tx) + sme_set_cfg_disable_tx(mac_handle, vdev_id, 0); + mac_ctx->is_usr_cfg_amsdu_enabled = true; + status = wlan_scan_cfg_set_scan_mode_6g(mac_ctx->psoc, + SCAN_MODE_6G_ALL_CHANNEL); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Failed to set scan mode for 6 GHz, %d", status); +} +#endif + +#ifdef WLAN_FEATURE_11BE +void sme_set_mlo_max_links(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + wlan_mlme_set_sta_mlo_conn_max_num(mac_ctx->psoc, val); + wlan_mlme_set_user_set_link_num(mac_ctx->psoc, val); +} + +void sme_set_mlo_max_simultaneous_links(mac_handle_t mac_handle, + uint8_t vdev_id, uint8_t val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + wlan_mlme_set_sta_mlo_simultaneous_links(mac_ctx->psoc, val); +} + +void sme_set_mlo_assoc_link_band(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t val) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + wlan_mlme_set_sta_mlo_conn_band_bmp(mac_ctx->psoc, val); +} + +void sme_set_eht_testbed_def(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + tDot11fIEeht_cap *mlme_eht_cap; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + mlme_eht_cap = &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap; + sme_debug("set EHT caps testbed defaults"); + mlme_eht_cap->epcs_pri_access = 0; + mlme_eht_cap->eht_om_ctl = 0; + mlme_eht_cap->triggered_txop_sharing_mode1 = 0; + mlme_eht_cap->restricted_twt = 0; + mlme_eht_cap->support_320mhz_6ghz = 0; + mlme_eht_cap->partial_bw_mu_mimo = 0; + mlme_eht_cap->su_beamformer = 0; + mlme_eht_cap->su_beamformee = 1; + mlme_eht_cap->bfee_ss_le_80mhz = 3; + mlme_eht_cap->bfee_ss_160mhz = 0; + mlme_eht_cap->bfee_ss_320mhz = 0; + mlme_eht_cap->num_sounding_dim_le_80mhz = 0; + mlme_eht_cap->num_sounding_dim_160mhz = 0; + mlme_eht_cap->num_sounding_dim_320mhz = 0; + mlme_eht_cap->mu_bformer_le_80mhz = 0; + mlme_eht_cap->mu_bformer_160mhz = 0; + mlme_eht_cap->mu_bformer_320mhz = 0; + mlme_eht_cap->partial_bw_dl_mu_mimo = 0; + mlme_eht_cap->ru_242tone_wt_20mhz = 0; + mlme_eht_cap->psr_based_sr = 0; + mlme_eht_cap->triggered_cqi_feedback = 0; + mlme_eht_cap->trig_mu_bforming_partial_bw_feedback = 0; + mlme_eht_cap->trig_su_bforming_feedback = 0; + mlme_eht_cap->cb_sz_7_5_su_feedback = 0; + mlme_eht_cap->cb_sz_4_2_su_feedback = 0; + mlme_eht_cap->ng_16_mu_feedback = 0; + mlme_eht_cap->ng_16_su_feedback = 0; + mlme_eht_cap->ndp_4x_eht_ltf_3dot2_us_gi = 0; + mlme_eht_cap->common_nominal_pkt_padding = 3; + mlme_eht_cap->ppet_present = 0; + mlme_eht_cap->rx_1024_4096_qam_lt_242_tone_ru = 0; + mlme_eht_cap->tx_1024_4096_qam_lt_242_tone_ru = 0; + mlme_eht_cap->non_trig_cqi_feedback = 0; + mlme_eht_cap->max_nc = 0; + mlme_eht_cap->rx_4k_qam_in_wider_bw_dl_ofdma = 0; + mlme_eht_cap->rx_1k_qam_in_wider_bw_dl_ofdma = 0; + mlme_eht_cap->tb_sounding_feedback_rl = 0; + mlme_eht_cap->op_sta_rx_ndp_wider_bw_20mhz = 0; + mlme_eht_cap->eht_dup_6ghz = 0; + mlme_eht_cap->mcs_15 = 0; + mlme_eht_cap->max_num_eht_ltf = 0; + mlme_eht_cap->eht_mu_ppdu_4x_ltf_0_8_us_gi = 0; + mlme_eht_cap->power_boost_factor = 0; + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7 = 1; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7 = 1; + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9 = 1; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9 = 1; + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9 = 1; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9 = 1; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_0_to_9 = 1; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_0_to_9 = 1; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9 = 1; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_0_to_9 = 1; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13 = 0; + + csr_update_session_eht_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->eht_cap_2g, mlme_eht_cap, + sizeof(tDot11fIEeht_cap)); + + mac_ctx->eht_cap_2g.bw_le_80_rx_max_nss_for_mcs_0_to_9 = 0; + mac_ctx->eht_cap_2g.bw_le_80_tx_max_nss_for_mcs_0_to_9 = 0; + + qdf_mem_copy(&mac_ctx->eht_cap_5g, mlme_eht_cap, + sizeof(tDot11fIEeht_cap)); + + mac_ctx->usr_eht_testbed_cfg = true; + mac_ctx->roam.configParam.channelBondingMode24GHz = 0; + wlan_mlme_set_sta_mlo_conn_max_num(mac_ctx->psoc, 1); + ucfg_mlme_set_bss_color_collision_det_sta(mac_ctx->psoc, false); +} + +void sme_set_per_link_ba_mode(mac_handle_t mac_handle, uint8_t val) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + enum QDF_OPMODE op_mode; + uint8_t vdev_id; + int ret_val = 0; + + for (vdev_id = 0; vdev_id < WLAN_MAX_VDEVS; vdev_id++) { + op_mode = wlan_get_opmode_from_vdev_id(mac->pdev, vdev_id); + if (op_mode == QDF_STA_MODE) { + ret_val = wma_cli_set_command( + vdev_id, + wmi_vdev_param_set_ba_mode, + val, VDEV_CMD); + + if (QDF_IS_STATUS_ERROR(ret_val)) + sme_err("BA mode set failed for vdev: %d, ret %d", + vdev_id, ret_val); + else + sme_debug("vdev: %d ba mode: %d param id %d", + vdev_id, val, wmi_vdev_param_set_ba_mode); + } + } +} + +static inline +void sme_set_mcs_15_tx_rx_disable(uint8_t vdev_id) +{ + uint32_t tx_disable[2] = {67, 0}; + uint32_t rx_disable[3] = {125, 0, 1}; + QDF_STATUS status; + + sme_debug("Send MCS 15 rx/tx disable to FW"); + + status = sme_send_unit_test_cmd(vdev_id, 10, 2, tx_disable); + if (status) + sme_err("Failed to send MCS 15 tx disable"); + + status = sme_send_unit_test_cmd(vdev_id, 67, 3, rx_disable); + if (status) + sme_err("Failed to send MCS 15 rx disable"); +} + +void sme_reset_eht_caps(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + bool val; + QDF_STATUS status; + uint8_t ba_mode_auto = 0; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + sme_debug("reset EHT caps"); + mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap = + mac_ctx->mlme_cfg->eht_caps.eht_cap_orig; + csr_update_session_eht_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->eht_cap_2g, + &mac_ctx->eht_cap_2g_orig, + sizeof(tDot11fIEeht_cap)); + + qdf_mem_copy(&mac_ctx->eht_cap_5g, + &mac_ctx->eht_cap_5g_orig, + sizeof(tDot11fIEeht_cap)); + mac_ctx->usr_eht_testbed_cfg = false; + mac_ctx->roam.configParam.channelBondingMode24GHz = 1; + wlan_mlme_set_sta_mlo_conn_band_bmp(mac_ctx->psoc, 0x77); + wlan_mlme_set_sta_mlo_conn_max_num(mac_ctx->psoc, 2); + status = ucfg_mlme_get_bss_color_collision_det_support(mac_ctx->psoc, + &val); + if (QDF_IS_STATUS_SUCCESS(status)) + ucfg_mlme_set_bss_color_collision_det_sta(mac_ctx->psoc, val); + sme_set_per_link_ba_mode(mac_handle, ba_mode_auto); + sme_set_mcs_15_tx_rx_disable(vdev_id); + wlan_mlme_set_btm_abridge_flag(mac_ctx->psoc, false); + wlan_mlme_set_eht_mld_id(mac_ctx->psoc, 0); +} + +void sme_update_eht_cap_nss(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t nss) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + tDot11fIEeht_cap *mlme_eht_cap; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + mlme_eht_cap = &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap; + if (!nss || (nss > 2)) { + sme_err("invalid Nss value nss %d", nss); + return; + } + sme_debug("Nss value %d", nss); + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7 = nss; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7 = nss; + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9 = nss; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9 = nss; + if (mlme_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11) { + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 = nss; + } + if (mlme_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13) { + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 = nss; + } + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9 = nss; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9 = nss; + if (mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11) { + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11 = nss; + } + if (mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13) { + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13 = nss; + } + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_0_to_9 = nss; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_0_to_9 = nss; + if (mlme_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11) { + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11 = nss; + } + if (mlme_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13) { + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13 = nss; + } + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9 = nss; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_0_to_9 = nss; + + if (mlme_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11) { + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11 = nss; + } + if (mlme_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13) { + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13 = nss; + } + + csr_update_session_eht_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->eht_cap_2g, mlme_eht_cap, + sizeof(tDot11fIEeht_cap)); + + qdf_mem_copy(&mac_ctx->eht_cap_5g, mlme_eht_cap, + sizeof(tDot11fIEeht_cap)); +} + +void sme_update_eht_cap_mcs(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t mcs) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + tDot11fIEeht_cap *mlme_eht_cap; + uint8_t nss; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("No session for id %d", vdev_id); + return; + } + mlme_eht_cap = &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap; + nss = mlme_eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7; + + if (!nss) + nss = mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9; + if (!nss) { + sme_err("No valid Nss"); + return; + } + sme_debug("nss %d, mcs %d", nss, mcs); + + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11 = 0; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13 = 0; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13 = 0; + + if (mcs > 1) { /* 0 - 11*/ + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11 = nss; + mlme_eht_cap->rx_1024_4096_qam_lt_242_tone_ru = 1; + mlme_eht_cap->tx_1024_4096_qam_lt_242_tone_ru = 1; + } + + if (mcs == 3) { /* 0 - 13*/ + mlme_eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13 = nss; + mlme_eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13 = nss; + } + csr_update_session_eht_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->eht_cap_2g, mlme_eht_cap, + sizeof(tDot11fIEeht_cap)); + + qdf_mem_copy(&mac_ctx->eht_cap_5g, mlme_eht_cap, + sizeof(tDot11fIEeht_cap)); +} + +void sme_activate_mlo_links(mac_handle_t mac_handle, uint8_t session_id, + uint8_t num_links, + struct qdf_mac_addr active_link_addr[2]) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return; + } + + if (ml_is_nlink_service_supported(mac_ctx->psoc)) { + policy_mgr_activate_mlo_links_nlink(mac_ctx->psoc, session_id, + num_links, + active_link_addr); + } else { + policy_mgr_activate_mlo_links(mac_ctx->psoc, session_id, + num_links, active_link_addr); + } +} + +int sme_update_eht_caps(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val, enum sme_eht_tx_bfee_cap_type cap_type, + enum QDF_OPMODE op_mode) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct csr_roam_session *session; + tDot11fIEeht_cap *cfg_eht_cap; + + session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) { + sme_err("No session for id %d", session_id); + return -EINVAL; + } + cfg_eht_cap = &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap; + + switch (cap_type) { + case EHT_TX_BFEE_ENABLE: + cfg_eht_cap->su_beamformee = cfg_val; + break; + case EHT_TX_BFEE_SS_80MHZ: + cfg_eht_cap->bfee_ss_le_80mhz = cfg_val; + break; + case EHT_TX_BFEE_SS_160MHZ: + cfg_eht_cap->bfee_ss_160mhz = cfg_val; + break; + case EHT_TX_BFEE_SS_320MHZ: + cfg_eht_cap->bfee_ss_320mhz = cfg_val; + break; + case EHT_TX_BFEE_SOUNDING_FEEDBACK_RATELIMIT: + cfg_eht_cap->tb_sounding_feedback_rl = cfg_val; + break; + default: + sme_debug("default: Unhandled cap type %d", cap_type); + return -EINVAL; + } + + sme_debug("EHT cap: cap type %d, cfg val %d", cap_type, cfg_val); + csr_update_session_eht_cap(mac_ctx, session); + + qdf_mem_copy(&mac_ctx->eht_cap_2g, cfg_eht_cap, + sizeof(tDot11fIEeht_cap)); + qdf_mem_copy(&mac_ctx->eht_cap_5g, cfg_eht_cap, + sizeof(tDot11fIEeht_cap)); + sme_set_vdev_ies_per_band(mac_handle, session_id, op_mode); + + return 0; +} + +int +sme_send_vdev_pause_for_bcn_period(mac_handle_t mac_handle, uint8_t session_id, + uint8_t cfg_val) +{ + struct sme_vdev_pause *vdev_pause; + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + vdev_pause = qdf_mem_malloc(sizeof(*vdev_pause)); + if (!vdev_pause) + return -EIO; + + vdev_pause->session_id = session_id; + vdev_pause->vdev_pause_duration = cfg_val; + qdf_mem_zero(&msg, sizeof(msg)); + msg.type = eWNI_SME_VDEV_PAUSE_IND; + msg.reserved = 0; + msg.bodyptr = vdev_pause; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (status != QDF_STATUS_SUCCESS) { + sme_err("Not able to post vdev pause indication"); + qdf_mem_free(vdev_pause); + return -EIO; + } + + return 0; +} +#endif + +void sme_set_nss_capability(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t nss, enum QDF_OPMODE op_mode) +{ + sme_debug("Nss cap update, NSS %d", nss); + + sme_update_he_cap_nss(mac_handle, vdev_id, nss); + sme_update_eht_cap_nss(mac_handle, vdev_id, nss); + sme_set_vdev_ies_per_band(mac_handle, vdev_id, op_mode); +} + +uint8_t sme_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags, + bool is_he_mcs_12_13_supported, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flags) +{ + return wma_get_mcs_idx(raw_rate, rate_flags, is_he_mcs_12_13_supported, + nss, dcm, guard_interval, mcs_rate_flags); +} + +#ifdef WLAN_UNIT_TEST +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +QDF_STATUS sme_get_sta_cxn_info(mac_handle_t mac_handle, uint32_t session_id, + char *buf, uint32_t buf_sz) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac_ctx->sme); + csr_cm_get_sta_cxn_info(mac_ctx, session_id, buf, buf_sz); + sme_release_global_lock(&mac_ctx->sme); + + return status; +} +#endif +#endif + +QDF_STATUS +sme_get_roam_scan_stats(mac_handle_t mac_handle, + roam_scan_stats_cb cb, void *context, + uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + struct sir_roam_scan_stats *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + req->vdev_id = vdev_id; + req->cb = cb; + req->context = context; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + msg.bodyptr = req; + msg.type = WMA_GET_ROAM_SCAN_STATS; + msg.reserved = 0; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg); + sme_release_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("post roam scan stats req failed"); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(req); + } + } else { + qdf_mem_free(req); + } + + return status; +} + +#ifdef WLAN_FEATURE_11BE +static inline bool sme_is_phy_mode_11be(eCsrPhyMode phy_mode) +{ + if (phy_mode == eCSR_DOT11_MODE_AUTO || + CSR_IS_DOT11_PHY_MODE_11BE(phy_mode) || + CSR_IS_DOT11_PHY_MODE_11BE_ONLY(phy_mode)) { + return true; + } + + return false; +} +#else +static inline bool sme_is_phy_mode_11be(eCsrPhyMode phy_mode) +{ + return false; +} +#endif + +void sme_update_score_config(mac_handle_t mac_handle, eCsrPhyMode phy_mode, + uint8_t num_rf_chains) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct wlan_mlme_nss_chains vdev_ini_cfg; + bool bval = false; + uint32_t channel_bonding_mode; + QDF_STATUS status; + struct psoc_phy_config config = {0}; + bool eht_cap; + + ucfg_psoc_mlme_get_11be_capab(mac_ctx->psoc, &eht_cap); + config.eht_cap = eht_cap; + + qdf_mem_zero(&vdev_ini_cfg, sizeof(struct wlan_mlme_nss_chains)); + /* Populate the nss chain params from ini for this vdev type */ + sme_populate_nss_chain_params(mac_handle, &vdev_ini_cfg, + QDF_STA_MODE, num_rf_chains); + + config.vdev_nss_24g = vdev_ini_cfg.rx_nss[NSS_CHAINS_BAND_2GHZ]; + config.vdev_nss_5g = vdev_ini_cfg.rx_nss[NSS_CHAINS_BAND_5GHZ]; + + if (config.eht_cap || + phy_mode == eCSR_DOT11_MODE_AUTO || + phy_mode == eCSR_DOT11_MODE_11ax || + phy_mode == eCSR_DOT11_MODE_11ax_ONLY) + config.he_cap = 1; + + if (config.he_cap || + phy_mode == eCSR_DOT11_MODE_11ac || + phy_mode == eCSR_DOT11_MODE_11ac_ONLY) + config.vht_cap = 1; + + if (config.vht_cap || phy_mode == eCSR_DOT11_MODE_11n || + phy_mode == eCSR_DOT11_MODE_11n_ONLY) + config.ht_cap = 1; + + if (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + config.he_cap = 0; + + if (!IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + config.vht_cap = 0; + + status = wlan_mlme_get_vht_for_24ghz(mac_ctx->psoc, &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("Failed to get vht_for_24ghz"); + if (config.vht_cap && bval) + config.vht_24G_cap = 1; + + status = wlan_mlme_get_vht_enable_tx_bf(mac_ctx->psoc, + &bval); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("unable to get vht_enable_tx_bf"); + + if (bval) + config.beamformee_cap = 1; + + ucfg_mlme_get_channel_bonding_24ghz(mac_ctx->psoc, + &channel_bonding_mode); + config.bw_above_20_24ghz = channel_bonding_mode; + ucfg_mlme_get_channel_bonding_5ghz(mac_ctx->psoc, + &channel_bonding_mode); + config.bw_above_20_5ghz = channel_bonding_mode; + config.max_chan_switch_ie = mlme_max_chan_switch_is_set(mac_ctx->psoc); + + wlan_psoc_set_phy_config(mac_ctx->psoc, &config); +} + +static void +__sme_enable_fw_module_log_level(uint8_t *enable_fw_module_log_level, + uint8_t enable_fw_module_log_level_num, + int vdev_id, int param_id) +{ + uint8_t count = 0; + uint32_t value = 0; + int ret; + + while (count < enable_fw_module_log_level_num) { + /* + * FW module log level input array looks like + * below: + * enable_fw_module_log_level = {, + * ,...} + * For example: + * enable_fw_module_log_level= + * {1,0,2,1,3,2,4,3,5,4,6,5,7,6} + * Above input array means : + * For FW module ID 1 enable log level 0 + * For FW module ID 2 enable log level 1 + * For FW module ID 3 enable log level 2 + * For FW module ID 4 enable log level 3 + * For FW module ID 5 enable log level 4 + * For FW module ID 6 enable log level 5 + * For FW module ID 7 enable log level 6 + */ + + if ((enable_fw_module_log_level[count] > WLAN_MODULE_ID_MAX) || + (enable_fw_module_log_level[count + 1] > DBGLOG_LVL_MAX)) { + sme_err("Module id %d or dbglog level %d input value is more than max", + enable_fw_module_log_level[count], + enable_fw_module_log_level[count + 1]); + count += 2; + continue; + } + + value = enable_fw_module_log_level[count] << 16; + value |= enable_fw_module_log_level[count + 1]; + ret = sme_cli_set_command(vdev_id, param_id, value, DBG_CMD); + if (ret != 0) + sme_err("Failed to enable FW module log level %d ret %d", + value, ret); + + count += 2; + } +} + +void sme_enable_fw_module_log_level(mac_handle_t mac_handle, int vdev_id) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t *enable_fw_module_log_level; + uint8_t enable_fw_module_log_level_num; + + status = ucfg_fwol_get_enable_fw_module_log_level( + mac_ctx->psoc, &enable_fw_module_log_level, + &enable_fw_module_log_level_num); + if (QDF_IS_STATUS_ERROR(status)) + return; + __sme_enable_fw_module_log_level(enable_fw_module_log_level, + enable_fw_module_log_level_num, + vdev_id, + WMI_DBGLOG_MOD_LOG_LEVEL); + + enable_fw_module_log_level_num = 0; + status = ucfg_fwol_wow_get_enable_fw_module_log_level( + mac_ctx->psoc, &enable_fw_module_log_level, + &enable_fw_module_log_level_num); + if (QDF_IS_STATUS_ERROR(status)) + return; + __sme_enable_fw_module_log_level(enable_fw_module_log_level, + enable_fw_module_log_level_num, + vdev_id, + WMI_DBGLOG_MOD_WOW_LOG_LEVEL); +} + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * sme_set_md_bl_evt_cb - Register/set motion detection baseline callback + * @mac_handle: mac handle + * @callback_fn: callback function pointer + * @hdd_ctx: hdd context + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_set_md_bl_evt_cb( + mac_handle_t mac_handle, + QDF_STATUS (*callback_fn)(void *ctx, struct sir_md_bl_evt *event), + void *hdd_ctx +) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->sme.md_bl_evt_cb = callback_fn; + mac->sme.md_ctx = hdd_ctx; + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} + +/** + * sme_set_md_host_evt_cb - Register/set motion detection callback + * @mac_handle: mac handle + * @callback_fn: motion detection callback function pointer + * @hdd_ctx: hdd context + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_set_md_host_evt_cb( + mac_handle_t mac_handle, + QDF_STATUS (*callback_fn)(void *ctx, struct sir_md_evt *event), + void *hdd_ctx +) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + mac->sme.md_host_evt_cb = callback_fn; + mac->sme.md_ctx = hdd_ctx; + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} + +/** + * sme_motion_det_config - Post motion detection configuration msg to scheduler + * @mac_handle: mac handle + * @motion_det_config: motion detection configuration + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_config(mac_handle_t mac_handle, + struct sme_motion_det_cfg *motion_det_config) +{ + struct scheduler_msg msg; + struct sme_motion_det_cfg *motion_det_cfg; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + motion_det_cfg = + qdf_mem_malloc(sizeof(*motion_det_cfg)); + if (!motion_det_cfg) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + *motion_det_cfg = *motion_det_config; + + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_MOTION_DET_CONFIG; + msg.bodyptr = motion_det_cfg; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(motion_det_cfg); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} + +/** + * sme_motion_det_enable - Post motion detection start/stop msg to scheduler + * @mac_handle: mac handle + * @motion_det_enable: motion detection start/stop + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_enable(mac_handle_t mac_handle, + struct sme_motion_det_en *motion_det_enable) +{ + struct scheduler_msg msg; + struct sme_motion_det_en *motion_det_en; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + motion_det_en = qdf_mem_malloc(sizeof(*motion_det_en)); + if (!motion_det_en) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + *motion_det_en = *motion_det_enable; + + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_MOTION_DET_ENABLE; + msg.bodyptr = motion_det_en; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(motion_det_en); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} + +/** + * sme_motion_det_base_line_config - Post md baselining cfg msg to scheduler + * @mac_handle: mac handle + * @motion_det_base_line_config: motion detection baselining configuration + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_base_line_config( + mac_handle_t mac_handle, + struct sme_motion_det_base_line_cfg *motion_det_base_line_config) +{ + struct scheduler_msg msg; + struct sme_motion_det_base_line_cfg *motion_det_base_line_cfg; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + motion_det_base_line_cfg = + qdf_mem_malloc(sizeof(*motion_det_base_line_cfg)); + + if (!motion_det_base_line_cfg) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + *motion_det_base_line_cfg = *motion_det_base_line_config; + + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_MOTION_DET_BASE_LINE_CONFIG; + msg.bodyptr = motion_det_base_line_cfg; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(motion_det_base_line_cfg); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} + +/** + * sme_motion_det_base_line_enable - Post md baselining enable msg to scheduler + * @mac_handle: mac handle + * @motion_det_base_line_enable: motion detection baselining start/stop + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS sme_motion_det_base_line_enable( + mac_handle_t mac_handle, + struct sme_motion_det_base_line_en *motion_det_base_line_enable) +{ + struct scheduler_msg msg; + struct sme_motion_det_base_line_en *motion_det_base_line_en; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + motion_det_base_line_en = + qdf_mem_malloc(sizeof(*motion_det_base_line_en)); + + if (!motion_det_base_line_en) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + *motion_det_base_line_en = *motion_det_base_line_enable; + + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_MOTION_DET_BASE_LINE_ENABLE; + msg.bodyptr = motion_det_base_line_en; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(motion_det_base_line_en); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +#ifdef FW_THERMAL_THROTTLE_SUPPORT + +/** + * sme_set_thermal_throttle_cfg() - SME API to set the thermal throttle + * configuration parameters + * @mac_handle: Opaque handle to the global MAC context + * @therm_params: structure of thermal configuration parameters + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_throttle_cfg(mac_handle_t mac_handle, + struct thermal_mitigation_params *therm_params) + +{ + struct scheduler_msg msg; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct thermal_mitigation_params *therm_cfg_params; + + therm_cfg_params = qdf_mem_malloc(sizeof(*therm_cfg_params)); + if (!therm_cfg_params) + return QDF_STATUS_E_NOMEM; + + qdf_mem_set(therm_cfg_params, sizeof(*therm_cfg_params), 0); + qdf_mem_copy(therm_cfg_params, therm_params, sizeof(*therm_cfg_params)); + + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_THERMAL_THROTTLE_CFG; + msg.reserved = 0; + msg.bodyptr = therm_cfg_params; + + qdf_status = sme_acquire_global_lock(&mac->sme); + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("failed to schedule throttle config req %d", + qdf_status); + qdf_mem_free(therm_cfg_params); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + return qdf_status; +} + +/** + * sme_set_thermal_mgmt() - SME API to set the thermal management params + * @mac_handle: Opaque handle to the global MAC context + * @lower_thresh_deg: Lower threshold value of Temperature + * @higher_thresh_deg: Higher threshold value of Temperature + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_set_thermal_mgmt(mac_handle_t mac_handle, + uint16_t lower_thresh_deg, + uint16_t higher_thresh_deg) +{ + struct scheduler_msg msg; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + t_thermal_cmd_params *therm_mgmt_cmd; + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_STATUS_SUCCESS == qdf_status) { + therm_mgmt_cmd = qdf_mem_malloc(sizeof(*therm_mgmt_cmd)); + if (!therm_mgmt_cmd) { + sme_release_global_lock(&mac->sme); + return QDF_STATUS_E_NOMEM; + } + + therm_mgmt_cmd->minTemp = lower_thresh_deg; + therm_mgmt_cmd->maxTemp = higher_thresh_deg; + therm_mgmt_cmd->thermalEnable = 1; + + qdf_mem_set(&msg, sizeof(msg), 0); + msg.type = WMA_SET_THERMAL_MGMT; + msg.reserved = 0; + msg.bodyptr = therm_mgmt_cmd; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(therm_mgmt_cmd); + qdf_status = QDF_STATUS_E_FAILURE; + } + sme_release_global_lock(&mac->sme); + } + return qdf_status; +} +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + +QDF_STATUS sme_update_hidden_ssid_status_cb(mac_handle_t mac_handle, + hidden_ssid_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.hidden_ssid_cb = cb; + sme_release_global_lock(&mac->sme); + } + + return status; +} + +QDF_STATUS sme_update_owe_info(struct mac_context *mac, + struct assoc_ind *assoc_ind) +{ + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_update_owe_info(mac, assoc_ind); + sme_release_global_lock(&mac->sme); + } + + return status; +} + +QDF_STATUS sme_update_ft_info(struct mac_context *mac, + struct assoc_ind *assoc_ind) +{ + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + status = csr_update_ft_info(mac, assoc_ind); + sme_release_global_lock(&mac->sme); + } + + return status; +} + +#ifdef WLAN_MWS_INFO_DEBUGFS +QDF_STATUS +sme_get_mws_coex_info(mac_handle_t mac_handle, uint32_t vdev_id, + uint32_t cmd_id, void (*callback_fn)(void *coex_info_data, + void *context, + wmi_mws_coex_cmd_id + cmd_id), + void *context) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct scheduler_msg msg = {0}; + struct sir_get_mws_coex_info *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + req->vdev_id = vdev_id; + req->cmd_id = cmd_id; + mac->sme.mws_coex_info_state_resp_callback = callback_fn; + mac->sme.mws_coex_info_ctx = context; + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + msg.bodyptr = req; + msg.type = WMA_GET_MWS_COEX_INFO_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg); + sme_release_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("post MWS coex info req failed"); + status = QDF_STATUS_E_FAILURE; + qdf_mem_free(req); + } + } else { + sme_err("sme_acquire_global_lock failed"); + qdf_mem_free(req); + } + + return status; +} +#endif /* WLAN_MWS_INFO_DEBUGFS */ + +#ifdef WLAN_BCN_RECV_FEATURE +/** + * sme_scan_event_handler() - Scan complete event handler + * @vdev: vdev obj manager + * @event: scan event + * @arg: arg of scan event + * + * This function is getting called after Host receive scan start + * + * Return: None + */ +static void sme_scan_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + struct mac_context *mac = arg; + uint8_t vdev_id; + + if (!mac) { + sme_err("Invalid mac context"); + return; + } + + if (!mac->sme.beacon_pause_cb) + return; + + if (event->type != SCAN_EVENT_TYPE_STARTED) + return; + + for (vdev_id = 0 ; vdev_id < WLAN_MAX_VDEVS ; vdev_id++) { + if (CSR_IS_SESSION_VALID(mac, vdev_id) && + sme_is_beacon_report_started(MAC_HANDLE(mac), vdev_id)) { + sme_debug("Send pause ind for vdev_id : %d", vdev_id); + mac->sme.beacon_pause_cb(mac->hdd_handle, vdev_id, + event->type, false); + } + } +} + +QDF_STATUS sme_register_bcn_recv_pause_ind_cb(mac_handle_t mac_handle, + beacon_pause_cb cb) +{ + QDF_STATUS status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!mac) { + sme_err("Invalid mac context"); + return QDF_STATUS_E_NOMEM; + } + + /* scan event de-registration */ + if (!cb) { + ucfg_scan_unregister_event_handler(mac->pdev, + sme_scan_event_handler, mac); + return QDF_STATUS_SUCCESS; + } + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + mac->sme.beacon_pause_cb = cb; + sme_release_global_lock(&mac->sme); + } + + /* scan event registration */ + status = ucfg_scan_register_event_handler(mac->pdev, + sme_scan_event_handler, mac); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("scan event register failed "); + + return status; +} +#endif + +QDF_STATUS sme_set_vdev_sw_retry(uint8_t vdev_id, uint8_t sw_retry_count, + wmi_vdev_custom_sw_retry_type_t sw_retry_type) +{ + QDF_STATUS status; + + status = wma_set_vdev_sw_retry_th(vdev_id, sw_retry_count, + sw_retry_type); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to set retry count for vdev: %d", vdev_id); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_set_disconnect_ies(mac_handle_t mac_handle, uint8_t vdev_id, + uint8_t *ie_data, uint16_t ie_len) +{ + struct mac_context *mac_ctx; + struct wlan_objmgr_vdev *vdev; + struct element_info ie; + + if (!ie_data || !ie_len) { + sme_debug("Got NULL disconnect IEs"); + return QDF_STATUS_E_INVAL; + } + + mac_ctx = MAC_CONTEXT(mac_handle); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("Got NULL vdev obj, returning"); + return QDF_STATUS_E_FAILURE; + } + + ie.ptr = ie_data; + ie.len = ie_len; + + mlme_set_self_disconnect_ies(vdev, &ie); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +sme_send_vendor_btm_params(mac_handle_t mac_handle, uint8_t vdev_id) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (vdev_id >= WLAN_MAX_VDEVS) { + sme_err("Invalid sme session id: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (mac->mlme_cfg->lfr.roam_scan_offload_enabled) + wlan_roam_update_cfg(mac->psoc, vdev_id, + REASON_ROAM_CONTROL_CONFIG_CHANGED); + sme_release_global_lock(&mac->sme); + } + + return status; +} + +QDF_STATUS sme_set_roam_config_enable(mac_handle_t mac_handle, + uint8_t vdev_id, + uint8_t roam_control_enable) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy src_config = {}; + + if (!mac->mlme_cfg->lfr.roam_scan_offload_enabled) + return QDF_STATUS_E_INVAL; + + src_config.bool_value = !!roam_control_enable; + return wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + ROAM_CONFIG_ENABLE, + &src_config); +} + +QDF_STATUS sme_get_roam_config_status(mac_handle_t mac_handle, + uint8_t vdev_id, + uint8_t *config_status) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(mac->psoc, vdev_id, ROAM_CONTROL_ENABLE, + &temp); + *config_status = temp.bool_value; + + return QDF_STATUS_SUCCESS; +} + +uint16_t sme_get_full_roam_scan_period_global(mac_handle_t mac_handle) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + return mac->mlme_cfg->lfr.roam_full_scan_period; +} + +QDF_STATUS +sme_get_full_roam_scan_period(mac_handle_t mac_handle, uint8_t vdev_id, + uint32_t *full_roam_scan_period) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct cm_roam_values_copy temp; + + wlan_cm_roam_cfg_get_value(mac->psoc, vdev_id, + FULL_ROAM_SCAN_PERIOD, &temp); + *full_roam_scan_period = temp.uint_value; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_check_for_duplicate_session(mac_handle_t mac_handle, + uint8_t **mac_list) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool peer_exist = false; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + uint8_t **peer_addr = mac_list; + + if (!soc) + return QDF_STATUS_E_INVAL; + + if (QDF_STATUS_SUCCESS != sme_acquire_global_lock(&mac_ctx->sme)) + return QDF_STATUS_E_INVAL; + + while (*peer_addr) { + peer_exist = cdp_find_peer_exist(soc, OL_TXRX_PDEV_ID, + *peer_addr); + if (peer_exist) { + sme_err("Peer exists with same MAC"); + status = QDF_STATUS_E_EXISTS; + break; + } + peer_addr++; + } + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +#ifdef FEATURE_ANI_LEVEL_REQUEST +QDF_STATUS sme_get_ani_level(mac_handle_t mac_handle, uint32_t *freqs, + uint8_t num_freqs, void (*callback)( + struct wmi_host_ani_level_event *ani, uint8_t num, + void *context), void *context) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + void *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + mac->ani_params.ani_level_cb = callback; + mac->ani_params.context = context; + + status = wma_send_ani_level_request(wma_handle, freqs, num_freqs); + return status; +} +#endif /* FEATURE_ANI_LEVEL_REQUEST */ + +#ifdef FEATURE_MONITOR_MODE_SUPPORT + +QDF_STATUS sme_set_monitor_mode_cb(mac_handle_t mac_handle, + void (*monitor_mode_cb)(uint8_t vdev_id)) +{ + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("Failed to acquire sme lock; status: %d", qdf_status); + return qdf_status; + } + mac->sme.monitor_mode_cb = monitor_mode_cb; + sme_release_global_lock(&mac->sme); + + return qdf_status; +} + +QDF_STATUS sme_process_monitor_mode_vdev_up_evt(uint8_t vdev_id) +{ + mac_handle_t mac_handle; + struct mac_context *mac; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_handle) + return QDF_STATUS_E_INVAL; + + mac = MAC_CONTEXT(mac_handle); + + if (mac->sme.monitor_mode_cb) + mac->sme.monitor_mode_cb(vdev_id); + else { + sme_warn_rl("monitor_mode_cb is not registered"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) +QDF_STATUS +sme_set_beacon_latency_event_cb(mac_handle_t mac_handle, + void (*beacon_latency_event_cb) + (uint32_t latency_level)) +{ + QDF_STATUS qdf_status; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + qdf_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("Failed to acquire sme lock; status: %d", qdf_status); + return qdf_status; + } + mac->sme.beacon_latency_event_cb = beacon_latency_event_cb; + sme_release_global_lock(&mac->sme); + + return qdf_status; +} +#endif + +void sme_fill_enc_type(eCsrEncryptionType *cipher_type, + uint32_t cipherset) +{ + csr_fill_enc_type(cipher_type, cipherset); +} + +void sme_fill_auth_type(enum csr_akm_type *auth_type, + uint32_t authmodeset, uint32_t akm, + uint32_t ucastcipherset) +{ + csr_fill_auth_type(auth_type, authmodeset, + akm, ucastcipherset); +} + +enum csr_cfgdot11mode sme_phy_mode_to_dot11mode(enum wlan_phymode phy_mode) +{ + return csr_phy_mode_to_dot11mode(phy_mode); +} + +QDF_STATUS sme_switch_channel(mac_handle_t mac_handle, + struct qdf_mac_addr *bssid, + qdf_freq_t chan_freq, + enum phy_ch_width chan_width) +{ + struct scheduler_msg msg = {0}; + struct csa_offload_params *csa_offload_event; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + csa_offload_event = qdf_mem_malloc(sizeof(*csa_offload_event)); + if (!csa_offload_event) + return QDF_STATUS_E_NOMEM; + + qdf_copy_macaddr(&csa_offload_event->bssid, bssid); + csa_offload_event->csa_chan_freq = (uint32_t)chan_freq; + csa_offload_event->new_ch_width = chan_width; + csa_offload_event->channel = + wlan_reg_freq_to_chan(mac_ctx->pdev, + csa_offload_event->csa_chan_freq); + csa_offload_event->switch_mode = 1; + + sme_debug("bssid " QDF_MAC_ADDR_FMT " freq %u width %u", + QDF_MAC_ADDR_REF(csa_offload_event->bssid.bytes), + csa_offload_event->csa_chan_freq, + csa_offload_event->new_ch_width); + + msg.type = eWNI_SME_CSA_REQ; + msg.reserved = 0; + msg.bodyptr = csa_offload_event; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + &msg)) { + qdf_mem_free(csa_offload_event); + sme_err("Not able to post WMA_CSA_OFFLOAD_EVENT to PE"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +QDF_STATUS sme_send_set_mac_addr(struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE vdev_opmode; + QDF_STATUS status; + struct vdev_mlme_obj *vdev_mlme; + + if (!vdev) { + sme_err("Invalid VDEV"); + return QDF_STATUS_E_INVAL; + } + + vdev_opmode = wlan_vdev_mlme_get_opmode(vdev); + + if (vdev_opmode == QDF_P2P_DEVICE_MODE) { + status = wma_p2p_self_peer_remove(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + } + + status = wlan_vdev_mlme_send_set_mac_addr(mac_addr, mld_addr, vdev); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + + /** + * Failed to send set MAC address command to FW. Create P2P self peer + * again with old MAC address + */ + if (vdev_opmode == QDF_P2P_DEVICE_MODE) { + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + sme_err("Invalid vdev MLME context"); + return QDF_STATUS_E_INVAL; + } + + status = wma_vdev_self_peer_create(vdev_mlme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_nofl_err("Failed to create self peer for P2P device mode. Status:%d", + status); + return QDF_STATUS_E_INVAL; + } + } + + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS sme_update_vdev_mac_addr(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr mac_addr, + struct qdf_mac_addr mld_addr, + bool update_sta_self_peer, + bool update_mld_addr, int req_status) +{ + enum QDF_OPMODE vdev_opmode; + uint8_t *old_macaddr, *new_macaddr; + QDF_STATUS qdf_ret_status; + struct wlan_objmgr_peer *peer; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + + vdev_opmode = wlan_vdev_mlme_get_opmode(vdev); + + if (req_status) + goto p2p_self_peer_create; + + if (vdev_opmode == QDF_STA_MODE && update_sta_self_peer) { + if (update_mld_addr) { + old_macaddr = wlan_vdev_mlme_get_mldaddr(vdev); + new_macaddr = mld_addr.bytes; + } else { + old_macaddr = wlan_vdev_mlme_get_macaddr(vdev); + new_macaddr = mac_addr.bytes; + } + + /* Update self peer MAC address */ + peer = wlan_objmgr_get_peer_by_mac(psoc, old_macaddr, + WLAN_MLME_NB_ID); + if (peer) { + qdf_ret_status = wlan_peer_update_macaddr(peer, + new_macaddr); + wlan_objmgr_peer_release_ref(peer, WLAN_MLME_NB_ID); + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) { + sme_nofl_err("Failed to update self peer MAC address. Status:%d", + qdf_ret_status); + return qdf_ret_status; + } + } else { + sme_err("Self peer not found with MAC addr:" + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(old_macaddr)); + return QDF_STATUS_E_INVAL; + } + } + + /* Update VDEV MAC address */ + if (update_mld_addr) { + if (update_sta_self_peer || vdev_opmode == QDF_SAP_MODE) { + qdf_ret_status = wlan_mlo_mgr_update_mld_addr( + (struct qdf_mac_addr *) + wlan_vdev_mlme_get_mldaddr(vdev), + &mld_addr); + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) + return qdf_ret_status; + } + wlan_vdev_mlme_set_mldaddr(vdev, mld_addr.bytes); + } + wlan_vdev_mlme_set_macaddr(vdev, mac_addr.bytes); + wlan_vdev_mlme_set_linkaddr(vdev, mac_addr.bytes); + + ucfg_vdev_mgr_cdp_vdev_attach(vdev); +p2p_self_peer_create: + if (vdev_opmode == QDF_P2P_DEVICE_MODE) { + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + sme_err("Invalid vdev MLME context"); + return QDF_STATUS_E_INVAL; + } + + qdf_ret_status = wma_vdev_self_peer_create(vdev_mlme); + if (QDF_IS_STATUS_ERROR(qdf_ret_status)) { + sme_nofl_err("Failed to create self peer for P2P device mode. Status:%d", + qdf_ret_status); + return QDF_STATUS_E_INVAL; + } + } + return QDF_STATUS_SUCCESS; +} +#endif + +static QDF_STATUS sme_send_start_bss_msg(struct mac_context *mac, + struct start_bss_config *cfg) +{ + struct scheduler_msg msg = {0}; + struct start_bss_config *start_bss_cfg; + struct start_bss_rsp rsp; + + if (!cfg) + return QDF_STATUS_E_FAILURE; + + csr_roam_state_change(mac, eCSR_ROAMING_STATE_JOINING, cfg->vdev_id); + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_START_BSS_REQ, + cfg->vdev_id); + + start_bss_cfg = qdf_mem_malloc(sizeof(*start_bss_cfg)); + if (!start_bss_cfg) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(start_bss_cfg, cfg, sizeof(*start_bss_cfg)); + msg.type = eWNI_SME_START_BSS_REQ; + msg.bodyptr = start_bss_cfg; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + &msg)) + goto failure; + + return QDF_STATUS_SUCCESS; +failure: + sme_err("Failed to post start bss request to PE for vdev : %d", + start_bss_cfg->vdev_id); + csr_process_sap_response(mac, CSR_SAP_START_BSS_FAILURE, &rsp, + start_bss_cfg->vdev_id); + qdf_mem_free(start_bss_cfg); + return QDF_STATUS_E_FAILURE; +} + +static QDF_STATUS sme_send_stop_bss_msg(struct mac_context *mac, + struct stop_bss_req *cfg) +{ + struct scheduler_msg msg = {0}; + struct stop_bss_req *stop_bss_req; + + csr_roam_state_change(mac, eCSR_ROAMING_STATE_JOINING, cfg->vdev_id); + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_STOP_BSS_REQ, + cfg->vdev_id); + + sme_err("Stop bss request received for vdev : %d cmd_id : %d", + cfg->vdev_id, cfg->cmd_id); + + stop_bss_req = qdf_mem_malloc(sizeof(*stop_bss_req)); + if (!stop_bss_req) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(stop_bss_req, cfg, sizeof(*stop_bss_req)); + + msg.type = eWNI_SME_STOP_BSS_REQ; + msg.bodyptr = stop_bss_req; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + &msg)) { + sme_err("Failed to post stop bss request for vdev id : %d", + cfg->vdev_id); + qdf_mem_free(stop_bss_req); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS sme_sap_activate_cmd(struct wlan_serialization_command *cmd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + mac_handle_t mac_handle; + struct mac_context *mac; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac = MAC_CONTEXT(mac_handle); + if (!mac) { + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + switch (cmd->cmd_type) { + case WLAN_SER_CMD_VDEV_START_BSS: + status = sme_send_start_bss_msg(mac, cmd->umac_cmd); + break; + case WLAN_SER_CMD_VDEV_STOP_BSS: + status = sme_send_stop_bss_msg(mac, cmd->umac_cmd); + break; + default: + status = QDF_STATUS_E_FAILURE; + break; + } + return status; +} + +QDF_STATUS sme_sap_ser_callback(struct wlan_serialization_command *cmd, + enum wlan_serialization_cb_reason reason) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + + if (!cmd) { + sme_err("Invalid Serialization command"); + return QDF_STATUS_E_FAILURE; + } + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + if (mac_handle) + mac_ctx = MAC_CONTEXT(mac_handle); + else + return QDF_STATUS_E_FAILURE; + + switch (reason) { + case WLAN_SER_CB_ACTIVATE_CMD: + status = sme_sap_activate_cmd(cmd); + break; + case WLAN_SER_CB_CANCEL_CMD: + break; + case WLAN_SER_CB_RELEASE_MEM_CMD: + if (cmd->vdev) + wlan_objmgr_vdev_release_ref(cmd->vdev, + WLAN_LEGACY_MAC_ID); + if (cmd->umac_cmd) + qdf_mem_free(cmd->umac_cmd); + break; + case WLAN_SER_CB_ACTIVE_CMD_TIMEOUT: + qdf_trigger_self_recovery(mac_ctx->psoc, + QDF_ACTIVE_LIST_TIMEOUT); + break; + default: + sme_debug("unknown reason code"); + return QDF_STATUS_E_FAILURE; + } + return status; +} + +void sme_fill_channel_change_request(mac_handle_t mac_handle, + struct channel_change_req *req, + eCsrPhyMode phy_mode) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct bss_dot11_config dot11_cfg = {0}; + + dot11_cfg.vdev_id = req->vdev_id; + dot11_cfg.bss_op_ch_freq = req->target_chan_freq; + dot11_cfg.phy_mode = phy_mode; + + sme_get_network_params(mac_ctx, &dot11_cfg); + + req->dot11mode = dot11_cfg.dot11_mode; + req->nw_type = dot11_cfg.nw_type; + + if (dot11_cfg.opr_rates.numRates) { + qdf_mem_copy(req->opr_rates.rate, + dot11_cfg.opr_rates.rate, + dot11_cfg.opr_rates.numRates); + req->opr_rates.numRates = + dot11_cfg.opr_rates.numRates; + } + + if (dot11_cfg.ext_rates.numRates) { + qdf_mem_copy(req->ext_rates.rate, + dot11_cfg.ext_rates.rate, + dot11_cfg.ext_rates.numRates); + req->ext_rates.numRates = + dot11_cfg.ext_rates.numRates; + } +} + +QDF_STATUS sme_update_beacon_country_ie(mac_handle_t mac_handle, + uint8_t vdev_id, + bool country_ie_for_all_band) +{ + struct mac_context *mac = MAC_CONTEXT(mac_handle); + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_MLME_NB_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev_id %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + return QDF_STATUS_E_FAILURE; + } + + mlme_priv->country_ie_for_all_band = country_ie_for_all_band; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_NB_ID); + + csr_update_beacon(mac); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +sme_send_multi_pdev_vdev_set_params(enum mlme_dev_setparam param_type, + uint8_t dev_id, + struct dev_set_param *param, + uint8_t max_index) +{ + return wma_send_multi_pdev_vdev_set_params(param_type, dev_id, param, + max_index); +} + +QDF_STATUS +sme_validate_txrx_chain_mask(uint32_t id, uint32_t value) +{ + return wma_validate_txrx_chain_mask(id, value); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_power_save.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_power_save.c new file mode 100644 index 0000000000..c75f4605cd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_power_save.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "sme_power_save.h" +#include "sme_power_save_api.h" +#include +#include +#include +#include "sme_trace.h" +#include "qdf_mem.h" +#include "qdf_types.h" +#include "wma.h" +#include "wma_internal.h" +#include "wmm_apsd.h" +#include "csr_inside_api.h" + +/** + * sme_post_ps_msg_to_wma(): post message to WMA. + * @type: type + * @body: body pointer + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_post_ps_msg_to_wma(uint16_t type, void *body) +{ + struct scheduler_msg msg = {0}; + + msg.type = type; + msg.reserved = 0; + msg.bodyptr = body; + msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Posting message %d failed", type); + qdf_mem_free(body); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_uapsd_req_params(): enables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static void sme_ps_fill_uapsd_req_params(struct mac_context *mac_ctx, + tUapsd_Params *uapsdParams, uint32_t session_id, + enum ps_state *ps_state) +{ + + uint8_t uapsd_delivery_mask = 0; + uint8_t uapsd_trigger_mask = 0; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + + uapsd_delivery_mask = + ps_param->uapsd_per_ac_bit_mask | + ps_param->uapsd_per_ac_delivery_enable_mask; + + uapsd_trigger_mask = + ps_param->uapsd_per_ac_bit_mask | + ps_param->uapsd_per_ac_trigger_enable_mask; + + uapsdParams->bkDeliveryEnabled = + LIM_UAPSD_GET(ACBK, uapsd_delivery_mask); + + uapsdParams->beDeliveryEnabled = + LIM_UAPSD_GET(ACBE, uapsd_delivery_mask); + + uapsdParams->viDeliveryEnabled = + LIM_UAPSD_GET(ACVI, uapsd_delivery_mask); + + uapsdParams->voDeliveryEnabled = + LIM_UAPSD_GET(ACVO, uapsd_delivery_mask); + + uapsdParams->bkTriggerEnabled = + LIM_UAPSD_GET(ACBK, uapsd_trigger_mask); + + uapsdParams->beTriggerEnabled = + LIM_UAPSD_GET(ACBE, uapsd_trigger_mask); + + uapsdParams->viTriggerEnabled = + LIM_UAPSD_GET(ACVI, uapsd_trigger_mask); + + uapsdParams->voTriggerEnabled = + LIM_UAPSD_GET(ACVO, uapsd_trigger_mask); + if (ps_param->ps_state != FULL_POWER_MODE) { + uapsdParams->enable_ps = true; + *ps_state = UAPSD_MODE; + } else { + uapsdParams->enable_ps = false; + *ps_state = FULL_POWER_MODE; + } +} + +static void sme_set_ps_state(struct mac_context *mac_ctx, + uint32_t session_id, enum ps_state ps_state) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + + ps_param->ps_state = ps_state; +} + +static void sme_get_ps_state(struct mac_context *mac_ctx, + uint32_t session_id, enum ps_state *ps_state) +{ + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + *ps_state = ps_param->ps_state; +} +/** + * sme_ps_enable_ps_req_params(): enables power save req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS +sme_ps_enable_ps_req_params(struct mac_context *mac_ctx, uint32_t vdev_id) +{ + struct sEnablePsParams *enable_ps_req_params; + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[vdev_id]; + enum ps_state ps_state; + + enable_ps_req_params = qdf_mem_malloc(sizeof(*enable_ps_req_params)); + if (!enable_ps_req_params) + return QDF_STATUS_E_NOMEM; + + if (ps_param->uapsd_per_ac_bit_mask) { + enable_ps_req_params->psSetting = eSIR_ADDON_ENABLE_UAPSD; + sme_ps_fill_uapsd_req_params(mac_ctx, + &enable_ps_req_params->uapsdParams, + vdev_id, &ps_state); + ps_state = UAPSD_MODE; + enable_ps_req_params->uapsdParams.enable_ps = true; + } else { + enable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + ps_state = LEGACY_POWER_SAVE_MODE; + } + enable_ps_req_params->sessionid = vdev_id; + + wma_enable_sta_ps_mode(enable_ps_req_params); + + qdf_mem_free(enable_ps_req_params); + + sme_debug("Powersave Enable sent to FW"); + ps_param->ps_state = ps_state; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_disable_ps_req_params(): Disable power save req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_disable_ps_req_params(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ + struct sDisablePsParams *disable_ps_req_params; + + disable_ps_req_params = qdf_mem_malloc(sizeof(*disable_ps_req_params)); + if (!disable_ps_req_params) + return QDF_STATUS_E_NOMEM; + + disable_ps_req_params->psSetting = eSIR_ADDON_NOTHING; + disable_ps_req_params->sessionid = vdev_id; + + wma_disable_sta_ps_mode(disable_ps_req_params); + qdf_mem_free(disable_ps_req_params); + + sme_debug("Powersave disable sent to FW"); + sme_set_ps_state(mac_ctx, vdev_id, FULL_POWER_MODE); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_uapsd_req_params(): enables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_enable_uapsd_req_params(struct mac_context *mac_ctx, + uint32_t session_id) +{ + + struct sEnableUapsdParams *enable_uapsd_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum ps_state ps_state; + + enable_uapsd_req_params = + qdf_mem_malloc(sizeof(*enable_uapsd_req_params)); + if (!enable_uapsd_req_params) + return QDF_STATUS_E_NOMEM; + + sme_ps_fill_uapsd_req_params(mac_ctx, + &enable_uapsd_req_params->uapsdParams, + session_id, &ps_state); + enable_uapsd_req_params->sessionid = session_id; + + status = sme_post_ps_msg_to_wma(WMA_ENABLE_UAPSD_REQ, + enable_uapsd_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + + sme_debug("Msg WMA_ENABLE_UAPSD_REQ Successfully sent to WMA"); + sme_set_ps_state(mac_ctx, session_id, ps_state); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_disable_uapsd_req_params(): disables UASPD req params + * @mac_ctx: global mac context + * @session_id: session id + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_ps_disable_uapsd_req_params(struct mac_context *mac_ctx, + uint32_t session_id) +{ + struct sDisableUapsdParams *disable_uapsd_req_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + enum ps_state ps_state; + + sme_get_ps_state(mac_ctx, session_id, &ps_state); + if (ps_state != UAPSD_MODE) { + sme_err("UAPSD is already disabled"); + return QDF_STATUS_SUCCESS; + } + disable_uapsd_req_params = + qdf_mem_malloc(sizeof(*disable_uapsd_req_params)); + if (!disable_uapsd_req_params) + return QDF_STATUS_E_NOMEM; + + disable_uapsd_req_params->sessionid = session_id; + status = sme_post_ps_msg_to_wma(WMA_DISABLE_UAPSD_REQ, + disable_uapsd_req_params); + if (!QDF_IS_STATUS_SUCCESS(status)) + return QDF_STATUS_E_FAILURE; + + sme_debug("Message WMA_DISABLE_UAPSD_REQ Successfully sent to WMA"); + sme_set_ps_state(mac_ctx, session_id, LEGACY_POWER_SAVE_MODE); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_process_command(): Sme process power save messages + * and pass messages to WMA. + * @mac_ctx: global mac context + * @session_id: session id + * sme_ps_cmd: power save message + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_process_command(struct mac_context *mac_ctx, uint32_t session_id, + enum sme_ps_cmd command) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid Session_id: %d", session_id); + return QDF_STATUS_E_INVAL; + } + sme_debug("Vdev id %d, Power Save command %d", session_id, command); + switch (command) { + case SME_PS_ENABLE: + status = sme_ps_enable_ps_req_params(mac_ctx, session_id); + break; + case SME_PS_DISABLE: + status = sme_ps_disable_ps_req_params(mac_ctx, session_id); + break; + case SME_PS_UAPSD_ENABLE: + status = sme_ps_enable_uapsd_req_params(mac_ctx, session_id); + break; + case SME_PS_UAPSD_DISABLE: + status = sme_ps_disable_uapsd_req_params(mac_ctx, session_id); + break; + default: + sme_err("Invalid command type: %d", command); + status = QDF_STATUS_E_FAILURE; + break; + } + if (status != QDF_STATUS_SUCCESS) { + sme_err("Not able to enter in PS, Command: %d", command); + } + return status; +} + +/** + * sme_enable_sta_ps_check(): Checks if it is ok to enable power save or not. + * @mac_ctx: global mac context + * @session_id: session id + * @ command: sme_ps_cmd + * Pre Condition for enabling sta mode power save + * 1) Sta Mode Ps should be enabled in ini file. + * 2) Session should be in infra mode and in connected state. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_enable_sta_ps_check(struct mac_context *mac_ctx, + uint32_t vdev_id, enum sme_ps_cmd command) +{ + bool usr_cfg_ps_enable; + + QDF_BUG(vdev_id < WLAN_MAX_VDEVS); + if (vdev_id >= WLAN_MAX_VDEVS) + return QDF_STATUS_E_INVAL; + + if (!mac_ctx->mlme_cfg->ps_params.is_bmps_enabled) { + sme_debug("vdev:%d power save mode is disabled via ini", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + usr_cfg_ps_enable = mlme_get_user_ps(mac_ctx->psoc, vdev_id); + if (command == SME_PS_ENABLE && !usr_cfg_ps_enable) { + sme_debug("vdev:%d power save mode is disabled by usr(ioctl)", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* + * If command is power save disable there is not need to check for + * connected or roaming state as firmware can handle this + */ + if (command == SME_PS_DISABLE) + return QDF_STATUS_SUCCESS; + + /* If command is power save enable, check whether the given session is + * in connected or roaming state or not + */ + if (!cm_is_vdevid_active(mac_ctx->pdev, vdev_id)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_ps_enable_disable(): function to enable/disable PS. + * @mac_handle: Opaque handle to the global MAC context + * @vdev_id: session id + * sme_ps_cmd: power save message + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_enable_disable(mac_handle_t mac_handle, uint32_t vdev_id, + enum sme_ps_cmd command) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("can't acquire sme global lock"); + return status; + } + + status = sme_enable_sta_ps_check(mac_ctx, vdev_id, command); + if (QDF_IS_STATUS_ERROR(status)) { + /* + * In non associated state driver won't handle the power save + * But kernel expects return status success even in the + * disconnected state. + */ + if (!cm_is_vdevid_active(mac_ctx->pdev, vdev_id)) + status = QDF_STATUS_SUCCESS; + sme_release_global_lock(&mac_ctx->sme); + return status; + } + status = sme_ps_process_command(mac_ctx, vdev_id, command); + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +QDF_STATUS sme_ps_update(mac_handle_t mac_handle, uint32_t vdev_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + bool usr_ps_cfg; + enum sme_ps_cmd command; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("can't acquire sme global lock"); + return status; + } + usr_ps_cfg = mlme_get_user_ps(mac_ctx->psoc, vdev_id); + command = usr_ps_cfg ? SME_PS_ENABLE : SME_PS_DISABLE; + sme_debug("Allow power save %d vdev %d", + usr_ps_cfg, vdev_id); + status = sme_ps_enable_disable(mac_handle, vdev_id, command); + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +#ifdef QCA_WIFI_EMULATION +static +QDF_STATUS sme_ps_set_powersave_disable_auto_timer(mac_handle_t mac_handle, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#else +static +QDF_STATUS sme_ps_set_powersave_disable_auto_timer(mac_handle_t mac_handle, + uint8_t vdev_id) +{ + return sme_ps_disable_auto_ps_timer(mac_handle, + vdev_id); +} +#endif + +QDF_STATUS sme_ps_set_powersave(mac_handle_t mac_handle, + uint8_t vdev_id, bool allow_power_save, + uint32_t timeout, + bool ap_supports_immediate_power_save) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + QDF_STATUS status; + bool is_bmps_enabled; + enum QDF_OPMODE device_mode; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("can't acquire sme global lock"); + return status; + } + sme_debug("Allow power save %d vdev %d timeout %d imm ps %d", + allow_power_save, vdev_id, timeout, + ap_supports_immediate_power_save); + + mlme_set_user_ps(mac_ctx->psoc, vdev_id, allow_power_save); + /* + * This is a workaround for defective AP's that send a disassoc + * immediately after WPS connection completes. Defer powersave by a + * small amount if the affected AP is detected. + */ + device_mode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + if (allow_power_save && + device_mode == QDF_STA_MODE && + !ap_supports_immediate_power_save) { + timeout = AUTO_PS_DEFER_TIMEOUT_MS; + sme_debug("Defer power-save due to AP spec non-conformance"); + } + + if (allow_power_save) { + if (device_mode == QDF_STA_MODE || + device_mode == QDF_P2P_CLIENT_MODE) { + sme_debug("Disabling Auto Power save timer"); + status = sme_ps_disable_auto_ps_timer( + mac_handle, vdev_id); + if (status != QDF_STATUS_SUCCESS) + goto end; + } + + wlan_mlme_is_bmps_enabled(mac_ctx->psoc, &is_bmps_enabled); + if (is_bmps_enabled) { + sme_debug("Wlan driver Entering Power save"); + + /* + * Enter Power Save command received from GUI + * this means DHCP is completed + */ + if (timeout) { + status = sme_ps_enable_auto_ps_timer( + mac_handle, + vdev_id, + timeout); + if (status != QDF_STATUS_SUCCESS) + goto end; + } else { + status = sme_ps_enable_disable( + mac_handle, + vdev_id, + SME_PS_ENABLE); + if (status != QDF_STATUS_SUCCESS) + goto end; + } + } else { + sme_debug("Power Save is not enabled in the cfg"); + } + } else { + sme_debug("Wlan driver Entering Full Power"); + + /* + * Enter Full power command received from GUI + * this means we are disconnected + */ + status = sme_ps_set_powersave_disable_auto_timer(mac_handle, + vdev_id); + if (status != QDF_STATUS_SUCCESS) + goto end; + + wlan_mlme_is_bmps_enabled(mac_ctx->psoc, &is_bmps_enabled); + if (is_bmps_enabled) { + status = sme_ps_enable_disable(mac_handle, + vdev_id, + SME_PS_DISABLE); + if (status != QDF_STATUS_SUCCESS) + goto end; + } + } + +end: + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +QDF_STATUS sme_ps_timer_flush_sync(mac_handle_t mac_handle, uint8_t session_id) +{ + QDF_STATUS status; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct ps_params *ps_parm; + enum ps_state ps_state; + QDF_TIMER_STATE tstate; + struct sEnablePsParams *req; + + QDF_BUG(session_id < WLAN_MAX_VDEVS); + if (session_id >= WLAN_MAX_VDEVS) + return QDF_STATUS_E_INVAL; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("can't acquire sme global lock"); + return status; + } + + status = sme_enable_sta_ps_check(mac_ctx, session_id, SME_PS_ENABLE); + if (QDF_IS_STATUS_ERROR(status)) { + sme_debug("Power save not allowed for vdev id %d", session_id); + status = QDF_STATUS_SUCCESS; + goto end; + } + + ps_parm = &mac_ctx->sme.ps_global_info.ps_params[session_id]; + tstate = qdf_mc_timer_get_current_state(&ps_parm->auto_ps_enable_timer); + if (tstate != QDF_TIMER_STATE_RUNNING) { + status = QDF_STATUS_SUCCESS; + goto end; + } + + sme_debug("flushing powersave enable for vdev %u", session_id); + + qdf_mc_timer_stop(&ps_parm->auto_ps_enable_timer); + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + + if (ps_parm->uapsd_per_ac_bit_mask) { + req->psSetting = eSIR_ADDON_ENABLE_UAPSD; + sme_ps_fill_uapsd_req_params(mac_ctx, &req->uapsdParams, + session_id, &ps_state); + ps_state = UAPSD_MODE; + req->uapsdParams.enable_ps = true; + } else { + req->psSetting = eSIR_ADDON_NOTHING; + ps_state = LEGACY_POWER_SAVE_MODE; + } + req->sessionid = session_id; + + wma_enable_sta_ps_mode(req); + qdf_mem_free(req); + + ps_parm->ps_state = ps_state; +end: + sme_release_global_lock(&mac_ctx->sme); + + return status; +} + +/** + * sme_ps_uapsd_enable(): function to enable UAPSD. + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_uapsd_enable(mac_handle_t mac_handle, uint32_t session_id) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + status = sme_enable_sta_ps_check(mac_ctx, session_id, + SME_PS_UAPSD_ENABLE); + if (status != QDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, + SME_PS_UAPSD_ENABLE); + if (status == QDF_STATUS_SUCCESS) + sme_offload_qos_process_into_uapsd_mode(mac_ctx, session_id); + + return status; +} + +/** + * sme_ps_uapsd_disable(): function to disable UAPSD. + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_uapsd_disable(mac_handle_t mac_handle, uint32_t session_id) +{ + + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + status = sme_enable_sta_ps_check(mac_ctx, session_id, + SME_PS_UAPSD_DISABLE); + if (status != QDF_STATUS_SUCCESS) + return status; + status = sme_ps_process_command(mac_ctx, session_id, + SME_PS_UAPSD_DISABLE); + if (status == QDF_STATUS_SUCCESS) + sme_offload_qos_process_out_of_uapsd_mode(mac_ctx, session_id); + + return status; +} + +/** + * sme_set_tspec_uapsd_mask_per_session(): set tspec UAPSD mask per session + * @mac_ctx: global mac context + * @ts_info: tspec info. + * @session_id: session id + * + * Return: QDF_STATUS + */ +void sme_set_tspec_uapsd_mask_per_session(struct mac_context *mac_ctx, + struct mac_ts_info *ts_info, + uint8_t session_id) +{ + uint8_t user_prio = (uint8_t) ts_info->traffic.userPrio; + uint16_t direction = ts_info->traffic.direction; + uint8_t ac = upToAc(user_prio); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + + sme_debug("Set UAPSD mask for AC: %d dir: %d action: %d", + ac, direction, ts_info->traffic.psb); + + /* Converting AC to appropriate Uapsd Bit Mask + * AC_BE(0) --> UAPSD_BITOFFSET_ACVO(3) + * AC_BK(1) --> UAPSD_BITOFFSET_ACVO(2) + * AC_VI(2) --> UAPSD_BITOFFSET_ACVO(1) + * AC_VO(3) --> UAPSD_BITOFFSET_ACVO(0) + */ + ac = ((~ac) & 0x3); + if (ts_info->traffic.psb) { + ps_param->uapsd_per_ac_bit_mask |= (1 << ac); + if (direction == SIR_MAC_DIRECTION_UPLINK) + ps_param->uapsd_per_ac_trigger_enable_mask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + ps_param->uapsd_per_ac_delivery_enable_mask |= + (1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->uapsd_per_ac_trigger_enable_mask |= + (1 << ac); + ps_param->uapsd_per_ac_delivery_enable_mask |= + (1 << ac); + } + } else { + ps_param->uapsd_per_ac_bit_mask &= ~(1 << ac); + if (direction == SIR_MAC_DIRECTION_UPLINK) + ps_param->uapsd_per_ac_trigger_enable_mask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_DNLINK) + ps_param->uapsd_per_ac_delivery_enable_mask &= + ~(1 << ac); + else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->uapsd_per_ac_trigger_enable_mask &= + ~(1 << ac); + ps_param->uapsd_per_ac_delivery_enable_mask &= + ~(1 << ac); + } + } + + /* + * ADDTS success, so AC is now admitted. We shall now use the default + * EDCA parameters as advertised by AP and send the updated EDCA params + * to HAL. + */ + if (direction == SIR_MAC_DIRECTION_UPLINK) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + } else if (direction == SIR_MAC_DIRECTION_DNLINK) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } else if (direction == SIR_MAC_DIRECTION_BIDIR) { + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK] |= + (1 << ac); + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_DNLINK] |= + (1 << ac); + } + + sme_debug("New ps_param->uapsd_per_ac_trigger_enable_mask: 0x%x", + ps_param->uapsd_per_ac_trigger_enable_mask); + sme_debug("New ps_param->uapsd_per_ac_delivery_enable_mask: 0x%x", + ps_param->uapsd_per_ac_delivery_enable_mask); + sme_debug("New ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK]: 0x%x", + ps_param->ac_admit_mask[SIR_MAC_DIRECTION_UPLINK]); +} + +/** + * sme_ps_start_uapsd(): function to start UAPSD. + * @mac_handle: Opaque handle to the global MAC context + * @session_id: session id + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_ps_start_uapsd(mac_handle_t mac_handle, uint32_t session_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + status = sme_ps_uapsd_enable(mac_handle, session_id); + return status; +} + +/** + * sme_set_ps_host_offload(): Set the host offload feature. + * @mac_handle - The handle returned by mac_open. + * @request - Pointer to the offload request. + * + * Return QDF_STATUS + * QDF_STATUS_E_FAILURE Cannot set the offload. + * QDF_STATUS_SUCCESS Request accepted. + */ +QDF_STATUS sme_set_ps_host_offload(mac_handle_t mac_handle, + struct sir_host_offload_req *request, + uint8_t session_id) +{ + struct sir_host_offload_req *request_buf; + struct scheduler_msg msg = {0}; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + + sme_debug("IP address = %d.%d.%d.%d", + request->params.hostIpv4Addr[0], + request->params.hostIpv4Addr[1], + request->params.hostIpv4Addr[2], + request->params.hostIpv4Addr[3]); + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session is invalid"); + return QDF_STATUS_E_INVAL; + } + + request_buf = qdf_mem_malloc(sizeof(struct sir_host_offload_req)); + if (!request_buf) + return QDF_STATUS_E_NOMEM; + + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, session_id, + &request->bssid); + qdf_mem_copy(request_buf, request, sizeof(struct sir_host_offload_req)); + + msg.type = WMA_SET_HOST_OFFLOAD; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err("Not able to post WMA_SET_HOST_OFFLOAD msg to WMA"); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_NS_OFFLOAD +/** + * sme_set_ps_ns_offload(): Set the host offload feature. + * @mac_handle - The handle returned by mac_open. + * @request - Pointer to the offload request. + * + * Return QDF_STATUS + * QDF_STATUS_E_FAILURE Cannot set the offload. + * QDF_STATUS_SUCCESS Request accepted. + */ +QDF_STATUS sme_set_ps_ns_offload(mac_handle_t mac_handle, + struct sir_host_offload_req *request, + uint8_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct sir_host_offload_req *request_buf; + struct scheduler_msg msg = {0}; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("CSR session is invalid"); + return QDF_STATUS_E_INVAL; + } + + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, session_id, + &request->bssid); + + request_buf = qdf_mem_malloc(sizeof(*request_buf)); + if (!request_buf) + return QDF_STATUS_E_NOMEM; + + *request_buf = *request; + + msg.type = WMA_SET_NS_OFFLOAD; + msg.reserved = 0; + msg.bodyptr = request_buf; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + session_id, msg.type)); + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + sme_err( + "Not able to post SIR_HAL_SET_HOST_OFFLOAD message to HAL"); + qdf_mem_free(request_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_NS_OFFLOAD */ +/** + * sme_post_pe_message + * + * FUNCTION: + * Post a message to the pmm message queue + * + * LOGIC: + * + * ASSUMPTIONS: + * + * NOTE: + * + * @param msg pointer to message + * @return None + */ + +QDF_STATUS sme_post_pe_message(struct mac_context *mac_ctx, + struct scheduler_msg *msg) +{ + QDF_STATUS qdf_status; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("scheduler_post_msg failed with status: %d", + qdf_status); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef QCA_WIFI_EMULATION +static QDF_STATUS sme_ps_scale_auto_ps_timeout(uint32_t timeout) +{ + return AUTO_PS_EMULATION_TIMEOUT; +} +#else +static QDF_STATUS sme_ps_scale_auto_ps_timeout(uint32_t timeout) +{ + return timeout; +} +#endif + +QDF_STATUS sme_ps_enable_auto_ps_timer(mac_handle_t mac_handle, + uint32_t session_id, uint32_t timeout) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + QDF_STATUS qdf_status; + QDF_TIMER_STATE cur_state; + bool usr_cfg_ps_enable; + + usr_cfg_ps_enable = + mlme_get_user_ps(mac_ctx->psoc, session_id); + if (!timeout && !usr_cfg_ps_enable) { + sme_debug("auto_ps_timer called with timeout 0; ignore"); + return QDF_STATUS_SUCCESS; + } + if (!timeout) + timeout = AUTO_PS_ENTRY_TIMER_DEFAULT_VALUE; + + cur_state = + qdf_mc_timer_get_current_state(&ps_param->auto_ps_enable_timer); + if (cur_state == QDF_TIMER_STATE_STARTING || + cur_state == QDF_TIMER_STATE_RUNNING) { + sme_debug("auto_ps_timer is already started: %d", cur_state); + return QDF_STATUS_SUCCESS; + } + + timeout = sme_ps_scale_auto_ps_timeout(timeout); + sme_debug("Start auto_ps_timer for %d ms", timeout); + qdf_status = qdf_mc_timer_start(&ps_param->auto_ps_enable_timer, + timeout); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + if (QDF_STATUS_E_ALREADY == qdf_status) { + /* Consider this ok since the timer is already started*/ + sme_debug("auto_ps_timer is already started"); + } else { + sme_err("Cannot start auto_ps_timer"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_ps_disable_auto_ps_timer(mac_handle_t mac_handle, + uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param; + + if (!sme_is_session_id_valid(mac_handle, session_id)) + return QDF_STATUS_SUCCESS; + + ps_param = &ps_global_info->ps_params[session_id]; + /* + * Stop the auto ps entry timer if running + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) { + sme_debug("Stop auto_ps_enable_timer Timer for session ID: %d", + session_id); + qdf_mc_timer_stop(&ps_param->auto_ps_enable_timer); + } + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS sme_ps_open(mac_handle_t mac_handle) +{ + uint32_t i; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + mlme_set_user_ps(mac->psoc, i, true); + + if (QDF_STATUS_SUCCESS != sme_ps_open_per_session(mac_handle, + i)) { + sme_err("PMC Init Failed for session: %d", i); + return QDF_STATUS_E_FAILURE; + } + } + return QDF_STATUS_SUCCESS; +} + + +QDF_STATUS sme_ps_open_per_session(mac_handle_t mac_handle, uint32_t session_id) +{ + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + + ps_param->session_id = session_id; + ps_param->mac_ctx = mac_ctx; + /* Allocate a timer to enable ps automatically */ + if (!QDF_IS_STATUS_SUCCESS(qdf_mc_timer_init( + &ps_param->auto_ps_enable_timer, + QDF_TIMER_TYPE_SW, + sme_auto_ps_entry_timer_expired, + ps_param))) { + sme_err("Cannot allocate timer for auto ps entry"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; + +} + +void sme_auto_ps_entry_timer_expired(void *data) +{ + struct ps_params *ps_params = (struct ps_params *)data; + struct mac_context *mac_ctx; + uint32_t session_id; + QDF_STATUS status; + + if (!ps_params) { + sme_err("ps_params is NULL"); + return; + } + mac_ctx = (struct mac_context *)ps_params->mac_ctx; + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + return; + } + status = sme_acquire_global_lock(&mac_ctx->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("can't acquire sme global lock"); + return; + } + + session_id = ps_params->session_id; + sme_debug("auto_ps_timer expired, enabling powersave"); + + status = sme_enable_sta_ps_check(mac_ctx, session_id, SME_PS_ENABLE); + if (QDF_STATUS_SUCCESS == status) + sme_ps_enable_disable(MAC_HANDLE(mac_ctx), session_id, + SME_PS_ENABLE); + sme_release_global_lock(&mac_ctx->sme); +} + +QDF_STATUS sme_ps_close(mac_handle_t mac_handle) +{ + uint32_t i; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) + sme_ps_close_per_session(mac_handle, i); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_ps_close_per_session(mac_handle_t mac_handle, + uint32_t session_id) +{ + + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + struct ps_global_info *ps_global_info = &mac_ctx->sme.ps_global_info; + struct ps_params *ps_param = &ps_global_info->ps_params[session_id]; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + /* + * Stop the auto ps entry timer if running + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &ps_param->auto_ps_enable_timer)) + qdf_mc_timer_stop(&ps_param->auto_ps_enable_timer); + + qdf_status = + qdf_mc_timer_destroy(&ps_param->auto_ps_enable_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sme_err("Cannot deallocate suto PS timer"); + return qdf_status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_trace.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_trace.c new file mode 100644 index 0000000000..69e2cf9b8e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/common/sme_trace.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: smeTrace.c + * Implementation for trace related APIs + * + * Author Kiran Kumar Reddy CH L V + */ +#include "ani_global.h" /* for struct mac_context **/ +#include "mac_trace.h" +#include "sme_trace.h" +#include "sme_internal.h" +#ifndef SME_TRACE_RECORD +void sme_trace_init(struct mac_context *mac) +{ + +} +#endif +#ifdef SME_TRACE_RECORD + +static uint8_t *sme_trace_get_rx_msg_string(uint32_t code) +{ + switch (code) { + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_GET_RESULTS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_CONNECT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SET_11DINFO); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_GET_SOFTAP_DOMAIN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SET_REGINFO); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CHANNEL_CONFIG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_UPDATE_CONFIG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_HDDREADYIND); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_RESULTS); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_FLUSH_P2PRESULTS); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETFIRST); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_GETNEXT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_SCAN_RESULT_PURGE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_REASSOC); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_DISCONNECT); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_ROAM_GET_CONNECTPROFILE); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_ROAM_FREE_CONNECTPROFILE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_SET_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_DEL_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ROAM_GET_PMKIDCACHE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CONFIGPARAM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_MODPROFFIELDS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CONFIG_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CONFIG_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ENABLE_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DISABLE_PWRSAVE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SIGNAL_POWER_EVENT); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_START_AUTO_BMPSTIMER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_STOP_AUTO_BMPSTIMER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_IS_PWRSAVE_ENABLED); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_FULLPOWER); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_BMPS); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_DHCP_FLAG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REQUEST_STANDBY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_WOWL_ADDBCAST_PATTERN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_WOWL_DELBCAST_PATTERN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ENTER_WOWL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_EXIT_WOWL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_KEY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REMOVE_KEY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CNTRYCODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_CFGPRIVACY); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_NEIGHBOR_REPORTREQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_READREG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_WRITEREG); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_READMEM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DBG_WRITEMEM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_OPEN_SESSION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CLOSE_SESSION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_HOSTOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_GTKOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_GTKOFFLOAD); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ABORT_MACSCAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REGISTER_MGMTFR); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DEREGISTER_MGMTFR); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_REMAIN_ONCHAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SEND_ACTION); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CANCEL_REMAIN_ONCHAN); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_RXPFIL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_SUSPENDIND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_RESUMEREQ); +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_EXTWOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE1); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CONFIG_APP_TYPE2); +#endif + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_MAXTXPOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_TXPOW); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_TMLEVEL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CAPS_EXCH); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_DISABLE_CAP); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_DEFCCNV); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_GET_CURCC); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_RESET_PW5G); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_RP5G); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_ROAMIBAND); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_RSSIDIFF); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_IMMRSSIDIFF); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_FTENABLED); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_WESMODE); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_SET_SCANCTRL); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_UPDATE_P2P_IE); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_N_PROBES); + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_UPDATE_ROAM_SCAN_HOME_AWAY_TIME); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_STORE_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_CLEAR_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_ISSUE_JOIN_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_MSG_DEAUTH_STA); +#ifdef FEATURE_WLAN_TDLS + CASE_RETURN_STRING + (TRACE_CODE_SME_RX_HDD_TDLS_LINK_ESTABLISH_PARAM); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_CHAN_SWITCH_REQ); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_SEND_MGMT_FRAME); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_CHANGE_PEER_STA); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_ADD_PEER_STA); + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_TDLS_DEL_PEER_STA); +#endif + CASE_RETURN_STRING(TRACE_CODE_SME_RX_HDD_PREF_NET_LIST); + default: + return "UNKNOWN"; + } +} + +static uint8_t *sme_trace_get_command_string(uint32_t command) +{ + switch (command) { + CASE_RETURN_STRING(eSmeNoCommand); + CASE_RETURN_STRING(eSmeCsrCommandMask); + CASE_RETURN_STRING(eSmeCommandRoam); + CASE_RETURN_STRING(eSmeCommandWmStatusChange); + CASE_RETURN_STRING(eSmeQosCommandMask); + CASE_RETURN_STRING(eSmeCommandAddTs); + CASE_RETURN_STRING(eSmeCommandDelTs); + CASE_RETURN_STRING(e_sme_command_set_hw_mode); + CASE_RETURN_STRING(e_sme_command_nss_update); + CASE_RETURN_STRING(e_sme_command_set_dual_mac_config); + CASE_RETURN_STRING(e_sme_command_set_antenna_mode); + CASE_RETURN_STRING(e_sme_command_sap_ch_width_update); + default: + return "UNKNOWN"; + } +} + +static void sme_trace_dump(void *mac_ctx, tp_qdf_trace_record record, + uint16_t rec_index) +{ + switch (record->code) { + case TRACE_CODE_SME_COMMAND: + sme_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, + record->session, "SME COMMAND:", + sme_trace_get_command_string(record->data), + record->data); + break; + case TRACE_CODE_SME_TX_WMA_MSG: + sme_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, + record->session, "TX WMA Msg:", + mac_trace_get_wma_msg_string((uint16_t)record->data), + record->data); + break; + case TRACE_CODE_SME_RX_WMA_MSG: + sme_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, record->session, + "RX WMA Msg:", + mac_trace_get_sme_msg_string((uint16_t)record->data), + record->data); + break; + default: + sme_nofl_debug("%04d %012llu %s S%d %-14s %-30s(0x%x)", + rec_index, record->qtime, record->time, record->session, + "RX HDD MSG:", + sme_trace_get_rx_msg_string(record->code), + record->data); + break; + } +} + +void sme_trace_init(struct mac_context *mac) +{ + qdf_trace_register(QDF_MODULE_ID_SME, &sme_trace_dump); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_api_roam.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_api_roam.c new file mode 100644 index 0000000000..a4854f6452 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_api_roam.c @@ -0,0 +1,8218 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: csr_api_roam.c + * + * Implementation for the Common Roaming interfaces. + */ +#include "ani_global.h" /* for struct mac_context **/ +#include "wma_types.h" +#include "wma_if.h" /* for STA_INVALID_IDX. */ +#include "csr_inside_api.h" +#include +#include "sme_trace.h" +#include "sme_qos_internal.h" +#include "sme_inside.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#include "csr_api.h" +#include "csr_internal.h" +#include "cds_reg_service.h" +#include "mac_trace.h" +#include "cds_regdomain.h" +#include "cds_utils.h" +#include "sir_types.h" +#include "cfg_ucfg_api.h" +#include "sme_power_save_api.h" +#include "wma.h" +#include "wlan_policy_mgr_api.h" +#include "sme_nan_datapath.h" +#include "pld_common.h" +#include "wlan_reg_services_api.h" +#include "qdf_crypto.h" +#include +#include "wlan_objmgr_psoc_obj.h" +#include +#include +#include +#include +#include +#include +#include +#include "wlan_mlme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include +#include "cfg_mlme.h" +#include "wlan_mlme_public_struct.h" +#include +#include "wlan_qct_sys.h" +#include "wlan_dlm_api.h" +#include "wlan_policy_mgr_i.h" +#include "wlan_scan_utils_api.h" +#include "wlan_p2p_cfg_api.h" +#include "cfg_nan_api.h" +#include "nan_ucfg_api.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include "wlan_reg_ucfg_api.h" + +#include +#include "wlan_pkt_capture_ucfg_api.h" +#include "wlan_psoc_mlme_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_if_mgr_public_struct.h" +#include "wlan_if_mgr_ucfg_api.h" +#include "wlan_if_mgr_roam.h" +#include "wlan_roam_debug.h" +#include "wlan_cm_roam_public_struct.h" +#include "wlan_mlme_twt_api.h" +#include +#include +#include "wlan_mlo_mgr_sta.h" +#include "wlan_mlo_mgr_roam.h" + +#define MAX_PWR_FCC_CHAN_12 8 +#define MAX_PWR_FCC_CHAN_13 2 +#define MAX_CB_VALUE_IN_INI (2) + +#define MAX_SOCIAL_CHANNELS 3 + +/* packet dump timer duration of 60 secs */ +#define PKT_DUMP_TIMER_DURATION 60 + +#ifdef WLAN_FEATURE_SAE +/** + * csr_sae_callback - Update SAE info to CSR roam session + * @mac_ctx: MAC context + * @msg_ptr: pointer to SAE message + * + * API to update SAE info to roam csr session + * + * Return: QDF_STATUS + */ +static QDF_STATUS csr_sae_callback(struct mac_context *mac_ctx, + tSirSmeRsp *msg_ptr) +{ + struct csr_roam_info *roam_info; + uint32_t session_id; + struct sir_sae_info *sae_info; + + sae_info = (struct sir_sae_info *) msg_ptr; + if (!sae_info) { + sme_err("SAE info is NULL"); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("vdev_id %d "QDF_MAC_ADDR_FMT, + sae_info->vdev_id, + QDF_MAC_ADDR_REF(sae_info->peer_mac_addr.bytes)); + + session_id = sae_info->vdev_id; + if (session_id == WLAN_UMAC_VDEV_ID_MAX) + return QDF_STATUS_E_INVAL; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_FAILURE; + + roam_info->sae_info = sae_info; + + csr_roam_call_callback(mac_ctx, session_id, roam_info, + eCSR_ROAM_SAE_COMPUTE, eCSR_ROAM_RESULT_NONE); + qdf_mem_free(roam_info); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS csr_sae_callback(struct mac_context *mac_ctx, + tSirSmeRsp *msg_ptr) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +static const uint32_t +social_channel_freq[MAX_SOCIAL_CHANNELS] = { 2412, 2437, 2462 }; + +static void init_config_param(struct mac_context *mac); +static QDF_STATUS csr_roam_open(struct mac_context *mac); +static QDF_STATUS csr_roam_close(struct mac_context *mac); +static QDF_STATUS csr_init11d_info(struct mac_context *mac, tCsr11dinfo *ps11dinfo); +static QDF_STATUS csr_init_channel_power_list(struct mac_context *mac, + tCsr11dinfo *ps11dinfo); +static QDF_STATUS csr_roam_free_connected_info(struct mac_context *mac, + struct csr_roam_connectedinfo * + pConnectedInfo); +static void csr_init_session(struct mac_context *mac, uint32_t sessionId); + +static void csr_init_operating_classes(struct mac_context *mac); + +static void csr_add_len_of_social_channels(struct mac_context *mac, + uint8_t *num_chan); +static void csr_add_social_channels(struct mac_context *mac, + tSirUpdateChanList *chan_list, struct csr_scanstruct *pScan, + uint8_t *num_chan); + +#ifdef WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +static struct csr_roam_session *csr_roam_roam_session; + +/* Allocate and initialize global variables */ +static QDF_STATUS csr_roam_init_globals(struct mac_context *mac) +{ + uint32_t buf_size; + QDF_STATUS status; + + buf_size = WLAN_MAX_VDEVS * sizeof(struct csr_roam_session); + + csr_roam_roam_session = qdf_mem_malloc(buf_size); + if (csr_roam_roam_session) { + mac->roam.roamSession = csr_roam_roam_session; + status = QDF_STATUS_SUCCESS; + } else { + status = QDF_STATUS_E_NOMEM; + } + + return status; +} + +/* Free memory allocated dynamically */ +static inline void csr_roam_free_globals(void) +{ + qdf_mem_free(csr_roam_roam_session); + csr_roam_roam_session = NULL; +} + +#else /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ +static struct csr_roam_session csr_roam_roam_session[WLAN_MAX_VDEVS]; + +/* Initialize global variables */ +static QDF_STATUS csr_roam_init_globals(struct mac_context *mac) +{ + qdf_mem_zero(&csr_roam_roam_session, + sizeof(csr_roam_roam_session)); + mac->roam.roamSession = csr_roam_roam_session; + + return QDF_STATUS_SUCCESS; +} + +static inline void csr_roam_free_globals(void) +{ +} +#endif /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ + +static void csr_roam_de_init_globals(struct mac_context *mac) +{ + csr_roam_free_globals(); + mac->roam.roamSession = NULL; +} + +/** + * csr_roam_lost_link - Process lost link indication + * @mac: MAC context + * @session_id: Session id of the current session + * @type: Type of the indication + * @sir_msg: sme response message + * + * Return: QDF_STATUS + */ +static +QDF_STATUS csr_roam_lost_link(struct mac_context *mac, uint32_t session_id, + uint32_t type, tSirSmeRsp *sir_msg) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct deauth_ind *deauth_ind_msg = NULL; + struct disassoc_ind *disassoc_ind_msg = NULL; + + sme_debug("vdev_id %d type %d ", session_id, type); + + if (type == eWNI_SME_DISASSOC_IND) { + disassoc_ind_msg = (struct disassoc_ind *)sir_msg; + status = csr_send_mb_disassoc_cnf_msg(mac, disassoc_ind_msg); + } else if (type == eWNI_SME_DEAUTH_IND) { + deauth_ind_msg = (struct deauth_ind *)sir_msg; + status = csr_send_mb_deauth_cnf_msg(mac, deauth_ind_msg); + } + + return status; +} + +/** + * csr_process_deauth_disassoc_cmd - Process deauth/disassoc command + * @mac: MAC context + * @sme_cmd: sme command which needs to be processed + * + * This function processes deauth or disassoc command + * + * Return: None + */ +static void csr_process_deauth_disassoc_cmd(struct mac_context *mac, + tSmeCmd *sme_cmd) +{ + if (sme_cmd->u.roamCmd.roamReason == eCsrForcedDisassocSta) { + sme_debug("Disassoc vdev_id %d with reason: %d peer " + QDF_MAC_ADDR_FMT, sme_cmd->vdev_id, + sme_cmd->u.roamCmd.reason, + QDF_MAC_ADDR_REF(sme_cmd->u.roamCmd.peerMac)); + csr_send_mb_disassoc_req_msg(mac, sme_cmd->vdev_id, + sme_cmd->u.roamCmd.peerMac, + sme_cmd->u.roamCmd.reason); + } else if (sme_cmd->u.roamCmd.roamReason == eCsrForcedDeauthSta) { + sme_debug("Deauth vdev_id %d with reason: %d peer " + QDF_MAC_ADDR_FMT, sme_cmd->vdev_id, + sme_cmd->u.roamCmd.reason, + QDF_MAC_ADDR_REF(sme_cmd->u.roamCmd.peerMac)); + csr_send_mb_deauth_req_msg(mac, sme_cmd->vdev_id, + sme_cmd->u.roamCmd.peerMac, + sme_cmd->u.roamCmd.reason); + } else { + sme_info("Invalid command, vdev_id %d reason: %d peer " + QDF_MAC_ADDR_FMT, sme_cmd->vdev_id, + sme_cmd->u.roamCmd.reason, + QDF_MAC_ADDR_REF(sme_cmd->u.roamCmd.peerMac)); + } +} + +/** + * csr_process_wmm_status_change_cmd - Process wmm status change command + * @mac: MAC context + * @sme_cmd: sme command which needs to be processed + * + * Return: None + */ +static void csr_process_wmm_status_change_cmd(struct mac_context *mac, + tSmeCmd *sme_cmd) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tSirSmeRsp *sir_msg; + + if (sme_cmd->u.wmStatusChangeCmd.Type == eCsrDisassociated) { + sir_msg = + (tSirSmeRsp *)&sme_cmd->u.wmStatusChangeCmd.u. + DisassocIndMsg; + status = csr_roam_lost_link(mac, sme_cmd->vdev_id, + eWNI_SME_DISASSOC_IND, + sir_msg); + } else if (sme_cmd->u.wmStatusChangeCmd.Type == eCsrDeauthenticated) { + sir_msg = (tSirSmeRsp *)&sme_cmd->u.wmStatusChangeCmd.u. + DeauthIndMsg; + status = csr_roam_lost_link(mac, sme_cmd->vdev_id, + eWNI_SME_DEAUTH_IND, + sir_msg); + } + if (QDF_IS_STATUS_ERROR(status)) { + sme_info("Failed to issue lost link command, status %d", + status); + /* + * As status returned is not success, there is nothing else + * left to do so release WM status change command here. + */ + csr_roam_wm_status_change_complete(mac, sme_cmd->vdev_id); + } +} + +/** + * csr_get_active_peer_disconnect_command - Get active peer disconnect command + * from serialization. + * @mac: MAC context + * @vdev_id: Vdev id for which active command needs to be return + * + * Return: None + */ +static tSmeCmd *csr_get_active_peer_disconnect_command(struct mac_context *mac, + uint8_t vdev_id) +{ + tSmeCmd *sme_cmd; + + sme_cmd = wlan_serialization_get_active_cmd( + mac->psoc, vdev_id, + WLAN_SER_CMD_FORCE_DEAUTH_STA); + if (sme_cmd) + return sme_cmd; + + sme_cmd = wlan_serialization_get_active_cmd( + mac->psoc, vdev_id, + WLAN_SER_CMD_FORCE_DISASSOC_STA); + if (sme_cmd) + return sme_cmd; + + return wlan_serialization_get_active_cmd(mac->psoc, vdev_id, + WLAN_SER_CMD_WM_STATUS_CHANGE); +} + +/** + * csr_continue_peer_disconnect_after_get_stats - Continue peer disconnect after + * getting peer disconnect stats + * @mac: MAC context + * + * Process the active serialization command after getting disconnect peer + * stats or after peer stats request gets timed out + * + * Return: None + */ +static void +csr_continue_peer_disconnect_after_get_stats(struct mac_context *mac) +{ + tSmeCmd *sme_cmd; + QDF_STATUS status; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(mac->psoc); + if (!mlme_obj) { + sme_err("NULL mlme psoc object"); + return; + } + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("can't acquire sme global lock"); + return; + } + + sme_cmd = csr_get_active_peer_disconnect_command( + mac, + mlme_obj->disconnect_stats_param.vdev_id); + if (!sme_cmd) { + sme_err("sme_cmd is NULL"); + goto release_lock; + } + + if (qdf_atomic_inc_return( + &mlme_obj->disconnect_stats_param.is_disconn_stats_completed) > + 1) { + sme_info("Command %d already in process", sme_cmd->command); + goto release_lock; + } + + switch (sme_cmd->command) { + case eSmeCommandRoam: + csr_process_deauth_disassoc_cmd(mac, sme_cmd); + break; + + case eSmeCommandWmStatusChange: + csr_process_wmm_status_change_cmd(mac, sme_cmd); + break; + default: + sme_info("Invalid command %d vdev_id %d", sme_cmd->command, + mlme_obj->disconnect_stats_param.vdev_id); + } +release_lock: + sme_release_global_lock(&mac->sme); +} + +/** + * csr_disconnect_stats_timer_cb - Disconnect stats timer callback + * @user_data: Void pointer to mac context + * + * Return: None + */ +static void csr_disconnect_stats_timer_cb(void *user_data) +{ + struct mac_context *mac = (struct mac_context *)user_data; + + if (!mac) { + sme_err("Invalid mac ctx"); + return; + } + + sme_debug("Disconnect peer stats timed out"); + csr_continue_peer_disconnect_after_get_stats(mac); +} + +/** + * csr_init_disconnect_stats_timer - Init Disconnect stats timer + * @mac: MAC context + * + * Return: None + */ +static void csr_init_disconnect_stats_timer(struct mac_context *mac) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(mac->psoc); + if (!mlme_obj) { + sme_err("NULL mlme psoc object"); + return; + } + + qdf_mc_timer_init(&mlme_obj->disconnect_stats_param.disconn_stats_timer, + QDF_TIMER_TYPE_SW, + csr_disconnect_stats_timer_cb, mac); + + qdf_atomic_init( + &mlme_obj->disconnect_stats_param.is_disconn_stats_completed); +} + +/** + * csr_deinit_disconnect_stats_timer - Deinit Disconnect stats timer + * @mac: MAC context + * + * Return: None + */ +static void csr_deinit_disconnect_stats_timer(struct mac_context *mac) +{ + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(mac->psoc); + if (!mlme_obj) { + sme_err("NULL mlme psoc object"); + return; + } + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state( + &mlme_obj->disconnect_stats_param.disconn_stats_timer)) + qdf_mc_timer_stop( + &mlme_obj->disconnect_stats_param.disconn_stats_timer); + + qdf_mc_timer_destroy( + &mlme_obj->disconnect_stats_param.disconn_stats_timer); +} + +QDF_STATUS csr_open(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + do { + /* Initialize CSR Roam Globals */ + status = csr_roam_init_globals(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) + csr_roam_state_change(mac, eCSR_ROAMING_STATE_STOP, i); + + init_config_param(mac); + status = csr_scan_open(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_free_globals(); + break; + } + status = csr_roam_open(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + csr_roam_free_globals(); + break; + } + csr_init_disconnect_stats_timer(mac); + } while (0); + + return status; +} + +QDF_STATUS csr_init_chan_list(struct mac_context *mac) +{ + QDF_STATUS status; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + wlan_reg_read_current_country(mac->psoc, reg_cc); + sme_debug("init time country code %.2s", reg_cc); + + status = csr_get_channel_and_power_list(mac); + + return status; +} + +QDF_STATUS csr_set_channels(struct mac_context *mac, + struct csr_config_params *pParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t index = 0; + + for (index = 0; index < mac->scan.base_channels.numChannels; + index++) { + pParam->Csr11dinfo.Channels.channel_freq_list[index] = + mac->scan.base_channels.channel_freq_list[index]; + pParam->Csr11dinfo.ChnPower[index].first_chan_freq = + mac->scan.base_channels.channel_freq_list[index]; + pParam->Csr11dinfo.ChnPower[index].numChannels = 1; + pParam->Csr11dinfo.ChnPower[index].maxtxPower = + mac->scan.defaultPowerTable[index].tx_power; + } + pParam->Csr11dinfo.Channels.numChannels = + mac->scan.base_channels.numChannels; + + return status; +} + +QDF_STATUS csr_close(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_deinit_disconnect_stats_timer(mac); + + csr_roam_close(mac); + csr_scan_close(mac); + /* DeInit Globals */ + csr_roam_de_init_globals(mac); + return status; +} + +static int8_t +csr_find_channel_pwr(struct channel_power *pdefaultPowerTable, + uint32_t chan_freq) +{ + uint8_t i; + /* TODO: if defaultPowerTable is guaranteed to be in ascending */ + /* order of channel numbers, we can employ binary search */ + for (i = 0; i < CFG_VALID_CHANNEL_LIST_LEN; i++) { + if (pdefaultPowerTable[i].center_freq == chan_freq) + return pdefaultPowerTable[i].tx_power; + } + /* could not find the channel list in default list */ + /* this should not have occurred */ + QDF_ASSERT(0); + return 0; +} + +/** + * csr_roam_arrange_ch_list() - Updates the channel list modified with greedy + * order for 5 Ghz preference and DFS channels. + * @mac_ctx: pointer to mac context. + * @chan_list: channel list updated with greedy channel order. + * @num_channel: Number of channels in list + * + * To allow Early Stop Roaming Scan feature to co-exist with 5G preference, + * this function moves 5G channels ahead of 2G channels. This function can + * also move 2G channels, ahead of DFS channel or vice versa. Order is + * maintained among same category channels + * + * Return: None + */ +static void csr_roam_arrange_ch_list(struct mac_context *mac_ctx, + tSirUpdateChanParam *chan_list, uint8_t num_channel) +{ + bool prefer_5g = CSR_IS_ROAM_PREFER_5GHZ(mac_ctx); + bool prefer_dfs = CSR_IS_DFS_CH_ROAM_ALLOWED(mac_ctx); + int i, j = 0; + tSirUpdateChanParam *tmp_list = NULL; + + if (!prefer_5g) + return; + + tmp_list = qdf_mem_malloc(sizeof(tSirUpdateChanParam) * num_channel); + if (!tmp_list) + return; + + /* Fist copy Non-DFS 5g channels */ + for (i = 0; i < num_channel; i++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_list[i].freq) && + !wlan_reg_is_dfs_for_freq(mac_ctx->pdev, + chan_list[i].freq)) { + qdf_mem_copy(&tmp_list[j++], + &chan_list[i], sizeof(tSirUpdateChanParam)); + chan_list[i].freq = 0; + } + } + if (prefer_dfs) { + /* next copy DFS channels (remaining channels in 5G) */ + for (i = 0; i < num_channel; i++) { + if (WLAN_REG_IS_5GHZ_CH_FREQ(chan_list[i].freq)) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].freq = 0; + } + } + } else { + /* next copy 2G channels */ + for (i = 0; i < num_channel; i++) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(chan_list[i].freq)) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].freq = 0; + } + } + } + /* copy rest of the channels in same order to tmp list */ + for (i = 0; i < num_channel; i++) { + if (chan_list[i].freq) { + qdf_mem_copy(&tmp_list[j++], &chan_list[i], + sizeof(tSirUpdateChanParam)); + chan_list[i].freq = 0; + } + } + /* copy tmp list to original channel list buffer */ + qdf_mem_copy(chan_list, tmp_list, + sizeof(tSirUpdateChanParam) * num_channel); + qdf_mem_free(tmp_list); +} + +/** + * csr_roam_sort_channel_for_early_stop() - Sort the channels + * @mac_ctx: mac global context + * @chan_list: Original channel list from the upper layers + * @num_channel: Number of original channels + * + * For Early stop scan feature, the channel list should be in an order, + * where-in there is a maximum chance to detect an AP in the initial + * channels in the list so that the scanning can be stopped early as the + * feature demands. + * Below fixed greedy channel list has been provided + * based on most of the enterprise wifi installations across the globe. + * + * Identify all the greedy channels within the channel list from user space. + * Identify all the non-greedy channels in the user space channel list. + * Merge greedy channels followed by non-greedy channels back into the + * chan_list. + * + * Return: None + */ +static void csr_roam_sort_channel_for_early_stop(struct mac_context *mac_ctx, + tSirUpdateChanList *chan_list, uint8_t num_channel) +{ + tSirUpdateChanList *chan_list_greedy, *chan_list_non_greedy; + uint8_t i, j; + static const uint32_t fixed_greedy_freq_list[] = {2412, 2437, 2462, + 5180, 5240, 5200, 5220, 2457, 2417, 2452, 5745, 5785, 5805, + 2422, 2427, 2447, 5765, 5825, 2442, 2432, 5680, 5700, 5260, + 5580, 5280, 5520, 5320, 5300, 5500, 5600, 2472, 2484, 5560, + 5660, 5755, 5775}; + uint8_t num_fixed_greedy_chan; + uint8_t num_greedy_chan = 0; + uint8_t num_non_greedy_chan = 0; + uint8_t match_found = false; + uint32_t buf_size; + + buf_size = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * num_channel); + chan_list_greedy = qdf_mem_malloc(buf_size); + chan_list_non_greedy = qdf_mem_malloc(buf_size); + if (!chan_list_greedy || !chan_list_non_greedy) + goto scan_list_sort_error; + /* + * fixed_greedy_freq_list is an evaluated freq list based on most of + * the enterprise wifi deployments and the order of the channels + * determines the highest possibility of finding an AP. + * chan_list is the channel list provided by upper layers based on the + * regulatory domain. + */ + num_fixed_greedy_chan = sizeof(fixed_greedy_freq_list) / + sizeof(uint32_t); + /* + * Browse through the chan_list and put all the non-greedy channels + * into a separate list by name chan_list_non_greedy + */ + for (i = 0; i < num_channel; i++) { + for (j = 0; j < num_fixed_greedy_chan; j++) { + if (chan_list->chanParam[i].freq == + fixed_greedy_freq_list[j]) { + match_found = true; + break; + } + } + if (!match_found) { + qdf_mem_copy( + &chan_list_non_greedy->chanParam[num_non_greedy_chan], + &chan_list->chanParam[i], + sizeof(tSirUpdateChanParam)); + num_non_greedy_chan++; + } else { + match_found = false; + } + } + /* + * Browse through the fixed_greedy_chan_list and put all the greedy + * channels in the chan_list into a separate list by name + * chan_list_greedy + */ + for (i = 0; i < num_fixed_greedy_chan; i++) { + for (j = 0; j < num_channel; j++) { + if (fixed_greedy_freq_list[i] == + chan_list->chanParam[j].freq) { + qdf_mem_copy( + &chan_list_greedy->chanParam[num_greedy_chan], + &chan_list->chanParam[j], + sizeof(tSirUpdateChanParam)); + num_greedy_chan++; + break; + } + } + } + sme_debug("greedy=%d, non-greedy=%d, tot=%d", num_greedy_chan, + num_non_greedy_chan, num_channel); + if ((num_greedy_chan + num_non_greedy_chan) != num_channel) { + sme_err("incorrect sorting of channels"); + goto scan_list_sort_error; + } + /* Copy the Greedy channels first */ + i = 0; + qdf_mem_copy(&chan_list->chanParam[i], + &chan_list_greedy->chanParam[i], + num_greedy_chan * sizeof(tSirUpdateChanParam)); + /* Copy the remaining Non Greedy channels */ + i = num_greedy_chan; + j = 0; + qdf_mem_copy(&chan_list->chanParam[i], + &chan_list_non_greedy->chanParam[j], + num_non_greedy_chan * sizeof(tSirUpdateChanParam)); + + /* Update channel list for 5g preference and allow DFS roam */ + csr_roam_arrange_ch_list(mac_ctx, chan_list->chanParam, num_channel); +scan_list_sort_error: + qdf_mem_free(chan_list_greedy); + qdf_mem_free(chan_list_non_greedy); +} + +/** + * csr_emu_chan_req() - update the required channel list for emulation + * @channel: channel number to check + * + * To reduce scan time during emulation platforms, this function + * restricts the scanning to be done on selected channels + * + * Return: QDF_STATUS enumeration + */ +#ifdef QCA_WIFI_EMULATION +#define SCAN_CHAN_LIST_5G_LEN 6 +#define SCAN_CHAN_LIST_2G_LEN 3 +#define SCAN_CHAN_LIST_6G_LEN 3 +static const uint16_t +csr_scan_chan_list_5g[SCAN_CHAN_LIST_5G_LEN] = { 5180, 5220, 5260, 5280, 5700, 5745 }; +static const uint16_t +csr_scan_chan_list_2g[SCAN_CHAN_LIST_2G_LEN] = { 2412, 2437, 2462 }; +static const uint16_t +csr_scan_chan_list_6g[SCAN_CHAN_LIST_6G_LEN] = { 6055, 6135, 6215 }; + +static QDF_STATUS csr_emu_chan_req(uint32_t channel) +{ + int i; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(channel)) { + for (i = 0; i < QDF_ARRAY_SIZE(csr_scan_chan_list_2g); i++) { + if (csr_scan_chan_list_2g[i] == channel) + return QDF_STATUS_SUCCESS; + } + } else if (WLAN_REG_IS_5GHZ_CH_FREQ(channel)) { + for (i = 0; i < QDF_ARRAY_SIZE(csr_scan_chan_list_5g); i++) { + if (csr_scan_chan_list_5g[i] == channel) + return QDF_STATUS_SUCCESS; + } + } else if (WLAN_REG_IS_6GHZ_CHAN_FREQ(channel)) { + for (i = 0; i < QDF_ARRAY_SIZE(csr_scan_chan_list_6g); i++) { + if (csr_scan_chan_list_6g[i] == channel) + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_E_FAILURE; +} +#else +static QDF_STATUS csr_emu_chan_req(uint32_t channel_num) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_ENABLE_SOCIAL_CHANNELS_5G_ONLY +static void csr_add_len_of_social_channels(struct mac_context *mac, + uint8_t *num_chan) +{ + uint8_t i; + uint8_t no_chan = *num_chan; + + sme_debug("add len of social channels, before adding - num_chan:%hu", + *num_chan); + if (CSR_IS_5G_BAND_ONLY(mac)) { + for (i = 0; i < MAX_SOCIAL_CHANNELS; i++) { + if (wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, social_channel_freq[i], + REG_CURRENT_PWR_MODE) == + CHANNEL_STATE_ENABLE) + no_chan++; + } + } + *num_chan = no_chan; + sme_debug("after adding - num_chan:%hu", *num_chan); +} + +static void csr_add_social_channels(struct mac_context *mac, + tSirUpdateChanList *chan_list, struct csr_scanstruct *pScan, + uint8_t *num_chan) +{ + uint8_t i; + uint8_t no_chan = *num_chan; + + sme_debug("add social channels chan_list %pK, num_chan %hu", chan_list, + *num_chan); + if (CSR_IS_5G_BAND_ONLY(mac)) { + for (i = 0; i < MAX_SOCIAL_CHANNELS; i++) { + if (wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, social_channel_freq[i], + REG_CURRENT_PWR_MODE) != + CHANNEL_STATE_ENABLE) + continue; + chan_list->chanParam[no_chan].freq = + social_channel_freq[i]; + chan_list->chanParam[no_chan].pwr = + csr_find_channel_pwr(pScan->defaultPowerTable, + social_channel_freq[i]); + chan_list->chanParam[no_chan].dfsSet = false; + if (cds_is_5_mhz_enabled()) + chan_list->chanParam[no_chan].quarter_rate + = 1; + else if (cds_is_10_mhz_enabled()) + chan_list->chanParam[no_chan].half_rate = 1; + no_chan++; + } + sme_debug("after adding -num_chan %hu", no_chan); + } + *num_chan = no_chan; +} +#else +static void csr_add_len_of_social_channels(struct mac_context *mac, + uint8_t *num_chan) +{ + sme_debug("skip adding len of social channels"); +} +static void csr_add_social_channels(struct mac_context *mac, + tSirUpdateChanList *chan_list, struct csr_scanstruct *pScan, + uint8_t *num_chan) +{ + sme_debug("skip social channels"); +} +#endif + +/** + * csr_scan_event_handler() - callback for scan event + * @vdev: wlan objmgr vdev pointer + * @event: scan event + * @arg: global mac context pointer + * + * Return: void + */ +static void csr_scan_event_handler(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, + void *arg) +{ + bool success = false; + QDF_STATUS lock_status; + struct mac_context *mac = arg; + + if (!mac) + return; + + if (!util_is_scan_completed(event, &success)) + return; + + lock_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(lock_status)) + return; + + if (mac->scan.pending_channel_list_req) + csr_update_channel_list(mac); + sme_release_global_lock(&mac->sme); +} + +/** + * csr_update_roam_pcl_per_connected_sta_vdev() - Update roam pcl per connected + * STA + * @psoc: pointer to psoc object + * + * Return: None + */ +static void csr_update_roam_pcl_per_connected_sta_vdev( + struct wlan_objmgr_psoc *psoc) +{ + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + + for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) { + vdev = + wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_SME_ID); + + if (!vdev) + continue; + + if (vdev->vdev_mlme.vdev_opmode != QDF_STA_MODE) + goto next; + + if (!wlan_cm_is_vdev_connected(vdev)) + goto next; + + policy_mgr_set_pcl_for_existing_combo(psoc, PM_STA_MODE, + vdev_id); +next: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + } +} + +QDF_STATUS csr_update_channel_list(struct mac_context *mac) +{ + tSirUpdateChanList *pChanList; + struct csr_scanstruct *pScan = &mac->scan; + uint8_t numChan = pScan->base_channels.numChannels; + uint8_t num_channel = 0; + uint32_t bufLen; + struct scheduler_msg msg = {0}; + uint8_t i; + uint8_t channel_state; + uint16_t unsafe_chan[NUM_CHANNELS]; + uint16_t unsafe_chan_cnt = 0; + uint16_t cnt = 0; + uint32_t channel_freq; + bool is_unsafe_chan; + bool is_same_band; + bool is_5mhz_enabled; + bool is_10mhz_enabled; + enum scm_scan_status scan_status; + QDF_STATUS lock_status; + struct rso_roam_policy_params *roam_policy; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + qdf_device_t qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + + if (!qdf_ctx) + return QDF_STATUS_E_FAILURE; + + mlme_obj = mlme_get_psoc_ext_obj(mac->psoc); + if (!mlme_obj) + return QDF_STATUS_E_FAILURE; + roam_policy = &mlme_obj->cfg.lfr.rso_user_config.policy_params; + lock_status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_ERROR(lock_status)) + return lock_status; + + if (mac->mlme_cfg->reg.enable_pending_chan_list_req) { + scan_status = wlan_get_pdev_status(mac->pdev); + if (scan_status == SCAN_IS_ACTIVE || + scan_status == SCAN_IS_ACTIVE_AND_PENDING) { + mac->scan.pending_channel_list_req = true; + sme_release_global_lock(&mac->sme); + sme_debug("scan in progress postpone channel list req "); + return QDF_STATUS_SUCCESS; + } + mac->scan.pending_channel_list_req = false; + } + sme_release_global_lock(&mac->sme); + + pld_get_wlan_unsafe_channel(qdf_ctx->dev, unsafe_chan, + &unsafe_chan_cnt, + sizeof(unsafe_chan)); + + csr_add_len_of_social_channels(mac, &numChan); + + bufLen = sizeof(tSirUpdateChanList) + + (sizeof(tSirUpdateChanParam) * (numChan)); + + csr_init_operating_classes(mac); + pChanList = qdf_mem_malloc(bufLen); + if (!pChanList) + return QDF_STATUS_E_NOMEM; + + is_5mhz_enabled = cds_is_5_mhz_enabled(); + if (is_5mhz_enabled) + sme_nofl_debug("quarter_rate enabled"); + is_10mhz_enabled = cds_is_10_mhz_enabled(); + if (is_10mhz_enabled) + sme_nofl_debug("half_rate enabled"); + + for (i = 0; i < pScan->base_channels.numChannels; i++) { + if (QDF_STATUS_SUCCESS != + csr_emu_chan_req(pScan->base_channels.channel_freq_list[i])) + continue; + + channel_freq = pScan->base_channels.channel_freq_list[i]; + /* Scan is not performed on DSRC channels*/ + if (wlan_reg_is_dsrc_freq(channel_freq)) + continue; + + channel_state = + wlan_reg_get_channel_state_for_pwrmode( + mac->pdev, channel_freq, + REG_CURRENT_PWR_MODE); + if ((CHANNEL_STATE_ENABLE == channel_state) || + mac->scan.fEnableDFSChnlScan) { + if (wlan_reg_is_6ghz_chan_freq(channel_freq) && + !wlan_reg_is_6ghz_band_set(mac->pdev)) { + sme_debug("skip 6ghz frequency %d", + channel_freq); + continue; + } + if ((roam_policy->dfs_mode == + STA_ROAM_POLICY_DFS_DISABLED) && + (channel_state == CHANNEL_STATE_DFS)) { + sme_debug("skip dfs channel frequency %d", + channel_freq); + continue; + } + if (roam_policy->skip_unsafe_channels && + unsafe_chan_cnt) { + is_unsafe_chan = false; + for (cnt = 0; cnt < unsafe_chan_cnt; cnt++) { + if (unsafe_chan[cnt] == channel_freq) { + is_unsafe_chan = true; + break; + } + } + is_same_band = + (WLAN_REG_IS_24GHZ_CH_FREQ( + channel_freq) && + roam_policy->sap_operating_band == + BAND_2G) || + (WLAN_REG_IS_5GHZ_CH_FREQ( + channel_freq) && + roam_policy->sap_operating_band == + BAND_5G); + if (is_unsafe_chan && is_same_band) { + sme_debug("ignoring unsafe channel freq %d", + channel_freq); + continue; + } + } + pChanList->chanParam[num_channel].freq = + pScan->base_channels.channel_freq_list[i]; + pChanList->chanParam[num_channel].pwr = + csr_find_channel_pwr( + pScan->defaultPowerTable, + pScan->base_channels.channel_freq_list[i]); + + if (pScan->fcc_constraint) { + if (2467 == + pScan->base_channels.channel_freq_list[i]) { + pChanList->chanParam[num_channel].pwr = + MAX_PWR_FCC_CHAN_12; + sme_debug("txpow for channel 12 is %d", + MAX_PWR_FCC_CHAN_12); + } + if (2472 == + pScan->base_channels.channel_freq_list[i]) { + pChanList->chanParam[num_channel].pwr = + MAX_PWR_FCC_CHAN_13; + sme_debug("txpow for channel 13 is %d", + MAX_PWR_FCC_CHAN_13); + } + } + + if (!ucfg_is_nan_allowed_on_freq(mac->pdev, + pChanList->chanParam[num_channel].freq)) + pChanList->chanParam[num_channel].nan_disabled = + true; + + if (CHANNEL_STATE_DFS == channel_state) + pChanList->chanParam[num_channel].dfsSet = + true; + + pChanList->chanParam[num_channel].quarter_rate = + is_5mhz_enabled; + + pChanList->chanParam[num_channel].half_rate = + is_10mhz_enabled; + + num_channel++; + } + } + + csr_add_social_channels(mac, pChanList, pScan, &num_channel); + + if (mac->mlme_cfg->lfr.early_stop_scan_enable) + csr_roam_sort_channel_for_early_stop(mac, pChanList, + num_channel); + else + sme_debug("Early Stop Scan Feature not supported"); + + if ((mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC) || + (mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AC_ONLY)) { + pChanList->vht_en = true; + if (mac->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band) + pChanList->vht_24_en = true; + } + if ((mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_AUTO) || + (mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N) || + (mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11N_ONLY)) { + pChanList->ht_en = true; + } + if ((mac->roam.configParam.uCfgDot11Mode == eCSR_CFG_DOT11_MODE_AUTO) || + (mac->roam.configParam.uCfgDot11Mode == eCSR_CFG_DOT11_MODE_11AX) || + (mac->roam.configParam.uCfgDot11Mode == + eCSR_CFG_DOT11_MODE_11AX_ONLY)) + pChanList->he_en = true; +#ifdef WLAN_FEATURE_11BE + if ((mac->roam.configParam.uCfgDot11Mode == eCSR_CFG_DOT11_MODE_AUTO) || + CSR_IS_CFG_DOT11_PHY_MODE_11BE( + mac->roam.configParam.uCfgDot11Mode) || + CSR_IS_CFG_DOT11_PHY_MODE_11BE_ONLY( + mac->roam.configParam.uCfgDot11Mode)) + pChanList->eht_en = true; +#endif + + pChanList->numChan = num_channel; + mlme_store_fw_scan_channels(mac->psoc, pChanList); + + msg.type = WMA_UPDATE_CHAN_LIST_REQ; + msg.reserved = 0; + msg.bodyptr = pChanList; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, msg.type)); + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + qdf_mem_free(pChanList); + return QDF_STATUS_E_FAILURE; + } + + csr_update_roam_pcl_per_connected_sta_vdev(mac->psoc); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_start(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t i; + + do { + for (i = 0; i < WLAN_MAX_VDEVS; i++) + csr_roam_state_change(mac, eCSR_ROAMING_STATE_IDLE, i); + + mac->roam.sPendingCommands = 0; + + if (mac->mlme_cfg->reg.enable_pending_chan_list_req) { + status = ucfg_scan_register_event_handler(mac->pdev, + csr_scan_event_handler, mac); + + if (QDF_IS_STATUS_ERROR(status)) + sme_err("scan event registration failed "); + } + } while (0); + return status; +} + +QDF_STATUS csr_stop(struct mac_context *mac) +{ + uint32_t sessionId; + + if (mac->mlme_cfg->reg.enable_pending_chan_list_req) + ucfg_scan_unregister_event_handler(mac->pdev, + csr_scan_event_handler, + mac); + wlan_scan_psoc_set_disable(mac->psoc, REASON_SYSTEM_DOWN); + + /* + * purge all serialization command if there are any pending to make + * sure memory and vdev ref are freed. + */ + csr_purge_pdev_all_ser_cmd_list(mac); + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; sessionId++) + csr_cleanup_vdev_session(mac, sessionId); + + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; sessionId++) + if (CSR_IS_SESSION_VALID(mac, sessionId)) + ucfg_scan_flush_results(mac->pdev, NULL); + + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; sessionId++) { + csr_roam_state_change(mac, eCSR_ROAMING_STATE_STOP, sessionId); + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_ready(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + /* If the gScanAgingTime is set to '0' then scan results aging timeout + * based on timer feature is not enabled + */ + status = csr_apply_channel_and_power_list(mac); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("csr_apply_channel_and_power_list failed status: %d", + status); + + return status; +} + +void csr_set_default_dot11_mode(struct mac_context *mac) +{ + mac->mlme_cfg->dot11_mode.dot11_mode = + csr_translate_to_wni_cfg_dot11_mode(mac, + mac->roam.configParam.uCfgDot11Mode); +} + +void csr_set_global_cfgs(struct mac_context *mac) +{ + wlan_mlme_set_frag_threshold(mac->psoc, csr_get_frag_thresh(mac)); + wlan_mlme_set_rts_threshold(mac->psoc, csr_get_rts_thresh(mac)); + /* For now we will just use the 5GHz CB mode ini parameter to decide + * whether CB supported or not in Probes when there is no session + * Once session is established we will use the session related params + * stored in PE session for CB mode + */ + if (cfg_in_range(CFG_CHANNEL_BONDING_MODE_5GHZ, + mac->roam.configParam.channelBondingMode5GHz)) + ucfg_mlme_set_channel_bonding_5ghz(mac->psoc, + mac->roam.configParam. + channelBondingMode5GHz); + if (cfg_in_range(CFG_CHANNEL_BONDING_MODE_24GHZ, + mac->roam.configParam.channelBondingMode24GHz)) + ucfg_mlme_set_channel_bonding_24ghz(mac->psoc, + mac->roam.configParam. + channelBondingMode24GHz); + + mac->mlme_cfg->timeouts.heart_beat_threshold = + cfg_default(CFG_HEART_BEAT_THRESHOLD); + + /* Update the operating mode to configured value during + * initialization, So that client can advertise full + * capabilities in Probe request frame. + */ + csr_set_default_dot11_mode(mac); +} + +#if defined(WLAN_LOGGING_SOCK_SVC_ENABLE) && \ + defined(CONNECTIVITY_PKTLOG) +/** + * csr_packetdump_timer_handler() - packet dump timer + * handler + * @pv: user data + * + * This function is used to handle packet dump timer + * + * Return: None + * + */ +static void csr_packetdump_timer_handler(void *pv) +{ + sme_debug("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(OL_TXRX_PDEV_ID); +} + +void csr_packetdump_timer_start(void) +{ + QDF_STATUS status; + mac_handle_t mac_handle; + struct mac_context *mac; + QDF_TIMER_STATE cur_state; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac = MAC_CONTEXT(mac_handle); + if (!mac) { + QDF_ASSERT(0); + return; + } + cur_state = qdf_mc_timer_get_current_state(&mac->roam.packetdump_timer); + if (cur_state == QDF_TIMER_STATE_STARTING || + cur_state == QDF_TIMER_STATE_STARTING) { + sme_debug("packetdump_timer is already started: %d", cur_state); + return; + } + + status = qdf_mc_timer_start(&mac->roam.packetdump_timer, + (PKT_DUMP_TIMER_DURATION * + QDF_MC_TIMER_TO_SEC_UNIT) / + QDF_MC_TIMER_TO_MS_UNIT); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_debug("cannot start packetdump timer status: %d", status); +} + +void csr_packetdump_timer_stop(void) +{ + QDF_STATUS status; + mac_handle_t mac_handle; + struct mac_context *mac; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac = MAC_CONTEXT(mac_handle); + if (!mac) { + QDF_ASSERT(0); + return; + } + + status = qdf_mc_timer_stop(&mac->roam.packetdump_timer); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_err("cannot stop packetdump timer"); +} + +static QDF_STATUS csr_packetdump_timer_init(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!mac) { + QDF_ASSERT(0); + return -EINVAL; + } + + status = qdf_mc_timer_init(&mac->roam.packetdump_timer, + QDF_TIMER_TYPE_SW, + csr_packetdump_timer_handler, + mac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("cannot allocate memory for packetdump timer"); + return status; + } + + return status; +} + +static void csr_packetdump_timer_deinit(struct mac_context *mac) +{ + if (!mac) { + QDF_ASSERT(0); + return; + } + + qdf_mc_timer_stop(&mac->roam.packetdump_timer); + qdf_mc_timer_destroy(&mac->roam.packetdump_timer); +} +#else +static inline QDF_STATUS csr_packetdump_timer_init(struct mac_context *mac) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void csr_packetdump_timer_deinit(struct mac_context *mac) {} +#endif + +static QDF_STATUS csr_roam_open(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = csr_packetdump_timer_init(mac); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + spin_lock_init(&mac->roam.roam_state_lock); + + return status; +} + +static QDF_STATUS csr_roam_close(struct mac_context *mac) +{ + uint32_t sessionId; + struct csr_roam_session *session; + + /* + * purge all serialization command if there are any pending to make + * sure memory and vdev ref are freed. + */ + csr_purge_pdev_all_ser_cmd_list(mac); + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; sessionId++) { + session = CSR_GET_SESSION(mac, sessionId); + if (!session) + continue; + csr_cleanup_vdev_session(mac, sessionId); + } + + csr_packetdump_timer_deinit(mac); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS csr_roam_free_connected_info(struct mac_context *mac, + struct csr_roam_connectedinfo * + pConnectedInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (pConnectedInfo->pbFrames) { + qdf_mem_free(pConnectedInfo->pbFrames); + pConnectedInfo->pbFrames = NULL; + } + pConnectedInfo->nBeaconLength = 0; + pConnectedInfo->nAssocReqLength = 0; + pConnectedInfo->nAssocRspLength = 0; + pConnectedInfo->nRICRspLength = 0; +#ifdef FEATURE_WLAN_ESE + pConnectedInfo->nTspecIeLength = 0; +#endif + return status; +} + +void csr_release_command_roam(struct mac_context *mac, tSmeCmd *pCommand) +{ + csr_reinit_roam_cmd(mac, pCommand); +} + +void csr_release_command_wm_status_change(struct mac_context *mac, + tSmeCmd *pCommand) +{ + csr_reinit_wm_status_change_cmd(mac, pCommand); +} + +void csr_roam_substate_change(struct mac_context *mac, + enum csr_roam_substate NewSubstate, uint32_t sessionId) +{ + if (sessionId >= WLAN_MAX_VDEVS) { + sme_err("Invalid no of concurrent sessions %d", + sessionId); + return; + } + if (mac->roam.curSubState[sessionId] == NewSubstate) + return; + sme_nofl_debug("CSR RoamSubstate: [ %s <== %s ]", + mac_trace_getcsr_roam_sub_state(NewSubstate), + mac_trace_getcsr_roam_sub_state(mac->roam. + curSubState[sessionId])); + spin_lock(&mac->roam.roam_state_lock); + mac->roam.curSubState[sessionId] = NewSubstate; + spin_unlock(&mac->roam.roam_state_lock); +} + +enum csr_roam_state csr_roam_state_change(struct mac_context *mac, + enum csr_roam_state NewRoamState, + uint8_t sessionId) +{ + enum csr_roam_state PreviousState; + + PreviousState = mac->roam.curState[sessionId]; + + if (NewRoamState == mac->roam.curState[sessionId]) + return PreviousState; + + sme_nofl_debug("CSR RoamState[%d]: [ %s <== %s ]", sessionId, + mac_trace_getcsr_roam_state(NewRoamState), + mac_trace_getcsr_roam_state( + mac->roam.curState[sessionId])); + /* + * Whenever we transition OUT of the Roaming state, + * clear the Roaming substate. + */ + if (CSR_IS_ROAM_JOINING(mac, sessionId)) { + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + } + + mac->roam.curState[sessionId] = NewRoamState; + + return PreviousState; +} + +static void init_config_param(struct mac_context *mac) +{ + mac->roam.configParam.channelBondingMode24GHz = + WNI_CFG_CHANNEL_BONDING_MODE_DISABLE; + mac->roam.configParam.channelBondingMode5GHz = + WNI_CFG_CHANNEL_BONDING_MODE_ENABLE; + + mac->roam.configParam.phyMode = eCSR_DOT11_MODE_AUTO; + mac->roam.configParam.uCfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + mac->roam.configParam.HeartbeatThresh50 = 40; + mac->roam.configParam.Is11eSupportEnabled = true; + mac->roam.configParam.WMMSupportMode = WMM_USER_MODE_AUTO; + mac->roam.configParam.ProprietaryRatesEnabled = true; + + mac->roam.configParam.nVhtChannelWidth = + WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1; +} + +/** + * csr_flush_roam_scan_chan_lists() - Flush the roam channel lists + * @mac: Global MAC context + * @vdev_id: vdev id + * + * Flush the roam channel lists pref_chan_info and specific_chan_info. + * + * Return: None + */ +static void +csr_flush_roam_scan_chan_lists(struct mac_context *mac, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct rso_config *rso_cfg; + struct rso_cfg_params *cfg_params; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac->pdev, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return; + + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + cfg_params = &rso_cfg->cfg_param; + wlan_cm_flush_roam_channel_list(&cfg_params->pref_chan_info); + wlan_cm_flush_roam_channel_list(&cfg_params->specific_chan_info); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} + +#ifdef FEATURE_WLAN_ESE +/** + * csr_roam_is_ese_assoc() - is this ese association + * @mac_ctx: Global MAC context + * @session_id: session identifier + * + * Returns whether the current association is a ESE assoc or not. + * + * Return: true if ese association; false otherwise + */ +bool csr_roam_is_ese_assoc(struct mac_context *mac_ctx, uint32_t session_id) +{ + return wlan_cm_get_ese_assoc(mac_ctx->pdev, session_id); +} + + +/** + * csr_tsm_stats_rsp_processor() - tsm stats response processor + * @mac: Global MAC context + * @pMsg: Message pointer + * + * Return: None + */ +static void csr_tsm_stats_rsp_processor(struct mac_context *mac, void *pMsg) +{ + tAniGetTsmStatsRsp *pTsmStatsRsp = (tAniGetTsmStatsRsp *) pMsg; + + if (pTsmStatsRsp) { + /* + * Get roam Rssi request is backed up and passed back + * to the response, Extract the request message + * to fetch callback. + */ + tpAniGetTsmStatsReq reqBkp + = (tAniGetTsmStatsReq *) pTsmStatsRsp->tsmStatsReq; + + if (reqBkp) { + if (reqBkp->tsmStatsCallback) { + ((tCsrTsmStatsCallback) + (reqBkp->tsmStatsCallback))(pTsmStatsRsp-> + tsmMetrics, + reqBkp-> + pDevContext); + reqBkp->tsmStatsCallback = NULL; + } + qdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } else { + if (reqBkp) { + qdf_mem_free(reqBkp); + pTsmStatsRsp->tsmStatsReq = NULL; + } + } + } else { + sme_err("pTsmStatsRsp is NULL"); + } +} + +/** + * csr_send_ese_adjacent_ap_rep_ind() - ese send adjacent ap report + * @mac: Global MAC context + * @pSession: Session pointer + * + * Return: None + */ +static void csr_send_ese_adjacent_ap_rep_ind(struct mac_context *mac, + struct csr_roam_session *pSession) +{ + uint32_t roamTS2 = 0; + struct csr_roam_info *roam_info; + struct pe_session *pe_session = NULL; + uint8_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + struct qdf_mac_addr connected_bssid; + + if (!pSession) { + sme_err("pSession is NULL"); + return; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + roamTS2 = qdf_mc_timer_get_system_time(); + roam_info->tsmRoamDelay = roamTS2 - pSession->roamTS1; + wlan_mlme_get_bssid_vdev_id(mac->pdev, pSession->vdev_id, + &connected_bssid); + sme_debug("Bssid(" QDF_MAC_ADDR_FMT ") Roaming Delay(%u ms)", + QDF_MAC_ADDR_REF(connected_bssid.bytes), + roam_info->tsmRoamDelay); + + pe_session = pe_find_session_by_bssid(mac, connected_bssid.bytes, + &sessionId); + if (!pe_session) { + sme_err("session %d not found", sessionId); + qdf_mem_free(roam_info); + return; + } + + pe_session->eseContext.tsm.tsmMetrics.RoamingDly + = roam_info->tsmRoamDelay; + + csr_roam_call_callback(mac, pSession->vdev_id, roam_info, + eCSR_ROAM_ESE_ADJ_AP_REPORT_IND, 0); + qdf_mem_free(roam_info); +} + +/** + * csr_get_tsm_stats() - get tsm stats + * @mac: Global MAC context + * @callback: TSM stats callback + * @staId: Station id + * @bssId: bssid + * @pContext: pointer to context + * @tid: traffic id + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS csr_get_tsm_stats(struct mac_context *mac, + tCsrTsmStatsCallback callback, + struct qdf_mac_addr bssId, + void *pContext, uint8_t tid) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tAniGetTsmStatsReq *pMsg = NULL; + + pMsg = qdf_mem_malloc(sizeof(tAniGetTsmStatsReq)); + if (!pMsg) { + return QDF_STATUS_E_NOMEM; + } + /* need to initiate a stats request to PE */ + pMsg->msgType = eWNI_SME_GET_TSM_STATS_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetTsmStatsReq); + pMsg->tid = tid; + qdf_copy_macaddr(&pMsg->bssId, &bssId); + pMsg->tsmStatsCallback = callback; + pMsg->pDevContext = pContext; + status = umac_send_mb_message_to_mac(pMsg); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Failed to send down the TSM req (status=%d)", status); + /* pMsg is freed by cds_send_mb_message_to_mac */ + status = QDF_STATUS_E_FAILURE; + } + return status; +} +#endif /* FEATURE_WLAN_ESE */ + +/* The funcns csr_convert_cb_ini_value_to_phy_cb_state and + * csr_convert_phy_cb_state_to_ini_value have been introduced + * to convert the ini value to the ENUM used in csr and MAC for CB state + * Ideally we should have kept the ini value and enum value same and + * representing the same cb values as in 11n standard i.e. + * Set to 1 (SCA) if the secondary channel is above the primary channel + * Set to 3 (SCB) if the secondary channel is below the primary channel + * Set to 0 (SCN) if no secondary channel is present + * However, since our driver is already distributed we will keep the ini + * definition as it is which is: + * 0 - secondary none + * 1 - secondary LOW + * 2 - secondary HIGH + * and convert to enum value used within the driver in + * csr_change_default_config_param using this funcn + * The enum values are as follows: + * PHY_SINGLE_CHANNEL_CENTERED = 0 + * PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1 + * PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3 + */ +ePhyChanBondState csr_convert_cb_ini_value_to_phy_cb_state(uint32_t cbIniValue) +{ + + ePhyChanBondState phyCbState; + + switch (cbIniValue) { + /* secondary none */ + case eCSR_INI_SINGLE_CHANNEL_CENTERED: + phyCbState = PHY_SINGLE_CHANNEL_CENTERED; + break; + /* secondary LOW */ + case eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY: + phyCbState = PHY_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + /* secondary HIGH */ + case eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY: + phyCbState = PHY_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + phyCbState = + PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + break; + case eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + phyCbState = PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + break; + default: + /* If an invalid value is passed, disable CHANNEL BONDING */ + phyCbState = PHY_SINGLE_CHANNEL_CENTERED; + break; + } + return phyCbState; +} + +static +uint32_t csr_convert_phy_cb_state_to_ini_value(ePhyChanBondState phyCbState) +{ + uint32_t cbIniValue; + + switch (phyCbState) { + /* secondary none */ + case PHY_SINGLE_CHANNEL_CENTERED: + cbIniValue = eCSR_INI_SINGLE_CHANNEL_CENTERED; + break; + /* secondary LOW */ + case PHY_DOUBLE_CHANNEL_HIGH_PRIMARY: + cbIniValue = eCSR_INI_DOUBLE_CHANNEL_HIGH_PRIMARY; + break; + /* secondary HIGH */ + case PHY_DOUBLE_CHANNEL_LOW_PRIMARY: + cbIniValue = eCSR_INI_DOUBLE_CHANNEL_LOW_PRIMARY; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED: + cbIniValue = + eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH; + break; + case PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH: + cbIniValue = eCSR_INI_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH; + break; + default: + /* return some invalid value */ + cbIniValue = eCSR_INI_CHANNEL_BONDING_STATE_MAX; + break; + } + return cbIniValue; +} + +#ifdef WLAN_FEATURE_11BE +void csr_update_session_eht_cap(struct mac_context *mac_ctx, + struct csr_roam_session *session) +{ + tDot11fIEeht_cap *eht_cap; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + session->vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return; + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + qdf_mem_copy(&mlme_priv->eht_config, + &mac_ctx->mlme_cfg->eht_caps.dot11_eht_cap, + sizeof(mlme_priv->eht_config)); + eht_cap = &mlme_priv->eht_config; + eht_cap->present = true; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} +#endif + +#ifdef WLAN_FEATURE_11AX +void csr_update_session_he_cap(struct mac_context *mac_ctx, + struct csr_roam_session *session) +{ + enum QDF_OPMODE persona; + tDot11fIEhe_cap *he_cap; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + session->vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return; + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + qdf_mem_copy(&mlme_priv->he_config, + &mac_ctx->mlme_cfg->he_caps.dot11_he_cap, + sizeof(mlme_priv->he_config)); + he_cap = &mlme_priv->he_config; + he_cap->present = true; + /* + * Do not advertise requester role for SAP & responder role + * for STA + */ + persona = wlan_vdev_mlme_get_opmode(vdev); + if (persona == QDF_SAP_MODE || persona == QDF_P2P_GO_MODE) { + he_cap->twt_request = false; + if (!he_cap->twt_responder) + he_cap->flex_twt_sched = false; + + } else if (persona == QDF_STA_MODE || persona == QDF_P2P_CLIENT_MODE) { + he_cap->twt_responder = false; + if (!he_cap->twt_request) + he_cap->flex_twt_sched = false; + } + + if (he_cap->ppet_present) { + /* till now operating channel is not decided yet, use 5g cap */ + qdf_mem_copy(he_cap->ppet.ppe_threshold.ppe_th, + mac_ctx->mlme_cfg->he_caps.he_ppet_5g, + WNI_CFG_HE_PPET_LEN); + he_cap->ppet.ppe_threshold.num_ppe_th = + lim_truncate_ppet(he_cap->ppet.ppe_threshold.ppe_th, + WNI_CFG_HE_PPET_LEN); + } else { + he_cap->ppet.ppe_threshold.num_ppe_th = 0; + } + mlme_priv->he_sta_obsspd = mac_ctx->mlme_cfg->he_caps.he_sta_obsspd; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} +#endif + +QDF_STATUS csr_change_default_config_param(struct mac_context *mac, + struct csr_config_params *pParam) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (pParam) { + mac->roam.configParam.is_force_1x1 = + pParam->is_force_1x1; + mac->roam.configParam.WMMSupportMode = pParam->WMMSupportMode; + mac->mlme_cfg->wmm_params.wme_enabled = + (pParam->WMMSupportMode == WMM_USER_MODE_NO_QOS) ? 0 : 1; + mac->roam.configParam.Is11eSupportEnabled = + pParam->Is11eSupportEnabled; + + mac->roam.configParam.fenableMCCMode = pParam->fEnableMCCMode; + mac->roam.configParam.mcc_rts_cts_prot_enable = + pParam->mcc_rts_cts_prot_enable; + mac->roam.configParam.mcc_bcast_prob_resp_enable = + pParam->mcc_bcast_prob_resp_enable; + mac->roam.configParam.fAllowMCCGODiffBI = + pParam->fAllowMCCGODiffBI; + + /* channelBondingMode5GHz plays a dual role right now + * INFRA STA will use this non zero value as CB enabled + * and SOFTAP will use this non-zero value to determine + * the secondary channel offset. This is how + * channelBondingMode5GHz works now and this is kept intact + * to avoid any cfg.ini change. + */ + if (pParam->channelBondingMode24GHz > MAX_CB_VALUE_IN_INI) + sme_warn("Invalid CB value from ini in 2.4GHz band %d, CB DISABLED", + pParam->channelBondingMode24GHz); + mac->roam.configParam.channelBondingMode24GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode24GHz); + if (pParam->channelBondingMode5GHz > MAX_CB_VALUE_IN_INI) + sme_warn("Invalid CB value from ini in 5GHz band %d, CB DISABLED", + pParam->channelBondingMode5GHz); + mac->roam.configParam.channelBondingMode5GHz = + csr_convert_cb_ini_value_to_phy_cb_state(pParam-> + channelBondingMode5GHz); + sme_debug("cb mode 2g %d 5g %d", + mac->roam.configParam.channelBondingMode24GHz, + mac->roam.configParam.channelBondingMode5GHz); + mac->roam.configParam.phyMode = pParam->phyMode; + mac->roam.configParam.HeartbeatThresh50 = + pParam->HeartbeatThresh50; + mac->roam.configParam.ProprietaryRatesEnabled = + pParam->ProprietaryRatesEnabled; + + mac->roam.configParam.wep_tkip_in_he = pParam->wep_tkip_in_he; + + mac->roam.configParam.uCfgDot11Mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(false, + mac->roam.configParam. + phyMode); + + /* Assign this before calling csr_init11d_info */ + if (wlan_reg_11d_enabled_on_host(mac->psoc)) + status = csr_init11d_info(mac, &pParam->Csr11dinfo); + + /* Initialize the power + channel information if 11h is + * enabled. If 11d is enabled this information has already + * been initialized + */ + if (csr_is11h_supported(mac) && + !wlan_reg_11d_enabled_on_host(mac->psoc)) + csr_init_channel_power_list(mac, &pParam->Csr11dinfo); + + mac->scan.fEnableDFSChnlScan = pParam->fEnableDFSChnlScan; + mac->roam.configParam.send_smps_action = + pParam->send_smps_action; +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + mac->roam.configParam.cc_switch_mode = pParam->cc_switch_mode; +#endif + mac->roam.configParam.obssEnabled = pParam->obssEnabled; + mac->roam.configParam.conc_custom_rule1 = + pParam->conc_custom_rule1; + mac->roam.configParam.conc_custom_rule2 = + pParam->conc_custom_rule2; + mac->roam.configParam.is_sta_connection_in_5gz_enabled = + pParam->is_sta_connection_in_5gz_enabled; + + /* update interface configuration */ + mac->sme.max_intf_count = pParam->max_intf_count; + + mac->f_sta_miracast_mcc_rest_time_val = + pParam->f_sta_miracast_mcc_rest_time_val; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + mac->sap.sap_channel_avoidance = + pParam->sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + } + return status; +} + +QDF_STATUS csr_get_config_param(struct mac_context *mac, + struct csr_config_params *pParam) +{ + struct csr_config *cfg_params = &mac->roam.configParam; + + if (!pParam) + return QDF_STATUS_E_INVAL; + + pParam->is_force_1x1 = cfg_params->is_force_1x1; + pParam->WMMSupportMode = cfg_params->WMMSupportMode; + pParam->Is11eSupportEnabled = cfg_params->Is11eSupportEnabled; + pParam->channelBondingMode24GHz = csr_convert_phy_cb_state_to_ini_value( + cfg_params->channelBondingMode24GHz); + pParam->channelBondingMode5GHz = csr_convert_phy_cb_state_to_ini_value( + cfg_params->channelBondingMode5GHz); + pParam->phyMode = cfg_params->phyMode; + pParam->HeartbeatThresh50 = cfg_params->HeartbeatThresh50; + pParam->ProprietaryRatesEnabled = cfg_params->ProprietaryRatesEnabled; + pParam->fEnableDFSChnlScan = mac->scan.fEnableDFSChnlScan; + pParam->fEnableMCCMode = cfg_params->fenableMCCMode; + pParam->fAllowMCCGODiffBI = cfg_params->fAllowMCCGODiffBI; + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + pParam->cc_switch_mode = cfg_params->cc_switch_mode; +#endif + pParam->wep_tkip_in_he = cfg_params->wep_tkip_in_he; + csr_set_channels(mac, pParam); + pParam->obssEnabled = cfg_params->obssEnabled; + pParam->conc_custom_rule1 = cfg_params->conc_custom_rule1; + pParam->conc_custom_rule2 = cfg_params->conc_custom_rule2; + pParam->is_sta_connection_in_5gz_enabled = + cfg_params->is_sta_connection_in_5gz_enabled; +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + pParam->sap_channel_avoidance = mac->sap.sap_channel_avoidance; +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + pParam->max_intf_count = mac->sme.max_intf_count; + pParam->f_sta_miracast_mcc_rest_time_val = + mac->f_sta_miracast_mcc_rest_time_val; + pParam->send_smps_action = mac->roam.configParam.send_smps_action; + + return QDF_STATUS_SUCCESS; +} + +/** + * csr_prune_ch_list() - prunes the channel list to keep only a type of channels + * @ch_lst: existing channel list + * @is_24_GHz: indicates if 2.5 GHz or 5 GHz channels are required + * + * Return: void + */ +static void csr_prune_ch_list(struct csr_channel *ch_lst, bool is_24_GHz) +{ + uint8_t idx = 0, num_channels = 0; + + for ( ; idx < ch_lst->numChannels; idx++) { + if (is_24_GHz) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_lst->channel_freq_list[idx])) { + ch_lst->channel_freq_list[num_channels] = + ch_lst->channel_freq_list[idx]; + num_channels++; + } + } else { + if (WLAN_REG_IS_5GHZ_CH_FREQ(ch_lst->channel_freq_list[idx])) { + ch_lst->channel_freq_list[num_channels] = + ch_lst->channel_freq_list[idx]; + num_channels++; + } + } + } + /* + * Cleanup the rest of channels. Note we only need to clean up the + * channels if we had to trim the list. Calling qdf_mem_set() with a 0 + * size is going to throw asserts on the debug builds so let's be a bit + * smarter about that. Zero out the reset of the channels only if we + * need to. The amount of memory to clear is the number of channesl that + * we trimmed (ch_lst->numChannels - num_channels) times the size of a + * channel in the structure. + */ + if (ch_lst->numChannels > num_channels) { + qdf_mem_zero(&ch_lst->channel_freq_list[num_channels], + sizeof(ch_lst->channel_freq_list[0]) * + (ch_lst->numChannels - num_channels)); + } + ch_lst->numChannels = num_channels; +} + +/** + * csr_prune_channel_list_for_mode() - prunes the channel list + * @mac_ctx: global mac context + * @ch_lst: existing channel list + * + * Prunes the channel list according to band stored in mac_ctx + * + * Return: void + */ +void csr_prune_channel_list_for_mode(struct mac_context *mac_ctx, + struct csr_channel *ch_lst) +{ + /* for dual band NICs, don't need to trim the channel list.... */ + if (CSR_IS_OPEARTING_DUAL_BAND(mac_ctx)) + return; + /* + * 2.4 GHz band operation requires the channel list to be trimmed to + * the 2.4 GHz channels only + */ + if (CSR_IS_24_BAND_ONLY(mac_ctx)) + csr_prune_ch_list(ch_lst, true); + else if (CSR_IS_5G_BAND_ONLY(mac_ctx)) + csr_prune_ch_list(ch_lst, false); +} + +#define INFRA_AP_DEFAULT_CHAN_FREQ 2437 + +QDF_STATUS csr_get_channel_and_power_list(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t num20MHzChannelsFound = 0; + QDF_STATUS qdf_status; + uint8_t Index = 0; + + qdf_status = wlan_reg_get_channel_list_with_power_for_freq( + mac->pdev, + mac->scan.defaultPowerTable, + &num20MHzChannelsFound); + + if ((QDF_STATUS_SUCCESS != qdf_status) || + (num20MHzChannelsFound == 0)) { + sme_err("failed to get channels"); + status = QDF_STATUS_E_FAILURE; + } else { + if (num20MHzChannelsFound > CFG_VALID_CHANNEL_LIST_LEN) + num20MHzChannelsFound = CFG_VALID_CHANNEL_LIST_LEN; + /* Move the channel list to the global data */ + /* structure -- this will be used as the scan list */ + for (Index = 0; Index < num20MHzChannelsFound; Index++) + mac->scan.base_channels.channel_freq_list[Index] = + mac->scan.defaultPowerTable[Index].center_freq; + mac->scan.base_channels.numChannels = + num20MHzChannelsFound; + } + return status; +} + +QDF_STATUS csr_apply_channel_and_power_list(struct mac_context *mac) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + csr_prune_channel_list_for_mode(mac, &mac->scan.base_channels); + csr_save_channel_power_for_band(mac, false); + csr_save_channel_power_for_band(mac, true); + csr_apply_channel_power_info_to_fw(mac, + &mac->scan.base_channels); + + csr_init_operating_classes(mac); + return status; +} + +static QDF_STATUS csr_init11d_info(struct mac_context *mac, tCsr11dinfo *ps11dinfo) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t index; + uint32_t count = 0; + struct pwr_channel_info *pChanInfo; + struct pwr_channel_info *pChanInfoStart; + bool applyConfig = true; + + if (!ps11dinfo) + return status; + + if (ps11dinfo->Channels.numChannels + && (CFG_VALID_CHANNEL_LIST_LEN >= + ps11dinfo->Channels.numChannels)) { + mac->scan.base_channels.numChannels = + ps11dinfo->Channels.numChannels; + qdf_mem_copy(mac->scan.base_channels.channel_freq_list, + ps11dinfo->Channels.channel_freq_list, + ps11dinfo->Channels.numChannels); + } else { + /* No change */ + return QDF_STATUS_SUCCESS; + } + /* legacy maintenance */ + + /* need to add the max power channel list */ + pChanInfo = + qdf_mem_malloc(sizeof(struct pwr_channel_info) * + CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo) { + pChanInfoStart = pChanInfo; + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->first_freq = ps11dinfo->ChnPower[index].first_chan_freq; + pChanInfo->num_chan = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->max_tx_pwr = + ps11dinfo->ChnPower[index].maxtxPower; + pChanInfo++; + count++; + } + if (count) { + status = csr_save_to_channel_power2_g_5_g(mac, + count * + sizeof(struct pwr_channel_info), + pChanInfoStart); + } + qdf_mem_free(pChanInfoStart); + } + /* Only apply them to CFG when not in STOP state. + * Otherwise they will be applied later + */ + if (QDF_IS_STATUS_SUCCESS(status)) { + for (index = 0; index < WLAN_MAX_VDEVS; index++) { + if ((CSR_IS_SESSION_VALID(mac, index)) + && CSR_IS_ROAM_STOP(mac, index)) { + applyConfig = false; + } + } + + if (true == applyConfig) { + /* Apply the base channel list, power info, + * and set the Country code. + */ + csr_apply_channel_power_info_to_fw(mac, + &mac->scan. + base_channels); + } + } + return status; +} + +/* Initialize the Channel + Power List in the local cache and in the CFG */ +QDF_STATUS csr_init_channel_power_list(struct mac_context *mac, + tCsr11dinfo *ps11dinfo) +{ + uint8_t index; + uint32_t count = 0; + struct pwr_channel_info *pChanInfo; + struct pwr_channel_info *pChanInfoStart; + + if (!ps11dinfo || !mac) + return QDF_STATUS_E_FAILURE; + + pChanInfo = + qdf_mem_malloc(sizeof(struct pwr_channel_info) * + CFG_VALID_CHANNEL_LIST_LEN); + if (pChanInfo) { + pChanInfoStart = pChanInfo; + + for (index = 0; index < ps11dinfo->Channels.numChannels; + index++) { + pChanInfo->first_freq = ps11dinfo->ChnPower[index].first_chan_freq; + pChanInfo->num_chan = + ps11dinfo->ChnPower[index].numChannels; + pChanInfo->max_tx_pwr = + ps11dinfo->ChnPower[index].maxtxPower; + pChanInfo++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(mac, + count * + sizeof(struct pwr_channel_info), + pChanInfoStart); + } + qdf_mem_free(pChanInfoStart); + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +#ifdef WLAN_UNIT_TEST +void csr_cm_get_sta_cxn_info(struct mac_context *mac_ctx, uint8_t vdev_id, + char *buf, uint32_t buf_sz) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev %d", vdev_id); + return; + } + + cm_get_sta_cxn_info(vdev, buf, buf_sz); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + +} +#endif +#endif + +QDF_STATUS csr_roam_call_callback(struct mac_context *mac, uint32_t sessionId, + struct csr_roam_info *roam_info, + eRoamCmdStatus u1, eCsrRoamResult u2) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession; + qdf_freq_t chan_freq; + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Session ID: %d is not valid", sessionId); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + pSession = CSR_GET_SESSION(mac, sessionId); + + if (false == pSession->sessionActive) { + sme_debug("Session is not Active"); + return QDF_STATUS_E_FAILURE; + } + chan_freq = wlan_get_operation_chan_freq_vdev_id(mac->pdev, sessionId); + + if (mac->session_roam_complete_cb) + status = mac->session_roam_complete_cb(mac->psoc, sessionId, + roam_info, u1, u2); + + return status; +} + +static bool csr_peer_mac_match_cmd(tSmeCmd *sme_cmd, + struct qdf_mac_addr *peer_macaddr, + struct qdf_mac_addr *peer_mld_addr, + uint8_t vdev_id) +{ + if (sme_cmd->command == eSmeCommandRoam && + (sme_cmd->u.roamCmd.roamReason == eCsrForcedDisassocSta || + sme_cmd->u.roamCmd.roamReason == eCsrForcedDeauthSta) && + (qdf_is_macaddr_equal( + peer_macaddr, + (struct qdf_mac_addr *)sme_cmd->u.roamCmd.peerMac) || + (!qdf_is_macaddr_zero(peer_mld_addr) && + qdf_is_macaddr_equal(peer_mld_addr, + &sme_cmd->u.roamCmd.peer_mld_addr)))) + return true; + + if (sme_cmd->command == eSmeCommandWmStatusChange) { + struct wmstatus_changecmd *wms_cmd; + + wms_cmd = &sme_cmd->u.wmStatusChangeCmd; + if (wms_cmd->Type == eCsrDisassociated && + (qdf_is_macaddr_equal( + peer_macaddr, + &wms_cmd->u.DisassocIndMsg.peer_macaddr) || + (!qdf_is_macaddr_zero(peer_mld_addr) && + qdf_is_macaddr_equal( + peer_mld_addr, + &wms_cmd->u.DisassocIndMsg.peer_mld_addr)))) + return true; + + if (wms_cmd->Type == eCsrDeauthenticated && + (qdf_is_macaddr_equal( + peer_macaddr, + &wms_cmd->u.DeauthIndMsg.peer_macaddr) || + (!qdf_is_macaddr_zero(peer_mld_addr) && + qdf_is_macaddr_equal( + peer_mld_addr, + &wms_cmd->u.DeauthIndMsg.peer_mld_addr)))) + return true; + } + + return false; +} + +static bool +csr_is_deauth_disassoc_in_pending_q(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr *peer_macaddr, + struct qdf_mac_addr *peer_mld_addr) +{ + tListElem *entry = NULL; + tSmeCmd *sme_cmd; + + entry = csr_nonscan_pending_ll_peek_head(mac_ctx, LL_ACCESS_NOLOCK); + while (entry) { + sme_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + if ((sme_cmd->vdev_id == vdev_id) && + csr_peer_mac_match_cmd(sme_cmd, peer_macaddr, + peer_mld_addr, vdev_id)) + return true; + entry = csr_nonscan_pending_ll_next(mac_ctx, entry, + LL_ACCESS_NOLOCK); + } + + return false; +} + +static bool +csr_is_deauth_disassoc_in_active_q(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr *peer_macaddr, + struct qdf_mac_addr *peer_mld_addr) +{ + tSmeCmd *sme_cmd; + + sme_cmd = wlan_serialization_get_active_cmd(mac_ctx->psoc, vdev_id, + WLAN_SER_CMD_FORCE_DEAUTH_STA); + + if (sme_cmd && csr_peer_mac_match_cmd(sme_cmd, peer_macaddr, + peer_mld_addr, vdev_id)) + return true; + + sme_cmd = wlan_serialization_get_active_cmd(mac_ctx->psoc, vdev_id, + WLAN_SER_CMD_FORCE_DISASSOC_STA); + + if (sme_cmd && csr_peer_mac_match_cmd(sme_cmd, peer_macaddr, + peer_mld_addr, vdev_id)) + return true; + + /* + * WLAN_SER_CMD_WM_STATUS_CHANGE is of two type, the handling + * should take care of both the types. + */ + sme_cmd = wlan_serialization_get_active_cmd(mac_ctx->psoc, vdev_id, + WLAN_SER_CMD_WM_STATUS_CHANGE); + if (sme_cmd && csr_peer_mac_match_cmd(sme_cmd, peer_macaddr, + peer_mld_addr, vdev_id)) + return true; + + return false; +} + +/* + * csr_is_deauth_disassoc_already_active() - Function to check if deauth or + * disassoc is already in progress. + * @mac_ctx: Global MAC context + * @vdev_id: vdev id + * @peer_macaddr: Peer MAC address to check + * @peer_mld_addr: peer MLD address to check + * + * Return: True if deauth/disassoc indication can be dropped + * else false + */ +static bool +csr_is_deauth_disassoc_already_active(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr *peer_macaddr, + struct qdf_mac_addr *peer_mld_addr) +{ + char mld_log_str[MAC_ADDR_DUMP_LEN] = {0}; + + bool ret = csr_is_deauth_disassoc_in_pending_q( + mac_ctx, vdev_id, peer_macaddr, + peer_mld_addr); + if (!ret) + /** + * commands are not found in pending queue, check in active + * queue as well + */ + ret = csr_is_deauth_disassoc_in_active_q( + mac_ctx, vdev_id, + peer_macaddr, peer_mld_addr); + + if (ret) { + if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)&peer_mld_addr)) + qdf_scnprintf(mld_log_str, MAC_ADDR_DUMP_LEN, + " mld: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mld_addr->bytes)); + sme_debug("Deauth/Disassoc already in progress for " QDF_MAC_ADDR_FMT "%s", + QDF_MAC_ADDR_REF(peer_macaddr->bytes), mld_log_str); + } + + return ret; +} + +/* + * csr_is_deauth_disassoc_cmd_active() - Function to check if deauth or + * disassoc is already in progress. + * @mac_ctx: Global MAC context + * @vdev_id: vdev ID + * @macaddr: mac address provided (mld/link/mac for the peer to check) + * @peer_mac: found peer mac + * @peer_mld_mac: found peer mld if ML connection + * + * Return: True if deauth/disassoc indication can be dropped else false + */ +static bool +csr_is_deauth_disassoc_cmd_active(struct mac_context *mac_ctx, + uint8_t vdev_id, struct qdf_mac_addr macaddr, + struct qdf_mac_addr *peer_mac, + struct qdf_mac_addr *peer_mld_mac) +{ + struct peer_mac_addresses peer_mac_info; + + qdf_mem_zero(&peer_mac_info, sizeof(struct peer_mac_addresses)); + qdf_copy_macaddr(&peer_mac_info.mac, &macaddr); + wlan_find_peer_and_get_mac_and_mld_addr(mac_ctx->psoc, &peer_mac_info); + if (csr_is_deauth_disassoc_already_active(mac_ctx, vdev_id, + &peer_mac_info.peer_mac, + &peer_mac_info.peer_mld)) + return true; + + if (peer_mac && peer_mld_mac) { + if (!qdf_is_macaddr_equal(&macaddr, &peer_mac_info.peer_mac)) + sme_debug("Vdev %d, given mac " QDF_MAC_ADDR_FMT " found peer mac " QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(macaddr.bytes), + QDF_MAC_ADDR_REF(peer_mac_info.peer_mac.bytes)); + qdf_copy_macaddr(peer_mac, &peer_mac_info.peer_mac); + qdf_copy_macaddr(peer_mld_mac, &peer_mac_info.peer_mld); + } + + return false; +} + +static QDF_STATUS +csr_roam_issue_discon_sta_roam_cmd(struct mac_context *mac, + uint8_t vdev_id, + enum csr_roam_reason discon_reason, + struct csr_del_sta_params *del_sta_params) +{ + tSmeCmd *cmd; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr peer_mac = QDF_MAC_ADDR_ZERO_INIT; + struct qdf_mac_addr peer_mld_mac = QDF_MAC_ADDR_ZERO_INIT; + + if (csr_is_deauth_disassoc_cmd_active(mac, vdev_id, + del_sta_params->peerMacAddr, + &peer_mac, &peer_mld_mac)) + return status; + + cmd = csr_get_command_buffer(mac); + if (!cmd) { + sme_err("Vdev %d " QDF_MAC_ADDR_FMT " fails to get command buffer for reason %d", + vdev_id, + QDF_MAC_ADDR_REF(del_sta_params->peerMacAddr.bytes), + discon_reason); + return QDF_STATUS_E_RESOURCES; + } + + cmd->command = eSmeCommandRoam; + cmd->vdev_id = vdev_id; + cmd->u.roamCmd.roamReason = discon_reason; + qdf_copy_macaddr((struct qdf_mac_addr *)&cmd->u.roamCmd.peerMac, + &peer_mac); + qdf_copy_macaddr(&cmd->u.roamCmd.peer_mld_addr, &peer_mld_mac); + cmd->u.roamCmd.reason = del_sta_params->reason_code; + + status = csr_queue_sme_command(mac, cmd, false); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("Vdev %d " QDF_MAC_ADDR_FMT " fails to get send message status: %d", + vdev_id, + QDF_MAC_ADDR_REF(del_sta_params->peerMacAddr.bytes), + status); + + return status; +} + +QDF_STATUS +csr_roam_issue_disassociate_sta_cmd(struct mac_context *mac, + uint8_t vdev_id, + struct csr_del_sta_params *del_sta_params) + +{ + return csr_roam_issue_discon_sta_roam_cmd(mac, vdev_id, + eCsrForcedDisassocSta, + del_sta_params); +} + +QDF_STATUS +csr_roam_issue_deauth_sta_cmd(struct mac_context *mac, + uint8_t vdev_id, + struct csr_del_sta_params *del_sta_params) +{ + return csr_roam_issue_discon_sta_roam_cmd(mac, vdev_id, + eCsrForcedDeauthSta, + del_sta_params); +} + +/** + * csr_get_peer_stats_cb - Peer stats callback + * @ev: stats event + * @cookie: Void pointer to mac contaxt + * + * Return: None + */ +static void csr_get_peer_stats_cb(struct stats_event *ev, void *cookie) +{ + struct mac_context *mac = (struct mac_context *)cookie; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + if (!mac) { + sme_err("Invalid mac ctx"); + return; + } + + mlme_obj = mlme_get_psoc_ext_obj(mac->psoc); + if (!mlme_obj) { + sme_err("NULL mlme psoc object"); + return; + } + + qdf_mc_timer_stop( + &mlme_obj->disconnect_stats_param.disconn_stats_timer); + + if (!ev->peer_stats) { + sme_debug("no peer stats"); + goto disconnect_stats_complete; + } + + mac->peer_rssi = ev->peer_stats->peer_rssi; + mac->peer_txrate = ev->peer_stats->tx_rate; + mac->peer_rxrate = ev->peer_stats->rx_rate; + if (!ev->peer_extended_stats) { + sme_debug("no peer extended stats"); + goto disconnect_stats_complete; + } + mac->rx_mc_bc_cnt = ev->peer_extended_stats->rx_mc_bc_cnt; + +disconnect_stats_complete: + sme_debug("peer rssi %d tx_rate %d rx_rate %d rx_mc_bc_cnt %d", + mac->peer_rssi, mac->peer_txrate, mac->peer_rxrate, + mac->rx_mc_bc_cnt); + csr_continue_peer_disconnect_after_get_stats(mac); +} + +/** + * csr_get_peer_stats - Get Peer stats + * @mac: MAC contaxt + * @session_id: Current session id + * @peer_mac: Peer mac address + * + * Return: None + */ +static void csr_get_peer_stats(struct mac_context *mac, uint32_t session_id, + struct qdf_mac_addr peer_mac) +{ + struct wlan_objmgr_vdev *vdev; + struct request_info info = {0}; + QDF_STATUS status; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + mlme_obj = mlme_get_psoc_ext_obj(mac->psoc); + if (!mlme_obj) { + sme_err("NULL mlme psoc object"); + return; + } + /* Reset is_disconn_stats_completed before error handing. */ + qdf_atomic_set( + &mlme_obj->disconnect_stats_param.is_disconn_stats_completed, + 0); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, session_id, + WLAN_LEGACY_SME_ID); + + if (!vdev) { + csr_continue_peer_disconnect_after_get_stats(mac); + return; + } + + info.cookie = mac; + info.u.get_peer_rssi_cb = csr_get_peer_stats_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + qdf_mem_copy(info.peer_mac_addr, &peer_mac, QDF_MAC_ADDR_SIZE); + sme_debug("peer_mac" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac.bytes)); + mlme_obj->disconnect_stats_param.vdev_id = info.vdev_id; + status = ucfg_mc_cp_stats_send_stats_request(vdev, TYPE_PEER_STATS, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("stats req failed: %d", status); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + csr_continue_peer_disconnect_after_get_stats(mac); + return; + } + + qdf_mc_timer_start( + &mlme_obj->disconnect_stats_param.disconn_stats_timer, + SME_CMD_GET_DISCONNECT_STATS_TIMEOUT); + + wma_get_rx_retry_cnt(mac, session_id, info.peer_mac_addr); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} + +QDF_STATUS csr_roam_process_command(struct mac_context *mac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t sessionId = pCommand->vdev_id; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + struct qdf_mac_addr peer_mac; + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + sme_debug("Roam Reason: %d sessionId: %d", + pCommand->u.roamCmd.roamReason, sessionId); + + switch (pCommand->u.roamCmd.roamReason) { + case eCsrForcedDisassocSta: + case eCsrForcedDeauthSta: + csr_roam_state_change(mac, eCSR_ROAMING_STATE_JOINING, + sessionId); + if (pCommand->u.roamCmd.roamReason == eCsrForcedDeauthSta) + csr_roam_substate_change(mac, + eCSR_ROAM_SUBSTATE_DEAUTH_REQ, + sessionId); + else + csr_roam_substate_change( + mac, + eCSR_ROAM_SUBSTATE_DISASSOC_REQ, + sessionId); + + qdf_mem_copy(&peer_mac, &pCommand->u.roamCmd.peerMac, + QDF_MAC_ADDR_SIZE); + /* + * Get peer stats before peer gets deleted so that these stats + * can be given to user space when big data stats are queried. + * Once peer stats are retrieved deauth sta will continue + */ + csr_get_peer_stats(mac, sessionId, peer_mac); + break; + } + return status; +} + +void csr_reinit_roam_cmd(struct mac_context *mac, tSmeCmd *pCommand) +{ + /* Because u.roamCmd is union and share with scanCmd and StatusChange */ + qdf_mem_zero(&pCommand->u.roamCmd, sizeof(struct roam_cmd)); +} + +void csr_reinit_wm_status_change_cmd(struct mac_context *mac, + tSmeCmd *pCommand) +{ + qdf_mem_zero(&pCommand->u.wmStatusChangeCmd, + sizeof(struct wmstatus_changecmd)); +} + +void csr_roam_complete(struct mac_context *mac_ctx, uint8_t session_id) +{ + tSmeCmd *sme_cmd; + struct wlan_serialization_command *cmd; + + cmd = wlan_serialization_peek_head_active_cmd_using_psoc( + mac_ctx->psoc, false); + if (!cmd) { + sme_err("Roam completion called but cmd is not active"); + return; + } + sme_cmd = cmd->umac_cmd; + if (!sme_cmd) { + sme_err("sme_cmd is NULL"); + return; + } + if (eSmeCommandRoam == sme_cmd->command) { + csr_roam_process_results_default(mac_ctx, sme_cmd); + csr_release_command(mac_ctx, sme_cmd); + } +} + +/* Returns whether the current association is a 11r assoc or not */ +bool csr_roam_is11r_assoc(struct mac_context *mac, uint8_t sessionId) +{ + struct cm_roam_values_copy config; + + wlan_cm_roam_cfg_get_value(mac->psoc, sessionId, IS_11R_CONNECTION, + &config); + + return config.bool_value; +} + +void csr_roam_process_results_default(struct mac_context *mac_ctx, + tSmeCmd *cmd) +{ + uint32_t session_id = cmd->vdev_id; + struct csr_roam_session *session; + struct csr_roam_info *roam_info; + QDF_STATUS status; + enum QDF_OPMODE opmode; + + if (!CSR_IS_SESSION_VALID(mac_ctx, session_id)) { + sme_err("Invalid session id %d", session_id); + return; + } + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, session_id); + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + session = CSR_GET_SESSION(mac_ctx, session_id); + if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, session_id)) { + /* + * do not free for the other profiles as we need + * to send down stop BSS later + */ + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_set_default_dot11_mode(mac_ctx); + } + + switch (cmd->u.roamCmd.roamReason) { + case eCsrForcedDisassocSta: + case eCsrForcedDeauthSta: + roam_info->rssi = mac_ctx->peer_rssi; + roam_info->tx_rate = mac_ctx->peer_txrate; + roam_info->rx_rate = mac_ctx->peer_rxrate; + roam_info->rx_mc_bc_cnt = mac_ctx->rx_mc_bc_cnt; + roam_info->rx_retry_cnt = mac_ctx->rx_retry_cnt; + + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, + session_id); + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) { + qdf_mem_copy(roam_info->peerMac.bytes, + cmd->u.roamCmd.peerMac, + sizeof(tSirMacAddr)); + roam_info->reasonCode = eCSR_ROAM_RESULT_FORCED; + /* Update the MAC reason code */ + roam_info->disassoc_reason = cmd->u.roamCmd.reason; + roam_info->status_code = eSIR_SME_SUCCESS; + status = csr_roam_call_callback(mac_ctx, session_id, + roam_info, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } + break; + default: + csr_roam_state_change(mac_ctx, + eCSR_ROAMING_STATE_IDLE, session_id); + break; + } + qdf_mem_free(roam_info); +} + +/** + * csr_roam_process_start_bss_success() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @context: Additional data in context of the cmd + * @vdev_id: vdev id + * + * Return: None + */ +static void csr_roam_process_start_bss_success(struct mac_context *mac_ctx, + struct csr_roam_info *roam_info, + void *context, uint8_t vdev_id) +{ + struct csr_roam_session *session; + struct start_bss_rsp *start_bss_rsp = NULL; + eRoamCmdStatus roam_status = eCSR_ROAM_INFRA_IND; + eCsrRoamResult roam_result = eCSR_ROAM_RESULT_INFRA_STARTED; + tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + QDF_STATUS status; + enum QDF_OPMODE opmode; + uint8_t wmm_mode = 0, value = 0; + + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("Invalid session id %d", vdev_id); + return; + } + session = CSR_GET_SESSION(mac_ctx, vdev_id); + + sme_debug("Start BSS success"); + start_bss_rsp = (struct start_bss_rsp *)context; + + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) + session->connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED; + else if (opmode == QDF_NDI_MODE) + session->connectState = eCSR_CONNECT_STATE_TYPE_NDI_STARTED; + else + session->connectState = eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED; + + if (opmode == QDF_NDI_MODE) { + status = ucfg_mlme_get_wmm_mode(mac_ctx->psoc, &wmm_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + if (wmm_mode == WMM_USER_MODE_NO_QOS) { + session->modifyProfileFields.uapsd_mask = 0; + } else { + status = + ucfg_mlme_get_wmm_uapsd_mask(mac_ctx->psoc, &value); + if (!QDF_IS_STATUS_SUCCESS(status)) + return; + session->modifyProfileFields.uapsd_mask = value; + } + } + csr_roam_state_change(mac_ctx, eCSR_ROAMING_STATE_JOINED, vdev_id); + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + wlan_mlme_get_mac_vdev_id(mac_ctx->pdev, vdev_id, &roam_info->bssid); + + /* We are done with the IEs so free it */ + /* + * Only set context for non-WDS_STA. We don't even need it for + * WDS_AP. But since the encryption. + * is WPA2-PSK so it won't matter. + */ + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) { + if (wlan_is_open_wep_cipher(mac_ctx->pdev, vdev_id)) { + csr_issue_set_context_req_helper(mac_ctx, vdev_id, + &bcast_mac, false, + false, 0); + } + } + + /* + * Only tell upper layer is we start the BSS because Vista doesn't like + * multiple connection indications. If we don't start the BSS ourself, + * handler of eSIR_SME_JOINED_NEW_BSS will trigger the connection start + * indication in Vista + */ + roam_info->staId = (uint8_t)start_bss_rsp->staId; + if (opmode == QDF_NDI_MODE) { + csr_roam_update_ndp_return_params(mac_ctx, + CSR_SAP_START_BSS_SUCCESS, + &roam_status, + &roam_result, + roam_info); + } + /* + * Only tell upper layer is we start the BSS because Vista + * doesn't like multiple connection indications. If we don't + * start the BSS ourself, handler of eSIR_SME_JOINED_NEW_BSS + * will trigger the connection start indication in Vista + */ + roam_info->status_code = eSIR_SME_SUCCESS; + csr_roam_call_callback(mac_ctx, vdev_id, roam_info, + roam_status, roam_result); +} + +static void csr_flush_pending_start_bss_cmd(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + struct wlan_serialization_queued_cmd_info cmd = {0}; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev not found for id %d", vdev_id); + return; + } + + /* Flush any pending vdev start command */ + cmd.vdev = vdev; + cmd.cmd_type = WLAN_SER_CMD_VDEV_START_BSS; + cmd.req_type = WLAN_SER_CANCEL_VDEV_NON_SCAN_CMD_TYPE; + cmd.requestor = WLAN_UMAC_COMP_MLME; + cmd.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; + + wlan_serialization_cancel_request(&cmd); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} + +bool cm_csr_is_ss_wait_for_key(uint8_t vdev_id) +{ + struct mac_context *mac; + bool is_wait_for_key = false; + + mac = sme_get_mac_context(); + if (!mac) { + sme_err("mac_ctx is NULL"); + return is_wait_for_key; + } + + spin_lock(&mac->roam.roam_state_lock); + if (CSR_IS_WAIT_FOR_KEY(mac, vdev_id)) + is_wait_for_key = true; + spin_unlock(&mac->roam.roam_state_lock); + + return is_wait_for_key; +} + +void cm_csr_set_ss_wait_for_key(uint8_t vdev_id) +{ + struct mac_context *mac; + + mac = sme_get_mac_context(); + if (!mac) { + sme_err("mac_ctx is NULL"); + return; + } + + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_WAIT_FOR_KEY, + vdev_id); +} + +void cm_csr_set_joining(uint8_t vdev_id) +{ + struct mac_context *mac; + + mac = sme_get_mac_context(); + if (!mac) { + sme_err("mac_ctx is NULL"); + return; + } + + csr_roam_state_change(mac, eCSR_ROAMING_STATE_JOINING, vdev_id); +} + +void cm_csr_set_joined(uint8_t vdev_id) +{ + struct mac_context *mac; + + mac = sme_get_mac_context(); + if (!mac) { + sme_err("mac_ctx is NULL"); + return; + } + + csr_roam_state_change(mac, eCSR_ROAMING_STATE_JOINED, vdev_id); +} + +void cm_csr_set_idle(uint8_t vdev_id) +{ + struct mac_context *mac; + + mac = sme_get_mac_context(); + if (!mac) { + sme_err("mac_ctx is NULL"); + return; + } + + csr_roam_state_change(mac, eCSR_ROAMING_STATE_IDLE, vdev_id); +} + +void cm_csr_set_ss_none(uint8_t vdev_id) +{ + struct mac_context *mac; + + mac = sme_get_mac_context(); + if (!mac) { + sme_err("mac_ctx is NULL"); + return; + } + + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_NONE, + vdev_id); +} + +QDF_STATUS csr_roam_ndi_stop(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool is_vdev_up; + bool is_start_bss_in_active_q = false; + + csr_flush_pending_start_bss_cmd(mac_ctx, vdev_id); + + is_vdev_up = wlan_is_vdev_id_up(mac_ctx->pdev, vdev_id); + if (wlan_serialization_get_active_cmd(mac_ctx->psoc, vdev_id, + WLAN_SER_CMD_VDEV_START_BSS)) + is_start_bss_in_active_q = true; + + sme_debug("vdev_id: %d is_vdev_up %d is_start_bss_in_active_q %d", + vdev_id, is_vdev_up, is_start_bss_in_active_q); + + if (is_vdev_up || is_start_bss_in_active_q) + status = csr_roam_issue_stop_bss_cmd(mac_ctx, vdev_id, + eCSR_BSS_TYPE_NDI); + return status; +} + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +static void csr_fill_single_pmk(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct bss_description *bss_desc) +{ + struct cm_roam_values_copy src_cfg = {}; + + src_cfg.bool_value = bss_desc->is_single_pmk; + wlan_cm_roam_cfg_set_value(psoc, vdev_id, + IS_SINGLE_PMK, &src_cfg); +} +#else +static inline void +csr_fill_single_pmk(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct bss_description *bss_desc) +{} +#endif + +void csr_roam_roaming_state_stop_bss_rsp_processor(struct mac_context *mac, + void *msg) +{ + struct stop_bss_rsp *stop_bss_rsp = (struct stop_bss_rsp *)msg; + uint8_t vdev_id = stop_bss_rsp->vdev_id; + enum csr_sap_response_type result_code = CSR_SAP_STOP_BSS_SUCCESS; + + sme_debug("Received stop bss rsp on vdev: %d", vdev_id); + mac->roam.roamSession[vdev_id].connectState = + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac, vdev_id)) { + if (stop_bss_rsp->status_code != eSIR_SME_SUCCESS) + result_code = CSR_SAP_STOP_BSS_FAILURE; + csr_process_sap_response(mac, result_code, NULL, vdev_id); + } +} + +static +void csr_roam_roaming_state_disassoc_rsp_processor(struct mac_context *mac, + struct disassoc_rsp *rsp) +{ + struct csr_roam_session *pSession; + + sme_debug("Received disassoc response for vdev : %d status : %d", + rsp->sessionId, rsp->status_code); + + pSession = CSR_GET_SESSION(mac, rsp->sessionId); + if (!pSession) { + sme_err("session not found"); + return; + } + + csr_roam_complete(mac, rsp->sessionId); +} + +static void csr_roam_roaming_state_deauth_rsp_processor(struct mac_context *mac, + struct deauth_rsp *rsp) +{ + csr_roam_complete(mac, rsp->sessionId); +} + +void +csr_roam_roaming_state_start_bss_rsp_processor(struct mac_context *mac, + void *msg) +{ + enum csr_sap_response_type result; + struct start_bss_rsp *start_bss_rsp = (struct start_bss_rsp *)msg; + + if (!CSR_IS_ROAM_SUBSTATE_START_BSS_REQ(mac, start_bss_rsp->vdev_id)) { + sme_err(" Start bss received in invalid state"); + return; + } + + sme_debug("Start Bss response status : %d", + start_bss_rsp->status_code); + if (start_bss_rsp->status_code == eSIR_SME_SUCCESS) + result = CSR_SAP_START_BSS_SUCCESS; + else + result = CSR_SAP_START_BSS_FAILURE; + + csr_process_sap_response(mac, result, start_bss_rsp, + start_bss_rsp->vdev_id); +} + + +/** + * csr_roam_send_disconnect_done_indication() - Send disconnect ind to HDD. + * + * @mac_ctx: mac global context + * @msg_ptr: incoming message + * + * This function gives final disconnect event to HDD after all cleanup in + * lower layers is done. + * + * Return: None + */ +static void +csr_roam_send_disconnect_done_indication(struct mac_context *mac_ctx, + tSirSmeRsp *msg_ptr) +{ + struct sir_sme_discon_done_ind *discon_ind = + (struct sir_sme_discon_done_ind *)(msg_ptr); + struct csr_roam_info *roam_info; + uint8_t vdev_id; + + vdev_id = discon_ind->session_id; + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + + sme_debug("DISCONNECT_DONE_IND RC:%d", discon_ind->reason_code); + + if (CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + roam_info->reasonCode = discon_ind->reason_code; + roam_info->status_code = eSIR_SME_STA_NOT_ASSOCIATED; + qdf_mem_copy(roam_info->peerMac.bytes, discon_ind->peer_mac, + ETH_ALEN); + + roam_info->rssi = mac_ctx->peer_rssi; + roam_info->tx_rate = mac_ctx->peer_txrate; + roam_info->rx_rate = mac_ctx->peer_rxrate; + roam_info->disassoc_reason = discon_ind->reason_code; + roam_info->rx_mc_bc_cnt = mac_ctx->rx_mc_bc_cnt; + roam_info->rx_retry_cnt = mac_ctx->rx_retry_cnt; + csr_roam_call_callback(mac_ctx, vdev_id, + roam_info, eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_DISASSOC_IND); + } else { + sme_err("Inactive vdev_id %d", vdev_id); + } + + /* + * Release WM status change command as eWNI_SME_DISCONNECT_DONE_IND + * has been sent to HDD and there is nothing else left to do. + */ + csr_roam_wm_status_change_complete(mac_ctx, vdev_id); + qdf_mem_free(roam_info); +} + +/** + * csr_roaming_state_msg_processor() - process roaming messages + * @mac: mac global context + * @msg_buf: message buffer + * + * We need to be careful on whether to cast msg_buf (pSmeRsp) to other type of + * structures. It depends on how the message is constructed. If the message is + * sent by lim_send_sme_rsp, the msg_buf is only a generic response and can only + * be used as pointer to tSirSmeRsp. For the messages where sender allocates + * memory for specific structures, then it can be cast accordingly. + * + * Return: status of operation + */ +void csr_roaming_state_msg_processor(struct mac_context *mac, void *msg_buf) +{ + tSirSmeRsp *pSmeRsp; + + pSmeRsp = (tSirSmeRsp *)msg_buf; + + switch (pSmeRsp->messageType) { + case eWNI_SME_DISASSOC_RSP: + /* or the Disassociate response message... */ + if (CSR_IS_ROAM_SUBSTATE_DISASSOC_REQ(mac, pSmeRsp->vdev_id)) { + sme_debug("eWNI_SME_DISASSOC_RSP subState = %s", + mac_trace_getcsr_roam_sub_state( + mac->roam.curSubState[pSmeRsp->vdev_id])); + csr_roam_roaming_state_disassoc_rsp_processor(mac, + (struct disassoc_rsp *) pSmeRsp); + } + break; + case eWNI_SME_DEAUTH_RSP: + /* or the Deauthentication response message... */ + if (CSR_IS_ROAM_SUBSTATE_DEAUTH_REQ(mac, pSmeRsp->vdev_id)) + csr_roam_roaming_state_deauth_rsp_processor(mac, + (struct deauth_rsp *) pSmeRsp); + break; + /* In case CSR issues STOP_BSS, we need to tell HDD about peer departed + * because PE is removing them + */ + case eWNI_SME_TRIGGER_SAE: + sme_debug("Invoke SAE callback"); + csr_sae_callback(mac, pSmeRsp); + break; + + case eWNI_SME_SETCONTEXT_RSP: + csr_roam_check_for_link_status_change(mac, pSmeRsp); + break; + + case eWNI_SME_DISCONNECT_DONE_IND: + csr_roam_send_disconnect_done_indication(mac, pSmeRsp); + break; + + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: + csr_roam_joined_state_msg_processor(mac, pSmeRsp); + break; + default: + sme_debug("Unexpected message type: %d[0x%X] received in substate %s", + pSmeRsp->messageType, pSmeRsp->messageType, + mac_trace_getcsr_roam_sub_state( + mac->roam.curSubState[pSmeRsp->vdev_id])); + /* If we are connected, check the link status change */ + if (!csr_is_conn_state_disconnected(mac, pSmeRsp->vdev_id)) + csr_roam_check_for_link_status_change(mac, pSmeRsp); + break; + } +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +csr_roam_assoc_cnf_mld_copy(struct csr_roam_info *roam_info, + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf, + uint32_t num_bytes) +{ + qdf_mem_copy(roam_info->peer_mld.bytes, + pUpperLayerAssocCnf->peer_mld_addr, + num_bytes); +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +csr_roam_assoc_cnf_mld_copy(struct csr_roam_info *roam_info, + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf, + uint32_t num_bytes) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +void csr_roam_joined_state_msg_processor(struct mac_context *mac, void *msg_buf) +{ + tSirSmeRsp *pSirMsg = (tSirSmeRsp *)msg_buf; + + switch (pSirMsg->messageType) { + case eWNI_SME_UPPER_LAYER_ASSOC_CNF: + { + struct csr_roam_session *pSession; + tSirSmeAssocIndToUpperLayerCnf *pUpperLayerAssocCnf; + struct csr_roam_info *roam_info; + uint32_t sessionId; + QDF_STATUS status; + enum QDF_OPMODE opmode; + + sme_debug("ASSOCIATION confirmation can be given to upper layer "); + pUpperLayerAssocCnf = + (tSirSmeAssocIndToUpperLayerCnf *)msg_buf; + status = csr_roam_get_session_id_from_bssid(mac, + (struct qdf_mac_addr *) + pUpperLayerAssocCnf-> + bssId, &sessionId); + pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + if (pUpperLayerAssocCnf->ies) + qdf_mem_free(pUpperLayerAssocCnf->ies); + return; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) { + if (pUpperLayerAssocCnf->ies) + qdf_mem_free(pUpperLayerAssocCnf->ies); + return; + } + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, sessionId); + /* send the status code as Success */ + roam_info->status_code = eSIR_SME_SUCCESS; + roam_info->staId = (uint8_t) pUpperLayerAssocCnf->aid; + roam_info->rsnIELen = + (uint8_t) pUpperLayerAssocCnf->rsnIE.length; + roam_info->prsnIE = + pUpperLayerAssocCnf->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + roam_info->wapiIELen = + (uint8_t) pUpperLayerAssocCnf->wapiIE.length; + roam_info->pwapiIE = + pUpperLayerAssocCnf->wapiIE.wapiIEdata; +#endif + roam_info->addIELen = + (uint8_t) pUpperLayerAssocCnf->addIE.length; + roam_info->paddIE = + pUpperLayerAssocCnf->addIE.addIEdata; + qdf_mem_copy(roam_info->peerMac.bytes, + pUpperLayerAssocCnf->peerMacAddr, + sizeof(tSirMacAddr)); + csr_roam_assoc_cnf_mld_copy(roam_info, + pUpperLayerAssocCnf, + sizeof(tSirMacAddr)); + qdf_mem_copy(&roam_info->bssid, + pUpperLayerAssocCnf->bssId, + sizeof(struct qdf_mac_addr)); + roam_info->wmmEnabledSta = + pUpperLayerAssocCnf->wmmEnabledSta; + roam_info->timingMeasCap = + pUpperLayerAssocCnf->timingMeasCap; + qdf_mem_copy(&roam_info->chan_info, + &pUpperLayerAssocCnf->chan_info, + sizeof(struct oem_channel_info)); + + roam_info->ampdu = pUpperLayerAssocCnf->ampdu; + roam_info->sgi_enable = pUpperLayerAssocCnf->sgi_enable; + roam_info->tx_stbc = pUpperLayerAssocCnf->tx_stbc; + roam_info->rx_stbc = pUpperLayerAssocCnf->rx_stbc; + roam_info->ch_width = pUpperLayerAssocCnf->ch_width; + roam_info->mode = pUpperLayerAssocCnf->mode; + roam_info->max_supp_idx = pUpperLayerAssocCnf->max_supp_idx; + roam_info->max_ext_idx = pUpperLayerAssocCnf->max_ext_idx; + roam_info->max_mcs_idx = pUpperLayerAssocCnf->max_mcs_idx; + roam_info->max_real_mcs_idx = + pUpperLayerAssocCnf->max_real_mcs_idx; + roam_info->rx_mcs_map = pUpperLayerAssocCnf->rx_mcs_map; + roam_info->tx_mcs_map = pUpperLayerAssocCnf->tx_mcs_map; + roam_info->ecsa_capable = pUpperLayerAssocCnf->ecsa_capable; + roam_info->ext_cap = pUpperLayerAssocCnf->ext_cap; + roam_info->supported_band = + pUpperLayerAssocCnf->supported_band; + if (pUpperLayerAssocCnf->ht_caps.present) + roam_info->ht_caps = pUpperLayerAssocCnf->ht_caps; + if (pUpperLayerAssocCnf->vht_caps.present) + roam_info->vht_caps = pUpperLayerAssocCnf->vht_caps; + roam_info->capability_info = + pUpperLayerAssocCnf->capability_info; + roam_info->he_caps_present = + pUpperLayerAssocCnf->he_caps_present; + roam_info->eht_caps_present = + pUpperLayerAssocCnf->eht_caps_present; + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) { + if (pUpperLayerAssocCnf->ies_len > 0) { + roam_info->assocReqLength = + pUpperLayerAssocCnf->ies_len; + roam_info->assocReqPtr = + pUpperLayerAssocCnf->ies; + } + + mac->roam.roamSession[sessionId].connectState = + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED; + roam_info->fReassocReq = + pUpperLayerAssocCnf->reassocReq; + status = csr_roam_call_callback(mac, sessionId, + roam_info, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + } + if (pUpperLayerAssocCnf->ies) + qdf_mem_free(pUpperLayerAssocCnf->ies); + qdf_mem_free(roam_info); + } + break; + default: + csr_roam_check_for_link_status_change(mac, pSirMsg); + break; + } +} + +/** + * csr_update_wep_key_peer_macaddr() - Update wep key peer mac addr + * @vdev: vdev object + * @crypto_key: crypto key info + * @unicast: uncast or broadcast + * @mac_addr: peer mac address + * + * Update peer mac address to key context before set wep key to target. + * + * Return void + */ +static void +csr_update_wep_key_peer_macaddr(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_key *crypto_key, + bool unicast, + struct qdf_mac_addr *mac_addr) +{ + if (!crypto_key || !vdev) { + sme_err("vdev or crytpo_key null"); + return; + } + + if (unicast) { + qdf_mem_copy(&crypto_key->macaddr, mac_addr, + QDF_MAC_ADDR_SIZE); + } else { + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE || + vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE) + qdf_mem_copy(&crypto_key->macaddr, mac_addr, + QDF_MAC_ADDR_SIZE); + else + qdf_mem_copy(&crypto_key->macaddr, + vdev->vdev_mlme.macaddr, + QDF_MAC_ADDR_SIZE); + } +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_set_ctx_rsp(struct mac_context *mac_ctx, + struct csr_roam_session *session, + struct set_context_rsp *pRsp) +{ + WLAN_HOST_DIAG_EVENT_DEF(setKeyEvent, + host_event_wlan_security_payload_type); + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, + session->vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) + return; + if (cm_is_open_mode(vdev)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + qdf_mem_zero(&setKeyEvent, + sizeof(host_event_wlan_security_payload_type)); + if (qdf_is_macaddr_group(&pRsp->peer_macaddr)) + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_BCAST_RSP; + else + setKeyEvent.eventId = + WLAN_SECURITY_EVENT_SET_UNICAST_RSP; + cm_diag_get_auth_enc_type_vdev_id(mac_ctx->psoc, + &setKeyEvent.authMode, + &setKeyEvent.encryptionModeUnicast, + &setKeyEvent.encryptionModeMulticast, + session->vdev_id); + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, session->vdev_id, + (struct qdf_mac_addr *)&setKeyEvent.bssid); + if (eSIR_SME_SUCCESS != pRsp->status_code) + setKeyEvent.status = WLAN_SECURITY_STATUS_FAILURE; + WLAN_HOST_DIAG_EVENT_REPORT(&setKeyEvent, EVENT_WLAN_SECURITY); +} +#else /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ +static void +csr_roam_diag_set_ctx_rsp(struct mac_context *mac_ctx, + struct csr_roam_session *session, + struct set_context_rsp *pRsp) +{ +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +csr_roam_send_rso_enable(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_objmgr_vdev *assoc_vdev = NULL; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + sme_err("vdev object is NULL for vdev %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + mlo_check_if_all_links_up(vdev)) { + assoc_vdev = wlan_mlo_get_assoc_link_vdev(vdev); + if (!assoc_vdev) { + sme_err("Assoc vdev is null"); + wlan_objmgr_vdev_release_ref(vdev, + WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_E_FAILURE; + } + cm_roam_start_init_on_connect(mac_ctx->pdev, + wlan_vdev_get_id(assoc_vdev)); + } else if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + cm_roam_start_init_on_connect(mac_ctx->pdev, vdev_id); + } + wlan_objmgr_vdev_release_ref(vdev, + WLAN_MLME_OBJMGR_ID); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +csr_roam_send_rso_enable(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + cm_roam_start_init_on_connect(mac_ctx->pdev, vdev_id); + return QDF_STATUS_SUCCESS; +} +#endif + +static void +csr_roam_chk_lnk_set_ctx_rsp(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + qdf_freq_t chan_freq; + struct csr_roam_info *roam_info; + eCsrRoamResult result = eCSR_ROAM_RESULT_NONE; + struct set_context_rsp *pRsp = (struct set_context_rsp *)msg_ptr; + struct qdf_mac_addr connected_bssid; + + if (!pRsp) { + sme_err("set key response is NULL"); + return; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + sessionId = pRsp->sessionId; + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + qdf_mem_free(roam_info); + return; + } + + csr_roam_diag_set_ctx_rsp(mac_ctx, session, pRsp); + chan_freq = wlan_get_operation_chan_freq_vdev_id(mac_ctx->pdev, + sessionId); + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, sessionId, + &connected_bssid); + sme_debug("vdev %d, Status %d, peer_macaddr "QDF_MAC_ADDR_FMT " obss offload %d freq %d opmode %d", + pRsp->sessionId, pRsp->status_code, + QDF_MAC_ADDR_REF(pRsp->peer_macaddr.bytes), + mac_ctx->obss_scan_offload, chan_freq, + wlan_get_opmode_from_vdev_id(mac_ctx->pdev, sessionId)); + + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, sessionId)) { + /* We are done with authentication, whethere succeed or not */ + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + sessionId); + cm_stop_wait_for_key_timer(mac_ctx->psoc, sessionId); + if (QDF_IS_STATUS_ERROR(csr_roam_send_rso_enable(mac_ctx, + sessionId))) { + qdf_mem_free(roam_info); + return; + } + } + if (eSIR_SME_SUCCESS == pRsp->status_code) { + qdf_copy_macaddr(&roam_info->peerMac, &pRsp->peer_macaddr); + /* Make sure we install the GTK before indicating to HDD as + * authenticated. This is to prevent broadcast packets go out + * after PTK and before GTK. + */ + if (qdf_is_macaddr_broadcast(&pRsp->peer_macaddr)) { + /* + * OBSS SCAN Indication will be sent to Firmware + * to start OBSS Scan + */ + if (mac_ctx->obss_scan_offload && + wlan_reg_is_24ghz_ch_freq(chan_freq) && + cm_is_vdevid_connected(mac_ctx->pdev, sessionId)) { + struct sme_obss_ht40_scanind_msg *msg; + + msg = qdf_mem_malloc(sizeof( + struct sme_obss_ht40_scanind_msg)); + if (!msg) { + qdf_mem_free(roam_info); + return; + } + + msg->msg_type = eWNI_SME_HT40_OBSS_SCAN_IND; + msg->length = + sizeof(struct sme_obss_ht40_scanind_msg); + qdf_copy_macaddr(&msg->mac_addr, + &connected_bssid); + status = umac_send_mb_message_to_mac(msg); + } + result = eCSR_ROAM_RESULT_AUTHENTICATED; + } else { + result = eCSR_ROAM_RESULT_NONE; + } + } else { + result = eCSR_ROAM_RESULT_FAILURE; + sme_err( + "CSR: setkey command failed(err=%d) PeerMac " + QDF_MAC_ADDR_FMT, + pRsp->status_code, + QDF_MAC_ADDR_REF(pRsp->peer_macaddr.bytes)); + } + csr_roam_call_callback(mac_ctx, sessionId, roam_info, + eCSR_ROAM_SET_KEY_COMPLETE, result); + /* Indicate SME_QOS that the SET_KEY is completed, so that SME_QOS + * can go ahead and initiate the TSPEC if any are pending + */ + sme_qos_csr_event_ind(mac_ctx, (uint8_t)sessionId, + SME_QOS_CSR_SET_KEY_SUCCESS_IND, NULL); +#ifdef FEATURE_WLAN_ESE + /* Send Adjacent AP repot to new AP. */ + if (result == eCSR_ROAM_RESULT_AUTHENTICATED && + session->isPrevApInfoValid && + wlan_cm_get_ese_assoc(mac_ctx->pdev, sessionId)) { + csr_send_ese_adjacent_ap_rep_ind(mac_ctx, session); + session->isPrevApInfoValid = false; + } +#endif + qdf_mem_free(roam_info); +} + +static QDF_STATUS csr_roam_issue_set_context_req(struct mac_context *mac_ctx, + uint32_t session_id, + bool add_key, bool unicast, + uint8_t key_idx, + struct qdf_mac_addr *mac_addr) +{ + enum wlan_crypto_cipher_type cipher; + struct wlan_crypto_key *crypto_key; + uint8_t wep_key_idx = 0; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, session_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("VDEV object not found for session_id %d", session_id); + return QDF_STATUS_E_INVAL; + } + cipher = wlan_crypto_get_cipher(vdev, unicast, key_idx); + if (IS_WEP_CIPHER(cipher)) { + wep_key_idx = wlan_crypto_get_default_key_idx(vdev, !unicast); + crypto_key = wlan_crypto_get_key(vdev, wep_key_idx); + csr_update_wep_key_peer_macaddr(vdev, crypto_key, unicast, + mac_addr); + } else { + crypto_key = wlan_crypto_get_key(vdev, key_idx); + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + sme_debug("session:%d, cipher:%d, ucast:%d, idx:%d, wep:%d, add:%d", + session_id, cipher, unicast, key_idx, wep_key_idx, add_key); + if (!IS_WEP_CIPHER(cipher) && !add_key) + return QDF_STATUS_E_INVAL; + + return ucfg_crypto_set_key_req(vdev, crypto_key, (unicast ? + WLAN_CRYPTO_KEY_TYPE_UNICAST : + WLAN_CRYPTO_KEY_TYPE_GROUP)); +} + +QDF_STATUS +csr_issue_set_context_req_helper(struct mac_context *mac_ctx, + uint32_t vdev_id, tSirMacAddr *bssid, + bool addkey, bool unicast, uint8_t key_id) +{ + return csr_roam_issue_set_context_req(mac_ctx, vdev_id, addkey, + unicast, key_id, + (struct qdf_mac_addr *)bssid); +} + +static +bool csr_roam_issue_wm_status_change(struct mac_context *mac, uint32_t sessionId, + enum csr_roam_wmstatus_changetypes Type, + tSirSmeRsp *pSmeRsp) +{ + bool fCommandQueued = false; + tSmeCmd *pCommand; + + do { + /* Validate the type is ok... */ + if ((eCsrDisassociated != Type) + && (eCsrDeauthenticated != Type)) + break; + pCommand = csr_get_command_buffer(mac); + if (!pCommand) { + sme_err(" fail to get command buffer"); + break; + } + + pCommand->command = eSmeCommandWmStatusChange; + pCommand->vdev_id = (uint8_t) sessionId; + pCommand->u.wmStatusChangeCmd.Type = Type; + if (eCsrDisassociated == Type) { + qdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg, pSmeRsp, + sizeof(pCommand->u.wmStatusChangeCmd.u. + DisassocIndMsg)); + } else { + qdf_mem_copy(&pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg, pSmeRsp, + sizeof(pCommand->u.wmStatusChangeCmd.u. + DeauthIndMsg)); + } + if (QDF_IS_STATUS_SUCCESS + (csr_queue_sme_command(mac, pCommand, false))) + fCommandQueued = true; + else + sme_err("fail to send message"); + } while (0); + return fCommandQueued; +} + +static void csr_update_snr(struct mac_context *mac, void *pMsg) +{ + tAniGetSnrReq *pGetSnrReq = (tAniGetSnrReq *) pMsg; + + if (pGetSnrReq) { + if (QDF_STATUS_SUCCESS != wma_get_snr(pGetSnrReq)) { + sme_err("Error in wma_get_snr"); + return; + } + + } else + sme_err("pGetSnrReq is NULL"); +} + +/** + * csr_translate_akm_type() - Convert ani_akm_type value to equivalent + * enum csr_akm_type + * @akm_type: value of type ani_akm_type + * + * Return: enum csr_akm_type value + */ +static enum csr_akm_type csr_translate_akm_type(enum ani_akm_type akm_type) +{ + enum csr_akm_type csr_akm_type; + + switch (akm_type) + { + case ANI_AKM_TYPE_NONE: + csr_akm_type = eCSR_AUTH_TYPE_NONE; + break; +#ifdef WLAN_FEATURE_SAE + case ANI_AKM_TYPE_SAE: + csr_akm_type = eCSR_AUTH_TYPE_SAE; + break; +#endif + case ANI_AKM_TYPE_WPA: + csr_akm_type = eCSR_AUTH_TYPE_WPA; + break; + case ANI_AKM_TYPE_WPA_PSK: + csr_akm_type = eCSR_AUTH_TYPE_WPA_PSK; + break; + case ANI_AKM_TYPE_RSN: + csr_akm_type = eCSR_AUTH_TYPE_RSN; + break; + case ANI_AKM_TYPE_RSN_PSK: + csr_akm_type = eCSR_AUTH_TYPE_RSN_PSK; + break; + case ANI_AKM_TYPE_FT_RSN: + csr_akm_type = eCSR_AUTH_TYPE_FT_RSN; + break; + case ANI_AKM_TYPE_FT_RSN_PSK: + csr_akm_type = eCSR_AUTH_TYPE_FT_RSN_PSK; + break; +#ifdef FEATURE_WLAN_ESE + case ANI_AKM_TYPE_CCKM: + csr_akm_type = eCSR_AUTH_TYPE_CCKM_RSN; + break; +#endif + case ANI_AKM_TYPE_RSN_PSK_SHA256: + csr_akm_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + break; + case ANI_AKM_TYPE_RSN_8021X_SHA256: + csr_akm_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + break; + case ANI_AKM_TYPE_FILS_SHA256: + csr_akm_type = eCSR_AUTH_TYPE_FILS_SHA256; + break; + case ANI_AKM_TYPE_FILS_SHA384: + csr_akm_type = eCSR_AUTH_TYPE_FILS_SHA384; + break; + case ANI_AKM_TYPE_FT_FILS_SHA256: + csr_akm_type = eCSR_AUTH_TYPE_FT_FILS_SHA256; + break; + case ANI_AKM_TYPE_FT_FILS_SHA384: + csr_akm_type = eCSR_AUTH_TYPE_FT_FILS_SHA384; + break; + case ANI_AKM_TYPE_DPP_RSN: + csr_akm_type = eCSR_AUTH_TYPE_DPP_RSN; + break; + case ANI_AKM_TYPE_OWE: + csr_akm_type = eCSR_AUTH_TYPE_OWE; + break; + case ANI_AKM_TYPE_SUITEB_EAP_SHA256: + csr_akm_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; + break; + case ANI_AKM_TYPE_SUITEB_EAP_SHA384: + csr_akm_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + break; + case ANI_AKM_TYPE_OSEN: + csr_akm_type = eCSR_AUTH_TYPE_OSEN; + break; + default: + csr_akm_type = eCSR_AUTH_TYPE_UNKNOWN; + } + + return csr_akm_type; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void +csr_send_assoc_ind_to_upper_layer_mac_copy(tSirSmeAssocIndToUpperLayerCnf *cnf, + struct assoc_ind *ind) +{ + qdf_mem_copy(&cnf->peer_mld_addr, &ind->peer_mld_addr, + sizeof(cnf->peer_mld_addr)); +} +#else /* WLAN_FEATURE_11BE_MLO */ +static inline void +csr_send_assoc_ind_to_upper_layer_mac_copy(tSirSmeAssocIndToUpperLayerCnf *cnf, + struct assoc_ind *ind) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +static QDF_STATUS +csr_send_assoc_ind_to_upper_layer_cnf_msg(struct mac_context *mac, + struct assoc_ind *ind, + QDF_STATUS status, + uint8_t vdev_id) +{ + struct scheduler_msg msg = {0}; + tSirSmeAssocIndToUpperLayerCnf *cnf; + + cnf = qdf_mem_malloc(sizeof(*cnf)); + if (!cnf) + return QDF_STATUS_E_NOMEM; + + cnf->messageType = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + cnf->length = sizeof(*cnf); + cnf->sessionId = vdev_id; + + if (QDF_IS_STATUS_SUCCESS(status)) + cnf->status_code = eSIR_SME_SUCCESS; + else + cnf->status_code = eSIR_SME_ASSOC_REFUSED; + qdf_mem_copy(&cnf->bssId, &ind->bssId, sizeof(cnf->bssId)); + qdf_mem_copy(&cnf->peerMacAddr, &ind->peerMacAddr, + sizeof(cnf->peerMacAddr)); + csr_send_assoc_ind_to_upper_layer_mac_copy(cnf, ind); + cnf->aid = ind->staId; + cnf->wmmEnabledSta = ind->wmmEnabledSta; + cnf->rsnIE = ind->rsnIE; +#ifdef FEATURE_WLAN_WAPI + cnf->wapiIE = ind->wapiIE; +#endif + cnf->addIE = ind->addIE; + cnf->reassocReq = ind->reassocReq; + cnf->timingMeasCap = ind->timingMeasCap; + cnf->chan_info = ind->chan_info; + cnf->ampdu = ind->ampdu; + cnf->sgi_enable = ind->sgi_enable; + cnf->tx_stbc = ind->tx_stbc; + cnf->ch_width = ind->ch_width; + cnf->mode = ind->mode; + cnf->rx_stbc = ind->rx_stbc; + cnf->max_supp_idx = ind->max_supp_idx; + cnf->max_ext_idx = ind->max_ext_idx; + cnf->max_mcs_idx = ind->max_mcs_idx; + cnf->max_real_mcs_idx = ind->max_real_mcs_idx; + cnf->rx_mcs_map = ind->rx_mcs_map; + cnf->tx_mcs_map = ind->tx_mcs_map; + cnf->ecsa_capable = ind->ecsa_capable; + cnf->ext_cap = ind->ext_cap; + cnf->supported_band = ind->supported_band; + if (ind->HTCaps.present) + cnf->ht_caps = ind->HTCaps; + if (ind->VHTCaps.present) + cnf->vht_caps = ind->VHTCaps; + cnf->capability_info = ind->capability_info; + cnf->he_caps_present = ind->he_caps_present; + cnf->eht_caps_present = ind->eht_caps_present; + if (ind->assocReqPtr) { + if (ind->assocReqLength < MAX_ASSOC_REQ_IE_LEN) { + cnf->ies = qdf_mem_malloc(ind->assocReqLength); + if (!cnf->ies) { + qdf_mem_free(cnf); + return QDF_STATUS_E_NOMEM; + } + cnf->ies_len = ind->assocReqLength; + qdf_mem_copy(cnf->ies, ind->assocReqPtr, + cnf->ies_len); + } else { + sme_err("Assoc Ie length is too long"); + } + } + + msg.type = eWNI_SME_UPPER_LAYER_ASSOC_CNF; + msg.bodyptr = cnf; + sys_process_mmh_msg(mac, &msg); + + return QDF_STATUS_SUCCESS; +} + +static void +csr_roam_chk_lnk_assoc_ind_upper_layer( + struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t session_id = WLAN_UMAC_VDEV_ID_MAX; + struct assoc_ind *assoc_ind; + QDF_STATUS status; + + assoc_ind = (struct assoc_ind *)msg_ptr; + status = csr_roam_get_session_id_from_bssid( + mac_ctx, (struct qdf_mac_addr *)assoc_ind->bssId, + &session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Couldn't find session_id for given BSSID"); + goto free_mem; + } + csr_send_assoc_ind_to_upper_layer_cnf_msg( + mac_ctx, assoc_ind, status, session_id); + /*in the association response tx compete case, + *memory for assoc_ind->assocReqPtr will be malloced + *in the lim_assoc_rsp_tx_complete -> lim_fill_sme_assoc_ind_params + *and then assoc_ind will pass here, so after using it + *in the csr_send_assoc_ind_to_upper_layer_cnf_msg and + *then free the memory here. + */ +free_mem: + if (assoc_ind->assocReqLength != 0 && assoc_ind->assocReqPtr) + qdf_mem_free(assoc_ind->assocReqPtr); +} + +static void +csr_roam_chk_lnk_assoc_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + struct csr_roam_info *roam_info; + struct assoc_ind *pAssocInd; + enum wlan_status_code mac_status_code = STATUS_SUCCESS; + enum csr_akm_type csr_akm_type; + enum QDF_OPMODE opmode; + + sme_debug("Receive WNI_SME_ASSOC_IND from SME"); + pAssocInd = (struct assoc_ind *) msg_ptr; + sme_debug("Receive WNI_SME_ASSOC_IND from SME vdev id %d", + pAssocInd->sessionId); + status = csr_roam_get_session_id_from_bssid(mac_ctx, + (struct qdf_mac_addr *) pAssocInd->bssId, + &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Couldn't find session_id for given BSSID" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pAssocInd->bssId)); + return; + } + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + csr_akm_type = csr_translate_akm_type(pAssocInd->akm_type); + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, sessionId); + /* Required for indicating the frames to upper layer */ + roam_info->assocReqLength = pAssocInd->assocReqLength; + roam_info->assocReqPtr = pAssocInd->assocReqPtr; + roam_info->status_code = eSIR_SME_SUCCESS; + roam_info->staId = (uint8_t)pAssocInd->staId; + roam_info->rsnIELen = (uint8_t)pAssocInd->rsnIE.length; + roam_info->prsnIE = pAssocInd->rsnIE.rsnIEdata; +#ifdef FEATURE_WLAN_WAPI + roam_info->wapiIELen = (uint8_t)pAssocInd->wapiIE.length; + roam_info->pwapiIE = pAssocInd->wapiIE.wapiIEdata; +#endif + roam_info->addIELen = (uint8_t)pAssocInd->addIE.length; + roam_info->paddIE = pAssocInd->addIE.addIEdata; + roam_info->fReassocReq = pAssocInd->reassocReq; + qdf_mem_copy(roam_info->peerMac.bytes, + pAssocInd->peerMacAddr, + sizeof(tSirMacAddr)); + qdf_mem_copy(roam_info->bssid.bytes, + pAssocInd->bssId, + sizeof(struct qdf_mac_addr)); + roam_info->wmmEnabledSta = pAssocInd->wmmEnabledSta; + roam_info->timingMeasCap = pAssocInd->timingMeasCap; + roam_info->ecsa_capable = pAssocInd->ecsa_capable; + qdf_mem_copy(&roam_info->chan_info, + &pAssocInd->chan_info, + sizeof(struct oem_channel_info)); + + if (pAssocInd->HTCaps.present) + qdf_mem_copy(&roam_info->ht_caps, + &pAssocInd->HTCaps, + sizeof(tDot11fIEHTCaps)); + if (pAssocInd->VHTCaps.present) + qdf_mem_copy(&roam_info->vht_caps, + &pAssocInd->VHTCaps, + sizeof(tDot11fIEVHTCaps)); + roam_info->capability_info = pAssocInd->capability_info; + roam_info->he_caps_present = pAssocInd->he_caps_present; + roam_info->eht_caps_present = pAssocInd->eht_caps_present; + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) { + if (wlan_is_open_wep_cipher(mac_ctx->pdev, sessionId)) { + csr_issue_set_context_req_helper(mac_ctx, sessionId, + &roam_info->peerMac.bytes, false, true, + 0); + roam_info->fAuthRequired = false; + } else { + roam_info->fAuthRequired = true; + } + sme_debug("Receive AUTH_TYPE of %d", csr_akm_type); + if (csr_akm_type == eCSR_AUTH_TYPE_OWE) { + roam_info->owe_pending_assoc_ind = qdf_mem_malloc( + sizeof(*pAssocInd)); + if (roam_info->owe_pending_assoc_ind) + qdf_mem_copy(roam_info->owe_pending_assoc_ind, + pAssocInd, sizeof(*pAssocInd)); + } else if (csr_akm_type == eCSR_AUTH_TYPE_FT_RSN_PSK) { + roam_info->ft_pending_assoc_ind = qdf_mem_malloc( + sizeof(*pAssocInd)); + if (roam_info->ft_pending_assoc_ind) + qdf_mem_copy(roam_info->ft_pending_assoc_ind, + pAssocInd, sizeof(*pAssocInd)); + } + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND); + if (!QDF_IS_STATUS_SUCCESS(status)) { + /* Refused due to Mac filtering */ + if (roam_info->owe_pending_assoc_ind) { + qdf_mem_free(roam_info->owe_pending_assoc_ind); + roam_info->owe_pending_assoc_ind = NULL; + } else if (roam_info->ft_pending_assoc_ind) { + qdf_mem_free(roam_info->ft_pending_assoc_ind); + roam_info->ft_pending_assoc_ind = NULL; + } + roam_info->status_code = eSIR_SME_ASSOC_REFUSED; + } + } + sme_debug("csr_akm_type: %d", csr_akm_type); + + if (csr_akm_type != eCSR_AUTH_TYPE_OWE && + csr_akm_type != eCSR_AUTH_TYPE_FT_RSN_PSK) { + if ((opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) && + roam_info->status_code != eSIR_SME_ASSOC_REFUSED) + pAssocInd->need_assoc_rsp_tx_cb = true; + /* Send Association completion message to PE */ + status = csr_send_assoc_cnf_msg(mac_ctx, pAssocInd, status, + mac_status_code); + } + + qdf_mem_free(roam_info); +} + +/* csr_if_peer_present() - Check whether peer is present or not + * @mac_ctx: Pointer to mac context + * @bssid: Pointer to bssid address + * @peer_macaddr: Pointer to peer mac address + * + * Consider a case + * 1. SAP received south bound disconnect command + * 2. At same time, SAP CSA to DFS channel happened and thus peers are deleted. + * 3. Later same peer got re-added and south bound disconnect command becomes + * active for same peer. + * + * When SAP receives south bound disconnect command req, driver will post to + * schedular thread and it will wait in SME message queue. When SAP CSA to DFS + * channel happens, driver will post to schedular thread and it will wait in PE + * message queue. Since PE has higher priority than SME message queue, so it + * will process first. As part of CSA, it will delete all peer including sta + * hash entry. + * After CSA, south bound disconnect command got queue to serialization and + * same peer got re-added again. When south bound disconnect command becomes + * active, the states will not be proper because for old peer, disassocTrigger + * is eLIM_PEER_ENTITY_DISASSOC/eLIM_PEER_ENTITY_DEAUTH and when new peer gets + * re-added, disassocTrigger will be eLIM_HOST_DISASSOC/eLIM_HOST_DEAUTH and + * thus response to CSR will not be proper. Due to this south bound disconnect + * command will not remove from active queue which leads to active command + * timeout. + * Validate the peer before sending to serialization to avoid queuing command + * if peer is already deleted. + * + * Return: True if peer is present otherwise return false + */ +static bool csr_if_peer_present(struct mac_context *mac_ctx, + uint8_t *bssid, + uint8_t *peer_macaddr) +{ + struct wlan_objmgr_peer *peer; + uint8_t pdev_id; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(mac_ctx->pdev); + + peer = wlan_objmgr_get_peer_by_mac_n_vdev(mac_ctx->psoc, pdev_id, + bssid, peer_macaddr, + WLAN_LEGACY_SME_ID); + + if (!peer) { + sme_info("peer not found for mac: " QDF_MAC_ADDR_FMT "and bssid: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(peer_macaddr), + QDF_MAC_ADDR_REF(bssid)); + return false; + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_SME_ID); + return true; +} + +static void +csr_roam_chk_lnk_disassoc_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint8_t vdev_id = WLAN_UMAC_VDEV_ID_MAX; + struct disassoc_ind *disassoc_ind; + + /* + * Check if AP dis-associated us because of MIC failure. If so, + * then we need to take action immediately and not wait till the + * the WmStatusChange requests is pushed and processed + */ + disassoc_ind = (struct disassoc_ind *)msg_ptr; + vdev_id = disassoc_ind->vdev_id; + + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("vdev:%d Invalid session. BSSID: " QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(disassoc_ind->bssid.bytes)); + + return; + } + + if (!csr_if_peer_present(mac_ctx, &disassoc_ind->bssid.bytes[0], + &disassoc_ind->peer_macaddr.bytes[0])) + return; + + if (csr_is_deauth_disassoc_cmd_active(mac_ctx, vdev_id, + disassoc_ind->peer_macaddr, + &disassoc_ind->peer_macaddr, + &disassoc_ind->peer_mld_addr)) + return; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_err("vdev %d session not found", vdev_id); + return; + } + sme_debug("Vdev %d, peer " QDF_MAC_ADDR_FMT " reason: %d status: %d", + vdev_id, QDF_MAC_ADDR_REF(disassoc_ind->peer_macaddr.bytes), + disassoc_ind->reasonCode, disassoc_ind->status_code); + /* Update the disconnect stats */ + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.disassoc_by_peer++; + + csr_roam_issue_wm_status_change(mac_ctx, vdev_id, + eCsrDisassociated, msg_ptr); +} + +static void +csr_roam_chk_lnk_deauth_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint8_t vdev_id = WLAN_UMAC_VDEV_ID_MAX; + struct deauth_ind *deauth_ind; + + deauth_ind = (struct deauth_ind *)msg_ptr; + + vdev_id = deauth_ind->vdev_id; + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("vdev %d: Invalid session BSSID: " QDF_MAC_ADDR_FMT, + deauth_ind->vdev_id, + QDF_MAC_ADDR_REF(deauth_ind->bssid.bytes)); + return; + } + + if (!csr_if_peer_present(mac_ctx, &deauth_ind->bssid.bytes[0], + &deauth_ind->peer_macaddr.bytes[0])) + return; + + if (csr_is_deauth_disassoc_cmd_active(mac_ctx, vdev_id, + deauth_ind->peer_macaddr, + &deauth_ind->peer_macaddr, + &deauth_ind->peer_mld_addr)) + return; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_err("vdev %d session not found", vdev_id); + return; + } + sme_debug("vdev %d bssid " QDF_MAC_ADDR_FMT " reason: %d status: %d", + deauth_ind->vdev_id, + QDF_MAC_ADDR_REF(deauth_ind->bssid.bytes), + deauth_ind->reasonCode, deauth_ind->status_code); + /* Update the disconnect stats */ + switch (deauth_ind->reasonCode) { + case REASON_DISASSOC_DUE_TO_INACTIVITY: + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.peer_kickout++; + break; + case REASON_UNSPEC_FAILURE: + case REASON_PREV_AUTH_NOT_VALID: + case REASON_DEAUTH_NETWORK_LEAVING: + case REASON_CLASS2_FRAME_FROM_NON_AUTH_STA: + case REASON_CLASS3_FRAME_FROM_NON_ASSOC_STA: + case REASON_STA_NOT_AUTHENTICATED: + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.deauth_by_peer++; + break; + case REASON_BEACON_MISSED: + session->disconnect_stats.disconnection_cnt++; + session->disconnect_stats.bmiss++; + break; + default: + /* Unknown reason code */ + break; + } + + csr_roam_issue_wm_status_change(mac_ctx, vdev_id, + eCsrDeauthenticated, + msg_ptr); +} + +static void +csr_roam_chk_lnk_swt_ch_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + struct csr_roam_session *session; + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + struct switch_channel_ind *pSwitchChnInd; + struct csr_roam_info *roam_info; + + /* in case of STA, the SWITCH_CHANNEL originates from its AP */ + sme_debug("eWNI_SME_SWITCH_CHL_IND from SME"); + pSwitchChnInd = (struct switch_channel_ind *)msg_ptr; + /* Update with the new channel id. The channel id is hidden in the + * status_code. + */ + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pSwitchChnInd->bssid, &sessionId); + if (QDF_IS_STATUS_ERROR(status)) + return; + + session = CSR_GET_SESSION(mac_ctx, sessionId); + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + + if (QDF_IS_STATUS_ERROR(pSwitchChnInd->status)) { + sme_err("Channel switch failed"); + return; + } + /* Update the occupied channel list with the new switched channel */ + wlan_cm_init_occupied_ch_freq_list(mac_ctx->pdev, mac_ctx->psoc, + sessionId); + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + roam_info->chan_info.mhz = pSwitchChnInd->freq; + roam_info->chan_info.ch_width = pSwitchChnInd->chan_params.ch_width; + roam_info->chan_info.sec_ch_offset = + pSwitchChnInd->chan_params.sec_ch_offset; + roam_info->chan_info.band_center_freq1 = + pSwitchChnInd->chan_params.mhz_freq_seg0; + roam_info->chan_info.band_center_freq2 = + pSwitchChnInd->chan_params.mhz_freq_seg1; + + if (IS_WLAN_PHYMODE_HT(pSwitchChnInd->ch_phymode)) + roam_info->mode = SIR_SME_PHY_MODE_HT; + else if (IS_WLAN_PHYMODE_VHT(pSwitchChnInd->ch_phymode) || + IS_WLAN_PHYMODE_HE(pSwitchChnInd->ch_phymode)) + roam_info->mode = SIR_SME_PHY_MODE_VHT; +#ifdef WLAN_FEATURE_11BE + else if (IS_WLAN_PHYMODE_EHT(pSwitchChnInd->ch_phymode)) + roam_info->mode = SIR_SME_PHY_MODE_VHT; +#endif + else + roam_info->mode = SIR_SME_PHY_MODE_LEGACY; + + status = csr_roam_call_callback(mac_ctx, sessionId, roam_info, + eCSR_ROAM_STA_CHANNEL_SWITCH, + eCSR_ROAM_RESULT_NONE); + qdf_mem_free(roam_info); +} + +static void +csr_roam_chk_lnk_deauth_rsp(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + struct csr_roam_info *roam_info; + struct deauth_rsp *pDeauthRsp = (struct deauth_rsp *) msg_ptr; + enum QDF_OPMODE opmode; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + sme_debug("eWNI_SME_DEAUTH_RSP from SME"); + sessionId = pDeauthRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) { + qdf_mem_free(roam_info); + return; + } + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, sessionId); + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) { + qdf_copy_macaddr(&roam_info->peerMac, + &pDeauthRsp->peer_macaddr); + roam_info->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info->status_code = pDeauthRsp->status_code; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info, eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } + qdf_mem_free(roam_info); +} + +static void +csr_roam_chk_lnk_disassoc_rsp(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + struct csr_roam_info *roam_info; + enum QDF_OPMODE opmode; + /* + * session id is invalid here so cant use it to access the array + * curSubstate as index + */ + struct disassoc_rsp *pDisassocRsp = (struct disassoc_rsp *) msg_ptr; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + sme_debug("eWNI_SME_DISASSOC_RSP from SME "); + sessionId = pDisassocRsp->sessionId; + if (!CSR_IS_SESSION_VALID(mac_ctx, sessionId)) { + qdf_mem_free(roam_info); + return; + } + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, sessionId); + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) { + qdf_copy_macaddr(&roam_info->peerMac, + &pDisassocRsp->peer_macaddr); + roam_info->reasonCode = eCSR_ROAM_RESULT_FORCED; + roam_info->status_code = pDisassocRsp->status_code; + status = csr_roam_call_callback(mac_ctx, sessionId, + roam_info, + eCSR_ROAM_LOSTLINK, + eCSR_ROAM_RESULT_FORCED); + } + qdf_mem_free(roam_info); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void +csr_roam_diag_mic_fail(struct mac_context *mac_ctx, uint32_t sessionId) +{ + WLAN_HOST_DIAG_EVENT_DEF(secEvent, + host_event_wlan_security_payload_type); + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, sessionId); + + if (!session) { + sme_err("session %d not found", sessionId); + return; + } + qdf_mem_zero(&secEvent, sizeof(host_event_wlan_security_payload_type)); + secEvent.eventId = WLAN_SECURITY_EVENT_MIC_ERROR; + cm_diag_get_auth_enc_type_vdev_id(mac_ctx->psoc, + &secEvent.authMode, + &secEvent.encryptionModeUnicast, + &secEvent.encryptionModeMulticast, + sessionId); + wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, sessionId, + (struct qdf_mac_addr *)&secEvent.bssid); + WLAN_HOST_DIAG_EVENT_REPORT(&secEvent, EVENT_WLAN_SECURITY); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +static void +csr_roam_chk_lnk_mic_fail_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + struct csr_roam_info *roam_info; + struct mic_failure_ind *mic_ind = (struct mic_failure_ind *)msg_ptr; + eCsrRoamResult result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &mic_ind->bssId, &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { + roam_info->u.pMICFailureInfo = &mic_ind->info; + if (mic_ind->info.multicast) + result = eCSR_ROAM_RESULT_MIC_ERROR_GROUP; + else + result = eCSR_ROAM_RESULT_MIC_ERROR_UNICAST; + csr_roam_call_callback(mac_ctx, sessionId, roam_info, + eCSR_ROAM_MIC_ERROR_IND, result); + } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_roam_diag_mic_fail(mac_ctx, sessionId); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + qdf_mem_free(roam_info); +} + +static void +csr_roam_chk_lnk_pbs_probe_req_ind(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + struct csr_roam_info *roam_info; + tpSirSmeProbeReqInd pProbeReqInd = (tpSirSmeProbeReqInd) msg_ptr; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + sme_debug("WPS PBC Probe request Indication from SME"); + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &pProbeReqInd->bssid, &sessionId); + if (QDF_IS_STATUS_SUCCESS(status)) { + roam_info->u.pWPSPBCProbeReq = &pProbeReqInd->WPSPBCProbeReq; + csr_roam_call_callback(mac_ctx, sessionId, roam_info, + eCSR_ROAM_WPS_PBC_PROBE_REQ_IND, + eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND); + } + qdf_mem_free(roam_info); +} + +static void +csr_roam_chk_lnk_max_assoc_exceeded(struct mac_context *mac_ctx, tSirSmeRsp *msg_ptr) +{ + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + tSmeMaxAssocInd *pSmeMaxAssocInd; + struct csr_roam_info *roam_info; + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return; + pSmeMaxAssocInd = (tSmeMaxAssocInd *) msg_ptr; + sme_debug( + "max assoc have been reached, new peer cannot be accepted"); + sessionId = pSmeMaxAssocInd->sessionId; + qdf_copy_macaddr(&roam_info->peerMac, &pSmeMaxAssocInd->peer_mac); + csr_roam_call_callback(mac_ctx, sessionId, roam_info, + eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED); + qdf_mem_free(roam_info); +} + +void csr_roam_check_for_link_status_change(struct mac_context *mac, + tSirSmeRsp *pSirMsg) +{ + if (!pSirMsg) { + sme_err("pSirMsg is NULL"); + return; + } + switch (pSirMsg->messageType) { + case eWNI_SME_ASSOC_IND: + csr_roam_chk_lnk_assoc_ind(mac, pSirMsg); + break; + case eWNI_SME_ASSOC_IND_UPPER_LAYER: + csr_roam_chk_lnk_assoc_ind_upper_layer(mac, pSirMsg); + break; + case eWNI_SME_DISASSOC_IND: + csr_roam_chk_lnk_disassoc_ind(mac, pSirMsg); + break; + case eWNI_SME_DISCONNECT_DONE_IND: + csr_roam_send_disconnect_done_indication(mac, pSirMsg); + break; + case eWNI_SME_DEAUTH_IND: + csr_roam_chk_lnk_deauth_ind(mac, pSirMsg); + break; + case eWNI_SME_SWITCH_CHL_IND: + csr_roam_chk_lnk_swt_ch_ind(mac, pSirMsg); + break; + case eWNI_SME_DEAUTH_RSP: + csr_roam_chk_lnk_deauth_rsp(mac, pSirMsg); + break; + case eWNI_SME_DISASSOC_RSP: + csr_roam_chk_lnk_disassoc_rsp(mac, pSirMsg); + break; + case eWNI_SME_MIC_FAILURE_IND: + csr_roam_chk_lnk_mic_fail_ind(mac, pSirMsg); + break; + case eWNI_SME_WPS_PBC_PROBE_REQ_IND: + csr_roam_chk_lnk_pbs_probe_req_ind(mac, pSirMsg); + break; + case eWNI_SME_SETCONTEXT_RSP: + csr_roam_chk_lnk_set_ctx_rsp(mac, pSirMsg); + break; +#ifdef FEATURE_WLAN_ESE + case eWNI_SME_GET_TSM_STATS_RSP: + sme_debug("TSM Stats rsp from PE"); + csr_tsm_stats_rsp_processor(mac, pSirMsg); + break; +#endif /* FEATURE_WLAN_ESE */ + case eWNI_SME_GET_SNR_REQ: + sme_debug("GetSnrReq from self"); + csr_update_snr(mac, pSirMsg); + break; + case eWNI_SME_MAX_ASSOC_EXCEEDED: + csr_roam_chk_lnk_max_assoc_exceeded(mac, pSirMsg); + break; + default: + break; + } /* end switch on message type */ +} + +void csr_roam_wm_status_change_complete(struct mac_context *mac, + uint8_t session_id) +{ + tListElem *pEntry; + tSmeCmd *pCommand; + + pEntry = csr_nonscan_active_ll_peek_head(mac, LL_ACCESS_LOCK); + if (pEntry) { + pCommand = GET_BASE_ADDR(pEntry, tSmeCmd, Link); + if (eSmeCommandWmStatusChange == pCommand->command) { + /* Nothing to process in a Lost Link completion.... It just kicks off a */ + /* roaming sequence. */ + if (csr_nonscan_active_ll_remove_entry(mac, pEntry, + LL_ACCESS_LOCK)) { + csr_release_command(mac, pCommand); + } else { + sme_err("Failed to release command"); + } + } else { + sme_warn("CSR: LOST LINK command is not ACTIVE ..."); + } + } else { + sme_warn("CSR: NO commands are ACTIVE ..."); + } +} + +void csr_roam_process_wm_status_change_command( + struct mac_context *mac, tSmeCmd *pCommand) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, + pCommand->vdev_id); + struct qdf_mac_addr peer_mac; + + if (!pSession) { + sme_err("session %d not found", pCommand->vdev_id); + csr_roam_wm_status_change_complete(mac, pCommand->vdev_id); + } + sme_debug("session:%d, CmdType : %d", + pCommand->vdev_id, pCommand->u.wmStatusChangeCmd.Type); + + switch (pCommand->u.wmStatusChangeCmd.Type) { + case eCsrDisassociated: + qdf_mem_copy(&peer_mac, &pCommand->u.wmStatusChangeCmd. + u.DisassocIndMsg.peer_macaddr, + QDF_MAC_ADDR_SIZE); + /* + * Get peer stats before peer gets deleted so that these stats + * can be given to user space when big data stats are queried. + * Once peer stats are retrieved disassoc sta will continue + */ + csr_get_peer_stats(mac, pCommand->vdev_id, peer_mac); + break; + case eCsrDeauthenticated: + qdf_mem_copy(&peer_mac, &pCommand->u.wmStatusChangeCmd. + u.DeauthIndMsg.peer_macaddr, + QDF_MAC_ADDR_SIZE); + /* + * Get peer stats before peer gets deleted so that these stats + * can be given to user space when big data stats are queried. + * Once peer stats are retrieved deauth sta will continue + */ + csr_get_peer_stats(mac, pCommand->vdev_id, peer_mac); + break; + default: + sme_warn("gets an unknown command %d", + pCommand->u.wmStatusChangeCmd.Type); + csr_roam_wm_status_change_complete(mac, pCommand->vdev_id); + break; + } +} + +/** + * csr_compute_mode_and_band() - computes dot11mode + * @mac: mac global context + * @dot11_mode: out param, do11 mode calculated + * @band: out param, band caclculated + * @opr_ch_freq: operating channel freq in MHz + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. + * + * Return: void + */ +static void +csr_compute_mode_and_band(struct mac_context *mac_ctx, + enum csr_cfgdot11mode *dot11_mode, + enum reg_wifi_band *band, + uint32_t opr_ch_freq) +{ + bool vht_24_ghz = mac_ctx->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band; + + switch (mac_ctx->roam.configParam.uCfgDot11Mode) { + case eCSR_CFG_DOT11_MODE_11A: + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = REG_BAND_5G; + break; + case eCSR_CFG_DOT11_MODE_11B: + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = REG_BAND_2G; + break; + case eCSR_CFG_DOT11_MODE_11G: + *dot11_mode = eCSR_CFG_DOT11_MODE_11G; + *band = REG_BAND_2G; + break; + case eCSR_CFG_DOT11_MODE_11N: + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + *band = wlan_reg_freq_to_band(opr_ch_freq); + break; + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(opr_ch_freq) && + !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = wlan_reg_freq_to_band(opr_ch_freq); + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(opr_ch_freq) && + !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC_ONLY; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = wlan_reg_freq_to_band(opr_ch_freq); + break; + case eCSR_CFG_DOT11_MODE_11AX: + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) { + *dot11_mode = mac_ctx->roam.configParam.uCfgDot11Mode; + } else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(opr_ch_freq) && + !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = wlan_reg_freq_to_band(opr_ch_freq); + break; +#ifdef WLAN_FEATURE_11BE + case eCSR_CFG_DOT11_MODE_11BE: + case eCSR_CFG_DOT11_MODE_11BE_ONLY: + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) { + *dot11_mode = mac_ctx->roam.configParam.uCfgDot11Mode; + } else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) { + *dot11_mode = eCSR_CFG_DOT11_MODE_11AX; + } else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, check + * for INI item to disable VHT operation in 2.4 GHz band + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(opr_ch_freq) && + !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = wlan_reg_freq_to_band(opr_ch_freq); + break; +#endif + case eCSR_CFG_DOT11_MODE_AUTO: +#ifdef WLAN_FEATURE_11BE + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) { + *dot11_mode = eCSR_CFG_DOT11_MODE_11BE; + } else +#endif + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) { + *dot11_mode = eCSR_CFG_DOT11_MODE_11AX; + } else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) { + /* + * If the operating channel is in 2.4 GHz band, + * check for INI item to disable VHT operation + * in 2.4 GHz band + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(opr_ch_freq) && + !vht_24_ghz) + /* Disable 11AC operation */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + else + *dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + } else { + *dot11_mode = eCSR_CFG_DOT11_MODE_11N; + } + *band = wlan_reg_freq_to_band(opr_ch_freq); + break; + default: + /* + * Global dot11 Mode setting is 11a/b/g. use the channel number + * to determine the Mode setting. + */ + if (eCSR_OPERATING_CHANNEL_AUTO == opr_ch_freq) { + *band = (mac_ctx->mlme_cfg->gen.band == BAND_2G ? + REG_BAND_2G : REG_BAND_5G); + if (REG_BAND_2G == *band) { + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } else { + /* prefer 5GHz */ + *band = REG_BAND_5G; + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(opr_ch_freq)) { + *dot11_mode = eCSR_CFG_DOT11_MODE_11B; + *band = REG_BAND_2G; + } else { + /* else, it's a 5.0GHz channel. Set mode to 11a. */ + *dot11_mode = eCSR_CFG_DOT11_MODE_11A; + *band = REG_BAND_5G; + } + break; + } /* switch */ +} + +/** + * csr_roam_get_phy_mode_band_for_bss() - This function returns band and mode + * information. + * @mac_ctx: mac global context + * dot11_cfg: pointer to dot11 config + * + * This function finds dot11 mode based on current mode, operating channel and + * fw supported modes. The only tricky part is that if phyMode is set to 11abg, + * this function may return eCSR_CFG_DOT11_MODE_11B instead of + * eCSR_CFG_DOT11_MODE_11G if everything is set to auto-pick. + * + * Return: dot11mode + */ +enum csr_cfgdot11mode +csr_roam_get_phy_mode_band_for_bss(struct mac_context *mac_ctx, + struct bss_dot11_config *dot11_cfg) +{ + enum reg_wifi_band band = REG_BAND_2G; + qdf_freq_t opr_freq = 0; + bool is_11n_allowed; + enum csr_cfgdot11mode curr_mode = + mac_ctx->roam.configParam.uCfgDot11Mode; + enum csr_cfgdot11mode cfg_dot11_mode; + enum QDF_OPMODE opmode; + bool is_ap = false; + uint8_t privacy; + uint8_t vdev_id = dot11_cfg->vdev_id; + + if (dot11_cfg->bss_op_ch_freq) + opr_freq = dot11_cfg->bss_op_ch_freq; + + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + is_ap = (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE); + cfg_dot11_mode = + csr_get_cfg_dot11_mode_from_csr_phy_mode(is_ap, + dot11_cfg->phy_mode); + privacy = dot11_cfg->privacy; + + /* + * If the global setting for dot11Mode is set to auto/abg, we overwrite + * the setting in the profile. + */ + if ((!is_ap && ((eCSR_CFG_DOT11_MODE_AUTO == curr_mode) || + (eCSR_CFG_DOT11_MODE_ABG == curr_mode))) || + (eCSR_CFG_DOT11_MODE_AUTO == cfg_dot11_mode) || + (eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode)) { + csr_compute_mode_and_band(mac_ctx, &cfg_dot11_mode, + &band, opr_freq); + } /* if( eCSR_CFG_DOT11_MODE_ABG == cfg_dot11_mode ) */ + else { + /* dot11 mode is set, lets pick the band */ + if (0 == opr_freq) { + /* channel is Auto also. */ + if (mac_ctx->mlme_cfg->gen.band == BAND_ALL) { + /* prefer 5GHz */ + band = REG_BAND_5G; + } + } else{ + band = wlan_reg_freq_to_band(opr_freq); + } + } + + dot11_cfg->p_band = band; + if (opr_freq == 2484 && wlan_reg_is_24ghz_ch_freq(opr_freq)) { + sme_err("Switching to Dot11B mode"); + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11B; + } + + if (wlan_reg_is_24ghz_ch_freq(opr_freq) && + !mac_ctx->mlme_cfg->vht_caps.vht_cap_info.b24ghz_band && + (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode || + eCSR_CFG_DOT11_MODE_11AC_ONLY == cfg_dot11_mode)) + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11N; + /* + * Incase of WEP Security encryption type is coming as part of add key. + * So while STart BSS dont have information + */ + is_11n_allowed = wlan_vdev_id_is_11n_allowed(mac_ctx->pdev, vdev_id); + if ((!is_11n_allowed || (privacy && + wlan_vdev_id_is_open_cipher(mac_ctx->pdev, vdev_id))) && + ((eCSR_CFG_DOT11_MODE_11N == cfg_dot11_mode) || + (eCSR_CFG_DOT11_MODE_11AC == cfg_dot11_mode) || + (eCSR_CFG_DOT11_MODE_11AX == cfg_dot11_mode) || + CSR_IS_CFG_DOT11_PHY_MODE_11BE(cfg_dot11_mode))) { + /* We cannot do 11n here */ + if (wlan_reg_is_24ghz_ch_freq(opr_freq)) + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11G; + else + cfg_dot11_mode = eCSR_CFG_DOT11_MODE_11A; + } + sme_debug("dot11mode: %d phyMode %d is_11n_allowed %d privacy %d chan freq %d fw sup AX %d", + cfg_dot11_mode, dot11_cfg->phy_mode, is_11n_allowed, + privacy, opr_freq, + IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)); + +#ifdef WLAN_FEATURE_11BE + sme_debug("BE :%d", IS_FEATURE_SUPPORTED_BY_FW(DOT11BE)); +#endif + return cfg_dot11_mode; +} + +QDF_STATUS csr_get_cfg_valid_channels(struct mac_context *mac, + qdf_freq_t *ch_freq_list, + uint32_t *num_ch_freq) +{ + uint8_t num_chan_temp = 0; + int i; + uint32_t *valid_ch_freq_list = + mac->mlme_cfg->reg.valid_channel_freq_list; + + *num_ch_freq = mac->mlme_cfg->reg.valid_channel_list_num; + + for (i = 0; i < *num_ch_freq; i++) { + if (!wlan_reg_is_dsrc_freq(valid_ch_freq_list[i])) { + ch_freq_list[num_chan_temp] = valid_ch_freq_list[i]; + num_chan_temp++; + } + } + + *num_ch_freq = num_chan_temp; + return QDF_STATUS_SUCCESS; +} + +/** + * csr_convert_mode_to_nw_type() - convert mode into network type + * @dot11_mode: dot11_mode + * @band: 2.4 or 5 GHz + * + * Return: tSirNwType + */ +tSirNwType +csr_convert_mode_to_nw_type(enum csr_cfgdot11mode dot11_mode, + enum reg_wifi_band band) +{ + switch (dot11_mode) { + case eCSR_CFG_DOT11_MODE_11G: + return eSIR_11G_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11B: + return eSIR_11B_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11A: + return eSIR_11A_NW_TYPE; + case eCSR_CFG_DOT11_MODE_11N: + default: + /* + * Because LIM only verifies it against 11a, 11b or 11g, set + * only 11g or 11a here + */ + if (REG_BAND_2G == band) + return eSIR_11G_NW_TYPE; + else + return eSIR_11A_NW_TYPE; + } + return eSIR_DONOT_USE_NW_TYPE; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef WLAN_FEATURE_11BE_MLO +static bool csr_pmk_match_mlo_address(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_pmksa *pmksa) +{ + struct qdf_mac_addr bss_peer_mld_mac = {0}; + + wlan_vdev_get_bss_peer_mld_mac(vdev, &bss_peer_mld_mac); + + return qdf_is_macaddr_equal(&bss_peer_mld_mac, &pmksa->bssid); +} +#else +static inline bool csr_pmk_match_mlo_address(struct wlan_objmgr_vdev *vdev, + struct wlan_crypto_pmksa *pmksa) +{ + return false; +} +#endif + +void csr_get_pmk_info(struct mac_context *mac_ctx, uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + if (!mac_ctx) { + sme_err("Mac_ctx is NULL"); + return; + } + wlan_cm_get_psk_pmk(mac_ctx->pdev, session_id, pmk_cache->pmk, + &pmk_cache->pmk_len); +} + +QDF_STATUS csr_roam_set_psk_pmk(struct mac_context *mac, + struct wlan_crypto_pmksa *pmksa, + uint8_t vdev_id, bool update_to_fw) +{ + struct wlan_objmgr_vdev *vdev; + struct qdf_mac_addr connected_bssid = {0}; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wlan_mlme_get_bssid_vdev_id(mac->pdev, vdev_id, &connected_bssid); + + /* + * If the set_pmksa is received from the userspace in + * connected state and if the connected BSSID is not + * same as the PMKSA entry bssid, then reject this + * global cache updation. + * + * Also for FILS connection, the set_pmksa will not have + * the BSSID. So avoid this check for FILS connection. + */ + if (wlan_vdev_mlme_get_state(vdev) == WLAN_VDEV_S_UP && + !pmksa->ssid_len && + !qdf_is_macaddr_equal(&connected_bssid, &pmksa->bssid) && + !csr_pmk_match_mlo_address(vdev, pmksa)) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + sme_debug("Set pmksa received for non-connected bss"); + return QDF_STATUS_E_INVAL; + } + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + wlan_cm_set_psk_pmk(mac->pdev, vdev_id, pmksa->pmk, pmksa->pmk_len); + if (update_to_fw) { + status = wlan_roam_update_cfg(mac->psoc, vdev_id, + REASON_ROAM_PSK_PMK_CHANGED); + if (status == QDF_STATUS_E_INVAL) + wlan_mlme_defer_pmk_set_in_roaming(mac->psoc, vdev_id, + true); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_set_pmk_cache_ft(struct mac_context *mac, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + struct wlan_objmgr_vdev *vdev; + int32_t akm; + + if (!CSR_IS_SESSION_VALID(mac, vdev_id)) { + sme_err("session %d not found", vdev_id); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + akm = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) { + sme_debug("PMK update is not required for ESE"); + return QDF_STATUS_SUCCESS; + } + + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384) || + QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) { + sme_debug("Auth type: %x update the MDID in cache", akm); + cm_update_pmk_cache_ft(mac->psoc, vdev_id, pmk_cache); + } else { + struct cm_roam_values_copy src_cfg = {}; + struct scan_filter *scan_filter; + qdf_list_t *list = NULL; + struct scan_cache_node *first_node = NULL; + struct rsn_mdie *mdie = NULL; + qdf_list_node_t *cur_node = NULL; + + scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); + if (!scan_filter) + return QDF_STATUS_E_NOMEM; + scan_filter->num_of_bssid = 1; + qdf_mem_copy(scan_filter->bssid_list[0].bytes, + &pmk_cache->bssid, sizeof(struct qdf_mac_addr)); + list = wlan_scan_get_result(mac->pdev, scan_filter); + qdf_mem_free(scan_filter); + if (!list || (list && !qdf_list_size(list))) { + sme_debug("Scan list is empty"); + goto err; + } + qdf_list_peek_front(list, &cur_node); + first_node = qdf_container_of(cur_node, + struct scan_cache_node, + node); + if (first_node && first_node->entry) + mdie = (struct rsn_mdie *) + util_scan_entry_mdie(first_node->entry); + if (mdie) { + sme_debug("Update MDID in cache from scan_res"); + src_cfg.bool_value = true; + src_cfg.uint_value = + (mdie->mobility_domain[0] | + (mdie->mobility_domain[1] << 8)); + wlan_cm_roam_cfg_set_value(mac->psoc, vdev_id, + MOBILITY_DOMAIN, &src_cfg); + cm_update_pmk_cache_ft(mac->psoc, vdev_id, pmk_cache); + } +err: + if (list) + wlan_scan_purge_results(list); + } + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +void csr_clear_sae_single_pmk(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache) +{ + struct wlan_objmgr_vdev *vdev; + int32_t keymgmt; + struct mlme_pmk_info pmk_info; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("vdev is NULL"); + return; + } + + keymgmt = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + if (keymgmt < 0) { + sme_err("Invalid mgmt cipher"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + + if (!(QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_SAE) || + QDF_HAS_PARAM(keymgmt, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY))) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return; + } + if (pmk_cache) { + qdf_mem_copy(&pmk_info.pmk, pmk_cache->pmk, pmk_cache->pmk_len); + pmk_info.pmk_len = pmk_cache->pmk_len; + wlan_mlme_clear_sae_single_pmk_info(vdev, &pmk_info); + } else { + wlan_mlme_clear_sae_single_pmk_info(vdev, NULL); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +} +#endif + +#ifdef FEATURE_WLAN_ESE +void csr_update_prev_ap_info(struct csr_roam_session *session, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_ssid ssid; + QDF_STATUS status; + enum QDF_OPMODE opmode; + struct rso_config *rso_cfg; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + rso_cfg = wlan_cm_get_rso_config(vdev); + if (!rso_cfg) + return; + + if (!rso_cfg->is_ese_assoc || opmode != QDF_STA_MODE) + return; + status = wlan_vdev_mlme_get_ssid(vdev, ssid.ssid, &ssid.length); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err(" failed to find SSID for vdev %d", session->vdev_id); + return; + } + session->isPrevApInfoValid = true; + session->roamTS1 = qdf_mc_timer_get_system_time(); +} +#endif + +#ifdef WLAN_FEATURE_FILS_SK +static QDF_STATUS csr_cm_update_fils_info(struct wlan_objmgr_vdev *vdev, + struct bss_description *bss_desc, + struct wlan_cm_vdev_connect_req *req) +{ + uint8_t cache_id[CACHE_ID_LEN] = {0}; + struct scan_cache_entry *entry; + struct wlan_crypto_pmksa *fils_ssid_pmksa, *bssid_lookup_pmksa; + + if (!req->fils_info || !req->fils_info->is_fils_connection) { + wlan_cm_update_mlme_fils_info(vdev, NULL); + return QDF_STATUS_SUCCESS; + } + + if (bss_desc->fils_info_element.is_cache_id_present) { + qdf_mem_copy(cache_id, bss_desc->fils_info_element.cache_id, + CACHE_ID_LEN); + sme_debug("FILS_PMKSA: cache_id[0]:%d, cache_id[1]:%d", + cache_id[0], cache_id[1]); + } + entry = req->bss->entry; + bssid_lookup_pmksa = wlan_crypto_get_pmksa(vdev, &entry->bssid); + fils_ssid_pmksa = + wlan_crypto_get_fils_pmksa(vdev, cache_id, + entry->ssid.ssid, + entry->ssid.length); + + if ((!req->fils_info->rrk_len || + !req->fils_info->username_len) && + !bss_desc->fils_info_element.is_cache_id_present && + !bssid_lookup_pmksa && !fils_ssid_pmksa) + return QDF_STATUS_E_FAILURE; + + return wlan_cm_update_mlme_fils_info(vdev, req->fils_info); +} +#else +static inline +QDF_STATUS csr_cm_update_fils_info(struct wlan_objmgr_vdev *vdev, + struct bss_description *bss_desc, + struct wlan_cm_vdev_connect_req *req) +{ +} +#endif + +#if defined(WLAN_FEATURE_HOST_ROAM) && defined(FEATURE_WLAN_ESE) +static void csr_update_tspec_info(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + tDot11fBeaconIEs *ie_struct) +{ + struct mlme_legacy_priv *mlme_priv; + tESETspecInfo *ese_tspec; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + if (!cm_is_ese_connection(vdev, ie_struct->ESEVersion.present)) + return; + + ese_tspec = &mlme_priv->connect_info.ese_tspec_info; + qdf_mem_zero(ese_tspec, sizeof(tESETspecInfo)); + ese_tspec->numTspecs = sme_qos_ese_retrieve_tspec_info(mac_ctx, + wlan_vdev_get_id(vdev), + ese_tspec->tspec); +} +#else +static inline void csr_update_tspec_info(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev, + tDot11fBeaconIEs *ie_struct) {} +#endif + +void cm_csr_send_set_ie(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *vdev_mlme; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + sme_err("Failed to get vdev mlme obj!"); + QDF_BUG(0); + return; + } + + csr_send_set_ie(vdev_mlme->mgmt.generic.type, + vdev_mlme->mgmt.generic.subtype, + wlan_vdev_get_id(vdev)); +} + +QDF_STATUS cm_csr_handle_join_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_connect_req *req, + struct cm_vdev_join_req *join_req, + bool reassoc) +{ + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + QDF_STATUS status; + tDot11fBeaconIEs *ie_struct; + struct bss_description *bss_desc; + uint32_t ie_len, bss_len; + + /* + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead + */ + mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + ie_len = util_scan_entry_ie_len(join_req->entry); + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + + bss_desc = qdf_mem_malloc(sizeof(*bss_desc) + bss_len); + if (!bss_desc) + return QDF_STATUS_E_NOMEM; + + status = wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc, + join_req->entry); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(bss_desc); + return QDF_STATUS_E_FAILURE; + } + + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &ie_struct); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("IE parsing failed vdev id %d", vdev_id); + qdf_mem_free(bss_desc); + return QDF_STATUS_E_FAILURE; + } + + if (reassoc) { + csr_update_tspec_info(mac_ctx, vdev, ie_struct); + } else { + status = csr_cm_update_fils_info(vdev, bss_desc, req); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to update fils info vdev id %d", + vdev_id); + qdf_mem_free(ie_struct); + qdf_mem_free(bss_desc); + return QDF_STATUS_E_FAILURE; + } + sme_qos_csr_event_ind(mac_ctx, vdev_id, + SME_QOS_CSR_JOIN_REQ, NULL); + } + + if ((wlan_reg_11d_enabled_on_host(mac_ctx->psoc)) && + !ie_struct->Country.present) + csr_apply_channel_power_info_wrapper(mac_ctx); + + qdf_mem_free(ie_struct); + qdf_mem_free(bss_desc); + + cm_csr_set_joining(vdev_id); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +static uint32_t csr_get_tspec_ie_len(struct cm_vdev_join_rsp *rsp) +{ + return rsp->tspec_ie.len; +} +static inline void csr_copy_tspec_ie_len(struct csr_roam_session *session, + uint8_t *frame_ptr, + struct cm_vdev_join_rsp *rsp) +{ + session->connectedInfo.nTspecIeLength = rsp->tspec_ie.len; + if (rsp->tspec_ie.len) + qdf_mem_copy(frame_ptr, rsp->tspec_ie.ptr, + rsp->tspec_ie.len); +} + +#else +static inline uint32_t csr_get_tspec_ie_len(struct cm_vdev_join_rsp *rsp) +{ + return 0; +} +static inline void csr_copy_tspec_ie_len(struct csr_roam_session *session, + uint8_t *frame_ptr, + struct cm_vdev_join_rsp *rsp) +{} +#endif + +static void csr_fill_connected_info(struct mac_context *mac_ctx, + struct csr_roam_session *session, + struct cm_vdev_join_rsp *rsp) +{ + uint32_t len; + struct wlan_connect_rsp_ies *connect_ies; + uint8_t *frame_ptr; + uint32_t beacon_data_len = 0; + + connect_ies = &rsp->connect_rsp.connect_ies; + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + if (connect_ies->bcn_probe_rsp.len > sizeof(struct wlan_frame_hdr)) + beacon_data_len = connect_ies->bcn_probe_rsp.len - + sizeof(struct wlan_frame_hdr); + len = beacon_data_len + connect_ies->assoc_req.len + + connect_ies->assoc_rsp.len + rsp->ric_resp_ie.len + + csr_get_tspec_ie_len(rsp); + if (!len) + return; + + session->connectedInfo.pbFrames = qdf_mem_malloc(len); + if (!session->connectedInfo.pbFrames) + return; + + frame_ptr = session->connectedInfo.pbFrames; + session->connectedInfo.nBeaconLength = beacon_data_len; + if (beacon_data_len) + qdf_mem_copy(frame_ptr, + connect_ies->bcn_probe_rsp.ptr + + sizeof(struct wlan_frame_hdr), + beacon_data_len); + frame_ptr += beacon_data_len; + + session->connectedInfo.nAssocReqLength = connect_ies->assoc_req.len; + if (connect_ies->assoc_req.len) + qdf_mem_copy(frame_ptr, + connect_ies->assoc_req.ptr, + connect_ies->assoc_req.len); + frame_ptr += connect_ies->assoc_req.len; + + session->connectedInfo.nAssocRspLength = connect_ies->assoc_rsp.len; + if (connect_ies->assoc_rsp.len) + qdf_mem_copy(frame_ptr, + connect_ies->assoc_rsp.ptr, + connect_ies->assoc_rsp.len); + frame_ptr += connect_ies->assoc_rsp.len; + + session->connectedInfo.nRICRspLength = rsp->ric_resp_ie.len; + if (rsp->ric_resp_ie.len) + qdf_mem_copy(frame_ptr, rsp->ric_resp_ie.ptr, + rsp->ric_resp_ie.len); + frame_ptr += rsp->ric_resp_ie.len; + + csr_copy_tspec_ie_len(session, frame_ptr, rsp); +} + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +static inline void csr_qos_send_disconnect_ind(struct mac_context *mac_ctx, + uint8_t vdev_id) +{ + sme_qos_csr_event_ind(mac_ctx, vdev_id, SME_QOS_CSR_DISCONNECT_IND, + NULL); +} + +static inline void csr_qos_send_assoc_ind(struct mac_context *mac_ctx, + uint8_t vdev_id, + sme_QosAssocInfo *assoc_info) +{ + sme_qos_csr_event_ind(mac_ctx, vdev_id, SME_QOS_CSR_ASSOC_COMPLETE, + assoc_info); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void +csr_qso_disconnect_complete_ind(struct mac_context *mac_ctx, + struct wlan_cm_connect_resp *connect_rsp) +{ + if (IS_ROAM_REASON_DISCONNECTION( + connect_rsp->roaming_info->roam_reason)) + sme_qos_csr_event_ind(mac_ctx, connect_rsp->vdev_id, + SME_QOS_CSR_DISCONNECT_ROAM_COMPLETE, + NULL); +} +#else +static inline void +csr_qso_disconnect_complete_ind(struct mac_context *mac_ctx, + struct wlan_cm_connect_resp *connect_rsp) {} +#endif + +static void +csr_qos_send_reassoc_ind(struct mac_context *mac_ctx, + uint8_t vdev_id, + sme_QosAssocInfo *assoc_info, + struct wlan_cm_connect_resp *connect_rsp) +{ + sme_qos_csr_event_ind(mac_ctx, vdev_id, SME_QOS_CSR_HANDOFF_ASSOC_REQ, + NULL); + sme_qos_csr_event_ind(mac_ctx, vdev_id, SME_QOS_CSR_REASSOC_REQ, + NULL); + sme_qos_csr_event_ind(mac_ctx, vdev_id, SME_QOS_CSR_HANDOFF_COMPLETE, + NULL); + sme_qos_csr_event_ind(mac_ctx, vdev_id, SME_QOS_CSR_REASSOC_COMPLETE, + assoc_info); + + csr_qso_disconnect_complete_ind(mac_ctx, connect_rsp); +} +#else +static inline void csr_qos_send_disconnect_ind(struct mac_context *mac_ctx, + uint8_t vdev_id) +{} + +static inline void csr_qos_send_assoc_ind(struct mac_context *mac_ctx, + uint8_t vdev_id, + sme_QosAssocInfo *assoc_info) +{} +static inline void +csr_qos_send_reassoc_ind(struct mac_context *mac_ctx, + uint8_t vdev_id, + sme_QosAssocInfo *assoc_info, + struct wlan_cm_connect_resp *connect_rsp) +{} +#endif + +static void +csr_update_beacon_in_connect_rsp(struct scan_cache_entry *entry, + struct wlan_connect_rsp_ies *connect_ies) +{ + if (!entry) + return; + + /* no need to update if already present */ + if (connect_ies->bcn_probe_rsp.ptr) + return; + + /* + * In case connection to MBSSID: Non Tx BSS OR host reassoc, + * vdev/peer manager doesn't send unicast probe req so fill the + * beacon in connect resp IEs here. + */ + connect_ies->bcn_probe_rsp.len = + util_scan_entry_frame_len(entry); + connect_ies->bcn_probe_rsp.ptr = + qdf_mem_malloc(connect_ies->bcn_probe_rsp.len); + if (!connect_ies->bcn_probe_rsp.ptr) + return; + + qdf_mem_copy(connect_ies->bcn_probe_rsp.ptr, + util_scan_entry_frame_ptr(entry), + connect_ies->bcn_probe_rsp.len); +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +static bool csr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return mlo_mgr_is_link_switch_in_progress(vdev); +} +#else +static bool csr_is_link_switch_in_progress(struct wlan_objmgr_vdev *vdev) +{ + return false; +} +#endif + +static void csr_fill_connected_profile(struct mac_context *mac_ctx, + struct csr_roam_session *session, + struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_rsp *rsp) +{ + struct scan_filter *filter; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + QDF_STATUS status; + qdf_list_t *list = NULL; + qdf_list_node_t *cur_lst = NULL; + struct scan_cache_node *cur_node = NULL; + uint32_t bss_len, ie_len; + struct bss_description *bss_desc = NULL; + tDot11fBeaconIEs *bcn_ies; + sme_QosAssocInfo assoc_info; + struct cm_roam_values_copy src_cfg = {}; + bool is_ese = false; + uint8_t country_code[REG_ALPHA2_LEN + 1]; + + session->modifyProfileFields.uapsd_mask = rsp->uapsd_mask; + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return; + + filter->num_of_bssid = 1; + qdf_copy_macaddr(&filter->bssid_list[0], &rsp->connect_rsp.bssid); + filter->ignore_auth_enc_type = true; + + status = wlan_vdev_mlme_get_ssid(vdev, filter->ssid_list[0].ssid, + &filter->ssid_list[0].length); + if (QDF_IS_STATUS_SUCCESS(status)) + filter->num_of_ssid = 1; + + list = wlan_scan_get_result(mac_ctx->pdev, filter); + qdf_mem_free(filter); + if (!list || (list && !qdf_list_size(list))) + goto purge_list; + + + qdf_list_peek_front(list, &cur_lst); + if (!cur_lst) + goto purge_list; + + cur_node = qdf_container_of(cur_lst, struct scan_cache_node, node); + ie_len = util_scan_entry_ie_len(cur_node->entry); + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + bss_desc = qdf_mem_malloc(bss_len); + if (!bss_desc) + goto purge_list; + + wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc, cur_node->entry); + src_cfg.uint_value = bss_desc->mbo_oce_enabled_ap; + wlan_cm_roam_cfg_set_value(mac_ctx->psoc, vdev_id, MBO_OCE_ENABLED_AP, + &src_cfg); + csr_fill_single_pmk(mac_ctx->psoc, vdev_id, bss_desc); + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &bcn_ies); + if (QDF_IS_STATUS_ERROR(status)) + goto purge_list; + + if (!bss_desc->beaconInterval) + sme_err("ERROR: Beacon interval is ZERO"); + + csr_update_beacon_in_connect_rsp(cur_node->entry, + &rsp->connect_rsp.connect_ies); + + assoc_info.bss_desc = bss_desc; + if (rsp->connect_rsp.is_reassoc) { + if (cm_is_ese_connection(vdev, bcn_ies->ESEVersion.present)) + is_ese = true; + wlan_cm_set_ese_assoc(mac_ctx->pdev, vdev_id, is_ese); + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, vdev_id, UAPSD_MASK, + &src_cfg); + assoc_info.uapsd_mask = src_cfg.uint_value; + csr_qos_send_reassoc_ind(mac_ctx, vdev_id, &assoc_info, + &rsp->connect_rsp); + if (src_cfg.uint_value) + sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), vdev_id); + } else { + assoc_info.uapsd_mask = rsp->uapsd_mask; + csr_qos_send_assoc_ind(mac_ctx, vdev_id, &assoc_info); + } + + if (rsp->connect_rsp.is_reassoc || + csr_is_link_switch_in_progress(vdev)) + mlme_set_mbssid_info(vdev, &cur_node->entry->mbssid_info, + bss_desc->chan_freq); + + if (bcn_ies->Country.present) + qdf_mem_copy(country_code, bcn_ies->Country.country, + REG_ALPHA2_LEN + 1); + else + qdf_mem_zero(country_code, REG_ALPHA2_LEN + 1); + wlan_cm_set_country_code(mac_ctx->pdev, vdev_id, country_code); + + qdf_mem_free(bcn_ies); + +purge_list: + if (bss_desc) + qdf_mem_free(bss_desc); + if (list) + wlan_scan_purge_results(list); + +} + +QDF_STATUS cm_csr_connect_rsp(struct wlan_objmgr_vdev *vdev, + struct cm_vdev_join_rsp *rsp) +{ + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct csr_roam_session *session; + struct cm_roam_values_copy src_config = {}; + + /* + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead + */ + if (QDF_IS_STATUS_ERROR(rsp->connect_rsp.connect_status)) + return QDF_STATUS_SUCCESS; + + /* handle below only in case of success */ + mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session || !CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("session not found for vdev_id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (!rsp->connect_rsp.is_reassoc) { + if (rsp->uapsd_mask) + sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), vdev_id); + src_config.uint_value = rsp->uapsd_mask; + wlan_cm_roam_cfg_set_value(mac_ctx->psoc, vdev_id, UAPSD_MASK, + &src_config); + } + session->nss = rsp->nss; + csr_fill_connected_info(mac_ctx, session, rsp); + csr_fill_connected_profile(mac_ctx, session, vdev, rsp); + + return QDF_STATUS_SUCCESS; +} + +static void +cm_update_rsn_ocv_cap(int32_t *rsn_cap, + struct wlan_cm_connect_resp *rsp) +{ + struct wlan_crypto_params crypto_params; + uint8_t *ie_ptr; + uint32_t ie_len; + QDF_STATUS status; + + /* no need to do anything if OCV is not set */ + if (!(*rsn_cap & WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED)) + return; + + if (!rsp->connect_ies.bcn_probe_rsp.ptr || + !rsp->connect_ies.bcn_probe_rsp.len || + (rsp->connect_ies.bcn_probe_rsp.len < + (sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)))) { + sme_err("invalid beacon probe rsp len %d", + rsp->connect_ies.bcn_probe_rsp.len); + return; + } + + ie_len = (rsp->connect_ies.bcn_probe_rsp.len - + sizeof(struct wlan_frame_hdr) - + offsetof(struct wlan_bcn_frame, ie)); + ie_ptr = (uint8_t *)(rsp->connect_ies.bcn_probe_rsp.ptr + + sizeof(struct wlan_frame_hdr) + + offsetof(struct wlan_bcn_frame, ie)); + + status = wlan_get_crypto_params_from_rsn_ie(&crypto_params, ie_ptr, + ie_len); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (!(crypto_params.rsn_caps & WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED)) + *rsn_cap &= ~WLAN_CRYPTO_RSN_CAP_OCV_SUPPORTED; +} + +QDF_STATUS +cm_csr_connect_done_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_connect_resp *rsp) +{ + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + int32_t count; + struct set_context_rsp install_key_rsp; + int32_t rsn_cap, set_value; + struct wlan_mlme_psoc_ext_obj *mlme_obj; + struct dual_sta_policy *dual_sta_policy; + bool enable_mcc_adaptive_sch = false; + struct qdf_mac_addr bc_mac = QDF_MAC_ADDR_BCAST_INIT; + + /* + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead + */ + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(mac_ctx->psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + if (QDF_IS_STATUS_ERROR(rsp->connect_status)) { + cm_csr_set_idle(vdev_id); + sme_qos_update_hand_off(vdev_id, false); + sme_qos_csr_event_ind(mac_ctx, vdev_id, + SME_QOS_CSR_DISCONNECT_IND, NULL); + /* Fill legacy structures from resp for failure */ + + return QDF_STATUS_SUCCESS; + } + + dual_sta_policy = &mlme_obj->cfg.gen.dual_sta_policy; + count = policy_mgr_mode_specific_connection_count(mac_ctx->psoc, + PM_STA_MODE, NULL); + /* + * send duty cycle percentage to FW only if STA + STA + * concurrency is in MCC. + */ + sme_debug("Current iface vdev_id:%d, Primary vdev_id:%d, Dual sta policy:%d, count:%d", + vdev_id, dual_sta_policy->primary_vdev_id, + dual_sta_policy->concurrent_sta_policy, count); + + if (dual_sta_policy->primary_vdev_id != WLAN_UMAC_VDEV_ID_MAX && + dual_sta_policy->concurrent_sta_policy == + QCA_WLAN_CONCURRENT_STA_POLICY_PREFER_PRIMARY && count == 2 && + policy_mgr_current_concurrency_is_mcc(mac_ctx->psoc)) { + policy_mgr_get_mcc_adaptive_sch(mac_ctx->psoc, + &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + sme_debug("Disable mcc_adaptive_scheduler"); + policy_mgr_set_dynamic_mcc_adaptive_sch( + mac_ctx->psoc, false); + if (QDF_STATUS_SUCCESS != sme_set_mas(false)) { + sme_err("Failed to disable mcc_adaptive_sched"); + return -EAGAIN; + } + } + set_value = + wlan_mlme_get_mcc_duty_cycle_percentage(mac_ctx->pdev); + sme_cli_set_command(vdev_id, WMA_VDEV_MCC_SET_TIME_QUOTA, + set_value, VDEV_CMD); + } else if (dual_sta_policy->concurrent_sta_policy == + QCA_WLAN_CONCURRENT_STA_POLICY_UNBIASED && count == 2 && + policy_mgr_current_concurrency_is_mcc(mac_ctx->psoc)) { + policy_mgr_get_mcc_adaptive_sch(mac_ctx->psoc, + &enable_mcc_adaptive_sch); + if (enable_mcc_adaptive_sch) { + sme_debug("Enable mcc_adaptive_scheduler"); + policy_mgr_set_dynamic_mcc_adaptive_sch( + mac_ctx->psoc, true); + if (QDF_STATUS_SUCCESS != sme_set_mas(true)) { + sme_err("Failed to enable mcc_adaptive_sched"); + return -EAGAIN; + } + } + } else { + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t quota_val; + + quota_val = + ucfg_mlme_get_user_mcc_quota_percentage(mac_ctx->psoc); + + if (quota_val) { + if (enable_mcc_adaptive_sch) { + policy_mgr_set_dynamic_mcc_adaptive_sch( + mac_ctx->psoc, false); + status = sme_set_mas(false); + } + if (status == QDF_STATUS_SUCCESS) + sme_cli_set_command(wlan_vdev_get_id(vdev), + WMA_VDEV_MCC_SET_TIME_QUOTA, + quota_val, VDEV_CMD); + } else { + sme_debug("no applicable user mcc/quota"); + } + } + + /* + * For open mode authentication, send dummy install key response to + * send OBSS scan and QOS event. + */ + if (!rsp->is_wps_connection && cm_is_open_mode(vdev)) { + install_key_rsp.length = sizeof(install_key_rsp); + install_key_rsp.status_code = eSIR_SME_SUCCESS; + install_key_rsp.sessionId = vdev_id; + /* use BC mac to enable OBSS scan */ + qdf_copy_macaddr(&install_key_rsp.peer_macaddr, &bc_mac); + csr_roam_chk_lnk_set_ctx_rsp(mac_ctx, + (tSirSmeRsp *)&install_key_rsp); + } + + rsn_cap = wlan_crypto_get_param(vdev, WLAN_CRYPTO_PARAM_RSN_CAP); + if (rsn_cap >= 0) { + cm_update_rsn_ocv_cap(&rsn_cap, rsp); + if (wma_cli_set2_command(vdev_id, wmi_vdev_param_rsn_capability, + rsn_cap, 0, VDEV_CMD)) + sme_err("Failed to update wmi_vdev_param_rsn_capability for vdev id %d", + vdev_id); + } + + /* + * Update the IEs after connection to reconfigure + * any capability that changed during connection. + */ + if (mlme_obj->cfg.obss_ht40.is_override_ht20_40_24g) + sme_set_vdev_ies_per_band(mac_handle, vdev_id, + wlan_vdev_mlme_get_opmode(vdev)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cm_csr_handle_diconnect_req(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_vdev_discon_req *req) +{ + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct csr_roam_session *session; + + /* + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead + */ + mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session || !CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) { + sme_err("session not found for vdev_id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + cm_csr_set_joining(vdev_id); + + /* Update the disconnect stats */ + session->disconnect_stats.disconnection_cnt++; + if (req->req.source == CM_PEER_DISCONNECT) { + session->disconnect_stats.disassoc_by_peer++; + } else if (req->req.source == CM_SB_DISCONNECT) { + switch (req->req.reason_code) { + case REASON_DISASSOC_DUE_TO_INACTIVITY: + session->disconnect_stats.peer_kickout++; + break; + case REASON_BEACON_MISSED: + session->disconnect_stats.bmiss++; + break; + default: + /* Unknown reason code */ + break; + } + } else if (req->req.source == CM_MLO_LINK_SWITCH_DISCONNECT) { + /* Do not update any stats as session is going to be deleted*/ + } else { + session->disconnect_stats.disconnection_by_app++; + } + + csr_update_prev_ap_info(session, vdev); + csr_qos_send_disconnect_ind(mac_ctx, vdev_id); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_csr_disconnect_done_ind(struct wlan_objmgr_vdev *vdev, + struct wlan_cm_discon_rsp *rsp) +{ + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_mlme_psoc_ext_obj *mlme_obj; + + /* + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead + */ + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) + return QDF_STATUS_E_INVAL; + + mlme_obj = mlme_get_psoc_ext_obj(mac_ctx->psoc); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + cm_csr_set_idle(vdev_id); + if (cm_is_vdev_roaming(vdev)) + sme_qos_update_hand_off(vdev_id, false); + csr_set_default_dot11_mode(mac_ctx); + + /* + * Update the IEs after disconnection to remove + * any connection specific capability change and + * to reset back to self cap + */ + if (mlme_obj->cfg.obss_ht40.is_override_ht20_40_24g) { + wlan_cm_set_force_20mhz_in_24ghz(vdev, true); + sme_set_vdev_ies_per_band(mac_handle, vdev_id, + wlan_vdev_mlme_get_opmode(vdev)); + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_HOST_ROAM +void cm_csr_preauth_done(struct wlan_objmgr_vdev *vdev) +{ + struct mac_context *mac_ctx; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct cm_roam_values_copy config; + bool is_11r; + + /* + * This API is to update legacy struct and should be removed once + * CSR is cleaned up fully. No new params should be added to CSR, use + * vdev/pdev/psoc instead + */ + mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + return; + } + + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, vdev_id, IS_11R_CONNECTION, + &config); + is_11r = config.bool_value; + if (is_11r || wlan_cm_get_ese_assoc(mac_ctx->pdev, vdev_id)) + sme_qos_csr_event_ind(mac_ctx, vdev_id, + SME_QOS_CSR_PREAUTH_SUCCESS_IND, NULL); +} +#endif + +/* */ +QDF_STATUS csr_send_mb_disassoc_req_msg(struct mac_context *mac, + uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode) +{ + struct disassoc_req *pMsg; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) + return QDF_STATUS_E_FAILURE; + + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_DISASSOC_REQ; + pMsg->length = sizeof(*pMsg); + pMsg->sessionId = sessionId; + + wlan_mlme_get_mac_vdev_id(mac->pdev, sessionId, &pMsg->bssid); + qdf_mem_copy(&pMsg->peer_macaddr.bytes, bssId, QDF_MAC_ADDR_SIZE); + pMsg->reasonCode = reasonCode; + + /* Update the disconnect stats */ + pSession->disconnect_stats.disconnection_cnt++; + pSession->disconnect_stats.disconnection_by_app++; + + return umac_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_send_chng_mcc_beacon_interval(struct mac_context *mac, + uint32_t sessionId) +{ + struct wlan_change_bi *pMsg; + uint16_t len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + /* NO need to update the Beacon Params if update beacon parameter flag + * is not set + */ + if (!mac->roam.roamSession[sessionId].update_bcn_int) + return QDF_STATUS_SUCCESS; + + mac->roam.roamSession[sessionId].update_bcn_int = + false; + + /* Create the message and send to lim */ + len = sizeof(*pMsg); + pMsg = qdf_mem_malloc(len); + if (!pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + pMsg->message_type = eWNI_SME_CHNG_MCC_BEACON_INTERVAL; + pMsg->length = len; + + wlan_mlme_get_mac_vdev_id(mac->pdev, sessionId, + &pMsg->bssid); + sme_debug("CSR Attempting to change BI for Bssid= " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pMsg->bssid.bytes)); + pMsg->session_id = sessionId; + sme_debug("session %d BeaconInterval %d", + sessionId, + mac->roam.roamSession[sessionId].bcn_int); + pMsg->beacon_interval = + mac->roam.roamSession[sessionId].bcn_int; + status = umac_send_mb_message_to_mac(pMsg); + } + return status; +} + +#ifdef QCA_HT_2040_COEX +QDF_STATUS csr_set_ht2040_mode(struct mac_context *mac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled) +{ + struct set_ht2040_mode *pMsg; + uint16_t len = 0; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* Create the message and send to lim */ + len = sizeof(struct set_ht2040_mode); + pMsg = qdf_mem_malloc(len); + if (!pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_zero(pMsg, sizeof(struct set_ht2040_mode)); + pMsg->messageType = eWNI_SME_SET_HT_2040_MODE; + pMsg->length = len; + + wlan_mlme_get_mac_vdev_id(mac->pdev, sessionId, &pMsg->bssid); + sme_debug( + "CSR Attempting to set HT20/40 mode for Bssid= " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pMsg->bssid.bytes)); + pMsg->sessionId = sessionId; + sme_debug(" session %d HT20/40 mode %d", + sessionId, cbMode); + pMsg->cbMode = cbMode; + pMsg->obssEnabled = obssEnabled; + status = umac_send_mb_message_to_mac(pMsg); + } + return status; +} +#endif + +QDF_STATUS csr_send_mb_deauth_req_msg(struct mac_context *mac, + uint32_t vdev_id, + tSirMacAddr bssId, uint16_t reasonCode) +{ + struct deauth_req *pMsg; + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, vdev_id); + + if (!CSR_IS_SESSION_VALID(mac, vdev_id)) + return QDF_STATUS_E_FAILURE; + + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_DEAUTH_REQ; + pMsg->length = sizeof(*pMsg); + pMsg->vdev_id = vdev_id; + + wlan_mlme_get_mac_vdev_id(mac->pdev, vdev_id, &pMsg->bssid); + /* Set the peer MAC address before sending the message to LIM */ + qdf_mem_copy(&pMsg->peer_macaddr.bytes, bssId, QDF_MAC_ADDR_SIZE); + pMsg->reasonCode = reasonCode; + + /* Update the disconnect stats */ + pSession->disconnect_stats.disconnection_cnt++; + pSession->disconnect_stats.disconnection_by_app++; + + return umac_send_mb_message_to_mac(pMsg); +} + +QDF_STATUS csr_send_mb_disassoc_cnf_msg(struct mac_context *mac, + struct disassoc_ind *pDisassocInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct disassoc_cnf *pMsg; + + do { + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (!pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMsg->messageType = eWNI_SME_DISASSOC_CNF; + pMsg->status_code = eSIR_SME_SUCCESS; + pMsg->length = sizeof(*pMsg); + pMsg->vdev_id = pDisassocInd->vdev_id; + qdf_copy_macaddr(&pMsg->peer_macaddr, + &pDisassocInd->peer_macaddr); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + + qdf_copy_macaddr(&pMsg->bssid, &pDisassocInd->bssid); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + + status = umac_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS csr_send_mb_deauth_cnf_msg(struct mac_context *mac, + struct deauth_ind *pDeauthInd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct deauth_cnf *pMsg; + + do { + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (!pMsg) + status = QDF_STATUS_E_NOMEM; + else + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) + break; + pMsg->messageType = eWNI_SME_DEAUTH_CNF; + pMsg->status_code = eSIR_SME_SUCCESS; + pMsg->length = sizeof(*pMsg); + pMsg->vdev_id = pDeauthInd->vdev_id; + qdf_copy_macaddr(&pMsg->bssid, &pDeauthInd->bssid); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + qdf_copy_macaddr(&pMsg->peer_macaddr, + &pDeauthInd->peer_macaddr); + status = QDF_STATUS_SUCCESS; + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + break; + } + status = umac_send_mb_message_to_mac(pMsg); + } while (0); + return status; +} + +QDF_STATUS csr_send_assoc_cnf_msg(struct mac_context *mac, + struct assoc_ind *pAssocInd, + QDF_STATUS Halstatus, + enum wlan_status_code mac_status_code) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct assoc_cnf *pMsg; + struct scheduler_msg msg = { 0 }; + + sme_debug("HalStatus: %d, mac_status_code %d", + Halstatus, mac_status_code); + do { + pMsg = qdf_mem_malloc(sizeof(*pMsg)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + pMsg->messageType = eWNI_SME_ASSOC_CNF; + pMsg->length = sizeof(*pMsg); + if (QDF_IS_STATUS_SUCCESS(Halstatus)) { + pMsg->status_code = eSIR_SME_SUCCESS; + } else { + pMsg->status_code = eSIR_SME_ASSOC_REFUSED; + pMsg->mac_status_code = mac_status_code; + } + /* bssId */ + qdf_mem_copy(pMsg->bssid.bytes, pAssocInd->bssId, + QDF_MAC_ADDR_SIZE); + /* peerMacAddr */ + qdf_mem_copy(pMsg->peer_macaddr.bytes, pAssocInd->peerMacAddr, + QDF_MAC_ADDR_SIZE); + /* aid */ + pMsg->aid = pAssocInd->aid; + /* OWE IE */ + if (pAssocInd->owe_ie_len) { + pMsg->owe_ie = qdf_mem_malloc(pAssocInd->owe_ie_len); + if (!pMsg->owe_ie) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(pMsg->owe_ie, pAssocInd->owe_ie, + pAssocInd->owe_ie_len); + pMsg->owe_ie_len = pAssocInd->owe_ie_len; + } + + if (pAssocInd->ft_ie_len) { + pMsg->ft_ie = qdf_mem_malloc(pAssocInd->ft_ie_len); + if (!pMsg->ft_ie) + return QDF_STATUS_E_NOMEM; + qdf_mem_copy(pMsg->ft_ie, pAssocInd->ft_ie, + pAssocInd->ft_ie_len); + pMsg->ft_ie_len = pAssocInd->ft_ie_len; + } + pMsg->need_assoc_rsp_tx_cb = pAssocInd->need_assoc_rsp_tx_cb; + + msg.type = pMsg->messageType; + msg.bodyval = 0; + msg.bodyptr = pMsg; + /* pMsg is freed by umac_send_mb_message_to_mac in anycase*/ + status = scheduler_post_msg_by_priority(QDF_MODULE_ID_PE, &msg, + true); + } while (0); + return status; +} + +/** + * csr_store_oce_cfg_flags_in_vdev() - fill OCE flags from ini + * @mac: mac_context. + * @vdev: Pointer to pdev obj + * @vdev_id: vdev_id + * + * This API will store the oce flags in vdev mlme priv object + * + * Return: none + */ +static void csr_store_oce_cfg_flags_in_vdev(struct mac_context *mac, + struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + uint8_t *vdev_dynamic_oce; + struct wlan_objmgr_vdev *vdev = + wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, WLAN_LEGACY_MAC_ID); + + if (!vdev) + return; + + vdev_dynamic_oce = mlme_get_dynamic_oce_flags(vdev); + if (vdev_dynamic_oce) + *vdev_dynamic_oce = mac->mlme_cfg->oce.feature_bitmap; + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +void csr_send_set_ie(uint8_t type, uint8_t sub_type, + uint8_t vdev_id) +{ + struct send_extcap_ie *msg; + QDF_STATUS status; + + sme_debug("send SET IE msg to PE"); + + if (!(type == WLAN_VDEV_MLME_TYPE_STA || + (type == WLAN_VDEV_MLME_TYPE_AP && + sub_type == WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE))) { + sme_debug("Failed to send set IE req for vdev_%d", vdev_id); + return; + } + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) + return; + + msg->msg_type = eWNI_SME_SET_IE_REQ; + msg->session_id = vdev_id; + msg->length = sizeof(*msg); + status = umac_send_mb_message_to_mac(msg); + if (!QDF_IS_STATUS_SUCCESS(status)) + sme_debug("Failed to send set IE req for vdev_%d", vdev_id); +} + +void csr_get_vdev_type_nss(enum QDF_OPMODE dev_mode, uint8_t *nss_2g, + uint8_t *nss_5g) +{ + struct mac_context *mac_ctx = sme_get_mac_context(); + + if (!mac_ctx) { + sme_err("Invalid MAC context"); + return; + } + + switch (dev_mode) { + case QDF_STA_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.sta; + *nss_5g = mac_ctx->vdev_type_nss_5g.sta; + break; + case QDF_SAP_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.sap; + *nss_5g = mac_ctx->vdev_type_nss_5g.sap; + break; + case QDF_P2P_CLIENT_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_cli; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_cli; + break; + case QDF_P2P_GO_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_go; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_go; + break; + case QDF_P2P_DEVICE_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.p2p_dev; + *nss_5g = mac_ctx->vdev_type_nss_5g.p2p_dev; + break; + case QDF_IBSS_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ibss; + *nss_5g = mac_ctx->vdev_type_nss_5g.ibss; + break; + case QDF_OCB_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ocb; + *nss_5g = mac_ctx->vdev_type_nss_5g.ocb; + break; + case QDF_NAN_DISC_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.nan; + *nss_5g = mac_ctx->vdev_type_nss_5g.nan; + break; + case QDF_NDI_MODE: + *nss_2g = mac_ctx->vdev_type_nss_2g.ndi; + *nss_5g = mac_ctx->vdev_type_nss_5g.ndi; + break; + default: + *nss_2g = 1; + *nss_5g = 1; + sme_err("Unknown device mode: %d", dev_mode); + break; + } + sme_debug("mode - %d: nss_2g - %d, 5g - %d", + dev_mode, *nss_2g, *nss_5g); +} + +QDF_STATUS csr_setup_vdev_session(struct vdev_mlme_obj *vdev_mlme) +{ + QDF_STATUS status; + uint32_t existing_session_id; + struct csr_roam_session *session; + struct mlme_vht_capabilities_info *vht_cap_info; + u8 vdev_id; + struct qdf_mac_addr *mac_addr; + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + struct wlan_objmgr_vdev *vdev; + struct wlan_vht_config vht_config; + struct wlan_ht_config ht_cap; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) { + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (!(mac_ctx->mlme_cfg)) { + sme_err("invalid mlme cfg"); + return QDF_STATUS_E_FAILURE; + } + vht_cap_info = &mac_ctx->mlme_cfg->vht_caps.vht_cap_info; + + vdev = vdev_mlme->vdev; + + vdev_id = wlan_vdev_get_id(vdev); + mac_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev); + /* check to see if the mac address already belongs to a session */ + status = csr_roam_get_session_id_from_bssid(mac_ctx, mac_addr, + &existing_session_id); + if (QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Session %d exists with mac address "QDF_MAC_ADDR_FMT, + existing_session_id, + QDF_MAC_ADDR_REF(mac_addr->bytes)); + return QDF_STATUS_E_FAILURE; + } + + /* attempt to retrieve session for Id */ + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_err("Session does not exist for interface %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* check to see if the session is already active */ + if (session->sessionActive) { + sme_err("Cannot re-open active session with Id %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + session->sessionActive = true; + session->vdev_id = vdev_id; + + ht_cap.caps = 0; + vht_config.caps = 0; + ht_cap.ht_caps = mac_ctx->mlme_cfg->ht_caps.ht_cap_info; + vdev_mlme->proto.ht_info.ht_caps = ht_cap.caps; + + vht_config.max_mpdu_len = vht_cap_info->ampdu_len; + vht_config.supported_channel_widthset = + vht_cap_info->supp_chan_width; + vht_config.ldpc_coding = vht_cap_info->ldpc_coding_cap; + vht_config.shortgi80 = vht_cap_info->short_gi_80mhz; + vht_config.shortgi160and80plus80 = + vht_cap_info->short_gi_160mhz; + vht_config.tx_stbc = vht_cap_info->tx_stbc; + vht_config.rx_stbc = vht_cap_info->rx_stbc; + vht_config.su_beam_former = vht_cap_info->su_bformer; + vht_config.su_beam_formee = vht_cap_info->su_bformee; + vht_config.csnof_beamformer_antSup = + vht_cap_info->tx_bfee_ant_supp; + vht_config.num_soundingdim = vht_cap_info->num_soundingdim; + vht_config.mu_beam_former = vht_cap_info->mu_bformer; + vht_config.mu_beam_formee = vht_cap_info->enable_mu_bformee; + vht_config.vht_txops = vht_cap_info->txop_ps; + vht_config.htc_vhtcap = vht_cap_info->htc_vhtc; + vht_config.rx_antpattern = vht_cap_info->rx_antpattern; + vht_config.tx_antpattern = vht_cap_info->tx_antpattern; + + vht_config.max_ampdu_lenexp = + vht_cap_info->ampdu_len_exponent; + vdev_mlme->proto.vht_info.caps = vht_config.caps; + csr_update_session_he_cap(mac_ctx, session); + csr_update_session_eht_cap(mac_ctx, session); + + csr_send_set_ie(vdev_mlme->mgmt.generic.type, + vdev_mlme->mgmt.generic.subtype, + wlan_vdev_get_id(vdev)); + + if (vdev_mlme->mgmt.generic.type == WLAN_VDEV_MLME_TYPE_STA) { + csr_store_oce_cfg_flags_in_vdev(mac_ctx, mac_ctx->pdev, + wlan_vdev_get_id(vdev)); + wlan_mlme_update_oce_flags(mac_ctx->pdev); + } + + return QDF_STATUS_SUCCESS; +} + +void csr_cleanup_vdev_session(struct mac_context *mac, uint8_t vdev_id) +{ + if (CSR_IS_SESSION_VALID(mac, vdev_id)) { + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, + vdev_id); + + csr_flush_roam_scan_chan_lists(mac, vdev_id); + csr_roam_free_connected_info(mac, &pSession->connectedInfo); + csr_init_session(mac, vdev_id); + } +} + +QDF_STATUS csr_prepare_vdev_delete(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *session; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) + return QDF_STATUS_E_INVAL; + + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) + return QDF_STATUS_E_INVAL; + + if (CSR_IS_WAIT_FOR_KEY(mac_ctx, vdev_id)) { + sme_debug("Stop Wait for key timer and change substate to eCSR_ROAM_SUBSTATE_NONE"); + cm_stop_wait_for_key_timer(mac_ctx->psoc, vdev_id); + csr_roam_substate_change(mac_ctx, eCSR_ROAM_SUBSTATE_NONE, + vdev_id); + } + + wlan_ser_vdev_queue_disable(vdev); + /* Flush all the commands for vdev */ + wlan_serialization_purge_all_cmd_by_vdev_id(mac_ctx->pdev, vdev_id); + if (!mac_ctx->session_close_cb) { + sme_err("no close session callback registered"); + return QDF_STATUS_E_FAILURE; + } + + return status; +} + +static void csr_init_session(struct mac_context *mac, uint32_t sessionId) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) + return; + + pSession->sessionActive = false; + pSession->vdev_id = WLAN_UMAC_VDEV_ID_MAX; + pSession->connectState = eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED; + csr_roam_free_connected_info(mac, &pSession->connectedInfo); +} + +static void csr_get_vdev_id_from_bssid(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct bssid_search_arg *bssid_arg = arg; + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)object; + struct wlan_objmgr_peer *peer; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) + return; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_LEGACY_SME_ID); + if (!peer) + return; + + if (WLAN_ADDR_EQ(bssid_arg->peer_addr.bytes, + wlan_peer_get_macaddr(peer)) == QDF_STATUS_SUCCESS) + bssid_arg->vdev_id = wlan_vdev_get_id(vdev); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_SME_ID); +} + +QDF_STATUS csr_roam_get_session_id_from_bssid(struct mac_context *mac, + struct qdf_mac_addr *bssid, + uint32_t *pSessionId) +{ + struct bssid_search_arg bssid_arg; + + qdf_copy_macaddr(&bssid_arg.peer_addr, bssid); + bssid_arg.vdev_id = WLAN_MAX_VDEVS; + wlan_objmgr_pdev_iterate_obj_list(mac->pdev, WLAN_VDEV_OP, + csr_get_vdev_id_from_bssid, + &bssid_arg, 0, + WLAN_LEGACY_SME_ID); + if (bssid_arg.vdev_id >= WLAN_MAX_VDEVS) { + *pSessionId = 0; + return QDF_STATUS_E_FAILURE; + } + + *pSessionId = bssid_arg.vdev_id; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_get_snr(struct mac_context *mac, + tCsrSnrCallback callback, + struct qdf_mac_addr bssId, void *pContext) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct scheduler_msg msg = {0}; + uint32_t sessionId = WLAN_UMAC_VDEV_ID_MAX; + tAniGetSnrReq *pMsg; + + pMsg = qdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + status = csr_roam_get_session_id_from_bssid(mac, &bssId, &sessionId); + if (!QDF_IS_STATUS_SUCCESS(status)) { + qdf_mem_free(pMsg); + sme_err("Couldn't find session_id for given BSSID"); + return status; + } + + pMsg->msgType = eWNI_SME_GET_SNR_REQ; + pMsg->msgLen = (uint16_t) sizeof(tAniGetSnrReq); + pMsg->sessionId = sessionId; + pMsg->snrCallback = callback; + pMsg->pDevContext = pContext; + msg.type = eWNI_SME_GET_SNR_REQ; + msg.bodyptr = pMsg; + msg.reserved = 0; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + &msg)) { + qdf_mem_free((void *)pMsg); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +#if defined(WLAN_FEATURE_HOST_ROAM) || defined(WLAN_FEATURE_ROAM_OFFLOAD) +QDF_STATUS csr_invoke_neighbor_report_request( + uint8_t session_id, + struct sRrmNeighborReq *neighbor_report_req, + bool send_resp_to_host) +{ + struct wmi_invoke_neighbor_report_params *invoke_params; + struct scheduler_msg msg = {0}; + + if (!neighbor_report_req) { + sme_err("Invalid params"); + return QDF_STATUS_E_INVAL; + } + + invoke_params = qdf_mem_malloc(sizeof(*invoke_params)); + if (!invoke_params) + return QDF_STATUS_E_NOMEM; + + invoke_params->vdev_id = session_id; + invoke_params->send_resp_to_host = send_resp_to_host; + + if (!neighbor_report_req->no_ssid) { + invoke_params->ssid.length = neighbor_report_req->ssid.length; + qdf_mem_copy(invoke_params->ssid.ssid, + neighbor_report_req->ssid.ssId, + neighbor_report_req->ssid.length); + } else { + invoke_params->ssid.length = 0; + } + + sme_debug("Sending SIR_HAL_INVOKE_NEIGHBOR_REPORT"); + + msg.type = SIR_HAL_INVOKE_NEIGHBOR_REPORT; + msg.reserved = 0; + msg.bodyptr = invoke_params; + + if (QDF_STATUS_SUCCESS != scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + &msg)) { + sme_err("Not able to post message to WMA"); + qdf_mem_free(invoke_params); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +void wlan_cm_ese_populate_additional_ies(struct wlan_objmgr_pdev *pdev, + struct wlan_mlme_psoc_ext_obj *mlme_obj, + uint8_t vdev_id, + struct wlan_roam_scan_offload_params *rso_mode_cfg) +{ + uint8_t tspec_ie_hdr[SIR_MAC_OUI_WME_HDR_MIN] + = { 0x00, 0x50, 0xf2, 0x02, 0x02, 0x01 }; + uint8_t tspec_ie_buf[DOT11F_IE_WMMTSPEC_MAX_LEN], j; + ese_wmm_tspec_ie *tspec_ie; + tESETspecInfo ese_tspec; + struct mac_context *mac_ctx; + struct csr_roam_session *session; + + mac_ctx = sme_get_mac_context(); + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + return; + } + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + if (!session) { + sme_err("session is null %d", vdev_id); + return; + } + + tspec_ie = (ese_wmm_tspec_ie *)(tspec_ie_buf + SIR_MAC_OUI_WME_HDR_MIN); + if (csr_is_wmm_supported(mac_ctx) && + mlme_obj->cfg.lfr.ese_enabled && + wlan_cm_get_ese_assoc(pdev, session->vdev_id)) { + ese_tspec.numTspecs = sme_qos_ese_retrieve_tspec_info( + mac_ctx, session->vdev_id, + (tTspecInfo *)&ese_tspec.tspec[0]); + qdf_mem_copy(tspec_ie_buf, tspec_ie_hdr, + SIR_MAC_OUI_WME_HDR_MIN); + for (j = 0; j < ese_tspec.numTspecs; j++) { + /* Populate the tspec_ie */ + ese_populate_wmm_tspec(&ese_tspec.tspec[j].tspec, + tspec_ie); + wlan_cm_append_assoc_ies(rso_mode_cfg, + WLAN_ELEMID_VENDOR, + DOT11F_IE_WMMTSPEC_MAX_LEN, + tspec_ie_buf); + } + } +} +#endif + +uint8_t *wlan_cm_get_rrm_cap_ie_data(void) +{ + struct mac_context *mac_ctx; + + mac_ctx = sme_get_mac_context(); + if (!mac_ctx) { + sme_err("mac_ctx is NULL"); + return NULL; + } + + return (uint8_t *)&mac_ctx->rrm.rrmPEContext.rrmEnabledCaps; +} +#endif + +tSmeCmd *csr_get_command_buffer(struct mac_context *mac) +{ + tSmeCmd *pCmd = sme_get_command_buffer(mac); + + if (pCmd) + mac->roam.sPendingCommands++; + + return pCmd; +} + +static void csr_free_cmd_memory(struct mac_context *mac, tSmeCmd *pCommand) +{ + if (!pCommand) { + sme_err("pCommand is NULL"); + return; + } + switch (pCommand->command) { + case eSmeCommandRoam: + csr_release_command_roam(mac, pCommand); + break; + case eSmeCommandWmStatusChange: + csr_release_command_wm_status_change(mac, pCommand); + break; + default: + break; + } +} + +void csr_release_command_buffer(struct mac_context *mac, tSmeCmd *pCommand) +{ + if (mac->roam.sPendingCommands > 0) { + /* + * All command allocated through csr_get_command_buffer + * need to decrement the pending count when releasing + */ + mac->roam.sPendingCommands--; + csr_free_cmd_memory(mac, pCommand); + sme_release_command(mac, pCommand); + } else { + sme_err("no pending commands"); + QDF_ASSERT(0); + } +} + +void csr_release_command(struct mac_context *mac_ctx, tSmeCmd *sme_cmd) +{ + struct wlan_serialization_queued_cmd_info cmd_info; + struct wlan_serialization_command cmd; + struct wlan_objmgr_vdev *vdev; + + if (!sme_cmd) { + sme_err("sme_cmd is NULL"); + return; + } + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + sme_cmd->vdev_id, WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("Invalid vdev"); + return; + } + qdf_mem_zero(&cmd_info, + sizeof(struct wlan_serialization_queued_cmd_info)); + cmd_info.cmd_id = sme_cmd->cmd_id; + cmd_info.req_type = WLAN_SER_CANCEL_NON_SCAN_CMD; + cmd_info.cmd_type = csr_get_cmd_type(sme_cmd); + cmd_info.vdev = vdev; + qdf_mem_zero(&cmd, sizeof(struct wlan_serialization_command)); + cmd.cmd_id = cmd_info.cmd_id; + cmd.cmd_type = cmd_info.cmd_type; + cmd.vdev = cmd_info.vdev; + if (wlan_serialization_is_cmd_present_in_active_queue( + mac_ctx->psoc, &cmd)) { + cmd_info.queue_type = WLAN_SERIALIZATION_ACTIVE_QUEUE; + wlan_serialization_remove_cmd(&cmd_info); + } else if (wlan_serialization_is_cmd_present_in_pending_queue( + mac_ctx->psoc, &cmd)) { + cmd_info.queue_type = WLAN_SERIALIZATION_PENDING_QUEUE; + wlan_serialization_cancel_request(&cmd_info); + } else { + sme_debug("can't find cmd_id %d cmd_type %d", cmd_info.cmd_id, + cmd_info.cmd_type); + } + if (cmd_info.vdev) + wlan_objmgr_vdev_release_ref(cmd_info.vdev, WLAN_LEGACY_SME_ID); +} + + +static enum wlan_serialization_cmd_type csr_get_roam_cmd_type( + tSmeCmd *sme_cmd) +{ + enum wlan_serialization_cmd_type cmd_type = WLAN_SER_CMD_MAX; + + switch (sme_cmd->u.roamCmd.roamReason) { + case eCsrForcedDisassocSta: + cmd_type = WLAN_SER_CMD_FORCE_DISASSOC_STA; + break; + case eCsrForcedDeauthSta: + cmd_type = WLAN_SER_CMD_FORCE_DEAUTH_STA; + break; + default: + break; + } + + return cmd_type; +} + +enum wlan_serialization_cmd_type csr_get_cmd_type(tSmeCmd *sme_cmd) +{ + enum wlan_serialization_cmd_type cmd_type = WLAN_SER_CMD_MAX; + + switch (sme_cmd->command) { + case eSmeCommandRoam: + cmd_type = csr_get_roam_cmd_type(sme_cmd); + break; + case eSmeCommandWmStatusChange: + cmd_type = WLAN_SER_CMD_WM_STATUS_CHANGE; + break; + case eSmeCommandAddTs: + cmd_type = WLAN_SER_CMD_ADDTS; + break; + case eSmeCommandDelTs: + cmd_type = WLAN_SER_CMD_DELTS; + break; + case e_sme_command_set_hw_mode: + cmd_type = WLAN_SER_CMD_SET_HW_MODE; + break; + case e_sme_command_nss_update: + cmd_type = WLAN_SER_CMD_NSS_UPDATE; + break; + case e_sme_command_set_dual_mac_config: + cmd_type = WLAN_SER_CMD_SET_DUAL_MAC_CONFIG; + break; + case e_sme_command_set_antenna_mode: + cmd_type = WLAN_SER_CMD_SET_ANTENNA_MODE; + break; + case e_sme_command_sap_ch_width_update: + cmd_type = WLAN_SER_CMD_SAP_BW_UPDATE; + break; + default: + break; + } + + return cmd_type; +} + +static uint32_t csr_get_monotonous_number(struct mac_context *mac_ctx) +{ + uint32_t cmd_id; + uint32_t mask = 0x00FFFFFF, prefix = 0x0D000000; + + cmd_id = qdf_atomic_inc_return(&mac_ctx->global_cmd_id); + cmd_id = (cmd_id & mask); + cmd_id = (cmd_id | prefix); + + return cmd_id; +} + +static void csr_fill_cmd_timeout(struct wlan_serialization_command *cmd) +{ + switch (cmd->cmd_type) { + case WLAN_SER_CMD_WM_STATUS_CHANGE: + cmd->cmd_timeout_duration = SME_CMD_PEER_DISCONNECT_TIMEOUT; + break; + case WLAN_SER_CMD_VDEV_START_BSS: + cmd->cmd_timeout_duration = SME_CMD_VDEV_START_BSS_TIMEOUT; + break; + case WLAN_SER_CMD_VDEV_STOP_BSS: + cmd->cmd_timeout_duration = SME_CMD_STOP_BSS_CMD_TIMEOUT; + break; + case WLAN_SER_CMD_FORCE_DISASSOC_STA: + case WLAN_SER_CMD_FORCE_DEAUTH_STA: + cmd->cmd_timeout_duration = SME_CMD_PEER_DISCONNECT_TIMEOUT; + break; + + case WLAN_SER_CMD_ADDTS: + case WLAN_SER_CMD_DELTS: + cmd->cmd_timeout_duration = SME_CMD_ADD_DEL_TS_TIMEOUT; + break; + case WLAN_SER_CMD_SET_HW_MODE: + case WLAN_SER_CMD_NSS_UPDATE: + case WLAN_SER_CMD_SET_DUAL_MAC_CONFIG: + case WLAN_SER_CMD_SET_ANTENNA_MODE: + case WLAN_SER_CMD_SAP_BW_UPDATE: + cmd->cmd_timeout_duration = SME_CMD_POLICY_MGR_CMD_TIMEOUT; + break; + default: + cmd->cmd_timeout_duration = SME_ACTIVE_LIST_CMD_TIMEOUT_VALUE; + break; + } +} + +QDF_STATUS csr_set_serialization_params_to_cmd(struct mac_context *mac_ctx, + tSmeCmd *sme_cmd, struct wlan_serialization_command *cmd, + uint8_t high_priority) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!sme_cmd) { + sme_err("Invalid sme_cmd"); + return status; + } + if (!cmd) { + sme_err("Invalid serialization_cmd"); + return status; + } + + /* + * no need to fill command id for non-scan as they will be + * zero always + */ + sme_cmd->cmd_id = csr_get_monotonous_number(mac_ctx); + cmd->cmd_id = sme_cmd->cmd_id; + + cmd->cmd_type = csr_get_cmd_type(sme_cmd); + if (cmd->cmd_type == WLAN_SER_CMD_MAX) { + sme_err("serialization enum not found for sme_cmd type %d", + sme_cmd->command); + return status; + } + cmd->vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, + sme_cmd->vdev_id, WLAN_LEGACY_SME_ID); + if (!cmd->vdev) { + sme_err("vdev is NULL for vdev_id:%d", sme_cmd->vdev_id); + return status; + } + cmd->umac_cmd = sme_cmd; + + csr_fill_cmd_timeout(cmd); + + cmd->source = WLAN_UMAC_COMP_MLME; + cmd->cmd_cb = sme_ser_cmd_callback; + cmd->is_high_priority = high_priority; + cmd->is_blocking = true; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_queue_sme_command(struct mac_context *mac_ctx, tSmeCmd *sme_cmd, + bool high_priority) +{ + struct wlan_serialization_command cmd; + struct wlan_objmgr_vdev *vdev = NULL; + enum wlan_serialization_status ser_cmd_status; + QDF_STATUS status; + + if (!SME_IS_START(mac_ctx)) { + sme_err("Sme in stop state"); + QDF_ASSERT(0); + goto error; + } + + qdf_mem_zero(&cmd, sizeof(struct wlan_serialization_command)); + status = csr_set_serialization_params_to_cmd(mac_ctx, sme_cmd, + &cmd, high_priority); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("failed to set ser params"); + goto error; + } + + vdev = cmd.vdev; + ser_cmd_status = wlan_serialization_request(&cmd); + + switch (ser_cmd_status) { + case WLAN_SER_CMD_PENDING: + case WLAN_SER_CMD_ACTIVE: + /* Command posted to active/pending list */ + status = QDF_STATUS_SUCCESS; + break; + default: + sme_err("Failed to queue command %d with status:%d", + sme_cmd->command, ser_cmd_status); + status = QDF_STATUS_E_FAILURE; + goto error; + } + + return status; + +error: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + csr_release_command_buffer(mac_ctx, sme_cmd); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS csr_roam_update_config(struct mac_context *mac_ctx, uint8_t session_id, + uint16_t capab, uint32_t value) +{ + struct update_config *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + sme_debug("update HT config requested"); + if (!session) { + sme_err("Session does not exist for session id %d", session_id); + return QDF_STATUS_E_FAILURE; + } + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) + return QDF_STATUS_E_NOMEM; + + msg->messageType = eWNI_SME_UPDATE_CONFIG; + msg->vdev_id = session_id; + msg->capab = capab; + msg->value = value; + msg->length = sizeof(*msg); + status = umac_send_mb_message_to_mac(msg); + + return status; +} + +QDF_STATUS csr_send_channel_change_req(struct mac_context *mac, + struct channel_change_req *req) +{ + struct scheduler_msg msg = {0}; + struct channel_change_req *ch_change_req; + QDF_STATUS status; + + ch_change_req = qdf_mem_malloc(sizeof(*ch_change_req)); + if (!ch_change_req) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(ch_change_req, req, sizeof(*ch_change_req)); + msg.type = eWNI_SME_CHANNEL_CHANGE_REQ; + msg.bodyptr = ch_change_req; + msg.reserved = 0; + + status = scheduler_post_message(QDF_MODULE_ID_SME, + QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, + &msg); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Failed to send channel change request with status : %d", + status); + qdf_mem_free(ch_change_req); + } + + return status; +} +/* + * Post Beacon Tx Start request to LIM + * immediately after SAP CAC WAIT is + * completed without any RADAR indications. + */ +QDF_STATUS csr_roam_start_beacon_req(struct mac_context *mac, + struct qdf_mac_addr bssid, + uint8_t dfsCacWaitStatus) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirStartBeaconIndication *pMsg; + + pMsg = qdf_mem_malloc(sizeof(tSirStartBeaconIndication)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_START_BEACON_REQ; + pMsg->messageLen = sizeof(tSirStartBeaconIndication); + pMsg->beaconStartStatus = dfsCacWaitStatus; + qdf_mem_copy(pMsg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE); + + status = umac_send_mb_message_to_mac(pMsg); + + return status; +} + +/* + * csr_roam_modify_add_ies - + * This function sends msg to modify the additional IE buffers in PE + * + * @mac: mac global structure + * @pModifyIE: pointer to tSirModifyIE structure + * @updateType: Type of buffer + * + * + * Return: QDF_STATUS - Success or failure + */ +QDF_STATUS +csr_roam_modify_add_ies(struct mac_context *mac, + tSirModifyIE *pModifyIE, eUpdateIEsType updateType) +{ + tpSirModifyIEsInd pModifyAddIEInd = NULL; + uint8_t *pLocalBuffer = NULL; + QDF_STATUS status; + + /* following buffer will be freed by consumer (PE) */ + pLocalBuffer = qdf_mem_malloc(pModifyIE->ieBufferlength); + if (!pLocalBuffer) + return QDF_STATUS_E_NOMEM; + + pModifyAddIEInd = qdf_mem_malloc(sizeof(tSirModifyIEsInd)); + if (!pModifyAddIEInd) { + qdf_mem_free(pLocalBuffer); + return QDF_STATUS_E_NOMEM; + } + + /*copy the IE buffer */ + qdf_mem_copy(pLocalBuffer, pModifyIE->pIEBuffer, + pModifyIE->ieBufferlength); + qdf_mem_zero(pModifyAddIEInd, sizeof(tSirModifyIEsInd)); + + pModifyAddIEInd->msgType = eWNI_SME_MODIFY_ADDITIONAL_IES; + pModifyAddIEInd->msgLen = sizeof(tSirModifyIEsInd); + + qdf_copy_macaddr(&pModifyAddIEInd->modifyIE.bssid, &pModifyIE->bssid); + + pModifyAddIEInd->modifyIE.vdev_id = pModifyIE->vdev_id; + pModifyAddIEInd->modifyIE.notify = pModifyIE->notify; + pModifyAddIEInd->modifyIE.ieID = pModifyIE->ieID; + pModifyAddIEInd->modifyIE.ieIDLen = pModifyIE->ieIDLen; + pModifyAddIEInd->modifyIE.pIEBuffer = pLocalBuffer; + pModifyAddIEInd->modifyIE.ieBufferlength = pModifyIE->ieBufferlength; + pModifyAddIEInd->modifyIE.oui_length = pModifyIE->oui_length; + + pModifyAddIEInd->updateType = updateType; + + status = umac_send_mb_message_to_mac(pModifyAddIEInd); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg status %d", + status); + qdf_mem_free(pLocalBuffer); + } + return status; +} + +/* + * csr_roam_update_add_ies - + * This function sends msg to updates the additional IE buffers in PE + * + * @mac: mac global structure + * @sessionId: SME session id + * @bssid: BSSID + * @additionIEBuffer: buffer containing addition IE from hostapd + * @length: length of buffer + * @updateType: Type of buffer + * @append: append or replace completely + * + * + * Return: QDF_STATUS - Success or failure + */ +QDF_STATUS +csr_roam_update_add_ies(struct mac_context *mac, + tSirUpdateIE *pUpdateIE, eUpdateIEsType updateType) +{ + tpSirUpdateIEsInd pUpdateAddIEs = NULL; + uint8_t *pLocalBuffer = NULL; + QDF_STATUS status; + + if (pUpdateIE->ieBufferlength != 0) { + /* Following buffer will be freed by consumer (PE) */ + pLocalBuffer = qdf_mem_malloc(pUpdateIE->ieBufferlength); + if (!pLocalBuffer) { + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(pLocalBuffer, pUpdateIE->pAdditionIEBuffer, + pUpdateIE->ieBufferlength); + } + + pUpdateAddIEs = qdf_mem_malloc(sizeof(tSirUpdateIEsInd)); + if (!pUpdateAddIEs) { + qdf_mem_free(pLocalBuffer); + return QDF_STATUS_E_NOMEM; + } + + pUpdateAddIEs->msgType = eWNI_SME_UPDATE_ADDITIONAL_IES; + pUpdateAddIEs->msgLen = sizeof(tSirUpdateIEsInd); + + qdf_copy_macaddr(&pUpdateAddIEs->updateIE.bssid, &pUpdateIE->bssid); + + pUpdateAddIEs->updateIE.vdev_id = pUpdateIE->vdev_id; + pUpdateAddIEs->updateIE.append = pUpdateIE->append; + pUpdateAddIEs->updateIE.notify = pUpdateIE->notify; + pUpdateAddIEs->updateIE.ieBufferlength = pUpdateIE->ieBufferlength; + pUpdateAddIEs->updateIE.pAdditionIEBuffer = pLocalBuffer; + + pUpdateAddIEs->updateType = updateType; + + status = umac_send_mb_message_to_mac(pUpdateAddIEs); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("Failed to send eWNI_SME_UPDATE_ADDTIONAL_IES msg status %d", + status); + qdf_mem_free(pLocalBuffer); + } + return status; +} + +/** + * csr_send_ext_change_freq()- function to post send ECSA + * action frame to lim. + * @mac_ctx: pointer to global mac structure + * @ch_freq: new channel freq to switch + * @session_id: senssion it should be sent on. + * + * This function is called to post ECSA frame to lim. + * + * Return: success if msg posted to LIM else return failure + */ +QDF_STATUS csr_send_ext_change_freq(struct mac_context *mac_ctx, + qdf_freq_t ch_freq, uint8_t session_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sir_sme_ext_cng_chan_req *msg; + + msg = qdf_mem_malloc(sizeof(*msg)); + if (!msg) + return QDF_STATUS_E_NOMEM; + + msg->message_type = eWNI_SME_EXT_CHANGE_CHANNEL; + msg->length = sizeof(*msg); + msg->new_ch_freq = ch_freq; + msg->vdev_id = session_id; + status = umac_send_mb_message_to_mac(msg); + return status; +} + +QDF_STATUS csr_csa_restart(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct scheduler_msg message = {0}; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("VDEV not found for vdev id: %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if_mgr_deliver_event(vdev, WLAN_IF_MGR_EV_AP_CSA_START, NULL); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + + /* Serialize the req through MC thread */ + message.bodyval = vdev_id; + message.type = eWNI_SME_CSA_RESTART_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("scheduler_post_msg failed!(err=%d)", status); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +QDF_STATUS csr_roam_send_chan_sw_ie_request(struct mac_context *mac_ctx, + struct qdf_mac_addr bssid, + uint32_t target_chan_freq, + uint8_t csa_ie_reqd, + struct ch_params *ch_params, + uint32_t new_cac_ms) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirDfsCsaIeRequest *msg; + + msg = qdf_mem_malloc(sizeof(tSirDfsCsaIeRequest)); + if (!msg) + return QDF_STATUS_E_NOMEM; + + msg->msgType = eWNI_SME_DFS_BEACON_CHAN_SW_IE_REQ; + msg->msgLen = sizeof(tSirDfsCsaIeRequest); + + msg->target_chan_freq = target_chan_freq; + msg->csaIeRequired = csa_ie_reqd; + msg->ch_switch_beacon_cnt = + mac_ctx->sap.SapDfsInfo.sap_ch_switch_beacon_cnt; + if (mac_ctx->sap.one_time_csa_count) { + msg->ch_switch_beacon_cnt = mac_ctx->sap.one_time_csa_count; + mac_ctx->sap.one_time_csa_count = 0; + } + msg->ch_switch_mode = mac_ctx->sap.SapDfsInfo.sap_ch_switch_mode; + msg->dfs_ch_switch_disable = + mac_ctx->sap.SapDfsInfo.disable_dfs_ch_switch; + msg->new_chan_cac_ms = new_cac_ms; + qdf_mem_copy(msg->bssid, bssid.bytes, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&msg->ch_params, ch_params, sizeof(struct ch_params)); + + status = umac_send_mb_message_to_mac(msg); + + return status; +} + +QDF_STATUS csr_sta_continue_csa(struct mac_context *mac_ctx, uint8_t vdev_id) +{ + QDF_STATUS status; + struct scheduler_msg message = {0}; + + /* Serialize the req through MC thread */ + message.bodyval = vdev_id; + message.type = eWNI_SME_STA_CSA_CONTINUE_REQ; + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("eWNI_SME_STA_CSA_CONTINUE_REQ failed!(err=%d)", + status); + status = QDF_STATUS_E_FAILURE; + } + + return status; +} + +/** + * csr_update_op_class_array() - update op class for each band + * @mac_ctx: mac global context + * @op_classes: out param, operating class array to update + * @channel_info: channel info + * @ch_name: channel band name to display in debug messages + * @i: out param, stores number of operating classes + * + * Return: void + */ +static void +csr_update_op_class_array(struct mac_context *mac_ctx, + uint8_t *op_classes, + struct csr_channel *channel_info, + char *ch_name, + uint8_t *i) +{ + uint8_t j = 0, idx = 0, class = 0; + bool found = false; + uint8_t num_channels = channel_info->numChannels; + uint8_t ch_num; + + sme_debug("Num %s channels, %d", ch_name, num_channels); + + for (idx = 0; idx < num_channels && + *i < (REG_MAX_SUPP_OPER_CLASSES - 1); idx++) { + wlan_reg_freq_to_chan_op_class( + mac_ctx->pdev, channel_info->channel_freq_list[idx], + true, BIT(BEHAV_NONE), &class, &ch_num); + + found = false; + for (j = 0; j < REG_MAX_SUPP_OPER_CLASSES - 1; j++) { + if (op_classes[j] == class) { + found = true; + break; + } + } + + if (!found) { + op_classes[*i] = class; + *i = *i + 1; + } + } +} + +/** + * csr_init_operating_classes() - update op class for all bands + * @mac: pointer to mac context. + * + * Return: void + */ +static void csr_init_operating_classes(struct mac_context *mac) +{ + uint8_t i = 0; + uint8_t j = 0; + uint8_t swap = 0; + uint8_t numClasses = 0; + uint8_t opClasses[REG_MAX_SUPP_OPER_CLASSES] = {0,}; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + wlan_reg_read_current_country(mac->psoc, reg_cc); + sme_debug("Current Country = %s", reg_cc); + + csr_update_op_class_array(mac, opClasses, + &mac->scan.base_channels, "20MHz", &i); + numClasses = i; + + /* As per spec the operating classes should be in ascending order. + * Bubble sort is fine since we don't have many classes + */ + for (i = 0; i < (numClasses - 1); i++) { + for (j = 0; j < (numClasses - i - 1); j++) { + /* For decreasing order use < */ + if (opClasses[j] > opClasses[j + 1]) { + swap = opClasses[j]; + opClasses[j] = opClasses[j + 1]; + opClasses[j + 1] = swap; + } + } + } + + /* Set the ordered list of op classes in regdomain + * for use by other modules + */ + wlan_reg_dmn_set_curr_opclasses(numClasses, &opClasses[0]); +} + +/** + * csr_process_set_hw_mode() - Set HW mode command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the set HW mode command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_set_hw_mode(struct mac_context *mac, tSmeCmd *command) +{ + uint32_t len; + struct s_sir_set_hw_mode *cmd = NULL; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct sir_set_hw_mode_resp *param; + enum policy_mgr_hw_mode_change hw_mode; + enum policy_mgr_conc_next_action action; + enum set_hw_mode_status hw_mode_change_status = + SET_HW_MODE_STATUS_ECANCELED; + + /* Setting HW mode is for the entire system. + * So, no need to check session + */ + + if (!command) { + sme_err("Set HW mode param is NULL"); + goto fail; + } + + len = sizeof(*cmd); + cmd = qdf_mem_malloc(len); + if (!cmd) + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + + action = command->u.set_hw_mode_cmd.action; + + status = policy_mgr_validate_dbs_switch(mac->psoc, action); + + if (QDF_IS_STATUS_ERROR(status)) { + sme_debug("Hw mode change not sent to FW status = %d", status); + if (status == QDF_STATUS_E_ALREADY) + hw_mode_change_status = SET_HW_MODE_STATUS_ALREADY; + goto fail; + } + + hw_mode = policy_mgr_get_hw_mode_change_from_hw_mode_index( + mac->psoc, command->u.set_hw_mode_cmd.hw_mode_index); + + if (POLICY_MGR_HW_MODE_NOT_IN_PROGRESS == hw_mode) { + sme_err("hw_mode %d, failing", hw_mode); + goto fail; + } + + policy_mgr_set_hw_mode_change_in_progress(mac->psoc, hw_mode); + policy_mgr_reset_connection_update(mac->psoc); + + if ((POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC == + command->u.set_hw_mode_cmd.reason) && + (true == mac->sme.get_connection_info_cb(NULL, NULL))) { + sme_err("Set HW mode refused: conn in progress"); + policy_mgr_restart_opportunistic_timer(mac->psoc, false); + goto reset_state; + } + + if ((POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC == + command->u.set_hw_mode_cmd.reason) && + (!command->u.set_hw_mode_cmd.hw_mode_index && + !policy_mgr_need_opportunistic_upgrade(mac->psoc, NULL))) { + sme_err("Set HW mode to SMM not needed anymore"); + goto reset_state; + } + + cmd->messageType = eWNI_SME_SET_HW_MODE_REQ; + cmd->length = len; + cmd->set_hw.hw_mode_index = command->u.set_hw_mode_cmd.hw_mode_index; + cmd->set_hw.reason = command->u.set_hw_mode_cmd.reason; + /* + * Below callback and context info are not needed for PE as of now. + * Storing the passed value in the same s_sir_set_hw_mode format. + */ + cmd->set_hw.set_hw_mode_cb = command->u.set_hw_mode_cmd.set_hw_mode_cb; + + sme_debug( + "Posting set hw mode req to PE session:%d reason:%d", + command->u.set_hw_mode_cmd.session_id, + command->u.set_hw_mode_cmd.reason); + + status = umac_send_mb_message_to_mac(cmd); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Posting to PE failed"); + cmd = NULL; + goto reset_state; + } + return; + +reset_state: + policy_mgr_set_hw_mode_change_in_progress(mac->psoc, + POLICY_MGR_HW_MODE_NOT_IN_PROGRESS); +fail: + if (cmd) + qdf_mem_free(cmd); + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return; + + sme_debug("Sending set HW fail response to SME"); + param->status = hw_mode_change_status; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + msg.type = eWNI_SME_SET_HW_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_set_dual_mac_config() - Set HW mode command to PE + * @mac: Global MAC pointer + * @command: Command received from SME + * + * Posts the set dual mac config command to PE. + * + * Return: None + */ +void csr_process_set_dual_mac_config(struct mac_context *mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_set_dual_mac_cfg *cmd; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct sir_dual_mac_config_resp *param; + + /* Setting MAC configuration is for the entire system. + * So, no need to check session + */ + + if (!command) { + sme_err("Set HW mode param is NULL"); + goto fail; + } + + len = sizeof(*cmd); + cmd = qdf_mem_malloc(len); + if (!cmd) + /* Probably the fail response will also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + + cmd->message_type = eWNI_SME_SET_DUAL_MAC_CFG_REQ; + cmd->length = len; + cmd->set_dual_mac.scan_config = command->u.set_dual_mac_cmd.scan_config; + cmd->set_dual_mac.fw_mode_config = + command->u.set_dual_mac_cmd.fw_mode_config; + /* + * Below callback and context info are not needed for PE as of now. + * Storing the passed value in the same sir_set_dual_mac_cfg format. + */ + cmd->set_dual_mac.set_dual_mac_cb = + command->u.set_dual_mac_cmd.set_dual_mac_cb; + + sme_debug("Posting eWNI_SME_SET_DUAL_MAC_CFG_REQ to PE: %x %x", + cmd->set_dual_mac.scan_config, + cmd->set_dual_mac.fw_mode_config); + + status = umac_send_mb_message_to_mac(cmd); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("Posting to PE failed"); + goto fail; + } + return; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return; + + sme_err("Sending set dual mac fail response to SME"); + param->status = SET_HW_MODE_STATUS_ECANCELED; + msg.type = eWNI_SME_SET_DUAL_MAC_CFG_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_set_antenna_mode() - Set antenna mode command to + * PE + * @mac: Global MAC pointer + * @command: Command received from SME + * + * Posts the set dual mac config command to PE. + * + * Return: None + */ +void csr_process_set_antenna_mode(struct mac_context *mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_set_antenna_mode *cmd; + QDF_STATUS status; + struct scheduler_msg msg = {0}; + struct sir_antenna_mode_resp *param; + + /* Setting MAC configuration is for the entire system. + * So, no need to check session + */ + + if (!command) { + sme_err("Set antenna mode param is NULL"); + goto fail; + } + + len = sizeof(*cmd); + cmd = qdf_mem_malloc(len); + if (!cmd) + goto fail; + + cmd->message_type = eWNI_SME_SET_ANTENNA_MODE_REQ; + cmd->length = len; + cmd->set_antenna_mode = command->u.set_antenna_mode_cmd; + + sme_debug( + "Posting eWNI_SME_SET_ANTENNA_MODE_REQ to PE: %d %d", + cmd->set_antenna_mode.num_rx_chains, + cmd->set_antenna_mode.num_tx_chains); + + status = umac_send_mb_message_to_mac(cmd); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Posting to PE failed"); + /* + * umac_send_mb_message_to_mac would've released the mem + * allocated by cmd. + */ + goto fail; + } + + return; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return; + + sme_err("Sending set dual mac fail response to SME"); + param->status = SET_ANTENNA_MODE_STATUS_ECANCELED; + msg.type = eWNI_SME_SET_ANTENNA_MODE_RESP; + msg.bodyptr = param; + msg.bodyval = 0; + sys_process_mmh_msg(mac, &msg); +} + +/** + * csr_process_nss_update_req() - Update nss command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the nss update command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_nss_update_req(struct mac_context *mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_nss_update_request *msg; + QDF_STATUS status; + struct scheduler_msg msg_return = {0}; + struct sir_bcn_update_rsp *param; + struct csr_roam_session *session; + + + if (!CSR_IS_SESSION_VALID(mac, command->vdev_id)) { + sme_err("Invalid session id %d", command->vdev_id); + goto fail; + } + session = CSR_GET_SESSION(mac, command->vdev_id); + + len = sizeof(*msg); + msg = qdf_mem_malloc(len); + if (!msg) + /* Probably the fail response is also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + + msg->msgType = eWNI_SME_NSS_UPDATE_REQ; + msg->msgLen = sizeof(*msg); + + msg->new_nss = command->u.nss_update_cmd.new_nss; + msg->ch_width = command->u.nss_update_cmd.ch_width; + msg->vdev_id = command->u.nss_update_cmd.session_id; + + sme_debug("Posting eWNI_SME_NSS_UPDATE_REQ to PE"); + + status = umac_send_mb_message_to_mac(msg); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + sme_err("Posting to PE failed"); +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return; + + sme_err("Sending nss update fail response to SME"); + param->status = QDF_STATUS_E_FAILURE; + param->vdev_id = command->u.nss_update_cmd.session_id; + param->reason = REASON_NSS_UPDATE; + msg_return.type = eWNI_SME_NSS_UPDATE_RSP; + msg_return.bodyptr = param; + msg_return.bodyval = 0; + sys_process_mmh_msg(mac, &msg_return); +} + +/** + * csr_process_sap_ch_width_update() - Update ch_width command to PE + * @mac: Globacl MAC pointer + * @command: Command received from SME + * + * Posts the ch_width update command to PE. This message passing + * through PE is required for PE's internal management + * + * Return: None + */ +void csr_process_sap_ch_width_update(struct mac_context *mac, tSmeCmd *command) +{ + uint32_t len; + struct sir_sap_ch_width_update *msg; + QDF_STATUS status; + struct scheduler_msg msg_return = {0}; + struct sir_bcn_update_rsp *param; + enum policy_mgr_conn_update_reason reason = + command->u.bw_update_cmd.reason; + + if (!CSR_IS_SESSION_VALID(mac, command->vdev_id)) { + sme_err("Invalid session id %d", command->vdev_id); + goto fail; + } + + if ((reason == POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC) && + (mac->sme.get_connection_info_cb(NULL, NULL))) { + policy_mgr_restart_opportunistic_timer(mac->psoc, false); + sme_info("Vdev %d : Avoid set BW as conn in progress", + command->vdev_id); + goto fail; + } + + if ((reason == POLICY_MGR_UPDATE_REASON_OPPORTUNISTIC) && + (!policy_mgr_need_opportunistic_upgrade(mac->psoc, &reason))) { + sme_info("Vdev %d: BW update not needed anymore", + command->vdev_id); + goto fail; + } + + len = sizeof(*msg); + msg = qdf_mem_malloc(len); + if (!msg) + /* Probably the fail response is also fail during malloc. + * Still proceeding to send response! + */ + goto fail; + + msg->msgType = eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ; + msg->msgLen = sizeof(*msg); + + msg->ch_width = command->u.bw_update_cmd.ch_width; + msg->vdev_id = command->u.bw_update_cmd.vdev_id; + + sme_debug("Posting eWNI_SME_SAP_CH_WIDTH_UPDATE_REQ to PE"); + + status = umac_send_mb_message_to_mac(msg); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + sme_err("Posting to PE failed"); +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (param) { + param->status = QDF_STATUS_E_FAILURE; + param->vdev_id = command->u.bw_update_cmd.vdev_id; + param->reason = REASON_CH_WIDTH_UPDATE; + } + msg_return.type = eWNI_SME_SAP_CH_WIDTH_UPDATE_RSP; + msg_return.bodyptr = param; + msg_return.bodyval = 0; + sys_process_mmh_msg(mac, &msg_return); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef WLAN_FEATURE_SAE +/** + * csr_process_roam_auth_sae_callback() - API to trigger the + * WPA3 pre-auth event for candidate AP received from firmware. + * @mac_ctx: Global mac context pointer + * @vdev_id: vdev id + * @roam_bssid: Candidate BSSID to roam + * @akm: Candidate AKM + * + * This function calls the hdd_sme_roam_callback with reason + * eCSR_ROAM_SAE_COMPUTE to trigger SAE auth to supplicant. + */ +static QDF_STATUS +csr_process_roam_auth_sae_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr roam_bssid, + uint32_t akm) +{ + struct csr_roam_info *roam_info; + struct sir_sae_info sae_info; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (!session) { + sme_err("WPA3 Preauth event with invalid session id:%d", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_FAILURE; + + sae_info.msg_len = sizeof(sae_info); + sae_info.vdev_id = vdev_id; + sae_info.akm = akm; + wlan_cm_get_roam_offload_ssid(mac_ctx->psoc, vdev_id, + sae_info.ssid.ssId, + &sae_info.ssid.length); + qdf_mem_copy(sae_info.peer_mac_addr.bytes, + roam_bssid.bytes, QDF_MAC_ADDR_SIZE); + + roam_info->sae_info = &sae_info; + + csr_roam_call_callback(mac_ctx, vdev_id, roam_info, + eCSR_ROAM_SAE_COMPUTE, eCSR_ROAM_RESULT_NONE); + + qdf_mem_free(roam_info); + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS +csr_process_roam_auth_sae_callback(struct mac_context *mac_ctx, + uint8_t vdev_id, + struct qdf_mac_addr roam_bssid, + uint32_t akm) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +QDF_STATUS +csr_roam_auth_offload_callback(struct mac_context *mac_ctx, uint8_t vdev_id, + struct qdf_mac_addr bssid, uint32_t akm) +{ + QDF_STATUS status; + + status = sme_acquire_global_lock(&mac_ctx->sme); + if (!QDF_IS_STATUS_SUCCESS(status)) + return status; + + status = csr_process_roam_auth_sae_callback(mac_ctx, vdev_id, + bssid, akm); + + sme_release_global_lock(&mac_ctx->sme); + + return status; + +} +#endif + +QDF_STATUS csr_update_owe_info(struct mac_context *mac, + struct assoc_ind *assoc_ind) +{ + uint32_t session_id = WLAN_UMAC_VDEV_ID_MAX; + QDF_STATUS status; + + status = csr_roam_get_session_id_from_bssid(mac, + (struct qdf_mac_addr *)assoc_ind->bssId, + &session_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_debug("Couldn't find session_id for given BSSID"); + return QDF_STATUS_E_FAILURE; + } + + /* Send Association completion message to PE */ + if (assoc_ind->owe_status) + status = QDF_STATUS_E_INVAL; + status = csr_send_assoc_cnf_msg(mac, assoc_ind, status, + assoc_ind->owe_status); + /* + * send a message to CSR itself just to avoid the EAPOL frames + * going OTA before association response + */ + if (assoc_ind->owe_status == 0) + status = csr_send_assoc_ind_to_upper_layer_cnf_msg(mac, + assoc_ind, + status, + session_id); + + return status; +} + +QDF_STATUS csr_update_ft_info(struct mac_context *mac, + struct assoc_ind *assoc_ind) +{ + QDF_STATUS status; + + /* Send Association completion message to PE */ + status = assoc_ind->ft_status ? QDF_STATUS_E_INVAL : QDF_STATUS_SUCCESS; + assoc_ind->need_assoc_rsp_tx_cb = true; + status = csr_send_assoc_cnf_msg(mac, assoc_ind, status, + assoc_ind->ft_status); + return status; +} + +/** + * csr_set_sap_ser_params() - API to fill serialization parameters for + * SAP requests + * @cmd : Serialization command + * @cmd_type: Type of serialization command + * + * Return: Void + */ +static void csr_set_sap_ser_params(struct wlan_serialization_command *cmd, + enum wlan_serialization_cmd_type cmd_type) +{ + cmd->cmd_type = cmd_type; + cmd->source = WLAN_UMAC_COMP_MLME; + cmd->cmd_cb = sme_sap_ser_callback; + cmd->is_high_priority = false; + cmd->is_blocking = true; + return; +} + +QDF_STATUS csr_bss_start(struct mac_context *mac, uint32_t vdev_id, + struct start_bss_config *bss_config) +{ + struct wlan_serialization_command cmd = {0}; + struct wlan_objmgr_vdev *vdev; + struct start_bss_config *start_bss_cfg = NULL; + enum QDF_OPMODE persona; + enum wlan_serialization_status status; + struct csr_roam_session *session; + struct validate_bss_data candidate; + + session = CSR_GET_SESSION(mac, vdev_id); + if (!session) + return QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac->pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("VDEV not found for vdev id : %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + persona = wlan_vdev_mlme_get_opmode(vdev); + if (persona != QDF_SAP_MODE && persona != QDF_NDI_MODE && + persona != QDF_P2P_GO_MODE) { + sme_err("Start BSS request for invalid mode %d", persona); + goto error; + } + + start_bss_cfg = qdf_mem_malloc(sizeof(struct start_bss_config)); + if (!start_bss_cfg) { + sme_err("SAP BSS config allocation failed"); + goto error; + } + + qdf_mem_copy(start_bss_cfg, bss_config, + sizeof(struct start_bss_config)); + start_bss_cfg->cmd_id = csr_get_monotonous_number(mac); + + session->cb_mode = start_bss_cfg->sec_ch_offset; + session->bcn_int = bss_config->beaconInterval; + candidate.beacon_interval = session->bcn_int; + candidate.chan_freq = bss_config->oper_ch_freq; + if_mgr_is_beacon_interval_valid(mac->pdev, vdev_id, + &candidate); + bss_config->beaconInterval = candidate.beacon_interval; + session->bcn_int = candidate.beacon_interval; + + cmd.cmd_id = start_bss_cfg->cmd_id; + csr_set_sap_ser_params(&cmd, WLAN_SER_CMD_VDEV_START_BSS); + cmd.umac_cmd = start_bss_cfg; + cmd.vdev = vdev; + csr_fill_cmd_timeout(&cmd); + + status = wlan_vdev_mlme_ser_start_bss(&cmd); + switch (status) { + case WLAN_SER_CMD_PENDING: + case WLAN_SER_CMD_ACTIVE: + break; + default: + sme_err("ser cmd status %d", status); + goto error; + } + + return QDF_STATUS_SUCCESS; +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + if (start_bss_cfg) + qdf_mem_free(start_bss_cfg); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS csr_roam_issue_stop_bss_cmd(struct mac_context *mac, + uint8_t vdev_id, + eCsrRoamBssType bss_type) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_serialization_command cmd = {0}; + enum wlan_serialization_status status; + struct stop_bss_req *stop_bss_req; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac->pdev, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("VDEV not found for vdev id : %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + /* Change the substate in case it is wait-for-key */ + if (CSR_IS_WAIT_FOR_KEY(mac, vdev_id)) { + cm_stop_wait_for_key_timer(mac->psoc, vdev_id); + csr_roam_substate_change(mac, eCSR_ROAM_SUBSTATE_NONE, + vdev_id); + } + + sme_debug("Stop BSS vdev_id: %d bss_type %d", vdev_id, bss_type); + stop_bss_req = qdf_mem_malloc(sizeof(*stop_bss_req)); + if (!stop_bss_req) + goto error; + + stop_bss_req->vdev_id = vdev_id; + stop_bss_req->cmd_id = csr_get_monotonous_number(mac); + + cmd.cmd_id = stop_bss_req->cmd_id; + csr_set_sap_ser_params(&cmd, WLAN_SER_CMD_VDEV_STOP_BSS); + cmd.umac_cmd = stop_bss_req; + cmd.vdev = vdev; + csr_fill_cmd_timeout(&cmd); + + status = wlan_vdev_mlme_ser_stop_bss(&cmd); + switch (status) { + case WLAN_SER_CMD_PENDING: + case WLAN_SER_CMD_ACTIVE: + break; + default: + sme_err("ser cmd status %d", status); + goto error; + } + return QDF_STATUS_SUCCESS; + +error: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); + qdf_mem_free(stop_bss_req); + return QDF_STATUS_E_FAILURE; +} + +static void csr_process_stop_bss_response(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, vdev_id); + + if (CSR_IS_ROAM_SUBSTATE_STOP_BSS_REQ(mac_ctx, vdev_id)) { + csr_roam_free_connected_info(mac_ctx, &session->connectedInfo); + csr_set_default_dot11_mode(mac_ctx); + } + + csr_roam_call_callback(mac_ctx, vdev_id, NULL, eCSR_ROAM_INFRA_IND, + eCSR_ROAM_RESULT_INFRA_STOPPED); + return; +} + +/** + * csr_process_sap_results() - API to process the LIM response for + * the messages posted by SAP module + * @mac_ctx: mac context + * @req: Serialization command posted by SAP + * @rsp: Response from LIM + * @result: Result from LIM + * @vdev_id : vdev id + * + * Return: void + */ +static bool csr_process_sap_results(struct mac_context *mac_ctx, + void *rsp, + enum csr_sap_response_type result, + uint8_t vdev_id) +{ + struct csr_roam_info *roam_info; + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, vdev_id); + eRoamCmdStatus roam_status = eCSR_ROAM_INFRA_IND; + eCsrRoamResult roam_result = eCSR_ROAM_RESULT_INFRA_START_FAILED; + enum QDF_OPMODE opmode; + + if (!session) { + sme_err("session %d not found ", vdev_id); + return false; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return false; + + opmode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + sme_debug("SAP result : %d", result); + + switch (result) { + case CSR_SAP_START_BSS_SUCCESS: + csr_roam_process_start_bss_success(mac_ctx, roam_info, + rsp, vdev_id); + break; + case CSR_SAP_START_BSS_FAILURE: + if (opmode == QDF_NDI_MODE) { + csr_roam_update_ndp_return_params(mac_ctx, + CSR_SAP_START_BSS_FAILURE, + &roam_status, + &roam_result, + roam_info); + } + csr_roam_call_callback(mac_ctx, vdev_id, roam_info, + roam_status, roam_result); + csr_set_default_dot11_mode(mac_ctx); + break; + case CSR_SAP_STOP_BSS_SUCCESS: + case CSR_SAP_STOP_BSS_FAILURE: + if (opmode == QDF_NDI_MODE) { + qdf_mem_zero(roam_info, sizeof(*roam_info)); + csr_roam_update_ndp_return_params(mac_ctx, result, + &roam_status, + &roam_result, + roam_info); + csr_roam_call_callback(mac_ctx, vdev_id, roam_info, + roam_status, roam_result); + } else { + csr_process_stop_bss_response(mac_ctx, vdev_id); + } + break; + default: + sme_err("Invalid response"); + break; + } + qdf_mem_free(roam_info); + return true; +} + +static enum wlan_serialization_cmd_type +get_cmd_type_from_result(enum csr_sap_response_type result) +{ + switch (result) { + case CSR_SAP_START_BSS_SUCCESS: + case CSR_SAP_START_BSS_FAILURE: + return WLAN_SER_CMD_VDEV_START_BSS; + case CSR_SAP_STOP_BSS_SUCCESS: + case CSR_SAP_STOP_BSS_FAILURE: + return WLAN_SER_CMD_VDEV_STOP_BSS; + default: + return WLAN_SER_CMD_MAX; + } +} + +static inline +uint32_t get_cmd_id_from_cmd_type(void *cmd, + enum wlan_serialization_cmd_type cmd_type) +{ + switch (cmd_type) { + case WLAN_SER_CMD_VDEV_START_BSS: + return ((struct start_bss_config *)cmd)->cmd_id; + case WLAN_SER_CMD_VDEV_STOP_BSS: + return ((struct stop_bss_req *)cmd)->cmd_id; + default: + sme_err("Invalid cmd_type %d to be dequeued", cmd_type); + return 0; + } +} + +void csr_process_sap_response(struct mac_context *mac_ctx, + enum csr_sap_response_type result, + void *rsp, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + void *req; + uint32_t cmd_id; + enum wlan_serialization_cmd_type cmd_type = + get_cmd_type_from_result(result); + + if (cmd_type >= WLAN_SER_CMD_MAX) { + sme_err("Invalid command to be dequeued %d", cmd_type); + return; + } + + req = wlan_serialization_get_active_cmd(mac_ctx->psoc, + vdev_id, cmd_type); + if (!req) { + sme_err("No active command for response from LIM for cmd: %d vdev: %d", + cmd_type, vdev_id); + csr_process_sap_results(mac_ctx, rsp, result, vdev_id); + return; + } + + csr_process_sap_results(mac_ctx, rsp, result, vdev_id); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_MAC_ID); + if (!vdev) { + sme_err("vdev not found for vdev id: %d", vdev_id); + return; + } + + cmd_id = get_cmd_id_from_cmd_type(req, cmd_type); + sme_debug("Dequeue cmd id : %d type : %d", cmd_id, cmd_type); + + wlan_vdev_mlme_ser_remove_request(vdev, cmd_id, cmd_type); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_MAC_ID); +} + +void csr_set_vdev_ies_per_band(mac_handle_t mac_handle, uint8_t vdev_id, + enum QDF_OPMODE device_mode) +{ + struct sir_set_vdev_ies_per_band *p_msg; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct mac_context *mac_ctx = MAC_CONTEXT(mac_handle); + enum csr_cfgdot11mode curr_dot11_mode = + mac_ctx->roam.configParam.uCfgDot11Mode; + + p_msg = qdf_mem_malloc(sizeof(*p_msg)); + if (!p_msg) + return; + + p_msg->vdev_id = vdev_id; + p_msg->device_mode = device_mode; + p_msg->dot11_mode = csr_get_vdev_dot11_mode(mac_ctx, vdev_id, + curr_dot11_mode); + p_msg->msg_type = eWNI_SME_SET_VDEV_IES_PER_BAND; + p_msg->len = sizeof(*p_msg); + sme_debug("SET_VDEV_IES_PER_BAND: vdev_id %d dot11mode %d dev_mode %d", + vdev_id, p_msg->dot11_mode, device_mode); + status = umac_send_mb_message_to_mac(p_msg); + if (QDF_STATUS_SUCCESS != status) + sme_err("Send eWNI_SME_SET_VDEV_IES_PER_BAND fail"); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_api_scan.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_api_scan.c new file mode 100644 index 0000000000..785ff4288e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_api_scan.c @@ -0,0 +1,1025 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: csr_api_scan.c + * + * Implementation for the Common Scan interfaces. + */ + +#include "ani_global.h" + +#include "csr_inside_api.h" +#include "sme_inside.h" + +#include "csr_support.h" + +#include "host_diag_core_log.h" +#include "host_diag_core_event.h" + +#include "cds_reg_service.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "wma.h" + +#include "wlan_policy_mgr_api.h" +#include "wlan_hdd_main.h" +#include "pld_common.h" +#include "csr_internal.h" +#include +#include +#include +#include +#include +#include +#include "wlan_reg_services_api.h" +#include "sch_api.h" +#include "wlan_dlm_api.h" +#include "qdf_crypto.h" +#include +#include "wlan_reg_ucfg_api.h" +#include "wlan_cm_bss_score_param.h" + +static void csr_set_cfg_valid_channel_list(struct mac_context *mac, + uint32_t *pchan_freq_list, + uint8_t NumChannels); + +static void csr_save_tx_power_to_cfg(struct mac_context *mac, + tDblLinkList *pList, + uint32_t cfgId); + +static void csr_purge_channel_power(struct mac_context *mac, + tDblLinkList *pChannelList); + +/* pResult is invalid calling this function. */ +void csr_free_scan_result_entry(struct mac_context *mac, + struct tag_csrscan_result *pResult) +{ + if (pResult->Result.pvIes) + qdf_mem_free(pResult->Result.pvIes); + + qdf_mem_free(pResult); +} + +static QDF_STATUS csr_ll_scan_purge_result(struct mac_context *mac, + tDblLinkList *pList) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tListElem *pEntry; + struct tag_csrscan_result *bss_desc; + + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + bss_desc = GET_BASE_ADDR(pEntry, struct tag_csrscan_result, + Link); + csr_free_scan_result_entry(mac, bss_desc); + } + + return status; +} + +QDF_STATUS csr_scan_open(struct mac_context *mac_ctx) +{ + csr_ll_open(&mac_ctx->scan.channelPowerInfoList24); + csr_ll_open(&mac_ctx->scan.channelPowerInfoList5G); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_close(struct mac_context *mac) +{ + csr_purge_channel_power(mac, &mac->scan.channelPowerInfoList24); + csr_purge_channel_power(mac, &mac->scan.channelPowerInfoList5G); + csr_ll_close(&mac->scan.channelPowerInfoList24); + csr_ll_close(&mac->scan.channelPowerInfoList5G); + wlan_scan_psoc_set_disable(mac->psoc, REASON_SYSTEM_DOWN); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_result_purge(struct mac_context *mac, + tScanResultHandle hScanList) +{ + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct scan_result_list *pScanList = + (struct scan_result_list *) hScanList; + + if (pScanList) { + status = csr_ll_scan_purge_result(mac, &pScanList->List); + csr_ll_close(&pScanList->List); + qdf_mem_free(pScanList); + } + return status; +} + +static void csr_purge_channel_power(struct mac_context *mac, + tDblLinkList *pChannelList) +{ + struct csr_channel_powerinfo *pChannelSet; + tListElem *pEntry; + + /* + * Remove the channel sets from the learned list and put them + * in the free list + */ + csr_ll_lock(pChannelList); + while ((pEntry = csr_ll_remove_head(pChannelList, + LL_ACCESS_NOLOCK)) != NULL) { + pChannelSet = GET_BASE_ADDR(pEntry, + struct csr_channel_powerinfo, link); + if (pChannelSet) + qdf_mem_free(pChannelSet); + } + csr_ll_unlock(pChannelList); +} + +#define FREQ_SIZE 4 +#define SPACE_SIZE 2 +#define SIZEOFNULL 1 +#define BUF24GHZSIZE (NUM_24GHZ_CHANNELS * (\ + FREQ_SIZE + SPACE_SIZE) + SIZEOFNULL) +#define BUF5GHZSIZE (NUM_5GHZ_CHANNELS * (\ + FREQ_SIZE + SPACE_SIZE) + SIZEOFNULL) + +/* + * Save the channelList into the ultimate storage as the final stage of channel + * Input: pCountryInfo -- the country code (e.g. "USI"), channel list, and power + * limit are all stored inside this data structure + */ +QDF_STATUS csr_save_to_channel_power2_g_5_g(struct mac_context *mac, + uint32_t tableSize, + struct pwr_channel_info *channelTable) +{ + uint32_t i = tableSize / sizeof(struct pwr_channel_info); + struct pwr_channel_info *pChannelInfo; + struct csr_channel_powerinfo *pchannelset; + bool f2GHzInfoFound = false; + bool f2GListPurged = false, f5GListPurged = false; + uint8_t *buf24ghz = qdf_mem_malloc(BUF24GHZSIZE); + uint8_t *buf5ghz = qdf_mem_malloc(BUF5GHZSIZE); + uint32_t size24ghz = 0, size5ghz = 0; + + if (!buf24ghz || !buf5ghz) { + if (buf24ghz) + qdf_mem_free(buf24ghz); + if (buf5ghz) + qdf_mem_free(buf5ghz); + return QDF_STATUS_E_NOMEM; + } + pChannelInfo = channelTable; + /* atleast 3 bytes have to be remaining -- from "countryString" */ + while (i--) { + pchannelset = qdf_mem_malloc(sizeof(struct csr_channel_powerinfo)); + if (!pchannelset) { + pChannelInfo++; + continue; + } + pchannelset->first_chan_freq = pChannelInfo->first_freq; + pchannelset->numChannels = pChannelInfo->num_chan; + /* + * Now set the inter-channel offset based on the frequency band + * the channel set lies in + */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(pchannelset->first_chan_freq) && + (pchannelset->first_chan_freq + 5 * (pchannelset->numChannels - 1) <= + WLAN_REG_MAX_24GHZ_CHAN_FREQ)) { + pchannelset->interChannelOffset = 5; + f2GHzInfoFound = true; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ(pchannelset->first_chan_freq) && + (pchannelset->first_chan_freq + 20 * (pchannelset->numChannels - 1) <= + WLAN_REG_MAX_5GHZ_CHAN_FREQ)) { + pchannelset->interChannelOffset = 20; + f2GHzInfoFound = false; + } else { + sme_warn("Invalid Channel freq %d Present in Country IE", + pchannelset->first_chan_freq); + qdf_mem_free(pchannelset); + qdf_mem_free(buf24ghz); + qdf_mem_free(buf5ghz); + return QDF_STATUS_E_FAILURE; + } + pchannelset->txPower = pChannelInfo->max_tx_pwr; + if (f2GHzInfoFound) { + if (!f2GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(mac, + &mac->scan. + channelPowerInfoList24); + f2GListPurged = true; + } + if (CSR_IS_OPERATING_BG_BAND(mac)) { + /* add to the list of 2.4 GHz channel sets */ + csr_ll_insert_tail(&mac->scan. + channelPowerInfoList24, + &pchannelset->link, + LL_ACCESS_LOCK); + } else { + size24ghz += qdf_scnprintf( + buf24ghz + size24ghz, + BUF24GHZSIZE - size24ghz, " %d", + pchannelset->first_chan_freq); + qdf_mem_free(pchannelset); + } + } else { + /* 5GHz info found */ + if (!f5GListPurged) { + /* purge previous results if found new */ + csr_purge_channel_power(mac, + &mac->scan. + channelPowerInfoList5G); + f5GListPurged = true; + } + if (CSR_IS_OPERATING_A_BAND(mac)) { + /* add to the list of 5GHz channel sets */ + csr_ll_insert_tail(&mac->scan. + channelPowerInfoList5G, + &pchannelset->link, + LL_ACCESS_LOCK); + } else { + size5ghz += qdf_scnprintf( + buf5ghz + size5ghz, + BUF5GHZSIZE - size5ghz, " %d", + pchannelset->first_chan_freq); + qdf_mem_free(pchannelset); + } + } + pChannelInfo++; /* move to next entry */ + } + if (size24ghz) + sme_nofl_debug("Adding 11B/G ch in 11A:%s", buf24ghz); + qdf_mem_free(buf24ghz); + if (size5ghz) + sme_nofl_debug("Adding 11A ch in B/G:%s", buf5ghz); + qdf_mem_free(buf5ghz); + return QDF_STATUS_SUCCESS; +} +void csr_apply_power2_current(struct mac_context *mac) +{ + sme_debug("Updating Cfg with power settings"); + csr_save_tx_power_to_cfg(mac, &mac->scan.channelPowerInfoList24, + BAND_2G); + csr_save_tx_power_to_cfg(mac, &mac->scan.channelPowerInfoList5G, + BAND_5G); +} + +void csr_apply_channel_power_info_to_fw(struct mac_context *mac_ctx, + struct csr_channel *ch_lst) +{ + int i; + uint8_t num_ch = 0; + uint8_t tempNumChannels = 0; + struct csr_channel tmp_ch_lst; + + if (ch_lst->numChannels) { + tempNumChannels = QDF_MIN(ch_lst->numChannels, + CFG_VALID_CHANNEL_LIST_LEN); + for (i = 0; i < tempNumChannels; i++) { + tmp_ch_lst.channel_freq_list[num_ch] = ch_lst->channel_freq_list[i]; + num_ch++; + } + tmp_ch_lst.numChannels = num_ch; + /* Store the channel+power info in the global place: Cfg */ + csr_apply_power2_current(mac_ctx); + csr_set_cfg_valid_channel_list(mac_ctx, tmp_ch_lst.channel_freq_list, + tmp_ch_lst.numChannels); + } else { + sme_err("11D channel list is empty"); + } + sch_edca_profile_update_all(mac_ctx); +} + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +static void csr_diag_reset_country_information(struct mac_context *mac) +{ + + host_log_802_11d_pkt_type *p11dLog; + int Index; + uint8_t reg_cc[REG_ALPHA2_LEN + 1]; + + WLAN_HOST_DIAG_LOG_ALLOC(p11dLog, host_log_802_11d_pkt_type, + LOG_WLAN_80211D_C); + if (!p11dLog) + return; + + p11dLog->eventId = WLAN_80211D_EVENT_RESET; + wlan_reg_read_current_country(mac->psoc, reg_cc); + qdf_mem_copy(p11dLog->countryCode, reg_cc, 3); + p11dLog->numChannel = mac->scan.base_channels.numChannels; + if (p11dLog->numChannel <= HOST_LOG_MAX_NUM_CHANNEL) { + for (Index = 0; + Index < mac->scan.base_channels.numChannels; + Index++) { + p11dLog->Channels[Index] = + wlan_reg_freq_to_chan(mac->pdev, mac->scan.base_channels.channel_freq_list[Index]); + p11dLog->TxPwr[Index] = + mac->scan.defaultPowerTable[Index].tx_power; + } + } + + WLAN_HOST_DIAG_LOG_REPORT(p11dLog); +} +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + +/** + * csr_apply_channel_power_info_wrapper() - sends channel info to fw + * @mac: main MAC data structure + * + * This function sends the channel power info to firmware + * + * Return: none + */ +void csr_apply_channel_power_info_wrapper(struct mac_context *mac) +{ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + csr_diag_reset_country_information(mac); +#endif /* FEATURE_WLAN_DIAG_SUPPORT_CSR */ + csr_prune_channel_list_for_mode(mac, &mac->scan.base_channels); + csr_save_channel_power_for_band(mac, false); + csr_save_channel_power_for_band(mac, true); + /* apply the channel list, power settings, and the country code. */ + csr_apply_channel_power_info_to_fw(mac, &mac->scan.base_channels); + /* clear the 11d channel list */ + qdf_mem_zero(&mac->scan.channels11d, sizeof(mac->scan.channels11d)); +} + +void csr_save_channel_power_for_band(struct mac_context *mac, bool fill_5f) +{ + uint32_t idx, count = 0; + struct pwr_channel_info *chan_info; + struct pwr_channel_info *ch_info_start; + int32_t max_ch_idx; + bool tmp_bool; + uint32_t ch_freq = 0; + + max_ch_idx = + (mac->scan.base_channels.numChannels < + CFG_VALID_CHANNEL_LIST_LEN) ? + mac->scan.base_channels.numChannels : + CFG_VALID_CHANNEL_LIST_LEN; + + chan_info = qdf_mem_malloc(sizeof(struct pwr_channel_info) * + CFG_VALID_CHANNEL_LIST_LEN); + if (!chan_info) + return; + + ch_info_start = chan_info; + for (idx = 0; idx < max_ch_idx; idx++) { + ch_freq = mac->scan.defaultPowerTable[idx].center_freq; + tmp_bool = (fill_5f && WLAN_REG_IS_5GHZ_CH_FREQ(ch_freq)) || + (!fill_5f && WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)); + if (!tmp_bool) + continue; + + if (count >= CFG_VALID_CHANNEL_LIST_LEN) { + sme_warn("count: %d exceeded", count); + break; + } + + chan_info->first_freq = + mac->scan.defaultPowerTable[idx].center_freq; + chan_info->num_chan = 1; + chan_info->max_tx_pwr = + mac->scan.defaultPowerTable[idx].tx_power; + chan_info++; + count++; + } + if (count) { + csr_save_to_channel_power2_g_5_g(mac, + count * sizeof(struct pwr_channel_info), + ch_info_start); + } + qdf_mem_free(ch_info_start); +} + +bool csr_is_supported_channel(struct mac_context *mac, uint32_t chan_freq) +{ + bool fRet = false; + uint32_t i; + + for (i = 0; i < mac->scan.base_channels.numChannels; i++) { + if (chan_freq == mac->scan.base_channels.channel_freq_list[i]) { + fRet = true; + break; + } + } + + return fRet; +} + +tCsrScanResultInfo *csr_scan_result_get_first(struct mac_context *mac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry; + struct tag_csrscan_result *pResult; + tCsrScanResultInfo *pRet = NULL; + struct scan_result_list *pResultList = + (struct scan_result_list *) hScanResult; + + if (pResultList) { + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + if (pEntry) { + pResult = GET_BASE_ADDR(pEntry, struct + tag_csrscan_result, Link); + pRet = &pResult->Result; + } + pResultList->pCurEntry = pEntry; + } + + return pRet; +} + +tCsrScanResultInfo *csr_scan_result_get_next(struct mac_context *mac, + tScanResultHandle hScanResult) +{ + tListElem *pEntry = NULL; + struct tag_csrscan_result *pResult = NULL; + tCsrScanResultInfo *pRet = NULL; + struct scan_result_list *pResultList = + (struct scan_result_list *) hScanResult; + + if (!pResultList) + return NULL; + + if (!pResultList->pCurEntry) + pEntry = csr_ll_peek_head(&pResultList->List, LL_ACCESS_NOLOCK); + else + pEntry = csr_ll_next(&pResultList->List, pResultList->pCurEntry, + LL_ACCESS_NOLOCK); + + if (pEntry) { + pResult = GET_BASE_ADDR(pEntry, struct tag_csrscan_result, + Link); + pRet = &pResult->Result; + } + pResultList->pCurEntry = pEntry; + + return pRet; +} + +static void csr_set_cfg_valid_channel_list(struct mac_context *mac, + uint32_t *pchan_freq_list, + uint8_t NumChannels) +{ + QDF_STATUS status; + uint8_t i; + + sme_debug("dump valid channel list(NumChannels(%d))", NumChannels); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_DEBUG, + pchan_freq_list, NumChannels); + for (i = 0; i < NumChannels; i++) { + mac->mlme_cfg->reg.valid_channel_freq_list[i] = pchan_freq_list[i]; + } + + mac->mlme_cfg->reg.valid_channel_list_num = NumChannels; + + sme_debug("Scan offload is enabled, update default chan list"); + /* + * disable fcc constraint since new country code + * is being set + */ + mac->scan.fcc_constraint = false; + status = csr_update_channel_list(mac); + if (QDF_STATUS_SUCCESS != status) { + sme_err("failed to update the supported channel list"); + } +} + +/* + * The Tx power limits are saved in the cfg for future usage. + */ +static void csr_save_tx_power_to_cfg(struct mac_context *mac, + tDblLinkList *pList, + enum band_info band) +{ + tListElem *pEntry; + uint32_t cbLen = 0, dataLen, tmp_len; + struct csr_channel_powerinfo *ch_set; + uint32_t idx, count = 0; + struct pwr_channel_info *ch_pwr_set; + uint8_t *p_buf = NULL; + + /* allocate maximum space for all channels */ + dataLen = CFG_VALID_CHANNEL_LIST_LEN * sizeof(struct pwr_channel_info); + p_buf = qdf_mem_malloc(dataLen); + if (!p_buf) + return; + + ch_pwr_set = (struct pwr_channel_info *)(p_buf); + csr_ll_lock(pList); + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + /* + * write the tuples (startChan, numChan, txPower) for each channel found + * in the channel power list. + */ + while (pEntry) { + ch_set = GET_BASE_ADDR(pEntry, + struct csr_channel_powerinfo, link); + if (ch_set->interChannelOffset != 5) { + /* + * we keep the 5G channel sets internally with an + * interchannel offset of 4. Expand these to the right + * format. (inter channel offset of 1 is the only option + * for the triplets that 11d advertises. + */ + tmp_len = cbLen + (ch_set->numChannels * + sizeof(struct pwr_channel_info)); + if (tmp_len >= dataLen) { + /* + * expanding this entry will overflow our + * allocation + */ + sme_err( + "Buffer overflow, start freq %d, num %d, offset %d", + ch_set->first_chan_freq, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + + for (idx = 0; idx < ch_set->numChannels; idx++) { + ch_pwr_set->first_freq = + ch_set->first_chan_freq; + ch_pwr_set->num_chan = 1; + ch_pwr_set->max_tx_pwr = ch_set->txPower; + cbLen += sizeof(struct pwr_channel_info); + ch_pwr_set++; + count++; + } + } else { + if (cbLen + sizeof(struct pwr_channel_info) >= dataLen) { + /* this entry will overflow our allocation */ + sme_err( + "Buffer overflow, start freq %d, num %d, offset %d", + ch_set->first_chan_freq, + ch_set->numChannels, + ch_set->interChannelOffset); + break; + } + ch_pwr_set->first_freq = ch_set->first_chan_freq; + ch_pwr_set->num_chan = ch_set->numChannels; + ch_pwr_set->max_tx_pwr = ch_set->txPower; + cbLen += sizeof(struct pwr_channel_info); + ch_pwr_set++; + count++; + } + pEntry = csr_ll_next(pList, pEntry, LL_ACCESS_NOLOCK); + } + csr_ll_unlock(pList); + if (band == BAND_2G) { + mac->mlme_cfg->power.max_tx_power_24.len = + sizeof(struct pwr_channel_info) * count; + if (mac->mlme_cfg->power.max_tx_power_24.len > + CFG_MAX_TX_POWER_2_4_LEN) + mac->mlme_cfg->power.max_tx_power_24.len = + CFG_MAX_TX_POWER_2_4_LEN; + qdf_mem_copy(mac->mlme_cfg->power.max_tx_power_24.data, + (uint8_t *)p_buf, + mac->mlme_cfg->power.max_tx_power_24.len); + } + if (band == BAND_5G) { + mac->mlme_cfg->power.max_tx_power_5.len = + sizeof(struct pwr_channel_info) * count; + if (mac->mlme_cfg->power.max_tx_power_5.len > + CFG_MAX_TX_POWER_5_LEN) + mac->mlme_cfg->power.max_tx_power_5.len = + CFG_MAX_TX_POWER_5_LEN; + qdf_mem_copy(mac->mlme_cfg->power.max_tx_power_5.data, + (uint8_t *)p_buf, + mac->mlme_cfg->power.max_tx_power_5.len); + } + qdf_mem_free(p_buf); +} + +static void csr_fill_rsn_auth_type(enum csr_akm_type *auth_type, uint32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA384)) + *auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_FILS_SHA256)) + *auth_type = eCSR_AUTH_TYPE_FT_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA384)) + *auth_type = eCSR_AUTH_TYPE_FILS_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FILS_SHA256)) + *auth_type = eCSR_AUTH_TYPE_FILS_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE_EXT_KEY)) + *auth_type = eCSR_AUTH_TYPE_FT_SAE_EXT_KEY; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE_EXT_KEY)) + *auth_type = eCSR_AUTH_TYPE_SAE_EXT_KEY; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_SAE)) + *auth_type = eCSR_AUTH_TYPE_FT_SAE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_SAE)) + *auth_type = eCSR_AUTH_TYPE_SAE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_DPP)) + *auth_type = eCSR_AUTH_TYPE_DPP_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OSEN)) + *auth_type = eCSR_AUTH_TYPE_OSEN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_OWE)) + *auth_type = eCSR_AUTH_TYPE_OWE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X)) + *auth_type = eCSR_AUTH_TYPE_FT_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_PSK)) + *auth_type = eCSR_AUTH_TYPE_FT_RSN_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + *auth_type = eCSR_AUTH_TYPE_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + *auth_type = eCSR_AUTH_TYPE_RSN_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + *auth_type = eCSR_AUTH_TYPE_CCKM_RSN; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK_SHA256)) + *auth_type = eCSR_AUTH_TYPE_RSN_PSK_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SHA256)) + *auth_type = eCSR_AUTH_TYPE_RSN_8021X_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B)) + *auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA256; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X_SUITE_B_192)) + *auth_type = eCSR_AUTH_TYPE_SUITEB_EAP_SHA384; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_FT_IEEE8021X_SHA384)) + *auth_type = eCSR_AUTH_TYPE_FT_SUITEB_EAP_SHA384; + else + *auth_type = eCSR_AUTH_TYPE_NONE; +} + +static void csr_fill_wpa_auth_type(enum csr_akm_type *auth_type, uint32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_IEEE8021X)) + *auth_type = eCSR_AUTH_TYPE_WPA; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_PSK)) + *auth_type = eCSR_AUTH_TYPE_WPA_PSK; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_CCKM)) + *auth_type = eCSR_AUTH_TYPE_CCKM_WPA; + else + *auth_type = eCSR_AUTH_TYPE_WPA_NONE; +} + +static void csr_fill_wapi_auth_type(enum csr_akm_type *auth_type, uint32_t akm) +{ + /* Try the more preferred ones first. */ + if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_CERT)) + *auth_type = eCSR_AUTH_TYPE_WAPI_WAI_CERTIFICATE; + else if (QDF_HAS_PARAM(akm, WLAN_CRYPTO_KEY_MGMT_WAPI_PSK)) + *auth_type = eCSR_AUTH_TYPE_WAPI_WAI_PSK; + else + *auth_type = eCSR_AUTH_TYPE_NONE; +} + +void csr_fill_auth_type(enum csr_akm_type *auth_type, + uint32_t authmodeset, uint32_t akm, + uint32_t ucastcipherset) +{ + if (!authmodeset) { + *auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_NONE) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_OPEN)) { + *auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_AUTO)) { + if ((QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP) || + QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP_40) || + QDF_HAS_PARAM(ucastcipherset, WLAN_CRYPTO_CIPHER_WEP_104))) + *auth_type = eCSR_AUTH_TYPE_AUTOSWITCH; + else + *auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; + + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_SHARED)) { + *auth_type = eCSR_AUTH_TYPE_SHARED_KEY; + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_8021X) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_RSNA) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_CCKM) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_SAE) || + QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_FILS_SK)) { + csr_fill_rsn_auth_type(auth_type, akm); + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_WPA)) { + csr_fill_wpa_auth_type(auth_type, akm); + return; + } + + if (QDF_HAS_PARAM(authmodeset, WLAN_CRYPTO_AUTH_WAPI)) { + csr_fill_wapi_auth_type(auth_type, akm); + return; + } + + *auth_type = eCSR_AUTH_TYPE_OPEN_SYSTEM; +} + +void csr_fill_enc_type(eCsrEncryptionType *cipher_type, uint32_t cipherset) +{ + if (!cipherset) { + *cipher_type = eCSR_ENCRYPT_TYPE_NONE; + return; + } + if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GCM_256)) + *cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP_256; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GCM)) + *cipher_type = eCSR_ENCRYPT_TYPE_AES_GCMP; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CCM) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_OCB) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CCM_256)) + *cipher_type = eCSR_ENCRYPT_TYPE_AES; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_TKIP)) + *cipher_type = eCSR_ENCRYPT_TYPE_TKIP; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CMAC) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_CMAC_256)) + *cipher_type = eCSR_ENCRYPT_TYPE_AES_CMAC; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WAPI_GCM4) || + QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WAPI_SMS4)) + *cipher_type = eCSR_ENCRYPT_TYPE_WPI; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GMAC)) + *cipher_type = eCSR_ENCRYPT_TYPE_AES_GMAC_128; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_AES_GMAC_256)) + *cipher_type = eCSR_ENCRYPT_TYPE_AES_GMAC_256; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP)) + *cipher_type = eCSR_ENCRYPT_TYPE_WEP40; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP_40)) + *cipher_type = eCSR_ENCRYPT_TYPE_WEP40; + else if (QDF_HAS_PARAM(cipherset, WLAN_CRYPTO_CIPHER_WEP_104)) + *cipher_type = eCSR_ENCRYPT_TYPE_WEP104; + else + *cipher_type = eCSR_ENCRYPT_TYPE_NONE; +} + +static void csr_fill_neg_crypto_info(struct tag_csrscan_result *bss, + struct security_info *sec_info) +{ + if (!sec_info->authmodeset && !sec_info->key_mgmt && + !sec_info->ucastcipherset) + return; + + csr_fill_enc_type(&bss->ucEncryptionType, sec_info->ucastcipherset); + csr_fill_enc_type(&bss->mcEncryptionType, sec_info->mcastcipherset); + csr_fill_auth_type(&bss->authType, sec_info->authmodeset, + sec_info->key_mgmt, sec_info->ucastcipherset); + sme_debug("Authmode %x, AKM %x, Cipher Uc %x Mc %x CSR: Auth %d, Cipher Uc %d Mc %d", + sec_info->authmodeset, sec_info->key_mgmt, + sec_info->ucastcipherset, sec_info->mcastcipherset, + bss->authType, bss->ucEncryptionType, bss->mcEncryptionType); +} + +static QDF_STATUS csr_fill_bss_from_scan_entry(struct mac_context *mac_ctx, + struct scan_cache_entry *scan_entry, + struct tag_csrscan_result **p_result) +{ + tDot11fBeaconIEs *bcn_ies; + struct bss_description *bss_desc; + tCsrScanResultInfo *result_info; + uint8_t *ie_ptr; + struct tag_csrscan_result *bss; + uint32_t bss_len, alloc_len, ie_len; + QDF_STATUS status; + enum channel_state ap_channel_state; + + ap_channel_state = + wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, + scan_entry->channel.chan_freq, + REG_CURRENT_PWR_MODE); + if (ap_channel_state == CHANNEL_STATE_DISABLE || + ap_channel_state == CHANNEL_STATE_INVALID) { + sme_err("BSS "QDF_MAC_ADDR_FMT" channel %d invalid, not populating this BSSID", + QDF_MAC_ADDR_REF(scan_entry->bssid.bytes), + scan_entry->channel.chan_freq); + return QDF_STATUS_E_INVAL; + } + + ie_len = util_scan_entry_ie_len(scan_entry); + ie_ptr = util_scan_entry_ie_data(scan_entry); + + bss_len = (uint16_t)(offsetof(struct bss_description, + ieFields[0]) + ie_len); + alloc_len = sizeof(struct tag_csrscan_result) + bss_len; + bss = qdf_mem_malloc(alloc_len); + if (!bss) + return QDF_STATUS_E_NOMEM; + + csr_fill_neg_crypto_info(bss, &scan_entry->neg_sec_info); + + result_info = &bss->Result; + result_info->ssId.length = scan_entry->ssid.length; + qdf_mem_copy(result_info->ssId.ssId, + scan_entry->ssid.ssid, + result_info->ssId.length); + result_info->timer = scan_entry->hidden_ssid_timestamp; + + bss_desc = &result_info->BssDescriptor; + + wlan_fill_bss_desc_from_scan_entry(mac_ctx, bss_desc, scan_entry); + + status = wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + &bcn_ies); + if (QDF_IS_STATUS_ERROR(status)) { + qdf_mem_free(bss); + return status; + } + result_info->pvIes = bcn_ies; + + *p_result = bss; + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS csr_parse_scan_list(struct mac_context *mac_ctx, + struct scan_result_list *ret_list, + qdf_list_t *scan_list) +{ + struct tag_csrscan_result *pResult = NULL; + struct scan_cache_node *cur_node = NULL; + struct scan_cache_node *next_node = NULL; + + qdf_list_peek_front(scan_list, (qdf_list_node_t **) &cur_node); + + while (cur_node) { + qdf_list_peek_next(scan_list, (qdf_list_node_t *) cur_node, + (qdf_list_node_t **) &next_node); + pResult = NULL; + csr_fill_bss_from_scan_entry(mac_ctx, + cur_node->entry, &pResult); + if (pResult) + csr_ll_insert_tail(&ret_list->List, &pResult->Link, + LL_ACCESS_NOLOCK); + cur_node = next_node; + next_node = NULL; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_scan_get_result(struct mac_context *mac_ctx, + struct scan_filter *filter, + tScanResultHandle *results) +{ + QDF_STATUS status; + struct scan_result_list *ret_list = NULL; + qdf_list_t *list = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + uint32_t num_bss = 0; + + if (results) + *results = CSR_INVALID_SCANRESULT_HANDLE; + + pdev = wlan_objmgr_get_pdev_by_id(mac_ctx->psoc, + 0, WLAN_LEGACY_MAC_ID); + if (!pdev) { + sme_err("pdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + list = wlan_scan_get_result(pdev, filter); + if (list) { + num_bss = qdf_list_size(list); + sme_debug("num_entries %d", num_bss); + } + + if (!list || (list && !qdf_list_size(list))) { + sme_debug("scan list empty"); + if (num_bss) + status = QDF_STATUS_E_EXISTS; + else + status = QDF_STATUS_E_NULL_VALUE; + goto error; + } + + ret_list = qdf_mem_malloc(sizeof(struct scan_result_list)); + if (!ret_list) { + status = QDF_STATUS_E_NOMEM; + goto error; + } + + csr_ll_open(&ret_list->List); + ret_list->pCurEntry = NULL; + status = csr_parse_scan_list(mac_ctx, ret_list, list); + if (QDF_IS_STATUS_ERROR(status) || !results) + /* Fail or No one wants the result. */ + csr_scan_result_purge(mac_ctx, (tScanResultHandle) ret_list); + else { + if (!csr_ll_count(&ret_list->List)) { + /* This mean that there is no match */ + csr_ll_close(&ret_list->List); + qdf_mem_free(ret_list); + /* + * Do not trigger scan for ssid if the scan entries + * are removed either due to rssi reject or assoc + * disallowed. + */ + if (num_bss) + status = QDF_STATUS_E_EXISTS; + else + status = QDF_STATUS_E_NULL_VALUE; + } else if (results) { + *results = ret_list; + } + } + +error: + if (list) + wlan_scan_purge_results(list); + if (pdev) + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + + return status; +} + +QDF_STATUS csr_scan_get_result_for_bssid(struct mac_context *mac_ctx, + struct qdf_mac_addr *bssid, + qdf_list_t **ret_list) +{ + struct scan_filter *scan_filter; + qdf_list_t *list = NULL; + + *ret_list = NULL; + scan_filter = qdf_mem_malloc(sizeof(*scan_filter)); + if (!scan_filter) + return QDF_STATUS_E_NOMEM; + + scan_filter->num_of_bssid = 1; + qdf_mem_copy(scan_filter->bssid_list[0].bytes, bssid->bytes, + QDF_MAC_ADDR_SIZE); + scan_filter->ignore_auth_enc_type = true; + + list = wlan_scan_get_result(mac_ctx->pdev, scan_filter); + qdf_mem_free(scan_filter); + if (!list || (list && !qdf_list_size(list))) + goto purge_list; + + *ret_list = list; + return QDF_STATUS_SUCCESS; + +purge_list: + if (list) + wlan_scan_purge_results(list); + + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS csr_scan_filter_results(struct mac_context *mac_ctx) +{ + uint32_t len = mac_ctx->mlme_cfg->reg.valid_channel_list_num; + struct wlan_objmgr_pdev *pdev = NULL; + uint32_t i, valid_chan_len = 0; + uint32_t ch_freq; + uint32_t valid_ch_freq_list[CFG_VALID_CHANNEL_LIST_LEN]; + + pdev = wlan_objmgr_get_pdev_by_id(mac_ctx->psoc, + 0, WLAN_LEGACY_MAC_ID); + if (!pdev) { + sme_err("pdev is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* This is a temporary conversion till the scm handles freq */ + for (i = 0; i < len; i++) { + if (wlan_reg_is_dsrc_freq( + mac_ctx->mlme_cfg->reg.valid_channel_freq_list[i])) + continue; + ch_freq = mac_ctx->mlme_cfg->reg.valid_channel_freq_list[i]; + valid_ch_freq_list[valid_chan_len++] = ch_freq; + } + sme_debug("No of valid channel %d", valid_chan_len); + + ucfg_scan_filter_valid_channel(pdev, valid_ch_freq_list, + valid_chan_len); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_MAC_ID); + + return QDF_STATUS_SUCCESS; +} + +void csr_update_beacon(struct mac_context *mac) +{ + struct scheduler_msg msg = { 0 }; + QDF_STATUS status; + + msg.type = SIR_LIM_UPDATE_BEACON; + status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (status != QDF_STATUS_SUCCESS) + sme_err("scheduler_post_message failed, status = %u", status); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c new file mode 100644 index 0000000000..183ea4f182 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_cmd_process.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: csr_cmd_process.c + * + * Implementation for processing various commands. + */ +#include "ani_global.h" +#include "csr_inside_api.h" +#include "sme_inside.h" +#include "mac_trace.h" + +/** + * csr_msg_processor() - To process all csr msg + * @mac_ctx: mac context + * @msg_buf: message buffer + * + * This routine will handle all the message for csr to process + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_msg_processor(struct mac_context *mac_ctx, void *msg_buf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tSirSmeRsp *sme_rsp = (tSirSmeRsp *) msg_buf; + uint8_t vdev_id = sme_rsp->vdev_id; + enum csr_roam_state cur_state; + + cur_state = sme_get_current_roam_state(MAC_HANDLE(mac_ctx), vdev_id); + sme_debug("msg %d[0x%04X] recvd in curstate %s & substate %s id(%d)", + sme_rsp->messageType, sme_rsp->messageType, + mac_trace_getcsr_roam_state(cur_state), + mac_trace_getcsr_roam_sub_state( + mac_ctx->roam.curSubState[vdev_id]), vdev_id); + + /* Process the message based on the state of the roaming states... */ + switch (cur_state) { + case eCSR_ROAMING_STATE_JOINED: + /* are we in joined state */ + csr_roam_joined_state_msg_processor(mac_ctx, msg_buf); + break; + case eCSR_ROAMING_STATE_JOINING: + /* are we in roaming states */ + csr_roaming_state_msg_processor(mac_ctx, msg_buf); + break; + + default: + + if (sme_rsp->messageType == + eWNI_SME_UPPER_LAYER_ASSOC_CNF) { + tSirSmeAssocIndToUpperLayerCnf *upper_layer_assoc_cnf = + (tSirSmeAssocIndToUpperLayerCnf *)msg_buf; + if (upper_layer_assoc_cnf->ies) { + qdf_mem_free(upper_layer_assoc_cnf->ies); + sme_debug("free ies"); + } + break; + } + + /* + * For all other messages, we ignore it + * To work-around an issue where checking for set/remove + * key base on connection state is no longer workable + * due to failure or finding the condition meets both + * SAP and infra requirement. + */ + if (eWNI_SME_SETCONTEXT_RSP == sme_rsp->messageType || + eWNI_SME_DISCONNECT_DONE_IND == + sme_rsp->messageType) { + sme_warn("handling msg 0x%X CSR state is %d", + sme_rsp->messageType, cur_state); + csr_roam_check_for_link_status_change(mac_ctx, + sme_rsp); + } else { + sme_err("Message 0x%04X is not handled by CSR state is %d session Id %d", + sme_rsp->messageType, cur_state, + vdev_id); + } + break; + } /* switch */ + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_inside_api.h b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_inside_api.h new file mode 100644 index 0000000000..866a2d35ab --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_inside_api.h @@ -0,0 +1,595 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: csr_inside_api.h + * + * Define interface only used by CSR. + */ +#ifndef CSR_INSIDE_API_H__ +#define CSR_INSIDE_API_H__ + +#include "csr_support.h" +#include "sme_inside.h" +#include "cds_reg_service.h" +#include "wlan_objmgr_vdev_obj.h" + +bool csr_is_supported_channel(struct mac_context *mac, uint32_t chan_freq); + +enum csr_sap_response_type { + CSR_SAP_START_BSS_SUCCESS, + CSR_SAP_START_BSS_FAILURE, + CSR_SAP_STOP_BSS_SUCCESS, + CSR_SAP_STOP_BSS_FAILURE, +}; + +struct tag_csrscan_result { + tListElem Link; + /* Preferred Encryption type that matched with profile. */ + eCsrEncryptionType ucEncryptionType; + eCsrEncryptionType mcEncryptionType; + /* Preferred auth type that matched with the profile. */ + enum csr_akm_type authType; + + tCsrScanResultInfo Result; + /* + * WARNING - Do not add any element here + * This member Result must be the last in the structure because the end + * of struct bss_description (inside) is an array with nonknown size at + * this time. + */ +}; + +struct scan_result_list { + tDblLinkList List; + tListElem *pCurEntry; +}; + +#define CSR_IS_WAIT_FOR_KEY(mac, sessionId) \ + (CSR_IS_ROAM_JOINED(mac, sessionId) && \ + CSR_IS_ROAM_SUBSTATE_WAITFORKEY(mac, sessionId)) + +enum csr_roam_state csr_roam_state_change(struct mac_context *mac, + enum csr_roam_state NewRoamState, + uint8_t sessionId); +void csr_roaming_state_msg_processor(struct mac_context *mac, void *msg_buf); +void csr_roam_joined_state_msg_processor(struct mac_context *mac, + void *msg_buf); + +void csr_release_command_roam(struct mac_context *mac, tSmeCmd *pCommand); +void csr_release_command_wm_status_change(struct mac_context *mac, + tSmeCmd *pCommand); +QDF_STATUS csr_scan_open(struct mac_context *mac); +QDF_STATUS csr_scan_close(struct mac_context *mac); + +void csr_free_scan_result_entry(struct mac_context *mac, struct tag_csrscan_result + *pResult); + +QDF_STATUS csr_roam_call_callback(struct mac_context *mac, uint32_t sessionId, + struct csr_roam_info *roam_info, + eRoamCmdStatus u1, eCsrRoamResult u2); +void csr_roam_complete(struct mac_context *mac, uint8_t session_id); + +/** + * csr_issue_set_context_req_helper - Function to fill unicast/broadcast keys + * request to set the keys to fw + * @mac_ctx: Pointer to mac context + * @vdev_id: vdev id + * @bssid: Connected BSSID + * @addkey: Is add key request to crypto + * @unicast: Unicast(1) or broadcast key(0) + * @key_id: Key index + * + * Return: QDF_STATUS + */ +QDF_STATUS +csr_issue_set_context_req_helper(struct mac_context *mac_ctx, + uint32_t vdev_id, tSirMacAddr *bssid, + bool addkey, bool unicast, uint8_t key_id); + +void csr_roam_check_for_link_status_change(struct mac_context *mac, + tSirSmeRsp *pSirMsg); +QDF_STATUS csr_send_mb_disassoc_req_msg(struct mac_context *mac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +QDF_STATUS csr_send_mb_deauth_req_msg(struct mac_context *mac, uint32_t sessionId, + tSirMacAddr bssId, uint16_t reasonCode); +QDF_STATUS csr_send_mb_disassoc_cnf_msg(struct mac_context *mac, + struct disassoc_ind *pDisassocInd); +QDF_STATUS csr_send_mb_deauth_cnf_msg(struct mac_context *mac, + struct deauth_ind *pDeauthInd); +QDF_STATUS csr_send_assoc_cnf_msg(struct mac_context *mac, + struct assoc_ind *pAssocInd, + QDF_STATUS status, + enum wlan_status_code mac_status_code); +/** + * csr_get_cfg_valid_channels() - Get valid channel frequency list + * @mac: mac context + * @ch_freq_list: valid channel frequencies + * @num_ch_freq: valid channel number + * + * This function returns the valid channel frequencies. + * + * Return: QDF_STATUS_SUCCESS for success. + */ +QDF_STATUS csr_get_cfg_valid_channels(struct mac_context *mac, + uint32_t *ch_freq_list, + uint32_t *num_ch_freq); + +enum csr_cfgdot11mode +csr_get_cfg_dot11_mode_from_csr_phy_mode(bool is_ap, eCsrPhyMode phyMode); + +uint32_t csr_translate_to_wni_cfg_dot11_mode(struct mac_context *mac, + enum csr_cfgdot11mode csrDot11Mode); +void csr_save_channel_power_for_band(struct mac_context *mac, bool fPopulate5GBand); +void csr_apply_channel_power_info_to_fw(struct mac_context *mac, + struct csr_channel *pChannelList); +void csr_apply_power2_current(struct mac_context *mac); +void csr_apply_channel_power_info_wrapper(struct mac_context *mac); +QDF_STATUS csr_save_to_channel_power2_g_5_g(struct mac_context *mac, + uint32_t tableSize, + struct pwr_channel_info *channelTable); + +/* + * csr_prepare_vdev_delete() - CSR api to delete vdev + * @mac_ctx: pointer to mac context + * @vdev: vdev object to be prepared for deletion. + * + * Return QDF_STATUS + */ +QDF_STATUS csr_prepare_vdev_delete(struct mac_context *mac_ctx, + struct wlan_objmgr_vdev *vdev); + +/* + * csr_cleanup_vdev_session() - CSR api to cleanup vdev + * @mac_ctx: pointer to mac context + * @vdev_id: vdev id to be deleted. + * + * This API is used to clean up vdev information gathered during + * vdev was enabled. + * + * Return QDF_STATUS + */ +void csr_cleanup_vdev_session(struct mac_context *mac, uint8_t vdev_id); + +QDF_STATUS csr_roam_get_session_id_from_bssid(struct mac_context *mac, + struct qdf_mac_addr *bssid, + uint32_t *pSessionId); + +/* + * csr_scan_get_result() - Return scan results based on filter + * @mac: Pointer to Global MAC structure + * @filter: If pFilter is NULL, all cached results are returned + * @phResult: an object for the result. + * + * Return QDF_STATUS + */ +QDF_STATUS csr_scan_get_result(struct mac_context *mac, + struct scan_filter *filter, + tScanResultHandle *phResult); + +/** + * csr_scan_get_result_for_bssid - gets the scan result from scan cache for the + * bssid specified + * @mac_ctx: mac context + * @bssid: bssid to get the scan result for + * @ret_list: pointer to scan results + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_scan_get_result_for_bssid(struct mac_context *mac_ctx, + struct qdf_mac_addr *bssid, + qdf_list_t **ret_list); + +/** + * csr_scan_filter_results: filter scan result based + * on valid channel list number. + * @mac_ctx: mac context + * + * Get scan result from scan list and Check Scan result channel number + * with 11d channel list if channel number is found in 11d channel list + * then do not remove scan result entry from scan list + * + * return: QDF Status + */ +QDF_STATUS csr_scan_filter_results(struct mac_context *mac); + +/* + * csr_scan_result_get_first + * Returns the first element of scan result. + * + * hScanResult - returned from csr_scan_get_result + * tCsrScanResultInfo * - NULL if no result + */ +tCsrScanResultInfo *csr_scan_result_get_first(struct mac_context *mac, + tScanResultHandle hScanResult); +/* + * csr_scan_result_get_next + * Returns the next element of scan result. It can be called without calling + * csr_scan_result_get_first first + * + * hScanResult - returned from csr_scan_get_result + * Return Null if no result or reach the end + */ +tCsrScanResultInfo *csr_scan_result_get_next(struct mac_context *mac, + tScanResultHandle hScanResult); + +/* some support functions */ +bool csr_is11h_supported(struct mac_context *mac); +bool csr_is_wmm_supported(struct mac_context *mac); + +/* Return SUCCESS is the command is queued, failed */ +QDF_STATUS csr_queue_sme_command(struct mac_context *mac, tSmeCmd *pCommand, + bool fHighPriority); +tSmeCmd *csr_get_command_buffer(struct mac_context *mac); +void csr_release_command(struct mac_context *mac, tSmeCmd *pCommand); +void csr_release_command_buffer(struct mac_context *mac, tSmeCmd *pCommand); + +/** + * csr_get_vdev_type_nss() - gets the nss value based on vdev type + * @dev_mode: current device operating mode. + * @nss2g: Pointer to the 2G Nss parameter. + * @nss5g: Pointer to the 5G Nss parameter. + * + * Fills the 2G and 5G Nss values based on device mode. + * + * Return: None + */ +void csr_get_vdev_type_nss(enum QDF_OPMODE dev_mode, uint8_t *nss_2g, + uint8_t *nss_5g); + +/** + * csr_send_set_ie - Send Set IE request to lim + * @type: Vdev type + * @sub_type: Vdev sub type + * @vdev_id: Vdev id + * + * Return: None + */ +void csr_send_set_ie(uint8_t type, uint8_t sub_type, uint8_t vdev_id); +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR + +/* Security */ +#define WLAN_SECURITY_EVENT_MIC_ERROR 9 +#define WLAN_SECURITY_EVENT_SET_UNICAST_RSP 11 +#define WLAN_SECURITY_EVENT_SET_BCAST_RSP 13 + +#define WLAN_SECURITY_STATUS_SUCCESS 0 +#define WLAN_SECURITY_STATUS_FAILURE 1 + +/* 11d */ +#define WLAN_80211D_EVENT_RESET 1 +#endif /* #ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR */ +/* + * csr_scan_result_purge() - + * Remove all items(tCsrScanResult) in the list and free memory for each item + * hScanResult - returned from csr_scan_get_result. hScanResult is considered + * gone by calling this function and even before this function returns. + * Return QDF_STATUS + */ +QDF_STATUS csr_scan_result_purge(struct mac_context *mac, + tScanResultHandle hScanResult); + +/* /////////////////////////////////////////Common Scan ends */ +/** + * csr_bss_start() - CSR API to post the start bss request to serialization + * module. + * @mac: mac context + * @vdev_id: vdev id + * @bss_config: start bss config + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_bss_start(struct mac_context *mac, uint32_t vdev_id, + struct start_bss_config *bss_config); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/* + * csr_get_pmk_info(): store PMK in pmk_cache + * @mac_ctx: pointer to global structure for MAC + * @session_id: Sme session id + * @pmk_cache: pointer to a structure of Pmk + * + * This API gets the PMK from the session and + * stores it in the pmk_cache + * + * Return: none + */ +void csr_get_pmk_info(struct mac_context *mac_ctx, uint8_t session_id, + struct wlan_crypto_pmksa *pmk_cache); + +/* + * csr_roam_set_psk_pmk() - store PSK/PMK in CSR session + * @mac - pointer to global structure for MAC + * @pmksa: PMKSA entry + * @vdev_id - vdev id + * @update_to_fw - Send RSO update config command to firmware to update + * PMK + * + * Return QDF_STATUS - usually it succeed unless sessionId is not found + */ +QDF_STATUS csr_roam_set_psk_pmk(struct mac_context *mac, + struct wlan_crypto_pmksa *pmksa, + uint8_t vdev_id, bool update_to_fw); + +/** + * csr_set_pmk_cache_ft() - store MDID in PMK cache + * + * @mac - pointer to global structure for MAC + * @session_id - Sme session id + * @pmk_cache: pointer to a structure of PMK + * + * Return QDF_STATUS - usually it succeed unless session_id is not found + */ +QDF_STATUS csr_set_pmk_cache_ft(struct mac_context *mac, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmk_cache); +#endif + +/* + * csr_apply_channel_and_power_list() - + * HDD calls this function to set the CFG_VALID_CHANNEL_LIST base on the + * band/mode settings. This function must be called after CFG is downloaded + * and all the band/mode setting already passed into CSR. + + * Return QDF_STATUS + */ +QDF_STATUS csr_apply_channel_and_power_list(struct mac_context *mac); + +/* + * csr_roam_ndi_stop() - stop ndi + * @mac: pointer to mac context + * @vdev_id: vdev ID + * + * Return QDF_STATUS + */ +QDF_STATUS csr_roam_ndi_stop(struct mac_context *mac, uint8_t vdev_id); + +/** + * csr_roam_issue_stop_bss_cmd() - This API posts the stop bss command + * to the serialization module. + * + * @mac: Global mac context + * @vdev_id: Vdev id + * @bss_type: BSS type + * + * Return : QDF_STATUS + */ +QDF_STATUS csr_roam_issue_stop_bss_cmd(struct mac_context *mac, uint8_t vdev_id, + eCsrRoamBssType bss_type); + +/** + * csr_roam_issue_disassociate_sta_cmd() - disassociate a associated station + * @mac: Pointer to global structure for MAC + * @vdev_id: vdev Id for Soft AP + * @del_sta_params: Pointer to parameters of the station to disassoc + * + * CSR function that HDD calls to issue a deauthenticate station command + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_* on error + */ +QDF_STATUS +csr_roam_issue_disassociate_sta_cmd(struct mac_context *mac, + uint8_t vdev_id, + struct csr_del_sta_params *del_sta_params); +/** + * csr_roam_issue_deauth_sta_cmd() - issue deauthenticate station command + * @mac: Pointer to global structure for MAC + * @vdev_id: vdev Id for Soft AP + * @del_sta_params: Pointer to parameters of the station to deauthenticate + * + * CSR function that HDD calls to issue a deauthenticate station command + * + * Return: QDF_STATUS_SUCCESS on success or another QDF_STATUS_** on error + */ +QDF_STATUS +csr_roam_issue_deauth_sta_cmd(struct mac_context *mac, + uint8_t vdev_id, + struct csr_del_sta_params *del_sta_params); + +/* + * csr_send_chng_mcc_beacon_interval() - + * csr function that HDD calls to send Update beacon interval + * + * sessionId - session Id for Soft AP + * Return QDF_STATUS + */ +QDF_STATUS +csr_send_chng_mcc_beacon_interval(struct mac_context *mac, uint32_t sessionId); + +#ifdef FEATURE_WLAN_ESE +void csr_update_prev_ap_info(struct csr_roam_session *session, + struct wlan_objmgr_vdev *vdev); + +#else +static inline void csr_update_prev_ap_info(struct csr_roam_session *session, + struct wlan_objmgr_vdev *vdev) {} +#endif + +QDF_STATUS csr_update_channel_list(struct mac_context *mac); + +#if defined(WLAN_SAE_SINGLE_PMK) && defined(WLAN_FEATURE_ROAM_OFFLOAD) +/** + * csr_clear_sae_single_pmk - API to clear single_pmk_info cache + * @psoc: psoc common object + * @vdev_id: session id + * @pmksa: pmk info + * + * Return : None + */ +void csr_clear_sae_single_pmk(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, struct wlan_crypto_pmksa *pmksa); +#else +static inline void +csr_clear_sae_single_pmk(struct wlan_objmgr_psoc *psoc, uint8_t vdev_id, + struct wlan_crypto_pmksa *pmksa) +{ +} +#endif + +QDF_STATUS csr_send_ext_change_freq(struct mac_context *mac_ctx, + qdf_freq_t ch_freq, uint8_t session_id); + +/** + * csr_csa_start() - request CSA IE transmission from PE + * @mac_ctx: handle returned by mac_open + * @session_id: SAP session id + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_csa_restart(struct mac_context *mac_ctx, uint8_t session_id); + +/** + * csr_sta_continue_csa() - Continue for CSA for STA after HW mode change + * @mac_ctx: handle returned by mac_open + * @vdev_id: STA VDEV ID + * + * Return: QDF_STATUS + */ +QDF_STATUS csr_sta_continue_csa(struct mac_context *mac_ctx, + uint8_t vdev_id); + +#ifdef QCA_HT_2040_COEX +QDF_STATUS csr_set_ht2040_mode(struct mac_context *mac, uint32_t sessionId, + ePhyChanBondState cbMode, bool obssEnabled); +#endif + +void csr_prune_channel_list_for_mode(struct mac_context *mac, + struct csr_channel *pChannelList); + +/** + * csr_is_pmkid_found_for_peer() - check if pmkid sent by peer is present + in PMK cache. Used in SAP mode. + * @mac: pointer to mac + * @session: sme session pointer + * @peer_mac_addr: mac address of the connecting peer + * @pmkid: pointer to pmkid(s) send by peer + * @pmkid_count: number of pmkids sent by peer + * + * Return: true if pmkid is found else false + */ +bool csr_is_pmkid_found_for_peer(struct mac_context *mac, + struct csr_roam_session *session, + tSirMacAddr peer_mac_addr, + uint8_t *pmkid, uint16_t pmkid_count); +#ifdef WLAN_FEATURE_11BE + +/** + * csr_update_session_eht_cap() - update sme session eht capabilities + * @mac_ctx: pointer to mac + * @session: sme session pointer + * + * Return: None + */ +void csr_update_session_eht_cap(struct mac_context *mac_ctx, + struct csr_roam_session *session); +#else +static inline void csr_update_session_eht_cap(struct mac_context *mac_ctx, + struct csr_roam_session *session) +{ +} +#endif + +#ifdef WLAN_FEATURE_11AX +void csr_update_session_he_cap(struct mac_context *mac_ctx, + struct csr_roam_session *session); +#else +static inline void csr_update_session_he_cap(struct mac_context *mac_ctx, + struct csr_roam_session *session) +{ +} +#endif + +/** + * csr_setup_vdev_session() - API to setup vdev mac session + * @vdev_mlme: vdev mlme private object + * + * This API setsup the vdev session for the mac layer + * + * Returns: QDF_STATUS + */ +QDF_STATUS csr_setup_vdev_session(struct vdev_mlme_obj *vdev_mlme); + + +#ifdef WLAN_UNIT_TEST +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR +/** + * csr_cm_get_sta_cxn_info() - This function populates all the connection + * information which is formed by DUT-STA to AP + * @mac_ctx: pointer to mac context + * @vdev_id: vdev id + * @buf: pointer to char buffer to write all the connection information. + * @buf_size: maximum size of the provided buffer + * + * Returns: None (information gets populated in buffer) + */ +void csr_cm_get_sta_cxn_info(struct mac_context *mac_ctx, uint8_t vdev_id, + char *buf, uint32_t buf_sz); + +#endif +#endif + +/** + * csr_process_sap_response() - Wrapper API to process the SAP + * response from LIM + * @mac_ctx: mac context + * @result: Response status of LIM processing + * @context: Response from LIM + * @session_id: vdev id + * + * Return: void + */ +void csr_process_sap_response(struct mac_context *mac, + enum csr_sap_response_type result, + void *context, uint8_t session_id); + +/** + * csr_roam_roaming_state_start_bss_rsp_processor() - Handles start bss + * response from LIM + * + * @mac: mac context + * @msg: start bss response pointer + * + * Return: void + */ +void +csr_roam_roaming_state_start_bss_rsp_processor(struct mac_context *mac, + void *msg); + +/** + * csr_roam_roaming_state_stop_bss_rsp_processor() - Handles stop bss + * response from LIM + * + * @mac: mac context + * @msg: stop bss response pointer + * + * Return: void + */ +void csr_roam_roaming_state_stop_bss_rsp_processor(struct mac_context *mac, + void *msg); + +/** + * csr_roam_process_results_default() - Process the result for start bss + * @mac_ctx: Global MAC Context + * @cmd: Command to be processed + * + * Return: None + */ +void +csr_roam_process_results_default(struct mac_context *mac_ctx, tSmeCmd *cmd); + +#endif /* CSR_INSIDE_API_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_link_list.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_link_list.c new file mode 100644 index 0000000000..ca304c1327 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_link_list.c @@ -0,0 +1,509 @@ +/* + * Copyright (c) 2011-2012, 2014-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: csr_link_list.c + * + * Implementation for the Common link list interfaces. + */ +#include "csr_link_list.h" +#include "qdf_lock.h" +#include "qdf_mem.h" +#include "qdf_trace.h" +#include "qdf_mc_timer.h" +#include "sme_api.h" + +static inline void csr_list_init(tListElem *pList) +{ + pList->last = pList->next = pList; +} + +static inline void csr_list_remove_entry(tListElem *pEntry) +{ + tListElem *pLast; + tListElem *pNext; + + pLast = pEntry->last; + pNext = pEntry->next; + pLast->next = pNext; + pNext->last = pLast; +} + +static inline tListElem *csr_list_remove_head(tListElem *pHead) +{ + tListElem *pEntry; + tListElem *pNext; + + pEntry = pHead->next; + pNext = pEntry->next; + pHead->next = pNext; + pNext->last = pHead; + + return pEntry; +} + +static inline tListElem *csr_list_remove_tail(tListElem *pHead) +{ + tListElem *pEntry; + tListElem *pLast; + + pEntry = pHead->last; + pLast = pEntry->last; + pHead->last = pLast; + pLast->next = pHead; + + return pEntry; +} + +static inline void csr_list_insert_tail(tListElem *pHead, tListElem *pEntry) +{ + tListElem *pLast; + + pLast = pHead->last; + pEntry->last = pLast; + pEntry->next = pHead; + pLast->next = pEntry; + pHead->last = pEntry; +} + +static inline void csr_list_insert_head(tListElem *pHead, tListElem *pEntry) +{ + tListElem *pNext; + + pNext = pHead->next; + pEntry->next = pNext; + pEntry->last = pHead; + pNext->last = pEntry; + pHead->next = pEntry; +} + +/* Insert pNewEntry before pEntry */ +static void csr_list_insert_entry(tListElem *pEntry, tListElem *pNewEntry) +{ + tListElem *pLast; + + if (!pEntry) { + sme_err("Error!! pEntry is Null"); + return; + } + + pLast = pEntry->last; + pLast->next = pNewEntry; + pEntry->last = pNewEntry; + pNewEntry->next = pEntry; + pNewEntry->last = pLast; +} + +uint32_t csr_ll_count(tDblLinkList *pList) +{ + uint32_t c = 0; + + if (!pList) { + sme_err("Error!! pList is Null"); + return c; + } + + if (pList && (LIST_FLAG_OPEN == pList->Flag)) + c = pList->Count; + + return c; +} + +void csr_ll_lock(tDblLinkList *pList) +{ + + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) + qdf_mutex_acquire(&pList->Lock); +} + +void csr_ll_unlock(tDblLinkList *pList) +{ + + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) + qdf_mutex_release(&pList->Lock); +} + +bool csr_ll_is_list_empty(tDblLinkList *pList, bool fInterlocked) +{ + bool fEmpty = true; + + if (!pList) { + sme_err("Error!! pList is Null"); + return fEmpty; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + fEmpty = csrIsListEmpty(&pList->ListHead); + + if (fInterlocked) + csr_ll_unlock(pList); + } + return fEmpty; +} + +bool csr_ll_find_entry(tDblLinkList *pList, tListElem *pEntryToFind) +{ + bool fFound = false; + tListElem *pEntry; + + if (!pList) { + sme_err("Error!! pList is Null"); + return fFound; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* Have to make sure we don't loop back to the head of the list, + * which will happen if the entry is NOT on the list. + */ + + while (pEntry && (pEntry != &pList->ListHead)) { + if (pEntry == pEntryToFind) { + fFound = true; + break; + } + pEntry = pEntry->next; + } + + } + return fFound; +} + +QDF_STATUS csr_ll_open(tDblLinkList *pList) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + QDF_STATUS qdf_status; + + if (!pList) { + sme_err("Error!! pList is Null"); + return QDF_STATUS_E_FAILURE; + } + + if (LIST_FLAG_OPEN != pList->Flag) { + pList->Count = 0; + qdf_status = qdf_mutex_create(&pList->Lock); + + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + csr_list_init(&pList->ListHead); + pList->Flag = LIST_FLAG_OPEN; + } else + status = QDF_STATUS_E_FAILURE; + } + return status; +} + +void csr_ll_close(tDblLinkList *pList) +{ + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + /* Make sure the list is empty... */ + csr_ll_purge(pList, LL_ACCESS_LOCK); + qdf_mutex_destroy(&pList->Lock); + pList->Flag = LIST_FLAG_CLOSE; + } +} + +void csr_ll_insert_tail(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + csr_list_insert_tail(&pList->ListHead, pEntry); + pList->Count++; + if (fInterlocked) + csr_ll_unlock(pList); + } +} + +void csr_ll_insert_head(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + csr_list_insert_head(&pList->ListHead, pEntry); + pList->Count++; + if (fInterlocked) + csr_ll_unlock(pList); + } +} + +void csr_ll_insert_entry(tDblLinkList *pList, tListElem *pEntry, + tListElem *pNewEntry, bool fInterlocked) +{ + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + csr_list_insert_entry(pEntry, pNewEntry); + pList->Count++; + if (fInterlocked) + csr_ll_unlock(pList); + } +} + +tListElem *csr_ll_remove_tail(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + sme_err("Error!! pList is Null"); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = csr_list_remove_tail(&pList->ListHead); + pList->Count--; + } + if (fInterlocked) + csr_ll_unlock(pList); + } + + return pEntry; +} + +tListElem *csr_ll_peek_tail(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + sme_err("Error!! pList is Null"); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + if (!csrIsListEmpty(&pList->ListHead)) + pEntry = pList->ListHead.last; + + if (fInterlocked) + csr_ll_unlock(pList); + } + + return pEntry; +} + +tListElem *csr_ll_remove_head(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + sme_err("Error!! pList is Null"); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + if (!csrIsListEmpty(&pList->ListHead)) { + pEntry = csr_list_remove_head(&pList->ListHead); + pList->Count--; + } + + if (fInterlocked) + csr_ll_unlock(pList); + } + + return pEntry; +} + +tListElem *csr_ll_peek_head(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry = NULL; + + if (!pList) { + sme_err("Error!! pList is Null"); + return pEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + if (!csrIsListEmpty(&pList->ListHead)) + pEntry = pList->ListHead.next; + + if (fInterlocked) + csr_ll_unlock(pList); + } + + return pEntry; +} + +void csr_ll_purge(tDblLinkList *pList, bool fInterlocked) +{ + tListElem *pEntry; + + if (!pList) { + sme_err("Error!! pList is Null"); + return; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + /* Remove everything from the list */ + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK))) + ; + + if (fInterlocked) + csr_ll_unlock(pList); + } +} + +bool csr_ll_remove_entry(tDblLinkList *pList, tListElem *pEntryToRemove, + bool fInterlocked) +{ + bool fFound = false; + tListElem *pEntry; + + if (!pList) { + sme_err("Error!! pList is Null"); + return fFound; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + pEntry = csr_ll_peek_head(pList, LL_ACCESS_NOLOCK); + + /* Have to make sure we don't loop back to the head of the + * list, which will happen if the entry is NOT on the list. + */ + while (pEntry && (pEntry != &pList->ListHead)) { + if (pEntry == pEntryToRemove) { + csr_list_remove_entry(pEntry); + pList->Count--; + + fFound = true; + break; + } + + pEntry = pEntry->next; + } + if (fInterlocked) + csr_ll_unlock(pList); + } + + return fFound; +} + +tListElem *csr_ll_next(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + tListElem *pNextEntry = NULL; + + if (!pList) { + sme_err("Error!! pList is Null"); + return pNextEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + if (!csrIsListEmpty(&pList->ListHead) + && csr_ll_find_entry(pList, pEntry)) { + pNextEntry = pEntry->next; + /* Make sure we don't walk past the head */ + if (pNextEntry == &pList->ListHead) + pNextEntry = NULL; + } + + if (fInterlocked) + csr_ll_unlock(pList); + } + + return pNextEntry; +} + +tListElem *csr_ll_previous(tDblLinkList *pList, tListElem *pEntry, + bool fInterlocked) +{ + tListElem *pNextEntry = NULL; + + if (!pList) { + sme_err("Error!! pList is Null"); + return pNextEntry; + } + + if (LIST_FLAG_OPEN == pList->Flag) { + if (fInterlocked) + csr_ll_lock(pList); + + if (!csrIsListEmpty(&pList->ListHead) + && csr_ll_find_entry(pList, pEntry)) { + pNextEntry = pEntry->last; + /* Make sure we don't walk past the head */ + if (pNextEntry == &pList->ListHead) + pNextEntry = NULL; + } + + if (fInterlocked) + csr_ll_unlock(pList); + } + + return pNextEntry; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_util.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_util.c new file mode 100644 index 0000000000..e74506ec2b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/csr/csr_util.c @@ -0,0 +1,1437 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: csr_util.c + * + * Implementation supporting routines for CSR. + */ + +#include "ani_global.h" + +#include "csr_support.h" +#include "csr_inside_api.h" +#include "sme_qos_internal.h" +#include "wma_types.h" +#include "cds_utils.h" +#include "wlan_policy_mgr_api.h" +#include "wlan_serialization_legacy_api.h" +#include "wlan_reg_services_api.h" +#include "wlan_crypto_global_api.h" +#include "wlan_cm_roam_api.h" +#include <../../core/src/wlan_cm_vdev_api.h> +#include +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_policy_mgr_ll_sap.h" + +#define CASE_RETURN_STR(n) {\ + case (n): return (# n);\ +} + +const char *get_e_roam_cmd_status_str(eRoamCmdStatus val) +{ + switch (val) { + CASE_RETURN_STR(eCSR_ROAM_LOSTLINK); + CASE_RETURN_STR(eCSR_ROAM_MIC_ERROR_IND); + CASE_RETURN_STR(eCSR_ROAM_SET_KEY_COMPLETE); + CASE_RETURN_STR(eCSR_ROAM_INFRA_IND); + CASE_RETURN_STR(eCSR_ROAM_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STR(eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS); + CASE_RETURN_STR(eCSR_ROAM_SEND_P2P_STOP_BSS); + CASE_RETURN_STR(eCSR_ROAM_UNPROT_MGMT_FRAME_IND); +#ifdef FEATURE_WLAN_ESE + CASE_RETURN_STR(eCSR_ROAM_TSM_IE_IND); + CASE_RETURN_STR(eCSR_ROAM_ESE_ADJ_AP_REPORT_IND); + CASE_RETURN_STR(eCSR_ROAM_ESE_BCN_REPORT_IND); +#endif /* FEATURE_WLAN_ESE */ + CASE_RETURN_STR(eCSR_ROAM_DFS_RADAR_IND); + CASE_RETURN_STR(eCSR_ROAM_SET_CHANNEL_RSP); + CASE_RETURN_STR(eCSR_ROAM_DFS_CHAN_SW_NOTIFY); + CASE_RETURN_STR(eCSR_ROAM_EXT_CHG_CHNL_IND); + CASE_RETURN_STR(eCSR_ROAM_STA_CHANNEL_SWITCH); + CASE_RETURN_STR(eCSR_ROAM_NDP_STATUS_UPDATE); + CASE_RETURN_STR(eCSR_ROAM_CHANNEL_COMPLETE_IND); + CASE_RETURN_STR(eCSR_ROAM_SAE_COMPUTE); + CASE_RETURN_STR(eCSR_ROAM_CHANNEL_INFO_EVENT_IND); + default: + return "unknown"; + } +} + +const char *get_e_csr_roam_result_str(eCsrRoamResult val) +{ + switch (val) { + CASE_RETURN_STR(eCSR_ROAM_RESULT_NONE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NOT_ASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_FORCED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DISASSOC_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DEAUTH_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CAP_CHANGED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_LOSTLINK); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_ERROR_UNICAST); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MIC_ERROR_GROUP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_AUTHENTICATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NEW_RSN_BSS); + #ifdef FEATURE_WLAN_WAPI + CASE_RETURN_STR(eCSR_ROAM_RESULT_NEW_WAPI_BSS); + #endif /* FEATURE_WLAN_WAPI */ + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_STARTED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_START_FAILED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_STOPPED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_ASSOCIATION_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_ASSOCIATION_CNF); + CASE_RETURN_STR(eCSR_ROAM_RESULT_INFRA_DISASSOCIATED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_WPS_PBC_PROBE_REQ_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_SEND_ACTION_FAIL); + CASE_RETURN_STR(eCSR_ROAM_RESULT_MAX_ASSOC_EXCEEDED); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL); + CASE_RETURN_STR(eCSR_ROAM_RESULT_ADD_TDLS_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_UPDATE_TDLS_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DELETE_TDLS_PEER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TEARDOWN_TDLS_PEER_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DELETE_ALL_TDLS_PEER_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_LINK_ESTABLISH_REQ_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TDLS_SHOULD_DISCOVER); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TDLS_SHOULD_TEARDOWN); + CASE_RETURN_STR(eCSR_ROAM_RESULT_TDLS_SHOULD_PEER_DISCONNECTED); + CASE_RETURN_STR + (eCSR_ROAM_RESULT_TDLS_CONNECTION_TRACKER_NOTIFICATION); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DFS_RADAR_FOUND_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CHANNEL_CHANGE_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CHANNEL_CHANGE_FAILURE); + CASE_RETURN_STR(eCSR_ROAM_RESULT_CSA_RESTART_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_DFS_CHANSW_UPDATE_SUCCESS); + CASE_RETURN_STR(eCSR_ROAM_EXT_CHG_CHNL_UPDATE_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDI_CREATE_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDI_DELETE_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_INITIATOR_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_NEW_PEER_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_CONFIRM_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_INDICATION); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_SCHED_UPDATE_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_RESPONDER_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_END_RSP); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_PEER_DEPARTED_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_NDP_END_IND); + CASE_RETURN_STR(eCSR_ROAM_RESULT_SCAN_FOR_SSID_FAILURE); + default: + return "unknown"; + } +} + +const char *csr_phy_mode_str(eCsrPhyMode phy_mode) +{ + switch (phy_mode) { + case eCSR_DOT11_MODE_abg: + return "abg"; + case eCSR_DOT11_MODE_11a: + return "11a"; + case eCSR_DOT11_MODE_11b: + return "11b"; + case eCSR_DOT11_MODE_11g: + return "11g"; + case eCSR_DOT11_MODE_11n: + return "11n"; + case eCSR_DOT11_MODE_11g_ONLY: + return "11g_only"; + case eCSR_DOT11_MODE_11n_ONLY: + return "11n_only"; + case eCSR_DOT11_MODE_11b_ONLY: + return "11b_only"; + case eCSR_DOT11_MODE_11ac: + return "11ac"; + case eCSR_DOT11_MODE_11ac_ONLY: + return "11ac_only"; + case eCSR_DOT11_MODE_AUTO: + return "auto"; + case eCSR_DOT11_MODE_11ax: + return "11ax"; + case eCSR_DOT11_MODE_11ax_ONLY: + return "11ax_only"; + case eCSR_DOT11_MODE_11be: + return "11be"; + case eCSR_DOT11_MODE_11be_ONLY: + return "11be_only"; + default: + return "unknown"; + } +} + +void csr_purge_pdev_all_ser_cmd_list(struct mac_context *mac_ctx) +{ + wlan_serialization_purge_all_pdev_cmd(mac_ctx->pdev); +} + +tListElem *csr_nonscan_active_ll_peek_head(struct mac_context *mac_ctx, + bool inter_locked) +{ + struct wlan_serialization_command *cmd; + tSmeCmd *sme_cmd; + + cmd = wlan_serialization_peek_head_active_cmd_using_psoc(mac_ctx->psoc, + false); + if (!cmd || cmd->source != WLAN_UMAC_COMP_MLME) + return NULL; + + sme_cmd = cmd->umac_cmd; + + return &sme_cmd->Link; +} + +tListElem *csr_nonscan_pending_ll_peek_head(struct mac_context *mac_ctx, + bool inter_locked) +{ + struct wlan_serialization_command *cmd; + tSmeCmd *sme_cmd; + + cmd = wlan_serialization_peek_head_pending_cmd_using_psoc(mac_ctx->psoc, + false); + while (cmd) { + if (cmd->source == WLAN_UMAC_COMP_MLME) { + sme_cmd = cmd->umac_cmd; + return &sme_cmd->Link; + } + cmd = wlan_serialization_get_pending_list_next_node_using_psoc( + mac_ctx->psoc, cmd, false); + } + + return NULL; +} + +bool csr_nonscan_active_ll_remove_entry(struct mac_context *mac_ctx, + tListElem *entry, bool inter_locked) +{ + tListElem *head; + + head = csr_nonscan_active_ll_peek_head(mac_ctx, inter_locked); + if (head == entry) + return true; + + return false; +} + +tListElem *csr_nonscan_pending_ll_next(struct mac_context *mac_ctx, + tListElem *entry, bool inter_locked) +{ + tSmeCmd *sme_cmd; + struct wlan_serialization_command cmd, *tcmd; + + if (!entry) + return NULL; + sme_cmd = GET_BASE_ADDR(entry, tSmeCmd, Link); + cmd.cmd_id = sme_cmd->cmd_id; + cmd.cmd_type = csr_get_cmd_type(sme_cmd); + cmd.vdev = wlan_objmgr_get_vdev_by_id_from_psoc_no_state( + mac_ctx->psoc, + sme_cmd->vdev_id, WLAN_LEGACY_SME_ID); + tcmd = wlan_serialization_get_pending_list_next_node_using_psoc( + mac_ctx->psoc, &cmd, false); + if (cmd.vdev) + wlan_objmgr_vdev_release_ref(cmd.vdev, WLAN_LEGACY_SME_ID); + while (tcmd) { + if (tcmd->source == WLAN_UMAC_COMP_MLME) { + sme_cmd = tcmd->umac_cmd; + return &sme_cmd->Link; + } + tcmd = wlan_serialization_get_pending_list_next_node_using_psoc( + mac_ctx->psoc, tcmd, false); + } + + return NULL; +} + +static bool csr_is_conn_state(struct mac_context *mac_ctx, uint32_t session_id, + eCsrConnectState state) +{ + QDF_BUG(session_id < WLAN_MAX_VDEVS); + if (session_id >= WLAN_MAX_VDEVS) + return false; + + return mac_ctx->roam.roamSession[session_id].connectState == state; +} + +bool csr_is_conn_state_connected(struct mac_context *mac, uint32_t sessionId) +{ + return cm_is_vdevid_connected(mac->pdev, sessionId) || + csr_is_conn_state_connected_wds(mac, sessionId); +} + +bool csr_is_conn_state_connected_wds(struct mac_context *mac_ctx, + uint32_t session_id) +{ + return csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_WDS_CONNECTED); +} + +bool csr_is_conn_state_connected_infra_ap(struct mac_context *mac_ctx, + uint32_t session_id) +{ + return csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_INFRA_CONNECTED) || + csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_INFRA_DISCONNECTED); +} + +bool csr_is_conn_state_disconnected_wds(struct mac_context *mac_ctx, + uint32_t session_id) +{ + return csr_is_conn_state(mac_ctx, session_id, + eCSR_ASSOC_STATE_TYPE_WDS_DISCONNECTED); +} + +bool csr_is_conn_state_wds(struct mac_context *mac, uint32_t sessionId) +{ + return csr_is_conn_state_connected_wds(mac, sessionId) || + csr_is_conn_state_disconnected_wds(mac, sessionId); +} + +uint16_t cm_csr_get_vdev_dot11_mode(uint8_t vdev_id) +{ + mac_handle_t mac_handle; + struct mac_context *mac_ctx; + enum csr_cfgdot11mode curr_dot11_mode; + + mac_handle = cds_get_context(QDF_MODULE_ID_SME); + mac_ctx = MAC_CONTEXT(mac_handle); + if (!mac_ctx) + return eCSR_CFG_DOT11_MODE_AUTO; + + curr_dot11_mode = mac_ctx->roam.configParam.uCfgDot11Mode; + + return csr_get_vdev_dot11_mode(mac_ctx, vdev_id, curr_dot11_mode); +} + +enum csr_cfgdot11mode +csr_get_vdev_dot11_mode(struct mac_context *mac, + uint8_t vdev_id, + enum csr_cfgdot11mode curr_dot11_mode) +{ + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *vdev_mlme; + enum mlme_vdev_dot11_mode vdev_dot11_mode; + enum csr_cfgdot11mode dot11_mode = curr_dot11_mode; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac->pdev, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) + return curr_dot11_mode; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return curr_dot11_mode; + } + + vdev_dot11_mode = vdev_mlme->proto.vdev_dot11_mode; + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + + if (vdev_dot11_mode == MLME_VDEV_DOT11_MODE_AUTO) + dot11_mode = curr_dot11_mode; + + if (CSR_IS_DOT11_MODE_11N(curr_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11N) + dot11_mode = eCSR_CFG_DOT11_MODE_11N; + + if (CSR_IS_DOT11_MODE_11AC(curr_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11AC) + dot11_mode = eCSR_CFG_DOT11_MODE_11AC; + + if (CSR_IS_DOT11_MODE_11AX(curr_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11AX) + dot11_mode = eCSR_CFG_DOT11_MODE_11AX; +#ifdef WLAN_FEATURE_11BE + if (CSR_IS_DOT11_MODE_11BE(curr_dot11_mode) && + vdev_dot11_mode == MLME_VDEV_DOT11_MODE_11BE) + dot11_mode = eCSR_CFG_DOT11_MODE_11BE; +#endif + sme_debug("INI vdev_dot11_mode %d new dot11_mode %d", + vdev_dot11_mode, dot11_mode); + + return dot11_mode; +} + +static bool csr_is_conn_state_ap(struct mac_context *mac, uint32_t sessionId) +{ + enum QDF_OPMODE opmode; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, sessionId); + if (opmode == QDF_SAP_MODE || opmode == QDF_P2P_GO_MODE) + return true; + + return false; +} + +bool csr_is_any_session_in_connect_state(struct mac_context *mac) +{ + uint32_t i; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (CSR_IS_SESSION_VALID(mac, i) && + (cm_is_vdevid_connected(mac->pdev, i) || + csr_is_conn_state_ap(mac, i))) { + return true; + } + } + + return false; +} + +qdf_freq_t csr_get_concurrent_operation_freq(struct mac_context *mac_ctx) +{ + uint8_t i = 0; + qdf_freq_t freq; + enum QDF_OPMODE op_mode; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + op_mode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, i); + /* check only for STA, CLI, GO and SAP */ + if (op_mode != QDF_STA_MODE && op_mode != QDF_P2P_CLIENT_MODE && + op_mode != QDF_P2P_GO_MODE && op_mode != QDF_SAP_MODE) + continue; + + freq = wlan_get_operation_chan_freq_vdev_id(mac_ctx->pdev, i); + if (!freq) + continue; + + return freq; + } + + return 0; +} + +uint32_t csr_get_beaconing_concurrent_channel(struct mac_context *mac_ctx, + uint8_t vdev_id_to_skip) +{ + struct csr_roam_session *session = NULL; + uint8_t i = 0; + enum QDF_OPMODE persona; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (i == vdev_id_to_skip) + continue; + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + session = CSR_GET_SESSION(mac_ctx, i); + persona = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, i); + if (((persona == QDF_P2P_GO_MODE) || + (persona == QDF_SAP_MODE)) && + (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) + return wlan_get_operation_chan_freq_vdev_id(mac_ctx->pdev, i); + } + + return 0; +} + +#ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH + +#define HALF_BW_OF(eCSR_bw_val) ((eCSR_bw_val)/2) + +/* calculation of center channel based on V/HT BW and WIFI channel bw=5MHz) */ + +#define CSR_GET_HT40_PLUS_CCH(och) ((och) + 10) +#define CSR_GET_HT40_MINUS_CCH(och) ((och) - 10) + +#define CSR_GET_HT80_PLUS_LL_CCH(och) ((och) + 30) +#define CSR_GET_HT80_PLUS_HL_CCH(och) ((och) + 30) +#define CSR_GET_HT80_MINUS_LH_CCH(och) ((och) - 10) +#define CSR_GET_HT80_MINUS_HH_CCH(och) ((och) - 30) + +/** + * csr_calc_chb_for_sap_phymode() - to calc channel bandwidth for sap phymode + * @mac_ctx: pointer to mac context + * @sap_ch: SAP operating channel + * @sap_phymode: SAP physical mode + * @sap_cch: concurrency channel + * @sap_hbw: SAP half bw + * @chb: channel bandwidth + * + * This routine is called to calculate channel bandwidth + * + * Return: none + */ +static void csr_calc_chb_for_sap_phymode(struct mac_context *mac_ctx, + uint32_t *sap_ch, eCsrPhyMode *sap_phymode, + uint32_t *sap_cch, uint32_t *sap_hbw, uint8_t *chb) +{ + if (*sap_phymode == eCSR_DOT11_MODE_11n || + *sap_phymode == eCSR_DOT11_MODE_11n_ONLY) { + + *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (*chb == PHY_DOUBLE_CHANNEL_LOW_PRIMARY) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == PHY_DOUBLE_CHANNEL_HIGH_PRIMARY) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + + } else if (*sap_phymode == eCSR_DOT11_MODE_11ac || + *sap_phymode == eCSR_DOT11_MODE_11ac_ONLY || + *sap_phymode == eCSR_DOT11_MODE_11ax || + *sap_phymode == eCSR_DOT11_MODE_11ax_ONLY || + CSR_IS_DOT11_PHY_MODE_11BE(*sap_phymode) || + CSR_IS_DOT11_PHY_MODE_11BE_ONLY(*sap_phymode)) { + /*11AC only 80/40/20 Mhz supported in Rome */ + if (mac_ctx->roam.configParam.nVhtChannelWidth == + (WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ + 1)) { + *sap_hbw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW - 1)) + *sap_cch = CSR_GET_HT80_PLUS_LL_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT80_PLUS_HL_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT80_MINUS_LH_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT80_MINUS_HH_CCH(*sap_ch); + } else { + *sap_hbw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + if (*chb == (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW + - 1)) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT40_PLUS_CCH(*sap_ch); + else if (*chb == + (PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH + - 1)) + *sap_cch = CSR_GET_HT40_MINUS_CCH(*sap_ch); + } + } +} + +static eCSR_BW_Val csr_get_half_bw(enum phy_ch_width ch_width) +{ + eCSR_BW_Val hw_bw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + switch (ch_width) { + case CH_WIDTH_40MHZ: + hw_bw = HALF_BW_OF(eCSR_BW_40MHz_VAL); + break; + case CH_WIDTH_80MHZ: + hw_bw = HALF_BW_OF(eCSR_BW_80MHz_VAL); + break; + case CH_WIDTH_160MHZ: + case CH_WIDTH_80P80MHZ: + hw_bw = HALF_BW_OF(eCSR_BW_160MHz_VAL); + break; + default: + break; + } + + return hw_bw; +} + +/** + * csr_handle_conc_chnl_overlap_for_sap_go - To handle overlap for AP+AP + * @mac_ctx: pointer to mac context + * @session: Current session + * @sap_ch_freq: SAP/GO operating channel frequency + * @sap_hbw: SAP/GO half bw + * @sap_cfreq: SAP/GO channel frequency + * @intf_ch_freq: concurrent SAP/GO operating channel frequency + * @intf_hbw: concurrent SAP/GO half bw + * @intf_cfreq: concurrent SAP/GO channel frequency + * @op_mode: opmode + * + * This routine is called to check if one SAP/GO channel is overlapping with + * other SAP/GO channel + * + * Return: none + */ +static void csr_handle_conc_chnl_overlap_for_sap_go( + struct mac_context *mac_ctx, + struct csr_roam_session *session, + uint32_t *sap_ch_freq, uint32_t *sap_hbw, uint32_t *sap_cfreq, + uint32_t *intf_ch_freq, uint32_t *intf_hbw, + uint32_t *intf_cfreq, enum QDF_OPMODE op_mode, + uint8_t cc_switch_mode) +{ + qdf_freq_t op_chan_freq; + qdf_freq_t freq_seg_0; + enum phy_ch_width ch_width; + + wlan_get_op_chan_freq_info_vdev_id(mac_ctx->pdev, session->vdev_id, + &op_chan_freq, &freq_seg_0, + &ch_width); + sme_debug("op_chan_freq:%d freq_seg_0:%d ch_width:%d", + op_chan_freq, freq_seg_0, ch_width); + /* + * if conc_custom_rule1 is defined then we don't + * want p2pgo to follow SAP's channel or SAP to + * follow P2PGO's channel. + */ + if (0 == mac_ctx->roam.configParam.conc_custom_rule1 && + 0 == mac_ctx->roam.configParam.conc_custom_rule2) { + if (*sap_ch_freq == 0) { + *sap_ch_freq = op_chan_freq; + *sap_cfreq = freq_seg_0; + *sap_hbw = csr_get_half_bw(ch_width); + } else if (*sap_ch_freq != op_chan_freq || + (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL && + op_mode == QDF_P2P_GO_MODE)) { + *intf_ch_freq = op_chan_freq; + *intf_cfreq = freq_seg_0; + *intf_hbw = csr_get_half_bw(ch_width); + } + } else if (*sap_ch_freq == 0 && op_mode == QDF_SAP_MODE) { + *sap_ch_freq = op_chan_freq; + *sap_cfreq = freq_seg_0; + *sap_hbw = csr_get_half_bw(ch_width); + } +} + +uint16_t csr_check_concurrent_channel_overlap(struct mac_context *mac_ctx, + uint32_t sap_ch_freq, eCsrPhyMode sap_phymode, + uint8_t cc_switch_mode, uint8_t vdev_id) +{ + struct csr_roam_session *session = NULL; + uint8_t i = 0, chb = PHY_SINGLE_CHANNEL_CENTERED; + uint32_t intf_ch_freq = 0, sap_hbw = 0, intf_hbw = 0, intf_cfreq = 0; + uint32_t sap_cfreq = 0; + uint32_t sap_lfreq, sap_hfreq, intf_lfreq, intf_hfreq; + QDF_STATUS status; + enum QDF_OPMODE op_mode; + enum phy_ch_width ch_width; + enum channel_state state; + +#ifdef WLAN_FEATURE_LL_LT_SAP + qdf_freq_t new_sap_freq = 0; + bool is_ll_lt_sap_present = false; +#endif + + if (mac_ctx->roam.configParam.cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_DISABLE) + return 0; + + /* + * This is temporary code and will be removed once this feature flag + * is enabled + */ +#ifndef WLAN_FEATURE_LL_LT_SAP + if (policy_mgr_is_vdev_ll_lt_sap(mac_ctx->psoc, vdev_id)) + return 0; +#else + policy_mgr_ll_lt_sap_get_valid_freq( + mac_ctx->psoc, mac_ctx->pdev, + vdev_id, sap_ch_freq, + mac_ctx->roam.configParam.cc_switch_mode, + &new_sap_freq, + &is_ll_lt_sap_present); + /* + * If ll_lt_sap is present, then it has already updated the frequency + * according to current concurrency, so, return from here + */ + if (is_ll_lt_sap_present) { + if (new_sap_freq == sap_ch_freq) + return 0; + + sme_debug("LL_LT_SAP concurrency updated freq %d for vdev %d", + new_sap_freq, vdev_id); + return new_sap_freq; + } +#endif + + if (sap_ch_freq != 0) { + sap_cfreq = sap_ch_freq; + sap_hbw = HALF_BW_OF(eCSR_BW_20MHz_VAL); + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(sap_ch_freq)) + chb = mac_ctx->roam.configParam.channelBondingMode5GHz; + else + chb = mac_ctx->roam.configParam.channelBondingMode24GHz; + + if (chb) + csr_calc_chb_for_sap_phymode(mac_ctx, &sap_ch_freq, + &sap_phymode, &sap_cfreq, + &sap_hbw, &chb); + } + + sme_debug("sap_ch:%d sap_phymode:%d sap_cch:%d sap_hbw:%d chb:%d", + sap_ch_freq, sap_phymode, sap_cfreq, sap_hbw, chb); + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, i)) + continue; + + session = CSR_GET_SESSION(mac_ctx, i); + op_mode = wlan_get_opmode_from_vdev_id(mac_ctx->pdev, i); + if ((op_mode == QDF_STA_MODE || + op_mode == QDF_P2P_CLIENT_MODE) && + cm_is_vdevid_connected(mac_ctx->pdev, i)) { + if (op_mode == QDF_STA_MODE && + policy_mgr_is_ml_vdev_id(mac_ctx->psoc, + session->vdev_id) && + policy_mgr_vdev_is_force_inactive( + mac_ctx->psoc, + session->vdev_id)) { + sme_debug("skip inactive ml sta vdev %d", + session->vdev_id); + continue; + } + wlan_get_op_chan_freq_info_vdev_id(mac_ctx->pdev, + session->vdev_id, + &intf_ch_freq, &intf_cfreq, + &ch_width); + intf_hbw = csr_get_half_bw(ch_width); + sme_debug("%d: intf_ch:%d intf_cfreq:%d intf_hbw:%d ch_width %d", + i, intf_ch_freq, intf_cfreq, intf_hbw, + ch_width); + } else if ((op_mode == QDF_P2P_GO_MODE || + op_mode == QDF_SAP_MODE) && + (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED)) { + + if (session->ch_switch_in_progress) + continue; + + csr_handle_conc_chnl_overlap_for_sap_go(mac_ctx, + session, &sap_ch_freq, &sap_hbw, + &sap_cfreq, &intf_ch_freq, &intf_hbw, + &intf_cfreq, op_mode, + cc_switch_mode); + } + + if (intf_ch_freq) { + state = wlan_reg_get_channel_state_for_pwrmode( + mac_ctx->pdev, intf_ch_freq, + REG_CURRENT_PWR_MODE); + if (state == CHANNEL_STATE_DISABLE || + state == CHANNEL_STATE_INVALID) { + sme_debug("skip vdev %d for intf_ch:%d", + i, intf_ch_freq); + intf_ch_freq = 0; + continue; + } + } + + if (intf_ch_freq && + ((intf_ch_freq <= wlan_reg_ch_to_freq(CHAN_ENUM_2484) && + sap_ch_freq <= wlan_reg_ch_to_freq(CHAN_ENUM_2484)) || + (intf_ch_freq > wlan_reg_ch_to_freq(CHAN_ENUM_2484) && + sap_ch_freq > wlan_reg_ch_to_freq(CHAN_ENUM_2484)))) + break; + } + + sme_debug("intf_ch:%d sap_ch:%d cc_switch_mode:%d, dbs:%d", + intf_ch_freq, sap_ch_freq, cc_switch_mode, + policy_mgr_is_hw_dbs_capable(mac_ctx->psoc)); + + if (intf_ch_freq && sap_ch_freq != intf_ch_freq && + !policy_mgr_is_force_scc(mac_ctx->psoc)) { + sap_lfreq = sap_cfreq - sap_hbw; + sap_hfreq = sap_cfreq + sap_hbw; + intf_lfreq = intf_cfreq - intf_hbw; + intf_hfreq = intf_cfreq + intf_hbw; + + sme_debug("SAP: OCH: %03d CCH: %03d BW: %d LF: %d HF: %d INTF: OCH: %03d CF: %d BW: %d LF: %d HF: %d", + sap_ch_freq, sap_cfreq, sap_hbw * 2, + sap_lfreq, sap_hfreq, intf_ch_freq, + intf_cfreq, intf_hbw * 2, intf_lfreq, intf_hfreq); + + if (!(((sap_lfreq > intf_lfreq && sap_lfreq < intf_hfreq) || + (sap_hfreq > intf_lfreq && sap_hfreq < intf_hfreq)) || + ((intf_lfreq > sap_lfreq && intf_lfreq < sap_hfreq) || + (intf_hfreq > sap_lfreq && intf_hfreq < sap_hfreq)))) + intf_ch_freq = 0; + } else if (intf_ch_freq && sap_ch_freq != intf_ch_freq && + (policy_mgr_is_force_scc(mac_ctx->psoc))) { + policy_mgr_check_scc_channel(mac_ctx->psoc, &intf_ch_freq, + sap_ch_freq, vdev_id, + cc_switch_mode); + } else if ((intf_ch_freq == sap_ch_freq) && (cc_switch_mode == + QDF_MCC_TO_SCC_SWITCH_WITH_FAVORITE_CHANNEL)) { + status = policy_mgr_handle_go_sap_fav_channel( + mac_ctx->psoc, vdev_id, + sap_ch_freq, &intf_ch_freq); + if (QDF_IS_STATUS_SUCCESS(status) && + intf_ch_freq && intf_ch_freq != sap_ch_freq) + goto end; + + if (WLAN_REG_IS_24GHZ_CH_FREQ(intf_ch_freq) || + WLAN_REG_IS_6GHZ_CHAN_FREQ(sap_ch_freq)) { + status = + policy_mgr_get_sap_mandatory_channel( + mac_ctx->psoc, sap_ch_freq, + &intf_ch_freq, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + sme_err("no mandatory channel"); + } + } +end: + if (intf_ch_freq == sap_ch_freq) + intf_ch_freq = 0; + + sme_debug("##Concurrent Channels (%d, %d) %s Interfering", sap_ch_freq, + intf_ch_freq, + intf_ch_freq == 0 ? "Not" : "Are"); + + return intf_ch_freq; +} +#endif + +bool csr_is_all_session_disconnected(struct mac_context *mac) +{ + uint32_t i; + bool fRc = true; + + for (i = 0; i < WLAN_MAX_VDEVS; i++) { + if (CSR_IS_SESSION_VALID(mac, i) + && !csr_is_conn_state_disconnected(mac, i)) { + fRc = false; + break; + } + } + + return fRc; +} + +bool csr_is_infra_ap_started(struct mac_context *mac) +{ + uint32_t sessionId; + bool fRc = false; + + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; sessionId++) { + if (CSR_IS_SESSION_VALID(mac, sessionId) && + (csr_is_conn_state_connected_infra_ap(mac, + sessionId))) { + fRc = true; + break; + } + } + + return fRc; + +} + +bool csr_is_conn_state_disconnected(struct mac_context *mac, uint8_t vdev_id) +{ + enum QDF_OPMODE opmode; + + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, vdev_id); + + if (opmode == QDF_STA_MODE || opmode == QDF_P2P_CLIENT_MODE) + return !cm_is_vdevid_connected(mac->pdev, vdev_id); + + return eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED == + mac->roam.roamSession[vdev_id].connectState; +} + +bool csr_is11h_supported(struct mac_context *mac) +{ + return mac->mlme_cfg->gen.enabled_11h; +} + +bool csr_is_wmm_supported(struct mac_context *mac) +{ + if (WMM_USER_MODE_NO_QOS == mac->roam.configParam.WMMSupportMode) + return false; + else + return true; +} + +/* This function will allocate memory for the parsed IEs to the caller. + * Caller must free the memory after it is done with the data only if + * this function succeeds + */ +QDF_STATUS csr_get_parsed_bss_description_ies(struct mac_context *mac_ctx, + struct bss_description *bss_desc, + tDot11fBeaconIEs **ppIEStruct) +{ + return wlan_get_parsed_bss_description_ies(mac_ctx, bss_desc, + ppIEStruct); +} + +uint32_t csr_get_frag_thresh(struct mac_context *mac_ctx) +{ + return mac_ctx->mlme_cfg->threshold.frag_threshold; +} + +uint32_t csr_get_rts_thresh(struct mac_context *mac_ctx) +{ + return mac_ctx->mlme_cfg->threshold.rts_threshold; +} + +uint32_t csr_translate_to_wni_cfg_dot11_mode(struct mac_context *mac, + enum csr_cfgdot11mode csrDot11Mode) +{ + uint32_t ret; + + switch (csrDot11Mode) { + case eCSR_CFG_DOT11_MODE_AUTO: +#ifdef WLAN_FEATURE_11BE + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) + ret = MLME_DOT11_MODE_11BE; + else +#endif + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = MLME_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC; + else + ret = MLME_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11A: + ret = MLME_DOT11_MODE_11A; + break; + case eCSR_CFG_DOT11_MODE_11B: + ret = MLME_DOT11_MODE_11B; + break; + case eCSR_CFG_DOT11_MODE_11G: + ret = MLME_DOT11_MODE_11G; + break; + case eCSR_CFG_DOT11_MODE_11N: + ret = MLME_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11G_ONLY: + ret = MLME_DOT11_MODE_11G_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11N_ONLY: + ret = MLME_DOT11_MODE_11N_ONLY; + break; + case eCSR_CFG_DOT11_MODE_11AC_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC_ONLY; + else + ret = MLME_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AC: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC; + else + ret = MLME_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AX_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = MLME_DOT11_MODE_11AX_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC; + else + ret = MLME_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11AX: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = MLME_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC; + else + ret = MLME_DOT11_MODE_11N; + break; +#ifdef WLAN_FEATURE_11BE + case eCSR_CFG_DOT11_MODE_11BE_ONLY: + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) + ret = MLME_DOT11_MODE_11BE_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = MLME_DOT11_MODE_11AX_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC; + else + ret = MLME_DOT11_MODE_11N; + break; + case eCSR_CFG_DOT11_MODE_11BE: + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) + ret = MLME_DOT11_MODE_11BE; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + ret = MLME_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + ret = MLME_DOT11_MODE_11AC; + else + ret = MLME_DOT11_MODE_11N; + break; +#endif + case eCSR_CFG_DOT11_MODE_ABG: + ret = MLME_DOT11_MODE_ABG; + break; + default: + sme_warn("doesn't expect %d as csrDo11Mode", csrDot11Mode); + ret = MLME_DOT11_MODE_ALL; + break; + } + + return ret; +} + +enum reg_phymode csr_convert_to_reg_phy_mode(eCsrPhyMode csr_phy_mode, + qdf_freq_t freq) +{ + if (csr_phy_mode == eCSR_DOT11_MODE_AUTO) + return REG_PHYMODE_MAX - 1; +#ifdef WLAN_FEATURE_11BE + else if (CSR_IS_DOT11_PHY_MODE_11BE(csr_phy_mode) || + CSR_IS_DOT11_PHY_MODE_11BE_ONLY(csr_phy_mode)) + return REG_PHYMODE_11BE; +#endif + else if (csr_phy_mode == eCSR_DOT11_MODE_11ax || + csr_phy_mode == eCSR_DOT11_MODE_11ax_ONLY) + return REG_PHYMODE_11AX; + else if (csr_phy_mode == eCSR_DOT11_MODE_11ac || + csr_phy_mode == eCSR_DOT11_MODE_11ac_ONLY) + return REG_PHYMODE_11AC; + else if (csr_phy_mode == eCSR_DOT11_MODE_11n || + csr_phy_mode == eCSR_DOT11_MODE_11n_ONLY) + return REG_PHYMODE_11N; + else if (csr_phy_mode == eCSR_DOT11_MODE_11a) + return REG_PHYMODE_11A; + else if (csr_phy_mode == eCSR_DOT11_MODE_11g || + csr_phy_mode == eCSR_DOT11_MODE_11g_ONLY) + return REG_PHYMODE_11G; + else if (csr_phy_mode == eCSR_DOT11_MODE_11b || + csr_phy_mode == eCSR_DOT11_MODE_11b_ONLY) + return REG_PHYMODE_11B; + else if (csr_phy_mode == eCSR_DOT11_MODE_abg) { + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq)) + return REG_PHYMODE_11G; + else + return REG_PHYMODE_11A; + } else { + sme_err("Invalid eCsrPhyMode"); + return REG_PHYMODE_INVALID; + } +} + +eCsrPhyMode csr_convert_from_reg_phy_mode(enum reg_phymode phymode) +{ + switch (phymode) { + case REG_PHYMODE_INVALID: + return eCSR_DOT11_MODE_AUTO; + case REG_PHYMODE_11B: + return eCSR_DOT11_MODE_11b; + case REG_PHYMODE_11G: + return eCSR_DOT11_MODE_11g; + case REG_PHYMODE_11A: + return eCSR_DOT11_MODE_11a; + case REG_PHYMODE_11N: + return eCSR_DOT11_MODE_11n; + case REG_PHYMODE_11AC: + return eCSR_DOT11_MODE_11ac; + case REG_PHYMODE_11AX: + return eCSR_DOT11_MODE_11ax; +#ifdef WLAN_FEATURE_11BE + case REG_PHYMODE_11BE: + return eCSR_DOT11_MODE_11be; +#endif + case REG_PHYMODE_MAX: + return eCSR_DOT11_MODE_AUTO; + default: + return eCSR_DOT11_MODE_AUTO; + } +} + +bool csr_is_auth_type_ese(enum csr_akm_type AuthType) +{ + switch (AuthType) { + case eCSR_AUTH_TYPE_CCKM_WPA: + case eCSR_AUTH_TYPE_CCKM_RSN: + return true; + default: + break; + } + return false; +} + +bool csr_is_pmkid_found_for_peer(struct mac_context *mac, + struct csr_roam_session *session, + tSirMacAddr peer_mac_addr, + uint8_t *pmkid, + uint16_t pmkid_count) +{ + uint32_t i; + uint8_t *session_pmkid; + struct wlan_crypto_pmksa *pmkid_cache; + + pmkid_cache = qdf_mem_malloc(sizeof(*pmkid_cache)); + if (!pmkid_cache) + return false; + + qdf_mem_copy(pmkid_cache->bssid.bytes, peer_mac_addr, + QDF_MAC_ADDR_SIZE); + + if (!cm_lookup_pmkid_using_bssid(mac->psoc, session->vdev_id, + pmkid_cache)) { + qdf_mem_free(pmkid_cache); + return false; + } + + session_pmkid = pmkid_cache->pmkid; + for (i = 0; i < pmkid_count; i++) { + if (!qdf_mem_cmp(pmkid + (i * PMKID_LEN), + session_pmkid, PMKID_LEN)) { + qdf_mem_free(pmkid_cache); + return true; + } + } + + sme_debug("PMKID in PmkidCacheInfo doesn't match with PMKIDs of peer"); + qdf_mem_free(pmkid_cache); + + return false; +} + +bool csr_is_bssid_match(struct qdf_mac_addr *pProfBssid, + struct qdf_mac_addr *BssBssid) +{ + bool fMatch = false; + struct qdf_mac_addr ProfileBssid; + + /* for efficiency of the MAC_ADDRESS functions, move the */ + /* Bssid's into MAC_ADDRESS structs. */ + qdf_mem_copy(&ProfileBssid, pProfBssid, sizeof(struct qdf_mac_addr)); + + do { + /* Give the profile the benefit of the doubt... accept + * either all 0 or the real broadcast Bssid (all 0xff) + * as broadcast Bssids (meaning to match any Bssids). + */ + if (qdf_is_macaddr_zero(&ProfileBssid) || + qdf_is_macaddr_broadcast(&ProfileBssid)) { + fMatch = true; + break; + } + + if (qdf_is_macaddr_equal(BssBssid, &ProfileBssid)) { + fMatch = true; + break; + } + + } while (0); + + return fMatch; +} + +/* This function use the parameters to decide the CFG value. */ +/* CSR never sets MLME_DOT11_MODE_ALL to the CFG */ +/* So PE should not see MLME_DOT11_MODE_ALL when it gets the CFG value */ +enum csr_cfgdot11mode +csr_get_cfg_dot11_mode_from_csr_phy_mode(bool is_ap, eCsrPhyMode phyMode) +{ + uint32_t cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG; + + switch (phyMode) { + case eCSR_DOT11_MODE_11a: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11A; + break; + case eCSR_DOT11_MODE_11b: + case eCSR_DOT11_MODE_11b_ONLY: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11B; + break; + case eCSR_DOT11_MODE_11g: + case eCSR_DOT11_MODE_11g_ONLY: + if (is_ap && (phyMode == eCSR_DOT11_MODE_11g_ONLY)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11G; + break; + case eCSR_DOT11_MODE_11n: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11n_ONLY: + if (is_ap) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_abg: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_ABG; + break; + case eCSR_DOT11_MODE_AUTO: + cfgDot11Mode = eCSR_CFG_DOT11_MODE_AUTO; + break; + + case eCSR_DOT11_MODE_11ac: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ac_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC_ONLY; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ax: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11ax_ONLY: + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; +#ifdef WLAN_FEATURE_11BE + case eCSR_DOT11_MODE_11be: + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11BE; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; + case eCSR_DOT11_MODE_11be_ONLY: + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11BE_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AX_ONLY; + else if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AC)) + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11AC; + else + cfgDot11Mode = eCSR_CFG_DOT11_MODE_11N; + break; +#endif + default: + /* No need to assign anything here */ + break; + } + + return cfgDot11Mode; +} + +QDF_STATUS csr_get_modify_profile_fields(struct mac_context *mac, + uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + if (!pModifyProfileFields) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(pModifyProfileFields, + &mac->roam.roamSession[sessionId].modifyProfileFields, + sizeof(tCsrRoamModifyProfileFields)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS csr_set_modify_profile_fields(struct mac_context *mac, + uint32_t sessionId, + tCsrRoamModifyProfileFields * + pModifyProfileFields) +{ + struct csr_roam_session *pSession = CSR_GET_SESSION(mac, sessionId); + + if (!pSession) { + sme_err("Session_id invalid %d", sessionId); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(&pSession->modifyProfileFields, + pModifyProfileFields, sizeof(tCsrRoamModifyProfileFields)); + + return QDF_STATUS_SUCCESS; +} + +/* no need to acquire lock for this basic function */ +uint16_t sme_chn_to_freq(uint8_t chanNum) +{ + int i; + + for (i = 0; i < NUM_CHANNELS; i++) { + if (WLAN_REG_CH_NUM(i) == chanNum) + return WLAN_REG_CH_TO_FREQ(i); + } + + return 0; +} + +const char *sme_bss_type_to_string(const uint8_t bss_type) +{ + switch (bss_type) { + CASE_RETURN_STRING(eCSR_BSS_TYPE_INFRASTRUCTURE); + CASE_RETURN_STRING(eCSR_BSS_TYPE_INFRA_AP); + CASE_RETURN_STRING(eCSR_BSS_TYPE_ANY); + default: + return "unknown bss type"; + } +} + +/** + * csr_is_ndi_started() - function to check if NDI is started + * @mac_ctx: handle to mac context + * @session_id: session identifier + * + * returns: true if NDI is started, false otherwise + */ +bool csr_is_ndi_started(struct mac_context *mac_ctx, uint32_t session_id) +{ + struct csr_roam_session *session = CSR_GET_SESSION(mac_ctx, session_id); + + if (!session) + return false; + + return eCSR_CONNECT_STATE_TYPE_NDI_STARTED == session->connectState; +} + +bool csr_is_mcc_channel(struct mac_context *mac_ctx, uint32_t chan_freq) +{ + struct csr_roam_session *session; + enum QDF_OPMODE oper_mode; + uint32_t oper_chan_freq = 0; + uint8_t vdev_id; + bool hw_dbs_capable, same_band_freqs; + + if (chan_freq == 0) + return false; + + hw_dbs_capable = policy_mgr_is_hw_dbs_capable(mac_ctx->psoc); + for (vdev_id = 0; vdev_id < WLAN_MAX_VDEVS; vdev_id++) { + if (!CSR_IS_SESSION_VALID(mac_ctx, vdev_id)) + continue; + + session = CSR_GET_SESSION(mac_ctx, vdev_id); + oper_mode = + wlan_get_opmode_from_vdev_id(mac_ctx->pdev, vdev_id); + if ((((oper_mode == QDF_STA_MODE) || + (oper_mode == QDF_P2P_CLIENT_MODE)) && + cm_is_vdevid_connected(mac_ctx->pdev, vdev_id)) || + (((oper_mode == QDF_P2P_GO_MODE) || + (oper_mode == QDF_SAP_MODE)) && + (session->connectState != + eCSR_ASSOC_STATE_TYPE_NOT_CONNECTED))) + oper_chan_freq = + wlan_get_operation_chan_freq_vdev_id(mac_ctx->pdev, + vdev_id); + + if (!oper_chan_freq) + continue; + same_band_freqs = WLAN_REG_IS_SAME_BAND_FREQS( + chan_freq, oper_chan_freq); + + if (oper_chan_freq && chan_freq != oper_chan_freq && + (!hw_dbs_capable || same_band_freqs)) + return true; + } + + return false; +} + +enum csr_cfgdot11mode csr_phy_mode_to_dot11mode(enum wlan_phymode phy_mode) +{ + switch (phy_mode) { + case WLAN_PHYMODE_AUTO: + return eCSR_CFG_DOT11_MODE_AUTO; + case WLAN_PHYMODE_11A: + return eCSR_CFG_DOT11_MODE_11A; + case WLAN_PHYMODE_11B: + return eCSR_CFG_DOT11_MODE_11B; + case WLAN_PHYMODE_11G: + return eCSR_CFG_DOT11_MODE_11G; + case WLAN_PHYMODE_11G_ONLY: + return eCSR_CFG_DOT11_MODE_11G_ONLY; + case WLAN_PHYMODE_11NA_HT20: + case WLAN_PHYMODE_11NG_HT20: + case WLAN_PHYMODE_11NA_HT40: + case WLAN_PHYMODE_11NG_HT40PLUS: + case WLAN_PHYMODE_11NG_HT40MINUS: + case WLAN_PHYMODE_11NG_HT40: + return eCSR_CFG_DOT11_MODE_11N; + case WLAN_PHYMODE_11AC_VHT20: + case WLAN_PHYMODE_11AC_VHT20_2G: + case WLAN_PHYMODE_11AC_VHT40: + case WLAN_PHYMODE_11AC_VHT40PLUS_2G: + case WLAN_PHYMODE_11AC_VHT40MINUS_2G: + case WLAN_PHYMODE_11AC_VHT40_2G: + case WLAN_PHYMODE_11AC_VHT80: + case WLAN_PHYMODE_11AC_VHT80_2G: + case WLAN_PHYMODE_11AC_VHT160: + case WLAN_PHYMODE_11AC_VHT80_80: + return eCSR_CFG_DOT11_MODE_11AC; + case WLAN_PHYMODE_11AXA_HE20: + case WLAN_PHYMODE_11AXG_HE20: + case WLAN_PHYMODE_11AXA_HE40: + case WLAN_PHYMODE_11AXG_HE40PLUS: + case WLAN_PHYMODE_11AXG_HE40MINUS: + case WLAN_PHYMODE_11AXG_HE40: + case WLAN_PHYMODE_11AXA_HE80: + case WLAN_PHYMODE_11AXG_HE80: + case WLAN_PHYMODE_11AXA_HE160: + case WLAN_PHYMODE_11AXA_HE80_80: + return eCSR_CFG_DOT11_MODE_11AX; +#ifdef WLAN_FEATURE_11BE + case WLAN_PHYMODE_11BEA_EHT20: + case WLAN_PHYMODE_11BEG_EHT20: + case WLAN_PHYMODE_11BEA_EHT40: + case WLAN_PHYMODE_11BEG_EHT40PLUS: + case WLAN_PHYMODE_11BEG_EHT40MINUS: + case WLAN_PHYMODE_11BEG_EHT40: + case WLAN_PHYMODE_11BEA_EHT80: + case WLAN_PHYMODE_11BEG_EHT80: + case WLAN_PHYMODE_11BEA_EHT160: + case WLAN_PHYMODE_11BEA_EHT320: + return eCSR_CFG_DOT11_MODE_11BE; +#endif + default: + sme_err("invalid phy mode %d", phy_mode); + return eCSR_CFG_DOT11_MODE_MAX; + } +} + +QDF_STATUS csr_mlme_vdev_disconnect_all_p2p_client_event(uint8_t vdev_id) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + return csr_roam_call_callback(mac_ctx, vdev_id, NULL, + eCSR_ROAM_DISCONNECT_ALL_P2P_CLIENTS, + eCSR_ROAM_RESULT_NONE); +} + +QDF_STATUS csr_mlme_vdev_stop_bss(uint8_t vdev_id) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + return csr_roam_call_callback(mac_ctx, vdev_id, NULL, + eCSR_ROAM_SEND_P2P_STOP_BSS, + eCSR_ROAM_RESULT_NONE); +} + +qdf_freq_t csr_mlme_get_concurrent_operation_freq(void) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_SME); + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + return csr_get_concurrent_operation_freq(mac_ctx); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c new file mode 100644 index 0000000000..fb11f1201c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/nan/nan_datapath_api.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: nan_datapath_api.c + * + * SME NAN Data path API implementation + */ +#include +#include +#include "sme_api.h" +#include "sme_inside.h" +#include "csr_internal.h" +#include "sme_nan_datapath.h" + +/** + * csr_roam_update_ndp_return_params() - updates ndp return parameters + * @mac_ctx: MAC context handle + * @result: result of the roaming command + * @roam_status: roam status returned to the roam command initiator + * @roam_result: roam result returned to the roam command initiator + * @roam_info: Roam info data structure to be updated + * + * Results: None + */ +void csr_roam_update_ndp_return_params(struct mac_context *mac_ctx, + uint32_t result, + uint32_t *roam_status, + uint32_t *roam_result, + struct csr_roam_info *roam_info) +{ + + switch (result) { + case CSR_SAP_START_BSS_SUCCESS: + roam_info->ndp.ndi_create_params.reason = 0; + roam_info->ndp.ndi_create_params.status = + NDP_RSP_STATUS_SUCCESS; + roam_info->ndp.ndi_create_params.sta_id = roam_info->staId; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_CREATE_RSP; + break; + case CSR_SAP_START_BSS_FAILURE: + roam_info->ndp.ndi_create_params.status = NDP_RSP_STATUS_ERROR; + roam_info->ndp.ndi_create_params.reason = + NDP_NAN_DATA_IFACE_CREATE_FAILED; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_CREATE_RSP; + break; + case CSR_SAP_STOP_BSS_SUCCESS: + roam_info->ndp.ndi_delete_params.reason = 0; + roam_info->ndp.ndi_delete_params.status = + NDP_RSP_STATUS_SUCCESS; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_DELETE_RSP; + break; + case CSR_SAP_STOP_BSS_FAILURE: + roam_info->ndp.ndi_delete_params.status = NDP_RSP_STATUS_ERROR; + roam_info->ndp.ndi_delete_params.reason = + NDP_NAN_DATA_IFACE_DELETE_FAILED; + *roam_status = eCSR_ROAM_NDP_STATUS_UPDATE; + *roam_result = eCSR_ROAM_RESULT_NDI_DELETE_RSP; + break; + default: + sme_err("Invalid CSR Roam result code: %d", result); + break; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/qos/sme_qos.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/qos/sme_qos.c new file mode 100644 index 0000000000..2d26f58dfd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/qos/sme_qos.c @@ -0,0 +1,7152 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: sme_qos.c + * + * Implementation for SME QoS APIs + */ +/* $Header$ */ +/* Include Files */ + +#include "ani_global.h" + +#include "sme_inside.h" +#include "csr_inside_api.h" +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" + +#include "utils_parser.h" +#include "sme_power_save_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_cm_roam_api.h" + +#ifndef WLAN_MDM_CODE_REDUCTION_OPT +/* TODO : 6Mbps as Cisco APs seem to like only this value; analysis req. */ +#define SME_QOS_MIN_PHY_RATE 0x5B8D80 +#define SME_QOS_SURPLUS_BW_ALLOWANCE 0x2000 /* Ratio of 1.0 */ +/* Max values to bound tspec params against and avoid rollover */ +#define SME_QOS_32BIT_MAX 0xFFFFFFFF +#define SME_QOS_16BIT_MAX 0xFFFF +#define SME_QOS_16BIT_MSB 0x8000 +/* Adds y to x, but saturates at 32-bit max to avoid rollover */ +#define SME_QOS_BOUNDED_U32_ADD_Y_TO_X(_x, _y) \ + do { \ + (_x) = ((SME_QOS_32BIT_MAX - (_x)) < (_y)) ? \ + (SME_QOS_32BIT_MAX) : (_x) + (_y); \ + } while (0) + +/* + * As per WMM spec there could be max 2 TSPEC running on the same AC with + * different direction. We will refer each TSPEC with an index + */ +#define SME_QOS_TSPEC_INDEX_0 0 +#define SME_QOS_TSPEC_INDEX_1 1 +#define SME_QOS_TSPEC_INDEX_MAX 2 +#define SME_QOS_TSPEC_MASK_BIT_1_SET 1 +#define SME_QOS_TSPEC_MASK_BIT_2_SET 2 +#define SME_QOS_TSPEC_MASK_BIT_1_2_SET 3 +#define SME_QOS_TSPEC_MASK_CLEAR 0 + +/* which key to search on, in the flowlist (1 = flowID, 2 = AC, 4 = reason) */ +#define SME_QOS_SEARCH_KEY_INDEX_1 1 +#define SME_QOS_SEARCH_KEY_INDEX_2 2 +#define SME_QOS_SEARCH_KEY_INDEX_3 4 +#define SME_QOS_SEARCH_KEY_INDEX_4 8 /* ac + direction */ +#define SME_QOS_SEARCH_KEY_INDEX_5 0x10 /* ac + tspec_mask */ +/* special value for searching any Session Id */ +#define SME_QOS_SEARCH_SESSION_ID_ANY WLAN_MAX_VDEVS +#define SME_QOS_ACCESS_POLICY_EDCA 1 +#define SME_QOS_MAX_TID 255 +#define SME_QOS_TSPEC_IE_LENGTH 61 +#define SME_QOS_TSPEC_IE_TYPE 2 +#define SME_QOS_MIN_FLOW_ID 1 +#define SME_QOS_MAX_FLOW_ID 0xFFFFFFFE +#define SME_QOS_INVALID_FLOW_ID 0xFFFFFFFF +/* per the WMM Specification v1.2 Section 2.2.10 */ +/* The Dialog Token field shall be set [...] to a non-zero value */ +#define SME_QOS_MIN_DIALOG_TOKEN 1 +#define SME_QOS_MAX_DIALOG_TOKEN 0xFF + +#ifdef WLAN_FEATURE_MSCS +#define MSCS_USER_PRIORITY 0x07C0 +#define MSCS_STREAM_TIMEOUT 60 /* in sec */ +#define MSCS_TCLAS_CLASSIFIER_MASK 0x5F +#define MSCS_TCLAS_CLASSIFIER_TYPE 4 +#endif + +/* Type declarations */ +/* Enumeration of the various states in the QoS state m/c */ +enum sme_qos_states { + SME_QOS_CLOSED = 0, + SME_QOS_INIT, + SME_QOS_LINK_UP, + SME_QOS_REQUESTED, + SME_QOS_QOS_ON, + SME_QOS_HANDOFF, + +}; +/* Enumeration of the various Release QoS trigger */ +enum sme_qosrel_triggers { + SME_QOS_RELEASE_DEFAULT = 0, + SME_QOS_RELEASE_BY_AP, +}; +/* Enumeration of the various QoS cmds */ +enum sme_qos_cmdtype { + SME_QOS_SETUP_REQ = 0, + SME_QOS_RELEASE_REQ, + SME_QOS_MODIFY_REQ, + SME_QOS_RESEND_REQ, + SME_QOS_CMD_MAX +}; +/* Enumeration of the various QoS reason codes to be used in the Flow list */ +enum sme_qos_reasontype { + SME_QOS_REASON_SETUP = 0, + SME_QOS_REASON_RELEASE, + SME_QOS_REASON_MODIFY, + SME_QOS_REASON_MODIFY_PENDING, + SME_QOS_REASON_REQ_SUCCESS, + SME_QOS_REASON_MAX +}; + +/* Table to map user priority passed in as an argument to appropriate Access + * Category as specified in 802.11e/WMM + */ +enum qca_wlan_ac_type sme_qos_up_to_ac_map[SME_QOS_WMM_UP_MAX] = { + QCA_WLAN_AC_BE, /* User Priority 0 */ + QCA_WLAN_AC_BK, /* User Priority 1 */ + QCA_WLAN_AC_BK, /* User Priority 2 */ + QCA_WLAN_AC_BE, /* User Priority 3 */ + QCA_WLAN_AC_VI, /* User Priority 4 */ + QCA_WLAN_AC_VI, /* User Priority 5 */ + QCA_WLAN_AC_VO, /* User Priority 6 */ + QCA_WLAN_AC_VO /* User Priority 7 */ +}; + +/* + * DESCRIPTION + * SME QoS module's FLOW Link List structure. This list can hold information + * per flow/request, like TSPEC params requested, which AC it is running on + */ +struct sme_qos_flowinfoentry { + tListElem link; /* list links */ + uint8_t sessionId; + uint8_t tspec_mask; + enum sme_qos_reasontype reason; + uint32_t QosFlowID; + enum qca_wlan_ac_type ac_type; + struct sme_qos_wmmtspecinfo QoSInfo; + void *HDDcontext; + sme_QosCallback QoSCallback; + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +}; +/* + * DESCRIPTION + * SME QoS module's setup request cmd related information structure. + */ +struct sme_qos_setupcmdinfo { + uint32_t QosFlowID; + struct sme_qos_wmmtspecinfo QoSInfo; + void *HDDcontext; + sme_QosCallback QoSCallback; + enum sme_qos_wmmuptype UPType; + bool hoRenewal; /* set to true while re-negotiating flows after */ + /* handoff, will set to false once done with */ + /* the process. Helps SME to decide if at all */ + /* to notify HDD/LIS for flow renewal after HO */ +}; +/* + * DESCRIPTION + * SME QoS module's modify cmd related information structure. + */ +struct sme_qos_modifycmdinfo { + uint32_t QosFlowID; + enum qca_wlan_ac_type ac; + struct sme_qos_wmmtspecinfo QoSInfo; +}; +/* + * DESCRIPTION + * SME QoS module's resend cmd related information structure. + */ +struct sme_qos_resendcmdinfo { + uint8_t tspecMask; + enum qca_wlan_ac_type ac; + struct sme_qos_wmmtspecinfo QoSInfo; +}; +/* + * DESCRIPTION + * SME QoS module's release cmd related information structure. + */ +struct sme_qos_releasecmdinfo { + uint32_t QosFlowID; +}; +/* + * DESCRIPTION + * SME QoS module's buffered cmd related information structure. + */ +struct sme_qos_cmdinfo { + enum sme_qos_cmdtype command; + struct mac_context *mac; + uint8_t sessionId; + union { + struct sme_qos_setupcmdinfo setupCmdInfo; + struct sme_qos_modifycmdinfo modifyCmdInfo; + struct sme_qos_resendcmdinfo resendCmdInfo; + struct sme_qos_releasecmdinfo releaseCmdInfo; + } u; +}; +/* + * DESCRIPTION + * SME QoS module's buffered cmd List structure. This list can hold information + * related to any pending cmd from HDD + */ +struct sme_qos_cmdinfoentry { + tListElem link; /* list links */ + struct sme_qos_cmdinfo cmdInfo; +}; +/* + * DESCRIPTION + * SME QoS module's Per AC information structure. This can hold information on + * how many flows running on the AC, the current, previous states the AC is in + */ +struct sme_qos_acinfo { + uint8_t num_flows[SME_QOS_TSPEC_INDEX_MAX]; + enum sme_qos_states curr_state; + enum sme_qos_states prev_state; + struct sme_qos_wmmtspecinfo curr_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; + struct sme_qos_wmmtspecinfo requested_QoSInfo[SME_QOS_TSPEC_INDEX_MAX]; + /* reassoc requested for APSD */ + bool reassoc_pending; + /* + * As per WMM spec there could be max 2 TSPEC running on the same + * AC with different direction. We will refer each TSPEC with an index + */ + /* status showing if both the indices are in use */ + uint8_t tspec_mask_status; + /* tspec negotiation going on for which index */ + uint8_t tspec_pending; + /* set to true while re-negotiating flows after */ + bool hoRenewal; + /* + * handoff, will set to false once done with the process. Helps SME to + * decide if at all to notify HDD/LIS for flow renewal after HO + */ + uint8_t ricIdentifier[SME_QOS_TSPEC_INDEX_MAX]; + /* + * stores the ADD TS response for each AC. The ADD TS response is + * formed by parsing the RIC received in the the reassoc response + */ + tSirAddtsRsp addTsRsp[SME_QOS_TSPEC_INDEX_MAX]; + enum sme_qosrel_triggers relTrig; + +}; +/* + * DESCRIPTION + * SME QoS module's Per session information structure. This can hold + * information on the state of the session + */ +struct sme_qos_sessioninfo { + /* what is this entry's session id */ + uint8_t sessionId; + /* is the session currently active */ + bool sessionActive; + /* All AC info for this session */ + struct sme_qos_acinfo ac_info[QCA_WLAN_AC_ALL]; + /* Bitmask of the ACs with APSD on */ + /* Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored */ + uint8_t apsdMask; + /* association information for this session */ + sme_QosAssocInfo assocInfo; + /* ID assigned to our reassoc request */ + uint32_t roamID; + /* are we in the process of handing off to a different AP */ + bool handoffRequested; + /* commands that are being buffered for this session */ + tDblLinkList bufferedCommandList; + + bool ftHandoffInProgress; + +}; +/* + * DESCRIPTION + * Search key union. We can use the flowID, ac type, or reason to find an + * entry in the flow list + */ +union sme_qos_searchkey { + uint32_t QosFlowID; + enum qca_wlan_ac_type ac_type; + enum sme_qos_reasontype reason; +}; +/* + * DESCRIPTION + * We can either use the flowID or the ac type to find an entry in the flow + * list. The index is a bitmap telling us which key to use. Starting from LSB, + * bit 0 - Flow ID + * bit 1 - AC type + */ +struct sme_qos_searchinfo { + uint8_t sessionId; + uint8_t index; + union sme_qos_searchkey key; + enum sme_qos_wmm_dir_type direction; + uint8_t tspec_mask; +}; + +typedef QDF_STATUS (*sme_QosProcessSearchEntry)(struct mac_context *mac, + tListElem *pEntry); + +static enum sme_qos_statustype sme_qos_internal_setup_req(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + enum sme_qos_wmmuptype UPType, + uint32_t QosFlowID, + bool buffered_cmd, bool hoRenewal); +static enum sme_qos_statustype sme_qos_internal_modify_req(struct mac_context *mac, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd); +static enum sme_qos_statustype sme_qos_internal_release_req(struct mac_context *mac, + uint8_t session_id, + uint32_t QosFlowID, + bool buffered_cmd); +static enum sme_qos_statustype sme_qos_setup(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + enum qca_wlan_ac_type ac); +static QDF_STATUS sme_qos_add_ts_req(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + enum qca_wlan_ac_type ac); +static QDF_STATUS sme_qos_del_ts_req(struct mac_context *mac, + uint8_t sessionId, + enum qca_wlan_ac_type ac, uint8_t tspec_mask); +static QDF_STATUS sme_qos_process_add_ts_rsp(struct mac_context *mac, + void *msg_buf); +static QDF_STATUS sme_qos_process_del_ts_ind(struct mac_context *mac, + void *msg_buf); +static QDF_STATUS sme_qos_process_del_ts_rsp(struct mac_context *mac, + void *msg_buf); +static QDF_STATUS sme_qos_process_assoc_complete_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_reassoc_req_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_reassoc_success_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_reassoc_failure_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_disconnect_ev(struct mac_context *mac, uint8_t + sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_join_req_ev(struct mac_context *mac, uint8_t + sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_handoff_assoc_req_ev(struct mac_context *mac, + uint8_t sessionId, + void *pEvent_info); +static QDF_STATUS sme_qos_process_handoff_success_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info); +static QDF_STATUS sme_qos_process_preauth_success_ind(struct mac_context *mac, + uint8_t sessionId, + void *pEvent_info); +static QDF_STATUS sme_qos_process_set_key_success_ind(struct mac_context *mac, + uint8_t sessionId, + void *pEvent_info); +static QDF_STATUS sme_qos_process_aggr_qos_rsp(struct mac_context *mac, + void *msg_buf); +static QDF_STATUS sme_qos_ft_aggr_qos_req(struct mac_context *mac, uint8_t + sessionId); +static QDF_STATUS sme_qos_process_add_ts_success_rsp(struct mac_context *mac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +static QDF_STATUS sme_qos_process_add_ts_failure_rsp(struct mac_context *mac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp); +static QDF_STATUS sme_qos_aggregate_params( + struct sme_qos_wmmtspecinfo *pInput_Tspec_Info, + struct sme_qos_wmmtspecinfo *pCurrent_Tspec_Info, + struct sme_qos_wmmtspecinfo *pUpdated_Tspec_Info); +static QDF_STATUS sme_qos_update_params(uint8_t sessionId, + enum qca_wlan_ac_type ac, + uint8_t tspec_mask, + struct sme_qos_wmmtspecinfo *pTspec_Info); +static enum qca_wlan_ac_type sme_qos_up_to_ac(enum sme_qos_wmmuptype up); + +static bool +sme_qos_is_acm(struct mac_context *mac, struct bss_description *pSirBssDesc, + enum qca_wlan_ac_type ac, tDot11fBeaconIEs *pIes); + +static tListElem *sme_qos_find_in_flow_list(struct sme_qos_searchinfo + search_key); +static QDF_STATUS sme_qos_find_all_in_flow_list(struct mac_context *mac, + struct sme_qos_searchinfo search_key, + sme_QosProcessSearchEntry fnp); +static void sme_qos_state_transition(uint8_t sessionId, + enum qca_wlan_ac_type ac, + enum sme_qos_states new_state); +static QDF_STATUS sme_qos_buffer_cmd(struct sme_qos_cmdinfo *pcmd, bool + insert_head); +static QDF_STATUS sme_qos_process_buffered_cmd(uint8_t sessionId); +static QDF_STATUS sme_qos_save_assoc_info(struct sme_qos_sessioninfo *pSession, + sme_QosAssocInfo *pAssoc_info); +static QDF_STATUS sme_qos_setup_fnp(struct mac_context *mac, tListElem *pEntry); +static QDF_STATUS sme_qos_modification_notify_fnp(struct mac_context *mac, + tListElem *pEntry); +static QDF_STATUS sme_qos_modify_fnp(struct mac_context *mac, tListElem *pEntry); +static QDF_STATUS sme_qos_del_ts_ind_fnp(struct mac_context *mac, tListElem + *pEntry); +static QDF_STATUS sme_qos_reassoc_success_ev_fnp(struct mac_context *mac, + tListElem *pEntry); +static QDF_STATUS sme_qos_add_ts_failure_fnp(struct mac_context *mac, tListElem + *pEntry); +static QDF_STATUS sme_qos_add_ts_success_fnp(struct mac_context *mac, tListElem + *pEntry); +static bool sme_qos_is_rsp_pending(uint8_t sessionId, enum qca_wlan_ac_type ac); +static bool sme_qos_is_uapsd_active(void); + +static QDF_STATUS sme_qos_buffer_existing_flows(struct mac_context *mac, + uint8_t sessionId); +static QDF_STATUS sme_qos_delete_existing_flows(struct mac_context *mac, + uint8_t sessionId); +static void sme_qos_cleanup_ctrl_blk_for_handoff(struct mac_context *mac, + uint8_t sessionId); +static QDF_STATUS sme_qos_delete_buffered_requests(struct mac_context *mac, + uint8_t sessionId); +static bool sme_qos_validate_requested_params(struct mac_context *mac, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint8_t sessionId); + +static QDF_STATUS qos_issue_command(struct mac_context *mac, uint8_t sessionId, + eSmeCommandType cmdType, + struct sme_qos_wmmtspecinfo *pQoSInfo, + enum qca_wlan_ac_type ac, uint8_t tspec_mask); +/* sme_qos_re_request_add_ts to re-send AddTS for the combined QoS request */ +static enum sme_qos_statustype sme_qos_re_request_add_ts(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pQoSInfo, + enum qca_wlan_ac_type ac, + uint8_t tspecMask); +static void sme_qos_init_a_cs(struct mac_context *mac, uint8_t sessionId); +static QDF_STATUS sme_qos_request_reassoc(struct mac_context *mac, + uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce); +static uint32_t sme_qos_assign_flow_id(void); +static uint8_t sme_qos_assign_dialog_token(void); +static QDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionId, + struct sme_qos_searchinfo search_key, + uint8_t new_tspec_mask); + +/* + * DESCRIPTION + * SME QoS module's internal control block. + */ +struct sme_qos_cb_s { + /* global Mac pointer */ + struct mac_context *mac; + /* All Session Info */ + struct sme_qos_sessioninfo *sessionInfo; + /* All FLOW info */ + tDblLinkList flow_list; + /* default TSPEC params */ + struct sme_qos_wmmtspecinfo *def_QoSInfo; + /* counter for assigning Flow IDs */ + uint32_t nextFlowId; + /* counter for assigning Dialog Tokens */ + uint8_t nextDialogToken; +} sme_qos_cb; + +#ifdef WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY +static inline QDF_STATUS sme_qos_allocate_control_block_buffer(void) +{ + uint32_t buf_size; + + buf_size = WLAN_MAX_VDEVS * sizeof(struct sme_qos_sessioninfo); + sme_qos_cb.sessionInfo = qdf_mem_malloc(buf_size); + if (!sme_qos_cb.sessionInfo) + return QDF_STATUS_E_NOMEM; + + buf_size = QCA_WLAN_AC_ALL * sizeof(struct sme_qos_wmmtspecinfo); + sme_qos_cb.def_QoSInfo = qdf_mem_malloc(buf_size); + + if (!sme_qos_cb.def_QoSInfo) { + qdf_mem_free(sme_qos_cb.sessionInfo); + return QDF_STATUS_E_NOMEM; + } + + return QDF_STATUS_SUCCESS; +} + +static inline void sme_qos_free_control_block_buffer(void) +{ + qdf_mem_free(sme_qos_cb.sessionInfo); + sme_qos_cb.sessionInfo = NULL; + + qdf_mem_free(sme_qos_cb.def_QoSInfo); + sme_qos_cb.def_QoSInfo = NULL; +} + +#else /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ + +struct sme_qos_sessioninfo sessionInfo[WLAN_MAX_VDEVS]; +struct sme_qos_wmmtspecinfo def_QoSInfo[QCA_WLAN_AC_ALL]; + +static inline QDF_STATUS sme_qos_allocate_control_block_buffer(void) +{ + qdf_mem_zero(&sessionInfo, sizeof(sessionInfo)); + sme_qos_cb.sessionInfo = sessionInfo; + qdf_mem_zero(&def_QoSInfo, sizeof(def_QoSInfo)); + sme_qos_cb.def_QoSInfo = def_QoSInfo; + + return QDF_STATUS_SUCCESS; +} + +static inline void sme_qos_free_control_block_buffer(void) +{ + sme_qos_cb.sessionInfo = NULL; + sme_qos_cb.def_QoSInfo = NULL; +} +#endif /* WLAN_ALLOCATE_GLOBAL_BUFFERS_DYNAMICALLY */ + +/* External APIs definitions */ + +/** + * sme_qos_open() - called to initialize SME QoS module. + * @mac: global MAC context + * + * This function must be called before any API call to + * SME QoS module. + * + * Return: QDF_STATUS + */ +QDF_STATUS sme_qos_open(struct mac_context *mac) +{ + struct sme_qos_sessioninfo *pSession; + uint8_t sessionId; + QDF_STATUS status; + + sme_debug("Initializing SME-QoS module"); + /* alloc and init the control block */ + /* (note that this will make all sessions invalid) */ + if (!QDF_IS_STATUS_SUCCESS(sme_qos_allocate_control_block_buffer())) { + sme_err("Failed to allocate buffer"); + return QDF_STATUS_E_NOMEM; + } + sme_qos_cb.mac = mac; + sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; + sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; + + /* init flow list */ + status = csr_ll_open(&sme_qos_cb.flow_list); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("cannot initialize Flow List"); + sme_qos_free_control_block_buffer(); + return QDF_STATUS_E_FAILURE; + } + + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pSession->sessionId = sessionId; + /* initialize the session's per-AC information */ + sme_qos_init_a_cs(mac, sessionId); + /* initialize the session's buffered command list */ + status = csr_ll_open(&pSession->bufferedCommandList); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("cannot initialize cmd list for session %d", + sessionId); + sme_qos_free_control_block_buffer(); + return QDF_STATUS_E_FAILURE; + } + } + + sme_debug("done initializing SME-QoS module"); + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_close() - To close down SME QoS module. There should not be + * any API call into this module after calling this function until another + * call of sme_qos_open. + * + * mac - Pointer to the global MAC parameter structure. + * Return QDF_STATUS + */ +QDF_STATUS sme_qos_close(struct mac_context *mac) +{ + struct sme_qos_sessioninfo *pSession; + enum qca_wlan_ac_type ac; + uint8_t sessionId; + + sme_debug("closing down SME-QoS"); + + /* cleanup control block */ + /* close the flow list */ + csr_ll_close(&sme_qos_cb.flow_list); + /* shut down all of the sessions */ + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession) + continue; + + sme_qos_init_a_cs(mac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + pSession->handoffRequested = false; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(mac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(mac, sessionId); + + /* Clean up the assoc info if already allocated */ + if (pSession->assocInfo.bss_desc) { + qdf_mem_free(pSession->assocInfo.bss_desc); + pSession->assocInfo.bss_desc = NULL; + } + /* close the session's buffered command list */ + csr_ll_close(&pSession->bufferedCommandList); + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) + sme_qos_state_transition(sessionId, ac, SME_QOS_CLOSED); + + pSession->sessionActive = false; + } + sme_qos_free_control_block_buffer(); + sme_debug("closed down QoS"); + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_setup_req() - The SME QoS API exposed to HDD to request for QoS + * on a particular AC. + * @mac_handle: The handle returned by mac_open. + * @sessionId: sessionId returned by sme_open_session. + * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the + * WMM TSPEC related info as defined above, provided by HDD + * @QoSCallback: The callback which is registered per flow while + * requesting for QoS. Used for any notification for the + * flow (i.e. setup success/failure/release) which needs to + * be sent to HDD + * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS + * notification (through the callback) to HDD + * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) + * looking for implicit QoS setup, in that + * case, the pQoSInfo will be NULL & SME will know about the AC + * (from the UP provided in this param) QoS is requested on + * @pQosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow is + * successful + * This function should be called after a link has been + * established, i.e. STA is associated with an AP etc. If the request involves + * admission control on the requested AC, HDD needs to provide the necessary + * Traffic Specification (TSPEC) parameters otherwise SME is going to use the + * default params. + * Return: QDF_STATUS_SUCCESS - Setup is successful. + * Other status means Setup request failed + */ +enum sme_qos_statustype sme_qos_setup_req(mac_handle_t mac_handle, + uint32_t sessionId, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + enum sme_qos_wmmuptype UPType, + uint32_t *pQosFlowID) +{ + struct sme_qos_sessioninfo *pSession; + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + enum sme_qos_statustype status; + + sme_debug("QoS Setup requested by client on session %d", sessionId); + lock_status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + /* Make sure the session is valid */ + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Supplied Session ID %d is invalid", sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Make sure the session is active */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + sme_err("Supplied Session ID %d is inactive", + sessionId); + status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + } else { + /* Assign a Flow ID */ + *pQosFlowID = sme_qos_assign_flow_id(); + sme_debug("QoS request on session %d assigned Flow ID %d", + sessionId, *pQosFlowID); + /* Call the internal function for QoS setup, */ + /* adding a layer of abstraction */ + status = + sme_qos_internal_setup_req(mac, (uint8_t) + sessionId, + pQoSInfo, QoSCallback, + HDDcontext, UPType, + *pQosFlowID, false, + false); + } + } + sme_release_global_lock(&mac->sme); + sme_debug("QoS setup return status on session %d is %d", + sessionId, status); + return status; +} + +/** + * sme_qos_modify_req() - The SME QoS API exposed to HDD to request for + * modification of certain QoS params on a flow running on a particular AC. + * @mac_handle: The handle returned by mac_open. + * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the + * WMM TSPEC related info as defined above, provided by HDD + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow has + * been successful already + * + * This function should be called after a link has been established, + * i.e. STA is associated with an AP etc. & a QoS setup has been successful for + * that flow. If the request involves admission control on the requested AC, + * HDD needs to provide the necessary Traffic Specification (TSPEC) parameters & + * SME might start the renegotiation process through ADDTS. + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. + * Other status means request failed + */ +enum sme_qos_statustype sme_qos_modify_req(mac_handle_t mac_handle, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint32_t QosFlowID) +{ + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + enum sme_qos_statustype status; + + sme_debug("QoS Modify requested by client for Flow %d", QosFlowID); + lock_status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + sme_err("Unable to obtain lock"); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + /* Call the internal function for QoS modify, adding a + * layer of abstraction + */ + status = sme_qos_internal_modify_req(mac, pQoSInfo, QosFlowID, false); + sme_release_global_lock(&mac->sme); + sme_debug("QoS Modify return status on Flow %d is %d", + QosFlowID, status); + return status; +} + +/** + * sme_qos_release_req() - The SME QoS API exposed to HDD to request for + * releasing a QoS flow running on a particular AC. + * + * @mac_handle: The handle returned by mac_open. + * @session_id: session_id returned by sme_open_session. + * @QosFlowID: Identification per flow running on each AC generated by SME + * It is only meaningful if the QoS setup for the flow is successful + * + * This function should be called only if a QoS is set up with a valid FlowID. + * HDD should invoke this API only if an explicit request for QoS release has + * come from Application + * + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +enum sme_qos_statustype sme_qos_release_req(mac_handle_t mac_handle, + uint8_t session_id, + uint32_t QosFlowID) +{ + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + enum sme_qos_statustype status; + + sme_debug("QoS Release requested by client for Flow %d", QosFlowID); + lock_status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + sme_err("Unable to obtain lock"); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + /* Call the internal function for QoS release, adding a + * layer of abstraction + */ + status = sme_qos_internal_release_req(mac, session_id, QosFlowID, + false); + sme_release_global_lock(&mac->sme); + sme_debug("QoS Release return status on Flow %d is %d", + QosFlowID, status); + return status; +} + +void qos_release_command(struct mac_context *mac, tSmeCmd *pCommand) +{ + qdf_mem_zero(&pCommand->u.qosCmd, sizeof(tGenericQosCmd)); + csr_release_command(mac, pCommand); +} + +/** + * sme_qos_msg_processor() - Processes QOS messages + * @mac_ctx: Pointer to the global MAC parameter structure. + * @msg_type: the type of msg passed by PE as defined in wni_api.h + * @msg: a pointer to a buffer that maps to various structures bases. + * + * sme_process_msg() calls this function for the messages that + * are handled by SME QoS module. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS sme_qos_msg_processor(struct mac_context *mac_ctx, + uint16_t msg_type, void *msg) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tListElem *entry = NULL; + tSmeCmd *command; + + sme_debug("msg = %d for QoS", msg_type); + /* switch on the msg type & make the state transition accordingly */ + switch (msg_type) { + case eWNI_SME_ADDTS_RSP: + entry = csr_nonscan_active_ll_peek_head(mac_ctx, + LL_ACCESS_LOCK); + if (!entry) + break; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandAddTs == command->command) { + status = sme_qos_process_add_ts_rsp(mac_ctx, msg); + if (csr_nonscan_active_ll_remove_entry(mac_ctx, entry, + LL_ACCESS_LOCK)) { + qos_release_command(mac_ctx, command); + } + } + break; + case eWNI_SME_DELTS_RSP: + entry = csr_nonscan_active_ll_peek_head(mac_ctx, + LL_ACCESS_LOCK); + if (!entry) + break; + command = GET_BASE_ADDR(entry, tSmeCmd, Link); + if (eSmeCommandDelTs == command->command) { + status = sme_qos_process_del_ts_rsp(mac_ctx, msg); + if (csr_nonscan_active_ll_remove_entry(mac_ctx, entry, + LL_ACCESS_LOCK)) { + qos_release_command(mac_ctx, command); + } + } + break; + case eWNI_SME_DELTS_IND: + status = sme_qos_process_del_ts_ind(mac_ctx, msg); + break; + case eWNI_SME_FT_AGGR_QOS_RSP: + status = sme_qos_process_aggr_qos_rsp(mac_ctx, msg); + break; + default: + /* err msg */ + sme_err("unknown msg type = %d", msg_type); + break; + } + return status; +} + +/** + * sme_qos_process_disconnect_roam_ind() - Delete the existing TSPEC + * flows when roaming due to disconnect is complete. + * @mac - Pointer to the global MAC parameter structure. + * @vdev_id: Vdev id + * + * Return: None + */ +static void +sme_qos_process_disconnect_roam_ind(struct mac_context *mac, + uint8_t vdev_id) +{ + sme_qos_delete_existing_flows(mac, vdev_id); +} + +/* + * sme_qos_csr_event_ind() - The QoS sub-module in SME expects notifications + * from CSR when certain events occur as mentioned in sme_qos_csr_event_indType. + * + * mac - Pointer to the global MAC parameter structure. + * ind - The event occurred of type sme_qos_csr_event_indType. + * pEvent_info - Information related to the event + * Return QDF_STATUS + */ +QDF_STATUS sme_qos_csr_event_ind(struct mac_context *mac, + uint8_t sessionId, + sme_qos_csr_event_indType ind, void *pEvent_info) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + sme_debug("vdev %d event %d", sessionId, ind); + switch (ind) { + case SME_QOS_CSR_ASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = sme_qos_process_assoc_complete_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_reassoc_req_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_COMPLETE: + /* expecting assoc info in pEvent_info */ + status = + sme_qos_process_reassoc_success_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_REASSOC_FAILURE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_reassoc_failure_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_DISCONNECT_REQ: + case SME_QOS_CSR_DISCONNECT_IND: + /* nothing expected in pEvent_info */ + status = sme_qos_process_disconnect_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_JOIN_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_join_req_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_ASSOC_REQ: + /* nothing expected in pEvent_info */ + status = sme_qos_process_handoff_assoc_req_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_HANDOFF_COMPLETE: + /* nothing expected in pEvent_info */ + status = + sme_qos_process_handoff_success_ev(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_PREAUTH_SUCCESS_IND: + status = + sme_qos_process_preauth_success_ind(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_SET_KEY_SUCCESS_IND: + status = + sme_qos_process_set_key_success_ind(mac, sessionId, + pEvent_info); + break; + case SME_QOS_CSR_DISCONNECT_ROAM_COMPLETE: + sme_qos_process_disconnect_roam_ind(mac, sessionId); + status = QDF_STATUS_SUCCESS; + break; + default: + /* Err msg */ + sme_err("On Session %d Unknown Event %d received from CSR", + sessionId, ind); + break; + } + + return status; +} + +/* + * sme_qos_get_acm_mask() - The QoS sub-module API to find out on which ACs + * AP mandates Admission Control (ACM = 1) + * (Bit0:VO; Bit1:VI; Bit2:BK; Bit3:BE all other bits are ignored) + * + * mac - Pointer to the global MAC parameter structure. + * pSirBssDesc - The event occurred of type sme_qos_csr_event_indType. + * Return a bit mask indicating for which ACs AP has ACM set to 1 + */ +uint8_t sme_qos_get_acm_mask(struct mac_context *mac, struct bss_description + *pSirBssDesc, tDot11fBeaconIEs *pIes) +{ + enum qca_wlan_ac_type ac; + uint8_t acm_mask = 0; + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + if (sme_qos_is_acm(mac, pSirBssDesc, ac, pIes)) + acm_mask = acm_mask | (1 << (QCA_WLAN_AC_VO - ac)); + } + + return acm_mask; +} + +/* Internal function definitions */ + +/** + * sme_qos_internal_setup_req() - The SME QoS internal setup request handling + * function. + * + * @mac: Pointer to the global MAC parameter structure. + * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the + * WMM TSPEC related info as defined above, provided by HDD + * @QoSCallback: The callback which is registered per flow while + * requesting for QoS. Used for any notification for the + * flow (i.e. setup success/failure/release) which needs to + * be sent to HDD + * @HDDcontext: A cookie passed by HDD to be used by SME during any QoS + * notification (through the callback) to HDD + * @UPType: Useful only if HDD or any other upper layer module (BAP etc.) + * looking for implicit QoS setup, in that + * case, the pQoSInfo will be NULL & SME will know about the AC + * (from the UP provided in this param) QoS is requested on + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow is + * successful + * @buffered_cmd: tells us if the cmd was a buffered one or fresh from + * client + * + * If the request involves admission control on the requested AC, HDD needs to + * provide the necessary Traffic Specification (TSPEC) parameters otherwise SME + * is going to use the default params. + * + * Return: QDF_STATUS_SUCCESS - Setup is successful. + * Other status means Setup request failed + */ +static enum sme_qos_statustype sme_qos_internal_setup_req(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pQoSInfo, + sme_QosCallback QoSCallback, + void *HDDcontext, + enum sme_qos_wmmuptype UPType, + uint32_t QosFlowID, + bool buffered_cmd, bool hoRenewal) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac; + struct sme_qos_wmmtspecinfo Tspec_Info; + enum sme_qos_states new_state = SME_QOS_CLOSED; + struct sme_qos_flowinfoentry *pentry = NULL; + struct sme_qos_cmdinfo cmd; + enum sme_qos_statustype status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + uint8_t tmask = 0; + uint8_t new_tmask = 0; + struct sme_qos_searchinfo search_key; + QDF_STATUS hstatus; + + sme_debug("invoked on session %d for flow %d", sessionId, QosFlowID); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* if caller sent an empty TSPEC, fill up with the default one */ + if (!pQoSInfo) { + sme_warn("caller sent an empty QoS param list, using defaults"); + /* find the AC with UPType passed in */ + ac = sme_qos_up_to_ac(UPType); + if (QCA_WLAN_AC_ALL == ac) { + sme_err("invalid AC %d from UP %d", ac, UPType); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + Tspec_Info = sme_qos_cb.def_QoSInfo[ac]; + } else { + /* find the AC */ + ac = sme_qos_up_to_ac(pQoSInfo->ts_info.up); + if (QCA_WLAN_AC_ALL == ac) { + sme_err("invalid AC %d from UP %d", ac, + pQoSInfo->ts_info.up); + + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + /* validate QoS params */ + if (!sme_qos_validate_requested_params(mac, pQoSInfo, + sessionId)) { + sme_err("invalid params"); + return SME_QOS_STATUS_SETUP_INVALID_PARAMS_RSP; + } + Tspec_Info = *pQoSInfo; + } + pACInfo = &pSession->ac_info[ac]; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending + * on any AC, which will safeguard the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + sme_debug("buffering the setup request for flow %d in state %d since another request is pending", + QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.setupCmdInfo.HDDcontext = HDDcontext; + cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; + cmd.u.setupCmdInfo.QoSCallback = QoSCallback; + cmd.u.setupCmdInfo.UPType = UPType; + cmd.u.setupCmdInfo.hoRenewal = hoRenewal; + cmd.u.setupCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("couldn't buffer the setup request in state = %d", + pACInfo->curr_state); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + sme_debug("Buffered setup request for flow = %d", QosFlowID); + return SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + } + /* get into the state m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + /* call the internal qos setup logic to decide on if the + * request is NOP, or need reassoc for APSD and/or need to + * send out ADDTS + */ + status = sme_qos_setup(mac, sessionId, &Tspec_Info, ac); + sme_debug("On session %d with AC %d in state SME_QOS_LINK_UP sme_qos_setup returned with status %d", + sessionId, ac, status); + + if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + /* we received an expected "good" status */ + /* create an entry in the flow list */ + pentry = qdf_mem_malloc(sizeof(*pentry)); + if (!pentry) + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + + pentry->ac_type = ac; + pentry->HDDcontext = HDDcontext; + pentry->QoSCallback = QoSCallback; + pentry->hoRenewal = hoRenewal; + pentry->QosFlowID = QosFlowID; + pentry->sessionId = sessionId; + /* since we are in state SME_QOS_LINK_UP this must be + * the first TSPEC on this AC, so use index 0 + * (mask bit 1) + */ + pACInfo->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + Tspec_Info; + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + if (pACInfo->tspec_mask_status && + !pACInfo->reassoc_pending) { + sme_err("On session %d with AC %d in state SME_QOS_LINK_UP tspec_mask_status is %d but should not be set yet", + sessionId, ac, + pACInfo->tspec_mask_status); + qdf_mem_free(pentry); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + if (!pACInfo->reassoc_pending) + /* we didn't request for reassoc, it + * must be a tspec negotiation + */ + pACInfo->tspec_pending = 1; + + pentry->reason = SME_QOS_REASON_SETUP; + new_state = SME_QOS_REQUESTED; + } else { + /* SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_ + * RSP or SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET + * _ALREADY + */ + pentry->reason = SME_QOS_REASON_REQ_SUCCESS; + new_state = SME_QOS_QOS_ON; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + Tspec_Info; + if (buffered_cmd && !pentry->hoRenewal) { + QoSCallback(MAC_HANDLE(mac), + HDDcontext, + &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + status, pentry->QosFlowID); + } + pentry->hoRenewal = false; + } + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0]++; + + /* indicate on which index the flow entry belongs to & + * add it to the Flow List at the end + */ + pentry->tspec_mask = pACInfo->tspec_mask_status; + pentry->QoSInfo = Tspec_Info; + sme_debug("Creating entry on session %d at %pK with flowID %d", + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + sme_err("On session %d unexpected status %d returned by sme_qos_setup", + sessionId, status); + new_state = pACInfo->curr_state; + if (buffered_cmd && hoRenewal) + QoSCallback(MAC_HANDLE(mac), HDDcontext, + &pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + QosFlowID); + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + sme_debug("Buffering setup request for flow %d in state = %d", + QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_SETUP_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.setupCmdInfo.HDDcontext = HDDcontext; + cmd.u.setupCmdInfo.QoSInfo = Tspec_Info; + cmd.u.setupCmdInfo.QoSCallback = QoSCallback; + cmd.u.setupCmdInfo.UPType = UPType; + cmd.u.setupCmdInfo.hoRenewal = hoRenewal; + cmd.u.setupCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("On session %d couldn't buffer the setup request for flow %d in state = %d", + sessionId, QosFlowID, pACInfo->curr_state); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + new_state = pACInfo->curr_state; + break; + case SME_QOS_QOS_ON: + + /* check if multiple flows running on the ac */ + if ((pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] > 0) || + (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { + /* do we need to care about the case where APSD + * needed on ACM = 0 below? + */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) || + sme_qos_is_acm(mac, pSession->assocInfo.bss_desc, + ac, NULL)) { + sme_debug("tspec_mask_status = %d for AC = %d", + pACInfo->tspec_mask_status, ac); + if (!pACInfo->tspec_mask_status) { + sme_err("tspec_mask_status can't be 0 for ac: %d in state: %d", + ac, pACInfo->curr_state); + return status; + } + /* Flow aggregation */ + if (((pACInfo->tspec_mask_status > 0) && + (pACInfo->tspec_mask_status <= + SME_QOS_TSPEC_INDEX_MAX))) { + /* Either of upstream, downstream or + * bidirectional flows are present If + * either of new stream or current + * stream is for bidirecional, aggregate + * the new stream with the current + * streams present and send out + * aggregated Tspec. + */ + if ((Tspec_Info.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) + || (pACInfo-> + curr_QoSInfo[pACInfo-> + tspec_mask_status - + 1].ts_info. + direction == + SME_QOS_WMM_TS_DIR_BOTH)) + /* Aggregate the new stream with + * the current stream(s). + */ + tmask = pACInfo-> + tspec_mask_status; + /* None of new stream or current + * (aggregated) streams are for + * bidirectional. Check if the new + * stream direction matches the current + * stream direction. + */ + else if (pACInfo-> + curr_QoSInfo[pACInfo-> + tspec_mask_status + - + 1].ts_info. + direction == + Tspec_Info.ts_info.direction) + /* Aggregate the new stream with + * the current stream(s). + */ + tmask = + pACInfo->tspec_mask_status; + /* New stream is in different + * direction. + */ + else { + /* No Aggregation. Mark the + * 2nd tpsec index also as + * active. + */ + tmask = + SME_QOS_TSPEC_MASK_CLEAR; + new_tmask = + SME_QOS_TSPEC_MASK_BIT_1_2_SET + & ~pACInfo-> + tspec_mask_status; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + } + } else if (SME_QOS_TSPEC_MASK_BIT_1_2_SET == + pACInfo->tspec_mask_status) { + /* Both uplink and downlink streams are + * present. If new stream is + * bidirectional, aggregate new stream + * with all existing upstreams and down + * streams. Send out new aggregated + * tpsec. + */ + if (Tspec_Info.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) { + /* Only one tspec index (0) will + * be in use after this + * aggregation. + */ + tmask = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_SET; + } + /* New stream is also uni-directional + * Find out the tsepc index with which + * it needs to be aggregated + */ + else if (pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0]. + ts_info.direction != + Tspec_Info.ts_info.direction) + /* Aggregate with 2nd tspec + * index + */ + tmask = + SME_QOS_TSPEC_MASK_BIT_2_SET; + else + /* Aggregate with 1st tspec + * index + */ + tmask = + SME_QOS_TSPEC_MASK_BIT_1_SET; + } else + sme_debug("wrong tmask = %d", + pACInfo->tspec_mask_status); + } else + /* ACM = 0 */ + /* We won't be sending a TSPEC to the AP but + * we still need to aggregate to calculate + * trigger frame parameters + */ + tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; + + sme_debug("tmask = %d, new_tmask = %d in state = %d tspec_mask_status = %d for AC = %d", + tmask, new_tmask, pACInfo->curr_state, + pACInfo->tspec_mask_status, ac); + if (tmask) { + /* create the aggregate TSPEC */ + if (tmask != SME_QOS_TSPEC_MASK_BIT_1_2_SET) { + hstatus = + sme_qos_aggregate_params( + &Tspec_Info, + &pACInfo-> + curr_QoSInfo + [tmask - 1], + &pACInfo-> + requested_QoSInfo + [tmask - 1]); + } else { + /* Aggregate the new bidirectional + * stream with the existing upstreams + * and downstreams in tspec indices 0 + * and 1. + */ + tmask = SME_QOS_TSPEC_MASK_BIT_1_SET; + + hstatus = sme_qos_aggregate_params( + &Tspec_Info, &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + &pACInfo-> + requested_QoSInfo + [tmask - 1]); + if (hstatus == QDF_STATUS_SUCCESS) { + hstatus = + sme_qos_aggregate_params + (&pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_1], + &pACInfo-> + requested_QoSInfo[tmask - 1], + NULL); + } + } + + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + sme_err("failed to aggregate params"); + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + } else { + if (! + (new_tmask > 0 + && new_tmask <= SME_QOS_TSPEC_INDEX_MAX)) { + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + } + tmask = new_tmask; + pACInfo->requested_QoSInfo[tmask - 1] = + Tspec_Info; + } + } else { + sme_err("no flows running for ac = %d while in state = %d", + ac, pACInfo->curr_state); + return status; + } + /* although aggregating, make sure to request on the correct + * UP,TID,PSB and direction + */ + pACInfo->requested_QoSInfo[tmask - 1].ts_info.up = + Tspec_Info.ts_info.up; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.tid = + Tspec_Info.ts_info.tid; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.direction = + Tspec_Info.ts_info.direction; + pACInfo->requested_QoSInfo[tmask - 1].ts_info.psb = + Tspec_Info.ts_info.psb; + status = + sme_qos_setup(mac, sessionId, + &pACInfo->requested_QoSInfo[tmask - 1], + ac); + sme_debug("On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", + sessionId, ac, status); + if ((SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + /* we received an expected "good" status */ + /* create an entry in the flow list */ + pentry = qdf_mem_malloc(sizeof(*pentry)); + if (!pentry) + return SME_QOS_STATUS_SETUP_FAILURE_RSP; + + pentry->ac_type = ac; + pentry->HDDcontext = HDDcontext; + pentry->QoSCallback = QoSCallback; + pentry->hoRenewal = hoRenewal; + pentry->QosFlowID = QosFlowID; + pentry->sessionId = sessionId; + sme_debug("Creating flow %d", QosFlowID); + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) + || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) { + new_state = pACInfo->curr_state; + pentry->reason = SME_QOS_REASON_REQ_SUCCESS; + pACInfo->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; + if (buffered_cmd && !pentry->hoRenewal) { + QoSCallback(MAC_HANDLE(mac), + HDDcontext, + &pACInfo-> + curr_QoSInfo + [SME_QOS_TSPEC_INDEX_0], + status, pentry->QosFlowID); + } + if ( + SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY + == status) { + /* if we are not in handoff, then notify + * all flows on this AC that the + * aggregate TSPEC may have changed + */ + if (!pentry->hoRenewal) { + qdf_mem_zero(&search_key, + sizeof + (struct sme_qos_searchinfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (mac, search_key, + sme_qos_setup_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + sme_err("couldn't notify other entries on this AC =%d", + ac); + } + } + } + pentry->hoRenewal = false; + } else { + /* SME_QOS_STATUS_SETUP_REQ_PENDING_RSP */ + new_state = SME_QOS_REQUESTED; + pentry->reason = SME_QOS_REASON_SETUP; + /* Need this info when addts comes back from PE + * to know on which index of the AC the request + * was from + */ + pACInfo->tspec_pending = tmask; + } + pACInfo->num_flows[tmask - 1]++; + /* indicate on which index the flow entry belongs to & + * add it to the Flow List at the end + */ + pentry->tspec_mask = tmask; + pentry->QoSInfo = Tspec_Info; + sme_debug("On session %d creating entry at %pK with flowID %d", + sessionId, pentry, QosFlowID); + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pentry->link, + true); + } else { + /* unexpected status returned by sme_qos_setup() */ + sme_err("On session %d unexpected status %d returned by sme_qos_setup", + sessionId, status); + new_state = pACInfo->curr_state; + } + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + sme_err("setup requested in unexpected state = %d", + pACInfo->curr_state); + new_state = pACInfo->curr_state; + } + /* If current state is same as previous no need for transition, + * if we are doing reassoc & we are already in handoff state, no need to + * move to requested state. But make sure to set the previous state as + * requested state + */ + if ((new_state != pACInfo->curr_state) && + (!(pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state)))) + sme_qos_state_transition(sessionId, ac, new_state); + + if (pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state)) + pACInfo->prev_state = SME_QOS_REQUESTED; + + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) + (void)sme_qos_process_buffered_cmd(sessionId); + + return status; +} + +/** + * sme_qos_internal_modify_req() - The SME QoS internal function to request + * for modification of certain QoS params on a flow running on a particular AC. + * @mac: Pointer to the global MAC parameter structure. + * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the + * WMM TSPEC related info as defined above, provided by HDD + * @QosFlowID: Identification per flow running on each AC generated by + * SME. It is only meaningful if the QoS setup for the flow has + * been successful already + * + * If the request involves admission control on the requested AC, HDD needs to + * provide the necessary Traffic Specification (TSPEC) parameters & SME might + * start the renegotiation process through ADDTS. + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP - Modification is successful. + * Other status means request failed + */ +static enum sme_qos_statustype sme_qos_internal_modify_req(struct mac_context *mac, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint32_t QosFlowID, + bool buffered_cmd) +{ + tListElem *pEntry = NULL; + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *pNewEntry = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + enum qca_wlan_ac_type ac; + enum sme_qos_states new_state = SME_QOS_CLOSED; + enum sme_qos_statustype status = + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + struct sme_qos_wmmtspecinfo Aggr_Tspec_Info; + struct sme_qos_searchinfo search_key; + struct sme_qos_cmdinfo cmd; + uint8_t sessionId; + QDF_STATUS hstatus; + + sme_debug("invoked for flow %d", QosFlowID); + + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.QosFlowID = QosFlowID; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; + search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; + /* go through the link list to find out the details on the flow */ + pEntry = sme_qos_find_in_flow_list(search_key); + if (!pEntry) { + /* Err msg */ + sme_err("no match found for flowID = %d", QosFlowID); + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + /* find the AC */ + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + + sessionId = flow_info->sessionId; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + + /* validate QoS params */ + if (!sme_qos_validate_requested_params(mac, pQoSInfo, sessionId)) { + sme_err("invalid params"); + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + /* For modify, make sure that direction, TID and UP are not + * being altered + */ + if ((pQoSInfo->ts_info.direction != + flow_info->QoSInfo.ts_info.direction) + || (pQoSInfo->ts_info.up != flow_info->QoSInfo.ts_info.up) + || (pQoSInfo->ts_info.tid != flow_info->QoSInfo.ts_info.tid)) { + sme_err("Modification of direction/tid/up is not allowed"); + + return SME_QOS_STATUS_MODIFY_SETUP_INVALID_PARAMS_RSP; + } + + /* should not be same as previous ioctl parameters */ + if ((pQoSInfo->nominal_msdu_size == + flow_info->QoSInfo.nominal_msdu_size) && + (pQoSInfo->maximum_msdu_size == + flow_info->QoSInfo.maximum_msdu_size) && + (pQoSInfo->min_data_rate == + flow_info->QoSInfo.min_data_rate) && + (pQoSInfo->mean_data_rate == + flow_info->QoSInfo.mean_data_rate) && + (pQoSInfo->peak_data_rate == + flow_info->QoSInfo.peak_data_rate) && + (pQoSInfo->min_service_interval == + flow_info->QoSInfo.min_service_interval) && + (pQoSInfo->max_service_interval == + flow_info->QoSInfo.max_service_interval) && + (pQoSInfo->inactivity_interval == + flow_info->QoSInfo.inactivity_interval) && + (pQoSInfo->suspension_interval == + flow_info->QoSInfo.suspension_interval) && + (pQoSInfo->surplus_bw_allowance == + flow_info->QoSInfo.surplus_bw_allowance)) { + sme_debug("the addts parameters are same as last request, dropping the current request"); + + return SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY; + } + + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending on + * any AC, which will safeguard the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + sme_debug("buffering the modify request for flow %d in state %d since another request is pending", + QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("couldn't buffer the modify request in state = %d", + pACInfo->curr_state); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + sme_debug("Buffered modify request for flow = %d", QosFlowID); + return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + } + /* get into the stat m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_QOS_ON: + /* save the new params adding a new (duplicate) entry in the + * Flow List Once we have decided on OTA exchange needed or + * not we can delete the original one from the List + */ + pNewEntry = qdf_mem_malloc(sizeof(*pNewEntry)); + if (!pNewEntry) + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + + pNewEntry->ac_type = ac; + pNewEntry->sessionId = sessionId; + pNewEntry->HDDcontext = flow_info->HDDcontext; + pNewEntry->QoSCallback = flow_info->QoSCallback; + pNewEntry->QosFlowID = flow_info->QosFlowID; + pNewEntry->reason = SME_QOS_REASON_MODIFY_PENDING; + /* since it is a modify request, use the same index on which + * the flow entry originally was running & add it to the Flow + * List at the end + */ + pNewEntry->tspec_mask = flow_info->tspec_mask; + pNewEntry->QoSInfo = *pQoSInfo; + /* update the entry from Flow List which needed to be + * modified + */ + flow_info->reason = SME_QOS_REASON_MODIFY; + sme_debug("On session %d creating modified entry at %pK with flowID %d", + sessionId, pNewEntry, pNewEntry->QosFlowID); + /* add the new entry under construction to the Flow List */ + csr_ll_insert_tail(&sme_qos_cb.flow_list, &pNewEntry->link, + true); + /* update TSPEC with the new param set */ + hstatus = sme_qos_update_params(sessionId, + ac, pNewEntry->tspec_mask, + &Aggr_Tspec_Info); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + pACInfo->requested_QoSInfo[pNewEntry->tspec_mask - 1] = + Aggr_Tspec_Info; + /* if ACM, send out a new ADDTS */ + status = sme_qos_setup(mac, sessionId, + &pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1], + ac); + sme_debug("On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", + sessionId, ac, status); + + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + new_state = SME_QOS_REQUESTED; + status = + SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + pACInfo->tspec_pending = pNewEntry->tspec_mask; + } else + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP + == status) + || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY + == status)) { + new_state = SME_QOS_QOS_ON; + + qdf_mem_zero(&search_key, + sizeof(struct sme_qos_searchinfo)); + /* delete the original entry in FLOW list which + * got modified + */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + hstatus = sme_qos_find_all_in_flow_list(mac, + search_key, + sme_qos_modify_fnp); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) + status = + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP != + status) { + pACInfo->curr_QoSInfo[pNewEntry-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[pNewEntry-> + tspec_mask - 1]; + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY; + qdf_mem_zero(&search_key, + sizeof + (struct sme_qos_searchinfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (mac, search_key, + sme_qos_modification_notify_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + sme_err("couldn't notify other entries on this AC =%d", + ac); + } + } else + if + (SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP + == status) + status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; + } + if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [pNewEntry-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + + } else { + /* unexpected status returned by + * sme_qos_setup() + */ + sme_err("On session %d unexpected status %d returned by sme_qos_setup", + sessionId, status); + new_state = SME_QOS_QOS_ON; + } + } else { + /* err msg */ + sme_err("sme_qos_update_params() failed"); + new_state = SME_QOS_LINK_UP; + } + /* if we are doing reassoc & we are already in handoff state, + * no need to move to requested state. But make sure to set + * the previous state as requested state + */ + if (!(pACInfo->reassoc_pending && + (SME_QOS_HANDOFF == pACInfo->curr_state))) + sme_qos_state_transition(sessionId, ac, new_state); + else + pACInfo->prev_state = SME_QOS_REQUESTED; + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + sme_debug("Buffering modify request for flow %d in state = %d", + QosFlowID, pACInfo->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_MODIFY_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.modifyCmdInfo.QosFlowID = QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = *pQoSInfo; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("couldn't buffer the modify request in state = %d", + pACInfo->curr_state); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + sme_err("modify requested in unexpected state = %d", + pACInfo->curr_state); + break; + } + if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) + || (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) + (void)sme_qos_process_buffered_cmd(sessionId); + + return status; +} + +/** + * sme_qos_internal_release_req() - release QOS flow on a particular AC + * @mac: Pointer to the global MAC parameter structure. + * @sessionId: sessionId returned by sme_open_session. + * @QosFlowID: Identification per flow running on each AC generated by SME + * It is only meaningful if the QoS setup for the flow is successful + * + * The SME QoS internal function to request + * for releasing a QoS flow running on a particular AC. + + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +static enum sme_qos_statustype sme_qos_internal_release_req(struct mac_context *mac, + uint8_t sessionId, + uint32_t QosFlowID, + bool buffered_cmd) +{ + tListElem *pEntry = NULL; + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + struct sme_qos_flowinfoentry *pDeletedFlow = NULL; + enum qca_wlan_ac_type ac; + enum sme_qos_states new_state = SME_QOS_CLOSED; + enum sme_qos_statustype status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; + struct sme_qos_wmmtspecinfo Aggr_Tspec_Info; + struct sme_qos_searchinfo search_key; + struct sme_qos_cmdinfo cmd; + tCsrRoamModifyProfileFields modifyProfileFields; + bool deltsIssued = false; + QDF_STATUS hstatus; + bool biDirectionalFlowsPresent = false; + bool uplinkFlowsPresent = false; + bool downlinkFlowsPresent = false; + tListElem *pResult = NULL; + mac_handle_t mac_hdl = MAC_HANDLE(mac); + + sme_debug("invoked for flow %d", QosFlowID); + + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.QosFlowID = QosFlowID; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_1; + search_key.sessionId = SME_QOS_SEARCH_SESSION_ID_ANY; + /* go through the link list to find out the details on the flow */ + pEntry = sme_qos_find_in_flow_list(search_key); + + if (!pEntry) { + /* Err msg */ + sme_err("no match found for flowID = %d", QosFlowID); + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!buffered_cmd && + !csr_ll_is_list_empty(&pSession->bufferedCommandList, + false)) { + cmd.command = SME_QOS_RELEASE_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_debug("Buffered release request for flow = %d", + QosFlowID); + return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + } + } + return SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; + } + /* find the AC */ + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + sessionId = flow_info->sessionId; + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Session Id: %d is invalid", sessionId); + return status; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* check to consider the following flowing scenario. + * Addts request is pending on one AC, while APSD requested on another + * which needs a reassoc. Will buffer a request if Addts is pending on + * any AC, which will safeguard the above scenario, & also won't + * confuse PE with back to back Addts or Addts followed by Reassoc + */ + if (sme_qos_is_rsp_pending(sessionId, ac)) { + sme_debug("buffering the release request for flow %d in state %d since another request is pending", + QosFlowID, pACInfo->curr_state); + /* we need to buffer the command */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("couldn't buffer the release request in state = %d", + pACInfo->curr_state); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + sme_debug("Buffered release request for flow = %d", QosFlowID); + return SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + } + /* get into the stat m/c to see if the request can be granted */ + switch (pACInfo->curr_state) { + case SME_QOS_QOS_ON: + sme_debug("tspec_mask_status = %d for AC = %d with entry tspec_mask = %d", + pACInfo->tspec_mask_status, ac, + flow_info->tspec_mask); + + /* check if multiple flows running on the ac */ + if (pACInfo->num_flows[flow_info->tspec_mask - 1] > 1) { + /* don't want to include the flow in the new TSPEC on + * which release is requested + */ + flow_info->reason = SME_QOS_REASON_RELEASE; + + /* Check if the flow being released is for bi-diretional + * Following flows may present in the system. + * a) bi-directional flows + * b) uplink flows + * c) downlink flows. + * If the flow being released is for bidirectional, + * splitting of existing streams into two tspec indices + * is required in case ff (b), (c) are present and not + * (a). In case if split occurs, all upstreams are + * aggregated into tspec index 0, downstreams are + * aggregaed into tspec index 1 and two tspec requests + * for (aggregated) upstream(s) followed by (aggregated) + * downstream(s) is sent to AP. + */ + if (flow_info->QoSInfo.ts_info.direction == + SME_QOS_WMM_TS_DIR_BOTH) { + qdf_mem_zero(&search_key, + sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in + * the Flow List + */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_4; + search_key.sessionId = sessionId; + search_key.direction = SME_QOS_WMM_TS_DIR_BOTH; + pResult = sme_qos_find_in_flow_list(search_key); + if (pResult) + biDirectionalFlowsPresent = true; + + if (!biDirectionalFlowsPresent) { + /* The only existing bidirectional flow + * is being released + */ + + /* Check if uplink flows exist */ + search_key.direction = + SME_QOS_WMM_TS_DIR_UPLINK; + pResult = + sme_qos_find_in_flow_list(search_key); + if (pResult) + uplinkFlowsPresent = true; + + /* Check if downlink flows exist */ + search_key.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + pResult = + sme_qos_find_in_flow_list(search_key); + if (pResult) + downlinkFlowsPresent = true; + + if (uplinkFlowsPresent + && downlinkFlowsPresent) { + /* Need to split the uni- + * directional flows into + * SME_QOS_TSPEC_INDEX_0 and + * SME_QOS_TSPEC_INDEX_1 + */ + + qdf_mem_zero(&search_key, + sizeof + (struct sme_qos_searchinfo)); + /* Mark all downstream flows as + * using tspec index 1 + */ + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_4; + search_key.sessionId = + sessionId; + search_key.direction = + SME_QOS_WMM_TS_DIR_DOWNLINK; + sme_qos_update_tspec_mask + (sessionId, search_key, + SME_QOS_TSPEC_MASK_BIT_2_SET); + + /* Aggregate all downstream + * flows + */ + hstatus = + sme_qos_update_params + (sessionId, ac, + SME_QOS_TSPEC_MASK_BIT_2_SET, + &Aggr_Tspec_Info); + + sme_err("On session %d buffering the AddTS request for AC %d in state %d as Addts is pending on other Tspec index of this AC", + sessionId, ac, + pACInfo->curr_state); + + /* Buffer the (aggregated) tspec + * request for downstream flows. + * Please note that the + * (aggregated) tspec for + * upstream flows is sent out by + * the susequent logic. + */ + cmd.command = + SME_QOS_RESEND_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = + SME_QOS_TSPEC_MASK_BIT_2_SET; + cmd.u.resendCmdInfo.QoSInfo = + Aggr_Tspec_Info; + pACInfo-> + requested_QoSInfo + [SME_QOS_TSPEC_MASK_BIT_2_SET + - 1] = Aggr_Tspec_Info; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd + (&cmd, + false))) { + sme_err("On session %d unable to buffer the AddTS request for AC %d TSPEC %d in state %d", + sessionId, ac, + SME_QOS_TSPEC_MASK_BIT_2_SET, + pACInfo-> + curr_state); + + return + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + pACInfo->tspec_mask_status = + SME_QOS_TSPEC_MASK_BIT_1_2_SET; + + } + } + } + + /* In case of splitting of existing streams, + * tspec_mask will be pointing to tspec index 0 and + * aggregated tspec for upstream(s) is sent out here. + */ + hstatus = sme_qos_update_params(sessionId, + ac, flow_info->tspec_mask, + &Aggr_Tspec_Info); + if (QDF_IS_STATUS_SUCCESS(hstatus)) { + pACInfo->requested_QoSInfo[flow_info-> + tspec_mask - 1] = + Aggr_Tspec_Info; + /* if ACM, send out a new ADDTS */ + status = sme_qos_setup(mac, sessionId, + &pACInfo-> + requested_QoSInfo + [flow_info->tspec_mask - + 1], ac); + sme_debug("On session %d with AC %d in state SME_QOS_QOS_ON sme_qos_setup returned with status %d", + sessionId, ac, status); + + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == + status) { + new_state = SME_QOS_REQUESTED; + status = + SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + pACInfo->tspec_pending = + flow_info->tspec_mask; + } else + if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == status) || (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status)) { + new_state = SME_QOS_QOS_ON; + pACInfo->num_flows[flow_info-> + tspec_mask - 1]--; + pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[flow_info-> + tspec_mask - 1]; + /* delete the entry from Flow List */ + sme_debug("Deleting entry at %pK with flowID %d", + flow_info, QosFlowID); + csr_ll_remove_entry(&sme_qos_cb. + flow_list, pEntry, true); + pDeletedFlow = flow_info; + if (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == status) { + qdf_mem_zero(&search_key, + sizeof + (struct sme_qos_searchinfo)); + search_key.key.ac_type = ac; + search_key.index = + SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = + sessionId; + hstatus = + sme_qos_find_all_in_flow_list + (mac, search_key, + sme_qos_setup_fnp); + if (!QDF_IS_STATUS_SUCCESS + (hstatus)) { + sme_err("couldn't notify other entries on this AC =%d", + ac); + } + } + status = + SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } else { + /* unexpected status returned by + * sme_qos_setup() + */ + sme_err("On session %d unexpected status %d returned by sme_qos_setup", + sessionId, status); + new_state = SME_QOS_LINK_UP; + pACInfo->num_flows[flow_info-> + tspec_mask - 1]--; + pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1] = + pACInfo-> + requested_QoSInfo[flow_info-> + tspec_mask - 1]; + /* delete the entry from Flow List */ + sme_debug("On session %d deleting entry at %pK with flowID %d", + sessionId, flow_info, + QosFlowID); + csr_ll_remove_entry(&sme_qos_cb. + flow_list, + pEntry, true); + pDeletedFlow = flow_info; + if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* err msg */ + sme_err("sme_qos_update_params() failed"); + new_state = SME_QOS_LINK_UP; + if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info-> + HDDcontext, + &pACInfo-> + curr_QoSInfo + [flow_info-> + tspec_mask - 1], + status, + flow_info-> + QosFlowID); + } + } + } else { + /* this is the only flow aggregated in this TSPEC */ + status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + /* check if delts needs to be sent */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) || + sme_qos_is_acm(mac, pSession->assocInfo.bss_desc, + ac, NULL)) { + /* check if other TSPEC for this AC is also + * in use + */ + if (SME_QOS_TSPEC_MASK_BIT_1_2_SET != + pACInfo->tspec_mask_status) { + /* this is the only TSPEC active on this + * AC so indicate that we no longer + * require APSD + */ + pSession->apsdMask &= + ~(1 << (QCA_WLAN_AC_VO - ac)); + /* Also update modifyProfileFields. + * uapsd_mask in CSR for consistency + */ + csr_get_modify_profile_fields(mac, + flow_info-> + sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask = + pSession->apsdMask; + csr_set_modify_profile_fields(mac, + flow_info-> + sessionId, + &modifyProfileFields); + if (!pSession->apsdMask) { + /* this session no longer needs + * UAPSD do any sessions still + * require UAPSD? + */ + if (!sme_qos_is_uapsd_active()) + /* No sessions require + * UAPSD so turn it off + * (really don't care + * when PMC stops it) + */ + sme_ps_uapsd_disable( + mac_hdl, + sessionId); + } + } + if (SME_QOS_RELEASE_DEFAULT == + pACInfo->relTrig) { + /* send delts */ + hstatus = + qos_issue_command(mac, + sessionId, + eSmeCommandDelTs, + NULL, ac, + flow_info-> + tspec_mask); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + sme_err("sme_qos_del_ts_req() failed"); + status = + SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } else { + pACInfo->tspec_mask_status &= + SME_QOS_TSPEC_MASK_BIT_1_2_SET + & (~flow_info->tspec_mask); + deltsIssued = true; + } + } else { + pACInfo->tspec_mask_status &= + SME_QOS_TSPEC_MASK_BIT_1_2_SET & + (~flow_info->tspec_mask); + deltsIssued = true; + } + } else if (pSession->apsdMask & + (1 << (QCA_WLAN_AC_VO - ac))) { + /* reassoc logic */ + csr_get_modify_profile_fields(mac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (QCA_WLAN_AC_VO - ac)); + pSession->apsdMask &= + ~(1 << (QCA_WLAN_AC_VO - ac)); + if (!pSession->apsdMask) { + /* this session no longer needs UAPSD + * do any sessions still require UAPSD? + */ + if (!sme_qos_is_uapsd_active()) + /* No sessions require UAPSD so + * turn it off (really don't + * care when PMC stops it) + */ + sme_ps_uapsd_disable( + mac_hdl, sessionId); + } + hstatus = sme_qos_request_reassoc(mac, + sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + sme_err("Reassoc failed"); + status = + SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } else { + /* no need to wait */ + pACInfo->reassoc_pending = false; + pACInfo->prev_state = SME_QOS_LINK_UP; + pACInfo->tspec_pending = 0; + } + } else { + sme_debug("nothing to do for AC = %d", ac); + } + + if (SME_QOS_RELEASE_BY_AP == pACInfo->relTrig) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - + 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + + sme_debug("Deleting entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + } else if (buffered_cmd) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + NULL, status, + flow_info->QosFlowID); + } + + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == status) + break; + + if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> + tspec_mask) > 0) + && + ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~flow_info-> + tspec_mask) <= SME_QOS_TSPEC_INDEX_MAX)) { + if (pACInfo-> + num_flows[(SME_QOS_TSPEC_MASK_BIT_1_2_SET & + ~flow_info->tspec_mask) - 1] > + 0) + new_state = SME_QOS_QOS_ON; + else + new_state = SME_QOS_LINK_UP; + } else { + sme_debug("Exceeded the array bounds of pACInfo->num_flows"); + return + SME_QOS_STATUS_RELEASE_INVALID_PARAMS_RSP; + } + + if (false == deltsIssued) { + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[flow_info-> + tspec_mask - 1], + sizeof(struct sme_qos_wmmtspecinfo)); + } + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[flow_info->tspec_mask - + 1], + sizeof(struct sme_qos_wmmtspecinfo)); + pACInfo->num_flows[flow_info->tspec_mask - 1]--; + /* delete the entry from Flow List */ + sme_debug("On session %d deleting entry at %pK with flowID %d", + sessionId, flow_info, QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, + true); + pDeletedFlow = flow_info; + pACInfo->relTrig = SME_QOS_RELEASE_DEFAULT; + } + /* if we are doing reassoc & we are already in handoff state, no + * need to move to requested state. But make sure to set the + * previous state as requested state + */ + if (SME_QOS_HANDOFF != pACInfo->curr_state) + sme_qos_state_transition(sessionId, ac, new_state); + + if (pACInfo->reassoc_pending) + pACInfo->prev_state = SME_QOS_REQUESTED; + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + /* buffer cmd */ + cmd.command = SME_QOS_RELEASE_REQ; + cmd.mac = mac; + cmd.sessionId = sessionId; + cmd.u.releaseCmdInfo.QosFlowID = QosFlowID; + hstatus = sme_qos_buffer_cmd(&cmd, buffered_cmd); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("couldn't buffer the release request in state = %d", + pACInfo->curr_state); + return SME_QOS_STATUS_RELEASE_FAILURE_RSP; + } + status = SME_QOS_STATUS_RELEASE_REQ_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + /* print error msg */ + sme_err("release request in unexpected state = %d", + pACInfo->curr_state); + break; + } + /* if we deleted a flow, reclaim the memory */ + if (pDeletedFlow) + qdf_mem_free(pDeletedFlow); + + if (SME_QOS_STATUS_RELEASE_SUCCESS_RSP == status) + (void)sme_qos_process_buffered_cmd(sessionId); + + return status; +} + +/** + * sme_qos_setup() - internal SME QOS setup function. + * @mac: Pointer to the global MAC parameter structure. + * @sessionId: Session upon which setup is being performed + * @pTspec_Info: Pointer to struct sme_qos_wmmtspecinfo which contains the WMM + * TSPEC related info as defined above + * @ac: Enumeration of the various EDCA Access Categories. + * + * The internal qos setup function which has the intelligence + * if the request is NOP, or for APSD and/or need to send out ADDTS. + * It also does the sanity check for QAP, AP supports APSD etc. + * The logic used in the code might be confusing. + * + * Trying to cover all the cases here. + * AP supports App wants ACM = 1 Already set APSD Result + * | 0 | 0 | 0 | 0 | NO ACM NO APSD + * | 0 | 0 | 0 | 1 | NO ACM NO APSD/INVALID + * | 0 | 0 | 1 | 0 | ADDTS + * | 0 | 0 | 1 | 1 | ADDTS + * | 0 | 1 | 0 | 0 | FAILURE + * | 0 | 1 | 0 | 1 | INVALID + * | 0 | 1 | 1 | 0 | ADDTS + * | 0 | 1 | 1 | 1 | ADDTS + * | 1 | 0 | 0 | 0 | NO ACM NO APSD + * | 1 | 0 | 0 | 1 | NO ACM NO APSD + * | 1 | 0 | 1 | 0 | ADDTS + * | 1 | 0 | 1 | 1 | ADDTS + * | 1 | 1 | 0 | 0 | REASSOC + * | 1 | 1 | 0 | 1 | NOP: APSD SET ALREADY + * | 1 | 1 | 1 | 0 | ADDTS + * | 1 | 1 | 1 | 1 | ADDTS + * + * Return: SME_QOS_STATUS_SETUP_SUCCESS_RSP if the setup is successful' + */ +static enum sme_qos_statustype sme_qos_setup(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + enum qca_wlan_ac_type ac) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum sme_qos_statustype status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + tDot11fBeaconIEs *pIes = NULL; + tCsrRoamModifyProfileFields modifyProfileFields; + QDF_STATUS hstatus; + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Session Id %d is invalid", sessionId); + return status; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (!pSession->sessionActive) { + sme_err("Session %d is inactive", sessionId); + return status; + } + if (!pSession->assocInfo.bss_desc) { + sme_err("Session %d has an Invalid BSS Descriptor", sessionId); + return status; + } + hstatus = csr_get_parsed_bss_description_ies(mac, + pSession->assocInfo.bss_desc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("On session %d unable to parse BSS IEs", sessionId); + return status; + } + + /* success so pIes was allocated */ + + if (!CSR_IS_QOS_BSS(pIes)) { + sme_err("On session %d AP doesn't support QoS", sessionId); + qdf_mem_free(pIes); + /* notify HDD through the synchronous status msg */ + return SME_QOS_STATUS_SETUP_NOT_QOS_AP_RSP; + } + + sme_debug("UAPSD/PSB set %d: ", pTspec_Info->ts_info.psb); + + pACInfo = &pSession->ac_info[ac]; + do { + /* is ACM enabled for this AC? */ + if (CSR_IS_ADDTS_WHEN_ACMOFF_SUPPORTED(mac) || + sme_qos_is_acm(mac, pSession->assocInfo.bss_desc, + ac, NULL)) { + /* ACM is enabled for this AC so we must send an + * AddTS + */ + if (pTspec_Info->ts_info.psb && + !(pIes->WMMParams. + qosInfo & SME_QOS_AP_SUPPORTS_APSD) + && !(pIes->WMMInfoAp.uapsd)) { + /* application is looking for APSD but AP + * doesn't support it + */ + sme_err("On session %d AP doesn't support APSD", + sessionId); + break; + } + + if (SME_QOS_MAX_TID == pTspec_Info->ts_info.tid) { + /* App didn't set TID, generate one */ + pTspec_Info->ts_info.tid = + (uint8_t) (SME_QOS_WMM_UP_NC - + pTspec_Info->ts_info.up); + } + /* addts logic */ + hstatus = + qos_issue_command(mac, sessionId, + eSmeCommandAddTs, + pTspec_Info, ac, 0); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("sme_qos_add_ts_req() failed"); + break; + } + sme_debug("On session %d AddTS on AC %d is pending", + sessionId, ac); + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + break; + } + /* ACM is not enabled for this AC */ + /* Is the application looking for APSD? */ + if (0 == pTspec_Info->ts_info.psb) { + /* no, we don't need APSD but check the case, if the + * setup is called as a result of a release or modify + * which boils down to the fact that APSD was set on + * this AC but no longer needed - so we need a reassoc + * for the above case to let the AP know + */ + if (pSession-> + apsdMask & (1 << (QCA_WLAN_AC_VO - ac))) { + /* APSD was formerly enabled on this AC but is + * no longer required so we must reassociate + */ + sme_debug("On session %d reassoc needed to disable APSD on AC %d", + sessionId, ac); + csr_get_modify_profile_fields(mac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask &= + ~(1 << (QCA_WLAN_AC_VO - ac)); + hstatus = + sme_qos_request_reassoc(mac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + sme_err("Unable to request reassociation"); + break; + } else { + sme_debug("On session %d reassociation to enable APSD on AC %d is pending", + sessionId, ac); + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + pACInfo->reassoc_pending = true; + } + } else { + /* we don't need APSD on this AC and we don't + * currently have APSD on this AC + */ + sme_debug("Request is not looking for APSD & Admission Control isn't mandatory for the AC"); + /* return success right away */ + status = + SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP; + } + break; + } else if (!(pIes->WMMParams.qosInfo & SME_QOS_AP_SUPPORTS_APSD) + && !(pIes->WMMInfoAp.uapsd)) { + /* application is looking for APSD but AP doesn't + * support it + */ + sme_err("On session %d AP doesn't support APSD", + sessionId); + break; + } else if (pSession-> + apsdMask & (1 << (QCA_WLAN_AC_VO - ac))) { + /* application is looking for APSD */ + /* and it is already enabled on this AC */ + status = SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY; + sme_debug("Request is looking for APSD and it is already set for the AC"); + break; + } else { + /* application is looking for APSD but it is not enabled on this + * AC so we need to reassociate + */ + sme_debug("On session %d reassoc needed to enable APSD on AC %d", + sessionId, ac); + /* reassoc logic */ + /* update the UAPSD mask to include the new */ + /* AC on which APSD is requested */ + csr_get_modify_profile_fields(mac, sessionId, + &modifyProfileFields); + modifyProfileFields.uapsd_mask |= + pSession->apsdMask; + modifyProfileFields.uapsd_mask |= + 1 << (QCA_WLAN_AC_VO - ac); + hstatus = sme_qos_request_reassoc(mac, sessionId, + &modifyProfileFields, + false); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + /* err msg */ + sme_err("Unable to request reassociation"); + break; + } else { + sme_debug("On session %d reassociation to enable APSD on AC %d is pending", + sessionId, ac); + status = SME_QOS_STATUS_SETUP_REQ_PENDING_RSP; + pACInfo->reassoc_pending = true; + } + } + } while (0); + + qdf_mem_free(pIes); + return status; +} + +/* This is a dummy function now. But the purpose of me adding this was to + * delay the TSPEC processing till SET_KEY completes. This function can be + * used to do any SME_QOS processing after the SET_KEY. As of now, it is + * not required as we are ok with tspec getting programmed before set_key + * as the roam timings are measured without tspec in reassoc! + */ +static QDF_STATUS sme_qos_process_set_key_success_ind(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info) +{ + (void)sme_qos_process_buffered_cmd(sessionId); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_qos_ese_save_tspec_response() - save TSPEC parameters. + * @mac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pTspec: Pointer to the TSPEC IE from the reassoc rsp + * @ac: Access Category for which this TSPEC rsp is received + * @tspecIndex: flow/direction + * + * This function saves the TSPEC parameters that came along in the TSPEC IE + * in the reassoc response + * + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +static QDF_STATUS +sme_qos_ese_save_tspec_response(struct mac_context *mac, uint8_t sessionId, + tDot11fIEWMMTSPEC *pTspec, uint8_t ac, + uint8_t tspecIndex) +{ + tpSirAddtsRsp pAddtsRsp = + &sme_qos_cb.sessionInfo[sessionId].ac_info[ac]. + addTsRsp[tspecIndex]; + + ac = sme_qos_up_to_ac_map[pTspec->user_priority]; + + qdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); + + pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; + pAddtsRsp->length = sizeof(tSirAddtsRsp); + pAddtsRsp->rc = QDF_STATUS_SUCCESS; + pAddtsRsp->sessionId = sessionId; + pAddtsRsp->rsp.dialogToken = 0; + pAddtsRsp->rsp.status = STATUS_SUCCESS; + pAddtsRsp->rsp.wmeTspecPresent = pTspec->present; + sme_debug("Copy Tspec to local data structure ac=%d, tspecIdx=%d", + ac, tspecIndex); + + if (pAddtsRsp->rsp.wmeTspecPresent) + /* Copy TSPEC params received in assoc response to addts + * response + */ + convert_wmmtspec(mac, &pAddtsRsp->rsp.tspec, pTspec); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_ese_process_reassoc_tspec_rsp() - process ese reassoc tspec response + * @mac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pEven_info: Pointer to the smeJoinRsp structure + * + * This function processes the WMM TSPEC IE in the reassoc response. + * Reassoc triggered as part of ESE roaming to another ESE capable AP. + * If the TSPEC was added before reassoc, as part of Call Admission Control, + * the reasso req from the STA would carry the TSPEC parameters which were + * already negotiated with the older AP. + * + * Return: QDF_STATUS_SUCCESS - Release is successful. + */ +static +QDF_STATUS sme_qos_ese_process_reassoc_tspec_rsp(struct mac_context *mac, + uint8_t sessionId, + void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + tDot11fIEWMMTSPEC *pTspecIE = NULL; + struct csr_roam_session *pCsrSession = NULL; + struct csr_roam_connectedinfo *pCsrConnectedInfo = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + uint8_t ac, numTspec, cnt; + uint8_t tspec_flow_index, tspec_mask_status; + uint32_t tspecIeLen; + + pCsrSession = CSR_GET_SESSION(mac, sessionId); + if (!pCsrSession) { + sme_err("session %d not found", sessionId); + return QDF_STATUS_E_FAILURE; + } + pCsrConnectedInfo = &pCsrSession->connectedInfo; + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + /* Get the TSPEC IEs which came along with the reassoc response */ + /* from the pbFrames pointer */ + pTspecIE = + (tDot11fIEWMMTSPEC *) (pCsrConnectedInfo->pbFrames + + pCsrConnectedInfo->nBeaconLength + + pCsrConnectedInfo->nAssocReqLength + + pCsrConnectedInfo->nAssocRspLength + + pCsrConnectedInfo->nRICRspLength); + + /* Get the number of tspecs Ies in the frame, the min length */ + /* should be atleast equal to the one TSPEC IE */ + tspecIeLen = pCsrConnectedInfo->nTspecIeLength; + if (tspecIeLen < sizeof(tDot11fIEWMMTSPEC)) { + sme_err("ESE Tspec IE len %d less than min %zu", + tspecIeLen, sizeof(tDot11fIEWMMTSPEC)); + return QDF_STATUS_E_FAILURE; + } + + sme_warn("TspecLen = %d, pbFrames = %pK, pTspecIE = %pK", + tspecIeLen, pCsrConnectedInfo->pbFrames, pTspecIE); + + numTspec = (tspecIeLen) / sizeof(tDot11fIEWMMTSPEC); + for (cnt = 0; cnt < numTspec; cnt++) { + ac = sme_qos_up_to_ac(pTspecIE->user_priority); + if (ac >= QCA_WLAN_AC_ALL) { + sme_err("ac %d more than it`s max value", ac); + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + tspec_mask_status = pACInfo->tspec_mask_status; + sme_warn("UP=%d, ac=%d, tspec_mask_status=%x", + pTspecIE->user_priority, ac, tspec_mask_status); + + for (tspec_flow_index = 0; + tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; + tspec_flow_index++) { + if (tspec_mask_status & (1 << tspec_flow_index)) { + sme_warn("Found Tspec entry flow = %d AC = %d", + tspec_flow_index, ac); + sme_qos_ese_save_tspec_response(mac, sessionId, + pTspecIE, ac, + tspec_flow_index); + } else { + sme_warn("Not found Tspec entry flow = %d AC = %d", + tspec_flow_index, ac); + } + } + /* Increment the pointer to point it to the next TSPEC IE */ + pTspecIE++; + } + + /* Send the Aggregated QoS request to HAL */ + status = sme_qos_ft_aggr_qos_req(mac, sessionId); + + return status; +} + +/** + * sme_qos_copy_tspec_info() - copy tspec info. + * @mac: Pointer to the global MAC parameter structure. + * @pTspec_Info: source structure + * @pTspec: destination structure + * + * This function copies the existing TSPEC parameters from the source structure + * to the destination structure. + * + * Return: None + */ +static void sme_qos_copy_tspec_info(struct mac_context *mac, + struct sme_qos_wmmtspecinfo *pTspec_Info, + struct mac_tspec_ie *pTspec) +{ + /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum + * Service Interval, Service Start Time, Suspension Interval and Delay + * Bound are all intended for HCCA operation and therefore must be set + * to zero + */ + pTspec->delayBound = pTspec_Info->delay_bound; + pTspec->inactInterval = pTspec_Info->inactivity_interval; + pTspec->length = SME_QOS_TSPEC_IE_LENGTH; + pTspec->maxBurstSz = pTspec_Info->max_burst_size; + pTspec->maxMsduSz = pTspec_Info->maximum_msdu_size; + pTspec->maxSvcInterval = pTspec_Info->max_service_interval; + pTspec->meanDataRate = pTspec_Info->mean_data_rate; + pTspec->mediumTime = pTspec_Info->medium_time; + pTspec->minDataRate = pTspec_Info->min_data_rate; + pTspec->minPhyRate = pTspec_Info->min_phy_rate; + pTspec->minSvcInterval = pTspec_Info->min_service_interval; + pTspec->nomMsduSz = pTspec_Info->nominal_msdu_size; + pTspec->peakDataRate = pTspec_Info->peak_data_rate; + pTspec->surplusBw = pTspec_Info->surplus_bw_allowance; + pTspec->suspendInterval = pTspec_Info->suspension_interval; + pTspec->svcStartTime = pTspec_Info->svc_start_time; + pTspec->tsinfo.traffic.direction = pTspec_Info->ts_info.direction; + + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) + pTspec->tsinfo.traffic.psb = pTspec_Info->ts_info.psb; + else { + pTspec->tsinfo.traffic.psb = 0; + pTspec_Info->ts_info.psb = 0; + } + pTspec->tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; + pTspec->tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; + pTspec->tsinfo.traffic.accessPolicy = SME_QOS_ACCESS_POLICY_EDCA; + pTspec->tsinfo.traffic.burstSizeDefn = + pTspec_Info->ts_info.burst_size_defn; + pTspec->tsinfo.traffic.ackPolicy = pTspec_Info->ts_info.ack_policy; + pTspec->type = SME_QOS_TSPEC_IE_TYPE; + + sme_debug("up = %d, tid = %d", pTspec_Info->ts_info.up, + pTspec_Info->ts_info.tid); +} + +/** + * sme_qos_ese_retrieve_tspec_info() - retrieve tspec info. + * @mac: Pointer to the global MAC parameter structure. + * @sessionId: SME session ID + * @pTspecInfo: Pointer to the structure to carry back the TSPEC parameters + * + * This function is called by CSR when try to create reassoc request message to + * PE - csrSendSmeReassocReqMsg. This functions get the existing tspec + * parameters to be included in the reassoc request. + * + * Return: uint8_t - number of existing negotiated TSPECs + */ +uint8_t sme_qos_ese_retrieve_tspec_info(struct mac_context *mac_ctx, + uint8_t session_id, tTspecInfo *tspec_info) +{ + struct sme_qos_sessioninfo *session; + struct sme_qos_acinfo *ac_info; + uint8_t ac, num_tspec = 0; + tTspecInfo *dst_tspec = tspec_info; + uint8_t tspec_mask; + uint8_t tspec_pending; + + /* TODO: Check if TSPEC has already been established + * if not return + */ + session = &sme_qos_cb.sessionInfo[session_id]; + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + volatile uint8_t index = 0; + + ac_info = &session->ac_info[ac]; + tspec_pending = ac_info->tspec_pending; + tspec_mask = ac_info->tspec_mask_status; + do { + /* + * If a tspec status is pending, take + * requested_QoSInfo for RIC request, + * else use curr_QoSInfo for the + * RIC request + */ + if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) + && (tspec_pending & + SME_QOS_TSPEC_MASK_BIT_1_SET)){ + sme_qos_copy_tspec_info(mac_ctx, + &ac_info->requested_QoSInfo[index], + &dst_tspec->tspec); + dst_tspec->valid = true; + num_tspec++; + dst_tspec++; + } else if ((tspec_mask & SME_QOS_TSPEC_MASK_BIT_1_SET) + && !(tspec_pending & + SME_QOS_TSPEC_MASK_BIT_1_SET)){ + sme_qos_copy_tspec_info(mac_ctx, + &ac_info->curr_QoSInfo[index], + &dst_tspec->tspec); + dst_tspec->valid = true; + num_tspec++; + dst_tspec++; + } + tspec_mask >>= 1; + tspec_pending >>= 1; + index++; + } while (tspec_mask); + } + return num_tspec; +} + +#endif + +#ifdef WLAN_FEATURE_HOST_ROAM +static +QDF_STATUS sme_qos_create_tspec_ricie(struct mac_context *mac, + struct sme_qos_wmmtspecinfo *tspec_info, + uint8_t *ric_buffer, uint32_t *ric_length, + uint8_t *ric_identifier) +{ + tDot11fIERICDataDesc *ric_ie; + uint32_t status; + + if (!ric_buffer || !ric_identifier || ric_length == + NULL) { + sme_err("RIC data is NULL, %pK, %pK, %pK", + ric_buffer, ric_identifier, ric_length); + return QDF_STATUS_E_FAILURE; + } + + ric_ie = qdf_mem_malloc(sizeof(*ric_ie)); + if (!ric_ie) { + sme_err("malloc failed for ric IE"); + return QDF_STATUS_E_NOMEM; + } + + ric_ie->present = 1; + ric_ie->RICData.present = 1; + ric_ie->RICData.resourceDescCount = 1; + ric_ie->RICData.statusCode = 0; + ric_ie->RICData.Identifier = sme_qos_assign_dialog_token(); +#ifndef USE_80211_WMMTSPEC_FOR_RIC + ric_ie->TSPEC.present = 1; + ric_ie->TSPEC.delay_bound = tspec_info->delay_bound; + ric_ie->TSPEC.inactivity_int = tspec_info->inactivity_interval; + ric_ie->TSPEC.burst_size = tspec_info->max_burst_size; + ric_ie->TSPEC.max_msdu_size = tspec_info->maximum_msdu_size; + ric_ie->TSPEC.max_service_int = tspec_info->max_service_interval; + ric_ie->TSPEC.mean_data_rate = tspec_info->mean_data_rate; + ric_ie->TSPEC.medium_time = 0; + ric_ie->TSPEC.min_data_rate = tspec_info->min_data_rate; + ric_ie->TSPEC.min_phy_rate = tspec_info->min_phy_rate; + ric_ie->TSPEC.min_service_int = tspec_info->min_service_interval; + ric_ie->TSPEC.size = tspec_info->nominal_msdu_size; + ric_ie->TSPEC.peak_data_rate = tspec_info->peak_data_rate; + ric_ie->TSPEC.surplus_bw_allowance = tspec_info->surplus_bw_allowance; + ric_ie->TSPEC.suspension_int = tspec_info->suspension_interval; + ric_ie->TSPEC.service_start_time = tspec_info->svc_start_time; + ric_ie->TSPEC.direction = tspec_info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (tspec_info->ts_info.psb) + ric_ie->TSPEC.psb = tspec_info->ts_info.psb; + else + ric_ie->TSPEC.psb = 0; + + ric_ie->TSPEC.tsid = tspec_info->ts_info.tid; + ric_ie->TSPEC.user_priority = tspec_info->ts_info.up; + ric_ie->TSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + *ric_identifier = ric_ie->RICData.Identifier; + + status = dot11f_pack_ie_ric_data_desc(mac, ric_ie, ric_buffer, + sizeof(*ric_ie), ric_length); + if (DOT11F_FAILED(status)) { + sme_err("Packing of RIC Data of length %d failed with status %d", + *ric_length, status); + } +#else /* WMM TSPEC */ + /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum + * Service Interval, Service Start Time, Suspension Interval and Delay + * Bound are all intended for HCCA operation and therefore must be set + * to zero + */ + ric_ie->WMMTSPEC.present = 1; + ric_ie->WMMTSPEC.version = 1; + ric_ie->WMMTSPEC.delay_bound = tspec_info->delay_bound; + ric_ie->WMMTSPEC.inactivity_int = tspec_info->inactivity_interval; + ric_ie->WMMTSPEC.burst_size = tspec_info->max_burst_size; + ric_ie->WMMTSPEC.max_msdu_size = tspec_info->maximum_msdu_size; + ric_ie->WMMTSPEC.max_service_int = tspec_info->max_service_interval; + ric_ie->WMMTSPEC.mean_data_rate = tspec_info->mean_data_rate; + ric_ie->WMMTSPEC.medium_time = 0; + ric_ie->WMMTSPEC.min_data_rate = tspec_info->min_data_rate; + ric_ie->WMMTSPEC.min_phy_rate = tspec_info->min_phy_rate; + ric_ie->WMMTSPEC.min_service_int = tspec_info->min_service_interval; + ric_ie->WMMTSPEC.size = tspec_info->nominal_msdu_size; + ric_ie->WMMTSPEC.peak_data_rate = tspec_info->peak_data_rate; + ric_ie->WMMTSPEC.surplus_bw_allowance = + tspec_info->surplus_bw_allowance; + ric_ie->WMMTSPEC.suspension_int = tspec_info->suspension_interval; + ric_ie->WMMTSPEC.service_start_time = tspec_info->svc_start_time; + ric_ie->WMMTSPEC.direction = tspec_info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (tspec_info->ts_info.psb) + ric_ie->WMMTSPEC.psb = tspec_info->ts_info.psb; + else + ric_ie->WMMTSPEC.psb = 0; + + ric_ie->WMMTSPEC.tsid = tspec_info->ts_info.tid; + ric_ie->WMMTSPEC.user_priority = tspec_info->ts_info.up; + ric_ie->WMMTSPEC.access_policy = SME_QOS_ACCESS_POLICY_EDCA; + + status = dot11f_pack_ie_ric_data_desc(mac, ric_ie, ric_buffer, + sizeof(*ric_ie), ric_length); + if (DOT11F_FAILED(status)) { + sme_err("Packing of RIC Data of length %d failed with status %d", + *ric_length, status); + } +#endif /* 80211_TSPEC */ + *ric_identifier = ric_ie->RICData.Identifier; + + qdf_mem_free(ric_ie); + return status; +} +#endif + +/** + * sme_qos_process_ft_reassoc_req_ev()- processes reassoc request + * + * @session_id: SME Session Id + * + * This function Process reassoc request related to QOS + * + * Return: QDF_STATUS enumeration value. + */ +static QDF_STATUS sme_qos_process_ft_reassoc_req_ev( + uint8_t sessionId) +{ + struct sme_qos_sessioninfo *session; + struct sme_qos_acinfo *ac_info; + uint8_t ac, qos_requested = false; + uint8_t tspec_index; + struct sme_qos_flowinfoentry *flow_info = NULL; + tListElem *entry = NULL; + + sme_debug("Invoked on session %d", sessionId); + + session = &sme_qos_cb.sessionInfo[sessionId]; + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + ac_info = &session->ac_info[ac]; + qos_requested = false; + + for (tspec_index = 0; + tspec_index < SME_QOS_TSPEC_INDEX_MAX; + tspec_index++) { + /* + * Only in the below case, copy the AC's curr + * QoS Info to requested QoS info + */ + if ((ac_info->ricIdentifier[tspec_index] + && !ac_info->tspec_pending) + || (ac_info-> + tspec_mask_status & (1 << tspec_index))) { + sme_debug("Copying the currentQos to requestedQos for AC=%d, flow=%d", + ac, tspec_index); + + ac_info->requested_QoSInfo[tspec_index] = + ac_info->curr_QoSInfo[tspec_index]; + qdf_mem_zero( + &ac_info->curr_QoSInfo[tspec_index], + sizeof(struct sme_qos_wmmtspecinfo)); + qos_requested = true; + } + } + + /* + * Only if the tspec is required, transition the state to + * SME_QOS_REQUESTED for this AC + */ + if (qos_requested) { + switch (ac_info->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, + SME_QOS_REQUESTED); + break; + default: + sme_err("FT Reassoc req event in unexpected state %d", + ac_info->curr_state); + } + } + } + + /* + * At this point of time, we are + * disconnected from the old AP, so it is safe + * to reset all these session variables + */ + session->apsdMask = 0; + + /* + * Now change reason and HO renewal of + * all the flow in this session only + */ + entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!entry) { + sme_debug("Flow List empty, nothing to update"); + return QDF_STATUS_E_FAILURE; + } + + do { + flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, + link); + if (sessionId == flow_info->sessionId) { + sme_debug("Changing FlowID %d reason to SETUP and HO renewal to false", + flow_info->QosFlowID); + flow_info->reason = SME_QOS_REASON_SETUP; + flow_info->hoRenewal = true; + } + entry = csr_ll_next(&sme_qos_cb.flow_list, entry, false); + } while (entry); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_fill_aggr_info - fill QOS Aggregation info + * + * @ac_id - index to the AC + * @ts_id - index to TS for a given AC + * @direction - traffic direction + * @msg - QOS message + * @session - sme session information + * + * this is a helper function to populate aggregation information + * for QOS message. + * + * Return: None + */ +static void sme_qos_fill_aggr_info(int ac_id, int ts_id, + enum sme_qos_wmm_dir_type direction, + tSirAggrQosReq *msg, + struct sme_qos_sessioninfo *session) +{ + sme_debug("Found tspec entry AC=%d, flow=%d, direction = %d", + ac_id, ts_id, direction); + + msg->aggrInfo.aggrAddTsInfo[ac_id].dialogToken = + sme_qos_assign_dialog_token(); + msg->aggrInfo.aggrAddTsInfo[ac_id].lleTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.lleTspecPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].numTclas = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.numTclas; + qdf_mem_copy(msg->aggrInfo.aggrAddTsInfo[ac_id].tclasInfo, + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasInfo, + SIR_MAC_TCLASIE_MAXNUM); + msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProc = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProc; + msg->aggrInfo.aggrAddTsInfo[ac_id].tclasProcPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tclasProcPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].tspec = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.tspec; + msg->aggrInfo.aggrAddTsInfo[ac_id].wmeTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.wmeTspecPresent; + msg->aggrInfo.aggrAddTsInfo[ac_id].wsmTspecPresent = + session->ac_info[ac_id].addTsRsp[ts_id].rsp.wsmTspecPresent; + msg->aggrInfo.tspecIdx |= (1 << ac_id); + + /* Mark the index for this AC as pending for response, which would be */ + /* used to validate the AddTS response from HAL->PE->SME */ + session->ac_info[ac_id].tspec_pending = (1 << ts_id); + +} + +/** + * sme_qos_ft_aggr_qos_req - send aggregated QOS request + * + * @mac_ctx - global MAC context + * @session_id - sme session Id + * + * This function is used to send aggregated QOS request to HAL. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_ft_aggr_qos_req(struct mac_context *mac_ctx, uint8_t + session_id) +{ + tSirAggrQosReq *aggr_req = NULL; + struct sme_qos_sessioninfo *session; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int i, j = 0; + uint8_t direction; + + sme_debug("invoked on session %d", session_id); + + session = &sme_qos_cb.sessionInfo[session_id]; + + aggr_req = qdf_mem_malloc(sizeof(tSirAggrQosReq)); + if (!aggr_req) + return QDF_STATUS_E_NOMEM; + + aggr_req->messageType = eWNI_SME_FT_AGGR_QOS_REQ; + aggr_req->length = sizeof(tSirAggrQosReq); + aggr_req->sessionId = session_id; + aggr_req->timeout = 0; + aggr_req->rspReqd = true; + qdf_mem_copy(&aggr_req->bssid.bytes[0], + &session->assocInfo.bss_desc->bssId[0], + sizeof(struct qdf_mac_addr)); + + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + sme_debug("ac=%d, tspec_mask_status=%x, tspec_index=%d direction = %d", + i, session->ac_info[i].tspec_mask_status, j, + session->ac_info[i].addTsRsp[j].rsp.tspec. + tsinfo.traffic.direction); + /* Check if any flow is active on this AC */ + if (!((session->ac_info[i].tspec_mask_status) & + (1 << j))) + continue; + + direction = session->ac_info[i].addTsRsp[j].rsp.tspec. + tsinfo.traffic.direction; + + if ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || + (direction == SME_QOS_WMM_TS_DIR_BOTH)) + sme_qos_fill_aggr_info(i, j, direction, + aggr_req, session); + } + } + + sme_debug("Sending aggregated message to HAL 0x%x", + aggr_req->aggrInfo.tspecIdx); + + if (QDF_IS_STATUS_SUCCESS(umac_send_mb_message_to_mac(aggr_req))) { + status = QDF_STATUS_SUCCESS; + sme_info("sent down a AGGR QoS req to PE"); + } + + return status; +} + +static +QDF_STATUS sme_qos_process_ftric_response(struct mac_context *mac, + uint8_t sessionId, + tDot11fIERICDataDesc *pRicDataDesc, + uint8_t ac, uint8_t tspecIndex) +{ + uint8_t i = 0; + tpSirAddtsRsp pAddtsRsp = &sme_qos_cb.sessionInfo[sessionId]. + ac_info[ac].addTsRsp[tspecIndex]; + + qdf_mem_zero(pAddtsRsp, sizeof(tSirAddtsRsp)); + + pAddtsRsp->messageType = eWNI_SME_ADDTS_RSP; + pAddtsRsp->length = sizeof(tSirAddtsRsp); + pAddtsRsp->rc = pRicDataDesc->RICData.statusCode; + pAddtsRsp->sessionId = sessionId; + pAddtsRsp->rsp.dialogToken = pRicDataDesc->RICData.Identifier; + pAddtsRsp->rsp.status = pRicDataDesc->RICData.statusCode; + pAddtsRsp->rsp.wmeTspecPresent = pRicDataDesc->TSPEC.present; + if (pAddtsRsp->rsp.wmeTspecPresent) + /* Copy TSPEC params received in RIC response to addts + * response + */ + convert_tspec(mac, &pAddtsRsp->rsp.tspec, + &pRicDataDesc->TSPEC); + + pAddtsRsp->rsp.numTclas = pRicDataDesc->num_TCLAS; + if (pAddtsRsp->rsp.numTclas) { + for (i = 0; i < pAddtsRsp->rsp.numTclas; i++) + /* Copy TCLAS info per index to the addts response */ + convert_tclas(mac, &pAddtsRsp->rsp.tclasInfo[i], + &pRicDataDesc->TCLAS[i]); + } + + pAddtsRsp->rsp.tclasProcPresent = pRicDataDesc->TCLASSPROC.present; + if (pAddtsRsp->rsp.tclasProcPresent) + pAddtsRsp->rsp.tclasProc = pRicDataDesc->TCLASSPROC.processing; + + pAddtsRsp->rsp.schedulePresent = pRicDataDesc->Schedule.present; + if (pAddtsRsp->rsp.schedulePresent) { + /* Copy Schedule IE params to addts response */ + convert_schedule(mac, &pAddtsRsp->rsp.schedule, + &pRicDataDesc->Schedule); + } + /* Need to check the below portion is a part of WMM TSPEC */ + /* Process Delay element */ + if (pRicDataDesc->TSDelay.present) + convert_ts_delay(mac, &pAddtsRsp->rsp.delay, + &pRicDataDesc->TSDelay); + + /* Need to call for WMMTSPEC */ + if (pRicDataDesc->WMMTSPEC.present) + convert_wmmtspec(mac, &pAddtsRsp->rsp.tspec, + &pRicDataDesc->WMMTSPEC); + + /* return sme_qos_process_add_ts_rsp(mac, &addtsRsp); */ + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_aggr_qos_rsp - process qos aggregation response + * + * @mac_ctx - global mac context + * @msgbuf - SME message buffer + * + * this function process the QOS aggregation response received. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_process_aggr_qos_rsp(struct mac_context *mac_ctx, + void *msgbuf) +{ + tpSirAggrQosRsp rsp = (tpSirAggrQosRsp) msgbuf; + tSirAddtsRsp addtsrsp; + QDF_STATUS status = QDF_STATUS_SUCCESS; + int i, j = 0; + uint8_t sessionid = rsp->sessionId; + + sme_debug("Received AGGR_QOS resp from LIM"); + + /* Copy the updated response information for TSPEC of all the ACs */ + for (i = 0; i < QCA_WLAN_AC_ALL; i++) { + uint8_t tspec_mask_status = + sme_qos_cb.sessionInfo[sessionid].ac_info[i]. + tspec_mask_status; + for (j = 0; j < SME_QOS_TSPEC_INDEX_MAX; j++) { + uint8_t direction = + sme_qos_cb.sessionInfo[sessionid]. + ac_info[i].addTsRsp[j].rsp.tspec.tsinfo.traffic. + direction; + + sme_debug("Addts rsp from LIM AC=%d, flow=%d dir=%d, tspecIdx=%x", + i, j, direction, rsp->aggrInfo.tspecIdx); + + /* Check if the direction is Uplink or bi-directional */ + if (!(((1 << i) & rsp->aggrInfo.tspecIdx) && + ((tspec_mask_status) & (1 << j)) && + ((direction == SME_QOS_WMM_TS_DIR_UPLINK) || + (direction == SME_QOS_WMM_TS_DIR_BOTH)))) { + continue; + } + addtsrsp = + sme_qos_cb.sessionInfo[sessionid].ac_info[i]. + addTsRsp[j]; + addtsrsp.rc = rsp->aggrInfo.aggrRsp[i].status; + addtsrsp.rsp.status = rsp->aggrInfo.aggrRsp[i].status; + addtsrsp.rsp.tspec = rsp->aggrInfo.aggrRsp[i].tspec; + + sme_debug("Processing Addts rsp from LIM AC=%d, flow=%d", + i, j); + /* post ADD TS response for each */ + if (sme_qos_process_add_ts_rsp(mac_ctx, &addtsrsp) != + QDF_STATUS_SUCCESS) + status = QDF_STATUS_E_FAILURE; + } + } + return status; +} + +/** + * sme_qos_find_matching_tspec() - utility function to find matching tspec + * @mac_ctx: global MAC context + * @sessionid: session ID + * @ac: AC index + * @ac_info: Current AC info + * @ric_data_desc: pointer to ric data + * @ric_rsplen: pointer to ric response length + * + * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev + * to find the matching tspec + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_find_matching_tspec(struct mac_context *mac_ctx, + uint8_t sessionid, uint8_t ac, struct sme_qos_acinfo *ac_info, + tDot11fIERICDataDesc *ric_data_desc, uint32_t *ric_rsplen) +{ + uint8_t tspec_flow_index; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sme_debug("invoked on session %d", sessionid); + + for (tspec_flow_index = 0; + tspec_flow_index < SME_QOS_TSPEC_INDEX_MAX; tspec_flow_index++) { + /* + * Only in the below case, copy the AC's curr QoS Info + * to requested QoS info + */ + if (!ac_info->ricIdentifier[tspec_flow_index]) + continue; + + if (!*ric_rsplen) { + sme_err("RIC Response not received for AC %d on TSPEC Index %d, RIC Req Identifier = %d", + ac, tspec_flow_index, + ac_info->ricIdentifier[tspec_flow_index]); + continue; + } + /* Now we got response for this identifier. Process it. */ + if (!ric_data_desc->present) + continue; + if (!ric_data_desc->RICData.present) + continue; + + if (ric_data_desc->RICData.Identifier != + ac_info->ricIdentifier[tspec_flow_index]) { + sme_err("RIC response order not same as request sent. Request ID = %d, Response ID = %d", + ac_info->ricIdentifier[tspec_flow_index], + ric_data_desc->RICData.Identifier); + } else { + sme_debug("Processing RIC Response for AC %d, TSPEC Flow index %d with RIC ID %d", + ac, tspec_flow_index, + ric_data_desc->RICData.Identifier); + status = sme_qos_process_ftric_response(mac_ctx, + sessionid, ric_data_desc, ac, + tspec_flow_index); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Failed with status %d for AC %d in TSPEC Flow index = %d", + status, ac, tspec_flow_index); + } + } + ric_data_desc++; + *ric_rsplen -= sizeof(tDot11fIERICDataDesc); + } + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * sme_qos_find_matching_tspec_lfr3() - utility function to find matching tspec + * @mac_ctx: global MAC context + * @sessionid: session ID + * @ac: AC index + * @qos_session: QOS session + * @ric_data_desc: pointer to ric data + * @ric_rsplen: ric response length + * + * This utility function is called by sme_qos_process_ft_reassoc_rsp_ev + * to find the matching tspec while LFR3 is enabled. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_find_matching_tspec_lfr3(struct mac_context *mac_ctx, + uint8_t sessionid, uint8_t ac, struct sme_qos_sessioninfo + *qos_session, + tDot11fIERICDataDesc *ric_data_desc, uint32_t ric_rsplen) +{ + struct sme_qos_acinfo *ac_info; + uint8_t tspec_flow_idx; + bool found = false; + enum sme_qos_wmm_dir_type direction, qos_dir; + uint8_t ac1; + tDot11fIERICDataDesc *ric_data = NULL; + uint32_t ric_len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + sme_debug("invoked on session %d", sessionid); + + if (ac == QCA_WLAN_AC_ALL) { + sme_err("Invalid AC %d", ac); + return QDF_STATUS_E_FAILURE; + } + ric_data = ric_data_desc; + ric_len = ric_rsplen; + ac_info = &qos_session->ac_info[ac]; + for (tspec_flow_idx = 0; tspec_flow_idx < SME_QOS_TSPEC_INDEX_MAX; + tspec_flow_idx++) { + if (!((qos_session->ac_info[ac].tspec_mask_status) & + (1 << tspec_flow_idx))) + goto sme_qos_next_ric; + qos_dir = + ac_info->requested_QoSInfo[tspec_flow_idx].ts_info.direction; + do { + ac1 = sme_qos_up_to_ac( + ric_data->WMMTSPEC.user_priority); + if (ac1 == QCA_WLAN_AC_ALL) { + sme_err("Invalid AC %d UP %d", ac1, + ric_data->WMMTSPEC.user_priority); + break; + } + direction = ric_data->WMMTSPEC.direction; + if (ac == ac1 && direction == qos_dir) { + found = true; + status = sme_qos_process_ftric_response(mac_ctx, + sessionid, ric_data, ac, + tspec_flow_idx); + if (QDF_STATUS_SUCCESS != status) { + sme_err("Failed with status %d for AC %d in TSPEC Flow index = %d", + status, ac, tspec_flow_idx); + } + break; + } + ric_data++; + ric_len -= sizeof(tDot11fIERICDataDesc); + } while (ric_len); +sme_qos_next_ric: + ric_data = ric_data_desc; + ric_len = ric_rsplen; + found = false; + } + + return status; +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +static +QDF_STATUS sme_qos_process_ft_reassoc_rsp_ev(struct mac_context *mac_ctx, + uint8_t sessionid, void *event_info) +{ + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_acinfo *ac_info; + uint8_t ac; + tDot11fIERICDataDesc *ric_data_desc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct csr_roam_session *csr_session = CSR_GET_SESSION(mac_ctx, + sessionid); + struct csr_roam_connectedinfo *csr_conn_info = NULL; + uint32_t ric_rsplen; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + tDot11fIERICDataDesc *ric_data = NULL; + uint32_t ric_len; +#endif + + if (!csr_session) { + sme_err("The Session pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + csr_conn_info = &csr_session->connectedInfo; + ric_rsplen = csr_conn_info->nRICRspLength; + + sme_debug("invoked on session %d", sessionid); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + ric_data_desc = (tDot11fIERICDataDesc *) ((csr_conn_info->pbFrames) + + (csr_conn_info->nBeaconLength + + csr_conn_info->nAssocReqLength + + csr_conn_info->nAssocRspLength)); + + if (!wlan_cm_is_roam_sync_in_progress(mac_ctx->psoc, sessionid)) { + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + ac_info = &qos_session->ac_info[ac]; + sme_qos_find_matching_tspec(mac_ctx, sessionid, ac, + ac_info, ric_data_desc, &ric_rsplen); + } + + if (ric_rsplen) { + sme_err("RIC Resp still follows . Rem len = %d", + ric_rsplen); + } +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + } else { + sme_debug("LFR3-11r Compare RIC in Reassoc Resp to find matching tspec in host"); + ric_data = ric_data_desc; + ric_len = ric_rsplen; + if (ric_rsplen && ric_data_desc->present && + ric_data_desc->WMMTSPEC.present) { + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; + ac++) { + sme_qos_find_matching_tspec_lfr3(mac_ctx, + sessionid, ac, qos_session, ric_data, + ric_len); + } + } else + sme_debug("LFR3-11r ric_rsplen is zero or ric_data_desc is not present or wmmtspec is not present"); +#endif + } + + /* Send the Aggregated QoS request to HAL */ + status = sme_qos_ft_aggr_qos_req(mac_ctx, sessionid); + + return status; +} + +#ifdef WLAN_FEATURE_MSCS +void sme_send_mscs_action_frame(uint8_t vdev_id) +{ + struct mscs_req_info *mscs_req; + struct sme_qos_sessioninfo *qos_session; + struct scheduler_msg msg = {0}; + QDF_STATUS qdf_status; + + qos_session = &sme_qos_cb.sessionInfo[vdev_id]; + if (!qos_session) { + sme_debug("qos_session is NULL"); + return; + } + mscs_req = qdf_mem_malloc(sizeof(*mscs_req)); + if (!mscs_req) + return; + + mscs_req->vdev_id = vdev_id; + if (!qos_session->assocInfo.bss_desc) { + sme_err("BSS descriptor is NULL so we won't send request to PE"); + qdf_mem_free(mscs_req); + return; + } + qdf_mem_copy(&mscs_req->bssid.bytes[0], + &qos_session->assocInfo.bss_desc->bssId[0], + sizeof(struct qdf_mac_addr)); + + mscs_req->dialog_token = sme_qos_assign_dialog_token(); + mscs_req->dec.request_type = SCS_REQ_ADD; + mscs_req->dec.user_priority_control = MSCS_USER_PRIORITY; + mscs_req->dec.stream_timeout = (MSCS_STREAM_TIMEOUT * 1000); + mscs_req->dec.tclas_mask.classifier_type = MSCS_TCLAS_CLASSIFIER_TYPE; + mscs_req->dec.tclas_mask.classifier_mask = MSCS_TCLAS_CLASSIFIER_MASK; + + msg.type = eWNI_SME_MSCS_REQ; + msg.reserved = 0; + msg.bodyptr = mscs_req; + qdf_status = scheduler_post_message(QDF_MODULE_ID_SME, QDF_MODULE_ID_PE, + QDF_MODULE_ID_PE, &msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + sme_err("Fail to send mscs request to PE"); + qdf_mem_free(mscs_req); + } +} +#endif + +/** + * sme_qos_add_ts_req() - send ADDTS request. + * @mac: Pointer to the global MAC parameter structure. + * @sessionId: Session upon which the TSPEC should be added + * @pTspec_Info: Pointer to struct sme_qos_wmmtspecinfo which contains the WMM + * TSPEC related info as defined above + * @ac: Enumeration of the various EDCA Access Categories. + * + * This function is used to send down the ADDTS request with TSPEC params to PE + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_add_ts_req(struct mac_context *mac, + uint8_t sessionId, + struct sme_qos_wmmtspecinfo *pTspec_Info, + enum qca_wlan_ac_type ac) +{ + tSirAddtsReq *pMsg = NULL; + struct sme_qos_sessioninfo *pSession; + QDF_STATUS status = QDF_STATUS_E_FAILURE; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + sme_debug("invoked on session %d for AC %d", sessionId, ac); + if (sessionId >= WLAN_MAX_VDEVS) { + /* err msg */ + sme_err("sessionId(%d) is invalid", sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pMsg = qdf_mem_malloc(sizeof(tSirAddtsReq)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + pMsg->messageType = eWNI_SME_ADDTS_REQ; + pMsg->length = sizeof(tSirAddtsReq); + pMsg->sessionId = sessionId; + pMsg->timeout = 0; + pMsg->rspReqd = true; + pMsg->req.dialogToken = sme_qos_assign_dialog_token(); + /* As per WMM_AC_testplan_v0.39 Minimum Service Interval, Maximum + * Service Interval, Service Start Time, Suspension Interval and Delay + * Bound are all intended for HCCA operation and therefore must be set + * to zero + */ + pMsg->req.tspec.delayBound = 0; + pMsg->req.tspec.inactInterval = pTspec_Info->inactivity_interval; + pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; + pMsg->req.tspec.maxBurstSz = pTspec_Info->max_burst_size; + pMsg->req.tspec.maxMsduSz = pTspec_Info->maximum_msdu_size; + pMsg->req.tspec.maxSvcInterval = pTspec_Info->max_service_interval; + pMsg->req.tspec.meanDataRate = pTspec_Info->mean_data_rate; + pMsg->req.tspec.mediumTime = pTspec_Info->medium_time; + pMsg->req.tspec.minDataRate = pTspec_Info->min_data_rate; + pMsg->req.tspec.minPhyRate = pTspec_Info->min_phy_rate; + pMsg->req.tspec.minSvcInterval = pTspec_Info->min_service_interval; + pMsg->req.tspec.nomMsduSz = pTspec_Info->nominal_msdu_size; + pMsg->req.tspec.peakDataRate = pTspec_Info->peak_data_rate; + pMsg->req.tspec.surplusBw = pTspec_Info->surplus_bw_allowance; + pMsg->req.tspec.suspendInterval = pTspec_Info->suspension_interval; + pMsg->req.tspec.svcStartTime = 0; + pMsg->req.tspec.tsinfo.traffic.direction = + pTspec_Info->ts_info.direction; + /* Make sure UAPSD is allowed */ + if (pTspec_Info->ts_info.psb) { + pMsg->req.tspec.tsinfo.traffic.psb = pTspec_Info->ts_info.psb; + } else { + pMsg->req.tspec.tsinfo.traffic.psb = 0; + pTspec_Info->ts_info.psb = 0; + } + pMsg->req.tspec.tsinfo.traffic.tsid = pTspec_Info->ts_info.tid; + pMsg->req.tspec.tsinfo.traffic.userPrio = pTspec_Info->ts_info.up; + pMsg->req.tspec.tsinfo.traffic.accessPolicy = + SME_QOS_ACCESS_POLICY_EDCA; + pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = + pTspec_Info->ts_info.burst_size_defn; + pMsg->req.tspec.tsinfo.traffic.ackPolicy = + pTspec_Info->ts_info.ack_policy; + pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; + /*Fill the BSSID pMsg->req.bssId */ + if (!pSession->assocInfo.bss_desc) { + sme_err("BSS descriptor is NULL so we don't send request to PE"); + qdf_mem_free(pMsg); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&pMsg->bssid.bytes[0], + &pSession->assocInfo.bss_desc->bssId[0], + sizeof(struct qdf_mac_addr)); + sme_debug("up = %d, tid = %d", + pTspec_Info->ts_info.up, pTspec_Info->ts_info.tid); +#ifdef FEATURE_WLAN_ESE + if (wlan_cm_get_ese_assoc(mac->pdev, sessionId)) { + pMsg->req.tsrsIE.tsid = pTspec_Info->ts_info.up; + pMsg->req.tsrsPresent = 1; + } +#endif + if (QDF_IS_STATUS_SUCCESS(umac_send_mb_message_to_mac(pMsg))) { + status = QDF_STATUS_SUCCESS; + sme_debug("sent down a ADDTS req to PE"); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_REQ; + qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + } + return status; +} + +/* + * sme_qos_del_ts_req() - To send down the DELTS request with TSPEC params + * to PE + * + * mac - Pointer to the global MAC parameter structure. + * sessionId - Session from which the TSPEC should be deleted + * ac - Enumeration of the various EDCA Access Categories. + * tspec_mask - on which tspec per AC, the delts is requested + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_del_ts_req(struct mac_context *mac, + uint8_t sessionId, + enum qca_wlan_ac_type ac, uint8_t tspec_mask) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + tSirDeltsReq *pMsg; + struct sme_qos_wmmtspecinfo *pTspecInfo; + struct mac_ts_info tsinfo; + +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + sme_debug("invoked on session %d for AC %d", sessionId, ac); + pMsg = qdf_mem_malloc(sizeof(tSirDeltsReq)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + /* get pointer to the TSPEC being deleted */ + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + pTspecInfo = &pACInfo->curr_QoSInfo[tspec_mask - 1]; + pMsg->messageType = eWNI_SME_DELTS_REQ; + pMsg->length = sizeof(tSirDeltsReq); + pMsg->sessionId = sessionId; + pMsg->rspReqd = true; + pMsg->req.tspec.delayBound = pTspecInfo->delay_bound; + pMsg->req.tspec.inactInterval = pTspecInfo->inactivity_interval; + pMsg->req.tspec.length = SME_QOS_TSPEC_IE_LENGTH; + pMsg->req.tspec.maxBurstSz = pTspecInfo->max_burst_size; + pMsg->req.tspec.maxMsduSz = pTspecInfo->maximum_msdu_size; + pMsg->req.tspec.maxSvcInterval = pTspecInfo->max_service_interval; + pMsg->req.tspec.meanDataRate = pTspecInfo->mean_data_rate; + pMsg->req.tspec.mediumTime = pTspecInfo->medium_time; + pMsg->req.tspec.minDataRate = pTspecInfo->min_data_rate; + pMsg->req.tspec.minPhyRate = pTspecInfo->min_phy_rate; + pMsg->req.tspec.minSvcInterval = pTspecInfo->min_service_interval; + pMsg->req.tspec.nomMsduSz = pTspecInfo->nominal_msdu_size; + pMsg->req.tspec.peakDataRate = pTspecInfo->peak_data_rate; + pMsg->req.tspec.surplusBw = pTspecInfo->surplus_bw_allowance; + pMsg->req.tspec.suspendInterval = pTspecInfo->suspension_interval; + pMsg->req.tspec.svcStartTime = pTspecInfo->svc_start_time; + pMsg->req.tspec.tsinfo.traffic.direction = + pTspecInfo->ts_info.direction; + pMsg->req.tspec.tsinfo.traffic.psb = pTspecInfo->ts_info.psb; + pMsg->req.tspec.tsinfo.traffic.tsid = pTspecInfo->ts_info.tid; + pMsg->req.tspec.tsinfo.traffic.userPrio = pTspecInfo->ts_info.up; + pMsg->req.tspec.tsinfo.traffic.accessPolicy = + SME_QOS_ACCESS_POLICY_EDCA; + pMsg->req.tspec.tsinfo.traffic.burstSizeDefn = + pTspecInfo->ts_info.burst_size_defn; + pMsg->req.tspec.tsinfo.traffic.ackPolicy = + pTspecInfo->ts_info.ack_policy; + pMsg->req.tspec.type = SME_QOS_TSPEC_IE_TYPE; + /*Fill the BSSID pMsg->req.bssId */ + if (!pSession->assocInfo.bss_desc) { + sme_err("BSS descriptor is NULL so we don't send request to PE"); + qdf_mem_free(pMsg); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&pMsg->bssid.bytes[0], + &pSession->assocInfo.bss_desc->bssId[0], + sizeof(struct qdf_mac_addr)); + + sme_debug("up = %d, tid = %d", + pTspecInfo->ts_info.up, pTspecInfo->ts_info.tid); + qdf_mem_zero(&pACInfo->curr_QoSInfo[tspec_mask - 1], + sizeof(struct sme_qos_wmmtspecinfo)); + qdf_mem_copy(&tsinfo, &pMsg->req.tspec.tsinfo, + sizeof(struct mac_ts_info)); + + if (!QDF_IS_STATUS_SUCCESS(umac_send_mb_message_to_mac(pMsg))) { + sme_err("DELTS req to PE failed"); + return QDF_STATUS_E_FAILURE; + } + + sme_debug("sent down a DELTS req to PE"); +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_DELTS; + qos.reasonCode = SME_QOS_DIAG_USER_REQUESTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif + + sme_set_tspec_uapsd_mask_per_session(mac, &tsinfo, sessionId); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_add_ts_rsp() - Function to process the + * eWNI_SME_ADDTS_RSP came from PE + * + * @mac - Pointer to the global MAC parameter structure. + * @msg_buf - Pointer to the msg buffer came from PE. + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_add_ts_rsp(struct mac_context *mac, + void *msg_buf) +{ + tpSirAddtsRsp paddts_rsp = (tpSirAddtsRsp) msg_buf; + struct sme_qos_sessioninfo *pSession; + uint8_t sessionId = paddts_rsp->sessionId; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum sme_qos_wmmuptype up = + (enum sme_qos_wmmuptype) + paddts_rsp->rsp.tspec.tsinfo.traffic.userPrio; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + sme_debug("invoked on session %d for UP %d", sessionId, up); + + ac = sme_qos_up_to_ac(up); + if (QCA_WLAN_AC_ALL == ac) { + /* err msg */ + sme_err("invalid AC %d from UP %d", ac, up); + + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_HANDOFF == pACInfo->curr_state) { + sme_debug("ADDTS Rsp received for AC %d in HANDOFF State. Dropping", + ac); + return QDF_STATUS_SUCCESS; + } + + sme_debug("Invoked on session %d with return code %d", + sessionId, paddts_rsp->rc); + if (paddts_rsp->rc) { + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_RSP; + qos.reasonCode = SME_QOS_DIAG_ADDTS_REFUSED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + status = + sme_qos_process_add_ts_failure_rsp(mac, sessionId, + &paddts_rsp->rsp); + } else { + status = + sme_qos_process_add_ts_success_rsp(mac, sessionId, + &paddts_rsp->rsp); + } + return status; +} + +/* + * sme_qos_process_del_ts_rsp() - Function to process the + * eWNI_SME_DELTS_RSP came from PE + * + * mac - Pointer to the global MAC parameter structure. + * msg_buf - Pointer to the msg buffer came from PE. + * + * Return QDF_STATUS + */ +static +QDF_STATUS sme_qos_process_del_ts_rsp(struct mac_context *mac, void *msg_buf) +{ + tpSirDeltsRsp pDeltsRsp = (tpSirDeltsRsp) msg_buf; + struct sme_qos_sessioninfo *pSession; + uint8_t sessionId = pDeltsRsp->sessionId; + + /* msg */ + sme_debug("Invoked on session %d with return code %d", + sessionId, pDeltsRsp->rc); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + (void)sme_qos_process_buffered_cmd(sessionId); + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_del_ts_ind() - Function to process the + * eWNI_SME_DELTS_IND came from PE + * + * Since it's a DELTS indication from AP, will notify all the flows running on + * this AC about QoS release + * + * mac - Pointer to the global MAC parameter structure. + * msg_buf - Pointer to the msg buffer came from PE. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_del_ts_ind(struct mac_context *mac, + void *msg_buf) +{ + tpSirDeltsRsp pdeltsind = (tpSirDeltsRsp)msg_buf; + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + uint8_t sessionId = pdeltsind->sessionId; + enum qca_wlan_ac_type ac; + struct sme_qos_searchinfo search_key; + struct mac_ts_info *tsinfo; + enum sme_qos_wmmuptype up = + (enum sme_qos_wmmuptype) + pdeltsind->rsp.tspec.tsinfo.traffic.userPrio; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); +#endif + sme_debug("Invoked on session %d for UP %d", sessionId, up); + tsinfo = &pdeltsind->rsp.tspec.tsinfo; + ac = sme_qos_up_to_ac(up); + if (QCA_WLAN_AC_ALL == ac) { + /* err msg */ + sme_err("invalid AC %d from UP %d", ac, up); + return QDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + /* find all Flows on the particular AC & delete them, also send HDD + * indication through the callback it registered per request + */ + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list(mac, search_key, + sme_qos_del_ts_ind_fnp))) { + sme_err("no match found for ac = %d", search_key.key.ac_type); + return QDF_STATUS_E_FAILURE; + } + sme_set_tspec_uapsd_mask_per_session(mac, tsinfo, sessionId); +/* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_DELTS; + qos.reasonCode = SME_QOS_DIAG_DELTS_IND_FROM_AP; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_assoc_complete_ev() - Function to process the + * SME_QOS_CSR_ASSOC_COMPLETE event indication from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_assoc_complete_ev(struct mac_context *mac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum qca_wlan_ac_type ac = QCA_WLAN_AC_BE; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (((SME_QOS_INIT == pSession->ac_info[QCA_WLAN_AC_BE].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[QCA_WLAN_AC_BK].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[QCA_WLAN_AC_VI].curr_state) + && (SME_QOS_INIT == + pSession->ac_info[QCA_WLAN_AC_VO].curr_state)) + || (pSession->handoffRequested)) { + /* get the association info */ + if (!pEvent_info) { + /* err msg */ + sme_err("pEvent_info is NULL"); + return status; + } + if (!((sme_QosAssocInfo *)pEvent_info)->bss_desc) { + /* err msg */ + sme_err("bss_desc is NULL"); + return status; + } + if ((pSession->assocInfo.bss_desc) && + (csr_is_bssid_match + ((struct qdf_mac_addr *) + &pSession->assocInfo.bss_desc->bssId, + (struct qdf_mac_addr *) &(((sme_QosAssocInfo *) + pEvent_info)->bss_desc->bssId)))) { + sme_err("assoc with the same BSS, no update needed"); + } else + status = sme_qos_save_assoc_info(pSession, pEvent_info); + } else { + sme_err("wrong state: BE %d, BK %d, VI %d, VO %d", + pSession->ac_info[QCA_WLAN_AC_BE].curr_state, + pSession->ac_info[QCA_WLAN_AC_BK].curr_state, + pSession->ac_info[QCA_WLAN_AC_VI].curr_state, + pSession->ac_info[QCA_WLAN_AC_VO].curr_state); + return status; + } + /* the session is active */ + pSession->sessionActive = true; + if (pSession->handoffRequested) { + pSession->handoffRequested = false; + /* renew all flows */ + (void)sme_qos_process_buffered_cmd(sessionId); + status = QDF_STATUS_SUCCESS; + } else { + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_INIT: + sme_qos_state_transition(sessionId, ac, + SME_QOS_LINK_UP); + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + case SME_QOS_HANDOFF: + case SME_QOS_CLOSED: + default: + sme_err("On session %d AC %d is in wrong state %d", + sessionId, ac, + pACInfo->curr_state); + break; + } + } + } + return status; +} + +/* + * sme_qos_process_reassoc_req_ev() - Function to process the + * SME_QOS_CSR_REASSOC_REQ event indication from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_reassoc_req_ev(struct mac_context *mac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac; + struct sme_qos_flowinfoentry *flow_info = NULL; + tListElem *entry = NULL; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (pSession->ftHandoffInProgress) { + sme_debug("no need for state transition, should already be in handoff state"); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + sme_err("curr_state is not HANDOFF, session %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + sme_qos_process_ft_reassoc_req_ev(sessionId); + return QDF_STATUS_SUCCESS; + } + + if (pSession->handoffRequested) { + sme_debug("no need for state transition, should already be in handoff state"); + + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + sme_err("curr_state is not HANDOFF, session %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + + /* + * Now change reason and HO renewal of + * all the flow in this session only + */ + entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!entry) { + sme_debug("Flow List empty, nothing to update"); + return QDF_STATUS_E_FAILURE; + } + + do { + flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, + link); + if (sessionId == flow_info->sessionId) { + sme_info("Changing FlowID %d reason toSETUP and HO renewal to true", + flow_info->QosFlowID); + flow_info->reason = SME_QOS_REASON_SETUP; + flow_info->hoRenewal = true; + } + entry = csr_ll_next(&sme_qos_cb.flow_list, entry, + false); + } while (entry); + + /* buffer the existing flows to be renewed after handoff is + * done + */ + sme_qos_buffer_existing_flows(mac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(mac, sessionId); + return QDF_STATUS_SUCCESS; + } +/* TBH: Assuming both handoff algo & 11r willn't be enabled at the same time */ + if (pSession->ftHandoffInProgress) { + sme_debug("no need for state transition, should already be in handoff state"); + + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + sme_err("curr_state is not HANDOFF, session %d", + sessionId); + return QDF_STATUS_E_FAILURE; + } + + sme_qos_process_ft_reassoc_req_ev(sessionId); + return QDF_STATUS_SUCCESS; + } + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionId, ac, + SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* This is normal because sme_qos_request_reassoc may + * already change the state + */ + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + sme_err("On session %d AC %d is in wrong state %d", + sessionId, ac, pACInfo->curr_state); + break; + } + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_handle_handoff_state() - utility function called by + * sme_qos_process_reassoc_success_ev + * @mac_ctx: global MAC context + * @qos_session: QOS session + * @ac_info: AC information + * @ac: current AC index + * @sessionid: session id + * + * This function is called by sme_qos_process_reassoc_success_ev + * to update the state machine on the reception of reassoc success + * notification + * + * Return: QDF_STATUS + */ +static +QDF_STATUS sme_qos_handle_handoff_state(struct mac_context *mac_ctx, + struct sme_qos_sessioninfo *qos_session, + struct sme_qos_acinfo *ac_info, + enum qca_wlan_ac_type ac, uint8_t sessionid) + +{ + struct sme_qos_searchinfo search_key; + struct sme_qos_searchinfo search_key1; + enum qca_wlan_ac_type ac_index; + tListElem *list_elt = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + /* return to our previous state */ + sme_qos_state_transition(sessionid, ac, ac_info->prev_state); + /* for which ac APSD (hence the reassoc) is requested */ + if (!ac_info->reassoc_pending) + return QDF_STATUS_SUCCESS; + + /* + * update the apsd mask in CB - make sure to take care of the + * case where we are resetting the bit in apsd_mask + */ + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0].ts_info.psb) + qos_session->apsdMask |= 1 << (QCA_WLAN_AC_VO - ac); + else + qos_session->apsdMask &= ~(1 << (QCA_WLAN_AC_VO - ac)); + + ac_info->reassoc_pending = false; + /* + * during setup it gets set as addts & reassoc both gets a + * pending flag ac_info->tspec_pending = 0; + */ + sme_qos_state_transition(sessionid, ac, SME_QOS_QOS_ON); + /* notify HDD with new Service Interval */ + ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0] = + ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]; + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionid; + /* notify PMC that reassoc is done for APSD on certain AC?? */ + + qdf_mem_zero(&search_key1, sizeof(struct sme_qos_searchinfo)); + /* set the hoRenewal field in control block if needed */ + search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; + search_key1.key.reason = SME_QOS_REASON_SETUP; + search_key1.sessionId = sessionid; + for (ac_index = QCA_WLAN_AC_BE; ac_index < QCA_WLAN_AC_ALL; + ac_index++) { + list_elt = sme_qos_find_in_flow_list(search_key1); + if (list_elt) { + flow_info = GET_BASE_ADDR(list_elt, + struct sme_qos_flowinfoentry, link); + if (flow_info->ac_type == ac) { + ac_info->hoRenewal = flow_info->hoRenewal; + break; + } + } + } + /* + * notify HDD the success for the requested flow notify all the + * other flows running on the AC that QoS got modified + */ + status = sme_qos_find_all_in_flow_list(mac_ctx, search_key, + sme_qos_reassoc_success_ev_fnp); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sme_err("no match found for ac = %d", search_key.key.ac_type); + return QDF_STATUS_E_FAILURE; + } + ac_info->hoRenewal = false; + qdf_mem_zero(&ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(struct sme_qos_wmmtspecinfo)); + + return status; +} + +/** + * sme_qos_process_reassoc_success_ev() - process SME_QOS_CSR_REASSOC_COMPLETE + * + * @mac_ctx: global MAC context + * @sessionid: session ID + * @event_info: event buffer from CSR + * + * Function to process the SME_QOS_CSR_REASSOC_COMPLETE event indication + * from CSR + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_process_reassoc_success_ev(struct mac_context *mac_ctx, + uint8_t sessionid, void *event_info) +{ + + struct csr_roam_session *csr_roam_session = NULL; + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_acinfo *ac_info; + enum qca_wlan_ac_type ac; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (sessionid >= WLAN_MAX_VDEVS) { + sme_err("invoked on session %d", sessionid); + return status; + } + + csr_roam_session = CSR_GET_SESSION(mac_ctx, sessionid); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + /* get the association info */ + if (!event_info) { + sme_err("event_info is NULL"); + return status; + } + + if (!((sme_QosAssocInfo *)event_info)->bss_desc) { + sme_err("bss_desc is NULL"); + return status; + } + status = sme_qos_save_assoc_info(qos_session, event_info); + if (status) + sme_err("sme_qos_save_assoc_info() failed"); + + /* + * Assuming both handoff algo & 11r willn't be enabled + * at the same time + */ + if (qos_session->handoffRequested) { + qos_session->handoffRequested = false; + /* renew all flows */ + (void)sme_qos_process_buffered_cmd(sessionid); + return QDF_STATUS_SUCCESS; + } + if (qos_session->ftHandoffInProgress) { + if (csr_roam_is11r_assoc(mac_ctx, sessionid)) { + if (csr_roam_session && + csr_roam_session->connectedInfo.nRICRspLength) { + status = sme_qos_process_ft_reassoc_rsp_ev( + mac_ctx, sessionid, + event_info); + } else { + sme_debug("session or RIC data is not present"); + } + } +#ifdef FEATURE_WLAN_ESE + /* + * If ESE association check for TSPEC IEs in the + * reassoc rsp frame + */ + if (csr_roam_is_ese_assoc(mac_ctx, sessionid)) { + if (csr_roam_session && + csr_roam_session->connectedInfo.nTspecIeLength) { + status = sme_qos_ese_process_reassoc_tspec_rsp( + mac_ctx, sessionid, event_info); + } + } +#endif + qos_session->ftHandoffInProgress = false; + qos_session->handoffRequested = false; + return status; + } + + qos_session->sessionActive = true; + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + ac_info = &qos_session->ac_info[ac]; + switch (ac_info->curr_state) { + case SME_QOS_HANDOFF: + status = sme_qos_handle_handoff_state(mac_ctx, + qos_session, ac_info, ac, sessionid); + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + /* NOP */ + status = QDF_STATUS_SUCCESS; + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + sme_err("session %d AC %d is in wrong state %d", + sessionid, ac, ac_info->curr_state); + break; + } + } + (void)sme_qos_process_buffered_cmd(sessionid); + return status; +} + +/* + * sme_qos_process_reassoc_failure_ev() - Function to process the + * SME_QOS_CSR_REASSOC_FAILURE event indication from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_reassoc_failure_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + if (pACInfo->reassoc_pending) + pACInfo->reassoc_pending = false; + + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(struct sme_qos_wmmtspecinfo)); + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_0], + sizeof(struct sme_qos_wmmtspecinfo)); + qdf_mem_zero(&pACInfo-> + curr_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(struct sme_qos_wmmtspecinfo)); + qdf_mem_zero(&pACInfo-> + requested_QoSInfo[SME_QOS_TSPEC_INDEX_1], + sizeof(struct sme_qos_wmmtspecinfo)); + pACInfo->tspec_mask_status = SME_QOS_TSPEC_MASK_CLEAR; + pACInfo->tspec_pending = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_0] = 0; + pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] = 0; + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + /* NOP */ + break; + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + default: + sme_err("On session %d AC %d is in wrong state %d", + sessionId, ac, pACInfo->curr_state); + break; + } + } + /* need to clean up flows */ + sme_qos_delete_existing_flows(mac, sessionId); + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +#ifdef FEATURE_WLAN_ESE +static bool sme_qos_ft_handoff_required(struct mac_context *mac, + uint8_t session_id) +{ + struct csr_roam_session *csr_roam_session; + + if (csr_roam_is11r_assoc(mac, session_id)) + return true; + + csr_roam_session = CSR_GET_SESSION(mac, session_id); + + if (csr_roam_session && + wlan_cm_is_roam_sync_in_progress(mac->psoc, session_id) && + csr_roam_is_ese_assoc(mac, session_id) && + csr_roam_session->connectedInfo.nTspecIeLength) + return true; + + return false; +} +#else +static inline bool sme_qos_ft_handoff_required(struct mac_context *mac, + uint8_t session_id) +{ + return csr_roam_is11r_assoc(mac, session_id) ? true : false; +} +#endif +#else +static inline bool sme_qos_ft_handoff_required(struct mac_context *mac, + uint8_t session_id) +{ + return false; +} +#endif + +#ifdef FEATURE_WLAN_ESE +static inline bool sme_qos_legacy_handoff_required(struct mac_context *mac, + uint8_t session_id) +{ + return csr_roam_is_ese_assoc(mac, session_id) ? false : true; +} +#else +static inline bool sme_qos_legacy_handoff_required(struct mac_context *mac, + uint8_t session_id) +{ + return true; +} +#endif + +/* + * sme_qos_process_handoff_assoc_req_ev() - Function to process the + * SME_QOS_CSR_HANDOFF_ASSOC_REQ event indication from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_handoff_assoc_req_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + uint8_t ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionId, ac, + SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* print error msg */ + if (pSession->ftHandoffInProgress) { + sme_debug("SME_QOS_CSR_HANDOFF_ASSOC_REQ received in SME_QOS_HANDOFF state with FT in progress"); + break; + } + fallthrough; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + sme_err("On session %d AC %d is in wrong state %d", + sessionId, ac, pACInfo->curr_state); + break; + } + } + + if (sme_qos_ft_handoff_required(mac, sessionId)) + pSession->ftHandoffInProgress = true; + + /* If FT handoff/ESE in progress, legacy handoff need not be enabled */ + if (!pSession->ftHandoffInProgress && + sme_qos_legacy_handoff_required(mac, sessionId)) + pSession->handoffRequested = true; + + /* this session no longer needs UAPSD */ + pSession->apsdMask = 0; + /* do any sessions still require UAPSD? */ + sme_ps_uapsd_disable(MAC_HANDLE(mac), sessionId); + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_handoff_success_ev() - Function to process the + * SME_QOS_CSR_HANDOFF_COMPLETE event indication from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_handoff_success_ev(struct mac_context *mac, + uint8_t sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + uint8_t ac; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* go back to original state before handoff */ + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + switch (pACInfo->curr_state) { + case SME_QOS_HANDOFF: + sme_qos_state_transition(sessionId, ac, + pACInfo->prev_state); + /* we will retry for the requested flow(s) with the + * new AP + */ + if (SME_QOS_REQUESTED == pACInfo->curr_state) + pACInfo->curr_state = SME_QOS_LINK_UP; + + status = QDF_STATUS_SUCCESS; + break; + /* FT logic, has already moved it to QOS_REQUESTED state during + * the reassoc request event, which would include the Qos + * (TSPEC) params in the reassoc req frame + */ + case SME_QOS_REQUESTED: + break; + case SME_QOS_INIT: + case SME_QOS_CLOSED: + case SME_QOS_LINK_UP: + case SME_QOS_QOS_ON: + default: +/* In case of 11r - RIC, we request QoS and Hand-off at the same time hence the + * state may be SME_QOS_REQUESTED + */ + if (pSession->ftHandoffInProgress) + break; + sme_err("On session %d AC %d is in wrong state %d", + sessionId, ac, pACInfo->curr_state); + break; + } + } + return status; +} + +/* + * sme_qos_process_disconnect_ev() - Function to process the + * SME_QOS_CSR_DISCONNECT_REQ or SME_QOS_CSR_DISCONNECT_IND event indication + * from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_disconnect_ev(struct mac_context *mac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + /* + * In case of 11r - RIC, we request QoS and Hand-off at the + * same time hence the state may be SME_QOS_REQUESTED + */ + if ((pSession->handoffRequested) + && !pSession->ftHandoffInProgress) { + sme_debug("no need for state transition, should already be in handoff state"); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) { + sme_err("curr_state is not HANDOFF, session %d", + sessionId); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; + } + sme_qos_init_a_cs(mac, sessionId); + /* this session doesn't require UAPSD */ + pSession->apsdMask = 0; + + sme_ps_uapsd_disable(MAC_HANDLE(mac), sessionId); + + pSession->handoffRequested = false; + pSession->roamID = 0; + /* need to clean up buffered req */ + sme_qos_delete_buffered_requests(mac, sessionId); + /* need to clean up flows */ + sme_qos_delete_existing_flows(mac, sessionId); + /* clean up the assoc info */ + if (pSession->assocInfo.bss_desc) { + qdf_mem_free(pSession->assocInfo.bss_desc); + pSession->assocInfo.bss_desc = NULL; + } + sme_qos_cb.sessionInfo[sessionId].sessionActive = false; + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_join_req_ev() - Function to process the + * SME_QOS_CSR_JOIN_REQ event indication from CSR + * + * pEvent_info - Pointer to relevant info from CSR. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_join_req_ev(struct mac_context *mac, uint8_t + sessionId, void *pEvent_info) +{ + struct sme_qos_sessioninfo *pSession; + enum qca_wlan_ac_type ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession->handoffRequested) { + sme_debug("No need for state transition, should already be in handoff state"); + if ((pSession->ac_info[0].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[1].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[2].curr_state != SME_QOS_HANDOFF) || + (pSession->ac_info[3].curr_state != SME_QOS_HANDOFF)) + sme_err("curr_state is not HANDOFF, session %d", + sessionId); + /* buffer the existing flows to be renewed after handoff is + * done + */ + sme_qos_buffer_existing_flows(mac, sessionId); + /* clean up the control block partially for handoff */ + sme_qos_cleanup_ctrl_blk_for_handoff(mac, sessionId); + return QDF_STATUS_SUCCESS; + } + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + + /* clean up the assoc info if already set */ + if (pSession->assocInfo.bss_desc) { + qdf_mem_free(pSession->assocInfo.bss_desc); + pSession->assocInfo.bss_desc = NULL; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * sme_qos_process_preauth_success_ind() - process preauth success indication + * @mac_ctx: global MAC context + * @sessionid: session ID + * @event_info: event buffer + * + * Function to process the SME_QOS_CSR_PREAUTH_SUCCESS_IND event indication + * from CSR + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_process_preauth_success_ind(struct mac_context *mac_ctx, + uint8_t sessionid, void *event_info) +{ + struct sme_qos_sessioninfo *qos_session; + struct csr_roam_session *sme_session = CSR_GET_SESSION(mac_ctx, + sessionid); + struct sme_qos_acinfo *ac_info; + uint8_t ac; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t ric_offset = 0; + uint32_t ric_ielen = 0; + uint8_t *ric_ie; + uint8_t tspec_mask_status = 0; + uint8_t tspec_pending_status = 0; + struct wlan_objmgr_vdev *vdev; + struct mlme_legacy_priv *mlme_priv; + + if (!sme_session) { + sme_err("sme_session is NULL"); + return QDF_STATUS_E_INVAL; + } + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + ac_info = &qos_session->ac_info[ac]; + + switch (ac_info->curr_state) { + case SME_QOS_LINK_UP: + case SME_QOS_REQUESTED: + case SME_QOS_QOS_ON: + sme_qos_state_transition(sessionid, ac, SME_QOS_HANDOFF); + break; + case SME_QOS_HANDOFF: + /* print error msg */ + case SME_QOS_CLOSED: + case SME_QOS_INIT: + default: + sme_err("Session %d AC %d is in wrong state %d", + sessionid, ac, ac_info->curr_state); + break; + } + } + + qos_session->ftHandoffInProgress = true; + + /* Check if its a 11R roaming before preparing the RIC IEs */ + if (!csr_roam_is11r_assoc(mac_ctx, sessionid)) + return status; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(mac_ctx->pdev, sessionid, + WLAN_LEGACY_SME_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) { + status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* + * Any Block Ack info there, should have been already filled by PE and + * present in this buffer and the ric_ies_length should contain the + * length of the whole RIC IEs. Filling of TSPEC info should start + * from this length + */ + qdf_mem_zero(mlme_priv->connect_info.ft_info.ric_ies, MAX_FTIE_SIZE); + mlme_priv->connect_info.ft_info.ric_ies_length = 0; + + ric_ie = mlme_priv->connect_info.ft_info.ric_ies; + ric_offset = mlme_priv->connect_info.ft_info.ric_ies_length; + + /* + * Now we have to process the currentTspeInfo inside this session and + * create the RIC IEs + */ + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + volatile uint8_t tspec_idx = 0; + + ric_ielen = 0; + ac_info = &qos_session->ac_info[ac]; + tspec_pending_status = ac_info->tspec_pending; + tspec_mask_status = ac_info->tspec_mask_status; + qdf_mem_zero(ac_info->ricIdentifier, SME_QOS_TSPEC_INDEX_MAX); + sme_debug("AC %d ==> TSPEC status = %d, tspec pending = %d", + ac, tspec_mask_status, tspec_pending_status); + + do { + if (!(tspec_mask_status & 0x1)) + goto add_next_ric; + + /* + * If a tspec status is pending, take requested_QoSInfo + * for RIC request, else use curr_QoSInfo for the + * RIC request + */ + if (tspec_pending_status & 0x1) { + status = sme_qos_create_tspec_ricie(mac_ctx, + &ac_info->requested_QoSInfo[tspec_idx], + ric_ie + ric_offset, &ric_ielen, + &ac_info->ricIdentifier[tspec_idx]); + } else { + status = sme_qos_create_tspec_ricie(mac_ctx, + &ac_info->curr_QoSInfo[tspec_idx], + ric_ie + ric_offset, &ric_ielen, + &ac_info->ricIdentifier[tspec_idx]); + } +add_next_ric: + ric_offset += ric_ielen; + mlme_priv->connect_info.ft_info.ric_ies_length = ric_ielen; + tspec_mask_status >>= 1; + tspec_pending_status >>= 1; + tspec_idx++; + } while (tspec_mask_status); + } +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + + return status; +} +#else +static inline +QDF_STATUS sme_qos_process_preauth_success_ind(struct mac_context *mac_ctx, + uint8_t sessionid, void *event_info) +{ + return QDF_STATUS_SUCCESS; +} +#endif +/* + * sme_qos_process_add_ts_failure_rsp() - Function to process the + * Addts request failure response came from PE + * + * We will notify HDD only for the requested Flow, other Flows running on the AC + * stay intact + * + * mac - Pointer to the global MAC parameter structure. + * pRsp - Pointer to the addts response structure came from PE. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_add_ts_failure_rsp(struct mac_context *mac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac; + struct sme_qos_searchinfo search_key; + uint8_t tspec_pending; + enum sme_qos_wmmuptype up = + (enum sme_qos_wmmuptype) pRsp->tspec.tsinfo.traffic.userPrio; + + sme_debug("invoked on session %d for UP %d", sessionId, up); + ac = sme_qos_up_to_ac(up); + if (QCA_WLAN_AC_ALL == ac) { + /* err msg */ + sme_err("invalid AC %d from UP %d", ac, up); + return QDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* is there a TSPEC request pending on this AC? */ + tspec_pending = pACInfo->tspec_pending; + if (!tspec_pending) { + sme_err("On session %d an AddTS is not pending on AC %d", + sessionId, ac); + return QDF_STATUS_E_FAILURE; + } + + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list + (mac, search_key, sme_qos_add_ts_failure_fnp))) { + sme_err("On session %d no match found for ac = %d", + sessionId, search_key.key.ac_type); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], + sizeof(struct sme_qos_wmmtspecinfo)); + + if ((!pACInfo->num_flows[0]) && (!pACInfo->num_flows[1])) { + pACInfo->tspec_mask_status &= SME_QOS_TSPEC_MASK_BIT_1_2_SET & + (~pACInfo->tspec_pending); + sme_qos_state_transition(sessionId, ac, SME_QOS_LINK_UP); + } else + sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); + + pACInfo->tspec_pending = 0; + + (void)sme_qos_process_buffered_cmd(sessionId); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_update_tspec_mask() - Utility function to update the tspec. + * @sessionid: Session upon which the TSPEC is being updated + * @search_key: search key + * @new_tspec_mask: tspec to be set for this AC + * + * Typical usage while aggregating unidirectional flows into a bi-directional + * flow on AC which is running multiple flows + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_update_tspec_mask(uint8_t sessionid, + struct sme_qos_searchinfo + search_key, + uint8_t new_tspec_mask) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_acinfo *ac_info; + + sme_debug("invoked on session %d for AC %d TSPEC %d", + sessionid, search_key.key.ac_type, new_tspec_mask); + + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + + if (search_key.key.ac_type < QCA_WLAN_AC_ALL) { + ac_info = &qos_session->ac_info[search_key.key.ac_type]; + } else { + sme_debug("Exceeded the array bounds"); + return QDF_STATUS_E_FAILURE; + } + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + sme_err("Flow List empty, nothing to update"); + return QDF_STATUS_E_FAILURE; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, struct + sme_qos_flowinfoentry, link); + + if (search_key.sessionId != flow_info->sessionId) { + list_elt = list_next_elt; + continue; + } + + if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.direction == + flow_info->QoSInfo.ts_info.direction)) { + sme_debug("Flow %d matches", + flow_info->QosFlowID); + ac_info->num_flows[flow_info->tspec_mask - 1]--; + ac_info->num_flows[new_tspec_mask - 1]++; + flow_info->tspec_mask = new_tspec_mask; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_5) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.tspec_mask == flow_info->tspec_mask)) { + sme_debug("Flow %d matches", + flow_info->QosFlowID); + ac_info->num_flows[flow_info->tspec_mask - 1]--; + ac_info->num_flows[new_tspec_mask - 1]++; + flow_info->tspec_mask = new_tspec_mask; + } + } + list_elt = list_next_elt; + } + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_process_add_ts_success_rsp() - Function to process the + * Addts request success response came from PE + * + * We will notify HDD with addts success for the requested Flow, & for other + * Flows running on the AC we will send an addts modify status + * + * mac - Pointer to the global MAC parameter structure. + * pRsp - Pointer to the addts response structure came from PE. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_process_add_ts_success_rsp(struct mac_context *mac, + uint8_t sessionId, + tSirAddtsRspInfo *pRsp) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac, ac_index; + struct sme_qos_searchinfo search_key; + struct sme_qos_searchinfo search_key1; + uint8_t tspec_pending; + tListElem *pEntry = NULL; + enum QDF_OPMODE opmode; + struct sme_qos_flowinfoentry *flow_info = NULL; + enum sme_qos_wmmuptype up = + (enum sme_qos_wmmuptype) pRsp->tspec.tsinfo.traffic.userPrio; +#ifdef FEATURE_WLAN_DIAG_SUPPORT + WLAN_HOST_DIAG_EVENT_DEF(qos, host_event_wlan_qos_payload_type); + host_log_qos_tspec_pkt_type *log_ptr = NULL; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + + sme_debug("invoked on session %d for UP %d", sessionId, up); + pSession = &sme_qos_cb.sessionInfo[sessionId]; + ac = sme_qos_up_to_ac(up); + if (QCA_WLAN_AC_ALL == ac) { + /* err msg */ + sme_err("invalid AC %d from UP %d", ac, up); + return QDF_STATUS_E_FAILURE; + } + pACInfo = &pSession->ac_info[ac]; + /* is there a TSPEC request pending on this AC? */ + tspec_pending = pACInfo->tspec_pending; + if (!tspec_pending) { + sme_err("On session %d an AddTS is not pending on AC %d", + sessionId, ac); + return QDF_STATUS_E_FAILURE; + } + /* App is looking for APSD or the App which was looking for APSD has + * been released, so STA re-negotiated with AP + */ + if (pACInfo->requested_QoSInfo[tspec_pending - 1].ts_info.psb) { + /* update the session's apsd mask */ + pSession->apsdMask |= 1 << (QCA_WLAN_AC_VO - ac); + } else { + if (((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) > 0) && + ((SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) <= + SME_QOS_TSPEC_INDEX_MAX)) { + if (!pACInfo->requested_QoSInfo + [(SME_QOS_TSPEC_MASK_BIT_1_2_SET & ~tspec_pending) - + 1].ts_info.psb) + /* update the session's apsd mask */ + pSession->apsdMask &= + ~(1 << (QCA_WLAN_AC_VO - ac)); + } else { + sme_debug("Exceeded the array bounds of pACInfo->requested_QosInfo"); + return QDF_STATUS_E_FAILURE; + } + } + + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.burst_size_defn = + pRsp->tspec.tsinfo.traffic.burstSizeDefn; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.ack_policy = + pRsp->tspec.tsinfo.traffic.ackPolicy; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.up = + pRsp->tspec.tsinfo.traffic.userPrio; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.psb = + pRsp->tspec.tsinfo.traffic.psb; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.direction = + pRsp->tspec.tsinfo.traffic.direction; + pACInfo->curr_QoSInfo[tspec_pending - 1].ts_info.tid = + pRsp->tspec.tsinfo.traffic.tsid; + pACInfo->curr_QoSInfo[tspec_pending - 1].nominal_msdu_size = + pRsp->tspec.nomMsduSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].maximum_msdu_size = + pRsp->tspec.maxMsduSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].min_service_interval = + pRsp->tspec.minSvcInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].max_service_interval = + pRsp->tspec.maxSvcInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].inactivity_interval = + pRsp->tspec.inactInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].suspension_interval = + pRsp->tspec.suspendInterval; + pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time = + pRsp->tspec.svcStartTime; + pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate = + pRsp->tspec.minDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate = + pRsp->tspec.meanDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate = + pRsp->tspec.peakDataRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size = + pRsp->tspec.maxBurstSz; + pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound = + pRsp->tspec.delayBound; + + pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate = + pRsp->tspec.minPhyRate; + pACInfo->curr_QoSInfo[tspec_pending - 1].surplus_bw_allowance = + pRsp->tspec.surplusBw; + pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time = + pRsp->tspec.mediumTime; + + sme_set_tspec_uapsd_mask_per_session(mac, + &pRsp->tspec.tsinfo, sessionId); + + sme_debug("On session %d AddTspec Medium Time %d", + sessionId, pRsp->tspec.mediumTime); + + /* Check if the current flow is for bi-directional. If so, update the + * number of flows to reflect that all flows are aggregated into tspec + * index 0. + */ + if ((pACInfo->curr_QoSInfo[pACInfo->tspec_pending - 1].ts_info. + direction == SME_QOS_WMM_TS_DIR_BOTH) + && (pACInfo->num_flows[SME_QOS_TSPEC_INDEX_1] > 0)) { + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* update tspec_mask for all the flows having + * SME_QOS_TSPEC_MASK_BIT_2_SET to SME_QOS_TSPEC_MASK_BIT_1_SET + */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_5; + search_key.sessionId = sessionId; + search_key.tspec_mask = SME_QOS_TSPEC_MASK_BIT_2_SET; + sme_qos_update_tspec_mask(sessionId, search_key, + SME_QOS_TSPEC_MASK_BIT_1_SET); + } + + qdf_mem_zero(&search_key1, sizeof(struct sme_qos_searchinfo)); + /* set the horenewal field in control block if needed */ + search_key1.index = SME_QOS_SEARCH_KEY_INDEX_3; + search_key1.key.reason = SME_QOS_REASON_SETUP; + search_key1.sessionId = sessionId; + for (ac_index = QCA_WLAN_AC_BE; ac_index < QCA_WLAN_AC_ALL; + ac_index++) { + pEntry = sme_qos_find_in_flow_list(search_key1); + if (pEntry) { + flow_info = GET_BASE_ADDR(pEntry, + struct sme_qos_flowinfoentry, link); + if (flow_info->ac_type == ac) { + pACInfo->hoRenewal = flow_info->hoRenewal; + break; + } + } + } + qdf_mem_zero(&search_key, sizeof(struct sme_qos_searchinfo)); + /* set the key type & the key to be searched in the Flow List */ + search_key.key.ac_type = ac; + search_key.index = SME_QOS_SEARCH_KEY_INDEX_2; + search_key.sessionId = sessionId; + /* notify HDD the success for the requested flow */ + /* notify all the other flows running on the AC that QoS got modified */ + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_find_all_in_flow_list + (mac, search_key, sme_qos_add_ts_success_fnp))) { + sme_err("On session %d no match found for ac %d", sessionId, + search_key.key.ac_type); + return QDF_STATUS_E_FAILURE; + } + pACInfo->hoRenewal = false; + qdf_mem_zero(&pACInfo->requested_QoSInfo[tspec_pending - 1], + sizeof(struct sme_qos_wmmtspecinfo)); + /* event: EVENT_WLAN_QOS */ +#ifdef FEATURE_WLAN_DIAG_SUPPORT + qos.eventId = SME_QOS_DIAG_ADDTS_RSP; + qos.reasonCode = SME_QOS_DIAG_ADDTS_ADMISSION_ACCEPTED; + WLAN_HOST_DIAG_EVENT_REPORT(&qos, EVENT_WLAN_QOS); + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, host_log_qos_tspec_pkt_type, + LOG_WLAN_QOS_TSPEC_C); + if (log_ptr) { + log_ptr->delay_bound = + pACInfo->curr_QoSInfo[tspec_pending - 1].delay_bound; + log_ptr->inactivity_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].inactivity_interval; + log_ptr->max_burst_size = + pACInfo->curr_QoSInfo[tspec_pending - 1].max_burst_size; + log_ptr->max_service_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].max_service_interval; + log_ptr->maximum_msdu_size = + pACInfo->curr_QoSInfo[tspec_pending - 1]. + maximum_msdu_size; + log_ptr->mean_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].mean_data_rate; + log_ptr->medium_time = + pACInfo->curr_QoSInfo[tspec_pending - 1].medium_time; + log_ptr->min_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].min_data_rate; + log_ptr->min_phy_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].min_phy_rate; + log_ptr->min_service_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].min_service_interval; + log_ptr->nominal_msdu_size = + pACInfo->curr_QoSInfo[tspec_pending - 1]. + nominal_msdu_size; + log_ptr->peak_data_rate = + pACInfo->curr_QoSInfo[tspec_pending - 1].peak_data_rate; + log_ptr->surplus_bw_allowance = + pACInfo->curr_QoSInfo[tspec_pending - + 1].surplus_bw_allowance; + log_ptr->suspension_interval = + pACInfo->curr_QoSInfo[tspec_pending - + 1].suspension_interval; + log_ptr->svc_start_time = + pACInfo->curr_QoSInfo[tspec_pending - 1].svc_start_time; + log_ptr->tsinfo[0] = + pACInfo->curr_QoSInfo[tspec_pending - + 1].ts_info.direction << 5 | + pACInfo-> + curr_QoSInfo[tspec_pending - 1].ts_info.tid << 1; + log_ptr->tsinfo[1] = + pACInfo->curr_QoSInfo[tspec_pending - + 1].ts_info.up << 11 | pACInfo-> + curr_QoSInfo[tspec_pending - 1].ts_info.psb << 10; + log_ptr->tsinfo[2] = 0; + } + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + pACInfo->tspec_pending = 0; + + sme_qos_state_transition(sessionId, ac, SME_QOS_QOS_ON); + + /* Inform this TSPEC IE change to FW */ + opmode = wlan_get_opmode_from_vdev_id(mac->pdev, sessionId); + if (opmode == QDF_STA_MODE) + wlan_roam_update_cfg(mac->psoc, sessionId, + REASON_CONNECT_IES_CHANGED); + + (void)sme_qos_process_buffered_cmd(sessionId); + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_aggregate_params() - Utility function to increment the TSPEC + * params per AC. Typical usage while using flow aggregation or deletion of + * flows + * + * pInput_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains the + * WMM TSPEC related info with which pCurrent_Tspec_Info will be updated + * pCurrent_Tspec_Info - Pointer to sme_QosWmmTspecInfo which contains + * current the WMM TSPEC related info + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_aggregate_params( + struct sme_qos_wmmtspecinfo *pInput_Tspec_Info, + struct sme_qos_wmmtspecinfo *pCurrent_Tspec_Info, + struct sme_qos_wmmtspecinfo *pUpdated_Tspec_Info) +{ + struct sme_qos_wmmtspecinfo TspecInfo; + + sme_debug("invoked"); + if (!pInput_Tspec_Info) { + sme_err("input is NULL, nothing to aggregate"); + return QDF_STATUS_E_FAILURE; + } + if (!pCurrent_Tspec_Info) { + sme_err("Current is NULL, can't aggregate"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(&TspecInfo, pCurrent_Tspec_Info, + sizeof(struct sme_qos_wmmtspecinfo)); + TspecInfo.ts_info.psb = pInput_Tspec_Info->ts_info.psb; + /* APSD preference is only meaningful if service interval + * was set by app + */ + if (pCurrent_Tspec_Info->min_service_interval && + pInput_Tspec_Info->min_service_interval && + (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction)) { + TspecInfo.min_service_interval = + QDF_MIN(pCurrent_Tspec_Info->min_service_interval, + pInput_Tspec_Info->min_service_interval); + } else if (pInput_Tspec_Info->min_service_interval) { + TspecInfo.min_service_interval = + pInput_Tspec_Info->min_service_interval; + } + if (pCurrent_Tspec_Info->max_service_interval && + pInput_Tspec_Info->max_service_interval && + (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction)) { + TspecInfo.max_service_interval = + QDF_MIN(pCurrent_Tspec_Info->max_service_interval, + pInput_Tspec_Info->max_service_interval); + } else { + TspecInfo.max_service_interval = + pInput_Tspec_Info->max_service_interval; + } + /* If directions don't match, it must necessarily be both uplink and + * downlink + */ + if (pCurrent_Tspec_Info->ts_info.direction != + pInput_Tspec_Info->ts_info.direction) + TspecInfo.ts_info.direction = + pInput_Tspec_Info->ts_info.direction; + + /* Max MSDU size : these sizes are `maxed' */ + TspecInfo.maximum_msdu_size = + QDF_MAX(pCurrent_Tspec_Info->maximum_msdu_size, + pInput_Tspec_Info->maximum_msdu_size); + + /* Inactivity interval : these sizes are `maxed' */ + TspecInfo.inactivity_interval = + QDF_MAX(pCurrent_Tspec_Info->inactivity_interval, + pInput_Tspec_Info->inactivity_interval); + + /* Delay bounds: min of all values + * Check on 0: if 0, it means initial value since delay can never be 0!! + */ + if (pCurrent_Tspec_Info->delay_bound) { + TspecInfo.delay_bound = + QDF_MIN(pCurrent_Tspec_Info->delay_bound, + pInput_Tspec_Info->delay_bound); + } else + TspecInfo.delay_bound = pInput_Tspec_Info->delay_bound; + + TspecInfo.max_burst_size = QDF_MAX(pCurrent_Tspec_Info->max_burst_size, + pInput_Tspec_Info->max_burst_size); + + /* Nominal MSDU size also has a fixed bit that needs to be `handled' + * before aggregation This can be handled only if previous size is the + * same as new or both have the fixed bit set These sizes are not added + * but `maxed' + */ + TspecInfo.nominal_msdu_size = + QDF_MAX(pCurrent_Tspec_Info->nominal_msdu_size & + ~SME_QOS_16BIT_MSB, pInput_Tspec_Info->nominal_msdu_size + & ~SME_QOS_16BIT_MSB); + + if (((pCurrent_Tspec_Info->nominal_msdu_size == 0) || + (pCurrent_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB)) && + ((pInput_Tspec_Info->nominal_msdu_size == 0) || + (pInput_Tspec_Info->nominal_msdu_size & SME_QOS_16BIT_MSB))) + TspecInfo.nominal_msdu_size |= SME_QOS_16BIT_MSB; + + /* Data rates: Add up the rates for aggregation */ + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.peak_data_rate, + pInput_Tspec_Info->peak_data_rate); + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.min_data_rate, + pInput_Tspec_Info->min_data_rate); + /* mean data rate = peak data rate: aggregate to be flexible on apps */ + SME_QOS_BOUNDED_U32_ADD_Y_TO_X(TspecInfo.mean_data_rate, + pInput_Tspec_Info->mean_data_rate); + + /* + * Suspension interval : this is set to the inactivity interval since + * per spec it is less than or equal to inactivity interval + * This is not provided by app since we currently don't support the HCCA + * mode of operation Currently set it to 0 to avoid confusion: Cisco ESE + * needs ~0; spec requires inactivity interval to be > suspension + * interval: this could be tricky! + */ + TspecInfo.suspension_interval = pInput_Tspec_Info->suspension_interval; + /* Remaining parameters do not come from app as they are very WLAN + * air interface specific Set meaningful values here + */ + TspecInfo.medium_time = 0; /* per WMM spec */ + TspecInfo.min_phy_rate = SME_QOS_MIN_PHY_RATE; + TspecInfo.svc_start_time = 0; /* arbitrary */ + TspecInfo.surplus_bw_allowance += + pInput_Tspec_Info->surplus_bw_allowance; + if (TspecInfo.surplus_bw_allowance > SME_QOS_SURPLUS_BW_ALLOWANCE) + TspecInfo.surplus_bw_allowance = SME_QOS_SURPLUS_BW_ALLOWANCE; + + /* Set ack_policy to block ack even if one stream requests block + * ack policy + */ + if ((pInput_Tspec_Info->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) + || (pCurrent_Tspec_Info->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK)) + TspecInfo.ts_info.ack_policy = + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK; + + if (pInput_Tspec_Info->ts_info.burst_size_defn + || pCurrent_Tspec_Info->ts_info.burst_size_defn) + TspecInfo.ts_info.burst_size_defn = 1; + + if (pUpdated_Tspec_Info) + qdf_mem_copy(pUpdated_Tspec_Info, &TspecInfo, + sizeof(struct sme_qos_wmmtspecinfo)); + else + qdf_mem_copy(pCurrent_Tspec_Info, &TspecInfo, + sizeof(struct sme_qos_wmmtspecinfo)); + + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_update_params() - Utility function to update the TSPEC + * params per AC. Typical usage while deleting flows on AC which is running + * multiple flows + * + * sessionId - Session upon which the TSPEC is being updated + * ac - Enumeration of the various EDCA Access Categories. + * tspec_mask - on which tspec per AC, the update is requested + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_update_params(uint8_t sessionId, + enum qca_wlan_ac_type ac, + uint8_t tspec_mask, + struct sme_qos_wmmtspecinfo *pTspec_Info) +{ + tListElem *pEntry = NULL, *pNextEntry = NULL; + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + struct sme_qos_wmmtspecinfo Tspec_Info; + + sme_debug("invoked on session %d for AC %d TSPEC %d", + sessionId, ac, tspec_mask); + if (!pTspec_Info) { + sme_err("output is NULL, can't aggregate"); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_zero(&Tspec_Info, sizeof(struct sme_qos_wmmtspecinfo)); + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + sme_err("Flow List empty, nothing to update"); + return QDF_STATUS_E_FAILURE; + } + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + /* init the TS info field */ + Tspec_Info.ts_info.up = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.up; + Tspec_Info.ts_info.psb = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.psb; + Tspec_Info.ts_info.tid = + pACInfo->curr_QoSInfo[tspec_mask - 1].ts_info.tid; + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, + link); + if ((sessionId == flow_info->sessionId) && + (ac == flow_info->ac_type) && + (tspec_mask == flow_info->tspec_mask)) { + sme_debug("Flow %d matches", flow_info->QosFlowID); + + if ((SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + /* msg */ + sme_debug("Skipping Flow %d as it is marked for release/modify", + flow_info->QosFlowID); + } else + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_aggregate_params + (&flow_info->QoSInfo, &Tspec_Info, + NULL))) { + /* err msg */ + sme_err("sme_qos_aggregate_params() failed"); + } + } + pEntry = pNextEntry; + } + /* return the aggregate */ + *pTspec_Info = Tspec_Info; + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_up_to_ac() - Utility function to map an UP to AC + * + * up - Enumeration of the various User priorities (UP). + * Return an Access Category + */ +static enum qca_wlan_ac_type sme_qos_up_to_ac(enum sme_qos_wmmuptype up) +{ + enum qca_wlan_ac_type ac = QCA_WLAN_AC_ALL; + + if (up >= 0 && up < SME_QOS_WMM_UP_MAX) + ac = sme_qos_up_to_ac_map[up]; + + sme_debug("up = %d ac = %d returned", up, ac); + return ac; +} + +/* + * sme_qos_state_transition() - The state transition function per AC. We + * save the previous state also. + * + * sessionId - Session upon which the state machine is running + * ac - Enumeration of the various EDCA Access Categories. + * new_state - The state FSM is moving to. + * + * Return None + */ +static void sme_qos_state_transition(uint8_t sessionId, + enum qca_wlan_ac_type ac, + enum sme_qos_states new_state) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pACInfo = &pSession->ac_info[ac]; + pACInfo->prev_state = pACInfo->curr_state; + pACInfo->curr_state = new_state; +} + +/** + * sme_qos_find_in_flow_list() - find a flow entry from the flow list + * @search_key: We can either use the flowID or the ac type to find the + * entry in the flow list. + * A bitmap in struct sme_qos_searchinfo tells which key to use. + * Starting from LSB, + * bit 0 - Flow ID + * bit 1 - AC type + * + * Utility function to find an flow entry from the flow_list. + * + * Return: pointer to the list element + */ +static tListElem *sme_qos_find_in_flow_list(struct sme_qos_searchinfo + search_key) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + sme_err("Flow List empty, can't search"); + return NULL; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, struct + sme_qos_flowinfoentry, link); + + if ((search_key.sessionId != flow_info->sessionId) && + (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { + list_elt = list_next_elt; + continue; + } + + if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) { + if (search_key.key.QosFlowID == flow_info->QosFlowID) { + sme_debug("match found on flowID, ending search"); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) { + if (search_key.key.ac_type == flow_info->ac_type) { + sme_debug("match found on ac, ending search"); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_3) { + if (search_key.key.reason == flow_info->reason) { + sme_debug("match found on reason, ending search"); + break; + } + } else if (search_key.index & SME_QOS_SEARCH_KEY_INDEX_4) { + if ((search_key.key.ac_type == flow_info->ac_type) && + (search_key.direction == + flow_info->QoSInfo.ts_info.direction)) { + sme_debug("match found on reason, ending search"); + break; + } + } + list_elt = list_next_elt; + } + return list_elt; +} + +/** + * sme_qos_find_all_in_flow_list() - find a flow entry in the flow list + * @mac_ctx: global MAC context + * @search_key: search key + * @fnp: function pointer specifying the action type for the entry found + * + * Utility function to find an flow entry from the flow_list & act on it. + * search_key - We can either use the flowID or the ac type to find the + * entry in the flow list. + * A bitmap in struct sme_qos_searchinfo tells which key to use. Starting from + * LSB, + * bit 0 - Flow ID + * bit 1 - AC type + * + * Return: None + */ +static QDF_STATUS sme_qos_find_all_in_flow_list(struct mac_context *mac_ctx, + struct sme_qos_searchinfo search_key, + sme_QosProcessSearchEntry fnp) +{ + tListElem *list_elt = NULL, *list_next_elt = NULL; + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_flowinfoentry *flow_info = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + enum qca_wlan_ac_type ac_type; + + list_elt = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_elt) { + sme_err("Flow List empty, can't search"); + return QDF_STATUS_E_FAILURE; + } + + while (list_elt) { + list_next_elt = csr_ll_next(&sme_qos_cb.flow_list, list_elt, + false); + flow_info = GET_BASE_ADDR(list_elt, struct + sme_qos_flowinfoentry, link); + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + if ((search_key.sessionId != flow_info->sessionId) && + (search_key.sessionId != SME_QOS_SEARCH_SESSION_ID_ANY)) { + list_elt = list_next_elt; + continue; + } + + if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_1) && + (search_key.key.QosFlowID == flow_info->QosFlowID)) { + sme_debug("match found on flowID, ending search"); + status = fnp(mac_ctx, list_elt); + if (QDF_STATUS_E_FAILURE == status) { + sme_err("Failed to process entry"); + break; + } + } else if ((search_key.index & SME_QOS_SEARCH_KEY_INDEX_2) && + (search_key.key.ac_type == flow_info->ac_type)) { + sme_debug("match found on ac, ending search"); + ac_type = flow_info->ac_type; + flow_info->hoRenewal = + qos_session->ac_info[ac_type].hoRenewal; + status = fnp(mac_ctx, list_elt); + if (QDF_STATUS_E_FAILURE == status) { + sme_err("Failed to process entry"); + break; + } + } + list_elt = list_next_elt; + } + return status; +} + +/* + * sme_qos_is_acm() - Utility function to check if a particular AC + * mandates Admission Control. + * + * ac - Enumeration of the various EDCA Access Categories. + * + * Return true if the AC mandates Admission Control + */ +static bool +sme_qos_is_acm(struct mac_context *mac, struct bss_description *pSirBssDesc, + enum qca_wlan_ac_type ac, tDot11fBeaconIEs *pIes) +{ + bool ret_val = false; + tDot11fBeaconIEs *pIesLocal; + + if (pIes) + /* IEs were provided so use them locally */ + pIesLocal = pIes; + else { + /* IEs were not provided so parse them ourselves */ + if (!QDF_IS_STATUS_SUCCESS + (csr_get_parsed_bss_description_ies + (mac, pSirBssDesc, &pIesLocal))) { + /* err msg */ + sme_err("csr_get_parsed_bss_description_ies() failed"); + return false; + } + + /* if success then pIesLocal was allocated */ + } + + if (CSR_IS_QOS_BSS(pIesLocal)) { + switch (ac) { + case QCA_WLAN_AC_BE: + if (pIesLocal->WMMParams.acbe_acm) + ret_val = true; + break; + case QCA_WLAN_AC_BK: + if (pIesLocal->WMMParams.acbk_acm) + ret_val = true; + break; + case QCA_WLAN_AC_VI: + if (pIesLocal->WMMParams.acvi_acm) + ret_val = true; + break; + case QCA_WLAN_AC_VO: + if (pIesLocal->WMMParams.acvo_acm) + ret_val = true; + break; + default: + sme_err("unknown AC = %d", ac); + break; + } + } /* IS_QOS_BSS */ + if (!pIes) + /* IEs were allocated locally so free them */ + qdf_mem_free(pIesLocal); + + return ret_val; +} + +/** + * sme_qos_buffer_existing_flows() - buffer existing flows in flow_list + * @mac_ctx: global MAC context + * @sessionid: session ID + * + * Utility function to buffer the existing flows in flow_list, + * so that we can renew them after handoff is done. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_buffer_existing_flows(struct mac_context *mac_ctx, + uint8_t sessionid) +{ + tListElem *list_entry = NULL, *list_nextentry = NULL; + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_flowinfoentry *flow_info = NULL; + struct sme_qos_cmdinfo cmd; + struct sme_qos_setupcmdinfo *setupinfo; + + list_entry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!list_entry) { + sme_err("Flow List empty, nothing to buffer"); + return QDF_STATUS_E_FAILURE; + } + + while (list_entry) { + list_nextentry = csr_ll_next(&sme_qos_cb.flow_list, list_entry, + false); + flow_info = GET_BASE_ADDR(list_entry, struct + sme_qos_flowinfoentry, link); + if (flow_info->sessionId != sessionid) { + list_entry = list_nextentry; + continue; + } + + if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || + (SME_QOS_REASON_SETUP == flow_info->reason)) { + cmd.command = SME_QOS_SETUP_REQ; + cmd.mac = mac_ctx; + cmd.sessionId = sessionid; + setupinfo = &cmd.u.setupCmdInfo; + + setupinfo->HDDcontext = flow_info->HDDcontext; + setupinfo->QoSInfo = flow_info->QoSInfo; + setupinfo->QoSCallback = flow_info->QoSCallback; + /* shouldn't be needed */ + setupinfo->UPType = SME_QOS_WMM_UP_MAX; + setupinfo->QosFlowID = flow_info->QosFlowID; + if (SME_QOS_REASON_SETUP == flow_info->reason) + setupinfo->hoRenewal = false; + else + setupinfo->hoRenewal = true; + + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + sme_err("couldn't buffer the setup request for flow %d in handoff state", + flow_info->QosFlowID); + else + sme_debug("buffered a setup request for flow %d in handoff state", + flow_info->QosFlowID); + } else if (SME_QOS_REASON_RELEASE == flow_info->reason) { + cmd.command = SME_QOS_RELEASE_REQ; + cmd.mac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.releaseCmdInfo.QosFlowID = flow_info->QosFlowID; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + sme_err("couldn't buffer the release req for flow %d in handoff state", + flow_info->QosFlowID); + else + sme_debug("buffered a release request for flow %d in handoff state", + flow_info->QosFlowID); + } else if (SME_QOS_REASON_MODIFY_PENDING == + flow_info->reason) { + cmd.command = SME_QOS_MODIFY_REQ; + cmd.mac = mac_ctx; + cmd.sessionId = sessionid; + cmd.u.modifyCmdInfo.QosFlowID = flow_info->QosFlowID; + cmd.u.modifyCmdInfo.QoSInfo = flow_info->QoSInfo; + if (!QDF_IS_STATUS_SUCCESS + (sme_qos_buffer_cmd(&cmd, true))) + sme_err("couldn't buffer the modify req for flow %d in handoff state", + flow_info->QosFlowID); + else + sme_debug("buffered a modify request for flow %d in handoff state", + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + sme_debug("Deleting original entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, list_entry, true); + qdf_mem_free(flow_info); + + list_entry = list_nextentry; + } + qos_session = &sme_qos_cb.sessionInfo[sessionid]; + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_delete_existing_flows() - Utility function to Delete the existing + * flows in flow_list, if we lost connectivity. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_delete_existing_flows(struct mac_context *mac, + uint8_t sessionId) +{ + tListElem *pEntry = NULL, *pNextEntry = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, true); + if (!pEntry) + return QDF_STATUS_E_FAILURE; + + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, true); + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, + link); + if (flow_info->sessionId == sessionId) { + if ((SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) || + (SME_QOS_REASON_SETUP == flow_info->reason) || + (SME_QOS_REASON_RELEASE == flow_info->reason) || + (SME_QOS_REASON_MODIFY == flow_info->reason)) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + NULL, + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + sme_debug("Deleting entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, + true); + qdf_mem_free(flow_info); + } + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_buffer_cmd() - buffer a request. + * @pcmd: a pointer to the cmd structure to be saved inside the buffered + * cmd link list + * @insert_head: flag indicate if cmd should be added to the list head. + * + * Utility function to buffer a request (setup/modify/release) from client + * while processing another one on the same AC. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_buffer_cmd(struct sme_qos_cmdinfo *pcmd, + bool insert_head) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_cmdinfoentry *pentry = NULL; + + sme_debug("Invoked"); + pentry = qdf_mem_malloc(sizeof(struct sme_qos_cmdinfoentry)); + if (!pentry) + return QDF_STATUS_E_NOMEM; + + /* copy the entire CmdInfo */ + pentry->cmdInfo = *pcmd; + + pSession = &sme_qos_cb.sessionInfo[pcmd->sessionId]; + if (insert_head) + csr_ll_insert_head(&pSession->bufferedCommandList, + &pentry->link, true); + else + csr_ll_insert_tail(&pSession->bufferedCommandList, + &pentry->link, true); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_process_buffered_cmd() - process qos buffered request + * @session_id: Session ID + * + * Utility function to process a buffered request (setup/modify/release) + * initially came from the client. + * + * Return:QDF_STATUS + */ +static QDF_STATUS sme_qos_process_buffered_cmd(uint8_t session_id) +{ + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_cmdinfoentry *pcmd = NULL; + tListElem *list_elt = NULL; + enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + struct sme_qos_cmdinfo *qos_cmd = NULL; + + qos_session = &sme_qos_cb.sessionInfo[session_id]; + if (!csr_ll_is_list_empty(&qos_session->bufferedCommandList, false)) { + list_elt = csr_ll_remove_head(&qos_session->bufferedCommandList, + true); + if (!list_elt) { + sme_err("no more buffered commands on session %d", + session_id); + return QDF_STATUS_E_FAILURE; + } + pcmd = GET_BASE_ADDR(list_elt, struct sme_qos_cmdinfoentry, + link); + qos_cmd = &pcmd->cmdInfo; + + sme_debug("Qos cmd %d", qos_cmd->command); + switch (qos_cmd->command) { + case SME_QOS_SETUP_REQ: + hdd_status = sme_qos_internal_setup_req( + qos_cmd->mac, qos_cmd->sessionId, + &qos_cmd->u.setupCmdInfo.QoSInfo, + qos_cmd->u.setupCmdInfo.QoSCallback, + qos_cmd->u.setupCmdInfo.HDDcontext, + qos_cmd->u.setupCmdInfo.UPType, + qos_cmd->u.setupCmdInfo.QosFlowID, + true, qos_cmd->u.setupCmdInfo.hoRenewal); + if (SME_QOS_STATUS_SETUP_FAILURE_RSP == hdd_status) { + sme_err("sme_qos_internal_setup_req failed on session %d", + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_RELEASE_REQ: + hdd_status = sme_qos_internal_release_req(qos_cmd->mac, + qos_cmd->sessionId, + qos_cmd->u.releaseCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_RELEASE_FAILURE_RSP == hdd_status) { + sme_err("sme_qos_internal_release_req failed on session %d", + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_MODIFY_REQ: + hdd_status = sme_qos_internal_modify_req(qos_cmd->mac, + &qos_cmd->u.modifyCmdInfo.QoSInfo, + qos_cmd->u.modifyCmdInfo.QosFlowID, + true); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + sme_err("sme_qos_internal_modify_req failed on session %d", + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + case SME_QOS_RESEND_REQ: + hdd_status = sme_qos_re_request_add_ts(qos_cmd->mac, + qos_cmd->sessionId, + &qos_cmd->u.resendCmdInfo.QoSInfo, + qos_cmd->u.resendCmdInfo.ac, + qos_cmd->u.resendCmdInfo.tspecMask); + if (SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP == + hdd_status) { + sme_err("sme_qos_re_request_add_ts failed on session %d", + session_id); + qdf_ret_status = QDF_STATUS_E_FAILURE; + } + break; + default: + sme_err("On session %d unknown cmd = %d", + session_id, qos_cmd->command); + break; + } + /* buffered command has been processed, reclaim the memory */ + qdf_mem_free(pcmd); + } + + return qdf_ret_status; +} + +/* + * sme_qos_delete_buffered_requests() - Utility function to Delete the buffered + * requests in the buffered_cmd_list, if we lost connectivity. + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_delete_buffered_requests(struct mac_context *mac, + uint8_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_cmdinfoentry *pcmd = NULL; + tListElem *pEntry = NULL, *pNextEntry = NULL; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + pEntry = csr_ll_peek_head(&pSession->bufferedCommandList, true); + if (!pEntry) + return QDF_STATUS_E_FAILURE; + + while (pEntry) { + pNextEntry = csr_ll_next(&pSession->bufferedCommandList, pEntry, + true); + sme_debug("deleting entry from buffered List"); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&pSession->bufferedCommandList, pEntry, + true); + /* reclaim the memory */ + pcmd = GET_BASE_ADDR(pEntry, struct sme_qos_cmdinfoentry, + link); + qdf_mem_free(pcmd); + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_save_assoc_info() - save assoc info. + * @pSession: pointer to QOS session + * @pAssoc_info: pointer to the assoc structure to store the BSS descriptor + * of the AP, the profile that HDD sent down with the + * connect request + * + * Utility function to save the assoc info in the CB like BSS descriptor + * of the AP, the profile that HDD sent down with the connect request, + * while CSR notifies for assoc/reassoc success. + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_qos_save_assoc_info(struct sme_qos_sessioninfo *pSession, + sme_QosAssocInfo *pAssoc_info) +{ + struct bss_description *bss_desc = NULL; + uint32_t bssLen = 0; + + if (!pAssoc_info) { + sme_err("pAssoc_info is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* clean up the assoc info if already set */ + if (pSession->assocInfo.bss_desc) { + qdf_mem_free(pSession->assocInfo.bss_desc); + pSession->assocInfo.bss_desc = NULL; + } + bssLen = pAssoc_info->bss_desc->length + + sizeof(pAssoc_info->bss_desc->length); + /* save the bss Descriptor */ + bss_desc = qdf_mem_malloc(bssLen); + if (!bss_desc) + return QDF_STATUS_E_NOMEM; + + qdf_mem_copy(bss_desc, pAssoc_info->bss_desc, bssLen); + pSession->assocInfo.bss_desc = bss_desc; + /* save the apsd info from assoc */ + pSession->apsdMask |= pAssoc_info->uapsd_mask; + + /* [TODO] Do we need to update the global APSD bitmap? */ + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_setup_fnp() - Utility function (pointer) to notify other entries + * in FLOW list on the same AC that qos params got modified + * + * mac - Pointer to the global MAC parameter structure. + * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_setup_fnp(struct mac_context *mac, tListElem *pEntry) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + enum qca_wlan_ac_type ac; + + if (!pEntry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { + /* notify HDD, only the other Flows running on the AC */ + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + sme_debug("Entry with flowID = %d getting notified", + flow_info->QosFlowID); + } + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_modification_notify_fnp() - Utility function (pointer) to notify + * other entries in FLOW list on the same AC that qos params got modified + * + * mac - Pointer to the global MAC parameter structure. + * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_modification_notify_fnp(struct mac_context *mac, tListElem + *pEntry) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + enum qca_wlan_ac_type ac; + + if (!pEntry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + if (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason) { + /* notify HDD, only the other Flows running on the AC */ + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[flow_info-> + tspec_mask - 1], + hdd_status, flow_info->QosFlowID); + sme_debug("Entry with flowID = %d getting notified", + flow_info->QosFlowID); + } + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_modify_fnp() - Utility function (pointer) to delete the original + * entry in FLOW list & add the modified one + * + * mac - Pointer to the global MAC parameter structure. + * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_modify_fnp(struct mac_context *mac, tListElem *pEntry) +{ + struct sme_qos_flowinfoentry *flow_info = NULL; + + if (!pEntry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + + sme_debug("reason %d", flow_info->reason); + switch (flow_info->reason) { + case SME_QOS_REASON_MODIFY_PENDING: + /* set the proper reason code for the new (with modified params) + * entry + */ + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + break; + case SME_QOS_REASON_MODIFY: + /* delete the original entry from Flow List */ + sme_debug("Deleting original entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + break; + default: + break; + } + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_del_ts_ind_fnp() - Utility function (pointer) to find all Flows on + * the particular AC & delete them, also send HDD indication through the + * callback it registered per request + * + * mac - Pointer to the global MAC parameter structure. + * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_del_ts_ind_fnp(struct mac_context *mac, tListElem *pEntry) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + enum qca_wlan_ac_type ac; + QDF_STATUS lock_status = QDF_STATUS_E_FAILURE; + enum sme_qos_statustype status; + + if (!pEntry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* delete the entry from Flow List */ + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + pACInfo->relTrig = SME_QOS_RELEASE_BY_AP; + + lock_status = sme_acquire_global_lock(&mac->sme); + if (!QDF_IS_STATUS_SUCCESS(lock_status)) { + sme_err("Unable to obtain lock"); + return QDF_STATUS_E_FAILURE; + } + /* Call the internal function for QoS release, adding a layer of + * abstraction + */ + status = + sme_qos_internal_release_req(mac, flow_info->sessionId, + flow_info->QosFlowID, false); + sme_release_global_lock(&mac->sme); + sme_debug("QoS Release return status on Flow %d is %d", + flow_info->QosFlowID, status); + + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_reassoc_success_ev_fnp Notification function to HDD + * + * @mac_ctx: Mac context + * @entry: Pointer to an entry in the flow_list + * + * Utility function (pointer) to notify HDD + * the success for the requested flow & notify all the other flows + * running on the same AC that QoS params got modified + * + * Return: QDF_STATUS enumaration + */ +static QDF_STATUS +sme_qos_reassoc_success_ev_fnp(struct mac_context *mac_ctx, + tListElem *entry) +{ + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_acinfo *ac_info; + struct sme_qos_flowinfoentry *flow_info = NULL; + bool delete_entry = false; + enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + enum qca_wlan_ac_type ac; + QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; + + if (!entry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + ac_info = &qos_session->ac_info[ac]; + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + /* -Check for the case where we had to do reassoc to + * reset the apsd bit for the ac - release or modify + * scenario.Notify PMC as App is looking for APSD + * If we already requested then we don't need to + * do anything. + */ + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]. + ts_info.psb) { + /* this is the first flow to detect we need + * PMC in UAPSD mode + */ + pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), + flow_info->sessionId); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & later + * to UAPSD state + */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } + } + /* for any other pmc status we declare success */ + break; + case SME_QOS_REASON_RELEASE: + ac_info->num_flows[SME_QOS_TSPEC_INDEX_0]--; + fallthrough; + case SME_QOS_REASON_MODIFY: + delete_entry = true; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + if (ac_info->requested_QoSInfo[SME_QOS_TSPEC_INDEX_0]. + ts_info.psb) { + /* this is the first flow to detect we need + * PMC in UAPSD mode + */ + pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), + flow_info->sessionId); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & + * later to UAPSD state + */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } + } + /* for any other pmc status we declare success */ + break; + case SME_QOS_REASON_REQ_SUCCESS: + hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + fallthrough; + default: + delete_entry = false; + break; + } + if (!delete_entry) { + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(MAC_HANDLE(mac_ctx), + flow_info->HDDcontext, + &ac_info->curr_QoSInfo[SME_QOS_TSPEC_INDEX_0], + hdd_status, + flow_info->QosFlowID); + } else + flow_info->hoRenewal = false; + } else { + /* delete the entry from Flow List */ + sme_debug("Deleting entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + } + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_add_ts_failure_fnp() - Utility function (pointer), + * if the Addts request was for for an flow setup request, delete the entry from + * Flow list & notify HDD if the Addts request was for downgrading of QoS params + * because of an flow release requested on the AC, delete the entry from Flow + * list & notify HDD if the Addts request was for change of QoS params because + * of an flow modification requested on the AC, delete the new entry from Flow + * list & notify HDD + * + * mac - Pointer to the global MAC parameter structure. + * pEntry - Pointer to an entry in the flow_list(i.e. tListElem structure) + * + * Return QDF_STATUS + */ +static QDF_STATUS sme_qos_add_ts_failure_fnp(struct mac_context *mac, tListElem + *pEntry) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + struct sme_qos_flowinfoentry *flow_info = NULL; + bool inform_hdd = false; + enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + enum qca_wlan_ac_type ac; + + if (!pEntry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + pACInfo = &pSession->ac_info[ac]; + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + pACInfo->num_flows[pACInfo->tspec_pending - 1]--; + inform_hdd = true; + break; + case SME_QOS_REASON_RELEASE: + hdd_status = SME_QOS_STATUS_RELEASE_FAILURE_RSP; + pACInfo->num_flows[pACInfo->tspec_pending - 1]--; + inform_hdd = true; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + inform_hdd = true; + break; + case SME_QOS_REASON_MODIFY: + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + fallthrough; + case SME_QOS_REASON_REQ_SUCCESS: + fallthrough; + default: + inform_hdd = false; + break; + } + if (inform_hdd) { + /* notify HDD, only the requested Flow, other Flows running on + * the AC stay intact + */ + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + hdd_status, + flow_info->QosFlowID); + } else { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pACInfo->curr_QoSInfo[pACInfo-> + tspec_pending + - 1], + SME_QOS_STATUS_RELEASE_QOS_LOST_IND, + flow_info->QosFlowID); + } + /* delete the entry from Flow List */ + sme_debug("Deleting entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + csr_ll_remove_entry(&sme_qos_cb.flow_list, pEntry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + } + return QDF_STATUS_SUCCESS; +} + +/** + * sme_qos_add_ts_success_fnp() - Utility function (pointer) to notify HDD + * + * @mac_ctx: Mac context + * @entry: Pointer to an entry in the flow_list(i.e. tListElem structure). + * + * Description : Utility function (pointer), + * If the Addts request was for for an flow setup request, notify + * HDD for success for the flow & notify all the other flows running + * on the same AC that QoS params got modified + * if the Addts request was for downgrading of QoS params + * because of an flow release requested on the AC, delete + * the entry from Flow list & notify HDD if the Addts request + * was for change of QoS params because of an flow modification + * requested on the AC, delete the old entry from Flow list & notify + * HDD for success for the flow & notify all the other flows running + * on the same AC that QoS params got modified + * + * Return: Status + */ + +static QDF_STATUS sme_qos_add_ts_success_fnp(struct mac_context *mac_ctx, + tListElem *entry) +{ + struct sme_qos_sessioninfo *qos_session; + struct sme_qos_acinfo *ac_info; + struct sme_qos_flowinfoentry *flow_info = NULL; + bool inform_hdd = false; + bool delete_entry = false; + enum sme_qos_statustype hdd_status = SME_QOS_STATUS_SETUP_FAILURE_RSP; + enum qca_wlan_ac_type ac; + QDF_STATUS pmc_status = QDF_STATUS_E_FAILURE; + tCsrRoamModifyProfileFields profile_fields; + uint8_t psb; + uint8_t tspec_index; + + if (!entry) { + sme_err("Entry is NULL"); + return QDF_STATUS_E_FAILURE; + } + flow_info = GET_BASE_ADDR(entry, struct sme_qos_flowinfoentry, link); + ac = flow_info->ac_type; + qos_session = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + ac_info = &qos_session->ac_info[ac]; + tspec_index = ac_info->tspec_pending - 1; + if (flow_info->tspec_mask != ac_info->tspec_pending) { + sme_debug(" No need to notify the HDD, the ADDTS success is not for index = %d of the AC = %d", + flow_info->tspec_mask, ac); + return QDF_STATUS_SUCCESS; + } + switch (flow_info->reason) { + case SME_QOS_REASON_SETUP: + hdd_status = SME_QOS_STATUS_SETUP_SUCCESS_IND; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + delete_entry = false; + inform_hdd = true; + /* check if App is looking for APSD + * notify PMC as App is looking for APSD. If we already + * requested then we don't need to do anything + */ + if (ac_info->requested_QoSInfo[tspec_index].ts_info.psb) { + /* this is the first flow to detect we need + * PMC in UAPSD mode + */ + pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), + flow_info->sessionId); + /* if PMC doesn't return success right away means + * it is yet to put the module in BMPS state & later + * to UAPSD state + */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } + } + break; + case SME_QOS_REASON_RELEASE: + ac_info->num_flows[tspec_index]--; + hdd_status = SME_QOS_STATUS_RELEASE_SUCCESS_RSP; + inform_hdd = true; + delete_entry = true; + break; + case SME_QOS_REASON_MODIFY: + delete_entry = true; + inform_hdd = false; + break; + case SME_QOS_REASON_MODIFY_PENDING: + hdd_status = SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND; + delete_entry = false; + flow_info->reason = SME_QOS_REASON_REQ_SUCCESS; + inform_hdd = true; + psb = ac_info->requested_QoSInfo[tspec_index].ts_info.psb; + /* notify PMC if App is looking for APSD + */ + if (psb) { + /* this is the first flow to detect + * we need PMC in UAPSD mode + */ + pmc_status = sme_ps_start_uapsd(MAC_HANDLE(mac_ctx), + flow_info->sessionId); + /* if PMC doesn't return success right + * away means it is yet to put + * the module in BMPS state & later to UAPSD state + */ + if (QDF_STATUS_E_FAILURE == pmc_status) { + hdd_status = + SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_IND_APSD_SET_FAILED; + /* we need to always notify this case */ + flow_info->hoRenewal = false; + } + } else if (!psb && + ((ac_info->num_flows[flow_info->tspec_mask - 1] == 1) + && (SME_QOS_TSPEC_MASK_BIT_1_2_SET != + ac_info->tspec_mask_status))) { + /* this is the only TSPEC active on this AC */ + /* so indicate that we no longer require APSD */ + qos_session->apsdMask &= + ~(1 << (QCA_WLAN_AC_VO - ac)); + /* Also update modifyProfileFields.uapsd_mask + * in CSR for consistency + */ + csr_get_modify_profile_fields(mac_ctx, + flow_info->sessionId, + &profile_fields); + profile_fields.uapsd_mask = + qos_session->apsdMask; + csr_set_modify_profile_fields(mac_ctx, + flow_info->sessionId, + &profile_fields); + if (!qos_session->apsdMask) + sme_ps_uapsd_disable(MAC_HANDLE(mac_ctx), + flow_info->sessionId); + } + break; + case SME_QOS_REASON_REQ_SUCCESS: + hdd_status = SME_QOS_STATUS_SETUP_MODIFIED_IND; + inform_hdd = true; + fallthrough; + default: + delete_entry = false; + break; + } + if (inform_hdd) { + if (!flow_info->hoRenewal) { + flow_info->QoSCallback(MAC_HANDLE(mac_ctx), + flow_info->HDDcontext, + &ac_info->curr_QoSInfo[tspec_index], + hdd_status, + flow_info->QosFlowID); + } else + flow_info->hoRenewal = false; + } + if (delete_entry) { + sme_debug("Deleting entry at %pK with flowID %d", + flow_info, flow_info->QosFlowID); + /* delete the entry from Flow List */ + csr_ll_remove_entry(&sme_qos_cb.flow_list, entry, true); + /* reclaim the memory */ + qdf_mem_free(flow_info); + } + return QDF_STATUS_SUCCESS; +} + +/* + * sme_qos_is_rsp_pending() - Utility function to check if we are waiting + * for an AddTS or reassoc response on some AC other than the given AC + * + * sessionId - Session we are interted in + * ac - Enumeration of the various EDCA Access Categories. + * + * Return bool + * true - Response is pending on an AC + */ +static bool sme_qos_is_rsp_pending(uint8_t sessionId, enum qca_wlan_ac_type ac) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type acIndex; + bool status = false; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (acIndex = QCA_WLAN_AC_BE; acIndex < QCA_WLAN_AC_ALL; + acIndex++) { + if (acIndex == ac) + continue; + pACInfo = &pSession->ac_info[acIndex]; + if ((pACInfo->tspec_pending) || (pACInfo->reassoc_pending)) { + status = true; + break; + } + } + return status; +} + +/* + * sme_qos_update_hand_off() - Function which can be called to update + * Hand-off state of SME QoS Session + * + * sessionId - session id + * updateHandOff - value True/False to update the handoff flag + */ +void sme_qos_update_hand_off(uint8_t sessionId, bool updateHandOff) +{ + struct sme_qos_sessioninfo *pSession; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if (pSession->handoffRequested != updateHandOff) + sme_debug("handoffRequested %d updateHandOff %d", + pSession->handoffRequested, updateHandOff); + + pSession->handoffRequested = updateHandOff; + +} + +/* + * sme_qos_is_uapsd_active() - Function which can be called to determine + * if any sessions require PMC to be in U-APSD mode. + * Return bool + * + * Returns true if at least one session required PMC to be in U-APSD mode + * Returns false if no sessions require PMC to be in U-APSD mode + */ +static bool sme_qos_is_uapsd_active(void) +{ + struct sme_qos_sessioninfo *pSession; + uint8_t sessionId; + + for (sessionId = 0; sessionId < WLAN_MAX_VDEVS; ++sessionId) { + pSession = &sme_qos_cb.sessionInfo[sessionId]; + if ((pSession->sessionActive) && (pSession->apsdMask)) + return true; + } + /* no active sessions have U-APSD active */ + return false; +} + +QDF_STATUS sme_offload_qos_process_out_of_uapsd_mode(struct mac_context *mac, + uint32_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + tListElem *pEntry = NULL, *pNextEntry = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + sme_debug("Flow List empty, can't search"); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, + link); + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + /* only notify the flows which already successfully setup + * UAPSD + */ + if ((sessionId == flow_info->sessionId) && + (flow_info->QoSInfo.max_service_interval || + flow_info->QoSInfo.min_service_interval) && + (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pSession->ac_info[flow_info-> + ac_type].curr_QoSInfo + [flow_info->tspec_mask - 1], + SME_QOS_STATUS_OUT_OF_APSD_POWER_MODE_IND, + flow_info->QosFlowID); + } + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS sme_offload_qos_process_into_uapsd_mode(struct mac_context *mac, + uint32_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + tListElem *pEntry = NULL, *pNextEntry = NULL; + struct sme_qos_flowinfoentry *flow_info = NULL; + + pEntry = csr_ll_peek_head(&sme_qos_cb.flow_list, false); + if (!pEntry) { + sme_err("Flow List empty, can't search"); + return QDF_STATUS_E_FAILURE; + } + while (pEntry) { + pNextEntry = csr_ll_next(&sme_qos_cb.flow_list, pEntry, false); + flow_info = GET_BASE_ADDR(pEntry, struct sme_qos_flowinfoentry, + link); + pSession = &sme_qos_cb.sessionInfo[flow_info->sessionId]; + /* only notify the flows which already successfully setup + * UAPSD + */ + if ((sessionId == flow_info->sessionId) && + (flow_info->QoSInfo.max_service_interval || + flow_info->QoSInfo.min_service_interval) && + (SME_QOS_REASON_REQ_SUCCESS == flow_info->reason)) { + flow_info->QoSCallback(MAC_HANDLE(mac), + flow_info->HDDcontext, + &pSession->ac_info[flow_info-> + ac_type].curr_QoSInfo + [flow_info->tspec_mask - 1], + SME_QOS_STATUS_INTO_APSD_POWER_MODE_IND, + flow_info->QosFlowID); + } + pEntry = pNextEntry; + } + return QDF_STATUS_SUCCESS; +} + +void sme_qos_cleanup_ctrl_blk_for_handoff(struct mac_context *mac, + uint8_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + enum qca_wlan_ac_type ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + sme_debug("invoked on session %d", sessionId); + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + qdf_mem_zero(pACInfo->curr_QoSInfo, + sizeof(struct sme_qos_wmmtspecinfo) * + SME_QOS_TSPEC_INDEX_MAX); + qdf_mem_zero(pACInfo->requested_QoSInfo, + sizeof(struct sme_qos_wmmtspecinfo) * + SME_QOS_TSPEC_INDEX_MAX); + pACInfo->num_flows[0] = 0; + pACInfo->num_flows[1] = 0; + pACInfo->reassoc_pending = false; + pACInfo->tspec_mask_status = 0; + pACInfo->tspec_pending = false; + pACInfo->hoRenewal = false; + pACInfo->prev_state = SME_QOS_LINK_UP; + } +} + +/** + * sme_qos_is_ts_info_ack_policy_valid() - check if ACK policy is allowed. + * @mac_handle: The handle returned by mac_open. + * @pQoSInfo: Pointer to struct sme_qos_wmmtspecinfo which contains the + * WMM TSPEC related info, provided by HDD + * @sessionId: sessionId returned by sme_open_session. + * + * The SME QoS API exposed to HDD to check if TS info ack policy field can be + * set to "HT-immediate block acknowledgment" + * + * Return: true - Current Association is HT association and so TS info ack + * policy can be set to "HT-immediate block acknowledgment" + */ +bool sme_qos_is_ts_info_ack_policy_valid(mac_handle_t mac_handle, + struct sme_qos_wmmtspecinfo *pQoSInfo, + uint8_t sessionId) +{ + tDot11fBeaconIEs *pIes = NULL; + struct sme_qos_sessioninfo *pSession; + QDF_STATUS hstatus; + struct mac_context *mac = MAC_CONTEXT(mac_handle); + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Session Id %d is invalid", sessionId); + return false; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + + if (!pSession->sessionActive) { + sme_err("Session %d is inactive", sessionId); + return false; + } + + if (!pSession->assocInfo.bss_desc) { + sme_err("Session %d has an Invalid BSS Descriptor", sessionId); + return false; + } + + hstatus = csr_get_parsed_bss_description_ies(mac, + pSession->assocInfo.bss_desc, + &pIes); + if (!QDF_IS_STATUS_SUCCESS(hstatus)) { + sme_err("On session %d unable to parse BSS IEs", sessionId); + return false; + } + + /* success means pIes was allocated */ + + if (!pIes->HTCaps.present && + pQoSInfo->ts_info.ack_policy == + SME_QOS_WMM_TS_ACK_POLICY_HT_IMMEDIATE_BLOCK_ACK) { + sme_err("On session %d HT Caps aren't present but application set ack policy to HT ", + sessionId); + + qdf_mem_free(pIes); + return false; + } + + qdf_mem_free(pIes); + return true; +} + +static bool sme_qos_validate_requested_params(struct mac_context *mac, + struct sme_qos_wmmtspecinfo *qos_info, + uint8_t session_id) +{ + if (SME_QOS_WMM_TS_DIR_RESV == qos_info->ts_info.direction) + return false; + if (!sme_qos_is_ts_info_ack_policy_valid(MAC_HANDLE(mac), + qos_info, session_id)) + return false; + + return true; +} + +static QDF_STATUS qos_issue_command(struct mac_context *mac, uint8_t vdev_id, + eSmeCommandType cmdType, + struct sme_qos_wmmtspecinfo *pQoSInfo, + enum qca_wlan_ac_type ac, uint8_t tspec_mask) +{ + QDF_STATUS status = QDF_STATUS_E_RESOURCES; + tSmeCmd *pCommand = NULL; + + do { + pCommand = csr_get_command_buffer(mac); + if (!pCommand) { + sme_err("fail to get command buffer for command %d", + cmdType); + break; + } + pCommand->command = cmdType; + pCommand->vdev_id = vdev_id; + switch (cmdType) { + case eSmeCommandAddTs: + if (pQoSInfo) { + status = QDF_STATUS_SUCCESS; + pCommand->u.qosCmd.tspecInfo = *pQoSInfo; + pCommand->u.qosCmd.ac = ac; + } else { + sme_err("NULL pointer passed"); + status = QDF_STATUS_E_INVAL; + } + break; + case eSmeCommandDelTs: + status = QDF_STATUS_SUCCESS; + pCommand->u.qosCmd.ac = ac; + pCommand->u.qosCmd.tspec_mask = tspec_mask; + break; + default: + sme_err("invalid command type %d", cmdType); + status = QDF_STATUS_E_INVAL; + break; + } + } while (0); + if (QDF_IS_STATUS_SUCCESS(status) && pCommand) + csr_queue_sme_command(mac, pCommand, false); + else if (pCommand) + qos_release_command(mac, pCommand); + + return status; +} + +bool qos_process_command(struct mac_context *mac, tSmeCmd *pCommand) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool fRemoveCmd = true; + + do { + switch (pCommand->command) { + case eSmeCommandAddTs: + status = + sme_qos_add_ts_req(mac, (uint8_t) + pCommand->vdev_id, + &pCommand->u.qosCmd.tspecInfo, + pCommand->u.qosCmd.ac); + if (QDF_IS_STATUS_SUCCESS(status)) + fRemoveCmd = false; + break; + case eSmeCommandDelTs: + status = + sme_qos_del_ts_req(mac, (uint8_t) + pCommand->vdev_id, + pCommand->u.qosCmd.ac, + pCommand->u.qosCmd.tspec_mask); + if (QDF_IS_STATUS_SUCCESS(status)) + fRemoveCmd = false; + break; + default: + sme_err("invalid command type %d", pCommand->command); + break; + } /* switch */ + } while (0); + return fRemoveCmd; +} + +/** + * sme_qos_re_request_add_ts - Re-send AddTS for the combined QoS request + * + * @mac_ctx Pointer to mac context + * @session_id SME session id + * @qos_info - Tspec information + * @ac - Access category + * @tspec_mask - Tspec Mask + * + * This function is called to re-send AddTS for the combined QoS request + * + * Return: status + */ +static +enum sme_qos_statustype sme_qos_re_request_add_ts(struct mac_context *mac_ctx, + uint8_t session_id, struct sme_qos_wmmtspecinfo *qos_info, + enum qca_wlan_ac_type ac, uint8_t tspec_mask) +{ + struct sme_qos_sessioninfo *session; + struct sme_qos_acinfo *ac_info; + enum sme_qos_statustype status = + SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + struct sme_qos_cmdinfo cmd; + + sme_debug(" Invoked on session %d for AC %d TSPEC %d", session_id, ac, + tspec_mask); + session = &sme_qos_cb.sessionInfo[session_id]; + ac_info = &session->ac_info[ac]; + /* + * call PMC's request for power function + * AND another check is added considering the flowing scenario + * Addts request is pending on one AC, while APSD requested on + * another which needs a reassoc. Will buffer a request if Addts + * is pending on any AC, which will safeguard the above scenario, + * 2& also won't confuse PE with back to back Addts or Addts + * followed by Reassoc. + */ + if (sme_qos_is_rsp_pending(session_id, ac)) { + sme_err("On session %d buffering the AddTS request for AC %d in state %d as Addts is pending on other AC or waiting for full power", + session_id, ac, ac_info->curr_state); + /* buffer cmd */ + cmd.command = SME_QOS_RESEND_REQ; + cmd.mac = mac_ctx; + cmd.sessionId = session_id; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = tspec_mask; + cmd.u.resendCmdInfo.QoSInfo = *qos_info; + if (!QDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { + sme_err("On session %d unable to buffer the AddTS request for AC %d TSPEC %d in state %d", + session_id, ac, tspec_mask, + ac_info->curr_state); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + return SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + } + + /* get into the stat m/c to see if the request can be granted */ + switch (ac_info->curr_state) { + case SME_QOS_QOS_ON: + { + /* if ACM, send out a new ADDTS */ + ac_info->hoRenewal = true; + status = sme_qos_setup(mac_ctx, session_id, qos_info, ac); + sme_debug("sme_qos_setup returned in SME_QOS_QOS_ON state sme_qos_setup AC %d with status =%d", + ac, status); + if (SME_QOS_STATUS_SETUP_REQ_PENDING_RSP == status) { + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + ac_info->tspec_pending = tspec_mask; + } else if ((SME_QOS_STATUS_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) || + (SME_QOS_STATUS_SETUP_SUCCESS_APSD_SET_ALREADY == + status) || + (SME_QOS_STATUS_SETUP_SUCCESS_IND_APSD_PENDING == + status)) { + sme_err("UAPSD is setup already status = %d ", status); + } else { + sme_err("sme_qos_setup return status = %d ", status); + } + } + break; + case SME_QOS_HANDOFF: + case SME_QOS_REQUESTED: + sme_err("Re-Add request in state = %d buffer the request", + ac_info->curr_state); + cmd.command = SME_QOS_RESEND_REQ; + cmd.mac = mac_ctx; + cmd.sessionId = session_id; + cmd.u.resendCmdInfo.ac = ac; + cmd.u.resendCmdInfo.tspecMask = tspec_mask; + cmd.u.resendCmdInfo.QoSInfo = *qos_info; + if (!QDF_IS_STATUS_SUCCESS(sme_qos_buffer_cmd(&cmd, false))) { + sme_err(" couldn't buf the read request state = %d", + ac_info->curr_state); + return SME_QOS_STATUS_MODIFY_SETUP_FAILURE_RSP; + } + status = SME_QOS_STATUS_MODIFY_SETUP_PENDING_RSP; + break; + case SME_QOS_CLOSED: + case SME_QOS_INIT: + case SME_QOS_LINK_UP: + default: + /* print error msg, */ + sme_err("Re-Add request in unexpected state = %d", + ac_info->curr_state); + break; + } + if ((SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_NO_ACM_NO_APSD_RSP == + status) || + (SME_QOS_STATUS_MODIFY_SETUP_SUCCESS_APSD_SET_ALREADY == + status)) + (void)sme_qos_process_buffered_cmd(session_id); + + return status; +} + +static void sme_qos_init_a_cs(struct mac_context *mac, uint8_t sessionId) +{ + struct sme_qos_sessioninfo *pSession; + enum qca_wlan_ac_type ac; + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + qdf_mem_zero(&pSession->ac_info[ac], + sizeof(struct sme_qos_acinfo)); + sme_qos_state_transition(sessionId, ac, SME_QOS_INIT); + } +} + +static QDF_STATUS sme_qos_request_reassoc(struct mac_context *mac, + uint8_t sessionId, + tCsrRoamModifyProfileFields * + pModFields, bool fForce) +{ + struct sme_qos_sessioninfo *pSession; + struct sme_qos_acinfo *pACInfo; + QDF_STATUS status; + struct qdf_mac_addr bssid; + qdf_freq_t ch_freq; + + sme_debug("Invoked on session %d with UAPSD mask 0x%X", + sessionId, pModFields->uapsd_mask); + + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Invalid session for sessionId: %d", sessionId); + return QDF_STATUS_E_FAILURE; + } + + pSession = &sme_qos_cb.sessionInfo[sessionId]; + wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, &bssid); + ch_freq = wlan_get_operation_chan_freq_vdev_id(mac->pdev, sessionId); + status = wlan_cm_roam_invoke(mac->pdev, sessionId, &bssid, ch_freq, + CM_ROAMING_HOST); + + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Update the state to Handoff so subsequent requests are + * queued until this one is finished + */ + enum qca_wlan_ac_type ac; + + for (ac = QCA_WLAN_AC_BE; ac < QCA_WLAN_AC_ALL; ac++) { + pACInfo = &pSession->ac_info[ac]; + sme_debug("AC[%d] is in state [%d]", + ac, pACInfo->curr_state); + /* If it is already in HANDOFF state, don't do + * anything since we MUST preserve the previous state + * and sme_qos_state_transition will change the previous + * state + */ + if (SME_QOS_HANDOFF != pACInfo->curr_state) + sme_qos_state_transition(sessionId, ac, + SME_QOS_HANDOFF); + } + } + return status; +} + +static uint32_t sme_qos_assign_flow_id(void) +{ + uint32_t flowId; + + flowId = sme_qos_cb.nextFlowId; + if (SME_QOS_MAX_FLOW_ID == flowId) { + /* The Flow ID wrapped. This is obviously not a real life + * scenario but handle it to keep the software test folks happy + */ + sme_debug("Software Test made the flow counter wrap, QoS may no longer be functional"); + sme_qos_cb.nextFlowId = SME_QOS_MIN_FLOW_ID; + } else + sme_qos_cb.nextFlowId++; + + return flowId; +} + +static uint8_t sme_qos_assign_dialog_token(void) +{ + uint8_t token; + + token = sme_qos_cb.nextDialogToken; + if (SME_QOS_MAX_DIALOG_TOKEN == token) + /* wrap is ok */ + sme_qos_cb.nextDialogToken = SME_QOS_MIN_DIALOG_TOKEN; + else + sme_qos_cb.nextDialogToken++; + + sme_debug("token %d", token); + return token; +} +#endif /* WLAN_MDM_CODE_REDUCTION_OPT */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/rrm/sme_rrm.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/rrm/sme_rrm.c new file mode 100644 index 0000000000..1d8768c93f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/rrm/sme_rrm.c @@ -0,0 +1,2225 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * DOC: sme_rrm.c + * + * Implementation for SME RRM APIs + */ + +#include "ani_global.h" +#include "sme_inside.h" +#include "sme_api.h" + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +#include "host_diag_core_event.h" +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +#include "csr_inside_api.h" + +#include "rrm_global.h" +#include +#include +#include +#include +#include <../../core/src/wlan_cm_vdev_api.h> +#include "rrm_api.h" +#include "wlan_cp_stats_mc_ucfg_api.h" + +/* Roam score for a neighbor AP will be calculated based on the below + * definitions. The calculated roam score will be used to select the + * roamable candidate from neighbor AP list + */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY 0 +/* When we support 11r over the DS, this should have a non-zero value */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY 10 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE 20 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT 0 +/* Not used */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS 5 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD 3 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM 8 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA 0 +/* We dont support delayed BA */ +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA 3 +#define RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN 30 + +#ifdef FEATURE_WLAN_ESE +#define RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST 30 +#endif +/* RRM SCAN DWELL TIME */ +#define RRM_SCAN_MIN_DWELL_TIME 20 + +uint64_t rrm_scan_timer; + +/** + * rrm_ll_purge_neighbor_cache() -Purges all the entries in the neighbor cache + * + * @mac: Pointer to the Hal Handle. + * @pList: Pointer the List that should be purged. + * + * This function purges all the entries in the neighbor cache and frees up all + * the internal nodes + * + * Return: void + */ +static void rrm_ll_purge_neighbor_cache(struct mac_context *mac, + tDblLinkList *pList) +{ + tListElem *pEntry; + tRrmNeighborReportDesc *pNeighborReportDesc; + + csr_ll_lock(pList); + while ((pEntry = csr_ll_remove_head(pList, LL_ACCESS_NOLOCK)) != NULL) { + pNeighborReportDesc = + GET_BASE_ADDR(pEntry, tRrmNeighborReportDesc, List); + qdf_mem_free(pNeighborReportDesc->pNeighborBssDescription); + qdf_mem_free(pNeighborReportDesc); + } + csr_ll_unlock(pList); +} + +/** + * rrm_indicate_neighbor_report_result() -calls the callback registered for + * neighbor report + * @mac: Pointer to the Hal Handle. + * @qdf_status - QDF_STATUS_SUCCESS/QDF_STATUS_FAILURE based on whether a valid + * report is received or neighbor timer expired + * + * This function calls the callback register by the caller while requesting for + * neighbor report. This function gets invoked if a neighbor report is received + * from an AP or neighbor response wait timer expires. + * + * Return: void + */ +static void rrm_indicate_neighbor_report_result(struct mac_context *mac, + QDF_STATUS qdf_status) +{ + NeighborReportRspCallback callback; + void *callbackContext; + + /* Reset the neighbor response pending status */ + mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX]. + neighborReqControlInfo.isNeighborRspPending = false; + + /* Stop the timer if it is already running. + * The timer should be running only in the SUCCESS case. + */ + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX]. + neighborReqControlInfo. + neighborRspWaitTimer)) { + sme_debug("No entry in neighbor report cache"); + qdf_mc_timer_stop(&mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX]. + neighborReqControlInfo.neighborRspWaitTimer); + } + callback = + mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX].neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallback; + callbackContext = + mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX].neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallbackContext; + + /* Reset the callback and the callback context before calling the + * callback. It is very likely that there may be a registration in + * callback itself. + */ + mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX].neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallback = NULL; + mac->rrm.rrmSmeContext[DEFAULT_RRM_IDX].neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallbackContext = NULL; + + /* Call the callback with the status received from caller */ + if (callback) + callback(callbackContext, qdf_status); +} + +/** + * sme_RrmBeaconReportXmitInd () - Send beacon report + * @mac_ctx Pointer to mac context + * @measurement_index: Measurement index + * @result_arr scan results + * @msrmnt_status flag to indicate that the measurement is done. + * @bss_count bss count + * + * Create and send the beacon report Xmit ind message to PE. + * + * Return: status + */ + +static QDF_STATUS +sme_rrm_send_beacon_report_xmit_ind(struct mac_context *mac_ctx, + uint8_t measurement_index, tCsrScanResultInfo **result_arr, + uint8_t msrmnt_status, uint8_t bss_count) +{ + struct bss_description *bss_desc = NULL; + tpSirBeaconReportXmitInd beacon_rep; + uint16_t length; + uint32_t size; + uint8_t i = 0, j = 0, counter = 0; + tCsrScanResultInfo *cur_result = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + tpRrmSMEContext rrm_ctx = + &mac_ctx->rrm.rrmSmeContext[measurement_index]; + struct bss_description *tmp_bss_desc[SIR_BCN_REPORT_MAX_BSS_DESC] = {0}; + + if (!result_arr && !msrmnt_status) { + sme_err("Beacon report xmit Ind to PE Failed"); + return QDF_STATUS_E_FAILURE; + } + + if (result_arr) + cur_result = result_arr[j]; + + do { + length = sizeof(tSirBeaconReportXmitInd); + beacon_rep = qdf_mem_malloc(length); + if (!beacon_rep) + return QDF_STATUS_E_NOMEM; + + beacon_rep->messageType = eWNI_SME_BEACON_REPORT_RESP_XMIT_IND; + beacon_rep->length = length; + beacon_rep->measurement_idx = measurement_index; + beacon_rep->uDialogToken = rrm_ctx->token; + beacon_rep->duration = rrm_ctx->duration[0]; + beacon_rep->regClass = rrm_ctx->regClass; + qdf_mem_copy(beacon_rep->bssId, rrm_ctx->sessionBssId.bytes, + QDF_MAC_ADDR_SIZE); + + i = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (!bss_desc) + break; + size = bss_desc->length + sizeof(bss_desc->length); + beacon_rep->pBssDescription[i] = qdf_mem_malloc(size); + if (NULL == + beacon_rep->pBssDescription[i]) + break; + qdf_mem_copy(beacon_rep->pBssDescription[i], + bss_desc, size); + tmp_bss_desc[i] = + beacon_rep->pBssDescription[i]; + sme_debug("RRM Result Bssid = " QDF_MAC_ADDR_FMT + " freq= %d, rssi = -%d", + QDF_MAC_ADDR_REF( + beacon_rep->pBssDescription[i]->bssId), + beacon_rep->pBssDescription[i]->chan_freq, + beacon_rep->pBssDescription[i]->rssi * (-1)); + beacon_rep->numBssDesc++; + if (++i >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + if (i + j >= bss_count) + break; + cur_result = + result_arr[j + i]; + } + + j += i; + if (!result_arr || (!cur_result) + || (j >= bss_count)) { + cur_result = NULL; + sme_debug("Reached to max/last BSS in cur_result list"); + } else { + cur_result = result_arr[j]; + sme_debug("Move to the next BSS set in cur_result list"); + } + beacon_rep->fMeasureDone = + (cur_result) ? false : msrmnt_status; + sme_debug("SME Sending BcnRepXmit to PE numBss %d i %d j %d", + beacon_rep->numBssDesc, i, j); + status = umac_send_mb_message_to_mac(beacon_rep); + if (status != QDF_STATUS_SUCCESS) + for (counter = 0; counter < i; ++counter) + qdf_mem_free(tmp_bss_desc[counter]); + } while (cur_result); + + return status; +} + +#ifdef FEATURE_WLAN_ESE +/** + * sme_ese_send_beacon_req_scan_results () - Send beacon report + * @mac_ctx: Pointer to mac context + * @measurement_index: Measurement request index + * @session_id: session id + * @freq: channel frequency + * @result_arr: scan results + * @msrmnt_status: flag to indicate that the measurement is done. + * @bss_count: number of bss found + * + * This function sends up the scan results received as a part of + * beacon request scanning. + * This function is called after receiving the scan results per channel + * Due to the limitation on the size of the IWEVCUSTOM buffer, we send + * 3 BSSIDs of beacon report information in one custom event; + * + * Return: status + */ +static QDF_STATUS sme_ese_send_beacon_req_scan_results( + struct mac_context *mac_ctx, uint8_t measurement_index, + uint32_t session_id, uint32_t freq, + tCsrScanResultInfo **result_arr, + uint8_t msrmnt_status, uint8_t bss_count) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + QDF_STATUS fill_ie_status; + struct bss_description *bss_desc = NULL; + uint32_t ie_len = 0; + uint32_t out_ie_len = 0; + uint8_t bss_counter = 0; + tCsrScanResultInfo *cur_result = NULL; + tpRrmSMEContext rrm_ctx = + &mac_ctx->rrm.rrmSmeContext[measurement_index]; + struct csr_roam_info *roam_info; + struct ese_bcn_report_rsp bcn_rpt_rsp; + struct ese_bcn_report_rsp *bcn_report = &bcn_rpt_rsp; + tpCsrEseBeaconReqParams cur_meas_req = NULL; + uint8_t i = 0, j = 0; + tBcnReportFields *bcn_rpt_fields; + + if (!rrm_ctx) { + sme_err("rrm_ctx is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!result_arr && !msrmnt_status) { + sme_err("Beacon report xmit Ind to HDD Failed"); + return QDF_STATUS_E_FAILURE; + } + + roam_info = qdf_mem_malloc(sizeof(*roam_info)); + if (!roam_info) + return QDF_STATUS_E_NOMEM; + + if (result_arr) + cur_result = result_arr[bss_counter]; + + do { + cur_meas_req = NULL; + /* memset bcn_rpt_rsp for each iteration */ + qdf_mem_zero(&bcn_rpt_rsp, sizeof(bcn_rpt_rsp)); + + for (i = 0; i < rrm_ctx->eseBcnReqInfo.numBcnReqIe; i++) { + if (rrm_ctx->eseBcnReqInfo.bcnReq[i].ch_freq == freq) { + cur_meas_req = + &rrm_ctx->eseBcnReqInfo.bcnReq[i]; + break; + } + } + if (cur_meas_req) + bcn_report->measurementToken = + cur_meas_req->measurementToken; + sme_debug("freq: %d MeasToken: %d", freq, + bcn_report->measurementToken); + + j = 0; + while (cur_result) { + bss_desc = &cur_result->BssDescriptor; + if (!bss_desc) { + cur_result = NULL; + break; + } + ie_len = GET_IE_LEN_IN_BSS(bss_desc->length); + bcn_rpt_fields = + &bcn_report->bcnRepBssInfo[j].bcnReportFields; + bcn_rpt_fields->ChanNum = wlan_reg_freq_to_chan( + mac_ctx->pdev, + bss_desc->chan_freq); + bcn_report->bcnRepBssInfo[j].bcnReportFields.Spare = 0; + if (cur_meas_req) + bcn_rpt_fields->MeasDuration = + cur_meas_req->measurementDuration; + bcn_rpt_fields->PhyType = bss_desc->nwType; + bcn_rpt_fields->RecvSigPower = bss_desc->rssi; + bcn_rpt_fields->ParentTsf = bss_desc->parentTSF; + bcn_rpt_fields->TargetTsf[0] = bss_desc->timeStamp[0]; + bcn_rpt_fields->TargetTsf[1] = bss_desc->timeStamp[1]; + bcn_rpt_fields->BcnInterval = bss_desc->beaconInterval; + bcn_rpt_fields->CapabilityInfo = + bss_desc->capabilityInfo; + + qdf_mem_copy(bcn_rpt_fields->Bssid, + bss_desc->bssId, sizeof(tSirMacAddr)); + fill_ie_status = + sir_beacon_ie_ese_bcn_report(mac_ctx, + (uint8_t *) bss_desc->ieFields, + ie_len, + &(bcn_report->bcnRepBssInfo[j]. + pBuf), + &out_ie_len); + if (QDF_STATUS_E_FAILURE == fill_ie_status) + continue; + bcn_report->bcnRepBssInfo[j].ieLen = out_ie_len; + + sme_debug("Bssid"QDF_MAC_ADDR_FMT" Freq:%d Rssi:%d", + QDF_MAC_ADDR_REF(bss_desc->bssId), + bss_desc->chan_freq, (-1) * bss_desc->rssi); + bcn_report->numBss++; + if (++j >= SIR_BCN_REPORT_MAX_BSS_DESC) + break; + if ((bss_counter + j) >= bss_count) + break; + cur_result = result_arr[bss_counter + j]; + } + + bss_counter += j; + if (!result_arr || !cur_result || (bss_counter >= bss_count)) { + cur_result = NULL; + sme_err("Reached to the max/last BSS in cur_result list"); + } else { + cur_result = result_arr[bss_counter]; + sme_err("Move to the next BSS set in cur_result list"); + } + + bcn_report->flag = + (msrmnt_status << 1) | ((cur_result) ? true : false); + + sme_debug("SME Sending BcnRep to HDD numBss: %d j: %d bss_counter: %d flag: %d", + bcn_report->numBss, j, bss_counter, + bcn_report->flag); + + roam_info->pEseBcnReportRsp = bcn_report; + status = csr_roam_call_callback(mac_ctx, session_id, roam_info, + eCSR_ROAM_ESE_BCN_REPORT_IND, 0); + + /* Free the memory allocated to IE */ + for (i = 0; i < j; i++) + if (bcn_report->bcnRepBssInfo[i].pBuf) + qdf_mem_free(bcn_report->bcnRepBssInfo[i].pBuf); + } while (cur_result); + qdf_mem_free(roam_info); + return status; +} + +static inline +void sme_reset_ese_bcn_req_in_progress(tpRrmSMEContext sme_rrm_ctx) +{ + if (sme_rrm_ctx) + sme_rrm_ctx->eseBcnReqInProgress = false; +} + +#else + +static inline +void sme_reset_ese_bcn_req_in_progress(tpRrmSMEContext sme_rrm_ctx) +{} +#endif /* FEATURE_WLAN_ESE */ + +/** + * sme_rrm_send_scan_result() - to get scan result and send the beacon report + * @mac_ctx: pointer to mac context + * @measurement_index: Measurement request number + * @num_chan: number of channels + * @freq_list: list of channel frequencies to fetch the result from + * @measurementdone: Flag to indicate measurement done or no + * + * This function is called to get the scan result from CSR and send the beacon + * report xmit ind message to PE + * + * Return: QDF_STATUS + */ +static QDF_STATUS sme_rrm_send_scan_result(struct mac_context *mac_ctx, + uint8_t measurement_index, + uint8_t num_chan, + uint32_t *freq_list, + uint8_t measurementdone) +{ + struct scan_filter *filter; + tScanResultHandle result_handle; + tCsrScanResultInfo *scan_results, *next_result; + tCsrScanResultInfo **scanresults_arr = NULL; + struct scan_result_list *result_list; + QDF_STATUS status; + uint32_t num_scan_results, counter = 0; + tpRrmSMEContext rrm_ctx = + &mac_ctx->rrm.rrmSmeContext[measurement_index]; + uint32_t session_id; + tSirScanType scan_type; + struct qdf_mac_addr bss_peer_mac; + + filter = qdf_mem_malloc(sizeof(*filter)); + if (!filter) + return QDF_STATUS_E_NOMEM; + + if (qdf_is_macaddr_zero(filter->bssid_list) || + qdf_is_macaddr_group(filter->bssid_list)) { + filter->num_of_bssid = 0; + } else { + /* update filter to get scan result with just target BSSID */ + filter->num_of_bssid = 1; + qdf_mem_copy(filter->bssid_list[0].bytes, + rrm_ctx->bssId, sizeof(struct qdf_mac_addr)); + } + + if (rrm_ctx->ssId.length) { + filter->num_of_ssid = 1; + filter->ssid_list[0].length = rrm_ctx->ssId.length; + if (filter->ssid_list[0].length > WLAN_SSID_MAX_LEN) + filter->ssid_list[0].length = WLAN_SSID_MAX_LEN; + qdf_mem_copy(filter->ssid_list[0].ssid, + rrm_ctx->ssId.ssId, filter->ssid_list[0].length); + } + + filter->num_of_channels = num_chan; + if (filter->num_of_channels > NUM_CHANNELS) + filter->num_of_channels = NUM_CHANNELS; + qdf_mem_copy(filter->chan_freq_list, freq_list, + filter->num_of_channels * + sizeof(filter->chan_freq_list[0])); + filter->rrm_measurement_filter = true; + + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == rrm_ctx->msgSource) + scan_type = rrm_ctx->measMode[rrm_ctx->currentIndex]; + else + scan_type = rrm_ctx->measMode[0]; + + if (scan_type == eSIR_BEACON_TABLE) + filter->age_threshold = + wlan_scan_get_aging_time(mac_ctx->psoc); + + + /* + * In case this is beacon report request from last AP (before roaming) + * following call to csr_roam_get_session_id_from_bssid will fail, + * hence use current session ID instead of one stored in SME rrm context + */ + if (QDF_STATUS_E_FAILURE == csr_roam_get_session_id_from_bssid(mac_ctx, + &rrm_ctx->sessionBssId, &session_id)) { + sme_debug("BSSID mismatch, using current session_id"); + session_id = mac_ctx->roam.roamSession->vdev_id; + } + status = csr_scan_get_result(mac_ctx, filter, &result_handle); + qdf_mem_free(filter); + + sme_debug("RRM Measurement Done %d for index:%d", + measurementdone, measurement_index); + if (!result_handle) { + /* + * no scan results + * Spec. doesn't say anything about such condition + * Since section 7.4.6.2 (IEEE802.11k-2008) says-rrm report + * frame should contain one or more report IEs. It probably + * means dont send any response if no matching BSS found. + * Moreover, there is no flag or field in measurement report + * IE(7.3.2.22) OR beacon report IE(7.3.2.22.6) that can be set + * to indicate no BSS found on a given channel. If we finished + * measurement on all the channels, we still need to send a + * xmit indication with moreToFollow set to MEASURMENT_DONE so + * that PE can clean any context allocated. + */ + if (!measurementdone) + return status; +#ifdef FEATURE_WLAN_ESE + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + measurement_index, session_id, + freq_list[0], NULL, + measurementdone, 0); + else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + measurement_index, NULL, + measurementdone, 0); + return status; + } + scan_results = csr_scan_result_get_first(mac_ctx, result_handle); + if (!scan_results && measurementdone) { +#ifdef FEATURE_WLAN_ESE + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) { + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + measurement_index, session_id, + freq_list[0], NULL, + measurementdone, 0); + } else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + measurement_index, + NULL, measurementdone, 0); + } + + result_list = (struct scan_result_list *)result_handle; + num_scan_results = csr_ll_count(&result_list->List); + if (!num_scan_results) { + sme_err("num_scan_results is %d", num_scan_results); + status = QDF_STATUS_E_FAILURE; + goto rrm_send_scan_results_done; + } + + sme_debug("num_scan_results %d", num_scan_results); + scanresults_arr = qdf_mem_malloc(num_scan_results * + sizeof(next_result)); + if (!scanresults_arr) { + status = QDF_STATUS_E_NOMEM; + goto send_scan_results; + } + + status = wlan_mlme_get_bssid_vdev_id(mac_ctx->pdev, session_id, + &bss_peer_mac); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("BSSID not found for vdev: %d", session_id); + status = QDF_STATUS_E_FAILURE; + goto send_scan_results; + } + + if (!cm_is_vdevid_connected(mac_ctx->pdev, session_id)) { + sme_err("vdev:%d is not connected", session_id); + status = QDF_STATUS_E_FAILURE; + goto send_scan_results; + } + + while (scan_results) { + /* + * Connected AP beacon is offloaded to firmware. + * Firmware will discard connected AP beacon except that + * special IE exists Connected AP beacon will not be sent + * to host. Hence, timer of connected AP in scan results is + * not updated and can not meet + * "pScanResult->timer >= RRM_scan_timer". + */ + uint8_t is_conn_bss_found = false; + uint8_t is_nontx_of_conn_bss = false; + + if (!qdf_mem_cmp(scan_results->BssDescriptor.bssId, + bss_peer_mac.bytes, + sizeof(struct qdf_mac_addr))) { + is_conn_bss_found = true; + sme_debug("Connected BSS in scan results"); + } + if (scan_results->BssDescriptor.mbssid_info.profile_num) { + if (!qdf_mem_cmp(scan_results->BssDescriptor. + mbssid_info.trans_bssid, + bss_peer_mac.bytes, + QDF_MAC_ADDR_SIZE)) { + is_nontx_of_conn_bss = true; + sme_debug("Non Tx BSS of Conn AP in results"); + } + } + next_result = csr_scan_result_get_next(mac_ctx, + result_handle); + sme_debug("Scan res timer:%lu, rrm scan timer:%llu", + scan_results->timer, rrm_scan_timer); + if ((scan_results->timer >= rrm_scan_timer) || + (is_conn_bss_found == true) || is_nontx_of_conn_bss) + scanresults_arr[counter++] = scan_results; + scan_results = next_result; + if (counter >= num_scan_results) + break; + } + +send_scan_results: + /* + * The beacon report should be sent whether the counter is zero or + * non-zero. There might be a few scan results in the cache but not + * actually are a result of this scan. During that scenario, the + * counter will be zero. The report should be sent and LIM will further + * cleanup the RRM to accept the further incoming requests + * In case the counter is Zero, the pScanResultsArr will be NULL. + * The next level routine does a check for the measurementDone to + * determine whether to send a report or not. + */ + sme_debug("Number of BSS Desc with RRM Scan %d", counter); + if (counter || measurementdone) { +#ifdef FEATURE_WLAN_ESE + if (eRRM_MSG_SOURCE_ESE_UPLOAD == rrm_ctx->msgSource) + status = sme_ese_send_beacon_req_scan_results(mac_ctx, + measurement_index, session_id, + freq_list[0], scanresults_arr, + measurementdone, counter); + else +#endif /* FEATURE_WLAN_ESE */ + status = sme_rrm_send_beacon_report_xmit_ind(mac_ctx, + measurement_index, scanresults_arr, + measurementdone, counter); + } + +rrm_send_scan_results_done: + if (scanresults_arr) + qdf_mem_free(scanresults_arr); + csr_scan_result_purge(mac_ctx, result_handle); + + return status; +} + +/** + * sme_rrm_scan_request_callback() -Sends the beacon report xmit to PE + * @mac_handle: Opaque handle to the MAC context + * @pSmeRrmContext: SME rrm context for measurement request + * @sessionId: session id + * @scanId: Scan ID. + * @status: CSR Status. + * + * The sme module calls this callback function once it finish the scan request + * and this function send the beacon report xmit to PE and starts a timer of + * random interval to issue next request. + * + * Return : 0 for success, non zero for failure + */ +static QDF_STATUS sme_rrm_scan_request_callback(struct mac_context *mac, + tpRrmSMEContext pSmeRrmContext, + uint8_t sessionId, + uint32_t scanId, + eCsrScanStatus status) +{ + uint8_t num_chan; + uint32_t *freq_list; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + /* + * Even if RRM scan response is received after roaming to different AP + * the messege shall be posted to PE for rrm cleanup. + */ + + freq_list = pSmeRrmContext->channelList.freq_list; + if (!freq_list) { + sme_err("[802.11 RRM]: Global freq list is null"); + pSmeRrmContext->channelList.numOfChannels = 0; + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + /* Sending the beacon report xmit for the all the valid channel + * scan results within randomization interval. + */ + num_chan = pSmeRrmContext->channelList.numOfChannels; + sme_rrm_send_scan_result(mac, pSmeRrmContext->measurement_idx, + num_chan, &freq_list[0], true); + + /* Clean up all context and send a + * message to PE with measurement done flag set. + */ + qdf_mem_free(pSmeRrmContext->channelList.freq_list); + pSmeRrmContext->channelList.freq_list = NULL; +end: + pSmeRrmContext->channelList.numOfChannels = 0; + sme_reset_ese_bcn_req_in_progress(pSmeRrmContext); + + return qdf_status; +} + +/** + * sme_rrm_send_chan_load_report_xmit_ind() -Sends the chan load report xmit + * to PE + * @mac: global mac context + * @rrm_sme_ctx: SME rrm context for measurement request + * @vdev_id: vdev id + * @is_report_success: need to send failure report or not + * + * The sme module calls this function once it finish the scan request + * and this function send the chan load report xmit to PE. + * + * Return : None + */ +static void +sme_rrm_send_chan_load_report_xmit_ind(struct mac_context *mac, + tpRrmSMEContext rrm_sme_ctx, + uint8_t vdev_id, + bool is_report_success) +{ + uint8_t measurement_index = rrm_sme_ctx->measurement_idx; + struct chan_load_xmit_ind *chan_load_resp; + uint16_t length; + tpRrmSMEContext rrm_ctx = &mac->rrm.rrmSmeContext[measurement_index]; + const struct bonded_channel_freq *range; + uint8_t chan_load = 0, temp_chan_load; + qdf_freq_t start_freq, end_freq, op_freq; + enum phy_ch_width req_chan_width; + + length = sizeof(struct chan_load_xmit_ind); + chan_load_resp = qdf_mem_malloc(length); + if (!chan_load_resp) + return; + + chan_load_resp->messageType = eWNI_SME_CHAN_LOAD_REPORT_RESP_XMIT_IND; + chan_load_resp->is_report_success = is_report_success; + chan_load_resp->length = length; + chan_load_resp->measurement_idx = measurement_index; + chan_load_resp->dialog_token = rrm_ctx->token; + chan_load_resp->duration = rrm_ctx->duration[0]; + chan_load_resp->op_class = rrm_ctx->regClass; + chan_load_resp->channel = rrm_ctx->chan_load_req_info.channel; + chan_load_resp->rrm_scan_tsf = rrm_ctx->chan_load_req_info.rrm_scan_tsf; + + op_freq = rrm_ctx->chan_load_req_info.req_freq; + req_chan_width = rrm_ctx->chan_load_req_info.req_chan_width; + if (req_chan_width == CH_WIDTH_INVALID) { + sme_debug("Invalid scanned_ch_width"); + return; + } + + if (req_chan_width == CH_WIDTH_20MHZ) { + start_freq = op_freq; + end_freq = op_freq; + sme_debug("cw %d: start_freq %d, end_freq %d", req_chan_width, + start_freq, end_freq); + } else if (req_chan_width == CH_WIDTH_320MHZ) { + if (!rrm_ctx->chan_load_req_info.bw_ind.is_bw_ind_element) { + sme_debug("is_bw_ind_element is false"); + return; + } + + qdf_mem_copy(&chan_load_resp->bw_ind, + &rrm_ctx->chan_load_req_info.bw_ind, + sizeof(chan_load_resp->bw_ind)); + range = wlan_reg_get_bonded_chan_entry(op_freq, + rrm_ctx->chan_load_req_info.bw_ind.channel_width, + rrm_ctx->chan_load_req_info.bw_ind.center_freq); + if (!range) { + sme_debug("vdev %d : range is null for freq %d", + vdev_id, op_freq); + return; + } + + start_freq = range->start_freq; + end_freq = range->end_freq; + sme_debug("cw %d: start_freq %d, end_freq %d", req_chan_width, + start_freq, end_freq); + } else { + if (rrm_ctx->chan_load_req_info.wide_bw.is_wide_bw_chan_switch) { + qdf_mem_copy(&chan_load_resp->wide_bw, + &rrm_ctx->chan_load_req_info.wide_bw, + sizeof(chan_load_resp->wide_bw)); + req_chan_width = + rrm_ctx->chan_load_req_info.wide_bw.channel_width; + sme_debug("Fill wide_bw_chan_switch IE for cw:%d", + req_chan_width); + } + + range = + wlan_reg_get_bonded_chan_entry(op_freq, req_chan_width, 0); + if (!range) { + sme_debug("range is NULL for freq %d, ch_width %d", + op_freq, req_chan_width); + return; + } + start_freq = range->start_freq; + end_freq = range->end_freq; + sme_debug("cw %d: start_freq %d, end_freq %d", + req_chan_width, start_freq, end_freq); + } + + for (; start_freq <= end_freq;) { + temp_chan_load = + wlan_cp_stats_get_rx_clear_count(mac->psoc, + vdev_id, + start_freq); + if (chan_load < temp_chan_load) + chan_load = temp_chan_load; + + start_freq += BW_20_MHZ; + } + + chan_load_resp->chan_load = chan_load; + + sme_debug("SME Sending CHAN_LOAD_REPORT_RESP_XMIT_IND to PE"); + umac_send_mb_message_to_mac(chan_load_resp); +} + +static void sme_rrm_scan_event_callback(struct wlan_objmgr_vdev *vdev, + struct scan_event *event, void *arg) +{ + struct mac_context *mac_ctx; + uint32_t scan_id; + uint8_t vdev_id, i; + eCsrScanStatus scan_status = eCSR_SCAN_FAILURE; + bool success = false; + tpRrmSMEContext smerrmctx; + + mac_ctx = (struct mac_context *)arg; + if (!mac_ctx) { + sme_err("invalid mac_ctx"); + return; + } + + vdev_id = wlan_vdev_get_id(vdev); + scan_id = event->scan_id; + + qdf_mtrace(QDF_MODULE_ID_SCAN, QDF_MODULE_ID_SME, event->type, + event->vdev_id, event->scan_id); + + if (!util_is_scan_completed(event, &success)) + return; + + if (success) + scan_status = eCSR_SCAN_SUCCESS; + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) { + smerrmctx = &mac_ctx->rrm.rrmSmeContext[i]; + if (smerrmctx->scan_id == scan_id) + break; + + if (i == (MAX_MEASUREMENT_REQUEST - 1)) + return; + } + + sme_debug("vdev: %d : Scan completed for scan_id:%d idx:%d, type:%d", + vdev_id, scan_id, smerrmctx->measurement_idx, + smerrmctx->measurement_type); + + switch (smerrmctx->measurement_type) { + case RRM_CHANNEL_LOAD: + sme_rrm_send_chan_load_report_xmit_ind(mac_ctx, smerrmctx, + vdev_id, true); + break; + case RRM_BEACON_REPORT: + sme_rrm_scan_request_callback(mac_ctx, smerrmctx, vdev_id, + scan_id, scan_status); + break; + default: + sme_err("Unknown measurement_type: %d", + smerrmctx->measurement_type); + break; + } +} + +#define RRM_CHAN_WEIGHT_CHAR_LEN 5 +#define RRM_MAX_CHAN_TO_PRINT 39 + +QDF_STATUS sme_rrm_issue_scan_req(struct mac_context *mac_ctx, uint8_t idx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpRrmSMEContext sme_rrm_ctx = &mac_ctx->rrm.rrmSmeContext[idx]; + uint32_t session_id; + tSirScanType scan_type; + uint8_t ch_idx; + uint32_t *freq_list; + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &sme_rrm_ctx->sessionBssId, &session_id); + if (status != QDF_STATUS_SUCCESS) { + sme_err("sme session ID not found for bssid= "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(sme_rrm_ctx->sessionBssId.bytes)); + status = QDF_STATUS_E_FAILURE; + goto send_ind; + } + + if ((sme_rrm_ctx->currentIndex) >= + sme_rrm_ctx->channelList.numOfChannels) { + sme_rrm_send_beacon_report_xmit_ind(mac_ctx, idx, NULL, + true, 0); + sme_debug("done with the complete ch lt. finish and fee now"); + goto free_ch_lst; + } + + if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource) + scan_type = sme_rrm_ctx->measMode[sme_rrm_ctx->currentIndex]; + else + scan_type = sme_rrm_ctx->measMode[0]; + + if ((eSIR_ACTIVE_SCAN == scan_type) || + (eSIR_PASSIVE_SCAN == scan_type)) { + uint32_t max_chan_time, buff_len, buff_num = 0, chan_count = 0; + uint64_t current_time; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + uint16_t i; + char *chan_buff = NULL; + + if (!sme_rrm_ctx->channelList.numOfChannels || + !sme_rrm_ctx->channelList.freq_list) { + sme_err("[802.11 RRM]: Global freq list is null"); + status = QDF_STATUS_E_FAILURE; + goto send_ind; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto send_ind; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + mac_ctx->psoc, + session_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("VDEV is null %d", session_id); + status = QDF_STATUS_E_INVAL; + qdf_mem_free(req); + goto send_ind; + } + wlan_scan_init_default_params(vdev, req); + req->scan_req.scan_id = wlan_scan_get_scan_id(mac_ctx->psoc); + sme_rrm_ctx->scan_id = req->scan_req.scan_id; + + sme_debug("RRM_SCN: rrm_idx:%d scan_id:%d", + sme_rrm_ctx->measurement_idx, sme_rrm_ctx->scan_id); + req->scan_req.scan_f_passive = + (scan_type == eSIR_ACTIVE_SCAN) ? false : true; + req->scan_req.vdev_id = wlan_vdev_get_id(vdev); + req->scan_req.scan_req_id = sme_rrm_ctx->req_id; + qdf_mem_copy(&req->scan_req.bssid_list[0], sme_rrm_ctx->bssId, + QDF_MAC_ADDR_SIZE); + req->scan_req.num_bssid = 1; + if (sme_rrm_ctx->ssId.length) { + req->scan_req.num_ssids = 1; + qdf_mem_copy(&req->scan_req.ssid[0].ssid, + sme_rrm_ctx->ssId.ssId, + sme_rrm_ctx->ssId.length); + req->scan_req.ssid[0].length = sme_rrm_ctx->ssId.length; + } + + /* + * set min and max channel time + * sme_rrm_ctx->duration; Dont use min timeout. + */ + if (eRRM_MSG_SOURCE_ESE_UPLOAD == sme_rrm_ctx->msgSource || + eRRM_MSG_SOURCE_LEGACY_ESE == sme_rrm_ctx->msgSource) + max_chan_time = + sme_rrm_ctx->duration[sme_rrm_ctx->currentIndex]; + else + max_chan_time = sme_rrm_ctx->duration[0]; + + /* + * Use max_chan_time if max_chan_time is more than def value + * depending on type of scan. + */ + if (req->scan_req.scan_f_passive) { + if (max_chan_time >= RRM_SCAN_MIN_DWELL_TIME) { + req->scan_req.dwell_time_passive = + max_chan_time; + req->scan_req.dwell_time_passive_6g = + max_chan_time; + } + sme_debug("Passive Max Dwell Time(%d)", + req->scan_req.dwell_time_passive); + } else { + if (max_chan_time >= RRM_SCAN_MIN_DWELL_TIME) { + req->scan_req.dwell_time_active = max_chan_time; + req->scan_req.dwell_time_active_2g = + max_chan_time; + req->scan_req.dwell_time_active_6g = + max_chan_time; + } + sme_debug("Active Max Dwell Time(%d) 2G Dwell time %d", + req->scan_req.dwell_time_active, + req->scan_req.dwell_time_active_2g); + } + + req->scan_req.adaptive_dwell_time_mode = SCAN_DWELL_MODE_STATIC; + /* + * For RRM scans timing is very important especially when the + * request is for limited channels. There is no need for + * firmware to rest for about 100-200 ms on the home channel. + * Instead, it can start the scan right away which will make the + * host to respond with the beacon report as quickly as + * possible. Ensure that the scan requests are not back to back + * and hence there is a check to see if the requests are atleast + * 1 second apart. + */ + current_time = (uint64_t)qdf_mc_timer_get_system_time(); + sme_debug("prev scan triggered before %llu ms, totalchannels %d", + current_time - rrm_scan_timer, + sme_rrm_ctx->channelList.numOfChannels); + if ((abs(current_time - rrm_scan_timer) > 1000) && + (sme_rrm_ctx->channelList.numOfChannels == 1)) { + req->scan_req.max_rest_time = 1; + req->scan_req.min_rest_time = 1; + req->scan_req.idle_time = 1; + } + + rrm_scan_timer = (uint64_t)qdf_mc_timer_get_system_time(); + + /* set requestType to full scan */ + req->scan_req.chan_list.num_chan = + sme_rrm_ctx->channelList.numOfChannels; + buff_len = (QDF_MIN(req->scan_req.chan_list.num_chan, + RRM_MAX_CHAN_TO_PRINT) * RRM_CHAN_WEIGHT_CHAR_LEN) + + 1; + chan_buff = qdf_mem_malloc(buff_len); + if (!chan_buff) { + status = QDF_STATUS_E_NOMEM; + goto send_ind; + } + sme_debug("Number of chan %d active duration %d passive %d", + req->scan_req.chan_list.num_chan, + req->scan_req.dwell_time_active, + req->scan_req.dwell_time_passive); + + for (i = 0; i < req->scan_req.chan_list.num_chan; i++) { + req->scan_req.chan_list.chan[i].freq = + (qdf_freq_t)sme_rrm_ctx->channelList.freq_list[i]; + buff_num += qdf_scnprintf(chan_buff + buff_num, + buff_len - buff_num, " %d", + req->scan_req.chan_list.chan[i].freq); + chan_count++; + if (chan_count >= RRM_MAX_CHAN_TO_PRINT) { + sme_debug("RRM Scan Req for channels: %s", + chan_buff); + buff_num = 0; + chan_count = 0; + } + } + if (buff_num) + sme_debug("RRM Freq scan req channels: %s", chan_buff); + qdf_mem_free(chan_buff); + /* + * Fill RRM scan type for these requests. This is done + * because in scan concurrency update params we update the + * dwell time active which was not the expectation. + * So doing a check of RRM scan request, we would not + * update the dwell time. + */ + req->scan_req.scan_type = SCAN_TYPE_RRM; + + status = wlan_scan_start(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + if (QDF_IS_STATUS_ERROR(status)) + goto send_ind; + + return status; + } else if (eSIR_BEACON_TABLE == scan_type) { + /* + * In beacon table mode, scan results are taken directly from + * scan cache without issuing any scan request. So, it is not + * proper to update rrm_scan_timer with latest time and hence + * made it to zero to satisfy + * pScanResult->timer >= rrm_scan_timer + */ + rrm_scan_timer = 0; + freq_list = sme_rrm_ctx->channelList.freq_list; + if (!freq_list) { + sme_err("[802.11 RRM]: Global freq list is null"); + sme_reset_ese_bcn_req_in_progress(sme_rrm_ctx); + status = QDF_STATUS_E_FAILURE; + goto send_ind; + } + + ch_idx = sme_rrm_ctx->currentIndex; + for (; ch_idx < sme_rrm_ctx->channelList.numOfChannels; ch_idx++) { + if ((ch_idx + 1) < + sme_rrm_ctx->channelList.numOfChannels) { + sme_rrm_send_scan_result(mac_ctx, idx, 1, + &freq_list[ch_idx], + false); + /* Advance the current index. */ + sme_rrm_ctx->currentIndex++; + } else { + /* + * Done with the measurement. Clean up all + * context and send a message to PE with + * measurement done flag set. + */ + sme_rrm_send_scan_result(mac_ctx, idx, 1, + &freq_list[ch_idx], + true); + sme_reset_ese_bcn_req_in_progress(sme_rrm_ctx); + goto free_ch_lst; + } + } + } + + sme_err("Unknown beacon report req mode(%d)", scan_type); + /* + * Indicate measurement completion to PE + * If this is not done, pCurrentReq pointer will not be freed + * and PE will not handle subsequent Beacon requests + */ +send_ind: + sme_rrm_send_beacon_report_xmit_ind(mac_ctx, idx, NULL, true, 0); +free_ch_lst: + qdf_mem_free(sme_rrm_ctx->channelList.freq_list); + sme_rrm_ctx->channelList.freq_list = NULL; + sme_rrm_ctx->channelList.numOfChannels = 0; + return status; +} + +static QDF_STATUS sme_rrm_fill_scan_channels(struct mac_context *mac, + uint8_t *country, + tpRrmSMEContext sme_rrm_context, + uint8_t op_class, + uint32_t num_channels) +{ + uint32_t num_chan = 0; + uint32_t i; + uint32_t *freq_list; + bool found; + + freq_list = sme_rrm_context->channelList.freq_list; + found = false; + for (i = 0; i < num_channels; i++) { + found = wlan_reg_is_freq_in_country_opclass(mac->pdev, + country, + op_class, + freq_list[i]); + if (found) { + freq_list[num_chan] = freq_list[i]; + num_chan++; + } + found = false; + } + + sme_rrm_context->channelList.numOfChannels = num_chan; + if (sme_rrm_context->channelList.numOfChannels == 0) { + qdf_mem_free(sme_rrm_context->channelList.freq_list); + sme_rrm_context->channelList.freq_list = NULL; + sme_err_rl("No channels populated with requested operation class and current country, Hence abort the rrm operation"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static uint8_t *sme_rrm_get_meas_mode_string(uint8_t meas_mode) +{ + switch (meas_mode) { + CASE_RETURN_STRING(eSIR_PASSIVE_SCAN); + CASE_RETURN_STRING(eSIR_ACTIVE_SCAN); + CASE_RETURN_STRING(eSIR_BEACON_TABLE); + default: + return (uint8_t *)"UNKNOWN"; + break; + } +} + +/** + * sme_rrm_fill_freq_list_for_channel_load() : Trigger wide band scan request + * to measure channel load + * @mac_ctx: global mac structure + * @sme_rrm_ctx: pointer to sme rrm context structure + * @vdev: vdev common object + * @req: scan request config + * + * Return : QDF_STATUS + */ +static QDF_STATUS +sme_rrm_fill_freq_list_for_channel_load(struct mac_context *mac_ctx, + tpRrmSMEContext sme_rrm_ctx, + struct wlan_objmgr_vdev *vdev, + struct scan_start_request *req) +{ + struct bw_ind_element *bw_ind; + struct wide_bw_chan_switch *wide_bw; + uint16_t c_space = 0; + uint8_t country_code[REG_ALPHA2_LEN + 1]; + enum phy_ch_width chan_width = CH_WIDTH_INVALID; + qdf_freq_t scan_freq; + uint8_t channel = sme_rrm_ctx->chan_load_req_info.channel; + qdf_freq_t cen320_freq = 0; + + rrm_get_country_code_from_connected_profile(mac_ctx, + wlan_vdev_get_id(vdev), + country_code); + scan_freq = wlan_reg_country_chan_opclass_to_freq(mac_ctx->pdev, + country_code, + channel, + sme_rrm_ctx->regClass, + false); + if (!scan_freq) { + sme_debug("invalid scan freq"); + return QDF_STATUS_E_INVAL; + } + + bw_ind = &sme_rrm_ctx->chan_load_req_info.bw_ind; + wide_bw = &sme_rrm_ctx->chan_load_req_info.wide_bw; + if (!bw_ind->is_bw_ind_element && !wide_bw->is_wide_bw_chan_switch) { + if (wlan_reg_is_6ghz_op_class(mac_ctx->pdev, + sme_rrm_ctx->regClass)) + c_space = + wlan_reg_get_op_class_width(mac_ctx->pdev, + sme_rrm_ctx->regClass, + true); + else + c_space = wlan_reg_dmn_get_chanwidth_from_opclass_auto( + country_code, + channel, + sme_rrm_ctx->regClass); + + sme_debug("op: %d, ch: %d freq:%d, cc %c%c 0x%x, c_space:%d", + sme_rrm_ctx->regClass, channel, scan_freq, + country_code[0], country_code[1], country_code[2], + c_space); + + switch (c_space) { + case 320: + fallthrough; + case 160: + chan_width = CH_WIDTH_160MHZ; + break; + case 80: + chan_width = CH_WIDTH_80MHZ; + break; + case 40: + chan_width = CH_WIDTH_40MHZ; + break; + case 20: + case 25: + chan_width = CH_WIDTH_20MHZ; + break; + default: + sme_err("invalid chan_space: %d", c_space); + return QDF_STATUS_E_FAILURE; + } + } else { + if (bw_ind->is_bw_ind_element) { + chan_width = bw_ind->channel_width; + cen320_freq = bw_ind->center_freq; + } + + if (wide_bw->is_wide_bw_chan_switch) + chan_width = wide_bw->channel_width; + } + + sme_rrm_ctx->chan_load_req_info.req_chan_width = chan_width; + return mlme_update_freq_in_scan_start_req(vdev, req, chan_width, + scan_freq, cen320_freq); +} + +/** + * sme_rrm_issue_chan_load_measurement_scan() : Trigger wide band scan request + * to measure channel load + * @mac_ctx: global mac structure + * @idx: measurement request index + * + * Return : QDF_STATUS + */ +static QDF_STATUS +sme_rrm_issue_chan_load_measurement_scan(struct mac_context *mac_ctx, + uint8_t idx) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpRrmSMEContext sme_rrm_ctx = &mac_ctx->rrm.rrmSmeContext[idx]; + uint32_t max_chan_time; + struct scan_start_request *req; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + + status = csr_roam_get_session_id_from_bssid(mac_ctx, + &sme_rrm_ctx->sessionBssId, + &vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("sme session ID not found for bssid "QDF_MAC_ADDR_FMT"", + QDF_MAC_ADDR_REF(sme_rrm_ctx->sessionBssId.bytes)); + goto send_ind; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac_ctx->psoc, vdev_id, + WLAN_LEGACY_SME_ID); + if (!vdev) { + sme_err("VDEV is null %d", vdev_id); + status = QDF_STATUS_E_INVAL; + goto send_ind; + } + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) { + status = QDF_STATUS_E_NOMEM; + goto error_handle; + } + + status = wlan_scan_init_default_params(vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto error_handle; + + req->scan_req.scan_id = wlan_scan_get_scan_id(mac_ctx->psoc); + sme_rrm_ctx->scan_id = req->scan_req.scan_id; + req->scan_req.vdev_id = wlan_vdev_get_id(vdev); + req->scan_req.scan_req_id = sme_rrm_ctx->req_id; + req->scan_req.scan_f_passive = true; + max_chan_time = sme_rrm_ctx->duration[0]; + req->scan_req.dwell_time_passive = max_chan_time; + req->scan_req.dwell_time_passive_6g = max_chan_time; + req->scan_req.adaptive_dwell_time_mode = SCAN_DWELL_MODE_STATIC; + req->scan_req.scan_type = SCAN_TYPE_RRM; + req->scan_req.scan_f_wide_band = true; + /* + * FW report CCA busy for each possible 20Mhz subbands of the + * wideband scan channel if below flag is true + */ + req->scan_req.scan_f_report_cca_busy_for_each_20mhz = true; + + status = sme_rrm_fill_freq_list_for_channel_load(mac_ctx, sme_rrm_ctx, + vdev, req); + if (QDF_IS_STATUS_ERROR(status)) + goto error_handle; + sme_debug("vdev:%d, rrm_idx:%d scan_id:%d num chan: %d dwell_time: %d", + req->scan_req.vdev_id, sme_rrm_ctx->measurement_idx, + sme_rrm_ctx->scan_id, + req->scan_req.chan_list.num_chan, + req->scan_req.dwell_time_passive); + /* store jiffies to send it in channel load report */ + sme_rrm_ctx->chan_load_req_info.rrm_scan_tsf = + (uint32_t)qdf_system_ticks(); + status = wlan_scan_start(req); + if (QDF_IS_STATUS_ERROR(status)) + goto error_handle; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); + return status; +error_handle: + qdf_mem_free(req); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_SME_ID); +send_ind: + sme_rrm_send_chan_load_report_xmit_ind(mac_ctx, sme_rrm_ctx, + vdev_id, false); + rrm_cleanup(mac_ctx, idx); + return status; +} + +/** + * sme_rrm_process_chan_load_req_ind() -Process beacon report request + * @mac: Global Mac structure + * @msg_buf: a pointer to a buffer that maps to various structures base + * on the message type.The beginning of the buffer can always + * map to tSirSmeRsp. + * + * This is called to process the channel load report request from peer AP + * forwarded through PE . + * + * Return : QDF_STATUS_SUCCESS - Validation is successful. + */ +static QDF_STATUS sme_rrm_process_chan_load_req_ind(struct mac_context *mac, + void *msg_buf) +{ + struct ch_load_ind *chan_load; + tpRrmSMEContext sme_rrm_ctx; + tpRrmPEContext rrm_ctx; + struct channel_load_req_info *req_info; + + chan_load = (struct ch_load_ind *)msg_buf; + sme_rrm_ctx = &mac->rrm.rrmSmeContext[chan_load->measurement_idx]; + rrm_ctx = &mac->rrm.rrmPEContext; + qdf_mem_copy(sme_rrm_ctx->sessionBssId.bytes, + chan_load->peer_addr.bytes, sizeof(struct qdf_mac_addr)); + + sme_rrm_ctx->token = chan_load->dialog_token; + sme_rrm_ctx->regClass = chan_load->op_class; + sme_rrm_ctx->randnIntvl = QDF_MAX(chan_load->randomization_intv, + mac->rrm.rrmConfig.max_randn_interval); + sme_rrm_ctx->currentIndex = 0; + qdf_mem_copy((uint8_t *)&sme_rrm_ctx->duration, + (uint8_t *)&chan_load->meas_duration, + SIR_ESE_MAX_MEAS_IE_REQS); + sme_rrm_ctx->measurement_type = RRM_CHANNEL_LOAD; + req_info = &sme_rrm_ctx->chan_load_req_info; + req_info->channel = chan_load->channel; + req_info->req_freq = chan_load->req_freq; + + qdf_mem_copy(&req_info->bw_ind, &chan_load->bw_ind, + sizeof(req_info->bw_ind)); + qdf_mem_copy(&req_info->wide_bw, &chan_load->wide_bw, + sizeof(req_info->wide_bw)); + + sme_debug("idx:%d, token: %d randnIntvl: %d meas_duration %d, rrm_ctx dur %d reg_class: %d, type: %d, channel: %d, freq: %d, [bw_ind present: %d, cw: %d, ccfs0: %d], [wide_bw present: %d, cw: %d]", + chan_load->measurement_idx, sme_rrm_ctx->token, + sme_rrm_ctx->randnIntvl, + chan_load->meas_duration, + sme_rrm_ctx->duration[0], sme_rrm_ctx->regClass, + sme_rrm_ctx->measurement_type, + req_info->channel, req_info->req_freq, + req_info->bw_ind.is_bw_ind_element, + req_info->bw_ind.channel_width, + req_info->bw_ind.center_freq, + req_info->wide_bw.is_wide_bw_chan_switch, + req_info->wide_bw.channel_width); + + return sme_rrm_issue_chan_load_measurement_scan(mac, + chan_load->measurement_idx); +} + +/** + * sme_rrm_process_beacon_report_req_ind() -Process beacon report request + * @mac:- Global Mac structure + * @msg_buf:- a pointer to a buffer that maps to various structures base + * on the message type.The beginning of the buffer can always + * map to tSirSmeRsp. + * + * This is called to process the Beacon + * report request from peer AP forwarded through PE . + * + * Return : QDF_STATUS_SUCCESS - Validation is successful. + */ +QDF_STATUS sme_rrm_process_beacon_report_req_ind(struct mac_context *mac, + void *msg_buf) +{ + tpSirBeaconReportReqInd beacon_req = (tpSirBeaconReportReqInd)msg_buf; + tpRrmSMEContext sme_rrm_ctx; + uint32_t len = 0, i = 0, j = 0; + uint8_t country[WNI_CFG_COUNTRY_CODE_LEN]; + uint32_t session_id; + struct csr_roam_session *session; + QDF_STATUS status; + uint32_t num_chan, local_num_channel; + bool chan_valid; + uint32_t *rrm_freq_list, *local_rrm_freq_list; + uint32_t bcn_chan_freq, local_bcn_chan_freq; + tpRrmPEContext rrm_ctx; + + sme_rrm_ctx = &mac->rrm.rrmSmeContext[beacon_req->measurement_idx]; + rrm_ctx = &mac->rrm.rrmPEContext; + + status = csr_roam_get_session_id_from_bssid(mac, (struct qdf_mac_addr *) + beacon_req->bssId, + &session_id); + if (QDF_IS_STATUS_ERROR(status)) { + sme_err("sme session ID not found for bssid"); + goto cleanup; + } + + session = CSR_GET_SESSION(mac, session_id); + if (!session) { + sme_err("Invalid session id %d", session_id); + status = QDF_STATUS_E_FAILURE; + goto cleanup; + } + + rrm_get_country_code_from_connected_profile(mac, session_id, country); + + if (wlan_reg_is_6ghz_op_class(mac->pdev, + beacon_req->channel_info.reg_class)) + country[2] = OP_CLASS_GLOBAL; + + sme_debug("RRM_SCN: Index:%d Request Reg class %d, AP's country code %c%c 0x%x, channel = %d", + beacon_req->measurement_idx, + beacon_req->channel_info.reg_class, + country[0], country[1], country[2], + beacon_req->channel_info.chan_num); + + if (beacon_req->channel_list.num_channels > SIR_ESE_MAX_MEAS_IE_REQS) { + sme_err("Beacon report request numChannels:%u exceeds max num channels", + beacon_req->channel_list.num_channels); + status = QDF_STATUS_E_INVAL; + goto cleanup; + } + + /* section 11.10.8.1 (IEEE Std 802.11k-2008) */ + /* channel 0 and 255 has special meaning. */ + if ((beacon_req->channel_info.chan_num == 0) || + ((beacon_req->channel_info.chan_num == 255) && + (beacon_req->channel_list.num_channels == 0))) { + /* Add all the channel in the regulatory domain. */ + len = mac->mlme_cfg->reg.valid_channel_list_num; + if (sme_rrm_ctx->channelList.freq_list) { + qdf_mem_free(sme_rrm_ctx->channelList.freq_list); + sme_rrm_ctx->channelList.freq_list = NULL; + } + sme_rrm_ctx->channelList.freq_list = + qdf_mem_malloc(sizeof(uint32_t) * len); + if (!sme_rrm_ctx->channelList.freq_list) { + status = QDF_STATUS_E_NOMEM; + sme_rrm_ctx->channelList.numOfChannels = 0; + goto cleanup; + } + + csr_get_cfg_valid_channels( + mac, sme_rrm_ctx->channelList.freq_list, &len); + + if (beacon_req->channel_info.reg_class) { + if (sme_rrm_fill_scan_channels( + mac, country, sme_rrm_ctx, + beacon_req->channel_info.reg_class, len) != + QDF_STATUS_SUCCESS) + goto cleanup; + } else { + sme_rrm_ctx->channelList.numOfChannels = len; + } + } else { + len = 0; + sme_rrm_ctx->channelList.numOfChannels = 0; + num_chan = 0; + + /* If valid channel is present. We first Measure on the given + * channel and if there are additional channels present in + * APchannelreport, measure on these also. + */ + if (beacon_req->channel_info.chan_num != 255) + len = 1; + + len += beacon_req->channel_list.num_channels; + + if (sme_rrm_ctx->channelList.freq_list) { + qdf_mem_free(sme_rrm_ctx->channelList.freq_list); + sme_rrm_ctx->channelList.freq_list = NULL; + } + sme_rrm_ctx->channelList.freq_list = + qdf_mem_malloc(sizeof(uint32_t) * len); + if (!sme_rrm_ctx->channelList.freq_list) { + sme_rrm_ctx->channelList.numOfChannels = 0; + status = QDF_STATUS_E_NOMEM; + goto cleanup; + } + + rrm_freq_list = sme_rrm_ctx->channelList.freq_list; + bcn_chan_freq = beacon_req->channel_info.chan_freq; + + if (beacon_req->channel_info.chan_num != 255) { + chan_valid = + wlan_roam_is_channel_valid(&mac->mlme_cfg->reg, + bcn_chan_freq); + + if (chan_valid) { + rrm_freq_list[num_chan] = bcn_chan_freq; + num_chan++; + } else { + sme_err("Invalid channel: %d", + beacon_req->channel_info.chan_num); + } + } + + for (i = 0; i < beacon_req->channel_list.num_channels; i++) { + bcn_chan_freq = + beacon_req->channel_list.chan_freq_lst[i]; + chan_valid = + wlan_roam_is_channel_valid(&mac->mlme_cfg->reg, + bcn_chan_freq); + + if (chan_valid) { + rrm_freq_list[num_chan] = bcn_chan_freq; + num_chan++; + } + } + + sme_rrm_ctx->channelList.numOfChannels = num_chan; + } + + local_rrm_freq_list = sme_rrm_ctx->channelList.freq_list; + local_num_channel = 0; + for (i = 0; i < sme_rrm_ctx->channelList.numOfChannels; i++) { + local_bcn_chan_freq = local_rrm_freq_list[i]; + chan_valid = true; + + if (beacon_req->measurement_idx > 0) { + for (j = 0; j < rrm_ctx->beacon_rpt_chan_num; j++) { + if (rrm_ctx->beacon_rpt_chan_list[j] == + local_bcn_chan_freq) { + /* + * Ignore this channel, As this is already + * included in previous request + */ + chan_valid = false; + break; + } + } + } + + if (chan_valid) { + uint8_t beacon_rpt_chan_num; + + beacon_rpt_chan_num = rrm_ctx->beacon_rpt_chan_num; + rrm_ctx->beacon_rpt_chan_list[beacon_rpt_chan_num] = + local_bcn_chan_freq; + rrm_ctx->beacon_rpt_chan_num++; + + if (rrm_ctx->beacon_rpt_chan_num >= + MAX_NUM_CHANNELS) { + /* this should never happen */ + sme_err("Reset beacon_rpt_chan_num : %d", + rrm_ctx->beacon_rpt_chan_num); + rrm_ctx->beacon_rpt_chan_num = 0; + } + local_rrm_freq_list[local_num_channel] = + local_bcn_chan_freq; + local_num_channel++; + } + } + + if (local_num_channel == 0) + goto cleanup; + + sme_rrm_ctx->channelList.numOfChannels = local_num_channel; + + /* Copy session bssid */ + qdf_mem_copy(sme_rrm_ctx->sessionBssId.bytes, beacon_req->bssId, + sizeof(tSirMacAddr)); + + /* copy measurement bssid */ + qdf_mem_copy(sme_rrm_ctx->bssId, beacon_req->macaddrBssid, + sizeof(tSirMacAddr)); + + /* Copy ssid */ + qdf_mem_copy(&sme_rrm_ctx->ssId, &beacon_req->ssId, + sizeof(tAniSSID)); + + sme_rrm_ctx->token = beacon_req->uDialogToken; + sme_rrm_ctx->regClass = beacon_req->channel_info.reg_class; + sme_rrm_ctx->randnIntvl = + QDF_MAX(beacon_req->randomizationInterval, + mac->rrm.rrmConfig.max_randn_interval); + sme_rrm_ctx->currentIndex = 0; + sme_rrm_ctx->msgSource = beacon_req->msgSource; + qdf_mem_copy((uint8_t *)&sme_rrm_ctx->measMode, + (uint8_t *)&beacon_req->fMeasurementtype, + SIR_ESE_MAX_MEAS_IE_REQS); + qdf_mem_copy((uint8_t *)&sme_rrm_ctx->duration, + (uint8_t *)&beacon_req->measurementDuration, + SIR_ESE_MAX_MEAS_IE_REQS); + + sme_rrm_ctx->measurement_type = RRM_BEACON_REPORT; + + sme_debug("token: %d randnIntvl: %d msgSource: %d measurementduration %d, rrm_ctx duration %d Meas_mode: %s, type: %d", + sme_rrm_ctx->token, sme_rrm_ctx->randnIntvl, + sme_rrm_ctx->msgSource, beacon_req->measurementDuration[0], + sme_rrm_ctx->duration[0], + sme_rrm_get_meas_mode_string(sme_rrm_ctx->measMode[0]), + sme_rrm_ctx->measurement_type); + + return sme_rrm_issue_scan_req(mac, beacon_req->measurement_idx); + +cleanup: + if (beacon_req->msgSource == eRRM_MSG_SOURCE_11K) { + /* Copy session bssid */ + qdf_mem_copy(sme_rrm_ctx->sessionBssId.bytes, + beacon_req->bssId, sizeof(tSirMacAddr)); + + /* copy measurement bssid */ + qdf_mem_copy(sme_rrm_ctx->bssId, beacon_req->macaddrBssid, + sizeof(tSirMacAddr)); + sme_rrm_ctx->token = beacon_req->uDialogToken; + sme_rrm_ctx->regClass = + beacon_req->channel_info.reg_class; + sme_rrm_ctx->randnIntvl = + QDF_MAX(beacon_req->randomizationInterval, + mac->rrm.rrmConfig.max_randn_interval); + + sme_rrm_send_beacon_report_xmit_ind(mac, + sme_rrm_ctx->measurement_idx, NULL, true, 0); + } + + return status; +} + +/** + * sme_rrm_neighbor_report_request() - This is API can be used to trigger a + * Neighbor report from the peer. + * @sessionId: session identifier on which the request should be made. + * @pNeighborReq: a pointer to a neighbor report request. + * + * This is API can be used to trigger a Neighbor report from the peer. + * + * Return: QDF_STATUS_SUCCESS - Validation is successful. + */ +QDF_STATUS sme_rrm_neighbor_report_request(struct mac_context *mac, uint8_t + sessionId, tpRrmNeighborReq + pNeighborReq, + tpRrmNeighborRspCallbackInfo + callbackInfo) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportReqInd pMsg; + + sme_debug("Request to send Neighbor report request received "); + if (!CSR_IS_SESSION_VALID(mac, sessionId)) { + sme_err("Invalid session %d", sessionId); + return QDF_STATUS_E_INVAL; + } + + /* If already a report is pending, return failure */ + if (true == + mac->rrm.rrmSmeContext[0].neighborReqControlInfo. + isNeighborRspPending) { + sme_err("Neighbor request already pending.. Not allowed"); + return QDF_STATUS_E_AGAIN; + } + + pMsg = qdf_mem_malloc(sizeof(tSirNeighborReportReqInd)); + if (!pMsg) + return QDF_STATUS_E_NOMEM; + + rrm_ll_purge_neighbor_cache(mac, + &mac->rrm.rrmSmeContext[0].neighborReportCache); + + pMsg->messageType = eWNI_SME_NEIGHBOR_REPORT_REQ_IND; + pMsg->length = sizeof(tSirNeighborReportReqInd); + wlan_mlme_get_bssid_vdev_id(mac->pdev, sessionId, + (struct qdf_mac_addr *)&pMsg->bssId); + pMsg->noSSID = pNeighborReq->no_ssid; + qdf_mem_copy(&pMsg->ucSSID, &pNeighborReq->ssid, sizeof(tSirMacSSid)); + + status = umac_send_mb_message_to_mac(pMsg); + if (status != QDF_STATUS_SUCCESS) + return QDF_STATUS_E_FAILURE; + + /* Neighbor report request message sent successfully to PE. + * Now register the callbacks + */ + mac->rrm.rrmSmeContext[0].neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallback = + callbackInfo->neighborRspCallback; + mac->rrm.rrmSmeContext[0].neighborReqControlInfo. + neighborRspCallbackInfo.neighborRspCallbackContext = + callbackInfo->neighborRspCallbackContext; + mac->rrm.rrmSmeContext[0].neighborReqControlInfo.isNeighborRspPending = + true; + + /* Start neighbor response wait timer now */ + qdf_mc_timer_start(&mac->rrm.rrmSmeContext[0].neighborReqControlInfo. + neighborRspWaitTimer, callbackInfo->timeout); + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_calculate_neighbor_ap_roam_score() - calculates roam score + * @mac_ctx: mac global context + * @pNeighborReportDesc: Neighbor BSS Descriptor node for which roam score + * should be calculated + * + * This API is called while handling individual neighbor reports from the APs + * neighbor AP report to calculate the cumulative roam score before storing it + * in neighbor cache. + * + * Return: void + */ +static void +rrm_calculate_neighbor_ap_roam_score(struct mac_context *mac_ctx, + tpRrmNeighborReportDesc nbr_report_desc) +{ + tpSirNeighborBssDescripton nbr_bss_desc; + uint32_t roam_score = 0; +#ifdef FEATURE_WLAN_ESE + uint8_t session_id; + struct cm_roam_values_copy config; +#endif + + if (!nbr_report_desc) { + QDF_ASSERT(0); + return; + } + + if (!nbr_report_desc->pNeighborBssDescription) { + QDF_ASSERT(0); + return; + } + + nbr_bss_desc = nbr_report_desc->pNeighborBssDescription; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fMobilityDomain) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_MOBILITY_DOMAIN; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameSecurityMode) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_SECURITY; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fSameAuthenticator) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_KEY_SCOPE; + if (!nbr_bss_desc->bssidInfo.rrmInfo.fCapRadioMeasurement) + goto check_11r_assoc; + + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_RRM; + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapSpectrumMeasurement) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_SPECTRUM_MGMT; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapQos) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_QOS; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapApsd) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_APSD; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapDelayedBlockAck) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_DELAYED_BA; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fCapImmediateBlockAck) + roam_score += + RRM_ROAM_SCORE_NEIGHBOR_REPORT_CAPABILITY_IMMEDIATE_BA; + + if (nbr_bss_desc->bssidInfo.rrmInfo.fApPreauthReachable) + roam_score += RRM_ROAM_SCORE_NEIGHBOR_REPORT_REACHABILITY; + +check_11r_assoc: +#ifdef FEATURE_WLAN_ESE + session_id = nbr_report_desc->sessionId; + wlan_cm_roam_cfg_get_value(mac_ctx->psoc, session_id, IS_11R_CONNECTION, + &config); + /* It has come in the report so its the best score */ + if (!config.bool_value) { + /* IAPP Route so lets make use of this info save all AP, as the + * list does not come all the time. Save and reuse till the next + * AP List comes to us. Even save our own MAC address. Will be + * useful next time around. + */ + roam_score += RRM_ROAM_SCORE_NEIGHBOR_IAPP_LIST; + } +#endif + nbr_report_desc->roamScore = roam_score; +} + +/** + * rrm_store_neighbor_rpt_by_roam_score()-store Neighbor BSS descriptor + * @mac: Pointer to mac context + * @pNeighborReportDesc - Neighbor BSS Descriptor node to be stored in cache + * @index: RRM sme context index + * + * This API is called to store a given + * Neighbor BSS descriptor to the neighbor cache. This function + * stores the neighbor BSS descriptors in such a way that descriptors + * are sorted by roamScore in descending order + * + * Return: void. + */ +static void rrm_store_neighbor_rpt_by_roam_score(struct mac_context *mac, + tpRrmNeighborReportDesc pNeighborReportDesc, + uint8_t index) +{ + tpRrmSMEContext pSmeRrmContext = &mac->rrm.rrmSmeContext[0]; + tListElem *pEntry; + tRrmNeighborReportDesc *pTempNeighborReportDesc; + + if (!pNeighborReportDesc) { + QDF_ASSERT(0); + return; + } + if (!pNeighborReportDesc->pNeighborBssDescription) { + QDF_ASSERT(0); + return; + } + + if (csr_ll_is_list_empty + (&pSmeRrmContext->neighborReportCache, LL_ACCESS_LOCK)) { + sme_err("Neighbor report cache is empty.. Adding a entry now"); + /* Neighbor list cache is empty. Insert this entry + * in the tail + */ + csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache, + &pNeighborReportDesc->List, LL_ACCESS_LOCK); + return; + } + /* Should store the neighbor BSS description in the order + * sorted by roamScore in descending order. APs with highest + * roamScore should be the 1st entry in the list + */ + pEntry = csr_ll_peek_head(&pSmeRrmContext->neighborReportCache, + LL_ACCESS_LOCK); + while (pEntry) { + pTempNeighborReportDesc = GET_BASE_ADDR(pEntry, + tRrmNeighborReportDesc, List); + if (pTempNeighborReportDesc->roamScore < + pNeighborReportDesc->roamScore) + break; + pEntry = csr_ll_next(&pSmeRrmContext-> + neighborReportCache, pEntry, LL_ACCESS_LOCK); + } + + if (pEntry) + /* This BSS roamscore is better than something in the + * list. Insert this before that one + */ + csr_ll_insert_entry(&pSmeRrmContext->neighborReportCache, + pEntry, &pNeighborReportDesc->List, + LL_ACCESS_LOCK); + else + /* All the entries in the list has a better roam Score + * than this one. Insert this at the last + */ + csr_ll_insert_tail(&pSmeRrmContext->neighborReportCache, + &pNeighborReportDesc->List, + LL_ACCESS_LOCK); +} + +/** + * sme_rrm_process_neighbor_report() -Process the Neighbor report received + * from PE + * @mac - Global MAC structure + * @msg_buf - a pointer to a buffer that maps to various structures base + * on the message type. + * The beginning of the buffer can always map to tSirSmeRsp. + * This is called to process the Neighbor report received from PE. + * + * Return: QDF_STATUS_SUCCESS - Validation is successful + */ +static QDF_STATUS sme_rrm_process_neighbor_report(struct mac_context *mac, + void *msg_buf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tpSirNeighborReportInd neighbor_rpt = (tpSirNeighborReportInd)msg_buf; + tpRrmNeighborReportDesc neighbor_rpt_desc; + uint8_t i = 0; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + /* Purge the cache on reception of unsolicited neighbor report */ + if (!mac->rrm.rrmSmeContext[neighbor_rpt->measurement_idx]. + neighborReqControlInfo.isNeighborRspPending) + rrm_ll_purge_neighbor_cache(mac, + &mac->rrm.rrmSmeContext[neighbor_rpt->measurement_idx]. + neighborReportCache); + + for (i = 0; i < neighbor_rpt->numNeighborReports; i++) { + neighbor_rpt_desc = + qdf_mem_malloc(sizeof(tRrmNeighborReportDesc)); + if (!neighbor_rpt_desc) { + status = QDF_STATUS_E_NOMEM; + goto end; + + } + + neighbor_rpt_desc->pNeighborBssDescription = + qdf_mem_malloc(sizeof(tSirNeighborBssDescription)); + if (!neighbor_rpt_desc->pNeighborBssDescription) { + qdf_mem_free(neighbor_rpt_desc); + status = QDF_STATUS_E_NOMEM; + goto end; + } + qdf_mem_copy(neighbor_rpt_desc->pNeighborBssDescription, + &neighbor_rpt->sNeighborBssDescription[i], + sizeof(tSirNeighborBssDescription)); + + sme_debug("Received neighbor report with Neighbor BSSID: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF( + neighbor_rpt->sNeighborBssDescription[i].bssId)); + + rrm_calculate_neighbor_ap_roam_score(mac, neighbor_rpt_desc); + + if (neighbor_rpt_desc->roamScore > 0) { + rrm_store_neighbor_rpt_by_roam_score( + mac, neighbor_rpt_desc, + neighbor_rpt->measurement_idx); + } else { + sme_err("Roam score of BSSID " QDF_MAC_ADDR_FMT + " is 0, Ignoring..", + QDF_MAC_ADDR_REF(neighbor_rpt-> + sNeighborBssDescription[i]. + bssId)); + + qdf_mem_free( + neighbor_rpt_desc->pNeighborBssDescription); + qdf_mem_free(neighbor_rpt_desc); + } + } +end: + + if (!csr_ll_count( + &mac->rrm.rrmSmeContext[neighbor_rpt->measurement_idx]. + neighborReportCache)) + qdf_status = QDF_STATUS_E_FAILURE; + + rrm_indicate_neighbor_report_result(mac, qdf_status); + + return status; +} + +/** + * sme_rrm_msg_processor()-Process RRM message + * @mac - Pointer to the global MAC parameter structure. + * @msg_type - the type of msg passed by PE as defined in wni_api.h + * @msg_buf - a pointer to a buffer that maps to various structures base + * on the message type. + * The beginning of the buffer can always map to tSirSmeRsp. + * sme_process_msg() calls this function for the + * messages that are handled by SME RRM module. + * + * Return: QDF_STATUS_SUCCESS - Validation is successful. + */ +QDF_STATUS sme_rrm_msg_processor(struct mac_context *mac, uint16_t msg_type, + void *msg_buf) +{ + sme_debug("Msg = %d for RRM measurement", msg_type); + + /* switch on the msg type & make the state transition accordingly */ + switch (msg_type) { + case eWNI_SME_NEIGHBOR_REPORT_IND: + sme_rrm_process_neighbor_report(mac, msg_buf); + break; + + case eWNI_SME_BEACON_REPORT_REQ_IND: + sme_rrm_process_beacon_report_req_ind(mac, msg_buf); + break; + + case eWNI_SME_CHAN_LOAD_REQ_IND: + sme_rrm_process_chan_load_req_ind(mac, msg_buf); + break; + + default: + sme_err("Unknown msg type: %d", msg_type); + break; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_neighbor_rsp_timeout_handler() - Timer handler to handlet the timeout + * @mac - The handle returned by mac_open. + * + * Timer handler to handle the timeout condition when a neighbor request is sent + * and no neighbor response is received from the AP + * + * Return: NULL + */ +static void rrm_neighbor_rsp_timeout_handler(void *userData) +{ + struct mac_context *mac = (struct mac_context *) userData; + + sme_warn("Neighbor Response timed out"); + rrm_indicate_neighbor_report_result(mac, QDF_STATUS_E_FAILURE); +} + +/** + * rrm_change_default_config_param() - Changing default config param to new + * @mac - The handle returned by mac_open. + * + * Return: None + */ +static void rrm_change_default_config_param(struct mac_context *mac) +{ + mac->rrm.rrmConfig.rrm_enabled = + mac->mlme_cfg->rrm_config.rrm_enabled; + mac->rrm.rrmConfig.sap_rrm_enabled = + mac->mlme_cfg->rrm_config.sap_rrm_enabled; + mac->rrm.rrmConfig.max_randn_interval = + mac->mlme_cfg->rrm_config.rrm_rand_interval; + + qdf_mem_copy(&mac->rrm.rrmConfig.rm_capability, + &mac->mlme_cfg->rrm_config.rm_capability, + RMENABLEDCAP_MAX_LEN); +} + +/** + * rrm_open() - Initialize all RRM module + * @ mac: The handle returned by mac_open. + * + * Initialize all RRM module. + * + * Return: QDF_STATUS + */ +QDF_STATUS rrm_open(struct mac_context *mac) +{ + + QDF_STATUS qdf_status; + tpRrmSMEContext pSmeRrmContext; + QDF_STATUS qdf_ret_status = QDF_STATUS_SUCCESS; + uint8_t i; + + mac->rrm.rrmConfig.max_randn_interval = 50; /* ms */ + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) { + pSmeRrmContext = &mac->rrm.rrmSmeContext[i]; + + qdf_status = + qdf_mc_timer_init(&pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer, QDF_TIMER_TYPE_SW, + rrm_neighbor_rsp_timeout_handler, + (void *)mac); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_err("Fail to init neighbor rsp wait timer"); + return QDF_STATUS_E_FAILURE; + } + + pSmeRrmContext->measurement_idx = i; + pSmeRrmContext->neighborReqControlInfo.isNeighborRspPending = + false; + + qdf_ret_status = + csr_ll_open(&pSmeRrmContext->neighborReportCache); + if (QDF_STATUS_SUCCESS != qdf_ret_status) { + sme_err("Fail to open neighbor cache result"); + return QDF_STATUS_E_FAILURE; + } + } + + rrm_change_default_config_param(mac); + + return QDF_STATUS_SUCCESS; +} + +/** + * rrm_close() - Release all RRM modules and their resources. + * @mac - The handle returned by mac_open. + * + * Release all RRM modules and their resources. + * + * Return: QDF_STATUS + * QDF_STATUS_E_FAILURE success + * QDF_STATUS_SUCCESS failure + */ + +QDF_STATUS rrm_close(struct mac_context *mac) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tpRrmSMEContext pSmeRrmContext; + uint8_t i; + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) { + pSmeRrmContext = &mac->rrm.rrmSmeContext[i]; + + if (pSmeRrmContext->channelList.freq_list) { + qdf_mem_free(pSmeRrmContext->channelList.freq_list); + pSmeRrmContext->channelList.freq_list = NULL; + pSmeRrmContext->channelList.numOfChannels = 0; + } + + if (QDF_TIMER_STATE_RUNNING == + qdf_mc_timer_get_current_state(&pSmeRrmContext-> + neighborReqControlInfo. + neighborRspWaitTimer)) { + qdf_status = qdf_mc_timer_stop(&pSmeRrmContext-> + neighborReqControlInfo. + neighborRspWaitTimer); + if (QDF_IS_STATUS_ERROR(qdf_status)) + sme_err("Timer stop fail"); + } + + qdf_status = qdf_mc_timer_destroy( + &pSmeRrmContext->neighborReqControlInfo. + neighborRspWaitTimer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + sme_err("Fail to destroy timer"); + + rrm_ll_purge_neighbor_cache( + mac, &pSmeRrmContext->neighborReportCache); + csr_ll_close(&pSmeRrmContext->neighborReportCache); + } + + return qdf_status; + +} + +QDF_STATUS rrm_start(struct mac_context *mac_ctx) +{ + tpRrmSMEContext smerrmctx; + wlan_scan_requester req_id; + uint8_t i; + + + /* Register with scan component */ + req_id = wlan_scan_register_requester(mac_ctx->psoc, + "RRM", + sme_rrm_scan_event_callback, + mac_ctx); + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) { + smerrmctx = &mac_ctx->rrm.rrmSmeContext[i]; + smerrmctx->req_id = req_id; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS rrm_stop(struct mac_context *mac_ctx) +{ + tpRrmSMEContext smerrmctx; + wlan_scan_requester req_id; + uint8_t i; + + for (i = 0; i < MAX_MEASUREMENT_REQUEST; i++) { + smerrmctx = &mac_ctx->rrm.rrmSmeContext[i]; + req_id = smerrmctx->req_id; + smerrmctx->req_id = 0; + } + + wlan_scan_unregister_requester(mac_ctx->psoc, req_id); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/sme/src/sme.c b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/sme.c new file mode 100644 index 0000000000..f145c54e21 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/sme/src/sme.c @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "csr_api_roam.c" +#include "csr_api_scan.c" +#include "csr_cmd_process.c" +#include "csr_link_list.c" +#include "csr_util.c" +#include "sme_qos.c" +#include "sme_api.c" +#include "sme_power_save.c" +#include "sme_trace.c" +#include "sme_rrm.c" + +#ifdef WLAN_FEATURE_NAN +#include "nan_datapath_api.c" +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma.h new file mode 100644 index 0000000000..32a1eccea0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma.h @@ -0,0 +1,2740 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WMA_H +#define WMA_H + +#include "a_types.h" +#include "qdf_types.h" +#include "osapi_linux.h" +#include "htc_packet.h" +#include "i_qdf_event.h" +#include "wmi_services.h" +#include "wmi_unified.h" +#include "wmi_version.h" +#include "qdf_types.h" +#include "qdf_status.h" +#include "cds_sched.h" +#include "cds_config.h" +#include "sir_mac_prot_def.h" +#include "wma_types.h" +#include +#include "utils_api.h" +#include "lim_types.h" +#include "wmi_unified_api.h" +#include "cdp_txrx_cmn.h" +#include "dbglog.h" +#include "cds_ieee80211_common.h" +#include "wlan_objmgr_psoc_obj.h" +#include +#include +#include "wma_api.h" +#include "wmi_unified_param.h" +#include "wmi.h" +#include "wlan_cm_roam_public_struct.h" +#include "target_if.h" +#include + +/* Platform specific configuration for max. no. of fragments */ +#define QCA_OL_11AC_TX_MAX_FRAGS 2 + +/* Private */ + +#define WMA_READY_EVENTID_TIMEOUT 6000 +#define WMA_SERVICE_READY_EXT_TIMEOUT 6000 +#define NAN_CLUSTER_ID_BYTES 4 + +#define WMA_CRASH_INJECT_TIMEOUT 5000 + +/* MAC ID to PDEV ID mapping is as given below + * MAC_ID PDEV_ID + * 0 1 + * 1 2 + * SOC Level WMI_PDEV_ID_SOC + */ +#define WMA_MAC_TO_PDEV_MAP(x) ((x) + (1)) +#define WMA_PDEV_TO_MAC_MAP(x) ((x) - (1)) + +#define MAX_PRINT_FAILURE_CNT 50 + +#define WMA_INVALID_VDEV_ID 0xFF + +#define wma_alert(params...) QDF_TRACE_FATAL(QDF_MODULE_ID_WMA, params) +#define wma_err(params...) QDF_TRACE_ERROR(QDF_MODULE_ID_WMA, params) +#define wma_warn(params...) QDF_TRACE_WARN(QDF_MODULE_ID_WMA, params) +#define wma_info(params...) QDF_TRACE_INFO(QDF_MODULE_ID_WMA, params) +#define wma_debug(params...) QDF_TRACE_DEBUG(QDF_MODULE_ID_WMA, params) +#define wma_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_WMA, params) +#define wma_err_rl(params...) QDF_TRACE_ERROR_RL(QDF_MODULE_ID_WMA, params) + +#define wma_nofl_alert(params...) \ + QDF_TRACE_FATAL_NO_FL(QDF_MODULE_ID_WMA, params) +#define wma_nofl_err(params...) \ + QDF_TRACE_ERROR_NO_FL(QDF_MODULE_ID_WMA, params) +#define wma_nofl_warn(params...) \ + QDF_TRACE_WARN_NO_FL(QDF_MODULE_ID_WMA, params) +#define wma_nofl_info(params...) \ + QDF_TRACE_INFO_NO_FL(QDF_MODULE_ID_WMA, params) +#define wma_nofl_debug(params...) \ + QDF_TRACE_DEBUG_NO_FL(QDF_MODULE_ID_WMA, params) + +#define wma_conditional_log(is_console_log_enabled, params...) \ + do { \ + if (is_console_log_enabled) \ + wma_info(params); \ + else \ + wma_debug(params); \ + } while(0); \ + +#define WMA_WILDCARD_PDEV_ID 0x0 + +#define WMA_HW_DEF_SCAN_MAX_DURATION 30000 /* 30 secs */ + +#define WMA_EAPOL_SUBTYPE_GET_MIN_LEN 21 +#define WMA_EAPOL_INFO_GET_MIN_LEN 23 +#define WMA_IS_DHCP_GET_MIN_LEN 38 +#define WMA_DHCP_SUBTYPE_GET_MIN_LEN 0x11D +#define WMA_DHCP_INFO_GET_MIN_LEN 50 +#define WMA_ARP_SUBTYPE_GET_MIN_LEN 22 +#define WMA_IPV4_PROTO_GET_MIN_LEN 24 +#define WMA_IPV4_PKT_INFO_GET_MIN_LEN 42 +#define WMA_ICMP_SUBTYPE_GET_MIN_LEN 35 +#define WMA_IPV6_PROTO_GET_MIN_LEN 21 +#define WMA_IPV6_PKT_INFO_GET_MIN_LEN 62 +#define WMA_ICMPV6_SUBTYPE_GET_MIN_LEN 55 + +/* Beacon tx rate */ +#define WMA_BEACON_TX_RATE_1_M 10 +#define WMA_BEACON_TX_RATE_2_M 20 +#define WMA_BEACON_TX_RATE_5_5_M 55 +#define WMA_BEACON_TX_RATE_11_M 110 +#define WMA_BEACON_TX_RATE_6_M 60 +#define WMA_BEACON_TX_RATE_9_M 90 +#define WMA_BEACON_TX_RATE_12_M 120 +#define WMA_BEACON_TX_RATE_18_M 180 +#define WMA_BEACON_TX_RATE_24_M 240 +#define WMA_BEACON_TX_RATE_36_M 360 +#define WMA_BEACON_TX_RATE_48_M 480 +#define WMA_BEACON_TX_RATE_54_M 540 + +/* Roaming default values + * All time and period values are in milliseconds. + * All rssi values are in dB except for WMA_NOISE_FLOOR_DBM_DEFAULT. + */ + +#define WMA_ROAM_SCAN_CHANNEL_SWITCH_TIME (4) +#define WMA_NOISE_FLOOR_DBM_DEFAULT (-96) +#define WMA_RSSI_MIN_VALUE (-128) +#define WMA_RSSI_MAX_VALUE (127) +#define WMA_ROAM_RSSI_DIFF_DEFAULT (5) +#define WMA_ROAM_DWELL_TIME_ACTIVE_DEFAULT (100) +#define WMA_ROAM_DWELL_TIME_PASSIVE_DEFAULT (110) +#define WMA_ROAM_MIN_REST_TIME_DEFAULT (50) +#define WMA_ROAM_MAX_REST_TIME_DEFAULT (500) + +#define WMA_INVALID_KEY_IDX 0xff + +#define WMA_MAX_RF_CHAINS(x) ((1 << x) - 1) +#define WMA_MIN_RF_CHAINS (1) +#define WMA_MAX_NSS (2) + +#define WMA_NOA_IE_SIZE(num_desc) (2 + (13 * (num_desc))) +#define WMA_MAX_NOA_DESCRIPTORS 4 + +#define WMA_TIM_SUPPORTED_PVB_LENGTH ((HAL_NUM_STA / 8) + 1) + +#define WMA_BSS_STATUS_STARTED 0x1 +#define WMA_BSS_STATUS_STOPPED 0x2 + +#define WMA_PEER_ASSOC_CNF_START 0x01 +#define WMA_PEER_ASSOC_TIMEOUT SIR_PEER_ASSOC_TIMEOUT + +#define WMA_DELETE_STA_RSP_START 0x02 +#define WMA_DELETE_STA_TIMEOUT SIR_DELETE_STA_TIMEOUT + +#define WMA_DEL_P2P_SELF_STA_RSP_START 0x03 +#define WMA_SET_LINK_PEER_RSP 0x04 +#define WMA_DELETE_PEER_RSP 0x05 + +#define WMA_PDEV_SET_HW_MODE_RESP 0x06 +#define WMA_PDEV_MAC_CFG_RESP 0x07 + +#define WMA_PEER_CREATE_RESPONSE 0x08 +#define WMA_PEER_CREATE_RESPONSE_TIMEOUT SIR_PEER_CREATE_RESPONSE_TIMEOUT + +/* send connect respone after bss peer is deleted */ +#define WMA_DELETE_STA_CONNECT_RSP 0x09 + +/* Peer create response for 11az PASN peer */ +#define WMA_PASN_PEER_CREATE_RESPONSE 0x0a + +#define WMA_PASN_PEER_DELETE_RESPONSE 0x0b +#define WMA_PEER_DELETE_RESPONSE_TIMEOUT SIR_DELETE_STA_TIMEOUT + +/* FW response timeout values in milli seconds */ +#define WMA_VDEV_PLCY_MGR_TIMEOUT SIR_VDEV_PLCY_MGR_TIMEOUT +#define WMA_VDEV_HW_MODE_REQUEST_TIMEOUT WMA_VDEV_PLCY_MGR_TIMEOUT +#define WMA_VDEV_DUAL_MAC_CFG_TIMEOUT WMA_VDEV_PLCY_MGR_TIMEOUT +#define WMA_VDEV_PLCY_MGR_WAKE_LOCK_TIMEOUT \ + (WMA_VDEV_PLCY_MGR_TIMEOUT + 500) + + +#define WMA_VDEV_SET_KEY_WAKELOCK_TIMEOUT WAKELOCK_DURATION_RECOMMENDED + +#define WMA_TX_Q_RECHECK_TIMER_WAIT 2 /* 2 ms */ + +#define WMA_SMPS_PARAM_VALUE_S 29 + +/* + * Setting the Tx Comp Timeout to 1 secs. + * TODO: Need to Revist the Timing + */ +#define WMA_TX_FRAME_COMPLETE_TIMEOUT 1000 +#define WMA_TX_FRAME_BUFFER_NO_FREE 0 +#define WMA_TX_FRAME_BUFFER_FREE 1 + +/* + * TODO: Add WMI_CMD_ID_MAX as part of WMI_CMD_ID + * instead of assigning it to the last valid wmi + * cmd+1 to avoid updating this when a command is + * added/deleted. + */ +#define WMI_CMDID_MAX (WMI_TXBF_CMDID + 1) + +#define WMA_NLO_FREQ_THRESH 1000 /* in MHz */ +#define WMA_MSEC_TO_USEC(msec) (msec * 1000) /* msec to usec */ + +#define WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT WAKELOCK_DURATION_RECOMMENDED +#define WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED +#define WMA_DEAUTH_RECV_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED +#define WMA_DISASSOC_RECV_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED +#define WMA_ROAM_HO_WAKE_LOCK_DURATION (500) /* in msec */ +#define WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION (2 * 1000) + +#define WMA_REASON_PROBE_REQ_WPS_IE_RECV_DURATION (3 * 1000) + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +#define WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED +#endif +#define WMA_BMISS_EVENT_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED +#define WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION WAKELOCK_DURATION_MAX + +#define WMA_TXMIC_LEN 8 +#define WMA_RXMIC_LEN 8 +#define WMA_IV_KEY_LEN 16 + +/* + * Length = (2 octets for Index and CTWin/Opp PS) and + * (13 octets for each NOA Descriptors) + */ + +#define WMA_P2P_NOA_IE_OPP_PS_SET (0x80) +#define WMA_P2P_NOA_IE_CTWIN_MASK (0x7F) + +#define WMA_P2P_IE_ID 0xdd +#define WMA_P2P_WFA_OUI { 0x50, 0x6f, 0x9a } +#define WMA_P2P_WFA_VER 0x09 /* ver 1.0 */ + +/* P2P Sub element definitions (according to table 5 of Wifi's P2P spec) */ +#define WMA_P2P_SUB_ELEMENT_STATUS 0 +#define WMA_P2P_SUB_ELEMENT_MINOR_REASON 1 +#define WMA_P2P_SUB_ELEMENT_CAPABILITY 2 +#define WMA_P2P_SUB_ELEMENT_DEVICE_ID 3 +#define WMA_P2P_SUB_ELEMENT_GO_INTENT 4 +#define WMA_P2P_SUB_ELEMENT_CONFIGURATION_TIMEOUT 5 +#define WMA_P2P_SUB_ELEMENT_LISTEN_CHANNEL 6 +#define WMA_P2P_SUB_ELEMENT_GROUP_BSSID 7 +#define WMA_P2P_SUB_ELEMENT_EXTENDED_LISTEN_TIMING 8 +#define WMA_P2P_SUB_ELEMENT_INTENDED_INTERFACE_ADDR 9 +#define WMA_P2P_SUB_ELEMENT_MANAGEABILITY 10 +#define WMA_P2P_SUB_ELEMENT_CHANNEL_LIST 11 +#define WMA_P2P_SUB_ELEMENT_NOA 12 +#define WMA_P2P_SUB_ELEMENT_DEVICE_INFO 13 +#define WMA_P2P_SUB_ELEMENT_GROUP_INFO 14 +#define WMA_P2P_SUB_ELEMENT_GROUP_ID 15 +#define WMA_P2P_SUB_ELEMENT_INTERFACE 16 +#define WMA_P2P_SUB_ELEMENT_OP_CHANNEL 17 +#define WMA_P2P_SUB_ELEMENT_INVITATION_FLAGS 18 +#define WMA_P2P_SUB_ELEMENT_VENDOR 221 + +/* Macros for handling unaligned memory accesses */ +#define P2PIE_PUT_LE16(a, val) \ + do { \ + (a)[1] = ((uint16_t) (val)) >> 8; \ + (a)[0] = ((uint16_t) (val)) & 0xff; \ + } while (0) + +#define P2PIE_PUT_LE32(a, val) \ + do { \ + (a)[3] = (uint8_t) ((((uint32_t) (val)) >> 24) & 0xff); \ + (a)[2] = (uint8_t) ((((uint32_t) (val)) >> 16) & 0xff); \ + (a)[1] = (uint8_t) ((((uint32_t) (val)) >> 8) & 0xff); \ + (a)[0] = (uint8_t) (((uint32_t) (val)) & 0xff); \ + } while (0) + + +#define WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE 1 + +#define WMA_VHT_PPS_PAID_MATCH 1 +#define WMA_VHT_PPS_GID_MATCH 2 +#define WMA_VHT_PPS_DELIM_CRC_FAIL 3 + +#define WMA_DEFAULT_HW_MODE_INDEX 0xFFFF +#define TWO_THIRD (2/3) + +#ifdef WLAN_FEATURE_SON +#define WMA_SON_MAX_PEER_EXT_STATS 16 +#else +#define WMA_SON_MAX_PEER_EXT_STATS 0 +#endif + +/** + * WMA hardware mode list bit-mask definitions. + * Bits 4:0, 31:29 are unused. + * + * The below definitions are added corresponding to WMI DBS HW mode + * list to make it independent of firmware changes for WMI definitions. + * Currently these definitions have dependency with BIT positions of + * the existing WMI macros. Thus, if the BIT positions are changed for + * WMI macros, then these macros' BIT definitions are also need to be + * changed. + */ +#define WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS (28) +#define WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS (24) +#define WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS (20) +#define WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS (16) +#define WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS (12) +#define WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS (8) +#define WMA_HW_MODE_DBS_MODE_BITPOS (7) +#define WMA_HW_MODE_AGILE_DFS_MODE_BITPOS (6) +#define WMA_HW_MODE_SBS_MODE_BITPOS (5) + +#define WMA_HW_MODE_MAC0_TX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_RX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_TX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_RX_STREAMS_MASK \ + (0xf << WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_BANDWIDTH_MASK \ + (0xf << WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_MAC1_BANDWIDTH_MASK \ + (0xf << WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_DBS_MODE_MASK \ + (0x1 << WMA_HW_MODE_DBS_MODE_BITPOS) +#define WMA_HW_MODE_AGILE_DFS_MODE_MASK \ + (0x1 << WMA_HW_MODE_AGILE_DFS_MODE_BITPOS) +#define WMA_HW_MODE_SBS_MODE_MASK \ + (0x1 << WMA_HW_MODE_SBS_MODE_BITPOS) + +#define WMA_HW_MODE_MAC0_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC0_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC1_TX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC1_RX_STREAMS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS, 4, value) +#define WMA_HW_MODE_MAC0_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS, 4, value) +#define WMA_HW_MODE_MAC1_BANDWIDTH_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS, 4, value) +#define WMA_HW_MODE_DBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_DBS_MODE_BITPOS, 1, value) +#define WMA_HW_MODE_AGILE_DFS_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_AGILE_DFS_MODE_BITPOS, 1, value) +#define WMA_HW_MODE_SBS_MODE_SET(hw_mode, value) \ + WMI_SET_BITS(hw_mode, WMA_HW_MODE_SBS_MODE_BITPOS, 1, value) + +#define WMA_HW_MODE_MAC0_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC0_TX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC0_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC0_RX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC0_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_TX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC1_TX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC1_TX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC1_RX_STREAMS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC1_RX_STREAMS_MASK) >> \ + WMA_HW_MODE_MAC1_RX_STREAMS_BITPOS) +#define WMA_HW_MODE_MAC0_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC0_BANDWIDTH_MASK) >> \ + WMA_HW_MODE_MAC0_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_MAC1_BANDWIDTH_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_MAC1_BANDWIDTH_MASK) >> \ + WMA_HW_MODE_MAC1_BANDWIDTH_BITPOS) +#define WMA_HW_MODE_DBS_MODE_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_DBS_MODE_MASK) >> \ + WMA_HW_MODE_DBS_MODE_BITPOS) +#define WMA_HW_MODE_AGILE_DFS_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_AGILE_DFS_MODE_MASK) >> \ + WMA_HW_MODE_AGILE_DFS_MODE_BITPOS) +#define WMA_HW_MODE_SBS_MODE_GET(hw_mode) \ + ((hw_mode & WMA_HW_MODE_SBS_MODE_MASK) >> \ + WMA_HW_MODE_SBS_MODE_BITPOS) + +/* + * Extract 2G or 5G tx/rx chainmask + * format of txrx_chainmask (from wmi_service_ready_event_fixed_param): + * [7:0] - 2G band tx chain mask + * [15:8] - 2G band rx chain mask + * [23:16] - 5G band tx chain mask + * [31:24] - 5G band rx chain mask + */ +#define EXTRACT_TX_CHAIN_MASK_2G(chainmask) ((chainmask) & 0xFF) +#define EXTRACT_RX_CHAIN_MASK_2G(chainmask) (((chainmask) >> 8) & 0xFF) +#define EXTRACT_TX_CHAIN_MASK_5G(chainmask) (((chainmask) >> 16) & 0xFF) +#define EXTRACT_RX_CHAIN_MASK_5G(chainmask) (((chainmask) >> 24) & 0xFF) + +/* + * PROBE_REQ_TX_DELAY + * param to specify probe request Tx delay for scans triggered on this VDEV + */ +#define PROBE_REQ_TX_DELAY 10 + +/* PROBE_REQ_TX_TIME_GAP + * param to specify the time gap between each set of probe request transmission. + * The number of probe requests in each set depends on the ssid_list and, + * bssid_list in the scan request. This parameter will get applied only, + * for the scans triggered on this VDEV. + */ +#define PROBE_REQ_TX_TIME_GAP 20 + +/** + * enum wma_rx_exec_ctx - wma rx execution context + * @WMA_RX_WORK_CTX: work queue context execution + * @WMA_RX_TASKLET_CTX: tasklet context execution + * @WMA_RX_SERIALIZER_CTX: MC thread context execution + * + */ +enum wma_rx_exec_ctx { + WMA_RX_WORK_CTX = WMI_RX_WORK_CTX, + WMA_RX_TASKLET_CTX = WMI_RX_TASKLET_CTX, + WMA_RX_SERIALIZER_CTX = WMI_RX_SERIALIZER_CTX, +}; + +/** + * struct beacon_info - structure to store beacon template + * @buf: skb ptr + * @len: length + * @dma_mapped: is it dma mapped or not + * @tim_ie_offset: TIM IE offset + * @dtim_count: DTIM count + * @seq_no: sequence no + * @noa_sub_ie: NOA sub IE + * @noa_sub_ie_len: NOA sub IE length + * @noa_ie: NOA IE + * @p2p_ie_offset: p2p IE offset + * @csa_count_offset: Offset of Switch count field in CSA IE + * @ecsa_count_offset: Offset of Switch count field in ECSA IE + * @lock: lock + */ +struct beacon_info { + qdf_nbuf_t buf; + uint32_t len; + uint8_t dma_mapped; + uint32_t tim_ie_offset; + uint8_t dtim_count; + uint16_t seq_no; + uint8_t noa_sub_ie[2 + WMA_NOA_IE_SIZE(WMA_MAX_NOA_DESCRIPTORS)]; + uint16_t noa_sub_ie_len; + uint8_t *noa_ie; + uint16_t p2p_ie_offset; + uint16_t csa_count_offset; + uint16_t ecsa_count_offset; + qdf_spinlock_t lock; +}; + +/** + * struct beacon_tim_ie - structure to store TIM IE of beacon + * @tim_ie: tim ie + * @tim_len: tim ie length + * @dtim_count: dtim count + * @dtim_period: dtim period + * @tim_bitctl: tim bit control + * @tim_bitmap: tim bitmap + */ +struct beacon_tim_ie { + uint8_t tim_ie; + uint8_t tim_len; + uint8_t dtim_count; + uint8_t dtim_period; + uint8_t tim_bitctl; + QDF_FLEX_ARRAY(uint8_t, tim_bitmap); +} __ATTRIB_PACK; + +/** + * struct pps - packet power save parameter + * @paid_match_enable: paid match enable + * @gid_match_enable: gid match enable + * @tim_clear: time clear + * @dtim_clear: dtim clear + * @eof_delim: eof delim + * @mac_match: mac match + * @delim_fail: delim fail + * @nsts_zero: nsts zero + * @rssi_chk: RSSI check + * @ebt_5g: ebt 5GHz + */ +struct pps { + bool paid_match_enable; + bool gid_match_enable; + bool tim_clear; + bool dtim_clear; + bool eof_delim; + bool mac_match; + bool delim_fail; + bool nsts_zero; + bool rssi_chk; + bool ebt_5g; +}; + +/** + * struct qpower_params - qpower related parameters + * @max_ps_poll_cnt: max ps poll count + * @max_tx_before_wake: max tx before wake + * @spec_ps_poll_wake_interval: ps poll wake interval + * @max_spec_nodata_ps_poll: no data ps poll + */ +struct qpower_params { + uint32_t max_ps_poll_cnt; + uint32_t max_tx_before_wake; + uint32_t spec_ps_poll_wake_interval; + uint32_t max_spec_nodata_ps_poll; +}; + + +/** + * struct gtx_config_t - GTX config + * @gtxRTMask: for HT and VHT rate masks + * @gtxUsrcfg: host request for GTX mask + * @gtxPERThreshold: PER Threshold (default: 10%) + * @gtxPERMargin: PER margin (default: 2%) + * @gtxTPCstep: TCP step (default: 1) + * @gtxTPCMin: TCP min (default: 5) + * @gtxBWMask: BW mask (20/40/80/160 Mhz) + */ +typedef struct { + uint32_t gtxRTMask[2]; + uint32_t gtxUsrcfg; + uint32_t gtxPERThreshold; + uint32_t gtxPERMargin; + uint32_t gtxTPCstep; + uint32_t gtxTPCMin; + uint32_t gtxBWMask; +} gtx_config_t; + +/** + * struct pdev_cli_config_t - store pdev parameters + * @ani_enable: ANI is enabled/disable on target + * @ani_poll_len: store ANI polling period + * @ani_listen_len: store ANI listening period + * @ani_ofdm_level: store ANI OFDM immunity level + * @ani_cck_level: store ANI CCK immunity level + * @cwmenable: Dynamic bw is enable/disable in fw + * @txchainmask: tx chain mask + * @rxchainmask: rx chain mask + * @txpow2g: tx power limit for 2GHz + * @txpow5g: tx power limit for 5GHz + * + * This structure stores pdev parameters. + * Some of these parameters are set in fw and some + * parameters are only maintained in host. + */ +typedef struct { + uint32_t ani_enable; + uint32_t ani_poll_len; + uint32_t ani_listen_len; + uint32_t ani_ofdm_level; + uint32_t ani_cck_level; + uint32_t cwmenable; + uint32_t cts_cbw; + uint32_t txchainmask; + uint32_t rxchainmask; + uint32_t txpow2g; + uint32_t txpow5g; +} pdev_cli_config_t; + +/** + * struct vdev_cli_config_t - store vdev parameters + * @nss: nss width + * @ldpc: is ldpc is enable/disable + * @tx_stbc: TX STBC is enable/disable + * @rx_stbc: RX STBC is enable/disable + * @shortgi: short gi is enable/disable + * @rtscts_en: RTS/CTS is enable/disable + * @chwidth: channel width + * @tx_rate: tx rate + * @ampdu: ampdu size + * @amsdu: amsdu size + * @erx_adjust: enable/disable early rx enable + * @erx_bmiss_num: target bmiss number per sample + * @erx_bmiss_cycle: sample cycle + * @erx_slop_step: slop_step value + * @erx_init_slop: init slop + * @erx_adj_pause: pause adjust enable/disable + * @erx_dri_sample: enable/disable drift sample + * @pps_params: packet power save parameters + * @qpower_params: qpower parameters + * @gtx_info: GTX offload info + * @dcm: DCM enable/disable + * @range_ext: HE range extension enable/disable + * @tx_ampdu: tx ampdu size + * @rx_ampdu: rx ampdu size + * @tx_amsdu: tx amsdu size + * @rx_amsdu: rx amsdu size + * + * This structure stores vdev parameters. + * Some of these parameters are set in fw and some + * parameters are only maintained in host. + */ +typedef struct { + uint32_t nss; + uint32_t ldpc; + uint32_t tx_stbc; + uint32_t rx_stbc; + uint32_t shortgi; + uint32_t rtscts_en; + uint32_t chwidth; + uint32_t tx_rate; + uint32_t ampdu; + uint32_t amsdu; + uint32_t erx_adjust; + uint32_t erx_bmiss_num; + uint32_t erx_bmiss_cycle; + uint32_t erx_slop_step; + uint32_t erx_init_slop; + uint32_t erx_adj_pause; + uint32_t erx_dri_sample; + struct pps pps_params; + struct qpower_params qpower_params; + gtx_config_t gtx_info; +#ifdef WLAN_FEATURE_11AX + uint8_t dcm; + uint8_t range_ext; +#endif + uint32_t tx_ampdu; + uint32_t rx_ampdu; + uint32_t tx_amsdu; + uint32_t rx_amsdu; +} vdev_cli_config_t; + +/** + * struct wma_version_info - Store wmi version info + * @major: wmi major version + * @minor: wmi minor version + * @revision: wmi revision number + */ +struct wma_version_info { + u_int32_t major; + u_int32_t minor; + u_int32_t revision; +}; + +/* Max number of invalid peer entries */ +#define INVALID_PEER_MAX_NUM 5 + +/** + * struct wma_invalid_peer_params - stores invalid peer entries + * @rx_macaddr: store mac addr of invalid peer + */ +struct wma_invalid_peer_params { + uint8_t rx_macaddr[QDF_MAC_ADDR_SIZE]; +}; + +/** + * struct wma_txrx_node - txrx node + * @vdev: pointer to vdev object + * @beacon: beacon info + * @config: per vdev config parameters + * @scan_info: scan info + * @type: type + * @sub_type: sub type + * @nlo_match_evt_received: is nlo match event received or not + * @pno_in_progress: is pno in progress or not + * @plm_in_progress: is plm in progress or not + * @beaconInterval: beacon interval + * @llbCoexist: 11b coexist + * @shortSlotTimeSupported: is short slot time supported or not + * @dtimPeriod: DTIM period + * @chan_width: channel bandwidth + * @vdev_up: is vdev up or not + * @tsfadjust: TSF adjust + * @addBssStaContext: add bss context + * @aid: association id + * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled + * @uapsd_cached_val: uapsd cached value + * @stats_rsp: stats response + * @del_staself_req: delete sta self request + * @bss_status: bss status + * @nss: nss value + * @is_channel_switch: is channel switch + * @pause_bitmap: pause bitmap + * @nwType: network type (802.11a/b/g/n/ac) + * @ps_enabled: is powersave enable/disable + * @peer_count: peer count + * @plink_status_req: link status request + * @psnr_req: snr request + * @tx_streams: number of tx streams can be used by the vdev + * @mac_id: the mac on which vdev is on + * @arp_offload_req: cached arp offload request + * @ns_offload_req: cached ns offload request + * @rcpi_req: rcpi request + * @in_bmps: Whether bmps for this interface has been enabled + * @ch_freq: channel frequency + * @roam_scan_stats_req: cached roam scan stats request + * @wma_invalid_peer_params: structure storing invalid peer params + * @invalid_peer_idx: invalid peer index + * It stores parameters per vdev in wma. + */ +struct wma_txrx_node { + struct wlan_objmgr_vdev *vdev; + struct beacon_info *beacon; + vdev_cli_config_t config; + uint32_t type; + uint32_t sub_type; +#ifdef FEATURE_WLAN_ESE + bool plm_in_progress; +#endif + tSirMacBeaconInterval beaconInterval; + uint8_t llbCoexist; + uint8_t shortSlotTimeSupported; + uint8_t dtimPeriod; + enum phy_ch_width chan_width; + bool vdev_active; + uint64_t tsfadjust; + tAddStaParams *addBssStaContext; + uint16_t aid; + uint8_t rmfEnabled; + uint32_t uapsd_cached_val; + void *del_staself_req; + bool is_del_sta_deferred; + qdf_atomic_t bss_status; + enum tx_rate_info rate_flags; + uint8_t nss; + uint16_t pause_bitmap; + uint32_t nwType; + uint32_t peer_count; + void *plink_status_req; + void *psnr_req; +#ifdef FEATURE_WLAN_EXTSCAN + bool extscan_in_progress; +#endif + uint32_t tx_streams; + uint32_t mac_id; + int32_t roam_synch_delay; + struct sme_rcpi_req *rcpi_req; + bool in_bmps; + struct beacon_filter_param beacon_filter; + bool beacon_filter_enabled; + struct roam_synch_frame_ind roam_synch_frame_ind; + bool is_waiting_for_key; + uint32_t ch_freq; + uint16_t ch_flagext; + struct sir_roam_scan_stats *roam_scan_stats_req; + struct wma_invalid_peer_params invalid_peers[INVALID_PEER_MAX_NUM]; + uint8_t invalid_peer_idx; + uint16_t bss_max_idle_period; +}; + +/** + * struct mac_ss_bw_info - hw_mode_list PHY/MAC params for each MAC + * @mac_tx_stream: Max TX stream + * @mac_rx_stream: Max RX stream + * @mac_bw: Max bandwidth + */ +struct mac_ss_bw_info { + uint32_t mac_tx_stream; + uint32_t mac_rx_stream; + uint32_t mac_bw; +}; + +/** + * struct wma_ini_config - Structure to hold wma ini configuration + * @max_no_of_peers: Max Number of supported + * @exclude_selftx_from_cca_busy: Exclude self tx time from cca busy time flag. + * + * Placeholder for WMA ini parameters. + */ +struct wma_ini_config { + uint8_t max_no_of_peers; + bool exclude_selftx_from_cca_busy; +}; + +/** + * struct wma_valid_channels - Channel details part of WMI_SCAN_CHAN_LIST_CMDID + * @num_channels: Number of channels + * @ch_freq_list: Channel Frequency list + */ +struct wma_valid_channels { + uint8_t num_channels; + uint32_t ch_freq_list[NUM_CHANNELS]; +}; + +#ifdef FEATURE_WLM_STATS +/** + * struct wma_wlm_stats_data - Data required to be used to send WLM req + * @wlm_stats_max_size: Buffer size provided by userspace + * @wlm_stats_cookie: Cookie to retrieve WLM req data + * @wlm_stats_callback: Callback to be used to send WLM response + */ +struct wma_wlm_stats_data { + uint32_t wlm_stats_max_size; + void *wlm_stats_cookie; + wma_wlm_stats_cb wlm_stats_callback; +}; +#endif + +#define WLAN_WMA_MAX_PF_SYM 50 +#define WLAN_WMA_PF_APPS_NOTIFY_BUF_LEN QDF_HANG_EVENT_DATA_SIZE +#define WLAN_WMA_PF_SYM_LEN 4 +#define WLAN_WMA_PF_SYM_CNT_LEN 1 +#define WLAN_WMA_PF_SYM_FLAGS_LEN 1 +#define WLAN_WMA_PER_PF_SYM_NOTIFY_BUF_LEN (WLAN_WMA_PF_SYM_LEN + \ + WLAN_WMA_PF_SYM_CNT_LEN + \ + WLAN_WMA_PF_SYM_FLAGS_LEN) + +/* + * struct wow_pf_sym - WOW PF wakeup symbol info + * @symbol: Address of PF symbol + * @count: Count of PF symbol + * @flags: Flags associated with @symbol + */ +struct wow_pf_sym { + uint32_t symbol; + uint8_t count; + uint8_t flags; +}; + +/* + * struct wow_pf_wakeup_ev_data - WOW PF wakeup event data + * @pf_sym: Array of each unique PF symbol in wakeup event payload + * @num_pf_syms: Total unique symbols in event. + * @pending_pf_syms: Pending PF symbols to process + */ +struct wow_pf_wakeup_ev_data { + struct wow_pf_sym *pf_sym; + uint8_t num_pf_syms; + uint8_t pending_pf_syms; +}; + +/** + * struct wma_pf_sym - Per symbol PF data in PF symbol history + * @pf_sym: PF symbol info + * @pf_event_ts: Array of page fault event ts + */ +struct wma_pf_sym { + struct wow_pf_sym pf_sym; + qdf_time_t *pf_ev_ts; +}; + +/* + * struct wma_pf_sym_hist - System level FW PF symbol history + * @wma_pf_sym: Array of symbols in history. + * @pf_notify_buf_ptr: Pointer to APPS notify buffer + * @pf_notify_buf_len: Current data length of @pf_notify_buf_ptr + * @lock: Lock to access PF symbol history + */ +struct wma_pf_sym_hist { + struct wma_pf_sym wma_pf_sym[WLAN_WMA_MAX_PF_SYM]; + uint8_t *pf_notify_buf_ptr; + uint32_t pf_notify_buf_len; + qdf_spinlock_t lock; +}; + +/** + * struct t_wma_handle - wma context + * @wmi_handle: wmi handle + * @cds_context: cds handle + * @mac_context: mac context + * @psoc: psoc context + * @pdev: physical device global object + * @target_suspend: target suspend event + * @recovery_event: wma FW recovery event + * @max_station: max stations + * @max_bssid: max bssid + * @myaddr: current mac address + * @hwaddr: mac address from EEPROM + * @lpss_support: LPSS feature is supported in target or not + * @wmi_ready: wmi status flag + * @wlan_init_status: wlan init status + * @qdf_dev: qdf device + * @wmi_service_bitmap: wmi services bitmap received from Target + * @wmi_service_ext_bitmap: extended wmi services bitmap received from Target + * @tx_frm_download_comp_cb: Tx Frame Compl Cb registered by umac + * @tx_frm_download_comp_event: Event to wait for tx download completion + * @tx_queue_empty_event: Dummy event to wait for draining MSDUs left + * in hardware tx queue and before requesting VDEV_STOP. Nobody will + * set this and wait will timeout, and code will poll the pending tx + * descriptors number to be zero. + * @umac_ota_ack_cb: Ack Complete Callback registered by umac + * @umac_data_ota_ack_cb: ack complete callback + * @last_umac_data_ota_timestamp: timestamp when OTA of last umac data + * was done + * @last_umac_data_nbuf: cache nbuf ptr for the last umac data buf + * @tgt_cfg_update_cb: configuration update callback + * @reg_cap: regulatory capabilities + * @scan_id: scan id + * @interfaces: txrx nodes(per vdev) + * @pdevconfig: pdev related configurations + * @wma_hold_req_queue: Queue use to serialize requests to firmware + * @wma_hold_req_q_lock: Mutex for @wma_hold_req_queue + * @vht_supp_mcs: VHT supported MCS + * @is_fw_assert: is fw asserted + * @ack_work_ctx: Context for deferred processing of TX ACK + * @pGetRssiReq: get RSSI request + * @get_one_peer_info: When a "get peer info" request is active, is + * the request for a single peer? + * @peer_macaddr: When @get_one_peer_info is true, the peer's mac address + * @thermal_mgmt_info: Thermal mitigation related info + * @enable_mc_list: To Check if Multicast list filtering is enabled in FW + * @hddTxFailCb: tx fail indication callback + * @extscan_wake_lock: extscan wake lock + * @wow_wake_lock: wow wake lock + * @wow_auth_req_wl: wow wake lock for auth req + * @wow_assoc_req_wl: wow wake lock for assoc req + * @wow_deauth_rec_wl: wow wake lock for deauth req + * @wow_disassoc_rec_wl: wow wake lock for disassoc req + * @wow_ap_assoc_lost_wl: wow wake lock for assoc lost req + * @wow_auto_shutdown_wl: wow wake lock for shutdown req + * @roam_ho_wl: wake lock for roam handoff req + * @wow_nack: wow negative ack flag + * @is_wow_bus_suspended: is wow bus suspended flag + * @IsRArateLimitEnabled: RA rate limiti s enabled or not + * @RArateLimitInterval: RA rate limit interval + * @is_lpass_enabled: Flag to indicate if LPASS feature is enabled or not + * @staMaxLIModDtim: station max listen interval + * @sta_max_li_mod_dtim_ms: station max listen interval in ms + * @staModDtim: station mode DTIM + * @staDynamicDtim: station dynamic DTIM + * @hw_bd_id: hardware board id + * @hw_bd_info: hardware board info + * @miracast_value: miracast value + * @log_completion_timer: log completion timer + * @old_hw_mode_index: Previous configured HW mode index + * @new_hw_mode_index: Current configured HW mode index + * @ocb_config_req: OCB request context + * @self_gen_frm_pwr: Self-generated frame power + * @tx_chain_mask_cck: Is the CCK tx chain mask enabled + * @service_ready_ext_timer: Timer for service ready extended. Note + * this is a a timer instead of wait event because on receiving the + * service ready event, we will be waiting on the MC thread for the + * service extended ready event which is also processed in MC + * thread. This leads to MC thread being stuck. Alternative was to + * process these events in tasklet/workqueue context. But, this + * leads to race conditions when the events are processed in two + * different context. So, processing ready event and extended ready + * event in the serialized MC thread context with a timer. + * @csr_roam_synch_cb: CSR callback for firmware Roam Sync events + * @pe_roam_synch_cb: pe callback for firmware Roam Sync events + * @csr_roam_auth_event_handle_cb: CSR callback for target authentication + * offload event. + * @pe_roam_set_ie_cb: PE callback to set IEs to firmware. + * @wmi_cmd_rsp_wake_lock: wmi command response wake lock + * @wmi_cmd_rsp_runtime_lock: wmi command response bus lock + * @active_uc_apf_mode: Setting that determines how APF is applied in + * active mode for uc packets + * @active_mc_bc_apf_mode: Setting that determines how APF is applied in + * active mode for MC/BC packets + * @ini_config: Initial configuration from upper layer + * @saved_chan: saved channel list sent as part of + * WMI_SCAN_CHAN_LIST_CMDID + * @nan_datapath_enabled: Is NAN datapath support enabled in firmware? + * @fw_timeout_crash: Should firmware be reset upon response timeout? + * @sub_20_support: Does target support sub-20MHz bandwidth (aka + * half-rate and quarter-rate)? + * @is_dfs_offloaded: Is dfs and cac timer offloaded? + * @wma_mgmt_tx_packetdump_cb: Callback function for TX packet dump + * @wma_mgmt_rx_packetdump_cb: Callback function for RX packet dump + * @rcpi_enabled: Is RCPI enabled? + * @link_stats_results: Structure for handing link stats from firmware + * @tx_fail_cnt: Number of TX failures + * @wlm_data: Data required for WLM req and resp handling + * @he_cap: 802.11ax capabilities + * @bandcapability: band capability configured through ini + * @tx_bfee_8ss_enabled: Is Tx Beamformee support for 8x8 enabled? + * @in_imps: Is device in Idle Mode Power Save? + * @dynamic_nss_chains_update: per vdev nss, chains update + * @ito_repeat_count: Indicates ito repeated count + * @wma_fw_time_sync_timer: timer used for firmware time sync + * * @fw_therm_throt_support: FW Supports thermal throttling? + * @eht_cap: 802.11be capabilities + * @set_hw_mode_resp_status: Set HW mode response status + * @wma_pf_hist: PF symbol history + * + * This structure is the global wma context. It contains global wma + * module parameters and handles of other modules. + + */ +typedef struct { + void *wmi_handle; + void *cds_context; + struct mac_context *mac_context; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + qdf_event_t target_suspend; + qdf_event_t runtime_suspend; + qdf_event_t recovery_event; + uint16_t max_station; + uint16_t max_bssid; + uint8_t myaddr[QDF_MAC_ADDR_SIZE]; + uint8_t hwaddr[QDF_MAC_ADDR_SIZE]; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; + bool wmi_ready; + uint32_t wlan_init_status; + qdf_device_t qdf_dev; + uint32_t wmi_service_bitmap[WMI_SERVICE_BM_SIZE]; + uint32_t wmi_service_ext_bitmap[WMI_SERVICE_SEGMENT_BM_SIZE32]; + wma_tx_dwnld_comp_callback tx_frm_download_comp_cb; + qdf_event_t tx_frm_download_comp_event; + qdf_event_t tx_queue_empty_event; + wma_tx_ota_comp_callback umac_data_ota_ack_cb; + unsigned long last_umac_data_ota_timestamp; + qdf_nbuf_t last_umac_data_nbuf; + wma_tgt_cfg_cb tgt_cfg_update_cb; + HAL_REG_CAPABILITIES reg_cap; + uint32_t scan_id; + struct wma_txrx_node *interfaces; + pdev_cli_config_t pdevconfig; + qdf_list_t wma_hold_req_queue; + qdf_spinlock_t wma_hold_req_q_lock; + uint32_t vht_supp_mcs; + uint8_t is_fw_assert; + struct wma_tx_ack_work_ctx *ack_work_ctx; + void *pGetRssiReq; + bool get_one_peer_info; + struct qdf_mac_addr peer_macaddr; + t_thermal_mgmt thermal_mgmt_info; + bool enable_mc_list; +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_t extscan_wake_lock; +#endif + qdf_wake_lock_t wow_wake_lock; + qdf_wake_lock_t wow_auth_req_wl; + qdf_wake_lock_t wow_assoc_req_wl; + qdf_wake_lock_t wow_deauth_rec_wl; + qdf_wake_lock_t wow_disassoc_rec_wl; + qdf_wake_lock_t wow_ap_assoc_lost_wl; + qdf_wake_lock_t wow_auto_shutdown_wl; + qdf_wake_lock_t roam_ho_wl; + qdf_wake_lock_t roam_preauth_wl; + qdf_wake_lock_t probe_req_wps_wl; + int wow_nack; + qdf_atomic_t is_wow_bus_suspended; +#ifdef WLAN_FEATURE_LPSS + bool is_lpass_enabled; +#endif + uint8_t staMaxLIModDtim; + uint16_t sta_max_li_mod_dtim_ms; + uint8_t staModDtim; + uint8_t staDynamicDtim; + uint32_t hw_bd_id; + uint32_t hw_bd_info[HW_BD_INFO_SIZE]; + uint32_t miracast_value; + qdf_mc_timer_t log_completion_timer; + uint32_t old_hw_mode_index; + uint32_t new_hw_mode_index; + uint16_t self_gen_frm_pwr; + bool tx_chain_mask_cck; + qdf_mc_timer_t service_ready_ext_timer; + + QDF_STATUS (*csr_roam_auth_event_handle_cb)(struct mac_context *mac, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm); + QDF_STATUS (*pe_roam_synch_cb)(struct mac_context *mac, + uint8_t vdev_id, + struct roam_offload_synch_ind *roam_synch_data, + uint16_t ie_len, + enum sir_roam_op_code reason); + QDF_STATUS (*pe_disconnect_cb) (struct mac_context *mac, + uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code); + QDF_STATUS (*pe_roam_set_ie_cb)(struct mac_context *mac_ctx, + uint8_t vdev_id, uint16_t dot11_mode, + enum QDF_OPMODE device_mode); + qdf_wake_lock_t wmi_cmd_rsp_wake_lock; + qdf_runtime_lock_t wmi_cmd_rsp_runtime_lock; + qdf_runtime_lock_t sap_prevent_runtime_pm_lock; + qdf_runtime_lock_t ndp_prevent_runtime_pm_lock; + enum active_apf_mode active_uc_apf_mode; + enum active_apf_mode active_mc_bc_apf_mode; + struct wma_ini_config ini_config; + struct wma_valid_channels saved_chan; + bool nan_datapath_enabled; + bool fw_timeout_crash; + bool sub_20_support; + bool is_dfs_offloaded; + ol_txrx_pktdump_cb wma_mgmt_tx_packetdump_cb; + ol_txrx_pktdump_cb wma_mgmt_rx_packetdump_cb; + bool rcpi_enabled; + tSirLLStatsResults *link_stats_results; + qdf_mutex_t radio_stats_lock; + uint64_t tx_fail_cnt; +#ifdef FEATURE_WLM_STATS + struct wma_wlm_stats_data wlm_data; +#endif +#ifdef WLAN_FEATURE_11AX + struct he_capability he_cap; +#endif + uint8_t bandcapability; + bool tx_bfee_8ss_enabled; + bool in_imps; + bool dynamic_nss_chains_support; + uint8_t ito_repeat_count; + bool fw_therm_throt_support; + bool enable_tx_compl_tsf64; +#ifdef WLAN_FEATURE_11BE + struct eht_capability eht_cap; +#endif + qdf_atomic_t sap_num_clients_connected; + qdf_atomic_t go_num_clients_connected; + qdf_wake_lock_t sap_d3_wow_wake_lock; + qdf_wake_lock_t go_d3_wow_wake_lock; + enum set_hw_mode_status set_hw_mode_resp_status; + struct wma_pf_sym_hist wma_pf_hist; +} t_wma_handle, *tp_wma_handle; + +/** + * wma_validate_handle() - Validate WMA handle + * @wma_handle: wma handle + * + * This function will log on error and hence caller should not log on error + * + * Return: errno if WMA handle is NULL; 0 otherwise + */ +#define wma_validate_handle(wma_handle) \ + __wma_validate_handle(wma_handle, __func__) +int __wma_validate_handle(tp_wma_handle wma_handle, const char *func); + +/** + * wma_vdev_nss_chain_params_send() - send vdev nss chain params to fw. + * @vdev_id: vdev_id + * @user_cfg: pointer to the params structure + * + * This function sends nss chain params to the fw + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_FAILURE on error + */ +QDF_STATUS +wma_vdev_nss_chain_params_send(uint8_t vdev_id, + struct wlan_mlme_nss_chains *user_cfg); + +/** + * wma_send_regdomain_info_to_fw() - send regdomain info to fw + * @reg_dmn: reg domain + * @regdmn2G: 2G reg domain + * @regdmn5G: 5G reg domain + * @ctl2G: 2G test limit + * @ctl5G: 5G test limit + * + * Return: none + */ +void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, uint8_t ctl2G, + uint8_t ctl5G); +/** + * enum frame_index - Frame index + * @GENERIC_NODOWNLD_NOACK_COMP_INDEX: Frame index for no download comp no ack + * @GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX: Frame index for download comp no ack + * @GENERIC_DOWNLD_COMP_ACK_COMP_INDEX: Frame index for download comp and ack + * @GENERIC_NODOWLOAD_ACK_COMP_INDEX: Frame index for no download comp and ack + * @FRAME_INDEX_MAX: maximum frame index + */ +enum frame_index { + GENERIC_NODOWNLD_NOACK_COMP_INDEX, + GENERIC_DOWNLD_COMP_NOACK_COMP_INDEX, + GENERIC_DOWNLD_COMP_ACK_COMP_INDEX, + GENERIC_NODOWLOAD_ACK_COMP_INDEX, + FRAME_INDEX_MAX +}; + +/** + * struct wma_tx_ack_work_ctx - tx ack work context + * @wma_handle: wma handle + * @sub_type: sub type + * @status: status + * @ack_cmp_work: work structure + * @frame: frame nbuf + */ +struct wma_tx_ack_work_ctx { + tp_wma_handle wma_handle; + uint16_t sub_type; + int32_t status; + qdf_work_t ack_cmp_work; + qdf_nbuf_t frame; +}; + +/** + * struct wma_target_req - target request parameters + * @event_timeout: event timeout + * @node: list + * @user_data: user data + * @addr: Mac address + * @msg_type: message type + * @vdev_id: vdev id + * @type: type + */ +struct wma_target_req { + qdf_mc_timer_t event_timeout; + qdf_list_node_t node; + void *user_data; + struct qdf_mac_addr addr; + uint32_t msg_type; + uint8_t vdev_id; + uint8_t type; +}; + +/** + * struct t_thermal_cmd_params - thermal command parameters + * @minTemp: minimum temperature + * @maxTemp: maximum temperature + * @thermalEnable: thermal enable + * @thermal_action: thermal action + */ +typedef struct { + uint16_t minTemp; + uint16_t maxTemp; + uint8_t thermalEnable; + enum thermal_mgmt_action_code thermal_action; +} t_thermal_cmd_params, *tp_thermal_cmd_params; + +/** + * enum wma_cfg_cmd_id - wma cmd ids + * @WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID: txrx firmware stats enable command + * @WMA_VDEV_TXRX_FWSTATS_RESET_CMDID: txrx firmware stats reset command + * @WMA_VDEV_MCC_SET_TIME_LATENCY: set MCC latency time + * @WMA_VDEV_MCC_SET_TIME_QUOTA: set MCC time quota + * @WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID: get IPA microcontroller fw stats + * @WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID: get IPA uC wifi-sharing stats + * @WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID: set IPA uC quota limit + * + * wma command ids for configuration request which + * does not involve sending a wmi command. + */ +enum wma_cfg_cmd_id { + WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID = WMI_CMDID_MAX, + WMA_VDEV_TXRX_FWSTATS_RESET_CMDID, + WMA_VDEV_MCC_SET_TIME_LATENCY, + WMA_VDEV_MCC_SET_TIME_QUOTA, + WMA_VDEV_TXRX_GET_IPA_UC_FW_STATS_CMDID, + WMA_VDEV_TXRX_GET_IPA_UC_SHARING_STATS_CMDID, + WMA_VDEV_TXRX_SET_IPA_UC_QUOTA_CMDID, + WMA_CMD_ID_MAX +}; + +/** + * struct wma_trigger_uapsd_params - trigger uapsd parameters + * @wmm_ac: wmm access category + * @user_priority: user priority + * @service_interval: service interval + * @suspend_interval: suspend interval + * @delay_interval: delay interval + */ +typedef struct wma_trigger_uapsd_params { + uint32_t wmm_ac; + uint32_t user_priority; + uint32_t service_interval; + uint32_t suspend_interval; + uint32_t delay_interval; +} t_wma_trigger_uapsd_params, *tp_wma_trigger_uapsd_params; + +/** + * enum uapsd_peer_param_max_sp - U-APSD maximum service period of peer station + * @UAPSD_MAX_SP_LEN_UNLIMITED: unlimited max service period + * @UAPSD_MAX_SP_LEN_2: max service period = 2 + * @UAPSD_MAX_SP_LEN_4: max service period = 4 + * @UAPSD_MAX_SP_LEN_6: max service period = 6 + */ +enum uapsd_peer_param_max_sp { + UAPSD_MAX_SP_LEN_UNLIMITED = 0, + UAPSD_MAX_SP_LEN_2 = 2, + UAPSD_MAX_SP_LEN_4 = 4, + UAPSD_MAX_SP_LEN_6 = 6 +}; + +/** + * enum uapsd_peer_param_enabled_ac - U-APSD Enabled AC's of peer station + * @UAPSD_VO_ENABLED: enable uapsd for voice + * @UAPSD_VI_ENABLED: enable uapsd for video + * @UAPSD_BK_ENABLED: enable uapsd for background + * @UAPSD_BE_ENABLED: enable uapsd for best effort + */ +enum uapsd_peer_param_enabled_ac { + UAPSD_VO_ENABLED = 0x01, + UAPSD_VI_ENABLED = 0x02, + UAPSD_BK_ENABLED = 0x04, + UAPSD_BE_ENABLED = 0x08 +}; + +/** + * enum profile_id_t - Firmware profiling index + * @PROF_CPU_IDLE: cpu idle profile + * @PROF_PPDU_PROC: ppdu processing profile + * @PROF_PPDU_POST: ppdu post profile + * @PROF_HTT_TX_INPUT: htt tx input profile + * @PROF_MSDU_ENQ: msdu enqueue profile + * @PROF_PPDU_POST_HAL: ppdu post profile + * @PROF_COMPUTE_TX_TIME: tx time profile + * @PROF_MAX_ID: max profile index + */ +enum profile_id_t { + PROF_CPU_IDLE, + PROF_PPDU_PROC, + PROF_PPDU_POST, + PROF_HTT_TX_INPUT, + PROF_MSDU_ENQ, + PROF_PPDU_POST_HAL, + PROF_COMPUTE_TX_TIME, + PROF_MAX_ID, +}; + +/** + * struct p2p_ie - P2P IE structural definition. + * @p2p_id: p2p id + * @p2p_len: p2p length + * @p2p_oui: p2p OUI + * @p2p_oui_type: p2p OUI type + */ +struct p2p_ie { + uint8_t p2p_id; + uint8_t p2p_len; + uint8_t p2p_oui[3]; + uint8_t p2p_oui_type; +} __packed; + +/** + * struct p2p_noa_descriptor - noa descriptor + * @type_count: 255: continuous schedule, 0: reserved + * @duration: Absent period duration in micro seconds + * @interval: Absent period interval in micro seconds + * @start_time: 32 bit tsf time when in starts + */ +struct p2p_noa_descriptor { + uint8_t type_count; + uint32_t duration; + uint32_t interval; + uint32_t start_time; +} __packed; + +/** + * struct p2p_sub_element_noa - p2p noa element + * @p2p_sub_id: p2p sub id + * @p2p_sub_len: p2p sub length + * @index: identifies instance of NOA su element + * @oppPS: oppPS state of the AP + * @ctwindow: ctwindow in TUs + * @num_descriptors: number of NOA descriptors + * @noa_descriptors: noa descriptors + */ +struct p2p_sub_element_noa { + uint8_t p2p_sub_id; + uint8_t p2p_sub_len; + uint8_t index; /* identifies instance of NOA su element */ + uint8_t oppPS:1, /* oppPS state of the AP */ + ctwindow:7; /* ctwindow in TUs */ + uint8_t num_descriptors; /* number of NOA descriptors */ + struct p2p_noa_descriptor noa_descriptors[WMA_MAX_NOA_DESCRIPTORS]; +}; + +/** + * struct wma_decap_info_t - decapsulation info + * @hdr: header + * @hdr_len: header length + */ +struct wma_decap_info_t { + uint8_t hdr[sizeof(struct ieee80211_qosframe_addr4)]; + int32_t hdr_len; +}; + +/** + * enum packet_power_save - packet power save params + * @WMI_VDEV_PPS_PAID_MATCH: paid match param + * @WMI_VDEV_PPS_GID_MATCH: gid match param + * @WMI_VDEV_PPS_EARLY_TIM_CLEAR: early tim clear param + * @WMI_VDEV_PPS_EARLY_DTIM_CLEAR: early dtim clear param + * @WMI_VDEV_PPS_EOF_PAD_DELIM: eof pad delim param + * @WMI_VDEV_PPS_MACADDR_MISMATCH: macaddr mismatch param + * @WMI_VDEV_PPS_DELIM_CRC_FAIL: delim CRC fail param + * @WMI_VDEV_PPS_GID_NSTS_ZERO: gid nsts zero param + * @WMI_VDEV_PPS_RSSI_CHECK: RSSI check param + * @WMI_VDEV_PPS_5G_EBT: 5G ebt param + */ +typedef enum { + WMI_VDEV_PPS_PAID_MATCH = 0, + WMI_VDEV_PPS_GID_MATCH = 1, + WMI_VDEV_PPS_EARLY_TIM_CLEAR = 2, + WMI_VDEV_PPS_EARLY_DTIM_CLEAR = 3, + WMI_VDEV_PPS_EOF_PAD_DELIM = 4, + WMI_VDEV_PPS_MACADDR_MISMATCH = 5, + WMI_VDEV_PPS_DELIM_CRC_FAIL = 6, + WMI_VDEV_PPS_GID_NSTS_ZERO = 7, + WMI_VDEV_PPS_RSSI_CHECK = 8, + WMI_VDEV_VHT_SET_GID_MGMT = 9, + WMI_VDEV_PPS_5G_EBT = 10 +} packet_power_save; + +/** + * enum green_tx_param - green tx parameters + * @wmi_vdev_param_gtx_ht_mcs: ht mcs param + * @wmi_vdev_param_gtx_vht_mcs: vht mcs param + * @wmi_vdev_param_gtx_usr_cfg: user cfg param + * @wmi_vdev_param_gtx_thre: thre param + * @wmi_vdev_param_gtx_margin: green tx margin param + * @wmi_vdev_param_gtx_step: green tx step param + * @wmi_vdev_param_gtx_mintpc: mintpc param + * @wmi_vdev_param_gtx_bw_mask: bandwidth mask + */ +typedef enum { + wmi_vdev_param_gtx_ht_mcs, + wmi_vdev_param_gtx_vht_mcs, + wmi_vdev_param_gtx_usr_cfg, + wmi_vdev_param_gtx_thre, + wmi_vdev_param_gtx_margin, + wmi_vdev_param_gtx_step, + wmi_vdev_param_gtx_mintpc, + wmi_vdev_param_gtx_bw_mask, +} green_tx_param; + +/** + * enum uapsd_ac - U-APSD Access Categories + * @UAPSD_BE: best effort + * @UAPSD_BK: back ground + * @UAPSD_VI: video + * @UAPSD_VO: voice + */ +enum uapsd_ac { + UAPSD_BE, + UAPSD_BK, + UAPSD_VI, + UAPSD_VO +}; + +/** + * wma_disable_uapsd_per_ac() - disable uapsd per ac + * @wmi_handle: wma handle + * @vdev_id: vdev id + * @ac: access category + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle, + uint32_t vdev_id, enum uapsd_ac ac); + +/** + * enum uapsd_up - U-APSD User Priorities + * @UAPSD_UP_BE: best effort + * @UAPSD_UP_BK: back ground + * @UAPSD_UP_RESV: reserve + * @UAPSD_UP_EE: Excellent Effort + * @UAPSD_UP_CL: Critical Applications + * @UAPSD_UP_VI: video + * @UAPSD_UP_VO: voice + * @UAPSD_UP_NC: Network Control + */ +enum uapsd_up { + UAPSD_UP_BE, + UAPSD_UP_BK, + UAPSD_UP_RESV, + UAPSD_UP_EE, + UAPSD_UP_CL, + UAPSD_UP_VI, + UAPSD_UP_VO, + UAPSD_UP_NC, + UAPSD_UP_MAX +}; + +/** + * wma_trigger_uapsd_params() - set trigger uapsd parameter + * @wmi_handle: wma handle + * @vdev_id: vdev id + * @trigger_uapsd_params: trigger uapsd parameters + * + * This function sets the trigger uapsd + * params such as service interval, delay + * interval and suspend interval which + * will be used by the firmware to send + * trigger frames periodically when there + * is no traffic on the transmit side. + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params); + +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle); +void wma_log_completion_timeout(void *data); + +#ifdef FEATURE_RSSI_MONITOR +/** + * wma_set_rssi_monitoring() - set rssi monitoring + * @handle: WMA handle + * @req: rssi monitoring request structure + * + * This function takes the incoming @req and sends it down to the + * firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_param *req); +#else /* FEATURE_RSSI_MONITOR */ +static inline +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_param *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_RSSI_MONITOR */ + +/** + * wma_map_pcl_weights - Map WMA pcl weights to wmi pcl weights + * @pcl_weight: Input PCL weight to be converted to wmi format + * + * Return: wmi_pcl_chan_weight + */ +wmi_pcl_chan_weight wma_map_pcl_weights(uint32_t pcl_weight); + +QDF_STATUS wma_send_set_pcl_cmd(tp_wma_handle wma_handle, + struct set_pcl_req *msg); + +QDF_STATUS wma_send_pdev_set_hw_mode_cmd(tp_wma_handle wma_handle, + struct policy_mgr_hw_mode *msg); + +QDF_STATUS wma_send_pdev_set_dual_mac_config(tp_wma_handle wma_handle, + struct policy_mgr_dual_mac_config *msg); +QDF_STATUS wma_send_pdev_set_antenna_mode(tp_wma_handle wma_handle, + struct sir_antenna_mode_param *msg); + +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params, + uint32_t len); +int wma_mgmt_tx_bundle_completion_handler(void *handle, + uint8_t *cmpl_event_params, uint32_t len); +uint32_t wma_get_vht_ch_width(void); + +#ifdef WLAN_FEATURE_11BE +/** + * wma_get_orig_eht_ch_width() - Get original EHT channel width supported + * + * API to get original EHT channel width + * + * Return: void + */ +uint32_t wma_get_orig_eht_ch_width(void); + +/** + * wma_get_orig_eht_ch_width() - Get current EHT channel width supported + * + * API to get current EHT channel width + * + * Return: void + */ +uint32_t wma_get_eht_ch_width(void); +#else +static inline uint32_t wma_get_orig_eht_ch_width(void) +{ + return 0; +} + +static inline uint32_t wma_get_eht_ch_width(void) +{ + return 0; +} +#endif + +QDF_STATUS +wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param, + A_UINT32 val, A_UINT32 *module_id_bitmap, + A_UINT32 bitmap_len); + +#ifdef FEATURE_LFR_SUBNET_DETECTION +/** + * wma_set_gateway_params() - set gateway parameters + * @wma: WMA handle + * @req: gateway update request parameter structure + * + * This function takes the incoming @req and sends it down to the + * firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_update_req_param *req); +#else +static inline +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_update_req_param *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma_handle, + int32_t vdev_id); + +QDF_STATUS wma_process_fw_test_cmd(WMA_HANDLE handle, + struct set_fwtest_params *wma_fwtest); + +QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, + struct obss_ht40_scanind *req); + +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask); + +#ifdef FEATURE_WLAN_APF +/** + * wma_get_apf_caps_event_handler() - Event handler for get apf capability + * @handle: WMA global handle + * @cmd_param_info: command event data + * @len: Length of @cmd_param_info + * + * Return: 0 on Success or Errno on failure + */ +int wma_get_apf_caps_event_handler(void *handle, + u_int8_t *cmd_param_info, + u_int32_t len); + +/** + * wma_get_apf_capabilities - Send get apf capability to firmware + * @wma_handle: wma handle + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma); + +/** + * wma_set_apf_instructions - Set apf instructions to firmware + * @wma: wma handle + * @apf_set_offload: APF offload information to set to firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +wma_set_apf_instructions(tp_wma_handle wma, + struct sir_apf_set_offload *apf_set_offload); + +/** + * wma_send_apf_enable_cmd - Send apf enable/disable cmd + * @wma_handle: wma handle + * @vdev_id: vdev id + * @apf_enable: true: Enable APF Int., false: Disable APF Int. + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS wma_send_apf_enable_cmd(WMA_HANDLE handle, uint8_t vdev_id, + bool apf_enable); + +/** + * wma_send_apf_write_work_memory_cmd - Command to write into the apf work + * memory + * @wma_handle: wma handle + * @write_params: APF parameters for the write operation + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS +wma_send_apf_write_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_write_memory_params + *write_params); + +/** + * wma_send_apf_read_work_memory_cmd - Command to get part of apf work memory + * @wma_handle: wma handle + * @callback: HDD callback to receive apf get mem event + * @context: Context for the HDD callback + * @read_params: APF parameters for the get operation + * + * Return: QDF_STATUS enumeration. + */ +QDF_STATUS +wma_send_apf_read_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_read_memory_params + *read_params); + +/** + * wma_apf_read_work_memory_event_handler - Event handler for get apf mem + * operation + * @handle: wma handle + * @evt_buf: Buffer pointer to the event + * @len: Length of the event buffer + * + * Return: status. + */ +int wma_apf_read_work_memory_event_handler(void *handle, uint8_t *evt_buf, + uint32_t len); +#else /* FEATURE_WLAN_APF */ +static inline QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wma_set_apf_instructions(tp_wma_handle wma, + struct sir_apf_set_offload *apf_set_offload) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_APF */ + +void wma_process_set_pdev_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); +void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params); + +QDF_STATUS wma_remove_peer(tp_wma_handle wma, uint8_t *mac_addr, + uint8_t vdev_id, bool no_fw_peer_delete); + +/** + * wma_create_peer() - Call wma_add_peer() to send peer create command to fw + * and setup cdp peer + * @wma: wma handle + * @peer_addr: peer mac address + * @peer_type: peer type + * @vdev_id: vdev id + * @peer_mld_addr: peer mld address + * @is_assoc_peer: is assoc peer or not + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_create_peer(tp_wma_handle wma, + uint8_t peer_addr[QDF_MAC_ADDR_SIZE], + u_int32_t peer_type, u_int8_t vdev_id, + uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE], + bool is_assoc_peer); + +/** + * wma_create_objmgr_peer() - create objmgr peer information in host driver + * @wma: wma handle + * @vdev_id: vdev id + * @peer_addr: peer mac address + * @wma_peer_type: peer type of enum wmi_peer_type + * @peer_mld: peer mld address + * + * Return: Pointer to objmgr_peer + */ +struct wlan_objmgr_peer *wma_create_objmgr_peer(tp_wma_handle wma, + uint8_t vdev_id, + uint8_t *peer_addr, + uint32_t wma_peer_type, + uint8_t *peer_mld); + +/** + * wma_remove_objmgr_peer() - Remove Object manager peer + * @wma: WMA handle + * @obj_vdev: Vdev object pointer + * @peer_addr: Peer mac address + * + * Return: None + */ +void wma_remove_objmgr_peer(tp_wma_handle wma, + struct wlan_objmgr_vdev *obj_vdev, + uint8_t *peer_addr); + +QDF_STATUS wma_peer_unmap_conf_cb(uint8_t vdev_id, + uint32_t peer_id_cnt, + uint16_t *peer_id_list); + +bool wma_objmgr_peer_exist(tp_wma_handle wma, + uint8_t *peer_addr, uint8_t *peer_vdev_id); + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +/** + * wma_peer_tbl_trans_add_entry() - Add peer transition to peer history + * @peer: Object manager peer pointer + * @is_create: Set to %true if @peer is getting created + * @peer_info: Info of peer setup on @peer create, + * %NULL if @is_create is %false. + * + * Adds new entry to peer history about the transition of peer in the system. + * The APIs has to be called to keep record of create and delete of peer. + * + * Returns: void + */ +void wma_peer_tbl_trans_add_entry(struct wlan_objmgr_peer *peer, bool is_create, + struct cdp_peer_setup_info *peer_info); +#else +static inline void +wma_peer_tbl_trans_add_entry(struct wlan_objmgr_peer *peer, bool is_create, + struct cdp_peer_setup_info *peer_info) +{ +} +#endif + +/** + * wma_get_cca_stats() - send request to fw to get CCA + * @wmi_hdl: wma handle + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle, + uint8_t vdev_id); + +struct wma_ini_config *wma_get_ini_handle(tp_wma_handle wma_handle); + +/** + * wma_chan_phy__mode() - get host phymode for channel + * @freq: channel freq + * @chan_width: maximum channel width possible + * @dot11_mode: maximum phy_mode possible + * + * Return: return host phymode + */ +enum wlan_phymode wma_chan_phy_mode(uint32_t freq, enum phy_ch_width chan_width, + uint8_t dot11_mode); + +/** + * wma_fw_to_host_phymode() - convert fw to host phymode + * @phymode: phymode to convert + * + * Return: one of the values defined in enum wlan_phymode; + * or WLAN_PHYMODE_AUTO if the conversion fails + */ +enum wlan_phymode wma_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode); + + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * wma_start_oem_req_cmd() - send oem request command to fw + * @wma_handle: wma handle + * @oem_data_req: the pointer of oem req buf + * + * Return: QDF status + */ +QDF_STATUS wma_start_oem_req_cmd(tp_wma_handle wma_handle, + struct oem_data_req *oem_data_req); +#endif + +#ifdef FEATURE_OEM_DATA +/** + * wma_start_oem_data_cmd() - send oem data command to fw + * @wma_handle: wma handle + * @oem_data: the pointer of oem data buf + * + * Return: QDF status + */ +QDF_STATUS wma_start_oem_data_cmd(tp_wma_handle wma_handle, + struct oem_data *oem_data); +#endif + +QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle, + uint8_t val); +void wma_register_packetdump_callback( + ol_txrx_pktdump_cb wma_mgmt_tx_packetdump_cb, + ol_txrx_pktdump_cb wma_mgmt_rx_packetdump_cb); +void wma_deregister_packetdump_callback(void); +void wma_update_sta_inactivity_timeout(tp_wma_handle wma, + struct sme_sta_inactivity_timeout *sta_inactivity_timer); + +/** + * wma_form_rx_packet() - form rx cds packet + * @buf: buffer + * @mgmt_rx_params: mgmt rx params + * @rx_pkt: cds packet + * + * This functions forms a cds packet from the rx mgmt frame received. + * + * Return: 0 for success or error code + */ +int wma_form_rx_packet(qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + cds_pkt_t *rx_pkt); + +/** + * wma_mgmt_unified_cmd_send() - send the mgmt tx packet + * @vdev: objmgr vdev + * @buf: buffer + * @desc_id: desc id + * @mgmt_tx_params: mgmt rx params + * + * This functions sends mgmt tx packet to WMI layer. + * + * Return: 0 for success or error code + */ +QDF_STATUS wma_mgmt_unified_cmd_send(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t buf, uint32_t desc_id, + void *mgmt_tx_params); + +#ifndef CONFIG_HL_SUPPORT +/** + * wma_mgmt_nbuf_unmap_cb() - dma unmap for pending mgmt pkts + * @pdev: objmgr pdev + * @buf: buffer + * + * This function does the dma unmap of the pending mgmt packet cleanup + * + * Return: None + */ +void wma_mgmt_nbuf_unmap_cb(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t buf); +/** + * wma_mgmt_nbuf_unmap_cb() - dma unmap for pending mgmt pkts + * @pdev: objmgr pdev + * @buf: buffer + * + * This is a cb function drains all mgmt packets of a vdev. + * This is called in event of target going down without sending completions. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_mgmt_frame_fill_peer_cb(struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf); +#else +static inline void wma_mgmt_nbuf_unmap_cb(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t buf) +{} +static inline QDF_STATUS wma_mgmt_frame_fill_peer_cb(struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_chan_info_event_handler() - chan info event handler + * @handle: wma handle + * @event_buf: event handler data + * @len: length of @event_buf + * + * this function will handle the WMI_CHAN_INFO_EVENTID + * + * Return: int + */ +int wma_chan_info_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +/** + * wma_update_vdev_pause_bitmap() - update vdev pause bitmap + * @vdev_id: the Id of the vdev to configure + * @value: value pause bitmap value + * + * Return: None + */ +static inline +void wma_vdev_update_pause_bitmap(uint8_t vdev_id, uint16_t value) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) + return; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id: %d", vdev_id); + return; + } + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + wma_err("Interface is NULL"); + return; + } + + iface->pause_bitmap = value; +} + +/** + * wma_vdev_get_pause_bitmap() - Get vdev pause bitmap + * @vdev_id: the Id of the vdev to configure + * + * Return: Vdev pause bitmap value else 0 on error + */ +static inline +uint16_t wma_vdev_get_pause_bitmap(uint8_t vdev_id) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) + return 0; + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + wma_err("Interface is NULL"); + return 0; + } + + return iface->pause_bitmap; +} + +/** + * wma_vdev_is_device_in_low_pwr_mode - is device in power save mode + * @vdev_id: the Id of the vdev to configure + * + * Return: true if device is in low power mode else false + */ +static inline bool wma_vdev_is_device_in_low_pwr_mode(uint8_t vdev_id) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) + return 0; + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + wma_err("Interface is NULL"); + return 0; + } + + return iface->in_bmps || wma->in_imps; +} + +/** + * wma_vdev_get_dtim_period - Get dtim period value from mlme + * @vdev_id: vdev index number + * @value: pointer to the value to fill out + * + * Note caller must verify return status before using value + * + * Return: QDF_STATUS_SUCCESS when fetched a valid value from cfg else + * QDF_STATUS_E_FAILURE + */ +static inline +QDF_STATUS wma_vdev_get_dtim_period(uint8_t vdev_id, uint8_t *value) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + /* set value to zero */ + *value = 0; + + if (!wma) + return QDF_STATUS_E_FAILURE; + + iface = &wma->interfaces[vdev_id]; + + if (!iface) + return QDF_STATUS_E_FAILURE; + + *value = iface->dtimPeriod; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_vdev_get_beacon_interval - Get beacon interval from mlme + * @vdev_id: vdev index number + * @value: pointer to the value to fill out + * + * Note caller must verify return status before using value + * + * Return: QDF_STATUS_SUCCESS when fetched a valid value from cfg else + * QDF_STATUS_E_FAILURE + */ +static inline +QDF_STATUS wma_vdev_get_beacon_interval(uint8_t vdev_id, uint16_t *value) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + /* set value to zero */ + *value = 0; + + if (!wma) + return QDF_STATUS_E_FAILURE; + + iface = &wma->interfaces[vdev_id]; + + if (!iface) + return QDF_STATUS_E_FAILURE; + + *value = iface->beaconInterval; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_vdev_rate_flag - Get beacon rate flag from mlme + * @vdev_id: vdev index number + * @rate_flag: pointer to the value to fill out + * + * Note caller must verify return status before using value + * + * Return: QDF_STATUS_SUCCESS when fetched a valid value from mlme else + * QDF_STATUS_E_FAILURE + */ +static inline QDF_STATUS +wma_get_vdev_rate_flag(struct wlan_objmgr_vdev *vdev, uint32_t *rate_flag) +{ + struct vdev_mlme_obj *mlme_obj; + + if (!vdev) { + wma_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("ailed to get mlme_obj"); + return QDF_STATUS_E_FAILURE; + } + + *rate_flag = mlme_obj->mgmt.rate_info.rate_flags; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_vdev_set_pause_bit() - Set a bit in vdev pause bitmap + * @vdev_id: the Id of the vdev to configure + * @bit_pos: set bit position in pause bitmap + * + * Return: None + */ +static inline +void wma_vdev_set_pause_bit(uint8_t vdev_id, wmi_tx_pause_type bit_pos) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) + return; + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + wma_err("Interface is NULL"); + return; + } + + iface->pause_bitmap |= (1 << bit_pos); +} + +/** + * wma_vdev_clear_pause_bit() - Clear a bit from vdev pause bitmap + * @vdev_id: the Id of the vdev to configure + * @bit_pos: set bit position in pause bitmap + * + * Return: None + */ +static inline +void wma_vdev_clear_pause_bit(uint8_t vdev_id, wmi_tx_pause_type bit_pos) +{ + tp_wma_handle wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) + return; + + iface = &wma->interfaces[vdev_id]; + + if (!iface) { + wma_err("Interface is NULL"); + return; + } + + iface->pause_bitmap &= ~(1 << bit_pos); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_send_roam_preauth_status() - Send the preauth status to wmi + * @handle: WMA handle + * @roam_req: Pointer to wmi_roam_auth_status_params from sae + * + * Return: None + */ +void +wma_send_roam_preauth_status(tp_wma_handle wma_handle, + struct wmi_roam_auth_status_params *params); +/** + * wma_handle_roam_sync_timeout() - Update roaming status at wma layer + * @wma_handle: wma handle + * @info: Info for roaming start timer + * + * This function gets called in case of roaming offload timer get expired + * + * Return: None + */ +void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle, + struct roam_sync_timeout_timer_info *info); +#else +static inline void +wma_send_roam_preauth_status(tp_wma_handle wma_handle, + struct wmi_roam_auth_status_params *params) +{} + +static inline void +wma_handle_roam_sync_timeout(tp_wma_handle wma_handle, + struct roam_sync_timeout_timer_info *info) +{} +#endif + +#ifdef WMI_INTERFACE_EVENT_LOGGING +static inline void wma_print_wmi_cmd_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, "Command Log (count %u)", count); + wmi_print_cmd_log(wma->wmi_handle, count, print, print_priv); + } +} + +static inline void wma_print_wmi_cmd_tx_cmp_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, "Command Tx Complete Log (count %u)", count); + wmi_print_cmd_tx_cmp_log(wma->wmi_handle, count, print, + print_priv); + } +} + +static inline void wma_print_wmi_mgmt_cmd_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, "Management Command Log (count %u)", count); + wmi_print_mgmt_cmd_log(wma->wmi_handle, count, print, + print_priv); + } +} + +static inline void wma_print_wmi_mgmt_cmd_tx_cmp_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, + "Management Command Tx Complete Log (count %u)", count); + wmi_print_mgmt_cmd_tx_cmp_log(wma->wmi_handle, count, print, + print_priv); + } +} + +static inline void wma_print_wmi_event_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, "Event Log (count %u)", count); + wmi_print_event_log(wma->wmi_handle, count, print, print_priv); + } +} + +static inline void wma_print_wmi_rx_event_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, "Rx Event Log (count %u)", count); + wmi_print_rx_event_log(wma->wmi_handle, count, print, + print_priv); + } +} + +static inline void wma_print_wmi_mgmt_event_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + print(print_priv, "Management Event Log (count %u)", count); + wmi_print_mgmt_event_log(wma->wmi_handle, count, print, + print_priv); + } +} +#else + +static inline void wma_print_wmi_cmd_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} + +static inline void wma_print_wmi_cmd_tx_cmp_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} + +static inline void wma_print_wmi_mgmt_cmd_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} + +static inline void wma_print_wmi_mgmt_cmd_tx_cmp_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} + +static inline void wma_print_wmi_event_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} + +static inline void wma_print_wmi_rx_event_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} + +static inline void wma_print_wmi_mgmt_event_log(uint32_t count, + qdf_abstract_print *print, + void *print_priv) +{ +} +#endif /* WMI_INTERFACE_EVENT_LOGGING */ + +/** + * wma_set_rx_reorder_timeout_val() - set rx recorder timeout value + * @wma_handle: pointer to wma handle + * @reorder_timeout: rx reorder timeout value + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_rx_reorder_timeout_val(tp_wma_handle wma_handle, + struct sir_set_rx_reorder_timeout_val *reorder_timeout); + +/** + * wma_set_rx_blocksize() - set rx blocksize + * @wma_handle: pointer to wma handle + * @peer_rx_blocksize: rx blocksize for peer mac + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_rx_blocksize(tp_wma_handle wma_handle, + struct sir_peer_set_rx_blocksize *peer_rx_blocksize); +/** + * wma_configure_smps_params() - Configures the smps parameters to set + * @vdev_id: Virtual device for the command + * @param_id: SMPS parameter ID + * @param_val: Value to be set for the parameter + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS wma_configure_smps_params(uint32_t vdev_id, uint32_t param_id, + uint32_t param_val); + +/* + * wma_chip_power_save_failure_detected_handler() - chip pwr save fail detected + * event handler + * @handle: wma handle + * @cmd_param_info: event handler data + * @len: length of @cmd_param_info + * + * Return: QDF_STATUS_SUCCESS on success; error code otherwise + */ +int wma_chip_power_save_failure_detected_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +/** + * wma_get_chain_rssi() - send wmi cmd to get chain rssi + * @wma_handle: wma handler + * @req_params: requset params + * + * Return: Return QDF_STATUS + */ +QDF_STATUS wma_get_chain_rssi(tp_wma_handle wma_handle, + struct get_chain_rssi_req_params *req_params); + +/** + * wma_config_bmiss_bcnt_params() - set bmiss config parameters + * @vdev_id: virtual device for the command + * @first_cnt: bmiss first value + * @final_cnt: bmiss final value + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS wma_config_bmiss_bcnt_params(uint32_t vdev_id, uint32_t first_cnt, + uint32_t final_cnt); + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD +/** + * wma_check_and_set_wake_timer(): checks all interfaces and if any interface + * has install_key pending, sets timer pattern in fw to wake up host after + * specified time has elapsed. + * @time: time after which host wants to be awaken. + * + * Return: None + */ +void wma_check_and_set_wake_timer(uint32_t time); +#endif + +/** + * wma_delete_invalid_peer_entries() - Delete invalid peer entries stored + * @vdev_id: virtual interface id + * @peer_mac_addr: Peer MAC address + * + * Removes the invalid peer mac entry from wma node + */ +void wma_delete_invalid_peer_entries(uint8_t vdev_id, uint8_t *peer_mac_addr); + +/** + * wma_rx_invalid_peer_ind() - the callback for DP to notify WMA layer + * invalid peer data is received, this function will send message to + * lim module. + * @vdev_id: virtual device ID + * @wh: Pointer to 802.11 frame header + * + * Return: 0 for success or non-zero on failure + */ +uint8_t wma_rx_invalid_peer_ind(uint8_t vdev_id, void *wh); + +/** + * wma_dp_send_delba_ind() - the callback for DP to notify WMA layer + * to del ba of rx + * @vdev_id: vdev id + * @peer_macaddr: peer mac address + * @tid: tid of rx + * @reason_code: reason code + * @cdp_rcode: CDP reason code for sending DELBA + * + * Return: 0 for success or non-zero on failure + */ +int wma_dp_send_delba_ind(uint8_t vdev_id, + uint8_t *peer_macaddr, + uint8_t tid, + uint8_t reason_code, + enum cdp_delba_rcode cdp_rcode); + +/** + * is_roam_inprogress() - Is vdev in progress + * @vdev_id: vdev of interest + * + * Return: true if roaming started, false during roam sync and otherwise + */ +bool wma_is_roam_in_progress(uint32_t vdev_id); + +/** + * wma_get_psoc_from_scn_handle() - API to get psoc from scn handle + * @scn_handle: opaque wma handle + * + * API to get psoc from scn handle + * + * Return: psoc context or null in case of failure + */ +struct wlan_objmgr_psoc *wma_get_psoc_from_scn_handle(void *scn_handle); + +/** + * wma_set_peer_ucast_cipher() - Update unicast cipher of the peer + * @mac_addr: peer mac address + * @cipher: peer cipher bits + * @cipher_cap: cipher cap + * + * Return: None + */ +void wma_set_peer_ucast_cipher(uint8_t *mac_addr, int32_t cipher, + int32_t cipher_cap); + +/** + * wma_update_set_key() - Update WMA layer for set key + * @session_id: vdev session identifier + * @pairwise: denotes if it is pairwise or group key + * @key_index: Key Index + * @cipher_type: cipher type being used for the encryption/decryption + * + * Return: None + */ +void wma_update_set_key(uint8_t session_id, bool pairwise, + uint8_t key_index, + enum wlan_crypto_cipher_type cipher_type); + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * wma_motion_det_host_event_handler - motion detection event handler + * @handle: WMA global handle + * @event: motion detection event + * @len: Length of cmd + * + * Call motion detection event callback handler + * + * Return: 0 on success, else error on failure + */ + +int wma_motion_det_host_event_handler(void *handle, u_int8_t *event, + u_int32_t len); + +/** + * wma_motion_det_base_line_host_event_handler - md baselining event handler + * @handle: WMA global handle + * @event: motion detection baselining event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +int wma_motion_det_base_line_host_event_handler(void *handle, u_int8_t *event, + u_int32_t len); +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +/** + * wma_add_bss_peer_sta() - create bss peer when sta connect + * @vdev_id: vdev id + * @bssid: AP bssid + * @roam_sync: if roam sync is in progress + * @is_resp_required: Peer create response is expected from firmware. + * This flag will be set to true for initial connection and false for + * LFR2 case. + * @mld_mac: peer mld mac address + * @is_assoc_peer: is assoc peer or not + * + * Return: 0 on success, else error on failure + */ +QDF_STATUS wma_add_bss_peer_sta(uint8_t vdev_id, uint8_t *bssid, + bool is_resp_required, uint8_t *mld_mac, + bool is_assoc_peer); + +/** + * wma_send_vdev_stop() - WMA api to send vdev stop to fw + * @vdev_id: vdev id + * + * Return: 0 on success, else error on failure + */ +QDF_STATUS wma_send_vdev_stop(uint8_t vdev_id); + +/** + * wma_pre_assoc_req() - wma pre assoc req when sta connect + * @add_bss: add bss param + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_pre_assoc_req(struct bss_params *add_bss); + +/** + * wma_add_bss_lfr3() - add bss during LFR3 offload roaming + * @wma: wma handler + * @add_bss: add bss param + * + * Return: None + */ +void wma_add_bss_lfr3(tp_wma_handle wma, struct bss_params *add_bss); + +#ifdef WLAN_FEATURE_HOST_ROAM +/** + * wma_add_bss_lfr2_vdev_start() - add bss and start vdev during host roaming + * @vdev: vdev in object manager + * @add_bss: add bss param + * + * Return: None + */ +QDF_STATUS wma_add_bss_lfr2_vdev_start(struct wlan_objmgr_vdev *vdev, + struct bss_params *add_bss); +#endif + +/** + * wma_set_vdev_bw() - wma send vdev bw + * @vdev_id: vdev id + * @bw: band width + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_vdev_bw(uint8_t vdev_id, uint8_t bw); + +/** + * wma_send_peer_assoc_req() - wma send peer assoc req when sta connect + * @add_bss: add bss param + * + * Return: None + */ +QDF_STATUS wma_send_peer_assoc_req(struct bss_params *add_bss); + +/** + * wma_get_rx_chainmask() - API to get rx chainmask from mac phy capability + * @pdev_id: pdev id + * @chainmask_2g: pointer to return 2g chainmask + * @chainmask_5g: pointer to return 5g chainmask + * + * API to get rx chainmask from mac phy capability directly. + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS wma_get_rx_chainmask(uint8_t pdev_id, uint32_t *chainmask_2g, + uint32_t *chainmask_5g); + +/** + * wma_handle_channel_switch_resp() - handle channel switch resp + * @wma: wma handle + * @rsp: response for channel switch + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_handle_channel_switch_resp(tp_wma_handle wma, + struct vdev_start_response *rsp); + +/** + * wma_pre_chan_switch_setup() - handler before channel switch vdev start + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id); + +/** + * wma_post_chan_switch_setup() - handler after channel switch vdev start + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id); + +/** + * wma_vdev_pre_start() - prepare vdev start + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_vdev_pre_start(uint8_t vdev_id, bool restart); + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wma_delete_peer_mlo() - Remove the MLO peer and detach link peer + * @psoc: PSOC objmgr pointer + * @macaddr: MAC address of objmgr peer + * + * The API will remove the ML peer with objmgr peer fetched from + * psoc peer list using the @macaddr. + * + * Return: void + */ +void wma_delete_peer_mlo(struct wlan_objmgr_psoc *psoc, uint8_t *macaddr); +#else +static inline +void wma_delete_peer_mlo(struct wlan_objmgr_psoc *psoc, uint8_t *macaddr) +{ +} +#endif + +/** + * wma_remove_bss_peer_on_failure() - remove the bss peers in case of + * failure + * @wma: wma handle. + * @vdev_id: vdev id + * + * This API deletes the BSS peer created during ADD BSS in case of ADD BSS + * request sent to the FW fails. + * + * Return: None; + */ +void wma_remove_bss_peer_on_failure(tp_wma_handle wma, uint8_t vdev_id); + +/** + * wma_remove_bss_peer_before_join() - remove the bss peers in case of + * failure before join (vdev start) for sta mode + * @wma: wma handle. + * @vdev_id: vdev id + * @cm_join_req: join cm context + * + * This API deletes the BSS peer if any failure before "join" (vdev start). + * And indicate connection failure to CM after bss peer delete event comes + * from FW. + * + * Return: QDF_STATUS_SUCCESS if success, QDF_STATUS_E_PENDING if peer delete + * event will be indicated later from target. + */ +QDF_STATUS wma_remove_bss_peer_before_join( + tp_wma_handle wma, uint8_t vdev_id, + void *cm_join_req); + +/** + * wma_send_add_bss_resp() - send add bss failure + * @wma: wma handle. + * @vdev_id: vdev id + * @status: status + * + * Return: None + */ +void wma_send_add_bss_resp(tp_wma_handle wma, uint8_t vdev_id, + QDF_STATUS status); + +/** + * wma_post_vdev_start_setup() - wma post vdev start handler + * @wma: wma handle. + * @vdev_id: vdev id + * + * Return: Success or Failure status + */ +QDF_STATUS wma_post_vdev_start_setup(uint8_t vdev_id); + +/** + * wma_pre_vdev_start_setup() - wma pre vdev start handler + * @wma: wma handle. + * @vdev_id: vdev id + * @addbss_param: bss param + * + * Return: Success or Failure status + */ +QDF_STATUS wma_pre_vdev_start_setup(uint8_t vdev_id, + struct bss_params *add_bss); + +#ifdef FEATURE_ANI_LEVEL_REQUEST +/** + * wma_send_ani_level_request() - Send get ani level cmd to WMI + * @wma_handle: wma handle. + * @freqs: pointer to channels for which ANI level has to be retrieved + * @num_freqs: number of channels in the above parameter + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_ani_level_request(tp_wma_handle wma_handle, + uint32_t *freqs, uint8_t num_freqs); +#endif /* FEATURE_ANI_LEVEL_REQUEST */ + +/** + * wma_vdev_detach() - send vdev delete command to fw + * @wma_handle: wma handle + * @pdel_vdev_req_param: del vdev params + * + * Return: QDF status + */ +QDF_STATUS wma_vdev_detach(struct del_vdev_params *pdel_vdev_req_param); + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +/** + * wma_p2p_self_peer_remove() - Send P2P self peer delete command to FW + * @vdev: Object manager vdev + * + * Return: success if peer delete command sent to firmware, else failure. + */ + +QDF_STATUS wma_p2p_self_peer_remove(struct wlan_objmgr_vdev *vdev); +#endif +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_api.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_api.h new file mode 100644 index 0000000000..df1b26ef76 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_api.h @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WMA_API_H +#define WMA_API_H + +#include "osdep.h" +#include "ani_global.h" +#include "a_types.h" +#include "osapi_linux.h" +#include "wmi_unified.h" +#ifdef NOT_YET +#include "htc_api.h" +#endif +#include "lim_global.h" +#include "cds_utils.h" +#include "scheduler_api.h" +#include "wlan_policy_mgr_api.h" +#include "wma_sar_public_structs.h" +#include +#include "include/wlan_vdev_mlme.h" +#include "wlan_mlme_vdev_mgr_interface.h" + +typedef void *WMA_HANDLE; + +/** + * enum GEN_PARAM - general parameters + * @GEN_VDEV_PARAM_AMPDU: Set ampdu size + * @GEN_VDEV_PARAM_AMSDU: Set amsdu size + * @GEN_PARAM_CRASH_INJECT: inject crash + * @GEN_PARAM_CAPTURE_TSF: read tsf + * @GEN_PARAM_RESET_TSF_GPIO: reset tsf gpio + * @GEN_VDEV_ROAM_SYNCH_DELAY: roam sync delay + * @GEN_VDEV_PARAM_TX_AMPDU: Set tx ampdu size + * @GEN_VDEV_PARAM_RX_AMPDU: Set rx ampdu size + * @GEN_VDEV_PARAM_TX_AMSDU: Set tx amsdu size + * @GEN_VDEV_PARAM_RX_AMSDU: Set rx amsdu size + * @GEN_PARAM_TSF_AUTO_REPORT_ENABLE: Enable auto report of clock delta change + * @GEN_PARAM_TSF_AUTO_REPORT_DISABLE: Disable auto report of clock delta change + */ +enum GEN_PARAM { + GEN_VDEV_PARAM_AMPDU = 0x1, + GEN_VDEV_PARAM_AMSDU, + GEN_PARAM_CRASH_INJECT, + GEN_PARAM_CAPTURE_TSF, + GEN_PARAM_RESET_TSF_GPIO, + GEN_VDEV_ROAM_SYNCH_DELAY, + GEN_VDEV_PARAM_TX_AMPDU, + GEN_VDEV_PARAM_RX_AMPDU, + GEN_VDEV_PARAM_TX_AMSDU, + GEN_VDEV_PARAM_RX_AMSDU, + GEN_PARAM_TSF_AUTO_REPORT_ENABLE, + GEN_PARAM_TSF_AUTO_REPORT_DISABLE, +}; + +/** + * struct wma_caps_per_phy - various caps per phy + * @ht_2g: entire HT cap for 2G band in terms of 32 bit flag + * @ht_5g: entire HT cap for 5G band in terms of 32 bit flag + * @vht_2g: entire VHT cap for 2G band in terms of 32 bit flag + * @vht_5g: entire VHT cap for 5G band in terms of 32 bit flag + * @he_2g: entire HE cap for 2G band in terms of 32 bit flag + * @he_5g: entire HE cap for 5G band in terms of 32 bit flag + * @tx_chain_mask_2G: tx chain mask for 2g + * @rx_chain_mask_2G: rx chain mask for 2g + * @tx_chain_mask_5G: tx chain mask for 5g + * @rx_chain_mask_5G: rx chain mask for 5g + */ +struct wma_caps_per_phy { + uint32_t ht_2g; + uint32_t ht_5g; + uint32_t vht_2g; + uint32_t vht_5g; + uint32_t he_2g[PSOC_HOST_MAX_MAC_SIZE]; + uint32_t he_5g[PSOC_HOST_MAX_MAC_SIZE]; + uint32_t tx_chain_mask_2G; + uint32_t rx_chain_mask_2G; + uint32_t tx_chain_mask_5G; + uint32_t rx_chain_mask_5G; +}; + +struct wma_ps_params { + enum wmi_sta_ps_scheme_cfg opm_mode; + uint16_t ps_ito; + uint16_t spec_wake; +}; + +/** + * enum wma_sta_ps_scheme_cfg - STA power save schemes + * @WMA_STA_PS_OPM_CONSERVATIVE - Conservative OPM mode + * @WMA_STA_PS_OPM_AGGRESSIVE - Aggressive OPM mode + * @WMA_STA_PS_USER_DEF - User defined OPM mode + */ +enum wma_sta_ps_scheme_cfg { + WMA_STA_PS_OPM_CONSERVATIVE = 0, + WMA_STA_PS_OPM_AGGRESSIVE = 1, + WMA_STA_PS_USER_DEF = 2, +}; + +#define VDEV_CMD 1 +#define PDEV_CMD 2 +#define GEN_CMD 3 +#define DBG_CMD 4 +#define PPS_CMD 5 +#define QPOWER_CMD 6 +#define GTX_CMD 7 + +typedef void (*wma_peer_authorized_fp) (uint32_t vdev_id); + + +QDF_STATUS wma_pre_start(void); + +QDF_STATUS wma_mc_process_handler(struct scheduler_msg *msg); + +QDF_STATUS wma_start(void); + +/** + * wma_stop() - wma stop function. + * + * Performs all of the operations required to stop the WMA layer + * + * Return: QDF_STATUS_SUCCESS on success, QDF Error on failure + */ +QDF_STATUS wma_stop(void); + +QDF_STATUS wma_close(void); + +QDF_STATUS wma_wmi_service_close(void); + +QDF_STATUS wma_wmi_work_close(void); + +int wma_rx_ready_event(void *handle, uint8_t *ev, uint32_t len); + +int wma_rx_service_ready_event(void *handle, uint8_t *ev, uint32_t len); + +int wma_rx_service_ready_ext_event(void *handle, uint8_t *ev, uint32_t len); + +/** + * wma_rx_service_ready_ext2_event() - evt handler for service ready ext2 event. + * @handle: wma handle + * @ev: params of the service ready extended event + * @len: param length + * + * Return: none + */ +int wma_rx_service_ready_ext2_event(void *handle, uint8_t *ev, uint32_t len); + +QDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle); + +int wma_cli_get_command(int vdev_id, int param_id, int vpdev); +int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev); +int wma_cli_set2_command(int vdev_id, int param_id, int sval1, + int sval2, int vpdev); + +/** + * wma_get_fw_phy_mode_for_freq_cb() - Callback to get current PHY Mode. + * @freq: channel freq + * @chan_width: maximum channel width possible + * @phy_mode: firmware PHY Mode + * + * Return: None + */ +void wma_get_fw_phy_mode_for_freq_cb(uint32_t freq, uint32_t chan_width, + uint32_t *phy_mode); +/** + * wma_get_phy_mode_cb() - Callback to get current PHY Mode. + * @freq: channel frequency + * @chan_width: maximum channel width possible + * @phy_mode: PHY Mode + * + * Return: None + */ +void wma_get_phy_mode_cb(qdf_freq_t freq, uint32_t chan_width, + enum wlan_phymode *phy_mode); + +QDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value); + +QDF_STATUS wma_set_peer_param(void *wma_ctx, uint8_t *peer_addr, + uint32_t param_id, + uint32_t param_value, uint32_t vdev_id); +QDF_STATUS wma_get_link_speed(WMA_HANDLE handle, + struct link_speed_info *pLinkSpeed); +#ifdef NOT_YET +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, void *scan_chan_info); +#endif + +/** + * wma_get_vdev_address_by_vdev_id() - lookup MAC address from vdev ID + * @vdev_id: vdev id + * + * Return: mac address + */ +uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id); +struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id); +QDF_STATUS wma_get_connection_info(uint8_t vdev_id, + struct policy_mgr_vdev_entry_info *conn_table_entry); +QDF_STATUS wma_ndi_update_connection_info(uint8_t vdev_id, + struct nan_datapath_channel_info *ndp_chan_info); + +#ifdef WLAN_FEATURE_PKT_CAPTURE +int wma_get_rmf_status(uint8_t vdev_id); +#endif + +bool wma_is_vdev_up(uint8_t vdev_id); + +void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size); + +bool wma_get_fw_wlan_feat_caps(enum cap_bitmap feature); +void wma_set_fw_wlan_feat_caps(enum cap_bitmap feature); + +QDF_STATUS wma_post_ctrl_msg(struct mac_context *mac, struct scheduler_msg *pMsg); + +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index); + +QDF_STATUS wma_get_caps_for_phyidx_hwmode(struct wma_caps_per_phy *caps_per_phy, + enum hw_mode_dbs_capab hw_mode, enum cds_band_type band); +bool wma_is_rx_ldpc_supported_for_channel(uint32_t ch_freq); + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +int wma_unified_radio_tx_mem_free(void *handle); + +/* + * wma_unified_link_stats_results_mem_free() - Free the memory for + * link_stats_results->results allocated when event comes. + * @link_stats_results: pointer to the memory that is to be freed + * + * Return: None + */ +void +wma_unified_link_stats_results_mem_free(tSirLLStatsResults *link_stats_results); + +#else /* WLAN_FEATURE_LINK_LAYER_STATS */ +static inline int wma_unified_radio_tx_mem_free(void *handle) +{ + return 0; +} +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * wma_form_unit_test_cmd_and_send() - to form a wma command and send it to FW + * @vdev_id: vdev id to be filled while forming the command + * @module_id: module id given by user to be filled in the command + * @arg_count: number of argument count + * @arg: pointer to argument list + * + * This API exposed to HDD layer which takes the argument from user and forms + * the wma unit test command to be sent down to firmware + * + * Return: QDF_STATUS based on overall success + */ +QDF_STATUS wma_form_unit_test_cmd_and_send(uint32_t vdev_id, + uint32_t module_id, uint32_t arg_count, uint32_t *arg); + +QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE wma, + struct beacon_filter_param *filter_params); + +QDF_STATUS wma_add_beacon_filter(WMA_HANDLE wma, + struct beacon_filter_param *filter_params); +QDF_STATUS wma_send_adapt_dwelltime_params(WMA_HANDLE handle, + struct adaptive_dwelltime_params *dwelltime_params); + +/** + * wma_send_dbs_scan_selection_params() - send DBS scan selection configuration + * params to firmware + * @handle: wma handler + * @dbs_scan_params: pointer to wmi_dbs_scan_sel_params + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure + */ +QDF_STATUS wma_send_dbs_scan_selection_params(WMA_HANDLE handle, + struct wmi_dbs_scan_sel_params *dbs_scan_params); +QDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value); +QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value); +QDF_STATUS wma_enable_disable_imps(uint32_t pdev_id, uint32_t param_val); + +bool wma_is_csa_offload_enabled(void); +/** + * wma_is_mbssid_enabled - checks MBSSID support + * + * Return: true or false + */ +bool wma_is_mbssid_enabled(void); + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +bool wma_is_p2p_lo_capable(void); +#else +static inline bool wma_is_p2p_lo_capable(void) +{ + return 0; +} +#endif +bool wma_capability_enhanced_mcast_filter(void); +void wma_process_pdev_hw_mode_trans_ind(void *wma, + wmi_pdev_hw_mode_transition_event_fixed_param *fixed_param, + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind); + +/** + * wma_set_cts2self_for_p2p_go() - set CTS2SELF command for P2P GO. + * @wma_handle: pointer to wma handle. + * @cts2self_for_p2p_go: value needs to set to firmware. + * + * At the time of driver startup, inform about ini parma to FW that + * if legacy client connects to P2P GO, stop using NOA for P2P GO. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_cts2self_for_p2p_go(void *wma_handle, + uint32_t cts2self_for_p2p_go); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_get_roam_scan_ch() - API to get roam scan channel list. + * @wma: pointer to wma handle. + * @vdev_id: vdev id + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wma, + uint8_t vdev_id); +#else +static inline +QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wma, + uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +/** + * wma_set_tx_rx_aggr_size() - set tx rx aggregation size + * @vdev_id: vdev id + * @tx_size: tx aggr size + * @rx_size: rx aggr size + * @aggr_type: aggregation type + * + * This function try to set the aggregation size. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_set_tx_rx_aggr_size(uint8_t vdev_id, + uint32_t tx_size, + uint32_t rx_size, + wmi_vdev_custom_aggr_type_t aggr_type); +/** + * wma_set_tx_rx_aggr_size_per_ac() - set aggregation size per ac + * @wma_handle: pointer to wma handle. + * @vdev_id: vdev_id + * @qos_aggr: QoS data + * @aggr_type: aggregation type + * + * This function try to set the aggregation size per AC. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +wma_set_tx_rx_aggr_size_per_ac(WMA_HANDLE wma_handle, + uint8_t vdev_id, + struct wlan_mlme_qos *qos_aggr, + wmi_vdev_custom_aggr_type_t aggr_type); + +/** + * wma_set_vdev_sw_retry_th() - set sw retry threshold per vdev + * @vdev_id: vdev id + * @sw_retry_count: sw retry number + * @retry_type: SW vdev retry type + * + * This function sends WMI command to set the sw retry threshold per vdev. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_vdev_sw_retry_th(uint8_t vdev_id, uint8_t sw_retry_count, + wmi_vdev_custom_sw_retry_type_t retry_type); + +/** + * wma_set_sw_retry_threshold_per_ac() - set sw retry threshold per AC for tx + * @handle: wma handle + * @vdev_id: vdev id + * @qos_aggr: pointer to QOS TX/RX aggregation values + * + * This function sends WMI command to set the sw retry threshold per AC + * for Tx. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_sw_retry_threshold_per_ac + (WMA_HANDLE handle, + uint8_t vdev_id, struct wlan_mlme_qos *qos_aggr); + +/** + * wma_set_sw_retry_threshold() - set sw retry threshold for tx + * @qos_aggr: pointer to wlan_mlme_qos + * + * This function sends WMI command to set the sw retry threshold for Tx. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_sw_retry_threshold(struct wlan_mlme_qos *qos_aggr); + +/** + * wma_get_sar_limit() - get SAR limits from the target + * @handle: wma handle + * @callback: Callback function to invoke with the results + * @context: Opaque context to pass back to caller in the callback + * + * This function sends WMI command to get SAR limits. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_get_sar_limit(WMA_HANDLE handle, + wma_sar_cb callback, void *context); + +/** + * wma_set_sar_limit() - set sar limits in the target + * @handle: wma handle + * @sar_limit_params: sar limit cmd params + * + * This function sends WMI command to set SAR limits. + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS wma_set_sar_limit(WMA_HANDLE handle, + struct sar_limit_cmd_params *sar_limit_params); + +/** + * wma_send_coex_config_cmd() - Send coex config params + * @wma_handle: wma handle + * @coex_cfg_params: struct to coex cofig params + * + * This function sends WMI command to send coex cofig params + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_coex_config_cmd(WMA_HANDLE wma_handle, + struct coex_config_params *coex_cfg_params); + +/** + * wma_set_power_config() - update power config in wma + * @vdev_id: the Id of the vdev to configure + * @power: new power value + * + * Return: QDF_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_power_config(uint8_t vdev_id, + enum wma_sta_ps_scheme_cfg power); + +/** + * wma_set_power_config_ito() - update power save inactivity timeout + * @vdev_id: the Id of the vdev to configure + * @ps_ito: new power save inactivity timeout in milliseconds + * + * Return: QDF_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_power_config_ito(uint8_t vdev_id, uint16_t ps_ito); + +/** + * wma_set_power_config_spec_wake() - update opm speculative wake interval + * @vdev_id: the Id of the vdev to configure + * @spec_wake: new opm speculative wake interval in milliseconds + * + * Return: QDF_STATUS_SUCCESS on success, error number otherwise + */ +QDF_STATUS wma_set_power_config_spec_wake(uint8_t vdev_id, uint16_t spec_wake); + +#ifdef FEATURE_WLAN_D0WOW +static inline bool wma_d0_wow_is_supported(void) +{ + return true; +} +#else +static inline bool wma_d0_wow_is_supported(void) +{ + return false; +} +#endif + +/** + * wma_store_pdev() - store pdev + * @wma_ctx: wma context + * @pdev: pdev context + * + * Return: void + */ +void wma_store_pdev(void *wma_ctx, struct wlan_objmgr_pdev *pdev); + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +/** + * wmi_to_sir_peer_type() - convert peer type from WMI to SIR enum + * @type: enum wmi_peer_type + * + * Return: tSirWifiPeerType + */ +tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type); +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +QDF_STATUS wma_crash_inject(WMA_HANDLE wma_handle, uint32_t type, + uint32_t delay_time_ms); + +/** + * wma_critical_events_in_flight() - get the number of critical events in flight + * + * This API gets the number of events in flight which should prevent power + * collapse. + * + * Return: the number of critical events in flight + */ +uint32_t wma_critical_events_in_flight(void); + +#ifdef FEATURE_WLAN_DYNAMIC_CVM +/** + * wma_set_vc_mode_config() - set voltage corner mode config to FW. + * @wma_handle: pointer to wma handle. + * @vc_bitmap: value needs to set to firmware. + * + * At the time of driver startup, set operating voltage corner mode + * for differenet phymode and bw configurations. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_vc_mode_config(void *wma_handle, + uint32_t vc_bitmap); +#endif + +QDF_STATUS wma_process_dhcp_ind(WMA_HANDLE wma_handle, + tAniDHCPInd *ta_dhcp_ind); + +/** + * wma_wmi_stop() - send wmi stop cmd + * + * Return: None + */ +void wma_wmi_stop(void); + +/** + * wma_get_mcs_idx() - get mcs index + * @raw_rate: raw rate from fw + * @rate_flags: rate flags + * @is_he_mcs_12_13_supported: is he mcs12/13 supported + * @nss: nss + * @dcm: dcm + * @guard_interval: guard interval + * @mcs_rate_flag: mcs rate flags + * + * Return: mcs index + */ +uint8_t wma_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags, + bool is_he_mcs_12_13_supported, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag); + +/** + * wma_get_hidden_ssid_restart_in_progress() - check if hidden ssid restart is + * in progress + * @iface: iface pointer + * + * Return: true if hidden ssid restart is in progress else false + */ +bool wma_get_hidden_ssid_restart_in_progress(struct wma_txrx_node *iface); + +/** + * wma_get_channel_switch_in_progress() - check if channel switch is in progress + * @iface: iface pointer + * + * Return: true if channel switch is in progress else false + */ +bool wma_get_channel_switch_in_progress(struct wma_txrx_node *iface); + +/** + * wma_sta_mlme_vdev_start_continue() - VDEV start response handling + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV start response actions + * + * Return: SUCCESS on successful completion of start response operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_sta_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_ap_mlme_vdev_start_continue() - VDEV start response handling + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV start response actions + * + * Return: SUCCESS on successful completion of start response operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_ap_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_sta_vdev_up_send() - Send VDEV UP command + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV UP Command + * + * Return: SUCCESS on successful completion of start response operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_sta_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_mlme_vdev_stop_continue() - VDEV stop response handling + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV stop response actions + * + * Return: SUCCESS on successful completion of stop response operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_mlme_vdev_stop_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_ap_mlme_vdev_down_send() - VDEV down operation + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV down operation + * + * Return: SUCCESS on successful completion of VDEV down operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_ap_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_mlme_vdev_notify_down_complete() - VDEV init state transition + * notification + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API notifies MLME on moving to INIT state + * + * Return: SUCCESS on successful completion of down notification + * FAILURE, if it fails due to any + */ +QDF_STATUS +wma_mlme_vdev_notify_down_complete(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_ap_mlme_vdev_stop_start_send() - handle vdev stop during start req + * @vdev_mlme: VDEV MLME comp object + * @type: restart req or start req + * @data_len: data size + * @data: event data + * + * API handle vdev stop during start req + * + * Return: SUCCESS alsways + */ +QDF_STATUS wma_ap_mlme_vdev_stop_start_send(struct vdev_mlme_obj *vdev_mlme, + enum vdev_cmd_type type, + uint16_t data_len, void *data); + +/** + * wma_post_vdev_create_setup() - Post vdev create setup + * @vdev: vdev obj + * + * This API is invoked after vded is created to perform post + * vdev create operations i.e. creating peer and setting vdev params. + * + * Return: SUCCESS on successful post vdev operations, FAILURE, if it + * fails due to any + */ +QDF_STATUS wma_post_vdev_create_setup(struct wlan_objmgr_vdev *vdev); + +/** + * wma_vdev_create_set_param() - vdev_create_set_param + * @vdev: vdev obj + * + * This API is invoked after vdev is created to perform post + * vdev create operations i.e. creating peer and setting vdev params. + * + * Return: SUCCESS on successful post vdev operations, FAILURE, if it + * fails due to any + */ +QDF_STATUS wma_vdev_create_set_param(struct wlan_objmgr_vdev *vdev); + +/** + * wma_send_multi_pdev_vdev_set_params - sends dev(vdev/pdev) set params + * @param_type: enum of type mlme_dev_setparam + * @dev_id: id of the particular vdev/pdev + * @param: Array of structure dev_set_param with @n_params combined + * @n_params: number of params that are combined in @param + * + * Return: SUCCESS on successful post vdev operations, FAILURE, if it + * fails due to any + */ +QDF_STATUS +wma_send_multi_pdev_vdev_set_params(enum mlme_dev_setparam param_type, + uint8_t dev_id, + struct dev_set_param *param, + uint8_t n_params); + +/** + * wma_validate_txrx_chain_mask - validates tx/rx chain mask set params + * @paramid: paramid of chainmask + * @paramvalue: param value + * + * Return: SUCCESS on successful post vdev operations, FAILURE, if it + * fails due to any + */ +QDF_STATUS +wma_validate_txrx_chain_mask(uint32_t paramid, uint32_t paramvalue); + +/** + * wma_vdev_set_data_tx_callback() - Set dp vdev tx callback + * @vdev: vdev obj + * + * This API is used to set dp dev tx callback. + * + * Return: SUCCESS on successful post vdev operations, FAILURE, if it + * fails due to any + */ +QDF_STATUS wma_vdev_set_data_tx_callback(struct wlan_objmgr_vdev *vdev); + +/** + * wma_mon_mlme_vdev_start_continue() - VDEV start response handling + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV start response actions + * + * Return: SUCCESS on successful completion of start response operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_mon_mlme_vdev_up_send() - Send VDEV UP command + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV UP Command + * + * Return: SUCCESS on successful completion of start response operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_mon_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_mon_mlme_vdev_stop_send() - VDEV stop operation + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV stop operation + * + * Return: SUCCESS on successful completion of VDEV stop operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_mon_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_mon_mlme_vdev_down_send() - VDEV down operation + * @vdev_mlme: VDEV MLME comp object + * @data_len: data size + * @data: event data + * + * API invokes VDEV down operation + * + * Return: SUCCESS on successful completion of VDEV down operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_mon_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data); + +/** + * wma_vdev_detach_callback() - VDEV delete response handler + * @rsp: pointer to vdev delete response + * + * This API processes vdev delete response and gives to upper layers + * + * Return: SUCCESS on successful completion of VDEV delete operation + * FAILURE, if it fails due to any + */ +QDF_STATUS wma_vdev_detach_callback(struct vdev_delete_response *rsp); + +/** + * wma_vdev_stop_resp_handler() - vdev stop response handler + * @vdev_mlme: vdev mlme obj + * @rsp: vdev stup response + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_vdev_stop_resp_handler(struct vdev_mlme_obj *vdev_mlme, + struct vdev_stop_response *rsp); + +/** + * wma_vdev_start_resp_handler() - vdev start response handler + * @vdev_mlme: vdev mlme obj + * @rsp: vdev start response + * + * Return: QDF status + */ +QDF_STATUS wma_vdev_start_resp_handler(struct vdev_mlme_obj *vdev_mlme, + struct vdev_start_response *rsp); + +#ifdef FEATURE_WLM_STATS +/** + * typedef wma_wlm_stats_cb() - Callback function for WLM stats + * @cookie: Cookie provided by client during callback registration + * @data: Hex ASCII representation of the WLM stats + */ +typedef void (*wma_wlm_stats_cb)(void *cookie, const char *data); + +/** + * wma_wlm_stats_req() - Send a req to WLAN Latency Manager in FW + * @vdev_id: vdev id to be sent to FW's WLM + * @bitmask: A bitmask which is requested by user to be sent to FW's WLM + * @max_size: Size of user's buffer to store the response + * @cb: A callback to be called to once response is available + * @cookie: A cookie to be used by callback to retrieve the context of req + * + * This API is used to send a message to WLAN latency manager component + * in FW to retrieve some latency related data and send it to user space. + * Driver is just a pass-through for user to interact with FW. + * + * Return: 0 on success and non-zero for error + */ +int wma_wlm_stats_req(int vdev_id, uint32_t bitmask, uint32_t max_size, + wma_wlm_stats_cb cb, void *cookie); + +/** + * wma_wlm_stats_rsp() - Handler to handle the response from FW's WLM component + * @wma_ctx: WMA context + * @event: WMI TLV event data + * @len: WMI TLV length + * + * This API is registered with WMI component in order to handle the response + * coming from FW's WLM correspondence to WLM REQ to FW. This API takes the + * data coming as HEX stream and write in to CHAR buffer as HEX CHAR stream + * and send this char buffer to user space through callback. + * + * Return: 0 on success and non-zero for error + */ +int wma_wlm_stats_rsp(void *wma_ctx, uint8_t *event, uint32_t len); +#endif /* FEATURE_WLM_STATS */ + +/** + * wma_vdev_self_peer_create() - create self peer in objmgr + * @vdev_mlme: vdev mlme component private object + * + * Create the self peer in firmware for beaconing vdev's and create then + * object manager self-peer for the vdev. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_vdev_self_peer_create(struct vdev_mlme_obj *vdev_mlme); + +/** + * wma_cleanup_vdev() - cleanup wma layers vdev + * @vdev: Object manager vdev + * + * This function cleansup the wma layers vdev related data. + * + * Return: None + */ +void wma_cleanup_vdev(struct wlan_objmgr_vdev *vdev); + +/** + * wma_set_wakeup_logs_to_console() - Enable/disable wakeup logs to console + * @value: boolean value + * + * API to enable/disable wow host wakeup event logs to console. + * + * Return: None + */ +void wma_set_wakeup_logs_to_console(bool value); +#endif /* WMA_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_coex.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_coex.h new file mode 100644 index 0000000000..33ff1fd4d5 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_coex.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _WLAN_HDD_DEBUGFS_COEX_H +#define _WLAN_HDD_DEBUGFS_COEX_H + +#include +#include "sme_api.h" + +#ifdef WLAN_MWS_INFO_DEBUGFS +void wma_get_mws_coex_info_req(tp_wma_handle wma_handle, + struct sir_get_mws_coex_info *req); +void wma_register_mws_coex_events(tp_wma_handle wma_handle); +#else +static void wma_register_mws_coex_events(tp_wma_handle wma_handle) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_fw_state.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_fw_state.h new file mode 100644 index 0000000000..d508cb0fb0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_fw_state.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_fw_state.h + * + * Get firmware state related API's and definitions + */ + +#ifndef __WMA_FW_STATE_H +#define __WMA_FW_STATE_H + +#include "wma.h" + +#ifdef FEATURE_FW_STATE +/** + * wma_get_fw_state() - send wmi cmd to get fw state + * @wma_handle: wma handler + * + * Return: Return QDF_STATUS + */ +QDF_STATUS wma_get_fw_state(tp_wma_handle wma_handle); +void wma_register_fw_state_events(wmi_unified_t wmi_handle); +#else /* FEATURE_FW_STATE */ +static inline +void wma_register_fw_state_events(WMA_HANDLE wma_handle) +{ +} +#endif /* FEATURE_FW_STATE */ +#endif /* __WMA_FW_STATE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_he.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_he.h new file mode 100644 index 0000000000..c6e64357bd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_he.h @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_HE_H +#define __WMA_HE_H + +#include "wma.h" +#include "sir_api.h" +#include "target_if.h" + +/* Number of bits to shift on HE MCS 12 13 MAP to get the desired map */ +#define WMA_MCS_12_13_MAP_L80 16 +#define WMA_MCS_12_13_MAP_G80 8 + +/* Mask to fill tx and rx mcs rate maps to be sent to the FW */ +#define WMA_MCS_12_13_PEER_RATE_MAP 0x00ff0000 + +#ifdef WLAN_FEATURE_11AX +/** + * wma_print_he_cap() - Print HE capabilities + * @he_cap: pointer to HE Capability + * + * Received HE capabilities are converted into dot11f structure. + * This function will print all the HE capabilities as stored + * in the dot11f structure. + * + * Return: None + */ +void wma_print_he_cap(tDot11fIEhe_cap *he_cap); + +/** + * wma_print_he_ppet() - Prints HE PPE Threshold + * @he_ppet: PPE Threshold + * + * This function prints HE PPE Threshold as received from FW. + * Refer to the definition of wmi_ppe_threshold to understand + * how PPE thresholds are packed by FW for a given NSS and RU. + * + * Return: none + */ +void wma_print_he_ppet(void *ppet); + +/** + * wma_print_he_phy_cap() - Print HE PHY Capability + * @phy_cap: pointer to PHY Capability + * + * This function prints HE PHY Capability received from FW. + * + * Return: none + */ +void wma_print_he_phy_cap(uint32_t *phy_cap); + +/** + * wma_print_he_mac_cap_w1() - Print HE MAC Capability + * @mac_cap: MAC Capability + * + * This function prints HE MAC Capability received from FW. + * + * Return: none + */ +void wma_print_he_mac_cap_w1(uint32_t mac_cap); + +/** + * wma_print_he_mac_cap_w2() - Print HE MAC Capability + * @mac_cap: MAC Capability + * + * This function prints HE MAC Capability received from FW. + * + * Return: none + */ +void wma_print_he_mac_cap_w2(uint32_t mac_cap); + +/** + * wma_print_he_op() - Print HE Operation + * @he_cap: pointer to HE Operation + * + * Print HE operation stored as dot11f structure + * + * Return: None + */ +void wma_print_he_op(tDot11fIEhe_op *he_ops); + +/** + * wma_update_target_ext_he_cap() - Update HE caps with given extended cap + * @tgt_hdl: target psoc information + * @tgt_cfg: Target config + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * HE caps and derives the final cap. + * + * Return: None + */ +void wma_update_target_ext_he_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg); + +/* + * wma_he_update_tgt_services() - update tgt cfg to indicate 11ax support + * @wmi_handle: pointer to WMI handle + * @cfg: pointer to WMA target services + * + * Based on WMI SERVICES information, enable 11ax support and set DOT11AX bit + * in feature caps bitmap. + * + * Return: None + */ +void wma_he_update_tgt_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg); + +/** + * wma_populate_peer_he_cap() - populate peer HE capabilities in peer assoc cmd + * @peer: pointer to peer assoc params + * @params: pointer to ADD STA params + * + * Return: None + */ +void wma_populate_peer_he_cap(struct peer_assoc_params *peer, + tpAddStaParams params); + +/** + * wma_update_vdev_he_ops() - update he ops in vdev start request + * @he_ops: target he ops + * @he_op: source he ops + * + * Return: None + */ +void wma_update_vdev_he_ops(uint32_t *he_ops, tDot11fIEhe_op *he_op); + +#define DOT11AX_HEMU_MODE 0x30 +#define HE_SUBFEE 0 +#define HE_SUBFER 1 +#define HE_MUBFEE 2 +#define HE_MUBFER 3 + +/** + * wma_get_hemu_mode() - get hemu mode + * @hemumode: pointer to have hemumode + * @mac: pointer to mac context + * + * Return: Success on proper hemumode else failure + */ +QDF_STATUS wma_get_hemu_mode(uint32_t *hemumode, struct mac_context *mac); + +/** + * wma_set_he_txbf_params() - set HE Tx beamforming params to FW + * @vdev_id: VDEV id + * @su bfer: SU beamformer capability + * @su bfee: SU beamformee capability + * @mu bfer: MU beamformer capability + * + * Return: None + */ +void wma_set_he_txbf_params(uint8_t vdev_id, bool su_bfer, + bool su_bfee, bool mu_bfer); + + +/** + * wma_set_he_txbf_cfg() - set HE Tx beamforming mlme cfg to FW + * @mac: Global MAC context + * @vdev_id: VDEV id + * + * Return: None + */ +void wma_set_he_txbf_cfg(struct mac_context *mac, uint8_t vdev_id); +/** + * wma_vdev_set_he_bss_params() - set HE OPs in vdev start + * @wma: pointer to wma handle + * @vdev_id: VDEV id + * @he_info: pointer to he info + * + * Return: None + */ +void wma_vdev_set_he_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct vdev_mlme_he_ops_info *he_info); + +/** + * wma_vdev_set_he_config() - set HE Config in vdev start + * @wma: pointer to wma handle + * @vdev_id: VDEV id + * @add_bss: BSS params + * + * Return: None + */ +void wma_vdev_set_he_config(tp_wma_handle wma, uint8_t vdev_id, + struct bss_params *add_bss); + +static inline bool wma_is_peer_he_capable(tpAddStaParams params) +{ + return params->he_capable; +} + +/** + * wma_update_he_ops_ie() - update the HE OPS IE to firmware + * @wma: pointer to wma context + * @vdev_id: vdev id + * @he_ops: 32bit value of HE ops + * + * This API is used to send updated HE operational IE to firmware, so that + * firmware can be in sync with host + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_update_he_ops_ie(tp_wma_handle wma, uint8_t vdev_id, + tDot11fIEhe_op *he_ops); + +/** + * wma_get_he_capabilities() - Get HE capabilities from WMA + * @he_cap: Pointer to HE capabilities + * + * Currently HE capabilities are not updated in wma_handle. This + * is an interface for upper layer to query capabilities from WMA. + * When the real use case arise, update wma_handle with HE capabilities + * as required. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_get_he_capabilities(struct he_capability *he_cap); + +/** + * wma_set_he_vdev_param() - update he vdev param in wma + * @intr: pointer to wma_txrx_node + * @param_id: vdev param id + * @value: value of vdev param + * + * Result: None + */ +void wma_set_he_vdev_param(struct wma_txrx_node *intr, + wmi_conv_vdev_param_id param_id, + uint32_t value); + +/** + * wma_get_he_vdev_param() - retrieve he vdev param from wma + * @intr: pointer to wma_txrx_node + * @param_id: vdev param id + * + * Result: param value + */ +uint32_t wma_get_he_vdev_param(struct wma_txrx_node *intr, + wmi_conv_vdev_param_id param_id); + +/** + * wma_prevent_suspend_on_obss_color_collision() - prevent suspend on obss color + * collision + * @vdev: pointer to vdev object + * + * Return: none + */ +void wma_prevent_suspend_on_obss_color_collision(struct wlan_objmgr_vdev *vdev); + +/** + * wma_allow_suspend_after_obss_color_change() - allow suspend on obss color + * change + * @vdev: pointer to vdev object + * + * Return: none + */ +void wma_allow_suspend_after_obss_color_change(struct wlan_objmgr_vdev *vdev); +#else +static inline void wma_print_he_cap(tDot11fIEhe_cap *he_cap) +{ +} + +static inline void wma_print_he_ppet(void *ppet) +{ +} + +static inline void wma_print_he_phy_cap(uint32_t *phy_cap) +{ +} + +static inline void wma_print_he_mac_cap_w1(uint32_t mac_cap) +{ +} + +static inline void wma_print_he_mac_cap_w2(uint32_t mac_cap) +{ +} + +static inline void wma_print_he_op(tDot11fIEhe_op *he_ops) +{ +} + +static inline void wma_update_target_ext_he_cap(struct + target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg) +{ +} + +static inline void wma_he_update_tgt_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_11ax = false; + return; +} + +static inline void wma_populate_peer_he_cap(struct peer_assoc_params *peer, + tpAddStaParams params) +{ +} + +static inline +void wma_update_vdev_he_ops(uint32_t *he_ops, tDot11fIEhe_op *he_op) +{ +} + +static inline QDF_STATUS wma_get_hemu_mode(uint32_t *hemumode, + struct mac_context *mac) +{ + return QDF_STATUS_E_FAILURE; +} + +static inline void wma_set_he_txbf_params(uint8_t vdev_id, bool su_bfer, + bool su_bfee, bool mu_bfer) +{ +} + +static inline void wma_set_he_txbf_cfg(struct mac_context *mac, uint8_t vdev_id) +{ +} + +static inline QDF_STATUS wma_update_he_ops_ie(tp_wma_handle wma, + uint8_t vdev_id, tDot11fIEhe_op *he_ops) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void wma_vdev_set_he_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct vdev_mlme_he_ops_info *he_info) +{ +} + +static inline void wma_vdev_set_he_config(tp_wma_handle wma, uint8_t vdev_id, + struct bss_params *add_bss) +{ +} + +static inline bool wma_is_peer_he_capable(tpAddStaParams params) +{ + return false; +} + +static inline void wma_set_he_vdev_param(struct wma_txrx_node *intr, + wmi_conv_vdev_param_id param_id, uint32_t value) +{ +} + +static inline uint32_t wma_get_he_vdev_param(struct wma_txrx_node *intr, + wmi_conv_vdev_param_id param_id) +{ + return 0; +} + +static inline void wma_prevent_suspend_on_obss_color_collision( + struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void wma_allow_suspend_after_obss_color_change( + struct wlan_objmgr_vdev *vdev) +{ +} +#endif + +#endif /* __WMA_HE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_if.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_if.h new file mode 100644 index 0000000000..abc132a5e0 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_if.h @@ -0,0 +1,801 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _HALMSGAPI_H_ +#define _HALMSGAPI_H_ + +#include "qdf_types.h" +#include "sir_api.h" +#include "sir_params.h" + +/* + * Validate the OS Type being built + */ + +#if defined(ANI_OS_TYPE_ANDROID) /* ANDROID */ + +#if defined(ANI_OS_TYPE_QNX) +#error "more than one ANI_OS_TYPE_xxx is defined for this build" +#endif + +#elif defined(ANI_OS_TYPE_QNX) /* QNX */ + +#if defined(ANI_OS_TYPE_ANDROID) +#error "more than one ANI_OS_TYPE_xxx is defined for this build" +#endif + +#elif !defined(ANI_OS_TYPE_ANDROID) && !defined(ANI_OS_TYPE_QNX) /* NONE */ +#error "NONE of the ANI_OS_TYPE_xxx are defined for this build" +#endif + +/* operMode in ADD BSS message */ +#define BSS_OPERATIONAL_MODE_AP 0 +#define BSS_OPERATIONAL_MODE_STA 1 +#define BSS_OPERATIONAL_MODE_IBSS 2 +#define BSS_OPERATIONAL_MODE_NDI 3 + +/* STA entry type in add sta message */ +#define STA_ENTRY_SELF 0 +#define STA_ENTRY_OTHER 1 +#define STA_ENTRY_BSSID 2 +/* Special station id for transmitting broadcast frames. */ +#define STA_ENTRY_BCAST 3 +#define STA_ENTRY_PEER STA_ENTRY_OTHER +#define STA_ENTRY_TDLS_PEER 4 +#ifdef FEATURE_WLAN_TDLS +#define IS_TDLS_PEER(type) ((type) == STA_ENTRY_TDLS_PEER) +#else /* !FEATURE_WLAN_TDLS */ +#define IS_TDLS_PEER(type) false +#endif /* FEATURE_WLAN_TDLS */ +#define STA_ENTRY_NDI_PEER 5 + +#define STA_INVALID_IDX 0xFF + +/* invalid channel id. */ +#define INVALID_CHANNEL_ID 0 + +/** + * enum eFrameType - frame types + * @TXRX_FRM_RAW: raw frame + * @TXRX_FRM_ETH2: ethernet frame + * @TXRX_FRM_802_3: 802.3 frame + * @TXRX_FRM_802_11_MGMT: 802.11 mgmt frame + * @TXRX_FRM_802_11_CTRL: 802.11 control frame + * @TXRX_FRM_802_11_DATA: 802.11 data frame + */ +typedef enum { + TXRX_FRM_RAW, + TXRX_FRM_ETH2, + TXRX_FRM_802_3, + TXRX_FRM_802_11_MGMT, + TXRX_FRM_802_11_CTRL, + TXRX_FRM_802_11_DATA, + TXRX_FRM_IGNORED, /* This frame will be dropped */ + TXRX_FRM_MAX +} eFrameType; + +/** + * enum eFrameTxDir - frame tx direction + * @ANI_TXDIR_IBSS: IBSS frame + * @ANI_TXDIR_TODS: frame to DS + * @ANI_TXDIR_FROMDS: Frame from DS + * @ANI_TXDIR_WDS: WDS frame + */ +typedef enum { + ANI_TXDIR_IBSS = 0, + ANI_TXDIR_TODS, + ANI_TXDIR_FROMDS, + ANI_TXDIR_WDS +} eFrameTxDir; + +/** + *struct sAniBeaconStruct - Beacon structure + * @beaconLength: beacon length + * @macHdr: mac header for beacon + */ +typedef struct sAniBeaconStruct { + uint32_t beaconLength; + tSirMacMgmtHdr macHdr; +} qdf_packed tAniBeaconStruct, *tpAniBeaconStruct; + +/** + * struct sAniProbeRspStruct - probeRsp template structure + * @macHdr: mac header for probe response + */ +struct sAniProbeRspStruct { + tSirMacMgmtHdr macHdr; + /* probeRsp body follows here */ +} qdf_packed; + +/** + * med_sync_delay - medium sync delay info + * @med_sync_duration: medium sync duration + * @med_sync_ofdm_ed_thresh: medium sync OFDM ED threshold + * @med_sync_max_txop_num: medium sync max txop num + */ +struct med_sync_delay { + uint16_t med_sync_duration:8; + uint16_t med_sync_ofdm_ed_thresh:4; + uint16_t med_sync_max_txop_num:4; +}; + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * struct ml_partner_link_info: partner link info + * @link_id: partner link ID + * @link_addr: partner link address + * @ch_freq:Channel in Mhz + * @ch_phymode: Channel phymode + */ +struct ml_partner_link_info { + uint8_t vdev_id; + uint8_t link_id; + struct qdf_mac_addr link_addr; + struct qdf_mac_addr self_mac_addr; + struct wlan_channel channel_info; +}; + +struct peer_ml_info { + uint32_t vdev_id; + uint32_t link_id; + struct qdf_mac_addr link_addr; + struct wlan_channel channel_info; + struct qdf_mac_addr self_mac_addr; + uint8_t num_links; + struct ml_partner_link_info partner_info[MLD_MAX_LINKS - 1]; + uint8_t rec_max_simultaneous_links; +}; +#endif + +/** + * struct tAddStaParams - add sta related parameters + * @bssId: bssid of sta + * @assocId: associd + * @staType: 0 - Self, 1 other/remote, 2 - bssid + * @staMac: MAC Address of STA + * @listenInterval: Listen interval + * @wmmEnabled: Support for 11e/WMM + * @uAPSD: U-APSD Flags: 1b per AC + * @maxSPLen: Max SP Length + * @htCapable: 11n HT capable STA + * @txChannelWidthSet: TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz + * @mimoPS: MIMO Power Save + * @maxAmpduDensity: 3 : 0~7 : 2^(11nAMPDUdensity -4) + * @maxAmsduSize: 1 : 3839 bytes, 0 : 7935 bytes + * @fShortGI40Mhz: short GI support for 40Mhz packets + * @fShortGI20Mhz: short GI support for 20Mhz packets + * @supportedRates: legacy supported rates + * @status: QDF status + * @staIdx: station index + * @updateSta: pdate the existing STA entry, if this flag is set + * @rmfEnabled: Robust Management Frame (RMF) enabled/disabled + * @encryptType: The unicast encryption type in the association + * @sessionId: PE session id + * @p2pCapableSta: if this is a P2P Capable Sta + * @csaOffloadEnable: CSA offload enable flag + * @vhtCapable: is VHT capabale or not + * @vhtTxChannelWidthSet: VHT channel width + * @vhtSupportedRxNss: VHT supported RX NSS + * @vhtTxBFCapable: txbf capable or not + * @vhtTxMUBformeeCapable: Bformee capable or not + * @enableVhtpAid: enable VHT AID + * @enableAmpduPs: AMPDU power save + * @enableHtSmps: enable HT SMPS + * @htSmpsconfig: HT SMPS config + * @htLdpcCapable: HT LDPC capable + * @vhtLdpcCapable: VHT LDPC capable + * @vht_mcs_10_11_supp: VHT MCS 10 & 11 support + * @smesessionId: sme session id + * @wpa_rsn: RSN capable + * @capab_info: capabality info + * @ht_caps: HT capabalities + * @vht_caps: VHT vapabalities + * @nwType: NW Type + * @maxTxPower: max tx power + * @nss: Return the number of spatial streams supported + * @stbc_capable: stbc capable + * @no_ptk_4_way: Do not need 4-way handshake + * @eht_capable: is EHT capabale or not + * @eht_config: EHT capability + * @eht_op: EHT operation + * @mld_mac_addr: mld mac address + * @is_assoc_peer: is assoc peer or not + * @emlsr_support: is EMLSR mode supported or not + * @msd_caps_present: is MSD capability present in MLO IE or not + * @link_id: per link id + * @emlsr_trans_timeout: EMLSR transition timeout value + * + * This structure contains parameter required for + * add sta request of upper layer. + */ +typedef struct { + tSirMacAddr bssId; + uint16_t assocId; + /* Field to indicate if this is sta entry for itself STA adding entry + * for itself or remote (AP adding STA after successful association. + * This may or may not be required in production driver. + */ + uint8_t staType; + tSirMacAddr staMac; + uint16_t listenInterval; + uint8_t wmmEnabled; + uint8_t uAPSD; + uint8_t maxSPLen; + uint8_t htCapable; + enum phy_ch_width ch_width; + tSirMacHTMIMOPowerSaveState mimoPS; + uint8_t maxAmpduSize; + uint8_t maxAmpduDensity; + /* 11n Parameters */ + /* HT STA should set it to 1 if it is enabled in BSS + * HT STA should set it to 0 if AP does not support it. + * This indication is sent to HAL and HAL uses this flag + * to pickup up appropriate 40Mhz rates. + */ + uint8_t fShortGI40Mhz; + uint8_t fShortGI20Mhz; + struct supported_rates supportedRates; + /* + * Following parameters are for returning status and station index from + * HAL to PE via response message. HAL does not read them. + */ + /* The return status of SIR_HAL_ADD_STA_REQ is reported here */ + QDF_STATUS status; + uint8_t updateSta; + uint8_t rmfEnabled; + uint32_t encryptType; + uint8_t sessionId; + uint8_t p2pCapableSta; + uint8_t csaOffloadEnable; + uint8_t vhtCapable; + uint8_t vhtSupportedRxNss; + uint8_t vht_160mhz_nss; + uint8_t vht_80p80mhz_nss; + uint8_t vht_extended_nss_bw_cap; + uint8_t vhtTxBFCapable; + uint8_t enable_su_tx_bformer; + uint8_t vhtTxMUBformeeCapable; + uint8_t enableVhtpAid; + uint8_t enableAmpduPs; + uint8_t enableHtSmps; + uint8_t htSmpsconfig; + bool send_smps_action; + uint8_t htLdpcCapable; + uint8_t vhtLdpcCapable; + uint8_t vht_mcs_10_11_supp; + uint8_t smesessionId; + uint8_t wpa_rsn; + uint16_t capab_info; + uint16_t ht_caps; + uint32_t vht_caps; + tSirNwType nwType; + int8_t maxTxPower; + uint8_t nonRoamReassoc; + uint32_t nss; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + tDot11fIEhe_cap he_config; + tDot11fIEhe_op he_op; + tDot11fIEhe_6ghz_band_cap he_6ghz_band_caps; + uint16_t he_mcs_12_13_map; +#endif + uint8_t stbc_capable; +#ifdef WLAN_SUPPORT_TWT + uint8_t twt_requestor; + uint8_t twt_responder; +#endif + bool no_ptk_4_way; +#ifdef WLAN_FEATURE_11BE + bool eht_capable; + tDot11fIEeht_cap eht_config; + tDot11fIEeht_op eht_op; +#endif + struct med_sync_delay msd_caps; +#ifdef WLAN_FEATURE_11BE_MLO + uint8_t mld_mac_addr[QDF_MAC_ADDR_SIZE]; + bool is_assoc_peer; + bool emlsr_support; + bool msd_caps_present; + uint8_t link_id; + uint16_t emlsr_trans_timeout; + struct ml_partner_link_info ml_partner_info[MLD_MAX_LINKS - 1]; + struct peer_ml_info ml_info; +#endif +} tAddStaParams, *tpAddStaParams; + +/** + * struct tDeleteStaParams - parameters required for del sta request + * @assocId: association index + * @status: status + * @respReqd: is response required + * @sessionId: PE session id + * @smesessionId: SME session id + * @staType: station type + * @staMac: station mac + */ +typedef struct { + uint16_t assocId; + QDF_STATUS status; + uint8_t respReqd; + uint8_t sessionId; + uint8_t smesessionId; + uint8_t staType; + tSirMacAddr staMac; +} tDeleteStaParams, *tpDeleteStaParams; + +/** + * struct tSetStaKeyParams - set key params + * @encType: encryption type + * @defWEPIdx: Default WEP key, valid only for static WEP, must between 0 and 3 + * @singleTidRc: 1=Single TID based Replay Count, 0=Per TID based RC + * @vdev_id: vdev_id + * @peerMacAddr: peer mac address + * @status: status + * @macaddr: MAC address of the peer + * @key_len: key len + * + * This is used by PE to configure the key information on a given station. + * When the secType is WEP40 or WEP104, the defWEPIdx is used to locate + * a preconfigured key from a BSS the station associated with; otherwise + * a new key descriptor is created based on the key field. + */ +typedef struct { + tAniEdType encType; + uint8_t defWEPIdx; + uint8_t singleTidRc; + uint8_t vdev_id; + struct qdf_mac_addr peer_macaddr; + QDF_STATUS status; + uint8_t sendRsp; + struct qdf_mac_addr macaddr; + uint16_t key_len; +} tSetStaKeyParams, *tpSetStaKeyParams; + +/** + * struct bss_params - parameters required for add bss params + * @bssId: MAC Address/BSSID + * @nwType: network type + * @shortSlotTimeSupported: is short slot time supported or not + * @llbCoexist: 11b coexist supported or not + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @htCapable: Enable/Disable HT capabilities + * @rmfEnabled: RMF enabled/disabled + * @staContext: sta context + * @updateBss: update the existing BSS entry, if this flag is set + * @maxTxPower: max power to be used after applying the power constraint + * @bSpectrumMgtEnabled: Spectrum Management Capability, 1:Enabled, 0:Disabled. + * @vhtCapable: VHT capability + * @ch_width: VHT tx channel width + * @he_capable: HE Capability + * @no_ptk_4_way: Do not need 4-way handshake + * @eht_capable: EHT capability + */ +struct bss_params { + tSirMacAddr bssId; + tSirNwType nwType; + uint8_t shortSlotTimeSupported; + uint8_t llbCoexist; + tSirMacBeaconInterval beaconInterval; + uint8_t dtimPeriod; + uint8_t htCapable; + uint8_t rmfEnabled; + tAddStaParams staContext; + /* HAL should update the existing BSS entry, if this flag is set. + * PE will set this flag in case of reassoc, where we want to reuse the + * the old bssID and still return success. + */ + uint8_t updateBss; + int8_t maxTxPower; + uint8_t vhtCapable; + enum phy_ch_width ch_width; + uint8_t nonRoamReassoc; +#ifdef WLAN_FEATURE_11AX + bool he_capable; + uint32_t he_sta_obsspd; +#endif + bool no_ptk_4_way; + uint16_t bss_max_idle_period; +#ifdef WLAN_FEATURE_11BE + bool eht_capable; +#endif +}; + +/** + * struct add_bss_rsp - params required for add bss response + * @vdev_id: vdev_id + * @status: QDF status + * @chain_mask: chain mask vdev start resp + * @smps_mode: smps mode in vdev start resp + */ +struct add_bss_rsp { + uint8_t vdev_id; + QDF_STATUS status; + uint32_t chain_mask; + uint8_t smps_mode; +}; + +typedef enum eDelStaReasonCode { + HAL_DEL_STA_REASON_CODE_KEEP_ALIVE = 0x1, + HAL_DEL_STA_REASON_CODE_TIM_BASED = 0x2, + HAL_DEL_STA_REASON_CODE_RA_BASED = 0x3, + HAL_DEL_STA_REASON_CODE_UNKNOWN_A2 = 0x4, + HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT = 0x5, + HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT = 0x6, + HAL_DEL_STA_REASON_CODE_XRETRY = 0x7, +} tDelStaReasonCode; + +typedef enum eSmpsModeValue { + STATIC_SMPS_MODE = 0x0, + DYNAMIC_SMPS_MODE = 0x1, + SMPS_MODE_RESERVED = 0x2, + SMPS_MODE_DISABLED = 0x3 +} tSmpsModeValue; + +/** + * struct tDeleteStaContext - params required for delete sta request + * @assocId: association id + * @bssId: mac address + * @addr2: mac address + * @reasonCode: reason code + * @rssi: rssi value during disconnection + */ +typedef struct { + bool is_tdls; + uint8_t vdev_id; + uint16_t assocId; + tSirMacAddr bssId; + tSirMacAddr addr2; + uint16_t reasonCode; + int8_t rssi; +} tDeleteStaContext, *tpDeleteStaContext; + +#ifdef FEATURE_OEM_DATA_SUPPORT + +#ifndef OEM_DATA_RSP_SIZE +#define OEM_DATA_RSP_SIZE 1724 +#endif + +/** + * struct tStartOemDataRsp - start OEM Data response + * @target_rsp: Indicates if the rsp is from Target or WMA generated. + * @rsp_len: oem data response length + * @oem_data_rsp: pointer to OEM Data response + */ +typedef struct { + bool target_rsp; + uint32_t rsp_len; + uint8_t *oem_data_rsp; +} tStartOemDataRsp, *tpStartOemDataRsp; +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +/** + * struct beacon_gen_params - params required for beacon gen request + * @bssdd: BSSID for which it is time to generate a beacon + */ +struct beacon_gen_params { + tSirMacAddr bssid; +}; + +/** + * struct tSendbeaconParams - send beacon parameters + * vdev_id: vdev id + * @bssId: BSSID mac address + * @beacon: beacon data + * @beaconLength: beacon length of template + * @timIeOffset: TIM IE offset + * @p2pIeOffset: P2P IE offset + * @csa_count_offset: Offset of Switch count field in CSA IE + * @ecsa_count_offset: Offset of Switch count field in ECSA IE + * @reason: bcn update reason + * @status: beacon send status + */ +typedef struct { + uint8_t vdev_id; + tSirMacAddr bssId; + uint8_t beacon[SIR_MAX_BEACON_SIZE]; + uint32_t beaconLength; + uint32_t timIeOffset; + uint16_t p2pIeOffset; + uint32_t csa_count_offset; + uint32_t ecsa_count_offset; + enum sir_bcn_update_reason reason; + QDF_STATUS status; +#ifdef WLAN_FEATURE_11BE_MLO + struct mlo_bcn_templ_partner_links mlo_partner; +#endif +} tSendbeaconParams, *tpSendbeaconParams; + +/** + * struct tSendProbeRespParams - send probe response parameters + * @bssId: BSSID + * @probeRespTemplate: probe response template + * @probeRespTemplateLen: probe response template length + * @ucProxyProbeReqValidIEBmap: valid IE bitmap + * @go_ignore_non_p2p_probe_req: go ignore non-p2p probe req + */ +typedef struct sSendProbeRespParams { + tSirMacAddr bssId; + uint8_t probeRespTemplate[SIR_MAX_PROBE_RESP_SIZE]; + uint32_t probeRespTemplateLen; + uint32_t ucProxyProbeReqValidIEBmap[8]; + bool go_ignore_non_p2p_probe_req; +} tSendProbeRespParams, *tpSendProbeRespParams; + +/** + * struct tSetBssKeyParams - BSS key parameters + * @vdev_id: vdev id id + * @status: return status of command + * @macaddr: MAC address of the peer + * @key_len: key len + */ +typedef struct { + uint8_t vdev_id; + QDF_STATUS status; + struct qdf_mac_addr macaddr; + uint16_t key_len; +} tSetBssKeyParams, *tpSetBssKeyParams; + +/** + * struct tUpdateBeaconParams - update beacon request parameters + * @bss_idx: BSSID index + * @fShortPreamble: shortPreamble mode + * @fShortSlotTime: short Slot time + * @beaconInterval: Beacon Interval + * @llaCoexist: 11a coexist + * @llbCoexist: 11b coexist + * @llgCoexist: 11g coexist + * @ht20MhzCoexist: HT 20MHz coexist + * @fLsigTXOPProtectionFullSupport: TXOP protection supported or not + * @fRIFSMode: RIFS mode + * @paramChangeBitmap: change bitmap + * @vdev_id: vdev_id + */ +typedef struct { + uint8_t bss_idx; + uint8_t fShortPreamble; + uint8_t fShortSlotTime; + uint16_t beaconInterval; + uint8_t llaCoexist; + uint8_t llbCoexist; + uint8_t llgCoexist; + uint8_t ht20MhzCoexist; + uint8_t llnNonGFCoexist; + uint8_t fLsigTXOPProtectionFullSupport; + uint8_t fRIFSMode; + uint16_t paramChangeBitmap; + uint8_t vdev_id; + uint32_t bss_color; + bool bss_color_disabled; +} tUpdateBeaconParams, *tpUpdateBeaconParams; + +/** + * struct tUpdateVHTOpMode - VHT operating mode + * @opMode: VHT operating mode + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint16_t opMode; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateVHTOpMode, *tpUpdateVHTOpMode; + +/** + * struct tUpdateRxNss - update rx nss parameters + * @rxNss: rx nss value + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint16_t rxNss; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateRxNss, *tpUpdateRxNss; + +/** + * struct tUpdateMembership - update membership parameters + * @membership: membership value + * @staId: station id + * @smesessionId: SME session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t membership; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateMembership, *tpUpdateMembership; + +/** + * struct tUpdateUserPos - update user position parameters + * @userPos: user position + * @staId: station id + * @smesessionId: sme session id + * @peer_mac: peer mac address + */ +typedef struct { + uint32_t userPos; + uint16_t smesessionId; + tSirMacAddr peer_mac; +} tUpdateUserPos, *tpUpdateUserPos; + +/** + * struct tEdcaParams - EDCA parameters + * @vdev_id: vdev id + * @acbe: best effort access category + * @acbk: Background access category + * @acvi: video access category + * @acvo: voice access category + * @mu_edca_params: flag to indicate MU EDCA + */ +typedef struct { + uint16_t vdev_id; + tSirMacEdcaParamRecord acbe; + tSirMacEdcaParamRecord acbk; + tSirMacEdcaParamRecord acvi; + tSirMacEdcaParamRecord acvo; + bool mu_edca_params; +} tEdcaParams, *tpEdcaParams; + +/** + * struct tSetMIMOPS - MIMO power save related parameters + * @htMIMOPSState: MIMO Power Save State + * @status: response status + * @fsendRsp: send response flag + * @peerMac: peer mac address + * @sessionId: session id + */ +typedef struct sSet_MIMOPS { + tSirMacHTMIMOPowerSaveState htMIMOPSState; + QDF_STATUS status; + uint8_t fsendRsp; + tSirMacAddr peerMac; + uint8_t sessionId; +} tSetMIMOPS, *tpSetMIMOPS; + +/** + * struct tMaxTxPowerParams - Max Tx Power parameters + * @bssId: BSSID is needed to identify which session issued this request + * @selfStaMacAddr: self mac address + * @power: tx power in dbm + * @dev_mode: device mode + * Request Type = SIR_HAL_SET_MAX_TX_POWER_REQ + */ +typedef struct sMaxTxPowerParams { + struct qdf_mac_addr bssId; + struct qdf_mac_addr selfStaMacAddr; + /* In request, + * power == MaxTx power to be used. + * In response, + * power == tx power used for management frames. + */ + int8_t power; + enum QDF_OPMODE dev_mode; +} tMaxTxPowerParams, *tpMaxTxPowerParams; + +/** + * struct tMaxTxPowerPerBandParams - max tx power per band info + * @bandInfo: band info + * @power: power in dbm + */ +typedef struct sMaxTxPowerPerBandParams { + enum band_info bandInfo; + int8_t power; +} tMaxTxPowerPerBandParams, *tpMaxTxPowerPerBandParams; + +/** + * struct set_ie_param - set IE params structure + * @pdev_id: pdev id + * @ie_type: IE type + * @nss: Nss value + * @ie_len: IE length + * @ie_ptr: Pointer to IE data + * + * Holds the set pdev IE req data. + */ +struct set_ie_param { + uint8_t pdev_id; + uint8_t ie_type; + uint8_t nss; + uint8_t ie_len; + uint8_t *ie_ptr; +}; + +/** + * struct set_dtim_params - dtim params + * @session_id: SME Session ID + * @dtim_period: dtim period + */ +struct set_dtim_params { + uint8_t session_id; + uint8_t dtim_period; +}; + +#define DOT11_HT_IE 1 +#define DOT11_VHT_IE 2 + +/** + * struct del_vdev_params - Del Sta Self params + * @session_id: SME Session ID + * @status: response status code + * @vdev: Object to vdev + */ +struct del_vdev_params { + tSirMacAddr self_mac_addr; + uint8_t vdev_id; + uint32_t status; + struct wlan_objmgr_vdev *vdev; +}; + +/** + * struct del_sta_self_rsp_params - Del Sta Self response params + * @self_sta_param: sta params + * @generate_rsp: generate response to upper layers + */ +struct del_sta_self_rsp_params { + struct del_vdev_params *self_sta_param; +}; + +/** + * struct send_peer_unmap_conf_params - Send Peer Unmap Conf param + * @vdev_id: vdev ID + * @peer_id_cnt: peer_id count + * @peer_id_list: list of peer IDs + */ +struct send_peer_unmap_conf_params { + uint8_t vdev_id; + uint32_t peer_id_cnt; + uint16_t *peer_id_list; +}; + +/** + * struct peer_create_rsp_params - Peer create response parameters + * @peer_mac: Peer mac address + */ +struct peer_create_rsp_params { + struct qdf_mac_addr peer_mac; +}; + +/** + * struct tDisableIntraBssFwd - intra bss forward parameters + * @sessionId: session id + * @disableintrabssfwd: disable intra bss forward flag + */ +typedef struct sDisableIntraBssFwd { + uint16_t sessionId; + bool disableintrabssfwd; +} qdf_packed tDisableIntraBssFwd, *tpDisableIntraBssFwd; + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * struct tStatsExtRequest - ext stats request + * @vdev_id: vdev id + * @request_data_len: request data length + * @request_data: request data + */ +typedef struct sStatsExtRequest { + uint32_t vdev_id; + uint32_t request_data_len; + uint8_t request_data[]; +} tStatsExtRequest, *tpStatsExtRequest; +#endif /* WLAN_FEATURE_STATS_EXT */ + +#endif /* _HALMSGAPI_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_internal.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_internal.h new file mode 100644 index 0000000000..564c502426 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_internal.h @@ -0,0 +1,1786 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WMA_INTERNAL_H +#define WMA_INTERNAL_H +#include +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif + +/* ################### defines ################### */ +/* + * TODO: Following constant should be shared by firmware in + * wmi_unified.h. This will be done once wmi_unified.h is updated. + */ +#define WMI_PEER_STATE_AUTHORIZED 0x2 + +#define WMA_2_4_GHZ_MAX_FREQ 3000 + +/*AR9888/AR6320 noise floor approx value + * similar to the mentioned the WMA + */ +#define WMA_TGT_NOISE_FLOOR_DBM (-96) +#define WMA_INVALID_PER_CHAIN_SNR (0x80) +#define WMA_INVALID_PER_CHAIN_RSSI (0xFF) + +/* + * Make sure that link monitor and keep alive + * default values should be in sync with CFG. + */ +#define WMA_LINK_MONITOR_DEFAULT_TIME_SECS 10 +#define WMA_KEEP_ALIVE_DEFAULT_TIME_SECS 5 + +#define WMA_WMM_EXPO_TO_VAL(val) ((1 << (val)) - 1) + +#define INVALID_MCS_IDX 255 + +#define IS_MCS_HAS_DCM_RATE(val) \ + ((val) == 0 || (val) == 1 || \ + (val) == 3 || (val) == 4) + +#define LINK_STATUS_LEGACY 0 +#define LINK_STATUS_VHT 0x1 +#define LINK_STATUS_MIMO 0x2 +#define LINK_SUPPORT_VHT 0x4 +#define LINK_SUPPORT_MIMO 0x8 + +#define LINK_RATE_VHT 0x3 + +#define MAX_ENTRY_HOLD_REQ_QUEUE 2 +#define MAX_ENTRY_VDEV_RESP_QUEUE 10 + +/** + * struct index_data_rate_type - non vht data rate type + * @mcs_index: mcs rate index + * @ht20_rate: HT20 supported rate table + * @ht40_rate: HT40 supported rate table + */ +struct index_data_rate_type { + uint8_t mcs_index; + uint16_t ht20_rate[2]; + uint16_t ht40_rate[2]; +}; + +/** + * struct index_vht_data_rate_type - vht data rate type + * @mcs_index: mcs rate index + * @ht20_rate: VHT20 supported rate table + * @ht40_rate: VHT40 supported rate table + * @ht80_rate: VHT80 supported rate table + * @ht160_rate: VHT160 supported rate table + */ +struct index_vht_data_rate_type { + uint8_t mcs_index; + uint16_t ht20_rate[2]; + uint16_t ht40_rate[2]; + uint16_t ht80_rate[2]; + uint16_t ht160_rate[2]; +}; + +#ifdef WLAN_FEATURE_11AX +#define MAX_HE_DCM_INDEX 2 +/** + * struct index_he_data_rate_type - he data rate type + * @beacon_rate_index: Beacon rate index + * @supported_he80_rate: he80 rate + * @supported_he40_rate: he40 rate + * @supported_he20_rate: he20 rate + * @supported_he160_rate: he160 rate + */ +struct index_he_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_he20_rate[MAX_HE_DCM_INDEX][3]; + uint16_t supported_he40_rate[MAX_HE_DCM_INDEX][3]; + uint16_t supported_he80_rate[MAX_HE_DCM_INDEX][3]; + uint16_t supported_he160_rate[MAX_HE_DCM_INDEX][3]; +}; +#endif + +struct wifi_scan_cmd_req_params; +/* + * wma_main.c functions declarations + */ + +/** + * wma_send_msg_by_priority() - Send wma message to PE with priority. + * @wma_handle: wma handle + * @msg_type: message type + * @body_ptr: message body ptr + * @body_val: message body value + * @is_high_priority: if msg is high priority + * + * Return: none + */ +void wma_send_msg_by_priority(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val, bool is_high_priority); + +/** + * wma_send_msg() - Send wma message to PE. + * @wma_handle: wma handle + * @msg_type: message type + * @body_ptr: message body ptr + * @body_val: message body value + * + * Return: none + */ +void wma_send_msg(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val); + +/** + * wma_send_msg_high_priority() - Send wma message to PE with high priority. + * @wma_handle: wma handle + * @msg_type: message type + * @body_ptr: message body ptr + * @body_val: message body value + * + * Return: none + */ +void wma_send_msg_high_priority(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val); + +void wma_data_tx_ack_comp_hdlr(void *wma_context, + qdf_nbuf_t netbuf, int32_t status); + +QDF_STATUS wma_set_ppsconfig(uint8_t vdev_id, uint16_t pps_param, + int value); + +/* + * wma_scan_roam.c functions declarations + */ + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + +#ifdef WLAN_FEATURE_FIPS +/** + * wma_register_pmkid_req_event_handler() - Register pmkid request event handler + * @wma_handle: wma_handle + * + * This function register pmkid request event handler. + */ +void wma_register_pmkid_req_event_handler(tp_wma_handle wma_handle); + +/** + * wma_roam_pmkid_request_event_handler() - Handles roam pmkid request event + * @handle: wma_handle + * @event: pmkid request event data pointer + * @len: length of the data + * + * Handles pmkid request event from firmware which is triggered after roam + * candidate selection. + */ +int wma_roam_pmkid_request_event_handler(void *handle, + uint8_t *event, + uint32_t len); +#else +static inline void +wma_register_pmkid_req_event_handler(tp_wma_handle wma_handle) +{ +} + +static inline int +wma_roam_pmkid_request_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif /* WLAN_FEATURE_FIPS */ + +/** + * wma_roam_stats_event_handler() - Handle the WMI_ROAM_STATS_EVENTID + * from target + * @handle: wma_handle + * @event: roam debug stats event data pointer + * @len: length of the data + * + * This function handles the roam debug stats from the target and logs it + * to kmsg. This WMI_ROAM_STATS_EVENTID event is received whenever roam + * scan trigger happens or when neighbor report is sent by the firmware. + * + * Return: Success or Failure status + */ +int wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event, + uint32_t len); + +/** + * wma_roam_vdev_disconnect_event_handler() - Handles roam vdev disconnect event + * @handle: wma_handle + * @event: pmkid request event data pointer + * @len: length of the data + * + * @Return: 0 on sucees else error code + */ +int wma_roam_vdev_disconnect_event_handler(void *handle, uint8_t *event, + uint32_t len); + +#else +static inline int wma_mlme_roam_synch_event_handler_cb(void *handle, + uint8_t *event, + uint32_t len) +{ + return 0; +} + +static inline int +wma_roam_vdev_disconnect_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + return 0; +} + +static inline int +wma_roam_stats_event_handler(WMA_HANDLE handle, uint8_t *event, + uint32_t len) +{ + return 0; +} + +static inline int +wma_roam_pmkid_request_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_roam_scan_chan_list_event_handler() - roam scan chan list event handler + * @handle: wma handle + * @event: pointer to fw event + * @len: length of event + * + * Return: Success or Failure status + */ +int wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, + uint8_t *event, + uint32_t len); +#else +static inline int +wma_roam_scan_chan_list_event_handler(WMA_HANDLE handle, uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif + +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list); + +QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, + A_INT32 first_bcnt, + A_UINT32 final_bcnt, uint32_t vdev_id); + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts); +#endif + +#ifdef FEATURE_WLAN_EXTSCAN + +int wma_extscan_start_stop_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_operations_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_table_usage_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_capabilities_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_hotlist_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_cached_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_extscan_change_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +int wma_passpoint_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +#endif + +#ifdef FEATURE_WLAN_EXTSCAN +int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len); + +void wma_register_extscan_event_handler(tp_wma_handle wma_handle); + +/** + * wma_start_extscan() - start extscan command to fw. + * @wma: wma handle + * @params: extscan command request params + * + * This function sends start extscan request to fw. + * + * Return: QDF Status. + */ +QDF_STATUS wma_start_extscan(tp_wma_handle wma, + struct wifi_scan_cmd_req_params *pstart); + +/** + * wma_stop_extscan() - stop extscan command to fw. + * @wma: wma handle + * @params: stop scan command request params + * + * This function sends stop extscan request to fw. + * + * Return: QDF Status. + */ +QDF_STATUS wma_stop_extscan(tp_wma_handle wma, + struct extscan_stop_req_params *params); + +/** + * wma_extscan_start_hotlist_monitor() - start hotlist monitor + * @wma: wma handle + * @params: hotlist request params + * + * This function configures hotlist monitor in fw. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + struct extscan_bssid_hotlist_set_params *params); + +/** + * wma_extscan_stop_hotlist_monitor() - stop hotlist monitor + * @wma: wma handle + * @params: hotlist request params + * + * This function configures hotlist monitor to stop in fw. + * + * Return: QDF status + */ +QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + struct extscan_bssid_hotlist_reset_params *params); + +/** + * wma_extscan_start_change_monitor() - send start change monitor cmd + * @wma: wma handle + * @params: change monitor request params + * + * This function sends start change monitor request to fw. + * + * Return: QDF status + */ +QDF_STATUS +wma_extscan_start_change_monitor(tp_wma_handle wma, + struct extscan_set_sig_changereq_params *params); + +/** + * wma_extscan_stop_change_monitor() - send stop change monitor cmd + * @wma: wma handle + * @params: change monitor request params + * + * This function sends stop change monitor request to fw. + * + * Return: QDF status + */ +QDF_STATUS +wma_extscan_stop_change_monitor(tp_wma_handle wma, + struct extscan_capabilities_reset_params *params); + +/** + * wma_extscan_get_cached_results() - extscan get cached results + * @wma: wma handle + * @params: cached results parameters + * + * This function send request to fw to get cached results. + * + * Return: QDF status + */ +QDF_STATUS +wma_extscan_get_cached_results(tp_wma_handle wma, + struct extscan_cached_result_params *params); + +/** + * wma_extscan_get_capabilities() - extscan get capabilities + * @wma: wma handle + * @params: get capabilities params + * + * This function sends request to fw to get extscan capabilities. + * + * Return: QDF status + */ +QDF_STATUS +wma_extscan_get_capabilities(tp_wma_handle wma, + struct extscan_capabilities_params *params); + +/** + * wma_set_epno_network_list() - set epno network list + * @wma: WMA handle + * @req: epno config params request structure + * + * This function reads the incoming epno config request structure + * and constructs the WMI message to the firmware. + * + * Return: 0 on success, error number otherwise + */ +QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_enhanced_pno_params *req); + +/** + * wma_set_passpoint_network_list() - set passpoint network list + * @wma: WMA handle + * @params: passpoint network request structure + * + * This function sends the passpoint configs down to the firmware + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req_param *params); + +/** + * wma_reset_passpoint_network_list() - reset passpoint network list + * @wma: WMA handle + * @params: passpoint network request structure + * + * This function sends down WMI command with network id set to wildcard id. + * firmware shall clear all the config entries + * + * Return: QDF_STATUS enumeration + */ +QDF_STATUS +wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req_param *params); +#endif + +/** + * wma_scan_probe_setoui() - set scan probe OUI + * @wma: wma handle + * @set_oui: OUI parameters + * + * set scan probe OUI parameters in firmware + * + * Return: QDF status + */ +QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, + struct scan_mac_oui *set_oui); + +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id); + +/* + * wma_dev_if.c functions declarations + */ + +/** + * wma_find_vdev_id_by_addr() - find vdev_id from mac address + * @wma: wma handle + * @addr: mac address + * @vdev_id: return vdev_id + * + * Return: SUCCESS or FAILURE + */ +QDF_STATUS wma_find_vdev_id_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id); + +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id); + +/** + * wma_get_vdev_bssid() - Get BSSID from mlme_obj + * @vdev - pointer to vdev + * + * This API is used to get BSSID stored in vdev mlme object. + * + * Return: pointer to bssid on success else NULL. + */ +uint8_t *wma_get_vdev_bssid(struct wlan_objmgr_vdev *vdev); + +/** + * wma_find_bssid_by_vdev_id() - Get the BSS ID corresponding to the vdev ID + * @wma - wma handle + * @vdev_id - vdev ID + * + * Return: Returns pointer to bssid on success, + * otherwise returns NULL. + */ +static inline uint8_t *wma_find_bssid_by_vdev_id(tp_wma_handle wma, + uint8_t vdev_id) +{ + if (vdev_id >= wma->max_bssid) + return NULL; + + return wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev); +} + +/** + * wma_find_vdev_id_by_bssid() - Get the corresponding vdev_id from BSSID + * @wma - wma handle + * @bssid - bssid address + * @vdev_id - vdev ID + * + * Return: SUCCESS or FAILURE. + */ +QDF_STATUS wma_find_vdev_id_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id); + +QDF_STATUS wma_vdev_set_param(wmi_unified_t wmi_handle, uint32_t if_id, + uint32_t param_id, uint32_t param_value); + +QDF_STATUS wma_remove_peer(tp_wma_handle wma, uint8_t *mac_addr, + uint8_t vdev_id, bool no_fw_peer_delete); + +QDF_STATUS wma_peer_unmap_conf_send(tp_wma_handle wma, + struct send_peer_unmap_conf_params *msg); + +/** + * wma_send_del_bss_response() - send delete bss resp + * @wma: wma handle + * @resp: pointer to del bss response + * + * Return: none + */ +void wma_send_del_bss_response(tp_wma_handle wma, struct del_bss_resp *resp); + +/** + * __wma_handle_vdev_stop_rsp() - vdev stop response handler + * @resp_event: pointer to response received + * + * Return: QDF_STATUS_SUCCESS for success or QDF_ERROR code + */ +QDF_STATUS +__wma_handle_vdev_stop_rsp(struct vdev_stop_response *resp_event); + +void wma_hold_req_timer(void *data); +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, uint32_t msg_type, + uint8_t type, void *params, + uint32_t timeout); + +/** + * wma_add_bss() - Add BSS request to fw as per opmode + * @wma: wma handle + * @params: add bss params + * + * Return: none + */ +void wma_add_bss(tp_wma_handle wma, struct bss_params *params); + +/** + * wma_add_sta() - process add sta request as per opmode + * @wma: wma handle + * @add_Sta: add sta params + * + * Return: none + */ +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta); + +/** + * wma_delete_sta() - process del sta request as per opmode + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta); + +/** + * wma_delete_bss() - process delete bss request from upper layer + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +void wma_delete_bss(tp_wma_handle wma, uint8_t vdev_id); + +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type); + +/** + * wma_set_vdev_intrabss_fwd() - set intra_fwd value to wni_in. + * @wma_handle: wma handle + * @pdis_intra_fwd: Pointer to DisableIntraBssFwd struct + * + * Return: none + */ +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd); + +/** + * wma_delete_bss_ho_fail() - process delete bss request for handoff failure + * @wma: wma handle + * @vdev_id: vdev id + * + * Delete BSS in case of ROAM_HO_FAIL processing is handled separately in + * this routine. It needs to be done without sending any commands to firmware + * because firmware has already stopped and deleted peer and vdev is down. + * Relevant logic is aggregated from other routines. It changes the host + * data structures without sending VDEV_STOP, PEER_FLUSH_TIDS, PEER_DELETE + * and VDEV_DOWN commands to firmware. + * + * Return: none + */ +void wma_delete_bss_ho_fail(tp_wma_handle wma, uint8_t vdev_id); + +uint32_t wma_get_bcn_rate_code(uint16_t rate); + +/* + * wma_mgmt.c functions declarations + */ +#ifdef WLAN_WMI_BCN +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len); +#endif + +/** + * wma_peer_sta_kickout_event_handler() - kickout event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * Kickout event is received from firmware on observing beacon miss + * It handles kickout event for different modes and indicate to + * upper layers. + * + * Return: 0 for success or error code + */ +int wma_peer_sta_kickout_event_handler(void *handle, uint8_t *event, + uint32_t len); + +/** + * wma_unified_bcntx_status_event_handler() - beacon tx status event handler + * @handle: wma handle + * @cmd_param_info: event data + * @len: data length + * + * WMI Handler for WMI_OFFLOAD_BCN_TX_STATUS_EVENTID event from firmware. + * This event is generated by FW when the beacon transmission is offloaded + * and the host performs beacon template modification using WMI_BCN_TMPL_CMDID + * The FW generates this event when the first successful beacon transmission + * after template update + * + * Return: 0 for success or error code + */ +int wma_unified_bcntx_status_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +void wma_set_sta_sa_query_param(tp_wma_handle wma, + uint8_t vdev_id); + +void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id, + uint32_t method, uint32_t timeperiod, + uint8_t *hostv4addr, uint8_t *destv4addr, + uint8_t *destmac); + +/** + * wma_objmgr_set_peer_mlme_phymode() - set phymode to peer object + * @wma: wma handle + * @mac_addr: mac addr of peer + * @phymode: phymode value to set + * + * Return: None + */ +void wma_objmgr_set_peer_mlme_phymode(tp_wma_handle wma, uint8_t *mac_addr, + enum wlan_phymode phymode); + +/** + * wma_objmgr_set_peer_mlme_nss() - set nss to peer object + * @wma: wma handle + * @mac_addr: mac addr of peer + * @nss: nss value to set + * + * Return: None + */ +void wma_objmgr_set_peer_mlme_nss(tp_wma_handle wma, uint8_t *mac_addr, + uint8_t nss); + +/** + * wma_objmgr_get_peer_mlme_nss() - set nss to peer object + * @wma: wma handle + * @mac_addr: mac addr of peer + * + * Return: Peer NSS + */ +uint8_t wma_objmgr_get_peer_mlme_nss(tp_wma_handle wma, uint8_t *mac_addr); + +QDF_STATUS wma_send_peer_assoc(tp_wma_handle wma, + tSirNwType nw_type, + tpAddStaParams params); + +QDF_STATUS wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, + uint32_t if_id, + gtx_config_t *gtx_info); + +void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id, + uint8_t llbcoexist); + +void wma_process_update_beacon_params(tp_wma_handle wma, + tUpdateBeaconParams *bcn_params); + +/** + * wma_update_rts_params() - update cfg parameters to target + * @wma: wma handle + * @value: rts_threshold + * + * Return: none + */ +void wma_update_rts_params(tp_wma_handle wma, uint32_t value); + +/** + * wma_update_frag_params() - update cfg parameters to target + * @wma: wma handle + * @value: frag_threshold + * + * Return: none + */ +void wma_update_frag_params(tp_wma_handle wma, uint32_t value); + +QDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params); + +/** + * wma_tbttoffset_update_event_handler() - tbtt offset update handler + * @handle: wma handle + * @event: event buffer + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event, + uint32_t len); + +void wma_send_probe_rsp_tmpl(tp_wma_handle wma, + tpSendProbeRespParams probe_rsp_info); + +/** + * wma_set_ap_vdev_up() - send vdev up req + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_ap_vdev_up(tp_wma_handle wma, uint8_t vdev_id); + +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info); + +void wma_set_keepalive_req(tp_wma_handle wma, + struct keep_alive_req *keepalive); + +void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id, + int32_t rssi); + +void wma_process_update_opmode(tp_wma_handle wma_handle, + tUpdateVHTOpMode *update_vht_opmode); + +void wma_process_update_rx_nss(tp_wma_handle wma_handle, + tUpdateRxNss *update_rx_nss); + +void wma_process_update_membership(tp_wma_handle wma_handle, + tUpdateMembership *membership); + +void wma_process_update_userpos(tp_wma_handle wma_handle, + tUpdateUserPos *userpos); + +/* + * wma_power.c functions declarations + */ + +/** + * wma_enable_sta_ps_mode() - enable sta powersave params in fw + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_sta_ps_mode(tpEnablePsParams ps_req); + +QDF_STATUS wma_unified_set_sta_ps_param(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t param, + uint32_t value); + +QDF_STATUS wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id, + uint8_t *peer_addr, uint8_t uapsd_value, + uint8_t max_sp); + +void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param, + struct wmi_host_wme_vparams *wmm_param, + int ac, bool mu_edca_param, + uint8_t *debug_str, + uint32_t debug_str_size, uint32_t *len); + +void wma_set_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params); + +void wma_set_max_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params); + +void wma_disable_sta_ps_mode(tpDisablePsParams ps_req); + +/** + * wma_enable_uapsd_mode() - enable uapsd mode in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req); + +void wma_disable_uapsd_mode(tp_wma_handle wma, tpDisableUapsdParams ps_req); + +QDF_STATUS wma_get_temperature(tp_wma_handle wma_handle); + +int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +QDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle, + struct tx_power_limit *ptxlim); + +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie); + +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie); + +void wma_process_set_mimops_req(tp_wma_handle wma_handle, + tSetMIMOPS *mimops); + +QDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value); + +QDF_STATUS wma_notify_modem_power_state(void *wma_ptr, + tSirModemPowerStateInd *pReq); + +QDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, + int value); + +/* + * wma_data.c functions declarations + */ +/** + * wma_set_bss_rate_flags() - set rate flags based on BSS capability + * @wma: pointer to wma handle + * @vdev_id: vdev id + * @add_bss: pointer to bss params + * + * Return: none + */ +void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id, + struct bss_params *add_bss); + +/** + * wma_get_vht_rate_flags() - Return the VHT rate flags corresponding to the BW + * @ch_width: BW for which rate flags is required + * + * Return: Rate flags corresponding to ch_width + */ +enum tx_rate_info wma_get_vht_rate_flags(enum phy_ch_width ch_width); + +/** + * wma_get_ht_rate_flags() - Return the HT rate flags corresponding to the BW + * @ch_width: BW for which rate flags is required + * + * Return: Rate flags corresponding to ch_width + */ +enum tx_rate_info wma_get_ht_rate_flags(enum phy_ch_width ch_width); + +/** + * wma_get_he_rate_flags() - Return the HE rate flags corresponding to the BW + * @ch_width: BW for which rate flags is required + * + * Return: Rate flags corresponding to ch_width + */ +enum tx_rate_info wma_get_he_rate_flags(enum phy_ch_width ch_width); + +/** + * wma_set_vht_txbf_cfg() - set VHT Tx beamforming capability to FW + * @mac: Global MAC context + * @vdev_id: VDEV id + * + * Return: None + */ +void wma_set_vht_txbf_cfg(struct mac_context *mac, uint8_t vdev_id); + +int32_t wmi_unified_send_txbf(tp_wma_handle wma, tpAddStaParams params); + +/** + * wma_check_txrx_chainmask() - check txrx chainmask + * @num_rf_chains: number of rf chains + * @cmd_value: command value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_check_txrx_chainmask(int num_rf_chains, int cmd_value); + +QDF_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(uint32_t + mcc_adaptive_scheduler); + +QDF_STATUS wma_set_mcc_channel_time_latency + (tp_wma_handle wma, + uint32_t mcc_channel, uint32_t mcc_channel_time_latency); + +QDF_STATUS wma_set_mcc_channel_time_quota + (tp_wma_handle wma, + uint32_t adapter_1_chan_number, + uint32_t adapter_1_quota, uint32_t adapter_2_chan_number); + +/** + * wma_process_rate_update_indate() - rate update indication + * @wma: wma handle + * @pRateUpdateParams: Rate update params + * + * This function update rate & short GI interval to fw based on params + * send by SME. + * + * Return: QDF status + */ +QDF_STATUS wma_process_rate_update_indicate(tp_wma_handle wma, + tSirRateUpdateInd * + pRateUpdateParams); + +QDF_STATUS wma_tx_attach(tp_wma_handle wma_handle); + +QDF_STATUS wma_tx_detach(tp_wma_handle wma_handle); + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + +/** + * wma_mcc_vdev_tx_pause_evt_handler() - pause event handler + * @handle: wma handle + * @event: event buffer + * @len: data length + * + * This function handle pause event from fw and pause/unpause + * vdev. + * + * Return: 0 for success or error code. + */ +int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, + uint32_t len); +#endif + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config); +#else +static inline QDF_STATUS +wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, + t_thermal_mgmt *pThermalParams); + +QDF_STATUS wma_process_set_thermal_level(tp_wma_handle wma, + uint8_t thermal_level); + +QDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, + t_thermal_cmd_params thermal_info); + +int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, + uint32_t len); +/* + * wma_utils.c functions declarations + */ + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wma_stats_ext_event_handler() - extended stats event handler + * @handle: wma handle + * @event_buf: event buffer received from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); +#endif + +enum eSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode); +int wma_smps_mode_to_force_mode_param(uint8_t smps_mode); + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle); + +/** + * wma_process_ll_stats_clear_req() - clear link layer stats + * @wma: wma handle + * @clearReq: ll stats clear request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_process_ll_stats_clear_req + (tp_wma_handle wma, const tpSirLLStatsClearReq clearReq); + +QDF_STATUS wma_process_ll_stats_set_req + (tp_wma_handle wma, const tpSirLLStatsSetReq setReq); + +/** + * wma_process_ll_stats_get_req() - link layer stats get request + * @wma:wma handle + * @getReq:ll stats get request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_process_ll_stats_get_req + (tp_wma_handle wma, const tpSirLLStatsGetReq getReq); + +int wma_unified_link_iface_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); +void wma_config_stats_ext_threshold(tp_wma_handle wma, + struct sir_ll_ext_stats_threshold *thresh); +#endif + +void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, + uint8_t link_status); + +/** + * wma_link_status_event_handler() - link status event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +/** + * wma_rso_cmd_status_event_handler() - RSO Command status event handler + * @vdev_id: VDEV id + * @notif: roam notification + * + * This function is used to send RSO command status to upper layer + * + * Return: 0 for success + */ +int wma_rso_cmd_status_event_handler(uint8_t vdev_id, uint32_t notif); + +QDF_STATUS wma_send_link_speed(uint32_t link_speed); + +int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len); + +/** + * wma_peer_phymode() - get phymode + * @nw_type: nw type + * @sta_type: sta type + * @is_ht: is ht supported + * @ch_width: supported channel width + * @is_vht: is vht supported + * @is_he: is HE supported + * @is_eht: is EHT supported + * + * Return: host phymode + */ +enum wlan_phymode +wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, + uint8_t is_ht, uint8_t ch_width, + uint8_t is_vht, bool is_he, bool is_eht); + +int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value); + +int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value); + +/* + * wma_features.c functions declarations + */ + +/** + * wma_sar_register_event_handlers() - Register SAR event handlers + * @handle: WMA Handle + * + * Function to be called during WMA initialization to register SAR + * event handlers with WMI + * + * Return: QDF_STATUS_SUCCESS if registration is successful, otherwise + * an error enumeration + */ +QDF_STATUS wma_sar_register_event_handlers(WMA_HANDLE handle); + +void wma_process_link_status_req(tp_wma_handle wma, + tAniGetLinkStatus *pGetLinkStatus); + +/** + * wma_get_isolation() - get antenna isolation + * @handle: wma interface + * + * This function will send WMI_COEX_GET_ANTENNA_ISOLATION_CMDID to FW + * + * Return: 0 on success, otherwise error value + */ +QDF_STATUS wma_get_isolation(tp_wma_handle wma); + +int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf, + uint32_t len); + +QDF_STATUS wma_unified_fw_profiling_cmd(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2); + +int wma_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef FEATURE_WLAN_TDLS +int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len); +#endif + +int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len); + +#ifdef FEATURE_OEM_DATA_SUPPORT +int wma_oem_data_response_handler(void *handle, uint8_t *datap, + uint32_t len); +#endif + +#if !defined(REMOVE_PKT_LOG) +QDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle, + struct ath_pktlog_wmi_params *params); +#endif + +int wma_wow_wakeup_host_event(void *handle, uint8_t *event, + uint32_t len); + +int wma_d0_wow_disable_ack_event(void *handle, uint8_t *event, uint32_t len); + +int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len); + +void wma_del_ts_req(tp_wma_handle wma, struct del_ts_params *msg); + +/** + * wma_aggr_qos_req() - send aggr qos request to fw + * @wma: handle to wma + * @pAggrQosRspMsg - combined struct for all ADD_TS requests. + * + * A function to handle WMA_AGGR_QOS_REQ. This will send out + * ADD_TS requests to firmware in loop for all the ACs with + * active flow. + * + * Return: none + */ +void wma_aggr_qos_req(tp_wma_handle wma, + struct aggr_add_ts_param *pAggrQosRspMsg); + +void wma_add_ts_req(tp_wma_handle wma, struct add_ts_param *msg); + +#ifdef FEATURE_WLAN_ESE +QDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg); +void wma_config_plm(tp_wma_handle wma, struct plm_req_params *plm); +#endif + +QDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList * mcbc_param); + +QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn *pattern); + +QDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams); + +#ifdef WLAN_FEATURE_STATS_EXT +/** + * wma_stats_ext_req() - request ext stats from fw + * @wma_ptr: wma handle + * @preq: stats ext params + * + * Return: QDF status + */ +QDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq); +#endif + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +QDF_STATUS wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params); + +int wma_set_app_type1_params_in_fw(tp_wma_handle wma, + tpSirAppType1Params appType1Params); + +QDF_STATUS wma_set_app_type2_params_in_fw(tp_wma_handle wma, + tpSirAppType2Params appType2Params); +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +int wma_auto_shutdown_event_handler(void *handle, uint8_t *event, + uint32_t len); + +/** + * wma_set_auto_shutdown_timer_req() - sets auto shutdown timer in firmware + * @wma_handle: wma handle + * @auto_sh_cmd: auto shutdown timer params + * + * Return: QDF status + */ +QDF_STATUS +wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + struct auto_shutdown_cmd *auto_sh_cmd); +#endif + +#ifdef WLAN_FEATURE_TSF +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len); +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id); +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id); +QDF_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle, uint32_t pin); + +#ifdef WLAN_FEATURE_TSF_AUTO_REPORT +/** + * wma_set_tsf_auto_report() - Set TSF auto report in firmware + * @wma_handle: wma handle + * @vdev_id: vdev id + * @param_id: enum GEN_PARAM + * @ena: true for enable, and false for disable + * + * Return: QDF_STATUS_SUCCESS for success, otherwise for failure + */ +QDF_STATUS wma_set_tsf_auto_report(WMA_HANDLE handle, uint32_t vdev_id, + uint32_t param_id, bool ena); +#else /* !WLAN_FEATURE_TSF_AUTO_REPORT */ +static inline QDF_STATUS wma_set_tsf_auto_report(WMA_HANDLE handle, + uint32_t vdev_id, + uint32_t param_id, bool ena) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif /* WLAN_FEATURE_TSF_AUTO_REPORT */ + +#else +static inline QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, + uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, + uint32_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline int wma_vdev_tsf_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + return 0; +} + +static inline QDF_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle, uint32_t pin) +{ + return QDF_STATUS_E_INVAL; +} +#endif + +QDF_STATUS wma_set_wisa_params(tp_wma_handle wma, struct sir_wisa_params *wisa); + +#ifdef DHCP_SERVER_OFFLOAD +/** + * wma_process_dhcpserver_offload() - enable DHCP server offload + * @wma_handle: wma handle + * @params: DHCP server offload information + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + struct dhcp_offload_info_params *params); +#endif + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +QDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, + struct flashing_req_params *flashing); +#endif + +/** + * wma_sar_rsp_evt_handler() - process sar response event from FW. + * @handle: ol scn handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_sar_rsp_evt_handler(ol_scn_t handle, uint8_t *event, uint32_t len); + +#ifdef FEATURE_WLAN_CH_AVOID +QDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, + tSirChAvoidUpdateReq * + ch_avoid_update_req); +#endif + +#ifdef FEATURE_WLAN_TDLS +int wma_update_tdls_peer_state(WMA_HANDLE handle, + struct tdls_peer_update_state *peer_state); +#endif + +void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id); +void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id); + +#ifdef FEATURE_RSSI_MONITOR +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len); +#else /* FEATURE_RSSI_MONITOR */ +static inline +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + return 0; +} +#endif /* FEATURE_RSSI_MONITOR */ + +QDF_STATUS wma_process_cfg_action_frm_tb_ppdu(tp_wma_handle wma, + struct cfg_action_frm_tb_ppdu *cfg_info); + +QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, + struct vdev_ie_info *ie_info); +int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +/** + * wma_peer_create_confirm_handler - Handle peer create confirmation + * result + * @handle: wma_handle + * @evt_param_info: event data + * @len: event length + * + * Return: 0 on success. Error value on failure + */ +int wma_peer_create_confirm_handler(void *handle, uint8_t *evt_param_info, + uint32_t len); + +int wma_peer_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type); + +/** + * wma_find_remove_req_msgtype() - find and remove request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @msg_type: message request type + * + * Find target request for given vdev id & sub type of request. + * Remove the same from active list. + * + * Return: Success if request found, failure other wise + */ +struct wma_target_req *wma_find_remove_req_msgtype(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type); + +/** + * wma_remove_peer_req - Remove the peer create + * request from WMA queue + * @wma: wma handle + * @vdev_id: vdev id + * @type: peer type + * @peer_addr: peer address + */ +void wma_remove_peer_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type, struct qdf_mac_addr *peer_addr); + +QDF_STATUS wma_process_hal_pwr_dbg_cmd(WMA_HANDLE handle, + struct sir_mac_pwr_dbg_cmd * + sir_pwr_dbg_params); + +/** + * wma_lost_link_info_handler() - collect lost link information and inform SME + * @wma: WMA handle + * @vdev_id: vdev ID + * @rssi: rssi at disconnection time + * + * Return: none + */ +void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id, + int32_t rssi); +int wma_unified_power_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, uint32_t len); +/** + * wma_unified_beacon_debug_stats_event_handler() - collect beacon debug stats + * @handle: WMA handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_beacon_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len); + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) +/** + * wma_vdev_bcn_latency_event_handler() - Get the latency info received in bcn + * @handle: WMA handle + * @event: data in event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_vdev_bcn_latency_event_handler(void *handle, uint8_t *event, + uint32_t len); +#else +static inline int wma_vdev_bcn_latency_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +/** + * wma_sta_kickout_event()- send sta kickout event + * @kickout_reason - reasoncode for kickout + * @macaddr[QDF_MAC_ADDR_SIZE]: Peer mac address + * @vdev_id: Unique id for identifying the VDEV + * + * This function sends sta kickout diag event + * + * Return: void. + */ +void wma_sta_kickout_event(uint32_t kickout_reason, uint8_t vdev_id, + uint8_t *macaddr); +#else +static inline void wma_sta_kickout_event(uint32_t kickout_reason, + uint8_t vdev_id, uint8_t *macaddr) +{ + +}; +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ + +/** + * wma_get_rcpi_req() - get rcpi request + * @handle: wma handle + * @rcpi_request: rcpi params + * + * Return: none + */ +QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle, + struct sme_rcpi_req *rcpi_request); + +/** + * wma_rcpi_event_handler() - rcpi event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len); + +/** + * wma_acquire_wakelock() - acquire the given wakelock + * @wl: the wakelock to acquire + * @msec: the wakelock duration in milliseconds + * + * This also acquires the wma runtime pm lock. + * + * Return: None + */ +void wma_acquire_wakelock(qdf_wake_lock_t *wl, uint32_t msec); + +/** + * wma_release_wakelock() - release the given wakelock + * @wl: the wakelock to release + * + * This also releases the wma runtime pm lock. + * + * Return: None + */ +void wma_release_wakelock(qdf_wake_lock_t *wl); + +/** + * wma_send_vdev_stop_to_fw() - send the vdev stop command to firmware + * @wma: a reference to the global WMA handle + * @vdev_id: the Id of the vdev to stop + * + * Consumers should call wma_release_wakelock() upon receipt of the vdev stop + * response from firmware to avoid power penalties. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id); + +int wma_get_arp_stats_handler(void *handle, uint8_t *data, uint32_t data_len); + +/** + * wma_send_vdev_down_to_fw() - send the vdev down command to firmware + * @wma: a reference to the global WMA handle + * @vdev_id: the Id of the vdev to down + * + * This also releases the vdev start wakelock. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_vdev_down_to_fw(t_wma_handle *wma, uint8_t vdev_id); + +/* + * wma_rx_aggr_failure_event_handler - event handler to handle rx aggr failure + * @handle: the wma handle + * @event_buf: buffer with event + * @len: buffer length + * + * This function receives rx aggregation failure event and then pass to upper + * layer + * + * Return: 0 on success + */ +int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf, + u_int32_t len); + +/** + * wma_wlan_bt_activity_evt_handler - event handler to handle bt activity + * @handle: the WMA handle + * @event: buffer with the event parameters + * @len: length of the buffer + * + * This function receives BT activity event from firmware and passes the event + * information to upper layers + * + * Return: 0 on success + */ +int wma_wlan_bt_activity_evt_handler(void *handle, uint8_t *event, + uint32_t len); + +/** + * wma_pdev_div_info_evt_handler - event handler to handle antenna info + * @handle: the wma handle + * @event_buf: buffer with event + * @len: buffer length + * + * This function receives antenna info from firmware and passes the event + * to upper layer + * + * Return: 0 on success + */ +int wma_pdev_div_info_evt_handler(void *handle, u_int8_t *event_buf, + u_int32_t len); + +/** + * wma_update_beacon_interval() - update beacon interval in fw + * @wma: wma handle + * @vdev_id: vdev id + * @beaconInterval: becon interval + * + * Return: none + */ +void +wma_update_beacon_interval(tp_wma_handle wma, uint8_t vdev_id, + uint16_t beaconInterval); + +#define RESET_BEACON_INTERVAL_TIMEOUT 200 + +struct wma_beacon_interval_reset_req { + qdf_timer_t event_timeout; + uint8_t vdev_id; + uint16_t interval; +}; + +/** + * wma_fill_beacon_interval_reset_req() - req to reset beacon interval + * @wma: wma handle + * @vdev_id: vdev id + * @beacon_interval: beacon interval + * @timeout: timeout val + * + * Return: status + */ +int wma_fill_beacon_interval_reset_req(tp_wma_handle wma, uint8_t vdev_id, + uint16_t beacon_interval, uint32_t timeout); +/* + * wma_is_vdev_valid() - check the vdev status + * @vdev_id: vdev identifier + * + * This function verifies the vdev validity + * + * Return: 'true' on valid vdev else 'false' + */ +bool wma_is_vdev_valid(uint32_t vdev_id); + +/** + * wma_vdev_obss_detection_info_handler - event handler to handle obss detection + * @handle: the wma handle + * @event: buffer with event + * @len: buffer length + * + * This function receives obss detection info from firmware which is used to + * decide obss protection. + * + * Return: 0 on success + */ +int wma_vdev_obss_detection_info_handler(void *handle, uint8_t *event, + uint32_t len); + +/** + * wma_vdev_bss_color_collision_info_handler - event handler to + * handle obss color collision detection. + * @handle: the wma handle + * @event: buffer with event + * @len: buffer length + * + * This function receives obss color collision detection info from firmware + * which is used to select new bss color. + * + * Return: 0 on success + */ +int wma_vdev_bss_color_collision_info_handler(void *handle, + uint8_t *event, + uint32_t len); + +#ifdef WLAN_SUPPORT_TWT +/** + * wma_register_twt_events - Register TWT wmi event handlers + * @handle: wma handle + * + * Return: None + */ +void wma_register_twt_events(tp_wma_handle wma_handle); +#endif + +/** + * wma_get_roam_scan_stats() - Get roam scan stats request + * @handle: wma handle + * @req: request details + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_get_roam_scan_stats(WMA_HANDLE handle, + struct sir_roam_scan_stats *req); + +/** + * wma_roam_scan_stats_event_handler() - roam scan stats event handler + * @handle: wma handle + * @event: event data + * @len: length of data + * + * Return: Success or Failure status + */ +int wma_roam_scan_stats_event_handler(void *handle, uint8_t *event, + uint32_t len); + +/** + * wma_send_vdev_down() - send del bss req to firmware + * @wma: wma handle. + * @req: pointer to del bss response + * + * This function sends del bss resp to upper layer + * + * Return: Success or Failure status + */ +QDF_STATUS wma_send_vdev_down(tp_wma_handle wma, struct del_bss_resp *req); + +/** + * wma_cold_boot_cal_event_handler() - Cold boot cal event handler + * @wma_ctx: wma handle + * @event_buff: event data + * @len: length of data + * + * Return: Success or Failure status + */ +int wma_cold_boot_cal_event_handler(void *wma_ctx, uint8_t *event_buff, + uint32_t len); + +#ifdef FEATURE_OEM_DATA +/** + * wma_oem_event_handler() - oem data event handler + * @wma_ctx: wma handle + * @event_buff: event data + * @len: length of event buffer + * + * Return: Success or Failure status + */ +int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len); +#endif + +#ifdef MULTI_CLIENT_LL_SUPPORT +/** + * wma_latency_level_event_handler() - latency level event handler + * @wma_ctx: wma handle + * @event_buff: event data + * @len: length of event buffer + * + * Return: Success or Failure status + */ +int wma_latency_level_event_handler(void *wma_ctx, uint8_t *event_buff, + uint32_t len); +#endif + +/** + * wma_get_ani_level_evt_handler - event handler to fetch ani level + * @handle: the wma handle + * @event_buf: buffer with event + * @len: buffer length + * + * This function receives ani level from firmware and passes the event + * to upper layer + * + * Return: 0 on success + */ +int wma_get_ani_level_evt_handler(void *handle, uint8_t *event_buf, + uint32_t len); +/** + * wma_mcs_rate_match() - find the match mcs rate + * @raw_rate: the rate to look up + * @is_he: if it is he rate + * @nss1_rate: the nss1 rate + * @nss2_rate: the nss2 rate + * @nss: the nss in use + * @guard_interval: to get guard interval from rate + * + * This is a helper function to find the match of the tx_rate + * and return nss/guard interval. + * + * Return: the found rate or 0 otherwise + */ +uint16_t wma_mcs_rate_match(uint16_t raw_rate, bool is_he, + const uint16_t *nss1_rate, + const uint16_t *nss2_rate, + uint8_t *nss, enum txrate_gi *guard_interval); + +/** + * wma_update_edca_pifs_param() - Update edca/pifs param + * @handle: wma handle + * @edca_pifs_param: pointer to edca_pifs_vparam struct + * + * This is a helper function to update edca/pifs param for ll sap + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_update_edca_pifs_param(WMA_HANDLE handle, + struct edca_pifs_vparam *edca_pifs_param); + +/** + * wma_update_bss_peer_phy_mode() - Update phymode of peer object + * @des_chan: des_chan object which has channel information + * @vdev: pointer to vdev object + * + * This is a helper function to update phymode of peer object + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_update_bss_peer_phy_mode(struct wlan_channel *des_chan, + struct wlan_objmgr_vdev *vdev); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_pasn_peer_api.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_pasn_peer_api.h new file mode 100644 index 0000000000..bfd2f845e6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_pasn_peer_api.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_PASN_PEER_API_H__ +#define __WMA_PASN_PEER_API_H__ + +#include "qdf_types.h" +#include "osapi_linux.h" +#include "wmi_services.h" +#include "wmi_unified.h" +#include "wmi_unified_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wma.h" + +#if defined(WIFI_POS_CONVERGED) && defined(WLAN_FEATURE_RTT_11AZ_SUPPORT) +/** + * wma_pasn_peer_remove - Remove RTT pasn peer and send peer delete command to + * firmware + * @wma: WMA handle + * @peer_addr: Peer mac address + * @vdev_id: vdev id + * @no_fw_peer_delete: Don't send peer delete to firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_pasn_peer_remove(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id, bool no_fw_peer_delete); + +/** + * wma_pasn_peer_create() - Create RTT PASN peer + * @psoc: PSOC pointer + * @peer_addr: Peer address + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_pasn_peer_create(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id); + +/** + * wma_pasn_handle_peer_create_conf() - Handle PASN peer create confirm event + * @wma: WMA handle + * @peer_mac: peer mac address + * @status: status + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_pasn_handle_peer_create_conf(tp_wma_handle wma, + struct qdf_mac_addr *peer_mac, + QDF_STATUS status, uint8_t vdev_id); + +/** + * wma_delete_all_pasn_peers() - Delete all PASN peers + * @wma: WMA handle + * @vdev: Vdev object pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS +wma_delete_all_pasn_peers(tp_wma_handle wma, struct wlan_objmgr_vdev *vdev); + +QDF_STATUS +wma_resume_vdev_delete(tp_wma_handle wma, uint8_t vdev_id); + +QDF_STATUS +wma_pasn_peer_delete_all_complete(struct wlan_objmgr_vdev *vdev); +#else +static inline QDF_STATUS +wma_pasn_peer_create(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wma_pasn_peer_remove(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id, bool no_fw_peer_delete) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wma_pasn_handle_peer_create_conf(tp_wma_handle wma, + struct qdf_mac_addr *peer_mac, + QDF_STATUS status, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wma_delete_all_pasn_peers(tp_wma_handle wma, struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +wma_resume_vdev_delete(tp_wma_handle wma, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h new file mode 100644 index 0000000000..72882f444d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_tgt_cfg.h @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WMA_TGT_CFG_H +#define WMA_TGT_CFG_H + +#include "wma_sar_public_structs.h" +#include "nan_public_structs.h" + +/** + * struct wma_tgt_services - target services + * @sta_power_save: sta power save + * @uapsd: uapsd + * @ap_dfs: ap dfs + * @en_11ac: enable 11ac + * @arp_offload: arp offload + * @early_rx: early rx + * @pno_offload: pno offload + * @beacon_offload: beacon offload + * @lte_coex_ant_share: LTE coex ant share + * @en_tdls: enable tdls + * @en_tdls_offchan: enable tdls offchan + * @en_tdls_uapsd_buf_sta: enable sta tdls uapsd buf + * @en_tdls_uapsd_sleep_sta: enable sta tdls uapsd sleep + * @en_tdls_wideband_support: Get TDLS wideband support + * @en_tdls_11ax_support: Get TDLS ax support + * @en_tdls_6g_support: Get TDLS 6g fw capability + * @en_tdls_mlo_support: Get TDLS mlo fw support + * @en_n_link_mlo_support: Get N-Link mlo fw support + * @en_roam_offload: enable roam offload + * @en_11ax: enable 11ax + * @is_fw_mawc_capable: Motion Aided Wireless Connectivity feature + * @twt_requestor: TWT requestor capability + * @twt_responder: TWT responder capability + * @bcn_reception_stats: Beacon Reception stats capability + * @is_roam_scan_ch_to_host: Get roam scan channels from fw supported + * @ll_stats_per_chan_rx_tx_time: Per channel tx and rx time support in ll stats + * @is_get_station_clubbed_in_ll_stats_req: Get station req support within ll + * stats req + * @is_fw_therm_throt_supp: Get thermal throttling threshold + * @igmp_offload_enable: Get igmp offload enable or disable + * @en_11be: enable 11be + * @dynamic_vdev_macaddr_support: Dynamic update of vdev MAC addr is + * supported or not + * @is_mlo_per_link_stats_supported: Per link mlo stats is supported or not + * @en_mlo_tid_to_link_support: Get tid to link fw support + */ +struct wma_tgt_services { + uint32_t sta_power_save; + bool uapsd; + uint32_t ap_dfs; + uint32_t en_11ac; + uint32_t arp_offload; + uint32_t early_rx; +#ifdef FEATURE_WLAN_SCAN_PNO + bool pno_offload; +#endif /* FEATURE_WLAN_SCAN_PNO */ + bool beacon_offload; + bool pmf_offload; + uint32_t lte_coex_ant_share; +#ifdef FEATURE_WLAN_TDLS + bool en_tdls; + bool en_tdls_offchan; + bool en_tdls_uapsd_buf_sta; + bool en_tdls_uapsd_sleep_sta; + bool en_tdls_wideband_support; +#ifdef WLAN_FEATURE_11AX + bool en_tdls_11ax_support; + bool en_tdls_6g_support; +#endif +#ifdef WLAN_FEATURE_11BE + bool en_tdls_mlo_support; + bool en_n_link_mlo_support; +#endif +#endif /* FEATURE_WLAN_TDLS */ +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + bool en_roam_offload; +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + bool en_11ax; + bool get_peer_info_enabled; + bool is_fils_roaming_supported; + bool is_fw_mawc_capable; + bool is_11k_offload_supported; + bool twt_requestor; + bool twt_responder; + bool obss_scan_offload; + bool bcn_reception_stats; + bool is_roam_scan_ch_to_host; + bool ll_stats_per_chan_rx_tx_time; +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION + bool is_get_station_clubbed_in_ll_stats_req; +#endif + bool is_fw_therm_throt_supp; +#ifdef WLAN_FEATURE_IGMP_OFFLOAD + bool igmp_offload_enable; +#endif + bool en_11be; +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE + bool dynamic_vdev_macaddr_support; +#endif +#ifdef WLAN_FEATURE_11BE_MLO + bool is_mlo_per_link_stats_supported; +#endif +#ifdef WLAN_FEATURE_11BE + bool en_mlo_tid_to_link_support; +#endif +}; + +/** + * struct wma_tgt_ht_cap - ht capabalitiy + * @mpdu_density: mpdu density + * @ht_rx_stbc: ht rx stbc + * @ht_tx_stbc: ht tx stbc + * @ht_rx_ldpc: ht rx ldpc + * @ht_sgi_20: ht sgi 20 + * @ht_sgi_40: ht sgi 40 + * @num_rf_chains: num of rf chains + * @dynamic_smps: Dynamic MIMO powersave + */ +struct wma_tgt_ht_cap { + uint32_t mpdu_density; + bool ht_rx_stbc; + bool ht_tx_stbc; + bool ht_rx_ldpc; + bool ht_sgi_20; + bool ht_sgi_40; + uint32_t num_rf_chains; + bool dynamic_smps; +}; + +/** + * struct wma_tgt_vht_cap - vht capabalities + * @vht_max_mpdu: vht max mpdu + * @supp_chan_width: supported channel width + * @vht_rx_ldpc: vht rx ldpc + * @vht_short_gi_80: vht short gi 80 + * @vht_short_gi_160: vht short gi 160 + * @vht_tx_stbc: vht tx stbc + * @vht_rx_stbc: vht rx stbc + * @vht_su_bformer: vht su bformer + * @vht_su_bformee: vht su bformee + * @vht_mu_bformer: vht mu bformer + * @vht_mu_bformee: vht mu bformee + * @vht_max_ampdu_len_exp: vht max ampdu len exp + * @vht_txop_ps: vht txop ps + * @vht_mcs_10_11_supp: VHT MCS 10 & 11 support + */ +struct wma_tgt_vht_cap { + uint32_t vht_max_mpdu; + uint32_t supp_chan_width; + uint32_t vht_rx_ldpc; + uint32_t vht_short_gi_80; + uint32_t vht_short_gi_160; + uint32_t vht_tx_stbc; + uint32_t vht_rx_stbc; + uint32_t vht_su_bformer; + uint32_t vht_su_bformee; + uint32_t vht_mu_bformer; + uint32_t vht_mu_bformee; + uint32_t vht_max_ampdu_len_exp; + uint32_t vht_txop_ps; + uint32_t vht_mcs_10_11_supp; +}; + +/** + * struct wma_tgt_aux_dev_caps - aux capability in wma layer + * @supported_modes_bitmap: each bit define in WMI_AUX_DEV_CAPS_SUPPORTED_MODE + * @listen_pdev_id_map: define which AUX MAC can listen/scan for the HW mode + * @emlsr_pdev_id_map: define which AUX MAC can perform eMLSR for the HW mode + */ +struct wma_tgt_aux_dev_caps { + uint32_t supported_modes_bitmap; + uint32_t listen_pdev_id_map; + uint32_t emlsr_pdev_id_map; +}; + +/** + * struct board_info - Structure for board related information + * @bdf_version: board file version + * @ref_design_id: reference design id + * @customer_id: customer id + * @project_id: project id + * @board_data_rev: board data revision + * + * This board information will be stored in board file during the + * calibration and customization. + * + */ +struct board_info { + uint32_t bdf_version; + uint32_t ref_design_id; + uint32_t customer_id; + uint32_t project_id; + uint32_t board_data_rev; +}; + +/** + * struct wma_tgt_cfg - target config + * @target_fw_version: target fw version + * @target_fw_vers_ext: target fw extended sub version + * @band_cap: band capability bitmap + * @reg_domain: reg domain + * @eeprom_rd_ext: eeprom rd ext + * @hw_macaddr: hw mcast addr + * @services: struct wma_tgt_services + * @ht_cap: struct wma_tgt_ht_cap + * @vht_cap: struct wma_tgt_vht_cap + * @max_intf_count: max interface count + * @lpss_support: lpass support + * @egap_support: enhanced green ap support + * @nan_datapath_enabled: nan data path support + * @he_cap: HE capability received from FW + * @dfs_cac_offload: dfs and cac timer offloaded + * @tx_bfee_8ss_enabled: Tx Beamformee support for 8x8 + * @dynamic_nss_chains_update: per vdev dynamic nss, chains update + * @rcpi_enabled: for checking rcpi support + * @obss_detection_offloaded: obss detection offloaded to firmware + * @obss_color_collision_offloaded: obss color collision offloaded to firmware + * @sar_version: Version of SAR supported by firmware + * @legacy_bcast_twt_support: broadcast twt support + * @restricted_80p80_bw_supp: Restricted 80+80MHz(165MHz BW) support + * @twt_bcast_req_support: twt bcast requestor support + * @twt_bcast_res_support: twt bcast responder support + * @twt_nudge_enabled: twt nudge enable + * @all_twt_enabled: all twt enabled + * @twt_stats_enabled: twt stats enabled + * + */ +struct wma_tgt_cfg { + uint32_t target_fw_version; + uint32_t target_fw_vers_ext; + uint32_t band_cap; + uint32_t reg_domain; + uint32_t eeprom_rd_ext; + struct qdf_mac_addr hw_macaddr; + struct wma_tgt_services services; + struct wma_tgt_ht_cap ht_cap; + struct wma_tgt_vht_cap vht_cap; + uint8_t max_intf_count; +#ifdef WLAN_FEATURE_LPSS + uint8_t lpss_support; +#endif + uint8_t ap_arpns_support; + uint32_t fine_time_measurement_cap; +#ifdef WLAN_FEATURE_NAN + bool nan_datapath_enabled; +#endif + bool sub_20_support; + uint16_t wmi_max_len; +#ifdef WLAN_FEATURE_11AX + tDot11fIEhe_cap he_cap; + uint8_t ppet_2g[HE_MAX_PPET_SIZE]; + uint8_t ppet_5g[HE_MAX_PPET_SIZE]; + tDot11fIEhe_cap he_cap_2g; + tDot11fIEhe_cap he_cap_5g; + uint16_t he_mcs_12_13_supp_2g; + uint16_t he_mcs_12_13_supp_5g; +#endif + bool dfs_cac_offload; + bool tx_bfee_8ss_enabled; + bool dynamic_nss_chains_support; + bool rcpi_enabled; + bool obss_detection_offloaded; + bool obss_color_collision_offloaded; + uint32_t hw_bd_id; + struct board_info hw_bd_info; + enum sar_version sar_version; + struct nan_tgt_caps nan_caps; + bool legacy_bcast_twt_support; + bool restricted_80p80_bw_supp; +#ifdef WLAN_SUPPORT_TWT + bool twt_bcast_req_support; + bool twt_bcast_res_support; + bool twt_nudge_enabled; + bool all_twt_enabled; + bool twt_stats_enabled; +#endif +#ifdef WLAN_FEATURE_11BE + tDot11fIEeht_cap eht_cap; + tDot11fIEeht_cap eht_cap_2g; + tDot11fIEeht_cap eht_cap_5g; +#endif + struct wma_tgt_aux_dev_caps wma_aux0_dev_caps[WMI_HOST_HW_MODE_MAX]; +}; +#endif /* WMA_TGT_CFG_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_twt.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_twt.h new file mode 100644 index 0000000000..8cc5f21747 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_twt.h @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_TWT_H +#define __WMA_TWT_H + +#include "wma.h" +#include "wmi_unified_twt_param.h" + +/** + * struct twt_enable_disable_conf - TWT enable/disable configuration/parameters + * @congestion_timeout: Congestion timer value in ms for firmware controlled TWT + * @bcast_en: If bcast TWT enabled + * @ext_conf_present: If extended config is present + * @role: The configuration is for WMI_TWT_ROLE + * @oper: The configuration is for WMI_TWT_OPERATION + */ +struct twt_enable_disable_conf { + uint32_t congestion_timeout; + bool bcast_en; + bool ext_conf_present; + enum WMI_TWT_ROLE role; + enum WMI_TWT_OPERATION oper; +}; + +/** + * struct wma_twt_add_dialog_complete_event - TWT add dialog complete event + * @params: Fixed parameters for TWT add dialog complete event + * @additional_params: additional parameters for TWT add dialog complete event + * + * Holds the fixed and additional parameters from add dialog + * complete event + */ +struct wma_twt_add_dialog_complete_event { + struct wmi_twt_add_dialog_complete_event_param params; + struct wmi_twt_add_dialog_additional_params additional_params; +}; + +#ifdef WLAN_SUPPORT_TWT +/** + * wma_send_twt_enable_cmd() - Send TWT Enable command to firmware + * @pdev_id: pdev id + * @conf: Pointer to twt_enable_disable_conf + * + * Return: None + */ +void wma_send_twt_enable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf); + +/** + * wma_set_twt_peer_caps() - Fill the peer TWT capabilities + * @params: STA context params which will store the capabilities + * @cmd: Command in which the capabilities should be populated + * + * Return: None + */ +void wma_set_twt_peer_caps(tpAddStaParams params, + struct peer_assoc_params *cmd); + +/** + * wma_send_twt_disable_cmd() - Send TWT disable command to firmware + * @pdev_id: pdev id + * @conf: Pointer to twt_enable_disable_conf + * + * Return: None + */ +void wma_send_twt_disable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf); + +/** + * wma_twt_process_add_dialog() - Process twt add dialog command + * @wma_handle: wma handle + * @params: add dialog configuration parameters + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ + +QDF_STATUS wma_twt_process_add_dialog(t_wma_handle *wma_handle, + struct wmi_twt_add_dialog_param *params); + +/** + * wma_twt_process_del_dialog() - Process del dialog command + * @wma_handle: wma handle + * @params: del dialog configuration parameters + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ +QDF_STATUS wma_twt_process_del_dialog(t_wma_handle *wma_handle, + struct wmi_twt_del_dialog_param *params); + +/** + * wma_twt_process_pause_dialog() - Process pause dialog command + * @wma_handle: wma handle + * @params: pause dialog configuration parameters + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ +QDF_STATUS +wma_twt_process_pause_dialog(t_wma_handle *wma_handle, + struct wmi_twt_pause_dialog_cmd_param *params); + +/** + * wma_twt_process_nudge_dialog() - Process nudge dialog command + * @wma_handle: wma handle + * @params: nudge dialog configuration parameters + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ +QDF_STATUS +wma_twt_process_nudge_dialog(t_wma_handle *wma_handle, + struct wmi_twt_nudge_dialog_cmd_param *params); + +/** + * wma_twt_process_resume_dialog() - Process resume dialog command + * @wma_handle: wma handle + * @params: resume dialog configuration parameters + * + * Return: QDF_STATUS_SUCCESS on success, other QDF_STATUS error code + * on failure + */ +QDF_STATUS +wma_twt_process_resume_dialog(t_wma_handle *wma_handle, + struct wmi_twt_resume_dialog_cmd_param *params); + +/** + * wma_update_bcast_twt_support() - update bcost twt support + * @wh: wma handle + * @tgt_cfg: target configuration to be updated + * + * Update braodcast twt support based on service bit. + * + * Return: None + */ +void wma_update_bcast_twt_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg); + +/** + * wma_update_twt_tgt_cap()- update the supported twt capabilities + * @wh: wma handle + * @tgt_cfg: target configuration to be updated + * + * Update support for twt capabilities based on service bit. + * + * Return: None + */ +void wma_update_twt_tgt_cap(tp_wma_handle wh, struct wma_tgt_cfg *tgt_cfg); + +/** + * wma_register_twt_events() - register for TWT wmi events + * @wma_handle : wma handle + * + * Registers the wmi event handlers for TWT. + * + * Return: None + */ +void wma_register_twt_events(tp_wma_handle wma_handle); +#else +static inline void +wma_send_twt_enable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf) +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); +} + +static inline void +wma_send_twt_disable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf) +{ +} + +static inline void wma_set_twt_peer_caps(tpAddStaParams params, + struct peer_assoc_params *cmd) +{ +} + +static inline +QDF_STATUS wma_twt_process_add_dialog(t_wma_handle *wma_handle, + struct wmi_twt_add_dialog_param *params) +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); + + return QDF_STATUS_E_INVAL; +} + +static inline +QDF_STATUS wma_twt_process_del_dialog(t_wma_handle *wma_handle, + struct wmi_twt_del_dialog_param *params) +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); + + return QDF_STATUS_E_INVAL; +} + +static inline QDF_STATUS +wma_twt_process_pause_dialog(t_wma_handle *wma_handle, + struct wmi_twt_pause_dialog_cmd_param *params) +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); + + return QDF_STATUS_E_INVAL; +} + +static inline QDF_STATUS +wma_twt_process_nudge_dialog(t_wma_handle *wma_handle, + struct wmi_twt_nudge_dialog_cmd_param *params) +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); + + return QDF_STATUS_E_INVAL; +} + +static inline QDF_STATUS +wma_twt_process_resume_dialog(t_wma_handle *wma_handle, + struct wmi_twt_resume_dialog_cmd_param *params) +{ + wma_debug("TWT not supported as WLAN_SUPPORT_TWT is disabled"); + + return QDF_STATUS_E_INVAL; +} + +static inline void wma_update_bcast_twt_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg) +{ +} + +static inline +void wma_update_twt_tgt_cap(tp_wma_handle wh, struct wma_tgt_cfg *tgt_cfg) +{ +} +static inline void wma_register_twt_events(tp_wma_handle wma_handle) +{ +} +#endif + +#endif /* __WMA_HE_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_types.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_types.h new file mode 100644 index 0000000000..c22c29ce2f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/inc/wma_types.h @@ -0,0 +1,770 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WLAN_QCT_WMA_H +#define WLAN_QCT_WMA_H + +#include "ani_global.h" + +#include "wma_api.h" +#include "wma_tgt_cfg.h" +#include "i_cds_packet.h" + +#define IS_FEATURE_SUPPORTED_BY_FW(feat_enum_value) \ + wma_get_fw_wlan_feat_caps(feat_enum_value) +#ifdef WLAN_FEATURE_11BE +#define IS_FEATURE_11BE_SUPPORTED_BY_FW IS_FEATURE_SUPPORTED_BY_FW(DOT11BE) +#else +#define IS_FEATURE_11BE_SUPPORTED_BY_FW 0 +#endif + +#define DPU_FEEDBACK_UNPROTECTED_ERROR 0x0F + +#define WMA_GET_QDF_NBUF(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->pkt_qdf_buf) + +#define WMA_GET_RX_MAC_HEADER_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_hdr_len) + +#define WMA_GET_RX_MAC_HEADER(pRxMeta) \ + (tpSirMacMgmtHdr)(((t_packetmeta *)pRxMeta)->mpdu_hdr_ptr) + +#define WMA_GET_RX_MPDUHEADER3A(pRxMeta) \ + (tpSirMacDataHdr3a)(((t_packetmeta *)pRxMeta)->mpdu_hdr_ptr) + +#define WMA_GET_RX_MPDU_HEADER_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_hdr_len) + +#define WMA_GET_RX_MPDU_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_len) + +#define WMA_GET_RX_PAYLOAD_LEN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_data_len) + +#define WMA_GET_RX_TSF_DELTA(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->tsf_delta) + +#define WMA_GET_RX_MAC_RATE_IDX(pRxMeta) 0 + +#define WMA_GET_RX_MPDU_DATA(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->mpdu_data_ptr) + +#define WMA_GET_RX_UNKNOWN_UCAST(pRxMeta) 0 + +#define WMA_GET_RX_FREQ(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->frequency) + +#define WMA_GET_RX_FT_DONE(pRxMeta) 0 + +#define WMA_GET_RX_DPU_FEEDBACK(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->dpuFeedback) + +#define WMA_GET_RX_BEACON_SENT(pRxMeta) 0 + +#define WMA_GET_RX_TSF_LATER(pRxMeta) 0 + +#define WMA_GET_RX_TIMESTAMP(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->timestamp) + +#define WMA_GET_OFFLOADSCANLEARN(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->offloadScanLearn) +#define WMA_GET_ROAMCANDIDATEIND(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->roamCandidateInd) +#define WMA_GET_SESSIONID(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->session_id) +#define WMA_GET_SCAN_SRC(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->scan_src) + +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_IS_EXTSCAN_SCAN_SRC(pRxMeta) \ + ((((t_packetmeta *)pRxMeta)->scan_src) == WMI_MGMT_RX_HDR_EXTSCAN) +#define WMA_IS_EPNO_SCAN_SRC(pRxMeta) \ + ((((t_packetmeta *)pRxMeta)->scan_src) & WMI_MGMT_RX_HDR_ENLO) +#endif /* FEATURE_WLAN_EXTSCAN */ + +#define WMA_GET_RX_SNR(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->snr) + +#define WMA_GET_RX_RFBAND(pRxMeta) 0 + +#define WMA_MAX_TXPOWER_INVALID 127 +/* rssi value normalized to noise floor of -96 dBm */ +#define WMA_GET_RX_RSSI_NORMALIZED(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->rssi) + +/* raw rssi based on actual noise floor in hardware */ +#define WMA_GET_RX_RSSI_RAW(pRxMeta) \ + (((t_packetmeta *)pRxMeta)->rssi_raw) + +/* + * the repeat_cnt is reserved by FW team, the current value + * is always 0xffffffff + */ +#define WMI_WOW_PULSE_REPEAT_CNT 0xffffffff + + +/* WMA Messages */ +enum wmamsgtype { + WMA_MSG_TYPES_BEGIN = SIR_HAL_MSG_TYPES_BEGIN, + WMA_ITC_MSG_TYPES_BEGIN = SIR_HAL_ITC_MSG_TYPES_BEGIN, + WMA_RADAR_DETECTED_IND = SIR_HAL_RADAR_DETECTED_IND, + + WMA_ADD_STA_REQ = SIR_HAL_ADD_STA_REQ, + WMA_ADD_STA_RSP = SIR_HAL_ADD_STA_RSP, + WMA_DELETE_STA_REQ = SIR_HAL_DELETE_STA_REQ, + WMA_DELETE_STA_RSP = SIR_HAL_DELETE_STA_RSP, + WMA_ADD_BSS_REQ = SIR_HAL_ADD_BSS_REQ, + WMA_DELETE_BSS_REQ = SIR_HAL_DELETE_BSS_REQ, + WMA_DELETE_BSS_HO_FAIL_REQ = SIR_HAL_DELETE_BSS_HO_FAIL_REQ, + WMA_DELETE_BSS_RSP = SIR_HAL_DELETE_BSS_RSP, + WMA_DELETE_BSS_HO_FAIL_RSP = SIR_HAL_DELETE_BSS_HO_FAIL_RSP, + WMA_SEND_BEACON_REQ = SIR_HAL_SEND_BEACON_REQ, + WMA_SEND_BCN_RSP = SIR_HAL_SEND_BCN_RSP, + WMA_SEND_PROBE_RSP_TMPL = SIR_HAL_SEND_PROBE_RSP_TMPL, + WMA_SEND_PEER_UNMAP_CONF = SIR_HAL_SEND_PEER_UNMAP_CONF, + + WMA_SET_BSSKEY_RSP = SIR_HAL_SET_BSSKEY_RSP, + WMA_SET_STAKEY_RSP = SIR_HAL_SET_STAKEY_RSP, + WMA_UPDATE_EDCA_PROFILE_IND = SIR_HAL_UPDATE_EDCA_PROFILE_IND, + + WMA_UPDATE_BEACON_IND = SIR_HAL_UPDATE_BEACON_IND, + WMA_CHNL_SWITCH_REQ = SIR_HAL_CHNL_SWITCH_REQ, + WMA_ADD_TS_REQ = SIR_HAL_ADD_TS_REQ, + WMA_DEL_TS_REQ = SIR_HAL_DEL_TS_REQ, + + WMA_MISSED_BEACON_IND = SIR_HAL_MISSED_BEACON_IND, + + WMA_SWITCH_CHANNEL_RSP = SIR_HAL_SWITCH_CHANNEL_RSP, + WMA_P2P_NOA_ATTR_IND = SIR_HAL_P2P_NOA_ATTR_IND, + WMA_PWR_SAVE_CFG = SIR_HAL_PWR_SAVE_CFG, + + WMA_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND = + SIR_HAL_TIMER_ADJUST_ADAPTIVE_THRESHOLD_IND, + WMA_SET_LINK_STATE = SIR_HAL_SET_LINK_STATE, + WMA_SET_STA_BCASTKEY_RSP = SIR_HAL_SET_STA_BCASTKEY_RSP, + WMA_ADD_TS_RSP = SIR_HAL_ADD_TS_RSP, + WMA_DPU_MIC_ERROR = SIR_HAL_DPU_MIC_ERROR, + WMA_TIMER_CHIP_MONITOR_TIMEOUT = SIR_HAL_TIMER_CHIP_MONITOR_TIMEOUT, + WMA_TIMER_TRAFFIC_ACTIVITY_REQ = SIR_HAL_TIMER_TRAFFIC_ACTIVITY_REQ, + WMA_TIMER_ADC_RSSI_STATS = SIR_HAL_TIMER_ADC_RSSI_STATS, + WMA_TIMER_TRAFFIC_STATS_IND = SIR_HAL_TRAFFIC_STATS_IND, + WMA_EXCLUDE_UNENCRYPTED_IND = SIR_HAL_EXCLUDE_UNENCRYPTED_IND, + +#ifdef FEATURE_WLAN_ESE + WMA_TSM_STATS_REQ = SIR_HAL_TSM_STATS_REQ, + WMA_TSM_STATS_RSP = SIR_HAL_TSM_STATS_RSP, +#endif + + WMA_ROAM_SCAN_CH_REQ = SIR_HAL_ROAM_SCAN_CH_REQ, + + WMA_HT40_OBSS_SCAN_IND = SIR_HAL_HT40_OBSS_SCAN_IND, + + WMA_SET_MIMOPS_REQ = SIR_HAL_SET_MIMOPS_REQ, + WMA_SET_MIMOPS_RSP = SIR_HAL_SET_MIMOPS_RSP, + WMA_SYS_READY_IND = SIR_HAL_SYS_READY_IND, + WMA_SET_TX_POWER_REQ = SIR_HAL_SET_TX_POWER_REQ, + WMA_SET_TX_POWER_RSP = SIR_HAL_SET_TX_POWER_RSP, + WMA_GET_TX_POWER_REQ = SIR_HAL_GET_TX_POWER_REQ, + + WMA_ENABLE_UAPSD_REQ = SIR_HAL_ENABLE_UAPSD_REQ, + WMA_DISABLE_UAPSD_REQ = SIR_HAL_DISABLE_UAPSD_REQ, + + WMA_SET_KEY_DONE = SIR_HAL_SET_KEY_DONE, + + + /* PE <-> HAL BTC messages */ + WMA_BTC_SET_CFG = SIR_HAL_BTC_SET_CFG, + WMA_HANDLE_FW_MBOX_RSP = SIR_HAL_HANDLE_FW_MBOX_RSP, + + WMA_SET_MAX_TX_POWER_REQ = SIR_HAL_SET_MAX_TX_POWER_REQ, + WMA_SET_MAX_TX_POWER_RSP = SIR_HAL_SET_MAX_TX_POWER_RSP, + WMA_SET_DTIM_PERIOD = SIR_HAL_SET_DTIM_PERIOD, + + WMA_SET_MAX_TX_POWER_PER_BAND_REQ = + SIR_HAL_SET_MAX_TX_POWER_PER_BAND_REQ, + + /* PE <-> HAL Host Offload message */ + WMA_SET_HOST_OFFLOAD = SIR_HAL_SET_HOST_OFFLOAD, + + /* PE <-> HAL Keep Alive message */ + WMA_SET_KEEP_ALIVE = SIR_HAL_SET_KEEP_ALIVE, + +#ifdef WLAN_NS_OFFLOAD + WMA_SET_NS_OFFLOAD = SIR_HAL_SET_NS_OFFLOAD, +#endif /* WLAN_NS_OFFLOAD */ + +#ifdef FEATURE_WLAN_TDLS + WMA_SET_TDLS_LINK_ESTABLISH_REQ = SIR_HAL_TDLS_LINK_ESTABLISH_REQ, + WMA_SET_TDLS_LINK_ESTABLISH_REQ_RSP = + SIR_HAL_TDLS_LINK_ESTABLISH_REQ_RSP, +#endif + + WMA_WLAN_SUSPEND_IND = SIR_HAL_WLAN_SUSPEND_IND, + WMA_WLAN_RESUME_REQ = SIR_HAL_WLAN_RESUME_REQ, + WMA_MSG_TYPES_END = SIR_HAL_MSG_TYPES_END, + + WMA_AGGR_QOS_REQ = SIR_HAL_AGGR_QOS_REQ, + WMA_AGGR_QOS_RSP = SIR_HAL_AGGR_QOS_RSP, + + WMA_CSA_OFFLOAD_EVENT = SIR_CSA_OFFLOAD_EVENT, + +#ifdef FEATURE_WLAN_ESE + WMA_SET_PLM_REQ = SIR_HAL_SET_PLM_REQ, +#endif + + WMA_ROAM_PRE_AUTH_STATUS = SIR_HAL_ROAM_PRE_AUTH_STATUS_IND, + + WMA_8023_MULTICAST_LIST_REQ = SIR_HAL_8023_MULTICAST_LIST_REQ, + +#ifdef WLAN_FEATURE_PACKET_FILTERING + WMA_RECEIVE_FILTER_SET_FILTER_REQ = + SIR_HAL_RECEIVE_FILTER_SET_FILTER_REQ, + WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ = + SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_REQ, + WMA_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP = + SIR_HAL_PACKET_COALESCING_FILTER_MATCH_COUNT_RSP, + WMA_RECEIVE_FILTER_CLEAR_FILTER_REQ = + SIR_HAL_RECEIVE_FILTER_CLEAR_FILTER_REQ, +#endif /* WLAN_FEATURE_PACKET_FILTERING */ + + WMA_DHCP_START_IND = SIR_HAL_DHCP_START_IND, + WMA_DHCP_STOP_IND = SIR_HAL_DHCP_STOP_IND, + +#ifdef WLAN_FEATURE_GTK_OFFLOAD + WMA_GTK_OFFLOAD_REQ = SIR_HAL_GTK_OFFLOAD_REQ, + WMA_GTK_OFFLOAD_GETINFO_REQ = SIR_HAL_GTK_OFFLOAD_GETINFO_REQ, + WMA_GTK_OFFLOAD_GETINFO_RSP = SIR_HAL_GTK_OFFLOAD_GETINFO_RSP, +#endif /* WLAN_FEATURE_GTK_OFFLOAD */ + + WMA_SET_TM_LEVEL_REQ = SIR_HAL_SET_TM_LEVEL_REQ, + + WMA_UPDATE_OP_MODE = SIR_HAL_UPDATE_OP_MODE, + WMA_UPDATE_RX_NSS = SIR_HAL_UPDATE_RX_NSS, + WMA_UPDATE_MEMBERSHIP = SIR_HAL_UPDATE_MEMBERSHIP, + WMA_UPDATE_USERPOS = SIR_HAL_UPDATE_USERPOS, + +#ifdef WLAN_FEATURE_NAN + WMA_NAN_REQUEST = SIR_HAL_NAN_REQUEST, +#endif + + WMA_UPDATE_CHAN_LIST_REQ = SIR_HAL_UPDATE_CHAN_LIST_REQ, + WMA_RX_SCAN_EVENT = SIR_HAL_RX_SCAN_EVENT, + + WMA_CLI_SET_CMD = SIR_HAL_CLI_SET_CMD, + +#ifndef REMOVE_PKT_LOG + WMA_PKTLOG_ENABLE_REQ = SIR_HAL_PKTLOG_ENABLE_REQ, +#endif + +#ifdef FEATURE_WLAN_LPHB + WMA_LPHB_CONF_REQ = SIR_HAL_LPHB_CONF_IND, +#endif /* FEATURE_WLAN_LPHB */ + +#ifdef FEATURE_WLAN_CH_AVOID + WMA_CH_AVOID_UPDATE_REQ = SIR_HAL_CH_AVOID_UPDATE_REQ, +#endif /* FEATURE_WLAN_CH_AVOID */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + WMA_SET_AUTO_SHUTDOWN_TIMER_REQ = SIR_HAL_SET_AUTO_SHUTDOWN_TIMER_REQ, +#endif + + WMA_ADD_PERIODIC_TX_PTRN_IND = SIR_HAL_ADD_PERIODIC_TX_PTRN_IND, + WMA_DEL_PERIODIC_TX_PTRN_IND = SIR_HAL_DEL_PERIODIC_TX_PTRN_IND, + + WMA_TX_POWER_LIMIT = SIR_HAL_SET_TX_POWER_LIMIT, + + WMA_RATE_UPDATE_IND = SIR_HAL_RATE_UPDATE_IND, + + WMA_SEND_ADDBA_REQ = SIR_HAL_SEND_ADDBA_REQ, + WMA_INIT_THERMAL_INFO_CMD = SIR_HAL_INIT_THERMAL_INFO_CMD, + WMA_SET_THERMAL_LEVEL = SIR_HAL_SET_THERMAL_LEVEL, + + WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD = SIR_HAL_BAD_PEER_TX_CTL_INI_CMD, + +#ifdef FEATURE_WLAN_TDLS + WMA_UPDATE_TDLS_PEER_STATE = SIR_HAL_UPDATE_TDLS_PEER_STATE, + WMA_TDLS_SHOULD_DISCOVER_CMD = SIR_HAL_TDLS_SHOULD_DISCOVER, + WMA_TDLS_SHOULD_TEARDOWN_CMD = SIR_HAL_TDLS_SHOULD_TEARDOWN, + WMA_TDLS_PEER_DISCONNECTED_CMD = SIR_HAL_TDLS_PEER_DISCONNECTED, +#endif + WMA_SET_SAP_INTRABSS_DIS = SIR_HAL_SET_SAP_INTRABSS_DIS, + +/* Message to indicate beacon tx completion after beacon template update + * beacon offload case + */ + WMA_DFS_BEACON_TX_SUCCESS_IND = SIR_HAL_BEACON_TX_SUCCESS_IND, + WMA_DISASSOC_TX_COMP = SIR_HAL_DISASSOC_TX_COMP, + WMA_DEAUTH_TX_COMP = SIR_HAL_DEAUTH_TX_COMP, + + WMA_GET_ISOLATION = SIR_HAL_GET_ISOLATION, + + WMA_MODEM_POWER_STATE_IND = SIR_HAL_MODEM_POWER_STATE_IND, + +#ifdef WLAN_FEATURE_STATS_EXT + WMA_STATS_EXT_REQUEST = SIR_HAL_STATS_EXT_REQUEST, +#endif + + WMA_GET_TEMPERATURE_REQ = SIR_HAL_GET_TEMPERATURE_REQ, + WMA_SET_WISA_PARAMS = SIR_HAL_SET_WISA_PARAMS, + +#ifdef FEATURE_WLAN_EXTSCAN + WMA_EXTSCAN_GET_CAPABILITIES_REQ = SIR_HAL_EXTSCAN_GET_CAPABILITIES_REQ, + WMA_EXTSCAN_START_REQ = SIR_HAL_EXTSCAN_START_REQ, + WMA_EXTSCAN_STOP_REQ = SIR_HAL_EXTSCAN_STOP_REQ, + WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ = + SIR_HAL_EXTSCAN_SET_BSS_HOTLIST_REQ, + WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ = + SIR_HAL_EXTSCAN_RESET_BSS_HOTLIST_REQ, + WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ = SIR_HAL_EXTSCAN_SET_SIGNF_CHANGE_REQ, + WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ = + SIR_HAL_EXTSCAN_RESET_SIGNF_CHANGE_REQ, + WMA_EXTSCAN_GET_CACHED_RESULTS_REQ = + SIR_HAL_EXTSCAN_GET_CACHED_RESULTS_REQ, + WMA_SET_EPNO_LIST_REQ = SIR_HAL_SET_EPNO_LIST_REQ, + WMA_SET_PASSPOINT_LIST_REQ = SIR_HAL_SET_PASSPOINT_LIST_REQ, + WMA_RESET_PASSPOINT_LIST_REQ = SIR_HAL_RESET_PASSPOINT_LIST_REQ, +#endif /* FEATURE_WLAN_EXTSCAN */ + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + WMA_LINK_LAYER_STATS_CLEAR_REQ = SIR_HAL_LL_STATS_CLEAR_REQ, + WMA_LINK_LAYER_STATS_SET_REQ = SIR_HAL_LL_STATS_SET_REQ, + WMA_LINK_LAYER_STATS_GET_REQ = SIR_HAL_LL_STATS_GET_REQ, + WMA_LINK_LAYER_STATS_RESULTS_RSP = SIR_HAL_LL_STATS_RESULTS_RSP, + WDA_LINK_LAYER_STATS_SET_THRESHOLD = SIR_HAL_LL_STATS_EXT_SET_THRESHOLD, +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + WMA_LINK_STATUS_GET_REQ = SIR_HAL_LINK_STATUS_GET_REQ, + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + WMA_WLAN_EXT_WOW = SIR_HAL_CONFIG_EXT_WOW, + WMA_WLAN_SET_APP_TYPE1_PARAMS = SIR_HAL_CONFIG_APP_TYPE1_PARAMS, + WMA_WLAN_SET_APP_TYPE2_PARAMS = SIR_HAL_CONFIG_APP_TYPE2_PARAMS, +#endif + + WMA_SET_SCAN_MAC_OUI_REQ = SIR_HAL_SET_SCAN_MAC_OUI_REQ, + WMA_TSF_GPIO_PIN = SIR_HAL_TSF_GPIO_PIN_REQ, + +#ifdef DHCP_SERVER_OFFLOAD + WMA_SET_DHCP_SERVER_OFFLOAD_CMD = SIR_HAL_SET_DHCP_SERVER_OFFLOAD, +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + WMA_LED_FLASHING_REQ = SIR_HAL_LED_FLASHING_REQ, +#endif + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + WMA_UPDATE_Q2Q_IE_IND = SIR_HAL_UPDATE_Q2Q_IE_IND, +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + WMA_SET_RSSI_MONITOR_REQ = SIR_HAL_SET_RSSI_MONITOR_REQ, + + WMA_OCB_SET_CONFIG_CMD = SIR_HAL_OCB_SET_CONFIG_CMD, + WMA_OCB_SET_UTC_TIME_CMD = SIR_HAL_OCB_SET_UTC_TIME_CMD, + WMA_OCB_START_TIMING_ADVERT_CMD = SIR_HAL_OCB_START_TIMING_ADVERT_CMD, + WMA_OCB_STOP_TIMING_ADVERT_CMD = SIR_HAL_OCB_STOP_TIMING_ADVERT_CMD, + WMA_OCB_GET_TSF_TIMER_CMD = SIR_HAL_OCB_GET_TSF_TIMER_CMD, + WMA_DCC_GET_STATS_CMD = SIR_HAL_DCC_GET_STATS_CMD, + WMA_DCC_CLEAR_STATS_CMD = SIR_HAL_DCC_CLEAR_STATS_CMD, + WMA_DCC_UPDATE_NDL_CMD = SIR_HAL_DCC_UPDATE_NDL_CMD, + WMA_SET_IE_INFO = SIR_HAL_SET_IE_INFO, + + WMA_GW_PARAM_UPDATE_REQ = SIR_HAL_GATEWAY_PARAM_UPDATE_REQ, + WMA_ADD_BCN_FILTER_CMDID = SIR_HAL_ADD_BCN_FILTER_CMDID, + WMA_REMOVE_BCN_FILTER_CMDID = SIR_HAL_REMOVE_BCN_FILTER_CMDID, + WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS = + SIR_HAL_SET_ADAPT_DWELLTIME_PARAMS, + + WDA_APF_GET_CAPABILITIES_REQ = SIR_HAL_APF_GET_CAPABILITIES_REQ, + WMA_ROAM_SYNC_TIMEOUT = SIR_HAL_WMA_ROAM_SYNC_TIMEOUT, + + WMA_SET_PDEV_IE_REQ = SIR_HAL_SET_PDEV_IE_REQ, + WMA_SEND_FREQ_RANGE_CONTROL_IND = SIR_HAL_SEND_FREQ_RANGE_CONTROL_IND, + WMA_POWER_DEBUG_STATS_REQ = SIR_HAL_POWER_DEBUG_STATS_REQ, + WMA_BEACON_DEBUG_STATS_REQ = SIR_HAL_BEACON_DEBUG_STATS_REQ, + WMA_GET_RCPI_REQ = SIR_HAL_GET_RCPI_REQ, + WMA_SET_DBS_SCAN_SEL_CONF_PARAMS = SIR_HAL_SET_DBS_SCAN_SEL_PARAMS, + + WMA_SET_WOW_PULSE_CMD = SIR_HAL_SET_WOW_PULSE_CMD, + + WMA_SEND_AP_VDEV_UP = SIR_HAL_SEND_AP_VDEV_UP, + + WMA_SET_ARP_STATS_REQ = SIR_HAL_SET_ARP_STATS_REQ, + WMA_GET_ARP_STATS_REQ = SIR_HAL_GET_ARP_STATS_REQ, + WMA_SET_LIMIT_OFF_CHAN = SIR_HAL_SET_LIMIT_OFF_CHAN, + WMA_OBSS_DETECTION_REQ = SIR_HAL_OBSS_DETECTION_REQ, + WMA_OBSS_DETECTION_INFO = SIR_HAL_OBSS_DETECTION_INFO, + WMA_INVOKE_NEIGHBOR_REPORT = SIR_HAL_INVOKE_NEIGHBOR_REPORT, + WMA_OBSS_COLOR_COLLISION_REQ = SIR_HAL_OBSS_COLOR_COLLISION_REQ, + WMA_OBSS_COLOR_COLLISION_INFO = SIR_HAL_OBSS_COLOR_COLLISION_INFO, + WMA_CFG_VENDOR_ACTION_TB_PPDU = SIR_HAL_CFG_VENDOR_ACTION_TB_PPDU, + WMA_GET_ROAM_SCAN_STATS = SIR_HAL_GET_ROAM_SCAN_STATS, + +#ifdef WLAN_FEATURE_MOTION_DETECTION + WMA_SET_MOTION_DET_CONFIG = SIR_HAL_SET_MOTION_DET_CONFIG, + WMA_SET_MOTION_DET_ENABLE = SIR_HAL_SET_MOTION_DET_ENABLE, + WMA_SET_MOTION_DET_BASE_LINE_CONFIG = + SIR_HAL_SET_MOTION_DET_BASE_LINE_CONFIG, + WMA_SET_MOTION_DET_BASE_LINE_ENABLE = + SIR_HAL_SET_MOTION_DET_BASE_LINE_ENABLE, +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +#ifdef FW_THERMAL_THROTTLE_SUPPORT + WMA_SET_THERMAL_THROTTLE_CFG = SIR_HAL_SET_THERMAL_THROTTLE_CFG, + WMA_SET_THERMAL_MGMT = SIR_HAL_SET_THERMAL_MGMT, +#endif /*FW_THERMAL_THROTTLE_SUPPORT */ + +#ifdef WLAN_MWS_INFO_DEBUGFS + WMA_GET_MWS_COEX_INFO_REQ = SIR_HAL_GET_MWS_COEX_INFO_REQ, +#endif + + WMA_TWT_ADD_DIALOG_REQUEST = SIR_HAL_TWT_ADD_DIALOG_REQUEST, + WMA_TWT_DEL_DIALOG_REQUEST = SIR_HAL_TWT_DEL_DIALOG_REQUEST, + WMA_TWT_PAUSE_DIALOG_REQUEST = SIR_HAL_TWT_PAUSE_DIALOG_REQUEST, + WMA_TWT_RESUME_DIALOG_REQUEST = SIR_HAL_TWT_RESUME_DIALOG_REQUEST, + WMA_PEER_CREATE_REQ = SIR_HAL_PEER_CREATE_REQ, + WMA_TWT_NUDGE_DIALOG_REQUEST = SIR_HAL_TWT_NUDGE_DIALOG_REQUEST, + WMA_PASN_PEER_DELETE_REQUEST = SIR_HAL_PASN_PEER_DELETE_REQUEST, + WMA_UPDATE_EDCA_PIFS_PARAM_IND = SIR_HAL_UPDATE_EDCA_PIFS_PARAM_IND, +}; + +/* Bit 6 will be used to control BD rate for Management frames */ +#define HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME 0x40 + +#define wma_tx_frame(hHal, pFrmBuf, frmLen, frmType, txDir, tid, pCompFunc, \ + pData, txFlag, sessionid, channel_freq, rid, peer_rssi) \ + (QDF_STATUS)( wma_tx_packet( \ + cds_get_context(QDF_MODULE_ID_WMA), \ + (pFrmBuf), \ + (frmLen), \ + (frmType), \ + (txDir), \ + (tid), \ + (pCompFunc), \ + (pData), \ + (NULL), \ + (txFlag), \ + (sessionid), \ + (false), \ + (channel_freq), \ + (rid), \ + (peer_rssi), \ + (0))) + +#define wma_tx_frameWithTxComplete(hHal, pFrmBuf, frmLen, frmType, txDir, tid, \ + pCompFunc, pData, pCBackFnTxComp, txFlag, sessionid, \ + tdlsflag, channel_freq, rid, peer_rssi, action) \ + (QDF_STATUS)( wma_tx_packet( \ + cds_get_context(QDF_MODULE_ID_WMA), \ + (pFrmBuf), \ + (frmLen), \ + (frmType), \ + (txDir), \ + (tid), \ + (pCompFunc), \ + (pData), \ + (pCBackFnTxComp), \ + (txFlag), \ + (sessionid), \ + (tdlsflag), \ + (channel_freq), \ + (rid), \ + (peer_rssi), \ + (action))) + +/** + * struct sUapsd_Params - Powersave Offload Changes + * @bkDeliveryEnabled: BK delivery enabled flag + * @beDeliveryEnabled: BE delivery enabled flag + * @viDeliveryEnabled: VI delivery enabled flag + * @voDeliveryEnabled: VO delivery enabled flag + * @bkTriggerEnabled: BK trigger enabled flag + * @beTriggerEnabled: BE trigger enabled flag + * @viTriggerEnabled: VI trigger enabled flag + * @voTriggerEnabled: VO trigger enabled flag + */ +typedef struct sUapsd_Params { + uint8_t bkDeliveryEnabled:1; + uint8_t beDeliveryEnabled:1; + uint8_t viDeliveryEnabled:1; + uint8_t voDeliveryEnabled:1; + uint8_t bkTriggerEnabled:1; + uint8_t beTriggerEnabled:1; + uint8_t viTriggerEnabled:1; + uint8_t voTriggerEnabled:1; + bool enable_ps; +} tUapsd_Params, *tpUapsd_Params; + +/** + * struct sEnablePsParams - Enable PowerSave Params + * @psSetting: power save setting + * @uapsdParams: UAPSD Parameters + * @sessionid: sme session id / vdev id + */ +typedef struct sEnablePsParams { + tSirAddonPsReq psSetting; + tUapsd_Params uapsdParams; + uint32_t sessionid; +} tEnablePsParams, *tpEnablePsParams; + +/** + * struct sDisablePsParams - Disable PowerSave Params + * @psSetting: power save setting + * @sessionid: sme session id / vdev id + */ +typedef struct sDisablePsParams { + tSirAddonPsReq psSetting; + uint32_t sessionid; +} tDisablePsParams, *tpDisablePsParams; + +/** + * struct sEnableUapsdParams - Enable Uapsd Params + * @uapsdParams: UAPSD parameters + * @bssid: mac address + * @sessionid: sme session id/ vdev id + * @status: success/failure + */ +typedef struct sEnableUapsdParams { + tUapsd_Params uapsdParams; + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tEnableUapsdParams, *tpEnableUapsdParams; + +/** + * struct sDisableUapsdParams - Disable Uapsd Params + * @bssid: mac address + * @sessionid: sme session id/ vdev id + * @status: success/failure + */ +typedef struct sDisableUapsdParams { + tSirMacAddr bssid; + uint32_t sessionid; + uint32_t status; +} tDisableUapsdParams, *tpDisableUapsdParams; + +/** + * wma_tx_dwnld_comp_callback - callback function for TX dwnld complete + * @context: global mac pointer + * @buf: buffer + * @bFreeData: to free/not free the buffer + * + * callback function for mgmt tx download completion. + * + * Return: QDF_STATUS_SUCCESS in case of success + */ +typedef QDF_STATUS (*wma_tx_dwnld_comp_callback)(void *context, qdf_nbuf_t buf, + bool bFreeData); + +/** + * wma_tx_ota_comp_callback - callback function for TX complete + * @context: global mac pointer + * @buf: buffer + * @status: tx completion status + * @params: tx completion params + * + * callback function for mgmt tx ota completion. + * + * Return: QDF_STATUS_SUCCESS in case of success + */ +typedef QDF_STATUS (*wma_tx_ota_comp_callback)(void *context, qdf_nbuf_t buf, + uint32_t status, void *params); + +/* generic callback for updating parameters from target to HDD */ +typedef int (*wma_tgt_cfg_cb)(hdd_handle_t handle, struct wma_tgt_cfg *cfg); + +/** + * struct wma_cli_set_cmd_t - set command parameters + * @param_id: parameter id + * @param_value: parameter value + * @param_sec_value: parameter sec value + * @param_vdev_id: parameter vdev id + * @param_vp_dev: is it per vdev/pdev + */ +typedef struct { + uint32_t param_id; + uint32_t param_value; + uint32_t param_sec_value; + uint32_t param_vdev_id; + uint32_t param_vp_dev; +} wma_cli_set_cmd_t; + +enum rateid { + RATEID_1MBPS = 0, + RATEID_2MBPS, + RATEID_5_5MBPS, + RATEID_11MBPS, + RATEID_6MBPS, + RATEID_9MBPS, + RATEID_12MBPS, + RATEID_18MBPS, + RATEID_24MBPS, + RATEID_36MBPS, + RATEID_48MBPS = 10, + RATEID_54MBPS, + RATEID_DEFAULT +}; + +QDF_STATUS wma_post_ctrl_msg(struct mac_context *mac, struct scheduler_msg *pMsg); + +QDF_STATUS u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb); + +QDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps); +QDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req); + +/** + * wma_get_rx_retry_cnt() - API to get rx retry count from data path + * @mac: pointer to mac context + * @vdev_id: vdev id + * @mac_addr: mac address of the remote station + * + * Return: none + */ +void wma_get_rx_retry_cnt(struct mac_context *mac, uint8_t vdev_id, + uint8_t *mac_addr); + +/** + * wma_set_wlm_latency_level() - set latency level to FW + * @wma_ptr: wma handle + * @latency_params: latency params + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_wlm_latency_level(void *wma_ptr, + struct wlm_latency_level_param *latency_params); + +/** + * wma_ds_peek_rx_packet_info() - peek rx packet info + * @pkt: packet + * @pkt_meta: packet meta + * + * Function fills the rx packet meta info from the the cds packet + * + * Return: QDF status + */ +QDF_STATUS wma_ds_peek_rx_packet_info(cds_pkt_t *pkt, void **pkt_meta); + +/** + * wma_tx_abort() - abort tx + * @vdev_id: vdev id + * + * In case of deauth host abort transmitting packet. + * + * Return: none + */ +void wma_tx_abort(uint8_t vdev_id); + +/** + * wma_tx_packet() - Sends Tx Frame to TxRx + * @wma_context: wma context + * @tx_frame: frame buffer + * @frmLen: frame length + * @frmType: frame type + * @txDir: tx diection + * @tid: TID + * @tx_frm_download_comp_cb: tx download callback handler + * @pData: tx packet + * @tx_frm_ota_comp_cb: OTA completion handler + * @tx_flag: tx flag + * @vdev_id: vdev id + * @tdls_flag: tdls flag + * @channel_freq: channel frequency + * @rid: rate id + * @peer_rssi: peer RSSI value + * @action: action code + * + * This function sends the frame corresponding to the + * given vdev id. + * This is blocking call till the downloading of frame is complete. + * + * Return: QDF status + */ +QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, + eFrameType frmType, eFrameTxDir txDir, uint8_t tid, + wma_tx_dwnld_comp_callback tx_frm_download_comp_cb, + void *pData, + wma_tx_ota_comp_callback tx_frm_ota_comp_cb, + uint8_t tx_flag, uint8_t vdev_id, bool tdls_flag, + uint16_t channel_freq, enum rateid rid, + int8_t peer_rssi, uint16_t action); + +/** + * wma_open() - Allocate wma context and initialize it. + * @psoc: Psoc pointer + * @pTgtUpdCB: tgt config update callback fun + * @cds_cfg: mac parameters + * @target_type: Target type + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, + wma_tgt_cfg_cb pTgtUpdCB, struct cds_config_info *cds_cfg, + uint32_t target_type); + +/** + * wma_vdev_init() - initialize a wma vdev + * @vdev: the vdev to initialize + * + * Return: None + */ +void wma_vdev_init(struct wma_txrx_node *vdev); + +/** + * wma_vdev_deinit() - de-initialize a wma vdev + * @vdev: the vdev to de-initialize + * + * Return: None + */ +void wma_vdev_deinit(struct wma_txrx_node *vdev); + +QDF_STATUS wma_register_mgmt_frm_client(void); + +QDF_STATUS wma_de_register_mgmt_frm_client(void); +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wma_register_roaming_callbacks( + QDF_STATUS (*csr_roam_auth_event_handle_cb)( + struct mac_context *mac, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm), + pe_roam_synch_fn_t pe_roam_synch_cb, + QDF_STATUS (*pe_disconnect_cb) (struct mac_context *mac, + uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code), + set_ies_fn_t pe_roam_set_ie_cb); +#else +static inline QDF_STATUS wma_register_roaming_callbacks( + QDF_STATUS (*csr_roam_auth_event_handle_cb)( + struct mac_context *mac, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm), + pe_roam_synch_fn_t pe_roam_synch_cb, + QDF_STATUS (*pe_disconnect_cb) (struct mac_context *mac, + uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code), + set_ies_fn_t pe_roam_set_ie_cb) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c new file mode 100644 index 0000000000..ce05f2df4e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wlan_qct_wma_legacy.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_qct_wma_legacy.c + * + * This software unit holds the implementation of the WLAN Device Adaptation + * Layer for the legacy functionalities that were part of the old HAL. + * + * The functions externalized by this module are to be called ONLY by other + * WLAN modules that properly register with the Transport Layer initially. + * + */ + +/* Standard include files */ +/* Application Specific include files */ +#include "lim_api.h" +#include "wma.h" +#include "sme_power_save_api.h" +/* Locally used Defines */ + +#define HAL_MMH_MB_MSG_TYPE_MASK 0xFF00 + +/** + * wma_post_ctrl_msg() - Posts WMA messages to MC thread + * @mac: MAC parameters structure + * @pMsg: pointer with message + * + * Return: Success or Failure + */ + +QDF_STATUS wma_post_ctrl_msg(struct mac_context *mac, struct scheduler_msg *pMsg) +{ + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, pMsg)) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} + +/** + * u_mac_post_ctrl_msg() - post ctrl msg + * @pMb: A pointer to the mailbox message + * + * Forwards the completely received message to the respective + * modules for further processing. + * + * NOTE: + * This function has been moved to the API file because for MAC running + * on Windows host, the host module will call this routine directly to + * send any mailbox messages. Making this function an API makes sure that + * outside world (any module outside MMH) only calls APIs to use MMH + * services and not an internal function. + * + * Return: success/error code + */ + +QDF_STATUS u_mac_post_ctrl_msg(void *pSirGlobal, tSirMbMsg *pMb) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = (struct mac_context *) pSirGlobal; + + msg.type = pMb->type; + msg.bodyval = 0; + msg.bodyptr = pMb; + + switch (msg.type & HAL_MMH_MB_MSG_TYPE_MASK) { + case WMA_MSG_TYPES_BEGIN: /* Posts a message to the HAL MsgQ */ + status = wma_post_ctrl_msg(mac, &msg); + break; + + case SIR_LIM_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + status = lim_post_msg_api(mac, &msg); + break; + + case SIR_SME_MSG_TYPES_BEGIN: /* Posts a message to the LIM MsgQ */ + status = sme_post_pe_message(mac, &msg); + break; + + default: + wma_debug("Unknown message type = 0x%X", msg.type); + qdf_mem_free(msg.bodyptr); + return QDF_STATUS_E_FAILURE; + } + + if (status != QDF_STATUS_SUCCESS) + qdf_mem_free(msg.bodyptr); + + return status; + +} /* u_mac_post_ctrl_msg() */ + +QDF_STATUS umac_send_mb_message_to_mac(void *msg) +{ + void *mac_handle = cds_get_context(QDF_MODULE_ID_SME); + + if (!mac_handle) { + qdf_mem_free(msg); + return QDF_STATUS_E_FAILURE; + } + + return u_mac_post_ctrl_msg(mac_handle, msg); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_coex.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_coex.c new file mode 100644 index 0000000000..8b04d6bbf2 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_coex.c @@ -0,0 +1,375 @@ + +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include "wmi_unified.h" + +/** + * wma_mws_coex_state_host_event_handler - Coex state Event Handler + * @handle: pointer to scn handle + * @event: Coex state event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +static int wma_mws_coex_state_host_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_VDEV_GET_MWS_COEX_STATE_EVENTID_param_tlvs *param_tlvs; + wmi_vdev_get_mws_coex_state_fixed_param *param_buf; + struct mws_coex_state coex_state; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + wma_debug("Enter"); + param_tlvs = + (WMI_VDEV_GET_MWS_COEX_STATE_EVENTID_param_tlvs *)event; + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + param_buf = param_tlvs->fixed_param; + if (!param_buf || !mac || !mac->sme.mws_coex_info_state_resp_callback) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + if (!param_buf) { + wma_debug("NULL mws coes state event fixed param"); + return -EINVAL; + } + + coex_state.vdev_id = param_buf->vdev_id; + coex_state.coex_scheme_bitmap = param_buf->coex_scheme_bitmap; + coex_state.active_conflict_count = param_buf->active_conflict_count; + coex_state.potential_conflict_count = + param_buf->potential_conflict_count; + coex_state.chavd_group0_bitmap = param_buf->chavd_group0_bitmap; + coex_state.chavd_group1_bitmap = param_buf->chavd_group1_bitmap; + coex_state.chavd_group2_bitmap = param_buf->chavd_group2_bitmap; + coex_state.chavd_group3_bitmap = param_buf->chavd_group3_bitmap; + mac->sme.mws_coex_info_state_resp_callback(&coex_state, + mac->sme.mws_coex_info_ctx, + WMI_MWS_COEX_STATE); + wma_debug("vdev_id = %u coex_scheme_bitmap = %u active_conflict_count = %u potential_conflict_count = %u chavd_group0_bitmap = %u chavd_group1_bitmap = %u chavd_group2_bitmap = %u chavd_group3_bitmap = %u", + param_buf->vdev_id, param_buf->coex_scheme_bitmap, + param_buf->active_conflict_count, + param_buf->potential_conflict_count, + param_buf->chavd_group0_bitmap, + param_buf->chavd_group1_bitmap, + param_buf->chavd_group2_bitmap, + param_buf->chavd_group3_bitmap); + + wma_debug("Exit"); + return 0; +} + +/** + * wma_mws_coex_state_dpwb_event_handler - DPWB state Event Handler + * @handle: handle to scn + * @event: DPWB state event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +static int wma_mws_coex_state_dpwb_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_VDEV_GET_MWS_COEX_DPWB_STATE_EVENTID_param_tlvs *param_tlvs; + wmi_vdev_get_mws_coex_dpwb_state_fixed_param *param_buf; + struct mws_coex_dpwb_state coex_dpwb; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + wma_debug("Enter"); + param_tlvs = + (WMI_VDEV_GET_MWS_COEX_DPWB_STATE_EVENTID_param_tlvs *)event; + if (!param_tlvs) { + wma_err("Invalid coex mws event"); + return -EINVAL; + } + + param_buf = param_tlvs->fixed_param; + if (!param_buf || !mac || !mac->sme.mws_coex_info_state_resp_callback) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + if (!param_buf) { + wma_err("NULL mws dpwb info event fixed param"); + return -EINVAL; + } + + coex_dpwb.vdev_id = param_buf->vdev_id; + coex_dpwb.current_dpwb_state = param_buf->current_dpwb_state; + coex_dpwb.pnp1_value = param_buf->pnp1_value; + coex_dpwb.lte_dutycycle = param_buf->lte_dutycycle; + coex_dpwb.sinr_wlan_on = param_buf->sinr_wlan_on; + coex_dpwb.sinr_wlan_off = param_buf->sinr_wlan_off; + coex_dpwb.bler_count = param_buf->bler_count; + coex_dpwb.block_count = param_buf->block_count; + coex_dpwb.wlan_rssi_level = param_buf->wlan_rssi_level; + coex_dpwb.wlan_rssi = param_buf->wlan_rssi; + coex_dpwb.is_tdm_running = param_buf->is_tdm_running; + mac->sme.mws_coex_info_state_resp_callback(&coex_dpwb, + mac->sme.mws_coex_info_ctx, + WMI_MWS_COEX_DPWB_STATE); + wma_debug("vdev_id = %u current_dpwb_state = %d pnp1_value = %d lte_dutycycle = %d sinr_wlan_on = %d sinr_wlan_off = %d bler_count = %u block_count = %u wlan_rssi_level = %u wlan_rssi = %d is_tdm_running = %u", + param_buf->vdev_id, param_buf->current_dpwb_state, + param_buf->pnp1_value, + param_buf->lte_dutycycle, param_buf->sinr_wlan_on, + param_buf->sinr_wlan_off, param_buf->bler_count, + param_buf->block_count, param_buf->wlan_rssi_level, + param_buf->wlan_rssi, param_buf->is_tdm_running); + + wma_debug("Exit"); + return 0; +} + +/** + * wma_mws_coex_tdm_event_handler - TDM state Event Handler + * @handle: handle to scn + * @event: TDM state event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +static int wma_mws_coex_tdm_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_VDEV_GET_MWS_COEX_TDM_STATE_EVENTID_param_tlvs *param_tlvs; + wmi_vdev_get_mws_coex_tdm_state_fixed_param *param_buf; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct mws_coex_tdm_state coex_tdm; + + wma_debug("Enter"); + param_tlvs = + (WMI_VDEV_GET_MWS_COEX_TDM_STATE_EVENTID_param_tlvs *)event; + if (!param_tlvs) { + wma_err("Invalid MWS coex event"); + return -EINVAL; + } + + param_buf = param_tlvs->fixed_param; + if (!param_buf || !mac || !mac->sme.mws_coex_info_state_resp_callback) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + if (!param_buf) { + wma_debug("NULL mws tdm info event fixed param"); + return -EINVAL; + } + + coex_tdm.vdev_id = param_buf->vdev_id; + coex_tdm.tdm_policy_bitmap = param_buf->tdm_policy_bitmap; + coex_tdm.tdm_sf_bitmap = param_buf->tdm_sf_bitmap; + + mac->sme.mws_coex_info_state_resp_callback(&coex_tdm, + mac->sme.mws_coex_info_ctx, + WMI_MWS_COEX_TDM_STATE); + wma_debug("vdev_id = %u tdm_policy_bitmap = %u tdm_sf_bitmap = %u", + param_buf->vdev_id, param_buf->tdm_policy_bitmap, + param_buf->tdm_sf_bitmap); + + wma_debug("Exit"); + return 0; +} + +/** + * wma_mws_coex_idrx_event_handler - IDRX state Event Handler + * @handle: handle to scn + * @event: IDRX state event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +static int wma_mws_coex_idrx_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + WMI_VDEV_GET_MWS_COEX_IDRX_STATE_EVENTID_param_tlvs *param_tlvs; + wmi_vdev_get_mws_coex_idrx_state_fixed_param *param_buf; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct mws_coex_idrx_state coex_idrx; + + wma_debug("Enter"); + param_tlvs = + (WMI_VDEV_GET_MWS_COEX_IDRX_STATE_EVENTID_param_tlvs *)event; + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + param_buf = param_tlvs->fixed_param; + if (!param_buf || !mac || !mac->sme.mws_coex_info_state_resp_callback) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + if (!param_buf) { + wma_debug("NULL MWS Coex event fixed param"); + return -EINVAL; + } + + coex_idrx.vdev_id = param_buf->vdev_id; + coex_idrx.sub0_techid = param_buf->sub0_techid; + coex_idrx.sub0_policy = param_buf->sub0_policy; + coex_idrx.sub0_is_link_critical = param_buf->sub0_is_link_critical; + coex_idrx.sub0_static_power = param_buf->sub0_static_power; + coex_idrx.sub0_rssi = param_buf->sub0_rssi; + coex_idrx.sub1_techid = param_buf->sub1_techid; + coex_idrx.sub1_policy = param_buf->sub1_policy; + coex_idrx.sub1_is_link_critical = param_buf->sub1_is_link_critical; + coex_idrx.sub1_static_power = param_buf->sub1_static_power; + coex_idrx.sub1_rssi = param_buf->sub1_rssi; + mac->sme.mws_coex_info_state_resp_callback(&coex_idrx, + mac->sme.mws_coex_info_ctx, + WMI_MWS_COEX_IDRX_STATE); + + wma_debug("vdev_id = %u sub0_techid = %u sub0_policy = %u sub0_is_link_critical = %u sub0_static_power = %u sub0_rssi = %d sub1_techid = %d sub1_policy = %d sub1_is_link_critical = %d sub1_static_power = %u sub1_rssi= %d", + param_buf->vdev_id, param_buf->sub0_techid, + param_buf->sub0_policy, param_buf->sub0_is_link_critical, + param_buf->sub0_static_power, param_buf->sub0_rssi, + param_buf->sub1_techid, param_buf->sub1_policy, + param_buf->sub1_is_link_critical, + param_buf->sub1_static_power, param_buf->sub1_rssi); + + wma_debug("EXIT"); + return 0; +} + +/** + * wma_mws_coex_antenna_sharing_event_handler - Antenna sharing Event Handler + * @handle: handle to scn + * @event: Antenna sharing state event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +static int wma_mws_coex_antenna_sharing_event_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_VDEV_GET_MWS_COEX_ANTENNA_SHARING_STATE_EVENTID_param_tlvs + *param_tlvs = + (WMI_VDEV_GET_MWS_COEX_ANTENNA_SHARING_STATE_EVENTID_param_tlvs *)event; + wmi_vdev_get_mws_coex_antenna_sharing_state_fixed_param *param_buf; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct mws_antenna_sharing_info *antenna_sharing; + + wma_debug("Enter"); + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + param_buf = param_tlvs->fixed_param; + if (!param_buf || !mac || !mac->sme.mws_coex_info_state_resp_callback) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + if (!param_buf) { + wma_debug("NULL MWS event fixed param"); + return -EINVAL; + } + + antenna_sharing = qdf_mem_malloc(sizeof(*antenna_sharing)); + if (!antenna_sharing) + return -ENOMEM; + + antenna_sharing->vdev_id = param_buf->vdev_id; + antenna_sharing->coex_flags = param_buf->coex_flags; + antenna_sharing->coex_config = param_buf->coex_config; + antenna_sharing->tx_chain_mask = param_buf->tx_chain_mask; + antenna_sharing->rx_chain_mask = param_buf->rx_chain_mask; + antenna_sharing->rx_nss = param_buf->rx_nss; + antenna_sharing->force_mrc = param_buf->force_mrc; + antenna_sharing->rssi_type = param_buf->rssi_type; + antenna_sharing->chain0_rssi = param_buf->chain0_rssi; + antenna_sharing->chain1_rssi = param_buf->chain1_rssi; + antenna_sharing->combined_rssi = param_buf->combined_rssi; + antenna_sharing->imbalance = param_buf->imbalance; + antenna_sharing->mrc_threshold = param_buf->mrc_threshold; + antenna_sharing->grant_duration = param_buf->grant_duration; + + mac->sme.mws_coex_info_state_resp_callback(antenna_sharing, + mac->sme.mws_coex_info_ctx, + WMI_MWS_COEX_ANTENNA_SHARING_STATE); + wma_debug("vdev_id = %u coex_flags = %u coex_config = %u tx_chain_mask = %u rx_chain_mask = %u rx_nss = %u force_mrc = %u rssi_type = %u chain0_rssi = %d chain1_rssi = %d chain0_rssi = %d imbalance = %u mrc_threshold = %d grant_duration = %u", + param_buf->vdev_id, param_buf->coex_flags, + param_buf->coex_config, param_buf->tx_chain_mask, + param_buf->rx_chain_mask, + param_buf->rx_nss, param_buf->force_mrc, + param_buf->rssi_type, param_buf->chain0_rssi, + param_buf->chain1_rssi, param_buf->combined_rssi, + param_buf->imbalance, param_buf->mrc_threshold, + param_buf->grant_duration); + + qdf_mem_free(antenna_sharing); + wma_debug("EXIT"); + return 0; +} + +void wma_get_mws_coex_info_req(tp_wma_handle wma_handle, + struct sir_get_mws_coex_info *req) +{ + QDF_STATUS status; + + status = wmi_unified_send_mws_coex_req_cmd(wma_handle->wmi_handle, + req->vdev_id, req->cmd_id); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send mws coex info"); +} + +void wma_register_mws_coex_events(tp_wma_handle wma_handle) +{ + if (wma_validate_handle(wma_handle)) + return; + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_get_mws_coex_state_eventid, + wma_mws_coex_state_host_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_vdev_get_mws_coex_dpwb_state_eventid, + wma_mws_coex_state_dpwb_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_vdev_get_mws_coex_tdm_state_eventid, + wma_mws_coex_tdm_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_vdev_get_mws_coex_idrx_state_eventid, + wma_mws_coex_idrx_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_vdev_get_mws_coex_antenna_sharing_state_eventid, + wma_mws_coex_antenna_sharing_event_handler, + WMA_RX_SERIALIZER_CTX); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_data.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_data.c new file mode 100644 index 0000000000..bd08cfc4b3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_data.c @@ -0,0 +1,3213 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_data.c + * This file contains tx/rx and data path related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "enet.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "qdf_util.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "wma_internal.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "cdp_txrx_cmn.h" +#include "cdp_txrx_misc.h" +#include +#include +#include "cdp_txrx_stats.h" +#include +#include "wlan_mgmt_txrx_utils_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_objmgr_peer_obj.h" +#include +#include "cfg_ucfg_api.h" +#include "wlan_policy_mgr_ucfg.h" +#include +#include "wlan_lmac_if_api.h" +#include +#include +#include +#include +#include "wlan_pkt_capture_ucfg_api.h" +#include "wma_eht.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_fw_offload_main.h" +#include "target_if_fwol.h" + +struct wma_search_rate { + int32_t rate; + uint8_t flag; +}; + +#define WMA_MAX_OFDM_CCK_RATE_TBL_SIZE 12 +/* In ofdm_cck_rate_tbl->flag, if bit 7 is 1 it's CCK, otherwise it ofdm. + * Lower bit carries the ofdm/cck index for encoding the rate + */ +static struct wma_search_rate ofdm_cck_rate_tbl[WMA_MAX_OFDM_CCK_RATE_TBL_SIZE] = { + {540, 4}, /* 4: OFDM 54 Mbps */ + {480, 0}, /* 0: OFDM 48 Mbps */ + {360, 5}, /* 5: OFDM 36 Mbps */ + {240, 1}, /* 1: OFDM 24 Mbps */ + {180, 6}, /* 6: OFDM 18 Mbps */ + {120, 2}, /* 2: OFDM 12 Mbps */ + {110, (1 << 7)}, /* 0: CCK 11 Mbps Long */ + {90, 7}, /* 7: OFDM 9 Mbps */ + {60, 3}, /* 3: OFDM 6 Mbps */ + {55, ((1 << 7) | 1)}, /* 1: CCK 5.5 Mbps Long */ + {20, ((1 << 7) | 2)}, /* 2: CCK 2 Mbps Long */ + {10, ((1 << 7) | 3)} /* 3: CCK 1 Mbps Long */ +}; + +#define WMA_MAX_VHT20_RATE_TBL_SIZE 9 +/* In vht20_400ns_rate_tbl flag carries the mcs index for encoding the rate */ +static struct wma_search_rate vht20_400ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = { + {867, 8}, /* MCS8 1SS short GI */ + {722, 7}, /* MCS7 1SS short GI */ + {650, 6}, /* MCS6 1SS short GI */ + {578, 5}, /* MCS5 1SS short GI */ + {433, 4}, /* MCS4 1SS short GI */ + {289, 3}, /* MCS3 1SS short GI */ + {217, 2}, /* MCS2 1SS short GI */ + {144, 1}, /* MCS1 1SS short GI */ + {72, 0} /* MCS0 1SS short GI */ +}; + +/* In vht20_800ns_rate_tbl flag carries the mcs index for encoding the rate */ +static struct wma_search_rate vht20_800ns_rate_tbl[WMA_MAX_VHT20_RATE_TBL_SIZE] = { + {780, 8}, /* MCS8 1SS long GI */ + {650, 7}, /* MCS7 1SS long GI */ + {585, 6}, /* MCS6 1SS long GI */ + {520, 5}, /* MCS5 1SS long GI */ + {390, 4}, /* MCS4 1SS long GI */ + {260, 3}, /* MCS3 1SS long GI */ + {195, 2}, /* MCS2 1SS long GI */ + {130, 1}, /* MCS1 1SS long GI */ + {65, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_VHT40_RATE_TBL_SIZE 10 +/* In vht40_400ns_rate_tbl flag carries the mcs index for encoding the rate */ +static struct wma_search_rate vht40_400ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = { + {2000, 9}, /* MCS9 1SS short GI */ + {1800, 8}, /* MCS8 1SS short GI */ + {1500, 7}, /* MCS7 1SS short GI */ + {1350, 6}, /* MCS6 1SS short GI */ + {1200, 5}, /* MCS5 1SS short GI */ + {900, 4}, /* MCS4 1SS short GI */ + {600, 3}, /* MCS3 1SS short GI */ + {450, 2}, /* MCS2 1SS short GI */ + {300, 1}, /* MCS1 1SS short GI */ + {150, 0}, /* MCS0 1SS short GI */ +}; + +static struct wma_search_rate vht40_800ns_rate_tbl[WMA_MAX_VHT40_RATE_TBL_SIZE] = { + {1800, 9}, /* MCS9 1SS long GI */ + {1620, 8}, /* MCS8 1SS long GI */ + {1350, 7}, /* MCS7 1SS long GI */ + {1215, 6}, /* MCS6 1SS long GI */ + {1080, 5}, /* MCS5 1SS long GI */ + {810, 4}, /* MCS4 1SS long GI */ + {540, 3}, /* MCS3 1SS long GI */ + {405, 2}, /* MCS2 1SS long GI */ + {270, 1}, /* MCS1 1SS long GI */ + {135, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_VHT80_RATE_TBL_SIZE 10 +static struct wma_search_rate vht80_400ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = { + {4333, 9}, /* MCS9 1SS short GI */ + {3900, 8}, /* MCS8 1SS short GI */ + {3250, 7}, /* MCS7 1SS short GI */ + {2925, 6}, /* MCS6 1SS short GI */ + {2600, 5}, /* MCS5 1SS short GI */ + {1950, 4}, /* MCS4 1SS short GI */ + {1300, 3}, /* MCS3 1SS short GI */ + {975, 2}, /* MCS2 1SS short GI */ + {650, 1}, /* MCS1 1SS short GI */ + {325, 0} /* MCS0 1SS short GI */ +}; + +static struct wma_search_rate vht80_800ns_rate_tbl[WMA_MAX_VHT80_RATE_TBL_SIZE] = { + {3900, 9}, /* MCS9 1SS long GI */ + {3510, 8}, /* MCS8 1SS long GI */ + {2925, 7}, /* MCS7 1SS long GI */ + {2633, 6}, /* MCS6 1SS long GI */ + {2340, 5}, /* MCS5 1SS long GI */ + {1755, 4}, /* MCS4 1SS long GI */ + {1170, 3}, /* MCS3 1SS long GI */ + {878, 2}, /* MCS2 1SS long GI */ + {585, 1}, /* MCS1 1SS long GI */ + {293, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_HT20_RATE_TBL_SIZE 8 +static struct wma_search_rate ht20_400ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = { + {722, 7}, /* MCS7 1SS short GI */ + {650, 6}, /* MCS6 1SS short GI */ + {578, 5}, /* MCS5 1SS short GI */ + {433, 4}, /* MCS4 1SS short GI */ + {289, 3}, /* MCS3 1SS short GI */ + {217, 2}, /* MCS2 1SS short GI */ + {144, 1}, /* MCS1 1SS short GI */ + {72, 0} /* MCS0 1SS short GI */ +}; + +static struct wma_search_rate ht20_800ns_rate_tbl[WMA_MAX_HT20_RATE_TBL_SIZE] = { + {650, 7}, /* MCS7 1SS long GI */ + {585, 6}, /* MCS6 1SS long GI */ + {520, 5}, /* MCS5 1SS long GI */ + {390, 4}, /* MCS4 1SS long GI */ + {260, 3}, /* MCS3 1SS long GI */ + {195, 2}, /* MCS2 1SS long GI */ + {130, 1}, /* MCS1 1SS long GI */ + {65, 0} /* MCS0 1SS long GI */ +}; + +#define WMA_MAX_HT40_RATE_TBL_SIZE 8 +static struct wma_search_rate ht40_400ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = { + {1500, 7}, /* MCS7 1SS short GI */ + {1350, 6}, /* MCS6 1SS short GI */ + {1200, 5}, /* MCS5 1SS short GI */ + {900, 4}, /* MCS4 1SS short GI */ + {600, 3}, /* MCS3 1SS short GI */ + {450, 2}, /* MCS2 1SS short GI */ + {300, 1}, /* MCS1 1SS short GI */ + {150, 0} /* MCS0 1SS short GI */ +}; + +static struct wma_search_rate ht40_800ns_rate_tbl[WMA_MAX_HT40_RATE_TBL_SIZE] = { + {1350, 7}, /* MCS7 1SS long GI */ + {1215, 6}, /* MCS6 1SS long GI */ + {1080, 5}, /* MCS5 1SS long GI */ + {810, 4}, /* MCS4 1SS long GI */ + {540, 3}, /* MCS3 1SS long GI */ + {405, 2}, /* MCS2 1SS long GI */ + {270, 1}, /* MCS1 1SS long GI */ + {135, 0} /* MCS0 1SS long GI */ +}; + +/** + * wma_bin_search_rate() - binary search function to find rate + * @tbl: rate table + * @tbl_size: table size + * @mbpsx10_rate: return mbps rate + * @ret_flag: return flag + * + * Return: none + */ +static void wma_bin_search_rate(struct wma_search_rate *tbl, int32_t tbl_size, + int32_t *mbpsx10_rate, uint8_t *ret_flag) +{ + int32_t upper, lower, mid; + + /* the table is descenting. index holds the largest value and the + * bottom index holds the smallest value + */ + + upper = 0; /* index 0 */ + lower = tbl_size - 1; /* last index */ + + if (*mbpsx10_rate >= tbl[upper].rate) { + /* use the largest rate */ + *mbpsx10_rate = tbl[upper].rate; + *ret_flag = tbl[upper].flag; + return; + } else if (*mbpsx10_rate <= tbl[lower].rate) { + /* use the smallest rate */ + *mbpsx10_rate = tbl[lower].rate; + *ret_flag = tbl[lower].flag; + return; + } + /* now we do binery search to get the floor value */ + while (lower - upper > 1) { + mid = (upper + lower) >> 1; + if (*mbpsx10_rate == tbl[mid].rate) { + /* found the exact match */ + *mbpsx10_rate = tbl[mid].rate; + *ret_flag = tbl[mid].flag; + return; + } + /* not found. if mid's rate is larger than input move + * upper to mid. If mid's rate is larger than input + * move lower to mid. + */ + if (*mbpsx10_rate > tbl[mid].rate) + lower = mid; + else + upper = mid; + } + /* after the bin search the index is the ceiling of rate */ + *mbpsx10_rate = tbl[upper].rate; + *ret_flag = tbl[upper].flag; + return; +} + +/** + * wma_fill_ofdm_cck_mcast_rate() - fill ofdm cck mcast rate + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ofdm_cck_mcast_rate(int32_t mbpsx10_rate, + uint8_t nss, uint8_t *rate) +{ + uint8_t idx = 0; + + wma_bin_search_rate(ofdm_cck_rate_tbl, WMA_MAX_OFDM_CCK_RATE_TBL_SIZE, + &mbpsx10_rate, &idx); + + /* if bit 7 is set it uses CCK */ + if (idx & 0x80) + *rate |= (1 << 6) | (idx & 0xF); /* set bit 6 to 1 for CCK */ + else + *rate |= (idx & 0xF); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_ht_vht_mcast_rate() - set ht/vht mcast rate + * @shortgi: short guard interval + * @mbpsx10_rate: mbps rates + * @sgi_idx: shortgi index + * @sgi_rate: shortgi rate + * @lgi_idx: longgi index + * @lgi_rate: longgi rate + * @premable: preamble + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: none + */ +static void wma_set_ht_vht_mcast_rate(uint32_t shortgi, int32_t mbpsx10_rate, + uint8_t sgi_idx, int32_t sgi_rate, + uint8_t lgi_idx, int32_t lgi_rate, + uint8_t premable, uint8_t *rate, + int32_t *streaming_rate) +{ + if (shortgi == 0) { + *rate |= (premable << 6) | (lgi_idx & 0xF); + *streaming_rate = lgi_rate; + } else { + *rate |= (premable << 6) | (sgi_idx & 0xF); + *streaming_rate = sgi_rate; + } +} + +/** + * wma_fill_ht20_mcast_rate() - fill ht20 mcast rate + * @shortgi: short guard interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ht20_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(ht20_400ns_rate_tbl, + WMA_MAX_HT20_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(ht20_800ns_rate_tbl, + WMA_MAX_HT20_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 2, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_ht40_mcast_rate() - fill ht40 mcast rate + * @shortgi: short guard interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ht40_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(ht40_400ns_rate_tbl, + WMA_MAX_HT40_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(ht40_800ns_rate_tbl, + WMA_MAX_HT40_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 2, rate, streaming_rate); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht20_mcast_rate() - fill vht20 mcast rate + * @shortgi: short guard interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht20_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht20_400ns_rate_tbl, + WMA_MAX_VHT20_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht20_800ns_rate_tbl, + WMA_MAX_VHT20_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht40_mcast_rate() - fill vht40 mcast rate + * @shortgi: short guard interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht40_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht40_400ns_rate_tbl, + WMA_MAX_VHT40_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht40_800ns_rate_tbl, + WMA_MAX_VHT40_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, + sgi_idx, sgi_rate, lgi_idx, lgi_rate, + 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_vht80_mcast_rate() - fill vht80 mcast rate + * @shortgi: short guard interval + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht80_mcast_rate(uint32_t shortgi, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + uint8_t sgi_idx = 0, lgi_idx = 0; + int32_t sgi_rate, lgi_rate; + + /* for 2x2 divide the rate by 2 */ + if (nss == 1) + mbpsx10_rate = mbpsx10_rate >> 1; + + sgi_rate = mbpsx10_rate; + lgi_rate = mbpsx10_rate; + if (shortgi) + wma_bin_search_rate(vht80_400ns_rate_tbl, + WMA_MAX_VHT80_RATE_TBL_SIZE, &sgi_rate, + &sgi_idx); + else + wma_bin_search_rate(vht80_800ns_rate_tbl, + WMA_MAX_VHT80_RATE_TBL_SIZE, &lgi_rate, + &lgi_idx); + + wma_set_ht_vht_mcast_rate(shortgi, mbpsx10_rate, sgi_idx, sgi_rate, + lgi_idx, lgi_rate, 3, rate, streaming_rate); + if (nss == 1) + *streaming_rate = *streaming_rate << 1; + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_ht_mcast_rate() - fill ht mcast rate + * @shortgi: short guard interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_ht_mcast_rate(uint32_t shortgi, + uint32_t chwidth, int32_t mbpsx10_rate, + uint8_t nss, uint8_t *rate, + int32_t *streaming_rate) +{ + int32_t ret = 0; + + *streaming_rate = 0; + if (chwidth == 0) + ret = wma_fill_ht20_mcast_rate(shortgi, mbpsx10_rate, + nss, rate, streaming_rate); + else if (chwidth == 1) + ret = wma_fill_ht40_mcast_rate(shortgi, mbpsx10_rate, + nss, rate, streaming_rate); + else + wma_err("Error, Invalid chwidth enum %d", chwidth); + return (*streaming_rate != 0) ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL; +} + +/** + * wma_fill_vht_mcast_rate() - fill vht mcast rate + * @shortgi: short guard interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * @streaming_rate: streaming rate + * + * Return: QDF status + */ +static QDF_STATUS wma_fill_vht_mcast_rate(uint32_t shortgi, + uint32_t chwidth, + int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate, + int32_t *streaming_rate) +{ + int32_t ret = 0; + + *streaming_rate = 0; + if (chwidth == 0) + ret = wma_fill_vht20_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else if (chwidth == 1) + ret = wma_fill_vht40_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else if (chwidth == 2) + ret = wma_fill_vht80_mcast_rate(shortgi, mbpsx10_rate, nss, + rate, streaming_rate); + else + wma_err("chwidth enum %d not supported", chwidth); + return (*streaming_rate != 0) ? QDF_STATUS_SUCCESS : QDF_STATUS_E_INVAL; +} + +#define WMA_MCAST_1X1_CUT_OFF_RATE 2000 +/** + * wma_encode_mc_rate() - fill mc rates + * @shortgi: short guard interval + * @chwidth: channel width + * @chanmode: channel mode + * @mhz: frequency + * @mbpsx10_rate: mbps rates + * @nss: nss + * @rate: rate + * + * Return: QDF status + */ +static QDF_STATUS wma_encode_mc_rate(uint32_t shortgi, uint32_t chwidth, + A_UINT32 mhz, int32_t mbpsx10_rate, uint8_t nss, + uint8_t *rate) +{ + int32_t ret = 0; + + /* nss input value: 0 - 1x1; 1 - 2x2; 2 - 3x3 + * the phymode selection is based on following assumption: + * (1) if the app specifically requested 1x1 or 2x2 we hornor it + * (2) if mbpsx10_rate <= 540: always use BG + * (3) 540 < mbpsx10_rate <= 2000: use 1x1 HT/VHT + * (4) 2000 < mbpsx10_rate: use 2x2 HT/VHT + */ + wma_debug("Input: nss = %d, mbpsx10 = 0x%x, chwidth = %d, shortgi = %d", + nss, mbpsx10_rate, chwidth, shortgi); + if ((mbpsx10_rate & 0x40000000) && nss > 0) { + /* bit 30 indicates user inputted nss, + * bit 28 and 29 used to encode nss + */ + uint8_t user_nss = (mbpsx10_rate & 0x30000000) >> 28; + + nss = (user_nss < nss) ? user_nss : nss; + /* zero out bits 19 - 21 to recover the actual rate */ + mbpsx10_rate &= ~0x70000000; + } else if (mbpsx10_rate <= WMA_MCAST_1X1_CUT_OFF_RATE) { + /* if the input rate is less or equal to the + * 1x1 cutoff rate we use 1x1 only + */ + nss = 0; + } + /* encode NSS bits (bit 4, bit 5) */ + *rate = (nss & 0x3) << 4; + /* if mcast input rate exceeds the ofdm/cck max rate 54mpbs + * we try to choose best ht/vht mcs rate + */ + if (540 < mbpsx10_rate) { + /* cannot use ofdm/cck, choose closest ht/vht mcs rate */ + uint8_t rate_ht = *rate; + uint8_t rate_vht = *rate; + int32_t stream_rate_ht = 0; + int32_t stream_rate_vht = 0; + int32_t stream_rate = 0; + + ret = wma_fill_ht_mcast_rate(shortgi, chwidth, mbpsx10_rate, + nss, &rate_ht, + &stream_rate_ht); + if (ret != QDF_STATUS_SUCCESS) + stream_rate_ht = 0; + if (mhz < WMA_2_4_GHZ_MAX_FREQ) { + /* not in 5 GHZ frequency */ + *rate = rate_ht; + stream_rate = stream_rate_ht; + goto ht_vht_done; + } + /* capable doing 11AC mcast so that search vht tables */ + ret = wma_fill_vht_mcast_rate(shortgi, chwidth, mbpsx10_rate, + nss, &rate_vht, + &stream_rate_vht); + if (ret != QDF_STATUS_SUCCESS) { + if (stream_rate_ht != 0) + ret = QDF_STATUS_SUCCESS; + *rate = rate_ht; + stream_rate = stream_rate_ht; + goto ht_vht_done; + } + if (stream_rate_ht == 0) { + /* only vht rate available */ + *rate = rate_vht; + stream_rate = stream_rate_vht; + } else { + /* set ht as default first */ + *rate = rate_ht; + stream_rate = stream_rate_ht; + if (stream_rate < mbpsx10_rate) { + if (mbpsx10_rate <= stream_rate_vht || + stream_rate < stream_rate_vht) { + *rate = rate_vht; + stream_rate = stream_rate_vht; + } + } else { + if (stream_rate_vht >= mbpsx10_rate && + stream_rate_vht < stream_rate) { + *rate = rate_vht; + stream_rate = stream_rate_vht; + } + } + } +ht_vht_done: + wma_debug("NSS = %d, freq = %d", nss, mhz); + wma_debug("input_rate = %d, chwidth = %d rate = 0x%x, streaming_rate = %d", + mbpsx10_rate, chwidth, *rate, stream_rate); + } else { + if (mbpsx10_rate > 0) + ret = wma_fill_ofdm_cck_mcast_rate(mbpsx10_rate, + nss, rate); + else + *rate = 0xFF; + + wma_debug("NSS = %d, input_rate = %d, rate = 0x%x", + nss, mbpsx10_rate, *rate); + } + return ret; +} + +/** + * wma_cp_stats_set_rate_flag() - set rate flags within cp_stats priv object + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +static void wma_cp_stats_set_rate_flag(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc = wma->psoc; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + uint32_t rate_flag; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("vdev not found for id: %d", vdev_id); + return; + } + + status = wma_get_vdev_rate_flag(iface->vdev, &rate_flag); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("vdev not found for id: %d", vdev_id); + return; + } + ucfg_mc_cp_stats_set_rate_flags(vdev, rate_flag); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); +} + +#ifdef WLAN_FEATURE_11AX +/** + * wma_set_bss_rate_flags_he() - set rate flags based on BSS capability + * @rate_flags: rate_flags pointer + * @add_bss: add_bss params + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_set_bss_rate_flags_he(enum tx_rate_info *rate_flags, + struct bss_params *add_bss) +{ + if (!add_bss->he_capable) + return QDF_STATUS_E_NOSUPPORT; + + *rate_flags |= wma_get_he_rate_flags(add_bss->ch_width); + + wma_debug("he_capable %d rate_flags 0x%x", add_bss->he_capable, + *rate_flags); + return QDF_STATUS_SUCCESS; +} + +static bool wma_get_bss_he_capable(struct bss_params *add_bss) +{ + return add_bss->he_capable; +} +#else +static QDF_STATUS wma_set_bss_rate_flags_he(enum tx_rate_info *rate_flags, + struct bss_params *add_bss) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static bool wma_get_bss_he_capable(struct bss_params *add_bss) +{ + return false; +} +#endif + +enum tx_rate_info wma_get_vht_rate_flags(enum phy_ch_width ch_width) +{ + enum tx_rate_info rate_flags = 0; + + if (ch_width == CH_WIDTH_80P80MHZ) + rate_flags |= TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 | + TX_RATE_VHT20; + if (ch_width == CH_WIDTH_160MHZ) + rate_flags |= TX_RATE_VHT160 | TX_RATE_VHT80 | TX_RATE_VHT40 | + TX_RATE_VHT20; + if (ch_width == CH_WIDTH_80MHZ) + rate_flags |= TX_RATE_VHT80 | TX_RATE_VHT40 | TX_RATE_VHT20; + else if (ch_width) + rate_flags |= TX_RATE_VHT40 | TX_RATE_VHT20; + else + rate_flags |= TX_RATE_VHT20; + return rate_flags; +} + +enum tx_rate_info wma_get_ht_rate_flags(enum phy_ch_width ch_width) +{ + enum tx_rate_info rate_flags = 0; + + if (ch_width) + rate_flags |= TX_RATE_HT40 | TX_RATE_HT20; + else + rate_flags |= TX_RATE_HT20; + + return rate_flags; +} + +enum tx_rate_info wma_get_he_rate_flags(enum phy_ch_width ch_width) +{ + enum tx_rate_info rate_flags = 0; + + if (ch_width == CH_WIDTH_160MHZ || + ch_width == CH_WIDTH_80P80MHZ) + rate_flags |= TX_RATE_HE160 | TX_RATE_HE80 | TX_RATE_HE40 | + TX_RATE_HE20; + else if (ch_width == CH_WIDTH_80MHZ) + rate_flags |= TX_RATE_HE80 | TX_RATE_HE40 | TX_RATE_HE20; + else if (ch_width) + rate_flags |= TX_RATE_HE40 | TX_RATE_HE20; + else + rate_flags |= TX_RATE_HE20; + + return rate_flags; +} + +void wma_set_bss_rate_flags(tp_wma_handle wma, uint8_t vdev_id, + struct bss_params *add_bss) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + struct vdev_mlme_obj *vdev_mlme; + enum tx_rate_info *rate_flags; + QDF_STATUS qdf_status; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!vdev_mlme) { + wma_err("Failed to get mlme obj for vdev_%d", vdev_id); + return; + } + rate_flags = &vdev_mlme->mgmt.rate_info.rate_flags; + *rate_flags = 0; + + qdf_status = wma_set_bss_rate_flags_eht(rate_flags, add_bss); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + if (QDF_STATUS_SUCCESS != + wma_set_bss_rate_flags_he(rate_flags, add_bss)) { + if (add_bss->vhtCapable) + *rate_flags = wma_get_vht_rate_flags(add_bss->ch_width); + /* avoid to conflict with htCapable flag */ + else if (add_bss->htCapable) + *rate_flags |= wma_get_ht_rate_flags(add_bss->ch_width); + } + } + + if (add_bss->staContext.fShortGI20Mhz || + add_bss->staContext.fShortGI40Mhz) + *rate_flags |= TX_RATE_SGI; + + if (!add_bss->htCapable && !add_bss->vhtCapable && + !wma_get_bss_he_capable(add_bss) && + !wma_get_bss_eht_capable(add_bss)) + *rate_flags = TX_RATE_LEGACY; + + wma_debug("capable: vht %u, ht %u, rate_flags %x, ch_width %d", + add_bss->vhtCapable, add_bss->htCapable, + *rate_flags, add_bss->ch_width); + + wma_cp_stats_set_rate_flag(wma, vdev_id); +} + +void wma_set_vht_txbf_cfg(struct mac_context *mac, uint8_t vdev_id) +{ + wmi_vdev_txbf_en txbf_en = {0}; + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return; + + txbf_en.sutxbfee = mac->mlme_cfg->vht_caps.vht_cap_info.su_bformee; + txbf_en.mutxbfee = + mac->mlme_cfg->vht_caps.vht_cap_info.enable_mu_bformee; + txbf_en.sutxbfer = mac->mlme_cfg->vht_caps.vht_cap_info.su_bformer; + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_txbf, + *((A_UINT8 *)&txbf_en)); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set VHT TXBF(status = %d)", status); +} + +/** + * wmi_unified_send_txbf() - set txbf parameter to fw + * @wma: wma handle + * @params: txbf parameters + * + * Return: 0 for success or error code + */ +int32_t wmi_unified_send_txbf(tp_wma_handle wma, tpAddStaParams params) +{ + wmi_vdev_txbf_en txbf_en = {0}; + + /* This is set when Other partner is Bformer + * and we are capable bformee(enabled both in ini and fw) + */ + txbf_en.sutxbfee = params->vhtTxBFCapable; + txbf_en.mutxbfee = params->vhtTxMUBformeeCapable; + txbf_en.sutxbfer = params->enable_su_tx_bformer; + + /* When MU TxBfee is set, SU TxBfee must be set by default */ + if (txbf_en.mutxbfee) + txbf_en.sutxbfee = txbf_en.mutxbfee; + + wma_debug("txbf_en.sutxbfee %d txbf_en.mutxbfee %d, sutxbfer %d", + txbf_en.sutxbfee, txbf_en.mutxbfee, txbf_en.sutxbfer); + + return wma_vdev_set_param(wma->wmi_handle, + params->smesessionId, + wmi_vdev_param_txbf, + *((A_UINT8 *) &txbf_en)); +} + +/** + * wma_data_tx_ack_work_handler() - process data tx ack + * @ack_work: work structure + * + * Return: none + */ +static void wma_data_tx_ack_work_handler(void *ack_work) +{ + struct wma_tx_ack_work_ctx *work; + tp_wma_handle wma_handle; + wma_tx_ota_comp_callback ack_cb; + + work = (struct wma_tx_ack_work_ctx *)ack_work; + + wma_handle = work->wma_handle; + if (!wma_handle || cds_is_load_or_unload_in_progress()) { + wma_err("Driver load/unload in progress"); + goto free_frame; + } + + wma_debug("Data Tx Ack Cb Status %d", work->status); + ack_cb = wma_handle->umac_data_ota_ack_cb; + if (!ack_cb) { + wma_err("Data Tx Ack Cb is NULL"); + goto free_frame; + } + + ack_cb(wma_handle->mac_context, work->frame, work->status, + NULL); + goto end; + +free_frame: + if (work->frame) + qdf_nbuf_free(work->frame); + +end: + qdf_mem_free(work); + + if (wma_handle) { + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + wma_handle->ack_work_ctx = NULL; + } +} + +/** + * wma_data_tx_ack_comp_hdlr() - handles tx data ack completion + * @context: context with which the handler is registered + * @netbuf: tx data nbuf + * @err: status of tx completion + * + * This is the cb registered with TxRx for + * Ack Complete + * + * Return: none + */ +void +wma_data_tx_ack_comp_hdlr(void *wma_context, qdf_nbuf_t netbuf, int32_t status) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + struct wma_tx_ack_work_ctx *ack_work; + QDF_STATUS qdf_status; + + if (wma_validate_handle(wma_handle)) + return; + + if (!netbuf) { + wma_debug("netbuf is NULL"); + return; + } + + /* + * if netBuf does not match with pending nbuf then just free the + * netbuf and do not call ack cb + */ + if (wma_handle->last_umac_data_nbuf != netbuf) { + wma_err("nbuf does not match but umac_data_ota_ack_cb is %s null", + wma_handle->umac_data_ota_ack_cb ? "not" : ""); + goto free_nbuf; + } + + if (!wma_handle->umac_data_ota_ack_cb) { + wma_err_rl("ota_ack cb not registered"); + goto free_nbuf; + } + + ack_work = qdf_mem_malloc(sizeof(struct wma_tx_ack_work_ctx)); + if (ack_work) { + wma_handle->ack_work_ctx = ack_work; + + ack_work->wma_handle = wma_handle; + ack_work->sub_type = 0; + ack_work->status = status; + ack_work->frame = netbuf; + + /* + * free of the netbuf will be done by the scheduled work so + * just do unmap here + */ + qdf_nbuf_unmap_single(wma_handle->qdf_dev, netbuf, + QDF_DMA_TO_DEVICE); + + qdf_status = qdf_create_work(0, &ack_work->ack_cmp_work, + wma_data_tx_ack_work_handler, + ack_work); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + qdf_nbuf_free(netbuf); + wma_err("Failed to create TX ack work"); + return; + } + + qdf_sched_work(0, &ack_work->ack_cmp_work); + return; + } + +free_nbuf: + /* unmap and freeing the tx buf as txrx is not taking care */ + qdf_nbuf_unmap_single(wma_handle->qdf_dev, netbuf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(netbuf); +} + +/** + * wma_check_txrx_chainmask() - check txrx chainmask + * @num_rf_chains: number of rf chains + * @cmd_value: command value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_check_txrx_chainmask(int num_rf_chains, int cmd_value) +{ + if ((cmd_value > WMA_MAX_RF_CHAINS(num_rf_chains)) || + (cmd_value < WMA_MIN_RF_CHAINS)) { + wma_err("Requested value %d over the range", cmd_value); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_enable_disable_mcc_adaptive_scheduler() -enable/disable mcc scheduler + * @mcc_adaptive_scheduler: enable/disable + * + * This function enable/disable mcc adaptive scheduler in fw. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_set_enable_disable_mcc_adaptive_scheduler(uint32_t + mcc_adaptive_scheduler) +{ + tp_wma_handle wma = NULL; + uint32_t pdev_id; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_FAULT; + + /* + * Since there could be up to two instances of OCS in FW (one per MAC), + * FW provides the option of enabling and disabling MAS on a per MAC + * basis. But, Host does not have enable/disable option for individual + * MACs. So, FW agreed for the Host to send down a 'pdev id' of 0. + * When 'pdev id' of 0 is used, FW treats this as a SOC level command + * and applies the same value to both MACs. Irrespective of the value + * of 'WMI_SERVICE_DEPRECATED_REPLACE', the pdev id needs to be '0' + * (SOC level) for WMI_RESMGR_ADAPTIVE_OCS_ENABLE_DISABLE_CMDID + */ + pdev_id = WMI_PDEV_ID_SOC; + + return wmi_unified_set_enable_disable_mcc_adaptive_scheduler_cmd( + wma->wmi_handle, mcc_adaptive_scheduler, pdev_id); +} + +/** + * wma_set_mcc_channel_time_latency() -set MCC channel time latency + * @wma: wma handle + * @mcc_channel: mcc channel + * @mcc_channel_time_latency: MCC channel time latency. + * + * Currently used to set time latency for an MCC vdev/adapter using operating + * channel of it and channel number. The info is provided run time using + * iwpriv command: iwpriv setMccLatency . + * + * Return: QDF status + */ +QDF_STATUS wma_set_mcc_channel_time_latency(tp_wma_handle wma, + uint32_t mcc_channel, uint32_t mcc_channel_time_latency) +{ + bool mcc_adapt_sch = false; + struct mac_context *mac = NULL; + uint32_t channel1 = mcc_channel; + uint32_t chan1_freq = cds_chan_to_freq(channel1); + + if (!wma) { + wma_err("NULL wma ptr. Exiting"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(mac)) { + wma_err("MCC is not active. Exiting"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + /* Confirm MCC adaptive scheduler feature is disabled */ + if (policy_mgr_get_dynamic_mcc_adaptive_sch(mac->psoc, + &mcc_adapt_sch) == + QDF_STATUS_SUCCESS) { + if (mcc_adapt_sch) { + wma_debug("Can't set channel latency while MCC ADAPTIVE SCHED is enabled. Exit"); + return QDF_STATUS_SUCCESS; + } + } else { + wma_err("Failed to get value for MCC_ADAPTIVE_SCHED, " + "Exit w/o setting latency"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_set_mcc_channel_time_latency_cmd(wma->wmi_handle, + chan1_freq, + mcc_channel_time_latency); +} + +/** + * wma_set_mcc_channel_time_quota() -set MCC channel time quota + * @wma: wma handle + * @adapter_1_chan_number: adapter 1 channel number + * @adapter_1_quota: adapter 1 quota + * @adapter_2_chan_number: adapter 2 channel number + * + * Currently used to set time quota for 2 MCC vdevs/adapters using (operating + * channel, quota) for each mode . The info is provided run time using + * iwpriv command: iwpriv setMccQuota . + * Note: the quota provided in command is for the same mode in cmd. HDD + * checks if MCC mode is active, gets the second mode and its operating chan. + * Quota for the 2nd role is calculated as 100 - quota of first mode. + * + * Return: QDF status + */ +QDF_STATUS wma_set_mcc_channel_time_quota(tp_wma_handle wma, + uint32_t adapter_1_chan_number, uint32_t adapter_1_quota, + uint32_t adapter_2_chan_number) +{ + bool mcc_adapt_sch = false; + struct mac_context *mac = NULL; + uint32_t chan1_freq = cds_chan_to_freq(adapter_1_chan_number); + uint32_t chan2_freq = cds_chan_to_freq(adapter_2_chan_number); + + if (!wma) { + wma_err("NULL wma ptr. Exiting"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* First step is to confirm if MCC is active */ + if (!lim_is_in_mcc(mac)) { + wma_debug("MCC is not active. Exiting"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + /* Confirm MCC adaptive scheduler feature is disabled */ + if (policy_mgr_get_dynamic_mcc_adaptive_sch(mac->psoc, + &mcc_adapt_sch) == + QDF_STATUS_SUCCESS) { + if (mcc_adapt_sch) { + wma_debug("Can't set channel quota while MCC_ADAPTIVE_SCHED is enabled. Exit"); + return QDF_STATUS_SUCCESS; + } + } else { + wma_err("Failed to retrieve WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED. Exit"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_set_mcc_channel_time_quota_cmd(wma->wmi_handle, + chan1_freq, + adapter_1_quota, + chan2_freq); +} + +#define MAX_VDEV_PROCESS_RATE_PARAMS 2 +/* params being sent: + * wmi_vdev_param_sgi + * wmi_vdev_param_mcast_data_rate + */ +QDF_STATUS wma_process_rate_update_indicate(tp_wma_handle wma, + tSirRateUpdateInd * + pRateUpdateParams) +{ + int32_t ret = 0; + uint8_t vdev_id = 0; + int32_t mbpsx10_rate = -1; + uint32_t paramid; + uint8_t rate = 0; + uint32_t short_gi, rate_flag; + struct wma_txrx_node *intr = wma->interfaces; + QDF_STATUS status; + struct dev_set_param setparam[MAX_VDEV_PROCESS_RATE_PARAMS] = {}; + uint8_t index = 0; + + /* Get the vdev id */ + if (wma_find_vdev_id_by_addr(wma, pRateUpdateParams->bssid.bytes, + &vdev_id)) { + wma_err("vdev handle is invalid for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pRateUpdateParams->bssid.bytes)); + qdf_mem_free(pRateUpdateParams); + return QDF_STATUS_E_INVAL; + } + short_gi = intr[vdev_id].config.shortgi; + + status = wma_get_vdev_rate_flag(intr[vdev_id].vdev, &rate_flag); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get rate_flag for VDEV_%d", vdev_id); + qdf_mem_free(pRateUpdateParams); + return QDF_STATUS_E_INVAL; + } + + if (short_gi == 0) + short_gi = (rate_flag & TX_RATE_SGI) ? true : false; + /* first check if reliable TX mcast rate is used. If not check the bcast + * Then is mcast. Mcast rate is saved in mcastDataRate24GHz + */ + if (pRateUpdateParams->reliableMcastDataRateTxFlag > 0) { + mbpsx10_rate = pRateUpdateParams->reliableMcastDataRate; + paramid = wmi_vdev_param_mcast_data_rate; + if (pRateUpdateParams-> + reliableMcastDataRateTxFlag & TX_RATE_SGI) + short_gi = 1; /* upper layer specified short GI */ + } else if (pRateUpdateParams->bcastDataRate > -1) { + mbpsx10_rate = pRateUpdateParams->bcastDataRate; + paramid = wmi_vdev_param_bcast_data_rate; + } else { + mbpsx10_rate = pRateUpdateParams->mcastDataRate24GHz; + paramid = wmi_vdev_param_mcast_data_rate; + if (pRateUpdateParams-> + mcastDataRate24GHzTxFlag & TX_RATE_SGI) + short_gi = 1; /* upper layer specified short GI */ + } + wma_debug("dev_id = %d, dev_type = %d, dev_mode = %d,", + vdev_id, intr[vdev_id].type, + pRateUpdateParams->dev_mode); + wma_debug("mac = "QDF_MAC_ADDR_FMT", config.shortgi = %d, rate_flags = 0x%x", + QDF_MAC_ADDR_REF(pRateUpdateParams->bssid.bytes), + intr[vdev_id].config.shortgi, rate_flag); + ret = wma_encode_mc_rate(short_gi, intr[vdev_id].config.chwidth, + intr[vdev_id].ch_freq, mbpsx10_rate, + pRateUpdateParams->nss, &rate); + if (ret != QDF_STATUS_SUCCESS) { + wma_err("Error, Invalid input rate value"); + qdf_mem_free(pRateUpdateParams); + return ret; + } + + ret = mlme_check_index_setparam(setparam, wmi_vdev_param_sgi, short_gi, + index++, MAX_VDEV_PROCESS_RATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed at wmi_vdev_param_sgi"); + goto error; + } + + ret = mlme_check_index_setparam(setparam, paramid, rate, index++, + MAX_VDEV_PROCESS_RATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed at paramid:%d", paramid); + goto error; + } + + ret = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(ret)) + wma_debug("failed to send vdev set params"); +error: + qdf_mem_free(pRateUpdateParams); + return ret; +} + +/** + * wma_mgmt_tx_ack_comp_hdlr() - handles tx ack mgmt completion + * @context: context with which the handler is registered + * @netbuf: tx mgmt nbuf + * @status: status of tx completion + * + * This is callback registered with TxRx for + * Ack Complete. + * + * Return: none + */ +static void +wma_mgmt_tx_ack_comp_hdlr(void *wma_context, qdf_nbuf_t netbuf, int32_t status) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + struct wlan_objmgr_pdev *pdev = (struct wlan_objmgr_pdev *) + wma_handle->pdev; + struct wmi_mgmt_params mgmt_params = {}; + uint16_t desc_id; + uint8_t vdev_id; + + desc_id = QDF_NBUF_CB_MGMT_TXRX_DESC_ID(netbuf); + vdev_id = mgmt_txrx_get_vdev_id(pdev, desc_id); + + mgmt_params.vdev_id = vdev_id; + mgmt_txrx_tx_completion_handler(pdev, desc_id, status, &mgmt_params); +} + +/** + * wma_mgmt_tx_dload_comp_hldr() - handles tx mgmt completion + * @context: context with which the handler is registered + * @netbuf: tx mgmt nbuf + * @status: status of tx completion + * + * This function calls registered download callback while sending mgmt packet. + * + * Return: none + */ +static void +wma_mgmt_tx_dload_comp_hldr(void *wma_context, qdf_nbuf_t netbuf, + int32_t status) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + tp_wma_handle wma_handle = (tp_wma_handle) wma_context; + void *mac_context = wma_handle->mac_context; + + wma_debug("Tx Complete Status %d", status); + + if (!wma_handle->tx_frm_download_comp_cb) { + wma_err("Tx Complete Cb not registered by umac"); + return; + } + + /* Call Tx Mgmt Complete Callback registered by umac */ + wma_handle->tx_frm_download_comp_cb(mac_context, netbuf, 0); + + /* Reset Callback */ + wma_handle->tx_frm_download_comp_cb = NULL; + + /* Set the Tx Mgmt Complete Event */ + qdf_status = qdf_event_set(&wma_handle->tx_frm_download_comp_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + wma_alert("Event Set failed - tx_frm_comp_event"); +} + +/** + * wma_tx_attach() - attach tx related callbacks + * @pwmaCtx: wma context + * + * attaches tx fn with underlying layer. + * + * Return: QDF status + */ +QDF_STATUS wma_tx_attach(tp_wma_handle wma_handle) +{ + /* Get the Vos Context */ + struct cds_context *cds_handle = + (struct cds_context *) (wma_handle->cds_context); + + /* Get the txRx Pdev ID */ + uint8_t pdev_id = WMI_PDEV_ID_SOC; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* Register for Tx Management Frames */ + cdp_mgmt_tx_cb_set(soc, pdev_id, 0, + wma_mgmt_tx_dload_comp_hldr, + wma_mgmt_tx_ack_comp_hdlr, wma_handle); + + /* Register callback to send PEER_UNMAP_RESPONSE cmd*/ + if (cdp_cfg_get_peer_unmap_conf_support(soc)) + cdp_peer_unmap_sync_cb_set(soc, pdev_id, + wma_peer_unmap_conf_cb); + + /* Store the Mac Context */ + wma_handle->mac_context = cds_handle->mac_context; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_tx_detach() - detach tx related callbacks + * @tp_wma_handle: wma context + * + * Deregister with TxRx for Tx Mgmt Download and Ack completion. + * + * Return: QDF status + */ +QDF_STATUS wma_tx_detach(tp_wma_handle wma_handle) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* Get the txRx Pdev ID */ + uint8_t pdev_id = WMI_PDEV_ID_SOC; + + if (!soc) + return QDF_STATUS_E_FAILURE; + + if (pdev_id != OL_TXRX_INVALID_PDEV_ID) { + /* Deregister with TxRx for Tx Mgmt completion call back */ + cdp_mgmt_tx_cb_set(soc, pdev_id, 0, NULL, NULL, NULL); + } + + /* Reset Tx Frm Callbacks */ + wma_handle->tx_frm_download_comp_cb = NULL; + + /* Reset Tx Data Frame Ack Cb */ + wma_handle->umac_data_ota_ack_cb = NULL; + + /* Reset last Tx Data Frame nbuf ptr */ + wma_handle->last_umac_data_nbuf = NULL; + + return QDF_STATUS_SUCCESS; +} + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) +static void wma_process_vdev_tx_pause_evt(void *soc, + tp_wma_handle wma, + wmi_tx_pause_event_fixed_param *event, + uint8_t vdev_id) +{ + /* PAUSE action, add bitmap */ + if (event->action == ACTION_PAUSE) { + /* Exclude TDLS_OFFCHAN_CHOP from vdev based pauses */ + if (event->pause_type == PAUSE_TYPE_CHOP_TDLS_OFFCHAN) { + cdp_fc_vdev_pause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_FW, + event->pause_type); + } else { + /* + * Now only support per-dev pause so it is not + * necessary to pause a paused queue again. + */ + if (!wma_vdev_get_pause_bitmap(vdev_id)) + cdp_fc_vdev_pause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_FW, + event->pause_type); + + wma_vdev_set_pause_bit(vdev_id, + event->pause_type); + } + } + /* UNPAUSE action, clean bitmap */ + else if (event->action == ACTION_UNPAUSE) { + /* Exclude TDLS_OFFCHAN_CHOP from vdev based pauses */ + if (event->pause_type == PAUSE_TYPE_CHOP_TDLS_OFFCHAN) { + cdp_fc_vdev_unpause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_FW, + event->pause_type); + } else { + /* Handle unpause only if already paused */ + if (wma_vdev_get_pause_bitmap(vdev_id)) { + wma_vdev_clear_pause_bit(vdev_id, + event->pause_type); + + if (wma->interfaces[vdev_id].pause_bitmap) + return; + + /* PAUSE BIT MAP is cleared + * UNPAUSE VDEV + */ + cdp_fc_vdev_unpause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_FW, + event->pause_type); + } + } + } else { + wma_err("Not Valid Action Type %d", event->action); + } +} + +int wma_mcc_vdev_tx_pause_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TX_PAUSE_EVENTID_param_tlvs *param_buf; + wmi_tx_pause_event_fixed_param *wmi_event; + uint8_t vdev_id; + A_UINT32 vdev_map; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + param_buf = (WMI_TX_PAUSE_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid roam event buffer"); + return -EINVAL; + } + + if (ucfg_pmo_get_wow_bus_suspend(wma->psoc)) { + wma_debug("Suspend is in progress: Pause/Unpause Tx is NoOp"); + return 0; + } + + if (!soc) + return -EINVAL; + + wmi_event = param_buf->fixed_param; + vdev_map = wmi_event->vdev_map; + /* FW mapped vdev from ID + * vdev_map = (1 << vdev_id) + * So, host should unmap to ID + */ + for (vdev_id = 0; vdev_map != 0 && vdev_id < wma->max_bssid; + vdev_id++) { + if (!(vdev_map & 0x1)) { + /* No Vdev */ + } else { + if (!wma->interfaces[vdev_id].vdev) { + wma_err("vdev is NULL for %d", vdev_id); + /* Test Next VDEV */ + vdev_map >>= 1; + continue; + } + + wma_process_vdev_tx_pause_evt(soc, wma, + wmi_event, + vdev_id); + + wma_debug + ("vdev_id %d, pause_map 0x%x, pause type %d, action %d", + vdev_id, wma_vdev_get_pause_bitmap(vdev_id), + wmi_event->pause_type, wmi_event->action); + } + /* Test Next VDEV */ + vdev_map >>= 1; + } + + return 0; +} + +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + +#if defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) + +/** + * wma_set_peer_rate_report_condition - + * this function set peer rate report + * condition info to firmware. + * @handle: Handle of WMA + * @config: Bad peer configuration from SIR module + * + * It is a wrapper function to sent WMI_PEER_SET_RATE_REPORT_CONDITION_CMDID + * to the firmware\target. If the command sent to firmware failed, free the + * buffer that allocated. + * + * Return: QDF_STATUS based on values sent to firmware + */ +static +QDF_STATUS wma_set_peer_rate_report_condition(WMA_HANDLE handle, + struct t_bad_peer_txtcl_config *config) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + struct wmi_peer_rate_report_params rate_report_params = {0}; + u_int32_t i, j; + + rate_report_params.rate_report_enable = config->enable; + rate_report_params.backoff_time = config->tgt_backoff; + rate_report_params.timer_period = config->tgt_report_prd; + for (i = 0; i < WMI_PEER_RATE_REPORT_COND_MAX_NUM; i++) { + rate_report_params.report_per_phy[i].cond_flags = + config->threshold[i].cond; + rate_report_params.report_per_phy[i].delta.delta_min = + config->threshold[i].delta; + rate_report_params.report_per_phy[i].delta.percent = + config->threshold[i].percentage; + for (j = 0; j < WMI_MAX_NUM_OF_RATE_THRESH; j++) { + rate_report_params.report_per_phy[i]. + report_rate_threshold[j] = + config->threshold[i].thresh[j]; + } + } + + return wmi_unified_peer_rate_report_cmd(wma_handle->wmi_handle, + &rate_report_params); +} + +/** + * wma_process_init_bad_peer_tx_ctl_info - + * this function to initialize peer rate report config info. + * @handle: Handle of WMA + * @config: Bad peer configuration from SIR module + * + * This function initializes the bad peer tx control data structure in WMA, + * sends down the initial configuration to the firmware and configures + * the peer status update setting in the tx_rx module. + * + * Return: QDF_STATUS based on procedure status + */ + +QDF_STATUS wma_process_init_bad_peer_tx_ctl_info(tp_wma_handle wma, + struct t_bad_peer_txtcl_config *config) +{ + /* Parameter sanity check */ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!wma || !config) { + wma_err("Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("enable %d period %d txq limit %d\n", + config->enable, + config->period, + config->txq_limit); + + /* Only need to initialize the setting + * when the feature is enabled + */ + if (config->enable) { + int i = 0; + + cdp_bad_peer_txctl_set_setting(soc, + WMI_PDEV_ID_SOC, + config->enable, + config->period, + config->txq_limit); + + for (i = 0; i < WLAN_WMA_IEEE80211_MAX_LEVEL; i++) { + u_int32_t threshold, limit; + + threshold = config->threshold[i].thresh[0]; + limit = config->threshold[i].txlimit; + cdp_bad_peer_txctl_update_threshold(soc, + WMI_PDEV_ID_SOC, + i, + threshold, + limit); + } + } + + return wma_set_peer_rate_report_condition(wma, config); +} +#endif /* defined(CONFIG_HL_SUPPORT) && defined(QCA_BAD_PEER_TX_FLOW_CL) */ + +#ifdef FW_THERMAL_THROTTLE_SUPPORT +/** + * wma_update_thermal_mitigation_to_fw - update thermal mitigation to fw + * @wma: wma handle + * @thermal_level: thermal level + * + * This function sends down thermal mitigation params to the fw + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +static QDF_STATUS wma_update_thermal_mitigation_to_fw(tp_wma_handle wma, + u_int8_t thermal_level) +{ + struct thermal_mitigation_params therm_data = {0}; + + /* Check if vdev is in mcc, if in mcc set dc value as 10, else 100 */ + therm_data.dc = 100; + therm_data.enable = 1; + therm_data.levelconf[0].dcoffpercent = + wma->thermal_mgmt_info.throttle_duty_cycle_tbl[thermal_level]; + therm_data.levelconf[0].priority = 0; + therm_data.num_thermal_conf = 1; + + return wmi_unified_thermal_mitigation_param_cmd_send(wma->wmi_handle, + &therm_data); +} +#else /* FW_THERMAL_THROTTLE_SUPPORT */ +/** + * wma_update_thermal_mitigation_to_fw - update thermal mitigation to fw + * @wma: wma handle + * @thermal_level: thermal level + * + * This function sends down thermal mitigation params to the fw + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +static QDF_STATUS wma_update_thermal_mitigation_to_fw(tp_wma_handle wma, + u_int8_t thermal_level) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_update_thermal_cfg_to_fw() - update thermal configuration to FW + * @wma: Pointer to WMA handle + * + * This function update thermal configuration to FW + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +static QDF_STATUS wma_update_thermal_cfg_to_fw(tp_wma_handle wma) +{ + t_thermal_cmd_params thermal_params = {0}; + + /* Get the temperature thresholds to set in firmware */ + thermal_params.minTemp = + wma->thermal_mgmt_info.thermalLevels[WLAN_WMA_THERMAL_LEVEL_0]. + minTempThreshold; + thermal_params.maxTemp = + wma->thermal_mgmt_info.thermalLevels[WLAN_WMA_THERMAL_LEVEL_0]. + maxTempThreshold; + thermal_params.thermalEnable = + wma->thermal_mgmt_info.thermalMgmtEnabled; + thermal_params.thermal_action = wma->thermal_mgmt_info.thermal_action; + + wma_debug("TM sending to fw: min_temp %d max_temp %d enable %d act %d", + thermal_params.minTemp, thermal_params.maxTemp, + thermal_params.thermalEnable, thermal_params.thermal_action); + + return wma_set_thermal_mgmt(wma, thermal_params); +} + +/** + * wma_process_init_thermal_info() - initialize thermal info + * @wma: Pointer to WMA handle + * @pThermalParams: Pointer to thermal mitigation parameters + * + * This function initializes the thermal management table in WMA, + * sends down the initial temperature thresholds to the firmware + * and configures the throttle period in the tx rx module + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_process_init_thermal_info(tp_wma_handle wma, + t_thermal_mgmt *pThermalParams) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; +#ifdef FW_THERMAL_THROTTLE_SUPPORT + int i = 0; +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + + if (!wma || !pThermalParams) { + wma_err("TM Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("TM enable %d period %d action %d", + pThermalParams->thermalMgmtEnabled, + pThermalParams->throttlePeriod, + pThermalParams->thermal_action); + + wma_nofl_debug("Throttle Duty Cycle Level in percentage:\n" + "0 %d\n" + "1 %d\n" + "2 %d\n" + "3 %d\n" + "4 %d\n" + "5 %d", + pThermalParams->throttle_duty_cycle_tbl[0], + pThermalParams->throttle_duty_cycle_tbl[1], + pThermalParams->throttle_duty_cycle_tbl[2], + pThermalParams->throttle_duty_cycle_tbl[3], + pThermalParams->throttle_duty_cycle_tbl[4], + pThermalParams->throttle_duty_cycle_tbl[5]); + + wma->thermal_mgmt_info.thermalMgmtEnabled = + pThermalParams->thermalMgmtEnabled; + wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold = + pThermalParams->thermalLevels[0].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold = + pThermalParams->thermalLevels[0].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold = + pThermalParams->thermalLevels[1].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold = + pThermalParams->thermalLevels[1].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold = + pThermalParams->thermalLevels[2].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold = + pThermalParams->thermalLevels[2].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold = + pThermalParams->thermalLevels[3].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold = + pThermalParams->thermalLevels[3].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[4].minTempThreshold = + pThermalParams->thermalLevels[4].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[4].maxTempThreshold = + pThermalParams->thermalLevels[4].maxTempThreshold; + wma->thermal_mgmt_info.thermalLevels[5].minTempThreshold = + pThermalParams->thermalLevels[5].minTempThreshold; + wma->thermal_mgmt_info.thermalLevels[5].maxTempThreshold = + pThermalParams->thermalLevels[5].maxTempThreshold; + wma->thermal_mgmt_info.thermalCurrLevel = WLAN_WMA_THERMAL_LEVEL_0; + wma->thermal_mgmt_info.thermal_action = pThermalParams->thermal_action; + wma_nofl_debug("TM level min max:\n" + "0 %d %d\n" + "1 %d %d\n" + "2 %d %d\n" + "3 %d %d\n" + "4 %d %d\n" + "5 %d %d", + wma->thermal_mgmt_info.thermalLevels[0].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[0].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[1].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[1].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[2].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[2].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[3].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[3].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[4].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[4].maxTempThreshold, + wma->thermal_mgmt_info.thermalLevels[5].minTempThreshold, + wma->thermal_mgmt_info.thermalLevels[5].maxTempThreshold); + +#ifdef FW_THERMAL_THROTTLE_SUPPORT + for (i = 0; i < THROTTLE_LEVEL_MAX; i++) + wma->thermal_mgmt_info.throttle_duty_cycle_tbl[i] = + pThermalParams->throttle_duty_cycle_tbl[i]; +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ + + if (wma->thermal_mgmt_info.thermalMgmtEnabled) { + if (!wma->fw_therm_throt_support) { + cdp_throttle_init_period( + cds_get_context(QDF_MODULE_ID_SOC), + WMI_PDEV_ID_SOC, pThermalParams->throttlePeriod, + &pThermalParams->throttle_duty_cycle_tbl[0]); + } else { + qdf_status = wma_update_thermal_mitigation_to_fw( + wma, WLAN_WMA_THERMAL_LEVEL_0); + if (QDF_STATUS_SUCCESS != qdf_status) + return qdf_status; + } + qdf_status = wma_update_thermal_cfg_to_fw(wma); + } + return qdf_status; +} + +/** + * wma_set_thermal_level_ind() - send SME set thermal level indication message + * @level: thermal level + * + * Send SME SET_THERMAL_LEVEL_IND message + * + * Returns: none + */ +static void wma_set_thermal_level_ind(u_int8_t level) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg sme_msg = {0}; + + wma_info("Thermal level: %d", level); + + sme_msg.type = eWNI_SME_SET_THERMAL_LEVEL_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = level; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + wma_err("Fail to post set thermal level ind msg"); +} + +/** + * wma_process_set_thermal_level() - sets thermal level + * @wma: Pointer to WMA handle + * @thermal_level : Thermal level + * + * This function sets the new thermal throttle level in the + * txrx module and sends down the corresponding temperature + * thresholds to the firmware + * + * Returns: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_process_set_thermal_level(tp_wma_handle wma, + uint8_t thermal_level) +{ + if (!wma) { + wma_err("TM Invalid input"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("TM set level %d", thermal_level); + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + wma_err("Thermal mgmt is not enabled, ignoring set level command"); + return QDF_STATUS_E_FAILURE; + } + + if (thermal_level >= WLAN_WMA_MAX_THERMAL_LEVELS) { + wma_err("Invalid thermal level set %d", thermal_level); + return QDF_STATUS_E_FAILURE; + } + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + wma_debug("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return QDF_STATUS_SUCCESS; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + + cdp_throttle_set_level(cds_get_context(QDF_MODULE_ID_SOC), + WMI_PDEV_ID_SOC, thermal_level); + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + return QDF_STATUS_SUCCESS; +} + + +/** + * wma_set_thermal_mgmt() - set thermal mgmt command to fw + * @wma_handle: Pointer to WMA handle + * @thermal_info: Thermal command information + * + * This function sends the thermal management command + * to the firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + */ +QDF_STATUS wma_set_thermal_mgmt(tp_wma_handle wma_handle, + t_thermal_cmd_params thermal_info) +{ + struct thermal_cmd_params mgmt_thermal_info = {0}; + + if (!wma_handle) { + wma_err("Invalid input"); + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + mgmt_thermal_info.min_temp = thermal_info.minTemp; + mgmt_thermal_info.max_temp = thermal_info.maxTemp; + mgmt_thermal_info.thermal_enable = thermal_info.thermalEnable; + mgmt_thermal_info.thermal_action = thermal_info.thermal_action; + + return wmi_unified_set_thermal_mgmt_cmd(wma_handle->wmi_handle, + &mgmt_thermal_info); +} + +/** + * wma_thermal_mgmt_get_level() - returns throttle level + * @handle: Pointer to WMA handle + * @temp: temperature + * + * This function returns the thermal(throttle) level + * given the temperature + * + * Return: thermal (throttle) level + */ +static uint8_t wma_thermal_mgmt_get_level(void *handle, uint32_t temp) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int i; + uint8_t level; + + level = i = wma->thermal_mgmt_info.thermalCurrLevel; + while (temp < wma->thermal_mgmt_info.thermalLevels[i].minTempThreshold + && i > 0) { + i--; + level = i; + } + + i = wma->thermal_mgmt_info.thermalCurrLevel; + while (temp > wma->thermal_mgmt_info.thermalLevels[i].maxTempThreshold + && i < (WLAN_WMA_MAX_THERMAL_LEVELS - 1)) { + i++; + level = i; + } + + wma_warn("Change thermal level from %d -> %d", + wma->thermal_mgmt_info.thermalCurrLevel, level); + + return level; +} + +/** + * wms_thermal_level_to_host() - Convert wma thermal level to host enum + * @level: current thermal throttle level + * + * Return: host thermal throttle level + */ +static enum thermal_throttle_level +wma_thermal_level_to_host(uint8_t level) +{ + switch (level) { + case WLAN_WMA_THERMAL_LEVEL_0: + return THERMAL_FULLPERF; + case WLAN_WMA_THERMAL_LEVEL_1: + case WLAN_WMA_THERMAL_LEVEL_2: + case WLAN_WMA_THERMAL_LEVEL_3: + return THERMAL_MITIGATION; + case WLAN_WMA_THERMAL_LEVEL_4: + return THERMAL_SHUTOFF; + case WLAN_WMA_THERMAL_LEVEL_5: + return THERMAL_SHUTDOWN_TARGET; + default: + return THERMAL_UNKNOWN; + } +} + +/** + * wma_thermal_mgmt_evt_handler() - thermal mgmt event handler + * @wma_handle: Pointer to WMA handle + * @event: Thermal event information + * @len: length of the event + * + * This function handles the thermal mgmt event from the firmware + * + * Return: 0 for success otherwise failure + */ +int wma_thermal_mgmt_evt_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma; + wmi_thermal_mgmt_event_fixed_param *tm_event; + uint8_t thermal_level; + t_thermal_cmd_params thermal_params = {0}; + WMI_THERMAL_MGMT_EVENTID_param_tlvs *param_buf; + struct wlan_objmgr_psoc *psoc; + struct thermal_throttle_info info = {0}; + + if (!event || !handle) { + wma_err("Invalid thermal mitigation event buffer"); + return -EINVAL; + } + + wma = (tp_wma_handle) handle; + + if (wma_validate_handle(wma)) + return -EINVAL; + + psoc = wma->psoc; + if (!psoc) { + wma_err("NULL psoc"); + return -EINVAL; + } + + param_buf = (WMI_THERMAL_MGMT_EVENTID_param_tlvs *) event; + + /* Check if thermal mitigation is enabled */ + if (!wma->thermal_mgmt_info.thermalMgmtEnabled) { + wma_err("Thermal mgmt is not enabled, ignoring event"); + return -EINVAL; + } + + tm_event = param_buf->fixed_param; + wma_debug("Thermal mgmt event received with temperature %d", + tm_event->temperature_degreeC); + + /* Get the thermal mitigation level for the reported temperature */ + thermal_level = wma_thermal_mgmt_get_level(handle, + tm_event->temperature_degreeC); + wma_debug("Thermal mgmt level %d", thermal_level); + + if (thermal_level == wma->thermal_mgmt_info.thermalCurrLevel) { + wma_debug("Current level %d is same as the set level, ignoring", + wma->thermal_mgmt_info.thermalCurrLevel); + return 0; + } + + wma->thermal_mgmt_info.thermalCurrLevel = thermal_level; + info.level = wma_thermal_level_to_host(thermal_level); + target_if_fwol_notify_thermal_throttle(psoc, &info); + + if (!wma->fw_therm_throt_support) { + /* Inform txrx */ + cdp_throttle_set_level(cds_get_context(QDF_MODULE_ID_SOC), + WMI_PDEV_ID_SOC, thermal_level); + } + + /* Send SME SET_THERMAL_LEVEL_IND message */ + wma_set_thermal_level_ind(thermal_level); + + if (wma->fw_therm_throt_support) { + /* Send duty cycle info to firmware for fw to throttle */ + if (QDF_STATUS_SUCCESS != + wma_update_thermal_mitigation_to_fw(wma, thermal_level)) + return QDF_STATUS_E_FAILURE; + } + + /* Get the temperature thresholds to set in firmware */ + thermal_params.minTemp = + wma->thermal_mgmt_info.thermalLevels[thermal_level]. + minTempThreshold; + thermal_params.maxTemp = + wma->thermal_mgmt_info.thermalLevels[thermal_level]. + maxTempThreshold; + thermal_params.thermalEnable = + wma->thermal_mgmt_info.thermalMgmtEnabled; + thermal_params.thermal_action = wma->thermal_mgmt_info.thermal_action; + + if (QDF_STATUS_SUCCESS != wma_set_thermal_mgmt(wma, thermal_params)) { + wma_err("Could not send thermal mgmt command to the firmware!"); + return -EINVAL; + } + + return 0; +} + +/** + * wma_decap_to_8023() - Decapsulate to 802.3 format + * @msdu: skb buffer + * @info: decapsulate info + * + * Return: none + */ +static void wma_decap_to_8023(qdf_nbuf_t msdu, struct wma_decap_info_t *info) +{ + struct llc_snap_hdr_t *llc_hdr; + uint16_t ether_type; + uint16_t l2_hdr_space; + struct ieee80211_qosframe_addr4 *wh; + uint8_t local_buf[ETHERNET_HDR_LEN]; + uint8_t *buf; + struct ethernet_hdr_t *ethr_hdr; + + buf = (uint8_t *) qdf_nbuf_data(msdu); + llc_hdr = (struct llc_snap_hdr_t *)buf; + ether_type = (llc_hdr->ethertype[0] << 8) | llc_hdr->ethertype[1]; + /* do llc remove if needed */ + l2_hdr_space = 0; + if (IS_SNAP(llc_hdr)) { + if (IS_BTEP(llc_hdr)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } else if (IS_RFC1042(llc_hdr)) { + if (!(ether_type == ETHERTYPE_AARP || + ether_type == ETHERTYPE_IPX)) { + /* remove llc */ + l2_hdr_space += sizeof(struct llc_snap_hdr_t); + llc_hdr = NULL; + } + } + } + if (l2_hdr_space > ETHERNET_HDR_LEN) + buf = qdf_nbuf_pull_head(msdu, l2_hdr_space - ETHERNET_HDR_LEN); + else if (l2_hdr_space < ETHERNET_HDR_LEN) + buf = qdf_nbuf_push_head(msdu, ETHERNET_HDR_LEN - l2_hdr_space); + + /* mpdu hdr should be present in info,re-create ethr_hdr based on + * mpdu hdr + */ + wh = (struct ieee80211_qosframe_addr4 *)info->hdr; + ethr_hdr = (struct ethernet_hdr_t *)local_buf; + switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { + case IEEE80211_FC1_DIR_NODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_TODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr2, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_FROMDS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr1, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr3, + QDF_MAC_ADDR_SIZE); + break; + case IEEE80211_FC1_DIR_DSTODS: + qdf_mem_copy(ethr_hdr->dest_addr, wh->i_addr3, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(ethr_hdr->src_addr, wh->i_addr4, + QDF_MAC_ADDR_SIZE); + break; + } + + if (!llc_hdr) { + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } else { + uint32_t pktlen = + qdf_nbuf_len(msdu) - sizeof(ethr_hdr->ethertype); + ether_type = (uint16_t) pktlen; + ether_type = qdf_nbuf_len(msdu) - sizeof(struct ethernet_hdr_t); + ethr_hdr->ethertype[0] = (ether_type >> 8) & 0xff; + ethr_hdr->ethertype[1] = (ether_type) & 0xff; + } + qdf_mem_copy(buf, ethr_hdr, ETHERNET_HDR_LEN); +} + +/** + * wma_ieee80211_hdrsize() - get 802.11 header size + * @data: 80211 frame + * + * Return: size of header + */ +static int32_t wma_ieee80211_hdrsize(const void *data) +{ + const struct ieee80211_frame *wh = (const struct ieee80211_frame *)data; + int32_t size = sizeof(struct ieee80211_frame); + + if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS) + size += QDF_MAC_ADDR_SIZE; + if (IEEE80211_QOS_HAS_SEQ(wh)) + size += sizeof(uint16_t); + return size; +} + +/** + * rate_pream: Mapping from data rates to preamble. + */ +static uint32_t rate_pream[] = {WMI_RATE_PREAMBLE_CCK, WMI_RATE_PREAMBLE_CCK, + WMI_RATE_PREAMBLE_CCK, WMI_RATE_PREAMBLE_CCK, + WMI_RATE_PREAMBLE_OFDM, WMI_RATE_PREAMBLE_OFDM, + WMI_RATE_PREAMBLE_OFDM, WMI_RATE_PREAMBLE_OFDM, + WMI_RATE_PREAMBLE_OFDM, WMI_RATE_PREAMBLE_OFDM, + WMI_RATE_PREAMBLE_OFDM, WMI_RATE_PREAMBLE_OFDM}; + +/** + * rate_mcs: Mapping from data rates to MCS (+4 for OFDM to keep the sequence). + */ +static uint32_t rate_mcs[] = {WMI_MAX_CCK_TX_RATE_1M, WMI_MAX_CCK_TX_RATE_2M, + WMI_MAX_CCK_TX_RATE_5_5M, WMI_MAX_CCK_TX_RATE_11M, + WMI_MAX_OFDM_TX_RATE_6M + 4, + WMI_MAX_OFDM_TX_RATE_9M + 4, + WMI_MAX_OFDM_TX_RATE_12M + 4, + WMI_MAX_OFDM_TX_RATE_18M + 4, + WMI_MAX_OFDM_TX_RATE_24M + 4, + WMI_MAX_OFDM_TX_RATE_36M + 4, + WMI_MAX_OFDM_TX_RATE_48M + 4, + WMI_MAX_OFDM_TX_RATE_54M + 4}; + +#define WMA_TX_SEND_MGMT_TYPE 0 +#define WMA_TX_SEND_DATA_TYPE 1 + +/** + * wma_update_tx_send_params() - Update tx_send_params TLV info + * @tx_param: Pointer to tx_send_params + * @rid: rate ID passed by PE + * + * Return: None + */ +static void wma_update_tx_send_params(struct tx_send_params *tx_param, + enum rateid rid) +{ + uint8_t preamble = 0, nss = 0, rix = 0; + + preamble = rate_pream[rid]; + rix = rate_mcs[rid]; + + tx_param->mcs_mask = (1 << rix); + tx_param->nss_mask = (1 << nss); + tx_param->preamble_type = (1 << preamble); + tx_param->frame_type = WMA_TX_SEND_MGMT_TYPE; + + wma_debug("rate_id: %d, mcs: %0x, nss: %0x, preamble: %0x", + rid, tx_param->mcs_mask, tx_param->nss_mask, + tx_param->preamble_type); +} + +QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, + eFrameType frmType, eFrameTxDir txDir, uint8_t tid, + wma_tx_dwnld_comp_callback tx_frm_download_comp_cb, + void *pData, + wma_tx_ota_comp_callback tx_frm_ota_comp_cb, + uint8_t tx_flag, uint8_t vdev_id, bool tdls_flag, + uint16_t channel_freq, enum rateid rid, + int8_t peer_rssi, uint16_t action) +{ + tp_wma_handle wma_handle = (tp_wma_handle) (wma_context); + int32_t status; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int32_t is_high_latency; + bool is_wmi_mgmt_tx = false; + enum frame_index tx_frm_index = GENERIC_NODOWNLD_NOACK_COMP_INDEX; + tpSirMacFrameCtl pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(tx_frame)); + uint8_t use_6mbps = 0; + uint8_t downld_comp_required = 0; + uint16_t chanfreq; + uint8_t *pFrame = NULL; + void *pPacket = NULL; + uint16_t newFrmLen = 0; + struct wma_txrx_node *iface; + struct mac_context *mac; + tpSirMacMgmtHdr mHdr; + struct wmi_mgmt_params mgmt_param = {0}; + struct cdp_cfg *ctrl_pdev; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct ieee80211_frame *wh; + struct wlan_objmgr_peer *peer = NULL; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev = NULL; + void *mac_addr; + uint8_t *mld_addr = NULL; + bool is_5g = false; + uint8_t pdev_id; + bool mlo_link_agnostic; + + if (wma_validate_handle(wma_handle)) { + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + if (vdev_id >= wma_handle->max_bssid) { + wma_err("tx packet with invalid vdev_id :%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + iface = &wma_handle->interfaces[vdev_id]; + + if (!soc) { + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + cdp_hl_tdls_flag_reset(soc, vdev_id, false); + + if (frmType >= TXRX_FRM_MAX) { + wma_err("Invalid Frame Type Fail to send Frame"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + /* + * Currently only support to + * send 80211 Mgmt and 80211 Data are added. + */ + if (!((frmType == TXRX_FRM_802_11_MGMT) || + (frmType == TXRX_FRM_802_11_DATA))) { + wma_err("No Support to send other frames except 802.11 Mgmt/Data"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + if (((iface->rmfEnabled || tx_flag & HAL_USE_PMF)) && + (frmType == TXRX_FRM_802_11_MGMT) && + (pFc->subType == SIR_MAC_MGMT_DISASSOC || + pFc->subType == SIR_MAC_MGMT_DEAUTH || + pFc->subType == SIR_MAC_MGMT_ACTION)) { + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(tx_frame); + if (!QDF_IS_ADDR_BROADCAST(wh->i_addr1) && + !IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (pFc->wep) { + uint8_t mic_len, hdr_len, pdev_id; + + /* Allocate extra bytes for privacy header and + * trailer + */ + if (iface->type == WMI_VDEV_TYPE_NDI && + (tx_flag & HAL_USE_PMF)) { + hdr_len = IEEE80211_CCMP_HEADERLEN; + mic_len = IEEE80211_CCMP_MICLEN; + } else { + pdev_id = wlan_objmgr_pdev_get_pdev_id( + wma_handle->pdev); + qdf_status = mlme_get_peer_mic_len( + wma_handle->psoc, + pdev_id, wh->i_addr1, + &mic_len, &hdr_len); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + cds_packet_free( + (void *)tx_frame); + goto error; + } + } + + newFrmLen = frmLen + hdr_len + mic_len; + qdf_status = + cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_alert("Failed to allocate %d bytes for RMF status code (%x)", + newFrmLen, + qdf_status); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + + /* + * Initialize the frame with 0's and only fill + * MAC header and data, Keep the CCMP header and + * trailer as 0's, firmware shall fill this + */ + qdf_mem_zero(pFrame, newFrmLen); + qdf_mem_copy(pFrame, wh, sizeof(*wh)); + qdf_mem_copy(pFrame + sizeof(*wh) + + hdr_len, + pData + sizeof(*wh), + frmLen - sizeof(*wh)); + + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + pData = pFrame; + frmLen = newFrmLen; + pFc = (tpSirMacFrameCtl) + (qdf_nbuf_data(tx_frame)); + } + } else { + uint16_t mmie_size; + int32_t mgmtcipherset; + + mgmtcipherset = wlan_crypto_get_param(iface->vdev, + WLAN_CRYPTO_PARAM_MGMT_CIPHER); + if (mgmtcipherset <= 0) { + wma_err("Invalid key cipher %d", mgmtcipherset); + cds_packet_free((void *)tx_frame); + return -EINVAL; + } + + if (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_CMAC)) + mmie_size = cds_get_mmie_size(); + else + mmie_size = cds_get_gmac_mmie_size(); + + /* Allocate extra bytes for MMIE */ + newFrmLen = frmLen + mmie_size; + qdf_status = cds_packet_alloc((uint16_t) newFrmLen, + (void **)&pFrame, + (void **)&pPacket); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_alert("Failed to allocate %d bytes for RMF status code (%x)", + newFrmLen, + qdf_status); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + goto error; + } + /* + * Initialize the frame with 0's and only fill + * MAC header and data. MMIE field will be + * filled by wlan_crypto_add_mmie API + */ + qdf_mem_zero(pFrame, newFrmLen); + qdf_mem_copy(pFrame, wh, sizeof(*wh)); + qdf_mem_copy(pFrame + sizeof(*wh), + pData + sizeof(*wh), frmLen - sizeof(*wh)); + + /* The API expect length without the mmie size */ + if (!wlan_crypto_add_mmie(iface->vdev, pFrame, + frmLen)) { + wma_alert("Failed to attach MMIE"); + /* Free the original packet memory */ + cds_packet_free((void *)tx_frame); + cds_packet_free((void *)pPacket); + goto error; + } + cds_packet_free((void *)tx_frame); + tx_frame = pPacket; + pData = pFrame; + frmLen = newFrmLen; + pFc = (tpSirMacFrameCtl) (qdf_nbuf_data(tx_frame)); + } + /* + * Some target which support sending mgmt frame based on htt + * would DMA write this PMF tx frame buffer, it may cause smmu + * check permission fault, set a flag to do bi-direction DMA + * map, normal tx unmap is enough for this case. + */ + QDF_NBUF_CB_TX_DMA_BI_MAP((qdf_nbuf_t)tx_frame) = 1; + } + mHdr = (tpSirMacMgmtHdr)qdf_nbuf_data(tx_frame); + if ((frmType == TXRX_FRM_802_11_MGMT) && + (pFc->subType == SIR_MAC_MGMT_PROBE_RSP)) { + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(tx_frame); + + /* Make the TSF offset negative to match TSF in beacons */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma_handle->interfaces[vdev_id]. + tsfadjust); + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + } + if (frmType == TXRX_FRM_802_11_DATA) { + qdf_nbuf_t ret; + qdf_nbuf_t skb = (qdf_nbuf_t) tx_frame; + + struct wma_decap_info_t decap_info; + struct ieee80211_frame *wh = + (struct ieee80211_frame *)qdf_nbuf_data(skb); + unsigned long curr_timestamp = qdf_mc_timer_get_system_ticks(); + + /* + * 1) TxRx Module expects data input to be 802.3 format + * So Decapsulation has to be done. + * 2) Only one Outstanding Data pending for Ack is allowed + */ + if (tx_frm_ota_comp_cb) { + if (wma_handle->umac_data_ota_ack_cb) { + /* + * If last data frame was sent more than 2 secs + * ago and still we didn't receive ack/nack from + * fw then allow Tx of this data frame + */ + if (curr_timestamp >= + wma_handle->last_umac_data_ota_timestamp + + 200) { + wma_err("No Tx Ack for last data frame for more than 2 secs, allow Tx of current data frame"); + } else { + wma_err("Already one Data pending for Ack, reject Tx of data frame"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + } + } else { + /* + * Data Frames are sent through TxRx Non Standard Data + * path so Ack Complete Cb is must + */ + wma_err("No Ack Complete Cb. Don't Allow"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + + /* Take out 802.11 header from skb */ + decap_info.hdr_len = wma_ieee80211_hdrsize(wh); + qdf_mem_copy(decap_info.hdr, wh, decap_info.hdr_len); + qdf_nbuf_pull_head(skb, decap_info.hdr_len); + + /* Decapsulate to 802.3 format */ + wma_decap_to_8023(skb, &decap_info); + + /* Zero out skb's context buffer for the driver to use */ + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + + /* Terminate the (single-element) list of tx frames */ + skb->next = NULL; + + /* Store the Ack Complete Cb */ + wma_handle->umac_data_ota_ack_cb = tx_frm_ota_comp_cb; + + /* Store the timestamp and nbuf for this data Tx */ + wma_handle->last_umac_data_ota_timestamp = curr_timestamp; + wma_handle->last_umac_data_nbuf = skb; + + /* Send the Data frame to TxRx in Non Standard Path */ + cdp_hl_tdls_flag_reset(soc, + vdev_id, tdls_flag); + + ret = cdp_tx_non_std(soc, + vdev_id, + OL_TX_SPEC_NO_FREE, skb); + + cdp_hl_tdls_flag_reset(soc, + vdev_id, false); + + if (ret) { + wma_err("TxRx Rejected. Fail to do Tx"); + /* Call Download Cb so that umac can free the buffer */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_FREE); + wma_handle->umac_data_ota_ack_cb = NULL; + wma_handle->last_umac_data_nbuf = NULL; + return QDF_STATUS_E_FAILURE; + } + + /* Call Download Callback if passed */ + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_NO_FREE); + + return QDF_STATUS_SUCCESS; + } + + ctrl_pdev = cdp_get_ctrl_pdev_from_vdev(soc, vdev_id); + if (!ctrl_pdev) { + wma_err("ol_pdev_handle is NULL"); + cds_packet_free((void *)tx_frame); + return QDF_STATUS_E_FAILURE; + } + is_high_latency = cdp_cfg_is_high_latency(soc, ctrl_pdev); + is_wmi_mgmt_tx = wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_mgmt_tx_wmi); + + downld_comp_required = tx_frm_download_comp_cb && is_high_latency && + (!is_wmi_mgmt_tx) && tx_frm_ota_comp_cb; + + /* Fill the frame index to send */ + if (pFc->type == SIR_MAC_MGMT_FRAME) { + if (tx_frm_ota_comp_cb) { + if (downld_comp_required) + tx_frm_index = + GENERIC_DOWNLD_COMP_ACK_COMP_INDEX; + else + tx_frm_index = GENERIC_NODOWLOAD_ACK_COMP_INDEX; + + } else { + tx_frm_index = + GENERIC_NODOWNLD_NOACK_COMP_INDEX; + } + + } + + /* + * If Download Complete is required + * Wait for download complete + */ + if (downld_comp_required) { + /* Store Tx Comp Cb */ + wma_handle->tx_frm_download_comp_cb = tx_frm_download_comp_cb; + + /* Reset the Tx Frame Complete Event */ + qdf_status = qdf_event_reset( + &wma_handle->tx_frm_download_comp_event); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_alert("Event Reset failed tx comp event %x", + qdf_status); + cds_packet_free((void *)tx_frame); + goto error; + } + } + + /* If the frame has to be sent at BD Rate2 inform TxRx */ + if (tx_flag & HAL_USE_BD_RATE2_FOR_MANAGEMENT_FRAME) + use_6mbps = 1; + + if (pFc->subType == SIR_MAC_MGMT_PROBE_RSP) { + if (wma_is_vdev_in_ap_mode(wma_handle, vdev_id) && + wma_handle->interfaces[vdev_id].ch_freq) + chanfreq = wma_handle->interfaces[vdev_id].ch_freq; + else + chanfreq = channel_freq; + wma_debug("Probe response frame on channel %d vdev:%d", + chanfreq, vdev_id); + if (wma_is_vdev_in_ap_mode(wma_handle, vdev_id) && !chanfreq) + wma_err("AP oper chan is zero"); + } else if (pFc->subType == SIR_MAC_MGMT_ACTION || + pFc->subType == SIR_MAC_MGMT_AUTH) { + chanfreq = channel_freq; + } else { + chanfreq = 0; + } + + if (pFc->type == SIR_MAC_MGMT_FRAME) { + if (((mac->mlme_cfg->gen.debug_packet_log & + DEBUG_PKTLOG_TYPE_MGMT) && + (pFc->subType != SIR_MAC_MGMT_PROBE_REQ) && + (pFc->subType != SIR_MAC_MGMT_PROBE_RSP) && + (pFc->subType != SIR_MAC_MGMT_ACTION)) || + ((mac->mlme_cfg->gen.debug_packet_log & + DEBUG_PKTLOG_TYPE_ACTION) && + (pFc->subType == SIR_MAC_MGMT_ACTION))) + mgmt_txrx_frame_hex_dump(pData, frmLen, true); + } + if (wlan_reg_is_5ghz_ch_freq(wma_handle->interfaces[vdev_id].ch_freq)) + is_5g = true; + + wh = (struct ieee80211_frame *)(qdf_nbuf_data(tx_frame)); + + mlo_link_agnostic = + wlan_get_mlo_link_agnostic_flag(iface->vdev, wh->i_addr1); + + mgmt_param.tx_frame = tx_frame; + mgmt_param.frm_len = frmLen; + mgmt_param.vdev_id = vdev_id; + mgmt_param.pdata = pData; + mgmt_param.chanfreq = chanfreq; + mgmt_param.qdf_ctx = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + mgmt_param.use_6mbps = use_6mbps; + mgmt_param.tx_type = tx_frm_index; + mgmt_param.peer_rssi = peer_rssi; + if (wlan_vdev_mlme_get_opmode(iface->vdev) == QDF_STA_MODE && + wlan_vdev_mlme_is_mlo_vdev(iface->vdev) && + (wlan_vdev_mlme_is_active(iface->vdev) == QDF_STATUS_SUCCESS) && + frmType == TXRX_FRM_802_11_MGMT && + pFc->subType != SIR_MAC_MGMT_PROBE_REQ && + pFc->subType != SIR_MAC_MGMT_AUTH && + action != (ACTION_CATEGORY_PUBLIC << 8 | TDLS_DISCOVERY_RESPONSE) && + action != (ACTION_CATEGORY_BACK << 8 | ADDBA_RESPONSE) && + mlo_link_agnostic) + mgmt_param.mlo_link_agnostic = true; + + if (tx_flag & HAL_USE_INCORRECT_KEY_PMF) + mgmt_param.tx_flags |= MGMT_TX_USE_INCORRECT_KEY; + + /* + * Update the tx_params TLV only for rates + * other than 1Mbps and 6 Mbps + */ + if (rid < RATEID_DEFAULT && + (rid != RATEID_1MBPS && !(rid == RATEID_6MBPS && is_5g))) { + wma_debug("using rate id: %d for Tx", rid); + mgmt_param.tx_params_valid = true; + wma_update_tx_send_params(&mgmt_param.tx_param, rid); + } + + psoc = wma_handle->psoc; + if (!psoc) { + wma_err("psoc ctx is NULL"); + cds_packet_free((void *)tx_frame); + goto error; + } + + if (!wma_handle->pdev) { + wma_err("pdev ctx is NULL"); + cds_packet_free((void *)tx_frame); + goto error; + } + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma_handle->pdev); + mac_addr = wh->i_addr1; + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, WLAN_MGMT_NB_ID); + if (!peer) { + mac_addr = wh->i_addr2; + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_MGMT_NB_ID); + if (!peer) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + vdev_id, + WLAN_MGMT_NB_ID); + if (!vdev) { + wma_err("vdev is null"); + cds_packet_free((void *)tx_frame); + goto error; + } + mld_addr = wlan_vdev_mlme_get_mldaddr(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_MGMT_NB_ID); + if (!mld_addr) { + wma_err("mld addr is null"); + cds_packet_free((void *)tx_frame); + goto error; + } + wma_debug("mld mac addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mld_addr)); + peer = wlan_objmgr_get_peer(psoc, pdev_id, + mld_addr, + WLAN_MGMT_NB_ID); + if (!peer) { + wma_err("peer is null"); + cds_packet_free((void *)tx_frame); + goto error; + } + } + } + + if (ucfg_pkt_capture_get_pktcap_mode(psoc) & + PKT_CAPTURE_MODE_MGMT_ONLY) { + ucfg_pkt_capture_mgmt_tx(wma_handle->pdev, + tx_frame, + wma_handle->interfaces[vdev_id].ch_freq, + mgmt_param.tx_param.preamble_type); + } + + status = wlan_mgmt_txrx_mgmt_frame_tx(peer, wma_handle->mac_context, + (qdf_nbuf_t)tx_frame, NULL, + tx_frm_ota_comp_cb, + WLAN_UMAC_COMP_MLME, + &mgmt_param); + + wlan_objmgr_peer_release_ref(peer, WLAN_MGMT_NB_ID); + if (status != QDF_STATUS_SUCCESS) { + wma_err_rl("mgmt tx failed"); + qdf_nbuf_free((qdf_nbuf_t)tx_frame); + goto error; + } + + /* + * Failed to send Tx Mgmt Frame + */ + if (status) { + /* Call Download Cb so that umac can free the buffer */ + uint32_t rem; + + if (tx_frm_download_comp_cb) + tx_frm_download_comp_cb(wma_handle->mac_context, + tx_frame, + WMA_TX_FRAME_BUFFER_FREE); + rem = qdf_do_div_rem(wma_handle->tx_fail_cnt, + MAX_PRINT_FAILURE_CNT); + if (!rem) + wma_err("Failed to send Mgmt Frame"); + else + wma_debug("Failed to send Mgmt Frame"); + wma_handle->tx_fail_cnt++; + goto error; + } + + if (!tx_frm_download_comp_cb) + return QDF_STATUS_SUCCESS; + + /* + * Wait for Download Complete + * if required + */ + if (downld_comp_required) { + /* + * Wait for Download Complete + * @ Integrated : Dxe Complete + * @ Discrete : Target Download Complete + */ + qdf_status = + qdf_wait_for_event_completion(&wma_handle-> + tx_frm_download_comp_event, + WMA_TX_FRAME_COMPLETE_TIMEOUT); + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_nofl_alert("Wait Event failed txfrm_comp_event"); + /* + * @Integrated: Something Wrong with Dxe + * TODO: Some Debug Code + * Here We need to trigger SSR since + * since system went into a bad state where + * we didn't get Download Complete for almost + * WMA_TX_FRAME_COMPLETE_TIMEOUT (1 sec) + */ + /* display scheduler stats */ + return cdp_display_stats(soc, CDP_SCHEDULER_STATS, + QDF_STATS_VERBOSITY_LEVEL_HIGH); + } + } + + return QDF_STATUS_SUCCESS; + +error: + wma_handle->tx_frm_download_comp_cb = NULL; + wma_handle->umac_data_ota_ack_cb = NULL; + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wma_ds_peek_rx_packet_info(cds_pkt_t *pkt, void **pkt_meta) +{ + if (!pkt) { + wma_err("wma:Invalid parameter sent on wma_peek_rx_pkt_info"); + return QDF_STATUS_E_FAULT; + } + + *pkt_meta = &(pkt->pkt_meta); + + return QDF_STATUS_SUCCESS; +} + +#ifdef HL_RX_AGGREGATION_HOLE_DETECTION +void ol_rx_aggregation_hole(uint32_t hole_info) +{ + struct sir_sme_rx_aggr_hole_ind *rx_aggr_hole_event; + uint32_t alloc_len; + cds_msg_t cds_msg = { 0 }; + QDF_STATUS status; + + alloc_len = sizeof(*rx_aggr_hole_event) + + sizeof(rx_aggr_hole_event->hole_info_array[0]); + rx_aggr_hole_event = qdf_mem_malloc(alloc_len); + if (!rx_aggr_hole_event) + return; + + rx_aggr_hole_event->hole_cnt = 1; + rx_aggr_hole_event->hole_info_array[0] = hole_info; + + cds_msg.type = eWNI_SME_RX_AGGR_HOLE_IND; + cds_msg.bodyptr = rx_aggr_hole_event; + cds_msg.bodyval = 0; + + status = cds_mq_post_message(CDS_MQ_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(rx_aggr_hole_event); + return; + } +} +#endif + +/** + * ol_rx_err() - ol rx err handler + * @pdev: ol pdev + * @vdev_id: vdev id + * @peer_mac_addr: peer mac address + * @tid: TID + * @tsf32: TSF + * @err_type: error type + * @rx_frame: rx frame + * @pn: PN Number + * @key_id: key id + * + * This function handles rx error and send MIC error failure to LIM + * + * Return: none + */ +/* + * Local prototype added to temporarily address warning caused by + * -Wmissing-prototypes. A more correct solution will come later + * as a solution to IR-196435 at which point this prototype will + * be removed. + */ +void ol_rx_err(void *pdev, uint8_t vdev_id, + uint8_t *peer_mac_addr, int tid, uint32_t tsf32, + enum ol_rx_err_type err_type, qdf_nbuf_t rx_frame, + uint64_t *pn, uint8_t key_id); +void ol_rx_err(void *pdev, uint8_t vdev_id, + uint8_t *peer_mac_addr, int tid, uint32_t tsf32, + enum ol_rx_err_type err_type, qdf_nbuf_t rx_frame, + uint64_t *pn, uint8_t key_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct mic_failure_ind *mic_err_ind; + qdf_ether_header_t *eth_hdr; + uint8_t *bssid; + struct scheduler_msg cds_msg = {0}; + + if (!wma) + return; + + if (err_type != OL_RX_ERR_TKIP_MIC) + return; + + if (qdf_nbuf_len(rx_frame) < sizeof(*eth_hdr)) + return; + eth_hdr = (qdf_ether_header_t *)qdf_nbuf_data(rx_frame); + mic_err_ind = qdf_mem_malloc(sizeof(*mic_err_ind)); + if (!mic_err_ind) + return; + + mic_err_ind->messageType = eWNI_SME_MIC_FAILURE_IND; + mic_err_ind->length = sizeof(*mic_err_ind); + mic_err_ind->sessionId = vdev_id; + bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", vdev_id); + qdf_mem_free((void *)mic_err_ind); + return; + } + qdf_copy_macaddr(&mic_err_ind->bssId, + (struct qdf_mac_addr *)bssid); + qdf_mem_copy(mic_err_ind->info.taMacAddr, + (struct qdf_mac_addr *) peer_mac_addr, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.srcMacAddr, + (struct qdf_mac_addr *) eth_hdr->ether_shost, + sizeof(tSirMacAddr)); + qdf_mem_copy(mic_err_ind->info.dstMacAddr, + (struct qdf_mac_addr *) eth_hdr->ether_dhost, + sizeof(tSirMacAddr)); + mic_err_ind->info.keyId = key_id; + mic_err_ind->info.multicast = + IEEE80211_IS_MULTICAST(eth_hdr->ether_dhost); + qdf_mem_copy(mic_err_ind->info.TSC, pn, SIR_CIPHER_SEQ_CTR_SIZE); + + qdf_mem_zero(&cds_msg, sizeof(struct scheduler_msg)); + cds_msg.type = eWNI_SME_MIC_FAILURE_IND; + cds_msg.bodyptr = (void *) mic_err_ind; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_TXRX, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + &cds_msg)) { + wma_err("could not post mic failure indication to SME"); + qdf_mem_free((void *)mic_err_ind); + } +} + +void wma_tx_abort(uint8_t vdev_id) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + tp_wma_handle wma; + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + struct wma_txrx_node *iface; + uint8_t *bssid; + struct peer_flush_params param = {0}; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + iface = &wma->interfaces[vdev_id]; + if (!iface->vdev) { + wma_err("iface->vdev is NULL"); + return; + } + + bssid = wma_get_vdev_bssid(iface->vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", vdev_id); + return; + } + + wma_debug("vdevid %d bssid "QDF_MAC_ADDR_FMT, vdev_id, + QDF_MAC_ADDR_REF(bssid)); + wma_vdev_set_pause_bit(vdev_id, PAUSE_TYPE_HOST); + cdp_fc_vdev_pause(cds_get_context(QDF_MODULE_ID_SOC), vdev_id, + OL_TXQ_PAUSE_REASON_TX_ABORT, 0); + + /* Flush all TIDs except MGMT TID for this peer in Target */ + peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); + param.peer_tid_bitmap = peer_tid_bitmap; + param.vdev_id = vdev_id; + wmi_unified_peer_flush_tids_send(wma->wmi_handle, bssid, + ¶m); +} + +void wma_delete_invalid_peer_entries(uint8_t vdev_id, uint8_t *peer_mac_addr) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint8_t i; + struct wma_txrx_node *iface; + + if (!wma) + return; + + iface = &wma->interfaces[vdev_id]; + + if (peer_mac_addr) { + for (i = 0; i < INVALID_PEER_MAX_NUM; i++) { + if (qdf_mem_cmp + (iface->invalid_peers[i].rx_macaddr, + peer_mac_addr, + QDF_MAC_ADDR_SIZE) == 0) { + qdf_mem_zero(iface->invalid_peers[i].rx_macaddr, + sizeof(QDF_MAC_ADDR_SIZE)); + break; + } + } + if (i == INVALID_PEER_MAX_NUM) + wma_debug("peer_mac_addr "QDF_MAC_ADDR_FMT" is not found", + QDF_MAC_ADDR_REF(peer_mac_addr)); + } else { + qdf_mem_zero(iface->invalid_peers, + sizeof(iface->invalid_peers)); + } +} + +uint8_t wma_rx_invalid_peer_ind(uint8_t vdev_id, void *wh) +{ + struct ol_rx_inv_peer_params *rx_inv_msg; + struct ieee80211_frame *wh_l = (struct ieee80211_frame *)wh; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint8_t i, index; + bool invalid_peer_found = false; + struct wma_txrx_node *iface; + + if (!wma) + return -EINVAL; + + iface = &wma->interfaces[vdev_id]; + rx_inv_msg = qdf_mem_malloc(sizeof(struct ol_rx_inv_peer_params)); + if (!rx_inv_msg) + return -ENOMEM; + + index = iface->invalid_peer_idx; + rx_inv_msg->vdev_id = vdev_id; + qdf_mem_copy(rx_inv_msg->ra, wh_l->i_addr1, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(rx_inv_msg->ta, wh_l->i_addr2, QDF_MAC_ADDR_SIZE); + + + for (i = 0; i < INVALID_PEER_MAX_NUM; i++) { + if (qdf_mem_cmp + (iface->invalid_peers[i].rx_macaddr, + rx_inv_msg->ta, + QDF_MAC_ADDR_SIZE) == 0) { + invalid_peer_found = true; + break; + } + } + + if (!invalid_peer_found) { + qdf_mem_copy(iface->invalid_peers[index].rx_macaddr, + rx_inv_msg->ta, + QDF_MAC_ADDR_SIZE); + + /* reset count if reached max */ + iface->invalid_peer_idx = + (index + 1) % INVALID_PEER_MAX_NUM; + + /* send deauth */ + wma_debug("vdev_id: %d RA: "QDF_MAC_ADDR_FMT" TA: "QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(rx_inv_msg->ra), + QDF_MAC_ADDR_REF(rx_inv_msg->ta)); + + wma_send_msg(wma, + SIR_LIM_RX_INVALID_PEER, + (void *)rx_inv_msg, 0); + } else { + wma_debug_rl("Ignore invalid peer indication as received more than once " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(rx_inv_msg->ta)); + qdf_mem_free(rx_inv_msg); + } + + return 0; +} + +static bool +wma_drop_delba(tp_wma_handle wma, uint8_t vdev_id, + enum cdp_delba_rcode cdp_reason_code) +{ + struct wlan_objmgr_vdev *vdev; + qdf_time_t last_ts, ts = qdf_mc_timer_get_system_time(); + bool drop = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_MLME_CM_ID); + if (!vdev) { + wma_err("vdev is NULL"); + return drop; + } + if (!wlan_mlme_is_ba_2k_jump_iot_ap(vdev)) + goto done; + + last_ts = wlan_mlme_get_last_delba_sent_time(vdev); + if ((last_ts && cdp_reason_code == CDP_DELBA_2K_JUMP) && + (ts - last_ts) < CDP_DELBA_INTERVAL_MS) { + wma_debug("Drop DELBA, last sent ts: %lu current ts: %lu", + last_ts, ts); + drop = true; + } + + wlan_mlme_set_last_delba_sent_time(vdev, ts); + +done: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_CM_ID); + + return drop; +} + +int wma_dp_send_delba_ind(uint8_t vdev_id, uint8_t *peer_macaddr, + uint8_t tid, uint8_t reason_code, + enum cdp_delba_rcode cdp_reason_code) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct lim_delba_req_info *req; + + if (!wma || !peer_macaddr) { + wma_err("wma handle or mac addr is NULL"); + return -EINVAL; + } + + if (wma_drop_delba(wma, vdev_id, cdp_reason_code)) + return 0; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return -ENOMEM; + req->vdev_id = vdev_id; + qdf_mem_copy(req->peer_macaddr, peer_macaddr, QDF_MAC_ADDR_SIZE); + req->tid = tid; + req->reason_code = reason_code; + wma_debug("req delba_ind vdev %d "QDF_MAC_ADDR_FMT" tid %d reason %d", + vdev_id, QDF_MAC_ADDR_REF(peer_macaddr), tid, reason_code); + wma_send_msg_high_priority(wma, SIR_HAL_REQ_SEND_DELBA_REQ_IND, + (void *)req, 0); + + return 0; +} + +bool wma_is_roam_in_progress(uint32_t vdev_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + enum QDF_OPMODE opmode; + + if (!wma_is_vdev_valid(vdev_id)) + return false; + + if (!wma || !wma->interfaces[vdev_id].vdev) + return false; + + opmode = wlan_vdev_mlme_get_opmode(wma->interfaces[vdev_id].vdev); + if (opmode != QDF_STA_MODE && opmode != QDF_P2P_CLIENT_MODE) + return false; + + return wlan_cm_is_vdev_roam_started(wma->interfaces[vdev_id].vdev); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_dev_if.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_dev_if.c new file mode 100644 index 0000000000..7c364897b3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_dev_if.c @@ -0,0 +1,7078 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_dev_if.c + * This file contains vdev & peer related operations. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" +#include "wma_pasn_peer_api.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" + +#include "wma_internal.h" + +#include "wma_ocb.h" +#include "cdp_txrx_cfg.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include +#include +#include + +#include "wlan_policy_mgr_api.h" +#include "wma_nan_datapath.h" +#include "wifi_pos_pasn_api.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include +#include +#include "wlan_pmo_ucfg_api.h" +#include "wlan_reg_services_api.h" +#include +#include "wma_he.h" +#include "wma_eht.h" +#include "wlan_roam_debug.h" +#include "wlan_ocb_ucfg_api.h" +#include "init_deinit_lmac.h" +#include +#include "wlan_policy_mgr_ucfg.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_main.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_mlme_twt_api.h" +#include +#include "../../core/src/vdev_mgr_ops.h" +#include "wlan_utility.h" +#include "wlan_coex_ucfg_api.h" +#include +#include "wmi_unified_vdev_api.h" +#include +#include <../../core/src/wlan_cm_vdev_api.h> +#include "wlan_nan_api.h" +#include "wlan_mlo_mgr_peer.h" +#include "wifi_pos_api.h" +#include "wifi_pos_pasn_api.h" +#ifdef DCS_INTERFERENCE_DETECTION +#include +#endif + +#ifdef FEATURE_STA_MODE_VOTE_LINK +#include "wlan_ipa_ucfg_api.h" +#endif + +#include "son_api.h" +#include "wlan_vdev_mgr_tgt_if_tx_defs.h" +#include "wlan_mlo_mgr_roam.h" +#include "target_if_vdev_mgr_tx_ops.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_vdev_mgr_utils_api.h" +#include "target_if.h" +#include + +/* + * FW only supports 8 clients in SAP/GO mode for D3 WoW feature + * and hence host needs to hold a wake lock after 9th client connects + * and release the wake lock when 9th client disconnects + */ +#define SAP_D3_WOW_MAX_CLIENT_HOLD_WAKE_LOCK (9) +#define SAP_D3_WOW_MAX_CLIENT_RELEASE_WAKE_LOCK (8) + +QDF_STATUS wma_find_vdev_id_by_addr(tp_wma_handle wma, uint8_t *addr, + uint8_t *vdev_id) +{ + uint8_t i; + struct wlan_objmgr_vdev *vdev; + + for (i = 0; i < wma->max_bssid; i++) { + vdev = wma->interfaces[i].vdev; + if (!vdev) + continue; + + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev), + (struct qdf_mac_addr *)addr) == true) { + *vdev_id = i; + return QDF_STATUS_SUCCESS; + } + + if (qdf_is_macaddr_equal((struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev), + (struct qdf_mac_addr *)addr) == true) { + *vdev_id = i; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} + + +/** + * wma_is_vdev_in_ap_mode() - check that vdev is in ap mode or not + * @wma: wma handle + * @vdev_id: vdev id + * + * Helper function to know whether given vdev id + * is in AP mode or not. + * + * Return: True/False + */ +bool wma_is_vdev_in_ap_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %hu", vdev_id); + QDF_ASSERT(0); + return false; + } + + if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) && + ((intf[vdev_id].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) || + (intf[vdev_id].sub_type == 0))) + return true; + + return false; +} + +uint8_t *wma_get_vdev_bssid(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_mlme_obj *mlme_obj; + + if (!vdev) { + wma_err("vdev is NULL"); + return NULL; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("Failed to get mlme_obj"); + return NULL; + } + + return mlme_obj->mgmt.generic.bssid; +} + +QDF_STATUS wma_find_vdev_id_by_bssid(tp_wma_handle wma, uint8_t *bssid, + uint8_t *vdev_id) +{ + int i; + uint8_t *bssid_addr; + + for (i = 0; i < wma->max_bssid; i++) { + if (!wma->interfaces[i].vdev) + continue; + bssid_addr = wma_get_vdev_bssid(wma->interfaces[i].vdev); + if (!bssid_addr) + continue; + + if (qdf_is_macaddr_equal( + (struct qdf_mac_addr *)bssid_addr, + (struct qdf_mac_addr *)bssid) == true) { + *vdev_id = i; + return QDF_STATUS_SUCCESS; + } + } + + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_find_req_on_timer_expiry() - find request by address + * @wma: wma handle + * @req: pointer to the target request + * + * On timer expiry, the pointer to the req message is received from the + * timer callback. Lookup the wma_hold_req_queue for the request with the + * same address and return success if found. + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_find_req_on_timer_expiry(tp_wma_handle wma, + struct wma_target_req *req) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *cur_node = NULL, *next_node = NULL; + QDF_STATUS status; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->wma_hold_req_queue, + &next_node)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_err("unable to get msg node from request queue"); + return QDF_STATUS_E_FAILURE; + } + + do { + cur_node = next_node; + req_msg = qdf_container_of(cur_node, + struct wma_target_req, node); + if (req_msg != req) + continue; + + found = true; + status = qdf_list_remove_node(&wma->wma_hold_req_queue, + cur_node); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_debug("Failed to remove request for req %pK", req); + return QDF_STATUS_E_FAILURE; + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->wma_hold_req_queue, + cur_node, &next_node)); + + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + if (!found) { + wma_err("target request not found for req %pK", req); + return QDF_STATUS_E_INVAL; + } + + wma_debug("target request found for vdev id: %d type %d", + req_msg->vdev_id, req_msg->type); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_find_req() - find target request for vdev id + * @wma: wma handle + * @vdev_id: vdev id + * @type: request type + * @peer_addr: Peer mac address + * + * Find target request for given vdev id & type of request. + * Remove that request from active list. + * + * Return: return target request if found or NULL. + */ +static struct wma_target_req *wma_find_req(tp_wma_handle wma, + uint8_t vdev_id, uint8_t type, + struct qdf_mac_addr *peer_addr) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + QDF_STATUS status; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->wma_hold_req_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_err("unable to get msg node from request queue"); + return NULL; + } + + do { + node1 = node2; + req_msg = qdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->type != type) + continue; + + found = true; + if (type == WMA_PEER_CREATE_RESPONSE && + peer_addr && + !qdf_is_macaddr_equal(&req_msg->addr, peer_addr)) + found = false; + + status = qdf_list_remove_node(&wma->wma_hold_req_queue, node1); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_debug("Failed to remove request for vdev_id %d type %d", + vdev_id, type); + return NULL; + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->wma_hold_req_queue, node1, + &node2)); + + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + if (!found) { + wma_err("target request not found for vdev_id %d type %d", + vdev_id, type); + return NULL; + } + + wma_debug("target request found for vdev id: %d type %d", + vdev_id, type); + + return req_msg; +} + +struct wma_target_req *wma_find_remove_req_msgtype(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type) +{ + struct wma_target_req *req_msg = NULL; + bool found = false; + qdf_list_node_t *node1 = NULL, *node2 = NULL; + QDF_STATUS status; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (QDF_STATUS_SUCCESS != qdf_list_peek_front(&wma->wma_hold_req_queue, + &node2)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_debug("unable to get msg node from request queue for vdev_id %d type %d", + vdev_id, msg_type); + return NULL; + } + + do { + node1 = node2; + req_msg = qdf_container_of(node1, struct wma_target_req, node); + if (req_msg->vdev_id != vdev_id) + continue; + if (req_msg->msg_type != msg_type) + continue; + + found = true; + status = qdf_list_remove_node(&wma->wma_hold_req_queue, node1); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_debug("Failed to remove request. vdev_id %d type %d", + vdev_id, msg_type); + return NULL; + } + break; + } while (QDF_STATUS_SUCCESS == + qdf_list_peek_next(&wma->wma_hold_req_queue, node1, + &node2)); + + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + if (!found) { + wma_debug("target request not found for vdev_id %d type %d", + vdev_id, msg_type); + return NULL; + } + + wma_debug("target request found for vdev id: %d type %d", + vdev_id, msg_type); + + return req_msg; +} + +QDF_STATUS wma_vdev_detach_callback(struct vdev_delete_response *rsp) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface = NULL; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_FAILURE; + + /* Sanitize the vdev id*/ + if (rsp->vdev_id >= wma->max_bssid) { + wma_err("vdev delete response with invalid vdev_id :%d", + rsp->vdev_id); + QDF_BUG(0); + return QDF_STATUS_E_FAILURE; + } + + iface = &wma->interfaces[rsp->vdev_id]; + + wma_debug("vdev del response received for VDEV_%d", rsp->vdev_id); + iface->del_staself_req = NULL; + + if (iface->roam_scan_stats_req) { + struct sir_roam_scan_stats *roam_scan_stats_req = + iface->roam_scan_stats_req; + + iface->roam_scan_stats_req = NULL; + qdf_mem_free(roam_scan_stats_req); + } + + wma_vdev_deinit(iface); + qdf_mem_zero(iface, sizeof(*iface)); + wma_vdev_init(iface); + + mlme_vdev_del_resp(rsp->vdev_id); + + return QDF_STATUS_SUCCESS; +} + +static void +wma_cdp_vdev_detach(ol_txrx_soc_handle soc, tp_wma_handle wma_handle, + uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct wlan_objmgr_vdev *vdev = iface->vdev; + + if (!vdev) { + wma_err("vdev is NULL"); + return; + } + + if (soc && wlan_vdev_get_id(vdev) != WLAN_INVALID_VDEV_ID) + cdp_vdev_detach(soc, vdev_id, NULL, NULL); +} + +/** + * wma_release_vdev_ref() - Release vdev object reference count + * @iface: wma interface txrx node + * + * Purpose of this function is to release vdev object reference count + * from wma interface txrx node. + * + * Return: None + */ +static void +wma_release_vdev_ref(struct wma_txrx_node *iface) +{ + struct wlan_objmgr_vdev *vdev; + + vdev = iface->vdev; + if (!vdev) { + wma_debug("vdev context is NULL"); + return; + } + wma_debug("vdev state: %d", vdev->obj_state); + if (vdev->obj_state != WLAN_OBJ_STATE_LOGICALLY_DELETED) { + wma_debug("no vdev delete"); + return; + } + iface->vdev_active = false; + iface->vdev = NULL; + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); +} + +/** + * wma_handle_monitor_mode_vdev_detach() - Stop and down monitor mode vdev + * @wma: wma handle + * @vdev_id: used to get wma interface txrx node + * + * Monitor mode is unconneted mode, so do explicit vdev stop and down + * + * Return: None + */ +static void wma_handle_monitor_mode_vdev_detach(tp_wma_handle wma, + uint8_t vdev_id) +{ + struct wma_txrx_node *iface; + + iface = &wma->interfaces[vdev_id]; + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_DOWN, + 0, NULL); + iface->vdev_active = false; +} + +/** + * wma_handle_vdev_detach() - wma vdev detach handler + * @wma_handle: pointer to wma handle + * @del_vdev_req_param: pointer to del req param + * + * Return: none. + */ +static QDF_STATUS wma_handle_vdev_detach(tp_wma_handle wma_handle, + struct del_vdev_params *del_vdev_req_param) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = del_vdev_req_param->vdev_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wmi_mgmt_params mgmt_params = {}; + + if (!soc) { + status = QDF_STATUS_E_FAILURE; + goto rel_ref; + } + + if ((cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) || + (policy_mgr_is_sta_mon_concurrency(wma_handle->psoc) && + wlan_vdev_mlme_get_opmode(iface->vdev) == QDF_MONITOR_MODE)) + wma_handle_monitor_mode_vdev_detach(wma_handle, vdev_id); + +rel_ref: + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + if (qdf_is_recovering()) + wlan_mgmt_txrx_vdev_drain(iface->vdev, + wma_mgmt_frame_fill_peer_cb, + &mgmt_params); + wma_debug("Releasing wma reference for vdev:%d", vdev_id); + wma_release_vdev_ref(iface); + return status; +} + +/** + * wma_self_peer_remove() - Self peer remove handler + * @wma_handle: wma handle + * @del_vdev_req: vdev id + * + * Return: success if peer delete command sent to firmware, else failure. + */ +static QDF_STATUS wma_self_peer_remove(tp_wma_handle wma_handle, + struct del_vdev_params *del_vdev_req) +{ + QDF_STATUS qdf_status; + uint8_t vdev_id = del_vdev_req->vdev_id; + struct wma_target_req *msg = NULL; + struct del_sta_self_rsp_params *sta_self_wmi_rsp = NULL; + + wma_debug("P2P Device: removing self peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(del_vdev_req->self_mac_addr)); + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sync_delete_cmds)) { + sta_self_wmi_rsp = + qdf_mem_malloc(sizeof(struct del_sta_self_rsp_params)); + if (!sta_self_wmi_rsp) { + qdf_status = QDF_STATUS_E_NOMEM; + goto error; + } + + sta_self_wmi_rsp->self_sta_param = del_vdev_req; + msg = wma_fill_hold_req(wma_handle, vdev_id, + WMA_DELETE_STA_REQ, + WMA_DEL_P2P_SELF_STA_RSP_START, + sta_self_wmi_rsp, + WMA_DELETE_STA_TIMEOUT); + if (!msg) { + wma_err("Failed to allocate request for vdev_id %d", + vdev_id); + wma_remove_req(wma_handle, vdev_id, + WMA_DEL_P2P_SELF_STA_RSP_START); + qdf_mem_free(sta_self_wmi_rsp); + qdf_status = QDF_STATUS_E_FAILURE; + goto error; + } + } + + qdf_status = wma_remove_peer(wma_handle, del_vdev_req->self_mac_addr, + vdev_id, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("wma_remove_peer is failed"); + wma_remove_req(wma_handle, vdev_id, + WMA_DEL_P2P_SELF_STA_RSP_START); + if (sta_self_wmi_rsp) + qdf_mem_free(sta_self_wmi_rsp); + + goto error; + } + +error: + return qdf_status; +} + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +QDF_STATUS wma_p2p_self_peer_remove(struct wlan_objmgr_vdev *vdev) +{ + struct del_vdev_params *del_self_peer_req; + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + del_self_peer_req = qdf_mem_malloc(sizeof(*del_self_peer_req)); + if (!del_self_peer_req) + return QDF_STATUS_E_NOMEM; + + del_self_peer_req->vdev = vdev; + del_self_peer_req->vdev_id = wlan_vdev_get_id(vdev); + qdf_mem_copy(del_self_peer_req->self_mac_addr, + wlan_vdev_mlme_get_macaddr(vdev), + QDF_MAC_ADDR_SIZE); + + status = wma_self_peer_remove(wma_handle, del_self_peer_req); + + return status; +} +#endif + +void wma_remove_objmgr_peer(tp_wma_handle wma, + struct wlan_objmgr_vdev *obj_vdev, + uint8_t *peer_addr) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *obj_peer; + struct wlan_objmgr_pdev *obj_pdev; + uint8_t pdev_id = 0; + + psoc = wma->psoc; + if (!psoc) { + wma_err("PSOC is NULL"); + return; + } + + obj_pdev = wlan_vdev_get_pdev(obj_vdev); + pdev_id = wlan_objmgr_pdev_get_pdev_id(obj_pdev); + obj_peer = wlan_objmgr_get_peer(psoc, pdev_id, peer_addr, + WLAN_LEGACY_WMA_ID); + if (obj_peer) { + wlan_objmgr_peer_obj_delete(obj_peer); + /* Unref to decrement ref happened in find_peer */ + wlan_objmgr_peer_release_ref(obj_peer, WLAN_LEGACY_WMA_ID); + } else { + wma_nofl_err("Peer "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(peer_addr)); + } + +} + +static QDF_STATUS wma_check_for_deferred_peer_delete(tp_wma_handle wma_handle, + struct del_vdev_params + *pdel_vdev_req_param) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = pdel_vdev_req_param->vdev_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + uint32_t vdev_stop_type; + + if (qdf_atomic_read(&iface->bss_status) == WMA_BSS_STATUS_STARTED) { + status = mlme_get_vdev_stop_type(iface->vdev, &vdev_stop_type); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get wma req msg_type for vdev_id: %d", + vdev_id); + status = QDF_STATUS_E_INVAL; + return status; + } + + if (vdev_stop_type != WMA_DELETE_BSS_REQ) { + status = QDF_STATUS_E_INVAL; + return status; + } + + wma_debug("BSS is not yet stopped. Deferring vdev(vdev id %x) deletion", + vdev_id); + iface->del_staself_req = pdel_vdev_req_param; + iface->is_del_sta_deferred = true; + } + + return status; +} + +static QDF_STATUS +wma_vdev_self_peer_delete(tp_wma_handle wma_handle, + struct del_vdev_params *pdel_vdev_req_param) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = pdel_vdev_req_param->vdev_id; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + + if (mlme_vdev_uses_self_peer(iface->type, iface->sub_type)) { + status = wma_self_peer_remove(wma_handle, pdel_vdev_req_param); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("can't remove selfpeer, send rsp session: %d", + vdev_id); + wma_handle_vdev_detach(wma_handle, pdel_vdev_req_param); + mlme_vdev_self_peer_delete_resp(pdel_vdev_req_param); + cds_trigger_recovery(QDF_SELF_PEER_DEL_FAILED); + return status; + } + } else if (iface->type == WMI_VDEV_TYPE_STA || + iface->type == WMI_VDEV_TYPE_NAN) { + wma_remove_objmgr_peer(wma_handle, iface->vdev, + pdel_vdev_req_param->self_mac_addr); + } + + return status; +} + +QDF_STATUS wma_vdev_detach(struct del_vdev_params *pdel_vdev_req_param) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id; + struct wma_txrx_node *iface = NULL; + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + vdev_id = wlan_vdev_get_id(pdel_vdev_req_param->vdev); + iface = &wma_handle->interfaces[vdev_id]; + if (!iface->vdev) { + wma_err("vdev %d is NULL", vdev_id); + return status; + } + + status = wma_check_for_deferred_peer_delete(wma_handle, + pdel_vdev_req_param); + if (QDF_IS_STATUS_ERROR(status)) + goto send_fail_rsp; + + if (iface->is_del_sta_deferred) + return status; + + iface->is_del_sta_deferred = false; + iface->del_staself_req = NULL; + + status = wma_vdev_self_peer_delete(wma_handle, pdel_vdev_req_param); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send self peer delete:%d", status); + status = QDF_STATUS_E_INVAL; + return status; + } + + if (iface->type != WMI_VDEV_TYPE_MONITOR) + iface->vdev_active = false; + + if (!mlme_vdev_uses_self_peer(iface->type, iface->sub_type) || + !wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sync_delete_cmds)) { + status = wma_handle_vdev_detach(wma_handle, + pdel_vdev_req_param); + pdel_vdev_req_param->status = status; + mlme_vdev_self_peer_delete_resp(pdel_vdev_req_param); + } + + return status; + +send_fail_rsp: + wma_err("rcvd del_self_sta without del_bss; vdev_id:%d", vdev_id); + cds_trigger_recovery(QDF_DEL_SELF_STA_FAILED); + status = QDF_STATUS_E_FAILURE; + return status; +} + +/** + * wma_send_start_resp() - send vdev start response to upper layer + * @wma: wma handle + * @add_bss_rsp: add bss params + * @rsp: response params + * + * Return: none + */ +static void wma_send_start_resp(tp_wma_handle wma, + struct add_bss_rsp *add_bss_rsp, + struct vdev_start_response *rsp) +{ + struct wma_txrx_node *iface = &wma->interfaces[rsp->vdev_id]; + QDF_STATUS status; + + if (QDF_IS_STATUS_SUCCESS(rsp->status) && + QDF_IS_STATUS_SUCCESS(add_bss_rsp->status)) { + status = + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_START_RESP, + sizeof(*add_bss_rsp), + add_bss_rsp); + if (QDF_IS_STATUS_SUCCESS(status)) + return; + + add_bss_rsp->status = status; + } + + /* Send vdev stop if vdev start was success */ + if (QDF_IS_STATUS_ERROR(add_bss_rsp->status) && + QDF_IS_STATUS_SUCCESS(rsp->status)) { + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_DOWN, + sizeof(*add_bss_rsp), + add_bss_rsp); + return; + } + + wma_remove_bss_peer_on_failure(wma, rsp->vdev_id); + + wma_debug("Sending add bss rsp to umac(vdev %d status %d)", + rsp->vdev_id, add_bss_rsp->status); + lim_handle_add_bss_rsp(wma->mac_context, add_bss_rsp); +} + +/** + * wma_vdev_start_rsp() - send vdev start response to upper layer + * @wma: wma handle + * @vdev: vdev + * @rsp: response params + * + * Return: none + */ +static void wma_vdev_start_rsp(tp_wma_handle wma, struct wlan_objmgr_vdev *vdev, + struct vdev_start_response *rsp) +{ + struct beacon_info *bcn; + enum QDF_OPMODE opmode; + struct add_bss_rsp *add_bss_rsp; + + opmode = wlan_vdev_mlme_get_opmode(vdev); + + add_bss_rsp = qdf_mem_malloc(sizeof(*add_bss_rsp)); + if (!add_bss_rsp) + return; + + add_bss_rsp->vdev_id = rsp->vdev_id; + add_bss_rsp->status = rsp->status; + add_bss_rsp->chain_mask = rsp->chain_mask; + add_bss_rsp->smps_mode = host_map_smps_mode(rsp->smps_mode); + + if (rsp->status) + goto send_fail_resp; + + if (opmode == QDF_P2P_GO_MODE || opmode == QDF_SAP_MODE) { + wma->interfaces[rsp->vdev_id].beacon = + qdf_mem_malloc(sizeof(struct beacon_info)); + + bcn = wma->interfaces[rsp->vdev_id].beacon; + if (!bcn) { + add_bss_rsp->status = QDF_STATUS_E_NOMEM; + goto send_fail_resp; + } + bcn->buf = qdf_nbuf_alloc(NULL, SIR_MAX_BEACON_SIZE, 0, + sizeof(uint32_t), 0); + if (!bcn->buf) { + qdf_mem_free(bcn); + add_bss_rsp->status = QDF_STATUS_E_FAILURE; + goto send_fail_resp; + } + bcn->seq_no = MIN_SW_SEQ; + qdf_spinlock_create(&bcn->lock); + qdf_atomic_set(&wma->interfaces[rsp->vdev_id].bss_status, + WMA_BSS_STATUS_STARTED); + wma_debug("AP mode (type %d subtype %d) BSS is started", + wma->interfaces[rsp->vdev_id].type, + wma->interfaces[rsp->vdev_id].sub_type); + } + +send_fail_resp: + wma_send_start_resp(wma, add_bss_rsp, rsp); +} + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wma_find_mcc_ap() - finds if device is operating AP in MCC mode or not + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * @add: flag indicating if current device is added or deleted + * + * This function parses through all the interfaces in wma and finds if + * any of those devces are in MCC mode with AP. If such a vdev is found + * involved AP vdevs are sent WDA_UPDATE_Q2Q_IE_IND msg to update their + * beacon template to include Q2Q IE. + * + * Return: none + */ +static void wma_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id, bool add) +{ + uint8_t i; + uint16_t prev_ch_freq = 0; + bool is_ap = false; + bool result = false; + uint8_t *ap_vdev_ids = NULL; + uint8_t num_ch = 0; + + ap_vdev_ids = qdf_mem_malloc(wma->max_bssid); + if (!ap_vdev_ids) + return; + + for (i = 0; i < wma->max_bssid; i++) { + ap_vdev_ids[i] = -1; + if (add == false && i == vdev_id) + continue; + + if (wma_is_vdev_up(vdev_id) || (i == vdev_id && add)) { + if (wma->interfaces[i].type == WMI_VDEV_TYPE_AP) { + is_ap = true; + ap_vdev_ids[i] = i; + } + + if (wma->interfaces[i].ch_freq != prev_ch_freq) { + num_ch++; + prev_ch_freq = wma->interfaces[i].ch_freq; + } + } + } + + if (is_ap && (num_ch > 1)) + result = true; + else + result = false; + + wma_send_msg(wma, WMA_UPDATE_Q2Q_IE_IND, (void *)ap_vdev_ids, result); +} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +/** + * wma_handle_hidden_ssid_restart() - handle hidden ssid restart + * @wma: wma handle + * @iface: interface pointer + * + * Return: none + */ +static void wma_handle_hidden_ssid_restart(tp_wma_handle wma, + struct wma_txrx_node *iface) +{ + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_RESTART_RESP, + 0, NULL); +} + +#ifdef WLAN_FEATURE_11BE +/** + * wma_get_peer_phymode() - get phy mode and eht puncture + * @nw_type: wlan type + * @old_peer_phymode: old peer phy mode + * @vdev_chan: vdev channel + * @is_eht: is eht mode + * @puncture_bitmap: eht puncture bitmap + * + * Return: new wlan phy mode + */ +static enum wlan_phymode +wma_get_peer_phymode(tSirNwType nw_type, enum wlan_phymode old_peer_phymode, + struct wlan_channel *vdev_chan, bool *is_eht, + uint16_t *puncture_bitmap) +{ + enum wlan_phymode new_phymode; + + new_phymode = wma_peer_phymode(nw_type, STA_ENTRY_PEER, + IS_WLAN_PHYMODE_HT(old_peer_phymode), + vdev_chan->ch_width, + IS_WLAN_PHYMODE_VHT(old_peer_phymode), + IS_WLAN_PHYMODE_HE(old_peer_phymode), + IS_WLAN_PHYMODE_EHT(old_peer_phymode)); + *is_eht = IS_WLAN_PHYMODE_EHT(new_phymode); + if (*is_eht) + *puncture_bitmap = vdev_chan->puncture_bitmap; + + return new_phymode; +} +#else +static enum wlan_phymode +wma_get_peer_phymode(tSirNwType nw_type, enum wlan_phymode old_peer_phymode, + struct wlan_channel *vdev_chan, bool *is_eht, + uint16_t *puncture_bitmap) +{ + enum wlan_phymode new_phymode; + + new_phymode = wma_peer_phymode(nw_type, STA_ENTRY_PEER, + IS_WLAN_PHYMODE_HT(old_peer_phymode), + vdev_chan->ch_width, + IS_WLAN_PHYMODE_VHT(old_peer_phymode), + IS_WLAN_PHYMODE_HE(old_peer_phymode), + 0); + + return new_phymode; +} +#endif + +static void wma_peer_send_phymode(struct wlan_objmgr_vdev *vdev, + void *object, void *arg) +{ + struct wlan_objmgr_peer *peer = object; + enum wlan_phymode old_peer_phymode; + struct wlan_channel *vdev_chan; + enum wlan_phymode new_phymode; + tSirNwType nw_type; + uint32_t fw_phymode; + uint32_t max_ch_width_supported; + tp_wma_handle wma; + uint8_t *peer_mac_addr; + uint8_t vdev_id; + bool is_eht = false; + uint16_t puncture_bitmap = 0; + uint16_t new_puncture_bitmap = 0; + uint32_t bw_puncture = 0; + enum phy_ch_width new_bw; + + if (wlan_peer_get_peer_type(peer) == WLAN_PEER_SELF) + return; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if(!wma) + return; + + old_peer_phymode = wlan_peer_get_phymode(peer); + vdev_chan = wlan_vdev_mlme_get_des_chan(vdev); + + peer_mac_addr = wlan_peer_get_macaddr(peer); + + if (WLAN_REG_IS_24GHZ_CH_FREQ(vdev_chan->ch_freq)) { + if (vdev_chan->ch_phymode == WLAN_PHYMODE_11B || + old_peer_phymode == WLAN_PHYMODE_11B) + nw_type = eSIR_11B_NW_TYPE; + else + nw_type = eSIR_11G_NW_TYPE; + } else { + nw_type = eSIR_11A_NW_TYPE; + } + + new_phymode = wma_get_peer_phymode(nw_type, old_peer_phymode, + vdev_chan, &is_eht, + &puncture_bitmap); + + if (!is_eht && new_phymode == old_peer_phymode) { + wma_debug("Ignore update as old %d and new %d phymode are same for mac "QDF_MAC_ADDR_FMT, + old_peer_phymode, new_phymode, + QDF_MAC_ADDR_REF(peer_mac_addr)); + return; + } + wlan_peer_set_phymode(peer, new_phymode); + + fw_phymode = wmi_host_to_fw_phymode(new_phymode); + vdev_id = wlan_vdev_get_id(vdev); + + max_ch_width_supported = + wmi_get_ch_width_from_phy_mode(wma->wmi_handle, + fw_phymode); + new_bw = + target_if_wmi_chan_width_to_phy_ch_width(max_ch_width_supported); + + if (is_eht) { + wlan_reg_extract_puncture_by_bw(vdev_chan->ch_width, + puncture_bitmap, + vdev_chan->ch_freq, + vdev_chan->ch_freq_seg2, + new_bw, + &new_puncture_bitmap); + QDF_SET_BITS(bw_puncture, 0, 8, new_bw); + QDF_SET_BITS(bw_puncture, 8, 16, new_puncture_bitmap); + wlan_util_vdev_peer_set_param_send(vdev, peer_mac_addr, + WLAN_MLME_PEER_BW_PUNCTURE, + bw_puncture); + } else { + wma_set_peer_param(wma, peer_mac_addr, WMI_HOST_PEER_CHWIDTH, + max_ch_width_supported, vdev_id); + } + + wma_set_peer_param(wma, peer_mac_addr, WMI_HOST_PEER_PHYMODE, + fw_phymode, vdev_id); + wma_debug("FW phymode %d old phymode %d new phymode %d bw %d punct: 0x%x macaddr " QDF_MAC_ADDR_FMT, + fw_phymode, old_peer_phymode, new_phymode, + max_ch_width_supported, new_puncture_bitmap, + QDF_MAC_ADDR_REF(peer_mac_addr)); +} + +static +void wma_update_rate_flags_after_vdev_restart(tp_wma_handle wma, + struct wma_txrx_node *iface) +{ + struct vdev_mlme_obj *vdev_mlme; + uint32_t rate_flags = 0; + enum wlan_phymode bss_phymode; + struct wlan_channel *des_chan; + + if (iface->type != WMI_VDEV_TYPE_STA) + return; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!vdev_mlme) + return; + + des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev); + bss_phymode = des_chan->ch_phymode; + + if (wma_is_eht_phymode_supported(bss_phymode)) { + rate_flags = wma_get_eht_rate_flags(des_chan->ch_width); + } else if (IS_WLAN_PHYMODE_HE(bss_phymode)) { + rate_flags = wma_get_he_rate_flags(des_chan->ch_width); + } else if (IS_WLAN_PHYMODE_VHT(bss_phymode)) { + rate_flags = wma_get_vht_rate_flags(des_chan->ch_width); + } else if (IS_WLAN_PHYMODE_HT(bss_phymode)) { + rate_flags = wma_get_ht_rate_flags(des_chan->ch_width); + } else { + rate_flags = TX_RATE_LEGACY; + } + + vdev_mlme->mgmt.rate_info.rate_flags = rate_flags; + + wma_debug("bss phymode %d rate_flags %x, ch_width %d", + bss_phymode, rate_flags, des_chan->ch_width); + + ucfg_mc_cp_stats_set_rate_flags(iface->vdev, rate_flags); +} + +QDF_STATUS wma_handle_channel_switch_resp(tp_wma_handle wma, + struct vdev_start_response *rsp) +{ + enum wlan_vdev_sm_evt event; + struct wma_txrx_node *iface; + + iface = &wma->interfaces[rsp->vdev_id]; + wma_debug("Send channel switch resp vdev %d status %d", + rsp->vdev_id, rsp->status); + + /* Indicate channel switch failure to LIM */ + if (QDF_IS_STATUS_ERROR(rsp->status) && + (iface->type == WMI_VDEV_TYPE_MONITOR || + wma_is_vdev_in_ap_mode(wma, rsp->vdev_id) || + mlme_is_chan_switch_in_progress(iface->vdev))) { + mlme_set_chan_switch_in_progress(iface->vdev, false); + lim_process_switch_channel_rsp(wma->mac_context, rsp); + return QDF_STATUS_SUCCESS; + } + + if (QDF_IS_STATUS_SUCCESS(rsp->status) && + rsp->resp_type == WMI_VDEV_RESTART_RESP_EVENT) { + wlan_objmgr_iterate_peerobj_list(iface->vdev, + wma_peer_send_phymode, NULL, + WLAN_LEGACY_WMA_ID); + wma_update_rate_flags_after_vdev_restart(wma, iface); + } + + if (wma_is_vdev_in_ap_mode(wma, rsp->vdev_id) || + mlme_is_chan_switch_in_progress(iface->vdev)) + event = WLAN_VDEV_SM_EV_RESTART_RESP; + else + event = WLAN_VDEV_SM_EV_START_RESP; + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, event, + sizeof(rsp), rsp); + + return QDF_STATUS_SUCCESS; +} + +#ifdef DCS_INTERFERENCE_DETECTION +/** + * wma_dcs_clear_vdev_starting() - clear vdev starting within dcs information + * @mac_ctx: mac context + * @vdev_id: vdev id + * + * This function is used to clear vdev starting within dcs information + * + * Return: None + */ +static void wma_dcs_clear_vdev_starting(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ + mac_ctx->sap.dcs_info.is_vdev_starting[vdev_id] = false; +} + +/** + * wma_dcs_wlan_interference_mitigation_enable() - enable wlan + * interference mitigation + * @mac_ctx: mac context + * @mac_id: mac id + * @rsp: vdev start response + * + * This function is used to enable wlan interference mitigation through + * send dcs command + * + * Return: None + */ +static void wma_dcs_wlan_interference_mitigation_enable( + struct mac_context *mac_ctx, + uint32_t mac_id, + struct vdev_start_response *rsp) +{ + int vdev_index; + uint32_t list[MAX_NUMBER_OF_CONC_CONNECTIONS]; + uint32_t count; + bool wlan_interference_mitigation_enable = + mac_ctx->sap.dcs_info. + wlan_interference_mitigation_enable[rsp->vdev_id]; + + count = policy_mgr_get_sap_go_count_on_mac( + mac_ctx->psoc, list, mac_id); + + for (vdev_index = 0; vdev_index < count; vdev_index++) { + if (mac_ctx->sap.dcs_info.is_vdev_starting[list[vdev_index]]) { + wma_err("vdev %d: does not finish restart", + list[vdev_index]); + return; + } + wlan_interference_mitigation_enable = + wlan_interference_mitigation_enable || + mac_ctx->sap.dcs_info. + wlan_interference_mitigation_enable[list[vdev_index]]; + } + + if (wlan_interference_mitigation_enable) + ucfg_config_dcs_event_data(mac_ctx->psoc, mac_id, true); + + if (rsp->resp_type == WMI_HOST_VDEV_START_RESP_EVENT) { + ucfg_config_dcs_enable(mac_ctx->psoc, mac_id, + WLAN_HOST_DCS_WLANIM); + ucfg_wlan_dcs_cmd(mac_ctx->psoc, mac_id, true); + } +} +#else +static void wma_dcs_wlan_interference_mitigation_enable( + struct mac_context *mac_ctx, + uint32_t mac_id, + struct vdev_start_response *rsp) +{ +} + + +static void wma_dcs_clear_vdev_starting(struct mac_context *mac_ctx, + uint32_t vdev_id) +{ +} +#endif + +/* + * wma_get_ratemask_type() - convert user input ratemask type to FW type + * @type: User input ratemask type maintained in HDD + * @fwtype: Value return arg for fw ratemask type value + * + * Return: FW configurable ratemask type + */ +static QDF_STATUS wma_get_ratemask_type(enum wlan_mlme_ratemask_type type, + uint8_t *fwtype) +{ + switch (type) { + case WLAN_MLME_RATEMASK_TYPE_CCK: + *fwtype = WMI_RATEMASK_TYPE_CCK; + break; + case WLAN_MLME_RATEMASK_TYPE_HT: + *fwtype = WMI_RATEMASK_TYPE_HT; + break; + case WLAN_MLME_RATEMASK_TYPE_VHT: + *fwtype = WMI_RATEMASK_TYPE_VHT; + break; + case WLAN_MLME_RATEMASK_TYPE_HE: + *fwtype = WMI_RATEMASK_TYPE_HE; + break; + default: + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_vdev_start_resp_handler(struct vdev_mlme_obj *vdev_mlme, + struct vdev_start_response *rsp) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface; + target_resource_config *wlan_res_cfg; + struct wlan_objmgr_psoc *psoc; + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + enum vdev_assoc_type assoc_type = VDEV_ASSOC; + struct vdev_mlme_obj *mlme_obj; + struct wlan_mlme_psoc_ext_obj *mlme_psoc_obj; + const struct wlan_mlme_ratemask *ratemask_cfg; + struct config_ratemask_params rparams = {0}; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_FAILURE; + + psoc = wma->psoc; + if (!psoc) { + wma_err("psoc is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_psoc_obj = mlme_get_psoc_ext_obj(psoc); + if (!mlme_psoc_obj) { + wma_err("Failed to get mlme_psoc"); + return QDF_STATUS_E_FAILURE; + } + + ratemask_cfg = &mlme_psoc_obj->cfg.ratemask_cfg; + + if (!mac_ctx) { + wma_err("Failed to get mac_ctx"); + return QDF_STATUS_E_FAILURE; + } + + wlan_res_cfg = lmac_get_tgt_res_cfg(psoc); + if (!wlan_res_cfg) { + wma_err("Wlan resource config is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (rsp->vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev id received from firmware"); + return QDF_STATUS_E_FAILURE; + } + + if (wma_is_vdev_in_ap_mode(wma, rsp->vdev_id)) + tgt_dfs_radar_enable(wma->pdev, 0, 0, true); + + iface = &wma->interfaces[rsp->vdev_id]; + if (!iface->vdev) { + wma_err("Invalid vdev"); + return QDF_STATUS_E_FAILURE; + } + + if (rsp->status == QDF_STATUS_SUCCESS) { + wma->interfaces[rsp->vdev_id].tx_streams = + rsp->cfgd_tx_streams; + + if (wlan_res_cfg->use_pdev_id) { + if (rsp->mac_id == OL_TXRX_PDEV_ID) { + wma_err("soc level id received for mac id"); + return -QDF_STATUS_E_INVAL; + } + wma->interfaces[rsp->vdev_id].mac_id = + WMA_PDEV_TO_MAC_MAP(rsp->mac_id); + } else { + wma->interfaces[rsp->vdev_id].mac_id = + rsp->mac_id; + } + + wma_debug("vdev:%d tx ss=%d rx ss=%d chain mask=%d mac=%d", + rsp->vdev_id, + rsp->cfgd_tx_streams, + rsp->cfgd_rx_streams, + rsp->chain_mask, + wma->interfaces[rsp->vdev_id].mac_id); + + /* Fill bss_chan after vdev start */ + qdf_mem_copy(iface->vdev->vdev_mlme.bss_chan, + iface->vdev->vdev_mlme.des_chan, + sizeof(struct wlan_channel)); + } + + if (wma_is_vdev_in_ap_mode(wma, rsp->vdev_id)) { + wma_dcs_clear_vdev_starting(mac_ctx, rsp->vdev_id); + wma_dcs_wlan_interference_mitigation_enable(mac_ctx, + iface->mac_id, rsp); + } + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE + if (rsp->status == QDF_STATUS_SUCCESS + && mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, rsp->vdev_id, true); +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + + if (wma_get_hidden_ssid_restart_in_progress(iface) && + wma_is_vdev_in_ap_mode(wma, rsp->vdev_id)) { + wma_handle_hidden_ssid_restart(wma, iface); + return QDF_STATUS_SUCCESS; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!mlme_obj) + return QDF_STATUS_E_INVAL; + + mlme_obj->mgmt.generic.tx_pwrlimit = rsp->max_allowed_tx_power; + wma_debug("Max allowed tx power: %d", rsp->max_allowed_tx_power); + + if (iface->type == WMI_VDEV_TYPE_STA) + assoc_type = mlme_get_assoc_type(vdev_mlme->vdev); + + if (mlme_is_chan_switch_in_progress(iface->vdev) || + iface->type == WMI_VDEV_TYPE_MONITOR || + (iface->type == WMI_VDEV_TYPE_STA && + (assoc_type == VDEV_ASSOC || assoc_type == VDEV_REASSOC))) { + status = wma_handle_channel_switch_resp(wma, + rsp); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + } else if (iface->type == WMI_VDEV_TYPE_OCB) { + mlme_obj->proto.sta.assoc_id = iface->aid; + if (vdev_mgr_up_send(mlme_obj) != QDF_STATUS_SUCCESS) { + wma_err("failed to send vdev up"); + return QDF_STATUS_E_FAILURE; + } + ucfg_ocb_config_channel(wma->pdev); + } else { + struct qdf_mac_addr bss_peer; + + status = + wlan_vdev_get_bss_peer_mac(iface->vdev, &bss_peer); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get bssid"); + return QDF_STATUS_E_INVAL; + } + qdf_mem_copy(mlme_obj->mgmt.generic.bssid, bss_peer.bytes, + QDF_MAC_ADDR_SIZE); + wma_vdev_start_rsp(wma, vdev_mlme->vdev, rsp); + } + if (iface->type == WMI_VDEV_TYPE_AP && wma_is_vdev_up(rsp->vdev_id)) + wma_set_sap_keepalive(wma, rsp->vdev_id); + + /* Send ratemask to firmware */ + if ((ratemask_cfg->type > WLAN_MLME_RATEMASK_TYPE_NO_MASK) && + (ratemask_cfg->type < WLAN_MLME_RATEMASK_TYPE_MAX)) { + struct wmi_unified *wmi_handle = wma->wmi_handle; + + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + rparams.vdev_id = rsp->vdev_id; + status = wma_get_ratemask_type(ratemask_cfg->type, + &rparams.type); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err(FL("unable to map ratemask")); + /* don't fail, default rates will still work */ + return QDF_STATUS_SUCCESS; + } + + rparams.lower32 = ratemask_cfg->lower32; + rparams.higher32 = ratemask_cfg->higher32; + rparams.lower32_2 = ratemask_cfg->lower32_2; + rparams.higher32_2 = ratemask_cfg->higher32_2; + + status = wmi_unified_vdev_config_ratemask_cmd_send(wmi_handle, + &rparams); + /* Only log failure. Do not abort */ + if (QDF_IS_STATUS_ERROR(status)) + wma_err(FL("failed to send ratemask")); + } + + return QDF_STATUS_SUCCESS; +} + +bool wma_is_vdev_valid(uint32_t vdev_id) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return false; + + /* No of interface are allocated based on max_bssid value */ + if (vdev_id >= wma_handle->max_bssid) { + wma_debug("vdev_id: %d is invalid, max_bssid: %d", + vdev_id, wma_handle->max_bssid); + return false; + } + + return wma_handle->interfaces[vdev_id].vdev_active; +} + +/** + * wma_vdev_set_param() - set per vdev params in fw + * @wmi_handle: wmi handle + * @if_id: vdev id + * @param_id: parameter id + * @param_value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +wma_vdev_set_param(wmi_unified_t wmi_handle, uint32_t if_id, + uint32_t param_id, uint32_t param_value) +{ + struct vdev_set_params param = {0}; + + if (!wma_is_vdev_valid(if_id)) { + wma_err("vdev_id: %d is not active reject the req: param id %d val %d", + if_id, param_id, param_value); + return QDF_STATUS_E_INVAL; + } + + param.vdev_id = if_id; + param.param_id = param_id; + param.param_value = param_value; + + return wmi_unified_vdev_set_param_send(wmi_handle, ¶m); +} + +/** + * wma_set_peer_param() - set peer parameter in fw + * @wma_ctx: wma handle + * @peer_addr: peer mac address + * @param_id: parameter id + * @param_value: parameter value + * @vdev_id: vdev id + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_set_peer_param(void *wma_ctx, uint8_t *peer_addr, + uint32_t param_id, uint32_t param_value, + uint32_t vdev_id) +{ + tp_wma_handle wma_handle = (tp_wma_handle) wma_ctx; + struct peer_set_params param = {0}; + QDF_STATUS status; + + param.vdev_id = vdev_id; + param.param_value = param_value; + param.param_id = param_id; + + status = wmi_set_peer_param_send(wma_handle->wmi_handle, + peer_addr, + ¶m); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("vdev_id: %d peer set failed, id %d, val %d", + vdev_id, param_id, param_value); + return status; +} + +/** + * wma_peer_unmap_conf_send - send peer unmap conf cmnd to fw + * @wma: wma handle + * @msg: peer unmap conf params + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_peer_unmap_conf_send(tp_wma_handle wma, + struct send_peer_unmap_conf_params *msg) +{ + QDF_STATUS qdf_status; + + if (!msg) { + wma_err("null input params"); + return QDF_STATUS_E_INVAL; + } + + qdf_status = wmi_unified_peer_unmap_conf_send( + wma->wmi_handle, + msg->vdev_id, + msg->peer_id_cnt, + msg->peer_id_list); + + if (qdf_status != QDF_STATUS_SUCCESS) + wma_err("peer_unmap_conf_send failed %d", qdf_status); + + qdf_mem_free(msg->peer_id_list); + msg->peer_id_list = NULL; + + return qdf_status; +} + +/** + * wma_peer_unmap_conf_cb - send peer unmap conf cmnd to fw + * @vdev_id: vdev id + * @peer_id_cnt: no of peer id + * @peer_id_list: list of peer ids + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_peer_unmap_conf_cb(uint8_t vdev_id, + uint32_t peer_id_cnt, + uint16_t *peer_id_list) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS qdf_status; + + if (!wma) + return QDF_STATUS_E_INVAL; + + wma_debug("peer_id_cnt: %d", peer_id_cnt); + qdf_status = wmi_unified_peer_unmap_conf_send( + wma->wmi_handle, + vdev_id, peer_id_cnt, + peer_id_list); + + if (qdf_status == QDF_STATUS_E_BUSY) { + QDF_STATUS retcode; + struct scheduler_msg msg = {0}; + struct send_peer_unmap_conf_params *peer_unmap_conf_req; + void *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + wma_debug("post unmap_conf cmd to MC thread"); + + if (!mac_ctx) + return QDF_STATUS_E_FAILURE; + + peer_unmap_conf_req = qdf_mem_malloc(sizeof( + struct send_peer_unmap_conf_params)); + + if (!peer_unmap_conf_req) + return QDF_STATUS_E_NOMEM; + + peer_unmap_conf_req->vdev_id = vdev_id; + peer_unmap_conf_req->peer_id_cnt = peer_id_cnt; + peer_unmap_conf_req->peer_id_list = qdf_mem_malloc( + sizeof(uint16_t) * peer_id_cnt); + if (!peer_unmap_conf_req->peer_id_list) { + qdf_mem_free(peer_unmap_conf_req); + peer_unmap_conf_req = NULL; + return QDF_STATUS_E_NOMEM; + } + qdf_mem_copy(peer_unmap_conf_req->peer_id_list, + peer_id_list, sizeof(uint16_t) * peer_id_cnt); + + msg.type = WMA_SEND_PEER_UNMAP_CONF; + msg.reserved = 0; + msg.bodyptr = peer_unmap_conf_req; + msg.bodyval = 0; + + retcode = wma_post_ctrl_msg(mac_ctx, &msg); + if (retcode != QDF_STATUS_SUCCESS) { + wma_err("wma_post_ctrl_msg failed"); + qdf_mem_free(peer_unmap_conf_req->peer_id_list); + qdf_mem_free(peer_unmap_conf_req); + return QDF_STATUS_E_FAILURE; + } + } + + return qdf_status; +} + +bool wma_objmgr_peer_exist(tp_wma_handle wma, + uint8_t *peer_addr, uint8_t *peer_vdev_id) +{ + struct wlan_objmgr_peer *peer; + + if (!peer_addr || + qdf_is_macaddr_zero((struct qdf_mac_addr *)peer_addr)) + return false; + + peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_addr, + WLAN_LEGACY_WMA_ID); + if (!peer) + return false; + + if (peer_vdev_id) + *peer_vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + return true; +} + +#ifdef WLAN_FEATURE_11BE_MLO_ADV_FEATURE +void wma_peer_tbl_trans_add_entry(struct wlan_objmgr_peer *peer, bool is_create, + struct cdp_peer_setup_info *peer_info) +{ + QDF_STATUS status; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_psoc *psoc; + struct wlan_peer_tbl_trans_entry *peer_trans_entry; + uint8_t *peer_mac, *peer_mld; + + vdev = wlan_peer_get_vdev(peer); + if (!vdev) + return; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return; + + peer_trans_entry = qdf_mem_malloc(sizeof(*peer_trans_entry)); + if (!peer_trans_entry) + return; + + peer_trans_entry->ts = qdf_get_log_timestamp(); + peer_trans_entry->vdev_id = wlan_vdev_get_id(vdev); + peer_trans_entry->opmode = wlan_vdev_mlme_get_opmode(vdev); + + peer_mac = wlan_peer_get_macaddr(peer); + peer_mld = wlan_peer_mlme_get_mldaddr(peer); + qdf_ether_addr_copy(&peer_trans_entry->peer_addr.bytes[0], peer_mac); + if (peer_mld) { + qdf_ether_addr_copy(&peer_trans_entry->peer_mld_addr.bytes[0], + peer_mld); + } + + peer_trans_entry->is_mlo = wlan_vdev_mlme_is_mlo_vdev(vdev); + peer_trans_entry->is_mlo_link = wlan_vdev_mlme_is_mlo_link_vdev(vdev); + + if (wlan_cm_is_vdev_roam_sync_inprogress(vdev)) { + peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_ROAM; + peer_trans_entry->auth_status = + wlan_cm_check_mlo_roam_auth_status(vdev); + peer_trans_entry->num_roam_links = mlo_mgr_num_roam_links(vdev); + } else if (wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev)) { + peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_LINK_SWITCH; + } else if (is_create) { + peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_CONNECT; + } else { + peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_DISCONNECT; + } + + if (is_create) { + peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_CREATE; + peer_trans_entry->is_primary = peer_info->is_primary_link; + peer_trans_entry->is_first_link = peer_info->is_first_link; + } else { + peer_trans_entry->peer_flags |= WLAN_PEER_TBL_TRANS_DESTROY; + } + + status = wlan_mlme_psoc_peer_tbl_trans_add_entry(psoc, + peer_trans_entry); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(peer_trans_entry); +} +#endif + +/** + * wma_remove_peer() - remove peer information from host driver and fw + * @wma: wma handle + * @mac_addr: peer mac address, to be removed + * @vdev_id: vdev id + * @no_fw_peer_delete: If true dont send peer delete to firmware + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_remove_peer(tp_wma_handle wma, uint8_t *mac_addr, + uint8_t vdev_id, bool no_fw_peer_delete) +{ +#define PEER_ALL_TID_BITMASK 0xffffffff + uint32_t peer_tid_bitmap = PEER_ALL_TID_BITMASK; + uint8_t peer_addr[QDF_MAC_ADDR_SIZE] = {0}; + struct peer_flush_params param = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + uint32_t bitmap = 1 << CDP_PEER_DELETE_NO_SPECIAL; + bool peer_unmap_conf_support_enabled; + uint8_t peer_vdev_id; + struct peer_delete_cmd_params del_param = {0}; + struct wma_txrx_node *iface; + struct wlan_objmgr_peer *peer; + + if (vdev_id >= WLAN_MAX_VDEVS) { + wma_err("Invalid vdev_id %d", vdev_id); + QDF_BUG(0); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(peer_addr, mac_addr, QDF_MAC_ADDR_SIZE); + + iface = &wma->interfaces[vdev_id]; + if (!iface->peer_count) { + wma_err("Can't remove peer with peer_addr "QDF_MAC_ADDR_FMT" vdevid %d peer_count %d", + QDF_MAC_ADDR_REF(peer_addr), vdev_id, + iface->peer_count); + QDF_ASSERT(0); + return QDF_STATUS_E_INVAL; + } + + if (!soc) { + QDF_BUG(0); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_addr, + WLAN_LEGACY_WMA_ID); + if (!peer) { + wma_err("peer doesn't exist peer_addr "QDF_MAC_ADDR_FMT" vdevid %d peer_count %d", + QDF_MAC_ADDR_REF(peer_addr), vdev_id, + iface->peer_count); + return QDF_STATUS_E_INVAL; + } + + peer_vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + if (peer_vdev_id != vdev_id) { + wma_err("peer "QDF_MAC_ADDR_FMT" is on vdev id %d but delete req on vdevid %d peer_count %d", + QDF_MAC_ADDR_REF(peer_addr), peer_vdev_id, vdev_id, + iface->peer_count); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + return QDF_STATUS_E_INVAL; + } + + wma_peer_tbl_trans_add_entry(peer, false, NULL); + peer_unmap_conf_support_enabled = + cdp_cfg_get_peer_unmap_conf_support(soc); + + cdp_peer_teardown(soc, vdev_id, peer_addr); + + if (no_fw_peer_delete) + goto peer_detach; + + /* Flush all TIDs except MGMT TID for this peer in Target */ + peer_tid_bitmap &= ~(0x1 << WMI_MGMT_TID); + param.peer_tid_bitmap = peer_tid_bitmap; + param.vdev_id = vdev_id; + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_delete_no_peer_flush_tids_cmd)) + wmi_unified_peer_flush_tids_send(wma->wmi_handle, peer_addr, + ¶m); + + /* peer->ref_cnt is not visible in WMA */ + wlan_roam_debug_log(vdev_id, DEBUG_PEER_DELETE_SEND, + DEBUG_INVALID_PEER_ID, peer_addr, NULL, + 0, 0); + + del_param.vdev_id = vdev_id; + del_param.is_mlo_link_switch = + wlan_vdev_mlme_is_mlo_link_switch_in_progress(iface->vdev); + qdf_status = wmi_unified_peer_delete_send(wma->wmi_handle, peer_addr, + &del_param); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Peer delete could not be sent to firmware %d", + qdf_status); + /* Clear default bit and set to NOT_START_UNMAP */ + bitmap = 1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER; + qdf_status = QDF_STATUS_E_FAILURE; + } + +peer_detach: + wma_debug("vdevid %d is detaching with peer_addr "QDF_MAC_ADDR_FMT" peer_count %d", + vdev_id, QDF_MAC_ADDR_REF(peer_addr), iface->peer_count); + if (no_fw_peer_delete && + is_cdp_peer_detach_force_delete_supported(soc)) { + if (!peer_unmap_conf_support_enabled) { + wma_debug("LFR3: trigger force delete for peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + cdp_peer_detach_force_delete(soc, vdev_id, peer_addr); + } else { + cdp_peer_delete_sync(soc, vdev_id, peer_addr, + wma_peer_unmap_conf_cb, + bitmap); + } + } else { + if (no_fw_peer_delete) + wma_debug("LFR3: Delete the peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + + if (peer_unmap_conf_support_enabled) + cdp_peer_delete_sync(soc, vdev_id, peer_addr, + wma_peer_unmap_conf_cb, + bitmap); + else + cdp_peer_delete(soc, vdev_id, peer_addr, bitmap); + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + wlan_release_peer_key_wakelock(wma->pdev, peer_addr); + wma_remove_objmgr_peer(wma, iface->vdev, peer_addr); + + iface->peer_count--; +#undef PEER_ALL_TID_BITMASK + + return qdf_status; +} + +/** + * wma_get_obj_mgr_peer_type() - Determine the type of peer(eg. STA/AP) + * @wma: wma handle + * @vdev_id: vdev id + * @peer_addr: peer mac address + * @wma_peer_type: wma peer type + * + * Return: Peer type + */ +static int wma_get_obj_mgr_peer_type(tp_wma_handle wma, uint8_t vdev_id, + uint8_t *peer_addr, uint32_t wma_peer_type) + +{ + uint32_t obj_peer_type = 0; + struct wlan_objmgr_vdev *vdev; + uint8_t *addr; + uint8_t *mld_addr; + + vdev = wma->interfaces[vdev_id].vdev; + if (!vdev) { + wma_err("Couldn't find vdev for VDEV_%d", vdev_id); + return obj_peer_type; + } + addr = wlan_vdev_mlme_get_macaddr(vdev); + mld_addr = wlan_vdev_mlme_get_mldaddr(vdev); + + if (wma_peer_type == WMI_PEER_TYPE_TDLS) + return WLAN_PEER_TDLS; + + if (wma_peer_type == WMI_PEER_TYPE_PASN) + return WLAN_PEER_RTT_PASN; + + if (!qdf_mem_cmp(addr, peer_addr, QDF_MAC_ADDR_SIZE) || + !qdf_mem_cmp(mld_addr, peer_addr, QDF_MAC_ADDR_SIZE)) { + obj_peer_type = WLAN_PEER_SELF; + } else if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA) { + if (wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) + obj_peer_type = WLAN_PEER_P2P_GO; + else + obj_peer_type = WLAN_PEER_AP; + } else if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_AP) { + obj_peer_type = WLAN_PEER_STA; + } else if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_IBSS) { + obj_peer_type = WLAN_PEER_IBSS; + } else if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_NDI) { + obj_peer_type = WLAN_PEER_NDP; + } else { + wma_err("Couldn't find peertype for type %d and sub type %d", + wma->interfaces[vdev_id].type, + wma->interfaces[vdev_id].sub_type); + } + + return obj_peer_type; + +} + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +wma_create_peer_validate_mld_address(tp_wma_handle wma, + uint8_t *peer_mld_addr, + struct wlan_objmgr_vdev *vdev) +{ + uint8_t peer_vdev_id, vdev_id; + struct wlan_objmgr_vdev *dup_vdev; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_psoc *psoc = wma->psoc; + + vdev_id = wlan_vdev_get_id(vdev); + /* Check if the @peer_mld_addr matches any other + * peer's link address. + * We may find a match if one of the peers added + * has same MLD and link, in such case check if + * both are in same ML dev context. + */ + if (wma_objmgr_peer_exist(wma, peer_mld_addr, &peer_vdev_id)) { + if (peer_vdev_id != vdev_id) { + dup_vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, peer_vdev_id, + WLAN_LEGACY_WMA_ID); + if (!dup_vdev) + return QDF_STATUS_E_INVAL; + + /* If ML dev context is NULL then the matching + * peer exist on non ML VDEV, so reject the peer. + */ + if (!dup_vdev->mlo_dev_ctx) { + wlan_objmgr_vdev_release_ref( + dup_vdev, WLAN_LEGACY_WMA_ID); + return QDF_STATUS_E_ALREADY; + } else if (dup_vdev->mlo_dev_ctx != vdev->mlo_dev_ctx) { + wma_debug("Peer " QDF_MAC_ADDR_FMT " already exists on vdev %d, current vdev %d", + QDF_MAC_ADDR_REF(peer_mld_addr), + peer_vdev_id, vdev_id); + wlan_objmgr_vdev_release_ref( + dup_vdev, WLAN_LEGACY_WMA_ID); + status = QDF_STATUS_E_ALREADY; + } else { + wlan_objmgr_vdev_release_ref( + dup_vdev, WLAN_LEGACY_WMA_ID); + wma_debug("Allow ML peer on same ML dev context"); + status = QDF_STATUS_SUCCESS; + } + } else { + wma_debug("ML Peer exists on same VDEV %d", vdev_id); + status = QDF_STATUS_E_ALREADY; + } + } else if (mlo_mgr_ml_peer_exist_on_diff_ml_ctx(peer_mld_addr, + &vdev_id)) { + /* Reject if MLD exists on different ML dev context, + */ + wma_debug("ML Peer " QDF_MAC_ADDR_FMT " already exists on different ML dev context", + QDF_MAC_ADDR_REF(peer_mld_addr)); + status = QDF_STATUS_E_ALREADY; + } + + return status; +} +#else +static QDF_STATUS +wma_create_peer_validate_mld_address(tp_wma_handle wma, + uint8_t *peer_mld_addr, + struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +struct wlan_objmgr_peer *wma_create_objmgr_peer(tp_wma_handle wma, + uint8_t vdev_id, + uint8_t *peer_addr, + uint32_t wma_peer_type, + uint8_t *peer_mld_addr) +{ + QDF_STATUS status; + uint8_t peer_vdev_id; + uint32_t obj_peer_type; + struct wlan_objmgr_vdev *obj_vdev; + struct wlan_objmgr_peer *obj_peer = NULL; + struct wlan_objmgr_psoc *psoc = wma->psoc; + + obj_vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + + if (!obj_vdev) { + wma_err("Invalid obj vdev. Unable to create peer"); + return NULL; + } + + /* + * Check if peer with same MAC exist on any Vdev, If so avoid + * adding this peer. + */ + if (wma_objmgr_peer_exist(wma, peer_addr, &peer_vdev_id)) { + wma_debug("Peer " QDF_MAC_ADDR_FMT " already exists on vdev %d, current vdev %d", + QDF_MAC_ADDR_REF(peer_addr), peer_vdev_id, vdev_id); + goto vdev_ref; + } + + /* Reject if same MAC exists on different ML dev context */ + if (mlo_mgr_ml_peer_exist_on_diff_ml_ctx(peer_addr, + &vdev_id)) { + wma_debug("Peer " QDF_MAC_ADDR_FMT " already exists on different ML dev context", + QDF_MAC_ADDR_REF(peer_addr)); + goto vdev_ref; + } + + status = wma_create_peer_validate_mld_address(wma, peer_mld_addr, + obj_vdev); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("MLD " QDF_MAC_ADDR_FMT " matches with peer on different MLD context", + QDF_MAC_ADDR_REF(peer_mld_addr)); + goto vdev_ref; + } + + obj_peer_type = wma_get_obj_mgr_peer_type(wma, vdev_id, peer_addr, + wma_peer_type); + if (!obj_peer_type) { + wma_err("Invalid obj peer type. Unable to create peer %d", + obj_peer_type); + goto vdev_ref; + } + + /* Create obj_mgr peer */ + obj_peer = wlan_objmgr_peer_obj_create(obj_vdev, obj_peer_type, + peer_addr); + +vdev_ref: + wlan_objmgr_vdev_release_ref(obj_vdev, WLAN_LEGACY_WMA_ID); + + return obj_peer; + +} + +/** + * wma_increment_peer_count() - Increment the vdev peer + * count + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +static void +wma_increment_peer_count(tp_wma_handle wma, uint8_t vdev_id) +{ + wma->interfaces[vdev_id].peer_count++; +} + +/** + * wma_update_mlo_peer_create() - update mlo parameter for peer creation + * @param: peer create param + * @mlo_enable: mlo enable or not + * + * Return: Void + */ +#ifdef WLAN_FEATURE_11BE_MLO +static void wma_update_mlo_peer_create(struct peer_create_params *param, + bool mlo_enable) +{ + param->mlo_enabled = mlo_enable; +} +#else +static void wma_update_mlo_peer_create(struct peer_create_params *param, + bool mlo_enable) +{ +} +#endif + +/** + * wma_add_peer() - send peer create command to fw + * @wma: wma handle + * @peer_addr: peer mac addr + * @peer_type: peer type + * @vdev_id: vdev id + * @peer_mld_addr: peer mld addr + * @is_assoc_peer: is assoc peer or not + * + * Return: QDF status + */ +static +QDF_STATUS wma_add_peer(tp_wma_handle wma, + uint8_t peer_addr[QDF_MAC_ADDR_SIZE], + uint32_t peer_type, uint8_t vdev_id, + uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE], + bool is_assoc_peer) +{ + struct peer_create_params param = {0}; + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_objmgr_psoc *psoc = wma->psoc; + target_resource_config *wlan_res_cfg; + struct wlan_objmgr_peer *obj_peer = NULL; + QDF_STATUS status; + + if (!psoc) { + wma_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + wlan_res_cfg = lmac_get_tgt_res_cfg(psoc); + if (!wlan_res_cfg) { + wma_err("psoc target res cfg is null"); + return QDF_STATUS_E_INVAL; + } + + if (wma->interfaces[vdev_id].peer_count >= + wlan_res_cfg->num_peers) { + wma_err("the peer count exceeds the limit %d", + wma->interfaces[vdev_id].peer_count); + return QDF_STATUS_E_FAILURE; + } + + if (!dp_soc) + return QDF_STATUS_E_FAILURE; + + if (qdf_is_macaddr_group((struct qdf_mac_addr *)peer_addr) || + qdf_is_macaddr_zero((struct qdf_mac_addr *)peer_addr)) { + wma_err("Invalid peer address received reject it"); + return QDF_STATUS_E_FAILURE; + } + + obj_peer = wma_create_objmgr_peer(wma, vdev_id, peer_addr, peer_type, + peer_mld_addr); + if (!obj_peer) + return QDF_STATUS_E_FAILURE; + + /* The peer object should be created before sending the WMI peer + * create command to firmware. This is to prevent a race condition + * where the HTT peer map event is received before the peer object + * is created in the data path + */ + if (peer_mld_addr && + !qdf_is_macaddr_zero((struct qdf_mac_addr *)peer_mld_addr)) { + wlan_peer_mlme_flag_ext_set(obj_peer, WLAN_PEER_FEXT_MLO); + wma_debug("peer " QDF_MAC_ADDR_FMT "is_assoc_peer%d mld mac " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr), is_assoc_peer, + QDF_MAC_ADDR_REF(peer_mld_addr)); + wlan_peer_mlme_set_mldaddr(obj_peer, peer_mld_addr); + wlan_peer_mlme_set_assoc_peer(obj_peer, is_assoc_peer); + wma_update_mlo_peer_create(¶m, true); + } + status = cdp_peer_create(dp_soc, vdev_id, peer_addr); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Unable to attach peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + wlan_objmgr_peer_obj_delete(obj_peer); + return QDF_STATUS_E_FAILURE; + } + + if (peer_type == WMI_PEER_TYPE_TDLS) + cdp_peer_set_peer_as_tdls(dp_soc, vdev_id, peer_addr, true); + + if (wlan_cm_is_roam_sync_in_progress(wma->psoc, vdev_id) || + MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id)) { + wma_debug("LFR3: Created peer "QDF_MAC_ADDR_FMT" vdev_id %d, peer_count %d", + QDF_MAC_ADDR_REF(peer_addr), vdev_id, + wma->interfaces[vdev_id].peer_count + 1); + return QDF_STATUS_SUCCESS; + } + param.peer_addr = peer_addr; + param.peer_type = peer_type; + param.vdev_id = vdev_id; + if (wmi_unified_peer_create_send(wma->wmi_handle, + ¶m) != QDF_STATUS_SUCCESS) { + wma_err("Unable to create peer in Target"); + if (cdp_cfg_get_peer_unmap_conf_support(dp_soc)) + cdp_peer_delete_sync( + dp_soc, vdev_id, peer_addr, + wma_peer_unmap_conf_cb, + 1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER); + else + cdp_peer_delete( + dp_soc, vdev_id, peer_addr, + 1 << CDP_PEER_DO_NOT_START_UNMAP_TIMER); + wlan_objmgr_peer_obj_delete(obj_peer); + + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Created peer peer_addr "QDF_MAC_ADDR_FMT" vdev_id %d, peer_count - %d", + QDF_MAC_ADDR_REF(peer_addr), vdev_id, + wma->interfaces[vdev_id].peer_count + 1); + + wlan_roam_debug_log(vdev_id, DEBUG_PEER_CREATE_SEND, + DEBUG_INVALID_PEER_ID, peer_addr, NULL, 0, 0); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static void wma_peer_setup_fill_info(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + struct cdp_peer_setup_info *peer_info) +{ + uint8_t vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + + peer_info->mld_peer_mac = wlan_peer_mlme_get_mldaddr(peer); + if (MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(psoc, vdev_id) && + wlan_vdev_mlme_get_is_mlo_link(psoc, vdev_id)) { + peer_info->is_first_link = true; + peer_info->is_primary_link = false; + } else if (wlan_cm_is_roam_sync_in_progress(psoc, vdev_id) && + wlan_vdev_mlme_get_is_mlo_vdev(psoc, vdev_id)) { + if (mlo_get_single_link_ml_roaming(psoc, vdev_id)) { + peer_info->is_first_link = true; + peer_info->is_primary_link = true; + } else { + peer_info->is_first_link = false; + peer_info->is_primary_link = true; + } + } else { + peer_info->is_first_link = wlan_peer_mlme_is_assoc_peer(peer); + peer_info->is_primary_link = peer_info->is_first_link; + } +} + +/** + * wma_cdp_peer_setup() - provide mlo information to cdp_peer_setup + * @dp_soc: dp soc + * @vdev_id: vdev id + * @peer: Object manager peer pointer + * @peer_info: Peer setup info + * + * Return: VOID + */ +static void wma_cdp_peer_setup(ol_txrx_soc_handle dp_soc, + uint8_t vdev_id, struct wlan_objmgr_peer *peer, + struct cdp_peer_setup_info *peer_info) +{ + uint8_t *mld_mac, *peer_addr; + + peer_addr = wlan_peer_get_macaddr(peer); + mld_mac = peer_info->mld_peer_mac; + + if (!mld_mac || qdf_is_macaddr_zero((struct qdf_mac_addr *)mld_mac)) { + cdp_peer_setup(dp_soc, vdev_id, peer_addr, NULL); + return; + } + + cdp_peer_setup(dp_soc, vdev_id, peer_addr, peer_info); +} +#else +static inline void +wma_peer_setup_fill_info(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_peer *peer, + struct cdp_peer_setup_info *peer_info) +{ + peer_info->mld_peer_mac = NULL; + peer_info->is_first_link = false; + peer_info->is_primary_link = false; +} + +static void wma_cdp_peer_setup(ol_txrx_soc_handle dp_soc, + uint8_t vdev_id, struct wlan_objmgr_peer *peer, + struct cdp_peer_setup_info *peer_info) +{ + uint8_t *peer_addr; + + peer_addr = wlan_peer_get_macaddr(peer); + cdp_peer_setup(dp_soc, vdev_id, peer_addr, NULL); +} +#endif + +QDF_STATUS wma_create_peer(tp_wma_handle wma, + uint8_t peer_addr[QDF_MAC_ADDR_SIZE], + uint32_t peer_type, uint8_t vdev_id, + uint8_t peer_mld_addr[QDF_MAC_ADDR_SIZE], + bool is_assoc_peer) +{ + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + struct wlan_objmgr_peer *obj_peer; + struct cdp_peer_setup_info peer_info = {0}; + + if (!dp_soc) + return QDF_STATUS_E_FAILURE; + status = wma_add_peer(wma, peer_addr, peer_type, vdev_id, + peer_mld_addr, is_assoc_peer); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + obj_peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_addr, + WLAN_LEGACY_WMA_ID); + if (!obj_peer) + return QDF_STATUS_E_FAILURE; + + wma_increment_peer_count(wma, vdev_id); + + wma_peer_setup_fill_info(wma->psoc, obj_peer, &peer_info); + wma_peer_tbl_trans_add_entry(obj_peer, true, &peer_info); + wma_cdp_peer_setup(dp_soc, vdev_id, obj_peer, &peer_info); + wlan_objmgr_peer_release_ref(obj_peer, WLAN_LEGACY_WMA_ID); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_create_sta_mode_bss_peer() - send peer create command to fw + * and start peer create response timer + * @wma: wma handle + * @peer_addr: peer mac address + * @peer_type: peer type + * @vdev_id: vdev id + * @mld_addr: peer mld address + * @is_assoc_peer: is assoc peer or not + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_create_sta_mode_bss_peer(tp_wma_handle wma, + uint8_t peer_addr[QDF_MAC_ADDR_SIZE], + uint32_t peer_type, uint8_t vdev_id, + uint8_t mld_addr[QDF_MAC_ADDR_SIZE], + bool is_assoc_peer) +{ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct wma_target_req *msg = NULL; + struct peer_create_rsp_params *peer_create_rsp = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + bool is_tgt_peer_conf_supported = false; + + if (!mac) { + wma_err("vdev%d: Mac context is null", vdev_id); + return status; + } + + /* + * If fw doesn't advertise peer create confirm event support, + * use the legacy peer create API + */ + is_tgt_peer_conf_supported = + wlan_psoc_nif_fw_ext_cap_get(wma->psoc, + WLAN_SOC_F_PEER_CREATE_RESP); + if (!is_tgt_peer_conf_supported) { + status = wma_create_peer(wma, peer_addr, peer_type, vdev_id, + mld_addr, is_assoc_peer); + goto end; + } + + peer_create_rsp = qdf_mem_malloc(sizeof(*peer_create_rsp)); + if (!peer_create_rsp) + goto end; + + wma_acquire_wakelock(&wma->wmi_cmd_rsp_wake_lock, + WMA_PEER_CREATE_RESPONSE_TIMEOUT); + + status = wma_add_peer(wma, peer_addr, peer_type, vdev_id, + mld_addr, is_assoc_peer); + if (QDF_IS_STATUS_ERROR(status)) { + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + goto end; + } + + wma_increment_peer_count(wma, vdev_id); + qdf_mem_copy(peer_create_rsp->peer_mac.bytes, peer_addr, + QDF_MAC_ADDR_SIZE); + + msg = wma_fill_hold_req(wma, vdev_id, WMA_PEER_CREATE_REQ, + WMA_PEER_CREATE_RESPONSE, + (void *)peer_create_rsp, + WMA_PEER_CREATE_RESPONSE_TIMEOUT); + if (!msg) { + wma_err("vdev:%d failed to fill peer create req", vdev_id); + wma_remove_peer_req(wma, vdev_id, WMA_PEER_CREATE_RESPONSE, + (struct qdf_mac_addr *)peer_addr); + wma_remove_peer(wma, peer_addr, vdev_id, false); + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + status = QDF_STATUS_E_FAILURE; + goto end; + } + + return status; + +end: + qdf_mem_free(peer_create_rsp); + lim_send_peer_create_resp(mac, vdev_id, status, peer_addr); + + return status; +} + +/** + * wma_remove_bss_peer() - remove BSS peer + * @wma: pointer to WMA handle + * @vdev_id: vdev id on which delete BSS request was received + * @vdev_stop_resp: pointer to Delete BSS response + * @type: request type + * + * This function is called on receiving vdev stop response from FW or + * vdev stop response timeout. In case of NDI, use vdev's self MAC + * for removing the peer. In case of STA/SAP use bssid passed as part of + * delete STA parameter. + * + * Return: 0 on success, ERROR code on failure + */ +static int wma_remove_bss_peer(tp_wma_handle wma, uint32_t vdev_id, + struct del_bss_resp *vdev_stop_resp, + uint8_t type) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t *mac_addr = NULL; + struct wma_target_req *del_req; + int ret_value = 0; + QDF_STATUS qdf_status; + struct qdf_mac_addr bssid; + + if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, vdev_id)) { + mac_addr = cdp_get_vdev_mac_addr(soc, vdev_id); + if (!mac_addr) { + wma_err("mac_addr is NULL for vdev_id = %d", vdev_id); + return -EINVAL; + } + } else { + qdf_status = wlan_vdev_get_bss_peer_mac( + wma->interfaces[vdev_id].vdev, + &bssid); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to get bssid for vdev_id: %d", vdev_id); + return -EINVAL; + } + mac_addr = bssid.bytes; + } + + qdf_status = wma_remove_peer(wma, mac_addr, vdev_id, false); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("wma_remove_peer failed vdev_id:%d", vdev_id); + return -EINVAL; + } + + if (cds_is_driver_recovering()) + return -EINVAL; + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + wma_debug("Wait for the peer delete. vdev_id %d", vdev_id); + del_req = wma_fill_hold_req(wma, vdev_id, + WMA_DELETE_STA_REQ, + type, + vdev_stop_resp, + WMA_DELETE_STA_TIMEOUT); + if (!del_req) { + wma_err("Failed to allocate request. vdev_id %d", vdev_id); + vdev_stop_resp->status = QDF_STATUS_E_NOMEM; + ret_value = -EINVAL; + } + } + + return ret_value; +} + +#ifdef FEATURE_WLAN_APF +/* + * get_fw_active_apf_mode() - convert HDD APF mode to FW configurable APF + * mode + * @mode: APF mode maintained in HDD + * + * Return: FW configurable BP mode + */ +static enum wmi_host_active_apf_mode +get_fw_active_apf_mode(enum active_apf_mode mode) +{ + switch (mode) { + case ACTIVE_APF_DISABLED: + return WMI_HOST_ACTIVE_APF_DISABLED; + case ACTIVE_APF_ENABLED: + return WMI_HOST_ACTIVE_APF_ENABLED; + case ACTIVE_APF_ADAPTIVE: + return WMI_HOST_ACTIVE_APF_ADAPTIVE; + default: + wma_err("Invalid Active APF Mode %d; Using 'disabled'", mode); + return WMI_HOST_ACTIVE_APF_DISABLED; + } +} + +/** + * wma_config_active_apf_mode() - Config active APF mode in FW + * @wma: the WMA handle + * @vdev_id: the Id of the vdev for which the configuration should be applied + * + * Return: QDF status + */ +static QDF_STATUS wma_config_active_apf_mode(t_wma_handle *wma, uint8_t vdev_id) +{ + enum wmi_host_active_apf_mode uc_mode, mcbc_mode; + + uc_mode = get_fw_active_apf_mode(wma->active_uc_apf_mode); + mcbc_mode = get_fw_active_apf_mode(wma->active_mc_bc_apf_mode); + + wma_debug("Configuring Active APF Mode UC:%d MC/BC:%d for vdev %u", + uc_mode, mcbc_mode, vdev_id); + + return wmi_unified_set_active_apf_mode_cmd(wma->wmi_handle, vdev_id, + uc_mode, mcbc_mode); +} +#else /* FEATURE_WLAN_APF */ +static QDF_STATUS wma_config_active_apf_mode(t_wma_handle *wma, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_APF */ + +#ifdef FEATURE_AP_MCC_CH_AVOIDANCE +/** + * wma_check_and_find_mcc_ap() - finds if device is operating AP + * in MCC mode or not + * @wma: wma handle. + * @vdev_id: vdev ID of device for which MCC has to be checked + * + * This function internally calls wma_find_mcc_ap finds if + * device is operating AP in MCC mode or not + * + * Return: none + */ +static void +wma_check_and_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id) +{ + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac_ctx) + return; + + if (mac_ctx->sap.sap_channel_avoidance) + wma_find_mcc_ap(wma, vdev_id, false); +} +#else +static inline void +wma_check_and_find_mcc_ap(tp_wma_handle wma, uint8_t vdev_id) +{} +#endif /* FEATURE_AP_MCC_CH_AVOIDANCE */ + +void wma_send_del_bss_response(tp_wma_handle wma, struct del_bss_resp *resp) +{ + struct wma_txrx_node *iface; + struct beacon_info *bcn; + uint8_t vdev_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!resp) { + wma_err("req is NULL"); + return; + } + + vdev_id = resp->vdev_id; + iface = &wma->interfaces[vdev_id]; + + if (!iface->vdev) { + wma_err("vdev id %d iface->vdev is NULL", vdev_id); + if (resp) + qdf_mem_free(resp); + return; + } + + cdp_fc_vdev_flush(soc, vdev_id); + wma_debug("vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + vdev_id); + cdp_fc_vdev_unpause(soc, vdev_id, OL_TXQ_PAUSE_REASON_VDEV_STOP, 0); + wma_vdev_clear_pause_bit(vdev_id, PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + wma_debug("(type %d subtype %d) BSS is stopped", + iface->type, iface->sub_type); + + bcn = wma->interfaces[vdev_id].beacon; + if (bcn) { + wma_debug("Freeing beacon struct %pK, template memory %pK", + bcn, bcn->buf); + if (bcn->dma_mapped) + qdf_nbuf_unmap_single(wma->qdf_dev, bcn->buf, + QDF_DMA_TO_DEVICE); + qdf_nbuf_free(bcn->buf); + qdf_mem_free(bcn); + wma->interfaces[vdev_id].beacon = NULL; + } + + /* Timeout status means its WMA generated DEL BSS REQ when ADD + * BSS REQ was timed out to stop the VDEV in this case no need + * to send response to UMAC + */ + if (resp->status == QDF_STATUS_FW_MSG_TIMEDOUT) { + qdf_mem_free(resp); + wma_err("DEL BSS from ADD BSS timeout do not send resp to UMAC (vdev id %x)", + vdev_id); + } else { + resp->status = QDF_STATUS_SUCCESS; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_RSP, + (void *)resp, 0); + } + + if (iface->del_staself_req && iface->is_del_sta_deferred) { + iface->is_del_sta_deferred = false; + wma_nofl_alert("scheduling deferred deletion (vdev id %x)", + vdev_id); + wma_vdev_detach(iface->del_staself_req); + } +} + +QDF_STATUS +wma_send_vdev_down(tp_wma_handle wma, struct del_bss_resp *resp) +{ + uint8_t vdev_id; + struct wma_txrx_node *iface = &wma->interfaces[resp->vdev_id]; + uint32_t vdev_stop_type; + QDF_STATUS status; + + if (!resp) { + wma_err("resp is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + vdev_id = resp->vdev_id; + status = mlme_get_vdev_stop_type(iface->vdev, &vdev_stop_type); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get vdev stop type"); + qdf_mem_free(resp); + return status; + } + + if (vdev_stop_type != WMA_DELETE_BSS_HO_FAIL_REQ) { + status = wma_send_vdev_down_to_fw(wma, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send vdev down cmd: vdev %d", vdev_id); + else + wma_check_and_find_mcc_ap(wma, vdev_id); + } + + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_DOWN_COMPLETE, + sizeof(*resp), resp); + return status; +} + +/** + * wma_send_vdev_down_req() - handle vdev down req + * @wma: wma handle + * @resp: pointer to vde del bss response + * + * Return: none + */ + +static void wma_send_vdev_down_req(tp_wma_handle wma, + struct del_bss_resp *resp) +{ + struct wma_txrx_node *iface = &wma->interfaces[resp->vdev_id]; + enum QDF_OPMODE mode; + + mode = wlan_vdev_mlme_get_opmode(iface->vdev); + if (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) { + /* initiate MLME Down req from CM for STA/CLI */ + wlan_cm_bss_peer_delete_rsp(iface->vdev, resp->status); + qdf_mem_free(resp); + return; + } + + wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_MLME_DOWN_REQ, + sizeof(*resp), resp); +} + +#ifdef WLAN_FEATURE_11BE_MLO +void wma_delete_peer_mlo(struct wlan_objmgr_psoc *psoc, uint8_t *macaddr) +{ + struct wlan_objmgr_peer *peer = NULL; + + peer = wlan_objmgr_get_peer_by_mac(psoc, macaddr, WLAN_LEGACY_WMA_ID); + if (peer) { + wlan_mlo_link_peer_delete(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + } +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +static QDF_STATUS +wma_delete_peer_on_vdev_stop(tp_wma_handle wma, uint8_t vdev_id) +{ + uint32_t vdev_stop_type; + struct del_bss_resp *vdev_stop_resp; + struct wma_txrx_node *iface; + QDF_STATUS status; + struct qdf_mac_addr bssid; + + iface = &wma->interfaces[vdev_id]; + status = wlan_vdev_get_bss_peer_mac(iface->vdev, &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get bssid"); + return QDF_STATUS_E_INVAL; + } + + status = mlme_get_vdev_stop_type(iface->vdev, &vdev_stop_type); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get wma req msg type for vdev id %d", + vdev_id); + return QDF_STATUS_E_INVAL; + } + + wma_delete_peer_mlo(wma->psoc, bssid.bytes); + + vdev_stop_resp = qdf_mem_malloc(sizeof(*vdev_stop_resp)); + if (!vdev_stop_resp) + return QDF_STATUS_E_NOMEM; + + if (vdev_stop_type == WMA_DELETE_BSS_HO_FAIL_REQ) { + status = wma_remove_peer(wma, bssid.bytes, + vdev_id, true); + if (QDF_IS_STATUS_ERROR(status)) + goto free_params; + + vdev_stop_resp->status = status; + vdev_stop_resp->vdev_id = vdev_id; + wma_send_vdev_down_req(wma, vdev_stop_resp); + } else if (vdev_stop_type == WMA_DELETE_BSS_REQ || + vdev_stop_type == WMA_SET_LINK_STATE) { + uint8_t type; + + /* CCA is required only for sta interface */ + if (iface->type == WMI_VDEV_TYPE_STA) + wma_get_cca_stats(wma, vdev_id); + if (vdev_stop_type == WMA_DELETE_BSS_REQ) + type = WMA_DELETE_PEER_RSP; + else + type = WMA_SET_LINK_PEER_RSP; + + vdev_stop_resp->vdev_id = vdev_id; + vdev_stop_resp->status = status; + status = wma_remove_bss_peer(wma, vdev_id, + vdev_stop_resp, type); + if (status) { + wma_err("Del bss failed vdev:%d", vdev_id); + wma_send_vdev_down_req(wma, vdev_stop_resp); + return status; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) + return status; + + wma_send_vdev_down_req(wma, vdev_stop_resp); + } + + return status; + +free_params: + qdf_mem_free(vdev_stop_resp); + return status; +} + +QDF_STATUS +cm_send_bss_peer_delete_req(struct wlan_objmgr_vdev *vdev) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + if (!wma) + return QDF_STATUS_E_INVAL; + + if (wlan_vdev_mlme_is_init_state(vdev) == QDF_STATUS_SUCCESS) { + wma_remove_bss_peer_on_failure(wma, vdev_id); + return QDF_STATUS_SUCCESS; + } + + return wma_delete_peer_on_vdev_stop(wma, vdev_id); +} + +QDF_STATUS +__wma_handle_vdev_stop_rsp(struct vdev_stop_response *resp_event) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + QDF_STATUS status; + struct qdf_mac_addr bssid; + enum QDF_OPMODE mode; + + if (!wma) + return QDF_STATUS_E_INVAL; + + /* Ignore stop_response in Monitor mode */ + if (cds_get_conparam() == QDF_GLOBAL_MONITOR_MODE) + return QDF_STATUS_SUCCESS; + + iface = &wma->interfaces[resp_event->vdev_id]; + + /* vdev in stopped state, no more waiting for key */ + iface->is_waiting_for_key = false; + + /* + * Reset the rmfEnabled as there might be MGMT action frames + * sent on this vdev before the next session is established. + */ + if (iface->rmfEnabled) { + iface->rmfEnabled = 0; + wma_debug("Reset rmfEnabled for vdev %d", + resp_event->vdev_id); + } + + mode = wlan_vdev_mlme_get_opmode(iface->vdev); + if (mode == QDF_STA_MODE || mode == QDF_P2P_CLIENT_MODE) { + status = wlan_vdev_get_bss_peer_mac(iface->vdev, &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("Failed to get bssid, peer might have got deleted already"); + return wlan_cm_bss_peer_delete_rsp(iface->vdev, status); + } + /* initiate CM to delete bss peer */ + return wlan_cm_bss_peer_delete_ind(iface->vdev, &bssid); + } else if (mode == QDF_SAP_MODE) { + wlan_son_deliver_vdev_stop(iface->vdev); + } + + return wma_delete_peer_on_vdev_stop(wma, resp_event->vdev_id); +} + +/** + * wma_handle_vdev_stop_rsp() - handle vdev stop resp + * @wma: wma handle + * @resp_event: fw resp + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_handle_vdev_stop_rsp(tp_wma_handle wma, + struct vdev_stop_response *resp_event) +{ + struct wma_txrx_node *iface; + + iface = &wma->interfaces[resp_event->vdev_id]; + return wlan_vdev_mlme_sm_deliver_evt(iface->vdev, + WLAN_VDEV_SM_EV_STOP_RESP, + sizeof(*resp_event), resp_event); +} + +QDF_STATUS wma_vdev_stop_resp_handler(struct vdev_mlme_obj *vdev_mlme, + struct vdev_stop_response *rsp) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface = NULL; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return status; + + iface = &wma->interfaces[vdev_mlme->vdev->vdev_objmgr.vdev_id]; + + if (rsp->vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %d from FW", rsp->vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wma_handle_vdev_stop_rsp(wma, rsp); + + return status; +} + +void wma_cleanup_vdev(struct wlan_objmgr_vdev *vdev) +{ + tp_wma_handle wma_handle; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct vdev_mlme_obj *vdev_mlme; + + if (!soc) + return; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return; + + if (!wma_handle->interfaces[vdev_id].vdev) { + wma_err("vdev is NULL"); + return; + } + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wma_err("Failed to get vdev mlme obj for vdev id %d", vdev_id); + return; + } + + wma_cdp_vdev_detach(soc, wma_handle, vdev_id); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + wma_handle->interfaces[vdev_id].vdev = NULL; + wma_handle->interfaces[vdev_id].vdev_active = false; +} + +QDF_STATUS wma_vdev_self_peer_create(struct vdev_mlme_obj *vdev_mlme) +{ + struct wlan_objmgr_peer *obj_peer; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev; + tp_wma_handle wma_handle; + uint8_t peer_vdev_id, *self_peer_macaddr; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (mlme_vdev_uses_self_peer(vdev_mlme->mgmt.generic.type, + vdev_mlme->mgmt.generic.subtype)) { + status = wma_create_peer(wma_handle, + vdev->vdev_mlme.macaddr, + WMI_PEER_TYPE_DEFAULT, + wlan_vdev_get_id(vdev), + NULL, false); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to create peer %d", status); + } else if (vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_STA || + vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_NAN) { + if (!qdf_is_macaddr_zero( + (struct qdf_mac_addr *)vdev->vdev_mlme.mldaddr)) + self_peer_macaddr = vdev->vdev_mlme.mldaddr; + else + self_peer_macaddr = vdev->vdev_mlme.macaddr; + + /** + * Self peer is used for the frames exchanged before + * association. For ML STA, Self peer create will be triggered + * for both the VDEVs, but one self peer is enough. So in case + * of ML, use MLD address for the self peer and ignore self peer + * creation for the partner link vdev. + */ + if (wma_objmgr_peer_exist(wma_handle, self_peer_macaddr, + &peer_vdev_id)) + return QDF_STATUS_SUCCESS; + + obj_peer = wma_create_objmgr_peer(wma_handle, + wlan_vdev_get_id(vdev), + self_peer_macaddr, + WMI_PEER_TYPE_DEFAULT, + vdev->vdev_mlme.macaddr); + if (!obj_peer) { + wma_err("Failed to create obj mgr peer for self"); + status = QDF_STATUS_E_INVAL; + } + } + + return status; +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +#define MAX_VDEV_LATENCY_PARAMS 10 +/* params being sent: + * 1.wmi_vdev_param_set_multi_client_ll_feature_config + * 2.wmi_vdev_param_set_normal_latency_flags_config + * 3.wmi_vdev_param_set_xr_latency_flags_config + * 4.wmi_vdev_param_set_low_latency_flags_config + * 5.wmi_vdev_param_set_ultra_low_latency_flags_config + * 6.wmi_vdev_param_set_normal_latency_ul_dl_config + * 7.wmi_vdev_param_set_xr_latency_ul_dl_config + * 8.wmi_vdev_param_set_low_latency_ul_dl_config + * 9.wmi_vdev_param_set_ultra_low_latency_ul_dl_config + * 10.wmi_vdev_param_set_default_ll_config + */ + +/** + * wma_set_vdev_latency_level_param() - Set per vdev latency level params in FW + * @wma_handle: wma handle + * @mac: mac context + * @vdev_id: vdev id + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_set_vdev_latency_level_param(tp_wma_handle wma_handle, + struct mac_context *mac, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool multi_client_ll_ini_support, multi_client_ll_caps; + uint32_t latency_flags; + static uint32_t ll[4] = {100, 60, 40, 20}; + uint32_t ul_latency, dl_latency, ul_dl_latency; + uint8_t default_latency_level; + struct dev_set_param setparam[MAX_VDEV_LATENCY_PARAMS]; + uint8_t index = 0; + + multi_client_ll_ini_support = + mac->mlme_cfg->wlm_config.multi_client_ll_support; + multi_client_ll_caps = + wlan_mlme_get_wlm_multi_client_ll_caps(mac->psoc); + wma_debug("INI support: %d, fw capability:%d", + multi_client_ll_ini_support, multi_client_ll_caps); + /* + * Multi-Client arbiter functionality is enabled only if both INI is + * set, and Service bit is configured. + */ + if (!(multi_client_ll_ini_support && multi_client_ll_caps)) + return status; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_multi_client_ll_feature_config, + multi_client_ll_ini_support, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure low latency feature"); + return status; + } + + /* wlm latency level index:0 - normal, 1 - xr, 2 - low, 3 - ultralow */ + wma_debug("Setting vdev params for latency level flags"); + + latency_flags = mac->mlme_cfg->wlm_config.latency_flags[0]; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_normal_latency_flags_config, + latency_flags, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure normal latency feature"); + return status; + } + + latency_flags = mac->mlme_cfg->wlm_config.latency_flags[1]; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_xr_latency_flags_config, + latency_flags, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure xr latency feature"); + return status; + } + + latency_flags = mac->mlme_cfg->wlm_config.latency_flags[2]; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_low_latency_flags_config, + latency_flags, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure low latency feature"); + return status; + } + + latency_flags = mac->mlme_cfg->wlm_config.latency_flags[3]; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_ultra_low_latency_flags_config, + latency_flags, index++, MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure ultra low latency feature"); + return status; + } + + wma_debug("Setting vdev params for Latency level UL/DL flags"); + /* + * Latency level UL/DL + * 0-15 bits: UL and 16-31 bits: DL + */ + dl_latency = ll[0]; + ul_latency = ll[0]; + ul_dl_latency = dl_latency << 16 | ul_latency; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_normal_latency_ul_dl_config, + ul_dl_latency, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure normal latency ul dl flag"); + return status; + } + + dl_latency = ll[1]; + ul_latency = ll[1]; + ul_dl_latency = dl_latency << 16 | ul_latency; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_xr_latency_ul_dl_config, + ul_dl_latency, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure normal latency ul dl flag"); + return status; + } + + dl_latency = ll[2]; + ul_latency = ll[2]; + ul_dl_latency = dl_latency << 16 | ul_latency; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_low_latency_ul_dl_config, + ul_dl_latency, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure normal latency ul dl flag"); + return status; + } + + dl_latency = ll[3]; + ul_latency = ll[3]; + ul_dl_latency = dl_latency << 16 | ul_latency; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_ultra_low_latency_ul_dl_config, + ul_dl_latency, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure normal latency ul dl flag"); + return status; + } + + default_latency_level = mac->mlme_cfg->wlm_config.latency_level; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_default_ll_config, + default_latency_level, index++, + MAX_VDEV_LATENCY_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to configure low latency feature"); + return status; + } + + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to configure vdev latency level params"); + return status; +} +#else +static QDF_STATUS wma_set_vdev_latency_level_param(tp_wma_handle wma_handle, + struct mac_context *mac, + uint8_t vdev_id) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + +QDF_STATUS wma_post_vdev_create_setup(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + bool mcc_adapt_sch = false; + QDF_STATUS ret; + uint8_t vdev_id; + struct wlan_mlme_qos *qos_aggr; + struct vdev_mlme_obj *vdev_mlme; + tp_wma_handle wma_handle; + uint8_t enable_sifs_burst = 0; + + if (!mac) + return QDF_STATUS_E_FAILURE; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (wlan_objmgr_vdev_try_get_ref(vdev, WLAN_LEGACY_WMA_ID) != + QDF_STATUS_SUCCESS) + return QDF_STATUS_E_FAILURE; + + vdev_id = wlan_vdev_get_id(vdev); + wma_handle->interfaces[vdev_id].vdev = vdev; + wma_handle->interfaces[vdev_id].vdev_active = true; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wma_err("Failed to get vdev mlme obj!"); + goto end; + } + + wma_vdev_update_pause_bitmap(vdev_id, 0); + + wma_handle->interfaces[vdev_id].type = + vdev_mlme->mgmt.generic.type; + wma_handle->interfaces[vdev_id].sub_type = + vdev_mlme->mgmt.generic.subtype; + + qos_aggr = &mac->mlme_cfg->qos_mlme_params; + if (vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_STA) { + wma_set_sta_keep_alive( + wma_handle, vdev_id, + SIR_KEEP_ALIVE_NULL_PKT, + mac->mlme_cfg->sta.sta_keep_alive_period, + NULL, NULL, NULL); + + /* offload STA SA query related params to fwr */ + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sta_pmf_offload)) { + wma_set_sta_sa_query_param(wma_handle, vdev_id); + } + + status = wma_set_sw_retry_threshold(qos_aggr); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set sw retry threshold (status = %d)", + status); + + status = wma_set_sw_retry_threshold_per_ac(wma_handle, vdev_id, + qos_aggr); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set sw retry threshold per ac(status = %d)", + status); + } + + status = wma_vdev_create_set_param(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to setup Vdev create set param for vdev: %d", + vdev_id); + return status; + } + + if (policy_mgr_get_dynamic_mcc_adaptive_sch(mac->psoc, + &mcc_adapt_sch) == + QDF_STATUS_SUCCESS) { + wma_debug("setting ini value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED: %d", + mcc_adapt_sch); + ret = + wma_set_enable_disable_mcc_adaptive_scheduler(mcc_adapt_sch); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Failed to set WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED"); + } + } else { + wma_err("Failed to get value for WNI_CFG_ENABLE_MCC_ADAPTIVE_SCHED, leaving unchanged"); + } + + if (vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_STA && + ucfg_pmo_is_apf_enabled(wma_handle->psoc)) { + ret = wma_config_active_apf_mode(wma_handle, + vdev_id); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to configure active APF mode"); + } + + if (vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_STA && + vdev_mlme->mgmt.generic.subtype == 0) + wma_set_vdev_latency_level_param(wma_handle, mac, vdev_id); + + switch (vdev_mlme->mgmt.generic.type) { + case WMI_VDEV_TYPE_AP: + if (vdev_mlme->mgmt.generic.subtype != + WLAN_VDEV_MLME_SUBTYPE_P2P_DEVICE) + break; + + fallthrough; + case WMI_VDEV_TYPE_STA: + case WMI_VDEV_TYPE_NAN: + case WMI_VDEV_TYPE_OCB: + case WMI_VDEV_TYPE_MONITOR: + status = ucfg_get_enable_sifs_burst(wma_handle->psoc, + &enable_sifs_burst); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to get sifs burst value, use default"); + + status = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + WMI_PDEV_PARAM_BURST_ENABLE, + enable_sifs_burst); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("WMI_PDEV_PARAM_BURST_ENABLE set failed %d", + status); + break; + default: + break; + } + + wma_vdev_set_data_tx_callback(vdev); + + return QDF_STATUS_SUCCESS; + +end: + wma_cleanup_vdev(vdev); + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wma_vdev_set_data_tx_callback(struct wlan_objmgr_vdev *vdev) +{ + u_int8_t vdev_id; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!vdev || !wma_handle || !soc) { + wma_err("null vdev, wma_handle or soc"); + return QDF_STATUS_E_FAILURE; + } + + vdev_id = wlan_vdev_get_id(vdev); + cdp_data_tx_cb_set(soc, vdev_id, + wma_data_tx_ack_comp_hdlr, + wma_handle); + + return QDF_STATUS_SUCCESS; +} + +enum mlme_bcn_tx_rate_code wma_get_bcn_rate_code(uint16_t rate) +{ + /* rate in multiples of 100 Kbps */ + switch (rate) { + case WMA_BEACON_TX_RATE_1_M: + return MLME_BCN_TX_RATE_CODE_1_M; + case WMA_BEACON_TX_RATE_2_M: + return MLME_BCN_TX_RATE_CODE_2_M; + case WMA_BEACON_TX_RATE_5_5_M: + return MLME_BCN_TX_RATE_CODE_5_5_M; + case WMA_BEACON_TX_RATE_11_M: + return MLME_BCN_TX_RATE_CODE_11M; + case WMA_BEACON_TX_RATE_6_M: + return MLME_BCN_TX_RATE_CODE_6_M; + case WMA_BEACON_TX_RATE_9_M: + return MLME_BCN_TX_RATE_CODE_9_M; + case WMA_BEACON_TX_RATE_12_M: + return MLME_BCN_TX_RATE_CODE_12_M; + case WMA_BEACON_TX_RATE_18_M: + return MLME_BCN_TX_RATE_CODE_18_M; + case WMA_BEACON_TX_RATE_24_M: + return MLME_BCN_TX_RATE_CODE_24_M; + case WMA_BEACON_TX_RATE_36_M: + return MLME_BCN_TX_RATE_CODE_36_M; + case WMA_BEACON_TX_RATE_48_M: + return MLME_BCN_TX_RATE_CODE_48_M; + case WMA_BEACON_TX_RATE_54_M: + return MLME_BCN_TX_RATE_CODE_54_M; + default: + return MLME_BCN_TX_RATE_CODE_1_M; + } +} + +#ifdef WLAN_BCN_RATECODE_ENABLE +/** + * wma_update_beacon_tx_rate_code() - Update bcn_tx_rate_code + * @mlme_obj: pointer to mlme object + * + * Return: none + */ +static void wma_update_beacon_tx_rate_code(struct vdev_mlme_obj *mlme_obj) +{ + uint8_t preamble, nss, rix; + uint32_t rate_code; + + rate_code = mlme_obj->mgmt.rate_info.bcn_tx_rate; + + rix = rate_code & RATECODE_V1_RIX_MASK; + nss = (rate_code >> RATECODE_V1_NSS_OFFSET) & RATECODE_V1_NSS_MASK; + preamble = rate_code >> RATECODE_V1_PREAMBLE_OFFSET; + + mlme_obj->mgmt.rate_info.bcn_tx_rate_code = + wlan_mlme_assemble_rate_code(preamble, nss, rix); +} +#else +static void wma_update_beacon_tx_rate_code(struct vdev_mlme_obj *mlme_obj) +{ +} +#endif + +QDF_STATUS wma_vdev_pre_start(uint8_t vdev_id, bool restart) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *intr; + struct mac_context *mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + struct wlan_mlme_nss_chains *ini_cfg; + struct vdev_mlme_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev; + struct wlan_channel *des_chan; + QDF_STATUS status; + enum coex_btc_chain_mode btc_chain_mode; + struct wlan_mlme_qos *qos_aggr; + uint8_t amsdu_val; + + if (!wma || !mac_ctx) + return QDF_STATUS_E_FAILURE; + + intr = wma->interfaces; + if (!intr) { + wma_err("Invalid interface"); + return QDF_STATUS_E_FAILURE; + } + if (vdev_id >= WLAN_MAX_VDEVS) { + wma_err("Invalid vdev id"); + return QDF_STATUS_E_INVAL; + } + vdev = intr[vdev_id].vdev; + if (!vdev) { + wma_err("Invalid vdev"); + return QDF_STATUS_E_FAILURE; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + des_chan = vdev->vdev_mlme.des_chan; + + ini_cfg = mlme_get_ini_vdev_config(vdev); + if (!ini_cfg) { + wma_err("nss chain ini config NULL"); + return QDF_STATUS_E_FAILURE; + } + + intr[vdev_id].config.gtx_info.gtxRTMask[0] = + CFG_TGT_DEFAULT_GTX_HT_MASK; + intr[vdev_id].config.gtx_info.gtxRTMask[1] = + CFG_TGT_DEFAULT_GTX_VHT_MASK; + + intr[vdev_id].config.gtx_info.gtxUsrcfg = + mac_ctx->mlme_cfg->sta.tgt_gtx_usr_cfg; + + intr[vdev_id].config.gtx_info.gtxPERThreshold = + CFG_TGT_DEFAULT_GTX_PER_THRESHOLD; + intr[vdev_id].config.gtx_info.gtxPERMargin = + CFG_TGT_DEFAULT_GTX_PER_MARGIN; + intr[vdev_id].config.gtx_info.gtxTPCstep = + CFG_TGT_DEFAULT_GTX_TPC_STEP; + intr[vdev_id].config.gtx_info.gtxTPCMin = + CFG_TGT_DEFAULT_GTX_TPC_MIN; + intr[vdev_id].config.gtx_info.gtxBWMask = + CFG_TGT_DEFAULT_GTX_BW_MASK; + intr[vdev_id].chan_width = des_chan->ch_width; + intr[vdev_id].ch_freq = des_chan->ch_freq; + intr[vdev_id].ch_flagext = des_chan->ch_flagext; + + /* + * If the channel has DFS set, flip on radar reporting. + * + * It may be that this should only be done for hostap operation + * as this flag may be interpreted (at some point in the future) + * by the firmware as "oh, and please do radar DETECTION." + * + * If that is ever the case we would insert the decision whether to + * enable the firmware flag here. + */ + if (QDF_GLOBAL_MONITOR_MODE != cds_get_conparam() && + utils_is_dfs_chan_for_freq(wma->pdev, des_chan->ch_freq)) + mlme_obj->mgmt.generic.disable_hw_ack = true; + + if (mlme_obj->mgmt.rate_info.bcn_tx_rate) { + wma_debug("beacon tx rate [%u * 100 Kbps]", + mlme_obj->mgmt.rate_info.bcn_tx_rate); + /* + * beacon_tx_rate is in multiples of 100 Kbps. + * Convert the data rate to hw rate code. + */ + mlme_obj->mgmt.rate_info.bcn_tx_rate = + wma_get_bcn_rate_code(mlme_obj->mgmt.rate_info.bcn_tx_rate); + wma_update_beacon_tx_rate_code(mlme_obj); + } + + if (!restart) { + wma_debug("vdev_id: %d, unpausing tx_ll_queue at VDEV_START", + vdev_id); + + cdp_fc_vdev_unpause(cds_get_context(QDF_MODULE_ID_SOC), + vdev_id, 0xffffffff, 0); + wma_vdev_update_pause_bitmap(vdev_id, 0); + } + + /* Send the dynamic nss chain params before vdev start to fw */ + if (wma->dynamic_nss_chains_support && !restart) + wma_vdev_nss_chain_params_send(vdev_id, ini_cfg); + + status = ucfg_coex_psoc_get_btc_chain_mode(wma->psoc, &btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get btc chain mode"); + return QDF_STATUS_E_FAILURE; + } + + if (btc_chain_mode != WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED) { + status = ucfg_coex_send_btc_chain_mode(vdev, btc_chain_mode); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send btc chain mode %d", + btc_chain_mode); + return QDF_STATUS_E_FAILURE; + } + } + + qos_aggr = &mac_ctx->mlme_cfg->qos_mlme_params; + status = wma_set_tx_rx_aggr_size(vdev_id, qos_aggr->tx_aggregation_size, + qos_aggr->rx_aggregation_size, + WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set aggregation sizes(status = %d)", status); + + if (mac_ctx->is_usr_cfg_amsdu_enabled) { + status = wlan_mlme_get_max_amsdu_num(wma->psoc, &amsdu_val); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to get amsdu aggr.size(status = %d)", + status); + } else { + status = wma_set_tx_rx_aggr_size( + vdev_id, amsdu_val, amsdu_val, + WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set amsdu aggr.size(status = %d)", + status); + } + } + + if (mlme_obj->mgmt.generic.type == WMI_VDEV_TYPE_STA) { + status = wma_set_tx_rx_aggr_size_per_ac(wma, vdev_id, qos_aggr, + WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set aggr size per ac(status = %d)", + status); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_peer_assoc_conf_handler() - peer assoc conf handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_peer_assoc_conf_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *param_buf; + wmi_peer_assoc_conf_event_fixed_param *event; + struct wma_target_req *req_msg; + uint8_t macaddr[QDF_MAC_ADDR_SIZE]; + int status = 0; + + param_buf = (WMI_PEER_ASSOC_CONF_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + wma_err("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + wma_err("Invalid peer assoc conf event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + wma_debug("peer assoc conf for vdev:%d mac="QDF_MAC_ADDR_FMT, + event->vdev_id, QDF_MAC_ADDR_REF(macaddr)); + + req_msg = wma_find_req(wma, event->vdev_id, + WMA_PEER_ASSOC_CNF_START, NULL); + + if (!req_msg) { + wma_err("Failed to lookup request message for vdev %d", + event->vdev_id); + return -EINVAL; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + + if (req_msg->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams)req_msg->user_data; + + if (!params) { + wma_err("add STA params is NULL for vdev %d", + event->vdev_id); + status = -EINVAL; + goto free_req_msg; + } + + /* peer assoc conf event means the cmd succeeds */ + params->status = event->status; + wma_debug("Send ADD_STA_RSP: statype %d vdev_id %d aid %d bssid "QDF_MAC_ADDR_FMT" status %d", + params->staType, params->smesessionId, + params->assocId, QDF_MAC_ADDR_REF(params->bssId), + params->status); + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, + (void *)params, 0); + } else if (req_msg->msg_type == WMA_ADD_BSS_REQ) { + wma_send_add_bss_resp(wma, event->vdev_id, event->status); + } else { + wma_err("Unhandled request message type: %d", req_msg->msg_type); + } + +free_req_msg: + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); + + return status; +} + +int wma_peer_create_confirm_handler(void *handle, uint8_t *evt_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + wmi_peer_create_conf_event_fixed_param *peer_create_rsp; + WMI_PEER_CREATE_CONF_EVENTID_param_tlvs *param_buf; + struct wma_target_req *req_msg = NULL; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct peer_create_rsp_params *rsp_data; + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + struct qdf_mac_addr peer_mac; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + int ret = -EINVAL; + uint8_t req_msg_type; + struct wlan_objmgr_peer *peer; + struct cdp_peer_setup_info peer_info = {0}; + + param_buf = (WMI_PEER_CREATE_CONF_EVENTID_param_tlvs *)evt_param_info; + if (!param_buf) { + wma_err("Invalid peer create conf evt buffer"); + return -EINVAL; + } + + peer_create_rsp = param_buf->fixed_param; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&peer_create_rsp->peer_macaddr, + peer_mac.bytes); + if (qdf_is_macaddr_zero(&peer_mac) || + qdf_is_macaddr_broadcast(&peer_mac) || + qdf_is_macaddr_group(&peer_mac)) { + wma_err("Invalid bssid"); + return -EINVAL; + } + + wma_debug("vdev:%d Peer create confirm for bssid: " QDF_MAC_ADDR_FMT, + peer_create_rsp->vdev_id, QDF_MAC_ADDR_REF(peer_mac.bytes)); + req_msg = wma_find_remove_req_msgtype(wma, peer_create_rsp->vdev_id, + WMA_PEER_CREATE_REQ); + if (!req_msg) { + wma_debug("vdev:%d Failed to lookup peer create request msg", + peer_create_rsp->vdev_id); + return -EINVAL; + } + + rsp_data = (struct peer_create_rsp_params *)req_msg->user_data; + req_msg_type = req_msg->type; + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(rsp_data); + qdf_mem_free(req_msg); + + if (req_msg_type == WMA_PASN_PEER_CREATE_RESPONSE) { + wma_pasn_handle_peer_create_conf(wma, &peer_mac, + peer_create_rsp->status, + peer_create_rsp->vdev_id); + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + return 0; + } + + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + if (!peer_create_rsp->status) { + if (!dp_soc) { + wma_err("DP SOC context is NULL"); + goto fail; + } + + peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_mac.bytes, + WLAN_LEGACY_WMA_ID); + if (!peer) { + status = QDF_STATUS_E_FAILURE; + goto fail; + } + + wma_peer_setup_fill_info(wma->psoc, peer, &peer_info); + wma_peer_tbl_trans_add_entry(peer, true, &peer_info); + wma_cdp_peer_setup(dp_soc, peer_create_rsp->vdev_id, + peer, &peer_info); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + status = QDF_STATUS_SUCCESS; + ret = 0; + } + +fail: + if (QDF_IS_STATUS_ERROR(status)) + wma_remove_peer(wma, peer_mac.bytes, peer_create_rsp->vdev_id, + (peer_create_rsp->status > 0) ? true : false); + + if (mac) + lim_send_peer_create_resp(mac, peer_create_rsp->vdev_id, status, + peer_mac.bytes); + + return ret; +} + +#ifdef FEATURE_WDS +/* + * wma_cdp_cp_peer_del_response - handle peer delete response + * @psoc: psoc object pointer + * @mac_addr: Mac address of the peer + * @vdev_id: id of virtual device object + * + * when peer map v2 is enabled, cdp_peer_teardown() does not remove the AST from + * hash table. Call cdp_cp_peer_del_response() when peer delete response is + * received from fw to delete the AST entry from the AST hash. + * + * Return: None + */ +static void +wma_cdp_cp_peer_del_response(struct wlan_objmgr_psoc *psoc, + uint8_t *peer_mac, uint8_t vdev_id) +{ + ol_txrx_soc_handle soc_txrx_handle; + + soc_txrx_handle = wlan_psoc_get_dp_handle(psoc); + cdp_cp_peer_del_response(soc_txrx_handle, vdev_id, peer_mac); +} +#else +static void +wma_cdp_cp_peer_del_response(struct wlan_objmgr_psoc *psoc, + uint8_t *peer_mac, uint8_t vdev_id) +{ +} +#endif + +/** + * wma_peer_delete_handler() - peer delete response handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_peer_delete_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *param_buf; + wmi_peer_delete_cmd_fixed_param *event; + struct wma_target_req *req_msg; + tDeleteStaParams *del_sta; + uint8_t macaddr[QDF_MAC_ADDR_SIZE]; + int status = 0; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("mac context is null"); + return -EINVAL; + } + param_buf = (WMI_PEER_DELETE_RESP_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + wma_err("Invalid vdev delete event buffer"); + return -EINVAL; + } + + event = (wmi_peer_delete_cmd_fixed_param *)param_buf->fixed_param; + if (!event) { + wma_err("Invalid vdev delete event buffer"); + return -EINVAL; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->peer_macaddr, macaddr); + wma_debug("Peer Delete Response, vdev %d Peer "QDF_MAC_ADDR_FMT, + event->vdev_id, QDF_MAC_ADDR_REF(macaddr)); + wlan_roam_debug_log(event->vdev_id, DEBUG_PEER_DELETE_RESP, + DEBUG_INVALID_PEER_ID, macaddr, NULL, 0, 0); + req_msg = wma_find_remove_req_msgtype(wma, event->vdev_id, + WMA_DELETE_STA_REQ); + if (!req_msg) { + wma_debug("Peer Delete response is not handled"); + return -EINVAL; + } + + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + + /* Cleanup timeout handler */ + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + + if (req_msg->type == WMA_DELETE_STA_RSP_START) { + del_sta = req_msg->user_data; + if (del_sta->respReqd) { + wma_debug("Sending peer del rsp to umac"); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, + (void *)del_sta, QDF_STATUS_SUCCESS); + } else { + qdf_mem_free(del_sta); + } + } else if (req_msg->type == WMA_DEL_P2P_SELF_STA_RSP_START) { + struct del_sta_self_rsp_params *data; + + data = (struct del_sta_self_rsp_params *)req_msg->user_data; + wma_debug("Calling vdev detach handler"); + wma_handle_vdev_detach(wma, data->self_sta_param); + mlme_vdev_self_peer_delete_resp(data->self_sta_param); + qdf_mem_free(data); + } else if (req_msg->type == WMA_SET_LINK_PEER_RSP || + req_msg->type == WMA_DELETE_PEER_RSP) { + wma_send_vdev_down_req(wma, req_msg->user_data); + } else if (req_msg->type == WMA_DELETE_STA_CONNECT_RSP) { + wma_debug("wma delete peer completed vdev %d", + req_msg->vdev_id); + lim_cm_send_connect_rsp(mac, NULL, req_msg->user_data, + CM_GENERIC_FAILURE, + QDF_STATUS_E_FAILURE, 0, false); + cm_free_join_req(req_msg->user_data); + } + + wma_cdp_cp_peer_del_response(wma->psoc, macaddr, event->vdev_id); + qdf_mem_free(req_msg); + + return status; +} + +static +void wma_trigger_recovery_assert_on_fw_timeout(uint16_t wma_msg, + enum qdf_hang_reason reason) +{ + wma_err("%s timed out, triggering recovery", + mac_trace_get_wma_msg_string(wma_msg)); + qdf_trigger_self_recovery(NULL, reason); +} + +static inline bool wma_crash_on_fw_timeout(bool crash_enabled) +{ + /* Discard FW timeouts and dont crash during SSR */ + if (cds_is_driver_recovering()) + return false; + + /* Firmware is down send failure response */ + if (cds_is_fw_down()) + return false; + + if (cds_is_driver_unloading()) + return false; + + return crash_enabled; +} + +/** + * wma_hold_req_timer() - wma hold request timeout function + * @data: target request params + * + * Return: none + */ +void wma_hold_req_timer(void *data) +{ + tp_wma_handle wma; + struct wma_target_req *tgt_req = (struct wma_target_req *)data; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + status = wma_find_req_on_timer_expiry(wma, tgt_req); + + if (QDF_IS_STATUS_ERROR(status)) { + /* + * if find request failed, then firmware rsp should have + * consumed the buffer. Do not free. + */ + wma_debug("Failed to lookup request message - %pK", tgt_req); + return; + } + wma_alert("request %d is timed out for vdev_id - %d", + tgt_req->msg_type, tgt_req->vdev_id); + + if (tgt_req->msg_type == WMA_ADD_STA_REQ) { + tpAddStaParams params = (tpAddStaParams) tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + wma_alert("WMA_ADD_STA_REQ timed out"); + wma_debug("Sending add sta rsp to umac (mac:"QDF_MAC_ADDR_FMT", status:%d)", + QDF_MAC_ADDR_REF(params->staMac), params->status); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_ADD_STA_REQ, + QDF_AP_STA_CONNECT_REQ_TIMEOUT); + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, + (void *)params, 0); + } else if (tgt_req->msg_type == WMA_ADD_BSS_REQ) { + + wma_alert("WMA_ADD_BSS_REQ timed out"); + wma_debug("Sending add bss rsp to umac (vdev %d, status:%d)", + tgt_req->vdev_id, QDF_STATUS_E_TIMEOUT); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_ADD_BSS_REQ, + QDF_STA_AP_CONNECT_REQ_TIMEOUT); + + wma_send_add_bss_resp(wma, tgt_req->vdev_id, + QDF_STATUS_E_TIMEOUT); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DELETE_STA_RSP_START)) { + tpDeleteStaParams params = + (tpDeleteStaParams) tgt_req->user_data; + params->status = QDF_STATUS_E_TIMEOUT; + wma_err("WMA_DEL_STA_REQ timed out"); + wma_debug("Sending del sta rsp to umac (mac:"QDF_MAC_ADDR_FMT", status:%d)", + QDF_MAC_ADDR_REF(params->staMac), params->status); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DELETE_STA_REQ, + QDF_PEER_DELETION_TIMEDOUT); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, + (void *)params, 0); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DEL_P2P_SELF_STA_RSP_START)) { + struct del_sta_self_rsp_params *del_sta; + + del_sta = (struct del_sta_self_rsp_params *)tgt_req->user_data; + + del_sta->self_sta_param->status = QDF_STATUS_E_TIMEOUT; + wma_alert("wma delete sta p2p request timed out"); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DELETE_STA_REQ, + QDF_PEER_DELETION_TIMEDOUT); + wma_handle_vdev_detach(wma, del_sta->self_sta_param); + mlme_vdev_self_peer_delete_resp(del_sta->self_sta_param); + qdf_mem_free(tgt_req->user_data); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_SET_LINK_PEER_RSP || + tgt_req->type == WMA_DELETE_PEER_RSP)) { + struct del_bss_resp *params = + (struct del_bss_resp *)tgt_req->user_data; + + params->status = QDF_STATUS_E_TIMEOUT; + wma_err("wma delete peer for del bss req timed out"); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DELETE_STA_REQ, + QDF_PEER_DELETION_TIMEDOUT); + wma_send_vdev_down_req(wma, params); + } else if ((tgt_req->msg_type == WMA_DELETE_STA_REQ) && + (tgt_req->type == WMA_DELETE_STA_CONNECT_RSP)) { + wma_err("wma delete peer timed out vdev %d", + tgt_req->vdev_id); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_DELETE_STA_REQ, + QDF_PEER_DELETION_TIMEDOUT); + if (!mac) { + wma_err("mac: Null Pointer Error"); + goto timer_destroy; + } + lim_cm_send_connect_rsp(mac, NULL, tgt_req->user_data, + CM_GENERIC_FAILURE, + QDF_STATUS_E_FAILURE, 0, false); + cm_free_join_req(tgt_req->user_data); + } else if ((tgt_req->msg_type == SIR_HAL_PDEV_SET_HW_MODE) && + (tgt_req->type == WMA_PDEV_SET_HW_MODE_RESP)) { + struct sir_set_hw_mode_resp *params = + qdf_mem_malloc(sizeof(*params)); + + wma_err("set hw mode req timed out"); + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + SIR_HAL_PDEV_SET_HW_MODE, + QDF_MAC_HW_MODE_CHANGE_TIMEOUT); + if (!params) + goto timer_destroy; + + params->status = SET_HW_MODE_STATUS_ECANCELED; + params->cfgd_hw_mode_index = 0; + params->num_vdev_mac_entries = 0; + wma_send_msg_high_priority(wma, SIR_HAL_PDEV_SET_HW_MODE_RESP, + params, 0); + } else if ((tgt_req->msg_type == SIR_HAL_PDEV_DUAL_MAC_CFG_REQ) && + (tgt_req->type == WMA_PDEV_MAC_CFG_RESP)) { + struct sir_dual_mac_config_resp *resp = + qdf_mem_malloc(sizeof(*resp)); + + wma_err("set dual mac config timeout"); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + SIR_HAL_PDEV_DUAL_MAC_CFG_REQ, + QDF_MAC_HW_MODE_CONFIG_TIMEOUT); + if (!resp) + goto timer_destroy; + + resp->status = SET_HW_MODE_STATUS_ECANCELED; + wma_send_msg_high_priority(wma, SIR_HAL_PDEV_MAC_CFG_RESP, + resp, 0); + } else if ((tgt_req->msg_type == WMA_PEER_CREATE_REQ) && + (tgt_req->type == WMA_PEER_CREATE_RESPONSE)) { + struct peer_create_rsp_params *peer_create_rsp; + struct qdf_mac_addr *peer_mac; + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_PEER_CREATE_RESPONSE, + WMA_PEER_CREATE_RESPONSE_TIMEOUT); + + peer_create_rsp = + (struct peer_create_rsp_params *)tgt_req->user_data; + peer_mac = &peer_create_rsp->peer_mac; + wma_remove_peer(wma, peer_mac->bytes, + tgt_req->vdev_id, false); + if (!mac) { + qdf_mem_free(tgt_req->user_data); + goto timer_destroy; + } + + lim_send_peer_create_resp(mac, tgt_req->vdev_id, + QDF_STATUS_E_TIMEOUT, + (uint8_t *)tgt_req->user_data); + qdf_mem_free(tgt_req->user_data); + } else if ((tgt_req->msg_type == WMA_PEER_CREATE_REQ) && + (tgt_req->type == WMA_PASN_PEER_CREATE_RESPONSE)) { + struct peer_create_rsp_params *peer_create_rsp; + struct qdf_mac_addr *peer_mac; + + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_PEER_CREATE_RESPONSE, + WMA_PEER_CREATE_RESPONSE_TIMEOUT); + + peer_create_rsp = + (struct peer_create_rsp_params *)tgt_req->user_data; + peer_mac = &peer_create_rsp->peer_mac; + + wma_pasn_handle_peer_create_conf( + wma, peer_mac, QDF_STATUS_E_TIMEOUT, + tgt_req->vdev_id); + qdf_mem_free(tgt_req->user_data); + } else if (tgt_req->msg_type == WMA_PASN_PEER_DELETE_REQUEST && + tgt_req->type == WMA_PASN_PEER_DELETE_RESPONSE) { + wma_err("PASN Peer delete all resp not received. vdev:%d", + tgt_req->vdev_id); + if (wma_crash_on_fw_timeout(wma->fw_timeout_crash)) + wma_trigger_recovery_assert_on_fw_timeout( + WMA_PASN_PEER_DELETE_RESPONSE, + WMA_PEER_DELETE_RESPONSE_TIMEOUT); + + wma_resume_vdev_delete(wma, tgt_req->vdev_id); + } else { + wma_err("Unhandled timeout for msg_type:%d and type:%d", + tgt_req->msg_type, tgt_req->type); + QDF_BUG(0); + } + +timer_destroy: + qdf_mc_timer_destroy(&tgt_req->event_timeout); + qdf_mem_free(tgt_req); +} + +/** + * wma_fill_hold_req() - fill wma request + * @wma: wma handle + * @vdev_id: vdev id + * @msg_type: message type + * @type: request type + * @params: request params + * @timeout: timeout value + * + * Return: wma_target_req ptr + */ +struct wma_target_req *wma_fill_hold_req(tp_wma_handle wma, + uint8_t vdev_id, + uint32_t msg_type, uint8_t type, + void *params, uint32_t timeout) +{ + struct wma_target_req *req; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return NULL; + + wma_debug("vdev_id %d msg %d type %d", vdev_id, msg_type, type); + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + req->vdev_id = vdev_id; + req->msg_type = msg_type; + req->type = type; + req->user_data = params; + status = qdf_list_insert_back(&wma->wma_hold_req_queue, &req->node); + if (QDF_STATUS_SUCCESS != status) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_err("Failed add request in queue"); + qdf_mem_free(req); + return NULL; + } + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + qdf_mc_timer_init(&req->event_timeout, QDF_TIMER_TYPE_SW, + wma_hold_req_timer, req); + qdf_mc_timer_start(&req->event_timeout, timeout); + return req; +} + +void wma_remove_peer_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type, struct qdf_mac_addr *peer_addr) +{ + struct wma_target_req *req_msg; + + wma_debug("Remove req for vdev: %d type: %d", vdev_id, type); + req_msg = wma_find_req(wma, vdev_id, type, peer_addr); + if (!req_msg) { + wma_err("target req not found for vdev: %d type: %d", + vdev_id, type); + return; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); +} + +/** + * wma_remove_req() - remove request + * @wma: wma handle + * @vdev_id: vdev id + * @type: type + * + * Return: none + */ +void wma_remove_req(tp_wma_handle wma, uint8_t vdev_id, + uint8_t type) +{ + struct wma_target_req *req_msg; + + wma_debug("Remove req for vdev: %d type: %d", vdev_id, type); + req_msg = wma_find_req(wma, vdev_id, type, NULL); + if (!req_msg) { + wma_err("target req not found for vdev: %d type: %d", + vdev_id, type); + return; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + qdf_mem_free(req_msg); +} + +#define MAX_VDEV_SET_BSS_PARAMS 5 +/* params being sent: + * 1.wmi_vdev_param_beacon_interval + * 2.wmi_vdev_param_dtim_period + * 3.wmi_vdev_param_tx_pwrlimit + * 4.wmi_vdev_param_slot_time + * 5.wmi_vdev_param_protection_mode + */ + +/** + * wma_vdev_set_bss_params() - BSS set params functions + * @wma: wma handle + * @vdev_id: vdev id + * @beaconInterval: beacon interval + * @dtimPeriod: DTIM period + * @shortSlotTimeSupported: short slot time + * @llbCoexist: llbCoexist + * @maxTxPower: max tx power + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_vdev_set_bss_params(tp_wma_handle wma, int vdev_id, + tSirMacBeaconInterval beaconInterval, + uint8_t dtimPeriod, uint8_t shortSlotTimeSupported, + uint8_t llbCoexist, int8_t maxTxPower) +{ + uint32_t slot_time; + struct wma_txrx_node *intr = wma->interfaces; + struct dev_set_param setparam[MAX_VDEV_SET_BSS_PARAMS]; + uint8_t index = 0; + enum ieee80211_protmode prot_mode; + uint32_t keep_alive_period; + QDF_STATUS ret; + + ret = QDF_STATUS_E_FAILURE; + /* Beacon Interval setting */ + ret = mlme_check_index_setparam(setparam, + wmi_vdev_param_beacon_interval, + beaconInterval, index++, + MAX_VDEV_SET_BSS_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to send wmi_vdev_param_beacon_interval to fw"); + goto error; + } + + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, vdev_id, + &intr[vdev_id].config.gtx_info); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("failed to set vdev gtx cfg"); + goto error; + } + ret = mlme_check_index_setparam(setparam, wmi_vdev_param_dtim_period, + dtimPeriod, index++, + MAX_VDEV_SET_BSS_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to send wmi_vdev_param_dtim_period fw"); + goto error; + } + intr[vdev_id].dtimPeriod = dtimPeriod; + + if (!wlan_reg_is_ext_tpc_supported(wma->psoc)) { + if (!maxTxPower) + wma_warn("Setting Tx power limit to 0"); + + wma_nofl_debug("TXP[W][set_bss_params]: %d", maxTxPower); + + if (maxTxPower != INVALID_TXPOWER) { + ret = mlme_check_index_setparam( + setparam, + wmi_vdev_param_tx_pwrlimit, + maxTxPower, index++, + MAX_VDEV_SET_BSS_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to send wmi_vdev_param_tx_pwrlimit to fw"); + goto error; + } + } else { + wma_err("Invalid max Tx power"); + } + } + /* Slot time */ + if (shortSlotTimeSupported) + slot_time = WMI_VDEV_SLOT_TIME_SHORT; + else + slot_time = WMI_VDEV_SLOT_TIME_LONG; + ret = mlme_check_index_setparam(setparam, wmi_vdev_param_slot_time, + slot_time, index++, + MAX_VDEV_SET_BSS_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to send wmi_vdev_param_slot_time to fw"); + goto error; + } + /* Initialize protection mode in case of coexistence */ + prot_mode = llbCoexist ? IEEE80211_PROT_CTSONLY : IEEE80211_PROT_NONE; + ret = mlme_check_index_setparam(setparam, + wmi_vdev_param_protection_mode, + prot_mode, index++, + MAX_VDEV_SET_BSS_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to send wmi_vdev_param_protection_mode to fw"); + goto error; + } + ret = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Failed to set BEACON/DTIM_PERIOD/PWRLIMIT/SLOTTIME/PROTECTION params"); + goto error; + } + mlme_set_max_reg_power(intr[vdev_id].vdev, maxTxPower); + wlan_mlme_get_sta_keep_alive_period(wma->psoc, + &keep_alive_period); + wma_set_sta_keep_alive( + wma, vdev_id, + SIR_KEEP_ALIVE_NULL_PKT, + keep_alive_period, + NULL, NULL, NULL); +error: + return ret; +} + +static void wma_set_mgmt_frame_protection(tp_wma_handle wma) +{ + struct pdev_params param = {0}; + QDF_STATUS ret; + + /* + * when 802.11w PMF is enabled for hw encr/decr + * use hw MFP Qos bits 0x10 + */ + param.param_id = wmi_pdev_param_pmf_qos; + param.param_value = true; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + ¶m, WMA_WILDCARD_PDEV_ID); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Failed to set QOS MFP/PMF (%d)", ret); + } else { + wma_debug("QOS MFP/PMF set"); + } +} + +/** + * wma_set_peer_pmf_status() - Get the peer and update PMF capability of it + * @wma: wma handle + * @peer_mac: peer mac addr + * @is_pmf_enabled: Carries the status whether PMF is enabled or not + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_set_peer_pmf_status(tp_wma_handle wma, uint8_t *peer_mac, + bool is_pmf_enabled) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + wma_err("Peer of peer_mac "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(peer_mac)); + return QDF_STATUS_E_INVAL; + } + mlme_set_peer_pmf_status(peer, is_pmf_enabled); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + wma_debug("set is_pmf_enabled %d for "QDF_MAC_ADDR_FMT, + is_pmf_enabled, QDF_MAC_ADDR_REF(peer_mac)); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_pre_vdev_start_setup(uint8_t vdev_id, + struct bss_params *add_bss) +{ + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wma_txrx_node *iface; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct vdev_mlme_obj *mlme_obj; + uint8_t *mac_addr; + + if (!soc || !wma) + return QDF_STATUS_E_FAILURE; + + iface = &wma->interfaces[vdev_id]; + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!mlme_obj) { + wma_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wma_set_bss_rate_flags(wma, vdev_id, add_bss); + if (wlan_vdev_mlme_get_opmode(iface->vdev) == QDF_NDI_MODE || + wlan_vdev_mlme_get_opmode(iface->vdev) == QDF_IBSS_MODE) + mac_addr = mlme_obj->mgmt.generic.bssid; + else + mac_addr = wlan_vdev_mlme_get_macaddr(iface->vdev); + + status = wma_create_peer(wma, mac_addr, + WMI_PEER_TYPE_DEFAULT, vdev_id, + NULL, false); + if (status != QDF_STATUS_SUCCESS) { + wma_err("Failed to create peer"); + return status; + } + + if (!cdp_find_peer_exist(soc, OL_TXRX_PDEV_ID, mac_addr)) { + wma_err("Failed to find peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr)); + return QDF_STATUS_E_FAILURE; + } + + iface->rmfEnabled = add_bss->rmfEnabled; + if (add_bss->rmfEnabled) + wma_set_mgmt_frame_protection(wma); + + return status; +} + +QDF_STATUS wma_post_vdev_start_setup(uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *intr; + struct vdev_mlme_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev; + uint8_t bss_power = 0; + + if (!wma) + return QDF_STATUS_E_FAILURE; + + intr = &wma->interfaces[vdev_id]; + if (!intr) { + wma_err("Invalid interface"); + return QDF_STATUS_E_FAILURE; + } + vdev = intr->vdev; + if (!vdev) { + wma_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + if (wlan_vdev_mlme_get_opmode(vdev) == QDF_NDI_MODE || + wlan_vdev_mlme_get_opmode(vdev) == QDF_IBSS_MODE) { + /* Initialize protection mode to no protection */ + wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_protection_mode, + IEEE80211_PROT_NONE); + return status; + } + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Fill bss_chan after vdev start */ + qdf_mem_copy(vdev->vdev_mlme.bss_chan, + vdev->vdev_mlme.des_chan, + sizeof(struct wlan_channel)); + + if (!wlan_reg_is_ext_tpc_supported(wma->psoc)) + bss_power = wlan_reg_get_channel_reg_power_for_freq( + wma->pdev, vdev->vdev_mlme.bss_chan->ch_freq); + + if (wma_vdev_set_bss_params(wma, vdev_id, + mlme_obj->proto.generic.beacon_interval, + mlme_obj->proto.generic.dtim_period, + mlme_obj->proto.generic.slot_time, + mlme_obj->proto.generic.protection_mode, + bss_power)) { + wma_err("Failed to set wma_vdev_set_bss_params"); + } + + wma_vdev_set_he_bss_params(wma, vdev_id, + &mlme_obj->proto.he_ops_info); +#if defined(WLAN_FEATURE_11BE) + wma_vdev_set_eht_bss_params(wma, vdev_id, + &mlme_obj->proto.eht_ops_info); +#endif + + return status; +} + +static QDF_STATUS wma_update_iface_params(tp_wma_handle wma, + struct bss_params *add_bss) +{ + struct wma_txrx_node *iface; + uint8_t vdev_id; + + vdev_id = add_bss->staContext.smesessionId; + iface = &wma->interfaces[vdev_id]; + wma_set_bss_rate_flags(wma, vdev_id, add_bss); + + if (iface->addBssStaContext) + qdf_mem_free(iface->addBssStaContext); + iface->addBssStaContext = qdf_mem_malloc(sizeof(tAddStaParams)); + if (!iface->addBssStaContext) + return QDF_STATUS_E_RESOURCES; + + *iface->addBssStaContext = add_bss->staContext; + /* Save parameters later needed by WMA_ADD_STA_REQ */ + iface->rmfEnabled = add_bss->rmfEnabled; + if (add_bss->rmfEnabled) + wma_set_peer_pmf_status(wma, add_bss->bssId, true); + iface->beaconInterval = add_bss->beaconInterval; + iface->llbCoexist = add_bss->llbCoexist; + iface->shortSlotTimeSupported = add_bss->shortSlotTimeSupported; + iface->nwType = add_bss->nwType; + iface->bss_max_idle_period = add_bss->bss_max_idle_period; + + return QDF_STATUS_SUCCESS; +} + +static inline +bool wma_cdp_find_peer_by_addr(uint8_t *peer_addr) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t pdev_id = OL_TXRX_PDEV_ID; + + if (!soc || pdev_id == OL_TXRX_INVALID_PDEV_ID) { + wma_err("Failed to get pdev/soc"); + return NULL; + } + + return cdp_find_peer_exist(soc, pdev_id, peer_addr); +} + +static +QDF_STATUS wma_save_bss_params(tp_wma_handle wma, struct bss_params *add_bss) +{ + QDF_STATUS status; + + wma_vdev_set_he_config(wma, add_bss->staContext.smesessionId, add_bss); + if (!wma_cdp_find_peer_by_addr(add_bss->bssId)) + status = QDF_STATUS_E_FAILURE; + else + status = QDF_STATUS_SUCCESS; + qdf_mem_copy(add_bss->staContext.staMac, add_bss->bssId, + sizeof(add_bss->staContext.staMac)); + + wma_debug("update_bss %d nw_type %d bssid "QDF_MAC_ADDR_FMT" status %d", + add_bss->updateBss, add_bss->nwType, + QDF_MAC_ADDR_REF(add_bss->bssId), + status); + + return status; +} + +QDF_STATUS wma_pre_assoc_req(struct bss_params *add_bss) +{ + QDF_STATUS status; + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_INVAL; + + status = wma_update_iface_params(wma, add_bss); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + status = wma_save_bss_params(wma, add_bss); + + return status; +} + +void wma_add_bss_lfr3(tp_wma_handle wma, struct bss_params *add_bss) +{ + QDF_STATUS status; + + status = wma_update_iface_params(wma, add_bss); + if (QDF_IS_STATUS_ERROR(status)) + return; + + if (!wma_cdp_find_peer_by_addr(add_bss->bssId)) { + wma_err("Failed to find peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_bss->bssId)); + return; + } + wma_debug("LFR3: bssid "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_bss->bssId)); +} + + +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || defined(QCA_LL_TX_FLOW_CONTROL_V2) +static +QDF_STATUS wma_set_cdp_vdev_pause_reason(tp_wma_handle wma, uint8_t vdev_id) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + cdp_fc_vdev_pause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_PEER_UNAUTHORIZED, 0); + + return QDF_STATUS_SUCCESS; +} +#else +static inline +QDF_STATUS wma_set_cdp_vdev_pause_reason(tp_wma_handle wma, uint8_t vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +void wma_send_add_bss_resp(tp_wma_handle wma, uint8_t vdev_id, + QDF_STATUS status) +{ + struct add_bss_rsp *add_bss_rsp; + + add_bss_rsp = qdf_mem_malloc(sizeof(*add_bss_rsp)); + if (!add_bss_rsp) + return; + + add_bss_rsp->vdev_id = vdev_id; + add_bss_rsp->status = status; + lim_handle_add_bss_rsp(wma->mac_context, add_bss_rsp); +} + +#ifdef WLAN_FEATURE_HOST_ROAM +QDF_STATUS wma_add_bss_lfr2_vdev_start(struct wlan_objmgr_vdev *vdev, + struct bss_params *add_bss) +{ + tp_wma_handle wma; + QDF_STATUS status; + struct vdev_mlme_obj *mlme_obj; + uint8_t vdev_id; + bool peer_exist = false; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma || !vdev) { + wma_err("Invalid wma or vdev"); + return QDF_STATUS_E_INVAL; + } + + vdev_id = vdev->vdev_objmgr.vdev_id; + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + status = wma_update_iface_params(wma, add_bss); + if (QDF_IS_STATUS_ERROR(status)) + goto send_fail_resp; + + peer_exist = wma_cdp_find_peer_by_addr(mlme_obj->mgmt.generic.bssid); + if (!peer_exist) { + wma_err("Failed to find peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mlme_obj->mgmt.generic.bssid)); + goto send_fail_resp; + } + + status = wma_vdev_pre_start(vdev_id, false); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed, status: %d", status); + goto peer_cleanup; + } + status = vdev_mgr_start_send(mlme_obj, false); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed, status: %d", status); + goto peer_cleanup; + } + status = wma_set_cdp_vdev_pause_reason(wma, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + goto peer_cleanup; + + /* ADD_BSS_RESP will be deferred to completion of VDEV_START */ + return QDF_STATUS_SUCCESS; + +peer_cleanup: + if (peer_exist) + wma_remove_peer(wma, mlme_obj->mgmt.generic.bssid, vdev_id, + false); + +send_fail_resp: + wma_send_add_bss_resp(wma, vdev_id, QDF_STATUS_E_FAILURE); + + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wma_set_vdev_bw(uint8_t vdev_id, uint8_t bw) +{ + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_INVAL; + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_chwidth, bw); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set vdev bw, status: %d", status); + + return status; +} + +QDF_STATUS wma_send_peer_assoc_req(struct bss_params *add_bss) +{ + struct wma_target_req *msg; + tp_wma_handle wma; + uint8_t vdev_id; + bool peer_exist; + QDF_STATUS status; + struct wma_txrx_node *iface; + int pps_val = 0; + struct vdev_mlme_obj *mlme_obj; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma || !mac || !soc) + return QDF_STATUS_E_INVAL; + + vdev_id = add_bss->staContext.smesessionId; + + iface = &wma->interfaces[vdev_id]; + status = wma_update_iface_params(wma, add_bss); + if (QDF_IS_STATUS_ERROR(status)) + goto send_resp; + + peer_exist = wma_cdp_find_peer_by_addr(add_bss->bssId); + if (add_bss->nonRoamReassoc && peer_exist) + goto send_resp; + + if (!add_bss->updateBss) + goto send_resp; + + if (!peer_exist) { + wma_err("Failed to find peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_bss->bssId)); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + + + if (add_bss->staContext.encryptType == eSIR_ED_NONE) { + wma_debug("Update peer("QDF_MAC_ADDR_FMT") state into auth", + QDF_MAC_ADDR_REF(add_bss->bssId)); + cdp_peer_state_update(soc, add_bss->bssId, + OL_TXRX_PEER_STATE_AUTH); + } else { + wma_debug("Update peer("QDF_MAC_ADDR_FMT") state into conn", + QDF_MAC_ADDR_REF(add_bss->bssId)); + cdp_peer_state_update(soc, add_bss->bssId, + OL_TXRX_PEER_STATE_CONN); + status = wma_set_cdp_vdev_pause_reason(wma, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + goto send_resp; + } + + wmi_unified_send_txbf(wma, &add_bss->staContext); + + pps_val = ((mac->mlme_cfg->sta.enable_5g_ebt << 31) & + 0xffff0000) | (PKT_PWR_SAVE_5G_EBT & 0xffff); + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_packet_powersave, + pps_val); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send wmi packet power save cmd"); + else + wma_debug("Sent packet power save %x", pps_val); + + add_bss->staContext.no_ptk_4_way = add_bss->no_ptk_4_way; + + status = wma_send_peer_assoc(wma, add_bss->nwType, + &add_bss->staContext); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send peer assoc status:%d", status); + goto send_resp; + } + + /* we just had peer assoc, so install key will be done later */ + if (add_bss->staContext.encryptType != eSIR_ED_NONE) + iface->is_waiting_for_key = true; + + if (add_bss->rmfEnabled) + wma_set_mgmt_frame_protection(wma); + + if (wlan_reg_is_ext_tpc_supported(wma->psoc)) + add_bss->maxTxPower = 0; + + if (wma_vdev_set_bss_params(wma, add_bss->staContext.smesessionId, + add_bss->beaconInterval, + add_bss->dtimPeriod, + add_bss->shortSlotTimeSupported, + add_bss->llbCoexist, + add_bss->maxTxPower)) { + wma_err("Failed to set bss params"); + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!mlme_obj) { + wma_err("Failed to mlme obj"); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + /* + * Store the bssid in interface table, bssid will + * be used during group key setting sta mode. + */ + qdf_mem_copy(mlme_obj->mgmt.generic.bssid, + add_bss->bssId, QDF_MAC_ADDR_SIZE); + + wma_save_bss_params(wma, add_bss); + + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + wma_debug("WMI_SERVICE_PEER_ASSOC_CONF not enabled"); + goto send_resp; + } + + msg = wma_fill_hold_req(wma, vdev_id, WMA_ADD_BSS_REQ, + WMA_PEER_ASSOC_CNF_START, NULL, + WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + wma_err("Failed to allocate request for vdev_id %d", vdev_id); + wma_remove_req(wma, vdev_id, WMA_PEER_ASSOC_CNF_START); + status = QDF_STATUS_E_FAILURE; + goto send_resp; + } + + return QDF_STATUS_SUCCESS; + +send_resp: + wma_send_add_bss_resp(wma, vdev_id, status); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wma_get_mld_info_ap() - get mld mac addr and assoc peer flag for ap + * @add_sta: tpAddStaParams + * @peer_mld_addr: peer mld mac addr + * @is_assoc_peer: is assoc peer or not + * + * Return: void + */ +static void wma_get_mld_info_ap(tpAddStaParams add_sta, + uint8_t **peer_mld_addr, + bool *is_assoc_peer) +{ + if (add_sta) { + *peer_mld_addr = add_sta->mld_mac_addr; + *is_assoc_peer = add_sta->is_assoc_peer; + } else { + peer_mld_addr = NULL; + *is_assoc_peer = false; + } +} + +static inline QDF_STATUS +wma_check_for_mlo_peer_conflict(struct wlan_mlo_peer_context *peer_1, + struct wlan_mlo_peer_context *peer_2) +{ + if (!peer_1 && !peer_2) + return QDF_STATUS_SUCCESS; + + if (!peer_2) { + wma_err("ML-peer with same mac address exists for a different AID"); + return QDF_STATUS_E_ALREADY; + } else if (peer_1 == peer_2) { + return QDF_STATUS_SUCCESS; + } + + /* Two ML-peers exists with different AID */ + QDF_ASSERT(0); + + return QDF_STATUS_E_FAILURE; +} + +static QDF_STATUS +wma_validate_mac_for_conflict_on_same_ml_ctx(tp_wma_handle wma, + tpAddStaParams add_sta, + uint8_t *peer_mld) +{ + struct wlan_objmgr_vdev *vdev = NULL; + struct wlan_mlo_peer_context *ml_peer, *tmp_ml_peer; + struct qdf_mac_addr sta_addr = {0}; + struct wlan_objmgr_peer *peer; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + add_sta->smesessionId, + WLAN_LEGACY_WMA_ID); + if (!vdev) + return QDF_STATUS_E_FAILURE; + + /* Not an ML-SAP, therefore skip the validation */ + if (!vdev->mlo_dev_ctx) + goto release_ref; + + qdf_mem_copy(&sta_addr.bytes[0], add_sta->staMac, + sizeof(tSirMacAddr)); + + ml_peer = wlan_mlo_get_mlpeer(vdev->mlo_dev_ctx, + &sta_addr); + /* + * ML-peer exists on the ML-dev with same address. + * If the AID is different, then another ML-STA + * is already associated to this SAP using the + * same MLD mac + */ + if (ml_peer) { + tmp_ml_peer = wlan_mlo_get_mlpeer_by_aid(vdev->mlo_dev_ctx, + add_sta->assocId); + + status = wma_check_for_mlo_peer_conflict(ml_peer, tmp_ml_peer); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Link mac address conflicts with another MLO peer on same interface"); + goto release_ref; + } + } + + /* + * ML-peer exists on the ML-dev with same MLD address. + * If the AID is different, reject the peer create + */ + ml_peer = wlan_mlo_get_mlpeer(vdev->mlo_dev_ctx, + (struct qdf_mac_addr *)peer_mld); + if (ml_peer) { + tmp_ml_peer = wlan_mlo_get_mlpeer_by_aid(vdev->mlo_dev_ctx, + add_sta->assocId); + status = wma_check_for_mlo_peer_conflict(ml_peer, tmp_ml_peer); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("MLD mac address conflicts with another MLO peer on same interface"); + goto release_ref; + } + } + + /* + * If the link address of another ML-peer(with different AID) matches + * with the MLD address of the incoming peer, reject the peer create. + * + * Note: Legacy MLD mac - link mac conflict is taken care at + * wma_create_peer_validate_mld_address() + */ + peer = wlan_objmgr_get_peer_by_mac(wma->psoc, peer_mld, + WLAN_LEGACY_WMA_ID); + if (!peer) { + goto release_ref; + } else { + if (peer->mlo_peer_ctx && + peer->mlo_peer_ctx->assoc_id != add_sta->assocId) { + wma_err("MLD mac address conflicts with link mac address of another ML-peer on same interface"); + status = QDF_STATUS_E_FAILURE; + } + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + } + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + return status; +} +#else +static void wma_get_mld_info_ap(tpAddStaParams add_sta, + uint8_t **peer_mld_addr, + bool *is_assoc_peer) +{ + *peer_mld_addr = NULL; + *is_assoc_peer = false; +} + +static QDF_STATUS +wma_validate_mac_for_conflict_on_same_ml_ctx(tp_wma_handle wma, + tpAddStaParams add_sta, + uint8_t *peer_mld) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_add_sta_req_ap_mode() - process add sta request in ap mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_sta_req_ap_mode(tp_wma_handle wma, tpAddStaParams add_sta) +{ + enum ol_txrx_peer_state state = OL_TXRX_PEER_STATE_CONN; + uint8_t pdev_id = OL_TXRX_PDEV_ID; + QDF_STATUS status; + int32_t ret; + struct wma_txrx_node *iface = NULL; + struct wma_target_req *msg = NULL; + bool peer_assoc_cnf = false; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t i, j; + uint16_t mcs_limit; + uint8_t *rate_pos; + struct mac_context *mac = wma->mac_context; + uint8_t *peer_mld_addr = NULL; + bool is_assoc_peer = false; + + /* UMAC sends WMA_ADD_STA_REQ msg twice to WMA when the station + * associates. First WMA_ADD_STA_REQ will have staType as + * STA_ENTRY_PEER and second posting will have STA_ENTRY_SELF. + * Peer creation is done in first WMA_ADD_STA_REQ and second + * WMA_ADD_STA_REQ which has STA_ENTRY_SELF is ignored and + * send fake response with success to UMAC. Otherwise UMAC + * will get blocked. + */ + if (add_sta->staType != STA_ENTRY_PEER) { + add_sta->status = QDF_STATUS_SUCCESS; + goto send_rsp; + } + + iface = &wma->interfaces[add_sta->smesessionId]; + + if (cdp_find_peer_exist_on_vdev(soc, add_sta->smesessionId, + add_sta->staMac)) { + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + false); + wma_err("Peer already exists, Deleted peer with peer_addr "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + } + /* The code above only checks the peer existence on its own vdev. + * Need to check whether the peer exists on other vDevs because firmware + * can't create the peer if the peer with same MAC address already + * exists on the pDev. As this peer belongs to other vDevs, just return + * here. + */ + if (cdp_find_peer_exist(soc, pdev_id, add_sta->staMac)) { + wma_err("My vdev id %d, but Peer exists on other vdev with peer_addr "QDF_MAC_ADDR_FMT, + add_sta->smesessionId, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = QDF_STATUS_E_FAILURE; + goto send_rsp; + } + + wma_delete_invalid_peer_entries(add_sta->smesessionId, add_sta->staMac); + + wma_get_mld_info_ap(add_sta, &peer_mld_addr, &is_assoc_peer); + + status = wma_validate_mac_for_conflict_on_same_ml_ctx(wma, add_sta, + peer_mld_addr); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Conflict detected with mac address, peer create failed"); + add_sta->status = status; + goto send_rsp; + } + + status = wma_create_peer(wma, add_sta->staMac, WMI_PEER_TYPE_DEFAULT, + add_sta->smesessionId, peer_mld_addr, + is_assoc_peer); + if (status != QDF_STATUS_SUCCESS) { + wma_err("Failed to create peer for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = status; + goto send_rsp; + } + + if (!cdp_find_peer_exist_on_vdev(soc, add_sta->smesessionId, + add_sta->staMac)) { + wma_err("Failed to find peer handle using peer mac "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + false); + goto send_rsp; + } + + wmi_unified_send_txbf(wma, add_sta); + + /* + * Get MCS limit from ini configure, and map it to rate parameters + * This will limit HT rate upper bound. CFG_CTRL_MASK is used to + * check whether ini config is enabled and CFG_DATA_MASK to get the + * MCS value. + */ +#define CFG_CTRL_MASK 0xFF00 +#define CFG_DATA_MASK 0x00FF + + mcs_limit = mac->mlme_cfg->rates.sap_max_mcs_txdata; + + if (mcs_limit & CFG_CTRL_MASK) { + wma_debug("set mcs_limit %x", mcs_limit); + + mcs_limit &= CFG_DATA_MASK; + rate_pos = (u_int8_t *)add_sta->supportedRates.supportedMCSSet; + for (i = 0, j = 0; i < MAX_SUPPORTED_RATES;) { + if (j < mcs_limit / 8) { + rate_pos[j] = 0xff; + j++; + i += 8; + } else if (j < mcs_limit / 8 + 1) { + if (i <= mcs_limit) + rate_pos[i / 8] |= 1 << (i % 8); + else + rate_pos[i / 8] &= ~(1 << (i % 8)); + i++; + + if (i >= (j + 1) * 8) + j++; + } else { + rate_pos[j++] = 0; + i += 8; + } + } + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, add_sta->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + add_sta, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + wma_err("Failed to alloc request for vdev_id %d", + add_sta->smesessionId); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + wma_err("WMI_SERVICE_PEER_ASSOC_CONF not enabled"); + } + + ret = wma_send_peer_assoc(wma, add_sta->nwType, add_sta); + if (ret) { + add_sta->status = QDF_STATUS_E_FAILURE; + if (msg) { + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + peer_assoc_cnf = false; + } + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + false); + goto send_rsp; + } + + if (add_sta->rmfEnabled) + wma_set_peer_pmf_status(wma, add_sta->staMac, true); + + if (add_sta->uAPSD) { + status = wma_set_ap_peer_uapsd(wma, add_sta->smesessionId, + add_sta->staMac, + add_sta->uAPSD, add_sta->maxSPLen); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to set peer uapsd param for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, false); + goto send_rsp; + } + } + + wma_debug("Moving peer "QDF_MAC_ADDR_FMT" to state %d", + QDF_MAC_ADDR_REF(add_sta->staMac), state); + cdp_peer_state_update(soc, add_sta->staMac, state); + + add_sta->nss = wma_objmgr_get_peer_mlme_nss(wma, add_sta->staMac); + add_sta->status = QDF_STATUS_SUCCESS; +send_rsp: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) { + wma_debug("WMI_SERVICE_PEER_ASSOC_CONF is enabled"); + return; + } + + wma_debug("statype %d vdev_id %d aid %d bssid "QDF_MAC_ADDR_FMT" status %d", + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, QDF_MAC_ADDR_REF(add_sta->bssId), + add_sta->status); + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} + +#ifdef FEATURE_WLAN_TDLS + +/** + * wma_add_tdls_sta() - process add sta request in TDLS mode + * @wma: wma handle + * @add_sta: add sta params + * + * Return: none + */ +static void wma_add_tdls_sta(tp_wma_handle wma, tpAddStaParams add_sta) +{ + QDF_STATUS status; + int32_t ret; + struct tdls_peer_update_state *peer_state; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t pdev_id = OL_TXRX_PDEV_ID; + struct wma_txrx_node *iface = &wma->interfaces[add_sta->smesessionId]; + + wma_debug("staType: %d, updateSta: %d, bssId: "QDF_MAC_ADDR_FMT", staMac: "QDF_MAC_ADDR_FMT, + add_sta->staType, + add_sta->updateSta, QDF_MAC_ADDR_REF(add_sta->bssId), + QDF_MAC_ADDR_REF(add_sta->staMac)); + + if (iface->vdev && wlan_cm_is_vdev_roaming(iface->vdev)) { + wma_err("Vdev %d roaming in progress, reject add sta!", + add_sta->smesessionId); + add_sta->status = QDF_STATUS_E_PERM; + goto send_rsp; + } + + if (0 == add_sta->updateSta) { + /* its a add sta request * */ + + cdp_peer_copy_mac_addr_raw(soc, add_sta->smesessionId, + add_sta->bssId); + + wma_debug("addSta, calling wma_create_peer for "QDF_MAC_ADDR_FMT", vdev_id %hu", + QDF_MAC_ADDR_REF(add_sta->staMac), + add_sta->smesessionId); + + status = wma_create_peer(wma, add_sta->staMac, + WMI_PEER_TYPE_TDLS, + add_sta->smesessionId, NULL, false); + if (status != QDF_STATUS_SUCCESS) { + wma_err("Failed to create peer for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = status; + goto send_rsp; + } + + wma_debug("addSta, after calling cdp_local_peer_id, staMac: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + + peer_state = qdf_mem_malloc(sizeof(*peer_state)); + if (!peer_state) { + add_sta->status = QDF_STATUS_E_NOMEM; + goto send_rsp; + } + + peer_state->peer_state = WMI_TDLS_PEER_STATE_PEERING; + peer_state->vdev_id = add_sta->smesessionId; + qdf_mem_copy(&peer_state->peer_macaddr, + &add_sta->staMac, sizeof(tSirMacAddr)); + wma_update_tdls_peer_state(wma, peer_state); + } else { + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + wma_err("WMI_SERVICE_PEER_ASSOC_CONF is enabled"); + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, add_sta->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + add_sta, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + wma_err("Failed to alloc request for vdev_id %d", + add_sta->smesessionId); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, false); + peer_assoc_cnf = false; + goto send_rsp; + } + } else { + wma_err("WMI_SERVICE_PEER_ASSOC_CONF not enabled"); + } + + wma_debug("changeSta, calling wma_send_peer_assoc"); + if (add_sta->rmfEnabled) + wma_set_peer_pmf_status(wma, add_sta->staMac, true); + + ret = + wma_send_peer_assoc(wma, add_sta->nwType, add_sta); + if (ret) { + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, + add_sta->smesessionId, false); + cdp_peer_add_last_real_peer(soc, pdev_id, + add_sta->smesessionId); + wma_remove_req(wma, add_sta->smesessionId, + WMA_PEER_ASSOC_CNF_START); + peer_assoc_cnf = false; + + goto send_rsp; + } + } + +send_rsp: + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + wma_debug("statype %d vdev_id %d aid %d bssid "QDF_MAC_ADDR_FMT" status %d", + add_sta->staType, add_sta->smesessionId, + add_sta->assocId, QDF_MAC_ADDR_REF(add_sta->bssId), + add_sta->status); + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); +} +#endif + +/** + * wma_send_bss_color_change_enable() - send bss color change enable cmd. + * @wma: wma handle + * @params: add sta params + * + * Send bss color change command to firmware, to enable firmware to update + * internally if any change in bss color in advertised by associated AP. + * + * Return: none + */ +#ifdef WLAN_FEATURE_11AX +static void wma_send_bss_color_change_enable(tp_wma_handle wma, + tpAddStaParams params) +{ + QDF_STATUS status; + uint32_t vdev_id = params->smesessionId; + + if (!params->he_capable) { + wma_debug("he_capable is not set for vdev_id:%d", vdev_id); + return; + } + + status = wmi_unified_send_bss_color_change_enable_cmd(wma->wmi_handle, + vdev_id, + true); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to enable bss color change offload, vdev:%d", + vdev_id); + } + + return; +} +#else +static void wma_send_bss_color_change_enable(tp_wma_handle wma, + tpAddStaParams params) +{ +} +#endif + +#define MAX_VDEV_STA_REQ_PARAMS 5 +/* params being sent: + * 1.wmi_vdev_param_max_li_of_moddtim + * 2.wmi_vdev_param_max_li_of_moddtim_ms + * 3.wmi_vdev_param_dyndtim_cnt + * 4.wmi_vdev_param_moddtim_cnt + * 5.wmi_vdev_param_moddtim_cnt + */ + +/** + * wma_add_sta_req_sta_mode() - process add sta request in sta mode + * @wma: wma handle + * @params: add sta params + * + * Return: none + */ +static void wma_add_sta_req_sta_mode(tp_wma_handle wma, tpAddStaParams params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wma_txrx_node *iface; + int8_t maxTxPower = 0; + int ret = 0; + struct wma_target_req *msg; + bool peer_assoc_cnf = false; + int smps_param; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct dev_set_param setparam[MAX_VDEV_STA_REQ_PARAMS]; + uint8_t index = 0; + +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_add_tdls_sta(wma, params); + return; + } +#endif + + iface = &wma->interfaces[params->smesessionId]; + if (params->staType != STA_ENTRY_SELF) { + wma_err("unsupported station type %d", params->staType); + goto out; + } + if (params->nonRoamReassoc) { + cdp_peer_state_update(soc, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + goto out; + } + + if (wma_is_vdev_up(params->smesessionId)) { + wma_debug("vdev id %d is already UP for "QDF_MAC_ADDR_FMT, + params->smesessionId, + QDF_MAC_ADDR_REF(params->bssId)); + status = QDF_STATUS_E_FAILURE; + goto out; + } + + if (cdp_peer_state_get(soc, params->smesessionId, + params->bssId, true) == OL_TXRX_PEER_STATE_DISC) { + /* + * This is the case for reassociation. + * peer state update and peer_assoc is required since it + * was not done by WMA_ADD_BSS_REQ. + */ + + /* Update peer state */ + if (params->encryptType == eSIR_ED_NONE) { + wma_debug("Update peer("QDF_MAC_ADDR_FMT") state into auth", + QDF_MAC_ADDR_REF(params->bssId)); + cdp_peer_state_update(soc, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + } else { + wma_debug("Update peer("QDF_MAC_ADDR_FMT") state into conn", + QDF_MAC_ADDR_REF(params->bssId)); + cdp_peer_state_update(soc, params->bssId, + OL_TXRX_PEER_STATE_CONN); + } + + if (wlan_cm_is_roam_sync_in_progress(wma->psoc, + params->smesessionId) || + MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, + params->smesessionId)) { + /* iface->nss = params->nss; */ + /*In LFR2.0, the following operations are performed as + * part of wma_send_peer_assoc. As we are + * skipping this operation, we are just executing the + * following which are useful for LFR3.0 + */ + cdp_peer_state_update(soc, params->bssId, + OL_TXRX_PEER_STATE_AUTH); + qdf_atomic_set(&iface->bss_status, + WMA_BSS_STATUS_STARTED); + iface->aid = params->assocId; + wma_debug("LFR3:statype %d vdev %d aid %d bssid "QDF_MAC_ADDR_FMT, + params->staType, params->smesessionId, + params->assocId, + QDF_MAC_ADDR_REF(params->bssId)); + return; + } + wmi_unified_send_txbf(wma, params); + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_peer_assoc_conf)) { + peer_assoc_cnf = true; + msg = wma_fill_hold_req(wma, params->smesessionId, + WMA_ADD_STA_REQ, WMA_PEER_ASSOC_CNF_START, + params, WMA_PEER_ASSOC_TIMEOUT); + if (!msg) { + wma_debug("Failed to alloc request for vdev_id %d", + params->smesessionId); + params->status = QDF_STATUS_E_FAILURE; + wma_remove_req(wma, params->smesessionId, + WMA_PEER_ASSOC_CNF_START); + wma_remove_peer(wma, params->bssId, + params->smesessionId, false); + peer_assoc_cnf = false; + goto out; + } + } else { + wma_debug("WMI_SERVICE_PEER_ASSOC_CONF not enabled"); + } + + ((tAddStaParams *)iface->addBssStaContext)->no_ptk_4_way = + params->no_ptk_4_way; + + qdf_mem_copy(((tAddStaParams *)iface->addBssStaContext)-> + supportedRates.supportedMCSSet, + params->supportedRates.supportedMCSSet, + SIR_MAC_MAX_SUPPORTED_MCS_SET); + + + ret = wma_send_peer_assoc(wma, + iface->nwType, + (tAddStaParams *) iface->addBssStaContext); + if (ret) { + status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, params->bssId, + params->smesessionId, false); + goto out; + } + + if (params->rmfEnabled) { + wma_set_mgmt_frame_protection(wma); + wma_set_peer_pmf_status(wma, params->bssId, true); + } + } + + if (!wlan_reg_is_ext_tpc_supported(wma->psoc)) + maxTxPower = params->maxTxPower; + + if (wma_vdev_set_bss_params(wma, params->smesessionId, + iface->beaconInterval, iface->dtimPeriod, + iface->shortSlotTimeSupported, + iface->llbCoexist, maxTxPower)) { + wma_err("Failed to bss params"); + } + + params->csaOffloadEnable = 0; + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_csa_offload)) { + params->csaOffloadEnable = 1; + if (wma_unified_csa_offload_enable(wma, params->smesessionId) < + 0) { + wma_err("Unable to enable CSA offload for vdev_id:%d", + params->smesessionId); + } + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_filter_ipsec_natkeepalive)) { + if (wmi_unified_nat_keepalive_en_cmd(wma->wmi_handle, + params->smesessionId)) { + wma_err("Unable to enable NAT keepalive for vdev_id:%d", + params->smesessionId); + } + } + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STARTED); + /* Sta is now associated, configure various params */ + + /* Send SMPS force command to FW to send the required + * action frame only when SM power save is enabled in + * from INI. In case dynamic antenna selection, the + * action frames are sent by the chain mask manager + * In addition to the action frames, The SM power save is + * published in the assoc request HT SMPS IE for both cases. + */ + if ((params->enableHtSmps) && (params->send_smps_action)) { + smps_param = wma_smps_mode_to_force_mode_param( + params->htSmpsconfig); + if (smps_param >= 0) { + wma_debug("Send SMPS force mode: %d", + params->htSmpsconfig); + wma_set_mimops(wma, params->smesessionId, + smps_param); + } + } + + wma_send_bss_color_change_enable(wma, params); + + /* Partial AID match power save, enable when SU bformee */ + if (params->enableVhtpAid && params->vhtTxBFCapable) + wma_set_ppsconfig(params->smesessionId, + WMA_VHT_PPS_PAID_MATCH, 1); + + /* Enable AMPDU power save, if htCapable/vhtCapable */ + if (params->enableAmpduPs && (params->htCapable || params->vhtCapable)) + wma_set_ppsconfig(params->smesessionId, + WMA_VHT_PPS_DELIM_CRC_FAIL, 1); + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_listen_interval_offload_support)) { + struct wlan_objmgr_vdev *vdev = NULL; + uint32_t moddtim; + bool is_connection_roaming_cfg_set = 0; + + wma_debug("listen interval offload enabled, setting params"); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_max_li_of_moddtim, + wma->staMaxLIModDtim, index++, + MAX_VDEV_STA_REQ_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to send wmi_vdev_param_max_li_of_moddtim"); + goto out; + } + + ucfg_mlme_get_connection_roaming_ini_present( + wma->psoc, + &is_connection_roaming_cfg_set); + if (is_connection_roaming_cfg_set) { + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_max_li_of_moddtim_ms, + wma->sta_max_li_mod_dtim_ms, index++, + MAX_VDEV_STA_REQ_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to send wmi_vdev_param_max_li_of_moddtim_ms"); + goto out; + } + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_dyndtim_cnt, + wma->staDynamicDtim, index++, + MAX_VDEV_STA_REQ_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to send wmi_vdev_param_dyndtim_cnt"); + goto out; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + params->smesessionId, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_debug("Invalid vdev"); + goto out; + } + + if (!ucfg_pmo_get_moddtim_user_enable(vdev)) { + moddtim = wma->staModDtim; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_moddtim_cnt, + moddtim, index++, + MAX_VDEV_STA_REQ_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to send wmi_vdev_param_moddtim_cnt"); + goto rel_ref; + } + } else if (ucfg_pmo_get_moddtim_user_enable(vdev) && + !ucfg_pmo_get_moddtim_user_active(vdev)) { + moddtim = ucfg_pmo_get_moddtim_user(vdev); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_moddtim_cnt, + moddtim, index++, + MAX_VDEV_STA_REQ_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to send wmi_vdev_param_moddtim_cnt"); + goto rel_ref; + } + } + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + params->smesessionId, + setparam, index); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to send DTIM vdev setparams"); + } +rel_ref: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + + } else { + wma_debug("listen interval offload is not set"); + } + params->nss = iface->nss; +out: + iface->aid = params->assocId; + + /* Do not send add stat resp when peer assoc cnf is enabled */ + if (peer_assoc_cnf) + return; + + params->status = status; + wma_debug("vdev_id %d aid %d sta mac " QDF_MAC_ADDR_FMT " status %d", + params->smesessionId, iface->aid, + QDF_MAC_ADDR_REF(params->bssId), params->status); + + /* Don't send a response during roam sync operation */ + if (!wlan_cm_is_roam_sync_in_progress(wma->psoc, + params->smesessionId) && + !MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, + params->smesessionId)) + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, + (void *)params, 0); +} + +/** + * wma_delete_sta_req_ap_mode() - process delete sta request from UMAC in AP mode + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +static void wma_delete_sta_req_ap_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + struct wma_target_req *msg; + QDF_STATUS qdf_status; + + qdf_status = wma_remove_peer(wma, del_sta->staMac, + del_sta->smesessionId, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("wma_remove_peer failed"); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + del_sta->status = QDF_STATUS_SUCCESS; + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + msg = wma_fill_hold_req(wma, del_sta->smesessionId, + WMA_DELETE_STA_REQ, + WMA_DELETE_STA_RSP_START, del_sta, + WMA_DELETE_STA_TIMEOUT); + if (!msg) { + wma_err("Failed to allocate request. vdev_id %d", + del_sta->smesessionId); + wma_remove_req(wma, del_sta->smesessionId, + WMA_DELETE_STA_RSP_START); + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + + wma_acquire_wakelock(&wma->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); + + return; + } + +send_del_rsp: + if (del_sta->respReqd) { + wma_debug("Sending del rsp to umac (status: %d)", + del_sta->status); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, + (void *)del_sta, 0); + } +} + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_del_tdls_sta() - process delete sta request from UMAC in TDLS + * @wma: wma handle + * @del_sta: delete sta params + * + * Return: none + */ +static void wma_del_tdls_sta(tp_wma_handle wma, tpDeleteStaParams del_sta) +{ + struct tdls_peer_update_state *peer_state; + struct wma_target_req *msg; + int status; + + peer_state = qdf_mem_malloc(sizeof(*peer_state)); + if (!peer_state) { + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + + peer_state->peer_state = TDLS_PEER_STATE_TEARDOWN; + peer_state->vdev_id = del_sta->smesessionId; + peer_state->resp_reqd = del_sta->respReqd; + qdf_mem_copy(&peer_state->peer_macaddr, + &del_sta->staMac, sizeof(tSirMacAddr)); + + wma_debug("sending tdls_peer_state for peer mac: "QDF_MAC_ADDR_FMT", peerState: %d", + QDF_MAC_ADDR_REF(peer_state->peer_macaddr), + peer_state->peer_state); + + status = wma_update_tdls_peer_state(wma, peer_state); + + if (status < 0) { + wma_err("wma_update_tdls_peer_state returned failure"); + del_sta->status = QDF_STATUS_E_FAILURE; + goto send_del_rsp; + } + + if (del_sta->respReqd && + wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + del_sta->status = QDF_STATUS_SUCCESS; + msg = wma_fill_hold_req(wma, + del_sta->smesessionId, + WMA_DELETE_STA_REQ, + WMA_DELETE_STA_RSP_START, del_sta, + WMA_DELETE_STA_TIMEOUT); + if (!msg) { + wma_err("Failed to allocate vdev_id %d", + del_sta->smesessionId); + wma_remove_req(wma, + del_sta->smesessionId, + WMA_DELETE_STA_RSP_START); + del_sta->status = QDF_STATUS_E_NOMEM; + goto send_del_rsp; + } + + wma_acquire_wakelock(&wma->wmi_cmd_rsp_wake_lock, + WMA_FW_RSP_EVENT_WAKE_LOCK_DURATION); + } + + return; + +send_del_rsp: + if (del_sta->respReqd) { + wma_debug("Sending del rsp to umac (status: %d)", + del_sta->status); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, + (void *)del_sta, 0); + } +} +#endif + +/** + * wma_delete_sta_req_sta_mode() - process delete sta request from UMAC + * @wma: wma handle + * @params: delete sta params + * + * Return: none + */ +static void wma_delete_sta_req_sta_mode(tp_wma_handle wma, + tpDeleteStaParams params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wma_txrx_node *iface; + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_listen_interval_offload_support)) { + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + params->smesessionId, + WLAN_LEGACY_WMA_ID); + if (vdev) { + if (ucfg_pmo_get_moddtim_user_enable(vdev)) + ucfg_pmo_set_moddtim_user_enable(vdev, false); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + } + } + + iface = &wma->interfaces[params->smesessionId]; + iface->uapsd_cached_val = 0; +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) { + wma_del_tdls_sta(wma, params); + return; + } +#endif + params->status = status; + if (params->respReqd) { + wma_debug("vdev_id %d status %d", + params->smesessionId, status); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, + (void *)params, 0); + } +} + +static void wma_sap_prevent_runtime_pm(tp_wma_handle wma) +{ + qdf_runtime_pm_prevent_suspend(&wma->sap_prevent_runtime_pm_lock); +} + +static void wma_sap_allow_runtime_pm(tp_wma_handle wma) +{ + qdf_runtime_pm_allow_suspend(&wma->sap_prevent_runtime_pm_lock); +} + +static void wma_ndp_prevent_runtime_pm(tp_wma_handle wma) +{ + qdf_runtime_pm_prevent_suspend(&wma->ndp_prevent_runtime_pm_lock); +} + +static void wma_ndp_allow_runtime_pm(tp_wma_handle wma) +{ + qdf_runtime_pm_allow_suspend(&wma->ndp_prevent_runtime_pm_lock); +} +#ifdef FEATURE_STA_MODE_VOTE_LINK +static bool wma_add_sta_allow_sta_mode_vote_link(uint8_t oper_mode) +{ + if (oper_mode == BSS_OPERATIONAL_MODE_STA && ucfg_ipa_is_enabled()) + return true; + + return false; +} +#else /* !FEATURE_STA_MODE_VOTE_LINK */ +static bool wma_add_sta_allow_sta_mode_vote_link(uint8_t oper_mode) +{ + return false; +} +#endif /* FEATURE_STA_MODE_VOTE_LINK */ + +static bool wma_is_vdev_in_sap_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %hu", vdev_id); + QDF_ASSERT(0); + return false; + } + + if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) && + (intf[vdev_id].sub_type == 0)) + return true; + + return false; +} + +static bool wma_is_vdev_in_go_mode(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wma_txrx_node *intf = wma->interfaces; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %hu", vdev_id); + QDF_ASSERT(0); + return false; + } + + if ((intf[vdev_id].type == WMI_VDEV_TYPE_AP) && + (intf[vdev_id].sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO)) + return true; + + return false; +} + +static void wma_sap_d3_wow_client_connect(tp_wma_handle wma) +{ + uint32_t num_clients; + + num_clients = qdf_atomic_inc_return(&wma->sap_num_clients_connected); + wmi_debug("sap d3 wow %d client connected", num_clients); + if (num_clients == SAP_D3_WOW_MAX_CLIENT_HOLD_WAKE_LOCK) { + wmi_info("max clients connected acquire sap d3 wow wake lock"); + qdf_wake_lock_acquire(&wma->sap_d3_wow_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_SAP_D3_WOW); + } +} + +static void wma_sap_d3_wow_client_disconnect(tp_wma_handle wma) +{ + uint32_t num_clients; + + num_clients = qdf_atomic_dec_return(&wma->sap_num_clients_connected); + wmi_debug("sap d3 wow %d client connected", num_clients); + if (num_clients == SAP_D3_WOW_MAX_CLIENT_RELEASE_WAKE_LOCK) { + wmi_info("max clients disconnected release sap d3 wow wake lock"); + qdf_wake_lock_release(&wma->sap_d3_wow_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_SAP_D3_WOW); + } +} + +static void wma_go_d3_wow_client_connect(tp_wma_handle wma) +{ + uint32_t num_clients; + + num_clients = qdf_atomic_inc_return(&wma->go_num_clients_connected); + wmi_debug("go d3 wow %d client connected", num_clients); + if (num_clients == SAP_D3_WOW_MAX_CLIENT_HOLD_WAKE_LOCK) { + wmi_info("max clients connected acquire go d3 wow wake lock"); + qdf_wake_lock_acquire(&wma->go_d3_wow_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_GO_D3_WOW); + } +} + +static void wma_go_d3_wow_client_disconnect(tp_wma_handle wma) +{ + uint32_t num_clients; + + num_clients = qdf_atomic_dec_return(&wma->go_num_clients_connected); + wmi_debug("go d3 wow %d client connected", num_clients); + if (num_clients == SAP_D3_WOW_MAX_CLIENT_RELEASE_WAKE_LOCK) { + wmi_info("max clients disconnected release go d3 wow wake lock"); + qdf_wake_lock_release(&wma->go_d3_wow_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_GO_D3_WOW); + } +} + +void wma_add_sta(tp_wma_handle wma, tpAddStaParams add_sta) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + void *htc_handle; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = add_sta->smesessionId; + + htc_handle = lmac_get_htc_hdl(wma->psoc); + if (!htc_handle) { + wma_err("HTC handle is NULL"); + return; + } + + wma_debug("Vdev %d BSSID "QDF_MAC_ADDR_FMT, vdev_id, + QDF_MAC_ADDR_REF(add_sta->bssId)); + + if (wma_is_vdev_in_ap_mode(wma, vdev_id)) + oper_mode = BSS_OPERATIONAL_MODE_AP; + + if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, vdev_id)) + oper_mode = BSS_OPERATIONAL_MODE_NDI; + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + wma_add_sta_req_sta_mode(wma, add_sta); + break; + + case BSS_OPERATIONAL_MODE_AP: + wma_add_sta_req_ap_mode(wma, add_sta); + break; + case BSS_OPERATIONAL_MODE_NDI: + status = wma_add_sta_ndi_mode(wma, add_sta); + break; + } + + /* + * not use add_sta after this to avoid use after free + * as it maybe freed. + */ + + /* handle wow for sap with 1 or more peer in same way */ + if (wma_is_vdev_in_sap_mode(wma, vdev_id)) { + bool is_bus_suspend_allowed_in_sap_mode = + (wlan_pmo_get_sap_mode_bus_suspend(wma->psoc) && + wmi_service_enabled(wma->wmi_handle, + wmi_service_sap_connected_d3_wow)); + if (!is_bus_suspend_allowed_in_sap_mode) { + htc_vote_link_up(htc_handle, HTC_LINK_VOTE_SAP_USER_ID); + wmi_info("sap d0 wow"); + } else { + wmi_debug("sap d3 wow"); + wma_sap_d3_wow_client_connect(wma); + } + wma_sap_prevent_runtime_pm(wma); + + return; + } + + /* handle wow for p2pgo with 1 or more peer in same way */ + if (wma_is_vdev_in_go_mode(wma, vdev_id)) { + bool is_bus_suspend_allowed_in_go_mode = + (wlan_pmo_get_go_mode_bus_suspend(wma->psoc) && + wmi_service_enabled(wma->wmi_handle, + wmi_service_go_connected_d3_wow)); + if (!is_bus_suspend_allowed_in_go_mode) { + htc_vote_link_up(htc_handle, HTC_LINK_VOTE_GO_USER_ID); + wmi_info("p2p go d0 wow"); + } else { + wmi_info("p2p go d3 wow"); + wma_go_d3_wow_client_connect(wma); + } + wma_sap_prevent_runtime_pm(wma); + + return; + } + + /* handle wow for nan with 1 or more peer in same way */ + if (BSS_OPERATIONAL_MODE_NDI == oper_mode && + QDF_IS_STATUS_SUCCESS(status)) { + wma_debug("disable runtime pm and vote for link up"); + htc_vote_link_up(htc_handle, HTC_LINK_VOTE_NDP_USER_ID); + wma_ndp_prevent_runtime_pm(wma); + } else if (wma_add_sta_allow_sta_mode_vote_link(oper_mode)) { + wma_debug("vote for link up"); + htc_vote_link_up(htc_handle, HTC_LINK_VOTE_STA_USER_ID); + } +} + +void wma_delete_sta(tp_wma_handle wma, tpDeleteStaParams del_sta) +{ + uint8_t oper_mode = BSS_OPERATIONAL_MODE_STA; + uint8_t vdev_id = del_sta->smesessionId; + bool rsp_requested = del_sta->respReqd; + void *htc_handle; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + htc_handle = lmac_get_htc_hdl(wma->psoc); + if (!htc_handle) { + wma_err("HTC handle is NULL"); + return; + } + + if (wma_is_vdev_in_ap_mode(wma, vdev_id)) + oper_mode = BSS_OPERATIONAL_MODE_AP; + if (del_sta->staType == STA_ENTRY_NDI_PEER) + oper_mode = BSS_OPERATIONAL_MODE_NDI; + + wma_debug("vdev %d oper_mode %d", vdev_id, oper_mode); + + switch (oper_mode) { + case BSS_OPERATIONAL_MODE_STA: + if (wlan_cm_is_roam_sync_in_progress(wma->psoc, vdev_id) || + MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id) || + mlo_is_roaming_in_progress(wma->psoc, vdev_id)) { + wma_debug("LFR3: Del STA on vdev_id %d", vdev_id); + qdf_mem_free(del_sta); + return; + } + wma_delete_sta_req_sta_mode(wma, del_sta); + if (!rsp_requested) + qdf_mem_free(del_sta); + + break; + + case BSS_OPERATIONAL_MODE_AP: + wma_delete_sta_req_ap_mode(wma, del_sta); + /* free the memory here only if sync feature is not enabled */ + if (!rsp_requested && + !wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) + qdf_mem_free(del_sta); + else if (!rsp_requested && + (del_sta->status != QDF_STATUS_SUCCESS)) + qdf_mem_free(del_sta); + break; + case BSS_OPERATIONAL_MODE_NDI: + status = wma_delete_sta_req_ndi_mode(wma, del_sta); + break; + default: + wma_err("Incorrect oper mode %d", oper_mode); + qdf_mem_free(del_sta); + } + + if (wma_is_vdev_in_sap_mode(wma, vdev_id)) { + bool is_bus_suspend_allowed_in_sap_mode = + (wlan_pmo_get_sap_mode_bus_suspend(wma->psoc) && + wmi_service_enabled(wma->wmi_handle, + wmi_service_sap_connected_d3_wow)); + if (!is_bus_suspend_allowed_in_sap_mode) { + htc_vote_link_down(htc_handle, + HTC_LINK_VOTE_SAP_USER_ID); + wmi_info("sap d0 wow"); + } else { + wmi_debug("sap d3 wow"); + wma_sap_d3_wow_client_disconnect(wma); + } + wma_sap_allow_runtime_pm(wma); + + return; + } + + if (wma_is_vdev_in_go_mode(wma, vdev_id)) { + bool is_bus_suspend_allowed_in_go_mode = + (wlan_pmo_get_go_mode_bus_suspend(wma->psoc) && + wmi_service_enabled(wma->wmi_handle, + wmi_service_go_connected_d3_wow)); + if (!is_bus_suspend_allowed_in_go_mode) { + htc_vote_link_down(htc_handle, + HTC_LINK_VOTE_GO_USER_ID); + wmi_info("p2p go d0 wow"); + } else { + wmi_info("p2p go d3 wow"); + wma_go_d3_wow_client_disconnect(wma); + } + wma_sap_allow_runtime_pm(wma); + + return; + } + + if (BSS_OPERATIONAL_MODE_NDI == oper_mode && + QDF_IS_STATUS_SUCCESS(status)) { + wma_debug("allow runtime pm and vote for link down"); + htc_vote_link_down(htc_handle, HTC_LINK_VOTE_NDP_USER_ID); + wma_ndp_allow_runtime_pm(wma); + } else if (wma_add_sta_allow_sta_mode_vote_link(oper_mode)) { + wma_debug("vote for link down"); + htc_vote_link_down(htc_handle, HTC_LINK_VOTE_STA_USER_ID); + } +} + +void wma_delete_bss_ho_fail(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wma_txrx_node *iface; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct vdev_stop_response resp_event; + struct del_bss_resp *vdev_stop_resp; + uint8_t *bssid; + + iface = &wma->interfaces[vdev_id]; + if (!iface) { + wma_err("iface for vdev_id %d is already deleted", vdev_id); + goto fail_del_bss_ho_fail; + } + bssid = wma_get_vdev_bssid(iface->vdev); + if (!bssid) { + wma_err("Invalid bssid"); + status = QDF_STATUS_E_FAILURE; + goto fail_del_bss_ho_fail; + } + qdf_mem_zero(bssid, QDF_MAC_ADDR_SIZE); + + if (iface->psnr_req) { + qdf_mem_free(iface->psnr_req); + iface->psnr_req = NULL; + } + + if (iface->rcpi_req) { + struct sme_rcpi_req *rcpi_req = iface->rcpi_req; + + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + } + + if (iface->roam_scan_stats_req) { + struct sir_roam_scan_stats *roam_scan_stats_req = + iface->roam_scan_stats_req; + + iface->roam_scan_stats_req = NULL; + qdf_mem_free(roam_scan_stats_req); + } + + wma_debug("vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + vdev_id); + cdp_fc_vdev_pause(soc, vdev_id, OL_TXQ_PAUSE_REASON_VDEV_STOP, 0); + wma_vdev_set_pause_bit(vdev_id, PAUSE_TYPE_HOST); + cdp_fc_vdev_flush(soc, vdev_id); + wma_debug("vdev_id: %d, un-pausing tx_ll_queue for VDEV_STOP rsp", + vdev_id); + cdp_fc_vdev_unpause(soc, vdev_id, OL_TXQ_PAUSE_REASON_VDEV_STOP, 0); + wma_vdev_clear_pause_bit(vdev_id, PAUSE_TYPE_HOST); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + wma_debug("(type %d subtype %d) BSS is stopped", + iface->type, iface->sub_type); + + status = mlme_set_vdev_stop_type(iface->vdev, + WMA_DELETE_BSS_HO_FAIL_REQ); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to set wma req msg_type for vdev_id: %d", + vdev_id); + goto fail_del_bss_ho_fail; + } + + /* Try to use the vdev stop response path */ + resp_event.vdev_id = vdev_id; + status = wma_handle_vdev_stop_rsp(wma, &resp_event); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to handle vdev stop rsp for vdev_id %d", + vdev_id); + goto fail_del_bss_ho_fail; + } + + return; + +fail_del_bss_ho_fail: + vdev_stop_resp = qdf_mem_malloc(sizeof(*vdev_stop_resp)); + if (!vdev_stop_resp) + return; + + vdev_stop_resp->vdev_id = vdev_id; + vdev_stop_resp->status = status; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_HO_FAIL_RSP, + (void *)vdev_stop_resp, 0); +} + +/** + * wma_wait_tx_complete() - Wait till tx packets are drained + * @wma: wma handle + * @session_id: vdev id + * + * Return: none + */ +static void wma_wait_tx_complete(tp_wma_handle wma, + uint32_t session_id) +{ + uint8_t max_wait_iterations = 0, delay = 0; + cdp_config_param_type val; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + + if (!wma_is_vdev_valid(session_id)) { + wma_err("Vdev is not valid: %d", session_id); + return; + } + + status = ucfg_mlme_get_delay_before_vdev_stop(wma->psoc, &delay); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to get delay before vdev stop"); + + max_wait_iterations = delay / WMA_TX_Q_RECHECK_TIMER_WAIT; + if (cdp_txrx_get_pdev_param(soc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + CDP_TX_PENDING, &val)) + return; + while (val.cdp_pdev_param_tx_pending && max_wait_iterations) { + wma_warn("Waiting for outstanding packet to drain"); + qdf_wait_for_event_completion(&wma->tx_queue_empty_event, + WMA_TX_Q_RECHECK_TIMER_WAIT); + if (cdp_txrx_get_pdev_param( + soc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + CDP_TX_PENDING, &val)) + return; + max_wait_iterations--; + } +} + +void wma_delete_bss(tp_wma_handle wma, uint8_t vdev_id) +{ + bool peer_exist = false; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint32_t tx_pending = 0; + cdp_config_param_type val; + bool roam_synch_in_progress = false; + struct wma_txrx_node *iface; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct qdf_mac_addr bssid; + struct del_bss_resp *params; + uint8_t *addr, *bssid_addr; + + iface = &wma->interfaces[vdev_id]; + if (!iface || !iface->vdev) { + wma_err("vdev id %d is already deleted", vdev_id); + goto out; + } + + status = wlan_vdev_get_bss_peer_mac(iface->vdev, &bssid); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("vdev id %d : failed to get bssid", vdev_id); + goto out; + } + + addr = wlan_vdev_mlme_get_macaddr(iface->vdev); + if (!addr) { + wma_err("vdev id %d : failed to get macaddr", vdev_id); + goto out; + } + + if (WMA_IS_VDEV_IN_NDI_MODE(wma->interfaces, + vdev_id)) + /* In ndi case, self mac is used to create the self peer */ + peer_exist = wma_cdp_find_peer_by_addr(addr); + else + peer_exist = wma_cdp_find_peer_by_addr(bssid.bytes); + if (!peer_exist) { + wma_err("Failed to find peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + status = QDF_STATUS_E_FAILURE; + goto out; + } + bssid_addr = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev); + if (!bssid_addr) { + wma_err("Failed to bssid for vdev_%d", vdev_id); + status = QDF_STATUS_E_FAILURE; + goto out; + } + qdf_mem_zero(bssid_addr, + QDF_MAC_ADDR_SIZE); + + wma_delete_invalid_peer_entries(vdev_id, NULL); + + if (iface->psnr_req) { + qdf_mem_free(iface->psnr_req); + iface->psnr_req = NULL; + } + + if (iface->rcpi_req) { + struct sme_rcpi_req *rcpi_req = iface->rcpi_req; + + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + } + + if (iface->roam_scan_stats_req) { + struct sir_roam_scan_stats *roam_scan_stats_req = + iface->roam_scan_stats_req; + + iface->roam_scan_stats_req = NULL; + qdf_mem_free(roam_scan_stats_req); + } + + if (wlan_cm_is_roam_sync_in_progress(wma->psoc, vdev_id) || + MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id) || + mlo_is_roaming_in_progress(wma->psoc, vdev_id)) { + roam_synch_in_progress = true; + wma_debug("LFR3: Setting vdev_up to FALSE for vdev:%d", + vdev_id); + + goto detach_peer; + } + + status = mlme_set_vdev_stop_type(iface->vdev, + WMA_DELETE_BSS_REQ); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to set wma req msg_type for vdev_id: %d", + vdev_id); + goto out; + } + + cdp_txrx_get_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(wma->pdev), + CDP_TX_PENDING, &val); + tx_pending = val.cdp_pdev_param_tx_pending; + wma_debug("Outstanding msdu packets: %u", tx_pending); + wma_wait_tx_complete(wma, vdev_id); + + cdp_txrx_get_pdev_param(soc, wlan_objmgr_pdev_get_pdev_id(wma->pdev), + CDP_TX_PENDING, &val); + if (tx_pending) { + wma_debug("Outstanding msdu packets before VDEV_STOP : %u", + tx_pending); + } + + wma_debug("vdev_id: %d, pausing tx_ll_queue for VDEV_STOP (del_bss)", + vdev_id); + wma_vdev_set_pause_bit(vdev_id, PAUSE_TYPE_HOST); + cdp_fc_vdev_pause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_VDEV_STOP, 0); + + if (wma_send_vdev_stop_to_fw(wma, vdev_id)) { + struct vdev_stop_response vdev_stop_rsp = {0}; + + wma_err("Failed to send vdev stop to FW, explicitly invoke vdev stop rsp"); + vdev_stop_rsp.vdev_id = vdev_id; + wma_handle_vdev_stop_rsp(wma, &vdev_stop_rsp); + qdf_atomic_set(&iface->bss_status, WMA_BSS_STATUS_STOPPED); + } + wma_debug("bssid "QDF_MAC_ADDR_FMT" vdev_id %d", + QDF_MAC_ADDR_REF(bssid.bytes), vdev_id); + + return; + +detach_peer: + wma_remove_peer(wma, bssid.bytes, vdev_id, roam_synch_in_progress); + if (roam_synch_in_progress) + return; + +out: + /* skip when legacy to mlo roam sync ongoing */ + if (MLME_IS_MLO_ROAM_SYNCH_IN_PROGRESS(wma->psoc, vdev_id)) + return; + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return; + + params->vdev_id = vdev_id; + params->status = status; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_RSP, params, 0); +} + +/** + * wma_find_vdev_by_type() - This function finds vdev_id based on input type + * @wma: wma handle + * @type: vdev type + * + * Return: vdev id + */ +int32_t wma_find_vdev_by_type(tp_wma_handle wma, int32_t type) +{ + int32_t vdev_id = 0; + struct wma_txrx_node *intf = wma->interfaces; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + if (intf) { + if (intf[vdev_id].type == type) + return vdev_id; + } + } + + return -EFAULT; +} + +void wma_set_vdev_intrabss_fwd(tp_wma_handle wma_handle, + tpDisableIntraBssFwd pdis_intra_fwd) +{ + struct wlan_objmgr_vdev *vdev; + + wma_debug("intra_fwd:vdev(%d) intrabss_dis=%s", + pdis_intra_fwd->sessionId, + (pdis_intra_fwd->disableintrabssfwd ? "true" : "false")); + + vdev = wma_handle->interfaces[pdis_intra_fwd->sessionId].vdev; + cdp_cfg_vdev_rx_set_intrabss_fwd(cds_get_context(QDF_MODULE_ID_SOC), + pdis_intra_fwd->sessionId, + pdis_intra_fwd->disableintrabssfwd); +} + +/** + * wma_get_pdev_from_scn_handle() - API to get pdev from scn handle + * @scn_handle: opaque wma handle + * + * API to get pdev from scn handle + * + * Return: None + */ +static struct wlan_objmgr_pdev *wma_get_pdev_from_scn_handle(void *scn_handle) +{ + tp_wma_handle wma_handle; + + if (!scn_handle) { + wma_err("invalid scn handle"); + return NULL; + } + wma_handle = (tp_wma_handle)scn_handle; + + return wma_handle->pdev; +} + +void wma_store_pdev(void *wma_ctx, struct wlan_objmgr_pdev *pdev) +{ + tp_wma_handle wma = (tp_wma_handle)wma_ctx; + QDF_STATUS status; + + status = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_LEGACY_WMA_ID); + if (QDF_STATUS_SUCCESS != status) { + wma->pdev = NULL; + return; + } + + wma->pdev = pdev; + + target_if_store_pdev_target_if_ctx(wma_get_pdev_from_scn_handle); + target_pdev_set_wmi_handle(wma->pdev->tgt_if_handle, + wma->wmi_handle); +} + +/** + * wma_vdev_reset_beacon_interval_timer() - reset beacon interval back + * to its original value after the channel switch. + * + * @data: data + * + * Return: void + */ +static void wma_vdev_reset_beacon_interval_timer(void *data) +{ + tp_wma_handle wma; + struct wma_beacon_interval_reset_req *req = + (struct wma_beacon_interval_reset_req *)data; + uint16_t beacon_interval = req->interval; + uint8_t vdev_id = req->vdev_id; + + wma = (tp_wma_handle)cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + goto end; + + /* Change the beacon interval back to its original value */ + wma_debug("Change beacon interval back to %d", beacon_interval); + wma_update_beacon_interval(wma, vdev_id, beacon_interval); + +end: + qdf_timer_stop(&req->event_timeout); + qdf_timer_free(&req->event_timeout); + qdf_mem_free(req); +} + +int wma_fill_beacon_interval_reset_req(tp_wma_handle wma, uint8_t vdev_id, + uint16_t beacon_interval, uint32_t timeout) +{ + struct wma_beacon_interval_reset_req *req; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return -ENOMEM; + + wma_debug("vdev_id %d ", vdev_id); + req->vdev_id = vdev_id; + req->interval = beacon_interval; + qdf_timer_init(NULL, &req->event_timeout, + wma_vdev_reset_beacon_interval_timer, req, QDF_TIMER_TYPE_SW); + qdf_timer_start(&req->event_timeout, timeout); + + return 0; +} + +QDF_STATUS wma_set_wlm_latency_level(void *wma_ptr, + struct wlm_latency_level_param *latency_params) +{ + QDF_STATUS ret; + tp_wma_handle wma = (tp_wma_handle)wma_ptr; + + wma_debug("set latency level %d, fw wlm_latency_flags 0x%x", + latency_params->wlm_latency_level, + latency_params->wlm_latency_flags); + + ret = wmi_unified_wlm_latency_level_cmd(wma->wmi_handle, + latency_params); + if (QDF_IS_STATUS_ERROR(ret)) + wma_warn("Failed to set latency level"); + + return ret; +} + +QDF_STATUS wma_add_bss_peer_sta(uint8_t vdev_id, uint8_t *bssid, + bool is_resp_required, + uint8_t *mld_mac, bool is_assoc_peer) +{ + tp_wma_handle wma; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + goto err; + + if (is_resp_required) + status = wma_create_sta_mode_bss_peer(wma, bssid, + WMI_PEER_TYPE_DEFAULT, + vdev_id, mld_mac, + is_assoc_peer); + else + status = wma_create_peer(wma, bssid, WMI_PEER_TYPE_DEFAULT, + vdev_id, mld_mac, is_assoc_peer); +err: + return status; +} + +QDF_STATUS wma_send_vdev_stop(uint8_t vdev_id) +{ + tp_wma_handle wma; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_FAILURE; + + wma_debug("vdev_id: %d, pausing tx_ll_queue for VDEV_STOP", vdev_id); + cdp_fc_vdev_pause(soc, vdev_id, + OL_TXQ_PAUSE_REASON_VDEV_STOP, 0); + + status = mlme_set_vdev_stop_type( + wma->interfaces[vdev_id].vdev, + WMA_SET_LINK_STATE); + if (QDF_IS_STATUS_ERROR(status)) { + wma_alert("Failed to set wma req msg_type for vdev_id %d", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + wma_vdev_set_pause_bit(vdev_id, PAUSE_TYPE_HOST); + + status = wma_send_vdev_stop_to_fw(wma, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + struct vdev_stop_response resp_event; + + wma_info("vdev %d Failed to send vdev stop", vdev_id); + resp_event.vdev_id = vdev_id; + mlme_set_connection_fail(wma->interfaces[vdev_id].vdev, false); + wma_handle_vdev_stop_rsp(wma, &resp_event); + } + + /* + * Remove peer, Vdev down and sending set link + * response will be handled in vdev stop response + * handler + */ + + return QDF_STATUS_SUCCESS; +} + +#define TX_MGMT_RATE_2G_ENABLE_OFFSET 30 +#define TX_MGMT_RATE_5G_ENABLE_OFFSET 31 +#define TX_MGMT_RATE_2G_OFFSET 0 +#define TX_MGMT_RATE_5G_OFFSET 12 + +/** + * wma_verify_rate_code() - verify if rate code is valid. + * @rate_code: rate code + * @band: band information + * + * Return: verify result + */ +static bool wma_verify_rate_code(uint32_t rate_code, enum cds_band_type band) +{ + uint8_t preamble, nss, rate; + bool valid = true; + + preamble = (rate_code & 0xc0) >> 6; + nss = (rate_code & 0x30) >> 4; + rate = rate_code & 0xf; + + switch (preamble) { + case WMI_RATE_PREAMBLE_CCK: + if (nss != 0 || rate > 3 || band == CDS_BAND_5GHZ) + valid = false; + break; + case WMI_RATE_PREAMBLE_OFDM: + if (nss != 0 || rate > 7) + valid = false; + break; + case WMI_RATE_PREAMBLE_HT: + if (nss != 0 || rate > 7) + valid = false; + break; + case WMI_RATE_PREAMBLE_VHT: + if (nss != 0 || rate > 9) + valid = false; + break; + default: + break; + } + return valid; +} + +/** + * wma_vdev_mgmt_tx_rate() - set vdev mgmt rate. + * @info: pointer to vdev set param. + * + * Return: return status + */ +static QDF_STATUS wma_vdev_mgmt_tx_rate(struct dev_set_param *info) +{ + uint32_t cfg_val; + enum cds_band_type band = 0; + QDF_STATUS status; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("Failed to get mac"); + return QDF_STATUS_E_FAILURE; + } + + cfg_val = mac->mlme_cfg->sap_cfg.rate_tx_mgmt; + band = CDS_BAND_ALL; + if (cfg_val == MLME_CFG_TX_MGMT_RATE_DEF || + !wma_verify_rate_code(cfg_val, band)) { + wma_nofl_debug("default WNI_CFG_RATE_FOR_TX_MGMT, ignore"); + status = QDF_STATUS_E_FAILURE; + } else { + info->param_id = wmi_vdev_param_mgmt_tx_rate; + info->param_value = cfg_val; + status = QDF_STATUS_SUCCESS; + } + return status; +} + +/** + * wma_vdev_mgmt_perband_tx_rate() - set vdev mgmt perband tx rate. + * @info: pointer to vdev set param + * + * Return: returns status + */ +static QDF_STATUS wma_vdev_mgmt_perband_tx_rate(struct dev_set_param *info) +{ + uint32_t cfg_val; + uint32_t per_band_mgmt_tx_rate = 0; + enum cds_band_type band = 0; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("failed to get mac"); + return QDF_STATUS_E_FAILURE; + } + + cfg_val = mac->mlme_cfg->sap_cfg.rate_tx_mgmt_2g; + band = CDS_BAND_2GHZ; + if (cfg_val == MLME_CFG_TX_MGMT_2G_RATE_DEF || + !wma_verify_rate_code(cfg_val, band)) { + wma_nofl_debug("use default 2G MGMT rate."); + per_band_mgmt_tx_rate &= + ~(1 << TX_MGMT_RATE_2G_ENABLE_OFFSET); + } else { + per_band_mgmt_tx_rate |= + (1 << TX_MGMT_RATE_2G_ENABLE_OFFSET); + per_band_mgmt_tx_rate |= + ((cfg_val & 0x7FF) << TX_MGMT_RATE_2G_OFFSET); + } + + cfg_val = mac->mlme_cfg->sap_cfg.rate_tx_mgmt; + band = CDS_BAND_5GHZ; + if (cfg_val == MLME_CFG_TX_MGMT_5G_RATE_DEF || + !wma_verify_rate_code(cfg_val, band)) { + wma_nofl_debug("use default 5G MGMT rate."); + per_band_mgmt_tx_rate &= + ~(1 << TX_MGMT_RATE_5G_ENABLE_OFFSET); + } else { + per_band_mgmt_tx_rate |= + (1 << TX_MGMT_RATE_5G_ENABLE_OFFSET); + per_band_mgmt_tx_rate |= + ((cfg_val & 0x7FF) << TX_MGMT_RATE_5G_OFFSET); + } + + info->param_id = wmi_vdev_param_per_band_mgmt_tx_rate; + info->param_value = per_band_mgmt_tx_rate; + return QDF_STATUS_SUCCESS; +} + +#define MAX_VDEV_CREATE_PARAMS 22 +/* params being sent: + * 1.wmi_vdev_param_wmm_txop_enable + * 2.wmi_vdev_param_disconnect_th + * 3.wmi_vdev_param_mcc_rtscts_protection_enable + * 4.wmi_vdev_param_mcc_broadcast_probe_enable + * 5.wmi_vdev_param_rts_threshold + * 6.wmi_vdev_param_fragmentation_threshold + * 7.wmi_vdev_param_tx_stbc + * 8.wmi_vdev_param_mgmt_tx_rate + * 9.wmi_vdev_param_per_band_mgmt_tx_rate + * 10.wmi_vdev_param_set_eht_mu_mode + * 11.wmi_vdev_param_set_hemu_mode + * 12.wmi_vdev_param_txbf + * 13.wmi_vdev_param_enable_bcast_probe_response + * 14.wmi_vdev_param_fils_max_channel_guard_time + * 15.wmi_vdev_param_probe_delay + * 16.wmi_vdev_param_repeat_probe_time + * 17.wmi_vdev_param_enable_disable_oce_features + * 18.wmi_vdev_param_bmiss_first_bcnt + * 19.wmi_vdev_param_bmiss_final_bcnt + * 20.wmi_vdev_param_set_sap_ps_with_twt + * 21.wmi_vdev_param_disable_2g_twt + * 22.wmi_vdev_param_disable_twt_info_frame + */ + +QDF_STATUS wma_vdev_create_set_param(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + struct mlme_ht_capabilities_info *ht_cap_info; + uint32_t cfg_val; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct dev_set_param ext_val; + wmi_vdev_txbf_en txbf_en = {0}; + struct vdev_mlme_obj *vdev_mlme; + uint8_t vdev_id; + uint32_t hemu_mode; + struct dev_set_param setparam[MAX_VDEV_CREATE_PARAMS]; + uint8_t index = 0; + bool is_24ghz_twt_enabled; + bool disable_twt_info_frame; + enum QDF_OPMODE opmode; + + if (!mac) + return QDF_STATUS_E_FAILURE; + + vdev_id = wlan_vdev_get_id(vdev); + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wma_err("Failed to get vdev mlme obj!"); + return QDF_STATUS_E_FAILURE; + } + + status = mlme_check_index_setparam( + setparam, wmi_vdev_param_wmm_txop_enable, + mac->mlme_cfg->edca_params.enable_wmm_txop, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_wmm_txop_enable"); + goto error; + } + wma_debug("Setting wmi_vdev_param_disconnect_th: %d", + mac->mlme_cfg->gen.dropped_pkt_disconnect_thresh); + status = mlme_check_index_setparam( + setparam, wmi_vdev_param_disconnect_th, + mac->mlme_cfg->gen.dropped_pkt_disconnect_thresh, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_disconnect_th"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_mcc_rtscts_protection_enable, + mac->roam.configParam.mcc_rts_cts_prot_enable, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_mcc_rtscts_protection_enable"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_mcc_broadcast_probe_enable, + mac->roam.configParam.mcc_bcast_prob_resp_enable, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_mcc_broadcast_probe_enable"); + goto error; + } + if (wlan_mlme_get_rts_threshold(mac->psoc, &cfg_val) == + QDF_STATUS_SUCCESS) { + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_rts_threshold, + cfg_val, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_rts_threshold"); + goto error; + } + } else { + wma_err("Fail to get val for rts threshold, leave unchanged"); + } + if (wlan_mlme_get_frag_threshold(mac->psoc, &cfg_val) == + QDF_STATUS_SUCCESS) { + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_fragmentation_threshold, + cfg_val, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_fragmentation_threshold"); + goto error; + } + } else { + wma_err("Fail to get val for frag threshold, leave unchanged"); + } + + ht_cap_info = &mac->mlme_cfg->ht_caps.ht_cap_info; + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_tx_stbc, + ht_cap_info->tx_stbc, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_tx_stbc"); + goto error; + } + if (!wma_vdev_mgmt_tx_rate(&ext_val)) { + status = mlme_check_index_setparam(setparam, ext_val.param_id, + ext_val.param_value, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set param for MGMT RATE"); + goto error; + } + } + if (!wma_vdev_mgmt_perband_tx_rate(&ext_val)) { + status = mlme_check_index_setparam(setparam, ext_val.param_id, + ext_val.param_value, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set PERBAND_MGMT RATE"); + goto error; + } + } + if (IS_FEATURE_11BE_SUPPORTED_BY_FW) { + uint32_t mode; + + status = wma_set_eht_txbf_vdev_params(mac, &mode); + if (status == QDF_STATUS_SUCCESS) { + wma_debug("set EHTMU_MODE (ehtmu_mode = 0x%x)", mode); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_eht_mu_mode, + mode, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_set_eht_mu_mode"); + goto error; + } + } + } + if (IS_FEATURE_SUPPORTED_BY_FW(DOT11AX)) { + if (!wma_get_hemu_mode(&hemu_mode, mac)) { + wma_debug("set HEMU_MODE (hemu_mode = 0x%x)", + hemu_mode); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_hemu_mode, + hemu_mode, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_set_hemu_mode"); + goto error; + } + } + } + if (wlan_nan_is_beamforming_supported(mac->psoc)) { + txbf_en.sutxbfee = + mac->mlme_cfg->vht_caps.vht_cap_info.su_bformee; + txbf_en.mutxbfee = + mac->mlme_cfg->vht_caps.vht_cap_info.enable_mu_bformee; + txbf_en.sutxbfer = + mac->mlme_cfg->vht_caps.vht_cap_info.su_bformer; + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_txbf, + *((A_UINT8 *)&txbf_en), index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_txbf"); + goto error; + } + } + /* Initialize roaming offload state */ + if (vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_STA && + vdev_mlme->mgmt.generic.subtype == 0) { + /* Pass down enable/disable bcast probe rsp to FW */ + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_enable_bcast_probe_response, + mac->mlme_cfg->oce.enable_bcast_probe_rsp, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_enable_bcast_probe_response"); + goto error; + } + /* Pass down the FILS max channel guard time to FW */ + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_fils_max_channel_guard_time, + mac->mlme_cfg->sta.fils_max_chan_guard_time, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_fils_max_channel_guard_time"); + goto error; + } + /* Pass down the Probe Request tx delay(in ms) to FW */ + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_probe_delay, + PROBE_REQ_TX_DELAY, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_probe_delay"); + goto error; + } + /* Pass down the probe request tx time gap_ms to FW */ + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_repeat_probe_time, + PROBE_REQ_TX_TIME_GAP, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_repeat_probe_time"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_enable_disable_oce_features, + mac->mlme_cfg->oce.feature_bitmap, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_enable_disable_oce_features"); + goto error; + } + /* Initialize BMISS parameters */ + wma_debug("first_bcnt: %d, final_bcnt: %d", + mac->mlme_cfg->lfr.roam_bmiss_first_bcnt, + mac->mlme_cfg->lfr.roam_bmiss_final_bcnt); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_bmiss_first_bcnt, + mac->mlme_cfg->lfr.roam_bmiss_first_bcnt, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_bmiss_first_bcnt"); + goto error; + } + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_bmiss_final_bcnt, + mac->mlme_cfg->lfr.roam_bmiss_final_bcnt, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_bmiss_final_bcnt"); + goto error; + } + } + if (vdev_mlme->mgmt.generic.type == WMI_VDEV_TYPE_AP && + vdev_mlme->mgmt.generic.subtype == 0) { + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_enable_disable_oce_features, + mac->mlme_cfg->oce.feature_bitmap, index++, + MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_enable_disable_oce_features"); + goto error; + } + } + + opmode = wlan_vdev_mlme_get_opmode(vdev); + if (opmode == QDF_SAP_MODE) { + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_set_sap_ps_with_twt, + wlan_mlme_get_sap_ps_with_twt(mac->psoc), + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_set_sap_ps_with_twt"); + goto error; + } + } + + is_24ghz_twt_enabled = mlme_is_24ghz_twt_enabled(mac->psoc); + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_disable_2g_twt, + !is_24ghz_twt_enabled, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_disable_2g_twt"); + goto error; + } + + disable_twt_info_frame = mlme_is_twt_disable_info_frame(mac->psoc); + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_disable_twt_info_frame, + disable_twt_info_frame, + index++, MAX_VDEV_CREATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("failed to set wmi_vdev_param_disable_twt_info_frame"); + goto error; + } + + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to update vdev set all params"); + status = QDF_STATUS_E_FAILURE; + goto error; + } +error: + return status; +} + +static inline bool wma_tx_is_chainmask_valid(int value, + struct target_psoc_info *tgt_hdl) +{ + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + uint8_t total_mac_phy_cnt, i; + + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return false; + } + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + for (i = 0; i < total_mac_phy_cnt; i++) { + if (((mac_phy_cap[i].tx_chain_mask_5G) & (value))) + return true; + } + return false; +} + +QDF_STATUS +wma_validate_txrx_chain_mask(uint32_t id, uint32_t value) +{ + tp_wma_handle wma_handle = + cds_get_context(QDF_MODULE_ID_WMA); + struct target_psoc_info *tgt_hdl; + + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) + return QDF_STATUS_E_FAILURE; + + wma_debug("pdev pid %d pval %d", id, value); + if (id == wmi_pdev_param_tx_chain_mask) { + if (wma_check_txrx_chainmask(target_if_get_num_rf_chains( + tgt_hdl), value) || !wma_tx_is_chainmask_valid(value, + tgt_hdl)) { + wma_err("failed in validating tx chainmask"); + return QDF_STATUS_E_FAILURE; + } + } + if (id == wmi_pdev_param_rx_chain_mask) { + if (wma_check_txrx_chainmask(target_if_get_num_rf_chains( + tgt_hdl), value)) { + wma_err("failed in validating rtx chainmask"); + return QDF_STATUS_SUCCESS; + } + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_send_multi_pdev_vdev_set_params(enum mlme_dev_setparam param_type, + uint8_t dev_id, + struct dev_set_param *param, + uint8_t n_params) +{ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct set_multiple_pdev_vdev_param params = {}; + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!mac) + return QDF_STATUS_E_FAILURE; + + wmi_handle = get_wmi_unified_hdl_from_psoc(mac->psoc); + if (!wmi_handle) + return QDF_STATUS_E_FAILURE; + + params.param_type = param_type; + params.dev_id = dev_id; + params.is_host_pdev_id = false; + params.params = param; + params.n_params = n_params; + + if (param_type == MLME_VDEV_SETPARAM) { + status = wmi_unified_multiple_vdev_param_send(wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to send multi vdev set params"); + } else if (param_type == MLME_PDEV_SETPARAM) { + status = wmi_unified_multiple_pdev_param_send(wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to send multi pdev set params"); + } else { + status = QDF_STATUS_E_FAILURE; + wma_err("Invalid param type"); + } + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_eht.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_eht.c new file mode 100644 index 0000000000..5e0032dd90 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_eht.c @@ -0,0 +1,1117 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_eht.c + * + * WLAN Host Device Driver 802.11be - Extremely High Throughput Implementation + */ + +#include "wma_eht.h" +#include "wmi_unified.h" +#include "service_ready_param.h" +#include "target_if.h" +#include "wma_internal.h" + +#if defined(WLAN_FEATURE_11BE) +/* MCS Based EHT rate table */ +/* MCS parameters with Nss = 1*/ +static const struct index_eht_data_rate_type eht_mcs_nss1[] = { +/* MCS, {dcm0:0.8/1.6/3.2}, {dcm1:0.8/1.6/3.2} */ + {0, {{86, 81, 73}, {0} }, /* EHT20 */ + {{172, 163, 146}, {0} }, /* EHT40 */ + {{360, 340, 306}, {0} }, /* EHT80 */ + {{721, 681, 613}, {0} }, /* EHT160 */ + {{1441, 1361, 1225}, {0}}} , /* EHT320 */ + {1, {{172, 163, 146 }, {0} }, + {{344, 325, 293 }, {0} }, + {{721, 681, 613 }, {0} }, + {{1441, 1361, 1225}, {0} }, + {{2882, 2722, 2450}, {0} } } , + {2, {{258, 244, 219 }, {0} }, + {{516, 488, 439 }, {0} }, + {{1081, 1021, 919 }, {0} }, + {{2162, 2042, 1838}, {0} }, + {{4324, 4083, 3675}, {0} } } , + {3, {{344, 325, 293 }, {0} }, + {{688, 650, 585 }, {0} }, + {{1441, 1361, 1225}, {0} }, + {{2882, 2722, 2450}, {0} }, + {{5765, 5444, 4900}, {0} } } , + {4, {{516, 488, 439 }, {0} }, + {{1032, 975, 878 }, {0} }, + {{2162, 2042, 1838}, {0} }, + {{4324, 4083, 3675}, {0} }, + {{8647, 8167, 7350}, {0} } } , + {5, {{688, 650, 585 }, {0} }, + {{1376, 1300, 1170}, {0} }, + {{2882, 2722, 2450}, {0} }, + {{5765, 5444, 4900}, {0} }, + {{11529, 10889, 9800}, {0}}} , + {6, {{774, 731, 658 }, {0} }, + {{1549, 1463, 1316}, {0} }, + {{3243, 3063, 2756}, {0} }, + {{6485, 6125, 5513}, {0} }, + {{12971, 12250, 11025}, {0} } } , + {7, {{860, 813, 731 }, {0} }, + {{1721, 1625, 1463}, {0} }, + {{3603, 3403, 3063}, {0} }, + {{7206, 6806, 6125}, {0} }, + {{14412, 13611, 12250}, {0} } } , + {8, {{1032, 975, 878 }, {0} }, + {{2065, 1950, 1755}, {0} }, + {{4324, 4083, 3675}, {0} }, + {{8647, 8167, 7350}, {0} }, + {{17294, 16333, 14700}, {0} }} , + {9, {{1147, 1083, 975 }, {0} }, + {{2294, 2167, 1950}, {0} }, + {{4804, 4537, 4083}, {0} }, + {{9608, 9074, 8167}, {0} }, + {{19216, 18148, 16333}, {0} } } , + {10, {{1290, 1219, 1097}, {0} }, + {{2581, 2438, 2194}, {0} }, + {{5404, 5104, 4594}, {0} }, + {{10809, 10208, 9188}, {0} }, + {{21618, 20417, 18375}, {0} } } , + {11, {{1434, 1354, 1219}, {0} }, + {{2868, 2708, 2438}, {0} }, + {{6005, 5671, 5104}, {0} }, + {{12010, 11342, 10208}, {0} }, + {{24020, 22685, 20417}, {0} }} , + {12, {{1549, 1463, 1316}, {0} }, + {{3097, 2925, 2633}, {0} }, + {{6485, 6125, 5513}, {0} }, + {{12971, 12250, 11025}, {0} }, + {{25941, 24500, 22050}, {0} }} , + {13, {{1721, 1625, 1463}, {0} }, + {{3441, 3250, 2925}, {0} }, + {{7206, 6806, 6125}, {0} }, + {{14412, 13611, 12250}, {0}}, + {{28824, 27222, 24500}, {0}}} , +}; + +/*MCS parameters with Nss = 2*/ +static const struct index_eht_data_rate_type eht_mcs_nss2[] = { +/* MCS, {dcm0:0.8/1.6/3.2}, {dcm1:0.8/1.6/3.2} */ + {0, {{172, 162, 146 }, {0} }, /* EHT20 */ + {{344, 326, 292 }, {0} }, /* EHT40 */ + {{720, 680, 612 }, {0} }, /* EHT80 */ + {{1442, 1362, 1226}, {0} }, /* EHT160 */ + {{2882, 2722, 2450}, {0} } } , /* EHT320 */ + {1, {{344, 326, 292 }, {0} }, + {{688, 650, 586 }, {0} }, + {{1442, 1362, 1226}, {0} }, + {{2882, 2722, 2450}, {0}}, + {{5764, 5444, 4900}, {0} }} , + {2, {{516, 488, 438 }, {0} }, + {{1032, 976, 878 }, {0} }, + {{2162, 2042, 1838}, {0} }, + {{4324, 4084, 3676}, {0} }, + {{8648, 8166, 7350}, {0} } } , + {3, {{688, 650, 586 }, {0} }, + {{1376, 1300, 1170}, {0} }, + {{2882, 2722, 2450}, {0} }, + {{5764, 5444, 4900}, {0} }, + {{11530, 10888, 9800}, {0}} } , + {4, {{1032, 976, 878 }, {0} }, + {{2064, 1950, 1756}, {0} }, + {{4324, 4083, 36756}, {0} }, + {{8648, 8166, 7350}, {0} }, + {{17294, 16334, 14700}, {0}}}, + {5, {{1376, 1300, 1170}, {0} }, + {{2752, 2600, 2340}, {0} }, + {{5764, 5444, 4900}, {0} }, + {{11530, 10888, 9800}, {0} }, + {{23058, 21778, 19600}, {0} }} , + {6, {{1548, 1462, 1316}, {0} }, + {{3098, 2926, 2632}, {0} }, + {{6486, 6126, 5512}, {0} }, + {{12970, 12250, 11026}, {0} }, + {{25942, 24500, 22050}, {0} }} , + {7, {{1720, 1626, 1462}, {0} }, + {{3442, 3250, 2926}, {0} }, + {{7206, 6806, 61256}, {0} }, + {{14412, 13612, 12250}, {0} }, + {{28824, 27222, 24500}, {0} }} , + {8, {{2064, 1950, 1756}, {0} }, + {{4130, 3900, 3510}, {0} }, + {{8648, 8166, 7350}, {0} }, + {{17294, 16334, 14700}, {0} }, + {{34588, 32666, 29400}, {0} }} , + {9, {{2294, 2166, 1950}, {0} }, + {{4588, 4334, 3900}, {0} }, + {{9608, 9074, 8166}, {0} }, + {{19216, 18148, 16334}, {0} }, + {{38432, 36296, 32666}, {0} }} , + {10, {{2580, 2438, 2194}, {0} }, + {{5162, 4876, 4388}, {0} }, + {{10808, 10208, 9188}, {0} }, + {{21618, 20416, 18376}, {0} }, + {{43236, 40834, 36750}, {0} }} , + {11, {{2868, 2708, 2438}, {0} }, + {{5736, 5416, 4876}, {0} }, + {{12010, 11342, 10208}, {0} }, + {{24020, 22686, 20416}, {0} }, + {{48040, 45370, 40834}, {0} }} , + {12, {{3098, 2926, 2632}, {0} }, + {{6194, 5850, 5266}, {0} }, + {{12970, 12250, 11026}, {0} }, + {{25942, 24500, 22050}, {0} }, + {{51882, 49000, 44100}, {0} }} , + {13, {{3442, 3250, 2926}, {0} }, + {{6882, 6500, 5850}, {0} }, + {{14412, 13611, 12250}, {0} }, + {{28824, 27222, 24500}, {0} }, + {{57648, 54444, 49000}, {0} }} +}; + +/** + * wma_convert_eht_cap() - convert EHT capabilities into dot11f structure + * @eht_cap: pointer to dot11f structure + * @mac_cap: Received EHT MAC capability + * @phy_cap: Received EHT PHY capability + * + * This function converts various EHT capability received as part of extended + * service ready event into dot11f structure. + * + * Return: None + */ +static void wma_convert_eht_cap(tDot11fIEeht_cap *eht_cap, uint32_t *mac_cap, + uint32_t *phy_cap) +{ + eht_cap->present = true; + + /* EHT MAC capabilities */ + eht_cap->epcs_pri_access = WMI_EHTCAP_MAC_NSEPPRIACCESS_GET(mac_cap); + eht_cap->eht_om_ctl = WMI_EHTCAP_MAC_EHTOMCTRL_GET(mac_cap); + eht_cap->triggered_txop_sharing_mode1 = + WMI_EHTCAP_MAC_TRIGTXOPMODE1_GET(mac_cap); + eht_cap->triggered_txop_sharing_mode2 = + WMI_EHTCAP_MAC_TRIGTXOPMODE2_GET(mac_cap); + eht_cap->restricted_twt = WMI_EHTCAP_MAC_RESTRICTTWT_GET(mac_cap); + eht_cap->scs_traffic_desc = WMI_EHTCAP_MAC_SCSTRAFFICDESC_GET(mac_cap); + eht_cap->max_mpdu_len = WMI_EHTCAP_MAC_MAXMPDULEN_GET(mac_cap); + eht_cap->max_a_mpdu_len_exponent_ext = + WMI_EHTCAP_MAC_MAXAMPDULEN_EXP_GET(mac_cap); + eht_cap->eht_trs_support = + WMI_EHTCAP_MAC_TRS_SUPPORT_GET(mac_cap); + eht_cap->txop_return_support_txop_share_m2 = + WMI_EHTCAP_MAC_TXOP_RETURN_SUPP_IN_SHARINGMODE2_GET(mac_cap); + eht_cap->two_bqrs_support = + WMI_EHTCAP_MAC_TWO_BQRS_SUPP_GET(mac_cap); + eht_cap->eht_link_adaptation_support = + WMI_EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_GET(mac_cap); + + /* EHT PHY capabilities */ + eht_cap->support_320mhz_6ghz = WMI_EHTCAP_PHY_320MHZIN6GHZ_GET(phy_cap); + eht_cap->ru_242tone_wt_20mhz = WMI_EHTCAP_PHY_242TONERUBWLT20MHZ_GET( + phy_cap); + eht_cap->ndp_4x_eht_ltf_3dot2_us_gi = + WMI_EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_GET(phy_cap); + eht_cap->partial_bw_mu_mimo = WMI_EHTCAP_PHY_PARTIALBWULMU_GET(phy_cap); + eht_cap->su_beamformer = WMI_EHTCAP_PHY_SUBFMR_GET(phy_cap); + eht_cap->su_beamformee = WMI_EHTCAP_PHY_SUBFME_GET(phy_cap); + eht_cap->bfee_ss_le_80mhz = WMI_EHTCAP_PHY_BFMESSLT80MHZ_GET(phy_cap); + eht_cap->bfee_ss_160mhz = WMI_EHTCAP_PHY_BFMESS160MHZ_GET(phy_cap); + eht_cap->bfee_ss_320mhz = WMI_EHTCAP_PHY_BFMESS320MHZ_GET(phy_cap); + eht_cap->num_sounding_dim_le_80mhz = WMI_EHTCAP_PHY_NUMSOUNDLT80MHZ_GET( + phy_cap); + eht_cap->num_sounding_dim_160mhz = WMI_EHTCAP_PHY_NUMSOUND160MHZ_GET( + phy_cap); + eht_cap->num_sounding_dim_320mhz = WMI_EHTCAP_PHY_NUMSOUND320MHZ_GET( + phy_cap); + eht_cap->ng_16_su_feedback = WMI_EHTCAP_PHY_NG16SUFB_GET(phy_cap); + eht_cap->ng_16_mu_feedback = WMI_EHTCAP_PHY_NG16MUFB_GET(phy_cap); + eht_cap->cb_sz_4_2_su_feedback = WMI_EHTCAP_PHY_CODBK42SUFB_GET( + phy_cap); + eht_cap->cb_sz_7_5_su_feedback = WMI_EHTCAP_PHY_CODBK75MUFB_GET( + phy_cap); + eht_cap->trig_su_bforming_feedback = WMI_EHTCAP_PHY_TRIGSUBFFB_GET( + phy_cap); + eht_cap->trig_mu_bforming_partial_bw_feedback = + WMI_EHTCAP_PHY_TRIGMUBFPARTBWFB_GET(phy_cap); + eht_cap->triggered_cqi_feedback = WMI_EHTCAP_PHY_TRIGCQIFB_GET(phy_cap); + eht_cap->partial_bw_dl_mu_mimo = WMI_EHTCAP_PHY_PARTBWDLMUMIMO_GET( + phy_cap); + eht_cap->psr_based_sr = WMI_EHTCAP_PHY_PSRSR_GET(phy_cap); + eht_cap->power_boost_factor = WMI_EHTCAP_PHY_PWRBSTFACTOR_GET(phy_cap); + eht_cap->eht_mu_ppdu_4x_ltf_0_8_us_gi = + WMI_EHTCAP_PHY_4XEHTLTFAND800NSGI_GET(phy_cap); + eht_cap->max_nc = WMI_EHTCAP_PHY_MAXNC_GET(phy_cap); + eht_cap->non_trig_cqi_feedback = WMI_EHTCAP_PHY_NONTRIGCQIFB_GET( + phy_cap); + eht_cap->tx_1024_4096_qam_lt_242_tone_ru = + WMI_EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_GET(phy_cap); + eht_cap->rx_1024_4096_qam_lt_242_tone_ru = + WMI_EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_GET(phy_cap); + eht_cap->ppet_present = WMI_EHTCAP_PHY_PPETHRESPRESENT_GET(phy_cap); + eht_cap->common_nominal_pkt_padding = WMI_EHTCAP_PHY_CMNNOMPKTPAD_GET( + phy_cap); + eht_cap->max_num_eht_ltf = WMI_EHTCAP_PHY_MAXNUMEHTLTF_GET(phy_cap); + eht_cap->mcs_15 = WMI_EHTCAP_PHY_SUPMCS15_GET(phy_cap); + eht_cap->eht_dup_6ghz = WMI_EHTCAP_PHY_EHTDUPIN6GHZ_GET(phy_cap); + eht_cap->op_sta_rx_ndp_wider_bw_20mhz = + WMI_EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_GET(phy_cap); + eht_cap->non_ofdma_ul_mu_mimo_le_80mhz = + WMI_EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_GET(phy_cap); + eht_cap->non_ofdma_ul_mu_mimo_160mhz = + WMI_EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_GET(phy_cap); + eht_cap->non_ofdma_ul_mu_mimo_320mhz = + WMI_EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_GET(phy_cap); + eht_cap->mu_bformer_le_80mhz = WMI_EHTCAP_PHY_MUBFMRLT80MHZ_GET( + phy_cap); + eht_cap->mu_bformer_160mhz = WMI_EHTCAP_PHY_MUBFMR160MHZ_GET(phy_cap); + eht_cap->mu_bformer_320mhz = WMI_EHTCAP_PHY_MUBFMR320MHZ_GET(phy_cap); + eht_cap->tb_sounding_feedback_rl = + WMI_EHTCAP_PHY_TBSUNDFBRATELIMIT_GET(phy_cap); + eht_cap->rx_1k_qam_in_wider_bw_dl_ofdma = + WMI_EHTCAP_PHY_RX1024QAMWIDERBWDLOFDMA_GET(phy_cap); + eht_cap->rx_4k_qam_in_wider_bw_dl_ofdma = + WMI_EHTCAP_PHY_RX4096QAMWIDERBWDLOFDMA_GET(phy_cap); + eht_cap->limited_cap_support_20mhz = + WMI_EHTCAP_PHY_20MHZ_ONLY_CAPS_GET(phy_cap); + eht_cap->triggered_mu_bf_full_bw_fb_and_dl_mumimo = + WMI_EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_GET(phy_cap); + eht_cap->mru_support_20mhz = + WMI_EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_GET(phy_cap); + + /* TODO: MCS map and PPET */ +} + +void wma_eht_update_tgt_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + if (wmi_service_enabled(wmi_handle, wmi_service_11be)) { + cfg->en_11be = true; + wma_set_fw_wlan_feat_caps(DOT11BE); + wma_debug("11be is enabled"); + } else { + cfg->en_11be = false; + wma_debug("11be is not enabled"); + } +} + +static void +wma_update_eht_cap_support_for_320mhz(struct target_psoc_info *tgt_hdl, + tDot11fIEeht_cap *eht_cap) +{ + struct wlan_psoc_host_mac_phy_caps_ext2 *cap; + + cap = target_psoc_get_mac_phy_cap_ext2_for_mode( + tgt_hdl, WMI_HOST_HW_MODE_SINGLE); + if (!cap) { + wma_debug("HW_MODE_SINGLE does not exist"); + return; + } + + eht_cap->support_320mhz_6ghz = WMI_EHTCAP_PHY_320MHZIN6GHZ_GET( + cap->eht_cap_phy_info_5G); + eht_cap->max_num_eht_ltf = + WMI_EHTCAP_PHY_MAXNUMEHTLTF_GET(cap->eht_cap_phy_info_5G); + wma_debug("Support for 320MHz 0x%01x, max_num_eht_ltf %d", + eht_cap->support_320mhz_6ghz, eht_cap->max_num_eht_ltf); +} + +static void +wma_update_eht_20mhz_only_mcs(uint32_t *mcs_2g_20, tDot11fIEeht_cap *eht_cap) +{ + eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7 |= QDF_GET_BITS(*mcs_2g_20, 0, 4); + eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7 |= QDF_GET_BITS(*mcs_2g_20, 4, 4); + eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9 |= QDF_GET_BITS(*mcs_2g_20, 8, 4); + eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9 |= + QDF_GET_BITS(*mcs_2g_20, 12, 4); + eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_2g_20, 16, 4); + eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_2g_20, 20, 4); + eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_2g_20, 24, 4); + eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_2g_20, 28, 4); +} + +static void +wma_update_eht_le_80mhz_mcs(uint32_t *mcs_le_80, tDot11fIEeht_cap *eht_cap) +{ + eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9 |= + QDF_GET_BITS(*mcs_le_80, 0, 4); + eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9 |= + QDF_GET_BITS(*mcs_le_80, 4, 4); + eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_le_80, 8, 4); + eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_le_80, 12, 4); + eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_le_80, 16, 4); + eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_le_80, 20, 4); +} + +static void +wma_update_eht_160mhz_mcs(uint32_t *mcs_160mhz, tDot11fIEeht_cap *eht_cap) +{ + eht_cap->bw_160_rx_max_nss_for_mcs_0_to_9 |= + QDF_GET_BITS(*mcs_160mhz, 0, 4); + eht_cap->bw_160_tx_max_nss_for_mcs_0_to_9 |= + QDF_GET_BITS(*mcs_160mhz, 4, 4); + eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_160mhz, 8, 4); + eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_160mhz, 12, 4); + eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_160mhz, 16, 4); + eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_160mhz, 20, 4); +} + +static void +wma_update_eht_320mhz_mcs(uint32_t *mcs_320mhz, tDot11fIEeht_cap *eht_cap) +{ + eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9 |= + QDF_GET_BITS(*mcs_320mhz, 0, 4); + eht_cap->bw_320_tx_max_nss_for_mcs_0_to_9 |= + QDF_GET_BITS(*mcs_320mhz, 4, 4); + eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_320mhz, 8, 4); + eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11 |= + QDF_GET_BITS(*mcs_320mhz, 12, 4); + eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_320mhz, 16, 4); + eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13 |= + QDF_GET_BITS(*mcs_320mhz, 20, 4); +} + +void wma_update_target_ext_eht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg) +{ + tDot11fIEeht_cap *eht_cap = &tgt_cfg->eht_cap; + tDot11fIEeht_cap *eht_cap_2g = &tgt_cfg->eht_cap_2g; + tDot11fIEeht_cap *eht_cap_5g = &tgt_cfg->eht_cap_5g; + int i, num_hw_modes, total_mac_phy_cnt; + tDot11fIEeht_cap eht_cap_mac; + struct wlan_psoc_host_mac_phy_caps_ext2 *mac_phy_cap, *mac_phy_caps2; + struct wlan_psoc_host_mac_phy_caps *host_cap; + uint32_t supported_bands; + uint32_t *mcs_supp; + + qdf_mem_zero(eht_cap_2g, sizeof(tDot11fIEeht_cap)); + qdf_mem_zero(eht_cap_5g, sizeof(tDot11fIEeht_cap)); + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap_ext2(tgt_hdl); + host_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + if (!mac_phy_cap || !host_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + eht_cap->present = false; + return; + } + + if (!num_hw_modes) { + wma_err("No extended EHT cap for current SOC"); + eht_cap->present = false; + return; + } + + if (!tgt_cfg->services.en_11be) { + wma_info("Target does not support 11BE"); + eht_cap->present = false; + return; + } + + for (i = 0; i < total_mac_phy_cnt; i++) { + supported_bands = host_cap[i].supported_bands; + qdf_mem_zero(&eht_cap_mac, sizeof(tDot11fIEeht_cap)); + mac_phy_caps2 = &mac_phy_cap[i]; + if (supported_bands & WLAN_2G_CAPABILITY) { + wma_convert_eht_cap(&eht_cap_mac, + mac_phy_caps2->eht_cap_info_2G, + mac_phy_caps2->eht_cap_phy_info_2G); + /* TODO: PPET */ + /* WMI_EHT_SUPP_MCS_20MHZ_ONLY */ + mcs_supp = &mac_phy_caps2->eht_supp_mcs_ext_2G[0]; + wma_update_eht_20mhz_only_mcs(mcs_supp, &eht_cap_mac); + /* WMI_EHT_SUPP_MCS_LE_80MHZ */ + mcs_supp = &mac_phy_caps2->eht_supp_mcs_ext_2G[1]; + wma_update_eht_le_80mhz_mcs(mcs_supp, &eht_cap_mac); + + qdf_mem_copy(eht_cap_2g, &eht_cap_mac, + sizeof(tDot11fIEeht_cap)); + } + + if (supported_bands & WLAN_5G_CAPABILITY) { + qdf_mem_zero(&eht_cap_mac, sizeof(tDot11fIEeht_cap)); + wma_convert_eht_cap(&eht_cap_mac, + mac_phy_caps2->eht_cap_info_5G, + mac_phy_caps2->eht_cap_phy_info_5G); + + /* WMI_EHT_SUPP_MCS_20MHZ_ONLY */ + mcs_supp = &mac_phy_caps2->eht_supp_mcs_ext_5G[0]; + wma_update_eht_20mhz_only_mcs(mcs_supp, &eht_cap_mac); + /* WMI_EHT_SUPP_MCS_LE_80MHZ */ + mcs_supp = &mac_phy_caps2->eht_supp_mcs_ext_5G[1]; + wma_update_eht_le_80mhz_mcs(mcs_supp, &eht_cap_mac); + + /* WMI_EHT_SUPP_MCS_160MHZ */ + mcs_supp = &mac_phy_caps2->eht_supp_mcs_ext_5G[2]; + wma_update_eht_160mhz_mcs(mcs_supp, &eht_cap_mac); + /* WMI_EHT_SUPP_MCS_320MHZ */ + mcs_supp = &mac_phy_caps2->eht_supp_mcs_ext_5G[3]; + wma_update_eht_320mhz_mcs(mcs_supp, &eht_cap_mac); + + qdf_mem_copy(eht_cap_5g, &eht_cap_mac, + sizeof(tDot11fIEeht_cap)); + } + } + qdf_mem_copy(eht_cap, &eht_cap_mac, sizeof(tDot11fIEeht_cap)); + + wma_update_eht_cap_support_for_320mhz(tgt_hdl, eht_cap); + wma_update_eht_cap_support_for_320mhz(tgt_hdl, eht_cap_5g); + + wma_print_eht_cap(eht_cap); +} + +void wma_update_vdev_eht_ops(uint32_t *eht_ops, tDot11fIEeht_op *eht_op) +{ +} + +void wma_print_eht_cap(tDot11fIEeht_cap *eht_cap) +{ + if (!eht_cap->present) + return; + + wma_debug("EHT Caps: EPCS PA 0x%01x OM ctl 0x%01x Triggered TXOP Sharing mode1:0x%01x mode2:0x%01x, Restricted TWT 0x%01x SCS Traffic Desc 0x%01x Max MPDU 0x%01x Max A-MPDU exponent ext: 0x%01x", + eht_cap->epcs_pri_access, eht_cap->eht_om_ctl, + eht_cap->triggered_txop_sharing_mode1, + eht_cap->triggered_txop_sharing_mode2, + eht_cap->restricted_twt, eht_cap->scs_traffic_desc, + eht_cap->max_mpdu_len, + eht_cap->max_a_mpdu_len_exponent_ext); + wma_nofl_debug(" TRS supp 0x%01x TXOP return support in TXOP M2 0x%01x Two BQRs supp 0x%01x EHT link adaptation supp 0x%01x 320MHz 6GHz 0x%01x 242-tone RU WT 20 MHz 0x%01x NDP_4x EHT-LTF 3.2 us GI 0x%01x", + eht_cap->eht_trs_support, + eht_cap->txop_return_support_txop_share_m2, + eht_cap->two_bqrs_support, + eht_cap->eht_link_adaptation_support, + eht_cap->support_320mhz_6ghz, + eht_cap->ru_242tone_wt_20mhz, + eht_cap->ndp_4x_eht_ltf_3dot2_us_gi); + wma_nofl_debug(" Partial BW UL MU-MIMO: 0x%01x, SU: Bfer 0x%01x Bfee 0x%01x, Bfee SS: LE 80Mhz 0x%03x 160Mhz 0x%03x 320Mhz 0x%03x, No. of Sounding Dim LE 80Mhz 0x%03x 160Mhz 0x%03x 320Mhz 0x%03x ", + eht_cap->partial_bw_mu_mimo, + eht_cap->su_beamformer, eht_cap->su_beamformee, + eht_cap->bfee_ss_le_80mhz, eht_cap->bfee_ss_160mhz, + eht_cap->bfee_ss_320mhz, + eht_cap->num_sounding_dim_le_80mhz, + eht_cap->num_sounding_dim_160mhz, + eht_cap->num_sounding_dim_320mhz); + wma_nofl_debug(" Ng 16: SU Feedback 0x%01x, MU Feedback 0x%01x Codebook: 4 2 SU: 0x%01x, 7 5 MU: 0x%01x, Trig SU Bfing fb 0x%01x, MU Bfing partial BW 0x%01x Trig CQI FB 0x%01x, Part BW DL MU-MIMO: 0x%01x", + eht_cap->ng_16_su_feedback, eht_cap->ng_16_mu_feedback, + eht_cap->cb_sz_4_2_su_feedback, + eht_cap->cb_sz_7_5_su_feedback, + eht_cap->trig_su_bforming_feedback, + eht_cap->trig_mu_bforming_partial_bw_feedback, + eht_cap->triggered_cqi_feedback, + eht_cap->partial_bw_dl_mu_mimo); + wma_nofl_debug(" PSR-Based SR 0x%01x, Power Boost Factor 0x%01x, MU PPDU With 4x EHT-LTF 0.8 us GI 0x%01x Max Nc: 0x%04x, Non-Trig CQI FB 0x%01x, 1024-QAM 4096-QAM < 242-tone RU: TX 0x%01x RX 0x%01x", + eht_cap->psr_based_sr, eht_cap->power_boost_factor, + eht_cap->eht_mu_ppdu_4x_ltf_0_8_us_gi, + eht_cap->max_nc, eht_cap->non_trig_cqi_feedback, + eht_cap->tx_1024_4096_qam_lt_242_tone_ru, + eht_cap->rx_1024_4096_qam_lt_242_tone_ru); + wma_nofl_debug(" PPE Thresholds 0x%01x, Common Nominal Pkt Padding 0x%02x, Max No. Sup EHT-LTFs 0x%05x, MCS 15 0x%04x, DUP 6 GHz 0x%01x, 20 MHz STA RX NDP With Wider BW 0x%01x", + eht_cap->ppet_present, + eht_cap->common_nominal_pkt_padding, + eht_cap->max_num_eht_ltf, eht_cap->mcs_15, + eht_cap->eht_dup_6ghz, + eht_cap->op_sta_rx_ndp_wider_bw_20mhz); + wma_nofl_debug(" Non-OFDMA ULMU: LE 80MHz 0x%01x 160MHz 0x%01x 320MHz 0x%01x, MUBfmer: LE 80MHz 0x%01x 160MHz 0x%01x 320MHz 0x%01x, TB sound FBRL 0x%01x, WBDL OFDMA Rx: 1024QAM 0x%01x 4096QAM 0x%01x", + eht_cap->non_ofdma_ul_mu_mimo_le_80mhz, + eht_cap->non_ofdma_ul_mu_mimo_160mhz, + eht_cap->non_ofdma_ul_mu_mimo_320mhz, + eht_cap->mu_bformer_le_80mhz, + eht_cap->mu_bformer_160mhz, eht_cap->mu_bformer_320mhz, + eht_cap->tb_sounding_feedback_rl, + eht_cap->rx_1k_qam_in_wider_bw_dl_ofdma, + eht_cap->rx_4k_qam_in_wider_bw_dl_ofdma); + wma_nofl_debug(" 20 MHz-Only: Limited Cap 0x%01x Triggered MU Bfing Full BW FB, DL MU-MIMO 0x%01x M-RU Support 0x%01x, EHT MCS: 20MHz::: 0-7: RX: 0x%x TX: 0x%x, 8-9: RX: 0x%x TX: 0x%x", + eht_cap->limited_cap_support_20mhz, + eht_cap->triggered_mu_bf_full_bw_fb_and_dl_mumimo, + eht_cap->mru_support_20mhz, + eht_cap->bw_20_rx_max_nss_for_mcs_0_to_7, + eht_cap->bw_20_tx_max_nss_for_mcs_0_to_7, + eht_cap->bw_20_rx_max_nss_for_mcs_8_and_9, + eht_cap->bw_20_tx_max_nss_for_mcs_8_and_9); + wma_nofl_debug(" 20MHz::: 10-11: RX: 0x%x TX: 0x%x, 12-13: RX: 0x%x TX: 0x%x, 80Mhz LE::: 0-9: RX: 0x%x TX: 0x%x, 10-11: RX: 0x%x TX: 0x%x, 12-13: RX: 0x%x TX: 0x%x", + eht_cap->bw_20_rx_max_nss_for_mcs_10_and_11, + eht_cap->bw_20_tx_max_nss_for_mcs_10_and_11, + eht_cap->bw_20_rx_max_nss_for_mcs_12_and_13, + eht_cap->bw_20_tx_max_nss_for_mcs_12_and_13, + eht_cap->bw_le_80_rx_max_nss_for_mcs_0_to_9, + eht_cap->bw_le_80_tx_max_nss_for_mcs_0_to_9, + eht_cap->bw_le_80_rx_max_nss_for_mcs_10_and_11, + eht_cap->bw_le_80_tx_max_nss_for_mcs_10_and_11, + eht_cap->bw_le_80_rx_max_nss_for_mcs_12_and_13, + eht_cap->bw_le_80_tx_max_nss_for_mcs_12_and_13); + wma_nofl_debug(" 160Mhz::: 0-9: RX: 0x%x TX: 0x%x, 10-11: RX: 0x%x TX: 0x%x, 12-13: RX: 0x%x TX: 0x%x, 320Mhz::: 0-9: RX: 0x%x TX: 0x%x, 10-11: RX: 0x%x TX: 0x%x, 12-13: RX: 0x%x TX: 0x%x", + eht_cap->bw_160_rx_max_nss_for_mcs_0_to_9, + eht_cap->bw_160_tx_max_nss_for_mcs_0_to_9, + eht_cap->bw_160_rx_max_nss_for_mcs_10_and_11, + eht_cap->bw_160_tx_max_nss_for_mcs_10_and_11, + eht_cap->bw_160_rx_max_nss_for_mcs_12_and_13, + eht_cap->bw_160_tx_max_nss_for_mcs_12_and_13, + eht_cap->bw_320_rx_max_nss_for_mcs_0_to_9, + eht_cap->bw_320_tx_max_nss_for_mcs_0_to_9, + eht_cap->bw_320_rx_max_nss_for_mcs_10_and_11, + eht_cap->bw_320_tx_max_nss_for_mcs_10_and_11, + eht_cap->bw_320_rx_max_nss_for_mcs_12_and_13, + eht_cap->bw_320_tx_max_nss_for_mcs_12_and_13); +} + +void wma_print_eht_phy_cap(uint32_t *phy_cap) +{ + wma_debug("EHT PHY Cap: 320 MHz In 6 GHz 0x%01x, 242-tone RU In BW Wider Than 20 MHz 0x%01x, NDP With 4x EHT-LTF And 3.2 us GI 0x%01x, Partial BW UL MU-MIMO 0x%01x", + WMI_EHTCAP_PHY_320MHZIN6GHZ_GET(phy_cap), + WMI_EHTCAP_PHY_242TONERUBWLT20MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_GET(phy_cap), + WMI_EHTCAP_PHY_PARTIALBWULMU_GET(phy_cap)); + wma_nofl_debug(" SU: Bfmer 0x%01x Bfmee 0x%01x, Bfmee SS: LE 80MHz 0x%03x 160MHz 0x%03x 320MHz 0x%03x, No. of Sounding Dim: LE 80MHz 0x%03x 160MHz 0x%03x 320MHz 0x%03x", + WMI_EHTCAP_PHY_SUBFMR_GET(phy_cap), + WMI_EHTCAP_PHY_SUBFME_GET(phy_cap), + WMI_EHTCAP_PHY_BFMESSLT80MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_BFMESS160MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_BFMESS320MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_NUMSOUNDLT80MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_NUMSOUND160MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_NUMSOUND320MHZ_GET(phy_cap)); + wma_nofl_debug(" Ng 16 FB: SU 0x%01x MU 0x%01x, Codebook Size: 42 SU FB 0x%01x 75 MU FB: 0x%01x, Trigg SU Bfming FB 0x%01x, MU Bfming Partial BW FB 0x%01x", + WMI_EHTCAP_PHY_NG16SUFB_GET(phy_cap), + WMI_EHTCAP_PHY_NG16MUFB_GET(phy_cap), + WMI_EHTCAP_PHY_CODBK42SUFB_GET(phy_cap), + WMI_EHTCAP_PHY_CODBK75MUFB_GET(phy_cap), + WMI_EHTCAP_PHY_TRIGSUBFFB_GET(phy_cap), + WMI_EHTCAP_PHY_TRIGMUBFPARTBWFB_GET(phy_cap)); + wma_nofl_debug(" Triggered CQI FB 0x%01x, Partial BW DL MU-MIMO 0x%01x, PSR-Based SR 0x%01x, Power Boost Factor 0x%01x, MU PPDU 4x EHT-LTF 0.8 us GI 0x%01x", + WMI_EHTCAP_PHY_TRIGCQIFB_GET(phy_cap), + WMI_EHTCAP_PHY_TRIGMUBFPARTBWFB_GET(phy_cap), + WMI_EHTCAP_PHY_PSRSR_GET(phy_cap), + WMI_EHTCAP_PHY_PWRBSTFACTOR_GET(phy_cap), + WMI_EHTCAP_PHY_4XEHTLTFAND800NSGI_GET(phy_cap)); + wma_nofl_debug(" Max Nc 0x%04x, Non-Triggered CQI FB 0x%01x, 1024-QAM 4096-QAM < 242-tone RU: TX 0x%01x RX 0x%01x, PPE Thresholds 0x%01x, Common Nominal Packet Padding 0x%02x", + WMI_EHTCAP_PHY_MAXNC_GET(phy_cap), + WMI_EHTCAP_PHY_NONTRIGCQIFB_GET(phy_cap), + WMI_EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_GET(phy_cap), + WMI_EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_GET(phy_cap), + WMI_EHTCAP_PHY_PPETHRESPRESENT_GET(phy_cap), + WMI_EHTCAP_PHY_CMNNOMPKTPAD_GET(phy_cap)); + wma_nofl_debug(" Max No. Supp LTFs 0x%05x, MCS 15 0x%04x, EHT DUP 6 GHz 0x%01x, 20MHz STA RX NDP Wider BW 0x%01x, Non-OFDMA UL MU-MIMO: LE 80MHz 0x%01x 160 MHz 0x%01x 320Mhz 0x%01x", + WMI_EHTCAP_PHY_MAXNUMEHTLTF_GET(phy_cap), + WMI_EHTCAP_PHY_SUPMCS15_GET(phy_cap), + WMI_EHTCAP_PHY_EHTDUPIN6GHZ_GET(phy_cap), + WMI_EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_GET(phy_cap), + WMI_EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_GET(phy_cap)); + wma_nofl_debug(" MUBfmer: LE 80MHz 0x%01x 160MHz 0x%01x 320Mhz 0x%01x, TB sound FBRL 0x%01x, WBW DLOFDMA Rx: 1024QAM 0x%01x 4096QAM 0x%01x, 20MHz: Lim Cap 0x%01x Trig MUBfing BWFB DLMU 0x%01x M-RU 0x%01x", + WMI_EHTCAP_PHY_MUBFMRLT80MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_MUBFMR160MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_MUBFMR320MHZ_GET(phy_cap), + WMI_EHTCAP_PHY_TBSUNDFBRATELIMIT_GET(phy_cap), + WMI_EHTCAP_PHY_RX1024QAMWIDERBWDLOFDMA_GET(phy_cap), + WMI_EHTCAP_PHY_RX4096QAMWIDERBWDLOFDMA_GET(phy_cap), + WMI_EHTCAP_PHY_20MHZ_ONLY_CAPS_GET(phy_cap), + WMI_EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_GET(phy_cap), + WMI_EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_GET(phy_cap)); +} + +void wma_print_eht_mac_cap(uint32_t *mac_cap) +{ + wma_debug("EHT MAC Cap: EPCS Priority Access: 0x%01x OM Control: 0x%01x, Trig TXOP Sharing: mode1 0x%01x mode2 0x%01x, Restricted TWT 0x%01x SCS Traffic Desc 0x%01x", + WMI_EHTCAP_MAC_EPCSPRIACCESS_GET(mac_cap), + WMI_EHTCAP_MAC_EHTOMCTRL_GET(mac_cap), + WMI_EHTCAP_MAC_TRIGTXOPMODE1_GET(mac_cap), + WMI_EHTCAP_MAC_TRIGTXOPMODE2_GET(mac_cap), + WMI_EHTCAP_MAC_RESTRICTTWT_GET(mac_cap), + WMI_EHTCAP_MAC_SCSTRAFFICDESC_GET(mac_cap)); + wma_nofl_debug(" Max MPDU len 0x%01x, Max A-MPDU Len Exponent Ext 0x%01x EHT TRS 0x%01x, OP In TXOP Sharing Mode2 0x%01x, Two BQRs 0x%01x, EHT Link Adaptation 0x%01x", + WMI_EHTCAP_MAC_MAXMPDULEN_GET(mac_cap), + WMI_EHTCAP_MAC_MAXAMPDULEN_EXP_GET(mac_cap), + WMI_EHTCAP_MAC_TRS_SUPPORT_GET(mac_cap), + WMI_EHTCAP_MAC_TXOP_RETURN_SUPP_IN_SHARINGMODE2_GET(mac_cap), + WMI_EHTCAP_MAC_TWO_BQRS_SUPP_GET(mac_cap), + WMI_EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_GET(mac_cap)); +} + +void wma_print_eht_op(tDot11fIEeht_op *eht_ops) +{ +} + +void wma_populate_peer_eht_cap(struct peer_assoc_params *peer, + tpAddStaParams params) +{ + tDot11fIEeht_cap *eht_cap = ¶ms->eht_config; + uint32_t *phy_cap = peer->peer_eht_cap_phyinfo; + uint32_t *mac_cap = peer->peer_eht_cap_macinfo; + struct supported_rates *rates; + + if (!params->eht_capable) + return; + + peer->eht_flag = 1; + peer->qos_flag = 1; + + /* EHT MAC Capabilities */ + WMI_EHTCAP_MAC_EPCSPRIACCESS_SET(mac_cap, eht_cap->epcs_pri_access); + WMI_EHTCAP_MAC_EHTOMCTRL_SET(mac_cap, eht_cap->eht_om_ctl); + WMI_EHTCAP_MAC_TRIGTXOPMODE1_SET(mac_cap, + eht_cap->triggered_txop_sharing_mode1); + WMI_EHTCAP_MAC_TRIGTXOPMODE2_SET(mac_cap, + eht_cap->triggered_txop_sharing_mode2); + WMI_EHTCAP_MAC_RESTRICTTWT_SET(mac_cap, + eht_cap->restricted_twt); + WMI_EHTCAP_MAC_SCSTRAFFICDESC_SET(mac_cap, + eht_cap->scs_traffic_desc); + WMI_EHTCAP_MAC_MAXMPDULEN_SET(mac_cap, + eht_cap->max_mpdu_len); + WMI_EHTCAP_MAC_MAXAMPDULEN_EXP_SET(mac_cap, + eht_cap->max_a_mpdu_len_exponent_ext); + WMI_EHTCAP_MAC_TRS_SUPPORT_SET(mac_cap, + eht_cap->eht_trs_support); + WMI_EHTCAP_MAC_TXOP_RETURN_SUPP_IN_SHARINGMODE2_SET(mac_cap, + eht_cap->txop_return_support_txop_share_m2); + WMI_EHTCAP_MAC_TWO_BQRS_SUPP_SET(mac_cap, + eht_cap->two_bqrs_support); + WMI_EHTCAP_MAC_EHT_LINK_ADAPTATION_SUPP_SET(mac_cap, + eht_cap->eht_link_adaptation_support); + + /* EHT PHY Capabilities */ + WMI_EHTCAP_PHY_320MHZIN6GHZ_SET(phy_cap, eht_cap->support_320mhz_6ghz); + WMI_EHTCAP_PHY_242TONERUBWLT20MHZ_SET(phy_cap, + eht_cap->ru_242tone_wt_20mhz); + WMI_EHTCAP_PHY_NDP4XEHTLTFAND320NSGI_SET( + phy_cap, eht_cap->ndp_4x_eht_ltf_3dot2_us_gi); + WMI_EHTCAP_PHY_PARTIALBWULMU_SET(phy_cap, eht_cap->partial_bw_mu_mimo); + WMI_EHTCAP_PHY_SUBFMR_SET(phy_cap, eht_cap->su_beamformer); + WMI_EHTCAP_PHY_SUBFME_SET(phy_cap, eht_cap->su_beamformee); + WMI_EHTCAP_PHY_BFMESSLT80MHZ_SET(phy_cap, eht_cap->bfee_ss_le_80mhz); + WMI_EHTCAP_PHY_BFMESS160MHZ_SET(phy_cap, eht_cap->bfee_ss_160mhz); + WMI_EHTCAP_PHY_BFMESS320MHZ_SET(phy_cap, eht_cap->bfee_ss_320mhz); + WMI_EHTCAP_PHY_NUMSOUNDLT80MHZ_SET( + phy_cap, eht_cap->num_sounding_dim_le_80mhz); + WMI_EHTCAP_PHY_NUMSOUND160MHZ_SET(phy_cap, + eht_cap->num_sounding_dim_160mhz); + WMI_EHTCAP_PHY_NUMSOUND320MHZ_SET(phy_cap, + eht_cap->num_sounding_dim_320mhz); + WMI_EHTCAP_PHY_NG16SUFB_SET(phy_cap, eht_cap->ng_16_su_feedback); + WMI_EHTCAP_PHY_NG16MUFB_SET(phy_cap, eht_cap->ng_16_mu_feedback); + WMI_EHTCAP_PHY_CODBK42SUFB_SET(phy_cap, eht_cap->cb_sz_4_2_su_feedback); + WMI_EHTCAP_PHY_CODBK75MUFB_SET(phy_cap, eht_cap->cb_sz_7_5_su_feedback); + WMI_EHTCAP_PHY_TRIGSUBFFB_SET(phy_cap, + eht_cap->trig_su_bforming_feedback); + WMI_EHTCAP_PHY_TRIGMUBFPARTBWFB_SET( + phy_cap, eht_cap->trig_mu_bforming_partial_bw_feedback); + WMI_EHTCAP_PHY_TRIGCQIFB_SET(phy_cap, eht_cap->triggered_cqi_feedback); + WMI_EHTCAP_PHY_PARTBWDLMUMIMO_SET(phy_cap, + eht_cap->partial_bw_dl_mu_mimo); + WMI_EHTCAP_PHY_PSRSR_SET(phy_cap, eht_cap->psr_based_sr); + WMI_EHTCAP_PHY_PWRBSTFACTOR_SET(phy_cap, eht_cap->power_boost_factor); + WMI_EHTCAP_PHY_4XEHTLTFAND800NSGI_SET( + phy_cap, eht_cap->eht_mu_ppdu_4x_ltf_0_8_us_gi); + WMI_EHTCAP_PHY_MAXNC_SET(phy_cap, eht_cap->max_nc); + WMI_EHTCAP_PHY_NONTRIGCQIFB_SET(phy_cap, + eht_cap->non_trig_cqi_feedback); + WMI_EHTCAP_PHY_TX1024AND4096QAMLS242TONERU_SET( + phy_cap, eht_cap->tx_1024_4096_qam_lt_242_tone_ru); + WMI_EHTCAP_PHY_RX1024AND4096QAMLS242TONERU_SET( + phy_cap, eht_cap->rx_1024_4096_qam_lt_242_tone_ru); + WMI_EHTCAP_PHY_PPETHRESPRESENT_SET(phy_cap, eht_cap->ppet_present); + WMI_EHTCAP_PHY_CMNNOMPKTPAD_SET(phy_cap, + eht_cap->common_nominal_pkt_padding); + WMI_EHTCAP_PHY_MAXNUMEHTLTF_SET(phy_cap, eht_cap->max_num_eht_ltf); + WMI_EHTCAP_PHY_SUPMCS15_SET(phy_cap, eht_cap->mcs_15); + WMI_EHTCAP_PHY_EHTDUPIN6GHZ_SET(phy_cap, eht_cap->eht_dup_6ghz); + WMI_EHTCAP_PHY_20MHZOPSTARXNDPWIDERBW_SET( + phy_cap, eht_cap->op_sta_rx_ndp_wider_bw_20mhz); + WMI_EHTCAP_PHY_NONOFDMAULMUMIMOLT80MHZ_SET( + phy_cap, eht_cap->non_ofdma_ul_mu_mimo_le_80mhz); + WMI_EHTCAP_PHY_NONOFDMAULMUMIMO160MHZ_SET( + phy_cap, eht_cap->non_ofdma_ul_mu_mimo_160mhz); + WMI_EHTCAP_PHY_NONOFDMAULMUMIMO320MHZ_SET( + phy_cap, eht_cap->non_ofdma_ul_mu_mimo_320mhz); + WMI_EHTCAP_PHY_MUBFMRLT80MHZ_SET(phy_cap, eht_cap->mu_bformer_le_80mhz); + WMI_EHTCAP_PHY_MUBFMR160MHZ_SET(phy_cap, eht_cap->mu_bformer_160mhz); + WMI_EHTCAP_PHY_MUBFMR320MHZ_SET(phy_cap, eht_cap->mu_bformer_320mhz); + WMI_EHTCAP_PHY_TBSUNDFBRATELIMIT_SET(phy_cap, + eht_cap->tb_sounding_feedback_rl); + WMI_EHTCAP_PHY_RX1024QAMWIDERBWDLOFDMA_SET(phy_cap, + eht_cap->rx_1k_qam_in_wider_bw_dl_ofdma); + WMI_EHTCAP_PHY_RX4096QAMWIDERBWDLOFDMA_SET(phy_cap, + eht_cap->rx_4k_qam_in_wider_bw_dl_ofdma); + WMI_EHTCAP_PHY_20MHZ_ONLY_CAPS_SET(phy_cap, + eht_cap->limited_cap_support_20mhz); + WMI_EHTCAP_PHY_20MHZ_ONLY_TRIGGER_MUBF_FULL_BW_FB_AND_DLMUMIMO_SET(phy_cap, + eht_cap->triggered_mu_bf_full_bw_fb_and_dl_mumimo); + WMI_EHTCAP_PHY_20MHZ_ONLY_MRU_SUPP_SET(phy_cap, + eht_cap->mru_support_20mhz); + + peer->peer_eht_mcs_count = 0; + rates = ¶ms->supportedRates; + + /* + * Convert eht mcs to firmware understandable format + * BITS 0:3 indicates support for mcs 0 to 7 + * BITS 4:7 indicates support for mcs 8 and 9 + * BITS 8:11 indicates support for mcs 10 and 11 + * BITS 12:15 indicates support for mcs 12 and 13 + */ + switch (params->ch_width) { + case CH_WIDTH_320MHZ: + peer->peer_eht_mcs_count++; + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 0, 4, rates->bw_320_rx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 0, 4, rates->bw_320_tx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 4, 4, rates->bw_320_rx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 4, 4, rates->bw_320_tx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 8, 4, rates->bw_320_rx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 8, 4, rates->bw_320_tx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 12, 4, rates->bw_320_rx_max_nss_for_mcs_12_and_13); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX2], + 12, 4, rates->bw_320_tx_max_nss_for_mcs_12_and_13); + fallthrough; + case CH_WIDTH_160MHZ: + peer->peer_eht_mcs_count++; + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 0, 4, rates->bw_160_rx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 0, 4, rates->bw_160_tx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 4, 4, rates->bw_160_rx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 4, 4, rates->bw_160_tx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 8, 4, rates->bw_160_rx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 8, 4, rates->bw_160_rx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 12, 4, rates->bw_160_rx_max_nss_for_mcs_12_and_13); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX1], + 12, 4, rates->bw_160_tx_max_nss_for_mcs_12_and_13); + fallthrough; + case CH_WIDTH_80MHZ: + case CH_WIDTH_40MHZ: + peer->peer_eht_mcs_count++; + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 0, 4, rates->bw_le_80_rx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 0, 4, rates->bw_le_80_tx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 4, 4, rates->bw_le_80_rx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 4, 4, rates->bw_le_80_tx_max_nss_for_mcs_0_to_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 8, 4, rates->bw_le_80_rx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 8, 4, rates->bw_le_80_tx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 12, 4, rates->bw_le_80_rx_max_nss_for_mcs_12_and_13); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 12, 4, rates->bw_le_80_rx_max_nss_for_mcs_12_and_13); + break; + case CH_WIDTH_20MHZ: + peer->peer_eht_mcs_count++; + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 0, 4, rates->bw_20_rx_max_nss_for_mcs_0_to_7); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 0, 4, rates->bw_20_tx_max_nss_for_mcs_0_to_7); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 4, 4, rates->bw_20_rx_max_nss_for_mcs_8_and_9); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 4, 4, rates->bw_20_tx_max_nss_for_mcs_8_and_9); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 8, 4, rates->bw_20_rx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 8, 4, rates->bw_20_tx_max_nss_for_mcs_10_and_11); + QDF_SET_BITS(peer->peer_eht_rx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 12, 4, rates->bw_20_rx_max_nss_for_mcs_12_and_13); + QDF_SET_BITS(peer->peer_eht_tx_mcs_set[EHTCAP_TXRX_MCS_NSS_IDX0], + 12, 4, rates->bw_20_tx_max_nss_for_mcs_12_and_13); + break; + default: + break; + } + + wma_print_eht_cap(eht_cap); + wma_debug("Peer EHT Capabilities:"); + wma_print_eht_phy_cap(phy_cap); + wma_print_eht_mac_cap(mac_cap); +} + +void wma_vdev_set_eht_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct vdev_mlme_eht_ops_info *eht_info) +{ + if (!eht_info->eht_ops) + return; +} + +QDF_STATUS wma_get_eht_capabilities(struct eht_capability *eht_cap) +{ + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(eht_cap->phy_cap, + &wma_handle->eht_cap.phy_cap, + WMI_MAX_EHTCAP_PHY_SIZE); + eht_cap->mac_cap = wma_handle->eht_cap.mac_cap; + return QDF_STATUS_SUCCESS; +} + +void wma_set_peer_assoc_params_bw_320(struct peer_assoc_params *params, + enum phy_ch_width ch_width) +{ + if (ch_width == CH_WIDTH_320MHZ) + params->bw_320 = 1; +} + +void wma_set_eht_txbf_cfg(struct mac_context *mac, uint8_t vdev_id) +{ + wma_set_eht_txbf_params( + vdev_id, mac->mlme_cfg->eht_caps.dot11_eht_cap.su_beamformer, + mac->mlme_cfg->eht_caps.dot11_eht_cap.su_beamformee, + mac->mlme_cfg->eht_caps.dot11_eht_cap.mu_bformer_le_80mhz || + mac->mlme_cfg->eht_caps.dot11_eht_cap.mu_bformer_160mhz || + mac->mlme_cfg->eht_caps.dot11_eht_cap.mu_bformer_320mhz); +} + +void wma_set_eht_txbf_params(uint8_t vdev_id, bool su_bfer, + bool su_bfee, bool mu_bfer) +{ + uint32_t ehtmu_mode = 0; + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return; + + if (su_bfer) + WMI_VDEV_EHT_SUBFER_ENABLE(ehtmu_mode); + if (su_bfee) { + WMI_VDEV_EHT_SUBFEE_ENABLE(ehtmu_mode); + WMI_VDEV_EHT_MUBFEE_ENABLE(ehtmu_mode); + } + if (mu_bfer) + WMI_VDEV_EHT_MUBFER_ENABLE(ehtmu_mode); + + WMI_VDEV_EHT_DLOFDMA_ENABLE(ehtmu_mode); + WMI_VDEV_EHT_ULOFDMA_ENABLE(ehtmu_mode); + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_set_eht_mu_mode, ehtmu_mode); + wma_debug("set EHTMU_MODE (ehtmu_mode = 0x%x)", ehtmu_mode); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set EHTMU_MODE(status = %d)", status); +} + +QDF_STATUS wma_set_bss_rate_flags_eht(enum tx_rate_info *rate_flags, + struct bss_params *add_bss) +{ + if (!add_bss->eht_capable) + return QDF_STATUS_E_NOSUPPORT; + + *rate_flags |= wma_get_eht_rate_flags(add_bss->ch_width); + + wma_debug("ehe_capable %d rate_flags 0x%x", add_bss->eht_capable, + *rate_flags); + return QDF_STATUS_SUCCESS; +} + +bool wma_get_bss_eht_capable(struct bss_params *add_bss) +{ + return add_bss->eht_capable; +} + +enum tx_rate_info wma_get_eht_rate_flags(enum phy_ch_width ch_width) +{ + enum tx_rate_info rate_flags = 0; + + if (ch_width == CH_WIDTH_320MHZ) + rate_flags |= TX_RATE_EHT320 | TX_RATE_EHT160 | + TX_RATE_EHT80 | TX_RATE_EHT40 | TX_RATE_EHT20; + else if (ch_width == CH_WIDTH_160MHZ || ch_width == CH_WIDTH_80P80MHZ) + rate_flags |= TX_RATE_EHT160 | TX_RATE_EHT80 | TX_RATE_EHT40 | + TX_RATE_EHT20; + else if (ch_width == CH_WIDTH_80MHZ) + rate_flags |= TX_RATE_EHT80 | TX_RATE_EHT40 | TX_RATE_EHT20; + else if (ch_width) + rate_flags |= TX_RATE_EHT40 | TX_RATE_EHT20; + else + rate_flags |= TX_RATE_EHT20; + + return rate_flags; +} + +uint16_t wma_match_eht_rate(uint16_t raw_rate, + enum tx_rate_info rate_flags, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag, + uint8_t *p_index) +{ + uint8_t index; + uint8_t dcm_index_max = 1; + uint8_t dcm_index; + uint16_t match_rate = 0; + const uint16_t *nss1_rate; + const uint16_t *nss2_rate; + + *p_index = 0; + if (!(rate_flags & (TX_RATE_EHT320 | TX_RATE_EHT160 | TX_RATE_EHT80 | + TX_RATE_EHT40 | TX_RATE_EHT20))) + return 0; + + for (index = 0; index < QDF_ARRAY_SIZE(eht_mcs_nss1); index++) { + dcm_index_max = IS_MCS_HAS_DCM_RATE(index) ? 2 : 1; + for (dcm_index = 0; dcm_index < dcm_index_max; dcm_index++) { + if (rate_flags & TX_RATE_EHT320) { + nss1_rate = &eht_mcs_nss1[index].supported_eht320_rate[dcm_index][0]; + nss2_rate = &eht_mcs_nss2[index].supported_eht320_rate[dcm_index][0]; + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + if (match_rate) + goto rate_found; + } + if (rate_flags & TX_RATE_EHT160) { + nss1_rate = &eht_mcs_nss1[index].supported_eht160_rate[dcm_index][0]; + nss2_rate = &eht_mcs_nss2[index].supported_eht160_rate[dcm_index][0]; + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + if (match_rate) + goto rate_found; + } + + if (rate_flags & (TX_RATE_EHT80 | TX_RATE_EHT160)) { + nss1_rate = &eht_mcs_nss1[index].supported_eht80_rate[dcm_index][0]; + nss2_rate = &eht_mcs_nss2[index].supported_eht80_rate[dcm_index][0]; + /* check for he80 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + if (match_rate) { + *mcs_rate_flag &= ~TX_RATE_EHT160; + goto rate_found; + } + } + + if (rate_flags & (TX_RATE_EHT40 | TX_RATE_EHT80 | + TX_RATE_EHT160)) { + nss1_rate = &eht_mcs_nss1[index].supported_eht40_rate[dcm_index][0]; + nss2_rate = &eht_mcs_nss2[index].supported_eht40_rate[dcm_index][0]; + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + + if (match_rate) { + *mcs_rate_flag &= ~(TX_RATE_EHT80 | + TX_RATE_EHT160); + goto rate_found; + } + } + + if (rate_flags & (TX_RATE_EHT80 | TX_RATE_EHT40 | + TX_RATE_EHT20 | TX_RATE_EHT160)) { + nss1_rate = &eht_mcs_nss1[index].supported_eht20_rate[dcm_index][0]; + nss2_rate = &eht_mcs_nss2[index].supported_eht20_rate[dcm_index][0]; + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + + if (match_rate) { + *mcs_rate_flag &= TX_RATE_EHT20; + goto rate_found; + } + } + } + } + +rate_found: + if (match_rate) { + if (dcm_index == 1) + *dcm = 1; + *p_index = index; + } + return match_rate; +} + +QDF_STATUS +wma_set_eht_txbf_vdev_params(struct mac_context *mac, uint32_t *mode) +{ + uint32_t ehtmu_mode = 0; + bool su_bfer = mac->mlme_cfg->eht_caps.dot11_eht_cap.su_beamformer; + bool su_bfee = mac->mlme_cfg->eht_caps.dot11_eht_cap.su_beamformee; + bool mu_bfer = + (mac->mlme_cfg->eht_caps.dot11_eht_cap.mu_bformer_le_80mhz || + mac->mlme_cfg->eht_caps.dot11_eht_cap.mu_bformer_160mhz || + mac->mlme_cfg->eht_caps.dot11_eht_cap.mu_bformer_320mhz); + + if (su_bfer) + WMI_VDEV_EHT_SUBFER_ENABLE(ehtmu_mode); + if (su_bfee) { + WMI_VDEV_EHT_SUBFEE_ENABLE(ehtmu_mode); + WMI_VDEV_EHT_MUBFEE_ENABLE(ehtmu_mode); + } + if (mu_bfer) + WMI_VDEV_EHT_MUBFER_ENABLE(ehtmu_mode); + WMI_VDEV_EHT_DLOFDMA_ENABLE(ehtmu_mode); + WMI_VDEV_EHT_ULOFDMA_ENABLE(ehtmu_mode); + wma_debug("set EHTMU_MODE (ehtmu_mode = 0x%x)", + ehtmu_mode); + *mode = ehtmu_mode; + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +void wma_vdev_set_listen_interval(uint8_t vdev_id, uint8_t val) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_listen_interval, val); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set Listen interval for vdev: %d", vdev_id); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_eht.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_eht.h new file mode 100644 index 0000000000..5c79b83ca3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_eht.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_EHT_H +#define __WMA_EHT_H + +#include "wma.h" + +enum EHT_TXRX_MCS_NSS_IDX { + EHTCAP_TXRX_MCS_NSS_IDX0, + EHTCAP_TXRX_MCS_NSS_IDX1, + EHTCAP_TXRX_MCS_NSS_IDX2, + EHTCAP_TXRX_MCS_NSS_IDXMAX, +}; + +#if defined(WLAN_FEATURE_11BE) +#define MAX_EHT_DCM_INDEX 2 +/* valid only for mcs-15 */ +#define IS_EHT_ MCS_HAS_DCM_RATE(val) ((val) == 15) +/** + * struct index_eht_data_rate_type - eht data rate type + * @beacon_rate_index: Beacon rate index + * @supported_eht20_rate: eht20 rate + * @supported_eht40_rate: eht40 rate + * @supported_eht80_rate: eht80 rate + * @supported_eht160_rate: eht160 rate + */ +struct index_eht_data_rate_type { + uint8_t beacon_rate_index; + uint16_t supported_eht20_rate[MAX_EHT_DCM_INDEX][3]; + uint16_t supported_eht40_rate[MAX_EHT_DCM_INDEX][3]; + uint16_t supported_eht80_rate[MAX_EHT_DCM_INDEX][3]; + uint16_t supported_eht160_rate[MAX_EHT_DCM_INDEX][3]; + uint16_t supported_eht320_rate[MAX_EHT_DCM_INDEX][3]; +}; + +/* + * wma_eht_update_tgt_services() - update tgt cfg to indicate 11be support + * @wmi_handle: pointer to WMI handle + * @cfg: pointer to WMA target services + * + * Based on WMI SERVICES information, enable 11be support and set DOT11BE + * bit in feature caps bitmap. + * + * Return: None + */ +void wma_eht_update_tgt_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg); +/** + * wma_update_target_ext_eht_cap() - Update EHT caps with given extended cap + * @tgt_hdl: target psoc information + * @tgt_cfg: Target config + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * EHT caps and derives the final cap. + * + * Return: None + */ +void wma_update_target_ext_eht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg); + +void wma_update_vdev_eht_ops(uint32_t *eht_ops, tDot11fIEeht_op *eht_op); + +/** + * wma_print_eht_cap() - Print EHT capabilities + * @eht_cap: pointer to EHT Capability + * + * Received EHT capabilities are converted into dot11f structure. + * This function will print all the EHT capabilities as stored + * in the dot11f structure. + * + * Return: None + */ +void wma_print_eht_cap(tDot11fIEeht_cap *eht_cap); + +/** + * wma_print_eht_phy_cap() - Print EHT PHY Capability + * @phy_cap: pointer to PHY Capability + * + * This function prints EHT PHY Capability received from FW. + * + * Return: none + */ +void wma_print_eht_phy_cap(uint32_t *phy_cap); + +/** + * wma_print_eht_mac_cap() - Print EHT MAC Capability + * @mac_cap: pointer to MAC Capability + * + * This function prints EHT MAC Capability received from FW. + * + * Return: none + */ +void wma_print_eht_mac_cap(uint32_t *mac_cap); + +/** + * wma_print_eht_op() - Print EHT Operation + * @eht_cap: pointer to EHT Operation + * + * Print EHT operation stored as dot11f structure + * + * Return: None + */ +void wma_print_eht_op(tDot11fIEeht_op *eht_ops); + +/** + * wma_populate_peer_eht_cap() - populate peer EHT capabilities in + * peer assoc cmd + * @peer: pointer to peer assoc params + * @params: pointer to ADD STA params + * + * Return: None + */ +void wma_populate_peer_eht_cap(struct peer_assoc_params *peer, + tpAddStaParams params); + +/** + * wma_vdev_set_eht_bss_params() - set EHT OPs in vdev start + * @wma: pointer to wma handle + * @vdev_id: VDEV id + * @eht_info: pointer to eht info + * + * Return: None + */ +void wma_vdev_set_eht_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct vdev_mlme_eht_ops_info *eht_info); + +/** + * wma_is_peer_eht_capable() - whether peer is eht capable or not + * @params: add sta params + * + * Return: true if eht capable is present + */ +static inline bool wma_is_peer_eht_capable(tpAddStaParams params) +{ + return params->eht_capable; +} + +/** + * wma_get_eht_capabilities() - Get EHT capabilities from WMA + * @eht_cap: Pointer to EHT capabilities + * + * Currently EHT capabilities are not updated in wma_handle. This + * is an interface for upper layer to query capabilities from WMA. + * When the real use case arise, update wma_handle with EHT capabilities + * as required. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_get_eht_capabilities(struct eht_capability *eht_cap); + +/** + * wma_set_peer_assoc_params_bw_320() - Set bw_320 based on ch_width + * @params: pointer to peer assoc params + * @ch_width: enum phy_ch_width + * + * If ch_width is CH_WIDTH_320MHZ, set params->bw_320 to 1 + * + * Return: None + */ +void wma_set_peer_assoc_params_bw_320(struct peer_assoc_params *params, + enum phy_ch_width ch_width); + +/** + * wma_set_eht_txbf_cfg() - set EHT Tx beamforming mlme cfg to FW + * @mac: Global MAC context + * @vdev_id: VDEV id + * + * Return: None + */ +void wma_set_eht_txbf_cfg(struct mac_context *mac, uint8_t vdev_id); + +/** + * wma_set_eht_txbf_params() - set EHT Tx beamforming params to FW + * @vdev_id: VDEV id + * @su bfer: SU beamformer capability + * @su bfee: SU beamformee capability + * @mu bfer: MU beamformer capability + * + * Return: None + */ +void wma_set_eht_txbf_params(uint8_t vdev_id, bool su_bfer, + bool su_bfee, bool mu_bfer); + +/** + * wma_get_eht_rate_flags() - Return the EHT rate flags corresponding to the BW + * @ch_width: BW for which rate flags is required + * + * Return: Rate flags corresponding to ch_width + */ +enum tx_rate_info wma_get_eht_rate_flags(enum phy_ch_width ch_width); + +/** + * wma_match_eht_rate() - get eht rate matching with nss + * @raw_rate: raw rate from fw + * @rate_flags: rate flags + * @nss: nss + * @dcm: dcm + * @guard_interval: guard interval + * @mcs_rate_flag: mcs rate flags + * @p_index: index for matched rate + * + * Return: return match rate if found, else 0 + */ +uint16_t wma_match_eht_rate(uint16_t raw_rate, + enum tx_rate_info rate_flags, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag, + uint8_t *p_index); + +/** + * wma_set_bss_rate_flags_eht() - set rate flags based on BSS capability + * @rate_flags: rate_flags pointer + * @add_bss: add_bss params + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_bss_rate_flags_eht(enum tx_rate_info *rate_flags, + struct bss_params *add_bss); + +/** + * wma_get_bss_eht_capable() - whether bss is eht capable or not + * @add_bss: add_bss params + * + * Return: true if eht capable is present + */ +bool wma_get_bss_eht_capable(struct bss_params *add_bss); + +static +inline bool wma_is_eht_phymode_supported(enum wlan_phymode bss_phymode) +{ + return IS_WLAN_PHYMODE_EHT(bss_phymode); +} + +/** + * wma_set_eht_txbf_vdev_params() - set EHT Tx beamforming params to FW + * @mac: mac context + * @mode: mode address to access mode value + * + * Return: success + */ +QDF_STATUS +wma_set_eht_txbf_vdev_params(struct mac_context *mac, uint32_t *mode); + +#else +static inline void wma_eht_update_tgt_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_11be = false; + return; +} + +static inline +void wma_update_target_ext_eht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg) +{ +} + +static inline +void wma_update_vdev_eht_ops(uint32_t *eht_ops, tDot11fIEeht_op *eht_op) +{ +} + +static inline +void wma_print_eht_cap(tDot11fIEeht_cap *eht_cap) +{ +} + +static inline +void wma_print_eht_phy_cap(uint32_t *phy_cap) +{ +} + +static inline +void wma_print_eht_mac_cap(uint32_t *mac_cap) +{ +} + +static inline +void wma_print_eht_op(tDot11fIEeht_op *eht_ops) +{ +} + +static inline +void wma_populate_peer_eht_cap(struct peer_assoc_params *peer, + tpAddStaParams params) +{ +} + +static inline bool wma_is_peer_eht_capable(tpAddStaParams params) +{ + return false; +} + +static inline +void wma_set_peer_assoc_params_bw_320(struct peer_assoc_params *params, + enum phy_ch_width ch_width) +{ +} + +static inline +void wma_set_eht_txbf_cfg(struct mac_context *mac, uint8_t vdev_id) +{ +} + +static inline +void wma_set_eht_txbf_params(uint8_t vdev_id, bool su_bfer, + bool su_bfee, bool mu_bfer) +{ +} + +static inline +QDF_STATUS wma_set_bss_rate_flags_eht(enum tx_rate_info *rate_flags, + struct bss_params *add_bss) +{ + return QDF_STATUS_E_INVAL; +} + +static inline +enum tx_rate_info wma_get_eht_rate_flags(enum phy_ch_width ch_width) +{ + return TX_RATE_EHT20; +} + +static inline +uint16_t wma_match_eht_rate(uint16_t raw_rate, + enum tx_rate_info rate_flags, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag, + uint8_t *p_index) +{ + return 0; +} + +static inline +bool wma_get_bss_eht_capable(struct bss_params *add_bss) +{ + return false; +} + +static inline bool wma_is_eht_phymode_supported(enum wlan_phymode bss_phymode) +{ + return false; +} + +static inline +QDF_STATUS wma_set_eht_txbf_vdev_params(struct mac_context *mac, uint32_t *mode) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +void wma_vdev_set_listen_interval(uint8_t vdev_id, uint8_t val); +#else +static inline +void wma_vdev_set_listen_interval(uint8_t vdev_id, uint8_t val) +{} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_features.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_features.c new file mode 100644 index 0000000000..0248caa146 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_features.c @@ -0,0 +1,6338 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_features.c + * This file contains different features related functions like WoW, + * Offloads, TDLS etc. + */ + +/* Header files */ + +#include "cds_ieee80211_common.h" /* ieee80211_frame */ +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include +#include + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "qdf_util.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" +#include "cfg_ucfg_api.h" +#include "cds_utils.h" +#include "cfg_qos.h" +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "wma_internal.h" +#include "wma_nan_datapath.h" +#include +#include "wlan_pmo_ucfg_api.h" +#include +#include "wlan_reg_services_api.h" +#include "wlan_roam_debug.h" +#include +#ifdef WLAN_FEATURE_NAN +#include "target_if_nan.h" +#endif +#include "wlan_scan_api.h" +#include "spatial_reuse_api.h" +#include "wlan_cm_api.h" +#include +#include "cdp_txrx_host_stats.h" +#include "target_if_cm_roam_event.h" +#include +#include "hif.h" +#include "wlan_cmn_ieee80211.h" +#include "wlan_mlo_mgr_cmn.h" +#include "wlan_mlo_mgr_peer.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_cp_stats_mc_defs.h" + + +/** + * WMA_SET_VDEV_IE_SOURCE_HOST - Flag to identify the source of VDEV SET IE + * command. The value is 0x0 for the VDEV SET IE WMI commands from mobile + * MCL platform. + */ +#define WMA_SET_VDEV_IE_SOURCE_HOST 0x0 + +/* + * Max AMPDU Tx Aggr supported size + */ +#define ADDBA_TXAGGR_SIZE_HELIUM 64 +#define ADDBA_TXAGGR_SIZE_LITHIUM 256 +#define ADDBA_TXAGGR_SIZE_512 512 +#define ADDBA_TXAGGR_SIZE_BERYLLIUM 1024 + +static bool is_wakeup_event_console_logs_enabled = false; + +void wma_set_wakeup_logs_to_console(bool value) +{ + is_wakeup_event_console_logs_enabled = value; +} + +#if defined(FEATURE_WLAN_DIAG_SUPPORT) +/** + * qdf_wma_wow_wakeup_stats_event()- send wow wakeup stats + * @tp_wma_handle wma: WOW wakeup packet counter + * + * This function sends wow wakeup stats diag event + * + * Return: void. + */ +static inline void qdf_wma_wow_wakeup_stats_event(tp_wma_handle wma) +{ + QDF_STATUS status; + struct wake_lock_stats stats = {0}; + + WLAN_HOST_DIAG_EVENT_DEF(wow_stats, + struct host_event_wlan_powersave_wow_stats); + + status = ucfg_mc_cp_stats_get_psoc_wake_lock_stats(wma->psoc, &stats); + if (QDF_IS_STATUS_ERROR(status)) + return; + qdf_mem_zero(&wow_stats, sizeof(wow_stats)); + + wow_stats.wow_bcast_wake_up_count = stats.bcast_wake_up_count; + wow_stats.wow_ipv4_mcast_wake_up_count = stats.ipv4_mcast_wake_up_count; + wow_stats.wow_ipv6_mcast_wake_up_count = stats.ipv6_mcast_wake_up_count; + wow_stats.wow_ipv6_mcast_ra_stats = stats.ipv6_mcast_ra_stats; + wow_stats.wow_ipv6_mcast_ns_stats = stats.ipv6_mcast_ns_stats; + wow_stats.wow_ipv6_mcast_na_stats = stats.ipv6_mcast_na_stats; + wow_stats.wow_pno_match_wake_up_count = stats.pno_match_wake_up_count; + wow_stats.wow_pno_complete_wake_up_count = + stats.pno_complete_wake_up_count; + wow_stats.wow_gscan_wake_up_count = stats.gscan_wake_up_count; + wow_stats.wow_low_rssi_wake_up_count = stats.low_rssi_wake_up_count; + wow_stats.wow_rssi_breach_wake_up_count = + stats.rssi_breach_wake_up_count; + wow_stats.wow_icmpv4_count = stats.icmpv4_count; + wow_stats.wow_icmpv6_count = stats.icmpv6_count; + wow_stats.wow_oem_response_wake_up_count = + stats.oem_response_wake_up_count; + + WLAN_HOST_DIAG_EVENT_REPORT(&wow_stats, EVENT_WLAN_POWERSAVE_WOW_STATS); +} +#else +static inline void qdf_wma_wow_wakeup_stats_event(tp_wma_handle wma) +{ + return; +} +#endif + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_wake_reason_auto_shutdown() - to post auto shutdown event to sme + * + * Return: 0 for success or error code + */ +static int wma_wake_reason_auto_shutdown(void) +{ + QDF_STATUS qdf_status; + struct scheduler_msg sme_msg = { 0 }; + + sme_msg.type = eWNI_SME_AUTO_SHUTDOWN_IND; + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + wma_err("Fail to post eWNI_SME_AUTO_SHUTDOWN_IND msg to SME"); + + return qdf_status_to_os_return(qdf_status); +} +#else +static inline int wma_wake_reason_auto_shutdown(void) +{ + return 0; +} +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + +#ifdef FEATURE_WLAN_SCAN_PNO +static int wma_wake_reason_nlod(t_wma_handle *wma, uint8_t vdev_id) +{ + wmi_nlo_event nlo_event = { .vdev_id = vdev_id }; + WMI_NLO_MATCH_EVENTID_param_tlvs param = { .fixed_param = &nlo_event }; + + return target_if_nlo_match_event_handler(wma, (uint8_t *)¶m, + sizeof(param)); +} +#else +static inline int wma_wake_reason_nlod(t_wma_handle *wma, uint8_t vdev_id) +{ + return 0; +} +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_rsp_handler_callback() - call NAN Discovery event handler + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +static int wma_nan_rsp_handler_callback(void *handle, uint8_t *event, + uint32_t len) +{ + return target_if_nan_rsp_handler(handle, event, len); +} +#else +static inline int wma_nan_rsp_handler_callback(void *handle, uint8_t *event, + uint32_t len) +{ + return 0; +} +#endif + +/** + * wma_get_snr() - get RSSI from fw + * @psnr_req: request params + * + * Return: QDF status + */ +QDF_STATUS wma_get_snr(tAniGetSnrReq *psnr_req) +{ + tAniGetSnrReq *psnr_req_bkp; + tp_wma_handle wma_handle = NULL; + struct wma_txrx_node *intr; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAULT; + + intr = &wma_handle->interfaces[psnr_req->sessionId]; + /* command is in progress */ + if (intr->psnr_req) { + wma_err("previous snr request is pending"); + return QDF_STATUS_SUCCESS; + } + + psnr_req_bkp = qdf_mem_malloc(sizeof(tAniGetSnrReq)); + if (!psnr_req_bkp) + return QDF_STATUS_E_NOMEM; + + qdf_mem_zero(psnr_req_bkp, sizeof(tAniGetSnrReq)); + psnr_req_bkp->pDevContext = psnr_req->pDevContext; + psnr_req_bkp->snrCallback = psnr_req->snrCallback; + intr->psnr_req = (void *)psnr_req_bkp; + + if (wmi_unified_snr_cmd(wma_handle->wmi_handle, + psnr_req->sessionId)) { + wma_err("Failed to send host stats request to fw"); + qdf_mem_free(psnr_req_bkp); + intr->psnr_req = NULL; + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +void wma_get_rx_retry_cnt(struct mac_context *mac, uint8_t vdev_id, + uint8_t *mac_addr) +{ + struct cdp_peer_stats *peer_stats; + QDF_STATUS status; + + peer_stats = qdf_mem_malloc(sizeof(*peer_stats)); + if (!peer_stats) + return; + + status = cdp_host_get_peer_stats(cds_get_context(QDF_MODULE_ID_SOC), + vdev_id, mac_addr, peer_stats); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get peer stats"); + goto exit; + } + + mac->rx_retry_cnt = peer_stats->rx.rx_retries; + wma_debug("Rx retry count %d, Peer" QDF_MAC_ADDR_FMT, mac->rx_retry_cnt, + QDF_MAC_ADDR_REF(mac_addr)); + +exit: + qdf_mem_free(peer_stats); +} + +/** + * wma_process_link_status_req() - process link status request from UMAC + * @wma: wma handle + * @pGetLinkStatus: get link params + * + * Return: none + */ +void wma_process_link_status_req(tp_wma_handle wma, + tAniGetLinkStatus *pGetLinkStatus) +{ + struct link_status_params cmd = {0}; + struct wma_txrx_node *iface = + &wma->interfaces[pGetLinkStatus->sessionId]; + + if (iface->plink_status_req) { + wma_err("previous link status request is pending,deleting the new request"); + qdf_mem_free(pGetLinkStatus); + return; + } + + iface->plink_status_req = pGetLinkStatus; + cmd.vdev_id = pGetLinkStatus->sessionId; + if (wmi_unified_link_status_req_cmd(wma->wmi_handle, &cmd)) { + wma_err("Failed to send WMI link status request to fw"); + iface->plink_status_req = NULL; + goto end; + } + + return; + +end: + wma_post_link_status(pGetLinkStatus, LINK_STATUS_LEGACY); +} + +#ifdef WLAN_FEATURE_TSF + +#if defined(WLAN_FEATURE_TSF_AUTO_REPORT) || defined(QCA_GET_TSF_VIA_REG) +static inline void +wma_vdev_tsf_set_mac_id_tsf_id(struct stsf *ptsf, uint32_t mac_id, + uint32_t mac_id_valid, uint32_t tsf_id, + uint32_t tsf_id_valid) +{ + ptsf->mac_id = mac_id; + ptsf->mac_id_valid = mac_id_valid; + ptsf->tsf_id = tsf_id; + ptsf->tsf_id_valid = tsf_id_valid; + + wma_nofl_debug("mac_id %d mac_id_valid %d tsf_id %d tsf_id_valid %d", + ptsf->mac_id, ptsf->mac_id_valid, ptsf->tsf_id, + ptsf->tsf_id_valid); +} +#else /* !(WLAN_FEATURE_TSF_AUTO_REPORT || QCA_GET_TSF_VIA_REG) */ +static inline void +wma_vdev_tsf_set_mac_id_tsf_id(struct stsf *ptsf, uint32_t mac_id, + uint32_t mac_id_valid, uint32_t tsf_id, + uint32_t tsf_id_valid) +{ +} +#endif /* WLAN_FEATURE_TSF_AUTO_REPORT || QCA_GET_TSF_VIA_REG */ + +/** + * wma_vdev_tsf_handler() - handle tsf event indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_vdev_tsf_handler(void *handle, uint8_t *data, uint32_t data_len) +{ + struct scheduler_msg tsf_msg = {0}; + WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *param_buf; + wmi_vdev_tsf_report_event_fixed_param *tsf_event; + struct stsf *ptsf; + + if (!data) { + wma_err("invalid pointer"); + return -EINVAL; + } + ptsf = qdf_mem_malloc(sizeof(*ptsf)); + if (!ptsf) + return -ENOMEM; + + param_buf = (WMI_VDEV_TSF_REPORT_EVENTID_param_tlvs *)data; + tsf_event = param_buf->fixed_param; + + ptsf->vdev_id = tsf_event->vdev_id; + ptsf->tsf_low = tsf_event->tsf_low; + ptsf->tsf_high = tsf_event->tsf_high; + ptsf->soc_timer_low = tsf_event->qtimer_low; + ptsf->soc_timer_high = tsf_event->qtimer_high; + ptsf->global_tsf_low = tsf_event->wlan_global_tsf_low; + ptsf->global_tsf_high = tsf_event->wlan_global_tsf_high; + wma_nofl_debug("receive WMI_VDEV_TSF_REPORT_EVENTID on %d, tsf: %d %d", + ptsf->vdev_id, ptsf->tsf_low, ptsf->tsf_high); + + wma_nofl_debug("g_tsf: %d %d; soc_timer: %d %d", + ptsf->global_tsf_low, ptsf->global_tsf_high, + ptsf->soc_timer_low, ptsf->soc_timer_high); + + wma_vdev_tsf_set_mac_id_tsf_id(ptsf, tsf_event->mac_id, + tsf_event->mac_id_valid, + tsf_event->tsf_id, + tsf_event->tsf_id_valid); + tsf_msg.type = eWNI_SME_TSF_EVENT; + tsf_msg.bodyptr = ptsf; + tsf_msg.bodyval = 0; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &tsf_msg)) { + qdf_mem_free(ptsf); + return -EINVAL; + } + return 0; +} + +#if defined(QCA_WIFI_3_0) || defined(WLAN_FEATURE_TSF_TIMER_SYNC) +#define TSF_FW_ACTION_CMD TSF_TSTAMP_QTIMER_CAPTURE_REQ +#else +#define TSF_FW_ACTION_CMD TSF_TSTAMP_CAPTURE_REQ +#endif +/** + * wma_capture_tsf() - send wmi to fw to capture tsf + * @wma_handle: wma handler + * @vdev_id: vdev id + * + * Return: wmi send state + */ +QDF_STATUS wma_capture_tsf(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + QDF_STATUS status; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) wmi_buf_data(buf); + cmd->vdev_id = vdev_id; + cmd->tsf_action = TSF_FW_ACTION_CMD; + wma_debug("vdev_id %u, tsf_cmd: %d", cmd->vdev_id, cmd->tsf_action); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * wma_reset_tsf_gpio() - send wmi to fw to reset GPIO + * @wma_handle: wma handler + * @vdev_id: vdev id + * + * Return: wmi send state + */ +QDF_STATUS wma_reset_tsf_gpio(tp_wma_handle wma_handle, uint32_t vdev_id) +{ + QDF_STATUS status; + wmi_buf_t buf; + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + int len = sizeof(*cmd); + uint8_t *buf_ptr; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *) buf_ptr; + cmd->vdev_id = vdev_id; + cmd->tsf_action = TSF_TSTAMP_CAPTURE_RESET; + + wma_debug("vdev_id %u, TSF_TSTAMP_CAPTURE_RESET", cmd->vdev_id); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * wma_set_tsf_gpio_pin() - send wmi cmd to configure gpio pin + * @handle: wma handler + * @pin: GPIO pin id + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_set_tsf_gpio_pin(WMA_HANDLE handle, uint32_t pin) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + struct pdev_params pdev_param = {0}; + int32_t ret; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + wma_debug("set tsf gpio pin: %d", pin); + + pdev_param.param_id = wmi_pdev_param_wnts_config; + pdev_param.param_value = pin; + ret = wmi_unified_pdev_param_send(wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + if (ret) { + wma_err("Failed to set tsf gpio pin (status=%d)", ret); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_TSF_AUTO_REPORT +QDF_STATUS wma_set_tsf_auto_report(WMA_HANDLE handle, uint32_t vdev_id, + uint32_t param_id, bool ena) +{ + wmi_vdev_tsf_tstamp_action_cmd_fixed_param *cmd; + tp_wma_handle wma = (tp_wma_handle)handle; + struct wmi_unified *wmi_handle; + int len = sizeof(*cmd); + QDF_STATUS status; + uint8_t *buf_ptr; + wmi_buf_t buf; + + if (param_id != GEN_PARAM_TSF_AUTO_REPORT_ENABLE && + param_id != GEN_PARAM_TSF_AUTO_REPORT_DISABLE) + return QDF_STATUS_E_FAILURE; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *)wmi_buf_data(buf); + cmd = (wmi_vdev_tsf_tstamp_action_cmd_fixed_param *)buf_ptr; + cmd->vdev_id = vdev_id; + cmd->tsf_action = ena ? TSF_TSTAMP_AUTO_REPORT_ENABLE : + TSF_TSTAMP_AUTO_REPORT_DISABLE; + + wma_debug("vdev_id %u tsf_action %d", cmd->vdev_id, cmd->tsf_action); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_tsf_tstamp_action_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_tsf_tstamp_action_cmd_fixed_param)); + + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_VDEV_TSF_TSTAMP_ACTION_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} +#endif /* WLAN_FEATURE_TSF_AUTO_REPORT */ +#endif + +/** + * wma_set_wisa_params(): Set WISA features related params in FW + * @wma_handle: WMA handle + * @wisa: Pointer to WISA param struct + * + * Return: CDF status + */ +QDF_STATUS wma_set_wisa_params(tp_wma_handle wma_handle, + struct sir_wisa_params *wisa) +{ + QDF_STATUS status; + wmi_buf_t buf; + wmi_vdev_wisa_cmd_fixed_param *cmd; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_vdev_wisa_cmd_fixed_param *) wmi_buf_data(buf); + cmd->wisa_mode = wisa->mode; + cmd->vdev_id = wisa->vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_wisa_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_wisa_cmd_fixed_param)); + + status = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_WISA_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * wma_process_dhcp_ind() - process dhcp indication from SME + * @wma_handle: wma handle + * @ta_dhcp_ind: DHCP indication + * + * Return: QDF Status + */ +QDF_STATUS wma_process_dhcp_ind(WMA_HANDLE handle, + tAniDHCPInd *ta_dhcp_ind) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + wmi_peer_set_param_cmd_fixed_param peer_set_param_fp = {0}; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + if (!ta_dhcp_ind) { + wma_err("DHCP indication is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (wma_find_vdev_id_by_addr(wma_handle, + ta_dhcp_ind->adapterMacAddr.bytes, + &vdev_id)) { + wma_err("Failed to find vdev id for DHCP indication"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("WMA --> WMI_PEER_SET_PARAM triggered by DHCP, msgType=%s, device_mode=%d, macAddr=" QDF_MAC_ADDR_FMT, + ta_dhcp_ind->msgType == WMA_DHCP_START_IND ? + "WMA_DHCP_START_IND" : "WMA_DHCP_STOP_IND", + ta_dhcp_ind->device_mode, + QDF_MAC_ADDR_REF(ta_dhcp_ind->peerMacAddr.bytes)); + + /* fill in values */ + peer_set_param_fp.vdev_id = vdev_id; + peer_set_param_fp.param_id = WMI_HOST_PEER_CRIT_PROTO_HINT_ENABLED; + if (WMA_DHCP_START_IND == ta_dhcp_ind->msgType) + peer_set_param_fp.param_value = 1; + else + peer_set_param_fp.param_value = 0; + WMI_CHAR_ARRAY_TO_MAC_ADDR(ta_dhcp_ind->peerMacAddr.bytes, + &peer_set_param_fp.peer_macaddr); + + return wmi_unified_process_dhcp_ind(wma_handle->wmi_handle, + &peer_set_param_fp); +} + +#if defined(WLAN_FEATURE_11BE) +static enum wlan_phymode +wma_eht_chan_phy_mode(uint32_t freq, uint8_t dot11_mode, uint16_t bw_val, + enum phy_ch_width chan_width) +{ + if((dot11_mode == MLME_DOT11_MODE_11BE) || + (dot11_mode == MLME_DOT11_MODE_11BE_ONLY)) + { + if (wlan_reg_is_24ghz_ch_freq(freq)) { + if (bw_val == 20) + return WLAN_PHYMODE_11BEG_EHT20; + else if (bw_val == 40) + return WLAN_PHYMODE_11BEG_EHT40; + } else { + if (bw_val == 20) + return WLAN_PHYMODE_11BEA_EHT20; + else if (bw_val == 40) + return WLAN_PHYMODE_11BEA_EHT40; + else if (bw_val == 80) + return WLAN_PHYMODE_11BEA_EHT80; + else if (chan_width == CH_WIDTH_160MHZ) + return WLAN_PHYMODE_11BEA_EHT160; + else if (chan_width == CH_WIDTH_320MHZ) + return WLAN_PHYMODE_11BEA_EHT320; + } + } + + return WLAN_PHYMODE_AUTO; +} +#else +static enum wlan_phymode +wma_eht_chan_phy_mode(uint32_t freq, uint8_t dot11_mode, uint16_t bw_val, + enum phy_ch_width chan_width) +{ + return WLAN_PHYMODE_AUTO; +} +#endif + +enum wlan_phymode wma_chan_phy_mode(uint32_t freq, enum phy_ch_width chan_width, + uint8_t dot11_mode) +{ + enum wlan_phymode phymode = WLAN_PHYMODE_AUTO; + uint16_t bw_val = wlan_reg_get_bw_value(chan_width); + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return WLAN_PHYMODE_AUTO; + + if (chan_width >= CH_WIDTH_INVALID || !bw_val || + (wlan_reg_is_24ghz_ch_freq(freq) && bw_val > 40)) { + wma_err_rl("Invalid channel width %d freq %d", + chan_width, freq); + return WLAN_PHYMODE_AUTO; + } + + if (wlan_reg_is_24ghz_ch_freq(freq)) { + if (((CH_WIDTH_5MHZ == chan_width) || + (CH_WIDTH_10MHZ == chan_width)) && + ((MLME_DOT11_MODE_11B == dot11_mode) || + (MLME_DOT11_MODE_11G == dot11_mode) || + (MLME_DOT11_MODE_11N == dot11_mode) || + (MLME_DOT11_MODE_ALL == dot11_mode) || + (MLME_DOT11_MODE_11AC == dot11_mode) || + (MLME_DOT11_MODE_11AX == dot11_mode))) + phymode = WLAN_PHYMODE_11G; + else { + switch (dot11_mode) { + case MLME_DOT11_MODE_11B: + if ((bw_val == 20) || (bw_val == 40)) + phymode = WLAN_PHYMODE_11B; + break; + case MLME_DOT11_MODE_11G: + if ((bw_val == 20) || (bw_val == 40)) + phymode = WLAN_PHYMODE_11G; + break; + case MLME_DOT11_MODE_11G_ONLY: + if ((bw_val == 20) || (bw_val == 40)) + phymode = WLAN_PHYMODE_11G_ONLY; + break; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11N_ONLY: + if (bw_val == 20) + phymode = WLAN_PHYMODE_11NG_HT20; + else if (bw_val == 40) + phymode = WLAN_PHYMODE_11NG_HT40; + break; + case MLME_DOT11_MODE_ALL: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AC_ONLY: + if (bw_val == 20) + phymode = WLAN_PHYMODE_11AC_VHT20_2G; + else if (bw_val == 40) + phymode = WLAN_PHYMODE_11AC_VHT40_2G; + break; + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11AX_ONLY: + if (20 == bw_val) + phymode = WLAN_PHYMODE_11AXG_HE20; + else if (40 == bw_val) + phymode = WLAN_PHYMODE_11AXG_HE40; + break; + default: + phymode = wma_eht_chan_phy_mode( + freq, + dot11_mode, + bw_val, + chan_width); + break; + } + } + } else if (wlan_reg_is_dsrc_freq(freq)) + phymode = WLAN_PHYMODE_11A; + else { + if (((CH_WIDTH_5MHZ == chan_width) || + (CH_WIDTH_10MHZ == chan_width)) && + ((MLME_DOT11_MODE_11A == dot11_mode) || + (MLME_DOT11_MODE_11N == dot11_mode) || + (MLME_DOT11_MODE_ALL == dot11_mode) || + (MLME_DOT11_MODE_11AC == dot11_mode) || + (MLME_DOT11_MODE_11AX == dot11_mode))) + phymode = WLAN_PHYMODE_11A; + else { + switch (dot11_mode) { + case MLME_DOT11_MODE_11A: + if (0 < bw_val) + phymode = WLAN_PHYMODE_11A; + break; + case MLME_DOT11_MODE_11N: + case MLME_DOT11_MODE_11N_ONLY: + if (bw_val == 20) + phymode = WLAN_PHYMODE_11NA_HT20; + else if (40 <= bw_val) + phymode = WLAN_PHYMODE_11NA_HT40; + break; + case MLME_DOT11_MODE_ALL: + case MLME_DOT11_MODE_11AC: + case MLME_DOT11_MODE_11AC_ONLY: + if (bw_val == 20) + phymode = WLAN_PHYMODE_11AC_VHT20; + else if (bw_val == 40) + phymode = WLAN_PHYMODE_11AC_VHT40; + else if (bw_val == 80) + phymode = WLAN_PHYMODE_11AC_VHT80; + else if (chan_width == CH_WIDTH_160MHZ) + phymode = WLAN_PHYMODE_11AC_VHT160; + else if (chan_width == CH_WIDTH_80P80MHZ) + phymode = WLAN_PHYMODE_11AC_VHT80_80; + break; + case MLME_DOT11_MODE_11AX: + case MLME_DOT11_MODE_11AX_ONLY: + if (20 == bw_val) + phymode = WLAN_PHYMODE_11AXA_HE20; + else if (40 == bw_val) + phymode = WLAN_PHYMODE_11AXA_HE40; + else if (80 == bw_val) + phymode = WLAN_PHYMODE_11AXA_HE80; + else if (CH_WIDTH_160MHZ == chan_width) + phymode = WLAN_PHYMODE_11AXA_HE160; + else if (CH_WIDTH_80P80MHZ == chan_width) + phymode = WLAN_PHYMODE_11AXA_HE80_80; + break; + default: + phymode = wma_eht_chan_phy_mode( + freq, + dot11_mode, + bw_val, + chan_width); + break; + } + } + } + + wma_debug("phymode %d freq %d ch_width %d dot11_mode %d", + phymode, freq, chan_width, dot11_mode); + + QDF_ASSERT(phymode != WLAN_PHYMODE_AUTO); + return phymode; +} + +/** + * wma_get_link_speed() -send command to get linkspeed + * @handle: wma handle + * @pLinkSpeed: link speed info + * + * Return: QDF status + */ +QDF_STATUS wma_get_link_speed(WMA_HANDLE handle, + struct link_speed_info *pLinkSpeed) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + wmi_mac_addr peer_macaddr; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, + wmi_service_estimate_linkspeed)) { + wma_err("Linkspeed feature bit not enabled Sending value 0 as link speed"); + wma_send_link_speed(0); + return QDF_STATUS_E_FAILURE; + } + /* Copy the peer macaddress to the wma buffer */ + WMI_CHAR_ARRAY_TO_MAC_ADDR(pLinkSpeed->peer_macaddr.bytes, + &peer_macaddr); + wma_debug("pLinkSpeed->peerMacAddr: "QDF_MAC_ADDR_FMT", peer_macaddr.mac_addr31to0: 0x%x, peer_macaddr.mac_addr47to32: 0x%x", + QDF_MAC_ADDR_REF(pLinkSpeed->peer_macaddr.bytes), + peer_macaddr.mac_addr31to0, + peer_macaddr.mac_addr47to32); + if (wmi_unified_get_link_speed_cmd(wmi_handle, peer_macaddr)) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_get_isolation(tp_wma_handle wma) +{ + wmi_coex_get_antenna_isolation_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + uint8_t *buf_ptr; + struct wmi_unified *wmi_handle; + + wma_debug("get isolation"); + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wma->wmi_handle)) + return QDF_STATUS_E_INVAL; + + len = sizeof(wmi_coex_get_antenna_isolation_cmd_fixed_param); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) { + wma_err("wmi_buf_alloc failed"); + return QDF_STATUS_E_NOMEM; + } + buf_ptr = (uint8_t *)wmi_buf_data(wmi_buf); + + cmd = (wmi_coex_get_antenna_isolation_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_coex_get_antenna_isolation_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_coex_get_antenna_isolation_cmd_fixed_param)); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_COEX_GET_ANTENNA_ISOLATION_CMDID)) { + wma_err("Failed to get isolation request from fw"); + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_add_beacon_filter() - Issue WMI command to set beacon filter + * @wma: wma handler + * @filter_params: beacon_filter_param to set + * + * Return: Return QDF_STATUS + */ +QDF_STATUS wma_add_beacon_filter(WMA_HANDLE handle, + struct beacon_filter_param *filter_params) +{ + int i; + wmi_buf_t wmi_buf; + u_int8_t *buf; + A_UINT32 *ie_map; + int ret; + struct wma_txrx_node *iface; + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + wmi_add_bcn_filter_cmd_fixed_param *cmd; + int len = sizeof(wmi_add_bcn_filter_cmd_fixed_param); + + len += WMI_TLV_HDR_SIZE; + len += BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(A_UINT32); + + /* for ext ie map */ + len += WMI_TLV_HDR_SIZE; + len += BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(A_UINT32); + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wma->wmi_handle)) + return QDF_STATUS_E_INVAL; + + iface = &wma->interfaces[filter_params->vdev_id]; + qdf_mem_copy(&iface->beacon_filter, filter_params, + sizeof(struct beacon_filter_param)); + iface->beacon_filter_enabled = true; + + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + buf = (u_int8_t *) wmi_buf_data(wmi_buf); + + cmd = (wmi_add_bcn_filter_cmd_fixed_param *)wmi_buf_data(wmi_buf); + cmd->vdev_id = filter_params->vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_add_bcn_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_add_bcn_filter_cmd_fixed_param)); + + buf += sizeof(wmi_add_bcn_filter_cmd_fixed_param); + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_UINT32, + (BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t))); + + ie_map = (A_UINT32 *)(buf + WMI_TLV_HDR_SIZE); + for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) + ie_map[i] = filter_params->ie_map[i]; + + wma_debug("Beacon filter ie map Hex dump:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)ie_map, + BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t)); + + buf += WMI_TLV_HDR_SIZE; + buf += BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(A_UINT32); + + WMITLV_SET_HDR(buf, WMITLV_TAG_ARRAY_UINT32, + (BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t))); + + ie_map = (A_UINT32 *)(buf + WMI_TLV_HDR_SIZE); + for (i = 0; i < BCN_FLT_MAX_ELEMS_IE_LIST; i++) + ie_map[i] = filter_params->ie_map[i + 8]; + + wma_debug("Beacon filter ext ie map Hex dump:"); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + (uint8_t *)ie_map, + BCN_FLT_MAX_ELEMS_IE_LIST * sizeof(u_int32_t)); + + ret = wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_ADD_BCN_FILTER_CMDID); + if (ret) { + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** +* wma_remove_beacon_filter() - Issue WMI command to remove beacon filter +* @wma: wma handler +* @filter_params: beacon_filter_params +* +* Return: Return QDF_STATUS +*/ +QDF_STATUS wma_remove_beacon_filter(WMA_HANDLE handle, + struct beacon_filter_param *filter_params) +{ + wmi_buf_t buf; + tp_wma_handle wma = (tp_wma_handle) handle; + wmi_rmv_bcn_filter_cmd_fixed_param *cmd; + int len = sizeof(wmi_rmv_bcn_filter_cmd_fixed_param); + int ret; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wma->wmi_handle)) + return QDF_STATUS_E_INVAL; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_rmv_bcn_filter_cmd_fixed_param *)wmi_buf_data(buf); + cmd->vdev_id = filter_params->vdev_id; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_rmv_bcn_filter_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_rmv_bcn_filter_cmd_fixed_param)); + + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_RMV_BCN_FILTER_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_adapt_dwelltime_params() - send adaptive dwelltime configuration + * params to firmware + * @wma_handle: wma handler + * @dwelltime_params: pointer to dwelltime_params + * + * Return: QDF_STATUS_SUCCESS on success and QDF failure reason code for failure + */ +QDF_STATUS wma_send_adapt_dwelltime_params(WMA_HANDLE handle, + struct adaptive_dwelltime_params *dwelltime_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_adaptive_dwelltime_params wmi_param = {0}; + int32_t err; + + wmi_param.is_enabled = dwelltime_params->is_enabled; + wmi_param.dwelltime_mode = dwelltime_params->dwelltime_mode; + wmi_param.lpf_weight = dwelltime_params->lpf_weight; + wmi_param.passive_mon_intval = dwelltime_params->passive_mon_intval; + wmi_param.wifi_act_threshold = dwelltime_params->wifi_act_threshold; + err = wmi_unified_send_adapt_dwelltime_params_cmd(wma_handle-> + wmi_handle, &wmi_param); + if (err) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_send_dbs_scan_selection_params(WMA_HANDLE handle, + struct wmi_dbs_scan_sel_params *dbs_scan_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + int32_t err; + + err = wmi_unified_send_dbs_scan_sel_params_cmd(wma_handle-> + wmi_handle, dbs_scan_params); + if (err) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_unified_fw_profiling_cmd() - send FW profiling cmd to WLAN FW + * @wma: wma handle + * @cmd: Profiling command index + * @value1: parameter1 value + * @value2: parameter2 value + * + * Return: 0 for success else error code + */ +QDF_STATUS wma_unified_fw_profiling_cmd(wmi_unified_t wmi_handle, + uint32_t cmd, uint32_t value1, uint32_t value2) +{ + int ret; + + ret = wmi_unified_fw_profiling_data_cmd(wmi_handle, cmd, + value1, value2); + if (ret) { + wma_err("enable cmd Failed for id %d value %d", value1, value2); + return ret; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wow_set_wake_time() - set timer pattern tlv, so that firmware will wake + * up host after specified time is elapsed + * @wma_handle: wma handle + * @vdev_id: vdev id + * @cookie: value to identify reason why host set up wake call. + * @time: time in ms + * + * Return: QDF status + */ +static QDF_STATUS wma_wow_set_wake_time(WMA_HANDLE wma_handle, uint8_t vdev_id, + uint32_t cookie, uint32_t time) +{ + int ret; + tp_wma_handle wma = (tp_wma_handle)wma_handle; + + wma_debug("send timer pattern with time: %d and vdev = %d to fw", + time, vdev_id); + ret = wmi_unified_wow_timer_pattern_cmd(wma->wmi_handle, vdev_id, + cookie, time); + if (ret) { + wma_err("Failed to send timer pattern to fw"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_POWER_MANAGEMENT_OFFLOAD +/** + * wma_check_and_set_wake_timer(): checks all interfaces and if any interface + * has install_key pending, sets timer pattern in fw to wake up host after + * specified time has elapsed. + * @wma: wma handle + * @time: time after which host wants to be awaken. + * + * Return: None + */ +void wma_check_and_set_wake_timer(uint32_t time) +{ + int i; + struct wma_txrx_node *iface; + bool is_set_key_in_progress = false; + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return; + + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_wow_wakeup_by_timer_pattern)) { + wma_debug("TIME_PATTERN is not enabled"); + return; + } + + for (i = 0; i < wma->max_bssid; i++) { + iface = &wma->interfaces[i]; + if (iface->vdev_active && iface->is_waiting_for_key) { + /* + * right now cookie is dont care, since FW disregards + * that. + */ + is_set_key_in_progress = true; + wma_wow_set_wake_time((WMA_HANDLE)wma, i, 0, time); + break; + } + } + + if (!is_set_key_in_progress) + wma_debug("set key not in progress for any vdev"); +} + +/** + * wma_unified_csa_offload_enable() - sen CSA offload enable command + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: 0 for success or error code + */ +int wma_unified_csa_offload_enable(tp_wma_handle wma, uint8_t vdev_id) +{ + if (wmi_unified_csa_offload_enable(wma->wmi_handle, + vdev_id)) { + wma_alert("Failed to send CSA offload enable command"); + return -EIO; + } + + return 0; +} +#endif /* WLAN_POWER_MANAGEMENT_OFFLOAD */ + +static uint8_t * +wma_parse_ch_switch_wrapper_ie(uint8_t *ch_wr_ie, uint8_t sub_ele_id, + uint8_t ie_extn_id) +{ + uint8_t len = 0, sub_ele_len = 0; + struct ie_header *ele; + struct extn_ie_header *extn_ie; + + ele = (struct ie_header *)ch_wr_ie; + if (ele->ie_id != WLAN_ELEMID_CHAN_SWITCH_WRAP || ele->ie_len == 0) { + wma_debug("Invalid len: %d", ele->ie_len); + return NULL; + } + + len = ele->ie_len; + ele = (struct ie_header *)(ch_wr_ie + sizeof(struct ie_header)); + + while (len > 0) { + sub_ele_len = sizeof(struct ie_header) + ele->ie_len; + if (sub_ele_len > len) { + wma_debug("invalid sub element len :%d id:%d ie len:%d", + sub_ele_len, ele->ie_id, ele->ie_len); + return NULL; + } + len -= sub_ele_len; + if (ele->ie_id == sub_ele_id) { + if (sub_ele_id == WLAN_ELEMID_EXTN_ELEM) { + extn_ie = (struct extn_ie_header *)ele; + if (extn_ie->ie_extn_id == ie_extn_id) + return (uint8_t *)ele; + } else { + return (uint8_t *)ele; + } + } + ele = (struct ie_header *)((uint8_t *)ele + sub_ele_len); + } + + return NULL; +} + +#ifdef WLAN_FEATURE_11BE +/** + * wma_parse_bw_indication_ie(): STA parse bandwidth indication IE of connected + * AP for channel switch or puncture update. + * @ie: bandwidth indication IE + * @tlv_len: total length of ie tlv + * @csa_event: struct to save channel switch info + * + * Return - QDF_STATUS. + */ +static +QDF_STATUS wma_parse_bw_indication_ie(uint8_t *ie, + uint8_t tlv_len, + struct csa_offload_params *csa_event) +{ + uint16_t puncture_bitmap = 0; + uint8_t *sub_ie; + struct wlan_ie_bw_ind *bw_ind; + struct ie_header *ie_head; + uint8_t ccfs0, ccfs1; + enum phy_ch_width ch_width; + QDF_STATUS status; + + ie_head = (struct ie_header *)ie; + if (ie_head->ie_len + sizeof(struct ie_header) > tlv_len) { + wma_err("Invalid ie len: %d, buffer len: %d", + ie_head->ie_len, tlv_len); + return QDF_STATUS_E_INVAL; + } + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ie, tlv_len); + + sub_ie = wma_parse_ch_switch_wrapper_ie(ie, + WLAN_ELEMID_EXTN_ELEM, + WLAN_EXTN_ELEMID_BW_IND); + if (!sub_ie) { + wma_err("Invalid ie"); + return QDF_STATUS_E_INVAL; + } + + bw_ind = (struct wlan_ie_bw_ind *)sub_ie; + + status = util_parse_bw_ind(bw_ind, &ccfs0, &ccfs1, &ch_width, + &puncture_bitmap); + + wma_debug("ch width: %d, ccfs0: %d, ccfs1: %d, puncture: %d", ch_width, + ccfs0, ccfs1, puncture_bitmap); + + csa_event->new_ch_width = ch_width; + csa_event->new_ch_freq_seg1 = ccfs0; + csa_event->new_ch_freq_seg2 = ccfs1; + csa_event->new_punct_bitmap = puncture_bitmap; + + return QDF_STATUS_SUCCESS; +} +#else +static inline +QDF_STATUS wma_parse_bw_indication_ie(uint8_t *ie, + uint8_t tlv_len, + struct csa_offload_params *csa_event) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +static bool fill_csa_offload_params( + wmi_csa_event_fixed_param *csa_event, + struct csa_offload_params *csa_offload_event, + struct wlan_objmgr_pdev *pdev) +{ + struct ieee80211_channelswitch_ie *csa_ie; + struct ieee80211_extendedchannelswitch_ie *xcsa_ie; + uint8_t is_csa_ie_present = false; + + if (csa_event->ies_present_flag & WMI_CSA_IE_PRESENT) { + csa_ie = (struct ieee80211_channelswitch_ie *) + (&csa_event->csa_ie[0]); + csa_offload_event->channel = csa_ie->newchannel; + csa_offload_event->csa_chan_freq = + wlan_reg_legacy_chan_to_freq(pdev, + csa_ie->newchannel); + csa_offload_event->switch_mode = csa_ie->switchmode; + csa_offload_event->ies_present_flag |= MLME_CSA_IE_PRESENT; + is_csa_ie_present = true; + } else if (csa_event->ies_present_flag & WMI_XCSA_IE_PRESENT) { + xcsa_ie = (struct ieee80211_extendedchannelswitch_ie *) + (&csa_event->xcsa_ie[0]); + csa_offload_event->channel = xcsa_ie->newchannel; + csa_offload_event->switch_mode = xcsa_ie->switchmode; + csa_offload_event->new_op_class = xcsa_ie->newClass; + if (wlan_reg_is_6ghz_op_class(pdev, xcsa_ie->newClass)) { + csa_offload_event->csa_chan_freq = + wlan_reg_chan_band_to_freq + (pdev, xcsa_ie->newchannel, + BIT(REG_BAND_6G)); + } else { + csa_offload_event->csa_chan_freq = + wlan_reg_legacy_chan_to_freq + (pdev, xcsa_ie->newchannel); + } + csa_offload_event->ies_present_flag |= MLME_XCSA_IE_PRESENT; + is_csa_ie_present = true; + } + return is_csa_ie_present; +} + +#ifdef WLAN_FEATURE_11BE +static bool handle_csa_standby_link(wmi_csa_event_fixed_param *csa_event, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + struct mlo_link_info *link_info; + struct wlan_mlo_dev_context *mldev; + uint8_t mld_addr[QDF_MAC_ADDR_SIZE]; + struct csa_offload_params csa_param = {0}; + struct mlo_link_bss_params params = {0}; + uint8_t is_csa_standby = false; + uint8_t link_id; + struct wlan_lmac_if_mlo_tx_ops *mlo_tx_ops; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!psoc) { + wma_err("null psoc"); + return is_csa_standby; + } + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->mld_mac_address, + &mld_addr[0]); + wlan_mlo_get_mlpeer_by_peer_mladdr( + (struct qdf_mac_addr *)&mld_addr[0], + &mldev); + if (!mldev) { + wma_err("NULL ml dev ctx"); + return is_csa_standby; + } + + link_id = csa_event->link_id; + link_info = mlo_mgr_get_ap_link_by_link_id(mldev, + link_id); + if (!link_info) { + wma_err("NULL link info "); + return is_csa_standby; + } + + if (link_info->vdev_id != WLAN_INVALID_VDEV_ID) { + wma_debug("vdev id %d link id %d ", link_info->vdev_id, + link_id); + return is_csa_standby; + } + + mlo_tx_ops = &psoc->soc_cb.tx_ops->mlo_ops; + if (!mlo_tx_ops) { + wma_err("tx_ops is null!"); + return is_csa_standby; + } + + if (!fill_csa_offload_params(csa_event, &csa_param, pdev)) { + wma_err("CSA Event error: No CSA IE present"); + return is_csa_standby; + } + + mlo_mgr_update_csa_link_info(pdev, mldev, &csa_param, link_id); + + params.link_id = link_info->link_id; + params.chan = qdf_mem_malloc(sizeof(struct wlan_channel)); + if (!params.chan) { + wma_err("no mem acquired"); + return is_csa_standby; + } + + qdf_copy_macaddr((struct qdf_mac_addr *)¶ms.ap_mld_mac[0], + &link_info->ap_link_addr); + + params.chan->ch_freq = link_info->link_chan_info->ch_freq; + params.chan->ch_cfreq1 = link_info->link_chan_info->ch_cfreq1; + params.chan->ch_cfreq2 = link_info->link_chan_info->ch_cfreq2; + params.chan->ch_phymode = link_info->link_chan_info->ch_phymode; + + mlo_debug("link id %d chan freq %d cfreq1 %d cfreq2 %d host phymode %d ap mld mac " QDF_MAC_ADDR_FMT, + link_info->link_id, link_info->link_chan_info->ch_freq, + link_info->link_chan_info->ch_cfreq1, + link_info->link_chan_info->ch_cfreq2, + link_info->link_chan_info->ch_phymode, + QDF_MAC_ADDR_REF(¶ms.ap_mld_mac[0])); + + if (!mlo_tx_ops->send_link_set_bss_params_cmd) { + wma_err("handler is not registered"); + qdf_mem_free(params.chan); + return is_csa_standby; + } + + status = mlo_tx_ops->send_link_set_bss_params_cmd(psoc, ¶ms); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to send link set bss request command to FW"); + qdf_mem_free(params.chan); + return is_csa_standby; + } + + is_csa_standby = true; + qdf_mem_free(params.chan); + + return is_csa_standby; +} + +static int fill_peer_mac_addr(wmi_csa_event_fixed_param *csa_event, + uint8_t *bssid) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t mld_addr[QDF_MAC_ADDR_SIZE]; + uint8_t link_addr[QDF_MAC_ADDR_SIZE]; + uint8_t link_id; + struct mlo_link_info *link_info; + struct wlan_mlo_dev_context *mldev; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->mld_mac_address, + &mld_addr[0]); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->link_mac_address, + &link_addr[0]); + wlan_mlo_get_mlpeer_by_peer_mladdr( + (struct qdf_mac_addr *)&mld_addr[0], + &mldev); + if (!mldev) { + wma_err("NULL ml dev ctx"); + return -EINVAL; + } + + link_id = csa_event->link_id; + link_info = mlo_mgr_get_ap_link_by_link_id(mldev, + link_id); + if (!link_info) { + wma_err("NULL link info "); + return -EINVAL; + } + + qdf_copy_macaddr((struct qdf_mac_addr *)&bssid[0], + &link_info->ap_link_addr); + wma_debug("csa event link id %d vdev id %d peer mld addr" QDF_MAC_ADDR_FMT "peer link addr" QDF_MAC_ADDR_FMT "host link info ap_link_addr" QDF_MAC_ADDR_FMT, + link_id, link_info->vdev_id, + QDF_MAC_ADDR_REF(&mld_addr[0]), + QDF_MAC_ADDR_REF(&link_addr[0]), + QDF_MAC_ADDR_REF(link_info->ap_link_addr.bytes)); + + return status; +} + +#else +static int fill_peer_mac_addr(wmi_csa_event_fixed_param *csa_event, + uint8_t *bssid) +{ + return 0; +} + +static bool handle_csa_standby_link(wmi_csa_event_fixed_param *csa_event, + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + return false; +} + +#endif + +/** + * wma_csa_offload_handler() - CSA event handler + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * This event is sent by firmware when it receives CSA IE. + * + * Return: 0 for success or error code + */ +int wma_csa_offload_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_CSA_HANDLING_EVENTID_param_tlvs *param_buf; + wmi_csa_event_fixed_param *csa_event; + uint8_t bssid[QDF_MAC_ADDR_SIZE]; + uint8_t vdev_id = 0; + uint8_t cur_chan = 0; + struct csa_offload_params *csa_offload_event; + struct ieee80211_ie_wide_bw_switch *wb_ie; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_vdev *vdev; + QDF_STATUS status; + uint8_t tlv_len; + struct wlan_channel *chan; + + param_buf = (WMI_CSA_HANDLING_EVENTID_param_tlvs *) event; + + wma_debug("Enter"); + if (!param_buf) { + wma_err("Invalid csa event buffer"); + return -EINVAL; + } + csa_event = param_buf->fixed_param; + + if (csa_event->link_id_present && + csa_event->mld_mac_address_present) { + status = fill_peer_mac_addr(csa_event, &bssid[0]); + if (status) + return -EINVAL; + + /* check standby link and return */ + if (handle_csa_standby_link(csa_event, wma->psoc, wma->pdev)) + return 0; + } else { + WMI_MAC_ADDR_TO_CHAR_ARRAY(&csa_event->i_addr2, + &bssid[0]); + } + + peer = wlan_objmgr_get_peer_by_mac(wma->psoc, + bssid, WLAN_LEGACY_WMA_ID); + if (!peer) { + wma_err("Invalid peer"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(wlan_peer_get_vdev(peer)); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) + return -EINVAL; + + csa_offload_event = qdf_mem_malloc(sizeof(*csa_offload_event)); + if (!csa_offload_event) { + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + return -EINVAL; + } + if (wlan_cm_is_vdev_roaming(vdev)) { + wma_err("Roaming in progress for vdev %d, ignore csa event", + vdev_id); + qdf_mem_free(csa_offload_event); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + return -EINVAL; + } + + qdf_mem_zero(csa_offload_event, sizeof(*csa_offload_event)); + qdf_copy_macaddr(&csa_offload_event->bssid, + (struct qdf_mac_addr *)bssid); + + if (!fill_csa_offload_params(csa_event, csa_offload_event, wma->pdev)) { + wma_err("CSA Event error: No CSA IE present"); + qdf_mem_free(csa_offload_event); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + return -EINVAL; + } + + if (csa_event->ies_present_flag & WMI_CSWRAP_IE_EXT_VER_2_PRESENT) { + wma_debug("WMI_CSWRAP_IE_EXT_VER_2 received"); + tlv_len = csa_event->num_bytes_valid_in_cswrap_ie_ext_ver2; + status = wma_parse_bw_indication_ie(param_buf->cs_wrap_ie, + tlv_len, + csa_offload_event); + if (QDF_IS_STATUS_SUCCESS(status)) { + csa_offload_event->ies_present_flag |= + MLME_CSWRAP_IE_EXT_V2_PRESENT; + goto got_chan; + } + } + + if (csa_event->ies_present_flag & WMI_WBW_IE_PRESENT) { + wb_ie = (struct ieee80211_ie_wide_bw_switch *) + (&csa_event->wb_ie[0]); + csa_offload_event->new_ch_freq_seg1 = wb_ie->new_ch_freq_seg1; + csa_offload_event->new_ch_freq_seg2 = wb_ie->new_ch_freq_seg2; + csa_offload_event->new_ch_width = + wlan_mlme_convert_vht_op_bw_to_phy_ch_width(wb_ie->new_ch_width, + csa_offload_event->channel, + wb_ie->new_ch_freq_seg1, + wb_ie->new_ch_freq_seg2); + + csa_offload_event->ies_present_flag |= MLME_WBW_IE_PRESENT; + } else if (csa_event->ies_present_flag & + WMI_CSWRAP_IE_EXTENDED_PRESENT) { + wb_ie = (struct ieee80211_ie_wide_bw_switch *) + wma_parse_ch_switch_wrapper_ie( + (uint8_t *)&csa_event->cswrap_ie_extended, + WLAN_ELEMID_WIDE_BAND_CHAN_SWITCH, 0); + if (wb_ie) { + csa_offload_event->new_ch_freq_seg1 = + wb_ie->new_ch_freq_seg1; + csa_offload_event->new_ch_freq_seg2 = + wb_ie->new_ch_freq_seg2; + csa_offload_event->new_ch_width = + wlan_mlme_convert_vht_op_bw_to_phy_ch_width(wb_ie->new_ch_width, + csa_offload_event->channel, + wb_ie->new_ch_freq_seg1, + wb_ie->new_ch_freq_seg2); + csa_event->ies_present_flag |= WMI_WBW_IE_PRESENT; + csa_offload_event->ies_present_flag |= + MLME_WBW_IE_PRESENT; + } + csa_offload_event->ies_present_flag |= + MLME_CSWRAP_IE_EXTENDED_PRESENT; + } + +got_chan: + wma_debug("CSA: BSSID "QDF_MAC_ADDR_FMT" chan %d freq %d flag 0x%x width = %d freq1 = %d freq2 = %d op class = %d", + QDF_MAC_ADDR_REF(csa_offload_event->bssid.bytes), + csa_offload_event->channel, + csa_offload_event->csa_chan_freq, + csa_offload_event->ies_present_flag, + csa_offload_event->new_ch_width, + csa_offload_event->new_ch_freq_seg1, + csa_offload_event->new_ch_freq_seg2, + csa_offload_event->new_op_class); + + chan = wlan_vdev_get_active_channel(vdev); + if (!chan) { + wmi_err("failed to get active channel"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + qdf_mem_free(csa_offload_event); + return false; + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + cur_chan = cds_freq_to_chan(chan->ch_freq); + /* + * basic sanity check: requested channel should not be 0 + * and equal to home channel + */ + if (0 == csa_offload_event->channel) { + wma_err("CSA Event with channel %d. Ignore !!", + csa_offload_event->channel); + qdf_mem_free(csa_offload_event); + return -EINVAL; + } + + wma_send_msg(wma, WMA_CSA_OFFLOAD_EVENT, (void *)csa_offload_event, 0); + return 0; +} + +#ifdef FEATURE_OEM_DATA_SUPPORT +/** + * wma_oem_data_response_handler() - OEM data response event handler + * @handle: wma handle + * @datap: data ptr + * @len: data length + * + * Return: 0 for success or error code + */ +int wma_oem_data_response_handler(void *handle, + uint8_t *datap, uint32_t len) +{ + WMI_OEM_RESPONSE_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + struct oem_data_rsp *oem_rsp; + struct mac_context *pmac = cds_get_context(QDF_MODULE_ID_PE); + + if (!pmac) + return -EINVAL; + + if (!pmac->sme.oem_data_rsp_callback) { + wma_err("Callback not registered"); + return -EINVAL; + } + + param_buf = (WMI_OEM_RESPONSE_EVENTID_param_tlvs *) datap; + if (!param_buf) { + wma_err("Received NULL buf ptr from FW"); + return -ENOMEM; + } + + data = param_buf->data; + datalen = param_buf->num_data; + + if (!data) { + wma_err("Received NULL data from FW"); + return -EINVAL; + } + + if (datalen > OEM_DATA_RSP_SIZE) { + wma_err("Received data len %d exceeds max value %d", + datalen, OEM_DATA_RSP_SIZE); + return -EINVAL; + } + + oem_rsp = qdf_mem_malloc(sizeof(*oem_rsp)); + if (!oem_rsp) + return -ENOMEM; + + oem_rsp->rsp_len = datalen; + if (oem_rsp->rsp_len) { + oem_rsp->data = qdf_mem_malloc(oem_rsp->rsp_len); + if (!oem_rsp->data) { + qdf_mem_free(oem_rsp); + return -ENOMEM; + } + } else { + wma_err("Invalid rsp length: %d", oem_rsp->rsp_len); + qdf_mem_free(oem_rsp); + return -EINVAL; + } + + qdf_mem_copy(oem_rsp->data, data, datalen); + + wma_debug("Sending OEM_DATA_RSP(len: %d) to upper layer", datalen); + + pmac->sme.oem_data_rsp_callback(oem_rsp); + + if (oem_rsp->data) + qdf_mem_free(oem_rsp->data); + qdf_mem_free(oem_rsp); + + return 0; +} + +QDF_STATUS wma_start_oem_req_cmd(tp_wma_handle wma_handle, + struct oem_data_req *oem_data_req) +{ + QDF_STATUS ret; + struct wmi_unified *wmi_handle; + + wma_debug("Send OEM Data Request to target"); + + if (!oem_data_req || !oem_data_req->data) { + wma_err("oem_data_req is null"); + return QDF_STATUS_E_INVAL; + } + + if (wma_validate_handle(wma_handle)) { + qdf_mem_free(oem_data_req->data); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) { + qdf_mem_free(oem_data_req->data); + return QDF_STATUS_E_INVAL; + } + + /* legacy api, for oem data request case */ + ret = wmi_unified_start_oem_data_cmd(wmi_handle, + oem_data_req->data_len, + oem_data_req->data); + + if (!QDF_IS_STATUS_SUCCESS(ret)) + wma_err("wmi cmd send failed"); + + return ret; +} +#endif /* FEATURE_OEM_DATA_SUPPORT */ + +#ifdef FEATURE_OEM_DATA +QDF_STATUS wma_start_oem_data_cmd(tp_wma_handle wma_handle, + struct oem_data *oem_data) +{ + QDF_STATUS ret; + struct wmi_unified *wmi_handle; + + wma_debug("Send OEM Data to target"); + + if (!oem_data || !oem_data->data) { + wma_err("oem_data is null"); + return QDF_STATUS_E_INVAL; + } + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + /* common api, for oem data command case */ + ret = wmi_unified_start_oemv2_data_cmd(wmi_handle, oem_data); + if (!QDF_IS_STATUS_SUCCESS(ret)) + wma_err("call start wmi cmd failed"); + + return ret; +} +#endif + +#if !defined(REMOVE_PKT_LOG) && defined(FEATURE_PKTLOG) +/** + * wma_pktlog_wmi_send_cmd() - send pktlog enable/disable command to target + * @handle: wma handle + * @params: pktlog params + * + * Return: QDF status + */ +QDF_STATUS wma_pktlog_wmi_send_cmd(WMA_HANDLE handle, + struct ath_pktlog_wmi_params *params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + int ret; + + ret = wmi_unified_pktlog_wmi_send_cmd(wma_handle->wmi_handle, + params->pktlog_event, + params->cmd_id, params->user_triggered); + if (ret) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} +#endif /* !REMOVE_PKT_LOG && FEATURE_PKTLOG */ + +/** + * wma_wow_wake_reason_str() - Converts wow wakeup reason code to text format + * @wake_reason - WOW wake reason + * + * Return: reason code in string format + */ +static const uint8_t *wma_wow_wake_reason_str(A_INT32 wake_reason) +{ + switch (wake_reason) { + case WOW_REASON_UNSPECIFIED: + return "UNSPECIFIED"; + case WOW_REASON_NLOD: + return "NLOD"; + case WOW_REASON_AP_ASSOC_LOST: + return "AP_ASSOC_LOST"; + case WOW_REASON_LOW_RSSI: + return "LOW_RSSI"; + case WOW_REASON_DEAUTH_RECVD: + return "DEAUTH_RECVD"; + case WOW_REASON_DISASSOC_RECVD: + return "DISASSOC_RECVD"; + case WOW_REASON_GTK_HS_ERR: + return "GTK_HS_ERR"; + case WOW_REASON_EAP_REQ: + return "EAP_REQ"; + case WOW_REASON_FOURWAY_HS_RECV: + return "FOURWAY_HS_RECV"; + case WOW_REASON_TIMER_INTR_RECV: + return "TIMER_INTR_RECV"; + case WOW_REASON_PATTERN_MATCH_FOUND: + return "PATTERN_MATCH_FOUND"; + case WOW_REASON_RECV_MAGIC_PATTERN: + return "RECV_MAGIC_PATTERN"; + case WOW_REASON_P2P_DISC: + return "P2P_DISC"; + case WOW_REASON_WLAN_HB: + return "WLAN_HB"; + case WOW_REASON_CSA_EVENT: + return "CSA_EVENT"; + case WOW_REASON_PROBE_REQ_WPS_IE_RECV: + return "PROBE_REQ_WPS_IE_RECV"; + case WOW_REASON_AUTH_REQ_RECV: + return "AUTH_REQ_RECV"; + case WOW_REASON_ASSOC_REQ_RECV: + return "ASSOC_REQ_RECV"; + case WOW_REASON_HTT_EVENT: + return "HTT_EVENT"; + case WOW_REASON_RA_MATCH: + return "RA_MATCH"; + case WOW_REASON_HOST_AUTO_SHUTDOWN: + return "HOST_AUTO_SHUTDOWN"; + case WOW_REASON_IOAC_MAGIC_EVENT: + return "IOAC_MAGIC_EVENT"; + case WOW_REASON_IOAC_SHORT_EVENT: + return "IOAC_SHORT_EVENT"; + case WOW_REASON_IOAC_EXTEND_EVENT: + return "IOAC_EXTEND_EVENT"; + case WOW_REASON_IOAC_TIMER_EVENT: + return "IOAC_TIMER_EVENT"; + case WOW_REASON_ROAM_HO: + return "ROAM_HO"; + case WOW_REASON_ROAM_PREAUTH_START: + return "ROAM_PREAUTH_START_EVENT"; + case WOW_REASON_DFS_PHYERR_RADADR_EVENT: + return "DFS_PHYERR_RADADR_EVENT"; + case WOW_REASON_BEACON_RECV: + return "BEACON_RECV"; + case WOW_REASON_CLIENT_KICKOUT_EVENT: + return "CLIENT_KICKOUT_EVENT"; + case WOW_REASON_NAN_EVENT: + return "NAN_EVENT"; + case WOW_REASON_EXTSCAN: + return "EXTSCAN"; + case WOW_REASON_RSSI_BREACH_EVENT: + return "RSSI_BREACH_EVENT"; + case WOW_REASON_IOAC_REV_KA_FAIL_EVENT: + return "IOAC_REV_KA_FAIL_EVENT"; + case WOW_REASON_IOAC_SOCK_EVENT: + return "IOAC_SOCK_EVENT"; + case WOW_REASON_NLO_SCAN_COMPLETE: + return "NLO_SCAN_COMPLETE"; + case WOW_REASON_PACKET_FILTER_MATCH: + return "PACKET_FILTER_MATCH"; + case WOW_REASON_ASSOC_RES_RECV: + return "ASSOC_RES_RECV"; + case WOW_REASON_REASSOC_REQ_RECV: + return "REASSOC_REQ_RECV"; + case WOW_REASON_REASSOC_RES_RECV: + return "REASSOC_RES_RECV"; + case WOW_REASON_ACTION_FRAME_RECV: + return "ACTION_FRAME_RECV"; + case WOW_REASON_BPF_ALLOW: + return "BPF_ALLOW"; + case WOW_REASON_NAN_DATA: + return "NAN_DATA"; + case WOW_REASON_OEM_RESPONSE_EVENT: + return "OEM_RESPONSE_EVENT"; + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + return "TDLS_CONN_TRACKER_EVENT"; + case WOW_REASON_CRITICAL_LOG: + return "CRITICAL_LOG"; + case WOW_REASON_P2P_LISTEN_OFFLOAD: + return "P2P_LISTEN_OFFLOAD"; + case WOW_REASON_NAN_EVENT_WAKE_HOST: + return "NAN_EVENT_WAKE_HOST"; + case WOW_REASON_DEBUG_TEST: + return "DEBUG_TEST"; + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + return "CHIP_POWER_FAILURE_DETECT"; + case WOW_REASON_11D_SCAN: + return "11D_SCAN"; + case WOW_REASON_SAP_OBSS_DETECTION: + return "SAP_OBSS_DETECTION"; + case WOW_REASON_BSS_COLOR_COLLISION_DETECT: + return "BSS_COLOR_COLLISION_DETECT"; +#ifdef WLAN_FEATURE_MOTION_DETECTION + case WOW_REASON_WLAN_MD: + return "MOTION_DETECT"; + case WOW_REASON_WLAN_BL: + return "MOTION_DETECT_BASELINE"; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + case WOW_REASON_PAGE_FAULT: + return "PF"; + case WOW_REASON_ROAM_PMKID_REQUEST: + return "ROAM_PMKID_REQUEST"; + case WOW_REASON_VDEV_DISCONNECT: + return "VDEV_DISCONNECT"; + case WOW_REASON_LOCAL_DATA_UC_DROP: + return "LOCAL_DATA_UC_DROP"; + case WOW_REASON_FATAL_EVENT_WAKE: + return "FATAL_EVENT_WAKE"; + case WOW_REASON_GENERIC_WAKE: + return "GENERIC_WAKE"; + case WOW_REASON_TWT: + return "TWT Event"; + case WOW_REASON_DCS_INT_DET: + return "DCS_INT_DET"; + case WOW_REASON_ROAM_STATS: + return "ROAM_STATS"; + case WOW_REASON_RTT_11AZ: + return "WOW_REASON_RTT_11AZ"; + case WOW_REASON_DELAYED_WAKEUP_HOST_CFG_TIMER_ELAPSED: + return "DELAYED_WAKEUP_TIMER_ELAPSED"; + case WOW_REASON_DELAYED_WAKEUP_DATA_STORE_LIST_FULL: + return "DELAYED_WAKEUP_DATA_STORE_LIST_FULL"; +#ifndef WLAN_SUPPORT_GAP_LL_PS_MODE + case WOW_REASON_XGAP: + return "XGAP"; +#endif + default: + return "unknown"; + } +} + +static bool wma_wow_reason_has_stats(enum wake_reason_e reason) +{ + switch (reason) { + case WOW_REASON_ASSOC_REQ_RECV: + case WOW_REASON_DISASSOC_RECVD: + case WOW_REASON_ASSOC_RES_RECV: + case WOW_REASON_REASSOC_REQ_RECV: + case WOW_REASON_REASSOC_RES_RECV: + case WOW_REASON_AUTH_REQ_RECV: + case WOW_REASON_DEAUTH_RECVD: + case WOW_REASON_ACTION_FRAME_RECV: + case WOW_REASON_BPF_ALLOW: + case WOW_REASON_PATTERN_MATCH_FOUND: + case WOW_REASON_PACKET_FILTER_MATCH: + case WOW_REASON_RA_MATCH: + case WOW_REASON_NLOD: + case WOW_REASON_NLO_SCAN_COMPLETE: + case WOW_REASON_LOW_RSSI: + case WOW_REASON_EXTSCAN: + case WOW_REASON_RSSI_BREACH_EVENT: + case WOW_REASON_OEM_RESPONSE_EVENT: + case WOW_REASON_CHIP_POWER_FAILURE_DETECT: + case WOW_REASON_11D_SCAN: + case WOW_REASON_LOCAL_DATA_UC_DROP: + case WOW_REASON_FATAL_EVENT_WAKE: + return true; +#ifdef WLAN_FEATURE_MOTION_DETECTION + case WOW_REASON_WLAN_MD: + case WOW_REASON_WLAN_BL: + return true; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + default: + return false; + } +} + +static void wma_inc_wow_stats(t_wma_handle *wma, + WOW_EVENT_INFO_fixed_param *wake_info) +{ + ucfg_mc_cp_stats_inc_wake_lock_stats(wma->psoc, + wake_info->vdev_id, + wake_info->wake_reason); +} + +static void wma_wow_stats_display(struct wake_lock_stats *stats) +{ + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "WLAN wake reason counters:"); + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "uc:%d bc:%d v4_mc:%d v6_mc:%d ra:%d ns:%d na:%d " + "icmp:%d icmpv6:%d", + stats->ucast_wake_up_count, + stats->bcast_wake_up_count, + stats->ipv4_mcast_wake_up_count, + stats->ipv6_mcast_wake_up_count, + stats->ipv6_mcast_ra_stats, + stats->ipv6_mcast_ns_stats, + stats->ipv6_mcast_na_stats, + stats->icmpv4_count, + stats->icmpv6_count); + + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "assoc:%d disassoc:%d assoc_resp:%d reassoc:%d " + "reassoc_resp:%d auth:%d deauth:%d action:%d", + stats->mgmt_assoc, + stats->mgmt_disassoc, + stats->mgmt_assoc_resp, + stats->mgmt_reassoc, + stats->mgmt_reassoc_resp, + stats->mgmt_auth, + stats->mgmt_deauth, + stats->mgmt_action); + + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "pno_match:%d pno_complete:%d gscan:%d low_rssi:%d" + " rssi_breach:%d oem:%d ucdrop:%d scan_11d:%d" + " fatal_event:%d", + stats->pno_match_wake_up_count, + stats->pno_complete_wake_up_count, + stats->gscan_wake_up_count, + stats->low_rssi_wake_up_count, + stats->rssi_breach_wake_up_count, + stats->oem_response_wake_up_count, + stats->uc_drop_wake_up_count, + stats->scan_11d, + stats->fatal_event_wake_up_count); +} + +static void wma_print_wow_stats(t_wma_handle *wma, + WOW_EVENT_INFO_fixed_param *wake_info) +{ + struct wlan_objmgr_vdev *vdev; + struct wake_lock_stats stats = {0}; + + if (!wma_wow_reason_has_stats(wake_info->wake_reason)) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + wake_info->vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("vdev_id: %d, failed to get vdev from psoc", + wake_info->vdev_id); + return; + } + + ucfg_mc_cp_stats_get_vdev_wake_lock_stats(vdev, &stats); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + wma_wow_stats_display(&stats); +} + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * wma_extscan_get_eventid_from_tlvtag() - map tlv tag to corresponding event id + * @tag: WMI TLV tag + * + * Return: + * 0 if TLV tag is invalid + * else return corresponding WMI event id + */ +static int wma_extscan_get_eventid_from_tlvtag(uint32_t tag) +{ + uint32_t event_id; + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: + event_id = WMI_EXTSCAN_START_STOP_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: + event_id = WMI_EXTSCAN_OPERATION_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: + event_id = WMI_EXTSCAN_TABLE_USAGE_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: + event_id = WMI_EXTSCAN_CACHED_RESULTS_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: + event_id = WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: + event_id = WMI_EXTSCAN_HOTLIST_MATCH_EVENTID; + break; + + case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: + event_id = WMI_EXTSCAN_CAPABILITIES_EVENTID; + break; + + default: + event_id = 0; + wma_err("Unknown tag: %d", tag); + break; + } + + wma_info("For tag %d WMI event 0x%x", tag, event_id); + return event_id; +} +#else +static int wma_extscan_get_eventid_from_tlvtag(uint32_t tag) +{ + return 0; +} +#endif + +/** + * wow_get_wmi_eventid() - map reason or tlv tag to corresponding event id + * @tag: WMI TLV tag + * @reason: WOW reason + * + * WOW reason type is primarily used to find the ID. If there could be + * multiple events that can be sent as a WOW event with same reason + * then tlv tag is used to identify the corresponding event. + * + * Return: + * 0 if TLV tag/reason is invalid + * else return corresponding WMI event id + */ +static int wow_get_wmi_eventid(int32_t reason, uint32_t tag) +{ + int event_id; + + switch (reason) { + case WOW_REASON_AP_ASSOC_LOST: + event_id = WMI_ROAM_EVENTID; + break; + case WOW_REASON_NLO_SCAN_COMPLETE: + event_id = WMI_NLO_SCAN_COMPLETE_EVENTID; + break; + case WOW_REASON_CSA_EVENT: + event_id = WMI_CSA_HANDLING_EVENTID; + break; + case WOW_REASON_LOW_RSSI: + event_id = WMI_ROAM_EVENTID; + break; + case WOW_REASON_CLIENT_KICKOUT_EVENT: + event_id = WMI_PEER_STA_KICKOUT_EVENTID; + break; + case WOW_REASON_EXTSCAN: + event_id = wma_extscan_get_eventid_from_tlvtag(tag); + break; + case WOW_REASON_RSSI_BREACH_EVENT: + event_id = WMI_RSSI_BREACH_EVENTID; + break; + case WOW_REASON_NAN_EVENT: + event_id = WMI_NAN_EVENTID; + break; + case WOW_REASON_NAN_DATA: + event_id = wma_ndp_get_eventid_from_tlvtag(tag); + break; + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + event_id = WMI_TDLS_PEER_EVENTID; + break; + case WOW_REASON_ROAM_HO: + event_id = WMI_ROAM_EVENTID; + break; + case WOW_REASON_11D_SCAN: + event_id = WMI_11D_NEW_COUNTRY_EVENTID; + break; + case WOW_REASON_ROAM_PMKID_REQUEST: + event_id = WMI_ROAM_PMKID_REQUEST_EVENTID; + break; + case WOW_REASON_VDEV_DISCONNECT: + event_id = WMI_VDEV_DISCONNECT_EVENTID; + break; + default: + wma_debug("No Event Id for WOW reason %s(%d)", + wma_wow_wake_reason_str(reason), reason); + event_id = 0; + break; + } + wlan_roam_debug_log(WMA_INVALID_VDEV_ID, DEBUG_WOW_REASON, + DEBUG_INVALID_PEER_ID, NULL, NULL, + reason, event_id); + + return event_id; +} + +/** + * is_piggybacked_event() - Returns true if the given wake reason indicates + * there will be piggybacked TLV event data + * @reason: WOW reason + * + * There are three types of WoW event payloads: none, piggybacked event, and + * network packet. This function returns true for wake reasons that fall into + * the piggybacked event case. + * + * Return: true for piggybacked event data + */ +static bool is_piggybacked_event(int32_t reason) +{ + switch (reason) { + case WOW_REASON_AP_ASSOC_LOST: + case WOW_REASON_NLO_SCAN_COMPLETE: + case WOW_REASON_CSA_EVENT: + case WOW_REASON_LOW_RSSI: + case WOW_REASON_CLIENT_KICKOUT_EVENT: + case WOW_REASON_EXTSCAN: + case WOW_REASON_RSSI_BREACH_EVENT: + case WOW_REASON_NAN_EVENT: + case WOW_REASON_NAN_DATA: + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + case WOW_REASON_ROAM_HO: + case WOW_REASON_ROAM_PMKID_REQUEST: + case WOW_REASON_VDEV_DISCONNECT: + case WOW_REASON_TWT: + return true; + default: + return false; + } +} + +/** + * wma_pkt_proto_subtype_to_string() - to convert proto subtype + * of data packet to string. + * @proto_subtype: proto subtype for data packet + * + * This function returns the string for the proto subtype of + * data packet. + * + * Return: string for proto subtype for data packet + */ +static const char * +wma_pkt_proto_subtype_to_string(enum qdf_proto_subtype proto_subtype) +{ + switch (proto_subtype) { + case QDF_PROTO_EAPOL_M1: + return "EAPOL M1"; + case QDF_PROTO_EAPOL_M2: + return "EAPOL M2"; + case QDF_PROTO_EAPOL_M3: + return "EAPOL M3"; + case QDF_PROTO_EAPOL_M4: + return "EAPOL M4"; + case QDF_PROTO_DHCP_DISCOVER: + return "DHCP DISCOVER"; + case QDF_PROTO_DHCP_REQUEST: + return "DHCP REQUEST"; + case QDF_PROTO_DHCP_OFFER: + return "DHCP OFFER"; + case QDF_PROTO_DHCP_ACK: + return "DHCP ACK"; + case QDF_PROTO_DHCP_NACK: + return "DHCP NACK"; + case QDF_PROTO_DHCP_RELEASE: + return "DHCP RELEASE"; + case QDF_PROTO_DHCP_INFORM: + return "DHCP INFORM"; + case QDF_PROTO_DHCP_DECLINE: + return "DHCP DECLINE"; + case QDF_PROTO_ARP_REQ: + return "ARP REQUEST"; + case QDF_PROTO_ARP_RES: + return "ARP RESPONSE"; + case QDF_PROTO_ICMP_REQ: + return "ICMP REQUEST"; + case QDF_PROTO_ICMP_RES: + return "ICMP RESPONSE"; + case QDF_PROTO_ICMPV6_REQ: + return "ICMPV6 REQUEST"; + case QDF_PROTO_ICMPV6_RES: + return "ICMPV6 RESPONSE"; + case QDF_PROTO_ICMPV6_RS: + return "ICMPV6 RS"; + case QDF_PROTO_ICMPV6_RA: + return "ICMPV6 RA"; + case QDF_PROTO_ICMPV6_NS: + return "ICMPV6 NS"; + case QDF_PROTO_ICMPV6_NA: + return "ICMPV6 NA"; + case QDF_PROTO_IPV4_UDP: + return "IPV4 UDP Packet"; + case QDF_PROTO_IPV4_TCP: + return "IPV4 TCP Packet"; + case QDF_PROTO_IPV6_UDP: + return "IPV6 UDP Packet"; + case QDF_PROTO_IPV6_TCP: + return "IPV6 TCP Packet"; + default: + return NULL; + } +} + +/** + * wma_wow_get_pkt_proto_subtype() - get the proto subtype of the packet. + * @data: Pointer to the packet data buffer + * @len: length of the packet data buffer + * + * Return: proto subtype of the packet. + */ +static enum qdf_proto_subtype +wma_wow_get_pkt_proto_subtype(uint8_t *data, uint32_t len) +{ + uint16_t eth_type; + uint8_t proto_type; + + if (len < QDF_NBUF_TRAC_ETH_TYPE_OFFSET + 2) { + wma_err("Malformed ethernet packet: length %u < %d", + len, QDF_NBUF_TRAC_ETH_TYPE_OFFSET + 2); + return QDF_PROTO_INVALID; + } + + eth_type = *(uint16_t *)(data + QDF_NBUF_TRAC_ETH_TYPE_OFFSET); + eth_type = qdf_cpu_to_be16(eth_type); + + wma_debug("Ether Type: 0x%04x", eth_type); + switch (eth_type) { + case QDF_NBUF_TRAC_EAPOL_ETH_TYPE: + if (len < WMA_EAPOL_SUBTYPE_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("EAPOL Packet"); + return qdf_nbuf_data_get_eapol_subtype(data); + + case QDF_NBUF_TRAC_ARP_ETH_TYPE: + if (len < WMA_ARP_SUBTYPE_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("ARP Packet"); + return qdf_nbuf_data_get_arp_subtype(data); + + case QDF_NBUF_TRAC_IPV4_ETH_TYPE: + if (len < WMA_IPV4_PROTO_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("IPV4 Packet"); + + proto_type = qdf_nbuf_data_get_ipv4_proto(data); + wma_debug("IPV4_proto_type: %u", proto_type); + + switch (proto_type) { + case QDF_NBUF_TRAC_ICMP_TYPE: + if (len < WMA_ICMP_SUBTYPE_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("ICMP Packet"); + return qdf_nbuf_data_get_icmp_subtype(data); + + case QDF_NBUF_TRAC_UDP_TYPE: + if (len < WMA_IS_DHCP_GET_MIN_LEN) + return QDF_PROTO_IPV4_UDP; + + if (!qdf_nbuf_data_is_ipv4_dhcp_pkt(data)) + return QDF_PROTO_IPV4_UDP; + + if (len < WMA_DHCP_SUBTYPE_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("DHCP Packet"); + return qdf_nbuf_data_get_dhcp_subtype(data); + + case QDF_NBUF_TRAC_TCP_TYPE: + return QDF_PROTO_IPV4_TCP; + + default: + return QDF_PROTO_INVALID; + } + + case QDF_NBUF_TRAC_IPV6_ETH_TYPE: + if (len < WMA_IPV6_PROTO_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("IPV6 Packet"); + + proto_type = qdf_nbuf_data_get_ipv6_proto(data); + wma_debug("IPV6_proto_type: %u", proto_type); + + switch (proto_type) { + case QDF_NBUF_TRAC_ICMPV6_TYPE: + if (len < WMA_ICMPV6_SUBTYPE_GET_MIN_LEN) + return QDF_PROTO_INVALID; + + wma_debug("ICMPV6 Packet"); + return qdf_nbuf_data_get_icmpv6_subtype(data); + + case QDF_NBUF_TRAC_UDP_TYPE: + return QDF_PROTO_IPV6_UDP; + + case QDF_NBUF_TRAC_TCP_TYPE: + return QDF_PROTO_IPV6_TCP; + + default: + return QDF_PROTO_INVALID; + } + + default: + return QDF_PROTO_INVALID; + } +} + +static void wma_log_pkt_eapol(uint8_t *data, uint32_t length) +{ + uint16_t pkt_len, key_len; + + if (length < WMA_EAPOL_INFO_GET_MIN_LEN) + return; + + pkt_len = *(uint16_t *)(data + EAPOL_PKT_LEN_OFFSET); + key_len = *(uint16_t *)(data + EAPOL_KEY_LEN_OFFSET); + wma_debug("Pkt_len: %u, Key_len: %u", + qdf_cpu_to_be16(pkt_len), qdf_cpu_to_be16(key_len)); +} + +static void wma_log_pkt_dhcp(uint8_t *data, uint32_t length) +{ + uint16_t pkt_len; + uint32_t trans_id; + + if (length < WMA_DHCP_INFO_GET_MIN_LEN) + return; + + pkt_len = *(uint16_t *)(data + DHCP_PKT_LEN_OFFSET); + trans_id = *(uint32_t *)(data + DHCP_TRANSACTION_ID_OFFSET); + wma_debug("Pkt_len: %u, Transaction_id: %u", + qdf_cpu_to_be16(pkt_len), qdf_cpu_to_be16(trans_id)); +} + +static void wma_log_pkt_icmpv4(uint8_t *data, uint32_t length) +{ + uint16_t pkt_len, seq_num; + + if (length < WMA_IPV4_PKT_INFO_GET_MIN_LEN) + return; + + pkt_len = *(uint16_t *)(data + IPV4_PKT_LEN_OFFSET); + seq_num = *(uint16_t *)(data + ICMP_SEQ_NUM_OFFSET); + wma_debug("Pkt_len: %u, Seq_num: %u", + qdf_cpu_to_be16(pkt_len), qdf_cpu_to_be16(seq_num)); +} + +static void wma_log_pkt_icmpv6(uint8_t *data, uint32_t length) +{ + uint16_t pkt_len, seq_num; + + if (length < WMA_IPV6_PKT_INFO_GET_MIN_LEN) + return; + + pkt_len = *(uint16_t *)(data + IPV6_PKT_LEN_OFFSET); + seq_num = *(uint16_t *)(data + ICMPV6_SEQ_NUM_OFFSET); + wma_debug("Pkt_len: %u, Seq_num: %u", + qdf_cpu_to_be16(pkt_len), qdf_cpu_to_be16(seq_num)); +} + +static void wma_log_pkt_ipv4(uint8_t *data, uint32_t length) +{ + uint16_t pkt_len, src_port, dst_port; + char *ip_addr; + + if (length < WMA_IPV4_PKT_INFO_GET_MIN_LEN) + return; + + pkt_len = *(uint16_t *)(data + IPV4_PKT_LEN_OFFSET); + ip_addr = (char *)(data + IPV4_SRC_ADDR_OFFSET); + wma_nofl_debug("src addr %d:%d:%d:%d", ip_addr[0], ip_addr[1], + ip_addr[2], ip_addr[3]); + ip_addr = (char *)(data + IPV4_DST_ADDR_OFFSET); + wma_nofl_debug("dst addr %d:%d:%d:%d", ip_addr[0], ip_addr[1], + ip_addr[2], ip_addr[3]); + src_port = *(uint16_t *)(data + IPV4_SRC_PORT_OFFSET); + dst_port = *(uint16_t *)(data + IPV4_DST_PORT_OFFSET); + wma_debug("Pkt_len: %u, src_port: %u, dst_port: %u", + qdf_cpu_to_be16(pkt_len), + qdf_cpu_to_be16(src_port), + qdf_cpu_to_be16(dst_port)); +} + +static void wma_log_pkt_ipv6(uint8_t *data, uint32_t length) +{ + uint16_t pkt_len, src_port, dst_port; + char *ip_addr; + + if (length < WMA_IPV6_PKT_INFO_GET_MIN_LEN) + return; + + pkt_len = *(uint16_t *)(data + IPV6_PKT_LEN_OFFSET); + ip_addr = (char *)(data + IPV6_SRC_ADDR_OFFSET); + wma_nofl_debug("src addr "IPV6_ADDR_STR, ip_addr[0], + ip_addr[1], ip_addr[2], ip_addr[3], ip_addr[4], + ip_addr[5], ip_addr[6], ip_addr[7], ip_addr[8], + ip_addr[9], ip_addr[10], ip_addr[11], + ip_addr[12], ip_addr[13], ip_addr[14], + ip_addr[15]); + ip_addr = (char *)(data + IPV6_DST_ADDR_OFFSET); + wma_nofl_debug("dst addr "IPV6_ADDR_STR, ip_addr[0], + ip_addr[1], ip_addr[2], ip_addr[3], ip_addr[4], + ip_addr[5], ip_addr[6], ip_addr[7], ip_addr[8], + ip_addr[9], ip_addr[10], ip_addr[11], + ip_addr[12], ip_addr[13], ip_addr[14], + ip_addr[15]); + src_port = *(uint16_t *)(data + IPV6_SRC_PORT_OFFSET); + dst_port = *(uint16_t *)(data + IPV6_DST_PORT_OFFSET); + wma_info("Pkt_len: %u, src_port: %u, dst_port: %u", + qdf_cpu_to_be16(pkt_len), + qdf_cpu_to_be16(src_port), + qdf_cpu_to_be16(dst_port)); +} + +static void wma_log_pkt_tcpv4(uint8_t *data, uint32_t length) +{ + uint32_t seq_num; + + if (length < WMA_IPV4_PKT_INFO_GET_MIN_LEN) + return; + + seq_num = *(uint32_t *)(data + IPV4_TCP_SEQ_NUM_OFFSET); + wma_debug("TCP_seq_num: %u", qdf_cpu_to_be16(seq_num)); +} + +static void wma_log_pkt_tcpv6(uint8_t *data, uint32_t length) +{ + uint32_t seq_num; + + if (length < WMA_IPV6_PKT_INFO_GET_MIN_LEN) + return; + + seq_num = *(uint32_t *)(data + IPV6_TCP_SEQ_NUM_OFFSET); + wma_debug("TCP_seq_num: %u", qdf_cpu_to_be16(seq_num)); +} + +static void wma_wow_inc_wake_lock_stats_by_dst_addr(t_wma_handle *wma, + uint8_t vdev_id, + uint8_t *dest_mac) +{ + ucfg_mc_cp_stats_inc_wake_lock_stats_by_dst_addr(wma->psoc, + vdev_id, + dest_mac); +} + +static void wma_wow_inc_wake_lock_stats_by_protocol(t_wma_handle *wma, + uint8_t vdev_id, enum qdf_proto_subtype proto_subtype) +{ + ucfg_mc_cp_stats_inc_wake_lock_stats_by_protocol(wma->psoc, + vdev_id, + proto_subtype); +} + +/** + * wma_wow_parse_data_pkt() - API to parse data buffer for data + * packet that resulted in WOW wakeup. + * @stats: per-vdev stats for tracking packet types + * @data: Pointer to data buffer + * @length: data buffer length + * + * This function parses the data buffer received (first few bytes of + * skb->data) to get information like src mac addr, dst mac addr, packet + * len, seq_num, etc. It also increments stats for different packet types. + * + * Return: void + */ +static void wma_wow_parse_data_pkt(t_wma_handle *wma, + uint8_t vdev_id, uint8_t *data, + uint32_t length) +{ + uint8_t *src_mac; + uint8_t *dest_mac; + const char *proto_subtype_name; + enum qdf_proto_subtype proto_subtype; + + wma_debug("packet length: %u", length); + if (length < QDF_NBUF_TRAC_IPV4_OFFSET) + return; + + src_mac = data + QDF_NBUF_SRC_MAC_OFFSET; + dest_mac = data + QDF_NBUF_DEST_MAC_OFFSET; + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "Src_mac: " QDF_MAC_ADDR_FMT ", Dst_mac: " + QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(src_mac), + QDF_MAC_ADDR_REF(dest_mac)); + + wma_wow_inc_wake_lock_stats_by_dst_addr(wma, vdev_id, dest_mac); + + proto_subtype = wma_wow_get_pkt_proto_subtype(data, length); + proto_subtype_name = wma_pkt_proto_subtype_to_string(proto_subtype); + if (proto_subtype_name) + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "WOW Wakeup: %s rcvd", proto_subtype_name); + + switch (proto_subtype) { + case QDF_PROTO_EAPOL_M1: + case QDF_PROTO_EAPOL_M2: + case QDF_PROTO_EAPOL_M3: + case QDF_PROTO_EAPOL_M4: + wma_log_pkt_eapol(data, length); + break; + + case QDF_PROTO_DHCP_DISCOVER: + case QDF_PROTO_DHCP_REQUEST: + case QDF_PROTO_DHCP_OFFER: + case QDF_PROTO_DHCP_ACK: + case QDF_PROTO_DHCP_NACK: + case QDF_PROTO_DHCP_RELEASE: + case QDF_PROTO_DHCP_INFORM: + case QDF_PROTO_DHCP_DECLINE: + wma_log_pkt_dhcp(data, length); + break; + + case QDF_PROTO_ICMP_REQ: + case QDF_PROTO_ICMP_RES: + wma_wow_inc_wake_lock_stats_by_protocol(wma, vdev_id, + proto_subtype); + wma_log_pkt_icmpv4(data, length); + break; + + case QDF_PROTO_ICMPV6_REQ: + case QDF_PROTO_ICMPV6_RES: + case QDF_PROTO_ICMPV6_RS: + case QDF_PROTO_ICMPV6_RA: + case QDF_PROTO_ICMPV6_NS: + case QDF_PROTO_ICMPV6_NA: + wma_wow_inc_wake_lock_stats_by_protocol(wma, vdev_id, + proto_subtype); + wma_log_pkt_icmpv6(data, length); + break; + + case QDF_PROTO_IPV4_UDP: + wma_log_pkt_ipv4(data, length); + break; + case QDF_PROTO_IPV4_TCP: + wma_log_pkt_ipv4(data, length); + wma_log_pkt_tcpv4(data, length); + break; + + case QDF_PROTO_IPV6_UDP: + wma_log_pkt_ipv6(data, length); + break; + case QDF_PROTO_IPV6_TCP: + wma_log_pkt_ipv6(data, length); + wma_log_pkt_tcpv6(data, length); + break; + default: + break; + } +} + +/** + * wma_wow_dump_mgmt_buffer() - API to parse data buffer for mgmt. + * packet that resulted in WOW wakeup. + * @wow_packet_buffer: Pointer to data buffer + * @buf_len: length of data buffer + * + * This function parses the data buffer received (802.11 header) + * to get information like src mac addr, dst mac addr, seq_num, + * frag_num, etc. + * + * Return: void + */ +static void wma_wow_dump_mgmt_buffer(uint8_t *wow_packet_buffer, + uint32_t buf_len) +{ + struct ieee80211_frame_addr4 *wh; + + wma_debug("wow_buf_pkt_len: %u", buf_len); + wh = (struct ieee80211_frame_addr4 *) + (wow_packet_buffer); + if (buf_len >= sizeof(struct ieee80211_frame)) { + uint8_t to_from_ds, frag_num; + uint32_t seq_num; + + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "RA: " QDF_MAC_ADDR_FMT " TA: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wh->i_addr1), + QDF_MAC_ADDR_REF(wh->i_addr2)); + + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "TO_DS: %u, FROM_DS: %u", + wh->i_fc[1] & IEEE80211_FC1_DIR_TODS, + wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS); + + to_from_ds = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; + + switch (to_from_ds) { + case IEEE80211_FC1_DIR_NODS: + wma_conditional_log( + is_wakeup_event_console_logs_enabled, + "BSSID: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wh->i_addr3)); + break; + case IEEE80211_FC1_DIR_TODS: + wma_conditional_log( + is_wakeup_event_console_logs_enabled, + "DA: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wh->i_addr3)); + break; + case IEEE80211_FC1_DIR_FROMDS: + wma_conditional_log( + is_wakeup_event_console_logs_enabled, + "SA: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wh->i_addr3)); + break; + case IEEE80211_FC1_DIR_DSTODS: + if (buf_len >= sizeof(struct ieee80211_frame_addr4)) + wma_conditional_log( + is_wakeup_event_console_logs_enabled, + "DA: " QDF_MAC_ADDR_FMT " SA: " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wh->i_addr3), + QDF_MAC_ADDR_REF(wh->i_addr4)); + break; + } + + seq_num = (((*(uint16_t *)wh->i_seq) & + IEEE80211_SEQ_SEQ_MASK) >> + IEEE80211_SEQ_SEQ_SHIFT); + frag_num = (((*(uint16_t *)wh->i_seq) & + IEEE80211_SEQ_FRAG_MASK) >> + IEEE80211_SEQ_FRAG_SHIFT); + + wma_conditional_log(is_wakeup_event_console_logs_enabled, + "SEQ_NUM: %u, FRAG_NUM: %u", seq_num, + frag_num); + } else { + wma_err("Insufficient buffer length for mgmt. packet"); + } +} + +/** + * wma_acquire_wakelock() - conditionally acquires a wakelock base on wake reason + * @wma: the wma handle with the wakelocks to acquire + * @wake_reason: wow wakeup reason + * + * Return: None + */ +static void wma_acquire_wow_wakelock(t_wma_handle *wma, int wake_reason) +{ + qdf_wake_lock_t *wl; + uint32_t ms; + + switch (wake_reason) { + case WOW_REASON_AUTH_REQ_RECV: + wl = &wma->wow_auth_req_wl; + ms = WMA_AUTH_REQ_RECV_WAKE_LOCK_TIMEOUT; + break; + case WOW_REASON_ASSOC_REQ_RECV: + wl = &wma->wow_assoc_req_wl; + ms = WMA_ASSOC_REQ_RECV_WAKE_LOCK_DURATION; + break; + case WOW_REASON_DEAUTH_RECVD: + wl = &wma->wow_deauth_rec_wl; + ms = WMA_DEAUTH_RECV_WAKE_LOCK_DURATION; + break; + case WOW_REASON_DISASSOC_RECVD: + wl = &wma->wow_disassoc_rec_wl; + ms = WMA_DISASSOC_RECV_WAKE_LOCK_DURATION; + break; + case WOW_REASON_AP_ASSOC_LOST: + wl = &wma->wow_ap_assoc_lost_wl; + ms = WMA_BMISS_EVENT_WAKE_LOCK_DURATION; + break; +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WOW_REASON_HOST_AUTO_SHUTDOWN: + wl = &wma->wow_auto_shutdown_wl; + ms = WMA_AUTO_SHUTDOWN_WAKE_LOCK_DURATION; + break; +#endif + case WOW_REASON_ROAM_HO: + wl = &wma->roam_ho_wl; + ms = WMA_ROAM_HO_WAKE_LOCK_DURATION; + break; + case WOW_REASON_ROAM_PREAUTH_START: + wl = &wma->roam_preauth_wl; + ms = WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION; + break; + case WOW_REASON_PROBE_REQ_WPS_IE_RECV: + wl = &wma->probe_req_wps_wl; + ms = WMA_REASON_PROBE_REQ_WPS_IE_RECV_DURATION; + break; + default: + return; + } + + wma_alert("Holding %d msec wake_lock", ms); + cds_host_diag_log_work(wl, ms, WIFI_POWER_EVENT_WAKELOCK_WOW); + qdf_wake_lock_timeout_acquire(wl, ms); +} + +/** + * wma_wake_reason_ap_assoc_lost() - WOW_REASON_AP_ASSOC_LOST handler + * @wma: Pointer to wma handle + * @event: pointer to piggybacked WMI_ROAM_EVENTID_param_tlvs buffer + * @len: length of the event buffer + * + * Return: Errno + */ +static int +wma_wake_reason_ap_assoc_lost(t_wma_handle *wma, void *event, uint32_t len) +{ + WMI_ROAM_EVENTID_param_tlvs *event_param; + wmi_roam_event_fixed_param *roam_event; + + event_param = event; + if (!event_param) { + wma_err("AP Assoc Lost event data is null"); + return -EINVAL; + } + + roam_event = event_param->fixed_param; + wma_alert("Beacon miss indication on vdev %d", roam_event->vdev_id); + + wma_beacon_miss_handler(wma, roam_event->vdev_id, roam_event->rssi); + + return 0; +} + +static const char *wma_vdev_type_str(uint32_t vdev_type) +{ + switch (vdev_type) { + case WMI_VDEV_TYPE_AP: + return "AP"; + case WMI_VDEV_TYPE_STA: + return "STA"; + case WMI_VDEV_TYPE_IBSS: + return "IBSS"; + case WMI_VDEV_TYPE_MONITOR: + return "MONITOR"; + case WMI_VDEV_TYPE_NAN: + return "NAN"; + case WMI_VDEV_TYPE_OCB: + return "OCB"; + case WMI_VDEV_TYPE_NDI: + return "NDI"; + default: + return "unknown"; + } +} + +static int wma_wake_event_packet( + t_wma_handle *wma, + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *event_param, + uint32_t length) +{ + WOW_EVENT_INFO_fixed_param *wake_info; + struct wma_txrx_node *vdev; + uint8_t *packet; + uint32_t packet_len; + + if (event_param->num_wow_packet_buffer <= 4) { + wma_err("Invalid wow packet buffer from firmware %u", + event_param->num_wow_packet_buffer); + return -EINVAL; + } + /* first 4 bytes are the length, followed by the buffer */ + packet_len = *(uint32_t *)event_param->wow_packet_buffer; + packet = event_param->wow_packet_buffer + 4; + + if (!packet_len) { + wma_err("Wake event packet is empty"); + return 0; + } + + if (packet_len > (event_param->num_wow_packet_buffer - 4)) { + wma_err("Invalid packet_len from firmware, packet_len: %u, num_wow_packet_buffer: %u", + packet_len, + event_param->num_wow_packet_buffer); + return -EINVAL; + } + + wake_info = event_param->fixed_param; + + wma_debug("Number of delayed packets received = %d", + wake_info->delayed_pkt_count); + + switch (wake_info->wake_reason) { + case WOW_REASON_AUTH_REQ_RECV: + case WOW_REASON_ASSOC_REQ_RECV: + case WOW_REASON_DEAUTH_RECVD: + case WOW_REASON_DISASSOC_RECVD: + case WOW_REASON_ASSOC_RES_RECV: + case WOW_REASON_REASSOC_REQ_RECV: + case WOW_REASON_REASSOC_RES_RECV: + case WOW_REASON_BEACON_RECV: + case WOW_REASON_ACTION_FRAME_RECV: + /* management frame case */ + wma_wow_dump_mgmt_buffer(packet, packet_len); + break; + + case WOW_REASON_BPF_ALLOW: + case WOW_REASON_PATTERN_MATCH_FOUND: + case WOW_REASON_RA_MATCH: + case WOW_REASON_RECV_MAGIC_PATTERN: + case WOW_REASON_PACKET_FILTER_MATCH: + case WOW_REASON_DELAYED_WAKEUP_HOST_CFG_TIMER_ELAPSED: + case WOW_REASON_DELAYED_WAKEUP_DATA_STORE_LIST_FULL: + wma_info("Wake event packet:"); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + packet, packet_len); + + vdev = &wma->interfaces[wake_info->vdev_id]; + wma_wow_parse_data_pkt(wma, wake_info->vdev_id, + packet, packet_len); + break; + + case WOW_REASON_PAGE_FAULT: + /* + * In case PAGE_FAULT occurs on non-DRV platform, + * dump event buffer which contains more info regarding + * current page fault. + */ + wma_info("PF occurs during suspend: packet_len %u", + packet_len); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_INFO, + packet, packet_len); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int wma_wake_event_no_payload( + t_wma_handle *wma, + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *event_param, + uint32_t length) +{ + WOW_EVENT_INFO_fixed_param *wake_info = event_param->fixed_param; + + switch (wake_info->wake_reason) { + case WOW_REASON_HOST_AUTO_SHUTDOWN: + return wma_wake_reason_auto_shutdown(); + + case WOW_REASON_NLOD: + return wma_wake_reason_nlod(wma, wake_info->vdev_id); + + case WOW_REASON_GENERIC_WAKE: + case WOW_REASON_ROAM_STATS: + case WOW_REASON_RTT_11AZ: + wma_info("Wake reason %s", + wma_wow_wake_reason_str(wake_info->wake_reason)); + return 0; + + default: + return 0; + } +} + +static int wma_wake_event_piggybacked( + t_wma_handle *wma, + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *event_param, + uint32_t length) +{ + int errno = 0; + void *pb_event; + uint32_t pb_event_len; + uint32_t wake_reason; + uint32_t event_id; + uint8_t *bssid; + tpDeleteStaContext del_sta_ctx; + + /* + * There are "normal" cases where a wake reason that usually contains a + * piggybacked event is empty. In these cases we just want to wake up, + * and no action is needed. Bail out now if that is the case. + */ + if (!event_param->wow_packet_buffer || + event_param->num_wow_packet_buffer <= 4) { + wma_err("Invalid wow packet buffer from firmware %u", + event_param->num_wow_packet_buffer); + return 0; + } + + bssid = wma_get_vdev_bssid + (wma->interfaces[event_param->fixed_param->vdev_id].vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", + event_param->fixed_param->vdev_id); + return 0; + } + wake_reason = event_param->fixed_param->wake_reason; + + /* parse piggybacked event from param buffer */ + { + int ret_code; + uint8_t *pb_event_buf; + uint32_t tag; + + /* first 4 bytes are the length, followed by the buffer */ + pb_event_len = *(uint32_t *)event_param->wow_packet_buffer; + if (pb_event_len > (event_param->num_wow_packet_buffer - 4)) { + wma_err("Invalid pb_event_len from firmware, pb_event_len: %u, num_wow_packet_buffer: %u", + pb_event_len, + event_param->num_wow_packet_buffer); + return -EINVAL; + } + pb_event_buf = event_param->wow_packet_buffer + 4; + + wma_debug("piggybacked event buffer:"); + qdf_trace_hex_dump(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + pb_event_buf, pb_event_len); + + tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(pb_event_buf)); + event_id = wow_get_wmi_eventid(wake_reason, tag); + if (!event_id) { + wma_err("Unable to find Event Id"); + return -EINVAL; + } + + ret_code = wmitlv_check_and_pad_event_tlvs(wma, pb_event_buf, + pb_event_len, + event_id, &pb_event); + if (ret_code) { + wma_err("Bad TLVs; len:%d, event_id:%d, status:%d", + pb_event_len, event_id, ret_code); + return -EINVAL; + } + } + + switch (wake_reason) { + case WOW_REASON_AP_ASSOC_LOST: + errno = wma_wake_reason_ap_assoc_lost(wma, pb_event, + pb_event_len); + break; + +#ifdef FEATURE_WLAN_SCAN_PNO + case WOW_REASON_NLO_SCAN_COMPLETE: + errno = target_if_nlo_complete_handler(wma, pb_event, + pb_event_len); + break; +#endif /* FEATURE_WLAN_SCAN_PNO */ + + case WOW_REASON_CSA_EVENT: + errno = wma_csa_offload_handler(wma, pb_event, pb_event_len); + break; + + /* + * WOW_REASON_LOW_RSSI is used for following roaming events - + * WMI_ROAM_REASON_BETTER_AP, WMI_ROAM_REASON_BMISS, + * WMI_ROAM_REASON_SUITABLE_AP will be handled by + * wma_roam_event_callback(). + * WOW_REASON_ROAM_HO is associated with + * WMI_ROAM_REASON_HO_FAILED event and it will be handled by + * wma_roam_event_callback(). + */ + case WOW_REASON_LOW_RSSI: + case WOW_REASON_ROAM_HO: + wlan_roam_debug_log(event_param->fixed_param->vdev_id, + DEBUG_WOW_ROAM_EVENT, + DEBUG_INVALID_PEER_ID, + NULL, NULL, wake_reason, + pb_event_len); + if (pb_event_len > 0) { + errno = target_if_cm_roam_event(wma, pb_event, + pb_event_len); + } else { + /* + * No wow_packet_buffer means a better AP beacon + * will follow in a later event. + */ + wma_debug("Host woken up because of better AP beacon"); + } + break; + + case WOW_REASON_CLIENT_KICKOUT_EVENT: + errno = wma_peer_sta_kickout_event_handler(wma, pb_event, + pb_event_len); + break; + +#ifdef FEATURE_WLAN_EXTSCAN + case WOW_REASON_EXTSCAN: + errno = wma_extscan_wow_event_callback(wma, pb_event, + pb_event_len); + break; +#endif + + case WOW_REASON_RSSI_BREACH_EVENT: + errno = wma_rssi_breached_event_handler(wma, pb_event, + pb_event_len); + break; + + case WOW_REASON_NAN_EVENT: + errno = wma_nan_rsp_handler_callback(wma, pb_event, + pb_event_len); + break; + + case WOW_REASON_NAN_DATA: + errno = wma_ndp_wow_event_callback(wma, pb_event, pb_event_len, + event_id); + break; + +#ifdef FEATURE_WLAN_TDLS + case WOW_REASON_TDLS_CONN_TRACKER_EVENT: + errno = wma_tdls_event_handler(wma, pb_event, pb_event_len); + break; +#endif + + case WOW_REASON_TIMER_INTR_RECV: + /* + * Right now firmware is not returning any cookie host has + * programmed. So do not check for cookie. + */ + wma_err("WOW_REASON_TIMER_INTR_RECV received, indicating key exchange did not finish. Initiate disconnect"); + del_sta_ctx = qdf_mem_malloc(sizeof(*del_sta_ctx)); + if (!del_sta_ctx) + break; + + del_sta_ctx->is_tdls = false; + del_sta_ctx->vdev_id = event_param->fixed_param->vdev_id; + qdf_mem_copy(del_sta_ctx->addr2, bssid, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(del_sta_ctx->bssId, bssid, QDF_MAC_ADDR_SIZE); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, del_sta_ctx, + 0); + break; + case WOW_REASON_ROAM_PMKID_REQUEST: + wma_debug("Host woken up because of PMKID request event"); + errno = target_if_pmkid_request_event_handler(wma, + pb_event, pb_event_len); + break; + case WOW_REASON_VDEV_DISCONNECT: + wma_debug("Host woken up because of vdev disconnect event"); + errno = target_if_cm_roam_vdev_disconnect_event_handler(wma, + pb_event, pb_event_len); + break; + default: + wma_err("Wake reason %s(%u) is not a piggybacked event", + wma_wow_wake_reason_str(wake_reason), wake_reason); + errno = -EINVAL; + break; + } + + wmitlv_free_allocated_event_tlvs(event_id, &pb_event); + + return errno; +} + +static void wma_debug_assert_page_fault_wakeup(uint32_t reason) +{ + /* During DRV if page fault wake up then assert */ + if ((WOW_REASON_PAGE_FAULT == reason) && (qdf_is_drv_connected())) + QDF_DEBUG_PANIC("Unexpected page fault wake up detected during DRV wow"); +} + +static void wma_wake_event_log_reason(t_wma_handle *wma, + WOW_EVENT_INFO_fixed_param *wake_info) +{ + struct wma_txrx_node *vdev; + + /* "Unspecified" means APPS triggered wake, else firmware triggered */ + if (wake_info->wake_reason != WOW_REASON_UNSPECIFIED) { + vdev = &wma->interfaces[wake_info->vdev_id]; + wma_nofl_info("WLAN triggered wakeup: %s (%d), vdev: %d (%s)", + wma_wow_wake_reason_str(wake_info->wake_reason), + wake_info->wake_reason, + wake_info->vdev_id, + wma_vdev_type_str(vdev->type)); + wma_debug_assert_page_fault_wakeup(wake_info->wake_reason); + } else if (!wmi_get_runtime_pm_inprogress(wma->wmi_handle)) { + wma_nofl_info("Non-WLAN triggered wakeup: %s (%d)", + wma_wow_wake_reason_str(wake_info->wake_reason), + wake_info->wake_reason); + } + + qdf_wow_wakeup_host_event(wake_info->wake_reason); + qdf_wma_wow_wakeup_stats_event(wma); +} + +static QDF_STATUS wma_wow_pagefault_action_cb(void *buf) +{ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("NULL mac ptr"); + return QDF_STATUS_E_INVAL; + } + + return mac->sme.pagefault_action_cb(buf, WLAN_WMA_PF_APPS_NOTIFY_BUF_LEN); +} + +static QDF_STATUS +wma_wow_pagefault_add_sym_to_event(tp_wma_handle wma, struct wow_pf_sym *pf_sym) +{ + uint8_t *buf_ptr = wma->wma_pf_hist.pf_notify_buf_ptr; + uint32_t buf_len = wma->wma_pf_hist.pf_notify_buf_len; + + if (WLAN_WMA_PF_APPS_NOTIFY_BUF_LEN - buf_len < + WLAN_WMA_PER_PF_SYM_NOTIFY_BUF_LEN) { + wma_wow_pagefault_action_cb(buf_ptr); + buf_len = 0; + } + + /* Mem zero to send buffer with zero padding */ + if (!buf_len) + qdf_mem_zero(buf_ptr, WLAN_WMA_PF_APPS_NOTIFY_BUF_LEN); + + qdf_mem_copy(buf_ptr + buf_len, pf_sym, + WLAN_WMA_PER_PF_SYM_NOTIFY_BUF_LEN); + buf_len += WLAN_WMA_PER_PF_SYM_NOTIFY_BUF_LEN; + + wma->wma_pf_hist.pf_notify_buf_len = buf_len; + + return QDF_STATUS_SUCCESS; +} + +static void +wma_wow_pagefault_add_new_sym_from_event(tp_wma_handle wma, + struct wow_pf_wakeup_ev_data *pf_sym_list, + qdf_time_t cur_time) +{ + uint8_t tbl_idx, ev_lst_idx, new_pf_idx, idx2; + uint8_t new_idx_cnt, cur_idx_cnt, ev_sym_cnt, pf_th; + uint8_t max_sym_count = WLAN_WMA_MAX_PF_SYM; + qdf_time_t new_idx_last_ts, cur_idx_last_ts; + qdf_time_t new_idx_old_ts, cur_idx_old_ts; + struct wma_pf_sym *cur_pf_entry, *new_pf_entry; + struct wma_pf_sym_hist *pf_sym_hist = &wma->wma_pf_hist; + + pf_th = wlan_pmo_get_min_pagefault_wakeups_for_action(wma->psoc); + for (tbl_idx = 0; tbl_idx < max_sym_count; tbl_idx++) { + if (!pf_sym_list->pending_pf_syms) + break; + + new_pf_idx = tbl_idx; + new_pf_entry = &pf_sym_hist->wma_pf_sym[tbl_idx]; + new_idx_cnt = new_pf_entry->pf_sym.count; + new_idx_last_ts = new_pf_entry->pf_ev_ts[new_idx_cnt - 1]; + new_idx_old_ts = new_pf_entry->pf_ev_ts[0]; + + for (ev_lst_idx = 0; ev_lst_idx < pf_sym_list->num_pf_syms; + ev_lst_idx++) { + if (!pf_sym_list->pf_sym[ev_lst_idx].count) + continue; + + /* Add the sym that already met threshold to the buf */ + if (pf_sym_list->pf_sym[ev_lst_idx].count >= pf_th) { + wma_wow_pagefault_add_sym_to_event(wma, + pf_sym_list->pf_sym); + pf_sym_list->pf_sym[ev_lst_idx].count = 0x0; + pf_sym_list->pending_pf_syms--; + continue; + } + + ev_sym_cnt = pf_sym_list->pf_sym[ev_lst_idx].count; + + /* If current entry is NULL, add the symbol here */ + if (!new_idx_cnt) + goto add_sym; + + /* Replace event if count is equal as current event + * is latest and don't replace symbol from current event + */ + if (new_idx_cnt > ev_sym_cnt || + qdf_system_time_after_eq(new_idx_last_ts, cur_time)) + break; + + for (idx2 = tbl_idx + 1; idx2 < max_sym_count; idx2++) { + cur_pf_entry = &pf_sym_hist->wma_pf_sym[idx2]; + cur_idx_cnt = cur_pf_entry->pf_sym.count; + cur_idx_last_ts = + cur_pf_entry->pf_ev_ts[cur_idx_cnt - 1]; + cur_idx_old_ts = cur_pf_entry->pf_ev_ts[0]; + + if (cur_idx_cnt > new_idx_cnt) + continue; + + /* Don't replace symbol from current event */ + if (qdf_system_time_after_eq(cur_idx_last_ts, + cur_time)) { + continue; + } + + if (cur_idx_cnt == new_idx_cnt && + qdf_system_time_after_eq(cur_idx_old_ts, + new_idx_old_ts)) { + continue; + } + + new_pf_idx = idx2; + new_idx_cnt = cur_idx_cnt; + new_idx_last_ts = cur_idx_last_ts; + new_idx_old_ts = cur_idx_old_ts; + } + +add_sym: + /* Replace symbol with current event symbol */ + new_pf_entry = &pf_sym_hist->wma_pf_sym[new_pf_idx]; + new_pf_entry->pf_sym.symbol = + pf_sym_list->pf_sym[ev_lst_idx].symbol; + new_pf_entry->pf_sym.count = ev_sym_cnt; + for (idx2 = 0; idx2 < ev_sym_cnt; idx2++) + new_pf_entry->pf_ev_ts[idx2] = cur_time; + + pf_sym_list->pending_pf_syms--; + pf_sym_list->pf_sym[ev_lst_idx].count = 0; + break; + } + } +} + +static void +wma_wow_pagefault_process_existing_syms(tp_wma_handle wma, + struct wma_pf_sym *pf_sym_entry, + struct wow_pf_wakeup_ev_data *ev_list, + qdf_time_t cur_time) +{ + uint8_t ev_idx, add_idx; + uint8_t pf_th, *tbl_sym_cnt, ev_sym_cnt; + + pf_th = wlan_pmo_get_min_pagefault_wakeups_for_action(wma->psoc); + tbl_sym_cnt = &pf_sym_entry->pf_sym.count; + + for (ev_idx = 0; ev_idx < ev_list->num_pf_syms; ev_idx++) { + /* Ignore if all symbols are processed */ + if (!ev_list->pending_pf_syms) + break; + + if (!ev_list->pf_sym[ev_idx].count) + continue; + + /* Only process symbol equals current entry in the history */ + if (ev_list->pf_sym[ev_idx].symbol != + pf_sym_entry->pf_sym.symbol) { + continue; + } + + ev_sym_cnt = ev_list->pf_sym[ev_idx].count; + + /* If symbol reaches threshold, then clear the ts data */ + if (*tbl_sym_cnt + ev_sym_cnt >= pf_th) { + qdf_mem_zero(&pf_sym_entry->pf_ev_ts[0], + (*tbl_sym_cnt * sizeof(qdf_time_t))); + *tbl_sym_cnt += ev_sym_cnt; + wma_wow_pagefault_add_sym_to_event(wma, + &pf_sym_entry->pf_sym); + *tbl_sym_cnt = 0x0; + + goto sym_handled; + } + + for (add_idx = 0; add_idx < ev_sym_cnt; add_idx++) + pf_sym_entry->pf_ev_ts[(*tbl_sym_cnt)++] = cur_time; + +sym_handled: + ev_list->pending_pf_syms--; + ev_list->pf_sym[ev_idx].count = 0; + break; + } +} + +static void +wma_wow_pagefault_flush_ageout_entries(struct wma_pf_sym *pf_sym_entry, + qdf_time_t cutoff_time) +{ + qdf_time_t entry_ts; + uint8_t *cur_pf_count, pf_ts_idx; + + cur_pf_count = &pf_sym_entry->pf_sym.count; + /* Find the count of entries which elapsed cutoff time */ + for (pf_ts_idx = 0; pf_ts_idx < *cur_pf_count; pf_ts_idx++) { + entry_ts = pf_sym_entry->pf_ev_ts[pf_ts_idx]; + if (qdf_system_time_before(cutoff_time, entry_ts)) + break; + } + + /* Remove the entries which elapsed cutoff time */ + if (pf_ts_idx > 0) { + *cur_pf_count -= pf_ts_idx; + qdf_mem_copy(&pf_sym_entry->pf_ev_ts[0], + &pf_sym_entry->pf_ev_ts[pf_ts_idx], + (*cur_pf_count * sizeof(qdf_time_t))); + qdf_mem_zero(&pf_sym_entry->pf_ev_ts[*cur_pf_count], + pf_ts_idx * sizeof(qdf_time_t)); + } +} + +static QDF_STATUS +wma_wow_pagefault_parse_event(struct wlan_objmgr_psoc *psoc, + void *ev, uint32_t ev_len, + struct wow_pf_wakeup_ev_data *pf_sym_list) +{ + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *event_param = ev; + uint8_t *cur_list_count, *pf_sym_addr, buf_idx, sym_idx, i; + uint32_t packet_len, symbol, pf_sym_count; + struct wow_pf_sym tmp_pf_sym; + + if (event_param->num_wow_packet_buffer <= sizeof(packet_len)) { + wma_err("Invalid wow packet buffer from FW %u", + event_param->num_wow_packet_buffer); + return QDF_STATUS_E_INVAL; + } + + packet_len = *(uint32_t *)event_param->wow_packet_buffer; + if (!packet_len) { + wma_err("Wake event packet is empty"); + return QDF_STATUS_E_INVAL; + } + + if (packet_len > + (event_param->num_wow_packet_buffer - sizeof(packet_len))) { + wma_err("Invalid packet_len from firmware, packet_len: %u, num_wow_packet_buffer: %u", + packet_len, event_param->num_wow_packet_buffer); + return QDF_STATUS_E_INVAL; + } + + pf_sym_count = packet_len / sizeof(symbol); + /* First 4 bytes following packet len contains UUID */ + pf_sym_count--; + + pf_sym_list->pf_sym = + qdf_mem_malloc(pf_sym_count * sizeof(*pf_sym_list->pf_sym)); + if (!pf_sym_list->pf_sym) + return QDF_STATUS_E_NOMEM; + + /* First 4 bytes of buffer gives length and next 4 bytes for UUID */ + pf_sym_addr = event_param->wow_packet_buffer + (sizeof(packet_len) * 2); + + cur_list_count = &pf_sym_list->num_pf_syms; + for (buf_idx = 0; buf_idx < pf_sym_count; buf_idx++) { + symbol = *(uint32_t *)pf_sym_addr; + + /* Ignore invalid symbols */ + if (!symbol || symbol == (uint32_t)-1) + goto iter_next_sym; + + for (sym_idx = 0; sym_idx < *cur_list_count; sym_idx++) { + if (pf_sym_list->pf_sym[sym_idx].symbol == symbol) { + pf_sym_list->pf_sym[sym_idx].count++; + goto iter_next_sym; + } + } + + pf_sym_list->pf_sym[*cur_list_count].symbol = symbol; + pf_sym_list->pf_sym[*cur_list_count].count++; + (*cur_list_count)++; + +iter_next_sym: + pf_sym_addr += sizeof(symbol); + } + + pf_sym_list->pending_pf_syms = *cur_list_count; + + /* Reorder to prioritize syms with high frequency */ + for (sym_idx = 0; sym_idx < *cur_list_count; sym_idx++) { + for (i = sym_idx + 1; i < *cur_list_count; i++) { + if (pf_sym_list->pf_sym[i].count <= + pf_sym_list->pf_sym[sym_idx].count) { + continue; + } + + tmp_pf_sym.symbol = pf_sym_list->pf_sym[sym_idx].symbol; + tmp_pf_sym.count = pf_sym_list->pf_sym[sym_idx].count; + + pf_sym_list->pf_sym[sym_idx].symbol = + pf_sym_list->pf_sym[i].symbol; + pf_sym_list->pf_sym[sym_idx].count = + pf_sym_list->pf_sym[i].count; + + pf_sym_list->pf_sym[i].symbol = tmp_pf_sym.symbol; + pf_sym_list->pf_sym[i].count = tmp_pf_sym.count; + } + } + + return QDF_STATUS_SUCCESS; +} + +static void wma_wow_pagefault_handle_ssr_action(tp_wma_handle wma) +{ + QDF_STATUS status; + uint8_t *cur_count, pf_thresh; + qdf_time_t cur_time, cutoff_time; + uint32_t pf_wakeup_intv; + struct wma_pf_sym *pf_sym_entry; + + cur_time = qdf_get_system_uptime(); + pf_wakeup_intv = + wlan_pmo_get_interval_for_pagefault_wakeup_counts(wma->psoc); + pf_thresh = wlan_pmo_get_min_pagefault_wakeups_for_action(wma->psoc); + cutoff_time = cur_time - qdf_system_msecs_to_ticks(pf_wakeup_intv); + + pf_sym_entry = &wma->wma_pf_hist.wma_pf_sym[0]; + cur_count = &pf_sym_entry->pf_sym.count; + if (cutoff_time < cur_time) { + wma_wow_pagefault_flush_ageout_entries(pf_sym_entry, + cutoff_time); + } + + pf_sym_entry->pf_ev_ts[(*cur_count)++] = cur_time; + if (*cur_count < pf_thresh) + return; + + /* If SSR threshold condition fails, SSR will not be triggered, so + * save current event and flush oldest entry. + */ + status = wma_wow_pagefault_action_cb(NULL); + if (QDF_IS_STATUS_ERROR(status)) { + (*cur_count)--; + qdf_mem_copy(&pf_sym_entry->pf_ev_ts[0], + &pf_sym_entry->pf_ev_ts[1], + (*cur_count * sizeof(qdf_time_t))); + qdf_mem_zero(&pf_sym_entry->pf_ev_ts[*cur_count], + sizeof(qdf_time_t)); + } +} + +static void +wma_wow_wakeup_pagefault_notify(tp_wma_handle wma, void *ev, uint32_t ev_len) +{ + QDF_STATUS status; + uint32_t pf_wakeup_intv; + qdf_time_t cur_time, cutoff_time; + struct wma_pf_sym *pf_sym_entry; + struct wma_pf_sym_hist *pf_sym_hist = &wma->wma_pf_hist; + struct wlan_objmgr_psoc *psoc = wma->psoc; + uint8_t pf_tbl_idx; + struct wow_pf_wakeup_ev_data pf_sym_list = {0}; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_debug("MAC context NULL"); + return; + } + + if (wlan_pmo_no_op_on_page_fault(psoc)) + return; + + if (wmi_get_runtime_pm_inprogress(wma->wmi_handle)) { + wma_debug("Ignore run time pm wakeup"); + return; + } + + if (!mac->sme.pagefault_action_cb) { + wma_debug("NULL pagefault action cb"); + return; + } + + if (wlan_pmo_enable_ssr_on_page_fault(psoc)) { + wma_wow_pagefault_handle_ssr_action(wma); + return; + } + + cur_time = qdf_get_system_uptime(); + pf_wakeup_intv = + wlan_pmo_get_interval_for_pagefault_wakeup_counts(psoc); + cutoff_time = cur_time - qdf_system_msecs_to_ticks(pf_wakeup_intv); + + status = wma_wow_pagefault_parse_event(psoc, ev, ev_len, &pf_sym_list); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("Failed during page fault payload parse"); + return; + } + + qdf_spinlock_acquire(&pf_sym_hist->lock); + for (pf_tbl_idx = 0; pf_tbl_idx < WLAN_WMA_MAX_PF_SYM; pf_tbl_idx++) { + pf_sym_entry = &pf_sym_hist->wma_pf_sym[pf_tbl_idx]; + if (cutoff_time < cur_time) { + wma_wow_pagefault_flush_ageout_entries(pf_sym_entry, + cutoff_time); + } + + wma_wow_pagefault_process_existing_syms(wma, pf_sym_entry, + &pf_sym_list, cur_time); + + if (!pf_sym_list.pending_pf_syms) + goto send_event; + } + + /* Process if any new symbols are present in the event */ + wma_wow_pagefault_add_new_sym_from_event(wma, &pf_sym_list, cur_time); + +send_event: + if (pf_sym_hist->pf_notify_buf_len) { + wma_wow_pagefault_action_cb(pf_sym_hist->pf_notify_buf_ptr); + pf_sym_hist->pf_notify_buf_len = 0; + } + + qdf_spinlock_release(&pf_sym_hist->lock); + + qdf_mem_free(pf_sym_list.pf_sym); + pf_sym_list.pf_sym = NULL; +} + +/** + * wma_wow_wakeup_host_event() - wakeup host event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Handler to catch wow wakeup host event. This event will have + * reason why the firmware has woken the host. + * + * Return: Errno + */ +int wma_wow_wakeup_host_event(void *handle, uint8_t *event, uint32_t len) +{ + int errno; + t_wma_handle *wma = handle; + WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *event_param; + WOW_EVENT_INFO_fixed_param *wake_info; + + event_param = (WMI_WOW_WAKEUP_HOST_EVENTID_param_tlvs *)event; + if (!event_param) { + wma_err("Wake event data is null"); + return -EINVAL; + } + + wake_info = event_param->fixed_param; + + if (wake_info->vdev_id >= wma->max_bssid) { + wma_err("received invalid vdev_id %d", wake_info->vdev_id); + return -EINVAL; + } + + wma_wake_event_log_reason(wma, wake_info); + if (wake_info->wake_reason == WOW_REASON_PAGE_FAULT) + wma_wow_wakeup_pagefault_notify(wma, event, len); + + if (wake_info->wake_reason == WOW_REASON_LOCAL_DATA_UC_DROP) + hif_rtpm_set_autosuspend_delay(WOW_LARGE_RX_RTPM_DELAY); + + ucfg_pmo_psoc_wakeup_host_event_received(wma->psoc); + + wma_print_wow_stats(wma, wake_info); + /* split based on payload type */ + if (is_piggybacked_event(wake_info->wake_reason)) + errno = wma_wake_event_piggybacked(wma, event_param, len); + else if (event_param->wow_packet_buffer) + errno = wma_wake_event_packet(wma, event_param, len); + else + errno = wma_wake_event_no_payload(wma, event_param, len); + + wma_inc_wow_stats(wma, wake_info); + wma_print_wow_stats(wma, wake_info); + wma_acquire_wow_wakelock(wma, wake_info->wake_reason); + + return errno; +} + +#ifdef FEATURE_WLAN_D0WOW +/** + * wma_d0_wow_disable_ack_event() - wakeup host event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Handler to catch D0-WOW disable ACK event. This event will have + * reason why the firmware has woken the host. + * This is for backward compatible with cld2.0. + * + * Return: 0 for success or error + */ +int wma_d0_wow_disable_ack_event(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + WMI_D0_WOW_DISABLE_ACK_EVENTID_param_tlvs *param_buf; + wmi_d0_wow_disable_ack_event_fixed_param *resp_data; + + param_buf = (WMI_D0_WOW_DISABLE_ACK_EVENTID_param_tlvs *)event; + if (!param_buf) { + wma_err("Invalid D0-WOW disable ACK event buffer!"); + return -EINVAL; + } + + resp_data = param_buf->fixed_param; + + ucfg_pmo_psoc_wakeup_host_event_received(wma->psoc); + + wma_debug("Received D0-WOW disable ACK"); + + return 0; +} +#else +int wma_d0_wow_disable_ack_event(void *handle, uint8_t *event, uint32_t len) +{ + return 0; +} +#endif + +/** + * wma_pdev_resume_event_handler() - PDEV resume event handler + * @handle: wma handle + * @event: event data + * @len: buffer length + * + * Return: 0 for success or error + */ +int wma_pdev_resume_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + + wma_nofl_info("Received PDEV resume event"); + + ucfg_pmo_psoc_wakeup_host_event_received(wma->psoc); + + return 0; +} + +/** + * wma_del_ts_req() - send DELTS request to fw + * @wma: wma handle + * @msg: delts params + * + * Return: none + */ +void wma_del_ts_req(tp_wma_handle wma, struct del_ts_params *msg) +{ + if (!wma_is_vdev_valid(msg->sessionId)) { + wma_err("vdev id:%d is not active ", msg->sessionId); + qdf_mem_free(msg); + return; + } + if (wmi_unified_del_ts_cmd(wma->wmi_handle, + msg->sessionId, + TID_TO_WME_AC(msg->userPrio))) { + wma_alert("Failed to send vdev DELTS command"); + } + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (msg->setRICparams == true) + wma_set_ric_req(wma, msg, false); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + qdf_mem_free(msg); +} + +void wma_aggr_qos_req(tp_wma_handle wma, + struct aggr_add_ts_param *aggr_qos_rsp_msg) +{ + if (!wma_is_vdev_valid(aggr_qos_rsp_msg->vdev_id)) { + wma_err("vdev id:%d is not active ", + aggr_qos_rsp_msg->vdev_id); + return; + } + wmi_unified_aggr_qos_cmd(wma->wmi_handle, aggr_qos_rsp_msg); + /* send response to upper layers from here only. */ + wma_send_msg_high_priority(wma, WMA_AGGR_QOS_RSP, aggr_qos_rsp_msg, 0); +} + +#ifdef FEATURE_WLAN_ESE +/** + * wma_set_tsm_interval() - Set TSM interval + * @req: pointer to ADDTS request + * + * Return: QDF_STATUS_E_FAILURE or QDF_STATUS_SUCCESS + */ +static QDF_STATUS wma_set_tsm_interval(struct add_ts_param *req) +{ + /* + * msmt_interval is in unit called TU (1 TU = 1024 us) + * max value of msmt_interval cannot make resulting + * interval_milliseconds overflow 32 bit + * + */ + uint32_t interval_milliseconds; + + interval_milliseconds = (req->tsm_interval * 1024) / 1000; + + cdp_tx_set_compute_interval(cds_get_context(QDF_MODULE_ID_SOC), + WMI_PDEV_ID_SOC, + interval_milliseconds); + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS wma_set_tsm_interval(struct add_ts_param *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* FEATURE_WLAN_ESE */ + +/** + * wma_add_ts_req() - send ADDTS request to fw + * @wma: wma handle + * @msg: ADDTS params + * + * Return: none + */ +void wma_add_ts_req(tp_wma_handle wma, struct add_ts_param *msg) +{ + struct add_ts_param cmd = {0}; + + msg->status = QDF_STATUS_SUCCESS; + if (wma_set_tsm_interval(msg) == QDF_STATUS_SUCCESS) { + + cmd.vdev_id = msg->vdev_id; + cmd.tspec.tsinfo.traffic.userPrio = + TID_TO_WME_AC(msg->tspec.tsinfo.traffic.userPrio); + cmd.tspec.mediumTime = msg->tspec.mediumTime; + if (wmi_unified_add_ts_cmd(wma->wmi_handle, &cmd)) + msg->status = QDF_STATUS_E_FAILURE; + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + if (msg->set_ric_params) + wma_set_ric_req(wma, msg, true); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + + } + wma_send_msg_high_priority(wma, WMA_ADD_TS_RSP, msg, 0); +} + +#ifdef FEATURE_WLAN_ESE + +#define TSM_DELAY_HISTROGRAM_BINS 4 +/** + * wma_process_tsm_stats_req() - process tsm stats request + * @wma_handler - handle to wma + * @pTsmStatsMsg - TSM stats struct that needs to be populated and + * passed in message. + * + * A parallel function to WMA_ProcessTsmStatsReq for pronto. This + * function fetches stats from data path APIs and post + * WMA_TSM_STATS_RSP msg back to LIM. + * + * Return: QDF status + */ +QDF_STATUS wma_process_tsm_stats_req(tp_wma_handle wma_handler, + void *pTsmStatsMsg) +{ + uint8_t counter; + uint32_t queue_delay_microsec = 0; + uint32_t tx_delay_microsec = 0; + uint16_t packet_count = 0; + uint16_t packet_loss_count = 0; + tpAniTrafStrmMetrics pTsmMetric = NULL; + tpAniGetTsmStatsReq pStats = (tpAniGetTsmStatsReq) pTsmStatsMsg; + tpAniGetTsmStatsRsp pTsmRspParams = NULL; + int tid = pStats->tid; + /* + * The number of histrogram bin report by data path api are different + * than required by TSM, hence different (6) size array used + */ + uint16_t bin_values[QCA_TX_DELAY_HIST_REPORT_BINS] = { 0, }; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + /* get required values from data path APIs */ + cdp_tx_delay(soc, + WMI_PDEV_ID_SOC, + &queue_delay_microsec, + &tx_delay_microsec, tid); + cdp_tx_delay_hist(soc, + WMI_PDEV_ID_SOC, + bin_values, tid); + cdp_tx_packet_count(soc, + WMI_PDEV_ID_SOC, + &packet_count, + &packet_loss_count, tid); + + pTsmRspParams = qdf_mem_malloc(sizeof(*pTsmRspParams)); + if (!pTsmRspParams) { + QDF_ASSERT(0); + qdf_mem_free(pTsmStatsMsg); + return QDF_STATUS_E_NOMEM; + } + + qdf_copy_macaddr(&pTsmRspParams->bssid, &pStats->bssId); + pTsmRspParams->rc = QDF_STATUS_E_FAILURE; + pTsmRspParams->tsmStatsReq = pStats; + pTsmMetric = &pTsmRspParams->tsmMetrics; + /* populate pTsmMetric */ + pTsmMetric->UplinkPktQueueDly = queue_delay_microsec; + /* store only required number of bin values */ + for (counter = 0; counter < TSM_DELAY_HISTROGRAM_BINS; counter++) { + pTsmMetric->UplinkPktQueueDlyHist[counter] = + bin_values[counter]; + } + pTsmMetric->UplinkPktTxDly = tx_delay_microsec; + pTsmMetric->UplinkPktLoss = packet_loss_count; + pTsmMetric->UplinkPktCount = packet_count; + + /* + * No need to populate roaming delay and roaming count as they are + * being populated just before sending IAPP frame out + */ + /* post this message to LIM/PE */ + wma_send_msg(wma_handler, WMA_TSM_STATS_RSP, (void *)pTsmRspParams, 0); + return QDF_STATUS_SUCCESS; +} + +#endif /* FEATURE_WLAN_ESE */ + +/** + * wma_process_mcbc_set_filter_req() - process mcbc set filter request + * @wma_handle: wma handle + * @mcbc_param: mcbc params + * + * Return: QDF status + */ +QDF_STATUS wma_process_mcbc_set_filter_req(tp_wma_handle wma_handle, + tSirRcvFltMcAddrList *mcbc_param) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_add_periodic_tx_ptrn_ind() - add periodic tx pattern + * @handle: wma handle + * @pattern: tx pattern params + * + * Return: QDF status + */ +QDF_STATUS wma_process_add_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirAddPeriodicTxPtrn *pattern) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct periodic_tx_pattern *params_ptr; + uint8_t vdev_id; + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (wma_find_vdev_id_by_addr(wma_handle, + pattern->mac_address.bytes, + &vdev_id)) { + wma_err("Failed to find vdev id for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pattern->mac_address.bytes)); + return QDF_STATUS_E_INVAL; + } + + params_ptr = qdf_mem_malloc(sizeof(*params_ptr)); + if (!params_ptr) + return QDF_STATUS_E_NOMEM; + + params_ptr->ucPtrnId = pattern->ucPtrnId; + params_ptr->ucPtrnSize = pattern->ucPtrnSize; + params_ptr->usPtrnIntervalMs = pattern->usPtrnIntervalMs; + qdf_mem_copy(¶ms_ptr->mac_address, &pattern->mac_address, + sizeof(struct qdf_mac_addr)); + qdf_mem_copy(params_ptr->ucPattern, pattern->ucPattern, + params_ptr->ucPtrnSize); + + status = wmi_unified_process_add_periodic_tx_ptrn_cmd( + wmi_handle, params_ptr, vdev_id); + + qdf_mem_free(params_ptr); + return status; +} + +/** + * wma_process_del_periodic_tx_ptrn_ind - del periodic tx ptrn + * @handle: wma handle + * @pDelPeriodicTxPtrnParams: tx ptrn params + * + * Return: QDF status + */ +QDF_STATUS wma_process_del_periodic_tx_ptrn_ind(WMA_HANDLE handle, + tSirDelPeriodicTxPtrn * + pDelPeriodicTxPtrnParams) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (wma_find_vdev_id_by_addr( + wma_handle, + pDelPeriodicTxPtrnParams->mac_address.bytes, + &vdev_id)) { + wma_err("Failed to find vdev id for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(pDelPeriodicTxPtrnParams->mac_address.bytes)); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_process_del_periodic_tx_ptrn_cmd( + wmi_handle, vdev_id, + pDelPeriodicTxPtrnParams->ucPtrnId); +} + +#ifdef WLAN_FEATURE_STATS_EXT +#ifdef WLAN_FEATURE_11BE_MLO +/* + * wma_stats_ext_req_vdev_id_bitmap() -API to calculate connected links bitmap + * in case of MLO. + * psoc: psoc common object + * vdev_id: vdev_id for the stats ext request + * bitmap: connected links bitmap + * + * Return None + */ +static void wma_stats_ext_req_vdev_id_bitmap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint32_t *bitmap) +{ + struct wlan_objmgr_vdev *vdev, *link_vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint32_t i, connected_links_bitmap = 0; + uint8_t connected_vdev_id; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("vdev object is NULL for vdev_id %d", vdev_id); + return; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) + goto end; + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + link_vdev = mlo_dev_ctx->wlan_vdev_list[i]; + if (!link_vdev) + continue; + + connected_vdev_id = wlan_vdev_get_id(link_vdev); + if (wlan_cm_is_vdev_connected(link_vdev)) + connected_links_bitmap |= BIT(connected_vdev_id); + } + + wma_debug("mlo connected links bitmap[0x%x]", connected_links_bitmap); + *bitmap = connected_links_bitmap; + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); +} +#else +static void wma_stats_ext_req_vdev_id_bitmap(struct wlan_objmgr_psoc *psoc, + uint32_t vdev_id, uint32_t *bitmap) +{ + *bitmap = 0; +} +#endif + +QDF_STATUS wma_stats_ext_req(void *wma_ptr, tpStatsExtRequest preq) +{ + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + struct stats_ext_params *params; + size_t params_len; + QDF_STATUS status; + + if (!wma) { + wma_err("wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + params_len = sizeof(*params) + preq->request_data_len; + params = qdf_mem_malloc(params_len); + if (!params) + return QDF_STATUS_E_NOMEM; + + params->vdev_id = preq->vdev_id; + params->request_data_len = preq->request_data_len; + if (preq->request_data_len > 0) + qdf_mem_copy(params->request_data, preq->request_data, + params->request_data_len); + + wma_stats_ext_req_vdev_id_bitmap(wma->psoc, params->vdev_id, + ¶ms->vdev_id_bitmap); + + status = wmi_unified_stats_ext_req_cmd(wma->wmi_handle, params); + qdf_mem_free(params); + + return status; +} + +#endif /* WLAN_FEATURE_STATS_EXT */ + +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT +/** + * wma_send_status_of_ext_wow() - send ext wow status to SME + * @wma: wma handle + * @status: status + * + * Return: none + */ +static void wma_send_status_of_ext_wow(tp_wma_handle wma, bool status) +{ + tSirReadyToExtWoWInd *ready_to_extwow; + QDF_STATUS vstatus; + struct scheduler_msg message = {0}; + uint8_t len; + + wma_debug("Posting ready to suspend indication to umac"); + + len = sizeof(tSirReadyToExtWoWInd); + ready_to_extwow = qdf_mem_malloc(len); + if (!ready_to_extwow) + return; + + ready_to_extwow->mesgType = eWNI_SME_READY_TO_EXTWOW_IND; + ready_to_extwow->mesgLen = len; + ready_to_extwow->status = status; + + message.type = eWNI_SME_READY_TO_EXTWOW_IND; + message.bodyptr = (void *)ready_to_extwow; + message.bodyval = 0; + + vstatus = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &message); + if (vstatus != QDF_STATUS_SUCCESS) + qdf_mem_free(ready_to_extwow); +} + +/** + * wma_enable_ext_wow() - enable ext wow in fw + * @wma: wma handle + * @params: ext wow params + * + * Return:0 for success or error code + */ +QDF_STATUS wma_enable_ext_wow(tp_wma_handle wma, tpSirExtWoWParams params) +{ + struct ext_wow_params wow_params = {0}; + QDF_STATUS status; + + if (!wma) { + wma_err("wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wow_params.vdev_id = params->vdev_id; + wow_params.type = (enum wmi_ext_wow_type) params->type; + wow_params.wakeup_pin_num = params->wakeup_pin_num; + + status = wmi_unified_enable_ext_wow_cmd(wma->wmi_handle, + &wow_params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma_send_status_of_ext_wow(wma, true); + return status; + +} + +/** + * wma_set_app_type1_params_in_fw() - set app type1 params in fw + * @wma: wma handle + * @appType1Params: app type1 params + * + * Return: QDF status + */ +int wma_set_app_type1_params_in_fw(tp_wma_handle wma, + tpSirAppType1Params appType1Params) +{ + int ret; + + ret = wmi_unified_app_type1_params_in_fw_cmd(wma->wmi_handle, + (struct app_type1_params *)appType1Params); + if (ret) { + wma_err("Failed to set APP TYPE1 PARAMS"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_app_type2_params_in_fw() - set app type2 params in fw + * @wma: wma handle + * @appType2Params: app type2 params + * + * Return: QDF status + */ +QDF_STATUS wma_set_app_type2_params_in_fw(tp_wma_handle wma, + tpSirAppType2Params appType2Params) +{ + struct app_type2_params params = {0}; + + if (!wma) { + wma_err("wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + params.vdev_id = appType2Params->vdev_id; + params.rc4_key_len = appType2Params->rc4_key_len; + qdf_mem_copy(params.rc4_key, appType2Params->rc4_key, 16); + params.ip_id = appType2Params->ip_id; + params.ip_device_ip = appType2Params->ip_device_ip; + params.ip_server_ip = appType2Params->ip_server_ip; + params.tcp_src_port = appType2Params->tcp_src_port; + params.tcp_dst_port = appType2Params->tcp_dst_port; + params.tcp_seq = appType2Params->tcp_seq; + params.tcp_ack_seq = appType2Params->tcp_ack_seq; + params.keepalive_init = appType2Params->keepalive_init; + params.keepalive_min = appType2Params->keepalive_min; + params.keepalive_max = appType2Params->keepalive_max; + params.keepalive_inc = appType2Params->keepalive_inc; + params.tcp_tx_timeout_val = appType2Params->tcp_tx_timeout_val; + params.tcp_rx_timeout_val = appType2Params->tcp_rx_timeout_val; + qdf_mem_copy(¶ms.gateway_mac, &appType2Params->gateway_mac, + sizeof(struct qdf_mac_addr)); + + return wmi_unified_set_app_type2_params_in_fw_cmd(wma->wmi_handle, + ¶ms); +} +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN +/** + * wma_auto_shutdown_event_handler() - process auto shutdown timer trigger + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_auto_shutdown_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + wmi_host_auto_shutdown_event_fixed_param *wmi_auto_sh_evt; + WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *param_buf = + (WMI_HOST_AUTO_SHUTDOWN_EVENTID_param_tlvs *) + event; + + if (!param_buf || !param_buf->fixed_param) { + wma_err("Invalid Auto shutdown timer evt"); + return -EINVAL; + } + + wmi_auto_sh_evt = param_buf->fixed_param; + + if (wmi_auto_sh_evt->shutdown_reason + != WMI_HOST_AUTO_SHUTDOWN_REASON_TIMER_EXPIRY) { + wma_err("Invalid Auto shutdown timer evt"); + return -EINVAL; + } + + wma_debug("Auto Shutdown Evt: %d", wmi_auto_sh_evt->shutdown_reason); + return wma_wake_reason_auto_shutdown(); +} + +QDF_STATUS +wma_set_auto_shutdown_timer_req(tp_wma_handle wma_handle, + struct auto_shutdown_cmd *auto_sh_cmd) +{ + if (!auto_sh_cmd) { + wma_err("Invalid Autoshutdown cfg cmd"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_set_auto_shutdown_timer_cmd(wma_handle->wmi_handle, + auto_sh_cmd->timer_val); +} +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + +#ifdef DHCP_SERVER_OFFLOAD +QDF_STATUS +wma_process_dhcpserver_offload(tp_wma_handle wma_handle, + struct dhcp_offload_info_params *params) +{ + QDF_STATUS status; + wmi_unified_t wmi_handle; + + if (!wma_handle) { + wma_err("wma handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wmi_handle = wma_handle->wmi_handle; + status = wmi_unified_process_dhcpserver_offload_cmd(wmi_handle, + params); + wma_debug("Set dhcp server offload to vdev %d status %d", + params->vdev_id, status); + + return status; +} +#endif /* DHCP_SERVER_OFFLOAD */ + +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING +/** + * wma_set_led_flashing() - set led flashing in fw + * @wma_handle: wma handle + * @flashing: flashing request + * + * Return: QDF status + */ +QDF_STATUS wma_set_led_flashing(tp_wma_handle wma_handle, + struct flashing_req_params *flashing) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!flashing) { + wma_err("invalid parameter: flashing"); + return QDF_STATUS_E_INVAL; + } + status = wmi_unified_set_led_flashing_cmd(wmi_handle, flashing); + return status; +} +#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */ + +int wma_sar_rsp_evt_handler(ol_scn_t handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma_handle; + wmi_unified_t wmi_handle; + QDF_STATUS status; + + wma_debug("handle:%pK event:%pK len:%u", handle, event, len); + + wma_handle = handle; + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + status = wmi_unified_extract_sar2_result_event(wmi_handle, + event, len); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Event extract failure: %d", status); + return -EINVAL; + } + + return 0; +} + +#ifdef FEATURE_WLAN_CH_AVOID +/** + * wma_process_ch_avoid_update_req() - handles channel avoid update request + * @wma_handle: wma handle + * @ch_avoid_update_req: channel avoid update params + * + * Return: QDF status + */ +QDF_STATUS wma_process_ch_avoid_update_req(tp_wma_handle wma_handle, + tSirChAvoidUpdateReq * + ch_avoid_update_req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_FAILURE; + + if (!ch_avoid_update_req) { + wma_err("ch_avoid_update_req is NULL"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("WMA --> WMI_CHAN_AVOID_UPDATE"); + + status = wmi_unified_process_ch_avoid_update_cmd(wmi_handle); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma_debug("WMA --> WMI_CHAN_AVOID_UPDATE sent through WMI"); + return status; +} +#endif + +void wma_send_regdomain_info_to_fw(uint32_t reg_dmn, uint16_t regdmn2G, + uint16_t regdmn5G, uint8_t ctl2G, + uint8_t ctl5G) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int32_t cck_mask_val = 0; + struct pdev_params pdev_param = {0}; + QDF_STATUS ret = QDF_STATUS_SUCCESS; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + wma_debug("reg_dmn: %d regdmn2g: %d regdmn5g :%d ctl2g: %d ctl5g: %d", + reg_dmn, regdmn2G, regdmn5G, ctl2G, ctl5G); + + if (!wma) + return; + + status = wmi_unified_send_regdomain_info_to_fw_cmd(wma->wmi_handle, + reg_dmn, regdmn2G, regdmn5G, ctl2G, ctl5G); + if (status == QDF_STATUS_E_NOMEM) + return; + + if ((((reg_dmn & ~CTRY_FLAG) == CTRY_JAPAN15) || + ((reg_dmn & ~CTRY_FLAG) == CTRY_KOREA_ROC)) && + (true == wma->tx_chain_mask_cck)) + cck_mask_val = 1; + + cck_mask_val |= (wma->self_gen_frm_pwr << 16); + pdev_param.param_id = wmi_pdev_param_tx_chain_mask_cck; + pdev_param.param_value = cck_mask_val; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + WMA_WILDCARD_PDEV_ID); + + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("failed to set PDEV tx_chain_mask_cck %d", ret); +} + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_tdls_event_handler() - handle TDLS event + * @handle: wma handle + * @event: event buffer + * @len: buffer length + * + * Return: 0 for success or error code + */ +int wma_tdls_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + /* TODO update with target rx ops */ + return 0; +} + +/** + * wma_update_tdls_peer_state() - update TDLS peer state + * @handle: wma handle + * @peer_state: TDLS peer state params + * + * Return: 0 for success or error code + */ +int wma_update_tdls_peer_state(WMA_HANDLE handle, + struct tdls_peer_update_state *peer_state) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint32_t i; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct tdls_peer_params *peer_cap; + int ret = 0; + uint32_t *ch_mhz = NULL; + size_t ch_mhz_len; + bool restore_last_peer = false; + QDF_STATUS qdf_status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) { + ret = -EINVAL; + goto end_tdls_peer_state; + } + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) { + ret = -EINVAL; + goto end_tdls_peer_state; + } + + if (!soc) { + ret = -EINVAL; + goto end_tdls_peer_state; + } + + if (wlan_cm_is_roam_sync_in_progress(wma_handle->psoc, + peer_state->vdev_id)) { + wma_err("roaming in progress, reject peer update cmd!"); + ret = -EPERM; + goto end_tdls_peer_state; + } + + + if (!wma_objmgr_peer_exist(wma_handle, + peer_state->peer_macaddr, NULL)) { + wma_err("peer:" QDF_MAC_ADDR_FMT "doesn't exist", + QDF_MAC_ADDR_REF(peer_state->peer_macaddr)); + ret = -EINVAL; + goto end_tdls_peer_state; + } + + peer_cap = &peer_state->peer_cap; + + /* peer capability info is valid only when peer state is connected */ + if (TDLS_PEER_STATE_CONNECTED != peer_state->peer_state) + qdf_mem_zero(peer_cap, sizeof(*peer_cap)); + + if (peer_cap->peer_chanlen) { + ch_mhz_len = sizeof(*ch_mhz) * peer_cap->peer_chanlen; + ch_mhz = qdf_mem_malloc(ch_mhz_len); + if (!ch_mhz) { + ret = -ENOMEM; + goto end_tdls_peer_state; + } + + for (i = 0; i < peer_cap->peer_chanlen; ++i) + ch_mhz[i] = peer_cap->peer_chan[i].ch_freq; + } + + cdp_peer_set_tdls_offchan_enabled(soc, peer_state->vdev_id, + peer_state->peer_macaddr, + !!peer_cap->peer_off_chan_support); + + if (wmi_unified_update_tdls_peer_state_cmd(wma_handle->wmi_handle, + peer_state, + ch_mhz)) { + wma_err("failed to send tdls peer update state command"); + ret = -EIO; + /* Fall through to delete TDLS peer for teardown */ + } + + /* in case of teardown, remove peer from fw */ + if (TDLS_PEER_STATE_TEARDOWN == peer_state->peer_state) { + restore_last_peer = cdp_peer_is_vdev_restore_last_peer( + soc, + peer_state->vdev_id, + peer_state->peer_macaddr); + + wma_debug("calling wma_remove_peer for peer " QDF_MAC_ADDR_FMT + " vdevId: %d", + QDF_MAC_ADDR_REF(peer_state->peer_macaddr), + peer_state->vdev_id); + qdf_status = wma_remove_peer(wma_handle, + peer_state->peer_macaddr, + peer_state->vdev_id, false); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("wma_remove_peer failed"); + ret = -EINVAL; + } + cdp_peer_update_last_real_peer(soc, WMI_PDEV_ID_SOC, + peer_state->vdev_id, + restore_last_peer); + } + + if (TDLS_PEER_STATE_CONNECTED == peer_state->peer_state) { + cdp_peer_state_update(soc, peer_state->peer_macaddr, + OL_TXRX_PEER_STATE_AUTH); + } + +end_tdls_peer_state: + if (ch_mhz) + qdf_mem_free(ch_mhz); + if (peer_state) + qdf_mem_free(peer_state); + return ret; +} +#endif /* FEATURE_WLAN_TDLS */ + +/* + * wma_process_cfg_action_frm_tb_ppdu() - action frame TB PPDU cfg to firmware + * @wma: Pointer to WMA handle + * @cfg_info: Pointer for cfg info + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS wma_process_cfg_action_frm_tb_ppdu(tp_wma_handle wma, + struct cfg_action_frm_tb_ppdu *cfg_info) +{ + struct cfg_action_frm_tb_ppdu_param cmd = {0}; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_FAILURE; + + cmd.frm_len = cfg_info->frm_len; + cmd.cfg = cfg_info->cfg; + cmd.data = cfg_info->data; + + wma_debug("cfg: %d, frm_len: %d", cfg_info->cfg, cfg_info->frm_len); + + return wmi_unified_cfg_action_frm_tb_ppdu_cmd(wma->wmi_handle, &cmd); +} + + +/* + * wma_process_set_ie_info() - Function to send IE info to firmware + * @wma: Pointer to WMA handle + * @ie_data: Pointer for ie data + * + * This function sends IE information to firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +QDF_STATUS wma_process_set_ie_info(tp_wma_handle wma, + struct vdev_ie_info *ie_info) +{ + struct wma_txrx_node *interface; + struct vdev_ie_info_param cmd = {0}; + + if (!ie_info || !wma) { + wma_err("input pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + /* Validate the input */ + if (ie_info->length <= 0) { + wma_err("Invalid IE length"); + return QDF_STATUS_E_INVAL; + } + + if (!wma_is_vdev_valid(ie_info->vdev_id)) { + wma_err("vdev_id: %d is not active", ie_info->vdev_id); + return QDF_STATUS_E_INVAL; + } + + interface = &wma->interfaces[ie_info->vdev_id]; + cmd.vdev_id = ie_info->vdev_id; + cmd.ie_id = ie_info->ie_id; + cmd.length = ie_info->length; + cmd.band = ie_info->band; + cmd.data = ie_info->data; + cmd.ie_source = WMA_SET_VDEV_IE_SOURCE_HOST; + + wma_debug("vdev id: %d, ie_id: %d, band: %d, len: %d", + ie_info->vdev_id, ie_info->ie_id, ie_info->band, + ie_info->length); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + ie_info->data, ie_info->length); + + return wmi_unified_process_set_ie_info_cmd(wma->wmi_handle, &cmd); +} + +#ifdef FEATURE_WLAN_APF +/** + * wma_get_apf_caps_event_handler() - Event handler for get apf capability + * @handle: WMA global handle + * @cmd_param_info: command event data + * @len: Length of @cmd_param_info + * + * Return: 0 on Success or Errno on failure + */ +int wma_get_apf_caps_event_handler(void *handle, u_int8_t *cmd_param_info, + u_int32_t len) +{ + WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *param_buf; + wmi_bpf_capability_info_evt_fixed_param *event; + struct sir_apf_get_offload *apf_get_offload; + struct mac_context *pmac = (struct mac_context *)cds_get_context( + QDF_MODULE_ID_PE); + + if (!pmac) + return -EINVAL; + + if (!pmac->sme.apf_get_offload_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + + param_buf = (WMI_BPF_CAPABILIY_INFO_EVENTID_param_tlvs *)cmd_param_info; + event = param_buf->fixed_param; + apf_get_offload = qdf_mem_malloc(sizeof(*apf_get_offload)); + if (!apf_get_offload) + return -ENOMEM; + + apf_get_offload->apf_version = event->bpf_version; + apf_get_offload->max_apf_filters = event->max_bpf_filters; + apf_get_offload->max_bytes_for_apf_inst = + event->max_bytes_for_bpf_inst; + wma_debug("APF capabilities version: %d max apf filter size: %d", + apf_get_offload->apf_version, + apf_get_offload->max_bytes_for_apf_inst); + + wma_debug("sending apf capabilities event to hdd"); + pmac->sme.apf_get_offload_cb(pmac->sme.apf_get_offload_context, + apf_get_offload); + qdf_mem_free(apf_get_offload); + return 0; +} + +QDF_STATUS wma_get_apf_capabilities(tp_wma_handle wma) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_bpf_get_capability_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len; + u_int8_t *buf_ptr; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_apf_offload)) { + wma_err("APF cababilities feature bit not enabled"); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_bpf_get_capability_cmd_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bpf_get_capability_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_bpf_get_capability_cmd_fixed_param)); + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_BPF_GET_CAPABILITY_CMDID)) { + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + return status; +} + +QDF_STATUS wma_set_apf_instructions(tp_wma_handle wma, + struct sir_apf_set_offload *apf_set_offload) +{ + wmi_bpf_set_vdev_instructions_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = 0, len_aligned = 0; + u_int8_t *buf_ptr; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, + wmi_service_apf_offload)) { + wma_err("APF offload feature Disabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + if (!apf_set_offload) { + wma_err("Invalid APF instruction request"); + return QDF_STATUS_E_INVAL; + } + + if (apf_set_offload->session_id >= wma->max_bssid) { + wma_err("Invalid vdev_id: %d", apf_set_offload->session_id); + return QDF_STATUS_E_INVAL; + } + + if (!wma_is_vdev_up(apf_set_offload->session_id)) { + wma_err("vdev %d is not up skipping APF offload", + apf_set_offload->session_id); + return QDF_STATUS_E_INVAL; + } + + if (apf_set_offload->total_length) { + len_aligned = roundup(apf_set_offload->current_length, + sizeof(A_UINT32)); + len = len_aligned + WMI_TLV_HDR_SIZE; + } + + len += sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *) wmi_buf_data(wmi_buf); + cmd = (wmi_bpf_set_vdev_instructions_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_bpf_set_vdev_instructions_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_bpf_set_vdev_instructions_cmd_fixed_param)); + cmd->vdev_id = apf_set_offload->session_id; + cmd->filter_id = apf_set_offload->filter_id; + cmd->total_length = apf_set_offload->total_length; + cmd->current_offset = apf_set_offload->current_offset; + cmd->current_length = apf_set_offload->current_length; + + if (apf_set_offload->total_length) { + buf_ptr += + sizeof(wmi_bpf_set_vdev_instructions_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, len_aligned); + buf_ptr += WMI_TLV_HDR_SIZE; + qdf_mem_copy(buf_ptr, apf_set_offload->program, + apf_set_offload->current_length); + } + + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_BPF_SET_VDEV_INSTRUCTIONS_CMDID)) { + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + wma_debug("APF offload enabled in fw"); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_send_apf_enable_cmd(WMA_HANDLE handle, uint8_t vdev_id, + bool apf_enable) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (!wma_is_vdev_valid(vdev_id)) + return QDF_STATUS_E_INVAL; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + wma_err("APF cababilities feature bit not enabled"); + return QDF_STATUS_E_FAILURE; + } + + status = wmi_unified_send_apf_enable_cmd(wmi_handle, vdev_id, + apf_enable); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send apf enable/disable cmd"); + return QDF_STATUS_E_FAILURE; + } + + if (apf_enable) + wma_debug("Sent APF Enable on vdevid: %d", vdev_id); + else + wma_debug("Sent APF Disable on vdevid: %d", vdev_id); + + return status; +} + +QDF_STATUS +wma_send_apf_write_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_write_memory_params + *write_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + wma_err("APF cababilities feature bit not enabled"); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_send_apf_write_work_memory_cmd(wmi_handle, + write_params)) { + wma_err("Failed to send APF write mem command"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Sent APF write mem on vdevid: %d", write_params->vdev_id); + return status; +} + +int wma_apf_read_work_memory_event_handler(void *handle, uint8_t *evt_buf, + uint32_t len) +{ + tp_wma_handle wma_handle; + wmi_unified_t wmi_handle; + struct wmi_apf_read_memory_resp_event_params evt_params = {0}; + QDF_STATUS status; + struct mac_context *pmac = cds_get_context(QDF_MODULE_ID_PE); + + wma_debug("handle:%pK event:%pK len:%u", handle, evt_buf, len); + + wma_handle = handle; + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + if (!pmac) + return -EINVAL; + + if (!pmac->sme.apf_read_mem_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + + status = wmi_extract_apf_read_memory_resp_event(wmi_handle, + evt_buf, &evt_params); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Event extract failure: %d", status); + return -EINVAL; + } + + pmac->sme.apf_read_mem_cb(pmac->hdd_handle, &evt_params); + + return 0; +} + +QDF_STATUS wma_send_apf_read_work_memory_cmd(WMA_HANDLE handle, + struct wmi_apf_read_memory_params + *read_params) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!WMI_SERVICE_IS_ENABLED(wma->wmi_service_bitmap, + WMI_SERVICE_BPF_OFFLOAD)) { + wma_err("APF cababilities feature bit not enabled"); + return QDF_STATUS_E_FAILURE; + } + + if (wmi_unified_send_apf_read_work_memory_cmd(wmi_handle, + read_params)) { + wma_err("Failed to send APF read memory command"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Sent APF read memory on vdevid: %d", read_params->vdev_id); + return status; +} +#endif /* FEATURE_WLAN_APF */ + +QDF_STATUS wma_set_tx_rx_aggr_size(uint8_t vdev_id, + uint32_t tx_size, + uint32_t rx_size, + wmi_vdev_custom_aggr_type_t aggr_type) +{ + tp_wma_handle wma_handle; + struct wma_txrx_node *intr; + wmi_vdev_set_custom_aggr_size_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + intr = wma_handle->interfaces; + if (!intr) { + wma_err("WMA interface is invalid!"); + return QDF_STATUS_E_INVAL; + } + + if (aggr_type == WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU) { + intr[vdev_id].config.tx_ampdu = tx_size; + intr[vdev_id].config.rx_ampdu = rx_size; + } else { + intr[vdev_id].config.tx_amsdu = tx_size; + intr[vdev_id].config.rx_amsdu = rx_size; + } + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + cmd = (wmi_vdev_set_custom_aggr_size_cmd_fixed_param *) buf_ptr; + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_set_custom_aggr_size_cmd_fixed_param)); + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_ampdu_tx_buf_size_256_support)) { + cmd->enable_bitmap |= (0x1 << 6); + } + + if ((tx_size > ADDBA_TXAGGR_SIZE_HELIUM) && + (tx_size != ADDBA_TXAGGR_SIZE_LITHIUM) && + (tx_size != ADDBA_TXAGGR_SIZE_512) && + (tx_size != ADDBA_TXAGGR_SIZE_BERYLLIUM)) { + wma_err("Invalid AMPDU Size"); + return QDF_STATUS_E_INVAL; + } + + cmd->vdev_id = vdev_id; + cmd->tx_aggr_size = tx_size; + cmd->rx_aggr_size = rx_size; + /* bit 2 (aggr_type): TX Aggregation Type (0=A-MPDU, 1=A-MSDU) */ + if (aggr_type == WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU) + cmd->enable_bitmap |= 0x04; + + wma_debug("tx aggr: %d rx aggr: %d vdev: %d enable_bitmap %d", + cmd->tx_aggr_size, cmd->rx_aggr_size, cmd->vdev_id, + cmd->enable_bitmap); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_set_tx_rx_aggr_size_per_ac(WMA_HANDLE handle, + uint8_t vdev_id, + struct wlan_mlme_qos *qos_aggr, + wmi_vdev_custom_aggr_type_t aggr_type) +{ + wmi_vdev_set_custom_aggr_size_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret; + int queue_num; + uint32_t tx_aggr_size[4]; + tp_wma_handle wma_handle = (tp_wma_handle)handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + tx_aggr_size[0] = qos_aggr->tx_aggregation_size_be; + tx_aggr_size[1] = qos_aggr->tx_aggregation_size_bk; + tx_aggr_size[2] = qos_aggr->tx_aggregation_size_vi; + tx_aggr_size[3] = qos_aggr->tx_aggregation_size_vo; + + for (queue_num = 0; queue_num < 4; queue_num++) { + if (tx_aggr_size[queue_num] == 0) + continue; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *)wmi_buf_data(buf); + cmd = (wmi_vdev_set_custom_aggr_size_cmd_fixed_param *)buf_ptr; + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_custom_aggr_size_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_set_custom_aggr_size_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->rx_aggr_size = qos_aggr->rx_aggregation_size; + cmd->tx_aggr_size = tx_aggr_size[queue_num]; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_ampdu_tx_buf_size_256_support)) { + cmd->enable_bitmap |= (0x1 << 6); + } + + if ((tx_aggr_size[queue_num] != ADDBA_TXAGGR_SIZE_LITHIUM) && + (tx_aggr_size[queue_num] > ADDBA_TXAGGR_SIZE_HELIUM)) { + wma_err("Invalid AMPDU Size"); + return QDF_STATUS_E_INVAL; + } + + /* bit 5: tx_ac_enable, if set, ac bitmap is valid. */ + cmd->enable_bitmap |= 0x20 | queue_num; + /* bit 2 (aggr_type): TX Aggregation Type (0=A-MPDU, 1=A-MSDU) */ + if (aggr_type == WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU) + cmd->enable_bitmap |= 0x04; + + wma_debug("queue_num: %d, tx aggr: %d rx aggr: %d vdev: %d, bitmap: %d", + queue_num, cmd->tx_aggr_size, + cmd->rx_aggr_size, cmd->vdev_id, + cmd->enable_bitmap); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wma_set_sw_retry_by_qos( + tp_wma_handle handle, uint8_t vdev_id, + wmi_vdev_custom_sw_retry_type_t retry_type, + wmi_traffic_ac ac_type, + uint32_t sw_retry) +{ + wmi_vdev_set_custom_sw_retry_th_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(handle->wmi_handle, len); + + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *)wmi_buf_data(buf); + cmd = (wmi_vdev_set_custom_sw_retry_th_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_vdev_set_custom_sw_retry_th_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_set_custom_sw_retry_th_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + cmd->ac_type = ac_type; + cmd->sw_retry_type = retry_type; + cmd->sw_retry_th = sw_retry; + + wma_debug("ac_type: %d re_type: %d threshold: %d vid: %d", + cmd->ac_type, cmd->sw_retry_type, + cmd->sw_retry_th, cmd->vdev_id); + + ret = wmi_unified_cmd_send(handle->wmi_handle, + buf, len, + WMI_VDEV_SET_CUSTOM_SW_RETRY_TH_CMDID); + + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_set_vdev_sw_retry_th(uint8_t vdev_id, uint8_t sw_retry_count, + wmi_vdev_custom_sw_retry_type_t retry_type) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + uint32_t queue_num; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + + for (queue_num = 0; queue_num < WMI_AC_MAX; queue_num++) { + if (sw_retry_count == 0) + continue; + + status = wma_set_sw_retry_by_qos(wma_handle, + vdev_id, + retry_type, + queue_num, + sw_retry_count); + + if (QDF_IS_STATUS_ERROR(status)) + return status; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_set_sw_retry_threshold_per_ac(WMA_HANDLE handle, + uint8_t vdev_id, + struct wlan_mlme_qos *qos_aggr) +{ + QDF_STATUS ret; + int retry_type, queue_num; + uint32_t tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_MAX][WMI_AC_MAX]; + uint32_t sw_retry; + tp_wma_handle wma_handle = (tp_wma_handle)handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_BE] = + qos_aggr->tx_aggr_sw_retry_threshold_be; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_BK] = + qos_aggr->tx_aggr_sw_retry_threshold_bk; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_VI] = + qos_aggr->tx_aggr_sw_retry_threshold_vi; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_AGGR][WMI_AC_VO] = + qos_aggr->tx_aggr_sw_retry_threshold_vo; + + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_BE] = + qos_aggr->tx_non_aggr_sw_retry_threshold_be; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_BK] = + qos_aggr->tx_non_aggr_sw_retry_threshold_bk; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_VI] = + qos_aggr->tx_non_aggr_sw_retry_threshold_vi; + tx_sw_retry[WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR][WMI_AC_VO] = + qos_aggr->tx_non_aggr_sw_retry_threshold_vo; + + retry_type = WMI_VDEV_CUSTOM_SW_RETRY_TYPE_NONAGGR; + while (retry_type < WMI_VDEV_CUSTOM_SW_RETRY_TYPE_MAX) { + for (queue_num = 0; queue_num < WMI_AC_MAX; queue_num++) { + if (tx_sw_retry[retry_type][queue_num] == 0) + continue; + + sw_retry = tx_sw_retry[retry_type][queue_num]; + ret = wma_set_sw_retry_by_qos(wma_handle, + vdev_id, + retry_type, + queue_num, + sw_retry); + + if (QDF_IS_STATUS_ERROR(ret)) + return ret; + } + retry_type++; + } + + return QDF_STATUS_SUCCESS; +} + +#define MAX_PDEV_SW_RETRY_PARAMS 2 +/* params being sent: + * 1.wmi_pdev_param_agg_sw_retry_th + * 2.wmi_pdev_param_non_agg_sw_retry_th + */ + +QDF_STATUS wma_set_sw_retry_threshold(struct wlan_mlme_qos *qos_aggr) +{ + uint32_t max, min, retry; + struct dev_set_param setparam[MAX_PDEV_SW_RETRY_PARAMS]; + QDF_STATUS ret; + uint8_t index = 0; + + retry = qos_aggr->tx_aggr_sw_retry_threshold; + max = cfg_max(CFG_TX_AGGR_SW_RETRY); + min = cfg_min(CFG_TX_AGGR_SW_RETRY); + retry = (retry > max) ? max : retry; + retry = (retry < min) ? min : retry; + + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_agg_sw_retry_th, + retry, index++, + MAX_PDEV_SW_RETRY_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to set wmi_pdev_param_agg_sw_retry_th"); + return ret; + } + retry = qos_aggr->tx_non_aggr_sw_retry_threshold; + max = cfg_max(CFG_TX_NON_AGGR_SW_RETRY); + min = cfg_min(CFG_TX_NON_AGGR_SW_RETRY); + retry = (retry > max) ? max : retry; + retry = (retry < min) ? min : retry; + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_non_agg_sw_retry_th, + retry, index++, + MAX_PDEV_SW_RETRY_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_debug("failed to set wmi_pdev_param_non_agg_sw_retry_th"); + return ret; + } + ret = wma_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + return ret; +} + +/** + * wma_process_fw_test_cmd() - send unit test command to fw. + * @handle: wma handle + * @wma_fwtest: fw test command + * + * This function send fw test command to fw. + * + * Return: none + */ +QDF_STATUS wma_process_fw_test_cmd(WMA_HANDLE handle, + struct set_fwtest_params *wma_fwtest) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (wmi_unified_fw_test_cmd(wmi_handle, + (struct set_fwtest_params *)wma_fwtest)) { + wma_err("Failed to issue fw test cmd"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_enable_disable_caevent_ind() - Issue WMI command to enable or + * disable ca event indication + * @wma: wma handler + * @val: boolean value true or false + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma, uint8_t val) +{ + WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint8_t *buf_ptr; + uint32_t len; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (uint8_t *) wmi_buf_data(wmi_buf); + cmd = (WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param *) buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + WMI_CHAN_AVOID_RPT_ALLOW_CMD_fixed_param)); + cmd->rpt_allow = val; + if (wmi_unified_cmd_send(wmi_handle, wmi_buf, len, + WMI_CHAN_AVOID_RPT_ALLOW_CMDID)) { + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static wma_sar_cb sar_callback; +static void *sar_context; + +static int wma_sar_event_handler(void *handle, uint8_t *evt_buf, uint32_t len) +{ + tp_wma_handle wma_handle; + wmi_unified_t wmi_handle; + struct sar_limit_event *event; + wma_sar_cb callback; + QDF_STATUS status; + + wma_info("handle:%pK event:%pK len:%u", handle, evt_buf, len); + + wma_handle = handle; + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + event = qdf_mem_malloc(sizeof(*event)); + if (!event) + return QDF_STATUS_E_NOMEM; + + status = wmi_unified_extract_sar_limit_event(wmi_handle, + evt_buf, event); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Event extract failure: %d", status); + qdf_mem_free(event); + return QDF_STATUS_E_INVAL; + } + + callback = sar_callback; + sar_callback = NULL; + if (callback) + callback(sar_context, event); + + qdf_mem_free(event); + + return 0; +} + +QDF_STATUS wma_sar_register_event_handlers(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_register_event_handler(wmi_handle, + wmi_sar_get_limits_event_id, + wma_sar_event_handler, + WMA_RX_WORK_CTX); +} + +QDF_STATUS wma_get_sar_limit(WMA_HANDLE handle, + wma_sar_cb callback, void *context) +{ + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + QDF_STATUS status; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + sar_callback = callback; + sar_context = context; + status = wmi_unified_get_sar_limit_cmd(wmi_handle); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("wmi_unified_get_sar_limit_cmd() error: %u", + status); + sar_callback = NULL; + } + + return status; +} + +QDF_STATUS wma_set_sar_limit(WMA_HANDLE handle, + struct sar_limit_cmd_params *sar_limit_params) +{ + int ret; + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!sar_limit_params) { + wma_err("set sar limit ptr NULL"); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_send_sar_limit_cmd(wmi_handle, + sar_limit_params); + + return ret; +} + +QDF_STATUS wma_send_coex_config_cmd(WMA_HANDLE wma_handle, + struct coex_config_params *coex_cfg_params) +{ + tp_wma_handle wma = (tp_wma_handle)wma_handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!coex_cfg_params) { + wma_err("coex cfg params ptr NULL"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_send_coex_config_cmd(wmi_handle, + coex_cfg_params); +} + +/** + * wma_get_arp_stats_handler() - handle arp stats data + * indicated by FW + * @handle: wma context + * @data: event buffer + * @data len: length of event buffer + * + * Return: 0 on success + */ +int wma_get_arp_stats_handler(void *handle, uint8_t *data, + uint32_t data_len) +{ + WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *param_buf; + wmi_vdev_get_arp_stats_event_fixed_param *data_event; + wmi_vdev_get_connectivity_check_stats *connect_stats_event; + uint8_t *buf_ptr; + struct rsp_stats rsp = {0}; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + if (!mac->sme.get_arp_stats_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + + if (!data) { + wma_err("invalid pointer"); + return -EINVAL; + } + param_buf = (WMI_VDEV_GET_ARP_STAT_EVENTID_param_tlvs *)data; + if (!param_buf) { + wma_err("Invalid get arp stats event"); + return -EINVAL; + } + data_event = param_buf->fixed_param; + if (!data_event) { + wma_err("Invalid get arp stats data event"); + return -EINVAL; + } + rsp.arp_req_enqueue = data_event->arp_req_enqueue; + rsp.vdev_id = data_event->vdev_id; + rsp.arp_req_tx_success = data_event->arp_req_tx_success; + rsp.arp_req_tx_failure = data_event->arp_req_tx_failure; + rsp.arp_rsp_recvd = data_event->arp_rsp_recvd; + rsp.out_of_order_arp_rsp_drop_cnt = + data_event->out_of_order_arp_rsp_drop_cnt; + rsp.dad_detected = data_event->dad_detected; + rsp.connect_status = data_event->connect_status; + rsp.ba_session_establishment_status = + data_event->ba_session_establishment_status; + + buf_ptr = (uint8_t *)data_event; + buf_ptr = buf_ptr + sizeof(wmi_vdev_get_arp_stats_event_fixed_param) + + WMI_TLV_HDR_SIZE; + connect_stats_event = (wmi_vdev_get_connectivity_check_stats *)buf_ptr; + + if (((connect_stats_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_vdev_get_connectivity_check_stats)) { + rsp.connect_stats_present = true; + rsp.tcp_ack_recvd = connect_stats_event->tcp_ack_recvd; + rsp.icmpv4_rsp_recvd = connect_stats_event->icmpv4_rsp_recvd; + wma_debug("tcp_ack_recvd %d icmpv4_rsp_recvd %d", + connect_stats_event->tcp_ack_recvd, + connect_stats_event->icmpv4_rsp_recvd); + } + + mac->sme.get_arp_stats_cb(mac->hdd_handle, &rsp, + mac->sme.get_arp_stats_context); + + return 0; +} + +/** + * wma_unified_power_debug_stats_event_handler() - WMA handler function to + * handle Power stats event from firmware + * @handle: Pointer to wma handle + * @cmd_param_info: Pointer to Power stats event TLV + * @len: Length of the cmd_param_info + * + * Return: 0 on success, error number otherwise + */ + #ifdef WLAN_POWER_DEBUG +int wma_unified_power_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, uint32_t len) +{ + WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *param_tlvs; + struct power_stats_response *power_stats_results; + wmi_pdev_chip_power_stats_event_fixed_param *param_buf; + uint32_t power_stats_len, stats_registers_len, *debug_registers; + + struct mac_context *mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + + param_tlvs = + (WMI_PDEV_CHIP_POWER_STATS_EVENTID_param_tlvs *) cmd_param_info; + + param_buf = (wmi_pdev_chip_power_stats_event_fixed_param *) + param_tlvs->fixed_param; + if (!mac) { + wma_debug("NULL mac ptr"); + return -EINVAL; + } + + if (!param_buf) { + wma_debug("NULL power stats event fixed param"); + return -EINVAL; + } + + if (param_buf->num_debug_register > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(wmi_pdev_chip_power_stats_event_fixed_param)) / + sizeof(uint32_t)) || + param_buf->num_debug_register > param_tlvs->num_debug_registers) { + wma_err("excess payload: LEN num_debug_register:%u", + param_buf->num_debug_register); + return -EINVAL; + } + debug_registers = param_tlvs->debug_registers; + stats_registers_len = + (sizeof(uint32_t) * param_buf->num_debug_register); + power_stats_len = stats_registers_len + sizeof(*power_stats_results); + power_stats_results = qdf_mem_malloc(power_stats_len); + if (!power_stats_results) + return -ENOMEM; + + wma_debug("Cumulative sleep time %d cumulative total on time %d deep sleep enter counter %d last deep sleep enter tstamp ts %d debug registers fmt %d num debug register %d", + param_buf->cumulative_sleep_time_ms, + param_buf->cumulative_total_on_time_ms, + param_buf->deep_sleep_enter_counter, + param_buf->last_deep_sleep_enter_tstamp_ms, + param_buf->debug_register_fmt, + param_buf->num_debug_register); + + power_stats_results->cumulative_sleep_time_ms + = param_buf->cumulative_sleep_time_ms; + power_stats_results->cumulative_total_on_time_ms + = param_buf->cumulative_total_on_time_ms; + power_stats_results->deep_sleep_enter_counter + = param_buf->deep_sleep_enter_counter; + power_stats_results->last_deep_sleep_enter_tstamp_ms + = param_buf->last_deep_sleep_enter_tstamp_ms; + power_stats_results->debug_register_fmt + = param_buf->debug_register_fmt; + power_stats_results->num_debug_register + = param_buf->num_debug_register; + + power_stats_results->debug_registers + = (uint32_t *)(power_stats_results + 1); + + qdf_mem_copy(power_stats_results->debug_registers, + debug_registers, stats_registers_len); + if (mac->sme.sme_power_debug_stats_callback) + mac->sme.sme_power_debug_stats_callback(mac, + power_stats_results); + + qdf_mem_free(power_stats_results); + return 0; +} +#endif + +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +int wma_unified_beacon_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_VDEV_BCN_RECEPTION_STATS_EVENTID_param_tlvs *param_tlvs; + struct bcn_reception_stats_rsp *bcn_reception_stats; + wmi_vdev_bcn_recv_stats_fixed_param *param_buf; + struct mac_context *mac = + (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + + param_tlvs = + (WMI_VDEV_BCN_RECEPTION_STATS_EVENTID_param_tlvs *)cmd_param_info; + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + param_buf = (wmi_vdev_bcn_recv_stats_fixed_param *) + param_tlvs->fixed_param; + if (!param_buf || !mac || !mac->sme.beacon_stats_resp_callback) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + if (!param_buf) { + wma_debug("NULL beacon stats event fixed param"); + return -EINVAL; + } + + bcn_reception_stats = qdf_mem_malloc(sizeof(*bcn_reception_stats)); + if (!bcn_reception_stats) + return -ENOMEM; + + bcn_reception_stats->total_bcn_cnt = param_buf->total_bcn_cnt; + bcn_reception_stats->total_bmiss_cnt = param_buf->total_bmiss_cnt; + bcn_reception_stats->vdev_id = param_buf->vdev_id; + + wma_debug("Total beacon count %d total beacon miss count %d vdev_id %d", + param_buf->total_bcn_cnt, + param_buf->total_bmiss_cnt, + param_buf->vdev_id); + + qdf_mem_copy(bcn_reception_stats->bmiss_bitmap, + param_buf->bmiss_bitmap, + MAX_BCNMISS_BITMAP * sizeof(uint32_t)); + + mac->sme.beacon_stats_resp_callback(bcn_reception_stats, + mac->sme.beacon_stats_context); + qdf_mem_free(bcn_reception_stats); + return 0; +} +#else +int wma_unified_beacon_debug_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + return 0; +} +#endif + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) +int +wma_vdev_bcn_latency_event_handler(void *handle, + uint8_t *event_info, + uint32_t len) +{ + WMI_VDEV_BCN_LATENCY_EVENTID_param_tlvs *param_buf = NULL; + wmi_vdev_bcn_latency_fixed_param *bcn_latency = NULL; + struct mac_context *mac = + (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + uint32_t latency_level; + + param_buf = (WMI_VDEV_BCN_LATENCY_EVENTID_param_tlvs *)event_info; + if (!param_buf) { + wma_err("Invalid bcn latency event"); + return -EINVAL; + } + + bcn_latency = param_buf->fixed_param; + if (!bcn_latency) { + wma_debug("beacon latency event fixed param is NULL"); + return -EINVAL; + } + + /* Map the latency value to the level which host expects + * 1 - normal, 2 - moderate, 3 - low, 4 - ultralow + */ + latency_level = bcn_latency->latency_level + 1; + if (latency_level < 1 || latency_level > 4) { + wma_debug("invalid beacon latency level value"); + return -EINVAL; + } + + /* Call the registered sme callback */ + mac->sme.beacon_latency_event_cb(latency_level); + + return 0; +} +#endif + +static void +wma_update_scan_channel_info_buf(wmi_unified_t wmi_handle, + wmi_chan_info_event_fixed_param *event, + struct scan_chan_info *buf, + wmi_cca_busy_subband_info *cca_info, + uint32_t num_tlvs) +{ + uint32_t i; + + if (cca_info && num_tlvs > 0) { + buf->subband_info.num_chan = 0; + for (i = 0; i < num_tlvs && i < MAX_WIDE_BAND_SCAN_CHAN; i++) { + buf->subband_info.cca_busy_subband_info[i] = + cca_info->rx_clear_count; + wma_debug("cca_info->rx_clear_count:%d", + cca_info->rx_clear_count); + buf->subband_info.num_chan++; + cca_info++; + } + + buf->subband_info.is_wide_band_scan = true; + buf->subband_info.vdev_id = event->vdev_id; + } +} + +static void +wma_update_scan_channel_subband_info(wmi_chan_info_event_fixed_param *event, + struct channel_status *channel_status, + wmi_cca_busy_subband_info *cca_info, + uint32_t num_tlvs) +{ + uint32_t i; + + if (cca_info && num_tlvs > 0) { + channel_status->subband_info.num_chan = 0; + for (i = 0; i < num_tlvs && i < MAX_WIDE_BAND_SCAN_CHAN; i++) { + channel_status->subband_info.cca_busy_subband_info[i] = + cca_info->rx_clear_count; + wma_debug("cca_info->rx_clear_count[%d]: %d", i, + cca_info->rx_clear_count); + channel_status->subband_info.num_chan++; + cca_info++; + } + + channel_status->subband_info.is_wide_band_scan = true; + channel_status->subband_info.vdev_id = event->vdev_id; + } +} + +int wma_chan_info_event_handler(void *handle, uint8_t *event_buf, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + WMI_CHAN_INFO_EVENTID_param_tlvs *param_buf; + wmi_chan_info_event_fixed_param *event; + struct scan_chan_info buf = {0}; + struct mac_context *mac = NULL; + struct channel_status *channel_status; + bool snr_monitor_enabled; + struct scheduler_msg sme_msg = {0}; + wmi_cca_busy_subband_info *cca_info = NULL; + uint32_t num_tlvs = 0; + bool is_cca_busy_info; + QDF_STATUS qdf_status; + + if (wma && wma->cds_context) + mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + param_buf = (WMI_CHAN_INFO_EVENTID_param_tlvs *)event_buf; + if (!param_buf) { + wma_err("Invalid chan info event buffer"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + wma_err("Invalid fixed param"); + return -EINVAL; + } + + /* Ignore the last channel event data whose command flag is set to 1. + * It’s basically an event with empty data only to indicate scan event + * completion. + */ + if (event->cmd_flags == WMI_CHAN_INFO_END_RESP) + return 0; + + cca_info = param_buf->cca_busy_subband_info; + num_tlvs = param_buf->num_cca_busy_subband_info; + is_cca_busy_info = wmi_service_enabled(wma->wmi_handle, + wmi_service_cca_busy_info_for_each_20mhz); + + snr_monitor_enabled = wlan_scan_is_snr_monitor_enabled(mac->psoc); + if (snr_monitor_enabled && mac->chan_info_cb) { + buf.tx_frame_count = event->tx_frame_cnt; + buf.clock_freq = event->mac_clk_mhz; + buf.cmd_flag = event->cmd_flags; + buf.freq = event->freq; + buf.noise_floor = event->noise_floor; + buf.cycle_count = event->cycle_count; + buf.rx_clear_count = event->rx_clear_count; + /* wide band scan case */ + if (is_cca_busy_info && num_tlvs) + wma_update_scan_channel_info_buf(wma->wmi_handle, + event, &buf, + cca_info, num_tlvs); + mac->chan_info_cb(&buf); + } + + channel_status = qdf_mem_malloc(sizeof(*channel_status)); + if (!channel_status) + return -ENOMEM; + + channel_status->channel_freq = event->freq; + channel_status->noise_floor = event->noise_floor; + + if (is_cca_busy_info && num_tlvs) + wma_update_scan_channel_subband_info(event, channel_status, + cca_info, num_tlvs); + else + channel_status->rx_clear_count = event->rx_clear_count; + + channel_status->cycle_count = event->cycle_count; + channel_status->chan_tx_pwr_range = event->chan_tx_pwr_range; + channel_status->chan_tx_pwr_throughput = event->chan_tx_pwr_tp; + channel_status->rx_frame_count = event->rx_frame_count; + channel_status->bss_rx_cycle_count = event->my_bss_rx_cycle_count; + channel_status->rx_11b_mode_data_duration = + event->rx_11b_mode_data_duration; + channel_status->tx_frame_count = event->tx_frame_cnt; + channel_status->mac_clk_mhz = event->mac_clk_mhz; + channel_status->channel_id = cds_freq_to_chan(event->freq); + channel_status->cmd_flags = event->cmd_flags; + + wma_debug("freq %d, nf %d, rcc %u, ch_rcc:%u, cc %u, tx_r %d, tx_t %d, chan_id:%d, flags:%d, cap: %d, num_tlvs:%d", + event->freq, event->noise_floor, + event->rx_clear_count, channel_status->rx_clear_count, + event->cycle_count, event->chan_tx_pwr_range, + event->chan_tx_pwr_tp, channel_status->channel_id, + channel_status->cmd_flags, is_cca_busy_info, num_tlvs); + + sme_msg.type = eWNI_SME_CHAN_INFO_EVENT; + sme_msg.bodyptr = channel_status; + sme_msg.bodyval = event->vdev_id; + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) + qdf_mem_free(channel_status); + + return 0; +} + +int wma_rx_aggr_failure_event_handler(void *handle, u_int8_t *event_buf, + u_int32_t len) +{ + WMI_REPORT_RX_AGGR_FAILURE_EVENTID_param_tlvs *param_buf; + struct sir_sme_rx_aggr_hole_ind *rx_aggr_hole_event; + wmi_rx_aggr_failure_event_fixed_param *rx_aggr_failure_info; + wmi_rx_aggr_failure_info *hole_info; + uint32_t i, alloc_len; + struct mac_context *mac; + + mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + if (!mac || !mac->sme.stats_ext2_cb) { + wma_debug("NULL mac ptr or HDD callback is null"); + return -EINVAL; + } + + param_buf = (WMI_REPORT_RX_AGGR_FAILURE_EVENTID_param_tlvs *)event_buf; + if (!param_buf) { + wma_err("Invalid stats ext event buf"); + return -EINVAL; + } + + rx_aggr_failure_info = param_buf->fixed_param; + hole_info = param_buf->failure_info; + + if (rx_aggr_failure_info->num_failure_info > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(*rx_aggr_hole_event)) / + sizeof(rx_aggr_hole_event->hole_info_array[0]))) { + wma_err("Excess data from WMI num_failure_info %d", + rx_aggr_failure_info->num_failure_info); + return -EINVAL; + } + + alloc_len = sizeof(*rx_aggr_hole_event) + + (rx_aggr_failure_info->num_failure_info)* + sizeof(rx_aggr_hole_event->hole_info_array[0]); + rx_aggr_hole_event = qdf_mem_malloc(alloc_len); + if (!rx_aggr_hole_event) + return -ENOMEM; + + rx_aggr_hole_event->hole_cnt = rx_aggr_failure_info->num_failure_info; + if (rx_aggr_hole_event->hole_cnt > param_buf->num_failure_info) { + wma_err("Invalid no of hole count: %d", + rx_aggr_hole_event->hole_cnt); + qdf_mem_free(rx_aggr_hole_event); + return -EINVAL; + } + wma_debug("aggr holes_sum: %d\n", + rx_aggr_failure_info->num_failure_info); + for (i = 0; i < rx_aggr_hole_event->hole_cnt; i++) { + rx_aggr_hole_event->hole_info_array[i] = + hole_info->end_seq - hole_info->start_seq + 1; + wma_nofl_debug("aggr_index: %d\tstart_seq: %d\tend_seq: %d\t" + "hole_info: %d mpdu lost", + i, hole_info->start_seq, hole_info->end_seq, + rx_aggr_hole_event->hole_info_array[i]); + hole_info++; + } + + mac->sme.stats_ext2_cb(mac->hdd_handle, rx_aggr_hole_event); + qdf_mem_free(rx_aggr_hole_event); + + return 0; +} + +int wma_wlan_bt_activity_evt_handler(void *handle, uint8_t *event, uint32_t len) +{ + wmi_coex_bt_activity_event_fixed_param *fixed_param; + WMI_WLAN_COEX_BT_ACTIVITY_EVENTID_param_tlvs *param_buf = + (WMI_WLAN_COEX_BT_ACTIVITY_EVENTID_param_tlvs *)event; + struct scheduler_msg sme_msg = {0}; + QDF_STATUS qdf_status; + + if (!param_buf) { + wma_err("Invalid BT activity event buffer"); + return -EINVAL; + } + + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + wma_err("Invalid BT activity event fixed param buffer"); + return -EINVAL; + } + + wma_info("Received BT activity event %u", + fixed_param->coex_profile_evt); + + sme_msg.type = eWNI_SME_BT_ACTIVITY_INFO_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = fixed_param->coex_profile_evt; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return -EINVAL; + + return 0; +} + +int wma_pdev_div_info_evt_handler(void *handle, u_int8_t *event_buf, + u_int32_t len) +{ + WMI_PDEV_DIV_RSSI_ANTID_EVENTID_param_tlvs *param_buf; + wmi_pdev_div_rssi_antid_event_fixed_param *event; + struct chain_rssi_result chain_rssi_result; + u_int32_t i; + u_int8_t macaddr[QDF_MAC_ADDR_SIZE]; + tp_wma_handle wma = (tp_wma_handle)handle; + + struct mac_context *pmac = (struct mac_context *)cds_get_context( + QDF_MODULE_ID_PE); + if (!pmac || !wma) { + wma_err("Invalid pmac or wma"); + return -EINVAL; + } + + if (!pmac->sme.get_chain_rssi_cb) { + wma_err("Invalid get_chain_rssi_cb"); + return -EINVAL; + } + param_buf = (WMI_PDEV_DIV_RSSI_ANTID_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + wma_err("Invalid rssi antid event buffer"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + wma_err("Invalid fixed param"); + return -EINVAL; + } + + if (event->num_chains_valid > CHAIN_MAX_NUM) { + wma_err("Invalid num of chains"); + return -EINVAL; + } + + qdf_mem_zero(&chain_rssi_result, sizeof(chain_rssi_result)); + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->macaddr, macaddr); + wma_debug("macaddr: " QDF_MAC_ADDR_FMT, QDF_MAC_ADDR_REF(macaddr)); + + wma_debug("num_chains_valid: %d", event->num_chains_valid); + chain_rssi_result.num_chains_valid = event->num_chains_valid; + + qdf_mem_copy(chain_rssi_result.chain_rssi, event->chain_rssi, + sizeof(event->chain_rssi)); + + qdf_mem_copy(chain_rssi_result.chain_evm, event->chain_evm, + sizeof(event->chain_evm)); + + qdf_mem_copy(chain_rssi_result.ant_id, event->ant_id, + sizeof(event->ant_id)); + + for (i = 0; i < chain_rssi_result.num_chains_valid; i++) { + wma_nofl_debug("chain_rssi: %d, chain_evm: %d,ant_id: %d", + chain_rssi_result.chain_rssi[i], + chain_rssi_result.chain_evm[i], + chain_rssi_result.ant_id[i]); + + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_hw_db2dbm_support)) { + if (chain_rssi_result.chain_rssi[i] != + WMA_INVALID_PER_CHAIN_SNR) + chain_rssi_result.chain_rssi[i] += + WMA_TGT_NOISE_FLOOR_DBM; + else + chain_rssi_result.chain_rssi[i] = + WMA_INVALID_PER_CHAIN_RSSI; + } + } + + pmac->sme.get_chain_rssi_cb(pmac->sme.get_chain_rssi_context, + &chain_rssi_result); + + return 0; +} + +int wma_vdev_obss_detection_info_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_obss_detect_info *obss_detection; + QDF_STATUS status; + + if (!event) { + wma_err("Invalid obss_detection_info event buffer"); + return -EINVAL; + } + + obss_detection = qdf_mem_malloc(sizeof(*obss_detection)); + if (!obss_detection) + return -ENOMEM; + + status = wmi_unified_extract_obss_detection_info(wma->wmi_handle, + event, obss_detection); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to extract obss info"); + qdf_mem_free(obss_detection); + return -EINVAL; + } + + if (!wma_is_vdev_valid(obss_detection->vdev_id)) { + wma_err("Invalid vdev id %d", obss_detection->vdev_id); + qdf_mem_free(obss_detection); + return -EINVAL; + } + + wma_send_msg(wma, WMA_OBSS_DETECTION_INFO, obss_detection, 0); + + return 0; +} + +static void wma_send_set_key_rsp(uint8_t vdev_id, bool pairwise, + uint8_t key_index) +{ + tSetStaKeyParams *key_info_uc; + tSetBssKeyParams *key_info_mc; + struct wlan_crypto_key *crypto_key; + struct wlan_objmgr_vdev *vdev; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct qdf_mac_addr bcast_mac = QDF_MAC_ADDR_BCAST_INIT; + + if (!wma) + return; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("VDEV object not found"); + return; + } + crypto_key = wlan_crypto_get_key(vdev, key_index); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + if (!crypto_key) { + wma_debug("crypto_key not found"); + return; + } + + if (pairwise) { + key_info_uc = qdf_mem_malloc(sizeof(*key_info_uc)); + if (!key_info_uc) + return; + key_info_uc->vdev_id = vdev_id; + key_info_uc->status = QDF_STATUS_SUCCESS; + key_info_uc->key_len = crypto_key->keylen; + qdf_mem_copy(&key_info_uc->macaddr, &crypto_key->macaddr, + QDF_MAC_ADDR_SIZE); + wma_send_msg_high_priority(wma, WMA_SET_STAKEY_RSP, + key_info_uc, 0); + wlan_release_peer_key_wakelock(wma->pdev, crypto_key->macaddr); + } else { + key_info_mc = qdf_mem_malloc(sizeof(*key_info_mc)); + if (!key_info_mc) + return; + key_info_mc->vdev_id = vdev_id; + key_info_mc->status = QDF_STATUS_SUCCESS; + key_info_mc->key_len = crypto_key->keylen; + qdf_mem_copy(&key_info_mc->macaddr, &bcast_mac, + QDF_MAC_ADDR_SIZE); + wma_send_msg_high_priority(wma, WMA_SET_BSSKEY_RSP, + key_info_mc, 0); + } +} + +void wma_set_peer_ucast_cipher(uint8_t *mac_addr, int32_t uc_cipher, + int32_t cipher_cap) +{ + struct wlan_objmgr_peer *peer; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return; + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + mac_addr, WLAN_LEGACY_WMA_ID); + if (!peer) { + wma_err("Peer of peer_mac "QDF_MAC_ADDR_FMT" not found", + QDF_MAC_ADDR_REF(mac_addr)); + return; + } + + wlan_crypto_set_peer_param(peer, WLAN_CRYPTO_PARAM_CIPHER_CAP, + cipher_cap); + wlan_crypto_set_peer_param(peer, WLAN_CRYPTO_PARAM_UCAST_CIPHER, + uc_cipher); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + wma_debug("Set unicast cipher %x and cap %x for "QDF_MAC_ADDR_FMT, + uc_cipher, cipher_cap, QDF_MAC_ADDR_REF(mac_addr)); +} + +void wma_update_set_key(uint8_t session_id, bool pairwise, + uint8_t key_index, + enum wlan_crypto_cipher_type cipher_type) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *iface; + + if (!wma) + return; + + iface = &wma->interfaces[session_id]; + if (!iface) { + wma_err("iface not found for session id %d", session_id); + return; + } + + if (iface) + iface->is_waiting_for_key = false; + + wma_send_set_key_rsp(session_id, pairwise, key_index); +} + +int wma_vdev_bss_color_collision_info_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + struct wmi_obss_color_collision_info *obss_color_info; + QDF_STATUS status; + + if (!event) { + wma_err("Invalid obss_color_collision event buffer"); + return -EINVAL; + } + + obss_color_info = qdf_mem_malloc(sizeof(*obss_color_info)); + if (!obss_color_info) + return -ENOMEM; + + status = wmi_unified_extract_obss_color_collision_info(wma->wmi_handle, + event, + obss_color_info); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to extract obss color info"); + qdf_mem_free(obss_color_info); + return -EINVAL; + } + + if (!wma_is_vdev_valid(obss_color_info->vdev_id)) { + wma_err("Invalid vdev id %d", obss_color_info->vdev_id); + qdf_mem_free(obss_color_info); + return -EINVAL; + } + + wma_send_msg(wma, WMA_OBSS_COLOR_COLLISION_INFO, obss_color_info, 0); + + return 0; +} + +#ifdef FEATURE_ANI_LEVEL_REQUEST +int wma_get_ani_level_evt_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + struct wmi_host_ani_level_event *ani = NULL; + uint32_t num_freqs = 0; + QDF_STATUS status; + struct mac_context *pmac; + int ret = 0; + + pmac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + if (!pmac || !wma) { + wma_err("Invalid pmac or wma"); + return -EINVAL; + } + + status = wmi_unified_extract_ani_level(wma->wmi_handle, event_buf, + &ani, &num_freqs); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to extract ani level"); + return -EINVAL; + } + + if (!pmac->ani_params.ani_level_cb) { + wma_err("Invalid ani_level_cb"); + ret = -EINVAL; + goto free; + } + + pmac->ani_params.ani_level_cb(ani, num_freqs, + pmac->ani_params.context); + +free: + qdf_mem_free(ani); + return ret; +} +#else +int wma_get_ani_level_evt_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + return 0; +} +#endif + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_api.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_api.c new file mode 100644 index 0000000000..91f5ce6b91 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_api.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017, 2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_fips_api.c + * + * WLAN Host Device Driver FIPS Certification Feature + */ + +#include "wma.h" +#include "wma_fips_api.h" +#include "wmi_unified_api.h" + +static wma_fips_cb fips_callback; +static void *fips_context; + +static int +wma_fips_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma_handle; + wmi_unified_t wmi_handle; + struct wmi_host_fips_event_param param; + wma_fips_cb callback; + QDF_STATUS status; + + wma_handle = handle; + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + status = wmi_extract_fips_event_data(wmi_handle, event, ¶m); + + wma_info("Received FIPS event, pdev:%u status:%u data_len:%u", + param.pdev_id, param.error_status, param.data_len); + + /* make sure extraction error is propagated to upper layers */ + if (QDF_IS_STATUS_ERROR(status)) + param.error_status = FIPS_ERROR_OPER_TIMEOUT; + + callback = fips_callback; + fips_callback = NULL; + if (callback) + callback(fips_context, ¶m); + + return 0; +} + +QDF_STATUS wma_fips_request(WMA_HANDLE handle, + struct fips_params *param, + wma_fips_cb callback, + void *context) +{ + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + QDF_STATUS status; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + fips_callback = callback; + fips_context = context; + status = wmi_unified_pdev_fips_cmd_send(wmi_handle, param); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("wmi_unified_pdev_fips_cmd_send() error: %u", + status); + fips_callback = NULL; + } + + return status; +} + +QDF_STATUS wma_fips_register_event_handlers(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = handle; + + return wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_pdev_fips_event_id, + wma_fips_event_handler, + WMA_RX_WORK_CTX); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_api.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_api.h new file mode 100644 index 0000000000..5ca0efb944 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_api.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_FIPS_API_H +#define __WMA_FIPS_API_H + +#include "wma_api.h" +#include "wmi_unified_api.h" +#include "wma_fips_public_structs.h" + +#ifdef WLAN_FEATURE_FIPS +/** + * wma_fips_request() - Perform a FIPS certification operation + * @handle: WMA handle of the object being certified + * @param: The FIPS certification parameters + * @callback: Callback function to invoke with the results + * @context: Opaque context to pass back to caller in the callback + * + * Return: QDF_STATUS_SUCCESS if the request is successfully sent + * to firmware for processing, otherwise an error status. + */ +QDF_STATUS wma_fips_request(WMA_HANDLE handle, + struct fips_params *param, + wma_fips_cb callback, + void *context); + +/** + * wma_fips_register_event_handlers() - Register FIPS event handlers + * @handle: WMA handle of the object being initialized + * + * This function registers all WMI event handlers required by the FIPS + * feature. + * + * Return: QDF_STATUS_SUCCESS upon success, otherwise an error + */ +QDF_STATUS wma_fips_register_event_handlers(WMA_HANDLE handle); + +#else /* WLAN_FEATURE_FIPS */ + +static inline +QDF_STATUS wma_fips_request(WMA_HANDLE handle, + const struct fips_params *param, + wma_fips_cb callback, + void *context) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS wma_fips_register_event_handlers(WMA_HANDLE wma_handle) +{ + return QDF_STATUS_SUCCESS; +} + +#endif /* WLAN_FEATURE_FIPS */ + +#endif /* __WMA_FIPS_API_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_public_structs.h new file mode 100644 index 0000000000..13c5999b3b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fips_public_structs.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_FIPS_PUBLIC_STRUCTS_H +#define __WMA_FIPS_PUBLIC_STRUCTS_H + +struct wmi_host_fips_event_param; + +/** + * typedef wma_fips_cb() - FIPS callback function + * @context: Opaque context provided by caller in FIPS request + * @param: FIPS event parameters + */ +typedef void (*wma_fips_cb)(void *context, + struct wmi_host_fips_event_param *param); + +#endif /* __WMA_FIPS_PUBLIC_STRUCTS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fw_state.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fw_state.c new file mode 100644 index 0000000000..aeef0ab147 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_fw_state.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_fw_state.c + * + * The implementation for getting firmware state + */ + +#include "wma_fw_state.h" +#include "wmi_unified_api.h" + +QDF_STATUS wma_get_fw_state(tp_wma_handle wma_handle) +{ + wmi_echo_cmd_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = sizeof(*cmd); + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_echo_cmd_fixed_param *)wmi_buf_data(wmi_buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_echo_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_echo_cmd_fixed_param)); + cmd->value = true; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_ECHO_CMDID)) { + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_echo_event_handler() - process fw state rsp + * @handle: wma interface + * @buf: wmi event buf pointer + * @len: length of event buffer + * + * This function will send eWNI_SME_FW_STATUS_IND to SME + * + * Return: 0 for success or error code + */ +static int wma_echo_event_handler(void *handle, uint8_t *buf, uint32_t len) +{ + struct scheduler_msg sme_msg = { + .type = eWNI_SME_FW_STATUS_IND, + }; + QDF_STATUS qdf_status; + + wma_debug("Received Echo reply from firmware!"); + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("Fail to post fw state reply msg"); + return -EINVAL; + } + + return 0; +} + +void wma_register_fw_state_events(wmi_unified_t wmi_handle) +{ + wmi_unified_register_event_handler(wmi_handle, + wmi_echo_event_id, + wma_echo_event_handler, + WMA_RX_SERIALIZER_CTX); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_he.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_he.c new file mode 100644 index 0000000000..9472faf17f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_he.c @@ -0,0 +1,1487 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_he.c + * + * WLAN Host Device Driver 802.11ax - High Efficiency Implementation + */ + +#include "wma_he.h" +#include "wmi_unified_api.h" +#include "cds_utils.h" +#include "wma_internal.h" + +/** + * wma_he_ppet_merge() - Merge PPET8 and PPET16 for a given ru and nss + * @host_ppet: pointer to dot11f array + * @byte_idx_p: pointer to byte index position where ppet should be added + * @used_p: pointer to used position + * @ppet: incoming PPET to be merged + * + * This function does the actual packing of dot11f structure. Split the + * incoming PPET(3 bits) to fit into an octet. If there are more than + * 3 bits available in a given byte_idx no splitting is required. + * + * Return: None + */ +static void wma_he_ppet_merge(uint8_t *host_ppet, int *byte_idx_p, int *used_p, + uint8_t ppet) +{ + int byte_idx = *byte_idx_p, used = *used_p; + int lshift, rshift; + + if (used <= (HE_BYTE_SIZE - HE_PPET_SIZE)) { + /* Enough space to fit the incoming PPET */ + lshift = used; + host_ppet[byte_idx] |= (ppet << lshift); + used += HE_PPET_SIZE; + if (used == HE_BYTE_SIZE) { + used = 0; + byte_idx++; + } + } else { + /* Need to split the PPET */ + lshift = used; + rshift = HE_BYTE_SIZE - used; + host_ppet[byte_idx] |= (ppet << lshift); + byte_idx++; + used = 0; + host_ppet[byte_idx] |= (ppet >> rshift); + used += HE_PPET_SIZE - rshift; + } + + *byte_idx_p = byte_idx; + *used_p = used; +} + +/** + * wma_he_populate_ppet() - Helper function for PPET conversion + * @ppet: pointer to fw array + * @nss: Number of NSS + * @ru: Number of RU + * @host_ppet: pointer to dot11f array + * @req_byte: Number of bytes in dot11f array + * + * This function retrieves PPET16/PPET8 pair for combination of NSS/RU + * and try to pack them in the OTA type dot11f structure by calling + * wma_he_ppet_merge. + * + * Return: None + */ +static void wma_he_populate_ppet(uint32_t *ppet, int nss, int ru, + uint8_t *host_ppet, int req_byte) +{ + int byte_idx = 0, used, i, j; + uint8_t ppet16, ppet8; + + wma_debug("nss: %d ru: %d req_byte: %d", nss, ru, req_byte); + /* NSS and RU_IDX are already populated */ + used = HE_PPET_NSS_RU_LEN; + + for (i = 0; i < nss; i++) { + for (j = 1; j <= ru; j++) { + ppet16 = WMI_GET_PPET16(ppet, j, i); + ppet8 = WMI_GET_PPET8(ppet, j, i); + wma_nofl_debug("ppet16 (nss:%d ru:%d): %04x", + i, j, ppet16); + wma_nofl_debug("ppet8 (nss:%d ru:%d): %04x", + i, j, ppet8); + wma_he_ppet_merge(host_ppet, &byte_idx, &used, ppet16); + wma_he_ppet_merge(host_ppet, &byte_idx, &used, ppet8); + } + } + +} + +/** + * wma_convert_he_ppet() - convert WMI ppet structure to dot11f structure + * @he_ppet: pointer to dot11f ppet structure + * @ppet: pointer to FW ppet structure + * + * PPET info coming from FW is stored as described in WMI definition. Convert + * that into equivalent dot11f structure. + * + * Return: None + */ +static void wma_convert_he_ppet(uint8_t *he_ppet, + struct wmi_host_ppe_threshold *ppet) +{ + int bits, req_byte; + struct ppet_hdr *hdr; + uint8_t ru_count, mask; + struct ppe_threshold *ppet_1; + + ppet_1 = NULL; + if (!ppet) { + wma_err("PPET is NULL"); + qdf_mem_zero(he_ppet, HE_MAX_PPET_SIZE); + return; + } + + hdr = (struct ppet_hdr *)he_ppet; + hdr->nss = ppet->numss_m1; + hdr->ru_idx_mask = ppet->ru_bit_mask; + mask = hdr->ru_idx_mask; + for (ru_count = 0; mask; mask >>= 1) + if (mask & 0x01) + ru_count++; + + /* + * there will be two PPET for each NSS/RU pair + * PPET8 and PPET16, hence HE_PPET_SIZE * 2 bits for PPET + */ + bits = HE_PPET_NSS_RU_LEN + ((hdr->nss + 1) * ru_count) * + (HE_PPET_SIZE * 2); + + req_byte = (bits / HE_BYTE_SIZE) + 1; + wma_he_populate_ppet(ppet->ppet16_ppet8_ru3_ru0, hdr->nss + 1, + ru_count, he_ppet, req_byte); +} + +/** + * wma_convert_he_cap() - convert HE capabilities into dot11f structure + * @he_cap: pointer to dot11f structure + * @mac_cap: Received HE MAC capability + * @phy_cap: Received HE PHY capability + * @supp_mcs: Max MCS supported (Tx/Rx) + * @tx_chain_mask: Tx chain mask + * @rx_chain_mask: Rx chain mask + * @mcs_12_13_support: Store the supported MCS 12/13 capability + * + * This function converts various HE capability received as part of extended + * service ready event into dot11f structure. GET macros are defined at WMI + * layer, use them to unpack the incoming FW capability. + * + * Return: None + */ +static void wma_convert_he_cap(tDot11fIEhe_cap *he_cap, uint32_t *mac_cap, + uint32_t *phy_cap, uint32_t supp_mcs, + uint32_t tx_chain_mask, uint32_t rx_chain_mask, + uint16_t *mcs_12_13_supp) +{ + uint8_t nss, chan_width; + uint16_t rx_mcs_le_80, tx_mcs_le_80, rx_mcs_160, tx_mcs_160; + + nss = QDF_MAX(wma_get_num_of_setbits_from_bitmask(tx_chain_mask), + wma_get_num_of_setbits_from_bitmask(rx_chain_mask)); + + he_cap->present = true; + /* HE MAC capabilities */ + he_cap->htc_he = WMI_HECAP_MAC_HECTRL_GET(mac_cap[0]); + he_cap->twt_request = WMI_HECAP_MAC_TWTREQ_GET(mac_cap[0]); + he_cap->twt_responder = WMI_HECAP_MAC_TWTRSP_GET(mac_cap[0]); + he_cap->fragmentation = WMI_HECAP_MAC_HEFRAG_GET(mac_cap[0]); + he_cap->max_num_frag_msdu_amsdu_exp = + WMI_HECAP_MAC_MAXFRAGMSDU_GET(mac_cap[0]); + he_cap->min_frag_size = WMI_HECAP_MAC_MINFRAGSZ_GET(mac_cap[0]); + he_cap->trigger_frm_mac_pad = WMI_HECAP_MAC_TRIGPADDUR_GET(mac_cap[0]); + he_cap->multi_tid_aggr_rx_supp = + WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap[0]); + he_cap->he_link_adaptation = WMI_HECAP_MAC_HELINK_ADPT_GET(mac_cap[0]); + he_cap->all_ack = WMI_HECAP_MAC_AACK_GET(mac_cap[0]); + he_cap->trigd_rsp_sched = WMI_HECAP_MAC_TRS_GET(mac_cap[0]); + he_cap->a_bsr = WMI_HECAP_MAC_BSR_GET(mac_cap[0]); + he_cap->broadcast_twt = WMI_HECAP_MAC_BCSTTWT_GET(mac_cap[0]); + he_cap->ba_32bit_bitmap = WMI_HECAP_MAC_32BITBA_GET(mac_cap[0]); + he_cap->mu_cascade = WMI_HECAP_MAC_MUCASCADE_GET(mac_cap[0]); + he_cap->ack_enabled_multitid = + WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap[0]); + he_cap->omi_a_ctrl = WMI_HECAP_MAC_OMI_GET(mac_cap[0]); + he_cap->ofdma_ra = WMI_HECAP_MAC_OFDMARA_GET(mac_cap[0]); + he_cap->max_ampdu_len_exp_ext = + WMI_HECAP_MAC_MAXAMPDULEN_EXP_GET(mac_cap[0]); + he_cap->amsdu_frag = WMI_HECAP_MAC_AMSDUFRAG_GET(mac_cap[0]); + he_cap->flex_twt_sched = WMI_HECAP_MAC_FLEXTWT_GET(mac_cap[0]); + he_cap->rx_ctrl_frame = WMI_HECAP_MAC_MBSS_GET(mac_cap[0]); + he_cap->bsrp_ampdu_aggr = WMI_HECAP_MAC_BSRPAMPDU_GET(mac_cap[1]); + he_cap->qtp = WMI_HECAP_MAC_QTP_GET(mac_cap[1]); + he_cap->a_bqr = WMI_HECAP_MAC_ABQR_GET(mac_cap[1]); + he_cap->spatial_reuse_param_rspder = + WMI_HECAP_MAC_SRPRESP_GET(mac_cap[1]); + he_cap->ndp_feedback_supp = WMI_HECAP_MAC_NDPFDBKRPT_GET(mac_cap[1]); + he_cap->ops_supp = WMI_HECAP_MAC_OPS_GET(mac_cap[1]); + he_cap->amsdu_in_ampdu = WMI_HECAP_MAC_AMSDUINAMPDU_GET(mac_cap[1]); + he_cap->multi_tid_aggr_tx_supp = WMI_HECAP_MAC_MTID_TX_GET(mac_cap[1]); + he_cap->he_sub_ch_sel_tx_supp = + WMI_HECAP_MAC_SUBCHANSELTX_GET(mac_cap[1]); + he_cap->ul_2x996_tone_ru_supp = WMI_HECAP_MAC_UL2X996RU_GET(mac_cap[1]); + he_cap->om_ctrl_ul_mu_data_dis_rx = + WMI_HECAP_MAC_OMCULMUDDIS_GET(mac_cap[1]); + he_cap->he_dynamic_smps = + WMI_HECAP_MAC_DYNSMPWRSAVE_GET(mac_cap[1]); + he_cap->punctured_sounding_supp = + WMI_HECAP_MAC_PUNCSOUNDING_GET(mac_cap[1]); + he_cap->ht_vht_trg_frm_rx_supp = + WMI_HECAP_MAC_HTVHTTRIGRX_GET(mac_cap[1]); + *mcs_12_13_supp = WMI_GET_BITS(mac_cap[1], 16, 16); + /* HE PHY capabilities */ + chan_width = WMI_HECAP_PHY_CBW_GET(phy_cap); + he_cap->chan_width_0 = HE_CH_WIDTH_GET_BIT(chan_width, 0); + he_cap->chan_width_1 = HE_CH_WIDTH_GET_BIT(chan_width, 1); + he_cap->chan_width_2 = HE_CH_WIDTH_GET_BIT(chan_width, 2); + he_cap->chan_width_3 = HE_CH_WIDTH_GET_BIT(chan_width, 3); + he_cap->chan_width_4 = HE_CH_WIDTH_GET_BIT(chan_width, 4); + he_cap->chan_width_5 = HE_CH_WIDTH_GET_BIT(chan_width, 5); + he_cap->chan_width_6 = HE_CH_WIDTH_GET_BIT(chan_width, 6); + he_cap->rx_pream_puncturing = WMI_HECAP_PHY_PREAMBLEPUNCRX_GET(phy_cap); + he_cap->device_class = WMI_HECAP_PHY_COD_GET(phy_cap); + he_cap->ldpc_coding = WMI_HECAP_PHY_LDPC_GET(phy_cap); + he_cap->he_1x_ltf_800_gi_ppdu = WMI_HECAP_PHY_LTFGIFORHE_GET(phy_cap); + he_cap->midamble_tx_rx_max_nsts = + WMI_HECAP_PHY_MIDAMBLETXRXMAXNSTS_GET(phy_cap); + he_cap->he_4x_ltf_3200_gi_ndp = WMI_HECAP_PHY_LTFGIFORNDP_GET(phy_cap); + he_cap->rx_stbc_lt_80mhz = WMI_HECAP_PHY_RXSTBC_GET(phy_cap); + he_cap->tb_ppdu_tx_stbc_lt_80mhz = WMI_HECAP_PHY_TXSTBC_GET(phy_cap); + he_cap->rx_stbc_gt_80mhz = WMI_HECAP_PHY_STBCRXGT80_GET(phy_cap); + he_cap->tb_ppdu_tx_stbc_gt_80mhz = + WMI_HECAP_PHY_STBCTXGT80_GET(phy_cap); + + he_cap->doppler = (WMI_HECAP_PHY_RXDOPPLER_GET(phy_cap) << 1) | + WMI_HECAP_PHY_TXDOPPLER(phy_cap); + he_cap->ul_mu = (WMI_HECAP_PHY_ULMUMIMOOFDMA_GET(phy_cap) << 1) | + WMI_HECAP_PHY_UL_MU_MIMO_GET(phy_cap); + he_cap->dcm_enc_tx = WMI_HECAP_PHY_DCMTX_GET(phy_cap); + he_cap->dcm_enc_rx = WMI_HECAP_PHY_DCMRX_GET(phy_cap); + he_cap->ul_he_mu = WMI_HECAP_PHY_ULHEMU_GET(phy_cap); + he_cap->su_beamformer = WMI_HECAP_PHY_SUBFMR_GET(phy_cap); + he_cap->su_beamformee = WMI_HECAP_PHY_SUBFME_GET(phy_cap); + he_cap->mu_beamformer = WMI_HECAP_PHY_MUBFMR_GET(phy_cap); + he_cap->bfee_sts_lt_80 = WMI_HECAP_PHY_BFMESTSLT80MHZ_GET(phy_cap); + he_cap->bfee_sts_gt_80 = WMI_HECAP_PHY_BFMESTSGT80MHZ_GET(phy_cap); + he_cap->num_sounding_lt_80 = WMI_HECAP_PHY_NUMSOUNDLT80MHZ_GET(phy_cap); + he_cap->num_sounding_gt_80 = WMI_HECAP_PHY_NUMSOUNDGT80MHZ_GET(phy_cap); + he_cap->su_feedback_tone16 = + WMI_HECAP_PHY_NG16SUFEEDBACKLT80_GET(phy_cap); + he_cap->mu_feedback_tone16 = + WMI_HECAP_PHY_NG16MUFEEDBACKGT80_GET(phy_cap); + he_cap->codebook_su = WMI_HECAP_PHY_CODBK42SU_GET(phy_cap); + he_cap->codebook_mu = WMI_HECAP_PHY_CODBK75MU_GET(phy_cap); + he_cap->beamforming_feedback = + WMI_HECAP_PHY_BFFEEDBACKTRIG_GET(phy_cap); + he_cap->he_er_su_ppdu = WMI_HECAP_PHY_HEERSU_GET(phy_cap); + he_cap->dl_mu_mimo_part_bw = + WMI_HECAP_PHY_DLMUMIMOPARTIALBW_GET(phy_cap); + he_cap->ppet_present = WMI_HECAP_PHY_PETHRESPRESENT_GET(phy_cap); + he_cap->srp = WMI_HECAP_PHY_SRPSPRESENT_GET(phy_cap); + he_cap->power_boost = WMI_HECAP_PHY_PWRBOOSTAR_GET(phy_cap); + he_cap->he_ltf_800_gi_4x = + WMI_HECAP_PHY_4XLTFAND800NSECSGI_GET(phy_cap); + he_cap->max_nc = WMI_HECAP_PHY_MAXNC_GET(phy_cap); + he_cap->tb_ppdu_tx_stbc_gt_80mhz = + WMI_HECAP_PHY_STBCTXGT80_GET(phy_cap); + he_cap->rx_stbc_gt_80mhz = WMI_HECAP_PHY_STBCRXGT80_GET(phy_cap); + he_cap->er_he_ltf_800_gi_4x = + WMI_HECAP_PHY_ERSU4X800NSECGI_GET(phy_cap); + he_cap->he_ppdu_20_in_40Mhz_2G = + WMI_HECAP_PHY_HEPPDU20IN40MHZ2G_GET(phy_cap); + he_cap->he_ppdu_20_in_160_80p80Mhz = + WMI_HECAP_PHY_HEPPDU20IN160OR80P80MHZ_GET(phy_cap); + he_cap->he_ppdu_80_in_160_80p80Mhz = + WMI_HECAP_PHY_HEPPDU80IN160OR80P80MHZ_GET(phy_cap); + he_cap->er_1x_he_ltf_gi = WMI_HECAP_PHY_ERSU1X800NSECGI_GET(phy_cap); + he_cap->midamble_tx_rx_1x_he_ltf = + WMI_HECAP_PHY_MIDAMBLETXRX2XAND1XHELTF_GET(phy_cap); + + he_cap->dcm_max_bw = WMI_HECAP_PHY_DCMMAXBW_GET(phy_cap); + he_cap->longer_than_16_he_sigb_ofdm_sym = + WMI_HECAP_PHY_LNG16SIGBSYMBSUPRT_GET(phy_cap); + he_cap->non_trig_cqi_feedback = + WMI_HECAP_PHY_NONTRIGCQIFEEDBK_GET(phy_cap); + he_cap->tx_1024_qam_lt_242_tone_ru = + WMI_HECAP_PHY_TX1024QAM242RUSUPRT_GET(phy_cap); + he_cap->rx_1024_qam_lt_242_tone_ru = + WMI_HECAP_PHY_RX1024QAM242RUSUPRT_GET(phy_cap); + he_cap->rx_full_bw_su_he_mu_compress_sigb = + WMI_HECAP_PHY_RXFULBWSUWCMPRSSIGB_GET(phy_cap); + he_cap->rx_full_bw_su_he_mu_non_cmpr_sigb = + WMI_HECAP_PHY_RXFULBWSUWNONCMPRSSIGB_GET(phy_cap); + + /* + * supp_mcs is split into 16 bits with lower indicating le_80 and + * upper indicating 160 and 80_80. + */ + wma_debug("supported_mcs: 0x%08x", supp_mcs); + rx_mcs_le_80 = supp_mcs & 0xFFFF; + tx_mcs_le_80 = supp_mcs & 0xFFFF; + rx_mcs_160 = (supp_mcs & 0xFFFF0000) >> 16; + tx_mcs_160 = (supp_mcs & 0xFFFF0000) >> 16; + /* if FW indicated it is using 1x1 disable upper NSS-MCS sets */ + if (nss == NSS_1x1_MODE) { + rx_mcs_le_80 |= HE_MCS_INV_MSK_4_NSS(1); + tx_mcs_le_80 |= HE_MCS_INV_MSK_4_NSS(1); + rx_mcs_160 |= HE_MCS_INV_MSK_4_NSS(1); + tx_mcs_160 |= HE_MCS_INV_MSK_4_NSS(1); + } + he_cap->rx_he_mcs_map_lt_80 = rx_mcs_le_80; + he_cap->tx_he_mcs_map_lt_80 = tx_mcs_le_80; + *((uint16_t *)he_cap->tx_he_mcs_map_160) = rx_mcs_160; + *((uint16_t *)he_cap->rx_he_mcs_map_160) = tx_mcs_160; + *((uint16_t *)he_cap->rx_he_mcs_map_80_80) = rx_mcs_160; + *((uint16_t *)he_cap->tx_he_mcs_map_80_80) = tx_mcs_160; +} + +/** + * wma_derive_ext_he_cap() - Derive HE caps based on given value + * @he_cap: pointer to given HE caps to be filled + * @new_he_cap: new HE cap info provided. + * + * This function takes the value provided in and combines it wht the incoming + * HE capability. After decoding, what ever value it gets, + * it takes the union(max) or intersection(min) with previously derived values. + * Currently, intersection(min) is taken for all the capabilities. + * + * Return: none + */ +static void wma_derive_ext_he_cap(tDot11fIEhe_cap *he_cap, + tDot11fIEhe_cap *new_cap, + bool is_5g_cap) +{ + uint16_t mcs_1, mcs_2; + + if (!he_cap->present) { + /* First time update, copy the capability as is */ + qdf_mem_copy(he_cap, new_cap, sizeof(*he_cap)); + he_cap->present = true; + return; + } + /* Take union(max) or intersection(min) of the capabilities */ + he_cap->htc_he = QDF_MIN(he_cap->htc_he, new_cap->htc_he); + he_cap->twt_request = QDF_MIN(he_cap->twt_request, + new_cap->twt_request); + he_cap->twt_responder = QDF_MIN(he_cap->twt_responder, + new_cap->twt_responder); + he_cap->fragmentation = QDF_MIN(he_cap->fragmentation, + new_cap->fragmentation); + he_cap->max_num_frag_msdu_amsdu_exp = QDF_MIN( + he_cap->max_num_frag_msdu_amsdu_exp, + new_cap->max_num_frag_msdu_amsdu_exp); + he_cap->min_frag_size = QDF_MIN(he_cap->min_frag_size, + new_cap->min_frag_size); + he_cap->trigger_frm_mac_pad = + QDF_MIN(he_cap->trigger_frm_mac_pad, + new_cap->trigger_frm_mac_pad); + he_cap->multi_tid_aggr_rx_supp = QDF_MIN(he_cap->multi_tid_aggr_rx_supp, + new_cap->multi_tid_aggr_rx_supp); + he_cap->he_link_adaptation = QDF_MIN(he_cap->he_link_adaptation, + new_cap->he_link_adaptation); + he_cap->all_ack = QDF_MIN(he_cap->all_ack, + new_cap->all_ack); + he_cap->trigd_rsp_sched = QDF_MIN(he_cap->trigd_rsp_sched, + new_cap->trigd_rsp_sched); + he_cap->a_bsr = QDF_MIN(he_cap->a_bsr, + new_cap->a_bsr); + he_cap->broadcast_twt = QDF_MIN(he_cap->broadcast_twt, + new_cap->broadcast_twt); + he_cap->ba_32bit_bitmap = QDF_MIN(he_cap->ba_32bit_bitmap, + new_cap->ba_32bit_bitmap); + he_cap->mu_cascade = QDF_MIN(he_cap->mu_cascade, + new_cap->mu_cascade); + he_cap->ack_enabled_multitid = + QDF_MIN(he_cap->ack_enabled_multitid, + new_cap->ack_enabled_multitid); + he_cap->omi_a_ctrl = QDF_MIN(he_cap->omi_a_ctrl, + new_cap->omi_a_ctrl); + he_cap->ofdma_ra = QDF_MIN(he_cap->ofdma_ra, + new_cap->ofdma_ra); + he_cap->max_ampdu_len_exp_ext = QDF_MIN(he_cap->max_ampdu_len_exp_ext, + new_cap->max_ampdu_len_exp_ext); + he_cap->amsdu_frag = QDF_MIN(he_cap->amsdu_frag, + new_cap->amsdu_frag); + he_cap->flex_twt_sched = QDF_MIN(he_cap->flex_twt_sched, + new_cap->flex_twt_sched); + he_cap->rx_ctrl_frame = QDF_MIN(he_cap->rx_ctrl_frame, + new_cap->rx_ctrl_frame); + he_cap->bsrp_ampdu_aggr = QDF_MIN(he_cap->bsrp_ampdu_aggr, + new_cap->bsrp_ampdu_aggr); + he_cap->qtp = QDF_MIN(he_cap->qtp, new_cap->qtp); + he_cap->a_bqr = QDF_MIN(he_cap->a_bqr, new_cap->a_bqr); + he_cap->spatial_reuse_param_rspder = QDF_MIN( + he_cap->spatial_reuse_param_rspder, + new_cap->spatial_reuse_param_rspder); + he_cap->ndp_feedback_supp = QDF_MIN(he_cap->ndp_feedback_supp, + new_cap->ndp_feedback_supp); + he_cap->ops_supp = QDF_MIN(he_cap->ops_supp, new_cap->ops_supp); + he_cap->amsdu_in_ampdu = QDF_MIN(he_cap->amsdu_in_ampdu, + new_cap->amsdu_in_ampdu); + + he_cap->chan_width_0 = he_cap->chan_width_0 | new_cap->chan_width_0; + he_cap->chan_width_1 = he_cap->chan_width_1 | new_cap->chan_width_1; + he_cap->chan_width_2 = he_cap->chan_width_2 | new_cap->chan_width_2; + he_cap->chan_width_3 = he_cap->chan_width_3 | new_cap->chan_width_3; + he_cap->chan_width_4 = he_cap->chan_width_4 | new_cap->chan_width_4; + he_cap->chan_width_5 = he_cap->chan_width_5 | new_cap->chan_width_5; + he_cap->chan_width_6 = he_cap->chan_width_6 | new_cap->chan_width_6; + + he_cap->device_class = QDF_MIN(he_cap->device_class, + new_cap->device_class); + he_cap->ldpc_coding = QDF_MIN(he_cap->ldpc_coding, + new_cap->ldpc_coding); + he_cap->he_1x_ltf_800_gi_ppdu = + QDF_MIN(he_cap->he_1x_ltf_800_gi_ppdu, + new_cap->he_1x_ltf_800_gi_ppdu); + he_cap->midamble_tx_rx_max_nsts = + QDF_MIN(he_cap->midamble_tx_rx_max_nsts, + new_cap->midamble_tx_rx_max_nsts); + he_cap->he_4x_ltf_3200_gi_ndp = + QDF_MIN(he_cap->he_4x_ltf_3200_gi_ndp, + new_cap->he_4x_ltf_3200_gi_ndp); + he_cap->tb_ppdu_tx_stbc_lt_80mhz = QDF_MIN( + he_cap->tb_ppdu_tx_stbc_lt_80mhz, + new_cap->tb_ppdu_tx_stbc_lt_80mhz); + he_cap->rx_stbc_lt_80mhz = QDF_MIN(he_cap->rx_stbc_lt_80mhz, + new_cap->rx_stbc_lt_80mhz); + he_cap->doppler = QDF_MIN(he_cap->doppler, + new_cap->doppler); + he_cap->ul_mu = QDF_MIN(he_cap->ul_mu, new_cap->ul_mu); + he_cap->dcm_enc_tx = QDF_MIN(he_cap->dcm_enc_tx, + new_cap->dcm_enc_tx); + he_cap->dcm_enc_rx = QDF_MIN(he_cap->dcm_enc_rx, + new_cap->dcm_enc_rx); + he_cap->ul_he_mu = QDF_MIN(he_cap->ul_he_mu, new_cap->ul_he_mu); + he_cap->su_beamformer = QDF_MIN(he_cap->su_beamformer, + new_cap->su_beamformer); + he_cap->su_beamformee = QDF_MIN(he_cap->su_beamformee, + new_cap->su_beamformee); + he_cap->mu_beamformer = QDF_MIN(he_cap->mu_beamformer, + new_cap->mu_beamformer); + he_cap->bfee_sts_lt_80 = QDF_MIN(he_cap->bfee_sts_lt_80, + new_cap->bfee_sts_lt_80); + he_cap->bfee_sts_gt_80 = QDF_MIN(he_cap->bfee_sts_gt_80, + new_cap->bfee_sts_gt_80); + he_cap->num_sounding_lt_80 = QDF_MIN(he_cap->num_sounding_lt_80, + new_cap->num_sounding_lt_80); + he_cap->num_sounding_gt_80 = QDF_MIN(he_cap->num_sounding_gt_80, + new_cap->num_sounding_gt_80); + he_cap->su_feedback_tone16 = QDF_MIN(he_cap->su_feedback_tone16, + new_cap->su_feedback_tone16); + he_cap->mu_feedback_tone16 = QDF_MIN(he_cap->mu_feedback_tone16, + new_cap->mu_feedback_tone16); + he_cap->codebook_su = QDF_MIN(he_cap->codebook_su, + new_cap->codebook_su); + he_cap->codebook_mu = QDF_MIN(he_cap->codebook_mu, + new_cap->codebook_mu); + he_cap->beamforming_feedback = + QDF_MIN(he_cap->beamforming_feedback, + new_cap->beamforming_feedback); + he_cap->he_er_su_ppdu = QDF_MIN(he_cap->he_er_su_ppdu, + new_cap->he_er_su_ppdu); + he_cap->dl_mu_mimo_part_bw = QDF_MIN(he_cap->dl_mu_mimo_part_bw, + new_cap->dl_mu_mimo_part_bw); + he_cap->ppet_present = QDF_MIN(he_cap->ppet_present, + new_cap->ppet_present); + he_cap->srp = QDF_MIN(he_cap->srp, new_cap->srp); + he_cap->power_boost = QDF_MIN(he_cap->power_boost, + new_cap->power_boost); + he_cap->he_ltf_800_gi_4x = QDF_MIN(he_cap->he_ltf_800_gi_4x, + new_cap->he_ltf_800_gi_4x); + he_cap->er_he_ltf_800_gi_4x = + QDF_MIN(he_cap->er_he_ltf_800_gi_4x, + new_cap->er_he_ltf_800_gi_4x); + he_cap->he_ppdu_20_in_40Mhz_2G = + QDF_MIN(he_cap->he_ppdu_20_in_40Mhz_2G, + new_cap->he_ppdu_20_in_40Mhz_2G); + he_cap->he_ppdu_20_in_160_80p80Mhz = + QDF_MIN(he_cap->he_ppdu_20_in_160_80p80Mhz, + new_cap->he_ppdu_20_in_160_80p80Mhz); + he_cap->he_ppdu_80_in_160_80p80Mhz = + QDF_MIN(he_cap->he_ppdu_80_in_160_80p80Mhz, + new_cap->he_ppdu_80_in_160_80p80Mhz); + he_cap->er_1x_he_ltf_gi = QDF_MIN(he_cap->er_1x_he_ltf_gi, + new_cap->er_1x_he_ltf_gi); + he_cap->midamble_tx_rx_1x_he_ltf = + QDF_MIN(he_cap->midamble_tx_rx_1x_he_ltf, + new_cap->midamble_tx_rx_1x_he_ltf); + he_cap->reserved2 = QDF_MIN(he_cap->reserved2, + new_cap->reserved2); + + /* take intersection for MCS map */ + mcs_1 = he_cap->rx_he_mcs_map_lt_80; + mcs_2 = new_cap->rx_he_mcs_map_lt_80; + he_cap->rx_he_mcs_map_lt_80 = HE_INTERSECT_MCS(mcs_1, mcs_2); + mcs_1 = he_cap->tx_he_mcs_map_lt_80; + mcs_2 = new_cap->tx_he_mcs_map_lt_80; + he_cap->tx_he_mcs_map_lt_80 = HE_INTERSECT_MCS(mcs_1, mcs_2); + if (is_5g_cap) { + he_cap->rx_pream_puncturing = + QDF_MIN(he_cap->rx_pream_puncturing, + new_cap->rx_pream_puncturing); + *((uint16_t *)he_cap->rx_he_mcs_map_160) = + *((uint16_t *)new_cap->rx_he_mcs_map_160); + *((uint16_t *)he_cap->tx_he_mcs_map_160) = + *((uint16_t *)new_cap->tx_he_mcs_map_160); + *((uint16_t *)he_cap->rx_he_mcs_map_80_80) = + *((uint16_t *)new_cap->rx_he_mcs_map_80_80); + *((uint16_t *)he_cap->tx_he_mcs_map_80_80) = + *((uint16_t *)new_cap->tx_he_mcs_map_80_80); + } +} + +void wma_print_he_cap(tDot11fIEhe_cap *he_cap) +{ + uint8_t chan_width; + struct ppet_hdr *hdr; + + if (!he_cap->present) + return; + + /* HE MAC capabilities */ + wma_debug("HE Cap: HTC-HE 0x%01x, TWT: Reqstor 0x%01x Respder 0x%01x, Frag 0x%02x, Max MSDUs 0x%03x, Min frag 0x%02x, Trigg MAC pad duration 0x%02x", + he_cap->htc_he, he_cap->twt_request, he_cap->twt_responder, + he_cap->fragmentation, he_cap->max_num_frag_msdu_amsdu_exp, + he_cap->min_frag_size, he_cap->trigger_frm_mac_pad); + + wma_nofl_debug(" Multi-TID aggr RX 0x%03x, Link adapt 0x%02x, All ACK 0x%01x, Trigg resp sched 0x%01x, A-Buff status rpt 0x%01x, BC TWT 0x%01x, 32bit BA 0x%01x", + he_cap->multi_tid_aggr_rx_supp, + he_cap->he_link_adaptation, he_cap->all_ack, + he_cap->trigd_rsp_sched, he_cap->a_bsr, + he_cap->broadcast_twt, he_cap->ba_32bit_bitmap); + + wma_nofl_debug(" MU Cascading 0x%01x, ACK enabled Multi-TID 0x%01x, OMI A-Cntrl 0x%01x, OFDMA RA 0x%01x, Max A-MPDU 0x%02x, A-MSDU Frag 0x%01x, Flex TWT sched 0x%01x", + he_cap->mu_cascade, he_cap->ack_enabled_multitid, + he_cap->omi_a_ctrl, he_cap->ofdma_ra, + he_cap->max_ampdu_len_exp_ext, he_cap->amsdu_frag, + he_cap->flex_twt_sched); + + wma_nofl_debug(" Rx Ctrl frame MBSS 0x%01x, BSRP A-MPDU Aggr 0x%01x, Quite Time Period 0x%01x, A-BQR 0x%01x, SR Respder 0x%01x, ndp FB 0x%01x, ops supp 0x%01x", + he_cap->rx_ctrl_frame, he_cap->bsrp_ampdu_aggr, + he_cap->qtp, he_cap->a_bqr, + he_cap->spatial_reuse_param_rspder, + he_cap->ndp_feedback_supp, he_cap->ops_supp); + + wma_nofl_debug(" Amsdu in ampdu 0x%01x, Multi-TID aggr 0x%03x, sub ch sel tx 0x%01x, UL 2x996tone RU 0x%01x, OM ctrl ULMU dis rx 0x%01x, DSMPS 0x%01x", + he_cap->amsdu_in_ampdu, he_cap->multi_tid_aggr_tx_supp, + he_cap->he_sub_ch_sel_tx_supp, + he_cap->ul_2x996_tone_ru_supp, + he_cap->om_ctrl_ul_mu_data_dis_rx, + he_cap->he_dynamic_smps); + + /* HE PHY capabilities */ + chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0, + he_cap->chan_width_1, he_cap->chan_width_2, + he_cap->chan_width_3, he_cap->chan_width_4, + he_cap->chan_width_5, he_cap->chan_width_6); + + wma_nofl_debug(" Punctured sounding 0x%01x, HTVHT Trigg frame Rx 0x%01x, Chan width 0x%07x, Preamble punct Rx 0x%04x, device class 0x%01x, LDPC 0x%01x", + he_cap->punctured_sounding_supp, + he_cap->ht_vht_trg_frm_rx_supp, chan_width, + he_cap->rx_pream_puncturing, he_cap->device_class, + he_cap->ldpc_coding); + + wma_nofl_debug(" LTF and GI for HE PPDUs 0x%02x, Midamble Tx Rx MAX NSTS 0x%02x, LTF and GI for NDP 0x%02x, TB PPDU STBC Tx support LE 80MHz 0x%01x", + he_cap->he_1x_ltf_800_gi_ppdu, + he_cap->midamble_tx_rx_max_nsts, + he_cap->he_4x_ltf_3200_gi_ndp, + he_cap->tb_ppdu_tx_stbc_lt_80mhz); + + wma_nofl_debug(" STBC Rx support LE 80Mhz 0x%01x, Doppler 0x%02x, UL MU: 0x%02x, DCM encoding: Tx 0x%03x Rx 0x%03x, HE MU PPDU payload 0x%01x", + he_cap->rx_stbc_lt_80mhz, he_cap->doppler, he_cap->ul_mu, + he_cap->dcm_enc_tx, he_cap->dcm_enc_rx, + he_cap->ul_he_mu); + + wma_nofl_debug(" SU: Bfer 0x%01x Bfee 0x%01x, MU Bfer 0x%01x, Bfee STS: LE 80Mhz 0x%03x GT 80Mhz 0x%03x, No. of sounding dim: LE 80Mhz 0x%03x GT 80Mhz 0x%03x", + he_cap->su_beamformer, he_cap->su_beamformee, + he_cap->mu_beamformer, he_cap->bfee_sts_lt_80, + he_cap->bfee_sts_gt_80, he_cap->num_sounding_lt_80, + he_cap->num_sounding_gt_80); + + wma_nofl_debug(" Ng=16 FB: SU 0x%01x MU 0x%01x, Codebook size: SU 0x%01x MU 0x%01x, Bfing trigger w/ Trigger 0x%01x, ER SU PPDU payload 0x%01x", + he_cap->su_feedback_tone16, he_cap->mu_feedback_tone16, + he_cap->codebook_su, he_cap->codebook_mu, + he_cap->beamforming_feedback, he_cap->he_er_su_ppdu); + + wma_nofl_debug(" DL MUMIMO on partial BW: 0x%01x, PPET 0x%01x, SRP 0x%01x, Power boost 0x%01x, 4x HE LTF 0x%01x, Max NC 0x%01x, TB PPDU stbc Tx GT 80Mhz 0x%01x", + he_cap->dl_mu_mimo_part_bw, he_cap->ppet_present, + he_cap->srp, he_cap->power_boost, + he_cap->he_ltf_800_gi_4x, he_cap->max_nc, + he_cap->tb_ppdu_tx_stbc_gt_80mhz); + + wma_nofl_debug(" STBC Rx GT 80Mhz 0x%01x, er ltf 800 gt 4x 0x%01x, ppdu 20: 40Mhz 2G 0x%01x 160_80p80Mhz 0x%01x, ppdu 80 160_80p80Mhz 0x%01x", + he_cap->rx_stbc_gt_80mhz, + he_cap->er_he_ltf_800_gi_4x, + he_cap->he_ppdu_20_in_40Mhz_2G, + he_cap->he_ppdu_20_in_160_80p80Mhz, + he_cap->he_ppdu_80_in_160_80p80Mhz); + + wma_nofl_debug(" ER 1X LTF GI 0x%01x, midamble tx/rx 1x LTF 0x%01x, DCM max BW 0x%02x, LT 16 sigb ofdm sym 0x%01x, non-trig cqi fb 0x%01x", + he_cap->er_1x_he_ltf_gi, + he_cap->midamble_tx_rx_1x_he_ltf, he_cap->dcm_max_bw, + he_cap->longer_than_16_he_sigb_ofdm_sym, + he_cap->non_trig_cqi_feedback); + + wma_nofl_debug(" 1024 QAM LT 242 tone ru: Tx 0x%01x RX 0x%01x, RX full BW SU MU SIGB: Compress 0x%01x non compress 0x%01x", + he_cap->tx_1024_qam_lt_242_tone_ru, + he_cap->rx_1024_qam_lt_242_tone_ru, + he_cap->rx_full_bw_su_he_mu_compress_sigb, + he_cap->rx_full_bw_su_he_mu_non_cmpr_sigb); + + /* HE PPET */ + hdr = (struct ppet_hdr *)&he_cap->ppet.ppe_threshold.ppe_th[0]; + wma_nofl_debug(" RX MCS: LE 80MHz 0x%x 160MHz 0x%x 80+80MHz 0x%x, TX MCS: LE 80MHz 0x%x 160MHz 0x%x 80+80MHz 0x%x, NSS %d, RU index 0x%04x, num ppet %d", + he_cap->rx_he_mcs_map_lt_80, + *((uint16_t *)he_cap->rx_he_mcs_map_160), + *((uint16_t *)he_cap->rx_he_mcs_map_80_80), + he_cap->tx_he_mcs_map_lt_80, + *((uint16_t *)he_cap->tx_he_mcs_map_160), + *((uint16_t *)he_cap->tx_he_mcs_map_80_80), + hdr->nss + 1, hdr->ru_idx_mask, + he_cap->ppet.ppe_threshold.num_ppe_th); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + he_cap->ppet.ppe_threshold.ppe_th, + he_cap->ppet.ppe_threshold.num_ppe_th); +} + +void wma_print_he_ppet(void *he_ppet) +{ + int numss, ru_count, ru_bit_mask, i, j; + struct wmi_host_ppe_threshold *ppet = he_ppet; + + if (!ppet) { + wma_err("PPET is NULL"); + return; + } + + numss = ppet->numss_m1 + 1; + ru_bit_mask = ppet->ru_bit_mask; + + wma_debug("HE PPET: ru_idx_mask: %04x", ru_bit_mask); + for (ru_count = 0; ru_bit_mask; ru_bit_mask >>= 1) + if (ru_bit_mask & 0x1) + ru_count++; + if (numss > WMI_HOST_MAX_NUM_SS) { + wma_err("invalid numss_m1 %d", ppet->numss_m1); + return; + } + if (ru_count > HE_PEPT_RU_IDX_LEN) { + wma_err("invalid ru_count 0x%08x", ppet->ru_bit_mask); + return; + } + + if (ru_count > 0) { + wma_debug("PPET has following RU INDEX,"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX0_MASK) + wma_nofl_debug("\tRU ALLOCATION INDEX 0"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX1_MASK) + wma_nofl_debug("\tRU ALLOCATION INDEX 1"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX2_MASK) + wma_nofl_debug("\tRU ALLOCATION INDEX 2"); + if (ppet->ru_bit_mask & HE_RU_ALLOC_INDX3_MASK) + wma_nofl_debug("\tRU ALLOCATION INDEX 3"); + } + + wma_debug("HE PPET: nss: %d, ru_count: %d", numss, ru_count); + + for (i = 0; i < numss; i++) { + wma_nofl_debug("PPET for NSS[%d]", i); + for (j = 1; j <= ru_count; j++) { + wma_nofl_debug("\tNSS[%d],RU[%d]: PPET16: %02x PPET8: %02x", + i, j, + WMI_GET_PPET16(ppet->ppet16_ppet8_ru3_ru0, j, i), + WMI_GET_PPET8(ppet->ppet16_ppet8_ru3_ru0, j, i)); + } + } + +} + +void wma_print_he_phy_cap(uint32_t *phy_cap) +{ + wma_debug("HE PHY Caps: Chan width 0x%07x, Preamble punct Rx 0x%04x, dev class 0x%01x, LDPC 0x%01x, LTF and GI: HE PPDUs 0x%02x NDP 0x%02x", + WMI_HECAP_PHY_CBW_GET(phy_cap), + WMI_HECAP_PHY_PREAMBLEPUNCRX_GET(phy_cap), + WMI_HECAP_PHY_COD_GET(phy_cap), + WMI_HECAP_PHY_LDPC_GET(phy_cap), + WMI_HECAP_PHY_LTFGIFORHE_GET(phy_cap), + WMI_HECAP_PHY_LTFGIFORNDP_GET(phy_cap)); + + wma_nofl_debug(" STBC Tx & Rx support LE 80Mhz 0x%02x, Doppler 0x%02x, UL MU: Full BW 0x%01x Partial BW 0x%01x, DCM encoding: TX 0x%03x RX 0x%03x", + (WMI_HECAP_PHY_RXSTBC_GET(phy_cap) << 1) | + WMI_HECAP_PHY_TXSTBC_GET(phy_cap), + (WMI_HECAP_PHY_RXDOPPLER_GET(phy_cap) << 1) | + WMI_HECAP_PHY_TXDOPPLER(phy_cap), + WMI_HECAP_PHY_UL_MU_MIMO_GET(phy_cap), + WMI_HECAP_PHY_ULMUMIMOOFDMA_GET(phy_cap), + WMI_HECAP_PHY_DCMTX_GET(phy_cap), + WMI_HECAP_PHY_DCMRX_GET(phy_cap)); + + wma_nofl_debug(" HE MU PPDU payload 0x%01x, SU: Bfer 0x%01x Bfee 0x%01x, MU Bfer 0x%01x, Bfee STS: LE 80Mhz 0x%03x GT 80Mhz 0x%03x", + WMI_HECAP_PHY_ULHEMU_GET(phy_cap), + WMI_HECAP_PHY_SUBFMR_GET(phy_cap), + WMI_HECAP_PHY_SUBFME_GET(phy_cap), + WMI_HECAP_PHY_MUBFMR_GET(phy_cap), + WMI_HECAP_PHY_BFMESTSLT80MHZ_GET(phy_cap), + WMI_HECAP_PHY_BFMESTSGT80MHZ_GET(phy_cap)); + + wma_nofl_debug(" NSTS: LE 80Mhz 0x%03x GT 80Mhz 0x%03x, No of Sounding dim: LE 80Mhz 0x%03x GT 80Mhz 0x%03x, Ng=16 FB: SU 0x%01x MU 0x%01x", + WMI_HECAP_PHY_NSTSLT80MHZ_GET(phy_cap), + WMI_HECAP_PHY_NSTSGT80MHZ_GET(phy_cap), + WMI_HECAP_PHY_NUMSOUNDLT80MHZ_GET(phy_cap), + WMI_HECAP_PHY_NUMSOUNDGT80MHZ_GET(phy_cap), + WMI_HECAP_PHY_NG16SUFEEDBACKLT80_GET(phy_cap), + WMI_HECAP_PHY_NG16MUFEEDBACKGT80_GET(phy_cap)); + + wma_nofl_debug(" Codebook size: SU 0x%01x MU 0x%01x, Beamforming trigger w/ Trigger 0x%01x, HE ER SU PPDU 0x%01x, DL MUMIMO on partial BW 0x%01x", + WMI_HECAP_PHY_CODBK42SU_GET(phy_cap), + WMI_HECAP_PHY_CODBK75MU_GET(phy_cap), + WMI_HECAP_PHY_BFFEEDBACKTRIG_GET(phy_cap), + WMI_HECAP_PHY_HEERSU_GET(phy_cap), + WMI_HECAP_PHY_DLMUMIMOPARTIALBW_GET(phy_cap)); + wma_nofl_debug(" PPET 0x%01x, SRP based SR 0x%01x, Power boost 0x%01x, 4x HE LTF 0x%01x, Max Nc 0x%03x, STBC Tx/Rx GT 80Mhz 0x%02x, ER 4x HE LTF 0x%01x", + WMI_HECAP_PHY_PETHRESPRESENT_GET(phy_cap), + WMI_HECAP_PHY_SRPSPRESENT_GET(phy_cap), + WMI_HECAP_PHY_PWRBOOSTAR_GET(phy_cap), + WMI_HECAP_PHY_4XLTFAND800NSECSGI_GET(phy_cap), + WMI_HECAP_PHY_MAXNC_GET(phy_cap), + (WMI_HECAP_PHY_STBCRXGT80_GET(phy_cap) << 1) | + WMI_HECAP_PHY_STBCTXGT80_GET(phy_cap), + WMI_HECAP_PHY_ERSU4X800NSECGI_GET(phy_cap)); +} + +void wma_print_he_mac_cap_w1(uint32_t mac_cap) +{ + wma_debug("HE MAC Caps: HTC-HE control 0x%01x, TWT Requestor 0x%01x, TWT Responder 0x%01x, Fragmentation 0x%02x, Max no.of MSDUs 0x%03x, Min. frag 0x%02x", + WMI_HECAP_MAC_HECTRL_GET(mac_cap), + WMI_HECAP_MAC_TWTREQ_GET(mac_cap), + WMI_HECAP_MAC_TWTRSP_GET(mac_cap), + WMI_HECAP_MAC_HEFRAG_GET(mac_cap), + WMI_HECAP_MAC_MAXFRAGMSDU_GET(mac_cap), + WMI_HECAP_MAC_MINFRAGSZ_GET(mac_cap)); + + wma_nofl_debug(" Trigger MAC pad dur 0x%02x, Multi-TID aggr Rx 0x%03x, Link adaptation 0x%02x, All ACK 0x%01x, UL MU resp sched 0x%01x, A-Buff status 0x%01x", + WMI_HECAP_MAC_TRIGPADDUR_GET(mac_cap), + WMI_HECAP_MAC_MTID_RX_GET(mac_cap), + WMI_HECAP_MAC_HELINK_ADPT_GET(mac_cap), + WMI_HECAP_MAC_AACK_GET(mac_cap), + WMI_HECAP_MAC_TRS_GET(mac_cap), + WMI_HECAP_MAC_BSR_GET(mac_cap)); + wma_nofl_debug(" BC TWT 0x%01x, 32bit BA 0x%01x, MU Cascading 0x%01x, ACK enabled Multi-TID 0x%01x, OMI A-Control 0x%01x, OFDMA RA 0x%01x, Max A-MPDU 0x%02x", + WMI_HECAP_MAC_BCSTTWT_GET(mac_cap), + WMI_HECAP_MAC_32BITBA_GET(mac_cap), + WMI_HECAP_MAC_MUCASCADE_GET(mac_cap), + WMI_HECAP_MAC_ACKMTIDAMPDU_GET(mac_cap), + WMI_HECAP_MAC_OMI_GET(mac_cap), + WMI_HECAP_MAC_OFDMARA_GET(mac_cap), + WMI_HECAP_MAC_MAXAMPDULEN_EXP_GET(mac_cap)); + wma_nofl_debug(" A-MSDU Fragmentation: 0x%01x, Flex. TWT sched 0x%01x, Rx Ctrl frame to MBSS: 0x%01x", + WMI_HECAP_MAC_AMSDUFRAG_GET(mac_cap), + WMI_HECAP_MAC_FLEXTWT_GET(mac_cap), + WMI_HECAP_MAC_MBSS_GET(mac_cap)); +} + +void wma_print_he_mac_cap_w2(uint32_t mac_cap) +{ + wma_nofl_debug(" BSRP A-MPDU Aggregation 0x%01x, Quite Time Period 0x%01x, A-BQR 0x%01x, SR Responder 0x%01x, NDP Feedback 0x%01x, OPS 0x%01x", + WMI_HECAP_MAC_BSRPAMPDU_GET(mac_cap), + WMI_HECAP_MAC_QTP_GET(mac_cap), + WMI_HECAP_MAC_ABQR_GET(mac_cap), + WMI_HECAP_MAC_SRPRESP_GET(mac_cap), + WMI_HECAP_MAC_NDPFDBKRPT_GET(mac_cap), + WMI_HECAP_MAC_OPS_GET(mac_cap)); + wma_nofl_debug(" Multi-TID aggr Tx 0x%03x, Sub Ch selective Tx 0x%01x, UL 2x996 tone RU 0x%01x, OM ctrl UL MU data disable Rx: 0x%01x", + WMI_HECAP_MAC_MTID_TX_GET(mac_cap), + WMI_HECAP_MAC_SUBCHANSELTX_GET(mac_cap), + WMI_HECAP_MAC_UL2X996RU_GET(mac_cap), + WMI_HECAP_MAC_OMCULMUDDIS_GET(mac_cap)); +} + +void wma_update_target_ext_he_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg) +{ + tDot11fIEhe_cap *he_cap = &tgt_cfg->he_cap; + int i, num_hw_modes, total_mac_phy_cnt; + struct wlan_psoc_host_mac_phy_caps *mac_cap, *mac_phy_cap; + tDot11fIEhe_cap he_cap_mac; + tDot11fIEhe_cap tmp_he_cap = {0}; + bool is_5g_cap; + + qdf_mem_zero(&tgt_cfg->he_cap_2g, sizeof(tgt_cfg->he_cap_2g)); + qdf_mem_zero(&tgt_cfg->he_cap_5g, sizeof(tgt_cfg->he_cap_5g)); + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + he_cap->present = false; + return; + } + + if (!num_hw_modes) { + wma_err("No extended HE cap for current SOC"); + he_cap->present = false; + return; + } + + if (!tgt_cfg->services.en_11ax) { + wma_info("Target does not support 11AX"); + he_cap->present = false; + return; + } + + for (i = 0; i < total_mac_phy_cnt; i++) { + qdf_mem_zero(&he_cap_mac, + sizeof(tDot11fIEhe_cap)); + mac_cap = &mac_phy_cap[i]; + is_5g_cap = false; + if (mac_cap->supported_bands & WLAN_2G_CAPABILITY) { + wma_convert_he_cap(&he_cap_mac, + mac_cap->he_cap_info_2G, + mac_cap->he_cap_phy_info_2G, + mac_cap->he_supp_mcs_2G, + mac_cap->tx_chain_mask_2G, + mac_cap->rx_chain_mask_2G, + &tgt_cfg->he_mcs_12_13_supp_2g); + wma_debug("2g phy: nss: %d, ru_idx_msk: %d", + mac_cap->he_ppet2G.numss_m1, + mac_cap->he_ppet2G.ru_bit_mask); + wma_convert_he_ppet(tgt_cfg->ppet_2g, + (struct wmi_host_ppe_threshold *) + &mac_cap->he_ppet2G); + } + + if (he_cap_mac.present) { + wma_derive_ext_he_cap(&tmp_he_cap, + &he_cap_mac, + is_5g_cap); + wma_derive_ext_he_cap(&tgt_cfg->he_cap_2g, + &he_cap_mac, + is_5g_cap); + } + + qdf_mem_zero(&he_cap_mac, + sizeof(tDot11fIEhe_cap)); + if (mac_cap->supported_bands & WLAN_5G_CAPABILITY) { + wma_convert_he_cap(&he_cap_mac, + mac_cap->he_cap_info_5G, + mac_cap->he_cap_phy_info_5G, + mac_cap->he_supp_mcs_5G, + mac_cap->tx_chain_mask_5G, + mac_cap->rx_chain_mask_5G, + &tgt_cfg->he_mcs_12_13_supp_5g); + wma_debug("5g phy: nss: %d, ru_idx_msk: %d", + mac_cap->he_ppet5G.numss_m1, + mac_cap->he_ppet5G.ru_bit_mask); + wma_convert_he_ppet(tgt_cfg->ppet_5g, + (struct wmi_host_ppe_threshold *) + &mac_cap->he_ppet5G); + is_5g_cap = true; + } + if (he_cap_mac.present) { + wma_derive_ext_he_cap(&tmp_he_cap, + &he_cap_mac, + is_5g_cap); + wma_derive_ext_he_cap(&tgt_cfg->he_cap_5g, + &he_cap_mac, + is_5g_cap); + } + } + + qdf_mem_copy(he_cap, &tmp_he_cap, sizeof(*he_cap)); + wma_print_he_cap(he_cap); + wma_debug("5 GHz HE caps:"); + wma_print_he_cap(&tgt_cfg->he_cap_5g); + wma_debug("2.4 GHz HE caps:"); + wma_print_he_cap(&tgt_cfg->he_cap_2g); +} + +void wma_he_update_tgt_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + if (wmi_service_enabled(wmi_handle, wmi_service_11ax)) { + cfg->en_11ax = true; + wma_set_fw_wlan_feat_caps(DOT11AX); + wma_debug("11ax is enabled"); + } else { + wma_debug("11ax is not enabled"); + } +} + +void wma_print_he_op(tDot11fIEhe_op *he_ops) +{ + wma_debug("bss_color %0x def_pe_dur %0x twt_req %0x txop_rts_thre %0x vht_oper %0x part_bss_color %0x, MBSSID AP %0x BSS color dis %0x", + he_ops->bss_color, he_ops->default_pe, + he_ops->twt_required, he_ops->txop_rts_threshold, + he_ops->vht_oper_present, he_ops->partial_bss_col, + he_ops->co_located_bss, he_ops->bss_col_disabled); +} + +/** + * wma_parse_he_ppet() - Convert PPET stored in dot11f structure into FW + * structure. + * @rcvd_ppet: pointer to dot11f format PPET + * @peer_ppet: pointer peer_ppet to be sent in peer assoc + * + * This function converts the sequence of PPET stored in the host in OTA type + * structure into FW understandable structure to be sent as part of peer assoc + * command. + * + * Return: None + */ +static void wma_parse_he_ppet(int8_t *rcvd_ppet, + struct wmi_host_ppe_threshold *peer_ppet) +{ + struct ppet_hdr *hdr; + uint8_t num_ppet, mask, mask1, mask2; + uint32_t ppet1, ppet2, ppet; + uint8_t bits, pad, pad_bits, req_byte; + uint8_t byte_idx, start, i, j, parsed; + uint32_t *ppet_r = peer_ppet->ppet16_ppet8_ru3_ru0; + uint8_t nss, ru; + + hdr = (struct ppet_hdr *)rcvd_ppet; + nss = hdr->nss + 1; + mask = hdr->ru_idx_mask; + peer_ppet->numss_m1 = nss - 1; + peer_ppet->ru_bit_mask = mask; + + for (ru = 0; mask; mask >>= 1) { + if (mask & 0x1) + ru++; + } + + wma_debug("Rcvd nss=%d ru_idx_mask: %0x ru_count=%d", + nss, hdr->ru_idx_mask, ru); + + /* each nss-ru pair have 2 PPET (PPET8/PPET16) */ + bits = HE_PPET_NSS_RU_LEN + (nss + ru) * (HE_PPET_SIZE * 2); + pad = bits % HE_BYTE_SIZE; + pad_bits = HE_BYTE_SIZE - pad; + req_byte = (bits + pad_bits) / HE_BYTE_SIZE; + + /* + * PPE Threshold Field Format + * +-----------+--------------+--------------------+-------------+ + * | NSS | RU idx mask | PPE Threshold info | Padding | + * +-----------+--------------+--------------------+-------------+ + * 3 4 1 + variable variable (bits) + * + * PPE Threshold Info field: + * number of NSS:n, number of RU: m + * +------------+-----------+-----+------------+-----------+-----+-----------+-----------+ + * | PPET16 for | PPET8 for | ... | PPET16 for | PPET8 for | ... | PET16 for | PPET8 for | + * | NSS1, RU1 | NSS1, RU1 | ... | NSS1, RUm | NSS1, RUm | ... | NSSn, RUm | NSSn, RUm | + * +------------+-----------+-----+------------+-----------+-----+-----------+-----------+ + * 3 3 ... 3 3 ... 3 3 + */ + + /* first bit of first PPET is in the last bit of first byte */ + parsed = HE_PPET_NSS_RU_LEN; + + /* + * refer wmi_ppe_threshold defn to understand how ppet is stored. + * Index of ppet array(ppet16_ppet8_ru3_ru0) is the NSS value. + * Each item in ppet16_ppet8_ru3_ru0 holds ppet for all the RUs. + */ + num_ppet = ru * 2; /* for each NSS */ + for (i = 0; i < nss; i++) { + for (j = 1; j <= num_ppet; j++) { + start = parsed + (i * (num_ppet * HE_PPET_SIZE)) + + (j-1) * HE_PPET_SIZE; + byte_idx = start / HE_BYTE_SIZE; + start = start % HE_BYTE_SIZE; + + if (start <= HE_BYTE_SIZE - HE_PPET_SIZE) { + mask = 0x07 << start; + ppet = (rcvd_ppet[byte_idx] & mask) >> start; + ppet_r[i] |= (ppet << (j - 1) * HE_PPET_SIZE); + } else { + mask1 = 0x07 << start; + ppet1 = (rcvd_ppet[byte_idx] & mask1) >> start; + mask2 = 0x07 >> (HE_BYTE_SIZE - start); + ppet2 = (rcvd_ppet[byte_idx + 1] & mask2) << + (HE_BYTE_SIZE - start); + ppet = ppet1 | ppet2; + ppet_r[i] |= (ppet << (j - 1) * HE_PPET_SIZE); + } + wma_nofl_debug(" nss:%d ru:%d ppet_r:%0x", i, j / 2, + ppet_r[i]); + } + } +} + +void wma_populate_peer_he_cap(struct peer_assoc_params *peer, + tpAddStaParams params) +{ + tDot11fIEhe_cap *he_cap = ¶ms->he_config; + tDot11fIEhe_op *he_op = ¶ms->he_op; + uint32_t *phy_cap = peer->peer_he_cap_phyinfo; + uint32_t mac_cap[PSOC_HOST_MAX_MAC_SIZE] = {0}, he_ops = 0; + uint8_t temp, i, chan_width; + + if (!params->he_capable) + return; + + peer->he_flag = 1; + peer->qos_flag = 1; + + /* HE MAC capabilities */ + WMI_HECAP_MAC_HECTRL_SET(mac_cap[0], he_cap->htc_he); + WMI_HECAP_MAC_TWTREQ_SET(mac_cap[0], he_cap->twt_request); + WMI_HECAP_MAC_TWTRSP_SET(mac_cap[0], he_cap->twt_responder); + WMI_HECAP_MAC_HEFRAG_SET(mac_cap[0], he_cap->fragmentation); + WMI_HECAP_MAC_MAXFRAGMSDU_SET(mac_cap[0], + he_cap->max_num_frag_msdu_amsdu_exp); + WMI_HECAP_MAC_MINFRAGSZ_SET(mac_cap[0], he_cap->min_frag_size); + WMI_HECAP_MAC_TRIGPADDUR_SET(mac_cap[0], he_cap->trigger_frm_mac_pad); + WMI_HECAP_MAC_ACKMTIDAMPDU_SET(mac_cap[0], + he_cap->multi_tid_aggr_rx_supp); + WMI_HECAP_MAC_HELKAD_SET(mac_cap[0], he_cap->he_link_adaptation); + WMI_HECAP_MAC_AACK_SET(mac_cap[0], he_cap->all_ack); + WMI_HECAP_MAC_TRS_SET(mac_cap[0], he_cap->trigd_rsp_sched); + WMI_HECAP_MAC_BSR_SET(mac_cap[0], he_cap->a_bsr); + WMI_HECAP_MAC_BCSTTWT_SET(mac_cap[0], he_cap->broadcast_twt); + WMI_HECAP_MAC_32BITBA_SET(mac_cap[0], he_cap->ba_32bit_bitmap); + WMI_HECAP_MAC_MUCASCADE_SET(mac_cap[0], he_cap->mu_cascade); + WMI_HECAP_MAC_ACKMTIDAMPDU_SET(mac_cap[0], + he_cap->ack_enabled_multitid); + WMI_HECAP_MAC_OMI_SET(mac_cap[0], he_cap->omi_a_ctrl); + WMI_HECAP_MAC_OFDMARA_SET(mac_cap[0], he_cap->ofdma_ra); + WMI_HECAP_MAC_MAXAMPDULEN_EXP_SET(mac_cap[0], + he_cap->max_ampdu_len_exp_ext); + WMI_HECAP_MAC_AMSDUFRAG_SET(mac_cap[0], he_cap->amsdu_frag); + WMI_HECAP_MAC_FLEXTWT_SET(mac_cap[0], he_cap->flex_twt_sched); + WMI_HECAP_MAC_MBSS_SET(mac_cap[0], he_cap->rx_ctrl_frame); + WMI_HECAP_MAC_BSRPAMPDU_SET(mac_cap[1], he_cap->bsrp_ampdu_aggr); + WMI_HECAP_MAC_QTP_SET(mac_cap[1], he_cap->qtp); + WMI_HECAP_MAC_ABQR_SET(mac_cap[1], he_cap->a_bqr); + WMI_HECAP_MAC_SRPRESP_SET(mac_cap[1], + he_cap->spatial_reuse_param_rspder); + WMI_HECAP_MAC_OPS_SET(mac_cap[1], he_cap->ops_supp); + WMI_HECAP_MAC_NDPFDBKRPT_SET(mac_cap[1], he_cap->ndp_feedback_supp); + WMI_HECAP_MAC_AMSDUINAMPDU_SET(mac_cap[1], he_cap->amsdu_in_ampdu); + WMI_HECAP_MAC_MTID_TX_SET(mac_cap[1], he_cap->multi_tid_aggr_tx_supp); + WMI_HECAP_MAC_SUBCHANSELTX_SET(mac_cap[1], + he_cap->he_sub_ch_sel_tx_supp); + WMI_HECAP_MAC_UL2X996RU_SET(mac_cap[1], he_cap->ul_2x996_tone_ru_supp); + WMI_HECAP_MAC_OMCULMUDDIS_SET(mac_cap[1], + he_cap->om_ctrl_ul_mu_data_dis_rx); + WMI_HECAP_MAC_DYNSMPWRSAVE_SET(mac_cap[1], he_cap->he_dynamic_smps); + WMI_HECAP_MAC_PUNCSOUNDING_SET(mac_cap[1], + he_cap->punctured_sounding_supp); + WMI_HECAP_MAC_HTVHTTRIGRX_SET(mac_cap[1], + he_cap->ht_vht_trg_frm_rx_supp); + qdf_mem_copy(peer->peer_he_cap_macinfo, mac_cap, sizeof(mac_cap)); + + /* HE PHY capabilities */ + chan_width = HE_CH_WIDTH_COMBINE(he_cap->chan_width_0, + he_cap->chan_width_1, he_cap->chan_width_2, + he_cap->chan_width_3, he_cap->chan_width_4, + he_cap->chan_width_5, he_cap->chan_width_6); + WMI_HECAP_PHY_CBW_SET(phy_cap, chan_width); + WMI_HECAP_PHY_PREAMBLEPUNCRX_SET(phy_cap, he_cap->rx_pream_puncturing); + WMI_HECAP_PHY_COD_SET(phy_cap, he_cap->device_class); + WMI_HECAP_PHY_LDPC_SET(phy_cap, he_cap->ldpc_coding); + WMI_HECAP_PHY_LTFGIFORHE_SET(phy_cap, he_cap->he_1x_ltf_800_gi_ppdu); + WMI_HECAP_PHY_MIDAMBLETXRXMAXNSTS_SET(phy_cap, + he_cap->midamble_tx_rx_max_nsts); + WMI_HECAP_PHY_LTFGIFORNDP_SET(phy_cap, he_cap->he_4x_ltf_3200_gi_ndp); + + WMI_HECAP_PHY_RXSTBC_SET(phy_cap, he_cap->rx_stbc_lt_80mhz); + WMI_HECAP_PHY_TXSTBC_SET(phy_cap, he_cap->tb_ppdu_tx_stbc_lt_80mhz); + + temp = he_cap->doppler & 0x1; + WMI_HECAP_PHY_RXDOPPLER_SET(phy_cap, temp); + temp = he_cap->doppler >> 0x1; + WMI_HECAP_PHY_TXDOPPLER_SET(phy_cap, temp); + + temp = he_cap->ul_mu & 0x1; + WMI_HECAP_PHY_UL_MU_MIMO_SET(phy_cap, temp); + temp = he_cap->ul_mu >> 0x1; + WMI_HECAP_PHY_ULMUMIMOOFDMA_SET(phy_cap, temp); + + WMI_HECAP_PHY_DCMTX_SET(phy_cap, he_cap->dcm_enc_tx); + WMI_HECAP_PHY_DCMRX_SET(phy_cap, he_cap->dcm_enc_rx); + WMI_HECAP_PHY_ULHEMU_SET(phy_cap, he_cap->ul_he_mu); + WMI_HECAP_PHY_SUBFMR_SET(phy_cap, he_cap->su_beamformer); + WMI_HECAP_PHY_SUBFME_SET(phy_cap, he_cap->su_beamformee); + WMI_HECAP_PHY_MUBFMR_SET(phy_cap, he_cap->mu_beamformer); + WMI_HECAP_PHY_BFMESTSLT80MHZ_SET(phy_cap, he_cap->bfee_sts_lt_80); + WMI_HECAP_PHY_BFMESTSGT80MHZ_SET(phy_cap, he_cap->bfee_sts_gt_80); + WMI_HECAP_PHY_NUMSOUNDLT80MHZ_SET(phy_cap, he_cap->num_sounding_lt_80); + WMI_HECAP_PHY_NUMSOUNDGT80MHZ_SET(phy_cap, he_cap->num_sounding_gt_80); + WMI_HECAP_PHY_NG16SUFEEDBACKLT80_SET(phy_cap, + he_cap->su_feedback_tone16); + WMI_HECAP_PHY_NG16MUFEEDBACKGT80_SET(phy_cap, + he_cap->mu_feedback_tone16); + WMI_HECAP_PHY_CODBK42SU_SET(phy_cap, he_cap->codebook_su); + WMI_HECAP_PHY_CODBK75MU_SET(phy_cap, he_cap->codebook_mu); + WMI_HECAP_PHY_BFFEEDBACKTRIG_SET(phy_cap, he_cap->beamforming_feedback); + WMI_HECAP_PHY_HEERSU_SET(phy_cap, he_cap->he_er_su_ppdu); + WMI_HECAP_PHY_DLMUMIMOPARTIALBW_SET(phy_cap, + he_cap->dl_mu_mimo_part_bw); + WMI_HECAP_PHY_PETHRESPRESENT_SET(phy_cap, he_cap->ppet_present); + WMI_HECAP_PHY_SRPPRESENT_SET(phy_cap, he_cap->srp); + WMI_HECAP_PHY_PWRBOOSTAR_SET(phy_cap, he_cap->power_boost); + WMI_HECAP_PHY_4XLTFAND800NSECSGI_SET(phy_cap, he_cap->he_ltf_800_gi_4x); + + WMI_HECAP_PHY_MAXNC_SET(phy_cap, he_cap->max_nc); + + WMI_HECAP_PHY_STBCRXGT80_SET(phy_cap, he_cap->rx_stbc_gt_80mhz); + WMI_HECAP_PHY_STBCTXGT80_SET(phy_cap, he_cap->tb_ppdu_tx_stbc_gt_80mhz); + + WMI_HECAP_PHY_ERSU4X800NSECGI_SET(phy_cap, he_cap->er_he_ltf_800_gi_4x); + WMI_HECAP_PHY_HEPPDU20IN40MHZ2G_SET(phy_cap, + he_cap->he_ppdu_20_in_40Mhz_2G); + WMI_HECAP_PHY_HEPPDU20IN160OR80P80MHZ_SET(phy_cap, + he_cap->he_ppdu_20_in_160_80p80Mhz); + WMI_HECAP_PHY_HEPPDU80IN160OR80P80MHZ_SET(phy_cap, + he_cap->he_ppdu_80_in_160_80p80Mhz); + WMI_HECAP_PHY_ERSU1X800NSECGI_SET(phy_cap, he_cap->er_1x_he_ltf_gi); + WMI_HECAP_PHY_MIDAMBLETXRX2XAND1XHELTF_SET(phy_cap, + he_cap-> + midamble_tx_rx_1x_he_ltf); + WMI_HECAP_PHY_DCMMAXBW_SET(phy_cap, he_cap->dcm_max_bw); + WMI_HECAP_PHY_LNG16SIGBSYMBSUPRT_SET(phy_cap, + he_cap-> + longer_than_16_he_sigb_ofdm_sym); + WMI_HECAP_PHY_NONTRIGCQIFEEDBK_SET(phy_cap, + he_cap->non_trig_cqi_feedback); + WMI_HECAP_PHY_TX1024QAM242RUSUPRT_SET(phy_cap, + he_cap-> + tx_1024_qam_lt_242_tone_ru); + WMI_HECAP_PHY_RX1024QAM242RUSUPRT_SET(phy_cap, + he_cap-> + rx_1024_qam_lt_242_tone_ru); + WMI_HECAP_PHY_RXFULBWSUWCMPRSSIGB_SET(phy_cap, + he_cap->rx_full_bw_su_he_mu_compress_sigb); + WMI_HECAP_PHY_RXFULBWSUWNONCMPRSSIGB_SET(phy_cap, + he_cap->rx_full_bw_su_he_mu_non_cmpr_sigb); + + /* as per 11ax draft 1.4 */ + peer->peer_he_mcs_count = 1; + peer->peer_he_rx_mcs_set[0] = + params->supportedRates.rx_he_mcs_map_lt_80; + peer->peer_he_tx_mcs_set[0] = + params->supportedRates.tx_he_mcs_map_lt_80; + if (params->he_mcs_12_13_map) { + peer->peer_he_tx_mcs_set[0] |= + (params->he_mcs_12_13_map << + WMA_MCS_12_13_MAP_L80) & WMA_MCS_12_13_PEER_RATE_MAP; + peer->peer_he_rx_mcs_set[0] |= + (params->he_mcs_12_13_map << + WMA_MCS_12_13_MAP_L80) & WMA_MCS_12_13_PEER_RATE_MAP; + } + + if (params->ch_width > CH_WIDTH_80MHZ || + IS_TDLS_PEER(params->staType)) { + peer->peer_he_mcs_count = WMI_HOST_MAX_HE_RATE_SET; + peer->peer_he_rx_mcs_set[1] |= + params->supportedRates.rx_he_mcs_map_160; + peer->peer_he_tx_mcs_set[1] |= + params->supportedRates.tx_he_mcs_map_160; + peer->peer_he_rx_mcs_set[2] |= + params->supportedRates.rx_he_mcs_map_80_80; + peer->peer_he_tx_mcs_set[2] |= + params->supportedRates.tx_he_mcs_map_80_80; + + if (params->he_mcs_12_13_map) { + peer->peer_he_tx_mcs_set[1] |= + (params->he_mcs_12_13_map << + WMA_MCS_12_13_MAP_G80) & + WMA_MCS_12_13_PEER_RATE_MAP; + peer->peer_he_tx_mcs_set[2] |= + (params->he_mcs_12_13_map << + WMA_MCS_12_13_MAP_G80) & + WMA_MCS_12_13_PEER_RATE_MAP; + peer->peer_he_rx_mcs_set[1] |= + (params->he_mcs_12_13_map << + WMA_MCS_12_13_MAP_G80) & + WMA_MCS_12_13_PEER_RATE_MAP; + peer->peer_he_rx_mcs_set[2] |= + (params->he_mcs_12_13_map << + WMA_MCS_12_13_MAP_G80) & + WMA_MCS_12_13_PEER_RATE_MAP; + } + } + + wma_debug("Sending TX/RX MCS set to FW: <=80: %x, 160: %x, 80+80: %x", + peer->peer_he_rx_mcs_set[0], peer->peer_he_rx_mcs_set[1], + peer->peer_he_rx_mcs_set[2]); + +#define HE2x2MCSMASK 0xc + + peer->peer_nss = ((params->supportedRates.rx_he_mcs_map_lt_80 & + HE2x2MCSMASK) == HE2x2MCSMASK) ? 1 : 2; + for (i = 0; i < peer->peer_he_mcs_count; i++) + wma_debug("[HE - MCS Map: %d] rx_mcs: 0x%x, tx_mcs: 0x%x", i, + peer->peer_he_rx_mcs_set[i], + peer->peer_he_tx_mcs_set[i]); + + WMI_HEOPS_COLOR_SET(he_ops, he_op->bss_color); + WMI_HEOPS_DEFPE_SET(he_ops, he_op->default_pe); + WMI_HEOPS_TWT_SET(he_ops, he_op->twt_required); + WMI_HEOPS_RTSTHLD_SET(he_ops, he_op->txop_rts_threshold); + WMI_HEOPS_ERSUDIS_SET(he_ops, he_op->er_su_disable); + WMI_HEOPS_PARTBSSCOLOR_SET(he_ops, he_op->partial_bss_col); + WMI_HEOPS_BSSCOLORDISABLE_SET(he_ops, he_op->bss_col_disabled); + peer->peer_he_ops = he_ops; + + wma_parse_he_ppet(he_cap->ppet.ppe_threshold.ppe_th, &peer->peer_ppet); + + wma_print_he_cap(he_cap); + wma_debug("Peer HE Caps:"); + wma_print_he_phy_cap(phy_cap); + wma_print_he_mac_cap_w1(mac_cap[0]); + wma_print_he_mac_cap_w2(mac_cap[1]); + wma_print_he_ppet(&peer->peer_ppet); + + if (params->he_6ghz_band_caps.present) { + peer->peer_he_caps_6ghz = + (params->he_6ghz_band_caps.min_mpdu_start_spacing << + HE_6G_MIN_MPDU_START_SAPCE_BIT_POS) | + (params->he_6ghz_band_caps.max_ampdu_len_exp << + HE_6G_MAX_AMPDU_LEN_EXP_BIT_POS) | + (params->he_6ghz_band_caps.max_mpdu_len << + HE_6G_MAX_MPDU_LEN_BIT_POS) | + (params->he_6ghz_band_caps.sm_pow_save << + HE_6G_SMPS_BIT_POS) | + (params->he_6ghz_band_caps.rd_responder << + HE_6G_RD_RESP_BIT_POS) | + (params->he_6ghz_band_caps.rx_ant_pattern_consistency << + HE_6G_RX_ANT_PATTERN_BIT_POS) | + (params->he_6ghz_band_caps.tx_ant_pattern_consistency << + HE_6G_TX_ANT_PATTERN_BIT_POS); + wma_debug("HE 6GHz band caps: %0x", peer->peer_he_caps_6ghz); + } else { + peer->peer_he_caps_6ghz = 0; + } +} + +void wma_update_vdev_he_ops(uint32_t *he_ops, tDot11fIEhe_op *he_op) +{ + WMI_HEOPS_COLOR_SET(*he_ops, he_op->bss_color); + WMI_HEOPS_DEFPE_SET(*he_ops, he_op->default_pe); + WMI_HEOPS_TWT_SET(*he_ops, he_op->twt_required); + WMI_HEOPS_RTSTHLD_SET(*he_ops, he_op->txop_rts_threshold); + WMI_HEOPS_PARTBSSCOLOR_SET(*he_ops, he_op->partial_bss_col); + WMI_HEOPS_BSSCOLORDISABLE_SET(*he_ops, he_op->bss_col_disabled); +} + +void wma_vdev_set_he_bss_params(tp_wma_handle wma, uint8_t vdev_id, + struct vdev_mlme_he_ops_info *he_info) +{ + QDF_STATUS ret; + + if (!he_info->he_ops) + return; + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_set_heop, he_info->he_ops); + + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to set HE OPs"); +} + +void wma_vdev_set_he_config(tp_wma_handle wma, uint8_t vdev_id, + struct bss_params *add_bss) +{ + QDF_STATUS ret; + int8_t pd_min, pd_max, sec_ch_ed, tx_pwr; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_obsspd, add_bss->he_sta_obsspd); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to set HE Config"); + pd_min = add_bss->he_sta_obsspd & 0xff, + pd_max = (add_bss->he_sta_obsspd & 0xff00) >> 8, + sec_ch_ed = (add_bss->he_sta_obsspd & 0xff0000) >> 16, + tx_pwr = (add_bss->he_sta_obsspd & 0xff000000) >> 24; + wma_debug("HE_STA_OBSSPD: PD_MIN: %d PD_MAX: %d SEC_CH_ED: %d TX_PWR: %d", + pd_min, pd_max, sec_ch_ed, tx_pwr); +} + +QDF_STATUS wma_update_he_ops_ie(tp_wma_handle wma, uint8_t vdev_id, + tDot11fIEhe_op *he_op) +{ + QDF_STATUS ret; + uint32_t dword_he_op = 0; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_FAILURE; + + WMI_HEOPS_COLOR_SET(dword_he_op, he_op->bss_color); + WMI_HEOPS_DEFPE_SET(dword_he_op, he_op->default_pe); + WMI_HEOPS_TWT_SET(dword_he_op, he_op->twt_required); + WMI_HEOPS_RTSTHLD_SET(dword_he_op, he_op->txop_rts_threshold); + WMI_HEOPS_PARTBSSCOLOR_SET(dword_he_op, he_op->partial_bss_col); + WMI_HEOPS_BSSCOLORDISABLE_SET(dword_he_op, he_op->bss_col_disabled); + + wma_debug("vdev_id: %d HE_OPs: 0x%x", vdev_id, dword_he_op); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_set_heop, dword_he_op); + + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to set HE OPs"); + + return ret; +} + +void wma_set_he_txbf_cfg(struct mac_context *mac, uint8_t vdev_id) +{ + wma_set_he_txbf_params(vdev_id, + mac->mlme_cfg->he_caps.dot11_he_cap.su_beamformer, + mac->mlme_cfg->he_caps.dot11_he_cap.su_beamformee, + mac->mlme_cfg->he_caps.dot11_he_cap.mu_beamformer); +} + +void wma_set_he_txbf_params(uint8_t vdev_id, bool su_bfer, + bool su_bfee, bool mu_bfer) +{ + uint32_t hemu_mode; + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return; + + hemu_mode = DOT11AX_HEMU_MODE; + hemu_mode |= ((su_bfer << HE_SUBFER) | (su_bfee << HE_SUBFEE) | + (mu_bfer << HE_MUBFER) | (su_bfee << HE_MUBFEE)); + /* + * Enable / disable trigger access for a AP vdev's peers. + * For a STA mode vdev this will enable/disable triggered + * access and enable/disable Multi User mode of operation. + * A value of 0 in a given bit disables corresponding mode. + * bit | hemu mode + * --------------- + * 0 | HE SUBFEE + * 1 | HE SUBFER + * 2 | HE MUBFEE + * 3 | HE MUBFER + * 4 | DL OFDMA, for AP its DL Tx OFDMA for Sta its Rx OFDMA + * 5 | UL OFDMA, for AP its Tx OFDMA trigger for Sta its + * Rx OFDMA trigger receive & UL response + * 6 | UL MUMIMO + */ + status = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_set_hemu_mode, hemu_mode); + wma_debug("set HEMU_MODE (hemu_mode = 0x%x)", hemu_mode); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set HEMU_MODE(status = %d)", status); +} + +QDF_STATUS wma_get_he_capabilities(struct he_capability *he_cap) +{ + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + qdf_mem_copy(he_cap->phy_cap, + &wma_handle->he_cap.phy_cap, + WMI_MAX_HECAP_PHY_SIZE); + he_cap->mac_cap = wma_handle->he_cap.mac_cap; + he_cap->mcs = wma_handle->he_cap.mcs; + + he_cap->ppet.numss_m1 = wma_handle->he_cap.ppet.numss_m1; + he_cap->ppet.ru_bit_mask = wma_handle->he_cap.ppet.ru_bit_mask; + qdf_mem_copy(&he_cap->ppet.ppet16_ppet8_ru3_ru0, + &wma_handle->he_cap.ppet.ppet16_ppet8_ru3_ru0, + WMI_MAX_NUM_SS); + + return QDF_STATUS_SUCCESS; +} + +void wma_set_he_vdev_param(struct wma_txrx_node *intr, + wmi_conv_vdev_param_id param_id, + uint32_t value) +{ + switch (param_id) { + case wmi_vdev_param_he_dcm_enable: + intr->config.dcm = value; + break; + case wmi_vdev_param_he_range_ext: + intr->config.range_ext = value; + break; + default: + wma_err("Unhandled HE vdev param: %0x", param_id); + break; + } +} + +uint32_t wma_get_he_vdev_param(struct wma_txrx_node *intr, + wmi_conv_vdev_param_id param_id) +{ + switch (param_id) { + case wmi_vdev_param_he_dcm_enable: + return intr->config.dcm; + case wmi_vdev_param_he_range_ext: + return intr->config.range_ext; + default: + wma_err("Unhandled HE vdev param: %0x", param_id); + break; + } + return 0; +} + +QDF_STATUS wma_get_hemu_mode(uint32_t *hemumode, struct mac_context *mac) +{ + if (!hemumode || !mac) + return QDF_STATUS_E_FAILURE; + + *hemumode = DOT11AX_HEMU_MODE; + *hemumode |= ((mac->mlme_cfg->he_caps.dot11_he_cap.su_beamformer << HE_SUBFER) | + (mac->mlme_cfg->he_caps.dot11_he_cap.su_beamformee << HE_SUBFEE) | + (mac->mlme_cfg->he_caps.dot11_he_cap.mu_beamformer << HE_MUBFER) | + (mac->mlme_cfg->he_caps.dot11_he_cap.su_beamformee << HE_MUBFEE)); + /* + * Enable / disable trigger access for a AP vdev's peers. + * For a STA mode vdev this will enable/disable triggered + * access and enable/disable Multi User mode of operation. + * A value of 0 in a given bit disables corresponding mode. + * bit | hemu mode + * --------------- + * 0 | HE SUBFEE + * 1 | HE SUBFER + * 2 | HE MUBFEE + * 3 | HE MUBFER + * 4 | DL OFDMA, for AP its DL Tx OFDMA for Sta its Rx OFDMA + * 5 | UL OFDMA, for AP its Tx OFDMA trigger for Sta its + * Rx OFDMA trigger receive & UL response + * 6 | UL MUMIMO + */ + return QDF_STATUS_SUCCESS; +} + +void wma_prevent_suspend_on_obss_color_collision(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + qdf_wake_lock_timeout_acquire(&mlme_priv->bss_color_change_wakelock, + MAX_WAKELOCK_FOR_BSS_COLOR_CHANGE); + qdf_runtime_pm_prevent_suspend( + &mlme_priv->bss_color_change_runtime_lock); +} + +void wma_allow_suspend_after_obss_color_change(struct wlan_objmgr_vdev *vdev) +{ + struct mlme_legacy_priv *mlme_priv; + + mlme_priv = wlan_vdev_mlme_get_ext_hdl(vdev); + if (!mlme_priv) + return; + + qdf_runtime_pm_allow_suspend( + &mlme_priv->bss_color_change_runtime_lock); + qdf_wake_lock_release(&mlme_priv->bss_color_change_wakelock, 0); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_main.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_main.c new file mode 100644 index 0000000000..da32301b79 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_main.c @@ -0,0 +1,10435 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_main.c + * + * This file contains wma initialization and FW exchange + * related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" +#include "wlan_cm_tgt_if_tx_api.h" +#include "wlan_cm_roam_api.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "wma_internal.h" + +#include "wma_ocb.h" +#include "wlan_policy_mgr_api.h" +#include "cdp_txrx_cfg.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include "cdp_txrx_flow_ctrl_v2.h" +#include "cdp_txrx_ipa.h" +#include "cdp_txrx_misc.h" +#include "wma_fips_api.h" +#include "wma_nan_datapath.h" +#include "wma_fw_state.h" +#include "wlan_lmac_if_def.h" +#include "wlan_lmac_if_api.h" +#include "target_if.h" +#include "target_if_scan.h" +#include "wlan_global_lmac_if_api.h" +#include "target_if_pmo.h" +#include "wma_he.h" +#include "wlan_pmo_obj_mgmt_api.h" + +#include "wlan_reg_tgt_api.h" +#include "wlan_reg_services_api.h" +#include +#include +#include "wifi_pos_api.h" +#include "hif_main.h" +#ifdef WLAN_CONV_SPECTRAL_ENABLE +#include +#include +#endif +#include "init_event_handler.h" +#include "init_deinit_lmac.h" +#include "target_if_green_ap.h" +#include "service_ready_param.h" +#include "wlan_cp_stats_mc_ucfg_api.h" +#include "cfg_nan_api.h" +#include "wlan_mlme_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "cfg_ucfg_api.h" +#include "init_cmd_api.h" +#include "nan_ucfg_api.h" +#include "wma_coex.h" +#include "wma_twt.h" +#include "target_if_vdev_mgr_rx_ops.h" +#include "wlan_tdls_cfg_api.h" +#include "wlan_policy_mgr_i.h" +#include "target_if_psoc_timer_tx_ops.h" +#include +#include "wlan_ipa_ucfg_api.h" +#include "wma_eht.h" + +#ifdef DIRECT_BUF_RX_ENABLE +#include +#endif + +#include "wlan_pkt_capture_ucfg_api.h" +#include "target_if_cm_roam_event.h" +#include "wlan_fwol_ucfg_api.h" +#include "wlan_tdls_api.h" +#include "wlan_twt_cfg_ext_api.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_dp_api.h" +#include "wlan_dp_ucfg_api.h" + +#define WMA_LOG_COMPLETION_TIMER 500 /* 500 msecs */ +#define WMI_TLV_HEADROOM 128 + +static uint32_t g_fw_wlan_feat_caps; +/** + * wma_get_fw_wlan_feat_caps() - get fw feature capability + * @feature: feature enum value + * + * Return: true/false + */ +bool wma_get_fw_wlan_feat_caps(enum cap_bitmap feature) +{ + return (g_fw_wlan_feat_caps & (1 << feature)) ? true : false; +} + +/** + * wma_set_fw_wlan_feat_caps() - set fw feature capability + * @feature: feature enum value + * + * Return: None + */ +void wma_set_fw_wlan_feat_caps(enum cap_bitmap feature) +{ + g_fw_wlan_feat_caps |= (1 << feature); +} + +/** + * wma_service_ready_ext_evt_timeout() - Service ready extended event timeout + * @data: Timeout handler data + * + * This function is called when the FW fails to send WMI_SERVICE_READY_EXT_EVENT + * message + * + * Return: None + */ +static void wma_service_ready_ext_evt_timeout(void *data) +{ + wma_alert("Timeout waiting for WMI_SERVICE_READY_EXT_EVENT"); + + /* Assert here. Panic is being called in insmod thread */ + QDF_ASSERT(0); +} + +/** + * wma_get_ini_handle() - API to get WMA ini info handle + * @wma: WMA Handle + * + * Returns the pointer to WMA ini structure. + * Return: struct wma_ini_config + */ +struct wma_ini_config *wma_get_ini_handle(tp_wma_handle wma) +{ + if (wma_validate_handle(wma)) + return NULL; + + return &wma->ini_config; +} + +int __wma_validate_handle(tp_wma_handle wma_handle, const char *func) +{ + if (!wma_handle) { + wma_err("Invalid WMA handle (via %s)", func); + return -EINVAL; + } + + return 0; +} + +#define MAX_SUPPORTED_PEERS_REV1_1 14 +#define MAX_SUPPORTED_PEERS_REV1_3 32 +#ifdef WLAN_MAX_CLIENTS_ALLOWED +#define MAX_SUPPORTED_PEERS WLAN_MAX_CLIENTS_ALLOWED +#else +#define MAX_SUPPORTED_PEERS 32 +#endif +#define MIN_NO_OF_PEERS 1 + +/** + * wma_get_number_of_peers_supported - API to query for number of peers + * supported + * @wma: WMA Handle + * + * Return: Max Number of Peers Supported + */ +static uint8_t wma_get_number_of_peers_supported(tp_wma_handle wma) +{ + struct wma_ini_config *cfg = wma_get_ini_handle(wma); + uint8_t max_no_of_peers = cfg ? cfg->max_no_of_peers : MIN_NO_OF_PEERS; + + return max_no_of_peers; +} + +/** + * wma_get_number_of_tids_supported - API to query for number of tids supported + * @no_of_peers_supported: Number of peer supported + * @no_vdevs: Number of vdevs + * + * Return: Max number of tids supported + */ +#if defined(CONFIG_HL_SUPPORT) +static uint32_t wma_get_number_of_tids_supported(uint8_t no_of_peers_supported, + uint8_t num_vdevs) +{ + return 4 * no_of_peers_supported; +} +#else +static uint32_t wma_get_number_of_tids_supported(uint8_t no_of_peers_supported, + uint8_t num_vdevs) +{ + return 2 * (no_of_peers_supported + num_vdevs + 2); +} +#endif + +#if (defined(IPA_DISABLE_OVERRIDE)) && (!defined(IPA_OFFLOAD)) +static void wma_set_ipa_disable_config( + target_resource_config *tgt_cfg) +{ + tgt_cfg->ipa_disable = true; +} +#else +static void wma_set_ipa_disable_config( + target_resource_config *tgt_cfg) +{ + tgt_cfg->ipa_disable = ucfg_ipa_is_enabled() ? false : true; +} +#endif + +#ifndef NUM_OF_ADDITIONAL_FW_PEERS +#define NUM_OF_ADDITIONAL_FW_PEERS 2 +#endif + +/** + * wma_update_num_peers_tids() - Update num_peers and tids based on num_vdevs + * @wma_handle: wma handle + * @tgt_cfg: Resource config given to target + * + * Get num_vdevs from tgt_cfg and update num_peers and tids based on it. + * + * Return: none + */ +static void wma_update_num_peers_tids(t_wma_handle *wma_handle, + target_resource_config *tgt_cfg) + +{ + uint8_t no_of_peers_supported; + + no_of_peers_supported = wma_get_number_of_peers_supported(wma_handle); + + tgt_cfg->num_peers = no_of_peers_supported + tgt_cfg->num_vdevs + + NUM_OF_ADDITIONAL_FW_PEERS; + /* The current firmware implementation requires the number of + * offload peers should be (number of vdevs + 1). + */ + tgt_cfg->num_tids = + wma_get_number_of_tids_supported(no_of_peers_supported, + tgt_cfg->num_vdevs); +} + +#ifdef FEATURE_WDS +/** + * wma_set_peer_map_unmap_v2_config() - Update peer_map_unmap_v2 + * @psoc: Object manager psoc + * @tgt_cfg: Resource config given to target + * + * This function enables Peer map/unmap v2 feature. + * + * Return: none + */ +static void wma_set_peer_map_unmap_v2_config(struct wlan_objmgr_psoc *psoc, + target_resource_config *tgt_cfg) +{ + tgt_cfg->peer_map_unmap_v2 = + wlan_mlme_get_wds_mode(psoc) ? true : false; +} +#else +static void wma_set_peer_map_unmap_v2_config(struct wlan_objmgr_psoc *psoc, + target_resource_config *tgt_cfg) +{ + tgt_cfg->peer_map_unmap_v2 = false; +} +#endif + +#ifdef FEATURE_SET +/** + * wma_get_concurrency_support() - Get concurrency support + * @psoc: Object manager psoc + * + * Return: WMI_HOST_BAND_CONCURRENCY + */ +static WMI_HOST_BAND_CONCURRENCY +wma_get_concurrency_support(struct wlan_objmgr_psoc *psoc) +{ + bool is_sbs_enabled = false; + + if (policy_mgr_is_dual_mac_disabled_in_ini(psoc)) + return WMI_HOST_BAND_CONCURRENCY_NONE; + + policy_mgr_get_sbs_cfg(psoc, &is_sbs_enabled); + + if (is_sbs_enabled) + return WMI_HOST_BAND_CONCURRENCY_DBS_SBS; + else + return WMI_HOST_BAND_CONCURRENCY_DBS; +} + +/** + * wma_update_set_feature_version() - Update the set feature version + * + * @fs: Feature set structure in which version needs to be updated. + * + * Version 1 - Base feature version + * Version 2 - WMI_HOST_VENDOR1_REQ1_VERSION_3_30 updated. + * Version 3 - min sleep period for TWT and Scheduled PM in FW updated + * Version 4 - WMI_HOST_VENDOR1_REQ1_VERSION_3_40 updated. + * Version 5 - INI based 11BE support updated + * Version 6 - sta dump info updated + * + * Return: None + */ +static void wma_update_set_feature_version(struct target_feature_set *fs) +{ + fs->feature_set_version = 6; +} + +/** + * wma_set_feature_set_info() - Set feature set info + * @wma_handle: WMA handle + * @feature_set: Feature set structure which needs to be filled + * + * Return: WMI_HOST_BAND_CONCURRENCY + */ +static void wma_set_feature_set_info(tp_wma_handle wma_handle, + struct target_feature_set *feature_set) +{ + struct cds_context *cds_ctx = + (struct cds_context *)(wma_handle->cds_context); + struct wlan_objmgr_psoc *psoc; + struct wlan_scan_features scan_feature_set = {0}; + struct wlan_twt_features twt_feature_set = {0}; + struct wlan_mlme_features mlme_feature_set = {0}; + struct wlan_tdls_features tdls_feature_set = {0}; + + psoc = wma_handle->psoc; + if (!psoc) { + wma_err("Invalid psoc"); + return; + } + + if (!cds_ctx) { + wma_err("Invalid cds context"); + return; + } + + if (!cds_ctx->cds_cfg) { + wma_err("Invalid cds config"); + return; + } + + feature_set->wifi_standard = + cds_ctx->cds_cfg->cds_feature_set.wifi_standard; + feature_set->sap_5g_supported = + cds_ctx->cds_cfg->cds_feature_set.sap_5g_supported; + feature_set->sap_6g_supported = + cds_ctx->cds_cfg->cds_feature_set.sap_6g_supported; + feature_set->band_capability = + cds_ctx->cds_cfg->cds_feature_set.band_capability; + + feature_set->concurrency_support = wma_get_concurrency_support(psoc); + + wlan_scan_get_feature_info(psoc, &scan_feature_set); + feature_set->pno_in_unassoc_state = + scan_feature_set.pno_in_unassoc_state; + if (feature_set->pno_in_unassoc_state) + feature_set->pno_in_assoc_state = + scan_feature_set.pno_in_assoc_state; + + wlan_twt_get_feature_info(psoc, &twt_feature_set); + feature_set->enable_twt = twt_feature_set.enable_twt; + if (feature_set->enable_twt) { + feature_set->enable_twt_requester = + twt_feature_set.enable_twt_requester; + feature_set->enable_twt_broadcast = + twt_feature_set.enable_twt_broadcast; + feature_set->enable_twt_flexible = + twt_feature_set.enable_twt_flexible; + } + + feature_set->enable_rfc835 = true; + + wlan_mlme_get_feature_info(psoc, &mlme_feature_set); + + feature_set->enable_wifi_optimizer = + mlme_feature_set.enable_wifi_optimizer; + feature_set->sap_max_num_clients = + mlme_feature_set.sap_max_num_clients; + + feature_set->vendor_req_1_version = + mlme_feature_set.vendor_req_1_version; + feature_set->roaming_high_cu_roam_trigger = + mlme_feature_set.roaming_high_cu_roam_trigger; + feature_set->roaming_emergency_trigger = + mlme_feature_set.roaming_emergency_trigger; + feature_set->roaming_btm_trihgger = + mlme_feature_set.roaming_btm_trihgger; + feature_set->roaming_idle_trigger = + mlme_feature_set.roaming_idle_trigger; + feature_set->roaming_wtc_trigger = + mlme_feature_set.roaming_wtc_trigger; + feature_set->roaming_btcoex_trigger = + mlme_feature_set.roaming_btcoex_trigger; + feature_set->roaming_btw_wpa_wpa2 = + mlme_feature_set.roaming_btw_wpa_wpa2; + feature_set->roaming_manage_chan_list_api = + mlme_feature_set.roaming_manage_chan_list_api; + + feature_set->roaming_adaptive_11r = + mlme_feature_set.roaming_adaptive_11r; + feature_set->roaming_ctrl_api_get_set = + mlme_feature_set.roaming_ctrl_api_get_set; + feature_set->roaming_ctrl_api_reassoc = + mlme_feature_set.roaming_ctrl_api_reassoc; + feature_set->roaming_ctrl_get_cu = + mlme_feature_set.roaming_ctrl_get_cu; + feature_set->vendor_req_2_version = + mlme_feature_set.vendor_req_2_version; + feature_set->iface_combinations = mlme_feature_set.iface_combinations; + + if (mlme_feature_set.enable2x2) + feature_set->num_antennas = WMI_HOST_MIMO_2X2; + else + feature_set->num_antennas = WMI_HOST_SISO; + + feature_set->set_country_code_hal_supported = true; + feature_set->get_valid_channel_supported = true; + feature_set->supported_dot11mode = feature_set->wifi_standard; + feature_set->sap_wpa3_support = true; + feature_set->assurance_disconnect_reason_api = true; + feature_set->frame_pcap_log_mgmt = + ucfg_dp_is_local_pkt_capture_enabled(psoc); + feature_set->frame_pcap_log_ctrl = feature_set->frame_pcap_log_mgmt; + feature_set->frame_pcap_log_data = feature_set->frame_pcap_log_mgmt; + + /* + * This information is hardcoded based on hdd_sta_akm_suites, + *wlan_crypto_key_mgmt and wlan_crypto_rsnx_cap + */ + + /* WLAN_CRYPTO_RSNX_CAP_SAE_H2E support*/ + feature_set->security_wpa3_sae_h2e = true; + feature_set->security_wpa3_sae_ft = true; + feature_set->security_wpa3_enterp_suitb = true; + feature_set->security_wpa3_enterp_suitb_192bit = true; + feature_set->security_fills_sha_256 = true; + feature_set->security_fills_sha_384 = true; + feature_set->security_fills_sha_256_FT = true; + feature_set->security_fills_sha_384_FT = true; + /* This is OWE security support */ + feature_set->security_enhanced_open = true; + + feature_set->enable_nan = cfg_nan_get_enable(psoc); + + wlan_tdls_get_features_info(psoc, &tdls_feature_set); + feature_set->enable_tdls = tdls_feature_set.enable_tdls; + if (feature_set->enable_tdls) { + feature_set->enable_tdls_offchannel = + tdls_feature_set.enable_tdls_offchannel; + feature_set->max_tdls_peers = tdls_feature_set.max_tdls_peers; + feature_set->enable_tdls_capability_enhance = + tdls_feature_set.enable_tdls_capability_enhance; + } + + if (feature_set->sap_6g_supported) + feature_set->enable_p2p_6e = + policy_mgr_is_6ghz_conc_mode_supported( + psoc, + PM_P2P_CLIENT_MODE); + + feature_set->peer_bigdata_getbssinfo_support = true; + feature_set->peer_bigdata_assocreject_info_support = true; + feature_set->peer_getstainfo_support = true; + feature_set->sta_dump_support = true; + wma_update_set_feature_version(feature_set); +} + +/** + * wma_send_feature_set_cmd() - Send feature set command to FW + * @wma_handle: WMA handle + * + * Return: None + */ +static void wma_send_feature_set_cmd(tp_wma_handle wma_handle) +{ + struct target_feature_set feature_set; + + if (!wma_handle) { + wma_err("Invalid wma_handle"); + return; + } + + wma_set_feature_set_info(wma_handle, &feature_set); + + wmi_feature_set_cmd_send(wma_handle->wmi_handle, + &feature_set); +} + +/** + * wma_is_feature_set_supported() - Check if feaure set is supported or not + * @wma_handle: WMA handle + * + * Return: True, if feature set is supported else return false + */ +static bool wma_is_feature_set_supported(tp_wma_handle wma_handle) +{ + struct cds_context *cds_ctx = + (struct cds_context *)(wma_handle->cds_context); + bool is_feature_enabled_from_fw; + + if (!cds_ctx) { + wma_err("Invalid cds context"); + return false; + } + + if (!cds_ctx->cds_cfg) { + wma_err("Invalid cds config"); + return false; + } + + is_feature_enabled_from_fw = + wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_feature_set_event_support); + + if (!is_feature_enabled_from_fw) + wma_debug("Get wifi feature is disabled from fw"); + + return (is_feature_enabled_from_fw && + cds_ctx->cds_cfg->get_wifi_features); +} +#else +static inline void wma_send_feature_set_cmd(tp_wma_handle wma_handle) +{ +} + +static bool wma_is_feature_set_supported(tp_wma_handle wma_handle) +{ + return false; +} + +#endif + +/** + * wma_set_default_tgt_config() - set default tgt config + * @wma_handle: wma handle + * @tgt_cfg: Resource config given to target + * @cds_cfg: cds configuration + * + * Return: none + */ +static void wma_set_default_tgt_config(tp_wma_handle wma_handle, + target_resource_config *tgt_cfg, + struct cds_config_info *cds_cfg) +{ + enum QDF_GLOBAL_MODE con_mode; + + qdf_mem_zero(tgt_cfg, sizeof(target_resource_config)); + + tgt_cfg->num_vdevs = cds_cfg->num_vdevs; + wma_update_num_peers_tids(wma_handle, tgt_cfg); + + /* The current firmware implementation requires the number of + * offload peers should be (number of vdevs + 1). + */ + tgt_cfg->num_offload_peers = cds_cfg->ap_maxoffload_peers + 1; + tgt_cfg->num_offload_reorder_buffs = + cds_cfg->ap_maxoffload_reorderbuffs + 1; + tgt_cfg->num_peer_keys = CFG_TGT_NUM_PEER_KEYS; + tgt_cfg->ast_skid_limit = CFG_TGT_AST_SKID_LIMIT; + tgt_cfg->tx_chain_mask = CFG_TGT_DEFAULT_TX_CHAIN_MASK; + tgt_cfg->rx_chain_mask = CFG_TGT_DEFAULT_RX_CHAIN_MASK; + tgt_cfg->rx_timeout_pri[0] = CFG_TGT_RX_TIMEOUT_LO_PRI; + tgt_cfg->rx_timeout_pri[1] = CFG_TGT_RX_TIMEOUT_LO_PRI; + tgt_cfg->rx_timeout_pri[2] = CFG_TGT_RX_TIMEOUT_LO_PRI; + tgt_cfg->rx_timeout_pri[3] = CFG_TGT_RX_TIMEOUT_HI_PRI; + tgt_cfg->rx_decap_mode = CFG_TGT_RX_DECAP_MODE; + tgt_cfg->scan_max_pending_req = WLAN_MAX_ACTIVE_SCANS_ALLOWED; + tgt_cfg->bmiss_offload_max_vdev = + CFG_TGT_DEFAULT_BMISS_OFFLOAD_MAX_VDEV; + tgt_cfg->roam_offload_max_vdev = CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_VDEV; + tgt_cfg->roam_offload_max_ap_profiles = + CFG_TGT_DEFAULT_ROAM_OFFLOAD_MAX_PROFILES; + tgt_cfg->num_mcast_groups = CFG_TGT_DEFAULT_NUM_MCAST_GROUPS; + tgt_cfg->num_mcast_table_elems = CFG_TGT_DEFAULT_NUM_MCAST_TABLE_ELEMS; + tgt_cfg->mcast2ucast_mode = CFG_TGT_DEFAULT_MCAST2UCAST_MODE; + tgt_cfg->tx_dbg_log_size = CFG_TGT_DEFAULT_TX_DBG_LOG_SIZE; + tgt_cfg->num_wds_entries = CFG_TGT_WDS_ENTRIES; + tgt_cfg->dma_burst_size = CFG_TGT_DEFAULT_DMA_BURST_SIZE; + tgt_cfg->mac_aggr_delim = CFG_TGT_DEFAULT_MAC_AGGR_DELIM; + tgt_cfg->rx_skip_defrag_timeout_dup_detection_check = + CFG_TGT_DEFAULT_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK, + tgt_cfg->vow_config = CFG_TGT_DEFAULT_VOW_CONFIG; + tgt_cfg->gtk_offload_max_vdev = CFG_TGT_DEFAULT_GTK_OFFLOAD_MAX_VDEV; + tgt_cfg->num_msdu_desc = CFG_TGT_NUM_MSDU_DESC; + tgt_cfg->max_frag_entries = CFG_TGT_MAX_FRAG_TABLE_ENTRIES; + tgt_cfg->num_tdls_vdevs = CFG_TGT_NUM_TDLS_VDEVS; + tgt_cfg->num_tdls_conn_table_entries = + QDF_MIN(CFG_TGT_NUM_TDLS_CONN_TABLE_ENTRIES, + cfg_tdls_get_max_peer_count(wma_handle->psoc)); + tgt_cfg->beacon_tx_offload_max_vdev = + CFG_TGT_DEFAULT_BEACON_TX_OFFLOAD_MAX_VDEV; + tgt_cfg->num_multicast_filter_entries = + CFG_TGT_MAX_MULTICAST_FILTER_ENTRIES; + tgt_cfg->num_wow_filters = 0; + tgt_cfg->num_keep_alive_pattern = MAXNUM_PERIODIC_TX_PTRNS; + tgt_cfg->num_max_sta_vdevs = CFG_TGT_DEFAULT_MAX_STA_VDEVS; + tgt_cfg->keep_alive_pattern_size = 0; + tgt_cfg->max_tdls_concurrent_sleep_sta = + CFG_TGT_NUM_TDLS_CONC_SLEEP_STAS; + tgt_cfg->max_tdls_concurrent_buffer_sta = + CFG_TGT_NUM_TDLS_CONC_BUFFER_STAS; + tgt_cfg->wmi_send_separate = 0; + tgt_cfg->num_ocb_vdevs = CFG_TGT_NUM_OCB_VDEVS; + tgt_cfg->num_ocb_channels = CFG_TGT_NUM_OCB_CHANNELS; + tgt_cfg->num_ocb_schedules = CFG_TGT_NUM_OCB_SCHEDULES; + tgt_cfg->twt_ap_sta_count = CFG_TGT_DEFAULT_TWT_AP_STA_COUNT; + tgt_cfg->enable_pci_gen = cfg_get(wma_handle->psoc, CFG_ENABLE_PCI_GEN); + + tgt_cfg->mgmt_comp_evt_bundle_support = true; + tgt_cfg->tx_msdu_new_partition_id_support = true; + tgt_cfg->is_sap_connected_d3wow_enabled = + ucfg_pmo_get_sap_mode_bus_suspend(wma_handle->psoc); + tgt_cfg->is_go_connected_d3wow_enabled = + ucfg_pmo_get_go_mode_bus_suspend(wma_handle->psoc); + tgt_cfg->num_max_active_vdevs = + policy_mgr_get_max_conc_cxns(wma_handle->psoc); + tgt_cfg->num_max_mlo_link_per_ml_bss = + wlan_mlme_get_sta_mlo_conn_max_num(wma_handle->psoc); + cfg_nan_get_max_ndi(wma_handle->psoc, + &tgt_cfg->max_ndi); + + con_mode = cds_get_conparam(); + if (con_mode == QDF_GLOBAL_MONITOR_MODE) + tgt_cfg->rx_decap_mode = CFG_TGT_RX_DECAP_MODE_RAW; + + if (con_mode == QDF_GLOBAL_FTM_MODE) { + tgt_cfg->num_offload_peers = 0; + tgt_cfg->num_offload_reorder_buffs = 0; + tgt_cfg->bmiss_offload_max_vdev = 0; + tgt_cfg->roam_offload_max_vdev = 0; + tgt_cfg->roam_offload_max_ap_profiles = 0; + tgt_cfg->beacon_tx_offload_max_vdev = 1; + tgt_cfg->num_multicast_filter_entries = 0; + tgt_cfg->gtk_offload_max_vdev = 0; + } + cfg_nan_get_ndp_max_sessions(wma_handle->psoc, + &tgt_cfg->max_ndp_sessions); + + wma_set_ipa_disable_config(tgt_cfg); + wma_set_peer_map_unmap_v2_config(wma_handle->psoc, tgt_cfg); + + tgt_cfg->notify_frame_support = DP_MARK_NOTIFY_FRAME_SUPPORT; +} + +/** + * wma_cli_get_command() - WMA "get" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @vpdev: parameter category + * + * Return: parameter value on success, -EINVAL on failure + */ +int wma_cli_get_command(int vdev_id, int param_id, int vpdev) +{ + int ret = 0; + tp_wma_handle wma; + struct wma_txrx_node *intr = NULL; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return -EINVAL; + + intr = wma->interfaces; + + if (VDEV_CMD == vpdev) { + switch (param_id) { + case wmi_vdev_param_nss: + ret = intr[vdev_id].config.nss; + break; +#ifdef QCA_SUPPORT_GTX + case wmi_vdev_param_gtx_ht_mcs: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[0]; + break; + case wmi_vdev_param_gtx_vht_mcs: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[1]; + break; + case wmi_vdev_param_gtx_usr_cfg: + ret = intr[vdev_id].config.gtx_info.gtxUsrcfg; + break; + case wmi_vdev_param_gtx_thre: + ret = intr[vdev_id].config.gtx_info.gtxPERThreshold; + break; + case wmi_vdev_param_gtx_margin: + ret = intr[vdev_id].config.gtx_info.gtxPERMargin; + break; + case wmi_vdev_param_gtx_step: + ret = intr[vdev_id].config.gtx_info.gtxTPCstep; + break; + case wmi_vdev_param_gtx_mintpc: + ret = intr[vdev_id].config.gtx_info.gtxTPCMin; + break; + case wmi_vdev_param_gtx_bw_mask: + ret = intr[vdev_id].config.gtx_info.gtxBWMask; + break; +#endif /* QCA_SUPPORT_GTX */ + case wmi_vdev_param_ldpc: + ret = intr[vdev_id].config.ldpc; + break; + case wmi_vdev_param_tx_stbc: + ret = intr[vdev_id].config.tx_stbc; + break; + case wmi_vdev_param_rx_stbc: + ret = intr[vdev_id].config.rx_stbc; + break; + case wmi_vdev_param_sgi: + ret = intr[vdev_id].config.shortgi; + break; + case wmi_vdev_param_enable_rtscts: + ret = intr[vdev_id].config.rtscts_en; + break; + case wmi_vdev_param_chwidth: + ret = intr[vdev_id].config.chwidth; + break; + case wmi_vdev_param_fixed_rate: + ret = intr[vdev_id].config.tx_rate; + break; + case wmi_vdev_param_he_dcm_enable: + case wmi_vdev_param_he_range_ext: + ret = wma_get_he_vdev_param(&intr[vdev_id], param_id); + break; + default: + wma_err("Invalid cli_get vdev command/Not yet implemented 0x%x", + param_id); + return -EINVAL; + } + } else if (PDEV_CMD == vpdev) { + switch (param_id) { + case wmi_pdev_param_ani_enable: + ret = wma->pdevconfig.ani_enable; + break; + case wmi_pdev_param_ani_poll_period: + ret = wma->pdevconfig.ani_poll_len; + break; + case wmi_pdev_param_ani_listen_period: + ret = wma->pdevconfig.ani_listen_len; + break; + case wmi_pdev_param_ani_ofdm_level: + ret = wma->pdevconfig.ani_ofdm_level; + break; + case wmi_pdev_param_ani_cck_level: + ret = wma->pdevconfig.ani_cck_level; + break; + case wmi_pdev_param_dynamic_bw: + ret = wma->pdevconfig.cwmenable; + break; + case wmi_pdev_param_cts_cbw: + ret = wma->pdevconfig.cts_cbw; + break; + case wmi_pdev_param_tx_chain_mask: + ret = wma->pdevconfig.txchainmask; + break; + case wmi_pdev_param_rx_chain_mask: + ret = wma->pdevconfig.rxchainmask; + break; + case wmi_pdev_param_txpower_limit2g: + ret = wma->pdevconfig.txpow2g; + break; + case wmi_pdev_param_txpower_limit5g: + ret = wma->pdevconfig.txpow5g; + break; + default: + wma_err("Invalid cli_get pdev command/Not yet implemented 0x%x", + param_id); + return -EINVAL; + } + } else if (GEN_CMD == vpdev) { + switch (param_id) { + case GEN_VDEV_PARAM_AMPDU: + ret = intr[vdev_id].config.ampdu; + break; + case GEN_VDEV_PARAM_AMSDU: + ret = intr[vdev_id].config.amsdu; + break; + case GEN_VDEV_ROAM_SYNCH_DELAY: + ret = intr[vdev_id].roam_synch_delay; + break; + case GEN_VDEV_PARAM_TX_AMPDU: + ret = intr[vdev_id].config.tx_ampdu; + break; + case GEN_VDEV_PARAM_RX_AMPDU: + ret = intr[vdev_id].config.rx_ampdu; + break; + case GEN_VDEV_PARAM_TX_AMSDU: + ret = intr[vdev_id].config.tx_amsdu; + break; + case GEN_VDEV_PARAM_RX_AMSDU: + ret = intr[vdev_id].config.rx_amsdu; + break; + default: + wma_warn("Invalid generic vdev command/Not yet implemented 0x%x", + param_id); + return -EINVAL; + } + } else if (PPS_CMD == vpdev) { + switch (param_id) { + case WMI_VDEV_PPS_PAID_MATCH: + ret = intr[vdev_id].config.pps_params.paid_match_enable; + break; + case WMI_VDEV_PPS_GID_MATCH: + ret = intr[vdev_id].config.pps_params.gid_match_enable; + break; + case WMI_VDEV_PPS_EARLY_TIM_CLEAR: + ret = intr[vdev_id].config.pps_params.tim_clear; + break; + case WMI_VDEV_PPS_EARLY_DTIM_CLEAR: + ret = intr[vdev_id].config.pps_params.dtim_clear; + break; + case WMI_VDEV_PPS_EOF_PAD_DELIM: + ret = intr[vdev_id].config.pps_params.eof_delim; + break; + case WMI_VDEV_PPS_MACADDR_MISMATCH: + ret = intr[vdev_id].config.pps_params.mac_match; + break; + case WMI_VDEV_PPS_DELIM_CRC_FAIL: + ret = intr[vdev_id].config.pps_params.delim_fail; + break; + case WMI_VDEV_PPS_GID_NSTS_ZERO: + ret = intr[vdev_id].config.pps_params.nsts_zero; + break; + case WMI_VDEV_PPS_RSSI_CHECK: + ret = intr[vdev_id].config.pps_params.rssi_chk; + break; + default: + wma_err("Invalid pps vdev command/Not yet implemented 0x%x", + param_id); + return -EINVAL; + } + } else if (QPOWER_CMD == vpdev) { + switch (param_id) { + case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT: + ret = intr[vdev_id].config.qpower_params. + max_ps_poll_cnt; + break; + case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE: + ret = intr[vdev_id].config.qpower_params. + max_tx_before_wake; + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + ret = intr[vdev_id].config.qpower_params. + spec_ps_poll_wake_interval; + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + ret = intr[vdev_id].config.qpower_params. + max_spec_nodata_ps_poll; + break; + default: + wma_warn("Invalid generic vdev command/Not yet implemented 0x%x", + param_id); + return -EINVAL; + } + } else if (GTX_CMD == vpdev) { + switch (param_id) { + case wmi_vdev_param_gtx_ht_mcs: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[0]; + break; + case wmi_vdev_param_gtx_vht_mcs: + ret = intr[vdev_id].config.gtx_info.gtxRTMask[1]; + break; + case wmi_vdev_param_gtx_usr_cfg: + ret = intr[vdev_id].config.gtx_info.gtxUsrcfg; + break; + case wmi_vdev_param_gtx_thre: + ret = intr[vdev_id].config.gtx_info.gtxPERThreshold; + break; + case wmi_vdev_param_gtx_margin: + ret = intr[vdev_id].config.gtx_info.gtxPERMargin; + break; + case wmi_vdev_param_gtx_step: + ret = intr[vdev_id].config.gtx_info.gtxTPCstep; + break; + case wmi_vdev_param_gtx_mintpc: + ret = intr[vdev_id].config.gtx_info.gtxTPCMin; + break; + case wmi_vdev_param_gtx_bw_mask: + ret = intr[vdev_id].config.gtx_info.gtxBWMask; + break; + default: + wma_warn("Invalid generic vdev command/Not yet implemented 0x%x", + param_id); + return -EINVAL; + } + } + return ret; +} + +/** + * wma_cli_set2_command() - WMA "set 2 params" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval1: first parameter value + * @sval2: second parameter value + * @vpdev: parameter category + * + * Command handler for set operations which require 2 parameters + * + * Return: 0 on success, errno on failure + */ +int wma_cli_set2_command(int vdev_id, int param_id, int sval1, + int sval2, int vpdev) +{ + struct scheduler_msg msg = { 0 }; + wma_cli_set_cmd_t *iwcmd; + + iwcmd = qdf_mem_malloc(sizeof(*iwcmd)); + if (!iwcmd) + return -ENOMEM; + + qdf_mem_zero(iwcmd, sizeof(*iwcmd)); + iwcmd->param_value = sval1; + iwcmd->param_sec_value = sval2; + iwcmd->param_vdev_id = vdev_id; + iwcmd->param_id = param_id; + iwcmd->param_vp_dev = vpdev; + msg.type = WMA_CLI_SET_CMD; + msg.reserved = 0; + msg.bodyptr = iwcmd; + + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, &msg)) { + qdf_mem_free(iwcmd); + return -EIO; + } + return 0; +} + +/** + * wma_cli_set_command() - WMA "set" command processor + * @vdev_id: virtual device for the command + * @param_id: parameter id + * @sval: parameter value + * @vpdev: parameter category + * + * Command handler for set operations + * + * Return: 0 on success, errno on failure + */ +int wma_cli_set_command(int vdev_id, int param_id, int sval, int vpdev) +{ + return wma_cli_set2_command(vdev_id, param_id, sval, 0, vpdev); + +} + +QDF_STATUS wma_form_unit_test_cmd_and_send(uint32_t vdev_id, + uint32_t module_id, uint32_t arg_count, uint32_t *arg) +{ + struct wmi_unit_test_cmd *unit_test_args; + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + uint32_t i; + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wma_debug("enter"); + + if (QDF_GLOBAL_FTM_MODE != cds_get_conparam()) { + if (!wma_is_vdev_valid(vdev_id)) + return QDF_STATUS_E_FAILURE; + } + + if (arg_count > WMI_UNIT_TEST_MAX_NUM_ARGS) { + wma_err("arg_count is crossed the boundary"); + return QDF_STATUS_E_FAILURE; + } + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_FAILURE; + + unit_test_args = qdf_mem_malloc(sizeof(*unit_test_args)); + if (!unit_test_args) + return QDF_STATUS_E_NOMEM; + + unit_test_args->vdev_id = vdev_id; + unit_test_args->module_id = module_id; + unit_test_args->num_args = arg_count; + for (i = 0; i < arg_count; i++) + unit_test_args->args[i] = arg[i]; + + status = wmi_unified_unit_test_cmd(wmi_handle, + unit_test_args); + qdf_mem_free(unit_test_args); + wma_debug("exit"); + + return status; +} + +static void wma_process_send_addba_req(tp_wma_handle wma_handle, + struct send_add_ba_req *send_addba) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) { + qdf_mem_free(send_addba); + return; + } + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) { + qdf_mem_free(send_addba); + return; + } + + status = wmi_unified_addba_send_cmd_send(wmi_handle, + send_addba->mac_addr, + &send_addba->param); + if (QDF_STATUS_SUCCESS != status) { + wma_err("Failed to process WMA_SEND_ADDBA_REQ"); + } + wma_debug("sent ADDBA req to" QDF_MAC_ADDR_FMT "tid %d buff_size %d", + QDF_MAC_ADDR_REF(send_addba->mac_addr), + send_addba->param.tidno, + send_addba->param.buffersize); + + qdf_mem_free(send_addba); +} + +/** + * wma_set_priv_cfg() - set private config parameters + * @wma_handle: wma handle + * @privcmd: private command + * + * Return: 0 for success or error code + */ +static int32_t wma_set_priv_cfg(tp_wma_handle wma_handle, + wma_cli_set_cmd_t *privcmd) +{ + int32_t ret = 0; + + switch (privcmd->param_id) { + case WMA_VDEV_TXRX_FWSTATS_ENABLE_CMDID: + ret = wma_set_txrx_fw_stats_level(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMA_VDEV_TXRX_FWSTATS_RESET_CMDID: + ret = wma_txrx_fw_stats_reset(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMI_STA_SMPS_FORCE_MODE_CMDID: + ret = wma_set_mimops(wma_handle, + privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMI_STA_SMPS_PARAM_CMDID: + wma_set_smps_params(wma_handle, privcmd->param_vdev_id, + privcmd->param_value); + break; + case WMA_VDEV_MCC_SET_TIME_LATENCY: + { + /* Extract first MCC adapter/vdev channel number and latency */ + uint8_t mcc_channel = privcmd->param_value & 0x000000FF; + uint8_t mcc_channel_latency = + (privcmd->param_value & 0x0000FF00) >> 8; + int ret = -1; + + wma_debug("Parsed input: Channel #1:%d, latency:%dms", + mcc_channel, mcc_channel_latency); + ret = wma_set_mcc_channel_time_latency(wma_handle, + mcc_channel, + mcc_channel_latency); + } + break; + case WMA_VDEV_MCC_SET_TIME_QUOTA: + { + /* Extract the MCC 2 adapters/vdevs channel numbers and time + * quota value for the first adapter only (which is specified + * in iwpriv command. + */ + uint8_t adapter_2_chan_number = + privcmd->param_value & 0x000000FF; + uint8_t adapter_1_chan_number = + (privcmd->param_value & 0x0000FF00) >> 8; + uint8_t adapter_1_quota = + (privcmd->param_value & 0x00FF0000) >> 16; + int ret = -1; + + wma_debug("Parsed input: Channel #1:%d, Channel #2:%d, quota 1:%dms", + adapter_1_chan_number, + adapter_2_chan_number, adapter_1_quota); + + ret = wma_set_mcc_channel_time_quota(wma_handle, + adapter_1_chan_number, + adapter_1_quota, + adapter_2_chan_number); + } + break; + default: + wma_err("Invalid wma config command id:%d", privcmd->param_id); + ret = -EINVAL; + } + return ret; +} + +/** + * wma_set_dtim_period() - set dtim period to FW + * @wma: wma handle + * @dtim_params: dtim params + * + * Return: none + */ +static void wma_set_dtim_period(tp_wma_handle wma, + struct set_dtim_params *dtim_params) +{ + struct wma_txrx_node *iface = + &wma->interfaces[dtim_params->session_id]; + if (!wma_is_vdev_valid(dtim_params->session_id)) { + wma_err("invalid VDEV"); + return; + } + wma_debug("set dtim_period %d", dtim_params->dtim_period); + iface->dtimPeriod = dtim_params->dtim_period; + +} + +static inline bool wma_is_tx_chainmask_valid(int value, + struct target_psoc_info *tgt_hdl) +{ + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + uint8_t total_mac_phy_cnt, i; + + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return false; + } + + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + for (i = 0; i < total_mac_phy_cnt; i++) { + if (((mac_phy_cap[i].tx_chain_mask_5G) & (value))) { + return true; + } + } + + return false; +} + +/** + * wma_convert_ac_value() - map ac setting to the value to be used in FW. + * @ac_value: ac value to be mapped. + * + * Return: enum wmi_traffic_ac + */ +static inline wmi_traffic_ac wma_convert_ac_value(uint32_t ac_value) +{ + switch (ac_value) { + case QCA_WLAN_AC_BE: + return WMI_AC_BE; + case QCA_WLAN_AC_BK: + return WMI_AC_BK; + case QCA_WLAN_AC_VI: + return WMI_AC_VI; + case QCA_WLAN_AC_VO: + return WMI_AC_VO; + case QCA_WLAN_AC_ALL: + return WMI_AC_MAX; + } + wma_err("invalid enum: %u", ac_value); + return WMI_AC_MAX; +} + +#ifdef WLAN_FEATURE_11BE +/** + * wma_set_per_link_amsdu_cap() - Set AMSDU/AMPDU capability per link to FW. + * @wma: wma handle + * @privcmd: pointer to set command parameters + * @aggr_type: aggregration type + * + * Return: QDF_STATUS_SUCCESS if set command is sent successfully, else + * QDF_STATUS_E_FAILURE + */ +static QDF_STATUS +wma_set_per_link_amsdu_cap(tp_wma_handle wma, wma_cli_set_cmd_t *privcmd, + wmi_vdev_custom_aggr_type_t aggr_type) +{ + uint8_t vdev_id; + uint8_t op_mode; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + + for (vdev_id = 0; vdev_id < WLAN_MAX_VDEVS; vdev_id++) { + op_mode = wlan_get_opmode_from_vdev_id(wma->pdev, vdev_id); + if (op_mode == QDF_STA_MODE) { + ret = wma_set_tx_rx_aggr_size(vdev_id, + privcmd->param_value, + privcmd->param_value, + aggr_type); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("set_aggr_size failed for vdev: %d, ret %d", + vdev_id, ret); + return ret; + } + } + } + + return ret; +} +#else +static inline QDF_STATUS +wma_set_per_link_amsdu_cap(tp_wma_handle wma, wma_cli_set_cmd_t *privcmd, + wmi_vdev_custom_aggr_type_t aggr_type) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_process_cli_set_cmd() - set parameters to fw + * @wma: wma handle + * @privcmd: command + * + * Return: none + */ +static void wma_process_cli_set_cmd(tp_wma_handle wma, + wma_cli_set_cmd_t *privcmd) +{ + int vid = privcmd->param_vdev_id, pps_val = 0; + QDF_STATUS ret; + struct wma_txrx_node *intr = wma->interfaces; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct qpower_params *qparams = &intr[vid].config.qpower_params; + struct pdev_params pdev_param = {0}; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct target_psoc_info *tgt_hdl; + enum wlan_eht_mode eht_mode; + + if (!mac) { + wma_err("Failed to get mac"); + return; + } + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return; + } + + if (privcmd->param_id >= WMI_CMDID_MAX) { + /* + * This configuration setting is not done using any wmi + * command, call appropriate handler. + */ + if (wma_set_priv_cfg(wma, privcmd)) + wma_err("Failed to set wma priv configuration"); + return; + } + + switch (privcmd->param_vp_dev) { + case VDEV_CMD: + if (!wma_is_vdev_valid(privcmd->param_vdev_id)) { + wma_err("Vdev id is not valid"); + return; + } + + wma_debug("vdev id %d pid %d pval %d", privcmd->param_vdev_id, + privcmd->param_id, privcmd->param_value); + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + privcmd->param_id, + privcmd->param_value); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("wma_vdev_set_param failed ret %d", ret); + return; + } + break; + case PDEV_CMD: + wma_debug("pdev pid %d pval %d", privcmd->param_id, + privcmd->param_value); + if ((privcmd->param_id == wmi_pdev_param_rx_chain_mask) || + (privcmd->param_id == wmi_pdev_param_tx_chain_mask)) { + if (QDF_STATUS_SUCCESS != + wma_check_txrx_chainmask( + target_if_get_num_rf_chains(tgt_hdl), + privcmd->param_value)) { + wma_debug("Chainmask value is invalid"); + return; + } + } + + if (privcmd->param_id == wmi_pdev_param_tx_chain_mask) { + if (!wma_is_tx_chainmask_valid(privcmd->param_value, + tgt_hdl)) { + wma_debug("Chainmask value is invalid"); + return; + } + } + pdev_param.param_id = privcmd->param_id; + pdev_param.param_value = privcmd->param_value; + if (privcmd->param_id == wmi_pdev_param_twt_ac_config) + pdev_param.param_value = + wma_convert_ac_value(pdev_param.param_value); + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdev_param, + privcmd->param_sec_value); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("wma_vdev_set_param failed ret %d", ret); + return; + } + break; + case GEN_CMD: + { + struct wma_txrx_node *intr = wma->interfaces; + wmi_vdev_custom_aggr_type_t aggr_type = + WMI_VDEV_CUSTOM_AGGR_TYPE_AMSDU; + + wma_debug("gen pid %d pval %d", privcmd->param_id, + privcmd->param_value); + + switch (privcmd->param_id) { + case GEN_VDEV_PARAM_AMSDU: + case GEN_VDEV_PARAM_AMPDU: + if (!soc) { + wma_err("SOC context is NULL"); + return; + } + + if (privcmd->param_id == GEN_VDEV_PARAM_AMPDU) { + ret = cdp_aggr_cfg(soc, privcmd->param_vdev_id, + privcmd->param_value, 0); + if (ret) + wma_err("cdp_aggr_cfg set ampdu failed ret %d", + ret); + else + intr[privcmd->param_vdev_id].config. + ampdu = privcmd->param_value; + + aggr_type = + WMI_VDEV_CUSTOM_AGGR_TYPE_AMPDU; + } + + wlan_mlme_get_eht_mode(wma->psoc, &eht_mode); + if (eht_mode == WLAN_EHT_MODE_MLSR || + eht_mode == WLAN_EHT_MODE_MLMR) { + ret = wma_set_per_link_amsdu_cap(wma, privcmd, + aggr_type); + if (QDF_IS_STATUS_ERROR(ret)) + return; + } else { + ret = wma_set_tx_rx_aggr_size( + vid, + privcmd->param_value, + privcmd->param_value, + aggr_type); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("set_aggr_size failed ret %d", + ret); + return; + } + } + break; + case GEN_PARAM_CRASH_INJECT: + if (QDF_GLOBAL_FTM_MODE == cds_get_conparam()) + wma_err("Crash inject not allowed in FTM mode"); + else + ret = wma_crash_inject(wma, + privcmd->param_value, + privcmd->param_sec_value); + break; + case GEN_PARAM_CAPTURE_TSF: + ret = wma_capture_tsf(wma, privcmd->param_value); + break; + case GEN_PARAM_RESET_TSF_GPIO: + ret = wma_reset_tsf_gpio(wma, privcmd->param_value); + break; + default: + ret = wma_set_tsf_auto_report(wma, + privcmd->param_vdev_id, + privcmd->param_id, + privcmd->param_value); + if (ret == QDF_STATUS_E_FAILURE) + wma_err("Invalid param id 0x%x", + privcmd->param_id); + break; + } + break; + } + case DBG_CMD: + wma_debug("dbg pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + case WMI_DBGLOG_LOG_LEVEL: + ret = dbglog_set_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + wma_err("dbglog_set_log_lvl failed ret %d", + ret); + break; + case WMI_DBGLOG_VAP_ENABLE: + ret = dbglog_vap_log_enable(wma->wmi_handle, + privcmd->param_value, true); + if (ret) + wma_err("dbglog_vap_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_VAP_DISABLE: + ret = dbglog_vap_log_enable(wma->wmi_handle, + privcmd->param_value, false); + if (ret) + wma_err("dbglog_vap_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MODULE_ENABLE: + ret = dbglog_module_log_enable(wma->wmi_handle, + privcmd->param_value, true); + if (ret) + wma_err("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MODULE_DISABLE: + ret = dbglog_module_log_enable(wma->wmi_handle, + privcmd->param_value, false); + if (ret) + wma_err("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MOD_LOG_LEVEL: + ret = dbglog_set_mod_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + wma_err("dbglog_module_log_enable failed ret %d", + ret); + break; + case WMI_DBGLOG_MOD_WOW_LOG_LEVEL: + ret = dbglog_set_mod_wow_log_lvl(wma->wmi_handle, + privcmd->param_value); + if (ret) + wma_err("WMI_DBGLOG_MOD_WOW_LOG_LEVEL failed ret %d", + ret); + break; + case WMI_DBGLOG_TYPE: + ret = dbglog_parser_type_init(wma->wmi_handle, + privcmd->param_value); + if (ret) + wma_err("dbglog_parser_type_init failed ret %d", + ret); + break; + case WMI_DBGLOG_REPORT_ENABLE: + ret = dbglog_report_enable(wma->wmi_handle, + privcmd->param_value); + if (ret) + wma_err("dbglog_report_enable failed ret %d", + ret); + break; + case WMI_WLAN_PROFILE_TRIGGER_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_TRIGGER_CMDID, + privcmd->param_value, 0); + if (ret) + wma_err("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_TRIGGER_CMDID, ret); + break; + case WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + privcmd->param_value, + privcmd->param_sec_value); + if (ret) + wma_err("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + ret); + break; + case WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + privcmd->param_value, + privcmd->param_sec_value); + if (ret) + wma_err("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + ret); + break; + case WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + 0, 0); + if (ret) + wma_err("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + ret); + break; + case WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID: + ret = wma_unified_fw_profiling_cmd(wma->wmi_handle, + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + 0, 0); + if (ret) + wma_err("Profile cmd failed for %d ret %d", + WMI_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + ret); + break; + case WMI_PDEV_GREEN_AP_PS_ENABLE_CMDID: + /* Set the Green AP */ + ret = wmi_unified_green_ap_ps_send + (wma->wmi_handle, privcmd->param_value, + WMA_WILDCARD_PDEV_ID); + if (ret) { + wma_err("Set GreenAP Failed val %d", + privcmd->param_value); + } + break; + + default: + wma_err("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case PPS_CMD: + wma_debug("dbg pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + + case WMI_VDEV_PPS_PAID_MATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_PAID_MATCH & 0xffff); + intr[vid].config.pps_params.paid_match_enable = + privcmd->param_value; + break; + case WMI_VDEV_PPS_GID_MATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_MATCH & 0xffff); + intr[vid].config.pps_params.gid_match_enable = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EARLY_TIM_CLEAR: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff); + intr[vid].config.pps_params.tim_clear = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EARLY_DTIM_CLEAR: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff); + intr[vid].config.pps_params.dtim_clear = + privcmd->param_value; + break; + case WMI_VDEV_PPS_EOF_PAD_DELIM: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff); + intr[vid].config.pps_params.eof_delim = + privcmd->param_value; + break; + case WMI_VDEV_PPS_MACADDR_MISMATCH: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff); + intr[vid].config.pps_params.mac_match = + privcmd->param_value; + break; + case WMI_VDEV_PPS_DELIM_CRC_FAIL: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff); + intr[vid].config.pps_params.delim_fail = + privcmd->param_value; + break; + case WMI_VDEV_PPS_GID_NSTS_ZERO: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff); + intr[vid].config.pps_params.nsts_zero = + privcmd->param_value; + break; + case WMI_VDEV_PPS_RSSI_CHECK: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_RSSI_CHECK & 0xffff); + intr[vid].config.pps_params.rssi_chk = + privcmd->param_value; + break; + case WMI_VDEV_PPS_5G_EBT: + pps_val = ((privcmd->param_value << 31) & 0xffff0000) | + (PKT_PWR_SAVE_5G_EBT & 0xffff); + intr[vid].config.pps_params.ebt_5g = + privcmd->param_value; + break; + default: + wma_err("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + + case QPOWER_CMD: + wma_debug("QPOWER CLI CMD pid %d pval %d", privcmd->param_id, + privcmd->param_value); + switch (privcmd->param_id) { + case WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT: + wma_debug("QPOWER CLI CMD:Ps Poll Cnt val %d", + privcmd->param_value); + /* Set the QPower Ps Poll Count */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_PSPOLL_COUNT, + privcmd->param_value); + if (ret) { + wma_err("Set Q-PsPollCnt Failed vdevId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_ps_poll_cnt = privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE: + wma_debug("QPOWER CLI CMD:Max Tx Before wake val %d", + privcmd->param_value); + /* Set the QPower Max Tx Before Wake */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, + vid, WMI_STA_PS_PARAM_QPOWER_MAX_TX_BEFORE_WAKE, + privcmd->param_value); + if (ret) { + wma_err("Set Q-MaxTxBefWake Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_tx_before_wake = + privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL: + wma_debug("QPOWER CLI CMD:Ps Poll Wake Inv val %d", + privcmd->param_value); + /* Set the QPower Spec Ps Poll Wake Inv */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vid, + WMI_STA_PS_PARAM_QPOWER_SPEC_PSPOLL_WAKE_INTERVAL, + privcmd->param_value); + if (ret) { + wma_err("Set Q-PsPoll WakeIntv Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->spec_ps_poll_wake_interval = + privcmd->param_value; + } + break; + case WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL: + wma_debug("QPOWER CLI CMD:Spec NoData Ps Poll val %d", + privcmd->param_value); + /* Set the QPower Spec NoData PsPoll */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vid, + WMI_STA_PS_PARAM_QPOWER_SPEC_MAX_SPEC_NODATA_PSPOLL, + privcmd->param_value); + if (ret) { + wma_err("Set Q-SpecNoDataPsPoll Failed vId %d val %d", + vid, privcmd->param_value); + } else { + qparams->max_spec_nodata_ps_poll = + privcmd->param_value; + } + break; + + default: + wma_err("Invalid param id 0x%x", privcmd->param_id); + break; + } + break; + case GTX_CMD: + wma_debug("vdev id %d pid %d pval %d", privcmd->param_vdev_id, + privcmd->param_id, privcmd->param_value); + switch (privcmd->param_id) { + case wmi_vdev_param_gtx_ht_mcs: + intr[vid].config.gtx_info.gtxRTMask[0] = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + case wmi_vdev_param_gtx_vht_mcs: + intr[vid].config.gtx_info.gtxRTMask[1] = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case wmi_vdev_param_gtx_usr_cfg: + intr[vid].config.gtx_info.gtxUsrcfg = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case wmi_vdev_param_gtx_thre: + intr[vid].config.gtx_info.gtxPERThreshold = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case wmi_vdev_param_gtx_margin: + intr[vid].config.gtx_info.gtxPERMargin = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case wmi_vdev_param_gtx_step: + intr[vid].config.gtx_info.gtxTPCstep = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case wmi_vdev_param_gtx_mintpc: + intr[vid].config.gtx_info.gtxTPCMin = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + break; + + case wmi_vdev_param_gtx_bw_mask: + intr[vid].config.gtx_info.gtxBWMask = + privcmd->param_value; + ret = wmi_unified_vdev_set_gtx_cfg_send(wma->wmi_handle, + privcmd->param_vdev_id, + &intr[vid].config.gtx_info); + if (ret) { + wma_err("wma_vdev_set_param failed ret %d", + ret); + return; + } + break; + default: + break; + } + break; + + default: + wma_err("Invalid vpdev command id"); + } + if (1 == privcmd->param_vp_dev) { + switch (privcmd->param_id) { + case wmi_vdev_param_nss: + intr[vid].config.nss = privcmd->param_value; + break; + case wmi_vdev_param_ldpc: + intr[vid].config.ldpc = privcmd->param_value; + break; + case wmi_vdev_param_tx_stbc: + intr[vid].config.tx_stbc = privcmd->param_value; + break; + case wmi_vdev_param_rx_stbc: + intr[vid].config.rx_stbc = privcmd->param_value; + break; + case wmi_vdev_param_sgi: + intr[vid].config.shortgi = privcmd->param_value; + break; + case wmi_vdev_param_enable_rtscts: + intr[vid].config.rtscts_en = privcmd->param_value; + break; + case wmi_vdev_param_chwidth: + intr[vid].config.chwidth = privcmd->param_value; + break; + case wmi_vdev_param_fixed_rate: + intr[vid].config.tx_rate = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_adjust_enable: + intr[vid].config.erx_adjust = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_tgt_bmiss_num: + intr[vid].config.erx_bmiss_num = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_bmiss_sample_cycle: + intr[vid].config.erx_bmiss_cycle = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_slop_step: + intr[vid].config.erx_slop_step = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_init_slop: + intr[vid].config.erx_init_slop = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_adjust_pause: + intr[vid].config.erx_adj_pause = privcmd->param_value; + break; + case wmi_vdev_param_early_rx_drift_sample: + intr[vid].config.erx_dri_sample = privcmd->param_value; + break; + case wmi_vdev_param_he_dcm_enable: + case wmi_vdev_param_he_range_ext: + wma_set_he_vdev_param(&intr[vid], privcmd->param_id, + privcmd->param_value); + break; + default: + wma_debug("vdev cmd is not part vdev_cli_config 0x%x", + privcmd->param_id); + break; + } + } else if (2 == privcmd->param_vp_dev) { + switch (privcmd->param_id) { + case wmi_pdev_param_ani_enable: + wma->pdevconfig.ani_enable = privcmd->param_value; + break; + case wmi_pdev_param_ani_poll_period: + wma->pdevconfig.ani_poll_len = privcmd->param_value; + break; + case wmi_pdev_param_ani_listen_period: + wma->pdevconfig.ani_listen_len = privcmd->param_value; + break; + case wmi_pdev_param_ani_ofdm_level: + wma->pdevconfig.ani_ofdm_level = privcmd->param_value; + break; + case wmi_pdev_param_ani_cck_level: + wma->pdevconfig.ani_cck_level = privcmd->param_value; + break; + case wmi_pdev_param_dynamic_bw: + wma->pdevconfig.cwmenable = privcmd->param_value; + break; + case wmi_pdev_param_cts_cbw: + wma->pdevconfig.cts_cbw = privcmd->param_value; + break; + case wmi_pdev_param_tx_chain_mask: + wma->pdevconfig.txchainmask = privcmd->param_value; + break; + case wmi_pdev_param_rx_chain_mask: + wma->pdevconfig.rxchainmask = privcmd->param_value; + break; + case wmi_pdev_param_txpower_limit2g: + wma->pdevconfig.txpow2g = privcmd->param_value; + if (mac->mlme_cfg->gen.band_capability & BIT(REG_BAND_2G)) + mac->mlme_cfg->power.current_tx_power_level = + (uint8_t)privcmd->param_value; + else + wma_err("Current band is not 2G"); + break; + case wmi_pdev_param_txpower_limit5g: + wma->pdevconfig.txpow5g = privcmd->param_value; + if (mac->mlme_cfg->gen.band_capability & BIT(REG_BAND_5G)) + mac->mlme_cfg->power.current_tx_power_level = + (uint8_t)privcmd->param_value; + else + wma_err("Current band is not 5G"); + break; + default: + wma_debug("Invalid wma_cli_set pdev command/Not yet implemented 0x%x", + privcmd->param_id); + break; + } + } else if (5 == privcmd->param_vp_dev) { + ret = wma_vdev_set_param(wma->wmi_handle, + privcmd->param_vdev_id, + wmi_vdev_param_packet_powersave, + pps_val); + if (ret) + wma_err("Failed to send wmi packet power save cmd"); + else + wma_debug("Sent packet power save cmd %d value %x to target", + privcmd->param_id, pps_val); + } +} + +uint32_t wma_critical_events_in_flight(void) +{ + t_wma_handle *wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return 0; + + if (wmi_validate_handle(wma->wmi_handle)) + return 0; + + return wmi_critical_events_in_flight(wma->wmi_handle); +} + +/** + * wma_process_hal_pwr_dbg_cmd() - send hal pwr dbg cmd to fw. + * @handle: wma handle + * @sir_pwr_dbg_params: unit test command + * + * This function send unit test command to fw. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wma_process_hal_pwr_dbg_cmd(WMA_HANDLE handle, + struct sir_mac_pwr_dbg_cmd * + sir_pwr_dbg_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + int i; + struct wmi_power_dbg_params wmi_pwr_dbg_params; + QDF_STATUS status; + + if (!sir_pwr_dbg_params) { + wma_err("sir_pwr_dbg_params is null"); + return QDF_STATUS_E_INVAL; + } + wmi_pwr_dbg_params.module_id = sir_pwr_dbg_params->module_id; + wmi_pwr_dbg_params.pdev_id = sir_pwr_dbg_params->pdev_id; + wmi_pwr_dbg_params.num_args = sir_pwr_dbg_params->num_args; + + for (i = 0; i < wmi_pwr_dbg_params.num_args; i++) + wmi_pwr_dbg_params.args[i] = sir_pwr_dbg_params->args[i]; + + status = wmi_unified_send_power_dbg_cmd(wma_handle->wmi_handle, + &wmi_pwr_dbg_params); + + return status; +} + +static QDF_STATUS wma_discard_fw_event(struct scheduler_msg *msg) +{ + if (!msg->bodyptr) + return QDF_STATUS_E_INVAL; + + qdf_mem_free(msg->bodyptr); + msg->bodyptr = NULL; + msg->bodyval = 0; + msg->type = 0; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_vdev_nss_chain_params_send(uint8_t vdev_id, + struct wlan_mlme_nss_chains *user_cfg) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct vdev_nss_chains vdev_user_cfg; + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + vdev_user_cfg.disable_rx_mrc[NSS_CHAINS_BAND_2GHZ] = + user_cfg->disable_rx_mrc[NSS_CHAINS_BAND_2GHZ]; + vdev_user_cfg.disable_tx_mrc[NSS_CHAINS_BAND_2GHZ] = + user_cfg->disable_tx_mrc[NSS_CHAINS_BAND_2GHZ]; + vdev_user_cfg.disable_rx_mrc[NSS_CHAINS_BAND_5GHZ] = + user_cfg->disable_rx_mrc[NSS_CHAINS_BAND_5GHZ]; + vdev_user_cfg.disable_tx_mrc[NSS_CHAINS_BAND_5GHZ] = + user_cfg->disable_tx_mrc[NSS_CHAINS_BAND_5GHZ]; + + vdev_user_cfg.num_rx_chains[NSS_CHAINS_BAND_2GHZ] + = user_cfg->num_rx_chains[NSS_CHAINS_BAND_2GHZ]; + vdev_user_cfg.num_tx_chains[NSS_CHAINS_BAND_2GHZ] + = user_cfg->num_tx_chains[NSS_CHAINS_BAND_2GHZ]; + vdev_user_cfg.num_rx_chains[NSS_CHAINS_BAND_5GHZ] = + user_cfg->num_rx_chains[NSS_CHAINS_BAND_5GHZ]; + vdev_user_cfg.num_tx_chains[NSS_CHAINS_BAND_5GHZ] = + user_cfg->num_tx_chains[NSS_CHAINS_BAND_5GHZ]; + + vdev_user_cfg.rx_nss[NSS_CHAINS_BAND_2GHZ] = + user_cfg->rx_nss[NSS_CHAINS_BAND_2GHZ]; + vdev_user_cfg.tx_nss[NSS_CHAINS_BAND_2GHZ] = + user_cfg->tx_nss[NSS_CHAINS_BAND_2GHZ]; + vdev_user_cfg.rx_nss[NSS_CHAINS_BAND_5GHZ] = + user_cfg->rx_nss[NSS_CHAINS_BAND_5GHZ]; + vdev_user_cfg.tx_nss[NSS_CHAINS_BAND_5GHZ] = + user_cfg->tx_nss[NSS_CHAINS_BAND_5GHZ]; + + vdev_user_cfg.num_tx_chains_11a = user_cfg->num_tx_chains_11a; + vdev_user_cfg.num_tx_chains_11b = user_cfg->num_tx_chains_11b; + vdev_user_cfg.num_tx_chains_11g = user_cfg->num_tx_chains_11g; + + return wmi_unified_vdev_nss_chain_params_send(wma_handle->wmi_handle, + vdev_id, + &vdev_user_cfg); +} + +/** + * wma_antenna_isolation_event_handler() - antenna isolation event handler + * @handle: wma handle + * @param: event data + * @len: length + * + * Return: 0 for success or error code + */ +static int wma_antenna_isolation_event_handler(void *handle, + u8 *param, + u32 len) +{ + struct scheduler_msg cds_msg = {0}; + wmi_coex_report_isolation_event_fixed_param *event; + WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID_param_tlvs *param_buf; + struct sir_isolation_resp *pisolation; + struct mac_context *mac = NULL; + + wma_debug("handle %pK param %pK len %d", handle, param, len); + + mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + wma_err("Invalid mac context"); + return -EINVAL; + } + + pisolation = qdf_mem_malloc(sizeof(*pisolation)); + if (!pisolation) + return 0; + + param_buf = + (WMI_COEX_REPORT_ANTENNA_ISOLATION_EVENTID_param_tlvs *)param; + if (!param_buf) { + wma_err("Invalid isolation event"); + return -EINVAL; + } + event = param_buf->fixed_param; + pisolation->isolation_chain0 = event->isolation_chain0; + pisolation->isolation_chain1 = event->isolation_chain1; + pisolation->isolation_chain2 = event->isolation_chain2; + pisolation->isolation_chain3 = event->isolation_chain3; + + wma_debug("chain1 %d chain2 %d chain3 %d chain4 %d", + pisolation->isolation_chain0, pisolation->isolation_chain1, + pisolation->isolation_chain2, pisolation->isolation_chain3); + + cds_msg.type = eWNI_SME_ANTENNA_ISOLATION_RSP; + cds_msg.bodyptr = pisolation; + cds_msg.bodyval = 0; + if (QDF_STATUS_SUCCESS != + scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &cds_msg)) { + wma_err("could not post peer info rsp msg to SME"); + /* free the mem and return */ + qdf_mem_free(pisolation); + } + + return 0; +} + +/** + * wma_init_max_no_of_peers - API to initialize wma configuration params + * @wma_handle: WMA Handle + * @max_peers: Max Peers supported + * + * Return: void + */ +static uint8_t wma_init_max_no_of_peers(tp_wma_handle wma_handle, + uint16_t max_peers) +{ + struct wma_ini_config *cfg = wma_get_ini_handle(wma_handle); + struct hif_opaque_softc *scn = cds_get_context(QDF_MODULE_ID_HIF); + uint32_t tgt_version = hif_get_target_info_handle(scn)->target_version; + uint8_t max_no_of_peers; + uint8_t max_supported_peers; + + if (!cfg) { + wma_err("NULL WMA ini handle"); + return 0; + } + + switch (tgt_version) { + case AR6320_REV1_1_VERSION: + max_supported_peers = MAX_SUPPORTED_PEERS_REV1_1; + break; + case AR6320_REV1_3_VERSION: + max_supported_peers = MAX_SUPPORTED_PEERS_REV1_3; + break; + default: + max_supported_peers = MAX_SUPPORTED_PEERS; + break; + } + max_no_of_peers = (max_peers > max_supported_peers) ? + max_supported_peers : max_peers; + cfg->max_no_of_peers = max_no_of_peers; + + return max_no_of_peers; +} + +/** + * wma_cleanup_hold_req() - cleanup hold request queue + * @wma: wma handle + * + * Return: none + */ +static void wma_cleanup_hold_req(tp_wma_handle wma) +{ + struct wma_target_req *req_msg = NULL; + qdf_list_node_t *node1 = NULL; + + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + if (!qdf_list_size(&wma->wma_hold_req_queue)) { + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + wma_debug("request queue is empty"); + return; + } + + /* peek front, and then cleanup it in wma_hold_req_timer */ + while (QDF_STATUS_SUCCESS == + qdf_list_peek_front(&wma->wma_hold_req_queue, &node1)) { + req_msg = qdf_container_of(node1, struct wma_target_req, node); + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); + /* Cleanup timeout handler */ + qdf_mc_timer_stop(&req_msg->event_timeout); + wma_hold_req_timer(req_msg); + qdf_spin_lock_bh(&wma->wma_hold_req_q_lock); + } + qdf_spin_unlock_bh(&wma->wma_hold_req_q_lock); +} + +/** + * wma_cleanup_vdev_resp_and_hold_req() - cleaunup the vdev resp and hold req + * queue + * @msg :scheduler msg + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_cleanup_vdev_resp_and_hold_req(struct scheduler_msg *msg) +{ + tp_wma_handle wma; + + if (!msg || !msg->bodyptr) { + wma_err("msg or body pointer is NULL"); + return QDF_STATUS_E_INVAL; + } + + wma = msg->bodyptr; + target_if_flush_psoc_vdev_timers(wma->psoc); + wma_cleanup_hold_req(wma); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_cleanup_vdev_resp_and_hold_req_flush_cb() - flush cb for the msg to clean + * up vdev resp and hold req + * @msg :scheduler msg + * + * As passed msg->bodyptr is wma in this case this is dummy flush cb so that + * driver doesn't try to free msg->bodyptr when this msg is flushed. + * + * Return: QDF_STATUS + */ +static inline QDF_STATUS +wma_cleanup_vdev_resp_and_hold_req_flush_cb(struct scheduler_msg *msg) +{ + return QDF_STATUS_SUCCESS; +} + +/** + * wma_shutdown_notifier_cb - Shutdown notifier call back + * @priv : WMA handle + * + * During recovery, WMA may wait for resume to complete if the crash happens + * while in suspend. This may cause delays in completing the recovery. This call + * back would be called during recovery and the event is completed so that if + * the resume is waiting on FW to respond then it can get out of the wait so + * that recovery thread can start bringing down all the modules. + * + * Return: None + */ +static void wma_shutdown_notifier_cb(void *priv) +{ + tp_wma_handle wma_handle = priv; + struct scheduler_msg msg = { 0 }; + QDF_STATUS status; + + ucfg_pmo_psoc_wakeup_host_event_received(wma_handle->psoc); + wmi_stop(wma_handle->wmi_handle); + + msg.bodyptr = wma_handle; + msg.callback = wma_cleanup_vdev_resp_and_hold_req; + msg.flush_callback = wma_cleanup_vdev_resp_and_hold_req_flush_cb; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_WMA, + QDF_MODULE_ID_TARGET_IF, &msg); +} + +struct wma_version_info g_wmi_version_info; + +#ifdef WLAN_FEATURE_MEMDUMP_ENABLE +/** + * wma_state_info_dump() - prints state information of wma layer + * @buf_ptr: buffer pointer + * @size: size of buffer to be filled + * + * This function is used to dump state information of wma layer + * + * Return: None + */ +static void wma_state_info_dump(char **buf_ptr, uint16_t *size) +{ + uint8_t vdev_id; + uint16_t len = 0; + t_wma_handle *wma; + char *buf = *buf_ptr; + struct wma_txrx_node *iface; + struct wake_lock_stats stats; + struct wlan_objmgr_vdev *vdev; + uint32_t rate_flag; + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + wma_debug("size of buffer: %d", *size); + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + iface = &wma->interfaces[vdev_id]; + vdev = iface->vdev; + if (!vdev) + continue; + + status = wma_get_vdev_rate_flag(iface->vdev, &rate_flag); + if (QDF_IS_STATUS_ERROR(status)) + continue; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, + vdev_id, WLAN_LEGACY_WMA_ID); + if (!vdev) + continue; + ucfg_mc_cp_stats_get_vdev_wake_lock_stats(vdev, &stats); + len += qdf_scnprintf(buf + len, *size - len, + "\n" + "vdev_id %d\n" + "WoW Stats\n" + "\tpno_match %u\n" + "\tpno_complete %u\n" + "\tgscan %u\n" + "\tlow_rssi %u\n" + "\trssi_breach %u\n" + "\tucast %u\n" + "\tbcast %u\n" + "\ticmpv4 %u\n" + "\ticmpv6 %u\n" + "\tipv4_mcast %u\n" + "\tipv6_mcast %u\n" + "\tipv6_mcast_ra %u\n" + "\tipv6_mcast_ns %u\n" + "\tipv6_mcast_na %u\n" + "\toem_response %u\n" + "\tuc_drop %u\n" + "\tfatal_event %u\n" + "dtimPeriod %d\n" + "chan_width %d\n" + "vdev_active %d\n" + "vdev_up %d\n" + "aid %d\n" + "rate_flags %d\n" + "nss %d\n" + "nwType %d\n" + "tx_streams %d", + vdev_id, + stats.pno_match_wake_up_count, + stats.pno_complete_wake_up_count, + stats.gscan_wake_up_count, + stats.low_rssi_wake_up_count, + stats.rssi_breach_wake_up_count, + stats.ucast_wake_up_count, + stats.bcast_wake_up_count, + stats.icmpv4_count, + stats.icmpv6_count, + stats.ipv4_mcast_wake_up_count, + stats.ipv6_mcast_wake_up_count, + stats.ipv6_mcast_ra_stats, + stats.ipv6_mcast_ns_stats, + stats.ipv6_mcast_na_stats, + stats.oem_response_wake_up_count, + stats.uc_drop_wake_up_count, + stats.fatal_event_wake_up_count, + iface->dtimPeriod, + iface->chan_width, + iface->vdev_active, + wma_is_vdev_up(vdev_id), + iface->aid, + rate_flag, + iface->nss, + iface->nwType, + iface->tx_streams); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + } + + *size -= len; + *buf_ptr += len; +} + +/** + * wma_register_debug_callback() - registration function for wma layer + * to print wma state information + */ +static void wma_register_debug_callback(void) +{ + qdf_register_debug_callback(QDF_MODULE_ID_WMA, &wma_state_info_dump); +} +#else /* WLAN_FEATURE_MEMDUMP_ENABLE */ +static void wma_register_debug_callback(void) +{ +} +#endif /* WLAN_FEATURE_MEMDUMP_ENABLE */ +/** + * wma_register_tx_ops_handler() - register tx_ops of southbound + * @tx_ops: tx_ops pointer in southbound + * + * Return: 0 on success, errno on failure + */ +static QDF_STATUS +wma_register_tx_ops_handler(struct wlan_lmac_if_tx_ops *tx_ops) +{ + /* + * Assign tx_ops, it's up to UMAC modules to declare and define these + * functions which are used to send wmi command to target. + */ + + if (!tx_ops) { + wma_err("pointer to lmac if tx ops is NULL"); + return QDF_STATUS_E_INVAL; + } + + /* mgmt_txrx component's tx ops */ + tx_ops->mgmt_txrx_tx_ops.mgmt_tx_send = wma_mgmt_unified_cmd_send; + + /* mgmt txrx component nbuf op for nbuf dma unmap */ + tx_ops->mgmt_txrx_tx_ops.tx_drain_nbuf_op = wma_mgmt_nbuf_unmap_cb; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_target_if_open() - Attach UMAC modules' interface with wmi layer + * @wma_handle: wma handle + * + * Separate module defines below functions: + * 1. tgt_wmi__ api sends wmi command, assigned to south bound + * tx_ops function pointers; + * 2. module's south dispatcher handles information from lower layer, assigned + * to south bound rx_ops function pointers; + * 3. wmi event handler deals with wmi event, extracts umac needed information, + * and call rx_ops(module's dispatcher). It executes in tasklet context and + * is up to dispatcher to decide the context to reside in tasklet or in + * thread context. + * + * Return: None + */ +static void wma_target_if_open(tp_wma_handle wma_handle) +{ + struct wlan_objmgr_psoc *psoc = wma_handle->psoc; + + if (!psoc) + return; + + wlan_global_lmac_if_set_txops_registration_cb(WLAN_DEV_OL, + target_if_register_tx_ops); + wlan_lmac_if_set_umac_txops_registration_cb( + wma_register_tx_ops_handler); + wlan_global_lmac_if_open(psoc); + +} + +/** + * wma_legacy_service_ready_event_handler() - legacy (ext)service ready handler + * @event_id: event_id + * @handle: wma handle + * @event_data: event data + * @length: event length + * + * Return: 0 for success, negative error code for failure + */ +static int wma_legacy_service_ready_event_handler(uint32_t event_id, + void *handle, + uint8_t *event_data, + uint32_t length) +{ + switch (event_id) { + case wmi_service_ready_event_id: + return wma_rx_service_ready_event(handle, event_data, length); + case wmi_service_ready_ext_event_id: + return wma_rx_service_ready_ext_event(handle, event_data, + length); + case wmi_ready_event_id: + return wma_rx_ready_event(handle, event_data, length); + case wmi_service_ready_ext2_event_id: + return wma_rx_service_ready_ext2_event(handle, event_data, + length); + default: + wma_err("Legacy callback invoked with invalid event_id:%d", + event_id); + QDF_BUG(0); + } + + return 0; +} + +#ifdef WLAN_FEATURE_CAL_FAILURE_TRIGGER +/** + * wma_process_cal_fail_info() - Process cal failure event and + * send it to userspace + * @wmi_event: Cal failure event data + */ +static void wma_process_cal_fail_info(uint8_t *wmi_event) +{ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + uint8_t *buf_ptr; + wmi_debug_mesg_fw_cal_failure_param *cal_failure_event; + + if (!mac) { + wma_err("Invalid mac context"); + return; + } + + if (!mac->cal_failure_event_cb) { + wma_err("Callback not registered for cal failure event"); + return; + } + + buf_ptr = wmi_event; + buf_ptr = buf_ptr + sizeof(wmi_debug_mesg_flush_complete_fixed_param) + + WMI_TLV_HDR_SIZE + + sizeof(wmi_debug_mesg_fw_data_stall_param) + WMI_TLV_HDR_SIZE; + + cal_failure_event = (wmi_debug_mesg_fw_cal_failure_param *)buf_ptr; + + if (((cal_failure_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_debug_mesg_fw_cal_failure_param)) { + /** + * Log calibration failure information received from FW + */ + wma_debug("Calibration failure event:"); + wma_debug("calType: %x calFailureReasonCode: %x", + cal_failure_event->cal_type, + cal_failure_event->cal_failure_reason_code); + mac->cal_failure_event_cb( + cal_failure_event->cal_type, + cal_failure_event->cal_failure_reason_code); + } else { + wma_err("Invalid TLV header in cal failure event"); + } +} +#else +static inline void wma_process_cal_fail_info(uint8_t *wmi_event) +{ +} +#endif + +/** + * wma_flush_complete_evt_handler() - FW log flush complete event handler + * @handle: WMI handle + * @event: Event received from FW + * @len: Length of the event + * + */ +static int wma_flush_complete_evt_handler(void *handle, + u_int8_t *event, + u_int32_t len) +{ + QDF_STATUS status; + tp_wma_handle wma = (tp_wma_handle) handle; + + WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *param_buf; + wmi_debug_mesg_flush_complete_fixed_param *wmi_event; + wmi_debug_mesg_fw_data_stall_param *data_stall_event; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t *buf_ptr; + uint32_t reason_code; + + param_buf = (WMI_DEBUG_MESG_FLUSH_COMPLETE_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid log flush complete event buffer"); + return QDF_STATUS_E_FAILURE; + } + + wmi_event = param_buf->fixed_param; + reason_code = wmi_event->reserved0; + wma_debug("Received reason code %d from FW", reason_code); + + if (reason_code == WMI_DIAG_TRIGGER_DATA_STALL) { + buf_ptr = (uint8_t *)wmi_event; + buf_ptr = buf_ptr + + sizeof(wmi_debug_mesg_flush_complete_fixed_param) + + WMI_TLV_HDR_SIZE; + data_stall_event = + (wmi_debug_mesg_fw_data_stall_param *)buf_ptr; + } + + if (reason_code == WMI_DIAG_TRIGGER_DATA_STALL && + ((data_stall_event->tlv_header & 0xFFFF0000) >> 16 == + WMITLV_TAG_STRUC_wmi_debug_mesg_fw_data_stall_param)) { + /** + * Log data stall info received from FW: + * + * Possible data stall recovery types: + * WLAN_DBG_DATA_STALL_RECOVERY_CONNECT_DISCONNECT + * WLAN_DBG_DATA_STALL_RECOVERY_CONNECT_MAC_PHY_RESET + * WLAN_DBG_DATA_STALL_RECOVERY_CONNECT_PDR + * + * Possible data stall event types: + * WLAN_DBG_DATA_STALL_VDEV_PAUSE + * WLAN_DBG_DATA_STALL_HWSCHED_CMD_FILTER + * WLAN_DBG_DATA_STALL_HWSCHED_CMD_FLUSH + * WLAN_DBG_DATA_STALL_RX_REFILL_FAILED + * WLAN_DBG_DATA_STALL_RX_FCS_LEN_ERROR + * + * reason_code1: + * The information stored in reason_code1 varies based on the + * data stall type values: + * + * data_stall_type | reason_code1 + * ----------------------------------------------------- + * HWSCHED_CMD_FLUSH | flush req reason (0-40) + * RX_REFILL_FAILED | ring_id (0-7) + * RX_FCS_LEN_ERROR | exact error type + * + * reasone_code2: + * on which tid/hwq stall happened + * + */ + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + "Data Stall event:"); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_DEBUG, + "data_stall_type: %x vdev_id_bitmap: %x reason_code1: %x reason_code2: %x recovery_type: %x ", + data_stall_event->data_stall_type, + data_stall_event->vdev_id_bitmap, + data_stall_event->reason_code1, + data_stall_event->reason_code2, + data_stall_event->recovery_type); + + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_FIRMWARE, + data_stall_event->data_stall_type, + OL_TXRX_PDEV_ID, + data_stall_event->vdev_id_bitmap, + data_stall_event->recovery_type); + } + + if (reason_code == WMI_DIAG_TRIGGER_CAL_FAILURE) { + wma_process_cal_fail_info((uint8_t *)wmi_event); + return QDF_STATUS_SUCCESS; + } + + /* + * reason_code = 0; Flush event in response to flush command + * reason_code = other value; Asynchronous flush event for fatal events + */ + if (!reason_code && (cds_is_log_report_in_progress() == false)) { + wma_debug("Received WMI flush event without sending CMD"); + return -EINVAL; + } else if (!reason_code && cds_is_log_report_in_progress() == true) { + /* Flush event in response to flush command */ + wma_debug("Received WMI flush event in response to flush CMD"); + status = qdf_mc_timer_stop(&wma->log_completion_timer); + if (status != QDF_STATUS_SUCCESS) + wma_err("Failed to stop the log completion timeout"); + cds_logging_set_fw_flush_complete(); + return QDF_STATUS_SUCCESS; + } else if (reason_code && cds_is_log_report_in_progress() == false) { + /* Asynchronous flush event for fatal events */ + status = cds_set_log_completion(WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, + reason_code, false); + if (QDF_STATUS_SUCCESS != status) { + wma_err("Failed to set log trigger params"); + return QDF_STATUS_E_FAILURE; + } + cds_logging_set_fw_flush_complete(); + return status; + } else { + /* Asynchronous flush event for fatal event, + * but, report in progress already + */ + wma_debug("Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, reason_code); + return QDF_STATUS_E_FAILURE; + } + /* Asynchronous flush event for fatal event, + * but, report in progress already + */ + wma_warn("Bug report already in progress - dropping! type:%d, indicator=%d reason_code=%d", + WLAN_LOG_TYPE_FATAL, + WLAN_LOG_INDICATOR_FIRMWARE, reason_code); + return QDF_STATUS_E_FAILURE; +} + +#ifdef WLAN_CONV_SPECTRAL_ENABLE +/** + * wma_extract_single_phyerr_spectral() - extract single phy error from event + * @handle: wma handle + * @evt_buf: pointer to event buffer + * @datalen: data length of event buffer + * @buf_offset: Pointer to hold value of current event buffer offset + * post extraction + * @phyerr: Pointer to hold phyerr + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_extract_single_phyerr_spectral(void *handle, + void *evt_buf, + uint16_t datalen, uint16_t *buf_offset, + wmi_host_phyerr_t *phyerr) +{ + wmi_single_phyerr_rx_event *ev; + int n = *buf_offset; + + ev = (wmi_single_phyerr_rx_event *)((uint8_t *)evt_buf + n); + + if (n < datalen) { + /* ensure there's at least space for the header */ + if ((datalen - n) < sizeof(ev->hdr)) { + wma_err("not enough space? (datalen=%d, n=%d, hdr=%zu bytes", + datalen, n, sizeof(ev->hdr)); + return QDF_STATUS_E_FAILURE; + } + + phyerr->bufp = ev->bufp; + phyerr->buf_len = ev->hdr.buf_len; + + /* + * Sanity check the buffer length of the event against + * what we currently have. + * + * Since buf_len is 32 bits, we check if it overflows + * a large 32 bit value. It's not 0x7fffffff because + * we increase n by (buf_len + sizeof(hdr)), which would + * in itself cause n to overflow. + * + * If "int" is 64 bits then this becomes a moot point. + */ + if (ev->hdr.buf_len > 0x7f000000) { + wma_err("buf_len is garbage? (0x%x)", ev->hdr.buf_len); + return QDF_STATUS_E_FAILURE; + } + if (n + ev->hdr.buf_len > datalen) { + wma_err("buf_len exceeds available space n=%d, buf_len=%d, datalen=%d", + n, ev->hdr.buf_len, datalen); + return QDF_STATUS_E_FAILURE; + } + + phyerr->phy_err_code = WMI_UNIFIED_PHYERRCODE_GET(&ev->hdr); + phyerr->tsf_timestamp = ev->hdr.tsf_timestamp; + +#ifdef DEBUG_SPECTRAL_SCAN + wma_debug("len=%d, tsf=0x%08x, rssi = 0x%x/0x%x/0x%x/0x%x, comb rssi = 0x%x, phycode=%d", + ev->hdr.buf_len, + ev->hdr.tsf_timestamp, + ev->hdr.rssi_chain0, + ev->hdr.rssi_chain1, + ev->hdr.rssi_chain2, + ev->hdr.rssi_chain3, + WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr), + phyerr->phy_err_code); + + /* + * For now, unroll this loop - the chain 'value' field isn't + * a variable but glued together into a macro field definition. + * Grr. :-) + */ + wma_debug("chain 0: raw=0x%08x; pri20=%d sec20=%d sec40=%d sec80=%d", + ev->hdr.rssi_chain0, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC80)); + + wma_debug("chain 1: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d", + ev->hdr.rssi_chain1, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC80)); + + wma_debug("chain 2: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d", + ev->hdr.rssi_chain2, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC80)); + + wma_debug("chain 3: raw=0x%08x: pri20=%d sec20=%d sec40=%d sec80=%d", + ev->hdr.rssi_chain3, + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, PRI20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC20), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC40), + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC80)); + + + wma_debug("freq_info_1=0x%08x, freq_info_2=0x%08x", + ev->hdr.freq_info_1, ev->hdr.freq_info_2); + + /* + * The NF chain values are signed and are negative - hence + * the cast evilness. + */ + wma_debug("nfval[1]=0x%08x, nfval[2]=0x%08x, nf=%d/%d/%d/%d, freq1=%d, freq2=%d, cw=%d", + ev->hdr.nf_list_1, + ev->hdr.nf_list_2, + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 0), + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 1), + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 2), + (int) WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 3), + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 1), + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 2), + WMI_UNIFIED_CHWIDTH_GET(&ev->hdr)); +#endif + + /* + * If required, pass spectral events to the spectral module + */ + if (ev->hdr.buf_len > 0) { + + /* Initialize the NF values to Zero. */ + phyerr->rf_info.noise_floor[0] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 0); + phyerr->rf_info.noise_floor[1] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 1); + phyerr->rf_info.noise_floor[2] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 2); + phyerr->rf_info.noise_floor[3] = + WMI_UNIFIED_NF_CHAIN_GET(&ev->hdr, 3); + + /* populate the rf info */ + phyerr->rf_info.rssi_comb = + WMI_UNIFIED_RSSI_COMB_GET(&ev->hdr); + + /* Need to unroll loop due to macro + * constraints chain 0 + */ + phyerr->rf_info.pc_rssi_info[0].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, PRI20); + phyerr->rf_info.pc_rssi_info[0].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC20); + phyerr->rf_info.pc_rssi_info[0].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC40); + phyerr->rf_info.pc_rssi_info[0].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 0, SEC80); + + /* chain 1 */ + phyerr->rf_info.pc_rssi_info[1].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, PRI20); + phyerr->rf_info.pc_rssi_info[1].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC20); + phyerr->rf_info.pc_rssi_info[1].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC40); + phyerr->rf_info.pc_rssi_info[1].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 1, SEC80); + + /* chain 2 */ + phyerr->rf_info.pc_rssi_info[2].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, PRI20); + phyerr->rf_info.pc_rssi_info[2].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC20); + phyerr->rf_info.pc_rssi_info[2].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC40); + phyerr->rf_info.pc_rssi_info[2].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 2, SEC80); + + /* chain 3 */ + phyerr->rf_info.pc_rssi_info[3].rssi_pri20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, PRI20); + phyerr->rf_info.pc_rssi_info[3].rssi_sec20 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC20); + phyerr->rf_info.pc_rssi_info[3].rssi_sec40 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC40); + phyerr->rf_info.pc_rssi_info[3].rssi_sec80 = + WMI_UNIFIED_RSSI_CHAN_GET(&ev->hdr, 3, SEC80); + + phyerr->chan_info.center_freq1 = + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 1); + phyerr->chan_info.center_freq2 = + WMI_UNIFIED_FREQ_INFO_GET(&ev->hdr, 2); + + } + + /* + * Advance the buffer pointer to the next PHY error. + * buflen is the length of this payload, so we need to + * advance past the current header _AND_ the payload. + */ + n += sizeof(*ev) + ev->hdr.buf_len; + } + *buf_offset += n; + + return QDF_STATUS_SUCCESS; +} + +/** + * spectral_phyerr_event_handler() - spectral phyerr event handler + * @handle: wma handle + * @data: data buffer + * @datalen: buffer length + * + * Return: QDF_STATUS + */ +static QDF_STATUS spectral_phyerr_event_handler(void *handle, + uint8_t *data, + uint32_t datalen) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint16_t buf_offset, event_buf_len = 0; + wmi_single_phyerr_rx_event *ev; + wmi_host_phyerr_t phyerr; + struct target_if_spectral_rfqual_info rfqual_info; + struct target_if_spectral_chan_info chan_info; + struct target_if_spectral_acs_stats acs_stats; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_FAILURE; + + memset(&phyerr, 0, sizeof(wmi_host_phyerr_t)); + status = wmi_extract_comb_phyerr(wma->wmi_handle, data, datalen, + &buf_offset, &phyerr); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("extract comb phyerr failed"); + return QDF_STATUS_E_FAILURE; + } + + ev = (wmi_single_phyerr_rx_event *)phyerr.bufp; + event_buf_len = phyerr.buf_len; + /* Loop over the bufp, extracting out phyerrors */ + buf_offset = 0; + while (buf_offset < event_buf_len) { + if (wma_extract_single_phyerr_spectral(handle, ev, + event_buf_len, &buf_offset, &phyerr)) { + wma_err("extract single phy err failed"); + return QDF_STATUS_E_FAILURE; + } + + if (phyerr.buf_len > 0) { + if (sizeof(phyerr.rf_info) > sizeof(rfqual_info)) + qdf_mem_copy(&rfqual_info, &phyerr.rf_info, + sizeof(rfqual_info)); + else + qdf_mem_copy(&rfqual_info, &phyerr.rf_info, + sizeof(phyerr.rf_info)); + + if (sizeof(phyerr.chan_info) > sizeof(chan_info)) + qdf_mem_copy(&chan_info, &phyerr.chan_info, + sizeof(chan_info)); + else + qdf_mem_copy(&chan_info, &phyerr.chan_info, + sizeof(phyerr.chan_info)); + + target_if_spectral_process_phyerr(wma->pdev, phyerr.bufp, + phyerr.buf_len, + &rfqual_info, + &chan_info, + phyerr.tsf64, + &acs_stats); + } + } + + return status; +} +#else +static QDF_STATUS +wma_extract_single_phyerr_spectral(void *handle, void *evt_buf, + uint16_t datalen, + uint16_t *buf_offset, + wmi_host_phyerr_t *phyerr) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS spectral_phyerr_event_handler(void *handle, + uint8_t *data, uint32_t datalen) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * dfs_phyerr_event_handler() - dfs phyerr event handler + * @handle: wma handle + * @data: data buffer + * @datalen: buffer length + * @fulltsf: 64 bit event TSF + * + * Function to process DFS phy errors. + * + * Return: QDF_STATUS + */ +static QDF_STATUS dfs_phyerr_event_handler(tp_wma_handle handle, + uint8_t *data, + uint32_t datalen, + uint64_t fulltsf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_lmac_if_dfs_rx_ops *dfs_rx_ops; + wmi_host_phyerr_t phyerr; + int8_t rssi_comb; + uint16_t buf_offset; + + if (!handle->psoc) { + wma_err("psoc is null"); + return QDF_STATUS_E_INVAL; + } + + dfs_rx_ops = wlan_lmac_if_get_dfs_rx_ops(handle->psoc); + if (!dfs_rx_ops) { + wma_err("dfs_rx_ops is null"); + return QDF_STATUS_E_INVAL; + } + + if (!dfs_rx_ops->dfs_process_phyerr) { + wma_err("dfs_process_phyerr handler is null"); + return QDF_STATUS_E_INVAL; + } + + if (!handle->pdev) { + wma_err("pdev is null"); + return -EINVAL; + } + + buf_offset = 0; + while (buf_offset < datalen) { + status = wmi_extract_single_phyerr(handle->wmi_handle, data, datalen, + &buf_offset, &phyerr); + if (QDF_IS_STATUS_ERROR(status)) { + /* wmi_extract_single_phyerr has logs */ + return status; + } + + rssi_comb = phyerr.rf_info.rssi_comb & 0xFF; + if (phyerr.buf_len > 0) + dfs_rx_ops->dfs_process_phyerr(handle->pdev, + &phyerr.bufp[0], + phyerr.buf_len, + rssi_comb, + rssi_comb, + phyerr.tsf_timestamp, + fulltsf); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_unified_phyerr_rx_event_handler() - phyerr event handler + * @handle: wma handle + * @data: data buffer + * @datalen: buffer length + * + * WMI Handler for WMI_PHYERR_EVENTID event from firmware. + * This handler is currently handling DFS and spectral scan + * phy errors. + * + * Return: 0 for success, other value for failure + */ +static int wma_unified_phyerr_rx_event_handler(void *handle, + uint8_t *data, + uint32_t datalen) +{ + /* phyerr handling is moved to cmn project + * As WIN still uses handler registration in non-cmn code. + * need complete testing of non offloaded DFS code before we enable + * it in cmn code. + **/ + tp_wma_handle wma = (tp_wma_handle) handle; + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_host_phyerr_t phyerr; + uint16_t buf_offset = 0; + wmi_single_phyerr_rx_event *ev; + uint16_t event_buf_len = 0; + wmi_host_phyerr_t phyerr2; + bool spectralscan = false; + + if (wma_validate_handle(wma)) + return -EINVAL; + + /* sanity check on data length */ + status = wmi_extract_comb_phyerr(wma->wmi_handle, data, datalen, + &buf_offset, &phyerr); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("extract phyerr failed: %d", status); + return qdf_status_to_os_return(status); + } + ev = (wmi_single_phyerr_rx_event *)phyerr.bufp; + event_buf_len = phyerr.buf_len; + /* Loop over the bufp, extracting out phyerrors */ + buf_offset = 0; + while (ev && (buf_offset < event_buf_len)) { + if (wma_extract_single_phyerr_spectral(handle, ev, + event_buf_len, + &buf_offset, + &phyerr2)) { + wma_err("extract single phy err failed"); + return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); + } + if ((buf_offset != 0) && (phyerr2.phy_err_code == 0x26 || + phyerr2.phy_err_code == 0x24)) { + spectralscan = true; + } else { + break; + } + } + if (spectralscan) { + status = spectral_phyerr_event_handler(wma, data, datalen); + return qdf_status_to_os_return(status); + } + /* handle different PHY Error conditions */ + if (((phyerr.phy_err_mask0 & (WMI_PHY_ERROR_MASK0_RADAR | + WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT | + WMI_PHY_ERROR_MASK0_SPECTRAL_SCAN)) == 0)) { + wma_debug("Unknown phy error event"); + return -EINVAL; + } + + /* Handle Spectral or DFS PHY Error */ + if (phyerr.phy_err_mask0 & (WMI_PHY_ERROR_MASK0_RADAR | + WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT)) { + if (wma->is_dfs_offloaded) { + wma_debug("Unexpected phy error, dfs offloaded"); + return -EINVAL; + } + status = dfs_phyerr_event_handler(wma, + phyerr.bufp, + phyerr.buf_len, + phyerr.tsf64); + } else if (phyerr.phy_err_mask0 & (WMI_PHY_ERROR_MASK0_SPECTRAL_SCAN | + WMI_PHY_ERROR_MASK0_FALSE_RADAR_EXT)) { + status = spectral_phyerr_event_handler(wma, data, datalen); + } + + return qdf_status_to_os_return(status); +} + +void wma_vdev_init(struct wma_txrx_node *vdev) +{ + vdev->is_waiting_for_key = false; +} + +void wma_vdev_deinit(struct wma_txrx_node *vdev) +{ + struct beacon_info *bcn; + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return; + + bcn = vdev->beacon; + if (bcn) { + if (bcn->dma_mapped) + qdf_nbuf_unmap_single(wma_handle->qdf_dev, + bcn->buf, QDF_DMA_TO_DEVICE); + qdf_nbuf_free(bcn->buf); + qdf_mem_free(bcn); + vdev->beacon = NULL; + } + + if (vdev->vdev_active == true) + vdev->vdev_active = false; + + if (vdev->addBssStaContext) { + qdf_mem_free(vdev->addBssStaContext); + vdev->addBssStaContext = NULL; + } + + if (vdev->psnr_req) { + qdf_mem_free(vdev->psnr_req); + vdev->psnr_req = NULL; + } + + if (vdev->rcpi_req) { + qdf_mem_free(vdev->rcpi_req); + vdev->rcpi_req = NULL; + } + + if (vdev->roam_scan_stats_req) { + struct sir_roam_scan_stats *req; + + req = vdev->roam_scan_stats_req; + vdev->roam_scan_stats_req = NULL; + qdf_mem_free(req); + } + + if (vdev->roam_synch_frame_ind.bcn_probe_rsp) { + qdf_mem_free(vdev->roam_synch_frame_ind.bcn_probe_rsp); + vdev->roam_synch_frame_ind.bcn_probe_rsp = NULL; + } + + if (vdev->roam_synch_frame_ind.reassoc_req) { + qdf_mem_free(vdev->roam_synch_frame_ind.reassoc_req); + vdev->roam_synch_frame_ind.reassoc_req = NULL; + } + + if (vdev->roam_synch_frame_ind.reassoc_rsp) { + qdf_mem_free(vdev->roam_synch_frame_ind.reassoc_rsp); + vdev->roam_synch_frame_ind.reassoc_rsp = NULL; + } + + if (vdev->plink_status_req) { + qdf_mem_free(vdev->plink_status_req); + vdev->plink_status_req = NULL; + } + + vdev->is_waiting_for_key = false; +} + +/** + * wma_wmi_stop() - generic function to block WMI commands + * @return: None + */ +void wma_wmi_stop(void) +{ + tp_wma_handle wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return; + + if (wmi_validate_handle(wma_handle->wmi_handle)) + return; + + wmi_stop(wma_handle->wmi_handle); +} + +#ifdef WLAN_WMI_BCN +static QDF_STATUS +wma_register_swba_events(wmi_unified_t wmi_handle) +{ + QDF_STATUS status; + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_host_swba_event_id, + wma_beacon_swba_handler, + WMA_RX_SERIALIZER_CTX); + + return status; +} +#else +static QDF_STATUS wma_register_swba_events(wmi_unified_t wmi_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef FEATURE_WLAN_APF +static void wma_register_apf_events(tp_wma_handle wma_handle) +{ + if (wma_validate_handle(wma_handle)) + return; + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_apf_capability_info_event_id, + wma_get_apf_caps_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_apf_get_vdev_work_memory_resp_event_id, + wma_apf_read_work_memory_event_handler, + WMA_RX_SERIALIZER_CTX); +} +#else /* FEATURE_WLAN_APF */ +static void wma_register_apf_events(tp_wma_handle wma_handle) +{ +} +#endif /* FEATURE_WLAN_APF */ + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * wma_register_md_events - Register motion detection event handlers + * @wma_handle: wma handle + * Return: None + */ +static void wma_register_md_events(tp_wma_handle wma_handle) +{ + if (wma_validate_handle(wma_handle)) + return; + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_motion_det_host_eventid, + wma_motion_det_host_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_motion_det_base_line_host_eventid, + wma_motion_det_base_line_host_event_handler, + WMA_RX_SERIALIZER_CTX); +} +#else /* WLAN_FEATURE_MOTION_DETECTION */ +/** + * wma_register_md_events - Register motion detection event handlers + * @wma_handle: wma handle + * Return: None + */ +static void wma_register_md_events(tp_wma_handle wma_handle) +{ +} +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +#ifdef FEATURE_WLM_STATS +static void wma_register_wlm_stats_events(tp_wma_handle wma_handle) +{ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_wlm_stats_event_id, + wma_wlm_stats_rsp, + WMA_RX_SERIALIZER_CTX); +} +#else /* FEATURE_WLM_STATS */ +static void wma_register_wlm_stats_events(tp_wma_handle wma_handle) +{ +} +#endif /* FEATURE_WLM_STATS */ + +#ifdef MULTI_CLIENT_LL_SUPPORT +static void wma_register_wlm_latency_level_event(tp_wma_handle wma_handle) +{ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_latency_event_id, + wma_latency_level_event_handler, + WMA_RX_WORK_CTX); +} +#else +static void wma_register_wlm_latency_level_event(tp_wma_handle wma_handle) +{ +} +#endif + +struct wlan_objmgr_psoc *wma_get_psoc_from_scn_handle(void *scn_handle) +{ + tp_wma_handle wma_handle; + + if (!scn_handle) { + wma_err("invalid scn handle"); + return NULL; + } + wma_handle = (tp_wma_handle)scn_handle; + + return wma_handle->psoc; +} + +void wma_get_fw_phy_mode_for_freq_cb(uint32_t freq, uint32_t chan_width, + uint32_t *phy_mode) +{ + uint32_t dot11_mode; + enum wlan_phymode host_phy_mode; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("MAC context is NULL"); + *phy_mode = WLAN_PHYMODE_AUTO; + return; + } + + dot11_mode = mac->mlme_cfg->dot11_mode.dot11_mode; + + /* Update invalid dot11 modes to valid dot11 modes */ + if (WLAN_REG_IS_24GHZ_CH_FREQ(freq) && + dot11_mode == MLME_DOT11_MODE_11A) + dot11_mode = MLME_DOT11_MODE_11G; + + if (WLAN_REG_IS_5GHZ_CH_FREQ(freq) && + (dot11_mode == MLME_DOT11_MODE_11B || + dot11_mode == MLME_DOT11_MODE_11G || + dot11_mode == MLME_DOT11_MODE_11G_ONLY)) + dot11_mode = MLME_DOT11_MODE_11A; + + host_phy_mode = wma_chan_phy_mode(freq, chan_width, dot11_mode); + *phy_mode = wmi_host_to_fw_phymode(host_phy_mode); +} + +void wma_get_phy_mode_cb(qdf_freq_t freq, uint32_t chan_width, + enum wlan_phymode *phy_mode) +{ + uint32_t dot11_mode; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("MAC context is NULL"); + *phy_mode = WLAN_PHYMODE_AUTO; + return; + } + + dot11_mode = mac->mlme_cfg->dot11_mode.dot11_mode; + *phy_mode = wma_chan_phy_mode(freq, chan_width, dot11_mode); +} + +#ifdef WLAN_FEATURE_NAN +static void +wma_register_nan_callbacks(tp_wma_handle wma_handle) +{ + struct nan_callbacks cb_obj = {0}; + + cb_obj.update_ndi_conn = wma_ndi_update_connection_info; + + ucfg_nan_register_wma_callbacks(wma_handle->psoc, &cb_obj); +} +#else +static void wma_register_nan_callbacks(tp_wma_handle wma_handle) +{ +} +#endif + +#ifdef WLAN_FEATURE_PKT_CAPTURE +static void +wma_register_pkt_capture_callbacks(tp_wma_handle wma_handle) +{ + struct pkt_capture_callbacks cb_obj = {0}; + + cb_obj.get_rmf_status = wma_get_rmf_status; + + ucfg_pkt_capture_register_wma_callbacks(wma_handle->psoc, &cb_obj); +} +#else +static inline void +wma_register_pkt_capture_callbacks(tp_wma_handle wma_handle) +{ +} +#endif + +#ifdef TRACE_RECORD +static void wma_trace_dump(void *mac_ctx, tp_qdf_trace_record record, + uint16_t rec_index) +{ + /* + * This is dummy handler registered to qdf_trace as wma module wants to + * insert trace records in qdf trace global record table but qdf_trace + * does not allow to insert the trace records in the global record + * table if a module is not registered with the qdf trace. + */ +} + +static void wma_trace_init(void) +{ + qdf_trace_register(QDF_MODULE_ID_WMA, &wma_trace_dump); +} +#else +static inline void wma_trace_init(void) +{ +} +#endif + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +static void wma_get_service_cap_club_get_sta_in_ll_stats_req( + struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->is_get_station_clubbed_in_ll_stats_req = + wmi_service_enabled(wmi_handle, + wmi_service_get_station_in_ll_stats_req); +} +#else +static void wma_get_service_cap_club_get_sta_in_ll_stats_req( + struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ +} +#endif /* FEATURE_CLUB_LL_STATS_AND_GET_STATION */ + +#ifdef WLAN_FEATURE_11BE_MLO +static void +wma_update_num_tdls_vdevs_if_11be_mlo(struct wlan_objmgr_psoc *psoc, + target_resource_config *wlan_res_cfg) +{ + if (!wlan_tdls_is_fw_11be_mlo_capable(psoc)) + return; + + wlan_res_cfg->num_tdls_vdevs = WLAN_UMAC_MLO_MAX_VDEVS; + wma_debug("update tdls num vdevs %d", wlan_res_cfg->num_tdls_vdevs); +} + +static void +wma_get_service_cap_per_link_mlo_stats(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->is_mlo_per_link_stats_supported = + wmi_service_enabled(wmi_handle, + wmi_service_per_link_stats_support); + wma_debug("mlo_per_link stats is %s supported by FW", + cfg->is_mlo_per_link_stats_supported ? "" : "NOT"); +} +#else +static void +wma_update_num_tdls_vdevs_if_11be_mlo(struct wlan_objmgr_psoc *psoc, + target_resource_config *wlan_res_cfg) +{ +} + +static void +wma_get_service_cap_per_link_mlo_stats(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ +} +#endif + +/** + * wma_set_exclude_selftx_from_cca_busy_time() - Set exclude self tx time from + * cca busy time bool + * @exclude_selftx_from_cca_busy: Bool to update in in wma ini config + * @wma_handle: WMA handle + * + * Return: None + */ +static void +wma_set_exclude_selftx_from_cca_busy_time(bool exclude_selftx_from_cca_busy, + tp_wma_handle wma_handle) +{ + struct wma_ini_config *cfg = wma_get_ini_handle(wma_handle); + + if (!cfg) { + wma_err("NULL WMA ini handle"); + return; + } + + cfg->exclude_selftx_from_cca_busy = exclude_selftx_from_cca_busy; +} + +static void wma_deinit_pagefault_wakeup_history(tp_wma_handle wma) +{ + struct wma_pf_sym *pf_sym_entry; + int8_t idx, max_sym_count = WLAN_WMA_MAX_PF_SYM; + bool is_ssr = false; + + if (wlan_pmo_enable_ssr_on_page_fault(wma->psoc)) { + is_ssr = true; + max_sym_count = 0x1; + } + + for (idx = 0; idx < max_sym_count; idx++) { + pf_sym_entry = &wma->wma_pf_hist.wma_pf_sym[idx]; + pf_sym_entry->pf_sym.symbol = 0x0; + pf_sym_entry->pf_sym.count = 0x0; + qdf_mem_free(pf_sym_entry->pf_ev_ts); + pf_sym_entry->pf_ev_ts = NULL; + } + + if (!is_ssr) { + qdf_mem_free(wma->wma_pf_hist.pf_notify_buf_ptr); + wma->wma_pf_hist.pf_notify_buf_ptr = NULL; + wma->wma_pf_hist.pf_notify_buf_len = 0x0; + } + qdf_spinlock_destroy(&wma->wma_pf_hist.lock); +} + +static QDF_STATUS wma_init_pagefault_wakeup_history(tp_wma_handle wma) +{ + struct wma_pf_sym *pf_sym_entry; + int8_t idx, idx2, max_sym_count = WLAN_WMA_MAX_PF_SYM; + uint8_t max_pf_count; + bool is_ssr = false; + + if (wlan_pmo_enable_ssr_on_page_fault(wma->psoc)) { + is_ssr = true; + max_sym_count = 0x1; + } + + max_pf_count = wlan_pmo_get_min_pagefault_wakeups_for_action(wma->psoc); + for (idx = 0; idx < max_sym_count; idx++) { + pf_sym_entry = &wma->wma_pf_hist.wma_pf_sym[idx]; + pf_sym_entry->pf_sym.symbol = 0x0; + pf_sym_entry->pf_sym.count = 0x0; + pf_sym_entry->pf_ev_ts = qdf_mem_malloc(max_pf_count * + sizeof(qdf_time_t)); + if (!pf_sym_entry->pf_ev_ts) + goto mem_err; + } + + if (!is_ssr) { + wma->wma_pf_hist.pf_notify_buf_len = 0x0; + wma->wma_pf_hist.pf_notify_buf_ptr = + qdf_mem_malloc(WLAN_WMA_PF_APPS_NOTIFY_BUF_LEN); + if (!wma->wma_pf_hist.pf_notify_buf_ptr) + goto mem_err; + } + + qdf_spinlock_create(&wma->wma_pf_hist.lock); + + return QDF_STATUS_SUCCESS; + +mem_err: + for (idx2 = --idx; idx2 >= 0; idx2--) { + pf_sym_entry = &wma->wma_pf_hist.wma_pf_sym[idx2]; + qdf_mem_free(pf_sym_entry->pf_ev_ts); + pf_sym_entry->pf_ev_ts = NULL; + } + + return QDF_STATUS_E_NOMEM; +} + +/** + * wma_open() - Allocate wma context and initialize it. + * @psoc: psoc object + * @tgt_cfg_cb: tgt config callback fun + * @cds_cfg: mac parameters + * @target_type: target type + * + * Return: 0 on success, errno on failure + */ +QDF_STATUS wma_open(struct wlan_objmgr_psoc *psoc, + wma_tgt_cfg_cb tgt_cfg_cb, + struct cds_config_info *cds_cfg, + uint32_t target_type) +{ + tp_wma_handle wma_handle; + HTC_HANDLE htc_handle; + qdf_device_t qdf_dev; + void *wmi_handle; + QDF_STATUS qdf_status; + struct wmi_unified_attach_params *params; + struct policy_mgr_wma_cbacks wma_cbacks; + struct target_psoc_info *tgt_psoc_info; + int i; + bool val = 0; + void *cds_context; + target_resource_config *wlan_res_cfg; + uint32_t self_gen_frm_pwr = 0; + uint32_t device_mode = cds_get_conparam(); + + wma_debug("Enter"); + + cds_context = cds_get_global_context(); + if (!cds_context) { + wma_err("Invalid CDS context"); + return QDF_STATUS_E_INVAL; + } + + g_wmi_version_info.major = __WMI_VER_MAJOR_; + g_wmi_version_info.minor = __WMI_VER_MINOR_; + g_wmi_version_info.revision = __WMI_REVISION_; + + qdf_dev = cds_get_context(QDF_MODULE_ID_QDF_DEVICE); + htc_handle = cds_get_context(QDF_MODULE_ID_HTC); + + if (!htc_handle) { + wma_err("Invalid HTC handle"); + return QDF_STATUS_E_INVAL; + } + + /* Alloc memory for WMA Context */ + qdf_status = cds_alloc_context(QDF_MODULE_ID_WMA, + (void **)&wma_handle, + sizeof(*wma_handle)); + + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("Memory allocation failed for wma_handle"); + return qdf_status; + } + + qdf_mem_zero(wma_handle, sizeof(t_wma_handle)); + + if (target_if_alloc_psoc_tgt_info(psoc)) { + wma_err("target psoc info allocation failed"); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_free_wma_handle; + } + + if (device_mode != QDF_GLOBAL_FTM_MODE) { +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_create(&wma_handle->extscan_wake_lock, + "wlan_extscan_wl"); +#endif /* FEATURE_WLAN_EXTSCAN */ + qdf_wake_lock_create(&wma_handle->wow_wake_lock, + "wlan_wow_wl"); + qdf_wake_lock_create(&wma_handle->wow_auth_req_wl, + "wlan_auth_req_wl"); + qdf_wake_lock_create(&wma_handle->wow_assoc_req_wl, + "wlan_assoc_req_wl"); + qdf_wake_lock_create(&wma_handle->wow_deauth_rec_wl, + "wlan_deauth_rec_wl"); + qdf_wake_lock_create(&wma_handle->wow_disassoc_rec_wl, + "wlan_disassoc_rec_wl"); + qdf_wake_lock_create(&wma_handle->wow_ap_assoc_lost_wl, + "wlan_ap_assoc_lost_wl"); + qdf_wake_lock_create(&wma_handle->wow_auto_shutdown_wl, + "wlan_auto_shutdown_wl"); + qdf_wake_lock_create(&wma_handle->roam_ho_wl, + "wlan_roam_ho_wl"); + qdf_wake_lock_create(&wma_handle->roam_preauth_wl, + "wlan_roam_preauth_wl"); + qdf_wake_lock_create(&wma_handle->probe_req_wps_wl, + "wlan_probe_req_wps_wl"); + qdf_wake_lock_create(&wma_handle->sap_d3_wow_wake_lock, + "wlan_sap_d3_wow_wake_lock"); + qdf_wake_lock_create(&wma_handle->go_d3_wow_wake_lock, + "wlan_go_d3_wow_wake_lock"); + } + + qdf_status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_LEGACY_WMA_ID); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("PSOC get_ref fails"); + goto err_get_psoc_ref; + } + wma_handle->psoc = psoc; + + if (!wlan_pmo_no_op_on_page_fault(psoc)) { + qdf_status = wma_init_pagefault_wakeup_history(wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto err_wma_handle; + } + + wma_target_if_open(wma_handle); + + /* + * Allocate locally used params with its rx_ops member, + * and free it immediately after used. + */ + params = qdf_mem_malloc(sizeof(*params)); + if (!params) { + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + params->osdev = NULL; + params->target_type = WMI_TLV_TARGET; + params->use_cookie = false; + params->psoc = psoc; + params->max_commands = WMI_MAX_CMDS; + + /* initialize tlv attach */ + wmi_tlv_init(); + + /* attach the wmi */ + wmi_handle = wmi_unified_attach(wma_handle, params); + qdf_mem_free(params); + if (!wmi_handle) { + wma_err("failed to attach WMI"); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + target_if_register_legacy_service_ready_cb( + wma_legacy_service_ready_event_handler); + + wma_info("WMA --> wmi_unified_attach - success"); + + /* store the wmi handle in tgt_if_handle */ + tgt_psoc_info = wlan_psoc_get_tgt_if_handle(psoc); + + target_psoc_set_target_type(tgt_psoc_info, target_type); + target_psoc_set_device_mode(tgt_psoc_info, device_mode); + /* Save the WMI & HTC handle */ + target_psoc_set_wmi_hdl(tgt_psoc_info, wmi_handle); + wma_handle->wmi_handle = wmi_handle; + target_psoc_set_htc_hdl(tgt_psoc_info, htc_handle); + wma_handle->cds_context = cds_context; + wma_handle->qdf_dev = qdf_dev; + wma_handle->enable_tx_compl_tsf64 = + cds_cfg->enable_tx_compl_tsf64; + + /* Register Converged Event handlers */ + init_deinit_register_tgt_psoc_ev_handlers(psoc); + + /* Register LFR2/3 common Roam Event handler */ + target_if_roam_register_common_events(psoc); + + /* Register Roam offload Event handlers */ + target_if_roam_offload_register_events(psoc); + + /* Initialize max_no_of_peers for wma_get_number_of_peers_supported() */ + cds_cfg->max_station = wma_init_max_no_of_peers(wma_handle, + cds_cfg->max_station); + + wlan_mlme_set_assoc_sta_limit(psoc, cds_cfg->max_station); + + wlan_mlme_register_common_events(psoc); + + /* initialize default target config */ + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_psoc_info); + if (!wlan_res_cfg) { + wma_err("wlan_res_cfg is null"); + qdf_status = QDF_STATUS_E_NOMEM; + goto err_wma_handle; + } + + wma_set_default_tgt_config(wma_handle, wlan_res_cfg, cds_cfg); + wma_update_num_tdls_vdevs_if_11be_mlo(psoc, wlan_res_cfg); + + qdf_status = wlan_mlme_get_tx_chainmask_cck(psoc, &val); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("Failed to get tx_chainmask_cck"); + qdf_status = QDF_STATUS_E_FAILURE; + goto err_wma_handle; + } + wma_handle->tx_chain_mask_cck = val; + + qdf_status = wlan_mlme_get_self_gen_frm_pwr(psoc, &self_gen_frm_pwr); + if (qdf_status != QDF_STATUS_SUCCESS) + wma_err("Failed to get self_gen_frm_pwr"); + wma_handle->self_gen_frm_pwr = self_gen_frm_pwr; + + cds_cfg->max_bssid = WLAN_MAX_VDEVS; + + wma_handle->max_station = cds_cfg->max_station; + wma_handle->max_bssid = cds_cfg->max_bssid; + wma_handle->enable_mc_list = + ucfg_pmo_is_mc_addr_list_enabled(wma_handle->psoc); + wma_handle->active_uc_apf_mode = + ucfg_pmo_get_active_uc_apf_mode(wma_handle->psoc); + wma_handle->active_mc_bc_apf_mode = + ucfg_pmo_get_active_mc_bc_apf_mode(wma_handle->psoc); + wma_handle->link_stats_results = NULL; +#ifdef WLAN_FEATURE_LPSS + wma_handle->is_lpass_enabled = cds_cfg->is_lpass_enabled; +#endif + wma_handle->interfaces = qdf_mem_malloc(sizeof(struct wma_txrx_node) * + wma_handle->max_bssid); + if (!wma_handle->interfaces) { + qdf_status = QDF_STATUS_E_NOMEM; + goto err_scn_context; + } + + for (i = 0; i < wma_handle->max_bssid; ++i) + wma_vdev_init(&wma_handle->interfaces[i]); + + /* Register the debug print event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_debug_print_event_id, + wma_unified_debug_print_event_handler, + WMA_RX_SERIALIZER_CTX); + /* Register profiling event Handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_wlan_profile_data_event_id, + wma_profile_data_report_event_handler, + WMA_RX_SERIALIZER_CTX); + + wma_handle->tgt_cfg_update_cb = tgt_cfg_cb; + wma_handle->old_hw_mode_index = WMA_DEFAULT_HW_MODE_INDEX; + wma_handle->new_hw_mode_index = WMA_DEFAULT_HW_MODE_INDEX; + wma_handle->saved_chan.num_channels = 0; + wma_handle->fw_timeout_crash = cds_cfg->fw_timeout_crash; + + qdf_status = qdf_mc_timer_init(&wma_handle->service_ready_ext_timer, + QDF_TIMER_TYPE_SW, + wma_service_ready_ext_evt_timeout, + wma_handle); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("Failed to initialize service ready ext timeout"); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->target_suspend); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("target suspend event initialization failed"); + goto err_event_init; + } + + /* Init Tx Frame Complete event */ + qdf_status = qdf_event_create(&wma_handle->tx_frm_download_comp_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("failed to init tx_frm_download_comp_event"); + goto err_event_init; + } + + /* Init tx queue empty check event */ + qdf_status = qdf_event_create(&wma_handle->tx_queue_empty_event); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("failed to init tx_queue_empty_event"); + goto err_event_init; + } + + qdf_status = cds_shutdown_notifier_register(wma_shutdown_notifier_cb, + wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("Shutdown notifier register failed: %d", qdf_status); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->runtime_suspend); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("runtime_suspend event initialization failed"); + goto err_event_init; + } + + qdf_status = qdf_event_create(&wma_handle->recovery_event); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("recovery event initialization failed"); + goto err_event_init; + } + + qdf_status = qdf_mutex_create(&wma_handle->radio_stats_lock); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to create radio stats mutex"); + goto err_event_init; + } + + qdf_list_create(&wma_handle->wma_hold_req_queue, + MAX_ENTRY_HOLD_REQ_QUEUE); + qdf_spinlock_create(&wma_handle->wma_hold_req_q_lock); + qdf_atomic_init(&wma_handle->is_wow_bus_suspended); + qdf_atomic_init(&wma_handle->sap_num_clients_connected); + qdf_atomic_init(&wma_handle->go_num_clients_connected); + + /* register for STA kickout function */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_sta_kickout_event_id, + wma_peer_sta_kickout_event_handler, + WMA_RX_SERIALIZER_CTX); + /* register for fw state response event */ + wma_register_fw_state_events(wma_handle->wmi_handle); + +#ifdef WLAN_POWER_DEBUG + /* register for Chip Power stats event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_pdev_chip_power_stats_event_id, + wma_unified_power_debug_stats_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS + /* register for beacon stats event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_bcn_reception_stats_event_id, + wma_unified_beacon_debug_stats_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif + +#if defined(CLD_PM_QOS) && defined(WLAN_FEATURE_LL_MODE) + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_vdev_bcn_latency_event_id, + wma_vdev_bcn_latency_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif + /* register for linkspeed response event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_estimated_linkspeed_event_id, + wma_link_speed_event_handler, + WMA_RX_SERIALIZER_CTX); + +#ifdef FEATURE_OEM_DATA_SUPPORT + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_oem_response_event_id, + wma_oem_data_response_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* FEATURE_OEM_DATA_SUPPORT */ + + /* Register beacon tx complete event id. The event is required + * for sending channel switch announcement frames + */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_offload_bcn_tx_status_event_id, + wma_unified_bcntx_status_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_update_vdev_rate_stats_event_id, + wma_link_status_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_roam_scan_stats_event_id, + wma_roam_scan_stats_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_pdev_cold_boot_cal_event_id, + wma_cold_boot_cal_event_handler, + WMA_RX_WORK_CTX); + +#ifdef FEATURE_OEM_DATA + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_oem_data_event_id, + wma_oem_event_handler, + WMA_RX_WORK_CTX); +#endif + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + /* Register event handler for processing Link Layer Stats + * response from the FW + */ + wma_register_ll_stats_event_handler(wma_handle); + +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + + wmi_set_tgt_assert(wma_handle->wmi_handle, + cds_cfg->force_target_assert_enabled); + /* Firmware debug log */ + qdf_status = dbglog_init(wma_handle->wmi_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("Firmware Dbglog initialization failed"); + goto err_dbglog_init; + } + + wma_handle->staMaxLIModDtim = cds_cfg->sta_maxlimod_dtim; + wma_handle->sta_max_li_mod_dtim_ms = cds_cfg->sta_maxlimod_dtim_ms; + wma_handle->staModDtim = ucfg_pmo_get_sta_mod_dtim(wma_handle->psoc); + wma_handle->staDynamicDtim = + ucfg_pmo_get_sta_dynamic_dtim(wma_handle->psoc); + +#ifdef WLAN_FEATURE_STATS_EXT + /* register for extended stats event */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_stats_ext_event_id, + wma_stats_ext_event_handler, + WMA_RX_SERIALIZER_CTX); +#endif /* WLAN_FEATURE_STATS_EXT */ +#ifdef FEATURE_WLAN_EXTSCAN + wma_register_extscan_event_handler(wma_handle); +#endif /* WLAN_FEATURE_STATS_EXT */ + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_rssi_breach_event_id, + wma_rssi_breached_event_handler, + WMA_RX_SERIALIZER_CTX); + + qdf_wake_lock_create(&wma_handle->wmi_cmd_rsp_wake_lock, + "wlan_fw_rsp_wakelock"); + qdf_runtime_lock_init(&wma_handle->wmi_cmd_rsp_runtime_lock); + qdf_runtime_lock_init(&wma_handle->sap_prevent_runtime_pm_lock); + qdf_runtime_lock_init(&wma_handle->ndp_prevent_runtime_pm_lock); + + /* Register peer assoc conf event handler */ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_assoc_conf_event_id, + wma_peer_assoc_conf_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_create_conf_event_id, + wma_peer_create_confirm_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_delete_response_event_id, + wma_peer_delete_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_chan_info_event_id, + wma_chan_info_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_dbg_mesg_flush_complete_event_id, + wma_flush_complete_evt_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_report_rx_aggr_failure_event_id, + wma_rx_aggr_failure_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_coex_report_antenna_isolation_event_id, + wma_antenna_isolation_event_handler, + WMA_RX_SERIALIZER_CTX); + + wma_handle->ito_repeat_count = cds_cfg->ito_repeat_count; + wma_handle->bandcapability = cds_cfg->bandcapability; + + /* Register PWR_SAVE_FAIL event only in case of recovery(1) */ + if (ucfg_pmo_get_auto_power_fail_mode(wma_handle->psoc) == + PMO_FW_TO_SEND_WOW_IND_ON_PWR_FAILURE) { + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_pdev_chip_pwr_save_failure_detect_event_id, + wma_chip_power_save_failure_detected_handler, + WMA_RX_WORK_CTX); + } + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_pdev_div_rssi_antid_event_id, + wma_pdev_div_info_evt_handler, + WMA_RX_WORK_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_get_ani_level_event_id, + wma_get_ani_level_evt_handler, + WMA_RX_WORK_CTX); + + wma_register_debug_callback(); + wifi_pos_register_get_phy_mode_cb(wma_handle->psoc, + wma_get_phy_mode_cb); + wifi_pos_register_get_fw_phy_mode_for_freq_cb( + wma_handle->psoc, + wma_get_fw_phy_mode_for_freq_cb); + + /* Register callback with PMO so PMO can update the vdev pause bitmap*/ + pmo_register_pause_bitmap_notifier(wma_handle->psoc, + wma_vdev_update_pause_bitmap); + pmo_register_get_pause_bitmap(wma_handle->psoc, + wma_vdev_get_pause_bitmap); + pmo_register_is_device_in_low_pwr_mode(wma_handle->psoc, + wma_vdev_is_device_in_low_pwr_mode); + pmo_register_get_dtim_period_callback(wma_handle->psoc, + wma_vdev_get_dtim_period); + pmo_register_get_beacon_interval_callback(wma_handle->psoc, + wma_vdev_get_beacon_interval); + wma_cbacks.wma_get_connection_info = wma_get_connection_info; + wma_register_nan_callbacks(wma_handle); + wma_register_pkt_capture_callbacks(wma_handle); + qdf_status = policy_mgr_register_wma_cb(wma_handle->psoc, &wma_cbacks); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("Failed to register wma cb with Policy Manager"); + } + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_phyerr_event_id, + wma_unified_phyerr_rx_event_handler, + WMA_RX_WORK_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_sap_obss_detection_report_event_id, + wma_vdev_obss_detection_info_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_obss_color_collision_report_event_id, + wma_vdev_bss_color_collision_info_handler, + WMA_RX_WORK_CTX); + + wma_register_twt_events(wma_handle); + + wma_register_apf_events(wma_handle); + wma_register_md_events(wma_handle); + wma_register_wlm_stats_events(wma_handle); + wma_register_wlm_latency_level_event(wma_handle); + wma_register_mws_coex_events(wma_handle); + wma_trace_init(); + wma_set_exclude_selftx_from_cca_busy_time( + cds_cfg->exclude_selftx_from_cca_busy, + wma_handle); + return QDF_STATUS_SUCCESS; + +err_dbglog_init: + qdf_status = qdf_mutex_destroy(&wma_handle->radio_stats_lock); + if (QDF_IS_STATUS_ERROR(qdf_status)) + wma_err("Failed to destroy radio stats mutex"); + + qdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock); + qdf_runtime_lock_deinit(&wma_handle->ndp_prevent_runtime_pm_lock); + qdf_runtime_lock_deinit(&wma_handle->sap_prevent_runtime_pm_lock); + qdf_runtime_lock_deinit(&wma_handle->wmi_cmd_rsp_runtime_lock); + qdf_spinlock_destroy(&wma_handle->wma_hold_req_q_lock); +err_event_init: + wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + wmi_debug_print_event_id); + + for (i = 0; i < wma_handle->max_bssid; ++i) + wma_vdev_deinit(&wma_handle->interfaces[i]); + + qdf_mem_free(wma_handle->interfaces); + +err_scn_context: + qdf_mem_free(((struct cds_context *) cds_context)->cfg_ctx); + ((struct cds_context *)cds_context)->cfg_ctx = NULL; + qdf_mem_free(wmi_handle); + +err_wma_handle: + wlan_objmgr_psoc_release_ref(psoc, WLAN_LEGACY_WMA_ID); +err_get_psoc_ref: + target_if_free_psoc_tgt_info(psoc); + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + qdf_wake_lock_destroy(&wma_handle->go_d3_wow_wake_lock); + qdf_wake_lock_destroy(&wma_handle->sap_d3_wow_wake_lock); +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_destroy(&wma_handle->extscan_wake_lock); +#endif /* FEATURE_WLAN_EXTSCAN */ + qdf_wake_lock_destroy(&wma_handle->wow_wake_lock); + qdf_wake_lock_destroy(&wma_handle->wow_auth_req_wl); + qdf_wake_lock_destroy(&wma_handle->wow_assoc_req_wl); + qdf_wake_lock_destroy(&wma_handle->wow_deauth_rec_wl); + qdf_wake_lock_destroy(&wma_handle->wow_disassoc_rec_wl); + qdf_wake_lock_destroy(&wma_handle->wow_ap_assoc_lost_wl); + qdf_wake_lock_destroy(&wma_handle->wow_auto_shutdown_wl); + qdf_wake_lock_destroy(&wma_handle->roam_ho_wl); + qdf_wake_lock_destroy(&wma_handle->roam_preauth_wl); + qdf_wake_lock_destroy(&wma_handle->probe_req_wps_wl); + } +err_free_wma_handle: + cds_free_context(QDF_MODULE_ID_WMA, wma_handle); + + wma_debug("Exit"); + + return qdf_status; +} + +/** + * wma_pre_start() - wma pre start + * + * Return: 0 on success, errno on failure + */ +QDF_STATUS wma_pre_start(void) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + void *htc_handle; + + wma_debug("Enter"); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + /* Validate the wma_handle */ + if (!wma_handle) { + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + htc_handle = lmac_get_htc_hdl(wma_handle->psoc); + if (!htc_handle) { + wma_err("invalid htc handle"); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + /* Open endpoint for ctrl path - WMI <--> HTC */ + qdf_status = wmi_unified_connect_htc_service(wma_handle->wmi_handle, + htc_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("wmi_unified_connect_htc_service"); + if (!cds_is_fw_down()) + QDF_BUG(0); + + qdf_status = QDF_STATUS_E_FAULT; + goto end; + } + + /* Open endpoint for wmi diag path */ + qdf_status = wmi_diag_connect_pdev_htc_service(wma_handle->wmi_handle, + htc_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("wmi_diag_connect_pdev_htc_service"); + if (!cds_is_fw_down()) + QDF_BUG(0); + + qdf_status = QDF_STATUS_E_FAULT; + goto end; + } + + wma_debug("WMA --> wmi_unified_connect_htc_service - success"); + +end: + wma_debug("Exit"); + return qdf_status; +} + +void wma_send_msg_by_priority(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val, bool is_high_priority) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + + msg.type = msg_type; + msg.bodyval = body_val; + msg.bodyptr = body_ptr; + msg.flush_callback = wma_discard_fw_event; + + status = scheduler_post_msg_by_priority(QDF_MODULE_ID_PE, + &msg, is_high_priority); + if (!QDF_IS_STATUS_SUCCESS(status)) { + if (body_ptr) + qdf_mem_free(body_ptr); + } +} + + +void wma_send_msg(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val) +{ + wma_send_msg_by_priority(wma_handle, msg_type, + body_ptr, body_val, false); +} + +void wma_send_msg_high_priority(tp_wma_handle wma_handle, uint16_t msg_type, + void *body_ptr, uint32_t body_val) +{ + wma_send_msg_by_priority(wma_handle, msg_type, + body_ptr, body_val, true); +} + +/** + * wma_set_base_macaddr_indicate() - set base mac address in fw + * @wma_handle: wma handle + * @customAddr: base mac address + * + * Return: 0 for success or error code + */ +static int wma_set_base_macaddr_indicate(tp_wma_handle wma_handle, + tSirMacAddr *customAddr) +{ + int err; + + err = wmi_unified_set_base_macaddr_indicate_cmd(wma_handle->wmi_handle, + (uint8_t *)customAddr); + if (err) + return -EIO; + wma_debug("Base MAC Addr: " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF((*customAddr))); + + return 0; +} + +/** + * wma_log_supported_evt_handler() - Enable/Disable FW diag/log events + * @handle: WMA handle + * @event: Event received from FW + * @len: Length of the event + * + * Enables the low frequency events and disables the high frequency + * events. Bit 17 indicates if the event if low/high frequency. + * 1 - high frequency, 0 - low frequency + * + * Return: 0 on successfully enabling/disabling the events + */ +static int wma_log_supported_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + + if (wmi_unified_log_supported_evt_cmd(wma->wmi_handle, + event, len)) + return -EINVAL; + + return 0; +} + +/** + * wma_pdev_set_hw_mode_resp_evt_handler() - Set HW mode resp evt handler + * @handle: WMI handle + * @event: Event received from FW + * @len: Length of the event + * + * Event handler for WMI_PDEV_SET_HW_MODE_RESP_EVENTID that is sent to host + * driver in response to a WMI_PDEV_SET_HW_MODE_CMDID being sent to WLAN + * firmware + * + * Return: QDF_STATUS + */ +static int wma_pdev_set_hw_mode_resp_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_PDEV_SET_HW_MODE_RESP_EVENTID_param_tlvs *param_buf; + wmi_pdev_set_hw_mode_response_event_fixed_param *wmi_event; + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry; + uint32_t i; + struct sir_set_hw_mode_resp *hw_mode_resp; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (wma_validate_handle(wma)) { + /* Since WMA handle itself is NULL, we cannot send fail + * response back to LIM here + */ + return QDF_STATUS_E_NULL_VALUE; + } + + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + wma_remove_req(wma, 0, WMA_PDEV_SET_HW_MODE_RESP); + + hw_mode_resp = qdf_mem_malloc(sizeof(*hw_mode_resp)); + if (!hw_mode_resp) { + /* Since this memory allocation itself failed, we cannot + * send fail response back to LIM here + */ + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_PDEV_SET_HW_MODE_RESP_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid WMI_PDEV_SET_HW_MODE_RESP_EVENTID event"); + /* Need to send response back to upper layer to free + * active command list + */ + goto fail; + } + if (param_buf->fixed_param->num_vdev_mac_entries >= + MAX_VDEV_SUPPORTED) { + wma_err("num_vdev_mac_entries crossed max value"); + goto fail; + } + + wmi_event = param_buf->fixed_param; + if (wmi_event->num_vdev_mac_entries > + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping) { + wma_err("Invalid num_vdev_mac_entries: %d", + wmi_event->num_vdev_mac_entries); + goto fail; + } + hw_mode_resp->status = wmi_event->status; + hw_mode_resp->cfgd_hw_mode_index = wmi_event->cfgd_hw_mode_index; + hw_mode_resp->num_vdev_mac_entries = wmi_event->num_vdev_mac_entries; + + wma->set_hw_mode_resp_status = wmi_event->status; + wma_debug("status:%d cfgd_hw_mode_index:%d num_vdev_mac_entries:%d", + wmi_event->status, + wmi_event->cfgd_hw_mode_index, + wmi_event->num_vdev_mac_entries); + vdev_mac_entry = + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping; + + /* Store the vdev-mac map in WMA and prepare to send to PE */ + for (i = 0; i < wmi_event->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id, pdev_id; + + vdev_id = vdev_mac_entry[i].vdev_id; + pdev_id = vdev_mac_entry[i].pdev_id; + if (pdev_id == OL_TXRX_PDEV_ID) { + wma_err("soc level id received for mac id"); + goto fail; + } + if (vdev_id >= wma->max_bssid) { + wma_err("vdev_id: %d is invalid, max_bssid: %d", + vdev_id, wma->max_bssid); + goto fail; + } + + mac_id = WMA_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + + wma_debug("vdev_id:%d mac_id:%d", vdev_id, mac_id); + + hw_mode_resp->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_resp->vdev_mac_map[i].mac_id = mac_id; + wma_update_intf_hw_mode_params(vdev_id, mac_id, + wmi_event->cfgd_hw_mode_index); + } + + if (hw_mode_resp->status == SET_HW_MODE_STATUS_OK) { + if (WMA_DEFAULT_HW_MODE_INDEX == wma->new_hw_mode_index) { + wma->new_hw_mode_index = wmi_event->cfgd_hw_mode_index; + } else { + wma->old_hw_mode_index = wma->new_hw_mode_index; + wma->new_hw_mode_index = wmi_event->cfgd_hw_mode_index; + } + policy_mgr_update_hw_mode_index(wma->psoc, + wmi_event->cfgd_hw_mode_index); + } + + wma_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + wma->old_hw_mode_index, wma->new_hw_mode_index); + + wma_send_msg(wma, SIR_HAL_PDEV_SET_HW_MODE_RESP, + (void *) hw_mode_resp, 0); + + return QDF_STATUS_SUCCESS; + +fail: + wma_err("Sending fail response to LIM"); + hw_mode_resp->status = SET_HW_MODE_STATUS_ECANCELED; + hw_mode_resp->cfgd_hw_mode_index = 0; + hw_mode_resp->num_vdev_mac_entries = 0; + wma_send_msg(wma, SIR_HAL_PDEV_SET_HW_MODE_RESP, + (void *) hw_mode_resp, 0); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_process_pdev_hw_mode_trans_ind() - Process HW mode transition info + * + * @handle: WMA handle + * @fixed_param: Event fixed parameters + * @vdev_mac_entry: vdev mac entry + * @hw_mode_trans_ind: Buffer to store parsed information + * + * Parses fixed_param, vdev_mac_entry and fills in the information into + * hw_mode_trans_ind and wma + * + * Return: None + */ +void wma_process_pdev_hw_mode_trans_ind(void *handle, + wmi_pdev_hw_mode_transition_event_fixed_param *fixed_param, + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind) +{ + uint32_t i; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (fixed_param->num_vdev_mac_entries > MAX_VDEV_SUPPORTED) { + wma_err("Number of Vdev mac entries %d exceeded max vdev supported %d", + fixed_param->num_vdev_mac_entries, + MAX_VDEV_SUPPORTED); + return; + } + hw_mode_trans_ind->old_hw_mode_index = fixed_param->old_hw_mode_index; + hw_mode_trans_ind->new_hw_mode_index = fixed_param->new_hw_mode_index; + hw_mode_trans_ind->num_vdev_mac_entries = + fixed_param->num_vdev_mac_entries; + + if (!vdev_mac_entry) { + wma_debug("null vdev_mac_entry"); + goto update_hw_mode; + } + + /* Store the vdev-mac map in WMA and send to policy manager */ + for (i = 0; i < fixed_param->num_vdev_mac_entries; i++) { + uint32_t vdev_id, mac_id, pdev_id; + + vdev_id = vdev_mac_entry[i].vdev_id; + pdev_id = vdev_mac_entry[i].pdev_id; + + if (pdev_id == OL_TXRX_PDEV_ID) { + wma_err("soc level id received for mac id"); + return; + } + if (vdev_id >= wma->max_bssid) { + wma_err("vdev_id: %d is invalid, max_bssid: %d", + vdev_id, wma->max_bssid); + return; + } + + mac_id = WMA_PDEV_TO_MAC_MAP(vdev_mac_entry[i].pdev_id); + hw_mode_trans_ind->vdev_mac_map[i].vdev_id = vdev_id; + hw_mode_trans_ind->vdev_mac_map[i].mac_id = mac_id; + wma_update_intf_hw_mode_params(vdev_id, mac_id, + fixed_param->new_hw_mode_index); + } +update_hw_mode: + wma->old_hw_mode_index = fixed_param->old_hw_mode_index; + wma->new_hw_mode_index = fixed_param->new_hw_mode_index; + policy_mgr_update_new_hw_mode_index(wma->psoc, + fixed_param->new_hw_mode_index); + policy_mgr_update_old_hw_mode_index(wma->psoc, + fixed_param->old_hw_mode_index); +} + +static void +wma_process_mac_freq_mapping(struct cm_hw_mode_trans_ind *hw_mode_trans_ind, + WMI_PDEV_HW_MODE_TRANSITION_EVENTID_param_tlvs *param_buf) +{ + uint32_t i, num_mac_freq; + wmi_pdev_band_to_mac *mac_freq; + + mac_freq = param_buf->mac_freq_mapping; + num_mac_freq = param_buf->num_mac_freq_mapping; + + if (!mac_freq) { + wma_debug("mac_freq Null"); + return; + } + + if (!num_mac_freq || num_mac_freq > MAX_FREQ_RANGE_NUM) { + wma_debug("num mac freq invalid %d", num_mac_freq); + return; + } + + hw_mode_trans_ind->num_freq_map = num_mac_freq; + for (i = 0; i < num_mac_freq; i++) { + hw_mode_trans_ind->mac_freq_map[i].mac_id = + WMA_PDEV_TO_MAC_MAP(mac_freq[i].pdev_id); + hw_mode_trans_ind->mac_freq_map[i].start_freq = + mac_freq[i].start_freq; + hw_mode_trans_ind->mac_freq_map[i].end_freq = + mac_freq[i].end_freq; + } +} + +/** + * wma_pdev_hw_mode_transition_evt_handler() - HW mode transition evt handler + * @handle: WMI handle + * @event: Event received from FW + * @len: Length of the event + * + * Event handler for WMI_PDEV_HW_MODE_TRANSITION_EVENTID that indicates an + * asynchronous hardware mode transition. This event notifies the host driver + * that firmware independently changed the hardware mode for some reason, such + * as Coex, LFR 3.0, etc + * + * Return: Success on receiving valid params from FW + */ +static int wma_pdev_hw_mode_transition_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_PDEV_HW_MODE_TRANSITION_EVENTID_param_tlvs *param_buf; + wmi_pdev_hw_mode_transition_event_fixed_param *wmi_event; + wmi_pdev_set_hw_mode_response_vdev_mac_entry *vdev_mac_entry; + struct cm_hw_mode_trans_ind *hw_mode_trans_ind; + tp_wma_handle wma = (tp_wma_handle) handle; + + if (wma_validate_handle(wma)) { + /* This is an async event. So, not sending any event to LIM */ + return QDF_STATUS_E_NULL_VALUE; + } + + param_buf = (WMI_PDEV_HW_MODE_TRANSITION_EVENTID_param_tlvs *) event; + if (!param_buf) { + /* This is an async event. So, not sending any event to LIM */ + wma_err("Invalid WMI_PDEV_HW_MODE_TRANSITION_EVENTID event"); + return QDF_STATUS_E_FAILURE; + } + + if (param_buf->fixed_param->num_vdev_mac_entries > MAX_VDEV_SUPPORTED) { + wma_err("num_vdev_mac_entries: %d crossed max value: %d", + param_buf->fixed_param->num_vdev_mac_entries, + MAX_VDEV_SUPPORTED); + return QDF_STATUS_E_FAILURE; + } + + hw_mode_trans_ind = qdf_mem_malloc(sizeof(*hw_mode_trans_ind)); + if (!hw_mode_trans_ind) + return QDF_STATUS_E_NOMEM; + + wmi_event = param_buf->fixed_param; + vdev_mac_entry = + param_buf->wmi_pdev_set_hw_mode_response_vdev_mac_mapping; + if (wmi_event->num_vdev_mac_entries > + param_buf->num_wmi_pdev_set_hw_mode_response_vdev_mac_mapping) { + wma_err("Invalid num_vdev_mac_entries: %d", + wmi_event->num_vdev_mac_entries); + qdf_mem_free(hw_mode_trans_ind); + return -EINVAL; + } + + wma_process_pdev_hw_mode_trans_ind(wma, wmi_event, vdev_mac_entry, + hw_mode_trans_ind); + wma_process_mac_freq_mapping(hw_mode_trans_ind, param_buf); + + if (policy_mgr_is_hwmode_offload_enabled(wma->psoc)) { + policy_mgr_hw_mode_transition_cb( + hw_mode_trans_ind->old_hw_mode_index, + hw_mode_trans_ind->new_hw_mode_index, + hw_mode_trans_ind->num_vdev_mac_entries, + hw_mode_trans_ind->vdev_mac_map, + hw_mode_trans_ind->num_freq_map, + hw_mode_trans_ind->mac_freq_map, + wma->psoc); + qdf_mem_free(hw_mode_trans_ind); + } else { + struct scheduler_msg sme_msg = {0}; + QDF_STATUS status; + + wma_debug("post eWNI_SME_HW_MODE_TRANS_IND"); + sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND; + sme_msg.bodyptr = hw_mode_trans_ind; + sme_msg.flush_callback = wma_discard_fw_event; + + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(hw_mode_trans_ind); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_pdev_set_dual_mode_config_resp_evt_handler() - Dual mode evt handler + * @handle: WMI handle + * @event: Event received from FW + * @len: Length of the event + * + * Notifies the host driver of the completion or failure of a + * WMI_PDEV_SET_MAC_CONFIG_CMDID command. This event would be returned to + * the host driver once the firmware has completed a reconfiguration of the Scan + * and FW mode configuration. This changes could include entering or leaving a + * dual mac configuration for either scan and/or more permanent firmware mode. + * + * Return: Success on receiving valid params from FW + */ +static int wma_pdev_set_dual_mode_config_resp_evt_handler(void *handle, + uint8_t *event, + uint32_t len) +{ + WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID_param_tlvs *param_buf; + wmi_pdev_set_mac_config_response_event_fixed_param *wmi_event; + tp_wma_handle wma = (tp_wma_handle) handle; + struct sir_dual_mac_config_resp *dual_mac_cfg_resp; + + if (wma_validate_handle(wma)) { + /* Since the WMA handle is NULL, we cannot send resp to LIM. + * So, returning from here. + */ + return QDF_STATUS_E_NULL_VALUE; + } + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + wma_remove_req(wma, 0, WMA_PDEV_MAC_CFG_RESP); + + dual_mac_cfg_resp = qdf_mem_malloc(sizeof(*dual_mac_cfg_resp)); + if (!dual_mac_cfg_resp) + /* Since the mem alloc failed, we cannot send resp to LIM. + * So, returning from here. + */ + return QDF_STATUS_E_NULL_VALUE; + + param_buf = (WMI_PDEV_SET_MAC_CONFIG_RESP_EVENTID_param_tlvs *) + event; + if (!param_buf) { + wma_err("Invalid event"); + goto fail; + } + + wmi_event = param_buf->fixed_param; + wma_debug("status: %d", wmi_event->status); + dual_mac_cfg_resp->status = wmi_event->status; + + if (SET_HW_MODE_STATUS_OK == dual_mac_cfg_resp->status) { + policy_mgr_update_dbs_scan_config(wma->psoc); + policy_mgr_update_dbs_fw_config(wma->psoc); + } + + /* Pass the message to PE */ + wma_send_msg(wma, SIR_HAL_PDEV_MAC_CFG_RESP, + (void *) dual_mac_cfg_resp, 0); + + return QDF_STATUS_SUCCESS; + +fail: + wma_err("Sending fail response to LIM"); + dual_mac_cfg_resp->status = SET_HW_MODE_STATUS_ECANCELED; + wma_send_msg(wma, SIR_HAL_PDEV_MAC_CFG_RESP, + (void *) dual_mac_cfg_resp, 0); + + return QDF_STATUS_E_FAILURE; + +} + +#ifdef WLAN_CONV_SPECTRAL_ENABLE +static void wma_register_spectral_cmds(tp_wma_handle wma_handle) +{ + struct spectral_wmi_ops cmd_ops; + + cmd_ops.wmi_spectral_configure_cmd_send = + wmi_unified_vdev_spectral_configure_cmd_send; + cmd_ops.wmi_spectral_enable_cmd_send = + wmi_unified_vdev_spectral_enable_cmd_send; + wlan_register_spectral_wmi_ops(wma_handle->psoc, &cmd_ops); +} +#else +static void wma_register_spectral_cmds(tp_wma_handle wma_handle) +{ +} +#endif +/** + * wma_start() - wma start function. + * Initialize event handlers and timers. + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_start(void) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + struct wmi_unified *wmi_handle; + struct mac_context *mac = NULL; + + wma_debug("Enter"); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + if (wmi_validate_handle(wmi_handle)) { + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_wow_wakeup_host_event_id, + wma_wow_wakeup_host_event, + WMA_RX_TASKLET_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register wow wakeup host event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + if (wma_d0_wow_is_supported()) { + qdf_status = wmi_unified_register_event_handler( + wmi_handle, + wmi_d0_wow_disable_ack_event_id, + wma_d0_wow_disable_ack_event, + WMA_RX_TASKLET_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register d0wow disable ack event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + } + + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_resume_event_id, + wma_pdev_resume_event_handler, + WMA_RX_TASKLET_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register PDEV resume event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } +#if defined(QCA_LL_LEGACY_TX_FLOW_CONTROL) || \ + defined(QCA_LL_TX_FLOW_CONTROL_V2) || defined(CONFIG_HL_SUPPORT) + wma_debug("MCC TX Pause Event Handler register"); + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_tx_pause_event_id, + wma_mcc_vdev_tx_pause_evt_handler, + WMA_RX_TASKLET_CTX); +#endif /* QCA_LL_LEGACY_TX_FLOW_CONTROL */ + + wma_debug("Registering SAR2 response handler"); + qdf_status = wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_wlan_sar2_result_event_id, + wma_sar_rsp_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register sar response event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + wma_debug("Registering auto shutdown handler"); + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_host_auto_shutdown_event_id, + wma_auto_shutdown_event_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register WMI Auto shutdown event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_thermal_mgmt_event_id, + wma_thermal_mgmt_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register thermal mitigation event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_status = wma_ocb_register_callbacks(wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register OCB callbacks"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_status = QDF_STATUS_SUCCESS; + +#ifdef QCA_WIFI_FTM + /* + * Tx mgmt attach requires TXRX context which is not created + * in FTM mode. So skip the TX mgmt attach. + */ + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + goto end; +#endif /* QCA_WIFI_FTM */ + + qdf_status = wma_tx_attach(wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register tx management"); + goto end; + } + + /* Initialize log completion timeout */ + qdf_status = qdf_mc_timer_init(&wma_handle->log_completion_timer, + QDF_TIMER_TYPE_SW, + wma_log_completion_timeout, + wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to initialize log completion timeout"); + goto end; + } + + qdf_status = wma_fips_register_event_handlers(wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register FIPS event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_status = wma_sar_register_event_handlers(wma_handle); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register SAR event handlers"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the get temperature event handler */ + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_temperature_event_id, + wma_pdev_temperature_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register get_temperature event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_vdev_tsf_report_event_id, + wma_vdev_tsf_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register tsf callback"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the wma_pdev_set_hw_mode_resp_evt_handler event handler */ + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_set_hw_mode_rsp_event_id, + wma_pdev_set_hw_mode_resp_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register set hw mode resp event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the WMI_SOC_HW_MODE_TRANSITION_EVENTID event handler */ + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_hw_mode_transition_event_id, + wma_pdev_hw_mode_transition_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register hw mode transition event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + /* Initialize the set dual mac configuration event handler */ + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_pdev_set_mac_config_resp_event_id, + wma_pdev_set_dual_mode_config_resp_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register hw mode transition event cb"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + + qdf_status = wmi_unified_register_event_handler(wmi_handle, + wmi_coex_bt_activity_event_id, + wma_wlan_bt_activity_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to register coex bt activity event handler"); + qdf_status = QDF_STATUS_E_FAILURE; + goto end; + } + wma_register_spectral_cmds(wma_handle); + +end: + wma_debug("Exit"); + return qdf_status; +} + +QDF_STATUS wma_stop(void) +{ + tp_wma_handle wma_handle; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int i; + struct mac_context *mac = NULL; + struct wlan_objmgr_vdev *vdev; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + wma_debug("Enter"); + if (!wma_handle) { + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + mac = cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + goto end; + } +#ifdef QCA_WIFI_FTM + /* + * Tx mgmt detach requires TXRX context which is not created + * in FTM mode. So skip the TX mgmt detach. + */ + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) { + qdf_status = QDF_STATUS_SUCCESS; + goto end; + } +#endif /* QCA_WIFI_FTM */ + + if (wma_handle->ack_work_ctx) { + cds_flush_work(&wma_handle->ack_work_ctx->ack_cmp_work); + if (wma_handle->ack_work_ctx->frame) + qdf_nbuf_free(wma_handle->ack_work_ctx->frame); + + qdf_mem_free(wma_handle->ack_work_ctx); + wma_handle->ack_work_ctx = NULL; + } + + /* Destroy the timer for log completion */ + qdf_status = qdf_mc_timer_destroy(&wma_handle->log_completion_timer); + if (qdf_status != QDF_STATUS_SUCCESS) + wma_err("Failed to destroy the log completion timer"); + /* clean up ll-queue for all vdev */ + for (i = 0; i < wma_handle->max_bssid; i++) { + vdev = wma_handle->interfaces[i].vdev; + if (!vdev) + continue; + + if (wma_is_vdev_up(i)) + cdp_fc_vdev_flush(cds_get_context(QDF_MODULE_ID_SOC), + i); + } + + qdf_status = wma_tx_detach(wma_handle); + if (qdf_status != QDF_STATUS_SUCCESS) { + wma_err("Failed to deregister tx management"); + goto end; + } + +end: + wma_debug("Exit"); + return qdf_status; +} + +/** + * wma_wmi_service_close() - close wma wmi service interface. + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_wmi_service_close(void) +{ + void *cds_ctx; + tp_wma_handle wma_handle; + uint8_t i; + struct wmi_unified *wmi_handle; + + wma_debug("Enter"); + + cds_ctx = cds_get_global_context(); + if (!cds_ctx) { + wma_err("Invalid CDS context"); + return QDF_STATUS_E_INVAL; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + /* detach the wmi service */ + wma_debug("calling wmi_unified_detach"); + wmi_unified_detach(wmi_handle); + wma_handle->wmi_handle = NULL; + + for (i = 0; i < wma_handle->max_bssid; i++) + wma_vdev_deinit(&wma_handle->interfaces[i]); + + qdf_mem_free(wma_handle->interfaces); + + /* free the wma_handle */ + cds_free_context(QDF_MODULE_ID_WMA, wma_handle); + + if (((struct cds_context *)cds_ctx)->cfg_ctx) + qdf_mem_free(((struct cds_context *)cds_ctx)->cfg_ctx); + ((struct cds_context *)cds_ctx)->cfg_ctx = NULL; + wma_debug("Exit"); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_wmi_work_close() - close the work queue items associated with WMI + * + * This function closes work queue items associated with WMI, but not fully + * closes WMI service. + * + * Return: QDF_STATUS_SUCCESS if work close is successful. Otherwise + * proper error codes. + */ +QDF_STATUS wma_wmi_work_close(void) +{ + tp_wma_handle wma_handle; + struct wmi_unified *wmi_handle; + + wma_debug("Enter"); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + /* remove the wmi work */ + wma_debug("calling wmi_unified_remove_work"); + wmi_unified_remove_work(wmi_handle); + + wma_debug("Exit"); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_close() - wma close function. + * cleanup resources attached with wma. + * + * Return: 0 on success, QDF Error on failure + */ +QDF_STATUS wma_close(void) +{ + tp_wma_handle wma_handle; + struct target_psoc_info *tgt_psoc_info; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct wmi_unified *wmi_handle; + + wma_debug("Enter"); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wlan_pmo_no_op_on_page_fault(wma_handle->psoc)) + wma_deinit_pagefault_wakeup_history(wma_handle); + + qdf_atomic_set(&wma_handle->sap_num_clients_connected, 0); + qdf_atomic_set(&wma_handle->go_num_clients_connected, 0); + + if (cds_get_conparam() != QDF_GLOBAL_FTM_MODE) { + qdf_wake_lock_destroy(&wma_handle->go_d3_wow_wake_lock); + qdf_wake_lock_destroy(&wma_handle->sap_d3_wow_wake_lock); +#ifdef FEATURE_WLAN_EXTSCAN + qdf_wake_lock_destroy(&wma_handle->extscan_wake_lock); +#endif /* FEATURE_WLAN_EXTSCAN */ + qdf_wake_lock_destroy(&wma_handle->wow_wake_lock); + qdf_wake_lock_destroy(&wma_handle->wow_auth_req_wl); + qdf_wake_lock_destroy(&wma_handle->wow_assoc_req_wl); + qdf_wake_lock_destroy(&wma_handle->wow_deauth_rec_wl); + qdf_wake_lock_destroy(&wma_handle->wow_disassoc_rec_wl); + qdf_wake_lock_destroy(&wma_handle->wow_ap_assoc_lost_wl); + qdf_wake_lock_destroy(&wma_handle->wow_auto_shutdown_wl); + qdf_wake_lock_destroy(&wma_handle->roam_ho_wl); + qdf_wake_lock_destroy(&wma_handle->roam_preauth_wl); + qdf_wake_lock_destroy(&wma_handle->probe_req_wps_wl); + } + + /* unregister Firmware debug log */ + qdf_status = dbglog_deinit(wmi_handle); + if (qdf_status != QDF_STATUS_SUCCESS) + wma_err("dbglog_deinit failed"); + + qdf_status = qdf_mc_timer_destroy(&wma_handle->service_ready_ext_timer); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + wma_err("Failed to destroy service ready ext event timer"); + + qdf_event_destroy(&wma_handle->target_suspend); + qdf_event_destroy(&wma_handle->runtime_suspend); + qdf_event_destroy(&wma_handle->recovery_event); + qdf_event_destroy(&wma_handle->tx_frm_download_comp_event); + qdf_event_destroy(&wma_handle->tx_queue_empty_event); + wma_cleanup_hold_req(wma_handle); + qdf_wake_lock_destroy(&wma_handle->wmi_cmd_rsp_wake_lock); + qdf_runtime_lock_deinit(&wma_handle->ndp_prevent_runtime_pm_lock); + qdf_runtime_lock_deinit(&wma_handle->sap_prevent_runtime_pm_lock); + qdf_runtime_lock_deinit(&wma_handle->wmi_cmd_rsp_runtime_lock); + qdf_spinlock_destroy(&wma_handle->wma_hold_req_q_lock); + + if (wma_handle->pGetRssiReq) { + qdf_mem_free(wma_handle->pGetRssiReq); + wma_handle->pGetRssiReq = NULL; + } + + wma_unified_radio_tx_mem_free(wma_handle); + + qdf_status = qdf_mutex_destroy(&wma_handle->radio_stats_lock); + if (QDF_IS_STATUS_ERROR(qdf_status)) + wma_err("Failed to destroy radio stats mutex"); + + if (wma_handle->pdev) { + wlan_objmgr_pdev_release_ref(wma_handle->pdev, + WLAN_LEGACY_WMA_ID); + wma_handle->pdev = NULL; + } + + pmo_unregister_get_beacon_interval_callback(wma_handle->psoc); + pmo_unregister_get_dtim_period_callback(wma_handle->psoc); + pmo_unregister_is_device_in_low_pwr_mode(wma_handle->psoc); + pmo_unregister_get_pause_bitmap(wma_handle->psoc); + pmo_unregister_pause_bitmap_notifier(wma_handle->psoc); + + tgt_psoc_info = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + init_deinit_free_num_units(wma_handle->psoc, tgt_psoc_info); + target_if_free_psoc_tgt_info(wma_handle->psoc); + + wlan_objmgr_psoc_release_ref(wma_handle->psoc, WLAN_LEGACY_WMA_ID); + wma_handle->psoc = NULL; + + wma_debug("Exit"); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_fw_config() - update fw configuration + * @psoc: psoc to query configuration from + * @tgt_hdl: target capability info + * + * Return: none + */ +static void wma_update_fw_config(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl) +{ + target_resource_config *cfg = &tgt_hdl->info.wlan_res_cfg; + + /* Override the no. of max fragments as per platform configuration */ + cfg->max_frag_entries = QDF_MIN(QCA_OL_11AC_TX_MAX_FRAGS, + target_if_get_max_frag_entry(tgt_hdl)); + target_if_set_max_frag_entry(tgt_hdl, cfg->max_frag_entries); + + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + cfg->num_wow_filters = 0; + else + cfg->num_wow_filters = ucfg_pmo_get_num_wow_filters(psoc); + + cfg->apf_instruction_size = ucfg_pmo_get_apf_instruction_size(psoc); + cfg->num_packet_filters = ucfg_pmo_get_num_packet_filters(psoc); +} + +/** + * wma_set_tx_partition_base() - set TX MSDU ID partition base for IPA + * @value: TX MSDU ID partition base + * + * Return: none + */ +#ifdef IPA_OFFLOAD +static void wma_set_tx_partition_base(uint32_t value) +{ + cdp_ipa_set_uc_tx_partition_base( + cds_get_context(QDF_MODULE_ID_SOC), + (struct cdp_cfg *)cds_get_context(QDF_MODULE_ID_CFG), + value); + wma_debug("TX_MSDU_ID_PARTITION=%d", value); +} +#else +static void wma_set_tx_partition_base(uint32_t value) +{ +} +#endif + +#ifdef WLAN_FEATURE_IGMP_OFFLOAD +/** + * wma_get_igmp_offload_enable() - update tgt service with igmp offload support + * @wmi_handle: Unified wmi handle + * @cfg: target services + * + * Return: none + */ +static inline void +wma_get_igmp_offload_enable(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->igmp_offload_enable = wmi_service_enabled( + wmi_handle, + wmi_service_igmp_offload_support); +} +#else +static inline void +wma_get_igmp_offload_enable(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} +#endif + +#ifdef FEATURE_WLAN_TDLS +/** + * wma_get_tdls_wideband_support() - update tgt service with service tdls + * wideband support + * @wmi_handle: Unified wmi handle + * @cfg: target services + * + * Return: none + */ +static inline void +wma_get_tdls_wideband_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_tdls_wideband_support = wmi_service_enabled( + wmi_handle, + wmi_service_tdls_wideband_support); +} + +#ifdef WLAN_FEATURE_11BE +/** + * wma_get_tdls_mlo_support() - update tgt service with service tdls + * be support + * @wmi_handle: Unified wmi handle + * @cfg: target services + * + * Return: none + */ +static inline void +wma_get_tdls_mlo_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_tdls_mlo_support = + wmi_service_enabled(wmi_handle, + wmi_service_tdls_mlo_support); +} + +static inline void +wma_get_n_link_mlo_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_n_link_mlo_support = + wmi_service_enabled(wmi_handle, + wmi_service_n_link_mlo_support); +} + +#else +static inline void +wma_get_tdls_mlo_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ +} + +static inline void +wma_get_n_link_mlo_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ +} +#endif /* WLAN_FEATURE_11BE */ + +#ifdef WLAN_FEATURE_11AX +/** + * wma_get_tdls_ax_support() - update tgt service with service tdls ax support + * @wmi_handle: Unified wmi handle + * @cfg: target services + * + * Return: none + */ +static inline void +wma_get_tdls_ax_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_tdls_11ax_support = wmi_service_enabled( + wmi_handle, + wmi_service_tdls_ax_support); +} + +static inline void +wma_get_tdls_6g_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_tdls_6g_support = wmi_service_enabled( + wmi_handle, + wmi_service_tdls_6g_support); +} + +#else +static inline void +wma_get_tdls_ax_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} + +static inline void +wma_get_tdls_6g_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} + +#endif +#else +static inline void +wma_get_tdls_mlo_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ +} + +static inline void +wma_get_n_link_mlo_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} + +static inline void +wma_get_tdls_ax_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} + +static inline void +wma_get_tdls_6g_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} + +static inline void +wma_get_tdls_wideband_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{} +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_MAC_ADDR_UPDATE +static inline void wma_get_dynamic_vdev_macaddr_support( + struct wmi_unified *wmi_handle, struct wma_tgt_services *cfg) +{ + cfg->dynamic_vdev_macaddr_support = + wmi_service_enabled( + wmi_handle, + wmi_service_dynamic_update_vdev_macaddr_support); +} +#else +static inline void wma_get_dynamic_vdev_macaddr_support( + struct wmi_unified *wmi_handle, struct wma_tgt_services *cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * wma_get_mlo_tid_to_link_mapping_support() - update tgt service with + * service tid to link mapping support + * @wmi_handle: Unified wmi handle + * @cfg: target services + * + * Return: none + */ +static inline void +wma_get_mlo_tid_to_link_mapping_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + cfg->en_mlo_tid_to_link_support = + wmi_service_enabled(wmi_handle, + wmi_service_mlo_tid_to_link_mapping_support); +} + +#else +static inline void +wma_get_mlo_tid_to_link_mapping_support(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ +} +#endif + +#ifdef WLAN_FEATURE_NAN +/** + * wma_nan_set_pairing_feature() - set feature bit for Secure NAN if max + * pairing session has non-zero value. + * + * Return: none + */ +static void wma_nan_set_pairing_feature(void) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct target_psoc_info *tgt_hdl; + struct wlan_objmgr_psoc *psoc; + + if (!wma_handle) { + wma_err("wma handle is null"); + return; + } + + psoc = wma_handle->psoc; + tgt_hdl = wlan_psoc_get_tgt_if_handle(psoc); + if (!tgt_hdl) { + wma_err("tgt_hdl is null"); + return; + } + + if (tgt_hdl->info.service_ext2_param.max_nan_pairing_sessions) { + wma_set_fw_wlan_feat_caps(SECURE_NAN); + wma_debug("Secure NAN is enabled"); + } +} +#endif /* WLAN_FEATURE_NAN */ + +/** + * wma_update_target_services() - update target services from wma handle + * @wmi_handle: Unified wmi handle + * @cfg: target services + * + * Return: none + */ +static inline void wma_update_target_services(struct wmi_unified *wmi_handle, + struct wma_tgt_services *cfg) +{ + /* STA power save */ + cfg->sta_power_save = wmi_service_enabled(wmi_handle, + wmi_service_sta_pwrsave); + + /* Enable UAPSD */ + cfg->uapsd = wmi_service_enabled(wmi_handle, + wmi_service_ap_uapsd); + + /* Update AP DFS service */ + cfg->ap_dfs = wmi_service_enabled(wmi_handle, + wmi_service_ap_dfs); + + /* Enable 11AC */ + cfg->en_11ac = wmi_service_enabled(wmi_handle, + wmi_service_11ac); + if (cfg->en_11ac) + g_fw_wlan_feat_caps |= (1 << DOT11AC); + + /* Proactive ARP response */ + g_fw_wlan_feat_caps |= (1 << WLAN_PERIODIC_TX_PTRN); + + /* Enable WOW */ + g_fw_wlan_feat_caps |= (1 << WOW); + + /* ARP offload */ + cfg->arp_offload = wmi_service_enabled(wmi_handle, + wmi_service_arpns_offload); + + /* Adaptive early-rx */ + cfg->early_rx = wmi_service_enabled(wmi_handle, + wmi_service_early_rx); + + cfg->is_fw_therm_throt_supp = wmi_service_enabled(wmi_handle, + wmi_service_tt); + +#ifdef FEATURE_WLAN_SCAN_PNO + /* PNO offload */ + if (wmi_service_enabled(wmi_handle, wmi_service_nlo)) { + cfg->pno_offload = true; + g_fw_wlan_feat_caps |= (1 << PNO); + } +#endif /* FEATURE_WLAN_SCAN_PNO */ + +#ifdef FEATURE_WLAN_EXTSCAN + if (wmi_service_enabled(wmi_handle, wmi_service_extscan)) + g_fw_wlan_feat_caps |= (1 << EXTENDED_SCAN); +#endif /* FEATURE_WLAN_EXTSCAN */ + cfg->lte_coex_ant_share = wmi_service_enabled(wmi_handle, + wmi_service_lte_ant_share_support); +#ifdef FEATURE_WLAN_TDLS + /* Enable TDLS */ + if (wmi_service_enabled(wmi_handle, wmi_service_tdls)) { + cfg->en_tdls = 1; + g_fw_wlan_feat_caps |= (1 << TDLS); + } + /* Enable advanced TDLS features */ + if (wmi_service_enabled(wmi_handle, wmi_service_tdls_offchan)) { + cfg->en_tdls_offchan = 1; + g_fw_wlan_feat_caps |= (1 << TDLS_OFF_CHANNEL); + } + + cfg->en_tdls_uapsd_buf_sta = + wmi_service_enabled(wmi_handle, + wmi_service_tdls_uapsd_buffer_sta); + cfg->en_tdls_uapsd_sleep_sta = + wmi_service_enabled(wmi_handle, + wmi_service_tdls_uapsd_sleep_sta); +#endif /* FEATURE_WLAN_TDLS */ + if (wmi_service_enabled + (wmi_handle, wmi_service_beacon_offload)) + cfg->beacon_offload = true; + if (wmi_service_enabled + (wmi_handle, wmi_service_sta_pmf_offload)) + cfg->pmf_offload = true; +#ifdef WLAN_FEATURE_ROAM_OFFLOAD + /* Enable Roam Offload */ + cfg->en_roam_offload = wmi_service_enabled(wmi_handle, + wmi_service_roam_ho_offload); +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ +#ifdef WLAN_FEATURE_NAN + if (wmi_service_enabled(wmi_handle, wmi_service_nan)) + g_fw_wlan_feat_caps |= (1 << NAN); + wma_nan_set_pairing_feature(); +#endif /* WLAN_FEATURE_NAN */ + + if (wmi_service_enabled(wmi_handle, wmi_service_rtt)) + g_fw_wlan_feat_caps |= (1 << RTT); + + if (wmi_service_enabled(wmi_handle, + wmi_service_tx_msdu_id_new_partition_support)) { + wma_set_tx_partition_base(HTT_TX_IPA_NEW_MSDU_ID_SPACE_BEGIN); + } else { + wma_set_tx_partition_base(HTT_TX_IPA_MSDU_ID_SPACE_BEGIN); + } + + wma_he_update_tgt_services(wmi_handle, cfg); + wma_eht_update_tgt_services(wmi_handle, cfg); + + cfg->get_peer_info_enabled = + wmi_service_enabled(wmi_handle, + wmi_service_peer_stats_info); + if (wmi_service_enabled(wmi_handle, wmi_service_fils_support)) + cfg->is_fils_roaming_supported = true; + + if (wmi_service_enabled(wmi_handle, wmi_service_mawc_support)) + cfg->is_fw_mawc_capable = true; + + if (wmi_service_enabled(wmi_handle, + wmi_service_11k_neighbour_report_support)) + cfg->is_11k_offload_supported = true; + + if (wmi_service_enabled(wmi_handle, wmi_service_twt_requestor)) + cfg->twt_requestor = true; + if (wmi_service_enabled(wmi_handle, wmi_service_twt_responder)) + cfg->twt_responder = true; + if (wmi_service_enabled(wmi_handle, wmi_service_obss_scan)) + cfg->obss_scan_offload = true; + if (wmi_service_enabled(wmi_handle, wmi_service_beacon_reception_stats)) + cfg->bcn_reception_stats = true; + + if (wmi_service_enabled(wmi_handle, wmi_service_vdev_latency_config)) + g_fw_wlan_feat_caps |= (1 << VDEV_LATENCY_CONFIG); + if (wmi_service_enabled(wmi_handle, + wmi_roam_scan_chan_list_to_host_support)) + cfg->is_roam_scan_ch_to_host = true; + + cfg->ll_stats_per_chan_rx_tx_time = + wmi_service_enabled(wmi_handle, + wmi_service_ll_stats_per_chan_rx_tx_time); + + wma_get_service_cap_club_get_sta_in_ll_stats_req(wmi_handle, cfg); + + wma_get_igmp_offload_enable(wmi_handle, cfg); + wma_get_tdls_ax_support(wmi_handle, cfg); + wma_get_tdls_mlo_support(wmi_handle, cfg); + wma_get_tdls_6g_support(wmi_handle, cfg); + wma_get_tdls_wideband_support(wmi_handle, cfg); + wma_get_dynamic_vdev_macaddr_support(wmi_handle, cfg); + wma_get_service_cap_per_link_mlo_stats(wmi_handle, cfg); + wma_get_n_link_mlo_support(wmi_handle, cfg); + wma_get_mlo_tid_to_link_mapping_support(wmi_handle, cfg); +} + +/** + * wma_update_target_ht_cap() - update ht capabality from wma handle + * @tgt_hdl: pointer to structure target_psoc_info + * @cfg: ht capability + * + * Return: none + */ +static inline void +wma_update_target_ht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_ht_cap *cfg) +{ + int ht_cap_info; + + ht_cap_info = target_if_get_ht_cap_info(tgt_hdl); + /* RX STBC */ + cfg->ht_rx_stbc = !!(ht_cap_info & WMI_HT_CAP_RX_STBC); + + /* TX STBC */ + cfg->ht_tx_stbc = !!(ht_cap_info & WMI_HT_CAP_TX_STBC); + + /* MPDU density */ + cfg->mpdu_density = ht_cap_info & WMI_HT_CAP_MPDU_DENSITY; + + /* HT RX LDPC */ + cfg->ht_rx_ldpc = !!(ht_cap_info & WMI_HT_CAP_LDPC); + + /* HT SGI */ + cfg->ht_sgi_20 = !!(ht_cap_info & WMI_HT_CAP_HT20_SGI); + + cfg->ht_sgi_40 = !!(ht_cap_info & WMI_HT_CAP_HT40_SGI); + + cfg->dynamic_smps = !!(ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS); + + /* RF chains */ + cfg->num_rf_chains = target_if_get_num_rf_chains(tgt_hdl); + + wma_nofl_debug("ht_cap_info - %x ht_rx_stbc - %d, ht_tx_stbc - %d\n" + "mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n" + "ht_sgi_40 - %d num_rf_chains - %d dynamic_smps - %d", + ht_cap_info, + cfg->ht_rx_stbc, cfg->ht_tx_stbc, cfg->mpdu_density, + cfg->ht_rx_ldpc, cfg->ht_sgi_20, cfg->ht_sgi_40, + cfg->num_rf_chains, cfg->dynamic_smps); + +} + +/** + * wma_update_target_vht_cap() - update vht capabality from wma handle + * @tgt_hdl: pointer to structure target_psoc_info + * @cfg: vht capabality + * + * Return: none + */ +static inline void +wma_update_target_vht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_vht_cap *cfg) +{ + int vht_cap_info = target_if_get_vht_cap_info(tgt_hdl); + + if (vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + cfg->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (vht_cap_info & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + cfg->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + cfg->vht_max_mpdu = 0; + + + if (vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) { + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80P80MHZ; + cfg->supp_chan_width |= 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else if (vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + cfg->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + + cfg->vht_rx_ldpc = vht_cap_info & WMI_VHT_CAP_RX_LDPC; + + cfg->vht_short_gi_80 = vht_cap_info & WMI_VHT_CAP_SGI_80MHZ; + cfg->vht_short_gi_160 = vht_cap_info & WMI_VHT_CAP_SGI_160MHZ; + + cfg->vht_tx_stbc = vht_cap_info & WMI_VHT_CAP_TX_STBC; + + cfg->vht_rx_stbc = + (vht_cap_info & WMI_VHT_CAP_RX_STBC_1SS) | + (vht_cap_info & WMI_VHT_CAP_RX_STBC_2SS) | + (vht_cap_info & WMI_VHT_CAP_RX_STBC_3SS); + + cfg->vht_max_ampdu_len_exp = (vht_cap_info & + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) + >> WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT; + + cfg->vht_su_bformer = vht_cap_info & WMI_VHT_CAP_SU_BFORMER; + + cfg->vht_su_bformee = vht_cap_info & WMI_VHT_CAP_SU_BFORMEE; + + cfg->vht_mu_bformer = vht_cap_info & WMI_VHT_CAP_MU_BFORMER; + + cfg->vht_mu_bformee = vht_cap_info & WMI_VHT_CAP_MU_BFORMEE; + + cfg->vht_txop_ps = vht_cap_info & WMI_VHT_CAP_TXOP_PS; + + wma_nofl_debug("max_mpdu %d supp_chan_width %x rx_ldpc %x\n" + "short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n" + "su_bformee %x mu_bformee %x max_ampdu_len_exp %d", + cfg->vht_max_mpdu, cfg->supp_chan_width, cfg->vht_rx_ldpc, + cfg->vht_short_gi_80, cfg->vht_tx_stbc, cfg->vht_rx_stbc, + cfg->vht_txop_ps, cfg->vht_su_bformee, cfg->vht_mu_bformee, + cfg->vht_max_ampdu_len_exp); +} + +/** + * wma_update_supported_bands() - update supported bands from service ready ext + * @supported_bands: Supported band given by FW through service ready ext params + * @new_supported_bands: New supported band which needs to be updated by + * this API which WMA layer understands + * + * This API will convert FW given supported band to enum which WMA layer + * understands + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_update_supported_bands( + WLAN_BAND_CAPABILITY supported_bands, + WMI_PHY_CAPABILITY *new_supported_bands) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!new_supported_bands) { + wma_err("NULL new supported band variable"); + return QDF_STATUS_E_FAILURE; + } + switch (supported_bands) { + case WLAN_2G_CAPABILITY: + *new_supported_bands |= WMI_11G_CAPABILITY; + break; + case WLAN_5G_CAPABILITY: + *new_supported_bands |= WMI_11A_CAPABILITY; + break; + default: + wma_err("wrong supported band"); + status = QDF_STATUS_E_FAILURE; + break; + } + return status; +} + +/** + * wma_derive_ext_ht_cap() - Derive HT caps based on given value + * @ht_cap: given pointer to HT caps which needs to be updated + * @value: new HT cap info provided in form of bitmask + * @tx_chain: given tx chainmask value + * @rx_chain: given rx chainmask value + * + * This function takes the value provided in form of bitmask and decodes + * it. After decoding, what ever value it gets, it takes the union(max) or + * intersection(min) with previously derived values. + * + * Return: none + * + */ +static void wma_derive_ext_ht_cap( + struct wma_tgt_ht_cap *ht_cap, uint32_t value, + uint32_t tx_chain, uint32_t rx_chain) +{ + struct wma_tgt_ht_cap tmp = {0}; + + if (!ht_cap) + return; + + if (!qdf_mem_cmp(ht_cap, &tmp, sizeof(struct wma_tgt_ht_cap))) { + ht_cap->ht_rx_stbc = (!!(value & WMI_HT_CAP_RX_STBC)); + ht_cap->ht_tx_stbc = (!!(value & WMI_HT_CAP_TX_STBC)); + ht_cap->mpdu_density = (!!(value & WMI_HT_CAP_MPDU_DENSITY)); + ht_cap->ht_rx_ldpc = (!!(value & WMI_HT_CAP_RX_LDPC)); + ht_cap->ht_sgi_20 = (!!(value & WMI_HT_CAP_HT20_SGI)); + ht_cap->ht_sgi_40 = (!!(value & WMI_HT_CAP_HT40_SGI)); + ht_cap->dynamic_smps = (!!(value & WMI_HT_CAP_DYNAMIC_SMPS)); + ht_cap->num_rf_chains = + QDF_MAX(wma_get_num_of_setbits_from_bitmask(tx_chain), + wma_get_num_of_setbits_from_bitmask(rx_chain)); + } else { + ht_cap->ht_rx_stbc = QDF_MIN(ht_cap->ht_rx_stbc, + (!!(value & WMI_HT_CAP_RX_STBC))); + ht_cap->ht_tx_stbc = QDF_MAX(ht_cap->ht_tx_stbc, + (!!(value & WMI_HT_CAP_TX_STBC))); + ht_cap->mpdu_density = QDF_MIN(ht_cap->mpdu_density, + (!!(value & WMI_HT_CAP_MPDU_DENSITY))); + ht_cap->ht_rx_ldpc = QDF_MIN(ht_cap->ht_rx_ldpc, + (!!(value & WMI_HT_CAP_RX_LDPC))); + ht_cap->ht_sgi_20 = QDF_MIN(ht_cap->ht_sgi_20, + (!!(value & WMI_HT_CAP_HT20_SGI))); + ht_cap->ht_sgi_40 = QDF_MIN(ht_cap->ht_sgi_40, + (!!(value & WMI_HT_CAP_HT40_SGI))); + ht_cap->dynamic_smps = QDF_MIN(ht_cap->dynamic_smps, + (!!(value & WMI_HT_CAP_DYNAMIC_SMPS))); + + ht_cap->num_rf_chains = + QDF_MAX(ht_cap->num_rf_chains, + QDF_MAX(wma_get_num_of_setbits_from_bitmask( + tx_chain), + wma_get_num_of_setbits_from_bitmask( + rx_chain))); + } +} + +/** + * wma_update_target_ext_ht_cap() - Update HT caps with given extended cap + * @tgt_hdl: target psoc information + * @ht_cap: HT cap structure to be filled + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * HT caps and derives the final cap. + * + * Return: none + * + */ +static void wma_update_target_ext_ht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_ht_cap *ht_cap) +{ + int i, total_mac_phy_cnt; + uint32_t ht_2g, ht_5g; + struct wma_tgt_ht_cap tmp_ht_cap = {0}, tmp_cap = {0}; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + int num_hw_modes; + + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return; + } + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!num_hw_modes) { + wma_debug("No extended HT cap for current SOC"); + return; + } + + for (i = 0; i < total_mac_phy_cnt; i++) { + ht_2g = mac_phy_cap[i].ht_cap_info_2G; + ht_5g = mac_phy_cap[i].ht_cap_info_5G; + if (ht_2g) + wma_derive_ext_ht_cap(&tmp_ht_cap, + ht_2g, + mac_phy_cap[i].tx_chain_mask_2G, + mac_phy_cap[i].rx_chain_mask_2G); + if (ht_5g) + wma_derive_ext_ht_cap(&tmp_ht_cap, + ht_5g, + mac_phy_cap[i].tx_chain_mask_5G, + mac_phy_cap[i].rx_chain_mask_5G); + } + + if (qdf_mem_cmp(&tmp_cap, &tmp_ht_cap, + sizeof(struct wma_tgt_ht_cap))) { + qdf_mem_copy(ht_cap, &tmp_ht_cap, + sizeof(struct wma_tgt_ht_cap)); + } + + wma_nofl_debug("[ext ht cap] ht_rx_stbc - %d, ht_tx_stbc - %d\n" + "mpdu_density - %d ht_rx_ldpc - %d ht_sgi_20 - %d\n" + "ht_sgi_40 - %d num_rf_chains - %d dynamic_smps - %d", + ht_cap->ht_rx_stbc, ht_cap->ht_tx_stbc, + ht_cap->mpdu_density, ht_cap->ht_rx_ldpc, + ht_cap->ht_sgi_20, ht_cap->ht_sgi_40, + ht_cap->num_rf_chains, ht_cap->dynamic_smps); +} + +/** + * wma_derive_ext_vht_cap() - Derive VHT caps based on given value + * @vht_cap: pointer to given VHT caps to be filled + * @value: new VHT cap info provided in form of bitmask + * + * This function takes the value provided in form of bitmask and decodes + * it. After decoding, what ever value it gets, it takes the union(max) or + * intersection(min) with previously derived values. + * + * Return: none + * + */ +static void wma_derive_ext_vht_cap( + struct wma_tgt_vht_cap *vht_cap, uint32_t value) +{ + struct wma_tgt_vht_cap tmp_cap = {0}; + uint32_t tmp = 0; + + if (!vht_cap) + return; + + if (!qdf_mem_cmp(vht_cap, &tmp_cap, + sizeof(struct wma_tgt_vht_cap))) { + if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + vht_cap->vht_max_mpdu = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + vht_cap->vht_max_mpdu = 0; + + if (value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) { + vht_cap->supp_chan_width = + 1 << eHT_CHANNEL_WIDTH_80P80MHZ; + vht_cap->supp_chan_width |= + 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + vht_cap->supp_chan_width = + 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + vht_cap->supp_chan_width = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + vht_cap->vht_rx_ldpc = value & WMI_VHT_CAP_RX_LDPC; + vht_cap->vht_short_gi_80 = value & WMI_VHT_CAP_SGI_80MHZ; + vht_cap->vht_short_gi_160 = value & WMI_VHT_CAP_SGI_160MHZ; + vht_cap->vht_tx_stbc = value & WMI_VHT_CAP_TX_STBC; + vht_cap->vht_rx_stbc = + (value & WMI_VHT_CAP_RX_STBC_1SS) | + (value & WMI_VHT_CAP_RX_STBC_2SS) | + (value & WMI_VHT_CAP_RX_STBC_3SS); + vht_cap->vht_max_ampdu_len_exp = + (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >> + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT; + vht_cap->vht_su_bformer = value & WMI_VHT_CAP_SU_BFORMER; + vht_cap->vht_su_bformee = value & WMI_VHT_CAP_SU_BFORMEE; + vht_cap->vht_mu_bformer = value & WMI_VHT_CAP_MU_BFORMER; + vht_cap->vht_mu_bformee = value & WMI_VHT_CAP_MU_BFORMEE; + vht_cap->vht_txop_ps = value & WMI_VHT_CAP_TXOP_PS; + } else { + if (value & WMI_VHT_CAP_MAX_MPDU_LEN_11454) + tmp = WMI_VHT_CAP_MAX_MPDU_LEN_11454; + else if (value & WMI_VHT_CAP_MAX_MPDU_LEN_7935) + tmp = WMI_VHT_CAP_MAX_MPDU_LEN_7935; + else + tmp = 0; + vht_cap->vht_max_mpdu = QDF_MIN(vht_cap->vht_max_mpdu, tmp); + + if ((value & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ)) { + tmp = (1 << eHT_CHANNEL_WIDTH_80P80MHZ) | + (1 << eHT_CHANNEL_WIDTH_160MHZ); + } else if (value & WMI_VHT_CAP_CH_WIDTH_160MHZ) { + tmp = 1 << eHT_CHANNEL_WIDTH_160MHZ; + } else { + tmp = 1 << eHT_CHANNEL_WIDTH_80MHZ; + } + vht_cap->supp_chan_width = + QDF_MAX(vht_cap->supp_chan_width, tmp); + vht_cap->vht_rx_ldpc = QDF_MIN(vht_cap->vht_rx_ldpc, + value & WMI_VHT_CAP_RX_LDPC); + vht_cap->vht_short_gi_80 = QDF_MAX(vht_cap->vht_short_gi_80, + value & WMI_VHT_CAP_SGI_80MHZ); + vht_cap->vht_short_gi_160 = QDF_MAX(vht_cap->vht_short_gi_160, + value & WMI_VHT_CAP_SGI_160MHZ); + vht_cap->vht_tx_stbc = QDF_MAX(vht_cap->vht_tx_stbc, + value & WMI_VHT_CAP_TX_STBC); + vht_cap->vht_rx_stbc = QDF_MIN(vht_cap->vht_rx_stbc, + (value & WMI_VHT_CAP_RX_STBC_1SS) | + (value & WMI_VHT_CAP_RX_STBC_2SS) | + (value & WMI_VHT_CAP_RX_STBC_3SS)); + vht_cap->vht_max_ampdu_len_exp = + QDF_MIN(vht_cap->vht_max_ampdu_len_exp, + (value & WMI_VHT_CAP_MAX_AMPDU_LEN_EXP) >> + WMI_VHT_CAP_MAX_AMPDU_LEN_EXP_SHIFT); + vht_cap->vht_su_bformer = QDF_MAX(vht_cap->vht_su_bformer, + value & WMI_VHT_CAP_SU_BFORMER); + vht_cap->vht_su_bformee = QDF_MAX(vht_cap->vht_su_bformee, + value & WMI_VHT_CAP_SU_BFORMEE); + vht_cap->vht_mu_bformer = QDF_MAX(vht_cap->vht_mu_bformer, + value & WMI_VHT_CAP_MU_BFORMER); + vht_cap->vht_mu_bformee = QDF_MAX(vht_cap->vht_mu_bformee, + value & WMI_VHT_CAP_MU_BFORMEE); + vht_cap->vht_txop_ps = QDF_MIN(vht_cap->vht_txop_ps, + value & WMI_VHT_CAP_TXOP_PS); + } +} + +/** + * wma_update_target_ext_vht_cap() - Update VHT caps with given extended cap + * @tgt_hdl: target psoc information + * @vht_cap: VHT cap structure to be filled + * + * This function loop through each hardware mode and for each hardware mode + * again it loop through each MAC/PHY and pull the caps 2G and 5G specific + * VHT caps and derives the final cap. + * + * Return: none + * + */ +static void wma_update_target_ext_vht_cap(struct target_psoc_info *tgt_hdl, + struct wma_tgt_vht_cap *vht_cap) +{ + int i, num_hw_modes, total_mac_phy_cnt; + uint32_t vht_cap_info_2g, vht_cap_info_5g; + struct wma_tgt_vht_cap tmp_vht_cap = {0}, tmp_cap = {0}; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + uint32_t vht_mcs_10_11_supp = 0; + + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return; + } + + /* + * for legacy device extended cap might not even come, so in that case + * don't overwrite legacy values + */ + if (!num_hw_modes) { + wma_debug("No extended VHT cap for current SOC"); + return; + } + + for (i = 0; i < total_mac_phy_cnt; i++) { + vht_cap_info_2g = mac_phy_cap[i].vht_cap_info_2G; + vht_cap_info_5g = mac_phy_cap[i].vht_cap_info_5G; + if (vht_cap_info_2g) + wma_derive_ext_vht_cap(&tmp_vht_cap, + vht_cap_info_2g); + if (vht_cap_info_5g) + wma_derive_ext_vht_cap(&tmp_vht_cap, + vht_cap_info_5g); + if (WMI_GET_BITS(mac_phy_cap[i].vht_supp_mcs_5G, 16, 2) && + WMI_VHT_MCS_NOTIFY_EXT_SS_GET(mac_phy_cap[i]. + vht_supp_mcs_5G)) + vht_mcs_10_11_supp = 1; + if (WMI_GET_BITS(mac_phy_cap[i].vht_supp_mcs_2G, 16, 2) && + WMI_VHT_MCS_NOTIFY_EXT_SS_GET(mac_phy_cap[i]. + vht_supp_mcs_2G)) + vht_mcs_10_11_supp = 1; + } + + if (qdf_mem_cmp(&tmp_cap, &tmp_vht_cap, + sizeof(struct wma_tgt_vht_cap))) { + qdf_mem_copy(vht_cap, &tmp_vht_cap, + sizeof(struct wma_tgt_vht_cap)); + } + vht_cap->vht_mcs_10_11_supp = vht_mcs_10_11_supp; + wma_nofl_debug("[ext vhtcap] max_mpdu %d supp_chan_width %x rx_ldpc %x\n" + "short_gi_80 %x tx_stbc %x rx_stbc %x txop_ps %x\n" + "su_bformee %x mu_bformee %x max_ampdu_len_exp %d\n" + "vht_mcs_10_11_supp %d", + vht_cap->vht_max_mpdu, vht_cap->supp_chan_width, + vht_cap->vht_rx_ldpc, vht_cap->vht_short_gi_80, + vht_cap->vht_tx_stbc, vht_cap->vht_rx_stbc, + vht_cap->vht_txop_ps, vht_cap->vht_su_bformee, + vht_cap->vht_mu_bformee, vht_cap->vht_max_ampdu_len_exp, + vht_cap->vht_mcs_10_11_supp); +} + +static void +wma_update_sar_version(struct wlan_psoc_host_service_ext_param *param, + struct wma_tgt_cfg *cfg) +{ + cfg->sar_version = param ? param->sar_version : SAR_VERSION_1; +} + +/** + * wma_update_hdd_band_cap() - update band cap which hdd understands + * @supported_band: supported band which has been given by FW + * @tgt_cfg: target configuration to be updated + * @psoc: psoc ptr + * + * Convert WMA given supported band to enum which HDD understands + * + * Return: None + */ +static void wma_update_hdd_band_cap(WMI_PHY_CAPABILITY supported_band, + struct wma_tgt_cfg *tgt_cfg, + struct wlan_objmgr_psoc *psoc) +{ + switch (supported_band) { + case WMI_11G_CAPABILITY: + case WMI_11NG_CAPABILITY: + tgt_cfg->band_cap = BIT(REG_BAND_2G); + break; + case WMI_11A_CAPABILITY: + case WMI_11NA_CAPABILITY: + case WMI_11AC_CAPABILITY: + tgt_cfg->band_cap = BIT(REG_BAND_5G); + break; + case WMI_11AG_CAPABILITY: + case WMI_11NAG_CAPABILITY: + case WMI_11AX_CAPABILITY: + tgt_cfg->band_cap = (BIT(REG_BAND_2G) | BIT(REG_BAND_5G)); + if (wlan_reg_is_6ghz_supported(psoc)) + tgt_cfg->band_cap |= BIT(REG_BAND_6G); + break; + default: + tgt_cfg->band_cap = (BIT(REG_BAND_2G) | + BIT(REG_BAND_5G) | + BIT(REG_BAND_6G)); + } +} + +/** + * wma_update_obss_detection_support() - update obss detection offload support + * @wh: wma handle + * @tgt_cfg: target configuration to be updated + * + * Update obss detection offload support based on service bit. + * + * Return: None + */ +static void wma_update_obss_detection_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wh->wmi_handle, + wmi_service_ap_obss_detection_offload)) + tgt_cfg->obss_detection_offloaded = true; + else + tgt_cfg->obss_detection_offloaded = false; +} + +/** + * wma_update_obss_color_collision_support() - update obss color collision + * offload support + * @wh: wma handle + * @tgt_cfg: target configuration to be updated + * + * Update obss color collision offload support based on service bit. + * + * Return: None + */ +static void wma_update_obss_color_collision_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wh->wmi_handle, wmi_service_bss_color_offload)) + tgt_cfg->obss_color_collision_offloaded = true; + else + tgt_cfg->obss_color_collision_offloaded = false; +} + +/** + * wma_update_restricted_80p80_bw_support() - update restricted 80+80 support + * @wh: wma handle + * @tgt_cfg: target configuration to be updated + * + * Update restricted 80+80MHz (165MHz) BW support based on service bit. + * + * Return: None + */ +static void wma_update_restricted_80p80_bw_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wh->wmi_handle, + wmi_service_bw_165mhz_support)) + tgt_cfg->restricted_80p80_bw_supp = true; + else + tgt_cfg->restricted_80p80_bw_supp = false; +} + +/** + * wma_update_aux_dev_caps() - update aux device capability + * @tgt_hdl: target psoc information + * @tgt_cfg: target configuration to be updated + * + * Update aux device capability to wma_tgt_cfg. + * + * Return: None + */ +static void wma_update_aux_dev_caps(struct target_psoc_info *tgt_hdl, + struct wma_tgt_cfg *tgt_cfg) +{ + uint8_t cap_idx; + uint32_t num_aux_dev_caps; + struct wlan_psoc_host_aux_dev_caps *aux_dev_caps; + enum wmi_host_hw_mode_config_type hw_mode_id; + + num_aux_dev_caps = tgt_hdl->info.service_ext2_param.num_aux_dev_caps; + aux_dev_caps = tgt_hdl->info.aux_dev_caps; + + for (cap_idx = 0; cap_idx < num_aux_dev_caps; cap_idx++) { + /*current only support AUX0*/ + if (aux_dev_caps[cap_idx].aux_index != 0) + continue; + + hw_mode_id = aux_dev_caps[cap_idx].hw_mode_id; + if (hw_mode_id >= WMI_HOST_HW_MODE_MAX) { + wma_err("invalid hw mode id %d.", hw_mode_id); + continue; + } + tgt_cfg->wma_aux0_dev_caps[hw_mode_id].supported_modes_bitmap = + aux_dev_caps[cap_idx].supported_modes_bitmap; + tgt_cfg->wma_aux0_dev_caps[hw_mode_id].listen_pdev_id_map = + aux_dev_caps[cap_idx].listen_pdev_id_map; + tgt_cfg->wma_aux0_dev_caps[hw_mode_id].emlsr_pdev_id_map = + aux_dev_caps[cap_idx].emlsr_pdev_id_map; + } +} + +#ifdef WLAN_SUPPORT_GREEN_AP +static void wma_green_ap_register_handlers(tp_wma_handle wma_handle) +{ + if (WMI_SERVICE_IS_ENABLED(wma_handle->wmi_service_bitmap, + WMI_SERVICE_EGAP)) + target_if_green_ap_register_egap_event_handler( + wma_handle->pdev); + + target_if_green_ap_register_ll_ps_event_handler(wma_handle->pdev); + +} +#else +static inline void wma_green_ap_register_handlers(tp_wma_handle wma_handle) +{ +} +#endif + +#ifdef WLAN_FEATURE_NAN +#ifdef WLAN_FEATURE_11BE_MLO +static void wma_update_mlo_sta_nan_ndi_target_caps(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_mlo_sta_nan_ndi_support)) + tgt_cfg->nan_caps.mlo_sta_nan_ndi_allowed = 1; +} +#else +static void wma_update_mlo_sta_nan_ndi_target_caps(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ +} +#endif /* WLAN_FEATURE_11BE_MLO */ + +static void wma_update_nan_target_caps(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_nan_disable_support)) + tgt_cfg->nan_caps.nan_conc_control = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_nan_dbs_support)) + tgt_cfg->nan_caps.nan_dbs_supported = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_ndi_dbs_support)) + tgt_cfg->nan_caps.ndi_dbs_supported = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_nan_sap_support)) + tgt_cfg->nan_caps.nan_sap_supported = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_ndi_sap_support)) + tgt_cfg->nan_caps.ndi_sap_supported = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, wmi_service_nan_vdev)) + tgt_cfg->nan_caps.nan_vdev_allowed = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sta_nan_ndi_four_port)) + tgt_cfg->nan_caps.sta_nan_ndi_ndi_allowed = 1; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_ndi_txbf_support)) + tgt_cfg->nan_caps.ndi_txbf_supported = 1; + + wma_update_mlo_sta_nan_ndi_target_caps(wma_handle, tgt_cfg); +} +#else +static void wma_update_nan_target_caps(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ +} +#endif + +static uint8_t +wma_convert_chainmask_to_chain(uint8_t chainmask) +{ + uint8_t num_chains = 0; + + while (chainmask) { + chainmask &= (chainmask - 1); + num_chains++; + } + + return num_chains; +} + +static void +wma_fill_chain_cfg(struct target_psoc_info *tgt_hdl, + uint8_t phy) +{ + struct mac_context *mac_ctx; + uint8_t num_chain; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap = + tgt_hdl->info.mac_phy_cap; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + wma_err("fill chain cfg failed as mac_ctx is NULL"); + return; + } + + num_chain = wma_convert_chainmask_to_chain(mac_phy_cap[phy]. + tx_chain_mask_2G); + + if (num_chain > mac_ctx->fw_chain_cfg.max_tx_chains_2g) + mac_ctx->fw_chain_cfg.max_tx_chains_2g = num_chain; + + num_chain = wma_convert_chainmask_to_chain(mac_phy_cap[phy]. + tx_chain_mask_5G); + + if (num_chain > mac_ctx->fw_chain_cfg.max_tx_chains_5g) + mac_ctx->fw_chain_cfg.max_tx_chains_5g = num_chain; + + num_chain = wma_convert_chainmask_to_chain(mac_phy_cap[phy]. + rx_chain_mask_2G); + + if (num_chain > mac_ctx->fw_chain_cfg.max_rx_chains_2g) + mac_ctx->fw_chain_cfg.max_rx_chains_2g = num_chain; + + num_chain = wma_convert_chainmask_to_chain(mac_phy_cap[phy]. + rx_chain_mask_5G); + + if (num_chain > mac_ctx->fw_chain_cfg.max_rx_chains_5g) + mac_ctx->fw_chain_cfg.max_rx_chains_5g = num_chain; +} + +static void wma_update_mlme_related_tgt_caps(struct wlan_objmgr_psoc *psoc, + struct wmi_unified *wmi_handle) +{ + struct mlme_tgt_caps mlme_tgt_cfg; + + mlme_tgt_cfg.data_stall_recovery_fw_support = + wmi_service_enabled(wmi_handle, + wmi_service_data_stall_recovery_support); + + mlme_tgt_cfg.bigtk_support = + wmi_service_enabled(wmi_handle, wmi_beacon_protection_support); + + mlme_tgt_cfg.stop_all_host_scan_support = + wmi_service_enabled(wmi_handle, + wmi_service_host_scan_stop_vdev_all); + mlme_tgt_cfg.dual_sta_roam_fw_support = + wmi_service_enabled(wmi_handle, + wmi_service_dual_sta_roam_support); + + mlme_tgt_cfg.ocv_support = + wmi_service_enabled(wmi_handle, + wmi_service_ocv_support); + + wma_debug("beacon protection support %d, ocv support %d", + mlme_tgt_cfg.bigtk_support, mlme_tgt_cfg.ocv_support); + + /* Call this at last only after filling all the tgt caps */ + wlan_mlme_update_cfg_with_tgt_caps(psoc, &mlme_tgt_cfg); +} + +/** + * wma_update_mlme_aux_dev_caps() - update aux device capability to mlme + * @psoc: psoc handle + * @tgt_hdl: target psoc information + * + * Update aux device capability to mlme. + * + * Return: None + */ +static void wma_update_mlme_aux_dev_caps(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl) +{ + uint8_t cap_idx; + uint32_t num_aux_dev_caps; + struct wlan_psoc_host_aux_dev_caps *aux_dev_caps; + enum wmi_host_hw_mode_config_type hw_mode_id; + struct wlan_mlme_aux_dev_caps + wlan_mlme_aux0_dev_caps[WLAN_MLME_HW_MODE_MAX] = {0}; + + if (WMI_HOST_HW_MODE_MAX != WLAN_MLME_HW_MODE_MAX) + wma_err("struct define mismatch, pls fix it."); + + num_aux_dev_caps = + tgt_hdl->info.service_ext2_param.num_aux_dev_caps; + aux_dev_caps = tgt_hdl->info.aux_dev_caps; + + for (cap_idx = 0; cap_idx < num_aux_dev_caps; cap_idx++) { + /*current only support AUX0*/ + if (aux_dev_caps[cap_idx].aux_index != 0) + continue; + + hw_mode_id = aux_dev_caps[cap_idx].hw_mode_id; + if (hw_mode_id >= WMI_HOST_HW_MODE_MAX) { + wma_err("invalid hw mode id %d.", hw_mode_id); + continue; + } + wlan_mlme_aux0_dev_caps[hw_mode_id].supported_modes_bitmap = + aux_dev_caps[cap_idx].supported_modes_bitmap; + wlan_mlme_aux0_dev_caps[hw_mode_id].listen_pdev_id_map = + aux_dev_caps[cap_idx].listen_pdev_id_map; + wlan_mlme_aux0_dev_caps[hw_mode_id].emlsr_pdev_id_map = + aux_dev_caps[cap_idx].emlsr_pdev_id_map; + } + + wlan_mlme_update_aux_dev_caps(psoc, wlan_mlme_aux0_dev_caps); +} + +static bool +wma_is_dbs_mandatory(struct wlan_objmgr_psoc *psoc, + struct target_psoc_info *tgt_hdl) +{ + uint8_t i, total_mac_phy_cnt; + struct wlan_psoc_host_mac_phy_caps *mac_cap, *mac_phy_cap; + uint8_t supported_band = 0; + + if (!policy_mgr_find_if_fw_supports_dbs(psoc) || + !policy_mgr_find_if_hwlist_has_dbs(psoc)) { + wma_debug("DBS is not mandatory"); + return false; + } + + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return false; + } + + + for (i = 0; i < total_mac_phy_cnt; i++) { + mac_cap = &mac_phy_cap[i]; + if (mac_cap && (mac_cap->phy_id == 0)) + supported_band |= mac_cap->supported_bands; + } + + /* If Mac0 supports both the bands then DBS is not mandatory */ + if (supported_band & WLAN_2G_CAPABILITY && + supported_band & WLAN_5G_CAPABILITY) { + wma_debug("Mac0 supports both bands DBS is optional"); + return false; + } + + wma_info("MAC0 does not support both bands %d DBS is mandatory", + supported_band); + + return true; +} + +/** + * wma_update_hdd_cfg() - update HDD config + * @wma_handle: wma handle + * + * Return: Zero on success err number on failure + */ +static int wma_update_hdd_cfg(tp_wma_handle wma_handle) +{ + struct wma_tgt_cfg tgt_cfg; + void *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + target_resource_config *wlan_res_cfg; + struct wlan_psoc_host_service_ext_param *service_ext_param; + struct target_psoc_info *tgt_hdl; + struct wmi_unified *wmi_handle; + uint8_t i; + int ret; + + wma_debug("Enter"); + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return -EINVAL; + } + + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_hdl); + if (!wlan_res_cfg) { + wma_err("wlan_res_cfg is null"); + return -EINVAL; + } + + service_ext_param = + target_psoc_get_service_ext_param(tgt_hdl); + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + wma_update_mlme_related_tgt_caps(wma_handle->psoc, wmi_handle); + wma_update_mlme_aux_dev_caps(wma_handle->psoc, tgt_hdl); + + if (wmi_service_enabled(wmi_handle, wmi_service_peer_create_conf)) + wlan_psoc_nif_fw_ext_cap_set(wma_handle->psoc, + WLAN_SOC_F_PEER_CREATE_RESP); + + qdf_mem_zero(&tgt_cfg, sizeof(struct wma_tgt_cfg)); + + tgt_cfg.sub_20_support = wma_handle->sub_20_support; + tgt_cfg.reg_domain = wma_handle->reg_cap.eeprom_rd; + tgt_cfg.eeprom_rd_ext = wma_handle->reg_cap.eeprom_rd_ext; + + tgt_cfg.max_intf_count = wlan_res_cfg->num_vdevs; + policy_mgr_set_max_conc_cxns(wma_handle->psoc, + wlan_res_cfg->num_max_active_vdevs); + + qdf_mem_copy(tgt_cfg.hw_macaddr.bytes, wma_handle->hwaddr, + ATH_MAC_LEN); + + wma_update_target_services(wmi_handle, &tgt_cfg.services); + wma_update_target_ht_cap(tgt_hdl, &tgt_cfg.ht_cap); + wma_update_target_vht_cap(tgt_hdl, &tgt_cfg.vht_cap); + /* + * This will overwrite the structure filled by wma_update_target_ht_cap + * and wma_update_target_vht_cap APIs. + */ + wma_update_target_ext_ht_cap(tgt_hdl, &tgt_cfg.ht_cap); + wma_update_target_ext_vht_cap(tgt_hdl, &tgt_cfg.vht_cap); + + wma_update_target_ext_he_cap(tgt_hdl, &tgt_cfg); + wma_update_target_ext_eht_cap(tgt_hdl, &tgt_cfg); + + tgt_cfg.target_fw_version = target_if_get_fw_version(tgt_hdl); + if (service_ext_param) + tgt_cfg.target_fw_vers_ext = + service_ext_param->fw_build_vers_ext; + + tgt_cfg.hw_bd_id = wma_handle->hw_bd_id; + tgt_cfg.hw_bd_info.bdf_version = wma_handle->hw_bd_info[BDF_VERSION]; + tgt_cfg.hw_bd_info.ref_design_id = + wma_handle->hw_bd_info[REF_DESIGN_ID]; + tgt_cfg.hw_bd_info.customer_id = wma_handle->hw_bd_info[CUSTOMER_ID]; + tgt_cfg.hw_bd_info.project_id = wma_handle->hw_bd_info[PROJECT_ID]; + tgt_cfg.hw_bd_info.board_data_rev = + wma_handle->hw_bd_info[BOARD_DATA_REV]; + +#ifdef WLAN_FEATURE_LPSS + tgt_cfg.lpss_support = wma_handle->lpss_support; +#endif /* WLAN_FEATURE_LPSS */ + tgt_cfg.ap_arpns_support = wma_handle->ap_arpns_support; + tgt_cfg.dfs_cac_offload = wma_handle->is_dfs_offloaded; + tgt_cfg.rcpi_enabled = wma_handle->rcpi_enabled; + wma_update_hdd_band_cap(target_if_get_phy_capability(tgt_hdl), + &tgt_cfg, wma_handle->psoc); + wma_update_sar_version(service_ext_param, &tgt_cfg); + tgt_cfg.fine_time_measurement_cap = + target_if_get_wmi_fw_sub_feat_caps(tgt_hdl); + tgt_cfg.wmi_max_len = wmi_get_max_msg_len(wma_handle->wmi_handle) + - WMI_TLV_HEADROOM; + tgt_cfg.tx_bfee_8ss_enabled = wma_handle->tx_bfee_8ss_enabled; + tgt_cfg.dynamic_nss_chains_support = + wma_handle->dynamic_nss_chains_support; + wma_update_obss_detection_support(wma_handle, &tgt_cfg); + wma_update_obss_color_collision_support(wma_handle, &tgt_cfg); + wma_update_hdd_cfg_ndp(wma_handle, &tgt_cfg); + wma_update_nan_target_caps(wma_handle, &tgt_cfg); + wma_update_bcast_twt_support(wma_handle, &tgt_cfg); + wma_update_twt_tgt_cap(wma_handle, &tgt_cfg); + wma_update_restricted_80p80_bw_support(wma_handle, &tgt_cfg); + wma_update_aux_dev_caps(tgt_hdl, &tgt_cfg); + /* Take the max of chains supported by FW, which will limit nss */ + for (i = 0; i < tgt_hdl->info.total_mac_phy_cnt; i++) + wma_fill_chain_cfg(tgt_hdl, i); + + ret = wma_handle->tgt_cfg_update_cb(hdd_ctx, &tgt_cfg); + if (ret) + return -EINVAL; + + wma_green_ap_register_handlers(wma_handle); + + return ret; +} + +/** + * wma_init_scan_fw_mode_config() - Initialize scan/fw mode config + * @psoc: Object manager psoc + * @scan_config: Scam mode configuration + * @fw_config: FW mode configuration + * + * Enables all the valid bits of concurrent_scan_config_bits and + * fw_mode_config_bits. + * + * Return: None + */ +static void wma_init_scan_fw_mode_config(struct wlan_objmgr_psoc *psoc, + uint32_t scan_config, + uint32_t fw_config) +{ + wma_debug("Enter"); + + if (!psoc) { + wma_err("obj psoc is NULL"); + return; + } + + policy_mgr_init_dbs_config(psoc, scan_config, fw_config); + policy_mgr_init_sbs_fw_config(psoc, fw_config); + + wma_debug("Exit"); +} + +static void wma_set_pmo_caps(struct wlan_objmgr_psoc *psoc) +{ + QDF_STATUS status; + tp_wma_handle wma; + struct pmo_device_caps caps; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + caps.arp_ns_offload = + wmi_service_enabled(wma->wmi_handle, wmi_service_arpns_offload); + caps.apf = + wmi_service_enabled(wma->wmi_handle, wmi_service_apf_offload); + caps.packet_filter = + wmi_service_enabled(wma->wmi_handle, + wmi_service_packet_filter_offload); + caps.unified_wow = + wmi_service_enabled(wma->wmi_handle, + wmi_service_unified_wow_capability); + caps.li_offload = + wmi_service_enabled(wma->wmi_handle, + wmi_service_listen_interval_offload_support + ); + + status = ucfg_pmo_psoc_set_caps(psoc, &caps); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to set PMO capabilities; status:%d", status); +} + +/** + * wma_set_mlme_caps() - Populate the MLME related target capabilities to the + * mlme component + * @psoc: Pointer to psoc object + * + * Return: None + */ +static void wma_set_mlme_caps(struct wlan_objmgr_psoc *psoc) +{ + tp_wma_handle wma; + bool tgt_cap; + uint32_t akm_bitmap = 0; + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_adaptive_11r_support); + + status = ucfg_mlme_set_tgt_adaptive_11r_cap(psoc, tgt_cap); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to set adaptive 11r cap"); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_wpa3_ft_sae_support); + if (tgt_cap) + akm_bitmap |= (1 << AKM_FT_SAE); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_wpa3_ft_suite_b_support); + if (tgt_cap) + akm_bitmap |= (1 << AKM_FT_SUITEB_SHA384); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_ft_fils); + if (tgt_cap) + akm_bitmap |= (1 << AKM_FT_FILS); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_owe_roam_support); + if (tgt_cap) + akm_bitmap |= (1 << AKM_OWE); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_sae_roam_support); + if (tgt_cap) + akm_bitmap |= (1 << AKM_SAE); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_suiteb_roam_support); + if (tgt_cap) + akm_bitmap |= (1 << AKM_SUITEB); + + tgt_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_wpa3_sha384_roam_support); + if (tgt_cap) + akm_bitmap |= (1 << AKM_SAE_EXT); + + status = mlme_set_tgt_wpa3_roam_cap(psoc, akm_bitmap); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to set sae roam support"); +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +static bool wma_is_big_data_support_enable(struct wmi_unified *wmi_handle) +{ + return wmi_service_enabled(wmi_handle, wmi_service_big_data_support); +} +#else +static bool wma_is_big_data_support_enable(struct wmi_unified *wmi_handle) +{ + return false; +} +#endif + +/** + * wma_set_mc_cp_caps() - Populate mc cp component related capabilities + * to the mc cp component + * + * @psoc: Pointer to psoc object + * + * Return: None + */ +static void wma_set_mc_cp_caps(struct wlan_objmgr_psoc *psoc) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + if (wma_is_big_data_support_enable(wma->wmi_handle)) + ucfg_mc_cp_set_big_data_fw_support(psoc, true); + else + ucfg_mc_cp_set_big_data_fw_support(psoc, false); +} + +#ifdef THERMAL_STATS_SUPPORT +static void wma_set_thermal_stats_fw_cap(tp_wma_handle wma, + struct wlan_fwol_capability_info *cap) +{ + cap->fw_thermal_stats_cap = wmi_service_enabled(wma->wmi_handle, + wmi_service_thermal_stats_temp_range_supported); +} +#else +static void wma_set_thermal_stats_fw_cap(tp_wma_handle wma, + struct wlan_fwol_capability_info *cap) +{ +} +#endif + +/** + * wma_set_fwol_caps() - Populate fwol component related capabilities + * to the fwol component + * + * @psoc: Pointer to psoc object + * + * Return: None + */ +static void wma_set_fwol_caps(struct wlan_objmgr_psoc *psoc) +{ + tp_wma_handle wma; + struct wlan_fwol_capability_info cap_info; + wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + wma_err_rl("wma Null"); + return; + } + if (!psoc) { + wma_err_rl("psoc Null"); + return; + } + + wma_set_thermal_stats_fw_cap(wma, &cap_info); + ucfg_fwol_update_fw_cap_info(psoc, &cap_info); +} +static void wma_set_component_caps(struct wlan_objmgr_psoc *psoc) +{ + wma_set_pmo_caps(psoc); + wma_set_mlme_caps(psoc); + wma_set_mc_cp_caps(psoc); + wma_set_fwol_caps(psoc); +} + +#if defined(WLAN_FEATURE_GTK_OFFLOAD) && defined(WLAN_POWER_MANAGEMENT_OFFLOAD) +static QDF_STATUS wma_register_gtk_offload_event(tp_wma_handle wma_handle) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_gtk_offload)) { + status = wmi_unified_register_event_handler( + wma_handle->wmi_handle, + wmi_gtk_offload_status_event_id, + target_if_pmo_gtk_offload_status_event, + WMA_RX_WORK_CTX); + } + return status; +} +#else +static QDF_STATUS wma_register_gtk_offload_event(tp_wma_handle wma_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_GTK_OFFLOAD && WLAN_POWER_MANAGEMENT_OFFLOAD */ + +/** + * wma_rx_service_ready_event() - event handler to process + * wmi rx service ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * @length: param length + * + * Return: none + */ +int wma_rx_service_ready_event(void *handle, uint8_t *cmd_param_info, + uint32_t length) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_SERVICE_READY_EVENTID_param_tlvs *param_buf; + wmi_service_ready_event_fixed_param *ev; + QDF_STATUS status; + uint32_t *ev_wlan_dbs_hw_mode_list; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct target_psoc_info *tgt_hdl; + struct wlan_psoc_target_capability_info *tgt_cap_info; + target_resource_config *wlan_res_cfg; + struct wmi_unified *wmi_handle; + uint32_t *service_bitmap; + + wma_debug("Enter"); + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return -EINVAL; + } + + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_hdl); + tgt_cap_info = target_psoc_get_target_caps(tgt_hdl); + service_bitmap = target_psoc_get_service_bitmap(tgt_hdl); + + param_buf = (WMI_SERVICE_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + wma_err("Invalid arguments"); + return -EINVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + wma_err("Invalid buffer"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + wma_debug("WMA <-- WMI_SERVICE_READY_EVENTID"); + + if (ev->num_dbs_hw_modes > param_buf->num_wlan_dbs_hw_mode_list) { + wma_err("FW dbs_hw_mode entry %d more than value %d in TLV hdr", + ev->num_dbs_hw_modes, + param_buf->num_wlan_dbs_hw_mode_list); + return -EINVAL; + } + + ev_wlan_dbs_hw_mode_list = param_buf->wlan_dbs_hw_mode_list; + + /* Continuing with the rest of the processing, + * even if memory allocation fails + */ + policy_mgr_init_dbs_hw_mode(wma_handle->psoc, ev->num_dbs_hw_modes, + ev_wlan_dbs_hw_mode_list); + + /* Initializes the fw_mode and scan_config to zero. + * If ext service ready event is present it will set + * the actual values of these two params. + * This is to ensure that no garbage values would be + * present in the absence of ext service ready event. + */ + wma_init_scan_fw_mode_config(wma_handle->psoc, 0, 0); + + qdf_mem_copy(&wma_handle->reg_cap, param_buf->hal_reg_capabilities, + sizeof(HAL_REG_CAPABILITIES)); + + wma_handle->vht_supp_mcs = ev->vht_supp_mcs; + + wma_handle->new_hw_mode_index = tgt_cap_info->default_dbs_hw_mode_index; + policy_mgr_update_new_hw_mode_index(wma_handle->psoc, + tgt_cap_info->default_dbs_hw_mode_index); + + wma_debug("Firmware default hw mode index : %d", + tgt_cap_info->default_dbs_hw_mode_index); + wma_info("Firmware build version : %08x", + ev->fw_build_vers); + wma_debug("FW fine time meas cap: 0x%x", + tgt_cap_info->wmi_fw_sub_feat_caps); + + wma_handle->hw_bd_id = ev->hw_bd_id; + + wma_handle->hw_bd_info[BDF_VERSION] = + WMI_GET_BDF_VERSION(ev->hw_bd_info); + wma_handle->hw_bd_info[REF_DESIGN_ID] = + WMI_GET_REF_DESIGN(ev->hw_bd_info); + wma_handle->hw_bd_info[CUSTOMER_ID] = + WMI_GET_CUSTOMER_ID(ev->hw_bd_info); + wma_handle->hw_bd_info[PROJECT_ID] = + WMI_GET_PROJECT_ID(ev->hw_bd_info); + wma_handle->hw_bd_info[BOARD_DATA_REV] = + WMI_GET_BOARD_DATA_REV(ev->hw_bd_info); + + wma_info("Board id: %x, Board version: %x %x %x %x %x", + wma_handle->hw_bd_id, + wma_handle->hw_bd_info[BDF_VERSION], + wma_handle->hw_bd_info[REF_DESIGN_ID], + wma_handle->hw_bd_info[CUSTOMER_ID], + wma_handle->hw_bd_info[PROJECT_ID], + wma_handle->hw_bd_info[BOARD_DATA_REV]); + + /* wmi service is ready */ + qdf_mem_copy(wma_handle->wmi_service_bitmap, + service_bitmap, + sizeof(wma_handle->wmi_service_bitmap)); + + cdp_cfg_tx_set_is_mgmt_over_wmi_enabled(soc, + wmi_service_enabled(wmi_handle, wmi_service_mgmt_tx_wmi)); + cdp_set_desc_global_pool_size(soc, ev->num_msdu_desc); + /* SWBA event handler for beacon transmission */ + status = wma_register_swba_events(wma_handle->wmi_handle); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register swba beacon event cb"); + goto failure; + } +#ifdef WLAN_FEATURE_LPSS + wma_handle->lpss_support = + wmi_service_enabled(wmi_handle, wmi_service_lpass); +#endif /* WLAN_FEATURE_LPSS */ + + if (wmi_service_enabled(wmi_handle, wmi_service_fse_cmem_alloc_support)) + wlan_dp_set_fst_in_cmem(true); + + if (wmi_service_enabled(wmi_handle, + wmi_service_fisa_dynamic_msdu_aggr_size_support)) + wlan_dp_set_fisa_dynamic_aggr_size_support(true); + /* + * This Service bit is added to check for ARP/NS Offload + * support for LL/HL targets + */ + wma_handle->ap_arpns_support = + wmi_service_enabled(wmi_handle, wmi_service_ap_arpns_offload); + + if (wmi_service_enabled(wmi_handle, wmi_service_csa_offload)) { + wma_debug("FW support CSA offload capability"); + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_csa_handling_event_id, + wma_csa_offload_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register CSA offload event cb"); + goto failure; + } + } + + if (wmi_service_enabled(wmi_handle, wmi_service_mgmt_tx_wmi)) { + wma_debug("Firmware supports management TX over WMI,use WMI interface instead of HTT for management Tx"); + /* + * Register Tx completion event handler for MGMT Tx over WMI + * case + */ + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_mgmt_tx_completion_event_id, + wma_mgmt_tx_completion_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register MGMT over WMI completion handler"); + goto failure; + } + + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_mgmt_tx_bundle_completion_event_id, + wma_mgmt_tx_bundle_completion_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register MGMT over WMI completion handler"); + goto failure; + } + + } else { + wma_err("FW does not support WMI_SERVICE_MGMT_TX_WMI, Use HTT interface for Management Tx"); + } + + status = wma_register_gtk_offload_event(wma_handle); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register GTK offload event cb"); + goto failure; + } + + status = wmi_unified_register_event_handler(wmi_handle, + wmi_tbttoffset_update_event_id, + wma_tbttoffset_update_event_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register WMI_TBTTOFFSET_UPDATE_EVENTID callback"); + goto failure; + } + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_rcpi_support)) { + /* register for rcpi response event */ + status = wmi_unified_register_event_handler( + wmi_handle, + wmi_update_rcpi_event_id, + wma_rcpi_event_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register RCPI event handler"); + goto failure; + } + wma_handle->rcpi_enabled = true; + } + + /* mac_id is replaced with pdev_id in converged firmware to have + * multi-radio support. In order to maintain backward compatibility + * with old fw, host needs to check WMI_SERVICE_DEPRECATED_REPLACE + * in service bitmap from FW and host needs to set use_pdev_id in + * wmi_resource_config to true. If WMI_SERVICE_DEPRECATED_REPLACE + * service is not set, then host shall not expect MAC ID from FW in + * VDEV START RESPONSE event and host shall use PDEV ID. + */ + if (wmi_service_enabled(wmi_handle, wmi_service_deprecated_replace)) + wlan_res_cfg->use_pdev_id = true; + else + wlan_res_cfg->use_pdev_id = false; + + wlan_res_cfg->max_num_dbs_scan_duty_cycle = CDS_DBS_SCAN_CLIENTS_MAX; + + /* Initialize the log supported event handler */ + status = wmi_unified_register_event_handler(wmi_handle, + wmi_diag_event_id_log_supported_event_id, + wma_log_supported_evt_handler, + WMA_RX_SERIALIZER_CTX); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to register log supported event cb"); + goto failure; + } + + cdp_mark_first_wakeup_packet( + soc, OL_TXRX_PDEV_ID, + wmi_service_enabled(wmi_handle, + wmi_service_mark_first_wakeup_packet)); + wma_handle->is_dfs_offloaded = + wmi_service_enabled(wmi_handle, + wmi_service_dfs_phyerr_offload); + + wma_handle->nan_datapath_enabled = + wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_nan_data); + + wma_handle->fw_therm_throt_support = + wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_tt); + + wma_set_component_caps(wma_handle->psoc); + + wma_update_fw_config(wma_handle->psoc, tgt_hdl); + + status = wmi_unified_save_fw_version_cmd(wmi_handle, param_buf); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send WMI_INIT_CMDID command"); + goto failure; + } + + if (wmi_service_enabled(wmi_handle, wmi_service_ext_msg)) { + status = qdf_mc_timer_start( + &wma_handle->service_ready_ext_timer, + WMA_SERVICE_READY_EXT_TIMEOUT); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to start the service ready ext timer"); + } + wma_handle->tx_bfee_8ss_enabled = + wmi_service_enabled(wmi_handle, wmi_service_8ss_tx_bfee); + + wma_handle->dynamic_nss_chains_support = wmi_service_enabled(wmi_handle, + wmi_service_per_vdev_chain_support); + target_psoc_set_num_radios(tgt_hdl, 1); + + return 0; + +failure: + return -EINVAL; + +} + +/** + * wma_get_caps_for_phyidx_hwmode() - to fetch caps for given hw mode and band + * @caps_per_phy: Pointer to capabilities structure which needs to be filled + * @hw_mode: Provided hardware mode + * @band: Provide band i.e. 2G or 5G + * + * This API finds cap which suitable for provided hw mode and band. If user + * is provides some invalid hw mode then it will automatically falls back to + * default hw mode + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_get_caps_for_phyidx_hwmode(struct wma_caps_per_phy *caps_per_phy, + enum hw_mode_dbs_capab hw_mode, enum cds_band_type band) +{ + t_wma_handle *wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct target_psoc_info *tgt_hdl; + int ht_cap_info, vht_cap_info; + uint8_t our_hw_mode = hw_mode, num_hw_modes, hw_mode_config_type; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + struct wlan_psoc_target_capability_info *tgt_cap_info; + uint8_t total_mac_phy_cnt, i; + + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return -EINVAL; + } + if (!caps_per_phy) { + wma_err("Invalid caps pointer"); + return QDF_STATUS_E_FAILURE; + } + + ht_cap_info = target_if_get_ht_cap_info(tgt_hdl); + vht_cap_info = target_if_get_vht_cap_info(tgt_hdl); + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + tgt_cap_info = target_psoc_get_target_caps(tgt_hdl); + + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return QDF_STATUS_E_FAILURE; + } + + if (!tgt_cap_info) { + wma_err("Invalid target capabilities handle"); + return QDF_STATUS_E_FAILURE; + } + + if (!num_hw_modes) { + wma_debug("Invalid number of hw modes, use legacy HT/VHT caps"); + caps_per_phy->ht_2g = ht_cap_info; + caps_per_phy->ht_5g = ht_cap_info; + caps_per_phy->vht_2g = vht_cap_info; + caps_per_phy->vht_5g = vht_cap_info; + /* legacy platform doesn't support HE IE */ + caps_per_phy->he_2g[0] = 0; + caps_per_phy->he_2g[1] = 0; + caps_per_phy->he_5g[0] = 0; + caps_per_phy->he_5g[1] = 0; + caps_per_phy->tx_chain_mask_2G = + EXTRACT_TX_CHAIN_MASK_2G(tgt_cap_info->txrx_chainmask); + caps_per_phy->rx_chain_mask_2G = + EXTRACT_RX_CHAIN_MASK_2G(tgt_cap_info->txrx_chainmask); + caps_per_phy->tx_chain_mask_5G = + EXTRACT_TX_CHAIN_MASK_5G(tgt_cap_info->txrx_chainmask); + caps_per_phy->rx_chain_mask_5G = + EXTRACT_RX_CHAIN_MASK_5G(tgt_cap_info->txrx_chainmask); + + return QDF_STATUS_SUCCESS; + } + + if (!policy_mgr_is_dbs_enable(wma_handle->psoc)) + our_hw_mode = HW_MODE_DBS_NONE; + + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + for (i = 0; i < total_mac_phy_cnt; i++) { + hw_mode_config_type = mac_phy_cap[i].hw_mode_config_type; + if (our_hw_mode == HW_MODE_DBS && + !(hw_mode_config_type == WMI_HW_MODE_DBS || + hw_mode_config_type == WMI_HW_MODE_DBS_OR_SBS)) + continue; + + if ((band == CDS_BAND_2GHZ || band == CDS_BAND_ALL) && + (WLAN_2G_CAPABILITY & mac_phy_cap[i].supported_bands) && + !caps_per_phy->tx_chain_mask_2G) { + caps_per_phy->ht_2g = mac_phy_cap[i].ht_cap_info_2G; + caps_per_phy->vht_2g = mac_phy_cap[i].vht_cap_info_2G; + qdf_mem_copy(caps_per_phy->he_2g, + mac_phy_cap[i].he_cap_info_2G, + sizeof(caps_per_phy->he_2g)); + + caps_per_phy->tx_chain_mask_2G = + mac_phy_cap[i].tx_chain_mask_2G; + caps_per_phy->rx_chain_mask_2G = + mac_phy_cap[i].rx_chain_mask_2G; + + wma_debug("Select 2G capable phyid[%d] chain %d %d ht 0x%x vht 0x%x", + i, + caps_per_phy->tx_chain_mask_2G, + caps_per_phy->rx_chain_mask_2G, + caps_per_phy->ht_2g, + caps_per_phy->vht_2g); + } + if ((band == CDS_BAND_5GHZ || band == CDS_BAND_ALL) && + (WLAN_5G_CAPABILITY & mac_phy_cap[i].supported_bands) && + !caps_per_phy->tx_chain_mask_5G) { + caps_per_phy->ht_5g = mac_phy_cap[i].ht_cap_info_5G; + caps_per_phy->vht_5g = mac_phy_cap[i].vht_cap_info_5G; + qdf_mem_copy(caps_per_phy->he_5g, + mac_phy_cap[i].he_cap_info_5G, + sizeof(caps_per_phy->he_5g)); + + caps_per_phy->tx_chain_mask_5G = + mac_phy_cap[i].tx_chain_mask_5G; + caps_per_phy->rx_chain_mask_5G = + mac_phy_cap[i].rx_chain_mask_5G; + + wma_debug("Select 5G capable phyid[%d] chain %d %d ht 0x%x vht 0x%x", + i, + caps_per_phy->tx_chain_mask_5G, + caps_per_phy->rx_chain_mask_5G, + caps_per_phy->ht_5g, + caps_per_phy->vht_5g); + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_is_rx_ldpc_supported_for_channel() - to find out if ldpc is supported + * + * @ch_freq: Channel freq for which it needs to check if rx ldpc is enabled + * + * This API takes channel number as argument and takes default hw mode as DBS + * to check if rx LDPC support is enabled for that channel or no + */ +bool wma_is_rx_ldpc_supported_for_channel(uint32_t ch_freq) +{ + t_wma_handle *wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct target_psoc_info *tgt_hdl; + struct wma_caps_per_phy caps_per_phy = {0}; + enum cds_band_type band; + bool status; + uint8_t num_hw_modes; + + if (!wma_handle) + return false; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("Target handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + + if (!WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) + band = CDS_BAND_5GHZ; + else + band = CDS_BAND_2GHZ; + + if (QDF_STATUS_SUCCESS != wma_get_caps_for_phyidx_hwmode( + &caps_per_phy, + HW_MODE_DBS, band)) { + return false; + } + + /* + * Legacy platforms like Rome set WMI_HT_CAP_LDPC to specify RX LDPC + * capability. But new platforms like Helium set WMI_HT_CAP_RX_LDPC + * instead. + */ + if (0 == num_hw_modes) { + status = (!!(caps_per_phy.ht_2g & WMI_HT_CAP_LDPC)); + } else { + if (WLAN_REG_IS_24GHZ_CH_FREQ(ch_freq)) + status = (!!(caps_per_phy.ht_2g & WMI_HT_CAP_RX_LDPC)); + else + status = (!!(caps_per_phy.ht_5g & WMI_HT_CAP_RX_LDPC)); + } + + return status; +} + +/** + * wma_print_mac_phy_capabilities() - Prints MAC PHY capabilities + * @cap: pointer to WMI_MAC_PHY_CAPABILITIES + * @index: MAC_PHY index + * + * Return: none + */ +static void wma_print_mac_phy_capabilities(struct wlan_psoc_host_mac_phy_caps + *cap, int index) +{ + uint32_t mac_2G[PSOC_HOST_MAX_MAC_SIZE]; + uint32_t mac_5G[PSOC_HOST_MAX_MAC_SIZE]; + uint32_t phy_2G[WMI_MAX_HECAP_PHY_SIZE]; + uint32_t phy_5G[WMI_MAX_HECAP_PHY_SIZE]; + struct wlan_psoc_host_ppe_threshold ppet_2G, ppet_5G; + + wma_nofl_debug("\t: index [%d]", index); + wma_nofl_debug("\t: cap for hw_mode_id[%d]", cap->hw_mode_id); + wma_nofl_debug("\t: pdev_id[%d]", cap->pdev_id); + wma_nofl_debug("\t: phy_id[%d]", cap->phy_id); + wma_nofl_debug("\t: hw_mode_config_type[%d]", cap->hw_mode_config_type); + wma_nofl_debug("\t: supports_11b[%d]", cap->supports_11b); + wma_nofl_debug("\t: supports_11g[%d]", cap->supports_11g); + wma_nofl_debug("\t: supports_11a[%d]", cap->supports_11a); + wma_nofl_debug("\t: supports_11n[%d]", cap->supports_11n); + wma_nofl_debug("\t: supports_11ac[%d]", cap->supports_11ac); + wma_nofl_debug("\t: supports_11ax[%d]", cap->supports_11ax); + wma_nofl_debug("\t: supported_bands[%d]", cap->supported_bands); + wma_nofl_debug("\t: ampdu_density[%d]", cap->ampdu_density); + wma_nofl_debug("\t: max_bw_supported_2G[%d]", cap->max_bw_supported_2G); + wma_nofl_debug("\t: ht_cap_info_2G[%d]", cap->ht_cap_info_2G); + wma_nofl_debug("\t: vht_cap_info_2G[0x%0X]", cap->vht_cap_info_2G); + wma_nofl_debug("\t: vht_supp_mcs_2G[0x%0X]", cap->vht_supp_mcs_2G); + wma_nofl_debug("\t: tx_chain_mask_2G[%d]", cap->tx_chain_mask_2G); + wma_nofl_debug("\t: rx_chain_mask_2G[%d]", cap->rx_chain_mask_2G); + wma_nofl_debug("\t: max_bw_supported_5G[%d]", cap->max_bw_supported_5G); + wma_nofl_debug("\t: ht_cap_info_5G[%d]", cap->ht_cap_info_5G); + wma_nofl_debug("\t: vht_cap_info_5G[0x%0X]", cap->vht_cap_info_5G); + wma_nofl_debug("\t: vht_supp_mcs_5G[0x%0X]", cap->vht_supp_mcs_5G); + wma_nofl_debug("\t: tx_chain_mask_5G[%d]", cap->tx_chain_mask_5G); + wma_nofl_debug("\t: rx_chain_mask_5G[%d]", cap->rx_chain_mask_5G); + wma_nofl_debug("\t: he_cap_info_2G[0][%08x]", cap->he_cap_info_2G[0]); + wma_nofl_debug("\t: he_cap_info_2G[1][%08x]", cap->he_cap_info_2G[1]); + wma_nofl_debug("\t: he_supp_mcs_2G[%08x]", cap->he_supp_mcs_2G); + wma_nofl_debug("\t: he_cap_info_5G[0][%08x]", cap->he_cap_info_5G[0]); + wma_nofl_debug("\t: he_cap_info_5G[1][%08x]", cap->he_cap_info_5G[1]); + wma_nofl_debug("\t: he_supp_mcs_5G[%08x]", cap->he_supp_mcs_5G); + qdf_mem_copy(mac_2G, cap->he_cap_info_2G, sizeof(mac_2G)); + qdf_mem_copy(mac_5G, cap->he_cap_info_5G, sizeof(mac_5G)); + qdf_mem_copy(phy_2G, cap->he_cap_phy_info_2G, + WMI_MAX_HECAP_PHY_SIZE * 4); + qdf_mem_copy(phy_5G, cap->he_cap_phy_info_5G, + WMI_MAX_HECAP_PHY_SIZE * 4); + ppet_2G = cap->he_ppet2G; + ppet_5G = cap->he_ppet5G; + + wma_print_he_mac_cap_w1(mac_2G[0]); + wma_print_he_mac_cap_w2(mac_2G[1]); + wma_print_he_phy_cap(phy_2G); + wma_print_he_ppet(&ppet_2G); + wma_print_he_mac_cap_w1(mac_5G[0]); + wma_print_he_mac_cap_w1(mac_5G[1]); + wma_print_he_phy_cap(phy_5G); + wma_print_he_ppet(&ppet_5G); +} + +/** + * wma_print_populate_soc_caps() - Prints all the caps populated per hw mode + * @tgt_hdl: target related info + * + * This function prints all the caps populater per hw mode and per PHY + * + * Return: none + */ +static void wma_print_populate_soc_caps(struct target_psoc_info *tgt_hdl) +{ + int i, num_hw_modes, total_mac_phy_cnt; + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap, *tmp; + + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + + /* print number of hw modes */ + wma_debug("num of hw modes [%d]", num_hw_modes); + wma_debug("num mac_phy_cnt [%d]", total_mac_phy_cnt); + + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return; + } + + wma_debug("<====== HW mode cap printing starts ======>"); + /* print cap of each hw mode */ + for (i = 0; i < total_mac_phy_cnt; i++) { + if (&mac_phy_cap[i]) { + wma_nofl_debug("====>: hw mode id[%d], phy id[%d]", + mac_phy_cap[i].hw_mode_id, + mac_phy_cap[i].phy_id); + tmp = &mac_phy_cap[i]; + wma_print_mac_phy_capabilities(tmp, i); + } + } + wma_debug("<====== HW mode cap printing ends ======>\n"); +} + +/** + * wma_update_hw_mode_list() - updates hw_mode_list + * @wma_handle: pointer to wma global structure + * @tgt_hdl: target psoc information + * + * This function updates hw_mode_list with tx_streams, rx_streams, + * bandwidth, dbs and agile dfs for each hw_mode. + * + * Returns: 0 for success else failure. + */ +static QDF_STATUS wma_update_hw_mode_list(t_wma_handle *wma_handle, + struct target_psoc_info *tgt_hdl) +{ + struct wlan_psoc_host_mac_phy_caps *tmp, *mac_phy_cap; + uint32_t i, hw_config_type, j = 0; + WMI_PHY_CAPABILITY new_supported_band = 0; + bool supported_band_update_failure = false; + struct wlan_psoc_target_capability_info *tgt_cap_info; + int num_hw_modes; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + tgt_cap_info = target_psoc_get_target_caps(tgt_hdl); + + if (!mac_phy_cap) { + wma_err("mac_phy_cap Null"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Num modes:%d", num_hw_modes); + for (i = 0; i < num_hw_modes; i++) { + /* Update for MAC0 */ + tmp = &mac_phy_cap[j++]; + hw_config_type = tmp->hw_mode_config_type; + if (wma_update_supported_bands(tmp->supported_bands, + &new_supported_band) + != QDF_STATUS_SUCCESS) + supported_band_update_failure = true; + + /* SBS and DBS have dual MAC. Upto 2 MACs are considered. */ + if ((hw_config_type == WMI_HW_MODE_DBS) || + (hw_config_type == WMI_HW_MODE_SBS_PASSIVE) || + (hw_config_type == WMI_HW_MODE_SBS) || + (hw_config_type == WMI_HW_MODE_DBS_OR_SBS)) { + /* Update for MAC1 */ + tmp = &mac_phy_cap[j++]; + if (QDF_STATUS_SUCCESS != + wma_update_supported_bands(tmp->supported_bands, + &new_supported_band)) + supported_band_update_failure = true; + } + } + + /* overwrite phy_capability which we got from service ready event */ + if (!supported_band_update_failure) { + wma_debug("updating supported band from old[%d] to new[%d]", + target_if_get_phy_capability(tgt_hdl), + new_supported_band); + target_if_set_phy_capability(tgt_hdl, new_supported_band); + } + + if (QDF_STATUS_SUCCESS != + policy_mgr_update_hw_mode_list(wma_handle->psoc, + tgt_hdl)) + wma_err("failed to update policy manager"); + + return QDF_STATUS_SUCCESS; +} + +static void wma_init_wifi_pos_dma_rings(t_wma_handle *wma_handle, + uint8_t num_mac, void *buf) +{ + struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + void *hal_soc; + + if (!hif_ctx) { + wma_err("invalid hif context"); + return; + } + + hal_soc = hif_get_hal_handle(hif_ctx); + + wifi_pos_init_cir_cfr_rings(wma_handle->psoc, hal_soc, num_mac, buf); +} + +/** + * wma_populate_soc_caps() - populate entire SOC's capabilities + * @wma_handle: pointer to wma global structure + * @tgt_hdl: target psoc information + * @param_buf: pointer to param of service ready extension event from fw + * + * This API populates all capabilities of entire SOC. For example, + * how many number of hw modes are supported by this SOC, what are the + * capabilities of each phy per hw mode, what are HAL reg capabilities per + * phy. + * + * Return: none + */ +static void wma_populate_soc_caps(t_wma_handle *wma_handle, + struct target_psoc_info *tgt_hdl, + WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *param_buf) +{ + + wma_debug("Enter"); + + wma_init_wifi_pos_dma_rings(wma_handle, + param_buf->num_oem_dma_ring_caps, + param_buf->oem_dma_ring_caps); + + wma_print_populate_soc_caps(tgt_hdl); + wma_debug("Exit"); +} + +/** + * wma_init_dbr_params() - init dbr params + * @wma_handle: pointer to wma global structure + * + * This API initializes params of direct buffer rx component. + * + * Return: none + */ +#ifdef DIRECT_BUF_RX_ENABLE +static void wma_init_dbr_params(t_wma_handle *wma_handle) +{ + struct hif_opaque_softc *hif_ctx = cds_get_context(QDF_MODULE_ID_HIF); + void *hal_soc; + + if (!hif_ctx) { + wma_err("invalid hif context"); + return; + } + + hal_soc = hif_get_hal_handle(hif_ctx); + direct_buf_rx_target_attach(wma_handle->psoc, hal_soc, + wma_handle->qdf_dev); +} +#else +static inline void wma_init_dbr_params(t_wma_handle *wma_handle) +{ +} +#endif + +/** + * wma_set_coex_res_cfg() - Set target COEX resource configuration. + * @wma_handle: pointer to wma global structure + * @wmi_handle: pointer to wmi handle + * @wlan_res_cfg: Pointer to target resource configuration + * + * Return: none + */ +#ifdef FEATURE_COEX_CONFIG +static void wma_set_coex_res_cfg(t_wma_handle *wma_handle, + struct wmi_unified *wmi_handle, + target_resource_config *wlan_res_cfg) +{ + if (cfg_get(wma_handle->psoc, CFG_THREE_WAY_COEX_CONFIG_LEGACY) && + wmi_service_enabled(wmi_handle, + wmi_service_three_way_coex_config_legacy)) { + wlan_res_cfg->three_way_coex_config_legacy_en = true; + } else { + wlan_res_cfg->three_way_coex_config_legacy_en = false; + } +} +#else +static void wma_set_coex_res_cfg(t_wma_handle *wma_handle, + struct wmi_unified *wmi_handle, + target_resource_config *wlan_res_cfg) +{ +} +#endif + +static void wma_update_hw_mode_config(tp_wma_handle wma_handle, + struct target_psoc_info *tgt_hdl) +{ + uint32_t conc_scan_config_bits, fw_config_bits; + + fw_config_bits = target_if_get_fw_config_bits(tgt_hdl); + conc_scan_config_bits = target_if_get_conc_scan_config_bits(tgt_hdl); + + wma_debug("Defaults: scan config:%x FW mode config:%x", + conc_scan_config_bits, fw_config_bits); + + if (wma_is_dbs_mandatory(wma_handle->psoc, tgt_hdl) && + (policy_mgr_is_dual_mac_disabled_in_ini(wma_handle->psoc))) { + policy_mgr_set_dual_mac_feature(wma_handle->psoc, + ENABLE_DBS_CXN_AND_DISABLE_SIMULTANEOUS_SCAN); + policy_mgr_set_ch_select_plcy(wma_handle->psoc, + POLICY_MGR_CH_SELECT_POLICY_DEF); + } + wma_init_scan_fw_mode_config(wma_handle->psoc, conc_scan_config_bits, + fw_config_bits); +} + +#define MAX_GRP_KEY 16 + +int wma_rx_service_ready_ext2_event(void *handle, uint8_t *ev, uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + struct target_psoc_info *tgt_hdl; + target_resource_config *wlan_res_cfg; + QDF_STATUS status; + + wma_debug("Enter"); + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return -EINVAL; + } + + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_hdl); + + if (wlan_mlme_is_multipass_sap(wma_handle->psoc)) + wlan_res_cfg->max_num_group_keys = MAX_GRP_KEY; + + status = policy_mgr_update_sbs_freq(wma_handle->psoc, tgt_hdl); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + wma_update_hw_mode_config(wma_handle, tgt_hdl); + + return 0; +} + +/** + * wma_rx_service_ready_ext_event() - evt handler for service ready ext event. + * @handle: wma handle + * @event: params of the service ready extended event + * @length: param length + * + * Return: none + */ +int wma_rx_service_ready_ext_event(void *handle, uint8_t *event, + uint32_t length) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *param_buf; + wmi_service_ready_ext_event_fixed_param *ev; + QDF_STATUS ret; + struct target_psoc_info *tgt_hdl; + struct wlan_psoc_target_capability_info *tgt_cap_info; + struct wmi_unified *wmi_handle; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + target_resource_config *wlan_res_cfg; + + wma_debug("Enter"); + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + wmi_handle = get_wmi_unified_hdl_from_psoc(wma_handle->psoc); + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return -EINVAL; + } + + wlan_res_cfg = target_psoc_get_wlan_res_cfg(tgt_hdl); + param_buf = (WMI_SERVICE_READY_EXT_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid event"); + return -EINVAL; + } + + ev = param_buf->fixed_param; + if (!ev) { + wma_err("Invalid buffer"); + return -EINVAL; + } + + wma_debug("WMA <-- WMI_SERVICE_READY_EXT_EVENTID"); + + tgt_cap_info = target_psoc_get_target_caps(tgt_hdl); + ret = qdf_mc_timer_stop(&wma_handle->service_ready_ext_timer); + if (!QDF_IS_STATUS_SUCCESS(ret)) { + wma_err("Failed to stop the service ready ext timer"); + return -EINVAL; + } + wma_populate_soc_caps(wma_handle, tgt_hdl, param_buf); + + ret = wma_update_hw_mode_list(wma_handle, tgt_hdl); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Failed to update hw mode list"); + return -EINVAL; + } + + wma_debug("WMA --> WMI_INIT_CMDID"); + + wma_update_hw_mode_config(wma_handle, tgt_hdl); + + target_psoc_set_num_radios(tgt_hdl, 1); + + wlan_dp_update_peer_map_unmap_version(&wlan_res_cfg->peer_map_unmap_version); + + if (wmi_service_enabled(wmi_handle, + wmi_service_new_htt_msg_format)) { + cdp_cfg_set_new_htt_msg_format(soc, 1); + wlan_res_cfg->new_htt_msg_format = true; + } else { + cdp_cfg_set_new_htt_msg_format(soc, 0); + wlan_res_cfg->new_htt_msg_format = false; + } + + if (QDF_GLOBAL_FTM_MODE != cds_get_conparam() && + ucfg_mlme_get_peer_unmap_conf(wma_handle->psoc) && + wmi_service_enabled(wmi_handle, + wmi_service_peer_unmap_cnf_support)) { + wlan_res_cfg->peer_unmap_conf_support = true; + cdp_cfg_set_peer_unmap_conf_support(soc, true); + } else { + wlan_res_cfg->peer_unmap_conf_support = false; + cdp_cfg_set_peer_unmap_conf_support(soc, false); + } + + if (wma_handle->enable_tx_compl_tsf64 && + wmi_service_enabled(wmi_handle, + wmi_service_tx_compl_tsf64)) { + wlan_res_cfg->tstamp64_en = true; + cdp_cfg_set_tx_compl_tsf64(soc, true); + } else { + wlan_res_cfg->tstamp64_en = false; + cdp_cfg_set_tx_compl_tsf64(soc, false); + } + + if (ucfg_is_ftm_time_sync_enable(wma_handle->psoc) && + wmi_service_enabled(wmi_handle, wmi_service_time_sync_ftm)) { + wlan_res_cfg->time_sync_ftm = true; + ucfg_ftm_time_sync_set_enable(wma_handle->psoc, true); + } else { + wlan_res_cfg->time_sync_ftm = false; + ucfg_ftm_time_sync_set_enable(wma_handle->psoc, false); + } + + if (wmi_service_enabled(wma_handle->wmi_handle, wmi_service_nan_vdev)) + ucfg_nan_set_vdev_creation_supp_by_fw(wma_handle->psoc, true); + + /* Change default hw mode as below kind of target will only be + * sending single HW mode + */ + if (!wmi_service_enabled(wmi_handle, + wmi_service_dual_band_simultaneous_support)) + wma_handle->new_hw_mode_index = + tgt_cap_info->default_dbs_hw_mode_index; + + /* + * Firmware can accommodate maximum 4 vdevs and the ini gNumVdevs + * indicates the same. + * If host driver is going to create vdev for NAN, it indicates + * the total no.of vdevs supported to firmware which includes the + * NAN vdev. + * If firmware is going to create NAN discovery vdev, host should + * indicate 3 vdevs and firmware shall add 1 vdev for NAN. So decrement + * the num_vdevs by 1. + * If NAN is not supported on some target(disabled through ini + * param gEnableNanSupport), there is no use of reserving one vdev for + * it in firmware though firmware advertises wmi_service_nan. Indicate + * firmware that host is going to take care of the NAN vdev. Host can + * use the vdev either for NAN or other operations on need basis. + */ + + if (wmi_service_enabled(wma_handle->wmi_handle, wmi_service_nan)) { + if (ucfg_nan_is_vdev_creation_allowed(wma_handle->psoc) || + QDF_GLOBAL_FTM_MODE == cds_get_conparam() || + !cfg_nan_get_enable(wma_handle->psoc)) { + wlan_res_cfg->nan_separate_iface_support = true; + } else { + wlan_res_cfg->num_vdevs--; + wma_update_num_peers_tids(wma_handle, wlan_res_cfg); + } + } + + if ((ucfg_pkt_capture_get_mode(wma_handle->psoc) != + PACKET_CAPTURE_MODE_DISABLE) && + wmi_service_enabled(wmi_handle, + wmi_service_packet_capture_support)) + wlan_res_cfg->pktcapture_support = true; + else + wlan_res_cfg->pktcapture_support = false; + wlan_res_cfg->max_peer_ext_stats = WMA_SON_MAX_PEER_EXT_STATS; + + if (wmi_service_enabled(wmi_handle, + wmi_service_sae_eapol_offload_support)) + wlan_res_cfg->sae_eapol_offload = true; + else + wlan_res_cfg->sae_eapol_offload = false; + + wma_debug("num_vdevs: %u", wlan_res_cfg->num_vdevs); + + wma_init_dbr_params(wma_handle); + + wma_set_coex_res_cfg(wma_handle, wmi_handle, wlan_res_cfg); + + return 0; +} + +/** + * wma_rx_ready_event() - event handler to process + * wmi rx ready event. + * @handle: wma handle + * @cmd_param_info: command params info + * @length: param length + * + * Return: none + */ +int wma_rx_ready_event(void *handle, uint8_t *cmd_param_info, + uint32_t length) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + WMI_READY_EVENTID_param_tlvs *param_buf = NULL; + wmi_ready_event_fixed_param *ev = NULL; + int ret; + + wma_debug("Enter"); + + param_buf = (WMI_READY_EVENTID_param_tlvs *) cmd_param_info; + if (!(wma_handle && param_buf)) { + wma_err("Invalid arguments"); + QDF_ASSERT(0); + return -EINVAL; + } + + wma_debug("WMA <-- WMI_READY_EVENTID"); + + if (wma_is_feature_set_supported(wma_handle)) + wma_send_feature_set_cmd(wma_handle); + + ev = param_buf->fixed_param; + /* Indicate to the waiting thread that the ready + * event was received + */ + wma_handle->sub_20_support = + wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_half_rate_quarter_rate_support); + wma_handle->wmi_ready = true; + wma_handle->wlan_init_status = ev->status; + + if (wma_handle->is_dfs_offloaded) + wmi_unified_dfs_phyerr_offload_en_cmd( + wma_handle->wmi_handle, 0); + /* copy the mac addr */ + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->myaddr); + WMI_MAC_ADDR_TO_CHAR_ARRAY(&ev->mac_addr, wma_handle->hwaddr); + ret = wma_update_hdd_cfg(wma_handle); + if (ret) + return ret; + + wma_debug("Exit"); + + return 0; +} + +/** + * wma_wait_for_ready_event() - wait for wma ready event + * @handle: wma handle + * + * Return: 0 for success or QDF error + */ +QDF_STATUS wma_wait_for_ready_event(WMA_HANDLE handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + QDF_STATUS status; + struct target_psoc_info *tgt_hdl; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return QDF_STATUS_E_INVAL; + } + + status = qdf_wait_for_event_completion(&tgt_hdl->info.event, + WMA_READY_EVENTID_TIMEOUT); + if (!tgt_hdl->info.wmi_ready) { + wma_err("Error in pdev creation"); + if (!cds_is_driver_recovering() || !cds_is_fw_down()) + QDF_DEBUG_PANIC("FW ready event timed out"); + return QDF_STATUS_E_INVAL; + } + + if (status == QDF_STATUS_E_TIMEOUT) + wma_err("Timeout waiting for FW ready event"); + else if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to wait for FW ready event; status:%u", status); + else + wma_info("FW ready event received"); + + return status; +} + +/** + * wma_set_ppsconfig() - set pps config in fw + * @vdev_id: vdev id + * @pps_param: pps params + * @val : param value + * + * Return: 0 for success or QDF error + */ +QDF_STATUS wma_set_ppsconfig(uint8_t vdev_id, uint16_t pps_param, + int val) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int ret = -EIO; + uint32_t pps_val; + + if (!wma) + return QDF_STATUS_E_INVAL; + + switch (pps_param) { + case WMA_VHT_PPS_PAID_MATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_PAID_MATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_GID_MATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_MATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_DELIM_CRC_FAIL: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_DELIM_CRC_FAIL & 0xffff); + goto pkt_pwr_save_config; + + /* Enable the code below as and when the functionality + * is supported/added in host. + */ +#ifdef NOT_YET + case WMA_VHT_PPS_EARLY_TIM_CLEAR: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_TIM_CLEAR & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_EARLY_DTIM_CLEAR: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EARLY_DTIM_CLEAR & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_EOF_PAD_DELIM: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_EOF_PAD_DELIM & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_MACADDR_MISMATCH: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_MACADDR_MISMATCH & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_GID_NSTS_ZERO: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_GID_NSTS_ZERO & 0xffff); + goto pkt_pwr_save_config; + case WMA_VHT_PPS_RSSI_CHECK: + pps_val = ((val << 31) & 0xffff0000) | + (PKT_PWR_SAVE_RSSI_CHECK & 0xffff); + goto pkt_pwr_save_config; +#endif /* NOT_YET */ +pkt_pwr_save_config: + wma_debug("vdev_id:%d val:0x%x pps_val:0x%x", vdev_id, + val, pps_val); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_packet_powersave, + pps_val); + break; + default: + wma_err("INVALID PPS CONFIG"); + } + + return (ret) ? QDF_STATUS_E_FAILURE : QDF_STATUS_SUCCESS; +} + +/** + * wma_process_set_mas() - Function to enable/disable MAS + * @wma: Pointer to WMA handle + * @mas_val: 1-Enable MAS, 0-Disable MAS + * + * This function enables/disables the MAS value + * + * Return: QDF_SUCCESS for success otherwise failure + */ +static QDF_STATUS wma_process_set_mas(tp_wma_handle wma, + uint32_t *mas_val) +{ + uint32_t val; + + if (!wma || !mas_val) { + wma_err("Invalid input to enable/disable MAS"); + return QDF_STATUS_E_FAILURE; + } + + val = (*mas_val); + + if (QDF_STATUS_SUCCESS != + wma_set_enable_disable_mcc_adaptive_scheduler(val)) { + wma_err("Unable to enable/disable MAS"); + return QDF_STATUS_E_FAILURE; + } + wma_debug("Value is %d", val); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_set_miracast() - Function to set miracast value in WMA + * @wma: Pointer to WMA handle + * @miracast_val: 0-Disabled,1-Source,2-Sink + * + * This function stores the miracast value in WMA + * + * Return: QDF_SUCCESS for success otherwise failure + * + */ +static QDF_STATUS wma_process_set_miracast(tp_wma_handle wma, + uint32_t *miracast_val) +{ + if (!wma || !miracast_val) { + wma_err("Invalid input to store miracast value"); + return QDF_STATUS_E_FAILURE; + } + + wma->miracast_value = *miracast_val; + wma_debug("Miracast value is %d", wma->miracast_value); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_config_stats_factor() - Function to configure stats avg. factor + * @wma: pointer to WMA handle + * @avg_factor: stats. avg. factor passed down by userspace + * + * This function configures the avg. stats value in firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +static QDF_STATUS wma_config_stats_factor(tp_wma_handle wma, + struct sir_stats_avg_factor *avg_factor) +{ + QDF_STATUS ret; + + if (!wma || !avg_factor) { + wma_err("Invalid input of stats avg factor"); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, + avg_factor->vdev_id, + wmi_vdev_param_stats_avg_factor, + avg_factor->stats_avg_factor); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("failed to set avg_factor for vdev_id %d", + avg_factor->vdev_id); + } + + wma_debug("Set stats_avg_factor %d for vdev_id %d", + avg_factor->stats_avg_factor, avg_factor->vdev_id); + + return ret; +} + +/** + * wma_config_guard_time() - Function to set guard time in firmware + * @wma: pointer to WMA handle + * @guard_time: guard time passed down by userspace + * + * This function configures the guard time in firmware + * + * Return: QDF_STATUS_SUCCESS for success otherwise failure + * + */ +static QDF_STATUS wma_config_guard_time(tp_wma_handle wma, + struct sir_guard_time_request *guard_time) +{ + QDF_STATUS ret; + + if (!wma || !guard_time) { + wma_err("Invalid input of guard time"); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma->wmi_handle, + guard_time->vdev_id, + wmi_vdev_param_rx_leak_window, + guard_time->guard_time); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("failed to set guard time for vdev_id %d", + guard_time->vdev_id); + } + + wma_debug("Set guard time %d for vdev_id %d", + guard_time->guard_time, guard_time->vdev_id); + + return ret; +} + +/** + * wma_enable_specific_fw_logs() - Start/Stop logging of diag event/log id + * @wma_handle: WMA handle + * @start_log: Start logging related parameters + * + * Send the command to the FW based on which specific logging of diag + * event/log id can be started/stopped + * + * Return: None + */ +static void wma_enable_specific_fw_logs(tp_wma_handle wma_handle, + struct sir_wifi_start_log *start_log) +{ + + if (!start_log) { + wma_err("start_log pointer is NULL"); + return; + } + if (wma_validate_handle(wma_handle)) + return; + + if (!((start_log->ring_id == RING_ID_CONNECTIVITY) || + (start_log->ring_id == RING_ID_FIRMWARE_DEBUG))) { + wma_debug("Not connectivity or fw debug ring: %d", + start_log->ring_id); + return; + } + + wmi_unified_enable_specific_fw_logs_cmd(wma_handle->wmi_handle, + (struct wmi_wifi_start_log *)start_log); +} + +#define MEGABYTE (1024 * 1024) +/** + * wma_set_wifi_start_packet_stats() - Start/stop packet stats + * @wma_handle: WMA handle + * @start_log: Structure containing the start wifi logger params + * + * This function is used to send the WMA commands to start/stop logging + * of per packet statistics + * + * Return: None + * + */ +#if !defined(FEATURE_PKTLOG) || defined(REMOVE_PKT_LOG) +static void wma_set_wifi_start_packet_stats(void *wma_handle, + struct sir_wifi_start_log *start_log) +{ +} + +#else +static void wma_set_wifi_start_packet_stats(void *wma_handle, + struct sir_wifi_start_log *start_log) +{ + struct hif_opaque_softc *scn; + uint32_t log_state; + + if (!start_log) { + wma_err("start_log pointer is NULL"); + return; + } + if (wma_validate_handle(wma_handle)) + return; + + /* No need to register for ring IDs other than packet stats */ + if (start_log->ring_id != RING_ID_PER_PACKET_STATS) { + wma_debug("Ring id is not for per packet stats: %d", + start_log->ring_id); + return; + } + + scn = cds_get_context(QDF_MODULE_ID_HIF); + if (!scn) { + wma_err("Invalid HIF handle"); + return; + } + +#ifdef PKTLOG_LEGACY + log_state = ATH_PKTLOG_ANI | ATH_PKTLOG_RCUPDATE | ATH_PKTLOG_RCFIND | + ATH_PKTLOG_RX | ATH_PKTLOG_TX | + ATH_PKTLOG_TEXT | ATH_PKTLOG_SW_EVENT; +#elif defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) || \ + defined(QCA_WIFI_QCA6750) || defined(QCA_WIFI_KIWI) || \ + defined(QCA_WIFI_WCN6450) + log_state = ATH_PKTLOG_RCFIND | ATH_PKTLOG_RCUPDATE | + ATH_PKTLOG_TX | ATH_PKTLOG_LITE_T2H | + ATH_PKTLOG_SW_EVENT | ATH_PKTLOG_RX; +#elif defined(QCA_WIFI_QCA6290) + log_state = ATH_PKTLOG_LITE_RX | ATH_PKTLOG_LITE_T2H; +#else + wma_debug("Packet log Not supported"); + log_state = 0; +#endif + if (start_log->size != 0) { + pktlog_setsize(scn, start_log->size * MEGABYTE); + return; + } else if (start_log->is_pktlog_buff_clear == true) { + pktlog_clearbuff(scn, start_log->is_pktlog_buff_clear); + return; + } + + if (start_log->verbose_level == WLAN_LOG_LEVEL_ACTIVE) { + pktlog_enable(scn, log_state, start_log->ini_triggered, + start_log->user_triggered, + start_log->is_iwpriv_command); + wma_debug("Enabling per packet stats"); + } else { + pktlog_enable(scn, 0, start_log->ini_triggered, + start_log->user_triggered, + start_log->is_iwpriv_command); + wma_debug("Disabling per packet stats"); + } +} +#endif + +/** + * wma_send_flush_logs_to_fw() - Send log flush command to FW + * @wma_handle: WMI handle + * + * This function is used to send the flush command to the FW, + * that will flush the fw logs that are residue in the FW + * + * Return: None + */ +void wma_send_flush_logs_to_fw(tp_wma_handle wma_handle) +{ + QDF_STATUS status; + + status = wmi_unified_flush_logs_to_fw_cmd(wma_handle->wmi_handle); + if (QDF_IS_STATUS_ERROR(status)) + return; + + status = qdf_mc_timer_start(&wma_handle->log_completion_timer, + WMA_LOG_COMPLETION_TIMER); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to start the log completion timer"); +} + +/** + * wma_update_tx_fail_cnt_th() - Set threshold for TX pkt fail + * @wma: WMA handle + * @tx_fail_cnt_th: sme_tx_fail_cnt_threshold parameter + * + * This function is used to set Tx pkt fail count threshold, + * FW will do disconnect with station once this threshold is reached. + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_update_tx_fail_cnt_th(tp_wma_handle wma, + struct sme_tx_fail_cnt_threshold *tx_fail_cnt_th) +{ + u_int8_t vdev_id; + u_int32_t tx_fail_disconn_th; + int ret = -EIO; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + vdev_id = tx_fail_cnt_th->session_id; + tx_fail_disconn_th = tx_fail_cnt_th->tx_fail_cnt_threshold; + wma_debug("Set TX pkt fail count threshold vdevId %d count %d", + vdev_id, tx_fail_disconn_th); + + ret = wma_vdev_set_param(wmi_handle, vdev_id, + wmi_vdev_param_disconnect_th, + tx_fail_disconn_th); + + if (ret) { + wma_err("Failed to send TX pkt fail count threshold command"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_short_retry_limit() - Set retry limit for short frames + * @wma: WMA handle + * @short_retry_limit_th: retry limir count for Short frames. + * + * This function is used to configure the transmission retry limit at which + * short frames needs to be retry. + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_update_short_retry_limit(tp_wma_handle wma, + struct sme_short_retry_limit *short_retry_limit_th) +{ + uint8_t vdev_id; + uint32_t short_retry_limit; + int ret; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + vdev_id = short_retry_limit_th->session_id; + short_retry_limit = short_retry_limit_th->short_retry_limit; + wma_debug("Set short retry limit threshold vdevId %d count %d", + vdev_id, short_retry_limit); + + ret = wma_vdev_set_param(wmi_handle, vdev_id, + wmi_vdev_param_non_agg_sw_retry_th, + short_retry_limit); + + if (ret) { + wma_err("Failed to send short limit threshold command"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_long_retry_limit() - Set retry limit for long frames + * @wma: WMA handle + * @long_retry_limit_th: retry limir count for long frames + * + * This function is used to configure the transmission retry limit at which + * long frames needs to be retry + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_update_long_retry_limit(tp_wma_handle wma, + struct sme_long_retry_limit *long_retry_limit_th) +{ + uint8_t vdev_id; + uint32_t long_retry_limit; + int ret; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + vdev_id = long_retry_limit_th->session_id; + long_retry_limit = long_retry_limit_th->long_retry_limit; + wma_debug("Set TX pkt fail count threshold vdevId %d count %d", + vdev_id, long_retry_limit); + + ret = wma_vdev_set_param(wmi_handle, vdev_id, + wmi_vdev_param_agg_sw_retry_th, + long_retry_limit); + + if (ret) { + wma_err("Failed to send long limit threshold command"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#define MAX_VDEV_AP_ALIVE_PARAMS 4 +/* params being sent: + * wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs + * wmi_vdev_param_ap_keepalive_max_idle_inactive_secs + * wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs + * wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs + */ + +/* + * wma_update_sta_inactivity_timeout() - Set sta_inactivity_timeout to fw + * @wma_handle: WMA handle + * @sta_inactivity_timer: sme_sta_inactivity_timeout + * + * This function is used to set sta_inactivity_timeout. + * If a station does not send anything in sta_inactivity_timeout seconds, an + * empty data frame is sent to it in order to verify whether it is + * still in range. If this frame is not ACKed, the station will be + * disassociated and then deauthenticated. + * + * Return: None + */ +void wma_update_sta_inactivity_timeout(tp_wma_handle wma, + struct sme_sta_inactivity_timeout *sta_inactivity_timer) +{ + uint8_t vdev_id; + uint32_t max_unresponsive_time; + uint32_t min_inactive_time, max_inactive_time; + struct wmi_unified *wmi_handle; + struct dev_set_param setparam[MAX_VDEV_AP_ALIVE_PARAMS] = {}; + uint8_t index = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (wma_validate_handle(wma)) + return; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return; + + vdev_id = sta_inactivity_timer->session_id; + max_unresponsive_time = sta_inactivity_timer->sta_inactivity_timeout; + max_inactive_time = max_unresponsive_time * TWO_THIRD; + min_inactive_time = max_unresponsive_time - max_inactive_time; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs, + min_inactive_time, index++, + MAX_VDEV_AP_ALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_max_idle_inactive_secs, + min_inactive_time, index++, MAX_VDEV_AP_ALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_max_idle_inactive_secs"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs, + max_inactive_time, index++, MAX_VDEV_AP_ALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs, + max_unresponsive_time, index++, + MAX_VDEV_AP_ALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs"); + goto error; + } + + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send idle_inactive,unresponsive time vdev set params"); + +error: + return; +} + +#ifdef WLAN_FEATURE_WOW_PULSE + + +#define WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM \ +WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMD_fixed_param + + +#define WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM \ +WMITLV_TAG_STRUC_wmi_wow_hostwakeup_gpio_pin_pattern_config_cmd_fixed_param + +/** + * wma_send_wow_pulse_cmd() - send wmi cmd of wow pulse cmd + * information to fw. + * @wma_handle: wma handler + * @wow_pulse_cmd: wow_pulse_mode pointer + * + * Return: Return QDF_STATUS + */ +static QDF_STATUS wma_send_wow_pulse_cmd(tp_wma_handle wma_handle, + struct wow_pulse_mode *wow_pulse_cmd) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + wmi_buf_t buf; + WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM *cmd; + u_int16_t len; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM *)wmi_buf_data(buf); + qdf_mem_zero(cmd, len); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM, + WMITLV_GET_STRUCT_TLVLEN( + WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM)); + + cmd->enable = wow_pulse_cmd->wow_pulse_enable; + cmd->pin = wow_pulse_cmd->wow_pulse_pin; + cmd->interval_low = wow_pulse_cmd->wow_pulse_interval_low; + cmd->interval_high = wow_pulse_cmd->wow_pulse_interval_high; + cmd->repeat_cnt = wow_pulse_cmd->wow_pulse_repeat_count; + cmd->init_state = wow_pulse_cmd->wow_pulse_init_state; + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_WOW_HOSTWAKEUP_GPIO_PIN_PATTERN_CONFIG_CMDID)) { + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + } + + wma_debug("Exit"); + return status; +} + +#undef WMI_WOW_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM +#undef WMITLV_TAG_HOSTWAKEUP_GPIO_CMD_FIXED_PARAM +#undef WMI_WOW_PULSE_REPEAT_CNT + +#else +static inline QDF_STATUS wma_send_wow_pulse_cmd(tp_wma_handle wma_handle, + struct wow_pulse_mode *wow_pulse_cmd) +{ + return QDF_STATUS_E_FAILURE; +} +#endif + + +/** + * wma_process_power_debug_stats_req() - Process the Chip Power stats collect + * request and pass the Power stats request to Fw + * @wma_handle: WMA handle + * + * Return: QDF_STATUS + */ +#ifdef WLAN_POWER_DEBUG +static QDF_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle) +{ + wmi_pdev_get_chip_power_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + cmd = (wmi_pdev_get_chip_power_stats_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_get_chip_power_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_get_chip_power_stats_cmd_fixed_param)); + cmd->pdev_id = 0; + + wma_debug("POWER_DEBUG_STATS - Get Request Params; Pdev id - %d", + cmd->pdev_id); + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_GET_CHIP_POWER_STATS_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS wma_process_power_debug_stats_req(tp_wma_handle wma_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#ifdef WLAN_FEATURE_BEACON_RECEPTION_STATS +static QDF_STATUS wma_process_beacon_debug_stats_req(tp_wma_handle wma_handle, + uint32_t *vdev_id) +{ + wmi_vdev_get_bcn_recv_stats_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + uint8_t *buf_ptr; + int ret; + + wma_debug("Enter"); + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *)wmi_buf_data(buf); + cmd = (wmi_vdev_get_bcn_recv_stats_cmd_fixed_param *)buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_get_bcn_recv_stats_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_vdev_get_bcn_recv_stats_cmd_fixed_param)); + cmd->vdev_id = *vdev_id; + + wma_debug("BEACON_DEBUG_STATS - Get Request Params; vdev id - %d", + cmd->vdev_id); + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_VDEV_GET_BCN_RECEPTION_STATS_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Exit"); + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS wma_process_beacon_debug_stats_req(tp_wma_handle wma_handle, + uint32_t *vdev_id) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_set_arp_req_stats() - process set arp stats request command to fw + * @handle: WMA handle + * @req_buf: set srp stats request buffer + * + * Return: None + */ +static void wma_set_arp_req_stats(WMA_HANDLE handle, + struct set_arp_stats_params *req_buf) +{ + QDF_STATUS status; + struct set_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wlan_objmgr_vdev *vdev; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return; + + if (!wma_is_vdev_valid(req_buf->vdev_id)) { + wma_err("vdev id:%d is not active", req_buf->vdev_id); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma_handle->psoc, + req_buf->vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("Can't get vdev by vdev_id:%d", req_buf->vdev_id); + return; + } + + if (!wma_is_vdev_up(req_buf->vdev_id)) { + wma_debug("vdev id:%d is not started", req_buf->vdev_id); + goto release_ref; + } + + arp_stats = (struct set_arp_stats *)req_buf; + status = wmi_unified_set_arp_stats_req(wmi_handle, arp_stats); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to set arp stats to FW"); + +release_ref: + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); +} + +/** + * wma_get_arp_req_stats() - process get arp stats request command to fw + * @wma_handle: WMA handle + * @req_buf: get srp stats request buffer + * + * Return: None + */ +static void wma_get_arp_req_stats(WMA_HANDLE handle, + struct get_arp_stats_params *req_buf) +{ + QDF_STATUS status; + struct get_arp_stats *arp_stats; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return; + + if (!wma_is_vdev_valid(req_buf->vdev_id)) { + wma_err("vdev id:%d is not active", req_buf->vdev_id); + return; + } + + arp_stats = (struct get_arp_stats *)req_buf; + status = wmi_unified_get_arp_stats_req(wmi_handle, arp_stats); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to send get arp stats to FW"); +} + +/** + * wma_set_del_pmkid_cache() - API to set/delete PMKID cache entry in fw + * @handle: WMA handle + * @pmk_cache: PMK cache entry + * + * Return: None + */ +static void wma_set_del_pmkid_cache(WMA_HANDLE handle, + struct wmi_unified_pmk_cache *pmk_cache) +{ + QDF_STATUS status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return; + + status = wmi_unified_set_del_pmkid_cache(wmi_handle, pmk_cache); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to send set/del pmkid cmd to fw"); +} + +/** + * wma_send_invoke_neighbor_report() - API to send invoke neighbor report + * command to fw + * + * @handle: WMA handle + * @params: Pointer to invoke neighbor report params + * + * Return: None + */ +static +void wma_send_invoke_neighbor_report(WMA_HANDLE handle, + struct wmi_invoke_neighbor_report_params *params) +{ + QDF_STATUS status; + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return; + + status = wmi_unified_invoke_neighbor_report_cmd(wmi_handle, params); + + if (status != QDF_STATUS_SUCCESS) + wma_err("failed to send invoke neighbor report command"); +} + +QDF_STATUS wma_set_rx_reorder_timeout_val(tp_wma_handle wma_handle, + struct sir_set_rx_reorder_timeout_val *reorder_timeout) +{ + wmi_pdev_set_reorder_timeout_val_cmd_fixed_param *cmd; + uint32_t len; + wmi_buf_t buf; + int ret; + + if (!reorder_timeout) { + wma_err("invalid pointer"); + return QDF_STATUS_E_INVAL; + } + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_pdev_set_reorder_timeout_val_cmd_fixed_param *) + wmi_buf_data(buf); + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_reorder_timeout_val_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_pdev_set_reorder_timeout_val_cmd_fixed_param)); + + memcpy(cmd->rx_timeout_pri, reorder_timeout->rx_timeout_pri, + sizeof(reorder_timeout->rx_timeout_pri)); + + wma_debug("rx aggr record timeout: VO: %d, VI: %d, BE: %d, BK: %d", + cmd->rx_timeout_pri[0], cmd->rx_timeout_pri[1], + cmd->rx_timeout_pri[2], cmd->rx_timeout_pri[3]); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_SET_REORDER_TIMEOUT_VAL_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_set_rx_blocksize(tp_wma_handle wma_handle, + struct sir_peer_set_rx_blocksize *peer_rx_blocksize) +{ + wmi_peer_set_rx_blocksize_cmd_fixed_param *cmd; + int32_t len; + wmi_buf_t buf; + u_int8_t *buf_ptr; + int ret; + + if (!peer_rx_blocksize) { + wma_err("invalid pointer"); + return QDF_STATUS_E_INVAL; + } + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + len = sizeof(*cmd); + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *) wmi_buf_data(buf); + cmd = (wmi_peer_set_rx_blocksize_cmd_fixed_param *) buf_ptr; + + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_peer_set_rx_blocksize_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_peer_set_rx_blocksize_cmd_fixed_param)); + + cmd->vdev_id = peer_rx_blocksize->vdev_id; + cmd->rx_block_ack_win_limit = + peer_rx_blocksize->rx_block_ack_win_limit; + WMI_CHAR_ARRAY_TO_MAC_ADDR(peer_rx_blocksize->peer_macaddr.bytes, + &cmd->peer_macaddr); + + wma_debug("rx aggr blocksize: %d", cmd->rx_block_ack_win_limit); + + ret = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PEER_SET_RX_BLOCKSIZE_CMDID); + if (ret) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_get_chain_rssi(tp_wma_handle wma_handle, + struct get_chain_rssi_req_params *req_params) +{ + wmi_pdev_div_get_rssi_antid_fixed_param *cmd; + wmi_buf_t wmi_buf; + uint32_t len = sizeof(wmi_pdev_div_get_rssi_antid_fixed_param); + u_int8_t *buf_ptr; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!wmi_buf) + return QDF_STATUS_E_NOMEM; + + buf_ptr = (u_int8_t *)wmi_buf_data(wmi_buf); + + cmd = (wmi_pdev_div_get_rssi_antid_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_div_get_rssi_antid_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_div_get_rssi_antid_fixed_param)); + cmd->pdev_id = 0; + WMI_CHAR_ARRAY_TO_MAC_ADDR(req_params->peer_macaddr.bytes, + &cmd->macaddr); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, len, + WMI_PDEV_DIV_GET_RSSI_ANTID_CMDID)) { + wmi_buf_free(wmi_buf); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#if defined(WLAN_FEATURE_FILS_SK) +/** + * wma_roam_scan_send_hlp() - API to send HLP IE info to fw + * @wma_handle: WMA handle + * @req: HLP params + * + * Return: QDF_STATUS + */ +static QDF_STATUS wma_roam_scan_send_hlp(tp_wma_handle wma_handle, + struct hlp_params *req) +{ + struct hlp_params *params; + QDF_STATUS status; + + params = qdf_mem_malloc(sizeof(*params)); + if (!params) + return QDF_STATUS_E_NOMEM; + + params->vdev_id = req->vdev_id; + params->hlp_ie_len = req->hlp_ie_len; + qdf_mem_copy(params->hlp_ie, req->hlp_ie, req->hlp_ie_len); + status = wmi_unified_roam_send_hlp_cmd(wma_handle->wmi_handle, params); + + wma_debug("Send HLP status %d vdev id %d", status, params->vdev_id); + qdf_trace_hex_dump(QDF_MODULE_ID_WMI, QDF_TRACE_LEVEL_DEBUG, + params->hlp_ie, 10); + + qdf_mem_free(params); + return status; +} +#else +static QDF_STATUS wma_roam_scan_send_hlp(tp_wma_handle wma_handle, + struct hlp_params *req) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_process_limit_off_chan() - set limit off channel parameters + * @wma_handle: pointer to wma handle + * @param: pointer to sir_limit_off_chan + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +static QDF_STATUS wma_process_limit_off_chan(tp_wma_handle wma_handle, + struct sir_limit_off_chan *param) +{ + int32_t err; + struct wmi_limit_off_chan_param limit_off_chan_param; + + if (param->vdev_id >= wma_handle->max_bssid) { + wma_err("Invalid vdev_id: %d", param->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!wma_is_vdev_up(param->vdev_id)) { + wma_debug("vdev %d is not up skipping limit_off_chan_param", + param->vdev_id); + return QDF_STATUS_E_INVAL; + } + + limit_off_chan_param.vdev_id = param->vdev_id; + limit_off_chan_param.status = param->is_tos_active; + limit_off_chan_param.max_offchan_time = param->max_off_chan_time; + limit_off_chan_param.rest_time = param->rest_time; + limit_off_chan_param.skip_dfs_chans = param->skip_dfs_chans; + + err = wmi_unified_send_limit_off_chan_cmd(wma_handle->wmi_handle, + &limit_off_chan_param); + if (err) { + wma_err("failed to set limit off chan cmd"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wma_process_obss_color_collision_req(tp_wma_handle wma_handle, + struct wmi_obss_color_collision_cfg_param *cfg) +{ + QDF_STATUS status; + + if (cfg->vdev_id >= wma_handle->max_bssid) { + wma_err("Invalid vdev_id: %d", cfg->vdev_id); + return QDF_STATUS_E_INVAL; + } + if (!wma_is_vdev_up(cfg->vdev_id)) { + wma_err("vdev %d is not up skipping obss color collision req", + cfg->vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_send_obss_color_collision_cfg_cmd(wma_handle-> + wmi_handle, cfg); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send obss color collision cfg"); + + return status; +} + +/** + * wma_send_obss_detection_cfg() - send obss detection cfg to firmware + * @wma_handle: pointer to wma handle + * @cfg: obss detection configuration + * + * Send obss detection configuration to firmware. + * + * Return: None + */ +static void wma_send_obss_detection_cfg(tp_wma_handle wma_handle, + struct wmi_obss_detection_cfg_param + *cfg) +{ + QDF_STATUS status; + + if (cfg->vdev_id >= wma_handle->max_bssid) { + wma_err("Invalid vdev_id: %d", cfg->vdev_id); + return; + } + if (!wma_is_vdev_up(cfg->vdev_id)) { + wma_err("vdev %d is not up skipping obss detection req", + cfg->vdev_id); + return; + } + + status = wmi_unified_send_obss_detection_cfg_cmd(wma_handle->wmi_handle, + cfg); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send obss detection cfg"); + + return; +} + +#ifdef WLAN_FEATURE_MOTION_DETECTION +/** + * wma_motion_det_host_event_handler - motion detection event handler + * @handle: WMA global handle + * @event: motion detection event + * @len: Length of cmd + * + * Call motion detection event callback handler + * + * Return: 0 on success, else error on failure + */ +int wma_motion_det_host_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + wmi_motion_det_event *motion_det_event_hdr; + WMI_MOTION_DET_HOST_EVENTID_param_tlvs *param_buf = + (WMI_MOTION_DET_HOST_EVENTID_param_tlvs *)event; + struct sir_md_evt *md_event; + struct mac_context *pmac = (struct mac_context *)cds_get_context( + QDF_MODULE_ID_PE); + + if (!param_buf) { + wma_err("Invalid motion det host event buffer"); + return -EINVAL; + } + + if (!pmac || !pmac->sme.md_host_evt_cb) { + wma_err("Invalid motion detect callback"); + return -EINVAL; + } + + motion_det_event_hdr = param_buf->fixed_param; + wma_alert("motion detect host event received, vdev_id=%d, status=%d", + motion_det_event_hdr->vdev_id, motion_det_event_hdr->status); + + md_event = qdf_mem_malloc(sizeof(*md_event)); + if (!md_event) + return -ENOMEM; + + md_event->vdev_id = motion_det_event_hdr->vdev_id; + md_event->status = motion_det_event_hdr->status; + + pmac->sme.md_host_evt_cb(pmac->sme.md_ctx, md_event); + + qdf_mem_free(md_event); + return 0; +} + +/** + * wma_motion_det_base_line_host_event_handler - md baselining event handler + * @handle: WMA global handle + * @event: motion detection baselining event + * @len: Length of cmd + * + * Return: 0 on success, else error on failure + */ +int wma_motion_det_base_line_host_event_handler(void *handle, + uint8_t *event, uint32_t len) +{ + wmi_motion_det_base_line_event *motion_det_base_line_event_hdr; + WMI_MOTION_DET_BASE_LINE_HOST_EVENTID_param_tlvs *param_buf = + (WMI_MOTION_DET_BASE_LINE_HOST_EVENTID_param_tlvs *)event; + struct sir_md_bl_evt *md_bl_event; + struct mac_context *pmac = (struct mac_context *)cds_get_context( + QDF_MODULE_ID_PE); + + if (!param_buf) { + wma_err("Invalid motion detection base line event buffer"); + return -EINVAL; + } + + if (!pmac || !pmac->sme.md_bl_evt_cb) { + wma_err("Invalid motion detection base line callback"); + return -EINVAL; + } + + motion_det_base_line_event_hdr = param_buf->fixed_param; + wma_alert("motion detection base line event received, vdev_id=%d", + motion_det_base_line_event_hdr->vdev_id); + wma_alert("baseline_value=%d bl_max_corr_resv=%d bl_min_corr_resv=%d", + motion_det_base_line_event_hdr->bl_baseline_value, + motion_det_base_line_event_hdr->bl_max_corr_reserved, + motion_det_base_line_event_hdr->bl_min_corr_reserved); + + md_bl_event = qdf_mem_malloc(sizeof(*md_bl_event)); + if (!md_bl_event) + return -ENOMEM; + + md_bl_event->vdev_id = motion_det_base_line_event_hdr->vdev_id; + md_bl_event->bl_baseline_value = + motion_det_base_line_event_hdr->bl_baseline_value; + md_bl_event->bl_max_corr_reserved = + motion_det_base_line_event_hdr->bl_max_corr_reserved; + md_bl_event->bl_min_corr_reserved = + motion_det_base_line_event_hdr->bl_min_corr_reserved; + + pmac->sme.md_bl_evt_cb(pmac->sme.md_ctx, md_bl_event); + + qdf_mem_free(md_bl_event); + return 0; +} + +/** + * wma_set_motion_det_config - Sends motion detection configuration wmi cmd + * @wma_handle: WMA global handle + * @motion_det_cfg: motion detection configuration + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_ERROR on error + */ +static QDF_STATUS wma_set_motion_det_config( + tp_wma_handle wma_handle, + struct sme_motion_det_cfg *motion_det_cfg) +{ + wmi_motion_det_config_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_motion_det_config_params_cmd_fixed_param *)wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_motion_det_config_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_motion_det_config_params_cmd_fixed_param)); + cmd->vdev_id = motion_det_cfg->vdev_id; + cmd->time_t1 = motion_det_cfg->time_t1; + cmd->time_t2 = motion_det_cfg->time_t2; + cmd->n1 = motion_det_cfg->n1; + cmd->n2 = motion_det_cfg->n2; + cmd->time_t1_gap = motion_det_cfg->time_t1_gap; + cmd->time_t2_gap = motion_det_cfg->time_t2_gap; + cmd->coarse_K = motion_det_cfg->coarse_K; + cmd->fine_K = motion_det_cfg->fine_K; + cmd->coarse_Q = motion_det_cfg->coarse_Q; + cmd->fine_Q = motion_det_cfg->fine_Q; + cmd->md_coarse_thr_high = motion_det_cfg->md_coarse_thr_high; + cmd->md_fine_thr_high = motion_det_cfg->md_fine_thr_high; + cmd->md_coarse_thr_low = motion_det_cfg->md_coarse_thr_low; + cmd->md_fine_thr_low = motion_det_cfg->md_fine_thr_low; + + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, sizeof(*cmd), + WMI_MOTION_DET_CONFIG_PARAM_CMDID); + if (err) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + wma_nofl_alert("Set motion_det_config to vdevId %d\n" + "time_t1 %d\n" + "time_t2 %d\n" + "n1 %d\n" + "n2 %d\n" + "time_t1_gap %d\n" + "time_t2_gap %d\n" + "coarse_K %d\n" + "fine_K %d\n" + "coarse_Q %d\n" + "fine_Q %d\n" + "md_coarse_thr_high %d\n" + "md_fine_thr_high %d\n" + "md_coarse_thr_low %d\n" + "md_fine_thr_low %d\n", + motion_det_cfg->vdev_id, + motion_det_cfg->time_t1, + motion_det_cfg->time_t2, + motion_det_cfg->n1, + motion_det_cfg->n2, + motion_det_cfg->time_t1_gap, + motion_det_cfg->time_t2_gap, + motion_det_cfg->coarse_K, + motion_det_cfg->fine_K, + motion_det_cfg->coarse_Q, + motion_det_cfg->fine_Q, + motion_det_cfg->md_coarse_thr_high, + motion_det_cfg->md_fine_thr_high, + motion_det_cfg->md_coarse_thr_low, + motion_det_cfg->md_fine_thr_low); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_motion_det_enable - Sends motion detection start/stop wmi cmd + * @wma_handle: WMA global handle + * @md_en: motion detection start/stop + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_ERROR on error + */ +static QDF_STATUS wma_set_motion_det_enable(tp_wma_handle wma_handle, + struct sme_motion_det_en *md_en) +{ + wmi_motion_det_start_stop_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_motion_det_start_stop_cmd_fixed_param *)wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_motion_det_start_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_motion_det_start_stop_cmd_fixed_param)); + cmd->vdev_id = md_en->vdev_id; + cmd->enable = md_en->enable; + + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, sizeof(*cmd), + WMI_MOTION_DET_START_STOP_CMDID); + if (err) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + wma_alert("Set motion_det_enable to vdevId %d %d", md_en->vdev_id, + md_en->enable); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_motion_det_base_line_config - Sends md baselining cfg wmi cmd + * @wma_handle: WMA global handle + * @md_base_line_cfg: md baselining configuration + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_ERROR on error + */ +static QDF_STATUS wma_set_motion_det_base_line_config( + tp_wma_handle wma_handle, + struct sme_motion_det_base_line_cfg *md_base_line_cfg) +{ + wmi_motion_det_base_line_config_params_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_motion_det_base_line_config_params_cmd_fixed_param *) + wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_motion_det_base_line_config_params_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_motion_det_base_line_config_params_cmd_fixed_param)); + + cmd->vdev_id = md_base_line_cfg->vdev_id; + cmd->bl_time_t = md_base_line_cfg->bl_time_t; + cmd->bl_packet_gap = md_base_line_cfg->bl_packet_gap; + cmd->bl_n = md_base_line_cfg->bl_n; + cmd->bl_num_meas = md_base_line_cfg->bl_num_meas; + + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, sizeof(*cmd), + WMI_MOTION_DET_BASE_LINE_CONFIG_PARAM_CMDID); + if (err) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + wma_nofl_alert("Set motion_det_baseline_config to vdevId %d\n" + "bl_time_t %d\n" + "bl_packet_gap %d\n" + "bl_n %d\n" + "bl_num_meas %d\n", + md_base_line_cfg->vdev_id, + md_base_line_cfg->bl_time_t, + md_base_line_cfg->bl_packet_gap, + md_base_line_cfg->bl_n, + md_base_line_cfg->bl_num_meas); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_motion_det_base_line_enable - Sends md baselining start/stop wmi cmd + * @wma_handle: WMA global handle + * @md_base_line_en: motion detection baselining start/stop + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_ERROR on error + */ +static QDF_STATUS wma_set_motion_det_base_line_enable( + tp_wma_handle wma_handle, + struct sme_motion_det_base_line_en *md_base_line_en) +{ + wmi_motion_det_base_line_start_stop_cmd_fixed_param *cmd; + wmi_buf_t buf; + int err; + + buf = wmi_buf_alloc(wma_handle->wmi_handle, sizeof(*cmd)); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_motion_det_base_line_start_stop_cmd_fixed_param *) + wmi_buf_data(buf); + qdf_mem_zero(cmd, sizeof(*cmd)); + + WMITLV_SET_HDR( + &cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_motion_det_base_line_start_stop_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_motion_det_base_line_start_stop_cmd_fixed_param)); + + cmd->vdev_id = md_base_line_en->vdev_id; + cmd->enable = md_base_line_en->enable; + + err = wmi_unified_cmd_send(wma_handle->wmi_handle, buf, sizeof(*cmd), + WMI_MOTION_DET_BASE_LINE_START_STOP_CMDID); + if (err) { + wmi_buf_free(buf); + return QDF_STATUS_E_FAILURE; + } + wma_alert("Set motion_det_base_line_enable to vdevId %d enable %d", + md_base_line_en->vdev_id, md_base_line_en->enable); + return QDF_STATUS_SUCCESS; +} +#endif /* WLAN_FEATURE_MOTION_DETECTION */ + +/** + * wma_mc_process_msg() - process wma messages and call appropriate function. + * @msg: message + * + * Return: QDF_SUCCESS for success otherwise failure + */ +static QDF_STATUS wma_mc_process_msg(struct scheduler_msg *msg) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle; + + if (!msg) { + wma_err("msg is NULL"); + QDF_ASSERT(0); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + wma_nofl_debug("Handle msg %s(0x%x)", + mac_trace_get_wma_msg_string(msg->type), msg->type); + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) { + QDF_ASSERT(0); + qdf_mem_free(msg->bodyptr); + qdf_status = QDF_STATUS_E_INVAL; + goto end; + } + + switch (msg->type) { +#ifdef FEATURE_WLAN_ESE + case WMA_TSM_STATS_REQ: + wma_debug("McThread: WMA_TSM_STATS_REQ"); + wma_process_tsm_stats_req(wma_handle, (void *)msg->bodyptr); + break; +#endif /* FEATURE_WLAN_ESE */ + case WMA_UPDATE_CHAN_LIST_REQ: + wma_update_channel_list(wma_handle, + (tSirUpdateChanList *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_ADD_STA_REQ: + wma_add_sta(wma_handle, (tpAddStaParams) msg->bodyptr); + break; + case WMA_SEND_PEER_UNMAP_CONF: + wma_peer_unmap_conf_send( + wma_handle, + (struct send_peer_unmap_conf_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DELETE_STA_REQ: + wma_delete_sta(wma_handle, (tpDeleteStaParams) msg->bodyptr); + break; + case WMA_DELETE_BSS_HO_FAIL_REQ: + wma_delete_bss_ho_fail(wma_handle, msg->bodyval); + break; + case WMA_DELETE_BSS_REQ: + wma_delete_bss(wma_handle, msg->bodyval); + break; + case WMA_UPDATE_EDCA_PROFILE_IND: + wma_process_update_edca_param_req(wma_handle, + (tEdcaParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_BEACON_REQ: + wma_send_beacon(wma_handle, (tpSendbeaconParams) msg->bodyptr); + break; + case WMA_SEND_AP_VDEV_UP: + wma_set_ap_vdev_up(wma_handle, msg->bodyval); + break; + case WMA_SEND_PROBE_RSP_TMPL: + wma_send_probe_rsp_tmpl(wma_handle, + (tpSendProbeRespParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_CLI_SET_CMD: + wma_process_cli_set_cmd(wma_handle, + (wma_cli_set_cmd_t *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PDEV_IE_REQ: + wma_process_set_pdev_ie_req(wma_handle, + (struct set_ie_param *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#if !defined(REMOVE_PKT_LOG) && defined(FEATURE_PKTLOG) + case WMA_PKTLOG_ENABLE_REQ: + wma_pktlog_wmi_send_cmd(wma_handle, + (struct ath_pktlog_wmi_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* REMOVE_PKT_LOG */ + case WMA_ENABLE_UAPSD_REQ: + wma_enable_uapsd_mode(wma_handle, + (tpEnableUapsdParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DISABLE_UAPSD_REQ: + wma_disable_uapsd_mode(wma_handle, + (tpDisableUapsdParams) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_DTIM_PERIOD: + wma_set_dtim_period(wma_handle, + (struct set_dtim_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_TX_POWER_REQ: + wma_set_tx_power(wma_handle, (tpMaxTxPowerParams) msg->bodyptr); + break; + case WMA_SET_MAX_TX_POWER_REQ: + wma_set_max_tx_power(wma_handle, + (tpMaxTxPowerParams) msg->bodyptr); + break; + case WMA_SET_KEEP_ALIVE: + wma_set_keepalive_req(wma_handle, msg->bodyptr); + break; +#ifdef FEATURE_WLAN_ESE + case WMA_SET_PLM_REQ: + wma_config_plm(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif + + case WMA_UPDATE_OP_MODE: + wma_process_update_opmode(wma_handle, + (tUpdateVHTOpMode *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_RX_NSS: + wma_process_update_rx_nss(wma_handle, + (tUpdateRxNss *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_MEMBERSHIP: + wma_process_update_membership(wma_handle, + (tUpdateMembership *) msg->bodyptr); + break; + case WMA_UPDATE_USERPOS: + wma_process_update_userpos(wma_handle, + (tUpdateUserPos *) msg->bodyptr); + break; + case WMA_UPDATE_BEACON_IND: + wma_process_update_beacon_params(wma_handle, + (tUpdateBeaconParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_ADD_TS_REQ: + wma_add_ts_req(wma_handle, msg->bodyptr); + break; + + case WMA_DEL_TS_REQ: + wma_del_ts_req(wma_handle, msg->bodyptr); + break; + + case WMA_AGGR_QOS_REQ: + wma_aggr_qos_req(wma_handle, msg->bodyptr); + break; + + case WMA_8023_MULTICAST_LIST_REQ: + wma_process_mcbc_set_filter_req(wma_handle, + (tpSirRcvFltMcAddrList) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_ROAM_PRE_AUTH_STATUS: + wma_send_roam_preauth_status(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_ROAM_SYNC_TIMEOUT: + wma_handle_roam_sync_timeout(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_RATE_UPDATE_IND: + wma_process_rate_update_indicate(wma_handle, + (tSirRateUpdateInd *) msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_TDLS + case WMA_UPDATE_TDLS_PEER_STATE: + wma_update_tdls_peer_state(wma_handle, msg->bodyptr); + break; +#endif /* FEATURE_WLAN_TDLS */ + case WMA_ADD_PERIODIC_TX_PTRN_IND: + wma_process_add_periodic_tx_ptrn_ind(wma_handle, + (tSirAddPeriodicTxPtrn *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_DEL_PERIODIC_TX_PTRN_IND: + wma_process_del_periodic_tx_ptrn_ind(wma_handle, + (tSirDelPeriodicTxPtrn *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TX_POWER_LIMIT: + wma_process_tx_power_limits(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_ADDBA_REQ: + wma_process_send_addba_req(wma_handle, + (struct send_add_ba_req *)msg->bodyptr); + break; + +#ifdef FEATURE_WLAN_CH_AVOID + case WMA_CH_AVOID_UPDATE_REQ: + wma_process_ch_avoid_update_req(wma_handle, + (tSirChAvoidUpdateReq *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_CH_AVOID */ +#ifdef FEATURE_WLAN_AUTO_SHUTDOWN + case WMA_SET_AUTO_SHUTDOWN_TIMER_REQ: + wma_set_auto_shutdown_timer_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_AUTO_SHUTDOWN */ + case WMA_DHCP_START_IND: + case WMA_DHCP_STOP_IND: + wma_process_dhcp_ind(wma_handle, (tAniDHCPInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_INIT_THERMAL_INFO_CMD: + wma_process_init_thermal_info(wma_handle, + (t_thermal_mgmt *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + + case WMA_SET_THERMAL_LEVEL: + wma_process_set_thermal_level(wma_handle, msg->bodyval); + break; +#ifdef CONFIG_HL_SUPPORT + case WMA_INIT_BAD_PEER_TX_CTL_INFO_CMD: + wma_process_init_bad_peer_tx_ctl_info( + wma_handle, + (struct t_bad_peer_txtcl_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif + case WMA_SET_MIMOPS_REQ: + wma_process_set_mimops_req(wma_handle, + (tSetMIMOPS *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_SAP_INTRABSS_DIS: + wma_set_vdev_intrabss_fwd(wma_handle, + (tDisableIntraBssFwd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_ISOLATION: + wma_get_isolation(wma_handle); + break; + case WMA_MODEM_POWER_STATE_IND: + wma_notify_modem_power_state(wma_handle, + (tSirModemPowerStateInd *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_STATS_EXT + case WMA_STATS_EXT_REQUEST: + wma_stats_ext_req(wma_handle, + (tpStatsExtRequest) (msg->bodyptr)); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_STATS_EXT */ +#ifdef WLAN_FEATURE_EXTWOW_SUPPORT + case WMA_WLAN_EXT_WOW: + wma_enable_ext_wow(wma_handle, + (tSirExtWoWParams *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_SET_APP_TYPE1_PARAMS: + wma_set_app_type1_params_in_fw(wma_handle, + (tSirAppType1Params *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_WLAN_SET_APP_TYPE2_PARAMS: + wma_set_app_type2_params_in_fw(wma_handle, + (tSirAppType2Params *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_EXTWOW_SUPPORT */ +#ifdef FEATURE_WLAN_EXTSCAN + case WMA_EXTSCAN_START_REQ: + wma_start_extscan(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_STOP_REQ: + wma_stop_extscan(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_SET_BSSID_HOTLIST_REQ: + wma_extscan_start_hotlist_monitor(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_RESET_BSSID_HOTLIST_REQ: + wma_extscan_stop_hotlist_monitor(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_SET_SIGNF_CHANGE_REQ: + wma_extscan_start_change_monitor(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_RESET_SIGNF_CHANGE_REQ: + wma_extscan_stop_change_monitor(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CACHED_RESULTS_REQ: + wma_extscan_get_cached_results(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_EXTSCAN_GET_CAPABILITIES_REQ: + wma_extscan_get_capabilities(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_EPNO_LIST_REQ: + wma_set_epno_network_list(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_PASSPOINT_LIST_REQ: + /* Issue reset passpoint network list first and clear + * the entries + */ + wma_reset_passpoint_network_list(wma_handle, msg->bodyptr); + + wma_set_passpoint_network_list(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_RESET_PASSPOINT_LIST_REQ: + wma_reset_passpoint_network_list(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* FEATURE_WLAN_EXTSCAN */ + case WMA_SET_SCAN_MAC_OUI_REQ: + wma_scan_probe_setoui(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + case WMA_LINK_LAYER_STATS_CLEAR_REQ: + wma_process_ll_stats_clear_req(wma_handle, + (tpSirLLStatsClearReq) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_LAYER_STATS_SET_REQ: + wma_process_ll_stats_set_req(wma_handle, + (tpSirLLStatsSetReq) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_LAYER_STATS_GET_REQ: + wma_process_ll_stats_get_req(wma_handle, + (tpSirLLStatsGetReq) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WDA_LINK_LAYER_STATS_SET_THRESHOLD: + wma_config_stats_ext_threshold(wma_handle, + (struct sir_ll_ext_stats_threshold *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + case SIR_HAL_SET_BASE_MACADDR_IND: + wma_set_base_macaddr_indicate(wma_handle, + (tSirMacAddr *) msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_LINK_STATUS_GET_REQ: + wma_process_link_status_req(wma_handle, + (tAniGetLinkStatus *) msg->bodyptr); + break; + case WMA_GET_TEMPERATURE_REQ: + wma_get_temperature(wma_handle); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TSF_GPIO_PIN: + wma_set_tsf_gpio_pin(wma_handle, msg->bodyval); + break; + +#ifdef DHCP_SERVER_OFFLOAD + case WMA_SET_DHCP_SERVER_OFFLOAD_CMD: + wma_process_dhcpserver_offload(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* DHCP_SERVER_OFFLOAD */ +#ifdef WLAN_FEATURE_GPIO_LED_FLASHING + case WMA_LED_FLASHING_REQ: + wma_set_led_flashing(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_GPIO_LED_FLASHING */ + case SIR_HAL_SET_MAS: + wma_process_set_mas(wma_handle, + (uint32_t *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SET_MIRACAST: + wma_process_set_miracast(wma_handle, + (uint32_t *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_CONFIG_STATS_FACTOR: + wma_config_stats_factor(wma_handle, + (struct sir_stats_avg_factor *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_CONFIG_GUARD_TIME: + wma_config_guard_time(wma_handle, + (struct sir_guard_time_request *) + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_START_STOP_LOGGING: + wma_set_wifi_start_packet_stats(wma_handle, + (struct sir_wifi_start_log *)msg->bodyptr); + wma_enable_specific_fw_logs(wma_handle, + (struct sir_wifi_start_log *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_FLUSH_LOG_TO_FW: + wma_send_flush_logs_to_fw(wma_handle); + /* Body ptr is NULL here */ + break; + case WMA_SET_RSSI_MONITOR_REQ: + wma_set_rssi_monitoring(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SET_PCL_TO_FW: + wma_send_set_pcl_cmd(wma_handle, + (struct set_pcl_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_PDEV_SET_HW_MODE: + wma_send_pdev_set_hw_mode_cmd(wma_handle, + (struct policy_mgr_hw_mode *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_WISA_PARAMS: + wma_set_wisa_params(wma_handle, + (struct sir_wisa_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_PDEV_DUAL_MAC_CFG_REQ: + wma_send_pdev_set_dual_mac_config(wma_handle, + (struct policy_mgr_dual_mac_config *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_IE_INFO: + wma_process_set_ie_info(wma_handle, + (struct vdev_ie_info *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_CFG_VENDOR_ACTION_TB_PPDU: + wma_process_cfg_action_frm_tb_ppdu(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SOC_ANTENNA_MODE_REQ: + wma_send_pdev_set_antenna_mode(wma_handle, + (struct sir_antenna_mode_param *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GW_PARAM_UPDATE_REQ: + wma_set_gateway_params(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_ADAPT_DWELLTIME_CONF_PARAMS: + wma_send_adapt_dwelltime_params(wma_handle, + (struct adaptive_dwelltime_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_HT40_OBSS_SCAN_IND: + wma_send_ht40_obss_scanind(wma_handle, + (struct obss_ht40_scanind *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_ADD_BCN_FILTER_CMDID: + wma_add_beacon_filter(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_REMOVE_BCN_FILTER_CMDID: + wma_remove_beacon_filter(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WDA_APF_GET_CAPABILITIES_REQ: + wma_get_apf_capabilities(wma_handle); + break; + case SIR_HAL_POWER_DBG_CMD: + wma_process_hal_pwr_dbg_cmd(wma_handle, + msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SEND_FREQ_RANGE_CONTROL_IND: + wma_enable_disable_caevent_ind(wma_handle, msg->bodyval); + break; + case SIR_HAL_UPDATE_TX_FAIL_CNT_TH: + wma_update_tx_fail_cnt_th(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_LONG_RETRY_LIMIT_CNT: + wma_update_long_retry_limit(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SHORT_RETRY_LIMIT_CNT: + wma_update_short_retry_limit(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_POWER_DEBUG_STATS_REQ: + wma_process_power_debug_stats_req(wma_handle); + break; + case WMA_BEACON_DEBUG_STATS_REQ: + wma_process_beacon_debug_stats_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_RCPI_REQ: + wma_get_rcpi_req(wma_handle, + (struct sme_rcpi_req *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_WOW_PULSE_CMD: + wma_send_wow_pulse_cmd(wma_handle, + (struct wow_pulse_mode *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_DBS_SCAN_SEL_CONF_PARAMS: + wma_send_dbs_scan_selection_params(wma_handle, + (struct wmi_dbs_scan_sel_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_ARP_STATS_REQ: + wma_set_arp_req_stats(wma_handle, + (struct set_arp_stats_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_ARP_STATS_REQ: + wma_get_arp_req_stats(wma_handle, + (struct get_arp_stats_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case SIR_HAL_SET_DEL_PMKID_CACHE: + wma_set_del_pmkid_cache(wma_handle, msg->bodyptr); + if (msg->bodyptr) { + qdf_mem_zero(msg->bodyptr, + sizeof(struct wmi_unified_pmk_cache)); + qdf_mem_free(msg->bodyptr); + } + break; + case SIR_HAL_HLP_IE_INFO: + wma_roam_scan_send_hlp(wma_handle, + (struct hlp_params *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_LIMIT_OFF_CHAN: + wma_process_limit_off_chan(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OBSS_DETECTION_REQ: + wma_send_obss_detection_cfg(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_INVOKE_NEIGHBOR_REPORT: + wma_send_invoke_neighbor_report(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_OBSS_COLOR_COLLISION_REQ: + wma_process_obss_color_collision_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_GET_ROAM_SCAN_STATS: + wma_get_roam_scan_stats(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#ifdef WLAN_FEATURE_MOTION_DETECTION + case WMA_SET_MOTION_DET_CONFIG: + wma_set_motion_det_config( + wma_handle, + (struct sme_motion_det_cfg *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_MOTION_DET_ENABLE: + wma_set_motion_det_enable( + wma_handle, + (struct sme_motion_det_en *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_MOTION_DET_BASE_LINE_CONFIG: + wma_set_motion_det_base_line_config( + wma_handle, + (struct sme_motion_det_base_line_cfg *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_MOTION_DET_BASE_LINE_ENABLE: + wma_set_motion_det_base_line_enable( + wma_handle, + (struct sme_motion_det_base_line_en *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif /* WLAN_FEATURE_MOTION_DETECTION */ +#ifdef FW_THERMAL_THROTTLE_SUPPORT + case WMA_SET_THERMAL_THROTTLE_CFG: + if (!wma_handle->thermal_mgmt_info.thermalMgmtEnabled) + wmi_unified_thermal_mitigation_param_cmd_send( + wma_handle->wmi_handle, msg->bodyptr); + else + qdf_status = QDF_STATUS_E_INVAL; + qdf_mem_free(msg->bodyptr); + break; + case WMA_SET_THERMAL_MGMT: + if (!wma_handle->thermal_mgmt_info.thermalMgmtEnabled) + wma_set_thermal_mgmt( + wma_handle, + *((t_thermal_cmd_params *)msg->bodyptr)); + else + qdf_status = QDF_STATUS_E_INVAL; + qdf_mem_free(msg->bodyptr); + break; +#endif /* FW_THERMAL_THROTTLE_SUPPORT */ +#ifdef WLAN_MWS_INFO_DEBUGFS + case WMA_GET_MWS_COEX_INFO_REQ: + wma_get_mws_coex_info_req(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; +#endif + case WMA_ROAM_SCAN_CH_REQ: + wma_get_roam_scan_ch(wma_handle->wmi_handle, msg->bodyval); + break; + case WMA_TWT_ADD_DIALOG_REQUEST: + wma_twt_process_add_dialog(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TWT_DEL_DIALOG_REQUEST: + wma_twt_process_del_dialog(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TWT_PAUSE_DIALOG_REQUEST: + wma_twt_process_pause_dialog(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TWT_RESUME_DIALOG_REQUEST: + wma_twt_process_resume_dialog(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_TWT_NUDGE_DIALOG_REQUEST: + wma_twt_process_nudge_dialog(wma_handle, msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + case WMA_UPDATE_EDCA_PIFS_PARAM_IND: + wma_update_edca_pifs_param( + wma_handle, + (struct edca_pifs_vparam *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; + default: + wma_debug("Unhandled WMA message of type %d", msg->type); + if (msg->bodyptr) + qdf_mem_free(msg->bodyptr); + } +end: + return qdf_status; +} + +QDF_STATUS wma_mc_process_handler(struct scheduler_msg *msg) +{ + return wma_mc_process_msg(msg); +} + +/** + * wma_log_completion_timeout() - Log completion timeout + * @data: Timeout handler data + * + * This function is called when log completion timer expires + * + * Return: None + */ +void wma_log_completion_timeout(void *data) +{ + wma_debug("Timeout occurred for log completion command"); + + /* Though we did not receive any event from FW, + * we can flush whatever logs we have with us + */ + cds_logging_set_fw_flush_complete(); +} + +/** + * wma_map_pcl_weights() - Map PCL weights + * @pcl_weight: Internal PCL weights + * + * Maps the internal weights of PCL to the weights needed by FW + * + * Return: Mapped channel weight of type wmi_pcl_chan_weight + */ +wmi_pcl_chan_weight wma_map_pcl_weights(uint32_t pcl_weight) +{ + switch (pcl_weight) { + case WEIGHT_OF_GROUP1_PCL_CHANNELS: + return WMI_PCL_WEIGHT_VERY_HIGH; + case WEIGHT_OF_GROUP2_PCL_CHANNELS: + return WMI_PCL_WEIGHT_HIGH; + case WEIGHT_OF_GROUP3_PCL_CHANNELS: + return WMI_PCL_WEIGHT_MEDIUM; + case WEIGHT_OF_GROUP4_PCL_CHANNELS: + return WMI_PCL_WEIGHT_MEDIUM; + case WEIGHT_OF_NON_PCL_CHANNELS: + return WMI_PCL_WEIGHT_LOW; + default: + return WMI_PCL_WEIGHT_DISALLOW; + } +} + +/** + * wma_send_set_pcl_cmd() - Send WMI_SOC_SET_PCL_CMDID to FW + * @wma_handle: WMA handle + * @msg: PCL structure containing the PCL and the number of channels + * + * WMI_PDEV_SET_PCL_CMDID provides a Preferred Channel List (PCL) to the WLAN + * firmware. The DBS Manager is the consumer of this information in the WLAN + * firmware. The channel list will be used when a Virtual DEVice (VDEV) needs + * to migrate to a new channel without host driver involvement. An example of + * this behavior is Legacy Fast Roaming (LFR 3.0). Generally, the host will + * manage the channel selection without firmware involvement. + * + * WMI_PDEV_SET_PCL_CMDID will carry only the weight list and not the actual + * channel list. The weights corresponds to the channels sent in + * WMI_SCAN_CHAN_LIST_CMDID. The channels from PCL would be having a higher + * weightage compared to the non PCL channels. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +QDF_STATUS wma_send_set_pcl_cmd(tp_wma_handle wma_handle, + struct set_pcl_req *msg) +{ + uint32_t i; + QDF_STATUS status; + bool is_channel_allowed; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_NULL_VALUE; + + /* + * if vdev_id is WLAN_UMAC_VDEV_ID_MAX, then roaming is enabled on + * only one sta, so PDEV PCL command needs to be sent. + * If a valid vdev id is present, then vdev pcl command needs to be + * sent. + */ + if (msg->vdev_id != WLAN_UMAC_VDEV_ID_MAX) + return wlan_cm_roam_send_set_vdev_pcl(wma_handle->psoc, msg); + + + wma_debug("RSO_CFG: BandCapability:%d, band_mask:%d", + wma_handle->bandcapability, msg->band_mask); + for (i = 0; i < wma_handle->saved_chan.num_channels; i++) { + msg->chan_weights.saved_chan_list[i] = + wma_handle->saved_chan.ch_freq_list[i]; + } + + msg->chan_weights.saved_num_chan = wma_handle->saved_chan.num_channels; + + status = policy_mgr_get_valid_chan_weights(wma_handle->psoc, + (struct policy_mgr_pcl_chan_weights *)&msg->chan_weights, + PM_STA_MODE, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Error in creating weighed pcl"); + return status; + } + + for (i = 0; i < msg->chan_weights.saved_num_chan; i++) { + msg->chan_weights.weighed_valid_list[i] = + wma_map_pcl_weights( + msg->chan_weights.weighed_valid_list[i]); + + is_channel_allowed = + policy_mgr_is_sta_chan_valid_for_connect_and_roam( + wma_handle->pdev, + msg->chan_weights.saved_chan_list[i]); + if (!is_channel_allowed) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + + if (msg->band_mask == + (BIT(REG_BAND_2G) | BIT(REG_BAND_5G) | BIT(REG_BAND_6G))) + continue; + + /* + * Dont allow roaming on 5G/6G band if only 2G band configured + * as supported roam band mask + */ + if (((wma_handle->bandcapability == BAND_2G) || + (msg->band_mask == BIT(REG_BAND_2G))) && + !WLAN_REG_IS_24GHZ_CH_FREQ( + msg->chan_weights.saved_chan_list[i])) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + + /* + * Dont allow roaming on 2G/6G band if only 5G band configured + * as supported roam band mask + */ + if (((wma_handle->bandcapability == BAND_5G) || + (msg->band_mask == BIT(REG_BAND_5G))) && + !WLAN_REG_IS_5GHZ_CH_FREQ( + msg->chan_weights.saved_chan_list[i])) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + + /* + * Dont allow roaming on 2G/5G band if only 6G band configured + * as supported roam band mask + */ + if (msg->band_mask == BIT(REG_BAND_6G) && + !WLAN_REG_IS_6GHZ_CHAN_FREQ( + msg->chan_weights.saved_chan_list[i])) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + + /* + * Dont allow roaming on 6G band if only 2G + 5G band configured + * as supported roam band mask. + */ + if (msg->band_mask == (BIT(REG_BAND_2G) | BIT(REG_BAND_5G)) && + (WLAN_REG_IS_6GHZ_CHAN_FREQ( + msg->chan_weights.saved_chan_list[i]))) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + + /* + * Dont allow roaming on 2G band if only 5G + 6G band configured + * as supported roam band mask. + */ + if (msg->band_mask == (BIT(REG_BAND_5G) | BIT(REG_BAND_6G)) && + (WLAN_REG_IS_24GHZ_CH_FREQ( + msg->chan_weights.saved_chan_list[i]))) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + + /* + * Dont allow roaming on 5G band if only 2G + 6G band configured + * as supported roam band mask. + */ + if (msg->band_mask == (BIT(REG_BAND_2G) | BIT(REG_BAND_6G)) && + (WLAN_REG_IS_5GHZ_CH_FREQ( + msg->chan_weights.saved_chan_list[i]))) { + msg->chan_weights.weighed_valid_list[i] = + WEIGHT_OF_DISALLOWED_CHANNELS; + continue; + } + } + + wma_debug("RSO_CFG: Dump PDEV PCL weights for vdev[%d]", msg->vdev_id); + policy_mgr_dump_channel_list(msg->chan_weights.saved_num_chan, + msg->chan_weights.saved_chan_list, + msg->chan_weights.weighed_valid_list); + + if (wmi_unified_pdev_set_pcl_cmd(wma_handle->wmi_handle, + &msg->chan_weights)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_send_pdev_set_hw_mode_cmd() - Send WMI_PDEV_SET_HW_MODE_CMDID to FW + * @wma_handle: WMA handle + * @msg: Structure containing the following parameters + * + * - hw_mode_index: The HW_Mode field is a enumerated type that is selected + * from the HW_Mode table, which is returned in the WMI_SERVICE_READY_EVENTID. + * + * Provides notification to the WLAN firmware that host driver is requesting a + * HardWare (HW) Mode change. This command is needed to support iHelium in the + * configurations that include the Dual Band Simultaneous (DBS) feature. + * + * Return: Success if the cmd is sent successfully to the firmware + */ +QDF_STATUS wma_send_pdev_set_hw_mode_cmd(tp_wma_handle wma_handle, + struct policy_mgr_hw_mode *msg) +{ + struct sir_set_hw_mode_resp *param; + struct wma_target_req *timeout_msg; + + if (wma_validate_handle(wma_handle)) { + /* Handle is NULL. Will not be able to send failure + * response as well + */ + return QDF_STATUS_E_NULL_VALUE; + } + + if (!msg) { + wma_err("Set HW mode param is NULL"); + /* Lets try to free the active command list */ + goto fail; + } + + wma_acquire_wakelock(&wma_handle->wmi_cmd_rsp_wake_lock, + WMA_VDEV_HW_MODE_REQUEST_TIMEOUT); + if (wmi_unified_soc_set_hw_mode_cmd(wma_handle->wmi_handle, + msg->hw_mode_index)) { + wma_release_wakelock(&wma_handle->wmi_cmd_rsp_wake_lock); + goto fail; + } + timeout_msg = wma_fill_hold_req(wma_handle, 0, + SIR_HAL_PDEV_SET_HW_MODE, + WMA_PDEV_SET_HW_MODE_RESP, NULL, + WMA_VDEV_HW_MODE_REQUEST_TIMEOUT - 1); + if (!timeout_msg) { + wma_err("Failed to allocate request for SIR_HAL_PDEV_SET_HW_MODE"); + wma_remove_req(wma_handle, 0, WMA_PDEV_SET_HW_MODE_RESP); + } + + return QDF_STATUS_SUCCESS; +fail: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_NULL_VALUE; + + param->status = SET_HW_MODE_STATUS_ECANCELED; + param->cfgd_hw_mode_index = 0; + param->num_vdev_mac_entries = 0; + wma_debug("Sending HW mode fail response to LIM"); + wma_send_msg(wma_handle, SIR_HAL_PDEV_SET_HW_MODE_RESP, + (void *) param, 0); + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_send_pdev_set_dual_mac_config() - Set dual mac config to FW + * @wma_handle: WMA handle + * @msg: Dual MAC config parameters + * + * Configures WLAN firmware with the dual MAC features + * + * Return: QDF_STATUS. 0 on success. + */ +QDF_STATUS wma_send_pdev_set_dual_mac_config(tp_wma_handle wma_handle, + struct policy_mgr_dual_mac_config *msg) +{ + QDF_STATUS status; + struct wma_target_req *req_msg; + struct sir_dual_mac_config_resp *resp; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_NULL_VALUE; + + if (!msg) { + wma_err("Set dual mode config is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + req_msg = wma_fill_hold_req(wma_handle, 0, + SIR_HAL_PDEV_DUAL_MAC_CFG_REQ, + WMA_PDEV_MAC_CFG_RESP, NULL, + WMA_VDEV_DUAL_MAC_CFG_TIMEOUT); + if (!req_msg) { + wma_err("Failed to allocate request for SIR_HAL_PDEV_DUAL_MAC_CFG_REQ"); + return QDF_STATUS_E_FAILURE; + } + + /* + * acquire the wake lock here and release it in response handler function + * In error condition, release the wake lock right away + */ + wma_acquire_wakelock(&wma_handle->wmi_cmd_rsp_wake_lock, + WMA_VDEV_PLCY_MGR_WAKE_LOCK_TIMEOUT); + status = wmi_unified_pdev_set_dual_mac_config_cmd( + wma_handle->wmi_handle, + (struct policy_mgr_dual_mac_config *)msg); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send WMI_PDEV_SET_DUAL_MAC_CONFIG_CMDID: %d", + status); + wma_release_wakelock(&wma_handle->wmi_cmd_rsp_wake_lock); + wma_remove_req(wma_handle, 0, WMA_PDEV_MAC_CFG_RESP); + goto fail; + } + policy_mgr_update_dbs_req_config(wma_handle->psoc, + msg->scan_config, msg->fw_mode_config); + + return QDF_STATUS_SUCCESS; + +fail: + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) + return QDF_STATUS_E_NULL_VALUE; + + resp->status = SET_HW_MODE_STATUS_ECANCELED; + wma_debug("Sending failure response to LIM"); + wma_send_msg(wma_handle, SIR_HAL_PDEV_MAC_CFG_RESP, (void *) resp, 0); + + return QDF_STATUS_E_FAILURE; +} + +/** + * wma_send_pdev_set_antenna_mode() - Set antenna mode to FW + * @wma_handle: WMA handle + * @msg: Antenna mode parameters + * + * Send WMI_PDEV_SET_ANTENNA_MODE_CMDID to FW requesting to + * modify the number of TX/RX chains from host + * + * Return: QDF_STATUS. 0 on success. + */ +QDF_STATUS wma_send_pdev_set_antenna_mode(tp_wma_handle wma_handle, + struct sir_antenna_mode_param *msg) +{ + wmi_pdev_set_antenna_mode_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint32_t len; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct sir_antenna_mode_resp *param; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_NULL_VALUE; + + if (!msg) { + wma_err("Set antenna mode param is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma_handle->wmi_handle, len); + if (!buf) { + status = QDF_STATUS_E_NOMEM; + goto resp; + } + + cmd = (wmi_pdev_set_antenna_mode_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_antenna_mode_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_antenna_mode_cmd_fixed_param)); + + cmd->pdev_id = OL_TXRX_PDEV_ID; + /* Bits 0-15 is num of RX chains 16-31 is num of TX chains */ + cmd->num_txrx_chains = msg->num_rx_chains; + cmd->num_txrx_chains |= (msg->num_tx_chains << 16); + + wma_debug("Num of chains TX: %d RX: %d txrx_chains: 0x%x", + msg->num_tx_chains, + msg->num_rx_chains, cmd->num_txrx_chains); + + if (wmi_unified_cmd_send(wma_handle->wmi_handle, buf, len, + WMI_PDEV_SET_ANTENNA_MODE_CMDID)) { + wmi_buf_free(buf); + status = QDF_STATUS_E_FAILURE; + goto resp; + } + status = QDF_STATUS_SUCCESS; + +resp: + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return QDF_STATUS_E_NOMEM; + + param->status = (status) ? + SET_ANTENNA_MODE_STATUS_ECANCELED : + SET_ANTENNA_MODE_STATUS_OK; + wma_debug("Send antenna mode resp to LIM status: %d", + param->status); + wma_send_msg(wma_handle, SIR_HAL_SOC_ANTENNA_MODE_RESP, + (void *) param, 0); + return status; +} + +/** + * wma_crash_inject() - sends command to FW to simulate crash + * @wma_handle: pointer of WMA context + * @type: subtype of the command + * @delay_time_ms: time in milliseconds for FW to delay the crash + * + * This function will send a command to FW in order to simulate different + * kinds of FW crashes. + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_crash_inject(WMA_HANDLE wma_handle, uint32_t type, + uint32_t delay_time_ms) +{ + struct crash_inject param; + tp_wma_handle wma = (tp_wma_handle)wma_handle; + + param.type = type; + param.delay_time_ms = delay_time_ms; + return wmi_crash_inject(wma->wmi_handle, ¶m); +} + +QDF_STATUS wma_configure_smps_params(uint32_t vdev_id, uint32_t param_id, + uint32_t param_val) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + int smps_cmd_value; + int status = QDF_STATUS_E_INVAL; + + if (!wma) + return status; + + smps_cmd_value = param_id << WMI_SMPS_PARAM_VALUE_S; + smps_cmd_value = smps_cmd_value | param_val; + + status = wma_set_smps_params(wma, vdev_id, smps_cmd_value); + if (status) + wma_err("Failed to set SMPS Param"); + + return status; +} + + +/** + * wma_config_bmiss_bcnt_params() - set bmiss config parameters + * @vdev_id: virtual device for the command + * @first_cnt: bmiss first value + * @final_cnt: bmiss final value + * + * Return: QDF_STATUS_SUCCESS or non-zero on failure + */ +QDF_STATUS wma_config_bmiss_bcnt_params(uint32_t vdev_id, uint32_t first_cnt, + uint32_t final_cnt) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + int status = QDF_STATUS_E_INVAL; + + if (!wma_handle) + return status; + + status = wma_roam_scan_bmiss_cnt(wma_handle, first_cnt, final_cnt, + vdev_id); + + if (status) + wma_err("Failed to set Bmiss Param"); + + return status; +} + +QDF_STATUS wma_get_rx_chainmask(uint8_t pdev_id, uint32_t *chainmask_2g, + uint32_t *chainmask_5g) +{ + struct wlan_psoc_host_mac_phy_caps *mac_phy_cap; + uint8_t total_mac_phy_cnt, idx; + struct target_psoc_info *tgt_hdl; + uint32_t hw_mode_idx = 0, num_hw_modes = 0; + + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return QDF_STATUS_E_INVAL; + } + + total_mac_phy_cnt = target_psoc_get_total_mac_phy_cnt(tgt_hdl); + num_hw_modes = target_psoc_get_num_hw_modes(tgt_hdl); + if (total_mac_phy_cnt <= pdev_id) { + wma_err("mac phy cnt %d, pdev id %d", + total_mac_phy_cnt, pdev_id); + return QDF_STATUS_E_FAILURE; + } + + if ((wma_handle->new_hw_mode_index != WMA_DEFAULT_HW_MODE_INDEX) && + (wma_handle->new_hw_mode_index <= num_hw_modes)) + hw_mode_idx = wma_handle->new_hw_mode_index; + mac_phy_cap = target_psoc_get_mac_phy_cap(tgt_hdl); + if (!mac_phy_cap) { + wma_err("Invalid MAC PHY capabilities handle"); + return QDF_STATUS_E_FAILURE; + } + for (idx = 0; idx < total_mac_phy_cnt; idx++) { + if (mac_phy_cap[idx].hw_mode_id != hw_mode_idx) + continue; + if (mac_phy_cap[idx].supported_bands & WLAN_2G_CAPABILITY) + *chainmask_2g = mac_phy_cap[idx].rx_chain_mask_2G; + if (mac_phy_cap[idx].supported_bands & WLAN_5G_CAPABILITY) + *chainmask_5g = mac_phy_cap[idx].rx_chain_mask_5G; + } + wma_debug("pdev id: %d, hw_mode_idx: %d, rx chainmask 2g:%d, 5g:%d", + pdev_id, hw_mode_idx, *chainmask_2g, *chainmask_5g); + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_ANI_LEVEL_REQUEST +QDF_STATUS wma_send_ani_level_request(tp_wma_handle wma_handle, + uint32_t *freqs, uint8_t num_freqs) +{ + return wmi_unified_ani_level_cmd_send(wma_handle->wmi_handle, freqs, + num_freqs); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_mgmt.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_mgmt.c new file mode 100644 index 0000000000..19c5ab5da1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_mgmt.c @@ -0,0 +1,4251 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_mgmt.c + * + * This file contains STA/SAP and protocol related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" +#include "wlan_dlm_api.h" +#if defined(CONNECTIVITY_PKTLOG) || !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#else +#include "pktlog_ac_fmt.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" +#include "wma_internal.h" +#include "wlan_policy_mgr_api.h" +#include "cdp_txrx_flow_ctrl_legacy.h" +#include +#include +#include +#include +#include +#include +#include "wlan_mgmt_txrx_tgt_api.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_lmac_if_api.h" +#include +#include "wma_he.h" +#include "wma_eht.h" +#include +#include "wma_twt.h" +#include "wlan_p2p_cfg_api.h" +#include "cfg_ucfg_api.h" +#include "cfg_mlme_sta.h" +#include "wlan_mlme_api.h" +#include "wmi_unified_bcn_api.h" +#include +#include +#include <../../core/src/vdev_mgr_ops.h> +#include "wlan_pkt_capture_ucfg_api.h" + +#if defined(CONNECTIVITY_PKTLOG) || !defined(REMOVE_PKT_LOG) +#include +#endif +#include "wlan_cm_roam_api.h" +#include "wlan_cm_api.h" +#include "wlan_mlo_link_force.h" +#include +#include "wlan_nan_api_i.h" + +/* Max debug string size for WMM in bytes */ +#define WMA_WMM_DEBUG_STRING_SIZE 512 + +/** + * wma_send_bcn_buf_ll() - prepare and send beacon buffer to fw for LL + * @wma: wma handle + * @vdev_id: vdev id + * @param_buf: SWBA parameters + * + * Return: none + */ +#ifdef WLAN_WMI_BCN +static void wma_send_bcn_buf_ll(tp_wma_handle wma, + uint8_t vdev_id, + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf) +{ + struct ieee80211_frame *wh; + struct beacon_info *bcn; + wmi_tim_info *tim_info = param_buf->tim_info; + uint8_t *bcn_payload; + QDF_STATUS ret; + struct beacon_tim_ie *tim_ie; + wmi_p2p_noa_info *p2p_noa_info = param_buf->p2p_noa_info; + struct p2p_sub_element_noa noa_ie; + struct wmi_bcn_send_from_host params; + uint8_t i; + + bcn = wma->interfaces[vdev_id].beacon; + if (!bcn || !bcn->buf) { + wma_err("Invalid beacon buffer"); + return; + } + + if (!param_buf->tim_info || !param_buf->p2p_noa_info) { + wma_err("Invalid tim info or p2p noa info"); + return; + } + + if (WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info) > + WMI_P2P_MAX_NOA_DESCRIPTORS) { + wma_err("Too many descriptors %d", + WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info)); + return; + } + + qdf_spin_lock_bh(&bcn->lock); + + bcn_payload = qdf_nbuf_data(bcn->buf); + + tim_ie = (struct beacon_tim_ie *)(&bcn_payload[bcn->tim_ie_offset]); + + if (tim_info->tim_changed) { + if (tim_info->tim_num_ps_pending) + qdf_mem_copy(&tim_ie->tim_bitmap, tim_info->tim_bitmap, + WMA_TIM_SUPPORTED_PVB_LENGTH); + else + qdf_mem_zero(&tim_ie->tim_bitmap, + WMA_TIM_SUPPORTED_PVB_LENGTH); + /* + * Currently we support fixed number of + * peers as limited by HAL_NUM_STA. + * tim offset is always 0 + */ + tim_ie->tim_bitctl = 0; + } + + /* Update DTIM Count */ + if (tim_ie->dtim_count == 0) + tim_ie->dtim_count = tim_ie->dtim_period - 1; + else + tim_ie->dtim_count--; + + /* + * DTIM count needs to be backedup so that + * when umac updates the beacon template + * current dtim count can be updated properly + */ + bcn->dtim_count = tim_ie->dtim_count; + + /* update state for buffered multicast frames on DTIM */ + if (tim_info->tim_mcast && (tim_ie->dtim_count == 0 || + tim_ie->dtim_period == 1)) + tim_ie->tim_bitctl |= 1; + else + tim_ie->tim_bitctl &= ~1; + + /* To avoid sw generated frame sequence the same as H/W generated frame, + * the value lower than min_sw_seq is reserved for HW generated frame + */ + if ((bcn->seq_no & IEEE80211_SEQ_MASK) < MIN_SW_SEQ) + bcn->seq_no = MIN_SW_SEQ; + + wh = (struct ieee80211_frame *)bcn_payload; + *(uint16_t *) &wh->i_seq[0] = htole16(bcn->seq_no + << IEEE80211_SEQ_SEQ_SHIFT); + bcn->seq_no++; + + if (WMI_UNIFIED_NOA_ATTR_IS_MODIFIED(p2p_noa_info)) { + qdf_mem_zero(&noa_ie, sizeof(noa_ie)); + + noa_ie.index = + (uint8_t) WMI_UNIFIED_NOA_ATTR_INDEX_GET(p2p_noa_info); + noa_ie.oppPS = + (uint8_t) WMI_UNIFIED_NOA_ATTR_OPP_PS_GET(p2p_noa_info); + noa_ie.ctwindow = + (uint8_t) WMI_UNIFIED_NOA_ATTR_CTWIN_GET(p2p_noa_info); + noa_ie.num_descriptors = (uint8_t) + WMI_UNIFIED_NOA_ATTR_NUM_DESC_GET(p2p_noa_info); + wma_debug("index %u, oppPs %u, ctwindow %u, num_descriptors = %u", + noa_ie.index, + noa_ie.oppPS, noa_ie.ctwindow, noa_ie.num_descriptors); + for (i = 0; i < noa_ie.num_descriptors; i++) { + noa_ie.noa_descriptors[i].type_count = + (uint8_t) p2p_noa_info->noa_descriptors[i]. + type_count; + noa_ie.noa_descriptors[i].duration = + p2p_noa_info->noa_descriptors[i].duration; + noa_ie.noa_descriptors[i].interval = + p2p_noa_info->noa_descriptors[i].interval; + noa_ie.noa_descriptors[i].start_time = + p2p_noa_info->noa_descriptors[i].start_time; + wma_debug("NoA descriptor[%d] type_count %u, duration %u, interval %u, start_time = %u", + i, + noa_ie.noa_descriptors[i].type_count, + noa_ie.noa_descriptors[i].duration, + noa_ie.noa_descriptors[i].interval, + noa_ie.noa_descriptors[i].start_time); + } + wma_update_noa(bcn, &noa_ie); + + /* Send a msg to LIM to update the NoA IE in probe response + * frames transmitted by the host + */ + wma_update_probe_resp_noa(wma, &noa_ie); + } + + if (bcn->dma_mapped) { + qdf_nbuf_unmap_single(wma->qdf_dev, bcn->buf, QDF_DMA_TO_DEVICE); + bcn->dma_mapped = 0; + } + ret = qdf_nbuf_map_single(wma->qdf_dev, bcn->buf, QDF_DMA_TO_DEVICE); + if (ret != QDF_STATUS_SUCCESS) { + wma_err("failed map beacon buf to DMA region"); + qdf_spin_unlock_bh(&bcn->lock); + return; + } + + bcn->dma_mapped = 1; + params.vdev_id = vdev_id; + params.data_len = bcn->len; + params.frame_ctrl = *((A_UINT16 *) wh->i_fc); + params.frag_ptr = qdf_nbuf_get_frag_paddr(bcn->buf, 0); + params.dtim_flag = 0; + /* notify Firmware of DTM and mcast/bcast traffic */ + if (tim_ie->dtim_count == 0) { + params.dtim_flag |= WMI_BCN_SEND_DTIM_ZERO; + /* deliver mcast/bcast traffic in next DTIM beacon */ + if (tim_ie->tim_bitctl & 0x01) + params.dtim_flag |= WMI_BCN_SEND_DTIM_BITCTL_SET; + } + + wmi_unified_bcn_buf_ll_cmd(wma->wmi_handle, + ¶ms); + + qdf_spin_unlock_bh(&bcn->lock); +} +#else +static inline void +wma_send_bcn_buf_ll(tp_wma_handle wma, + uint8_t vdev_id, + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf) +{ +} +#endif +/** + * wma_beacon_swba_handler() - swba event handler + * @handle: wma handle + * @event: event data + * @len: data length + * + * SWBA event is alert event to Host requesting host to Queue a beacon + * for transmission use only in host beacon mode + * + * Return: 0 for success or error code + */ +#ifdef WLAN_WMI_BCN +int wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_HOST_SWBA_EVENTID_param_tlvs *param_buf; + wmi_host_swba_event_fixed_param *swba_event; + uint32_t vdev_map; + uint8_t vdev_id = 0; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + param_buf = (WMI_HOST_SWBA_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid swba event buffer"); + return -EINVAL; + } + swba_event = param_buf->fixed_param; + vdev_map = swba_event->vdev_map; + + wma_debug("vdev_map = %d", vdev_map); + for (; vdev_map && vdev_id < wma->max_bssid; + vdev_id++, vdev_map >>= 1) { + if (!(vdev_map & 0x1)) + continue; + if (!cdp_cfg_is_high_latency(soc, + (struct cdp_cfg *)cds_get_context(QDF_MODULE_ID_CFG))) + wma_send_bcn_buf_ll(wma, vdev_id, param_buf); + break; + } + return 0; +} +#else +static inline int +wma_beacon_swba_handler(void *handle, uint8_t *event, uint32_t len) +{ + return 0; +} +#endif + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +void wma_sta_kickout_event(uint32_t kickout_reason, uint8_t vdev_id, + uint8_t *macaddr) +{ + WLAN_HOST_DIAG_EVENT_DEF(sta_kickout, struct host_event_wlan_kickout); + qdf_mem_zero(&sta_kickout, sizeof(sta_kickout)); + sta_kickout.reasoncode = kickout_reason; + sta_kickout.vdev_id = vdev_id; + if (macaddr) + qdf_mem_copy(sta_kickout.peer_mac, macaddr, + QDF_MAC_ADDR_SIZE); + WLAN_HOST_DIAG_EVENT_REPORT(&sta_kickout, EVENT_WLAN_STA_KICKOUT); +} +#endif + +int wma_peer_sta_kickout_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *param_buf = NULL; + wmi_peer_sta_kickout_event_fixed_param *kickout_event = NULL; + uint8_t vdev_id, macaddr[QDF_MAC_ADDR_SIZE]; + tpDeleteStaContext del_sta_ctx; + uint8_t *addr, *bssid; + struct wlan_objmgr_vdev *vdev; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + param_buf = (WMI_PEER_STA_KICKOUT_EVENTID_param_tlvs *) event; + kickout_event = param_buf->fixed_param; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&kickout_event->peer_macaddr, macaddr); + if (cdp_peer_get_vdevid(soc, macaddr, &vdev_id) != + QDF_STATUS_SUCCESS) { + wma_err("Not able to find BSSID for peer ["QDF_MAC_ADDR_FMT"]", + QDF_MAC_ADDR_REF(macaddr)); + return -EINVAL; + } + + if (!wma_is_vdev_valid(vdev_id)) + return -EINVAL; + + vdev = wma->interfaces[vdev_id].vdev; + if (!vdev) { + wma_err("Not able to find vdev for VDEV_%d", vdev_id); + return -EINVAL; + } + addr = wlan_vdev_mlme_get_macaddr(vdev); + + wma_nofl_info("STA kickout for "QDF_MAC_ADDR_FMT", on mac "QDF_MAC_ADDR_FMT", vdev %d, reason:%d", + QDF_MAC_ADDR_REF(macaddr), QDF_MAC_ADDR_REF(addr), + vdev_id, kickout_event->reason); + + if (wma_is_roam_in_progress(vdev_id)) { + wma_err("vdev_id %d: Ignore STA kick out since roaming is in progress", + vdev_id); + return -EINVAL; + } + bssid = wma_get_vdev_bssid(vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", vdev_id); + return -ENOMEM; + } + + switch (kickout_event->reason) { + case WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT: + goto exit_handler; +#ifdef FEATURE_WLAN_TDLS + case WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT: + del_sta_ctx = (tpDeleteStaContext) + qdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + wma_err("mem alloc failed for struct del_sta_context for TDLS peer: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(macaddr)); + return -ENOMEM; + } + + del_sta_ctx->is_tdls = true; + del_sta_ctx->vdev_id = vdev_id; + qdf_mem_copy(del_sta_ctx->addr2, macaddr, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(del_sta_ctx->bssId, bssid, + QDF_MAC_ADDR_SIZE); + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, + (void *)del_sta_ctx, 0); + goto exit_handler; +#endif /* FEATURE_WLAN_TDLS */ + + case WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED: + /* + * Default legacy value used by original firmware implementation + */ + if (wma->interfaces[vdev_id].type == WMI_VDEV_TYPE_STA && + (wma->interfaces[vdev_id].sub_type == 0 || + wma->interfaces[vdev_id].sub_type == + WMI_UNIFIED_VDEV_SUBTYPE_P2P_CLIENT) && + !qdf_mem_cmp(bssid, + macaddr, QDF_MAC_ADDR_SIZE)) { + wma_sta_kickout_event( + HOST_STA_KICKOUT_REASON_UNSPECIFIED, vdev_id, macaddr); + /* + * KICKOUT event is for current station-AP connection. + * Treat it like final beacon miss. Station may not have + * missed beacons but not able to transmit frames to AP + * for a long time. Must disconnect to get out of + * this sticky situation. + * In future implementation, roaming module will also + * handle this event and perform a scan. + */ + wma_warn("WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED event for STA"); + wma_beacon_miss_handler(wma, vdev_id, + kickout_event->rssi); + goto exit_handler; + } + break; + + case WMI_PEER_STA_KICKOUT_REASON_XRETRY: + case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY: + /* + * Handle SA query kickout is same as inactivity kickout. + * This could be for STA or SAP role + */ + case WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT: + default: + break; + } + + /* + * default action is to send delete station context indication to LIM + */ + del_sta_ctx = + (tDeleteStaContext *) qdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) { + wma_err("QDF MEM Alloc Failed for struct del_sta_context"); + return -ENOMEM; + } + + del_sta_ctx->is_tdls = false; + del_sta_ctx->vdev_id = vdev_id; + qdf_mem_copy(del_sta_ctx->addr2, macaddr, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(del_sta_ctx->bssId, addr, QDF_MAC_ADDR_SIZE); + if (kickout_event->reason == + WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT) + del_sta_ctx->reasonCode = + HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT; + else if (kickout_event->reason == WMI_PEER_STA_KICKOUT_REASON_XRETRY) + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_XRETRY; + else + del_sta_ctx->reasonCode = HAL_DEL_STA_REASON_CODE_KEEP_ALIVE; + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_hw_db2dbm_support)) + del_sta_ctx->rssi = kickout_event->rssi; + else + del_sta_ctx->rssi = kickout_event->rssi + + WMA_TGT_NOISE_FLOOR_DBM; + wma_sta_kickout_event(del_sta_ctx->reasonCode, vdev_id, macaddr); + wma_send_msg(wma, SIR_LIM_DELETE_STA_CONTEXT_IND, (void *)del_sta_ctx, + 0); + wma_lost_link_info_handler(wma, vdev_id, del_sta_ctx->rssi); + +exit_handler: + return 0; +} + +int wma_unified_bcntx_status_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *param_buf; + wmi_offload_bcn_tx_status_event_fixed_param *resp_event; + tSirFirstBeaconTxCompleteInd *beacon_tx_complete_ind; + + param_buf = + (WMI_OFFLOAD_BCN_TX_STATUS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + wma_err("Invalid bcn tx response event buffer"); + return -EINVAL; + } + + resp_event = param_buf->fixed_param; + + if (resp_event->vdev_id >= wma->max_bssid) { + wma_err("received invalid vdev_id %d", resp_event->vdev_id); + return -EINVAL; + } + + /* Check for valid handle to ensure session is not + * deleted in any race + */ + if (!wma->interfaces[resp_event->vdev_id].vdev) { + wma_err("vdev is NULL for vdev_%d", resp_event->vdev_id); + return -EINVAL; + } + + /* Beacon Tx Indication supports only AP mode. Ignore in other modes */ + if (wma_is_vdev_in_ap_mode(wma, resp_event->vdev_id) == false) { + wma_debug("Beacon Tx Indication does not support type %d and sub_type %d", + wma->interfaces[resp_event->vdev_id].type, + wma->interfaces[resp_event->vdev_id].sub_type); + return 0; + } + + beacon_tx_complete_ind = (tSirFirstBeaconTxCompleteInd *) + qdf_mem_malloc(sizeof(tSirFirstBeaconTxCompleteInd)); + if (!beacon_tx_complete_ind) { + wma_err("Failed to alloc beacon_tx_complete_ind"); + return -ENOMEM; + } + + beacon_tx_complete_ind->messageType = WMA_DFS_BEACON_TX_SUCCESS_IND; + beacon_tx_complete_ind->length = sizeof(tSirFirstBeaconTxCompleteInd); + beacon_tx_complete_ind->bss_idx = resp_event->vdev_id; + + wma_send_msg(wma, WMA_DFS_BEACON_TX_SUCCESS_IND, + (void *)beacon_tx_complete_ind, 0); + return 0; +} + +/** + * wma_get_go_probe_timeout() - get P2P GO probe timeout + * @mac: UMAC handler + * @max_inactive_time: return max inactive time + * @max_unresponsive_time: return max unresponsive time + * + * Return: none + */ +#ifdef CONVERGED_P2P_ENABLE +static inline void +wma_get_go_probe_timeout(struct mac_context *mac, + uint32_t *max_inactive_time, + uint32_t *max_unresponsive_time) +{ + uint32_t keep_alive; + QDF_STATUS status; + + status = cfg_p2p_get_go_link_monitor_period(mac->psoc, + max_inactive_time); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to go monitor period"); + *max_inactive_time = WMA_LINK_MONITOR_DEFAULT_TIME_SECS; + } + status = cfg_p2p_get_go_keepalive_period(mac->psoc, + &keep_alive); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to read go keep alive"); + keep_alive = WMA_KEEP_ALIVE_DEFAULT_TIME_SECS; + } + + *max_unresponsive_time = *max_inactive_time + keep_alive; +} +#else +static inline void +wma_get_go_probe_timeout(struct mac_context *mac, + uint32_t *max_inactive_time, + uint32_t *max_unresponsive_time) +{ +} +#endif + +/** + * wma_get_link_probe_timeout() - get link timeout based on sub type + * @mac: UMAC handler + * @sub_type: vdev syb type + * @max_inactive_time: return max inactive time + * @max_unresponsive_time: return max unresponsive time + * + * Return: none + */ +static inline void +wma_get_link_probe_timeout(struct mac_context *mac, + uint32_t sub_type, + uint32_t *max_inactive_time, + uint32_t *max_unresponsive_time) +{ + if (sub_type == WMI_UNIFIED_VDEV_SUBTYPE_P2P_GO) { + wma_get_go_probe_timeout(mac, max_inactive_time, + max_unresponsive_time); + } else { + *max_inactive_time = + mac->mlme_cfg->timeouts.ap_link_monitor_timeout; + *max_unresponsive_time = *max_inactive_time + + mac->mlme_cfg->timeouts.ap_keep_alive_timeout; + } +} + +/** + * wma_verify_rate_code() - verify if rate code is valid. + * @rate_code: rate code + * @band: band information + * + * Return: verify result + */ +static bool wma_verify_rate_code(u_int32_t rate_code, enum cds_band_type band) +{ + uint8_t preamble, nss, rate; + bool valid = true; + + preamble = (rate_code & 0xc0) >> 6; + nss = (rate_code & 0x30) >> 4; + rate = rate_code & 0xf; + + switch (preamble) { + case WMI_RATE_PREAMBLE_CCK: + if (nss != 0 || rate > 3 || band == CDS_BAND_5GHZ) + valid = false; + break; + case WMI_RATE_PREAMBLE_OFDM: + if (nss != 0 || rate > 7) + valid = false; + break; + case WMI_RATE_PREAMBLE_HT: + if (nss != 0 || rate > 7) + valid = false; + break; + case WMI_RATE_PREAMBLE_VHT: + if (nss != 0 || rate > 9) + valid = false; + break; + default: + break; + } + return valid; +} + +#define TX_MGMT_RATE_2G_ENABLE_OFFSET 30 +#define TX_MGMT_RATE_5G_ENABLE_OFFSET 31 +#define TX_MGMT_RATE_2G_OFFSET 0 +#define TX_MGMT_RATE_5G_OFFSET 12 + +#define MAX_VDEV_MGMT_RATE_PARAMS 2 +/* params being sent: + * wmi_vdev_param_mgmt_tx_rate + * wmi_vdev_param_per_band_mgmt_tx_rate + */ + +/** + * wma_set_mgmt_rate() - set vdev mgmt rate. + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: None + */ +void wma_set_vdev_mgmt_rate(tp_wma_handle wma, uint8_t vdev_id) +{ + uint32_t cfg_val; + uint32_t per_band_mgmt_tx_rate = 0; + enum cds_band_type band = 0; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct dev_set_param setparam[MAX_VDEV_MGMT_RATE_PARAMS] = {}; + uint8_t index = 0; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + if (!mac) { + wma_err("Failed to get mac"); + return; + } + + cfg_val = mac->mlme_cfg->sap_cfg.rate_tx_mgmt; + band = CDS_BAND_ALL; + if ((cfg_val == MLME_CFG_TX_MGMT_RATE_DEF) || + !wma_verify_rate_code(cfg_val, band)) { + wma_nofl_debug("default WNI_CFG_RATE_FOR_TX_MGMT, ignore"); + } else { + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_mgmt_tx_rate, + cfg_val, index++, + MAX_VDEV_MGMT_RATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed at wmi_vdev_param_mgmt_tx_rate"); + goto error; + } + } + + cfg_val = mac->mlme_cfg->sap_cfg.rate_tx_mgmt_2g; + band = CDS_BAND_2GHZ; + if ((cfg_val == MLME_CFG_TX_MGMT_2G_RATE_DEF) || + !wma_verify_rate_code(cfg_val, band)) { + wma_nofl_debug("use default 2G MGMT rate."); + per_band_mgmt_tx_rate &= + ~(1 << TX_MGMT_RATE_2G_ENABLE_OFFSET); + } else { + per_band_mgmt_tx_rate |= + (1 << TX_MGMT_RATE_2G_ENABLE_OFFSET); + per_band_mgmt_tx_rate |= + ((cfg_val & 0x7FF) << TX_MGMT_RATE_2G_OFFSET); + } + + cfg_val = mac->mlme_cfg->sap_cfg.rate_tx_mgmt; + band = CDS_BAND_5GHZ; + if ((cfg_val == MLME_CFG_TX_MGMT_5G_RATE_DEF) || + !wma_verify_rate_code(cfg_val, band)) { + wma_nofl_debug("use default 5G MGMT rate."); + per_band_mgmt_tx_rate &= + ~(1 << TX_MGMT_RATE_5G_ENABLE_OFFSET); + } else { + per_band_mgmt_tx_rate |= + (1 << TX_MGMT_RATE_5G_ENABLE_OFFSET); + per_band_mgmt_tx_rate |= + ((cfg_val & 0x7FF) << TX_MGMT_RATE_5G_OFFSET); + } + + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_per_band_mgmt_tx_rate, + per_band_mgmt_tx_rate, index++, + MAX_VDEV_MGMT_RATE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed at wmi_vdev_param_per_band_mgmt_tx_rate"); + goto error; + } + + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + wma_debug("failed to send MGMT_TX_RATE vdev set params stat:%d", + status); +error: + return; +} + +#define MAX_VDEV_SAP_KEEPALIVE_PARAMS 3 +/* params being sent: + * wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs + * wmi_vdev_param_ap_keepalive_max_idle_inactive_time_secs + * wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs + */ + +/** + * wma_set_sap_keepalive() - set SAP keep alive parameters to fw + * @wma: wma handle + * @vdev_id: vdev id + * + * Return: none + */ +void wma_set_sap_keepalive(tp_wma_handle wma, uint8_t vdev_id) +{ + uint32_t min_inactive_time, max_inactive_time, max_unresponsive_time; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + struct dev_set_param setparam[MAX_VDEV_SAP_KEEPALIVE_PARAMS] = {}; + uint8_t index = 0; + + if (!mac) { + wma_err("Failed to get mac"); + return; + } + + wma_get_link_probe_timeout(mac, wma->interfaces[vdev_id].sub_type, + &max_inactive_time, &max_unresponsive_time); + + min_inactive_time = max_inactive_time / 2; + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs, + min_inactive_time, index++, + MAX_VDEV_SAP_KEEPALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_min_idle_inactive_time_secs"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_max_idle_inactive_time_secs, + max_inactive_time, index++, + MAX_VDEV_SAP_KEEPALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_max_idle_inactive_time_secs"); + goto error; + } + status = mlme_check_index_setparam( + setparam, + wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs, + max_unresponsive_time, index++, + MAX_VDEV_SAP_KEEPALIVE_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_ap_keepalive_max_unresponsive_time_secs"); + goto error; + } + + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to Set AP MIN/MAX IDLE INACTIVE TIME, MAX UNRESPONSIVE TIME:%d", status); + else + wma_debug("vdev_id:%d min_inactive_time: %u max_inactive_time: %u max_unresponsive_time: %u", + vdev_id, min_inactive_time, max_inactive_time, + max_unresponsive_time); +error: + return; +} + +/** + * wma_set_sta_sa_query_param() - set sta sa query parameters + * @wma: wma handle + * @vdev_id: vdev id + + * This function sets sta query related parameters in fw. + * + * Return: none + */ + +void wma_set_sta_sa_query_param(tp_wma_handle wma, + uint8_t vdev_id) +{ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + uint8_t max_retries; + uint16_t retry_interval; + + if (!mac) { + wma_err("mac context is NULL"); + return; + } + + max_retries = mac->mlme_cfg->gen.pmf_sa_query_max_retries; + retry_interval = mac->mlme_cfg->gen.pmf_sa_query_retry_interval; + + wmi_unified_set_sta_sa_query_param_cmd(wma->wmi_handle, + vdev_id, + max_retries, + retry_interval); +} + +/** + * wma_set_sta_keep_alive() - set sta keep alive parameters + * @wma: wma handle + * @vdev_id: vdev id + * @method: method for keep alive + * @timeperiod: time period + * @hostv4addr: host ipv4 address + * @destv4addr: dst ipv4 address + * @destmac: destination mac + * + * This function sets keep alive related parameters in fw. + * + * Return: none + */ +void wma_set_sta_keep_alive(tp_wma_handle wma, uint8_t vdev_id, + uint32_t method, uint32_t timeperiod, + uint8_t *hostv4addr, uint8_t *destv4addr, + uint8_t *destmac) +{ + struct sta_keep_alive_params params = { 0 }; + struct wma_txrx_node *intr; + + if (wma_validate_handle(wma)) + return; + + intr = &wma->interfaces[vdev_id]; + if (timeperiod > cfg_max(CFG_INFRA_STA_KEEP_ALIVE_PERIOD)) { + wmi_err("Invalid period %d Max limit %d", timeperiod, + cfg_max(CFG_INFRA_STA_KEEP_ALIVE_PERIOD)); + return; + } + + params.vdev_id = vdev_id; + params.method = method; + params.timeperiod = timeperiod; + if (intr) { + if (intr->bss_max_idle_period) { + if (intr->bss_max_idle_period < timeperiod) + params.timeperiod = intr->bss_max_idle_period; + + if (method == WMI_KEEP_ALIVE_NULL_PKT) + params.method = WMI_KEEP_ALIVE_MGMT_FRAME; + } + + wlan_mlme_set_keepalive_period(intr->vdev, params.timeperiod); + } + + if (hostv4addr) + qdf_mem_copy(params.hostv4addr, hostv4addr, QDF_IPV4_ADDR_SIZE); + if (destv4addr) + qdf_mem_copy(params.destv4addr, destv4addr, QDF_IPV4_ADDR_SIZE); + if (destmac) + qdf_mem_copy(params.destmac, destmac, QDF_MAC_ADDR_SIZE); + + wmi_unified_set_sta_keep_alive_cmd(wma->wmi_handle, ¶ms); +} + +/* + * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": + * 0 for no restriction + * 1 for 1/4 us - Our lower layer calculations limit our precision to 1 msec + * 2 for 1/2 us - Our lower layer calculations limit our precision to 1 msec + * 3 for 1 us + * 4 for 2 us + * 5 for 4 us + * 6 for 8 us + * 7 for 16 us + */ +static const uint8_t wma_mpdu_spacing[] = { 0, 1, 1, 1, 2, 4, 8, 16 }; + +/** + * wma_parse_mpdudensity() - give mpdu spacing from mpdu density + * @mpdudensity: mpdu density + * + * Return: mpdu spacing or 0 for error + */ +static inline uint8_t wma_parse_mpdudensity(uint8_t mpdudensity) +{ + if (mpdudensity < sizeof(wma_mpdu_spacing)) + return wma_mpdu_spacing[mpdudensity]; + else + return 0; +} + +#define CFG_CTRL_MASK 0xFF00 +#define CFG_DATA_MASK 0x00FF + +/** + * wma_mask_tx_ht_rate() - mask tx ht rate based on config + * @wma: wma handle + * @mcs_set mcs set buffer + * + * Return: None + */ +static void wma_mask_tx_ht_rate(tp_wma_handle wma, uint8_t *mcs_set) +{ + uint32_t i, j; + uint16_t mcs_limit; + uint8_t *rate_pos = mcs_set; + struct mac_context *mac = wma->mac_context; + + /* + * Get MCS limit from ini configure, and map it to rate parameters + * This will limit HT rate upper bound. CFG_CTRL_MASK is used to + * check whether ini config is enabled and CFG_DATA_MASK to get the + * MCS value. + */ + mcs_limit = mac->mlme_cfg->rates.max_htmcs_txdata; + + if (mcs_limit & CFG_CTRL_MASK) { + wma_debug("set mcs_limit %x", mcs_limit); + + mcs_limit &= CFG_DATA_MASK; + for (i = 0, j = 0; i < MAX_SUPPORTED_RATES;) { + if (j < mcs_limit / 8) { + rate_pos[j] = 0xff; + j++; + i += 8; + } else if (j < mcs_limit / 8 + 1) { + if (i <= mcs_limit) + rate_pos[i / 8] |= 1 << (i % 8); + else + rate_pos[i / 8] &= ~(1 << (i % 8)); + i++; + + if (i >= (j + 1) * 8) + j++; + } else { + rate_pos[j++] = 0; + i += 8; + } + } + } +} + +#if SUPPORT_11AX +/** + * wma_fw_to_host_phymode_11ax() - convert fw to host phymode for 11ax phymodes + * @phymode: phymode to convert + * + * Return: one of the 11ax values defined in enum wlan_phymode; + * or WLAN_PHYMODE_AUTO if the input is not an 11ax phymode + */ +static enum wlan_phymode +wma_fw_to_host_phymode_11ax(WMI_HOST_WLAN_PHY_MODE phymode) +{ + switch (phymode) { + default: + return WLAN_PHYMODE_AUTO; + case WMI_HOST_MODE_11AX_HE20: + return WLAN_PHYMODE_11AXA_HE20; + case WMI_HOST_MODE_11AX_HE40: + return WLAN_PHYMODE_11AXA_HE40; + case WMI_HOST_MODE_11AX_HE80: + return WLAN_PHYMODE_11AXA_HE80; + case WMI_HOST_MODE_11AX_HE80_80: + return WLAN_PHYMODE_11AXA_HE80_80; + case WMI_HOST_MODE_11AX_HE160: + return WLAN_PHYMODE_11AXA_HE160; + case WMI_HOST_MODE_11AX_HE20_2G: + return WLAN_PHYMODE_11AXG_HE20; + case WMI_HOST_MODE_11AX_HE40_2G: + return WLAN_PHYMODE_11AXG_HE40; + case WMI_HOST_MODE_11AX_HE80_2G: + return WLAN_PHYMODE_11AXG_HE80; + } + return WLAN_PHYMODE_AUTO; +} +#else +static enum wlan_phymode +wma_fw_to_host_phymode_11ax(WMI_HOST_WLAN_PHY_MODE phymode) +{ + return WLAN_PHYMODE_AUTO; +} +#endif + +#ifdef WLAN_FEATURE_11BE +/** + * wma_fw_to_host_phymode_11be() - convert fw to host phymode for 11be phymodes + * @phymode: phymode to convert + * + * Return: one of the 11be values defined in enum wlan_phymode; + * or WLAN_PHYMODE_AUTO if the input is not an 11be phymode + */ +static enum wlan_phymode +wma_fw_to_host_phymode_11be(WMI_HOST_WLAN_PHY_MODE phymode) +{ + switch (phymode) { + default: + return WLAN_PHYMODE_AUTO; + case WMI_HOST_MODE_11BE_EHT20: + return WLAN_PHYMODE_11BEA_EHT20; + case WMI_HOST_MODE_11BE_EHT40: + return WLAN_PHYMODE_11BEA_EHT40; + case WMI_HOST_MODE_11BE_EHT80: + return WLAN_PHYMODE_11BEA_EHT80; + case WMI_HOST_MODE_11BE_EHT160: + return WLAN_PHYMODE_11BEA_EHT160; + case WMI_HOST_MODE_11BE_EHT320: + return WLAN_PHYMODE_11BEA_EHT320; + case WMI_HOST_MODE_11BE_EHT20_2G: + return WLAN_PHYMODE_11BEG_EHT20; + case WMI_HOST_MODE_11BE_EHT40_2G: + return WLAN_PHYMODE_11BEG_EHT40; + } + return WLAN_PHYMODE_AUTO; +} + +static inline bool wma_is_phymode_eht(enum wlan_phymode phymode) +{ + return IS_WLAN_PHYMODE_EHT(phymode); +} +#else +static enum wlan_phymode +wma_fw_to_host_phymode_11be(WMI_HOST_WLAN_PHY_MODE phymode) +{ + return WLAN_PHYMODE_AUTO; +} + +static inline bool wma_is_phymode_eht(enum wlan_phymode phymode) +{ + return false; +} +#endif + +#ifdef CONFIG_160MHZ_SUPPORT +/** + * wma_fw_to_host_phymode_160() - convert fw to host phymode for 160 mhz + * phymodes + * @phymode: phymode to convert + * + * Return: one of the 160 mhz values defined in enum wlan_phymode; + * or WLAN_PHYMODE_AUTO if the input is not a 160 mhz phymode + */ +static enum wlan_phymode +wma_fw_to_host_phymode_160(WMI_HOST_WLAN_PHY_MODE phymode) +{ + switch (phymode) { + default: + return WLAN_PHYMODE_AUTO; + case WMI_HOST_MODE_11AC_VHT80_80: + return WLAN_PHYMODE_11AC_VHT80_80; + case WMI_HOST_MODE_11AC_VHT160: + return WLAN_PHYMODE_11AC_VHT160; + } +} +#else +static enum wlan_phymode +wma_fw_to_host_phymode_160(WMI_HOST_WLAN_PHY_MODE phymode) +{ + return WLAN_PHYMODE_AUTO; +} +#endif + +enum wlan_phymode wma_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode) +{ + enum wlan_phymode host_phymode; + switch (phymode) { + default: + host_phymode = wma_fw_to_host_phymode_160(phymode); + if (host_phymode != WLAN_PHYMODE_AUTO) + return host_phymode; + host_phymode = wma_fw_to_host_phymode_11ax(phymode); + if (host_phymode != WLAN_PHYMODE_AUTO) + return host_phymode; + return wma_fw_to_host_phymode_11be(phymode); + case WMI_HOST_MODE_11A: + return WLAN_PHYMODE_11A; + case WMI_HOST_MODE_11G: + return WLAN_PHYMODE_11G; + case WMI_HOST_MODE_11B: + return WLAN_PHYMODE_11B; + case WMI_HOST_MODE_11GONLY: + return WLAN_PHYMODE_11G_ONLY; + case WMI_HOST_MODE_11NA_HT20: + return WLAN_PHYMODE_11NA_HT20; + case WMI_HOST_MODE_11NG_HT20: + return WLAN_PHYMODE_11NG_HT20; + case WMI_HOST_MODE_11NA_HT40: + return WLAN_PHYMODE_11NA_HT40; + case WMI_HOST_MODE_11NG_HT40: + return WLAN_PHYMODE_11NG_HT40; + case WMI_HOST_MODE_11AC_VHT20: + return WLAN_PHYMODE_11AC_VHT20; + case WMI_HOST_MODE_11AC_VHT40: + return WLAN_PHYMODE_11AC_VHT40; + case WMI_HOST_MODE_11AC_VHT80: + return WLAN_PHYMODE_11AC_VHT80; + case WMI_HOST_MODE_11AC_VHT20_2G: + return WLAN_PHYMODE_11AC_VHT20_2G; + case WMI_HOST_MODE_11AC_VHT40_2G: + return WLAN_PHYMODE_11AC_VHT40_2G; + case WMI_HOST_MODE_11AC_VHT80_2G: + return WLAN_PHYMODE_11AC_VHT80_2G; + } +} + +#ifdef WLAN_FEATURE_11BE +static void wma_populate_peer_puncture(struct peer_assoc_params *peer, + struct wlan_channel *des_chan) +{ + peer->puncture_bitmap = des_chan->puncture_bitmap; + wma_debug("Peer EHT puncture bitmap %d", peer->puncture_bitmap); +} + +static void wma_populate_peer_mlo_cap(struct peer_assoc_params *peer, + tpAddStaParams params) +{ + struct peer_assoc_ml_partner_links *ml_links; + struct peer_assoc_mlo_params *mlo_params; + struct peer_ml_info *ml_info; + uint8_t i; + + ml_info = ¶ms->ml_info; + mlo_params = &peer->mlo_params; + ml_links = &peer->ml_links; + + /* Assoc link info */ + mlo_params->vdev_id = ml_info->vdev_id; + mlo_params->ieee_link_id = ml_info->link_id; + qdf_mem_copy(&mlo_params->chan, &ml_info->channel_info, + sizeof(struct wlan_channel)); + qdf_mem_copy(&mlo_params->bssid, &ml_info->link_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&mlo_params->mac_addr, &ml_info->self_mac_addr, + QDF_MAC_ADDR_SIZE); + + mlo_params->rec_max_simultaneous_links = + ml_info->rec_max_simultaneous_links; + + /* Fill partner link info */ + ml_links->num_links = ml_info->num_links; + for (i = 0; i < ml_links->num_links; i++) { + ml_links->partner_info[i].vdev_id = + ml_info->partner_info[i].vdev_id; + ml_links->partner_info[i].link_id = + ml_info->partner_info[i].link_id; + qdf_mem_copy(&ml_links->partner_info[i].chan, + &ml_info->partner_info[i].channel_info, + sizeof(struct wlan_channel)); + qdf_mem_copy(&ml_links->partner_info[i].bssid, + &ml_info->partner_info[i].link_addr, + QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&ml_links->partner_info[i].mac_addr, + &ml_info->partner_info[i].self_mac_addr, + QDF_MAC_ADDR_SIZE); + } +} +#else +static void wma_populate_peer_puncture(struct peer_assoc_params *peer, + struct wlan_channel *des_chan) +{ +} + +static void wma_populate_peer_mlo_cap(struct peer_assoc_params *peer, + tpAddStaParams params) +{ +} +#endif + +void wma_objmgr_set_peer_mlme_nss(tp_wma_handle wma, uint8_t *mac_addr, + uint8_t nss) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_psoc *psoc = wma->psoc; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma->pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_LEGACY_WMA_ID); + if (!peer) + return; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + return; + } + + peer_priv->nss = nss; + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +uint8_t wma_objmgr_get_peer_mlme_nss(tp_wma_handle wma, uint8_t *mac_addr) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_psoc *psoc = wma->psoc; + uint8_t nss; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma->pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_LEGACY_WMA_ID); + if (!peer) + return 0; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + return 0; + } + + nss = peer_priv->nss; + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + return nss; +} + +void wma_objmgr_set_peer_mlme_phymode(tp_wma_handle wma, uint8_t *mac_addr, + enum wlan_phymode phymode) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc = wma->psoc; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma->pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_LEGACY_WMA_ID); + if (!peer) + return; + + wlan_peer_obj_lock(peer); + wlan_peer_set_phymode(peer, phymode); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +/** + * wma_objmgr_set_peer_mlme_type() - set peer type to peer object + * @wma: wma handle + * @mac_addr: mac addr of peer + * @peer_type: peer type value to set + * + * Return: None + */ +static void wma_objmgr_set_peer_mlme_type(tp_wma_handle wma, + uint8_t *mac_addr, + enum wlan_peer_type peer_type) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc = wma->psoc; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma->pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, mac_addr, + WLAN_LEGACY_WMA_ID); + if (!peer) + return; + + wlan_peer_obj_lock(peer); + wlan_peer_set_peer_type(peer, peer_type); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +#ifdef WLAN_FEATURE_11BE_MLO + +#define MIN_TIMEOUT_VAL 0 +#define MAX_TIMEOUT_VAL 11 + +#define TIMEOUT_TO_US 6 + +/* + * wma_convert_trans_timeout_us() - API to convert + * emlsr transition timeout to microseconds. Refer Table 9-401h + * of IEEE802.11be specification + * @timeout: EMLSR transition timeout + * + * Return: Timeout value in microseconds + */ +static inline uint32_t +wma_convert_trans_timeout_us(uint16_t timeout) +{ + uint32_t us = 0; + + if (timeout > MIN_TIMEOUT_VAL && timeout < MAX_TIMEOUT_VAL) { + /* timeout = 1 is for 128us*/ + us = (1 << (timeout + TIMEOUT_TO_US)); + } + + return us; +} + +/** + * wma_set_mlo_capability() - set MLO caps to the peer assoc request + * @wma: wma handle + * @vdev: vdev object + * @params: Add sta params + * @req: peer assoc request parameters + * + * Return: None + */ +static void wma_set_mlo_capability(tp_wma_handle wma, + struct wlan_objmgr_vdev *vdev, + tpAddStaParams params, + struct peer_assoc_params *req) +{ + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc = wma->psoc; + uint16_t link_id_bitmap; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma->pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, req->peer_mac, + WLAN_LEGACY_WMA_ID); + + if (!peer) { + wma_err("peer not valid"); + return; + } + + if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)peer->mldaddr)) { + req->mlo_params.mlo_enabled = true; + req->mlo_params.mlo_assoc_link = + wlan_peer_mlme_is_assoc_peer(peer); + WLAN_ADDR_COPY(req->mlo_params.mld_mac, peer->mldaddr); + if (policy_mgr_ml_link_vdev_need_to_be_disabled(psoc, vdev, + true) || + policy_mgr_is_emlsr_sta_concurrency_present(psoc)) { + req->mlo_params.mlo_force_link_inactive = 1; + link_id_bitmap = 1 << params->link_id; + ml_nlink_set_curr_force_inactive_state( + psoc, vdev, link_id_bitmap, LINK_ADD); + ml_nlink_init_concurrency_link_request(psoc, vdev); + } + wma_debug("assoc_link %d" QDF_MAC_ADDR_FMT ", force inactive %d link id %d", + req->mlo_params.mlo_assoc_link, + QDF_MAC_ADDR_REF(peer->mldaddr), + req->mlo_params.mlo_force_link_inactive, + params->link_id); + + req->mlo_params.emlsr_support = params->emlsr_support; + req->mlo_params.ieee_link_id = params->link_id; + if (req->mlo_params.emlsr_support) { + req->mlo_params.trans_timeout_us = + wma_convert_trans_timeout_us(params->emlsr_trans_timeout); + } + req->mlo_params.msd_cap_support = params->msd_caps_present; + req->mlo_params.medium_sync_duration = + params->msd_caps.med_sync_duration; + req->mlo_params.medium_sync_ofdm_ed_thresh = + params->msd_caps.med_sync_ofdm_ed_thresh; + req->mlo_params.medium_sync_max_txop_num = + params->msd_caps.med_sync_max_txop_num; + req->mlo_params.link_switch_in_progress = + wlan_vdev_mlme_is_mlo_link_switch_in_progress(vdev); + /* + * Set max simultaneous links = 1 for MLSR, 2 for MLMR. The +1 + * is added as per the agreement with FW for backward + * compatibility purposes. Our internal structures still + * conform to the values as per spec i.e. 0 = MLSR, 1 = MLMR. + */ + req->mlo_params.max_num_simultaneous_links = + wlan_mlme_get_sta_mlo_simultaneous_links(psoc) + 1; + } else { + wma_debug("Peer MLO context is NULL"); + req->mlo_params.mlo_enabled = false; + req->mlo_params.emlsr_support = false; + } + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); +} + +static void wma_set_mlo_assoc_vdev(struct wlan_objmgr_vdev *vdev, + struct peer_assoc_params *req) +{ + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + !wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + req->is_assoc_vdev = true; +} +#else +static inline void wma_set_mlo_capability(tp_wma_handle wma, + struct wlan_objmgr_vdev *vdev, + tpAddStaParams params, + struct peer_assoc_params *req) +{ +} + +static inline void wma_set_mlo_assoc_vdev(struct wlan_objmgr_vdev *vdev, + struct peer_assoc_params *req) +{ +} +#endif + +/** + * wmi_unified_send_peer_assoc() - send peer assoc command to fw + * @wma: wma handle + * @nw_type: nw type + * @params: add sta params + * + * This function send peer assoc command to firmware with + * different parameters. + * + * Return: QDF_STATUS + */ +QDF_STATUS wma_send_peer_assoc(tp_wma_handle wma, + tSirNwType nw_type, + tpAddStaParams params) +{ + struct peer_assoc_params *cmd; + int32_t ret, max_rates, i; + uint8_t *rate_pos; + wmi_rate_set peer_legacy_rates, peer_ht_rates; + uint32_t num_peer_11b_rates = 0; + uint32_t num_peer_11a_rates = 0; + enum wlan_phymode phymode, vdev_phymode; + uint32_t peer_nss = 1; + struct wma_txrx_node *intr = NULL; + bool is_he; + bool is_eht; + QDF_STATUS status; + struct mac_context *mac = wma->mac_context; + struct wlan_channel *des_chan; + int32_t keymgmt, uccipher, authmode; + + cmd = qdf_mem_malloc(sizeof(struct peer_assoc_params)); + if (!cmd) { + wma_err("Failed to allocate peer_assoc_params param"); + return QDF_STATUS_E_NOMEM; + } + + intr = &wma->interfaces[params->smesessionId]; + + wma_mask_tx_ht_rate(wma, params->supportedRates.supportedMCSSet); + + qdf_mem_zero(&peer_legacy_rates, sizeof(wmi_rate_set)); + qdf_mem_zero(&peer_ht_rates, sizeof(wmi_rate_set)); + qdf_mem_zero(cmd, sizeof(struct peer_assoc_params)); + + is_he = wma_is_peer_he_capable(params); + is_eht = wma_is_peer_eht_capable(params); + if ((params->ch_width > CH_WIDTH_40MHZ) && + ((nw_type == eSIR_11G_NW_TYPE) || + (nw_type == eSIR_11B_NW_TYPE))) { + wma_err("ch_width %d sent in 11G, configure to 40MHz", + params->ch_width); + params->ch_width = CH_WIDTH_40MHZ; + } + phymode = wma_peer_phymode(nw_type, params->staType, + params->htCapable, params->ch_width, + params->vhtCapable, is_he, is_eht); + + des_chan = wlan_vdev_mlme_get_des_chan(intr->vdev); + vdev_phymode = des_chan->ch_phymode; + if ((intr->type == WMI_VDEV_TYPE_AP) && (phymode > vdev_phymode)) { + wma_nofl_debug("Peer phymode %d is not allowed. Set it equal to sap/go phymode %d", + phymode, vdev_phymode); + phymode = vdev_phymode; + } + + if (!mac->mlme_cfg->rates.disable_abg_rate_txdata && + !WLAN_REG_IS_6GHZ_CHAN_FREQ(des_chan->ch_freq)) { + /* Legacy Rateset */ + rate_pos = (uint8_t *) peer_legacy_rates.rates; + for (i = 0; i < SIR_NUM_11B_RATES; i++) { + if (!params->supportedRates.llbRates[i]) + continue; + rate_pos[peer_legacy_rates.num_rates++] = + params->supportedRates.llbRates[i]; + num_peer_11b_rates++; + } + for (i = 0; i < SIR_NUM_11A_RATES; i++) { + if (!params->supportedRates.llaRates[i]) + continue; + rate_pos[peer_legacy_rates.num_rates++] = + params->supportedRates.llaRates[i]; + num_peer_11a_rates++; + } + } + + if ((phymode == WLAN_PHYMODE_11A && num_peer_11a_rates == 0) || + (phymode == WLAN_PHYMODE_11B && num_peer_11b_rates == 0)) { + wma_warn("Invalid phy rates. phymode 0x%x, 11b_rates %d, 11a_rates %d", + phymode, num_peer_11b_rates, + num_peer_11a_rates); + qdf_mem_free(cmd); + return QDF_STATUS_E_INVAL; + } + + /* HT Rateset */ + max_rates = sizeof(peer_ht_rates.rates) / + sizeof(peer_ht_rates.rates[0]); + rate_pos = (uint8_t *) peer_ht_rates.rates; + for (i = 0; i < MAX_SUPPORTED_RATES; i++) { + if (params->supportedRates.supportedMCSSet[i / 8] & + (1 << (i % 8))) { + rate_pos[peer_ht_rates.num_rates++] = i; + if (i >= 8) { + /* MCS8 or higher rate is present, must be 2x2 */ + peer_nss = 2; + } + } + if (peer_ht_rates.num_rates == max_rates) + break; + } + + if (params->htCapable && !peer_ht_rates.num_rates) { + uint8_t temp_ni_rates[8] = { 0x0, 0x1, 0x2, 0x3, + 0x4, 0x5, 0x6, 0x7}; + /* + * Workaround for EV 116382: The peer is marked HT but with + * supported rx mcs set is set to 0. 11n spec mandates MCS0-7 + * for a HT STA. So forcing the supported rx mcs rate to + * MCS 0-7. This workaround will be removed once we get + * clarification from WFA regarding this STA behavior. + */ + + /* TODO: Do we really need this? */ + wma_warn("Peer is marked as HT capable but supported mcs rate is 0"); + peer_ht_rates.num_rates = sizeof(temp_ni_rates); + qdf_mem_copy((uint8_t *) peer_ht_rates.rates, temp_ni_rates, + peer_ht_rates.num_rates); + } + + /* in ap mode and for tdls peer, use mac address of the peer in + * the other end as the new peer address; in sta mode, use bss id to + * be the new peer address + */ + if ((wma_is_vdev_in_ap_mode(wma, params->smesessionId)) +#ifdef FEATURE_WLAN_TDLS + || (STA_ENTRY_TDLS_PEER == params->staType) +#endif /* FEATURE_WLAN_TDLS */ + ) { + qdf_mem_copy(cmd->peer_mac, params->staMac, + sizeof(cmd->peer_mac)); + } else { + qdf_mem_copy(cmd->peer_mac, params->bssId, + sizeof(cmd->peer_mac)); + } + wma_objmgr_set_peer_mlme_phymode(wma, cmd->peer_mac, phymode); + + cmd->vdev_id = params->smesessionId; + cmd->peer_new_assoc = 1; + cmd->peer_associd = params->assocId; + + cmd->is_wme_set = 1; + + if (params->wmmEnabled) + cmd->qos_flag = 1; + + if (params->uAPSD) { + cmd->apsd_flag = 1; + wma_nofl_debug("Set WMI_PEER_APSD: uapsd Mask %d", + params->uAPSD); + } + + if (params->htCapable) { + cmd->ht_flag = 1; + cmd->qos_flag = 1; + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + } + + if (params->vhtCapable) { + cmd->ht_flag = 1; + cmd->qos_flag = 1; + cmd->vht_flag = 1; + cmd->peer_rate_caps |= WMI_RC_HT_FLAG; + } + + if (params->ch_width) { + cmd->peer_rate_caps |= WMI_RC_CW40_FLAG; + if (params->fShortGI40Mhz) + cmd->peer_rate_caps |= WMI_RC_SGI_FLAG; + } else if (params->fShortGI20Mhz) { + cmd->peer_rate_caps |= WMI_RC_SGI_FLAG; + } + + switch (params->ch_width) { + case CH_WIDTH_320MHZ: + wma_set_peer_assoc_params_bw_320(cmd, params->ch_width); + fallthrough; + case CH_WIDTH_80P80MHZ: + case CH_WIDTH_160MHZ: + cmd->bw_160 = 1; + fallthrough; + case CH_WIDTH_80MHZ: + cmd->bw_80 = 1; + fallthrough; + case CH_WIDTH_40MHZ: + cmd->bw_40 = 1; + fallthrough; + default: + break; + } + + cmd->peer_vht_caps = params->vht_caps; + if (params->p2pCapableSta) { + cmd->p2p_capable_sta = 1; + wma_objmgr_set_peer_mlme_type(wma, params->staMac, + WLAN_PEER_P2P_CLI); + } + + if (params->rmfEnabled) + cmd->is_pmf_enabled = 1; + + if (params->stbc_capable) + cmd->stbc_flag = 1; + + if (params->htLdpcCapable || params->vhtLdpcCapable) + cmd->ldpc_flag = 1; + + switch (params->mimoPS) { + case eSIR_HT_MIMO_PS_STATIC: + cmd->static_mimops_flag = 1; + break; + case eSIR_HT_MIMO_PS_DYNAMIC: + cmd->dynamic_mimops_flag = 1; + break; + case eSIR_HT_MIMO_PS_NO_LIMIT: + cmd->spatial_mux_flag = 1; + break; + default: + break; + } + + wma_set_twt_peer_caps(params, cmd); +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == params->staType) + cmd->auth_flag = 1; +#endif /* FEATURE_WLAN_TDLS */ + + if (params->wpa_rsn +#ifdef FEATURE_WLAN_WAPI + || params->encryptType == eSIR_ED_WPI +#endif /* FEATURE_WLAN_WAPI */ + ) { + if (!params->no_ptk_4_way) { + cmd->need_ptk_4_way = 1; + wlan_acquire_peer_key_wakelock(wma->pdev, + cmd->peer_mac); + } + } + + if (params->wpa_rsn >> 1) + cmd->need_gtk_2_way = 1; + +#ifdef FEATURE_WLAN_WAPI + if (params->encryptType == eSIR_ED_WPI) { + ret = wma_vdev_set_param(wma->wmi_handle, params->smesessionId, + wmi_vdev_param_drop_unencry, false); + if (ret) { + wma_err("Set wmi_vdev_param_drop_unencry Param status:%d", + ret); + qdf_mem_free(cmd); + return ret; + } + } +#endif /* FEATURE_WLAN_WAPI */ + + cmd->peer_caps = params->capab_info; + cmd->peer_listen_intval = params->listenInterval; + cmd->peer_ht_caps = params->ht_caps; + cmd->peer_max_mpdu = (1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + params->maxAmpduSize)) - 1; + cmd->peer_mpdu_density = wma_parse_mpdudensity(params->maxAmpduDensity); + + if (params->supportedRates.supportedMCSSet[1] && + params->supportedRates.supportedMCSSet[2]) + cmd->peer_rate_caps |= WMI_RC_TS_FLAG; + else if (params->supportedRates.supportedMCSSet[1]) + cmd->peer_rate_caps |= WMI_RC_DS_FLAG; + + /* Update peer legacy rate information */ + cmd->peer_legacy_rates.num_rates = peer_legacy_rates.num_rates; + qdf_mem_copy(cmd->peer_legacy_rates.rates, peer_legacy_rates.rates, + peer_legacy_rates.num_rates); + + /* Update peer HT rate information */ + cmd->peer_ht_rates.num_rates = peer_ht_rates.num_rates; + qdf_mem_copy(cmd->peer_ht_rates.rates, peer_ht_rates.rates, + peer_ht_rates.num_rates); + + /* VHT Rates */ + + cmd->peer_nss = peer_nss; + /* + * Because of DBS a vdev may come up in any of the two MACs with + * different capabilities. STBC capab should be fetched for given + * hard_mode->MAC_id combo. It is planned that firmware should provide + * these dev capabilities. But for now number of tx streams can be used + * to identify if Tx STBC needs to be disabled. + */ + if (intr->tx_streams < 2) { + cmd->peer_vht_caps &= ~(1 << SIR_MAC_VHT_CAP_TXSTBC); + wma_nofl_debug("Num tx_streams: %d, Disabled txSTBC", + intr->tx_streams); + } + + cmd->vht_capable = params->vhtCapable; + if (params->vhtCapable) { +#define VHT2x2MCSMASK 0xc + cmd->rx_max_rate = params->supportedRates.vhtRxHighestDataRate; + cmd->rx_mcs_set = params->supportedRates.vhtRxMCSMap; + cmd->tx_max_rate = params->supportedRates.vhtTxHighestDataRate; + cmd->tx_mcs_set = params->supportedRates.vhtTxMCSMap; + /* + * tx_mcs_set is intersection of self tx NSS and peer rx mcs map + */ + if (params->vhtSupportedRxNss) + cmd->peer_nss = params->vhtSupportedRxNss; + else + cmd->peer_nss = ((cmd->tx_mcs_set & VHT2x2MCSMASK) + == VHT2x2MCSMASK) ? 1 : 2; + + if (params->vht_mcs_10_11_supp) { + WMI_SET_BITS(cmd->tx_mcs_set, 16, cmd->peer_nss, + ((1 << cmd->peer_nss) - 1)); + WMI_VHT_MCS_NOTIFY_EXT_SS_SET(cmd->tx_mcs_set, 1); + } + if (params->vht_extended_nss_bw_cap && + (params->vht_160mhz_nss || params->vht_80p80mhz_nss)) { + /* + * bit[2:0] : Represents value of Rx NSS for 160 MHz + * bit[5:3] : Represents value of Rx NSS for 80_80 MHz + * Extended NSS support + * bit[30:6]: Reserved + * bit[31] : MSB(0/1): 1 in case of valid data + */ + cmd->peer_bw_rxnss_override |= (1 << 31); + if (params->vht_160mhz_nss) + cmd->peer_bw_rxnss_override |= + (params->vht_160mhz_nss - 1); + if (params->vht_80p80mhz_nss) + cmd->peer_bw_rxnss_override |= + ((params->vht_80p80mhz_nss - 1) << 3); + wma_debug("peer_bw_rxnss_override %0X", + cmd->peer_bw_rxnss_override); + } + } + + wma_set_mlo_capability(wma, intr->vdev, params, cmd); + + wma_set_mlo_assoc_vdev(intr->vdev, cmd); + + wma_debug("rx_max_rate %d, rx_mcs %x, tx_max_rate %d, tx_mcs: %x num rates %d need 4 way %d", + cmd->rx_max_rate, cmd->rx_mcs_set, cmd->tx_max_rate, + cmd->tx_mcs_set, peer_ht_rates.num_rates, + cmd->need_ptk_4_way); + + /* + * Limit nss to max number of rf chain supported by target + * Otherwise Fw will crash + */ + if (cmd->peer_nss > WMA_MAX_NSS) { + wma_err("peer Nss %d is more than supported", cmd->peer_nss); + cmd->peer_nss = WMA_MAX_NSS; + } + + wma_populate_peer_he_cap(cmd, params); + wma_populate_peer_eht_cap(cmd, params); + wma_populate_peer_puncture(cmd, des_chan); + wma_populate_peer_mlo_cap(cmd, params); + if (!wma_is_vdev_in_ap_mode(wma, params->smesessionId)) + intr->nss = cmd->peer_nss; + wma_objmgr_set_peer_mlme_nss(wma, cmd->peer_mac, cmd->peer_nss); + + /* Till conversion is not done in WMI we need to fill fw phy mode */ + cmd->peer_phymode = wmi_host_to_fw_phymode(phymode); + + keymgmt = wlan_crypto_get_param(intr->vdev, WLAN_CRYPTO_PARAM_KEY_MGMT); + authmode = wlan_crypto_get_param(intr->vdev, + WLAN_CRYPTO_PARAM_AUTH_MODE); + uccipher = wlan_crypto_get_param(intr->vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + + cmd->akm = cm_crypto_authmode_to_wmi_authmode(authmode, + keymgmt, + uccipher); + + status = wmi_unified_peer_assoc_send(wma->wmi_handle, + cmd); + if (QDF_IS_STATUS_ERROR(status)) + wma_alert("Failed to send peer assoc command status = %d", + status); + qdf_mem_free(cmd); + + return status; +} + +/** + * wmi_unified_vdev_set_gtx_cfg_send() - set GTX params + * @wmi_handle: wmi handle + * @if_id: vdev id + * @gtx_info: GTX config params + * + * This function set GTX related params in firmware. + * + * Return: 0 for success or error code + */ +QDF_STATUS wmi_unified_vdev_set_gtx_cfg_send(wmi_unified_t wmi_handle, + uint32_t if_id, + gtx_config_t *gtx_info) +{ + struct wmi_gtx_config params; + + params.gtx_rt_mask[0] = gtx_info->gtxRTMask[0]; + params.gtx_rt_mask[1] = gtx_info->gtxRTMask[1]; + params.gtx_usrcfg = gtx_info->gtxUsrcfg; + params.gtx_threshold = gtx_info->gtxPERThreshold; + params.gtx_margin = gtx_info->gtxPERMargin; + params.gtx_tpcstep = gtx_info->gtxTPCstep; + params.gtx_tpcmin = gtx_info->gtxTPCMin; + params.gtx_bwmask = gtx_info->gtxBWMask; + + return wmi_unified_vdev_set_gtx_cfg_cmd(wmi_handle, + if_id, ¶ms); + +} + +/** + * wma_update_protection_mode() - update protection mode + * @wma: wma handle + * @vdev_id: vdev id + * @llbcoexist: protection mode info + * + * This function set protection mode(RTS/CTS) to fw for passed vdev id. + * + * Return: none + */ +void wma_update_protection_mode(tp_wma_handle wma, uint8_t vdev_id, + uint8_t llbcoexist) +{ + QDF_STATUS ret; + enum ieee80211_protmode prot_mode; + + prot_mode = llbcoexist ? IEEE80211_PROT_CTSONLY : IEEE80211_PROT_NONE; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_protection_mode, + prot_mode); + + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to send wmi protection mode cmd"); + else + wma_nofl_debug("Updated protection mode %d to target", + prot_mode); +} + +void +wma_update_beacon_interval(tp_wma_handle wma, uint8_t vdev_id, + uint16_t beaconInterval) +{ + QDF_STATUS ret; + + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_beacon_interval, + beaconInterval); + + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to update beacon interval"); + else + wma_info("Updated beacon interval %d for vdev %d", + beaconInterval, vdev_id); +} + +#ifdef WLAN_FEATURE_11AX_BSS_COLOR +/** + * wma_update_bss_color() - update beacon bss color in fw + * @wma: wma handle + * @vdev_id: vdev id + * @he_ops: HE operation, only the bss_color and bss_color_disabled fields + * are updated. + * + * Return: none + */ +static void +wma_update_bss_color(tp_wma_handle wma, uint8_t vdev_id, + tUpdateBeaconParams *bcn_params) +{ + QDF_STATUS ret; + uint32_t dword_he_ops = 0; + + WMI_HEOPS_COLOR_SET(dword_he_ops, bcn_params->bss_color); + WMI_HEOPS_BSSCOLORDISABLE_SET(dword_he_ops, + bcn_params->bss_color_disabled); + wma_nofl_debug("vdev: %d, update bss color, HE_OPS: 0x%x", + vdev_id, dword_he_ops); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_he_bss_color, dword_he_ops); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to update HE operations"); +} +#else +static void wma_update_bss_color(tp_wma_handle wma, uint8_t vdev_id, + tUpdateBeaconParams *bcn_params) +{ +} +#endif + +/** + * wma_process_update_beacon_params() - update beacon parameters to target + * @wma: wma handle + * @bcn_params: beacon parameters + * + * Return: none + */ +void +wma_process_update_beacon_params(tp_wma_handle wma, + tUpdateBeaconParams *bcn_params) +{ + if (!bcn_params) { + wma_err("bcn_params NULL"); + return; + } + + if (bcn_params->vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev id %d", bcn_params->vdev_id); + return; + } + + if (bcn_params->paramChangeBitmap & PARAM_BCN_INTERVAL_CHANGED) { + wma_update_beacon_interval(wma, bcn_params->vdev_id, + bcn_params->beaconInterval); + } + + if (bcn_params->paramChangeBitmap & PARAM_llBCOEXIST_CHANGED) + wma_update_protection_mode(wma, bcn_params->vdev_id, + bcn_params->llbCoexist); + + if (bcn_params->paramChangeBitmap & PARAM_BSS_COLOR_CHANGED) + wma_update_bss_color(wma, bcn_params->vdev_id, + bcn_params); +} + +void wma_update_rts_params(tp_wma_handle wma, uint32_t value) +{ + uint8_t vdev_id; + QDF_STATUS ret; + struct wlan_objmgr_vdev *vdev; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + vdev = wma->interfaces[vdev_id].vdev; + if (!vdev) + continue; + ret = wma_vdev_set_param(wma->wmi_handle, + vdev_id, + wmi_vdev_param_rts_threshold, + value); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Update cfg param fail for vdevId %d", vdev_id); + } +} + +void wma_update_frag_params(tp_wma_handle wma, uint32_t value) +{ + uint8_t vdev_id; + QDF_STATUS ret; + struct wlan_objmgr_vdev *vdev; + + for (vdev_id = 0; vdev_id < wma->max_bssid; vdev_id++) { + vdev = wma->interfaces[vdev_id].vdev; + if (!vdev) + continue; + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_fragmentation_threshold, + value); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Update cfg params failed for vdevId %d", + vdev_id); + } +} + +/** + * wma_process_update_edca_param_req() - update EDCA params + * @handle: wma handle + * @edca_params: edca parameters + * + * This function updates EDCA parameters to the target + * + * Return: QDF Status + */ +QDF_STATUS wma_process_update_edca_param_req(WMA_HANDLE handle, + tEdcaParams *edca_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct wmi_host_wme_vparams wmm_param[QCA_WLAN_AC_ALL]; + tSirMacEdcaParamRecord *edca_record; + int ac; + struct ol_tx_wmm_param_t ol_tx_wmm_param; + uint8_t vdev_id; + QDF_STATUS status; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t *debug_str; + uint32_t len = 0; + + vdev_id = edca_params->vdev_id; + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("vdev id:%d is not active ", vdev_id); + goto fail; + } + + debug_str = qdf_mem_malloc(WMA_WMM_DEBUG_STRING_SIZE); + if (!debug_str) + goto fail; + + for (ac = 0; ac < QCA_WLAN_AC_ALL; ac++) { + switch (ac) { + case QCA_WLAN_AC_BE: + edca_record = &edca_params->acbe; + break; + case QCA_WLAN_AC_BK: + edca_record = &edca_params->acbk; + break; + case QCA_WLAN_AC_VI: + edca_record = &edca_params->acvi; + break; + case QCA_WLAN_AC_VO: + edca_record = &edca_params->acvo; + break; + default: + qdf_mem_free(debug_str); + goto fail; + } + + wma_update_edca_params_for_ac(edca_record, &wmm_param[ac], ac, + edca_params->mu_edca_params, + debug_str, + WMA_WMM_DEBUG_STRING_SIZE, &len); + + ol_tx_wmm_param.ac[ac].aifs = wmm_param[ac].aifs; + ol_tx_wmm_param.ac[ac].cwmin = wmm_param[ac].cwmin; + ol_tx_wmm_param.ac[ac].cwmax = wmm_param[ac].cwmax; + } + + wma_nofl_debug("WMM params: %s", debug_str); + qdf_mem_free(debug_str); + + status = wmi_unified_process_update_edca_param(wma_handle->wmi_handle, + vdev_id, + edca_params->mu_edca_params, + wmm_param); + if (status == QDF_STATUS_E_NOMEM) + return status; + else if (status == QDF_STATUS_E_FAILURE) + goto fail; + + cdp_set_wmm_param(soc, WMI_PDEV_ID_SOC, ol_tx_wmm_param); + + return QDF_STATUS_SUCCESS; + +fail: + wma_err("Failed to set WMM Parameters"); + return QDF_STATUS_E_FAILURE; +} + +/** + * wmi_unified_probe_rsp_tmpl_send() - send probe response template to fw + * @wma: wma handle + * @vdev_id: vdev id + * @probe_rsp_info: probe response info + * + * Return: 0 for success or error code + */ +static int wmi_unified_probe_rsp_tmpl_send(tp_wma_handle wma, + uint8_t vdev_id, + tpSendProbeRespParams probe_rsp_info) +{ + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh; + struct wmi_probe_resp_params params; + + /* + * Make the TSF offset negative so probe response in the same + * staggered batch have the same TSF. + */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma->interfaces[vdev_id].tsfadjust); + /* Update the timstamp in the probe response buffer with adjusted TSF */ + wh = (struct ieee80211_frame *)probe_rsp_info->probeRespTemplate; + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + + params.prb_rsp_template_len = probe_rsp_info->probeRespTemplateLen; + params.prb_rsp_template_frm = probe_rsp_info->probeRespTemplate; + params.go_ignore_non_p2p_probe_req = + probe_rsp_info->go_ignore_non_p2p_probe_req; + + return wmi_unified_probe_rsp_tmpl_send_cmd(wma->wmi_handle, vdev_id, + ¶ms); +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wma_upt_mlo_partner_info() - update mlo info in beacon template + * @params: beacon template params + * @bcn_param: beacon params + * @bytes_to_strip: bytes to strip + * + * Return: Void + */ +static void wma_upt_mlo_partner_info(struct beacon_tmpl_params *params, + const tpSendbeaconParams bcn_param, + uint8_t bytes_to_strip) +{ + struct ml_bcn_partner_info *bcn_info; + struct ml_bcn_partner_info *info; + int link; + + params->mlo_partner.num_links = bcn_param->mlo_partner.num_links; + for (link = 0; link < params->mlo_partner.num_links; link++) { + bcn_info = &bcn_param->mlo_partner.partner_info[link]; + info = ¶ms->mlo_partner.partner_info[link]; + info->vdev_id = bcn_info->vdev_id; + info->beacon_interval = bcn_info->beacon_interval; + if (bcn_info->csa_switch_count_offset && + bcn_info->csa_switch_count_offset > bytes_to_strip) + info->csa_switch_count_offset = + bcn_info->csa_switch_count_offset - + bytes_to_strip; + if (bcn_info->ext_csa_switch_count_offset && + bcn_info->ext_csa_switch_count_offset > bytes_to_strip) + info->ext_csa_switch_count_offset = + bcn_info->ext_csa_switch_count_offset - + bytes_to_strip; + } +} +#else +static void wma_upt_mlo_partner_info(struct beacon_tmpl_params *params, + const tpSendbeaconParams bcn_param, + uint8_t bytes_to_strip) +{ +} +#endif + +/** + * wma_unified_bcn_tmpl_send() - send beacon template to fw + * @wma:wma handle + * @vdev_id: vdev id + * @bcn_info: beacon info + * @bytes_to_strip: bytes to strip + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wma_unified_bcn_tmpl_send(tp_wma_handle wma, + uint8_t vdev_id, + const tpSendbeaconParams bcn_info, + uint8_t bytes_to_strip) +{ + struct beacon_tmpl_params params = {0}; + uint32_t tmpl_len, tmpl_len_aligned; + uint8_t *frm; + QDF_STATUS ret; + uint8_t *p2p_ie; + uint16_t p2p_ie_len = 0; + uint64_t adjusted_tsf_le; + struct ieee80211_frame *wh; + + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("vdev id:%d is not active ", vdev_id); + return QDF_STATUS_E_INVAL; + } + + wma_nofl_debug("vdev %d: bcn update reason %d", vdev_id, + bcn_info->reason); + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + p2p_ie_len = (uint16_t) p2p_ie[1] + 2; + } + + /* + * XXX: The first byte of beacon buffer contains beacon length + * only when UMAC in sending the beacon template. In othercases + * (ex: from tbtt update) beacon length is read from beacon + * information. + */ + if (bytes_to_strip) + tmpl_len = *(uint32_t *) &bcn_info->beacon[0]; + else + tmpl_len = bcn_info->beaconLength; + + if (tmpl_len > WMI_BEACON_TX_BUFFER_SIZE) { + wma_err("tmpl_len: %d > %d. Invalid tmpl len", tmpl_len, + WMI_BEACON_TX_BUFFER_SIZE); + return -EINVAL; + } + + if (p2p_ie_len) { + if (tmpl_len <= p2p_ie_len) { + wma_err("tmpl_len %d <= p2p_ie_len %d, Invalid", + tmpl_len, p2p_ie_len); + return -EINVAL; + } + tmpl_len -= (uint32_t) p2p_ie_len; + } + + frm = bcn_info->beacon + bytes_to_strip; + tmpl_len_aligned = roundup(tmpl_len, sizeof(A_UINT32)); + /* + * Make the TSF offset negative so beacons in the same + * staggered batch have the same TSF. + */ + adjusted_tsf_le = cpu_to_le64(0ULL - + wma->interfaces[vdev_id].tsfadjust); + /* Update the timstamp in the beacon buffer with adjusted TSF */ + wh = (struct ieee80211_frame *)frm; + A_MEMCPY(&wh[1], &adjusted_tsf_le, sizeof(adjusted_tsf_le)); + + + + params.vdev_id = vdev_id; + params.tim_ie_offset = bcn_info->timIeOffset - bytes_to_strip; + params.tmpl_len = tmpl_len; + params.frm = frm; + params.tmpl_len_aligned = tmpl_len_aligned; + params.enable_bigtk = + mlme_get_bigtk_support(wma->interfaces[vdev_id].vdev); + if (bcn_info->csa_count_offset && + (bcn_info->csa_count_offset > bytes_to_strip)) + params.csa_switch_count_offset = + bcn_info->csa_count_offset - bytes_to_strip; + if (bcn_info->ecsa_count_offset && + (bcn_info->ecsa_count_offset > bytes_to_strip)) + params.ext_csa_switch_count_offset = + bcn_info->ecsa_count_offset - bytes_to_strip; + + wma_upt_mlo_partner_info(¶ms, bcn_info, bytes_to_strip); + + ret = wmi_unified_beacon_tmpl_send_cmd(wma->wmi_handle, + ¶ms); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to send bcn tmpl: %d", ret); + + return ret; +} + +/** + * wma_store_bcn_tmpl() - store beacon template + * @wma: wma handle + * @vdev_id: vdev id + * @bcn_info: beacon params + * + * This function stores beacon template locally. + * This will send to target on the reception of + * SWBA event. + * + * Return: QDF status + */ +static QDF_STATUS wma_store_bcn_tmpl(tp_wma_handle wma, uint8_t vdev_id, + tpSendbeaconParams bcn_info) +{ + struct beacon_info *bcn; + uint32_t len; + uint8_t *bcn_payload; + struct beacon_tim_ie *tim_ie; + + bcn = wma->interfaces[vdev_id].beacon; + if (!bcn || !bcn->buf) { + wma_err("Memory is not allocated to hold bcn template"); + return QDF_STATUS_E_INVAL; + } + + len = *(uint32_t *) &bcn_info->beacon[0]; + if (len > SIR_MAX_BEACON_SIZE - sizeof(uint32_t)) { + wma_err("Received beacon len %u exceeding max limit %lu", + len, (unsigned long)( + SIR_MAX_BEACON_SIZE - sizeof(uint32_t))); + return QDF_STATUS_E_INVAL; + } + qdf_spin_lock_bh(&bcn->lock); + + /* + * Copy received beacon template content in local buffer. + * this will be send to target on the reception of SWBA + * event from target. + */ + qdf_nbuf_trim_tail(bcn->buf, qdf_nbuf_len(bcn->buf)); + memcpy(qdf_nbuf_data(bcn->buf), + bcn_info->beacon + 4 /* Exclude beacon length field */, + len); + if (bcn_info->timIeOffset > 3) + bcn->tim_ie_offset = bcn_info->timIeOffset - 4; + else + bcn->tim_ie_offset = bcn_info->timIeOffset; + + if (bcn_info->p2pIeOffset > 3) + bcn->p2p_ie_offset = bcn_info->p2pIeOffset - 4; + else + bcn->p2p_ie_offset = bcn_info->p2pIeOffset; + + if (bcn_info->csa_count_offset > 3) + bcn->csa_count_offset = bcn_info->csa_count_offset - 4; + else + bcn->csa_count_offset = bcn_info->csa_count_offset; + + if (bcn_info->ecsa_count_offset > 3) + bcn->ecsa_count_offset = bcn_info->ecsa_count_offset - 4; + else + bcn->ecsa_count_offset = bcn_info->ecsa_count_offset; + + bcn_payload = qdf_nbuf_data(bcn->buf); + if (bcn->tim_ie_offset) { + tim_ie = (struct beacon_tim_ie *) + (&bcn_payload[bcn->tim_ie_offset]); + /* + * Initial Value of bcn->dtim_count will be 0. + * But if the beacon gets updated then current dtim + * count will be restored + */ + tim_ie->dtim_count = bcn->dtim_count; + tim_ie->tim_bitctl = 0; + } + + qdf_nbuf_put_tail(bcn->buf, len); + bcn->len = len; + + qdf_spin_unlock_bh(&bcn->lock); + + return QDF_STATUS_SUCCESS; +} + +int wma_tbttoffset_update_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *param_buf; + wmi_tbtt_offset_event_fixed_param *tbtt_offset_event; + struct wma_txrx_node *intf; + struct beacon_info *bcn; + tSendbeaconParams bcn_info; + uint32_t *adjusted_tsf = NULL; + uint32_t if_id = 0, vdev_map; + + if (wma_validate_handle(wma)) + return -EINVAL; + + param_buf = (WMI_TBTTOFFSET_UPDATE_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid tbtt update event buffer"); + return -EINVAL; + } + + tbtt_offset_event = param_buf->fixed_param; + intf = wma->interfaces; + vdev_map = tbtt_offset_event->vdev_map; + adjusted_tsf = param_buf->tbttoffset_list; + if (!adjusted_tsf) { + wma_err("Invalid adjusted_tsf"); + return -EINVAL; + } + + for (; (if_id < wma->max_bssid && vdev_map); vdev_map >>= 1, if_id++) { + if (!intf[if_id].vdev) + continue; + + if (!(vdev_map & 0x1)) + continue; + + bcn = intf[if_id].beacon; + if (!bcn) { + wma_err("Invalid beacon"); + return -EINVAL; + } + if (!bcn->buf) { + wma_err("Invalid beacon buffer"); + return -EINVAL; + } + /* Save the adjusted TSF */ + intf[if_id].tsfadjust = adjusted_tsf[if_id]; + + qdf_spin_lock_bh(&bcn->lock); + qdf_mem_zero(&bcn_info, sizeof(bcn_info)); + qdf_mem_copy(bcn_info.beacon, + qdf_nbuf_data(bcn->buf), bcn->len); + bcn_info.p2pIeOffset = bcn->p2p_ie_offset; + bcn_info.beaconLength = bcn->len; + bcn_info.timIeOffset = bcn->tim_ie_offset; + bcn_info.csa_count_offset = bcn->csa_count_offset; + bcn_info.ecsa_count_offset = bcn->ecsa_count_offset; + qdf_spin_unlock_bh(&bcn->lock); + + wma_err_rl("Update beacon template for vdev %d due to TBTT offset update", + if_id); + /* Update beacon template in firmware */ + wma_unified_bcn_tmpl_send(wma, if_id, &bcn_info, 0); + } + return 0; +} + +/** + * wma_p2p_go_set_beacon_ie() - set beacon IE for p2p go + * @wma_handle: wma handle + * @vdev_id: vdev id + * @p2pIe: p2p IE + * + * Return: 0 for success or error code + */ +static int wma_p2p_go_set_beacon_ie(t_wma_handle *wma_handle, + A_UINT32 vdev_id, uint8_t *p2pIe) +{ + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_FAILURE; + + return wmi_unified_p2p_go_set_beacon_ie_cmd(wma_handle->wmi_handle, + vdev_id, p2pIe); +} + +/** + * wma_send_probe_rsp_tmpl() - send probe resp template + * @wma: wma handle + * @probe_rsp_info: probe response info + * + * This function sends probe response template to fw which + * firmware will use in case of probe response offload. + * + * Return: none + */ +void wma_send_probe_rsp_tmpl(tp_wma_handle wma, + tpSendProbeRespParams probe_rsp_info) +{ + uint8_t vdev_id; + struct sAniProbeRspStruct *probe_rsp; + + if (!probe_rsp_info) { + wma_err("probe_rsp_info is NULL"); + return; + } + + probe_rsp = (struct sAniProbeRspStruct *) + (probe_rsp_info->probeRespTemplate); + if (!probe_rsp) { + wma_err("probe_rsp is NULL"); + return; + } + + if (wma_find_vdev_id_by_addr(wma, probe_rsp->macHdr.sa, &vdev_id)) { + wma_err("failed to get vdev id"); + return; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_beacon_offload)) { + if (wmi_unified_probe_rsp_tmpl_send(wma, vdev_id, + probe_rsp_info) < 0) { + wma_err("wmi_unified_probe_rsp_tmpl_send Failed"); + return; + } + } +} + +QDF_STATUS wma_set_ap_vdev_up(tp_wma_handle wma, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct vdev_mlme_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev; + struct wma_txrx_node *iface; + + iface = &wma->interfaces[vdev_id]; + vdev = iface->vdev; + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("failed to get mlme_obj"); + return QDF_STATUS_E_INVAL; + } + mlme_obj->proto.sta.assoc_id = 0; + + status = vdev_mgr_up_send(mlme_obj); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to send vdev up"); + return status; + } + wma_set_sap_keepalive(wma, vdev_id); + wma_set_vdev_mgmt_rate(wma, vdev_id); + wma_vdev_set_he_bss_params(wma, vdev_id, &mlme_obj->proto.he_ops_info); + mlme_sr_update(vdev, true); + + return status; +} + +/** + * wma_send_beacon() - send beacon template + * @wma: wma handle + * @bcn_info: beacon info + * + * This function store beacon template locally and + * update keep alive parameters + * + * Return: none + */ +void wma_send_beacon(tp_wma_handle wma, tpSendbeaconParams bcn_info) +{ + uint8_t vdev_id; + QDF_STATUS status; + uint8_t *p2p_ie; + struct sAniBeaconStruct *beacon; + + beacon = (struct sAniBeaconStruct *) (bcn_info->beacon); + if (wma_find_vdev_id_by_addr(wma, beacon->macHdr.sa, &vdev_id)) { + wma_err("failed to get vdev id"); + status = QDF_STATUS_E_INVAL; + goto send_rsp; + } + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_beacon_offload)) { + status = wma_unified_bcn_tmpl_send(wma, vdev_id, bcn_info, 4); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("wmi_unified_bcn_tmpl_send Failed"); + goto send_rsp; + } + + if (bcn_info->p2pIeOffset) { + p2p_ie = bcn_info->beacon + bcn_info->p2pIeOffset; + wma_debug("p2pIe is present - vdev_id %hu, p2p_ie = %pK, p2p ie len = %hu", + vdev_id, p2p_ie, p2p_ie[1]); + if (wma_p2p_go_set_beacon_ie(wma, vdev_id, + p2p_ie) < 0) { + wma_err("wmi_unified_bcn_tmpl_send Failed"); + status = QDF_STATUS_E_INVAL; + goto send_rsp; + } + } + } + status = wma_store_bcn_tmpl(wma, vdev_id, bcn_info); + if (status != QDF_STATUS_SUCCESS) { + wma_err("wma_store_bcn_tmpl Failed"); + goto send_rsp; + } + +send_rsp: + bcn_info->status = status; + wma_send_msg(wma, WMA_SEND_BCN_RSP, (void *)bcn_info, 0); +} + +/** + * wma_set_keepalive_req() - send keep alive request to fw + * @wma: wma handle + * @keepalive: keep alive parameters + * + * Return: none + */ +void wma_set_keepalive_req(tp_wma_handle wma, + struct keep_alive_req *keepalive) +{ + wma_nofl_debug("KEEPALIVE:PacketType:%d", keepalive->packetType); + wma_set_sta_keep_alive(wma, keepalive->sessionId, + keepalive->packetType, + keepalive->timePeriod, + keepalive->hostIpv4Addr, + keepalive->destIpv4Addr, + keepalive->dest_macaddr.bytes); + + qdf_mem_free(keepalive); +} + +/** + * wma_beacon_miss_handler() - beacon miss event handler + * @wma: wma handle + * @vdev_id: vdev id + * @rssi: rssi value + * + * This function send beacon miss indication to upper layers. + * + * Return: none + */ +void wma_beacon_miss_handler(tp_wma_handle wma, uint32_t vdev_id, int32_t rssi) +{ + struct missed_beacon_ind *beacon_miss_ind; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + beacon_miss_ind = qdf_mem_malloc(sizeof(*beacon_miss_ind)); + if (!beacon_miss_ind) + return; + + if (mac && mac->sme.tx_queue_cb) + mac->sme.tx_queue_cb(mac->hdd_handle, vdev_id, + WLAN_STOP_ALL_NETIF_QUEUE, + WLAN_CONTROL_PATH); + beacon_miss_ind->messageType = WMA_MISSED_BEACON_IND; + beacon_miss_ind->length = sizeof(*beacon_miss_ind); + beacon_miss_ind->bss_idx = vdev_id; + beacon_miss_ind->rssi = rssi; + + wma_send_msg(wma, WMA_MISSED_BEACON_IND, beacon_miss_ind, 0); + if (!wmi_service_enabled(wma->wmi_handle, + wmi_service_hw_db2dbm_support)) + rssi += WMA_TGT_NOISE_FLOOR_DBM; + wma_lost_link_info_handler(wma, vdev_id, rssi); +} + +void wlan_cm_send_beacon_miss(uint8_t vdev_id, int32_t rssi) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + wma_beacon_miss_handler(wma, vdev_id, rssi); +} + +/** + * wma_get_status_str() - get string of tx status from firmware + * @status: tx status + * + * Return: converted string of tx status + */ +static const char *wma_get_status_str(uint32_t status) +{ + switch (status) { + default: + return "unknown"; + CASE_RETURN_STRING(WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK); + CASE_RETURN_STRING(WMI_MGMT_TX_COMP_TYPE_DISCARD); + CASE_RETURN_STRING(WMI_MGMT_TX_COMP_TYPE_INSPECT); + CASE_RETURN_STRING(WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK); + CASE_RETURN_STRING(WMI_MGMT_TX_COMP_TYPE_MAX); + } +} + +#ifdef CONFIG_HL_SUPPORT +static inline void wma_mgmt_unmap_buf(tp_wma_handle wma_handle, qdf_nbuf_t buf) +{ +} +#else +static inline void wma_mgmt_unmap_buf(tp_wma_handle wma_handle, qdf_nbuf_t buf) +{ + qdf_nbuf_unmap_single(wma_handle->qdf_dev, buf, QDF_DMA_TO_DEVICE); +} +#endif + +#if defined(CONNECTIVITY_PKTLOG) || !defined(REMOVE_PKT_LOG) +/** + * wma_mgmt_qdf_status_map() - map MGMT Tx completion status with + * packet dump Tx status + * @status: MGMT Tx completion status + * + * Return: packet dump tx_status enum + */ +static inline enum qdf_dp_tx_rx_status +wma_mgmt_qdf_status_map(WMI_MGMT_TX_COMP_STATUS_TYPE status) +{ + enum qdf_dp_tx_rx_status pktdump_status; + + switch (status) { + case WMI_MGMT_TX_COMP_TYPE_COMPLETE_OK: + pktdump_status = QDF_TX_RX_STATUS_OK; + break; + case WMI_MGMT_TX_COMP_TYPE_DISCARD: + pktdump_status = QDF_TX_RX_STATUS_DROP; + break; + case WMI_MGMT_TX_COMP_TYPE_COMPLETE_NO_ACK: + pktdump_status = QDF_TX_RX_STATUS_NO_ACK; + break; + default: + pktdump_status = QDF_TX_RX_STATUS_DROP; + break; + } + return pktdump_status; +} + +/** + * wma_mgmt_pktdump_tx_handler() - calls tx cb if CONNECTIVITY_PKTLOG + * feature is enabled + * @wma_handle: wma handle + * @buf: nbuf + * @vdev_id : vdev id + * @status : status + * + * Return: none + */ +static inline void wma_mgmt_pktdump_tx_handler(tp_wma_handle wma_handle, + qdf_nbuf_t buf, uint8_t vdev_id, + uint32_t status) +{ + ol_txrx_pktdump_cb packetdump_cb; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + enum qdf_dp_tx_rx_status pktdump_status; + + packetdump_cb = wma_handle->wma_mgmt_tx_packetdump_cb; + pktdump_status = wma_mgmt_qdf_status_map(status); + if (packetdump_cb) + packetdump_cb(soc, WMI_PDEV_ID_SOC, vdev_id, + buf, pktdump_status, QDF_TX_MGMT_PKT); +} + +/** + * wma_mgmt_pktdump_rx_handler() - calls rx cb if CONNECTIVITY_PKTLOG + * feature is enabled + * @mgmt_rx_params: mgmt rx params + * @rx_pkt: cds packet + * @wma_handle: wma handle + * mgt_type: management type + * mgt_subtype: management subtype + * + * Return: none + */ +static inline void wma_mgmt_pktdump_rx_handler( + struct mgmt_rx_event_params *mgmt_rx_params, + cds_pkt_t *rx_pkt, tp_wma_handle wma_handle, + uint8_t mgt_type, uint8_t mgt_subtype) +{ + ol_txrx_pktdump_cb packetdump_cb; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + packetdump_cb = wma_handle->wma_mgmt_rx_packetdump_cb; + if ((mgt_type == IEEE80211_FC0_TYPE_MGT && + mgt_subtype != MGMT_SUBTYPE_BEACON) && + packetdump_cb) + packetdump_cb(soc, mgmt_rx_params->pdev_id, + rx_pkt->pkt_meta.session_id, rx_pkt->pkt_buf, + QDF_TX_RX_STATUS_OK, QDF_RX_MGMT_PKT); +} + +#else +static inline void wma_mgmt_pktdump_tx_handler(tp_wma_handle wma_handle, + qdf_nbuf_t buf, uint8_t vdev_id, + uint32_t status) +{ +} + +static inline void wma_mgmt_pktdump_rx_handler( + struct mgmt_rx_event_params *mgmt_rx_params, + cds_pkt_t *rx_pkt, tp_wma_handle wma_handle, + uint8_t mgt_type, uint8_t mgt_subtype) +{ +} +#endif + +/** + * wma_process_mgmt_tx_completion() - process mgmt completion + * @wma_handle: wma handle + * @desc_id: descriptor id + * @status: status + * + * Return: 0 for success or error code + */ +static int wma_process_mgmt_tx_completion(tp_wma_handle wma_handle, + uint32_t desc_id, uint32_t status) +{ + struct wlan_objmgr_pdev *pdev; + qdf_nbuf_t buf = NULL; + QDF_STATUS ret; + uint8_t vdev_id = 0; + struct wmi_mgmt_params mgmt_params = {}; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + wma_debug("status: %s wmi_desc_id: %d", + wma_get_status_str(status), desc_id); + + pdev = wma_handle->pdev; + if (!pdev) { + wma_err("psoc ptr is NULL"); + return -EINVAL; + } + + buf = mgmt_txrx_get_nbuf(pdev, desc_id); + + + if (buf) + wma_mgmt_unmap_buf(wma_handle, buf); + + vdev_id = mgmt_txrx_get_vdev_id(pdev, desc_id); + mgmt_params.vdev_id = vdev_id; + + wma_mgmt_pktdump_tx_handler(wma_handle, buf, vdev_id, status); + ret = mgmt_txrx_tx_completion_handler(pdev, desc_id, status, + &mgmt_params); + + if (ret != QDF_STATUS_SUCCESS) { + wma_err("Failed to process mgmt tx completion"); + return -EINVAL; + } + + return 0; +} + +/** + * wma_extract_mgmt_offload_event_params() - Extract mgmt event params + * @params: Management offload event params + * @hdr: Management header to extract + * + * Return: None + */ +static void wma_extract_mgmt_offload_event_params( + struct mgmt_offload_event_params *params, + wmi_mgmt_hdr *hdr) +{ + params->tsf_l32 = hdr->tsf_l32; + params->chan_freq = hdr->chan_freq; + params->rate_kbps = hdr->rate_kbps; + params->rssi = hdr->rssi; + params->buf_len = hdr->buf_len; + params->tx_status = hdr->tx_status; + params->tx_retry_cnt = hdr->tx_retry_cnt; +} + +/** + * wma_mgmt_tx_completion_handler() - wma mgmt Tx completion event handler + * @handle: wma handle + * @cmpl_event_params: completion event handler data + * @len: length of @cmpl_event_params + * + * Return: 0 on success; error number otherwise + */ + +int wma_mgmt_tx_completion_handler(void *handle, uint8_t *cmpl_event_params, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *param_buf; + wmi_mgmt_tx_compl_event_fixed_param *cmpl_params; + + param_buf = (WMI_MGMT_TX_COMPLETION_EVENTID_param_tlvs *) + cmpl_event_params; + if (!param_buf || !wma_handle) { + wma_err("Invalid mgmt Tx completion event"); + return -EINVAL; + } + cmpl_params = param_buf->fixed_param; + + if ((ucfg_pkt_capture_get_pktcap_mode(wma_handle->psoc) & + PKT_CAPTURE_MODE_MGMT_ONLY) && param_buf->mgmt_hdr) { + struct mgmt_offload_event_params params = {0}; + + wma_extract_mgmt_offload_event_params( + ¶ms, + (wmi_mgmt_hdr *)param_buf->mgmt_hdr); + ucfg_pkt_capture_mgmt_tx_completion(wma_handle->pdev, + cmpl_params->desc_id, + cmpl_params->status, + ¶ms); + } + + wma_process_mgmt_tx_completion(wma_handle, cmpl_params->desc_id, + cmpl_params->status); + + return 0; +} + +/** + * wma_mgmt_tx_bundle_completion_handler() - mgmt bundle comp handler + * @handle: wma handle + * @buf: buffer + * @len: length + * + * Return: 0 for success or error code + */ +int wma_mgmt_tx_bundle_completion_handler(void *handle, uint8_t *buf, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID_param_tlvs *param_buf; + wmi_mgmt_tx_compl_bundle_event_fixed_param *cmpl_params; + uint32_t num_reports; + uint32_t *desc_ids; + uint32_t *status; + uint32_t i, buf_len; + bool excess_data = false; + + param_buf = (WMI_MGMT_TX_BUNDLE_COMPLETION_EVENTID_param_tlvs *)buf; + if (!param_buf || !wma_handle) { + wma_err("Invalid mgmt Tx completion event"); + return -EINVAL; + } + cmpl_params = param_buf->fixed_param; + num_reports = cmpl_params->num_reports; + desc_ids = (uint32_t *)(param_buf->desc_ids); + status = (uint32_t *)(param_buf->status); + + /* buf contains num_reports * sizeof(uint32) len of desc_ids and + * num_reports * sizeof(uint32) status, + * so (2 x (num_reports * sizeof(uint32)) should not exceed MAX + */ + if (cmpl_params->num_reports > (WMI_SVC_MSG_MAX_SIZE / + (2 * sizeof(uint32_t)))) + excess_data = true; + else + buf_len = cmpl_params->num_reports * (2 * sizeof(uint32_t)); + + if (excess_data || (sizeof(*cmpl_params) > (WMI_SVC_MSG_MAX_SIZE - + buf_len))) { + wma_err("excess wmi buffer: num_reports %d", + cmpl_params->num_reports); + return -EINVAL; + } + + if ((cmpl_params->num_reports > param_buf->num_desc_ids) || + (cmpl_params->num_reports > param_buf->num_status)) { + wma_err("Invalid num_reports %d, num_desc_ids %d, num_status %d", + cmpl_params->num_reports, param_buf->num_desc_ids, + param_buf->num_status); + return -EINVAL; + } + + for (i = 0; i < num_reports; i++) { + if ((ucfg_pkt_capture_get_pktcap_mode(wma_handle->psoc) & + PKT_CAPTURE_MODE_MGMT_ONLY) && param_buf->mgmt_hdr) { + struct mgmt_offload_event_params params = {0}; + + wma_extract_mgmt_offload_event_params( + ¶ms, + &((wmi_mgmt_hdr *)param_buf->mgmt_hdr)[i]); + ucfg_pkt_capture_mgmt_tx_completion( + wma_handle->pdev, desc_ids[i], + status[i], ¶ms); + } + + wma_process_mgmt_tx_completion(wma_handle, + desc_ids[i], status[i]); + } + return 0; +} + +/** + * wma_process_update_opmode() - process update VHT opmode cmd from UMAC + * @wma_handle: wma handle + * @update_vht_opmode: vht opmode + * + * Return: none + */ +void wma_process_update_opmode(tp_wma_handle wma_handle, + tUpdateVHTOpMode *update_vht_opmode) +{ + wmi_host_channel_width ch_width; + uint8_t pdev_id; + struct wlan_objmgr_peer *peer; + struct wlan_objmgr_psoc *psoc = wma_handle->psoc; + enum wlan_phymode peer_phymode; + uint32_t fw_phymode; + enum wlan_peer_type peer_type; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(wma_handle->pdev); + peer = wlan_objmgr_get_peer(psoc, pdev_id, + update_vht_opmode->peer_mac, + WLAN_LEGACY_WMA_ID); + if (!peer) { + wma_err("peer object invalid"); + return; + } + + peer_type = wlan_peer_get_peer_type(peer); + if (peer_type == WLAN_PEER_SELF) { + wma_err("self peer wrongly used"); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + return; + } + + wlan_peer_obj_lock(peer); + peer_phymode = wlan_peer_get_phymode(peer); + wlan_peer_obj_unlock(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + fw_phymode = wmi_host_to_fw_phymode(peer_phymode); + + ch_width = wmi_get_ch_width_from_phy_mode(wma_handle->wmi_handle, + fw_phymode); + wma_debug("ch_width: %d, fw phymode: %d peer_phymode: %d, op_mode: %d", + ch_width, fw_phymode, peer_phymode, + update_vht_opmode->opMode); + + if (ch_width < update_vht_opmode->opMode) { + wma_err("Invalid peer bw update %d, self bw %d", + update_vht_opmode->opMode, ch_width); + return; + } + + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_HOST_PEER_CHWIDTH, update_vht_opmode->opMode, + update_vht_opmode->smesessionId); + + wma_set_peer_param(wma_handle, update_vht_opmode->peer_mac, + WMI_HOST_PEER_PHYMODE, + fw_phymode, update_vht_opmode->smesessionId); +} + +/** + * wma_process_update_rx_nss() - process update RX NSS cmd from UMAC + * @wma_handle: wma handle + * @update_rx_nss: rx nss value + * + * Return: none + */ +void wma_process_update_rx_nss(tp_wma_handle wma_handle, + tUpdateRxNss *update_rx_nss) +{ + struct target_psoc_info *tgt_hdl; + struct wma_txrx_node *intr = + &wma_handle->interfaces[update_rx_nss->smesessionId]; + int rx_nss = update_rx_nss->rxNss; + int num_rf_chains; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wma_handle->psoc); + if (!tgt_hdl) { + wma_err("target psoc info is NULL"); + return; + } + + num_rf_chains = target_if_get_num_rf_chains(tgt_hdl); + if (rx_nss > num_rf_chains || rx_nss > WMA_MAX_NSS) + rx_nss = QDF_MIN(num_rf_chains, WMA_MAX_NSS); + + intr->nss = (uint8_t)rx_nss; + update_rx_nss->rxNss = (uint32_t)rx_nss; + + wma_debug("Rx Nss = %d", update_rx_nss->rxNss); + + wma_set_peer_param(wma_handle, update_rx_nss->peer_mac, + WMI_HOST_PEER_NSS, update_rx_nss->rxNss, + update_rx_nss->smesessionId); +} + +/** + * wma_process_update_membership() - process update group membership cmd + * @wma_handle: wma handle + * @membership: group membership info + * + * Return: none + */ +void wma_process_update_membership(tp_wma_handle wma_handle, + tUpdateMembership *membership) +{ + wma_debug("membership = %x ", membership->membership); + + wma_set_peer_param(wma_handle, membership->peer_mac, + WMI_HOST_PEER_MEMBERSHIP, membership->membership, + membership->smesessionId); +} + +/** + * wma_process_update_userpos() - process update user pos cmd from UMAC + * @wma_handle: wma handle + * @userpos: user pos value + * + * Return: none + */ +void wma_process_update_userpos(tp_wma_handle wma_handle, + tUpdateUserPos *userpos) +{ + wma_debug("userPos = %x ", userpos->userPos); + + wma_set_peer_param(wma_handle, userpos->peer_mac, + WMI_HOST_PEER_USERPOS, userpos->userPos, + userpos->smesessionId); + + /* Now that membership/userpos is updated in fw, + * enable GID PPS. + */ + wma_set_ppsconfig(userpos->smesessionId, WMA_VHT_PPS_GID_MATCH, 1); + +} + +QDF_STATUS wma_set_cts2self_for_p2p_go(void *wma_handle, + uint32_t cts2self_for_p2p_go) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle)wma_handle; + struct pdev_params pdevparam = {}; + + pdevparam.param_id = wmi_pdev_param_cts2self_for_p2p_go_config; + pdevparam.param_value = cts2self_for_p2p_go; + + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + wma_err("Fail to Set CTS2SELF for p2p GO %d", + cts2self_for_p2p_go); + return QDF_STATUS_E_FAILURE; + } + + wma_nofl_debug("Successfully Set CTS2SELF for p2p GO %d", + cts2self_for_p2p_go); + + return QDF_STATUS_SUCCESS; +} + + +/** + * wma_set_htconfig() - set ht config parameters to target + * @vdev_id: vdev id + * @ht_capab: ht capability + * @value: value of ht param + * + * Return: QDF status + */ +QDF_STATUS wma_set_htconfig(uint8_t vdev_id, uint16_t ht_capab, int value) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + + if (!wma) + return QDF_STATUS_E_INVAL; + + switch (ht_capab) { + case WNI_CFG_HT_CAP_INFO_ADVANCE_CODING: + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_ldpc, + value); + break; + case WNI_CFG_HT_CAP_INFO_TX_STBC: + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_tx_stbc, + value); + break; + case WNI_CFG_HT_CAP_INFO_RX_STBC: + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_rx_stbc, + value); + break; + case WNI_CFG_HT_CAP_INFO_SHORT_GI_20MHZ: + case WNI_CFG_HT_CAP_INFO_SHORT_GI_40MHZ: + wma_err("ht_capab = %d, value = %d", ht_capab, + value); + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_sgi, value); + if (ret == QDF_STATUS_SUCCESS) + wma->interfaces[vdev_id].config.shortgi = value; + break; + default: + wma_err("INVALID HT CONFIG"); + } + + return ret; +} + +/** + * wma_extract_ccmp_pn() - extract 6 byte PN from the CCMP header + * @ccmp_ptr: CCMP header + * + * Return: PN extracted from header. + */ +static uint64_t wma_extract_ccmp_pn(uint8_t *ccmp_ptr) +{ + uint8_t rsvd, key, pn[6]; + uint64_t new_pn; + + /* + * +-----+-----+------+----------+-----+-----+-----+-----+ + * | PN0 | PN1 | rsvd | rsvd/key | PN2 | PN3 | PN4 | PN5 | + * +-----+-----+------+----------+-----+-----+-----+-----+ + * CCMP Header Format + */ + + /* Extract individual bytes */ + pn[0] = (uint8_t) *ccmp_ptr; + pn[1] = (uint8_t) *(ccmp_ptr + 1); + rsvd = (uint8_t) *(ccmp_ptr + 2); + key = (uint8_t) *(ccmp_ptr + 3); + pn[2] = (uint8_t) *(ccmp_ptr + 4); + pn[3] = (uint8_t) *(ccmp_ptr + 5); + pn[4] = (uint8_t) *(ccmp_ptr + 6); + pn[5] = (uint8_t) *(ccmp_ptr + 7); + + /* Form 6 byte PN with 6 individual bytes of PN */ + new_pn = ((uint64_t) pn[5] << 40) | + ((uint64_t) pn[4] << 32) | + ((uint64_t) pn[3] << 24) | + ((uint64_t) pn[2] << 16) | + ((uint64_t) pn[1] << 8) | ((uint64_t) pn[0] << 0); + + return new_pn; +} + +/** + * wma_is_ccmp_pn_replay_attack() - detect replay attacking using PN in CCMP + * @wma: wma context + * @wh: 802.11 frame header + * @ccmp_ptr: CCMP frame header + * + * Return: true/false + */ +static bool +wma_is_ccmp_pn_replay_attack(tp_wma_handle wma, struct ieee80211_frame *wh, + uint8_t *ccmp_ptr) +{ + uint64_t new_pn; + bool ret = false; + struct peer_mlme_priv_obj *peer_priv; + struct wlan_objmgr_peer *peer; + + new_pn = wma_extract_ccmp_pn(ccmp_ptr); + + peer = wlan_objmgr_get_peer_by_mac(wma->psoc, wh->i_addr2, + WLAN_LEGACY_WMA_ID); + if (!peer) + return ret; + + peer_priv = wlan_objmgr_peer_get_comp_private_obj(peer, + WLAN_UMAC_COMP_MLME); + if (!peer_priv) { + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + return ret; + } + + if (peer_priv->last_pn_valid) { + if (new_pn > peer_priv->last_pn) { + peer_priv->last_pn = new_pn; + } else { + wma_err_rl("PN Replay attack detected"); + /* per 11W amendment, keeping track of replay attacks */ + peer_priv->rmf_pn_replays += 1; + ret = true; + } + } else { + peer_priv->last_pn_valid = 1; + peer_priv->last_pn = new_pn; + } + + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + + return ret; +} + +/** + * wma_process_bip() - process mmie in rmf frame + * @wma_handle: wma handle + * @iface: txrx node + * @wh: 80211 frame + * @wbuf: Buffer + * + * Return: 0 for success or error code + */ +static +int wma_process_bip(tp_wma_handle wma_handle, struct wma_txrx_node *iface, + struct ieee80211_frame *wh, qdf_nbuf_t wbuf) +{ + uint16_t mmie_size; + uint8_t *efrm; + int32_t mgmtcipherset; + enum wlan_crypto_cipher_type key_cipher; + + efrm = qdf_nbuf_data(wbuf) + qdf_nbuf_len(wbuf); + + mgmtcipherset = wlan_crypto_get_param(iface->vdev, + WLAN_CRYPTO_PARAM_MGMT_CIPHER); + if (mgmtcipherset <= 0) { + wma_err("Invalid key cipher %d", mgmtcipherset); + return -EINVAL; + } + + if (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_CMAC)) { + key_cipher = WLAN_CRYPTO_CIPHER_AES_CMAC; + mmie_size = cds_get_mmie_size(); + } else if (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_GMAC)) { + key_cipher = WLAN_CRYPTO_CIPHER_AES_GMAC; + mmie_size = cds_get_gmac_mmie_size(); + } else if (mgmtcipherset & (1 << WLAN_CRYPTO_CIPHER_AES_GMAC_256)) { + key_cipher = WLAN_CRYPTO_CIPHER_AES_GMAC_256; + mmie_size = cds_get_gmac_mmie_size(); + } else { + wma_err("Invalid key cipher %d", mgmtcipherset); + return -EINVAL; + } + + /* Check if frame is invalid length */ + if (efrm - (uint8_t *)wh < sizeof(*wh) + mmie_size) { + wma_err("Invalid frame length"); + return -EINVAL; + } + + switch (key_cipher) { + case WLAN_CRYPTO_CIPHER_AES_CMAC: + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_sta_pmf_offload)) { + if (!wlan_crypto_is_mmie_valid(iface->vdev, + (uint8_t *)wh, efrm)) { + wma_debug("BC/MC MIC error or MMIE not present, dropping the frame"); + return -EINVAL; + } + } + break; + case WLAN_CRYPTO_CIPHER_AES_GMAC: + case WLAN_CRYPTO_CIPHER_AES_GMAC_256: + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_gmac_offload_support)) { + if (!wlan_crypto_is_mmie_valid(iface->vdev, + (uint8_t *)wh, efrm)) { + wma_debug("BC/MC GMAC MIC error or MMIE not present, dropping the frame"); + return -EINVAL; + } + } + break; + default: + wma_err("Invalid key_type %d", key_cipher); + return -EINVAL; + } + + qdf_nbuf_trim_tail(wbuf, mmie_size); + + return 0; +} + +/** + * wma_process_rmf_frame() - process rmf frame + * @wma_handle: wma handle + * @iface: txrx node + * @wh: 80211 frame + * @rx_pkt: rx packet + * @wbuf: Buffer + * + * Return: 0 for success or error code + */ +static +int wma_process_rmf_frame(tp_wma_handle wma_handle, + struct wma_txrx_node *iface, + struct ieee80211_frame *wh, + cds_pkt_t *rx_pkt, + qdf_nbuf_t wbuf) +{ + uint8_t *orig_hdr; + uint8_t *ccmp; + uint8_t mic_len, hdr_len, pdev_id; + QDF_STATUS status; + + if ((wh)->i_fc[1] & IEEE80211_FC1_WEP) { + if (QDF_IS_ADDR_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + wma_err("Encrypted BC/MC frame dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + if (iface->type == WMI_VDEV_TYPE_NDI || + iface->type == WMI_VDEV_TYPE_NAN) { + hdr_len = IEEE80211_CCMP_HEADERLEN; + mic_len = IEEE80211_CCMP_MICLEN; + } else { + pdev_id = + wlan_objmgr_pdev_get_pdev_id(wma_handle->pdev); + status = mlme_get_peer_mic_len(wma_handle->psoc, + pdev_id, wh->i_addr2, + &mic_len, &hdr_len); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get mic hdr and length"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + } + + if (qdf_nbuf_len(wbuf) < (sizeof(*wh) + hdr_len + mic_len)) { + wma_err("Buffer length less than expected %d", + (int)qdf_nbuf_len(wbuf)); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + orig_hdr = (uint8_t *) qdf_nbuf_data(wbuf); + /* Pointer to head of CCMP header */ + ccmp = orig_hdr + sizeof(*wh); + if (wma_is_ccmp_pn_replay_attack(wma_handle, wh, ccmp)) { + wma_err_rl("Dropping the frame"); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + /* Strip privacy headers (and trailer) + * for a received frame + */ + qdf_mem_move(orig_hdr + + hdr_len, wh, + sizeof(*wh)); + qdf_nbuf_pull_head(wbuf, + hdr_len); + qdf_nbuf_trim_tail(wbuf, mic_len); + /* + * CCMP header has been pulled off + * reinitialize the start pointer of mac header + * to avoid accessing incorrect address + */ + wh = (struct ieee80211_frame *) qdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_hdr_ptr = + qdf_nbuf_data(wbuf); + rx_pkt->pkt_meta.mpdu_len = qdf_nbuf_len(wbuf); + rx_pkt->pkt_buf = wbuf; + if (rx_pkt->pkt_meta.mpdu_len >= + rx_pkt->pkt_meta.mpdu_hdr_len) { + rx_pkt->pkt_meta.mpdu_data_len = + rx_pkt->pkt_meta.mpdu_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + } else { + wma_err("mpdu len %d less than hdr %d, dropping frame", + rx_pkt->pkt_meta.mpdu_len, + rx_pkt->pkt_meta.mpdu_hdr_len); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + + if (rx_pkt->pkt_meta.mpdu_data_len > MAX_MGMT_MPDU_LEN) { + wma_err("Data Len %d greater than max, dropping frame", + rx_pkt->pkt_meta.mpdu_data_len); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + rx_pkt->pkt_meta.mpdu_data_ptr = + rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + wma_debug("BSSID: "QDF_MAC_ADDR_FMT" tsf_delta: %u", + QDF_MAC_ADDR_REF(wh->i_addr3), + rx_pkt->pkt_meta.tsf_delta); + } else { + if (QDF_IS_ADDR_BROADCAST(wh->i_addr1) || + IEEE80211_IS_MULTICAST(wh->i_addr1)) { + if (0 != wma_process_bip(wma_handle, iface, wh, wbuf)) { + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + } else { + wma_err_rl("Rx unprotected unicast mgmt frame"); + rx_pkt->pkt_meta.dpuFeedback = + DPU_FEEDBACK_UNPROTECTED_ERROR; + } + } + return 0; +} + +/** + * wma_get_peer_pmf_status() - Get the PMF capability of peer + * @wma: wma handle + * @peer_mac: peer mac addr + * + * Return: True if PMF is enabled, false otherwise. + */ +static bool +wma_get_peer_pmf_status(tp_wma_handle wma, uint8_t *peer_mac) +{ + struct wlan_objmgr_peer *peer; + bool is_pmf_enabled; + + if (!peer_mac) { + wma_err("peer_mac is NULL"); + return false; + } + + peer = wlan_objmgr_get_peer(wma->psoc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + peer_mac, WLAN_LEGACY_WMA_ID); + if (!peer) { + wma_debug("Peer of peer_mac " QDF_MAC_ADDR_FMT " not found", + QDF_MAC_ADDR_REF(peer_mac)); + return false; + } + is_pmf_enabled = mlme_get_peer_pmf_status(peer); + wlan_objmgr_peer_release_ref(peer, WLAN_LEGACY_WMA_ID); + wma_nofl_debug("get is_pmf_enabled %d for "QDF_MAC_ADDR_FMT, + is_pmf_enabled, QDF_MAC_ADDR_REF(peer_mac)); + + return is_pmf_enabled; +} + +/** + * wma_check_and_process_rmf_frame() - Process the frame if it is of rmf type + * @wma_handle: wma handle + * @vdev_id: vdev id + * @wh: double pointer to 802.11 frame header which will be updated if the + * frame is of rmf type. + * @rx_pkt: rx packet + * @buf: Buffer + * + * Process the frame as rmf frame only if both DUT and peer are of PMF capable + * + * Return: 0 for success or error code + */ +static int +wma_check_and_process_rmf_frame(tp_wma_handle wma_handle, + uint8_t vdev_id, + struct ieee80211_frame **wh, + cds_pkt_t *rx_pkt, + qdf_nbuf_t buf) +{ + int status; + struct wma_txrx_node *iface; + struct ieee80211_frame *hdr = *wh; + + iface = &(wma_handle->interfaces[vdev_id]); + if ((iface->type != WMI_VDEV_TYPE_NDI && + iface->type != WMI_VDEV_TYPE_NAN) && !iface->rmfEnabled) + return 0; + + if (qdf_is_macaddr_group((struct qdf_mac_addr *)(hdr->i_addr1)) || + qdf_is_macaddr_broadcast((struct qdf_mac_addr *)(hdr->i_addr1)) || + wma_get_peer_pmf_status(wma_handle, hdr->i_addr2) || + ((iface->type == WMI_VDEV_TYPE_NDI || + iface->type == WMI_VDEV_TYPE_NAN) && + (hdr->i_fc[1] & IEEE80211_FC1_WEP))) { + status = wma_process_rmf_frame(wma_handle, iface, hdr, + rx_pkt, buf); + if (status) + return status; + /* + * CCMP header might have been pulled off reinitialize the + * start pointer of mac header + */ + *wh = (struct ieee80211_frame *)qdf_nbuf_data(buf); + } + + return 0; +} + +/** + * wma_is_pkt_drop_candidate() - check if the mgmt frame should be dropped + * @wma_handle: wma handle + * @peer_addr: peer MAC address + * @bssid: BSSID Address + * @subtype: Management frame subtype + * + * This function is used to decide if a particular management frame should be + * dropped to prevent DOS attack. Timestamp is used to decide the DOS attack. + * + * Return: true if the packet should be dropped and false otherwise + */ +static bool wma_is_pkt_drop_candidate(tp_wma_handle wma_handle, + uint8_t *peer_addr, uint8_t *bssid, + uint8_t subtype) +{ + bool should_drop = false; + uint8_t nan_addr[] = {0x50, 0x6F, 0x9A, 0x01, 0x00, 0x00}; + + /* Drop the beacons from NAN device */ + if ((subtype == MGMT_SUBTYPE_BEACON) && + (!qdf_mem_cmp(nan_addr, bssid, NAN_CLUSTER_ID_BYTES))) { + should_drop = true; + goto end; + } +end: + return should_drop; +} + +#define RATE_LIMIT 16 + +int wma_form_rx_packet(qdf_nbuf_t buf, + struct mgmt_rx_event_params *mgmt_rx_params, + cds_pkt_t *rx_pkt) +{ + uint8_t vdev_id = WMA_INVALID_VDEV_ID; + struct ieee80211_frame *wh; + uint8_t mgt_type, mgt_subtype; + int status; + tp_wma_handle wma_handle = (tp_wma_handle) + cds_get_context(QDF_MODULE_ID_WMA); + static uint8_t limit_prints_invalid_len = RATE_LIMIT - 1; + static uint8_t limit_prints_load_unload = RATE_LIMIT - 1; + static uint8_t limit_prints_recovery = RATE_LIMIT - 1; + + if (!wma_handle) { + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + if (!mgmt_rx_params) { + limit_prints_invalid_len++; + if (limit_prints_invalid_len == RATE_LIMIT) { + wma_debug("mgmt rx params is NULL"); + limit_prints_invalid_len = 0; + } + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + if (cds_is_load_or_unload_in_progress()) { + limit_prints_load_unload++; + if (limit_prints_load_unload == RATE_LIMIT) { + wma_debug("Load/Unload in progress"); + limit_prints_load_unload = 0; + } + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + if (cds_is_driver_recovering()) { + limit_prints_recovery++; + if (limit_prints_recovery == RATE_LIMIT) { + wma_debug("Recovery in progress"); + limit_prints_recovery = 0; + } + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + if (cds_is_driver_in_bad_state()) { + limit_prints_recovery++; + if (limit_prints_recovery == RATE_LIMIT) { + wma_debug("Driver in bad state"); + limit_prints_recovery = 0; + } + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + /* + * Fill in meta information needed by pe/lim + * TODO: Try to maintain rx metainfo as part of skb->data. + */ + rx_pkt->pkt_meta.frequency = mgmt_rx_params->chan_freq; + rx_pkt->pkt_meta.scan_src = mgmt_rx_params->flags; + + /* + * Get the rssi value from the current snr value + * using standard noise floor of -96. + */ + rx_pkt->pkt_meta.rssi = mgmt_rx_params->snr + + WMA_NOISE_FLOOR_DBM_DEFAULT; + rx_pkt->pkt_meta.snr = mgmt_rx_params->snr; + + /* If absolute rssi is available from firmware, use it */ + if (mgmt_rx_params->rssi != 0) + rx_pkt->pkt_meta.rssi_raw = mgmt_rx_params->rssi; + else + rx_pkt->pkt_meta.rssi_raw = rx_pkt->pkt_meta.rssi; + + + /* + * FIXME: Assigning the local timestamp as hw timestamp is not + * available. Need to see if pe/lim really uses this data. + */ + rx_pkt->pkt_meta.timestamp = (uint32_t) jiffies; + rx_pkt->pkt_meta.mpdu_hdr_len = sizeof(struct ieee80211_frame); + rx_pkt->pkt_meta.mpdu_len = mgmt_rx_params->buf_len; + + /* + * The buf_len should be at least 802.11 header len + */ + if (mgmt_rx_params->buf_len < rx_pkt->pkt_meta.mpdu_hdr_len) { + wma_err("MPDU Len %d lesser than header len %d", + mgmt_rx_params->buf_len, + rx_pkt->pkt_meta.mpdu_hdr_len); + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + rx_pkt->pkt_meta.mpdu_data_len = mgmt_rx_params->buf_len - + rx_pkt->pkt_meta.mpdu_hdr_len; + + rx_pkt->pkt_meta.roamCandidateInd = 0; + + wh = (struct ieee80211_frame *)qdf_nbuf_data(buf); + + /* + * If the mpdu_data_len is greater than Max (2k), drop the frame + */ + if (rx_pkt->pkt_meta.mpdu_data_len > MAX_MGMT_MPDU_LEN) { + wma_err("Data Len %d greater than max, dropping frame from "QDF_MAC_ADDR_FMT, + rx_pkt->pkt_meta.mpdu_data_len, + QDF_MAC_ADDR_REF(wh->i_addr3)); + qdf_nbuf_free(buf); + qdf_mem_free(rx_pkt); + return -EINVAL; + } + + rx_pkt->pkt_meta.mpdu_hdr_ptr = qdf_nbuf_data(buf); + rx_pkt->pkt_meta.mpdu_data_ptr = rx_pkt->pkt_meta.mpdu_hdr_ptr + + rx_pkt->pkt_meta.mpdu_hdr_len; + rx_pkt->pkt_meta.tsf_delta = mgmt_rx_params->tsf_delta; + rx_pkt->pkt_buf = buf; + rx_pkt->pkt_meta.pkt_qdf_buf = buf; + + /* If it is a beacon/probe response, save it for future use */ + mgt_type = (wh)->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + mgt_subtype = (wh)->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + if (mgt_type == IEEE80211_FC0_TYPE_MGT && + (mgt_subtype == MGMT_SUBTYPE_DISASSOC || + mgt_subtype == MGMT_SUBTYPE_DEAUTH || + mgt_subtype == MGMT_SUBTYPE_ACTION)) { + if (wma_find_vdev_id_by_bssid(wma_handle, wh->i_addr3, + &vdev_id) == QDF_STATUS_SUCCESS) { + status = wma_check_and_process_rmf_frame(wma_handle, + vdev_id, + &wh, + rx_pkt, + buf); + if (status) + return status; + } else if (wma_find_vdev_id_by_addr(wma_handle, wh->i_addr1, + &vdev_id) == QDF_STATUS_SUCCESS) { + status = wma_check_and_process_rmf_frame(wma_handle, + vdev_id, + &wh, + rx_pkt, + buf); + if (status) + return status; + } else if (mgt_subtype == MGMT_SUBTYPE_ACTION) { + /* NAN Action frame */ + vdev_id = wlan_nan_get_vdev_id_from_bssid( + wma_handle->pdev, + wh->i_addr3, + WLAN_ACTION_OUI_ID); + + if (vdev_id != WMA_INVALID_VDEV_ID) { + status = wma_check_and_process_rmf_frame( + wma_handle, + vdev_id, &wh, + rx_pkt, buf); + if (status) + return status; + } + } + } + + rx_pkt->pkt_meta.session_id = + (vdev_id == WMA_INVALID_VDEV_ID ? 0 : vdev_id); + + if (mgt_type == IEEE80211_FC0_TYPE_MGT && + (mgt_subtype == MGMT_SUBTYPE_BEACON || + mgt_subtype == MGMT_SUBTYPE_PROBE_RESP)) { + if (mgmt_rx_params->buf_len <= + (sizeof(struct ieee80211_frame) + + offsetof(struct wlan_bcn_frame, ie))) { + wma_debug("Dropping frame from "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(wh->i_addr3)); + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + } + + if (wma_is_pkt_drop_candidate(wma_handle, wh->i_addr2, wh->i_addr3, + mgt_subtype)) { + cds_pkt_return_packet(rx_pkt); + return -EINVAL; + } + wma_mgmt_pktdump_rx_handler(mgmt_rx_params, rx_pkt, + wma_handle, mgt_type, mgt_subtype); + + return 0; +} + +/** + * wma_mem_endianness_based_copy() - does memory copy from src to dst + * @dst: destination address + * @src: source address + * @size: size to be copied + * + * This function copies the memory of size passed from source + * address to destination address. + * + * Return: Nothing + */ +#ifdef BIG_ENDIAN_HOST +static void wma_mem_endianness_based_copy( + uint8_t *dst, uint8_t *src, uint32_t size) +{ + /* + * For big endian host, copy engine byte_swap is enabled + * But the rx mgmt frame buffer content is in network byte order + * Need to byte swap the mgmt frame buffer content - so when + * copy engine does byte_swap - host gets buffer content in the + * correct byte order. + */ + + uint32_t i; + uint32_t *destp, *srcp; + + destp = (uint32_t *) dst; + srcp = (uint32_t *) src; + for (i = 0; i < (roundup(size, sizeof(uint32_t)) / 4); i++) { + *destp = cpu_to_le32(*srcp); + destp++; + srcp++; + } +} +#else +static void wma_mem_endianness_based_copy( + uint8_t *dst, uint8_t *src, uint32_t size) +{ + qdf_mem_copy(dst, src, size); +} +#endif + +#define RESERVE_BYTES 100 +/** + * wma_mgmt_rx_process() - process management rx frame. + * @handle: wma handle + * @data: rx data + * @data_len: data length + * + * Return: 0 for success or error code + */ +static int wma_mgmt_rx_process(void *handle, uint8_t *data, + uint32_t data_len) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct mgmt_rx_event_params *mgmt_rx_params; + struct wlan_objmgr_psoc *psoc; + uint8_t *bufp; + qdf_nbuf_t wbuf; + QDF_STATUS status; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + mgmt_rx_params = qdf_mem_malloc(sizeof(*mgmt_rx_params)); + if (!mgmt_rx_params) { + return -ENOMEM; + } + + if (wmi_extract_mgmt_rx_params(wma_handle->wmi_handle, + data, mgmt_rx_params, &bufp) != QDF_STATUS_SUCCESS) { + wma_err_rl("Extraction of mgmt rx params failed"); + qdf_mem_free(mgmt_rx_params); + return -EINVAL; + } + + if (mgmt_rx_params->buf_len > data_len || + !mgmt_rx_params->buf_len || + !bufp) { + wma_err_rl("Invalid data_len %u, buf_len %u bufp %pK", + data_len, mgmt_rx_params->buf_len, bufp); + qdf_mem_free(mgmt_rx_params); + return -EINVAL; + } + + if (!mgmt_rx_params->chan_freq) { + /* + * It indicates that FW is legacy and is operating on + * channel numbers and it also indicates that BAND_6G support + * is not there as BAND_6G works only on frequencies and channel + * numbers can be treated as unique. + */ + mgmt_rx_params->chan_freq = wlan_reg_legacy_chan_to_freq( + wma_handle->pdev, + mgmt_rx_params->channel); + } + + mgmt_rx_params->pdev_id = 0; + mgmt_rx_params->rx_params = NULL; + + /* + * Allocate the memory for this rx packet, add extra 100 bytes for:- + * + * 1. Filling the missing RSN capabilities by some APs, which fill the + * RSN IE length as extra 2 bytes but dont fill the IE data with + * capabilities, resulting in failure in unpack core due to length + * mismatch. Check sir_validate_and_rectify_ies for more info. + * + * 2. In the API wma_process_rmf_frame(), the driver trims the CCMP + * header by overwriting the IEEE header to memory occupied by CCMP + * header, but an overflow is possible if the memory allocated to + * frame is less than the sizeof(struct ieee80211_frame) +CCMP + * HEADER len, so allocating 100 bytes would solve this issue too. + * + * 3. CCMP header is pointing to orig_hdr + + * sizeof(struct ieee80211_frame) which could also result in OOB + * access, if the data len is less than + * sizeof(struct ieee80211_frame), allocating extra bytes would + * result in solving this issue too. + */ + wbuf = qdf_nbuf_alloc(NULL, roundup(mgmt_rx_params->buf_len + + RESERVE_BYTES, + 4), 0, 4, false); + if (!wbuf) { + qdf_mem_free(mgmt_rx_params); + return -ENOMEM; + } + + qdf_nbuf_put_tail(wbuf, mgmt_rx_params->buf_len); + qdf_nbuf_set_protocol(wbuf, ETH_P_CONTROL); + + qdf_mem_zero(((uint8_t *)qdf_nbuf_data(wbuf) + mgmt_rx_params->buf_len), + (roundup(mgmt_rx_params->buf_len + RESERVE_BYTES, 4) - + mgmt_rx_params->buf_len)); + + wma_mem_endianness_based_copy(qdf_nbuf_data(wbuf), + bufp, mgmt_rx_params->buf_len); + + psoc = (struct wlan_objmgr_psoc *) + wma_handle->psoc; + if (!psoc) { + wma_err("psoc ctx is NULL"); + qdf_nbuf_free(wbuf); + qdf_mem_free(mgmt_rx_params); + return -EINVAL; + } + + status = mgmt_txrx_rx_handler(psoc, wbuf, mgmt_rx_params); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(mgmt_rx_params); + return -EINVAL; + } + + qdf_mem_free(mgmt_rx_params); + return 0; +} + +/** + * wma_de_register_mgmt_frm_client() - deregister management frame + * + * This function deregisters the event handler registered for + * WMI_MGMT_RX_EVENTID. + * + * Return: QDF status + */ +QDF_STATUS wma_de_register_mgmt_frm_client(void) +{ + tp_wma_handle wma_handle = (tp_wma_handle) + cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_NULL_VALUE; + +#ifdef QCA_WIFI_FTM + if (cds_get_conparam() == QDF_GLOBAL_FTM_MODE) + return QDF_STATUS_SUCCESS; +#endif + + if (wmi_unified_unregister_event_handler(wma_handle->wmi_handle, + wmi_mgmt_rx_event_id) != 0) { + wma_err("Failed to Unregister rx mgmt handler with wmi"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_register_roaming_callbacks() - Register roaming callbacks + * @csr_roam_auth_event_handle_cb: CSR callback routine pointer + * @pe_roam_synch_cb: PE roam synch callback routine pointer + * + * Register the SME and PE callback routines with WMA for + * handling roaming + * + * Return: Success or Failure Status + */ +QDF_STATUS wma_register_roaming_callbacks( + QDF_STATUS (*csr_roam_auth_event_handle_cb)(struct mac_context *mac, + uint8_t vdev_id, + struct qdf_mac_addr bssid, + uint32_t akm), + pe_roam_synch_fn_t pe_roam_synch_cb, + QDF_STATUS (*pe_disconnect_cb) (struct mac_context *mac, + uint8_t vdev_id, + uint8_t *deauth_disassoc_frame, + uint16_t deauth_disassoc_frame_len, + uint16_t reason_code), + set_ies_fn_t pe_roam_set_ie_cb) +{ + + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_FAILURE; + + wma->csr_roam_auth_event_handle_cb = csr_roam_auth_event_handle_cb; + wma->pe_roam_synch_cb = pe_roam_synch_cb; + wma->pe_disconnect_cb = pe_disconnect_cb; + wma->pe_roam_set_ie_cb = pe_roam_set_ie_cb; + wma_debug("Registered roam synch callbacks with WMA successfully"); + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * wma_register_mgmt_frm_client() - register management frame callback + * + * This function registers event handler for WMI_MGMT_RX_EVENTID. + * + * Return: QDF status + */ +QDF_STATUS wma_register_mgmt_frm_client(void) +{ + tp_wma_handle wma_handle = (tp_wma_handle) + cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_NULL_VALUE; + + if (wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_mgmt_rx_event_id, + wma_mgmt_rx_process, + WMA_RX_WORK_CTX) != 0) { + wma_err("Failed to register rx mgmt handler with wmi"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_register_packetdump_callback() - stores tx and rx mgmt packet dump + * callback handler + * @tx_cb: tx mgmt packetdump cb + * @rx_cb: rx mgmt packetdump cb + * + * This function is used to store tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_register_packetdump_callback( + ol_txrx_pktdump_cb tx_cb, + ol_txrx_pktdump_cb rx_cb) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return; + + wma_handle->wma_mgmt_tx_packetdump_cb = tx_cb; + wma_handle->wma_mgmt_rx_packetdump_cb = rx_cb; +} + +/** + * wma_deregister_packetdump_callback() - removes tx and rx mgmt packet dump + * callback handler + * + * This function is used to remove tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_deregister_packetdump_callback(void) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return; + + wma_handle->wma_mgmt_tx_packetdump_cb = NULL; + wma_handle->wma_mgmt_rx_packetdump_cb = NULL; +} + +QDF_STATUS wma_mgmt_unified_cmd_send(struct wlan_objmgr_vdev *vdev, + qdf_nbuf_t buf, uint32_t desc_id, + void *mgmt_tx_params) +{ + tp_wma_handle wma_handle; + int ret; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct wmi_mgmt_params *mgmt_params = + (struct wmi_mgmt_params *)mgmt_tx_params; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!mgmt_params) { + wma_err("mgmt_params ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + mgmt_params->desc_id = desc_id; + + if (!vdev) { + wma_err("vdev ptr passed is NULL"); + return QDF_STATUS_E_INVAL; + } + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return QDF_STATUS_E_INVAL; + + if (wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_mgmt_tx_wmi)) { + status = wmi_mgmt_unified_cmd_send(wma_handle->wmi_handle, + mgmt_params); + } else { + QDF_NBUF_CB_MGMT_TXRX_DESC_ID(buf) + = mgmt_params->desc_id; + + ret = cdp_mgmt_send_ext(soc, mgmt_params->vdev_id, buf, + mgmt_params->tx_type, + mgmt_params->use_6mbps, + mgmt_params->chanfreq); + status = qdf_status_from_os_return(ret); + } + + if (status != QDF_STATUS_SUCCESS) { + wma_err("mgmt tx failed"); + return status; + } + + return QDF_STATUS_SUCCESS; +} + +#ifndef CONFIG_HL_SUPPORT +void wma_mgmt_nbuf_unmap_cb(struct wlan_objmgr_pdev *pdev, + qdf_nbuf_t buf) +{ + struct wlan_objmgr_psoc *psoc; + qdf_device_t dev; + + if (!buf) + return; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + wma_err("Psoc handle NULL"); + return; + } + + dev = wlan_psoc_get_qdf_dev(psoc); + qdf_nbuf_unmap_single(dev, buf, QDF_DMA_TO_DEVICE); +} + +QDF_STATUS wma_mgmt_frame_fill_peer_cb(struct wlan_objmgr_peer *peer, + qdf_nbuf_t buf) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + + psoc = wlan_peer_get_psoc(peer); + if (!psoc) { + wma_err("Psoc handle NULL"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_objmgr_get_pdev_by_id((struct wlan_objmgr_psoc *)psoc, + wlan_peer_get_pdev_id(peer), + WLAN_LEGACY_WMA_ID); + if (!pdev) { + wma_err("Pdev handle NULL"); + return QDF_STATUS_E_INVAL; + } + wma_mgmt_nbuf_unmap_cb(pdev, buf); + wlan_objmgr_pdev_release_ref(pdev, WLAN_LEGACY_WMA_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_update_edca_pifs_param(WMA_HANDLE handle, + struct edca_pifs_vparam *edca_pifs_param) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + QDF_STATUS status; + + status = wmi_unified_update_edca_pifs_param(wma_handle->wmi_handle, + edca_pifs_param); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to set EDCA/PIFS Parameters"); + + return status; +} +#endif + +QDF_STATUS +wma_update_bss_peer_phy_mode(struct wlan_channel *des_chan, + struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_peer *bss_peer; + enum wlan_phymode old_peer_phymode, new_phymode; + tSirNwType nw_type; + struct vdev_mlme_obj *mlme_obj; + + bss_peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_LEGACY_WMA_ID); + if (!bss_peer) { + wma_err("not able to find bss peer for vdev %d", + wlan_vdev_get_id(vdev)); + return QDF_STATUS_E_INVAL; + } + + old_peer_phymode = wlan_peer_get_phymode(bss_peer); + + if (WLAN_REG_IS_24GHZ_CH_FREQ(des_chan->ch_freq)) { + if (des_chan->ch_phymode == WLAN_PHYMODE_11B || + old_peer_phymode == WLAN_PHYMODE_11B) + nw_type = eSIR_11B_NW_TYPE; + else + nw_type = eSIR_11G_NW_TYPE; + } else { + nw_type = eSIR_11A_NW_TYPE; + } + + new_phymode = wma_peer_phymode(nw_type, STA_ENTRY_PEER, + IS_WLAN_PHYMODE_HT(old_peer_phymode), + des_chan->ch_width, + IS_WLAN_PHYMODE_VHT(old_peer_phymode), + IS_WLAN_PHYMODE_HE(old_peer_phymode), + wma_is_phymode_eht(old_peer_phymode)); + + if (new_phymode == old_peer_phymode) { + wma_debug("Ignore update, old %d and new %d phymode are same, vdev_id : %d", + old_peer_phymode, new_phymode, + wlan_vdev_get_id(vdev)); + wlan_objmgr_peer_release_ref(bss_peer, WLAN_LEGACY_WMA_ID); + return QDF_STATUS_SUCCESS; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("not able to get mlme_obj"); + wlan_objmgr_peer_release_ref(bss_peer, WLAN_LEGACY_WMA_ID); + return QDF_STATUS_E_INVAL; + } + + wlan_peer_obj_lock(bss_peer); + wlan_peer_set_phymode(bss_peer, new_phymode); + wlan_peer_obj_unlock(bss_peer); + + wlan_objmgr_peer_release_ref(bss_peer, WLAN_LEGACY_WMA_ID); + + mlme_obj->mgmt.generic.phy_mode = wmi_host_to_fw_phymode(new_phymode); + des_chan->ch_phymode = new_phymode; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_send_ies_for_roam_invoke(struct wlan_objmgr_vdev *vdev, uint16_t dot11_mode) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + enum QDF_OPMODE op_mode; + QDF_STATUS status; + uint8_t vdev_id; + + if (!wma) + return QDF_STATUS_E_FAILURE; + + vdev_id = wlan_vdev_get_id(vdev); + op_mode = wlan_vdev_mlme_get_opmode(vdev); + + status = wma->pe_roam_set_ie_cb(wma->mac_context, vdev_id, dot11_mode, + op_mode); + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_nan_datapath.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_nan_datapath.c new file mode 100644 index 0000000000..b5ec49dfdd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_nan_datapath.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_nan_datapath.c + * + * WMA NAN Data path API implementation + */ + +#include "wma.h" +#include "wma_api.h" +#include "wmi_unified_api.h" +#include "wmi_unified.h" +#include "wma_nan_datapath.h" +#include "wma_internal.h" +#include "cds_utils.h" +#include "cdp_txrx_peer_ops.h" +#include "cdp_txrx_tx_delay.h" +#include "cdp_txrx_misc.h" +#include + +QDF_STATUS wma_add_sta_ndi_mode(tp_wma_handle wma, tpAddStaParams add_sta) +{ + enum ol_txrx_peer_state state = OL_TXRX_PEER_STATE_CONN; + uint8_t pdev_id = WMI_PDEV_ID_SOC; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + struct wma_txrx_node *iface; + + iface = &wma->interfaces[add_sta->smesessionId]; + wma_debug("vdev: %d, peer_mac_addr: "QDF_MAC_ADDR_FMT, + add_sta->smesessionId, QDF_MAC_ADDR_REF(add_sta->staMac)); + + if (cdp_find_peer_exist_on_vdev(soc, add_sta->smesessionId, + add_sta->staMac)) { + wma_err("NDI peer already exists, peer_addr "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = QDF_STATUS_E_EXISTS; + goto send_rsp; + } + + /* + * The code above only checks the peer existence on its own vdev. + * Need to check whether the peer exists on other vDevs because firmware + * can't create the peer if the peer with same MAC address already + * exists on the pDev. As this peer belongs to other vDevs, just return + * here. + */ + if (cdp_find_peer_exist(soc, pdev_id, add_sta->staMac)) { + wma_err("peer exists on other vdev with peer_addr "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = QDF_STATUS_E_EXISTS; + goto send_rsp; + } + + status = wma_create_peer(wma, add_sta->staMac, + WMI_PEER_TYPE_NAN_DATA, add_sta->smesessionId, + NULL, false); + if (status != QDF_STATUS_SUCCESS) { + wma_err("Failed to create peer for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = status; + goto send_rsp; + } + + if (!cdp_find_peer_exist_on_vdev(soc, add_sta->smesessionId, + add_sta->staMac)) { + wma_err("Failed to find peer handle using peer mac "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(add_sta->staMac)); + add_sta->status = QDF_STATUS_E_FAILURE; + wma_remove_peer(wma, add_sta->staMac, add_sta->smesessionId, + false); + goto send_rsp; + } + + wma_debug("Moving peer "QDF_MAC_ADDR_FMT" to state %d", + QDF_MAC_ADDR_REF(add_sta->staMac), state); + cdp_peer_state_update(soc, add_sta->staMac, state); + + add_sta->nss = iface->nss; + add_sta->status = QDF_STATUS_SUCCESS; +send_rsp: + status = add_sta->status; + wma_debug("Sending add sta rsp to umac (mac:"QDF_MAC_ADDR_FMT", status:%d)", + QDF_MAC_ADDR_REF(add_sta->staMac), add_sta->status); + + wma_send_msg_high_priority(wma, WMA_ADD_STA_RSP, (void *)add_sta, 0); + + return status; +} + +QDF_STATUS wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + QDF_STATUS status; + + status = wma_remove_peer(wma, del_sta->staMac, + del_sta->smesessionId, false); + del_sta->status = QDF_STATUS_SUCCESS; + + if (del_sta->respReqd) { + wma_debug("Sending del rsp to umac (status: %d)", + del_sta->status); + wma_send_msg_high_priority(wma, WMA_DELETE_STA_RSP, del_sta, 0); + } else { + wma_debug("NDI Del Sta resp not needed"); + qdf_mem_free(del_sta); + } + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_nan_datapath.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_nan_datapath.h new file mode 100644 index 0000000000..d5ae1c241d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_nan_datapath.h @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_nan_datapath.h + * + * WMA NAN Data path API specification + */ + +#ifndef __WMA_NAN_DATAPATH_H +#define __WMA_NAN_DATAPATH_H + +#include +#include +#include "wma.h" +#include "sir_api.h" +#include "sme_nan_datapath.h" + +static inline int wma_ndp_wow_event_callback(void *handle, void *event, + uint32_t len, uint32_t event_id) +{ + return 0; +} + +static inline uint32_t wma_ndp_get_eventid_from_tlvtag(uint32_t tag) +{ + return 0; +} + +#ifdef WLAN_FEATURE_NAN +#define WMA_IS_VDEV_IN_NDI_MODE(intf, vdev_id) \ + (WMI_VDEV_TYPE_NDI == intf[vdev_id].type) + +/** + * wma_add_sta_ndi_mode() - Process ADD_STA for NaN Data path + * @wma: wma handle + * @add_sta: Parameters of ADD_STA command + * + * Sends CREATE_PEER command to firmware + * Return: QDF status + */ +QDF_STATUS wma_add_sta_ndi_mode(tp_wma_handle wma, tpAddStaParams add_sta); + +/** + * wma_update_hdd_cfg_ndp() - Update target device NAN datapath capability + * @wma_handle: pointer to WMA context + * @tgt_cfg: Pointer to target configuration data structure + * + * Return: none + */ +static inline void wma_update_hdd_cfg_ndp(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ + tgt_cfg->nan_datapath_enabled = wma_handle->nan_datapath_enabled; +} + +/** + * wma_delete_sta_req_ndi_mode() - Process DEL_STA request for NDI data peer + * @wma: WMA context + * @del_sta: DEL_STA parameters from LIM + * + * Removes wma/txrx peer entry for the NDI STA + * + * Returns: QDF_STATUS_SUCCESS if peer deletion is successful + */ +QDF_STATUS wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta); + +/** + * wma_is_ndi_active() - Determines of the nan data iface is active + * @wma_handle: handle to wma context + * + * Returns: true if ndi active, flase otherwise + */ +static inline bool wma_is_ndi_active(tp_wma_handle wma_handle) +{ + int i; + + for (i = 0; i < wma_handle->max_bssid; i++) { + if (wma_handle->interfaces[i].type == WMI_VDEV_TYPE_NDI && + wma_handle->interfaces[i].peer_count > 0) + return true; + } + return false; +} +#else /* WLAN_FEATURE_NAN */ +#define WMA_IS_VDEV_IN_NDI_MODE(intf, vdev_id) (false) +static inline void wma_update_hdd_cfg_ndp(tp_wma_handle wma_handle, + struct wma_tgt_cfg *tgt_cfg) +{ + return; +} + +static inline +QDF_STATUS wma_delete_sta_req_ndi_mode(tp_wma_handle wma, + tpDeleteStaParams del_sta) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS wma_add_sta_ndi_mode(tp_wma_handle wma, + tpAddStaParams add_sta) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline bool wma_is_ndi_active(tp_wma_handle wma_handle) { return false; } +#endif /* WLAN_FEATURE_NAN */ + +#endif /* __WMA_NAN_DATAPATH_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_ocb.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_ocb.c new file mode 100644 index 0000000000..6770c40cf6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_ocb.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_ocb.c + * + * WLAN Host Device Driver 802.11p OCB implementation + */ + +#include "wma_ocb.h" +#include "cds_utils.h" +#include "cds_api.h" +#include "wlan_ocb_ucfg_api.h" +#include "lim_utils.h" +#include "../../core/src/vdev_mgr_ops.h" + +/** + * wma_start_ocb_vdev() - start OCB vdev + * @config: ocb channel config + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS wma_start_ocb_vdev(struct ocb_config *config) +{ + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wlan_objmgr_vdev *vdev; + struct vdev_mlme_obj *mlme_obj; + struct wlan_channel *des_chan; + uint8_t dot11_mode; + + vdev = wma->interfaces[config->vdev_id].vdev; + if (!vdev) { + wma_err("vdev is NULL"); + return QDF_STATUS_E_FAILURE; + } + + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + wma_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + des_chan = vdev->vdev_mlme.des_chan; + + des_chan->ch_freq = config->channels[0].chan_freq; + if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq)) + dot11_mode = MLME_DOT11_MODE_11G; + else + dot11_mode = MLME_DOT11_MODE_11A; + des_chan->ch_ieee = + wlan_reg_freq_to_chan(wma->pdev, des_chan->ch_freq); + + status = lim_set_ch_phy_mode(vdev, dot11_mode); + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + mlme_obj->mgmt.chainmask_info.num_rx_chain = 2; + mlme_obj->mgmt.chainmask_info.num_tx_chain = 2; + + status = wma_vdev_pre_start(config->vdev_id, false); + if (status != QDF_STATUS_SUCCESS) + return status; + + status = vdev_mgr_start_send(mlme_obj, false); + + return status; +} + +QDF_STATUS wma_ocb_register_callbacks(tp_wma_handle wma_handle) +{ + ucfg_ocb_register_vdev_start(wma_handle->pdev, wma_start_ocb_vdev); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_ocb.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_ocb.h new file mode 100644 index 0000000000..a6339a3dd8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_ocb.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015-2018 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_OCB_H +#define __WMA_OCB_H + +#include "wma.h" + +#ifdef WLAN_FEATURE_DSRC +/** + * wma_ocb_register_callbacks() - register WMA layer callback for OCB + * @wma_handle: wma handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS wma_ocb_register_callbacks(tp_wma_handle wma_handle); +#else +/** + * wma_ocb_register_callbacks() - register WMA layer callback for OCB + * @wma_handle: wma handle + * + * Return: QDF_STATUS_SUCCESS on success + */ +static inline QDF_STATUS wma_ocb_register_callbacks(tp_wma_handle wma_handle) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif /* __WMA_OCB_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_pasn_peer_api.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_pasn_peer_api.c new file mode 100644 index 0000000000..5fbf10688b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_pasn_peer_api.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_pasn_peer_api.c + * This file contains PASN peer related operations. + */ + +#include "wma.h" +#include "wma_api.h" +#include "wmi_unified_api.h" +#include "wmi_unified.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "wma_types.h" +#include "wma_internal.h" +#include "wma_pasn_peer_api.h" +#include "wifi_pos_pasn_api.h" +#include "wifi_pos_api.h" +#include "init_deinit_lmac.h" + +QDF_STATUS +wma_pasn_peer_remove(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id, bool no_fw_peer_delete) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct peer_delete_cmd_params del_param = {0}; + QDF_STATUS qdf_status; + uint8_t peer_vdev_id; + + if (!wma) { + wma_err("wma_handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + if (!wma_objmgr_peer_exist(wma, peer_addr->bytes, &peer_vdev_id)) { + wma_err("peer doesn't exist peer_addr " QDF_MAC_ADDR_FMT " vdevid %d", + QDF_MAC_ADDR_REF(peer_addr->bytes), vdev_id); + return QDF_STATUS_E_INVAL; + } + + if (peer_vdev_id != vdev_id) { + wma_err("peer " QDF_MAC_ADDR_FMT " is on vdev id %d but delete req on vdevid %d", + QDF_MAC_ADDR_REF(peer_addr->bytes), + peer_vdev_id, vdev_id); + return QDF_STATUS_E_INVAL; + } + + del_param.vdev_id = vdev_id; + qdf_status = wmi_unified_peer_delete_send(wma->wmi_handle, + peer_addr->bytes, + &del_param); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Peer delete could not be sent to firmware %d", + qdf_status); + qdf_status = QDF_STATUS_E_FAILURE; + } + + wma_remove_objmgr_peer(wma, wma->interfaces[vdev_id].vdev, + peer_addr->bytes); + + return qdf_status; +} + +QDF_STATUS +wma_pasn_peer_create(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *peer_addr, + uint8_t vdev_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + target_resource_config *wlan_res_cfg; + struct wlan_objmgr_peer *obj_peer; + struct wma_target_req *wma_req; + struct peer_create_rsp_params *peer_create_rsp; + struct peer_create_params param; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool is_tgt_peer_conf_supported; + + if (!wma) { + wma_err("wma_handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + wlan_res_cfg = lmac_get_tgt_res_cfg(psoc); + if (!wlan_res_cfg) { + wma_err("psoc target res cfg is null"); + return QDF_STATUS_E_INVAL; + } + + if (wma->interfaces[vdev_id].peer_count >= + wlan_res_cfg->num_peers) { + wma_err("the peer count exceeds the limit %d", + wma->interfaces[vdev_id].peer_count); + return QDF_STATUS_E_FAILURE; + } + + if (qdf_is_macaddr_group(peer_addr) || + qdf_is_macaddr_zero(peer_addr)) { + wma_err("Invalid peer address received reject it"); + return QDF_STATUS_E_FAILURE; + } + + wma_acquire_wakelock(&wma->wmi_cmd_rsp_wake_lock, + WMA_PEER_CREATE_RESPONSE_TIMEOUT); + /* + * The peer object should be created before sending the WMI peer + * create command to firmware. + */ + obj_peer = wma_create_objmgr_peer(wma, vdev_id, peer_addr->bytes, + WMI_PEER_TYPE_PASN, NULL); + if (!obj_peer) { + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + return QDF_STATUS_E_FAILURE; + } + + param.peer_addr = peer_addr->bytes; + param.peer_type = WMI_PEER_TYPE_PASN; + param.vdev_id = vdev_id; + if (wmi_unified_peer_create_send(wma->wmi_handle, + ¶m) != QDF_STATUS_SUCCESS) { + wma_err("Unable to create peer in Target"); + wlan_objmgr_peer_obj_delete(obj_peer); + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + + return QDF_STATUS_E_FAILURE; + } + + /* + * If fw doesn't advertise peer create confirm event support, + * use the legacy peer create API + */ + is_tgt_peer_conf_supported = + wlan_psoc_nif_fw_ext_cap_get(wma->psoc, + WLAN_SOC_F_PEER_CREATE_RESP); + if (!is_tgt_peer_conf_supported) { + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + return QDF_STATUS_SUCCESS; + } + + peer_create_rsp = qdf_mem_malloc(sizeof(*peer_create_rsp)); + if (!peer_create_rsp) { + wlan_objmgr_peer_obj_delete(obj_peer); + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_copy(peer_create_rsp->peer_mac.bytes, peer_addr->bytes, + QDF_MAC_ADDR_SIZE); + wma_req = wma_fill_hold_req(wma, vdev_id, WMA_PEER_CREATE_REQ, + WMA_PASN_PEER_CREATE_RESPONSE, + peer_create_rsp, + WMA_PEER_CREATE_RESPONSE_TIMEOUT); + if (!wma_req) { + wma_err("vdev:%d failed to fill peer create req", vdev_id); + wma_remove_peer_req(wma, vdev_id, WMA_PASN_PEER_CREATE_RESPONSE, + peer_addr); + wma_pasn_peer_remove(psoc, peer_addr, vdev_id, false); + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + qdf_mem_free(peer_create_rsp); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Created ranging peer peer_addr " QDF_MAC_ADDR_FMT " vdev_id %d", + QDF_MAC_ADDR_REF(peer_addr->bytes), vdev_id); + + return status; +} + +QDF_STATUS +wma_pasn_handle_peer_create_conf(tp_wma_handle wma, + struct qdf_mac_addr *peer_mac, + QDF_STATUS status, uint8_t vdev_id) +{ + struct wlan_lmac_if_wifi_pos_rx_ops *rx_ops; + struct wlan_objmgr_vdev *vdev; + enum QDF_OPMODE mode; + + if (status) + wma_pasn_peer_remove(wma->psoc, peer_mac, vdev_id, + QDF_IS_STATUS_ERROR(status)); + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("Vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + + /* + * Only in I-sta case update the wifi pos module to + * track the peer to initiate PASN authentication. + * For R-STA, return from here. + */ + if (mode != QDF_STA_MODE) { + wma_debug("PASN opmode:%d is not sta", mode); + return QDF_STATUS_SUCCESS; + } + + rx_ops = wifi_pos_get_rx_ops(wma->psoc); + if (!rx_ops || !rx_ops->wifi_pos_ranging_peer_create_rsp_cb) { + wma_err("%s is null", + !rx_ops ? "rx_ops" : "rx_ops->ranging_peer_cb"); + return QDF_STATUS_E_NULL_VALUE; + } + + rx_ops->wifi_pos_ranging_peer_create_rsp_cb(wma->psoc, vdev_id, + peer_mac, status); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_resume_vdev_delete(tp_wma_handle wma, uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct mac_context *mac = wma->mac_context; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + if (!vdev) { + wma_err("Vdev is NULL"); + return QDF_STATUS_E_NULL_VALUE; + } + + lim_pasn_peer_del_all_resp_vdev_delete_resume(mac, vdev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_pasn_peer_delete_all_complete(struct wlan_objmgr_vdev *vdev) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_target_req *req_msg; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + if (!wma) { + wma_err("wma_handle is NULL"); + return QDF_STATUS_E_FAILURE; + } + + req_msg = wma_find_remove_req_msgtype(wma, vdev_id, + WMA_PASN_PEER_DELETE_REQUEST); + if (!req_msg) { + wma_debug("vdev:%d Failed to lookup pasn peer del req", + vdev_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_mc_timer_stop(&req_msg->event_timeout); + qdf_mc_timer_destroy(&req_msg->event_timeout); + + qdf_mem_free(req_msg); + + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + + return wma_resume_vdev_delete(wma, vdev_id); +} + +QDF_STATUS +wma_delete_all_pasn_peers(tp_wma_handle wma, struct wlan_objmgr_vdev *vdev) +{ + struct wlan_lmac_if_wifi_pos_rx_ops *rx_ops; + struct wma_target_req *msg; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + rx_ops = wifi_pos_get_rx_ops(wma->psoc); + if (!rx_ops || !rx_ops->wifi_pos_vdev_delete_all_ranging_peers_cb) { + wma_err("rx_ops is NULL"); + return QDF_STATUS_E_INVAL; + } + + wma_acquire_wakelock(&wma->wmi_cmd_rsp_wake_lock, + WMA_PEER_DELETE_RESPONSE_TIMEOUT); + wma_err("Delete all ranging peers vdev:%d", + wlan_vdev_get_id(vdev)); + status = rx_ops->wifi_pos_vdev_delete_all_ranging_peers_cb(vdev); + if (QDF_IS_STATUS_ERROR(status)) { + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + wma_err("Delete all ranging peers failed"); + return status; + } + + msg = wma_fill_hold_req(wma, vdev_id, + WMA_PASN_PEER_DELETE_REQUEST, + WMA_PASN_PEER_DELETE_RESPONSE, NULL, + WMA_PEER_DELETE_RESPONSE_TIMEOUT); + if (!msg) { + wma_err("Failed to allocate request for vdev_id %d", vdev_id); + wma_remove_req(wma, vdev_id, WMA_PASN_PEER_DELETE_RESPONSE); + wma_release_wakelock(&wma->wmi_cmd_rsp_wake_lock); + wma_resume_vdev_delete(wma, vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return status; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_power.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_power.c new file mode 100644 index 0000000000..9383febaf7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_power.c @@ -0,0 +1,1732 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_power.c + * This file contains powersave related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "wma_internal.h" +#include "wlan_pmo_ucfg_api.h" + +/** + * wma_unified_modem_power_state() - set modem power state to fw + * @wmi_handle: wmi handle + * @param_value: parameter value + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_unified_modem_power_state(wmi_unified_t wmi_handle, uint32_t param_value) +{ + QDF_STATUS status; + wmi_modem_power_state_cmd_param *cmd; + wmi_buf_t buf; + uint16_t len = sizeof(*cmd); + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) + return -ENOMEM; + + cmd = (wmi_modem_power_state_cmd_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_modem_power_state_cmd_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_modem_power_state_cmd_param)); + cmd->modem_power_state = param_value; + wma_debug("Setting cmd->modem_power_state = %u", param_value); + status = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_MODEM_POWER_STATE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * wma_unified_set_sta_ps_param() - set sta power save parameter to fw + * @wmi_handle: wmi handle + * @vdev_id: vdev id + * @param: param + * @value: parameter value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_unified_set_sta_ps_param(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint32_t param, + uint32_t value) +{ + tp_wma_handle wma; + struct wma_txrx_node *iface; + struct sta_ps_params sta_ps_param = {0}; + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_FAILURE; + if (!wma_is_vdev_valid(vdev_id)) + return QDF_STATUS_E_INVAL; + + wma_debug("Set Sta Ps param vdevId %d Param %d val %d", + vdev_id, param, value); + iface = &wma->interfaces[vdev_id]; + + sta_ps_param.vdev_id = vdev_id; + sta_ps_param.param_id = param; + sta_ps_param.value = value; + status = wmi_unified_sta_ps_cmd_send(wmi_handle, &sta_ps_param); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return status; +} + +/** + * wma_set_ap_peer_uapsd() - set powersave parameters in ap mode to fw + * @wma: wma handle + * @vdev_id: vdev id + * @peer_addr: peer mac address + * @uapsd_value: uapsd value + * @max_sp: maximum service period + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_set_ap_peer_uapsd(tp_wma_handle wma, uint32_t vdev_id, + uint8_t *peer_addr, uint8_t uapsd_value, + uint8_t max_sp) +{ + uint32_t uapsd = 0; + uint32_t max_sp_len = 0; + QDF_STATUS ret; + struct ap_ps_params param = {0}; + + if (uapsd_value & UAPSD_VO_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC3_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_VI_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC2_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC2_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_BK_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC1_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC1_TRIGGER_EN; + } + + if (uapsd_value & UAPSD_BE_ENABLED) { + uapsd |= WMI_AP_PS_UAPSD_AC0_DELIVERY_EN | + WMI_AP_PS_UAPSD_AC0_TRIGGER_EN; + } + + switch (max_sp) { + case UAPSD_MAX_SP_LEN_2: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_2; + break; + case UAPSD_MAX_SP_LEN_4: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_4; + break; + case UAPSD_MAX_SP_LEN_6: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_6; + break; + default: + max_sp_len = WMI_AP_PS_PEER_PARAM_MAX_SP_UNLIMITED; + break; + } + + wma_debug("Set WMI_AP_PS_PEER_PARAM_UAPSD 0x%x for "QDF_MAC_ADDR_FMT, + uapsd, QDF_MAC_ADDR_REF(peer_addr)); + param.vdev_id = vdev_id; + param.param = WMI_AP_PS_PEER_PARAM_UAPSD; + param.value = uapsd; + ret = wmi_unified_ap_ps_cmd_send(wma->wmi_handle, peer_addr, + ¶m); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Failed to set WMI_AP_PS_PEER_PARAM_UAPSD for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + return ret; + } + + wma_debug("Set WMI_AP_PS_PEER_PARAM_MAX_SP 0x%x for "QDF_MAC_ADDR_FMT, + max_sp_len, QDF_MAC_ADDR_REF(peer_addr)); + + param.vdev_id = vdev_id; + param.param = WMI_AP_PS_PEER_PARAM_MAX_SP; + param.value = max_sp_len; + ret = wmi_unified_ap_ps_cmd_send(wma->wmi_handle, peer_addr, + ¶m); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Failed to set WMI_AP_PS_PEER_PARAM_MAX_SP for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_addr)); + return ret; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_update_edca_params_for_ac() - to update per ac EDCA parameters + * @edca_param: EDCA parameters + * @wmm_param: wmm parameters + * @ac: access category + * + * Return: none + */ +void wma_update_edca_params_for_ac(tSirMacEdcaParamRecord *edca_param, + struct wmi_host_wme_vparams *wmm_param, + int ac, bool mu_edca_param, + uint8_t *debug_str, + uint32_t debug_str_size, uint32_t *len) +{ + wmm_param->cwmin = WMA_WMM_EXPO_TO_VAL(edca_param->cw.min); + wmm_param->cwmax = WMA_WMM_EXPO_TO_VAL(edca_param->cw.max); + wmm_param->aifs = edca_param->aci.aifsn; + if (mu_edca_param) + wmm_param->mu_edca_timer = edca_param->mu_edca_timer; + else + wmm_param->txoplimit = edca_param->txoplimit; + wmm_param->acm = edca_param->aci.acm; + + wmm_param->noackpolicy = edca_param->no_ack; + + *len += qdf_scnprintf(debug_str + *len, debug_str_size - *len, + "AC[%d]: AIFS %d Min %d Max %d %s %d ACM %d NOACK %d, ", + ac, wmm_param->aifs, wmm_param->cwmin, + wmm_param->cwmax, + mu_edca_param ? "MU_EDCA TIMER" : "TXOP", + mu_edca_param ? wmm_param->mu_edca_timer : wmm_param->txoplimit, + wmm_param->acm, wmm_param->noackpolicy); +} + +/** + * wma_set_tx_power() - set tx power limit in fw + * @handle: wma handle + * @tx_pwr_params: tx power parameters + * + * Return: none + */ +void wma_set_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + int8_t max_reg_power; + struct wma_txrx_node *iface; + + if (tx_pwr_params->dev_mode == QDF_SAP_MODE || + tx_pwr_params->dev_mode == QDF_P2P_GO_MODE) { + ret = wma_find_vdev_id_by_addr(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } else { + ret = wma_find_vdev_id_by_bssid(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } + if (ret) { + wma_err("vdev id is invalid for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(tx_pwr_params->bssId.bytes)); + qdf_mem_free(tx_pwr_params); + return; + } + + if (!wma_is_vdev_up(vdev_id)) { + wma_err("vdev id %d is not up for "QDF_MAC_ADDR_FMT, vdev_id, + QDF_MAC_ADDR_REF(tx_pwr_params->bssId.bytes)); + qdf_mem_free(tx_pwr_params); + return; + } + + iface = &wma_handle->interfaces[vdev_id]; + if (tx_pwr_params->power == 0) { + /* set to default. Since the app does not care the tx power + * we keep the previous setting + */ + mlme_set_tx_power(iface->vdev, tx_pwr_params->power); + ret = 0; + goto end; + } + + max_reg_power = mlme_get_max_reg_power(iface->vdev); + + if (max_reg_power != 0) { + /* make sure tx_power less than max_tx_power */ + if (tx_pwr_params->power > max_reg_power) { + tx_pwr_params->power = max_reg_power; + } + } + if (mlme_get_tx_power(iface->vdev) != tx_pwr_params->power) { + + /* tx_power changed, Push the tx_power to FW */ + wma_nofl_debug("TXP[W][set_tx_pwr]: %d", tx_pwr_params->power); + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + wmi_vdev_param_tx_pwrlimit, + tx_pwr_params->power); + if (ret == QDF_STATUS_SUCCESS) + mlme_set_tx_power(iface->vdev, tx_pwr_params->power); + } else { + /* no tx_power change */ + ret = QDF_STATUS_SUCCESS; + } +end: + qdf_mem_free(tx_pwr_params); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to set vdev param wmi_vdev_param_tx_pwrlimit"); +} + +/** + * wma_set_max_tx_power() - set max tx power limit in fw + * @handle: wma handle + * @tx_pwr_params: tx power parameters + * + * Return: none + */ +void wma_set_max_tx_power(WMA_HANDLE handle, + tMaxTxPowerParams *tx_pwr_params) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + uint8_t vdev_id; + QDF_STATUS ret = QDF_STATUS_E_FAILURE; + int8_t max_reg_power; + struct wma_txrx_node *iface; + int8_t max_tx_power; + struct wlan_channel *channel; + uint16_t ch_freq; + + if (tx_pwr_params->dev_mode == QDF_SAP_MODE || + tx_pwr_params->dev_mode == QDF_P2P_GO_MODE) { + ret = wma_find_vdev_id_by_addr(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } else { + ret = wma_find_vdev_id_by_bssid(wma_handle, + tx_pwr_params->bssId.bytes, + &vdev_id); + } + if (ret) { + wma_err("vdev id is invalid for "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(tx_pwr_params->bssId.bytes)); + qdf_mem_free(tx_pwr_params); + return; + } + + if (!wma_is_vdev_up(vdev_id)) { + wma_err("vdev id %d is not up", vdev_id); + qdf_mem_free(tx_pwr_params); + return; + } + + iface = &wma_handle->interfaces[vdev_id]; + channel = wlan_vdev_get_active_channel(iface->vdev); + if (channel) { + ch_freq = channel->ch_freq; + } else { + wma_err("Failed to get active channel"); + qdf_mem_free(tx_pwr_params); + return; + } + max_reg_power = wlan_reg_get_channel_reg_power_for_freq( + wma_handle->mac_context->pdev, ch_freq); + /* + * When user tx power as auto, host will configure + * the tx power as max regulatory power allowed for + * that channel which signifies that it will be the + * upper limit for tx power used while transmission + */ + if (tx_pwr_params->power == 0) + max_tx_power = max_reg_power; + else + max_tx_power = QDF_MIN(tx_pwr_params->power, max_reg_power); + + wma_nofl_debug("TXP[W][set_max_pwr_req]: %d", max_tx_power); + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + wmi_vdev_param_tx_pwrlimit, + max_tx_power); + if (ret == QDF_STATUS_SUCCESS) + mlme_set_tx_power(iface->vdev, max_tx_power); + qdf_mem_free(tx_pwr_params); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to set vdev param wmi_vdev_param_tx_pwrlimit"); +} + +/** + * wmi_unified_set_sta_ps() - set sta powersave params in fw + * @handle: wma handle + * @vdev_id: vdev id + * @val: value + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wmi_unified_set_sta_ps(wmi_unified_t wmi_handle, + uint32_t vdev_id, uint8_t val) +{ + QDF_STATUS ret; + + ret = wmi_unified_set_sta_ps_mode(wmi_handle, vdev_id, + val); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to send set Mimo PS ret = %d", ret); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_uapsd_mask() - get uapsd mask based on uapsd parameters + * @uapsd_params: uapsed parameters + * + * Return: uapsd mask + */ +static inline uint32_t wma_get_uapsd_mask(tpUapsd_Params uapsd_params) +{ + uint32_t uapsd_val = 0; + + if (uapsd_params->beDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC0_DELIVERY_EN; + + if (uapsd_params->beTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC0_TRIGGER_EN; + + if (uapsd_params->bkDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC1_DELIVERY_EN; + + if (uapsd_params->bkTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC1_TRIGGER_EN; + + if (uapsd_params->viDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC2_DELIVERY_EN; + + if (uapsd_params->viTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC2_TRIGGER_EN; + + if (uapsd_params->voDeliveryEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC3_DELIVERY_EN; + + if (uapsd_params->voTriggerEnabled) + uapsd_val |= WMI_STA_PS_UAPSD_AC3_TRIGGER_EN; + + return uapsd_val; +} + +/** + * wma_set_force_sleep() - set power save parameters to fw + * @wma: wma handle + * @vdev_id: vdev id + * @enable: enable/disable + * @ps_param: OPM params + * @enable_ps: enable power save + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wma_set_force_sleep(tp_wma_handle wma, + uint32_t vdev_id, + uint8_t enable, + struct wma_ps_params *ps_params, + bool enable_ps) +{ + QDF_STATUS ret; + /* get mac to access CFG data base */ + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t rx_wake_policy; + uint32_t tx_wake_threshold; + uint32_t pspoll_count; + uint32_t psmode; + struct wlan_objmgr_vdev *vdev; + u32 listen_interval = 0; + + wma_debug("Set Force Sleep vdevId %d val %d", vdev_id, enable); + + if (!mac) { + wma_err("Unable to get PE context"); + return QDF_STATUS_E_NOMEM; + } + + if (enable) { + /* override normal configuration and force station asleep */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + + if (ucfg_pmo_get_max_ps_poll(mac->psoc)) + pspoll_count = + (uint32_t)ucfg_pmo_get_max_ps_poll(mac->psoc); + else + pspoll_count = WMA_DEFAULT_MAX_PSPOLL_BEFORE_WAKE; + + psmode = WMI_STA_PS_MODE_ENABLED; + } else { + /* Ps Poll Wake Policy */ + if (ucfg_pmo_get_max_ps_poll(mac->psoc)) { + /* Ps Poll is enabled */ + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD; + pspoll_count = + (uint32_t)ucfg_pmo_get_max_ps_poll(mac->psoc); + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER; + } else { + rx_wake_policy = WMI_STA_PS_RX_WAKE_POLICY_WAKE; + pspoll_count = WMI_STA_PS_PSPOLL_COUNT_NO_MAX; + tx_wake_threshold = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS; + } + psmode = WMI_STA_PS_MODE_ENABLED; + } + + /* + * Advanced power save is enabled by default in Firmware + * So Disable advanced power save explicitly + */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_ENABLE_OPM, + ps_params->opm_mode); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("%s(%d) Power Failed vdevId %d", + ps_params->opm_mode ? "Enable" : "Disable", + ps_params->opm_mode, vdev_id); + return ret; + } + wma_debug("Power %s(%d) vdevId %d", + ps_params->opm_mode ? "Enabled" : "Disabled", + ps_params->opm_mode, vdev_id); + + /* Set the Tx/Rx InActivity */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, + ps_params->ps_ito); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Setting Tx/Rx InActivity Failed vdevId %d InAct %d", + vdev_id, ps_params->ps_ito); + return ret; + } + wma_debug("Set Tx/Rx InActivity vdevId %d InAct %d", + vdev_id, ps_params->ps_ito); + + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL, + ps_params->spec_wake); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Setting Spec wake Failed vdevId %d InAct %d", + vdev_id, ps_params->spec_wake); + return ret; + } + wma_debug("Set Spec wake vdevId %d InAct %d", + vdev_id, ps_params->spec_wake); + + /* Set the Wake Policy to WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_RX_WAKE_POLICY, + rx_wake_policy); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Setting wake policy Failed vdevId %d", vdev_id); + return ret; + } + wma_debug("Setting wake policy to %d vdevId %d", + rx_wake_policy, vdev_id); + + /* Set the Tx Wake Threshold */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD, + tx_wake_threshold); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Setting TxWake Threshold vdevId %d", vdev_id); + return ret; + } + wma_debug("Setting TxWake Threshold to %d vdevId %d", + tx_wake_threshold, vdev_id); + + /* Set the Ps Poll Count */ + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_PSPOLL_COUNT, + pspoll_count); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Set Ps Poll Count Failed vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + return ret; + } + wma_debug("Set Ps Poll Count vdevId %d ps poll cnt %d", + vdev_id, pspoll_count); + + /* Enable Sta Mode Power save */ + if (enable_ps) { + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, true); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Enable Sta Mode Ps Failed vdevId %d", + vdev_id); + return ret; + } + } + + /* Set Listen Interval */ + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(mac->psoc, vdev_id, + WLAN_LEGACY_WMA_ID); + /* If user has configured listen interval already + * No need to send vdev set param cmd + */ + if (vdev) { + ret = wlan_pmo_get_listen_interval(vdev, &listen_interval); + wlan_objmgr_vdev_release_ref(vdev, WLAN_LEGACY_WMA_ID); + } + + if (!listen_interval || QDF_IS_STATUS_ERROR(ret)) { + listen_interval = mac->mlme_cfg->sap_cfg.listen_interval; + ret = wma_vdev_set_param(wma->wmi_handle, vdev_id, + wmi_vdev_param_listen_interval, + listen_interval); + } + if (QDF_IS_STATUS_ERROR(ret)) { + /* Even it fails continue Fw will take default LI */ + wma_err("Failed to Set Listen Interval vdevId %d", vdev_id); + } + wma_debug("Set Listen Interval vdevId %d Listen Intv %d", + vdev_id, listen_interval); + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS wma_wlan_pmo_get_ps_params(struct wlan_objmgr_vdev *vdev, + struct wma_ps_params *ps_params) +{ + struct pmo_ps_params pmo_ps_param = {0}; + QDF_STATUS status; + + status = wlan_pmo_get_ps_params(vdev, &pmo_ps_param); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + switch (pmo_ps_param.opm_mode) { + case PMO_PS_ADVANCED_POWER_SAVE_DISABLE: + ps_params->opm_mode = WMI_STA_PS_OPM_CONSERVATIVE; + break; + case PMO_PS_ADVANCED_POWER_SAVE_ENABLE: + ps_params->opm_mode = WMI_STA_PS_OPM_AGGRESSIVE; + break; + case PMO_PS_ADVANCED_POWER_SAVE_USER_DEFINED: + ps_params->opm_mode = WMI_STA_PS_USER_DEF; + break; + default: + wma_err("Invalid opm_mode:%d", pmo_ps_param.opm_mode); + return QDF_STATUS_E_INVAL; + } + ps_params->ps_ito = pmo_ps_param.ps_ito; + ps_params->spec_wake = pmo_ps_param.spec_wake; + + return status; +} + +void wma_enable_sta_ps_mode(tpEnablePsParams ps_req) +{ + uint32_t vdev_id = ps_req->sessionid; + QDF_STATUS ret; + struct wma_txrx_node *iface; + t_wma_handle *wma_handle; + struct wma_ps_params ps_params = {0}; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return; + + iface = &wma_handle->interfaces[vdev_id]; + + if (!iface || !iface->vdev) { + wma_err("vdev is NULL for vdev_%d", vdev_id); + return; + } + + ret = wma_wlan_pmo_get_ps_params(iface->vdev, &ps_params); + if (QDF_IS_STATUS_ERROR(ret)) + return; + + if (eSIR_ADDON_NOTHING == ps_req->psSetting) { + if (ps_params.opm_mode && iface->uapsd_cached_val) { + ps_params.opm_mode = WMI_STA_PS_OPM_CONSERVATIVE; + wma_debug("Advanced power save is disabled"); + } + wma_debug("Enable Sta Mode Ps vdevId %d", vdev_id); + ret = wma_unified_set_sta_ps_param(wma_handle->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Set Uapsd param 0 Failed vdevId %d", vdev_id); + return; + } + + ret = wma_set_force_sleep(wma_handle, vdev_id, false, + &ps_params, true); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Enable Sta Ps Failed vdevId %d", vdev_id); + return; + } + } else if (eSIR_ADDON_ENABLE_UAPSD == ps_req->psSetting) { + uint32_t uapsd_val = 0; + + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + if (uapsd_val != iface->uapsd_cached_val) { + wma_debug("Enable Uapsd vdevId %d Mask %d", + vdev_id, uapsd_val); + ret = + wma_unified_set_sta_ps_param(wma_handle->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_UAPSD, + uapsd_val); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Enable Uapsd Failed vdevId %d", + vdev_id); + return; + } + /* Cache the Uapsd Mask */ + iface->uapsd_cached_val = uapsd_val; + } else { + wma_debug("Already Uapsd Enabled vdevId %d Mask %d", + vdev_id, uapsd_val); + } + + if (!!ps_params.opm_mode && !!iface->uapsd_cached_val) { + ps_params.opm_mode = WMI_STA_PS_OPM_CONSERVATIVE; + wma_debug("Qpower is disabled"); + } + wma_debug("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma_handle, vdev_id, true, + &ps_params, true); + + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Enable Forced Sleep Failed vdevId %d", + vdev_id); + return; + } + } + + if (wma_handle->ito_repeat_count) { + wma_debug("Set ITO count to %d for vdevId %d", + wma_handle->ito_repeat_count, vdev_id); + + ret = wma_unified_set_sta_ps_param(wma_handle->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_MAX_RESET_ITO_COUNT_ON_TIM_NO_TXRX, + wma_handle->ito_repeat_count); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Set ITO count failed vdevId %d Error %d", + vdev_id, ret); + return; + } + } + + /* power save request succeeded */ + iface->in_bmps = true; +} + + +/** + * wma_disable_sta_ps_mode() - disable sta powersave params in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_disable_sta_ps_mode(tpDisablePsParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + struct wma_txrx_node *iface; + t_wma_handle *wma_handle; + + wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma_handle) + return; + + iface = &wma_handle->interfaces[vdev_id]; + + wma_debug("Disable Sta Mode Ps vdevId %d", vdev_id); + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma_handle->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + iface->in_bmps = false; + + /* Disable UAPSD incase if additional Req came */ + if (eSIR_ADDON_DISABLE_UAPSD == ps_req->psSetting) { + wma_debug("Disable Uapsd vdevId %d", vdev_id); + ret = wma_unified_set_sta_ps_param(wma_handle->wmi_handle, + vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Uapsd Failed vdevId %d", vdev_id); + /* + * Even this fails we can proceed as success + * since we disabled powersave + */ + } + } +} + +/** + * wma_convert_opm_mode() - convert opm with equivalent wmi opm + * @opm_mode: Optimized power management mode + * + * Return: enum wmi_sta_ps_scheme_cfg + */ +static enum wmi_sta_ps_scheme_cfg +wma_convert_opm_mode(enum wma_sta_ps_scheme_cfg opm_mode) +{ + switch (opm_mode) { + case WMA_STA_PS_OPM_CONSERVATIVE: + return WMI_STA_PS_OPM_CONSERVATIVE; + case WMA_STA_PS_OPM_AGGRESSIVE: + return WMI_STA_PS_OPM_AGGRESSIVE; + case WMA_STA_PS_USER_DEF: + return WMI_STA_PS_USER_DEF; + default: + wma_err("Invalid opm_mode: %d", opm_mode); + return WMI_STA_PS_OPM_CONSERVATIVE; + } +} + +QDF_STATUS wma_set_power_config(uint8_t vdev_id, + enum wma_sta_ps_scheme_cfg power) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_INVAL; + + wma_info("configuring power: %d", power); + return wma_unified_set_sta_ps_param(wma->wmi_handle, + vdev_id, + WMI_STA_PS_ENABLE_OPM, + wma_convert_opm_mode(power)); +} + +QDF_STATUS wma_set_power_config_ito(uint8_t vdev_id, uint16_t ps_ito) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + wma_err("wma_handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + return wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_INACTIVITY_TIME, + ps_ito); +} + +QDF_STATUS wma_set_power_config_spec_wake(uint8_t vdev_id, uint16_t spec_wake) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + wma_err("wma_handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + return wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_SPEC_WAKE_INTERVAL, + spec_wake); +} + +void wma_enable_uapsd_mode(tp_wma_handle wma, tpEnableUapsdParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + uint32_t uapsd_val = 0; + struct wma_ps_params ps_params = {0}; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + if (!iface->vdev) { + wma_err("vdev is NULL for vdev_%d", vdev_id); + return; + } + + ret = wma_wlan_pmo_get_ps_params(iface->vdev, &ps_params); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("ps_param is invalid for vdev_%d", vdev_id); + return; + } + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + uapsd_val = wma_get_uapsd_mask(&ps_req->uapsdParams); + + wma_debug("Enable Uapsd vdevId %d Mask %d", vdev_id, uapsd_val); + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, uapsd_val); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Enable Uapsd Failed vdevId %d", vdev_id); + return; + } + + if (!!ps_params.opm_mode && !!uapsd_val) { + ps_params.opm_mode = 0; + wma_debug("Disable power %d", vdev_id); + } + iface->uapsd_cached_val = uapsd_val; + wma_debug("Enable Forced Sleep vdevId %d", vdev_id); + ret = wma_set_force_sleep(wma, vdev_id, true, + &ps_params, ps_req->uapsdParams.enable_ps); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Enable Forced Sleep Failed vdevId %d", vdev_id); + return; + } + +} + +/** + * wma_disable_uapsd_mode() - disable uapsd mode in fw + * @wma: wma handle + * @ps_req: power save request + * + * Return: none + */ +void wma_disable_uapsd_mode(tp_wma_handle wma, + tpDisableUapsdParams ps_req) +{ + QDF_STATUS ret; + uint32_t vdev_id = ps_req->sessionid; + struct wma_ps_params ps_params = {0}; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + + if (!iface->vdev) { + wma_err("vdev is null for vdev_%d", vdev_id); + return; + } + + wma_debug("Disable Uapsd vdevId %d", vdev_id); + + ret = wma_wlan_pmo_get_ps_params(iface->vdev, &ps_params); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("ps_param is invalid for vdev_%d", vdev_id); + return; + } + + /* Disable Sta Mode Power save */ + ret = wmi_unified_set_sta_ps(wma->wmi_handle, vdev_id, false); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Sta Mode Ps Failed vdevId %d", vdev_id); + return; + } + + ret = wma_unified_set_sta_ps_param(wma->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, 0); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Uapsd Failed vdevId %d", vdev_id); + return; + } + + /* Re enable Sta Mode Powersave with proper configuration */ + ret = wma_set_force_sleep(wma, vdev_id, false, + &ps_params, true); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Forced Sleep Failed vdevId %d", vdev_id); + return; + } +} + +/** + * wma_set_sta_uapsd_auto_trig_cmd() - set uapsd auto trigger command + * @wmi_handle: wma handle + * @vdevid: vdev id + * @peer_addr: peer mac address + * @trig_param: auto trigger parameters + * @num_ac: number of access category + * + * This function sets the trigger + * uapsd params such as service interval, delay interval + * and suspend interval which will be used by the firmware + * to send trigger frames periodically when there is no + * traffic on the transmit side. + * + * Return: 0 for success or error code. + */ +static QDF_STATUS wma_set_sta_uapsd_auto_trig_cmd(wmi_unified_t wmi_handle, + uint32_t vdevid, + uint8_t peer_addr[QDF_MAC_ADDR_SIZE], + struct sta_uapsd_params *trig_param, + uint32_t num_ac) +{ + QDF_STATUS ret; + struct sta_uapsd_trig_params cmd = {0}; + + cmd.vdevid = vdevid; + cmd.auto_triggerparam = trig_param; + cmd.num_ac = num_ac; + + qdf_mem_copy((uint8_t *) cmd.peer_addr, (uint8_t *) peer_addr, + sizeof(uint8_t) * QDF_MAC_ADDR_SIZE); + ret = wmi_unified_set_sta_uapsd_auto_trig_cmd(wmi_handle, + &cmd); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to send set uapsd param ret = %d", ret); + + return ret; +} + +QDF_STATUS wma_trigger_uapsd_params(tp_wma_handle wma_handle, uint32_t vdev_id, + tp_wma_trigger_uapsd_params + trigger_uapsd_params) +{ + QDF_STATUS ret; + uint8_t *bssid; + struct sta_uapsd_params uapsd_trigger_param; + + wma_debug("Trigger uapsd params vdev id %d", vdev_id); + + wma_debug("WMM AC %d User Priority %d SvcIntv %d DelIntv %d SusIntv %d", + trigger_uapsd_params->wmm_ac, + trigger_uapsd_params->user_priority, + trigger_uapsd_params->service_interval, + trigger_uapsd_params->delay_interval, + trigger_uapsd_params->suspend_interval); + + if (!wmi_service_enabled(wma_handle->wmi_handle, + wmi_sta_uapsd_basic_auto_trig) || + !wmi_service_enabled(wma_handle->wmi_handle, + wmi_sta_uapsd_var_auto_trig)) { + wma_debug("Trigger uapsd is not supported vdev id %d", vdev_id); + return QDF_STATUS_SUCCESS; + } + + uapsd_trigger_param.wmm_ac = trigger_uapsd_params->wmm_ac; + uapsd_trigger_param.user_priority = trigger_uapsd_params->user_priority; + uapsd_trigger_param.service_interval = + trigger_uapsd_params->service_interval; + uapsd_trigger_param.suspend_interval = + trigger_uapsd_params->suspend_interval; + uapsd_trigger_param.delay_interval = + trigger_uapsd_params->delay_interval; + + bssid = wma_get_vdev_bssid(wma_handle->interfaces[vdev_id].vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + ret = wma_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, bssid, + &uapsd_trigger_param, 1); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Fail to send uapsd param cmd for vdevid %d ret = %d", + ret, vdev_id); + return ret; + } + + return ret; +} + +QDF_STATUS wma_disable_uapsd_per_ac(tp_wma_handle wma_handle, + uint32_t vdev_id, enum uapsd_ac ac) +{ + QDF_STATUS ret; + uint8_t *bssid; + struct wma_txrx_node *iface = &wma_handle->interfaces[vdev_id]; + struct sta_uapsd_params uapsd_trigger_param; + enum uapsd_up user_priority; + + wma_debug("Disable Uapsd per ac vdevId %d ac %d", vdev_id, ac); + + switch (ac) { + case UAPSD_VO: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC3_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC3_TRIGGER_EN); + user_priority = UAPSD_UP_VO; + break; + case UAPSD_VI: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC2_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC2_TRIGGER_EN); + user_priority = UAPSD_UP_VI; + break; + case UAPSD_BK: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC1_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC1_TRIGGER_EN); + user_priority = UAPSD_UP_BK; + break; + case UAPSD_BE: + iface->uapsd_cached_val &= + ~(WMI_STA_PS_UAPSD_AC0_DELIVERY_EN | + WMI_STA_PS_UAPSD_AC0_TRIGGER_EN); + user_priority = UAPSD_UP_BE; + break; + default: + wma_err("Invalid AC vdevId %d ac %d", vdev_id, ac); + return QDF_STATUS_E_FAILURE; + } + + /* + * Disable Auto Trigger Functionality before + * disabling uapsd for a particular AC + */ + uapsd_trigger_param.wmm_ac = ac; + uapsd_trigger_param.user_priority = user_priority; + uapsd_trigger_param.service_interval = 0; + uapsd_trigger_param.suspend_interval = 0; + uapsd_trigger_param.delay_interval = 0; + + bssid = wma_get_vdev_bssid(wma_handle->interfaces[vdev_id].vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + ret = wma_set_sta_uapsd_auto_trig_cmd(wma_handle->wmi_handle, + vdev_id, bssid, + &uapsd_trigger_param, 1); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Fail to send auto trig cmd for vdevid %d ret = %d", + ret, vdev_id); + return ret; + } + + ret = wma_unified_set_sta_ps_param(wma_handle->wmi_handle, vdev_id, + WMI_STA_PS_PARAM_UAPSD, + iface->uapsd_cached_val); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("Disable Uapsd per ac Failed vdevId %d ac %d", vdev_id, + ac); + return ret; + } + wma_debug("Disable Uapsd per ac vdevId %d val %d", vdev_id, + iface->uapsd_cached_val); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_temperature() - get pdev temperature req + * @wmi_handle: wma handle + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_get_temperature(tp_wma_handle wma_handle) +{ + QDF_STATUS ret = QDF_STATUS_SUCCESS; + + ret = wmi_unified_get_temperature(wma_handle->wmi_handle); + if (ret) + wma_err("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +/** + * wma_pdev_temperature_evt_handler() - pdev temperature event handler + * @handle: wma handle + * @event: event buffer + * @len : length + * + * Return: 0 for success or error code. + */ +int wma_pdev_temperature_evt_handler(void *handle, uint8_t *event, + uint32_t len) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg sme_msg = { 0 }; + WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *param_buf; + wmi_pdev_temperature_event_fixed_param *wmi_event; + + param_buf = (WMI_PDEV_TEMPERATURE_EVENTID_param_tlvs *) event; + if (!param_buf) { + wma_err("Invalid pdev_temperature event buffer"); + return -EINVAL; + } + + wmi_event = param_buf->fixed_param; + wma_info("temperature: %d", wmi_event->value); + + sme_msg.type = eWNI_SME_MSG_GET_TEMPERATURE_IND; + sme_msg.bodyptr = NULL; + sme_msg.bodyval = wmi_event->value; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + wma_err("Fail to post get temperature ind msg"); + return 0; +} + +#define MAX_PDEV_TXPOWER_PARAMS 2 +/* params being sent: + * wmi_pdev_param_txpower_limit2g + * wmi_pdev_param_txpower_limit5g + */ + +/** + * wma_process_tx_power_limits() - sends the power limits for 2g/5g to firmware + * @handle: wma handle + * @ptxlim: power limit value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_process_tx_power_limits(WMA_HANDLE handle, + struct tx_power_limit *ptxlim) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + int32_t ret = 0; + uint32_t txpower_params2g = 0; + uint32_t txpower_params5g = 0; + struct wmi_unified *wmi_handle; + struct dev_set_param setparam[MAX_PDEV_TXPOWER_PARAMS] = {}; + uint8_t index = 0; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + /* Set value and reason code for 2g and 5g power limit */ + + SET_PDEV_PARAM_TXPOWER_REASON(txpower_params2g, + wmi_pdev_param_txpower_reason_sar); + SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params2g, ptxlim->txPower2g); + + SET_PDEV_PARAM_TXPOWER_REASON(txpower_params5g, + wmi_pdev_param_txpower_reason_sar); + SET_PDEV_PARAM_TXPOWER_VALUE(txpower_params5g, ptxlim->txPower5g); + + wma_debug("txpower2g: %x txpower5g: %x", + txpower_params2g, txpower_params5g); + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_txpower_limit2g, + txpower_params2g, index++, + MAX_PDEV_TXPOWER_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("failed at wmi_pdev_param_txpower_limit2g"); + goto error; + } + ret = mlme_check_index_setparam(setparam, + wmi_pdev_param_txpower_limit5g, + txpower_params5g, index++, + MAX_PDEV_TXPOWER_PARAMS); + if (QDF_IS_STATUS_ERROR(ret)) { + wma_err("failed at wmi_pdev_param_txpower_limit5g"); + goto error; + } + ret = wma_send_multi_pdev_vdev_set_params(MLME_PDEV_SETPARAM, + WMI_PDEV_ID_SOC, setparam, + index); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("failed to send tx power pdev set params"); +error: + return ret; +} + +#ifdef WLAN_WMI_BCN +/** + * wma_add_p2p_ie() - add p2p IE + * @frm: ptr where p2p ie needs to add + * + * Return: ptr after p2p ie + */ +static uint8_t *wma_add_p2p_ie(uint8_t *frm) +{ + uint8_t wfa_oui[3] = WMA_P2P_WFA_OUI; + struct p2p_ie *p2p_ie = (struct p2p_ie *)frm; + + p2p_ie->p2p_id = WMA_P2P_IE_ID; + p2p_ie->p2p_oui[0] = wfa_oui[0]; + p2p_ie->p2p_oui[1] = wfa_oui[1]; + p2p_ie->p2p_oui[2] = wfa_oui[2]; + p2p_ie->p2p_oui_type = WMA_P2P_WFA_VER; + p2p_ie->p2p_len = 4; + return frm + sizeof(struct p2p_ie); +} + +/** + * wma_update_beacon_noa_ie() - update beacon ie + * @bcn: beacon info + * @new_noa_sub_ie_len: ie length + * + * Return: none + */ +static void wma_update_beacon_noa_ie(struct beacon_info *bcn, + uint16_t new_noa_sub_ie_len) +{ + struct p2p_ie *p2p_ie; + uint8_t *buf; + + /* if there is nothing to add, just return */ + if (new_noa_sub_ie_len == 0) { + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + wma_debug("NoA is present in previous beacon, but not present in swba event, So Reset the NoA"); + /* TODO: Assuming p2p noa ie is last ie in the beacon */ + qdf_mem_zero(bcn->noa_ie, (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie))); + bcn->len -= (bcn->noa_sub_ie_len + + sizeof(struct p2p_ie)); + bcn->noa_ie = NULL; + bcn->noa_sub_ie_len = 0; + } + wma_debug("No need to update NoA"); + return; + } + + if (bcn->noa_sub_ie_len && bcn->noa_ie) { + /* NoA present in previous beacon, update it */ + wma_debug("NoA present in previous beacon, update the NoA IE, bcn->len %u bcn->noa_sub_ie_len %u", + bcn->len, bcn->noa_sub_ie_len); + bcn->len -= (bcn->noa_sub_ie_len + sizeof(struct p2p_ie)); + qdf_mem_zero(bcn->noa_ie, + (bcn->noa_sub_ie_len + sizeof(struct p2p_ie))); + } else { /* NoA is not present in previous beacon */ + wma_debug("NoA not present in previous beacon, add it bcn->len %u", + bcn->len); + buf = qdf_nbuf_data(bcn->buf); + bcn->noa_ie = buf + bcn->len; + } + + if (bcn->len + sizeof(struct p2p_ie) + new_noa_sub_ie_len > + SIR_MAX_BEACON_SIZE) { + wma_err("exceed max beacon length, bcn->len %d, new_noa_sub_ie_len %d, p2p len %u", + bcn->len, new_noa_sub_ie_len, + (uint32_t)sizeof(struct p2p_ie)); + return; + } + + bcn->noa_sub_ie_len = new_noa_sub_ie_len; + wma_add_p2p_ie(bcn->noa_ie); + p2p_ie = (struct p2p_ie *)bcn->noa_ie; + p2p_ie->p2p_len += new_noa_sub_ie_len; + qdf_mem_copy((bcn->noa_ie + sizeof(struct p2p_ie)), bcn->noa_sub_ie, + new_noa_sub_ie_len); + + bcn->len += (new_noa_sub_ie_len + sizeof(struct p2p_ie)); + wma_debug("Updated beacon length with NoA Ie is %u", bcn->len); +} + +/** + * wma_p2p_create_sub_ie_noa() - put p2p noa ie + * @buf: buffer + * @noa: noa element ie + * @new_noa_sub_ie_len: ie length + * + * Return: none + */ +static void wma_p2p_create_sub_ie_noa(uint8_t *buf, + struct p2p_sub_element_noa *noa, + uint16_t *new_noa_sub_ie_len) +{ + uint8_t tmp_octet = 0; + int i; + uint8_t *buf_start = buf; + + *buf++ = WMA_P2P_SUB_ELEMENT_NOA; /* sub-element id */ + ASSERT(noa->num_descriptors <= WMA_MAX_NOA_DESCRIPTORS); + + /* + * Length = (2 octets for Index and CTWin/Opp PS) and + * (13 octets for each NOA Descriptors) + */ + P2PIE_PUT_LE16(buf, WMA_NOA_IE_SIZE(noa->num_descriptors)); + buf += 2; + + *buf++ = noa->index; /* Instance Index */ + + tmp_octet = noa->ctwindow & WMA_P2P_NOA_IE_CTWIN_MASK; + if (noa->oppPS) + tmp_octet |= WMA_P2P_NOA_IE_OPP_PS_SET; + *buf++ = tmp_octet; /* Opp Ps and CTWin capabilities */ + + for (i = 0; i < noa->num_descriptors; i++) { + ASSERT(noa->noa_descriptors[i].type_count != 0); + + *buf++ = noa->noa_descriptors[i].type_count; + + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].duration); + buf += 4; + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].interval); + buf += 4; + P2PIE_PUT_LE32(buf, noa->noa_descriptors[i].start_time); + buf += 4; + } + *new_noa_sub_ie_len = (buf - buf_start); +} + +/** + * wma_update_noa() - update noa params + * @beacon: beacon info + * @noa_ie: noa ie + * + * Return: none + */ +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie) +{ + uint16_t new_noa_sub_ie_len; + + /* Call this function by holding the spinlock on beacon->lock */ + + if (noa_ie) { + if ((noa_ie->ctwindow == 0) && (noa_ie->oppPS == 0) && + (noa_ie->num_descriptors == 0)) { + /* NoA is not present */ + wma_debug("NoA is not present"); + new_noa_sub_ie_len = 0; + } else { + /* Create the binary blob containing NOA sub-IE */ + wma_debug("Create NOA sub ie"); + wma_p2p_create_sub_ie_noa(&beacon->noa_sub_ie[0], + noa_ie, &new_noa_sub_ie_len); + } + } else { + wma_debug("No need to add NOA"); + new_noa_sub_ie_len = 0; /* no NOA IE sub-attributes */ + } + + wma_update_beacon_noa_ie(beacon, new_noa_sub_ie_len); +} + +/** + * wma_update_probe_resp_noa() - update noa IE in probe response + * @wma_handle: wma handle + * @noa_ie: noa ie + * + * Return: none + */ +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie) +{ + tSirP2PNoaAttr *noa_attr = qdf_mem_malloc(sizeof(tSirP2PNoaAttr)); + wma_debug("Received update NoA event"); + if (!noa_attr) + return; + + qdf_mem_zero(noa_attr, sizeof(tSirP2PNoaAttr)); + + noa_attr->index = noa_ie->index; + noa_attr->oppPsFlag = noa_ie->oppPS; + noa_attr->ctWin = noa_ie->ctwindow; + if (!noa_ie->num_descriptors) { + wma_debug("Zero NoA descriptors"); + } else { + wma_debug("%d NoA descriptors", noa_ie->num_descriptors); + noa_attr->uNoa1IntervalCnt = + noa_ie->noa_descriptors[0].type_count; + noa_attr->uNoa1Duration = noa_ie->noa_descriptors[0].duration; + noa_attr->uNoa1Interval = noa_ie->noa_descriptors[0].interval; + noa_attr->uNoa1StartTime = + noa_ie->noa_descriptors[0].start_time; + if (noa_ie->num_descriptors > 1) { + noa_attr->uNoa2IntervalCnt = + noa_ie->noa_descriptors[1].type_count; + noa_attr->uNoa2Duration = + noa_ie->noa_descriptors[1].duration; + noa_attr->uNoa2Interval = + noa_ie->noa_descriptors[1].interval; + noa_attr->uNoa2StartTime = + noa_ie->noa_descriptors[1].start_time; + } + } + wma_debug("Sending SIR_HAL_P2P_NOA_ATTR_IND to LIM"); + wma_send_msg(wma_handle, SIR_HAL_P2P_NOA_ATTR_IND, (void *)noa_attr, 0); +} + +#else +static inline uint8_t *wma_add_p2p_ie(uint8_t *frm) +{ + return 0; +} + +static inline void +wma_update_beacon_noa_ie(struct beacon_info *bcn, + uint16_t new_noa_sub_ie_len) +{ +} + +static inline void +wma_p2p_create_sub_ie_noa(uint8_t *buf, + struct p2p_sub_element_noa *noa, + uint16_t *new_noa_sub_ie_len) +{ +} + +void wma_update_noa(struct beacon_info *beacon, + struct p2p_sub_element_noa *noa_ie) +{ +} + +void wma_update_probe_resp_noa(tp_wma_handle wma_handle, + struct p2p_sub_element_noa *noa_ie) +{ +} + +#endif + +/** + * wma_process_set_mimops_req() - Set the received MiMo PS state to firmware + * @handle: wma handle + * @mimops: MIMO powersave params + * + * Return: none + */ +void wma_process_set_mimops_req(tp_wma_handle wma_handle, + tSetMIMOPS *mimops) +{ + /* Translate to what firmware understands */ + if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_DYNAMIC) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_DYNAMIC; + else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_STATIC) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_STATIC; + else if (mimops->htMIMOPSState == eSIR_HT_MIMO_PS_NO_LIMIT) + mimops->htMIMOPSState = WMI_PEER_MIMO_PS_NONE; + + wma_debug("htMIMOPSState = %d, sessionId = %d peerMac <"QDF_MAC_ADDR_FMT">", + mimops->htMIMOPSState, mimops->sessionId, + QDF_MAC_ADDR_REF(mimops->peerMac)); + + wma_set_peer_param(wma_handle, mimops->peerMac, + WMI_HOST_PEER_MIMO_PS_STATE, mimops->htMIMOPSState, + mimops->sessionId); +} + +/** + * wma_set_mimops() - set MIMO powersave + * @handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_mimops(tp_wma_handle wma, uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + + ret = wmi_unified_set_mimops(wma->wmi_handle, vdev_id, + value); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +/** + * wma_notify_modem_power_state() - notify modem power state + * @wma_ptr: wma handle + * @pReq: modem power state + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_notify_modem_power_state(void *wma_ptr, + tSirModemPowerStateInd *pReq) +{ + QDF_STATUS status; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + + wma_debug("WMA notify Modem Power State %d", pReq->param); + + status = wma_unified_modem_power_state(wma->wmi_handle, pReq->param); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to notify Modem Power State %d", pReq->param); + return status; + } + + wma_debug("Successfully notify Modem Power State %d", pReq->param); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_idle_ps_config() - enable/disable Low Power Support(Pdev Specific) + * @wma_ptr: wma handle + * @idle_ps: idle powersave + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_idle_ps_config(void *wma_ptr, uint32_t idle_ps) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle) wma_ptr; + struct pdev_params pdevparam = {}; + + wma_debug("WMA Set Idle Ps Config [1:set 0:clear] val %d", idle_ps); + + /* Set Idle Mode Power Save Config */ + pdevparam.param_id = wmi_pdev_param_idle_ps_config; + pdevparam.param_value = idle_ps; + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + + if (ret) { + wma_err("Fail to Set Idle Ps Config %d", idle_ps); + return QDF_STATUS_E_FAILURE; + } + wma->in_imps = !!idle_ps; + + wma_debug("Successfully Set Idle Ps Config %d", idle_ps); + return QDF_STATUS_SUCCESS; +} + +/** + * wma_set_smps_params() - set smps params + * @wma: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_smps_params(tp_wma_handle wma, uint8_t vdev_id, + int value) +{ + QDF_STATUS ret; + + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("Invalid VDEV ID: %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + ret = wmi_unified_set_smps_params(wma->wmi_handle, vdev_id, + value); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Failed to send set Mimo PS ret = %d", ret); + + return ret; +} + +#ifdef FEATURE_TX_POWER +/** + * wma_set_tx_power_scale() - set tx power scale + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_tx_power_scale(uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (!wma_is_vdev_up(vdev_id)) { + wma_err("vdev id %d is not up", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + wmi_vdev_param_txpower_scale, value); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Set tx power scale failed"); + + return ret; +} + +/** + * wma_set_tx_power_scale_decr_db() - decrease power by DB value + * @vdev_id: vdev id + * @value: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_set_tx_power_scale_decr_db(uint8_t vdev_id, int value) +{ + QDF_STATUS ret; + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) + return QDF_STATUS_E_FAILURE; + + if (!wma_is_vdev_up(vdev_id)) { + wma_err("vdev id %d is not up", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + ret = wma_vdev_set_param(wma_handle->wmi_handle, vdev_id, + wmi_vdev_param_txpower_scale_decr_db, value); + if (QDF_IS_STATUS_ERROR(ret)) + wma_err("Decrease tx power value failed"); + + return ret; +} + +/** + * wma_enable_disable_imps() - enable/disable FW IMPS feature + * @pdev_id: pdev id + * @param_val: value + * + * Return: QDF_STATUS_SUCCESS for success or error code. + */ +QDF_STATUS wma_enable_disable_imps(uint32_t pdev_id, uint32_t param_val) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct pdev_params pparam = {0}; + QDF_STATUS status; + + if (!wma) + return QDF_STATUS_E_FAILURE; + + pparam.is_host_pdev_id = false; + + /* Enable-disable IMPS */ + pparam.param_id = WMI_PDEV_PARAM_IDLE_PS_CONFIG; + pparam.param_value = param_val; + status = wmi_unified_pdev_param_send(wma->wmi_handle, + &pparam, pdev_id); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Unable to enable/disable:(%d) IMPS", + param_val); + + wma->in_imps = !!param_val; + + return status; +} +#endif /* FEATURE_TX_POWER */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_sar_public_structs.h b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_sar_public_structs.h new file mode 100644 index 0000000000..9c1d1c4d1d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_sar_public_structs.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __WMA_SAR_PUBLIC_STRUCTS_H +#define __WMA_SAR_PUBLIC_STRUCTS_H + +struct sar_limit_event; + +enum sar_version { + SAR_VERSION_1, + SAR_VERSION_2, + SAR_VERSION_3, + SAR_VERSION_4, + SAR_VERSION_5, + SAR_VERSION_6, +}; + +/** + * typedef wma_sar_cb() - SAR callback function + * @context: Opaque context provided by caller in the original request + * @event: SAR limits event + */ +typedef void (*wma_sar_cb)(void *context, struct sar_limit_event *event); + +#endif /* __WMA_SAR_PUBLIC_STRUCTS_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_scan_roam.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_scan_roam.c new file mode 100644 index 0000000000..df54161b54 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_scan_roam.c @@ -0,0 +1,3274 @@ + /* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_scan_roam.c + * This file contains functions related to scan and + * roaming functionality. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" +#include +#include +#include + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" +#include "wlan_dlm_api.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" +#include "wlan_policy_mgr_api.h" +#include + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "wma_internal.h" +#if defined(CONFIG_HL_SUPPORT) +#include "wlan_tgt_def_config_hl.h" +#else +#include "wlan_tgt_def_config.h" +#endif +#include "wlan_reg_services_api.h" +#include "wlan_roam_debug.h" +#include "wlan_mlme_public_struct.h" +#include "wlan_mgmt_txrx_utils_api.h" + +/* This is temporary, should be removed */ +#include "ol_htt_api.h" +#include +#include "wma_he.h" +#include +#include +#include "wma_nan_datapath.h" +#include "wlan_mlme_api.h" +#include +#include +#include +#include +#include "wlan_dlm_api.h" +#include "wlan_cm_roam_api.h" +#ifdef FEATURE_WLAN_DIAG_SUPPORT /* FEATURE_WLAN_DIAG_SUPPORT */ +#include "host_diag_core_log.h" +#endif /* FEATURE_WLAN_DIAG_SUPPORT */ +#include <../../core/src/wlan_cm_roam_i.h> +#include "wlan_cm_roam_api.h" +#include "wlan_mlo_mgr_roam.h" +#include "lim_mlo.h" +#include "wlan_dp_api.h" +#ifdef FEATURE_WLAN_EXTSCAN +#define WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION WAKELOCK_DURATION_RECOMMENDED + +/* + * Maximum number of entries that could be present in the + * WMI_EXTSCAN_HOTLIST_MATCH_EVENT buffer from the firmware + */ +#define WMA_EXTSCAN_MAX_HOTLIST_ENTRIES 10 +#endif + +static inline wmi_host_channel_width +wma_map_phy_ch_bw_to_wmi_channel_width(enum phy_ch_width ch_width) +{ + switch (ch_width) { + case CH_WIDTH_20MHZ: + return WMI_HOST_CHAN_WIDTH_20; + case CH_WIDTH_40MHZ: + return WMI_HOST_CHAN_WIDTH_40; + case CH_WIDTH_80MHZ: + return WMI_HOST_CHAN_WIDTH_80; + case CH_WIDTH_160MHZ: + return WMI_HOST_CHAN_WIDTH_160; + case CH_WIDTH_5MHZ: + return WMI_HOST_CHAN_WIDTH_5; + case CH_WIDTH_10MHZ: + return WMI_HOST_CHAN_WIDTH_10; + case CH_WIDTH_320MHZ: + return WMI_HOST_CHAN_WIDTH_320; + default: + return WMI_HOST_CHAN_WIDTH_20; + } +} + +#define WNI_CFG_VHT_CHANNEL_WIDTH_20_40MHZ 0 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ 1 +#define WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ 2 +#define WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ 3 + +#if defined(WLAN_FEATURE_11BE) +static void wma_update_ch_list_11be_params(struct ch_params *ch) +{ + ch->ch_width = CH_WIDTH_320MHZ; +} +#else /* !WLAN_FEATURE_11BE */ +static void wma_update_ch_list_11be_params(struct ch_params *ch) +{ + ch->ch_width = CH_WIDTH_160MHZ; +} +#endif /* WLAN_FEATURE_11BE */ + +/** + * wma_update_channel_list() - update channel list + * @handle: wma handle + * @chan_list: channel list + * + * Function is used to update the support channel list in fw. + * + * Return: QDF status + */ +QDF_STATUS wma_update_channel_list(WMA_HANDLE handle, + tSirUpdateChanList *chan_list) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + int i, len; + struct scan_chan_list_params *scan_ch_param; + struct channel_param *chan_p; + struct ch_params ch_params = {0}; + + len = sizeof(struct channel_param) * chan_list->numChan + + offsetof(struct scan_chan_list_params, ch_param[0]); + scan_ch_param = qdf_mem_malloc(len); + if (!scan_ch_param) + return QDF_STATUS_E_NOMEM; + + qdf_mem_zero(scan_ch_param, len); + wma_debug("no of channels = %d", chan_list->numChan); + chan_p = &scan_ch_param->ch_param[0]; + scan_ch_param->nallchans = chan_list->numChan; + scan_ch_param->max_bw_support_present = true; + wma_handle->saved_chan.num_channels = chan_list->numChan; + wma_debug("ht %d, vht %d, vht_24 %d", chan_list->ht_en, + chan_list->vht_en, chan_list->vht_24_en); + + for (i = 0; i < chan_list->numChan; ++i) { + chan_p->mhz = chan_list->chanParam[i].freq; + chan_p->cfreq1 = chan_p->mhz; + chan_p->cfreq2 = 0; + wma_handle->saved_chan.ch_freq_list[i] = + chan_list->chanParam[i].freq; + + if (chan_list->chanParam[i].dfsSet) { + chan_p->is_chan_passive = 1; + chan_p->dfs_set = 1; + } + + if (chan_list->chanParam[i].nan_disabled) + chan_p->nan_disabled = 1; + + if (chan_p->mhz < WMA_2_4_GHZ_MAX_FREQ) { + chan_p->phy_mode = MODE_11G; + if (chan_list->vht_en && chan_list->vht_24_en) + chan_p->allow_vht = 1; + } else { + chan_p->phy_mode = MODE_11A; + if (chan_list->vht_en && + !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz))) + chan_p->allow_vht = 1; + } + + if (chan_list->ht_en && + !(WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz))) + chan_p->allow_ht = 1; + + if (chan_list->he_en) + chan_p->allow_he = 1; + + if (chan_list->eht_en) + chan_p->allow_eht = 1; + + if (chan_list->chanParam[i].half_rate) + chan_p->half_rate = 1; + else if (chan_list->chanParam[i].quarter_rate) + chan_p->quarter_rate = 1; + + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_p->mhz) && + wlan_reg_is_6ghz_psc_chan_freq(chan_p->mhz)) + chan_p->psc_channel = 1; + + /*TODO: Set WMI_SET_CHANNEL_MIN_POWER */ + /*TODO: Set WMI_SET_CHANNEL_ANTENNA_MAX */ + /*TODO: WMI_SET_CHANNEL_REG_CLASSID */ + chan_p->maxregpower = chan_list->chanParam[i].pwr; + + wma_update_ch_list_11be_params(&ch_params); + + wlan_reg_set_channel_params_for_pwrmode(wma_handle->pdev, + chan_p->mhz, 0, + &ch_params, + REG_CURRENT_PWR_MODE); + + chan_p->max_bw_supported = + wma_map_phy_ch_bw_to_wmi_channel_width(ch_params.ch_width); + chan_p++; + } + + qdf_status = wmi_unified_scan_chan_list_cmd_send(wma_handle->wmi_handle, + scan_ch_param); + + if (QDF_IS_STATUS_ERROR(qdf_status)) + wma_err("Failed to send WMI_SCAN_CHAN_LIST_CMDID"); + + qdf_mem_free(scan_ch_param); + + return qdf_status; +} + +/** + * wma_handle_disconnect_reason() - Send del sta msg to lim on receiving + * @wma_handle: wma handle + * @vdev_id: vdev id + * @reason: disconnection reason from fw + * + * Return: None + */ +static void wma_handle_disconnect_reason(tp_wma_handle wma_handle, + uint32_t vdev_id, uint32_t reason) +{ + tpDeleteStaContext del_sta_ctx; + + del_sta_ctx = qdf_mem_malloc(sizeof(tDeleteStaContext)); + if (!del_sta_ctx) + return; + + del_sta_ctx->vdev_id = vdev_id; + del_sta_ctx->reasonCode = reason; + wma_send_msg(wma_handle, SIR_LIM_DELETE_STA_CONTEXT_IND, + (void *)del_sta_ctx, 0); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS +cm_handle_auth_offload(struct auth_offload_event *auth_event) +{ + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct mac_context *mac_ctx; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx || !wma) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + + cds_host_diag_log_work(&wma->roam_preauth_wl, + WMA_ROAM_PREAUTH_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_WOW); + + qdf_wake_lock_timeout_acquire(&wma->roam_ho_wl, + WMA_ROAM_HO_WAKE_LOCK_DURATION); + + lim_sae_auth_cleanup_retry(mac_ctx, auth_event->vdev_id); + wlan_cm_set_sae_auth_ta(mac_ctx->pdev, + auth_event->vdev_id, + auth_event->ta); + + wlan_cm_store_mlo_roam_peer_address(mac_ctx->pdev, auth_event); + + status = + wlan_cm_update_offload_ssid_from_candidate(mac_ctx->pdev, + auth_event->vdev_id, + &auth_event->ap_bssid); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err_rl("Set offload ssid failed %d", status); + return QDF_STATUS_E_FAILURE; + } + + status = wma->csr_roam_auth_event_handle_cb(mac_ctx, auth_event->vdev_id, + auth_event->ap_bssid, + auth_event->akm); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err_rl("Trigger pre-auth failed"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_handle_disconnect_reason(struct vdev_disconnect_event_data *data) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) { + QDF_ASSERT(0); + return QDF_STATUS_E_FAILURE; + } + switch (data->reason) { + case CM_DISCONNECT_REASON_CSA_SA_QUERY_TIMEOUT: + wma_handle_disconnect_reason(wma, data->vdev_id, + HAL_DEL_STA_REASON_CODE_SA_QUERY_TIMEOUT); + break; + case CM_DISCONNECT_REASON_MOVE_TO_CELLULAR: + wma_handle_disconnect_reason(wma, data->vdev_id, + HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT); + break; + default: + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_handle_scan_ch_list_data(struct cm_roam_scan_ch_resp *data) +{ + struct scheduler_msg sme_msg = {0}; + + sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT; + sme_msg.bodyptr = data; + + if (scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg)) { + wma_err("Failed to post msg to SME"); + qdf_mem_free(sme_msg.bodyptr); + return -EINVAL; + } + + return QDF_STATUS_SUCCESS; +} + +#endif + +/** + * wma_process_set_pdev_ie_req() - process the pdev set IE req + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * + * Sends the WMI req to set the IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + if (ie_params->ie_type == DOT11_HT_IE) + wma_process_set_pdev_ht_ie_req(wma, ie_params); + if (ie_params->ie_type == DOT11_VHT_IE) + wma_process_set_pdev_vht_ie_req(wma, ie_params); + + qdf_mem_free(ie_params->ie_ptr); +} + +/** + * wma_process_set_pdev_ht_ie_req() - sends HT IE data to FW + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * @nss: Nss values to prepare the HT IE. + * + * Sends the WMI req to set the HT IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_ht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + QDF_STATUS status; + wmi_pdev_set_ht_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint16_t ie_len_pad; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); + len += ie_len_pad; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) + return; + + cmd = (wmi_pdev_set_ht_ie_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_ht_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_ht_ie_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->ie_len = ie_params->ie_len; + cmd->tx_streams = ie_params->nss; + cmd->rx_streams = ie_params->nss; + wma_debug("Setting pdev HT ie with Nss = %u", ie_params->nss); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); + if (ie_params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)ie_params->ie_ptr, + ie_params->ie_len); + } + + status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_HT_CAP_IE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); +} + +/** + * wma_process_set_pdev_vht_ie_req() - sends VHT IE data to FW + * @wma: Pointer to wma handle + * @ie_params: Pointer to IE data. + * @nss: Nss values to prepare the VHT IE. + * + * Sends the WMI req to set the VHT IE to FW. + * + * Return: None + */ +void wma_process_set_pdev_vht_ie_req(tp_wma_handle wma, + struct set_ie_param *ie_params) +{ + QDF_STATUS status; + wmi_pdev_set_vht_ie_cmd_fixed_param *cmd; + wmi_buf_t buf; + uint16_t len; + uint16_t ie_len_pad; + uint8_t *buf_ptr; + + len = sizeof(*cmd) + WMI_TLV_HDR_SIZE; + ie_len_pad = roundup(ie_params->ie_len, sizeof(uint32_t)); + len += ie_len_pad; + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) + return; + + cmd = (wmi_pdev_set_vht_ie_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_pdev_set_vht_ie_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_vht_ie_cmd_fixed_param)); + cmd->reserved0 = 0; + cmd->ie_len = ie_params->ie_len; + cmd->tx_streams = ie_params->nss; + cmd->rx_streams = ie_params->nss; + wma_debug("Setting pdev VHT ie with Nss = %u", ie_params->nss); + buf_ptr = (uint8_t *)cmd + sizeof(*cmd); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, ie_len_pad); + if (ie_params->ie_len) { + qdf_mem_copy(buf_ptr + WMI_TLV_HDR_SIZE, + (uint8_t *)ie_params->ie_ptr, ie_params->ie_len); + } + + status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_VHT_CAP_IE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); +} + +#define MAX_VDEV_ROAM_SCAN_PARAMS 2 +/* params being sent: + * wmi_vdev_param_bmiss_first_bcnt + * wmi_vdev_param_bmiss_final_bcnt + */ + +/** + * wma_roam_scan_bmiss_cnt() - set bmiss count to fw + * @wma_handle: wma handle + * @first_bcnt: first bmiss count + * @final_bcnt: final bmiss count + * @vdev_id: vdev id + * + * set first & final biss count to fw. + * + * Return: QDF status + */ +QDF_STATUS wma_roam_scan_bmiss_cnt(tp_wma_handle wma_handle, + A_INT32 first_bcnt, + A_UINT32 final_bcnt, uint32_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct dev_set_param setparam[MAX_VDEV_ROAM_SCAN_PARAMS] = {}; + uint8_t index = 0; + + wma_debug("first_bcnt: %d, final_bcnt: %d", first_bcnt, final_bcnt); + + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_bmiss_first_bcnt, + first_bcnt, index++, + MAX_VDEV_ROAM_SCAN_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_bmiss_first_bcnt"); + goto error; + } + status = mlme_check_index_setparam(setparam, + wmi_vdev_param_bmiss_final_bcnt, + final_bcnt, index++, + MAX_VDEV_ROAM_SCAN_PARAMS); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("failed to set wmi_vdev_param_bmiss_final_bcnt"); + goto error; + } + status = wma_send_multi_pdev_vdev_set_params(MLME_VDEV_SETPARAM, + vdev_id, setparam, index); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to set BMISS FIRST and FINAL vdev set params"); +error: + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +void +wma_send_roam_preauth_status(tp_wma_handle wma_handle, + struct wmi_roam_auth_status_params *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma_handle)) + return; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return; + + status = wmi_unified_send_roam_preauth_status(wmi_handle, params); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("failed to send disconnect roam preauth status"); +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_delete_bss_peer() Delete bss peer/s for Non ML interface + * @wma: Global WMA Handle + * @vdev_id: vdev id + * + * This function will perform cleanup of the peer corresponds + * to given vdev_id + * + * Return: QDF status + */ +static +QDF_STATUS wma_delete_bss_peer(tp_wma_handle wma, + uint8_t vdev_id) +{ + tDeleteStaParams *del_sta_params; + + del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params)); + if (!del_sta_params) + return QDF_STATUS_E_NOMEM; + + del_sta_params->smesessionId = vdev_id; + wma_delete_sta(wma, del_sta_params); + wma_delete_bss(wma, vdev_id); + + return QDF_STATUS_SUCCESS; +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wma_delete_all_peers() - Delete all bss peer/s + * @wma: Global WMA Handle + * @vdev_id: vdev id + * @del_sta_params: parameters required for del sta request + * + * This function will perform deleting of all the link peers + * after self roaming. + * + * Return: None + */ +static QDF_STATUS +wma_delete_all_peers(tp_wma_handle wma, + uint8_t vdev_id) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_mlo_dev_context *mlo_dev_ctx; + uint8_t i; + uint8_t link_vdev_id; + tDeleteStaParams *del_sta_params; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr bssid; + struct qdf_mac_addr *mld_addr; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(wma->psoc, vdev_id, + WLAN_MLME_OBJMGR_ID); + if (!vdev) { + mlme_err("vdev object is NULL for vdev %d", vdev_id); + return QDF_STATUS_E_NULL_VALUE; + } + + mlo_dev_ctx = vdev->mlo_dev_ctx; + if (!mlo_dev_ctx) { + mld_addr = + (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + /* It's not a ML interface*/ + if (qdf_is_macaddr_zero(mld_addr)) { + mlme_debug("Non-ML STA vdev_id: %d", vdev_id); + status = wma_delete_bss_peer(wma, vdev_id); + goto end; + } + + mlme_err("mlo_dev_ctx object is NULL for vdev %d", vdev_id); + status = QDF_STATUS_E_NULL_VALUE; + goto end; + } + + for (i = 0; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + if (!mlo_dev_ctx->wlan_vdev_list[i]) + continue; + + if (QDF_IS_STATUS_ERROR(wlan_vdev_get_bss_peer_mac( + mlo_dev_ctx->wlan_vdev_list[i], + &bssid))) { + pe_debug("bss peer is not present on vdev id %d, no need to cleanup", + wlan_vdev_get_id( + mlo_dev_ctx->wlan_vdev_list[i])); + continue; + } + + del_sta_params = qdf_mem_malloc(sizeof(*del_sta_params)); + if (!del_sta_params) { + status = QDF_STATUS_E_NOMEM; + goto end; + } + lim_mlo_roam_peer_disconn_del(mlo_dev_ctx->wlan_vdev_list[i]); + qdf_mem_zero(del_sta_params, sizeof(*del_sta_params)); + link_vdev_id = wlan_vdev_get_id(mlo_dev_ctx->wlan_vdev_list[i]); + if (link_vdev_id == WLAN_INVALID_VDEV_ID) { + mlme_err("invalid vdev id"); + status = QDF_STATUS_E_INVAL; + goto end; + } + del_sta_params->smesessionId = link_vdev_id; + wma_delete_sta(wma, del_sta_params); + wma_delete_bss(wma, link_vdev_id); + } + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_MLME_OBJMGR_ID); + return status; +} +#else +static inline QDF_STATUS +wma_delete_all_peers(tp_wma_handle wma, + uint8_t vdev_id) +{ + return wma_delete_bss_peer(wma, vdev_id); +} +#endif +/** + * wma_roam_update_vdev() - Update the STA and BSS + * @wma: Global WMA Handle + * @roam_synch_ind_ptr: Information needed for roam sync propagation + * + * This function will perform all the vdev related operations with + * respect to the self sta and the peer after roaming and completes + * the roam synch propagation with respect to WMA layer. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_roam_update_vdev(tp_wma_handle wma, + struct roam_offload_synch_ind *roam_synch_ind_ptr, + uint8_t roamed_vdev_id) +{ + tAddStaParams *add_sta_params; + uint8_t vdev_id, *bssid; + int32_t uc_cipher, cipher_cap; + bool is_assoc_peer = false; + struct qdf_mac_addr mac_addr; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + vdev_id = roamed_vdev_id; + wma->interfaces[vdev_id].nss = roam_synch_ind_ptr->nss; + + /* update channel width */ + wma->interfaces[vdev_id].chan_width = roam_synch_ind_ptr->chan_width; + /* Fill link freq from roam_synch_ind */ + if (is_multi_link_roam(roam_synch_ind_ptr)) + wma->interfaces[vdev_id].ch_freq = + mlo_roam_get_chan_freq(vdev_id, roam_synch_ind_ptr); + else + wma->interfaces[vdev_id].ch_freq = + roam_synch_ind_ptr->chan_freq; + + add_sta_params = qdf_mem_malloc(sizeof(*add_sta_params)); + if (!add_sta_params) + return QDF_STATUS_E_INVAL; + + if (is_multi_link_roam(roam_synch_ind_ptr)) + mlo_get_sta_link_mac_addr(vdev_id, roam_synch_ind_ptr, + &mac_addr); + else + mac_addr = roam_synch_ind_ptr->bssid; + + qdf_mem_zero(add_sta_params, sizeof(*add_sta_params)); + + /* With self roaming on multi link AP, as the same + * peer already exists, new peer creation fails + * To handle this delete all link peers, + * while doing roam sync on first link. + */ + if (!is_multi_link_roam(roam_synch_ind_ptr) || + wlan_vdev_mlme_get_is_mlo_link(wma->psoc, vdev_id) || + mlo_get_single_link_ml_roaming(wma->psoc, vdev_id)) { + status = wma_delete_all_peers(wma, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) + goto end; + } + + add_sta_params->staType = STA_ENTRY_SELF; + add_sta_params->smesessionId = vdev_id; + qdf_mem_copy(&add_sta_params->bssId, &mac_addr, QDF_MAC_ADDR_SIZE); + add_sta_params->assocId = roam_synch_ind_ptr->aid; + + bssid = wma_get_vdev_bssid(wma->interfaces[vdev_id].vdev); + if (!bssid) { + wma_err("Failed to get bssid for vdev_%d", vdev_id); + return QDF_STATUS_E_INVAL; + } + + is_assoc_peer = wlan_vdev_mlme_get_is_mlo_vdev(wma->psoc, vdev_id); + if (is_multi_link_roam(roam_synch_ind_ptr)) { + status = wma_create_peer(wma, mac_addr.bytes, + WMI_PEER_TYPE_DEFAULT, vdev_id, + roam_synch_ind_ptr->bssid.bytes, + is_assoc_peer); + } else { + status = wma_create_peer(wma, mac_addr.bytes, + WMI_PEER_TYPE_DEFAULT, vdev_id, NULL, + is_assoc_peer); + } + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to create peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + goto end; + } + + if (is_multi_link_roam(roam_synch_ind_ptr)) { + status = lim_roam_mlo_create_peer(wma->mac_context, + roam_synch_ind_ptr, vdev_id, + mac_addr.bytes); + + /* The created peer will be destroyed on HO failure cleanup */ + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to attach MLO peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac_addr.bytes)); + goto end; + } + } + + if (wlan_vdev_mlme_get_opmode(wma->interfaces[vdev_id].vdev) == + QDF_STA_MODE) + wlan_cdp_set_peer_freq(wma->psoc, mac_addr.bytes, + wma->interfaces[vdev_id].ch_freq, + vdev_id); + + /* Update new peer's uc cipher */ + uc_cipher = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev, + WLAN_CRYPTO_PARAM_UCAST_CIPHER); + cipher_cap = wlan_crypto_get_param(wma->interfaces[vdev_id].vdev, + WLAN_CRYPTO_PARAM_CIPHER_CAP); + wma_set_peer_ucast_cipher(mac_addr.bytes, uc_cipher, + cipher_cap); + wma_add_bss_lfr3(wma, roam_synch_ind_ptr->add_bss_params); + wma_add_sta(wma, add_sta_params); + qdf_mem_copy(bssid, mac_addr.bytes, + QDF_MAC_ADDR_SIZE); + lim_fill_roamed_peer_twt_caps(wma->mac_context, vdev_id, + roam_synch_ind_ptr); +end: + qdf_mem_free(add_sta_params); + return status; +} + +static void wma_update_phymode_on_roam(tp_wma_handle wma, + struct qdf_mac_addr *bssid, + wmi_channel *chan, + struct wma_txrx_node *iface) +{ + enum wlan_phymode bss_phymode; + struct wlan_channel *des_chan; + struct wlan_channel *bss_chan; + struct vdev_mlme_obj *vdev_mlme; + uint8_t channel; + struct wlan_objmgr_pdev *pdev = NULL; + qdf_freq_t sec_ch_2g_freq = 0; + struct ch_params ch_params = {0}; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!vdev_mlme) + return; + + pdev = wlan_vdev_get_pdev(vdev_mlme->vdev); + + channel = wlan_reg_freq_to_chan(pdev, iface->ch_freq); + if (chan) + bss_phymode = + wma_fw_to_host_phymode(WMI_GET_CHANNEL_MODE(chan)); + else + wma_get_phy_mode_cb(iface->ch_freq, + iface->chan_width, &bss_phymode); + + /* Update vdev mlme channel info after roaming */ + des_chan = wlan_vdev_mlme_get_des_chan(iface->vdev); + bss_chan = wlan_vdev_mlme_get_bss_chan(iface->vdev); + des_chan->ch_phymode = bss_phymode; + des_chan->ch_width = iface->chan_width; + if (chan) { + des_chan->ch_freq = chan->mhz; + ch_params.ch_width = des_chan->ch_width; + if (wlan_reg_is_24ghz_ch_freq(des_chan->ch_freq) && + des_chan->ch_width == CH_WIDTH_40MHZ && + chan->band_center_freq1) { + if (des_chan->ch_freq < chan->band_center_freq1) + sec_ch_2g_freq = des_chan->ch_freq + 20; + else + sec_ch_2g_freq = des_chan->ch_freq - 20; + } + wlan_reg_set_channel_params_for_pwrmode(pdev, des_chan->ch_freq, + sec_ch_2g_freq, + &ch_params, + REG_CURRENT_PWR_MODE); + if (ch_params.ch_width != des_chan->ch_width || + ch_params.mhz_freq_seg0 != chan->band_center_freq1 || + ch_params.mhz_freq_seg1 != chan->band_center_freq2) + wma_err("ch mismatch host & fw bw (%d %d) seg0 (%d, %d) seg1 (%d, %d)", + ch_params.ch_width, des_chan->ch_width, + ch_params.mhz_freq_seg0, + chan->band_center_freq1, + ch_params.mhz_freq_seg1, + chan->band_center_freq2); + des_chan->ch_cfreq1 = ch_params.mhz_freq_seg0; + des_chan->ch_cfreq2 = ch_params.mhz_freq_seg1; + des_chan->ch_width = ch_params.ch_width; + } else { + wma_err("LFR3: invalid chan"); + } + qdf_mem_copy(bss_chan, des_chan, sizeof(struct wlan_channel)); + + /* Till conversion is not done in WMI we need to fill fw phy mode */ + vdev_mlme->mgmt.generic.phy_mode = wmi_host_to_fw_phymode(bss_phymode); + + /* update new phymode to peer */ + wma_objmgr_set_peer_mlme_phymode(wma, bssid->bytes, bss_phymode); + + wma_debug("LFR3: new phymode %d freq %d (bw %d, %d %d)", + bss_phymode, des_chan->ch_freq, des_chan->ch_width, + des_chan->ch_cfreq1, des_chan->ch_cfreq2); +} + +/** + * wma_set_ric_req() - set ric request element + * @wma: wma handle + * @msg: message + * @is_add_ts: is addts required + * + * This function sets ric request element for 11r roaming. + * + * Return: none + */ +void wma_set_ric_req(tp_wma_handle wma, void *msg, uint8_t is_add_ts) +{ + if (!wma) { + wma_err("wma handle is NULL"); + return; + } + + wmi_unified_set_ric_req_cmd(wma->wmi_handle, msg, is_add_ts); +} +#endif /* WLAN_FEATURE_ROAM_OFFLOAD */ + +#ifdef FEATURE_RSSI_MONITOR +QDF_STATUS wma_set_rssi_monitoring(tp_wma_handle wma, + struct rssi_monitor_param *req) +{ + if (!wma) { + wma_err("wma handle is NULL"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_set_rssi_monitoring_cmd(wma->wmi_handle, req); +} + +/** + * wma_rssi_breached_event_handler() - rssi breached event handler + * @handle: wma handle + * @cmd_param_info: event handler data + * @len: length of @cmd_param_info + * + * Return: 0 on success; error number otherwise + */ +int wma_rssi_breached_event_handler(void *handle, + u_int8_t *cmd_param_info, u_int32_t len) +{ + WMI_RSSI_BREACH_EVENTID_param_tlvs *param_buf; + wmi_rssi_breach_event_fixed_param *event; + struct rssi_breach_event rssi; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!mac || !wma) { + wma_err("Invalid mac/wma context"); + return -EINVAL; + } + if (!mac->sme.rssi_threshold_breached_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_RSSI_BREACH_EVENTID_param_tlvs *)cmd_param_info; + if (!param_buf) { + wma_err("Invalid rssi breached event"); + return -EINVAL; + } + event = param_buf->fixed_param; + + rssi.request_id = event->request_id; + rssi.session_id = event->vdev_id; + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_hw_db2dbm_support)) + rssi.curr_rssi = event->rssi; + else + rssi.curr_rssi = event->rssi + WMA_TGT_NOISE_FLOOR_DBM; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, rssi.curr_bssid.bytes); + + wma_debug("req_id: %u vdev_id: %d curr_rssi: %d", + rssi.request_id, rssi.session_id, rssi.curr_rssi); + wma_debug("curr_bssid: "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(rssi.curr_bssid.bytes)); + + mac->sme.rssi_threshold_breached_cb(mac->hdd_handle, &rssi); + wma_debug("Invoke HDD rssi breached callback"); + return 0; +} +#endif /* FEATURE_RSSI_MONITOR */ + +QDF_STATUS wma_pre_chan_switch_setup(uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *intr; + uint16_t beacon_interval_ori; + bool restart; + uint16_t reduced_beacon_interval; + struct vdev_mlme_obj *mlme_obj; + struct wlan_objmgr_vdev *vdev; + + if (!wma) { + pe_err("wma is NULL"); + return QDF_STATUS_E_FAILURE; + } + intr = &wma->interfaces[vdev_id]; + if (!intr) { + pe_err("wma txrx node is NULL"); + return QDF_STATUS_E_FAILURE; + } + vdev = intr->vdev; + mlme_obj = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!mlme_obj) { + pe_err("vdev component object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + restart = + wma_get_channel_switch_in_progress(intr); + if (restart && intr->beacon_filter_enabled) + wma_remove_beacon_filter(wma, &intr->beacon_filter); + + reduced_beacon_interval = + wma->mac_context->sap.SapDfsInfo.reduced_beacon_interval; + if (wma_is_vdev_in_ap_mode(wma, vdev_id) && reduced_beacon_interval) { + + + /* Reduce the beacon interval just before the channel switch. + * This would help in reducing the downtime on the STA side + * (which is waiting for beacons from the AP to resume back + * transmission). Switch back the beacon_interval to its + * original value after the channel switch based on the + * timeout. This would ensure there are atleast some beacons + * sent with increased frequency. + */ + + wma_debug("Changing beacon interval to %d", + reduced_beacon_interval); + + /* Add a timer to reset the beacon interval back*/ + beacon_interval_ori = mlme_obj->proto.generic.beacon_interval; + mlme_obj->proto.generic.beacon_interval = + reduced_beacon_interval; + if (wma_fill_beacon_interval_reset_req(wma, + vdev_id, + beacon_interval_ori, + RESET_BEACON_INTERVAL_TIMEOUT)) { + + wma_debug("Failed to fill beacon interval reset req"); + } + } + + status = wma_vdev_pre_start(vdev_id, restart); + + return status; +} + +QDF_STATUS wma_post_chan_switch_setup(uint8_t vdev_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wma_txrx_node *intr; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + struct wlan_channel *des_chan; + cdp_config_param_type val; + + if (!wma) { + pe_err("wma is NULL"); + return QDF_STATUS_E_FAILURE; + } + intr = &wma->interfaces[vdev_id]; + if (!intr) { + pe_err("wma txrx node is NULL"); + return QDF_STATUS_E_FAILURE; + } + /* + * Record monitor mode channel here in case HW + * indicate RX PPDU TLV with invalid channel number. + */ + if (intr->type == WMI_VDEV_TYPE_MONITOR) { + des_chan = intr->vdev->vdev_mlme.des_chan; + val.cdp_pdev_param_monitor_chan = des_chan->ch_ieee; + cdp_txrx_set_pdev_param(soc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + CDP_MONITOR_CHANNEL, val); + val.cdp_pdev_param_mon_freq = des_chan->ch_freq; + cdp_txrx_set_pdev_param(soc, + wlan_objmgr_pdev_get_pdev_id(wma->pdev), + CDP_MONITOR_FREQUENCY, val); + } + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_WLAN_ESE +/** + * wma_plm_start() - plm start request + * @wma: wma handle + * @params: plm request parameters + * + * This function request FW to start PLM. + * + * Return: QDF status + */ +static QDF_STATUS wma_plm_start(tp_wma_handle wma, + struct plm_req_params *params) +{ + QDF_STATUS status; + + wma_debug("PLM Start"); + + status = wmi_unified_plm_start_cmd(wma->wmi_handle, params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[params->vdev_id].plm_in_progress = true; + + wma_debug("Plm start request sent successfully for vdev %d", + params->vdev_id); + + return status; +} + +/** + * wma_plm_stop() - plm stop request + * @wma: wma handle + * @params: plm request parameters + * + * This function request FW to stop PLM. + * + * Return: QDF status + */ +static QDF_STATUS wma_plm_stop(tp_wma_handle wma, + struct plm_req_params *params) +{ + QDF_STATUS status; + + if (!wma->interfaces[params->vdev_id].plm_in_progress) { + wma_err("No active plm req found, skip plm stop req"); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("PLM Stop"); + + status = wmi_unified_plm_stop_cmd(wma->wmi_handle, params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[params->vdev_id].plm_in_progress = false; + + wma_debug("Plm stop request sent successfully for vdev %d", + params->vdev_id); + + return status; +} + +/** + * wma_config_plm() - config PLM + * @wma: wma handle + * @params: plm request parameters + * + * Return: none + */ +void wma_config_plm(tp_wma_handle wma, struct plm_req_params *params) +{ + QDF_STATUS ret; + + if (!params || !wma) + return; + + if (params->enable) + ret = wma_plm_start(wma, params); + else + ret = wma_plm_stop(wma, params); + + if (ret) + wma_err("PLM %s failed %d", + params->enable ? "start" : "stop", ret); +} +#endif + +#ifdef FEATURE_WLAN_EXTSCAN +/** + * wma_extscan_wow_event_callback() - extscan wow event callback + * @handle: WMA handle + * @event: event buffer + * @len: length of @event buffer + * + * In wow case, the wow event is followed by the payload of the event + * which generated the wow event. + * payload is 4 bytes of length followed by event buffer. the first 4 bytes + * of event buffer is common tlv header, which is a combination + * of tag (higher 2 bytes) and length (lower 2 bytes). The tag is used to + * identify the event which triggered wow event. + * Payload is extracted and converted into generic tlv structure before + * being passed to this function. + * + * @Return: Errno + */ +int wma_extscan_wow_event_callback(void *handle, void *event, uint32_t len) +{ + uint32_t tag = WMITLV_GET_TLVTAG(WMITLV_GET_HDR(event)); + + switch (tag) { + case WMITLV_TAG_STRUC_wmi_extscan_start_stop_event_fixed_param: + return wma_extscan_start_stop_event_handler(handle, event, len); + + case WMITLV_TAG_STRUC_wmi_extscan_operation_event_fixed_param: + return wma_extscan_operations_event_handler(handle, event, len); + + case WMITLV_TAG_STRUC_wmi_extscan_table_usage_event_fixed_param: + return wma_extscan_table_usage_event_handler(handle, event, + len); + + case WMITLV_TAG_STRUC_wmi_extscan_cached_results_event_fixed_param: + return wma_extscan_cached_results_event_handler(handle, event, + len); + + case WMITLV_TAG_STRUC_wmi_extscan_wlan_change_results_event_fixed_param: + return wma_extscan_change_results_event_handler(handle, event, + len); + + case WMITLV_TAG_STRUC_wmi_extscan_hotlist_match_event_fixed_param: + return wma_extscan_hotlist_match_event_handler(handle, event, + len); + + case WMITLV_TAG_STRUC_wmi_extscan_capabilities_event_fixed_param: + return wma_extscan_capabilities_event_handler(handle, event, + len); + + default: + wma_err("Unknown tag: %d", tag); + return 0; + } +} + +/** + * wma_register_extscan_event_handler() - register extscan event handler + * @wma_handle: wma handle + * + * This function register extscan related event handlers. + * + * Return: none + */ +void wma_register_extscan_event_handler(tp_wma_handle wma_handle) +{ + if (wma_validate_handle(wma_handle)) + return; + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_start_stop_event_id, + wma_extscan_start_stop_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_capabilities_event_id, + wma_extscan_capabilities_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_hotlist_match_event_id, + wma_extscan_hotlist_match_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_wlan_change_results_event_id, + wma_extscan_change_results_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_operation_event_id, + wma_extscan_operations_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_table_usage_event_id, + wma_extscan_table_usage_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_extscan_cached_results_event_id, + wma_extscan_cached_results_event_handler, + WMA_RX_SERIALIZER_CTX); + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_passpoint_match_event_id, + wma_passpoint_match_event_handler, + WMA_RX_SERIALIZER_CTX); +} + +/** + * wma_extscan_start_stop_event_handler() - extscan start/stop event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: data length + * + * This function handles different extscan related commands + * like start/stop/get results etc and indicate to upper layers. + * + * Return: 0 for success or error code. + */ +int wma_extscan_start_stop_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *param_buf; + wmi_extscan_start_stop_event_fixed_param *event; + struct sir_extscan_generic_response *extscan_ind; + uint16_t event_type; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_START_STOP_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid extscan event"); + return -EINVAL; + } + event = param_buf->fixed_param; + extscan_ind = qdf_mem_malloc(sizeof(*extscan_ind)); + if (!extscan_ind) + return -ENOMEM; + + switch (event->command) { + case WMI_EXTSCAN_START_CMDID: + event_type = eSIR_EXTSCAN_START_RSP; + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + break; + case WMI_EXTSCAN_STOP_CMDID: + event_type = eSIR_EXTSCAN_STOP_RSP; + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + break; + case WMI_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) + event_type = + eSIR_EXTSCAN_RESET_SIGNIFICANT_WIFI_CHANGE_RSP; + else + event_type = + eSIR_EXTSCAN_SET_SIGNIFICANT_WIFI_CHANGE_RSP; + break; + case WMI_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) + event_type = eSIR_EXTSCAN_RESET_BSSID_HOTLIST_RSP; + else + event_type = eSIR_EXTSCAN_SET_BSSID_HOTLIST_RSP; + break; + case WMI_EXTSCAN_GET_CACHED_RESULTS_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + event_type = eSIR_EXTSCAN_CACHED_RESULTS_RSP; + break; + case WMI_EXTSCAN_CONFIGURE_HOTLIST_SSID_MONITOR_CMDID: + extscan_ind->status = event->status; + extscan_ind->request_id = event->request_id; + if (event->mode == WMI_EXTSCAN_MODE_STOP) + event_type = + eSIR_EXTSCAN_RESET_SSID_HOTLIST_RSP; + else + event_type = + eSIR_EXTSCAN_SET_SSID_HOTLIST_RSP; + break; + default: + wma_err("Unknown event(%d) from target", event->status); + qdf_mem_free(extscan_ind); + return -EINVAL; + } + mac->sme.ext_scan_ind_cb(mac->hdd_handle, event_type, extscan_ind); + wma_debug("sending event to umac for requestid %u with status %d", + extscan_ind->request_id, extscan_ind->status); + qdf_mem_free(extscan_ind); + return 0; +} + +/** + * wma_extscan_operations_event_handler() - extscan operation event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles different operations related event and indicate + * upper layers with appropriate callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_operations_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *param_buf; + wmi_extscan_operation_event_fixed_param *oprn_event; + tSirExtScanOnScanEventIndParams *oprn_ind; + uint32_t cnt; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_OPERATION_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid scan operation event"); + return -EINVAL; + } + oprn_event = param_buf->fixed_param; + oprn_ind = qdf_mem_malloc(sizeof(*oprn_ind)); + if (!oprn_ind) + return -ENOMEM; + + oprn_ind->requestId = oprn_event->request_id; + + switch (oprn_event->event) { + case WMI_EXTSCAN_BUCKET_COMPLETED_EVENT: + oprn_ind->status = 0; + goto exit_handler; + case WMI_EXTSCAN_CYCLE_STARTED_EVENT: + wma_debug("received WMI_EXTSCAN_CYCLE_STARTED_EVENT"); + + if (oprn_event->num_buckets > param_buf->num_bucket_id) { + wma_err("FW mesg num_buk %d more than TLV hdr %d", + oprn_event->num_buckets, + param_buf->num_bucket_id); + qdf_mem_free(oprn_ind); + return -EINVAL; + } + + cds_host_diag_log_work(&wma->extscan_wake_lock, + WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); + qdf_wake_lock_timeout_acquire(&wma->extscan_wake_lock, + WMA_EXTSCAN_CYCLE_WAKE_LOCK_DURATION); + oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_STARTED_EVENT; + oprn_ind->status = 0; + oprn_ind->buckets_scanned = 0; + for (cnt = 0; cnt < oprn_event->num_buckets; cnt++) + oprn_ind->buckets_scanned |= + (1 << param_buf->bucket_id[cnt]); + wma_debug("num_buckets %u request_id %u buckets_scanned %u", + oprn_event->num_buckets, oprn_ind->requestId, + oprn_ind->buckets_scanned); + break; + case WMI_EXTSCAN_CYCLE_COMPLETED_EVENT: + wma_debug("received WMI_EXTSCAN_CYCLE_COMPLETED_EVENT"); + qdf_wake_lock_release(&wma->extscan_wake_lock, + WIFI_POWER_EVENT_WAKELOCK_EXT_SCAN); + oprn_ind->scanEventType = WIFI_EXTSCAN_CYCLE_COMPLETED_EVENT; + oprn_ind->status = 0; + /* Set bucket scanned mask to zero on cycle complete */ + oprn_ind->buckets_scanned = 0; + break; + case WMI_EXTSCAN_BUCKET_STARTED_EVENT: + wma_debug("received WMI_EXTSCAN_BUCKET_STARTED_EVENT"); + oprn_ind->scanEventType = WIFI_EXTSCAN_BUCKET_STARTED_EVENT; + oprn_ind->status = 0; + goto exit_handler; + case WMI_EXTSCAN_THRESHOLD_NUM_SCANS: + wma_debug("received WMI_EXTSCAN_THRESHOLD_NUM_SCANS"); + oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_NUM_SCANS; + oprn_ind->status = 0; + break; + case WMI_EXTSCAN_THRESHOLD_PERCENT: + wma_debug("received WMI_EXTSCAN_THRESHOLD_PERCENT"); + oprn_ind->scanEventType = WIFI_EXTSCAN_THRESHOLD_PERCENT; + oprn_ind->status = 0; + break; + default: + wma_err("Unknown event(%d) from target", oprn_event->event); + qdf_mem_free(oprn_ind); + return -EINVAL; + } + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_SCAN_PROGRESS_EVENT_IND, oprn_ind); + wma_debug("sending scan progress event to hdd"); +exit_handler: + qdf_mem_free(oprn_ind); + return 0; +} + +/** + * wma_extscan_table_usage_event_handler() - extscan table usage event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles table usage related event and indicate + * upper layers with appropriate callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_table_usage_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *param_buf; + wmi_extscan_table_usage_event_fixed_param *event; + tSirExtScanResultsAvailableIndParams *tbl_usg_ind; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_TABLE_USAGE_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid table usage event"); + return -EINVAL; + } + event = param_buf->fixed_param; + tbl_usg_ind = qdf_mem_malloc(sizeof(*tbl_usg_ind)); + if (!tbl_usg_ind) + return -ENOMEM; + + tbl_usg_ind->requestId = event->request_id; + tbl_usg_ind->numResultsAvailable = event->entries_in_use; + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_SCAN_RES_AVAILABLE_IND, + tbl_usg_ind); + wma_debug("sending scan_res available event to hdd"); + qdf_mem_free(tbl_usg_ind); + return 0; +} + +/** + * wma_extscan_capabilities_event_handler() - extscan capabilities event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles capabilities event and indicate + * upper layers with registered callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_capabilities_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *param_buf; + wmi_extscan_capabilities_event_fixed_param *event; + wmi_extscan_cache_capabilities *src_cache; + wmi_extscan_hotlist_monitor_capabilities *src_hotlist; + wmi_extscan_wlan_change_monitor_capabilities *src_change; + struct ext_scan_capabilities_response *dest_capab; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CAPABILITIES_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid capabilities event"); + return -EINVAL; + } + event = param_buf->fixed_param; + src_cache = param_buf->extscan_cache_capabilities; + src_hotlist = param_buf->hotlist_capabilities; + src_change = param_buf->wlan_change_capabilities; + + if (!src_cache || !src_hotlist || !src_change) { + wma_err("Invalid capabilities list"); + return -EINVAL; + } + dest_capab = qdf_mem_malloc(sizeof(*dest_capab)); + if (!dest_capab) + return -ENOMEM; + + dest_capab->requestId = event->request_id; + dest_capab->max_scan_buckets = src_cache->max_buckets; + dest_capab->max_scan_cache_size = src_cache->scan_cache_entry_size; + dest_capab->max_ap_cache_per_scan = src_cache->max_bssid_per_scan; + dest_capab->max_scan_reporting_threshold = + src_cache->max_table_usage_threshold; + + dest_capab->max_hotlist_bssids = src_hotlist->max_hotlist_entries; + dest_capab->max_rssi_sample_size = + src_change->max_rssi_averaging_samples; + dest_capab->max_bssid_history_entries = + src_change->max_rssi_history_entries; + dest_capab->max_significant_wifi_change_aps = + src_change->max_wlan_change_entries; + dest_capab->max_hotlist_ssids = + event->num_extscan_hotlist_ssid; + dest_capab->max_number_epno_networks = + event->num_epno_networks; + dest_capab->max_number_epno_networks_by_ssid = + event->num_epno_networks; + dest_capab->max_number_of_allow_listed_ssid = + event->num_roam_ssid_whitelist; + dest_capab->max_number_of_deny_listed_bssid = + event->num_roam_bssid_blacklist; + dest_capab->status = 0; + + wma_debug("request_id: %u status: %d", + dest_capab->requestId, dest_capab->status); + + wma_debug("Capabilities: max_scan_buckets: %d, max_hotlist_bssids: %d, max_scan_cache_size: %d, max_ap_cache_per_scan: %d", + dest_capab->max_scan_buckets, + dest_capab->max_hotlist_bssids, dest_capab->max_scan_cache_size, + dest_capab->max_ap_cache_per_scan); + wma_debug("max_scan_reporting_threshold: %d, max_rssi_sample_size: %d, max_bssid_history_entries: %d, max_significant_wifi_change_aps: %d", + dest_capab->max_scan_reporting_threshold, + dest_capab->max_rssi_sample_size, + dest_capab->max_bssid_history_entries, + dest_capab->max_significant_wifi_change_aps); + + wma_debug("Capabilities: max_hotlist_ssids: %d, max_number_epno_networks: %d, max_number_epno_networks_by_ssid: %d", + dest_capab->max_hotlist_ssids, + dest_capab->max_number_epno_networks, + dest_capab->max_number_epno_networks_by_ssid); + wma_debug("max_number_of_allow_listed_ssid: %d, max_number_of_deny_listed_bssid: %d", + dest_capab->max_number_of_allow_listed_ssid, + dest_capab->max_number_of_deny_listed_bssid); + + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_GET_CAPABILITIES_IND, dest_capab); + qdf_mem_free(dest_capab); + return 0; +} + +/** + * wma_extscan_hotlist_match_event_handler() - hotlist match event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles hotlist match event and indicate + * upper layers with registered callback. + * + * Return: 0 for success or error code. + */ +int wma_extscan_hotlist_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *param_buf; + wmi_extscan_hotlist_match_event_fixed_param *event; + struct extscan_hotlist_match *dest_hotlist; + tSirWifiScanResult *dest_ap; + wmi_extscan_wlan_descriptor *src_hotlist; + uint32_t numap; + int j, ap_found = 0; + uint32_t buf_len; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) + return -EINVAL; + + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_HOTLIST_MATCH_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid hotlist match event"); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->hotlist_match; + numap = event->total_entries; + + if (!src_hotlist || !numap) { + wma_err("Hotlist AP's list invalid"); + return -EINVAL; + } + if (numap > param_buf->num_hotlist_match) { + wma_err("Invalid no of total enteries %d", numap); + return -EINVAL; + } + if (numap > WMA_EXTSCAN_MAX_HOTLIST_ENTRIES) { + wma_err("Total Entries %u greater than max", numap); + numap = WMA_EXTSCAN_MAX_HOTLIST_ENTRIES; + } + + buf_len = sizeof(wmi_extscan_hotlist_match_event_fixed_param) + + WMI_TLV_HDR_SIZE + + (numap * sizeof(wmi_extscan_wlan_descriptor)); + + if (buf_len > len) { + wma_err("Invalid buf len from FW %d numap %d", len, numap); + return -EINVAL; + } + + dest_hotlist = qdf_mem_malloc(sizeof(*dest_hotlist) + + sizeof(*dest_ap) * numap); + if (!dest_hotlist) + return -ENOMEM; + + dest_ap = &dest_hotlist->ap[0]; + dest_hotlist->numOfAps = numap; + dest_hotlist->requestId = event->config_request_id; + + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + dest_hotlist->moreData = 1; + else + dest_hotlist->moreData = 0; + + wma_debug("Hotlist match: requestId: %u numOfAps: %d", + dest_hotlist->requestId, dest_hotlist->numOfAps); + + /* + * Currently firmware sends only one bss information in-case + * of both hotlist ap found and lost. + */ + for (j = 0; j < numap; j++) { + dest_ap->rssi = 0; + dest_ap->channel = src_hotlist->channel; + dest_ap->ts = src_hotlist->tstamp; + ap_found = src_hotlist->flags & WMI_HOTLIST_FLAG_PRESENCE; + dest_ap->rtt = src_hotlist->rtt; + dest_ap->rtt_sd = src_hotlist->rtt_sd; + dest_ap->beaconPeriod = src_hotlist->beacon_interval; + dest_ap->capability = src_hotlist->capabilities; + dest_ap->ieLength = src_hotlist->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + dest_ap->bssid.bytes); + if (src_hotlist->ssid.ssid_len > WLAN_SSID_MAX_LEN) { + wma_err("Invalid SSID len %d, truncating", + src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = WLAN_SSID_MAX_LEN; + } + qdf_mem_copy(dest_ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + dest_ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + dest_ap++; + src_hotlist++; + } + dest_hotlist->ap_found = ap_found; + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_HOTLIST_MATCH_IND, dest_hotlist); + wma_debug("sending hotlist match event to hdd"); + qdf_mem_free(dest_hotlist); + return 0; +} + +/** wma_extscan_find_unique_scan_ids() - find unique scan ids + * @cmd_param_info: event data. + * + * This utility function parses the input bss table of information + * and find the unique number of scan ids + * + * Return: 0 on success; error number otherwise + */ +static int wma_extscan_find_unique_scan_ids(const u_int8_t *cmd_param_info) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + int prev_scan_id, scan_ids_cnt, i; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + + /* Find the unique number of scan_id's for grouping */ + prev_scan_id = src_rssi->scan_cycle_id; + scan_ids_cnt = 1; + for (i = 1; i < param_buf->num_rssi_list; i++) { + src_rssi++; + + if (prev_scan_id != src_rssi->scan_cycle_id) { + scan_ids_cnt++; + prev_scan_id = src_rssi->scan_cycle_id; + } + } + + return scan_ids_cnt; +} + +/** wma_fill_num_results_per_scan_id() - fill number of bss per scan id + * @cmd_param_info: event data. + * @scan_id_group: pointer to scan id group. + * + * This utility function parses the input bss table of information + * and finds how many bss are there per unique scan id. + * + * Return: 0 on success; error number otherwise + */ +static int wma_fill_num_results_per_scan_id(const u_int8_t *cmd_param_info, + struct extscan_cached_scan_result *scan_id_group) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + struct extscan_cached_scan_result *t_scan_id_grp; + int i, prev_scan_id; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + t_scan_id_grp = scan_id_group; + + prev_scan_id = src_rssi->scan_cycle_id; + + t_scan_id_grp->scan_id = src_rssi->scan_cycle_id; + t_scan_id_grp->flags = src_rssi->flags; + t_scan_id_grp->buckets_scanned = src_rssi->buckets_scanned; + t_scan_id_grp->num_results = 1; + for (i = 1; i < param_buf->num_rssi_list; i++) { + src_rssi++; + if (prev_scan_id == src_rssi->scan_cycle_id) { + t_scan_id_grp->num_results++; + } else { + t_scan_id_grp++; + prev_scan_id = t_scan_id_grp->scan_id = + src_rssi->scan_cycle_id; + t_scan_id_grp->flags = src_rssi->flags; + t_scan_id_grp->buckets_scanned = + src_rssi->buckets_scanned; + t_scan_id_grp->num_results = 1; + } + } + return 0; +} + +/** wma_group_num_bss_to_scan_id() - group bss to scan id table + * @cmd_param_info: event data. + * @cached_result: pointer to cached table. + * + * This function reads the bss information from the format + * ------------------------------------------------------------------------ + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_1 | flags | + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_2 | flags | + * ........................................................................ + * | bss info {rssi, channel, ssid, bssid, timestamp} | scan id_N | flags | + * ------------------------------------------------------------------------ + * + * and converts it into the below format and store it + * + * ------------------------------------------------------------------------ + * | scan id_1 | -> bss info_1 -> bss info_2 -> .... bss info_M1 + * | scan id_2 | -> bss info_1 -> bss info_2 -> .... bss info_M2 + * ...................... + * | scan id_N | -> bss info_1 -> bss info_2 -> .... bss info_Mn + * ------------------------------------------------------------------------ + * + * Return: 0 on success; error number otherwise + */ +static int wma_group_num_bss_to_scan_id(const u_int8_t *cmd_param_info, + struct extscan_cached_scan_results *cached_result) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + struct extscan_cached_scan_results *t_cached_result; + struct extscan_cached_scan_result *t_scan_id_grp; + int i, j; + uint32_t total_scan_num_results = 0; + tSirWifiScanResult *ap; + + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + t_cached_result = cached_result; + t_scan_id_grp = &t_cached_result->result[0]; + + for (i = 0; i < t_cached_result->num_scan_ids; i++) { + total_scan_num_results += t_scan_id_grp->num_results; + t_scan_id_grp++; + } + + if (total_scan_num_results > param_buf->num_bssid_list) { + wma_err("total_scan_num_results %d, num_bssid_list %d", + total_scan_num_results, + param_buf->num_bssid_list); + return -EINVAL; + } + + t_scan_id_grp = &t_cached_result->result[0]; + wma_debug("num_scan_ids:%d", + t_cached_result->num_scan_ids); + for (i = 0; i < t_cached_result->num_scan_ids; i++) { + wma_debug("num_results:%d", t_scan_id_grp->num_results); + t_scan_id_grp->ap = qdf_mem_malloc(t_scan_id_grp->num_results * + sizeof(*ap)); + if (!t_scan_id_grp->ap) + return -ENOMEM; + + ap = &t_scan_id_grp->ap[0]; + for (j = 0; j < t_scan_id_grp->num_results; j++) { + ap->channel = src_hotlist->channel; + ap->ts = WMA_MSEC_TO_USEC(src_rssi->tstamp); + ap->rtt = src_hotlist->rtt; + ap->rtt_sd = src_hotlist->rtt_sd; + ap->beaconPeriod = src_hotlist->beacon_interval; + ap->capability = src_hotlist->capabilities; + ap->ieLength = src_hotlist->ie_length; + + /* Firmware already applied noise floor adjustment and + * due to WMI interface "UINT32 rssi", host driver + * receives a positive value, hence convert to + * signed char to get the absolute rssi. + */ + ap->rssi = (signed char) src_rssi->rssi; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_hotlist->bssid, + ap->bssid.bytes); + + if (src_hotlist->ssid.ssid_len > + WLAN_SSID_MAX_LEN) { + wma_debug("Invalid SSID len %d, truncating", + src_hotlist->ssid.ssid_len); + src_hotlist->ssid.ssid_len = + WLAN_SSID_MAX_LEN; + } + qdf_mem_copy(ap->ssid, src_hotlist->ssid.ssid, + src_hotlist->ssid.ssid_len); + ap->ssid[src_hotlist->ssid.ssid_len] = '\0'; + ap++; + src_rssi++; + src_hotlist++; + } + t_scan_id_grp++; + } + return 0; +} + +/** + * wma_extscan_cached_results_event_handler() - cached results event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length of @cmd_param_info + * + * This function handles cached results event and indicate + * cached results to upper layer. + * + * Return: 0 for success or error code. + */ +int wma_extscan_cached_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_cached_results_event_fixed_param *event; + struct extscan_cached_scan_results *dest_cachelist; + struct extscan_cached_scan_result *dest_result; + struct extscan_cached_scan_results empty_cachelist; + wmi_extscan_wlan_descriptor *src_hotlist; + wmi_extscan_rssi_info *src_rssi; + int i, moredata, scan_ids_cnt, buf_len, status; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t total_len; + bool excess_data = false; + + if (!mac) { + wma_err("Invalid mac"); + return -EINVAL; + } + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_CACHED_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid cached results event"); + return -EINVAL; + } + event = param_buf->fixed_param; + src_hotlist = param_buf->bssid_list; + src_rssi = param_buf->rssi_list; + wma_debug("Total_entries: %u first_entry_index: %u num_entries_in_page: %d", + event->total_entries, + event->first_entry_index, + event->num_entries_in_page); + + if (!src_hotlist || !src_rssi || !event->num_entries_in_page) { + wma_warn("Cached results empty, send 0 results"); + goto noresults; + } + + if (event->num_entries_in_page > + (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/sizeof(*src_hotlist) || + event->num_entries_in_page > param_buf->num_bssid_list) { + wma_err("excess num_entries_in_page %d in WMI event. num_bssid_list %d", + event->num_entries_in_page, param_buf->num_bssid_list); + return -EINVAL; + } else { + total_len = sizeof(*event) + + (event->num_entries_in_page * sizeof(*src_hotlist)); + } + for (i = 0; i < event->num_entries_in_page; i++) { + if (src_hotlist[i].ie_length > + WMI_SVC_MSG_MAX_SIZE - total_len) { + excess_data = true; + break; + } else { + total_len += src_hotlist[i].ie_length; + wma_debug("total len IE: %d", total_len); + } + + if (src_hotlist[i].number_rssi_samples > + (WMI_SVC_MSG_MAX_SIZE - total_len) / sizeof(*src_rssi)) { + excess_data = true; + break; + } else { + total_len += (src_hotlist[i].number_rssi_samples * + sizeof(*src_rssi)); + wma_debug("total len RSSI samples: %d", total_len); + } + } + if (excess_data) { + wma_err("excess data in WMI event"); + return -EINVAL; + } + + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) + moredata = 1; + else + moredata = 0; + + dest_cachelist = qdf_mem_malloc(sizeof(*dest_cachelist)); + if (!dest_cachelist) + return -ENOMEM; + + qdf_mem_zero(dest_cachelist, sizeof(*dest_cachelist)); + dest_cachelist->request_id = event->request_id; + dest_cachelist->more_data = moredata; + + scan_ids_cnt = wma_extscan_find_unique_scan_ids(cmd_param_info); + wma_debug("scan_ids_cnt %d", scan_ids_cnt); + dest_cachelist->num_scan_ids = scan_ids_cnt; + + buf_len = sizeof(*dest_result) * scan_ids_cnt; + dest_cachelist->result = qdf_mem_malloc(buf_len); + if (!dest_cachelist->result) { + qdf_mem_free(dest_cachelist); + return -ENOMEM; + } + + dest_result = dest_cachelist->result; + wma_fill_num_results_per_scan_id(cmd_param_info, dest_result); + + status = wma_group_num_bss_to_scan_id(cmd_param_info, dest_cachelist); + if (!status) + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + dest_cachelist); + else + wma_debug("wma_group_num_bss_to_scan_id failed, not calling callback"); + + dest_result = dest_cachelist->result; + for (i = 0; i < dest_cachelist->num_scan_ids; i++) { + if (dest_result->ap) + qdf_mem_free(dest_result->ap); + dest_result++; + } + qdf_mem_free(dest_cachelist->result); + qdf_mem_free(dest_cachelist); + return status; + +noresults: + empty_cachelist.request_id = event->request_id; + empty_cachelist.more_data = 0; + empty_cachelist.num_scan_ids = 0; + + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_CACHED_RESULTS_IND, + &empty_cachelist); + return 0; +} + +/** + * wma_extscan_change_results_event_handler() - change results event handler + * @handle: wma handle + * @cmd_param_info: event buffer + * @len: length + * + * This function handles change results event and indicate + * change results to upper layer. + * + * Return: 0 for success or error code. + */ +int wma_extscan_change_results_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *param_buf; + wmi_extscan_wlan_change_results_event_fixed_param *event; + tSirWifiSignificantChangeEvent *dest_chglist; + tSirWifiSignificantChange *dest_ap; + wmi_extscan_wlan_change_result_bssid *src_chglist; + + uint32_t numap; + int i, k; + uint8_t *src_rssi; + int count = 0; + int moredata; + uint32_t rssi_num = 0; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + uint32_t buf_len; + bool excess_data = false; + + if (!mac) { + wma_err("Invalid mac"); + return -EINVAL; + } + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + param_buf = (WMI_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid change monitor event"); + return -EINVAL; + } + event = param_buf->fixed_param; + src_chglist = param_buf->bssid_signal_descriptor_list; + src_rssi = param_buf->rssi_list; + numap = event->num_entries_in_page; + + if (!src_chglist || !numap) { + wma_err("Results invalid"); + return -EINVAL; + } + if (numap > param_buf->num_bssid_signal_descriptor_list) { + wma_err("Invalid num of entries in page: %d", numap); + return -EINVAL; + } + for (i = 0; i < numap; i++) { + if (src_chglist->num_rssi_samples > (UINT_MAX - rssi_num)) { + wma_err("Invalid num of rssi samples %d numap %d rssi_num %d", + src_chglist->num_rssi_samples, + numap, rssi_num); + return -EINVAL; + } + rssi_num += src_chglist->num_rssi_samples; + src_chglist++; + } + src_chglist = param_buf->bssid_signal_descriptor_list; + + if (event->first_entry_index + + event->num_entries_in_page < event->total_entries) { + moredata = 1; + } else { + moredata = 0; + } + + do { + if (event->num_entries_in_page > + (WMI_SVC_MSG_MAX_SIZE - sizeof(*event))/ + sizeof(*src_chglist)) { + excess_data = true; + break; + } else { + buf_len = + sizeof(*event) + (event->num_entries_in_page * + sizeof(*src_chglist)); + } + if (rssi_num > + (WMI_SVC_MSG_MAX_SIZE - buf_len)/sizeof(int32_t)) { + excess_data = true; + break; + } + } while (0); + + if (excess_data) { + wma_err("buffer len exceeds WMI payload,numap:%d, rssi_num:%d", + numap, rssi_num); + QDF_ASSERT(0); + return -EINVAL; + } + dest_chglist = qdf_mem_malloc(sizeof(*dest_chglist) + + sizeof(*dest_ap) * numap + + sizeof(int32_t) * rssi_num); + if (!dest_chglist) + return -ENOMEM; + + dest_ap = &dest_chglist->ap[0]; + for (i = 0; i < numap; i++) { + dest_ap->channel = src_chglist->channel; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&src_chglist->bssid, + dest_ap->bssid.bytes); + dest_ap->numOfRssi = src_chglist->num_rssi_samples; + if (dest_ap->numOfRssi) { + if ((dest_ap->numOfRssi + count) > + param_buf->num_rssi_list) { + wma_err("Invalid num in rssi list: %d", + dest_ap->numOfRssi); + qdf_mem_free(dest_chglist); + return -EINVAL; + } + for (k = 0; k < dest_ap->numOfRssi; k++) { + dest_ap->rssi[k] = WMA_TGT_NOISE_FLOOR_DBM + + src_rssi[count++]; + } + } + dest_ap = (tSirWifiSignificantChange *)((char *)dest_ap + + dest_ap->numOfRssi * sizeof(int32_t) + + sizeof(*dest_ap)); + src_chglist++; + } + dest_chglist->requestId = event->request_id; + dest_chglist->moreData = moredata; + dest_chglist->numResults = numap; + + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_EXTSCAN_SIGNIFICANT_WIFI_CHANGE_RESULTS_IND, + dest_chglist); + wma_debug("sending change monitor results"); + qdf_mem_free(dest_chglist); + return 0; +} + +/** + * wma_passpoint_match_event_handler() - passpoint match found event handler + * @handle: WMA handle + * @cmd_param_info: event data + * @len: event data length + * + * This is the passpoint match found event handler; it reads event data from + * @cmd_param_info and fill in the destination buffer and sends indication + * up layer. + * + * Return: 0 on success; error number otherwise + */ +int wma_passpoint_match_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *param_buf; + wmi_passpoint_event_hdr *event; + struct wifi_passpoint_match *dest_match; + tSirWifiScanResult *dest_ap; + uint8_t *buf_ptr; + uint32_t buf_len = 0; + bool excess_data = false; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_err("Invalid mac"); + return -EINVAL; + } + if (!mac->sme.ext_scan_ind_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + + param_buf = (WMI_PASSPOINT_MATCH_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + wma_err("Invalid passpoint match event"); + return -EINVAL; + } + event = param_buf->fixed_param; + buf_ptr = (uint8_t *)param_buf->fixed_param; + + do { + if (event->ie_length > (WMI_SVC_MSG_MAX_SIZE)) { + excess_data = true; + break; + } else { + buf_len = event->ie_length; + } + + if (event->anqp_length > (WMI_SVC_MSG_MAX_SIZE)) { + excess_data = true; + break; + } else { + buf_len += event->anqp_length; + } + + } while (0); + + if (excess_data || buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*event)) || + buf_len > (WMI_SVC_MSG_MAX_SIZE - sizeof(*dest_match)) || + (event->ie_length + event->anqp_length) > param_buf->num_bufp) { + wma_err("IE Length: %u or ANQP Length: %u is huge, num_bufp: %u", + event->ie_length, event->anqp_length, + param_buf->num_bufp); + return -EINVAL; + } + + if (event->ssid.ssid_len > WLAN_SSID_MAX_LEN) { + wma_debug("Invalid ssid len %d, truncating", + event->ssid.ssid_len); + event->ssid.ssid_len = WLAN_SSID_MAX_LEN; + } + + dest_match = qdf_mem_malloc(sizeof(*dest_match) + buf_len); + if (!dest_match) + return -EINVAL; + + dest_ap = &dest_match->ap; + dest_match->request_id = 0; + dest_match->id = event->id; + dest_match->anqp_len = event->anqp_length; + wma_info("passpoint match: id: %u anqp length %u", + dest_match->id, dest_match->anqp_len); + + dest_ap->channel = event->channel_mhz; + dest_ap->ts = event->timestamp; + dest_ap->rtt = event->rtt; + dest_ap->rssi = event->rssi; + dest_ap->rtt_sd = event->rtt_sd; + dest_ap->beaconPeriod = event->beacon_period; + dest_ap->capability = event->capability; + dest_ap->ieLength = event->ie_length; + WMI_MAC_ADDR_TO_CHAR_ARRAY(&event->bssid, dest_ap->bssid.bytes); + qdf_mem_copy(dest_ap->ssid, event->ssid.ssid, + event->ssid.ssid_len); + dest_ap->ssid[event->ssid.ssid_len] = '\0'; + qdf_mem_copy(dest_ap->ieData, buf_ptr + sizeof(*event) + + WMI_TLV_HDR_SIZE, dest_ap->ieLength); + qdf_mem_copy(dest_match->anqp, buf_ptr + sizeof(*event) + + WMI_TLV_HDR_SIZE + dest_ap->ieLength, + dest_match->anqp_len); + + mac->sme.ext_scan_ind_cb(mac->hdd_handle, + eSIR_PASSPOINT_NETWORK_FOUND_IND, + dest_match); + wma_debug("sending passpoint match event to hdd"); + qdf_mem_free(dest_match); + return 0; +} + +QDF_STATUS wma_start_extscan(tp_wma_handle wma, + struct wifi_scan_cmd_req_params *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_FAILURE; + } + + if (!params) { + wma_err("NULL param"); + return QDF_STATUS_E_NOMEM; + } + + status = wmi_unified_start_extscan_cmd(wmi_handle, params); + if (QDF_IS_STATUS_SUCCESS(status)) + wma->interfaces[params->vdev_id].extscan_in_progress = true; + + wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); + + return status; +} + +QDF_STATUS wma_stop_extscan(tp_wma_handle wma, + struct extscan_stop_req_params *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_FAILURE; + } + + status = wmi_unified_stop_extscan_cmd(wmi_handle, params); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + wma->interfaces[params->vdev_id].extscan_in_progress = false; + wma_debug("Extscan stop request sent successfully for vdev %d", + params->vdev_id); + + return status; +} + +QDF_STATUS wma_extscan_start_hotlist_monitor(tp_wma_handle wma, + struct extscan_bssid_hotlist_set_params *params) +{ + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!params) { + wma_err("Invalid params"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_extscan_start_hotlist_monitor_cmd(wmi_handle, + params); +} + +QDF_STATUS wma_extscan_stop_hotlist_monitor(tp_wma_handle wma, + struct extscan_bssid_hotlist_reset_params *params) +{ + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!params) { + wma_err("Invalid params"); + return QDF_STATUS_E_INVAL; + } + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_extscan_stop_hotlist_monitor_cmd(wmi_handle, + params); +} + +QDF_STATUS +wma_extscan_start_change_monitor(tp_wma_handle wma, + struct extscan_set_sig_changereq_params *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!params) { + wma_err("NULL params"); + return QDF_STATUS_E_NOMEM; + } + + status = wmi_unified_extscan_start_change_monitor_cmd(wmi_handle, + params); + return status; +} + +QDF_STATUS wma_extscan_stop_change_monitor(tp_wma_handle wma, + struct extscan_capabilities_reset_params *params) +{ + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("ext scan not enabled"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_extscan_stop_change_monitor_cmd(wmi_handle, + params); +} + +QDF_STATUS +wma_extscan_get_cached_results(tp_wma_handle wma, + struct extscan_cached_result_params *params) +{ + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_extscan_get_cached_results_cmd(wmi_handle, + params); +} + +QDF_STATUS +wma_extscan_get_capabilities(tp_wma_handle wma, + struct extscan_capabilities_params *params) +{ + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_FAILURE; + } + + return wmi_unified_extscan_get_capabilities_cmd(wmi_handle, + params); +} + +QDF_STATUS wma_set_epno_network_list(tp_wma_handle wma, + struct wifi_enhanced_pno_params *req) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wma_debug("Enter"); + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_FAILURE; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_FAILURE; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + status = wmi_unified_set_epno_network_list_cmd(wmi_handle, req); + wma_debug("Exit, vdev %d, status %d", req->vdev_id, status); + + return status; +} + +QDF_STATUS +wma_set_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req_param *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wma_debug("Enter"); + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_FAILURE; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_FAILURE; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + status = wmi_unified_set_passpoint_network_list_cmd(wmi_handle, + params); + wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); + + return status; +} + +QDF_STATUS +wma_reset_passpoint_network_list(tp_wma_handle wma, + struct wifi_passpoint_req_param *params) +{ + QDF_STATUS status; + struct wmi_unified *wmi_handle; + + wma_debug("Enter"); + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_FAILURE; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_FAILURE; + + if (!wmi_service_enabled(wmi_handle, wmi_service_extscan)) { + wma_err("extscan not enabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + status = wmi_unified_reset_passpoint_network_list_cmd(wmi_handle, + params); + wma_debug("Exit, vdev %d, status %d", params->vdev_id, status); + + return status; +} + +#endif + +QDF_STATUS wma_scan_probe_setoui(tp_wma_handle wma, + struct scan_mac_oui *set_oui) +{ + struct wmi_unified *wmi_handle; + + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + if (!wma_is_vdev_valid(set_oui->vdev_id)) { + wma_err("vdev_id: %d is not active", set_oui->vdev_id); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_scan_probe_setoui_cmd(wmi_handle, set_oui); +} + +/** + * wma_roam_better_ap_handler() - better ap event handler + * @wma: wma handle + * @vdev_id: vdev id + * + * Handler for WMI_ROAM_REASON_BETTER_AP event from roam firmware in Rome. + * This event means roam algorithm in Rome has found a better matching + * candidate AP. The indication is sent to SME. + * + * Return: none + */ +void wma_roam_better_ap_handler(tp_wma_handle wma, uint32_t vdev_id) +{ + struct scheduler_msg msg = {0}; + QDF_STATUS status; + struct cm_host_roam_start_ind *ind; + + ind = qdf_mem_malloc(sizeof(*ind)); + if (!ind) + return; + + ind->pdev = wma->pdev; + ind->vdev_id = vdev_id; + msg.bodyptr = ind; + msg.callback = wlan_cm_host_roam_start; + wma_debug("Posting ROam start ind to connection manager, vdev %d", + vdev_id); + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_OS_IF, + QDF_MODULE_ID_SCAN, &msg); + + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(msg.bodyptr); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +/** + * wma_invalid_roam_reason_handler() - Handle Invalid roam notification + * @wma: wma handle + * @vdev_id: vdev id + * @op_code: Operation to be done by the callback + * + * This function calls pe and csr callbacks with proper op_code + * + * Return: None + */ +static void wma_invalid_roam_reason_handler(tp_wma_handle wma_handle, + uint32_t vdev_id, + enum cm_roam_notif notif) +{ + struct roam_offload_synch_ind *roam_synch_data; + enum sir_roam_op_code op_code; + + if (notif == CM_ROAM_NOTIF_ROAM_START) { + op_code = SIR_ROAMING_START; + } else if (notif == CM_ROAM_NOTIF_ROAM_ABORT) { + op_code = SIR_ROAMING_ABORT; + lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); + } else { + wma_debug("Invalid notif %d", notif); + return; + } + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (!roam_synch_data) + return; + + roam_synch_data->roamed_vdev_id = vdev_id; + if (notif != CM_ROAM_NOTIF_ROAM_START) + wma_handle->pe_roam_synch_cb(wma_handle->mac_context, + roam_synch_data->roamed_vdev_id, + roam_synch_data, 0, op_code); + + if (notif == CM_ROAM_NOTIF_ROAM_START) + cm_fw_roam_start_req(wma_handle->psoc, vdev_id); + else + cm_fw_roam_abort_req(wma_handle->psoc, vdev_id); + + qdf_mem_free(roam_synch_data); +} + +void wma_handle_roam_sync_timeout(tp_wma_handle wma_handle, + struct roam_sync_timeout_timer_info *info) +{ + wma_invalid_roam_reason_handler(wma_handle, info->vdev_id, + CM_ROAM_NOTIF_ROAM_ABORT); +} + +void cm_invalid_roam_reason_handler(uint32_t vdev_id, enum cm_roam_notif notif, + uint32_t reason) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + wma_invalid_roam_reason_handler(wma_handle, vdev_id, notif); + + if (notif == CM_ROAM_NOTIF_SCAN_START || + notif == CM_ROAM_NOTIF_SCAN_END) + cm_report_roam_rt_stats(wma_handle->psoc, vdev_id, + ROAM_RT_STATS_TYPE_SCAN_STATE, + NULL, notif, 0, reason); +} +#endif + +static void +wma_handle_roam_reason_invoke_roam_fail(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t notif_params) +{ + struct roam_offload_synch_ind *roam_synch_data; + + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (!roam_synch_data) + return; + + lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); + roam_synch_data->roamed_vdev_id = vdev_id; + cm_fw_roam_invoke_fail(wma_handle->psoc, vdev_id); + wlan_cm_update_roam_states(wma_handle->psoc, vdev_id, + notif_params, + ROAM_INVOKE_FAIL_REASON); + qdf_mem_free(roam_synch_data); +} + +static void wma_handle_roam_reason_btm(uint8_t vdev_id) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + /* + * This event is received from firmware if firmware is unable to + * find candidate AP after roam scan and BTM request from AP + * has disassoc imminent bit set. + */ + wma_debug("Kickout due to btm request"); + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BTM, vdev_id, NULL); + wma_handle_disconnect_reason(wma_handle, vdev_id, + HAL_DEL_STA_REASON_CODE_BTM_DISASSOC_IMMINENT); +} + +static void wma_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + /* + * WMI_ROAM_REASON_BMISS can get called in soft IRQ context, so + * avoid using CSR/PE structure directly + */ + wma_debug("Beacon Miss for vdevid %x", vdev_id); + mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi); + wma_beacon_miss_handler(wma_handle, vdev_id, rssi); + wma_sta_kickout_event(HOST_STA_KICKOUT_REASON_BMISS, vdev_id, NULL); +} + +static void wma_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + /* + * WMI_ROAM_REASON_BETTER_AP can get called in soft IRQ context, + * so avoid using CSR/PE structure directly. + */ + wma_debug("Better AP found for vdevid %x, rssi %d", vdev_id, rssi); + mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev, + false); + wma_roam_better_ap_handler(wma_handle, vdev_id); +} + +static void wma_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + /* + * WMI_ROAM_REASON_SUITABLE_AP can get called in soft IRQ + * context, so avoid using CSR/PE structure directly. + */ + mlme_set_roam_reason_better_ap(wma_handle->interfaces[vdev_id].vdev, + true); + mlme_set_hb_ap_rssi(wma_handle->interfaces[vdev_id].vdev, rssi); + wma_debug("Bmiss scan AP found for vdevid %x, rssi %d", vdev_id, rssi); + wma_roam_better_ap_handler(wma_handle, vdev_id); +} + +static void +wma_update_pdev_hw_mode_trans_ind(tp_wma_handle wma, + struct cm_hw_mode_trans_ind *trans_ind) +{ + uint32_t i; + + /* Store the vdev-mac map in WMA and send to policy manager */ + for (i = 0; i < trans_ind->num_vdev_mac_entries; i++) + wma_update_intf_hw_mode_params( + trans_ind->vdev_mac_map[i].vdev_id, + trans_ind->vdev_mac_map[i].mac_id, + trans_ind->new_hw_mode_index); + + wma->old_hw_mode_index = trans_ind->old_hw_mode_index; + wma->new_hw_mode_index = trans_ind->new_hw_mode_index; + policy_mgr_update_new_hw_mode_index(wma->psoc, + trans_ind->new_hw_mode_index); + policy_mgr_update_old_hw_mode_index(wma->psoc, + trans_ind->old_hw_mode_index); + + wma_debug("Updated: old_hw_mode_index:%d new_hw_mode_index:%d", + wma->old_hw_mode_index, wma->new_hw_mode_index); +} + +static void +wma_handle_hw_mode_trans_ind(tp_wma_handle wma_handle, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind) +{ + struct scheduler_msg sme_msg = {0}; + QDF_STATUS status; + + if (hw_mode_trans_ind) { + wma_update_pdev_hw_mode_trans_ind(wma_handle, + hw_mode_trans_ind); + wma_debug("Update HW mode"); + sme_msg.type = eWNI_SME_HW_MODE_TRANS_IND; + sme_msg.bodyptr = hw_mode_trans_ind; + + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(hw_mode_trans_ind); + } else { + wma_debug("hw_mode transition fixed param is NULL"); + } +} + +int cm_rso_cmd_status_event_handler(uint8_t vdev_id, enum cm_roam_notif notif) +{ + return wma_rso_cmd_status_event_handler(vdev_id, notif); +} + +void +cm_handle_roam_reason_invoke_roam_fail(uint8_t vdev_id, uint32_t notif_params, + struct cm_hw_mode_trans_ind *trans_ind) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + wma_handle_hw_mode_trans_ind(wma_handle, trans_ind); + wma_handle_roam_reason_invoke_roam_fail(wma_handle, vdev_id, + notif_params); + cm_report_roam_rt_stats(wma_handle->psoc, vdev_id, + ROAM_RT_STATS_TYPE_INVOKE_FAIL_REASON, + NULL, notif_params, 0, 0); +} + +void +cm_handle_roam_sync_update_hw_mode(struct cm_hw_mode_trans_ind *trans_ind) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct cm_hw_mode_trans_ind *trans_ind_data; + + if (!wma_handle) { + wma_err("invalid wma handle"); + return; + } + trans_ind_data = qdf_mem_malloc(sizeof(*trans_ind_data)); + if (!trans_ind_data) + return; + qdf_mem_copy(trans_ind_data, trans_ind, sizeof(*trans_ind_data)); + wma_handle_hw_mode_trans_ind(wma_handle, trans_ind_data); +} + +static void +wma_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params, + uint32_t notif_params1, + uint8_t *deauth_disassoc_frame) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + struct roam_offload_synch_ind *roam_synch_data; + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + wma_debug("Received disconnect roam event reason:%d", notif_params); + wma_handle->pe_disconnect_cb(wma_handle->mac_context, + vdev_id, + deauth_disassoc_frame, notif_params1, + notif_params); + roam_synch_data = qdf_mem_malloc(sizeof(*roam_synch_data)); + if (!roam_synch_data) + return; + + roam_synch_data->roamed_vdev_id = vdev_id; + qdf_mem_free(roam_synch_data); +} + +void cm_handle_roam_reason_deauth(uint8_t vdev_id, uint32_t notif_params, + uint8_t *deauth_disassoc_frame, + uint32_t frame_len) +{ + wma_handle_roam_reason_deauth(vdev_id, notif_params, frame_len, + deauth_disassoc_frame); +} + +void cm_handle_roam_reason_btm(uint8_t vdev_id) +{ + wma_handle_roam_reason_btm(vdev_id); +} + +void cm_handle_roam_reason_bmiss(uint8_t vdev_id, uint32_t rssi) +{ + wma_handle_roam_reason_bmiss(vdev_id, rssi); +} + +void cm_handle_roam_reason_better_ap(uint8_t vdev_id, uint32_t rssi) +{ + wma_handle_roam_reason_better_ap(vdev_id, rssi); +} + +void cm_handle_roam_reason_suitable_ap(uint8_t vdev_id, uint32_t rssi) +{ + wma_handle_roam_reason_suitable_ap(vdev_id, rssi); +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +static void +wma_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + QDF_ASSERT(0); + return; + } + /* + * WMI_ROAM_REASON_HO_FAILED can get called in soft IRQ context, + * so avoid using CSR/PE structure directly. + */ + wma_err("LFR3:Hand-Off Failed for vdevid %x", vdev_id); + wma_debug("mac addr to avoid " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bssid.bytes)); + wma_handle_hw_mode_trans_ind(wma_handle, hw_mode_trans_ind); + cm_fw_ho_fail_req(wma_handle->psoc, vdev_id, bssid); + lim_sae_auth_cleanup_retry(wma_handle->mac_context, vdev_id); +} + +void +cm_handle_roam_reason_ho_failed(uint8_t vdev_id, struct qdf_mac_addr bssid, + struct cm_hw_mode_trans_ind *hw_mode_trans_ind) +{ + wma_handle_roam_reason_ho_failed(vdev_id, bssid, hw_mode_trans_ind); +} +#endif + +#ifdef FEATURE_LFR_SUBNET_DETECTION +QDF_STATUS wma_set_gateway_params(tp_wma_handle wma, + struct gateway_update_req_param *req) +{ + if (wma_validate_handle(wma)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_set_gateway_params_cmd(wma->wmi_handle, req); +} +#endif /* FEATURE_LFR_SUBNET_DETECTION */ + +/** + * wma_ht40_stop_obss_scan() - ht40 obss stop scan + * @wma: WMA handle + * @vdev_id: vdev identifier + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS wma_ht40_stop_obss_scan(tp_wma_handle wma, int32_t vdev_id) +{ + QDF_STATUS status; + wmi_buf_t buf; + wmi_obss_scan_disable_cmd_fixed_param *cmd; + int len = sizeof(*cmd); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + wma_debug("cmd %x vdev_id %d", WMI_OBSS_SCAN_DISABLE_CMDID, vdev_id); + + cmd = (wmi_obss_scan_disable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_obss_scan_disable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN( + wmi_obss_scan_disable_cmd_fixed_param)); + + cmd->vdev_id = vdev_id; + status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_OBSS_SCAN_DISABLE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +/** + * wma_send_ht40_obss_scanind() - ht40 obss start scan indication + * @wma: WMA handle + * @req: start scan request + * + * Return: Return QDF_STATUS, otherwise appropriate failure code + */ +QDF_STATUS wma_send_ht40_obss_scanind(tp_wma_handle wma, + struct obss_ht40_scanind *req) +{ + QDF_STATUS status; + wmi_buf_t buf; + wmi_obss_scan_enable_cmd_fixed_param *cmd; + int len = 0; + uint8_t *buf_ptr, i; + uint8_t *channel_list; + uint32_t *chan_freq_list; + + len += sizeof(wmi_obss_scan_enable_cmd_fixed_param); + + len += WMI_TLV_HDR_SIZE; + len += qdf_roundup(sizeof(uint8_t) * req->channel_count, + sizeof(uint32_t)); + + len += WMI_TLV_HDR_SIZE; + len += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); + + /* length calculation for chan_freqs */ + len += WMI_TLV_HDR_SIZE; + len += sizeof(uint32_t) * req->channel_count; + + wma_debug("cmdlen %d vdev_id %d channel count %d iefield_len %d", + len, req->bss_id, req->channel_count, req->iefield_len); + + wma_debug("scantype %d active_time %d passive %d Obss interval %d", + req->scan_type, req->obss_active_dwelltime, + req->obss_passive_dwelltime, + req->obss_width_trigger_interval); + + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) + return QDF_STATUS_E_NOMEM; + + cmd = (wmi_obss_scan_enable_cmd_fixed_param *) wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_obss_scan_enable_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN(wmi_obss_scan_enable_cmd_fixed_param)); + + buf_ptr = (uint8_t *) cmd; + + cmd->vdev_id = req->bss_id; + cmd->scan_type = req->scan_type; + cmd->obss_scan_active_dwell = + req->obss_active_dwelltime; + cmd->obss_scan_passive_dwell = + req->obss_passive_dwelltime; + cmd->bss_channel_width_trigger_scan_interval = + req->obss_width_trigger_interval; + cmd->bss_width_channel_transition_delay_factor = + req->bsswidth_ch_trans_delay; + cmd->obss_scan_active_total_per_channel = + req->obss_active_total_per_channel; + cmd->obss_scan_passive_total_per_channel = + req->obss_passive_total_per_channel; + cmd->obss_scan_activity_threshold = + req->obss_activity_threshold; + + cmd->channel_len = req->channel_count; + cmd->forty_mhz_intolerant = req->fortymhz_intolerent; + cmd->current_operating_class = req->current_operatingclass; + cmd->ie_len = req->iefield_len; + + buf_ptr += sizeof(wmi_obss_scan_enable_cmd_fixed_param); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + qdf_roundup(req->channel_count, sizeof(uint32_t))); + + buf_ptr += WMI_TLV_HDR_SIZE; + channel_list = (uint8_t *) buf_ptr; + + for (i = 0; i < req->channel_count; i++) { + channel_list[i] = + wlan_reg_freq_to_chan(wma->pdev, req->chan_freq_list[i]); + wma_nofl_debug("Ch[%d]: %d ", i, channel_list[i]); + } + + buf_ptr += qdf_roundup(sizeof(uint8_t) * req->channel_count, + sizeof(uint32_t)); + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_BYTE, + qdf_roundup(1, sizeof(uint32_t))); + buf_ptr += WMI_TLV_HDR_SIZE; + + buf_ptr += qdf_roundup(sizeof(uint8_t) * 1, sizeof(uint32_t)); + + WMITLV_SET_HDR(buf_ptr, WMITLV_TAG_ARRAY_UINT32, + sizeof(uint32_t) * req->channel_count); + buf_ptr += WMI_TLV_HDR_SIZE; + + chan_freq_list = (uint32_t *)buf_ptr; + for (i = 0; i < req->channel_count; i++) { + chan_freq_list[i] = req->chan_freq_list[i]; + wma_nofl_debug("freq[%u]: %u ", i, chan_freq_list[i]); + } + + buf_ptr += sizeof(uint32_t) * req->channel_count; + + status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_OBSS_SCAN_ENABLE_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); + + return status; +} + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS cm_roam_update_vdev(struct wlan_objmgr_vdev *vdev, + struct roam_offload_synch_ind *sync_ind) +{ + QDF_STATUS status; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct qdf_mac_addr *self_mac_addr; + uint8_t vdev_id; + + if (!wma) + return QDF_STATUS_E_INVAL; + + vdev_id = wlan_vdev_get_id(vdev); + + status = wma_roam_update_vdev(wma, sync_ind, vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + wma_debug("VDEV update failed for roam on %d", vdev_id); + return status; + } + + if (!wlan_vdev_mlme_is_mlo_vdev(vdev)) { + self_mac_addr = + (struct qdf_mac_addr *)wlan_vdev_mlme_get_macaddr(vdev); + goto update_deflink; + } + + if (wlan_vdev_mlme_is_mlo_vdev(vdev) && + wlan_vdev_mlme_is_mlo_link_vdev(vdev)) + return QDF_STATUS_SUCCESS; + + self_mac_addr = (struct qdf_mac_addr *)wlan_vdev_mlme_get_mldaddr(vdev); + +update_deflink: + /* Set the assoc vdev as DP deflink after roaming */ + wlan_dp_update_def_link(wma->psoc, self_mac_addr, vdev); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +cm_roam_pe_sync_callback(struct roam_offload_synch_ind *sync_ind, + uint8_t vdev_id, uint16_t ie_len) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct pe_session *pe_session; + bool new_link_session = false; + QDF_STATUS status; + + if (!wma) + return QDF_STATUS_E_INVAL; + + pe_session = pe_find_session_by_vdev_id(wma->mac_context, vdev_id); + if (!pe_session) { + new_link_session = true; + /* Legacy to MLO roaming: create new pe session */ + status = lim_create_and_fill_link_session(wma->mac_context, + vdev_id, + sync_ind, ie_len); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("MLO ROAM: pe session creation failed vdev id %d", + vdev_id); + return status; + } + } + status = wma->pe_roam_synch_cb(wma->mac_context, + vdev_id, sync_ind, ie_len, + SIR_ROAM_SYNCH_PROPAGATION); + + /* delete newly added pe session in case of failure */ + if (new_link_session && QDF_IS_STATUS_ERROR(status)) { + pe_session = pe_find_session_by_vdev_id(wma->mac_context, + vdev_id); + if (pe_session) + pe_delete_session(wma->mac_context, pe_session); + } + return status; +} + +void cm_update_phymode_on_roam(uint8_t vdev_id, + struct roam_offload_synch_ind *sync_ind) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct qdf_mac_addr link_bssid; + wmi_channel link_chan; + + if (!wma) + return; + + if (is_multi_link_roam(sync_ind)) { + mlo_roam_get_bssid_chan_for_link(vdev_id, sync_ind, + &link_bssid, + &link_chan); + wma_update_phymode_on_roam(wma, &link_bssid, + &link_chan, + &wma->interfaces[vdev_id]); + } else { + wma_update_phymode_on_roam(wma, &sync_ind->bssid, + &sync_ind->chan, + &wma->interfaces[vdev_id]); + } +} + +enum wlan_phymode +wlan_cm_fw_to_host_phymode(WMI_HOST_WLAN_PHY_MODE phymode) +{ + return wma_fw_to_host_phymode(phymode); +} +#endif + +QDF_STATUS +wlan_update_peer_phy_mode(struct wlan_channel *des_chan, + struct wlan_objmgr_vdev *vdev) +{ + return wma_update_bss_peer_phy_mode(des_chan, vdev); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_twt.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_twt.c new file mode 100644 index 0000000000..fb8760cb0d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_twt.c @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_twt.c + * + * WLAN Host Device Driver TWT - Target Wake Time Implementation + */ +#include "wma_twt.h" +#include "wmi_unified_twt_api.h" +#include "wma_internal.h" +#include "wmi_unified_priv.h" + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) + +void wma_update_bcast_twt_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg) +{ +} + +void wma_register_twt_events(tp_wma_handle wma_handle) +{ +} + +void wma_set_twt_peer_caps(tpAddStaParams params, struct peer_assoc_params *cmd) +{ + cmd->twt_requester = params->twt_requestor; + cmd->twt_responder = params->twt_responder; +} + +void wma_update_twt_tgt_cap(tp_wma_handle wh, struct wma_tgt_cfg *tgt_cfg) +{ +} + +void wma_send_twt_enable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf) +{ +} + +void wma_send_twt_disable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf) +{ +} + +QDF_STATUS wma_twt_process_add_dialog(t_wma_handle *wma_handle, + struct wmi_twt_add_dialog_param *params) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_twt_process_del_dialog(t_wma_handle *wma_handle, + struct wmi_twt_del_dialog_param *params) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_twt_process_pause_dialog(t_wma_handle *wma_handle, + struct wmi_twt_pause_dialog_cmd_param *params) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_twt_process_nudge_dialog(t_wma_handle *wma_handle, + struct wmi_twt_nudge_dialog_cmd_param *params) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wma_twt_process_resume_dialog(t_wma_handle *wma_handle, + struct wmi_twt_resume_dialog_cmd_param *params) +{ + return QDF_STATUS_SUCCESS; +} + +#elif WLAN_SUPPORT_TWT +void wma_send_twt_enable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wmi_twt_enable_param twt_enable_params = {0}; + int32_t ret; + + if (!wma) + return; + + twt_enable_params.pdev_id = pdev_id; + twt_enable_params.sta_cong_timer_ms = conf->congestion_timeout; + twt_enable_params.b_twt_enable = conf->bcast_en; + twt_enable_params.ext_conf_present = conf->ext_conf_present; + twt_enable_params.twt_role = conf->role; + twt_enable_params.twt_oper = conf->oper; + ret = wmi_unified_twt_enable_cmd(wma->wmi_handle, &twt_enable_params); + + if (ret) + wma_err("Failed to enable TWT"); +} + +/** + * wma_twt_en_complete_event_handler - TWT enable complete event handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_en_complete_event_handler(void *handle, + uint8_t *event, uint32_t len) +{ + struct wmi_twt_enable_complete_event_param param; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (wma_validate_handle(wma_handle)) + return status; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return status; + + if (!mac) + return status; + + if (wmi_handle->ops->extract_twt_enable_comp_event) + status = wmi_handle->ops->extract_twt_enable_comp_event( + wmi_handle, + event, + ¶m); + wma_debug("TWT: Received TWT enable comp event, status:%d", status); + + if (mac->sme.twt_enable_cb) + mac->sme.twt_enable_cb(mac->hdd_handle, ¶m); + + return status; +} + +void wma_send_twt_disable_cmd(uint32_t pdev_id, + struct twt_enable_disable_conf *conf) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + struct wmi_twt_disable_param twt_disable_params = {0}; + int32_t ret; + + if (!wma) + return; + + twt_disable_params.pdev_id = pdev_id; + twt_disable_params.ext_conf_present = conf->ext_conf_present; + twt_disable_params.twt_role = conf->role; + twt_disable_params.twt_oper = conf->oper; + + ret = wmi_unified_twt_disable_cmd(wma->wmi_handle, &twt_disable_params); + + if (ret) + wma_err("Failed to disable TWT"); +} + +/** + * wma_twt_disable_comp_event_handler- TWT disable complete event handler + * @handle: wma handle + * @data: data buffer + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_disable_comp_event_handler(void *handle, uint8_t *data, + uint32_t len) +{ + struct mac_context *mac; + struct wmi_twt_disable_complete_event event; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + QDF_STATUS status; + + mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + if (!mac) + return -EINVAL; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + wma_debug("TWT: Rcvd TWT disable comp event"); + status = wmi_extract_twt_disable_comp_event(wmi_handle, data, &event); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("TWT disable extract event failed(status=%d)", status); + return -EINVAL; + } + + wma_debug("pdev_id: %d", event.pdev_id); + + if (mac->sme.twt_disable_cb) + mac->sme.twt_disable_cb(mac->hdd_handle); + + return 0; +} + +void wma_set_twt_peer_caps(tpAddStaParams params, struct peer_assoc_params *cmd) +{ + if (params->twt_requestor) + cmd->twt_requester = 1; + if (params->twt_responder) + cmd->twt_responder = 1; +} + +QDF_STATUS wma_twt_process_add_dialog(t_wma_handle *wma_handle, + struct wmi_twt_add_dialog_param *params) +{ + wmi_unified_t wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_twt_add_dialog_cmd(wmi_handle, params); +} + +/** + * wma_twt_add_dialog_complete_event_handler - TWT add dialog complete event + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_add_dialog_complete_event_handler(void *handle, + uint8_t *event, uint32_t len) +{ + struct wma_twt_add_dialog_complete_event *add_dialog_event; + struct scheduler_msg sme_msg = {0}; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + if (!mac) + return -EINVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + add_dialog_event = qdf_mem_malloc(sizeof(*add_dialog_event)); + if (!add_dialog_event) + return -ENOMEM; + + status = wmi_extract_twt_add_dialog_comp_event(wmi_handle, event, + &add_dialog_event->params); + if (QDF_IS_STATUS_ERROR(status)) + goto exit; + + if (add_dialog_event->params.num_additional_twt_params) { + status = wmi_extract_twt_add_dialog_comp_additional_params(wmi_handle, + event, + len, 0, + &add_dialog_event->additional_params); + if (QDF_IS_STATUS_ERROR(status)) + goto exit; + } + + wma_debug("TWT: Extract TWT add dialog event id:%d", + add_dialog_event->params.dialog_id); + + sme_msg.type = eWNI_SME_TWT_ADD_DIALOG_EVENT; + sme_msg.bodyptr = add_dialog_event; + sme_msg.bodyval = 0; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + goto exit; + +exit: + if (QDF_IS_STATUS_ERROR(status)) + qdf_mem_free(add_dialog_event); + + return qdf_status_to_os_return(status); +} + +QDF_STATUS +wma_twt_process_del_dialog(t_wma_handle *wma_handle, + struct wmi_twt_del_dialog_param *params) +{ + wmi_unified_t wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_twt_del_dialog_cmd(wmi_handle, params); +} + +/** + * wma_twt_del_dialog_complete_event_handler - TWT del dialog complete event + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_del_dialog_complete_event_handler(void *handle, + uint8_t *event, uint32_t len) +{ + struct wmi_twt_del_dialog_complete_event_param *param; + struct scheduler_msg sme_msg = {0}; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (wma_validate_handle(wma_handle)) + return status; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return status; + + if (!mac) + return status; + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + status = wmi_extract_twt_del_dialog_comp_event(wmi_handle, event, + param); + wma_debug("TWT: Extract TWT del dlg comp event, status:%d", status); + + sme_msg.type = eWNI_SME_TWT_DEL_DIALOG_EVENT; + sme_msg.bodyptr = param; + sme_msg.bodyval = 0; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return status; +} + +QDF_STATUS +wma_twt_process_pause_dialog(t_wma_handle *wma_handle, + struct wmi_twt_pause_dialog_cmd_param *params) +{ + wmi_unified_t wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_twt_pause_dialog_cmd(wmi_handle, params); +} + +QDF_STATUS +wma_twt_process_nudge_dialog(t_wma_handle *wma_handle, + struct wmi_twt_nudge_dialog_cmd_param *params) +{ + wmi_unified_t wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle, twt nudge dialog failed"); + return QDF_STATUS_E_INVAL; + } + + return wmi_unified_twt_nudge_dialog_cmd(wmi_handle, params); +} + +/** + * wma_twt_pause_dialog_complete_event_handler - TWT pause dlg complete evt + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_pause_dialog_complete_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + struct wmi_twt_pause_dialog_complete_event_param *param; + struct scheduler_msg sme_msg = {0}; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (!mac) + return status; + + if (wma_validate_handle(wma_handle)) + return status; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return status; + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + if (wmi_handle->ops->extract_twt_pause_dialog_comp_event) + status = wmi_handle->ops->extract_twt_pause_dialog_comp_event(wmi_handle, + event, + param); + wma_debug("TWT: Extract pause dialog comp event status:%d", status); + + sme_msg.type = eWNI_SME_TWT_PAUSE_DIALOG_EVENT; + sme_msg.bodyptr = param; + sme_msg.bodyval = 0; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return status; +} + +/** + * wma_twt_nudge_dialog_complete_event_handler - TWT nudge dlg complete evt + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_nudge_dialog_complete_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + struct wmi_twt_nudge_dialog_complete_event_param *param; + struct scheduler_msg sme_msg = {0}; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (!mac) + return status; + + if (wma_validate_handle(wma_handle)) + return status; + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle for TWT nudge dialog complete"); + return status; + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + if (wmi_handle->ops->extract_twt_nudge_dialog_comp_event) + status = wmi_handle->ops->extract_twt_nudge_dialog_comp_event( + wmi_handle, event, param); + + wma_debug("TWT: Extract nudge dialog comp event status:%d", status); + + sme_msg.type = eWNI_SME_TWT_NUDGE_DIALOG_EVENT; + sme_msg.bodyptr = param; + sme_msg.bodyval = 0; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return status; +} +QDF_STATUS +wma_twt_process_resume_dialog(t_wma_handle *wma_handle, + struct wmi_twt_resume_dialog_cmd_param *params) +{ + wmi_unified_t wmi_handle; + + if (wma_validate_handle(wma_handle)) + return QDF_STATUS_E_INVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return QDF_STATUS_E_INVAL; + + return wmi_unified_twt_resume_dialog_cmd(wmi_handle, params); +} + +/** + * wma_twt_notify_event_handler - TWT notify event handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_notify_event_handler(void *handle, uint8_t *event, uint32_t len) +{ + struct wmi_twt_notify_event_param *param; + struct scheduler_msg sme_msg = {0}; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (!mac) + return status; + + if (wma_validate_handle(wma_handle)) + return status; + + wmi_handle = (wmi_unified_t)wma_handle->wmi_handle; + if (!wmi_handle) { + wma_err("Invalid wmi handle for TWT notify event"); + return status; + } + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + if (wmi_handle->ops->extract_twt_notify_event) + status = wmi_handle->ops->extract_twt_notify_event(wmi_handle, + event, + param); + wma_debug("Extract Notify event status:%d", status); + + sme_msg.type = eWNI_SME_TWT_NOTIFY_EVENT; + sme_msg.bodyptr = param; + sme_msg.bodyval = 0; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return 0; +} + +/** + * wma_twt_resume_dialog_complete_event_handler - TWT resume dlg complete evt + * handler + * @handle: wma handle + * @event: buffer with event + * @len: buffer length + * + * Return: 0 on success, negative value on failure + */ +static +int wma_twt_resume_dialog_complete_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + struct wmi_twt_resume_dialog_complete_event_param *param; + struct scheduler_msg sme_msg = {0}; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + int status = -EINVAL; + + if (!mac) + return status; + + if (wma_validate_handle(wma_handle)) + return status; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return status; + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + if (wmi_handle->ops->extract_twt_resume_dialog_comp_event) + status = wmi_handle->ops->extract_twt_resume_dialog_comp_event(wmi_handle, + event, + param); + wma_debug("TWT: Extract resume dialog comp event status:%d", status); + + sme_msg.type = eWNI_SME_TWT_RESUME_DIALOG_EVENT; + sme_msg.bodyptr = param; + sme_msg.bodyval = 0; + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + return status; +} + +static +int wma_twt_ack_complete_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + struct wmi_twt_ack_complete_event_param *param; + tp_wma_handle wma_handle = handle; + wmi_unified_t wmi_handle; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + QDF_STATUS status; + + if (!mac) + return -EINVAL; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + param = qdf_mem_malloc(sizeof(*param)); + if (!param) + return -ENOMEM; + + status = wmi_extract_twt_ack_comp_event(wmi_handle, event, + param); + + wma_debug("TWT: Received TWT ack comp event, status:%d", status); + + if (QDF_IS_STATUS_ERROR(status)) + goto exit; + + if (mac->sme.twt_ack_comp_cb) + mac->sme.twt_ack_comp_cb(param, mac->sme.twt_ack_context_cb); + +exit: + qdf_mem_free(param); + return qdf_status_to_os_return(status); +} + +/** + * wma_update_bcast_twt_support() - update bcost twt support + * @wh: wma handle + * @tgt_cfg: target configuration to be updated + * + * Update braodcast twt support based on service bit. + * + * Return: None + */ +void wma_update_bcast_twt_support(tp_wma_handle wh, + struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wh->wmi_handle, + wmi_service_bcast_twt_support)) + tgt_cfg->legacy_bcast_twt_support = true; + else + tgt_cfg->legacy_bcast_twt_support = false; + + if (wmi_service_enabled(wh->wmi_handle, + wmi_service_twt_bcast_req_support)) + tgt_cfg->twt_bcast_req_support = true; + else + tgt_cfg->twt_bcast_req_support = false; + + if (wmi_service_enabled(wh->wmi_handle, + wmi_service_twt_bcast_resp_support)) + tgt_cfg->twt_bcast_res_support = true; + else + tgt_cfg->twt_bcast_res_support = false; +} + +void wma_update_twt_tgt_cap(tp_wma_handle wh, struct wma_tgt_cfg *tgt_cfg) +{ + if (wmi_service_enabled(wh->wmi_handle, wmi_service_twt_nudge)) + tgt_cfg->twt_nudge_enabled = true; + + if (wmi_service_enabled(wh->wmi_handle, wmi_service_all_twt)) + tgt_cfg->all_twt_enabled = true; + + if (wmi_service_enabled(wh->wmi_handle, wmi_service_twt_statistics)) + tgt_cfg->twt_stats_enabled = true; +} + +void wma_register_twt_events(tp_wma_handle wma_handle) +{ + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_twt_enable_complete_event_id, + wma_twt_en_complete_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_twt_disable_complete_event_id, + wma_twt_disable_comp_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_add_dialog_complete_event_id, + wma_twt_add_dialog_complete_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_del_dialog_complete_event_id, + wma_twt_del_dialog_complete_event_handler, + WMA_RX_WORK_CTX); + + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_pause_dialog_complete_event_id, + wma_twt_pause_dialog_complete_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_resume_dialog_complete_event_id, + wma_twt_resume_dialog_complete_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_nudge_dialog_complete_event_id, + wma_twt_nudge_dialog_complete_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_notify_event_id, + wma_twt_notify_event_handler, + WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler + (wma_handle->wmi_handle, + wmi_twt_ack_complete_event_id, + wma_twt_ack_complete_event_handler, + WMA_RX_WORK_CTX); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_utils.c b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_utils.c new file mode 100644 index 0000000000..10ce12e04e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/core/wma/src/wma_utils.c @@ -0,0 +1,5226 @@ +/* + * Copyright (c) 2013-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wma_utis.c + * This file contains utilities and stats related functions. + */ + +/* Header files */ + +#include "wma.h" +#include "wma_api.h" +#include "cds_api.h" +#include "wmi_unified_api.h" +#include "wlan_qct_sys.h" +#include "wni_api.h" +#include "ani_global.h" +#include "wmi_unified.h" +#include "wni_cfg.h" + +#include "qdf_nbuf.h" +#include "qdf_types.h" +#include "qdf_mem.h" + +#include "wma_types.h" +#include "lim_api.h" +#include "lim_session_utils.h" + +#include "cds_utils.h" + +#if !defined(REMOVE_PKT_LOG) +#include "pktlog_ac.h" +#endif /* REMOVE_PKT_LOG */ + +#include "dbglog_host.h" +#include "csr_api.h" +#include "ol_fw.h" + +#include "wma_internal.h" +#include "wlan_policy_mgr_api.h" +#include "wmi_unified_param.h" +#include "linux/ieee80211.h" +#include +#include +#include "cds_reg_service.h" +#include "target_if.h" +#include +#include +#include "host_diag_core_log.h" +#include +#include <../../core/src/vdev_mgr_ops.h> +#include "cdp_txrx_misc.h" +#include +#include "wlan_mlme_ucfg_api.h" +#include +#include "wma_eht.h" +#include +#include "wlan_dp_ucfg_api.h" + +/* MCS Based rate table */ +/* HT MCS parameters with Nss = 1 */ +static const struct index_data_rate_type mcs_nss1[] = { + /* MCS L20 S20 L40 S40 */ + {0, {65, 72}, {135, 150 } }, + {1, {130, 144}, {270, 300 } }, + {2, {195, 217}, {405, 450 } }, + {3, {260, 289}, {540, 600 } }, + {4, {390, 433}, {815, 900 } }, + {5, {520, 578}, {1080, 1200} }, + {6, {585, 650}, {1215, 1350} }, + {7, {650, 722}, {1350, 1500} } +}; + +/* HT MCS parameters with Nss = 2 */ +static const struct index_data_rate_type mcs_nss2[] = { + /* MCS L20 S20 L40 S40 */ + {0, {130, 144}, {270, 300 } }, + {1, {260, 289}, {540, 600 } }, + {2, {390, 433}, {810, 900 } }, + {3, {520, 578}, {1080, 1200} }, + {4, {780, 867}, {1620, 1800} }, + {5, {1040, 1156}, {2160, 2400} }, + {6, {1170, 1300}, {2430, 2700} }, + {7, {1300, 1440}, {2700, 3000} } +}; + +/* MCS Based VHT rate table */ +/* MCS parameters with Nss = 1*/ +static const struct index_vht_data_rate_type vht_mcs_nss1[] = { + /* MCS L20 S20 L40 S40 L80 S80 L160 S160*/ + {0, {65, 72 }, {135, 150}, {293, 325}, {585, 650} }, + {1, {130, 144}, {270, 300}, {585, 650}, {1170, 1300} }, + {2, {195, 217}, {405, 450}, {878, 975}, {1755, 1950} }, + {3, {260, 289}, {540, 600}, {1170, 1300}, {2340, 2600} }, + {4, {390, 433}, {810, 900}, {1755, 1950}, {3510, 3900} }, + {5, {520, 578}, {1080, 1200}, {2340, 2600}, {4680, 5200} }, + {6, {585, 650}, {1215, 1350}, {2633, 2925}, {5265, 5850} }, + {7, {650, 722}, {1350, 1500}, {2925, 3250}, {5850, 6500} }, + {8, {780, 867}, {1620, 1800}, {3510, 3900}, {7020, 7800} }, + {9, {865, 960}, {1800, 2000}, {3900, 4333}, {7800, 8667} }, + {10, {975, 1083}, {2025, 2250}, {4388, 4875}, {8775, 9750} }, + {11, {1083, 1204}, {2250, 2500}, {4875, 5417}, {9750, 1083} } +}; + +/*MCS parameters with Nss = 2*/ +static const struct index_vht_data_rate_type vht_mcs_nss2[] = { + /* MCS L20 S20 L40 S40 L80 S80 L160 S160*/ + {0, {130, 144}, {270, 300}, { 585, 650}, {1170, 1300} }, + {1, {260, 289}, {540, 600}, {1170, 1300}, {2340, 2600} }, + {2, {390, 433}, {810, 900}, {1755, 1950}, {3510, 3900} }, + {3, {520, 578}, {1080, 1200}, {2340, 2600}, {4680, 5200} }, + {4, {780, 867}, {1620, 1800}, {3510, 3900}, {7020, 7800} }, + {5, {1040, 1156}, {2160, 2400}, {4680, 5200}, {9360, 10400} }, + {6, {1170, 1300}, {2430, 2700}, {5265, 5850}, {10530, 11700} }, + {7, {1300, 1444}, {2700, 3000}, {5850, 6500}, {11700, 13000} }, + {8, {1560, 1733}, {3240, 3600}, {7020, 7800}, {14040, 15600} }, + {9, {1730, 1920}, {3600, 4000}, {7800, 8667}, {15600, 17333} }, + {10, {1950, 2167}, {4050, 4500}, {8775, 9750}, {17550, 19500} }, + {11, {2167, 2407}, {4500, 5000}, {9750, 10833}, {19500, 21667} } +}; + +#ifdef WLAN_FEATURE_11AX +/* MCS Based HE rate table */ +/* MCS parameters with Nss = 1*/ +static const struct index_he_data_rate_type he_mcs_nss1[] = { +/* MCS, {dcm0:0.8/1.6/3.2}, {dcm1:0.8/1.6/3.2} */ + {0, {{86, 81, 73 }, {43, 40, 36 } }, /* HE20 */ + {{172, 163, 146 }, {86, 81, 73 } }, /* HE40 */ + {{360, 340, 306 }, {180, 170, 153} }, /* HE80 */ + {{721, 681, 613 }, {360, 340, 306} } }, /* HE160/HE80+80 */ + {1, {{172, 163, 146 }, {86, 81, 73 } }, + {{344, 325, 293 }, {172, 163, 146} }, + {{721, 681, 613 }, {360, 340, 306} }, + {{1441, 1361, 1225}, {721, 681, 613} } }, + {2, {{258, 244, 219 }, {0} }, + {{516, 488, 439 }, {0} }, + {{1081, 1021, 919 }, {0} }, + {{2162, 2042, 1838}, {0} } }, + {3, {{344, 325, 293 }, {172, 163, 146} }, + {{688, 650, 585 }, {344, 325, 293} }, + {{1441, 1361, 1225}, {721, 681, 613} }, + {{2882, 2722, 2450}, {1441, 1361, 1225} } }, + {4, {{516, 488, 439 }, {258, 244, 219} }, + {{1032, 975, 878 }, {516, 488, 439} }, + {{2162, 2042, 1838}, {1081, 1021, 919} }, + {{4324, 4083, 3675}, {2162, 2042, 1838} } }, + {5, {{688, 650, 585 }, {0} }, + {{1376, 1300, 1170}, {0} }, + {{2882, 2722, 2450}, {0} }, + {{5765, 5444, 4900}, {0} } }, + {6, {{774, 731, 658 }, {0} }, + {{1549, 1463, 1316}, {0} }, + {{3243, 3063, 2756}, {0} }, + {{6485, 6125, 5513}, {0} } }, + {7, {{860, 813, 731 }, {0} }, + {{1721, 1625, 1463}, {0} }, + {{3603, 3403, 3063}, {0} }, + {{7206, 6806, 6125}, {0} } }, + {8, {{1032, 975, 878 }, {0} }, + {{2065, 1950, 1755}, {0} }, + {{4324, 4083, 3675}, {0} }, + {{8647, 8167, 7350}, {0} } }, + {9, {{1147, 1083, 975 }, {0} }, + {{2294, 2167, 1950}, {0} }, + {{4804, 4537, 4083}, {0} }, + {{9607, 9074, 8166}, {0} } }, + {10, {{1290, 1219, 1097}, {0} }, + {{2581, 2438, 2194}, {0} }, + {{5404, 5104, 4594}, {0} }, + {{10809, 10208, 9188}, {0} } }, + {11, {{1434, 1354, 1219}, {0} }, + {{2868, 2708, 2438}, {0} }, + {{6004, 5671, 5104}, {0} }, + {{12010, 11342, 10208}, {0} } }, + {12, {{1549, 1463, 1316}, {0} }, + {{3097, 2925, 2633}, {0} }, + {{6485, 6125, 5513}, {0} }, + {{12971, 12250, 11025}, {0} } }, + {13, {{1721, 1625, 1463}, {0} }, + {{3441, 3250, 2925}, {0} }, + {{7206, 6806, 6125}, {0} }, + {{14412, 13611, 12250}, {0} } } +}; + +/*MCS parameters with Nss = 2*/ +static const struct index_he_data_rate_type he_mcs_nss2[] = { +/* MCS, {dcm0:0.8/1.6/3.2}, {dcm1:0.8/1.6/3.2} */ + {0, {{172, 163, 146 }, {86, 81, 73 } }, /* HE20 */ + {{344, 325, 293 }, {172, 163, 146} }, /* HE40 */ + {{721, 681, 613 }, {360, 340, 306} }, /* HE80 */ + {{1441, 1361, 1225}, {721, 681, 613} } }, /* HE160/HE80+80 */ + {1, {{344, 325, 293 }, {172, 163, 146} }, + {{688, 650, 585 }, {344, 325, 293} }, + {{1441, 1361, 1225}, {721, 681, 613} }, + {{2882, 2722, 2450}, {1441, 1361, 1225} } }, + {2, {{516, 488, 439 }, {0} }, + {{1032, 975, 878 }, {0} }, + {{2162, 2042, 1838}, {0} }, + {{4324, 4083, 3675}, {0} } }, + {3, {{688, 650, 585 }, {344, 325, 293 } }, + {{1376, 1300, 1170}, {688, 650, 585 } }, + {{2882, 2722, 2450}, {1441, 1361, 1225} }, + {{5765, 5444, 4900}, {2882, 2722, 2450} } }, + {4, {{1032, 975, 878 }, {516, 488, 439 } }, + {{2065, 1950, 1755}, {1032, 975, 878 } }, + {{4324, 4083, 3675}, {2162, 2042, 1838} }, + {{8647, 8167, 7350}, {4324, 4083, 3675} } }, + {5, {{1376, 1300, 1170}, {0} }, + {{2753, 2600, 2340}, {0} }, + {{5765, 5444, 4900}, {0} }, + {{11529, 10889, 9800}, {0} } }, + {6, {{1549, 1463, 1316}, {0} }, + {{3097, 2925, 2633}, {0} }, + {{6485, 6125, 5513}, {0} }, + {{12971, 12250, 11025}, {0} } }, + {7, {{1721, 1625, 1463}, {0} }, + {{3441, 3250, 2925}, {0} }, + {{7206, 6806, 6125}, {0} }, + {{14412, 13611, 12250}, {0} } }, + {8, {{2065, 1950, 1755}, {0} }, + {{4129, 3900, 3510}, {0} }, + {{8647, 8167, 7350}, {0} }, + {{17294, 16333, 14700}, {0} } }, + {9, {{2294, 2167, 1950}, {0} }, + {{4588, 4333, 3900}, {0} }, + {{9607, 9074, 8166}, {0} }, + {{19215, 18148, 16333}, {0} } }, + {10, {{2581, 2438, 2194}, {0} }, + {{5162, 4875, 4388}, {0} }, + {{10809, 10208, 9188}, {0} }, + {{21618, 20417, 18375}, {0} } }, + {11, {{2868, 2708, 2438}, {0} }, + {{5735, 5417, 4875}, {0} }, + {{12010, 11343, 10208}, {0} }, + {{24019, 22685, 20416}, {0} } }, + {12, {{3097, 2925, 2633}, {0} }, + {{6194, 5850, 5265}, {0} }, + {{12971, 12250, 11025}, {0} }, + {{25941, 24500, 22050}, {0} } }, + {13, {{3441, 3250, 2925}, {0} }, + {{6882, 6500, 5850}, {0} }, + {{14412, 13611, 12250}, {0} }, + {{28824, 27222, 24500}, {0} } } +}; +#endif + +#ifdef BIG_ENDIAN_HOST + +/* ############# function definitions ############ */ + +/** + * wma_swap_bytes() - swap bytes + * @pv: buffer + * @n: swap bytes + * + * Return: none + */ +void wma_swap_bytes(void *pv, uint32_t n) +{ + int32_t no_words; + int32_t i; + uint32_t *word_ptr; + + no_words = n / sizeof(uint32_t); + word_ptr = (uint32_t *) pv; + for (i = 0; i < no_words; i++) + *(word_ptr + i) = __cpu_to_le32(*(word_ptr + i)); +} + +#define SWAPME(x, len) wma_swap_bytes(&x, len) +#endif /* BIG_ENDIAN_HOST */ + +uint16_t wma_mcs_rate_match(uint16_t raw_rate, bool is_he, + const uint16_t *nss1_rate, + const uint16_t *nss2_rate, + uint8_t *nss, enum txrate_gi *guard_interval) +{ + uint8_t gi_index; + uint8_t gi_index_max = 2; + uint16_t ret_rate = 0; + + if (is_he) + gi_index_max = 3; + + for (gi_index = 0; gi_index < gi_index_max; gi_index++) { + if (raw_rate == nss1_rate[gi_index]) { + *nss = 1; + ret_rate = nss1_rate[gi_index]; + break; + } + if (*nss == 2 && raw_rate == nss2_rate[gi_index]) { + ret_rate = nss2_rate[gi_index]; + break; + } + } + + if (ret_rate) { + if (gi_index == 1) + *guard_interval = + is_he ? TXRATE_GI_1_6_US : TXRATE_GI_0_4_US; + else if (is_he && gi_index == 2) + *guard_interval = TXRATE_GI_3_2_US; + else + *guard_interval = TXRATE_GI_0_8_US; + } + + return ret_rate; +} + +#ifdef WLAN_FEATURE_11AX +/** + * wma_match_he_rate() - get matching rate for HE + * @raw_rate: raw rate from fw + * @rate_flags: rate flags + * @is_he_mcs_12_13_supported: is HE MCS12/MCS13 supported + * @nss: nss + * @dcm: dcm + * @guard_interval: guard interval + * @mcs_rate_flag: mcs rate flags + * @p_index: index for matched rate + * + * Return: return match rate if found, else 0 + */ +static uint16_t wma_match_he_rate(uint16_t raw_rate, + enum tx_rate_info rate_flags, + bool is_he_mcs_12_13_supported, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag, + uint8_t *p_index) +{ + uint8_t index = 0, max_he_mcs_idx; + uint8_t dcm_index_max = 1; + uint8_t dcm_index = 0; + uint16_t match_rate = 0; + const uint16_t *nss1_rate; + const uint16_t *nss2_rate; + + *p_index = 0; + if (!(rate_flags & (TX_RATE_HE160 | TX_RATE_HE80 | TX_RATE_HE40 | + TX_RATE_HE20))) + return 0; + + if (is_he_mcs_12_13_supported) + max_he_mcs_idx = QDF_ARRAY_SIZE(he_mcs_nss1); + else + max_he_mcs_idx = QDF_ARRAY_SIZE(he_mcs_nss1) - 2; + + for (index = 0; index < max_he_mcs_idx; index++) { + dcm_index_max = IS_MCS_HAS_DCM_RATE(index) ? 2 : 1; + + for (dcm_index = 0; dcm_index < dcm_index_max; + dcm_index++) { + if (rate_flags & TX_RATE_HE160) { + nss1_rate = &he_mcs_nss1[index]. + supported_he160_rate[dcm_index][0]; + nss2_rate = &he_mcs_nss2[index]. + supported_he160_rate[dcm_index][0]; + /* check for he160 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + if (match_rate) + goto rate_found; + } + + if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE160)) { + nss1_rate = &he_mcs_nss1[index]. + supported_he80_rate[dcm_index][0]; + nss2_rate = &he_mcs_nss2[index]. + supported_he80_rate[dcm_index][0]; + /* check for he80 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + if (match_rate) { + *mcs_rate_flag &= ~TX_RATE_HE160; + goto rate_found; + } + } + + if (rate_flags & (TX_RATE_HE40 | TX_RATE_HE80 | + TX_RATE_HE160)) { + nss1_rate = &he_mcs_nss1[index]. + supported_he40_rate[dcm_index][0]; + nss2_rate = &he_mcs_nss2[index]. + supported_he40_rate[dcm_index][0]; + /* check for he40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + + if (match_rate) { + *mcs_rate_flag &= ~(TX_RATE_HE80 | + TX_RATE_HE160); + goto rate_found; + } + } + + if (rate_flags & (TX_RATE_HE80 | TX_RATE_HE40 | + TX_RATE_HE20 | TX_RATE_HE160)) { + nss1_rate = &he_mcs_nss1[index]. + supported_he20_rate[dcm_index][0]; + nss2_rate = &he_mcs_nss2[index]. + supported_he20_rate[dcm_index][0]; + /* check for he20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 1, + nss1_rate, + nss2_rate, + nss, + guard_interval); + + if (match_rate) { + *mcs_rate_flag &= TX_RATE_HE20; + goto rate_found; + } + } + } + } + +rate_found: + if (match_rate) { + if (dcm_index == 1) + *dcm = 1; + *p_index = index; + } + return match_rate; +} +#else +static uint16_t wma_match_he_rate(uint16_t raw_rate, + enum tx_rate_info rate_flags, + bool is_he_mcs_12_13_supported, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag, + uint8_t *p_index) +{ + return 0; +} +#endif + +uint8_t wma_get_mcs_idx(uint16_t raw_rate, enum tx_rate_info rate_flags, + bool is_he_mcs_12_13_supported, + uint8_t *nss, uint8_t *dcm, + enum txrate_gi *guard_interval, + enum tx_rate_info *mcs_rate_flag) +{ + uint8_t index = 0; + uint16_t match_rate = 0; + uint8_t max_ht_mcs_idx; + const uint16_t *nss1_rate; + const uint16_t *nss2_rate; + + wma_debug("Rates from FW: raw_rate:%d rate_flgs: 0x%x is_he_mcs_12_13_supported: %d nss: %d", + raw_rate, rate_flags, is_he_mcs_12_13_supported, *nss); + + *mcs_rate_flag = rate_flags; + + match_rate = wma_match_eht_rate(raw_rate, rate_flags, + nss, dcm, guard_interval, + mcs_rate_flag, &index); + if (match_rate) + goto rate_found; + + match_rate = wma_match_he_rate(raw_rate, rate_flags, + is_he_mcs_12_13_supported, + nss, dcm, guard_interval, + mcs_rate_flag, &index); + if (match_rate) + goto rate_found; + + for (index = 0; index < QDF_ARRAY_SIZE(vht_mcs_nss1); index++) { + if (rate_flags & TX_RATE_VHT160) { + nss1_rate = &vht_mcs_nss1[index].ht160_rate[0]; + nss2_rate = &vht_mcs_nss2[index].ht160_rate[0]; + /* check for vht160 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 0, + nss1_rate, + nss2_rate, + nss, guard_interval); + if (match_rate) + goto rate_found; + } + if (rate_flags & (TX_RATE_VHT80 | TX_RATE_VHT160)) { + nss1_rate = &vht_mcs_nss1[index].ht80_rate[0]; + nss2_rate = &vht_mcs_nss2[index].ht80_rate[0]; + /* check for vht80 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 0, + nss1_rate, + nss2_rate, + nss, guard_interval); + if (match_rate) { + *mcs_rate_flag &= ~TX_RATE_VHT160; + goto rate_found; + } + } + if (rate_flags & (TX_RATE_VHT40 | TX_RATE_VHT80 | + TX_RATE_VHT160)) { + nss1_rate = &vht_mcs_nss1[index].ht40_rate[0]; + nss2_rate = &vht_mcs_nss2[index].ht40_rate[0]; + /* check for vht40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 0, + nss1_rate, + nss2_rate, + nss, guard_interval); + if (match_rate) { + *mcs_rate_flag &= ~TX_RATE_VHT80; + goto rate_found; + } + } + if (rate_flags & (TX_RATE_VHT20 | TX_RATE_VHT40 | + TX_RATE_VHT80 | TX_RATE_VHT160)) { + nss1_rate = &vht_mcs_nss1[index].ht20_rate[0]; + nss2_rate = &vht_mcs_nss2[index].ht20_rate[0]; + /* check for vht20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 0, + nss1_rate, + nss2_rate, + nss, guard_interval); + if (match_rate) { + *mcs_rate_flag &= ~(TX_RATE_VHT80 | + TX_RATE_VHT40); + goto rate_found; + } + } + } + max_ht_mcs_idx = QDF_ARRAY_SIZE(mcs_nss1); + for (index = 0; index < max_ht_mcs_idx; index++) { + if (rate_flags & TX_RATE_HT40) { + nss1_rate = &mcs_nss1[index].ht40_rate[0]; + nss2_rate = &mcs_nss2[index].ht40_rate[0]; + /* check for ht40 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 0, + nss1_rate, + nss2_rate, + nss, guard_interval); + if (match_rate) { + *mcs_rate_flag = TX_RATE_HT40; + if (*nss == 2) + index += max_ht_mcs_idx; + goto rate_found; + } + } + if (rate_flags & (TX_RATE_HT20 | TX_RATE_HT40)) { + nss1_rate = &mcs_nss1[index].ht20_rate[0]; + nss2_rate = &mcs_nss2[index].ht20_rate[0]; + /* check for ht20 nss1/2 rate set */ + match_rate = wma_mcs_rate_match(raw_rate, 0, + nss1_rate, + nss2_rate, + nss, guard_interval); + if (match_rate) { + *mcs_rate_flag = TX_RATE_HT20; + if (*nss == 2) + index += max_ht_mcs_idx; + goto rate_found; + } + } + } + +rate_found: + + /* set SGI flag only if this is SGI rate */ + if (match_rate && *guard_interval == TXRATE_GI_0_4_US) + *mcs_rate_flag |= TX_RATE_SGI; + else + *mcs_rate_flag &= ~TX_RATE_SGI; + + wma_debug("Matched rate in table: %d index: %d" + " mcs_rate_flag: 0x%x nss %d guard interval %d", + match_rate, index, *mcs_rate_flag, + *nss, *guard_interval); + + return match_rate ? index : INVALID_MCS_IDX; +} + +void wma_lost_link_info_handler(tp_wma_handle wma, uint32_t vdev_id, + int32_t rssi) +{ + struct sir_lost_link_info *lost_link_info; + QDF_STATUS qdf_status; + struct scheduler_msg sme_msg = {0}; + + if (vdev_id >= wma->max_bssid) { + wma_err("received invalid vdev_id %d", vdev_id); + return; + } + + /* report lost link information only for STA mode */ + if (wma_is_vdev_up(vdev_id) && + (WMI_VDEV_TYPE_STA == wma->interfaces[vdev_id].type) && + (0 == wma->interfaces[vdev_id].sub_type)) { + lim_update_lost_link_rssi(wma->mac_context, rssi); + lost_link_info = qdf_mem_malloc(sizeof(*lost_link_info)); + if (!lost_link_info) + return; + + lost_link_info->vdev_id = vdev_id; + lost_link_info->rssi = rssi; + sme_msg.type = eWNI_SME_LOST_LINK_INFO_IND; + sme_msg.bodyptr = lost_link_info; + sme_msg.bodyval = 0; + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("fail to post msg to SME"); + qdf_mem_free(lost_link_info); + } + } +} + +/** + * host_map_smps_mode() - map fw smps mode to enum eSmpsModeValue + * @fw_smps_mode: fw smps mode + * + * Return: return enum eSmpsModeValue + */ +enum eSmpsModeValue host_map_smps_mode(A_UINT32 fw_smps_mode) +{ + enum eSmpsModeValue smps_mode = SMPS_MODE_DISABLED; + + switch (fw_smps_mode) { + case WMI_SMPS_FORCED_MODE_STATIC: + smps_mode = STATIC_SMPS_MODE; + break; + case WMI_SMPS_FORCED_MODE_DYNAMIC: + smps_mode = DYNAMIC_SMPS_MODE; + break; + default: + smps_mode = SMPS_MODE_DISABLED; + } + + return smps_mode; +} + +/** + * wma_smps_mode_to_force_mode_param() - Map smps mode to force + * mode command param + * @smps_mode: SMPS mode according to the protocol + * + * Return: int > 0 for success else failure + */ +int wma_smps_mode_to_force_mode_param(uint8_t smps_mode) +{ + int param = -EINVAL; + + switch (smps_mode) { + case STATIC_SMPS_MODE: + param = WMI_SMPS_FORCED_MODE_STATIC; + break; + case DYNAMIC_SMPS_MODE: + param = WMI_SMPS_FORCED_MODE_DYNAMIC; + break; + case SMPS_MODE_DISABLED: + param = WMI_SMPS_FORCED_MODE_DISABLED; + break; + default: + wma_err("smps mode cannot be mapped :%d", smps_mode); + } + return param; +} + +#ifdef WLAN_FEATURE_STATS_EXT +#ifdef FEATURE_STATS_EXT_V2 +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_STATS_EXT_EVENTID_param_tlvs *param_buf; + tSirStatsExtEvent *stats_ext_event; + wmi_stats_ext_event_fixed_param *stats_ext_info; + QDF_STATUS status; + struct scheduler_msg cds_msg = {0}; + uint8_t *buf_ptr; + uint32_t alloc_len = 0, i, partner_links_data_len = 0; + struct cdp_txrx_ext_stats ext_stats = {0}; + struct cdp_soc_t *soc_hdl = cds_get_context(QDF_MODULE_ID_SOC); + wmi_partner_link_stats *link_stats; + + wma_debug("Posting stats ext event to SME"); + + param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *)event_buf; + if (!param_buf) { + wma_err("Invalid stats ext event buf"); + return -EINVAL; + } + + if (param_buf->num_partner_link_stats) + wma_debug("number of partner link stats:%d", + param_buf->num_partner_link_stats); + + stats_ext_info = param_buf->fixed_param; + buf_ptr = (uint8_t *)stats_ext_info; + + alloc_len += sizeof(tSirStatsExtEvent); + alloc_len += stats_ext_info->data_len; + alloc_len += sizeof(struct cdp_txrx_ext_stats); + + if (param_buf->num_partner_link_stats) { + link_stats = param_buf->partner_link_stats; + if (link_stats) { + for (i = 0; i < param_buf->num_partner_link_stats; i++) { + partner_links_data_len += link_stats->data_length; + link_stats++; + } + alloc_len += partner_links_data_len; + alloc_len += param_buf->num_partner_link_stats * + sizeof(struct cdp_txrx_ext_stats); + } + } + + if (stats_ext_info->data_len > (WMI_SVC_MSG_MAX_SIZE - + WMI_TLV_HDR_SIZE - sizeof(*stats_ext_info)) || + stats_ext_info->data_len > param_buf->num_data) { + wma_err("Excess data_len:%d, num_data:%d", + stats_ext_info->data_len, param_buf->num_data); + return -EINVAL; + } + stats_ext_event = qdf_mem_malloc(alloc_len); + if (!stats_ext_event) + return -ENOMEM; + + buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE; + + stats_ext_event->vdev_id = stats_ext_info->vdev_id; + stats_ext_event->event_data_len = stats_ext_info->data_len; + qdf_mem_copy(stats_ext_event->event_data, + buf_ptr, stats_ext_event->event_data_len); + + cdp_txrx_ext_stats_request(soc_hdl, OL_TXRX_PDEV_ID, &ext_stats); + qdf_mem_copy(stats_ext_event->event_data + + stats_ext_event->event_data_len, + &ext_stats, sizeof(struct cdp_txrx_ext_stats)); + + stats_ext_event->event_data_len += sizeof(struct cdp_txrx_ext_stats); + + if (param_buf->num_partner_link_stats) { + link_stats = param_buf->partner_link_stats; + if (link_stats) { + for (i = 0; i < param_buf->num_partner_link_stats; i++) { + qdf_mem_copy(((uint8_t *)stats_ext_event->event_data) + + stats_ext_event->event_data_len, + param_buf->partner_link_data + + link_stats->offset, + link_stats->data_length); + + stats_ext_event->event_data_len += + link_stats->data_length; + + qdf_mem_copy(stats_ext_event->event_data + + stats_ext_event->event_data_len, + &ext_stats, + sizeof(struct cdp_txrx_ext_stats)); + stats_ext_event->event_data_len += + sizeof(struct cdp_txrx_ext_stats); + link_stats++; + } + } + } + + cds_msg.type = eWNI_SME_STATS_EXT_EVENT; + cds_msg.bodyptr = (void *)stats_ext_event; + cds_msg.bodyval = 0; + + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(stats_ext_event); + return -EFAULT; + } + + wma_debug("stats ext event Posted to SME"); + return 0; +} +#else +int wma_stats_ext_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_STATS_EXT_EVENTID_param_tlvs *param_buf; + tSirStatsExtEvent *stats_ext_event; + wmi_stats_ext_event_fixed_param *stats_ext_info; + QDF_STATUS status; + struct scheduler_msg cds_msg = {0}; + uint8_t *buf_ptr; + uint32_t alloc_len; + + wma_debug("Posting stats ext event to SME"); + + param_buf = (WMI_STATS_EXT_EVENTID_param_tlvs *)event_buf; + if (!param_buf) { + wma_err("Invalid stats ext event buf"); + return -EINVAL; + } + + stats_ext_info = param_buf->fixed_param; + buf_ptr = (uint8_t *)stats_ext_info; + + alloc_len = sizeof(tSirStatsExtEvent); + alloc_len += stats_ext_info->data_len; + + if (stats_ext_info->data_len > (WMI_SVC_MSG_MAX_SIZE - + WMI_TLV_HDR_SIZE - sizeof(*stats_ext_info)) || + stats_ext_info->data_len > param_buf->num_data) { + wma_err("Excess data_len:%d, num_data:%d", + stats_ext_info->data_len, param_buf->num_data); + return -EINVAL; + } + stats_ext_event = qdf_mem_malloc(alloc_len); + if (!stats_ext_event) + return -ENOMEM; + + buf_ptr += sizeof(wmi_stats_ext_event_fixed_param) + WMI_TLV_HDR_SIZE; + + stats_ext_event->vdev_id = stats_ext_info->vdev_id; + stats_ext_event->event_data_len = stats_ext_info->data_len; + qdf_mem_copy(stats_ext_event->event_data, + buf_ptr, stats_ext_event->event_data_len); + + cds_msg.type = eWNI_SME_STATS_EXT_EVENT; + cds_msg.bodyptr = (void *)stats_ext_event; + cds_msg.bodyval = 0; + + status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &cds_msg); + if (status != QDF_STATUS_SUCCESS) { + qdf_mem_free(stats_ext_event); + return -EFAULT; + } + + wma_debug("stats ext event Posted to SME"); + return 0; +} +#endif +#endif /* WLAN_FEATURE_STATS_EXT */ + +/** + * wma_profile_data_report_event_handler() - fw profiling handler + * @handle: wma handle + * @event_buf: event buffer received from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf, + uint32_t len) +{ + WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *param_buf; + wmi_wlan_profile_ctx_t *profile_ctx; + wmi_wlan_profile_t *profile_data; + uint32_t i = 0; + uint32_t entries; + char temp_str[150]; + + param_buf = (WMI_WLAN_PROFILE_DATA_EVENTID_param_tlvs *) event_buf; + if (!param_buf) { + wma_err("Invalid profile data event buf"); + return -EINVAL; + } + + profile_ctx = param_buf->profile_ctx; + entries = profile_ctx->bin_count; + if (entries > param_buf->num_profile_data) { + wma_err("FW bin count %d more than data %d in TLV hdr", + entries, + param_buf->num_profile_data); + return -EINVAL; + } + + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Profile data stats\n"); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "TOT: %d\n" + "tx_msdu_cnt: %d\n" + "tx_mpdu_cnt: %d\n" + "tx_ppdu_cnt: %d\n" + "rx_msdu_cnt: %d\n" + "rx_mpdu_cnt: %d\n" + "bin_count: %d\n", + profile_ctx->tot, + profile_ctx->tx_msdu_cnt, + profile_ctx->tx_mpdu_cnt, + profile_ctx->tx_ppdu_cnt, + profile_ctx->rx_msdu_cnt, + profile_ctx->rx_mpdu_cnt, + profile_ctx->bin_count); + + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "Profile ID: Count: TOT: Min: Max: hist_intvl: hist[0]: hist[1]:hist[2]"); + + profile_data = param_buf->profile_data; + for (i = 0; i < entries; i++) { + if (i == WMI_WLAN_PROFILE_MAX_BIN_CNT) + break; + snprintf(temp_str, sizeof(temp_str), + " %d : %d : %d : %d : %d : %d : %d : %d : %d", + profile_data[i].id, + profile_data[i].cnt, + profile_data[i].tot, + profile_data[i].min, + profile_data[i].max, + profile_data[i].hist_intvl, + profile_data[i].hist[0], + profile_data[i].hist[1], + profile_data[i].hist[2]); + QDF_TRACE(QDF_MODULE_ID_WMA, QDF_TRACE_LEVEL_ERROR, + "%s", temp_str); + } + + return 0; +} + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS + +#define WMA_FILL_TX_STATS(eve, msg) do {\ + (msg)->msdus = (eve)->tx_msdu_cnt;\ + (msg)->mpdus = (eve)->tx_mpdu_cnt;\ + (msg)->ppdus = (eve)->tx_ppdu_cnt;\ + (msg)->bytes = (eve)->tx_bytes;\ + (msg)->drops = (eve)->tx_msdu_drop_cnt;\ + (msg)->drop_bytes = (eve)->tx_drop_bytes;\ + (msg)->retries = (eve)->tx_mpdu_retry_cnt;\ + (msg)->failed = (eve)->tx_mpdu_fail_cnt;\ +} while (0) + +#define WMA_FILL_RX_STATS(eve, msg) do {\ + (msg)->mpdus = (eve)->mac_rx_mpdu_cnt;\ + (msg)->bytes = (eve)->mac_rx_bytes;\ + (msg)->ppdus = (eve)->phy_rx_ppdu_cnt;\ + (msg)->ppdu_bytes = (eve)->phy_rx_bytes;\ + (msg)->mpdu_retry = (eve)->rx_mpdu_retry_cnt;\ + (msg)->mpdu_dup = (eve)->rx_mpdu_dup_cnt;\ + (msg)->mpdu_discard = (eve)->rx_mpdu_discard_cnt;\ +} while (0) + +/** + * wma_get_ll_stats_ext_buf() - alloc result buffer for MAC counters + * @len: buffer length output + * @peer_num: peer number + * @fixed_param: fixed parameters in WMI event + * + * Structure of the stats message + * LL_EXT_STATS + * | + * |--Channel stats[1~n] + * |--Peer[1~n] + * | + * +---Signal + * +---TX + * | +---BE + * | +---BK + * | +---VI + * | +---VO + * | + * +---RX + * +---BE + * +---BK + * +---VI + * +---VO + * For each Access Category, the arregation and mcs + * stats are as this: + * TX + * +-BE/BK/VI/VO + * +----tx_mpdu_aggr_array + * +----tx_succ_mcs_array + * +----tx_fail_mcs_array + * +----tx_delay_array + * RX + * +-BE/BK/VI/VO + * +----rx_mpdu_aggr_array + * +----rx_mcs_array + * + * return: Address for result buffer. + */ +static tSirLLStatsResults *wma_get_ll_stats_ext_buf(uint32_t *len, + uint32_t peer_num, + wmi_report_stats_event_fixed_param *fixed_param) +{ + tSirLLStatsResults *buf; + uint32_t buf_len; + uint32_t total_array_len, total_peer_len; + bool excess_data = false; + + if (!len || !fixed_param) { + wma_err("Invalid input parameters"); + return NULL; + } + + /* + * Result buffer has a structure like this: + * --------------------------------- + * | trigger_cond_i | + * +-------------------------------+ + * | cca_chgd_bitmap | + * +-------------------------------+ + * | sig_chgd_bitmap | + * +-------------------------------+ + * | tx_chgd_bitmap | + * +-------------------------------+ + * | rx_chgd_bitmap | + * +-------------------------------+ + * | peer_num | + * +-------------------------------+ + * | channel_num | + * +-------------------------------+ + * | tx_mpdu_aggr_array_len | + * +-------------------------------+ + * | tx_succ_mcs_array_len | + * +-------------------------------+ + * | tx_fail_mcs_array_len | + * +-------------------------------+ + * | tx_delay_array_len | + * +-------------------------------+ + * | rx_mpdu_aggr_array_len | + * +-------------------------------+ + * | rx_mcs_array_len | + * +-------------------------------+ + * | pointer to CCA stats | + * +-------------------------------+ + * | CCA stats | + * +-------------------------------+ + * | peer_stats |----+ + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | not fixed. |<-+ | + * +-------------------------------+ | | + * | per peer tx stats |--+ | + * | BE | <--+ + * | BK | | + * | VI | | + * | VO | | + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | not fixed. |<-+ | + * +-------------------------------+ | | + * | peer peer rx stats |--+ | + * | BE | <--+ + * | BK | + * | VI | + * | VO | + * --------------------------------- + */ + + buf_len = sizeof(tSirLLStatsResults) + + sizeof(struct sir_wifi_ll_ext_stats); + do { + if (fixed_param->num_chan_cca_stats > (WMI_SVC_MSG_MAX_SIZE / + sizeof(struct sir_wifi_chan_cca_stats))) { + excess_data = true; + break; + } + buf_len += (fixed_param->num_chan_cca_stats * + sizeof(struct sir_wifi_chan_cca_stats)); + if (fixed_param->tx_mpdu_aggr_array_len > + WMI_SVC_MSG_MAX_SIZE) { + excess_data = true; + break; + } else { + total_array_len = fixed_param->tx_mpdu_aggr_array_len; + } + if (fixed_param->tx_succ_mcs_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->tx_succ_mcs_array_len; + } + if (fixed_param->tx_fail_mcs_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->tx_fail_mcs_array_len; + } + if (fixed_param->tx_ppdu_delay_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->tx_ppdu_delay_array_len; + } + if (fixed_param->rx_mpdu_aggr_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->rx_mpdu_aggr_array_len; + } + if (fixed_param->rx_mcs_array_len > + (WMI_SVC_MSG_MAX_SIZE - total_array_len)) { + excess_data = true; + break; + } else { + total_array_len += fixed_param->rx_mcs_array_len; + } + + if (total_array_len > (WMI_SVC_MSG_MAX_SIZE / + (sizeof(uint32_t) * WLAN_MAX_AC))) { + excess_data = true; + break; + } else { + total_peer_len = (sizeof(uint32_t) * WLAN_MAX_AC * + total_array_len) + + (WLAN_MAX_AC * + (sizeof(struct sir_wifi_tx) + + sizeof(struct sir_wifi_rx))); + } + if (total_peer_len > WMI_SVC_MSG_MAX_SIZE) { + excess_data = true; + break; + } + if (peer_num > WMI_SVC_MSG_MAX_SIZE / (total_peer_len + + sizeof(struct sir_wifi_ll_ext_peer_stats))) { + excess_data = true; + break; + } else { + buf_len += peer_num * + (sizeof(struct sir_wifi_ll_ext_peer_stats) + + total_peer_len); + } + } while (0); + + if (excess_data || (buf_len > WMI_SVC_MSG_MAX_SIZE)) { + wma_err("excess wmi buffer: peer %d cca %d tx_mpdu %d tx_succ%d tx_fail %d tx_ppdu %d rx_mpdu %d rx_mcs %d", + peer_num, fixed_param->num_chan_cca_stats, + fixed_param->tx_mpdu_aggr_array_len, + fixed_param->tx_succ_mcs_array_len, + fixed_param->tx_fail_mcs_array_len, + fixed_param->tx_ppdu_delay_array_len, + fixed_param->rx_mpdu_aggr_array_len, + fixed_param->rx_mcs_array_len); + return NULL; + } + + buf = qdf_mem_malloc(buf_len); + if (!buf) + *len = 0; + else + *len = buf_len; + + return buf; +} + +/** + * wma_fill_tx_stats() - Fix TX stats into result buffer + * @ll_stats: LL stats buffer + * @fix_param: parameters with fixed length in WMI event + * @param_buf: parameters without fixed length in WMI event + * @buf: buffer for TLV parameters + * @buf_length: length of @buf + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_fill_tx_stats(struct sir_wifi_ll_ext_stats *ll_stats, + wmi_report_stats_event_fixed_param *fix_param, + WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf, + uint8_t **buf, uint32_t *buf_length) +{ + uint8_t *result; + uint32_t i, j, k; + wmi_peer_ac_tx_stats *wmi_peer_tx; + wmi_tx_stats *wmi_tx; + struct sir_wifi_tx *tx_stats; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + uint32_t *tx_mpdu_aggr, *tx_succ_mcs, *tx_fail_mcs, *tx_delay; + uint32_t len, dst_len, param_len, num_entries, + tx_mpdu_aggr_array_len, tx_succ_mcs_array_len, + tx_fail_mcs_array_len, tx_delay_array_len; + + result = *buf; + dst_len = *buf_length; + tx_mpdu_aggr_array_len = fix_param->tx_mpdu_aggr_array_len; + ll_stats->tx_mpdu_aggr_array_len = tx_mpdu_aggr_array_len; + tx_succ_mcs_array_len = fix_param->tx_succ_mcs_array_len; + ll_stats->tx_succ_mcs_array_len = tx_succ_mcs_array_len; + tx_fail_mcs_array_len = fix_param->tx_fail_mcs_array_len; + ll_stats->tx_fail_mcs_array_len = tx_fail_mcs_array_len; + tx_delay_array_len = fix_param->tx_ppdu_delay_array_len; + ll_stats->tx_delay_array_len = tx_delay_array_len; + wmi_peer_tx = param_buf->peer_ac_tx_stats; + wmi_tx = param_buf->tx_stats; + + len = fix_param->num_peer_ac_tx_stats * + WLAN_MAX_AC * tx_mpdu_aggr_array_len * sizeof(uint32_t); + param_len = param_buf->num_tx_mpdu_aggr * sizeof(uint32_t); + if (len <= dst_len && len <= param_len && param_buf->tx_mpdu_aggr) { + tx_mpdu_aggr = (uint32_t *)result; + qdf_mem_copy(tx_mpdu_aggr, param_buf->tx_mpdu_aggr, len); + result += len; + dst_len -= len; + } else { + wma_err("TX_MPDU_AGGR invalid arg, %d, %d, %d", + len, dst_len, param_len); + return QDF_STATUS_E_FAILURE; + } + + len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC * + tx_succ_mcs_array_len * sizeof(uint32_t); + param_len = param_buf->num_tx_succ_mcs * sizeof(uint32_t); + if (len <= dst_len && len <= param_len && param_buf->tx_succ_mcs) { + tx_succ_mcs = (uint32_t *)result; + qdf_mem_copy(tx_succ_mcs, param_buf->tx_succ_mcs, len); + result += len; + dst_len -= len; + } else { + wma_err("TX_SUCC_MCS invalid arg, %d, %d, %d", + len, dst_len, param_len); + return QDF_STATUS_E_FAILURE; + } + + len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC * + tx_fail_mcs_array_len * sizeof(uint32_t); + param_len = param_buf->num_tx_fail_mcs * sizeof(uint32_t); + if (len <= dst_len && len <= param_len && param_buf->tx_fail_mcs) { + tx_fail_mcs = (uint32_t *)result; + qdf_mem_copy(tx_fail_mcs, param_buf->tx_fail_mcs, len); + result += len; + dst_len -= len; + } else { + wma_err("TX_FAIL_MCS invalid arg, %d, %d %d", + len, dst_len, param_len); + return QDF_STATUS_E_FAILURE; + } + + len = fix_param->num_peer_ac_tx_stats * + WLAN_MAX_AC * tx_delay_array_len * sizeof(uint32_t); + param_len = param_buf->num_tx_ppdu_delay * sizeof(uint32_t); + if (len <= dst_len && len <= param_len && param_buf->tx_ppdu_delay) { + tx_delay = (uint32_t *)result; + qdf_mem_copy(tx_delay, param_buf->tx_ppdu_delay, len); + result += len; + dst_len -= len; + } else { + wma_err("TX_DELAY invalid arg, %d, %d, %d", + len, dst_len, param_len); + return QDF_STATUS_E_FAILURE; + } + + /* per peer tx stats */ + peer_stats = ll_stats->peer_stats; + if (!wmi_peer_tx || !wmi_tx || !peer_stats) { + wma_err("Invalid arg, peer_tx %pK, wmi_tx %pK stats %pK", + wmi_peer_tx, wmi_tx, peer_stats); + return QDF_STATUS_E_FAILURE; + } + + num_entries = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC; + if (num_entries > param_buf->num_tx_stats) { + wma_err("tx stats invalid arg, %d", num_entries); + return QDF_STATUS_E_FAILURE; + } + + for (i = 0; i < fix_param->num_peer_ac_tx_stats; i++) { + uint32_t peer_id = wmi_peer_tx[i].peer_id; + struct sir_wifi_tx *ac; + wmi_tx_stats *wmi_tx_stats; + + for (j = 0; j < ll_stats->peer_num; j++) { + peer_stats += j; + if (peer_stats->peer_id == WIFI_INVALID_PEER_ID || + peer_stats->peer_id == peer_id) + break; + } + + if (j < ll_stats->peer_num) { + peer_stats->peer_id = wmi_peer_tx[i].peer_id; + peer_stats->vdev_id = wmi_peer_tx[i].vdev_id; + tx_stats = (struct sir_wifi_tx *)result; + for (k = 0; k < WLAN_MAX_AC; k++) { + wmi_tx_stats = &wmi_tx[i * WLAN_MAX_AC + k]; + ac = &tx_stats[k]; + WMA_FILL_TX_STATS(wmi_tx_stats, ac); + ac->mpdu_aggr_size = tx_mpdu_aggr; + ac->aggr_len = tx_mpdu_aggr_array_len * + sizeof(uint32_t); + ac->success_mcs_len = tx_succ_mcs_array_len * + sizeof(uint32_t); + ac->success_mcs = tx_succ_mcs; + ac->fail_mcs = tx_fail_mcs; + ac->fail_mcs_len = tx_fail_mcs_array_len * + sizeof(uint32_t); + ac->delay = tx_delay; + ac->delay_len = tx_delay_array_len * + sizeof(uint32_t); + peer_stats->ac_stats[k].tx_stats = ac; + peer_stats->ac_stats[k].type = k; + tx_mpdu_aggr += tx_mpdu_aggr_array_len; + tx_succ_mcs += tx_succ_mcs_array_len; + tx_fail_mcs += tx_fail_mcs_array_len; + tx_delay += tx_delay_array_len; + } + result += WLAN_MAX_AC * sizeof(struct sir_wifi_tx); + } else { + /* + * Buffer for Peer TX counter overflow. + * There is peer ID mismatch between TX, RX, + * signal counters. + */ + wma_err("One peer TX info is dropped"); + + tx_mpdu_aggr += tx_mpdu_aggr_array_len * WLAN_MAX_AC; + tx_succ_mcs += tx_succ_mcs_array_len * WLAN_MAX_AC; + tx_fail_mcs += tx_fail_mcs_array_len * WLAN_MAX_AC; + tx_delay += tx_delay_array_len * WLAN_MAX_AC; + } + } + *buf = result; + *buf_length = dst_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_fill_rx_stats() - Fix RX stats into result buffer + * @ll_stats: LL stats buffer + * @fix_param: parameters with fixed length in WMI event + * @param_buf: parameters without fixed length in WMI event + * @buf: buffer for TLV parameters + * @buf_length: length of @buf + * + * Return: QDF_STATUS + */ +static QDF_STATUS +wma_fill_rx_stats(struct sir_wifi_ll_ext_stats *ll_stats, + wmi_report_stats_event_fixed_param *fix_param, + WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf, + uint8_t **buf, uint32_t *buf_length) +{ + uint8_t *result; + uint32_t i, j, k; + uint32_t *rx_mpdu_aggr, *rx_mcs; + wmi_rx_stats *wmi_rx; + wmi_peer_ac_rx_stats *wmi_peer_rx; + struct sir_wifi_rx *rx_stats; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + uint32_t len, dst_len, param_len, + rx_mpdu_aggr_array_len, rx_mcs_array_len; + + rx_mpdu_aggr_array_len = fix_param->rx_mpdu_aggr_array_len; + ll_stats->rx_mpdu_aggr_array_len = rx_mpdu_aggr_array_len; + rx_mcs_array_len = fix_param->rx_mcs_array_len; + ll_stats->rx_mcs_array_len = rx_mcs_array_len; + wmi_peer_rx = param_buf->peer_ac_rx_stats; + wmi_rx = param_buf->rx_stats; + + result = *buf; + dst_len = *buf_length; + len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats * + WLAN_MAX_AC * rx_mpdu_aggr_array_len); + param_len = param_buf->num_rx_mpdu_aggr * sizeof(uint32_t); + if (len <= dst_len && len <= param_len && param_buf->rx_mpdu_aggr) { + rx_mpdu_aggr = (uint32_t *)result; + qdf_mem_copy(rx_mpdu_aggr, param_buf->rx_mpdu_aggr, len); + result += len; + dst_len -= len; + } else { + wma_err("RX_MPDU_AGGR invalid arg %d, %d, %d", + len, dst_len, param_len); + return QDF_STATUS_E_FAILURE; + } + + len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats * + WLAN_MAX_AC * rx_mcs_array_len); + param_len = param_buf->num_rx_mcs * sizeof(uint32_t); + if (len <= dst_len && len <= param_len && param_buf->rx_mcs) { + rx_mcs = (uint32_t *)result; + qdf_mem_copy(rx_mcs, param_buf->rx_mcs, len); + result += len; + dst_len -= len; + } else { + wma_err("RX_MCS invalid arg %d, %d, %d", + len, dst_len, param_len); + return QDF_STATUS_E_FAILURE; + } + + /* per peer rx stats */ + peer_stats = ll_stats->peer_stats; + if (!wmi_peer_rx || !wmi_rx || !peer_stats) { + wma_err("Invalid arg, peer_rx %pK, wmi_rx %pK stats %pK", + wmi_peer_rx, wmi_rx, peer_stats); + return QDF_STATUS_E_FAILURE; + } + for (i = 0; i < fix_param->num_peer_ac_rx_stats; i++) { + uint32_t peer_id = wmi_peer_rx[i].peer_id; + struct sir_wifi_rx *ac; + wmi_rx_stats *wmi_rx_stats; + + for (j = 0; j < ll_stats->peer_num; j++) { + peer_stats += j; + if ((peer_stats->peer_id == WIFI_INVALID_PEER_ID) || + (peer_stats->peer_id == peer_id)) + break; + } + + if (j < ll_stats->peer_num) { + peer_stats->peer_id = wmi_peer_rx[i].peer_id; + peer_stats->vdev_id = wmi_peer_rx[i].vdev_id; + peer_stats->sta_ps_inds = wmi_peer_rx[i].sta_ps_inds; + peer_stats->sta_ps_durs = wmi_peer_rx[i].sta_ps_durs; + peer_stats->rx_probe_reqs = + wmi_peer_rx[i].rx_probe_reqs; + peer_stats->rx_oth_mgmts = wmi_peer_rx[i].rx_oth_mgmts; + rx_stats = (struct sir_wifi_rx *)result; + + for (k = 0; k < WLAN_MAX_AC; k++) { + wmi_rx_stats = &wmi_rx[i * WLAN_MAX_AC + k]; + ac = &rx_stats[k]; + WMA_FILL_RX_STATS(wmi_rx_stats, ac); + ac->mpdu_aggr = rx_mpdu_aggr; + ac->aggr_len = rx_mpdu_aggr_array_len * + sizeof(uint32_t); + ac->mcs = rx_mcs; + ac->mcs_len = rx_mcs_array_len * + sizeof(uint32_t); + peer_stats->ac_stats[k].rx_stats = ac; + peer_stats->ac_stats[k].type = k; + rx_mpdu_aggr += rx_mpdu_aggr_array_len; + rx_mcs += rx_mcs_array_len; + } + result += WLAN_MAX_AC * sizeof(struct sir_wifi_rx); + } else { + /* + * Buffer for Peer RX counter overflow. + * There is peer ID mismatch between TX, RX, + * signal counters. + */ + wma_err("One peer RX info is dropped"); + rx_mpdu_aggr += rx_mpdu_aggr_array_len * WLAN_MAX_AC; + rx_mcs += rx_mcs_array_len * WLAN_MAX_AC; + } + } + *buf = result; + *buf_length = dst_len; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_ll_stats_evt_handler() - handler for MAC layer counters. + * @handle: wma handle + * @event: FW event + * @len: length of FW event + * + * return: 0 success. + */ +static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event, + u_int32_t len) +{ + WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf; + wmi_report_stats_event_fixed_param *fixed_param; + tSirLLStatsResults *link_stats_results; + wmi_chan_cca_stats *wmi_cca_stats; + wmi_peer_signal_stats *wmi_peer_signal; + struct sir_wifi_ll_ext_stats *ll_stats; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + struct sir_wifi_chan_cca_stats *cca_stats; + struct sir_wifi_peer_signal_stats *peer_signal; + uint8_t *result; + uint32_t i, peer_num, result_size, dst_len; + struct mac_context *mac; + struct scheduler_msg sme_msg = { 0 }; + QDF_STATUS qdf_status; + + mac = (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + wma_debug("NULL mac ptr. Exiting"); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_ext_cb) { + wma_debug("HDD callback is null"); + return -EINVAL; + } + + wma_debug("Posting MAC counters event to HDD"); + + param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event; + if (!param_buf) { + wma_debug("param_buf is null"); + return -EINVAL; + } + fixed_param = param_buf->fixed_param; + if (!fixed_param) { + wma_debug("fixed_param is null"); + return -EINVAL; + } + wmi_cca_stats = param_buf->chan_cca_stats; + wmi_peer_signal = param_buf->peer_signal_stats; + if (fixed_param->num_peer_signal_stats > + param_buf->num_peer_signal_stats || + fixed_param->num_peer_ac_tx_stats > + param_buf->num_peer_ac_tx_stats || + fixed_param->num_peer_ac_rx_stats > + param_buf->num_peer_ac_rx_stats) { + wma_err("excess num_peer_signal_stats:%d, num_peer_ac_tx_stats:%d, num_peer_ac_rx_stats:%d", + fixed_param->num_peer_signal_stats, + fixed_param->num_peer_ac_tx_stats, + fixed_param->num_peer_ac_rx_stats); + return -EINVAL; + } + + /* Get the MAX of three peer numbers */ + peer_num = fixed_param->num_peer_signal_stats > + fixed_param->num_peer_ac_tx_stats ? + fixed_param->num_peer_signal_stats : + fixed_param->num_peer_ac_tx_stats; + peer_num = peer_num > fixed_param->num_peer_ac_rx_stats ? + peer_num : fixed_param->num_peer_ac_rx_stats; + + if (peer_num == 0) + return -EINVAL; + + link_stats_results = wma_get_ll_stats_ext_buf(&result_size, + peer_num, + fixed_param); + if (!link_stats_results) { + wma_err("Fail to allocate stats buffer"); + return -EINVAL; + } + link_stats_results->paramId = WMI_LL_STATS_EXT_MAC_COUNTER; + link_stats_results->num_peers = peer_num; + link_stats_results->peer_event_number = 1; + link_stats_results->moreResultToFollow = 0; + + ll_stats = (struct sir_wifi_ll_ext_stats *)link_stats_results->results; + ll_stats->trigger_cond_id = fixed_param->trigger_cond_id; + ll_stats->cca_chgd_bitmap = fixed_param->cca_chgd_bitmap; + ll_stats->sig_chgd_bitmap = fixed_param->sig_chgd_bitmap; + ll_stats->tx_chgd_bitmap = fixed_param->tx_chgd_bitmap; + ll_stats->rx_chgd_bitmap = fixed_param->rx_chgd_bitmap; + ll_stats->channel_num = fixed_param->num_chan_cca_stats; + ll_stats->peer_num = peer_num; + + result = (uint8_t *)ll_stats->stats; + if (!result) { + wma_err("result is null"); + qdf_mem_free(link_stats_results); + return -EINVAL; + } + peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result; + ll_stats->peer_stats = peer_stats; + + for (i = 0; i < peer_num && peer_stats; i++) { + peer_stats[i].peer_id = WIFI_INVALID_PEER_ID; + peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID; + } + + /* Per peer signal */ + result_size -= sizeof(struct sir_wifi_ll_ext_stats); + dst_len = sizeof(struct sir_wifi_peer_signal_stats); + for (i = 0; + i < fixed_param->num_peer_signal_stats && + peer_stats && wmi_peer_signal; + i++) { + peer_stats[i].peer_id = wmi_peer_signal->peer_id; + peer_stats[i].vdev_id = wmi_peer_signal->vdev_id; + peer_signal = &peer_stats[i].peer_signal_stats; + + wma_debug("%d antennas for peer %d", + wmi_peer_signal->num_chains_valid, + wmi_peer_signal->peer_id); + if (dst_len <= result_size && peer_signal) { + peer_signal->vdev_id = wmi_peer_signal->vdev_id; + peer_signal->peer_id = wmi_peer_signal->peer_id; + peer_signal->num_chain = + wmi_peer_signal->num_chains_valid; + qdf_mem_copy(peer_signal->per_ant_snr, + wmi_peer_signal->per_chain_snr, + sizeof(peer_signal->per_ant_snr)); + qdf_mem_copy(peer_signal->nf, + wmi_peer_signal->per_chain_nf, + sizeof(peer_signal->nf)); + qdf_mem_copy(peer_signal->per_ant_rx_mpdus, + wmi_peer_signal->per_antenna_rx_mpdus, + sizeof(peer_signal->per_ant_rx_mpdus)); + qdf_mem_copy(peer_signal->per_ant_tx_mpdus, + wmi_peer_signal->per_antenna_tx_mpdus, + sizeof(peer_signal->per_ant_tx_mpdus)); + result_size -= dst_len; + } else { + wma_err("Invalid length of PEER signal"); + } + wmi_peer_signal++; + } + + result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats); + cca_stats = (struct sir_wifi_chan_cca_stats *)result; + ll_stats->cca = cca_stats; + dst_len = sizeof(*cca_stats); + for (i = 0; + i < ll_stats->channel_num && cca_stats && wmi_cca_stats; + i++) { + if (dst_len <= result_size) { + cca_stats->vdev_id = wmi_cca_stats->vdev_id; + cca_stats->idle_time = wmi_cca_stats->idle_time; + cca_stats->tx_time = wmi_cca_stats->tx_time; + cca_stats->rx_in_bss_time = + wmi_cca_stats->rx_in_bss_time; + cca_stats->rx_out_bss_time = + wmi_cca_stats->rx_out_bss_time; + cca_stats->rx_busy_time = wmi_cca_stats->rx_busy_time; + cca_stats->rx_in_bad_cond_time = + wmi_cca_stats->rx_in_bad_cond_time; + cca_stats->tx_in_bad_cond_time = + wmi_cca_stats->tx_in_bad_cond_time; + cca_stats->wlan_not_avail_time = + wmi_cca_stats->wlan_not_avail_time; + result_size -= dst_len; + } else { + wma_err("Invalid length of CCA"); + } + cca_stats++; + } + + result += i * sizeof(struct sir_wifi_chan_cca_stats); + qdf_status = wma_fill_tx_stats(ll_stats, fixed_param, param_buf, + &result, &result_size); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) + qdf_status = wma_fill_rx_stats(ll_stats, fixed_param, param_buf, + &result, &result_size); + if (QDF_IS_STATUS_SUCCESS(qdf_status)) { + sme_msg.type = eWMI_SME_LL_STATS_IND; + sme_msg.bodyptr = (void *)link_stats_results; + sme_msg.bodyval = 0; + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, + &sme_msg); + } + + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + qdf_mem_free(link_stats_results); + return -EINVAL; + } + + return 0; +} + +#ifdef WLAN_FEATURE_11BE_MLO +static bool wma_get_mlo_per_link_stats_cap(wmi_unified_t wmi_handle) +{ + return wmi_service_enabled(wmi_handle, + wmi_service_per_link_stats_support); +} +#else +static inline bool wma_get_mlo_per_link_stats_cap(wmi_unified_t wmi_handle) +{ + return false; +} +#endif + +/** + * wma_get_dp_peer_stats() - get host dp peer stats + * @wmi_handle: wmi handle + * @dp_stats: buffer to store stats + * @peer_mac: peer mac address + * + * Return: 0 on success or error code + */ +static QDF_STATUS wma_get_dp_peer_stats(wmi_unified_t wmi_handle, + struct cdp_peer_stats *dp_stats, + uint8_t *peer_mac) +{ + void *dp_soc = cds_get_context(QDF_MODULE_ID_SOC); + uint8_t vdev_id; + QDF_STATUS status; + + status = cdp_peer_get_vdevid(dp_soc, peer_mac, &vdev_id); + if (!QDF_IS_STATUS_SUCCESS(status)) { + wma_err("Unable to find peer ["QDF_MAC_ADDR_FMT"]", + QDF_MAC_ADDR_REF(peer_mac)); + return status; + } + + if (!wma_get_mlo_per_link_stats_cap(wmi_handle)) + return cdp_host_get_peer_stats(dp_soc, vdev_id, + peer_mac, dp_stats); + + return ucfg_dp_get_per_link_peer_stats(dp_soc, vdev_id, peer_mac, + dp_stats, CDP_WILD_PEER_TYPE, + WLAN_MAX_MLD); +} + +/** + * wma_unified_link_peer_stats_event_handler() - peer stats event handler + * @handle: wma handle + * @cmd_param_info: data received with event from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +static int wma_unified_link_peer_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_PEER_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_peer_stats_event_fixed_param *fixed_param; + wmi_peer_link_stats *peer_stats, *temp_peer_stats; + wmi_rate_stats *rate_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_peer_stats, *t_rate_stats, *peer_mac; + uint32_t count, rate_cnt; + uint32_t total_num_rates = 0; + uint32_t next_res_offset, next_peer_offset, next_rate_offset; + size_t peer_info_size, peer_stats_size, rate_stats_size; + size_t link_stats_results_size; + bool excess_data = false; + uint32_t buf_len = 0; + struct cdp_peer_stats *dp_stats; + QDF_STATUS status; + uint8_t mcs_index; + + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_debug("NULL mac ptr. Exiting"); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_cb) { + wma_debug("HDD callback is null"); + return -EINVAL; + } + + param_tlvs = (WMI_PEER_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + /* + * cmd_param_info contains + * wmi_peer_stats_event_fixed_param fixed_param; + * num_peers * size of(struct wmi_peer_link_stats) + * total_num_rates * size of(struct wmi_rate_stats) + * total_num_rates is the sum of the rates of all the peers. + */ + fixed_param = param_tlvs->fixed_param; + peer_stats = param_tlvs->peer_stats; + rate_stats = param_tlvs->peer_rate_stats; + + if (!fixed_param || !peer_stats || + (peer_stats->num_rates && !rate_stats)) { + wma_err("Invalid param_tlvs for Peer Stats"); + return -EINVAL; + } + + do { + if (fixed_param->num_peers > + WMI_SVC_MSG_MAX_SIZE/sizeof(wmi_peer_link_stats) || + fixed_param->num_peers > param_tlvs->num_peer_stats) { + excess_data = true; + break; + } else { + buf_len = fixed_param->num_peers * + sizeof(wmi_peer_link_stats); + } + temp_peer_stats = (wmi_peer_link_stats *) peer_stats; + for (count = 0; count < fixed_param->num_peers; count++) { + if (temp_peer_stats->num_rates > + WMI_SVC_MSG_MAX_SIZE / sizeof(wmi_rate_stats)) { + excess_data = true; + break; + } else { + total_num_rates += temp_peer_stats->num_rates; + if (total_num_rates > + WMI_SVC_MSG_MAX_SIZE / + sizeof(wmi_rate_stats) || total_num_rates > + param_tlvs->num_peer_rate_stats) { + excess_data = true; + break; + } + buf_len += temp_peer_stats->num_rates * + sizeof(wmi_rate_stats); + } + temp_peer_stats++; + } + } while (0); + + if (excess_data || + (buf_len > WMI_SVC_MSG_MAX_SIZE - sizeof(*fixed_param))) { + wma_err("excess wmi buffer: rates:%d, peers:%d", + peer_stats->num_rates, fixed_param->num_peers); + return -EINVAL; + } + + peer_stats_size = sizeof(struct wifi_peer_stat); + peer_info_size = sizeof(struct wifi_peer_info); + rate_stats_size = sizeof(struct wifi_rate_stat); + link_stats_results_size = + sizeof(*link_stats_results) + peer_stats_size + + (fixed_param->num_peers * peer_info_size) + + (total_num_rates * rate_stats_size); + + link_stats_results = qdf_mem_malloc(link_stats_results_size); + if (!link_stats_results) + return -ENOMEM; + + qdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_ALL_PEER; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = fixed_param->vdev_id_info.vdev_id; + link_stats_results->num_peers = fixed_param->num_peers; + link_stats_results->peer_event_number = fixed_param->peer_event_number; + link_stats_results->moreResultToFollow = fixed_param->more_data; + + qdf_mem_copy(link_stats_results->results, + &fixed_param->num_peers, peer_stats_size); + dp_stats = qdf_mem_malloc(sizeof(*dp_stats)); + if (!dp_stats) { + qdf_mem_free(link_stats_results); + return -ENOMEM; + } + + results = (uint8_t *) link_stats_results->results; + t_peer_stats = (uint8_t *) peer_stats; + t_rate_stats = (uint8_t *) rate_stats; + next_res_offset = peer_stats_size; + next_peer_offset = WMI_TLV_HDR_SIZE; + next_rate_offset = WMI_TLV_HDR_SIZE; + for (rate_cnt = 0; rate_cnt < fixed_param->num_peers; rate_cnt++) { + qdf_mem_copy(results + next_res_offset, + t_peer_stats + next_peer_offset, peer_info_size); + next_res_offset += peer_info_size; + + peer_mac = (uint8_t *)&peer_stats->peer_mac_address; + status = wma_get_dp_peer_stats(wma_handle->wmi_handle, + dp_stats, peer_mac); + + /* Copy rate stats associated with this peer */ + for (count = 0; count < peer_stats->num_rates; count++) { + mcs_index = RATE_STAT_GET_MCS_INDEX(rate_stats->rate); + if (QDF_IS_STATUS_SUCCESS(status)) { + if (mcs_index < MAX_MCS) + rate_stats->rx_mpdu = + dp_stats->rx.rx_mpdu_cnt[mcs_index]; + else + rate_stats->rx_mpdu = 0; + } + rate_stats++; + + qdf_mem_copy(results + next_res_offset, + t_rate_stats + next_rate_offset, + rate_stats_size); + next_res_offset += rate_stats_size; + next_rate_offset += sizeof(*rate_stats); + } + next_peer_offset += sizeof(*peer_stats); + peer_stats++; + } + + qdf_mem_free(dp_stats); + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + mac->sme.link_layer_stats_cb(mac->hdd_handle, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results, + mac->sme.ll_stats_context); + qdf_mem_free(link_stats_results); + + return 0; +} + +/** + * wma_unified_link_stats_results_mem_free() - Free link stats results memory + * @link_stats_results: pointer to link stats result + * + * Return: 0 on success, error number otherwise. + */ +void wma_unified_link_stats_results_mem_free( + tSirLLStatsResults *link_stats_results) +{ + struct wifi_radio_stats *rs_results; + uint32_t i = 0; + + if (!link_stats_results) + return; + + rs_results = (struct wifi_radio_stats *) + &link_stats_results->results[0]; + for (i = 0; i < link_stats_results->num_radio; i++) { + if (rs_results->tx_time_per_power_level) { + qdf_mem_free(rs_results->tx_time_per_power_level); + rs_results->tx_time_per_power_level = NULL; + } + + if (rs_results->channels) { + qdf_mem_free(rs_results->channels); + rs_results->channels = NULL; + } + rs_results++; + } +} + + +static int __wma_unified_radio_tx_mem_free(tp_wma_handle wma_handle) +{ + wma_unified_link_stats_results_mem_free(wma_handle->link_stats_results); + + qdf_mem_free(wma_handle->link_stats_results); + wma_handle->link_stats_results = NULL; + + return 0; +} + +/** + * wma_unified_radio_tx_mem_free() - Free radio tx power stats memory + * @handle: WMI handle + * + * Return: 0 on success, error number otherwise. + */ +int wma_unified_radio_tx_mem_free(void *handle) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + int ret; + + if (!wma_handle->link_stats_results) + return 0; + + wma_debug("free link_stats_results"); + qdf_mutex_acquire(&wma_handle->radio_stats_lock); + ret = __wma_unified_radio_tx_mem_free(wma_handle); + qdf_mutex_release(&wma_handle->radio_stats_lock); + + return ret; +} + +static int __wma_unified_radio_tx_power_level_stats_event_handler( + tp_wma_handle wma_handle, + u_int8_t *cmd_param_info, + u_int32_t len) +{ + WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_tx_power_level_stats_evt_fixed_param *fixed_param; + uint8_t *tx_power_level_values; + tSirLLStatsResults *link_stats_results; + struct wifi_radio_stats *rs_results; + uint32_t max_total_num_tx_power_levels = MAX_TPC_LEVELS * NUM_OF_BANDS * + MAX_SPATIAL_STREAM_ANY_V3; + + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_debug("NULL mac ptr. Exiting"); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_cb) { + wma_debug("HDD callback is null"); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_TX_POWER_LEVEL_STATS_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_tlvs) { + wma_err("Invalid tx power level stats event"); + return -EINVAL; + } + + fixed_param = param_tlvs->fixed_param; + if (!fixed_param) { + wma_err("Invalid param_tlvs for Radio tx_power level Stats"); + return -EINVAL; + } + + link_stats_results = wma_handle->link_stats_results; + if (!link_stats_results) { + wma_err("link_stats_results is NULL"); + return -EINVAL; + } + + if (fixed_param->num_tx_power_levels > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(*fixed_param)) / sizeof(uint32_t)) || + fixed_param->num_tx_power_levels > + param_tlvs->num_tx_time_per_power_level) { + wma_err("excess tx_power buffers:%d, num_tx_time_per_power_level:%d", + fixed_param->num_tx_power_levels, + param_tlvs->num_tx_time_per_power_level); + return -EINVAL; + } + + if (fixed_param->radio_id >= link_stats_results->num_radio) { + wma_err("Invalid radio_id %d num_radio %d", + fixed_param->radio_id, + link_stats_results->num_radio); + return -EINVAL; + } + + if (fixed_param->total_num_tx_power_levels > + max_total_num_tx_power_levels) { + wma_debug("Invalid total_num_tx_power_levels %d", + fixed_param->total_num_tx_power_levels); + return -EINVAL; + } + + rs_results = (struct wifi_radio_stats *) &link_stats_results->results[0] + + fixed_param->radio_id; + tx_power_level_values = (uint8_t *) param_tlvs->tx_time_per_power_level; + + if (rs_results->total_num_tx_power_levels && + fixed_param->total_num_tx_power_levels > + rs_results->total_num_tx_power_levels) { + wma_err("excess tx_power buffers:%d, total_num_tx_power_levels:%d", + fixed_param->total_num_tx_power_levels, + rs_results->total_num_tx_power_levels); + return -EINVAL; + } + + rs_results->total_num_tx_power_levels = + fixed_param->total_num_tx_power_levels; + if (!rs_results->total_num_tx_power_levels) { + link_stats_results->nr_received++; + goto post_stats; + } + + if ((fixed_param->power_level_offset > + rs_results->total_num_tx_power_levels) || + (fixed_param->num_tx_power_levels > + rs_results->total_num_tx_power_levels - + fixed_param->power_level_offset)) { + wma_err("Invalid offset %d total_num %d num %d", + fixed_param->power_level_offset, + rs_results->total_num_tx_power_levels, + fixed_param->num_tx_power_levels); + return -EINVAL; + } + + if (!rs_results->tx_time_per_power_level) { + rs_results->tx_time_per_power_level = + qdf_mem_malloc(sizeof(uint32_t) * + rs_results->total_num_tx_power_levels); + if (!rs_results->tx_time_per_power_level) { + /* In error case, atleast send the radio stats without + * tx_power_level stats + */ + rs_results->total_num_tx_power_levels = 0; + link_stats_results->nr_received++; + goto post_stats; + } + } + qdf_mem_copy(&rs_results->tx_time_per_power_level[ + fixed_param->power_level_offset], + tx_power_level_values, + sizeof(uint32_t) * fixed_param->num_tx_power_levels); + if (rs_results->total_num_tx_power_levels == + (fixed_param->num_tx_power_levels + + fixed_param->power_level_offset)) { + link_stats_results->moreResultToFollow = 0; + link_stats_results->nr_received++; + } + wma_debug("num tx pwr lvls %u num tx pwr lvls %u pwr lvl offset %u radio_id %u moretofollow: %u nr_received: %u", + fixed_param->total_num_tx_power_levels, + fixed_param->num_tx_power_levels, + fixed_param->power_level_offset, fixed_param->radio_id, + link_stats_results->moreResultToFollow, + link_stats_results->nr_received); + + /* If still data to receive, return from here */ + if (link_stats_results->moreResultToFollow) + return 0; + +post_stats: + if (link_stats_results->num_radio != link_stats_results->nr_received) { + /* Not received all radio stats yet, don't post yet */ + return 0; + } + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + mac->sme.link_layer_stats_cb(mac->hdd_handle, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results, + mac->sme.ll_stats_context); + + return 0; +} + +/** + * wma_unified_radio_tx_power_level_stats_event_handler() - tx power level stats + * @handle: WMI handle + * @cmd_param_info: command param info + * @len: Length of @cmd_param_info + * + * This is the WMI event handler function to receive radio stats tx + * power level stats. + * + * Return: 0 on success, error number otherwise. + */ +static int wma_unified_radio_tx_power_level_stats_event_handler( + void *handle, + u_int8_t *cmd_param_info, + u_int32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + int ret; + + qdf_mutex_acquire(&wma_handle->radio_stats_lock); + ret = __wma_unified_radio_tx_power_level_stats_event_handler( + wma_handle, + cmd_param_info, + len); + qdf_mutex_release(&wma_handle->radio_stats_lock); + + return ret; +} + +static int wma_copy_chan_stats(uint32_t num_chan, + struct wifi_channel_stats *channels, + struct wifi_radio_stats *rs_results) +{ + uint32_t num_chan_in_prev_event = rs_results->num_channels; + struct wifi_channel_stats *channels_in_prev_event = + rs_results->channels; + if (!rs_results->channels) { + wma_debug("Num of channels in first event %d", num_chan); + /* It means this is the first event for this radio */ + rs_results->num_channels = num_chan; + rs_results->channels = channels; + return 0; + } + if (rs_results->num_channels + num_chan > NUM_CHANNELS) { + wma_err("total chan stats num unexpected %d new %d", + rs_results->num_channels, num_chan); + /* do not add more */ + qdf_mem_free(channels); + return 0; + } + + wma_debug("Num of channels in Second event %d", num_chan); + rs_results->num_channels += num_chan; + rs_results->channels = qdf_mem_malloc(rs_results->num_channels * + sizeof(*channels)); + if (!rs_results->channels) { + qdf_mem_free(channels); + qdf_mem_free(channels_in_prev_event); + return -ENOMEM; + } + + /* copy the previous event's information */ + qdf_mem_copy(rs_results->channels, channels_in_prev_event, + num_chan_in_prev_event * sizeof(*channels_in_prev_event)); + + /* copy the current event's information */ + qdf_mem_copy(rs_results->channels + num_chan_in_prev_event, channels, + num_chan * sizeof(*channels)); + + qdf_mem_free(channels); + qdf_mem_free(channels_in_prev_event); + return 0; +} + +#define WMI_MAX_RADIO_STATS_LOGS 350 + +/* + * Consider 4 char each for center_freq, channel_width, center_freq0, + * center_freq1 and 10 char each for radio_awake_time, cca_busy_time, + * tx_time and rx_time 14 char for parenthesis, 1 for space and 1 to + * end string, making it a total of 72 chars. + */ +#define WMI_MAX_RADIO_SINGLE_STATS_LEN 72 + +static int +__wma_unified_link_radio_stats_event_handler(tp_wma_handle wma_handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_radio_link_stats_event_fixed_param *fixed_param; + wmi_radio_link_stats *radio_stats; + wmi_channel_stats *channel_stats; + tSirLLStatsResults *link_stats_results; + uint8_t *results, *t_radio_stats, *t_channel_stats; + uint32_t next_chan_offset, count; + uint32_t num_chan_in_this_event = 0; + size_t radio_stats_size, chan_stats_size; + size_t link_stats_results_size; + struct wifi_radio_stats *rs_results = NULL; + struct wifi_channel_stats *chn_results; + struct wifi_channel_stats *channels_in_this_event; + bool per_chan_rx_tx_time_enabled = false; + int32_t status; + uint8_t *info; + uint32_t stats_len = 0; + int ret; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + struct wma_ini_config *cfg = wma_get_ini_handle(wma_handle); + bool exclude_selftx_from_cca_busy; + + if (!mac) { + wma_debug("NULL mac ptr. Exiting"); + return -EINVAL; + } + + if (!cfg) { + wma_err("NULL WMA ini handle"); + return 0; + } + + exclude_selftx_from_cca_busy = cfg->exclude_selftx_from_cca_busy; + + if (!mac->sme.link_layer_stats_cb) { + wma_debug("HDD callback is null"); + return -EINVAL; + } + + param_tlvs = (WMI_RADIO_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + /* + * cmd_param_info contains + * wmi_radio_link_stats_event_fixed_param fixed_param; + * size of(struct wmi_radio_link_stats); + * num_channels * size of(struct wmi_channel_stats) + */ + fixed_param = param_tlvs->fixed_param; + if (fixed_param && !fixed_param->num_radio && + !fixed_param->more_radio_events) { + wma_debug("FW indicates dummy link radio stats"); + if (!wma_handle->link_stats_results) { + wma_handle->link_stats_results = qdf_mem_malloc( + sizeof(*link_stats_results)); + if (!wma_handle->link_stats_results) + return -ENOMEM; + } + + /* + * Free the already allocated memory, if any, before setting + * the num_radio to 0 + */ + wma_unified_link_stats_results_mem_free( + wma_handle->link_stats_results); + + link_stats_results = wma_handle->link_stats_results; + link_stats_results->num_radio = fixed_param->num_radio; + goto link_radio_stats_cb; + } + + radio_stats = param_tlvs->radio_stats; + channel_stats = param_tlvs->channel_stats; + + if (!fixed_param || !radio_stats || + (radio_stats->num_channels && !channel_stats)) { + wma_err("Invalid param_tlvs for Radio Stats"); + return -EINVAL; + } + if (radio_stats->num_channels > NUM_CHANNELS || + radio_stats->num_channels > param_tlvs->num_channel_stats) { + wma_err("Too many channels %d", radio_stats->num_channels); + return -EINVAL; + } + + radio_stats_size = sizeof(struct wifi_radio_stats); + chan_stats_size = sizeof(struct wifi_channel_stats); + if (fixed_param->num_radio > + (UINT_MAX - sizeof(*link_stats_results))/radio_stats_size) { + wma_err("excess num_radio %d is leading to int overflow", + fixed_param->num_radio); + return -EINVAL; + } + link_stats_results_size = sizeof(*link_stats_results) + + fixed_param->num_radio * radio_stats_size; + + if (radio_stats->radio_id >= fixed_param->num_radio) { + wma_err("invalid radio id:%d, num radio:%d", + radio_stats->radio_id, + fixed_param->num_radio); + return -EINVAL; + } + if (wma_handle->link_stats_results && + !wma_handle->link_stats_results->num_radio) + __wma_unified_radio_tx_mem_free(wma_handle); + + if (!wma_handle->link_stats_results) { + wma_handle->link_stats_results = qdf_mem_malloc( + link_stats_results_size); + if (!wma_handle->link_stats_results) + return -ENOMEM; + } + link_stats_results = wma_handle->link_stats_results; + if (link_stats_results->num_radio == 0) { + link_stats_results->num_radio = fixed_param->num_radio; + } else if (link_stats_results->num_radio < fixed_param->num_radio) { + /* + * The link stats results size allocated based on num_radio of + * first event must be same as following events. Otherwise these + * events may be spoofed. Drop all of them and report error. + */ + wma_err("Invalid following WMI_RADIO_LINK_STATS_EVENTID. Discarding this set"); + return -EINVAL; + } + + wma_debug("Radio stats Fixed Param: req_id: %u num_radio: %u more_radio_events: %u more_channels %u", + fixed_param->request_id, fixed_param->num_radio, + fixed_param->more_radio_events, fixed_param->more_channels); + + results = (uint8_t *) link_stats_results->results; + t_radio_stats = (uint8_t *) radio_stats; + t_channel_stats = (uint8_t *) channel_stats; + + rs_results = (struct wifi_radio_stats *) &results[0] + radio_stats->radio_id; + + /* + * If more channels is true, means this is the second event for the + * same radio so no need to process radio stats again as the second + * event will only contain remaining channel stats. + */ + if (!rs_results->more_channels) { + rs_results->radio = radio_stats->radio_id; + rs_results->on_time = radio_stats->on_time; + rs_results->tx_time = radio_stats->tx_time; + rs_results->rx_time = radio_stats->rx_time; + rs_results->on_time_scan = radio_stats->on_time_scan; + rs_results->on_time_nbd = radio_stats->on_time_nbd; + rs_results->on_time_gscan = radio_stats->on_time_gscan; + rs_results->on_time_roam_scan = radio_stats->on_time_roam_scan; + rs_results->on_time_pno_scan = radio_stats->on_time_pno_scan; + rs_results->on_time_hs20 = radio_stats->on_time_hs20; + rs_results->on_time_host_scan = radio_stats->on_time_host_scan; + rs_results->on_time_lpi_scan = radio_stats->on_time_lpi_scan; + if (rs_results->channels) { + qdf_mem_free(rs_results->channels); + rs_results->channels = NULL; + } + } + + rs_results->total_num_tx_power_levels = 0; + if (rs_results->tx_time_per_power_level) { + qdf_mem_free(rs_results->tx_time_per_power_level); + rs_results->tx_time_per_power_level = NULL; + } + + per_chan_rx_tx_time_enabled = wmi_service_enabled( + wma_handle->wmi_handle, + wmi_service_ll_stats_per_chan_rx_tx_time); + if (!per_chan_rx_tx_time_enabled) + wma_nofl_debug("LL Stats per channel tx time and rx time are not supported."); + + rs_results->more_channels = fixed_param->more_channels; + num_chan_in_this_event = radio_stats->num_channels; + + if (num_chan_in_this_event) { + channels_in_this_event = qdf_mem_malloc( + radio_stats->num_channels * + chan_stats_size); + if (!channels_in_this_event) + return -ENOMEM; + + chn_results = + (struct wifi_channel_stats *)&channels_in_this_event[0]; + next_chan_offset = WMI_TLV_HDR_SIZE; + wma_debug("Channel Stats Info, radio id %d, total channels %d", + radio_stats->radio_id, radio_stats->num_channels); + + info = qdf_mem_malloc(WMI_MAX_RADIO_STATS_LOGS); + if (!info) { + qdf_mem_free(channels_in_this_event); + return -ENOMEM; + } + + for (count = 0; count < radio_stats->num_channels; count++) { + if (exclude_selftx_from_cca_busy && + channel_stats->cca_busy_time >= + channel_stats->tx_time) + channel_stats->cca_busy_time -= + channel_stats->tx_time; + + ret = qdf_scnprintf(info + stats_len, + WMI_MAX_RADIO_STATS_LOGS - stats_len, + " %d[%d][%d][%d]", + channel_stats->center_freq, + channel_stats->channel_width, + channel_stats->center_freq0, + channel_stats->center_freq1); + if (ret <= 0) + break; + stats_len += ret; + + ret = qdf_scnprintf(info + stats_len, + WMI_MAX_RADIO_STATS_LOGS - stats_len, + "[%d][%d][%d][%d]", + channel_stats->radio_awake_time, + channel_stats->cca_busy_time, + channel_stats->tx_time, + channel_stats->rx_time); + if (ret <= 0) + break; + stats_len += ret; + + if (stats_len >= (WMI_MAX_RADIO_STATS_LOGS - + WMI_MAX_RADIO_SINGLE_STATS_LEN)) { + wmi_nofl_debug("freq[width][freq0][freq1][awake time][cca busy time][tx time][rx time] :%s", + info); + stats_len = 0; + } + + channel_stats++; + + qdf_mem_copy(chn_results, + t_channel_stats + next_chan_offset, + chan_stats_size); + + chn_results++; + next_chan_offset += sizeof(*channel_stats); + } + + if (stats_len) + wmi_nofl_debug("freq[width][freq0][freq1][awake time][cca busy time][tx time][rx time] :%s", + info); + + qdf_mem_free(info); + + status = wma_copy_chan_stats(num_chan_in_this_event, + channels_in_this_event, + rs_results); + if (status) { + wma_err("Failed to copy channel stats"); + return status; + } + } + +link_radio_stats_cb: + link_stats_results->paramId = WMI_LINK_STATS_RADIO; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = fixed_param->vdev_id_info.vdev_id; + link_stats_results->peer_event_number = 0; + + /* + * Backward compatibility: + * There are firmware(s) which will send Radio stats only with + * more_radio_events set to 0 and firmware which sends Radio stats + * followed by tx_power level stats with more_radio_events set to 1. + * if more_radio_events is set to 1, buffer the radio stats and + * wait for tx_power_level stats. + */ + link_stats_results->moreResultToFollow = fixed_param->more_radio_events; + + if ((rs_results && rs_results->more_channels) || + link_stats_results->moreResultToFollow) { + /* More results coming, don't post yet */ + return 0; + } + if (link_stats_results->num_radio) { + link_stats_results->nr_received++; + + if (link_stats_results->num_radio != + link_stats_results->nr_received) { + /* Not received all radio stats yet, don't post yet */ + return 0; + } + } + + mac->sme.link_layer_stats_cb(mac->hdd_handle, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results, + mac->sme.ll_stats_context); + + return 0; +} + +/** + * wma_unified_link_radio_stats_event_handler() - radio link stats event handler + * @handle: wma handle + * @cmd_param_info: data received with event from fw + * @len: length of data + * + * Return: 0 for success or error code + */ +static int wma_unified_link_radio_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + int ret; + + qdf_mutex_acquire(&wma_handle->radio_stats_lock); + ret = __wma_unified_link_radio_stats_event_handler(wma_handle, + cmd_param_info, len); + qdf_mutex_release(&wma_handle->radio_stats_lock); + + return ret; +} + +#ifdef WLAN_PEER_PS_NOTIFICATION +/** + * wma_peer_ps_evt_handler() - handler for PEER power state change. + * @handle: wma handle + * @event: FW event + * @len: length of FW event + * + * Once peer STA power state changes, an event will be indicated by + * FW. This function send a link layer state change msg to HDD. HDD + * link layer callback will converts the event to NL msg. + * + * Return: 0 Success. Others fail. + */ +static int wma_peer_ps_evt_handler(void *handle, u_int8_t *event, + u_int32_t len) +{ + WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *param_buf; + wmi_peer_sta_ps_statechange_event_fixed_param *fixed_param; + struct wifi_peer_stat *peer_stat; + struct wifi_peer_info *peer_info; + tSirLLStatsResults *link_stats_results; + tSirMacAddr mac_address; + uint32_t result_len; + cds_msg_t sme_msg = { 0 }; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_debug("NULL mac ptr. Exiting"); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_ext_cb) { + wma_debug("HDD callback is null"); + return -EINVAL; + } + + wma_debug("Posting Peer Stats PS event to HDD"); + + param_buf = (WMI_PEER_STA_PS_STATECHG_EVENTID_param_tlvs *)event; + fixed_param = param_buf->fixed_param; + + result_len = sizeof(tSirLLStatsResults) + + sizeof(struct wifi_peer_stat) + + sizeof(struct wifi_peer_info); + link_stats_results = qdf_mem_malloc(result_len); + if (!link_stats_results) + return -EINVAL; + + WMI_MAC_ADDR_TO_CHAR_ARRAY(&fixed_param->peer_macaddr, &mac_address[0]); + wma_debug("Peer power state change event from FW"); + wma_debug("Fixed Param:"); + wma_nofl_debug("MAC address: %2x:%2x:%2x:%2x:%2x:%2x, Power state: %d", + mac_address[0], mac_address[1], mac_address[2], + mac_address[3], mac_address[4], mac_address[5], + fixed_param->peer_ps_state); + + link_stats_results->paramId = WMI_LL_STATS_EXT_PS_CHG; + link_stats_results->num_peers = 1; + link_stats_results->peer_event_number = 1; + link_stats_results->moreResultToFollow = 0; + + peer_stat = (struct wifi_peer_stat *)link_stats_results->results; + peer_stat->num_peers = 1; + peer_info = (struct wifi_peer_info *)peer_stat->peer_info; + qdf_mem_copy(&peer_info->peer_macaddr, + &mac_address, + sizeof(tSirMacAddr)); + peer_info->power_saving = fixed_param->peer_ps_state; + + sme_msg.type = eWMI_SME_LL_STATS_IND; + sme_msg.bodyptr = link_stats_results; + sme_msg.bodyval = 0; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("Fail to post ps change ind msg"); + qdf_mem_free(link_stats_results); + } + + return 0; +} +#else +/** + * wma_peer_ps_evt_handler() - handler for PEER power state change. + * @handle: wma handle + * @event: FW event + * @len: length of FW event + * + * Once peer STA power state changes, an event will be indicated by + * FW. This function send a link layer state change msg to HDD. HDD + * link layer callback will converts the event to NL msg. + * + * Return: 0 Success. Others fail. + */ +static inline int wma_peer_ps_evt_handler(void *handle, u_int8_t *event, + u_int32_t len) +{ + return 0; +} +#endif + +/** + * wma_register_ll_stats_event_handler() - register link layer stats related + * event handler + * @wma_handle: wma handle + * + * Return: none + */ +void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle) +{ + if (wma_validate_handle(wma_handle)) + return; + + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_iface_link_stats_event_id, + wma_unified_link_iface_stats_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_link_stats_event_id, + wma_unified_link_peer_stats_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_radio_link_stats_link, + wma_unified_link_radio_stats_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_radio_tx_power_level_stats_event_id, + wma_unified_radio_tx_power_level_stats_event_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_peer_sta_ps_statechg_event_id, + wma_peer_ps_evt_handler, + WMA_RX_WORK_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + wmi_report_stats_event_id, + wma_ll_stats_evt_handler, + WMA_RX_WORK_CTX); + +} + +QDF_STATUS wma_process_ll_stats_clear_req(tp_wma_handle wma, + const tpSirLLStatsClearReq clearReq) +{ + uint8_t *addr; + struct ll_stats_clear_params cmd = {0}; + int ret; + struct wlan_objmgr_vdev *vdev; + + if (!clearReq || !wma) { + wma_err("input pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + vdev = wma->interfaces[clearReq->staId].vdev; + if (!vdev) { + wma_err("vdev is NULL for vdev_%d", clearReq->staId); + return QDF_STATUS_E_FAILURE; + } + + cmd.stop_req = clearReq->stopReq; + cmd.vdev_id = clearReq->staId; + cmd.stats_clear_mask = clearReq->statsClearReqMask; + + vdev = wma->interfaces[clearReq->staId].vdev; + if (!vdev) { + wma_err("Failed to get vdev for vdev_%d", clearReq->staId); + return QDF_STATUS_E_FAILURE; + } + addr = wlan_vdev_mlme_get_macaddr(vdev); + if (!addr) { + wma_err("Failed to get macaddr for vdev_%d", clearReq->staId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(cmd.peer_macaddr.bytes, addr, QDF_MAC_ADDR_SIZE); + ret = wmi_unified_process_ll_stats_clear_cmd(wma->wmi_handle, &cmd); + if (ret) { + wma_err("Failed to send clear link stats req"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_process_ll_stats_set_req() - link layer stats set request + * @wma: wma handle + * @setReq: ll stats set request command params + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_process_ll_stats_set_req(tp_wma_handle wma, + const tpSirLLStatsSetReq setReq) +{ + struct ll_stats_set_params cmd = {0}; + int ret; + + if (!setReq || !wma) { + wma_err("input pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + cmd.mpdu_size_threshold = setReq->mpduSizeThreshold; + cmd.aggressive_statistics_gathering = + setReq->aggressiveStatisticsGathering; + + ret = wmi_unified_process_ll_stats_set_cmd(wma->wmi_handle, + &cmd); + if (ret) { + wma_err("Failed to send set link stats request"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +#ifdef FEATURE_CLUB_LL_STATS_AND_GET_STATION +static QDF_STATUS +wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle, + struct ll_stats_get_params *cmd) +{ + if (!(cfg_get(wma_handle->psoc, CFG_CLUB_LL_STA_AND_GET_STATION) && + wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_get_station_in_ll_stats_req) && + wma_handle->interfaces[cmd->vdev_id].type == WMI_VDEV_TYPE_STA)) + return wmi_unified_process_ll_stats_get_cmd( + wma_handle->wmi_handle, cmd); + + return wmi_process_unified_ll_stats_get_sta_cmd(wma_handle->wmi_handle, + cmd); +} +#else +static QDF_STATUS +wma_send_ll_stats_get_cmd(tp_wma_handle wma_handle, + struct ll_stats_get_params *cmd) +{ + return wmi_unified_process_ll_stats_get_cmd(wma_handle->wmi_handle, + cmd); +} +#endif + +#ifdef WLAN_FEATURE_11BE_MLO +static QDF_STATUS +wma_update_params_for_mlo_stats(tp_wma_handle wma, + const tpSirLLStatsGetReq getReq, + struct ll_stats_get_params *cmd) +{ + struct wlan_objmgr_vdev *vdev; + uint8_t *mld_addr; + + cmd->is_mlo_req = getReq->is_mlo_req; + + vdev = wma->interfaces[getReq->staId].vdev; + if (!vdev) { + wma_err("Failed to get vdev for vdev_%d", getReq->staId); + return QDF_STATUS_E_FAILURE; + } + if (getReq->is_mlo_req) { + cmd->vdev_id_bitmap = getReq->mlo_vdev_id_bitmap; + mld_addr = wlan_vdev_mlme_get_mldaddr(vdev); + if (!mld_addr) { + wma_err("Failed to get mld_macaddr for vdev_%d", + getReq->staId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(cmd->mld_macaddr.bytes, mld_addr, + QDF_MAC_ADDR_SIZE); + } + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +wma_update_params_for_mlo_stats(tp_wma_handle wma, + const tpSirLLStatsGetReq getReq, + struct ll_stats_get_params *cmd) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +QDF_STATUS wma_process_ll_stats_get_req(tp_wma_handle wma, + const tpSirLLStatsGetReq getReq) +{ + struct wlan_objmgr_vdev *vdev; + uint8_t *addr; + struct ll_stats_get_params cmd = {0}; + int ret; + QDF_STATUS status; + + if (!getReq || !wma) { + wma_err("input pointer is NULL"); + return QDF_STATUS_E_FAILURE; + } + + if (!wma_is_vdev_valid(getReq->staId)) { + wma_err("vdev:%d not created yet", getReq->staId); + return QDF_STATUS_E_FAILURE; + } + + cmd.req_id = getReq->reqId; + cmd.param_id_mask = getReq->paramIdMask; + cmd.vdev_id = getReq->staId; + + vdev = wma->interfaces[getReq->staId].vdev; + if (!vdev) { + wma_err("Failed to get vdev for vdev_%d", getReq->staId); + return QDF_STATUS_E_FAILURE; + } + addr = wlan_vdev_mlme_get_macaddr(vdev); + if (!addr) { + wma_err("Failed to get macaddr for vdev_%d", getReq->staId); + return QDF_STATUS_E_FAILURE; + } + qdf_mem_copy(cmd.peer_macaddr.bytes, addr, QDF_MAC_ADDR_SIZE); + + if (getReq->mlo_vdev_id_bitmap) { + status = wma_update_params_for_mlo_stats(wma, getReq, &cmd); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to update params for mlo_stats"); + return status; + } + } + + ret = wma_send_ll_stats_get_cmd(wma, &cmd); + if (ret) { + wma_err("Failed to send get link stats request"); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_unified_link_iface_stats_event_handler() - link iface stats event handler + * @handle: wma handle + * @cmd_param_info: data from event + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_link_iface_stats_event_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_iface_link_stats_event_fixed_param *fixed_param; + wmi_iface_link_stats *link_stats, *iface_link_stats; + wmi_wmm_ac_stats *ac_stats, *iface_ac_stats; + wmi_iface_offload_stats *offload_stats, *iface_offload_stats; + wmi_iface_powersave_stats *powersave_stats; + tSirLLStatsResults *link_stats_results; + struct wifi_interface_stats *iface_stat; + uint32_t count; + size_t link_stats_size, ac_stats_size, iface_info_size; + size_t link_stats_results_size, offload_stats_size; + size_t total_ac_size, total_offload_size; + bool db2dbm_enabled; + + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + + if (!mac) { + wma_debug("NULL mac ptr. Exiting"); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_cb) { + wma_debug("HDD callback is null"); + return -EINVAL; + } + + param_tlvs = (WMI_IFACE_LINK_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_tlvs) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + /* + * cmd_param_info contains + * wmi_iface_link_stats_event_fixed_param fixed_param; + * wmi_iface_link_stats iface_link_stats; + * iface_link_stats->num_ac * size of(struct wmi_wmm_ac_stats) + * fixed_param->num_offload_stats * size of(wmi_iface_offload_stats); + */ + fixed_param = param_tlvs->fixed_param; + link_stats = param_tlvs->iface_link_stats; + ac_stats = param_tlvs->ac; + offload_stats = param_tlvs->iface_offload_stats; + + if (!fixed_param || !link_stats || (link_stats->num_ac && !ac_stats) || + (fixed_param->num_offload_stats && !offload_stats)) { + wma_err("Invalid param_tlvs for Iface Stats"); + return -EINVAL; + } + if (link_stats->num_ac > WIFI_AC_MAX || link_stats->num_ac > + param_tlvs->num_ac) { + wma_err("Excess data received from firmware num_ac %d, param_tlvs->num_ac %d", + link_stats->num_ac, param_tlvs->num_ac); + return -EINVAL; + } + if (fixed_param->num_offload_stats > WMI_OFFLOAD_STATS_TYPE_MAX || + fixed_param->num_offload_stats > + param_tlvs->num_iface_offload_stats) { + wma_err("Excess num offload stats recvd from fw: %d, um_iface_offload_stats: %d", + fixed_param->num_offload_stats, + param_tlvs->num_iface_offload_stats); + return -EINVAL; + } + + link_stats_size = sizeof(struct wifi_interface_stats); + iface_info_size = sizeof(struct wifi_interface_info); + + ac_stats_size = sizeof(wmi_wmm_ac_stats); + offload_stats_size = sizeof(wmi_iface_offload_stats); + + total_ac_size = ac_stats_size * WIFI_AC_MAX; + total_offload_size = offload_stats_size * WMI_OFFLOAD_STATS_TYPE_MAX + + member_size(struct wifi_interface_stats, + num_offload_stats); + + link_stats_results_size = sizeof(*link_stats_results) + link_stats_size; + + link_stats_results = qdf_mem_malloc(link_stats_results_size); + if (!link_stats_results) + return -ENOMEM; + + qdf_mem_zero(link_stats_results, link_stats_results_size); + + link_stats_results->paramId = WMI_LINK_STATS_IFACE; + link_stats_results->rspId = fixed_param->request_id; + link_stats_results->ifaceId = fixed_param->vdev_id; + link_stats_results->num_peers = link_stats->num_peers; + link_stats_results->peer_event_number = 0; + link_stats_results->moreResultToFollow = 0; + + /* results is copied to struct wifi_interface_stats in upper layer + * struct wifi_interface_stats + * - struct wifi_interface_info (all fields except roaming is + * filled by host in the upper layer) + * - various members of struct wifi_interface_stats (from + * wmi_iface_link_stats) + * - ACs information (from wmi_wmm_ac_stats) + * - num_offload_stats (from fixed param) + * - offload stats (from wmi_iface_offload_stats) + */ + + iface_stat = (struct wifi_interface_stats *)link_stats_results->results; + + iface_link_stats = &iface_stat->link_stats; + *iface_link_stats = *link_stats; + db2dbm_enabled = wmi_service_enabled(wma_handle->wmi_handle, + wmi_service_hw_db2dbm_support); + if (!db2dbm_enabled) { + /* FW doesn't indicate support for HW db2dbm conversion */ + iface_link_stats->rssi_mgmt += WMA_TGT_NOISE_FLOOR_DBM; + iface_link_stats->rssi_data += WMA_TGT_NOISE_FLOOR_DBM; + iface_link_stats->rssi_ack += WMA_TGT_NOISE_FLOOR_DBM; + } + + /* Copy roaming state */ + iface_stat->info.roaming = link_stats->roam_state; + /* Copy time slicing duty cycle */ + iface_stat->info.time_slice_duty_cycle = + link_stats->time_slice_duty_cycle; + + wma_debug("db2dbm: %d, rssi_mgmt: %d, rssi_data: %d, rssi_ack: %d, beacon_rx %u, time_slice_duty_cycle %u", + db2dbm_enabled, iface_link_stats->rssi_mgmt, + iface_link_stats->rssi_data, iface_link_stats->rssi_ack, + iface_link_stats->beacon_rx, + iface_stat->info.time_slice_duty_cycle); + + iface_ac_stats = &iface_stat->ac_stats[0]; + for (count = 0; count < link_stats->num_ac; count++) { + *iface_ac_stats = *ac_stats; + ac_stats++; + iface_ac_stats++; + } + + /* Copy wmi_iface_offload_stats to wifi_iface_offload_stat */ + iface_stat->num_offload_stats = fixed_param->num_offload_stats; + iface_offload_stats = &iface_stat->offload_stats[0]; + for (count = 0; count < fixed_param->num_offload_stats; count++) { + *iface_offload_stats = *offload_stats; + offload_stats++; + iface_offload_stats++; + } + + powersave_stats = param_tlvs->iface_powersave_stats; + if (powersave_stats) + iface_stat->powersave_stats = *powersave_stats; + + /* Copying vdev_id info into the iface_stat for MLO*/ + iface_stat->vdev_id = fixed_param->vdev_id; + + /* call hdd callback with Link Layer Statistics + * vdev_id/ifacId in link_stats_results will be + * used to retrieve the correct HDD context + */ + mac->sme.link_layer_stats_cb(mac->hdd_handle, + WMA_LINK_LAYER_STATS_RESULTS_RSP, + link_stats_results, + mac->sme.ll_stats_context); + qdf_mem_free(link_stats_results); + + return 0; +} + +/** + * wma_config_stats_ext_threshold - set threthold for MAC counters + * @wma: wma handler + * @thresh: threshold for MAC counters + * + * For each MAC layer counter, FW holds two copies. One is the current value. + * The other is the last report. Once a current counter's increment is larger + * than the threshold, FW will indicate that counter to host even if the + * monitoring timer does not expire. + * + * Return: None + */ +void wma_config_stats_ext_threshold(tp_wma_handle wma, + struct sir_ll_ext_stats_threshold *thresh) +{ + QDF_STATUS status; + uint32_t len, tag, hdr_len; + uint8_t *buf_ptr; + wmi_buf_t buf; + wmi_pdev_set_stats_threshold_cmd_fixed_param *cmd; + wmi_chan_cca_stats_thresh *cca; + wmi_peer_signal_stats_thresh *signal; + wmi_tx_stats_thresh *tx; + wmi_rx_stats_thresh *rx; + + if (!thresh) { + wma_err("Invalid threshold input"); + return; + } + + len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param) + + sizeof(wmi_chan_cca_stats_thresh) + + sizeof(wmi_peer_signal_stats_thresh) + + sizeof(wmi_tx_stats_thresh) + + sizeof(wmi_rx_stats_thresh) + + 5 * WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) + return; + + buf_ptr = (u_int8_t *)wmi_buf_data(buf); + tag = WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param; + hdr_len = WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_stats_threshold_cmd_fixed_param); + wma_debug("Setting fixed parameters. tag=%d, len=%d", tag, hdr_len); + cmd = (wmi_pdev_set_stats_threshold_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, tag, hdr_len); + cmd->enable_thresh = thresh->enable; + cmd->use_thresh_bitmap = thresh->enable_bitmap; + cmd->gbl_thresh = thresh->global_threshold; + cmd->cca_thresh_enable_bitmap = thresh->cca_bitmap; + cmd->signal_thresh_enable_bitmap = thresh->signal_bitmap; + cmd->tx_thresh_enable_bitmap = thresh->tx_bitmap; + cmd->rx_thresh_enable_bitmap = thresh->rx_bitmap; + len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param); + + tag = WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh, + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_chan_cca_stats_thresh); + cca = (wmi_chan_cca_stats_thresh *)(buf_ptr + len); + WMITLV_SET_HDR(&cca->tlv_header, tag, hdr_len); + wma_debug("Setting cca parameters. tag=%d, len=%d", tag, hdr_len); + cca->idle_time = thresh->cca.idle_time; + cca->tx_time = thresh->cca.tx_time; + cca->rx_in_bss_time = thresh->cca.rx_in_bss_time; + cca->rx_out_bss_time = thresh->cca.rx_out_bss_time; + cca->rx_busy_time = thresh->cca.rx_busy_time; + cca->rx_in_bad_cond_time = thresh->cca.rx_in_bad_cond_time; + cca->tx_in_bad_cond_time = thresh->cca.tx_in_bad_cond_time; + cca->wlan_not_avail_time = thresh->cca.wlan_not_avail_time; + wma_debug("idle time=%d, tx_time=%d, in_bss=%d, out_bss=%d", + cca->idle_time, cca->tx_time, + cca->rx_in_bss_time, cca->rx_out_bss_time); + wma_debug("rx_busy=%d, rx_bad=%d, tx_bad=%d, not_avail=%d", + cca->rx_busy_time, cca->rx_in_bad_cond_time, + cca->tx_in_bad_cond_time, cca->wlan_not_avail_time); + len += sizeof(wmi_chan_cca_stats_thresh); + + signal = (wmi_peer_signal_stats_thresh *)(buf_ptr + len); + tag = WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh; + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_peer_signal_stats_thresh); + wma_debug("Setting signal parameters. tag=%d, len=%d", tag, hdr_len); + WMITLV_SET_HDR(&signal->tlv_header, tag, hdr_len); + signal->per_chain_snr = thresh->signal.snr; + signal->per_chain_nf = thresh->signal.nf; + wma_debug("snr=%d, nf=%d", signal->per_chain_snr, + signal->per_chain_nf); + len += sizeof(wmi_peer_signal_stats_thresh); + + tx = (wmi_tx_stats_thresh *)(buf_ptr + len); + tag = WMITLV_TAG_STRUC_wmi_tx_stats_thresh; + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_tx_stats_thresh); + wma_debug("Setting TX parameters. tag=%d, len=%d", tag, len); + WMITLV_SET_HDR(&tx->tlv_header, tag, hdr_len); + tx->tx_msdu_cnt = thresh->tx.msdu; + tx->tx_mpdu_cnt = thresh->tx.mpdu; + tx->tx_ppdu_cnt = thresh->tx.ppdu; + tx->tx_bytes = thresh->tx.bytes; + tx->tx_msdu_drop_cnt = thresh->tx.msdu_drop; + tx->tx_drop_bytes = thresh->tx.byte_drop; + tx->tx_mpdu_retry_cnt = thresh->tx.mpdu_retry; + tx->tx_mpdu_fail_cnt = thresh->tx.mpdu_fail; + tx->tx_ppdu_fail_cnt = thresh->tx.ppdu_fail; + tx->tx_mpdu_aggr = thresh->tx.aggregation; + tx->tx_succ_mcs = thresh->tx.succ_mcs; + tx->tx_fail_mcs = thresh->tx.fail_mcs; + tx->tx_ppdu_delay = thresh->tx.delay; + wma_debug("msdu=%d, mpdu=%d, ppdu=%d, bytes=%d, msdu_drop=%d", + tx->tx_msdu_cnt, tx->tx_mpdu_cnt, tx->tx_ppdu_cnt, + tx->tx_bytes, tx->tx_msdu_drop_cnt); + wma_debug("byte_drop=%d, mpdu_retry=%d, mpdu_fail=%d, ppdu_fail=%d", + tx->tx_drop_bytes, tx->tx_mpdu_retry_cnt, + tx->tx_mpdu_fail_cnt, tx->tx_ppdu_fail_cnt); + wma_debug("aggr=%d, succ_mcs=%d, fail_mcs=%d, delay=%d", + tx->tx_mpdu_aggr, tx->tx_succ_mcs, tx->tx_fail_mcs, + tx->tx_ppdu_delay); + len += sizeof(wmi_tx_stats_thresh); + + rx = (wmi_rx_stats_thresh *)(buf_ptr + len); + tag = WMITLV_TAG_STRUC_wmi_rx_stats_thresh, + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_rx_stats_thresh); + WMITLV_SET_HDR(&rx->tlv_header, tag, hdr_len); + wma_debug("Setting RX parameters. tag=%d, len=%d", tag, hdr_len); + rx->mac_rx_mpdu_cnt = thresh->rx.mpdu; + rx->mac_rx_bytes = thresh->rx.bytes; + rx->phy_rx_ppdu_cnt = thresh->rx.ppdu; + rx->phy_rx_bytes = thresh->rx.ppdu_bytes; + rx->rx_disorder_cnt = thresh->rx.disorder; + rx->rx_mpdu_retry_cnt = thresh->rx.mpdu_retry; + rx->rx_mpdu_dup_cnt = thresh->rx.mpdu_dup; + rx->rx_mpdu_discard_cnt = thresh->rx.mpdu_discard; + rx->rx_mpdu_aggr = thresh->rx.aggregation; + rx->rx_mcs = thresh->rx.mcs; + rx->sta_ps_inds = thresh->rx.ps_inds; + rx->sta_ps_durs = thresh->rx.ps_durs; + rx->rx_probe_reqs = thresh->rx.probe_reqs; + rx->rx_oth_mgmts = thresh->rx.other_mgmt; + wma_debug("rx_mpdu=%d, rx_bytes=%d, rx_ppdu=%d, rx_pbytes=%d", + rx->mac_rx_mpdu_cnt, rx->mac_rx_bytes, + rx->phy_rx_ppdu_cnt, rx->phy_rx_bytes); + wma_debug("disorder=%d, rx_dup=%d, rx_aggr=%d, rx_mcs=%d", + rx->rx_disorder_cnt, rx->rx_mpdu_dup_cnt, + rx->rx_mpdu_aggr, rx->rx_mcs); + wma_debug("rx_ind=%d, rx_dur=%d, rx_probe=%d, rx_mgmt=%d", + rx->sta_ps_inds, rx->sta_ps_durs, + rx->rx_probe_reqs, rx->rx_oth_mgmts); + len += sizeof(wmi_rx_stats_thresh); + + wma_alert("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d", + WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len); + status = wmi_unified_cmd_send(wma->wmi_handle, buf, len, + WMI_PDEV_SET_STATS_THRESHOLD_CMDID); + if (QDF_IS_STATUS_ERROR(status)) + wmi_buf_free(buf); +} +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +/** + * wma_post_link_status() - post link status to SME + * @pGetLinkStatus: SME Link status + * @link_status: Link status + * + * Return: none + */ +void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, + uint8_t link_status) +{ + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + struct scheduler_msg sme_msg = { 0 }; + + pGetLinkStatus->linkStatus = link_status; + sme_msg.type = eWNI_SME_LINK_STATUS_IND; + sme_msg.bodyptr = pGetLinkStatus; + sme_msg.bodyval = 0; + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("Fail to post link status ind msg"); + qdf_mem_free(pGetLinkStatus); + } +} + +int wma_link_status_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle) handle; + WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *param_buf; + wmi_vdev_rate_stats_event_fixed_param *event; + wmi_vdev_rate_ht_info *ht_info; + struct wma_txrx_node *intr = wma->interfaces; + uint8_t link_status = LINK_STATUS_LEGACY; + uint32_t i, rate_flag; + QDF_STATUS status; + + param_buf = + (WMI_UPDATE_VDEV_RATE_STATS_EVENTID_param_tlvs *) cmd_param_info; + if (!param_buf) { + wma_err("Invalid stats event"); + return -EINVAL; + } + + event = (wmi_vdev_rate_stats_event_fixed_param *) + param_buf->fixed_param; + ht_info = (wmi_vdev_rate_ht_info *) param_buf->ht_info; + + if (!ht_info) { + wma_err("Invalid ht_info"); + return -EINVAL; + } + + wma_debug("num_vdev_stats: %d", event->num_vdev_stats); + + if (event->num_vdev_stats > ((WMI_SVC_MSG_MAX_SIZE - + sizeof(*event)) / sizeof(*ht_info)) || + event->num_vdev_stats > param_buf->num_ht_info) { + wma_err("excess vdev_stats buffers:%d, num_ht_info:%d", + event->num_vdev_stats, + param_buf->num_ht_info); + return -EINVAL; + } + + if (!wma_is_vdev_valid(ht_info->vdevid)) { + wma_err("Invalid vdevid %d", ht_info->vdevid); + return -EINVAL; + } + + if (!intr[ht_info->vdevid].vdev) { + wma_err("Vdev is NULL"); + return -EINVAL; + } + + status = wma_get_vdev_rate_flag(intr[ht_info->vdevid].vdev, &rate_flag); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get rate flag"); + return -EINVAL; + } + + for (i = 0; (i < event->num_vdev_stats) && ht_info; i++) { + wma_debug("vdevId:%d tx_nss:%d rx_nss:%d tx_preamble:%d rx_preamble:%d", + ht_info->vdevid, ht_info->tx_nss, + ht_info->rx_nss, ht_info->tx_preamble, + ht_info->rx_preamble); + if (ht_info->vdevid < wma->max_bssid + && intr[ht_info->vdevid].plink_status_req) { + if (ht_info->tx_nss || ht_info->rx_nss) + link_status = LINK_STATUS_MIMO; + + if ((ht_info->tx_preamble == LINK_RATE_VHT) || + (ht_info->rx_preamble == LINK_RATE_VHT)) + link_status |= LINK_STATUS_VHT; + + if (intr[ht_info->vdevid].nss == 2) + link_status |= LINK_SUPPORT_MIMO; + + if (rate_flag & + (TX_RATE_VHT20 | TX_RATE_VHT40 | + TX_RATE_VHT80)) + link_status |= LINK_SUPPORT_VHT; + + wma_post_link_status( + intr[ht_info->vdevid].plink_status_req, + link_status); + intr[ht_info->vdevid].plink_status_req = NULL; + link_status = LINK_STATUS_LEGACY; + } + + ht_info++; + } + + return 0; +} + +int wma_rso_cmd_status_event_handler(uint8_t vdev_id, enum cm_roam_notif notif) +{ + struct rso_cmd_status *rso_status; + struct scheduler_msg sme_msg = {0}; + QDF_STATUS qdf_status; + + rso_status = qdf_mem_malloc(sizeof(*rso_status)); + if (!rso_status) + return -ENOMEM; + + rso_status->vdev_id = vdev_id; + if (notif == CM_ROAM_NOTIF_SCAN_MODE_SUCCESS) + rso_status->status = true; + else if (notif == CM_ROAM_NOTIF_SCAN_MODE_FAIL) + rso_status->status = false; + sme_msg.type = eWNI_SME_RSO_CMD_STATUS_IND; + sme_msg.bodyptr = rso_status; + sme_msg.bodyval = 0; + wma_debug("Post RSO cmd status to SME"); + + qdf_status = scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + wma_err("fail to post RSO cmd status to SME"); + qdf_mem_free(rso_status); + } + return 0; +} + +/** + * wma_send_link_speed() - send link speed to SME + * @link_speed: link speed + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wma_send_link_speed(uint32_t link_speed) +{ + struct mac_context *mac_ctx; + struct link_speed_info *ls_ind; + + mac_ctx = cds_get_context(QDF_MODULE_ID_PE); + if (!mac_ctx) { + wma_debug("NULL mac ptr. Exiting"); + return QDF_STATUS_E_INVAL; + } + + ls_ind = qdf_mem_malloc(sizeof(*ls_ind)); + if (!ls_ind) + return QDF_STATUS_E_NOMEM; + + ls_ind->estLinkSpeed = link_speed; + if (mac_ctx->sme.link_speed_cb) + mac_ctx->sme.link_speed_cb(ls_ind, + mac_ctx->sme.link_speed_context); + else + wma_debug("link_speed_cb is null"); + qdf_mem_free(ls_ind); + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_link_speed_event_handler() - link speed event handler + * @handle: wma handle + * @cmd_param_info: event data + * @len: length + * + * Return: 0 for success or error code + */ +int wma_link_speed_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *param_buf; + wmi_peer_estimated_linkspeed_event_fixed_param *event; + QDF_STATUS qdf_status; + + param_buf = (WMI_PEER_ESTIMATED_LINKSPEED_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid linkspeed event"); + return -EINVAL; + } + event = param_buf->fixed_param; + qdf_status = wma_send_link_speed(event->est_linkspeed_kbps); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) + return -EINVAL; + return 0; +} + +#define BIG_ENDIAN_MAX_DEBUG_BUF 500 +/** + * wma_unified_debug_print_event_handler() - debug print event handler + * @handle: wma handle + * @datap: data pointer + * @len: length + * + * Return: 0 for success or error code + */ +int wma_unified_debug_print_event_handler(void *handle, uint8_t *datap, + uint32_t len) +{ + WMI_DEBUG_PRINT_EVENTID_param_tlvs *param_buf; + uint8_t *data; + uint32_t datalen; + + param_buf = (WMI_DEBUG_PRINT_EVENTID_param_tlvs *) datap; + if (!param_buf || !param_buf->data) { + wma_err("Get NULL point message from FW"); + return -ENOMEM; + } + data = param_buf->data; + datalen = param_buf->num_data; + if (datalen > WMI_SVC_MSG_MAX_SIZE) { + wma_err("Received data len %d exceeds max value %d", + datalen, WMI_SVC_MSG_MAX_SIZE); + return QDF_STATUS_E_FAILURE; + } + data[datalen - 1] = '\0'; + +#ifdef BIG_ENDIAN_HOST + { + if (datalen >= BIG_ENDIAN_MAX_DEBUG_BUF) { + wma_err("Invalid data len %d, limiting to max", + datalen); + datalen = BIG_ENDIAN_MAX_DEBUG_BUF - 1; + } + char dbgbuf[BIG_ENDIAN_MAX_DEBUG_BUF] = { 0 }; + + memcpy(dbgbuf, data, datalen); + SWAPME(dbgbuf, datalen); + wma_debug("FIRMWARE:%s", dbgbuf); + return 0; + } +#else + wma_debug("FIRMWARE:%s", data); + return 0; +#endif /* BIG_ENDIAN_HOST */ +} + +enum wlan_phymode +wma_peer_phymode(tSirNwType nw_type, uint8_t sta_type, + uint8_t is_ht, uint8_t ch_width, + uint8_t is_vht, bool is_he, bool is_eht) +{ + enum wlan_phymode phymode = WLAN_PHYMODE_AUTO; + + switch (nw_type) { + case eSIR_11B_NW_TYPE: +#ifdef FEATURE_WLAN_TDLS + if (STA_ENTRY_TDLS_PEER == sta_type) { + if (is_he) + phymode = WLAN_PHYMODE_11AXG_HE20; + else if (is_vht) + phymode = WLAN_PHYMODE_11AC_VHT20_2G; + else if (is_ht) + phymode = WLAN_PHYMODE_11NG_HT20; + else + phymode = WLAN_PHYMODE_11B; + } else +#endif /* FEATURE_WLAN_TDLS */ + { + phymode = WLAN_PHYMODE_11B; + if (is_ht || is_vht || is_he || is_eht) + wma_err("HT/VHT is enabled with 11B NW type"); + } + break; + case eSIR_11G_NW_TYPE: + if (!(is_ht || is_vht || is_he || is_eht)) { + phymode = WLAN_PHYMODE_11G; + break; + } + if (CH_WIDTH_40MHZ < ch_width) + wma_err("80/160 MHz BW sent in 11G, configured 40MHz"); +#ifdef WLAN_FEATURE_11BE + if (ch_width) + phymode = (is_eht) ? WLAN_PHYMODE_11BEG_EHT40 : + (is_he) ? WLAN_PHYMODE_11AXG_HE40 : + (is_vht) ? WLAN_PHYMODE_11AC_VHT40_2G : + WLAN_PHYMODE_11NG_HT40; + else + phymode = (is_eht) ? WLAN_PHYMODE_11BEG_EHT20 : + (is_he) ? WLAN_PHYMODE_11AXG_HE20 : + (is_vht) ? WLAN_PHYMODE_11AC_VHT20_2G : + WLAN_PHYMODE_11NG_HT20; +#else + if (ch_width) + phymode = (is_he) ? WLAN_PHYMODE_11AXG_HE40 : (is_vht) ? + WLAN_PHYMODE_11AC_VHT40_2G : + WLAN_PHYMODE_11NG_HT40; + else + phymode = (is_he) ? WLAN_PHYMODE_11AXG_HE20 : (is_vht) ? + WLAN_PHYMODE_11AC_VHT20_2G : + WLAN_PHYMODE_11NG_HT20; +#endif + break; + case eSIR_11A_NW_TYPE: + if (!(is_ht || is_vht || is_he || is_eht)) { + phymode = WLAN_PHYMODE_11A; + break; + } +#if defined(WLAN_FEATURE_11BE) + if (is_eht) { + if (ch_width == CH_WIDTH_160MHZ) + phymode = WLAN_PHYMODE_11BEA_EHT160; + else if (ch_width == CH_WIDTH_320MHZ) + phymode = WLAN_PHYMODE_11BEA_EHT320; + else if (ch_width == CH_WIDTH_80MHZ) + phymode = WLAN_PHYMODE_11BEA_EHT80; + else + phymode = (ch_width) ? + WLAN_PHYMODE_11BEA_EHT40 : + WLAN_PHYMODE_11BEA_EHT20; + } else +#endif + if (is_he) { + if (ch_width == CH_WIDTH_160MHZ) + phymode = WLAN_PHYMODE_11AXA_HE160; + else if (ch_width == CH_WIDTH_80P80MHZ) + phymode = WLAN_PHYMODE_11AXA_HE80_80; + else if (ch_width == CH_WIDTH_80MHZ) + phymode = WLAN_PHYMODE_11AXA_HE80; + else + phymode = (ch_width) ? + WLAN_PHYMODE_11AXA_HE40 : + WLAN_PHYMODE_11AXA_HE20; + } else if (is_vht) { + if (ch_width == CH_WIDTH_160MHZ) + phymode = WLAN_PHYMODE_11AC_VHT160; + else if (ch_width == CH_WIDTH_80P80MHZ) + phymode = WLAN_PHYMODE_11AC_VHT80_80; + else if (ch_width == CH_WIDTH_80MHZ) + phymode = WLAN_PHYMODE_11AC_VHT80; + else + phymode = (ch_width) ? + WLAN_PHYMODE_11AC_VHT40 : + WLAN_PHYMODE_11AC_VHT20; + } else + phymode = (ch_width) ? WLAN_PHYMODE_11NA_HT40 : + WLAN_PHYMODE_11NA_HT20; + break; + default: + wma_err("Invalid nw type %d", nw_type); + break; + } + wma_debug("nw_type %d is_ht %d ch_width %d is_vht %d is_he %d is_eht %d phymode %d", + nw_type, is_ht, ch_width, is_vht, is_he, is_eht, phymode); + + return phymode; +} + +/** + * wma_txrx_fw_stats_reset() - reset txrx fw statistics + * @wma_handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: 0 for success or return error + */ +int32_t wma_txrx_fw_stats_reset(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value) +{ + struct ol_txrx_stats_req req; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + wma_err("SOC context is NULL"); + return -EINVAL; + } + + qdf_mem_zero(&req, sizeof(req)); + req.stats_type_reset_mask = value; + cdp_fw_stats_get(soc, vdev_id, &req, false, false); + + return 0; +} + +#ifdef HELIUMPLUS +#define SET_UPLOAD_MASK(_mask, _rate_info) \ + ((_mask) = 1 << (_rate_info ## _V2)) +#else /* !HELIUMPLUS */ +#define SET_UPLOAD_MASK(_mask, _rate_info) \ + ((_mask) = 1 << (_rate_info)) +#endif + +#if defined(HELIUMPLUS) || defined(QCN7605_SUPPORT) +static bool wma_is_valid_fw_stats_cmd(uint32_t value) +{ + if (value > (HTT_DBG_NUM_STATS + 1) || + value == (HTT_DBG_STATS_RX_RATE_INFO + 1) || + value == (HTT_DBG_STATS_TX_RATE_INFO + 1) || + value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) { + wma_err("Not supported"); + return false; + } + return true; +} +#else +static bool wma_is_valid_fw_stats_cmd(uint32_t value) +{ + if (value > (HTT_DBG_NUM_STATS + 1) || + value == (HTT_DBG_STATS_RX_RATE_INFO_V2 + 1) || + value == (HTT_DBG_STATS_TX_RATE_INFO_V2 + 1) || + value == (HTT_DBG_STATS_TXBF_MUSU_NDPA_PKT + 1)) { + wma_err("Not supported"); + return false; + } + return true; +} +#endif + +/** + * wma_set_txrx_fw_stats_level() - set txrx fw stats level + * @wma_handle: wma handle + * @vdev_id: vdev id + * @value: value + * + * Return: 0 for success or return error + */ +int32_t wma_set_txrx_fw_stats_level(tp_wma_handle wma_handle, + uint8_t vdev_id, uint32_t value) +{ + struct ol_txrx_stats_req req; + uint32_t l_up_mask; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (!soc) { + wma_err("SOC context is NULL"); + return -EINVAL; + } + + if (wma_is_valid_fw_stats_cmd(value) == false) + return -EINVAL; + + qdf_mem_zero(&req, sizeof(req)); + req.print.verbose = 1; + + /* TODO: Need to check how to avoid mem leak*/ + l_up_mask = 1 << (value - 1); + req.stats_type_upload_mask = l_up_mask; + + cdp_fw_stats_get(soc, vdev_id, &req, false, true); + + return 0; +} + +/** + * wma_get_cca_stats() - send request to fw to get CCA + * @wma_handle: wma handle + * @vdev_id: vdev id + * + * Return: QDF status + */ +QDF_STATUS wma_get_cca_stats(tp_wma_handle wma_handle, + uint8_t vdev_id) +{ + if (wmi_unified_congestion_request_cmd(wma_handle->wmi_handle, + vdev_id)) { + wma_err("Failed to congestion request to fw"); + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_beacon_buffer_by_vdev_id() - get the beacon buffer from vdev ID + * @vdev_id: vdev id + * @buffer_size: size of buffer + * + * Return: none + */ +void *wma_get_beacon_buffer_by_vdev_id(uint8_t vdev_id, uint32_t *buffer_size) +{ + tp_wma_handle wma; + struct beacon_info *beacon; + uint8_t *buf; + uint32_t buf_size; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return NULL; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %u", vdev_id); + return NULL; + } + + if (!wma_is_vdev_in_ap_mode(wma, vdev_id)) { + wma_err("vdevid %d is not in AP mode", vdev_id); + return NULL; + } + + beacon = wma->interfaces[vdev_id].beacon; + + if (!beacon) { + wma_err("beacon invalid"); + return NULL; + } + + qdf_spin_lock_bh(&beacon->lock); + + buf_size = qdf_nbuf_len(beacon->buf); + buf = qdf_mem_malloc(buf_size); + if (!buf) { + qdf_spin_unlock_bh(&beacon->lock); + return NULL; + } + + qdf_mem_copy(buf, qdf_nbuf_data(beacon->buf), buf_size); + + qdf_spin_unlock_bh(&beacon->lock); + + if (buffer_size) + *buffer_size = buf_size; + + return buf; +} + +uint8_t *wma_get_vdev_address_by_vdev_id(uint8_t vdev_id) +{ + tp_wma_handle wma; + struct wlan_objmgr_vdev *vdev; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return NULL; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %u", vdev_id); + return NULL; + } + vdev = wma->interfaces[vdev_id].vdev; + if (!vdev) { + wma_err("Invalid vdev for vdev_id %u", vdev_id); + return NULL; + } + return wlan_vdev_mlme_get_macaddr(vdev); +} + +QDF_STATUS wma_get_connection_info(uint8_t vdev_id, + struct policy_mgr_vdev_entry_info *conn_table_entry) +{ + struct wma_txrx_node *wma_conn_table_entry; + + wma_conn_table_entry = wma_get_interface_by_vdev_id(vdev_id); + if (!wma_conn_table_entry) { + wma_err("can't find vdev_id %d in WMA table", vdev_id); + return QDF_STATUS_E_FAILURE; + } + conn_table_entry->chan_width = wma_conn_table_entry->chan_width; + conn_table_entry->mac_id = wma_conn_table_entry->mac_id; + conn_table_entry->mhz = wma_conn_table_entry->ch_freq; + conn_table_entry->sub_type = wma_conn_table_entry->sub_type; + conn_table_entry->type = wma_conn_table_entry->type; + conn_table_entry->ch_flagext = wma_conn_table_entry->ch_flagext; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_ndi_update_connection_info(uint8_t vdev_id, + struct nan_datapath_channel_info *ndp_chan_info) +{ + struct wma_txrx_node *wma_iface_entry; + + wma_iface_entry = wma_get_interface_by_vdev_id(vdev_id); + if (!wma_iface_entry) { + wma_err("can't find vdev_id %d in WMA table", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (WMI_VDEV_TYPE_NDI != wma_iface_entry->type) { + wma_err("Given vdev id(%d) not of type NDI!", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + if (!ndp_chan_info) { + wma_err("Provided chan info is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + wma_iface_entry->chan_width = ndp_chan_info->ch_width; + wma_iface_entry->ch_freq = ndp_chan_info->freq; + wma_iface_entry->nss = ndp_chan_info->nss; + wma_iface_entry->mac_id = ndp_chan_info->mac_id; + + return QDF_STATUS_SUCCESS; +} + +/** + * wma_get_interface_by_vdev_id() - lookup interface entry using vdev ID + * @vdev_id: vdev id + * + * Return: entry from vdev table + */ +struct wma_txrx_node *wma_get_interface_by_vdev_id(uint8_t vdev_id) +{ + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return NULL; + + if (vdev_id >= wma->max_bssid) { + wma_err("Invalid vdev_id %u", vdev_id); + return NULL; + } + + return &wma->interfaces[vdev_id]; +} + +#ifdef WLAN_FEATURE_PKT_CAPTURE +int wma_get_rmf_status(uint8_t vdev_id) +{ + struct wma_txrx_node *iface; + + iface = wma_get_interface_by_vdev_id(vdev_id); + if (!iface) { + wma_err("Unable to get wma interface"); + return -EINVAL; + } + + return iface->rmfEnabled; +} +#endif + +/** + * wma_update_intf_hw_mode_params() - Update WMA params + * @vdev_id: VDEV id whose params needs to be updated + * @mac_id: MAC id to be updated + * @cfgd_hw_mode_index: HW mode index from which Tx and Rx SS will be updated + * + * Updates the MAC id, tx spatial stream, rx spatial stream in WMA + * + * Return: None + */ +void wma_update_intf_hw_mode_params(uint32_t vdev_id, uint32_t mac_id, + uint32_t cfgd_hw_mode_index) +{ + tp_wma_handle wma; + struct policy_mgr_hw_mode_params hw_mode; + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return; + + if (!wma->interfaces) { + wma_err("Interface is NULL"); + return; + } + + status = policy_mgr_get_hw_mode_from_idx(wma->psoc, cfgd_hw_mode_index, + &hw_mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + wma_err("cfgd_hw_mode_index %d not found", + cfgd_hw_mode_index); + return; + } + wma->interfaces[vdev_id].mac_id = mac_id; + if (mac_id == 0) + wma->interfaces[vdev_id].tx_streams = + hw_mode.mac0_tx_ss; + else + wma->interfaces[vdev_id].tx_streams = + hw_mode.mac1_tx_ss; +} + +/** + * wma_get_vht_ch_width - return vht channel width + * + * Return: return vht channel width + */ +uint32_t wma_get_vht_ch_width(void) +{ + uint32_t fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80MHZ; + tp_wma_handle wm_hdl = cds_get_context(QDF_MODULE_ID_WMA); + struct target_psoc_info *tgt_hdl; + int vht_cap_info; + + if (!wm_hdl) + return fw_ch_wd; + + tgt_hdl = wlan_psoc_get_tgt_if_handle(wm_hdl->psoc); + if (!tgt_hdl) + return fw_ch_wd; + + vht_cap_info = target_if_get_vht_cap_info(tgt_hdl); + if (vht_cap_info & WMI_VHT_CAP_CH_WIDTH_80P80_160MHZ) + fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_80_PLUS_80MHZ; + else if (vht_cap_info & WMI_VHT_CAP_CH_WIDTH_160MHZ) + fw_ch_wd = WNI_CFG_VHT_CHANNEL_WIDTH_160MHZ; + + return fw_ch_wd; +} + +/** + * wma_get_num_of_setbits_from_bitmask() - to get num of setbits from bitmask + * @mask: given bitmask + * + * This helper function should return number of setbits from bitmask + * + * Return: number of setbits from bitmask + */ +uint32_t wma_get_num_of_setbits_from_bitmask(uint32_t mask) +{ + uint32_t num_of_setbits = 0; + + while (mask) { + mask &= (mask - 1); + num_of_setbits++; + } + return num_of_setbits; +} + +/** + * wma_is_csa_offload_enabled - checks fw CSA offload capability + * + * Return: true or false + */ + +bool wma_is_csa_offload_enabled(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return false; + + return wmi_service_enabled(wma->wmi_handle, + wmi_service_csa_offload); +} + +bool wma_is_mbssid_enabled(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return false; + + return wmi_service_enabled(wma->wmi_handle, + wmi_service_infra_mbssid); +} + +#ifdef FEATURE_FW_LOG_PARSING +/** + * wma_config_debug_module_cmd - set debug log config + * @wmi_handle: wmi layer handle + * @param: debug log parameter + * @val: debug log value + * @module_id_bitmap: debug module id bitmap + * @bitmap_len: debug module bitmap length + * + * Return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS +wma_config_debug_module_cmd(wmi_unified_t wmi_handle, A_UINT32 param, + A_UINT32 val, A_UINT32 *module_id_bitmap, + A_UINT32 bitmap_len) +{ + struct dbglog_params dbg_param; + + dbg_param.param = param; + dbg_param.val = val; + dbg_param.module_id_bitmap = module_id_bitmap; + dbg_param.bitmap_len = bitmap_len; + + return wmi_unified_dbglog_cmd_send(wmi_handle, &dbg_param); +} +#endif +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * wma_is_p2p_lo_capable() - if driver is capable of p2p listen offload + * + * This function checks if driver is capable of p2p listen offload + * true: capable of p2p offload + * false: not capable + * + * Return: true - capable, false - not capable + */ +bool wma_is_p2p_lo_capable(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + return wmi_service_enabled + (wma->wmi_handle, + wmi_service_p2p_listen_offload_support); + } + + return 0; +} +#endif + +#ifdef WLAN_FEATURE_ROAM_OFFLOAD +QDF_STATUS wma_get_roam_scan_ch(wmi_unified_t wmi_handle, + uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct roam_scan_ch_resp *roam_ch; + struct scheduler_msg sme_msg = {0}; + + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("vdev_id: %d is not active", vdev_id); + return QDF_STATUS_E_INVAL; + } + + status = wmi_unified_get_roam_scan_ch_list(wmi_handle, vdev_id); + if (QDF_IS_STATUS_SUCCESS(status)) + return status; + roam_ch = qdf_mem_malloc(sizeof(struct roam_scan_ch_resp)); + if (!roam_ch) + return QDF_STATUS_E_INVAL; + + roam_ch->command_resp = 1; + roam_ch->num_channels = 0; + roam_ch->chan_list = NULL; + roam_ch->vdev_id = vdev_id; + sme_msg.type = eWNI_SME_GET_ROAM_SCAN_CH_LIST_EVENT; + sme_msg.bodyptr = roam_ch; + + if (scheduler_post_message(QDF_MODULE_ID_WMA, + QDF_MODULE_ID_SME, + QDF_MODULE_ID_SME, &sme_msg)) { + wma_err("Failed to post msg to SME"); + qdf_mem_free(roam_ch); + return QDF_STATUS_E_INVAL; + } + + return status; +} +#endif + +bool wma_capability_enhanced_mcast_filter(void) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (wma) { + return wmi_service_enabled(wma->wmi_handle, + wmi_service_enhanced_mcast_filter); + } + + return 0; +} + + +bool wma_is_vdev_up(uint8_t vdev_id) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return false; + + return wlan_is_vdev_id_up(wma->pdev, vdev_id); +} + +void wma_acquire_wakelock(qdf_wake_lock_t *wl, uint32_t msec) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + cds_host_diag_log_work(wl, msec, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_wake_lock_timeout_acquire(wl, msec); + qdf_runtime_pm_prevent_suspend(&wma->wmi_cmd_rsp_runtime_lock); +} + +void wma_release_wakelock(qdf_wake_lock_t *wl) +{ + t_wma_handle *wma = cds_get_context(QDF_MODULE_ID_WMA); + + qdf_wake_lock_release(wl, WIFI_POWER_EVENT_WAKELOCK_WMI_CMD_RSP); + qdf_runtime_pm_allow_suspend(&wma->wmi_cmd_rsp_runtime_lock); +} + +QDF_STATUS wma_send_vdev_stop_to_fw(t_wma_handle *wma, uint8_t vdev_id) +{ + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + struct vdev_mlme_obj *vdev_mlme = NULL; + + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("Invalid vdev id:%d", vdev_id); + return status; + } + + wlan_mlme_reset_sta_keepalive_period(wma->psoc, iface->vdev); + iface->bss_max_idle_period = 0; + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(iface->vdev); + if (!vdev_mlme) { + wma_err("Failed to get vdev mlme obj for vdev id %d", vdev_id); + return status; + } + /* + * Reset the dynamic nss chains config to the ini values, as when the + * vdev gets its started again, this would be a fresh connection, + * and we dont want the config of previous connection to affect the + * current connection. + */ + qdf_mem_copy(mlme_get_dynamic_vdev_config(iface->vdev), + mlme_get_ini_vdev_config(iface->vdev), + sizeof(struct wlan_mlme_nss_chains)); + + status = vdev_mgr_stop_send(vdev_mlme); + + /* + * If vdev_stop send to fw during channel switch, it means channel + * switch failure. Clean flag chan_switch_in_progress. + */ + mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false); + + return status; +} + +QDF_STATUS wma_get_rcpi_req(WMA_HANDLE handle, + struct sme_rcpi_req *rcpi_request) +{ + tp_wma_handle wma_handle = (tp_wma_handle) handle; + struct rcpi_req cmd = {0}; + struct wma_txrx_node *iface; + struct sme_rcpi_req *node_rcpi_req; + + wma_debug("Enter"); + iface = &wma_handle->interfaces[rcpi_request->session_id]; + /* command is in progress */ + if (iface->rcpi_req) { + wma_err("previous rcpi request is pending"); + return QDF_STATUS_SUCCESS; + } + + node_rcpi_req = qdf_mem_malloc(sizeof(*node_rcpi_req)); + if (!node_rcpi_req) + return QDF_STATUS_E_NOMEM; + + *node_rcpi_req = *rcpi_request; + iface->rcpi_req = node_rcpi_req; + + cmd.vdev_id = rcpi_request->session_id; + qdf_mem_copy(cmd.mac_addr, &rcpi_request->mac_addr, QDF_MAC_ADDR_SIZE); + cmd.measurement_type = rcpi_request->measurement_type; + + if (wmi_unified_send_request_get_rcpi_cmd(wma_handle->wmi_handle, + &cmd)) { + wma_err("Failed to send WMI_REQUEST_RCPI_CMDID"); + iface->rcpi_req = NULL; + qdf_mem_free(node_rcpi_req); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Exit"); + + return QDF_STATUS_SUCCESS; +} + +int wma_rcpi_event_handler(void *handle, uint8_t *cmd_param_info, + uint32_t len) +{ + struct rcpi_res res = {0}; + struct sme_rcpi_req *rcpi_req; + struct qdf_mac_addr qdf_mac; + struct wma_txrx_node *iface; + QDF_STATUS status = QDF_STATUS_SUCCESS; + tp_wma_handle wma_handle = (tp_wma_handle)handle; + + status = wmi_extract_rcpi_response_event(wma_handle->wmi_handle, + cmd_param_info, &res); + if (status == QDF_STATUS_E_INVAL) + return -EINVAL; + + if (res.vdev_id >= wma_handle->max_bssid) { + wma_err("received invalid vdev_id %d", res.vdev_id); + return -EINVAL; + } + + iface = &wma_handle->interfaces[res.vdev_id]; + if (!iface->rcpi_req) { + wmi_err("rcpi_req buffer not available"); + return 0; + } + + rcpi_req = iface->rcpi_req; + if (!rcpi_req->rcpi_callback) { + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + return 0; + } + + if ((res.measurement_type == RCPI_MEASUREMENT_TYPE_INVALID) || + (res.vdev_id != rcpi_req->session_id) || + (res.measurement_type != rcpi_req->measurement_type) || + (qdf_mem_cmp(res.mac_addr, &rcpi_req->mac_addr, + QDF_MAC_ADDR_SIZE))) { + wmi_err("Invalid rcpi_response"); + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + return 0; + } + + qdf_mem_copy(&qdf_mac, res.mac_addr, QDF_MAC_ADDR_SIZE); + (rcpi_req->rcpi_callback)(rcpi_req->rcpi_context, qdf_mac, + res.rcpi_value, status); + iface->rcpi_req = NULL; + qdf_mem_free(rcpi_req); + + return 0; +} + +QDF_STATUS wma_send_vdev_down_to_fw(t_wma_handle *wma, uint8_t vdev_id) +{ + struct wma_txrx_node *iface = &wma->interfaces[vdev_id]; + struct vdev_mlme_obj *vdev_mlme; + struct wlan_objmgr_vdev *vdev = iface->vdev; + + if (!wma_is_vdev_valid(vdev_id)) { + wma_err("Invalid vdev id:%d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + vdev_mlme = wlan_vdev_mlme_get_cmpt_obj(vdev); + if (!vdev_mlme) { + wma_err("Failed to get vdev mlme obj for vdev id %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + return vdev_mgr_down_send(vdev_mlme); +} + +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +tSirWifiPeerType wmi_to_sir_peer_type(enum wmi_peer_type type) +{ + switch (type) { + case WMI_PEER_TYPE_DEFAULT: + return WIFI_PEER_STA; + case WMI_PEER_TYPE_BSS: + return WIFI_PEER_AP; + case WMI_PEER_TYPE_TDLS: + return WIFI_PEER_TDLS; + case WMI_PEER_TYPE_NAN_DATA: + return WIFI_PEER_NAN; + default: + wma_err("Cannot map wmi_peer_type %d to HAL peer type", type); + return WIFI_PEER_INVALID; + } +} +#endif /* WLAN_FEATURE_LINK_LAYER_STATS */ + +#ifdef FEATURE_WLAN_DYNAMIC_CVM +/** + * wma_set_vc_mode_config() - set voltage corner mode config to FW. + * @wma_handle: pointer to wma handle. + * @vc_bitmap: value needs to set to firmware. + * + * At the time of driver startup, set operating voltage corner mode + * for differenet phymode and bw configurations. + * + * Return: QDF_STATUS. + */ +QDF_STATUS wma_set_vc_mode_config(void *wma_handle, + uint32_t vc_bitmap) +{ + int32_t ret; + tp_wma_handle wma = (tp_wma_handle)wma_handle; + struct pdev_params pdevparam = {}; + + pdevparam.param_id = WMI_PDEV_UPDATE_WDCVS_ALGO; + pdevparam.param_value = vc_bitmap; + + ret = wmi_unified_pdev_param_send(wma->wmi_handle, + &pdevparam, + WMA_WILDCARD_PDEV_ID); + if (ret) { + wma_err("Fail to Set Voltage Corner config (0x%x)", + vc_bitmap); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Successfully Set Voltage Corner config (0x%x)", + vc_bitmap); + + return QDF_STATUS_SUCCESS; +} +#endif + +int wma_chip_power_save_failure_detected_handler(void *handle, + uint8_t *cmd_param_info, + uint32_t len) +{ + tp_wma_handle wma = (tp_wma_handle)handle; + WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *param_buf; + wmi_chip_power_save_failure_detected_fixed_param *event; + struct chip_pwr_save_fail_detected_params pwr_save_fail_params; + struct mac_context *mac = cds_get_context(QDF_MODULE_ID_PE); + if (wma_validate_handle(wma)) + return -EINVAL; + + if (!mac) + return -EINVAL; + + if (!mac->sme.chip_power_save_fail_cb) { + wma_err("Callback not registered"); + return -EINVAL; + } + + param_buf = + (WMI_PDEV_CHIP_POWER_SAVE_FAILURE_DETECTED_EVENTID_param_tlvs *) + cmd_param_info; + if (!param_buf) { + wma_err("Invalid pwr_save_fail_params breached event"); + return -EINVAL; + } + event = param_buf->fixed_param; + pwr_save_fail_params.failure_reason_code = + event->power_save_failure_reason_code; + pwr_save_fail_params.wake_lock_bitmap[0] = + event->protocol_wake_lock_bitmap[0]; + pwr_save_fail_params.wake_lock_bitmap[1] = + event->protocol_wake_lock_bitmap[1]; + pwr_save_fail_params.wake_lock_bitmap[2] = + event->protocol_wake_lock_bitmap[2]; + pwr_save_fail_params.wake_lock_bitmap[3] = + event->protocol_wake_lock_bitmap[3]; + mac->sme.chip_power_save_fail_cb(mac->hdd_handle, + &pwr_save_fail_params); + + wma_debug("Invoke HDD pwr_save_fail callback"); + return 0; +} + +int wma_roam_scan_stats_event_handler(void *handle, uint8_t *event, + uint32_t len) +{ + tp_wma_handle wma_handle; + wmi_unified_t wmi_handle; + struct sir_roam_scan_stats *roam_scan_stats_req = NULL; + struct wma_txrx_node *iface = NULL; + struct wmi_roam_scan_stats_res *res = NULL; + int ret = 0; + uint32_t vdev_id; + QDF_STATUS status; + + wma_handle = handle; + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + status = wmi_extract_roam_scan_stats_res_evt(wmi_handle, event, + &vdev_id, + &res); + + /* vdev_id can be invalid though status is success, hence validate */ + if (vdev_id >= wma_handle->max_bssid) { + wma_err("Received invalid vdev_id: %d", vdev_id); + ret = -EINVAL; + goto free_res; + } + + /* Get interface for valid vdev_id */ + iface = &wma_handle->interfaces[vdev_id]; + if (!iface) { + wmi_err("Interface not available for vdev_id: %d", vdev_id); + ret = -EINVAL; + goto free_res; + } + + roam_scan_stats_req = iface->roam_scan_stats_req; + iface->roam_scan_stats_req = NULL; + if (!roam_scan_stats_req) { + wmi_err("No pending request vdev_id: %d", vdev_id); + ret = -EINVAL; + goto free_res; + } + + if (!QDF_IS_STATUS_SUCCESS(status) || + !roam_scan_stats_req->cb || + roam_scan_stats_req->vdev_id != vdev_id) { + wmi_err("roam_scan_stats buffer not available"); + ret = -EINVAL; + goto free_roam_scan_stats_req; + } + + roam_scan_stats_req->cb(roam_scan_stats_req->context, res); + +free_roam_scan_stats_req: + qdf_mem_free(roam_scan_stats_req); + roam_scan_stats_req = NULL; + +free_res: + qdf_mem_free(res); + res = NULL; + + return ret; +} + +QDF_STATUS wma_get_roam_scan_stats(WMA_HANDLE handle, + struct sir_roam_scan_stats *req) +{ + tp_wma_handle wma_handle = (tp_wma_handle)handle; + struct wmi_roam_scan_stats_req cmd = {0}; + struct wma_txrx_node *iface; + struct sir_roam_scan_stats *node_req = NULL; + + wma_debug("Enter"); + iface = &wma_handle->interfaces[req->vdev_id]; + /* command is in progress */ + if (iface->roam_scan_stats_req) { + wma_err("previous roam scan stats req is pending"); + return QDF_STATUS_SUCCESS; + } + + node_req = qdf_mem_malloc(sizeof(*node_req)); + if (!node_req) + return QDF_STATUS_E_NOMEM; + + *node_req = *req; + iface->roam_scan_stats_req = node_req; + cmd.vdev_id = req->vdev_id; + + if (wmi_unified_send_roam_scan_stats_cmd(wma_handle->wmi_handle, + &cmd)) { + wma_err("Failed to send WMI_REQUEST_ROAM_SCAN_STATS_CMDID"); + iface->roam_scan_stats_req = NULL; + qdf_mem_free(node_req); + return QDF_STATUS_E_FAILURE; + } + + wma_debug("Exit"); + + return QDF_STATUS_SUCCESS; +} + +void wma_remove_bss_peer_on_failure(tp_wma_handle wma, uint8_t vdev_id) +{ + uint8_t pdev_id = WMI_PDEV_ID_SOC; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + QDF_STATUS status; + struct qdf_mac_addr bss_peer; + struct wma_txrx_node *iface; + + iface = &wma->interfaces[vdev_id]; + + status = wlan_vdev_get_bss_peer_mac(iface->vdev, &bss_peer); + if (QDF_IS_STATUS_ERROR(status)) + return; + + wma_err("connect failure for vdev %d", vdev_id); + + if (!cdp_find_peer_exist(soc, pdev_id, bss_peer.bytes)) { + wma_err("Failed to find peer "QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(bss_peer.bytes)); + return; + } + + wma_delete_peer_mlo(wma->psoc, bss_peer.bytes); + + wma_remove_peer(wma, bss_peer.bytes, vdev_id, false); +} + +QDF_STATUS wma_remove_bss_peer_before_join( + tp_wma_handle wma, uint8_t vdev_id, + void *cm_join_req) +{ + uint8_t *mac_addr; + struct wma_target_req *del_req; + QDF_STATUS qdf_status; + struct qdf_mac_addr bssid; + enum QDF_OPMODE mode; + struct wlan_objmgr_vdev *vdev; + + if (!wma || !wma->interfaces) + return QDF_STATUS_E_FAILURE; + + if (vdev_id >= WLAN_MAX_VDEVS) { + wma_err("Invalid vdev id %d", vdev_id); + return QDF_STATUS_E_INVAL; + } + vdev = wma->interfaces[vdev_id].vdev; + if (!vdev) { + wma_err("Invalid vdev, %d", vdev_id); + return QDF_STATUS_E_FAILURE; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE) { + wma_err("unexpected mode %d vdev %d", mode, vdev_id); + return QDF_STATUS_E_FAILURE; + } + + qdf_status = wlan_vdev_get_bss_peer_mac(vdev, &bssid); + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("Failed to get bssid for vdev_id: %d", vdev_id); + return qdf_status; + } + mac_addr = bssid.bytes; + + wma_delete_peer_mlo(wma->psoc, mac_addr); + + qdf_status = wma_remove_peer(wma, mac_addr, vdev_id, false); + + if (QDF_IS_STATUS_ERROR(qdf_status)) { + wma_err("wma_remove_peer failed vdev_id:%d", vdev_id); + return qdf_status; + } + + if (cds_is_driver_recovering()) + return QDF_STATUS_E_FAILURE; + + if (wmi_service_enabled(wma->wmi_handle, + wmi_service_sync_delete_cmds)) { + wma_debug("Wait for the peer delete. vdev_id %d", vdev_id); + del_req = wma_fill_hold_req(wma, vdev_id, + WMA_DELETE_STA_REQ, + WMA_DELETE_STA_CONNECT_RSP, + cm_join_req, + WMA_DELETE_STA_TIMEOUT); + if (!del_req) { + wma_err("Failed to allocate request. vdev_id %d", + vdev_id); + qdf_status = QDF_STATUS_E_NOMEM; + } else { + qdf_status = QDF_STATUS_E_PENDING; + } + } + + return qdf_status; +} + +QDF_STATUS wma_sta_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + uint8_t vdev_id; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + struct wma_txrx_node *iface; + + if (!wma) + return QDF_STATUS_E_INVAL; + + vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + iface = &wma->interfaces[vdev_id]; + vdev_mlme->proto.sta.assoc_id = iface->aid; + + status = vdev_mgr_up_send(vdev_mlme); + + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to send vdev up cmd: vdev %d", vdev_id); + status = QDF_STATUS_E_FAILURE; + } else { + wma_set_vdev_mgmt_rate(wma, vdev_id); + if (iface->beacon_filter_enabled) + wma_add_beacon_filter( + wma, + &iface->beacon_filter); + } + + return QDF_STATUS_SUCCESS; +} + +bool wma_get_hidden_ssid_restart_in_progress(struct wma_txrx_node *iface) +{ + if (!iface) + return false; + + return ap_mlme_is_hidden_ssid_restart_in_progress(iface->vdev); +} + +bool wma_get_channel_switch_in_progress(struct wma_txrx_node *iface) +{ + if (!iface) + return false; + + return mlme_is_chan_switch_in_progress(iface->vdev); +} + +static QDF_STATUS wma_vdev_send_start_resp(tp_wma_handle wma, + struct add_bss_rsp *add_bss_rsp) +{ + wma_debug("Sending add bss rsp to umac(vdev %d status %d)", + add_bss_rsp->vdev_id, add_bss_rsp->status); + lim_handle_add_bss_rsp(wma->mac_context, add_bss_rsp); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_sta_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + enum vdev_assoc_type assoc_type; + + if (!wma) + return QDF_STATUS_E_FAILURE; + + if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) { + mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false); + lim_process_switch_channel_rsp(wma->mac_context, data); + return QDF_STATUS_SUCCESS; + } + + assoc_type = mlme_get_assoc_type(vdev_mlme->vdev); + switch (assoc_type) { + case VDEV_ASSOC: + case VDEV_REASSOC: + lim_process_switch_channel_rsp(wma->mac_context, data); + break; + case VDEV_FT_REASSOC: + lim_handle_add_bss_rsp(wma->mac_context, data); + break; + default: + wma_err("assoc_type %d is invalid", assoc_type); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wma_ap_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tp_wma_handle wma; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_vdev *vdev = vdev_mlme->vdev; + uint8_t vdev_id; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_INVAL; + + if (mlme_is_chan_switch_in_progress(vdev)) { + mlme_set_chan_switch_in_progress(vdev, false); + lim_process_switch_channel_rsp(wma->mac_context, data); + } else if (ap_mlme_is_hidden_ssid_restart_in_progress(vdev)) { + vdev_id = vdev->vdev_objmgr.vdev_id; + lim_process_mlm_update_hidden_ssid_rsp(wma->mac_context, + vdev_id); + ap_mlme_set_hidden_ssid_restart_in_progress(vdev, false); + } else { + status = wma_vdev_send_start_resp(wma, data); + } + + return status; +} + +QDF_STATUS wma_mlme_vdev_stop_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + return __wma_handle_vdev_stop_rsp( + (struct vdev_stop_response *)data); +} + +QDF_STATUS wma_ap_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_INVAL; + + return wma_send_vdev_down(wma, data); +} + +QDF_STATUS +wma_mlme_vdev_notify_down_complete(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tp_wma_handle wma; + QDF_STATUS status; + uint32_t vdev_stop_type; + struct del_bss_resp *resp = (struct del_bss_resp *)data; + + if (mlme_is_connection_fail(vdev_mlme->vdev) || + mlme_get_vdev_start_failed(vdev_mlme->vdev)) { + wma_debug("Vdev start req failed, no action required"); + mlme_set_connection_fail(vdev_mlme->vdev, false); + mlme_set_vdev_start_failed(vdev_mlme->vdev, false); + return QDF_STATUS_SUCCESS; + } + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) { + status = QDF_STATUS_E_INVAL; + goto end; + } + + status = mlme_get_vdev_stop_type(wma->interfaces[resp->vdev_id].vdev, + &vdev_stop_type); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err("Failed to get vdev stop type for vdev_id: %d", + resp->vdev_id); + status = QDF_STATUS_E_INVAL; + goto end; + } + + /* + * Need reset vdev_stop_type to 0 here, otherwise the vdev_stop_type + * would be taken to next BSS stop in some stress test, then cause + * unexpected behavior. + */ + mlme_set_vdev_stop_type(wma->interfaces[resp->vdev_id].vdev, 0); + + if (vdev_stop_type == WMA_DELETE_BSS_HO_FAIL_REQ) { + resp->status = QDF_STATUS_SUCCESS; + wma_send_msg_high_priority(wma, WMA_DELETE_BSS_HO_FAIL_RSP, + (void *)resp, 0); + return QDF_STATUS_SUCCESS; + } + + if (vdev_stop_type == WMA_SET_LINK_STATE) { + lim_join_result_callback(wma->mac_context, + wlan_vdev_get_id(vdev_mlme->vdev)); + } else { + wma_send_del_bss_response(wma, resp); + return QDF_STATUS_SUCCESS; + } + +end: + qdf_mem_free(resp); + + return status; +} + +QDF_STATUS wma_ap_mlme_vdev_stop_start_send(struct vdev_mlme_obj *vdev_mlme, + enum vdev_cmd_type type, + uint16_t data_len, void *data) +{ + tp_wma_handle wma; + struct add_bss_rsp *add_bss_rsp = data; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (!wma) + return QDF_STATUS_E_INVAL; + + if (wma_send_vdev_stop_to_fw(wma, add_bss_rsp->vdev_id)) + wma_err("Failed to send vdev stop for vdev id %d", + add_bss_rsp->vdev_id); + + wma_remove_bss_peer_on_failure(wma, add_bss_rsp->vdev_id); + + return wma_vdev_send_start_resp(wma, add_bss_rsp); +} + +#ifdef QCA_SUPPORT_CP_STATS +QDF_STATUS wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + struct request_info info = {0}; + uint8_t interval = 1; + QDF_STATUS status; + int pdev; + + if (!wma) + return QDF_STATUS_E_INVAL; + + if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) + mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false); + + pdev = target_if_mc_cp_get_mac_id(vdev_mlme); + + /* Cancel periodic pdev stats update if running for other mac */ + status = wma_cli_set_command(vdev_mlme->vdev->vdev_objmgr.vdev_id, + wmi_pdev_param_pdev_stats_update_period, + 0, PDEV_CMD); + if (status != QDF_STATUS_SUCCESS) + pe_err("failed to clear fw stats request = %d", status); + + /* send periodic fw stats to get chan noise floor for monitor mode */ + info.vdev_id = vdev_mlme->vdev->vdev_objmgr.vdev_id; + info.pdev_id = pdev; + status = tgt_send_mc_cp_stats_req((wlan_vdev_get_psoc(vdev_mlme->vdev)), + TYPE_STATION_STATS, + &info); + if (status != QDF_STATUS_SUCCESS) + pe_err("failed to send fw stats request = %d", status); + + status = wma_cli_set2_command(vdev_mlme->vdev->vdev_objmgr.vdev_id, + wmi_pdev_param_pdev_stats_update_period, + interval * 2000, pdev, PDEV_CMD); + if (status != QDF_STATUS_SUCCESS) + pe_err("failed to send fw stats request = %d", status); + + lim_process_switch_channel_rsp(wma->mac_context, data); + + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS wma_mon_mlme_vdev_start_continue(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma) + return QDF_STATUS_E_INVAL; + + if (mlme_is_chan_switch_in_progress(vdev_mlme->vdev)) + mlme_set_chan_switch_in_progress(vdev_mlme->vdev, false); + + lim_process_switch_channel_rsp(wma->mac_context, data); + + return QDF_STATUS_SUCCESS; +} +#endif /* QCA_SUPPORT_CP_STATS */ + +QDF_STATUS wma_mon_mlme_vdev_up_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + uint8_t vdev_id; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + struct wma_txrx_node *iface; + + if (!wma) + return QDF_STATUS_E_INVAL; + + vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + iface = &wma->interfaces[vdev_id]; + vdev_mlme->proto.sta.assoc_id = 0; + + status = vdev_mgr_up_send(vdev_mlme); + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send vdev up cmd: vdev %d", vdev_id); + + return status; +} + +QDF_STATUS wma_mon_mlme_vdev_stop_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + uint8_t vdev_id; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + + if (!wma) + return QDF_STATUS_E_INVAL; + + vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + + status = wma_send_vdev_stop_to_fw(wma, vdev_id); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send vdev stop cmd: vdev %d", vdev_id); + + wlan_vdev_mlme_sm_deliver_evt(vdev_mlme->vdev, + WLAN_VDEV_SM_EV_MLME_DOWN_REQ, + 0, + NULL); + + return status; +} + +QDF_STATUS wma_mon_mlme_vdev_down_send(struct vdev_mlme_obj *vdev_mlme, + uint16_t data_len, void *data) +{ + uint8_t vdev_id; + tp_wma_handle wma = cds_get_context(QDF_MODULE_ID_WMA); + QDF_STATUS status; + + if (!wma) + return QDF_STATUS_E_INVAL; + + vdev_id = wlan_vdev_get_id(vdev_mlme->vdev); + + status = wma_send_vdev_down_to_fw(wma, vdev_id); + + if (QDF_IS_STATUS_ERROR(status)) + wma_err("Failed to send vdev down cmd: vdev %d", vdev_id); + + wlan_vdev_mlme_sm_deliver_evt(vdev_mlme->vdev, + WLAN_VDEV_SM_EV_DOWN_COMPLETE, + 0, + NULL); + + return status; +} + +#ifdef FEATURE_WLM_STATS +int wma_wlm_stats_req(int vdev_id, uint32_t bitmask, uint32_t max_size, + wma_wlm_stats_cb cb, void *cookie) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + wmi_unified_t wmi_handle; + wmi_buf_t wmi_buf; + uint32_t buf_len, tlv_tag, tlv_len; + wmi_request_wlm_stats_cmd_fixed_param *cmd; + QDF_STATUS status; + + if (!wma_handle) + return -EINVAL; + + wmi_handle = wma_handle->wmi_handle; + if (wmi_validate_handle(wmi_handle)) + return -EINVAL; + + if (!wmi_service_enabled(wmi_handle, wmi_service_wlm_stats_support)) { + wma_err("Feature not supported by firmware"); + return -ENOTSUPP; + } + + wma_handle->wlm_data.wlm_stats_cookie = cookie; + wma_handle->wlm_data.wlm_stats_callback = cb; + wma_handle->wlm_data.wlm_stats_max_size = max_size; + + buf_len = sizeof(*cmd); + wmi_buf = wmi_buf_alloc(wma_handle->wmi_handle, buf_len); + if (!wmi_buf) + return -EINVAL; + + cmd = (void *)wmi_buf_data(wmi_buf); + + tlv_tag = WMITLV_TAG_STRUC_wmi_request_wlm_stats_cmd_fixed_param; + tlv_len = + WMITLV_GET_STRUCT_TLVLEN(wmi_request_wlm_stats_cmd_fixed_param); + WMITLV_SET_HDR(&cmd->tlv_header, tlv_tag, tlv_len); + + cmd->vdev_id = vdev_id; + cmd->request_bitmask = bitmask; + status = wmi_unified_cmd_send(wma_handle->wmi_handle, wmi_buf, buf_len, + WMI_REQUEST_WLM_STATS_CMDID); + if (QDF_IS_STATUS_ERROR(status)) { + wmi_buf_free(wmi_buf); + return -EINVAL; + } + /* info logging per test team request */ + wma_info("---->sent request for vdev:%d", vdev_id); + + return 0; +} + +int wma_wlm_stats_rsp(void *wma_ctx, uint8_t *event, uint32_t evt_len) +{ + WMI_WLM_STATS_EVENTID_param_tlvs *param_tlvs; + wmi_wlm_stats_event_fixed_param *param; + tp_wma_handle wma_handle = wma_ctx; + char *data; + void *cookie; + uint32_t *raw_data; + uint32_t len, buffer_size, raw_data_num, i; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + if (!wma_handle->wlm_data.wlm_stats_callback) { + wma_err("No callback registered"); + return -EINVAL; + } + + param_tlvs = (WMI_WLM_STATS_EVENTID_param_tlvs *)event; + param = param_tlvs->fixed_param; + if (!param) { + wma_err("Fix size param is not present, something is wrong"); + return -EINVAL; + } + + /* info logging per test team request */ + wma_info("---->Received response for vdev:%d", param->vdev_id); + + raw_data = param_tlvs->data; + raw_data_num = param_tlvs->num_data; + + len = 0; + buffer_size = wma_handle->wlm_data.wlm_stats_max_size; + data = qdf_mem_malloc(buffer_size); + if (!data) + return -ENOMEM; + + len += qdf_scnprintf(data + len, buffer_size - len, "\n%x ", + param->request_bitmask); + len += qdf_scnprintf(data + len, buffer_size - len, "%x ", + param->vdev_id); + len += qdf_scnprintf(data + len, buffer_size - len, "%x ", + param->timestamp); + len += qdf_scnprintf(data + len, buffer_size - len, "%x ", + param->req_interval); + if (!raw_data) + goto send_data; + + len += qdf_scnprintf(data + len, buffer_size - len, "\ndata:\n"); + + for (i = 0; i < raw_data_num; i++) + len += qdf_scnprintf(data + len, buffer_size - len, "%x ", + *raw_data++); + +send_data: + cookie = wma_handle->wlm_data.wlm_stats_cookie; + wma_handle->wlm_data.wlm_stats_callback(cookie, data); + + qdf_mem_free(data); + + return 0; +} +#endif /* FEATURE_WLM_STATS */ + +#ifdef FEATURE_WLAN_DIAG_SUPPORT +static QDF_STATUS wma_send_cold_boot_cal_data(uint8_t *data, + wmi_cold_boot_cal_data_fixed_param *event) +{ + struct host_log_cold_boot_cal_data_type *log_ptr = NULL; + + WLAN_HOST_DIAG_LOG_ALLOC(log_ptr, + struct host_log_cold_boot_cal_data_type, + LOG_WLAN_COLD_BOOT_CAL_DATA_C); + + if (!log_ptr) + return QDF_STATUS_E_NOMEM; + + log_ptr->version = VERSION_LOG_WLAN_COLD_BOOT_CAL_DATA_C; + log_ptr->cb_cal_data_len = event->data_len; + log_ptr->flags = event->flags; + qdf_mem_copy(log_ptr->cb_cal_data, data, log_ptr->cb_cal_data_len); + + WLAN_HOST_DIAG_LOG_REPORT(log_ptr); + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS wma_send_cold_boot_cal_data(uint8_t *data, + wmi_cold_boot_cal_data_fixed_param *event) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +int wma_cold_boot_cal_event_handler(void *wma_ctx, uint8_t *event_buff, + uint32_t len) +{ + WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *param_buf; + wmi_cold_boot_cal_data_fixed_param *event; + QDF_STATUS status; + tp_wma_handle wma_handle = (tp_wma_handle)wma_ctx; + + if (wma_validate_handle(wma_handle)) + return -EINVAL; + + param_buf = + (WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID_param_tlvs *)event_buff; + if (!param_buf) { + wma_err("Invalid Cold Boot Cal Event"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if ((event->data_len > param_buf->num_data) || + (param_buf->num_data > HOST_LOG_MAX_COLD_BOOT_CAL_DATA_SIZE)) { + wma_err("Excess data_len:%d, num_data:%d", event->data_len, + param_buf->num_data); + return -EINVAL; + } + + status = wma_send_cold_boot_cal_data((uint8_t *)param_buf->data, event); + if (status != QDF_STATUS_SUCCESS) { + wma_err("Cold Boot Cal Diag log not sent"); + return -ENOMEM; + } + + return 0; +} + +#ifdef MULTI_CLIENT_LL_SUPPORT +int wma_latency_level_event_handler(void *wma_ctx, uint8_t *event_buff, + uint32_t len) +{ + WMI_VDEV_LATENCY_LEVEL_EVENTID_param_tlvs *param_buf; + struct mac_context *pmac = + (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + wmi_vdev_latency_event_fixed_param *event; + struct latency_level_data event_data; + bool multi_client_ll_support, multi_client_ll_caps; + + if (!pmac) { + wma_err("NULL mac handle"); + return -EINVAL; + } + + multi_client_ll_support = + pmac->mlme_cfg->wlm_config.multi_client_ll_support; + multi_client_ll_caps = + wlan_mlme_get_wlm_multi_client_ll_caps(pmac->psoc); + + wma_debug("multi client ll INI:%d, caps:%d", multi_client_ll_support, + multi_client_ll_caps); + + if ((!multi_client_ll_support) || (!multi_client_ll_caps)) + return -EINVAL; + + if (!pmac->sme.latency_level_event_handler_cb) { + wma_err("latency level data handler cb is not registered"); + return -EINVAL; + } + + param_buf = (WMI_VDEV_LATENCY_LEVEL_EVENTID_param_tlvs *)event_buff; + if (!param_buf) { + wma_err("Invalid latency level data Event"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + wma_err("Invalid fixed param in latency data Event"); + return -EINVAL; + } + + event_data.vdev_id = event->vdev_id; + event_data.latency_level = event->latency_level; + wma_debug("received event latency level :%d, vdev_id:%d", + event->latency_level, event->vdev_id); + pmac->sme.latency_level_event_handler_cb(&event_data, + event->vdev_id); + + return 0; +} +#endif + +#ifdef FEATURE_OEM_DATA +int wma_oem_event_handler(void *wma_ctx, uint8_t *event_buff, uint32_t len) +{ + WMI_OEM_DATA_EVENTID_param_tlvs *param_buf; + struct mac_context *pmac = + (struct mac_context *)cds_get_context(QDF_MODULE_ID_PE); + wmi_oem_data_event_fixed_param *event; + struct oem_data oem_event_data; + + if (!pmac) { + wma_err("NULL mac handle"); + return -EINVAL; + } + + param_buf = + (WMI_OEM_DATA_EVENTID_param_tlvs *)event_buff; + if (!param_buf) { + wma_err("Invalid oem data Event"); + return -EINVAL; + } + + event = param_buf->fixed_param; + if (!event) { + wma_err("Invalid fixed param in oem data Event"); + return -EINVAL; + } + + if (event->data_len > param_buf->num_data) { + wma_err("Invalid data len %d num_data %d", event->data_len, + param_buf->num_data); + return -EINVAL; + } + + oem_event_data.data_len = event->data_len; + oem_event_data.data = param_buf->data; + + if (param_buf->num_file_name) { + oem_event_data.file_name = param_buf->file_name; + oem_event_data.file_name_len = param_buf->num_file_name; + } + + if (event->event_cause == WMI_OEM_DATA_EVT_CAUSE_UNSPECIFIED) { + if (pmac->sme.oem_data_event_handler_cb) + pmac->sme.oem_data_event_handler_cb( + &oem_event_data, + pmac->sme.oem_data_vdev_id); + else if (pmac->sme.oem_data_async_event_handler_cb) + pmac->sme.oem_data_async_event_handler_cb( + &oem_event_data); + } else if (event->event_cause == WMI_OEM_DATA_EVT_CAUSE_CMD_REQ) { + if (pmac->sme.oem_data_event_handler_cb) + pmac->sme.oem_data_event_handler_cb( + &oem_event_data, + pmac->sme.oem_data_vdev_id); + } else if (event->event_cause == WMI_OEM_DATA_EVT_CAUSE_ASYNC) { + if (pmac->sme.oem_data_async_event_handler_cb) + pmac->sme.oem_data_async_event_handler_cb( + &oem_event_data); + } else { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} +#endif + +#ifdef WLAN_FEATURE_11BE +uint32_t wma_get_orig_eht_ch_width(void) +{ + tDot11fIEeht_cap eht_cap; + tp_wma_handle wma; + QDF_STATUS status; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (qdf_unlikely(!wma)) { + wma_err_rl("wma handle is NULL"); + goto vht_ch_width; + } + + status = mlme_cfg_get_orig_eht_caps(wma->psoc, &eht_cap); + if (QDF_IS_STATUS_ERROR(status)) { + wma_err_rl("Failed to get eht caps"); + goto vht_ch_width; + } + + if (eht_cap.support_320mhz_6ghz) + return WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ; + +vht_ch_width: + return wma_get_vht_ch_width(); +} + +uint32_t wma_get_eht_ch_width(void) +{ + tDot11fIEeht_cap eht_cap; + tp_wma_handle wma; + + wma = cds_get_context(QDF_MODULE_ID_WMA); + if (qdf_unlikely(!wma)) { + wma_err_rl("wma handle is NULL"); + goto vht_ch_width; + } + + if (QDF_IS_STATUS_ERROR(mlme_cfg_get_eht_caps(wma->psoc, &eht_cap))) { + wma_err_rl("Failed to get eht caps"); + goto vht_ch_width; + } + + if (eht_cap.support_320mhz_6ghz) + return WNI_CFG_EHT_CHANNEL_WIDTH_320MHZ; + +vht_ch_width: + return wma_get_vht_ch_width(); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/coap/inc/wlan_cfg80211_coap.h b/qcom/opensource/wlan/qcacld-3.0/os_if/coap/inc/wlan_cfg80211_coap.h new file mode 100644 index 0000000000..9d9c34006d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/coap/inc/wlan_cfg80211_coap.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declares driver functions interfacing with linux kernel + */ + +#ifndef _WLAN_CFG80211_COAP_H_ +#define _WLAN_CFG80211_COAP_H_ +#include + +#ifdef WLAN_FEATURE_COAP +/** + * wlan_cfg80211_coap_offload() - configure CoAP offloading + * @wiphy: pointer to wireless wiphy structure. + * @vdev: VDEV Object pointer + * @data: pointer to netlink TLV buffer + * @data_len: the length of @data in bytes + * + * Return: An error code or 0 on success. + */ +int +wlan_cfg80211_coap_offload(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/coap/src/wlan_cfg80211_coap.c b/qcom/opensource/wlan/qcacld-3.0/os_if/coap/src/wlan_cfg80211_coap.c new file mode 100644 index 0000000000..7111b78e5e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/coap/src/wlan_cfg80211_coap.c @@ -0,0 +1,683 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define COAP_MATCH_DATA_BYTES_MAX 16 +#define COAP_MSG_BYTES_MAX 1152 +#define COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS 40000 +#define COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS 2000 + +#define COAP_ATTR(_name) QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_ ## _name + +static const struct nla_policy +coap_offload_filter_policy[COAP_ATTR(FILTER_MAX) + 1] = { + [COAP_ATTR(FILTER_DEST_IPV4)] = {.type = NLA_U32}, + [COAP_ATTR(FILTER_DEST_IPV4_IS_BC)] = {.type = NLA_FLAG}, + [COAP_ATTR(FILTER_DEST_PORT)] = {.type = NLA_U16}, + [COAP_ATTR(FILTER_MATCH_OFFSET)] = {.type = NLA_U32}, + [COAP_ATTR(FILTER_MATCH_DATA)] = { + .type = NLA_BINARY, .len = COAP_MATCH_DATA_BYTES_MAX}, +}; + +static const struct nla_policy +coap_offload_tx_ipv4_policy[COAP_ATTR(TX_IPV4_MAX) + 1] = { + [COAP_ATTR(TX_IPV4_SRC_ADDR)] = {.type = NLA_U32}, + [COAP_ATTR(TX_IPV4_SRC_PORT)] = {.type = NLA_U16}, + [COAP_ATTR(TX_IPV4_DEST_ADDR)] = {.type = NLA_U32}, + [COAP_ATTR(TX_IPV4_DEST_IS_BC)] = {.type = NLA_FLAG}, + [COAP_ATTR(TX_IPV4_DEST_PORT)] = {.type = NLA_U16}, +}; + +static const struct nla_policy +coap_offload_reply_policy[COAP_ATTR(REPLY_MAX) + 1] = { + [COAP_ATTR(REPLY_SRC_IPV4)] = {.type = NLA_U32}, + [COAP_ATTR(REPLY_FILTER)] = + VENDOR_NLA_POLICY_NESTED(coap_offload_filter_policy), + [COAP_ATTR(REPLY_MSG)] = { + .type = NLA_BINARY, .len = COAP_MSG_BYTES_MAX}, + [COAP_ATTR(REPLY_CACHE_EXPTIME)] = {.type = NLA_U32}, +}; + +static const struct nla_policy +coap_offload_periodic_tx_policy[COAP_ATTR(PERIODIC_TX_MAX) + 1] = { + [COAP_ATTR(PERIODIC_TX_IPV4)] = + VENDOR_NLA_POLICY_NESTED(coap_offload_tx_ipv4_policy), + [COAP_ATTR(PERIODIC_TX_PERIOD)] = {.type = NLA_U32}, + [COAP_ATTR(PERIODIC_TX_MSG)] = { + .type = NLA_BINARY, .len = COAP_MSG_BYTES_MAX}, +}; + +const struct nla_policy +coap_offload_policy[COAP_ATTR(MAX) + 1] = { + [COAP_ATTR(ACTION)] = {.type = NLA_U32 }, + [COAP_ATTR(REQ_ID)] = {.type = NLA_U32 }, + [COAP_ATTR(REPLY)] = + VENDOR_NLA_POLICY_NESTED(coap_offload_reply_policy), + [COAP_ATTR(PERIODIC_TX)] = + VENDOR_NLA_POLICY_NESTED(coap_offload_periodic_tx_policy), +}; + +/** + * wlan_cfg80211_coap_offload_reply_fill_filter() - fill filter for CoAP + * offload reply. + * @attr_filter: pointer to filter attribute + * @params: pointer to parameters for CoAP offload reply + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_reply_fill_filter(struct nlattr *attr_filter, + struct coap_offload_reply_param *params) +{ + struct nlattr *tb[COAP_ATTR(FILTER_MAX) + 1]; + + if (!attr_filter) { + coap_err("No ATTR filter"); + return -EINVAL; + } + + if (!nla_data(attr_filter)) { + coap_err("Invalid filter"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(FILTER_MAX), + attr_filter, + coap_offload_filter_policy)) { + coap_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[COAP_ATTR(FILTER_DEST_IPV4)]) { + coap_err("no ATTR dest IPv4"); + return -EINVAL; + } + + params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(FILTER_DEST_IPV4)]); + params->dest_ip_v4_is_bc = + nla_get_flag(tb[COAP_ATTR(FILTER_DEST_IPV4_IS_BC)]); + + if (!tb[COAP_ATTR(FILTER_DEST_PORT)]) { + coap_err("no ATTR dest IPv4 port"); + return -EINVAL; + } + + params->dest_udp_port = nla_get_u16(tb[COAP_ATTR(FILTER_DEST_PORT)]); + + if (!tb[COAP_ATTR(FILTER_MATCH_OFFSET)]) { + coap_err("no ATTR match offset"); + return -EINVAL; + } + + params->verify_offset = + nla_get_u32(tb[COAP_ATTR(FILTER_MATCH_OFFSET)]); + + if (!tb[COAP_ATTR(FILTER_MATCH_DATA)]) { + coap_err("no ATTR match data"); + return -EINVAL; + } + + params->verify_len = nla_len(tb[COAP_ATTR(FILTER_MATCH_DATA)]); + if (!params->verify_len) { + coap_err("invalid match data len"); + return -EINVAL; + } + + params->verify = nla_data(tb[COAP_ATTR(FILTER_MATCH_DATA)]); + return 0; +} + +/** + * wlan_cfg80211_coap_offload_reply_enable() - enable CoAP offload reply + * @vdev: pointer to vdev object + * @req_id: request id + * @attr_reply: pointer to CoAP offload reply attribute + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_reply_enable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id, + struct nlattr *attr_reply) +{ + struct nlattr *tb[COAP_ATTR(REPLY_MAX) + 1]; + struct coap_offload_reply_param params = {0}; + struct nlattr *attr; + QDF_STATUS status; + int ret; + + if (!attr_reply) { + coap_err("No ATTR reply"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(REPLY_MAX), + attr_reply, + coap_offload_reply_policy)) { + coap_err("Invalid ATTR"); + return -EINVAL; + } + + attr = tb[COAP_ATTR(REPLY_SRC_IPV4)]; + if (!attr) { + coap_err("No ATTR IPv4"); + return -EINVAL; + } + + params.pattern_id = req_id; + params.vdev_id = wlan_vdev_get_id(vdev); + params.src_ip_v4 = nla_get_u32(attr); + + attr = tb[COAP_ATTR(REPLY_FILTER)]; + ret = wlan_cfg80211_coap_offload_reply_fill_filter(attr, ¶ms); + if (ret) + return ret; + + attr = tb[COAP_ATTR(REPLY_MSG)]; + if (!attr) { + coap_err("No ATTR msg"); + return -EINVAL; + } + + params.coapmsg_len = nla_len(attr); + params.coapmsg = nla_data(attr); + + attr = tb[COAP_ATTR(REPLY_CACHE_EXPTIME)]; + if (!attr) + params.cache_timeout = COAP_OFFLOAD_REPLY_CACHE_EXPTIME_MS; + else + params.cache_timeout = nla_get_u32(attr); + + status = ucfg_coap_offload_reply_enable(vdev, ¶ms); + ret = qdf_status_to_os_return(status); + return ret; +} + +/** + * wlan_cfg80211_coap_offload_fill_tx_ipv4() - fill IPv4 source/destination + * address/port for offload transmitting. + * @attr_ipv4: pointer to TX IPv4 attribute + * @params: pointer to parameters for CoAP offload reply + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_fill_tx_ipv4(struct nlattr *attr_ipv4, + struct coap_offload_periodic_tx_param *params) +{ + struct nlattr *tb[COAP_ATTR(TX_IPV4_MAX) + 1]; + + if (!attr_ipv4) { + coap_err("No ATTR TX IPv4"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(TX_IPV4_MAX), + attr_ipv4, + coap_offload_tx_ipv4_policy)) { + coap_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]) { + coap_err("no ATTR src addr"); + return -EINVAL; + } + + params->src_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_ADDR)]); + if (tb[COAP_ATTR(TX_IPV4_SRC_PORT)]) + params->src_udp_port = + nla_get_u32(tb[COAP_ATTR(TX_IPV4_SRC_PORT)]); + + if (!tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]) { + coap_err("no ATTR IPv4 dest addr"); + return -EINVAL; + } + + params->dest_ip_v4 = nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_ADDR)]); + params->dest_ip_v4_is_bc = + nla_get_flag(tb[COAP_ATTR(TX_IPV4_DEST_IS_BC)]); + + if (!tb[COAP_ATTR(TX_IPV4_DEST_PORT)]) { + coap_err("no ATTR dest IPv4 port"); + return -EINVAL; + } + + params->dest_udp_port = + nla_get_u32(tb[COAP_ATTR(TX_IPV4_DEST_PORT)]); + return 0; +} + +/** + * wlan_cfg80211_coap_offload_periodic_tx_enable() - enable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @req_id: request id + * @attr_periodic_tx: pointer to CoAP offload periodic TX attribute + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_periodic_tx_enable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id, + struct nlattr *attr_periodic_tx) +{ + struct nlattr *tb[COAP_ATTR(PERIODIC_TX_MAX) + 1]; + struct coap_offload_periodic_tx_param param = {0}; + struct nlattr *attr_ipv4; + QDF_STATUS status; + int ret; + + if (!attr_periodic_tx) { + coap_err("No ATTR periodic tx"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse_nested(tb, COAP_ATTR(PERIODIC_TX_MAX), + attr_periodic_tx, + coap_offload_periodic_tx_policy)) { + coap_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[COAP_ATTR(PERIODIC_TX_PERIOD)]) { + coap_err("no ATTR period"); + return -EINVAL; + } + + param.timeout = nla_get_u32(tb[COAP_ATTR(PERIODIC_TX_PERIOD)]); + attr_ipv4 = tb[COAP_ATTR(PERIODIC_TX_IPV4)]; + ret = wlan_cfg80211_coap_offload_fill_tx_ipv4(attr_ipv4, ¶m); + if (ret) + return ret; + + param.vdev_id = wlan_vdev_get_id(vdev); + param.pattern_id = req_id; + if (!tb[COAP_ATTR(PERIODIC_TX_MSG)]) { + coap_err("no ATTR msg"); + return -EINVAL; + } + + param.coapmsg_len = nla_len(tb[COAP_ATTR(PERIODIC_TX_MSG)]); + param.coapmsg = nla_data(tb[COAP_ATTR(PERIODIC_TX_MSG)]); + status = ucfg_coap_offload_periodic_tx_enable(vdev, ¶m); + return qdf_status_to_os_return(status); +} + +/** + * wlan_cfg80211_coap_offload_periodic_tx_disable() - disable CoAP offload + * periodic transmitting + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_periodic_tx_disable(struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + QDF_STATUS status; + + status = ucfg_coap_offload_periodic_tx_disable(vdev, req_id); + return qdf_status_to_os_return(status); +} + +/** + * wlan_cfg80211_dealloc_coap_buf_info() - Callback to free priv + * allocations for CoAP buffer info + * @priv: Pointer to priv data statucture + * + * Return: None + */ +static void wlan_cfg80211_dealloc_coap_buf_info(void *priv) +{ + struct coap_buf_info *info = priv; + struct coap_buf_node *cur, *next; + + if (!info) + return; + + qdf_list_for_each_del(&info->info_list, cur, next, node) { + qdf_list_remove_node(&info->info_list, &cur->node); + qdf_mem_free(cur->payload); + qdf_mem_free(cur); + } + + qdf_list_destroy(&info->info_list); +} + +static void +wlan_cfg80211_coap_cache_get_cbk(void *context, struct coap_buf_info *info) +{ + struct osif_request *request; + struct coap_buf_info *priv_info; + + if (!context || !info) + return; + + request = osif_request_get(context); + if (!request) + return; + + priv_info = osif_request_priv(request); + if (info->req_id == priv_info->req_id) { + qdf_list_join(&priv_info->info_list, &info->info_list); + if (!info->more_info) + osif_request_complete(request); + } + + osif_request_put(request); +} + +/** + * wlan_cfg80211_coap_fill_buf_info() - Fill cache get response buffer + * @reply_skb : pointer to reply_skb + * @info : information of cached CoAP messages + * @index : attribute type index for nla_next_start() + * + * Return : 0 on success and errno on failure + */ +static int +wlan_cfg80211_coap_fill_buf_info(struct sk_buff *reply_skb, + struct coap_buf_node *info, int index) +{ + struct nlattr *attr; + + attr = nla_nest_start(reply_skb, index); + if (!attr) { + coap_err("nla_nest_start failed"); + return -EINVAL; + } + + if (hdd_wlan_nla_put_u64(reply_skb, COAP_ATTR(CACHE_INFO_TS), + info->tsf) || + nla_put_u32(reply_skb, COAP_ATTR(CACHE_INFO_SRC_IPV4), + info->src_ip) || + nla_put(reply_skb, COAP_ATTR(CACHE_INFO_MSG), + info->len, info->payload)) { + coap_err("nla_put failed"); + return -EINVAL; + } + + nla_nest_end(reply_skb, attr); + return 0; +} + +/** + * wlan_cfg80211_coap_offload_cache_deliver() - deliver cached CoAP messages + * @wiphy: pointer to wireless wiphy structure. + * @cache_list: list of cached CoAP messages + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_cache_deliver(struct wiphy *wiphy, + qdf_list_t *cache_list) +{ + struct sk_buff *skb; + uint32_t skb_len = NLMSG_HDRLEN; + struct coap_buf_node *cur, *next; + struct nlattr *attr; + int i = 0, ret; + + /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHES */ + skb_len += nla_total_size(0); + qdf_list_for_each_del(cache_list, cur, next, node) { + if (!cur->len || !cur->payload) + continue; + + /* nest attribute */ + skb_len += nla_total_size(0); + + /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_TS */ + skb_len += nla_total_size(sizeof(uint64_t)); + + /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_SRC_IPV4 */ + skb_len += nla_total_size(sizeof(uint32_t)); + + /* QCA_WLAN_VENDOR_ATTR_COAP_OFFLOAD_CACHE_INFO_MSG */ + skb_len += nla_total_size(cur->len); + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, skb_len); + attr = nla_nest_start(skb, COAP_ATTR(CACHES)); + if (!attr) { + hdd_err("nla_nest_start failed"); + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + qdf_list_for_each_del(cache_list, cur, next, node) { + if (!cur->len || !cur->payload) + continue; + + qdf_list_remove_node(cache_list, &cur->node); + ret = wlan_cfg80211_coap_fill_buf_info(skb, cur, i++); + if (ret) { + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; + } + + qdf_mem_free(cur->payload); + qdf_mem_free(cur); + } + + nla_nest_end(skb, attr); + return wlan_cfg80211_vendor_cmd_reply(skb); +} + +/** + * wlan_cfg80211_coap_offload_cache_get() - get cached CoAP messages + * @wiphy: pointer to wireless wiphy structure. + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_cache_get(struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + void *cookie; + QDF_STATUS status; + struct osif_request *request; + struct coap_buf_info *buf_info; + int ret; + static const struct osif_request_params params = { + .priv_size = sizeof(*buf_info), + .timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS, + .dealloc = wlan_cfg80211_dealloc_coap_buf_info, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + coap_err("Request allocation failure"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + buf_info = osif_request_priv(request); + qdf_list_create(&buf_info->info_list, 0); + buf_info->req_id = req_id; + buf_info->vdev_id = wlan_vdev_get_id(vdev); + + cookie = osif_request_cookie(request); + status = ucfg_coap_offload_cache_get(vdev, req_id, + wlan_cfg80211_coap_cache_get_cbk, + cookie); + if (QDF_IS_STATUS_ERROR(status)) { + coap_err("Unable to get cache"); + goto out; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + coap_err("Target response timed out"); + status = qdf_status_from_os_return(ret); + goto out; + } + + ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy, + &buf_info->info_list); + if (ret) { + coap_err("Failed to deliver buf info"); + status = qdf_status_from_os_return(ret); + goto out; + } + +out: + if (request) + osif_request_put(request); + return qdf_status_to_os_return(status); +} + +/** + * wlan_cfg80211_coap_offload_reply_disable() - disable CoAP offload reply + * @wiphy: pointer to wireless wiphy structure. + * @vdev: pointer to vdev object + * @req_id: request id + * + * Return: 0 on success; error number otherwise + */ +static int +wlan_cfg80211_coap_offload_reply_disable(struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + uint32_t req_id) +{ + void *cookie; + QDF_STATUS status; + struct osif_request *request; + struct coap_buf_info *buf_info; + int ret; + static const struct osif_request_params params = { + .priv_size = sizeof(*buf_info), + .timeout_ms = COAP_OFFLOAD_CACHE_GET_TIMEOUT_MS, + .dealloc = wlan_cfg80211_dealloc_coap_buf_info, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + coap_err("Request allocation failure"); + status = QDF_STATUS_E_NOMEM; + goto out; + } + + buf_info = osif_request_priv(request); + qdf_list_create(&buf_info->info_list, 0); + buf_info->req_id = req_id; + buf_info->vdev_id = wlan_vdev_get_id(vdev); + + cookie = osif_request_cookie(request); + status = ucfg_coap_offload_reply_disable(vdev, req_id, + wlan_cfg80211_coap_cache_get_cbk, cookie); + if (QDF_IS_STATUS_ERROR(status)) { + coap_err("Failed to disable offload reply"); + goto out; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + coap_err("Target response timed out"); + status = qdf_status_from_os_return(ret); + goto out; + } + + ret = wlan_cfg80211_coap_offload_cache_deliver(wiphy, + &buf_info->info_list); + if (ret) { + coap_err("Failed to deliver buf info"); + status = qdf_status_from_os_return(ret); + goto out; + } + +out: + if (request) + osif_request_put(request); + return qdf_status_to_os_return(status); +} + +int +wlan_cfg80211_coap_offload(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + struct nlattr *tb[COAP_ATTR(MAX) + 1]; + struct nlattr *attr; + uint32_t action, req_id; + int ret; + + if (wlan_cfg80211_nla_parse(tb, COAP_ATTR(MAX), + data, data_len, coap_offload_policy)) { + coap_err("Invalid ATTR"); + return -EINVAL; + } + + if (!tb[COAP_ATTR(ACTION)]) { + coap_err("no attr action"); + return -EINVAL; + } + + if (!tb[COAP_ATTR(REQ_ID)]) { + coap_err("no attr req id"); + return -EINVAL; + } + + action = nla_get_u32(tb[COAP_ATTR(ACTION)]); + req_id = nla_get_u32(tb[COAP_ATTR(REQ_ID)]); + switch (action) { + case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_ENABLE: + attr = tb[COAP_ATTR(REPLY)]; + ret = wlan_cfg80211_coap_offload_reply_enable(vdev, req_id, + attr); + break; + case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_REPLY_DISABLE: + ret = wlan_cfg80211_coap_offload_reply_disable(wiphy, vdev, + req_id); + break; + case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_ENABLE: + attr = tb[COAP_ATTR(PERIODIC_TX)]; + ret = wlan_cfg80211_coap_offload_periodic_tx_enable(vdev, + req_id, + attr); + break; + case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_PERIODIC_TX_DISABLE: + ret = wlan_cfg80211_coap_offload_periodic_tx_disable(vdev, + req_id); + break; + case QCA_WLAN_VENDOR_COAP_OFFLOAD_ACTION_CACHE_GET: + ret = wlan_cfg80211_coap_offload_cache_get(wiphy, vdev, + req_id); + break; + default: + ret = -EINVAL; + break; + } + + coap_debug("vdev_id %u action %u req id %u ret %d", + wlan_vdev_get_id(vdev), action, req_id, ret); + return ret; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/coex/inc/wlan_cfg80211_coex.h b/qcom/opensource/wlan/qcacld-3.0/os_if/coex/inc/wlan_cfg80211_coex.h new file mode 100644 index 0000000000..c94ab840e1 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/coex/inc/wlan_cfg80211_coex.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declares driver functions interfacing with linux kernel + */ + +#ifndef _WLAN_CFG80211_COEX_H_ +#define _WLAN_CFG80211_COEX_H_ +#include +#include + +extern const struct nla_policy + btc_chain_mode_policy + [QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1]; + +#ifdef FEATURE_COEX +int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); +#else +static inline int +wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + return -ENOTSUPP; +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/coex/src/wlan_cfg80211_coex.c b/qcom/opensource/wlan/qcacld-3.0/os_if/coex/src/wlan_cfg80211_coex.c new file mode 100644 index 0000000000..d2180a1059 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/coex/src/wlan_cfg80211_coex.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ +#include +#include +#include +#include +#include +#include +#include + +const struct nla_policy +btc_chain_mode_policy[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1] = { + [QCA_VENDOR_ATTR_BTC_CHAIN_MODE] = {.type = NLA_U32}, + [QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART] = {.type = NLA_FLAG}, +}; + +static enum coex_btc_chain_mode +__wlan_cfg80211_coex_map_btc_chain_mode(enum qca_btc_chain_mode mode) +{ + switch (mode) { + case QCA_BTC_CHAIN_SHARED: + return WLAN_COEX_BTC_CHAIN_MODE_SHARED; + case QCA_BTC_CHAIN_SEPARATED_HYBRID: + return WLAN_COEX_BTC_CHAIN_MODE_HYBRID; + case QCA_BTC_CHAIN_SEPARATED_FDD: + return WLAN_COEX_BTC_CHAIN_MODE_FDD; + default: + return WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED; + } +} + +static int +__wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + enum coex_btc_chain_mode mode, + bool do_restart) +{ + QDF_STATUS status; + enum coex_btc_chain_mode cur_mode; + int err; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev_tmp; + int vdev_id; + struct coex_psoc_obj *coex_obj; + + if (!vdev) { + coex_err("Null vdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + coex_err("NULL psoc"); + return -EINVAL; + } + + coex_obj = wlan_psoc_get_coex_obj(psoc); + if (!coex_obj) + return -EINVAL; + + status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &cur_mode); + if (QDF_IS_STATUS_ERROR(status)) { + coex_err("failed to get cur BTC chain mode, status %d", status); + return -EFAULT; + } + + if (cur_mode == mode) + return -EALREADY; + + status = ucfg_coex_psoc_set_btc_chain_mode(psoc, mode); + if (!QDF_IS_STATUS_SUCCESS(status)) { + coex_err("unable to set BTC chain mode to %d", mode); + return -EFAULT; + } + + wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev_tmp) { + status = ucfg_coex_send_btc_chain_mode(vdev_tmp, mode); + err = qdf_status_to_os_return(status); + if (err) { + coex_err("Failed to set btc chain mode to %d for vdev %d", + mode, vdev_id); + return err; + } + coex_debug("Set btc chain mode to %d for vdev %d", + mode, vdev_id); + + if (!do_restart) + continue; + + wlan_coex_config_updated(vdev_tmp, COEX_CONFIG_BTC_CHAIN_MODE); + } + + return 0; +} + +/** + * wlan_cfg80211_coex_set_btc_chain_mode() - set btc chain mode + * @vdev: pointer to vdev structure. + * @data: pointer to btc chain mode command parameters. + * @data_len: the length in byte of btc chain mode command parameters. + * + * Return: An error code or 0 on success. + */ +int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + struct nlattr *tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1]; + uint32_t mode; + enum coex_btc_chain_mode chain_mode; + bool restart; + + if (wlan_cfg80211_nla_parse(tb, QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX, + data, data_len, btc_chain_mode_policy)) { + coex_err("Invalid btc chain mode ATTR"); + return -EINVAL; + } + + if (!tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]) { + coex_err("btc chain mode - no attr mode"); + return -EINVAL; + } + + mode = nla_get_u32(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]); + if (mode > QCA_BTC_CHAIN_SEPARATED_FDD) { + coex_err("Invalid btc chain mode %d", mode); + return -EINVAL; + } + + restart = nla_get_flag(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART]); + + /* map to internal mode definitions */ + chain_mode = __wlan_cfg80211_coex_map_btc_chain_mode(mode); + if (chain_mode == WLAN_COEX_BTC_CHAIN_MODE_UNSETTLED) { + coex_err("Invalid wlan btc chain mode %d", chain_mode); + return -EINVAL; + } + + coex_debug("vdev_id %u mode %u restart %u", + wlan_vdev_get_id(vdev), chain_mode, restart); + + return __wlan_cfg80211_coex_set_btc_chain_mode(vdev, + chain_mode, + restart); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h b/qcom/opensource/wlan/qcacld-3.0/os_if/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h new file mode 100644 index 0000000000..3801bc3810 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/cp_stats/inc/wlan_cfg80211_mc_cp_stats.h @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved. + * + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cfg80211_mc_cp_stats.h + * + * This Header file provide declaration for cfg80211 command handler API + * registered cp stats and specific with ic + */ + +#ifndef __WLAN_CFG80211_MC_CP_STATS_H__ +#define __WLAN_CFG80211_MC_CP_STATS_H__ + +#ifdef QCA_SUPPORT_CP_STATS + +/* forward declaration */ +struct wiphy; +struct wlan_objmgr_psoc; + +/** + * wlan_cfg80211_mc_cp_stats_get_wakelock_stats() - API to request wake lock + * stats. Stats are returned to user space via vendor event + * @psoc: Pointer to psoc + * @wiphy: wiphy pointer + * + * Return: 0 on success, negative value on failure + */ +int wlan_cfg80211_mc_cp_stats_get_wakelock_stats(struct wlan_objmgr_psoc *psoc, + struct wiphy *wiphy); + +/** + * wlan_cfg80211_mc_cp_stats_get_tx_power() - API to fetch tx power + * @vdev: Pointer to vdev + * @dbm: Pointer to TX power in dbm + * + * Return: 0 on success, negative value on failure + */ +int wlan_cfg80211_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, + int *dbm); +#ifdef WLAN_FEATURE_MIB_STATS +/** + * wlan_cfg80211_mc_cp_stats_get_mib_stats() - API to get mib stats + * statistics from firmware + * @vdev: Pointer to vdev + * @errno: error type in case of failure + * + * Callers of this API must call wlan_cfg80211_mc_cp_stats_free_stats_event + * API. + * Return: stats buffer on success, Null on failure + */ +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_mib_stats(struct wlan_objmgr_vdev *vdev, + int *errno); +#endif + +/** + * wlan_cfg80211_mc_cp_stats_get_station_stats() - API to get station + * statistics to firmware + * @vdev: Pointer to vdev + * @errno: error type in case of failure + * + * Call of this API must call wlan_cfg80211_mc_cp_stats_free_stats_event + * API when done with information provided by info. + * Return: stats buffer on success, Null on failure + */ +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, + int *errno); + +/** + * wlan_cfg80211_mc_cp_stats_free_stats_event() - API to release station + * statistics buffer + * @info: pointer to object populated with station stats + * + * Return: None + */ +void wlan_cfg80211_mc_cp_stats_free_stats_event(struct stats_event *info); + +/** + * wlan_cfg80211_mc_cp_stats_get_peer_rssi() - API to fetch peer rssi + * @vdev: Pointer to vdev + * @macaddress: mac address + * @errno: error type in case of failure + * + * Call of this API must call wlan_cfg80211_mc_cp_stats_free_stats_event + * API when done with information provided by rssi_info. + * Return: stats buffer on success, Null on failure + */ +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddress, int *errno); + +/** + * wlan_cfg80211_mc_cp_stats_get_peer_stats() - API to get peer + * statistics from firmware + * @vdev: Pointer to vdev + * @mac_addr: mac address + * @errno: error type in case of failure + * + * Call of this API must call wlan_cfg80211_mc_cp_stats_free_stats_event + * API when done with information provided by info. + * Return: stats buffer on success, Null on failure + */ +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_stats(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac_addr, + int *errno); +#else +static inline int wlan_cfg80211_mc_cp_stats_get_tx_power( + struct wlan_objmgr_vdev *vdev, + int *dbm) +{ + return 0; +} + +static inline int wlan_cfg80211_mc_cp_stats_get_wakelock_stats( + struct wlan_objmgr_psoc *psoc, + struct wiphy *wiphy) +{ + return 0; +} + +static inline struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *macaddress, int *errno) +{ + return NULL; +} + +static inline void wlan_cfg80211_mc_cp_stats_free_stats_event( + struct stats_event *info) +{} + +static inline struct stats_event * +wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, + int *errno) +{ + return NULL; +} + +static inline struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_stats(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac_addr, + int *errno) +{ + return NULL; +} +#endif /* QCA_SUPPORT_CP_STATS */ +#endif /* __WLAN_CFG80211_MC_CP_STATS_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c b/qcom/opensource/wlan/qcacld-3.0/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c new file mode 100644 index 0000000000..1492c4d611 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c @@ -0,0 +1,2012 @@ +/* + * Copyright (c) 2011-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cfg80211_mc_cp_stats.c + * + * This file provide definitions to cp stats supported cfg80211 cmd handlers + */ + +#include +#include +#include +#include +#include +#include "wlan_osif_request_manager.h" +#include "wlan_objmgr_peer_obj.h" +#include "wlan_mlme_twt_ucfg_api.h" +#include "cds_utils.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_stats.h" +#include "../../core/src/wlan_cp_stats_obj_mgr_handler.h" + + +/* max time in ms, caller may wait for stats request get serviced */ +#define CP_STATS_WAIT_TIME_STAT 800 + +#ifdef WLAN_FEATURE_MIB_STATS +/** + * wlan_free_mib_stats() - free allocations for mib stats + * @stats: Pointer to stats event statucture + * + * Return: None + */ +static void wlan_free_mib_stats(struct stats_event *stats) +{ + qdf_mem_free(stats->mib_stats); + stats->mib_stats = NULL; +} +#else +static void wlan_free_mib_stats(struct stats_event *stats) +{ +} +#endif + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS +#ifdef WLAN_SUPPORT_TWT +static void wlan_cfg80211_infra_cp_stats_twt_dealloc(void *priv) +{ + struct infra_cp_stats_event *stats = priv; + + qdf_mem_free(stats->twt_infra_cp_stats); + stats->twt_infra_cp_stats = NULL; +} +#else +static void wlan_cfg80211_infra_cp_stats_twt_dealloc(void *priv) +{ +} +#endif /* WLAN_SUPPORT_TWT */ + +#ifdef CONFIG_WLAN_BMISS +static void wlan_cfg80211_infra_cp_stats_bmiss_dealloc(void *priv) +{ + struct infra_cp_stats_event *stats = priv; + + qdf_mem_free(stats->bmiss_infra_cp_stats); + stats->bmiss_infra_cp_stats = NULL; +} +#else /* CONFIG_WLAN_BMISS */ +static void wlan_cfg80211_infra_cp_stats_bmiss_dealloc(void *priv) +{ +} +#endif /* CONFIG_WLAN_BMISS */ +/** + * wlan_cfg80211_mc_infra_cp_stats_dealloc() - callback to free priv + * allocations for infra cp stats + * @priv: Pointer to priv data statucture + * + * Return: None + */ +static inline +void wlan_cfg80211_mc_infra_cp_stats_dealloc(void *priv) +{ + struct infra_cp_stats_event *stats = priv; + + if (!stats) { + osif_err("infar_cp_stats is NULL"); + return; + } + wlan_cfg80211_infra_cp_stats_twt_dealloc(priv); + wlan_cfg80211_infra_cp_stats_bmiss_dealloc(priv); +} +#endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ + +/** + * wlan_cfg80211_mc_cp_stats_free_peer_stats_info_ext() - API to free peer stats + * info ext structure + * @ev: structure from where peer stats info ext needs to be freed + * + * Return: none + */ +static void wlan_cfg80211_mc_cp_stats_free_peer_stats_info_ext( + struct stats_event *ev) +{ + struct peer_stats_info_ext_event *peer_stats_info = + ev->peer_stats_info_ext; + uint16_t i; + + if (!ev->peer_stats_info_ext) { + ev->num_peer_stats_info_ext = 0; + return; + } + for (i = 0; i < ev->num_peer_stats_info_ext; i++) { + qdf_mem_free(peer_stats_info->tx_pkt_per_mcs); + peer_stats_info->tx_pkt_per_mcs = NULL; + qdf_mem_free(peer_stats_info->rx_pkt_per_mcs); + peer_stats_info->tx_pkt_per_mcs = NULL; + peer_stats_info++; + } + + qdf_mem_free(ev->peer_stats_info_ext); + ev->peer_stats_info_ext = NULL; + ev->num_peer_stats_info_ext = 0; +} + +/** + * wlan_cfg80211_mc_cp_stats_dealloc() - callback to free priv + * allocations for stats + * @priv: Pointer to priv data statucture + * + * Return: None + */ +static void wlan_cfg80211_mc_cp_stats_dealloc(void *priv) +{ + struct stats_event *stats = priv; + + if (!stats) { + osif_err("stats is NULL"); + return; + } + + qdf_mem_free(stats->pdev_stats); + qdf_mem_free(stats->pdev_extd_stats); + qdf_mem_free(stats->peer_stats); + qdf_mem_free(stats->cca_stats); + qdf_mem_free(stats->vdev_summary_stats); + qdf_mem_free(stats->vdev_chain_rssi); + qdf_mem_free(stats->peer_adv_stats); + wlan_cfg80211_mc_cp_stats_free_peer_stats_info_ext(stats); + wlan_free_mib_stats(stats); + qdf_mem_free(stats->vdev_extd_stats); +} + +#define QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE \ + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_DRIVER_FW_LOCAL_WAKE +#define QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR \ + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_PTR +#define QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ \ + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_DRIVER_FW_LOCAL_WAKE_CNT_SZ + +/** + * wlan_cfg80211_mc_cp_stats_send_wake_lock_stats() - API to send wakelock stats + * @wiphy: wiphy pointer + * @stats: stats data to be sent + * + * Return: 0 on success, error number otherwise. + */ +static int wlan_cfg80211_mc_cp_stats_send_wake_lock_stats(struct wiphy *wiphy, + struct wake_lock_stats *stats) +{ + struct sk_buff *skb; + uint32_t nl_buf_len; + uint32_t icmpv6_cnt; + uint32_t ipv6_rx_multicast_addr_cnt; + uint32_t total_rx_data_wake, rx_multicast_cnt; + + nl_buf_len = NLMSG_HDRLEN; + nl_buf_len += QCA_WLAN_VENDOR_GET_WAKE_STATS_MAX * + (NLMSG_HDRLEN + sizeof(uint32_t)); + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, nl_buf_len); + + if (!skb) { + osif_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + return -ENOMEM; + } + + osif_debug("wow_ucast_wake_up_count %d", + stats->ucast_wake_up_count); + osif_debug("wow_bcast_wake_up_count %d", + stats->bcast_wake_up_count); + osif_debug("wow_ipv4_mcast_wake_up_count %d", + stats->ipv4_mcast_wake_up_count); + osif_debug("wow_ipv6_mcast_wake_up_count %d", + stats->ipv6_mcast_wake_up_count); + osif_debug("wow_ipv6_mcast_ra_stats %d", + stats->ipv6_mcast_ra_stats); + osif_debug("wow_ipv6_mcast_ns_stats %d", + stats->ipv6_mcast_ns_stats); + osif_debug("wow_ipv6_mcast_na_stats %d", + stats->ipv6_mcast_na_stats); + osif_debug("wow_icmpv4_count %d", + stats->icmpv4_count); + osif_debug("wow_icmpv6_count %d", + stats->icmpv6_count); + osif_debug("wow_rssi_breach_wake_up_count %d", + stats->rssi_breach_wake_up_count); + osif_debug("wow_low_rssi_wake_up_count %d", + stats->low_rssi_wake_up_count); + osif_debug("wow_gscan_wake_up_count %d", + stats->gscan_wake_up_count); + osif_debug("wow_pno_complete_wake_up_count %d", + stats->pno_complete_wake_up_count); + osif_debug("wow_pno_match_wake_up_count %d", + stats->pno_match_wake_up_count); + + ipv6_rx_multicast_addr_cnt = stats->ipv6_mcast_wake_up_count; + icmpv6_cnt = stats->icmpv6_count; + rx_multicast_cnt = stats->ipv4_mcast_wake_up_count + + ipv6_rx_multicast_addr_cnt; + total_rx_data_wake = stats->ucast_wake_up_count + + stats->bcast_wake_up_count + rx_multicast_cnt; + + if (nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_CMD_EVENT_WAKE, + 0) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_PTR, + 0) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_CMD_EVENT_WAKE_CNT_SZ, + 0) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE, + 0) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR, + 0) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ, + 0) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_TOTAL_RX_DATA_WAKE, + total_rx_data_wake) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_UNICAST_CNT, + stats->ucast_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_MULTICAST_CNT, + rx_multicast_cnt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RX_BROADCAST_CNT, + stats->bcast_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP_PKT, + stats->icmpv4_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_PKT, + icmpv6_cnt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RA, + stats->ipv6_mcast_ra_stats) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NA, + stats->ipv6_mcast_na_stats) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_NS, + stats->ipv6_mcast_ns_stats) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP4_RX_MULTICAST_CNT, + stats->ipv4_mcast_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_ICMP6_RX_MULTICAST_CNT, + ipv6_rx_multicast_addr_cnt) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_RSSI_BREACH_CNT, + stats->rssi_breach_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_LOW_RSSI_CNT, + stats->low_rssi_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_GSCAN_CNT, + stats->gscan_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_COMPLETE_CNT, + stats->pno_complete_wake_up_count) || + nla_put_u32(skb, + QCA_WLAN_VENDOR_ATTR_WAKE_STATS_PNO_MATCH_CNT, + stats->pno_match_wake_up_count)) { + osif_err("nla put fail"); + goto nla_put_failure; + } + + wlan_cfg80211_vendor_cmd_reply(skb); + return 0; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(skb); + return -EINVAL; +} + +#undef QCA_WLAN_VENDOR_ATTR_TOTAL_DRIVER_FW_LOCAL_WAKE +#undef QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_PTR +#undef QCA_WLAN_VENDOR_ATTR_DRIVER_FW_LOCAL_WAKE_CNT_SZ + +int wlan_cfg80211_mc_cp_stats_get_wakelock_stats(struct wlan_objmgr_psoc *psoc, + struct wiphy *wiphy) +{ + /* refer __wlan_hdd_cfg80211_get_wakelock_stats */ + QDF_STATUS status; + struct wake_lock_stats stats = {0}; + + status = ucfg_mc_cp_stats_get_psoc_wake_lock_stats(psoc, &stats); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + return wlan_cfg80211_mc_cp_stats_send_wake_lock_stats(wiphy, &stats); +} + +struct tx_power_priv { + int dbm; +}; + +/** + * get_tx_power_cb() - "Get tx power" callback function + * @tx_power: tx_power + * @cookie: a cookie for the request context + * + * Return: None + */ +static void get_tx_power_cb(int tx_power, void *cookie) +{ + struct osif_request *request; + struct tx_power_priv *priv; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->dbm = tx_power; + osif_request_complete(request); + osif_request_put(request); +} + +int wlan_cfg80211_mc_cp_stats_get_tx_power(struct wlan_objmgr_vdev *vdev, + int *dbm) +{ + int ret = 0; + void *cookie; + QDF_STATUS status; + struct request_info info = {0}; + struct wlan_objmgr_peer *peer; + struct tx_power_priv *priv = NULL; + struct osif_request *request = NULL; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = CP_STATS_WAIT_TIME_STAT, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure, return cached value"); + goto fetch_tx_power; + } + + cookie = osif_request_cookie(request); + info.cookie = cookie; + info.u.get_tx_power_cb = get_tx_power_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID); + if (!peer) { + ret = -EINVAL; + goto peer_is_null; + } + qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + status = ucfg_mc_cp_stats_send_stats_request(vdev, + TYPE_CONNECTION_TX_POWER, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("wlan_mc_cp_stats_request_tx_power status: %d", + status); + ret = qdf_status_to_os_return(status); + } else { + ret = osif_request_wait_for_response(request); + if (ret) + osif_err("wait failed or timed out ret: %d", ret); + else + priv = osif_request_priv(request); + } + +fetch_tx_power: + if (priv) { + *dbm = priv->dbm; + } else { + status = ucfg_mc_cp_stats_get_tx_power(vdev, dbm); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("ucfg_mc_cp_stats_get_tx_power status: %d", + status); + ret = qdf_status_to_os_return(status); + } + } + +peer_is_null: + /* + * either we never sent a request, we sent a request and + * received a response or we sent a request and timed out. + * regardless we are done with the request. + */ + if (request) + osif_request_put(request); + + return ret; +} + +/** + * get_peer_rssi_cb() - get_peer_rssi_cb callback function + * @ev: peer stats buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static void get_peer_rssi_cb(struct stats_event *ev, void *cookie) +{ + struct stats_event *priv; + struct osif_request *request; + uint32_t rssi_size; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + if (!ev->peer_stats) { + osif_err("no peer stats"); + goto get_peer_rssi_cb_fail; + } + + priv = osif_request_priv(request); + rssi_size = sizeof(*ev->peer_stats) * ev->num_peer_stats; + if (rssi_size == 0) { + osif_err("Invalid rssi stats"); + goto get_peer_rssi_cb_fail; + } + + priv->peer_stats = qdf_mem_malloc(rssi_size); + if (!priv->peer_stats) + goto get_peer_rssi_cb_fail; + + priv->num_peer_stats = ev->num_peer_stats; + qdf_mem_copy(priv->peer_stats, ev->peer_stats, rssi_size); + +get_peer_rssi_cb_fail: + osif_request_complete(request); + osif_request_put(request); +} + +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_rssi(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct stats_event *priv, *out; + struct request_info info = {0}; + struct osif_request *request = NULL; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_cp_stats_dealloc, + }; + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure, return cached value"); + *errno = -ENOMEM; + qdf_mem_free(out); + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + info.cookie = cookie; + info.u.get_peer_rssi_cb = get_peer_rssi_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + qdf_mem_copy(info.peer_mac_addr, mac_addr, QDF_MAC_ADDR_SIZE); + status = ucfg_mc_cp_stats_send_stats_request(vdev, TYPE_PEER_STATS, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("stats req failed: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_peer_rssi_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_debug("wait failed or timed out ret: %d", *errno); + goto get_peer_rssi_fail; + } + + if (!priv->peer_stats || priv->num_peer_stats == 0) { + osif_err("Invalid peer stats, count %d, data %pK", + priv->num_peer_stats, priv->peer_stats); + *errno = -EINVAL; + goto get_peer_rssi_fail; + } + out->num_peer_stats = priv->num_peer_stats; + out->peer_stats = priv->peer_stats; + priv->peer_stats = NULL; + osif_request_put(request); + + return out; + +get_peer_rssi_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + + return NULL; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +static void get_big_data_stats_cb(struct big_data_stats_event *ev, void *cookie) +{ + struct big_data_stats_event *priv; + struct osif_request *request; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->tsf_out_of_sync = ev->tsf_out_of_sync; + priv->vdev_id = ev->vdev_id; + priv->ani_level = ev->ani_level; + + priv->last_data_tx_pwr = ev->last_data_tx_pwr; + priv->target_power_dsss = ev->target_power_dsss; + priv->target_power_ofdm = ev->target_power_ofdm; + priv->last_tx_data_rix = ev->last_tx_data_rix; + priv->last_tx_data_rate_kbps = ev->last_tx_data_rate_kbps; + + osif_request_complete(request); + osif_request_put(request); +} +#endif + +/** + * get_station_stats_cb() - get_station_stats_cb callback function + * @ev: station stats buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static void get_station_stats_cb(struct stats_event *ev, void *cookie) +{ + struct stats_event *priv; + struct osif_request *request; + uint32_t summary_size, rssi_size, peer_adv_size = 0, pdev_size; + uint32_t vdev_extd_size; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + if (!ev->vdev_summary_stats || !ev->vdev_chain_rssi) { + osif_debug("Invalid stats"); + goto station_stats_cb_fail; + } + + summary_size = sizeof(*ev->vdev_summary_stats) * ev->num_summary_stats; + rssi_size = sizeof(*ev->vdev_chain_rssi) * ev->num_chain_rssi_stats; + if (ev->peer_adv_stats && ev->num_peer_adv_stats) + peer_adv_size = + sizeof(*ev->peer_adv_stats) * ev->num_peer_adv_stats; + + if (summary_size == 0 || rssi_size == 0) { + osif_err("Invalid stats, summary %d rssi %d", + summary_size, rssi_size); + goto station_stats_cb_fail; + } + if (priv->vdev_summary_stats || priv->vdev_chain_rssi || + priv->peer_adv_stats) { + osif_err("invalid context cookie %pK request %pK", + cookie, request); + goto station_stats_cb_fail; + } + + priv->vdev_summary_stats = qdf_mem_malloc(summary_size); + if (!priv->vdev_summary_stats) + goto station_stats_cb_fail; + + priv->vdev_chain_rssi = qdf_mem_malloc(rssi_size); + if (!priv->vdev_chain_rssi) + goto station_stats_cb_fail; + + if (peer_adv_size) { + priv->peer_adv_stats = qdf_mem_malloc(peer_adv_size); + if (!priv->peer_adv_stats) + goto station_stats_cb_fail; + + qdf_mem_copy(priv->peer_adv_stats, ev->peer_adv_stats, + peer_adv_size); + } + + if (ev->num_pdev_stats && ev->pdev_stats) { + pdev_size = sizeof(*ev->pdev_stats) * ev->num_pdev_stats; + priv->pdev_stats = qdf_mem_malloc(pdev_size); + if (!priv->pdev_stats) + goto station_stats_cb_fail; + + qdf_mem_copy(priv->pdev_stats, ev->pdev_stats, pdev_size); + } + + if (ev->num_vdev_extd_stats && ev->vdev_extd_stats) { + vdev_extd_size = + sizeof(*ev->vdev_extd_stats) * ev->num_vdev_extd_stats; + priv->vdev_extd_stats = qdf_mem_malloc(vdev_extd_size); + if (!priv->vdev_extd_stats) + goto station_stats_cb_fail; + + qdf_mem_copy(priv->vdev_extd_stats, ev->vdev_extd_stats, + vdev_extd_size); + } + + priv->num_summary_stats = ev->num_summary_stats; + priv->num_chain_rssi_stats = ev->num_chain_rssi_stats; + priv->tx_rate = ev->tx_rate; + priv->rx_rate = ev->rx_rate; + priv->tx_rate_flags = ev->tx_rate_flags; + priv->num_peer_adv_stats = ev->num_peer_adv_stats; + qdf_mem_copy(priv->vdev_chain_rssi, ev->vdev_chain_rssi, rssi_size); + qdf_mem_copy(priv->vdev_summary_stats, ev->vdev_summary_stats, + summary_size); + priv->bcn_protect_stats = ev->bcn_protect_stats; + +station_stats_cb_fail: + osif_request_complete(request); + osif_request_put(request); +} + +#ifdef WLAN_SUPPORT_INFRA_CTRL_PATH_STATS + +#ifdef WLAN_SUPPORT_TWT +static void get_twt_infra_cp_stats(struct infra_cp_stats_event *ev, + struct infra_cp_stats_event *priv) + +{ + priv->num_twt_infra_cp_stats = ev->num_twt_infra_cp_stats; + priv->twt_infra_cp_stats->dialog_id = ev->twt_infra_cp_stats->dialog_id; + priv->twt_infra_cp_stats->status = ev->twt_infra_cp_stats->status; + priv->twt_infra_cp_stats->num_sp_cycles = + ev->twt_infra_cp_stats->num_sp_cycles; + priv->twt_infra_cp_stats->avg_sp_dur_us = + ev->twt_infra_cp_stats->avg_sp_dur_us; + priv->twt_infra_cp_stats->min_sp_dur_us = + ev->twt_infra_cp_stats->min_sp_dur_us; + priv->twt_infra_cp_stats->max_sp_dur_us = + ev->twt_infra_cp_stats->max_sp_dur_us; + priv->twt_infra_cp_stats->tx_mpdu_per_sp = + ev->twt_infra_cp_stats->tx_mpdu_per_sp; + priv->twt_infra_cp_stats->rx_mpdu_per_sp = + ev->twt_infra_cp_stats->rx_mpdu_per_sp; + priv->twt_infra_cp_stats->tx_bytes_per_sp = + ev->twt_infra_cp_stats->tx_bytes_per_sp; + priv->twt_infra_cp_stats->rx_bytes_per_sp = + ev->twt_infra_cp_stats->rx_bytes_per_sp; +} + +static void +wlan_cfg80211_mc_infra_cp_free_twt_stats(struct infra_cp_stats_event *stats) +{ + qdf_mem_free(stats->twt_infra_cp_stats); +} +#else +static void get_twt_infra_cp_stats(struct infra_cp_stats_event *ev, + struct infra_cp_stats_event *priv) +{ +} + +static void +wlan_cfg80211_mc_infra_cp_free_twt_stats(struct infra_cp_stats_event *stats) +{ +} +#endif /* WLAN_SUPPORT_TWT */ + +#ifdef CONFIG_WLAN_BMISS +static void +wlan_cfg80211_mc_infra_cp_free_bmiss_stats(struct infra_cp_stats_event *stats) +{ + if (stats->bmiss_infra_cp_stats) { + qdf_mem_free(stats->bmiss_infra_cp_stats); + stats->bmiss_infra_cp_stats = NULL; + } +} +#else /* CONFIG_WLAN_BMISS */ +static void +wlan_cfg80211_mc_infra_cp_free_bmiss_stats(struct infra_cp_stats_event *stats) +{ +} +#endif/* CONFIG_WLAN_BMISS */ +static inline void +wlan_cfg80211_mc_infra_cp_stats_free_stats_event( + struct infra_cp_stats_event *stats) +{ + if (!stats) + return; + wlan_cfg80211_mc_infra_cp_free_twt_stats(stats); + wlan_cfg80211_mc_infra_cp_free_bmiss_stats(stats); + qdf_mem_free(stats); +} + +/** + * infra_cp_stats_response_cb() - callback function to handle stats event + * @ev: stats event buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static inline +void infra_cp_stats_response_cb(struct infra_cp_stats_event *ev, + void *cookie) +{ + struct infra_cp_stats_event *priv; + struct osif_request *request; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + priv->action = ev->action; + priv->request_id = ev->request_id; + priv->status = ev->status; + get_twt_infra_cp_stats(ev, priv); + + osif_request_complete(request); + osif_request_put(request); +} + +#ifdef WLAN_SUPPORT_TWT +/*Infra limits Add comment here*/ +#define MAX_TWT_STAT_VDEV_ENTRIES 1 +#define MAX_TWT_STAT_MAC_ADDR_ENTRIES 1 +struct infra_cp_stats_event * +wlan_cfg80211_mc_twt_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + uint8_t twt_peer_mac[QDF_MAC_ADDR_SIZE], + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct infra_cp_stats_event *priv, *out; + struct twt_infra_cp_stats_event *twt_event; + struct wlan_objmgr_peer *peer; + struct osif_request *request; + struct infra_cp_stats_cmd_info info = {0}; + get_infra_cp_stats_cb resp_cb = NULL; + void *context = NULL; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_infra_cp_stats_dealloc, + }; + + osif_debug("Enter"); + status = wlan_cp_stats_infra_cp_get_context(wlan_vdev_get_psoc(vdev), + &resp_cb, &context); + if (QDF_IS_STATUS_ERROR(status)) { + *errno = -EFAULT; + return NULL; + } + if (resp_cb) { + osif_debug("another request already in progress"); + *errno = -EBUSY; + return NULL; + } + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + out->twt_infra_cp_stats = + qdf_mem_malloc(sizeof(*out->twt_infra_cp_stats)); + if (!out->twt_infra_cp_stats) { + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + *errno = -ENOMEM; + wlan_cfg80211_mc_infra_cp_stats_free_stats_event(out); + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + priv->twt_infra_cp_stats = + qdf_mem_malloc(sizeof(*priv->twt_infra_cp_stats)); + if (!priv->twt_infra_cp_stats) { + *errno = -ENOMEM; + goto free_stats_event; + } + twt_event = priv->twt_infra_cp_stats; + + info.request_cookie = cookie; + info.stats_id = TYPE_REQ_CTRL_PATH_TWT_STAT; + info.action = ACTION_REQ_CTRL_PATH_STAT_GET; + info.infra_cp_stats_resp_cb = infra_cp_stats_response_cb; + info.num_pdev_ids = 0; + info.num_vdev_ids = MAX_TWT_STAT_VDEV_ENTRIES; + info.vdev_id[0] = wlan_vdev_get_id(vdev); + info.num_mac_addr_list = MAX_TWT_STAT_MAC_ADDR_ENTRIES; + qdf_mem_copy(&info.peer_mac_addr[0], twt_peer_mac, QDF_MAC_ADDR_SIZE); + + info.dialog_id = dialog_id; + info.num_pdev_ids = 0; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID); + if (!peer) { + osif_err("peer is null"); + *errno = -EINVAL; + goto free_stats_event; + } + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + status = ucfg_infra_cp_stats_register_resp_cb(wlan_vdev_get_psoc(vdev), + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to register resp callback: %d", status); + *errno = qdf_status_to_os_return(status); + goto free_stats_event; + } + + status = ucfg_send_infra_cp_stats_request(vdev, &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send twt stats request status: %d", + status); + *errno = qdf_status_to_os_return(status); + goto get_twt_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_twt_stats_fail; + } + + out->num_twt_infra_cp_stats = priv->num_twt_infra_cp_stats; + out->request_id = priv->request_id; + out->twt_infra_cp_stats->dialog_id = twt_event->dialog_id; + out->twt_infra_cp_stats->status = twt_event->status; + out->twt_infra_cp_stats->num_sp_cycles = twt_event->num_sp_cycles; + out->twt_infra_cp_stats->avg_sp_dur_us = twt_event->avg_sp_dur_us; + out->twt_infra_cp_stats->min_sp_dur_us = twt_event->min_sp_dur_us; + out->twt_infra_cp_stats->max_sp_dur_us = twt_event->max_sp_dur_us; + out->twt_infra_cp_stats->tx_mpdu_per_sp = twt_event->tx_mpdu_per_sp; + out->twt_infra_cp_stats->rx_mpdu_per_sp = twt_event->rx_mpdu_per_sp; + out->twt_infra_cp_stats->tx_bytes_per_sp = twt_event->tx_bytes_per_sp; + out->twt_infra_cp_stats->rx_bytes_per_sp = twt_event->rx_bytes_per_sp; + qdf_mem_copy(&out->twt_infra_cp_stats->peer_macaddr, twt_peer_mac, + QDF_MAC_ADDR_SIZE); + osif_request_put(request); + + status = ucfg_infra_cp_stats_deregister_resp_cb( + wlan_vdev_get_psoc(vdev)); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to deregister resp callback: %d", status); + osif_debug("Exit"); + + return out; + +get_twt_stats_fail: + status = ucfg_infra_cp_stats_deregister_resp_cb( + wlan_vdev_get_psoc(vdev)); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to deregister resp callback: %d", status); + +free_stats_event: + osif_request_put(request); + wlan_cfg80211_mc_infra_cp_stats_free_stats_event(out); + + osif_debug("Exit"); + + return NULL; +} + +/** + * infra_cp_stats_reset_cb() - callback function to handle stats event + * due to reset action + * @ev: stats event buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static void infra_cp_stats_reset_cb(struct infra_cp_stats_event *ev, + void *cookie) +{ + struct infra_cp_stats_event *priv; + struct osif_request *request; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + osif_debug("clear stats action %d req_id %d, status %d num_cp_stats %d", + ev->action, ev->request_id, ev->status, + ev->num_twt_infra_cp_stats); + + osif_request_complete(request); + osif_request_put(request); +} + +/** + * wlan_cfg80211_mc_twt_clear_infra_cp_stats() - send clear twt statistics + * request to firmware + * @vdev: vdev id + * @dialog_id: dialog id of the twt session. + * @twt_peer_mac: peer mac address + * + * Return: 0 for success or error code for failure + */ +int +wlan_cfg80211_mc_twt_clear_infra_cp_stats( + struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + uint8_t twt_peer_mac[QDF_MAC_ADDR_SIZE]) +{ + int ret; + void *cookie; + QDF_STATUS status; + struct infra_cp_stats_event *priv; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_peer *peer; + struct osif_request *request; + struct infra_cp_stats_cmd_info info = {0}; + get_infra_cp_stats_cb resp_cb = NULL; + void *context = NULL; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_infra_cp_stats_dealloc, + }; + + osif_debug("Enter"); + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + status = wlan_cp_stats_infra_cp_get_context(psoc, &resp_cb, &context); + if (QDF_IS_STATUS_ERROR(status)) + return -EINVAL; + + if (resp_cb) { + osif_debug("another request already in progress"); + return -EINVAL; + } + request = osif_request_alloc(¶ms); + if (!request) + return -ENOMEM; + + ucfg_mlme_set_twt_command_in_progress(psoc, + (struct qdf_mac_addr *)twt_peer_mac, + dialog_id, + WLAN_TWT_CLEAR_STATISTICS); + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + priv->twt_infra_cp_stats = + qdf_mem_malloc(sizeof(*priv->twt_infra_cp_stats)); + if (!priv->twt_infra_cp_stats) { + ret = -ENOMEM; + goto clear_twt_stats_fail; + } + + info.request_cookie = cookie; + info.stats_id = TYPE_REQ_CTRL_PATH_TWT_STAT; + info.action = ACTION_REQ_CTRL_PATH_STAT_RESET; + + info.infra_cp_stats_resp_cb = infra_cp_stats_reset_cb; + info.num_pdev_ids = 0; + info.num_vdev_ids = MAX_TWT_STAT_VDEV_ENTRIES; + info.vdev_id[0] = wlan_vdev_get_id(vdev); + info.num_mac_addr_list = MAX_TWT_STAT_MAC_ADDR_ENTRIES; + qdf_mem_copy(&info.peer_mac_addr[0], twt_peer_mac, QDF_MAC_ADDR_SIZE); + + info.dialog_id = dialog_id; + info.num_pdev_ids = 0; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID); + if (!peer) { + osif_err("peer is null"); + ret = -EINVAL; + goto clear_twt_stats_fail; + } + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + status = ucfg_infra_cp_stats_register_resp_cb(psoc, &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to register resp callback: %d", status); + ret = qdf_status_to_os_return(status); + goto clear_twt_stats_fail; + } + + status = ucfg_send_infra_cp_stats_request(vdev, &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send twt stats request status: %d", + status); + ret = qdf_status_to_os_return(status); + goto deregister_cb; + } + + ret = osif_request_wait_for_response(request); + if (ret) + osif_err("wait failed or timed out ret: %d", ret); + +deregister_cb: + status = ucfg_infra_cp_stats_deregister_resp_cb( + wlan_vdev_get_psoc(vdev)); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to deregister resp callback: %d", status); + +clear_twt_stats_fail: + ucfg_mlme_set_twt_command_in_progress(psoc, + (struct qdf_mac_addr *)twt_peer_mac, + dialog_id, + WLAN_TWT_NONE); + osif_request_put(request); + osif_debug("Exit"); + + return ret; +} +#endif +#endif /* WLAN_SUPPORT_INFRA_CTRL_PATH_STATS */ + +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_station_stats(struct wlan_objmgr_vdev *vdev, + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct stats_event *priv, *out; + struct wlan_objmgr_peer *peer; + struct osif_request *request; + struct request_info info = {0}; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_cp_stats_dealloc, + }; + + osif_debug("Enter"); + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + info.cookie = cookie; + info.u.get_station_stats_cb = get_station_stats_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID); + if (!peer) { + osif_err("peer is null"); + *errno = -EINVAL; + goto get_station_stats_fail; + } + qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + status = ucfg_mc_cp_stats_send_stats_request(vdev, TYPE_STATION_STATS, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send stats request status: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_station_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_station_stats_fail; + } + + if (!priv->vdev_summary_stats || !priv->vdev_chain_rssi || + priv->num_summary_stats == 0 || priv->num_chain_rssi_stats == 0) { + osif_err("Invalid stats"); + osif_err("summary %d:%pK, rssi %d:%pK", + priv->num_summary_stats, priv->vdev_summary_stats, + priv->num_chain_rssi_stats, priv->vdev_chain_rssi); + *errno = -EINVAL; + goto get_station_stats_fail; + } + + out->tx_rate = priv->tx_rate; + out->rx_rate = priv->rx_rate; + out->tx_rate_flags = priv->tx_rate_flags; + out->num_summary_stats = priv->num_summary_stats; + out->num_chain_rssi_stats = priv->num_chain_rssi_stats; + out->vdev_summary_stats = priv->vdev_summary_stats; + priv->vdev_summary_stats = NULL; + out->vdev_chain_rssi = priv->vdev_chain_rssi; + priv->vdev_chain_rssi = NULL; + out->num_peer_adv_stats = priv->num_peer_adv_stats; + if (priv->peer_adv_stats) + out->peer_adv_stats = priv->peer_adv_stats; + priv->peer_adv_stats = NULL; + if (priv->pdev_stats) + out->pdev_stats = priv->pdev_stats; + priv->pdev_stats = NULL; + if (priv->vdev_extd_stats) + out->vdev_extd_stats = priv->vdev_extd_stats; + priv->vdev_extd_stats = NULL; + + out->bcn_protect_stats = priv->bcn_protect_stats; + osif_request_put(request); + + osif_debug("Exit"); + + return out; + +get_station_stats_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + + osif_debug("Exit"); + + return NULL; +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +struct big_data_stats_event * +wlan_cfg80211_mc_cp_get_big_data_stats(struct wlan_objmgr_vdev *vdev, + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct big_data_stats_event *priv, *out; + struct hdd_context *hdd_ctx = NULL; + struct osif_request *request; + struct request_info info = {0}; + struct request_info last_req = {0}; + bool pending = false; + + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + }; + + osif_debug("Enter"); + + hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD); + if (wlan_hdd_validate_context(hdd_ctx)) + return NULL; + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) + return NULL; + + request = osif_request_alloc(¶ms); + if (!request) { + qdf_mem_free(out); + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + info.cookie = cookie; + info.u.get_big_data_stats_cb = get_big_data_stats_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + + status = ucfg_send_big_data_stats_request(vdev, + TYPE_BIG_DATA_STATS, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send stats request status: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_station_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + ucfg_mc_cp_stats_reset_pending_req(hdd_ctx->psoc, + TYPE_BIG_DATA_STATS, + &last_req, &pending); + goto get_station_stats_fail; + } + + osif_debug("vdev_id: %d tsf_out_of_sync: %d ani_level: %d tx_pwr_last_data_frm: %d target_power_dsss: %d target_power_ofdm: %d rix_last_data_frm: %d tx_rate_last_data_frm: %d", + priv->vdev_id, + priv->tsf_out_of_sync, priv->ani_level, + priv->last_data_tx_pwr, priv->target_power_dsss, + priv->target_power_ofdm, priv->last_tx_data_rix, + priv->last_tx_data_rate_kbps); + + out->vdev_id = priv->vdev_id; + out->tsf_out_of_sync = priv->tsf_out_of_sync; + out->ani_level = priv->ani_level; + out->last_data_tx_pwr = priv->last_data_tx_pwr; + out->target_power_dsss = priv->target_power_dsss; + out->target_power_ofdm = priv->target_power_ofdm; + out->last_tx_data_rix = priv->last_tx_data_rix; + out->last_tx_data_rate_kbps = priv->last_tx_data_rate_kbps; + osif_request_put(request); + + osif_debug("Exit"); + + return out; + +get_station_stats_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_big_data_stats_event(out); + + osif_debug("Exit"); + + return NULL; +} +#endif + +#ifdef WLAN_FEATURE_MIB_STATS +/** + * get_mib_stats_cb() - get mib stats from fw callback function + * @ev: mib stats buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static void get_mib_stats_cb(struct stats_event *ev, void *cookie) +{ + struct stats_event *priv; + struct osif_request *request; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + priv->mib_stats = qdf_mem_malloc(sizeof(*ev->mib_stats)); + if (!priv->mib_stats) + goto get_mib_stats_cb_fail; + + priv->num_mib_stats = ev->num_mib_stats; + qdf_mem_copy(priv->mib_stats, ev->mib_stats, sizeof(*ev->mib_stats)); + +get_mib_stats_cb_fail: + osif_request_complete(request); + osif_request_put(request); +} + +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_mib_stats(struct wlan_objmgr_vdev *vdev, + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct stats_event *priv, *out; + struct wlan_objmgr_peer *peer; + struct osif_request *request; + struct request_info info = {0}; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_cp_stats_dealloc, + }; + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + info.cookie = cookie; + info.u.get_mib_stats_cb = get_mib_stats_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_CP_STATS_ID); + if (!peer) { + osif_err("peer is null"); + *errno = -EINVAL; + goto get_mib_stats_fail; + } + qdf_mem_copy(info.peer_mac_addr, peer->macaddr, QDF_MAC_ADDR_SIZE); + + osif_debug("vdev id %d, pdev id %d, peer " QDF_MAC_ADDR_FMT, + info.vdev_id, info.pdev_id, + QDF_MAC_ADDR_REF(info.peer_mac_addr)); + + wlan_objmgr_peer_release_ref(peer, WLAN_CP_STATS_ID); + + status = ucfg_mc_cp_stats_send_stats_request(vdev, TYPE_MIB_STATS, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send stats request status: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_mib_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_mib_stats_fail; + } + + if (!priv->mib_stats || priv->num_mib_stats == 0 ) { + osif_err("Invalid mib stats %d:%pK", + priv->num_mib_stats, priv->mib_stats); + *errno = -EINVAL; + goto get_mib_stats_fail; + } + + out->num_mib_stats = priv->num_mib_stats; + out->mib_stats = priv->mib_stats; + priv->mib_stats = NULL; + + osif_request_put(request); + + return out; + +get_mib_stats_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + + return NULL; +} +#endif + +/** + * copy_peer_stats_info_ext - Copy peer ext stats info from stats event to + * destination peer stats info + * @dst_peer_stats_info: Destination peer ext stats pointer where peer ext info + * needs to be copied. + * @ev: Stats event pointer from where peers stats info needs to be copied + * + * Return: Void + */ +static void +copy_peer_stats_info_ext(struct peer_stats_info_ext_event *dst_peer_stats_info, + struct stats_event *ev) +{ + uint32_t i, j; + struct peer_stats_info_ext_event *src_peer_stats_info = + ev->peer_stats_info_ext; + struct peer_stats_info_ext_event *peer_stats_info = dst_peer_stats_info; + + for (i = 0; i < ev->num_peer_stats_info_ext; i++) { + qdf_mem_copy(&peer_stats_info->peer_macaddr, + &src_peer_stats_info->peer_macaddr, + sizeof(peer_stats_info->peer_macaddr)); + peer_stats_info->tx_packets = src_peer_stats_info->tx_packets; + peer_stats_info->tx_bytes = src_peer_stats_info->tx_bytes; + peer_stats_info->rx_packets = src_peer_stats_info->rx_packets; + peer_stats_info->rx_bytes = src_peer_stats_info->rx_bytes; + peer_stats_info->tx_retries = src_peer_stats_info->tx_retries; + peer_stats_info->tx_failed = src_peer_stats_info->tx_failed; + peer_stats_info->tx_succeed = src_peer_stats_info->tx_succeed; + peer_stats_info->rssi = src_peer_stats_info->rssi; + peer_stats_info->tx_rate = src_peer_stats_info->tx_rate; + peer_stats_info->tx_rate_code = + src_peer_stats_info->tx_rate_code; + peer_stats_info->rx_rate = src_peer_stats_info->rx_rate; + peer_stats_info->rx_rate_code = + src_peer_stats_info->rx_rate_code; + for (j = 0; j < WMI_MAX_CHAINS; j++) + peer_stats_info->peer_rssi_per_chain[j] = + src_peer_stats_info->peer_rssi_per_chain[j]; + + if (src_peer_stats_info->num_tx_rate_counts) { + peer_stats_info->tx_pkt_per_mcs = + qdf_mem_malloc( + src_peer_stats_info->num_tx_rate_counts * + sizeof(uint32_t)); + if (!peer_stats_info->tx_pkt_per_mcs) + return; + + peer_stats_info->num_tx_rate_counts = + src_peer_stats_info->num_tx_rate_counts; + qdf_mem_copy(peer_stats_info->tx_pkt_per_mcs, + src_peer_stats_info->tx_pkt_per_mcs, + peer_stats_info->num_tx_rate_counts * + sizeof(uint32_t)); + } + if (src_peer_stats_info->num_rx_rate_counts) { + peer_stats_info->rx_pkt_per_mcs = + qdf_mem_malloc( + src_peer_stats_info->num_rx_rate_counts * + sizeof(uint32_t)); + if (!peer_stats_info->rx_pkt_per_mcs) + return; + + peer_stats_info->num_rx_rate_counts = + src_peer_stats_info->num_rx_rate_counts; + qdf_mem_copy(peer_stats_info->rx_pkt_per_mcs, + src_peer_stats_info->rx_pkt_per_mcs, + peer_stats_info->num_rx_rate_counts * + sizeof(uint32_t)); + } + src_peer_stats_info++; + peer_stats_info++; + } +} + +/** + * get_peer_stats_cb() - get_peer_stats_cb callback function + * @ev: peer stats buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static void get_peer_stats_cb(struct stats_event *ev, void *cookie) +{ + struct stats_event *priv; + struct osif_request *request; + uint32_t peer_stats_info_size; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + peer_stats_info_size = sizeof(*ev->peer_stats_info_ext) * + ev->num_peer_stats_info_ext; + + if (priv->peer_stats_info_ext) { + osif_err("invalid context cookie %pK request %pK", + cookie, request); + goto peer_stats_cb_fail; + } + + priv->peer_stats_info_ext = qdf_mem_malloc(peer_stats_info_size); + if (!priv->peer_stats_info_ext) + goto peer_stats_cb_fail; + + copy_peer_stats_info_ext(priv->peer_stats_info_ext, ev); + + priv->num_peer_stats_info_ext = ev->num_peer_stats_info_ext; + +peer_stats_cb_fail: + osif_request_complete(request); + osif_request_put(request); +} + +/** + * get_station_adv_stats_cb() - get_station_adv_stats_cb callback function + * @ev: station stats buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static void get_station_adv_stats_cb(struct stats_event *ev, void *cookie) +{ + struct stats_event *priv; + struct osif_request *request; + uint32_t peer_adv_size; + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + if (!ev->peer_adv_stats || ev->num_peer_adv_stats == 0) { + osif_debug("Invalid stats"); + goto station_adv_stats_cb_fail; + } + + peer_adv_size = sizeof(*ev->peer_adv_stats) * ev->num_peer_adv_stats; + + if (peer_adv_size) { + priv->peer_adv_stats = qdf_mem_malloc(peer_adv_size); + if (!priv->peer_adv_stats) + goto station_adv_stats_cb_fail; + + qdf_mem_copy(priv->peer_adv_stats, ev->peer_adv_stats, + peer_adv_size); + } + priv->num_peer_adv_stats = ev->num_peer_adv_stats; + +station_adv_stats_cb_fail: + osif_request_complete(request); + osif_request_put(request); +} + +#ifdef WLAN_FEATURE_11BE_MLO +/** + * wlan_cfg80211_get_mlstats_vdev_peer - get peer per ml vdev + * @psoc: pointer to psoc struct + * @req_info: pointer to request info struct + * + * Return: QDF_STATUS_SUCCESS on success + */ +static QDF_STATUS +wlan_cfg80211_get_mlstats_vdev_peer(struct wlan_objmgr_psoc *psoc, + struct request_info *req_info) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_peer *peer; + struct mlo_stats_vdev_params *info = &req_info->ml_vdev_info; + int i; + + for (i = 0; i < info->ml_vdev_count; i++) { + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + info->ml_vdev_id[i], + WLAN_OSIF_STATS_ID); + if (!vdev) { + hdd_err("vdev object is NULL for vdev %d", + info->ml_vdev_id[i]); + return QDF_STATUS_E_INVAL; + } + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, + WLAN_OSIF_STATS_ID); + if (!peer) { + hdd_err("peer is null"); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID); + return QDF_STATUS_E_INVAL; + } + + qdf_mem_copy(&req_info->ml_peer_mac_addr[i][0], peer->macaddr, + QDF_MAC_ADDR_SIZE); + + wlan_objmgr_peer_release_ref(peer, WLAN_OSIF_STATS_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_OSIF_STATS_ID); + } + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +wlan_cfg80211_get_mlstats_vdev_params(struct wlan_objmgr_vdev *vdev, + struct request_info *info) +{ + struct wlan_objmgr_psoc *psoc; + bool is_mlo_vdev; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + is_mlo_vdev = wlan_vdev_mlme_get_is_mlo_vdev(psoc, info->vdev_id); + if (is_mlo_vdev) { + status = mlo_get_mlstats_vdev_params(psoc, &info->ml_vdev_info, + info->vdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("unable to get vdev params for mlo stats"); + return status; + } + } + + status = wlan_cfg80211_get_mlstats_vdev_peer(psoc, info); + return status; +} +#else +static QDF_STATUS +wlan_cfg80211_get_mlstats_vdev_params(struct wlan_objmgr_vdev *vdev, + struct request_info *info) +{ + return QDF_STATUS_SUCCESS; +} +#endif + +struct stats_event * +wlan_cfg80211_mc_cp_stats_get_peer_stats(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac_addr, + int *errno) +{ + void *cookie; + QDF_STATUS status; + struct stats_event *priv, *out; + struct osif_request *request; + struct request_info info = {0}; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_cp_stats_dealloc, + }; + + osif_debug("Enter"); + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + info.cookie = cookie; + info.u.get_peer_stats_cb = get_peer_stats_cb; + info.vdev_id = wlan_vdev_get_id(vdev); + info.pdev_id = wlan_objmgr_pdev_get_pdev_id(wlan_vdev_get_pdev(vdev)); + qdf_mem_copy(info.peer_mac_addr, mac_addr, QDF_MAC_ADDR_SIZE); + status = ucfg_mc_cp_stats_send_stats_request(vdev, + TYPE_PEER_STATS_INFO_EXT, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send stats request status: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_peer_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_peer_stats_fail; + } + + if (!priv->peer_stats_info_ext || priv->num_peer_stats_info_ext == 0) { + osif_err("Invalid stats"); + osif_err("Peer stats info ext %d:%pK", + priv->num_peer_stats_info_ext, + priv->peer_stats_info_ext); + *errno = -EINVAL; + goto get_peer_stats_fail; + } + + out->num_peer_stats_info_ext = priv->num_peer_stats_info_ext; + out->peer_stats_info_ext = priv->peer_stats_info_ext; + priv->peer_stats_info_ext = NULL; + osif_request_put(request); + + request = osif_request_alloc(¶ms); + if (!request) { + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + *errno = -ENOMEM; + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + info.cookie = cookie; + info.u.get_station_stats_cb = get_station_adv_stats_cb; + + status = wlan_cfg80211_get_mlstats_vdev_params(vdev, &info); + if (QDF_IS_STATUS_ERROR(status)) { + *errno = qdf_status_to_os_return(status); + goto get_peer_stats_fail; + } + + status = ucfg_mc_cp_stats_send_stats_request(vdev, TYPE_STATION_STATS, + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send stats request status: %d", status); + *errno = qdf_status_to_os_return(status); + goto get_peer_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_peer_stats_fail; + } + + if (!priv->peer_adv_stats || priv->num_peer_adv_stats == 0) { + osif_debug("Invalid stats"); + goto get_peer_stats_fail; + } + + out->num_peer_adv_stats = priv->num_peer_adv_stats; + out->peer_adv_stats = priv->peer_adv_stats; + priv->peer_adv_stats = NULL; + osif_request_put(request); + osif_debug("Exit"); + return out; +get_peer_stats_fail: + osif_request_put(request); + wlan_cfg80211_mc_cp_stats_free_stats_event(out); + + osif_debug("Exit"); + + return NULL; +} + +void wlan_cfg80211_mc_cp_stats_free_stats_event(struct stats_event *stats) +{ + if (!stats) + return; + + qdf_mem_free(stats->pdev_stats); + qdf_mem_free(stats->peer_stats); + qdf_mem_free(stats->cca_stats); + qdf_mem_free(stats->vdev_summary_stats); + qdf_mem_free(stats->vdev_chain_rssi); + qdf_mem_free(stats->peer_adv_stats); + wlan_free_mib_stats(stats); + wlan_cfg80211_mc_cp_stats_free_peer_stats_info_ext(stats); + qdf_mem_free(stats->vdev_extd_stats); + qdf_mem_free(stats); +} + +#ifdef WLAN_FEATURE_BIG_DATA_STATS +void +wlan_cfg80211_mc_cp_stats_free_big_data_stats_event( + struct big_data_stats_event *stats) +{ + if (!stats) + return; + + qdf_mem_free(stats); +} +#endif + +#ifdef CONFIG_WLAN_BMISS +static void get_bmiss_infra_cp_stats(struct infra_cp_stats_event *ev, + struct infra_cp_stats_event *priv) + +{ + int idx = 0; + + if (!ev || !ev->bmiss_infra_cp_stats) { + osif_err("got bmiss_infra_cp_stats as NULL"); + return; + } + priv->bmiss_infra_cp_stats->num_pre_bmiss = + ev->bmiss_infra_cp_stats->num_pre_bmiss; + for (idx = 0; idx < BMISS_STATS_RSSI_SAMPLES_MAX; idx++) { + priv->bmiss_infra_cp_stats->rssi_samples[idx].rssi = + ev->bmiss_infra_cp_stats->rssi_samples[idx].rssi; + priv->bmiss_infra_cp_stats->rssi_samples[idx].sample_time = + ev->bmiss_infra_cp_stats->rssi_samples[idx].sample_time; + } + priv->bmiss_infra_cp_stats->rssi_sample_curr_index = + ev->bmiss_infra_cp_stats->rssi_sample_curr_index; + priv->bmiss_infra_cp_stats->num_first_bmiss = + ev->bmiss_infra_cp_stats->num_first_bmiss; + priv->bmiss_infra_cp_stats->num_final_bmiss = + ev->bmiss_infra_cp_stats->num_final_bmiss; + priv->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss = + ev->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss; + priv->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss = + ev->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss; + priv->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss = + ev->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss; + priv->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss = + ev->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss; + priv->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences = + ev->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences; + priv->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound = + ev->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound; + priv->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost = + ev->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost; +} + +/** + * infra_cp_stats_bmiss_response_cb() - callback function to handle stats event + * @ev: stats event buffer + * @cookie: a cookie for the request context + * + * Return: None + */ +static inline +void infra_cp_stats_bmiss_response_cb(struct infra_cp_stats_event *ev, + void *cookie) +{ + struct infra_cp_stats_event *priv; + struct osif_request *request; + + osif_debug("Enter"); + + request = osif_request_get(cookie); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + + priv->action = ev->action; + priv->request_id = ev->request_id; + priv->status = ev->status; + get_bmiss_infra_cp_stats(ev, priv); + + osif_request_complete(request); + osif_request_put(request); +} + +#define MAX_BMISS_STAT_VDEV_ENTRIES 1 +#define MAX_BMISS_STAT_MAC_ADDR_ENTRIES 1 + +struct infra_cp_stats_event * +wlan_cfg80211_mc_bmiss_get_infra_cp_stats(struct wlan_objmgr_vdev *vdev, + uint8_t mac[QDF_MAC_ADDR_SIZE], + int *errno) +{ + void *cookie; + int idx = 0; + QDF_STATUS status; + struct infra_cp_stats_event *priv, *out; + struct bmiss_infra_cp_stats_event *bmiss_event; + struct osif_request *request; + struct infra_cp_stats_cmd_info info = {0}; + get_infra_cp_stats_cb resp_cb = NULL; + void *context = NULL; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = 2 * CP_STATS_WAIT_TIME_STAT, + .dealloc = wlan_cfg80211_mc_infra_cp_stats_dealloc, + }; + + osif_debug("Enter"); + status = wlan_cp_stats_infra_cp_get_context(wlan_vdev_get_psoc(vdev), + &resp_cb, &context); + if (QDF_IS_STATUS_ERROR(status)) { + *errno = -EFAULT; + return NULL; + } + if (resp_cb) { + osif_debug("another request already in progress"); + *errno = -EBUSY; + return NULL; + } + + out = qdf_mem_malloc(sizeof(*out)); + if (!out) { + *errno = -ENOMEM; + return NULL; + } + + out->bmiss_infra_cp_stats = + qdf_mem_malloc(sizeof(*out->bmiss_infra_cp_stats)); + if (!out->bmiss_infra_cp_stats) { + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + request = osif_request_alloc(¶ms); + if (!request) { + qdf_mem_free(out->bmiss_infra_cp_stats); + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + + cookie = osif_request_cookie(request); + priv = osif_request_priv(request); + + priv->bmiss_infra_cp_stats = + qdf_mem_malloc(sizeof(*priv->bmiss_infra_cp_stats)); + if (!priv->bmiss_infra_cp_stats) { + qdf_mem_free(out->bmiss_infra_cp_stats); + qdf_mem_free(out); + *errno = -ENOMEM; + return NULL; + } + bmiss_event = priv->bmiss_infra_cp_stats; + info.request_cookie = cookie; + info.stats_id = TYPE_REQ_CTRL_PATH_BMISS_STAT; + info.action = ACTION_REQ_CTRL_PATH_STAT_GET; + info.infra_cp_stats_resp_cb = infra_cp_stats_bmiss_response_cb; + info.num_pdev_ids = 0; + info.num_vdev_ids = MAX_BMISS_STAT_VDEV_ENTRIES; + info.vdev_id[0] = wlan_vdev_get_id(vdev); + info.num_mac_addr_list = MAX_TWT_STAT_MAC_ADDR_ENTRIES; + info.num_pdev_ids = 0; + + qdf_mem_copy(&info.peer_mac_addr[0], mac, QDF_MAC_ADDR_SIZE); + status = ucfg_infra_cp_stats_register_resp_cb(wlan_vdev_get_psoc(vdev), + &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to register resp callback: %d", status); + *errno = qdf_status_to_os_return(status); + goto free_stats; + } + + status = ucfg_send_infra_cp_stats_request(vdev, &info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send bmiss stats request status: %d", + status); + *errno = qdf_status_to_os_return(status); + goto get_bmiss_stats_fail; + } + + *errno = osif_request_wait_for_response(request); + if (*errno) { + osif_err("wait failed or timed out ret: %d", *errno); + goto get_bmiss_stats_fail; + } + + out->request_id = priv->request_id; + out->bmiss_infra_cp_stats->num_pre_bmiss = bmiss_event->num_pre_bmiss; + out->bmiss_infra_cp_stats->num_pre_bmiss = + bmiss_event->num_pre_bmiss; + for (idx = 0; idx < BMISS_STATS_RSSI_SAMPLES_MAX; idx++) { + out->bmiss_infra_cp_stats->rssi_samples[idx].rssi = + bmiss_event->rssi_samples[idx].rssi; + out->bmiss_infra_cp_stats->rssi_samples[idx].sample_time = + bmiss_event->rssi_samples[idx].sample_time; + } + out->bmiss_infra_cp_stats->rssi_sample_curr_index = + bmiss_event->rssi_sample_curr_index; + out->bmiss_infra_cp_stats->num_first_bmiss = + bmiss_event->num_first_bmiss; + out->bmiss_infra_cp_stats->num_null_sent_in_first_bmiss = + bmiss_event->num_null_sent_in_first_bmiss; + out->bmiss_infra_cp_stats->num_null_failed_in_first_bmiss = + bmiss_event->num_null_failed_in_first_bmiss; + out->bmiss_infra_cp_stats->num_null_sent_in_final_bmiss = + bmiss_event->num_null_sent_in_final_bmiss; + out->bmiss_infra_cp_stats->num_null_failed_in_final_bmiss = + bmiss_event->num_null_failed_in_final_bmiss; + out->bmiss_infra_cp_stats->cons_bmiss_stats.num_of_bmiss_sequences = + bmiss_event->cons_bmiss_stats.num_of_bmiss_sequences; + out->bmiss_infra_cp_stats->cons_bmiss_stats.num_bitmask_wraparound = + bmiss_event->cons_bmiss_stats.num_bitmask_wraparound; + out->bmiss_infra_cp_stats->cons_bmiss_stats.num_bcn_hist_lost = + bmiss_event->cons_bmiss_stats.num_bcn_hist_lost; + + qdf_mem_copy(&out->bmiss_infra_cp_stats->peer_macaddr, mac, + QDF_MAC_ADDR_SIZE); + osif_request_put(request); + status = ucfg_infra_cp_stats_deregister_resp_cb( + wlan_vdev_get_psoc(vdev)); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to deregister resp callback: %d", status); + osif_debug("Exit"); + return out; +get_bmiss_stats_fail: + status = ucfg_infra_cp_stats_deregister_resp_cb( + wlan_vdev_get_psoc(vdev)); + if (QDF_IS_STATUS_ERROR(status)) + hdd_err("Failed to deregister resp callback: %d", status); +free_stats: + osif_request_put(request); + wlan_cfg80211_mc_infra_cp_stats_free_stats_event(out); + osif_debug("Exit"); + return NULL; +} +#endif /* CONFIG_WLAN_BMISS */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp.h b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp.h new file mode 100644 index 0000000000..f7fbb36aa3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: os_if_dp.h + * + * + */ +#ifndef __OSIF_DP_H__ +#define __OSIF_DP_H__ + +#include "wlan_dp_public_struct.h" +#include + +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +/** + * enum qdisc_filter_status - QDISC filter status + * @QDISC_FILTER_RTNL_LOCK_FAIL: rtnl lock acquire failed + * @QDISC_FILTER_PRIO_MATCH: qdisc filter with priority match + * @QDISC_FILTER_PRIO_MISMATCH: no filter match with configured priority + */ +enum qdisc_filter_status { + QDISC_FILTER_RTNL_LOCK_FAIL, + QDISC_FILTER_PRIO_MATCH, + QDISC_FILTER_PRIO_MISMATCH, +}; +#endif + +/** + * osif_dp_classify_pkt() - classify packet + * @skb: sk buff + * + * Return: None + */ +void osif_dp_classify_pkt(struct sk_buff *skb); + +/** + * osif_dp_mark_pkt_type() - Mark pkt type in CB + * @skb: sk buff + * + * Return: None + */ +void osif_dp_mark_pkt_type(struct sk_buff *skb); + +/* wait time for nud stats in milliseconds */ +#define WLAN_WAIT_TIME_NUD_STATS 800 +/* nud stats skb max length */ +#define WLAN_NUD_STATS_LEN 800 +/* ARP packet type for NUD debug stats */ +#define WLAN_NUD_STATS_ARP_PKT_TYPE 1 + +#define MAX_USER_COMMAND_SIZE 4096 +#define DNS_DOMAIN_NAME_MAX_LEN 255 +#define ICMPV6_ADDR_LEN 16 + +#define CONNECTIVITY_CHECK_SET_ARP \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ARP +#define CONNECTIVITY_CHECK_SET_DNS \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_DNS +#define CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE +#define CONNECTIVITY_CHECK_SET_ICMPV4 \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ICMPV4 +#define CONNECTIVITY_CHECK_SET_ICMPV6 \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_ICMPV6 +#define CONNECTIVITY_CHECK_SET_TCP_SYN \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_SYN +#define CONNECTIVITY_CHECK_SET_TCP_SYN_ACK \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_SYN_ACK +#define CONNECTIVITY_CHECK_SET_TCP_ACK \ + QCA_WLAN_VENDOR_CONNECTIVITY_CHECK_SET_TCP_ACK + +/** + * os_if_dp_register_txrx_callbacks() - Register TX/RX OSIF callbacks + * @cb_obj: Call back object pointer for ops registration + * + * Return: None + */ +void os_if_dp_register_txrx_callbacks(struct wlan_dp_psoc_callbacks *cb_obj); + +/** + * os_if_dp_register_hdd_callbacks() - Register callback handlers + * @psoc: Pointer to psoc context + * @cb_obj: Callback object pointer + * + * Return: None + */ +void os_if_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_psoc_callbacks *cb_obj); + +/** + * osif_dp_nud_register_netevent_notifier() - Register netevent notifier + * @psoc: Pointer to psoc context + * + * Return: 0 on success, error code on failure + */ +int osif_dp_nud_register_netevent_notifier(struct wlan_objmgr_psoc *psoc); + +/** + * osif_dp_nud_unregister_netevent_notifier() - Unregister netevent notifier + * @psoc: Pointer to psoc context + * + * Return: None + */ +void osif_dp_nud_unregister_netevent_notifier(struct wlan_objmgr_psoc *psoc); + +/** + * osif_dp_get_nud_stats() - get arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @vdev: pointer to vdev context. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to get arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +int osif_dp_get_nud_stats(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); + +/** + * osif_dp_set_nud_stats() - set arp stats command to firmware + * @wiphy: pointer to wireless wiphy structure. + * @vdev: pointer to wireless_dev structure. + * @data: pointer to apfind configuration data. + * @data_len: the length in byte of apfind data. + * + * This is called when wlan driver needs to send arp stats to + * firmware. + * + * Return: An error code or 0 on success. + */ +int osif_dp_set_nud_stats(struct wiphy *wiphy, struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); +#endif /* __OSIF_DP_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp_local_pkt_capture.h b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp_local_pkt_capture.h new file mode 100644 index 0000000000..9db397788d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp_local_pkt_capture.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OS_IF_DP_LOCAL_PKT_CAPTURE_H_ +#define _OS_IF_DP_LOCAL_PKT_CAPTURE_H_ + +#include "qdf_types.h" +#include "qca_vendor.h" + +#ifdef WLAN_FEATURE_LOCAL_PKT_CAPTURE + +#define FEATURE_MONITOR_MODE_VENDOR_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_monitor_mode, \ + vendor_command_policy(set_monitor_mode_policy, \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MAX) \ + }, \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_get_monitor_mode, \ + vendor_command_policy(VENDOR_CMD_RAW_DATA, 0) \ + }, + +extern const struct nla_policy +set_monitor_mode_policy[QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MAX + 1]; + +/** + * os_if_dp_set_lpc_configure() - Configure local packet capture + * operation in the received vendor command + * @vdev: vdev + * @data: NL data + * @data_len: NL data length + * + * Return: QDF_STATUS_SUCCESS if Success; + * QDF_STATUS_E_* if Failure + */ +QDF_STATUS os_if_dp_set_lpc_configure(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); + +/** + * os_if_dp_local_pkt_capture_stop() - Stop local packet capture + * @vdev: vdev + * + * Return: 0 for Success and negative value for failure + */ +QDF_STATUS os_if_dp_local_pkt_capture_stop(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_dp_get_lpc_state() - get local packet capture state + * in the received vendor command + * @vdev: vdev + * @data: NL data + * @data_len: NL data length + * + * Return: QDF_STATUS_SUCCESS if Success; + * QDF_STATUS_E_* if Failure + */ +QDF_STATUS os_if_dp_get_lpc_state(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len); + +/** + * os_if_lpc_mon_intf_creation_allowed() - Check if local packet capture + * monitor interface creation is allowed or not + * @psoc: psoc object handle + * + * Return: true, If monitor interface creation is allowed + * false, Otherwise + */ +bool os_if_lpc_mon_intf_creation_allowed(struct wlan_objmgr_psoc *psoc); +#else +static inline +QDF_STATUS os_if_dp_set_lpc_configure(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS os_if_dp_local_pkt_capture_stop(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +QDF_STATUS os_if_dp_get_lpc_state(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +bool os_if_lpc_mon_intf_creation_allowed(struct wlan_objmgr_psoc *psoc) +{ + return true; +} + +#endif /* WLAN_FEATURE_LOCAL_PKT_CAPTURE */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp_lro.h b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp_lro.h new file mode 100644 index 0000000000..d53f359e0a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/inc/os_if_dp_lro.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_dp_lro.h + * + * WLAN Host Device Driver file for DP LRO support. + * + */ + +#ifndef _OSIF_DP_LRO_H_ +#define _OSIF_DP_LRO_H_ + +#include +#include + +#if defined(FEATURE_LRO) +/** + * osif_dp_lro_rx() - Handle Rx processing via LRO + * @dev: netdev + * @nbuf: network buffer + * + * Return: QDF_STATUS_SUCCESS if processed via LRO or non zero return code + */ +QDF_STATUS osif_dp_lro_rx(qdf_netdev_t dev, qdf_nbuf_t nbuf); + +void osif_dp_lro_display_stats(struct wlan_objmgr_vdev *vdev); + +/** + * osif_dp_lro_set_reset() - vendor command for Disable/Enable LRO + * @vdev: Vdev obj mgr + * @enable_flag: enable or disable LRO. + * + * Return: none + */ +QDF_STATUS +osif_dp_lro_set_reset(struct wlan_objmgr_vdev *vdev, uint8_t enable_flag); + +#else +static inline +QDF_STATUS osif_dp_lro_rx(qdf_netdev_t dev, qdf_nbuf_t nbuf) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline void osif_dp_lro_display_stats(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline QDF_STATUS +osif_dp_lro_set_reset(struct wlan_objmgr_vdev *vdev, uint8_t enable_flag) +{ + return 0; +} +#endif /* FEATURE_LRO */ + +#endif /* _OSIF_DP_LRO_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp.c b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp.c new file mode 100644 index 0000000000..f906004691 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp.c @@ -0,0 +1,1247 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + /** + * DOC: os_if_dp.c + * + * + */ +#include "os_if_dp.h" +#include "wlan_nlink_srv.h" +#include +#include +#include +#include "qca_vendor.h" +#include "wlan_dp_ucfg_api.h" +#include "osif_vdev_sync.h" +#include "osif_sync.h" +#include +#include "wlan_osif_request_manager.h" +#include + +/* + * define short names for the global vendor params + * used by wlan_hdd_cfg80211_setarp_stats_cmd() + */ +#define STATS_GET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define COUNT_FROM_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_FROM_NETDEV +#define COUNT_TO_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TO_LOWER_MAC +#define RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_REQ_RX_COUNT_BY_LOWER_MAC +#define COUNT_TX_SUCCESS \ + QCA_ATTR_NUD_STATS_ARP_REQ_COUNT_TX_SUCCESS +#define RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_LOWER_MAC +#define RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_NUD_STATS_ARP_RSP_RX_COUNT_BY_UPPER_MAC +#define RSP_COUNT_TO_NETDEV \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_TO_NETDEV +#define RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_NUD_STATS_ARP_RSP_COUNT_OUT_OF_ORDER_DROP +#define AP_LINK_ACTIVE \ + QCA_ATTR_NUD_STATS_AP_LINK_ACTIVE +#define AP_LINK_DAD \ + QCA_ATTR_NUD_STATS_IS_DAD +#define DATA_PKT_STATS \ + QCA_ATTR_NUD_STATS_DATA_PKT_STATS +#define STATS_GET_MAX \ + QCA_ATTR_NUD_STATS_GET_MAX + +#define CHECK_STATS_INVALID \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_INVALID +#define CHECK_STATS_PKT_TYPE \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_TYPE +#define CHECK_STATS_PKT_DNS_DOMAIN_NAME \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DNS_DOMAIN_NAME +#define CHECK_STATS_PKT_SRC_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_SRC_PORT +#define CHECK_STATS_PKT_DEST_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_PORT +#define CHECK_STATS_PKT_DEST_IPV4 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_IPV4 +#define CHECK_STATS_PKT_DEST_IPV6 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_DEST_IPV6 +#define CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV +#define CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC +#define CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC +#define CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS +#define CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC +#define CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC +#define CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV +#define CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP +#define CHECK_DATA_STATS_MAX \ + QCA_ATTR_CONNECTIVITY_CHECK_DATA_STATS_MAX + +#define STATS_SET_INVALID \ + QCA_ATTR_NUD_STATS_SET_INVALID +#define STATS_SET_START \ + QCA_ATTR_NUD_STATS_SET_START +#define STATS_GW_IPV4 \ + QCA_ATTR_NUD_STATS_GW_IPV4 +#define STATS_SET_DATA_PKT_INFO \ + QCA_ATTR_NUD_STATS_SET_DATA_PKT_INFO +#define STATS_SET_MAX \ + QCA_ATTR_NUD_STATS_SET_MAX + +const struct nla_policy +dp_set_nud_stats_policy[STATS_SET_MAX + 1] = { + [STATS_SET_START] = {.type = NLA_FLAG }, + [STATS_GW_IPV4] = {.type = NLA_U32 }, + [STATS_SET_DATA_PKT_INFO] = {.type = NLA_NESTED }, +}; + +/* define short names for the global vendor params */ +#define CONNECTIVITY_STATS_SET_INVALID \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SET_INVALID +#define STATS_PKT_INFO_TYPE \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_STATS_PKT_INFO_TYPE +#define STATS_DNS_DOMAIN_NAME \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DNS_DOMAIN_NAME +#define STATS_SRC_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SRC_PORT +#define STATS_DEST_PORT \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_PORT +#define STATS_DEST_IPV4 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_IPV4 +#define STATS_DEST_IPV6 \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_DEST_IPV6 +#define CONNECTIVITY_STATS_SET_MAX \ + QCA_ATTR_CONNECTIVITY_CHECK_STATS_SET_MAX + +const struct nla_policy +dp_set_connectivity_check_stats[CONNECTIVITY_STATS_SET_MAX + 1] = { + [STATS_PKT_INFO_TYPE] = {.type = NLA_U32 }, + [STATS_DNS_DOMAIN_NAME] = {.type = NLA_NUL_STRING, + .len = DNS_DOMAIN_NAME_MAX_LEN }, + [STATS_SRC_PORT] = {.type = NLA_U32 }, + [STATS_DEST_PORT] = {.type = NLA_U32 }, + [STATS_DEST_IPV4] = {.type = NLA_U32 }, + [STATS_DEST_IPV6] = {.type = NLA_BINARY, + .len = ICMPV6_ADDR_LEN }, +}; + +#ifdef WLAN_FEATURE_DP_BUS_BANDWIDTH +/** + * osif_dp_send_tcp_param_update_event() - Send vendor event to update + * TCP parameter through Wi-Fi HAL + * @psoc: Pointer to psoc context + * @data: Parameters to update + * @dir: Direction(tx/rx) to update + * + * Return: None + */ +static +void osif_dp_send_tcp_param_update_event(struct wlan_objmgr_psoc *psoc, + union wlan_tp_data *data, + uint8_t dir) +{ + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev; + struct pdev_osif_priv *os_priv; + uint32_t event_len; + bool tcp_limit_output = false; + bool tcp_del_ack_ind_enabled = false; + bool tcp_adv_win_scl_enabled = false; + enum wlan_tp_level next_tp_level = WLAN_SVC_TP_NONE; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_THROUGHPUT_CHANGE_EVENT_INDEX; + + event_len = sizeof(uint8_t) + sizeof(uint8_t) + NLMSG_HDRLEN; + pdev = wlan_objmgr_get_pdev_by_id(psoc, 0, WLAN_DP_ID); + if (!pdev) + return; + + os_priv = wlan_pdev_get_ospriv(pdev); + + if (dir == 0) /*TX Flow */ { + struct wlan_tx_tp_data *tx_tp_data = + (struct wlan_tx_tp_data *)data; + + next_tp_level = tx_tp_data->level; + + if (tx_tp_data->tcp_limit_output) { + /* TCP_LIMIT_OUTPUT_BYTES */ + event_len += sizeof(uint32_t); + tcp_limit_output = true; + } + } else if (dir == 1) /* RX Flow */ { + struct wlan_rx_tp_data *rx_tp_data = + (struct wlan_rx_tp_data *)data; + + next_tp_level = rx_tp_data->level; + + if (rx_tp_data->rx_tp_flags & TCP_DEL_ACK_IND_MASK) { + event_len += sizeof(uint32_t); /* TCP_DELACK_SEG */ + tcp_del_ack_ind_enabled = true; + } + if (rx_tp_data->rx_tp_flags & TCP_ADV_WIN_SCL_MASK) { + event_len += sizeof(uint32_t); /* TCP_ADV_WIN_SCALE */ + tcp_adv_win_scl_enabled = true; + } + } else { + dp_err("Invalid Direction [%d]", dir); + wlan_objmgr_pdev_release_ref(pdev, WLAN_DP_ID); + return; + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, + NULL, event_len, + index, GFP_KERNEL); + + if (!vendor_event) { + dp_err("wlan_cfg80211_vendor_event_alloc failed"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_DP_ID); + return; + } + + if (nla_put_u8( + vendor_event, + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_DIRECTION, + dir)) + goto tcp_param_change_nla_failed; + + if (nla_put_u8( + vendor_event, + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_THROUGHPUT_LEVEL, + (next_tp_level == WLAN_SVC_TP_LOW ? + QCA_WLAN_THROUGHPUT_LEVEL_LOW : + QCA_WLAN_THROUGHPUT_LEVEL_HIGH))) + goto tcp_param_change_nla_failed; + + if (tcp_limit_output && + nla_put_u32( + vendor_event, + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_LIMIT_OUTPUT_BYTES, + (next_tp_level == WLAN_SVC_TP_LOW ? + TCP_LIMIT_OUTPUT_BYTES_LOW : + TCP_LIMIT_OUTPUT_BYTES_HI))) + goto tcp_param_change_nla_failed; + + if (tcp_del_ack_ind_enabled && + (nla_put_u32( + vendor_event, + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_DELACK_SEG, + (next_tp_level == WLAN_SVC_TP_LOW ? + TCP_DEL_ACK_LOW : TCP_DEL_ACK_HI)))) + goto tcp_param_change_nla_failed; + + if (tcp_adv_win_scl_enabled && + (nla_put_u32( + vendor_event, + QCA_WLAN_VENDOR_ATTR_THROUGHPUT_CHANGE_TCP_ADV_WIN_SCALE, + (next_tp_level == WLAN_SVC_TP_LOW ? + WIN_SCALE_LOW : WIN_SCALE_HI)))) + goto tcp_param_change_nla_failed; + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + wlan_objmgr_pdev_release_ref(pdev, WLAN_DP_ID); + return; + +tcp_param_change_nla_failed: + wlan_objmgr_pdev_release_ref(pdev, WLAN_DP_ID); + dp_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} +#else +static +void osif_dp_send_tcp_param_update_event(struct wlan_objmgr_psoc *psoc, + union wlan_tp_data *data, + uint8_t dir) +{ +} +#endif /*WLAN_FEATURE_DP_BUS_BANDWIDTH*/ + +/** + * osif_dp_get_net_dev_from_vdev() - Get netdev object from vdev + * @vdev: Pointer to vdev manager + * @out_net_dev: Pointer to output netdev + * + * Return: 0 on success, error code on failure + */ +static int osif_dp_get_net_dev_from_vdev(struct wlan_objmgr_vdev *vdev, + struct net_device **out_net_dev) +{ + struct vdev_osif_priv *priv; + + if (!vdev) + return -EINVAL; + + priv = wlan_vdev_get_ospriv(vdev); + if (!priv || !priv->wdev || !priv->wdev->netdev) + return -EINVAL; + + *out_net_dev = priv->wdev->netdev; + + return 0; +} + +/** + * osif_dp_process_mic_error() - Indicate mic error to supplicant + * @info: MIC error information + * @vdev: vdev handle + * + * Return: None + */ +static void +osif_dp_process_mic_error(struct dp_mic_error_info *info, + struct wlan_objmgr_vdev *vdev) +{ + struct net_device *dev; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_dp_get_net_dev_from_vdev(vdev, &dev); + if (errno) { + dp_err("failed to get netdev"); + return; + } + if (osif_vdev_sync_op_start(dev, &vdev_sync)) + return; + + /* inform mic failure to nl80211 */ + cfg80211_michael_mic_failure(dev, + (uint8_t *)&info->ta_mac_addr, + info->multicast ? + NL80211_KEYTYPE_GROUP : + NL80211_KEYTYPE_PAIRWISE, + info->key_id, + info->tsc, + GFP_KERNEL); + osif_vdev_sync_op_stop(vdev_sync); +} + + +/** + * osif_dp_get_arp_stats_event_handler() - ARP get stats event handler + * @psoc: psoc handle + * @rsp: Get ARP stats response + * + * Return: None + */ +static void osif_dp_get_arp_stats_event_handler(struct wlan_objmgr_psoc *psoc, + struct dp_rsp_stats *rsp) +{ + struct osif_request *request = NULL; + void *context; + + context = ucfg_dp_get_arp_request_ctx(psoc); + if (!context) + return; + + request = osif_request_get(context); + if (!request) + return; + + ucfg_dp_get_arp_stats_event_handler(psoc, rsp); + + osif_request_complete(request); + osif_request_put(request); +} + +#ifdef WLAN_NUD_TRACKING +/** + * nud_state_osif_to_dp() - convert os_if to enum + * @curr_state: Current NUD state + * + * Return: DP enum equivalent to NUD state + */ +static inline enum dp_nud_state nud_state_osif_to_dp(uint8_t curr_state) +{ + switch (curr_state) { + case NUD_NONE: + return DP_NUD_NONE; + case NUD_INCOMPLETE: + return DP_NUD_INCOMPLETE; + case NUD_REACHABLE: + return DP_NUD_REACHABLE; + case NUD_STALE: + return DP_NUD_STALE; + case NUD_DELAY: + return DP_NUD_DELAY; + case NUD_PROBE: + return DP_NUD_PROBE; + case NUD_FAILED: + return DP_NUD_FAILED; + case NUD_NOARP: + return DP_NUD_NOARP; + case NUD_PERMANENT: + return DP_NUD_PERMANENT; + default: + return DP_NUD_STATE_INVALID; + } +} + +/** + * os_if_dp_nud_stats_info() - print NUD stats info + * @vdev: vdev handle + * + * Return: None + */ +static void os_if_dp_nud_stats_info(struct wlan_objmgr_vdev *vdev) +{ + struct netdev_queue *txq; + struct net_device *net_dev; + int i = 0, errno; + + errno = osif_dp_get_net_dev_from_vdev(vdev, &net_dev); + if (errno) { + dp_err("failed to get netdev"); + return; + } + dp_info("carrier state: %d", netif_carrier_ok(net_dev)); + + for (i = 0; i < NUM_TX_QUEUES; i++) { + txq = netdev_get_tx_queue(net_dev, i); + dp_info("Queue: %d status: %d txq->trans_start: %lu", + i, netif_tx_queue_stopped(txq), txq->trans_start); + } +} + +/** + * os_if_dp_nud_netevent_cb() - netevent callback + * @nb: Pointer to notifier block + * @event: Net Event triggered + * @data: Pointer to neighbour struct + * + * Callback for netevent + * + * Return: 0 on success + */ +static int os_if_dp_nud_netevent_cb(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct neighbour *neighbor = data; + struct osif_vdev_sync *vdev_sync; + const struct net_device *netdev = neighbor->dev; + int errno; + + errno = osif_vdev_sync_op_start(neighbor->dev, &vdev_sync); + if (errno) + return errno; + + switch (event) { + case NETEVENT_NEIGH_UPDATE: + ucfg_dp_nud_event((struct qdf_mac_addr *)netdev->dev_addr, + (struct qdf_mac_addr *)&neighbor->ha[0], + nud_state_osif_to_dp(neighbor->nud_state)); + break; + default: + break; + } + + osif_vdev_sync_op_stop(vdev_sync); + + return 0; +} + +static struct notifier_block wlan_netevent_nb = { + .notifier_call = os_if_dp_nud_netevent_cb +}; + +int osif_dp_nud_register_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ + int ret = 0; + + if (ucfg_dp_nud_tracking_enabled(psoc)) { + ret = register_netevent_notifier(&wlan_netevent_nb); + if (!ret) + dp_info("Registered netevent notifier"); + } + return ret; +} + +void osif_dp_nud_unregister_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ + int ret = 0; + + if (ucfg_dp_nud_tracking_enabled(psoc)) { + ret = unregister_netevent_notifier(&wlan_netevent_nb); + if (!ret) + dp_info("Unregistered netevent notifier"); + } +} +#else +static void os_if_dp_nud_stats_info(struct wlan_objmgr_vdev *vdev) +{ +} + +int osif_dp_nud_register_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +void osif_dp_nud_unregister_netevent_notifier(struct wlan_objmgr_psoc *psoc) +{ +} +#endif + +/** + * dp_dns_unmake_name_query() - Convert an uncompressed DNS name to a + * NUL-terminated string + * @name: DNS name + * + * Return: Produce a printable version of a DNS name. + */ +static inline uint8_t *dp_dns_unmake_name_query(uint8_t *name) +{ + uint8_t *p; + unsigned int len; + + p = name; + while ((len = *p)) { + *(p++) = '.'; + p += len; + } + + return name + 1; +} + +/** + * dp_dns_make_name_query() - Convert a standard NUL-terminated string + * to DNS name + * @string: Name as a NUL-terminated string + * @buf: Buffer in which to place DNS name + * @len: BUffer length + * + * DNS names consist of "element" pairs. + * + * Return: Byte following constructed DNS name + */ +static uint8_t *dp_dns_make_name_query(const uint8_t *string, + uint8_t *buf, uint8_t len) +{ + uint8_t *length_byte = buf++; + uint8_t c; + + if (string[len - 1]) { + dp_err("DNS name is not null terminated"); + return NULL; + } + + while ((c = *(string++))) { + if (c == '.') { + *length_byte = buf - length_byte - 1; + length_byte = buf; + } + *(buf++) = c; + } + *length_byte = buf - length_byte - 1; + *(buf++) = '\0'; + return buf; +} + +/** + * osif_dp_set_clear_connectivity_check_stats_info() - set/clear stats info + * @vdev: vdev context + * @arp_stats_params: arp stats structure to be sent to FW + * @tb: nl attribute + * @is_set_stats: set/clear stats + * + * + * Return: 0 on success, negative errno on failure + */ +static int osif_dp_set_clear_connectivity_check_stats_info( + struct wlan_objmgr_vdev *vdev, + struct dp_set_arp_stats_params *arp_stats_params, + struct nlattr **tb, bool is_set_stats) +{ + struct nlattr *tb2[CONNECTIVITY_STATS_SET_MAX + 1]; + struct nlattr *curr_attr = NULL; + int err = 0; + uint32_t pkt_bitmap; + int rem; + uint8_t dns_payload[256]; + uint32_t pkt_type_bitmap = ucfg_dp_get_pkt_type_bitmap_value(vdev); + + /* Set NUD command for start tracking is received. */ + nla_for_each_nested(curr_attr, + tb[STATS_SET_DATA_PKT_INFO], + rem) { + if (wlan_cfg80211_nla_parse(tb2, + CONNECTIVITY_STATS_SET_MAX, + nla_data(curr_attr), nla_len(curr_attr), + dp_set_connectivity_check_stats)) { + dp_err("nla_parse failed"); + err = -EINVAL; + goto end; + } + + if (tb2[STATS_PKT_INFO_TYPE]) { + pkt_bitmap = nla_get_u32(tb2[STATS_PKT_INFO_TYPE]); + if (!pkt_bitmap) { + dp_err("pkt tracking bitmap is empty"); + err = -EINVAL; + goto end; + } + + if (is_set_stats) { + arp_stats_params->pkt_type_bitmap = pkt_bitmap; + arp_stats_params->flag = true; + pkt_type_bitmap |= + arp_stats_params->pkt_type_bitmap; + ucfg_dp_set_pkt_type_bitmap_value(vdev, + pkt_type_bitmap); + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_ARP) { + if (!tb[STATS_GW_IPV4]) { + dp_err("GW ipv4 address is not present"); + err = -EINVAL; + goto end; + } + arp_stats_params->ip_addr = + nla_get_u32(tb[STATS_GW_IPV4]); + arp_stats_params->pkt_type = + WLAN_NUD_STATS_ARP_PKT_TYPE; + ucfg_dp_set_track_arp_ip_value(vdev, + arp_stats_params->ip_addr); + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + uint8_t *domain_name; + + if (!tb2[STATS_DNS_DOMAIN_NAME]) { + dp_err("DNS domain id is not present"); + err = -EINVAL; + goto end; + } + domain_name = nla_data( + tb2[STATS_DNS_DOMAIN_NAME]); + ucfg_dp_set_track_dns_domain_len_value(vdev, + nla_len(tb2[STATS_DNS_DOMAIN_NAME])); + ucfg_dp_get_dns_payload_value(vdev, dns_payload); + if (!dp_dns_make_name_query( + domain_name, + dns_payload, + ucfg_dp_get_track_dns_domain_len_value(vdev))) + ucfg_dp_set_track_dns_domain_len_value(vdev, 0); + /* DNStracking isn't supported in FW. */ + arp_stats_params->pkt_type_bitmap &= + ~CONNECTIVITY_CHECK_SET_DNS; + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + if (!tb2[STATS_SRC_PORT] || + !tb2[STATS_DEST_PORT]) { + dp_err("Source/Dest port is not present"); + err = -EINVAL; + goto end; + } + arp_stats_params->tcp_src_port = + nla_get_u32( + tb2[STATS_SRC_PORT]); + arp_stats_params->tcp_dst_port = + nla_get_u32( + tb2[STATS_DEST_PORT]); + ucfg_dp_set_track_src_port_value(vdev, + arp_stats_params->tcp_src_port); + ucfg_dp_set_track_dest_port_value(vdev, + arp_stats_params->tcp_dst_port); + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_ICMPV4) { + if (!tb2[STATS_DEST_IPV4]) { + dp_err("destination ipv4 address to track ping packets is not present"); + err = -EINVAL; + goto end; + } + arp_stats_params->icmp_ipv4 = + nla_get_u32( + tb2[STATS_DEST_IPV4]); + ucfg_dp_set_track_dest_ipv4_value(vdev, + arp_stats_params->icmp_ipv4); + } + } else { + /* clear stats command received */ + arp_stats_params->pkt_type_bitmap = pkt_bitmap; + arp_stats_params->flag = false; + pkt_type_bitmap &= + (~arp_stats_params->pkt_type_bitmap); + ucfg_dp_set_pkt_type_bitmap_value(vdev, pkt_type_bitmap); + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_ARP) { + arp_stats_params->pkt_type = + WLAN_NUD_STATS_ARP_PKT_TYPE; + ucfg_dp_clear_arp_stats(vdev); + ucfg_dp_set_track_arp_ip_value(vdev, 0); + } + + if (pkt_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + /* DNStracking isn't supported in FW. */ + arp_stats_params->pkt_type_bitmap &= + ~CONNECTIVITY_CHECK_SET_DNS; + ucfg_dp_clear_dns_stats(vdev); + ucfg_dp_clear_dns_payload_value(vdev); + ucfg_dp_set_track_dns_domain_len_value(vdev, 0); + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + ucfg_dp_clear_tcp_stats(vdev); + ucfg_dp_set_track_src_port_value(vdev, + 0); + ucfg_dp_set_track_dest_port_value(vdev, + 0); + } + + if (pkt_bitmap & + CONNECTIVITY_CHECK_SET_ICMPV4) { + ucfg_dp_clear_icmpv4_stats(vdev); + ucfg_dp_set_track_dest_ipv4_value(vdev, + 0); + } + } + } else { + dp_err("stats list empty"); + err = -EINVAL; + goto end; + } + } + +end: + return err; +} + +/** + * osif_dp_populate_dns_stats_info() - populate dns stats info + * @vdev: vdev context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int osif_dp_populate_dns_stats_info(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb) +{ + uint8_t *dns_query; + uint32_t track_dns_domain_len; + struct dp_dns_stats *dns_stats = ucfg_dp_get_dns_stats(vdev); + + if (!dns_stats) { + dp_err("Unable to get DNS stats"); + return -EINVAL; + } + + track_dns_domain_len = ucfg_dp_get_track_dns_domain_len_value(vdev); + dns_query = qdf_mem_malloc(track_dns_domain_len + 1); + if (!dns_query) + return -EINVAL; + + ucfg_dp_get_dns_payload_value(vdev, dns_query); + + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_DNS) || + nla_put(skb, CHECK_STATS_PKT_DNS_DOMAIN_NAME, + track_dns_domain_len, + dp_dns_unmake_name_query(dns_query)) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + dns_stats->tx_dns_req_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + dns_stats->tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + dns_stats->tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + dns_stats->tx_ack_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + dns_stats->rx_dns_rsp_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + dns_stats->rx_delivered) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + dns_stats->rx_host_drop)) { + dp_err("nla put fail"); + qdf_mem_free(dns_query); + kfree_skb(skb); + return -EINVAL; + } + qdf_mem_free(dns_query); + return 0; +} + +/** + * osif_dp_populate_tcp_stats_info() - populate tcp stats info + * @vdev: pointer to vdev context + * @skb: pointer to skb + * @pkt_type: tcp pkt type + * + * Return: An error code or 0 on success. + */ +static int osif_dp_populate_tcp_stats_info(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + uint8_t pkt_type) +{ + uint32_t track_src_port = ucfg_dp_get_track_src_port_value(vdev); + uint32_t track_dest_port = ucfg_dp_get_track_dest_port_value(vdev); + struct dp_tcp_stats *tcp_stats = ucfg_dp_get_tcp_stats(vdev); + + if (!tcp_stats) { + dp_err("Unable to get TCP stats"); + return -EINVAL; + } + + switch (pkt_type) { + case CONNECTIVITY_CHECK_SET_TCP_SYN: + /* Fill info for tcp syn packets (tx packet) */ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_TCP_SYN) || + nla_put_u16(skb, CHECK_STATS_PKT_SRC_PORT, + track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + tcp_stats->tx_tcp_syn_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + tcp_stats->tx_tcp_syn_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + tcp_stats->tx_tcp_syn_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + tcp_stats->tx_tcp_syn_ack_cnt)) { + dp_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + case CONNECTIVITY_CHECK_SET_TCP_SYN_ACK: + /* Fill info for tcp syn-ack packets (rx packet) */ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_TCP_SYN_ACK) || + nla_put_u16(skb, CHECK_STATS_PKT_SRC_PORT, + track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC, + tcp_stats->rx_fw_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + tcp_stats->rx_tcp_syn_ack_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + tcp_stats->rx_delivered) || + nla_put_u16(skb, + CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + tcp_stats->rx_host_drop)) { + dp_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + case CONNECTIVITY_CHECK_SET_TCP_ACK: + /* Fill info for tcp ack packets (tx packet) */ + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_TCP_ACK) || + nla_put_u16(skb, CHECK_STATS_PKT_SRC_PORT, + track_src_port) || + nla_put_u16(skb, CHECK_STATS_PKT_DEST_PORT, + track_dest_port) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + tcp_stats->tx_tcp_ack_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + tcp_stats->tx_tcp_ack_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + tcp_stats->tx_tcp_ack_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + tcp_stats->tx_tcp_ack_ack_cnt)) { + dp_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + break; + default: + break; + } + return 0; +} + +/** + * osif_dp_populate_icmpv4_stats_info() - populate icmpv4 stats + * @vdev: pointer to vdev context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int osif_dp_populate_icmpv4_stats_info(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb) +{ + struct dp_icmpv4_stats *icmpv4_stats = ucfg_dp_get_icmpv4_stats(vdev); + uint32_t track_dest_ipv4 = ucfg_dp_get_track_dest_ipv4_value(vdev); + + if (!icmpv4_stats) { + dp_err("Unable to get ICMP stats"); + return -EINVAL; + } + + if (nla_put_u16(skb, CHECK_STATS_PKT_TYPE, + CONNECTIVITY_CHECK_SET_ICMPV4) || + nla_put_u32(skb, CHECK_STATS_PKT_DEST_IPV4, + track_dest_ipv4) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_FROM_NETDEV, + icmpv4_stats->tx_icmpv4_req_count) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TO_LOWER_MAC, + icmpv4_stats->tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_RX_COUNT_BY_LOWER_MAC, + icmpv4_stats->tx_host_fw_sent) || + nla_put_u16(skb, CHECK_STATS_PKT_REQ_COUNT_TX_SUCCESS, + icmpv4_stats->tx_ack_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_LOWER_MAC, + icmpv4_stats->rx_fw_cnt) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_RX_COUNT_BY_UPPER_MAC, + icmpv4_stats->rx_icmpv4_rsp_count) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_TO_NETDEV, + icmpv4_stats->rx_delivered) || + nla_put_u16(skb, CHECK_STATS_PKT_RSP_COUNT_OUT_OF_ORDER_DROP, + icmpv4_stats->rx_host_drop)) { + dp_err("nla put fail"); + kfree_skb(skb); + return -EINVAL; + } + return 0; +} + +/** + * osif_dp_populate_connectivity_check_stats_info() - Poplulate connectivity + * stats info + * @vdev: pointer to vdev context + * @skb: pointer to skb + * + * + * Return: An error code or 0 on success. + */ +static int +osif_dp_populate_connectivity_check_stats_info(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb) +{ + struct nlattr *connect_stats, *connect_info; + uint32_t count = 0; + uint32_t pkt_type_bitmap = ucfg_dp_get_pkt_type_bitmap_value(vdev); + + connect_stats = nla_nest_start(skb, DATA_PKT_STATS); + if (!connect_stats) { + dp_err("nla_nest_start failed"); + return -EINVAL; + } + + if (pkt_type_bitmap & CONNECTIVITY_CHECK_SET_DNS) { + connect_info = nla_nest_start(skb, count); + if (!connect_info) { + dp_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + + if (osif_dp_populate_dns_stats_info(vdev, skb)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + if (pkt_type_bitmap & CONNECTIVITY_CHECK_SET_TCP_HANDSHAKE) { + connect_info = nla_nest_start(skb, count); + if (!connect_info) { + dp_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (osif_dp_populate_tcp_stats_info(vdev, skb, + CONNECTIVITY_CHECK_SET_TCP_SYN)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + + connect_info = nla_nest_start(skb, count); + if (!connect_info) { + dp_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (osif_dp_populate_tcp_stats_info(vdev, skb, + CONNECTIVITY_CHECK_SET_TCP_SYN_ACK)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + + connect_info = nla_nest_start(skb, count); + if (!connect_info) { + dp_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + if (osif_dp_populate_tcp_stats_info(vdev, skb, + CONNECTIVITY_CHECK_SET_TCP_ACK)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + if (pkt_type_bitmap & CONNECTIVITY_CHECK_SET_ICMPV4) { + connect_info = nla_nest_start(skb, count); + if (!connect_info) { + dp_err("nla_nest_start failed count %u", count); + return -EINVAL; + } + + if (osif_dp_populate_icmpv4_stats_info(vdev, skb)) + goto put_attr_fail; + nla_nest_end(skb, connect_info); + count++; + } + + nla_nest_end(skb, connect_stats); + return 0; + +put_attr_fail: + dp_err("QCA_WLAN_VENDOR_ATTR put fail. count %u", count); + return -EINVAL; +} + +int osif_dp_get_nud_stats(struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + int err = 0; + struct dp_get_arp_stats_params arp_stats_params; + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + uint32_t pkt_type_bitmap = ucfg_dp_get_pkt_type_bitmap_value(vdev); + struct sk_buff *skb; + struct osif_request *request = NULL; + struct dp_arp_stats *arp_stats; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + static const struct osif_request_params params = { + .priv_size = 0, + .timeout_ms = WLAN_WAIT_TIME_NUD_STATS, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + dp_err("Request allocation failure"); + return -ENOMEM; + } + + ucfg_dp_set_nud_stats_cb(psoc, osif_request_cookie(request)); + + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + arp_stats_params.vdev_id = ucfg_dp_get_link_id(vdev); + + /* send NUD failure event only when ARP tracking is enabled. */ + if (ucfg_dp_nud_fail_data_stall_evt_enabled() && + !ucfg_dp_nud_tracking_enabled(psoc) && + (pkt_type_bitmap & CONNECTIVITY_CHECK_SET_ARP)) { + QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_ERROR, + "Data stall due to NUD failure"); + cdp_post_data_stall_event(soc, + DATA_STALL_LOG_INDICATOR_FRAMEWORK, + DATA_STALL_LOG_NUD_FAILURE, + OL_TXRX_PDEV_ID, 0XFF, + DATA_STALL_LOG_RECOVERY_TRIGGER_PDR); + } + + if (QDF_STATUS_SUCCESS != + ucfg_dp_req_get_arp_stats(psoc, &arp_stats_params)) { + dp_err("Unable to sent ARP stats request"); + err = -EINVAL; + goto exit; + } + + err = osif_request_wait_for_response(request); + if (err) { + dp_err("timedout while retrieving NUD stats"); + err = -ETIMEDOUT; + goto exit; + } + + arp_stats = ucfg_dp_get_arp_stats(vdev); + if (!arp_stats) { + dp_err("Unable to get ARP stats"); + err = -EINVAL; + goto exit; + } + + skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy, + WLAN_NUD_STATS_LEN); + if (!skb) { + dp_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed"); + err = -ENOMEM; + goto exit; + } + + if (nla_put_u16(skb, COUNT_FROM_NETDEV, + arp_stats->tx_arp_req_count) || + nla_put_u16(skb, COUNT_TO_LOWER_MAC, + arp_stats->tx_host_fw_sent) || + nla_put_u16(skb, RX_COUNT_BY_LOWER_MAC, + arp_stats->tx_host_fw_sent) || + nla_put_u16(skb, COUNT_TX_SUCCESS, + arp_stats->tx_ack_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_LOWER_MAC, + arp_stats->rx_fw_cnt) || + nla_put_u16(skb, RSP_RX_COUNT_BY_UPPER_MAC, + arp_stats->rx_arp_rsp_count) || + nla_put_u16(skb, RSP_COUNT_TO_NETDEV, + arp_stats->rx_delivered) || + nla_put_u16(skb, RSP_COUNT_OUT_OF_ORDER_DROP, + arp_stats->rx_host_drop_reorder)) { + dp_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(skb); + err = -EINVAL; + goto exit; + } + if (ucfg_dp_get_con_status_value(vdev)) + nla_put_flag(skb, AP_LINK_ACTIVE); + if (ucfg_dp_get_dad_value(vdev)) + nla_put_flag(skb, AP_LINK_DAD); + + /* ARP tracking is done above. */ + pkt_type_bitmap &= ~CONNECTIVITY_CHECK_SET_ARP; + + if (pkt_type_bitmap) { + if (osif_dp_populate_connectivity_check_stats_info(vdev, skb)) { + err = -EINVAL; + goto exit; + } + } + + wlan_cfg80211_vendor_cmd_reply(skb); +exit: + ucfg_dp_clear_nud_stats_cb(psoc); + osif_request_put(request); + return err; +} + +int osif_dp_set_nud_stats(struct wiphy *wiphy, + struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + struct nlattr *tb[STATS_SET_MAX + 1]; + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + struct dp_set_arp_stats_params arp_stats_params = {0}; + uint32_t pkt_type_bitmap = ucfg_dp_get_pkt_type_bitmap_value(vdev); + int err = 0; + + err = wlan_cfg80211_nla_parse(tb, STATS_SET_MAX, data, data_len, + dp_set_nud_stats_policy); + if (err) { + dp_err("STATS_SET_START ATTR"); + return err; + } + + if (tb[STATS_SET_START]) { + /* tracking is enabled for stats other than arp. */ + if (tb[STATS_SET_DATA_PKT_INFO]) { + err = osif_dp_set_clear_connectivity_check_stats_info( + vdev, + &arp_stats_params, tb, true); + if (err) + return -EINVAL; + + /* + * if only tracking dns, then don't send + * wmi command to FW. + */ + if (!arp_stats_params.pkt_type_bitmap) + return err; + } else { + if (!tb[STATS_GW_IPV4]) { + dp_err("STATS_SET_START CMD"); + return -EINVAL; + } + + arp_stats_params.pkt_type_bitmap = + CONNECTIVITY_CHECK_SET_ARP; + pkt_type_bitmap |= + arp_stats_params.pkt_type_bitmap; + ucfg_dp_set_pkt_type_bitmap_value(vdev, + pkt_type_bitmap); + arp_stats_params.flag = true; + arp_stats_params.ip_addr = + nla_get_u32(tb[STATS_GW_IPV4]); + ucfg_dp_set_track_arp_ip_value(vdev, + arp_stats_params.ip_addr); + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + } + } else { + /* clear stats command received. */ + if (tb[STATS_SET_DATA_PKT_INFO]) { + err = osif_dp_set_clear_connectivity_check_stats_info( + vdev, + &arp_stats_params, tb, false); + if (err) + return -EINVAL; + + /* + * if only tracking dns, then don't send + * wmi command to FW. + */ + if (!arp_stats_params.pkt_type_bitmap) + return err; + } else { + arp_stats_params.pkt_type_bitmap = + CONNECTIVITY_CHECK_SET_ARP; + pkt_type_bitmap &= (~arp_stats_params.pkt_type_bitmap); + ucfg_dp_set_pkt_type_bitmap_value(vdev, + pkt_type_bitmap); + arp_stats_params.flag = false; + ucfg_dp_clear_arp_stats(vdev); + arp_stats_params.pkt_type = WLAN_NUD_STATS_ARP_PKT_TYPE; + } + } + + dp_info("STATS_SET_START Received flag %d!", arp_stats_params.flag); + + arp_stats_params.vdev_id = ucfg_dp_get_link_id(vdev); + + if (QDF_STATUS_SUCCESS != + ucfg_dp_req_set_arp_stats(psoc, &arp_stats_params)) { + dp_err("Unable to set ARP stats!"); + return -EINVAL; + } + return err; +} + +/* + * os_if_dp_register_event_handler() - Register osif event handler + * @psoc: psoc handle + * + * Return: None + */ +static void os_if_dp_register_event_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_dp_psoc_nb_ops cb_obj = {0}; + + cb_obj.osif_dp_get_arp_stats_evt = + osif_dp_get_arp_stats_event_handler; + + ucfg_dp_register_event_handler(psoc, &cb_obj); +} + +void os_if_dp_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_dp_psoc_callbacks *cb_obj) +{ + cb_obj->osif_dp_send_tcp_param_update_event = + osif_dp_send_tcp_param_update_event; + cb_obj->os_if_dp_nud_stats_info = os_if_dp_nud_stats_info; + cb_obj->osif_dp_process_mic_error = osif_dp_process_mic_error; + os_if_dp_register_txrx_callbacks(cb_obj); + + ucfg_dp_register_hdd_callbacks(psoc, cb_obj); + os_if_dp_register_event_handler(psoc); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_local_pkt_capture.c b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_local_pkt_capture.c new file mode 100644 index 0000000000..93885f0a89 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_local_pkt_capture.c @@ -0,0 +1,399 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "qdf_types.h" +#include +#include "wlan_cfg80211.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "os_if_dp_local_pkt_capture.h" +#include "wlan_dp_ucfg_api.h" +#include "wlan_dp_main.h" +#include "cdp_txrx_mon.h" +#include "wlan_policy_mgr_api.h" +#include +#include "wlan_osif_priv.h" + +/* Short name for QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE command */ +#define SET_MONITOR_MODE_CONFIG_MAX \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MAX +#define SET_MONITOR_MODE_INVALID \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_INVALID +#define SET_MONITOR_MODE_DATA_TX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE +#define SET_MONITOR_MODE_DATA_RX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE +#define SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE +#define SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE +#define SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE +#define SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE + +/* Short name for QCA_NL80211_VENDOR_SUBCMD_GET_MONITOR_MODE command */ +#define GET_MONITOR_MODE_CONFIG_MAX \ + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_MAX +#define GET_MONITOR_MODE_INVALID \ + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_INVALID +#define GET_MONITOR_MODE_STATUS \ + QCA_WLAN_VENDOR_ATTR_GET_MONITOR_MODE_STATUS + +#define MGMT_FRAME_TYPE 0 +#define DATA_FRAME_TYPE 1 +#define CTRL_FRAME_TYPE 2 + +const struct nla_policy +set_monitor_mode_policy[SET_MONITOR_MODE_CONFIG_MAX + 1] = { + [SET_MONITOR_MODE_DATA_TX_FRAME_TYPE] = { .type = NLA_U32 }, + [SET_MONITOR_MODE_DATA_RX_FRAME_TYPE] = { .type = NLA_U32 }, + [SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE] = { .type = NLA_U32 }, + [SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE] = { .type = NLA_U32 }, + [SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE] = { .type = NLA_U32 }, + [SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE] = { .type = NLA_U32 }, +}; + +static +bool os_if_local_pkt_capture_concurrency_allowed(struct wlan_objmgr_psoc *psoc) +{ + uint32_t num_connections, sta_count; + + num_connections = policy_mgr_get_connection_count(psoc); + osif_debug("Total connections %d", num_connections); + + /* + * No connections, local packet capture is allowed + * Only 1 connection and its STA, then local packet capture is allowed + * 2+ port concurrency, local packet capture is not allowed + */ + if (!num_connections) + return true; + + if (num_connections > 1) + return false; + + sta_count = policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL); + osif_debug("sta_count %d", sta_count); + if (sta_count == 1) + return true; + + return false; +} + +bool os_if_lpc_mon_intf_creation_allowed(struct wlan_objmgr_psoc *psoc) +{ + if (ucfg_dp_is_local_pkt_capture_enabled(psoc)) { + if (policy_mgr_is_mlo_sta_present(psoc)) { + osif_err("MLO STA present, lpc interface creation not allowed"); + return false; + } + + if (!os_if_local_pkt_capture_concurrency_allowed(psoc)) { + osif_err("Concurrency check failed, lpc interface creation not allowed"); + return false; + } + } + + return true; +} + +static QDF_STATUS os_if_start_capture_allowed(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev); + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return QDF_STATUS_E_INVAL; + } + + if (!ucfg_dp_is_local_pkt_capture_enabled(psoc)) { + osif_warn("local pkt capture feature not enabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + if (mode != QDF_MONITOR_MODE) { + osif_err("Operation not permitted in mode: %d", mode); + return QDF_STATUS_E_PERM; + } + + /* + * Whether STA interface is present or not, is already checked + * while creating monitor interface + */ + + if (policy_mgr_is_mlo_sta_present(psoc)) { + osif_err("MLO STA present, start capture is not permitted"); + return QDF_STATUS_E_PERM; + } + + if (!os_if_local_pkt_capture_concurrency_allowed(psoc)) { + osif_err("Concurrency check failed, start capture not allowed"); + return QDF_STATUS_E_PERM; + } + + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS os_if_stop_capture_allowed(struct wlan_objmgr_vdev *vdev) +{ + enum QDF_OPMODE mode; + struct wlan_objmgr_psoc *psoc; + void *soc; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) + return QDF_STATUS_E_INVAL; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return QDF_STATUS_E_INVAL; + } + + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_MONITOR_MODE) { + osif_warn("Operation not permitted in mode: %d", mode); + return QDF_STATUS_E_PERM; + } + + if (!ucfg_dp_is_local_pkt_capture_enabled(psoc)) { + osif_err("local pkt capture feature not enabled"); + return QDF_STATUS_E_NOSUPPORT; + } + + if (!cdp_is_local_pkt_capture_running(soc, OL_TXRX_PDEV_ID)) { + osif_debug("local pkt capture not running, no need to stop"); + return QDF_STATUS_E_PERM; + } + + return QDF_STATUS_SUCCESS; +} + +static +QDF_STATUS os_if_dp_local_pkt_capture_start(struct wlan_objmgr_vdev *vdev, + struct nlattr **tb) +{ + QDF_STATUS status; + struct cdp_monitor_filter filter = {0}; + uint32_t pkt_type = 0, val; + void *soc; + + status = os_if_start_capture_allowed(vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto error; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) + return QDF_STATUS_E_INVAL; + + if (tb[SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE]) { + val = nla_get_u32(tb[SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE]); + + if (val != QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL) { + osif_err("Invalid value: %d Expected: %d", + val, + QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL); + status = QDF_STATUS_E_INVAL; + goto error; + } + pkt_type |= BIT(MGMT_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE]) { + val = nla_get_u32(tb[SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE]); + + if (val != QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL) { + osif_err("Invalid value: %d Expected: %d", + val, + QCA_WLAN_VENDOR_MONITOR_MGMT_FRAME_TYPE_ALL); + status = QDF_STATUS_E_INVAL; + goto error; + } + pkt_type |= BIT(MGMT_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_DATA_TX_FRAME_TYPE]) { + val = nla_get_u32(tb[SET_MONITOR_MODE_DATA_TX_FRAME_TYPE]); + + if (val != QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ALL) { + osif_err("Invalid value: %d Expected: %d", + val, + QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ALL); + status = QDF_STATUS_E_INVAL; + goto error; + } + pkt_type |= BIT(DATA_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_DATA_RX_FRAME_TYPE]) { + val = nla_get_u32(tb[SET_MONITOR_MODE_DATA_RX_FRAME_TYPE]); + + if (val != QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ALL) { + osif_err("Invalid value: %d Expected: %d", + val, + QCA_WLAN_VENDOR_MONITOR_DATA_FRAME_TYPE_ALL); + status = QDF_STATUS_E_INVAL; + goto error; + } + pkt_type |= BIT(DATA_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE]) { + val = nla_get_u32(tb[SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE]); + + if (val != QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL) { + osif_err("Invalid value: %d Expected: %d", + val, + QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL); + status = QDF_STATUS_E_INVAL; + goto error; + } + pkt_type |= BIT(CTRL_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE]) { + val = nla_get_u32(tb[SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE]); + + if (val != QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL) { + osif_err("Invalid value: %d Expected: %d", + val, + QCA_WLAN_VENDOR_MONITOR_CTRL_FRAME_TYPE_ALL); + status = QDF_STATUS_E_INVAL; + goto error; + } + pkt_type |= BIT(CTRL_FRAME_TYPE); + } + + if (pkt_type == 0) { + osif_err("Invalid config, pkt_type: %d", pkt_type); + status = QDF_STATUS_E_INVAL; + goto error; + } + osif_debug("start capture config pkt_type:0x%x", pkt_type); + + filter.mode = MON_FILTER_PASS; + filter.fp_mgmt = pkt_type & BIT(MGMT_FRAME_TYPE) ? FILTER_MGMT_ALL : 0; + filter.fp_data = pkt_type & BIT(DATA_FRAME_TYPE) ? FILTER_DATA_ALL : 0; + filter.fp_ctrl = pkt_type & BIT(CTRL_FRAME_TYPE) ? FILTER_CTRL_ALL : 0; + + status = cdp_start_local_pkt_capture(soc, OL_TXRX_PDEV_ID, &filter); + +error: + return status; +} + +QDF_STATUS os_if_dp_set_lpc_configure(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + struct nlattr *tb[SET_MONITOR_MODE_CONFIG_MAX + 1]; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (wlan_cfg80211_nla_parse(tb, SET_MONITOR_MODE_CONFIG_MAX, + data, data_len, set_monitor_mode_policy)) { + osif_err("Invalid monitor attr"); + status = QDF_STATUS_E_INVAL; + goto error; + } + + status = os_if_dp_local_pkt_capture_start(vdev, tb); + +error: + return status; +} + +QDF_STATUS os_if_dp_local_pkt_capture_stop(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status; + void *soc; + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc || !vdev) + return QDF_STATUS_E_INVAL; + + status = os_if_stop_capture_allowed(vdev); + if (QDF_IS_STATUS_ERROR(status)) + return status; + + return cdp_stop_local_pkt_capture(soc, OL_TXRX_PDEV_ID); +} + +QDF_STATUS os_if_dp_get_lpc_state(struct wlan_objmgr_vdev *vdev, + const void *data, int data_len) +{ + struct wlan_objmgr_psoc *psoc; + struct vdev_osif_priv *osif_priv; + struct sk_buff *reply_skb; + uint32_t skb_len = NLMSG_HDRLEN, val; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wireless_dev *wdev; + bool running; + void *soc; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + return QDF_STATUS_E_INVAL; + } + + soc = cds_get_context(QDF_MODULE_ID_SOC); + if (!soc) + return QDF_STATUS_E_INVAL; + + /* Length of attribute QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_STATUS */ + skb_len += nla_total_size(sizeof(u32)); + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy, + skb_len); + if (!reply_skb) { + osif_err("alloc reply skb failed"); + return QDF_STATUS_E_NOMEM; + } + + running = cdp_is_local_pkt_capture_running(soc, OL_TXRX_PDEV_ID); + val = running ? QCA_WLAN_VENDOR_MONITOR_MODE_CAPTURE_RUNNING : + QCA_WLAN_VENDOR_MONITOR_MODE_NO_CAPTURE_RUNNING; + + if (nla_put_u32(reply_skb, GET_MONITOR_MODE_STATUS, val)) { + osif_err("nla put failed"); + status = QDF_STATUS_E_INVAL; + goto fail; + } + + if (wlan_cfg80211_vendor_cmd_reply(reply_skb)) + status = QDF_STATUS_E_INVAL; + + return status; +fail: + wlan_cfg80211_vendor_free_skb(reply_skb); + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_lro.c b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_lro.c new file mode 100644 index 0000000000..277d8e2adc --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_lro.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_dp_lro.c + * This file contains DP component's LRO osif API implementation + */ +#include "os_if_dp_lro.h" +#include +#include +#include +#include +#include + +#define LRO_VALID_FIELDS \ + (LRO_DESC | LRO_ELIGIBILITY_CHECKED | LRO_TCP_ACK_NUM | \ + LRO_TCP_DATA_CSUM | LRO_TCP_SEQ_NUM | LRO_TCP_WIN) + +#if defined(QCA_WIFI_QCA6290) || defined(QCA_WIFI_QCA6390) || \ + defined(QCA_WIFI_QCA6490) || defined(QCA_WIFI_QCA6750) || \ + defined(QCA_WIFI_KIWI) || defined(QCA_WIFI_WCN6450) +#ifdef WLAN_FEATURE_LRO_CTX_IN_CB +static qdf_lro_ctx_t osif_dp_get_lro_ctx(struct sk_buff *skb) +{ + return (qdf_lro_ctx_t)QDF_NBUF_CB_RX_LRO_CTX(skb); +} +#else +static qdf_lro_ctx_t osif_dp_get_lro_ctx(struct sk_buff *skb) +{ + struct hif_opaque_softc *hif_hdl = + (struct hif_opaque_softc *)cds_get_context(QDF_MODULE_ID_HIF); + if (!hif_hdl) + return NULL; + + return hif_get_lro_info(QDF_NBUF_CB_RX_CTX_ID(skb), hif_hdl); +} +#endif + +/** + * osif_dp_lro_rx() - LRO receive function + * @dev: netdev + * @nbuf: network buffer + * + * Delivers LRO eligible frames to the LRO manager + * + * Return: QDF_STATUS_SUCCESS - frame delivered to LRO manager + * QDF_STATUS_E_FAILURE - frame not delivered + */ +QDF_STATUS osif_dp_lro_rx(qdf_netdev_t dev, qdf_nbuf_t nbuf) +{ + qdf_lro_ctx_t ctx; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + struct qdf_lro_info info; + struct net_lro_desc *lro_desc = NULL; + struct sk_buff * skb = (struct sk_buff *)nbuf; + + if ((dev->features & NETIF_F_LRO) != NETIF_F_LRO) + return QDF_STATUS_E_NOSUPPORT; + + ctx = osif_dp_get_lro_ctx(skb); + if (!ctx) { + osif_err("LRO mgr is NULL"); + return status; + } + + info.iph = skb->data; + info.tcph = skb->data + QDF_NBUF_CB_RX_TCP_OFFSET(skb); + ctx->lro_mgr->dev = dev; + if (qdf_lro_get_info(ctx, skb, &info, (void **)&lro_desc)) { + struct net_lro_info dp_lro_info; + + dp_lro_info.valid_fields = LRO_VALID_FIELDS; + + dp_lro_info.lro_desc = lro_desc; + dp_lro_info.lro_eligible = 1; + dp_lro_info.tcp_ack_num = QDF_NBUF_CB_RX_TCP_ACK_NUM(skb); + dp_lro_info.tcp_data_csum = + csum_unfold(htons(QDF_NBUF_CB_RX_TCP_CHKSUM(skb))); + dp_lro_info.tcp_seq_num = QDF_NBUF_CB_RX_TCP_SEQ_NUM(skb); + dp_lro_info.tcp_win = QDF_NBUF_CB_RX_TCP_WIN(skb); + + lro_receive_skb_ext(ctx->lro_mgr, skb, NULL, + &dp_lro_info); + + if (!dp_lro_info.lro_desc->active) + qdf_lro_desc_free(ctx, lro_desc); + + status = QDF_STATUS_SUCCESS; + } else { + qdf_lro_flush_pkt(ctx, &info); + } + return status; +} + +/** + * osif_dp_lro_display_stats() - display LRO statistics + * @vdev: vdev objmgr context + * + * Return: none + */ +void osif_dp_lro_display_stats(struct wlan_vdev_objmgr *vdev) +{ + osif_debug("LRO stats is broken, will fix it"); +} + +QDF_STATUS +osif_dp_lro_set_reset(struct wlan_vdev_objmgr *vdev, uint8_t enable_flag) +{ + struct vdev_osif_priv *osif_priv; + struct net_device *dev; + QDF_STATUS status; + + osif_priv = wlan_vdev_get_ospriv(vdev); + dev = osif_priv->wdev->netdev; + + status = ucfg_dp_lro_set_reset(vdev, enable_flag); + if (QDF_IS_STATUS_ERROR(status)) + return 0; + + if (enable_flag) + dev->features |= NETIF_F_LRO; + else + dev->features &= ~NETIF_F_LRO; + + return 0; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_txrx.c b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_txrx.c new file mode 100644 index 0000000000..8c1ebda312 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/dp/src/os_if_dp_txrx.c @@ -0,0 +1,643 @@ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_dp_txrx.c + * This file contains DP component's TX/RX osif API implementation + */ +#include "os_if_dp.h" +#include "os_if_dp_lro.h" +#include +#include +#include "osif_sync.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_wmm.h" + +/** + * osif_dp_classify_pkt() - classify packet + * @skb: sk buff + * + * Return: none + */ +void osif_dp_classify_pkt(struct sk_buff *skb) +{ + struct ethhdr *eh = (struct ethhdr *)skb->data; + + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + + /* check destination mac address is broadcast/multicast */ + if (is_broadcast_ether_addr((uint8_t *)eh)) + QDF_NBUF_CB_GET_IS_BCAST(skb) = true; + else if (is_multicast_ether_addr((uint8_t *)eh)) + QDF_NBUF_CB_GET_IS_MCAST(skb) = true; + + if (qdf_nbuf_is_ipv4_arp_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ARP; + else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_DHCP; + else if (qdf_nbuf_is_ipv4_eapol_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_EAPOL; + else if (qdf_nbuf_is_ipv4_wapi_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_WAPI; + else if (qdf_nbuf_is_icmp_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ICMP; + else if (qdf_nbuf_is_icmpv6_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ICMPv6; +} + +/** + * osif_dp_mark_critical_pkt() - Identify and mark critical packets + * @skb: skb ptr + * + * Return: None + */ +static void osif_dp_mark_critical_pkt(struct sk_buff *skb) +{ + if (qdf_nbuf_is_ipv4_eapol_pkt(skb)) { + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_EAPOL; + } else if (qdf_nbuf_is_ipv4_arp_pkt(skb)) { + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ARP; + } else if (qdf_nbuf_is_ipv4_dhcp_pkt(skb)) { + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_DHCP; + } else if (qdf_nbuf_is_ipv6_dhcp_pkt(skb)) { + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_DHCPV6; + } else if (qdf_nbuf_is_icmpv6_pkt(skb)) { + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ICMPv6; + } + + QDF_NBUF_CB_TX_EXTRA_IS_CRITICAL(skb) = true; +} + +#ifdef DP_TX_PACKET_INSPECT_FOR_ILP +/** + * osif_dp_mark_pkt_type_by_priority() - mark packet type to skb->cb + * by type from priority of skb + * @skb: network buffer + * + * Return: true - packet type marked, false - not marked + */ +static inline +bool osif_dp_mark_pkt_type_by_priority(struct sk_buff *skb) +{ + bool type_marked = false; + uint32_t pkt_type = + qdf_nbuf_get_priority_pkt_type(skb); + + if (qdf_unlikely(pkt_type == QDF_NBUF_PRIORITY_PKT_TCP_ACK)) { + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_TCP_ACK; + type_marked = true; + } + /* cleanup the packet type in priority */ + qdf_nbuf_remove_priority_pkt_type(skb); + + return type_marked; +} +#else +static inline +bool osif_dp_mark_pkt_type_by_priority(struct sk_buff *skb) +{ + return false; +} +#endif + +/** + * osif_dp_mark_non_critical_pkt() - Identify and mark non-critical packets + * @skb: skb ptr + * + * Return: None + */ +static void osif_dp_mark_non_critical_pkt(struct sk_buff *skb) +{ + /* check if packet type is marked from skb->priority already */ + if (osif_dp_mark_pkt_type_by_priority(skb)) + return; + + if (qdf_nbuf_is_icmp_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_ICMP; + else if (qdf_nbuf_is_ipv4_wapi_pkt(skb)) + QDF_NBUF_CB_GET_PACKET_TYPE(skb) = + QDF_NBUF_CB_PACKET_TYPE_WAPI; +} + +void osif_dp_mark_pkt_type(struct sk_buff *skb) +{ + struct ethhdr *eh = (struct ethhdr *)skb->data; + + /* + * Zero out CB before accessing it. Expectation is that cb is accessed + * for the first time here on TX path in hard_start_xmit. + */ + qdf_mem_zero(skb->cb, sizeof(skb->cb)); + + /* check destination mac address is broadcast/multicast */ + if (is_broadcast_ether_addr((uint8_t *)eh)) + QDF_NBUF_CB_GET_IS_BCAST(skb) = true; + else if (is_multicast_ether_addr((uint8_t *)eh)) + QDF_NBUF_CB_GET_IS_MCAST(skb) = true; + + /* + * TX Packets in the HI_PRIO queue are assumed to be critical and + * marked accordingly. + */ + if (skb->queue_mapping == TX_GET_QUEUE_IDX(HDD_LINUX_AC_HI_PRIO, 0)) + osif_dp_mark_critical_pkt(skb); + else + osif_dp_mark_non_critical_pkt(skb); +} + +/* + * When bus bandwidth is idle, if RX data is delivered with + * napi_gro_receive, to reduce RX delay related with GRO, + * check gro_result returned from napi_gro_receive to determine + * is extra GRO flush still necessary. + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +#define DP_IS_EXTRA_GRO_FLUSH_NECESSARY(_gro_ret) true +#define GRO_DROP_UPDATE_STATUS(gro_ret, status) +#else +#define GRO_DROP_UPDATE_STATUS(gro_ret, status) \ + if ((gro_ret) == GRO_DROP) ((status) = QDF_STATUS_E_GRO_DROP) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +#define DP_IS_EXTRA_GRO_FLUSH_NECESSARY(_gro_ret) \ + ((_gro_ret) != GRO_DROP) +#else +#define DP_IS_EXTRA_GRO_FLUSH_NECESSARY(_gro_ret) \ + ((_gro_ret) != GRO_DROP && (_gro_ret) != GRO_NORMAL) +#endif +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +/** + * osif_dp_rx_thread_napi_gro_flush() - do gro flush + * @napi: napi used to do gro flush + * @flush_code: flush_code differentiating low_tput_flush and normal_flush + * + * if there is RX GRO_NORMAL packets pending in napi + * rx_list, flush them manually right after napi_gro_flush. + * + * Return: none + */ +static inline +void osif_dp_rx_thread_napi_gro_flush(struct napi_struct *napi, + enum dp_rx_gro_flush_code flush_code) +{ + if (napi->poll) { + /* Skipping GRO flush in low TPUT */ + if (flush_code != DP_RX_GRO_LOW_TPUT_FLUSH) + napi_gro_flush(napi, false); + + if (napi->rx_count) { + netif_receive_skb_list(&napi->rx_list); + qdf_init_list_head(&napi->rx_list); + napi->rx_count = 0; + } + } +} +#else +static inline +void osif_dp_rx_thread_napi_gro_flush(struct napi_struct *napi, + enum dp_rx_gro_flush_code flush_code) +{ + if (napi->poll) { + /* Skipping GRO flush in low TPUT */ + if (flush_code != DP_RX_GRO_LOW_TPUT_FLUSH) + napi_gro_flush(napi, false); + } +} +#endif + +/** + * osif_dp_rx_napi_gro_flush() - GRO RX/flush function. + * @napi_to_use: napi to be used to give packets to the stack, gro flush + * @nbuf: pointer to n/w buff + * @low_tput_force_flush: Is force flush required in low tput + * + * Function calls napi_gro_receive for the skb. If the skb indicates that a + * flush needs to be done (set by the lower DP layer), the function also calls + * napi_gro_flush. Local softirqs are disabled (and later enabled) while making + * napi_gro__ calls. + * + * Return: QDF_STATUS_SUCCESS if not dropped by napi_gro_receive or + * QDF error code. + */ + +static QDF_STATUS +osif_dp_rx_napi_gro_flush(qdf_napi_struct *napi_to_use, + qdf_nbuf_t nbuf, + uint8_t *low_tput_force_flush) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + gro_result_t gro_ret; + + skb_set_hash(nbuf, QDF_NBUF_CB_RX_FLOW_ID(nbuf), PKT_HASH_TYPE_L4); + + local_bh_disable(); + gro_ret = napi_gro_receive((struct napi_struct *)napi_to_use, nbuf); + + if (DP_IS_EXTRA_GRO_FLUSH_NECESSARY(gro_ret)) { + *low_tput_force_flush = 1; + osif_dp_rx_thread_napi_gro_flush((struct napi_struct *)napi_to_use, + DP_RX_GRO_NORMAL_FLUSH); + } + + local_bh_enable(); + GRO_DROP_UPDATE_STATUS(gro_ret, status); + + return status; +} + +/** + * osif_dp_rx_napi_gro_receive() - GRO RX receive function. + * @napi_to_use: napi to be used to give packets to the stack + * @nbuf: pointer to n/w buff + * + * Function calls napi_gro_receive for the skb. + * napi_gro_flush. Local softirqs are disabled (and later enabled) while making + * napi_gro__ calls. + * + * Return: QDF_STATUS_SUCCESS if not dropped by napi_gro_receive or + * QDF error code. + */ +static QDF_STATUS +osif_dp_rx_napi_gro_receive(qdf_napi_struct *napi_to_use, + qdf_nbuf_t nbuf) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + gro_result_t gro_ret; + + skb_set_hash(nbuf, QDF_NBUF_CB_RX_FLOW_ID(nbuf), PKT_HASH_TYPE_L4); + + local_bh_disable(); + gro_ret = napi_gro_receive((struct napi_struct *)napi_to_use, nbuf); + + local_bh_enable(); + GRO_DROP_UPDATE_STATUS(gro_ret, status); + + return status; +} + +#ifdef RECEIVE_OFFLOAD +/** + * osif_dp_rxthread_napi_normal_gro_flush() - GRO flush cbk for NAPI+Rx_Thread + * Rx mode + * @data: hif NAPI context + * + * Return: none + */ +static void osif_dp_rxthread_napi_normal_gro_flush(void *data) +{ + struct qca_napi_info *qca_napi = (struct qca_napi_info *)data; + + local_bh_disable(); + /* + * As we are breaking context in Rxthread mode, there is rx_thread NAPI + * corresponds each hif_napi. + */ + osif_dp_rx_thread_napi_gro_flush(&qca_napi->rx_thread_napi, + DP_RX_GRO_NORMAL_FLUSH); + local_bh_enable(); +} + +/** + * osif_dp_hif_napi_gro_flush() - GRO flush callback for NAPI Rx mode + * @data: hif NAPI context + * + * Return: none + */ +static void osif_dp_hif_napi_gro_flush(void *data) +{ + struct qca_napi_info *qca_napi = (struct qca_napi_info *)data; + + local_bh_disable(); + napi_gro_flush(&qca_napi->napi, false); + local_bh_enable(); +} +#endif + +#ifdef FEATURE_LRO +/** + * osif_dp_qdf_lro_flush() - LRO flush wrapper + * @data: hif NAPI context + * + * Return: none + */ +static void osif_dp_qdf_lro_flush(void *data) +{ + struct qca_napi_info *qca_napii = (struct qca_napi_info *)data; + qdf_lro_ctx_t qdf_lro_ctx = qca_napii->lro_ctx; + + qdf_lro_flush(qdf_lro_ctx); +} +#elif defined(RECEIVE_OFFLOAD) +static void osif_dp_qdf_lro_flush(void *data) +{ +} +#endif + +#ifdef WLAN_FEATURE_DYNAMIC_RX_AGGREGATION +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) +static enum qdisc_filter_status +__osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block, + uint32_t prio) +{ + struct tcf_chain *chain; + struct tcf_proto *tp; + struct tcf_proto *tp_next; + enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH; + + mutex_lock(&block->lock); + list_for_each_entry(chain, &block->chain_list, list) { + mutex_lock(&chain->filter_chain_lock); + tp = tcf_chain_dereference(chain->filter_chain, chain); + while (tp) { + tp_next = rtnl_dereference(tp->next); + if (tp->prio == (prio << 16)) { + ret = QDISC_FILTER_PRIO_MATCH; + break; + } + tp = tp_next; + } + mutex_unlock(&chain->filter_chain_lock); + + if (ret == QDISC_FILTER_PRIO_MATCH) + break; + } + mutex_unlock(&block->lock); + + return ret; +} +#else +static enum qdisc_filter_status +__osif_check_for_prio_filter_in_clsact_qdisc(struct tcf_block *block, + uint32_t prio) +{ + struct tcf_chain *chain; + struct tcf_proto *tp; + enum qdisc_filter_status ret = QDISC_FILTER_PRIO_MISMATCH; + + if (!rtnl_trylock()) + return QDISC_FILTER_RTNL_LOCK_FAIL; + + list_for_each_entry(chain, &block->chain_list, list) { + for (tp = rtnl_dereference(chain->filter_chain); tp; + tp = rtnl_dereference(tp->next)) { + if (tp->prio == (prio << 16)) + ret = QDISC_FILTER_PRIO_MATCH; + } + } + rtnl_unlock(); + + return ret; +} +#endif + +/** + * osif_check_for_prio_filter_in_clsact_qdisc() - Check if priority 3 filter + * is configured in the ingress clsact qdisc + * @qdisc: pointer to clsact qdisc + * @prio: traffic priority + * + * Return: qdisc filter status + */ +static enum qdisc_filter_status +osif_check_for_prio_filter_in_clsact_qdisc(struct Qdisc *qdisc, uint32_t prio) +{ + const struct Qdisc_class_ops *cops; + struct tcf_block *ingress_block; + + cops = qdisc->ops->cl_ops; + if (qdf_unlikely(!cops || !cops->tcf_block)) + return QDISC_FILTER_PRIO_MISMATCH; + + ingress_block = cops->tcf_block(qdisc, TC_H_MIN_INGRESS, NULL); + if (qdf_unlikely(!ingress_block)) + return QDISC_FILTER_PRIO_MISMATCH; + + return __osif_check_for_prio_filter_in_clsact_qdisc(ingress_block, + prio); +} + +/** + * osif_dp_rx_check_qdisc_configured() - Check if any ingress qdisc + * configured for given netdev + * @ndev: pointer to netdev + * @prio: traffic priority + * + * The function checks if ingress qdisc is registered for a given + * net device. + * + * Return: None + */ +static QDF_STATUS +osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint32_t prio) +{ + struct netdev_queue *ingress_q; + struct Qdisc *ingress_qdisc; + struct net_device *dev = (struct net_device *)ndev; + bool disable_gro = false; + enum qdisc_filter_status status; + + if (!dev->ingress_queue) + goto reset_wl; + + if (!rtnl_trylock()) + return QDF_STATUS_E_AGAIN; + + ingress_q = rtnl_dereference(dev->ingress_queue); + if (qdf_unlikely(!ingress_q)) + goto reset; + + ingress_qdisc = rtnl_dereference(ingress_q->qdisc); + if (qdf_unlikely(!ingress_qdisc)) + goto reset; + + if (qdf_str_eq(ingress_qdisc->ops->id, "ingress")) { + disable_gro = true; + } else if (qdf_str_eq(ingress_qdisc->ops->id, "clsact")) { + status = osif_check_for_prio_filter_in_clsact_qdisc( + ingress_qdisc, + prio); + + if (status == QDISC_FILTER_PRIO_MISMATCH) + goto reset; + + disable_gro = true; + } + + if (disable_gro) { + rtnl_unlock(); + return QDF_STATUS_SUCCESS; + } + +reset: + rtnl_unlock(); + +reset_wl: + return QDF_STATUS_E_NOSUPPORT; +} + +#else +static QDF_STATUS +osif_dp_rx_check_qdisc_configured(qdf_netdev_t ndev, uint32_t prio) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 6, 0)) +static void +osif_dp_register_arp_unsolicited_cbk(struct wlan_dp_psoc_callbacks *cb_obj) +{ + cb_obj->dp_is_gratuitous_arp_unsolicited_na = NULL; +} +#else +static bool osif_dp_is_gratuitous_arp_unsolicited_na(qdf_nbuf_t nbuf) +{ + return cfg80211_is_gratuitous_arp_unsolicited_na((struct sk_buff *)nbuf); +} + +static void +osif_dp_register_arp_unsolicited_cbk(struct wlan_dp_psoc_callbacks *cb_obj) +{ + cb_obj->dp_is_gratuitous_arp_unsolicited_na = + osif_dp_is_gratuitous_arp_unsolicited_na; +} +#endif + +#if defined(CFG80211_CTRL_FRAME_SRC_ADDR_TA_ADDR) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 41)) +static +bool osif_dp_cfg80211_rx_control_port(qdf_netdev_t dev, u8 *ta_addr, + qdf_nbuf_t nbuf, bool unencrypted) +{ + return cfg80211_rx_control_port((struct net_device *)dev, + (struct sk_buff *)nbuf, + unencrypted, -1); +} + +#else +static +bool osif_dp_cfg80211_rx_control_port(qdf_netdev_t dev, u8 *ta_addr, + qdf_nbuf_t nbuf, bool unencrypted) +{ + return cfg80211_rx_control_port((struct net_device *)dev, + ta_addr, (struct sk_buff *)nbuf, + unencrypted); +} +#endif + +static void +osif_dp_register_send_rx_pkt_over_nl(struct wlan_dp_psoc_callbacks *cb_obj) +{ + cb_obj->dp_send_rx_pkt_over_nl = osif_dp_cfg80211_rx_control_port; +} + +#else +static void +osif_dp_register_send_rx_pkt_over_nl(struct wlan_dp_psoc_callbacks *cb_obj) +{ + cb_obj->dp_send_rx_pkt_over_nl = NULL; +} +#endif + +#ifdef RECEIVE_OFFLOAD +static +void osif_dp_register_rx_offld_flush_cb(enum dp_rx_offld_flush_cb cb_type) +{ + void *soc = cds_get_context(QDF_MODULE_ID_SOC); + + if (cb_type == DP_RX_FLUSH_LRO) + cdp_register_rx_offld_flush_cb(soc, osif_dp_qdf_lro_flush); + else if (cb_type == DP_RX_FLUSH_THREAD) + cdp_register_rx_offld_flush_cb(soc, + osif_dp_rxthread_napi_normal_gro_flush); + else if (cb_type == DP_RX_FLUSH_NAPI) + cdp_register_rx_offld_flush_cb(soc, + osif_dp_hif_napi_gro_flush); +} +#else + +static +void osif_dp_register_rx_offld_flush_cb(enum dp_rx_offld_flush_cb cb_type) { } +#endif + +static +QDF_STATUS osif_dp_rx_pkt_to_nw(qdf_nbuf_t nbuf, enum dp_nbuf_push_type type) +{ + int netif_status; + + if (type == DP_NBUF_PUSH_BH_DISABLE) { + local_bh_disable(); + netif_status = netif_receive_skb(nbuf); + local_bh_enable(); + } else if (type == DP_NBUF_PUSH_NI) { + netif_status = netif_rx_ni(nbuf); + } else if (type == DP_NBUF_PUSH_NAPI) { + netif_status = netif_receive_skb(nbuf); + } else { + netif_status = netif_rx(nbuf); + } + + if (qdf_likely(netif_status == NET_RX_SUCCESS)) + return QDF_STATUS_SUCCESS; + + return QDF_STATUS_E_FAILURE; +} + +void os_if_dp_register_txrx_callbacks(struct wlan_dp_psoc_callbacks *cb_obj) +{ + cb_obj->dp_nbuf_push_pkt = osif_dp_rx_pkt_to_nw; + cb_obj->dp_rx_napi_gro_flush = osif_dp_rx_napi_gro_flush; + cb_obj->dp_rx_napi_gro_receive = osif_dp_rx_napi_gro_receive; + cb_obj->dp_rx_thread_napi_gro_flush = osif_dp_rx_thread_napi_gro_flush; + cb_obj->dp_lro_rx_cb = osif_dp_lro_rx; + cb_obj->dp_register_rx_offld_flush_cb = + osif_dp_register_rx_offld_flush_cb; + cb_obj->dp_rx_check_qdisc_configured = + osif_dp_rx_check_qdisc_configured; + + osif_dp_register_arp_unsolicited_cbk(cb_obj); + + osif_dp_register_send_rx_pkt_over_nl(cb_obj); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/fw_offload/inc/os_if_fwol.h b/qcom/opensource/wlan/qcacld-3.0/os_if/fw_offload/inc/os_if_fwol.h new file mode 100644 index 0000000000..07276d9472 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/fw_offload/inc/os_if_fwol.h @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: os_if_fwol.h + * + * This Header file provide declaration for OS interface API + */ + +#ifndef __OS_IF_FWOL_H__ +#define __OS_IF_FWOL_H__ + +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_fwol_public_structs.h" + +#ifdef WLAN_FEATURE_ELNA +/** + * os_if_fwol_set_elna_bypass() - Set eLNA bypass + * @vdev: Pointer to vdev + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + const struct nlattr *attr); + +/** + * os_if_fwol_get_elna_bypass() - Get eLNA bypass + * @vdev: Pointer to vdev + * @skb: sk buffer to hold nl80211 attributes + * @attr: Pointer to struct nlattr + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + const struct nlattr *attr); +#else +static inline int os_if_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + const struct nlattr *attr) +{ + return 0; +} + +static inline int os_if_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + const struct nlattr *attr) +{ + return 0; +} +#endif /* WLAN_FEATURE_ELNA */ + +#ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW +/** + * os_if_fwol_send_dscp_up_map_to_fw() - Send DSCP to UP map to FW + * @vdev: Pointer to vdev + * @dscp_to_up_map: Array of DSCP to UP map values + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_send_dscp_up_map_to_fw(struct wlan_objmgr_vdev *vdev, + uint32_t *dscp_to_up_map); +#else +static inline int os_if_fwol_send_dscp_up_map_to_fw( + struct wlan_objmgr_vdev *vdev, uint32_t *dscp_to_up_map) +{ + return -EOPNOTSUPP; +} +#endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */ + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD +/** + * os_if_fwol_enable_mdns_offload() - Enable mdns offload + * @psoc: Pointer to psoc object + * @mdns_info: MDNS offload information + * + * This function will offload mdns response to FW. + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_enable_mdns_offload(struct wlan_objmgr_psoc *psoc, + struct mdns_config_info *mdns_info); + +/** + * os_if_fwol_disable_mdns_offload() - Disable mdns offload + * @psoc: Pointer to psoc + * + * This function will disable the mdns offload feature. + * + * Return: 0 on success; error number otherwise + */ +int os_if_fwol_disable_mdns_offload(struct wlan_objmgr_psoc *psoc); +#else +static inline int os_if_fwol_enable_mdns_offload(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} + +static inline int os_if_fwol_disable_mdns_offload(struct wlan_objmgr_psoc *psoc) +{ + return 0; +} +#endif /* WLAN_FEATURE_MDNS_OFFLOAD */ + +#ifdef THERMAL_STATS_SUPPORT +int os_if_fwol_get_thermal_stats_req(struct wlan_objmgr_psoc *psoc, + enum thermal_stats_request_type req, + void (*callback)(void *context, + struct thermal_throttle_info *response), + void *context); +#endif /* THERMAL_STATS_SUPPORT */ + +#endif /* __OS_IF_FWOL_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/fw_offload/src/os_if_fwol.c b/qcom/opensource/wlan/qcacld-3.0/os_if/fw_offload/src/os_if_fwol.c new file mode 100644 index 0000000000..3231954e16 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/fw_offload/src/os_if_fwol.c @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ + +#include "wlan_cfg80211.h" +#include "wlan_osif_request_manager.h" +#include "wlan_fwol_ucfg_api.h" +#include "os_if_fwol.h" + +#ifdef WLAN_FEATURE_ELNA +#define WLAN_WAIT_TIME_GET_ELNA_BYPASS 1500 + +int os_if_fwol_set_elna_bypass(struct wlan_objmgr_vdev *vdev, + const struct nlattr *attr) +{ + struct set_elna_bypass_request req; + QDF_STATUS status; + + req.vdev_id = vdev->vdev_objmgr.vdev_id; + req.elna_mode = nla_get_u8(attr); + if (req.elna_mode > EXTLNA_MODE_FIRMWARE_DEFAULT) { + osif_err("Invalid elna_bypass value %d", req.elna_mode); + return -EINVAL; + } + + status = ucfg_fwol_set_elna_bypass(vdev, &req); + if (!QDF_IS_STATUS_SUCCESS(status)) + osif_err("Failed to set ELNA BYPASS, %d", status); + + return qdf_status_to_os_return(status); +} + +struct osif_get_elna_bypass_priv { + enum fwol_extlna_mode elna_mode; +}; + +/** + * os_if_fwol_get_elna_bypass_callback() - Get eLNA bypass callback + * @context: Call context + * @response: Pointer to response structure + * + * Return: void + */ +static void +os_if_fwol_get_elna_bypass_callback(void *context, + struct get_elna_bypass_response *response) +{ + struct osif_request *request; + struct osif_get_elna_bypass_priv *priv; + + request = osif_request_get(context); + if (!request) { + osif_err("Obsolete request"); + return; + } + + priv = osif_request_priv(request); + priv->elna_mode = response->elna_mode; + + osif_request_complete(request); + osif_request_put(request); +} + +int os_if_fwol_get_elna_bypass(struct wlan_objmgr_vdev *vdev, + struct sk_buff *skb, + const struct nlattr *attr) +{ + struct get_elna_bypass_request req; + void *cookie; + struct osif_request *request; + struct osif_get_elna_bypass_priv *priv; + static const struct osif_request_params params = { + .priv_size = sizeof(*priv), + .timeout_ms = WLAN_WAIT_TIME_GET_ELNA_BYPASS, + }; + QDF_STATUS status; + int ret = 0; + + req.vdev_id = vdev->vdev_objmgr.vdev_id; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + cookie = osif_request_cookie(request); + + status = ucfg_fwol_get_elna_bypass(vdev, &req, + os_if_fwol_get_elna_bypass_callback, + cookie); + if (!QDF_IS_STATUS_SUCCESS(status)) { + osif_err("Failed to get ELNA BYPASS, %d", status); + ret = qdf_status_to_os_return(status); + goto end; + } + + ret = osif_request_wait_for_response(request); + if (ret) { + osif_err("Operation timed out"); + goto end; + } + + priv = osif_request_priv(request); + if (nla_put_u8(skb, QCA_WLAN_VENDOR_ATTR_CONFIG_ELNA_BYPASS, + priv->elna_mode)) { + osif_err("put fail with elna_mode:%d", priv->elna_mode); + ret = -EINVAL; + } + +end: + osif_request_put(request); + return ret; +} +#endif /* #ifdef WLAN_FEATURE_ELNA */ + +#ifdef WLAN_SEND_DSCP_UP_MAP_TO_FW +int os_if_fwol_send_dscp_up_map_to_fw(struct wlan_objmgr_vdev *vdev, + uint32_t *dscp_to_up_map) +{ + QDF_STATUS status; + + status = ucfg_fwol_send_dscp_up_map_to_fw(vdev, dscp_to_up_map); + if (!QDF_IS_STATUS_SUCCESS(status)) + osif_err("Failed to send dscp_up_map to FW, %d", status); + + return qdf_status_to_os_return(status); +} +#endif + +#ifdef WLAN_FEATURE_MDNS_OFFLOAD +int os_if_fwol_enable_mdns_offload(struct wlan_objmgr_psoc *psoc, + struct mdns_config_info *mdns_info) +{ + int ret = 0; + QDF_STATUS status; + + if (!psoc) { + osif_err("Null pointer for psoc"); + return -EINVAL; + } + + if (!mdns_info) { + osif_err("Invalid mDNS config"); + return -EINVAL; + } + + status = ucfg_fwol_set_mdns_config(psoc, mdns_info); + if (!QDF_IS_STATUS_SUCCESS(status)) { + osif_err("Failed to set mDNS Config"); + ret = qdf_status_to_os_return(status); + } + + return ret; +} + +int os_if_fwol_disable_mdns_offload(struct wlan_objmgr_psoc *psoc) +{ + struct mdns_config_info *mdns_info = NULL; + int ret = 0; + QDF_STATUS status; + + if (!psoc) { + osif_err("Null pointer for psoc"); + return -EINVAL; + } + + mdns_info = qdf_mem_malloc(sizeof(*mdns_info)); + if (!mdns_info) { + ret = -ENOMEM; + goto out; + } + + mdns_info->enable = false; + status = ucfg_fwol_set_mdns_config(psoc, mdns_info); + if (!QDF_IS_STATUS_SUCCESS(status)) + osif_err("Failed to set mDNS Config"); + ret = qdf_status_to_os_return(status); +out: + qdf_mem_free(mdns_info); + return ret; +} +#endif /* WLAN_FEATURE_MDNS_OFFLOAD */ + +#ifdef THERMAL_STATS_SUPPORT +int os_if_fwol_get_thermal_stats_req(struct wlan_objmgr_psoc *psoc, + enum thermal_stats_request_type req, + void (*callback)(void *context, + struct thermal_throttle_info *response), + void *context) +{ + QDF_STATUS status; + + + status = ucfg_fwol_send_get_thermal_stats_cmd(psoc, req, callback, + context); + if (!QDF_IS_STATUS_SUCCESS(status)) + osif_err("Failed to send get thermal stats cmd to FW, %d", + status); + + return qdf_status_to_os_return(status); +} +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/interop_issues_ap/inc/wlan_cfg80211_interop_issues_ap.h b/qcom/opensource/wlan/qcacld-3.0/os_if/interop_issues_ap/inc/wlan_cfg80211_interop_issues_ap.h new file mode 100644 index 0000000000..bb2215e3de --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/interop_issues_ap/inc/wlan_cfg80211_interop_issues_ap.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_cfg80211_interop_issues_ap.h + * + * This Header file provide declaration for cfg80211 command handler API + */ + +#ifndef __WLAN_CFG80211_INTEROP_ISSUES_AP_H__ +#define __WLAN_CFG80211_INTEROP_ISSUES_AP_H__ + +#include +#include +#include +#include + +#ifdef WLAN_FEATURE_INTEROP_ISSUES_AP + +extern const struct nla_policy + interop_issues_ap_policy + [QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX + 1]; + +#define FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS \ +{ \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_cfg80211_set_interop_issues_ap_config, \ + vendor_command_policy(interop_issues_ap_policy, \ + QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX) \ +}, + +#define FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS_INDEX \ + [QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP_INDEX] = { \ + .vendor_id = QCA_NL80211_VENDOR_ID, \ + .subcmd = QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP \ + }, + +/** + * wlan_cfg80211_init_interop_issues_ap() - init interop issues ap setting + * @pdev: the pointer of pdev object + * + * Return: none + */ +void wlan_cfg80211_init_interop_issues_ap(struct wlan_objmgr_pdev *pdev); + +/** + * wlan_cfg80211_set_interop_issues_ap_config() - set interop issues ap config + * @wiphy: pointer to wireless wiphy structure + * @wdev: pointer to wireless_dev structure + * @data: Pointer to the data to be passed via vendor interface + * @data_len: Length of the data to be passed + * + * Return: Return the Success or Failure code + */ +int wlan_cfg80211_set_interop_issues_ap_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len); +#else +static inline +void wlan_cfg80211_init_interop_issues_ap(struct wlan_objmgr_pdev *pdev) {} +#define FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS +#define FEATURE_INTEROP_ISSUES_AP_VENDOR_COMMANDS_INDEX +#endif +#endif /* __WLAN_CFG80211_INTEROP_ISSUES_AP_H__ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/interop_issues_ap/src/wlan_cfg80211_interop_issues_ap.c b/qcom/opensource/wlan/qcacld-3.0/os_if/interop_issues_ap/src/wlan_cfg80211_interop_issues_ap.c new file mode 100644 index 0000000000..29a9eb1b89 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/interop_issues_ap/src/wlan_cfg80211_interop_issues_ap.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_hdd_main.h" +#include "cfg_ucfg_api.h" +#include "wlan_hdd_object_manager.h" + +const struct nla_policy +interop_issues_ap_policy[QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_TYPE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) }, + [QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST] = { + .type = NLA_U32, + .len = sizeof(uint32_t) }, + [QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID] = + VENDOR_NLA_POLICY_MAC_ADDR, +}; + +/** + * wlan_cfg80211_send_interop_issues_ap_cb() - report information + * @data: interop issues ap mac received from fw + * + * Generate a wlan interop issues ap info package and send it to user + * space daemon through netlink. + * + * Return: none + */ +static void +wlan_cfg80211_send_interop_issues_ap_cb( + struct wlan_interop_issues_ap_event *data) +{ + struct wlan_objmgr_pdev *pdev; + struct pdev_osif_priv *os_priv; + struct sk_buff *skb; + uint32_t index, len; + + if (!data) { + osif_err("Invalid result."); + return; + } + + pdev = data->pdev; + if (!pdev) { + osif_err("pdev is null."); + return; + } + os_priv = wlan_pdev_get_ospriv(pdev); + if (!os_priv) { + osif_err("os_priv is null."); + return; + } + + index = QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP_INDEX; + len = nla_total_size(QDF_MAC_ADDR_SIZE + NLMSG_HDRLEN); + skb = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, len, index, + GFP_KERNEL); + if (!skb) { + osif_err("skb alloc failed"); + return; + } + + osif_debug("interop issues ap mac:" QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(data->rap_addr.bytes)); + + if (nla_put(skb, + QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID, + QDF_MAC_ADDR_SIZE, data->rap_addr.bytes)) { + osif_err("nla put fail"); + wlan_cfg80211_vendor_free_skb(skb); + return; + } + + wlan_cfg80211_vendor_event(skb, GFP_KERNEL); +} + +static void wlan_interop_issues_ap_register_cbk(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_interop_issues_ap_callbacks cb; + + cb.os_if_interop_issues_ap_event_handler = + wlan_cfg80211_send_interop_issues_ap_cb; + ucfg_register_interop_issues_ap_callback(pdev, &cb); +} + +/** + * wlan_parse_interop_issues_ap() - parse the interop issues ap info + * @interop_issues_ap: the pointer of interop issues ap + * @attr: list of attributes + * + * Return: 0 on success; error number on failure + */ +static int +wlan_parse_interop_issues_ap(struct qdf_mac_addr *interop_issues_ap, + struct nlattr *attr) +{ + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX + 1]; + struct nlattr *curr_attr = NULL; + uint32_t rem; + qdf_size_t i = 0; + + nla_for_each_nested(curr_attr, attr, rem) { + if (i == MAX_INTEROP_ISSUES_AP_NUM) { + osif_err("Ignoring excess"); + break; + } + + if (wlan_cfg80211_nla_parse(tb2, + QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX, + nla_data(curr_attr), + nla_len(curr_attr), + interop_issues_ap_policy)) { + osif_err("nla_parse failed"); + return -EINVAL; + } + if (!tb2[QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID]) { + osif_err("attr addr failed"); + return -EINVAL; + } + nla_memcpy(interop_issues_ap[i].bytes, + tb2[QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_BSSID], + QDF_MAC_ADDR_SIZE); + osif_debug(QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(interop_issues_ap[i].bytes)); + i++; + } + + return i; +} + +/** + * __wlan_cfg80211_set_interop_issues_ap_config() - set config status + * @wiphy: WIPHY structure pointer + * @wdev: Wireless device structure pointer + * @data: Pointer to the data received + * @data_len: Length of the data received + * + * Return: 0 on success and errno on failure + */ +static int +__wlan_cfg80211_set_interop_issues_ap_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct net_device *dev = wdev->netdev; + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev); + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX + 1]; + struct nlattr *attr; + uint32_t count = 0; + struct wlan_interop_issues_ap_info interop_issues_ap = {0}; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Command not allowed in FTM mode"); + return -EPERM; + } + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_INTEROP_ISSUES_AP_ID); + if (!vdev) { + osif_err("Invalid vdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_INTEROP_ISSUES_AP_ID); + if (!psoc) { + osif_err("Invalid psoc"); + return -EINVAL; + } + + if (wlan_cfg80211_nla_parse(tb, + QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_MAX, + data, data_len, + interop_issues_ap_policy)) { + osif_err("Invalid ATTR"); + return -EINVAL; + } + + attr = tb[QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_LIST]; + if (attr) { + count = + wlan_parse_interop_issues_ap(interop_issues_ap.rap_items, + attr); + if (count < 0) + return -EINVAL; + } + + osif_debug("Num of interop issues ap: %d", count); + interop_issues_ap.count = count; + interop_issues_ap.detect_enable = true; + + /* + * need to figure out a converged way of obtaining the vdev for + * a given netdev that doesn't involve the legacy mechanism. + */ + ucfg_set_interop_issues_ap_config(psoc, &interop_issues_ap); + + return 0; +} + +int wlan_cfg80211_set_interop_issues_ap_config(struct wiphy *wiphy, + struct wireless_dev *wdev, + const void *data, int data_len) +{ + struct osif_psoc_sync *psoc_sync; + int ret; + + ret = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync); + if (ret) + return ret; + + ret = __wlan_cfg80211_set_interop_issues_ap_config(wiphy, wdev, + data, data_len); + osif_psoc_sync_op_stop(psoc_sync); + + return ret; +} + +void wlan_cfg80211_init_interop_issues_ap(struct wlan_objmgr_pdev *pdev) +{ + /* + * the special mac is used to trigger uplayer sets + * interop issues ap list to fw when driver reloads but + * cnss-daemon does not restart. + */ + uint8_t fmac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + struct wlan_interop_issues_ap_info interop_issues_ap = {0}; + struct wlan_interop_issues_ap_event data; + struct wlan_objmgr_psoc *psoc; + + if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { + hdd_err("Operation not supported in FTM mode"); + return; + } + + wlan_interop_issues_ap_register_cbk(pdev); + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + osif_err("Invalid psoc"); + return; + } + interop_issues_ap.detect_enable = true; + ucfg_set_interop_issues_ap_config(psoc, &interop_issues_ap); + + data.pdev = pdev; + qdf_mem_copy(data.rap_addr.bytes, fmac, QDF_MAC_ADDR_SIZE); + + wlan_cfg80211_send_interop_issues_ap_cb(&data); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/mlme/sap/ll_sap/inc/os_if_ll_sap.h b/qcom/opensource/wlan/qcacld-3.0/os_if/mlme/sap/ll_sap/inc/os_if_ll_sap.h new file mode 100644 index 0000000000..a6ed3d1762 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/mlme/sap/ll_sap/inc/os_if_ll_sap.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_sap definitions specific to the ll_sap module + */ + +#ifndef __OS_IF_LL_SAP_H__ +#define __OS_IF_LL_SAP_H__ + +#include "qdf_types.h" +#include "qca_vendor.h" +#include "wlan_objmgr_vdev_obj.h" + +#ifdef WLAN_FEATURE_LL_LT_SAP + +/** + * osif_ll_sap_register_cb() - Register ll_sap osif callbacks + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_ll_sap_register_cb(void); + +/** + * osif_ll_sap_unregister_cb() - un-register ll_sap osif callbacks + * + * Return: QDF_STATUS + */ +void osif_ll_sap_unregister_cb(void); + +/** + * osif_ll_lt_sap_request_for_audio_transport_switch() - Userspace request for + * the audio transport switch + * @vdev: Vdev on which the request is received + * @req_type: Type of the request + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum qca_wlan_audio_transport_switch_type req_type); + +/** + * osif_ll_lt_sap_deliver_audio_transport_switch_resp() - Deliver userspace + * response for the audio transport switch request to BS_SM + * @vdev: Vdev on which the response is received + * @req_type: Type of the request + * @status: status of the response + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum qca_wlan_audio_transport_switch_type req_type, + enum qca_wlan_audio_transport_switch_status status); + +#else +static inline QDF_STATUS osif_ll_sap_register_cb(void) +{ + return QDF_STATUS_SUCCESS; +} + +static inline void osif_ll_sap_unregister_cb(void) {} + +static inline QDF_STATUS +osif_ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum qca_wlan_audio_transport_switch_type req_type) +{ + return QDF_STATUS_E_INVAL; +} + +static inline QDF_STATUS +osif_ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum qca_wlan_audio_transport_switch_type req_type, + enum qca_wlan_audio_transport_switch_status status) +{ + return QDF_STATUS_E_INVAL; +} + +#endif /* WLAN_FEATURE_LL_LT_SAP */ +#endif /* __OS_IF_LL_SAP_H__*/ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/mlme/sap/ll_sap/src/os_if_ll_sap.c b/qcom/opensource/wlan/qcacld-3.0/os_if/mlme/sap/ll_sap/src/os_if_ll_sap.c new file mode 100644 index 0000000000..89ad9c1a0b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/mlme/sap/ll_sap/src/os_if_ll_sap.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains ll_sap definitions specific to the ll_lt_sap module + */ + +#include "os_if_ll_sap.h" +#include "wlan_ll_sap_public_structs.h" +#include "wlan_ll_sap_ucfg_api.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_cfg80211.h" +#include "wlan_osif_priv.h" + +#define WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_INVALID 0xFFFF + +/** + * osif_convert_audio_transport_switch_req_type_to_qca_type() - Convert + * audio transport switch request type to qca audio transport switch req type + * @req_type: Request type + * + * Return: enum qca_wlan_audio_transport_switch_type + */ +static enum qca_wlan_audio_transport_switch_type +osif_convert_audio_transport_switch_req_type_to_qca_type + (enum bearer_switch_req_type req_type) +{ + switch (req_type) { + case WLAN_BS_REQ_TO_NON_WLAN: + return QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN; + case WLAN_BS_REQ_TO_WLAN: + return QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN; + default: + osif_err("Invalid audio transport switch type"); + return WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_INVALID; + } +} + +/** + * osif_convert_audio_transport_switch_req_type_from_qca_type() - Convert + * audio transport switch request type from qca audio transport switch req type + * @req_type: Request type. + * + * Return: enum bearer_switch_req_type + */ +static enum bearer_switch_req_type +osif_convert_audio_transport_switch_req_type_from_qca_type + (enum qca_wlan_audio_transport_switch_type req_type) +{ + switch (req_type) { + case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_NON_WLAN: + return WLAN_BS_REQ_TO_NON_WLAN; + case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_TYPE_WLAN: + return WLAN_BS_REQ_TO_WLAN; + default: + osif_err("Invalid %d req type", req_type); + return WLAN_BS_REQ_INVALID; + } +} + +/** + * osif_convert_audio_transport_switch_status_type_from_qca_type() - Convert + * audio transport switch status from qca audio transport switch status type + * @status: audio transport switch status. + * + * Return: enum bearer_switch_status + */ +static enum bearer_switch_status +osif_convert_audio_transport_switch_status_type_from_qca_type + (enum qca_wlan_audio_transport_switch_status status) +{ + switch (status) { + case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED: + return WLAN_BS_STATUS_REJECTED; + case QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED: + return WLAN_BS_STATUS_COMPLETED; + default: + return WLAN_BS_STATUS_INVALID; + } +} + +/** + * wlan_osif_send_audio_transport_switch_req() - Send audio transport + * switch request + * @vdev: pointer to vdev structure. + * @req_type: Request type. + * + * Return: None. + */ +static void +wlan_osif_send_audio_transport_switch_req(struct wlan_objmgr_vdev *vdev, + enum bearer_switch_req_type req_type) +{ + struct sk_buff *vendor_event; + struct wireless_dev *wdev; + struct vdev_osif_priv *osif_priv; + uint32_t len; + enum qca_wlan_audio_transport_switch_type switch_type; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("Vdev %d osif_priv is null", vdev_id); + return; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("vdev %d wireless dev is null", vdev_id); + return; + } + + switch_type = + osif_convert_audio_transport_switch_req_type_to_qca_type( + req_type); + len = nla_total_size(sizeof(uint8_t)) + NLMSG_HDRLEN; + + vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, len, + QCA_NL80211_VENDOR_SUBCMD_AUDIO_TRANSPORT_SWITCH_INDEX, + GFP_KERNEL); + + if (!vendor_event) { + osif_err("vdev %d wlan_cfg80211_vendor_event_alloc failed", + vdev_id); + return; + } + + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE, + switch_type)) { + osif_err("Vdev %d VENDOR_ATTR_AUDIO_TRANSPORT_SWITCH_TYPE put fail", + vdev_id); + wlan_cfg80211_vendor_free_skb(vendor_event); + return; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + osif_nofl_debug("Vdev %d Audio Transport switch request %d sent", + vdev_id, switch_type); +} + +QDF_STATUS osif_ll_lt_sap_request_for_audio_transport_switch( + struct wlan_objmgr_vdev *vdev, + enum qca_wlan_audio_transport_switch_type req_type) +{ + return ucfg_ll_lt_sap_request_for_audio_transport_switch( + vdev, + osif_convert_audio_transport_switch_req_type_from_qca_type( + req_type)); +} + +QDF_STATUS osif_ll_lt_sap_deliver_audio_transport_switch_resp( + struct wlan_objmgr_vdev *vdev, + enum qca_wlan_audio_transport_switch_type req_type, + enum qca_wlan_audio_transport_switch_status status) +{ + static enum bearer_switch_status bs_status; + enum bearer_switch_req_type bs_req_type; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + + if (status == QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_COMPLETED) { + osif_nofl_debug("vdev %d Transport switch request %d completed", + vdev_id, req_type); + } else if (status == QCA_WLAN_AUDIO_TRANSPORT_SWITCH_STATUS_REJECTED) { + osif_nofl_debug("vdev %d Transport switch request %d rejected", + vdev_id, req_type); + } else { + osif_err("vdev %d Invalid transport switch status %d", vdev_id, + status); + return QDF_STATUS_E_INVAL; + } + bs_status = + osif_convert_audio_transport_switch_status_type_from_qca_type( + status); + bs_req_type = + osif_convert_audio_transport_switch_req_type_from_qca_type( + req_type); + + ucfg_ll_lt_sap_deliver_audio_transport_switch_resp(vdev, bs_req_type, + bs_status); + + return QDF_STATUS_SUCCESS; +} + +static struct ll_sap_ops ll_sap_global_ops = { + .ll_sap_send_audio_transport_switch_req_cb = + wlan_osif_send_audio_transport_switch_req, +}; + +QDF_STATUS osif_ll_sap_register_cb(void) +{ + ucfg_ll_sap_register_cb(&ll_sap_global_ops); + return QDF_STATUS_SUCCESS; +} + +void osif_ll_sap_unregister_cb(void) +{ + ucfg_ll_sap_unregister_cb(); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/nan/inc/os_if_nan.h b/qcom/opensource/wlan/qcacld-3.0/os_if/nan/inc/os_if_nan.h new file mode 100644 index 0000000000..bfabf2eba3 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/nan/inc/os_if_nan.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022,2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declares nan component os interface APIs + */ + +#ifndef _OS_IF_NAN_H_ +#define _OS_IF_NAN_H_ + +#include "qdf_types.h" +#ifdef WLAN_FEATURE_NAN +#include "nan_public_structs.h" +#include "nan_ucfg_api.h" +#include "qca_vendor.h" +#include + +/* QCA_NL80211_VENDOR_SUBCMD_NAN_EXT policy */ +extern const struct nla_policy nan_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX + 1]; + +/* QCA_NL80211_VENDOR_SUBCMD_NDP policy */ +extern const struct nla_policy vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1]; + +/** + * struct ndi_find_vdev_filter - find vdev filter object. this can be extended + * @ifname: interface name of vdev + * @found_vdev: found vdev object matching one or more of above params + */ +struct ndi_find_vdev_filter { + const char *ifname; + struct wlan_objmgr_vdev *found_vdev; +}; + +/** + * os_if_nan_process_ndp_cmd: os_if api to handle nan request message + * @psoc: pointer to psoc object + * @data: request data. contains vendor cmd tlvs + * @data_len: length of data + * @is_ndp_allowed: Indicates whether to allow NDP creation. + * NDI creation is always allowed. + * @wdev: Wireless device structure pointer + * + * Return: status of operation + */ +int os_if_nan_process_ndp_cmd(struct wlan_objmgr_psoc *psoc, + const void *data, int data_len, + bool is_ndp_allowed, + struct wireless_dev *wdev); + +/** + * os_if_nan_register_hdd_callbacks: os_if api to register hdd callbacks + * @psoc: pointer to psoc object + * @cb_obj: struct pointer containing callbacks + * + * Return: status of operation + */ +int os_if_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * os_if_nan_register_lim_callbacks: os_if api to register lim callbacks + * @psoc: pointer to psoc object + * @cb_obj: struct pointer containing callbacks + * + * Return: status of operation + */ +int os_if_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj); + +/** + * os_if_nan_post_ndi_create_rsp: os_if api to pos ndi create rsp to umac nan + * component + * @psoc: pointer to psoc object + * @vdev_id: vdev id of ndi + * @success: if create was success or failure + * + * Return: None + */ +void os_if_nan_post_ndi_create_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success); + +/** + * os_if_nan_post_ndi_delete_rsp: os_if api to pos ndi delete rsp to umac nan + * component + * @psoc: pointer to psoc object + * @vdev_id: vdev id of ndi + * @success: if delete was success or failure + * + * Return: None + */ +void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success); + +/** + * os_if_nan_ndi_session_end: os_if api to process ndi session end + * component + * @vdev: pointer to vdev deleted + * + * Return: None + */ +void os_if_nan_ndi_session_end(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_nan_set_ndi_state: os_if api set NDI state + * @vdev: pointer to vdev deleted + * @state: value to set + * + * Return: status of operation + */ +static inline QDF_STATUS os_if_nan_set_ndi_state(struct wlan_objmgr_vdev *vdev, + uint32_t state) +{ + return ucfg_nan_set_ndi_state(vdev, state); +} + +/** + * os_if_nan_set_ndp_create_transaction_id: set ndp create transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +static inline QDF_STATUS os_if_nan_set_ndp_create_transaction_id( + struct wlan_objmgr_vdev *vdev, + uint16_t val) +{ + return ucfg_nan_set_ndp_create_transaction_id(vdev, val); +} + +/** + * os_if_nan_set_ndp_delete_transaction_id: set ndp delete transaction id + * @vdev: pointer to vdev object + * @val: value to set + * + * Return: status of operation + */ +static inline QDF_STATUS os_if_nan_set_ndp_delete_transaction_id( + struct wlan_objmgr_vdev *vdev, + uint16_t val) +{ + return ucfg_nan_set_ndp_delete_transaction_id(vdev, val); +} + +/** + * os_if_process_nan_req: os_if api to handle NAN requests attached to the + * vendor command QCA_NL80211_VENDOR_SUBCMD_NAN_EXT + * @pdev: pointer to pdev object + * @vdev_id: NAN vdev id + * @data: request data. contains vendor cmd tlvs + * @data_len: length of data + * + * Return: status of operation + */ +int os_if_process_nan_req(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + const void *data, int data_len); +#else + +static inline void os_if_nan_post_ndi_create_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ +} + +static inline void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ +} + +#endif /* WLAN_FEATURE_NAN */ + +#if defined(WLAN_FEATURE_NAN) && defined(WLAN_CHIPSET_STATS) +/** + * os_if_cstats_log_ndp_initiator_req_evt() - Chipset stats for ndp + * initiator request + * + * @req : pointer to nan_datapath_initiator_req + * + * Return : void + */ +void +os_if_cstats_log_ndp_initiator_req_evt(struct nan_datapath_initiator_req *req); + +/** + * os_if_cstats_log_ndp_responder_req_evt() - Chipset stats for ndp + * responder request + * + * @vdev : pointer to vdev object + * @req : pointer to nan_datapath_responder_req + * + * Return : void + */ +void +os_if_cstats_log_ndp_responder_req_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_req *req); + +/** + * os_if_cstats_log_ndp_end_req_evt() - Chipset stats for ndp end + * request event + * + * @vdev : pointer to vdev object + * @rq : pointer to nan_datapath_end_req + * + * Return : void + */ +void os_if_cstats_log_ndp_end_req_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_req *rq); + +/** + * os_if_cstats_log_ndp_initiator_resp_evt() - Chipset stats for ndp + * initiator request event + * + * @vdev : pointer to vdev object + * @rsp : pointer to nan_datapath_end_req + * + * Return : void + */ +void +os_if_cstats_log_ndp_initiator_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_initiator_rsp *rsp); + +/** + * os_if_cstats_log_ndp_responder_resp_evt() - Chipset stats for ndp + * responder response event + * + * @vdev : pointer to vdev object + * @rsp : pointer to nan_datapath_responder_rsp + * + * Return : void + */ +void +os_if_cstats_log_ndp_responder_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_rsp *rsp); + +/** + * os_if_cstats_log_ndp_indication_evt() - Chipset stats for ndp + * indication event + * + * @vdev : pointer to vdev object + * @evt : pointer to nan_datapath_indication_event object + * + * Return : void + */ +void +os_if_cstats_log_ndp_indication_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_indication_event *evt); + +/** + * os_if_cstats_log_ndp_confirm_evt() - Chipset stats for ndp + * confirm event + * + * @vdev : pointer to vdev object + * @nc : pointer to nan_datapath_confirm_event + * + * Return : void + */ +void os_if_cstats_log_ndp_confirm_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_confirm_event *nc); + +/** + * os_if_cstats_log_ndp_end_rsp_evt() - Chipset stats for ndp + * end response event + * + * @vdev : pointer to vdev object + * @rsp : pointer to nan_datapath_end_rsp_event object + * + * Return : void + */ +void os_if_cstats_log_ndp_end_rsp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_rsp_event *rsp); + +/** + * os_if_cstats_log_ndp_new_peer_evt() - Chipset stats for ndp + * new peer event + * + * @vdev : pointer to vdev object + * @peer_ind : pointer to nan_datapath_peer_ind object + * + * Return : void + */ +void os_if_cstats_log_ndp_new_peer_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind); + +/** + * os_if_cstats_log_ndi_delete_resp_evt() - Chipset stats for ndi + * delete response event + * + * @vdev : pointer to vdev object + * @rsp : pointer to nan_datapath_inf_delete_rsp object + * + * Return : void + */ +void +os_if_cstats_log_ndi_delete_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_inf_delete_rsp *rsp); + +/** + * os_if_cstats_log_nan_disc_enable_req_evt() - Chipset stats for nan + * discovery enable request + * + * @vdev_id : pointer to vdev object + * @nan_req : pointer to nan_enable_req object + * + * Return : void + */ +void os_if_cstats_log_nan_disc_enable_req_evt(uint8_t vdev_id, + struct nan_enable_req *nan_req); + +/** + * os_if_cstats_log_disable_nan_disc_evt() - Chipset stats for nan + * discovery disable event + * + * @pdev : pointer to pdev object + * @vdev_id : vdev ID + * + * Return : void + */ +void os_if_cstats_log_disable_nan_disc_evt(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id); +#else +static inline void +os_if_cstats_log_ndp_initiator_req_evt(struct nan_datapath_initiator_req *req) +{ +} + +static inline void +os_if_cstats_log_ndp_responder_req_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_req *req) +{ +} + +static inline void +os_if_cstats_log_ndp_end_req_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_req *rq) +{ +} + +static inline void +os_if_cstats_log_ndp_initiator_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_initiator_rsp *rsp) +{ +} + +static inline void +os_if_cstats_log_ndp_responder_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_rsp *rsp) +{ +} + +static inline void +os_if_cstats_log_ndp_indication_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_indication_event *event) +{ +} + +static inline void +os_if_cstats_log_ndp_confirm_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_confirm_event *nc) +{ +} + +static inline void +os_if_cstats_log_ndp_end_rsp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_rsp_event *rsp) +{ +} + +static inline void +os_if_cstats_log_ndp_new_peer_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind) +{ +} + +static inline void +os_if_cstats_log_ndi_delete_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_inf_delete_rsp *rsp) +{ +} + +static inline void +os_if_cstats_log_nan_disc_enable_req_evt(uint8_t vdev_id, + struct nan_enable_req *nan_req) +{ +} + +static inline void +os_if_cstats_log_disable_nan_disc_evt(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ +} +#endif /* WLAN_CHIPSET_STATS */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/nan/src/os_if_nan.c b/qcom/opensource/wlan/qcacld-3.0/os_if/nan/src/os_if_nan.c new file mode 100644 index 0000000000..cda292545b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/nan/src/os_if_nan.c @@ -0,0 +1,3214 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines nan component os interface APIs + */ + +#include "osif_sync.h" +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "os_if_nan.h" +#include "wlan_nan_api.h" +#include "nan_ucfg_api.h" +#include "wlan_osif_priv.h" +#include +#include "wlan_cfg80211.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_utility.h" +#include "wlan_osif_request_manager.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_tdls_ucfg_api.h" + +#define NAN_CMD_MAX_SIZE 2048 + +/* NLA policy */ +const struct nla_policy nan_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA] = { + .type = NLA_BINARY, + .len = NAN_CMD_MAX_SIZE + }, + [QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, +}; + +/* NLA policy */ +const struct nla_policy vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID] = { + .type = NLA_U16, + .len = sizeof(uint16_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR] = { + .type = NLA_NUL_STRING, + .len = IFNAMSIZ - 1 + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR] = + VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_SECURITY] = { + .type = NLA_U16, + .len = sizeof(uint16_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO] = { + .type = NLA_BINARY, + .len = NDP_APP_INFO_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR] = { + .type = NLA_BINARY, + .len = QDF_MAC_ADDR_SIZE + }, + [QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY] = { + .type = NLA_BINARY, + .len = NDP_NUM_INSTANCE_ID + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CSID] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_PMK] = { + .type = NLA_BINARY, + .len = NDP_PMK_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SCID] = { + .type = NLA_BINARY, + .len = NDP_SCID_BUF_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE] = { + .type = NLA_BINARY, + .len = NAN_PASSPHRASE_MAX_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME] = { + .type = NLA_BINARY, + .len = NAN_MAX_SERVICE_NAME_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO] = { + .type = NLA_BINARY, + .len = NAN_CH_INFO_MAX_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_NSS] = { + .type = NLA_U32, + .len = sizeof(uint32_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR] = + VENDOR_NLA_POLICY_IPV6_ADDR, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT] = { + .type = NLA_U16, + .len = sizeof(uint16_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL] = { + .type = NLA_U8, + .len = sizeof(uint8_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID] = { + .type = NLA_U8, + .len = NDP_SERVICE_ID_LEN + }, + [QCA_WLAN_VENDOR_ATTR_NDP_CSIA_CAPABILITIES] = { + .type = NLA_U8, + .len = sizeof(uint8_t) + }, + [QCA_WLAN_VENDOR_ATTR_NDP_GTK_REQUIRED] = { + .type = NLA_FLAG, + }, +}; + +/** + * os_if_get_ndi_vdev_by_ifname_cb() - callback function to return vdev object + * from psoc matching given interface name + * @psoc: psoc object + * @obj: object used to iterate the callback function + * @arg: return argument which will be filled by the function + * + * Return : NULL + */ +static void os_if_get_ndi_vdev_by_ifname_cb(struct wlan_objmgr_psoc *psoc, + void *obj, void *arg) +{ + struct wlan_objmgr_vdev *vdev = obj; + struct ndi_find_vdev_filter *filter = arg; + struct vdev_osif_priv *osif_priv; + + if (filter->found_vdev) + return; + + wlan_vdev_obj_lock(vdev); + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + wlan_vdev_obj_unlock(vdev); + return; + } + + if (!osif_priv->wdev) { + wlan_vdev_obj_unlock(vdev); + return; + } + + if (!qdf_str_cmp(osif_priv->wdev->netdev->name, filter->ifname)) + filter->found_vdev = vdev; + + wlan_vdev_obj_unlock(vdev); +} + +/** + * os_if_get_ndi_vdev_by_ifname() - function to return vdev object from psoc + * matching given interface name + * @psoc: psoc object + * @ifname: interface name + * + * This function returns vdev object from psoc by interface name. If found this + * will also take reference with given ref_id + * + * Return : vdev object if found, NULL otherwise + */ +static struct wlan_objmgr_vdev * +os_if_get_ndi_vdev_by_ifname(struct wlan_objmgr_psoc *psoc, const char *ifname) +{ + QDF_STATUS status; + struct ndi_find_vdev_filter filter = {0}; + + filter.ifname = ifname; + wlan_objmgr_iterate_obj_list(psoc, WLAN_VDEV_OP, + os_if_get_ndi_vdev_by_ifname_cb, + &filter, 0, WLAN_NAN_ID); + + if (!filter.found_vdev) + return NULL; + + status = wlan_objmgr_vdev_try_get_ref(filter.found_vdev, WLAN_NAN_ID); + if (QDF_IS_STATUS_ERROR(status)) + return NULL; + + return filter.found_vdev; +} + +/** + * os_if_ndi_get_if_name() - get vdev's interface name + * @vdev: VDEV object + * + * API to get vdev's interface name + * + * Return: vdev's interface name + */ +static const uint8_t *os_if_ndi_get_if_name(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_osif_priv *osif_priv; + + wlan_vdev_obj_lock(vdev); + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + wlan_vdev_obj_unlock(vdev); + return NULL; + } + + if (!osif_priv->wdev) { + wlan_vdev_obj_unlock(vdev); + return NULL; + } + + wlan_vdev_obj_unlock(vdev); + + return osif_priv->wdev->netdev->name; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +static int os_if_nan_ndi_open(struct wlan_objmgr_psoc *psoc, + const char *iface_name) +{ + return 0; +} +#else +static int os_if_nan_ndi_open(struct wlan_objmgr_psoc *psoc, + const char *iface_name) +{ + QDF_STATUS status; + struct nan_callbacks cb_obj; + int ret; + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Couldn't get callback object"); + return -EINVAL; + } + + ret = cb_obj.ndi_open(iface_name, false); + if (ret) + osif_err("ndi_open failed"); + + return ret; +} +#endif + +static int __os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, + const char *iface_name, + struct nlattr **tb) +{ + int ret; + QDF_STATUS status; + uint16_t transaction_id; + struct wlan_objmgr_vdev *nan_vdev; + struct nan_callbacks cb_obj; + + osif_debug("enter"); + + nan_vdev = os_if_get_ndi_vdev_by_ifname(psoc, iface_name); + if (nan_vdev) { + osif_err("NAN data interface %s is already present", + iface_name); + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + return -EEXIST; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + osif_err("transaction id is unavailable"); + return -EINVAL; + } + transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Couldn't get callback object"); + return -EINVAL; + } + + if (cb_obj.ndi_set_mode(iface_name)) { + osif_err("NDI set mode fails"); + return -EINVAL; + } + + ret = os_if_nan_ndi_open(psoc, iface_name); + if (ret) + return ret; + + return cb_obj.ndi_start(iface_name, transaction_id); +} + +static int +osif_nla_str(struct nlattr **tb, size_t attr_id, const char **out_str) +{ + if (!tb || !tb[attr_id]) + return -EINVAL; + + *out_str = nla_data(tb[attr_id]); + + return 0; +} + +static int osif_net_dev_from_vdev(struct wlan_objmgr_vdev *vdev, + struct net_device **out_net_dev) +{ + struct vdev_osif_priv *priv; + + if (!vdev) + return -EINVAL; + + priv = wlan_vdev_get_ospriv(vdev); + if (!priv || !priv->wdev || !priv->wdev->netdev) + return -EINVAL; + + *out_net_dev = priv->wdev->netdev; + + return 0; +} + +static int osif_net_dev_from_ifname(struct wlan_objmgr_psoc *psoc, + const char *iface_name, + struct net_device **out_net_dev) +{ + struct wlan_objmgr_vdev *vdev; + struct net_device *net_dev; + int errno; + + vdev = os_if_get_ndi_vdev_by_ifname(psoc, iface_name); + if (!vdev) + return -EINVAL; + + errno = osif_net_dev_from_vdev(vdev, &net_dev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + if (errno) + return errno; + + *out_net_dev = net_dev; + + return 0; +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +static int os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb, + struct wireless_dev *wdev) +{ + struct osif_vdev_sync *vdev_sync; + const char *ifname; + int errno; + + osif_debug("enter"); + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + goto err; + + errno = osif_vdev_sync_trans_start(wdev->netdev, &vdev_sync); + if (errno) + goto err; + + errno = __os_if_nan_process_ndi_create(psoc, ifname, tb); + if (errno) { + osif_vdev_sync_trans_stop(vdev_sync); + goto err; + } + + osif_vdev_sync_trans_stop(vdev_sync); + + return 0; +err: + return errno; +} +#else + +static int +osif_device_from_psoc(struct wlan_objmgr_psoc *psoc, struct device **out_dev) +{ + qdf_device_t qdf_dev; + + if (!psoc) + return -EINVAL; + + qdf_dev = wlan_psoc_get_qdf_dev(psoc); + if (!qdf_dev || !qdf_dev->dev) + return -EINVAL; + + *out_dev = qdf_dev->dev; + + return 0; +} + +static int os_if_nan_process_ndi_create(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb, + struct wireless_dev *wdev) +{ + struct device *dev; + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + const char *ifname; + int errno; + + osif_debug("enter"); + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_device_from_psoc(psoc, &dev); + if (errno) + return errno; + + errno = osif_vdev_sync_create_and_trans(dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndi_create(psoc, ifname, tb); + if (errno) + goto destroy_sync; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + goto destroy_sync; + + osif_vdev_sync_register(net_dev, vdev_sync); + osif_vdev_sync_trans_stop(vdev_sync); + + return 0; + +destroy_sync: + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); + + return errno; +} +#endif + +static int __os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, + const char *iface_name, + struct nlattr **tb) +{ + uint8_t vdev_id; + QDF_STATUS status; + uint32_t num_peers; + uint16_t transaction_id; + struct nan_callbacks cb_obj; + struct wlan_objmgr_vdev *nan_vdev = NULL; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + osif_err("Transaction id is unavailable"); + return -EINVAL; + } + + nan_vdev = os_if_get_ndi_vdev_by_ifname(psoc, iface_name); + if (!nan_vdev) { + osif_debug("Nan datapath interface is not present"); + return -EINVAL; + } + + transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + vdev_id = wlan_vdev_get_id(nan_vdev); + num_peers = ucfg_nan_get_active_peers(nan_vdev); + /* + * os_if_get_ndi_vdev_by_ifname increments ref count + * decrement here since vdev returned by that api is not used any more + */ + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + /* check if there are active peers on the adapter */ + if (num_peers) + osif_err("NDP peers active: %d, active NDPs may not be terminated", + num_peers); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Couldn't get ballback object"); + return -EINVAL; + } + + return cb_obj.ndi_delete(vdev_id, iface_name, transaction_id); +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 12, 0)) +static int os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + const char *ifname; + int errno; + + osif_debug("enter"); + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + return errno; + + errno = osif_vdev_sync_trans_start_wait(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndi_delete(psoc, ifname, tb); + if (errno) + goto reregister; + + osif_vdev_sync_trans_stop(vdev_sync); + + return 0; + +reregister: + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} +#else +static int os_if_nan_process_ndi_delete(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + const char *ifname; + int errno; + + osif_debug("enter"); + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + return errno; + + errno = osif_vdev_sync_trans_start_wait(net_dev, &vdev_sync); + if (errno) + return errno; + + osif_vdev_sync_unregister(net_dev); + osif_vdev_sync_wait_for_ops(vdev_sync); + + errno = __os_if_nan_process_ndi_delete(psoc, ifname, tb); + if (errno) + goto reregister; + + osif_vdev_sync_trans_stop(vdev_sync); + osif_vdev_sync_destroy(vdev_sync); + + return 0; + +reregister: + osif_vdev_sync_register(net_dev, vdev_sync); + osif_vdev_sync_trans_stop(vdev_sync); + + return errno; +} +#endif + +/** + * os_if_nan_parse_security_params() - parse vendor attributes for security + * params. + * @tb: parsed NL attribute list + * @ncs_sk_type: out parameter to populate ncs_sk_type + * @pmk: out parameter to populate pmk + * @passphrase: out parameter to populate passphrase + * @service_name: out parameter to populate service_name + * @ndp_add_param: parameters to populate csid and gtk + * + * Return: 0 on success or error code on failure + */ +static int os_if_nan_parse_security_params(struct nlattr **tb, + uint32_t *ncs_sk_type, struct nan_datapath_pmk *pmk, + struct ndp_passphrase *passphrase, + struct ndp_service_name *service_name, + struct ndp_additional_params *ndp_add_param) +{ + struct nlattr *attr; + + if (!ncs_sk_type || !pmk || !passphrase || !service_name) { + osif_err("out buffers for one or more parameters is null"); + return -EINVAL; + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CSID]) { + *ncs_sk_type = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CSID]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]) { + pmk->pmk_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]); + qdf_mem_copy(pmk->pmk, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PMK]), + pmk->pmk_len); + osif_err("pmk len: %d", pmk->pmk_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + pmk->pmk, pmk->pmk_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE]) { + passphrase->passphrase_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE]); + qdf_mem_copy(passphrase->passphrase, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE]), + passphrase->passphrase_len); + osif_err("passphrase len: %d", passphrase->passphrase_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + passphrase->passphrase, + passphrase->passphrase_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME]) { + service_name->service_name_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME]); + qdf_mem_copy(service_name->service_name, + nla_data( + tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME]), + service_name->service_name_len); + osif_err("service_name len: %d", + service_name->service_name_len); + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_ERROR, + service_name->service_name, + service_name->service_name_len); + } + + attr = tb[QCA_WLAN_VENDOR_ATTR_NDP_CSIA_CAPABILITIES]; + if (attr) + ndp_add_param->csid_cap = nla_get_u8(attr); + + ndp_add_param->gtk = + nla_get_flag(tb[QCA_WLAN_VENDOR_ATTR_NDP_GTK_REQUIRED]); + + return 0; +} + +/** + * __os_if_nan_process_ndp_initiator_req() - NDP initiator request handler + * @psoc: psoc object + * @iface_name: interface name + * @tb: parsed NL attribute list + * + * tb will contain following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID + * QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PMK - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CSID - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE - optional + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME - optional + * + * Return: 0 on success or error code on failure + */ +static int __os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc, + const char *iface_name, + struct nlattr **tb) +{ + int ret = 0; + QDF_STATUS status; + enum nan_datapath_state state; + struct wlan_objmgr_vdev *nan_vdev; + struct nan_datapath_initiator_req req = {0}; + + nan_vdev = os_if_get_ndi_vdev_by_ifname(psoc, iface_name); + if (!nan_vdev) { + osif_err("NAN data interface %s not available", iface_name); + return -EINVAL; + } + + if (nan_vdev->vdev_mlme.vdev_opmode != QDF_NDI_MODE) { + osif_err("Interface found is not NDI"); + ret = -EINVAL; + goto initiator_req_failed; + } + + state = ucfg_nan_get_ndi_state(nan_vdev); + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE || + state == NAN_DATA_NDI_CREATING_STATE) { + osif_err("Data request not allowed in NDI current state: %d", + state); + ret = -EINVAL; + goto initiator_req_failed; + } + + if (!ucfg_nan_is_sta_ndp_concurrency_allowed(psoc, nan_vdev)) { + osif_err("NDP creation not allowed"); + ret = -EOPNOTSUPP; + goto initiator_req_failed; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + osif_err("Transaction ID is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]) { + req.channel = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG]) { + req.channel_cfg = nla_get_u32( + tb[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_CONFIG]); + } else { + osif_err("Channel config is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]) { + osif_err("NDP service instance ID is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + req.service_instance_id = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID]); + + qdf_mem_copy(req.self_ndi_mac_addr.bytes, + wlan_vdev_mlme_get_macaddr(nan_vdev), QDF_MAC_ADDR_SIZE); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]) { + osif_err("NDI peer discovery mac addr is unavailable"); + ret = -EINVAL; + goto initiator_req_failed; + } + qdf_mem_copy(req.peer_discovery_mac_addr.bytes, + nla_data( + tb[QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR]), + QDF_MAC_ADDR_SIZE); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { + req.ndp_info.ndp_app_info_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + qdf_mem_copy(req.ndp_info.ndp_app_info, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]), + req.ndp_info.ndp_app_info_len); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) { + /* at present ndp config stores 4 bytes QOS info only */ + req.ndp_config.ndp_cfg_len = 4; + *((uint32_t *)req.ndp_config.ndp_cfg) = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]) { + req.is_ipv6_addr_present = true; + qdf_mem_copy(req.ipv6_addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]), + QDF_IPV6_ADDR_SIZE); + } + + if (os_if_nan_parse_security_params(tb, &req.ncs_sk_type, &req.pmk, + &req.passphrase, + &req.service_name, + &req.ndp_add_params)) { + osif_err("inconsistent security params in request."); + ret = -EINVAL; + goto initiator_req_failed; + } + + req.vdev = nan_vdev; + + os_if_cstats_log_ndp_initiator_req_evt(&req); + + status = ucfg_nan_req_processor(nan_vdev, &req, NDP_INITIATOR_REQ); + ret = qdf_status_to_os_return(status); +initiator_req_failed: + if (ret) + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + return ret; +} + +static int os_if_nan_process_ndp_initiator_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + const char *ifname; + int errno; + + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, &ifname); + if (errno) + return errno; + + errno = osif_net_dev_from_ifname(psoc, ifname, &net_dev); + if (errno) + return errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndp_initiator_req(psoc, ifname, tb); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __os_if_nan_process_ndp_responder_req() - NDP responder request handler + * @psoc: psoc object + * @tb: parsed NL attribute list + * + * tb includes following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PMK - optional + * QCA_WLAN_VENDOR_ATTR_NDP_CSID - optional + * QCA_WLAN_VENDOR_ATTR_NDP_PASSPHRASE - optional + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_NAME - optional + * + * Return: 0 on success or error code on failure + */ +static int __os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + int ret = 0; + QDF_STATUS status; + enum nan_datapath_state state; + struct wlan_objmgr_vdev *nan_vdev = NULL; + struct nan_datapath_responder_req req = {0}; + const char *iface_name; + int errno; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]) { + osif_err("ndp_rsp is unavailable"); + return -EINVAL; + } + req.ndp_rsp = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE]); + + if (req.ndp_rsp == NAN_DATAPATH_RESPONSE_ACCEPT) { + errno = osif_nla_str(tb, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + &iface_name); + + if (errno) { + osif_err("NAN data iface not provided"); + return errno; + } + /* Check for an existing NAN interface */ + nan_vdev = os_if_get_ndi_vdev_by_ifname(psoc, iface_name); + if (!nan_vdev) { + osif_err("NAN data iface %s not available", + iface_name); + return -ENODEV; + } + + if (nan_vdev->vdev_mlme.vdev_opmode != QDF_NDI_MODE) { + osif_err("Interface found is not NDI"); + ret = -ENODEV; + goto responder_req_failed; + } + + if (!ucfg_nan_is_sta_ndp_concurrency_allowed(psoc, nan_vdev)) { + osif_err("NDP creation not allowed"); + ret = -EOPNOTSUPP; + goto responder_req_failed; + } + } else { + /* + * If the data indication is rejected, the userspace + * may not send the iface name. Use the first NDI + * in that case + */ + osif_debug("ndp rsp rejected, using first NDI"); + + nan_vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc( + psoc, QDF_NDI_MODE, WLAN_NAN_ID); + if (!nan_vdev) { + osif_err("NAN data iface is not available"); + return -ENODEV; + } + } + + state = ucfg_nan_get_ndi_state(nan_vdev); + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE || + state == NAN_DATA_NDI_CREATING_STATE) { + osif_err("Data request not allowed in current NDI state:%d", + state); + ret = -EAGAIN; + goto responder_req_failed; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + osif_err("Transaction ID is unavailable"); + ret = -EINVAL; + goto responder_req_failed; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]) { + osif_err("Instance ID is unavailable"); + ret = -EINVAL; + goto responder_req_failed; + } + req.ndp_instance_id = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]) { + req.ndp_info.ndp_app_info_len = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]); + qdf_mem_copy(req.ndp_info.ndp_app_info, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO]), + req.ndp_info.ndp_app_info_len); + } else { + osif_debug("NDP app info is unavailable"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]) { + /* at present ndp config stores 4 bytes QOS info only */ + req.ndp_config.ndp_cfg_len = 4; + *((uint32_t *)req.ndp_config.ndp_cfg) = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS]); + } else { + osif_debug("NDP config data is unavailable"); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]) { + req.is_ipv6_addr_present = true; + qdf_mem_copy(req.ipv6_addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR]), + QDF_IPV6_ADDR_SIZE); + } + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT]) { + req.is_port_present = true; + req.port = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT]); + } + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL]) { + req.is_protocol_present = true; + req.protocol = nla_get_u8( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL]); + } + osif_debug("ipv6 addr present: %d, addr: %pI6", + req.is_ipv6_addr_present, req.ipv6_addr); + osif_debug("port %d, present: %d protocol %d, present: %d", + req.port, req.is_port_present, req.protocol, + req.is_protocol_present); + + if (os_if_nan_parse_security_params(tb, &req.ncs_sk_type, &req.pmk, + &req.passphrase, &req.service_name, + &req.ndp_add_params)) { + osif_err("inconsistent security params in request."); + ret = -EINVAL; + goto responder_req_failed; + } + + os_if_cstats_log_ndp_responder_req_evt(nan_vdev, &req); + + osif_debug("vdev_id: %d, transaction_id: %d, ndp_rsp %d, ndp_instance_id: %d, ndp_app_info_len: %d, csid: %d", + wlan_vdev_get_id(nan_vdev), req.transaction_id, req.ndp_rsp, + req.ndp_instance_id, req.ndp_info.ndp_app_info_len, + req.ncs_sk_type); + + req.vdev = nan_vdev; + status = ucfg_nan_req_processor(nan_vdev, &req, NDP_RESPONDER_REQ); + ret = qdf_status_to_os_return(status); + +responder_req_failed: + if (ret) + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + return ret; + +} + +static int os_if_nan_process_ndp_responder_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb, + struct wireless_dev *wdev) +{ + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndp_responder_req(psoc, tb); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __os_if_nan_process_ndp_end_req() - NDP end request handler + * @psoc: pointer to psoc object + * + * @tb: parsed NL attribute list + * tb includes following vendor attributes: + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID + * + * Return: 0 on success or error code on failure + */ +static int __os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + int ret = 0; + QDF_STATUS status; + struct wlan_objmgr_vdev *nan_vdev; + struct nan_datapath_end_req req = {0}; + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + osif_err("Transaction ID is unavailable"); + return -EINVAL; + } + req.transaction_id = + nla_get_u16(tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) { + osif_err("NDP instance ID array is unavailable"); + return -EINVAL; + } + + req.num_ndp_instances = + nla_len(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]) / + sizeof(uint32_t); + if (0 >= req.num_ndp_instances) { + osif_err("Num NDP instances is 0"); + return -EINVAL; + } + qdf_mem_copy(req.ndp_ids, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY]), + req.num_ndp_instances * sizeof(uint32_t)); + + osif_debug("sending ndp_end_req to SME, transaction_id: %d", + req.transaction_id); + + nan_vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, QDF_NDI_MODE, + WLAN_NAN_ID); + if (!nan_vdev) { + osif_err("NAN data interface is not available"); + return -EINVAL; + } + + req.vdev = nan_vdev; + + os_if_cstats_log_ndp_end_req_evt(nan_vdev, &req); + + status = ucfg_nan_req_processor(nan_vdev, &req, NDP_END_REQ); + ret = qdf_status_to_os_return(status); + if (ret) + wlan_objmgr_vdev_release_ref(nan_vdev, WLAN_NAN_ID); + + return ret; +} + +static int os_if_nan_process_ndp_end_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct wlan_objmgr_vdev *vdev; + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + int errno; + + vdev = wlan_objmgr_get_vdev_by_opmode_from_psoc(psoc, QDF_NDI_MODE, + WLAN_NAN_ID); + if (!vdev) + return -EINVAL; + + errno = osif_net_dev_from_vdev(vdev, &net_dev); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + if (errno) + return errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __os_if_nan_process_ndp_end_req(psoc, tb); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +int os_if_nan_process_ndp_cmd(struct wlan_objmgr_psoc *psoc, + const void *data, int data_len, + bool is_ndp_allowed, + struct wireless_dev *wdev) +{ + uint32_t ndp_cmd_type; + uint16_t transaction_id; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX + 1]; + char *iface_name; + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_NDP_PARAMS_MAX, + data, data_len, vendor_attr_policy)) { + osif_err("Invalid NDP vendor command attributes"); + return -EINVAL; + } + + /* Parse and fetch NDP Command Type*/ + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]) { + osif_err("NAN datapath cmd type failed"); + return -EINVAL; + } + ndp_cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD]); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]) { + osif_err("attr transaction id failed"); + return -EINVAL; + } + transaction_id = nla_get_u16( + tb[QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]) { + iface_name = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR]); + osif_debug("Transaction Id: %u NDPCmd: %u iface_name: %s", + transaction_id, ndp_cmd_type, iface_name); + } else { + osif_debug("Transaction Id: %u NDPCmd: %u iface_name: unspecified", + transaction_id, ndp_cmd_type); + } + + switch (ndp_cmd_type) { + case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE: + /** + * NDI creation is not allowed if NAN discovery is not running. + * Allowing NDI creation when NAN discovery is not enabled may + * lead to issues if NDI has to be started in a + * 2GHz channel and if the target is not operating in DBS mode. + */ + if ((ucfg_is_nan_conc_control_supported(psoc)) && + (!ucfg_is_nan_disc_active(psoc))) { + osif_err("NDI creation is not allowed when NAN discovery is not running"); + return -EOPNOTSUPP; + } + return os_if_nan_process_ndi_create(psoc, tb, wdev); + case QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE: + return os_if_nan_process_ndi_delete(psoc, tb); + case QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_REQUEST: + if (!is_ndp_allowed) { + osif_err("Unsupported concurrency for NAN datapath"); + return -EOPNOTSUPP; + } + return os_if_nan_process_ndp_initiator_req(psoc, tb); + case QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_REQUEST: + if (!is_ndp_allowed) { + osif_err("Unsupported concurrency for NAN datapath"); + return -EOPNOTSUPP; + } + return os_if_nan_process_ndp_responder_req(psoc, tb, wdev); + case QCA_WLAN_VENDOR_ATTR_NDP_END_REQUEST: + if (!is_ndp_allowed) { + osif_err("Unsupported concurrency for NAN datapath"); + return -EOPNOTSUPP; + } + return os_if_nan_process_ndp_end_req(psoc, tb); + default: + osif_err("Unrecognized NDP vendor cmd %d", ndp_cmd_type); + return -EINVAL; + } + + return -EINVAL; +} + +static inline uint32_t osif_ndp_get_ndp_initiator_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +/** + * os_if_ndp_initiator_rsp_handler() - NDP initiator response handler + * @vdev: pointer to vdev object + * @rsp: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void os_if_ndp_initiator_rsp_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_initiator_rsp *rsp) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!rsp) { + osif_err("Invalid NDP Initiator response"); + return; + } + + data_len = osif_ndp_get_ndp_initiator_rsp_len(); + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_ATOMIC); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INITIATOR_RESPONSE)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + rsp->ndp_instance_id)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_initiator_rsp_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_initiator_rsp_nla_failed; + + os_if_cstats_log_ndp_initiator_resp_evt(vdev, rsp); + + osif_debug("NDP Initiator rsp sent, tid:%d, instance id:%d, status:%d, reason: %d", + rsp->transaction_id, rsp->ndp_instance_id, rsp->status, + rsp->reason); + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; +ndp_initiator_rsp_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_responder_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +/* + * os_if_ndp_responder_rsp_handler() - NDP responder response handler + * @vdev: pointer to vdev object + * @rsp: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * + * Return: none + */ +static void os_if_ndp_responder_rsp_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_rsp *rsp) +{ + uint16_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!rsp) { + osif_err("Invalid NDP Responder response"); + return; + } + + data_len = osif_ndp_get_ndp_responder_rsp_len(); + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_ATOMIC); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONDER_RESPONSE)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_responder_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_responder_rsp_nla_failed; + + os_if_cstats_log_ndp_responder_resp_evt(vdev, rsp); + + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; +ndp_responder_rsp_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_req_ind_len( + struct nan_datapath_indication_event *event) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_CSID].len); + /* allocate space including NULL terminator */ + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR].len + 1); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR].len); + if (event->is_ipv6_addr_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR].len); + if (event->scid.scid_len) + data_len += nla_total_size(event->scid.scid_len); + if (event->ndp_info.ndp_app_info_len) + data_len += nla_total_size(event->ndp_info.ndp_app_info_len); + if (event->is_service_id_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID].len); + + if (event->ndp_add_params.csid_cap) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_CSIA_CAPABILITIES].len); + if (event->ndp_add_params.gtk) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_GTK_REQUIRED].len); + + return data_len; +} + +/** + * os_if_ndp_indication_handler() - NDP indication handler + * @vdev: pointer to vdev object + * @event: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ) + * QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size) + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_CSID(4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_SCID(scid_len in size) + * QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR (16 bytes) + * + * Return: none + */ +static void os_if_ndp_indication_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_indication_event *event) +{ + const uint8_t *ifname; + uint16_t data_len; + qdf_size_t ifname_len; + uint32_t ndp_qos_config; + struct sk_buff *vendor_event; + enum nan_datapath_state state; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!event) { + osif_err("Invalid NDP Indication"); + return; + } + + osif_debug("NDP Indication, policy: %d", event->policy); + state = ucfg_nan_get_ndi_state(vdev); + /* check if we are in middle of deleting/creating the interface */ + + if (state == NAN_DATA_NDI_DELETED_STATE || + state == NAN_DATA_NDI_DELETING_STATE || + state == NAN_DATA_NDI_CREATING_STATE) { + osif_err("Data request not allowed in current NDI state: %d", + state); + return; + } + + ifname = os_if_ndi_get_if_name(vdev); + if (!ifname) { + osif_err("ifname is null"); + return; + } + ifname_len = qdf_str_len(ifname); + if (ifname_len > IFNAMSIZ) { + osif_err("ifname(%zu) too long", ifname_len); + return; + } + + data_len = osif_ndp_get_ndp_req_ind_len(event); + /* notify response to the upper layer */ + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, + NULL, data_len, + index, GFP_ATOMIC); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_REQUEST_IND)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + ifname_len, ifname)) + goto ndp_indication_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_INSTANCE_ID, + event->service_instance_id)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QDF_MAC_ADDR_SIZE, event->peer_mac_addr.bytes)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR, + QDF_MAC_ADDR_SIZE, event->peer_discovery_mac_addr.bytes)) + goto ndp_indication_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + event->ndp_instance_id)) + goto ndp_indication_nla_failed; + + if (event->ndp_info.ndp_app_info_len) + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + event->ndp_info.ndp_app_info_len, + event->ndp_info.ndp_app_info)) + goto ndp_indication_nla_failed; + + if (event->ndp_config.ndp_cfg_len) { + ndp_qos_config = *((uint32_t *)event->ndp_config.ndp_cfg); + /* at present ndp config stores 4 bytes QOS info only */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIG_QOS, + ndp_qos_config)) + goto ndp_indication_nla_failed; + } + + if (event->scid.scid_len) { + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_CSID, + event->ncs_sk_type)) + goto ndp_indication_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SCID, + event->scid.scid_len, + event->scid.scid)) + goto ndp_indication_nla_failed; + + osif_debug("csid: %d, scid_len: %d", + event->ncs_sk_type, event->scid.scid_len); + + QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_HDD, QDF_TRACE_LEVEL_DEBUG, + event->scid.scid, event->scid.scid_len); + } + + if (event->is_ipv6_addr_present) { + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR, + QDF_IPV6_ADDR_SIZE, event->ipv6_addr)) + goto ndp_indication_nla_failed; + } + + if (event->is_service_id_present) { + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SERVICE_ID, + NDP_SERVICE_ID_LEN, event->service_id)) + goto ndp_indication_nla_failed; + } + + if (event->ndp_add_params.csid_cap) { + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_CSIA_CAPABILITIES, + event->ndp_add_params.csid_cap)) + goto ndp_indication_nla_failed; + } + + if (event->ndp_add_params.gtk) { + if (nla_put_flag(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_GTK_REQUIRED)) + goto ndp_indication_nla_failed; + } + + os_if_cstats_log_ndp_indication_evt(vdev, event); + + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; +ndp_indication_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_confirm_ind_len( + struct nan_datapath_confirm_event *ndp_confirm) +{ + uint32_t ch_info_len = 0; + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR].len); + /* allocate space including NULL terminator */ + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR].len + 1); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + if (ndp_confirm->ndp_info.ndp_app_info_len) + data_len += + nla_total_size(ndp_confirm->ndp_info.ndp_app_info_len); + + if (ndp_confirm->is_ipv6_addr_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR].len); + if (ndp_confirm->is_port_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT].len); + if (ndp_confirm->is_protocol_present) + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL].len); + + /* ch_info is a nested array of following attributes */ + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_NSS].len); + + if (ndp_confirm->num_channels) + data_len += ndp_confirm->num_channels * + nla_total_size(ch_info_len); + + return data_len; +} + +static QDF_STATUS os_if_ndp_confirm_pack_ch_info(struct sk_buff *event, + struct nan_datapath_confirm_event *ndp_confirm) +{ + int idx = 0; + struct nlattr *ch_array, *ch_element; + + if (!ndp_confirm->num_channels) + return QDF_STATUS_SUCCESS; + + ch_array = nla_nest_start(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO); + if (!ch_array) + return QDF_STATUS_E_FAULT; + + for (idx = 0; idx < ndp_confirm->num_channels; idx++) { + ch_element = nla_nest_start(event, idx); + if (!ch_element) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL, + ndp_confirm->ch[idx].freq)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH, + ndp_confirm->ch[idx].ch_width)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_NSS, + ndp_confirm->ch[idx].nss)) + return QDF_STATUS_E_FAULT; + nla_nest_end(event, ch_element); + } + nla_nest_end(event, ch_array); + + return QDF_STATUS_SUCCESS; +} + +/** + * os_if_ndp_confirm_ind_handler() - NDP confirm indication handler + * @vdev: pointer to vdev object + * @ndp_confirm: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR (6 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR (IFNAMSIZ) + * QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO (ndp_app_info_len size) + * QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR (16 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL (1 byte) + * + * Return: none + */ +static void +os_if_ndp_confirm_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_confirm_event *ndp_confirm) +{ + const uint8_t *ifname; + uint32_t data_len; + QDF_STATUS status; + qdf_size_t ifname_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!ndp_confirm) { + osif_err("Invalid NDP Initiator response"); + return; + } + + ifname = os_if_ndi_get_if_name(vdev); + if (!ifname) { + osif_err("ifname is null"); + return; + } + ifname_len = qdf_str_len(ifname); + if (ifname_len > IFNAMSIZ) { + osif_err("ifname(%zu) too long", ifname_len); + return; + } + + data_len = osif_ndp_get_ndp_confirm_ind_len(ndp_confirm); + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_ATOMIC); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_CONFIRM_IND)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID, + ndp_confirm->ndp_instance_id)) + goto ndp_confirm_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NDI_MAC_ADDR, + QDF_MAC_ADDR_SIZE, ndp_confirm->peer_ndi_mac_addr.bytes)) + goto ndp_confirm_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IFACE_STR, + ifname_len, ifname)) + goto ndp_confirm_nla_failed; + + if (ndp_confirm->ndp_info.ndp_app_info_len && + nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_APP_INFO, + ndp_confirm->ndp_info.ndp_app_info_len, + ndp_confirm->ndp_info.ndp_app_info)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_RESPONSE_CODE, + ndp_confirm->rsp_code)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ndp_confirm->reason_code)) + goto ndp_confirm_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS, + ndp_confirm->num_channels)) + goto ndp_confirm_nla_failed; + + status = os_if_ndp_confirm_pack_ch_info(vendor_event, ndp_confirm); + if (QDF_IS_STATUS_ERROR(status)) + goto ndp_confirm_nla_failed; + + if (ndp_confirm->is_ipv6_addr_present) { + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_IPV6_ADDR, + QDF_IPV6_ADDR_SIZE, ndp_confirm->ipv6_addr)) + goto ndp_confirm_nla_failed; + } + if (ndp_confirm->is_port_present) + if (nla_put_u16(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PORT, + ndp_confirm->port)) + goto ndp_confirm_nla_failed; + if (ndp_confirm->is_protocol_present) + if (nla_put_u8(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_TRANSPORT_PROTOCOL, + ndp_confirm->protocol)) + goto ndp_confirm_nla_failed; + + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + + os_if_cstats_log_ndp_confirm_evt(vdev, ndp_confirm); + + osif_debug("NDP confim sent, ndp instance id: %d, peer addr: "QDF_MAC_ADDR_FMT" rsp_code: %d, reason_code: %d", + ndp_confirm->ndp_instance_id, + QDF_MAC_ADDR_REF(ndp_confirm->peer_ndi_mac_addr.bytes), + ndp_confirm->rsp_code, ndp_confirm->reason_code); + + return; +ndp_confirm_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_end_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + + return data_len; +} + +/** + * os_if_ndp_end_rsp_handler() - NDP end response handler + * @vdev: pointer to vdev object + * @rsp: response parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE(4 bytest) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * + * Return: none + */ +static void os_if_ndp_end_rsp_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_rsp_event *rsp) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!rsp) { + osif_err("Invalid ndp end response"); + return; + } + + data_len = osif_ndp_get_ndp_end_rsp_len(); + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_ATOMIC); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_END_RESPONSE)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + rsp->status)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + rsp->reason)) + goto ndp_end_rsp_nla_failed; + + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + rsp->transaction_id)) + goto ndp_end_rsp_nla_failed; + + os_if_cstats_log_ndp_end_rsp_evt(vdev, rsp); + + osif_debug("NDP End rsp sent, transaction id: %u, status: %u, reason: %u", + rsp->transaction_id, rsp->status, rsp->reason); + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; + +ndp_end_rsp_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +static inline uint32_t osif_ndp_get_ndp_end_ind_len( + struct nan_datapath_end_indication_event *end_ind) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + if (end_ind->num_ndp_ids) + data_len += nla_total_size(end_ind->num_ndp_ids * + sizeof(uint32_t)); + + return data_len; +} + +/** + * os_if_ndp_end_ind_handler() - NDP end indication handler + * @vdev: pointer to vdev object + * @end_ind: indication parameters + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_END_IND (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY (4 * num of NDP Instances) + * + * Return: none + */ +static void os_if_ndp_end_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_indication_event *end_ind) +{ + uint32_t data_len, i; + uint32_t *ndp_instance_array; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!end_ind) { + osif_err("Invalid ndp end indication"); + return; + } + + ndp_instance_array = qdf_mem_malloc(end_ind->num_ndp_ids * + sizeof(*ndp_instance_array)); + if (!ndp_instance_array) + return; + + for (i = 0; i < end_ind->num_ndp_ids; i++) + ndp_instance_array[i] = end_ind->ndp_map[i].ndp_instance_id; + + data_len = osif_ndp_get_ndp_end_ind_len(end_ind); + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_ATOMIC); + if (!vendor_event) { + qdf_mem_free(ndp_instance_array); + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_END_IND)) + goto ndp_end_ind_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY, + end_ind->num_ndp_ids * sizeof(*ndp_instance_array), + ndp_instance_array)) + goto ndp_end_ind_nla_failed; + + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + qdf_mem_free(ndp_instance_array); + return; + +ndp_end_ind_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); + qdf_mem_free(ndp_instance_array); +} + +/** + * os_if_new_peer_ind_handler() - NDP new peer indication handler + * @vdev: vdev object + * @peer_ind: indication parameters + * + * Return: none + */ +static void os_if_new_peer_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind) +{ + int ret; + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + uint32_t active_peers = ucfg_nan_get_active_peers(vdev); + struct nan_callbacks cb_obj; + + if (!peer_ind) { + osif_err("Invalid new NDP peer params"); + return; + } + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("failed to get callbacks"); + return; + } + + os_if_cstats_log_ndp_new_peer_evt(vdev, peer_ind); + + osif_debug("vdev_id: %d, peer_mac: "QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(peer_ind->peer_mac_addr.bytes)); + ret = cb_obj.new_peer_ind(vdev_id, peer_ind->sta_id, + &peer_ind->peer_mac_addr, + (active_peers == 0 ? true : false)); + if (ret) { + osif_err("new peer handling at HDD failed %d", ret); + return; + } + + active_peers++; + ucfg_nan_set_active_peers(vdev, active_peers); + osif_debug("num_peers: %d", active_peers); +} + +/** + * os_if_ndp_end_all_handler: Handler for NDP_END_ALL request cmd + * @vdev: pointer to vdev object + * + * Return: None + */ +static void os_if_ndp_end_all_handler(struct wlan_objmgr_vdev *vdev) +{ + struct nan_vdev_priv_obj *vdev_nan_obj; + struct osif_request *request; + + vdev_nan_obj = nan_get_vdev_priv_obj(vdev); + if (!vdev_nan_obj) { + osif_err("vdev_nan_obj is NULL"); + return; + } + + request = osif_request_get(vdev_nan_obj->disable_context); + if (!request) { + osif_debug("Obsolete request"); + return; + } + + osif_request_complete(request); + osif_request_put(request); +} + +/** + * os_if_peer_departed_ind_handler() - Handle NDP peer departed indication + * @vdev: vdev object + * @peer_ind: indication parameters + * + * Return: none + */ +static void os_if_peer_departed_ind_handler(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind) +{ + QDF_STATUS status; + struct nan_callbacks cb_obj; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + uint32_t active_peers = ucfg_nan_get_active_peers(vdev); + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("failed to get callbacks"); + return; + } + + if (!peer_ind) { + osif_err("Invalid new NDP peer params"); + return; + } + osif_debug("vdev_id: %d, peer_mac: "QDF_MAC_ADDR_FMT, + vdev_id, QDF_MAC_ADDR_REF(peer_ind->peer_mac_addr.bytes)); + active_peers--; + ucfg_nan_set_active_peers(vdev, active_peers); + cb_obj.peer_departed_ind(vdev_id, peer_ind->sta_id, + &peer_ind->peer_mac_addr, + (active_peers == 0 ? true : false)); + + /* if no peer left, stop wait timer for NDP_END_ALL` */ + if (!active_peers) + os_if_ndp_end_all_handler(vdev); +} + +static inline uint32_t osif_ndp_get_ndi_create_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +/** + * os_if_ndp_iface_create_rsp_handler() - NDP iface create response handler + * @psoc: soc object + * @vdev: vdev object + * @rsp_params: response parameters + * + * The function is expected to send a response back to the user space + * even if the creation of BSS has failed + * + * Following vendor event is sent to cfg80211: + * QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD = + * QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID (2 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE (4 bytes) + * QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE + * + * Return: none + */ +static void os_if_ndp_iface_create_rsp_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + void *rsp_params) +{ + uint32_t data_len; + QDF_STATUS status; + bool create_fail = false; + struct nan_callbacks cb_obj; + struct sk_buff *vendor_event; + uint16_t create_transaction_id; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + uint32_t create_status = NAN_DATAPATH_RSP_STATUS_ERROR; + uint32_t create_reason = NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED; + struct nan_datapath_inf_create_rsp *ndi_rsp = + (struct nan_datapath_inf_create_rsp *)rsp_params; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Couldn't get ballback object"); + return; + } + + if (ndi_rsp) { + create_status = ndi_rsp->status; + create_reason = ndi_rsp->reason; + } else { + osif_debug("Invalid ndi create response"); + create_fail = true; + } + + create_transaction_id = ucfg_nan_get_ndp_create_transaction_id(vdev); + data_len = osif_ndp_get_ndi_create_rsp_len(); + /* notify response to the upper layer */ + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_KERNEL); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + create_fail = true; + goto close_ndi; + } + + /* Sub vendor command */ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_CREATE)) { + osif_err("QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD put fail"); + goto nla_put_failure; + } + + /* Transaction id */ + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + create_transaction_id)) { + osif_err("VENDOR_ATTR_NDP_TRANSACTION_ID put fail"); + goto nla_put_failure; + } + + /* Status code */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + create_status)) { + osif_err("VENDOR_ATTR_NDP_DRV_RETURN_TYPE put fail"); + goto nla_put_failure; + } + + /* Status return value */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + create_reason)) { + osif_err("VENDOR_ATTR_NDP_DRV_RETURN_VALUE put fail"); + goto nla_put_failure; + } + + osif_debug("transaction id: %u status code: %u Reason: %u", + create_transaction_id, create_status, create_reason); + + if (!create_fail) { + /* update txrx queues and register self sta */ + cb_obj.drv_ndi_create_rsp_handler(wlan_vdev_get_id(vdev), + ndi_rsp); + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + } else { + osif_err("NDI interface creation failed with reason %d", + create_reason); + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + goto close_ndi; + } + + return; + +nla_put_failure: + wlan_cfg80211_vendor_free_skb(vendor_event); +close_ndi: + cb_obj.ndi_close(wlan_vdev_get_id(vdev)); + return; +} + +/** + * os_if_ndp_iface_delete_rsp_handler() - NDP iface delete response handler + * @psoc: soc object + * @vdev: vdev object + * @rsp_params: response parameters + * + * Return: none + */ +static void os_if_ndp_iface_delete_rsp_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + void *rsp_params) +{ + QDF_STATUS status; + uint8_t vdev_id = wlan_vdev_get_id(vdev); + struct nan_datapath_inf_delete_rsp *ndi_rsp = rsp_params; + struct nan_callbacks cb_obj; + + if (!ndi_rsp) { + osif_err("Invalid ndi delete response"); + return; + } + + status = ucfg_nan_get_callbacks(psoc, &cb_obj); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Couldn't get ballback object"); + return; + } + + if (ndi_rsp->status == NAN_DATAPATH_RSP_STATUS_SUCCESS) + osif_debug("NDI BSS successfully stopped"); + else + osif_debug("NDI BSS stop failed with reason %d", + ndi_rsp->reason); + + os_if_cstats_log_ndi_delete_resp_evt(vdev, ndi_rsp); + + ucfg_nan_set_ndi_delete_rsp_reason(vdev, ndi_rsp->reason); + ucfg_nan_set_ndi_delete_rsp_status(vdev, ndi_rsp->status); + cb_obj.drv_ndi_delete_rsp_handler(vdev_id); +} + +static inline uint32_t osif_ndp_get_ndp_sch_update_ind_len( + struct nan_datapath_sch_update_event *sch_update) +{ + uint32_t ch_info_len = 0; + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR].len); + if (sch_update->num_ndp_instances) + data_len += nla_total_size(sch_update->num_ndp_instances * + sizeof(uint32_t)); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS].len); + /* ch_info is a nested array of following attributes */ + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH].len); + ch_info_len += nla_total_size( + vendor_attr_policy[QCA_WLAN_VENDOR_ATTR_NDP_NSS].len); + + if (sch_update->num_ndp_instances) + data_len += sch_update->num_ndp_instances * + nla_total_size(ch_info_len); + + return data_len; +} + +static QDF_STATUS os_if_ndp_sch_update_pack_ch_info(struct sk_buff *event, + struct nan_datapath_sch_update_event *sch_update) +{ + int idx = 0; + struct nlattr *ch_array, *ch_element; + + osif_debug("num_ch: %d", sch_update->num_channels); + if (!sch_update->num_channels) + return QDF_STATUS_SUCCESS; + + ch_array = nla_nest_start(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_INFO); + if (!ch_array) + return QDF_STATUS_E_FAULT; + + for (idx = 0; idx < sch_update->num_channels; idx++) { + osif_debug("ch[%d]: freq: %d, width: %d, nss: %d", + idx, sch_update->ch[idx].freq, + sch_update->ch[idx].ch_width, + sch_update->ch[idx].nss); + ch_element = nla_nest_start(event, idx); + if (!ch_element) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL, + sch_update->ch[idx].freq)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_CHANNEL_WIDTH, + sch_update->ch[idx].ch_width)) + return QDF_STATUS_E_FAULT; + + if (nla_put_u32(event, QCA_WLAN_VENDOR_ATTR_NDP_NSS, + sch_update->ch[idx].nss)) + return QDF_STATUS_E_FAULT; + nla_nest_end(event, ch_element); + } + nla_nest_end(event, ch_array); + + return QDF_STATUS_SUCCESS; +} + +/** + * os_if_ndp_sch_update_ind_handler() - NDP schedule update handler + * @vdev: vdev object pointer + * @ind: sch update pointer + * + * Following vendor event is sent to cfg80211: + * + * Return: none + */ +static void os_if_ndp_sch_update_ind_handler(struct wlan_objmgr_vdev *vdev, + void *ind) +{ + int idx = 0; + const uint8_t *ifname; + QDF_STATUS status; + uint32_t data_len; + uint8_t ifname_len; + struct sk_buff *vendor_event; + struct nan_datapath_sch_update_event *sch_update = ind; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + if (!sch_update) { + osif_err("Invalid sch update params"); + return; + } + + ifname = os_if_ndi_get_if_name(vdev); + if (!ifname) { + osif_err("ifname is null"); + return; + } + ifname_len = qdf_str_len(ifname); + if (ifname_len > IFNAMSIZ) { + osif_err("ifname(%d) too long", ifname_len); + return; + } + + data_len = osif_ndp_get_ndp_sch_update_ind_len(sch_update); + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_ATOMIC); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_IND)) + goto ndp_sch_ind_nla_failed; + + if (nla_put(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_PEER_DISCOVERY_MAC_ADDR, + QDF_MAC_ADDR_SIZE, sch_update->peer_addr.bytes)) + goto ndp_sch_ind_nla_failed; + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_INSTANCE_ID_ARRAY, + sch_update->num_ndp_instances * sizeof(uint32_t), + sch_update->ndp_instances)) + goto ndp_sch_ind_nla_failed; + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_SCHEDULE_UPDATE_REASON, + sch_update->flags)) + goto ndp_sch_ind_nla_failed; + + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_NUM_CHANNELS, + sch_update->num_channels)) + goto ndp_sch_ind_nla_failed; + + status = os_if_ndp_sch_update_pack_ch_info(vendor_event, sch_update); + if (QDF_IS_STATUS_ERROR(status)) + goto ndp_sch_ind_nla_failed; + + osif_debug("Flags: %d, num_instance_id: %d", sch_update->flags, + sch_update->num_ndp_instances); + + for (idx = 0; idx < sch_update->num_ndp_instances; idx++) + osif_debug("ndp_instance[%d]: %d", idx, + sch_update->ndp_instances[idx]); + + wlan_cfg80211_vendor_event(vendor_event, GFP_ATOMIC); + return; + +ndp_sch_ind_nla_failed: + osif_err("nla_put api failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +static void os_if_nan_datapath_event_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev, + uint32_t type, void *msg) +{ + switch (type) { + case NAN_DATAPATH_INF_CREATE_RSP: + os_if_ndp_iface_create_rsp_handler(psoc, vdev, msg); + break; + case NAN_DATAPATH_INF_DELETE_RSP: + os_if_ndp_iface_delete_rsp_handler(psoc, vdev, msg); + break; + case NDP_CONFIRM: + os_if_ndp_confirm_ind_handler(vdev, msg); + break; + case NDP_INITIATOR_RSP: + os_if_ndp_initiator_rsp_handler(vdev, msg); + break; + case NDP_INDICATION: + os_if_ndp_indication_handler(vdev, msg); + break; + case NDP_NEW_PEER: + os_if_new_peer_ind_handler(vdev, msg); + break; + case NDP_RESPONDER_RSP: + os_if_ndp_responder_rsp_handler(vdev, msg); + break; + case NDP_END_RSP: + os_if_ndp_end_rsp_handler(vdev, msg); + break; + case NDP_END_IND: + os_if_ndp_end_ind_handler(vdev, msg); + break; + case NDP_PEER_DEPARTED: + os_if_peer_departed_ind_handler(vdev, msg); + break; + case NDP_SCHEDULE_UPDATE: + os_if_ndp_sch_update_ind_handler(vdev, msg); + break; + default: + break; + } +} + +int os_if_nan_register_lim_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + return ucfg_nan_register_lim_callbacks(psoc, cb_obj); +} + +void os_if_nan_post_ndi_create_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ + struct nan_datapath_inf_create_rsp rsp = {0}; + struct wlan_objmgr_vdev *vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id, WLAN_NAN_ID); + + if (!vdev) { + osif_err("vdev is null"); + return; + } + + if (success) { + rsp.status = NAN_DATAPATH_RSP_STATUS_SUCCESS; + rsp.reason = 0; + os_if_nan_datapath_event_handler(psoc, vdev, + NAN_DATAPATH_INF_CREATE_RSP, + &rsp); + } else { + rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + rsp.reason = NAN_DATAPATH_NAN_DATA_IFACE_CREATE_FAILED; + os_if_nan_datapath_event_handler(psoc, vdev, + NAN_DATAPATH_INF_CREATE_RSP, + &rsp); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); +} + +void os_if_nan_post_ndi_delete_rsp(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, bool success) +{ + struct nan_datapath_inf_delete_rsp rsp = {0}; + struct wlan_objmgr_vdev *vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id, WLAN_NAN_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + if (success) { + rsp.status = NAN_DATAPATH_RSP_STATUS_SUCCESS; + rsp.reason = 0; + os_if_nan_datapath_event_handler(psoc, vdev, + NAN_DATAPATH_INF_DELETE_RSP, + &rsp); + } else { + rsp.status = NAN_DATAPATH_RSP_STATUS_ERROR; + rsp.reason = NAN_DATAPATH_NAN_DATA_IFACE_DELETE_FAILED; + os_if_nan_datapath_event_handler(psoc, vdev, + NAN_DATAPATH_INF_DELETE_RSP, + &rsp); + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); +} + +static inline uint32_t osif_ndp_get_ndi_delete_rsp_len(void) +{ + uint32_t data_len = NLMSG_HDRLEN; + + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE].len); + data_len += nla_total_size(vendor_attr_policy[ + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE].len); + + return data_len; +} + +void os_if_nan_ndi_session_end(struct wlan_objmgr_vdev *vdev) +{ + uint32_t data_len; + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev = wlan_vdev_get_pdev(vdev); + struct pdev_osif_priv *os_priv = wlan_pdev_get_ospriv(pdev); + enum nan_datapath_state state; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NDP_INDEX; + + /* + * The virtual adapters are stopped and closed even during + * driver unload or stop, the service layer is not required + * to be informed in that case (response is not expected) + */ + state = ucfg_nan_get_ndi_state(vdev); + + /* + * With NDP Delete Vendor command, hdd_ndi_delete function modifies NDI + * state to delete "NAN_DATA_NDI_DELETING_STATE". + * But when user issues DEL Virtual Intf cmd, hdd_ndi_delete does not + * call and NDI state remains to created "NAN_DATA_NDI_CREATED_STATE". + */ + if (state == NAN_DATA_NDI_CREATED_STATE) { + osif_debug("NDI interface is just created: %u", state); + return; + } else if (state != NAN_DATA_NDI_DELETING_STATE && + state != NAN_DATA_DISCONNECTED_STATE) { + osif_err("NDI interface deleted: state: %u", state); + return; + } + + data_len = osif_ndp_get_ndi_delete_rsp_len(); + /* notify response to the upper layer */ + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, NULL, + data_len, index, + GFP_KERNEL); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + return; + } + + /* Sub vendor command goes first */ + if (nla_put_u32(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_SUBCMD, + QCA_WLAN_VENDOR_ATTR_NDP_INTERFACE_DELETE)) { + osif_err("VENDOR_ATTR_NDP_SUBCMD put fail"); + goto failure; + } + + /* Transaction id */ + if (nla_put_u16(vendor_event, QCA_WLAN_VENDOR_ATTR_NDP_TRANSACTION_ID, + ucfg_nan_get_ndp_delete_transaction_id(vdev))) { + osif_err("VENDOR_ATTR_NDP_TRANSACTION_ID put fail"); + goto failure; + } + + /* Status code */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RESPONSE_STATUS_TYPE, + ucfg_nan_get_ndi_delete_rsp_status(vdev))) { + osif_err("VENDOR_ATTR_NDP_DRV_RETURN_TYPE put fail"); + goto failure; + } + + /* Status return value */ + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_NDP_DRV_RETURN_VALUE, + ucfg_nan_get_ndi_delete_rsp_reason(vdev))) { + osif_err("VENDOR_ATTR_NDP_DRV_RETURN_VALUE put fail"); + goto failure; + } + + osif_debug("delete transaction id: %u, status code: %u reason: %u", + ucfg_nan_get_ndp_delete_transaction_id(vdev), + ucfg_nan_get_ndi_delete_rsp_status(vdev), + ucfg_nan_get_ndi_delete_rsp_reason(vdev)); + + ucfg_nan_set_ndp_delete_transaction_id(vdev, 0); + ucfg_nan_set_ndi_state(vdev, NAN_DATA_NDI_DELETED_STATE); + ucfg_ndi_remove_entry_from_policy_mgr(vdev); + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + + return; +failure: + wlan_cfg80211_vendor_free_skb(vendor_event); +} + +/** + * os_if_nan_handle_sr_nan_concurrency() - Handle NAN concurrency for Spatial + * Reuse + * @nan_evt: NAN Event parameters + * + * Module calls callback to send SR event to userspace. + * + * Return: none + */ +#ifdef WLAN_FEATURE_SR +static void +os_if_nan_handle_sr_nan_concurrency(struct nan_event_params *nan_evt) { + void (*nan_sr_conc_callback)(struct nan_event_params *nan_evt); + struct nan_psoc_priv_obj *psoc_obj = + nan_get_psoc_priv_obj(nan_evt->psoc); + + if (!psoc_obj) { + nan_err("nan psoc priv object is NULL"); + return; + } + + nan_sr_conc_callback = psoc_obj->cb_obj.nan_sr_concurrency_update; + if (nan_sr_conc_callback) + nan_sr_conc_callback(nan_evt); +} +#else +static void +os_if_nan_handle_sr_nan_concurrency(struct nan_event_params *nan_evt) +{} +#endif + +/** + * os_if_nan_discovery_event_handler() - NAN Discovery Interface event handler + * @nan_evt: NAN Event parameters + * + * Module sends a NAN related vendor event to the upper layer + * + * Return: none + */ +static void os_if_nan_discovery_event_handler(struct nan_event_params *nan_evt) +{ + struct sk_buff *vendor_event; + struct wlan_objmgr_pdev *pdev; + struct pdev_osif_priv *os_priv; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_NAN_INDEX; + struct wireless_dev *wdev; + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev = NULL; + + /* + * Since Partial Offload chipsets have only one pdev per psoc, the first + * pdev from the pdev list is used. + */ + pdev = wlan_objmgr_get_pdev_by_id(nan_evt->psoc, 0, WLAN_NAN_ID); + if (!pdev) { + osif_err("null pdev"); + return; + } + os_if_nan_handle_sr_nan_concurrency(nan_evt); + + os_priv = wlan_pdev_get_ospriv(pdev); + if (!os_priv) { + osif_err(" pdev osif priv is null"); + goto fail; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, nan_evt->vdev_id, + WLAN_NAN_ID); + if (!vdev) { + osif_err("vdev is null"); + goto fail; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(os_priv->wiphy, wdev, + nan_evt->buf_len + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + goto fail; + } + + if (nla_put(vendor_event, QCA_WLAN_VENDOR_ATTR_NAN, nan_evt->buf_len, + nan_evt->buf)) { + osif_err("QCA_WLAN_VENDOR_ATTR_NAN put failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); + goto fail; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); +fail: + if (vdev) + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_NAN_ID); +} + +int os_if_nan_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct nan_callbacks *cb_obj) +{ + cb_obj->os_if_ndp_event_handler = os_if_nan_datapath_event_handler; + cb_obj->os_if_nan_event_handler = os_if_nan_discovery_event_handler; + return ucfg_nan_register_hdd_callbacks(psoc, cb_obj); +} + +static int os_if_nan_generic_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + struct nan_generic_req *nan_req; + uint32_t buf_len; + QDF_STATUS status; + + buf_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA]); + + nan_req = qdf_mem_malloc(sizeof(*nan_req) + buf_len); + if (!nan_req) + return -ENOMEM; + qdf_mem_zero(nan_req, sizeof(*nan_req) + buf_len); + + nan_req->psoc = psoc; + nan_req->params.request_data_len = buf_len; + nla_memcpy(nan_req->params.request_data, + tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA], buf_len); + + status = ucfg_nan_discovery_req(nan_req, NAN_GENERIC_REQ); + + if (QDF_IS_STATUS_SUCCESS(status)) + osif_debug("Successfully sent a NAN request"); + else + osif_err("Unable to send a NAN request"); + + qdf_mem_free(nan_req); + return qdf_status_to_os_return(status); +} + +static int os_if_process_nan_disable_req(struct wlan_objmgr_psoc *psoc, + struct nlattr **tb) +{ + uint8_t *data; + uint32_t data_len; + QDF_STATUS status; + + data = nla_data(tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA]); + data_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA]); + + status = ucfg_disable_nan_discovery(psoc, data, data_len); + + return qdf_status_to_os_return(status); +} + +static int os_if_process_nan_enable_req(struct wlan_objmgr_pdev *pdev, + struct nlattr **tb, uint8_t vdev_id) +{ + uint32_t chan_freq_2g, chan_freq_5g = 0; + uint32_t buf_len; + QDF_STATUS status; + uint32_t fine_time_meas_cap; + struct nan_enable_req *nan_req; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!tb[QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ]) { + osif_err("NAN Social channel for 2.4Gz is unavailable!"); + return -EINVAL; + } + chan_freq_2g = + nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NAN_DISC_24GHZ_BAND_FREQ]); + + if (tb[QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ]) + chan_freq_5g = + nla_get_u32(tb[ + QCA_WLAN_VENDOR_ATTR_NAN_DISC_5GHZ_BAND_FREQ]); + + if (!ucfg_is_nan_enable_allowed(psoc, chan_freq_2g, vdev_id)) { + osif_err("NAN Enable not allowed at this moment for channel %d", + chan_freq_2g); + return -EINVAL; + } + + buf_len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA]); + + nan_req = qdf_mem_malloc(sizeof(*nan_req) + buf_len); + if (!nan_req) + return -ENOMEM; + + nan_req->social_chan_2g_freq = chan_freq_2g; + if (chan_freq_5g) + nan_req->social_chan_5g_freq = chan_freq_5g; + nan_req->psoc = psoc; + nan_req->pdev = pdev; + nan_req->params.request_data_len = buf_len; + + ucfg_mlme_get_fine_time_meas_cap(psoc, &fine_time_meas_cap); + nan_req->params.rtt_cap = fine_time_meas_cap; + nan_req->params.disable_6g_nan = ucfg_get_disable_6g_nan(psoc); + + nla_memcpy(nan_req->params.request_data, + tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA], buf_len); + + osif_debug("Sending NAN Enable Req. NAN Ch Freq: %d %d", + nan_req->social_chan_2g_freq, nan_req->social_chan_5g_freq); + status = ucfg_nan_discovery_req(nan_req, NAN_ENABLE_REQ); + + if (QDF_IS_STATUS_SUCCESS(status)) { + osif_debug("Successfully sent NAN Enable request"); + os_if_cstats_log_nan_disc_enable_req_evt(vdev_id, nan_req); + } else { + osif_err("Unable to send NAN Enable request"); + } + + qdf_mem_free(nan_req); + return qdf_status_to_os_return(status); +} + +int os_if_process_nan_req(struct wlan_objmgr_pdev *pdev, uint8_t vdev_id, + const void *data, int data_len) +{ + uint32_t nan_subcmd; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX + 1]; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (wlan_cfg80211_nla_parse(tb, QCA_WLAN_VENDOR_ATTR_NAN_PARAMS_MAX, + data, data_len, nan_attr_policy)) { + osif_err("Invalid NAN vendor command attributes"); + return -EINVAL; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_NAN_CMD_DATA]) { + osif_err("NAN cmd data missing!"); + return -EINVAL; + } + + /* + * If target does not support NAN DBS, stop the opportunistic timer. + * Opportunistic timer gets triggered as soon as a DBS use case is + * completed and hw_mode would be set to SMM when the timer(5 seconds) + * expires. + * This is to make sure that HW mode is not set to DBS by NAN Enable + * request. NAN state machine will remain unaffected in this case. + */ + if (!NAN_CONCURRENCY_SUPPORTED(psoc)) + policy_mgr_check_and_stop_opportunistic_timer(psoc, vdev_id); + + /* + * Send all requests other than Enable/Disable as type GENERIC. + * These will be treated as passthrough by the driver. + */ + if (!tb[QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE]) + return os_if_nan_generic_req(psoc, tb); + + nan_subcmd = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_NAN_SUBCMD_TYPE]); + + switch (nan_subcmd) { + case QCA_WLAN_NAN_EXT_SUBCMD_TYPE_ENABLE_REQ: + return os_if_process_nan_enable_req(pdev, tb, vdev_id); + case QCA_WLAN_NAN_EXT_SUBCMD_TYPE_DISABLE_REQ: + os_if_cstats_log_disable_nan_disc_evt(pdev, vdev_id); + return os_if_process_nan_disable_req(psoc, tb); + default: + osif_err("Unrecognized NAN subcmd type(%d)", nan_subcmd); + return -EINVAL; + } +} + +#ifdef WLAN_CHIPSET_STATS +void +os_if_cstats_log_ndp_initiator_req_evt(struct nan_datapath_initiator_req *req) +{ + struct cstats_nan_ndp_initiator_req stat = {0}; + struct wlan_objmgr_vdev *vdev; + + vdev = req->vdev; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_INITIATOR_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_initiator_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.transaction_id = req->transaction_id; + stat.channel = req->channel; + stat.channel_cfg = req->channel_cfg; + stat.service_instance_id = req->service_instance_id; + CSTATS_MAC_COPY(stat.self_ndi_mac_addr, req->self_ndi_mac_addr.bytes); + CSTATS_MAC_COPY(stat.peer_discovery_mac_addr, + req->peer_discovery_mac_addr.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_initiator_req), + &stat); +} + +void +os_if_cstats_log_ndp_responder_req_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_req *req) +{ + struct cstats_nan_ndp_responder_req stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_RESPONDER_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_responder_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.transaction_id = req->transaction_id; + stat.ndp_instance_id = req->ndp_instance_id; + stat.ndp_rsp = req->ndp_rsp; + stat.ncs_sk_type = req->ncs_sk_type; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_responder_req), + &stat); +} + +void os_if_cstats_log_ndp_end_req_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_req *rq) +{ + struct cstats_nan_ndp_end_req stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_END_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_end_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.transaction_id = rq->transaction_id; + stat.num_ndp_instances = rq->num_ndp_instances; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_end_req), &stat); +} + +void +os_if_cstats_log_ndp_initiator_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_initiator_rsp *rsp) +{ + struct cstats_nan_ndp_initiator_resp stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_INITIATOR_RSP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_initiator_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.status = rsp->status; + stat.reason = rsp->reason; + stat.transaction_id = rsp->transaction_id; + stat.service_instance_id = rsp->ndp_instance_id; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_initiator_resp), + &stat); +} + +void +os_if_cstats_log_ndp_responder_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_responder_rsp *rsp) +{ + struct cstats_nan_ndp_responder_resp stat = {0}; + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_NAN_NDP_RESPONDER_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_tdls_disc_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.status = rsp->status; + stat.reason = rsp->reason; + stat.transaction_id = rsp->transaction_id; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_responder_resp), + &stat); +} + +void +os_if_cstats_log_ndp_indication_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_indication_event *evt) +{ + struct cstats_nan_ndp_ind stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_INDICATION_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_ind) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.ndp_instance_id = evt->ndp_instance_id; + stat.service_instance_id = evt->service_instance_id; + CSTATS_MAC_COPY(stat.peer_mac, evt->peer_mac_addr.bytes); + CSTATS_MAC_COPY(stat.peer_discovery_mac_addr, + evt->peer_discovery_mac_addr.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_ind), &stat); +} + +void +os_if_cstats_log_ndp_confirm_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_confirm_event *nc) +{ + struct cstats_nan_ndp_confirm_ind stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_CONFIRM_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_confirm_ind) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.instance_id = nc->ndp_instance_id; + stat.rsp_code = nc->rsp_code; + stat.reason_code = nc->reason_code; + CSTATS_MAC_COPY(stat.peer_addr, nc->peer_ndi_mac_addr.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_confirm_ind), + &stat); +} + +void +os_if_cstats_log_ndp_end_rsp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_end_rsp_event *rsp) +{ + struct cstats_nan_ndp_end_resp stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_END_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_end_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.status = rsp->status; + stat.reason = rsp->reason; + stat.transaction_id = rsp->transaction_id; + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_end_resp), &stat); +} + +void +os_if_cstats_log_ndp_new_peer_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_peer_ind *peer_ind) +{ + struct cstats_nan_ndp_new_peer_ind stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDP_NEW_PEER_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndp_new_peer_ind) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.sta_id = peer_ind->sta_id; + CSTATS_MAC_COPY(stat.peer_mac, peer_ind->peer_mac_addr.bytes); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndp_new_peer_ind), + &stat); +} + +void +os_if_cstats_log_ndi_delete_resp_evt(struct wlan_objmgr_vdev *vdev, + struct nan_datapath_inf_delete_rsp *rsp) +{ + struct cstats_nan_ndi_delete_resp stat = {0}; + + stat.cmn.hdr.evt_id = WLAN_CHIPSET_STATS_NAN_NDI_DELETE_RESP_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_ndi_delete_resp) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.status = rsp->status; + stat.reason = rsp->reason; + stat.transaction_id = ucfg_nan_get_ndp_delete_transaction_id(vdev); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_ndi_delete_resp), + &stat); +} + +void os_if_cstats_log_nan_disc_enable_req_evt(uint8_t vdev_id, + struct nan_enable_req *nan_req) +{ + struct cstats_nan_disc_enable stat = {0}; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(nan_req->pdev, + vdev_id, WLAN_NAN_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_NAN_DISCOVERY_ENABLE_REQ_EVENT_ID; + stat.cmn.hdr.length = + sizeof(struct cstats_nan_disc_enable) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + stat.social_chan_2g_freq = nan_req->social_chan_2g_freq; + stat.social_chan_5g_freq = nan_req->social_chan_5g_freq; + stat.rtt_cap = nan_req->params.rtt_cap; + stat.disable_6g_nan = nan_req->params.disable_6g_nan; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_enable), &stat); +} + +void +os_if_cstats_log_disable_nan_disc_evt(struct wlan_objmgr_pdev *pdev, + uint8_t vdev_id) +{ + struct cstats_nan_disc_disable_req stat = {0}; + struct wlan_objmgr_vdev *vdev = NULL; + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, WLAN_NAN_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + stat.cmn.hdr.evt_id = + WLAN_CHIPSET_STATS_NAN_DISCOVERY_DISABLE_REQ_EVENT_ID; + stat.cmn.hdr.length = sizeof(struct cstats_nan_disc_disable_req) - + sizeof(struct cstats_hdr); + stat.cmn.opmode = wlan_vdev_mlme_get_opmode(vdev); + stat.cmn.vdev_id = wlan_vdev_get_id(vdev); + stat.cmn.timestamp_us = qdf_get_time_of_the_day_us(); + stat.cmn.time_tick = qdf_get_log_timestamp(); + + stat.disable_2g_discovery = 1; + stat.disable_5g_discovery = 1; + + wlan_objmgr_vdev_release_ref(vdev, WLAN_NAN_ID); + + wlan_cstats_host_stats(sizeof(struct cstats_nan_disc_disable_req), + &stat); +} +#endif /* WLAN_CHIPSET_STATS */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/p2p/inc/wlan_cfg80211_p2p.h b/qcom/opensource/wlan/qcacld-3.0/os_if/p2p/inc/wlan_cfg80211_p2p.h new file mode 100644 index 0000000000..87cf0feaea --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/p2p/inc/wlan_cfg80211_p2p.h @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declares P2P functions interfacing with linux kernel + */ + +#ifndef _WLAN_CFG80211_P2P_H_ +#define _WLAN_CFG80211_P2P_H_ + +#include + +struct wlan_objmgr_psoc; +struct wlan_objmgr_vdev; +struct ieee80211_channel; + +/** + * p2p_psoc_enable() - psoc API to enable p2p component + * @psoc: soc object + * + * This function used to enable P2P component and register events. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_psoc_enable(struct wlan_objmgr_psoc *psoc); + +/** + * p2p_psoc_disable() - psoc API to disable p2p component + * @psoc: soc object + * + * This function used to disable P2P component and unregister events. + * + * Return: QDF_STATUS_SUCCESS - in case of success + */ +QDF_STATUS p2p_psoc_disable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_cfg80211_roc() - API to process cfg80211 roc request + * @vdev: Pointer to vdev object + * @chan: Pointer to channel + * @duration: Duration for this roc request + * @cookie: Pointer to return cookie to up layer + * + * API to trigger remain on channel request. It returns cookie + * as the identifier of roc. + * + * Return: 0 for success, non zero for failure + */ +int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev, + struct ieee80211_channel *chan, uint32_t duration, + uint64_t *cookie); + +/** + * wlan_cfg80211_cancel_roc() - API to process cfg80211 cancel remain + * on channel request + * @vdev: Pointer to vdev object + * @cookie: Find out the roc request by cookie + * + * API to trigger cancel remain on channel request. + * + * Return: 0 for success, non zero for failure + */ +int wlan_cfg80211_cancel_roc(struct wlan_objmgr_vdev *vdev, + uint64_t cookie); + +/** + * wlan_cfg80211_mgmt_tx() - API to process cfg80211 mgmt tx request + * @vdev: Pointer to vdev object + * @chan: Pointer to channel + * @offchan: true if this is an off-channel frame + * @wait: wait time for this mgmt tx request + * @buf: TX buffer + * @len: Length of tx buffer + * @no_cck: Required cck or not + * @dont_wait_for_ack: Wait for ack or not + * @cookie: Return the cookie to caller + * + * API to trigger mgmt frame tx request. It returns cookie as the + * identifier of this tx. + * + * Return: 0 for success, non zero for failure + */ +int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, + struct ieee80211_channel *chan, bool offchan, uint32_t wait, + const uint8_t *buf, uint32_t len, bool no_cck, + bool dont_wait_for_ack, uint64_t *cookie); + +/** + * wlan_cfg80211_mgmt_tx_cancel() - API to process cfg80211 cancel to + * wait mgmt tx + * @vdev: Pointer to vdev object + * @cookie: Find out the mgmt tx request by cookie + * + * API to trigger cancel mgmt frame tx request. + * + * Return: 0 for success, non zero for failure + */ +int wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev *vdev, + uint64_t cookie); + +#endif /* _WLAN_CFG80211_P2P_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/p2p/src/wlan_cfg80211_p2p.c b/qcom/opensource/wlan/qcacld-3.0/os_if/p2p/src/wlan_cfg80211_p2p.c new file mode 100644 index 0000000000..59396ab078 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/p2p/src/wlan_cfg80211_p2p.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_cfg80211.h" +#include "wlan_cfg80211_p2p.h" +#include "wlan_mlo_mgr_sta.h" + +#define MAX_NO_OF_2_4_CHANNELS 14 +#define MAX_OFFCHAN_TIME_FOR_DNBS 150 + +/** + * wlan_p2p_rx_callback() - Callback for rx mgmt frame + * @user_data: pointer to soc object + * @rx_frame: RX mgmt frame information + * + * This callback will be used to rx frames in os interface. + * + * Return: None + */ +static void wlan_p2p_rx_callback(void *user_data, + struct p2p_rx_mgmt_frame *rx_frame) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev, *assoc_vdev; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + enum QDF_OPMODE opmode; + + psoc = user_data; + if (!psoc) { + osif_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + rx_frame->vdev_id, WLAN_P2P_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + assoc_vdev = vdev; + opmode = wlan_vdev_mlme_get_opmode(assoc_vdev); + + if (opmode == QDF_STA_MODE && wlan_vdev_mlme_is_mlo_vdev(vdev)) { + assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); + if (!assoc_vdev) { + osif_err("Assoc vdev is NULL"); + goto fail; + } + } + + osif_priv = wlan_vdev_get_ospriv(assoc_vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wdev is null"); + goto fail; + } + + osif_debug("Indicate frame over nl80211, idx:%d", + wdev->netdev->ifindex); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, + NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, + NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); +} + +/** + * wlan_p2p_action_tx_cnf_callback() - Callback for tx confirmation + * @user_data: pointer to soc object + * @tx_cnf: tx confirmation information + * + * This callback will be used to give tx mgmt frame confirmation to + * os interface. + * + * Return: None + */ +static void wlan_p2p_action_tx_cnf_callback(void *user_data, + struct p2p_tx_cnf *tx_cnf) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + bool is_success; + + psoc = user_data; + if (!psoc) { + osif_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + tx_cnf->vdev_id, WLAN_P2P_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + is_success = tx_cnf->status ? false : true; + cfg80211_mgmt_tx_status( + wdev, + tx_cnf->action_cookie, + tx_cnf->buf, tx_cnf->buf_len, + is_success, GFP_KERNEL); +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); +} + +#ifdef FEATURE_P2P_LISTEN_OFFLOAD +/** + * wlan_p2p_lo_event_callback() - Callback for listen offload event + * @user_data: pointer to soc object + * @p2p_lo_event: listen offload event information + * + * This callback will be used to give listen offload event to os interface. + * + * Return: None + */ +static void wlan_p2p_lo_event_callback(void *user_data, + struct p2p_lo_event *p2p_lo_event) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + struct sk_buff *vendor_event; + enum qca_nl80211_vendor_subcmds_index index = + QCA_NL80211_VENDOR_SUBCMD_P2P_LO_EVENT_INDEX; + + osif_debug("user data:%pK, vdev id:%d, reason code:%d", + user_data, p2p_lo_event->vdev_id, + p2p_lo_event->reason_code); + + psoc = user_data; + if (!psoc) { + osif_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + p2p_lo_event->vdev_id, WLAN_P2P_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + vendor_event = wlan_cfg80211_vendor_event_alloc(wdev->wiphy, NULL, + sizeof(uint32_t) + + NLMSG_HDRLEN, + index, GFP_KERNEL); + if (!vendor_event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + goto fail; + } + + if (nla_put_u32(vendor_event, + QCA_WLAN_VENDOR_ATTR_P2P_LISTEN_OFFLOAD_STOP_REASON, + p2p_lo_event->reason_code)) { + osif_err("nla put failed"); + wlan_cfg80211_vendor_free_skb(vendor_event); + goto fail; + } + + wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); +} + +static inline void wlan_p2p_init_lo_event(struct p2p_start_param *start_param, + struct wlan_objmgr_psoc *psoc) +{ + start_param->lo_event_cb = wlan_p2p_lo_event_callback; + start_param->lo_event_cb_data = psoc; +} +#else +static inline void wlan_p2p_init_lo_event(struct p2p_start_param *start_param, + struct wlan_objmgr_psoc *psoc) +{ +} +#endif /* FEATURE_P2P_LISTEN_OFFLOAD */ +/** + * wlan_p2p_event_callback() - Callback for P2P event + * @user_data: pointer to soc object + * @p2p_event: p2p event information + * + * This callback will be used to give p2p event to os interface. + * + * Return: None + */ +static void wlan_p2p_event_callback(void *user_data, + struct p2p_event *p2p_event) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev; + struct ieee80211_channel *chan; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + struct wlan_objmgr_pdev *pdev; + + osif_debug("user data:%pK, vdev id:%d, event type:%d", + user_data, p2p_event->vdev_id, p2p_event->roc_event); + + psoc = user_data; + if (!psoc) { + osif_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + p2p_event->vdev_id, WLAN_P2P_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + pdev = wlan_vdev_get_pdev(vdev); + chan = ieee80211_get_channel(wdev->wiphy, p2p_event->chan_freq); + if (!chan) { + osif_err("channel conversion failed"); + goto fail; + } + + if (p2p_event->roc_event == ROC_EVENT_READY_ON_CHAN) { + cfg80211_ready_on_channel(wdev, + p2p_event->cookie, chan, + p2p_event->duration, GFP_KERNEL); + } else if (p2p_event->roc_event == ROC_EVENT_COMPLETED) { + cfg80211_remain_on_channel_expired(wdev, + p2p_event->cookie, chan, GFP_KERNEL); + } else { + osif_err("Invalid p2p event"); + } + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_P2P_ID); +} + +QDF_STATUS p2p_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + struct p2p_start_param start_param; + + if (!psoc) { + osif_err("psoc null"); + return QDF_STATUS_E_INVAL; + } + + start_param.rx_cb = wlan_p2p_rx_callback; + start_param.rx_cb_data = psoc; + start_param.event_cb = wlan_p2p_event_callback; + start_param.event_cb_data = psoc; + start_param.tx_cnf_cb = wlan_p2p_action_tx_cnf_callback; + start_param.tx_cnf_cb_data = psoc; + wlan_p2p_init_lo_event(&start_param, psoc); + + return ucfg_p2p_psoc_start(psoc, &start_param); +} + +QDF_STATUS p2p_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + if (!psoc) { + osif_err("psoc null"); + return QDF_STATUS_E_INVAL; + } + + return ucfg_p2p_psoc_stop(psoc); +} + +int wlan_cfg80211_roc(struct wlan_objmgr_vdev *vdev, + struct ieee80211_channel *chan, uint32_t duration, + uint64_t *cookie) +{ + struct p2p_roc_req roc_req = {0}; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + bool ok; + int ret; + struct wlan_objmgr_pdev *pdev = NULL; + + if (!vdev) { + osif_err("invalid vdev object"); + return -EINVAL; + } + + if (!chan) { + osif_err("invalid channel"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + pdev = wlan_vdev_get_pdev(vdev); + + if (!psoc) { + osif_err("psoc handle is NULL"); + return -EINVAL; + } + + roc_req.chan_freq = chan->center_freq; + roc_req.duration = duration; + roc_req.vdev_id = (uint32_t)vdev_id; + + ret = policy_mgr_is_chan_ok_for_dnbs(psoc, chan->center_freq, &ok); + if (QDF_IS_STATUS_ERROR(ret)) { + osif_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d", + ret); + return -EINVAL; + } + + if (!ok) { + osif_err("channel%d not OK for DNBS", roc_req.chan_freq); + return -EINVAL; + } + + return qdf_status_to_os_return( + ucfg_p2p_roc_req(psoc, &roc_req, cookie)); +} + +int wlan_cfg80211_cancel_roc(struct wlan_objmgr_vdev *vdev, + uint64_t cookie) +{ + struct wlan_objmgr_psoc *psoc; + + if (!vdev) { + osif_err("invalid vdev object"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("psoc handle is NULL"); + return -EINVAL; + } + + return qdf_status_to_os_return( + ucfg_p2p_roc_cancel_req(psoc, cookie)); +} + +int wlan_cfg80211_mgmt_tx(struct wlan_objmgr_vdev *vdev, + struct ieee80211_channel *chan, bool offchan, + unsigned int wait, + const uint8_t *buf, uint32_t len, bool no_cck, + bool dont_wait_for_ack, uint64_t *cookie) +{ + struct p2p_mgmt_tx mgmt_tx = {0}; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + qdf_freq_t chan_freq = 0; + struct wlan_objmgr_pdev *pdev = NULL; + if (!vdev) { + osif_err("invalid vdev object"); + return -EINVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (chan) + chan_freq = chan->center_freq; + else + osif_debug("NULL chan, set channel to 0"); + + psoc = wlan_vdev_get_psoc(vdev); + vdev_id = wlan_vdev_get_id(vdev); + if (!psoc) { + osif_err("psoc handle is NULL"); + return -EINVAL; + } + + /** + * When offchannel time is more than MAX_OFFCHAN_TIME_FOR_DNBS, + * allow offchannel only if Do_Not_Switch_Channel is not set. + */ + if (wait > MAX_OFFCHAN_TIME_FOR_DNBS) { + int ret; + bool ok; + + ret = policy_mgr_is_chan_ok_for_dnbs(psoc, chan_freq, &ok); + if (QDF_IS_STATUS_ERROR(ret)) { + osif_err("policy_mgr_is_chan_ok_for_dnbs():ret:%d", + ret); + return -EINVAL; + } + if (!ok) { + osif_err("Rejecting mgmt_tx for channel:%d as DNSC is set", + chan_freq); + return -EINVAL; + } + } + + mgmt_tx.vdev_id = (uint32_t)vdev_id; + mgmt_tx.chan_freq = chan_freq; + mgmt_tx.wait = wait; + mgmt_tx.len = len; + mgmt_tx.no_cck = (uint32_t)no_cck; + mgmt_tx.dont_wait_for_ack = (uint32_t)dont_wait_for_ack; + mgmt_tx.off_chan = (uint32_t)offchan; + mgmt_tx.buf = buf; + + return qdf_status_to_os_return( + ucfg_p2p_mgmt_tx(psoc, &mgmt_tx, cookie, pdev)); +} + +int wlan_cfg80211_mgmt_tx_cancel(struct wlan_objmgr_vdev *vdev, + uint64_t cookie) +{ + struct wlan_objmgr_psoc *psoc; + + if (!vdev) { + osif_err("invalid vdev object"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("psoc handle is NULL"); + return -EINVAL; + } + + return qdf_status_to_os_return( + ucfg_p2p_mgmt_tx_cancel(psoc, vdev, cookie)); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/pkt_capture/inc/os_if_pkt_capture.h b/qcom/opensource/wlan/qcacld-3.0/os_if/pkt_capture/inc/os_if_pkt_capture.h new file mode 100644 index 0000000000..1094bac841 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/pkt_capture/inc/os_if_pkt_capture.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2012-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OS_IF_PKT_CAPTURE_H_ +#define _OS_IF_PKT_CAPTURE_H_ + +#include "qdf_types.h" +#include "qca_vendor.h" +#include "wlan_hdd_main.h" + +#ifdef WLAN_FEATURE_PKT_CAPTURE + +#define os_if_pkt_enter() QDF_TRACE_ENTER(QDF_MODULE_ID_HDD, "enter") +#define os_if_pkt_exit() QDF_TRACE_EXIT(QDF_MODULE_ID_HDD, "exit") + +#define FEATURE_MONITOR_MODE_VENDOR_COMMANDS \ + { \ + .info.vendor_id = QCA_NL80211_VENDOR_ID, \ + .info.subcmd = QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE, \ + .flags = WIPHY_VENDOR_CMD_NEED_WDEV | \ + WIPHY_VENDOR_CMD_NEED_NETDEV | \ + WIPHY_VENDOR_CMD_NEED_RUNNING, \ + .doit = wlan_hdd_cfg80211_set_monitor_mode, \ + vendor_command_policy(set_monitor_mode_policy, \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MAX) \ + }, + +/* Short name for QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE command */ + +#define SET_MONITOR_MODE_CONFIG_MAX \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MAX +#define SET_MONITOR_MODE_INVALID \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_INVALID +#define SET_MONITOR_MODE_DATA_TX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_TX_FRAME_TYPE +#define SET_MONITOR_MODE_DATA_RX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_DATA_RX_FRAME_TYPE +#define SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE +#define SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE +#define SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE +#define SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE +#define SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL \ + QCA_WLAN_VENDOR_ATTR_SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL + +extern const struct nla_policy +set_monitor_mode_policy[SET_MONITOR_MODE_CONFIG_MAX + 1]; + +/** + * os_if_monitor_mode_configure() - Process monitor mode configuration + * operation in the received vendor command + * @adapter: adapter pointer + * @data: %QCA_NL80211_VENDOR_SUBCMD_SET_MONITOR_MODE payload + * @data_len: length of @data + * + * Return: %QDF_STATUS_SUCCESS on success, error status otherwise + */ +QDF_STATUS os_if_monitor_mode_configure(struct hdd_adapter *adapter, + const void *data, int data_len); +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/pkt_capture/src/os_if_pkt_capture.c b/qcom/opensource/wlan/qcacld-3.0/os_if/pkt_capture/src/os_if_pkt_capture.c new file mode 100644 index 0000000000..77b2ec767d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/pkt_capture/src/os_if_pkt_capture.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2016-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "osif_sync.h" +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_types.h" +#include "wlan_osif_priv.h" +#include +#include "wlan_cfg80211.h" +#include "wlan_objmgr_psoc_obj.h" +#include "wlan_objmgr_pdev_obj.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_utility.h" +#include "wlan_osif_request_manager.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_pkt_capture_ucfg_api.h" +#include "os_if_pkt_capture.h" +#include "wlan_hdd_main.h" +#include "cfg_ucfg_api.h" +#include "wlan_hdd_object_manager.h" + +#ifdef WLAN_FEATURE_PKT_CAPTURE + +const struct nla_policy +set_monitor_mode_policy[SET_MONITOR_MODE_CONFIG_MAX + 1] = { + [SET_MONITOR_MODE_INVALID] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_DATA_TX_FRAME_TYPE] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_DATA_RX_FRAME_TYPE] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE] = { + .type = NLA_U32 + }, + [SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL] = { + .type = NLA_U32 + }, +}; + +QDF_STATUS os_if_monitor_mode_configure(struct hdd_adapter *adapter, + const void *data, int data_len) +{ + struct pkt_capture_frame_filter frame_filter = {0}; + struct wlan_objmgr_vdev *vdev; + struct nlattr *tb[SET_MONITOR_MODE_CONFIG_MAX + 1]; + QDF_STATUS status; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, + WLAN_PKT_CAPTURE_ID); + if (!vdev) + return QDF_STATUS_E_INVAL; + + if (wlan_cfg80211_nla_parse(tb, SET_MONITOR_MODE_CONFIG_MAX, + data, data_len, set_monitor_mode_policy)) { + osif_err("invalid monitor attr"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_PKT_CAPTURE_ID); + return QDF_STATUS_E_INVAL; + } + + if (tb[SET_MONITOR_MODE_INVALID]) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_PKT_CAPTURE_ID); + return QDF_STATUS_E_FAILURE; + } + + if (tb[SET_MONITOR_MODE_DATA_TX_FRAME_TYPE] && + nla_get_u32(tb[SET_MONITOR_MODE_DATA_TX_FRAME_TYPE]) < + PACKET_CAPTURE_DATA_MAX_FILTER) { + frame_filter.data_tx_frame_filter = + nla_get_u32(tb[SET_MONITOR_MODE_DATA_TX_FRAME_TYPE]); + frame_filter.vendor_attr_to_set = + BIT(SET_MONITOR_MODE_DATA_TX_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_DATA_RX_FRAME_TYPE] && + nla_get_u32(tb[SET_MONITOR_MODE_DATA_RX_FRAME_TYPE]) < + PACKET_CAPTURE_DATA_MAX_FILTER) { + frame_filter.data_rx_frame_filter = + nla_get_u32(tb[SET_MONITOR_MODE_DATA_RX_FRAME_TYPE]); + frame_filter.vendor_attr_to_set |= + BIT(SET_MONITOR_MODE_DATA_RX_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE] && + nla_get_u32(tb[SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE]) < + PACKET_CAPTURE_MGMT_MAX_FILTER) { + frame_filter.mgmt_tx_frame_filter = + nla_get_u32(tb[SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE]); + frame_filter.vendor_attr_to_set |= + BIT(SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE] && + nla_get_u32(tb[SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE]) < + PACKET_CAPTURE_MGMT_MAX_FILTER) { + frame_filter.mgmt_rx_frame_filter = + nla_get_u32(tb[SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE]); + frame_filter.vendor_attr_to_set |= + BIT(SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE] && + nla_get_u32(tb[SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE]) < + PACKET_CAPTURE_CTRL_MAX_FILTER) { + frame_filter.ctrl_tx_frame_filter = + nla_get_u32(tb[SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE]); + frame_filter.vendor_attr_to_set |= + BIT(SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE] && + nla_get_u32(tb[SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE]) < + PACKET_CAPTURE_CTRL_MAX_FILTER) { + frame_filter.ctrl_rx_frame_filter = + nla_get_u32(tb[SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE]); + frame_filter.vendor_attr_to_set |= + BIT(SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE); + } + + if (tb[SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL]) { + frame_filter.connected_beacon_interval = + nla_get_u32(tb[SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL]); + frame_filter.vendor_attr_to_set |= + BIT(SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL); + } + + osif_debug("Monitor mode config data tx %d data rx %d mgmt tx %d mgmt rx %d ctrl tx %d ctrl rx %d bi %d\n", + frame_filter.data_tx_frame_filter, + frame_filter.data_rx_frame_filter, + frame_filter.mgmt_tx_frame_filter, + frame_filter.mgmt_rx_frame_filter, + frame_filter.ctrl_tx_frame_filter, + frame_filter.ctrl_rx_frame_filter, + frame_filter.connected_beacon_interval); + + status = ucfg_pkt_capture_set_filter(frame_filter, vdev); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_PKT_CAPTURE_ID); + + return status; +} + +#undef SET_MONITOR_MODE_CONFIG_MAX +#undef SET_MONITOR_MODE_INVALID +#undef SET_MONITOR_MODE_DATA_TX_FRAME_TYPE +#undef SET_MONITOR_MODE_DATA_RX_FRAME_TYPE +#undef SET_MONITOR_MODE_MGMT_TX_FRAME_TYPE +#undef SET_MONITOR_MODE_MGMT_RX_FRAME_TYPE +#undef SET_MONITOR_MODE_CTRL_TX_FRAME_TYPE +#undef SET_MONITOR_MODE_CTRL_RX_FRAME_TYPE +#undef SET_MONITOR_MODE_CONNECTED_BEACON_INTERVAL + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/pre_cac/inc/osif_pre_cac.h b/qcom/opensource/wlan/qcacld-3.0/os_if/pre_cac/inc/osif_pre_cac.h new file mode 100644 index 0000000000..ee4e54664f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/pre_cac/inc/osif_pre_cac.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OSIF_PRE_CAC_H_ +#define _OSIF_PRE_CAC_H_ + +#include "wlan_objmgr_vdev_obj.h" + +#ifdef PRE_CAC_SUPPORT + +/** + * typedef osif_conditional_csa_ind_legacy_cb - CSA indication callback + * @vdev: vdev upon which channel switch is occurring + * @completed: true if channel switch has completed, false if channel + * switch is being initiated + * + * This callback is to send conditional channel switch status + * + * Context: Any context. + * Return: QDF_STATUS + */ +typedef void + (*osif_conditional_csa_ind_legacy_cb)(struct wlan_objmgr_vdev *vdev, + bool completed); + +/** + * typedef osif_pre_cac_complete_status_legacy_cb - pre cac complete callback + * @psoc: SOC where pre-cac is required + * @vdev_id: ID of the vdev where pre-cac is required + * @status: QDF_STATUS_SUCCESS if pre-cac was successful, otherwise an + * appropriate QDF error status code + * + * This callback is used to indicate the pre cac complete status + * + * Context: Any context. + * Return: None + */ +typedef void + (*osif_pre_cac_complete_status_legacy_cb)(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + QDF_STATUS status); + +/** + * struct osif_pre_cac_legacy_ops - pre cac legacy callbacks + * @conditional_csa_ind_legacy_cb: Callback for CSA indication + * @pre_cac_complete_legacy_cb: Callback for pre cac complete status + */ +struct osif_pre_cac_legacy_ops { + osif_conditional_csa_ind_legacy_cb conditional_csa_ind_legacy_cb; + osif_pre_cac_complete_status_legacy_cb pre_cac_complete_legacy_cb; +}; + +/** + * osif_pre_cac_set_legacy_cb() - Sets legacy callbacks to osif + * @osif_legacy_ops: Function pointer to legacy ops structure + * + * API to set legacy callbacks to osif + * Context: Any context. + * + * Return: void + */ +void +osif_pre_cac_set_legacy_cb(struct osif_pre_cac_legacy_ops *osif_legacy_ops); + +/** + * osif_pre_cac_reset_legacy_cb() - Resets legacy callbacks to osif + * + * API to reset legacy callbacks to osif + * Context: Any context. + * + * Return: void + */ +void osif_pre_cac_reset_legacy_cb(void); + +/** + * osif_pre_cac_register_cb() - API to register pre cac callbacks. + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_pre_cac_register_cb(void); +#endif /* PRE_CAC_SUPPORT */ +#endif /* _OSIF_PRE_CAC_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/pre_cac/src/osif_pre_cac.c b/qcom/opensource/wlan/qcacld-3.0/os_if/pre_cac/src/osif_pre_cac.c new file mode 100644 index 0000000000..06b255377e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/pre_cac/src/osif_pre_cac.c @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include "osif_pre_cac.h" +#include "wlan_pre_cac_public_struct.h" +#include "wlan_pre_cac_ucfg_api.h" +#include "wlan_cfg80211.h" +#include "wlan_objmgr_vdev_obj.h" +#include "wlan_osif_priv.h" +#include "osif_vdev_sync.h" + +static struct osif_pre_cac_legacy_ops *osif_pre_cac_legacy_ops; + +static void +osif_pre_cac_complete_legacy_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + QDF_STATUS status) +{ + osif_pre_cac_complete_status_legacy_cb cb = NULL; + + if (osif_pre_cac_legacy_ops) + cb = osif_pre_cac_legacy_ops->pre_cac_complete_legacy_cb; + + if (cb) + cb(psoc, vdev_id, status); +} + +static void osif_pre_cac_complete_cb(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + QDF_STATUS status) +{ + struct vdev_osif_priv *osif_priv; + struct osif_vdev_sync *vdev_sync; + int errno; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc( + psoc, vdev_id, + WLAN_PRE_CAC_ID); + if (!vdev) { + osif_err("Invalid vdev for %d", vdev_id); + return; + } + osif_priv = wlan_vdev_get_ospriv(vdev); + errno = osif_vdev_sync_trans_start_wait(osif_priv->wdev->netdev, + &vdev_sync); + wlan_objmgr_vdev_release_ref(vdev, WLAN_PRE_CAC_ID); + if (errno) + return; + + osif_pre_cac_complete_legacy_cb(psoc, vdev_id, status); + + osif_vdev_sync_trans_stop(vdev_sync); +} + +static void +osif_pre_cac_conditional_csa_ind_legacy_cb(struct wlan_objmgr_vdev *vdev, + bool completed) +{ + osif_conditional_csa_ind_legacy_cb cb = NULL; + + if (osif_pre_cac_legacy_ops) + cb = osif_pre_cac_legacy_ops->conditional_csa_ind_legacy_cb; + + if (cb) + cb(vdev, completed); +} + +static void +osif_pre_cac_send_conditional_freq_switch_status(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id, + bool status) +{ + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev; + struct wireless_dev *wdev; + struct sk_buff *event; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, + WLAN_PRE_CAC_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + event = wlan_cfg80211_vendor_event_alloc(wdev->wiphy, + wdev, sizeof(uint32_t) + NLMSG_HDRLEN, + QCA_NL80211_VENDOR_SUBCMD_SAP_CONDITIONAL_CHAN_SWITCH_INDEX, + GFP_KERNEL); + if (!event) { + osif_err("wlan_cfg80211_vendor_event_alloc failed"); + goto fail; + } + + if (nla_put_u32(event, + QCA_WLAN_VENDOR_ATTR_SAP_CONDITIONAL_CHAN_SWITCH_STATUS, + status)) { + osif_err("nla put failed"); + wlan_cfg80211_vendor_free_skb(event); + goto fail; + } + + wlan_cfg80211_vendor_event(event, GFP_KERNEL); + osif_pre_cac_conditional_csa_ind_legacy_cb(vdev, status); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_PRE_CAC_ID); +} + +void osif_pre_cac_set_legacy_cb(struct osif_pre_cac_legacy_ops *osif_legacy_ops) +{ + osif_pre_cac_legacy_ops = osif_legacy_ops; +} + +void osif_pre_cac_reset_legacy_cb(void) +{ + osif_pre_cac_legacy_ops = NULL; +} + +static struct pre_cac_ops pre_cac_ops = { + .pre_cac_conditional_csa_ind_cb = + osif_pre_cac_send_conditional_freq_switch_status, + .pre_cac_complete_cb = osif_pre_cac_complete_cb, +}; + +QDF_STATUS osif_pre_cac_register_cb(void) +{ + ucfg_pre_cac_set_osif_cb(&pre_cac_ops); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/inc/os_if_qmi.h b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/inc/os_if_qmi.h new file mode 100644 index 0000000000..4c9fd78563 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/inc/os_if_qmi.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: os_if_qmi.h + * + * This file contains declarations for wrapper APIs for QMI HLOS APIs + */ + +#ifndef _OS_IF_QMI_H_ +#define _OS_IF_QMI_H_ + +#include "wlan_qmi_public_struct.h" +#include +#include +#include +#include +#include "wlan_cfg80211.h" +#include "wlan_objmgr_psoc_obj.h" +#include + +#define QMI_WFDS_MAX_RECV_BUF_SIZE 4096 +#define QMI_WFDS_SERVICE_INS_ID_V01 0x0 +#define QMI_WFDS_TIMEOUT_MS 10000 +#define QMI_WFDS_TIMEOUT_JF \ + qdf_system_msecs_to_ticks(QMI_WFDS_TIMEOUT_MS) + +/** + * enum os_if_qmi_wfds_ut_cmd_type - WFDS unit test command type + * @WFDS_STOP_TRAFFIC: Stop WFDS traffic + * @WFDS_START_TRAFFIC: Start WFDS Traffic + * @WFDS_GET_STATS: Get WFDS traffic stats + * @WFDS_START_WHC: Start WHC traffic + * @WFDS_START_TSF: Start TSF handshake + * @WFDS_CMD_MISC: Miscellaneous test + * @WFDS_CMD_MAX: Max test commands + */ +enum os_if_qmi_wfds_ut_cmd_type { + WFDS_STOP_TRAFFIC, + WFDS_START_TRAFFIC, + WFDS_GET_STATS, + WFDS_START_WHC, + WFDS_START_TSF, + WFDS_CMD_MISC, + WFDS_CMD_MAX, +}; + +/** + * struct os_if_qmi_wfds_ut_cmd_info - WFDS UT cmd info structure + * @cmd: Command type + * @duration: Traffic duration + * @num_pkts: Buffers per flush + * @flush_period: Buffer flushing periodicity + * @buf_size: Buffer size + * @ether_type: ether_type of packet + * @dest_mac: Destination MAC address + * @src_mac: Source MAC address + * @dest_ip: Destination IPv4 address + * @src_ip: Source IPv4 address + * @dest_port: Destination port + */ +struct os_if_qmi_wfds_ut_cmd_info { + enum os_if_qmi_wfds_ut_cmd_type cmd; + uint32_t duration; + uint32_t flush_period; + uint32_t num_pkts; + uint32_t buf_size; + uint16_t ether_type; + struct qdf_mac_addr dest_mac; + struct qdf_mac_addr src_mac; + struct qdf_ipv4_addr dest_ip; + struct qdf_ipv4_addr src_ip; + uint16_t dest_port; +}; + +#ifdef QMI_COMPONENT_ENABLE +/** + * os_if_qmi_handle_init() - Initialize QMI handle + * @qmi_hdl: QMI handle to initialize + * @recv_buf_size: maximum size of incoming message + * @ops: reference to callbacks for QRTR notifications + * @qmi_msg_handlers: NULL-terminated list of QMI message handlers + * + * Returns: QDF status + */ +QDF_STATUS +os_if_qmi_handle_init(struct qmi_handle *qmi_hdl, qdf_size_t recv_buf_size, + const struct qmi_ops *ops, + const struct qmi_msg_handler *qmi_msg_handlers); + +/** + * os_if_qmi_handle_release() - Release QMI handle + * @qmi_hdl: QMI handle to release + * + * Returns: None + */ +void os_if_qmi_handle_release(struct qmi_handle *qmi_hdl); + +/** + * os_if_qmi_add_lookup() - Register a new lookup with the name service + * @qmi_hdl: QMI handle + * @service: service id of the request + * @instance: instance id of the request + * @version: version number of the request + * + * Return: QDF status + */ +QDF_STATUS os_if_qmi_add_lookup(struct qmi_handle *qmi_hdl, + unsigned int service, unsigned int version, + unsigned int instance); + +/** + * os_if_qmi_connect_to_svc() - Connect to QMI service + * @qmi_hdl: QMI handle + * @qmi_svc: QMI service handle + * + * Return: QDF status + */ +QDF_STATUS os_if_qmi_connect_to_svc(struct qmi_handle *qmi_hdl, + struct qmi_service *qmi_svc); + +/** + * os_if_qmi_txn_init() - Initialize QMI transaction + * @qmi_hdl: QMI handle + * @qmi_txn: QMI transaction handle + * @qmi_ei: description of how to decode a matching response (optional) + * @resp: pointer to the object to decode the response into (optional) + * + * Return: QDF status + */ +QDF_STATUS os_if_qmi_txn_init(struct qmi_handle *qmi_hdl, + struct qmi_txn *qmi_txn, + struct qmi_elem_info *qmi_ei, void *resp); + +/** + * os_if_qmi_send_request() - Connect to QMI service + * @qmi_hdl: QMI handle + * @sq: destination sockaddr + * @qmi_txn: QMI transaction handle + * @msg_id: message id + * @len: max length of the QMI message + * @ei: QMI message description + * @req: message to be encoded + * + * Return: QDF status + */ +QDF_STATUS os_if_qmi_send_request(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *qmi_txn, int msg_id, + uint32_t len, struct qmi_elem_info *ei, + const void *req); + +/** + * os_if_qmi_txn_wait() - Wait for transaction response + * @qmi_txn: QMI transaction handle + * @timeout: Timeout value in jiffies + * + * Return: QDF status + */ +QDF_STATUS os_if_qmi_txn_wait(struct qmi_txn *qmi_txn, unsigned long timeout); + +/** + * os_if_qmi_txn_cancel() - Cancel the QMI transaction + * @qmi_txn: QMI transaction handle + * + * Return: None + */ +void os_if_qmi_txn_cancel(struct qmi_txn *qmi_txn); + +/** + * os_if_qmi_register_callbacks() - Register callback handlers + * @psoc: Pointer to psoc context + * @cb_obj: Callback object pointer + * + * Return: None + */ +void os_if_qmi_register_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_psoc_callbacks *cb_obj); + +#ifdef QMI_WFDS +/** + * os_if_qmi_wfds_register_callbacks() - Register WFDS callback handlers + * @cb_obj: Callback object pointer + * + * Return: None + */ +void os_if_qmi_wfds_register_callbacks(struct wlan_qmi_psoc_callbacks *cb_obj); + +/** + * os_if_qmi_wfds_send_ut_cmd_req_msg() - Send WFDS unit test command + * @cmd_info: Unit test command info + * + * Return: QDF_STATUS + */ +QDF_STATUS +os_if_qmi_wfds_send_ut_cmd_req_msg(struct os_if_qmi_wfds_ut_cmd_info *cmd_info); + +#else +static inline +void os_if_qmi_wfds_register_callbacks(struct wlan_qmi_psoc_callbacks *cb_obj) +{ +} + +static inline QDF_STATUS +os_if_qmi_wfds_send_ut_cmd_req_msg(struct os_if_qmi_wfds_ut_cmd_info *cmd_info) +{ +} +#endif +#else +static inline +QDF_STATUS os_if_qmi_handle_init(struct qmi_handle *qmi_hdl, + qdf_size_t recv_buf_size, + const struct qmi_ops *ops, + const struct qmi_msg_handler *qmi_msg_handlers) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +void os_if_qmi_handle_release(struct qmi_handle *qmi_hdl) +{ +} + +static inline +QDF_STATUS os_if_qmi_add_lookup(struct qmi_handle *qmi_hdl, + unsigned int service, unsigned int version, + unsigned int instance) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS os_if_qmi_connect_to_svc(struct qmi_handle *qmi_hdl, + struct qmi_service *qmi_svc) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS os_if_qmi_txn_init(struct qmi_handle *qmi_hdl, + struct qmi_txn *qmi_txn, + struct qmi_elem_info *qmi_ei, void *resp) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS os_if_qmi_send_request(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *qmi_txn, int msg_id, + uint32_t len, struct qmi_elem_info *ei, + const void *req) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +QDF_STATUS os_if_qmi_txn_wait(struct qmi_txn *qmi_txn, unsigned long timeout) +{ + return QDF_STATUS_E_NOSUPPORT; +} + +static inline +void os_if_qmi_txn_cancel(struct qmi_txn *qmi_txn) +{ +} + +static inline +void os_if_qmi_register_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_psoc_callbacks *cb_obj) +{ +} +#endif +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/inc/os_if_qmi_wifi_driver_service_v01.h b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/inc/os_if_qmi_wifi_driver_service_v01.h new file mode 100644 index 0000000000..6f0f50642d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/inc/os_if_qmi_wifi_driver_service_v01.h @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef WIFI_DRIVER_SERVICE_V01_H +#define WIFI_DRIVER_SERVICE_V01_H + +#include + +#define WFDS_SERVICE_ID_V01 0x043C +#define WFDS_SERVICE_VERS_V01 0x01 + +#define QMI_WFDS_IPCC_MAP_N_CFG_RESP_V01 0x0003 +#define QMI_WFDS_UT_CMD_RESP_V01 0x0005 +#define QMI_WFDS_MISC_REQ_V01 0x0004 +#define QMI_WFDS_MISC_RESP_V01 0x0004 +#define QMI_WFDS_MEM_RESP_V01 0x0002 +#define QMI_WFDS_IPCC_MAP_N_CFG_REQ_V01 0x0003 +#define QMI_WFDS_MISC_IND_V01 0x0004 +#define QMI_WFDS_UT_CMD_REQ_V01 0x0005 +#define QMI_WFDS_CONFIG_REQ_V01 0x0001 +#define QMI_WFDS_IPCC_MAP_N_CFG_IND_V01 0x0003 +#define QMI_WFDS_CONFIG_RESP_V01 0x0001 +#define QMI_WFDS_MEM_REQ_V01 0x0002 +#define QMI_WFDS_MEM_IND_V01 0x0002 + +#define WFDS_CE_MAX_SRNG_V01 3 +#define WFDS_MEM_ARENA_MAX_V01 8 +#define WFDS_PAGE_INFO_MAX_ARRAY_SIZE_V01 255 + +/** + * struct wfds_gen_resp_msg_v01 - Generic QMI response message + * @resp: QMI result code + */ +struct wfds_gen_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + +#define WFDS_GEN_RESP_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wfds_gen_resp_msg_v01_ei[]; + +/** + * enum wifi_drv_qmi_srng_direction_v01 - SRNG direction + * @WIFI_DRV_QMI_SRNG_DIRECTION_MIN_VAL_V01: SRNG direction enum min value + * @WFDS_SRNG_SOURCE_RING_V01: SRNG source ring + * @WFDS_SRNG_DESTINATION_RING_V01: SRNG destination ring + * @WIFI_DRV_QMI_SRNG_DIRECTION_MAX_VAL_V01: SRNG direction enum max value + */ +enum wifi_drv_qmi_srng_direction_v01 { + WIFI_DRV_QMI_SRNG_DIRECTION_MIN_VAL_V01 = INT_MIN, + WFDS_SRNG_SOURCE_RING_V01 = 0, + WFDS_SRNG_DESTINATION_RING_V01 = 1, + WIFI_DRV_QMI_SRNG_DIRECTION_MAX_VAL_V01 = INT_MAX, +}; + +/** + * struct wifi_drv_qmi_srng_information_v01 - SRNG information + * @ring_id: SRNG ring id + * @dir: SRNG direction + * @num_entries: number of entries in SRNG + * @entry_size: size of SRNG descriptor + * @ring_base_paddr: ring base physical address of SRNG + * @hp_paddr: HP physical address of SRNG + * @tp_paddr: TP physical address of SRNG + */ +struct wifi_drv_qmi_srng_information_v01 { + u8 ring_id; + enum wifi_drv_qmi_srng_direction_v01 dir; + u32 num_entries; + u32 entry_size; + u64 ring_base_paddr; + u64 hp_paddr; + u64 tp_paddr; +}; + +/** + * enum wifi_drv_qmi_pipe_dir_v01 - pipe direction + * @WIFI_DRV_QMI_PIPE_DIR_MIN_VAL_V01: pipe direction enum min value + * @WFDS_PIPEDIR_NONE_V01: none pipe direction + * @WFDS_PIPEDIR_IN_V01: target to host pipe direction + * @WFDS_PIPEDIR_OUT_V01: host to target pipe direction + * @WIFI_DRV_QMI_PIPE_DIR_MAX_VAL_V01: pipe direction enum max value + */ +enum wifi_drv_qmi_pipe_dir_v01 { + WIFI_DRV_QMI_PIPE_DIR_MIN_VAL_V01 = INT_MIN, + WFDS_PIPEDIR_NONE_V01 = 0, + WFDS_PIPEDIR_IN_V01 = 1, + WFDS_PIPEDIR_OUT_V01 = 2, + WIFI_DRV_QMI_PIPE_DIR_MAX_VAL_V01 = INT_MAX, +}; + +/** + * struct wifi_drv_qmi_ce_information_v01 - CE information + * @ce_id: CE id + * @ce_dir: CE direction + * @srng_info: SRNG information + */ +struct wifi_drv_qmi_ce_information_v01 { + u8 ce_id; + enum wifi_drv_qmi_pipe_dir_v01 ce_dir; + struct wifi_drv_qmi_srng_information_v01 srng_info; +}; + +/** + * struct wfds_config_req_msg_v01 - WFDS config request message + * @ce_info_len: size of ce_info with valid entries + * @ce_info: CE information array + * @rx_refill_ring: refill SRNG information + * @shadow_rdptr_mem_paddr: shadow read memory physical address + * @shadow_rdptr_mem_size: shadow read memory size + * @shadow_wrptr_mem_paddr: shadow write memory physical address + * @shadow_wrptr_mem_size: shadow write memory size + * @rx_pkt_tlv_len: rx packet tlvs length + * @rx_rbm: return buffer manager for rx buffers + * @pcie_bar_pa: PCIe BAR physical address + * @pci_slot: PCIe slot + * @lpass_ep_id: LPASS data message service endpoint id + */ +struct wfds_config_req_msg_v01 { + u32 ce_info_len; + struct wifi_drv_qmi_ce_information_v01 ce_info[WFDS_CE_MAX_SRNG_V01]; + struct wifi_drv_qmi_srng_information_v01 rx_refill_ring; + u64 shadow_rdptr_mem_paddr; + u64 shadow_rdptr_mem_size; + u64 shadow_wrptr_mem_paddr; + u64 shadow_wrptr_mem_size; + u32 rx_pkt_tlv_len; + u32 rx_rbm; + u64 pcie_bar_pa; + u32 pci_slot; + u32 lpass_ep_id; +}; + +#define WFDS_CONFIG_REQ_MSG_V01_MAX_MSG_LEN 253 +extern struct qmi_elem_info wfds_config_req_msg_v01_ei[]; + +/** + * enum wifi_drv_qmi_mem_arenas_v01 - Memory arena + * @WIFI_DRV_QMI_MEM_ARENAS_MIN_VAL_V01: memory arena enum min value + * @WFDS_MEM_ARENA_TX_BUFFERS_V01: TX buffers memory arena + * @WFDS_MEM_ARENA_CE_TX_MSG_BUFFERS_V01: CE TX message buffers memory arena + * @WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS_V01: CE RX message buffers memory arena + * @WIFI_DRV_QMI_MEM_ARENAS_MAX_VAL_V01: memory arena enum max value + */ +enum wifi_drv_qmi_mem_arenas_v01 { + WIFI_DRV_QMI_MEM_ARENAS_MIN_VAL_V01 = INT_MIN, + WFDS_MEM_ARENA_TX_BUFFERS_V01 = 0, + WFDS_MEM_ARENA_CE_TX_MSG_BUFFERS_V01 = 1, + WFDS_MEM_ARENA_CE_RX_MSG_BUFFERS_V01 = 2, + WIFI_DRV_QMI_MEM_ARENAS_MAX_VAL_V01 = INT_MAX, +}; + +/** + * struct wifi_drv_qmi_mem_arena_information_v01 - Memory arena information + * @entry_size: entry size + * @num_entries: total number of entries required + */ +struct wifi_drv_qmi_mem_arena_information_v01 { + u16 entry_size; + u16 num_entries; +}; + +/** + * struct wfds_mem_ind_msg_v01 - Memory indication message + * @mem_arena_info_len: number of valid entries in mem_arena_info array + * @mem_arena_info: memory arena information array + */ +struct wfds_mem_ind_msg_v01 { + u32 mem_arena_info_len; + struct wifi_drv_qmi_mem_arena_information_v01 mem_arena_info[WFDS_MEM_ARENA_MAX_V01]; +}; + +#define WFDS_MEM_IND_MSG_V01_MAX_MSG_LEN 36 +extern struct qmi_elem_info wfds_mem_ind_msg_v01_ei[]; + +/** + * struct wifi_drv_qmi_mem_arena_page_information_v01 - Memory arena + * page information + * @num_entries_per_page: number of entries per page + * @page_dma_addr_len: number of valid entries in page_dma_addr array + * @page_dma_addr: page dma address array + */ +struct wifi_drv_qmi_mem_arena_page_information_v01 { + u16 num_entries_per_page; + u32 page_dma_addr_len; + u64 page_dma_addr[WFDS_PAGE_INFO_MAX_ARRAY_SIZE_V01]; +}; + +/** + * struct wfds_mem_req_msg_v01 - Memory request message + * page information + * @mem_arena_page_info_len: number of valid entries in + * mem_arena_page_info array + * @mem_arena_page_info: memory arena information + */ +struct wfds_mem_req_msg_v01 { + u32 mem_arena_page_info_len; + struct wifi_drv_qmi_mem_arena_page_information_v01 mem_arena_page_info[WFDS_MEM_ARENA_MAX_V01]; +}; + +#define WFDS_MEM_REQ_MSG_V01_MAX_MSG_LEN 16348 +extern struct qmi_elem_info wfds_mem_req_msg_v01_ei[]; + +/** + * struct wifi_drv_qmi_ipcc_information_v01 - IPCC information + * @ce_id: CE id + * @ipcc_trig_addr: IPCC trigger address + * @ipcc_trig_data: IPCC trigger data + */ +struct wifi_drv_qmi_ipcc_information_v01 { + u8 ce_id; + u64 ipcc_trig_addr; + u32 ipcc_trig_data; +}; + +/** + * struct wfds_ipcc_map_n_cfg_ind_msg_v01 - IPCC map and configure + * indication message + * @ipcc_ce_info_len: number of valid entries in ipcc_ce_info array + * @ipcc_ce_info: IPCC information for CE + */ +struct wfds_ipcc_map_n_cfg_ind_msg_v01 { + u32 ipcc_ce_info_len; + struct wifi_drv_qmi_ipcc_information_v01 ipcc_ce_info[WFDS_CE_MAX_SRNG_V01]; +}; + +#define WFDS_IPCC_MAP_N_CFG_IND_MSG_V01_MAX_MSG_LEN 43 +extern struct qmi_elem_info wfds_ipcc_map_n_cfg_ind_msg_v01_ei[]; + +/** + * struct wfds_ipcc_map_n_cfg_req_msg_v01 - IPCC map and configure + * request message + * @status: IPCC configuration status + */ +struct wfds_ipcc_map_n_cfg_req_msg_v01 { + u8 status; +}; + +#define WFDS_IPCC_MAP_N_CFG_REQ_MSG_V01_MAX_MSG_LEN 4 +extern struct qmi_elem_info wfds_ipcc_map_n_cfg_req_msg_v01_ei[]; + +/** + * enum wifi_drv_qmi_event_v01 - driver event + * @WIFI_DRV_QMI_EVENT_MIN_VAL_V01: event enum min value + * @WFDS_EVENT_WLAN_HOST_RMMOD_V01: host driver rmmod event + * @WFDS_EVENT_WLAN_SSR_V01: wlan SSR event + * @WFDS_EVENT_LPASS_SSR_V01: LPASS SSR event + * @WIFI_DRV_QMI_EVENT_MAX_VAL_V01: event enum max value + */ +enum wifi_drv_qmi_event_v01 { + WIFI_DRV_QMI_EVENT_MIN_VAL_V01 = INT_MIN, + WFDS_EVENT_WLAN_HOST_RMMOD_V01 = 0, + WFDS_EVENT_WLAN_SSR_V01 = 1, + WFDS_EVENT_LPASS_SSR_V01 = 2, + WIFI_DRV_QMI_EVENT_MAX_VAL_V01 = INT_MAX, +}; + +/** + * struct wfds_misc_req_msg_v01 - Miscellaneous request + * message + * @event: driver event + */ +struct wfds_misc_req_msg_v01 { + enum wifi_drv_qmi_event_v01 event; +}; + +#define WFDS_MISC_REQ_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wfds_misc_req_msg_v01_ei[]; + +/** + * struct wfds_misc_ind_msg_v01 - Miscellaneous indication + * message + * @event: driver event + */ +struct wfds_misc_ind_msg_v01 { + enum wifi_drv_qmi_event_v01 event; +}; + +#define WFDS_MISC_IND_MSG_V01_MAX_MSG_LEN 7 +extern struct qmi_elem_info wfds_misc_ind_msg_v01_ei[]; + +/** + * enum wifi_drv_qmi_ut_cmd_v01 - driver event + * @WIFI_DRV_QMI_UT_CMD_MIN_VAL_V01: event enum min value + * @WFDS_UT_CMD_STOP_V01: Stop WFDS traffic + * @WFDS_UT_CMD_START_V01: Start WFDS Traffic + * @WFDS_UT_CMD_STATS_V01: Get WFDS traffic stats + * @WFDS_UT_CMD_START_WHC_V01: Start WHC Traffic + * @WFDS_UT_CMD_START_TSF_SYNC_V01: Start TSF handshake + * @WFDS_UT_CMD_MISC_V01: Miscellaneous test + * @WIFI_DRV_QMI_UT_CMD_MAX_VAL_V01: event enum max value + */ +enum wifi_drv_qmi_ut_cmd_v01 { + WIFI_DRV_QMI_UT_CMD_MIN_VAL_V01 = INT_MIN, + WFDS_UT_CMD_STOP_V01 = 0, + WFDS_UT_CMD_START_V01 = 1, + WFDS_UT_CMD_STATS_V01 = 2, + WFDS_UT_CMD_START_WHC_V01 = 3, + WFDS_UT_CMD_START_TSF_SYNC_V01 = 4, + WFDS_UT_CMD_MISC_V01 = 5, + WIFI_DRV_QMI_UT_CMD_MAX_VAL_V01 = INT_MAX, +}; + +/** + * struct wfds_ut_cmd_req_msg_v01 - WFDS QMI UT cmd info structure + * @cmd: Command type + * @duration: Traffic duration + * @flush_period: Buffer flushing periodicity + * @num_pkts: Number of packets per flush + * @buf_size: Buffer size + * @ether_type: ether_type of packet + * @src_mac: Source MAC address + * @dest_mac: Destination MAC address + * @ip_ver: IP address version + * @src_ip_addr: source IP address + * @dest_ip_addr: Destination IP address + * @dest_port: Destination port + * @misc: Misc input data + */ +struct wfds_ut_cmd_req_msg_v01 { + enum wifi_drv_qmi_ut_cmd_v01 cmd; + u32 duration; + u32 flush_period; + u32 num_pkts; + u32 buf_size; + u16 ether_type; + u8 src_mac[6]; + u8 dest_mac[6]; + u8 ip_ver; + u8 src_ip_addr[16]; + u8 dest_ip_addr[16]; + u16 dest_port; + u8 misc[256]; +}; + +#define WFDS_UT_CMD_REQ_MSG_V01_MAX_MSG_LEN 364 +extern struct qmi_elem_info wfds_ut_cmd_req_msg_v01_ei[]; + +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi.c b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi.c new file mode 100644 index 0000000000..05be9b20fd --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi.c @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: os_if_qmi.c + * + * This file contains definitions of wrapper APIs for QMI HLOS APIs + */ + +#include "os_if_qmi.h" +#include "wlan_qmi_ucfg_api.h" + +QDF_STATUS os_if_qmi_handle_init(struct qmi_handle *qmi_hdl, + qdf_size_t recv_buf_size, + const struct qmi_ops *ops, + const struct qmi_msg_handler *qmi_msg_handlers) +{ + int ret; + + ret = qmi_handle_init(qmi_hdl, recv_buf_size, ops, qmi_msg_handlers); + if (ret < 0) { + osif_err("QMI handle initialization failed %d", ret); + return qdf_status_from_os_return(ret); + } + + return QDF_STATUS_SUCCESS; +} + +void os_if_qmi_handle_release(struct qmi_handle *qmi_hdl) +{ + qmi_handle_release(qmi_hdl); +} + +QDF_STATUS os_if_qmi_add_lookup(struct qmi_handle *qmi_hdl, + unsigned int service, unsigned int version, + unsigned int instance) +{ + int ret; + + ret = qmi_add_lookup(qmi_hdl, service, version, instance); + if (ret < 0) { + osif_err("QMI add lookup failed %d", ret); + return qdf_status_from_os_return(ret); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS os_if_qmi_connect_to_svc(struct qmi_handle *qmi_hdl, + struct qmi_service *qmi_svc) +{ + struct sockaddr_qrtr sq = { 0 }; + int ret; + + osif_debug("QMI server arriving: node %u port %u", qmi_svc->node, + qmi_svc->port); + + sq.sq_family = AF_QIPCRTR; + sq.sq_node = qmi_svc->node; + sq.sq_port = qmi_svc->port; + + ret = kernel_connect(qmi_hdl->sock, (struct sockaddr *)&sq, + sizeof(sq), 0); + if (ret < 0) { + osif_err("Failed to connect to QMI remote service %d", ret); + return qdf_status_from_os_return(ret); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS os_if_qmi_txn_init(struct qmi_handle *qmi_hdl, + struct qmi_txn *qmi_txn, + struct qmi_elem_info *qmi_ei, void *resp) +{ + int ret; + + ret = qmi_txn_init(qmi_hdl, qmi_txn, qmi_ei, resp); + if (ret < 0) + return qdf_status_from_os_return(ret); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS os_if_qmi_send_request(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *qmi_txn, int msg_id, + uint32_t len, struct qmi_elem_info *ei, + const void *req) +{ + int ret; + + ret = qmi_send_request(qmi_hdl, sq, qmi_txn, msg_id, len, ei, req); + if (ret < 0) + return qdf_status_from_os_return(ret); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS os_if_qmi_txn_wait(struct qmi_txn *qmi_txn, unsigned long timeout) +{ + int ret; + + ret = qmi_txn_wait(qmi_txn, timeout); + if (ret < 0) + return qdf_status_from_os_return(ret); + + return QDF_STATUS_SUCCESS; +} + +void os_if_qmi_txn_cancel(struct qmi_txn *qmi_txn) +{ + qmi_txn_cancel(qmi_txn); +} + +void os_if_qmi_register_callbacks(struct wlan_objmgr_psoc *psoc, + struct wlan_qmi_psoc_callbacks *cb_obj) +{ + os_if_qmi_wfds_register_callbacks(cb_obj); + ucfg_qmi_register_os_if_callbacks(psoc, cb_obj); +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi_wfds.c b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi_wfds.c new file mode 100644 index 0000000000..e6f449f80e --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi_wfds.c @@ -0,0 +1,666 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "os_if_qmi.h" +#include "os_if_qmi_wifi_driver_service_v01.h" +#include +#include "wlan_qmi_public_struct.h" +#include "wlan_dp_ucfg_api.h" + +static struct qmi_handle qmi_wfds; + +/* + * os_if_ce_dir_qmi_to_wfds_type() - Convert ce direction from internal + * type to type used in QMI message + * @ce_dir: internal ce direction + * + * Return: ce direction in QMI type + */ +static enum wifi_drv_qmi_pipe_dir_v01 +os_if_ce_dir_qmi_to_wfds_type(enum wlan_qmi_wfds_pipe_dir ce_dir) +{ + switch (ce_dir) { + case QMI_WFDS_PIPEDIR_NONE: + return WFDS_PIPEDIR_NONE_V01; + case QMI_WFDS_PIPEDIR_IN: + return WFDS_PIPEDIR_IN_V01; + case QMI_WFDS_PIPEDIR_OUT: + return WFDS_PIPEDIR_OUT_V01; + default: + return WIFI_DRV_QMI_PIPE_DIR_MAX_VAL_V01; + } +} + +/* + * os_if_srng_dir_qmi_to_wfds_type() - Convert srng direction from internal + * type to type used in QMI message + * @srng_dir: internal srng direction + * + * Return: srng direction in QMI type + */ +static enum wifi_drv_qmi_srng_direction_v01 +os_if_srng_dir_qmi_to_wfds_type(enum wlan_qmi_wfds_srng_dir srng_dir) +{ + switch (srng_dir) { + case QMI_WFDS_SRNG_SOURCE_RING: + return WFDS_SRNG_SOURCE_RING_V01; + case QMI_WFDS_SRNG_DESTINATION_RING: + return WFDS_SRNG_DESTINATION_RING_V01; + default: + return WIFI_DRV_QMI_SRNG_DIRECTION_MAX_VAL_V01; + } +} + +/* + * os_if_qmi_wfds_send_config_msg() - Send config message to QMI server + * to QMI server + * @src_info: source information to be filled in QMI message + * + * Return: QDF status + */ +static QDF_STATUS +os_if_qmi_wfds_send_config_msg(struct wlan_qmi_wfds_config_req_msg *src_info) +{ + struct wfds_config_req_msg_v01 *req; + struct wfds_gen_resp_msg_v01 *resp; + struct qmi_txn txn; + QDF_STATUS status; + uint8_t i; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + qdf_mem_free(req); + return QDF_STATUS_E_NOMEM; + } + + if (src_info->ce_info_len > QMI_WFDS_CE_MAX_SRNG) { + status = QDF_STATUS_E_INVAL; + goto out; + } + + req->ce_info_len = src_info->ce_info_len; + for (i = 0; i < req->ce_info_len; i++) { + req->ce_info[i].ce_id = src_info->ce_info[i].ce_id; + req->ce_info[i].ce_dir = + os_if_ce_dir_qmi_to_wfds_type(src_info->ce_info[i].ce_dir); + req->ce_info[i].srng_info.ring_id = + src_info->ce_info[i].srng_info.ring_id; + req->ce_info[i].srng_info.dir = + os_if_srng_dir_qmi_to_wfds_type(src_info->ce_info[i].srng_info.dir); + req->ce_info[i].srng_info.num_entries = + src_info->ce_info[i].srng_info.num_entries; + req->ce_info[i].srng_info.entry_size = + src_info->ce_info[i].srng_info.entry_size; + req->ce_info[i].srng_info.ring_base_paddr = + src_info->ce_info[i].srng_info.ring_base_paddr; + req->ce_info[i].srng_info.hp_paddr = + src_info->ce_info[i].srng_info.hp_paddr; + req->ce_info[i].srng_info.tp_paddr = + src_info->ce_info[i].srng_info.tp_paddr; + } + + req->rx_refill_ring.ring_id = src_info->rx_refill_ring.ring_id; + req->rx_refill_ring.dir = + os_if_srng_dir_qmi_to_wfds_type(src_info->rx_refill_ring.dir); + req->rx_refill_ring.num_entries = src_info->rx_refill_ring.num_entries; + req->rx_refill_ring.entry_size = src_info->rx_refill_ring.entry_size; + req->rx_refill_ring.ring_base_paddr = + src_info->rx_refill_ring.ring_base_paddr; + req->rx_refill_ring.hp_paddr = src_info->rx_refill_ring.hp_paddr; + req->rx_refill_ring.tp_paddr = src_info->rx_refill_ring.tp_paddr; + + req->shadow_rdptr_mem_paddr = src_info->shadow_rdptr_mem_paddr; + req->shadow_rdptr_mem_size = src_info->shadow_rdptr_mem_size; + req->shadow_wrptr_mem_paddr = src_info->shadow_wrptr_mem_paddr; + req->shadow_wrptr_mem_size = src_info->shadow_wrptr_mem_size; + req->rx_pkt_tlv_len = src_info->rx_pkt_tlv_len; + req->rx_rbm = src_info->rx_rbm; + req->pcie_bar_pa = src_info->pcie_bar_pa; + req->pci_slot = src_info->pci_slot; + req->lpass_ep_id = src_info->lpass_ep_id; + + status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei, + resp); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI txn init failed for WFDS config message %d", + status); + goto out; + } + + status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn, + QMI_WFDS_CONFIG_REQ_V01, + WFDS_CONFIG_REQ_MSG_V01_MAX_MSG_LEN, + wfds_config_req_msg_v01_ei, req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI WFDS config send request failed %d", status); + os_if_qmi_txn_cancel(&txn); + goto out; + } + + status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("Wait for QMI WFDS config response timed out %d", + status); + goto out; + } + + qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01); + +out: + qdf_mem_free(resp); + qdf_mem_free(req); + + return status; +} + +/* + * os_if_qmi_wfds_send_req_mem_msg() - Send Request Memory message to QMI server + * @src_info: source information to be filled in QMI message + * + * Return: QDF status + */ +static QDF_STATUS +os_if_qmi_wfds_send_req_mem_msg(struct wlan_qmi_wfds_mem_req_msg *src_info) +{ + struct wfds_mem_req_msg_v01 *req; + struct wfds_gen_resp_msg_v01 *resp; + struct qmi_txn txn; + QDF_STATUS status; + uint8_t i; + uint16_t j; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + qdf_mem_free(req); + return QDF_STATUS_E_NOMEM; + } + + if (src_info->mem_arena_page_info_len > QMI_WFDS_MEM_ARENA_MAX) { + status = QDF_STATUS_E_INVAL; + goto out; + } + + req->mem_arena_page_info_len = src_info->mem_arena_page_info_len; + for (i = 0; i < req->mem_arena_page_info_len; i++) { + req->mem_arena_page_info[i].num_entries_per_page = + src_info->mem_arena_page_info[i].num_entries_per_page; + req->mem_arena_page_info[i].page_dma_addr_len = + src_info->mem_arena_page_info[i].page_dma_addr_len; + + if (src_info->mem_arena_page_info[i].page_dma_addr_len > + QMI_WFDS_PAGE_INFO_ARRAY_MAX_SIZE) { + status = QDF_STATUS_E_INVAL; + goto out; + } + + for (j = 0; j < req->mem_arena_page_info[i].page_dma_addr_len; + j++) + req->mem_arena_page_info[i].page_dma_addr[j] = + src_info->mem_arena_page_info[i].page_dma_addr[j]; + } + + status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei, + resp); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI txn init failed for WFDS mem req message %d", + status); + goto out; + } + + status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn, + QMI_WFDS_MEM_REQ_V01, + WFDS_MEM_REQ_MSG_V01_MAX_MSG_LEN, + wfds_mem_req_msg_v01_ei, req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI WFDS mem request send failed %d", status); + os_if_qmi_txn_cancel(&txn); + goto out; + } + + status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("Wait for QMI WFDS mem response timed out %d", + status); + goto out; + } + + qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01); + +out: + qdf_mem_free(resp); + qdf_mem_free(req); + + return status; +} + +/* + * os_if_qmi_wfds_send_misc_req_msg() - Send misc req message to QMI server + * @is_ssr: true if SSR is in progress else false + * + * Return: QDF status + */ +static QDF_STATUS +os_if_qmi_wfds_send_misc_req_msg(bool is_ssr) +{ + struct wfds_misc_req_msg_v01 *req; + struct wfds_gen_resp_msg_v01 *resp; + struct qmi_txn txn; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + qdf_mem_free(req); + return QDF_STATUS_E_NOMEM; + } + + req->event = (is_ssr) ? WFDS_EVENT_WLAN_SSR_V01 : + WFDS_EVENT_WLAN_HOST_RMMOD_V01; + + status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei, + resp); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI txn for WFDS misc request failed %d", + status); + goto out; + } + + status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn, + QMI_WFDS_MISC_REQ_V01, + WFDS_MISC_REQ_MSG_V01_MAX_MSG_LEN, + wfds_misc_req_msg_v01_ei, req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI WFDS misc request send failed %d", status); + os_if_qmi_txn_cancel(&txn); + goto out; + } + + status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("Failed to wait for WFDS misc response %d", status); + goto out; + } + + qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01); + +out: + qdf_mem_free(resp); + qdf_mem_free(req); + + return status; +} + +/* + * os_if_srng_dir_qmi_to_wfds_type() - Convert status from internal + * type to type used in QMI message + * @status: internal status + * + * Return: status in QMI type + */ +static uint8_t +os_if_status_qmi_to_wfds_type(enum wlan_qmi_wfds_status status) +{ + switch (status) { + case QMI_WFDS_STATUS_SUCCESS: + return QMI_RESULT_SUCCESS_V01; + case QMI_WFDS_STATUS_FAILURE: + default: + return QMI_RESULT_FAILURE_V01; + } +} + +/* + * os_if_qmi_wfds_ipcc_map_n_cfg_msg() - Send the IPCC map and configure message + * to QMI server + * @src_info: source information to be filled in QMI message + * + * Return: QDF status + */ +static QDF_STATUS +os_if_qmi_wfds_ipcc_map_n_cfg_msg(struct wlan_qmi_wfds_ipcc_map_n_cfg_req_msg *src_info) +{ + struct wfds_ipcc_map_n_cfg_req_msg_v01 *req; + struct wfds_gen_resp_msg_v01 *resp; + struct qmi_txn txn; + QDF_STATUS status; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + qdf_mem_free(req); + return QDF_STATUS_E_NOMEM; + } + + req->status = os_if_status_qmi_to_wfds_type(src_info->status); + + status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei, + resp); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI txn init failed for WFDS ipcc cfg req message %d", + status); + goto out; + } + + status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn, + QMI_WFDS_IPCC_MAP_N_CFG_REQ_V01, + WFDS_IPCC_MAP_N_CFG_REQ_MSG_V01_MAX_MSG_LEN, + wfds_ipcc_map_n_cfg_req_msg_v01_ei, req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI WFDS IPCC cfg request send failed %d", status); + os_if_qmi_txn_cancel(&txn); + goto out; + } + + status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("Wait for QMI WFDS IPCC response timed out %d", + status); + goto out; + } + + qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01); + +out: + qdf_mem_free(resp); + qdf_mem_free(req); + + return status; +} + +/* + * os_if_qmi_wfds_request_mem_ind_cb() - Process request memory indication + * received from QMI server + * @qmi_hdl: QMI handle + * @sq: pointer to QRTR sock address + * @qmi_txn: pointer to QMI transaction + * @data: pointer to QMI data + * + * Return: None + */ +static void os_if_qmi_wfds_request_mem_ind_cb(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *qmi_txn, + const void *data) +{ + struct wfds_mem_ind_msg_v01 *src_info = + (struct wfds_mem_ind_msg_v01 *)data; + struct wlan_qmi_wfds_mem_ind_msg mem_ind_msg = {0}; + uint8_t i; + + if (!qmi_hdl || !qmi_txn) + return; + + if (src_info->mem_arena_info_len > QMI_WFDS_MEM_ARENA_MAX) { + osif_info("Memory arena information array size %d exceeds max length", + src_info->mem_arena_info_len); + return; + } + + mem_ind_msg.mem_arena_info_len = src_info->mem_arena_info_len; + for (i = 0; i < src_info->mem_arena_info_len; i++) { + mem_ind_msg.mem_arena_info[i].entry_size = + src_info->mem_arena_info[i].entry_size; + mem_ind_msg.mem_arena_info[i].num_entries = + src_info->mem_arena_info[i].num_entries; + } + + ucfg_dp_wfds_handle_request_mem_ind(&mem_ind_msg); +} + +/* + * os_if_wfds_ipcc_map_n_cfg_ind_cb() - Process IPCC map and configure + * indication received from QMI server + * @qmi_hdl: QMI handle + * @sq: pointer to QRTR sock address + * @qmi_txn: pointer to QMI transaction + * @data: pointer to QMI data + * + * Return: None + */ +static void os_if_wfds_ipcc_map_n_cfg_ind_cb(struct qmi_handle *qmi_hdl, + struct sockaddr_qrtr *sq, + struct qmi_txn *qmi_txn, + const void *data) +{ + struct wfds_ipcc_map_n_cfg_ind_msg_v01 *src_info = + (struct wfds_ipcc_map_n_cfg_ind_msg_v01 *)data; + struct wlan_qmi_wfds_ipcc_map_n_cfg_ind_msg ipcc_ind_msg = {0}; + uint8_t i; + + if (!qmi_hdl || !qmi_txn) + return; + + if (src_info->ipcc_ce_info_len > QMI_WFDS_CE_MAX_SRNG) { + osif_info("IPCC CE information array size %d exceeds max length", + src_info->ipcc_ce_info_len); + return; + } + + ipcc_ind_msg.ipcc_ce_info_len = src_info->ipcc_ce_info_len; + for (i = 0; i < src_info->ipcc_ce_info_len; i++) { + ipcc_ind_msg.ipcc_ce_info[i].ce_id = + src_info->ipcc_ce_info[i].ce_id; + ipcc_ind_msg.ipcc_ce_info[i].ipcc_trig_addr = + src_info->ipcc_ce_info[i].ipcc_trig_addr; + ipcc_ind_msg.ipcc_ce_info[i].ipcc_trig_data = + src_info->ipcc_ce_info[i].ipcc_trig_data; + } + + ucfg_dp_wfds_handle_ipcc_map_n_cfg_ind(&ipcc_ind_msg); +} + +QDF_STATUS +os_if_qmi_wfds_send_ut_cmd_req_msg(struct os_if_qmi_wfds_ut_cmd_info *cmd_info) +{ + struct wfds_ut_cmd_req_msg_v01 *req; + struct wfds_gen_resp_msg_v01 *resp; + struct qmi_txn txn; + QDF_STATUS status; + int i; + + req = qdf_mem_malloc(sizeof(*req)); + if (!req) + return QDF_STATUS_E_NOMEM; + + resp = qdf_mem_malloc(sizeof(*resp)); + if (!resp) { + qdf_mem_free(req); + return QDF_STATUS_E_NOMEM; + } + + req->cmd = (enum wifi_drv_qmi_ut_cmd_v01)cmd_info->cmd; + req->duration = cmd_info->duration; + req->flush_period = cmd_info->flush_period; + req->num_pkts = cmd_info->num_pkts; + req->buf_size = cmd_info->buf_size; + req->ether_type = cmd_info->ether_type; + for (i = 0; i < QDF_MAC_ADDR_SIZE; i++) { + req->src_mac[i] = cmd_info->src_mac.bytes[i]; + req->dest_mac[i] = cmd_info->dest_mac.bytes[i]; + } + + if (cmd_info->cmd == WFDS_START_WHC) { + for (i = 0; i < QDF_IPV4_ADDR_SIZE; i++) { + req->src_ip_addr[i] = cmd_info->src_ip.bytes[i]; + req->dest_ip_addr[i] = cmd_info->dest_ip.bytes[i]; + } + + req->dest_port = cmd_info->dest_port; + } + + osif_debug("cmd: %u for duration: %u s, flush period: %u ms", + req->cmd, req->duration, req->flush_period); + + status = os_if_qmi_txn_init(&qmi_wfds, &txn, wfds_gen_resp_msg_v01_ei, + resp); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI txn for WFDS unit test cmd init failed %d", + status); + goto out; + } + + status = os_if_qmi_send_request(&qmi_wfds, NULL, &txn, + QMI_WFDS_UT_CMD_REQ_V01, + WFDS_UT_CMD_REQ_MSG_V01_MAX_MSG_LEN, + wfds_ut_cmd_req_msg_v01_ei, req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("QMI WFDS UT command request send failed %d", + status); + os_if_qmi_txn_cancel(&txn); + goto out; + } + + status = os_if_qmi_txn_wait(&txn, QMI_WFDS_TIMEOUT_JF); + if (QDF_IS_STATUS_ERROR(status)) { + osif_info("Wait for unit test cmd response timed out %d", + status); + goto out; + } + + qdf_assert(resp->resp.result == QMI_RESULT_SUCCESS_V01); + +out: + qdf_mem_free(resp); + qdf_mem_free(req); + + return status; +} + +/** + * os_if_qmi_wfds_new_server() - New server callback triggered when service is + * up. + * @qmi_hdl: QMI client handle + * @qmi_svc: QMI service handle + * + * Returns: 0 on success else OS failure code + */ +static int +os_if_qmi_wfds_new_server(struct qmi_handle *qmi_hdl, + struct qmi_service *qmi_svc) +{ + QDF_STATUS status; + + status = os_if_qmi_connect_to_svc(qmi_hdl, qmi_svc); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to connect to WFDS QMI service port"); + return qdf_status_to_os_return(status); + } + + status = ucfg_dp_wfds_new_server(); + + return qdf_status_to_os_return(status); +} + +/** + * os_if_qmi_wfds_del_server() - Del server callback triggered when service is + * down. + * @qmi_hdl: QMI client handle + * @qmi_svc: QMI service handle + * + * Returns: None + */ +static void +os_if_qmi_wfds_del_server(struct qmi_handle *qmi_hdl, + struct qmi_service *qmi_svc) +{ + ucfg_dp_wfds_del_server(); +} + +static struct qmi_msg_handler qmi_wfds_msg_handler[] = { + { + .type = QMI_INDICATION, + .msg_id = QMI_WFDS_MEM_IND_V01, + .ei = wfds_mem_ind_msg_v01_ei, + .decoded_size = sizeof(struct wfds_mem_ind_msg_v01), + .fn = os_if_qmi_wfds_request_mem_ind_cb + }, + { + .type = QMI_INDICATION, + .msg_id = QMI_WFDS_IPCC_MAP_N_CFG_IND_V01, + .ei = wfds_ipcc_map_n_cfg_ind_msg_v01_ei, + .decoded_size = sizeof(struct wfds_ipcc_map_n_cfg_ind_msg_v01), + .fn = os_if_wfds_ipcc_map_n_cfg_ind_cb + }, +}; + +static struct qmi_ops qmi_wfds_ops = { + .new_server = os_if_qmi_wfds_new_server, + .del_server = os_if_qmi_wfds_del_server, +}; + +/** + * os_if_qmi_wfds_init() - Initialize WFDS QMI client + * + * Returns: QDF status + */ +static QDF_STATUS os_if_qmi_wfds_init(void) +{ + QDF_STATUS status; + + status = os_if_qmi_handle_init(&qmi_wfds, QMI_WFDS_MAX_RECV_BUF_SIZE, + &qmi_wfds_ops, qmi_wfds_msg_handler); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("WFDS QMI handle init failed"); + return status; + } + + status = os_if_qmi_add_lookup(&qmi_wfds, WFDS_SERVICE_ID_V01, + WFDS_SERVICE_VERS_V01, + QMI_WFDS_SERVICE_INS_ID_V01); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("WFDS QMI add lookup failed"); + os_if_qmi_handle_release(&qmi_wfds); + return status; + } + + return status; +} + +/** + * os_if_qmi_wfds_deinit() - Deinitialize WFDS QMI client + * + * Returns: None + */ +static void os_if_qmi_wfds_deinit(void) +{ + os_if_qmi_handle_release(&qmi_wfds); +} + +void os_if_qmi_wfds_register_callbacks(struct wlan_qmi_psoc_callbacks *cb_obj) +{ + cb_obj->qmi_wfds_init = os_if_qmi_wfds_init; + cb_obj->qmi_wfds_deinit = os_if_qmi_wfds_deinit; + cb_obj->qmi_wfds_send_config_msg = os_if_qmi_wfds_send_config_msg; + cb_obj->qmi_wfds_send_req_mem_msg = os_if_qmi_wfds_send_req_mem_msg; + cb_obj->qmi_wfds_send_ipcc_map_n_cfg_msg = + os_if_qmi_wfds_ipcc_map_n_cfg_msg; + cb_obj->qmi_wfds_send_misc_req_msg = + os_if_qmi_wfds_send_misc_req_msg; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi_wifi_driver_service_v01.c b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi_wifi_driver_service_v01.c new file mode 100644 index 0000000000..e3b1e8d90a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/qmi/src/os_if_qmi_wifi_driver_service_v01.c @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "os_if_qmi_wifi_driver_service_v01.h" +#include + +struct qmi_elem_info wfds_gen_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wfds_gen_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct qmi_elem_info wifi_drv_qmi_srng_information_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + ring_id), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wifi_drv_qmi_srng_direction_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + dir), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + num_entries), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + entry_size), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + ring_base_paddr), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + hp_paddr), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_srng_information_v01, + tp_paddr), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct qmi_elem_info wifi_drv_qmi_ce_information_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_ce_information_v01, + ce_id), + }, + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wifi_drv_qmi_pipe_dir_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_ce_information_v01, + ce_dir), + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wifi_drv_qmi_srng_information_v01), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_ce_information_v01, + srng_info), + .ei_array = wifi_drv_qmi_srng_information_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_config_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_config_req_msg_v01, + ce_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = WFDS_CE_MAX_SRNG_V01, + .elem_size = sizeof(struct wifi_drv_qmi_ce_information_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_config_req_msg_v01, + ce_info), + .ei_array = wifi_drv_qmi_ce_information_v01_ei, + }, + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct wifi_drv_qmi_srng_information_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct wfds_config_req_msg_v01, + rx_refill_ring), + .ei_array = wifi_drv_qmi_srng_information_v01_ei, + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct wfds_config_req_msg_v01, + shadow_rdptr_mem_paddr), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof(struct wfds_config_req_msg_v01, + shadow_rdptr_mem_size), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof(struct wfds_config_req_msg_v01, + shadow_wrptr_mem_paddr), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof(struct wfds_config_req_msg_v01, + shadow_wrptr_mem_size), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x07, + .offset = offsetof(struct wfds_config_req_msg_v01, + rx_pkt_tlv_len), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x08, + .offset = offsetof(struct wfds_config_req_msg_v01, + rx_rbm), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0x09, + .offset = offsetof(struct wfds_config_req_msg_v01, + pcie_bar_pa), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x0A, + .offset = offsetof(struct wfds_config_req_msg_v01, + pci_slot), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x0B, + .offset = offsetof(struct wfds_config_req_msg_v01, + lpass_ep_id), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct qmi_elem_info wifi_drv_qmi_mem_arena_information_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_mem_arena_information_v01, + entry_size), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_mem_arena_information_v01, + num_entries), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_mem_ind_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_mem_ind_msg_v01, + mem_arena_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = WFDS_MEM_ARENA_MAX_V01, + .elem_size = sizeof(struct wifi_drv_qmi_mem_arena_information_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_mem_ind_msg_v01, + mem_arena_info), + .ei_array = wifi_drv_qmi_mem_arena_information_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct qmi_elem_info wifi_drv_qmi_mem_arena_page_information_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_mem_arena_page_information_v01, + num_entries_per_page), + }, + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_mem_arena_page_information_v01, + page_dma_addr_len), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = WFDS_PAGE_INFO_MAX_ARRAY_SIZE_V01, + .elem_size = sizeof(u64), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_mem_arena_page_information_v01, + page_dma_addr), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_mem_req_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_mem_req_msg_v01, + mem_arena_page_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = WFDS_MEM_ARENA_MAX_V01, + .elem_size = sizeof(struct wifi_drv_qmi_mem_arena_page_information_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_mem_req_msg_v01, + mem_arena_page_info), + .ei_array = wifi_drv_qmi_mem_arena_page_information_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static struct qmi_elem_info wifi_drv_qmi_ipcc_information_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_ipcc_information_v01, + ce_id), + }, + { + .data_type = QMI_UNSIGNED_8_BYTE, + .elem_len = 1, + .elem_size = sizeof(u64), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_ipcc_information_v01, + ipcc_trig_addr), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0, + .offset = offsetof(struct wifi_drv_qmi_ipcc_information_v01, + ipcc_trig_data), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_ipcc_map_n_cfg_ind_msg_v01_ei[] = { + { + .data_type = QMI_DATA_LEN, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_ipcc_map_n_cfg_ind_msg_v01, + ipcc_ce_info_len), + }, + { + .data_type = QMI_STRUCT, + .elem_len = WFDS_CE_MAX_SRNG_V01, + .elem_size = sizeof(struct wifi_drv_qmi_ipcc_information_v01), + .array_type = VAR_LEN_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_ipcc_map_n_cfg_ind_msg_v01, + ipcc_ce_info), + .ei_array = wifi_drv_qmi_ipcc_information_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_ipcc_map_n_cfg_req_msg_v01_ei[] = { + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_ipcc_map_n_cfg_req_msg_v01, + status), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_misc_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wifi_drv_qmi_event_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_misc_req_msg_v01, + event), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_misc_ind_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wifi_drv_qmi_event_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct wfds_misc_ind_msg_v01, + event), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +struct qmi_elem_info wfds_ut_cmd_req_msg_v01_ei[] = { + { + .data_type = QMI_SIGNED_4_BYTE_ENUM, + .elem_len = 1, + .elem_size = sizeof(enum wifi_drv_qmi_ut_cmd_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x01, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + cmd), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + duration), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x03, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + flush_period), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x04, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + num_pkts), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x05, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + buf_size), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x06, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + ether_type), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 6, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x07, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + src_mac), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 6, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x08, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + dest_mac), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x09, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + ip_ver), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 16, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x0A, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + src_ip_addr), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 16, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x0B, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + dest_ip_addr), + }, + { + .data_type = QMI_UNSIGNED_2_BYTE, + .elem_len = 1, + .elem_size = sizeof(u16), + .array_type = NO_ARRAY, + .tlv_type = 0x0C, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + dest_port), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 256, + .elem_size = sizeof(u8), + .array_type = STATIC_ARRAY, + .tlv_type = 0x0D, + .offset = offsetof(struct + wfds_ut_cmd_req_msg_v01, + misc), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/son/inc/os_if_son.h b/qcom/opensource/wlan/qcacld-3.0/os_if/son/inc/os_if_son.h new file mode 100644 index 0000000000..358da99857 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/son/inc/os_if_son.h @@ -0,0 +1,794 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: os_if_son.h + * + * WLAN Host Device Driver file for son (Self Organizing Network) + * support. + * + */ +#ifndef _OS_IF_SON_H_ +#define _OS_IF_SON_H_ + +#include +#include +#include +#include +#include +#include + +#define INVALID_WIDTH 0xFF + +/** + * struct son_callbacks - struct containing callback to non-converged driver + * @os_if_is_acs_in_progress: whether acs is in progress or not + * @os_if_set_chan_ext_offset: set chan extend offset + * @os_if_get_chan_ext_offset: get chan extend offset + * @os_if_set_bandwidth: set band width + * @os_if_get_bandwidth: get band width + * @os_if_set_chan: set chan + * @os_if_get_sta_count: get station count + * @os_if_set_country_code: set country code + * @os_if_set_candidate_freq: set freq to switch after radar detection + * @os_if_get_candidate_freq: get freq to switch after radar detection + * @os_if_set_phymode: set phy mode + * @os_if_get_phymode: get phy mode + * @os_if_get_rx_nss: Gets number of RX spatial streams + * @os_if_set_acl_policy: set acl policy + * @os_if_get_acl_policy: get acl policy + * @os_if_add_acl_mac: add mac to acl + * @os_if_del_acl_mac: del mac from acl + * @os_if_kickout_mac: kickout sta with given mac + * @os_if_set_chwidth: set chan width + * @os_if_get_chwidth: get chan width + * @os_if_get_sta_list: get sta list + * @os_if_get_sta_space: get sta space + * @os_if_deauth_sta: Deauths the target peer + * @os_if_modify_acl: Add/Del target peer in ACL + * @os_if_get_vdev_by_netdev: Get vdev from net device + * @os_if_trigger_objmgr_object_creation: Trigger objmgr object creation + * @os_if_trigger_objmgr_object_deletion: Trigger objmgr object deletion + * @os_if_start_acs: Trigger ACS + * @os_if_set_acs_channels: Set channel list for ACS + * @os_if_get_acs_report: Gets the ACS report + * @os_if_get_node_info: Gets the datarate info for node + * @os_if_get_peer_capability: Gets peer capability + * @os_if_get_peer_max_mcs_idx: Gets peer max MCS index + * @os_if_get_sta_stats: Get sta stats + */ +struct son_callbacks { + uint32_t (*os_if_is_acs_in_progress)(struct wlan_objmgr_vdev *vdev); + int (*os_if_set_chan_ext_offset)( + struct wlan_objmgr_vdev *vdev, + enum sec20_chan_offset son_chan_ext_offset); + enum sec20_chan_offset (*os_if_get_chan_ext_offset)( + struct wlan_objmgr_vdev *vdev); + int (*os_if_set_bandwidth)(struct wlan_objmgr_vdev *vdev, + uint32_t son_bandwidth); + uint32_t (*os_if_get_bandwidth)(struct wlan_objmgr_vdev *vdev); + int (*os_if_set_chan)(struct wlan_objmgr_vdev *vdev, int chan, + enum wlan_band_id son_band); + uint32_t (*os_if_get_sta_count)(struct wlan_objmgr_vdev *vdev); + int (*os_if_set_country_code)(struct wlan_objmgr_vdev *vdev, + char *country_code); + int (*os_if_set_candidate_freq)(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + qdf_freq_t (*os_if_get_candidate_freq)(struct wlan_objmgr_vdev *vdev); + int (*os_if_set_phymode)(struct wlan_objmgr_vdev *vdev, + enum ieee80211_phymode mode); + enum ieee80211_phymode (*os_if_get_phymode)( + struct wlan_objmgr_vdev *vdev); + uint8_t (*os_if_get_rx_nss)(struct wlan_objmgr_vdev *vdev); + QDF_STATUS (*os_if_set_acl_policy)(struct wlan_objmgr_vdev *vdev, + ieee80211_acl_cmd son_acl_policy); + ieee80211_acl_cmd (*os_if_get_acl_policy)( + struct wlan_objmgr_vdev *vdev); + int (*os_if_add_acl_mac)(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac); + int (*os_if_del_acl_mac)(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac); + int (*os_if_kickout_mac)(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac); + int (*os_if_set_chwidth)(struct wlan_objmgr_vdev *vdev, + enum ieee80211_cwm_width son_chwidth); + enum ieee80211_cwm_width (*os_if_get_chwidth)( + struct wlan_objmgr_vdev *vdev); + void (*os_if_get_sta_list)(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_sta_info *req, + uint32_t *space); + uint32_t (*os_if_get_sta_space)(struct wlan_objmgr_vdev *vdev); + void (*os_if_deauth_sta)(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool ignore_frame); + void (*os_if_modify_acl)(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool allow_auth); + struct wlan_objmgr_vdev *(*os_if_get_vdev_by_netdev) + (struct net_device *dev); + QDF_STATUS (*os_if_trigger_objmgr_object_creation) + (enum wlan_umac_comp_id id); + QDF_STATUS (*os_if_trigger_objmgr_object_deletion) + (enum wlan_umac_comp_id id); + int (*os_if_start_acs)(struct wlan_objmgr_vdev *vdev, uint8_t enable); + int (*os_if_set_acs_channels)(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_athdbg *req); + int (*os_if_get_acs_report)(struct wlan_objmgr_vdev *vdev, + struct ieee80211_acs_dbg *acs_r); + QDF_STATUS (*os_if_get_node_info)(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + wlan_node_info *nodeinfo); + QDF_STATUS (*os_if_get_peer_capability)(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + wlan_peer_cap *cap); + uint32_t (*os_if_get_peer_max_mcs_idx)(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer); + int (*os_if_get_sta_stats)(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + struct ieee80211_nodestats *stats); +}; + +/** + * enum os_if_son_vendor_cmd_type - Enum to specify get/set command + * @OS_IF_SON_VENDOR_GET_CMD: Get type command called from wificonfiguration + * vendor command handler + * @OS_IF_SON_VENDOR_SET_CMD: Set type command called from wificonfiguration + * vendor command handler + * @OS_IF_SON_VENDOR_MAX_CMD: Max cmd type + */ +enum os_if_son_vendor_cmd_type { + OS_IF_SON_VENDOR_GET_CMD, + OS_IF_SON_VENDOR_SET_CMD, + OS_IF_SON_VENDOR_MAX_CMD, +}; + +/** + * struct os_if_son_rx_ops - Contains cb for os_if rx ops used by SON + * @parse_generic_nl_cmd: Callback for parsing generic nl vendor commands + */ +struct os_if_son_rx_ops { + int (*parse_generic_nl_cmd)(struct wiphy *wiphy, + struct wireless_dev *wdev, void *params, + enum os_if_son_vendor_cmd_type type); +}; + +/** + * struct wlan_os_if_son_ops - Contains cb for os_if txrx ops used by SON + * @son_osif_rx_ops: structure to contain rx ops + */ +struct wlan_os_if_son_ops { + struct os_if_son_rx_ops son_osif_rx_ops; +}; + +/** + * wlan_os_if_son_ops_register_cb() - Set son os_if ops cb + * @handler: son os_if ops cb table + * + * Return: void + */ +void +wlan_os_if_son_ops_register_cb(void (*handler)(struct wlan_os_if_son_ops *)); + +/** + * os_if_son_register_osif_ops() - Register son os_if ops with os_if + * + * Return: void + */ +void os_if_son_register_osif_ops(void); + +/** + * os_if_son_register_lmac_if_ops() - Register son lmac_if rx_ops with lmac + * @psoc: objmrg psoc handle + * + * Register son lmac_if rx_ops with lmac to be called by SON DLKM + * + * Return: void + */ +void os_if_son_register_lmac_if_ops(struct wlan_objmgr_psoc *psoc); + +/** + * os_if_son_register_hdd_callbacks() - register son hdd callback + * @psoc: psoc + * @cb_obj: pointer to callback + * + * Return: void + */ +void os_if_son_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct son_callbacks *cb_obj); + +/** + * os_if_son_get_freq() - get freq + * @vdev: vdev + * + * Return: freq of given vdev + */ +qdf_freq_t os_if_son_get_freq(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_is_acs_in_progress() - whether ACS in progress or not + * @vdev: vdev + * + * Return: true if ACS is in progress + */ +uint32_t os_if_son_is_acs_in_progress(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_is_cac_in_progress() - whether CAC is in progress or not + * @vdev: vdev + * + * Return: true if CAC is in progress + */ +uint32_t os_if_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_set_chan_ext_offset() - set chan extend offset + * @vdev: vdev + * @son_chan_ext_offset: son chan extend offset + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_chan_ext_offset(struct wlan_objmgr_vdev *vdev, + enum sec20_chan_offset son_chan_ext_offset); + +/** + * os_if_son_get_chan_ext_offset() - get chan extend offset + * @vdev: vdev + * + * Return: enum sec20_chan_offset + */ +enum sec20_chan_offset os_if_son_get_chan_ext_offset( + struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_set_bandwidth() - set band width + * @vdev: vdev + * @son_bandwidth: band width + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_bandwidth(struct wlan_objmgr_vdev *vdev, + uint32_t son_bandwidth); + +/** + * os_if_son_get_bandwidth() - get band width + * @vdev: vdev + * + * Return: band width + */ +uint32_t os_if_son_get_bandwidth(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_get_band_info() - get band info + * @vdev: vdev + * + * Return: band info + */ +uint32_t os_if_son_get_band_info(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_get_chan_list() - get a list of chan information + * @vdev: vdev + * @ic_chans: chan information array to get + * @chan_info: pointer to ieee80211_channel_info to get + * @ic_nchans: number of chan information it gets + * @flag_160: flag indicating the API to fill the center frequencies of 160MHz. + * @flag_6ghz: flag indicating the API to include 6 GHz or not + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_get_chan_list(struct wlan_objmgr_vdev *vdev, + struct ieee80211_ath_channel *ic_chans, + struct ieee80211_channel_info *chan_info, + uint8_t *ic_nchans, bool flag_160, bool flag_6ghz); + +/** + * os_if_son_get_sta_count() - get connected STA count + * @vdev: vdev + * + * Return: connected STA count + */ +uint32_t os_if_son_get_sta_count(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_get_bssid() - get bssid of given vdev + * @vdev: vdev + * @bssid: pointer to BSSID + * + * Return: 0 if BSSID is gotten successfully + */ +int os_if_son_get_bssid(struct wlan_objmgr_vdev *vdev, + uint8_t bssid[QDF_MAC_ADDR_SIZE]); + +/** + * os_if_son_get_ssid() - get ssid of given vdev + * @vdev: vdev + * @ssid: pointer to SSID + * @ssid_len: ssid length + * + * Return: 0 if SSID is gotten successfully + */ +int os_if_son_get_ssid(struct wlan_objmgr_vdev *vdev, + char ssid[WLAN_SSID_MAX_LEN + 1], + uint8_t *ssid_len); + +/** + * os_if_son_set_chan() - set chan + * @vdev: vdev + * @chan: given chan + * @son_band: given band + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_chan(struct wlan_objmgr_vdev *vdev, + int chan, enum wlan_band_id son_band); + +/** + * os_if_son_set_cac_timeout() - set cac timeout + * @vdev: vdev + * @cac_timeout: cac timeount to set + * + * Return: 0 if cac time out is set successfully + */ +int os_if_son_set_cac_timeout(struct wlan_objmgr_vdev *vdev, + int cac_timeout); + +/** + * os_if_son_get_cac_timeout() - get cac timeout + * @vdev: vdev + * @cac_timeout: cac timeout to get + * + * Return 0 if cac time out is get successfully + */ +int os_if_son_get_cac_timeout(struct wlan_objmgr_vdev *vdev, + int *cac_timeout); + +/** + * os_if_son_set_country_code() - set country code + * @vdev: vdev + * @country_code: country code to set + * + * Return: 0 if country code is set successfully + */ +int os_if_son_set_country_code(struct wlan_objmgr_vdev *vdev, + char *country_code); + +/** + * os_if_son_get_country_code() - get country code + * @vdev: vdev + * @country_code: country code to get + * + * Return: 0 if country code is get successfully + */ +int os_if_son_get_country_code(struct wlan_objmgr_vdev *vdev, + char *country_code); + +/** + * os_if_son_set_candidate_freq() - set freq to switch after radar detection + * @vdev: vdev + * @freq: freq to switch + * + * Return: 0 if candidate freq is set successfully + */ +int os_if_son_set_candidate_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq); + +/** + * os_if_son_get_candidate_freq() - get freq to switch after radar detection + * @vdev: vdev + * + * Return: candidate freq to switch after radar detection + */ +qdf_freq_t os_if_son_get_candidate_freq(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_get_phymode() - get phy mode + * @vdev: vdev + * + * Return: enum ieee80211_phymode + */ +enum ieee80211_phymode os_if_son_get_phymode(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_set_phymode() - set phy mode + * @vdev: vdev + * @mode: son phy mode to set + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_phymode(struct wlan_objmgr_vdev *vdev, + enum ieee80211_phymode mode); + +/** + * os_if_son_get_phy_stats() - get phy stats + * @vdev: vdev + * @phy_stats: phy stats + * + * Return: void + */ +void os_if_son_get_phy_stats(struct wlan_objmgr_vdev *vdev, + struct ol_ath_radiostats *phy_stats); + +/** + * os_if_son_cbs_init() - cbs init + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_cbs_init(void); + +/** + * os_if_son_cbs_deinit() - cbs deinit + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_cbs_deinit(void); + +/** + * os_if_son_set_cbs() - enable cbs or disable + * @vdev: vdev + * @enable: true or false + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_cbs(struct wlan_objmgr_vdev *vdev, + bool enable); + +/** + * os_if_son_set_cbs_wait_time() - set cbs wait time + * @vdev: vdev + * @val: value + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * os_if_son_set_cbs_dwell_split_time() - set cbs dwell split time + * @vdev: vdev + * @val: value + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev, + uint32_t val); + +/** + * os_if_son_get_chan_util() - get chan utilization + * @vdev: vdev + * + * Return: chan utilization (0 - 100) + */ +uint8_t os_if_son_get_chan_util(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_pdev_ops() - Handles PDEV specific SON commands + * @pdev: pdev + * @type: SON command to handle + * @data: Input Data + * @ret: Output Data + * + * Return: QDF_SUCCCESS_SUCCESS in case of success + */ +QDF_STATUS os_if_son_pdev_ops(struct wlan_objmgr_pdev *pdev, + enum wlan_mlme_pdev_param type, + void *data, void *ret); + +/** + * os_if_son_vdev_ops() - Handles VDEV specific SON commands + * @vdev: vdev + * @type: SON command to handle + * @data: Input Data + * @ret: Output Data + * + * Return: QDF_SUCCCESS_SUCCESS in case of success + */ +QDF_STATUS os_if_son_vdev_ops(struct wlan_objmgr_vdev *vdev, + enum wlan_mlme_vdev_param type, + void *data, void *ret); + +/** + * os_if_son_peer_ops() - Handles PEER specific SON commands + * @peer: peer + * @type: SON command to handle + * @data: Input Data. Pointer to wlan_mlme_peer_data + * @ret: Output Data. Pointer to wlan_mlme_peer_data + * + * Return: QDF_SUCCCESS_SUCCESS in case of success + */ +QDF_STATUS os_if_son_peer_ops(struct wlan_objmgr_peer *peer, + enum wlan_mlme_peer_param type, + union wlan_mlme_peer_data *data, + union wlan_mlme_peer_data *ret); + +/** + * os_if_son_scan_db_iterate() - get country code + * @pdev: pdev + * @handler: scan_iterator + * @arg: argument to be passed to handler + * + * Return: QDF_SUCCCESS_SUCCESS in case of success + */ +QDF_STATUS os_if_son_scan_db_iterate(struct wlan_objmgr_pdev *pdev, + scan_iterator_func handler, void *arg); + +/** + * os_if_son_acl_is_probe_wh_set() - Withheld probes for given mac_addr, + * not supported + * @vdev: vdev + * @mac_addr: 6-Byte MAC address + * @probe_rssi: Probe Request RSSI + * + * Return: true / false + */ +bool os_if_son_acl_is_probe_wh_set(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac_addr, + uint8_t probe_rssi); + +/** + * os_if_son_get_rx_streams() - Gets number of RX spatial streams + * @vdev: target vdev + * + * Return: number of spatial stream + */ +uint8_t os_if_son_get_rx_streams(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_cfg80211_reply() - replies to cfg80211 + * @sk_buf: sk_buff to uper layer + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS os_if_son_cfg80211_reply(qdf_nbuf_t sk_buf); + +/** + * os_if_son_vdev_is_wds() - checks if wds capability is supported or not + * @vdev: Pointer to vdev + * + * Return: true if wds is supported + */ +bool os_if_son_vdev_is_wds(struct wlan_objmgr_vdev *vdev); + +/* + * os_if_son_set_acl_policy() - set acl policy + * @vdev: vdev + * @son_acl_policy: son acl policy. enum ieee80211_acl_cmd + * + * Return: QDF_STATUS + */ +QDF_STATUS os_if_son_set_acl_policy(struct wlan_objmgr_vdev *vdev, + ieee80211_acl_cmd son_acl_policy); + +/** + * os_if_son_get_acl_policy() - get acl policy + * @vdev: vdev + * + * Return: acl policy. enum ieee80211_acl_cmd + */ +ieee80211_acl_cmd os_if_son_get_acl_policy(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_add_acl_mac() - add mac to acl + * @vdev: vdev + * @acl_mac: mac to add + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_add_acl_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac); + +/** + * os_if_son_get_sta_space() - get sta space + * @vdev: target vdev + * + * Return: bytes which is needed to fill sta information + */ +uint32_t os_if_son_get_sta_space(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_get_sta_list() - get sta list + * @vdev: target vdev + * @si: pointer to ieee80211req_sta_info + * @space: space left + * + * Return: void + */ +void os_if_son_get_sta_list(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_sta_info *si, uint32_t *space); + +/** + * os_if_son_del_acl_mac() - del mac from acl + * @vdev: vdev + * @acl_mac: mac to del + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_del_acl_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac); + +/** + * os_if_son_kickout_mac() - kickout sta with given mac + * @vdev: vdev + * @mac: sta mac to kickout + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_kickout_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac); + +/** + * os_if_son_set_chwidth() - set chan width + * @vdev: vdev + * @son_chwidth: son chan width + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_set_chwidth(struct wlan_objmgr_vdev *vdev, + enum ieee80211_cwm_width son_chwidth); + +/** + * os_if_son_get_chwidth() - get chan width + * @vdev: vdev + * + * Return: son chan width + */ +enum ieee80211_cwm_width os_if_son_get_chwidth(struct wlan_objmgr_vdev *vdev); + +/** + * os_if_son_deauth_peer_sta - Deauths specified STA + * @vdev: vdev + * @peer_mac: Target peer MAC address + * @ignore_frame: True to silently deauth the peer + * + * Return: void + */ +void os_if_son_deauth_peer_sta(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool ignore_frame); + +/** + * os_if_son_modify_acl - Updates ACL with given peer + * @vdev: vdev + * @peer_mac: Target peer MAC address + * @allow_auth: True to allow specified peer to connect + * + * Return: void + */ +void os_if_son_modify_acl(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool allow_auth); + +/** + * os_if_son_deliver_ald_event() - deliver ald events to son + * @vdev: vdev object + * @peer: peer object + * @event: Name of the event + * @event_data: event data + * + * Return: 0 on success + */ +int os_if_son_deliver_ald_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum ieee80211_event_type event, + void *event_data); +/** + * os_if_son_get_vdev_by_netdev() - Get vdev from net device + * @dev: net device struct + * + * Return: objmgr vdev on success else NULL + */ +struct wlan_objmgr_vdev *os_if_son_get_vdev_by_netdev(struct net_device *dev); + +/** + * os_if_son_trigger_objmgr_object_deletion() - Trigger objmgr object deletion + * @id: umac component id + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS os_if_son_trigger_objmgr_object_deletion(enum wlan_umac_comp_id id); + +/** + * os_if_son_trigger_objmgr_object_creation() - Trigger objmgr object creation + * @id: umac component id + * + * Return: QDF_STATUS_SUCCESS on success + */ +QDF_STATUS os_if_son_trigger_objmgr_object_creation(enum wlan_umac_comp_id id); + +/** + * os_if_son_start_acs() - Triggers ACS on the target vdev + * @vdev: target vdev + * @enable: True - to start ACS + * + * Return: 0 on success + */ +int os_if_son_start_acs(struct wlan_objmgr_vdev *vdev, uint8_t enable); + +/** + * os_if_son_set_acs_chan() - Set channel list for ACS + * @vdev: target vdev + * @req: channel list + * + * Return: 0 on success + */ +int os_if_son_set_acs_chan(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_athdbg *req); + +/** + * os_if_son_get_acs_report() - Get ACS report + * @vdev: target vdev + * @acs_r: ACS report structure + * + * Return: 0 on success + */ +int os_if_son_get_acs_report(struct wlan_objmgr_vdev *vdev, + struct ieee80211_acs_dbg *acs_r); + +/** + * os_if_son_parse_generic_nl_cmd() - Sends the Generic vendor commands + * to SON. + * @wiphy: Standard wiphy object + * @wdev: wireless device + * @tb: Command type structure pointer + * @type: Get/Set command + * + * This function parses the GENERIC vendor commands received from + * userspace then sends the extracted data to SON module for further + * processing along with wiphy, wdev, extected structure - param + * and command type i.e. GET / SET. Each of the GENERIC commands are + * interdependent and hence in SON module, they will be further + * parsed based on type i.e. GET / SET. + * + * Return: 0 on success + */ +int os_if_son_parse_generic_nl_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb, + enum os_if_son_vendor_cmd_type type); + +/** + * os_if_son_get_node_datarate_info() - Get datarate info about given mac + * @vdev: vdev_obj + * @mac_addr: mac_address to get datarate information + * @node_info: object to store datarate information + * + * Return: void + */ +QDF_STATUS os_if_son_get_node_datarate_info(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + wlan_node_info *node_info); + +/** + * os_if_son_get_peer_max_mcs_idx() - Get max mcs index of the peer + * @vdev: vdev obj + * @peer: peer obj + * + * Return: max mcs index on success / 0 on failure + */ +uint32_t os_if_son_get_peer_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer); + +/** + * os_if_son_get_sta_stats() - get connected sta rssi and estimated data rate + * @vdev: pointer to vdev + * @mac_addr: connected sta mac addr + * @stats: pointer to ieee80211_nodestats + * + * Return: 0 on success, negative errno on failure + */ +int os_if_son_get_sta_stats(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr, + struct ieee80211_nodestats *stats); +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/son/src/os_if_son.c b/qcom/opensource/wlan/qcacld-3.0/os_if/son/src/os_if_son.c new file mode 100644 index 0000000000..a7ac9ce2f9 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/son/src/os_if_son.c @@ -0,0 +1,1836 @@ +/* + * Copyright (c) 2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: os_if_son.c + * + * WLAN Host Device Driver file for son (Self Organizing Network) + * support. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct son_callbacks g_son_os_if_cb; +static struct wlan_os_if_son_ops g_son_os_if_txrx_ops; +static void (*os_if_son_ops_cb)(struct wlan_os_if_son_ops *son_ops); + +void os_if_son_register_hdd_callbacks(struct wlan_objmgr_psoc *psoc, + struct son_callbacks *cb_obj) +{ + g_son_os_if_cb = *cb_obj; +} + +qdf_freq_t os_if_son_get_freq(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev; + qdf_freq_t freq; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return 0; + } + + freq = ucfg_son_get_operation_chan_freq_vdev_id(pdev, + wlan_vdev_get_id(vdev)); + osif_debug("vdev %d get freq %d", wlan_vdev_get_id(vdev), freq); + + return freq; +} +qdf_export_symbol(os_if_son_get_freq); + +uint32_t os_if_son_is_acs_in_progress(struct wlan_objmgr_vdev *vdev) +{ + uint32_t acs_in_progress; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + acs_in_progress = g_son_os_if_cb.os_if_is_acs_in_progress(vdev); + osif_debug("vdev %d acs_in_progress %d", + wlan_vdev_get_id(vdev), acs_in_progress); + + return acs_in_progress; +} +qdf_export_symbol(os_if_son_is_acs_in_progress); + +uint32_t os_if_son_is_cac_in_progress(struct wlan_objmgr_vdev *vdev) +{ + uint32_t cac_in_progress; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + cac_in_progress = ucfg_son_is_cac_in_progress(vdev); + osif_debug("vdev %d cac_in_progress %d", + wlan_vdev_get_id(vdev), cac_in_progress); + + return cac_in_progress; +} +qdf_export_symbol(os_if_son_is_cac_in_progress); + +int os_if_son_set_chan_ext_offset(struct wlan_objmgr_vdev *vdev, + enum sec20_chan_offset son_chan_ext_offset) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + ret = g_son_os_if_cb.os_if_set_chan_ext_offset(vdev, + son_chan_ext_offset); + osif_debug("vdev %d set_chan_ext_offset %d, ret %d", + wlan_vdev_get_id(vdev), son_chan_ext_offset, ret); + + return ret; +} +qdf_export_symbol(os_if_son_set_chan_ext_offset); + +enum sec20_chan_offset os_if_son_get_chan_ext_offset( + struct wlan_objmgr_vdev *vdev) +{ + enum sec20_chan_offset chan_ext_offset; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + chan_ext_offset = g_son_os_if_cb.os_if_get_chan_ext_offset(vdev); + osif_debug("vdev %d chan_ext_offset %d", + wlan_vdev_get_id(vdev), chan_ext_offset); + + return chan_ext_offset; +} +qdf_export_symbol(os_if_son_get_chan_ext_offset); + +int os_if_son_set_bandwidth(struct wlan_objmgr_vdev *vdev, + uint32_t son_bandwidth) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + ret = g_son_os_if_cb.os_if_set_bandwidth(vdev, son_bandwidth); + osif_debug("vdev %d son_bandwidth %d ret %d", + wlan_vdev_get_id(vdev), son_bandwidth, ret); + + return ret; +} +qdf_export_symbol(os_if_son_set_bandwidth); + +uint32_t os_if_son_get_bandwidth(struct wlan_objmgr_vdev *vdev) +{ + uint32_t bandwidth; + + if (!vdev) { + osif_err("null vdev"); + return NONHT; + } + + bandwidth = g_son_os_if_cb.os_if_get_bandwidth(vdev); + osif_debug("vdev %d son_bandwidth %d", + wlan_vdev_get_id(vdev), bandwidth); + + return bandwidth; +} +qdf_export_symbol(os_if_son_get_bandwidth); + +static uint32_t os_if_band_bitmap_to_son_band_info( + uint32_t reg_wifi_band_bitmap) +{ + uint32_t son_band_info = FULL_BAND_RADIO; + + if (!(reg_wifi_band_bitmap & BIT(REG_BAND_5G)) && + !(reg_wifi_band_bitmap & BIT(REG_BAND_6G))) + return NON_5G_RADIO; + if (reg_wifi_band_bitmap & BIT(REG_BAND_6G) && + !(reg_wifi_band_bitmap & BIT(REG_BAND_2G)) && + !(reg_wifi_band_bitmap & BIT(REG_BAND_5G))) + return BAND_6G_RADIO; + + return son_band_info; +} + +uint32_t os_if_son_get_band_info(struct wlan_objmgr_vdev *vdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_pdev *pdev; + uint32_t reg_wifi_band_bitmap; + uint32_t band_info; + + if (!vdev) { + osif_err("null vdev"); + return NO_BAND_INFORMATION_AVAILABLE; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return NO_BAND_INFORMATION_AVAILABLE; + } + + status = ucfg_reg_get_band(pdev, ®_wifi_band_bitmap); + if (!QDF_IS_STATUS_SUCCESS(status)) { + osif_err("failed to get band"); + return NO_BAND_INFORMATION_AVAILABLE; + } + + band_info = os_if_band_bitmap_to_son_band_info(reg_wifi_band_bitmap); + osif_debug("vdev %d band_info %d", + wlan_vdev_get_id(vdev), band_info); + + return band_info; +} +qdf_export_symbol(os_if_son_get_band_info); + +#define BW_WITHIN(min, bw, max) ((min) <= (bw) && (bw) <= (max)) +/** + * os_if_son_fill_chan_info() - fill chan info + * @chan_info: chan info to fill + * @chan_num: chan number + * @primary_freq: chan frequency + * @ch_num_seg1: channel number for segment 1 + * @ch_num_seg2: channel number for segment 2 + * + * Return: void + */ +static void os_if_son_fill_chan_info(struct ieee80211_channel_info *chan_info, + uint8_t chan_num, qdf_freq_t primary_freq, + uint8_t ch_num_seg1, uint8_t ch_num_seg2) +{ + chan_info->ieee = chan_num; + chan_info->freq = primary_freq; + chan_info->vhtop_ch_num_seg1 = ch_num_seg1; + chan_info->vhtop_ch_num_seg2 = ch_num_seg2; +} + +/** + * os_if_son_update_chan_info() - update chan info + * @pdev: pdev + * @flag_160: flag indicating the API to fill the center frequencies of 160MHz. + * @cur_chan_list: pointer to regulatory_channel + * @chan_info: chan info to fill + * @half_and_quarter_rate_flags: half and quarter rate flags + * + * Return: void + */ +static void os_if_son_update_chan_info( + struct wlan_objmgr_pdev *pdev, bool flag_160, + struct regulatory_channel *cur_chan_list, + struct ieee80211_channel_info *chan_info, + uint64_t half_and_quarter_rate_flags) +{ + qdf_freq_t primary_freq = cur_chan_list->center_freq; + struct ch_params chan_params = {0}; + + if (!chan_info) { + osif_err("null chan info"); + return; + } + if (cur_chan_list->chan_flags & REGULATORY_CHAN_NO_OFDM) + chan_info->flags |= + VENDOR_CHAN_FLAG2(QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_B); + else + chan_info->flags |= ucfg_son_get_chan_flag(pdev, primary_freq, + flag_160, + &chan_params); + if (cur_chan_list->chan_flags & REGULATORY_CHAN_RADAR) { + chan_info->flags_ext |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DFS; + chan_info->flags_ext |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_DISALLOW_ADHOC; + chan_info->flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_PASSIVE; + } else if (cur_chan_list->chan_flags & REGULATORY_CHAN_NO_IR) { + /* For 2Ghz passive channels. */ + chan_info->flags |= QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_PASSIVE; + } + + if (WLAN_REG_IS_6GHZ_PSC_CHAN_FREQ(primary_freq)) + chan_info->flags_ext |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_EXT_PSC; + + os_if_son_fill_chan_info(chan_info, cur_chan_list->chan_num, + primary_freq, + chan_params.center_freq_seg0, + chan_params.center_freq_seg1); +} + +int os_if_son_get_chan_list(struct wlan_objmgr_vdev *vdev, + struct ieee80211_ath_channel *chan_list, + struct ieee80211_channel_info *chan_info, + uint8_t *nchans, bool flag_160, bool flag_6ghz) +{ + struct regulatory_channel *cur_chan_list; + int i; + uint32_t phybitmap; + uint32_t reg_wifi_band_bitmap; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + struct regulatory_channel *chan; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + if (!chan_info) { + osif_err("null chan info"); + return -EINVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return -EINVAL; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null psoc"); + return -EINVAL; + } + + status = ucfg_reg_get_band(pdev, ®_wifi_band_bitmap); + if (!QDF_IS_STATUS_SUCCESS(status)) { + osif_err("failed to get band"); + return -EINVAL; + } + + cur_chan_list = qdf_mem_malloc(NUM_CHANNELS * + sizeof(struct regulatory_channel)); + if (!cur_chan_list) { + osif_err("cur_chan_list allocation fails"); + return -EINVAL; + } + + if (wlan_reg_get_current_chan_list( + pdev, cur_chan_list) != QDF_STATUS_SUCCESS) { + qdf_mem_free(cur_chan_list); + osif_err("fail to get current chan list"); + return -EINVAL; + } + + ucfg_reg_get_band(pdev, &phybitmap); + + for (i = 0; i < NUM_CHANNELS; i++) { + uint64_t band_flags; + qdf_freq_t primary_freq = cur_chan_list[i].center_freq; + uint64_t half_and_quarter_rate_flags = 0; + + chan = &cur_chan_list[i]; + if ((chan->chan_flags & REGULATORY_CHAN_DISABLED) && + chan->state == CHANNEL_STATE_DISABLE && + !chan->nol_chan && !chan->nol_history) + continue; + if (WLAN_REG_IS_6GHZ_CHAN_FREQ(primary_freq)) { + if (!flag_6ghz || + !(reg_wifi_band_bitmap & BIT(REG_BAND_6G))) + continue; + band_flags = VENDOR_CHAN_FLAG2( + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_6GHZ); + } else if (WLAN_REG_IS_24GHZ_CH_FREQ(primary_freq)) { + if (!(reg_wifi_band_bitmap & BIT(REG_BAND_2G))) + continue; + band_flags = QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_2GHZ; + } else if (WLAN_REG_IS_5GHZ_CH_FREQ(primary_freq)) { + if (!(reg_wifi_band_bitmap & BIT(REG_BAND_5G))) + continue; + band_flags = QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_5GHZ; + } else if (WLAN_REG_IS_49GHZ_FREQ(primary_freq)) { + if (!(reg_wifi_band_bitmap & BIT(REG_BAND_5G))) + continue; + band_flags = QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_5GHZ; + /** + * If 4.9G Half and Quarter rates are supported + * by the channel, update them as separate entries + * to the list + */ + if (BW_WITHIN(chan->min_bw, BW_10_MHZ, chan->max_bw)) { + os_if_son_fill_chan_info(&chan_info[*nchans], + chan->chan_num, + primary_freq, 0, 0); + chan_info[*nchans].flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_HALF; + chan_info[*nchans].flags |= + VENDOR_CHAN_FLAG2( + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_A); + half_and_quarter_rate_flags = + chan_info[*nchans].flags; + if (++(*nchans) >= IEEE80211_CHAN_MAX) + break; + } + if (BW_WITHIN(chan->min_bw, BW_5_MHZ, chan->max_bw)) { + os_if_son_fill_chan_info(&chan_info[*nchans], + chan->chan_num, + primary_freq, 0, 0); + chan_info[*nchans].flags |= + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_QUARTER; + chan_info[*nchans].flags |= + VENDOR_CHAN_FLAG2( + QCA_WLAN_VENDOR_CHANNEL_PROP_FLAG_A); + half_and_quarter_rate_flags = + chan_info[*nchans].flags; + if (++(*nchans) >= IEEE80211_CHAN_MAX) + break; + } + } else { + continue; + } + + os_if_son_update_chan_info(pdev, flag_160, chan, + &chan_info[*nchans], + half_and_quarter_rate_flags); + + if (++(*nchans) >= IEEE80211_CHAN_MAX) + break; + } + + qdf_mem_free(cur_chan_list); + osif_debug("vdev %d channel_info exit", wlan_vdev_get_id(vdev)); + + return 0; +} +qdf_export_symbol(os_if_son_get_chan_list); + +uint32_t os_if_son_get_sta_count(struct wlan_objmgr_vdev *vdev) +{ + uint32_t sta_count; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + sta_count = ucfg_son_get_sta_count(vdev); + osif_debug("vdev %d sta count %d", wlan_vdev_get_id(vdev), sta_count); + + return sta_count; +} +qdf_export_symbol(os_if_son_get_sta_count); + +int os_if_son_get_bssid(struct wlan_objmgr_vdev *vdev, + uint8_t bssid[QDF_MAC_ADDR_SIZE]) +{ + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + ucfg_wlan_vdev_mgr_get_param_bssid(vdev, bssid); + osif_debug("vdev %d bssid " QDF_MAC_ADDR_FMT, + wlan_vdev_get_id(vdev), QDF_MAC_ADDR_REF(bssid)); + + return 0; +} +qdf_export_symbol(os_if_son_get_bssid); + +int os_if_son_get_ssid(struct wlan_objmgr_vdev *vdev, + char ssid[WLAN_SSID_MAX_LEN + 1], + uint8_t *ssid_len) +{ + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + ucfg_wlan_vdev_mgr_get_param_ssid(vdev, ssid, ssid_len); + osif_debug("vdev %d ssid " QDF_SSID_FMT, + wlan_vdev_get_id(vdev), + QDF_SSID_REF(*ssid_len, ssid)); + + return 0; +} +qdf_export_symbol(os_if_son_get_ssid); + +int os_if_son_set_chan(struct wlan_objmgr_vdev *vdev, + int chan, enum wlan_band_id son_band) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + ret = g_son_os_if_cb.os_if_set_chan(vdev, chan, son_band); + osif_debug("vdev %d chan %d son_band %d", wlan_vdev_get_id(vdev), + chan, son_band); + + return ret; +} +qdf_export_symbol(os_if_son_set_chan); + +int os_if_son_set_cac_timeout(struct wlan_objmgr_vdev *vdev, + int cac_timeout) +{ + struct wlan_objmgr_pdev *pdev; + int status; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return -EINVAL; + } + + if (QDF_IS_STATUS_ERROR(ucfg_dfs_override_cac_timeout( + pdev, cac_timeout, &status))) { + osif_err("cac timeout override fails"); + return -EINVAL; + } + osif_debug("vdev %d cac_timeout %d status %d", + wlan_vdev_get_id(vdev), cac_timeout, status); + + return status; +} +qdf_export_symbol(os_if_son_set_cac_timeout); + +int os_if_son_get_cac_timeout(struct wlan_objmgr_vdev *vdev, + int *cac_timeout) +{ + struct wlan_objmgr_pdev *pdev; + int status; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return -EINVAL; + } + + if (QDF_IS_STATUS_ERROR(ucfg_dfs_get_override_cac_timeout( + pdev, cac_timeout, &status))) { + osif_err("fails to get cac timeout"); + return -EINVAL; + } + osif_debug("vdev %d cac_timeout %d status %d", + wlan_vdev_get_id(vdev), *cac_timeout, status); + + return status; +} +qdf_export_symbol(os_if_son_get_cac_timeout); + +int os_if_son_set_country_code(struct wlan_objmgr_vdev *vdev, + char *country_code) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + ret = g_son_os_if_cb.os_if_set_country_code(vdev, country_code); + osif_debug("vdev %d country_code %s ret %d", + wlan_vdev_get_id(vdev), country_code, ret); + + return ret; +} +qdf_export_symbol(os_if_son_set_country_code); + +int os_if_son_get_country_code(struct wlan_objmgr_vdev *vdev, + char *country_code) +{ + QDF_STATUS status; + struct wlan_objmgr_psoc *psoc; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null psoc"); + return -EINVAL; + } + status = ucfg_reg_get_current_country(psoc, country_code); + osif_debug("vdev %d country_code %s status %d", + wlan_vdev_get_id(vdev), country_code, status); + + return qdf_status_to_os_return(status); +} +qdf_export_symbol(os_if_son_get_country_code); + +int os_if_son_set_candidate_freq(struct wlan_objmgr_vdev *vdev, + qdf_freq_t freq) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + ret = g_son_os_if_cb.os_if_set_candidate_freq(vdev, freq); + osif_debug("vdev %d set_candidate_freq %d ret %d", + wlan_vdev_get_id(vdev), freq, ret); + + return ret; +} +qdf_export_symbol(os_if_son_set_candidate_freq); + +qdf_freq_t os_if_son_get_candidate_freq(struct wlan_objmgr_vdev *vdev) +{ + qdf_freq_t freq; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + freq = g_son_os_if_cb.os_if_get_candidate_freq(vdev); + osif_debug("vdev %d candidate_freq %d", + wlan_vdev_get_id(vdev), freq); + + return freq; +} +qdf_export_symbol(os_if_son_get_candidate_freq); + +QDF_STATUS os_if_son_set_acl_policy(struct wlan_objmgr_vdev *vdev, + ieee80211_acl_cmd son_acl_policy) +{ + QDF_STATUS ret; + + if (!vdev) { + osif_err("null vdev"); + return QDF_STATUS_E_INVAL; + } + + ret = g_son_os_if_cb.os_if_set_acl_policy(vdev, son_acl_policy); + osif_debug("set acl policy %d status %d", son_acl_policy, ret); + + return ret; +} +qdf_export_symbol(os_if_son_set_acl_policy); + +ieee80211_acl_cmd os_if_son_get_acl_policy(struct wlan_objmgr_vdev *vdev) +{ + ieee80211_acl_cmd son_acl_policy; + + if (!vdev) { + osif_err("null vdev"); + return IEEE80211_MACCMD_DETACH; + } + son_acl_policy = g_son_os_if_cb.os_if_get_acl_policy(vdev); + osif_debug("get acl policy %d", son_acl_policy); + + return son_acl_policy; +} +qdf_export_symbol(os_if_son_get_acl_policy); + +int os_if_son_add_acl_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + ret = g_son_os_if_cb.os_if_add_acl_mac(vdev, acl_mac); + osif_debug("add_acl_mac " QDF_MAC_ADDR_FMT " ret %d", + QDF_MAC_ADDR_REF(acl_mac->bytes), ret); + + return ret; +} +qdf_export_symbol(os_if_son_add_acl_mac); + +int os_if_son_del_acl_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *acl_mac) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + ret = g_son_os_if_cb.os_if_del_acl_mac(vdev, acl_mac); + osif_debug("del_acl_mac " QDF_MAC_ADDR_FMT " ret %d", + QDF_MAC_ADDR_REF(acl_mac->bytes), ret); + + return ret; +} +qdf_export_symbol(os_if_son_del_acl_mac); + +int os_if_son_kickout_mac(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *mac) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + ret = g_son_os_if_cb.os_if_kickout_mac(vdev, mac); + osif_debug("kickout mac " QDF_MAC_ADDR_FMT " ret %d", + QDF_MAC_ADDR_REF(mac->bytes), ret); + + return ret; +} +qdf_export_symbol(os_if_son_kickout_mac); + +uint8_t os_if_son_get_chan_util(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_host_dcs_ch_util_stats dcs_son_stats = {}; + struct wlan_objmgr_psoc *psoc; + uint8_t mac_id; + QDF_STATUS status; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null psoc"); + return 0; + } + status = policy_mgr_get_mac_id_by_session_id(psoc, + wlan_vdev_get_id(vdev), + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to get mac_id"); + return 0; + } + + ucfg_dcs_get_ch_util(psoc, mac_id, &dcs_son_stats); + osif_debug("get_chan_util %d", dcs_son_stats.total_cu); + + return dcs_son_stats.total_cu; +} +qdf_export_symbol(os_if_son_get_chan_util); + +void os_if_son_get_phy_stats(struct wlan_objmgr_vdev *vdev, + struct ol_ath_radiostats *phy_stats) +{ + struct wlan_host_dcs_ch_util_stats dcs_son_stats = {}; + struct wlan_objmgr_psoc *psoc; + uint8_t mac_id; + QDF_STATUS status; + + if (!vdev) { + osif_err("null vdev"); + return; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null psoc"); + return; + } + status = policy_mgr_get_mac_id_by_session_id(psoc, + wlan_vdev_get_id(vdev), + &mac_id); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to get mac_id"); + return; + } + + ucfg_dcs_get_ch_util(psoc, mac_id, &dcs_son_stats); + + phy_stats->ap_rx_util = dcs_son_stats.rx_cu; + phy_stats->ap_tx_util = dcs_son_stats.tx_cu; + phy_stats->obss_rx_util = dcs_son_stats.obss_rx_cu; + if (dcs_son_stats.total_cu < 100) + phy_stats->free_medium = 100 - dcs_son_stats.total_cu; + else + phy_stats->free_medium = 0; + phy_stats->chan_nf = dcs_son_stats.chan_nf; + osif_debug("rx_util %d tx_util %d obss_rx_util %d free_medium %d noise floor %d", + phy_stats->ap_rx_util, phy_stats->ap_tx_util, + phy_stats->obss_rx_util, phy_stats->free_medium, + phy_stats->chan_nf); +} +qdf_export_symbol(os_if_son_get_phy_stats); + +int os_if_son_cbs_init(void) +{ + int ret; + + ret = ucfg_son_cbs_init(); + + return ret; +} + +qdf_export_symbol(os_if_son_cbs_init); + +int os_if_son_cbs_deinit(void) +{ + int ret; + + ret = ucfg_son_cbs_deinit(); + + return ret; +} + +qdf_export_symbol(os_if_son_cbs_deinit); + +int os_if_son_set_cbs(struct wlan_objmgr_vdev *vdev, + bool enable) +{ + int ret; + + ret = ucfg_son_set_cbs(vdev, enable); + + return ret; +} + +qdf_export_symbol(os_if_son_set_cbs); + +int os_if_son_set_cbs_wait_time(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + int ret; + + ret = ucfg_son_set_cbs_wait_time(vdev, val); + + return ret; +} + +qdf_export_symbol(os_if_son_set_cbs_wait_time); + +int os_if_son_set_cbs_dwell_split_time(struct wlan_objmgr_vdev *vdev, + uint32_t val) +{ + int ret; + + ret = ucfg_son_set_cbs_dwell_split_time(vdev, val); + + return ret; +} + +qdf_export_symbol(os_if_son_set_cbs_dwell_split_time); + +int os_if_son_set_phymode(struct wlan_objmgr_vdev *vdev, + enum ieee80211_phymode mode) +{ + int ret; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + ret = g_son_os_if_cb.os_if_set_phymode(vdev, mode); + osif_debug("vdev %d phymode %d ret %d", + wlan_vdev_get_id(vdev), mode, ret); + + return ret; +} +qdf_export_symbol(os_if_son_set_phymode); + +enum ieee80211_phymode os_if_son_get_phymode(struct wlan_objmgr_vdev *vdev) +{ + enum ieee80211_phymode phymode; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + phymode = g_son_os_if_cb.os_if_get_phymode(vdev); + osif_debug("vdev %d phymode %d", + wlan_vdev_get_id(vdev), phymode); + + return phymode; +} +qdf_export_symbol(os_if_son_get_phymode); + +static QDF_STATUS os_if_son_get_apcap(struct wlan_objmgr_vdev *vdev, + wlan_ap_cap *apcap) +{ + uint32_t num_rx_streams = 0; + uint32_t num_tx_streams = 0; + uint32_t value; + struct mlme_ht_capabilities_info ht_cap_info; + struct wlan_objmgr_psoc *psoc; + tDot11fIEhe_cap he_cap = {0}; + bool enabled; + QDF_STATUS status; + int32_t vht_caps = 0; + + /* Number of supported tx and rx streams */ + status = ucfg_son_vdev_get_supported_txrx_streams(vdev, &num_tx_streams, + &num_rx_streams); + if (status != QDF_STATUS_SUCCESS) { + osif_err("Could not get txrx streams"); + return status; + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null psoc"); + return QDF_STATUS_E_NULL_VALUE; + } + + /* Fetch HT CAP */ + status = ucfg_mlme_get_ht_cap_info(psoc, &ht_cap_info); + if (status == QDF_STATUS_SUCCESS) { + apcap->wlan_ap_ht_capabilities_valid = true; + qdf_mem_copy(&apcap->htcap.htcap, &ht_cap_info, + sizeof(struct mlme_ht_capabilities_info)); + apcap->htcap.max_tx_nss = num_tx_streams; + apcap->htcap.max_rx_nss = num_rx_streams; + } + + /* Fetch VHT CAP */ + status = ucfg_mlme_get_vht_enable2x2(psoc, &enabled); + if (enabled) { + apcap->wlan_ap_vht_capabilities_valid = 1; + ucfg_mlme_cfg_get_vht_tx_mcs_map(psoc, &value); + apcap->vhtcap.supp_tx_mcs = value; + ucfg_mlme_cfg_get_vht_rx_mcs_map(psoc, &value); + apcap->vhtcap.supp_rx_mcs = value; + apcap->vhtcap.max_tx_nss = num_tx_streams; + apcap->vhtcap.max_rx_nss = num_rx_streams; + if (ucfg_son_get_vht_cap(psoc, &vht_caps) == QDF_STATUS_SUCCESS) + apcap->vhtcap.vhtcap = vht_caps; + } + + /* Fetch HE CAP */ + ucfg_mlme_cfg_get_he_caps(psoc, &he_cap); + if (he_cap.present) { + apcap->wlan_ap_he_capabilities_valid = 1; + apcap->hecap.num_mcs_entries = MAP_MAX_HE_MCS; + apcap->hecap.max_tx_nss = num_tx_streams; + apcap->hecap.max_rx_nss = num_rx_streams; + apcap->hecap.he_su_ppdu_1x_ltf_800ns_gi = + he_cap.he_1x_ltf_800_gi_ppdu; + apcap->hecap.he_ndp_4x_ltf_3200ns_gi = + he_cap.he_4x_ltf_3200_gi_ndp; + apcap->hecap.he_su_bfer = he_cap.su_beamformer; + apcap->hecap.he_su_bfee = he_cap.su_beamformee; + apcap->hecap.he_mu_bfer = he_cap.mu_beamformer; + apcap->hecap.supported_he_mcs[0] = he_cap.rx_he_mcs_map_lt_80; + apcap->hecap.supported_he_mcs[1] = he_cap.tx_he_mcs_map_lt_80; + apcap->hecap.supported_he_mcs[2] = + he_cap.rx_he_mcs_map_160[0][0] | + (he_cap.rx_he_mcs_map_160[0][1] << 8); + apcap->hecap.supported_he_mcs[3] = + he_cap.tx_he_mcs_map_160[0][0] | + (he_cap.tx_he_mcs_map_160[0][1] << 8); + apcap->hecap.supported_he_mcs[4] = + he_cap.rx_he_mcs_map_80_80[0][0] | + (he_cap.rx_he_mcs_map_80_80[0][1] << 8); + apcap->hecap.supported_he_mcs[5] = + he_cap.tx_he_mcs_map_80_80[0][0] | + (he_cap.tx_he_mcs_map_80_80[0][1] << 8); + apcap->hecap.he_ul_mumimo = QDF_GET_BITS(he_cap.ul_mu, 0, 1); + apcap->hecap.he_ul_muofdma = QDF_GET_BITS(he_cap.ul_mu, 1, 1); + apcap->hecap.he_dl_muofdma = he_cap.dl_mu_mimo_part_bw; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS os_if_son_vdev_ops(struct wlan_objmgr_vdev *vdev, + enum wlan_mlme_vdev_param type, + void *data, void *ret) +{ + union wlan_mlme_vdev_data *in = (union wlan_mlme_vdev_data *)data; + union wlan_mlme_vdev_data *out = (union wlan_mlme_vdev_data *)ret; + + if (!vdev) + return QDF_STATUS_E_INVAL; + switch (type) { + case VDEV_SET_IE: + break; + case VDEV_CLR_IE: + break; + case VDEV_SET_ACL: + break; + case VDEV_CLR_ACL: + break; + case VDEV_SET_ACL_TIMER: + break; + case VDEV_SET_PEER_ACT_STATS: + break; + case VDEV_SET_SEC_STA_WDS: + break; + case VDEV_SET_MEC: + break; + case VDEV_SET_MBO_IE_BSTM: + break; + case VDEV_SET_WPS_ACL_ENABLE: + break; + case VDEV_SET_WNM_BSS_PREF: + break; + case VDEV_GET_NSS: + break; + case VDEV_GET_CHAN: + if (!out) + return QDF_STATUS_E_INVAL; + qdf_mem_copy(&out->chan, + wlan_vdev_get_active_channel(vdev), + sizeof(out->chan)); + break; + case VDEV_GET_CHAN_WIDTH: + break; + case VDEV_GET_CHAN_UTIL: + if (!out) + return QDF_STATUS_E_INVAL; + out->chan_util = os_if_son_get_chan_util(vdev); + break; + case VDEV_GET_APCAP: + if (!out) + return QDF_STATUS_E_INVAL; + return os_if_son_get_apcap(vdev, &out->apcap); + break; + case VDEV_GET_CONNECT_N_TX: + break; + case VDEV_GET_SSID: + break; + case VDEV_GET_MAX_PHYRATE: + break; + case VDEV_GET_ACL: + break; + case VDEV_GET_ACL_RSSI_THRESHOLDS: + break; + case VDEV_GET_NODE_CAP: + if (!out || !in) + return QDF_STATUS_E_INVAL; + os_if_son_get_node_datarate_info(vdev, in->mac, &out->nodeinfo); + break; + case VDEV_GET_WDS: + break; + default: + return QDF_STATUS_E_INVAL; + } + + return QDF_STATUS_SUCCESS; +} + +qdf_export_symbol(os_if_son_vdev_ops); + +static QDF_STATUS os_if_son_get_peer_capability(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + wlan_peer_cap *peer_cap) +{ + if (g_son_os_if_cb.os_if_get_peer_capability) + return g_son_os_if_cb.os_if_get_peer_capability(vdev, peer, + peer_cap); + return QDF_STATUS_E_INVAL; +} + +QDF_STATUS os_if_son_peer_ops(struct wlan_objmgr_peer *peer, + enum wlan_mlme_peer_param type, + union wlan_mlme_peer_data *in, + union wlan_mlme_peer_data *out) +{ + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct qdf_mac_addr mac; + int ret_val; + static uint32_t peer_ext_stats_count; + + if (!peer) { + osif_err("null peer"); + return QDF_STATUS_E_INVAL; + } + + vdev = wlan_peer_get_vdev(peer); + if (!vdev) { + osif_err("null vdev"); + return QDF_STATUS_E_INVAL; + } + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return QDF_STATUS_E_INVAL; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + osif_err("null psoc"); + return QDF_STATUS_E_INVAL; + } + osif_debug("type %d", type); + /* All PEER MLME operations exported to SON component */ + switch (type) { + /* SET/CLR API start */ + case PEER_SET_KICKOUT: + qdf_mem_copy(&mac.bytes, peer->macaddr, QDF_MAC_ADDR_SIZE); + ret_val = + g_son_os_if_cb.os_if_kickout_mac(vdev, &mac); + if (ret_val) { + osif_err("Failed to kickout peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer->macaddr)); + return QDF_STATUS_E_INVAL; + } + break; + case PEER_SET_KICKOUT_ALLOW: + if (!in) { + osif_err("invalid input parameter"); + return QDF_STATUS_E_INVAL; + } + status = ucfg_son_set_peer_kickout_allow(vdev, peer, + in->enable); + osif_debug("kickout allow %d, status %d", in->enable, status); + break; + case PEER_SET_EXT_STATS: + if (!in) + return QDF_STATUS_E_INVAL; + ret_val = wlan_peer_mlme_flag_get(peer, WLAN_PEER_F_EXT_STATS); + osif_debug("Enable: %d peer_ext_stats_count: %u ret_val: %d", + in->enable, peer_ext_stats_count, ret_val); + if ((!!ret_val) != in->enable) { + status = + wlan_son_peer_ext_stat_enable(pdev, peer->macaddr, + vdev, + peer_ext_stats_count, + in->enable); + osif_debug("status: %u", status); + if (status == QDF_STATUS_SUCCESS) { + peer_ext_stats_count++; + wlan_peer_mlme_flag_set(peer, + WLAN_PEER_F_EXT_STATS); + } else { + if (peer_ext_stats_count) + peer_ext_stats_count--; + wlan_peer_mlme_flag_clear + (peer, WLAN_PEER_F_EXT_STATS); + } + } + break; + case PEER_REQ_INST_STAT: + status = wlan_son_peer_req_inst_stats(pdev, peer->macaddr, + vdev); + if (status != QDF_STATUS_SUCCESS) + osif_err("Type: %d is failed", type); + break; + case PEER_GET_CAPABILITY: + if (!out) + return QDF_STATUS_E_INVAL; + status = os_if_son_get_peer_capability(vdev, peer, + &out->peercap); + break; + case PEER_GET_MAX_MCS: + if (!out) + return QDF_STATUS_E_INVAL; + out->mcs = os_if_son_get_peer_max_mcs_idx(vdev, peer); + break; + default: + osif_err("invalid type: %d", type); + status = QDF_STATUS_E_INVAL; + } + + return status; +} + +qdf_export_symbol(os_if_son_peer_ops); + +QDF_STATUS os_if_son_scan_db_iterate(struct wlan_objmgr_pdev *pdev, + scan_iterator_func handler, void *arg) +{ + return ucfg_scan_db_iterate(pdev, handler, arg); +} + +qdf_export_symbol(os_if_son_scan_db_iterate); + +bool os_if_son_acl_is_probe_wh_set(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac_addr, + uint8_t probe_rssi) +{ + return false; +} + +qdf_export_symbol(os_if_son_acl_is_probe_wh_set); + +int os_if_son_set_chwidth(struct wlan_objmgr_vdev *vdev, + enum ieee80211_cwm_width son_chwidth) +{ + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + + return g_son_os_if_cb.os_if_set_chwidth(vdev, son_chwidth); +} +qdf_export_symbol(os_if_son_set_chwidth); + +enum ieee80211_cwm_width os_if_son_get_chwidth(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + return g_son_os_if_cb.os_if_get_chwidth(vdev); +} +qdf_export_symbol(os_if_son_get_chwidth); + +u_int8_t os_if_son_get_rx_streams(struct wlan_objmgr_vdev *vdev) +{ + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + return g_son_os_if_cb.os_if_get_rx_nss(vdev); +} +qdf_export_symbol(os_if_son_get_rx_streams); + +QDF_STATUS os_if_son_cfg80211_reply(qdf_nbuf_t sk_buf) +{ + return wlan_cfg80211_qal_devcfg_send_response(sk_buf); +} + +qdf_export_symbol(os_if_son_cfg80211_reply); + +bool os_if_son_vdev_is_wds(struct wlan_objmgr_vdev *vdev) +{ + return true; +} + +qdf_export_symbol(os_if_son_vdev_is_wds); + +uint32_t os_if_son_get_sta_space(struct wlan_objmgr_vdev *vdev) +{ + uint32_t sta_space; + + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + sta_space = g_son_os_if_cb.os_if_get_sta_space(vdev); + osif_debug("need space %u", sta_space); + + return sta_space; +} + +qdf_export_symbol(os_if_son_get_sta_space); + +void os_if_son_get_sta_list(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_sta_info *si, uint32_t *space) +{ + if (!vdev) { + osif_err("null vdev"); + return; + } + + if (!si) { + osif_err("null si"); + return; + } + if (!space || *space == 0) { + osif_err("invalid input space"); + return; + } + + g_son_os_if_cb.os_if_get_sta_list(vdev, si, space); + + osif_debug("left space %u", *space); +} + +qdf_export_symbol(os_if_son_get_sta_list); + +void os_if_son_deauth_peer_sta(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool ignore_frame) +{ + if (!vdev || !peer_mac) { + osif_err("null vdev / peer_mac"); + return; + } + if (g_son_os_if_cb.os_if_deauth_sta) + g_son_os_if_cb.os_if_deauth_sta(vdev, peer_mac, ignore_frame); +} + +qdf_export_symbol(os_if_son_deauth_peer_sta); + +void os_if_son_modify_acl(struct wlan_objmgr_vdev *vdev, + uint8_t *peer_mac, + bool allow_auth) +{ + if (!vdev || !peer_mac) { + osif_err("null vdev / peer_mac"); + return; + } + if (g_son_os_if_cb.os_if_modify_acl) + g_son_os_if_cb.os_if_modify_acl(vdev, peer_mac, allow_auth); +} + +qdf_export_symbol(os_if_son_modify_acl); + +static +int os_if_son_reg_get_ap_hw_cap(struct wlan_objmgr_pdev *pdev, + struct wlan_radio_basic_capabilities *hwcap, + bool skip_6ghz) +{ + QDF_STATUS status; + uint8_t idx; + uint8_t max_supp_op_class = REG_MAX_SUPP_OPER_CLASSES; + uint8_t n_opclasses = 0; + /* nsoc = Number of supported operating classes */ + uint8_t nsoc = 0; + struct regdmn_ap_cap_opclass_t *reg_ap_cap; + + if (!pdev || !hwcap) + return nsoc; + + reg_ap_cap = qdf_mem_malloc(max_supp_op_class * sizeof(*reg_ap_cap)); + if (!reg_ap_cap) { + osif_err("Memory allocation failure"); + return nsoc; + } + status = wlan_reg_get_opclass_details(pdev, reg_ap_cap, &n_opclasses, + max_supp_op_class, true, + REG_CURRENT_PWR_MODE); + if (status == QDF_STATUS_E_FAILURE) { + osif_err("Failed to get SAP regulatory capabilities"); + goto end_reg_get_ap_hw_cap; + } + osif_debug("n_opclasses: %u", n_opclasses); + + for (idx = 0; reg_ap_cap[idx].op_class && idx < n_opclasses; idx++) { + osif_debug("idx: %d op_class: %u ch_width: %d max_tx_pwr_dbm: %u", + idx, reg_ap_cap[idx].op_class, + reg_ap_cap[idx].ch_width, + reg_ap_cap[idx].max_tx_pwr_dbm); + if (reg_ap_cap[idx].ch_width == BW_160_MHZ) + continue; + if (skip_6ghz && + wlan_reg_is_6ghz_op_class(pdev, reg_ap_cap[idx].op_class)) { + osif_debug("ignore 6 GHz op_class: %d to son", + reg_ap_cap[idx].op_class); + continue; + } + hwcap->opclasses[nsoc].opclass = reg_ap_cap[idx].op_class; + hwcap->opclasses[nsoc].max_tx_pwr_dbm = + reg_ap_cap[idx].max_tx_pwr_dbm; + hwcap->opclasses[nsoc].num_non_oper_chan = + reg_ap_cap[idx].num_non_supported_chan; + qdf_mem_copy(hwcap->opclasses[nsoc].non_oper_chan_num, + reg_ap_cap[idx].non_sup_chan_list, + reg_ap_cap[idx].num_non_supported_chan); + hwcap->wlan_radio_basic_capabilities_valid = 1; + nsoc++; + } + hwcap->num_supp_op_classes = nsoc; + +end_reg_get_ap_hw_cap: + + qdf_mem_free(reg_ap_cap); + return nsoc; +} + +static void os_if_son_reg_get_op_channels(struct wlan_objmgr_pdev *pdev, + struct wlan_op_chan *op_chan, + bool dfs_required) +{ + QDF_STATUS status; + uint8_t idx; + uint8_t max_supp_op_class = REG_MAX_SUPP_OPER_CLASSES; + uint8_t n_opclasses = 0; + /* nsoc = Number of supported operating classes */ + uint8_t nsoc = 0; + struct regdmn_ap_cap_opclass_t *reg_ap_cap; + struct wlan_objmgr_psoc *psoc; + + if (!pdev || !op_chan) { + osif_err("invalid input parameters"); + return; + } + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + osif_err("NULL psoc"); + return; + } + + reg_ap_cap = qdf_mem_malloc(max_supp_op_class * sizeof(*reg_ap_cap)); + if (!reg_ap_cap) { + osif_err("Memory allocation failure"); + return; + } + status = wlan_reg_get_opclass_details(pdev, reg_ap_cap, &n_opclasses, + max_supp_op_class, true, + REG_CURRENT_PWR_MODE); + if (status == QDF_STATUS_E_FAILURE) { + osif_err("Failed to get SAP regulatory capabilities"); + goto end_reg_get_op_channels; + } + osif_debug("n_opclasses: %u op_chan->opclass: %u", + n_opclasses, op_chan->opclass); + for (idx = 0; reg_ap_cap[idx].op_class && idx < n_opclasses; idx++) { + if ((reg_ap_cap[idx].ch_width == BW_160_MHZ) || + (op_chan->opclass != reg_ap_cap[idx].op_class)) + continue; + osif_debug("idx: %d op_class: %u ch_width: %d max_tx_pwr_dbm: %u", + idx, reg_ap_cap[idx].op_class, + reg_ap_cap[idx].ch_width, + reg_ap_cap[idx].max_tx_pwr_dbm); + if (reg_ap_cap[idx].op_class == op_chan->opclass) { + switch (reg_ap_cap[idx].ch_width) { + case BW_20_MHZ: + case BW_25_MHZ: + op_chan->ch_width = CH_WIDTH_20MHZ; + break; + case BW_40_MHZ: + op_chan->ch_width = CH_WIDTH_40MHZ; + break; + case BW_80_MHZ: + if (reg_ap_cap[idx].behav_limit == BIT(BEHAV_BW80_PLUS) && + ucfg_mlme_get_restricted_80p80_bw_supp(psoc)) + op_chan->ch_width = CH_WIDTH_80P80MHZ; + else + op_chan->ch_width = CH_WIDTH_80MHZ; + break; + case BW_160_MHZ: + op_chan->ch_width = CH_WIDTH_160MHZ; + break; + default: + op_chan->ch_width = INVALID_WIDTH; + break; + } + op_chan->num_oper_chan = + reg_ap_cap[idx].num_supported_chan; + qdf_mem_copy(op_chan->oper_chan_num, + reg_ap_cap[idx].sup_chan_list, + reg_ap_cap[idx].num_supported_chan); + } + } + osif_debug("num of supported channel: %u", + op_chan->num_oper_chan); + /* + * TBD: DFS channel support needs to be added + * Variable nsoc will be update whenever we add DFS + * channel support for Easymesh. + */ + op_chan->num_supp_op_classes = nsoc; + +end_reg_get_op_channels: + + qdf_mem_free(reg_ap_cap); +} + +/* size of sec chan offset element */ +#define IEEE80211_SEC_CHAN_OFFSET_BYTES 3 +/* no secondary channel */ +#define IEEE80211_SEC_CHAN_OFFSET_SCN 0 +/* secondary channel above */ +#define IEEE80211_SEC_CHAN_OFFSET_SCA 1 +/* secondary channel below */ +#define IEEE80211_SEC_CHAN_OFFSET_SCB 3 + +static void os_if_son_reg_get_opclass_details(struct wlan_objmgr_pdev *pdev, + struct wlan_op_class *op_class) +{ + QDF_STATUS status; + uint8_t i; + uint8_t idx; + uint8_t n_opclasses = 0; + uint8_t chan_idx; + uint8_t max_supp_op_class = REG_MAX_SUPP_OPER_CLASSES; + struct regdmn_ap_cap_opclass_t *reg_ap_cap = + qdf_mem_malloc(max_supp_op_class * sizeof(*reg_ap_cap)); + + if (!reg_ap_cap) { + osif_err("Memory allocation failure"); + return; + } + status = wlan_reg_get_opclass_details(pdev, reg_ap_cap, &n_opclasses, + max_supp_op_class, true, + REG_CURRENT_PWR_MODE); + if (status == QDF_STATUS_E_FAILURE) { + osif_err("Failed to get SAP regulatory capabilities"); + goto end_reg_get_opclass_details; + } + osif_debug("n_opclasses: %u", n_opclasses); + + for (idx = 0; reg_ap_cap[idx].op_class && idx < n_opclasses; idx++) { + osif_debug("idx: %d op_class: %u ch_width: %d", + idx, reg_ap_cap[idx].op_class, + reg_ap_cap[idx].ch_width); + if ((op_class->opclass != reg_ap_cap[idx].op_class) || + (reg_ap_cap[idx].ch_width == BW_160_MHZ)) + continue; + switch (reg_ap_cap[idx].ch_width) { + case BW_20_MHZ: + case BW_25_MHZ: + op_class->ch_width = CH_WIDTH_20MHZ; + break; + case BW_40_MHZ: + op_class->ch_width = CH_WIDTH_40MHZ; + break; + case BW_80_MHZ: + if (reg_ap_cap[idx].behav_limit == BIT(BEHAV_BW80_PLUS)) + op_class->ch_width = CH_WIDTH_80P80MHZ; + else + op_class->ch_width = CH_WIDTH_80MHZ; + break; + case BW_160_MHZ: + op_class->ch_width = CH_WIDTH_160MHZ; + break; + default: + op_class->ch_width = CH_WIDTH_INVALID; + break; + } + switch (reg_ap_cap[idx].behav_limit) { + case BIT(BEHAV_NONE): + op_class->sc_loc = IEEE80211_SEC_CHAN_OFFSET_SCN; + break; + case BIT(BEHAV_BW40_LOW_PRIMARY): + op_class->sc_loc = IEEE80211_SEC_CHAN_OFFSET_SCA; + break; + case BIT(BEHAV_BW40_HIGH_PRIMARY): + op_class->sc_loc = IEEE80211_SEC_CHAN_OFFSET_SCB; + break; + case BIT(BEHAV_BW80_PLUS): + op_class->sc_loc = IEEE80211_SEC_CHAN_OFFSET_SCN; + break; + default: + op_class->sc_loc = IEEE80211_SEC_CHAN_OFFSET_SCN; + break; + } + osif_debug("num_supported_chan: %u num_non_supported_chan: %u", + reg_ap_cap[idx].num_supported_chan, + reg_ap_cap[idx].num_non_supported_chan); + i = 0; + chan_idx = 0; + while ((i < reg_ap_cap[idx].num_supported_chan) && + (chan_idx < MAX_CHANNELS_PER_OP_CLASS)) + op_class->channels[chan_idx++] = + reg_ap_cap[idx].sup_chan_list[i++]; + i = 0; + while ((i < reg_ap_cap[idx].num_non_supported_chan) && + (chan_idx < MAX_CHANNELS_PER_OP_CLASS)) + op_class->channels[chan_idx++] = + reg_ap_cap[idx].non_sup_chan_list[i++]; + + op_class->num_chan = chan_idx; + } + +end_reg_get_opclass_details: + + qdf_mem_free(reg_ap_cap); +} + +QDF_STATUS os_if_son_pdev_ops(struct wlan_objmgr_pdev *pdev, + enum wlan_mlme_pdev_param type, + void *data, void *ret) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + union wlan_mlme_pdev_data *in = (union wlan_mlme_pdev_data *)data; + union wlan_mlme_pdev_data *out = (union wlan_mlme_pdev_data *)ret; + wlan_esp_data *esp_info; + + if (!out) + return QDF_STATUS_E_INVAL; + + osif_debug("Type: %d", type); + switch (type) { + case PDEV_GET_ESP_INFO: + esp_info = &out->esp_info; + /* BA Window Size of 16 */ + esp_info->per_ac[WME_AC_BE].ba_window_size = ba_window_size_16; + esp_info->per_ac[WME_AC_BE].est_air_time_fraction = 0; + /* Default : 250us PPDU Duration in native format */ + esp_info->per_ac[WME_AC_BE].data_ppdu_dur_target = + MAP_DEFAULT_PPDU_DURATION * MAP_PPDU_DURATION_UNITS; + break; + case PDEV_GET_CAPABILITY: + os_if_son_reg_get_ap_hw_cap(pdev, &out->cap, in->skip_6ghz); + break; + case PDEV_GET_OPERABLE_CHAN: + memcpy(&out->op_chan, &in->op_chan, + sizeof(struct wlan_op_chan)); + os_if_son_reg_get_op_channels(pdev, &out->op_chan, + in->op_chan.dfs_required); + break; + case PDEV_GET_OPERABLE_CLASS: + memcpy(&out->op_class, &in->op_class, + sizeof(struct wlan_op_class)); + os_if_son_reg_get_opclass_details(pdev, &out->op_class); + break; + default: + break; + } + + return status; +} + +qdf_export_symbol(os_if_son_pdev_ops); + +int os_if_son_deliver_ald_event(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer, + enum ieee80211_event_type event, + void *event_data) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_rx_ops *rx_ops; + int ret; + + if (!vdev) { + osif_err("null vdev"); + return -EINVAL; + } + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null posc"); + return -EINVAL; + } + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (rx_ops && rx_ops->son_rx_ops.deliver_event) + ret = rx_ops->son_rx_ops.deliver_event(vdev, peer, event, + event_data); + else + ret = -EINVAL; + + return ret; +} + +qdf_export_symbol(os_if_son_deliver_ald_event); + +struct wlan_objmgr_vdev * +os_if_son_get_vdev_by_netdev(struct net_device *dev) +{ + return g_son_os_if_cb.os_if_get_vdev_by_netdev(dev); +} + +qdf_export_symbol(os_if_son_get_vdev_by_netdev); + +QDF_STATUS os_if_son_trigger_objmgr_object_creation(enum wlan_umac_comp_id id) +{ + return g_son_os_if_cb.os_if_trigger_objmgr_object_creation(id); +} + +qdf_export_symbol(os_if_son_trigger_objmgr_object_creation); + +QDF_STATUS os_if_son_trigger_objmgr_object_deletion(enum wlan_umac_comp_id id) +{ + return g_son_os_if_cb.os_if_trigger_objmgr_object_deletion(id); +} + +qdf_export_symbol(os_if_son_trigger_objmgr_object_deletion); + +int os_if_son_start_acs(struct wlan_objmgr_vdev *vdev, uint8_t enable) +{ + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + return g_son_os_if_cb.os_if_start_acs(vdev, enable); +} + +qdf_export_symbol(os_if_son_start_acs); + +int os_if_son_set_acs_chan(struct wlan_objmgr_vdev *vdev, + struct ieee80211req_athdbg *req) +{ + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + return g_son_os_if_cb.os_if_set_acs_channels(vdev, req); +} + +qdf_export_symbol(os_if_son_set_acs_chan); + +int os_if_son_get_acs_report(struct wlan_objmgr_vdev *vdev, + struct ieee80211_acs_dbg *acs_r) +{ + if (!vdev) { + osif_err("null vdev"); + return 0; + } + + return g_son_os_if_cb.os_if_get_acs_report(vdev, acs_r); +} + +qdf_export_symbol(os_if_son_get_acs_report); + +void +wlan_os_if_son_ops_register_cb(void (*handler)(struct wlan_os_if_son_ops *)) +{ + os_if_son_ops_cb = handler; +} + +qdf_export_symbol(wlan_os_if_son_ops_register_cb); + +static void wlan_son_register_os_if_ops(struct wlan_os_if_son_ops *son_ops) +{ + if (os_if_son_ops_cb) + os_if_son_ops_cb(son_ops); + else + osif_err("\n***** OS_IF: SON MODULE NOT LOADED *****\n"); +} + +void os_if_son_register_lmac_if_ops(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_lmac_if_rx_ops *rx_ops; + + if (!psoc) { + osif_err("psoc is NULL"); + return; + } + + rx_ops = wlan_psoc_get_lmac_if_rxops(psoc); + if (!rx_ops) { + osif_err("rx_ops is null"); + return; + } + + wlan_lmac_if_son_mod_register_rx_ops(rx_ops); +} + +qdf_export_symbol(os_if_son_register_lmac_if_ops); + +void os_if_son_register_osif_ops(void) +{ + wlan_son_register_os_if_ops(&g_son_os_if_txrx_ops); +} + +qdf_export_symbol(os_if_son_register_osif_ops); + +int os_if_son_parse_generic_nl_cmd(struct wiphy *wiphy, + struct wireless_dev *wdev, + struct nlattr **tb, + enum os_if_son_vendor_cmd_type type) +{ + struct os_if_son_rx_ops *rx_ops = &g_son_os_if_txrx_ops.son_osif_rx_ops; + struct wlan_cfg8011_genric_params param = {}; + + if (!rx_ops->parse_generic_nl_cmd) + return -EINVAL; + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND]) + param.command = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_COMMAND]); + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE]) + param.value = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_VALUE]); + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA]) { + param.data = nla_data(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA]); + param.data_len = nla_len(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_DATA]); + } + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH]) + param.length = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_LENGTH]); + + if (tb[QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS]) + param.flags = nla_get_u32(tb + [QCA_WLAN_VENDOR_ATTR_CONFIG_GENERIC_FLAGS]); + + return rx_ops->parse_generic_nl_cmd(wiphy, wdev, ¶m, type); +} + +QDF_STATUS os_if_son_get_node_datarate_info(struct wlan_objmgr_vdev *vdev, + uint8_t *mac_addr, + wlan_node_info *node_info) +{ + int8_t max_tx_power; + int8_t min_tx_power; + struct wlan_objmgr_psoc *psoc; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("null posc"); + return QDF_STATUS_E_INVAL; + } + + if (WLAN_ADDR_EQ(wlan_vdev_mlme_get_macaddr(vdev), mac_addr) == + QDF_STATUS_SUCCESS) { + node_info->max_chwidth = os_if_son_get_chwidth(vdev); + node_info->phymode = os_if_son_get_phymode(vdev); + node_info->num_streams = os_if_son_get_rx_streams(vdev); + ucfg_son_get_min_and_max_power(psoc, &max_tx_power, + &min_tx_power); + node_info->max_txpower = max_tx_power; + node_info->max_MCS = ucfg_mlme_get_vdev_max_mcs_idx(vdev); + if (node_info->max_MCS == INVALID_MCS_NSS_INDEX) { + osif_err("invalid mcs index"); + return QDF_STATUS_E_INVAL; + } + osif_debug("node info: max_chwidth: %u, phymode: %u, num_streams: %d, max_mcs: %d, max_txpower: %d", + node_info->max_chwidth, node_info->phymode, + node_info->num_streams, node_info->max_MCS, + node_info->max_txpower); + } else { + if (!g_son_os_if_cb.os_if_get_node_info) { + osif_err("Callback not registered"); + return QDF_STATUS_E_INVAL; + } + status = g_son_os_if_cb.os_if_get_node_info(vdev, mac_addr, + node_info); + } + return status; +} + +qdf_export_symbol(os_if_son_get_node_datarate_info); + +uint32_t os_if_son_get_peer_max_mcs_idx(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_peer *peer) +{ + if (g_son_os_if_cb.os_if_get_peer_max_mcs_idx) + return g_son_os_if_cb.os_if_get_peer_max_mcs_idx(vdev, peer); + + return 0; +} + +int os_if_son_get_sta_stats(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr, + struct ieee80211_nodestats *stats) +{ + if (g_son_os_if_cb.os_if_get_sta_stats) + return g_son_os_if_cb.os_if_get_sta_stats(vdev, mac_addr, + stats); + + return 0; +} +qdf_export_symbol(os_if_son_get_sta_stats); diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_driver_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_driver_sync.h new file mode 100644 index 0000000000..8615e48e37 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_driver_sync.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __OSIF_DRIVER_SYNC_H +#define __OSIF_DRIVER_SYNC_H + +#include "qdf_types.h" + +/* + * struct osif_driver_sync - opaque synchronization handle for a driver + */ +struct osif_driver_sync; + +/** + * osif_driver_sync_create() - create a driver synchronization context + * @out_driver_sync: out parameter for the new synchronization context + * + * Return: Errno + */ +qdf_must_check int +osif_driver_sync_create(struct osif_driver_sync **out_driver_sync); + +/** + * osif_driver_sync_create_and_trans() - create a driver synchronization context + * @out_driver_sync: out parameter for the new synchronization context + * + * For protecting the driver initialization process. + * + * Return: Errno + */ +#define osif_driver_sync_create_and_trans(out_driver_sync) \ + __osif_driver_sync_create_and_trans(out_driver_sync, __func__) + +qdf_must_check int +__osif_driver_sync_create_and_trans(struct osif_driver_sync **out_driver_sync, + const char *desc); + +/** + * osif_driver_sync_destroy() - destroy a driver synchronization context + * @driver_sync: the context to destroy + * + * Return: none + */ +void osif_driver_sync_destroy(struct osif_driver_sync *driver_sync); + +/** + * osif_driver_sync_register() - register a driver for operations/transitions + * @driver_sync: the driver synchronization context to register + * + * Return: none + */ +void osif_driver_sync_register(struct osif_driver_sync *driver_sync); + +/** + * osif_driver_sync_unregister() - unregister a driver for + * operations/transitions + * + * Return: the driver synchronization context that was registered for @dev + */ +struct osif_driver_sync *osif_driver_sync_unregister(void); + +/** + * osif_driver_sync_trans_start() - attempt to start a driver transition + * @out_driver_sync: out parameter for the synchronization context previously + * registered, populated on success + * + * Return: Errno + */ +#define osif_driver_sync_trans_start(out_driver_sync) \ + __osif_driver_sync_trans_start(out_driver_sync, __func__) + +qdf_must_check int +__osif_driver_sync_trans_start(struct osif_driver_sync **out_driver_sync, + const char *desc); + +/** + * osif_driver_sync_trans_start_wait() - attempt to start a driver transition, + * blocking if a conflicting transition is in flight + * @out_driver_sync: out parameter for the synchronization context previously + * registered, populated on success + * + * Return: Errno + */ +#define osif_driver_sync_trans_start_wait(out_driver_sync) \ + __osif_driver_sync_trans_start_wait(out_driver_sync, __func__) + +qdf_must_check int +__osif_driver_sync_trans_start_wait(struct osif_driver_sync **out_driver_sync, + const char *desc); + +/** + * osif_driver_sync_trans_stop() - stop a transition associated with + * @driver_sync + * @driver_sync: the synchronization context tracking the transition + * + * Return: none + */ +void osif_driver_sync_trans_stop(struct osif_driver_sync *driver_sync); + +/** + * osif_driver_sync_assert_trans_protected() - assert that the driver is + * currently protected by a transition + * + * Return: none + */ +void osif_driver_sync_assert_trans_protected(void); + +/** + * osif_driver_sync_op_start() - attempt to start a driver operation + * @out_driver_sync: out parameter for the synchronization context previously + * registered, populated on success + * + * Return: Errno + */ +#define osif_driver_sync_op_start(out_driver_sync) \ + __osif_driver_sync_op_start(out_driver_sync, __func__) + +qdf_must_check int +__osif_driver_sync_op_start(struct osif_driver_sync **out_driver_sync, + const char *func); + +/** + * osif_driver_sync_op_stop() - stop an operation associated with @driver_sync + * @driver_sync: the synchronization context tracking the operation + * + * Return: none + */ +#define osif_driver_sync_op_stop(driver_sync) \ + __osif_driver_sync_op_stop(driver_sync, __func__) + +void __osif_driver_sync_op_stop(struct osif_driver_sync *driver_sync, + const char *func); + +/** + * osif_driver_sync_wait_for_ops() - wait until all @driver_sync operations + * complete + * @driver_sync: the synchronization context tracking the operations + * + * Return: None + */ +void osif_driver_sync_wait_for_ops(struct osif_driver_sync *driver_sync); + +#endif /* __OSIF_DRIVER_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_psoc_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_psoc_sync.h new file mode 100644 index 0000000000..dbe95820df --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_psoc_sync.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __OSIF_PSOC_SYNC_H +#define __OSIF_PSOC_SYNC_H + +#include "linux/device.h" +#include "wlan_dsc_driver.h" +#include "qdf_types.h" + +/* + * struct osif_psoc_sync - opaque synchronization handle for a psoc + */ +struct osif_psoc_sync; + +/** + * osif_psoc_sync_create() - create a psoc synchronization context + * @out_psoc_sync: out parameter for the new synchronization context + * + * Return: Errno + */ +qdf_must_check int +osif_psoc_sync_create(struct osif_psoc_sync **out_psoc_sync); + +/** + * osif_psoc_sync_create_and_trans() - create a psoc synchronization context + * @out_psoc_sync: out parameter for the new synchronization context + * + * For protecting the device creation process. + * + * Return: Errno + */ +#define osif_psoc_sync_create_and_trans(out_psoc_sync) \ + __osif_psoc_sync_create_and_trans(out_psoc_sync, __func__) + +qdf_must_check int +__osif_psoc_sync_create_and_trans(struct osif_psoc_sync **out_psoc_sync, + const char *desc); + +/** + * osif_psoc_sync_destroy() - destroy a psoc synchronization context + * @psoc_sync: the context to destroy + * + * Return: none + */ +void osif_psoc_sync_destroy(struct osif_psoc_sync *psoc_sync); + +/** + * osif_psoc_sync_register() - register a psoc for operations/transitions + * @dev: the device to use as the operation/transition lookup key + * @psoc_sync: the psoc synchronization context to register + * + * Return: none + */ +void osif_psoc_sync_register(struct device *dev, + struct osif_psoc_sync *psoc_sync); + +/** + * osif_psoc_sync_unregister() - unregister a psoc for operations/transitions + * @dev: the device originally used to register the psoc_sync context + * + * Return: the psoc synchronization context that was registered for @dev + */ +struct osif_psoc_sync *osif_psoc_sync_unregister(struct device *dev); + +/** + * osif_psoc_sync_trans_start() - attempt to start a transition on @dev + * @dev: the device to transition + * @out_psoc_sync: out parameter for the synchronization context registered with + * @dev, populated on success + * + * Return: Errno + */ +#define osif_psoc_sync_trans_start(dev, out_psoc_sync) \ + __osif_psoc_sync_trans_start(dev, out_psoc_sync, __func__) + +qdf_must_check int +__osif_psoc_sync_trans_start(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *desc); + +/** + * osif_psoc_sync_trans_start_wait() - attempt to start a transition on @dev, + * blocking if a conflicting transition is in flight + * @dev: the device to transition + * @out_psoc_sync: out parameter for the synchronization context registered with + * @dev, populated on success + * + * Return: Errno + */ +#define osif_psoc_sync_trans_start_wait(dev, out_psoc_sync) \ + __osif_psoc_sync_trans_start_wait(dev, out_psoc_sync, __func__) + +qdf_must_check int +__osif_psoc_sync_trans_start_wait(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *desc); + +/** + * osif_psoc_sync_trans_resume() - resume a transition on @dev + * @dev: the device under transition + * @out_psoc_sync: out parameter for the synchronization context registered with + * @dev, populated on success + * + * Return: Errno + */ +int osif_psoc_sync_trans_resume(struct device *dev, + struct osif_psoc_sync **out_psoc_sync); + +/** + * osif_psoc_sync_trans_stop() - stop a transition associated with @psoc_sync + * @psoc_sync: the synchronization context tracking the transition + * + * Return: none + */ +void osif_psoc_sync_trans_stop(struct osif_psoc_sync *psoc_sync); + +/** + * osif_psoc_sync_assert_trans_protected() - assert that @dev is currently + * protected by a transition + * @dev: the device to check + * + * Return: none + */ +void osif_psoc_sync_assert_trans_protected(struct device *dev); + +/** + * osif_psoc_sync_op_start() - attempt to start an operation on @dev + * @dev: the device to operate against + * @out_psoc_sync: out parameter for the synchronization context registered with + * @dev, populated on success + * + * Return: Errno + */ +#define osif_psoc_sync_op_start(dev, out_psoc_sync) \ + __osif_psoc_sync_op_start(dev, out_psoc_sync, __func__) + +qdf_must_check int +__osif_psoc_sync_op_start(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *func); + +/** + * osif_psoc_sync_op_stop() - stop an operation associated with @psoc_sync + * @psoc_sync: the synchronization context tracking the operation + * + * Return: none + */ +#define osif_psoc_sync_op_stop(psoc_sync) \ + __osif_psoc_sync_op_stop(psoc_sync, __func__) + +void __osif_psoc_sync_op_stop(struct osif_psoc_sync *psoc_sync, + const char *func); + +/** + * osif_psoc_sync_wait_for_ops() - wait until all @psoc_sync operations complete + * @psoc_sync: the synchronization context tracking the operations + * + * Return: None + */ +void osif_psoc_sync_wait_for_ops(struct osif_psoc_sync *psoc_sync); + +#endif /* __OSIF_PSOC_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_sync.h new file mode 100644 index 0000000000..38fcebf4a7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_sync.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Operating System Interface, Synchronization (osif_sync) + * + * osif_sync is a collection of APIs for synchronizing and safely interacting + * with external processes/threads via various operating system interfaces. It + * relies heavily on the Driver Synchronization Core, which defines the + * synchronization primitives and behavior. + * + * While DSC is great at doing the required synchronization, it (by design) does + * not address the gap between receiving a callback and involing the appropriate + * DSC protections. For example, given an input net_device pointer from the + * kernel, how does one safely acquire the appropriate DSC context? osif_sync + * implements this logic via wrapping DSC APIs with a registration mechanism. + * + * For example, after the creation of a new dsc_vdev context, osif_sync allows + * it to be registered with a specific net_device pointer as a key. Future + * operations against this net_device can use this pointer to atomically lookup + * the DSC context, and start either a DSC transition or DSC operation. If this + * is successful, the operation continues and is guaranteed protected from major + * state changes. Otherwise, the operation attempt is rejected. + * + * See also: wlan_dsc.h + */ + +#ifndef __OSIF_SYNC_H +#define __OSIF_SYNC_H + +#include "osif_driver_sync.h" +#include "osif_psoc_sync.h" +#include "osif_vdev_sync.h" + +/** + * osif_sync_init() - global initializer + * + * Return: None + */ +void osif_sync_init(void); + +/** + * osif_sync_deinit() - global de-initializer + * + * Return: None + */ +void osif_sync_deinit(void); + +#endif /* __OSIF_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_vdev_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_vdev_sync.h new file mode 100644 index 0000000000..6d73d63760 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/inc/osif_vdev_sync.h @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __OSIF_VDEV_SYNC_H +#define __OSIF_VDEV_SYNC_H + +#include "linux/device.h" +#include "linux/netdevice.h" +#include "qdf_types.h" + +/** + * struct osif_vdev_sync - vdev synchronization context + * @net_dev: the net_device used as a lookup key + * @dsc_vdev: the dsc_vdev used for synchronization + * @in_use: indicates if the context is being used + */ +struct osif_vdev_sync { + struct net_device *net_dev; + struct dsc_vdev *dsc_vdev; + bool in_use; +}; + +/** + * osif_vdev_sync_create() - create a vdev synchronization context + * @dev: parent device to the vdev + * @out_vdev_sync: out parameter for the new synchronization context + * + * Return: Errno + */ +qdf_must_check int +osif_vdev_sync_create(struct device *dev, + struct osif_vdev_sync **out_vdev_sync); + +/** + * osif_vdev_sync_create_and_trans() - create a vdev synchronization context + * @dev: parent device to the vdev + * @out_vdev_sync: out parameter for the new synchronization context + * + * For protecting the net_device creation process. + * + * Return: Errno + */ +#define osif_vdev_sync_create_and_trans(dev, out_vdev_sync) \ + __osif_vdev_sync_create_and_trans(dev, out_vdev_sync, __func__) + +qdf_must_check int +__osif_vdev_sync_create_and_trans(struct device *dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc); + +/** + * osif_vdev_sync_destroy() - destroy a vdev synchronization context + * @vdev_sync: the context to destroy + * + * Return: none + */ +void osif_vdev_sync_destroy(struct osif_vdev_sync *vdev_sync); + +/** + * osif_vdev_sync_register() - register a vdev for operations/transitions + * @net_dev: the net_device to use as the operation/transition lookup key + * @vdev_sync: the vdev synchronization context to register + * + * Return: none + */ +void osif_vdev_sync_register(struct net_device *net_dev, + struct osif_vdev_sync *vdev_sync); + +/** + * osif_vdev_sync_unregister() - unregister a vdev for operations/transitions + * @net_dev: the net_device originally used to register the vdev_sync context + * + * Return: the vdev synchronization context that was registered for @net_dev + */ +struct osif_vdev_sync *osif_vdev_sync_unregister(struct net_device *net_dev); + +/** + * osif_vdev_sync_trans_start() - attempt to start a transition on @net_dev + * @net_dev: the net_device to transition + * @out_vdev_sync: out parameter for the synchronization context registered with + * @net_dev, populated on success + * + * Return: Errno + */ +#define osif_vdev_sync_trans_start(net_dev, out_vdev_sync) \ + __osif_vdev_sync_trans_start(net_dev, out_vdev_sync, __func__) + +qdf_must_check int +__osif_vdev_sync_trans_start(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc); + +/** + * osif_vdev_sync_trans_start_wait() - attempt to start a transition on + * @net_dev, blocking if a conflicting transition is in flight + * @net_dev: the net_device to transition + * @out_vdev_sync: out parameter for the synchronization context registered with + * @net_dev, populated on success + * + * Return: Errno + */ +#define osif_vdev_sync_trans_start_wait(net_dev, out_vdev_sync) \ + __osif_vdev_sync_trans_start_wait(net_dev, out_vdev_sync, __func__) + +qdf_must_check int +__osif_vdev_sync_trans_start_wait(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc); + +/** + * osif_vdev_sync_trans_stop() - stop a transition associated with @vdev_sync + * @vdev_sync: the synchronization context tracking the transition + * + * Return: none + */ +void osif_vdev_sync_trans_stop(struct osif_vdev_sync *vdev_sync); + +/** + * osif_vdev_sync_assert_trans_protected() - assert that @net_dev is currently + * protected by a transition + * @net_dev: the net_device to check + * + * Return: none + */ +void osif_vdev_sync_assert_trans_protected(struct net_device *net_dev); + +/** + * osif_vdev_sync_op_start() - attempt to start an operation on @net_dev + * @net_dev: the net_device to operate against + * @out_vdev_sync: out parameter for the synchronization context registered with + * @net_dev, populated on success + * + * Return: Errno + */ +#define osif_vdev_sync_op_start(net_dev, out_vdev_sync) \ + __osif_vdev_sync_op_start(net_dev, out_vdev_sync, __func__) + +qdf_must_check int +__osif_vdev_sync_op_start(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *func); + +/** + * osif_vdev_sync_op_stop() - stop an operation associated with @vdev_sync + * @vdev_sync: the synchronization context tracking the operation + * + * Return: none + */ +#define osif_vdev_sync_op_stop(vdev_sync) \ + __osif_vdev_sync_op_stop(vdev_sync, __func__) + +void __osif_vdev_sync_op_stop(struct osif_vdev_sync *vdev_sync, + const char *func); + +/** + * osif_vdev_sync_wait_for_ops() - wait until all @vdev_sync operations complete + * @vdev_sync: the synchronization context tracking the operations + * + * Return: None + */ +void osif_vdev_sync_wait_for_ops(struct osif_vdev_sync *vdev_sync); + +/** + * osif_vdev_get_cached_cmd() - Get north bound cmd cached during SSR + * @vdev_sync: osif vdev sync corresponding to the network interface + * + * This api will be invoked after completion of SSR re-initialization to get + * the last north bound command received during SSR + * + * Return: North bound command ID + */ +uint8_t osif_vdev_get_cached_cmd(struct osif_vdev_sync *vdev_sync); + +/** + * osif_vdev_cache_command() - Cache north bound command during SSR + * @vdev_sync: osif vdev sync corresponding to the network interface + * @cmd_id: North bound command ID + * + * This api will be invoked when a north bound command is received during SSR + * and it should be handled after SSR re-initialization. + * + * Return: None + */ +void osif_vdev_cache_command(struct osif_vdev_sync *vdev_sync, uint8_t cmd_id); + +/** + * osif_get_vdev_sync_arr() - Get vdev sync array base pointer + * + * Return: Base pointer to the vdev sync array + */ +struct osif_vdev_sync *osif_get_vdev_sync_arr(void); + +#endif /* __OSIF_VDEV_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_driver_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_driver_sync.h new file mode 100644 index 0000000000..58f40ebb6f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_driver_sync.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ____OSIF_DRIVER_SYNC_H +#define ____OSIF_DRIVER_SYNC_H + +#include "qdf_status.h" +#include "wlan_dsc_psoc.h" + +/** + * osif_driver_sync_init() - global initializer + * + * Return: None + */ +void osif_driver_sync_init(void); + +/** + * osif_driver_sync_deinit() - global de-initializer + * + * Return: None + */ +void osif_driver_sync_deinit(void); + +/** + * osif_driver_sync_dsc_psoc_create() - create a dsc_psoc and attach it to the + * global dsc_driver instance + * @out_dsc_psoc: output pointer parameter for the new dsc_psoc + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_driver_sync_dsc_psoc_create(struct dsc_psoc **out_dsc_psoc); + +#endif /* ____OSIF_DRIVER_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_psoc_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_psoc_sync.h new file mode 100644 index 0000000000..ed6e5a50ba --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_psoc_sync.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ____OSIF_PSOC_SYNC_H +#define ____OSIF_PSOC_SYNC_H + +#include "linux/device.h" +#include "qdf_status.h" +#include "wlan_dsc_vdev.h" + +/** + * osif_psoc_sync_init() - global initializer + * + * Return: None + */ +void osif_psoc_sync_init(void); + +/** + * osif_psoc_sync_deinit() - global de-initializer + * + * Return: None + */ +void osif_psoc_sync_deinit(void); + +/** + * osif_psoc_sync_dsc_vdev_create() - create a dsc_vdev and attach it to a + * dsc_psoc keyed by @dev + * @dev: the device to key off of + * @out_dsc_vdev: output pointer parameter for the new dsc_vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_psoc_sync_dsc_vdev_create(struct device *dev, + struct dsc_vdev **out_dsc_vdev); + +#endif /* ____OSIF_PSOC_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_vdev_sync.h b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_vdev_sync.h new file mode 100644 index 0000000000..a0ca21fb5c --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/__osif_vdev_sync.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef ____OSIF_VDEV_SYNC_H +#define ____OSIF_VDEV_SYNC_H + +/** + * osif_vdev_sync_init() - global initializer + * + * Return: None + */ +void osif_vdev_sync_init(void); + +/** + * osif_vdev_sync_deinit() - global de-initializer + * + * Return: None + */ +void osif_vdev_sync_deinit(void); + +#endif /* ____OSIF_VDEV_SYNC_H */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_driver_sync.c b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_driver_sync.c new file mode 100644 index 0000000000..71c4ab8972 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_driver_sync.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "__osif_driver_sync.h" +#include "osif_driver_sync.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_types.h" +#include "wlan_dsc_driver.h" +#include "wlan_dsc_psoc.h" + +/** + * struct osif_driver_sync - a driver synchronization context + * @dsc_driver: the dsc_driver used for synchronization + * @in_use: indicates if the context is being used + * @is_registered: indicates if the context is registered for + * transitions/operations + */ +struct osif_driver_sync { + struct dsc_driver *dsc_driver; + bool in_use; + bool is_registered; +}; + +static struct osif_driver_sync __osif_driver_sync; +static qdf_spinlock_t __osif_driver_sync_lock; + +#define osif_driver_sync_lock_create() \ + qdf_spinlock_create(&__osif_driver_sync_lock) +#define osif_driver_sync_lock_destroy() \ + qdf_spinlock_destroy(&__osif_driver_sync_lock) +#define osif_driver_sync_lock() qdf_spin_lock_bh(&__osif_driver_sync_lock) +#define osif_driver_sync_unlock() qdf_spin_unlock_bh(&__osif_driver_sync_lock) + +static struct osif_driver_sync *osif_driver_sync_lookup(void) +{ + if (!__osif_driver_sync.is_registered) + return NULL; + + return &__osif_driver_sync; +} + +static struct osif_driver_sync *osif_driver_sync_get(void) +{ + if (__osif_driver_sync.in_use) + return NULL; + + __osif_driver_sync.in_use = true; + + return &__osif_driver_sync; +} + +static void osif_driver_sync_put(struct osif_driver_sync *driver_sync) +{ + qdf_mem_zero(driver_sync, sizeof(*driver_sync)); +} + +int osif_driver_sync_create(struct osif_driver_sync **out_driver_sync) +{ + QDF_STATUS status; + struct osif_driver_sync *driver_sync; + + QDF_BUG(out_driver_sync); + if (!out_driver_sync) + return -EINVAL; + + osif_driver_sync_lock(); + driver_sync = osif_driver_sync_get(); + osif_driver_sync_unlock(); + if (!driver_sync) + return -ENOMEM; + + status = dsc_driver_create(&driver_sync->dsc_driver); + if (QDF_IS_STATUS_ERROR(status)) + goto sync_put; + + *out_driver_sync = driver_sync; + + return 0; + +sync_put: + osif_driver_sync_lock(); + osif_driver_sync_put(driver_sync); + osif_driver_sync_unlock(); + + return qdf_status_to_os_return(status); +} + +int +__osif_driver_sync_create_and_trans(struct osif_driver_sync **out_driver_sync, + const char *desc) +{ + struct osif_driver_sync *driver_sync; + QDF_STATUS status; + int errno; + + errno = osif_driver_sync_create(&driver_sync); + if (errno) + return errno; + + status = dsc_driver_trans_start(driver_sync->dsc_driver, desc); + if (QDF_IS_STATUS_ERROR(status)) + goto sync_destroy; + + *out_driver_sync = driver_sync; + + return 0; + +sync_destroy: + osif_driver_sync_destroy(driver_sync); + + return qdf_status_to_os_return(status); +} + +void osif_driver_sync_destroy(struct osif_driver_sync *driver_sync) +{ + QDF_BUG(driver_sync); + if (!driver_sync) + return; + + dsc_driver_destroy(&driver_sync->dsc_driver); + + osif_driver_sync_lock(); + osif_driver_sync_put(driver_sync); + osif_driver_sync_unlock(); +} + +void osif_driver_sync_register(struct osif_driver_sync *driver_sync) +{ + QDF_BUG(driver_sync); + if (!driver_sync) + return; + + osif_driver_sync_lock(); + driver_sync->is_registered = true; + osif_driver_sync_unlock(); +} + +struct osif_driver_sync *osif_driver_sync_unregister(void) +{ + struct osif_driver_sync *driver_sync; + + osif_driver_sync_lock(); + driver_sync = osif_driver_sync_lookup(); + if (driver_sync) + driver_sync->is_registered = false; + osif_driver_sync_unlock(); + + return driver_sync; +} + +typedef QDF_STATUS (*driver_start_func)(struct dsc_driver *, const char *); + +static int +__osif_driver_sync_start_callback(struct osif_driver_sync **out_driver_sync, + const char *desc, + driver_start_func driver_start_cb) +{ + QDF_STATUS status; + struct osif_driver_sync *driver_sync; + + *out_driver_sync = NULL; + + driver_sync = osif_driver_sync_lookup(); + if (!driver_sync) + return -EAGAIN; + + status = driver_start_cb(driver_sync->dsc_driver, desc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + *out_driver_sync = driver_sync; + + return 0; +} + +static int +__osif_driver_sync_start_wait_callback( + struct osif_driver_sync **out_driver_sync, + const char *desc, + driver_start_func driver_start_cb) +{ + QDF_STATUS status; + struct osif_driver_sync *driver_sync; + + *out_driver_sync = NULL; + + osif_driver_sync_lock(); + driver_sync = osif_driver_sync_lookup(); + osif_driver_sync_unlock(); + if (!driver_sync) + return -EAGAIN; + + status = driver_start_cb(driver_sync->dsc_driver, desc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + *out_driver_sync = driver_sync; + + return 0; +} +int __osif_driver_sync_trans_start(struct osif_driver_sync **out_driver_sync, + const char *desc) +{ + int errno; + + osif_driver_sync_lock(); + errno = __osif_driver_sync_start_callback(out_driver_sync, desc, + dsc_driver_trans_start); + osif_driver_sync_unlock(); + + return errno; +} + +int +__osif_driver_sync_trans_start_wait(struct osif_driver_sync **out_driver_sync, + const char *desc) +{ + int errno; + + /* since dsc_driver_trans_start_wait may sleep do not take lock here */ + errno = __osif_driver_sync_start_wait_callback(out_driver_sync, desc, + dsc_driver_trans_start_wait); + + return errno; +} + +void osif_driver_sync_trans_stop(struct osif_driver_sync *driver_sync) +{ + dsc_driver_trans_stop(driver_sync->dsc_driver); +} + +void osif_driver_sync_assert_trans_protected(void) +{ + struct osif_driver_sync *driver_sync; + + osif_driver_sync_lock(); + + driver_sync = osif_driver_sync_lookup(); + QDF_BUG(driver_sync); + if (driver_sync) + dsc_driver_assert_trans_protected(driver_sync->dsc_driver); + + osif_driver_sync_unlock(); +} + +int __osif_driver_sync_op_start(struct osif_driver_sync **out_driver_sync, + const char *func) +{ + int errno; + + osif_driver_sync_lock(); + errno = __osif_driver_sync_start_callback(out_driver_sync, func, + _dsc_driver_op_start); + osif_driver_sync_unlock(); + + return errno; +} + +void __osif_driver_sync_op_stop(struct osif_driver_sync *driver_sync, + const char *func) +{ + _dsc_driver_op_stop(driver_sync->dsc_driver, func); +} + +void osif_driver_sync_wait_for_ops(struct osif_driver_sync *driver_sync) +{ + dsc_driver_wait_for_ops(driver_sync->dsc_driver); +} + +void osif_driver_sync_init(void) +{ + osif_driver_sync_lock_create(); +} + +void osif_driver_sync_deinit(void) +{ + osif_driver_sync_lock_destroy(); +} + +static QDF_STATUS +__osif_driver_sync_dsc_psoc_create(struct dsc_psoc **out_dsc_psoc) +{ + struct osif_driver_sync *driver_sync; + + driver_sync = osif_driver_sync_lookup(); + if (!driver_sync) + return QDF_STATUS_E_INVAL; + + return dsc_psoc_create(driver_sync->dsc_driver, out_dsc_psoc); +} + +QDF_STATUS osif_driver_sync_dsc_psoc_create(struct dsc_psoc **out_dsc_psoc) +{ + QDF_STATUS status; + + osif_driver_sync_lock(); + status = __osif_driver_sync_dsc_psoc_create(out_dsc_psoc); + osif_driver_sync_unlock(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_psoc_sync.c b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_psoc_sync.c new file mode 100644 index 0000000000..1f19631cd7 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_psoc_sync.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "linux/device.h" +#include "__osif_driver_sync.h" +#include "__osif_psoc_sync.h" +#include "osif_psoc_sync.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_types.h" +#include "wlan_dsc_psoc.h" +#include "wlan_dsc_vdev.h" +#include "__wlan_dsc.h" + +/** + * struct osif_psoc_sync - a psoc synchronization context + * @dev: the device used as a lookup key + * @dsc_psoc: the dsc_psoc used for synchronization + * @in_use: indicates if the context is being used + */ +struct osif_psoc_sync { + struct device *dev; + struct dsc_psoc *dsc_psoc; + bool in_use; +}; + +static struct osif_psoc_sync __osif_psoc_sync_arr[WLAN_MAX_PSOCS]; +static qdf_spinlock_t __osif_psoc_sync_lock; + +#define osif_psoc_sync_lock_create() qdf_spinlock_create(&__osif_psoc_sync_lock) +#define osif_psoc_sync_lock_destroy() \ + qdf_spinlock_destroy(&__osif_psoc_sync_lock) +#define osif_psoc_sync_lock() qdf_spin_lock_bh(&__osif_psoc_sync_lock) +#define osif_psoc_sync_unlock() qdf_spin_unlock_bh(&__osif_psoc_sync_lock) + +static struct osif_psoc_sync *osif_psoc_sync_lookup(struct device *dev) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(__osif_psoc_sync_arr); i++) { + struct osif_psoc_sync *psoc_sync = __osif_psoc_sync_arr + i; + + if (!psoc_sync->in_use) + continue; + + if (psoc_sync->dev == dev) + return psoc_sync; + } + + return NULL; +} + +static struct osif_psoc_sync *osif_psoc_sync_get(void) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(__osif_psoc_sync_arr); i++) { + struct osif_psoc_sync *psoc_sync = __osif_psoc_sync_arr + i; + + if (!psoc_sync->in_use) { + psoc_sync->in_use = true; + return psoc_sync; + } + } + + return NULL; +} + +static void osif_psoc_sync_put(struct osif_psoc_sync *psoc_sync) +{ + qdf_mem_zero(psoc_sync, sizeof(*psoc_sync)); +} + +int osif_psoc_sync_create(struct osif_psoc_sync **out_psoc_sync) +{ + QDF_STATUS status; + struct osif_psoc_sync *psoc_sync; + + QDF_BUG(out_psoc_sync); + if (!out_psoc_sync) + return -EINVAL; + + osif_psoc_sync_lock(); + psoc_sync = osif_psoc_sync_get(); + osif_psoc_sync_unlock(); + if (!psoc_sync) + return -ENOMEM; + + status = osif_driver_sync_dsc_psoc_create(&psoc_sync->dsc_psoc); + if (QDF_IS_STATUS_ERROR(status)) + goto sync_put; + + *out_psoc_sync = psoc_sync; + + return 0; + +sync_put: + osif_psoc_sync_lock(); + osif_psoc_sync_put(psoc_sync); + osif_psoc_sync_unlock(); + + return qdf_status_to_os_return(status); +} + +int __osif_psoc_sync_create_and_trans(struct osif_psoc_sync **out_psoc_sync, + const char *desc) +{ + struct osif_psoc_sync *psoc_sync; + QDF_STATUS status; + int errno; + + errno = osif_psoc_sync_create(&psoc_sync); + if (errno) + return errno; + + status = dsc_psoc_trans_start(psoc_sync->dsc_psoc, desc); + if (QDF_IS_STATUS_ERROR(status)) + goto sync_destroy; + + *out_psoc_sync = psoc_sync; + + return 0; + +sync_destroy: + osif_psoc_sync_destroy(psoc_sync); + + return qdf_status_to_os_return(status); +} + +void osif_psoc_sync_destroy(struct osif_psoc_sync *psoc_sync) +{ + QDF_BUG(psoc_sync); + if (!psoc_sync) + return; + + dsc_psoc_destroy(&psoc_sync->dsc_psoc); + + osif_psoc_sync_lock(); + osif_psoc_sync_put(psoc_sync); + osif_psoc_sync_unlock(); +} + +void osif_psoc_sync_register(struct device *dev, + struct osif_psoc_sync *psoc_sync) +{ + QDF_BUG(dev); + QDF_BUG(psoc_sync); + if (!psoc_sync) + return; + + osif_psoc_sync_lock(); + psoc_sync->dev = dev; + osif_psoc_sync_unlock(); +} + +struct osif_psoc_sync *osif_psoc_sync_unregister(struct device *dev) +{ + struct osif_psoc_sync *psoc_sync; + + QDF_BUG(dev); + if (!dev) + return NULL; + + osif_psoc_sync_lock(); + psoc_sync = osif_psoc_sync_lookup(dev); + if (psoc_sync) + psoc_sync->dev = NULL; + osif_psoc_sync_unlock(); + + return psoc_sync; +} + +typedef QDF_STATUS (*psoc_start_func)(struct dsc_psoc *, const char *); + +static int +__osif_psoc_sync_start_callback(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *desc, + psoc_start_func psoc_start_cb) +{ + QDF_STATUS status; + struct osif_psoc_sync *psoc_sync; + + *out_psoc_sync = NULL; + + psoc_sync = osif_psoc_sync_lookup(dev); + if (!psoc_sync) + return -EAGAIN; + + status = psoc_start_cb(psoc_sync->dsc_psoc, desc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + *out_psoc_sync = psoc_sync; + + return 0; +} + +static int +__osif_psoc_sync_start_wait_callback(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *desc, + psoc_start_func psoc_start_cb) +{ + QDF_STATUS status; + struct osif_psoc_sync *psoc_sync; + + *out_psoc_sync = NULL; + + osif_psoc_sync_lock(); + psoc_sync = osif_psoc_sync_lookup(dev); + osif_psoc_sync_unlock(); + if (!psoc_sync) + return -EAGAIN; + + status = psoc_start_cb(psoc_sync->dsc_psoc, desc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + *out_psoc_sync = psoc_sync; + + return 0; +} + +int __osif_psoc_sync_trans_start(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *desc) +{ + int errno; + + osif_psoc_sync_lock(); + errno = __osif_psoc_sync_start_callback(dev, out_psoc_sync, desc, + dsc_psoc_trans_start); + osif_psoc_sync_unlock(); + + return errno; +} + +int __osif_psoc_sync_trans_start_wait(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *desc) +{ + int errno; + + /* since dsc_psoc_trans_start_wait may sleep do not take lock here */ + errno = __osif_psoc_sync_start_wait_callback(dev, out_psoc_sync, desc, + dsc_psoc_trans_start_wait); + + return errno; +} + +static QDF_STATUS __assert_trans_cb(struct dsc_psoc *dsc_psoc, const char *desc) +{ + dsc_psoc_assert_trans_protected(dsc_psoc); + + return QDF_STATUS_SUCCESS; +} + +int osif_psoc_sync_trans_resume(struct device *dev, + struct osif_psoc_sync **out_psoc_sync) +{ + int errno; + + osif_psoc_sync_lock(); + errno = __osif_psoc_sync_start_callback(dev, out_psoc_sync, NULL, + __assert_trans_cb); + osif_psoc_sync_unlock(); + + return errno; +} + +void osif_psoc_sync_trans_stop(struct osif_psoc_sync *psoc_sync) +{ + dsc_psoc_trans_stop(psoc_sync->dsc_psoc); +} + +void osif_psoc_sync_assert_trans_protected(struct device *dev) +{ + struct osif_psoc_sync *psoc_sync; + + osif_psoc_sync_lock(); + + psoc_sync = osif_psoc_sync_lookup(dev); + QDF_BUG(psoc_sync); + if (psoc_sync) + dsc_psoc_assert_trans_protected(psoc_sync->dsc_psoc); + + osif_psoc_sync_unlock(); +} + +int __osif_psoc_sync_op_start(struct device *dev, + struct osif_psoc_sync **out_psoc_sync, + const char *func) +{ + int errno; + + osif_psoc_sync_lock(); + errno = __osif_psoc_sync_start_callback(dev, out_psoc_sync, func, + _dsc_psoc_op_start); + osif_psoc_sync_unlock(); + if (errno) + dsc_exit_status(errno); + + return errno; +} + +void __osif_psoc_sync_op_stop(struct osif_psoc_sync *psoc_sync, + const char *func) +{ + _dsc_psoc_op_stop(psoc_sync->dsc_psoc, func); +} + +void osif_psoc_sync_wait_for_ops(struct osif_psoc_sync *psoc_sync) +{ + dsc_psoc_wait_for_ops(psoc_sync->dsc_psoc); +} + +void osif_psoc_sync_init(void) +{ + osif_psoc_sync_lock_create(); +} + +void osif_psoc_sync_deinit(void) +{ + osif_psoc_sync_lock_destroy(); +} + +static QDF_STATUS +__osif_psoc_sync_dsc_vdev_create(struct device *dev, + struct dsc_vdev **out_dsc_vdev) +{ + struct osif_psoc_sync *psoc_sync; + + psoc_sync = osif_psoc_sync_lookup(dev); + if (!psoc_sync) + return QDF_STATUS_E_INVAL; + + return dsc_vdev_create(psoc_sync->dsc_psoc, out_dsc_vdev); +} + +QDF_STATUS osif_psoc_sync_dsc_vdev_create(struct device *dev, + struct dsc_vdev **out_dsc_vdev) +{ + QDF_STATUS status; + + osif_psoc_sync_lock(); + status = __osif_psoc_sync_dsc_vdev_create(dev, out_dsc_vdev); + osif_psoc_sync_unlock(); + + return status; +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_sync.c b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_sync.c new file mode 100644 index 0000000000..eff18b403d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_sync.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "__osif_driver_sync.h" +#include "__osif_psoc_sync.h" +#include "__osif_vdev_sync.h" +#include "osif_sync.h" + +void osif_sync_init(void) +{ + osif_driver_sync_init(); + osif_psoc_sync_init(); + osif_vdev_sync_init(); +} + +void osif_sync_deinit(void) +{ + osif_vdev_sync_deinit(); + osif_psoc_sync_deinit(); + osif_driver_sync_deinit(); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_vdev_sync.c b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_vdev_sync.c new file mode 100644 index 0000000000..8e6ba3ea00 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/sync/src/osif_vdev_sync.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 2018-2019, 2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "linux/device.h" +#include "linux/netdevice.h" +#include "__osif_psoc_sync.h" +#include "__osif_vdev_sync.h" +#include "osif_vdev_sync.h" +#include "qdf_lock.h" +#include "qdf_status.h" +#include "qdf_types.h" +#include +#include + +static struct osif_vdev_sync __osif_vdev_sync_arr[WLAN_MAX_VDEVS + + WLAN_MAX_ML_VDEVS]; +static qdf_spinlock_t __osif_vdev_sync_lock; + +#define osif_vdev_sync_lock_create() qdf_spinlock_create(&__osif_vdev_sync_lock) +#define osif_vdev_sync_lock_destroy() \ + qdf_spinlock_destroy(&__osif_vdev_sync_lock) +#define osif_vdev_sync_lock() qdf_spin_lock_bh(&__osif_vdev_sync_lock) +#define osif_vdev_sync_unlock() qdf_spin_unlock_bh(&__osif_vdev_sync_lock) + +static struct osif_vdev_sync *osif_vdev_sync_lookup(struct net_device *net_dev) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(__osif_vdev_sync_arr); i++) { + struct osif_vdev_sync *vdev_sync = __osif_vdev_sync_arr + i; + + if (!vdev_sync->in_use) + continue; + + if (vdev_sync->net_dev == net_dev) + return vdev_sync; + } + + return NULL; +} + +struct osif_vdev_sync *osif_get_vdev_sync_arr(void) +{ + return __osif_vdev_sync_arr; +} + +static struct osif_vdev_sync *osif_vdev_sync_get(void) +{ + int i; + + for (i = 0; i < QDF_ARRAY_SIZE(__osif_vdev_sync_arr); i++) { + struct osif_vdev_sync *vdev_sync = __osif_vdev_sync_arr + i; + + if (!vdev_sync->in_use) { + vdev_sync->in_use = true; + return vdev_sync; + } + } + + return NULL; +} + +static void osif_vdev_sync_put(struct osif_vdev_sync *vdev_sync) +{ + qdf_mem_zero(vdev_sync, sizeof(*vdev_sync)); +} + +int osif_vdev_sync_create(struct device *dev, + struct osif_vdev_sync **out_vdev_sync) +{ + struct osif_vdev_sync *vdev_sync; + QDF_STATUS status; + + QDF_BUG(dev); + if (!dev) + return -EINVAL; + + QDF_BUG(out_vdev_sync); + if (!out_vdev_sync) + return -EINVAL; + + osif_vdev_sync_lock(); + vdev_sync = osif_vdev_sync_get(); + osif_vdev_sync_unlock(); + if (!vdev_sync) + return -ENOMEM; + + status = osif_psoc_sync_dsc_vdev_create(dev, &vdev_sync->dsc_vdev); + if (QDF_IS_STATUS_ERROR(status)) + goto sync_put; + + *out_vdev_sync = vdev_sync; + + return 0; + +sync_put: + osif_vdev_sync_lock(); + osif_vdev_sync_put(vdev_sync); + osif_vdev_sync_unlock(); + + return qdf_status_to_os_return(status); +} + +int __osif_vdev_sync_create_and_trans(struct device *dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc) +{ + struct osif_vdev_sync *vdev_sync; + QDF_STATUS status; + int errno; + + errno = osif_vdev_sync_create(dev, &vdev_sync); + if (errno) + return errno; + + status = dsc_vdev_trans_start(vdev_sync->dsc_vdev, desc); + if (QDF_IS_STATUS_ERROR(status)) + goto sync_destroy; + + *out_vdev_sync = vdev_sync; + + return 0; + +sync_destroy: + osif_vdev_sync_destroy(vdev_sync); + + return qdf_status_to_os_return(status); +} + +void osif_vdev_sync_destroy(struct osif_vdev_sync *vdev_sync) +{ + QDF_BUG(vdev_sync); + if (!vdev_sync) + return; + + dsc_vdev_destroy(&vdev_sync->dsc_vdev); + + osif_vdev_sync_lock(); + osif_vdev_sync_put(vdev_sync); + osif_vdev_sync_unlock(); +} + +void osif_vdev_sync_register(struct net_device *net_dev, + struct osif_vdev_sync *vdev_sync) +{ + QDF_BUG(net_dev); + QDF_BUG(vdev_sync); + if (!vdev_sync) + return; + + osif_vdev_sync_lock(); + vdev_sync->net_dev = net_dev; + osif_vdev_sync_unlock(); +} + +struct osif_vdev_sync *osif_vdev_sync_unregister(struct net_device *net_dev) +{ + struct osif_vdev_sync *vdev_sync; + + QDF_BUG(net_dev); + if (!net_dev) + return NULL; + + osif_vdev_sync_lock(); + vdev_sync = osif_vdev_sync_lookup(net_dev); + if (vdev_sync) + vdev_sync->net_dev = NULL; + osif_vdev_sync_unlock(); + + return vdev_sync; +} + +typedef QDF_STATUS (*vdev_start_func)(struct dsc_vdev *, const char *); + +static int +__osif_vdev_sync_start_callback(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc, + vdev_start_func vdev_start_cb) +{ + QDF_STATUS status; + struct osif_vdev_sync *vdev_sync; + + *out_vdev_sync = NULL; + + vdev_sync = osif_vdev_sync_lookup(net_dev); + if (!vdev_sync) + return -EAGAIN; + + *out_vdev_sync = vdev_sync; + + status = vdev_start_cb(vdev_sync->dsc_vdev, desc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + return 0; +} + +static int +__osif_vdev_sync_start_wait_callback(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc, + vdev_start_func vdev_start_cb) +{ + QDF_STATUS status; + struct osif_vdev_sync *vdev_sync; + + *out_vdev_sync = NULL; + + osif_vdev_sync_lock(); + vdev_sync = osif_vdev_sync_lookup(net_dev); + osif_vdev_sync_unlock(); + if (!vdev_sync) + return -EAGAIN; + + status = vdev_start_cb(vdev_sync->dsc_vdev, desc); + if (QDF_IS_STATUS_ERROR(status)) + return qdf_status_to_os_return(status); + + *out_vdev_sync = vdev_sync; + + return 0; +} + +/** + * osif_vdev_sync_wait_for_uptree_ops - Wait for psoc/driver operations + * @vdev_sync: vdev sync pointer + * + * If there are any psoc/driver operations are taking place, then vdev + * trans/ops should wait for these operations to be completed to avoid + * memory domain mismatch issues. For example, if modules are closed + * because of idle shutdown, memory domain will be init domain and at + * that time if some psoc ops starts, memory allocated as part of this + * ops will be allocated in init domain and if at the same time if vdev + * up starts which will trigger the vdev trans and will start the + * modules and change the memory domain to active domain, now when the + * memory allocated as part of psoc operation is release on psoc ops + * completion will be released in the active domain which leads the + * memory domain mismatch. + * + * Return: None. + */ +static void osif_vdev_sync_wait_for_uptree_ops(struct osif_vdev_sync *vdev_sync) +{ + dsc_vdev_wait_for_uptree_ops(vdev_sync->dsc_vdev); +} + +int __osif_vdev_sync_trans_start(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc) +{ + int errno; + + osif_vdev_sync_lock(); + errno = __osif_vdev_sync_start_callback(net_dev, out_vdev_sync, desc, + dsc_vdev_trans_start); + osif_vdev_sync_unlock(); + + if (!errno) { + osif_vdev_sync_wait_for_ops(*out_vdev_sync); + osif_vdev_sync_wait_for_uptree_ops(*out_vdev_sync); + } + + return errno; +} + +int __osif_vdev_sync_trans_start_wait(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *desc) +{ + int errno; + + /* since dsc_vdev_trans_start_wait may sleep do not take lock here */ + errno = __osif_vdev_sync_start_wait_callback(net_dev, + out_vdev_sync, desc, + dsc_vdev_trans_start_wait); + + if (!errno) { + osif_vdev_sync_wait_for_ops(*out_vdev_sync); + osif_vdev_sync_wait_for_uptree_ops(*out_vdev_sync); + } + + return errno; +} + +void osif_vdev_sync_trans_stop(struct osif_vdev_sync *vdev_sync) +{ + dsc_vdev_trans_stop(vdev_sync->dsc_vdev); +} + +void osif_vdev_sync_assert_trans_protected(struct net_device *net_dev) +{ + struct osif_vdev_sync *vdev_sync; + + osif_vdev_sync_lock(); + + vdev_sync = osif_vdev_sync_lookup(net_dev); + QDF_BUG(vdev_sync); + if (vdev_sync) + dsc_vdev_assert_trans_protected(vdev_sync->dsc_vdev); + + osif_vdev_sync_unlock(); +} + +int __osif_vdev_sync_op_start(struct net_device *net_dev, + struct osif_vdev_sync **out_vdev_sync, + const char *func) +{ + int errno; + + osif_vdev_sync_lock(); + errno = __osif_vdev_sync_start_callback(net_dev, out_vdev_sync, func, + _dsc_vdev_op_start); + osif_vdev_sync_unlock(); + + return errno; +} + +void __osif_vdev_sync_op_stop(struct osif_vdev_sync *vdev_sync, + const char *func) +{ + _dsc_vdev_op_stop(vdev_sync->dsc_vdev, func); +} + +void osif_vdev_sync_wait_for_ops(struct osif_vdev_sync *vdev_sync) +{ + dsc_vdev_wait_for_ops(vdev_sync->dsc_vdev); +} + +void osif_vdev_sync_init(void) +{ + osif_vdev_sync_lock_create(); +} + +void osif_vdev_sync_deinit(void) +{ + osif_vdev_sync_lock_destroy(); +} + +uint8_t osif_vdev_get_cached_cmd(struct osif_vdev_sync *vdev_sync) +{ + return dsc_vdev_get_cached_cmd(vdev_sync->dsc_vdev); +} + +void osif_vdev_cache_command(struct osif_vdev_sync *vdev_sync, uint8_t cmd_id) +{ + dsc_vdev_cache_command(vdev_sync->dsc_vdev, cmd_id); + osif_debug("Set cache cmd to %d", cmd_id); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/tdls/inc/wlan_cfg80211_tdls.h b/qcom/opensource/wlan/qcacld-3.0/os_if/tdls/inc/wlan_cfg80211_tdls.h new file mode 100644 index 0000000000..1fdeac798b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/tdls/inc/wlan_cfg80211_tdls.h @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declares driver functions interfacing with linux kernel + */ + +#ifndef _WLAN_CFG80211_TDLS_H_ +#define _WLAN_CFG80211_TDLS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FEATURE_WLAN_TDLS + +#define TDLS_VDEV_MAGIC 0x54444c53 /* "TDLS" */ + +/** + * struct osif_tdls_vdev - OS tdls vdev private structure + * @tdls_add_peer_comp: Completion to add tdls peer + * @tdls_del_peer_comp: Completion to delete tdls peer + * @tdls_mgmt_comp: Completion to send tdls mgmt packets + * @tdls_link_establish_req_comp: Completion to establish link, sync to + * send establish params to firmware, not used today. + * @tdls_teardown_comp: Completion to teardown tdls peer + * @tdls_user_cmd_comp: tdls user command completion event + * @tdls_antenna_switch_comp: Completion to switch antenna + * @tdls_add_peer_status: Peer status after add peer + * @mgmt_tx_completion_status: Tdls mgmt frames TX completion status code + * @tdls_user_cmd_len: tdls user command written buffer length + * @tdls_antenna_switch_status: return status after antenna switch + * @tdls_user_cmd_in_progress: tdls user command progress status. + */ +struct osif_tdls_vdev { + struct completion tdls_add_peer_comp; + struct completion tdls_del_peer_comp; + struct completion tdls_mgmt_comp; + struct completion tdls_link_establish_req_comp; + struct completion tdls_teardown_comp; + struct completion tdls_user_cmd_comp; + struct completion tdls_antenna_switch_comp; + QDF_STATUS tdls_add_peer_status; + uint32_t mgmt_tx_completion_status; + uint32_t tdls_user_cmd_len; + int tdls_antenna_switch_status; + bool tdls_user_cmd_in_progress; +}; + +/** + * enum qca_wlan_vendor_tdls_trigger_mode_vdev_map: Maps the user space TDLS + * trigger mode in the host driver. + * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: TDLS Connection and + * disconnection handled by user space. + * @WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: TDLS connection and + * disconnection controlled by host driver based on data traffic. + * @WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: TDLS connection and + * disconnection jointly controlled by user space and host driver. + */ +enum qca_wlan_vendor_tdls_trigger_mode_vdev_map { + WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT, + WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT = + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT, + WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL = + ((QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT | + QCA_WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT) << 1), +}; + +/** + * wlan_cfg80211_tdls_osif_priv_init() - API to initialize tdls os private + * @vdev: vdev object + * + * API to initialize tdls os private + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_cfg80211_tdls_osif_priv_init(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cfg80211_tdls_osif_priv_deinit() - API to deinitialize tdls os private + * @vdev: vdev object + * + * API to deinitialize tdls os private + * + * Return: None + */ +void wlan_cfg80211_tdls_osif_priv_deinit(struct wlan_objmgr_vdev *vdev); + +/** + * wlan_cfg80211_tdls_add_peer_mlo() - process cfg80211 add TDLS peer request + * @adapter: adapter pointer + * @mac: MAC address for TDLS peer + * @link_id: link id + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_cfg80211_tdls_add_peer_mlo(struct hdd_adapter *adapter, + const uint8_t *mac, uint8_t link_id); + +/** + * wlan_cfg80211_tdls_update_peer() - process cfg80211 update TDLS peer request + * @vdev: vdev object + * @mac: MAC address for TDLS peer + * @params: Pointer to station parameters + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac, + struct station_parameters *params); + +/** + * wlan_cfg80211_tdls_configure_mode() - configure tdls mode + * @vdev: vdev obj manager + * @trigger_mode: tdls trgger mode + * + * Return: 0 for success; negative errno otherwise + */ +int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev, + uint32_t trigger_mode); + +/** + * wlan_cfg80211_tdls_oper() - process cfg80211 operation on an TDLS peer + * @vdev: vdev object + * @peer: MAC address of the TDLS peer + * @oper: cfg80211 TDLS operation + * + * Return: 0 on success; negative errno otherwise + */ +int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer, + enum nl80211_tdls_operation oper); + +/** + * wlan_cfg80211_tdls_get_all_peers() - get all the TDLS peers from the list + * @vdev: vdev object + * @buf: output buffer + * @buflen: valid length of the output error + * + * Return: length of the output buffer + */ +int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen); + +/** + * wlan_cfg80211_tdls_is_fw_wideband_capable() - Check whether fw supports + * wideband TDLS + * @vdev: Pointer to vdev + * + * Return: true if fw supports wideband TDLS connection + */ +bool wlan_cfg80211_tdls_is_fw_wideband_capable(struct wlan_objmgr_vdev *vdev); + +#ifdef WLAN_FEATURE_11AX +/** + * wlan_cfg80211_tdls_is_fw_6ghz_capable() - Check whether fw supports 6 GHz + * band TDLS + * @vdev: Pointer to vdev + * + * Return: true if fw supports 6 GHz TDLS connection + */ +bool wlan_cfg80211_tdls_is_fw_6ghz_capable(struct wlan_objmgr_vdev *vdev); +#endif + +/** + * wlan_cfg80211_tdls_mgmt_mlo() - process TDLS management frames from + * the supplicant + * @adapter: adapter object + * @peer: MAC address of the TDLS peer + * @action_code: type of TDLS mgmt frame to be sent + * @dialog_token: dialog token used in the frame + * @status_code: status to be included in the frame + * @peer_capability: peer capability information + * @buf: additional IEs to be included + * @len: length of additional Ies + * @link_id: link id + * + * Return: 0 on success; negative errno otherwise + */ +int wlan_cfg80211_tdls_mgmt_mlo(struct hdd_adapter *adapter, + const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len, int link_id); + +/** + * wlan_tdls_antenna_switch() - process TDLS antenna switch + * @vdev: vdev object + * @mode: antenna mode + * + * Return: 0 on success; -EAGAIN to retry + */ +int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode); + +/** + * wlan_cfg80211_tdls_event_callback() - callback for TDLS module + * @userdata: user data + * @type: request callback type + * @param: passed parameter + * + * This is used by TDLS to sync with os interface + * + * Return: None + */ +void wlan_cfg80211_tdls_event_callback(void *userdata, + enum tdls_event_type type, + struct tdls_osif_indication *param); + +/** + * wlan_cfg80211_tdls_rx_callback() - Callback for rx mgmt frame + * @user_data: pointer to soc object + * @rx_frame: RX mgmt frame information + * + * This callback will be used to rx frames in os interface. + * + * Return: None + */ +void wlan_cfg80211_tdls_rx_callback(void *user_data, + struct tdls_rx_mgmt_frame *rx_frame); + +/** + * hdd_notify_tdls_reset_adapter() - notify reset adapter to TDLS + * @vdev: vdev object manager + * + * Notify hdd reset adapter to TDLS component + * + * Return: None + */ +void hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev); + +#else /* FEATURE_WLAN_TDLS */ +static inline +QDF_STATUS wlan_cfg80211_tdls_osif_priv_init(struct wlan_objmgr_vdev *vdev) +{ + return QDF_STATUS_SUCCESS; +} + +static inline +void wlan_cfg80211_tdls_osif_priv_deinit(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline void +hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev, + uint32_t trigger_mode) +{ + return 0; +} +#endif /* FEATURE_WLAN_TDLS */ +#endif /* _WLAN_CFG80211_TDLS_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/tdls/src/wlan_cfg80211_tdls.c b/qcom/opensource/wlan/qcacld-3.0/os_if/tdls/src/wlan_cfg80211_tdls.c new file mode 100644 index 0000000000..2f99ad7c33 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/tdls/src/wlan_cfg80211_tdls.c @@ -0,0 +1,1489 @@ +/* + * Copyright (c) 2017-2021 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: defines driver functions interfacing with linux kernel + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_cfg80211_mc_cp_stats.h" +#include "sir_api.h" +#include "wlan_tdls_ucfg_api.h" +#include "wlan_cm_roam_api.h" +#include "wlan_mlo_mgr_sta.h" +#include "wlan_hdd_main.h" +#include "wlan_hdd_object_manager.h" + +static int wlan_cfg80211_tdls_validate_mac_addr(const uint8_t *mac) +{ + static const uint8_t temp_mac[QDF_MAC_ADDR_SIZE] = {0}; + + if (!qdf_mem_cmp(mac, temp_mac, QDF_MAC_ADDR_SIZE)) { + osif_debug("Invalid Mac address " QDF_MAC_ADDR_FMT + " cmd declined.", + QDF_MAC_ADDR_REF(mac)); + return -EINVAL; + } + + return 0; +} + +QDF_STATUS wlan_cfg80211_tdls_osif_priv_init(struct wlan_objmgr_vdev *vdev) +{ + struct osif_tdls_vdev *tdls_priv; + struct vdev_osif_priv *osif_priv; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is NULL!"); + return QDF_STATUS_E_FAULT; + } + + osif_debug("initialize tdls os if layer private structure"); + tdls_priv = qdf_mem_malloc(sizeof(*tdls_priv)); + if (!tdls_priv) + return QDF_STATUS_E_NOMEM; + + init_completion(&tdls_priv->tdls_add_peer_comp); + init_completion(&tdls_priv->tdls_del_peer_comp); + init_completion(&tdls_priv->tdls_mgmt_comp); + init_completion(&tdls_priv->tdls_link_establish_req_comp); + init_completion(&tdls_priv->tdls_teardown_comp); + init_completion(&tdls_priv->tdls_user_cmd_comp); + init_completion(&tdls_priv->tdls_antenna_switch_comp); + + osif_priv->osif_tdls = tdls_priv; + + return QDF_STATUS_SUCCESS; +} + +void wlan_cfg80211_tdls_osif_priv_deinit(struct wlan_objmgr_vdev *vdev) +{ + struct vdev_osif_priv *osif_priv; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is NULL!"); + return; + } + + osif_debug("deinitialize tdls os if layer private structure"); + if (osif_priv->osif_tdls) + qdf_mem_free(osif_priv->osif_tdls); + osif_priv->osif_tdls = NULL; +} + +void hdd_notify_tdls_reset_adapter(struct wlan_objmgr_vdev *vdev) +{ + ucfg_tdls_notify_reset_adapter(vdev); +} + +static int wlan_cfg80211_tdls_add_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac) +{ + struct tdls_add_peer_params *add_peer_req; + int status; + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + unsigned long rc; + + status = wlan_cfg80211_tdls_validate_mac_addr(mac); + + if (status) + return status; + + osif_debug("Add TDLS peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + + add_peer_req = qdf_mem_malloc(sizeof(*add_peer_req)); + if (!add_peer_req) + return -EINVAL; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv || !osif_priv->osif_tdls) { + osif_err("osif_tdls_vdev or osif_priv is NULL for the current vdev"); + status = -EINVAL; + goto error; + } + tdls_priv = osif_priv->osif_tdls; + add_peer_req->vdev_id = wlan_vdev_get_id(vdev); + + qdf_mem_copy(add_peer_req->peer_addr, mac, QDF_MAC_ADDR_SIZE); + + reinit_completion(&tdls_priv->tdls_add_peer_comp); + status = ucfg_tdls_add_peer(vdev, add_peer_req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("ucfg_tdls_add_peer returned err %d", status); + status = -EIO; + goto error; + } + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_add_peer_comp, + msecs_to_jiffies(WAIT_TIME_TDLS_ADD_STA)); + if (!rc) { + osif_err("timeout for tdls add peer indication %ld", rc); + status = -EPERM; + goto error; + } + + if (QDF_IS_STATUS_ERROR(tdls_priv->tdls_add_peer_status)) { + osif_err("tdls add peer failed, status:%d", + tdls_priv->tdls_add_peer_status); + status = -EPERM; + } +error: + qdf_mem_free(add_peer_req); + return status; +} + +int wlan_cfg80211_tdls_add_peer_mlo(struct hdd_adapter *adapter, + const uint8_t *mac, uint8_t link_id) +{ + struct wlan_objmgr_vdev *vdev; + bool is_mlo_vdev; + int status; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) { + osif_debug("sta is not connected or disconnecting"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + return -EINVAL; + } + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + + vdev = wlan_key_get_link_vdev(adapter, WLAN_OSIF_TDLS_ID, + link_id); + if (!vdev) + return -EINVAL; + + if (!ucfg_tdls_link_vdev_is_matching(vdev)) { + wlan_key_put_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + return -EINVAL; + } + + osif_debug("tdls add peer for vdev %d", wlan_vdev_get_id(vdev)); + status = wlan_cfg80211_tdls_add_peer(vdev, mac); + wlan_key_put_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + } else { + status = wlan_cfg80211_tdls_add_peer(vdev, mac); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + } + + return status; +} + +static bool +is_duplicate_freq(qdf_freq_t *arr, uint8_t index, qdf_freq_t freq) +{ + int i; + + for (i = 0; i < index; i++) { + if (arr[i] == freq) + return true; + } + return false; +} + +static uint8_t +tdls_fill_chan_freq_from_supported_ch_list(struct wlan_objmgr_pdev *pdev, + const uint8_t *country, + const uint8_t *src_chans, + uint8_t src_chan_num, + uint8_t src_opclass, + uint8_t *num_freq, + qdf_freq_t *freq_lst) +{ + uint8_t i = 0, j = 0, num_unique_freq = *num_freq; + uint8_t chan_count; + uint8_t wifi_chan_index; + uint8_t next_ch; + qdf_freq_t freq; + + for (i = 0; i < src_chan_num && + num_unique_freq < WLAN_MAC_MAX_SUPP_CHANNELS; i += 2) { + freq = wlan_reg_country_chan_opclass_to_freq(pdev, country, + src_chans[i], + src_opclass, + false); + + if (!freq || is_duplicate_freq(freq_lst, num_unique_freq, freq)) + continue; + + if (wlan_reg_is_6ghz_chan_freq(freq) && + !wlan_reg_is_6ghz_psc_chan_freq(freq)) { + osif_debug("skipping non-psc channel %d", freq); + continue; + } + + chan_count = src_chans[i + 1]; + wifi_chan_index = ((src_chans[i] <= WLAN_CHANNEL_14) ? 1 : 4); + freq_lst[num_unique_freq] = freq; + num_unique_freq++; + next_ch = src_chans[i]; + osif_debug("freq %d index %d ", freq, num_unique_freq); + + for (j = 1; j < chan_count && + num_unique_freq < WLAN_MAC_MAX_SUPP_CHANNELS; j++) { + next_ch += wifi_chan_index; + freq = wlan_reg_country_chan_opclass_to_freq( + pdev, country, next_ch, + src_opclass, false); + + if (!freq || + is_duplicate_freq(freq_lst, num_unique_freq, freq)) + continue; + + if (wlan_reg_is_6ghz_chan_freq(freq) && + !wlan_reg_is_6ghz_psc_chan_freq(freq)) { + osif_debug("skipping non-psc channel %d", freq); + continue; + } + + freq_lst[num_unique_freq] = freq; + osif_debug("freq %d index %d ", freq, num_unique_freq); + num_unique_freq++; + + if (num_unique_freq > NUM_CHANNELS) { + osif_debug("num_unique_freq more than max num"); + break; + } + } + } + *num_freq = num_unique_freq; + + return num_unique_freq; +} + +static void +tdls_calc_channels_from_staparams(struct wlan_objmgr_vdev *vdev, + struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ + uint8_t i = 0; + uint8_t num_unique_freq = 0; + const uint8_t *src_chans, *src_opclass; + qdf_freq_t *dest_freq; + uint8_t country[REG_ALPHA2_LEN + 1]; + QDF_STATUS status; + struct wlan_objmgr_pdev *pdev; + + if (!vdev) { + osif_err("null vdev"); + return; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + osif_err("null pdev"); + return; + } + src_chans = params->supported_channels; + src_opclass = params->supported_oper_classes; + dest_freq = req_info->supported_chan_freq; + pdev = wlan_vdev_get_pdev(vdev); + status = wlan_cm_get_country_code(pdev, wlan_vdev_get_id(vdev), + country); + + osif_debug("Country info from AP:%c%c 0x%x", country[0], + country[1], country[2]); + + for (i = 0; i < params->supported_oper_classes_len; i++) + tdls_fill_chan_freq_from_supported_ch_list( + pdev, country, src_chans, + params->supported_channels_len, + src_opclass[i], + &num_unique_freq, + dest_freq); + + osif_debug("Unique Channel List: supported_channels "); + for (i = 0; i < num_unique_freq; i++) + osif_debug(" %d,", dest_freq[i]); + + req_info->supported_channels_len = num_unique_freq; + osif_debug("After removing duplcates supported_channels_len: %d", + req_info->supported_channels_len); +} + +#ifdef WLAN_FEATURE_11AX +#if defined(WLAN_LINK_STA_PARAMS_PRESENT) && defined(CONFIG_BAND_6GHZ) +static void +wlan_cfg80211_tdls_extract_6ghz_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ + if (!params->link_sta_params.he_6ghz_capa) { + osif_debug("6 Ghz he_capa not present"); + return; + } + + qdf_mem_copy(&req_info->he_6ghz_cap, + params->link_sta_params.he_6ghz_capa, + sizeof(req_info->he_6ghz_cap)); +} +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)) && defined(CONFIG_BAND_6GHZ) +static void +wlan_cfg80211_tdls_extract_6ghz_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ + if (!params->he_6ghz_capa) { + osif_debug("6 Ghz he_capa not present"); + return; + } + + qdf_mem_copy(&req_info->he_6ghz_cap, params->he_6ghz_capa, + sizeof(req_info->he_6ghz_cap)); +} +#else +static void +wlan_cfg80211_tdls_extract_6ghz_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ + osif_debug("kernel don't support tdls 6 ghz band"); +} +#endif + +#ifdef WLAN_LINK_STA_PARAMS_PRESENT +static void +wlan_cfg80211_tdls_extract_he_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params, + bool tdls_6g_support) +{ + if (params->link_sta_params.he_capa_len < MIN_TDLS_HE_CAP_LEN) { + osif_debug("he_capa_len %d less than MIN_TDLS_HE_CAP_LEN", + params->link_sta_params.he_capa_len); + return; + } + + if (!params->link_sta_params.he_capa) { + osif_debug("he_capa not present"); + return; + } + + req_info->he_cap_len = params->link_sta_params.he_capa_len; + if (req_info->he_cap_len > MAX_TDLS_HE_CAP_LEN) + req_info->he_cap_len = MAX_TDLS_HE_CAP_LEN; + + qdf_mem_copy(&req_info->he_cap, params->link_sta_params.he_capa, + req_info->he_cap_len); + + if (tdls_6g_support) + wlan_cfg80211_tdls_extract_6ghz_params(req_info, params); +} +#else +static void +wlan_cfg80211_tdls_extract_he_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params, + bool tdls_6g_support) +{ + if (params->he_capa_len < MIN_TDLS_HE_CAP_LEN) { + osif_debug("he_capa_len %d less than MIN_TDLS_HE_CAP_LEN", + params->he_capa_len); + return; + } + + if (!params->he_capa) { + osif_debug("he_capa not present"); + return; + } + + req_info->he_cap_len = params->he_capa_len; + if (req_info->he_cap_len > MAX_TDLS_HE_CAP_LEN) + req_info->he_cap_len = MAX_TDLS_HE_CAP_LEN; + + qdf_mem_copy(&req_info->he_cap, params->he_capa, + req_info->he_cap_len); + + if (tdls_6g_support) + wlan_cfg80211_tdls_extract_6ghz_params(req_info, params); +} +#endif +#else +static inline void +wlan_cfg80211_tdls_extract_he_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params, + bool tdls_6g_support) +{ +} +#endif + +#ifdef WLAN_FEATURE_11BE +#ifdef WLAN_LINK_STA_PARAMS_PRESENT +static void +wlan_cfg80211_tdls_extract_eht_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ + if (params->link_sta_params.eht_capa) { + osif_debug("eht capa is present"); + req_info->ehtcap_present = 1; + req_info->eht_cap_len = params->link_sta_params.eht_capa_len; + qdf_mem_copy(&req_info->eht_cap, + params->link_sta_params.eht_capa, + sizeof(struct ehtcap)); + } else { + req_info->ehtcap_present = 0; + } +} +#elif defined(WLAN_EHT_CAPABILITY_PRESENT) +static void +wlan_cfg80211_tdls_extract_eht_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ + if (params->eht_capa) { + osif_debug("eht capa is present"); + req_info->ehtcap_present = 1; + req_info->eht_cap_len = params->eht_capa_len; + qdf_mem_copy(&req_info->eht_cap, params->eht_capa, + sizeof(struct ehtcap)); + } else { + req_info->ehtcap_present = 0; + } +} +#else +static inline void +wlan_cfg80211_tdls_extract_eht_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ +} +#endif +#else +static inline void +wlan_cfg80211_tdls_extract_eht_params(struct tdls_update_peer_params *req_info, + struct station_parameters *params) +{ +} +#endif + +#ifdef WLAN_LINK_STA_PARAMS_PRESENT +static void +wlan_cfg80211_tdls_extract_params(struct wlan_objmgr_vdev *vdev, + struct tdls_update_peer_params *req_info, + struct station_parameters *params, + bool tdls_11ax_support, bool tdls_6g_support) +{ + int i; + + osif_debug("sta cap %d, uapsd_queue %d, max_sp %d", + params->capability, + params->uapsd_queues, params->max_sp); + + if (!req_info) { + osif_err("reg_info is NULL"); + return; + } + req_info->capability = params->capability; + req_info->uapsd_queues = params->uapsd_queues; + req_info->max_sp = params->max_sp; + + if (params->supported_oper_classes_len > WLAN_MAX_SUPP_OPER_CLASSES) { + osif_debug("received oper classes:%d, resetting it to max supported: %d", + params->supported_oper_classes_len, + WLAN_MAX_SUPP_OPER_CLASSES); + params->supported_oper_classes_len = WLAN_MAX_SUPP_OPER_CLASSES; + } + + qdf_mem_copy(req_info->supported_oper_classes, + params->supported_oper_classes, + params->supported_oper_classes_len); + req_info->supported_oper_classes_len = + params->supported_oper_classes_len; + + if (params->supported_channels_len) + tdls_calc_channels_from_staparams(vdev, req_info, params); + + if (params->ext_capab_len) + qdf_mem_copy(req_info->extn_capability, params->ext_capab, + sizeof(req_info->extn_capability)); + + if (params->link_sta_params.ht_capa) { + req_info->htcap_present = 1; + qdf_mem_copy(&req_info->ht_cap, params->link_sta_params.ht_capa, + sizeof(struct htcap_cmn_ie)); + } + + req_info->supported_rates_len = + params->link_sta_params.supported_rates_len; + + /* Note: The Maximum size of supported_rates sent by the Supplicant is + * 32. The supported_rates array, for all the structures propagating + * until Add Sta to the firmware, has to be modified if the supplicant + * (ieee80211) is modified to send more rates. + */ + + /* To avoid Data Corruption, set to max length to SIR_MAC_MAX_SUPP_RATES + */ + if (req_info->supported_rates_len > WLAN_MAC_MAX_SUPP_RATES) + req_info->supported_rates_len = WLAN_MAC_MAX_SUPP_RATES; + + if (req_info->supported_rates_len) { + qdf_mem_copy(req_info->supported_rates, + params->link_sta_params.supported_rates, + req_info->supported_rates_len); + osif_debug("Supported Rates with Length %d", + req_info->supported_rates_len); + + for (i = 0; i < req_info->supported_rates_len; i++) + osif_debug("[%d]: %0x", i, + req_info->supported_rates[i]); + } + + if (params->link_sta_params.vht_capa) { + req_info->vhtcap_present = 1; + qdf_mem_copy(&req_info->vht_cap, + params->link_sta_params.vht_capa, + sizeof(struct vhtcap)); + } + + if (params->link_sta_params.ht_capa || + params->link_sta_params.vht_capa || + (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME))) + req_info->is_qos_wmm_sta = true; + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_MFP)) { + osif_debug("TDLS peer pmf capable"); + req_info->is_pmf = 1; + } + if (tdls_11ax_support) + wlan_cfg80211_tdls_extract_he_params(req_info, params, + tdls_6g_support); + else + osif_debug("tdls ax disabled"); + + wlan_cfg80211_tdls_extract_eht_params(req_info, params); +} +#else +static void +wlan_cfg80211_tdls_extract_params(struct wlan_objmgr_vdev *vdev, + struct tdls_update_peer_params *req_info, + struct station_parameters *params, + bool tdls_11ax_support, bool tdls_6g_support) +{ + int i; + + osif_debug("sta cap %d, uapsd_queue %d, max_sp %d", + params->capability, + params->uapsd_queues, params->max_sp); + + if (!req_info) { + osif_err("reg_info is NULL"); + return; + } + req_info->capability = params->capability; + req_info->uapsd_queues = params->uapsd_queues; + req_info->max_sp = params->max_sp; + + if (params->supported_oper_classes_len > WLAN_MAX_SUPP_OPER_CLASSES) { + osif_debug("received oper classes:%d, resetting it to max supported: %d", + params->supported_oper_classes_len, + WLAN_MAX_SUPP_OPER_CLASSES); + params->supported_oper_classes_len = WLAN_MAX_SUPP_OPER_CLASSES; + } + + qdf_mem_copy(req_info->supported_oper_classes, + params->supported_oper_classes, + params->supported_oper_classes_len); + req_info->supported_oper_classes_len = + params->supported_oper_classes_len; + + if (params->supported_channels_len) + tdls_calc_channels_from_staparams(vdev, req_info, params); + + if (params->ext_capab_len) + qdf_mem_copy(req_info->extn_capability, params->ext_capab, + sizeof(req_info->extn_capability)); + + if (params->ht_capa) { + req_info->htcap_present = 1; + qdf_mem_copy(&req_info->ht_cap, params->ht_capa, + sizeof(struct htcap_cmn_ie)); + } + + req_info->supported_rates_len = params->supported_rates_len; + + /* Note : The Maximum sizeof supported_rates sent by the Supplicant is + * 32. The supported_rates array , for all the structures propagating + * till Add Sta to the firmware has to be modified , if the supplicant + * (ieee80211) is modified to send more rates. + */ + + /* To avoid Data Currption , set to max length to SIR_MAC_MAX_SUPP_RATES + */ + if (req_info->supported_rates_len > WLAN_MAC_MAX_SUPP_RATES) + req_info->supported_rates_len = WLAN_MAC_MAX_SUPP_RATES; + + if (req_info->supported_rates_len) { + qdf_mem_copy(req_info->supported_rates, + params->supported_rates, + req_info->supported_rates_len); + osif_debug("Supported Rates with Length %d", + req_info->supported_rates_len); + + for (i = 0; i < req_info->supported_rates_len; i++) + osif_debug("[%d]: %0x", i, + req_info->supported_rates[i]); + } + + if (params->vht_capa) { + req_info->vhtcap_present = 1; + qdf_mem_copy(&req_info->vht_cap, params->vht_capa, + sizeof(struct vhtcap)); + } + + if (params->ht_capa || params->vht_capa || + (params->sta_flags_set & BIT(NL80211_STA_FLAG_WME))) + req_info->is_qos_wmm_sta = true; + if (params->sta_flags_set & BIT(NL80211_STA_FLAG_MFP)) { + osif_debug("TDLS peer pmf capable"); + req_info->is_pmf = 1; + } + if (tdls_11ax_support) + wlan_cfg80211_tdls_extract_he_params(req_info, params, + tdls_6g_support); + else + osif_debug("tdls ax disabled"); + + wlan_cfg80211_tdls_extract_eht_params(req_info, params); +} +#endif + +int wlan_cfg80211_tdls_update_peer(struct wlan_objmgr_vdev *vdev, + const uint8_t *mac, + struct station_parameters *params) +{ + struct tdls_update_peer_params *req_info; + int status; + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + unsigned long rc; + struct wlan_objmgr_psoc *psoc; + bool tdls_11ax_support = false; + bool tdls_6g_support = false; + bool is_mlo_vdev; + + status = wlan_cfg80211_tdls_validate_mac_addr(mac); + + if (status) + return status; + + osif_debug("Update TDLS peer " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(mac)); + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (!vdev) { + osif_err("no tdls link vdev"); + return -EINVAL; + } + } + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err_rl("Invalid psoc"); + goto relref; + } + + req_info = qdf_mem_malloc(sizeof(*req_info)); + if (!req_info) { + status = -EINVAL; + goto relref; + } + + tdls_11ax_support = ucfg_tdls_is_fw_11ax_capable(psoc); + tdls_6g_support = ucfg_tdls_is_fw_6g_capable(psoc); + wlan_cfg80211_tdls_extract_params(vdev, req_info, params, + tdls_11ax_support, + tdls_6g_support); + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv || !osif_priv->osif_tdls) { + osif_err("osif priv or tdls priv is NULL"); + status = -EINVAL; + goto error; + } + tdls_priv = osif_priv->osif_tdls; + req_info->vdev_id = wlan_vdev_get_id(vdev); + qdf_mem_copy(req_info->peer_addr, mac, QDF_MAC_ADDR_SIZE); + + reinit_completion(&tdls_priv->tdls_add_peer_comp); + status = ucfg_tdls_update_peer(vdev, req_info); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("ucfg_tdls_update_peer returned err %d", status); + status = -EIO; + goto error; + } + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_add_peer_comp, + msecs_to_jiffies(WAIT_TIME_TDLS_ADD_STA)); + if (!rc) { + osif_err("timeout for tdls update peer indication %ld", rc); + status = -EPERM; + goto error; + } + + if (QDF_IS_STATUS_ERROR(tdls_priv->tdls_add_peer_status)) { + osif_err("tdls update peer failed, status:%d", + tdls_priv->tdls_add_peer_status); + status = -EPERM; + } +error: + qdf_mem_free(req_info); +relref: + if (is_mlo_vdev) + ucfg_tdls_put_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + return status; +} + +static char *tdls_oper_to_str(enum nl80211_tdls_operation oper) +{ + switch (oper) { + case NL80211_TDLS_ENABLE_LINK: + return "TDLS_ENABLE_LINK"; + case NL80211_TDLS_DISABLE_LINK: + return "TDLS_DISABLE_LINK"; + case NL80211_TDLS_TEARDOWN: + return "TDLS_TEARDOWN"; + case NL80211_TDLS_SETUP: + return "TDLS_SETUP"; + default: + return "UNKNOWN:ERR"; + } +} + +static enum tdls_command_type tdls_oper_to_cmd(enum nl80211_tdls_operation oper) +{ + if (oper == NL80211_TDLS_ENABLE_LINK) + return TDLS_CMD_ENABLE_LINK; + else if (oper == NL80211_TDLS_DISABLE_LINK) + return TDLS_CMD_DISABLE_LINK; + else if (oper == NL80211_TDLS_TEARDOWN) + return TDLS_CMD_REMOVE_FORCE_PEER; + else if (oper == NL80211_TDLS_SETUP) + return TDLS_CMD_CONFIG_FORCE_PEER; + else + return 0; +} + +int wlan_cfg80211_tdls_configure_mode(struct wlan_objmgr_vdev *vdev, + uint32_t trigger_mode) +{ + enum tdls_feature_mode tdls_mode; + struct tdls_set_mode_params set_mode_params; + int status; + + if (!vdev) + return -EINVAL; + + switch (trigger_mode) { + case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXPLICIT: + tdls_mode = TDLS_SUPPORT_EXP_TRIG_ONLY; + return 0; + case WLAN_VENDOR_TDLS_TRIGGER_MODE_EXTERNAL: + tdls_mode = TDLS_SUPPORT_EXT_CONTROL; + break; + case WLAN_VENDOR_TDLS_TRIGGER_MODE_IMPLICIT: + tdls_mode = TDLS_SUPPORT_IMP_MODE; + return 0; + default: + osif_err("Invalid TDLS trigger mode"); + return -EINVAL; + } + + osif_notice("cfg80211 tdls trigger mode %d", trigger_mode); + set_mode_params.source = TDLS_SET_MODE_SOURCE_USER; + set_mode_params.tdls_mode = tdls_mode; + set_mode_params.update_last = false; + set_mode_params.vdev = vdev; + + status = ucfg_tdls_set_operating_mode(&set_mode_params); + return status; +} + +int wlan_cfg80211_tdls_oper(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer, + enum nl80211_tdls_operation oper) +{ + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + int status; + unsigned long rc; + enum tdls_command_type cmd; + bool is_mlo_vdev; + + status = wlan_cfg80211_tdls_validate_mac_addr(peer); + + if (status) + return status; + + if (NL80211_TDLS_DISCOVERY_REQ == oper) { + osif_warn( + "We don't support in-driver setup/teardown/discovery"); + return -ENOTSUPP; + } + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + vdev = ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (!vdev) { + osif_err("no tdls link vdev"); + return -EINVAL; + } + } + + osif_debug("%s start", tdls_oper_to_str(oper)); + cmd = tdls_oper_to_cmd(oper); + switch (oper) { + case NL80211_TDLS_ENABLE_LINK: + case NL80211_TDLS_TEARDOWN: + case NL80211_TDLS_SETUP: + status = ucfg_tdls_oper(vdev, peer, cmd); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("%s fail %d", + tdls_oper_to_str(oper), status); + status = -EIO; + goto error; + } + break; + case NL80211_TDLS_DISABLE_LINK: + wlan_vdev_mlme_feat_ext2_cap_clear(vdev, + WLAN_VDEV_FEXT2_MLO_STA_TDLS); + + osif_priv = wlan_vdev_get_ospriv(vdev); + + if (!osif_priv || !osif_priv->osif_tdls) { + osif_err("osif priv or tdls priv is NULL"); + status = -EINVAL; + goto error; + } + tdls_priv = osif_priv->osif_tdls; + reinit_completion(&tdls_priv->tdls_del_peer_comp); + status = ucfg_tdls_oper(vdev, peer, cmd); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("ucfg_tdls_disable_link fail %d", status); + status = -EIO; + goto error; + } + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_del_peer_comp, + msecs_to_jiffies(WAIT_TIME_TDLS_DEL_STA)); + if (!rc) { + osif_err("timeout for tdls disable link %ld", rc); + status = -EPERM; + } + break; + default: + osif_err("unsupported event %d", oper); + status = -ENOTSUPP; + } + +error: + if (is_mlo_vdev) + ucfg_tdls_put_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + return status; +} + +void wlan_cfg80211_tdls_rx_callback(void *user_data, + struct tdls_rx_mgmt_frame *rx_frame) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_vdev *vdev, *assoc_vdev; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + enum QDF_OPMODE opmode; + + psoc = user_data; + if (!psoc) { + osif_err("psoc is null"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + rx_frame->vdev_id, WLAN_TDLS_NB_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + assoc_vdev = vdev; + opmode = wlan_vdev_mlme_get_opmode(vdev); + + if ((opmode == QDF_STA_MODE || opmode == QDF_TDLS_MODE) && + wlan_vdev_mlme_is_mlo_vdev(vdev)) { + assoc_vdev = ucfg_mlo_get_assoc_link_vdev(vdev); + if (!assoc_vdev) { + osif_err("assoc vdev is null"); + goto fail; + } + } + + osif_priv = wlan_vdev_get_ospriv(assoc_vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wdev is null"); + goto fail; + } + + osif_notice("Indicate frame over nl80211, vdev id:%d, idx:%d", + rx_frame->vdev_id, wdev->netdev->ifindex); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 18, 0)) + cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, + NL80211_RXMGMT_FLAG_ANSWERED); +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)) + cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, + NL80211_RXMGMT_FLAG_ANSWERED, GFP_ATOMIC); +#else + cfg80211_rx_mgmt(wdev, rx_frame->rx_freq, rx_frame->rx_rssi * 100, + rx_frame->buf, rx_frame->frame_len, GFP_ATOMIC); +#endif /* LINUX_VERSION_CODE */ +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TDLS_NB_ID); +} + +static void wlan_cfg80211_update_tdls_peers_rssi(struct wlan_objmgr_vdev *vdev) +{ + int ret = 0, i; + struct stats_event *rssi_info; + struct qdf_mac_addr bcast_mac = QDF_MAC_ADDR_BCAST_INIT; + + rssi_info = wlan_cfg80211_mc_cp_stats_get_peer_rssi( + vdev, bcast_mac.bytes, + &ret); + if (ret || !rssi_info) { + osif_err("get peer rssi fail"); + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); + return; + } + + for (i = 0; i < rssi_info->num_peer_stats; i++) + ucfg_tdls_set_rssi(vdev, rssi_info->peer_stats[i].peer_macaddr, + rssi_info->peer_stats[i].peer_rssi); + + wlan_cfg80211_mc_cp_stats_free_stats_event(rssi_info); +} + +int wlan_cfg80211_tdls_get_all_peers(struct wlan_objmgr_vdev *vdev, + char *buf, int buflen) +{ + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + int32_t len; + QDF_STATUS status; + unsigned long rc; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv || !osif_priv->osif_tdls) { + osif_err("osif_tdls_vdev or osif_priv is NULL for the current vdev"); + return -EINVAL; + } + + tdls_priv = osif_priv->osif_tdls; + + /* + * We shouldn't use completion_done here for checking for completion + * as this will always return false, as tdls_user_cmd_comp.done will + * remain in init state always. So, the very first command will also + * not work. + * In general completion_done is used to check if there are multiple + * threads waiting on the complete event that's why it will return true + * only when tdls_user_cmd_comp.done is set with complete() + * In general completion_done will return true only when + * tdls_user_cmd_comp.done is set that will happen in complete(). + * Also, if there is already a thread waiting for wait_for_completion, + * this function will + * return true only after the wait timer is over or condition is + * met as wait_for_completion will hold out the hold lock and will + * will prevent completion_done from returning. + * Better to use a flag to determine command condition. + */ + if (tdls_priv->tdls_user_cmd_in_progress) { + osif_err("TDLS user cmd still in progress, reject this one"); + return -EBUSY; + } + + tdls_priv->tdls_user_cmd_in_progress = true; + wlan_cfg80211_update_tdls_peers_rssi(vdev); + + reinit_completion(&tdls_priv->tdls_user_cmd_comp); + status = ucfg_tdls_get_all_peers(vdev, buf, buflen); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("ucfg_tdls_get_all_peers failed err %d", status); + len = scnprintf(buf, buflen, + "\nucfg_tdls_send_mgmt failed\n"); + goto error_get_tdls_peers; + } + + osif_debug("Wait for tdls_user_cmd_comp. Timeout %u ms", + WAIT_TIME_FOR_TDLS_USER_CMD); + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_user_cmd_comp, + msecs_to_jiffies(WAIT_TIME_FOR_TDLS_USER_CMD)); + + if (0 == rc) { + osif_err("TDLS user cmd get all peers timed out rc %ld", + rc); + len = scnprintf(buf, buflen, + "\nTDLS user cmd get all peers timed out\n"); + goto error_get_tdls_peers; + } + + len = tdls_priv->tdls_user_cmd_len; + +error_get_tdls_peers: + tdls_priv->tdls_user_cmd_in_progress = false; + return len; +} + +bool wlan_cfg80211_tdls_is_fw_wideband_capable(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return false; + + return ucfg_tdls_is_fw_wideband_capable(psoc); +} + +#ifdef WLAN_FEATURE_11AX +bool wlan_cfg80211_tdls_is_fw_6ghz_capable(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return false; + + return ucfg_tdls_is_fw_6g_capable(psoc); +} +#endif + +static int +wlan_cfg80211_tdls_mgmt(struct wlan_objmgr_vdev *vdev, + const uint8_t *peer_mac, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len, int link_id) +{ + struct tdls_action_frame_request mgmt_req; + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + int status; + unsigned long rc; + struct tdls_set_responder_req set_responder; + + status = wlan_cfg80211_tdls_validate_mac_addr(peer_mac); + + if (status) + return status; + + osif_priv = wlan_vdev_get_ospriv(vdev); + + if (!osif_priv || !osif_priv->osif_tdls) { + osif_err("osif priv or tdls priv is NULL"); + return -EINVAL; + } + + tdls_priv = osif_priv->osif_tdls; + + /* make sure doesn't call send_mgmt() while it is pending */ + if (TDLS_VDEV_MAGIC == tdls_priv->mgmt_tx_completion_status) { + osif_err(QDF_MAC_ADDR_FMT " action %d couldn't sent, as one is pending. return EBUSY", + QDF_MAC_ADDR_REF(peer_mac), action_code); + return -EBUSY; + } + + /* Reset TDLS VDEV magic */ + tdls_priv->mgmt_tx_completion_status = TDLS_VDEV_MAGIC; + + + /*prepare the request */ + + /* Validate the management Request */ + mgmt_req.chk_frame.action_code = action_code; + qdf_mem_copy(mgmt_req.chk_frame.peer_mac, peer_mac, QDF_MAC_ADDR_SIZE); + mgmt_req.chk_frame.dialog_token = dialog_token; + mgmt_req.chk_frame.action_code = action_code; + mgmt_req.chk_frame.status_code = status_code; + mgmt_req.chk_frame.len = len; + + mgmt_req.vdev = vdev; + mgmt_req.vdev_id = wlan_vdev_get_id(vdev); + mgmt_req.session_id = mgmt_req.vdev_id; + /* populate management req params */ + qdf_mem_copy(mgmt_req.tdls_mgmt.peer_mac.bytes, + peer_mac, QDF_MAC_ADDR_SIZE); + mgmt_req.tdls_mgmt.dialog = dialog_token; + mgmt_req.tdls_mgmt.frame_type = action_code; + mgmt_req.tdls_mgmt.len = len; + mgmt_req.tdls_mgmt.peer_capability = peer_capability; + mgmt_req.tdls_mgmt.status_code = mgmt_req.chk_frame.status_code; + + mgmt_req.link_active = false; + mgmt_req.link_id = link_id; + /*populate the additional IE's */ + mgmt_req.cmd_buf = buf; + mgmt_req.len = len; + + reinit_completion(&tdls_priv->tdls_mgmt_comp); + status = ucfg_tdls_send_mgmt_frame(&mgmt_req); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("ucfg_tdls_send_mgmt failed err %d", status); + status = -EIO; + tdls_priv->mgmt_tx_completion_status = false; + goto error_mgmt_req; + } + + osif_debug("Wait for tdls_mgmt_comp. Timeout %u ms", + WAIT_TIME_FOR_TDLS_MGMT); + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_mgmt_comp, + msecs_to_jiffies(WAIT_TIME_FOR_TDLS_MGMT)); + + if ((0 == rc) || (QDF_STATUS_SUCCESS != + tdls_priv->mgmt_tx_completion_status)) { + osif_err("%s rc %ld mgmtTxCompletionStatus %u", + !rc ? "Mgmt Tx Completion timed out" : + "Mgmt Tx Completion failed", + rc, tdls_priv->mgmt_tx_completion_status); + + tdls_priv->mgmt_tx_completion_status = false; + status = -EINVAL; + goto error_mgmt_req; + } + + osif_debug("Mgmt Tx Completion status %ld TxCompletion %u", + rc, tdls_priv->mgmt_tx_completion_status); + + if (TDLS_SETUP_RESPONSE == action_code || + TDLS_SETUP_CONFIRM == action_code) { + qdf_mem_copy(set_responder.peer_mac, peer_mac, + QDF_MAC_ADDR_SIZE); + set_responder.vdev = vdev; + if (TDLS_SETUP_RESPONSE == action_code) + set_responder.responder = false; + if (TDLS_SETUP_CONFIRM == action_code) + set_responder.responder = true; + ucfg_tdls_responder(&set_responder); + } + +error_mgmt_req: + return status; +} + +int +wlan_cfg80211_tdls_mgmt_mlo(struct hdd_adapter *adapter, const uint8_t *peer, + uint8_t action_code, uint8_t dialog_token, + uint16_t status_code, uint32_t peer_capability, + const uint8_t *buf, size_t len, int link_id) +{ + struct wlan_objmgr_vdev *tdls_link_vdev = NULL; + struct wlan_objmgr_vdev *mlo_vdev = NULL; + struct wlan_objmgr_vdev *vdev; + bool is_mlo_vdev; + bool link_id_vdev = false; + bool dis_req_more = false; + uint8_t i; + int ret = 0; + + vdev = hdd_objmgr_get_vdev_by_user(adapter->deflink, WLAN_OSIF_TDLS_ID); + if (!vdev) + return -EINVAL; + + /* STA should be connected before sending any TDLS frame */ + if (wlan_vdev_is_up(vdev) != QDF_STATUS_SUCCESS) { + osif_err("STA is not connected"); + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + return -EAGAIN; + } + + is_mlo_vdev = wlan_vdev_mlme_is_mlo_vdev(vdev); + if (is_mlo_vdev) { + tdls_link_vdev = + ucfg_tdls_get_tdls_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + if (!tdls_link_vdev) { + if (action_code == TDLS_DISCOVERY_RESPONSE) { + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_OSIF_TDLS_ID); + if (link_id < 0) { + osif_err("link id is invalid"); + return -EINVAL; + } + /* Get the candidate vdev per link id */ + link_id_vdev = true; + vdev = wlan_key_get_link_vdev(adapter, + WLAN_OSIF_TDLS_ID, + link_id); + if (!vdev) { + osif_err("vdev is null"); + return -EINVAL; + } + } else if (action_code == TDLS_DISCOVERY_REQUEST) { + if (ucfg_tdls_discovery_on_going(vdev)) { + osif_err("discovery request is going"); + hdd_objmgr_put_vdev_by_user(vdev, + WLAN_OSIF_TDLS_ID); + return -EAGAIN; + } + dis_req_more = true; + } + } else { + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + vdev = tdls_link_vdev; + } + } + + if (dis_req_more) { + /* it needs to send discovery request on each vdev */ + for (i = 0 ; i < WLAN_UMAC_MLO_MAX_VDEVS; i++) { + mlo_vdev = ucfg_tdls_get_mlo_vdev(vdev, i, + WLAN_OSIF_TDLS_ID); + if (!mlo_vdev) { + osif_err("mlo vdev is NULL"); + continue; + } + ret = wlan_cfg80211_tdls_mgmt(mlo_vdev, peer, + action_code, + dialog_token, status_code, + peer_capability, buf, len, + link_id); + ucfg_tdls_release_mlo_vdev(mlo_vdev, WLAN_OSIF_TDLS_ID); + } + } else { + ret = wlan_cfg80211_tdls_mgmt(vdev, peer, + action_code, dialog_token, + status_code, peer_capability, + buf, len, link_id); + } + + if (vdev && link_id_vdev) + wlan_key_put_link_vdev(vdev, WLAN_OSIF_TDLS_ID); + else if (tdls_link_vdev) + ucfg_tdls_put_tdls_link_vdev(tdls_link_vdev, WLAN_OSIF_TDLS_ID); + else + hdd_objmgr_put_vdev_by_user(vdev, WLAN_OSIF_TDLS_ID); + + return ret; +} + +int wlan_tdls_antenna_switch(struct wlan_objmgr_vdev *vdev, uint32_t mode) +{ + struct vdev_osif_priv *osif_priv; + struct osif_tdls_vdev *tdls_priv; + int ret; + unsigned long rc; + + if (!vdev) { + osif_err("vdev is NULL"); + return -EAGAIN; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv || !osif_priv->osif_tdls) { + osif_err("osif priv or tdls priv is NULL"); + ret = -EINVAL; + goto error; + } + tdls_priv = osif_priv->osif_tdls; + + reinit_completion(&tdls_priv->tdls_antenna_switch_comp); + ret = ucfg_tdls_antenna_switch(vdev, mode); + if (QDF_IS_STATUS_ERROR(ret)) { + osif_err("ucfg_tdls_antenna_switch failed err %d", ret); + ret = -EAGAIN; + goto error; + } + + rc = wait_for_completion_timeout( + &tdls_priv->tdls_antenna_switch_comp, + msecs_to_jiffies(WAIT_TIME_FOR_TDLS_ANTENNA_SWITCH)); + if (!rc) { + osif_err("timeout for tdls antenna switch %ld", rc); + ret = -EAGAIN; + goto error; + } + + ret = tdls_priv->tdls_antenna_switch_status; + osif_debug("tdls antenna switch status:%d", ret); +error: + return ret; +} + +#ifdef TDLS_MGMT_VERSION5 +static void +wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + + cfg80211_tdls_oper_request(osif_vdev->wdev->netdev, + ind->peer_mac, -1, + NL80211_TDLS_DISCOVERY_REQ, + false, GFP_KERNEL); +} + +static void +wlan_cfg80211_tdls_indicate_setup(struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + int link_id = -1; + + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + if (wlan_vdev_mlme_is_mlo_vdev(ind->vdev)) + link_id = wlan_vdev_get_link_id(ind->vdev); + + osif_debug("Indication to request TDLS setup on link id %d", link_id); + cfg80211_tdls_oper_request(osif_vdev->wdev->netdev, + ind->peer_mac, link_id, + NL80211_TDLS_SETUP, false, + GFP_KERNEL); +} + +static void +wlan_cfg80211_tdls_indicate_teardown(struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + + osif_debug("Teardown reason %d", ind->reason); + cfg80211_tdls_oper_request(osif_vdev->wdev->netdev, + ind->peer_mac, -1, NL80211_TDLS_TEARDOWN, + ind->reason, GFP_KERNEL); +} +#else +static void +wlan_cfg80211_tdls_indicate_discovery(struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + + cfg80211_tdls_oper_request(osif_vdev->wdev->netdev, + ind->peer_mac, NL80211_TDLS_DISCOVERY_REQ, + false, GFP_KERNEL); +} + +static void +wlan_cfg80211_tdls_indicate_setup(struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + + osif_debug("Indication to request TDLS setup"); + cfg80211_tdls_oper_request(osif_vdev->wdev->netdev, + ind->peer_mac, NL80211_TDLS_SETUP, false, + GFP_KERNEL); +} + +static void +wlan_cfg80211_tdls_indicate_teardown(struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + + osif_debug("Teardown reason %d", ind->reason); + cfg80211_tdls_oper_request(osif_vdev->wdev->netdev, + ind->peer_mac, NL80211_TDLS_TEARDOWN, + ind->reason, GFP_KERNEL); +} +#endif + +void wlan_cfg80211_tdls_event_callback(void *user_data, + enum tdls_event_type type, + struct tdls_osif_indication *ind) +{ + struct vdev_osif_priv *osif_vdev; + struct osif_tdls_vdev *tdls_priv; + + if (!ind || !ind->vdev) { + osif_err("ind: %pK", ind); + return; + } + osif_vdev = wlan_vdev_get_ospriv(ind->vdev); + + if (!osif_vdev || !osif_vdev->osif_tdls) { + osif_err("osif priv or tdls priv is NULL"); + return; + } + + tdls_priv = osif_vdev->osif_tdls; + + switch (type) { + case TDLS_EVENT_MGMT_TX_ACK_CNF: + tdls_priv->mgmt_tx_completion_status = ind->status; + complete(&tdls_priv->tdls_mgmt_comp); + break; + case TDLS_EVENT_ADD_PEER: + tdls_priv->tdls_add_peer_status = ind->status; + complete(&tdls_priv->tdls_add_peer_comp); + break; + case TDLS_EVENT_DEL_PEER: + complete(&tdls_priv->tdls_del_peer_comp); + break; + case TDLS_EVENT_DISCOVERY_REQ: + wlan_cfg80211_tdls_indicate_discovery(ind); + break; + case TDLS_EVENT_TEARDOWN_REQ: + wlan_cfg80211_tdls_indicate_teardown(ind); + break; + case TDLS_EVENT_SETUP_REQ: + wlan_cfg80211_tdls_indicate_setup(ind); + break; + case TDLS_EVENT_USER_CMD: + tdls_priv->tdls_user_cmd_len = ind->status; + complete(&tdls_priv->tdls_user_cmd_comp); + break; + + case TDLS_EVENT_ANTENNA_SWITCH: + tdls_priv->tdls_antenna_switch_status = ind->status; + complete(&tdls_priv->tdls_antenna_switch_comp); + break; + default: + break; + } +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_ext_req.h b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_ext_req.h new file mode 100644 index 0000000000..a9a4452cef --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_ext_req.h @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_twt_ext_req.h + * + * WLAN Host Device Driver file for TWT (Target Wake Time) support. + * + */ +#ifndef _OSIF_TWT_EXT_REQ_H_ +#define _OSIF_TWT_EXT_REQ_H_ + +#include +#include +#include +#include + +#define TWT_WAKE_INTVL_MULTIPLICATION_FACTOR 1024 +#define TWT_WAKE_DURATION_MULTIPLICATION_FACTOR 256 + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/** + * osif_twt_setup_req() - Process TWT setup operation + * in the received vendor command and send it to firmware + * @vdev: vdev + * @twt_param_attr: nl attributes + * + * sets up TWT setup request from HDD. request is passed + * to TWT core + * + * Handles QCA_WLAN_TWT_SETUP + * + * Return: success on 0, failure on non-zero + */ +int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_sta_teardown_req() - Process TWT sta teardown operation + * in the received vendor command and send it to firmware + * @vdev: vdev + * @twt_param_attr: nl attributes + * + * sets up TWT teardown request from HDD. request is passed + * to TWT core + * + * Handles QCA_WLAN_TWT_TEARDOWN + * + * Return: success on 0, failure on non-zero + */ +int osif_twt_sta_teardown_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_sap_teardown_req() - Process TWT sap teardown operation + * in the received vendor command and send it to firmware + * @vdev: vdev + * @twt_param_attr: nl attributes + * + * sets up TWT teardown request from HDD. request is passed + * to TWT core + * + * Handles QCA_WLAN_TWT_TEARDOWN + * + * Return: success on 0, failure on non-zero + */ +int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_handle_renego_failure() - Handle twt renegotiation failure + * @psoc: pointer to psoc + * @add_dialog_event: event data + * + * Return: none + */ +void +osif_twt_handle_renego_failure(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *add_dialog_event); + +/** + * osif_twt_pause_req() - Process TWT pause operation + * in the received vendor command and send it to firmware + * @vdev: vdev + * @twt_param_attr: nl attributes + * + * sets up TWT pause request from HDD. request is passed + * to TWT core + * + * Handles QCA_WLAN_TWT_SUSPEND + * + * Return: success on 0, failure on non-zero + */ +int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_resume_req() - Process TWT resume operation + * in the received vendor command and send it to firmware + * @vdev: vdev + * @twt_param_attr: nl attributes + * + * sets up TWT resume request from HDD. request is passed + * to TWT core + * + * Handles QCA_WLAN_TWT_RESUME + * + * Return: success on 0, failure on non-zero + */ +int osif_twt_resume_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_nudge_req() - Process TWT nudge operation + * in the received vendor command and send it to firmware + * @vdev: vdev + * @twt_param_attr: nl attributes + * + * sets up TWT nudge request from HDD. request is passed + * to TWT core + * + * Handles QCA_WLAN_TWT_NUDGE + * + * Return: success on 0, failure on non-zero + */ +int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_get_capabilities() - Process TWT get capabilities + * in the received vendor command. + * @vdev: vdev + * + * Handles QCA_WLAN_TWT_GET_CAPABILITIES + * + * Return: 0 on success, negative value on failure + */ +int osif_twt_get_capabilities(struct wlan_objmgr_vdev *vdev); + +/** + * osif_twt_send_get_capabilities_response - TWT pack and send response to + * userspace for get capabilities command + * @psoc: pointer to global psoc + * @vdev: pointer to vdev + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_send_get_capabilities_response(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev); + +/** + * osif_fill_peer_macaddr - find peer from vdev and fill mac address + * @vdev: vdev pointer + * @mac_addr: output buffer to copy mac address + * + * This is the utility function, which finds peer bss info from the vdev + * and fill the output buffer with mac address + * + * Return: errno + */ +int osif_fill_peer_macaddr(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr); + +/** + * osif_twt_get_session_req() - Extract get TWT NL attributes + * @vdev: vdev pointer + * @twt_param_attr: TWT NL attributes coming from the user space + * + * Return: errno + */ +int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_get_session_traffic_stats() - Extract traffic stats NL attributes + * @vdev: vdev pointer + * @twt_param_attr: TWT NL attributes coming from the user space + * + * Return: errno + */ +int osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_get_stats_response() - Post get stats response to user space + * @vdev: vdev pointer + * @params: cp stats event params + * @num_session_stats: number of session stats + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_twt_get_stats_response(struct wlan_objmgr_vdev *vdev, + struct twt_infra_cp_stats_event *params, + uint32_t num_session_stats); + +int osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * osif_twt_set_param() - pdev TWT param send + * @vdev: Pointer to vdev object + * @twt_param_attr: nlattr for TWT access category + * + * Return: QDF Status + */ +int osif_twt_set_param(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr); + +/** + * __osif_twt_work_handler() - TWT work handler + * @vdev: vdev pointer + * + * Return: None + */ +void __osif_twt_work_handler(struct wlan_objmgr_vdev *vdev); + +/** + * osif_twt_work_handler() - TWT work wrapper function + * @data: data pointer + * + * Return: None + */ +void osif_twt_work_handler(void *data); + +/** + * osif_twt_create_work() - TWT create work + * @vdev: vdev pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_twt_create_work(struct wlan_objmgr_vdev *vdev); + +/** + * osif_twt_destroy_work() - TWT destroy work + * @vdev: vdev pointer + * + * Return: QDF_STATUS + */ +QDF_STATUS osif_twt_destroy_work(struct wlan_objmgr_vdev *vdev); +#else +static inline +int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_get_capabilities(struct wlan_objmgr_vdev *vdev) +{ + return 0; +} + +static inline +int osif_twt_sta_teardown_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_resume_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +int osif_twt_set_param(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + return 0; +} + +static inline +void __osif_twt_work_handler(struct wlan_objmgr_vdev *vdev) +{ +} + +static inline +void osif_twt_work_handler(void *data) +{ +} +#endif +#endif /* _OSIF_TWT_EXT_REQ_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_ext_rsp.h b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_ext_rsp.h new file mode 100644 index 0000000000..7069f2544d --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_ext_rsp.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_twt_ext_rsp.h + * + * WLAN Host Device Driver file for TWT (Target Wake Time) support. + * + */ + +#ifndef _OSIF_TWT_EXT_RSP_H_ +#define _OSIF_TWT_EXT_RSP_H_ + +#include + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/** + * osif_twt_setup_complete_cb() - setup complete osif callback + * @psoc: psoc pointer + * @event: setup complete response + * @renego_fail: flag to indicate if renegotiation failure case + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_setup_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event, + bool renego_fail); + +/** + * osif_twt_teardown_complete_cb() - teardown complete osif callback + * @psoc: psoc pointer + * @event: teardown complete response + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_teardown_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event); + +/** + * osif_twt_pause_complete_cb() - pause complete osif callback + * @psoc: psoc pointer + * @event: pause complete response + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_pause_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event); + +/** + * osif_twt_resume_complete_cb() - resume complete osif callback + * @psoc: psoc pointer + * @event: resume complete response + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_resume_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event); + +/** + * osif_twt_nudge_complete_cb() - nudge complete osif callback + * @psoc: psoc pointer + * @event: nudge complete response + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_nudge_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event); + +/** + * osif_twt_notify_complete_cb() - notify complete osif callback + * @psoc: psoc pointer + * @event: notify complete response + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_notify_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event); + +/** + * osif_twt_ack_complete_cb() - ack complete osif callback + * @psoc: psoc pointer + * @params: ack complete response + * @context: context + * + * Return: QDF_STATUS + */ +QDF_STATUS +osif_twt_ack_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *params, + void *context); + +#else +static inline QDF_STATUS +osif_twt_setup_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event, + bool renego_fail) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +osif_twt_teardown_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +osif_twt_pause_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +osif_twt_resume_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +osif_twt_nudge_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +osif_twt_notify_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event) +{ + return QDF_STATUS_SUCCESS; +} + +static inline QDF_STATUS +osif_twt_ack_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *params, + void *context) +{ + return QDF_STATUS_SUCCESS; +} + +#endif +#endif /* _OSIF_TWT_RSP_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_internal.h b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_internal.h new file mode 100644 index 0000000000..a763774cec --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/inc/osif_twt_internal.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_twt_internal.h + * + * WLAN Host Device Driver file for TWT (Target Wake Time) support. + * + */ + +#ifndef _OSIF_TWT_INTERNAL_H_ +#define _OSIF_TWT_INTERNAL_H_ + +#if defined(WLAN_SUPPORT_TWT) && defined(WLAN_TWT_CONV_SUPPORTED) +/** + * struct twt_conc_context: TWT concurrency args + * @psoc: pointer to psoc + */ +struct twt_conc_context { + struct wlan_objmgr_psoc *psoc; +}; + +/** + * osif_twt_send_requestor_enable_cmd() - Send TWT requestor enable command to + * target + * @psoc: pointer to global psoc structure + * @pdev_id: pdev id + * + * Return: errno + */ +int osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id); + +/** + * osif_twt_send_responder_enable_cmd() - Send TWT responder enable command to + * target + * @psoc: pointer to global psoc structure + * @pdev_id: pdev id + * + * Return: errno + */ +int osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id); + +/** + * osif_twt_send_requestor_disable_cmd() - Send TWT requestor disable command + * to target + * @psoc: pointer to global psoc structure + * @pdev_id: pdev id + * @reason: disable reason code + * + * Return: errno + */ +int osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t reason); + +/** + * osif_twt_send_responder_disable_cmd() - Send TWT responder disable command + * to target + * @psoc: pointer to global psoc structure + * @pdev_id: pdev id + * @reason: disable reason code + * + * Return: errno + */ +int osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t reason); + +/** + * osif_twt_concurrency_update_handler() - Handle TWT concurrency scenario + * @psoc: pointer to global psoc structure + * @pdev: pointer to pdev + * + * Return: none + */ +void osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * osif_twt_teardown_in_ps_disable() - Send TWT teardown if power save + * mode is disabled + * + * @psoc: pointer to global psoc structure + * @mac_addr: Peer MAC Address + * @vdev_id: vdev_id + */ +void osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id); +#else +static inline +int osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t reason) +{ + return 0; +} + +static inline +int osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id) +{ + return 0; +} + +static inline +int osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id) +{ + return 0; +} + +static inline +void osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ +} +static inline +void osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id) +{ +} +#endif +#endif /* _OSIF_TWT_INTERNAL_H_ */ + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_req.c b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_req.c new file mode 100644 index 0000000000..2f6469f946 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_req.c @@ -0,0 +1,2515 @@ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_twt_ext_req.c + * This file contains twt component's osif API implementation + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlan_cp_stats_mc_ucfg_api.h" +#include "wlan_mlme_ucfg_api.h" +#include "wlan_cp_stats_ucfg_api.h" +#include "osif_vdev_sync.h" + +#define TWT_ACK_COMPLETE_TIMEOUT 1000 + +#define TWT_FLOW_TYPE_ANNOUNCED 0 +#define TWT_FLOW_TYPE_UNANNOUNCED 1 + +#define TWT_SETUP_WAKE_INTVL_MANTISSA_MAX 0xFFFF +#define TWT_SETUP_WAKE_DURATION_MAX 0xFFFF +#define TWT_SETUP_WAKE_INTVL_EXP_MAX 31 +#define TWT_MAX_NEXT_TWT_SIZE 3 +#define TWT_DEL_DIALOG_REQ_MAX_RETRY 10 +#define TWT_TEARDOWN_IN_PS_DISABLE_WAIT_TIME 500 + +static const struct nla_policy +qca_wlan_vendor_twt_add_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST] = {.type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER] = {.type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION] = {.type = NLA_FLAG }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION] = { + .type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF] = {.type = NLA_U64 }, + [QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT] = {.type = NLA_U32 }, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_resume_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT] = {.type = NLA_U32 }, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_nudge_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID] = {.type = NLA_U8 }, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE] = {.type = NLA_U32 }, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR] = VENDOR_NLA_POLICY_MAC_ADDR, + [QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET] = {.type = NLA_S32}, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_set_param_policy[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE] = {.type = NLA_U8 }, +}; + +static const struct nla_policy +qca_wlan_vendor_twt_stats_dialog_policy[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1] = { + [QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID] = {.type = NLA_U8 }, +}; + +static int osif_is_twt_command_allowed(struct wlan_objmgr_vdev *vdev, + uint8_t vdev_id, + struct wlan_objmgr_psoc *psoc) +{ + enum QDF_OPMODE mode = wlan_vdev_mlme_get_opmode(vdev); + + if (mode != QDF_STA_MODE && + mode != QDF_P2P_CLIENT_MODE) + return -EOPNOTSUPP; + + if (!wlan_cm_is_vdev_connected(vdev)) { + osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode); + return -EAGAIN; + } + + if (wlan_cm_host_roam_in_progress(psoc, vdev_id)) + return -EBUSY; + + if (wlan_get_vdev_status(vdev)) { + osif_err_rl("Scan in progress"); + return -EBUSY; + } + + return 0; +} + +static bool osif_twt_setup_conc_allowed(struct wlan_objmgr_psoc *psoc, + uint8_t vdev_id) +{ + return policy_mgr_current_concurrency_is_mcc(psoc) || + policy_mgr_is_scc_with_this_vdev_id(psoc, vdev_id); +} + +/** + * osif_twt_setup_req_type_to_cmd() - Converts twt setup request type to twt cmd + * @req_type: twt setup request type + * @twt_cmd: pointer to store twt command + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +osif_twt_setup_req_type_to_cmd(u8 req_type, enum HOST_TWT_COMMAND *twt_cmd) +{ + if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_REQUEST) { + *twt_cmd = HOST_TWT_COMMAND_REQUEST_TWT; + } else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_SUGGEST) { + *twt_cmd = HOST_TWT_COMMAND_SUGGEST_TWT; + } else if (req_type == QCA_WLAN_VENDOR_TWT_SETUP_DEMAND) { + *twt_cmd = HOST_TWT_COMMAND_DEMAND_TWT; + } else { + osif_err_rl("Invalid TWT_SETUP_REQ_TYPE %d", req_type); + return QDF_STATUS_E_INVAL; + } + return QDF_STATUS_SUCCESS; +} + +/** + * osif_twt_parse_add_dialog_attrs() - Get TWT add dialog parameter + * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS + * @tb: nl attributes + * @params: wmi twt add dialog parameters + * + * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + * + * Return: 0 or -EINVAL. + */ +static int +osif_twt_parse_add_dialog_attrs(struct nlattr **tb, + struct twt_add_dialog_param *params) +{ + uint32_t wake_intvl_exp, result; + int cmd_id; + QDF_STATUS qdf_status; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[cmd_id]) { + params->dialog_id = nla_get_u8(tb[cmd_id]); + if (params->dialog_id > TWT_MAX_DIALOG_ID) { + osif_err_rl("Flow id (%u) invalid", params->dialog_id); + return -EINVAL; + } + } else { + params->dialog_id = 0; + osif_debug("TWT_SETUP_FLOW_ID not specified. set to zero"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (!tb[cmd_id]) { + osif_err_rl("TWT_SETUP_WAKE_INTVL_EXP is must"); + return -EINVAL; + } + wake_intvl_exp = nla_get_u8(tb[cmd_id]); + if (wake_intvl_exp > TWT_SETUP_WAKE_INTVL_EXP_MAX) { + osif_err_rl("Invalid wake_intvl_exp %u > %u", + wake_intvl_exp, + TWT_SETUP_WAKE_INTVL_EXP_MAX); + return -EINVAL; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + params->flag_bcast = nla_get_flag(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID; + if (tb[cmd_id]) { + params->dialog_id = nla_get_u8(tb[cmd_id]); + osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_RECOMMENDATION; + if (tb[cmd_id]) { + params->b_twt_recommendation = nla_get_u8(tb[cmd_id]); + osif_debug("TWT_SETUP_BCAST_RECOMM %d", + params->b_twt_recommendation); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_PERSISTENCE; + if (tb[cmd_id]) { + params->b_twt_persistence = nla_get_u8(tb[cmd_id]); + osif_debug("TWT_SETUP_BCAST_PERSIS %d", + params->b_twt_persistence); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_REQ_TYPE; + if (!tb[cmd_id]) { + osif_err_rl("TWT_SETUP_REQ_TYPE is must"); + return -EINVAL; + } + qdf_status = osif_twt_setup_req_type_to_cmd(nla_get_u8(tb[cmd_id]), + ¶ms->twt_cmd); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status_to_os_return(qdf_status); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + params->flag_trigger = nla_get_flag(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (!tb[cmd_id]) { + osif_err_rl("TWT_SETUP_FLOW_TYPE is must"); + return -EINVAL; + } + params->flag_flow_type = nla_get_u8(tb[cmd_id]); + if (params->flag_flow_type != TWT_FLOW_TYPE_ANNOUNCED && + params->flag_flow_type != TWT_FLOW_TYPE_UNANNOUNCED) + return -EINVAL; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + params->flag_protection = nla_get_flag(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME; + if (tb[cmd_id]) + params->sp_offset_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + if (!tb[cmd_id]) { + osif_err_rl("TWT_SETUP_WAKE_DURATION is must"); + return -EINVAL; + } + params->wake_dura_us = TWT_WAKE_DURATION_MULTIPLICATION_FACTOR * + nla_get_u32(tb[cmd_id]); + if (params->wake_dura_us > TWT_SETUP_WAKE_DURATION_MAX) { + osif_err_rl("Invalid wake_dura_us %u", + params->wake_dura_us); + return -EINVAL; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_DURATION; + if (tb[cmd_id]) + params->min_wake_dura_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_DURATION; + if (tb[cmd_id]) + params->max_wake_dura_us = nla_get_u32(tb[cmd_id]); + + if (params->min_wake_dura_us > params->max_wake_dura_us) { + osif_err_rl("Invalid wake duration range min:%d max:%d. Reset to zero", + params->min_wake_dura_us, params->max_wake_dura_us); + params->min_wake_dura_us = 0; + params->max_wake_dura_us = 0; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (!tb[cmd_id]) { + osif_err_rl("SETUP_WAKE_INTVL_MANTISSA is must"); + return -EINVAL; + } + params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]); + + /* + * If mantissa in microsecond is present then take precedence over + * mantissa in TU. And send mantissa in microsecond to firmware. + */ + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA; + if (tb[cmd_id]) + params->wake_intvl_mantis = nla_get_u32(tb[cmd_id]); + + if (params->wake_intvl_mantis > + TWT_SETUP_WAKE_INTVL_MANTISSA_MAX) { + osif_err_rl("Invalid wake_intvl_mantis %u", + params->wake_intvl_mantis); + return -EINVAL; + } + + if (wake_intvl_exp && params->wake_intvl_mantis) { + result = 2 << (wake_intvl_exp - 1); + if (result > + (UINT_MAX / params->wake_intvl_mantis)) { + osif_err_rl("Invalid exp %d mantissa %d", + wake_intvl_exp, + params->wake_intvl_mantis); + return -EINVAL; + } + params->wake_intvl_us = + params->wake_intvl_mantis * result; + } else { + params->wake_intvl_us = params->wake_intvl_mantis; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MIN_WAKE_INTVL; + if (tb[cmd_id]) + params->min_wake_intvl_us = nla_get_u32(tb[cmd_id]); + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX_WAKE_INTVL; + if (tb[cmd_id]) + params->max_wake_intvl_us = nla_get_u32(tb[cmd_id]); + + if (params->min_wake_intvl_us > params->max_wake_intvl_us) { + osif_err_rl("Invalid wake intvl range min:%d max:%d. Reset to zero", + params->min_wake_intvl_us, + params->max_wake_intvl_us); + params->min_wake_dura_us = 0; + params->max_wake_dura_us = 0; + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (tb[cmd_id]) + params->wake_time_tsf = nla_get_u64(tb[cmd_id]); + else + params->wake_time_tsf = 0; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE_TIMEOUT; + if (tb[cmd_id]) + params->announce_timeout_us = nla_get_u32(tb[cmd_id]); + else + params->announce_timeout_us = 0; + + osif_debug("twt: dialog_id %d, vdev %d, wake intvl_us %d, min %d, max %d, mantis %d", + params->dialog_id, params->vdev_id, params->wake_intvl_us, + params->min_wake_intvl_us, params->max_wake_intvl_us, + params->wake_intvl_mantis); + + osif_debug("twt: wake dura %d, min %d, max %d, sp_offset %d, cmd %d", + params->wake_dura_us, params->min_wake_dura_us, + params->max_wake_dura_us, params->sp_offset_us, + params->twt_cmd); + osif_debug("twt: bcast %d, trigger %d, flow_type %d, prot %d wake_tsf 0x%llx", + params->flag_bcast, params->flag_trigger, + params->flag_flow_type, + params->flag_protection, + params->wake_time_tsf); + osif_debug("twt: peer mac_addr " + QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params->peer_macaddr.bytes)); + osif_debug("twt: announce timeout(in us) %u", + params->announce_timeout_us); + return 0; +} + +/** + * osif_twt_parse_del_dialog_attrs() - Parse TWT del dialog parameters + * values from QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS + * @tb: nl attributes + * @params: twt del dialog parameters + * + * Handles QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + * + * Return: 0 or -EINVAL. + */ +static int +osif_twt_parse_del_dialog_attrs(struct nlattr **tb, + struct twt_del_dialog_param *params) +{ + int cmd_id; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[cmd_id]) { + params->dialog_id = nla_get_u8(tb[cmd_id]); + } else { + params->dialog_id = 0; + osif_debug("TWT_TERMINATE_FLOW_ID not specified. set to zero"); + } + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST_ID; + if (tb[cmd_id]) { + params->dialog_id = nla_get_u8(tb[cmd_id]); + osif_debug("TWT_SETUP_BCAST_ID %d", params->dialog_id); + } + + osif_debug("twt: dialog_id %d vdev %d peer mac_addr "QDF_MAC_ADDR_FMT, + params->dialog_id, params->vdev_id, + QDF_MAC_ADDR_REF(params->peer_macaddr.bytes)); + + return 0; +} + +int osif_fill_peer_macaddr(struct wlan_objmgr_vdev *vdev, uint8_t *mac_addr) +{ + struct wlan_objmgr_peer *peer; + + peer = wlan_objmgr_vdev_try_get_bsspeer(vdev, WLAN_TWT_ID); + if (!peer) { + osif_err("peer is null"); + return -EAGAIN; + } + wlan_peer_obj_lock(peer); + qdf_mem_copy(mac_addr, wlan_peer_get_macaddr(peer), QDF_MAC_ADDR_SIZE); + wlan_peer_obj_unlock(peer); + + wlan_objmgr_peer_release_ref(peer, WLAN_TWT_ID); + return 0; +} + +/** + * osif_twt_ack_wait_response: TWT wait for ack event if it's supported + * @psoc: psoc context + * @request: OSIF request cookie + * @twt_cmd: TWT command for which ack event come + * + * Return: QDF_STATUS + */ +static QDF_STATUS +osif_twt_ack_wait_response(struct wlan_objmgr_psoc *psoc, + struct osif_request *request, int twt_cmd) +{ + struct twt_ack_context *ack_priv; + int ret = 0; + bool twt_ack_cap; + + ucfg_twt_get_twt_ack_supported(psoc, &twt_ack_cap); + + if (!twt_ack_cap) { + osif_err("TWT ack is not supported. No need to wait"); + return QDF_STATUS_SUCCESS; + } + + ack_priv = osif_request_priv(request); + ack_priv->twt_cmd_ack = twt_cmd; + + ret = osif_request_wait_for_response(request); + if (ret) { + osif_err("TWT ack response timed out"); + return QDF_STATUS_E_TIMEOUT; + } + + osif_debug("TWT ack info: vdev_id %d dialog_id %d twt_cmd %d status %d peer_macaddr " + QDF_MAC_ADDR_FMT, ack_priv->vdev_id, ack_priv->dialog_id, + ack_priv->twt_cmd_ack, ack_priv->status, + QDF_MAC_ADDR_REF(ack_priv->peer_macaddr.bytes)); + + return QDF_STATUS_SUCCESS; +} + +static void +osif_send_twt_delete_cmd(struct wlan_objmgr_vdev *vdev, + struct qdf_mac_addr *peer_mac, uint8_t dialog_id, + bool is_ps_disabled) +{ + uint32_t twt_next_action = HOST_TWT_SEND_DELETE_CMD; + + ucfg_twt_set_work_params(vdev, peer_mac, dialog_id, is_ps_disabled, + twt_next_action); + qdf_sched_work(0, &vdev->twt_work); +} + +static int +osif_send_twt_setup_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_param *twt_params) +{ + QDF_STATUS status; + int twt_cmd, ret = 0; + struct osif_request *request; + struct twt_ack_context *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + + context = osif_request_cookie(request); + + status = ucfg_twt_setup_req(psoc, twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + osif_err("Failed to send add dialog command"); + goto cleanup; + } + + twt_cmd = HOST_TWT_ADD_DIALOG_CMDID; + status = osif_twt_ack_wait_response(psoc, request, twt_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + /* + * If the TWT ack event comes after the timeout or + * if the event is not received from the firmware, then + * initialize the context (reset the active command), + * otherwise future commands shall be blocked. + */ + ucfg_twt_init_context(psoc, &twt_params->peer_macaddr, + twt_params->dialog_id); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status) { + osif_err("Received TWT ack error: %d. Reset twt command", + ack_priv->status); + + if (ucfg_twt_is_setup_done(psoc, + &twt_params->peer_macaddr, + twt_params->dialog_id)) { + /* If TWT setup is already done then this is + * renegotiation failure scenario. + * Terminate TWT session on renegotiation failure. + */ + osif_debug("setup_done set, renego failure"); + osif_send_twt_delete_cmd(vdev, + &twt_params->peer_macaddr, + twt_params->dialog_id, false); + } else { + ucfg_twt_init_context(psoc, &twt_params->peer_macaddr, + twt_params->dialog_id); + } + + switch (ack_priv->status) { + case HOST_ADD_TWT_STATUS_INVALID_PARAM: + case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR: + case HOST_ADD_TWT_STATUS_USED_DIALOG_ID: + ret = -EINVAL; + break; + case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS: + case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS: + case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS: + case HOST_ADD_TWT_STATUS_LINK_SWITCH_IN_PROGRESS: + case HOST_ADD_TWT_STATUS_UNSUPPORTED_MODE_MLMR: + ret = -EBUSY; + break; + case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED: + ret = -EOPNOTSUPP; + break; + case HOST_ADD_TWT_STATUS_NOT_READY: + ret = -EAGAIN; + break; + case HOST_ADD_TWT_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + default: + ret = -EINVAL; + break; + } + } + +cleanup: + osif_request_put(request); + return ret; +} + +/** + * osif_send_twt_pause_req() - Send TWT pause dialog command to target + * @vdev: vdev + * @psoc: psoc + * @twt_params: Pointer to pause dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static int +osif_send_twt_pause_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_cmd_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_context *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + + context = osif_request_cookie(request); + + status = ucfg_twt_pause_req(psoc, twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send pause dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = HOST_TWT_PAUSE_DIALOG_CMDID; + status = osif_twt_ack_wait_response(psoc, request, twt_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status != HOST_TWT_PAUSE_STATUS_OK) { + osif_err("Received TWT ack error:%d. Reset twt command", + ack_priv->status); + + switch (ack_priv->status) { + case HOST_TWT_PAUSE_STATUS_INVALID_PARAM: + case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED: + case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST: + ret = -EAGAIN; + break; + case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case HOST_TWT_PAUSE_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS: + case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS: + case HOST_TWT_PAUSE_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + default: + ret = -EAGAIN; + break; + } + } + +cleanup: + osif_request_put(request); + return ret; +} + +static int +osif_send_sta_twt_teardown_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param *twt_params) +{ + QDF_STATUS status; + int twt_cmd, ret = 0; + struct osif_request *request; + struct twt_ack_context *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + + context = osif_request_cookie(request); + + status = ucfg_twt_teardown_req(psoc, twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + osif_err("Failed to send del dialog command"); + goto cleanup; + } + + twt_cmd = HOST_TWT_DEL_DIALOG_CMDID; + + status = osif_twt_ack_wait_response(psoc, request, twt_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + ucfg_twt_reset_active_command(psoc, &twt_params->peer_macaddr, + twt_params->dialog_id); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status != HOST_TWT_DEL_STATUS_OK) { + osif_err("Received TWT ack error:%d. Reset twt command", + ack_priv->status); + + switch (ack_priv->status) { + case HOST_TWT_DEL_STATUS_INVALID_PARAM: + case HOST_TWT_DEL_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case HOST_TWT_DEL_STATUS_DIALOG_ID_NOT_EXIST: + ret = -EAGAIN; + break; + case HOST_TWT_DEL_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case HOST_TWT_DEL_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case HOST_TWT_DEL_STATUS_ROAMING: + case HOST_TWT_DEL_STATUS_CHAN_SW_IN_PROGRESS: + case HOST_TWT_DEL_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + case HOST_TWT_DEL_STATUS_CONCURRENCY: + ret = -EAGAIN; + break; + default: + ret = -EAGAIN; + break; + } + } + +cleanup: + osif_request_put(request); + return ret; +} + +/** + * osif_send_twt_resume_req() - Send TWT resume dialog command to target + * @vdev: vdev + * @psoc: psoc + * @twt_params: Pointer to resume dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static int +osif_send_twt_resume_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_cmd_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_context *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + + context = osif_request_cookie(request); + + status = ucfg_twt_resume_req(psoc, twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send resume dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = HOST_TWT_RESUME_DIALOG_CMDID; + status = osif_twt_ack_wait_response(psoc, request, twt_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status != HOST_TWT_RESUME_STATUS_OK) { + osif_err("Received TWT ack error:%d. Reset twt command", + ack_priv->status); + + switch (ack_priv->status) { + case HOST_TWT_RESUME_STATUS_INVALID_PARAM: + case HOST_TWT_RESUME_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case HOST_TWT_RESUME_STATUS_DIALOG_ID_NOT_EXIST: + case HOST_TWT_RESUME_STATUS_NOT_PAUSED: + ret = -EAGAIN; + break; + case HOST_TWT_RESUME_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case HOST_TWT_RESUME_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case HOST_TWT_RESUME_STATUS_CHAN_SW_IN_PROGRESS: + case HOST_TWT_RESUME_STATUS_ROAM_IN_PROGRESS: + case HOST_TWT_RESUME_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + default: + ret = -EINVAL; + break; + } + } + +cleanup: + osif_request_put(request); + return ret; +} + +/** + * osif_send_twt_nudge_req() - Send TWT nudge dialog command to target + * @vdev: vdev + * @psoc: psoc + * @twt_params: Pointer to nudge dialog cmd params structure + * + * Return: 0 on success, negative value on failure + */ +static int +osif_send_twt_nudge_req(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_cmd_param *twt_params) +{ + QDF_STATUS status; + int ret = 0, twt_cmd; + struct osif_request *request; + struct twt_ack_context *ack_priv; + void *context; + static const struct osif_request_params params = { + .priv_size = sizeof(*ack_priv), + .timeout_ms = TWT_ACK_COMPLETE_TIMEOUT, + }; + + request = osif_request_alloc(¶ms); + if (!request) { + osif_err("Request allocation failure"); + return -ENOMEM; + } + + context = osif_request_cookie(request); + + status = ucfg_twt_nudge_req(psoc, twt_params, context); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send nudge dialog command"); + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + twt_cmd = HOST_TWT_NUDGE_DIALOG_CMDID; + + status = osif_twt_ack_wait_response(psoc, request, twt_cmd); + if (QDF_IS_STATUS_ERROR(status)) { + ret = qdf_status_to_os_return(status); + goto cleanup; + } + + ack_priv = osif_request_priv(request); + if (ack_priv->status != HOST_TWT_NUDGE_STATUS_OK) { + osif_err("Received TWT ack error:%d. Reset twt command", + ack_priv->status); + + switch (ack_priv->status) { + case HOST_TWT_NUDGE_STATUS_INVALID_PARAM: + case HOST_TWT_NUDGE_STATUS_UNKNOWN_ERROR: + ret = -EINVAL; + break; + case HOST_TWT_NUDGE_STATUS_DIALOG_ID_NOT_EXIST: + ret = -EAGAIN; + break; + case HOST_TWT_NUDGE_STATUS_DIALOG_ID_BUSY: + ret = -EINPROGRESS; + break; + case HOST_TWT_NUDGE_STATUS_NO_RESOURCE: + ret = -ENOMEM; + break; + case HOST_TWT_NUDGE_STATUS_CHAN_SW_IN_PROGRESS: + case HOST_TWT_NUDGE_STATUS_ROAM_IN_PROGRESS: + case HOST_TWT_NUDGE_STATUS_SCAN_IN_PROGRESS: + ret = -EBUSY; + break; + default: + ret = -EINVAL; + break; + } + } + +cleanup: + osif_request_put(request); + return ret; +} + +int osif_twt_send_requestor_enable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id) +{ + struct twt_enable_param req = {0}; + + req.pdev_id = pdev_id; + req.ext_conf_present = true; + + return osif_twt_requestor_enable(psoc, &req); +} + +int osif_twt_send_responder_enable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id) +{ + struct twt_enable_param req = {0}; + + req.pdev_id = pdev_id; + req.ext_conf_present = true; + + return osif_twt_responder_enable(psoc, &req); +} + +int osif_twt_send_requestor_disable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t reason) +{ + struct twt_disable_param req = {0}; + + req.pdev_id = pdev_id; + req.ext_conf_present = true; + req.dis_reason_code = reason; + + return osif_twt_requestor_disable(psoc, &req); +} + +int osif_twt_send_responder_disable_cmd(struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, uint32_t reason) +{ + struct twt_disable_param req = {0}; + + req.pdev_id = pdev_id; + req.ext_conf_present = true; + req.dis_reason_code = reason; + + return osif_twt_responder_disable(psoc, &req); +} + +void osif_twt_teardown_in_ps_disable(struct wlan_objmgr_psoc *psoc, + struct qdf_mac_addr *mac_addr, + uint8_t vdev_id) +{ + struct twt_del_dialog_param params = {0}; + int ret; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, vdev_id, WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is NULL"); + return; + } + + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + params.vdev_id = vdev_id; + qdf_copy_macaddr(¶ms.peer_macaddr, mac_addr); + + if (ucfg_twt_is_setup_done(psoc, mac_addr, params.dialog_id)) { + osif_debug("vdev%d: Terminate existing TWT session %d due to ps disable", + params.vdev_id, params.dialog_id); + ret = osif_send_sta_twt_teardown_req(vdev, psoc, ¶ms); + if (ret) { + osif_debug("TWT teardown is failed on vdev: %d", + vdev_id); + osif_send_twt_delete_cmd(vdev, mac_addr, + params.dialog_id, true); + } + } + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); +} + +int osif_twt_get_capabilities(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE mode; + QDF_STATUS status; + uint8_t vdev_id; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + vdev_id = wlan_vdev_get_id(vdev); + mode = wlan_vdev_mlme_get_opmode(vdev); + if (mode != QDF_STA_MODE && mode != QDF_P2P_CLIENT_MODE) + return -EOPNOTSUPP; + + if (!wlan_cm_is_vdev_connected(vdev)) { + osif_err_rl("Not associated!, vdev %d mode %d", vdev_id, mode); + return -EAGAIN; + } + + if (wlan_cm_host_roam_in_progress(psoc, vdev_id)) + return -EBUSY; + + status = osif_twt_send_get_capabilities_response(psoc, vdev); + if (QDF_IS_STATUS_ERROR(status)) + osif_err_rl("TWT: Get capabilities failed"); + + return qdf_status_to_os_return(status); +} + +int osif_twt_setup_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + int ret = 0; + uint8_t vdev_id, pdev_id; + struct twt_add_dialog_param params = {0}; + uint32_t congestion_timeout = 0, reason; + uint8_t peer_cap; + QDF_STATUS qdf_status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + + ret = wlan_cfg80211_nla_parse_nested(tb2, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes); + if (ret) + return ret; + + params.vdev_id = vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + + ret = osif_twt_parse_add_dialog_attrs(tb2, ¶ms); + if (ret) + return ret; + + qdf_status = ucfg_twt_get_peer_capabilities(psoc, ¶ms.peer_macaddr, + &peer_cap); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return -EINVAL; + + if (params.flag_bcast && !(peer_cap & WLAN_TWT_CAPA_BROADCAST)) { + osif_err_rl("TWT setup reject: TWT Broadcast not supported"); + return -EOPNOTSUPP; + } + + if (!params.flag_bcast && !(peer_cap & WLAN_TWT_CAPA_RESPONDER)) { + osif_err_rl("TWT setup reject: TWT responder not supported"); + return -EOPNOTSUPP; + } + + ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc); + if (ret) + return ret; + + if (osif_twt_setup_conc_allowed(psoc, vdev_id)) { + osif_err_rl("TWT setup reject: SCC or MCC concurrency exists"); + return -EAGAIN; + } + + ucfg_twt_cfg_get_congestion_timeout(psoc, &congestion_timeout); + + if (congestion_timeout) { + reason = HOST_TWT_DISABLE_REASON_CHANGE_CONGESTION_TIMEOUT; + ret = osif_twt_send_requestor_disable_cmd(psoc, pdev_id, + reason); + if (ret) { + osif_err("Failed to disable TWT"); + return ret; + } + } + + ucfg_twt_cfg_set_congestion_timeout(psoc, 0); + + ret = osif_twt_send_requestor_enable_cmd(psoc, pdev_id); + if (ret) { + osif_err("Failed to Enable TWT"); + return ret; + } + + return osif_send_twt_setup_req(vdev, psoc, ¶ms); +} + +/** + * osif_twt_handle_renego_failure() - Upon re-nego failure send TWT teardown + * @psoc: Pointer to psoc object + * @event: Pointer to Add dialog complete event structure + * + * Upon re-negotiation failure, this function constructs TWT teardown + * message to the target. + * + * Return: None + */ +void +osif_twt_handle_renego_failure(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + uint8_t pdev_id; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id; + + if (!event) + return; + + vdev_id = event->params.vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, + WLAN_TWT_ID); + if (pdev_id == WLAN_INVALID_PDEV_ID) { + osif_err("Invalid pdev id"); + return; + } + + pdev = wlan_objmgr_get_pdev_by_id(psoc, pdev_id, WLAN_TWT_ID); + if (!pdev) { + osif_err("Invalid pdev"); + return; + } + + vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, vdev_id, + WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev object is NULL"); + goto end; + } + + osif_send_twt_delete_cmd(vdev, &event->params.peer_macaddr, + event->params.dialog_id, false); + + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + +end: + wlan_objmgr_pdev_release_ref(pdev, WLAN_TWT_ID); +} + +int osif_twt_sap_teardown_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + int id, id1, ret = 0; + uint8_t vdev_id; + struct twt_del_dialog_param params = {0}; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + params.vdev_id = vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (tb[id] && tb[id1]) { + params.dialog_id = nla_get_u8(tb[id]); + nla_memcpy(params.peer_macaddr.bytes, tb[id1], + QDF_MAC_ADDR_SIZE); + } else if (!tb[id] && !tb[id1]) { + struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT; + + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + qdf_copy_macaddr(¶ms.peer_macaddr, &bcast_addr); + } else { + osif_err_rl("get_params dialog_id or mac_addr is missing"); + return -EINVAL; + } + + if (!params.dialog_id) + params.dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + + if (params.dialog_id != TWT_ALL_SESSIONS_DIALOG_ID && + qdf_is_macaddr_broadcast(¶ms.peer_macaddr)) { + osif_err("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d", + TWT_ALL_SESSIONS_DIALOG_ID, params.dialog_id); + return -EINVAL; + } + + osif_debug("vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, params.vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr.bytes)); + + status = ucfg_twt_teardown_req(psoc, ¶ms, NULL); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to send del dialog command"); + ret = qdf_status_to_os_return(status); + } + + return ret; +} + +int osif_twt_sta_teardown_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb2[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + int ret = 0; + uint8_t vdev_id, pdev_id; + struct twt_del_dialog_param params = {0}; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + + if (!wlan_cm_is_vdev_connected(vdev)) { + osif_err_rl("Not associated!, vdev %d", vdev_id); + /* + * Return success, since STA is not associated and there is + * no TWT session. + */ + return 0; + } + + if (wlan_cm_host_roam_in_progress(psoc, vdev_id)) + return -EBUSY; + + if (wlan_get_vdev_status(vdev)) { + osif_err_rl("Scan in progress"); + return -EBUSY; + } + + ret = wlan_cfg80211_nla_parse_nested(tb2, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes); + if (ret) + return ret; + + params.vdev_id = vdev_id; + pdev_id = wlan_get_pdev_id_from_vdev_id(psoc, vdev_id, WLAN_TWT_ID); + + ret = osif_twt_parse_del_dialog_attrs(tb2, ¶ms); + if (ret) + return ret; + + return osif_send_sta_twt_teardown_req(vdev, psoc, ¶ms); +} + +static void +osif_twt_concurrency_update_on_scc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = object; + struct twt_conc_context *twt_arg = arg; + QDF_STATUS status; + uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + uint32_t reason; + + if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + osif_debug("Concurrency exist on SAP vdev"); + reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_SCC; + status = osif_twt_send_responder_disable_cmd(twt_arg->psoc, + pdev_id, reason); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("TWT responder disable cmd to fw failed"); + return; + } + ucfg_twt_update_beacon_template(); + } + + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + osif_debug("Concurrency exist on STA vdev"); + reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_SCC; + status = osif_twt_send_requestor_disable_cmd(twt_arg->psoc, + pdev_id, reason); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("TWT requestor disable cmd to fw failed"); + return; + } + } +} + +static void +osif_twt_concurrency_update_on_mcc(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = object; + struct twt_conc_context *twt_arg = arg; + QDF_STATUS status; + uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + uint32_t reason; + uint8_t vdev_id; + struct wlan_objmgr_psoc *psoc; + + vdev_id = wlan_vdev_get_id(vdev); + psoc = wlan_pdev_get_psoc(pdev); + + if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + if (policy_mgr_is_vdev_ll_lt_sap(psoc, vdev_id)) + return; + + osif_debug("Concurrency exist on SAP vdev"); + reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_MCC; + status = osif_twt_send_responder_disable_cmd(twt_arg->psoc, + pdev_id, reason); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("TWT responder disable cmd to fw failed"); + return; + } + ucfg_twt_update_beacon_template(); + } + + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + osif_debug("Concurrency exist on STA vdev"); + reason = HOST_TWT_DISABLE_REASON_CONCURRENCY_MCC; + status = osif_twt_send_requestor_disable_cmd(twt_arg->psoc, + pdev_id, reason); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("TWT requestor disable cmd to fw failed"); + return; + } + } +} + +static void +osif_twt_concurrency_update_on_dbs(struct wlan_objmgr_pdev *pdev, + void *object, void *arg) +{ + struct wlan_objmgr_vdev *vdev = object; + struct twt_conc_context *twt_arg = arg; + QDF_STATUS status; + uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + + if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + osif_debug("SAP vdev exist"); + status = osif_twt_send_responder_enable_cmd(twt_arg->psoc, + pdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("TWT responder enable cmd to firmware failed"); + return; + } + ucfg_twt_update_beacon_template(); + } + + if (vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE && + vdev->vdev_mlme.mlme_state == WLAN_VDEV_S_UP) { + osif_debug("STA vdev exist"); + status = osif_twt_send_requestor_enable_cmd(twt_arg->psoc, + pdev_id); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("TWT requestor enable cmd to firmware failed"); + return; + } + } +} + +void osif_twt_concurrency_update_handler(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + uint32_t num_connections, sap_count, sta_count; + QDF_STATUS status; + struct twt_conc_context twt_arg; + uint8_t pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + + num_connections = policy_mgr_get_connection_count(psoc); + sta_count = policy_mgr_mode_specific_connection_count(psoc, + PM_STA_MODE, + NULL); + sap_count = policy_mgr_get_sap_mode_count(psoc, NULL); + + twt_arg.psoc = psoc; + + osif_debug("Total connection %d, sta_count %d, sap_count %d", + num_connections, sta_count, sap_count); + switch (num_connections) { + case 1: + if (sta_count == 1) { + osif_twt_send_requestor_enable_cmd(psoc, pdev_id); + } else if (sap_count == 1) { + osif_twt_send_responder_enable_cmd(psoc, pdev_id); + ucfg_twt_update_beacon_template(); + } + break; + case 2: + if (policy_mgr_current_concurrency_is_scc(psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + pdev, + WLAN_VDEV_OP, + osif_twt_concurrency_update_on_scc, + &twt_arg, 0, + WLAN_TWT_ID); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("2port conc: SAP/STA not in SCC"); + return; + } + } else if (policy_mgr_current_concurrency_is_mcc(psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + pdev, + WLAN_VDEV_OP, + osif_twt_concurrency_update_on_mcc, + &twt_arg, 0, + WLAN_TWT_ID); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("2port conc: SAP/STA not in MCC"); + return; + } + } else if (policy_mgr_is_current_hwmode_dbs(psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + pdev, + WLAN_VDEV_OP, + osif_twt_concurrency_update_on_dbs, + &twt_arg, 0, + WLAN_TWT_ID); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("SAP not in DBS case"); + return; + } + } + break; + case 3: + if (policy_mgr_current_concurrency_is_scc(psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + pdev, + WLAN_VDEV_OP, + osif_twt_concurrency_update_on_scc, + &twt_arg, 0, + WLAN_TWT_ID); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("3port conc: SAP/STA not in SCC"); + return; + } + } else if (policy_mgr_current_concurrency_is_mcc(psoc)) { + status = wlan_objmgr_pdev_iterate_obj_list( + pdev, + WLAN_VDEV_OP, + osif_twt_concurrency_update_on_mcc, + &twt_arg, 0, + WLAN_TWT_ID); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("3port conc: SAP/STA not in MCC"); + return; + } + } + break; + default: + osif_debug("Unexpected number of connections: %d", + num_connections); + break; + } +} + +int osif_twt_pause_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + int ret = 0, id; + uint32_t vdev_id; + struct twt_pause_dialog_cmd_param params = {0}; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc); + if (ret) + return ret; + + ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes); + if (ret) + return ret; + + if (twt_param_attr) { + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) + params.dialog_id = nla_get_u8(tb[id]); + else + osif_debug("TWT: FLOW_ID not specified. set to zero"); + } else { + osif_debug("TWT param not present. flow id set to zero"); + } + + osif_debug("twt_pause: vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr.bytes)); + + return osif_send_twt_pause_req(vdev, psoc, ¶ms); +} + +int osif_twt_resume_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + int ret = 0; + uint32_t vdev_id; + int id, id2; + struct twt_resume_dialog_cmd_param params = {0}; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + + ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc); + if (ret) + return ret; + + ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes); + if (ret) + return ret; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAX, + twt_param_attr, + qca_wlan_vendor_twt_resume_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID; + if (tb[id]) + params.dialog_id = nla_get_u8(tb[id]); + else + osif_debug("TWT_RESUME_FLOW_ID not specified. set to zero"); + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT; + id2 = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT2_TWT; + if (tb[id2]) + params.sp_offset_us = nla_get_u32(tb[id2]); + else if (tb[id]) + params.sp_offset_us = nla_get_u8(tb[id]); + else + params.sp_offset_us = 0; + + id = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_NEXT_TWT_SIZE; + if (tb[id]) { + params.next_twt_size = nla_get_u32(tb[id]); + } else { + osif_err_rl("TWT_RESUME NEXT_TWT_SIZE is must"); + return -EINVAL; + } + if (params.next_twt_size > TWT_MAX_NEXT_TWT_SIZE) + return -EINVAL; + + osif_debug("twt_resume: vdev_id %d dialog_id %d peer mac_addr " + QDF_MAC_ADDR_FMT, vdev_id, params.dialog_id, + QDF_MAC_ADDR_REF(params.peer_macaddr.bytes)); + + return osif_send_twt_resume_req(vdev, psoc, ¶ms); +} + +int osif_twt_nudge_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct wlan_objmgr_psoc *psoc; + int ret = 0, id; + uint32_t vdev_id; + struct twt_nudge_dialog_cmd_param params = {0}; + QDF_STATUS status; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("NULL psoc"); + return -EINVAL; + } + + vdev_id = wlan_vdev_get_id(vdev); + ret = osif_is_twt_command_allowed(vdev, vdev_id, psoc); + if (ret) + return ret; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAX, + twt_param_attr, + qca_wlan_vendor_twt_nudge_dialog_policy); + if (ret) + return ret; + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR; + if (tb[id]) { + nla_memcpy(params.peer_macaddr.bytes, tb[id], + QDF_MAC_ADDR_SIZE); + } else { + ret = osif_fill_peer_macaddr(vdev, params.peer_macaddr.bytes); + if (ret) + return ret; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID; + if (!tb[id]) { + osif_debug("TWT: FLOW_ID not specified"); + return -EINVAL; + } + params.dialog_id = nla_get_u8(tb[id]); + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME; + if (!tb[id]) { + osif_debug("TWT: NEXT_TWT_SIZE not specified"); + return -EINVAL; + } + + params.suspend_duration = nla_get_u32(tb[id]); + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_NEXT_TWT_SIZE; + if (!tb[id]) { + osif_debug("TWT: NEXT_TWT_SIZE not specified"); + return -EINVAL; + } + params.next_twt_size = nla_get_u32(tb[id]); + + id = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_SP_START_OFFSET; + if (tb[id]) { + uint8_t peer_cap = 0; + + status = ucfg_twt_get_peer_capabilities(psoc, + ¶ms.peer_macaddr, + &peer_cap); + if (QDF_IS_STATUS_SUCCESS(status) && + (peer_cap & WLAN_TWT_CAPA_FLEXIBLE)) { + params.sp_start_offset = nla_get_s32(tb[id]); + } + } + + osif_debug("twt_nudge: vdev_id %d dialog_id %d ", params.vdev_id, + params.dialog_id); + osif_debug("twt_nudge: suspend_duration %d next_twt_size %d", + params.suspend_duration, params.next_twt_size); + osif_debug("peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params.peer_macaddr.bytes)); + osif_debug("twt_nudge: sp_start_offset %d", params.sp_start_offset); + + return osif_send_twt_nudge_req(vdev, psoc, ¶ms); +} + +static uint32_t +osif_twt_get_params_resp_len(struct twt_session_stats_info *params) +{ + uint32_t len = nla_total_size(0); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR */ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_ANNOUNCE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA */ + len += nla_total_size(sizeof(u32)); + + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF */ + len += nla_total_size(sizeof(u64)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA */ + len += nla_total_size(sizeof(u32)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE */ + if (params->pm_responder_bit_valid) + len += nla_total_size(sizeof(u8)); + + return len; +} + +static enum qca_wlan_twt_setup_state +osif_get_converted_twt_state(enum wlan_twt_session_state state) +{ + switch (state) { + case WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED: + return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + case WLAN_TWT_SETUP_STATE_ACTIVE: + return QCA_WLAN_TWT_SETUP_STATE_ACTIVE; + case WLAN_TWT_SETUP_STATE_SUSPEND: + return QCA_WLAN_TWT_SETUP_STATE_SUSPEND; + default: + return QCA_WLAN_TWT_SETUP_STATE_NOT_ESTABLISHED; + } +} + +static QDF_STATUS +osif_twt_pack_get_params_resp_nlmsg(struct wlan_objmgr_psoc *psoc, + struct sk_buff *reply_skb, + struct twt_session_stats_info *params, + int num_twt_session) +{ + struct nlattr *config_attr, *nla_params; + enum wlan_twt_session_state state; + enum qca_wlan_twt_setup_state converted_state; + uint64_t tsf_val; + uint32_t wake_duration; + uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu; + int i, attr; + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("TWT: get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_twt_session; i++) { + if (params[i].event_type != HOST_TWT_SESSION_SETUP && + params[i].event_type != HOST_TWT_SESSION_UPDATE) + continue; + + nla_params = nla_nest_start(reply_skb, i); + if (!nla_params) { + osif_err("TWT: get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params[i].peer_mac.bytes)) { + osif_err("TWT: get_params failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[i].peer_mac.bytes)); + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) { + osif_err("TWT: get_params failed to put dialog_id"); + return QDF_STATUS_E_INVAL; + } + + if (params[i].bcast) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put bcast"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].trig) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put Trigger"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].announ) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put Announce"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].protection) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params fail to put Protect"); + return QDF_STATUS_E_INVAL; + } + } + + if (params[i].pm_responder_bit_valid) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESPONDER_PM_MODE; + if (nla_put_u8(reply_skb, attr, + params[i].pm_responder_bit)) { + osif_err("TWT: fail to put pm responder mode"); + return QDF_STATUS_E_INVAL; + } + } + + if (!params[i].info_frame_disabled) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED; + if (nla_put_flag(reply_skb, attr)) { + osif_err("TWT: get_params put Info Enable fail"); + return QDF_STATUS_E_INVAL; + } + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + wake_duration = (params[i].wake_dura_us / + TWT_WAKE_DURATION_MULTIPLICATION_FACTOR); + if (nla_put_u32(reply_skb, attr, wake_duration)) { + osif_err("TWT: get_params failed to put Wake duration"); + return QDF_STATUS_E_INVAL; + } + + wake_intvl_mantis_us = params[i].wake_intvl_us; + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_us)) { + osif_err("TWT: get_params failed to put Wake Interval in us"); + return QDF_STATUS_E_INVAL; + } + + wake_intvl_mantis_tu = params[i].wake_intvl_us / + TWT_WAKE_INTVL_MULTIPLICATION_FACTOR; + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) { + osif_err("TWT: get_params failed to put Wake Interval"); + return QDF_STATUS_E_INVAL; + } + + osif_debug("TWT: Send mantissa_us:%d, mantissa_tu:%d to userspace", + wake_intvl_mantis_us, wake_intvl_mantis_tu); + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (nla_put_u8(reply_skb, attr, 0)) { + osif_err("TWT: get_params put Wake Interval Exp failed"); + return QDF_STATUS_E_INVAL; + } + + tsf_val = ((uint64_t)params[i].sp_tsf_us_hi << 32) | + params[i].sp_tsf_us_lo; + osif_debug("TWT: get_params dialog_id %d TSF = 0x%llx", + params[i].dialog_id, tsf_val); + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (wlan_cfg80211_nla_put_u64(reply_skb, attr, tsf_val)) { + osif_err("TWT: get_params failed to put TSF Value"); + return QDF_STATUS_E_INVAL; + } + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATE; + state = ucfg_twt_get_session_state(psoc, + ¶ms[i].peer_mac, + params[i].dialog_id); + converted_state = osif_get_converted_twt_state(state); + if (nla_put_u32(reply_skb, attr, converted_state)) { + osif_err("TWT: get_params failed to put TWT state"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, nla_params); + } + nla_nest_end(reply_skb, config_attr); + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS +osif_twt_send_get_params_resp(struct wlan_objmgr_vdev *vdev, + struct twt_session_stats_info *params, + int num_twt_session) +{ + struct wlan_objmgr_psoc *psoc; + struct vdev_osif_priv *osif_priv; + struct sk_buff *reply_skb; + uint32_t skb_len = NLMSG_HDRLEN, i; + QDF_STATUS qdf_status; + struct wireless_dev *wdev; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return QDF_STATUS_E_INVAL; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + return QDF_STATUS_E_INVAL; + } + /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */ + skb_len += NLA_HDRLEN; + + /* Length of twt session parameters */ + for (i = 0; i < num_twt_session; i++) { + if (params[i].event_type == HOST_TWT_SESSION_SETUP || + params[i].event_type == HOST_TWT_SESSION_UPDATE) + skb_len += osif_twt_get_params_resp_len(params + i); + } + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy, + skb_len); + if (!reply_skb) { + osif_err("TWT: get_params alloc reply skb failed"); + return QDF_STATUS_E_NOMEM; + } + + qdf_status = osif_twt_pack_get_params_resp_nlmsg(psoc, reply_skb, + params, + num_twt_session); + if (QDF_IS_STATUS_ERROR(qdf_status)) + goto fail; + + if (wlan_cfg80211_vendor_cmd_reply(reply_skb)) + qdf_status = QDF_STATUS_E_INVAL; + + return qdf_status; +fail: + wlan_cfg80211_vendor_free_skb(reply_skb); + return qdf_status; +} + +static QDF_STATUS +osif_twt_get_peer_session_params(struct wlan_objmgr_vdev *vdev, + struct twt_session_stats_info *params) +{ + struct wlan_objmgr_psoc *psoc; + int num_twt_session = 0; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + + psoc = wlan_vdev_get_psoc(vdev); + + if (!psoc) + return qdf_status; + + num_twt_session = ucfg_cp_stats_twt_get_peer_session_params(psoc, + params); + + if (num_twt_session) + qdf_status = osif_twt_send_get_params_resp(vdev, params, + num_twt_session); + + return qdf_status; +} + +static QDF_STATUS +osif_send_inactive_session_reply(struct wlan_objmgr_vdev *vdev, + struct twt_session_stats_info *params) +{ + QDF_STATUS qdf_status; + int num_twt_session = 0; + + params[num_twt_session].event_type = HOST_TWT_SESSION_UPDATE; + num_twt_session++; + + qdf_status = osif_twt_send_get_params_resp(vdev, params, + num_twt_session); + + return qdf_status; +} + +static int +osif_twt_sap_get_session_params(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct wlan_objmgr_psoc *psoc; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + uint16_t num_peer; + struct twt_session_stats_info *params; + int ret, id, id1; + QDF_STATUS qdf_status = QDF_STATUS_E_INVAL; + uint8_t vdev_id; + + ret = wlan_cfg80211_nla_parse_nested( + tb, QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + + if (ret) + return ret; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + num_peer = wlan_vdev_get_peer_count(vdev); + params = qdf_mem_malloc(TWT_PEER_MAX_SESSIONS * num_peer * + sizeof(*params)); + + if (!params) + return -ENOMEM; + + vdev_id = wlan_vdev_get_id(vdev); + params[0].vdev_id = vdev_id; + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + id1 = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + + if (!tb[id] || !tb[id1]) { + osif_err_rl("TWT: get_params dialog_id or mac_addr is missing"); + goto done; + } + + params[0].dialog_id = nla_get_u8(tb[id]); + nla_memcpy(params[0].peer_mac.bytes, tb[id1], QDF_MAC_ADDR_SIZE); + + if (qdf_is_macaddr_broadcast(¶ms[0].peer_mac) && + params[0].dialog_id != TWT_ALL_SESSIONS_DIALOG_ID) { + osif_err_rl("Bcast MAC valid with dlg_id:%d but here dlg_id is:%d", + TWT_ALL_SESSIONS_DIALOG_ID, params[0].dialog_id); + goto done; + } + + if (!params[0].dialog_id) + params[0].dialog_id = TWT_ALL_SESSIONS_DIALOG_ID; + + osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT, + params[0].dialog_id, + QDF_MAC_ADDR_REF(params[0].peer_mac.bytes)); + qdf_status = osif_twt_get_peer_session_params(vdev, params); + +done: + qdf_mem_free(params); + return qdf_status_to_os_return(qdf_status); +} + +static int +osif_twt_sta_get_session_params(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct wlan_objmgr_psoc *psoc; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX + 1]; + struct twt_session_stats_info + params[TWT_PSOC_MAX_SESSIONS] = { {0} }; + int ret, id; + QDF_STATUS qdf_status; + struct qdf_mac_addr bcast_addr = QDF_MAC_ADDR_BCAST_INIT; + struct qdf_mac_addr peer_mac; + uint8_t vdev_id; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAX, + twt_param_attr, + qca_wlan_vendor_twt_add_dialog_policy); + if (ret) + return ret; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + vdev_id = wlan_vdev_get_id(vdev); + params[0].vdev_id = vdev_id; + + /* + * Currently twt_get_params nl cmd is sending only dialog_id(STA), fill + * mac_addr of STA in params and call osif_twt_get_peer_session_params. + * When twt_get_params passes mac_addr and dialog_id of STA/SAP, update + * both mac_addr and dialog_id in params before calling + * osif_twt_get_peer_session_params. dialog_id if not received, + * dialog_id of value 0 will be used as default. + */ + + id = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (tb[id]) + params[0].dialog_id = (uint32_t)nla_get_u8(tb[id]); + else + params[0].dialog_id = 0; + + if (osif_fill_peer_macaddr(vdev, peer_mac.bytes)) + return -EINVAL; + + if (params[0].dialog_id <= TWT_MAX_DIALOG_ID) { + qdf_copy_macaddr(¶ms[0].peer_mac, &peer_mac); + osif_debug("TWT: get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[0].peer_mac.bytes)); + } else { + qdf_copy_macaddr(¶ms[0].peer_mac, &bcast_addr); + } + + if (!ucfg_twt_is_setup_done(psoc, &peer_mac, + params[0].dialog_id)) { + osif_debug("vdev%d: TWT session %d setup incomplete", vdev_id, + params[0].dialog_id); + qdf_status = osif_send_inactive_session_reply(vdev, params); + return qdf_status_to_os_return(qdf_status); + } + + osif_debug("TWT: get_params dialog_id %d and mac_addr "QDF_MAC_ADDR_FMT, + params[0].dialog_id, + QDF_MAC_ADDR_REF(params[0].peer_mac.bytes)); + + qdf_status = osif_twt_get_peer_session_params(vdev, params); + + return qdf_status_to_os_return(qdf_status); +} + +int osif_twt_get_session_req(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + enum QDF_OPMODE device_mode; + + device_mode = wlan_vdev_mlme_get_opmode(vdev); + + switch (device_mode) { + case QDF_STA_MODE: + return osif_twt_sta_get_session_params(vdev, twt_param_attr); + case QDF_SAP_MODE: + return osif_twt_sap_get_session_params(vdev, twt_param_attr); + default: + osif_err_rl("TWT get session params is not supported on %s", + qdf_opmode_str(device_mode)); + } + + return -EOPNOTSUPP; +} + +/** + * osif_twt_request_session_traffic_stats() - Obtains twt session traffic + * statistics and sends response to the user space + * @vdev: vdev + * @dialog_id: dialog id of the twt session + * @peer_mac: Mac address of the peer + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +osif_twt_request_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, uint8_t *peer_mac) +{ + int errno; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct infra_cp_stats_event *event; + + if (!peer_mac) + return status; + event = wlan_cfg80211_mc_twt_get_infra_cp_stats(vdev, dialog_id, + peer_mac, &errno); + + if (!event) + return errno; + + status = osif_twt_get_stats_response(vdev, event->twt_infra_cp_stats, + event->num_twt_infra_cp_stats); + if (QDF_IS_STATUS_ERROR(status)) + osif_err("TWT: Get_traffic_stats failed status: %d", status); + + qdf_mem_free(event->twt_infra_cp_stats); + qdf_mem_free(event); + + return status; +} + +int osif_twt_get_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct wlan_objmgr_psoc *psoc; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1]; + int ret, id; + QDF_STATUS qdf_status; + uint32_t dialog_id; + bool is_stats_tgt_cap_enabled; + struct qdf_mac_addr peer_mac; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX, + twt_param_attr, + qca_wlan_vendor_twt_stats_dialog_policy); + + if (ret) + return ret; + + ucfg_twt_get_twt_stats_enabled(psoc, &is_stats_tgt_cap_enabled); + if (!is_stats_tgt_cap_enabled) { + osif_debug("TWT Stats not supported by target"); + return -EOPNOTSUPP; + } + + if (osif_fill_peer_macaddr(vdev, peer_mac.bytes)) + return -EINVAL; + + if (ucfg_twt_is_command_in_progress(psoc, &peer_mac, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_STATISTICS, + NULL) || + ucfg_twt_is_command_in_progress(psoc, &peer_mac, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_CLEAR_STATISTICS, + NULL)) { + osif_warn("Already TWT statistics or clear statistics exists"); + return -EALREADY; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (tb[id]) + dialog_id = (uint32_t)nla_get_u8(tb[id]); + else + dialog_id = 0; + + osif_debug("get_stats dialog_id %d", dialog_id); + osif_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(peer_mac.bytes)); + + if (!ucfg_twt_is_setup_done(psoc, &peer_mac, dialog_id)) { + osif_debug("TWT session %d setup incomplete", dialog_id); + return -EAGAIN; + } + + ucfg_twt_set_command_in_progress(psoc, &peer_mac, dialog_id, + WLAN_TWT_STATISTICS); + + qdf_status = osif_twt_request_session_traffic_stats(vdev, dialog_id, + peer_mac.bytes); + ucfg_twt_set_command_in_progress(psoc, &peer_mac, + dialog_id, WLAN_TWT_NONE); + + return qdf_status_to_os_return(qdf_status); +} + +int osif_twt_clear_session_traffic_stats(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct wlan_objmgr_psoc *psoc; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX + 1]; + int ret, id; + uint32_t dialog_id; + bool is_stats_tgt_cap_enabled; + QDF_STATUS status; + struct qdf_mac_addr peer_mac; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + ret = wlan_cfg80211_nla_parse_nested(tb, + QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX, + twt_param_attr, + qca_wlan_vendor_twt_stats_dialog_policy); + + if (ret) + return ret; + + ucfg_twt_get_twt_stats_enabled(psoc, &is_stats_tgt_cap_enabled); + if (!is_stats_tgt_cap_enabled) { + osif_debug("TWT Stats not supported by target"); + return -EOPNOTSUPP; + } + + id = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (!tb[id]) { + osif_err_rl("TWT Clear stats - dialog id param is must"); + return -EINVAL; + } + + if (osif_fill_peer_macaddr(vdev, peer_mac.bytes)) + return -EINVAL; + + dialog_id = (uint32_t)nla_get_u8(tb[id]); + osif_debug("dialog_id %d peer mac_addr "QDF_MAC_ADDR_FMT, + dialog_id, QDF_MAC_ADDR_REF(peer_mac.bytes)); + + status = ucfg_twt_check_all_twt_support(psoc, dialog_id); + if (QDF_IS_STATUS_ERROR(status)) { + osif_debug("All TWT sessions not supported by target"); + return -EOPNOTSUPP; + } + + if (ucfg_twt_is_command_in_progress(psoc, &peer_mac, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_STATISTICS, NULL) || + ucfg_twt_is_command_in_progress(psoc, &peer_mac, + TWT_ALL_SESSIONS_DIALOG_ID, + WLAN_TWT_CLEAR_STATISTICS, + NULL)) { + osif_warn("Already TWT statistics or clear statistics exists"); + return -EALREADY; + } + + if (!ucfg_twt_is_setup_done(psoc, &peer_mac, dialog_id)) { + osif_debug("TWT session %d setup incomplete", dialog_id); + return -EAGAIN; + } + + ret = wlan_cfg80211_mc_twt_clear_infra_cp_stats(vdev, dialog_id, + peer_mac.bytes); + + return ret; +} + +/** + * osif_twt_convert_ac_value() - map ac setting to the value to be used in FW. + * @ac_value: ac value to be mapped. + * + * Return: enum twt_traffic_ac + */ +static inline +enum twt_traffic_ac osif_twt_convert_ac_value(enum qca_wlan_ac_type ac_value) +{ + switch (ac_value) { + case QCA_WLAN_AC_BE: + return TWT_AC_BE; + case QCA_WLAN_AC_BK: + return TWT_AC_BK; + case QCA_WLAN_AC_VI: + return TWT_AC_VI; + case QCA_WLAN_AC_VO: + return TWT_AC_VO; + case QCA_WLAN_AC_ALL: + return TWT_AC_MAX; + } + osif_err("invalid enum: %u", ac_value); + return TWT_AC_MAX; +} + +/** + * osif_twt_add_ac_config() - pdev TWT param send + * @vdev: Pointer to vdev object + * @twt_ac: TWT access category + * + * Return: QDF Status + */ +static int osif_twt_add_ac_config(struct wlan_objmgr_vdev *vdev, + enum qca_wlan_ac_type twt_ac) +{ + bool is_responder_en; + int ret = 0; + struct wlan_objmgr_psoc *psoc; + enum QDF_OPMODE device_mode; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) + return -EINVAL; + + device_mode = wlan_vdev_mlme_get_opmode(vdev); + + if (twt_ac < QCA_WLAN_AC_BE || twt_ac > QCA_WLAN_AC_VO) { + osif_err_rl("Invalid AC parameter. Value: %d", twt_ac); + return -EINVAL; + } + + ucfg_twt_cfg_get_responder(psoc, &is_responder_en); + + if (device_mode == QDF_SAP_MODE && is_responder_en) { + ret = ucfg_twt_ac_pdev_param_send(psoc, + osif_twt_convert_ac_value(twt_ac)); + } else { + osif_err_rl("Undesired device mode. Mode: %d and responder: %d", + device_mode, is_responder_en); + return -EINVAL; + } + + return ret; +} + +int osif_twt_set_param(struct wlan_objmgr_vdev *vdev, + struct nlattr *twt_param_attr) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX + 1]; + int ret; + int cmd_id; + enum qca_wlan_ac_type twt_ac; + + ret = wlan_cfg80211_nla_parse_nested + (tb, + QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_MAX, + twt_param_attr, + qca_wlan_vendor_twt_set_param_policy); + if (ret) + return ret; + + cmd_id = QCA_WLAN_VENDOR_ATTR_TWT_SET_PARAM_AP_AC_VALUE; + + if (tb[cmd_id]) { + twt_ac = nla_get_u8(tb[cmd_id]); + osif_debug("TWT_AC_CONFIG_VALUE: %d", twt_ac); + ret = osif_twt_add_ac_config(vdev, twt_ac); + + if (ret) { + osif_err("Fail to set TWT AC parameter, errno %d", + ret); + return ret; + } + } + + return ret; +} + +static void osif_twt_teardown_req_retry(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_param params) +{ + int retries = 1; + int ret; + + while (retries < TWT_DEL_DIALOG_REQ_MAX_RETRY) { + qdf_sleep(TWT_TEARDOWN_IN_PS_DISABLE_WAIT_TIME); + osif_debug("Implicitly TWT teardown req retry count:%d", retries); + ret = osif_send_sta_twt_teardown_req(vdev, psoc, ¶ms); + if (ret != -EBUSY) + break; + retries++; + } + + if (retries >= TWT_DEL_DIALOG_REQ_MAX_RETRY) + osif_debug("TWT Del Dialog req max retries reached"); +} + +void __osif_twt_work_handler(struct wlan_objmgr_vdev *vdev) +{ + struct twt_del_dialog_param params = {0}; + struct twt_work_params twt_work_params = {0}; + struct wlan_objmgr_psoc *psoc; + uint8_t vdev_id; + uint32_t next_action; + int ret; + + psoc = wlan_vdev_get_psoc(vdev); + if (!psoc) { + osif_err("psoc is null"); + return; + } + + vdev_id = wlan_vdev_get_id(vdev); + ucfg_twt_get_work_params(vdev, &twt_work_params, &next_action); + + if (next_action != HOST_TWT_SEND_DELETE_CMD) { + osif_debug("Do not send STA teardown req as TWT renegotiation or power save work is not scheduled"); + return; + } + + qdf_copy_macaddr(¶ms.peer_macaddr, &twt_work_params.peer_macaddr); + params.dialog_id = twt_work_params.dialog_id; + params.vdev_id = vdev_id; + + ret = osif_send_sta_twt_teardown_req(vdev, psoc, ¶ms); + + /* + * In case of FW returns ack_event with status as scan_in_progress or + * Channel switch in progress and TWT teardown happens due to power + * save disable then host will retry the TWT teardown cmd. + */ + if (ret == -EBUSY && twt_work_params.is_ps_disabled) + osif_twt_teardown_req_retry(vdev, psoc, params); +} + +void osif_twt_work_handler(void *data) +{ + struct wlan_objmgr_vdev *vdev = (struct wlan_objmgr_vdev *)data; + struct net_device *net_dev; + struct osif_vdev_sync *vdev_sync; + struct vdev_osif_priv *priv; + int errno; + + if (!vdev) { + osif_err("vdev is null"); + return; + } + + priv = wlan_vdev_get_ospriv(vdev); + if (!priv || !priv->wdev || !priv->wdev->netdev) + return; + + net_dev = priv->wdev->netdev; + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return; + + __osif_twt_work_handler(vdev); + + osif_vdev_sync_op_stop(vdev_sync); +} + +QDF_STATUS osif_twt_create_work(struct wlan_objmgr_vdev *vdev) +{ + qdf_create_work(0, &vdev->twt_work, + osif_twt_work_handler, vdev); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS osif_twt_destroy_work(struct wlan_objmgr_vdev *vdev) +{ + qdf_flush_work(&vdev->twt_work); + qdf_destroy_work(NULL, &vdev->twt_work); + + return QDF_STATUS_SUCCESS; +} diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_rsp.c b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_rsp.c new file mode 100644 index 0000000000..e57cbce774 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_rsp.c @@ -0,0 +1,1590 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_twt_ext_rsp.c + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * osif_twt_get_setup_event_len() - Calculates the length of twt + * setup nl response + * @additional_params_present: if true, then length required for + * fixed and additional parameters is returned. if false, + * then length required for fixed parameters is returned. + * + * Return: Length of twt setup nl response + */ +static +uint32_t osif_twt_get_setup_event_len(bool additional_params_present) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + + /* Length of attribute QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS */ + len += NLA_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + + if (!additional_params_present) + return len; + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE */ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION*/ + len += nla_total_size(sizeof(u32)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA*/ + len += nla_total_size(sizeof(u32)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF*/ + len += nla_total_size(sizeof(u64)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME*/ + len += nla_total_size(sizeof(u32)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED*/ + len += nla_total_size(sizeof(u8)); + /*QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + return len; +} + +/** + * osif_twt_get_event_len() - calculate length of skb + * required for sending twt terminate, pause and resume + * command responses. + * + * Return: length of skb + */ +static uint32_t osif_twt_get_event_len(void) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR*/ + len += nla_total_size(QDF_MAC_ADDR_SIZE); + + return len; +} + +/** + * twt_add_status_to_vendor_twt_status() - convert from + * HOST_ADD_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: HOST_ADD_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to HOST_ADD_TWT_STATUS. + */ +static enum qca_wlan_vendor_twt_status +twt_add_status_to_vendor_twt_status(enum HOST_ADD_TWT_STATUS status) +{ + switch (status) { + case HOST_ADD_TWT_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case HOST_ADD_TWT_STATUS_TWT_NOT_ENABLED: + return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_ENABLED; + case HOST_ADD_TWT_STATUS_USED_DIALOG_ID: + return QCA_WLAN_VENDOR_TWT_STATUS_USED_DIALOG_ID; + case HOST_ADD_TWT_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case HOST_ADD_TWT_STATUS_NOT_READY: + return QCA_WLAN_VENDOR_TWT_STATUS_NOT_READY; + case HOST_ADD_TWT_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case HOST_ADD_TWT_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case HOST_ADD_TWT_STATUS_NO_RESPONSE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESPONSE; + case HOST_ADD_TWT_STATUS_DENIED: + return QCA_WLAN_VENDOR_TWT_STATUS_DENIED; + case HOST_ADD_TWT_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case HOST_ADD_TWT_STATUS_AP_PARAMS_NOT_IN_RANGE: + return QCA_WLAN_VENDOR_TWT_STATUS_PARAMS_NOT_IN_RANGE; + case HOST_ADD_TWT_STATUS_AP_IE_VALIDATION_FAILED: + return QCA_WLAN_VENDOR_TWT_STATUS_IE_INVALID; + case HOST_ADD_TWT_STATUS_ROAM_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS; + case HOST_ADD_TWT_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case HOST_ADD_TWT_STATUS_SCAN_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * twt_del_status_to_vendor_twt_status() - convert from + * HOST_DEL_TWT_STATUS to qca_wlan_vendor_twt_status + * @status: HOST_DEL_TWT_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to HOST_DEL_TWT_STATUS. + */ +static enum qca_wlan_vendor_twt_status +twt_del_status_to_vendor_twt_status(enum HOST_TWT_DEL_STATUS status) +{ + switch (status) { + case HOST_TWT_DEL_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case HOST_TWT_DEL_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case HOST_TWT_DEL_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case HOST_TWT_DEL_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case HOST_TWT_DEL_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case HOST_TWT_DEL_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case HOST_TWT_DEL_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case HOST_TWT_DEL_STATUS_PEER_INIT_TEARDOWN: + return QCA_WLAN_VENDOR_TWT_STATUS_PEER_INITIATED_TERMINATE; + case HOST_TWT_DEL_STATUS_ROAMING: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAM_INITIATED_TERMINATE; + case HOST_TWT_DEL_STATUS_CONCURRENCY: + return QCA_WLAN_VENDOR_TWT_STATUS_SCC_MCC_CONCURRENCY_TERMINATE; + case HOST_TWT_DEL_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case HOST_TWT_DEL_STATUS_SCAN_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS; + case HOST_TWT_DEL_STATUS_PS_DISABLE_TEARDOWN: + return QCA_WLAN_VENDOR_TWT_STATUS_POWER_SAVE_EXIT_TERMINATE; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * twt_resume_status_to_vendor_twt_status() - convert from + * HOST_TWT_RESUME_STATUS to qca_wlan_vendor_twt_status + * @status: HOST_TWT_RESUME_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +twt_resume_status_to_vendor_twt_status(enum HOST_TWT_RESUME_STATUS status) +{ + switch (status) { + case HOST_TWT_RESUME_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case HOST_TWT_RESUME_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case HOST_TWT_RESUME_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case HOST_TWT_RESUME_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case HOST_TWT_RESUME_STATUS_NOT_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_NOT_SUSPENDED; + case HOST_TWT_RESUME_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case HOST_TWT_RESUME_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case HOST_TWT_RESUME_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case HOST_TWT_RESUME_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case HOST_TWT_RESUME_STATUS_ROAM_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS; + case HOST_TWT_RESUME_STATUS_SCAN_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_SCAN_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * twt_nudge_status_to_vendor_twt_status() - convert from + * HOST_TWT_NUDGE_STATUS to qca_wlan_vendor_twt_status + * @status: HOST_TWT_NUDGE_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +twt_nudge_status_to_vendor_twt_status(enum HOST_TWT_NUDGE_STATUS status) +{ + switch (status) { + case HOST_TWT_NUDGE_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case HOST_TWT_NUDGE_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case HOST_TWT_NUDGE_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case HOST_TWT_NUDGE_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case HOST_TWT_NUDGE_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case HOST_TWT_NUDGE_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case HOST_TWT_NUDGE_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case HOST_TWT_NUDGE_STATUS_ALREADY_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED; + case HOST_TWT_NUDGE_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * twt_add_cmd_to_vendor_twt_resp_type() - convert from + * HOST_TWT_COMMAND to qca_wlan_vendor_twt_setup_resp_type + * @type: HOST_TWT_COMMAND value from firmware + * + * Return: qca_wlan_vendor_twt_setup_resp_type values for valid + * HOST_TWT_COMMAND value and -EINVAL for invalid value + */ +static +int twt_add_cmd_to_vendor_twt_resp_type(enum HOST_TWT_COMMAND type) +{ + switch (type) { + case HOST_TWT_COMMAND_ACCEPT_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_ACCEPT; + case HOST_TWT_COMMAND_ALTERNATE_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_ALTERNATE; + case HOST_TWT_COMMAND_DICTATE_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_DICTATE; + case HOST_TWT_COMMAND_REJECT_TWT: + return QCA_WLAN_VENDOR_TWT_RESP_REJECT; + default: + return -EINVAL; + } +} + +/** + * osif_twt_setup_pack_resp_nlmsg() - pack nlmsg response for setup + * @reply_skb: pointer to the response skb structure + * @event: twt event buffer with firmware response + * + * Pack the nl response with parameters and additional parameters + * received from firmware. + * Firmware sends additional parameters only for 2 conditions + * 1) TWT Negotiation is accepted by AP - Firmware sends + * QCA_WLAN_VENDOR_TWT_STATUS_OK with appropriate response type + * in additional parameters + * 2) AP has proposed Alternate values - In this case firmware sends + * QCA_WLAN_VENDOR_TWT_STATUS_DENIED with appropriate response type + * in additional parameters + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +static QDF_STATUS +osif_twt_setup_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct twt_add_dialog_complete_event *event) +{ + struct nlattr *config_attr; + uint64_t sp_offset_tsf; + enum qca_wlan_vendor_twt_status vendor_status; + int response_type, attr; + uint32_t wake_duration; + uint32_t wake_intvl_mantis_us, wake_intvl_mantis_tu; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_SET)) { + osif_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + sp_offset_tsf = event->additional_params.sp_tsf_us_hi; + sp_offset_tsf = (sp_offset_tsf << 32) | + event->additional_params.sp_tsf_us_lo; + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, event->params.dialog_id)) { + osif_err("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = twt_add_status_to_vendor_twt_status( + event->params.status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + osif_err("Failed to put setup status"); + return QDF_STATUS_E_FAILURE; + } + + if (event->params.num_additional_twt_params == 0) { + nla_nest_end(reply_skb, config_attr); + return QDF_STATUS_SUCCESS; + } + + response_type = twt_add_cmd_to_vendor_twt_resp_type( + event->additional_params.twt_cmd); + if (response_type == -EINVAL) { + osif_err("Invalid response type from firmware"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_RESP_TYPE; + if (nla_put_u8(reply_skb, attr, response_type)) { + osif_err("Failed to put setup response type"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_TYPE; + if (nla_put_u8(reply_skb, attr, event->additional_params.announce)) { + osif_err("Failed to put setup flow type"); + return QDF_STATUS_E_FAILURE; + } + + osif_debug("wake_dur_us %d", event->additional_params.wake_dur_us); + wake_duration = (event->additional_params.wake_dur_us / + TWT_WAKE_DURATION_MULTIPLICATION_FACTOR); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, wake_duration)) { + osif_err("Failed to put wake duration"); + return QDF_STATUS_E_FAILURE; + } + + wake_intvl_mantis_us = event->additional_params.wake_intvl_us; + if (nla_put_u32(reply_skb, + QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL2_MANTISSA, + wake_intvl_mantis_us)) { + osif_err("Failed to put wake interval mantissa in us"); + return QDF_STATUS_E_FAILURE; + } + + wake_intvl_mantis_tu = (event->additional_params.wake_intvl_us / + TWT_WAKE_INTVL_MULTIPLICATION_FACTOR); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_MANTISSA; + if (nla_put_u32(reply_skb, attr, wake_intvl_mantis_tu)) { + osif_err("Failed to put wake interval mantissa in tu"); + return QDF_STATUS_E_FAILURE; + } + osif_debug("Send mantissa_us:%d, mantissa_tu:%d to userspace", + wake_intvl_mantis_us, wake_intvl_mantis_tu); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_INTVL_EXP; + if (nla_put_u8(reply_skb, attr, 0)) { + osif_err("Failed to put wake interval exp"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME_TSF; + if (wlan_cfg80211_nla_put_u64(reply_skb, attr, sp_offset_tsf)) { + osif_err("Failed to put sp_offset_tsf"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_WAKE_TIME; + if (nla_put_u32(reply_skb, attr, + event->additional_params.sp_offset_us)) { + osif_err("Failed to put sp_offset_us"); + return QDF_STATUS_E_FAILURE; + } + + if (event->additional_params.trig_en) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TRIGGER; + if (nla_put_flag(reply_skb, attr)) { + osif_err("Failed to put trig type"); + return QDF_STATUS_E_FAILURE; + } + } + + if (event->additional_params.protection) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_PROTECTION; + if (nla_put_flag(reply_skb, attr)) { + osif_err("Failed to put protection flag"); + return QDF_STATUS_E_FAILURE; + } + } + + if (event->additional_params.bcast) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_BCAST; + if (nla_put_flag(reply_skb, attr)) { + osif_err("Failed to put bcast flag"); + return QDF_STATUS_E_FAILURE; + } + } + + if (!event->additional_params.info_frame_disabled) { + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_TWT_INFO_ENABLED; + if (nla_put_flag(reply_skb, attr)) { + osif_err("Failed to put twt info enable flag"); + return QDF_STATUS_E_FAILURE; + } + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + event->params.peer_macaddr.bytes)) { + osif_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * twt_notify_status_to_vendor_twt_status() - convert from + * HOST_NOTIFY_TWT_STATUS to qca_wlan_vendor_twt_notify_status + * @status: HOST_TWT_NOTIFY_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static enum qca_wlan_vendor_twt_status +twt_notify_status_to_vendor_twt_status(enum HOST_TWT_NOTIFY_STATUS status) +{ + switch (status) { + case HOST_TWT_NOTIFY_EVENT_AP_TWT_REQ_BIT_SET: + return QCA_WLAN_VENDOR_TWT_STATUS_TWT_REQUIRED; + case HOST_TWT_NOTIFY_EVENT_AP_TWT_REQ_BIT_CLEAR: + return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_TWT_NOT_REQUIRED; + } +} + +/** + * osif_twt_notify_pack_nlmsg() - pack nlmsg response for TWT notify + * @reply_skb: pointer to the response skb structure + * @event: twt event buffer with firmware response + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +static QDF_STATUS +osif_twt_notify_pack_nlmsg(struct sk_buff *reply_skb, + struct twt_notify_event_param *event) +{ + int attr; + enum qca_wlan_vendor_twt_status vendor_status; + enum qca_wlan_twt_operation twt_op; + + if (event->status == HOST_TWT_NOTIFY_EVENT_READY) + twt_op = QCA_WLAN_TWT_SETUP_READY_NOTIFY; + else + twt_op = QCA_WLAN_TWT_NOTIFY; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + twt_op)) { + osif_err("Failed to put TWT notify operation"); + return QDF_STATUS_E_FAILURE; + } + + if (event->status != HOST_TWT_NOTIFY_EVENT_READY) { + attr = QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS; + vendor_status = twt_notify_status_to_vendor_twt_status( + event->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + osif_err("Failed to put notify status"); + return QDF_STATUS_E_FAILURE; + } + } + + return QDF_STATUS_SUCCESS; +} + +/** + * osif_twt_teardown_pack_resp_nlmsg() - pack nlmsg response for teardown + * @reply_skb: pointer to the response skb structure + * @event: twt event buffer with firmware response + * + * Return: QDF_STATUS_SUCCESS on Success, other QDF_STATUS error codes + * on failure + */ +static QDF_STATUS +osif_twt_teardown_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct twt_del_dialog_complete_event_param *event) +{ + struct nlattr *config_attr; + enum qca_wlan_vendor_twt_status vendor_status; + int attr; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_TERMINATE)) { + osif_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, event->dialog_id)) { + osif_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = twt_del_status_to_vendor_twt_status(event->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + osif_err("Failed to put QCA_WLAN_TWT_TERMINATE"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + event->peer_macaddr.bytes)) { + osif_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * osif_twt_resume_pack_resp_nlmsg() - pack the skb with + * firmware response for twt resume command + * @reply_skb: skb to store the response + * @event: Pointer to resume dialog complete event buffer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +osif_twt_resume_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct twt_resume_dialog_complete_event_param *event) +{ + struct nlattr *config_attr; + int vendor_status, attr; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_RESUME)) { + osif_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_FLOW_ID; + if (nla_put_u8(reply_skb, attr, event->dialog_id)) { + osif_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = twt_resume_status_to_vendor_twt_status(event->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + osif_err("Failed to put QCA_WLAN_TWT_RESUME status"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_RESUME_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + event->peer_macaddr.bytes)) { + osif_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * osif_twt_nudge_pack_resp_nlmsg() - pack the skb with + * firmware response for twt nudge command + * @reply_skb: skb to store the response + * @event: Pointer to nudge dialog complete event buffer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +osif_twt_nudge_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct twt_nudge_dialog_complete_event_param *event) +{ + struct nlattr *config_attr; + int vendor_status, attr; + uint64_t tsf_val; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_NUDGE)) { + osif_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_FLOW_ID; + if (nla_put_u8(reply_skb, attr, event->dialog_id)) { + osif_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + tsf_val = event->next_twt_tsf_us_hi; + tsf_val = (tsf_val << 32) | event->next_twt_tsf_us_lo; + if (wlan_cfg80211_nla_put_u64(reply_skb, + QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_WAKE_TIME_TSF, + tsf_val)) { + osif_err("get_params failed to put TSF Value"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = twt_nudge_status_to_vendor_twt_status(event->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + osif_err("Failed to put QCA_WLAN_TWT_NUDGE status"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_NUDGE_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + event->peer_macaddr.bytes)) { + osif_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +osif_twt_send_get_capabilities_response(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_vdev *vdev) +{ + struct vdev_osif_priv *osif_priv; + struct nlattr *config_attr; + struct sk_buff *reply_skb; + size_t skb_len = NLMSG_HDRLEN; + QDF_STATUS qdf_status = QDF_STATUS_SUCCESS; + enum band_info connected_band; + uint8_t peer_cap = 0, self_cap = 0; + bool twt_req = false, twt_bcast_req = false; + bool is_twt_24ghz_allowed = true, val; + struct qdf_mac_addr peer_mac; + int ret; + + /* + * Userspace will query the TWT get capabilities before + * issuing a get capabilities request. If the STA is + * connected, then check the "enable_twt_24ghz" ini + * value to advertise the TWT requestor capability. + */ + connected_band = ucfg_cm_get_connected_band(vdev); + ucfg_twt_cfg_get_24ghz_enabled(psoc, &val); + + osif_debug("connected_band: %d val: %d", connected_band, val); + if (connected_band == BAND_2G && !val) + is_twt_24ghz_allowed = false; + + /* fill the self_capability bitmap */ + ucfg_twt_cfg_get_requestor(psoc, &twt_req); + osif_debug("is_twt_24ghz_allowed: %d twt_req: %d", + is_twt_24ghz_allowed, twt_req); + if (twt_req && is_twt_24ghz_allowed) + self_cap |= QCA_WLAN_TWT_CAPA_REQUESTOR; + + ucfg_twt_cfg_get_bcast_requestor(psoc, &twt_bcast_req); + osif_debug("twt_bcast_req: %d", twt_bcast_req); + self_cap |= (twt_bcast_req ? QCA_WLAN_TWT_CAPA_BROADCAST : 0); + + ucfg_twt_cfg_get_flex_sched(psoc, &val); + osif_debug("flex sched: %d", val); + if (val) + self_cap |= QCA_WLAN_TWT_CAPA_FLEXIBLE; + + ret = osif_fill_peer_macaddr(vdev, peer_mac.bytes); + if (ret) + return QDF_STATUS_E_INVAL; + + qdf_status = ucfg_twt_get_peer_capabilities(psoc, &peer_mac, &peer_cap); + if (QDF_IS_STATUS_ERROR(qdf_status)) + return qdf_status; + + osif_debug("self_cap: 0x%x peer_cap: 0x%x", self_cap, peer_cap); + osif_priv = wlan_vdev_get_ospriv(vdev); + /* + * Length of attribute QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF & + * QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER + */ + skb_len += 2 * nla_total_size(sizeof(u16)) + NLA_HDRLEN; + + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb( + osif_priv->wdev->wiphy, + skb_len); + if (!reply_skb) { + osif_err("TWT: get_caps alloc reply skb failed"); + return QDF_STATUS_E_NOMEM; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("TWT: nla_nest_start error"); + qdf_status = QDF_STATUS_E_FAILURE; + goto free_skb; + } + + if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_SELF, + self_cap)) { + osif_err("TWT: Failed to fill capabilities"); + qdf_status = QDF_STATUS_E_FAILURE; + goto free_skb; + } + + if (nla_put_u16(reply_skb, QCA_WLAN_VENDOR_ATTR_TWT_CAPABILITIES_PEER, + peer_cap)) { + osif_err("TWT: Failed to fill capabilities"); + qdf_status = QDF_STATUS_E_FAILURE; + goto free_skb; + } + + nla_nest_end(reply_skb, config_attr); + + if (wlan_cfg80211_vendor_cmd_reply(reply_skb)) + qdf_status = QDF_STATUS_E_INVAL; + return qdf_status; + +free_skb: + wlan_cfg80211_vendor_free_skb(reply_skb); + return qdf_status; +} + +static void +osif_twt_setup_response(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event) +{ + struct sk_buff *twt_vendor_event; + struct wireless_dev *wdev; + struct wlan_objmgr_vdev *vdev; + struct vdev_osif_priv *osif_priv; + size_t data_len; + QDF_STATUS status; + bool additional_params_present = false; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + event->params.vdev_id, + WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + if (event->params.num_additional_twt_params != 0) + additional_params_present = true; + + data_len = osif_twt_get_setup_event_len(additional_params_present); + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + osif_err("TWT: Alloc setup resp skb fail"); + goto fail; + } + + status = osif_twt_setup_pack_resp_nlmsg(twt_vendor_event, event); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to pack nl add dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + goto fail; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); +} + +static void +osif_twt_teardown_response(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + struct sk_buff *twt_vendor_event; + struct wireless_dev *wdev; + struct wlan_objmgr_vdev *vdev; + struct vdev_osif_priv *osif_priv; + size_t data_len; + QDF_STATUS status; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, + event->vdev_id, WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is null"); + return; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8)); + data_len += NLA_HDRLEN; + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + osif_err("TWT: Alloc teardown resp skb fail"); + goto fail; + } + + status = osif_twt_teardown_pack_resp_nlmsg(twt_vendor_event, event); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to pack nl del dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + goto fail; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); +} + +QDF_STATUS +osif_twt_setup_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_add_dialog_complete_event *event, + bool renego_fail) +{ + uint32_t vdev_id = event->params.vdev_id; + + osif_debug("TWT: add dialog_id:%d, status:%d vdev_id:%d renego_fail:%d peer mac_addr " + QDF_MAC_ADDR_FMT, event->params.dialog_id, + event->params.status, vdev_id, renego_fail, + QDF_MAC_ADDR_REF(event->params.peer_macaddr.bytes)); + + osif_twt_setup_response(psoc, event); + + if (renego_fail) + osif_twt_handle_renego_failure(psoc, event); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +osif_twt_teardown_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_del_dialog_complete_event_param *event) +{ + uint32_t vdev_id = event->vdev_id; + + osif_debug("TWT: del dialog_id:%d status:%d vdev_id:%d peer mac_addr " + QDF_MAC_ADDR_FMT, event->dialog_id, + event->status, vdev_id, + QDF_MAC_ADDR_REF(event->peer_macaddr.bytes)); + + osif_twt_teardown_response(psoc, event); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +osif_twt_resume_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_resume_dialog_complete_event_param *event) +{ + struct wireless_dev *wdev; + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id = event->vdev_id; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, + WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is null"); + return status; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + osif_debug("TWT: resume dialog_id:%d status:%d vdev_id:%d peer macaddr " + QDF_MAC_ADDR_FMT, event->dialog_id, + event->status, vdev_id, + QDF_MAC_ADDR_REF(event->peer_macaddr.bytes)); + + data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8)); + data_len += NLA_HDRLEN; + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + osif_err("TWT: Alloc resume resp skb fail"); + goto fail; + } + + status = osif_twt_resume_pack_resp_nlmsg(twt_vendor_event, event); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to pack nl resume dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + goto fail; + } + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return status; +} + +QDF_STATUS +osif_twt_nudge_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_nudge_dialog_complete_event_param *event) +{ + struct wireless_dev *wdev; + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id = event->vdev_id; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, + WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is null"); + return status; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + osif_debug("TWT: nudge dialog_id:%d status:%d vdev_id:%d peer macaddr " + QDF_MAC_ADDR_FMT, event->dialog_id, + event->status, vdev_id, + QDF_MAC_ADDR_REF(event->peer_macaddr.bytes)); + + data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8)) + + nla_total_size(sizeof(u64)); + data_len += NLA_HDRLEN; + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + osif_err("TWT: Alloc nudge resp skb fail"); + goto fail; + } + + status = osif_twt_nudge_pack_resp_nlmsg(twt_vendor_event, event); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to pack nl add dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + goto fail; + } + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return status; + +} + +/** + * osif_twt_get_notify_event_len() - calculates the length of twt + * notify nl response + * + * Return: Length of twt notify nl response + */ +static +uint32_t osif_twt_get_notify_event_len(void) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_NOTIFY_STATUS */ + len += nla_total_size(sizeof(u8)); + + return len; +} + +QDF_STATUS +osif_twt_notify_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_notify_event_param *event) +{ + struct wireless_dev *wdev; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status; + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, + WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is null"); + return QDF_STATUS_E_INVAL; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + status = QDF_STATUS_E_INVAL; + goto end; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + status = QDF_STATUS_E_INVAL; + goto end; + } + + data_len = osif_twt_get_notify_event_len(); + data_len += NLA_HDRLEN; + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + osif_err("Notify skb alloc failed"); + status = QDF_STATUS_E_INVAL; + goto end; + } + + osif_debug("TWT: twt Notify vdev_id: %d, status: %d", event->vdev_id, + event->status); + + status = osif_twt_notify_pack_nlmsg(twt_vendor_event, event); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to pack nl notify event"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + status = QDF_STATUS_E_INVAL; + goto end; + } + + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + status = QDF_STATUS_SUCCESS; + +end: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return status; +} + +/** + * twt_pause_status_to_vendor_twt_status() - convert from + * HOST_TWT_PAUSE_STATUS to qca_wlan_vendor_twt_status + * @status: HOST_TWT_PAUSE_STATUS value from firmware + * + * Return: qca_wlan_vendor_twt_status values corresponding + * to the firmware failure status + */ +static int +twt_pause_status_to_vendor_twt_status(enum HOST_TWT_PAUSE_STATUS status) +{ + switch (status) { + case HOST_TWT_PAUSE_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case HOST_TWT_PAUSE_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case HOST_TWT_PAUSE_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + case HOST_TWT_PAUSE_STATUS_DIALOG_ID_BUSY: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_BUSY; + case HOST_TWT_PAUSE_STATUS_ALREADY_PAUSED: + return QCA_WLAN_VENDOR_TWT_STATUS_ALREADY_SUSPENDED; + case HOST_TWT_PAUSE_STATUS_NO_RESOURCE: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_RESOURCE; + case HOST_TWT_PAUSE_STATUS_NO_ACK: + return QCA_WLAN_VENDOR_TWT_STATUS_NO_ACK; + case HOST_TWT_PAUSE_STATUS_UNKNOWN_ERROR: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + case HOST_TWT_PAUSE_STATUS_CHAN_SW_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_CHANNEL_SWITCH_IN_PROGRESS; + case HOST_TWT_PAUSE_STATUS_ROAM_IN_PROGRESS: + return QCA_WLAN_VENDOR_TWT_STATUS_ROAMING_IN_PROGRESS; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * osif_twt_pause_pack_resp_nlmsg() - pack the skb with + * firmware response for twt pause command + * @reply_skb: skb to store the response + * @event: Pointer to pause dialog complete event buffer + * + * Return: QDF_STATUS + */ +static QDF_STATUS +osif_twt_pause_pack_resp_nlmsg(struct sk_buff *reply_skb, + struct twt_pause_dialog_complete_event_param *event) +{ + struct nlattr *config_attr; + int vendor_status, attr; + + if (nla_put_u8(reply_skb, QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_OPERATION, + QCA_WLAN_TWT_SUSPEND)) { + osif_err("Failed to put TWT operation"); + return QDF_STATUS_E_FAILURE; + } + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + if (!config_attr) { + osif_err("nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID; + if (nla_put_u8(reply_skb, attr, event->dialog_id)) { + osif_debug("Failed to put dialog_id"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS; + vendor_status = twt_pause_status_to_vendor_twt_status(event->status); + if (nla_put_u8(reply_skb, attr, vendor_status)) { + osif_err("Failed to put QCA_WLAN_TWT_PAUSE status"); + return QDF_STATUS_E_FAILURE; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_SETUP_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + event->peer_macaddr.bytes)) { + osif_err("Failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +osif_twt_pause_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_pause_dialog_complete_event_param *event) + +{ + struct wireless_dev *wdev; + struct vdev_osif_priv *osif_priv; + struct wlan_objmgr_vdev *vdev; + uint32_t vdev_id = event->vdev_id; + struct sk_buff *twt_vendor_event; + size_t data_len; + QDF_STATUS status = QDF_STATUS_E_FAILURE; + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, event->vdev_id, + WLAN_TWT_ID); + if (!vdev) { + osif_err("vdev is null"); + return status; + } + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + goto fail; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + goto fail; + } + + osif_debug("TWT: pause dialog_id:%d status:%d vdev_id:%d peer macaddr " + QDF_MAC_ADDR_FMT, event->dialog_id, + event->status, vdev_id, + QDF_MAC_ADDR_REF(event->peer_macaddr.bytes)); + + data_len = osif_twt_get_event_len() + nla_total_size(sizeof(u8)); + data_len += NLA_HDRLEN; + + twt_vendor_event = wlan_cfg80211_vendor_event_alloc( + wdev->wiphy, wdev, data_len, + QCA_NL80211_VENDOR_SUBCMD_CONFIG_TWT_INDEX, + GFP_KERNEL); + if (!twt_vendor_event) { + osif_err("TWT: Alloc pause resp skb fail"); + goto fail; + } + + status = osif_twt_pause_pack_resp_nlmsg(twt_vendor_event, event); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Failed to pack nl add dialog response"); + wlan_cfg80211_vendor_free_skb(twt_vendor_event); + goto fail; + } + wlan_cfg80211_vendor_event(twt_vendor_event, GFP_KERNEL); + +fail: + wlan_objmgr_vdev_release_ref(vdev, WLAN_TWT_ID); + return status; +} + +QDF_STATUS +osif_twt_ack_complete_cb(struct wlan_objmgr_psoc *psoc, + struct twt_ack_complete_event_param *params, + void *context) +{ + struct osif_request *request = NULL; + struct twt_ack_context *status_priv; + + request = osif_request_get(context); + if (!request) { + osif_err("obsolete request"); + return QDF_STATUS_E_FAILURE; + } + + status_priv = osif_request_priv(request); + if (!status_priv) { + osif_err("obsolete status_priv"); + return QDF_STATUS_E_FAILURE; + } + + if (status_priv->twt_cmd_ack == params->twt_cmd_ack) { + status_priv->vdev_id = params->vdev_id; + qdf_copy_macaddr(&status_priv->peer_macaddr, + ¶ms->peer_macaddr); + status_priv->dialog_id = params->dialog_id; + status_priv->status = params->status; + osif_request_complete(request); + } else { + osif_err("Invalid TWT ack. Expected cmd: %d Actual cmd: %d", + status_priv->twt_cmd_ack, params->twt_cmd_ack); + } + + osif_request_put(request); + return QDF_STATUS_SUCCESS; +} + +static uint32_t +osif_get_session_wake_duration(struct wlan_objmgr_vdev *vdev, + uint32_t dialog_id, + struct qdf_mac_addr *peer_macaddr) +{ + struct wlan_objmgr_psoc *psoc; + struct twt_session_stats_info params = {0}; + int num_twt_session = 0; + + psoc = wlan_vdev_get_psoc(vdev); + params.dialog_id = dialog_id; + qdf_copy_macaddr(¶ms.peer_mac, peer_macaddr); + + osif_debug("Get_params peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params.peer_mac.bytes)); + + num_twt_session = ucfg_cp_stats_twt_get_peer_session_params(psoc, + ¶ms); + if (num_twt_session) + return params.wake_dura_us; + + return 0; +} + +static int +twt_get_stats_status_to_vendor_twt_status(enum HOST_TWT_GET_STATS_STATUS status) +{ + switch (status) { + case HOST_TWT_GET_STATS_STATUS_OK: + return QCA_WLAN_VENDOR_TWT_STATUS_OK; + case HOST_TWT_GET_STATS_STATUS_DIALOG_ID_NOT_EXIST: + return QCA_WLAN_VENDOR_TWT_STATUS_SESSION_NOT_EXIST; + case HOST_TWT_GET_STATS_STATUS_INVALID_PARAM: + return QCA_WLAN_VENDOR_TWT_STATUS_INVALID_PARAM; + default: + return QCA_WLAN_VENDOR_TWT_STATUS_UNKNOWN_ERROR; + } +} + +/** + * osif_twt_pack_get_stats_resp_nlmsg() - Packs and sends twt get stats response + * @vdev: vdev + * @reply_skb: pointer to response skb buffer + * @params: Pointer to twt session parameter buffer + * @num_session_stats: number of twt statistics + * + * Return: QDF_STATUS_SUCCESS on success, else other qdf error values + */ +static QDF_STATUS +osif_twt_pack_get_stats_resp_nlmsg(struct wlan_objmgr_vdev *vdev, + struct sk_buff *reply_skb, + struct twt_infra_cp_stats_event *params, + uint32_t num_session_stats) +{ + struct nlattr *config_attr, *nla_params; + int i, attr; + int vendor_status; + uint32_t duration; + + config_attr = nla_nest_start(reply_skb, + QCA_WLAN_VENDOR_ATTR_CONFIG_TWT_PARAMS); + + if (!config_attr) { + osif_err("get_params nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + for (i = 0; i < num_session_stats; i++) { + nla_params = nla_nest_start(reply_skb, i); + if (!nla_params) { + osif_err("get_stats nla_nest_start error"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAC_ADDR; + if (nla_put(reply_skb, attr, QDF_MAC_ADDR_SIZE, + params[i].peer_macaddr.bytes)) { + osif_err("get_stats failed to put mac_addr"); + return QDF_STATUS_E_INVAL; + } + + osif_debug("get_stats peer mac_addr " QDF_MAC_ADDR_FMT, + QDF_MAC_ADDR_REF(params[i].peer_macaddr.bytes)); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_FLOW_ID; + if (nla_put_u8(reply_skb, attr, params[i].dialog_id)) { + osif_err("get_stats failed to put dialog_id"); + return QDF_STATUS_E_INVAL; + } + + duration = osif_get_session_wake_duration(vdev, + params[i].dialog_id, + ¶ms[i].peer_macaddr); + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_SESSION_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, duration)) { + osif_err("get_params failed to put Wake duration"); + return QDF_STATUS_E_INVAL; + } + + osif_debug("dialog_id %d wake duration %d num sp cycles %d", + params[i].dialog_id, duration, + params[i].num_sp_cycles); + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_NUM_SP_ITERATIONS; + if (nla_put_u32(reply_skb, attr, params[i].num_sp_cycles)) { + osif_err("get_params failed to put num_sp_cycles"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVG_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].avg_sp_dur_us)) { + osif_err("get_params failed to put avg_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MIN_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].min_sp_dur_us)) { + osif_err("get_params failed to put min_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_MAX_WAKE_DURATION; + if (nla_put_u32(reply_skb, attr, params[i].max_sp_dur_us)) { + osif_err("get_params failed to put max_sp_dur_us"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_MPDU; + if (nla_put_u32(reply_skb, attr, params[i].tx_mpdu_per_sp)) { + osif_err("get_params failed to put tx_mpdu_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_MPDU; + if (nla_put_u32(reply_skb, attr, params[i].rx_mpdu_per_sp)) { + osif_err("get_params failed to put rx_mpdu_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_TX_PACKET_SIZE; + if (nla_put_u32(reply_skb, attr, params[i].tx_bytes_per_sp)) { + osif_err("get_params failed to put tx_bytes_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_AVERAGE_RX_PACKET_SIZE; + if (nla_put_u32(reply_skb, attr, params[i].rx_bytes_per_sp)) { + osif_err("get_params failed to put rx_bytes_per_sp"); + return QDF_STATUS_E_INVAL; + } + + attr = QCA_WLAN_VENDOR_ATTR_TWT_STATS_STATUS; + vendor_status = + twt_get_stats_status_to_vendor_twt_status(params[i].status); + if (nla_put_u32(reply_skb, attr, vendor_status)) { + osif_err("get_params failed to put status"); + return QDF_STATUS_E_INVAL; + } + + nla_nest_end(reply_skb, nla_params); + } + + nla_nest_end(reply_skb, config_attr); + + return QDF_STATUS_SUCCESS; +} + +/** + * osif_get_twt_get_stats_event_len() - calculate length of skb + * required for sending twt get statistics command responses. + * + * Return: length of skb + */ +static uint32_t osif_get_twt_get_stats_event_len(void) +{ + uint32_t len = 0; + + len += NLMSG_HDRLEN; + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_FLOW_ID */ + len += nla_total_size(sizeof(u8)); + + /* QCA_WLAN_VENDOR_ATTR_TWT_SETUP_STATUS */ + len += nla_total_size(sizeof(u8)); + + return len; +} + +QDF_STATUS osif_twt_get_stats_response(struct wlan_objmgr_vdev *vdev, + struct twt_infra_cp_stats_event *params, + uint32_t num_session_stats) +{ + int skb_len; + struct vdev_osif_priv *osif_priv; + struct wireless_dev *wdev; + QDF_STATUS status = QDF_STATUS_E_INVAL; + struct sk_buff *reply_skb; + int ret; + + osif_priv = wlan_vdev_get_ospriv(vdev); + if (!osif_priv) { + osif_err("osif_priv is null"); + return QDF_STATUS_E_INVAL; + } + + wdev = osif_priv->wdev; + if (!wdev) { + osif_err("wireless dev is null"); + return QDF_STATUS_E_INVAL; + } + + skb_len = osif_get_twt_get_stats_event_len(); + reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wdev->wiphy, + skb_len); + if (!reply_skb) { + osif_err("Get stats - alloc reply_skb failed"); + return QDF_STATUS_E_NOMEM; + } + + status = osif_twt_pack_get_stats_resp_nlmsg(vdev, reply_skb, params, + num_session_stats); + if (QDF_IS_STATUS_ERROR(status)) { + osif_err("Get stats - Failed to pack nl response"); + wlan_cfg80211_vendor_free_skb(reply_skb); + return qdf_status_to_os_return(status); + } + + ret = wlan_cfg80211_vendor_cmd_reply(reply_skb); + return qdf_status_from_os_return(ret); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_util.c b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_util.c new file mode 100644 index 0000000000..2034285b4b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/os_if/twt/src/osif_twt_ext_util.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: osif_twt_ext_util.c + */ +#include +#include +#include +#include +#include +#include + +static struct mlme_twt_ops twt_ops = { + .mlme_twt_enable_complete_cb = osif_twt_enable_complete_cb, + .mlme_twt_disable_complete_cb = osif_twt_disable_complete_cb, + .mlme_twt_setup_complete_cb = osif_twt_setup_complete_cb, + .mlme_twt_teardown_complete_cb = osif_twt_teardown_complete_cb, + .mlme_twt_pause_complete_cb = osif_twt_pause_complete_cb, + .mlme_twt_resume_complete_cb = osif_twt_resume_complete_cb, + .mlme_twt_nudge_complete_cb = osif_twt_nudge_complete_cb, + .mlme_twt_notify_complete_cb = osif_twt_notify_complete_cb, + .mlme_twt_ack_complete_cb = osif_twt_ack_complete_cb, + .mlme_twt_vdev_create_cb = osif_twt_create_work, + .mlme_twt_vdev_destroy_cb = osif_twt_destroy_work, +}; + +/** + * osif_twt_get_global_ops() - Get twt global ops + * + * Return: twt global ops + */ +static struct mlme_twt_ops *osif_twt_get_global_ops(void) +{ + return &twt_ops; +} + +QDF_STATUS osif_twt_register_cb(void) +{ + return ucfg_twt_set_osif_cb(osif_twt_get_global_ops); +} + diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/a_debug.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/a_debug.h new file mode 100644 index 0000000000..db21bc2d66 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/a_debug.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _A_DEBUG_H_ +#define _A_DEBUG_H_ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include "osapi_linux.h" + +/* standard debug print masks bits 0..7 */ +#define ATH_DEBUG_ERR (1 << 0) /* errors */ +#define ATH_DEBUG_WARN (1 << 1) /* warnings */ +#define ATH_DEBUG_INFO (1 << 2) /* informational (module startup info) */ +#define ATH_DEBUG_TRC (1 << 3) /* generic function call tracing */ +#define ATH_DEBUG_RSVD1 (1 << 4) +#define ATH_DEBUG_RSVD2 (1 << 5) +#define ATH_DEBUG_RSVD3 (1 << 6) +#define ATH_DEBUG_RSVD4 (1 << 7) + +#define ATH_DEBUG_MASK_DEFAULTS (ATH_DEBUG_ERR | ATH_DEBUG_WARN) +#define ATH_DEBUG_ANY 0xFFFF + +/* other aliases used throughout */ +#define ATH_DEBUG_ERROR ATH_DEBUG_ERR +#define ATH_LOG_ERR ATH_DEBUG_ERR +#define ATH_LOG_INF ATH_DEBUG_INFO +#define ATH_LOG_TRC ATH_DEBUG_TRC +#define ATH_DEBUG_TRACE ATH_DEBUG_TRC +#define ATH_DEBUG_INIT ATH_DEBUG_INFO + +/* bits 8..31 are module-specific masks */ +#define ATH_DEBUG_MODULE_MASK_SHIFT 8 + +/* macro to make a module-specific masks */ +#define ATH_DEBUG_MAKE_MODULE_MASK(index) (1 << (ATH_DEBUG_MODULE_MASK_SHIFT + (index))) + +void debug_dump_bytes(A_UCHAR *buffer, A_UINT16 length, + char *pDescription); + +/* Debug support on a per-module basis + * + * Usage: + * + * Each module can utilize it's own debug mask variable. A set of commonly used + * masks are provided (ERRORS, WARNINGS, TRACE etc..). It is up to each module + * to define module-specific masks using the macros above. + * + * Each module defines a single debug mask variable debug_XXX where the "name" of the module is + * common to all C-files within that module. This requires every C-file that includes a_debug.h + * to define the module name in that file. + * + * Example: + * + * #define ATH_MODULE_NAME htc + * #include "a_debug.h" + * + * This will define a debug mask structure called debug_htc and all debug macros will reference this + * variable. + * + * A module can define module-specific bit masks using the ATH_DEBUG_MAKE_MODULE_MASK() macro: + * + * #define ATH_DEBUG_MY_MASK1 ATH_DEBUG_MAKE_MODULE_MASK(0) + * #define ATH_DEBUG_MY_MASK2 ATH_DEBUG_MAKE_MODULE_MASK(1) + * + * The instantiation of the debug structure should be made by the module. When a module is + * instantiated, the module can set a description string, a default mask and an array of description + * entries containing information on each module-defined debug mask. + * NOTE: The instantiation is statically allocated, only one instance can exist per module. + * + * Example: + * + * + * #define ATH_DEBUG_BMI ATH_DEBUG_MAKE_MODULE_MASK(0) + * + * #ifdef DEBUG + * static ATH_DEBUG_MASK_DESCRIPTION bmi_debug_desc[] = { + * { ATH_DEBUG_BMI , "BMI Tracing"}, <== description of the module specific mask + * }; + * + * ATH_DEBUG_INSTANTIATE_MODULE_VAR(bmi, + * "bmi" <== module name + * "Boot Manager Interface", <== description of module + * ATH_DEBUG_MASK_DEFAULTS, <== defaults + * ATH_DEBUG_DESCRIPTION_COUNT(bmi_debug_desc), + * bmi_debug_desc); + * + * #endif + * + * A module can optionally register it's debug module information in order for other tools to change the + * bit mask at runtime. A module can call A_REGISTER_MODULE_DEBUG_INFO() in it's module + * init code. This macro can be called multiple times without consequence. The debug info maintains + * state to indicate whether the information was previously registered. + * + * */ + +#define ATH_DEBUG_MAX_MASK_DESC_LENGTH 32 +#define ATH_DEBUG_MAX_MOD_DESC_LENGTH 64 + +typedef struct { + A_UINT32 Mask; + A_CHAR Description[ATH_DEBUG_MAX_MASK_DESC_LENGTH]; +} ATH_DEBUG_MASK_DESCRIPTION; + +#define ATH_DEBUG_INFO_FLAGS_REGISTERED (1 << 0) + +typedef struct _ATH_DEBUG_MODULE_DBG_INFO { + struct _ATH_DEBUG_MODULE_DBG_INFO *pNext; + A_CHAR ModuleName[16]; + A_CHAR ModuleDescription[ATH_DEBUG_MAX_MOD_DESC_LENGTH]; + A_UINT32 Flags; + A_UINT32 CurrentMask; + int MaxDescriptions; + ATH_DEBUG_MASK_DESCRIPTION *pMaskDescriptions; /* pointer to array of descriptions */ +} ATH_DEBUG_MODULE_DBG_INFO; + +#define ATH_DEBUG_DESCRIPTION_COUNT(d) (int)((sizeof((d))) / (sizeof(ATH_DEBUG_MASK_DESCRIPTION))) + +#define GET_ATH_MODULE_DEBUG_VAR_NAME(s) _XGET_ATH_MODULE_NAME_DEBUG_(s) +#define GET_ATH_MODULE_DEBUG_VAR_MASK(s) _XGET_ATH_MODULE_NAME_DEBUG_(s).CurrentMask +#define _XGET_ATH_MODULE_NAME_DEBUG_(s) debug_ ## s + +#ifdef WLAN_DEBUG + +/* for source files that will instantiate the debug variables */ +#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s, name, moddesc, initmask, count, descriptions) \ + ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) = \ + {NULL, (name), (moddesc), 0, (initmask), (count), (descriptions)} + +#ifdef ATH_MODULE_NAME +extern ATH_DEBUG_MODULE_DBG_INFO +GET_ATH_MODULE_DEBUG_VAR_NAME(ATH_MODULE_NAME); +#define AR_DEBUG_LVL_CHECK(lvl) (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (lvl)) +#endif /* ATH_MODULE_NAME */ + +#define ATH_DEBUG_SET_DEBUG_MASK(s, lvl) GET_ATH_MODULE_DEBUG_VAR_MASK(s) = (lvl) + +#define ATH_DEBUG_DECLARE_EXTERN(s) \ + extern ATH_DEBUG_MODULE_DBG_INFO GET_ATH_MODULE_DEBUG_VAR_NAME(s) + +#define AR_DEBUG_PRINTBUF(buffer, length, desc) debug_dump_bytes(buffer, length, desc) + +#define AR_DEBUG_ASSERT A_ASSERT + +void a_dump_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo); +void a_register_module_debug_info(ATH_DEBUG_MODULE_DBG_INFO *pInfo); +#ifdef A_SIMOS_DEVHOST +#define A_DUMP_MODULE_DEBUG_INFO(s) a_dump_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s))) +#define A_REGISTER_MODULE_DEBUG_INFO(s) a_register_module_debug_info(&(GET_ATH_MODULE_DEBUG_VAR_NAME(s))) +#else +#define A_DUMP_MODULE_DEBUG_INFO(s) +#define A_REGISTER_MODULE_DEBUG_INFO(s) +#endif + +#else /* !DEBUG */ +/* NON DEBUG */ +#define ATH_DEBUG_INSTANTIATE_MODULE_VAR(s, name, moddesc, initmask, count, descriptions) +#define AR_DEBUG_LVL_CHECK(lvl) 0 +#define AR_DEBUG_PRINTBUF(buffer, length, desc) +#define AR_DEBUG_ASSERT(test) +#define ATH_DEBUG_DECLARE_EXTERN(s) +#define ATH_DEBUG_SET_DEBUG_MASK(s, lvl) +#define A_DUMP_MODULE_DEBUG_INFO(s) +#define A_REGISTER_MODULE_DEBUG_INFO(s) + +#endif + +#if defined(__linux__) && !defined(LINUX_EMULATION) +#include "debug_linux.h" +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/a_types.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/a_types.h new file mode 100644 index 0000000000..190d40df6a --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/a_types.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* depot/sw/qca_main/perf_pwr_offload/drivers/host/include/a_types.h#7 - integrate change 1327637 (ktext) */ +/* ============================================================================== */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* */ +/* Author(s): ="Atheros" */ +/* ============================================================================== */ + +#ifndef _A_TYPES_H_ +#define _A_TYPES_H_ +#include + +typedef unsigned int A_UINT32; +typedef unsigned long long A_UINT64; +typedef unsigned short A_UINT16; +typedef unsigned char A_UINT8; +typedef int A_INT32; +typedef short A_INT16; +typedef char A_INT8; +typedef unsigned char A_UCHAR; +typedef char A_CHAR; +typedef _Bool A_BOOL; + +#endif /* _ATHTYPES_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/athstartpack.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/athstartpack.h new file mode 100644 index 0000000000..0b92352228 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/athstartpack.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013-2014 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ATHSTARTPACK_H +#define _ATHSTARTPACK_H + +#if defined(LINUX) || defined(__linux__) +#include "osapi_linux.h" +#endif /* LINUX */ + +#ifdef QNX +#endif /* QNX */ + +#if __LONG_MAX__ == __INT_MAX__ +/* 32-bit compilation */ +#define PREPACK64 +#define POSTPACK64 +#else +/* 64-bit compilation */ +#define PREPACK64 PREPACK +#define POSTPACK64 POSTPACK +#endif + +#endif /* _ATHSTARTPACK_H */ diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/dbglog_common.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/dbglog_common.h new file mode 100644 index 0000000000..b1c0f6f1c6 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/dbglog_common.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2011, 2014-2015 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DBGLOG_COMMON_H_ +#define _DBGLOG_COMMON_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "dbglog_id.h" +#include "dbglog.h" + +#define MAX_DBG_MSGS 256 + +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define DBGLOG_PRINT_PREFIX "FWLOG: " + +/* Handy Macros to read data length and type from FW */ +#define WLAN_DIAG_0_TYPE_S 0 +#define WLAN_DIAG_0_TYPE 0x000000ff +#define WLAN_DIAG_0_TYPE_GET(x) WMI_F_MS(x, WLAN_DIAG_0_TYPE) +#define WLAN_DIAG_0_TYPE_SET(x, y) WMI_F_RMW(x, y, WLAN_DIAG_0_TYPE) +/* bits 8-15 reserved */ + +/* length includes the size of wlan_diag_data */ +#define WLAN_DIAG_0_LEN_S 16 +#define WLAN_DIAG_0_LEN 0xffff0000 +#define WLAN_DIAG_0_LEN_GET(x) WMI_F_MS(x, WLAN_DIAG_0_LEN) +#define WLAN_DIAG_0_LEN_SET(x, y) WMI_F_RMW(x, y, WLAN_DIAG_0_LEN) + +#define CNSS_DIAG_SLEEP_INTERVAL 5 /* In secs */ + +#define ATH6KL_FWLOG_MAX_ENTRIES 20 +#define ATH6KL_FWLOG_PAYLOAD_SIZE 1500 + +#define DIAG_WLAN_DRIVER_UNLOADED 6 +#define DIAG_WLAN_DRIVER_LOADED 7 +#define DIAG_TYPE_LOGS 1 +#define DIAG_TYPE_EVENTS 2 + +typedef enum { + DBGLOG_PROCESS_DEFAULT = 0, + DBGLOG_PROCESS_PRINT_RAW, /* print them in debug view */ + DBGLOG_PROCESS_POOL_RAW, /* user buffer pool to save them */ + DBGLOG_PROCESS_NET_RAW, /* user buffer pool to save them */ + DBGLOG_PROCESS_MAX, +} dbglog_process_t; + +enum cnss_diag_type { + DIAG_TYPE_FW_EVENT, /* send fw event- to diag */ + DIAG_TYPE_FW_LOG, /* send log event- to diag */ + DIAG_TYPE_FW_DEBUG_MSG, /* send dbg message- to diag */ + DIAG_TYPE_INIT_REQ, /* cnss_diag initialization- from diag */ + DIAG_TYPE_FW_MSG, /* fw msg command-to diag */ + DIAG_TYPE_HOST_MSG, /* host command-to diag */ + DIAG_TYPE_CRASH_INJECT, /*crash inject-from diag */ + DIAG_TYPE_DBG_LEVEL, /* DBG LEVEL-from diag */ +}; + +enum wlan_diag_config_type { + DIAG_VERSION_INFO, +}; + +enum wlan_diag_frame_type { + WLAN_DIAG_TYPE_CONFIG, + WLAN_DIAG_TYPE_EVENT, + WLAN_DIAG_TYPE_LOG, + WLAN_DIAG_TYPE_MSG, + WLAN_DIAG_TYPE_LEGACY_MSG, +}; + +/* log/event are always 32-bit aligned. Padding is inserted after + * optional payload to satisfy this requirement + */ +struct wlan_diag_data { + unsigned int word0; /* type, length */ + unsigned int target_time; + unsigned int code; /* Diag log or event Code */ + uint8_t payload[]; +}; + +struct dbglog_slot { + unsigned int diag_type; + unsigned int timestamp; + unsigned int length; + unsigned int dropped; + /* max ATH6KL_FWLOG_PAYLOAD_SIZE bytes */ + uint8_t payload[]; +} __packed; + +typedef struct event_report_s { + unsigned int diag_type; + unsigned short event_id; + unsigned short length; +} event_report_t; + +/* + * Custom debug_print handlers + * Args: + * module Id + * vap id + * debug msg id + * Time stamp + * no of arguments + * pointer to the buffer holding the args + */ +typedef A_BOOL (*module_dbg_print)(A_UINT32, A_UINT16, A_UINT32, + A_UINT32, A_UINT16, A_UINT32 *); + +/** Register module specific dbg print*/ +void dbglog_reg_modprint(A_UINT32 mod_id, module_dbg_print printfn); + +#ifdef __cplusplus +} +#endif + +#endif /* _DBGLOG_COMMON_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/debug_linux.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/debug_linux.h new file mode 100644 index 0000000000..d91dd110f8 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/debug_linux.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2013-2016 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DEBUG_LINUX_H_ +#define _DEBUG_LINUX_H_ + +/* macro to remove parens */ +#define ATH_PRINTX_ARG(arg ...) arg + +#ifdef WLAN_DEBUG +/* NOTE: the AR_DEBUG_PRINTF macro is defined here to handle special handling of variable arg macros + * which may be compiler dependent. */ +#define AR_DEBUG_PRINTF(mask, args) do { \ + if (GET_ATH_MODULE_DEBUG_VAR_MASK(ATH_MODULE_NAME) & (mask)) { \ + A_LOGGER(mask, ATH_MODULE_NAME, ATH_PRINTX_ARG args); \ + } \ +} while (0) +#else +/* on non-debug builds, keep in error and warning messages in the driver, all other + * message tracing will get compiled out */ +#define AR_DEBUG_PRINTF(mask, args) \ + if ((mask) & (ATH_DEBUG_ERR | ATH_DEBUG_WARN)) { A_PRINTF(ATH_PRINTX_ARG args); } + +#endif + +#endif /* _DEBUG_LINUX_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/osapi_linux.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/osapi_linux.h new file mode 100644 index 0000000000..99504f9e99 --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/osapi_linux.h @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2013-2018, 2021 The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +/* ------------------------------------------------------------------------------ */ +/* This file contains the definitions of the basic atheros data types. */ +/* It is used to map the data types in atheros files to a platform specific */ +/* type. */ +/* ------------------------------------------------------------------------------ */ + +#ifndef _OSAPI_LINUX_H_ +#define _OSAPI_LINUX_H_ + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +/* #include */ +#include "a_types.h" + +#ifdef __GNUC__ +#define __ATTRIB_PACK __attribute__ ((packed)) +#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2))) +#define __ATTRIB_NORETURN __attribute__ ((noreturn)) +#ifndef INLINE +#define INLINE __inline__ +#endif +#else /* Not GCC */ +#define __ATTRIB_PACK +#define __ATTRIB_PRINTF +#define __ATTRIB_NORETURN +#ifndef INLINE +#define INLINE __inline +#endif +#endif /* End __GNUC__ */ + +#define PREPACK +#define POSTPACK __ATTRIB_PACK + +#define A_MEMCPY(dst, src, len) memcpy((A_UINT8 *)(dst), (src), (len)) +#define A_MEMZERO(addr, len) memset(addr, 0, len) +#define A_MEMSET(addr, value, size) memset((addr), (value), (size)) +#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len)) + +#define A_LOGGER(mask, mod, args ...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, args) +#define A_PRINTF(args ...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_QDF, args) +#define A_SNPRINTF(buf, len, args ...) snprintf(buf, len, args) +#define A_OFFSETOF(type, field) offsetof(type, field) + +/* + * Timer Functions + */ +#define A_MSLEEP(msecs) \ + { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout((HZ * (msecs)) / 1000); \ + set_current_state(TASK_RUNNING); \ + } + +typedef struct timer_list A_TIMER; + +/* + * Wait Queue related functions + */ +#ifndef wait_event_interruptible_timeout +#define __wait_event_interruptible_timeout(wq, condition, ret) \ + do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;; ) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + if (condition) \ + break; \ + if (!signal_pending(current)) { \ + ret = schedule_timeout(ret); \ + if (!ret) \ + break; \ + continue; \ + } \ + ret = -ERESTARTSYS; \ + break; \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ + } while (0) + +#define wait_event_interruptible_timeout(wq, condition, timeout) \ + ({ \ + long __ret = timeout; \ + if (!(condition)) \ + __wait_event_interruptible_timeout(wq, condition, __ret); \ + __ret; \ + }) +#endif /* wait_event_interruptible_timeout */ + +#ifdef WLAN_DEBUG +#ifdef A_SIMOS_DEVHOST +extern unsigned int panic_on_assert; +#define A_ASSERT(expr) \ + if (!(expr)) { \ + printk(KERN_ALERT "Debug Assert Caught, File %s, Line: %d, Test:%s\n", __FILE__, __LINE__, # expr); \ + if (panic_on_assert) panic(# expr); \ + } +#else +#define A_ASSERT(expr) \ + if (!(expr)) { \ + printk(KERN_ALERT "Debug Assert Caught, File %s, Line: %d, Test:%s\n", __FILE__, __LINE__, # expr); \ + } +#endif +#else +#define A_ASSERT(expr) +#endif /* DEBUG */ + +#ifdef ANDROID_ENV +struct firmware; +int android_request_firmware(const struct firmware **firmware_p, + const char *filename, struct device *device); +void android_release_firmware(const struct firmware *firmware); +#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) android_request_firmware(_ppf, _pfile, _dev) +#define A_RELEASE_FIRMWARE(_pf) android_release_firmware(_pf) +#else +#define A_REQUEST_FIRMWARE(_ppf, _pfile, _dev) request_firmware(_ppf, _pfile, _dev) +#define A_RELEASE_FIRMWARE(_pf) release_firmware(_pf) +#endif + +/* + * Network buffer queue support + */ +typedef struct sk_buff_head A_NETBUF_QUEUE_T; + +#define A_NETBUF_FREE(bufPtr) \ + a_netbuf_free(bufPtr) +#define A_NETBUF_LEN(bufPtr) \ + a_netbuf_to_len(bufPtr) +#define A_NETBUF_PUSH(bufPtr, len) \ + a_netbuf_push(bufPtr, len) +#define A_NETBUF_PUT(bufPtr, len) \ + a_netbuf_put(bufPtr, len) +#define A_NETBUF_TRIM(bufPtr, len) \ + a_netbuf_trim(bufPtr, len) +#define A_NETBUF_PULL(bufPtr, len) \ + a_netbuf_pull(bufPtr, len) +#define A_NETBUF_HEADROOM(bufPtr) \ + a_netbuf_headroom(bufPtr) +#define A_NETBUF_SETLEN(bufPtr, len) \ + a_netbuf_setlen(bufPtr, len) + +/* Add data to end of a buffer */ +#define A_NETBUF_PUT_DATA(bufPtr, srcPtr, len) \ + a_netbuf_put_data(bufPtr, srcPtr, len) + +/* Add data to start of the buffer */ +#define A_NETBUF_PUSH_DATA(bufPtr, srcPtr, len) \ + a_netbuf_push_data(bufPtr, srcPtr, len) + +/* Remove data at start of the buffer */ +#define A_NETBUF_PULL_DATA(bufPtr, dstPtr, len) \ + a_netbuf_pull_data(bufPtr, dstPtr, len) + +/* Remove data from the end of the buffer */ +#define A_NETBUF_TRIM_DATA(bufPtr, dstPtr, len) \ + a_netbuf_trim_data(bufPtr, dstPtr, len) + +/* View data as "size" contiguous bytes of type "t" */ +#define A_NETBUF_VIEW_DATA(bufPtr, t, size) \ + (t)(((struct skbuf *)(bufPtr))->data) + +/* return the beginning of the headroom for the buffer */ +#define A_NETBUF_HEAD(bufPtr) \ + ((((struct sk_buff *)(bufPtr))->head)) + +/* + * OS specific network buffer access routines + */ +void a_netbuf_free(void *bufPtr); +void *a_netbuf_to_data(void *bufPtr); +A_UINT32 a_netbuf_to_len(void *bufPtr); +A_STATUS a_netbuf_push(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_push_data(void *bufPtr, char *srcPtr, A_INT32 len); +A_STATUS a_netbuf_put(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_put_data(void *bufPtr, char *srcPtr, A_INT32 len); +A_STATUS a_netbuf_pull(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_pull_data(void *bufPtr, char *dstPtr, A_INT32 len); +A_STATUS a_netbuf_trim(void *bufPtr, A_INT32 len); +A_STATUS a_netbuf_trim_data(void *bufPtr, char *dstPtr, A_INT32 len); +A_STATUS a_netbuf_setlen(void *bufPtr, A_INT32 len); +A_INT32 a_netbuf_headroom(void *bufPtr); +void a_netbuf_enqueue(A_NETBUF_QUEUE_T *q, void *pkt); +void a_netbuf_prequeue(A_NETBUF_QUEUE_T *q, void *pkt); +void *a_netbuf_dequeue(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_size(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q); +int a_netbuf_queue_empty(A_NETBUF_QUEUE_T *q); +void a_netbuf_queue_init(A_NETBUF_QUEUE_T *q); + +#ifdef QCA_PARTNER_PLATFORM +#include "ath_carr_pltfrm.h" +#endif /* QCA_PARTNER_PLATFORM */ + +#else /* __KERNEL__ */ + +#ifdef __GNUC__ +#define __ATTRIB_PACK __attribute__ ((packed)) +#define __ATTRIB_PRINTF __attribute__ ((format (printf, 1, 2))) +#define __ATTRIB_NORETURN __attribute__ ((noreturn)) +#ifndef inline +#define inline __inline__ +#endif +#ifndef INLINE +#define INLINE __inline__ +#endif +#else /* Not GCC */ +#define __ATTRIB_PACK +#define __ATTRIB_PRINTF +#define __ATTRIB_NORETURN +#ifndef inline +#define inline __inline +#endif +#ifndef INLINE +#define INLINE __inline +#endif +#endif /* End __GNUC__ */ + +#define PREPACK +#define POSTPACK __ATTRIB_PACK + +#define A_MEMCPY(dst, src, len) memcpy((dst), (src), (len)) +#define A_MEMSET(addr, value, size) memset((addr), (value), (size)) +#define A_MEMZERO(addr, len) memset((addr), 0, (len)) +#define A_MEMCMP(addr1, addr2, len) memcmp((addr1), (addr2), (len)) + +#ifdef ANDROID +#ifndef err +#include +#define err(_s, args ...) do { \ + fprintf(stderr, "%s: line %d ", __FILE__, __LINE__); \ + fprintf(stderr, args); fprintf(stderr, ": %d\n", errno); \ + exit(_s); } while (0) +#endif +#else +#include +#endif + +#endif /* __KERNEL__ */ + +#endif /* _OSAPI_LINUX_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h new file mode 100644 index 0000000000..1e3e45f38f --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/uapi/linux/pktlog_ac_fmt.h @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2012-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for + * any purpose with or without fee is hereby granted, provided that the + * above copyright notice and this permission notice appear in all + * copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _PKTLOG_FMT_H_ +#define _PKTLOG_FMT_H_ + +#if defined(CONNECTIVITY_PKTLOG) || !defined(REMOVE_PKT_LOG) + +#define CUR_PKTLOG_VER 10010 /* Packet log version */ +#define PKTLOG_MAGIC_NUM 7735225 + +#ifdef __linux__ +#ifdef MULTI_IF_NAME +#define PKTLOG_PROC_DIR "ath_pktlog" MULTI_IF_NAME +#define WLANDEV_BASENAME "cld" MULTI_IF_NAME +#else +#define PKTLOG_PROC_DIR "ath_pktlog" +#define WLANDEV_BASENAME "cld" +#endif +#endif +#define PKTLOG_PROC_SYSTEM "system" +#ifdef WIN32 +#pragma pack(push, pktlog_fmt, 1) +#define __ATTRIB_PACK +#elif defined(__EFI__) +#define __ATTRIB_PACK +#else +#ifndef __ATTRIB_PACK +#define __ATTRIB_PACK __attribute__ ((packed)) +#endif +#endif +#include +/* + * Each packet log entry consists of the following fixed length header + * followed by variable length log information determined by log_type + */ + +struct ath_pktlog_hdr { + uint16_t flags; + uint16_t missed_cnt; +#ifdef HELIUMPLUS + uint8_t log_type; + uint8_t macId; +#else + uint16_t log_type; +#endif + uint16_t size; + uint32_t timestamp; +#ifdef PKTLOG_HAS_SPECIFIC_DATA + uint32_t type_specific_data; +#endif +} __ATTRIB_PACK; + +#define ATH_PKTLOG_HDR_FLAGS_MASK 0xffff +#define ATH_PKTLOG_HDR_FLAGS_SHIFT 0 +#define ATH_PKTLOG_HDR_FLAGS_OFFSET 0 +#define ATH_PKTLOG_HDR_MISSED_CNT_MASK 0xffff0000 +#define ATH_PKTLOG_HDR_MISSED_CNT_SHIFT 16 +#define ATH_PKTLOG_HDR_MISSED_CNT_OFFSET 0 +#ifdef HELIUMPLUS +#define ATH_PKTLOG_HDR_LOG_TYPE_MASK 0x00ff +#define ATH_PKTLOG_HDR_LOG_TYPE_SHIFT 0 +#define ATH_PKTLOG_HDR_LOG_TYPE_OFFSET 1 +#define ATH_PKTLOG_HDR_MAC_ID_MASK 0xff00 +#define ATH_PKTLOG_HDR_MAC_ID_SHIFT 8 +#define ATH_PKTLOG_HDR_MAC_ID_OFFSET 1 +#else +#define ATH_PKTLOG_HDR_LOG_TYPE_MASK 0xffff +#define ATH_PKTLOG_HDR_LOG_TYPE_SHIFT 0 +#define ATH_PKTLOG_HDR_LOG_TYPE_OFFSET 1 +#endif + +#define ATH_PKTLOG_HDR_SIZE_MASK 0xffff0000 +#define ATH_PKTLOG_HDR_SIZE_SHIFT 16 +#define ATH_PKTLOG_HDR_SIZE_OFFSET 1 +#define ATH_PKTLOG_HDR_TIMESTAMP_OFFSET 2 +#define ATH_PKTLOG_HDR_TYPE_SPECIFIC_DATA_OFFSET 3 + +/** + * enum - Pktlog flag field details + * @PKTLOG_FLG_FRM_TYPE_LOCAL_S: local-generated frame (tx) + * @PKTLOG_FLG_FRM_TYPE_REMOTE_S: remote-generated frame (rx) + * @PKTLOG_FLG_FRM_TYPE_CLONE_S: cloned frame + * @PKTLOG_FLG_FRM_TYPE_CBF_S: CBF remote frame + * @PKTLOG_FLG_FRM_TYPE_UNKNOWN_S: Unknown + * + * struct ath_pktlog_hdr flags field bit definitions, + * (use 1 << [enum] to assign) + */ +enum { + PKTLOG_FLG_FRM_TYPE_LOCAL_S = 0, + PKTLOG_FLG_FRM_TYPE_REMOTE_S, + PKTLOG_FLG_FRM_TYPE_CLONE_S, + PKTLOG_FLG_FRM_TYPE_CBF_S, + PKTLOG_FLG_FRM_TYPE_UNKNOWN_S +}; + +#define PHFLAGS_INTERRUPT_CONTEXT 0x80000000 + +/* Masks for setting pktlog events filters */ +#define ATH_PKTLOG_TX 0x000000001 +#define ATH_PKTLOG_RX 0x000000002 +#define ATH_PKTLOG_RCFIND 0x000000004 +#define ATH_PKTLOG_RCUPDATE 0x000000008 +#define ATH_PKTLOG_ANI 0x000000010 +#define ATH_PKTLOG_TEXT 0x000000020 +#define ATH_PKTLOG_PHYERR 0x000000040 +#define ATH_PKTLOG_PROMISC 0x000000080 +#define ATH_PKTLOG_SW_EVENT 0x000000100 + +/* WIN defns */ +#define ATH_PKTLOG_H_INFO 0x000000200 +#define ATH_PKTLOG_STEERING 0x000000400 +#define ATH_PKTLOG_REMOTE_LOGGING_ENABLE 0x000000800 +#define ATH_PKTLOG_TX_CAPTURE_ENABLE 0x000001000 +#define ATH_PKTLOG_LITE_T2H 0x000002000 +#define ATH_PKTLOG_LITE_RX 0x000004000 + +/* Types of packet log events */ +#define PKTLOG_TYPE_TX_CTRL 1 +#define PKTLOG_TYPE_TX_STAT 2 +#define PKTLOG_TYPE_TX_MSDU_ID 3 +#define PKTLOG_TYPE_TX_FRM_HDR 4 +#define PKTLOG_TYPE_RX_STAT 5 +#define PKTLOG_TYPE_RC_FIND 6 +#define PKTLOG_TYPE_RC_UPDATE 7 +#define PKTLOG_TYPE_TX_VIRT_ADDR 8 +#define PKTLOG_TYPE_SMART_ANTENNA 9 +#define PKTLOG_TYPE_SW_EVENT 10 +#define PKTLOG_TYPE_PKT_DUMP 11 +/* Command to process Monitor status ring (Rx) buffers */ +#define PKTLOG_TYPE_RX_STATBUF 22 +/* Command to process PPDU Tx buffers from CE */ +#define PKTLOG_TYPE_LITE_T2H 23 +/* Command to process PPDU Rx buffers from Monitor status ring */ +#define PKTLOG_TYPE_LITE_RX 24 +#define PKTLOG_TYPE_MAX 25 + +#define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ +#define PKTLOG_MAX_TXSTATUS_WORDS 32 +#define PKTLOG_MAX_PROTO_WORDS 16 +#define PKTLOG_MAX_RXDESC_WORDS 62 +#define PKTLOG_HDR_SIZE_16 0x8000 + +struct txctl_frm_hdr { + uint16_t framectrl; /* frame control field from header */ + uint16_t seqctrl; /* frame control field from header */ + uint16_t bssid_tail; /* last two octets of bssid */ + uint16_t sa_tail; /* last two octets of SA */ + uint16_t da_tail; /* last two octets of DA */ + uint16_t resvd; +}; + +#if defined(HELIUMPLUS) +/* Peregrine 11ac based */ +#define MAX_PKT_INFO_MSDU_ID 1 +#else +/* Peregrine 11ac based */ +#define MAX_PKT_INFO_MSDU_ID 192 +#endif /* defined(HELIUMPLUS) */ + +/* + * msdu_id_info_t is defined for reference only + */ +struct msdu_id_info { + uint32_t num_msdu; + uint8_t bound_bmap[(MAX_PKT_INFO_MSDU_ID + 7)>>3]; + /* TODO: + * Convert the id's to uint32_t + * Reduces computation in the driver code + */ + uint16_t id[MAX_PKT_INFO_MSDU_ID]; +} __ATTRIB_PACK; +#define MSDU_ID_INFO_NUM_MSDU_OFFSET 0 /* char offset */ +#define MSDU_ID_INFO_BOUND_BM_OFFSET offsetof(struct msdu_id_info, bound_bmap) +#define MSDU_ID_INFO_ID_OFFSET offsetof(struct msdu_id_info, id) + + +struct ath_pktlog_txctl { + struct ath_pktlog_hdr pl_hdr; + /* struct txctl_frm_hdr frm_hdr; */ + void *txdesc_hdr_ctl; /* frm_hdr + Tx descriptor words */ + struct { + struct txctl_frm_hdr frm_hdr; + uint32_t txdesc_ctl[PKTLOG_MAX_TXCTL_WORDS]; + /* uint32_t *proto_hdr; / * protocol header (variable length!) * / */ + /* uint32_t *misc; / * Can be used for HT specific or other misc info * / */ + } priv; +} __ATTRIB_PACK; + +struct ath_pktlog_tx_status { + struct ath_pktlog_hdr pl_hdr; + void *ds_status; + int32_t misc[]; /* Can be used for HT specific or other misc info */ +} __ATTRIB_PACK; + +struct ath_pktlog_msdu_info { + struct ath_pktlog_hdr pl_hdr; + void *ath_msdu_info; + A_UINT32 num_msdu; + struct { + /* + * Provision to add more information fields + */ + struct msdu_info_t { + A_UINT32 num_msdu; + A_UINT8 bound_bmap[MAX_PKT_INFO_MSDU_ID >> 3]; + } msdu_id_info; + /* + * array of num_msdu + * Static implementation will consume unwanted memory + * Need to split the pktlog_get_buf to get the buffer pointer only + */ + uint16_t msdu_len[MAX_PKT_INFO_MSDU_ID]; + } priv; + size_t priv_size; + +} __ATTRIB_PACK; + +struct ath_pktlog_rx_info { + struct ath_pktlog_hdr pl_hdr; + void *rx_desc; +} __ATTRIB_PACK; + +struct ath_pktlog_rc_find { + struct ath_pktlog_hdr pl_hdr; + void *rcFind; +} __ATTRIB_PACK; + +struct ath_pktlog_sw_event { + struct ath_pktlog_hdr pl_hdr; + void *sw_event; +} __ATTRIB_PACK; + +struct ath_pktlog_rc_update { + struct ath_pktlog_hdr pl_hdr; + void *txRateCtrl; /* rate control state proper */ +} __ATTRIB_PACK; + +#ifdef WIN32 +#pragma pack(pop, pktlog_fmt) +#endif +#ifdef __ATTRIB_PACK +#undef __ATTRIB_PACK +#endif /* __ATTRIB_PACK */ + +/* + * The following header is included in the beginning of the file, + * followed by log entries when the log buffer is read through procfs + */ + +struct ath_pktlog_bufhdr { + uint32_t magic_num; /* Used by post processing scripts */ + uint32_t version; /* Set to CUR_PKTLOG_VER */ +}; + +struct ath_pktlog_buf { + struct ath_pktlog_bufhdr bufhdr; + int32_t rd_offset; + volatile int32_t wr_offset; + /* Whenever this bytes written value croses 4K bytes, + * logging will be triggered + */ + int32_t bytes_written; + /* Index of the messages sent to userspace */ + uint32_t msg_index; + /* Offset for read */ + loff_t offset; + char log_data[]; +}; + +#define PKTLOG_MOV_RD_IDX(_rd_offset, _log_buf, _log_size) \ + do { \ + if ((_rd_offset + sizeof(struct ath_pktlog_hdr) + \ + ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size) <= _log_size) { \ + _rd_offset = ((_rd_offset) + sizeof(struct ath_pktlog_hdr) + \ + ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size); \ + } else { \ + _rd_offset = ((struct ath_pktlog_hdr *)((_log_buf)->log_data + \ + (_rd_offset)))->size; \ + } \ + (_rd_offset) = (((_log_size) - (_rd_offset)) >= \ + sizeof(struct ath_pktlog_hdr)) ? _rd_offset : 0; \ + } while (0) + +#endif /* REMOVE_PKT_LOG */ + +/** + * enum pkt_type - packet type + * @START_MONITOR: indicates parser to start packetdump parsing + * @STOP_MONITOR: indicates parser to stop packetdump parsing + * @TX_MGMT_PKT: TX management Packet + * @TX_DATA_PKT: TX data Packet + * @RX_MGMT_PKT: RX management Packet + * @RX_DATA_PKT: RX data Packet + * @INVALID_PKT: Invalid packet + * + * This enum has packet types + */ +enum pkt_type { + START_MONITOR = 1, + STOP_MONITOR, + TX_MGMT_PKT, + TX_DATA_PKT, + RX_MGMT_PKT, + RX_DATA_PKT, + INVALID_PKT, +}; + +/** + * enum tx_pkt_fate - tx packet fate + * @TX_PKT_FATE_ACKED: Sent over air and ACKed + * @TX_PKT_FATE_SENT: Sent over air but not ACKed. + * @TX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent over air + * @TX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware as invalid. + * E.g. bad source address, bad checksum, or invalid for current state. + * @TX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware due + * to lack of buffer space + * @TX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware for any other + * reason. Includes frames that were sent by driver to firmware, but + * unaccounted for by firmware. + * @TX_PKT_FATE_DRV_QUEUED: Queued within driver, not yet sent to firmware. + * @TX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. bad source address, or invalid for current state. + * @TX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver due to lack of buffer space + * @TX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * E.g. out of buffers. + * + * This enum has packet fate types + */ + +enum tx_pkt_fate { + TX_PKT_FATE_ACKED, + TX_PKT_FATE_SENT, + TX_PKT_FATE_FW_QUEUED, + TX_PKT_FATE_FW_DROP_INVALID, + TX_PKT_FATE_FW_DROP_NOBUFS, + TX_PKT_FATE_FW_DROP_OTHER, + TX_PKT_FATE_DRV_QUEUED, + TX_PKT_FATE_DRV_DROP_INVALID, + TX_PKT_FATE_DRV_DROP_NOBUFS, + TX_PKT_FATE_DRV_DROP_OTHER, +}; + +/** + * enum rx_pkt_fate - rx packet fate + * @RX_PKT_FATE_SUCCESS: Valid and delivered to + * network stack (e.g., netif_rx()). + * @RX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent to driver. + * @RX_PKT_FATE_FW_DROP_FILTER: Dropped by firmware + * due to host-programmable filters. + * @RX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware + * as invalid. E.g. bad checksum, decrypt failed, or invalid for current state. + * @RX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware + * due to lack of buffer space. + * @RX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware + * for any other reason. + * @RX_PKT_FATE_DRV_QUEUED: Queued within driver, + * not yet delivered to network stack. + * @RX_PKT_FATE_DRV_DROP_FILTER: Dropped by driver + * due to filter rules. + * @RX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. not permitted in current state. + * @RX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver + * due to lack of buffer space. + * @RX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * + * This enum has packet fate types + */ + +enum rx_pkt_fate { + RX_PKT_FATE_SUCCESS, + RX_PKT_FATE_FW_QUEUED, + RX_PKT_FATE_FW_DROP_FILTER, + RX_PKT_FATE_FW_DROP_INVALID, + RX_PKT_FATE_FW_DROP_NOBUFS, + RX_PKT_FATE_FW_DROP_OTHER, + RX_PKT_FATE_DRV_QUEUED, + RX_PKT_FATE_DRV_DROP_FILTER, + RX_PKT_FATE_DRV_DROP_INVALID, + RX_PKT_FATE_DRV_DROP_NOBUFS, + RX_PKT_FATE_DRV_DROP_OTHER, +}; + +#endif /* _PKTLOG_FMT_H_ */ diff --git a/qcom/opensource/wlan/qcacld-3.0/wlan_qcacld3_modules.bzl b/qcom/opensource/wlan/qcacld-3.0/wlan_qcacld3_modules.bzl new file mode 100644 index 0000000000..72ca07895b --- /dev/null +++ b/qcom/opensource/wlan/qcacld-3.0/wlan_qcacld3_modules.bzl @@ -0,0 +1,2389 @@ +load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir") +load("//build/kernel/kleaf:kernel.bzl", "ddk_module") +load("//msm-kernel:target_variants.bzl", "get_all_variants") + +_target_chipset_map = { + "niobe": [ + "kiwi-v2", + ], + "pineapple": [ + "peach-v2", + "peach", + "kiwi-v2", + "qca6750", + ], + "sun": [ + "peach-v2", + "peach", + "kiwi-v2", + ], + "volcano": [ + "qca6750", + "peach-v2", + ], + "parrot": [ + "qca6750", + "adrastea", + ], +} + +_chipset_hw_map = { + "kiwi-v2": "BERYLLIUM", + "peach": "BERYLLIUM", + "peach-v2": "BERYLLIUM", + "qca6750": "MOSELLE", + "adrastea" : "ADRASTEA", +} + +_chipset_header_map = { + "peach-v2": [ + "api/hw/peach/v2", + "cmn/hal/wifi3.0/peach", + ], + "peach": [ + "api/hw/peach/v1", + "cmn/hal/wifi3.0/peach", + ], + "kiwi-v2": [ + "api/hw/kiwi/v2", + "cmn/hal/wifi3.0/kiwi", + ], + "qca6750" : [ + "api/hw/qca6750/v1", + "cmn/hal/wifi3.0/qca6750", + ], + "adrastea" : [ + ], +} + +_hw_header_map = { + "BERYLLIUM": [ + "cmn/hal/wifi3.0/be", + ], + "MOSELLE" : [ + "cmn/hal/wifi3.0/li", + ], + "ADRASTEA" : [ + ], +} + +_fixed_includes = [ + "configs/default_config.h", + "configs/config_to_feature.h", +] + +_fixed_ipaths = [ + "api/fw", + "cmn/cfg/inc", + "cmn/coex/dispatcher/inc", + "cmn/dp/cmn_dp_api", + "cmn/dp/inc", + "cmn/dp/wifi3.0", + "cmn/dp/wifi3.0/be", + "cmn/dp/wifi3.0/monitor", + "cmn/dp/wifi3.0/monitor/1.0", + "cmn/dp/wifi3.0/monitor/2.0", + "cmn/ftm/core/src", + "cmn/ftm/dispatcher/inc", + "cmn/global_lmac_if/inc", + "cmn/global_lmac_if/src", + "cmn/gpio/core/inc", + "cmn/gpio/dispatcher/inc", + "cmn/hal/wifi3.0", + "cmn/hif/inc", + "cmn/hif/src", + "cmn/hif/src/ce", + "cmn/hif/src/dispatcher", + "cmn/hif/src/pcie", + "cmn/hif/src/ipcie", + "cmn/hif/src/snoc", + "cmn/htc", + "cmn/init_deinit/dispatcher/inc", + "cmn/ipa/core/inc", + "cmn/ipa/dispatcher/inc", + "cmn/os_if/linux", + "cmn/os_if/linux/afc/inc", + "cmn/os_if/linux/cp_stats/inc", + "cmn/os_if/linux/crypto/inc", + "cmn/os_if/linux/ftm/inc", + "cmn/os_if/linux/ftm/src", + "cmn/os_if/linux/gpio/inc", + "cmn/os_if/linux/mlme/inc", + "cmn/os_if/linux/scan/inc", + "cmn/os_if/linux/spectral/inc", + "cmn/os_if/linux/twt/inc", + "cmn/os_if/linux/wifi_pos/inc", + "cmn/qal/inc", + "cmn/qal/linux/src", + "cmn/qdf/inc", + "cmn/qdf/linux/src", + "cmn/qdf/test", + "cmn/scheduler/inc", + "cmn/spectral/core", + "cmn/spectral/dispatcher/inc", + "cmn/target_if/cfr/inc", + "cmn/target_if/core/inc", + "cmn/target_if/core/src", + "cmn/target_if/cp_stats/inc", + "cmn/target_if/crypto/inc", + "cmn/target_if/dcs/inc", + "cmn/target_if/dfs/inc", + "cmn/target_if/direct_buf_rx/inc", + "cmn/target_if/direct_buf_rx/src", + "cmn/target_if/dispatcher/inc", + "cmn/target_if/dp/inc", + "cmn/target_if/ftm/inc", + "cmn/target_if/gpio", + "cmn/target_if/green_ap/inc", + "cmn/target_if/init_deinit/inc", + "cmn/target_if/ipa/inc", + "cmn/target_if/mlme/psoc/inc", + "cmn/target_if/mlme/vdev_mgr/inc", + "cmn/target_if/mlo_mgr/inc", + "cmn/target_if/regulatory/inc", + "cmn/target_if/scan/inc", + "cmn/target_if/son/inc", + "cmn/target_if/spatial_reuse/inc", + "cmn/target_if/spectral", + "cmn/target_if/twt/inc", + "cmn/target_if/wifi_pos/inc", + "cmn/umac", + "cmn/umac/afc/core/inc", + "cmn/umac/afc/dispatcher/inc", + "cmn/umac/cfr/core/inc", + "cmn/umac/cfr/dispatcher/inc", + "cmn/umac/cmn_services/cmn_defs/inc", + "cmn/umac/cmn_services/crypto/inc", + "cmn/umac/cmn_services/crypto/src", + "cmn/umac/cmn_services/inc", + "cmn/umac/cmn_services/interface_mgr/inc", + "cmn/umac/cmn_services/mgmt_txrx/dispatcher/inc", + "cmn/umac/cmn_services/obj_mgr/inc", + "cmn/umac/cmn_services/obj_mgr/src", + "cmn/umac/cmn_services/regulatory/inc", + "cmn/umac/cmn_services/serialization/inc", + "cmn/umac/cmn_services/sm_engine/inc", + "cmn/umac/cmn_services/utils/inc", + "cmn/umac/cp_stats/dispatcher/inc", + "cmn/umac/dcs/dispatcher/inc", + "cmn/umac/dfs/dispatcher/inc", + "cmn/umac/global_umac_dispatcher/lmac_if/inc", + "cmn/umac/green_ap/dispatcher/inc", + "cmn/umac/mlme", + "cmn/umac/mlme/connection_mgr/dispatcher/inc", + "cmn/umac/mlme/connection_mgr/utf/inc", + "cmn/umac/mlme/include", + "cmn/umac/mlme/mlme_objmgr/dispatcher/inc", + "cmn/umac/mlme/mlme_utils", + "cmn/umac/mlme/pdev_mgr/dispatcher/inc", + "cmn/umac/mlme/psoc_mgr/dispatcher/inc", + "cmn/umac/mlme/vdev_mgr/dispatcher/inc", + "cmn/umac/mlo_mgr/inc", + "cmn/umac/regulatory/dispatcher/inc", + "cmn/umac/regulatory/core/inc", + "cmn/umac/regulatory/core/src", + "cmn/umac/scan/dispatcher/inc", + "cmn/umac/thermal/dispatcher/inc", + "cmn/umac/twt/dispatcher/inc", + "cmn/umac/wifi_pos/inc", + "cmn/umac/wifi_radar/core/inc", + "cmn/umac/wifi_radar/dispatcher/inc", + "cmn/utils/epping/inc", + "cmn/utils/fwlog", + "cmn/utils/host_diag_log/inc", + "cmn/utils/host_diag_log/src", + "cmn/utils/logging/inc", + "cmn/utils/nlink/inc", + "cmn/utils/pktlog/include", + "cmn/utils/ptt/inc", + "cmn/utils/sys", + "cmn/wbuff/inc", + "cmn/wbuff/src", + "cmn/wlan_cfg", + "cmn/wmi/inc", + "cmn/wmi/src", + "components/action_oui/core/inc", + "components/action_oui/dispatcher/inc", + "components/cfg", + "components/cmn_services/interface_mgr/inc", + "components/cmn_services/logging/inc", + "components/cmn_services/policy_mgr/inc", + "components/cmn_services/policy_mgr/src", + "components/coap/core/inc", + "components/coap/dispatcher/inc", + "components/coex/core/inc", + "components/coex/dispatcher/inc", + "components/cp_stats/dispatcher/inc", + "components/target_if/mlme/inc", + "components/denylist_mgr/core/inc", + "components/denylist_mgr/dispatcher/inc", + "components/disa/core/inc", + "components/disa/dispatcher/inc", + "components/dp/core/inc", + "components/dp/core/src", + "components/dp/dispatcher/inc", + "components/dsc/inc", + "components/dsc/src", + "components/dsc/test", + "components/ftm_time_sync/core/inc", + "components/ftm_time_sync/dispatcher/inc", + "components/fw_offload/core/inc", + "components/fw_offload/dispatcher/inc", + "components/interop_issues_ap/core/inc", + "components/interop_issues_ap/dispatcher/inc", + "components/mlme/core/inc", + "components/mlme/core/src", + "components/mlme/dispatcher/inc", + "components/nan/core/inc", + "components/nan/core/src", + "components/nan/dispatcher/inc", + "components/ocb/core/inc", + "components/ocb/dispatcher/inc", + "components/p2p/dispatcher/inc", + "components/p2p/core/src", + "components/pkt_capture/core/inc", + "components/pkt_capture/dispatcher/inc", + "components/pmo/core/inc", + "components/pmo/core/src", + "components/pmo/dispatcher/inc", + "components/pmo/dispatcher/src", + "components/pre_cac/dispatcher/inc", + "components/pre_cac/core/src", + "components/qmi/core/inc", + "components/qmi/core/src", + "components/qmi/dispatcher/inc", + "components/son/dispatcher/inc", + "components/spatial_reuse/dispatcher/inc", + "components/target_if/action_oui/inc", + "components/target_if/coap/inc", + "components/target_if/coex/inc", + "components/target_if/connection_mgr/inc", + "components/target_if/denylist_mgr/inc", + "components/target_if/disa/inc", + "components/target_if/dp/inc", + "components/target_if/fw_offload/inc", + "components/target_if/interop_issues_ap/inc", + "components/target_if/nan/inc", + "components/target_if/p2p/inc", + "components/target_if/pkt_capture/inc", + "components/target_if/pmo/inc", + "components/target_if/pmo/src", + "components/target_if/sap/ll_sap/inc", + "components/target_if/tdls/inc", + "components/target_if/wfa_config/inc", + "components/tdls/dispatcher/inc", + "components/tdls/core/inc", + "components/tdls/core/src", + "components/umac", + "components/umac/mlme/connection_mgr/dispatcher/inc", + "components/umac/mlme/connection_mgr/utf/inc", + "components/umac/mlme/mlo_mgr/inc", + "components/umac/mlme/mlo_mgr/dispatcher/inc", + "components/umac/mlme/wfa_config/dispatcher/inc", + "components/umac/mlme/sap/ll_sap/dispatcher/inc", + "components/umac/twt/dispatcher/inc", + "components/wifi_pos/core/inc", + "components/wifi_pos/dispatcher/inc", + "components/wmi/inc", + "components/wmi/src", + "core/bmi/inc", + "core/cds/inc", + "core/cds/src", + "core/dp/htt", + "core/dp/ol/inc", + "core/dp/txrx", + "core/hdd/inc", + "core/hdd/src", + "core/mac/inc", + "core/mac/src/dph", + "core/mac/src/include", + "core/mac/src/pe/include", + "core/mac/src/pe/lim", + "core/mac/src/pe/nan", + "core/mac/src/sys/common/inc", + "core/mac/src/sys/legacy/src/platform/inc", + "core/mac/src/sys/legacy/src/system/inc", + "core/mac/src/sys/legacy/src/utils/inc", + "core/pld/inc", + "core/pld/src", + "core/sap/inc", + "core/sap/src", + "core/sme/inc", + "core/sme/src/common", + "core/sme/src/csr", + "core/sme/src/nan", + "core/sme/src/qos", + "core/sme/src/rrm", + "core/wma/inc", + "core/wma/src", + "os_if/coap/inc", + "os_if/coex/inc", + "os_if/cp_stats/inc", + "os_if/dp/inc", + "os_if/fw_offload/inc", + "os_if/interop_issues_ap/inc", + "os_if/mlme/sap/ll_sap/inc", + "os_if/nan/inc", + "os_if/p2p/inc", + "os_if/pkt_capture/inc", + "os_if/pre_cac/inc", + "os_if/qmi/inc", + "os_if/son/inc", + "os_if/sync/inc", + "os_if/sync/src", + "os_if/tdls/inc", + "os_if/twt/inc", + "uapi/linux", +] + +# paths where include files are private in src folders +_private_ipaths = [ + "cmn/os_if/linux/mlme/src", +] + +_fixed_srcs = [ + "cmn/cfg/src/cfg.c", + "cmn/global_lmac_if/src/wlan_global_lmac_if.c", + "cmn/hif/src/ath_procfs.c", + "cmn/hif/src/ce/ce_diag.c", + "cmn/hif/src/ce/ce_main.c", + "cmn/hif/src/ce/ce_service.c", + "cmn/hif/src/ce/ce_tasklet.c", + "cmn/hif/src/dispatcher/dummy.c", + "cmn/hif/src/dispatcher/multibus.c", + "cmn/hif/src/hif_exec.c", + "cmn/hif/src/hif_main.c", + "cmn/hif/src/hif_runtime_pm.c", + "cmn/hif/src/mp_dev.c", + "cmn/hif/src/regtable.c", + "cmn/htc/htc.c", + "cmn/htc/htc_recv.c", + "cmn/htc/htc_send.c", + "cmn/htc/htc_services.c", + "cmn/init_deinit/dispatcher/src/dispatcher_init_deinit.c", + "cmn/os_if/linux/crypto/src/wlan_cfg80211_crypto.c", + "cmn/os_if/linux/crypto/src/wlan_nl_to_crypto_params.c", + "cmn/os_if/linux/mlme/src/osif_cm_connect_rsp.c", + "cmn/os_if/linux/mlme/src/osif_cm_disconnect_rsp.c", + "cmn/os_if/linux/mlme/src/osif_cm_req.c", + "cmn/os_if/linux/mlme/src/osif_cm_roam_rsp.c", + "cmn/os_if/linux/mlme/src/osif_cm_util.c", + "cmn/os_if/linux/mlme/src/osif_vdev_mgr_util.c", + "cmn/os_if/linux/scan/src/wlan_cfg80211_scan.c", + "cmn/os_if/linux/wlan_cfg80211.c", + "cmn/os_if/linux/wlan_osif_request_manager.c", + "cmn/qdf/linux/src/qdf_crypto.c", + "cmn/qdf/linux/src/qdf_defer.c", + "cmn/qdf/linux/src/qdf_delayed_work.c", + "cmn/qdf/linux/src/qdf_event.c", + "cmn/qdf/linux/src/qdf_file.c", + "cmn/qdf/linux/src/qdf_func_tracker.c", + "cmn/qdf/linux/src/qdf_idr.c", + "cmn/qdf/linux/src/qdf_list.c", + "cmn/qdf/linux/src/qdf_lock.c", + "cmn/qdf/linux/src/qdf_mc_timer.c", + "cmn/qdf/linux/src/qdf_mem.c", + "cmn/qdf/linux/src/qdf_nbuf.c", + "cmn/qdf/linux/src/qdf_nbuf_frag.c", + "cmn/qdf/linux/src/qdf_periodic_work.c", + "cmn/qdf/linux/src/qdf_status.c", + "cmn/qdf/linux/src/qdf_threads.c", + "cmn/qdf/linux/src/qdf_trace.c", + "cmn/qdf/src/qdf_flex_mem.c", + "cmn/qdf/src/qdf_parse.c", + "cmn/qdf/src/qdf_platform.c", + "cmn/qdf/src/qdf_str.c", + "cmn/qdf/src/qdf_talloc.c", + "cmn/qdf/src/qdf_types.c", + "cmn/scheduler/src/scheduler_api.c", + "cmn/scheduler/src/scheduler_core.c", + "cmn/target_if/core/src/target_if_main.c", + "cmn/target_if/crypto/src/target_if_crypto.c", + "cmn/target_if/init_deinit/src/init_cmd_api.c", + "cmn/target_if/init_deinit/src/init_deinit_lmac.c", + "cmn/target_if/init_deinit/src/init_event_handler.c", + "cmn/target_if/init_deinit/src/service_ready_util.c", + "cmn/target_if/mlme/psoc/src/target_if_psoc_timer_tx_ops.c", + "cmn/target_if/mlme/vdev_mgr/src/target_if_vdev_mgr_rx_ops.c", + "cmn/target_if/mlme/vdev_mgr/src/target_if_vdev_mgr_tx_ops.c", + "cmn/target_if/regulatory/src/target_if_reg_11d.c", + "cmn/target_if/regulatory/src/target_if_reg.c", + "cmn/target_if/regulatory/src/target_if_reg_lte.c", + "cmn/target_if/scan/src/target_if_scan.c", + "cmn/umac/cmn_services/crypto/src/wlan_crypto_global_api.c", + "cmn/umac/cmn_services/crypto/src/wlan_crypto_main.c", + "cmn/umac/cmn_services/crypto/src/wlan_crypto_obj_mgr.c", + "cmn/umac/cmn_services/crypto/src/wlan_crypto_param_handling.c", + "cmn/umac/cmn_services/crypto/src/wlan_crypto_ucfg_api.c", + "cmn/umac/cmn_services/interface_mgr/src/wlan_if_mgr_core.c", + "cmn/umac/cmn_services/interface_mgr/src/wlan_if_mgr_main.c", + "cmn/umac/cmn_services/mgmt_txrx/core/src/wlan_mgmt_txrx_main.c", + "cmn/umac/cmn_services/mgmt_txrx/dispatcher/src/wlan_mgmt_txrx_tgt_api.c", + "cmn/umac/cmn_services/mgmt_txrx/dispatcher/src/wlan_mgmt_txrx_utils_api.c", + "cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_global_obj.c", + "cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_pdev_obj.c", + "cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_peer_obj.c", + "cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c", + "cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_api.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_internal.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_legacy_api.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_main.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_non_scan.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_queue.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_rules.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_scan.c", + "cmn/umac/cmn_services/serialization/src/wlan_serialization_utils.c", + "cmn/umac/cmn_services/sm_engine/src/wlan_sm_engine.c", + "cmn/umac/cmn_services/utils/src/wlan_utility.c", + "cmn/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_bss_scoring.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_connect.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_connect_scan.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_disconnect.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_main.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_roam_sm.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_sm.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_util.c", + "cmn/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_api.c", + "cmn/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_ucfg_api.c", + "cmn/umac/mlme/mlme_objmgr/dispatcher/src/wlan_cmn_mlme_main.c", + "cmn/umac/mlme/mlme_objmgr/dispatcher/src/wlan_pdev_mlme_main.c", + "cmn/umac/mlme/mlme_objmgr/dispatcher/src/wlan_psoc_mlme_main.c", + "cmn/umac/mlme/mlme_objmgr/dispatcher/src/wlan_vdev_mlme_main.c", + "cmn/umac/mlme/mlme_utils/wlan_vdev_mlme_ser_if.c", + "cmn/umac/mlme/pdev_mgr/dispatcher/src/wlan_pdev_mlme_api.c", + "cmn/umac/mlme/psoc_mgr/dispatcher/src/wlan_psoc_mlme_api.c", + "cmn/umac/mlme/psoc_mgr/dispatcher/src/wlan_psoc_mlme_ucfg_api.c", + "cmn/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c", + "cmn/umac/mlme/vdev_mgr/core/src/vdev_mlme_sm.c", + "cmn/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_api.c", + "cmn/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_tgt_if_rx_api.c", + "cmn/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_tgt_if_tx_api.c", + "cmn/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_ucfg_api.c", + "cmn/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mgr_utils_api.c", + "cmn/umac/mlme/vdev_mgr/dispatcher/src/wlan_vdev_mlme_api.c", + "cmn/umac/regulatory/core/src/reg_build_chan_list.c", + "cmn/umac/regulatory/core/src/reg_callbacks.c", + "cmn/umac/regulatory/core/src/reg_db.c", + "cmn/umac/regulatory/core/src/reg_db_parser.c", + "cmn/umac/regulatory/core/src/reg_lte.c", + "cmn/umac/regulatory/core/src/reg_offload_11d_scan.c", + "cmn/umac/regulatory/core/src/reg_opclass.c", + "cmn/umac/regulatory/core/src/reg_priv_objs.c", + "cmn/umac/regulatory/core/src/reg_services_common.c", + "cmn/umac/regulatory/core/src/reg_utils.c", + "cmn/umac/regulatory/dispatcher/src/wlan_reg_services_api.c", + "cmn/umac/regulatory/dispatcher/src/wlan_reg_tgt_api.c", + "cmn/umac/regulatory/dispatcher/src/wlan_reg_ucfg_api.c", + "cmn/umac/scan/core/src/wlan_scan_11d.c", + "cmn/umac/scan/core/src/wlan_scan_cache_db.c", + "cmn/umac/scan/core/src/wlan_scan_filter.c", + "cmn/umac/scan/core/src/wlan_scan_main.c", + "cmn/umac/scan/core/src/wlan_scan_manager.c", + "cmn/umac/scan/dispatcher/src/wlan_scan_api.c", + "cmn/umac/scan/dispatcher/src/wlan_scan_tgt_api.c", + "cmn/umac/scan/dispatcher/src/wlan_scan_ucfg_api.c", + "cmn/umac/scan/dispatcher/src/wlan_scan_utils_api.c", + "cmn/utils/logging/src/wlan_logging_sock_svc.c", + "cmn/utils/logging/src/wlan_roam_debug.c", + "cmn/utils/nlink/src/wlan_nlink_srv.c", + "cmn/utils/ptt/src/wlan_ptt_sock_svc.c", + "cmn/wmi/src/wmi_tlv_helper.c", + "cmn/wmi/src/wmi_tlv_platform.c", + "cmn/wmi/src/wmi_unified_api.c", + "cmn/wmi/src/wmi_unified.c", + "cmn/wmi/src/wmi_unified_crypto_api.c", + "cmn/wmi/src/wmi_unified_p2p_api.c", + "cmn/wmi/src/wmi_unified_p2p_tlv.c", + "cmn/wmi/src/wmi_unified_reg_api.c", + "cmn/wmi/src/wmi_unified_tlv.c", + "cmn/wmi/src/wmi_unified_vdev_api.c", + "cmn/wmi/src/wmi_unified_vdev_tlv.c", + "components/cmn_services/interface_mgr/src/wlan_if_mgr_roam.c", + "components/cmn_services/interface_mgr/src/wlan_if_mgr_sap.c", + "components/cmn_services/interface_mgr/src/wlan_if_mgr_sta.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_action.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_core.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_get_set_utils.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_init_deinit.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_pcl.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_ucfg.c", + "components/dp/core/src/wlan_dp_bus_bandwidth.c", + "components/dp/core/src/wlan_dp_main.c", + "components/dp/core/src/wlan_dp_softap_txrx.c", + "components/dp/core/src/wlan_dp_txrx.c", + "components/dp/dispatcher/src/wlan_dp_api.c", + "components/dp/dispatcher/src/wlan_dp_ucfg_api.c", + "components/dsc/src/__wlan_dsc.c", + "components/dsc/src/wlan_dsc_driver.c", + "components/dsc/src/wlan_dsc_psoc.c", + "components/dsc/src/wlan_dsc_vdev.c", + "components/mlme/core/src/wlan_mlme_main.c", + "components/mlme/core/src/wlan_mlme_vdev_mgr_interface.c", + "components/mlme/core/src/wlan_mlme_twt_api.c", + "components/mlme/dispatcher/src/wlan_mlme_api.c", + "components/mlme/dispatcher/src/wlan_mlme_ucfg_api.c", + "components/p2p/core/src/wlan_p2p_main.c", + "components/p2p/core/src/wlan_p2p_off_chan_tx.c", + "components/p2p/core/src/wlan_p2p_roc.c", + "components/p2p/dispatcher/src/wlan_p2p_api.c", + "components/p2p/dispatcher/src/wlan_p2p_cfg.c", + "components/p2p/dispatcher/src/wlan_p2p_tgt_api.c", + "components/p2p/dispatcher/src/wlan_p2p_ucfg_api.c", + "components/target_if/connection_mgr/src/target_if_cm_roam_event.c", + "components/target_if/connection_mgr/src/target_if_cm_roam_offload.c", + "components/target_if/dp/src/target_if_dp_comp.c", + "components/target_if/p2p/src/target_if_p2p.c", + "components/target_if/wfa_config/src/target_if_wfa_testcmd.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_connect.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_vdev_disconnect.c", + "components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_api.c", + "components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_roam_ucfg_api.c", + "components/umac/mlme/connection_mgr/dispatcher/src/wlan_cm_tgt_if_tx_api.c", + "components/umac/mlme/wfa_config/dispatcher/src/wlan_wfa_tgt_if_tx_api.c", + "core/cds/src/cds_api.c", + "core/cds/src/cds_packet.c", + "core/cds/src/cds_regdomain.c", + "core/cds/src/cds_reg_service.c", + "core/cds/src/cds_sched.c", + "core/cds/src/cds_utils.c", + "core/hdd/src/wlan_hdd_assoc.c", + "core/hdd/src/wlan_hdd_cfg80211.c", + "core/hdd/src/wlan_hdd_cfg.c", + "core/hdd/src/wlan_hdd_cm_connect.c", + "core/hdd/src/wlan_hdd_cm_disconnect.c", + "core/hdd/src/wlan_hdd_data_stall_detection.c", + "core/hdd/src/wlan_hdd_driver_ops.c", + "core/hdd/src/wlan_hdd_ftm.c", + "core/hdd/src/wlan_hdd_hostapd.c", + "core/hdd/src/wlan_hdd_ioctl.c", + "core/hdd/src/wlan_hdd_main.c", + "core/hdd/src/wlan_hdd_ll_lt_sap.c", + "core/hdd/src/wlan_hdd_object_manager.c", + "core/hdd/src/wlan_hdd_oemdata.c", + "core/hdd/src/wlan_hdd_p2p.c", + "core/hdd/src/wlan_hdd_power.c", + "core/hdd/src/wlan_hdd_regulatory.c", + "core/hdd/src/wlan_hdd_scan.c", + "core/hdd/src/wlan_hdd_softap_tx_rx.c", + "core/hdd/src/wlan_hdd_sta_info.c", + "core/hdd/src/wlan_hdd_stats.c", + "core/hdd/src/wlan_hdd_trace.c", + "core/hdd/src/wlan_hdd_tx_rx.c", + "core/hdd/src/wlan_hdd_wmm.c", + "core/hdd/src/wlan_hdd_wowl.c", + "core/mac/src/dph/dph_hash_table.c", + "core/mac/src/pe/lim/lim_admit_control.c", + "core/mac/src/pe/lim/lim_api.c", + "core/mac/src/pe/lim/lim_assoc_utils.c", + "core/mac/src/pe/lim/lim_ft.c", + "core/mac/src/pe/lim/lim_link_monitoring_algo.c", + "core/mac/src/pe/lim/lim_process_action_frame.c", + "core/mac/src/pe/lim/lim_process_assoc_req_frame.c", + "core/mac/src/pe/lim/lim_process_assoc_rsp_frame.c", + "core/mac/src/pe/lim/lim_process_auth_frame.c", + "core/mac/src/pe/lim/lim_process_beacon_frame.c", + "core/mac/src/pe/lim/lim_process_cfg_updates.c", + "core/mac/src/pe/lim/lim_process_deauth_frame.c", + "core/mac/src/pe/lim/lim_process_disassoc_frame.c", + "core/mac/src/pe/lim/lim_process_message_queue.c", + "core/mac/src/pe/lim/lim_process_mlm_req_messages.c", + "core/mac/src/pe/lim/lim_process_mlm_rsp_messages.c", + "core/mac/src/pe/lim/lim_process_probe_req_frame.c", + "core/mac/src/pe/lim/lim_process_probe_rsp_frame.c", + "core/mac/src/pe/lim/lim_process_sme_req_messages.c", + "core/mac/src/pe/lim/lim_prop_exts_utils.c", + "core/mac/src/pe/lim/lim_scan_result_utils.c", + "core/mac/src/pe/lim/lim_security_utils.c", + "core/mac/src/pe/lim/lim_send_management_frames.c", + "core/mac/src/pe/lim/lim_send_messages.c", + "core/mac/src/pe/lim/lim_send_sme_rsp_messages.c", + "core/mac/src/pe/lim/lim_session.c", + "core/mac/src/pe/lim/lim_session_utils.c", + "core/mac/src/pe/lim/lim_sme_req_utils.c", + "core/mac/src/pe/lim/lim_timer_utils.c", + "core/mac/src/pe/lim/lim_trace.c", + "core/mac/src/pe/lim/lim_utils.c", + "core/mac/src/pe/lim/lim_aid_mgmt.c", + "core/mac/src/pe/rrm/rrm_api.c", + "core/mac/src/pe/sch/sch_api.c", + "core/mac/src/pe/sch/sch_beacon_gen.c", + "core/mac/src/pe/sch/sch_beacon_process.c", + "core/mac/src/pe/sch/sch_message.c", + "core/mac/src/sys/common/src/wlan_qct_sys.c", + "core/mac/src/sys/legacy/src/platform/src/sys_wrapper.c", + "core/mac/src/sys/legacy/src/system/src/mac_init_api.c", + "core/mac/src/sys/legacy/src/system/src/sys_entry_func.c", + "core/mac/src/sys/legacy/src/utils/src/dot11f.c", + "core/mac/src/sys/legacy/src/utils/src/mac_trace.c", + "core/mac/src/sys/legacy/src/utils/src/parser_api.c", + "core/mac/src/sys/legacy/src/utils/src/utils_parser.c", + "core/pld/src/pld_common.c", + "core/sap/src/sap_api_link_cntl.c", + "core/sap/src/sap_ch_select.c", + "core/sap/src/sap_fsm.c", + "core/sap/src/sap_module.c", + "core/sme/src/common/sme_api.c", + "core/sme/src/common/sme_power_save.c", + "core/sme/src/common/sme_trace.c", + "core/sme/src/csr/csr_api_roam.c", + "core/sme/src/csr/csr_api_scan.c", + "core/sme/src/csr/csr_cmd_process.c", + "core/sme/src/csr/csr_link_list.c", + "core/sme/src/csr/csr_util.c", + "core/sme/src/qos/sme_qos.c", + "core/sme/src/rrm/sme_rrm.c", + "core/wma/src/wlan_qct_wma_legacy.c", + "core/wma/src/wma_data.c", + "core/wma/src/wma_dev_if.c", + "core/wma/src/wma_features.c", + "core/wma/src/wma_main.c", + "core/wma/src/wma_mgmt.c", + "core/wma/src/wma_power.c", + "core/wma/src/wma_scan_roam.c", + "core/wma/src/wma_utils.c", + "os_if/dp/src/os_if_dp.c", + "os_if/dp/src/os_if_dp_txrx.c", + "os_if/p2p/src/wlan_cfg80211_p2p.c", + "os_if/sync/src/osif_driver_sync.c", + "os_if/sync/src/osif_psoc_sync.c", + "os_if/sync/src/osif_sync.c", + "os_if/sync/src/osif_vdev_sync.c", +] + +_conditional_srcs = { + "CONFIG_BAND_6GHZ": { + True: [ + "cmn/umac/scan/core/src/wlan_scan_manager_6ghz.c", + ], + }, + "CONFIG_BERYLLIUM": { + True: [ + # TODO: how to handle Kbuild logic + #ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) + #ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) + "cmn/dp/cmn_dp_api/dp_ratetable.c", + "cmn/dp/wifi3.0/be/dp_be.c", + "cmn/dp/wifi3.0/be/dp_be_rx.c", + "cmn/dp/wifi3.0/be/dp_be_tx.c", + "cmn/dp/wifi3.0/dp_reo.c", + "cmn/dp/wifi3.0/dp_rings_main.c", + "cmn/dp/wifi3.0/dp_rx_err.c", + "cmn/dp/wifi3.0/dp_rx_tid.c", + "cmn/hal/wifi3.0/be/hal_be_generic_api.c", + "cmn/hal/wifi3.0/be/hal_be_reo.c", + "cmn/hal/wifi3.0/hal_reo.c", + "cmn/hal/wifi3.0/hal_srng.c", + "cmn/hif/src/ce/ce_service_srng.c", + "cmn/wlan_cfg/wlan_cfg.c", + "components/dp/core/src/wlan_dp_prealloc.c", + ], + }, + "CONFIG_BUS_AUTO_SUSPEND": { + True: [ + #TODO: need SYSFS-specific flag + "core/hdd/src/wlan_hdd_sysfs_runtime_pm.c", + ], + }, + "CONFIG_CM_UTF_ENABLE": { + True: [ + "components/umac/mlme/connection_mgr/utf/src/cm_utf.c", + "cmn/umac/mlme/connection_mgr/utf/src/wlan_cm_utf_main.c", + "cmn/umac/mlme/connection_mgr/utf/src/wlan_cm_utf_scan.c", + ], + }, + "CONFIG_CNSS2_SSR_DRIVER_DUMP": { + True: [ + "cmn/qdf/linux/src/qdf_ssr_driver_dump.c", + ], + }, + "CONFIG_CNSS_KIWI_V2": { + True: [ + "cmn/hif/src/kiwidef.c", + ], + }, + "CONFIG_INCLUDE_HAL_KIWI": { + True: [ + "cmn/hal/wifi3.0/kiwi/hal_kiwi.c", + ], + }, + "CONFIG_INCLUDE_HAL_PEACH": { + True: [ + "cmn/hal/wifi3.0/peach/hal_peach.c", + ], + }, + "CONFIG_QCA6750_HEADERS_DEF": { + True: [ + "cmn/hal/wifi3.0/qca6750/hal_6750.c", + "cmn/hif/src/qca6750def.c", + ], + }, + "CONFIG_CP_STATS": { + True: [ + "cmn/target_if/cp_stats/src/target_if_cp_stats.c", + "cmn/umac/cp_stats/core/src/wlan_cp_stats_comp_handler.c", + "cmn/umac/cp_stats/core/src/wlan_cp_stats_obj_mgr_handler.c", + "cmn/umac/cp_stats/core/src/wlan_cp_stats_ol_api.c", + "cmn/umac/cp_stats/dispatcher/src/wlan_cp_stats_ucfg_api.c", + "cmn/umac/cp_stats/dispatcher/src/wlan_cp_stats_utils_api.c", + "cmn/wmi/src/wmi_unified_cp_stats_api.c", + "cmn/wmi/src/wmi_unified_cp_stats_tlv.c", + "components/cp_stats/dispatcher/src/wlan_cp_stats_mc_tgt_api.c", + "components/cp_stats/dispatcher/src/wlan_cp_stats_mc_ucfg_api.c", + "components/target_if/cp_stats/src/target_if_mc_cp_stats.c", + "components/wmi/src/wmi_unified_mc_cp_stats_api.c", + "components/wmi/src/wmi_unified_mc_cp_stats_tlv.c", + "os_if/cp_stats/src/wlan_cfg80211_mc_cp_stats.c", + ], + }, + "CONFIG_WLAN_CHIPSET_STATS": { + True: [ + "cmn/umac/cp_stats/core/src/wlan_cp_stats_chipset_stats.c", + ], + }, + "CONFIG_QCA_TARGET_IF_MLME": { + True: [ + "components/target_if/mlme/src/target_if_mlme.c", + "components/wmi/src/wmi_unified_mlme_api.c", + "components/wmi/src/wmi_unified_mlme_tlv.c", + ], + }, + "CONFIG_DCS": { + True: [ + "cmn/target_if/dcs/src/target_if_dcs.c", + "cmn/umac/dcs/core/src/wlan_dcs.c", + "cmn/umac/dcs/dispatcher/src/wlan_dcs_init_deinit_api.c", + "cmn/umac/dcs/dispatcher/src/wlan_dcs_tgt_api.c", + "cmn/umac/dcs/dispatcher/src/wlan_dcs_ucfg_api.c", + "cmn/wmi/src/wmi_unified_dcs_api.c", + "cmn/wmi/src/wmi_unified_dcs_tlv.c", + "core/hdd/src/wlan_hdd_dcs.c", + ], + }, + "CONFIG_DIRECT_BUF_RX_ENABLE": { + True: [ + "cmn/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c", + "cmn/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c", + "cmn/wmi/src/wmi_unified_dbr_api.c", + "cmn/wmi/src/wmi_unified_dbr_tlv.c", + ], + }, + "CONFIG_DP_HW_TX_DELAY_STATS_ENABLE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dp_tx_delay_stats.c", + ], + }, + "CONFIG_DP_PKT_ADD_TIMESTAMP": { + True: [ + # TODO: need separate cfg for sysfs + "core/hdd/src/wlan_hdd_sysfs_add_timestamp.c", + "cmn/qdf/linux/src/qdf_pkt_add_timestamp.c", + ], + }, + "CONFIG_DP_SWLM": { + True: [ + # TODO: need separate cfg for sysfs + "core/hdd/src/wlan_hdd_sysfs_swlm.c", + "components/dp/core/src/wlan_dp_swlm.c", + ], + }, + "CONFIG_DP_TRAFFIC_END_INDICATION": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dp_traffic_end_indication.c", + ], + }, + "CONFIG_DSC_TEST": { + True: [ + "components/dsc/test/wlan_dsc_test.c", + ], + }, + "CONFIG_FEATURE_ACTIVE_TOS": { + True: [ + "core/hdd/src/wlan_hdd_active_tos.c", + ], + }, + "CONFIG_FEATURE_BSS_TRANSITION": { + True: [ + "core/hdd/src/wlan_hdd_bss_transition.c", + ], + }, + "CONFIG_FEATURE_COEX": { + True: [ + "components/coex/core/src/wlan_coex_main.c", + "components/coex/dispatcher/src/wlan_coex_tgt_api.c", + "components/coex/dispatcher/src/wlan_coex_ucfg_api.c", + "components/coex/dispatcher/src/wlan_coex_utils_api.c", + "components/target_if/coex/src/target_if_coex.c", + "os_if/coex/src/wlan_cfg80211_coex.c", + ], + }, + "CONFIG_FEATURE_CONCURRENCY_MATRIX": { + True: [ + "core/hdd/src/wlan_hdd_concurrency_matrix.c", + ], + }, + "CONFIG_FEATURE_DENYLIST_MGR": { + True: [ + "components/denylist_mgr/core/src/wlan_dlm_core.c", + "components/denylist_mgr/core/src/wlan_dlm_main.c", + "components/denylist_mgr/dispatcher/src/wlan_dlm_tgt_api.c", + "components/denylist_mgr/dispatcher/src/wlan_dlm_ucfg_api.c", + "components/target_if/denylist_mgr/src/target_if_dlm.c", + ], + }, + "CONFIG_FEATURE_DIRECT_LINK": { + True: [ + # TODO: need sysfs-specific flag + "core/hdd/src/wlan_hdd_sysfs_direct_link_ut_cmd.c", + "components/dp/core/src/wlan_dp_wfds.c", + ], + }, + "CONFIG_FEATURE_EPPING": { + True: [ + "cmn/utils/epping/src/epping_helper.c", + "cmn/utils/epping/src/epping_main.c", + "cmn/utils/epping/src/epping_rx.c", + "cmn/utils/epping/src/epping_tx.c", + "cmn/utils/epping/src/epping_txrx.c", + ], + }, + "CONFIG_FEATURE_FW_LOG_PARSING": { + True: [ + "cmn/utils/fwlog/dbglog_host.c", + ], + }, + "CONFIG_FEATURE_GPIO_CFG": { + True: [ + "core/hdd/src/wlan_hdd_gpio.c", + "cmn/gpio/core/src/wlan_gpio_api.c", + "cmn/gpio/dispatcher/src/wlan_gpio_tgt_api.c", + "cmn/gpio/dispatcher/src/wlan_gpio_ucfg_api.c", + "cmn/os_if/linux/gpio/src/wlan_cfg80211_gpio.c", + "cmn/target_if/gpio/target_if_gpio.c", + "cmn/wmi/src/wmi_unified_gpio_api.c", + "cmn/wmi/src/wmi_unified_gpio_tlv.c", + ], + }, + "CONFIG_FEATURE_HTC_CREDIT_HISTORY": { + True: [ + "cmn/htc/htc_credit_history.c", + ], + }, + "CONFIG_FEATURE_INTEROP_ISSUES_AP": { + True: [ + "cmn/wmi/src/wmi_unified_interop_issues_ap_api.c", + "cmn/wmi/src/wmi_unified_interop_issues_ap_tlv.c", + "components/interop_issues_ap/core/src/wlan_interop_issues_ap_api.c", + "components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_tgt_api.c", + "components/interop_issues_ap/dispatcher/src/wlan_interop_issues_ap_ucfg_api.c", + "components/target_if/interop_issues_ap/src/target_if_interop_issues_ap.c", + "os_if/interop_issues_ap/src/wlan_cfg80211_interop_issues_ap.c", + ], + }, + "CONFIG_FEATURE_MEC": { + True: [ + "cmn/dp/wifi3.0/dp_txrx_wds.c", + ], + }, + "CONFIG_FEATURE_MEMDUMP_ENABLE": { + True: [ + "core/hdd/src/wlan_hdd_memdump.c", + ], + }, + "CONFIG_FEATURE_MONITOR_MODE_SUPPORT": { + True: [ + "core/hdd/src/wlan_hdd_rx_monitor.c", + ], + }, + "CONFIG_FEATURE_MOTION_DETECTION": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_motion_detection.c", + ], + }, + "CONFIG_FEATURE_OTA_TEST": { + True: [ + "core/hdd/src/wlan_hdd_ota_test.c", + ], + }, + "CONFIG_FEATURE_P2P_LISTEN_OFFLOAD": { + True: [ + "core/hdd/src/wlan_hdd_p2p_listen_offload.c", + ], + }, + "CONFIG_FEATURE_RSSI_MONITOR": { + True: [ + "core/hdd/src/wlan_hdd_rssi_monitor.c", + ], + }, + "CONFIG_FEATURE_SAP_COND_CHAN_SWITCH": { + True: [ + "core/hdd/src/wlan_hdd_sap_cond_chan_switch.c", + ], + }, + "CONFIG_FEATURE_SAR_LIMITS": { + True: [ + "core/hdd/src/wlan_hdd_sar_limits.c", + ], + }, + "CONFIG_FEATURE_SET": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_wifi_features.c", + ], + }, + "CONFIG_FEATURE_STATION_INFO": { + True: [ + "core/hdd/src/wlan_hdd_station_info.c", + ], + }, + "CONFIG_FEATURE_TX_POWER": { + True: [ + "core/hdd/src/wlan_hdd_tx_power.c", + ], + }, + "CONFIG_FEATURE_UNIT_TEST_SUSPEND": { + True: [ + "cmn/hif/src/hif_unit_test_suspend.c", + #TODO: need separate flag for sysfs + "core/hdd/src/wlan_hdd_sysfs_suspend_resume.c", + ], + }, + "CONFIG_FEATURE_VDEV_OPS_WAKELOCK": { + True: [ + "cmn/target_if/mlme/psoc/src/target_if_psoc_wake_lock.c", + ], + }, + "CONFIG_FEATURE_WDS": { + True: [ + "core/hdd/src/wlan_hdd_wds.c", + "cmn/wmi/src/wmi_unified_wds_api.c", + "cmn/wmi/src/wmi_unified_wds_tlv.c", + ], + }, + "CONFIG_FEATURE_WLAN_CH_AVOID_EXT": { + True: [ + "core/hdd/src/wlan_hdd_avoid_freq_ext.c", + ], + }, + "CONFIG_FEATURE_WLAN_EXTSCAN": { + True: [ + "cmn/umac/scan/dispatcher/src/wlan_extscan_api.c", + "cmn/wmi/src/wmi_unified_extscan_api.c", + "cmn/wmi/src/wmi_unified_extscan_tlv.c", + "core/hdd/src/wlan_hdd_ext_scan.c", + ], + }, + "CONFIG_FEATURE_WLAN_PRE_CAC": { + True: [ + "components/pre_cac/core/src/wlan_pre_cac_main.c", + "components/pre_cac/dispatcher/src/wlan_pre_cac_api.c", + "components/pre_cac/dispatcher/src/wlan_pre_cac_ucfg_api.c", + "core/hdd/src/wlan_hdd_pre_cac.c", + "os_if/pre_cac/src/osif_pre_cac.c", + ], + }, + "CONFIG_FEATURE_WLAN_TIME_SYNC_FTM": { + True: [ + "components/ftm_time_sync/core/src/ftm_time_sync_main.c", + "components/ftm_time_sync/dispatcher/src/ftm_time_sync_ucfg_api.c", + "components/ftm_time_sync/dispatcher/src/wlan_ftm_time_sync_tgt_api.c", + "components/target_if/ftm_time_sync/src/target_if_ftm_time_sync.c", + "core/hdd/src/wlan_hdd_ftm_time_sync.c", + ], + }, + "CONFIG_FW_THERMAL_THROTTLE": { + True: [ + "core/hdd/src/wlan_hdd_thermal.c", + ], + }, + "CONFIG_HIF_IPCI": { + True: [ + "cmn/hif/src/dispatcher/multibus_ipci.c", + "cmn/hif/src/ipcie/if_ipci.c", + ], + }, + "CONFIG_HIF_PCI": { + True: [ + "cmn/hif/src/dispatcher/multibus_pci.c", + "cmn/hif/src/pcie/if_pci.c", + "core/pld/src/pld_pcie.c", + ], + }, + "CONFIG_HIF_SDIO": { + True: [ + "cmn/hif/src/dispatcher/multibus_sdio.c", + ], + }, + "CONFIG_HIF_SNOC": { + True: [ + "cmn/hif/src/dispatcher/multibus_snoc.c", + "cmn/hif/src/snoc/if_snoc.c" + ], + }, + "CONFIG_HIF_USB": { + True: [ + "cmn/hif/src/dispatcher/multibus_usb.c", + "core/pld/src/pld_usb.c", + ], + }, + "LEGACY_CONFIG_HL_DP_SUPPORT": { + True: [ + "core/dp/txrx/ol_tx_classify.c", + "core/dp/txrx/ol_tx_hl.c", + "core/dp/txrx/ol_tx_queue.c", + "core/dp/txrx/ol_tx_sched.c", + ], + }, + "CONFIG_HOST_11D_SCAN": { + True: [ + "cmn/umac/regulatory/core/src/reg_host_11d.c", + ], + }, + "CONFIG_IPA_OFFLOAD": { + True: [ + "cmn/dp/wifi3.0/dp_ipa.c", + "cmn/qdf/linux/src/qdf_ipa.c", + "cmn/ipa/core/src/wlan_ipa_core.c", + "cmn/ipa/core/src/wlan_ipa_main.c", + "cmn/ipa/core/src/wlan_ipa_rm.c", + "cmn/ipa/core/src/wlan_ipa_stats.c", + "cmn/ipa/dispatcher/src/wlan_ipa_obj_mgmt_api.c", + "cmn/ipa/dispatcher/src/wlan_ipa_tgt_api.c", + "cmn/ipa/dispatcher/src/wlan_ipa_ucfg_api.c", + "cmn/target_if/ipa/src/target_if_ipa.c", + "core/hdd/src/wlan_hdd_ipa.c", + # TODO: need a separate flag for sysfs + "core/hdd/src/wlan_hdd_sysfs_ipa.c", + ], + }, + "CONFIG_IPCIE_FW_SIM": { + True: [ + "core/pld/src/pld_pcie_fw_sim.c", + ], + }, + "CONFIG_LEAK_DETECTION": { + True: [ + "cmn/qdf/src/qdf_debug_domain.c", + "cmn/qdf/src/qdf_tracker.c", + ], + }, + "CONFIG_LFR_SUBNET_DETECTION": { + True: [ + "core/hdd/src/wlan_hdd_subnet_detect.c", + ], + }, + "CONFIG_LINUX_QCMBR": { + True: [ + "cmn/os_if/linux/ftm/src/wlan_ioctl_ftm.c", + ], + }, + "CONFIG_LITHIUM": { + True: [ + # TODO: how to handle Kbuild logic + #ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) + #ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) + "cmn/dp/cmn_dp_api/dp_ratetable.c", + "cmn/dp/wifi3.0/li/dp_li.c", + "cmn/dp/wifi3.0/li/dp_li_rx.c", + "cmn/dp/wifi3.0/li/dp_li_tx.c", + "cmn/dp/wifi3.0/dp_reo.c", + "cmn/dp/wifi3.0/dp_rings_main.c", + "cmn/dp/wifi3.0/dp_rx_err.c", + "cmn/dp/wifi3.0/dp_rx_tid.c", + "cmn/hal/wifi3.0/hal_reo.c", + "cmn/hal/wifi3.0/hal_srng.c", + "cmn/hal/wifi3.0/li/hal_li_generic_api.c", + "cmn/hal/wifi3.0/li/hal_li_reo.c", + "cmn/hif/src/ce/ce_service_srng.c", + "cmn/wlan_cfg/wlan_cfg.c", + "components/dp/core/src/wlan_dp_prealloc.c", + ], + }, + "CONFIG_HELIUMPLUS": { + True: [ + "cmn/hif/src/ce/ce_service_legacy.c", + "core/dp/txrx/ol_txrx.c", + "core/dp/txrx/ol_cfg.c", + "core/dp/txrx/ol_rx.c", + "core/dp/txrx/ol_rx_fwd.c", + "core/dp/txrx/ol_rx_defrag.c", + "core/dp/txrx/ol_tx_desc.c", + "core/dp/txrx/ol_tx.c", + "core/dp/txrx/ol_rx_reorder_timeout.c", + "core/dp/txrx/ol_rx_reorder.c", + "core/dp/txrx/ol_rx_pn.c", + "core/dp/txrx/ol_txrx_peer_find.c", + "core/dp/txrx/ol_txrx_encap.c", + "core/dp/txrx/ol_tx_send.c", + "core/dp/htt/htt.c", + "core/dp/htt/htt_h2t.c", + "core/dp/htt/htt_t2h.c", + "core/dp/htt/htt_rx.c", + "core/dp/htt/htt_fw_stats.c", + "core/dp/htt/htt_tx.c", + "core/dp/htt/htt_rx_ll.c", + "core/dp/htt/htt_monitor_rx.c", + "cmn/hif/src/hif_main_legacy.c" + ], + False: [ + "cmn/dp/wifi3.0/dp_arch_ops.c", + "cmn/dp/wifi3.0/dp_htt.c", + "cmn/dp/wifi3.0/dp_main.c", + "cmn/dp/wifi3.0/dp_peer.c", + "cmn/dp/wifi3.0/dp_rx.c", + "cmn/dp/wifi3.0/dp_rx_defrag.c", + "cmn/dp/wifi3.0/dp_rx_desc.c", + "cmn/dp/wifi3.0/dp_stats.c", + "cmn/dp/wifi3.0/dp_tx.c", + "cmn/dp/wifi3.0/dp_tx_desc.c", + "cmn/target_if/dp/src/target_if_dp.c", + ], + }, + "CONFIG_LL_DP_SUPPORT_LEGACY": { + True: [ + "core/dp/txrx/ol_tx_ll.c", + ], + }, + "CONFIG_OCB_UT_FRAMEWORK": { + True: [ + "cmn/wmi/src/wmi_unified_ocb_ut.c", + ], + }, + "CONFIG_PCIE_FW_SIM": { + True: [ + "core/pld/src/pld_pcie_fw_sim.c", + ], + }, + "CONFIG_PKTLOG_LEGACY": { + True: [ + "cmn/utils/pktlog/pktlog_wifi2.c", + ], + }, + "CONFIG_FEATURE_PKTLOG_EN_NON_LEGACY": { + True: [ + "cmn/utils/pktlog/pktlog_wifi3.c", + ], + }, + "CONFIG_PKT_LOG": { + #TODO: Currently this is CONFIG_REMOVE_PKT_LOG but expect it to change + # Also need a separate config for sysfs + True: [ + "cmn/utils/pktlog/linux_ac.c", + "cmn/utils/pktlog/pktlog_ac.c", + "cmn/utils/pktlog/pktlog_internal.c", + "core/hdd/src/wlan_hdd_sysfs_pktlog.c", + ], + }, + "CONFIG_PLD_IPCI_ICNSS_FLAG": { + True: [ + "core/pld/src/pld_ipci.c", + ], + }, + "CONFIG_PLD_SNOC_ICNSS_FLAG": { + True: [ + "core/pld/src/pld_snoc.c", + ], + }, + "CONFIG_POWER_MANAGEMENT_OFFLOAD": { + True: [ + "cmn/wmi/src/wmi_unified_pmo_api.c", + "cmn/wmi/src/wmi_unified_pmo_tlv.c", + "components/pmo/core/src/wlan_pmo_apf.c", + "components/pmo/core/src/wlan_pmo_arp.c", + "components/pmo/core/src/wlan_pmo_gtk.c", + "components/pmo/core/src/wlan_pmo_hw_filter.c", + "components/pmo/core/src/wlan_pmo_lphb.c", + "components/pmo/core/src/wlan_pmo_main.c", + "components/pmo/core/src/wlan_pmo_mc_addr_filtering.c", + "components/pmo/core/src/wlan_pmo_static_config.c", + "components/pmo/core/src/wlan_pmo_suspend_resume.c", + "components/pmo/core/src/wlan_pmo_wow.c", + "components/pmo/dispatcher/src/wlan_pmo_obj_mgmt_api.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_arp.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_gtk.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_hw_filter.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_lphb.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_mc_addr_filtering.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_static_config.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_suspend_resume.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_wow.c", + "components/pmo/dispatcher/src/wlan_pmo_ucfg_api.c", + "components/target_if/pmo/src/target_if_pmo_arp.c", + "components/target_if/pmo/src/target_if_pmo_gtk.c", + "components/target_if/pmo/src/target_if_pmo_hw_filter.c", + "components/target_if/pmo/src/target_if_pmo_lphb.c", + "components/target_if/pmo/src/target_if_pmo_main.c", + "components/target_if/pmo/src/target_if_pmo_mc_addr_filtering.c", + "components/target_if/pmo/src/target_if_pmo_static_config.c", + "components/target_if/pmo/src/target_if_pmo_suspend_resume.c", + "components/target_if/pmo/src/target_if_pmo_wow.c", + ], + }, + "CONFIG_QCACLD_FEATURE_APF": { + True: [ + "core/hdd/src/wlan_hdd_apf.c", + "cmn/wmi/src/wmi_unified_apf_tlv.c", + ], + }, + "CONFIG_QCACLD_FEATURE_BTC_CHAIN_MODE": { + True: [ + "core/hdd/src/wlan_hdd_btc_chain_mode.c", + ], + }, + "CONFIG_QCACLD_FEATURE_COEX_CONFIG": { + True: [ + "core/hdd/src/wlan_hdd_coex_config.c", + ], + }, + "CONFIG_QCACLD_FEATURE_FW_STATE": { + True: [ + "core/hdd/src/wlan_hdd_fw_state.c", + "core/wma/src/wma_fw_state.c", + ], + }, + "CONFIG_QCACLD_FEATURE_GREEN_AP": { + True: [ + "cmn/target_if/green_ap/src/target_if_green_ap.c", + "cmn/umac/green_ap/core/src/wlan_green_ap_main.c", + "cmn/umac/green_ap/dispatcher/src/wlan_green_ap_api.c", + "cmn/umac/green_ap/dispatcher/src/wlan_green_ap_ucfg_api.c", + "core/hdd/src/wlan_hdd_green_ap.c", + ], + }, + "CONFIG_QCACLD_FEATURE_HW_CAPABILITY": { + True: [ + "core/hdd/src/wlan_hdd_hw_capability.c", + ], + }, + "CONFIG_QCACLD_FEATURE_MPTA_HELPER": { + True: [ + "core/hdd/src/wlan_hdd_mpta_helper.c", + ], + }, + "CONFIG_QCACLD_FEATURE_NAN": { + True: [ + "cmn/wmi/src/wmi_unified_nan_api.c", + "cmn/wmi/src/wmi_unified_nan_tlv.c", + "components/nan/core/src/nan_api.c", + "components/nan/core/src/nan_main.c", + "components/nan/dispatcher/src/cfg_nan.c", + "components/nan/dispatcher/src/nan_ucfg_api.c", + "components/nan/dispatcher/src/wlan_nan_api.c", + "components/target_if/nan/src/target_if_nan.c", + "core/hdd/src/wlan_hdd_nan.c", + "core/hdd/src/wlan_hdd_nan_datapath.c", + "core/mac/src/pe/nan/nan_datapath.c", + "core/sme/src/nan/nan_datapath_api.c", + "core/wma/src/wma_nan_datapath.c", + "os_if/nan/src/os_if_nan.c", + ], + }, + "CONFIG_QCACLD_FEATURE_SON": { + True: [ + "cmn/target_if/son/src/target_if_son.c", + "components/son/dispatcher/src/son_api.c", + "components/son/dispatcher/src/son_ucfg_api.c", + "core/hdd/src/wlan_hdd_son.c", + "os_if/son/src/os_if_son.c", + ], + }, + "CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_EVENT": { + True: [ + "core/hdd/src/wlan_hdd_connectivity_logging.c", + "components/cmn_services/logging/src/wlan_connectivity_logging.c", + ], + }, + "CONFIG_QCACLD_WLAN_CONNECTIVITY_DIAG_LOGGING": { + True: [ + "core/hdd/src/wlan_hdd_connectivity_logging.c", + "components/cmn_services/logging/src/wlan_connectivity_logging.c", + ], + }, + "CONFIG_QCACLD_WLAN_LFR2": { + True: [ + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam.c", + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_host_roam_preauth.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_host_util.c", + "core/mac/src/pe/lim/lim_ft_preauth.c", + "core/mac/src/pe/lim/lim_process_mlm_host_roam.c", + "core/mac/src/pe/lim/lim_reassoc_utils.c", + "core/mac/src/pe/lim/lim_roam_timer_utils.c", + "core/mac/src/pe/lim/lim_send_frames_host_roam.c", + ], + }, + "CONFIG_QCACLD_WLAN_LFR3": { + True: [ + "cmn/umac/mlme/connection_mgr/core/src/wlan_cm_roam_util.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_fw_sync.c", + "components/umac/mlme/connection_mgr/core/src/wlan_cm_roam_offload_event.c", + ], + }, + "CONFIG_QCA_SUPPORT_TX_THROTTLE_LEGACY": { + True: [ + "core/dp/txrx/ol_tx_throttle.c", + ], + }, + "CONFIG_QCA_WIFI_FTM": { + True: [ + "cmn/ftm/core/src/wlan_ftm_svc.c", + "cmn/ftm/dispatcher/src/wlan_ftm_init_deinit.c", + "cmn/ftm/dispatcher/src/wlan_ftm_ucfg_api.c", + "cmn/target_if/ftm/src/target_if_ftm.c", + ], + }, + "CONFIG_QCA_WIFI_FTM_NL80211": { + True: [ + "cmn/os_if/linux/ftm/src/wlan_cfg80211_ftm.c", + ], + }, + "CONFIG_QCA_WIFI_SDIO": { + True: [ + "core/pld/src/pld_sdio.c", + ], + }, + "CONFIG_QCOM_TDLS": { + True: [ + "components/target_if/tdls/src/target_if_tdls.c", + "components/tdls/core/src/wlan_tdls_cmds_process.c", + "components/tdls/core/src/wlan_tdls_ct.c", + "components/tdls/core/src/wlan_tdls_main.c", + "components/tdls/core/src/wlan_tdls_mgmt.c", + "components/tdls/core/src/wlan_tdls_peer.c", + "components/tdls/dispatcher/src/wlan_tdls_api.c", + "components/tdls/dispatcher/src/wlan_tdls_cfg.c", + "components/tdls/dispatcher/src/wlan_tdls_tgt_api.c", + "components/tdls/dispatcher/src/wlan_tdls_ucfg_api.c", + "components/tdls/dispatcher/src/wlan_tdls_utils_api.c", + "core/hdd/src/wlan_hdd_tdls.c", + "core/mac/src/pe/lim/lim_process_tdls.c", + "os_if/tdls/src/wlan_cfg80211_tdls.c", + ], + }, + "CONFIG_QDF_TEST": { + True: [ + "cmn/qdf/test/qdf_delayed_work_test.c", + "cmn/qdf/test/qdf_hashtable_test.c", + "cmn/qdf/test/qdf_periodic_work_test.c", + "cmn/qdf/test/qdf_ptr_hash_test.c", + "cmn/qdf/test/qdf_slist_test.c", + "cmn/qdf/test/qdf_talloc_test.c", + "cmn/qdf/test/qdf_tracker_test.c", + "cmn/qdf/test/qdf_types_test.c", + ], + }, + "CONFIG_QMI_COMPONENT_ENABLE": { + True: [ + "components/qmi/core/src/wlan_qmi_main.c", + "components/qmi/dispatcher/src/wlan_qmi_ucfg_api.c", + "os_if/qmi/src/os_if_qmi.c", + ], + }, + "CONFIG_QMI_WFDS": { + True: [ + "components/qmi/dispatcher/src/wlan_qmi_wfds_api.c", + "os_if/qmi/src/os_if_qmi_wfds.c", + "os_if/qmi/src/os_if_qmi_wifi_driver_service_v01.c", + ], + }, + "CONFIG_RHINE": { + True: [ + # TODO: how to handle Kbuild logic + #ifneq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) + #ifeq (y,$(filter y,$(CONFIG_LITHIUM) $(CONFIG_BERYLLIUM) $(CONFIG_RHINE))) + "cmn/dp/cmn_dp_api/dp_ratetable.c", + "cmn/dp/wifi3.0/rh/dp_rh.c", + "cmn/dp/wifi3.0/rh/dp_rh_htt.c", + "cmn/dp/wifi3.0/rh/dp_rh_rx.c", + "cmn/dp/wifi3.0/rh/dp_rh_tx.c", + "cmn/hal/wifi3.0/hal_reo.c", + "cmn/hal/wifi3.0/hal_srng.c", + "cmn/wlan_cfg/wlan_cfg.c", + "components/dp/core/src/wlan_dp_prealloc.c", + ], + }, + "CONFIG_RX_FISA": { + True: [ + "components/dp/core/src/wlan_dp_fisa_rx.c", + "components/dp/core/src/wlan_dp_rx_fst.c", + #TODO: check LITHIUM/BERYLLIUM/RHINE dependency + "cmn/hal/wifi3.0/hal_rx_flow.c", + ], + }, + "CONFIG_SMP": { + True: [ + "cmn/qdf/linux/src/qdf_cpuhp.c", + "cmn/qdf/src/qdf_cpuhp.c", + ], + }, + "CONFIG_SM_ENG_HIST": { + True: [ + "cmn/umac/cmn_services/sm_engine/src/wlan_sm_engine_dbg.c", + ], + }, + "CONFIG_SNOC_FW_SIM": { + True: [ + "core/pld/src/pld_snoc_fw_sim.c", + ], + }, + "CONFIG_UNIT_TEST": { + True: [ + "core/hdd/src/wlan_hdd_unit_test.c", + ], + }, + "CONFIG_WDI_EVENT_ENABLE": { + True: [ + "core/dp/txrx/ol_txrx_event.c", + "cmn/dp/wifi3.0/dp_wdi_event.c", + ], + }, + "CONFIG_WIFI_MONITOR_SUPPORT": { + True: [ + "cmn/dp/wifi3.0/monitor/1.0/dp_mon_1.0.c", + "cmn/dp/wifi3.0/monitor/1.0/dp_mon_filter_1.0.c", + "cmn/dp/wifi3.0/monitor/1.0/dp_rx_mon_dest_1.0.c", + "cmn/dp/wifi3.0/monitor/1.0/dp_rx_mon_status_1.0.c", + "cmn/dp/wifi3.0/monitor/dp_mon.c", + "cmn/dp/wifi3.0/monitor/dp_mon_filter.c", + "cmn/dp/wifi3.0/monitor/dp_rx_mon.c", + ], + }, + "CONFIG_WIFI_MONITOR_SUPPORT_Y_WLAN_TX_MON_2_0": { + True: [ + "cmn/dp/wifi3.0/monitor/2.0/dp_mon_2.0.c", + "cmn/dp/wifi3.0/monitor/2.0/dp_mon_filter_2.0.c", + "cmn/dp/wifi3.0/monitor/2.0/dp_tx_mon_2.0.c", + "cmn/dp/wifi3.0/monitor/2.0/dp_tx_mon_status_2.0.c", + ], + }, + "CONFIG_WLAN_TX_MON_2_0_Y_WLAN_DP_LOCAL_PKT_CAPTURE": { + True: [ + "os_if/dp/src/os_if_dp_local_pkt_capture.c", + ], + }, + "CONFIG_WIFI_POS_CONVERGED": { + True: [ + "cmn/os_if/linux/wifi_pos/src/os_if_wifi_pos.c", + "cmn/os_if/linux/wifi_pos/src/os_if_wifi_pos_utils.c", + "cmn/os_if/linux/wifi_pos/src/wlan_cfg80211_wifi_pos.c", + "cmn/target_if/wifi_pos/src/target_if_wifi_pos.c", + "cmn/target_if/wifi_pos/src/target_if_wifi_pos_rx_ops.c", + "cmn/target_if/wifi_pos/src/target_if_wifi_pos_tx_ops.c", + "cmn/umac/wifi_pos/src/wifi_pos_api.c", + "cmn/umac/wifi_pos/src/wifi_pos_main.c", + "cmn/umac/wifi_pos/src/wifi_pos_ucfg.c", + "cmn/umac/wifi_pos/src/wifi_pos_utils.c", + "components/wifi_pos/dispatcher/src/wifi_pos_ucfg_api.c", + ], + }, + "CONFIG_WIFI_POS_PASN": { + True: [ + "cmn/umac/wifi_pos/src/wifi_pos_pasn_api.c", + "components/wifi_pos/core/src/wlan_wifi_pos_interface.c", + "core/hdd/src/wlan_hdd_wifi_pos_pasn.c", + "core/wma/src/wma_pasn_peer_api.c", + ], + }, + "CONFIG_WLAN_BCN_RECV_FEATURE": { + True: [ + "core/hdd/src/wlan_hdd_bcn_recv.c", + ], + }, + "CONFIG_WLAN_BMISS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_bmiss.c", + ], + }, + "CONFIG_WLAN_BOOTUP_MARKER": { + True: [ + "core/hdd/src/wlan_hdd_bootup_marker.c", + ], + }, + "CONFIG_WLAN_CFR_ADRASTEA": { + True: [ + "cmn/target_if/cfr/src/target_if_cfr_adrastea.c", + ], + }, + "CONFIG_WLAN_CFR_DBR": { + True: [ + "cmn/target_if/cfr/src/target_if_cfr_dbr.c", + ], + }, + "CONFIG_WLAN_CFR_ENABLE": { + True: [ + "cmn/target_if/cfr/src/target_if_cfr.c", + "cmn/target_if/cfr/src/target_if_cfr_6490.c", + "cmn/umac/cfr/core/src/cfr_common.c", + "cmn/umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c", + "cmn/umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c", + "cmn/umac/cfr/dispatcher/src/wlan_cfr_utils_api.c", + "cmn/wmi/src/wmi_unified_cfr_api.c", + "cmn/wmi/src/wmi_unified_cfr_tlv.c", + "core/hdd/src/wlan_hdd_cfr.c", + ], + }, + "CONFIG_WLAN_CONV_SPECTRAL_ENABLE": { + True: [ + "core/hdd/src/wlan_hdd_spectralscan.c", + "cmn/spectral/core/spectral_common.c", + "cmn/spectral/core/spectral_offload.c", + "cmn/spectral/dispatcher/src/wlan_spectral_tgt_api.c", + "cmn/spectral/dispatcher/src/wlan_spectral_ucfg_api.c", + "cmn/spectral/dispatcher/src/wlan_spectral_utils_api.c", + "cmn/os_if/linux/spectral/src/os_if_spectral_netlink.c", + "cmn/os_if/linux/spectral/src/wlan_cfg80211_spectral.c", + "cmn/target_if/spectral/target_if_spectral.c", + "cmn/target_if/spectral/target_if_spectral_netlink.c", + "cmn/target_if/spectral/target_if_spectral_phyerr.c", + "cmn/target_if/spectral/target_if_spectral_sim.c", + ], + }, + "CONFIG_WLAN_DEBUGFS": { + True: [ + "core/hdd/src/wlan_hdd_debugfs.c", + "core/hdd/src/wlan_hdd_debugfs_config.c", + "core/hdd/src/wlan_hdd_debugfs_csr.c", + "core/hdd/src/wlan_hdd_debugfs_offload.c", + "core/hdd/src/wlan_hdd_debugfs_roam.c", + "core/hdd/src/wlan_hdd_debugfs_unit_test.c", + "cmn/qdf/linux/src/qdf_debugfs.c", + ], + }, + "CONFIG_WLAN_DEBUG_CRASH_INJECT": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_crash_inject.c", + ], + }, + "CONFIG_WLAN_DFS_MASTER_ENABLE": { + True: [ + "cmn/target_if/dfs/src/target_if_dfs.c", + "cmn/umac/dfs/core/src/misc/dfs.c", + "cmn/umac/dfs/core/src/misc/dfs_nol.c", + "cmn/umac/dfs/core/src/misc/dfs_process_radar_found_ind.c", + "cmn/umac/dfs/core/src/misc/dfs_random_chan_sel.c", + "cmn/umac/dfs/dispatcher/src/wlan_dfs_init_deinit_api.c", + "cmn/umac/dfs/dispatcher/src/wlan_dfs_lmac_api.c", + "cmn/umac/dfs/dispatcher/src/wlan_dfs_mlme_api.c", + "cmn/umac/dfs/dispatcher/src/wlan_dfs_tgt_api.c", + "cmn/umac/dfs/dispatcher/src/wlan_dfs_ucfg_api.c", + "cmn/umac/dfs/dispatcher/src/wlan_dfs_utils_api.c", + "cmn/wmi/src/wmi_unified_dfs_api.c", + ], + }, + "CONFIG_WLAN_DIAG_VERSION": { + True: [ + "cmn/utils/host_diag_log/src/host_diag_log.c", + ], + }, + "CONFIG_WLAN_DL_MODES": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dl_modes.c", + ], + }, + "CONFIG_WLAN_DUMP_IN_PROGRESS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dump_in_progress.c", + ], + }, + "CONFIG_WLAN_ENABLE_GPIO_WAKEUP": { + True: [ + "core/hdd/src/wlan_hdd_gpio_wakeup.c", + ], + }, + "CONFIG_WLAN_ENH_CFR_ENABLE": { + True: [ + "cmn/target_if/cfr/src/target_if_cfr_enh.c", + ], + }, + "CONFIG_WLAN_FASTPATH_LEGACY": { + True: [ + "core/dp/txrx/ol_tx_ll_fastpath.c", + ], + }, + #TODO: Will need to create a separate flag to handle false case + #False: [ + # "core/dp/txrx/ol_tx_ll_legacy.c", + #], + #}, + "CONFIG_WLAN_FEATURE_11AX": { + True: [ + "core/hdd/src/wlan_hdd_he.c", + "core/wma/src/wma_he.c", + ], + }, + "CONFIG_WLAN_FEATURE_11BE": { + True: [ + "core/hdd/src/wlan_hdd_eht.c", + "core/wma/src/wma_eht.c", + ], + }, + "CONFIG_WLAN_FEATURE_11BE_MLO": { + True: [ + "core/hdd/src/wlan_hdd_mlo.c", + "core/mac/src/pe/lim/lim_mlo.c", + "cmn/target_if/mlo_mgr/src/target_if_mlo_mgr.c", + "cmn/umac/mlo_mgr/src/utils_mlo.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_aid.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_ap.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_cmn.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_main.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_msgq.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_op.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_peer.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_peer_list.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_primary_umac.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_sta.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_t2lm.c", + "components/umac/mlme/mlo_mgr/src/wlan_epcs_api.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_mgr_link_switch.c", + "cmn/umac/mlo_mgr/src/wlan_mlo_epcs.c", + "components/umac/mlme/mlo_mgr/dispatcher/src/wlan_mlo_epcs_ucfg_api.c", + "cmn/wmi/src/wmi_unified_11be_api.c", + "cmn/wmi/src/wmi_unified_11be_tlv.c", + "components/umac/mlme/mlo_mgr/src/wlan_mlo_mgr_roam.c", + "components/umac/mlme/mlo_mgr/src/wlan_t2lm_api.c", + "components/umac/mlme/mlo_mgr/src/wlan_mlo_link_force.c", + ], + }, + "CONFIG_WLAN_FEATURE_ACTION_OUI": { + True: [ + "components/action_oui/core/src/wlan_action_oui_main.c", + "components/action_oui/core/src/wlan_action_oui_parse.c", + "components/action_oui/dispatcher/src/wlan_action_oui_tgt_api.c", + "components/action_oui/dispatcher/src/wlan_action_oui_ucfg_api.c", + "components/target_if/action_oui/src/target_if_action_oui.c", + "cmn/wmi/src/wmi_unified_action_oui_tlv.c", + ], + }, + "CONFIG_WLAN_FEATURE_BMI": { + True: [ + "cmn/hif/src/ce/ce_bmi.c", + "cmn/hif/src/sdio/hif_bmi_reg_access.c", + "core/bmi/src/bmi.c", + "core/bmi/src/bmi_1.c", + "core/bmi/src/ol_fw.c", + "core/bmi/src/ol_fw_common.c", + ], + }, + "CONFIG_WLAN_FEATURE_COAP": { + True: [ + "components/coap/core/src/wlan_coap_main.c", + "components/coap/dispatcher/src/wlan_coap_tgt_api.c", + "components/coap/dispatcher/src/wlan_coap_ucfg_api.c", + "components/target_if/coap/src/target_if_coap.c", + "components/wmi/src/wmi_unified_coap_tlv.c", + "core/hdd/src/wlan_hdd_coap.c", + "os_if/coap/src/wlan_cfg80211_coap.c", + ], + }, + "CONFIG_WLAN_FEATURE_DFS_OFFLOAD": { + True: [ + "cmn/target_if/dfs/src/target_if_dfs_full_offload.c", + ], + #TODO: need a separate flag, otherwise the below are added + # even when DFS is disabled + False: [ + "cmn/target_if/dfs/src/target_if_dfs_partial_offload.c", + "cmn/umac/dfs/core/src/filtering/dfs_bindetects.c", + "cmn/umac/dfs/core/src/filtering/dfs_debug.c", + "cmn/umac/dfs/core/src/filtering/dfs_fcc_bin5.c", + "cmn/umac/dfs/core/src/filtering/dfs_init.c", + "cmn/umac/dfs/core/src/filtering/dfs_misc.c", + "cmn/umac/dfs/core/src/filtering/dfs_partial_offload_radar.c", + "cmn/umac/dfs/core/src/filtering/dfs_phyerr_tlv.c", + "cmn/umac/dfs/core/src/filtering/dfs_process_phyerr.c", + "cmn/umac/dfs/core/src/filtering/dfs_process_radarevent.c", + "cmn/umac/dfs/core/src/filtering/dfs_radar.c", + "cmn/umac/dfs/core/src/filtering/dfs_staggered.c", + "cmn/umac/dfs/core/src/misc/dfs_filter_init.c", + ], + }, + "CONFIG_WLAN_FEATURE_DISA": { + True: [ + "components/disa/core/src/wlan_disa_main.c", + "components/disa/dispatcher/src/wlan_disa_obj_mgmt_api.c", + "components/disa/dispatcher/src/wlan_disa_tgt_api.c", + "components/disa/dispatcher/src/wlan_disa_ucfg_api.c", + "components/target_if/disa/src/target_if_disa.c", + "core/hdd/src/wlan_hdd_disa.c", + ], + }, + "CONFIG_WLAN_FEATURE_DP_RX_THREADS": { + True: [ + "components/dp/core/src/wlan_dp_rx_thread.c", + ], + }, + "CONFIG_WLAN_FEATURE_DSRC": { + True: [ + "components/ocb/core/src/wlan_ocb_main.c", + "components/ocb/dispatcher/src/wlan_ocb_tgt_api.c", + "components/ocb/dispatcher/src/wlan_ocb_ucfg_api.c", + "components/target_if/ocb/src/target_if_ocb.c", + "core/hdd/src/wlan_hdd_ocb.c", + "core/wma/src/wma_ocb.c", + "cmn/wmi/src/wmi_unified_ocb_api.c", + "cmn/wmi/src/wmi_unified_ocb_tlv.c", + ], + }, + "CONFIG_WLAN_FEATURE_FILS": { + True: [ + "core/mac/src/pe/lim/lim_process_fils.c", + ], + }, + "CONFIG_WLAN_FEATURE_FIPS": { + True: [ + "core/hdd/src/wlan_hdd_fips.c", + "core/wma/src/wma_fips_api.c", + ], + }, + "CONFIG_WLAN_FEATURE_ICMP_OFFLOAD": { + True: [ + "components/pmo/core/src/wlan_pmo_icmp.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_icmp.c", + "components/target_if/pmo/src/target_if_pmo_icmp.c", + ], + }, + "CONFIG_WLAN_FEATURE_LINK_LAYER_STATS": { + True: [ + "core/hdd/src/wlan_hdd_debugfs_llstat.c", + ], + }, + "CONFIG_WLAN_FEATURE_LPSS": { + True: [ + "core/hdd/src/wlan_hdd_lpass.c", + ], + }, + "CONFIG_WLAN_FEATURE_MCC_QUOTA": { + True: [ + "components/p2p/core/src/wlan_p2p_mcc_quota.c", + "components/p2p/dispatcher/src/wlan_p2p_mcc_quota_tgt_api.c", + "components/target_if/p2p/src/target_if_p2p_mcc_quota.c", + "core/hdd/src/wlan_hdd_mcc_quota.c", + ], + }, + "CONFIG_WLAN_FEATURE_MDNS_OFFLOAD": { + True: [ + "core/hdd/src/wlan_hdd_mdns_offload.c", + ], + }, + "CONFIG_WLAN_FEATURE_MEDIUM_ASSESS": { + True: [ + "core/hdd/src/wlan_hdd_medium_assess.c", + ], + }, + "CONFIG_WLAN_FEATURE_MIB_STATS": { + True: [ + "core/hdd/src/wlan_hdd_debugfs_mibstat.c", + ], + }, + "CONFIG_WLAN_FEATURE_PACKET_FILTERING": { + True: [ + "components/pmo/core/src/wlan_pmo_pkt_filter.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_pkt_filter.c", + "components/target_if/pmo/src/target_if_pmo_pkt_filter.c", + "core/hdd/src/wlan_hdd_packet_filter.c", + ], + }, + "CONFIG_WLAN_FEATURE_PEER_TXQ_FLUSH_CONF": { + True: [ + "core/hdd/src/wlan_hdd_peer_txq_flush.c", + ], + }, + "CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS": { + True: [ + "components/dp/core/src/wlan_dp_periodic_sta_stats.c", + ], + }, + "CONFIG_WLAN_FEATURE_PKT_CAPTURE": { + True: [ + "components/pkt_capture/core/src/wlan_pkt_capture_data_txrx.c", + "components/pkt_capture/core/src/wlan_pkt_capture_main.c", + "components/pkt_capture/core/src/wlan_pkt_capture_mgmt_txrx.c", + "components/pkt_capture/core/src/wlan_pkt_capture_mon_thread.c", + "components/pkt_capture/dispatcher/src/wlan_pkt_capture_api.c", + "components/pkt_capture/dispatcher/src/wlan_pkt_capture_tgt_api.c", + "components/pkt_capture/dispatcher/src/wlan_pkt_capture_ucfg_api.c", + "components/target_if/pkt_capture/src/target_if_pkt_capture.c", + "os_if/pkt_capture/src/os_if_pkt_capture.c", + ], + }, + "CONFIG_WLAN_FEATURE_RX_BUFFER_POOL": { + True: [ + "cmn/dp/wifi3.0/dp_rx_buffer_pool.c", + ], + }, + "CONFIG_WLAN_FEATURE_SR": { + True: [ + "components/spatial_reuse/dispatcher/src/spatial_reuse_api.c", + "components/spatial_reuse/dispatcher/src/spatial_reuse_ucfg_api.c", + "cmn/target_if/spatial_reuse/src/target_if_spatial_reuse.c", + ], + }, + "CONFIG_WLAN_FEATURE_TWT": { + True: [ + "cmn/os_if/linux/twt/src/osif_twt_req.c", + "cmn/os_if/linux/twt/src/osif_twt_rsp.c", + "cmn/target_if/twt/src/target_if_twt.c", + "cmn/target_if/twt/src/target_if_twt_cmd.c", + "cmn/target_if/twt/src/target_if_twt_evt.c", + "cmn/umac/twt/core/src/wlan_twt_common.c", + "cmn/umac/twt/core/src/wlan_twt_objmgr.c", + "cmn/umac/twt/dispatcher/src/wlan_twt_api.c", + "cmn/umac/twt/dispatcher/src/wlan_twt_tgt_if_rx_api.c", + "cmn/umac/twt/dispatcher/src/wlan_twt_tgt_if_tx_api.c", + "cmn/umac/twt/dispatcher/src/wlan_twt_ucfg_api.c", + "cmn/wmi/src/wmi_unified_twt_api.c", + "cmn/wmi/src/wmi_unified_twt_tlv.c", + "components/target_if/twt/src/target_if_ext_twt_cmd.c", + "components/target_if/twt/src/target_if_ext_twt_evt.c", + "components/umac/twt/core/src/wlan_twt_cfg.c", + "components/umac/twt/core/src/wlan_twt_main.c", + "components/umac/twt/dispatcher/src/wlan_twt_cfg_ext_api.c", + "components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_rx_api.c", + "components/umac/twt/dispatcher/src/wlan_twt_tgt_if_ext_tx_api.c", + "components/umac/twt/dispatcher/src/wlan_twt_ucfg_ext_api.c", + "core/hdd/src/wlan_hdd_twt.c", + "os_if/twt/src/osif_twt_ext_req.c", + "os_if/twt/src/osif_twt_ext_rsp.c", + "os_if/twt/src/osif_twt_ext_util.c", + # TODO: rest being removed by David's TWT change + # "components/mlme/core/src/wlan_mlme_twt_api.c", + # TODO: to be removed by David's TWT change + "components/mlme/dispatcher/src/wlan_mlme_twt_ucfg_api.c", + "core/wma/src/wma_twt.c", + ], + }, + "CONFIG_WLAN_FREQ_LIST": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_get_freq_for_pwr.c", + ], + }, + "CONFIG_WLAN_FW_OFFLOAD": { + True: [ + "components/fw_offload/core/src/wlan_fw_offload_main.c", + "components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c", + "components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c", + "components/target_if/fw_offload/src/target_if_fwol.c", + "os_if/fw_offload/src/os_if_fwol.c", + "cmn/wmi/src/wmi_unified_fwol_api.c", + "cmn/wmi/src/wmi_unified_fwol_tlv.c", + ], + }, + "CONFIG_WLAN_GTX_BW_MASK": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_gtx_bw_mask.c", + ], + }, + "CONFIG_WLAN_HANG_EVENT": { + True: [ + "core/hdd/src/wlan_hdd_hang_event.c", + "cmn/htc/htc_hang_event.c", + "cmn/qdf/src/qdf_hang_event_notifier.c", + "cmn/qdf/src/qdf_notifier.c", + "cmn/wmi/src/wmi_hang_event.c", + ], + }, + "CONFIG_WLAN_LRO": { + True: [ + "cmn/qdf/linux/src/qdf_lro.c", + "os_if/dp/src/os_if_dp_lro.c", + ], + }, + "CONFIG_WLAN_MWS_INFO_DEBUGFS": { + True: [ + "core/hdd/src/wlan_hdd_debugfs_coex.c", + "core/wma/src/wma_coex.c", + ], + }, + "CONFIG_WLAN_NAPI": { + True: [ + "core/hdd/src/wlan_hdd_napi.c", + "cmn/hif/src/hif_irq_affinity.c", + "cmn/hif/src/hif_napi.c", + ], + }, + "CONFIG_WLAN_NS_OFFLOAD": { + True: [ + "components/pmo/core/src/wlan_pmo_ns.c", + "components/pmo/dispatcher/src/wlan_pmo_tgt_ns.c", + "components/target_if/pmo/src/target_if_pmo_ns.c", + ], + }, + "CONFIG_WLAN_NUD_TRACKING": { + True: [ + "core/hdd/src/wlan_hdd_nud_tracking.c", + "components/dp/core/src/wlan_dp_nud_tracking.c", + ], + }, + "CONFIG_WLAN_OBJMGR_DEBUG": { + True: [ + "cmn/umac/cmn_services/obj_mgr/src/wlan_objmgr_debug.c", + ], + }, + "CONFIG_WLAN_REASSOC": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_reassoc.c", + ], + }, + "CONFIG_WLAN_SCAN_DISABLE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_scan_disable.c", + ], + }, + "CONFIG_WLAN_STREAMFS": { + True: [ + "cmn/qdf/linux/src/qdf_streamfs.c", + ], + }, + "CONFIG_WLAN_SYNC_TSF": { + True: [ + "core/hdd/src/wlan_hdd_tsf.c", + ], + }, + "CONFIG_WLAN_SYSFS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs.c", + "core/hdd/src/wlan_hdd_sysfs_unit_test.c", + "core/hdd/src/wlan_hdd_sysfs_modify_acl.c", + "core/hdd/src/wlan_hdd_sysfs_policy_mgr.c", + "core/hdd/src/wlan_hdd_sysfs_dp_aggregation.c", + ], + }, + "CONFIG_WLAN_SYSFS_CHANNEL": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_channel.c", + ], + }, + "CONFIG_WLAN_SYSFS_CONNECT_INFO": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_connect_info.c", + ], + }, + "CONFIG_WLAN_SYSFS_DCM": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dcm.c", + ], + }, + "CONFIG_WLAN_SYSFS_DFSNOL": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dfsnol.c", + ], + }, + "CONFIG_WLAN_SYSFS_WDS_MODE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_wds_mode.c", + ], + }, + "CONFIG_WLAN_SYSFS_ROAM_TRIGGER_BITMAP": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_roam_trigger_bitmap.c", + ], + }, + "CONFIG_WLAN_SYSFS_RF_TEST_MODE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_rf_test_mode.c", + ], + }, + "CONFIG_WLAN_SYSFS_DP_STATS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_txrx_stats_console.c", + ], + }, + "CONFIG_WLAN_SYSFS_DP_TRACE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_dp_trace.c", + ], + }, + "CONFIG_WLAN_SYSFS_EHT_RATE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_eht_rate.c", + ], + }, + "CONFIG_WLAN_SYSFS_FW_MODE_CFG": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_fw_mode_config.c", + ], + }, + "CONFIG_WLAN_SYSFS_HE_BSS_COLOR": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_he_bss_color.c", + ], + }, + "CONFIG_WLAN_SYSFS_LOG_BUFFER": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_log_buffer.c", + ], + }, + "CONFIG_WLAN_SYSFS_MEM_STATS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_mem_stats.c", + ], + }, + "CONFIG_WLAN_SYSFS_MONITOR_MODE_CHANNEL": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_monitor_mode_channel.c", + ], + }, + "CONFIG_WLAN_SYSFS_RADAR": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_radar.c", + ], + }, + "CONFIG_WLAN_SYSFS_RANGE_EXT": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_range_ext.c", + ], + }, + "CONFIG_WLAN_SYSFS_RTS_CTS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_rts_cts.c", + ], + }, + "CONFIG_WLAN_SYSFS_SCAN_CFG": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_scan_config.c", + ], + }, + "CONFIG_WLAN_SYSFS_STATS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_stats.c", + ], + }, + "CONFIG_WLAN_SYSFS_STA_INFO": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_sta_info.c", + ], + }, + "CONFIG_WLAN_SYSFS_TDLS_PEERS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_tdls_peers.c", + ], + }, + "CONFIG_WLAN_SYSFS_TEMPERATURE": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_temperature.c", + ], + }, + "CONFIG_WLAN_SYSFS_TX_STBC": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_tx_stbc.c", + ], + }, + "CONFIG_WLAN_SYSFS_WLAN_DBG": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_wlan_dbg.c", + ], + }, + "CONFIG_WLAN_THERMAL_CFG": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_thermal_cfg.c", + ], + }, + "CONFIG_WLAN_SYSFS_BITRATES": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_bitrates.c", + ], + }, + "CONFIG_WLAN_TRACEPOINTS": { + True: [ + "cmn/qdf/linux/src/qdf_tracepoint.c", + ], + }, + "CONFIG_WLAN_TXRX_FW_STATS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_txrx_fw_stats.c", + ], + }, + "CONFIG_WLAN_TXRX_FW_ST_RST": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_txrx_fw_st_rst.c", + ], + }, + "CONFIG_WLAN_TXRX_STATS": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_txrx_stats.c", + ], + }, + "LEGACY_CONFIG_WLAN_TX_FLOW_CONTROL_LEGACY": { + True: [ + "core/dp/txrx/ol_txrx_legacy_flow_control.c", + ], + }, + "CONFIG_WLAN_TX_FLOW_CONTROL_V2": { + True: [ + "cmn/dp/wifi3.0/dp_tx_flow_control.c", + ], + }, + "CONFIG_WLAN_TX_FLOW_CONTROL_V2_HL": { + True: [ + "core/dp/txrx/ol_txrx_flow_control.c", + ], + }, + "CONFIG_WLAN_WBUFF": { + True: [ + "cmn/wbuff/src/wbuff.c", + ], + }, + "CONFIG_WLAN_WEXT_SUPPORT_ENABLE": { + True: [ + "core/hdd/src/wlan_hdd_hostapd_wext.c", + "core/hdd/src/wlan_hdd_wext.c", + ], + }, + "CONFIG_WLAN_WOWL_ADD_PTRN": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_wowl_add_ptrn.c", + ], + }, + "CONFIG_WLAN_WOWL_DEL_PTRN": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_wowl_del_ptrn.c", + ], + }, + "CONFIG_WLAN_WOW_ITO": { + True: [ + "core/hdd/src/wlan_hdd_sysfs_wow_ito.c", + ], + }, + "CONFIG_WMI_BCN_OFFLOAD": { + True: [ + "cmn/wmi/src/wmi_unified_bcn_api.c", + "cmn/wmi/src/wmi_unified_bcn_tlv.c", + ], + }, + "CONFIG_WMI_CONCURRENCY_SUPPORT": { + True: [ + "cmn/wmi/src/wmi_unified_concurrency_api.c", + "cmn/wmi/src/wmi_unified_concurrency_tlv.c", + ], + }, + "CONFIG_WMI_ROAM_SUPPORT": { + True: [ + "components/wmi/src/wmi_unified_roam_api.c", + "components/wmi/src/wmi_unified_roam_tlv.c", + ], + }, + "CONFIG_WMI_STA_SUPPORT": { + True: [ + "cmn/wmi/src/wmi_unified_sta_api.c", + "cmn/wmi/src/wmi_unified_sta_tlv.c", + ], + }, + "CONFIG_AFC_SUPPORT": { + True: [ + "core/hdd/src/wlan_hdd_afc.c", + ], + }, + "CONFIG_WLAN_FEATURE_LL_LT_SAP": { + True: [ + "components/target_if/sap/ll_sap/src/target_if_ll_sap.c", + "components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_api.c", + "components/umac/mlme/sap/ll_sap/dispatcher/src/wlan_ll_sap_ucfg_api.c", + "components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_bearer_switch.c", + "components/umac/mlme/sap/ll_sap/core/src/wlan_ll_lt_sap_main.c", + "components/umac/mlme/sap/ll_sap/core/src/wlan_ll_sap_main.c", + "components/wmi/src/wmi_unified_ll_sap_api.c", + "components/wmi/src/wmi_unified_ll_sap_tlv.c", + "components/cmn_services/policy_mgr/src/wlan_policy_mgr_ll_sap.c", + "os_if/mlme/sap/ll_sap/src/os_if_ll_sap.c", + ], + }, +} + +def _define_module_for_target_variant_chipset(target, variant, chipset): + tvc = "{}_{}_{}".format(target, variant, chipset) + tv = "{}_{}".format(target, variant) + name = "{}_qca_cld_{}".format(tv, chipset) + hw = _chipset_hw_map[chipset] + chipset_ipaths = _chipset_header_map[chipset] + hw_ipaths = _hw_header_map[hw] + + ipaths = chipset_ipaths + hw_ipaths + _fixed_ipaths + + iglobs = [] + for i in _fixed_includes: + iglobs.append(i) + for i in ipaths: + iglobs.append("{}/*.h".format(i)) + iglobs.append("{}/**/*.h".format(i)) + for i in _private_ipaths: + iglobs.append("{}/*.h".format(i)) + iglobs.append("{}/**/*.h".format(i)) + copts = [] + for i in _fixed_includes: + copts.append("-include") + copts.append(i) + + feature_grep_map = [ + { + "pattern": "nl80211_validate_key_link_id", + "file": "net/wireless/nl80211.c", + "flag": "CFG80211_MLO_KEY_OPERATION_SUPPORT", + }, + { + "pattern": "struct link_station_parameters", + "file": "include/net/cfg80211.h", + "flag": "CFG80211_LINK_STA_PARAMS_PRESENT", + }, + { + "pattern": "NL80211_EXT_FEATURE_PUNCT", + "file": "include/uapi/linux/nl80211.h", + "flag": "NL80211_EXT_FEATURE_PUNCT_SUPPORT", + }, + { + "pattern": "unsigned int link_id, u16 punct_bitmap", + "file": "include/net/cfg80211.h", + "flag": "CFG80211_RU_PUNCT_NOTIFY", + }, + { + "pattern": "NL80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA", + "file": "include/uapi/linux/nl80211.h", + "flag": "CFG80211_EXT_FEATURE_AUTH_AND_DEAUTH_RANDOM_TA", + }, + ] + + cmd = 'touch "$@"\n' + for feature_grep in feature_grep_map: + cmd += """ + if grep -qF "{pattern}" $(location //msm-kernel:{file}); then + echo "#define {flag} (1)" >> "$@" + fi + """.format( + pattern = feature_grep["pattern"], + file = feature_grep["file"], + flag = feature_grep["flag"], + ) + + grepSrcFiles = [] + for e in feature_grep_map: + grepSrcFiles.append("//msm-kernel:{}".format(e["file"])) + + depsetSrc = depset(grepSrcFiles) + native.genrule( + name = "{}_grep_defines".format(tvc), + outs = ["configs/grep_defines_{}.h".format(tvc)], + srcs = depsetSrc.to_list(), + cmd = cmd, + ) + + copts.append("-Wno-format") + copts.append("-fstrict-flex-arrays=0") + copts.append("-include") + copts.append("$(location :{}_grep_defines)".format(tvc)) + + native.genrule( + name = "configs/{}_defconfig_generate_consolidate".format(tvc), + outs = ["configs/{}_defconfig.generated_consolidate".format(tvc)], + srcs = [ + "configs/{}_gki_{}_defconfig".format(target, chipset), + "configs/{}_consolidate_{}_defconfig".format(target, chipset), + ], + cmd = "cat $(SRCS) > $@", + ) + native.genrule( + name = "configs/{}_defconfig_generate_gki".format(tvc), + outs = ["configs/{}_defconfig.generated_gki".format(tvc)], + srcs = [ + "configs/{}_gki_{}_defconfig".format(target, chipset), + ], + cmd = "cat $(SRCS) > $@", + ) + native.genrule( + name = "configs/{}_defconfig_generate_perf".format(tvc), + outs = ["configs/{}_defconfig.generated_perf".format(tvc)], + srcs = [ + "configs/{}_gki_{}_defconfig".format(target, chipset), + ], + cmd = "cat $(SRCS) > $@", + ) + + + srcs = native.glob(iglobs) + _fixed_srcs + + out = "qca_cld3_{}.ko".format(chipset.replace("-", "_")) + kconfig = "Kconfig" + defconfig = ":configs/{}_defconfig_generate_{}".format(tvc, variant) + + if chipset == "qca6750" or chipset == "adrastea": + deps = [ + "//vendor/qcom/opensource/wlan/platform:{}_icnss2".format(tv), + "//vendor/qcom/opensource/wlan/platform:{}_cnss_prealloc".format(tv), + "//vendor/qcom/opensource/wlan/platform:{}_cnss_utils".format(tv), + "//vendor/qcom/opensource/wlan/platform:{}_cnss_nl".format(tv), + "//msm-kernel:all_headers", + "//vendor/qcom/opensource/wlan/platform:wlan-platform-headers", + "//vendor/qcom/opensource/dataipa:include_headers", + "//vendor/qcom/opensource/dataipa:{}_{}_ipam".format(target, variant), + ] + else: + deps = [ + "//vendor/qcom/opensource/wlan/platform:{}_cnss2".format(tv), + "//vendor/qcom/opensource/wlan/platform:{}_cnss_prealloc".format(tv), + "//vendor/qcom/opensource/wlan/platform:{}_cnss_utils".format(tv), + "//vendor/qcom/opensource/wlan/platform:{}_cnss_nl".format(tv), + "//msm-kernel:all_headers", + "//vendor/qcom/opensource/wlan/platform:wlan-platform-headers", + "//vendor/qcom/opensource/dataipa:include_headers", + "//vendor/qcom/opensource/dataipa:{}_{}_ipam".format(target, variant), + ] + + print("name=", name) + print("hw=", hw) + print("ipaths=", ipaths) + print("srcs=", srcs) + print("out=", out) + print("iglobs=", iglobs) + print("copts=", copts) + print("kconfig=", kconfig) + print("defconfig=", defconfig) + print("deps = ", deps) + + ddk_module( + name = name, + srcs = srcs + [":{}_grep_defines".format(tvc)], + includes = ipaths + ["."], + kconfig = kconfig, + defconfig = defconfig, + conditional_srcs = _conditional_srcs, + copts = copts, + out = out, + kernel_build = "//msm-kernel:{}".format(tv), + deps = deps, + ) + +def define_dist(target, variant, chipsets): + tv = "{}_{}".format(target, variant) + dataList = [] + for c in chipsets: + tvc = "{}_{}_{}".format(target, variant, c) + name = "{}_qca_cld_{}".format(tv, c) + dataList.append(":{}".format(name)) + copy_to_dist_dir( + name = "{}_modules_dist".format(tvc), + data = [":{}".format(name)], + dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + log = "info", + ) + copy_to_dist_dir( + name = "{}_all_modules_dist".format(tv), + data = dataList, + dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + log = "info", + ) + +def define_modules(): + for (t, v) in get_all_variants(): + chipsets = _target_chipset_map.get(t) + if chipsets: + for c in chipsets: + _define_module_for_target_variant_chipset(t, v, c) + define_dist(t, v, chipsets)